summaryrefslogtreecommitdiffstats
path: root/contrib/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gdb')
-rw-r--r--contrib/gdb/COPYING340
-rw-r--r--contrib/gdb/COPYING.LIB482
-rw-r--r--contrib/gdb/FREEBSD-Xlist77
-rw-r--r--contrib/gdb/FREEBSD-diffs929
-rw-r--r--contrib/gdb/FREEBSD-upgrade9
-rw-r--r--contrib/gdb/README47
-rw-r--r--contrib/gdb/config-ml.in877
-rw-r--r--contrib/gdb/djunpack.bat52
-rw-r--r--contrib/gdb/gdb/CONTRIBUTE143
-rw-r--r--contrib/gdb/gdb/COPYING340
-rw-r--r--contrib/gdb/gdb/MAINTAINERS445
-rw-r--r--contrib/gdb/gdb/NEWS2504
-rw-r--r--contrib/gdb/gdb/PROBLEMS113
-rw-r--r--contrib/gdb/gdb/README573
-rw-r--r--contrib/gdb/gdb/TODO333
-rw-r--r--contrib/gdb/gdb/abug-rom.c182
-rw-r--r--contrib/gdb/gdb/acinclude.m4998
-rw-r--r--contrib/gdb/gdb/aclocal.m41040
-rw-r--r--contrib/gdb/gdb/ada-exp.c2642
-rw-r--r--contrib/gdb/gdb/ada-exp.y969
-rw-r--r--contrib/gdb/gdb/ada-lang.c8254
-rw-r--r--contrib/gdb/gdb/ada-lang.h392
-rw-r--r--contrib/gdb/gdb/ada-lex.l928
-rw-r--r--contrib/gdb/gdb/ada-tasks.c819
-rw-r--r--contrib/gdb/gdb/ada-typeprint.c852
-rw-r--r--contrib/gdb/gdb/ada-valprint.c987
-rw-r--r--contrib/gdb/gdb/alpha-mdebug-tdep.c386
-rw-r--r--contrib/gdb/gdb/alpha-nat.c272
-rw-r--r--contrib/gdb/gdb/alpha-tdep.c1615
-rw-r--r--contrib/gdb/gdb/alpha-tdep.h110
-rw-r--r--contrib/gdb/gdb/alphabsd-nat.c151
-rw-r--r--contrib/gdb/gdb/alphabsd-tdep.c55
-rw-r--r--contrib/gdb/gdb/alphabsd-tdep.h33
-rw-r--r--contrib/gdb/gdb/alphafbsd-tdep.c124
-rw-r--r--contrib/gdb/gdb/alphanbsd-tdep.c234
-rw-r--r--contrib/gdb/gdb/amd64-nat.c163
-rw-r--r--contrib/gdb/gdb/amd64-nat.h53
-rw-r--r--contrib/gdb/gdb/amd64-tdep.c1199
-rw-r--r--contrib/gdb/gdb/amd64-tdep.h93
-rw-r--r--contrib/gdb/gdb/amd64bsd-nat.c107
-rw-r--r--contrib/gdb/gdb/amd64fbsd-nat.c235
-rw-r--r--contrib/gdb/gdb/amd64fbsd-tdep.c155
-rw-r--r--contrib/gdb/gdb/amd64nbsd-nat.c68
-rw-r--r--contrib/gdb/gdb/amd64nbsd-tdep.c135
-rw-r--r--contrib/gdb/gdb/amd64obsd-nat.c68
-rw-r--r--contrib/gdb/gdb/amd64obsd-tdep.c224
-rw-r--r--contrib/gdb/gdb/annotate.c585
-rw-r--r--contrib/gdb/gdb/annotate.h106
-rw-r--r--contrib/gdb/gdb/arch-utils.c754
-rw-r--r--contrib/gdb/gdb/arch-utils.h167
-rw-r--r--contrib/gdb/gdb/arm-tdep.c2983
-rw-r--r--contrib/gdb/gdb/arm-tdep.h149
-rw-r--r--contrib/gdb/gdb/armnbsd-nat.c464
-rw-r--r--contrib/gdb/gdb/armnbsd-tdep.c105
-rw-r--r--contrib/gdb/gdb/auxv.c300
-rw-r--r--contrib/gdb/gdb/auxv.h75
-rw-r--r--contrib/gdb/gdb/ax-gdb.c1846
-rw-r--r--contrib/gdb/gdb/ax-gdb.h113
-rw-r--r--contrib/gdb/gdb/ax-general.c542
-rw-r--r--contrib/gdb/gdb/ax.h292
-rw-r--r--contrib/gdb/gdb/bcache.c439
-rw-r--r--contrib/gdb/gdb/bcache.h170
-rw-r--r--contrib/gdb/gdb/bfd-target.c131
-rw-r--r--contrib/gdb/gdb/bfd-target.h39
-rw-r--r--contrib/gdb/gdb/block.c295
-rw-r--r--contrib/gdb/gdb/block.h174
-rw-r--r--contrib/gdb/gdb/blockframe.c643
-rw-r--r--contrib/gdb/gdb/breakpoint.c8101
-rw-r--r--contrib/gdb/gdb/breakpoint.h805
-rw-r--r--contrib/gdb/gdb/buildsym.c1151
-rw-r--r--contrib/gdb/gdb/buildsym.h293
-rw-r--r--contrib/gdb/gdb/c-exp.c3443
-rw-r--r--contrib/gdb/gdb/c-exp.y1811
-rw-r--r--contrib/gdb/gdb/c-lang.c713
-rw-r--r--contrib/gdb/gdb/c-lang.h91
-rw-r--r--contrib/gdb/gdb/c-typeprint.c1212
-rw-r--r--contrib/gdb/gdb/c-valprint.c602
-rw-r--r--contrib/gdb/gdb/call-cmds.h35
-rw-r--r--contrib/gdb/gdb/charset.c1277
-rw-r--r--contrib/gdb/gdb/charset.h109
-rw-r--r--contrib/gdb/gdb/cli-out.c405
-rw-r--r--contrib/gdb/gdb/cli-out.h32
-rw-r--r--contrib/gdb/gdb/cli/cli-cmds.c1288
-rw-r--r--contrib/gdb/gdb/cli/cli-cmds.h125
-rw-r--r--contrib/gdb/gdb/cli/cli-decode.c1546
-rw-r--r--contrib/gdb/gdb/cli/cli-decode.h323
-rw-r--r--contrib/gdb/gdb/cli/cli-dump.c796
-rw-r--r--contrib/gdb/gdb/cli/cli-dump.h40
-rw-r--r--contrib/gdb/gdb/cli/cli-interp.c157
-rw-r--r--contrib/gdb/gdb/cli/cli-logging.c205
-rw-r--r--contrib/gdb/gdb/cli/cli-script.c1304
-rw-r--r--contrib/gdb/gdb/cli/cli-script.h56
-rw-r--r--contrib/gdb/gdb/cli/cli-setshow.c387
-rw-r--r--contrib/gdb/gdb/cli/cli-setshow.h38
-rw-r--r--contrib/gdb/gdb/cli/cli-utils.c21
-rw-r--r--contrib/gdb/gdb/cli/cli-utils.h22
-rw-r--r--contrib/gdb/gdb/coff-pe-read.c346
-rw-r--r--contrib/gdb/gdb/coff-pe-read.h32
-rw-r--r--contrib/gdb/gdb/coff-solib.c134
-rw-r--r--contrib/gdb/gdb/coff-solib.h186
-rw-r--r--contrib/gdb/gdb/coffread.c2140
-rw-r--r--contrib/gdb/gdb/command.h299
-rw-r--r--contrib/gdb/gdb/complaints.c321
-rw-r--r--contrib/gdb/gdb/complaints.h53
-rw-r--r--contrib/gdb/gdb/completer.c728
-rw-r--r--contrib/gdb/gdb/completer.h42
-rw-r--r--contrib/gdb/gdb/config/alpha/alpha-osf2.mh6
-rw-r--r--contrib/gdb/gdb/config/alpha/alpha-osf3.mh6
-rw-r--r--contrib/gdb/gdb/config/alpha/alpha.mt2
-rw-r--r--contrib/gdb/gdb/config/alpha/fbsd.mh5
-rw-r--r--contrib/gdb/gdb/config/alpha/fbsd.mt3
-rw-r--r--contrib/gdb/gdb/config/alpha/nbsd.mh4
-rw-r--r--contrib/gdb/gdb/config/alpha/nbsd.mt4
-rw-r--r--contrib/gdb/gdb/config/alpha/nm-fbsd.h43
-rw-r--r--contrib/gdb/gdb/config/alpha/nm-nbsd.h31
-rw-r--r--contrib/gdb/gdb/config/alpha/nm-osf.h50
-rw-r--r--contrib/gdb/gdb/config/alpha/nm-osf2.h52
-rw-r--r--contrib/gdb/gdb/config/alpha/nm-osf3.h27
-rw-r--r--contrib/gdb/gdb/config/alpha/tm-alpha.h74
-rw-r--r--contrib/gdb/gdb/config/alpha/tm-fbsd.h27
-rw-r--r--contrib/gdb/gdb/config/alpha/tm-nbsd.h28
-rw-r--r--contrib/gdb/gdb/config/alpha/xm-alphaosf.h24
-rw-r--r--contrib/gdb/gdb/config/arm/embed.mt7
-rw-r--r--contrib/gdb/gdb/config/arm/nbsd.mt3
-rw-r--r--contrib/gdb/gdb/config/arm/nbsdaout.mh5
-rw-r--r--contrib/gdb/gdb/config/arm/nbsdelf.mh4
-rw-r--r--contrib/gdb/gdb/config/arm/nm-nbsd.h27
-rw-r--r--contrib/gdb/gdb/config/arm/nm-nbsdaout.h29
-rw-r--r--contrib/gdb/gdb/config/arm/tm-arm.h32
-rw-r--r--contrib/gdb/gdb/config/arm/tm-embed.h52
-rw-r--r--contrib/gdb/gdb/config/arm/tm-nbsd.h26
-rw-r--r--contrib/gdb/gdb/config/arm/tm-wince.h34
-rw-r--r--contrib/gdb/gdb/config/arm/wince.mt5
-rw-r--r--contrib/gdb/gdb/config/arm/xm-nbsd.h22
-rw-r--r--contrib/gdb/gdb/config/i386/embed.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/fbsd.mh5
-rw-r--r--contrib/gdb/gdb/config/i386/fbsd.mt4
-rw-r--r--contrib/gdb/gdb/config/i386/fbsd64.mh5
-rw-r--r--contrib/gdb/gdb/config/i386/fbsd64.mt5
-rw-r--r--contrib/gdb/gdb/config/i386/go32.mh13
-rw-r--r--contrib/gdb/gdb/config/i386/go32.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/i386aout.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/i386gnu.mh33
-rw-r--r--contrib/gdb/gdb/config/i386/i386gnu.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/i386lynx.mh6
-rw-r--r--contrib/gdb/gdb/config/i386/i386lynx.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/i386nw.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/i386sco.mh12
-rw-r--r--contrib/gdb/gdb/config/i386/i386sco4.mh11
-rw-r--r--contrib/gdb/gdb/config/i386/i386sco5.mh16
-rw-r--r--contrib/gdb/gdb/config/i386/i386sol2.mh8
-rw-r--r--contrib/gdb/gdb/config/i386/i386sol2.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/i386v.mh7
-rw-r--r--contrib/gdb/gdb/config/i386/i386v.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/i386v4.mh10
-rw-r--r--contrib/gdb/gdb/config/i386/i386v42mp.mh20
-rw-r--r--contrib/gdb/gdb/config/i386/nbsd.mt4
-rw-r--r--contrib/gdb/gdb/config/i386/nbsd64.mh5
-rw-r--r--contrib/gdb/gdb/config/i386/nbsd64.mt4
-rw-r--r--contrib/gdb/gdb/config/i386/nbsdaout.mh5
-rw-r--r--contrib/gdb/gdb/config/i386/nbsdelf.mh4
-rw-r--r--contrib/gdb/gdb/config/i386/ncr3000.mh16
-rw-r--r--contrib/gdb/gdb/config/i386/ncr3000.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/nm-fbsd.h148
-rw-r--r--contrib/gdb/gdb/config/i386/nm-fbsd64.h37
-rw-r--r--contrib/gdb/gdb/config/i386/nm-go32.h36
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386.h122
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386gnu.h38
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386lynx.h26
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386sco.h33
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386sco4.h33
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386sco5.h78
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386sol2.h61
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386v.h44
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386v4.h26
-rw-r--r--contrib/gdb/gdb/config/i386/nm-i386v42mp.h92
-rw-r--r--contrib/gdb/gdb/config/i386/nm-nbsd.h29
-rw-r--r--contrib/gdb/gdb/config/i386/nm-nbsdaout.h31
-rwxr-xr-xcontrib/gdb/gdb/config/i386/nm-nto.h6
-rw-r--r--contrib/gdb/gdb/config/i386/nm-obsd.h112
-rwxr-xr-xcontrib/gdb/gdb/config/i386/nto.mh7
-rwxr-xr-xcontrib/gdb/gdb/config/i386/nto.mt4
-rw-r--r--contrib/gdb/gdb/config/i386/obsd.mh4
-rw-r--r--contrib/gdb/gdb/config/i386/obsd.mt4
-rw-r--r--contrib/gdb/gdb/config/i386/obsd64.mh5
-rw-r--r--contrib/gdb/gdb/config/i386/obsd64.mt5
-rw-r--r--contrib/gdb/gdb/config/i386/obsdaout.mh5
-rw-r--r--contrib/gdb/gdb/config/i386/tm-fbsd.h31
-rw-r--r--contrib/gdb/gdb/config/i386/tm-go32.h28
-rw-r--r--contrib/gdb/gdb/config/i386/tm-i386.h25
-rw-r--r--contrib/gdb/gdb/config/i386/tm-i386lynx.h29
-rw-r--r--contrib/gdb/gdb/config/i386/tm-i386sol2.h34
-rw-r--r--contrib/gdb/gdb/config/i386/tm-nbsd.h27
-rwxr-xr-xcontrib/gdb/gdb/config/i386/tm-nto.h33
-rw-r--r--contrib/gdb/gdb/config/i386/tm-vxworks.h28
-rw-r--r--contrib/gdb/gdb/config/i386/vxworks.mt3
-rw-r--r--contrib/gdb/gdb/config/i386/xm-go32.h26
-rw-r--r--contrib/gdb/gdb/config/i386/xm-i386.h31
-rw-r--r--contrib/gdb/gdb/config/i386/xm-i386sco.h31
-rw-r--r--contrib/gdb/gdb/config/i386/xm-i386v.h43
-rw-r--r--contrib/gdb/gdb/config/i386/xm-i386v4.h28
-rw-r--r--contrib/gdb/gdb/config/i386/xm-nbsd.h25
-rw-r--r--contrib/gdb/gdb/config/ia64/fbsd.mh3
-rw-r--r--contrib/gdb/gdb/config/ia64/fbsd.mt2
-rw-r--r--contrib/gdb/gdb/config/ia64/ia64.mt2
-rw-r--r--contrib/gdb/gdb/config/ia64/nm-fbsd.h24
-rw-r--r--contrib/gdb/gdb/config/ia64/tm-fbsd.h34
-rw-r--r--contrib/gdb/gdb/config/ia64/tm-ia64.h201
-rw-r--r--contrib/gdb/gdb/config/mips/decstation.mh4
-rw-r--r--contrib/gdb/gdb/config/mips/embed.mt4
-rw-r--r--contrib/gdb/gdb/config/mips/littlemips.mh3
-rw-r--r--contrib/gdb/gdb/config/mips/mipsv4.mh6
-rw-r--r--contrib/gdb/gdb/config/mips/mipsv4.mt3
-rw-r--r--contrib/gdb/gdb/config/mips/nbsd.mh4
-rw-r--r--contrib/gdb/gdb/config/mips/nbsd.mt7
-rw-r--r--contrib/gdb/gdb/config/mips/news-mips.mh3
-rw-r--r--contrib/gdb/gdb/config/mips/nm-fbsd.h48
-rw-r--r--contrib/gdb/gdb/config/mips/nm-mips.h34
-rw-r--r--contrib/gdb/gdb/config/mips/nm-nbsd.h28
-rw-r--r--contrib/gdb/gdb/config/mips/nm-news-mips.h43
-rw-r--r--contrib/gdb/gdb/config/mips/nm-riscos.h60
-rw-r--r--contrib/gdb/gdb/config/mips/riscos.mh16
-rw-r--r--contrib/gdb/gdb/config/mips/tm-fbsd.h43
-rw-r--r--contrib/gdb/gdb/config/mips/tm-mips.h119
-rw-r--r--contrib/gdb/gdb/config/mips/tm-mipsv4.h37
-rw-r--r--contrib/gdb/gdb/config/mips/tm-nbsd.h37
-rw-r--r--contrib/gdb/gdb/config/mips/tm-vxmips.h23
-rw-r--r--contrib/gdb/gdb/config/mips/tm-wince.h33
-rw-r--r--contrib/gdb/gdb/config/mips/vxmips.mt3
-rw-r--r--contrib/gdb/gdb/config/mips/wince.mt5
-rw-r--r--contrib/gdb/gdb/config/mips/xm-mips.h59
-rw-r--r--contrib/gdb/gdb/config/mips/xm-mipsv4.h22
-rw-r--r--contrib/gdb/gdb/config/mips/xm-riscos.h25
-rw-r--r--contrib/gdb/gdb/config/nm-gnu.h43
-rw-r--r--contrib/gdb/gdb/config/nm-lynx.h86
-rw-r--r--contrib/gdb/gdb/config/nm-nbsd.h27
-rw-r--r--contrib/gdb/gdb/config/nm-nbsdaout.h72
-rw-r--r--contrib/gdb/gdb/config/nm-sysv4.h34
-rw-r--r--contrib/gdb/gdb/config/powerpc/fbsd.mh5
-rw-r--r--contrib/gdb/gdb/config/powerpc/fbsd.mt4
-rw-r--r--contrib/gdb/gdb/config/powerpc/nbsd.mh3
-rw-r--r--contrib/gdb/gdb/config/powerpc/nbsd.mt7
-rw-r--r--contrib/gdb/gdb/config/powerpc/nm-fbsd.h18
-rw-r--r--contrib/gdb/gdb/config/powerpc/nm-nbsd.h27
-rw-r--r--contrib/gdb/gdb/config/powerpc/ppc-eabi.mt3
-rw-r--r--contrib/gdb/gdb/config/powerpc/ppc-sim.mt6
-rw-r--r--contrib/gdb/gdb/config/powerpc/tm-nbsd.h26
-rw-r--r--contrib/gdb/gdb/config/powerpc/tm-ppc-eabi.h40
-rw-r--r--contrib/gdb/gdb/config/powerpc/tm-ppcle-eabi.h28
-rw-r--r--contrib/gdb/gdb/config/powerpc/tm-ppcle-sim.h26
-rw-r--r--contrib/gdb/gdb/config/powerpc/tm-vxworks.h28
-rw-r--r--contrib/gdb/gdb/config/powerpc/vxworks.mt3
-rw-r--r--contrib/gdb/gdb/config/rs6000/nm-rs6000.h69
-rw-r--r--contrib/gdb/gdb/config/rs6000/nm-rs6000ly.h26
-rw-r--r--contrib/gdb/gdb/config/rs6000/rs6000.mh11
-rw-r--r--contrib/gdb/gdb/config/rs6000/rs6000.mt3
-rw-r--r--contrib/gdb/gdb/config/rs6000/rs6000lynx.mh6
-rw-r--r--contrib/gdb/gdb/config/rs6000/rs6000lynx.mt3
-rw-r--r--contrib/gdb/gdb/config/rs6000/tm-rs6000.h103
-rw-r--r--contrib/gdb/gdb/config/rs6000/tm-rs6000ly.h31
-rw-r--r--contrib/gdb/gdb/config/rs6000/xm-rs6000.h94
-rw-r--r--contrib/gdb/gdb/config/s390/s390.mh5
-rw-r--r--contrib/gdb/gdb/config/s390/s390.mt5
-rw-r--r--contrib/gdb/gdb/config/sparc/fbsd.mh5
-rw-r--r--contrib/gdb/gdb/config/sparc/fbsd.mt3
-rw-r--r--contrib/gdb/gdb/config/sparc/nbsd.mt4
-rw-r--r--contrib/gdb/gdb/config/sparc/nbsd64.mh4
-rw-r--r--contrib/gdb/gdb/config/sparc/nbsd64.mt5
-rw-r--r--contrib/gdb/gdb/config/sparc/nbsdaout.mh4
-rw-r--r--contrib/gdb/gdb/config/sparc/nbsdelf.mh4
-rw-r--r--contrib/gdb/gdb/config/sparc/nm-fbsd.h39
-rw-r--r--contrib/gdb/gdb/config/sparc/nm-nbsd.h42
-rw-r--r--contrib/gdb/gdb/config/sparc/nm-nbsdaout.h30
-rw-r--r--contrib/gdb/gdb/config/sparc/nm-sol2.h65
-rw-r--r--contrib/gdb/gdb/config/sparc/obsd.mt4
-rw-r--r--contrib/gdb/gdb/config/sparc/obsd64.mt5
-rw-r--r--contrib/gdb/gdb/config/sparc/sol2-64.mt3
-rw-r--r--contrib/gdb/gdb/config/sparc/sol2.mh6
-rw-r--r--contrib/gdb/gdb/config/sparc/sol2.mt3
-rw-r--r--contrib/gdb/gdb/config/sparc/sparc.mt2
-rw-r--r--contrib/gdb/gdb/config/sparc/sparc64.mt2
-rw-r--r--contrib/gdb/gdb/config/sparc/tm-fbsd.h27
-rw-r--r--contrib/gdb/gdb/config/sparc/tm-nbsd.h30
-rw-r--r--contrib/gdb/gdb/config/sparc/tm-nbsd64.h27
-rw-r--r--contrib/gdb/gdb/config/sparc/tm-sol2.h40
-rw-r--r--contrib/gdb/gdb/config/sparc/tm-vxworks.h31
-rw-r--r--contrib/gdb/gdb/config/sparc/vxworks.mt4
-rw-r--r--contrib/gdb/gdb/config/tm-lynx.h32
-rwxr-xr-xcontrib/gdb/gdb/config/tm-nto.h61
-rw-r--r--contrib/gdb/gdb/config/tm-sunos.h32
-rw-r--r--contrib/gdb/gdb/config/tm-sysv4.h37
-rw-r--r--contrib/gdb/gdb/config/tm-vxworks.h23
-rw-r--r--contrib/gdb/gdb/config/xm-nbsd.h26
-rw-r--r--contrib/gdb/gdb/config/xm-sysv4.h29
-rw-r--r--contrib/gdb/gdb/copying.awk77
-rw-r--r--contrib/gdb/gdb/copying.c323
-rw-r--r--contrib/gdb/gdb/core-aout.c146
-rw-r--r--contrib/gdb/gdb/core-regset.c119
-rw-r--r--contrib/gdb/gdb/corefile.c458
-rw-r--r--contrib/gdb/gdb/corelow.c654
-rw-r--r--contrib/gdb/gdb/cp-abi.c252
-rw-r--r--contrib/gdb/gdb/cp-abi.h172
-rw-r--r--contrib/gdb/gdb/cp-namespace.c871
-rw-r--r--contrib/gdb/gdb/cp-support.c757
-rw-r--r--contrib/gdb/gdb/cp-support.h120
-rw-r--r--contrib/gdb/gdb/cp-valprint.c839
-rw-r--r--contrib/gdb/gdb/cpu32bug-rom.c180
-rw-r--r--contrib/gdb/gdb/dbug-rom.c178
-rw-r--r--contrib/gdb/gdb/dbxread.c3577
-rw-r--r--contrib/gdb/gdb/dcache.c604
-rw-r--r--contrib/gdb/gdb/dcache.h43
-rw-r--r--contrib/gdb/gdb/defs.h1335
-rw-r--r--contrib/gdb/gdb/delta68-nat.c90
-rw-r--r--contrib/gdb/gdb/demangle.c203
-rw-r--r--contrib/gdb/gdb/dictionary.c836
-rw-r--r--contrib/gdb/gdb/dictionary.h156
-rw-r--r--contrib/gdb/gdb/dink32-rom.c178
-rw-r--r--contrib/gdb/gdb/disasm.c395
-rw-r--r--contrib/gdb/gdb/disasm.h38
-rw-r--r--contrib/gdb/gdb/doc/GDBvn.texi1
-rw-r--r--contrib/gdb/gdb/doc/LRS197
-rw-r--r--contrib/gdb/gdb/doc/a4rc.sed11
-rw-r--r--contrib/gdb/gdb/doc/agentexpr.texi837
-rw-r--r--contrib/gdb/gdb/doc/all-cfg.texi45
-rw-r--r--contrib/gdb/gdb/doc/annotate.texinfo834
-rw-r--r--contrib/gdb/gdb/doc/fdl.texi452
-rw-r--r--contrib/gdb/gdb/doc/gdb.info-17636
-rw-r--r--contrib/gdb/gdb/doc/gdb.info-29133
-rw-r--r--contrib/gdb/gdb/doc/gdb.info-36665
-rw-r--r--contrib/gdb/gdb/doc/gdb.texinfo21780
-rw-r--r--contrib/gdb/gdb/doc/gdbint.texinfo6757
-rw-r--r--contrib/gdb/gdb/doc/gpl.texi409
-rw-r--r--contrib/gdb/gdb/doc/lpsrc.sed13
-rw-r--r--contrib/gdb/gdb/doc/observer.texi70
-rw-r--r--contrib/gdb/gdb/doc/psrc.sed13
-rw-r--r--contrib/gdb/gdb/doc/refcard.tex647
-rw-r--r--contrib/gdb/gdb/doc/stabs.texinfo4046
-rw-r--r--contrib/gdb/gdb/doublest.c824
-rw-r--r--contrib/gdb/gdb/doublest.h90
-rw-r--r--contrib/gdb/gdb/dpx2-nat.c83
-rw-r--r--contrib/gdb/gdb/dsrec.c313
-rw-r--r--contrib/gdb/gdb/dummy-frame.c466
-rw-r--r--contrib/gdb/gdb/dummy-frame.h86
-rw-r--r--contrib/gdb/gdb/dve3900-rom.c1069
-rw-r--r--contrib/gdb/gdb/dwarf2-frame.c1621
-rw-r--r--contrib/gdb/gdb/dwarf2-frame.h98
-rw-r--r--contrib/gdb/gdb/dwarf2expr.c670
-rw-r--r--contrib/gdb/gdb/dwarf2expr.h96
-rw-r--r--contrib/gdb/gdb/dwarf2loc.c548
-rw-r--r--contrib/gdb/gdb/dwarf2loc.h70
-rw-r--r--contrib/gdb/gdb/dwarf2read.c8067
-rw-r--r--contrib/gdb/gdb/dwarfread.c3816
-rw-r--r--contrib/gdb/gdb/elfread.c745
-rw-r--r--contrib/gdb/gdb/environ.c186
-rw-r--r--contrib/gdb/gdb/environ.h51
-rw-r--r--contrib/gdb/gdb/eval.c2275
-rw-r--r--contrib/gdb/gdb/event-loop.c1158
-rw-r--r--contrib/gdb/gdb/event-loop.h96
-rw-r--r--contrib/gdb/gdb/event-top.c1187
-rw-r--r--contrib/gdb/gdb/event-top.h124
-rw-r--r--contrib/gdb/gdb/exc_request.defs51
-rw-r--r--contrib/gdb/gdb/exec.c761
-rw-r--r--contrib/gdb/gdb/exec.h39
-rw-r--r--contrib/gdb/gdb/expprint.c1069
-rw-r--r--contrib/gdb/gdb/expression.h419
-rw-r--r--contrib/gdb/gdb/f-exp.c2564
-rw-r--r--contrib/gdb/gdb/f-exp.y1188
-rw-r--r--contrib/gdb/gdb/f-lang.c986
-rw-r--r--contrib/gdb/gdb/f-lang.h98
-rw-r--r--contrib/gdb/gdb/f-typeprint.c406
-rw-r--r--contrib/gdb/gdb/f-valprint.c782
-rw-r--r--contrib/gdb/gdb/fbsd-proc.c166
-rw-r--r--contrib/gdb/gdb/findvar.c808
-rw-r--r--contrib/gdb/gdb/fork-child.c469
-rw-r--r--contrib/gdb/gdb/frame-base.c150
-rw-r--r--contrib/gdb/gdb/frame-base.h93
-rw-r--r--contrib/gdb/gdb/frame-unwind.c99
-rw-r--r--contrib/gdb/gdb/frame-unwind.h141
-rw-r--r--contrib/gdb/gdb/frame.c2363
-rw-r--r--contrib/gdb/gdb/frame.h705
-rw-r--r--contrib/gdb/gdb/gcore.c501
-rw-r--r--contrib/gdb/gdb/gdb-events.c444
-rw-r--r--contrib/gdb/gdb/gdb-events.h129
-rwxr-xr-xcontrib/gdb/gdb/gdb-events.sh620
-rw-r--r--contrib/gdb/gdb/gdb-stabs.h90
-rw-r--r--contrib/gdb/gdb/gdb.1381
-rw-r--r--contrib/gdb/gdb/gdb.c36
-rw-r--r--contrib/gdb/gdb/gdb.gdb35
-rw-r--r--contrib/gdb/gdb/gdb.h62
-rw-r--r--contrib/gdb/gdb/gdb_assert.h58
-rw-r--r--contrib/gdb/gdb/gdb_curses.h31
-rw-r--r--contrib/gdb/gdb/gdb_dirent.h42
-rwxr-xr-xcontrib/gdb/gdb/gdb_gcore.sh81
-rwxr-xr-xcontrib/gdb/gdb/gdb_indent.sh86
-rw-r--r--contrib/gdb/gdb/gdb_locale.h46
-rwxr-xr-xcontrib/gdb/gdb/gdb_mbuild.sh333
-rw-r--r--contrib/gdb/gdb/gdb_obstack.h39
-rw-r--r--contrib/gdb/gdb/gdb_proc_service.h86
-rw-r--r--contrib/gdb/gdb/gdb_regex.h32
-rw-r--r--contrib/gdb/gdb/gdb_stat.h74
-rw-r--r--contrib/gdb/gdb/gdb_string.h67
-rw-r--r--contrib/gdb/gdb/gdb_thread_db.h461
-rw-r--r--contrib/gdb/gdb/gdb_vfork.h28
-rw-r--r--contrib/gdb/gdb/gdb_wait.h121
-rw-r--r--contrib/gdb/gdb/gdbarch.c5885
-rw-r--r--contrib/gdb/gdb/gdbarch.h2581
-rwxr-xr-xcontrib/gdb/gdb/gdbarch.sh2320
-rw-r--r--contrib/gdb/gdb/gdbcmd.h122
-rw-r--r--contrib/gdb/gdb/gdbcore.h209
-rw-r--r--contrib/gdb/gdb/gdbinit.in17
-rw-r--r--contrib/gdb/gdb/gdbserver/README138
-rw-r--r--contrib/gdb/gdb/gdbserver/acinclude.m441
-rw-r--r--contrib/gdb/gdb/gdbserver/aclocal.m454
-rw-r--r--contrib/gdb/gdb/gdbserver/gdbreplay.c329
-rw-r--r--contrib/gdb/gdb/gdbserver/gdbserver.1116
-rw-r--r--contrib/gdb/gdb/gdbserver/i387-fp.c290
-rw-r--r--contrib/gdb/gdb/gdbserver/i387-fp.h33
-rw-r--r--contrib/gdb/gdb/gdbserver/inferiors.c199
-rw-r--r--contrib/gdb/gdb/gdbserver/mem-break.c278
-rw-r--r--contrib/gdb/gdb/gdbserver/mem-break.h71
-rw-r--r--contrib/gdb/gdb/gdbserver/proc-service.c256
-rw-r--r--contrib/gdb/gdb/gdbserver/regcache.c239
-rw-r--r--contrib/gdb/gdb/gdbserver/regcache.h72
-rw-r--r--contrib/gdb/gdb/gdbserver/remote-utils.c736
-rw-r--r--contrib/gdb/gdb/gdbserver/server.c621
-rw-r--r--contrib/gdb/gdb/gdbserver/server.h181
-rw-r--r--contrib/gdb/gdb/gdbserver/target.c112
-rw-r--r--contrib/gdb/gdb/gdbserver/target.h171
-rw-r--r--contrib/gdb/gdb/gdbserver/terminal.h51
-rw-r--r--contrib/gdb/gdb/gdbserver/thread-db.c342
-rw-r--r--contrib/gdb/gdb/gdbserver/utils.c96
-rw-r--r--contrib/gdb/gdb/gdbthread.h156
-rw-r--r--contrib/gdb/gdb/gdbtypes.c3499
-rw-r--r--contrib/gdb/gdb/gdbtypes.h1276
-rw-r--r--contrib/gdb/gdb/glibc-tdep.c101
-rw-r--r--contrib/gdb/gdb/glibc-tdep.h30
-rw-r--r--contrib/gdb/gdb/gnu-nat.c3409
-rw-r--r--contrib/gdb/gdb/gnu-nat.h101
-rw-r--r--contrib/gdb/gdb/gnu-v2-abi.c413
-rw-r--r--contrib/gdb/gdb/gnu-v3-abi.c447
-rw-r--r--contrib/gdb/gdb/go32-nat.c1963
-rw-r--r--contrib/gdb/gdb/gregset.h69
-rw-r--r--contrib/gdb/gdb/hpacc-abi.c329
-rw-r--r--contrib/gdb/gdb/hpread.c6327
-rw-r--r--contrib/gdb/gdb/i386-nat.c670
-rwxr-xr-xcontrib/gdb/gdb/i386-nto-tdep.c306
-rw-r--r--contrib/gdb/gdb/i386-sol2-tdep.c120
-rw-r--r--contrib/gdb/gdb/i386-stub.c952
-rw-r--r--contrib/gdb/gdb/i386-tdep.c2109
-rw-r--r--contrib/gdb/gdb/i386-tdep.h233
-rw-r--r--contrib/gdb/gdb/i386bsd-nat.c456
-rw-r--r--contrib/gdb/gdb/i386bsd-tdep.c170
-rw-r--r--contrib/gdb/gdb/i386fbsd-nat.c107
-rw-r--r--contrib/gdb/gdb/i386fbsd-tdep.c175
-rw-r--r--contrib/gdb/gdb/i386gnu-nat.c293
-rw-r--r--contrib/gdb/gdb/i386gnu-tdep.c44
-rw-r--r--contrib/gdb/gdb/i386ly-tdep.c81
-rw-r--r--contrib/gdb/gdb/i386nbsd-tdep.c286
-rw-r--r--contrib/gdb/gdb/i386obsd-nat.c60
-rw-r--r--contrib/gdb/gdb/i386obsd-tdep.c277
-rw-r--r--contrib/gdb/gdb/i386v-nat.c277
-rw-r--r--contrib/gdb/gdb/i386v4-nat.c160
-rw-r--r--contrib/gdb/gdb/i387-tdep.c774
-rw-r--r--contrib/gdb/gdb/i387-tdep.h118
-rw-r--r--contrib/gdb/gdb/ia64-fbsd-nat.c137
-rw-r--r--contrib/gdb/gdb/ia64-fbsd-tdep.c289
-rw-r--r--contrib/gdb/gdb/ia64-tdep.c3382
-rw-r--r--contrib/gdb/gdb/ia64-tdep.h46
-rw-r--r--contrib/gdb/gdb/inf-loop.c132
-rw-r--r--contrib/gdb/gdb/inf-loop.h29
-rw-r--r--contrib/gdb/gdb/infcall.c1103
-rw-r--r--contrib/gdb/gdb/infcall.h43
-rw-r--r--contrib/gdb/gdb/infcmd.c2159
-rw-r--r--contrib/gdb/gdb/inferior.h495
-rw-r--r--contrib/gdb/gdb/inflow.c771
-rw-r--r--contrib/gdb/gdb/inflow.h51
-rw-r--r--contrib/gdb/gdb/infptrace.c688
-rw-r--r--contrib/gdb/gdb/infrun.c4220
-rw-r--r--contrib/gdb/gdb/inftarg.c713
-rw-r--r--contrib/gdb/gdb/infttrace.c5607
-rw-r--r--contrib/gdb/gdb/infttrace.h28
-rw-r--r--contrib/gdb/gdb/interps.c486
-rw-r--r--contrib/gdb/gdb/interps.h76
-rw-r--r--contrib/gdb/gdb/jv-exp.c2842
-rw-r--r--contrib/gdb/gdb/jv-exp.y1469
-rw-r--r--contrib/gdb/gdb/jv-lang.c1100
-rw-r--r--contrib/gdb/gdb/jv-lang.h73
-rw-r--r--contrib/gdb/gdb/jv-typeprint.c343
-rw-r--r--contrib/gdb/gdb/jv-valprint.c535
-rw-r--r--contrib/gdb/gdb/kod-cisco.c317
-rw-r--r--contrib/gdb/gdb/kod.c241
-rw-r--r--contrib/gdb/gdb/kod.h61
-rw-r--r--contrib/gdb/gdb/language.c1442
-rw-r--r--contrib/gdb/gdb/language.h514
-rw-r--r--contrib/gdb/gdb/libunwind-frame.c387
-rw-r--r--contrib/gdb/gdb/libunwind-frame.h64
-rw-r--r--contrib/gdb/gdb/lin-lwp.c1882
-rw-r--r--contrib/gdb/gdb/linespec.c1850
-rw-r--r--contrib/gdb/gdb/linespec.h29
-rw-r--r--contrib/gdb/gdb/lynx-nat.c624
-rw-r--r--contrib/gdb/gdb/m2-exp.c2600
-rw-r--r--contrib/gdb/gdb/m2-exp.y1108
-rw-r--r--contrib/gdb/gdb/m2-lang.c473
-rw-r--r--contrib/gdb/gdb/m2-lang.h31
-rw-r--r--contrib/gdb/gdb/m2-typeprint.c41
-rw-r--r--contrib/gdb/gdb/m2-valprint.c39
-rw-r--r--contrib/gdb/gdb/macrocmd.c289
-rw-r--r--contrib/gdb/gdb/macroexp.c1169
-rw-r--r--contrib/gdb/gdb/macroexp.h90
-rw-r--r--contrib/gdb/gdb/macroscope.c132
-rw-r--r--contrib/gdb/gdb/macroscope.h63
-rw-r--r--contrib/gdb/gdb/macrotab.c892
-rw-r--r--contrib/gdb/gdb/macrotab.h304
-rw-r--r--contrib/gdb/gdb/main.c890
-rw-r--r--contrib/gdb/gdb/main.h35
-rw-r--r--contrib/gdb/gdb/maint.c868
-rw-r--r--contrib/gdb/gdb/mdebugread.c4996
-rw-r--r--contrib/gdb/gdb/mem-break.c92
-rw-r--r--contrib/gdb/gdb/memattr.c549
-rw-r--r--contrib/gdb/gdb/memattr.h91
-rw-r--r--contrib/gdb/gdb/mi/mi-cmd-break.c240
-rw-r--r--contrib/gdb/gdb/mi/mi-cmd-disas.c163
-rw-r--r--contrib/gdb/gdb/mi/mi-cmd-env.c259
-rw-r--r--contrib/gdb/gdb/mi/mi-cmd-file.c67
-rw-r--r--contrib/gdb/gdb/mi/mi-cmd-stack.c349
-rw-r--r--contrib/gdb/gdb/mi/mi-cmd-var.c538
-rw-r--r--contrib/gdb/gdb/mi/mi-cmds.c267
-rw-r--r--contrib/gdb/gdb/mi/mi-cmds.h152
-rw-r--r--contrib/gdb/gdb/mi/mi-console.c125
-rw-r--r--contrib/gdb/gdb/mi/mi-console.h29
-rw-r--r--contrib/gdb/gdb/mi/mi-getopt.c92
-rw-r--r--contrib/gdb/gdb/mi/mi-getopt.h80
-rw-r--r--contrib/gdb/gdb/mi/mi-interp.c406
-rw-r--r--contrib/gdb/gdb/mi/mi-main.c1494
-rw-r--r--contrib/gdb/gdb/mi/mi-main.h33
-rw-r--r--contrib/gdb/gdb/mi/mi-out.c409
-rw-r--r--contrib/gdb/gdb/mi/mi-out.h36
-rw-r--r--contrib/gdb/gdb/mi/mi-parse.c233
-rw-r--r--contrib/gdb/gdb/mi/mi-parse.h55
-rw-r--r--contrib/gdb/gdb/mi/mi-symbol-cmds.c67
-rw-r--r--contrib/gdb/gdb/minimon.h601
-rw-r--r--contrib/gdb/gdb/minsyms.c996
-rw-r--r--contrib/gdb/gdb/mips-nat.c254
-rw-r--r--contrib/gdb/gdb/mips-tdep.c6190
-rw-r--r--contrib/gdb/gdb/mips-tdep.h88
-rw-r--r--contrib/gdb/gdb/mipsfbsd-nat.c108
-rw-r--r--contrib/gdb/gdb/mipsfbsd-tdep.c579
-rw-r--r--contrib/gdb/gdb/mipsfbsd-tdep.h40
-rw-r--r--contrib/gdb/gdb/mipsnbsd-nat.c101
-rw-r--r--contrib/gdb/gdb/mipsnbsd-tdep.c370
-rw-r--r--contrib/gdb/gdb/mipsnbsd-tdep.h33
-rw-r--r--contrib/gdb/gdb/mipsread.c444
-rw-r--r--contrib/gdb/gdb/mipsv4-nat.c168
-rw-r--r--contrib/gdb/gdb/monitor.c2310
-rw-r--r--contrib/gdb/gdb/monitor.h260
-rw-r--r--contrib/gdb/gdb/msg.defs1
-rw-r--r--contrib/gdb/gdb/msg_reply.defs1
-rw-r--r--contrib/gdb/gdb/nbsd-tdep.c109
-rw-r--r--contrib/gdb/gdb/nbsd-tdep.h30
-rw-r--r--contrib/gdb/gdb/nlmread.c248
-rw-r--r--contrib/gdb/gdb/notify.defs1
-rwxr-xr-xcontrib/gdb/gdb/nto-procfs.c1389
-rwxr-xr-xcontrib/gdb/gdb/nto-tdep.c337
-rwxr-xr-xcontrib/gdb/gdb/nto-tdep.h156
-rw-r--r--contrib/gdb/gdb/objc-exp.c3464
-rw-r--r--contrib/gdb/gdb/objc-exp.y1820
-rw-r--r--contrib/gdb/gdb/objc-lang.c1929
-rw-r--r--contrib/gdb/gdb/objc-lang.h68
-rw-r--r--contrib/gdb/gdb/objfiles.c896
-rw-r--r--contrib/gdb/gdb/objfiles.h663
-rw-r--r--contrib/gdb/gdb/observer.c222
-rw-r--r--contrib/gdb/gdb/observer.h35
-rw-r--r--contrib/gdb/gdb/ocd.c1169
-rw-r--r--contrib/gdb/gdb/ocd.h142
-rw-r--r--contrib/gdb/gdb/osabi.c630
-rw-r--r--contrib/gdb/gdb/osabi.h55
-rw-r--r--contrib/gdb/gdb/p-exp.c2974
-rw-r--r--contrib/gdb/gdb/p-exp.y1650
-rw-r--r--contrib/gdb/gdb/p-lang.c485
-rw-r--r--contrib/gdb/gdb/p-lang.h76
-rw-r--r--contrib/gdb/gdb/p-typeprint.c817
-rw-r--r--contrib/gdb/gdb/p-valprint.c1114
-rw-r--r--contrib/gdb/gdb/pa64solib.c1247
-rw-r--r--contrib/gdb/gdb/pa64solib.h149
-rw-r--r--contrib/gdb/gdb/parse.c1308
-rw-r--r--contrib/gdb/gdb/parser-defs.h279
-rw-r--r--contrib/gdb/gdb/ppc-bdm.c356
-rw-r--r--contrib/gdb/gdb/ppc-sysv-tdep.c1002
-rw-r--r--contrib/gdb/gdb/ppc-tdep.h113
-rw-r--r--contrib/gdb/gdb/ppcbug-rom.c225
-rw-r--r--contrib/gdb/gdb/ppcfbsd-nat.c169
-rw-r--r--contrib/gdb/gdb/ppcfbsd-tdep.c296
-rw-r--r--contrib/gdb/gdb/ppcfbsd-tdep.h30
-rw-r--r--contrib/gdb/gdb/ppcnbsd-nat.c121
-rw-r--r--contrib/gdb/gdb/ppcnbsd-tdep.c250
-rw-r--r--contrib/gdb/gdb/ppcnbsd-tdep.h30
-rw-r--r--contrib/gdb/gdb/printcmd.c2172
-rwxr-xr-xcontrib/gdb/gdb/proc-api.c797
-rwxr-xr-xcontrib/gdb/gdb/proc-events.c1777
-rwxr-xr-xcontrib/gdb/gdb/proc-flags.c291
-rw-r--r--contrib/gdb/gdb/proc-service.c312
-rw-r--r--contrib/gdb/gdb/proc-utils.h95
-rwxr-xr-xcontrib/gdb/gdb/proc-why.c175
-rw-r--r--contrib/gdb/gdb/process_reply.defs1
-rw-r--r--contrib/gdb/gdb/procfs.c5960
-rw-r--r--contrib/gdb/gdb/regcache.c1742
-rw-r--r--contrib/gdb/gdb/regcache.h255
-rw-r--r--contrib/gdb/gdb/regformats/reg-arm.dat28
-rw-r--r--contrib/gdb/gdb/regformats/reg-i386.dat43
-rw-r--r--contrib/gdb/gdb/regformats/reg-ia64.dat603
-rw-r--r--contrib/gdb/gdb/regformats/reg-m68k.dat33
-rw-r--r--contrib/gdb/gdb/regformats/reg-mips.dat112
-rw-r--r--contrib/gdb/gdb/regformats/reg-ppc.dat76
-rw-r--r--contrib/gdb/gdb/regformats/reg-s390.dat53
-rw-r--r--contrib/gdb/gdb/regformats/reg-s390x.dat53
-rw-r--r--contrib/gdb/gdb/regformats/reg-sh.dat62
-rw-r--r--contrib/gdb/gdb/regformats/reg-x86-64.dat59
-rwxr-xr-xcontrib/gdb/gdb/regformats/regdat.sh169
-rw-r--r--contrib/gdb/gdb/regformats/regdef.h46
-rw-r--r--contrib/gdb/gdb/reggroups.c288
-rw-r--r--contrib/gdb/gdb/reggroups.h64
-rw-r--r--contrib/gdb/gdb/regset.h41
-rw-r--r--contrib/gdb/gdb/remote-e7000.c2194
-rw-r--r--contrib/gdb/gdb/remote-est.c186
-rw-r--r--contrib/gdb/gdb/remote-fileio.c1384
-rw-r--r--contrib/gdb/gdb/remote-fileio.h38
-rw-r--r--contrib/gdb/gdb/remote-hms.c159
-rw-r--r--contrib/gdb/gdb/remote-mips.c3421
-rw-r--r--contrib/gdb/gdb/remote-rdi.c1026
-rw-r--r--contrib/gdb/gdb/remote-rdp.c1431
-rw-r--r--contrib/gdb/gdb/remote-sds.c1130
-rw-r--r--contrib/gdb/gdb/remote-sim.c900
-rw-r--r--contrib/gdb/gdb/remote-st.c803
-rw-r--r--contrib/gdb/gdb/remote-utils.c609
-rw-r--r--contrib/gdb/gdb/remote-utils.h135
-rw-r--r--contrib/gdb/gdb/remote-vx.c1409
-rw-r--r--contrib/gdb/gdb/remote-vx68.c160
-rw-r--r--contrib/gdb/gdb/remote-vxmips.c201
-rw-r--r--contrib/gdb/gdb/remote-vxsparc.c128
-rw-r--r--contrib/gdb/gdb/remote.c5730
-rw-r--r--contrib/gdb/gdb/remote.h64
-rw-r--r--contrib/gdb/gdb/reply_mig_hack.awk123
-rw-r--r--contrib/gdb/gdb/rom68k-rom.c264
-rw-r--r--contrib/gdb/gdb/rs6000-nat.c1227
-rw-r--r--contrib/gdb/gdb/rs6000-tdep.c2981
-rw-r--r--contrib/gdb/gdb/s390-nat.c359
-rw-r--r--contrib/gdb/gdb/s390-tdep.c3102
-rw-r--r--contrib/gdb/gdb/s390-tdep.h105
-rw-r--r--contrib/gdb/gdb/scm-exp.c496
-rw-r--r--contrib/gdb/gdb/scm-lang.c287
-rw-r--r--contrib/gdb/gdb/scm-lang.h72
-rw-r--r--contrib/gdb/gdb/scm-tags.h379
-rw-r--r--contrib/gdb/gdb/scm-valprint.c395
-rw-r--r--contrib/gdb/gdb/sentinel-frame.c92
-rw-r--r--contrib/gdb/gdb/sentinel-frame.h41
-rw-r--r--contrib/gdb/gdb/ser-e7kpc.c436
-rw-r--r--contrib/gdb/gdb/ser-go32.c964
-rw-r--r--contrib/gdb/gdb/ser-pipe.c161
-rw-r--r--contrib/gdb/gdb/ser-tcp.c231
-rw-r--r--contrib/gdb/gdb/ser-unix.c1364
-rw-r--r--contrib/gdb/gdb/ser-unix.h54
-rw-r--r--contrib/gdb/gdb/serial.c712
-rw-r--r--contrib/gdb/gdb/serial.h243
-rw-r--r--contrib/gdb/gdb/signals/signals.c830
-rw-r--r--contrib/gdb/gdb/sim-regno.h45
-rw-r--r--contrib/gdb/gdb/sol-thread.c1720
-rw-r--r--contrib/gdb/gdb/solib-legacy.c153
-rw-r--r--contrib/gdb/gdb/solib-osf.c623
-rw-r--r--contrib/gdb/gdb/solib-sunos.c898
-rw-r--r--contrib/gdb/gdb/solib-svr4.c1605
-rw-r--r--contrib/gdb/gdb/solib-svr4.h90
-rw-r--r--contrib/gdb/gdb/solib.c912
-rw-r--r--contrib/gdb/gdb/solib.h110
-rw-r--r--contrib/gdb/gdb/solist.h134
-rw-r--r--contrib/gdb/gdb/somread.c736
-rw-r--r--contrib/gdb/gdb/somsolib.c1624
-rw-r--r--contrib/gdb/gdb/somsolib.h178
-rw-r--r--contrib/gdb/gdb/source.c1596
-rw-r--r--contrib/gdb/gdb/source.h68
-rw-r--r--contrib/gdb/gdb/sparc-nat.c330
-rw-r--r--contrib/gdb/gdb/sparc-nat.h40
-rw-r--r--contrib/gdb/gdb/sparc-sol2-nat.c98
-rw-r--r--contrib/gdb/gdb/sparc-sol2-tdep.c201
-rw-r--r--contrib/gdb/gdb/sparc-stub.c778
-rw-r--r--contrib/gdb/gdb/sparc-tdep.c1488
-rw-r--r--contrib/gdb/gdb/sparc-tdep.h204
-rw-r--r--contrib/gdb/gdb/sparc64-nat.c87
-rw-r--r--contrib/gdb/gdb/sparc64-sol2-tdep.c182
-rw-r--r--contrib/gdb/gdb/sparc64-tdep.c1433
-rw-r--r--contrib/gdb/gdb/sparc64-tdep.h123
-rw-r--r--contrib/gdb/gdb/sparc64fbsd-nat.c34
-rw-r--r--contrib/gdb/gdb/sparc64fbsd-tdep.c225
-rw-r--r--contrib/gdb/gdb/sparc64nbsd-nat.c139
-rw-r--r--contrib/gdb/gdb/sparc64nbsd-tdep.c256
-rw-r--r--contrib/gdb/gdb/sparc64obsd-tdep.c210
-rw-r--r--contrib/gdb/gdb/sparcnbsd-nat.c34
-rw-r--r--contrib/gdb/gdb/sparcnbsd-tdep.c358
-rw-r--r--contrib/gdb/gdb/sparcobsd-tdep.c171
-rw-r--r--contrib/gdb/gdb/srec.h39
-rw-r--r--contrib/gdb/gdb/stabsread.c4456
-rw-r--r--contrib/gdb/gdb/stabsread.h207
-rw-r--r--contrib/gdb/gdb/stack.c2180
-rw-r--r--contrib/gdb/gdb/stack.h27
-rw-r--r--contrib/gdb/gdb/standalone.c580
-rw-r--r--contrib/gdb/gdb/std-regs.c160
-rw-r--r--contrib/gdb/gdb/stop-gdb.c109
-rw-r--r--contrib/gdb/gdb/sun3-nat.c166
-rw-r--r--contrib/gdb/gdb/symfile.c3610
-rw-r--r--contrib/gdb/gdb/symfile.h340
-rw-r--r--contrib/gdb/gdb/symmisc.c1258
-rw-r--r--contrib/gdb/gdb/symtab.c4042
-rw-r--r--contrib/gdb/gdb/symtab.h1368
-rw-r--r--contrib/gdb/gdb/target.c2451
-rw-r--r--contrib/gdb/gdb/target.h1251
-rw-r--r--contrib/gdb/gdb/terminal.h91
-rw-r--r--contrib/gdb/gdb/thread-db.c1314
-rw-r--r--contrib/gdb/gdb/thread.c743
-rw-r--r--contrib/gdb/gdb/top.c1912
-rw-r--r--contrib/gdb/gdb/top.h84
-rw-r--r--contrib/gdb/gdb/tracepoint.c2811
-rw-r--r--contrib/gdb/gdb/tracepoint.h134
-rw-r--r--contrib/gdb/gdb/trad-frame.c134
-rw-r--r--contrib/gdb/gdb/trad-frame.h88
-rw-r--r--contrib/gdb/gdb/tui/tui-command.c131
-rw-r--r--contrib/gdb/gdb/tui/tui-command.h30
-rw-r--r--contrib/gdb/gdb/tui/tui-data.c924
-rw-r--r--contrib/gdb/gdb/tui/tui-data.h351
-rw-r--r--contrib/gdb/gdb/tui/tui-disasm.c397
-rw-r--r--contrib/gdb/gdb/tui/tui-disasm.h37
-rw-r--r--contrib/gdb/gdb/tui/tui-file.c238
-rw-r--r--contrib/gdb/gdb/tui/tui-file.h29
-rw-r--r--contrib/gdb/gdb/tui/tui-hooks.c320
-rw-r--r--contrib/gdb/gdb/tui/tui-hooks.h28
-rw-r--r--contrib/gdb/gdb/tui/tui-interp.c210
-rw-r--r--contrib/gdb/gdb/tui/tui-io.c708
-rw-r--r--contrib/gdb/gdb/tui/tui-io.h55
-rw-r--r--contrib/gdb/gdb/tui/tui-layout.c1072
-rw-r--r--contrib/gdb/gdb/tui/tui-layout.h38
-rw-r--r--contrib/gdb/gdb/tui/tui-main.c37
-rw-r--r--contrib/gdb/gdb/tui/tui-out.c413
-rw-r--r--contrib/gdb/gdb/tui/tui-regs.c754
-rw-r--r--contrib/gdb/gdb/tui/tui-regs.h39
-rw-r--r--contrib/gdb/gdb/tui/tui-source.c352
-rw-r--r--contrib/gdb/gdb/tui/tui-source.h40
-rw-r--r--contrib/gdb/gdb/tui/tui-stack.c427
-rw-r--r--contrib/gdb/gdb/tui/tui-stack.h34
-rw-r--r--contrib/gdb/gdb/tui/tui-win.c1520
-rw-r--r--contrib/gdb/gdb/tui/tui-win.h59
-rw-r--r--contrib/gdb/gdb/tui/tui-windata.c304
-rw-r--r--contrib/gdb/gdb/tui/tui-windata.h41
-rw-r--r--contrib/gdb/gdb/tui/tui-wingeneral.c276
-rw-r--r--contrib/gdb/gdb/tui/tui-wingeneral.h45
-rw-r--r--contrib/gdb/gdb/tui/tui-winsource.c654
-rw-r--r--contrib/gdb/gdb/tui/tui-winsource.h73
-rw-r--r--contrib/gdb/gdb/tui/tui.c590
-rw-r--r--contrib/gdb/gdb/tui/tui.h100
-rw-r--r--contrib/gdb/gdb/typeprint.c368
-rw-r--r--contrib/gdb/gdb/typeprint.h31
-rw-r--r--contrib/gdb/gdb/ui-file.c617
-rw-r--r--contrib/gdb/gdb/ui-file.h105
-rw-r--r--contrib/gdb/gdb/ui-out.c1163
-rw-r--r--contrib/gdb/gdb/ui-out.h276
-rw-r--r--contrib/gdb/gdb/user-regs.c211
-rw-r--r--contrib/gdb/gdb/user-regs.h71
-rw-r--r--contrib/gdb/gdb/utils.c3059
-rwxr-xr-xcontrib/gdb/gdb/uw-thread.c1067
-rw-r--r--contrib/gdb/gdb/valarith.c1419
-rw-r--r--contrib/gdb/gdb/valops.c2934
-rw-r--r--contrib/gdb/gdb/valprint.c1445
-rw-r--r--contrib/gdb/gdb/valprint.h72
-rw-r--r--contrib/gdb/gdb/value.h569
-rw-r--r--contrib/gdb/gdb/values.c1329
-rw-r--r--contrib/gdb/gdb/varobj.c2564
-rw-r--r--contrib/gdb/gdb/varobj.h100
-rw-r--r--contrib/gdb/gdb/version.h33
-rw-r--r--contrib/gdb/gdb/version.in1
-rw-r--r--contrib/gdb/gdb/win32-nat.c2460
-rw-r--r--contrib/gdb/gdb/wince-stub.c592
-rw-r--r--contrib/gdb/gdb/wince-stub.h48
-rw-r--r--contrib/gdb/gdb/wince.c2049
-rw-r--r--contrib/gdb/gdb/wrapper.c333
-rw-r--r--contrib/gdb/gdb/wrapper.h51
-rw-r--r--contrib/gdb/gdb/xcoffread.c3033
-rw-r--r--contrib/gdb/gdb/xcoffsolib.c196
-rw-r--r--contrib/gdb/gdb/xcoffsolib.h66
-rw-r--r--contrib/gdb/gdb/xmodem.c275
-rw-r--r--contrib/gdb/gdb/xmodem.h32
-rw-r--r--contrib/gdb/gettext.m4344
-rw-r--r--contrib/gdb/include/COPYING340
-rw-r--r--contrib/gdb/include/MAINTAINERS1
-rw-r--r--contrib/gdb/include/alloca-conf.h24
-rw-r--r--contrib/gdb/include/ansidecl.h315
-rw-r--r--contrib/gdb/include/bfdlink.h686
-rw-r--r--contrib/gdb/include/bin-bugs.h3
-rw-r--r--contrib/gdb/include/bout.h191
-rw-r--r--contrib/gdb/include/demangle.h533
-rw-r--r--contrib/gdb/include/dis-asm.h317
-rw-r--r--contrib/gdb/include/dyn-string.h63
-rw-r--r--contrib/gdb/include/fibheap.h86
-rw-r--r--contrib/gdb/include/filenames.h51
-rw-r--r--contrib/gdb/include/floatformat.h133
-rw-r--r--contrib/gdb/include/fnmatch.h70
-rw-r--r--contrib/gdb/include/fopen-bin.h27
-rw-r--r--contrib/gdb/include/fopen-same.h27
-rw-r--r--contrib/gdb/include/fopen-vms.h24
-rw-r--r--contrib/gdb/include/gdb/callback.h272
-rw-r--r--contrib/gdb/include/gdb/fileio.h146
-rw-r--r--contrib/gdb/include/gdb/remote-sim.h282
-rw-r--r--contrib/gdb/include/gdb/signals.h237
-rw-r--r--contrib/gdb/include/gdb/sim-arm.h114
-rw-r--r--contrib/gdb/include/gdb/sim-d10v.h142
-rw-r--r--contrib/gdb/include/gdb/sim-frv.h53
-rw-r--r--contrib/gdb/include/gdb/sim-h8300.h78
-rw-r--r--contrib/gdb/include/gdb/sim-sh.h161
-rw-r--r--contrib/gdb/include/gdbm.h91
-rw-r--r--contrib/gdb/include/getopt.h144
-rw-r--r--contrib/gdb/include/hashtab.h195
-rw-r--r--contrib/gdb/include/hp-symtab.h1866
-rw-r--r--contrib/gdb/include/ieee.h165
-rw-r--r--contrib/gdb/include/libiberty.h335
-rw-r--r--contrib/gdb/include/md5.h142
-rw-r--r--contrib/gdb/include/oasys.h192
-rw-r--r--contrib/gdb/include/objalloc.h115
-rw-r--r--contrib/gdb/include/obstack.h611
-rw-r--r--contrib/gdb/include/os9k.h181
-rw-r--r--contrib/gdb/include/partition.h85
-rw-r--r--contrib/gdb/include/progress.h37
-rw-r--r--contrib/gdb/include/safe-ctype.h119
-rw-r--r--contrib/gdb/include/sort.h48
-rw-r--r--contrib/gdb/include/splay-tree.h159
-rw-r--r--contrib/gdb/include/symcat.h49
-rw-r--r--contrib/gdb/include/ternary.h51
-rw-r--r--contrib/gdb/include/xregex.h28
-rw-r--r--contrib/gdb/include/xregex2.h571
-rw-r--r--contrib/gdb/include/xtensa-isa-internal.h114
-rw-r--r--contrib/gdb/include/xtensa-isa.h230
-rwxr-xr-xcontrib/gdb/install-sh316
-rw-r--r--contrib/gdb/libtool.m4893
-rw-r--r--contrib/gdb/ltcf-c.sh824
-rw-r--r--contrib/gdb/ltcf-cxx.sh1021
-rw-r--r--contrib/gdb/ltcf-gcj.sh651
-rwxr-xr-xcontrib/gdb/ltconfig2833
-rw-r--r--contrib/gdb/ltmain.sh5469
-rw-r--r--contrib/gdb/md5.sum5330
-rwxr-xr-xcontrib/gdb/missing336
-rwxr-xr-xcontrib/gdb/mkinstalldirs150
-rwxr-xr-xcontrib/gdb/move-if-change32
-rw-r--r--contrib/gdb/src-release336
-rwxr-xr-xcontrib/gdb/symlink-tree78
-rwxr-xr-xcontrib/gdb/ylwrap123
850 files changed, 486966 insertions, 0 deletions
diff --git a/contrib/gdb/COPYING b/contrib/gdb/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/contrib/gdb/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+
+ <signature of Ty Coon>, 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 0000000..161a3d1
--- /dev/null
+++ b/contrib/gdb/COPYING.LIB
@@ -0,0 +1,482 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, 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.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/contrib/gdb/FREEBSD-Xlist b/contrib/gdb/FREEBSD-Xlist
new file mode 100644
index 0000000..53f455c
--- /dev/null
+++ b/contrib/gdb/FREEBSD-Xlist
@@ -0,0 +1,77 @@
+$FreeBSD$
+gdb-*/bfd/*
+gdb-*/config/*
+gdb-*/etc/*
+gdb-*/gdb/avr*
+gdb-*/gdb/config/avr/*
+gdb-*/gdb/config/cris/*
+gdb-*/gdb/config/d10v/*
+gdb-*/gdb/config/djgpp/*
+gdb-*/gdb/config/frv/*
+gdb-*/gdb/config/h8300/*
+gdb-*/gdb/config/m32r/*
+gdb-*/gdb/config/m68hc11/*
+gdb-*/gdb/config/m68k/*
+gdb-*/gdb/config/mcore/*
+gdb-*/gdb/config/mn10300/*
+gdb-*/gdb/config/ns32k/*
+gdb-*/gdb/config/pa/*
+gdb-*/gdb/config/sh/*
+gdb-*/gdb/config/v850/*
+gdb-*/gdb/config/vax/*
+gdb-*/gdb/config/xstormy16/*
+gdb-*/gdb/cris*
+gdb-*/gdb/d10v*
+gdb-*/gdb/frv*
+gdb-*/gdb/h8300*
+gdb-*/gdb/iq2000*
+gdb-*/gdb/i386nbsd*
+gdb-*/gdb/m32c*
+gdb-*/gdb/*m32r*
+gdb-*/gdb/m68*
+gdb-*/gdb/m88*
+gdb-*/gdb/mcore*
+gdb-*/gdb/mn10300*
+gdb-*/gdb/mt-*
+gdb-*/gdb/nlm/*
+gdb-*/gdb/ns32k*
+gdb-*/gdb/osf-share/*
+gdb-*/gdb/ppcobsd*
+gdb-*/gdb/hppa*
+gdb-*/gdb/rdi-share/*
+gdb-*/gdb/sh*
+gdb-*/gdb/testsuite/*
+gdb-*/gdb/v850*
+gdb-*/gdb/vax*
+gdb-*/gdb/vx-share/*
+gdb-*/gdb/xstormy16*
+gdb-*/gdb/xtensa*
+gdb-*/include/aout/*
+gdb-*/include/coff/*
+gdb-*/include/elf/*
+gdb-*/include/mpw/*
+gdb-*/include/nlm/*
+gdb-*/include/opcode/*
+gdb-*/intl/*
+gdb-*/libiberty/*
+gdb-*/mmalloc/*
+gdb-*/opcodes/*
+gdb-*/readline/*
+gdb-*/regformats/reg-cris*
+gdb-*/sim/*
+gdb-*/texinfo/*
+gdb-*/utils/*
+*ChangeLog*
+*Makefile*
+*TODO*
+*aix*
+*config.*
+*configure*
+*cygwin*
+*hpux*
+*interix*
+*irix*
+*linux*
+*mingw*
+*osf1*
+*win32*
diff --git a/contrib/gdb/FREEBSD-diffs b/contrib/gdb/FREEBSD-diffs
new file mode 100644
index 0000000..85eb8d8
--- /dev/null
+++ b/contrib/gdb/FREEBSD-diffs
@@ -0,0 +1,929 @@
+Index: gdb/ia64-fbsd-nat.c
+===================================================================
+RCS file: gdb/ia64-fbsd-nat.c
+diff -N gdb/ia64-fbsd-nat.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ gdb/ia64-fbsd-nat.c 17 Apr 2004 19:39:20 -0000 1.3
+@@ -0,0 +1,145 @@
++/*
++ * Copyright (c) 2004 Marcel Moolenaar
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "defs.h"
++#include "inferior.h"
++#include "regcache.h"
++
++#include <sys/types.h>
++#include <sys/ptrace.h>
++#include <machine/reg.h>
++
++#ifdef HAVE_SYS_PROCFS_H
++#include <sys/procfs.h>
++#endif
++
++#ifndef HAVE_GREGSET_T
++typedef struct reg gregset_t;
++#endif
++
++#ifndef HAVE_FPREGSET_T
++typedef struct fpreg fpregset_t;
++#endif
++
++#include "gregset.h"
++
++#define FPREG_SUPPLIES(r) ((r) >= IA64_FR0_REGNUM && (r) <= IA64_FR127_REGNUM)
++#define GREG_SUPPLIES(r) (!FPREG_SUPPLIES(r))
++
++/* XXX need to go away. */
++void ia64_fbsd_supply_fpregs (void *, int);
++void ia64_fbsd_supply_gregs (void *, int);
++
++void
++fetch_inferior_registers (int regno)
++{
++ union {
++ fpregset_t fpr;
++ gregset_t r;
++ } regs;
++
++ if (regno == -1 || GREG_SUPPLIES(regno))
++ {
++ if (ptrace (PT_GETREGS, PIDGET(inferior_ptid),
++ (PTRACE_ARG3_TYPE)&regs.r, 0) == -1)
++ perror_with_name ("Couldn't get registers");
++ ia64_fbsd_supply_gregs (&regs.r, regno);
++ if (regno != -1)
++ return;
++ }
++
++ if (regno == -1 || FPREG_SUPPLIES(regno))
++ {
++ if (ptrace (PT_GETFPREGS, PIDGET(inferior_ptid),
++ (PTRACE_ARG3_TYPE)&regs.fpr, 0) == -1)
++ perror_with_name ("Couldn't get FP registers");
++ ia64_fbsd_supply_fpregs (&regs.fpr, regno);
++ if (regno != -1)
++ return;
++ }
++}
++
++void
++store_inferior_registers (int regno)
++{
++ union {
++ fpregset_t fpr;
++ gregset_t r;
++ } regs;
++
++ if (regno == -1 || GREG_SUPPLIES(regno))
++ {
++ if (ptrace (PT_GETREGS, PIDGET(inferior_ptid),
++ (PTRACE_ARG3_TYPE)&regs.r, 0) == -1)
++ perror_with_name ("Couldn't get registers");
++ fill_gregset (&regs.r, regno);
++ if (ptrace (PT_SETREGS, PIDGET(inferior_ptid),
++ (PTRACE_ARG3_TYPE)&regs.r, 0) == -1)
++ perror_with_name ("Couldn't get registers");
++ if (regno != -1)
++ return;
++ }
++
++ if (regno == -1 || FPREG_SUPPLIES(regno))
++ {
++ if (ptrace (PT_GETFPREGS, PIDGET(inferior_ptid),
++ (PTRACE_ARG3_TYPE)&regs.fpr, 0) == -1)
++ perror_with_name ("Couldn't get FP registers");
++ fill_fpregset (&regs.fpr, regno);
++ if (ptrace (PT_SETFPREGS, PIDGET(inferior_ptid),
++ (PTRACE_ARG3_TYPE)&regs.fpr, 0) == -1)
++ perror_with_name ("Couldn't get FP registers");
++ if (regno != -1)
++ return;
++ }
++}
++
++LONGEST ia64_fbsd_xfer_dirty (struct target_ops *ops, enum target_object obj,
++ const char *annex, void *rbuf, const void *wbuf,
++ ULONGEST ofs, LONGEST len)
++{
++ if (len != 8)
++ return (-1);
++ if (rbuf != NULL) {
++ if (ptrace (PT_GETKSTACK, PIDGET(inferior_ptid), (PTRACE_ARG3_TYPE)rbuf,
++ ofs >> 3) == -1) {
++ perror_with_name ("Couldn't read dirty register");
++ return (-1);
++ }
++ } else {
++ if (ptrace (PT_SETKSTACK, PIDGET(inferior_ptid), (PTRACE_ARG3_TYPE)wbuf,
++ ofs >> 3) == -1) {
++ perror_with_name ("Couldn't write dirty register");
++ return (-1);
++ }
++ }
++ return (len);
++}
++
++void
++_initialize_ia64_fbsd_nat (void)
++{
++}
+Index: gdb/ia64-fbsd-tdep.c
+===================================================================
+RCS file: gdb/ia64-fbsd-tdep.c
+diff -N gdb/ia64-fbsd-tdep.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ gdb/ia64-fbsd-tdep.c 17 Apr 2004 19:39:20 -0000 1.6
+@@ -0,0 +1,291 @@
++/*
++ * Copyright (c) 2004 Marcel Moolenaar
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "defs.h"
++#include "gdb_string.h"
++#include "regcache.h"
++#include "regset.h"
++#include "solib-svr4.h"
++#include "value.h"
++
++#include "ia64-tdep.h"
++
++#define FPREG_SUPPLIES(r) ((r) >= IA64_FR0_REGNUM && (r) <= IA64_FR127_REGNUM)
++#define GREG_SUPPLIES(r) (!FPREG_SUPPLIES(r))
++
++static int reg_offset[462] = {
++ -1, 96, 248, 256, 152, 160, 168, 176, /* Regs 0-7. */
++ 264, 272, 280, 288, 0, 64, 296, 304, /* Regs 8-15. */
++ 312, 320, 328, 336, 344, 352, 360, 368, /* Regs 16-23. */
++ 376, 384, 392, 400, 408, 416, 424, 432, /* Regs 24-31. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 32-39. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 40-47. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 48-55. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 56-63. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 64-71. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 72-79. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 80-87. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 88-95. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 96-103. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 104-111. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 112-119. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 120-127. */
++ -1, -1, 0, 16, 32, 48, 320, 336, /* Regs 128-135. */
++ 352, 368, 384, 400, 416, 432, 448, 464, /* Regs 136-143. */
++ 64, 80, 96, 112, 128, 144, 160, 176, /* Regs 144-151. */
++ 192, 208, 224, 240, 256, 272, 288, 304, /* Regs 152-159. */
++ 480, 496, 512, 528, 544, 560, 576, 592, /* Regs 160-167. */
++ 608, 624, 640, 656, 672, 688, 704, 720, /* Regs 168-175. */
++ 736, 752, 768, 784, 800, 816, 832, 848, /* Regs 176-183. */
++ 864, 880, 896, 912, 928, 944, 960, 976, /* Regs 184-191. */
++ 992, 1008, 1024, 1040, 1056, 1072, 1088, 1104, /* Regs 192-199. */
++ 1120, 1136, 1152, 1168, 1184, 1200, 1216, 1232, /* Regs 200-207. */
++ 1248, 1264, 1280, 1296, 1312, 1328, 1344, 1360, /* Regs 208-215. */
++ 1376, 1392, 1408, 1424, 1440, 1456, 1472, 1488, /* Regs 216-223. */
++ 1504, 1520, 1536, 1552, 1568, 1584, 1600, 1616, /* Regs 224-231. */
++ 1632, 1648, 1664, 1680, 1696, 1712, 1728, 1744, /* Regs 232-239. */
++ 1760, 1776, 1792, 1808, 1824, 1840, 1856, 1872, /* Regs 240-247. */
++ 1888, 1904, 1920, 1936, 1952, 1968, 1984, 2000, /* Regs 248-255. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 256-263. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 264-271. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 272-279. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 280-287. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 288-295. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 296-303. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 304-311. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 312-319. */
++ 16, 184, 192, 200, 208, 216, 440, 448, /* Regs 320-327. */
++ -1, -1, 24, 120, 88, 112, -1, -1, /* Regs 328-335. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 336-343. */
++ -1, -1, -1, -1, -1, -1, 72, 104, /* Regs 344-351. */
++ 40, 48, -1, -1, -1, -1, -1, 464, /* Regs 352-359. */
++ 472, -1, -1, -1, -1, -1, 456, -1, /* Regs 360-367. */
++ -1, -1, 8, -1, -1, -1, 80, -1, /* Regs 368-375. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 376-383. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 384-391. */
++ -1, -1, -1, -1, -1, -1, 32, 224, /* Regs 392-399. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 400-407. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 408-415. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 416-423. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 424-431. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 432-439. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 440-447. */
++ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 448-455. */
++ -1, -1, -1, -1, -1, -1
++};
++
++static void
++ia64_fbsd_regcache_collect (struct regcache *regcache, int regno,
++ void *regs)
++{
++ int ofs;
++
++ if (regno < 0 || regno >= NUM_REGS)
++ return;
++
++ ofs = reg_offset[regno];
++ if (ofs >= 0)
++ regcache_raw_collect (regcache, regno, (char*)regs + ofs);
++}
++
++static void
++ia64_fbsd_regcache_supply (struct regcache *regcache, int regno,
++ const void *regs)
++{
++ int ofs;
++
++ if (regno < 0 || regno >= NUM_REGS)
++ return;
++
++ ofs = reg_offset[regno];
++ if (regno == IA64_BSP_REGNUM)
++ {
++ /* BSP is synthesized. It's not actually present in struct reg,
++ but can be derived from bspstore and ndirty. The offset of
++ IA64_BSP_REGNUM in the reg_offset array above is that of the
++ ndirty field in struct reg. */
++ uint64_t bsp;
++ bsp = *((uint64_t*)((char *)regs + ofs)); /* ndirty */
++ bsp += *((uint64_t*)((char *)regs + reg_offset[IA64_BSPSTORE_REGNUM]));
++ regcache_raw_supply (regcache, regno, &bsp);
++ }
++ else
++ {
++ if (ofs < 0)
++ regcache_raw_supply (regcache, regno, NULL);
++ else
++ regcache_raw_supply (regcache, regno, (char *)regs + ofs);
++ }
++}
++
++void
++fill_fpregset (void *fpregs, int regno)
++{
++ if (regno == -1)
++ {
++ for (regno = 0; regno < NUM_REGS; regno++)
++ {
++ if (FPREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_collect (current_regcache, regno, fpregs);
++ }
++ }
++ else
++ {
++ if (FPREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_collect (current_regcache, regno, fpregs);
++ }
++}
++
++void
++fill_gregset (void *gregs, int regno)
++{
++ if (regno == -1)
++ {
++ for (regno = 0; regno < NUM_REGS; regno++)
++ {
++ if (GREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_collect (current_regcache, regno, gregs);
++ }
++ }
++ else
++ {
++ if (GREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_collect (current_regcache, regno, gregs);
++ }
++}
++
++void
++ia64_fbsd_supply_fpregs (const void *fpregs, int regno)
++{
++ if (regno == -1)
++ {
++ for (regno = 0; regno < NUM_REGS; regno++)
++ {
++ if (FPREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (current_regcache, regno, fpregs);
++ }
++ }
++ else
++ {
++ if (FPREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (current_regcache, regno, fpregs);
++ }
++}
++
++void
++ia64_fbsd_supply_gregs (const void *gregs, int regno)
++{
++ if (regno == -1)
++ {
++ for (regno = 0; regno < NUM_REGS; regno++)
++ {
++ if (GREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (current_regcache, regno, gregs);
++ }
++ }
++ else
++ {
++ if (GREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (current_regcache, regno, gregs);
++ }
++}
++
++static void
++ia64_fbsd_supply_gregset (const struct regset *regset,
++ struct regcache *regcache, int regno,
++ const void *gregs, size_t len)
++{
++ if (regno == -1)
++ {
++ for (regno = 0; regno < NUM_REGS; regno++)
++ {
++ if (GREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (regcache, regno, gregs);
++ }
++ }
++ else
++ if (GREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (regcache, regno, gregs);
++}
++
++static void
++ia64_fbsd_supply_fpregset (const struct regset *regset,
++ struct regcache *regcache, int regno,
++ const void *fpregs, size_t len)
++{
++ if (regno == -1)
++ {
++ for (regno = 0; regno < NUM_REGS; regno++)
++ {
++ if (FPREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (regcache, regno, fpregs);
++ }
++ }
++ else
++ if (FPREG_SUPPLIES(regno))
++ ia64_fbsd_regcache_supply (regcache, regno, fpregs);
++}
++
++static struct regset gregset = { NULL, ia64_fbsd_supply_gregset };
++static struct regset fpregset = { NULL, ia64_fbsd_supply_fpregset };
++
++static const struct regset *
++ia64_fbsd_regset_from_core_section (struct gdbarch *gdbarch,
++ const char *sect_name, size_t sect_size)
++{
++ if (strcmp (sect_name, ".reg") == 0)
++ return (&gregset);
++ if (strcmp (sect_name, ".reg2") == 0)
++ return (&fpregset);
++ return (NULL);
++}
++
++static int
++ia64_fbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
++{
++ uint64_t gwpage = 5ULL << 61;
++ return (pc >= gwpage && pc < (gwpage + 8192)) ? 1 : 0;
++}
++
++static void
++ia64_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++
++ set_gdbarch_pc_in_sigtramp (gdbarch, ia64_fbsd_pc_in_sigtramp);
++ set_gdbarch_regset_from_core_section (gdbarch,
++ ia64_fbsd_regset_from_core_section);
++ set_solib_svr4_fetch_link_map_offsets (gdbarch,
++ svr4_lp64_fetch_link_map_offsets);
++ tdep->find_global_pointer = ia64_generic_find_global_pointer;
++}
++
++void
++_initialize_ia64_fbsd_tdep (void)
++{
++ gdbarch_register_osabi (bfd_arch_ia64, 0ul, GDB_OSABI_FREEBSD_ELF,
++ ia64_fbsd_init_abi);
++}
+Index: gdb/ia64-tdep.c
+===================================================================
+RCS file: /home/marcel/CVS/gdb6/gdb/ia64-tdep.c,v
+retrieving revision 1.1.1.3
+retrieving revision 1.5
+diff -u -r1.1.1.3 -r1.5
+--- gdb/ia64-tdep.c 16 Apr 2004 00:51:25 -0000 1.1.1.3
++++ gdb/ia64-tdep.c 16 Apr 2004 01:28:33 -0000 1.5
+@@ -45,17 +45,6 @@
+ #include "libunwind-ia64.h"
+ #endif
+
+-/* Hook for determining the global pointer when calling functions in
+- the inferior under AIX. The initialization code in ia64-aix-nat.c
+- sets this hook to the address of a function which will find the
+- global pointer for a given address.
+-
+- The generic code which uses the dynamic section in the inferior for
+- finding the global pointer is not of much use on AIX since the
+- values obtained from the inferior have not been relocated. */
+-
+-CORE_ADDR (*native_find_global_pointer) (CORE_ADDR) = 0;
+-
+ /* An enumeration of the different IA-64 instruction types. */
+
+ typedef enum instruction_type
+@@ -256,20 +245,6 @@
+
+ };
+
+-struct gdbarch_tdep
+- {
+- CORE_ADDR (*sigcontext_register_address) (CORE_ADDR, int);
+- /* OS specific function which, given a frame address
+- and register number, returns the offset to the
+- given register from the start of the frame. */
+- CORE_ADDR (*find_global_pointer) (CORE_ADDR);
+- };
+-
+-#define SIGCONTEXT_REGISTER_ADDRESS \
+- (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
+-#define FIND_GLOBAL_POINTER \
+- (gdbarch_tdep (current_gdbarch)->find_global_pointer)
+-
+ int
+ ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+@@ -682,9 +657,18 @@
+
+ if ((cfm & 0x7f) > regnum - V32_REGNUM)
+ {
++ ULONGEST bspstore;
+ ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
+- reg = read_memory_integer ((CORE_ADDR)reg_addr, 8);
+- store_unsigned_integer (buf, register_size (current_gdbarch, regnum), reg);
++ regcache_cooked_read_unsigned (regcache, IA64_BSPSTORE_REGNUM,
++ &bspstore);
++ if (reg_addr < bspstore) {
++ reg = read_memory_integer ((CORE_ADDR)reg_addr, 8);
++ store_unsigned_integer (buf, register_size (current_gdbarch,
++ regnum), reg);
++ } else
++ target_read_partial (&current_target, TARGET_OBJECT_DIRTY,
++ (void*)bspstore, buf, reg_addr - bspstore,
++ register_size (current_gdbarch, regnum));
+ }
+ else
+ store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
+@@ -725,7 +709,21 @@
+ if (nat_addr >= bsp)
+ regcache_cooked_read_unsigned (regcache, IA64_RNAT_REGNUM, &nat_collection);
+ else
+- nat_collection = read_memory_integer (nat_addr, 8);
++ {
++ ULONGEST bspstore;
++ regcache_cooked_read_unsigned (regcache, IA64_BSPSTORE_REGNUM,
++ &bspstore);
++ if (nat_addr < bspstore)
++ nat_collection = read_memory_integer (nat_addr, 8);
++ else {
++ char natbuf[8];
++ target_read_partial (&current_target, TARGET_OBJECT_DIRTY,
++ (void*)bspstore, natbuf,
++ nat_addr - bspstore,
++ register_size (current_gdbarch, regnum));
++ nat_collection = *((uint64_t*)natbuf);
++ }
++ }
+ nat_bit = (gr_addr >> 3) & 0x3f;
+ natN_val = (nat_collection >> nat_bit) & 1;
+ }
+@@ -789,8 +787,16 @@
+
+ if ((cfm & 0x7f) > regnum - V32_REGNUM)
+ {
++ ULONGEST bspstore;
+ ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
+- write_memory (reg_addr, (void *)buf, 8);
++ regcache_cooked_read_unsigned (regcache, IA64_BSPSTORE_REGNUM,
++ &bspstore);
++ if (reg_addr < bspstore)
++ write_memory (reg_addr, (void *)buf, 8);
++ else
++ target_write_partial (&current_target, TARGET_OBJECT_DIRTY,
++ (void*)bspstore, buf, reg_addr - bspstore,
++ register_size (current_gdbarch, regnum));
+ }
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
+@@ -845,13 +851,33 @@
+ else
+ {
+ char nat_buf[8];
+- nat_collection = read_memory_integer (nat_addr, 8);
++ ULONGEST bspstore;
++ regcache_cooked_read_unsigned (regcache, IA64_BSPSTORE_REGNUM,
++ &bspstore);
++ if (nat_addr < bspstore)
++ nat_collection = read_memory_integer (nat_addr, 8);
++ else {
++ char natbuf[8];
++ target_read_partial (&current_target, TARGET_OBJECT_DIRTY,
++ (void*)bspstore, natbuf,
++ nat_addr - bspstore,
++ register_size (current_gdbarch, regnum));
++ nat_collection = *((uint64_t*)natbuf);
++ }
+ if (natN_val)
+ nat_collection |= natN_mask;
+ else
+ nat_collection &= ~natN_mask;
+- store_unsigned_integer (nat_buf, register_size (current_gdbarch, regnum), nat_collection);
+- write_memory (nat_addr, nat_buf, 8);
++ store_unsigned_integer (nat_buf, register_size (current_gdbarch,
++ regnum),
++ nat_collection);
++ if (nat_addr < bspstore)
++ write_memory (nat_addr, nat_buf, 8);
++ else
++ target_write_partial (&current_target, TARGET_OBJECT_DIRTY,
++ (void*)bspstore, nat_buf,
++ nat_addr - bspstore,
++ register_size (current_gdbarch, regnum));
+ }
+ }
+ }
+@@ -1813,6 +1839,7 @@
+ prev_bof = rse_address_add (prev_bsp, -(prev_cfm & 0x7f));
+
+ addr = rse_address_add (prev_bof, (regnum - IA64_GR32_REGNUM));
++ /* XXX marcel */
+ *lvalp = lval_memory;
+ *addrp = addr;
+ read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+@@ -2858,8 +2885,8 @@
+ DT_PLTGOT tag. If it finds one of these, the corresponding
+ d_un.d_ptr value is the global pointer. */
+
+-static CORE_ADDR
+-generic_elf_find_global_pointer (CORE_ADDR faddr)
++CORE_ADDR
++ia64_generic_find_global_pointer (CORE_ADDR faddr)
+ {
+ struct obj_section *faddr_sect;
+
+@@ -3255,32 +3282,9 @@
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+-
+- /* Set the method of obtaining the sigcontext addresses at which
+- registers are saved. The method of checking to see if
+- native_find_global_pointer is nonzero to indicate that we're
+- on AIX is kind of hokey, but I can't think of a better way
+- to do it. */
+- if (info.osabi == GDB_OSABI_LINUX)
+- tdep->sigcontext_register_address = ia64_linux_sigcontext_register_address;
+- else if (native_find_global_pointer != 0)
+- tdep->sigcontext_register_address = ia64_aix_sigcontext_register_address;
+- else
+- tdep->sigcontext_register_address = 0;
+-
+- /* We know that GNU/Linux won't have to resort to the
+- native_find_global_pointer hackery. But that's the only one we
+- know about so far, so if native_find_global_pointer is set to
+- something non-zero, then use it. Otherwise fall back to using
+- generic_elf_find_global_pointer. This arrangement should (in
+- theory) allow us to cross debug GNU/Linux binaries from an AIX
+- machine. */
+- if (info.osabi == GDB_OSABI_LINUX)
+- tdep->find_global_pointer = generic_elf_find_global_pointer;
+- else if (native_find_global_pointer != 0)
+- tdep->find_global_pointer = native_find_global_pointer;
+- else
+- tdep->find_global_pointer = generic_elf_find_global_pointer;
++ tdep->osabi = info.osabi;
++ tdep->sigcontext_register_address = NULL;
++ tdep->find_global_pointer = ia64_generic_find_global_pointer;
+
+ /* Define the ia64 floating-point format to gdb. */
+ builtin_type_ia64_ext =
+@@ -3338,10 +3342,7 @@
+ set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint);
+ set_gdbarch_breakpoint_from_pc (gdbarch, ia64_breakpoint_from_pc);
+ set_gdbarch_read_pc (gdbarch, ia64_read_pc);
+- if (info.osabi == GDB_OSABI_LINUX)
+- set_gdbarch_write_pc (gdbarch, ia64_linux_write_pc);
+- else
+- set_gdbarch_write_pc (gdbarch, ia64_write_pc);
++ set_gdbarch_write_pc (gdbarch, ia64_write_pc);
+
+ /* Settings for calling functions in the inferior. */
+ set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call);
+@@ -3365,6 +3366,8 @@
+
+ set_gdbarch_print_insn (gdbarch, ia64_print_insn);
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch, ia64_convert_from_func_ptr_addr);
++
++ gdbarch_init_osabi (info, gdbarch);
+
+ return gdbarch;
+ }
+Index: gdb/ia64-tdep.h
+===================================================================
+RCS file: /home/marcel/CVS/gdb6/gdb/ia64-tdep.h,v
+retrieving revision 1.1.1.1
+retrieving revision 1.2
+diff -u -r1.1.1.1 -r1.2
+--- gdb/ia64-tdep.h 26 Mar 2004 02:54:41 -0000 1.1.1.1
++++ gdb/ia64-tdep.h 28 Mar 2004 03:47:34 -0000 1.2
+@@ -22,10 +22,25 @@
+ #ifndef IA64_TDEP_H
+ #define IA64_TDEP_H
+
+-extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int);
+-extern CORE_ADDR ia64_aix_sigcontext_register_address (CORE_ADDR, int);
+-extern unsigned long ia64_linux_getunwind_table (void *, size_t);
+-extern void ia64_write_pc (CORE_ADDR, ptid_t);
+-extern void ia64_linux_write_pc (CORE_ADDR, ptid_t);
++#include "osabi.h"
++
++/* Target-dependent structure in gdbarch. */
++struct gdbarch_tdep
++{
++ enum gdb_osabi osabi; /* OS/ABI of inferior. */
++
++ CORE_ADDR (*sigcontext_register_address) (CORE_ADDR, int);
++ /* OS specific function which, given a frame address
++ and register number, returns the offset to the
++ given register from the start of the frame. */
++ CORE_ADDR (*find_global_pointer) (CORE_ADDR);
++};
++
++#define SIGCONTEXT_REGISTER_ADDRESS \
++ (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
++#define FIND_GLOBAL_POINTER \
++ (gdbarch_tdep (current_gdbarch)->find_global_pointer)
++
++extern CORE_ADDR ia64_generic_find_global_pointer (CORE_ADDR);
+
+ #endif /* IA64_TDEP_H */
+Index: gdb/inftarg.c
+===================================================================
+RCS file: /home/marcel/CVS/gdb6/gdb/inftarg.c,v
+retrieving revision 1.1.1.1
+retrieving revision 1.2
+diff -u -r1.1.1.1 -r1.2
+--- gdb/inftarg.c 26 Mar 2004 02:54:41 -0000 1.1.1.1
++++ gdb/inftarg.c 28 Mar 2004 03:47:34 -0000 1.2
+@@ -592,6 +592,13 @@
+ return NATIVE_XFER_WCOOKIE (ops, object, annex, readbuf, writebuf,
+ offset, len);
+
++ case TARGET_OBJECT_DIRTY:
++#ifndef TARGET_XFER_DIRTY
++#define TARGET_XFER_DIRTY(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
++#endif
++ return TARGET_XFER_DIRTY (ops, object, annex, readbuf, writebuf,
++ offset, len);
++
+ default:
+ return -1;
+ }
+Index: gdb/remote.c
+===================================================================
+RCS file: /home/marcel/CVS/gdb6/gdb/remote.c,v
+retrieving revision 1.1.1.3
+retrieving revision 1.5
+diff -u -r1.1.1.3 -r1.5
+--- gdb/remote.c 16 Apr 2004 00:51:28 -0000 1.1.1.3
++++ gdb/remote.c 16 Apr 2004 01:28:33 -0000 1.5
+@@ -998,6 +998,23 @@
+ show_packet_config_cmd (&remote_protocol_qPart_auxv);
+ }
+
++/* Should we try the 'qPart:dirty' (target dirty register read) request? */
++static struct packet_config remote_protocol_qPart_dirty;
++
++static void
++set_remote_protocol_qPart_dirty_packet_cmd (char *args, int from_tty,
++ struct cmd_list_element *c)
++{
++ update_packet_config (&remote_protocol_qPart_dirty);
++}
++
++static void
++show_remote_protocol_qPart_dirty_packet_cmd (char *args, int from_tty,
++ struct cmd_list_element *c)
++{
++ show_packet_config_cmd (&remote_protocol_qPart_dirty);
++}
++
+
+ /* Tokens for use by the asynchronous signal handlers for SIGINT */
+ static void *sigint_remote_twice_token;
+@@ -2088,6 +2105,7 @@
+ downloading. */
+ update_packet_config (&remote_protocol_binary_download);
+ update_packet_config (&remote_protocol_qPart_auxv);
++ update_packet_config (&remote_protocol_qPart_dirty);
+ }
+
+ /* Symbol look-up. */
+@@ -4925,6 +4943,23 @@
+ }
+ return -1;
+
++ case TARGET_OBJECT_DIRTY:
++ if (remote_protocol_qPart_dirty.support != PACKET_DISABLE)
++ {
++ snprintf (buf2, rs->remote_packet_size, "qPart:dirty:read::%lx",
++ (long)(offset >> 3));
++ i = putpkt (buf2);
++ if (i < 0)
++ return i;
++ buf2[0] = '\0';
++ getpkt (buf2, rs->remote_packet_size, 0);
++ if (packet_ok (buf2, &remote_protocol_qPart_dirty) != PACKET_OK)
++ return -1;
++ i = hex2bin (buf2, readbuf, len);
++ return i;
++ }
++ return -1;
++
+ default:
+ return -1;
+ }
+@@ -5423,6 +5458,7 @@
+ show_remote_protocol_vcont_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_binary_download_cmd (args, from_tty, NULL);
+ show_remote_protocol_qPart_auxv_packet_cmd (args, from_tty, NULL);
++ show_remote_protocol_qPart_dirty_packet_cmd (args, from_tty, NULL);
+ }
+
+ static void
+@@ -5670,6 +5706,13 @@
+ "qPart_auxv", "read-aux-vector",
+ set_remote_protocol_qPart_auxv_packet_cmd,
+ show_remote_protocol_qPart_auxv_packet_cmd,
++ &remote_set_cmdlist, &remote_show_cmdlist,
++ 0);
++
++ add_packet_config_cmd (&remote_protocol_qPart_dirty,
++ "qPart_dirty", "read-dirty-registers",
++ set_remote_protocol_qPart_dirty_packet_cmd,
++ show_remote_protocol_qPart_dirty_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+Index: gdb/target.h
+===================================================================
+RCS file: /home/marcel/CVS/gdb6/gdb/target.h,v
+retrieving revision 1.1.1.1
+retrieving revision 1.2
+diff -u -r1.1.1.1 -r1.2
+--- gdb/target.h 26 Mar 2004 02:54:42 -0000 1.1.1.1
++++ gdb/target.h 28 Mar 2004 03:47:34 -0000 1.2
+@@ -229,7 +229,9 @@
+ /* Transfer auxilliary vector. */
+ TARGET_OBJECT_AUXV,
+ /* StackGhost cookie. See "sparc-tdep.c". */
+- TARGET_OBJECT_WCOOKIE
++ TARGET_OBJECT_WCOOKIE,
++ /* Dirty registers. See "ia64-tdep.c". */
++ TARGET_OBJECT_DIRTY
+
+ /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
+ };
+Index: gdb/config/ia64/fbsd.mh
+===================================================================
+RCS file: gdb/config/ia64/fbsd.mh
+diff -N gdb/config/ia64/fbsd.mh
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ gdb/config/ia64/fbsd.mh 25 Jun 2004 03:55:31 -0000
+@@ -0,0 +1,3 @@
++NATDEPFILES= fbsd-proc.o fbsd-thread.o fork-child.o gcore.o \
++ ia64-fbsd-nat.o infptrace.o inftarg.o
++NAT_FILE= nm-fbsd.h
+Index: gdb/config/ia64/fbsd.mt
+===================================================================
+RCS file: gdb/config/ia64/fbsd.mt
+diff -N gdb/config/ia64/fbsd.mt
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ gdb/config/ia64/fbsd.mt 28 Mar 2004 03:47:38 -0000 1.1
+@@ -0,0 +1,2 @@
++TDEPFILES= corelow.o ia64-fbsd-tdep.o ia64-tdep.o solib.o solib-svr4.o
++TM_FILE= tm-fbsd.h
+Index: gdb/config/ia64/nm-fbsd.h
+===================================================================
+RCS file: gdb/config/ia64/nm-fbsd.h
+diff -N gdb/config/ia64/nm-fbsd.h
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ gdb/config/ia64/nm-fbsd.h 16 Apr 2004 02:49:16 -0000 1.2
+@@ -0,0 +1,24 @@
++/* GNU GPL */
++
++#ifndef NM_FBSD_H
++#define NM_FBSD_H
++
++/* Type of the third argument to the `ptrace' system call. */
++#define PTRACE_ARG3_TYPE caddr_t
++
++/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
++#define FETCH_INFERIOR_REGISTERS
++
++/* We can attach and detach. */
++#define ATTACH_DETACH
++
++/* Override child_pid_to_exec_file in 'inftarg.c'. */
++#define CHILD_PID_TO_EXEC_FILE
++
++#include "target.h"
++
++#define TARGET_XFER_DIRTY ia64_fbsd_xfer_dirty
++extern LONGEST ia64_fbsd_xfer_dirty(struct target_ops *, enum target_object,
++ const char *, void *, const void *, ULONGEST, LONGEST);
++
++#endif /* NM_FBSD_H */
+Index: gdb/config/ia64/tm-fbsd.h
+===================================================================
+RCS file: gdb/config/ia64/tm-fbsd.h
+diff -N gdb/config/ia64/tm-fbsd.h
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ gdb/config/ia64/tm-fbsd.h 17 Apr 2004 01:43:21 -0000 1.2
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (c) 2004 Marcel Moolenaar
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
++ */
++
++#ifndef TM_FBSD_H
++#define TM_FBSD_H
++
++#include "solib.h"
++
++#include "ia64/tm-ia64.h"
++
++#endif /* TM_FBSD_H */
diff --git a/contrib/gdb/FREEBSD-upgrade b/contrib/gdb/FREEBSD-upgrade
new file mode 100644
index 0000000..ac98f9c
--- /dev/null
+++ b/contrib/gdb/FREEBSD-upgrade
@@ -0,0 +1,9 @@
+$FreeBSD$
+
+To strip down a new version of gdb for import, extract the files like this:
+
+ tar xzf gdb-6.1.1.tar.gz -X FREEBSD-Xlist
+
+After importing, remove files on the vendor branch that are not part of the
+new gdb version (if any). Then remove files from HEAD that are not part of
+the new version (if applicable).
diff --git a/contrib/gdb/README b/contrib/gdb/README
new file mode 100644
index 0000000..eb0e436
--- /dev/null
+++ b/contrib/gdb/README
@@ -0,0 +1,47 @@
+ 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 binutils release, see binutils/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
+
+A similar example using csh:
+
+ setenv CC gcc
+ ./configure
+ make
+
+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, binutils/README, etc., for info
+on where and how to report problems.
diff --git a/contrib/gdb/config-ml.in b/contrib/gdb/config-ml.in
new file mode 100644
index 0000000..b2e4ea9
--- /dev/null
+++ b/contrib/gdb/config-ml.in
@@ -0,0 +1,877 @@
+# Configure fragment invoked in the post-target section for subdirs
+# wanting multilib support.
+#
+# Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+#
+# Please report bugs to <gcc-bugs@gnu.org>
+# and send patches to <gcc-patches@gnu.org>.
+
+# It is advisable to support a few --enable/--disable options to let the
+# user select which libraries s/he really wants.
+#
+# Subdirectories wishing to use multilib should put the following lines
+# in the "post-target" section of configure.in.
+#
+# if [ "${srcdir}" = "." ] ; then
+# if [ "${with_target_subdir}" != "." ] ; then
+# . ${with_multisrctop}../../config-ml.in
+# else
+# . ${with_multisrctop}../config-ml.in
+# fi
+# else
+# . ${srcdir}/../config-ml.in
+# fi
+#
+#
+# Things are complicated because 6 separate cases must be handled:
+# 2 (native, cross) x 3 (absolute-path, relative-not-dot, dot) = 6.
+#
+# srcdir=. is special. It must handle make programs that don't handle VPATH.
+# To implement this, a symlink tree is built for each library and for each
+# multilib subdir.
+#
+# The build tree is layed out as
+#
+# ./
+# newlib
+# m68020/
+# newlib
+# m68881/
+# newlib
+#
+# The nice feature about this arrangement is that inter-library references
+# in the build tree work without having to care where you are. Note that
+# inter-library references also work in the source tree because symlink trees
+# are built when srcdir=.
+#
+# Unfortunately, trying to access the libraries in the build tree requires
+# the user to manually choose which library to use as GCC won't be able to
+# find the right one. This is viewed as the lesser of two evils.
+#
+# Configure variables:
+# ${with_target_subdir} = "." for native, or ${target_alias} for cross.
+# Set by top level Makefile.
+# ${with_multisrctop} = how many levels of multilibs there are in the source
+# tree. It exists to handle the case of configuring in the source tree:
+# ${srcdir} is not constant.
+# ${with_multisubdir} = name of multilib subdirectory (eg: m68020/m68881).
+#
+# Makefile variables:
+# MULTISRCTOP = number of multilib levels in source tree (+1 if cross)
+# (FIXME: note that this is different than ${with_multisrctop}. Check out.).
+# MULTIBUILDTOP = number of multilib levels in build tree
+# MULTIDIRS = list of multilib subdirs (eg: m68000 m68020 ...)
+# (only defined in each library's main Makefile).
+# MULTISUBDIR = installed subdirectory name with leading '/' (eg: /m68000)
+# (only defined in each multilib subdir).
+
+# FIXME: Multilib is currently disabled by default for everything other than
+# newlib. It is up to each target to turn on multilib support for the other
+# libraries as desired.
+
+# Autoconf incoming variables:
+# srcdir, host, ac_configure_args
+#
+# We *could* figure srcdir and host out, but we'd have to do work that
+# our caller has already done to figure them out and requiring these two
+# seems reasonable.
+# Note that `host' in this case is GCC's `target'. Target libraries are
+# configured for a particular host.
+
+Makefile=${ac_file-Makefile}
+ml_config_shell=${CONFIG_SHELL-/bin/sh}
+ml_realsrcdir=${srcdir}
+
+# Scan all the arguments and set all the ones we need.
+
+ml_verbose=--verbose
+for option in ${ac_configure_args}
+do
+ case $option in
+ --*) ;;
+ -*) option=-$option ;;
+ esac
+
+ case $option in
+ --*=*)
+ optarg=`echo $option | sed -e 's/^[^=]*=//'`
+ ;;
+ esac
+
+ case $option in
+ --disable-*)
+ enableopt=`echo ${option} | sed 's:^--disable-:enable_:;s:-:_:g'`
+ eval $enableopt=no
+ ;;
+ --enable-*)
+ case "$option" in
+ *=*) ;;
+ *) optarg=yes ;;
+ esac
+ enableopt=`echo ${option} | sed 's:^--::;s:=.*$::;s:-:_:g'`
+ eval $enableopt="$optarg"
+ ;;
+ --norecursion | --no-recursion)
+ ml_norecursion=yes
+ ;;
+ --silent | --sil* | --quiet | --q*)
+ ml_verbose=--silent
+ ;;
+ --verbose | --v | --verb*)
+ ml_verbose=--verbose
+ ;;
+ --with-*)
+ case "$option" in
+ *=*) ;;
+ *) optarg=yes ;;
+ esac
+ withopt=`echo ${option} | sed 's:^--::;s:=.*$::;s:-:_:g'`
+ eval $withopt="$optarg"
+ ;;
+ --without-*)
+ withopt=`echo ${option} | sed 's:^--::;s:out::;s:-:_:g'`
+ eval $withopt=no
+ ;;
+ esac
+done
+
+# Only do this if --enable-multilib.
+if [ "${enable_multilib}" = yes ]; then
+
+# Compute whether this is the library's top level directory
+# (ie: not a multilib subdirectory, and not a subdirectory like newlib/src).
+# ${with_multisubdir} tells us we're in the right branch, but we could be
+# in a subdir of that.
+# ??? The previous version could void this test by separating the process into
+# two files: one that only the library's toplevel configure.in ran (to
+# configure the multilib subdirs), and another that all configure.in's ran to
+# update the Makefile. It seemed reasonable to collapse all multilib support
+# into one file, but it does leave us with having to perform this test.
+ml_toplevel_p=no
+if [ -z "${with_multisubdir}" ]; then
+ if [ "${srcdir}" = "." ]; then
+ # Use ${ml_realsrcdir} instead of ${srcdir} here to account for ${subdir}.
+ # ${with_target_subdir} = "." for native, otherwise target alias.
+ if [ "${with_target_subdir}" = "." ]; then
+ if [ -f ${ml_realsrcdir}/../config-ml.in ]; then
+ ml_toplevel_p=yes
+ fi
+ else
+ if [ -f ${ml_realsrcdir}/../../config-ml.in ]; then
+ ml_toplevel_p=yes
+ fi
+ fi
+ else
+ # Use ${ml_realsrcdir} instead of ${srcdir} here to account for ${subdir}.
+ if [ -f ${ml_realsrcdir}/../config-ml.in ]; then
+ ml_toplevel_p=yes
+ fi
+ fi
+fi
+
+# If this is the library's top level directory, set multidirs to the
+# multilib subdirs to support. This lives at the top because we need
+# `multidirs' set right away.
+
+if [ "${ml_toplevel_p}" = yes ]; then
+
+multidirs=
+for i in `${CC-gcc} --print-multi-lib 2>/dev/null`; do
+ dir=`echo $i | sed -e 's/;.*$//'`
+ if [ "${dir}" = "." ]; then
+ true
+ else
+ if [ -z "${multidirs}" ]; then
+ multidirs="${dir}"
+ else
+ multidirs="${multidirs} ${dir}"
+ fi
+ fi
+done
+
+# Target libraries are configured for the host they run on, so we check
+# $host here, not $target.
+
+case "${host}" in
+arc-*-elf*)
+ if [ x$enable_biendian != xyes ]
+ then
+ old_multidirs=${multidirs}
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "${x}" in
+ *be*) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ ;;
+arm-*-*)
+ if [ x"$enable_fpu" = xno ]
+ then
+ old_multidirs=${multidirs}
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "${x}" in
+ *fpu*) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x"$enable_26bit" = xno ]
+ then
+ old_multidirs=${multidirs}
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "${x}" in
+ *26bit*) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x"$enable_underscore" = xno ]
+ then
+ old_multidirs=${multidirs}
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "${x}" in
+ *under*) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x"$enable_interwork" = xno ]
+ then
+ old_multidirs=${multidirs}
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "${x}" in
+ *interwork*) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_biendian = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *le* ) : ;;
+ *be* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x"$enable_nofmult" = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *nofmult* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ ;;
+m68*-*-*)
+ if [ x$enable_softfloat = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *soft-float* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_m68881 = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *m68881* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_m68000 = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *m68000* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_m68020 = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *m68020* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ ;;
+mips*-*-*)
+ if [ x$enable_single_float = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *single* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_biendian = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *el* ) : ;;
+ *eb* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_softfloat = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *soft-float* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ case " $multidirs " in
+ *" mabi=64 "*)
+ # We will not be able to create libraries with -mabi=64 if
+ # we cannot even link a trivial program. It usually
+ # indicates the 64bit libraries are missing.
+ if echo 'main() {}' > conftest.c &&
+ ${CC-gcc} -mabi=64 conftest.c -o conftest; then
+ :
+ else
+ echo Could not link program with -mabi=64, disabling it.
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *mabi=64* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ rm -f conftest.c conftest
+ ;;
+ esac
+ ;;
+powerpc*-*-* | rs6000*-*-*)
+ if [ x$enable_aix64 = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *ppc64* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_pthread = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *pthread* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_softfloat = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *soft-float* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_powercpu = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ power | */power | */power/* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_powerpccpu = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *powerpc* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_powerpcos = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *mcall-linux* | *mcall-solaris* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_biendian = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *mlittle* | *mbig* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ if [ x$enable_sysv = xno ]
+ then
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *mcall-sysv* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ ;;
+sparc*-*-*)
+ case " $multidirs " in
+ *" m64 "*)
+ # We will not be able to create libraries with -m64 if
+ # we cannot even link a trivial program. It usually
+ # indicates the 64bit libraries are missing.
+ if echo 'main() {}' > conftest.c &&
+ ${CC-gcc} -m64 conftest.c -o conftest; then
+ :
+ else
+ echo Could not link program with -m64, disabling it.
+ old_multidirs="${multidirs}"
+ multidirs=""
+ for x in ${old_multidirs}; do
+ case "$x" in
+ *m64* ) : ;;
+ *) multidirs="${multidirs} ${x}" ;;
+ esac
+ done
+ fi
+ rm -f conftest.c conftest
+ ;;
+ esac
+ ;;
+esac
+
+# Remove extraneous blanks from multidirs.
+# Tests like `if [ -n "$multidirs" ]' require it.
+multidirs=`echo "$multidirs" | sed -e 's/^[ ][ ]*//' -e 's/[ ][ ]*$//' -e 's/[ ][ ]*/ /g'`
+
+# Add code to library's top level makefile to handle building the multilib
+# subdirs.
+
+cat > Multi.tem <<\EOF
+
+PWD_COMMAND=$${PWDCMD-pwd}
+
+# FIXME: There should be an @-sign in front of the `if'.
+# Leave out until this is tested a bit more.
+multi-do:
+ if [ -z "$(MULTIDIRS)" ]; then \
+ true; \
+ else \
+ rootpre=`${PWD_COMMAND}`/; export rootpre; \
+ srcrootpre=`cd $(srcdir); ${PWD_COMMAND}`/; export srcrootpre; \
+ lib=`echo $${rootpre} | sed -e 's,^.*/\([^/][^/]*\)/$$,\1,'`; \
+ compiler="$(CC)"; \
+ for i in `$${compiler} --print-multi-lib 2>/dev/null`; do \
+ dir=`echo $$i | sed -e 's/;.*$$//'`; \
+ if [ "$${dir}" = "." ]; then \
+ true; \
+ else \
+ if [ -d ../$${dir}/$${lib} ]; then \
+ flags=`echo $$i | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`; \
+ if (cd ../$${dir}/$${lib}; $(MAKE) $(FLAGS_TO_PASS) \
+ CFLAGS="$(CFLAGS) $${flags}" \
+ prefix="$(prefix)" \
+ exec_prefix="$(exec_prefix)" \
+ GCJFLAGS="$(GCJFLAGS) $${flags}" \
+ CXXFLAGS="$(CXXFLAGS) $${flags}" \
+ LIBCFLAGS="$(LIBCFLAGS) $${flags}" \
+ LIBCXXFLAGS="$(LIBCXXFLAGS) $${flags}" \
+ LDFLAGS="$(LDFLAGS) $${flags}" \
+ MULTIFLAGS="$${flags}" \
+ DESTDIR="$(DESTDIR)" \
+ INSTALL="$(INSTALL)" \
+ INSTALL_DATA="$(INSTALL_DATA)" \
+ INSTALL_PROGRAM="$(INSTALL_PROGRAM)" \
+ INSTALL_SCRIPT="$(INSTALL_SCRIPT)" \
+ $(DO)); then \
+ true; \
+ else \
+ exit 1; \
+ fi; \
+ else true; \
+ fi; \
+ fi; \
+ done; \
+ fi
+
+# FIXME: There should be an @-sign in front of the `if'.
+# Leave out until this is tested a bit more.
+multi-clean:
+ if [ -z "$(MULTIDIRS)" ]; then \
+ true; \
+ else \
+ lib=`${PWD_COMMAND} | sed -e 's,^.*/\([^/][^/]*\)$$,\1,'`; \
+ for dir in Makefile $(MULTIDIRS); do \
+ if [ -f ../$${dir}/$${lib}/Makefile ]; then \
+ if (cd ../$${dir}/$${lib}; $(MAKE) $(FLAGS_TO_PASS) $(DO)); \
+ then true; \
+ else exit 1; \
+ fi; \
+ else true; \
+ fi; \
+ done; \
+ fi
+EOF
+
+cat ${Makefile} Multi.tem > Makefile.tem
+rm -f ${Makefile} Multi.tem
+mv Makefile.tem ${Makefile}
+
+fi # ${ml_toplevel_p} = yes
+
+if [ "${ml_verbose}" = --verbose ]; then
+ echo "Adding multilib support to Makefile in ${ml_realsrcdir}"
+ if [ "${ml_toplevel_p}" = yes ]; then
+ echo "multidirs=${multidirs}"
+ fi
+ echo "with_multisubdir=${with_multisubdir}"
+fi
+
+if [ "${srcdir}" = "." ]; then
+ if [ "${with_target_subdir}" != "." ]; then
+ ml_srcdotdot="../"
+ else
+ ml_srcdotdot=""
+ fi
+else
+ ml_srcdotdot=""
+fi
+
+if [ -z "${with_multisubdir}" ]; then
+ ml_subdir=
+ ml_builddotdot=
+ : # ml_srcdotdot= # already set
+else
+ ml_subdir="/${with_multisubdir}"
+ # The '[^/][^/]*' appears that way to work around a SunOS sed bug.
+ ml_builddotdot=`echo ${with_multisubdir} | sed -e 's:[^/][^/]*:..:g'`/
+ if [ "$srcdir" = "." ]; then
+ ml_srcdotdot=${ml_srcdotdot}${ml_builddotdot}
+ else
+ : # ml_srcdotdot= # already set
+ fi
+fi
+
+if [ "${ml_toplevel_p}" = yes ]; then
+ ml_do='$(MAKE)'
+ ml_clean='$(MAKE)'
+else
+ ml_do=true
+ ml_clean=true
+fi
+
+# TOP is used by newlib and should not be used elsewhere for this purpose.
+# MULTI{SRC,BUILD}TOP are the proper ones to use. MULTISRCTOP is empty
+# when srcdir != builddir. MULTIBUILDTOP is always some number of ../'s.
+# FIXME: newlib needs to be updated to use MULTI{SRC,BUILD}TOP so we can
+# delete TOP. Newlib may wish to continue to use TOP for its own purposes
+# of course.
+# MULTIDIRS is non-empty for the cpu top level Makefile (eg: newlib/Makefile)
+# and lists the subdirectories to recurse into.
+# MULTISUBDIR is non-empty in each cpu subdirectory's Makefile
+# (eg: newlib/h8300h/Makefile) and is the installed subdirectory name with
+# a leading '/'.
+# MULTIDO is used for targets like all, install, and check where
+# $(FLAGS_TO_PASS) augmented with the subdir's compiler option is needed.
+# MULTICLEAN is used for the *clean targets.
+#
+# ??? It is possible to merge MULTIDO and MULTICLEAN into one. They are
+# currently kept separate because we don't want the *clean targets to require
+# the existence of the compiler (which MULTIDO currently requires) and
+# therefore we'd have to record the directory options as well as names
+# (currently we just record the names and use --print-multi-lib to get the
+# options).
+
+sed -e "s:^TOP[ ]*=[ ]*\([./]*\)[ ]*$:TOP = ${ml_builddotdot}\1:" \
+ -e "s:^MULTISRCTOP[ ]*=.*$:MULTISRCTOP = ${ml_srcdotdot}:" \
+ -e "s:^MULTIBUILDTOP[ ]*=.*$:MULTIBUILDTOP = ${ml_builddotdot}:" \
+ -e "s:^MULTIDIRS[ ]*=.*$:MULTIDIRS = ${multidirs}:" \
+ -e "s:^MULTISUBDIR[ ]*=.*$:MULTISUBDIR = ${ml_subdir}:" \
+ -e "s:^MULTIDO[ ]*=.*$:MULTIDO = $ml_do:" \
+ -e "s:^MULTICLEAN[ ]*=.*$:MULTICLEAN = $ml_clean:" \
+ ${Makefile} > Makefile.tem
+rm -f ${Makefile}
+mv Makefile.tem ${Makefile}
+
+# If this is the library's top level, configure each multilib subdir.
+# This is done at the end because this is the loop that runs configure
+# in each multilib subdir and it seemed reasonable to finish updating the
+# Makefile before going on to configure the subdirs.
+
+if [ "${ml_toplevel_p}" = yes ]; then
+
+# We must freshly configure each subdirectory. This bit of code is
+# actually partially stolen from the main configure script. FIXME.
+
+if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
+
+ if [ "${ml_verbose}" = --verbose ]; then
+ echo "Running configure in multilib subdirs ${multidirs}"
+ echo "pwd: `${PWDCMD-pwd}`"
+ fi
+
+ ml_origdir=`${PWDCMD-pwd}`
+ ml_libdir=`echo $ml_origdir | sed -e 's,^.*/,,'`
+ # cd to top-level-build-dir/${with_target_subdir}
+ cd ..
+
+ for ml_dir in ${multidirs}; do
+
+ if [ "${ml_verbose}" = --verbose ]; then
+ echo "Running configure in multilib subdir ${ml_dir}"
+ echo "pwd: `${PWDCMD-pwd}`"
+ fi
+
+ if [ -d ${ml_dir} ]; then true; else
+ # ``mkdir -p ${ml_dir}'' See also mkinstalldirs.
+ pathcomp=""
+ for d in `echo ":${ml_dir}" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`; do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$?
+ fi
+ if test ! -d "$pathcomp"; then
+ exit $lasterr
+ fi
+ pathcomp="$pathcomp/"
+ done
+ fi
+ if [ -d ${ml_dir}/${ml_libdir} ]; then true; else mkdir ${ml_dir}/${ml_libdir}; fi
+
+ # Eg: if ${ml_dir} = m68000/m68881, dotdot = ../../
+ dotdot=../`echo ${ml_dir} | sed -e 's|[^/]||g' -e 's|/|../|g'`
+
+ case ${srcdir} in
+ ".")
+ echo Building symlink tree in `${PWDCMD-pwd}`/${ml_dir}/${ml_libdir}
+ if [ "${with_target_subdir}" != "." ]; then
+ ml_unsubdir="../"
+ else
+ ml_unsubdir=""
+ fi
+ (cd ${ml_dir}/${ml_libdir};
+ ../${dotdot}${ml_unsubdir}symlink-tree ../${dotdot}${ml_unsubdir}${ml_libdir} "")
+ if [ -f ${ml_dir}/${ml_libdir}/Makefile ]; then
+ if [ x"${MAKE}" = x ]; then
+ (cd ${ml_dir}/${ml_libdir}; make distclean)
+ else
+ (cd ${ml_dir}/${ml_libdir}; ${MAKE} distclean)
+ fi
+ fi
+ ml_newsrcdir="."
+ ml_srcdiroption=
+ multisrctop=${dotdot}
+ ;;
+ *)
+ case "${srcdir}" in
+ /* | [A-Za-z]:[\\/]* ) # absolute path
+ ml_newsrcdir=${srcdir}
+ ;;
+ *) # otherwise relative
+ ml_newsrcdir=${dotdot}${srcdir}
+ ;;
+ esac
+ ml_srcdiroption="-srcdir=${ml_newsrcdir}"
+ multisrctop=
+ ;;
+ esac
+
+ case "${progname}" in
+ /* | [A-Za-z]:[\\/]* ) ml_recprog=${progname} ;;
+ *) ml_recprog=${dotdot}${progname} ;;
+ esac
+
+ # FIXME: POPDIR=${PWD=`pwd`} doesn't work here.
+ ML_POPDIR=`${PWDCMD-pwd}`
+ cd ${ml_dir}/${ml_libdir}
+
+ if [ -f ${ml_newsrcdir}/configure ]; then
+ ml_recprog="${ml_newsrcdir}/configure"
+ fi
+
+ # find compiler flag corresponding to ${ml_dir}
+ for i in `${CC-gcc} --print-multi-lib 2>/dev/null`; do
+ dir=`echo $i | sed -e 's/;.*$//'`
+ if [ "${dir}" = "${ml_dir}" ]; then
+ flags=`echo $i | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`
+ break
+ fi
+ done
+ ml_config_env='CC="${CC_}$flags" CXX="${CXX_}$flags" GCJ="${GCJ_}$flags"'
+
+ if [ "${with_target_subdir}" = "." ]; then
+ CC_=$CC' '
+ CXX_=$CXX' '
+ GCJ_=$GCJ' '
+ else
+ # Create a regular expression that matches any string as long
+ # as ML_POPDIR.
+ popdir_rx=`echo ${ML_POPDIR} | sed 's,.,.,g'`
+ CC_=
+ for arg in ${CC}; do
+ case $arg in
+ -[BIL]"${ML_POPDIR}"/*)
+ CC_="${CC_}"`echo "X${arg}" | sed -n "s/X\\(-[BIL]${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X-[BIL]${popdir_rx}\\(.*\\)/\1/p"`' ' ;;
+ "${ML_POPDIR}"/*)
+ CC_="${CC_}"`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`' ' ;;
+ *)
+ CC_="${CC_}${arg} " ;;
+ esac
+ done
+
+ CXX_=
+ for arg in ${CXX}; do
+ case $arg in
+ -[BIL]"${ML_POPDIR}"/*)
+ CXX_="${CXX_}"`echo "X${arg}" | sed -n "s/X\\(-[BIL]${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X-[BIL]${popdir_rx}\\(.*\\)/\\1/p"`' ' ;;
+ "${ML_POPDIR}"/*)
+ CXX_="${CXX_}"`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`' ' ;;
+ *)
+ CXX_="${CXX_}${arg} " ;;
+ esac
+ done
+
+ GCJ_=
+ for arg in ${GCJ}; do
+ case $arg in
+ -[BIL]"${ML_POPDIR}"/*)
+ GCJ_="${GCJ_}"`echo "X${arg}" | sed -n "s/X\\(-[BIL]${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X-[BIL]${popdir_rx}\\(.*\\)/\\1/p"`' ' ;;
+ "${ML_POPDIR}"/*)
+ GCJ_="${GCJ_}"`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`' ' ;;
+ *)
+ GCJ_="${GCJ_}${arg} " ;;
+ esac
+ done
+
+ if test "x${LD_LIBRARY_PATH+set}" = xset; then
+ LD_LIBRARY_PATH_=
+ for arg in `echo "$LD_LIBRARY_PATH" | tr ':' ' '`; do
+ case "$arg" in
+ "${ML_POPDIR}"/*)
+ arg=`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`
+ ;;
+ esac
+ if test "x$LD_LIBRARY_PATH_" != x; then
+ LD_LIBRARY_PATH_=$LD_LIBRARY_PATH_:$arg
+ else
+ LD_LIBRARY_PATH_=$arg
+ fi
+ done
+ ml_config_env="$ml_config_env LD_LIBRARY_PATH=$LD_LIBRARY_PATH_"
+ fi
+
+ if test "x${SHLIB_PATH+set}" = xset; then
+ SHLIB_PATH_=
+ for arg in `echo "$SHLIB_PATH" | tr ':' ' '`; do
+ case "$arg" in
+ "${ML_POPDIR}"/*)
+ arg=`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`
+ ;;
+ esac
+ if test "x$SHLIB_PATH_" != x; then
+ SHLIB_PATH_=$SHLIB_PATH_:$arg
+ else
+ SHLIB_PATH_=$arg
+ fi
+ done
+ ml_config_env="$ml_config_env SHLIB_PATH=$SHLIB_PATH_"
+ fi
+ fi
+
+ if eval ${ml_config_env} ${ml_config_shell} ${ml_recprog} \
+ --with-multisubdir=${ml_dir} --with-multisrctop=${multisrctop} \
+ ${ac_configure_args} ${ml_srcdiroption} ; then
+ true
+ else
+ exit 1
+ fi
+
+ cd ${ML_POPDIR}
+
+ done
+
+ cd ${ml_origdir}
+fi
+
+fi # ${ml_toplevel_p} = yes
+fi # ${enable_multilib} = yes
diff --git a/contrib/gdb/djunpack.bat b/contrib/gdb/djunpack.bat
new file mode 100644
index 0000000..04b45c3
--- /dev/null
+++ b/contrib/gdb/djunpack.bat
@@ -0,0 +1,52 @@
+@echo off
+Rem
+Rem WARNING WARNING WARNING: This file needs to have DOS CRLF end-of-line
+Rem format, or else stock DOS/Windows shells will refuse to run it.
+Rem
+Rem This batch file unpacks the GDB distribution while simultaneously
+Rem renaming some of the files whose names are invalid on DOS or conflict
+Rem with other file names after truncation to DOS 8+3 namespace.
+Rem
+Rem Invoke like this:
+Rem
+Rem djunpack gdb-XYZ.tar
+Rem
+Rem where XYZ is the version number. If the argument includes leading
+Rem directories, it MUST use backslashes, not forward slashes.
+Rem
+Rem The following 2 lines need to be changed with each new GDB release, to
+Rem be identical to the name of the top-level directory where the GDB
+Rem distribution unpacks itself.
+set GDBVER=gdb-6.1.1
+if "%GDBVER%"=="gdb-6.1.1" GoTo EnvOk
+Rem If their environment space is too small, re-exec with a larger one
+command.com /e:4096 /c %0 %1
+GoTo End
+:EnvOk
+if not exist %1 GoTo NoArchive
+djtar -x -p -o %GDBVER%/gdb/config/djgpp/fnchange.lst %1 > fnchange.tmp
+Rem The following uses a feature of COPY whereby it does not copy
+Rem empty files. We need that because the previous line will create
+Rem an empty fnchange.tmp even if the command failed for some reason.
+copy fnchange.tmp junk.tmp > nul
+if not exist junk.tmp GoTo NoDjTar
+del junk.tmp
+sed -e 's,@V@,%GDBVER%,g' < fnchange.tmp > fnchange.lst
+Rem See the comment above about the reason for using COPY.
+copy fnchange.lst junk.tmp > nul
+if not exist junk.tmp GoTo NoSed
+del junk.tmp
+djtar -x -n fnchange.lst %1
+GoTo End
+:NoSed
+echo FAIL: Sed is not available.
+GoTo End
+:NoDjTar
+echo FAIL: DJTAR is not available or no fnchange.lst file in %1.
+GoTo End
+:NoArchive
+echo FAIL: the file %1 does not seem to exist.
+echo Remember that %1 cannot use forward slashes, only backslashes.
+GoTo End
+:End
+set GDBVER=
diff --git a/contrib/gdb/gdb/CONTRIBUTE b/contrib/gdb/gdb/CONTRIBUTE
new file mode 100644
index 0000000..96c943c
--- /dev/null
+++ b/contrib/gdb/gdb/CONTRIBUTE
@@ -0,0 +1,143 @@
+
+ Contributing to GDB
+
+GDB is a collaborative project and one which wants to encourage new
+development. You may wish to fix GDB bugs, improve testing, port GDB
+to a new platform, update documentation, add new GDB features, and the
+like. To help with this, there is a lot of documentation
+available.. In addition to the user guide and internals manual
+included in the GDB distribution, the GDB web pages also contain much
+information.
+
+You may also want to submit your change so that can be considered for
+conclusion in a future version of GDB (see below). Regardless, we
+encourage you to distribute the change yourself.
+
+If you don't feel up to hacking GDB, there are still plenty of ways to
+help! You can answer questions on the mailing lists, write
+documentation, find bugs, create a GDB related website (contribute to
+the official GDB web site), or create a GDB related software
+package. We welcome all of the above and feel free to ask on the GDB
+mailing lists if you are looking for feedback or for people to review
+a work in progress.
+
+Ref: http://www.gnu.org/software/gdb/
+
+Finally, there are certain legal requirements and style issues which
+all contributors need to be aware of.
+
+o Coding Standards
+
+ All contributions must conform to the GNU Coding Standard.
+ Submissions which do not conform to the standards will be
+ returned with a request to reformat the changes.
+
+ GDB has certain additional coding requirements. Those
+ requirements are explained in the GDB internals documentation
+ in the gdb/doc directory.
+
+ Ref: http://www.gnu.org/prep/standards_toc.html
+
+
+o Copyright Assignment
+
+ Before we can accept code contributions from you, we need a
+ copyright assignment form filled out and filed with the FSF.
+
+ See some documentation by the FSF for details and contact us
+ (either via the GDB mailing list or the GDB maintainer that is
+ taking care of your contributions) to obtain the relevant
+ forms.
+
+ Small changes can be accepted without a copyright assignment form on file.
+
+ Ref: http://www.gnu.org/prep/maintain.html#SEC6
+
+
+o Submitting Patches
+
+ Every patch must have several pieces of information before we
+ can properly evaluate it.
+
+ A description of the bug and how your patch fixes this
+ bug. A reference to a testsuite failure is very helpful. For
+ new features a description of the feature and your
+ implementation.
+
+ A ChangeLog entry as plaintext (separate from the patch); see
+ the various ChangeLog files for format and content. Note that,
+ unlike some other projects, we do require ChangeLogs also for
+ documentation (i.e., .texi files).
+
+ The patch itself. If you are accessing the CVS repository use
+ "cvs update; cvs diff -cp"; else, use "diff -cp OLD NEW" or
+ "diff -up OLD NEW". If your version of diff does not support
+ these options, then get the latest version of GNU diff.
+
+ We accept patches as plain text (preferred for the compilers
+ themselves), MIME attachments (preferred for the web pages),
+ or as uuencoded gzipped text.
+
+ When you have all these pieces, bundle them up in a mail
+ message and send it to gdb-patches@sources.redhat.com. All
+ patches and related discussion should be sent to the
+ gdb-patches mailinglist. For further information on the GDB
+ CVS repository, see the Anonymous read-only CVS access and
+ Read-write CVS access page.
+
+--
+
+Supplemental information for GDB:
+
+o Please try to run the relevant testsuite before and after
+ committing a patch
+
+ If the contributor doesn't do it then the maintainer will. A
+ contributor might include before/after test results in their
+ contribution.
+
+
+o For bug fixes, please try to include a way of
+ demonstrating that the patch actually fixes something.
+
+ The best way of doing this is to ensure that the
+ testsuite contains one or more test cases that
+ fail without the fix but pass with the fix.
+
+ People are encouraged to submit patches that extend
+ the testsuite.
+
+
+o Please read your patch before submitting it.
+
+ A patch containing several unrelated changes or
+ arbitrary reformats will be returned with a request
+ to re-formatting / split it.
+
+
+o If ``gdb/configure.in'' is modified then you don't
+ need to include patches to the regenerated file
+ ``configure''.
+
+ The maintainer will re-generate those files
+ using autoconf (2.13 as of 2000-02-29).
+
+
+o If ``gdb/gdbarch.sh'' is modified, you don't
+ need to include patches to the generated files
+ ``gdbarch.h'' and ``gdbarch.c''.
+
+ See ``gdb/configure.in'' above.
+
+
+o When submitting a patch that fixes a bug
+ in GDB's bug database a brief reference
+ to the bug can be included in the ChangeLog
+ vis
+
+ * CONTRIBUTE: Mention PR convention.
+ Fix PR gdb/4705.
+
+ The text ``PR gdb/4705'' should also be included
+ in the CVS commit message. That causes the
+ patch to automatically be archived with the PR.
diff --git a/contrib/gdb/gdb/COPYING b/contrib/gdb/gdb/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/contrib/gdb/gdb/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+
+ <signature of Ty Coon>, 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/MAINTAINERS b/contrib/gdb/gdb/MAINTAINERS
new file mode 100644
index 0000000..95328a4
--- /dev/null
+++ b/contrib/gdb/gdb/MAINTAINERS
@@ -0,0 +1,445 @@
+ GDB Maintainers
+
+
+ Global Maintainers
+ (alphabetic)
+
+Jim Blandy jimb@redhat.com
+Kevin Buettner kevinb@redhat.com
+Andrew Cagney cagney@gnu.org
+J.T. Conklin jtc@acorntoolworks.com
+Fred Fish fnf@ninemoons.com
+Daniel Jacobowitz dan@debian.org
+Mark Kettenis kettenis@gnu.org
+Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
+Stan Shebs shebs@apple.com
+Michael Snyder msnyder@redhat.com
+Elena Zannoni ezannoni@redhat.com
+Eli Zaretskii eliz@gnu.org
+
+
+ Various Maintainers
+
+Note individuals who maintain parts of the debugger need approval to
+check in changes outside of the immediate domain that they maintain.
+
+If there is no maintainer for a given domain then the responsibility
+falls to a global maintainer.
+
+If there are several maintainers for a given domain then
+responsibility falls to the first maintainer. The first maintainer is
+free to devolve that responsibility among the other maintainers.
+
+
+ The Obvious Fix Rule
+
+All maintainers listed in this file are allowed to check in obvious
+fixes.
+
+An "obvious fix" means that there is no possibility that anyone will
+disagree with the change.
+
+A good mental test is "will the person who hates my work the most be
+able to find fault with the change" - if so, then it's not obvious and
+needs to be posted first. :-)
+
+Something like changing or bypassing an interface is _not_ an obvious
+fix, since such a change without discussion will result in
+instantaneous and loud complaints.
+
+
+Target Instruction Set Architectures:
+
+Generic ISA (Instruction Set Architecture) issues, API variants, CPU
+variants. *-tdep.c. The Target/Architecture maintainer works with the
+host maintainer when resolving build issues. The Target/Architecture
+maintainer works with the native maintainer when resolving API issues.
+
+ a29k Deleted.
+
+ alpha --target=alpha-elf ,-Werror
+ Maintenance only
+
+ arc Deleted.
+
+ arm --target=arm-elf ,-Werror
+ Scott Bambrough scottb@netwinder.org
+ Richard Earnshaw rearnsha@arm.com
+
+ avr --target=avr ,-Werror
+ Theodore A. Roth troth@openavr.org
+
+ cris --target=cris-elf ,-Werror
+ Orjan Friberg orjanf@axis.com
+
+ d10v --target=d10v-elf ,-Werror
+ Maintenance only
+
+ d30v Deleted.
+
+ fr30 Deleted.
+
+ frv --target=frv-elf ,-Werror
+ Maintenance only
+
+ h8300 --target=h8300hms ,-Werror
+ Maintenance only
+
+ h8500 Deleted.
+
+ i386 --target=i386-elf ,-Werror
+ Mark Kettenis kettenis@gnu.org
+
+ i960 Deleted.
+
+ ia64 --target=ia64-linux-gnu ,-Werror
+ (--target=ia64-elf broken)
+ Kevin Buettner kevinb@redhat.com
+
+ m32r --target=m32r-elf ,-Werror
+
+ m68hc11 --target=m68hc11-elf ,-Werror ,
+ Stephane Carrez stcarrez@nerim.fr
+
+ m68k --target=m68k-elf ,-Werror
+ Maintenance only
+
+ m88k Deleted.
+
+ mcore --target=mcore-elf ,-Werror
+ Maintenance only
+
+ mips --target=mips-elf ,-Werror
+ Andrew Cagney cagney@redhat.com
+
+ mn10200 Deleted.
+
+ mn10300 --target=mn10300-elf ,-Werror
+ Maintenance only
+
+ ns32k --target=ns32k-netbsd ,-Werror
+ Maintenance only
+
+ pa (--target=hppa-elf broken)
+ Maintenance only
+
+ powerpc --target=powerpc-eabi ,-Werror
+ Kevin Buettner kevinb@redhat.com
+
+ s390 --target=s390-linux-gnu ,-Werror
+ (contact DJ Barrow djbarrow@de.ibm.com)
+
+ sh --target=sh-elf ,-Werror
+ Elena Zannoni ezannoni@redhat.com
+
+ sparc --target=sparc-elf ,-Werror
+ Maintenance only
+
+ tic80 Deleted.
+
+ v850 --target=v850-elf ,-Werror
+ Maintenance only
+
+ vax --target=vax-netbsd ,-Werror
+ Maintenance only
+
+ w65 Deleted.
+
+ x86-64 --target=x86_64-linux-gnu ,-Werror
+ Maintenance only
+
+ xstormy16 --target=xstormy16-elf ,-Werror
+ Corinna Vinschen vinschen@redhat.com
+
+ z8k Deleted.
+
+All developers recognized by this file can make arbitrary changes to
+OBSOLETE targets.
+
+All maintainers can test and thence approve non-trivial changes to
+``maintenance only'' targets submitted by recognized developers.
+
+All recognized developers can make mechanical changes (by virtue of
+the obvious fix rule) to ``maintenance only'' targets. The change
+shall be sanity checked by compiling with one of the listed targets.
+
+The Bourne shell script gdb_mbuild.sh can be used to rebuild all the
+above targets.
+
+
+Host/Native:
+
+The Native maintainer is responsible for target specific native
+support - typically shared libraries and quirks to procfs/ptrace/...
+The Native maintainer works with the Arch and Core maintainers when
+resolving more generic problems.
+
+The host maintainer ensures that gdb can be built as a cross debugger on
+their platform.
+
+AIX Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
+ Kevin Buettner kevinb@redhat.com
+ Joel Brobecker brobecker@gnat.com
+
+djgpp native Eli Zaretskii eliz@gnu.org
+ DJ Delorie dj@redhat.com
+MS Windows (NT, '00, 9x, Me, XP) host & native
+ Chris Faylor cgf@alum.bu.edu
+GNU/Linux/x86 native & host
+ Mark Kettenis kettenis@gnu.org
+GNU/Linux PPC native Kevin Buettner kevinb@redhat.com
+GNU/Linux MIPS native & host
+ Daniel Jacobowitz dan@debian.org
+GNU/Linux m68k Andreas Schwab schwab@suse.de
+FreeBSD native & host Mark Kettenis kettenis@gnu.org
+ David O'Brien obrien@freebsd.org
+hurd native Mark Kettenis kettenis@gnu.org
+NetBSD native & host Jason Thorpe thorpej@wasabisystems.com
+SCO/Unixware Robert Lipe rjl@sco.com
+GNU/Linux ARM native Scott Bambrough scottb@netwinder.org
+Solaris/x86 native & host (devolved)
+ Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
+Solaris/SPARC native & host (devolved)
+ (Global Maintainers)
+
+
+
+Core: Generic components used by all of GDB
+
+generic arch support Andrew Cagney cagney@redhat.com
+ Any host/target maintainer can add to
+ gdbarch.{c,h,sh}. Send tricky ones to cagney.
+target vector Andrew Cagney cagney@redhat.com
+
+event loop Elena Zannoni ezannoni@redhat.com
+ For the part of top.c related to the event loop,
+ send questions to ezannoni@redhat.com
+
+generic symtabs Jim Blandy jimb@redhat.com
+ Elena Zannoni ezannoni@redhat.com
+ dwarf readers Jim Blandy jimb@redhat.com
+ Elena Zannoni ezannoni@redhat.com
+ elf reader Jim Blandy jimb@redhat.com
+ Elena Zannoni ezannoni@redhat.com
+ stabs reader Jim Blandy jimb@redhat.com
+ Elena Zannoni ezannoni@redhat.com
+ coff reader Philippe De Muyter phdm@macqel.be
+ xcoff reader Any maintainer can modify this; please send tricky
+ ones to Kevin Buettner <kevinb@redhat.com>
+ HP/UX readers Any [past] maintainer can modify this.
+ Please send tricky ones to the symtabs maintainers.
+
+tracing bytecode stuff Jim Blandy jimb@redhat.com
+ (Global Maintainers)
+tracing Michael Snyder msnyder@redhat.com
+threads Michael Snyder msnyder@redhat.com
+ Mark Kettenis kettenis@gnu.org
+breakpoints (Global Maintainers)
+language support (Blanket Write Privs Maintainers)
+ C++ Daniel Jacobowitz dan@debian.org
+ Java support (Global Maintainers)
+ Pascal support Pierre Muller muller@sources.redhat.com
+ Objective C support Adam Fedor fedor@gnu.org
+shared libs (devolved) Kevin Buettner kevinb@redhat.com
+ xcoffsolib Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
+
+remote.c Andrew Cagney cagney@redhat.com
+include/remote-sim.h, remote-sim.c
+ Andrew Cagney cagney@redhat.com
+sds protocol (vacant)
+rdi/adp protocol (vacant)
+documentation Eli Zaretskii eliz@gnu.org
+testsuite Michael Chastain mec.gnu@mindspring.com
+ (Global Maintainers)
+ lib/, config/, gdb.base/, ...
+ Michael Chastain mec.gnu@mindspring.com
+ (Global Maintainers)
+ gdbtk (gdb.gdbtk) Keith Seitz keiths@redhat.com
+ c++ (gdb.cp) Michael Chastain mec.gnu@mindspring.com
+ David Carlton carlton@bactrian.org
+ mi tests (gdb.mi) Elena Zannoni ezannoni@redhat.com
+ Andrew Cagney cagney@redhat.com
+ threads (gdb.threads) Michael Snyder msnyder@redhat.com
+ trace (gdb.trace) Michael Snyder msnyder@redhat.com
+ hp tests (gdb.hp) (vacant)
+ Java tests (gdb.java) Anthony Green green@redhat.com
+Kernel Object Display Fernando Nasser fnasser@redhat.com
+
+
+UI: External (user) interfaces.
+
+command interpreter (Global Maintainers)
+gdbtk (c & tcl) Jim Ingham jingham@apple.com
+ Fernando Nasser fnasser@redhat.com
+ Keith Seitz keiths@redhat.com
+libgui (w/foundry, sn) Jim Ingham jingham@apple.com
+ Keith Seitz keiths@redhat.com
+mi (gdb/mi) Andrew Cagney cagney@redhat.com
+ Elena Zannoni ezannoni@redhat.com
+ Fernando Nasser fnasser@redhat.com
+tui Stephane Carrez stcarrez@nerim.fr
+ (Global Maintainers)
+
+
+Misc:
+
+gdb/gdbserver Daniel Jacobowitz dan@debian.org
+
+Web pages. Jim Kingdon jkingdon@engr.sgi.com ++
+ (anyone can edit; kingdon is just lead maintainer)
+
+Makefile.in, configure* ALL
+
+mmalloc/ ALL Host maintainers
+
+NEWS ALL
+
+sim/ See sim/MAINTAINERS
+
+readline/ Master version: ftp://ftp.cwru.edu/pub/bash/
+ Elena Zannoni ezannoni@redhat.com
+ Host maintainers (host dependant parts)
+ (but get your changes into the master version)
+
+tcl/ tk/ itcl/ Ian Roxborough irox@redhat.com
+
+ Write After Approval
+ (alphabetic)
+
+To get recommended for the Write After Approval list you need a valid
+FSF assignment and have submitted one good patch.
+
+David Anderson davea@sgi.com
+Shrinivas Atre shrinivasa@kpitcummins.com
+Scott Bambrough scottb@netwinder.org
+Jim Blandy jimb@redhat.com
+Philip Blundell philb@gnu.org
+Per Bothner per@bothner.com
+Joel Brobecker brobecker@gnat.com
+Dave Brolley brolley@redhat.com
+Paul Brook paul@codesourcery.com
+Kevin Buettner kevinb@redhat.com
+Andrew Cagney cagney@gnu.org
+David Carlton carlton@bactrian.org
+Stephane Carrez stcarrez@nerim.fr
+Michael Chastain mec.gnu@mindspring.com
+Eric Christopher echristo@redhat.com
+Randolph Chung tausq@debian.org
+Nick Clifton nickc@redhat.com
+Brendan Conoboy blc@redhat.com
+DJ Delorie dj@redhat.com
+Chris G. Demetriou cgd@broadcom.com
+Philippe De Muyter phdm@macqel.be
+Dhananjay Deshpande dhananjayd@kpitcummins.com
+Klee Dienes kdienes@apple.com
+Richard Earnshaw rearnsha@arm.com
+Frank Ch. Eigler fche@redhat.com
+Ben Elliston bje@gnu.org
+Brian Ford ford@vss.fsi.com
+Raoul Gough RaoulGough@yahoo.co.uk
+Anthony Green green@redhat.com
+Matthew Green mrg@eterna.com.au
+Jerome Guitton guitton@act-europe.fr
+Adam Fedor fedor@gnu.org
+Fred Fish fnf@ninemoons.com
+Orjan Friberg orjanf@axis.com
+Ben Harris bjh21@netbsd.org
+Richard Henderson rth@redhat.com
+Aldy Hernandez aldyh@redhat.com
+Paul Hilfinger hilfinger@gnat.com
+Matt Hiller hiller@redhat.com
+Kazu Hirata kazu@cs.umass.edu
+Jeff Holcomb jeffh@redhat.com
+Don Howard dhoward@redhat.com
+Martin Hunt hunt@redhat.com
+Jim Ingham jingham@apple.com
+Daniel Jacobowitz dan@debian.org
+Andreas Jaeger aj@suse.de
+Jeff Johnston jjohnstn@redhat.com
+Geoff Keating geoffk@redhat.com
+Mark Kettenis kettenis@gnu.org
+Jim Kingdon jkingdon@engr.sgi.com ++
+Jonathan Larmour jlarmour@redhat.co.uk
+Jeff Law law@redhat.com
+David Lecomber david@streamline-computing.com
+Robert Lipe rjl@sco.com
+H.J. Lu hjl@lucon.org
+Michal Ludvig mludvig@suse.cz
+Glen McCready gkm@redhat.com
+Greg McGary greg@mcgary.org
+Roland McGrath roland@redhat.com
+Bryce McKinlay mckinlay@redhat.com
+Jason Merrill jason@redhat.com
+David S. Miller davem@redhat.com
+Mark Mitchell mark@codesourcery.com
+Marko Mlinar markom@opencores.org
+Alan Modra amodra@bigpond.net.au
+Jason Molenda jmolenda@apple.com
+Pierre Muller muller@sources.redhat.com
+Fernando Nasser fnasser@redhat.com
+Hans-Peter Nilsson hp@bitrange.com
+David O'Brien obrien@freebsd.org
+Alexandre Oliva aoliva@redhat.com
+Tom Rix trix@redhat.com
+Nick Roberts nick@nick.uklinux.net
+Bob Rossi bob_rossi@cox.net
+Theodore A. Roth troth@openavr.org
+Ian Roxborough irox@redhat.com
+Grace Sainsbury graces@redhat.com
+Kei Sakamoto sakamoto.kei@renesas.com
+Mark Salter msalter@redhat.com
+Richard Sandiford rsandifo@redhat.com
+Peter Schauer Peter.Schauer@regent
+Andreas Schwab schwab@suse.de
+Keith Seitz keiths@redhat.com
+Stan Shebs shebs@apple.com
+Aidan Skinner aidan@velvet.net
+Jiri Smid smid@suse.cz
+David Smith dsmith@redhat.com
+Stephen P. Smith ischis2@cox.net
+Jackie Smith Cashion jsmith@redhat.com
+Michael Snyder msnyder@redhat.com
+Petr Sorfa petrs@caldera.com
+Ian Lance Taylor ian@wasabisystems.com
+Gary Thomas gthomas@redhat.com
+Jason Thorpe thorpej@wasabisystems.com
+Tom Tromey tromey@redhat.com
+D Venkatasubramanian dvenkat@noida.hcltech.com
+Corinna Vinschen vinschen@redhat.com
+Keith Walker keith.walker@arm.com
+Kris Warkentin kewarken@qnx.com
+Ulrich Weigand uweigand@de.ibm.com
+Nathan Williams nathanw@wasabisystems.com
+Jim Wilson wilson@specifixinc.com
+Elena Zannoni ezannoni@redhat.com
+Eli Zaretskii eliz@gnu.org
+
+
+
+ Past Maintainers
+
+Jimmy Guo (gdb.hp, tui) guo at cup dot hp dot com
+Jeff Law (hppa) law at cygnus dot com
+Daniel Berlin (C++ support) dan at cgsoftware dot com
+Nick Duffek (powerpc, SCO, Sol/x86) nick at duffek dot com
+David Taylor (d10v, sparc, utils, defs,
+ expression evaluator, language support) taylor at candd dot org
+J.T. Conklin (dcache, NetBSD, remote) jtc at redback dot com
+Frank Ch. Eigler (sim) fche at redhat dot com
+Per Bothner (Java) per at bothner dot com
+Anthony Green (Java) green at redhat dot com
+Fernando Nasser (testsuite/, mi, cli) fnasser at redhat dot com
+Mark Salter (testsuite/lib+config) msalter at redhat dot com
+
+
+
+Folks that have been caught up in a paper trail:
+
+Chris Faylor cgf@alum.bu.edu
+Jim Kingdon jkingdon@engr.sgi.com
+David Carlton carlton@bactrian.org
+
+--
+
+(*) Indicates folks that don't have a Kerberos/SSH account in the GDB
+group.
diff --git a/contrib/gdb/gdb/NEWS b/contrib/gdb/gdb/NEWS
new file mode 100644
index 0000000..abba0e7
--- /dev/null
+++ b/contrib/gdb/gdb/NEWS
@@ -0,0 +1,2504 @@
+ What has changed in GDB?
+ (Organized release by release)
+
+*** Changes in GDB 6.1.1:
+
+* TUI (Text-mode User Interface) built-in (also included in GDB 6.1)
+
+The TUI (Text-mode User Interface) is now built as part of a default
+GDB configuration. It is enabled by either selecting the TUI with the
+command line option "-i=tui" or by running the separate "gdbtui"
+program. For more information on the TUI, see the manual "Debugging
+with GDB".
+
+* Pending breakpoint support (also included in GDB 6.1)
+
+Support has been added to allow you to specify breakpoints in shared
+libraries that have not yet been loaded. If a breakpoint location
+cannot be found, and the "breakpoint pending" option is set to auto,
+GDB queries you if you wish to make the breakpoint pending on a future
+shared-library load. If and when GDB resolves the breakpoint symbol,
+the pending breakpoint is removed as one or more regular breakpoints
+are created.
+
+Pending breakpoints are very useful for GCJ Java debugging.
+
+* Fixed ISO-C build problems
+
+The files bfd/elf-bfd.h, gdb/dictionary.c and gdb/types.c contained
+non ISO-C code that stopped them being built using a more strict ISO-C
+compiler (e.g., IBM's C compiler).
+
+* Fixed build problem on IRIX 5
+
+Due to header problems with <sys/proc.h>, the file gdb/proc-api.c
+wasn't able to compile compile on an IRIX 5 system.
+
+* Added execute permission to gdb/gdbserver/configure
+
+The shell script gdb/testsuite/gdb.stabs/configure lacked execute
+permission. This bug would cause configure to fail on a number of
+systems (Solaris, IRIX). Ref: server/519.
+
+* Fixed build problem on hpux2.0w-hp-hpux11.00 using the HP ANSI C compiler
+
+Older HPUX ANSI C compilers did not accept variable array sizes. somsolib.c
+has been updated to use constant array sizes.
+
+* Fixed a panic in the DWARF Call Frame Info code on Solaris 2.7
+
+GCC 3.3.2, on Solaris 2.7, includes the DW_EH_PE_funcrel encoding in
+its generated DWARF Call Frame Info. This encoding was causing GDB to
+panic, that panic has been fixed. Ref: gdb/1628.
+
+* Fixed a problem when examining parameters in shared library code.
+
+When examining parameters in optimized shared library code generated
+by a mainline GCC, GDB would incorrectly report ``Variable "..." is
+not available''. GDB now correctly displays the variable's value.
+
+*** Changes in GDB 6.1:
+
+* Removed --with-mmalloc
+
+Support for the mmalloc memory manager has been removed, as it
+conflicted with the internal gdb byte cache.
+
+* Changes in AMD64 configurations
+
+The AMD64 target now includes the %cs and %ss registers. As a result
+the AMD64 remote protocol has changed; this affects the floating-point
+and SSE registers. If you rely on those registers for your debugging,
+you should upgrade gdbserver on the remote side.
+
+* Revised SPARC target
+
+The SPARC target has been completely revised, incorporating the
+FreeBSD/sparc64 support that was added for GDB 6.0. As a result
+support for LynxOS and SunOS 4 has been dropped. Calling functions
+from within GDB on operating systems with a non-executable stack
+(Solaris, OpenBSD) now works.
+
+* New C++ demangler
+
+GDB has a new C++ demangler which does a better job on the mangled
+names generated by current versions of g++. It also runs faster, so
+with this and other changes gdb should now start faster on large C++
+programs.
+
+* DWARF 2 Location Expressions
+
+GDB support for location expressions has been extended to support function
+arguments and frame bases. Older versions of GDB could crash when they
+encountered these.
+
+* C++ nested types and namespaces
+
+GDB's support for nested types and namespaces in C++ has been
+improved, especially if you use the DWARF 2 debugging format. (This
+is the default for recent versions of GCC on most platforms.)
+Specifically, if you have a class "Inner" defined within a class or
+namespace "Outer", then GDB realizes that the class's name is
+"Outer::Inner", not simply "Inner". This should greatly reduce the
+frequency of complaints about not finding RTTI symbols. In addition,
+if you are stopped at inside of a function defined within a namespace,
+GDB modifies its name lookup accordingly.
+
+* New native configurations
+
+NetBSD/amd64 x86_64-*-netbsd*
+OpenBSD/amd64 x86_64-*-openbsd*
+OpenBSD/alpha alpha*-*-openbsd*
+OpenBSD/sparc sparc-*-openbsd*
+OpenBSD/sparc64 sparc64-*-openbsd*
+
+* New debugging protocols
+
+M32R with SDI protocol m32r-*-elf*
+
+* "set prompt-escape-char" command deleted.
+
+The command "set prompt-escape-char" has been deleted. This command,
+and its very obscure effet on GDB's prompt, was never documented,
+tested, nor mentioned in the NEWS file.
+
+* OBSOLETE configurations and files
+
+Configurations that have been declared obsolete in this release have
+been commented out. Unless there is activity to revive these
+configurations, the next release of GDB will have their sources
+permanently REMOVED.
+
+Sun 3, running SunOS 3 m68*-*-sunos3*
+Sun 3, running SunOS 4 m68*-*-sunos4*
+Sun 2, running SunOS 3 m68000-*-sunos3*
+Sun 2, running SunOS 4 m68000-*-sunos4*
+Motorola 680x0 running LynxOS m68*-*-lynxos*
+AT&T 3b1/Unix pc m68*-att-*
+Bull DPX2 (68k, System V release 3) m68*-bull-sysv*
+decstation mips-dec-* mips-little-*
+riscos mips-*-riscos* mips-*-sysv*
+sonymips mips-sony-*
+sysv mips*-*-sysv4* (IRIX 5/6 not included)
+
+* REMOVED configurations and files
+
+SGI Irix-4.x mips-sgi-irix4 or iris4
+SGI Iris (MIPS) running Irix V3: mips-sgi-irix or iris
+Z8000 simulator z8k-zilog-none or z8ksim
+Matsushita MN10200 w/simulator mn10200-*-*
+H8/500 simulator h8500-hitachi-hms or h8500hms
+HP/PA running BSD hppa*-*-bsd*
+HP/PA running OSF/1 hppa*-*-osf*
+HP/PA Pro target hppa*-*-pro*
+PMAX (MIPS) running Mach 3.0 mips*-*-mach3*
+386BSD i[3456]86-*-bsd*
+Sequent family i[3456]86-sequent-sysv4*
+ i[3456]86-sequent-sysv*
+ i[3456]86-sequent-bsd*
+SPARC running LynxOS sparc-*-lynxos*
+SPARC running SunOS 4 sparc-*-sunos4*
+Tsqware Sparclet sparclet-*-*
+Fujitsu SPARClite sparclite-fujitsu-none or sparclite
+
+*** Changes in GDB 6.0:
+
+* Objective-C
+
+Support for debugging the Objective-C programming language has been
+integrated into GDB.
+
+* New backtrace mechanism (includes DWARF 2 Call Frame Information).
+
+DWARF 2's Call Frame Information makes available compiler generated
+information that more exactly describes the program's run-time stack.
+By using this information, GDB is able to provide more robust stack
+backtraces.
+
+The i386, amd64 (nee, x86-64), Alpha, m68hc11, ia64, and m32r targets
+have been updated to use a new backtrace mechanism which includes
+DWARF 2 CFI support.
+
+* Hosted file I/O.
+
+GDB's remote protocol has been extended to include support for hosted
+file I/O (where the remote target uses GDB's file system). See GDB's
+remote protocol documentation for details.
+
+* All targets using the new architecture framework.
+
+All of GDB's targets have been updated to use the new internal
+architecture framework. The way is now open for future GDB releases
+to include cross-architecture native debugging support (i386 on amd64,
+ppc32 on ppc64).
+
+* GNU/Linux's Thread Local Storage (TLS)
+
+GDB now includes support for for the GNU/Linux implementation of
+per-thread variables.
+
+* GNU/Linux's Native POSIX Thread Library (NPTL)
+
+GDB's thread code has been updated to work with either the new
+GNU/Linux NPTL thread library or the older "LinuxThreads" library.
+
+* Separate debug info.
+
+GDB, in conjunction with BINUTILS, now supports a mechanism for
+automatically loading debug information from a separate file. Instead
+of shipping full debug and non-debug versions of system libraries,
+system integrators can now instead ship just the stripped libraries
+and optional debug files.
+
+* DWARF 2 Location Expressions
+
+DWARF 2 Location Expressions allow the compiler to more completely
+describe the location of variables (even in optimized code) to the
+debugger.
+
+GDB now includes preliminary support for location expressions (support
+for DW_OP_piece is still missing).
+
+* Java
+
+A number of long standing bugs that caused GDB to die while starting a
+Java application have been fixed. GDB's Java support is now
+considered "useable".
+
+* GNU/Linux support for fork, vfork, and exec.
+
+The "catch fork", "catch exec", "catch vfork", and "set follow-fork-mode"
+commands are now implemented for GNU/Linux. They require a 2.5.x or later
+kernel.
+
+* GDB supports logging output to a file
+
+There are two new commands, "set logging" and "show logging", which can be
+used to capture GDB's output to a file.
+
+* The meaning of "detach" has changed for gdbserver
+
+The "detach" command will now resume the application, as documented. To
+disconnect from gdbserver and leave it stopped, use the new "disconnect"
+command.
+
+* d10v, m68hc11 `regs' command deprecated
+
+The `info registers' command has been updated so that it displays the
+registers using a format identical to the old `regs' command.
+
+* Profiling support
+
+A new command, "maint set profile on/off", has been added. This command can
+be used to enable or disable profiling while running GDB, to profile a
+session or a set of commands. In addition there is a new configure switch,
+"--enable-profiling", which will cause GDB to be compiled with profiling
+data, for more informative profiling results.
+
+* Default MI syntax changed to "mi2".
+
+The default MI (machine interface) syntax, enabled by the command line
+option "-i=mi", has been changed to "mi2". The previous MI syntax,
+"mi1", can be enabled by specifying the option "-i=mi1".
+
+Support for the original "mi0" syntax (included in GDB 5.0) has been
+removed.
+
+Fix for gdb/192: removed extraneous space when displaying frame level.
+Fix for gdb/672: update changelist is now output in mi list format.
+Fix for gdb/702: a -var-assign that updates the value now shows up
+ in a subsequent -var-update.
+
+* New native configurations.
+
+FreeBSD/amd64 x86_64-*-freebsd*
+
+* Multi-arched targets.
+
+HP/PA HPUX11 hppa*-*-hpux*
+Renesas M32R/D w/simulator m32r-*-elf*
+
+* OBSOLETE configurations and files
+
+Configurations that have been declared obsolete in this release have
+been commented out. Unless there is activity to revive these
+configurations, the next release of GDB will have their sources
+permanently REMOVED.
+
+Z8000 simulator z8k-zilog-none or z8ksim
+Matsushita MN10200 w/simulator mn10200-*-*
+H8/500 simulator h8500-hitachi-hms or h8500hms
+HP/PA running BSD hppa*-*-bsd*
+HP/PA running OSF/1 hppa*-*-osf*
+HP/PA Pro target hppa*-*-pro*
+PMAX (MIPS) running Mach 3.0 mips*-*-mach3*
+Sequent family i[3456]86-sequent-sysv4*
+ i[3456]86-sequent-sysv*
+ i[3456]86-sequent-bsd*
+Tsqware Sparclet sparclet-*-*
+Fujitsu SPARClite sparclite-fujitsu-none or sparclite
+
+* REMOVED configurations and files
+
+V850EA ISA
+Motorola Delta 88000 running Sys V m88k-motorola-sysv or delta88
+IBM AIX PS/2 i[3456]86-*-aix
+i386 running Mach 3.0 i[3456]86-*-mach3*
+i386 running Mach i[3456]86-*-mach*
+i386 running OSF/1 i[3456]86-*osf1mk*
+HP/Apollo 68k Family m68*-apollo*-sysv*,
+ m68*-apollo*-bsd*,
+ m68*-hp-bsd*, m68*-hp-hpux*
+Argonaut Risc Chip (ARC) arc-*-*
+Mitsubishi D30V d30v-*-*
+Fujitsu FR30 fr30-*-elf*
+OS/9000 i[34]86-*-os9k
+I960 with MON960 i960-*-coff
+
+* MIPS $fp behavior changed
+
+The convenience variable $fp, for the MIPS, now consistently returns
+the address of the current frame's base. Previously, depending on the
+context, $fp could refer to either $sp or the current frame's base
+address. See ``8.10 Registers'' in the manual ``Debugging with GDB:
+The GNU Source-Level Debugger''.
+
+*** Changes in GDB 5.3:
+
+* GNU/Linux shared library multi-threaded performance improved.
+
+When debugging a multi-threaded application on GNU/Linux, GDB now uses
+`/proc', in preference to `ptrace' for memory reads. This may result
+in an improvement in the start-up time of multi-threaded, shared
+library applications when run under GDB. One GDB user writes: ``loads
+shared libs like mad''.
+
+* ``gdbserver'' now supports multi-threaded applications on some targets
+
+Support for debugging multi-threaded applications which use
+the GNU/Linux LinuxThreads package has been added for
+arm*-*-linux*-gnu*, i[3456]86-*-linux*-gnu*, mips*-*-linux*-gnu*,
+powerpc*-*-linux*-gnu*, and sh*-*-linux*-gnu*.
+
+* GDB now supports C/C++ preprocessor macros.
+
+GDB now expands preprocessor macro invocations in C/C++ expressions,
+and provides various commands for showing macro definitions and how
+they expand.
+
+The new command `macro expand EXPRESSION' expands any macro
+invocations in expression, and shows the result.
+
+The new command `show macro MACRO-NAME' shows the definition of the
+macro named MACRO-NAME, and where it was defined.
+
+Most compilers don't include information about macros in the debugging
+information by default. In GCC 3.1, for example, you need to compile
+your program with the options `-gdwarf-2 -g3'. If the macro
+information is present in the executable, GDB will read it.
+
+* Multi-arched targets.
+
+DEC Alpha (partial) alpha*-*-*
+DEC VAX (partial) vax-*-*
+NEC V850 v850-*-*
+National Semiconductor NS32000 (partial) ns32k-*-*
+Motorola 68000 (partial) m68k-*-*
+Motorola MCORE mcore-*-*
+
+* New targets.
+
+Fujitsu FRV architecture added by Red Hat frv*-*-*
+
+
+* New native configurations
+
+Alpha NetBSD alpha*-*-netbsd*
+SH NetBSD sh*-*-netbsdelf*
+MIPS NetBSD mips*-*-netbsd*
+UltraSPARC NetBSD sparc64-*-netbsd*
+
+* OBSOLETE configurations and files
+
+Configurations that have been declared obsolete in this release have
+been commented out. Unless there is activity to revive these
+configurations, the next release of GDB will have their sources
+permanently REMOVED.
+
+Mitsubishi D30V d30v-*-*
+OS/9000 i[34]86-*-os9k
+IBM AIX PS/2 i[3456]86-*-aix
+Fujitsu FR30 fr30-*-elf*
+Motorola Delta 88000 running Sys V m88k-motorola-sysv or delta88
+Argonaut Risc Chip (ARC) arc-*-*
+i386 running Mach 3.0 i[3456]86-*-mach3*
+i386 running Mach i[3456]86-*-mach*
+i386 running OSF/1 i[3456]86-*osf1mk*
+HP/Apollo 68k Family m68*-apollo*-sysv*,
+ m68*-apollo*-bsd*,
+ m68*-hp-bsd*, m68*-hp-hpux*
+I960 with MON960 i960-*-coff
+
+* OBSOLETE languages
+
+CHILL, a Pascal like language used by telecommunications companies.
+
+* REMOVED configurations and files
+
+AMD 29k family via UDI a29k-amd-udi, udi29k
+A29K VxWorks a29k-*-vxworks
+AMD 29000 embedded, using EBMON a29k-none-none
+AMD 29000 embedded with COFF a29k-none-coff
+AMD 29000 embedded with a.out a29k-none-aout
+
+testsuite/gdb.hp/gdb.threads-hp/ directory
+
+* New command "set max-user-call-depth <nnn>"
+
+This command allows the user to limit the call depth of user-defined
+commands. The default is 1024.
+
+* Changes in FreeBSD/i386 native debugging.
+
+Support for the "generate-core-file" has been added.
+
+* New commands "dump", "append", and "restore".
+
+These commands allow data to be copied from target memory
+to a bfd-format or binary file (dump and append), and back
+from a file into memory (restore).
+
+* Improved "next/step" support on multi-processor Alpha Tru64.
+
+The previous single-step mechanism could cause unpredictable problems,
+including the random appearance of SIGSEGV or SIGTRAP signals. The use
+of a software single-step mechanism prevents this.
+
+*** Changes in GDB 5.2.1:
+
+* New targets.
+
+Atmel AVR avr*-*-*
+
+* Bug fixes
+
+gdb/182: gdb/323: gdb/237: On alpha, gdb was reporting:
+mdebugread.c:2443: gdb-internal-error: sect_index_data not initialized
+Fix, by Joel Brobecker imported from mainline.
+
+gdb/439: gdb/291: On some ELF object files, gdb was reporting:
+dwarf2read.c:1072: gdb-internal-error: sect_index_text not initialize
+Fix, by Fred Fish, imported from mainline.
+
+Dwarf2 .debug_frame & .eh_frame handler improved in many ways.
+Surprisingly enough, it works now.
+By Michal Ludvig, imported from mainline.
+
+i386 hardware watchpoint support:
+avoid misses on second run for some targets.
+By Pierre Muller, imported from mainline.
+
+*** Changes in GDB 5.2:
+
+* New command "set trust-readonly-sections on[off]".
+
+This command is a hint that tells gdb that read-only sections
+really are read-only (ie. that their contents will not change).
+In this mode, gdb will go to the object file rather than the
+target to read memory from read-only sections (such as ".text").
+This can be a significant performance improvement on some
+(notably embedded) targets.
+
+* New command "generate-core-file" (or "gcore").
+
+This new gdb command allows the user to drop a core file of the child
+process state at any time. So far it's been implemented only for
+GNU/Linux and Solaris, but should be relatively easily ported to other
+hosts. Argument is core file name (defaults to core.<pid>).
+
+* New command line option
+
+GDB now accepts --pid or -p followed by a process id.
+
+* Change in command line behavior -- corefiles vs. process ids.
+
+There is a subtle behavior in the way in which GDB handles
+command line arguments. The first non-flag argument is always
+a program to debug, but the second non-flag argument may either
+be a corefile or a process id. Previously, GDB would attempt to
+open the second argument as a corefile, and if that failed, would
+issue a superfluous error message and then attempt to attach it as
+a process. Now, if the second argument begins with a non-digit,
+it will be treated as a corefile. If it begins with a digit,
+GDB will attempt to attach it as a process, and if no such process
+is found, will then attempt to open it as a corefile.
+
+* Changes in ARM configurations.
+
+Multi-arch support is enabled for all ARM configurations. The ARM/NetBSD
+configuration is fully multi-arch.
+
+* New native configurations
+
+ARM NetBSD arm*-*-netbsd*
+x86 OpenBSD i[3456]86-*-openbsd*
+AMD x86-64 running GNU/Linux x86_64-*-linux-*
+Sparc64 running FreeBSD sparc64-*-freebsd*
+
+* New targets
+
+Sanyo XStormy16 xstormy16-elf
+
+* OBSOLETE configurations and files
+
+Configurations that have been declared obsolete in this release have
+been commented out. Unless there is activity to revive these
+configurations, the next release of GDB will have their sources
+permanently REMOVED.
+
+AMD 29k family via UDI a29k-amd-udi, udi29k
+A29K VxWorks a29k-*-vxworks
+AMD 29000 embedded, using EBMON a29k-none-none
+AMD 29000 embedded with COFF a29k-none-coff
+AMD 29000 embedded with a.out a29k-none-aout
+
+testsuite/gdb.hp/gdb.threads-hp/ directory
+
+* REMOVED configurations and files
+
+TI TMS320C80 tic80-*-*
+WDC 65816 w65-*-*
+PowerPC Solaris powerpcle-*-solaris*
+PowerPC Windows NT powerpcle-*-cygwin32
+PowerPC Netware powerpc-*-netware*
+Harris/CXUX m88k m88*-harris-cxux*
+Most ns32k hosts and targets ns32k-*-mach3* ns32k-umax-*
+ ns32k-utek-sysv* ns32k-utek-*
+SunOS 4.0.Xi on i386 i[3456]86-*-sunos*
+Ultracomputer (29K) running Sym1 a29k-nyu-sym1 a29k-*-kern*
+Sony NEWS (68K) running NEWSOS 3.x m68*-sony-sysv news
+ISI Optimum V (3.05) under 4.3bsd. m68*-isi-*
+Apple Macintosh (MPW) host and target N/A host, powerpc-*-macos*
+
+* Changes to command line processing
+
+The new `--args' feature can be used to specify command-line arguments
+for the inferior from gdb's command line.
+
+* Changes to key bindings
+
+There is a new `operate-and-get-next' function bound to `C-o'.
+
+*** Changes in GDB 5.1.1
+
+Fix compile problem on DJGPP.
+
+Fix a problem with floating-point registers on the i386 being
+corrupted.
+
+Fix to stop GDB crashing on .debug_str debug info.
+
+Numerous documentation fixes.
+
+Numerous testsuite fixes.
+
+*** Changes in GDB 5.1:
+
+* New native configurations
+
+Alpha FreeBSD alpha*-*-freebsd*
+x86 FreeBSD 3.x and 4.x i[3456]86*-freebsd[34]*
+MIPS GNU/Linux mips*-*-linux*
+MIPS SGI Irix 6.x mips*-sgi-irix6*
+ia64 AIX ia64-*-aix*
+s390 and s390x GNU/Linux {s390,s390x}-*-linux*
+
+* New targets
+
+Motorola 68HC11 and 68HC12 m68hc11-elf
+CRIS cris-axis
+UltraSparc running GNU/Linux sparc64-*-linux*
+
+* OBSOLETE configurations and files
+
+x86 FreeBSD before 2.2 i[3456]86*-freebsd{1,2.[01]}*,
+Harris/CXUX m88k m88*-harris-cxux*
+Most ns32k hosts and targets ns32k-*-mach3* ns32k-umax-*
+ ns32k-utek-sysv* ns32k-utek-*
+TI TMS320C80 tic80-*-*
+WDC 65816 w65-*-*
+Ultracomputer (29K) running Sym1 a29k-nyu-sym1 a29k-*-kern*
+PowerPC Solaris powerpcle-*-solaris*
+PowerPC Windows NT powerpcle-*-cygwin32
+PowerPC Netware powerpc-*-netware*
+SunOS 4.0.Xi on i386 i[3456]86-*-sunos*
+Sony NEWS (68K) running NEWSOS 3.x m68*-sony-sysv news
+ISI Optimum V (3.05) under 4.3bsd. m68*-isi-*
+Apple Macintosh (MPW) host N/A
+
+stuff.c (Program to stuff files into a specially prepared space in kdb)
+kdb-start.c (Main loop for the standalone kernel debugger)
+
+Configurations that have been declared obsolete in this release have
+been commented out. Unless there is activity to revive these
+configurations, the next release of GDB will have their sources
+permanently REMOVED.
+
+* REMOVED configurations and files
+
+Altos 3068 m68*-altos-*
+Convex c1-*-*, c2-*-*
+Pyramid pyramid-*-*
+ARM RISCix arm-*-* (as host)
+Tahoe tahoe-*-*
+ser-ocd.c *-*-*
+
+* GDB has been converted to ISO C.
+
+GDB's source code has been converted to ISO C. In particular, the
+sources are fully protoized, and rely on standard headers being
+present.
+
+* Other news:
+
+* "info symbol" works on platforms which use COFF, ECOFF, XCOFF, and NLM.
+
+* The MI enabled by default.
+
+The new machine oriented interface (MI) introduced in GDB 5.0 has been
+revised and enabled by default. Packages which use GDB as a debugging
+engine behind a UI or another front end are encouraged to switch to
+using the GDB/MI interface, instead of the old annotations interface
+which is now deprecated.
+
+* Support for debugging Pascal programs.
+
+GDB now includes support for debugging Pascal programs. The following
+main features are supported:
+
+ - Pascal-specific data types such as sets;
+
+ - automatic recognition of Pascal sources based on file-name
+ extension;
+
+ - Pascal-style display of data types, variables, and functions;
+
+ - a Pascal expression parser.
+
+However, some important features are not yet supported.
+
+ - Pascal string operations are not supported at all;
+
+ - there are some problems with boolean types;
+
+ - Pascal type hexadecimal constants are not supported
+ because they conflict with the internal variables format;
+
+ - support for Pascal objects and classes is not full yet;
+
+ - unlike Pascal, GDB is case-sensitive for symbol names.
+
+* Changes in completion.
+
+Commands such as `shell', `run' and `set args', which pass arguments
+to inferior programs, now complete on file names, similar to what
+users expect at the shell prompt.
+
+Commands which accept locations, such as `disassemble', `print',
+`breakpoint', `until', etc. now complete on filenames as well as
+program symbols. Thus, if you type "break foob TAB", and the source
+files linked into the programs include `foobar.c', that file name will
+be one of the candidates for completion. However, file names are not
+considered for completion after you typed a colon that delimits a file
+name from a name of a function in that file, as in "break foo.c:bar".
+
+`set demangle-style' completes on available demangling styles.
+
+* New platform-independent commands:
+
+It is now possible to define a post-hook for a command as well as a
+hook that runs before the command. For more details, see the
+documentation of `hookpost' in the GDB manual.
+
+* Changes in GNU/Linux native debugging.
+
+Support for debugging multi-threaded programs has been completely
+revised for all platforms except m68k and sparc. You can now debug as
+many threads as your system allows you to have.
+
+Attach/detach is supported for multi-threaded programs.
+
+Support for SSE registers was added for x86. This doesn't work for
+multi-threaded programs though.
+
+* Changes in MIPS configurations.
+
+Multi-arch support is enabled for all MIPS configurations.
+
+GDB can now be built as native debugger on SGI Irix 6.x systems for
+debugging n32 executables. (Debugging 64-bit executables is not yet
+supported.)
+
+* Unified support for hardware watchpoints in all x86 configurations.
+
+Most (if not all) native x86 configurations support hardware-assisted
+breakpoints and watchpoints in a unified manner. This support
+implements debug register sharing between watchpoints, which allows to
+put a virtually infinite number of watchpoints on the same address,
+and also supports watching regions up to 16 bytes with several debug
+registers.
+
+The new maintenance command `maintenance show-debug-regs' toggles
+debugging print-outs in functions that insert, remove, and test
+watchpoints and hardware breakpoints.
+
+* Changes in the DJGPP native configuration.
+
+New command ``info dos sysinfo'' displays assorted information about
+the CPU, OS, memory, and DPMI server.
+
+New commands ``info dos gdt'', ``info dos ldt'', and ``info dos idt''
+display information about segment descriptors stored in GDT, LDT, and
+IDT.
+
+New commands ``info dos pde'' and ``info dos pte'' display entries
+from Page Directory and Page Tables (for now works with CWSDPMI only).
+New command ``info dos address-pte'' displays the Page Table entry for
+a given linear address.
+
+GDB can now pass command lines longer than 126 characters to the
+program being debugged (requires an update to the libdbg.a library
+which is part of the DJGPP development kit).
+
+DWARF2 debug info is now supported.
+
+It is now possible to `step' and `next' through calls to `longjmp'.
+
+* Changes in documentation.
+
+All GDB documentation was converted to GFDL, the GNU Free
+Documentation License.
+
+Tracepoints-related commands are now fully documented in the GDB
+manual.
+
+TUI, the Text-mode User Interface, is now documented in the manual.
+
+Tracepoints-related commands are now fully documented in the GDB
+manual.
+
+The "GDB Internals" manual now has an index. It also includes
+documentation of `ui_out' functions, GDB coding standards, x86
+hardware watchpoints, and memory region attributes.
+
+* GDB's version number moved to ``version.in''
+
+The Makefile variable VERSION has been replaced by the file
+``version.in''. People creating GDB distributions should update the
+contents of this file.
+
+* gdba.el deleted
+
+GUD support is now a standard part of the EMACS distribution.
+
+*** Changes in GDB 5.0:
+
+* Improved support for debugging FP programs on x86 targets
+
+Unified and much-improved support for debugging floating-point
+programs on all x86 targets. In particular, ``info float'' now
+displays the FP registers in the same format on all x86 targets, with
+greater level of detail.
+
+* Improvements and bugfixes in hardware-assisted watchpoints
+
+It is now possible to watch array elements, struct members, and
+bitfields with hardware-assisted watchpoints. Data-read watchpoints
+on x86 targets no longer erroneously trigger when the address is
+written.
+
+* Improvements in the native DJGPP version of GDB
+
+The distribution now includes all the scripts and auxiliary files
+necessary to build the native DJGPP version on MS-DOS/MS-Windows
+machines ``out of the box''.
+
+The DJGPP version can now debug programs that use signals. It is
+possible to catch signals that happened in the debuggee, deliver
+signals to it, interrupt it with Ctrl-C, etc. (Previously, a signal
+would kill the program being debugged.) Programs that hook hardware
+interrupts (keyboard, timer, etc.) can also be debugged.
+
+It is now possible to debug DJGPP programs that redirect their
+standard handles or switch them to raw (as opposed to cooked) mode, or
+even close them. The command ``run < foo > bar'' works as expected,
+and ``info terminal'' reports useful information about the debuggee's
+terminal, including raw/cooked mode, redirection, etc.
+
+The DJGPP version now uses termios functions for console I/O, which
+enables debugging graphics programs. Interrupting GDB with Ctrl-C
+also works.
+
+DOS-style file names with drive letters are now fully supported by
+GDB.
+
+It is now possible to debug DJGPP programs that switch their working
+directory. It is also possible to rerun the debuggee any number of
+times without restarting GDB; thus, you can use the same setup,
+breakpoints, etc. for many debugging sessions.
+
+* New native configurations
+
+ARM GNU/Linux arm*-*-linux*
+PowerPC GNU/Linux powerpc-*-linux*
+
+* New targets
+
+Motorola MCore mcore-*-*
+x86 VxWorks i[3456]86-*-vxworks*
+PowerPC VxWorks powerpc-*-vxworks*
+TI TMS320C80 tic80-*-*
+
+* OBSOLETE configurations
+
+Altos 3068 m68*-altos-*
+Convex c1-*-*, c2-*-*
+Pyramid pyramid-*-*
+ARM RISCix arm-*-* (as host)
+Tahoe tahoe-*-*
+
+Configurations that have been declared obsolete will be commented out,
+but the code will be left in place. If there is no activity to revive
+these configurations before the next release of GDB, the sources will
+be permanently REMOVED.
+
+* Gould support removed
+
+Support for the Gould PowerNode and NP1 has been removed.
+
+* New features for SVR4
+
+On SVR4 native platforms (such as Solaris), if you attach to a process
+without first loading a symbol file, GDB will now attempt to locate and
+load symbols from the running process's executable file.
+
+* Many C++ enhancements
+
+C++ support has been greatly improved. Overload resolution now works properly
+in almost all cases. RTTI support is on the way.
+
+* Remote targets can connect to a sub-program
+
+A popen(3) style serial-device has been added. This device starts a
+sub-process (such as a stand-alone simulator) and then communicates
+with that. The sub-program to run is specified using the syntax
+``|<program> <args>'' vis:
+
+ (gdb) set remotedebug 1
+ (gdb) target extended-remote |mn10300-elf-sim program-args
+
+* MIPS 64 remote protocol
+
+A long standing bug in the mips64 remote protocol where by GDB
+expected certain 32 bit registers (ex SR) to be transfered as 32
+instead of 64 bits has been fixed.
+
+The command ``set remote-mips64-transfers-32bit-regs on'' has been
+added to provide backward compatibility with older versions of GDB.
+
+* ``set remotebinarydownload'' replaced by ``set remote X-packet''
+
+The command ``set remotebinarydownload'' command has been replaced by
+``set remote X-packet''. Other commands in ``set remote'' family
+include ``set remote P-packet''.
+
+* Breakpoint commands accept ranges.
+
+The breakpoint commands ``enable'', ``disable'', and ``delete'' now
+accept a range of breakpoints, e.g. ``5-7''. The tracepoint command
+``tracepoint passcount'' also accepts a range of tracepoints.
+
+* ``apropos'' command added.
+
+The ``apropos'' command searches through command names and
+documentation strings, printing out matches, making it much easier to
+try to find a command that does what you are looking for.
+
+* New MI interface
+
+A new machine oriented interface (MI) has been added to GDB. This
+interface is designed for debug environments running GDB as a separate
+process. This is part of the long term libGDB project. See the
+"GDB/MI" chapter of the GDB manual for further information. It can be
+enabled by configuring with:
+
+ .../configure --enable-gdbmi
+
+*** Changes in GDB-4.18:
+
+* New native configurations
+
+HP-UX 10.20 hppa*-*-hpux10.20
+HP-UX 11.x hppa*-*-hpux11.0*
+M68K GNU/Linux m68*-*-linux*
+
+* New targets
+
+Fujitsu FR30 fr30-*-elf*
+Intel StrongARM strongarm-*-*
+Mitsubishi D30V d30v-*-*
+
+* OBSOLETE configurations
+
+Gould PowerNode, NP1 np1-*-*, pn-*-*
+
+Configurations that have been declared obsolete will be commented out,
+but the code will be left in place. If there is no activity to revive
+these configurations before the next release of GDB, the sources will
+be permanently REMOVED.
+
+* ANSI/ISO C
+
+As a compatibility experiment, GDB's source files buildsym.h and
+buildsym.c have been converted to pure standard C, no longer
+containing any K&R compatibility code. We believe that all systems in
+use today either come with a standard C compiler, or have a GCC port
+available. If this is not true, please report the affected
+configuration to bug-gdb@gnu.org immediately. See the README file for
+information about getting a standard C compiler if you don't have one
+already.
+
+* Readline 2.2
+
+GDB now uses readline 2.2.
+
+* set extension-language
+
+You can now control the mapping between filename extensions and source
+languages by using the `set extension-language' command. For instance,
+you can ask GDB to treat .c files as C++ by saying
+ set extension-language .c c++
+The command `info extensions' lists all of the recognized extensions
+and their associated languages.
+
+* Setting processor type for PowerPC and RS/6000
+
+When GDB is configured for a powerpc*-*-* or an rs6000*-*-* target,
+you can use the `set processor' command to specify what variant of the
+PowerPC family you are debugging. The command
+
+ set processor NAME
+
+sets the PowerPC/RS6000 variant to NAME. GDB knows about the
+following PowerPC and RS6000 variants:
+
+ ppc-uisa PowerPC UISA - a PPC processor as viewed by user-level code
+ rs6000 IBM RS6000 ("POWER") architecture, user-level view
+ 403 IBM PowerPC 403
+ 403GC IBM PowerPC 403GC
+ 505 Motorola PowerPC 505
+ 860 Motorola PowerPC 860 or 850
+ 601 Motorola PowerPC 601
+ 602 Motorola PowerPC 602
+ 603 Motorola/IBM PowerPC 603 or 603e
+ 604 Motorola PowerPC 604 or 604e
+ 750 Motorola/IBM PowerPC 750 or 750
+
+At the moment, this command just tells GDB what to name the
+special-purpose processor registers. Since almost all the affected
+registers are inaccessible to user-level programs, this command is
+only useful for remote debugging in its present form.
+
+* HP-UX support
+
+Thanks to a major code donation from Hewlett-Packard, GDB now has much
+more extensive support for HP-UX. Added features include shared
+library support, kernel threads and hardware watchpoints for 11.00,
+support for HP's ANSI C and C++ compilers, and a compatibility mode
+for xdb and dbx commands.
+
+* Catchpoints
+
+HP's donation includes the new concept of catchpoints, which is a
+generalization of the old catch command. On HP-UX, it is now possible
+to catch exec, fork, and vfork, as well as library loading.
+
+This means that the existing catch command has changed; its first
+argument now specifies the type of catch to be set up. See the
+output of "help catch" for a list of catchpoint types.
+
+* Debugging across forks
+
+On HP-UX, you can choose which process to debug when a fork() happens
+in the inferior.
+
+* TUI
+
+HP has donated a curses-based terminal user interface (TUI). To get
+it, build with --enable-tui. Although this can be enabled for any
+configuration, at present it only works for native HP debugging.
+
+* GDB remote protocol additions
+
+A new protocol packet 'X' that writes binary data is now available.
+Default behavior is to try 'X', then drop back to 'M' if the stub
+fails to respond. The settable variable `remotebinarydownload'
+allows explicit control over the use of 'X'.
+
+For 64-bit targets, the memory packets ('M' and 'm') can now contain a
+full 64-bit address. The command
+
+ set remoteaddresssize 32
+
+can be used to revert to the old behaviour. For existing remote stubs
+the change should not be noticed, as the additional address information
+will be discarded.
+
+In order to assist in debugging stubs, you may use the maintenance
+command `packet' to send any text string to the stub. For instance,
+
+ maint packet heythere
+
+sends the packet "$heythere#<checksum>". Note that it is very easy to
+disrupt a debugging session by sending the wrong packet at the wrong
+time.
+
+The compare-sections command allows you to compare section data on the
+target to what is in the executable file without uploading or
+downloading, by comparing CRC checksums.
+
+* Tracing can collect general expressions
+
+You may now collect general expressions at tracepoints. This requires
+further additions to the target-side stub; see tracepoint.c and
+doc/agentexpr.texi for further details.
+
+* mask-address variable for Mips
+
+For Mips targets, you may control the zeroing of the upper 32 bits of
+a 64-bit address by entering `set mask-address on'. This is mainly
+of interest to users of embedded R4xxx and R5xxx processors.
+
+* Higher serial baud rates
+
+GDB's serial code now allows you to specify baud rates 57600, 115200,
+230400, and 460800 baud. (Note that your host system may not be able
+to achieve all of these rates.)
+
+* i960 simulator
+
+The i960 configuration now includes an initial implementation of a
+builtin simulator, contributed by Jim Wilson.
+
+
+*** Changes in GDB-4.17:
+
+* New native configurations
+
+Alpha GNU/Linux alpha*-*-linux*
+Unixware 2.x i[3456]86-unixware2*
+Irix 6.x mips*-sgi-irix6*
+PowerPC GNU/Linux powerpc-*-linux*
+PowerPC Solaris powerpcle-*-solaris*
+Sparc GNU/Linux sparc-*-linux*
+Motorola sysV68 R3V7.1 m68k-motorola-sysv
+
+* New targets
+
+Argonaut Risc Chip (ARC) arc-*-*
+Hitachi H8/300S h8300*-*-*
+Matsushita MN10200 w/simulator mn10200-*-*
+Matsushita MN10300 w/simulator mn10300-*-*
+MIPS NEC VR4100 mips64*vr4100*{,el}-*-elf*
+MIPS NEC VR5000 mips64*vr5000*{,el}-*-elf*
+MIPS Toshiba TX39 mips64*tx39*{,el}-*-elf*
+Mitsubishi D10V w/simulator d10v-*-*
+Mitsubishi M32R/D w/simulator m32r-*-elf*
+Tsqware Sparclet sparclet-*-*
+NEC V850 w/simulator v850-*-*
+
+* New debugging protocols
+
+ARM with RDI protocol arm*-*-*
+M68K with dBUG monitor m68*-*-{aout,coff,elf}
+DDB and LSI variants of PMON protocol mips*-*-*
+PowerPC with DINK32 monitor powerpc{,le}-*-eabi
+PowerPC with SDS protocol powerpc{,le}-*-eabi
+Macraigor OCD (Wiggler) devices powerpc{,le}-*-eabi
+
+* DWARF 2
+
+All configurations can now understand and use the DWARF 2 debugging
+format. The choice is automatic, if the symbol file contains DWARF 2
+information.
+
+* Java frontend
+
+GDB now includes basic Java language support. This support is
+only useful with Java compilers that produce native machine code.
+
+* solib-absolute-prefix and solib-search-path
+
+For SunOS and SVR4 shared libraries, you may now set the prefix for
+loading absolute shared library symbol files, and the search path for
+locating non-absolute shared library symbol files.
+
+* Live range splitting
+
+GDB can now effectively debug code for which GCC has performed live
+range splitting as part of its optimization. See gdb/doc/LRS for
+more details on the expected format of the stabs information.
+
+* Hurd support
+
+GDB's support for the GNU Hurd, including thread debugging, has been
+updated to work with current versions of the Hurd.
+
+* ARM Thumb support
+
+GDB's ARM target configuration now handles the ARM7T (Thumb) 16-bit
+instruction set. ARM GDB automatically detects when Thumb
+instructions are in use, and adjusts disassembly and backtracing
+accordingly.
+
+* MIPS16 support
+
+GDB's MIPS target configurations now handle the MIP16 16-bit
+instruction set.
+
+* Overlay support
+
+GDB now includes support for overlays; if an executable has been
+linked such that multiple sections are based at the same address, GDB
+will decide which section to use for symbolic info. You can choose to
+control the decision manually, using overlay commands, or implement
+additional target-side support and use "overlay load-target" to bring
+in the overlay mapping. Do "help overlay" for more detail.
+
+* info symbol
+
+The command "info symbol <address>" displays information about
+the symbol at the specified address.
+
+* Trace support
+
+The standard remote protocol now includes an extension that allows
+asynchronous collection and display of trace data. This requires
+extensive support in the target-side debugging stub. Tracing mode
+includes a new interaction mode in GDB and new commands: see the
+file tracepoint.c for more details.
+
+* MIPS simulator
+
+Configurations for embedded MIPS now include a simulator contributed
+by Cygnus Solutions. The simulator supports the instruction sets
+of most MIPS variants.
+
+* Sparc simulator
+
+Sparc configurations may now include the ERC32 simulator contributed
+by the European Space Agency. The simulator is not built into
+Sparc targets by default; configure with --enable-sim to include it.
+
+* set architecture
+
+For target configurations that may include multiple variants of a
+basic architecture (such as MIPS and SH), you may now set the
+architecture explicitly. "set arch" sets, "info arch" lists
+the possible architectures.
+
+*** 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 <netrom-hostname>
+ load <prog>
+ target remote <netrom-hostname>: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 GNU/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
+
+GNU/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/PROBLEMS b/contrib/gdb/gdb/PROBLEMS
new file mode 100644
index 0000000..2f53313
--- /dev/null
+++ b/contrib/gdb/gdb/PROBLEMS
@@ -0,0 +1,113 @@
+
+ Known problems in GDB 6.1
+
+ See also: http://www.gnu.org/software/gdb/bugs/
+
+
+*** Build problems
+
+build/1458: comple failed on hpux11
+
+GDB 6.1 is known to have build problems on HP/UX 11.00 using the
+vendor supplied compilers (GDB does build on HP/UX 11.11, and using
+GCC).
+
+*** Misc
+
+gdb/1560: Control-C does not always interrupt GDB.
+
+When GDB is busy processing a command which takes a long time to
+complete, hitting Control-C does not have the expected effect.
+The command execution is not aborted, and the "QUIT" message confirming
+the abortion is displayed only after the command has been completed.
+
+*** C++ support
+
+gdb/931: GDB could be more generous when reading types C++ templates on input
+
+When the user types a template, GDB frequently requires the type to be
+typed in a certain way (e.g. "const char*" as opposed to "const char *"
+or "char const *" or "char const*").
+
+gdb/1512: no canonical way to output names of C++ types
+
+We currently don't have any canonical way to output names of C++ types.
+E.g. "const char *" versus "char const *"; more subtleties arise when
+dealing with templates.
+
+gdb/1516: [regression] local classes, gcc 2.95.3, dwarf-2
+
+With gcc 2.95.3 and the dwarf-2 debugging format, classes which are
+defined locally to a function include the demangled name of the function
+as part of their name. For example, if a function "foobar" contains a
+local class definition "Local", gdb will say that the name of the class
+type is "foobar__Fi.0:Local".
+
+This applies only to classes where the class type is defined inside a
+function, not to variables defined with types that are defined somewhere
+outside any function (which most types are).
+
+gdb/1588: names of c++ nested types in casts must be enclosed in quotes
+
+You must type
+ (gdb) print ('Foo::Bar') x
+or
+ (gdb) print ('Foo::Bar' *) y
+instead of
+ (gdb) print (Foo::Bar) x
+or
+ (gdb) print (Foo::Bar *) y
+respectively.
+
+gdb/1091: Constructor breakpoints ignored
+gdb/1193: g++ 3.3 creates multiple constructors: gdb 5.3 can't set breakpoints
+
+When gcc 3.x compiles a C++ constructor or C++ destructor, it generates
+2 or 3 different versions of the object code. These versions have
+unique mangled names (they have to, in order for linking to work), but
+they have identical source code names, which leads to a great deal of
+confusion. Specifically, if you set a breakpoint in a constructor or a
+destructor, gdb will put a breakpoint in one of the versions, but your
+program may execute the other version. This makes it impossible to set
+breakpoints reliably in constructors or destructors.
+
+gcc 3.x generates these multiple object code functions in order to
+implement virtual base classes. gcc 2.x generated just one object code
+function with a hidden parameter, but gcc 3.x conforms to a multi-vendor
+ABI for C++ which requires multiple object code functions.
+
+*** Stack backtraces
+
+GDB's core code base has been updated to use a new backtrace
+mechanism. This mechanism makes it possible to support new features
+such DWARF 2 Call Frame Information (which in turn makes possible
+backtraces through optimized code).
+
+Since this code is new, it is known to still have a few problems:
+
+gdb/1505: [regression] gdb prints a bad backtrace for a thread
+
+When backtracing a thread, gdb does not stop when it reaches the
+outermost frame, instead continuing until it hits garbage. This is
+sensitive to the operating system and thread library.
+
+hppa*-*-*
+mips*-*-*
+
+The MIPS and HPPA backtrace code has only very recently been updated
+to use GDB's new frame mechanism. At present there are still a few
+problems, in particular backtraces through signal handlers do not
+work.
+
+People encountering problems with these architectures should consult
+GDB's web pages and mailing lists (http://www.gnu.org/software/gdb/)
+to see if there are updates.
+
+powerpc*-*-*
+
+PowerPC architecture support, in 6.1, does not use the new frame code.
+
+Fortunately, PowerPC architecture support, in GDB's mainline sources,
+have been updated. People encountering problems should consider
+downloading a more current snapshot of GDB
+(http://www.gnu.org/software/gdb/current/).
diff --git a/contrib/gdb/gdb/README b/contrib/gdb/gdb/README
new file mode 100644
index 0000000..9a7cc05
--- /dev/null
+++ b/contrib/gdb/gdb/README
@@ -0,0 +1,573 @@
+ README for gdb-6.1 release
+ Updated 29 February, 2004 by Andrew Cagney
+
+This is GDB, the GNU source-level debugger.
+
+A summary of new features is in the file `gdb/NEWS'.
+
+Check the GDB home page at http://www.gnu.org/software/gdb/ for up to
+date release information, mailing list links and archives, etc.
+
+The file `gdb/PROBLEMS' contains information on problems identified
+late in the release cycle. GDB's bug tracking data base at
+http://www.gnu.org/software/gdb/bugs/ contains a more complete list of
+bugs.
+
+
+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-6.1 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 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-6.1.tar.gz file, you'll find a directory
+called `gdb-6.1', which contains:
+
+ COPYING config.sub intl missing opcodes
+ COPYING.LIB configure libiberty mkinstalldirs readline
+ Makefile.in configure.in libtool.m4 mmalloc sim
+ README djunpack.bat ltcf-c.sh move-if-change symlink-tree
+ bfd etc ltcf-cxx.sh mpw-README texinfo
+ config gdb ltcf-gcj.sh mpw-build.in utils
+ config-ml.in gettext.m4 ltconfig mpw-config.in ylwrap
+ config.guess include ltmain.sh mpw-configure
+ config.if install-sh md5.sum mpw-install
+
+You can build GDB right in the source directory:
+
+ cd gdb-6.1
+ ./configure
+ make
+ cp gdb/gdb /usr/local/bin/gdb (or wherever you want)
+
+However, we recommend that an empty directory be used instead.
+This way you do not clutter your source tree with binary files
+and will be able to create different builds with different
+configuration options.
+
+You can build GDB in any empty build directory:
+
+ mkdir build
+ cd build
+ <full path to your sources>/gdb-6.1/configure
+ make
+ cp gdb/gdb /usr/local/bin/gdb (or wherever you want)
+
+(Building GDB with DJGPP tools for MS-DOS/MS-Windows is slightly
+different; see the file gdb-6.1/gdb/config/djgpp/README for details.)
+
+ 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., `./configure sun4' or `./configure decstation'.
+
+ Make sure that your 'configure' line ends in 'gdb-6.1/configure':
+
+ /berman/migchain/source/gdb-6.1/configure # RIGHT
+ /berman/migchain/source/gdb-6.1/gdb/configure # WRONG
+
+ The gdb package contains several subdirectories, such as 'gdb',
+'bfd', and 'readline'. If your 'configure' line ends in
+'gdb-6.1/gdb/configure', then you are configuring only the gdb
+subdirectory, not the whole gdb package. This leads to build errors
+such as:
+
+ make: *** No rule to make target `../bfd/bfd.h', needed by `gdb.o'. Stop.
+
+ If you get other compiler errors during this stage, see the `Reporting
+Bugs' section below; there are a few known problems.
+
+ GDB requires an ISO C (ANSI C) compiler. If you do not have an ISO
+C compiler for your system, you may be able to download and install
+the GNU CC compiler. It is available via anonymous FTP from the
+directory `ftp://ftp.gnu.org/pub/gnu/gcc'.
+
+ 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
+******************
+
+ 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/doc' subdirectory. The main Info file is
+`gdb-6.1/gdb/doc/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-6.1', in the case of version 6.1), you can make
+the Info file by typing:
+
+ cd gdb/doc
+ make 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. This file is included in the GDB
+distribution, in the directory `gdb-6.1/texinfo'.
+
+ 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-6.1/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-6.1/gdb') and then type:
+
+ make doc/gdb.dvi
+
+ If you prefer to have the manual in PDF format, type this from the
+`gdb/doc' subdirectory of the main source directory:
+
+ make gdb.pdf
+
+For this to work, you will need the PDFTeX package to be installed.
+
+
+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 6.1 distribution is in the `gdb-6.1'
+directory. That directory contains:
+
+`gdb-6.1/{COPYING,COPYING.LIB}'
+ Standard GNU license files. Please read them.
+
+`gdb-6.1/bfd'
+ source for the Binary File Descriptor library
+
+`gdb-6.1/config*'
+ script for configuring GDB, along with other support files
+
+`gdb-6.1/gdb'
+ the source specific to GDB itself
+
+`gdb-6.1/include'
+ GNU include files
+
+`gdb-6.1/libiberty'
+ source for the `-liberty' free software library
+
+`gdb-6.1/mmalloc'
+ source for the GNU memory-mapped malloc package
+
+`gdb-6.1/opcodes'
+ source for the library of opcode tables and disassemblers
+
+`gdb-6.1/readline'
+ source for the GNU command-line interface
+ NOTE: The readline library is compiled for use by GDB, but will
+ not be installed on your system when "make install" is issued.
+
+`gdb-6.1/sim'
+ source for some simulators (ARM, D10V, SPARC, M32R, MIPS, PPC, V850, etc)
+
+`gdb-6.1/intl'
+ source for the GNU gettext library, for internationalization.
+ This is slightly modified from the standalone gettext
+ distribution you can get from GNU.
+
+`gdb-6.1/texinfo'
+ The `texinfo.tex' file, which you need in order to make a printed
+ manual using TeX.
+
+`gdb-6.1/etc'
+ Coding standards, useful files for editing GDB, and other
+ miscellanea.
+
+`gdb-6.1/utils'
+ A grab bag of random utilities.
+
+ Note: the following instructions are for building GDB on Unix or
+Unix-like systems. Instructions for building with DJGPP for
+MS-DOS/MS-Windows are in the file gdb/config/djgpp/README.
+
+ 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-6.1' directory.
+
+ First switch to the `gdb-VERSION-NUMBER' source directory if you are
+not already in it; then run `configure'.
+
+ For example:
+
+ cd gdb-6.1
+ ./configure
+ make
+
+ Running `configure' 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
+
+ If you run `configure' from a directory that contains source
+directories for multiple libraries or programs, such as the `gdb-6.1'
+source directory for version 6.1, `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 6.1, type the following to configure only
+the `bfd' subdirectory:
+
+ cd gdb-6.1/bfd
+ ../configure
+
+ 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 6.1, you can build GDB in a separate
+directory for a Sun 4 like this:
+
+ cd gdb-6.1
+ mkdir ../gdb-sun4
+ cd ../gdb-sun4
+ ../gdb-6.1/configure
+ 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-6.1' (or in a separate configured directory configured with
+`--srcdir=PATH/gdb-6.1'), 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-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-pc-sysv
+ % sh config.sub i786v
+ Invalid configuration `i786v': machine `i786v' not recognized
+
+`config.sub' is also distributed in the GDB source directory
+(`gdb-6.1', for version 6.1).
+
+
+`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]
+ [--enable-build-warnings]
+ [--target=TARGET]
+ [--host=HOST]
+ [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.
+
+`--enable-build-warnings'
+ When building the GDB sources, ask the compiler to warn about any
+ code which looks even vaguely suspicious. You should only using
+ this feature if you're compiling with GNU CC. It passes the
+ following flags:
+ -Wimplicit
+ -Wreturn-type
+ -Wcomment
+ -Wtrigraphs
+ -Wformat
+ -Wparentheses
+ -Wpointer-arith
+
+`--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=HOST'
+ Configure GDB to run on the specified HOST.
+
+ There is no convenient way to generate a list of all available
+ hosts.
+
+`HOST ...'
+ Same as `--host=HOST'. If you omit this, GDB will guess; it's
+ quite accurate.
+
+`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.
+
+
+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 directory gdb/gdbserver/ contains `gdbserver', a program that
+allows remote debugging for Unix applications. gdbserver is only
+supported for some native configurations, including Sun 3, Sun 4, and
+Linux.
+
+ There are a number of remote interfaces for talking to existing ROM
+monitors and other hardware:
+
+ remote-e7000.c Renesas E7000 ICE
+ remote-est.c EST emulator
+ remote-hms.c Renesas Micro Systems H8/300 monitor
+ remote-mips.c MIPS remote debugging protocol
+ remote-rdi.c ARM with Angel monitor
+ remote-rdp.c ARM with Demon monitor
+ remote-sds.c PowerPC SDS monitor
+ remote-sim.c Generalized simulator protocol
+ remote-st.c Tandem ST-2000 monitor
+ remote-vx.c VxWorks realtime kernel
+
+ 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.
+
+
+Reporting Bugs in GDB
+=====================
+
+ There are several ways of reporting bugs in GDB. The prefered
+method is to use the World Wide Web:
+
+ http://www.gnu.org/software/gdb/bugs/
+
+As an alternative, the bug report can be submitted, via e-mail, to the
+address "bug-gdb@gnu.org".
+
+ When submitting a bug, please include the GDB version number (e.g.,
+gdb-6.1), 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
+Reporting Bugs chapter of the GDB manual (gdb/doc/gdb.texinfo).
+
+
+Graphical interface to GDB -- X Windows, MS Windows
+==========================
+
+ Several graphical interfaces to GDB are available. You should
+check:
+
+ http://www.gnu.org/software/gdb/links/
+
+for an up-to-date list.
+
+ Emacs users will very likely enjoy the Grand Unified Debugger mode;
+try typing `M-x gdb RET'.
+
+
+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.
+
+ 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
+=============
+
+ Included with the GDB distribution is a DejaGNU based testsuite
+that can either be used to test your newly built GDB, or for
+regression testing a GDB with local modifications.
+
+ Running the testsuite requires the prior installation of DejaGNU,
+which is generally available via ftp. The directory
+ftp://sources.redhat.com/pub/dejagnu/ will contain a recent snapshot.
+Once DejaGNU is installed, you can run the tests in one of the
+following ways:
+
+ (1) cd gdb-6.1
+ make check-gdb
+
+or
+
+ (2) cd gdb-6.1/gdb
+ make check
+
+or
+
+ (3) cd gdb-6.1/gdb/testsuite
+ make site.exp (builds the site specific file)
+ runtest -tool gdb GDB=../gdb (or GDB=<somepath> as appropriate)
+
+The last 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 0000000..1ef9c22
--- /dev/null
+++ b/contrib/gdb/gdb/TODO
@@ -0,0 +1,333 @@
+If you find inaccuracies in this list, please send mail to
+gdb-patches@sources.redhat.com. 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.
+
+
+ GDB 5.1 - Fixes
+ ===============
+
+Below is a list of problems identified during the GDB 5.0 release
+cycle. People hope to have these problems fixed in 5.1.
+
+--
+
+Wow, three bug reports for the same problem in one day! We should
+probably make fixing this a real priority :-).
+
+Anyway, thanks for reporting.
+
+The following patch will fix the problems with setting breakpoints in
+dynamically loaded objects:
+
+ http://sources.redhat.com/ml/gdb-patches/2000-05/msg00230.html
+
+This patch isn't checked in yet (ping Michael/JimB), but I hope this
+will be in the next GDB release.
+
+There should really be a test in the testsuite for this problem, since
+it keeps coming up :-(. Any volunteers?
+
+Mark
+
+--
+
+ GDB 5.1 - New features
+ ======================
+
+The following new features should be included in 5.1.
+
+--
+
+ GDB 5.1 - Cleanups
+ ==================
+
+The following code cleanups will hopefully be applied to GDB 5.1.
+
+--
+
+ GDB 5.1 - Known Problems
+ ========================
+
+--
+
+z8k
+
+The z8k has suffered bit rot and is known to not build. The problem
+was occuring in the opcodes directory.
+
+--
+
+The BFD directory requires bug-fixed AUTOMAKE et.al.
+
+AUTOMAKE 1.4 incorrectly set the TEXINPUTS environment variable. It
+contained the full path to texinfo.tex when it should have only
+contained the directory. The bug has been fixed in the current
+AUTOMAKE sources. Automake snapshots can be found in:
+ ftp://sources.redhat.com/pub/gdb/infrastructure
+and ftp://sources.redhat.com/pub/binutils
+
+--
+
+Solaris 8 x86 CURSES_H problem
+http://sources.redhat.com/ml/gdb/2000-07/msg00038.html
+
+The original problem was worked around with:
+
+ 2000-06-06 Michael Snyder <msnyder@cygnus.com>
+
+ * configure.in: Enable autoconf to find curses.h on Solaris 2.8.
+ * configure: Regenerate.
+
+When building both GDB and SID using the same source tree the problem
+will still occure. sid/component/configure.in mis-configures
+<curses.h> and leaves wrong information in the config cache.
+
+--
+
+ GDB 5.2 - Fixes
+ ===============
+
+--
+
+ GDB 5.2 - New features
+ ======================
+
+--
+
+GCC 3.0 ABI support (but hopefully sooner...).
+
+--
+
+Objective C/C++ support (but hopefully sooner...).
+
+--
+
+Import of readline 4.2
+
+--
+
+ GDB 5.2 - Cleanups
+ ==================
+
+The following cleanups have been identified as part of GDB 5.2.
+
+--
+
+Compiler warnings.
+
+Eliminate warnings for all targets on at least one host for one of the
+-W flags. Flags up for debate include: -Wswitch -Wcomment -trigraphs
+-Wtrigraphs -Wunused-function -Wunused-label -Wunused-variable
+-Wunused-value -Wchar-subscripts -Wtraditional -Wshadow -Wcast-qual
+-Wcast-align -Wwrite-strings -Wconversion -Wstrict-prototypes
+-Wmissing-prototypes -Wmissing-declarations -Wredundant-decls
+-Woverloaded-virtual -Winline
+
+--
+
+Deprecate, if not delete, the following:
+
+ register[]
+ register_valid[]
+ REGISTER_BYTE()
+ Replaced by, on the target side
+ supply_register()
+ and on core-gdb side:
+ {read,write}_register_gen()
+ Remote.c will need to use something
+ other than REGISTER_BYTE() and
+ REGISTER_RAW_SIZE() when unpacking
+ [gG] packets.
+
+ STORE_PSEUDO_REGISTER
+ FETCH_PSEUDO_REGISTER
+ Now handed by the methods
+ gdbarch_{read,write}_register()
+ which sits between core GDB and
+ the register cache.
+
+ REGISTER_CONVERTIBLE
+ REGISTER_CONVERT_TO_RAW
+ REGISTER_CONVERT_TO_VIRTUAL
+ I think these three are redundant.
+ gdbarch_register_{read,write} can
+ do any conversion it likes.
+
+ REGISTER_VIRTUAL_SIZE
+ MAX_REGISTER_VIRTUAL_SIZE
+ REGISTER_VIRTUAL_TYPE
+ I think these can be replaced by
+ the pair:
+ FRAME_REGISTER_TYPE(frame, regnum)
+ REGISTER_TYPE(regnum)
+
+ DO_REGISTERS_INFO
+ Replace with
+ FRAME_REGISTER_INFO (frame, ...)
+
+ REGISTER_SIM_REGNO()
+ If nothing else rename this so that
+ how it relates to rawreg and the
+ regnum is clear.
+
+--
+
+Obsolete the targets:
+
+arm*-wince-pe
+mips*-*-pe
+sh*-*-pe
+
+--
+
+Obsolete the protocols:
+
+RDB?
+
+``As of version 5.3, WindRiver has removed the RDB server (RDB
+protocol support is built into gdb).'' -- Till.
+
+--
+
+Restructure gdb directory tree so that it avoids any 8.3 and 14
+filename problems.
+
+--
+
+Convert GDB build process to AUTOMAKE.
+
+See also sub-directory configure below.
+
+The current convention is (kind of) to use $(<header>_h) in all
+dependency lists. It isn't done in a consistent way.
+
+--
+
+ GDB 5.2 - Known Problems
+ ========================
+
+--
+
+ Code Cleanups: General
+ ======================
+
+The following are more general cleanups and fixes. They are not tied
+to any specific release.
+
+
+ New Features and Fixes
+ ======================
+
+These are harder than cleanups but easier than work involving
+fundamental architectural change.
+
+--
+
+ Language Support
+ ================
+
+New languages come onto the scene all the time.
+
+--
+
+Re: Various C++ things
+
+RTTI for g++ should be using the typeinfo functions rather than the
+vtables. The typeinfo functions are always at offset 4 from the
+beginning of the vtable, and are always right. The vtables will have
+weird names like E::VB sometimes. The typeinfo function will always
+be "E type_info function", or somesuch.
+
+value_virtual_fn_field needs to be fixed so there are no failures for
+virtual functions for C++ using g++.
+
+Testsuite cases are the major priority right now for C++ support,
+since i have to make a lot of changes that could potentially break
+each other.
+
+--
+
+
+ Symbol Support
+ ==============
+
+--
+
+Investiagate ways of reducing memory.
+
+--
+
+Investigate ways of improving load time.
+
+--
+
+ Testsuite Support
+ =================
+
+There are never to many testcases.
+
+--
+
+Better thread testsuite.
+
+--
+
+Better C++ testsuite.
+
+--
+
+ Architectural Changes: General
+ ==============================
+
+These are harder than simple cleanups / fixes and, consequently
+involve more work. Typically an Architectural Change will be broken
+down into a more digestible set of cleanups and fixes.
+
+--
+
+ Architectural Change: Multi-arch et al.
+ =======================================
+
+The long term objective is to remove all assumptions that there is a
+single target with a single address space with a single instruction
+set architecture and single application binary interface.
+
+This is an ongoing effort. The first milestone is to enable
+``multi-arch'' where by all architectural decisions are made at
+runtime.
+
+It should be noted that ``gdbarch'' is really ``gdbabi'' and
+``gdbisa''. Once things are multi-arched breaking that down correctly
+will become much easier.
+
+--
+
+ Architectural Change: MI, LIBGDB and scripting languages
+ ========================================================
+
+See also architectural changes related to the event loop. LIBGDB
+can't be finished until there is a generic event loop being used by
+all targets.
+
+The long term objective is it to be possible to integrate GDB into
+scripting languages.
+
+--
+
+ Architectural Change: Async
+ ===========================
+
+While GDB uses an event loop when prompting the user for input. That
+event loop is not exploited by targets when they allow the target
+program to continue. Typically targets still block in (target_wait())
+until the program again halts.
+
+The closest a target comes to supporting full asynchronous mode are
+the remote targets ``async'' and ``extended-async''.
+
+--
+
+# Local Variables:
+# mode: text
+# End:
diff --git a/contrib/gdb/gdb/abug-rom.c b/contrib/gdb/gdb/abug-rom.c
new file mode 100644
index 0000000..543f702
--- /dev/null
+++ b/contrib/gdb/gdb/abug-rom.c
@@ -0,0 +1,182 @@
+/* Remote debugging interface for ABug Rom monitor for GDB, the GNU debugger.
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ Written by Rob Savoye 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"
+#include "regcache.h"
+
+#include "m68k-tdep.h"
+
+/* Prototypes for local functions. */
+
+static void abug_open (char *args, int from_tty);
+
+static void
+abug_supply_register (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' + M68K_D0_REGNUM;
+ break;
+ case 'A':
+ if (regname[1] < '0' || regname[1] > '7')
+ return;
+ regno = regname[1] - '0' + M68K_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 const char *
+abug_regname (int index)
+{
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "PC",
+ };
+
+ if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+}
+
+/*
+ * 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 abug_ops;
+
+static char *abug_inits[] =
+{"\r", NULL};
+
+static struct monitor_ops abug_cmds;
+
+static void
+init_abug_cmds (void)
+{
+ abug_cmds.flags = MO_CLR_BREAK_USES_ADDR;
+ abug_cmds.init = abug_inits; /* Init strings */
+ abug_cmds.cont = "g\r"; /* continue command */
+ abug_cmds.step = "t\r"; /* single step */
+ abug_cmds.stop = NULL; /* interrupt command */
+ abug_cmds.set_break = "br %x\r"; /* set a breakpoint */
+ abug_cmds.clr_break = "nobr %x\r"; /* clear a breakpoint */
+ abug_cmds.clr_all_break = "nobr\r"; /* clear all breakpoints */
+ abug_cmds.fill = "bf %x:%x %x;b\r"; /* fill (start count val) */
+ abug_cmds.setmem.cmdb = "ms %x %02x\r"; /* setmem.cmdb (addr, value) */
+ abug_cmds.setmem.cmdw = "ms %x %04x\r"; /* setmem.cmdw (addr, value) */
+ abug_cmds.setmem.cmdl = "ms %x %08x\r"; /* setmem.cmdl (addr, value) */
+ abug_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ abug_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ abug_cmds.setmem.term = NULL; /* setreg.term */
+ abug_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ abug_cmds.getmem.cmdb = "md %x:%x;b\r"; /* getmem.cmdb (addr, len) */
+ abug_cmds.getmem.cmdw = "md %x:%x;b\r"; /* getmem.cmdw (addr, len) */
+ abug_cmds.getmem.cmdl = "md %x:%x;b\r"; /* getmem.cmdl (addr, len) */
+ abug_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
+ abug_cmds.getmem.resp_delim = " "; /* getmem.resp_delim */
+ abug_cmds.getmem.term = NULL; /* getmem.term */
+ abug_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
+ abug_cmds.setreg.cmd = "rm %s %x\r"; /* setreg.cmd (name, value) */
+ abug_cmds.setreg.resp_delim = "="; /* setreg.resp_delim */
+ abug_cmds.setreg.term = "? "; /* setreg.term */
+ abug_cmds.setreg.term_cmd = ".\r"; /* setreg.term_cmd */
+ abug_cmds.getreg.cmd = "rm %s\r"; /* getreg.cmd (name) */
+ abug_cmds.getreg.resp_delim = "="; /* getreg.resp_delim */
+ abug_cmds.getreg.term = "? "; /* getreg.term */
+ abug_cmds.getreg.term_cmd = ".\r"; /* getreg.term_cmd */
+ abug_cmds.dump_registers = "rd\r"; /* dump_registers */
+ abug_cmds.register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
+ abug_cmds.supply_register = abug_supply_register; /* supply_register */
+ abug_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ abug_cmds.load = "lo 0\r"; /* download command */
+ abug_cmds.loadresp = "\n"; /* load response */
+ abug_cmds.prompt = "135Bug>"; /* monitor command prompt */
+ abug_cmds.line_term = "\r"; /* end-of-line terminator */
+ abug_cmds.cmd_end = NULL; /* optional command terminator */
+ abug_cmds.target = &abug_ops; /* target operations */
+ abug_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ abug_cmds.regnames = NULL; /* registers names */
+ abug_cmds.regname = abug_regname;
+ abug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+};
+
+static void
+abug_open (char *args, int from_tty)
+{
+ monitor_open (args, &abug_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_abug_rom; /* -Wmissing-prototypes */
+
+void
+_initialize_abug_rom (void)
+{
+ init_abug_cmds ();
+ init_monitor_ops (&abug_ops);
+
+ abug_ops.to_shortname = "abug";
+ abug_ops.to_longname = "ABug monitor";
+ abug_ops.to_doc = "Debug via the ABug monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ abug_ops.to_open = abug_open;
+
+ add_target (&abug_ops);
+}
diff --git a/contrib/gdb/gdb/acinclude.m4 b/contrib/gdb/gdb/acinclude.m4
new file mode 100644
index 0000000..a85ce02
--- /dev/null
+++ b/contrib/gdb/gdb/acinclude.m4
@@ -0,0 +1,998 @@
+dnl written by Rob Savoye <rob@cygnus.com> for Cygnus Support
+dnl major rewriting for Tcl 7.5 by Don Libes <libes@nist.gov>
+
+dnl gdb/configure.in uses BFD_NEED_DECLARATION, so get its definition.
+sinclude(../bfd/acinclude.m4)
+
+dnl This gets the standard macros, like the TCL, TK, etc ones.
+sinclude(../config/acinclude.m4)
+
+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([if running 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. We don't use the cache
+# here cause if somebody fixes their compiler install, we want this to work.
+AC_DEFUN(CY_AC_C_WORKS,
+[# If we cannot compile and link a trivial program, we can't expect anything to work
+AC_MSG_CHECKING(whether the compiler ($CC) actually works)
+AC_TRY_COMPILE(, [/* don't need anything here */],
+ c_compiles=yes, c_compiles=no)
+
+AC_TRY_LINK(, [/* don't need anything here */],
+ c_links=yes, c_links=no)
+
+if test x"${c_compiles}" = x"no" ; then
+ AC_MSG_ERROR(the native compiler is broken and won't compile.)
+fi
+
+if test x"${c_links}" = x"no" ; then
+ AC_MSG_ERROR(the native compiler is broken and won't link.)
+fi
+AC_MSG_RESULT(yes)
+])
+
+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. dir=${configdir})
+AC_ARG_WITH(tclinclude, [ --with-tclinclude=DIR 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)`
+ elif test -f ${with_tclinclude}/generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd ${with_tclinclude}/generic; pwd)`
+ else
+ AC_MSG_ERROR([${with_tclinclude} directory doesn't contain private headers])
+ fi
+fi
+
+# next check if it came with Tcl configuration file
+if test x"${ac_cv_c_tclconfig}" = x ; then
+ if test -f $ac_cv_c_tclconfig/../generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd $ac_cv_c_tclconfig/..; pwd)`
+ 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[[7-9]]* 2>/dev/null` \
+ ${srcdir}/../../tcl \
+ `ls -dr ${srcdir}/../../tcl[[7-9]]* 2>/dev/null` \
+ ${srcdir}/../../../tcl \
+ `ls -dr ${srcdir}/../../../tcl[[7-9]]* 2>/dev/null ` ; do
+ if test -f $i/generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd $i/generic; pwd)`
+ break
+ 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[[7-9]]* 2>/dev/null` \
+ `ls -dr /usr/local/lib/tcl[[7-9]]* 2>/dev/null` \
+ /usr/local/src/tcl \
+ /usr/local/lib/tcl \
+ ${prefix}/include ; do
+ if test -f $i/generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd $i/generic; 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_tclh}" = 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_SUBST(TCLHDIR)
+])
+
+
+AC_DEFUN(CY_AC_PATH_TCLCONFIG, [
+#
+# Ok, lets find the tcl configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-tclconfig
+#
+
+if test x"${no_tcl}" = x ; then
+ # we reset no_tcl in case something fails here
+ no_tcl=true
+ AC_ARG_WITH(tclconfig, [ --with-tclconfig=DIR Directory containing tcl configuration (tclConfig.sh)],
+ with_tclconfig=${withval})
+ AC_MSG_CHECKING([for Tcl configuration])
+ AC_CACHE_VAL(ac_cv_c_tclconfig,[
+
+ # First check to see if --with-tclconfig was specified.
+ if test x"${with_tclconfig}" != x ; then
+ if test -f "${with_tclconfig}/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
+ fi
+ fi
+
+ # then check for a private Tcl installation
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ for i in \
+ ../tcl \
+ `ls -dr ../tcl[[7-9]]* 2>/dev/null` \
+ ../../tcl \
+ `ls -dr ../../tcl[[7-9]]* 2>/dev/null` \
+ ../../../tcl \
+ `ls -dr ../../../tcl[[7-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ for i in \
+ ${srcdir}/../tcl \
+ `ls -dr ${srcdir}/../tcl[[7-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ TCLCONFIG="# no Tcl configs found"
+ AC_MSG_WARN(Can't find Tcl configuration definitions)
+ else
+ no_tcl=
+ TCLCONFIG=${ac_cv_c_tclconfig}/tclConfig.sh
+ AC_MSG_RESULT(found $TCLCONFIG)
+ fi
+fi
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_TCLCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_TCLCONFIG, [
+ . $TCLCONFIG
+
+ AC_SUBST(TCL_VERSION)
+ AC_SUBST(TCL_MAJOR_VERSION)
+ AC_SUBST(TCL_MINOR_VERSION)
+ AC_SUBST(TCL_CC)
+ AC_SUBST(TCL_DEFS)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_LIB_FILE)
+
+dnl don't export, not used outside of configure
+dnl AC_SUBST(TCL_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_EXEC_PREFIX)
+
+ AC_SUBST(TCL_SHLIB_CFLAGS)
+ AC_SUBST(TCL_SHLIB_LD)
+dnl don't export, not used outside of configure
+ AC_SUBST(TCL_SHLIB_LD_LIBS)
+ AC_SUBST(TCL_SHLIB_SUFFIX)
+dnl not used, don't export to save symbols
+ AC_SUBST(TCL_DL_LIBS)
+ AC_SUBST(TCL_LD_FLAGS)
+dnl don't export, not used outside of configure
+ AC_SUBST(TCL_LD_SEARCH_FLAGS)
+ AC_SUBST(TCL_CC_SEARCH_FLAGS)
+ AC_SUBST(TCL_COMPAT_OBJS)
+ AC_SUBST(TCL_RANLIB)
+ AC_SUBST(TCL_BUILD_LIB_SPEC)
+ AC_SUBST(TCL_LIB_SPEC)
+ AC_SUBST(TCL_LIB_VERSIONS_OK)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_SHARED_LIB_SUFFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_UNSHARED_LIB_SUFFIX)
+])
+
+# Warning: Tk definitions are very similar to Tcl definitions but
+# are not precisely the same. There are a couple of differences,
+# so don't do changes to Tcl thinking you can cut and paste it do
+# the Tk differences and later simply substitute "Tk" for "Tcl".
+# Known differences:
+# - Acceptable Tcl major version #s is 7-9 while Tk is 4-9
+# - Searching for Tcl includes looking for tclInt.h, Tk looks for tk.h
+# - Computing major/minor versions is different because Tk depends on
+# headers to Tcl, Tk, and X.
+# - Symbols in tkConfig.sh are different than tclConfig.sh
+# - Acceptable for Tk to be missing but not Tcl.
+
+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 involked by --with-tkinclude
+#
+no_tk=true
+AC_MSG_CHECKING(for Tk private headers)
+AC_ARG_WITH(tkinclude, [ --with-tkinclude=DIR Directory where tk private headers are], with_tkinclude=${withval})
+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)`
+ elif test -f ${with_tkinclude}/generic/tk.h ; then
+ ac_cv_c_tkh=`(cd ${with_tkinclude}/generic; pwd)`
+ else
+ AC_MSG_ERROR([${with_tkinclude} directory doesn't contain private headers])
+ fi
+fi
+
+# next check if it came with Tk configuration file
+if test x"${ac_cv_c_tkconfig}" = x ; then
+ if test -f $ac_cv_c_tkconfig/../generic/tk.h ; then
+ ac_cv_c_tkh=`(cd $ac_cv_c_tkconfig/..; pwd)`
+ fi
+fi
+
+# next check in private source directory
+#
+# since ls returns lowest version numbers first, reverse its output
+if test x"${ac_cv_c_tkh}" = x ; then
+ for i in \
+ ${srcdir}/../tk \
+ `ls -dr ${srcdir}/../tk[[4-9]]* 2>/dev/null` \
+ ${srcdir}/../../tk \
+ `ls -dr ${srcdir}/../../tk[[4-9]]* 2>/dev/null` \
+ ${srcdir}/../../../tk \
+ `ls -dr ${srcdir}/../../../tk[[4-9]]* 2>/dev/null ` ; do
+ if test -f $i/generic/tk.h ; then
+ ac_cv_c_tkh=`(cd $i/generic; pwd)`
+ break
+ 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_tkh}" = x ; then
+ for i in \
+ `ls -dr /usr/local/src/tk[[4-9]]* 2>/dev/null` \
+ `ls -dr /usr/local/lib/tk[[4-9]]* 2>/dev/null` \
+ /usr/local/src/tk \
+ /usr/local/lib/tk \
+ ${prefix}/include ; do
+ if test -f $i/generic/tk.h ; then
+ ac_cv_c_tkh=`(cd $i/generic; 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, ac_cv_c_tkh="")
+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
+
+AC_SUBST(TKHDIR)
+])
+
+
+AC_DEFUN(CY_AC_PATH_TKCONFIG, [
+#
+# Ok, lets find the tk configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-tkconfig
+#
+
+if test x"${no_tk}" = x ; then
+ # we reset no_tk in case something fails here
+ no_tk=true
+ AC_ARG_WITH(tkconfig, [ --with-tkconfig=DIR Directory containing tk configuration (tkConfig.sh)],
+ with_tkconfig=${withval})
+ AC_MSG_CHECKING([for Tk configuration])
+ AC_CACHE_VAL(ac_cv_c_tkconfig,[
+
+ # First check to see if --with-tkconfig was specified.
+ if test x"${with_tkconfig}" != x ; then
+ if test -f "${with_tkconfig}/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh])
+ fi
+ fi
+
+ # then check for a private Tk library
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ for i in \
+ ../tk \
+ `ls -dr ../tk[[4-9]]* 2>/dev/null` \
+ ../../tk \
+ `ls -dr ../../tk[[4-9]]* 2>/dev/null` \
+ ../../../tk \
+ `ls -dr ../../../tk[[4-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ for i in \
+ ${srcdir}/../tk \
+ `ls -dr ${srcdir}/../tk[[4-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ TKCONFIG="# no Tk configs found"
+ AC_MSG_WARN(Can't find Tk configuration definitions)
+ else
+ no_tk=
+ TKCONFIG=${ac_cv_c_tkconfig}/tkConfig.sh
+ AC_MSG_RESULT(found $TKCONFIG)
+ fi
+fi
+
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_TKCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_TKCONFIG, [
+ if test -f "$TKCONFIG" ; then
+ . $TKCONFIG
+ fi
+
+ AC_SUBST(TK_VERSION)
+dnl not actually used, don't export to save symbols
+dnl AC_SUBST(TK_MAJOR_VERSION)
+dnl AC_SUBST(TK_MINOR_VERSION)
+ AC_SUBST(TK_DEFS)
+
+dnl not used, don't export to save symbols
+ dnl AC_SUBST(TK_LIB_FILE)
+
+dnl not used outside of configure
+dnl AC_SUBST(TK_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TK_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TK_EXEC_PREFIX)
+
+ AC_SUBST(TK_BUILD_INCLUDES)
+ AC_SUBST(TK_XINCLUDES)
+ AC_SUBST(TK_XLIBSW)
+ AC_SUBST(TK_BUILD_LIB_SPEC)
+ AC_SUBST(TK_LIB_SPEC)
+])
+
+# check for Itcl headers.
+
+AC_DEFUN(CY_AC_PATH_ITCLCONFIG, [
+#
+# Ok, lets find the itcl configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-itclconfig
+#
+
+if test x"${no_itcl}" = x ; then
+ # we reset no_itcl in case something fails here
+ no_itcl=true
+ AC_ARG_WITH(itclconfig, [ --with-itclconfig Directory containing itcl configuration (itclConfig.sh)],
+ with_itclconfig=${withval})
+ AC_MSG_CHECKING([for Itcl configuration])
+ AC_CACHE_VAL(ac_cv_c_itclconfig,[
+
+ # First check to see if --with-itclconfig was specified.
+ if test x"${with_itclconfig}" != x ; then
+ if test -f "${with_itclconfig}/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd ${with_itclconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_itclconfig} directory doesn't contain itclConfig.sh])
+ fi
+ fi
+
+ # then check for a private Itcl library
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ for i in \
+ ../itcl/itcl \
+ `ls -dr ../itcl[[4-9]]*/itcl 2>/dev/null` \
+ ../../itcl \
+ `ls -dr ../../itcl[[4-9]]*/itcl 2>/dev/null` \
+ ../../../itcl \
+ `ls -dr ../../../itcl[[4-9]]*/itcl 2>/dev/null` ; do
+ if test -f "$i/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ for i in \
+ ${srcdir}/../itcl/itcl \
+ `ls -dr ${srcdir}/../itcl[[4-9]]*/itcl 2>/dev/null` ; do
+ if test -f "$i/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ ITCLCONFIG="# no Itcl configs found"
+ AC_MSG_WARN(Can't find Itcl configuration definitions)
+ else
+ no_itcl=
+ ITCLCONFIG=${ac_cv_c_itclconfig}/itclConfig.sh
+ AC_MSG_RESULT(found $ITCLCONFIG)
+ fi
+fi
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_ITCLCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_ITCLCONFIG, [
+ if test -f "$ITCLCONFIG" ; then
+ . $ITCLCONFIG
+ fi
+
+ AC_SUBST(ITCL_VERSION)
+dnl not actually used, don't export to save symbols
+dnl AC_SUBST(ITCL_MAJOR_VERSION)
+dnl AC_SUBST(ITCL_MINOR_VERSION)
+ AC_SUBST(ITCL_DEFS)
+
+dnl not used, don't export to save symbols
+ dnl AC_SUBST(ITCL_LIB_FILE)
+
+dnl not used outside of configure
+dnl AC_SUBST(ITCL_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITCL_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITCL_EXEC_PREFIX)
+
+ AC_SUBST(ITCL_BUILD_INCLUDES)
+ AC_SUBST(ITCL_BUILD_LIB_SPEC)
+ AC_SUBST(ITCL_LIB_SPEC)
+])
+
+# check for Itcl headers.
+
+AC_DEFUN(CY_AC_PATH_ITCLH, [
+AC_MSG_CHECKING(for Itcl private headers. srcdir=${srcdir})
+if test x"${ac_cv_c_itclh}" = x ; then
+ for i in ${srcdir}/../itcl ${srcdir}/../../itcl ${srcdir}/../../../itcl ${srcdir}/../itcl/itcl; do
+ if test -f $i/generic/itcl.h ; then
+ ac_cv_c_itclh=`(cd $i/generic; pwd)`
+ break
+ fi
+ done
+fi
+if test x"${ac_cv_c_itclh}" = x ; then
+ ITCLHDIR="# no Itcl private headers found"
+ AC_MSG_ERROR([Can't find Itcl private headers])
+fi
+if test x"${ac_cv_c_itclh}" != x ; then
+ ITCLHDIR="-I${ac_cv_c_itclh}"
+fi
+# should always be here
+# ITCLLIB="../itcl/itcl/unix/libitcl.a"
+AC_SUBST(ITCLHDIR)
+#AC_SUBST(ITCLLIB)
+])
+
+
+AC_DEFUN(CY_AC_PATH_ITKCONFIG, [
+#
+# Ok, lets find the itk configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-itkconfig
+#
+
+if test x"${no_itk}" = x ; then
+ # we reset no_itk in case something fails here
+ no_itk=true
+ AC_ARG_WITH(itkconfig, [ --with-itkconfig Directory containing itk configuration (itkConfig.sh)],
+ with_itkconfig=${withval})
+ AC_MSG_CHECKING([for Itk configuration])
+ AC_CACHE_VAL(ac_cv_c_itkconfig,[
+
+ # First check to see if --with-itkconfig was specified.
+ if test x"${with_itkconfig}" != x ; then
+ if test -f "${with_itkconfig}/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd ${with_itkconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_itkconfig} directory doesn't contain itkConfig.sh])
+ fi
+ fi
+
+ # then check for a private Itk library
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ for i in \
+ ../itcl/itk \
+ `ls -dr ../itcl[[4-9]]*/itk 2>/dev/null` \
+ ../../itk \
+ `ls -dr ../../itcl[[4-9]]*/itk 2>/dev/null` \
+ ../../../itk \
+ `ls -dr ../../../itcl[[4-9]]*/itk 2>/dev/null` ; do
+ if test -f "$i/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ for i in \
+ ${srcdir}/../itcl/itk \
+ `ls -dr ${srcdir}/../itcl[[4-9]]*/itk 2>/dev/null` ; do
+ if test -f "$i/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ ITKCONFIG="# no Itk configs found"
+ AC_MSG_WARN(Can't find Itk configuration definitions)
+ else
+ no_itk=
+ ITKCONFIG=${ac_cv_c_itkconfig}/itkConfig.sh
+ AC_MSG_RESULT(found $ITKCONFIG)
+ fi
+fi
+
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_ITKCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_ITKCONFIG, [
+ if test -f "$ITKCONFIG" ; then
+ . $ITKCONFIG
+ fi
+
+ AC_SUBST(ITK_VERSION)
+dnl not actually used, don't export to save symbols
+dnl AC_SUBST(ITK_MAJOR_VERSION)
+dnl AC_SUBST(ITK_MINOR_VERSION)
+ AC_SUBST(ITK_DEFS)
+
+dnl not used, don't export to save symbols
+ dnl AC_SUBST(ITK_LIB_FILE)
+
+dnl not used outside of configure
+dnl AC_SUBST(ITK_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITK_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITK_EXEC_PREFIX)
+
+ AC_SUBST(ITK_BUILD_INCLUDES)
+ AC_SUBST(ITK_BUILD_LIB_SPEC)
+ AC_SUBST(ITK_LIB_SPEC)
+])
+
+AC_DEFUN(CY_AC_PATH_ITKH, [
+AC_MSG_CHECKING(for Itk private headers. srcdir=${srcdir})
+if test x"${ac_cv_c_itkh}" = x ; then
+ for i in ${srcdir}/../itcl ${srcdir}/../../itcl ${srcdir}/../../../itcl ${srcdir}/../itcl/itk; do
+ if test -f $i/generic/itk.h ; then
+ ac_cv_c_itkh=`(cd $i/generic; pwd)`
+ break
+ fi
+ done
+fi
+if test x"${ac_cv_c_itkh}" = x ; then
+ ITKHDIR="# no Itk private headers found"
+ AC_MSG_ERROR([Can't find Itk private headers])
+fi
+if test x"${ac_cv_c_itkh}" != x ; then
+ ITKHDIR="-I${ac_cv_c_itkh}"
+fi
+# should always be here
+# ITKLIB="../itcl/itk/unix/libitk.a"
+AC_SUBST(ITKHDIR)
+#AC_SUBST(ITKLIB)
+])
+
+
+dnl sinclude(../gettext.m4) already included by bfd/acinclude.m4
+dnl The lines below arrange for aclocal not to bring gettext.m4's
+dnl CY_GNU_GETTEXT into aclocal.m4.
+ifelse(yes,no,[
+AC_DEFUN([CY_GNU_GETTEXT],)
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible. ##
+## From Franc,ois Pinard ##
+## ----------------------------------------- ##
+
+# Copyright 1996, 1997, 1999, 2000, 2001 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.
+
+# serial 1
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so. This macro tries various
+# options that select ANSI C on some system or another. It considers the
+# compiler to be in ANSI C mode if it handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN([AM_PROG_CC_STDC],
+[AC_REQUIRE([AC_PROG_CC])
+AC_BEFORE([$0], [AC_C_INLINE])
+AC_BEFORE([$0], [AC_C_CONST])
+dnl Force this before AC_PROG_CPP. Some cpp's, eg on HPUX, require
+dnl a magic option to avoid problems with ANSI preprocessor commands
+dnl like #elif.
+dnl FIXME: can't do this because then AC_AIX won't work due to a
+dnl circular dependency.
+dnl AC_BEFORE([$0], [AC_PROG_CPP])
+AC_MSG_CHECKING([for ${CC-cc} option to accept ANSI C])
+AC_CACHE_VAL(am_cv_prog_cc_stdc,
+[am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ AC_TRY_COMPILE(
+[#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+], [
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+],
+[am_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CC="$ac_save_CC"
+])
+if test -z "$am_cv_prog_cc_stdc"; then
+ AC_MSG_RESULT([none needed])
+else
+ AC_MSG_RESULT([$am_cv_prog_cc_stdc])
+fi
+case "x$am_cv_prog_cc_stdc" in
+ x|xno) ;;
+ *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+])
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV],
+[
+ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+ dnl those with the standalone portable GNU libiconv installed).
+
+ AC_ARG_WITH([libiconv-prefix],
+[ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [
+ for dir in `echo "$withval" | tr : ' '`; do
+ if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi
+ if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi
+ done
+ ])
+
+ AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
+ am_cv_func_iconv="no, consider installing GNU libiconv"
+ am_cv_lib_iconv=no
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ am_cv_func_iconv=yes)
+ if test "$am_cv_func_iconv" != yes; then
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS -liconv"
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ am_cv_lib_iconv=yes
+ am_cv_func_iconv=yes)
+ LIBS="$am_save_LIBS"
+ fi
+ ])
+ if test "$am_cv_func_iconv" = yes; then
+ AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
+ AC_MSG_CHECKING([for iconv declaration])
+ AC_CACHE_VAL(am_cv_proto_iconv, [
+ AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+ am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+ am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+ AC_MSG_RESULT([$]{ac_t:-
+ }[$]am_cv_proto_iconv)
+ AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
+ [Define as const if the declaration of iconv() needs const.])
+ fi
+ LIBICONV=
+ if test "$am_cv_lib_iconv" = yes; then
+ LIBICONV="-liconv"
+ fi
+ AC_SUBST(LIBICONV)
+])
+
+# AC_GNU_SOURCE
+# -------------
+# FIXME: Remove thise once we start using Autoconf 2.5x (x>=4).
+AC_DEFUN([AC_GNU_SOURCE],
+[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl
+AC_BEFORE([$0], [AC_TRY_RUN])dnl
+AC_DEFINE([_GNU_SOURCE])
+])
+
+dnl written by Guido Draheim <guidod@gmx.de>, original by Alexandre Oliva
+dnl Version 1.3 (2001/03/02)
+dnl source http://www.gnu.org/software/ac-archive/Miscellaneous/ac_define_dir.html
+
+AC_DEFUN([AC_DEFINE_DIR], [
+ test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+ ac_define_dir=`eval echo [$]$2`
+ ac_define_dir=`eval echo [$]ac_define_dir`
+ ifelse($3, ,
+ AC_DEFINE_UNQUOTED($1, "$ac_define_dir"),
+ AC_DEFINE_UNQUOTED($1, "$ac_define_dir", $3))
+])
+
+dnl See whether we need a declaration for a function.
+dnl The result is highly dependent on the INCLUDES passed in, so make sure
+dnl to use a different cache variable name in this macro if it is invoked
+dnl in a different context somewhere else.
+dnl gcc_AC_CHECK_DECL(SYMBOL,
+dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]])
+AC_DEFUN(gcc_AC_CHECK_DECL,
+[AC_MSG_CHECKING([whether $1 is declared])
+AC_CACHE_VAL(gcc_cv_have_decl_$1,
+[AC_TRY_COMPILE([$4],
+[#ifndef $1
+char *(*pfn) = (char *(*)) $1 ;
+#endif], eval "gcc_cv_have_decl_$1=yes", eval "gcc_cv_have_decl_$1=no")])
+if eval "test \"`echo '$gcc_cv_have_decl_'$1`\" = yes"; then
+ AC_MSG_RESULT(yes) ; ifelse([$2], , :, [$2])
+else
+ AC_MSG_RESULT(no) ; ifelse([$3], , :, [$3])
+fi
+])dnl
+
+dnl Check multiple functions to see whether each needs a declaration.
+dnl Arrange to define HAVE_DECL_<FUNCTION> to 0 or 1 as appropriate.
+dnl gcc_AC_CHECK_DECLS(SYMBOLS,
+dnl [ACTION-IF-NEEDED [, ACTION-IF-NOT-NEEDED [, INCLUDES]]])
+AC_DEFUN(gcc_AC_CHECK_DECLS,
+[for ac_func in $1
+do
+changequote(, )dnl
+ ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+changequote([, ])dnl
+gcc_AC_CHECK_DECL($ac_func,
+ [AC_DEFINE_UNQUOTED($ac_tr_decl, 1) $2],
+ [AC_DEFINE_UNQUOTED($ac_tr_decl, 0) $3],
+dnl It is possible that the include files passed in here are local headers
+dnl which supply a backup declaration for the relevant prototype based on
+dnl the definition of (or lack of) the HAVE_DECL_ macro. If so, this test
+dnl will always return success. E.g. see libiberty.h's handling of
+dnl `basename'. To avoid this, we define the relevant HAVE_DECL_ macro to
+dnl 1 so that any local headers used do not provide their own prototype
+dnl during this test.
+#undef $ac_tr_decl
+#define $ac_tr_decl 1
+ $4
+)
+done
+dnl Automatically generate config.h entries via autoheader.
+if test x = y ; then
+ patsubst(translit([$1], [a-z], [A-Z]), [\w+],
+ [AC_DEFINE([HAVE_DECL_\&], 1,
+ [Define to 1 if we found this declaration otherwise define to 0.])])dnl
+fi
+])
+
diff --git a/contrib/gdb/gdb/aclocal.m4 b/contrib/gdb/gdb/aclocal.m4
new file mode 100644
index 0000000..40399a6
--- /dev/null
+++ b/contrib/gdb/gdb/aclocal.m4
@@ -0,0 +1,1040 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+dnl written by Rob Savoye <rob@cygnus.com> for Cygnus Support
+dnl major rewriting for Tcl 7.5 by Don Libes <libes@nist.gov>
+
+dnl gdb/configure.in uses BFD_NEED_DECLARATION, so get its definition.
+sinclude(../bfd/acinclude.m4)
+
+dnl This gets the standard macros, like the TCL, TK, etc ones.
+sinclude(../config/acinclude.m4)
+
+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([if running 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. We don't use the cache
+# here cause if somebody fixes their compiler install, we want this to work.
+AC_DEFUN(CY_AC_C_WORKS,
+[# If we cannot compile and link a trivial program, we can't expect anything to work
+AC_MSG_CHECKING(whether the compiler ($CC) actually works)
+AC_TRY_COMPILE(, [/* don't need anything here */],
+ c_compiles=yes, c_compiles=no)
+
+AC_TRY_LINK(, [/* don't need anything here */],
+ c_links=yes, c_links=no)
+
+if test x"${c_compiles}" = x"no" ; then
+ AC_MSG_ERROR(the native compiler is broken and won't compile.)
+fi
+
+if test x"${c_links}" = x"no" ; then
+ AC_MSG_ERROR(the native compiler is broken and won't link.)
+fi
+AC_MSG_RESULT(yes)
+])
+
+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. dir=${configdir})
+AC_ARG_WITH(tclinclude, [ --with-tclinclude=DIR 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)`
+ elif test -f ${with_tclinclude}/generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd ${with_tclinclude}/generic; pwd)`
+ else
+ AC_MSG_ERROR([${with_tclinclude} directory doesn't contain private headers])
+ fi
+fi
+
+# next check if it came with Tcl configuration file
+if test x"${ac_cv_c_tclconfig}" = x ; then
+ if test -f $ac_cv_c_tclconfig/../generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd $ac_cv_c_tclconfig/..; pwd)`
+ 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[[7-9]]* 2>/dev/null` \
+ ${srcdir}/../../tcl \
+ `ls -dr ${srcdir}/../../tcl[[7-9]]* 2>/dev/null` \
+ ${srcdir}/../../../tcl \
+ `ls -dr ${srcdir}/../../../tcl[[7-9]]* 2>/dev/null ` ; do
+ if test -f $i/generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd $i/generic; pwd)`
+ break
+ 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[[7-9]]* 2>/dev/null` \
+ `ls -dr /usr/local/lib/tcl[[7-9]]* 2>/dev/null` \
+ /usr/local/src/tcl \
+ /usr/local/lib/tcl \
+ ${prefix}/include ; do
+ if test -f $i/generic/tclInt.h ; then
+ ac_cv_c_tclh=`(cd $i/generic; 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_tclh}" = 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_SUBST(TCLHDIR)
+])
+
+
+AC_DEFUN(CY_AC_PATH_TCLCONFIG, [
+#
+# Ok, lets find the tcl configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-tclconfig
+#
+
+if test x"${no_tcl}" = x ; then
+ # we reset no_tcl in case something fails here
+ no_tcl=true
+ AC_ARG_WITH(tclconfig, [ --with-tclconfig=DIR Directory containing tcl configuration (tclConfig.sh)],
+ with_tclconfig=${withval})
+ AC_MSG_CHECKING([for Tcl configuration])
+ AC_CACHE_VAL(ac_cv_c_tclconfig,[
+
+ # First check to see if --with-tclconfig was specified.
+ if test x"${with_tclconfig}" != x ; then
+ if test -f "${with_tclconfig}/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
+ fi
+ fi
+
+ # then check for a private Tcl installation
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ for i in \
+ ../tcl \
+ `ls -dr ../tcl[[7-9]]* 2>/dev/null` \
+ ../../tcl \
+ `ls -dr ../../tcl[[7-9]]* 2>/dev/null` \
+ ../../../tcl \
+ `ls -dr ../../../tcl[[7-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ for i in \
+ ${srcdir}/../tcl \
+ `ls -dr ${srcdir}/../tcl[[7-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_tclconfig}" = x ; then
+ TCLCONFIG="# no Tcl configs found"
+ AC_MSG_WARN(Can't find Tcl configuration definitions)
+ else
+ no_tcl=
+ TCLCONFIG=${ac_cv_c_tclconfig}/tclConfig.sh
+ AC_MSG_RESULT(found $TCLCONFIG)
+ fi
+fi
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_TCLCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_TCLCONFIG, [
+ . $TCLCONFIG
+
+ AC_SUBST(TCL_VERSION)
+ AC_SUBST(TCL_MAJOR_VERSION)
+ AC_SUBST(TCL_MINOR_VERSION)
+ AC_SUBST(TCL_CC)
+ AC_SUBST(TCL_DEFS)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_LIB_FILE)
+
+dnl don't export, not used outside of configure
+dnl AC_SUBST(TCL_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_EXEC_PREFIX)
+
+ AC_SUBST(TCL_SHLIB_CFLAGS)
+ AC_SUBST(TCL_SHLIB_LD)
+dnl don't export, not used outside of configure
+ AC_SUBST(TCL_SHLIB_LD_LIBS)
+ AC_SUBST(TCL_SHLIB_SUFFIX)
+dnl not used, don't export to save symbols
+ AC_SUBST(TCL_DL_LIBS)
+ AC_SUBST(TCL_LD_FLAGS)
+dnl don't export, not used outside of configure
+ AC_SUBST(TCL_LD_SEARCH_FLAGS)
+ AC_SUBST(TCL_CC_SEARCH_FLAGS)
+ AC_SUBST(TCL_COMPAT_OBJS)
+ AC_SUBST(TCL_RANLIB)
+ AC_SUBST(TCL_BUILD_LIB_SPEC)
+ AC_SUBST(TCL_LIB_SPEC)
+ AC_SUBST(TCL_LIB_VERSIONS_OK)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_SHARED_LIB_SUFFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TCL_UNSHARED_LIB_SUFFIX)
+])
+
+# Warning: Tk definitions are very similar to Tcl definitions but
+# are not precisely the same. There are a couple of differences,
+# so don't do changes to Tcl thinking you can cut and paste it do
+# the Tk differences and later simply substitute "Tk" for "Tcl".
+# Known differences:
+# - Acceptable Tcl major version #s is 7-9 while Tk is 4-9
+# - Searching for Tcl includes looking for tclInt.h, Tk looks for tk.h
+# - Computing major/minor versions is different because Tk depends on
+# headers to Tcl, Tk, and X.
+# - Symbols in tkConfig.sh are different than tclConfig.sh
+# - Acceptable for Tk to be missing but not Tcl.
+
+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 involked by --with-tkinclude
+#
+no_tk=true
+AC_MSG_CHECKING(for Tk private headers)
+AC_ARG_WITH(tkinclude, [ --with-tkinclude=DIR Directory where tk private headers are], with_tkinclude=${withval})
+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)`
+ elif test -f ${with_tkinclude}/generic/tk.h ; then
+ ac_cv_c_tkh=`(cd ${with_tkinclude}/generic; pwd)`
+ else
+ AC_MSG_ERROR([${with_tkinclude} directory doesn't contain private headers])
+ fi
+fi
+
+# next check if it came with Tk configuration file
+if test x"${ac_cv_c_tkconfig}" = x ; then
+ if test -f $ac_cv_c_tkconfig/../generic/tk.h ; then
+ ac_cv_c_tkh=`(cd $ac_cv_c_tkconfig/..; pwd)`
+ fi
+fi
+
+# next check in private source directory
+#
+# since ls returns lowest version numbers first, reverse its output
+if test x"${ac_cv_c_tkh}" = x ; then
+ for i in \
+ ${srcdir}/../tk \
+ `ls -dr ${srcdir}/../tk[[4-9]]* 2>/dev/null` \
+ ${srcdir}/../../tk \
+ `ls -dr ${srcdir}/../../tk[[4-9]]* 2>/dev/null` \
+ ${srcdir}/../../../tk \
+ `ls -dr ${srcdir}/../../../tk[[4-9]]* 2>/dev/null ` ; do
+ if test -f $i/generic/tk.h ; then
+ ac_cv_c_tkh=`(cd $i/generic; pwd)`
+ break
+ 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_tkh}" = x ; then
+ for i in \
+ `ls -dr /usr/local/src/tk[[4-9]]* 2>/dev/null` \
+ `ls -dr /usr/local/lib/tk[[4-9]]* 2>/dev/null` \
+ /usr/local/src/tk \
+ /usr/local/lib/tk \
+ ${prefix}/include ; do
+ if test -f $i/generic/tk.h ; then
+ ac_cv_c_tkh=`(cd $i/generic; 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, ac_cv_c_tkh="")
+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
+
+AC_SUBST(TKHDIR)
+])
+
+
+AC_DEFUN(CY_AC_PATH_TKCONFIG, [
+#
+# Ok, lets find the tk configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-tkconfig
+#
+
+if test x"${no_tk}" = x ; then
+ # we reset no_tk in case something fails here
+ no_tk=true
+ AC_ARG_WITH(tkconfig, [ --with-tkconfig=DIR Directory containing tk configuration (tkConfig.sh)],
+ with_tkconfig=${withval})
+ AC_MSG_CHECKING([for Tk configuration])
+ AC_CACHE_VAL(ac_cv_c_tkconfig,[
+
+ # First check to see if --with-tkconfig was specified.
+ if test x"${with_tkconfig}" != x ; then
+ if test -f "${with_tkconfig}/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh])
+ fi
+ fi
+
+ # then check for a private Tk library
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ for i in \
+ ../tk \
+ `ls -dr ../tk[[4-9]]* 2>/dev/null` \
+ ../../tk \
+ `ls -dr ../../tk[[4-9]]* 2>/dev/null` \
+ ../../../tk \
+ `ls -dr ../../../tk[[4-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ for i in \
+ ${srcdir}/../tk \
+ `ls -dr ${srcdir}/../tk[[4-9]]* 2>/dev/null` ; do
+ if test -f "$i/${configdir}/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i/${configdir}; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_tkconfig}" = x ; then
+ TKCONFIG="# no Tk configs found"
+ AC_MSG_WARN(Can't find Tk configuration definitions)
+ else
+ no_tk=
+ TKCONFIG=${ac_cv_c_tkconfig}/tkConfig.sh
+ AC_MSG_RESULT(found $TKCONFIG)
+ fi
+fi
+
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_TKCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_TKCONFIG, [
+ if test -f "$TKCONFIG" ; then
+ . $TKCONFIG
+ fi
+
+ AC_SUBST(TK_VERSION)
+dnl not actually used, don't export to save symbols
+dnl AC_SUBST(TK_MAJOR_VERSION)
+dnl AC_SUBST(TK_MINOR_VERSION)
+ AC_SUBST(TK_DEFS)
+
+dnl not used, don't export to save symbols
+ dnl AC_SUBST(TK_LIB_FILE)
+
+dnl not used outside of configure
+dnl AC_SUBST(TK_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TK_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(TK_EXEC_PREFIX)
+
+ AC_SUBST(TK_BUILD_INCLUDES)
+ AC_SUBST(TK_XINCLUDES)
+ AC_SUBST(TK_XLIBSW)
+ AC_SUBST(TK_BUILD_LIB_SPEC)
+ AC_SUBST(TK_LIB_SPEC)
+])
+
+# check for Itcl headers.
+
+AC_DEFUN(CY_AC_PATH_ITCLCONFIG, [
+#
+# Ok, lets find the itcl configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-itclconfig
+#
+
+if test x"${no_itcl}" = x ; then
+ # we reset no_itcl in case something fails here
+ no_itcl=true
+ AC_ARG_WITH(itclconfig, [ --with-itclconfig Directory containing itcl configuration (itclConfig.sh)],
+ with_itclconfig=${withval})
+ AC_MSG_CHECKING([for Itcl configuration])
+ AC_CACHE_VAL(ac_cv_c_itclconfig,[
+
+ # First check to see if --with-itclconfig was specified.
+ if test x"${with_itclconfig}" != x ; then
+ if test -f "${with_itclconfig}/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd ${with_itclconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_itclconfig} directory doesn't contain itclConfig.sh])
+ fi
+ fi
+
+ # then check for a private Itcl library
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ for i in \
+ ../itcl/itcl \
+ `ls -dr ../itcl[[4-9]]*/itcl 2>/dev/null` \
+ ../../itcl \
+ `ls -dr ../../itcl[[4-9]]*/itcl 2>/dev/null` \
+ ../../../itcl \
+ `ls -dr ../../../itcl[[4-9]]*/itcl 2>/dev/null` ; do
+ if test -f "$i/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ for i in \
+ ${srcdir}/../itcl/itcl \
+ `ls -dr ${srcdir}/../itcl[[4-9]]*/itcl 2>/dev/null` ; do
+ if test -f "$i/itclConfig.sh" ; then
+ ac_cv_c_itclconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_itclconfig}" = x ; then
+ ITCLCONFIG="# no Itcl configs found"
+ AC_MSG_WARN(Can't find Itcl configuration definitions)
+ else
+ no_itcl=
+ ITCLCONFIG=${ac_cv_c_itclconfig}/itclConfig.sh
+ AC_MSG_RESULT(found $ITCLCONFIG)
+ fi
+fi
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_ITCLCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_ITCLCONFIG, [
+ if test -f "$ITCLCONFIG" ; then
+ . $ITCLCONFIG
+ fi
+
+ AC_SUBST(ITCL_VERSION)
+dnl not actually used, don't export to save symbols
+dnl AC_SUBST(ITCL_MAJOR_VERSION)
+dnl AC_SUBST(ITCL_MINOR_VERSION)
+ AC_SUBST(ITCL_DEFS)
+
+dnl not used, don't export to save symbols
+ dnl AC_SUBST(ITCL_LIB_FILE)
+
+dnl not used outside of configure
+dnl AC_SUBST(ITCL_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITCL_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITCL_EXEC_PREFIX)
+
+ AC_SUBST(ITCL_BUILD_INCLUDES)
+ AC_SUBST(ITCL_BUILD_LIB_SPEC)
+ AC_SUBST(ITCL_LIB_SPEC)
+])
+
+# check for Itcl headers.
+
+AC_DEFUN(CY_AC_PATH_ITCLH, [
+AC_MSG_CHECKING(for Itcl private headers. srcdir=${srcdir})
+if test x"${ac_cv_c_itclh}" = x ; then
+ for i in ${srcdir}/../itcl ${srcdir}/../../itcl ${srcdir}/../../../itcl ${srcdir}/../itcl/itcl; do
+ if test -f $i/generic/itcl.h ; then
+ ac_cv_c_itclh=`(cd $i/generic; pwd)`
+ break
+ fi
+ done
+fi
+if test x"${ac_cv_c_itclh}" = x ; then
+ ITCLHDIR="# no Itcl private headers found"
+ AC_MSG_ERROR([Can't find Itcl private headers])
+fi
+if test x"${ac_cv_c_itclh}" != x ; then
+ ITCLHDIR="-I${ac_cv_c_itclh}"
+fi
+# should always be here
+# ITCLLIB="../itcl/itcl/unix/libitcl.a"
+AC_SUBST(ITCLHDIR)
+#AC_SUBST(ITCLLIB)
+])
+
+
+AC_DEFUN(CY_AC_PATH_ITKCONFIG, [
+#
+# Ok, lets find the itk configuration
+# First, look for one uninstalled.
+# the alternative search directory is invoked by --with-itkconfig
+#
+
+if test x"${no_itk}" = x ; then
+ # we reset no_itk in case something fails here
+ no_itk=true
+ AC_ARG_WITH(itkconfig, [ --with-itkconfig Directory containing itk configuration (itkConfig.sh)],
+ with_itkconfig=${withval})
+ AC_MSG_CHECKING([for Itk configuration])
+ AC_CACHE_VAL(ac_cv_c_itkconfig,[
+
+ # First check to see if --with-itkconfig was specified.
+ if test x"${with_itkconfig}" != x ; then
+ if test -f "${with_itkconfig}/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd ${with_itkconfig}; pwd)`
+ else
+ AC_MSG_ERROR([${with_itkconfig} directory doesn't contain itkConfig.sh])
+ fi
+ fi
+
+ # then check for a private Itk library
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ for i in \
+ ../itcl/itk \
+ `ls -dr ../itcl[[4-9]]*/itk 2>/dev/null` \
+ ../../itk \
+ `ls -dr ../../itcl[[4-9]]*/itk 2>/dev/null` \
+ ../../../itk \
+ `ls -dr ../../../itcl[[4-9]]*/itk 2>/dev/null` ; do
+ if test -f "$i/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few common install locations
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
+ if test -f "$i/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ # check in a few other private locations
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ for i in \
+ ${srcdir}/../itcl/itk \
+ `ls -dr ${srcdir}/../itcl[[4-9]]*/itk 2>/dev/null` ; do
+ if test -f "$i/itkConfig.sh" ; then
+ ac_cv_c_itkconfig=`(cd $i; pwd)`
+ break
+ fi
+ done
+ fi
+ ])
+ if test x"${ac_cv_c_itkconfig}" = x ; then
+ ITKCONFIG="# no Itk configs found"
+ AC_MSG_WARN(Can't find Itk configuration definitions)
+ else
+ no_itk=
+ ITKCONFIG=${ac_cv_c_itkconfig}/itkConfig.sh
+ AC_MSG_RESULT(found $ITKCONFIG)
+ fi
+fi
+
+])
+
+# Defined as a separate macro so we don't have to cache the values
+# from PATH_ITKCONFIG (because this can also be cached).
+AC_DEFUN(CY_AC_LOAD_ITKCONFIG, [
+ if test -f "$ITKCONFIG" ; then
+ . $ITKCONFIG
+ fi
+
+ AC_SUBST(ITK_VERSION)
+dnl not actually used, don't export to save symbols
+dnl AC_SUBST(ITK_MAJOR_VERSION)
+dnl AC_SUBST(ITK_MINOR_VERSION)
+ AC_SUBST(ITK_DEFS)
+
+dnl not used, don't export to save symbols
+ dnl AC_SUBST(ITK_LIB_FILE)
+
+dnl not used outside of configure
+dnl AC_SUBST(ITK_LIBS)
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITK_PREFIX)
+
+dnl not used, don't export to save symbols
+dnl AC_SUBST(ITK_EXEC_PREFIX)
+
+ AC_SUBST(ITK_BUILD_INCLUDES)
+ AC_SUBST(ITK_BUILD_LIB_SPEC)
+ AC_SUBST(ITK_LIB_SPEC)
+])
+
+AC_DEFUN(CY_AC_PATH_ITKH, [
+AC_MSG_CHECKING(for Itk private headers. srcdir=${srcdir})
+if test x"${ac_cv_c_itkh}" = x ; then
+ for i in ${srcdir}/../itcl ${srcdir}/../../itcl ${srcdir}/../../../itcl ${srcdir}/../itcl/itk; do
+ if test -f $i/generic/itk.h ; then
+ ac_cv_c_itkh=`(cd $i/generic; pwd)`
+ break
+ fi
+ done
+fi
+if test x"${ac_cv_c_itkh}" = x ; then
+ ITKHDIR="# no Itk private headers found"
+ AC_MSG_ERROR([Can't find Itk private headers])
+fi
+if test x"${ac_cv_c_itkh}" != x ; then
+ ITKHDIR="-I${ac_cv_c_itkh}"
+fi
+# should always be here
+# ITKLIB="../itcl/itk/unix/libitk.a"
+AC_SUBST(ITKHDIR)
+#AC_SUBST(ITKLIB)
+])
+
+
+dnl sinclude(../gettext.m4) already included by bfd/acinclude.m4
+dnl The lines below arrange for aclocal not to bring gettext.m4's
+dnl CY_GNU_GETTEXT into aclocal.m4.
+ifelse(yes,no,[
+AC_DEFUN([CY_GNU_GETTEXT],)
+])
+
+
+# Copyright 1996, 1997, 1999, 2000, 2001 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.
+
+# serial 1
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so. This macro tries various
+# options that select ANSI C on some system or another. It considers the
+# compiler to be in ANSI C mode if it handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN([AM_PROG_CC_STDC],
+[AC_REQUIRE([AC_PROG_CC])
+AC_BEFORE([$0], [AC_C_INLINE])
+AC_BEFORE([$0], [AC_C_CONST])
+dnl Force this before AC_PROG_CPP. Some cpp's, eg on HPUX, require
+dnl a magic option to avoid problems with ANSI preprocessor commands
+dnl like #elif.
+dnl FIXME: can't do this because then AC_AIX won't work due to a
+dnl circular dependency.
+dnl AC_BEFORE([$0], [AC_PROG_CPP])
+AC_MSG_CHECKING([for ${CC-cc} option to accept ANSI C])
+AC_CACHE_VAL(am_cv_prog_cc_stdc,
+[am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ AC_TRY_COMPILE(
+[#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+], [
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+],
+[am_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CC="$ac_save_CC"
+])
+if test -z "$am_cv_prog_cc_stdc"; then
+ AC_MSG_RESULT([none needed])
+else
+ AC_MSG_RESULT([$am_cv_prog_cc_stdc])
+fi
+case "x$am_cv_prog_cc_stdc" in
+ x|xno) ;;
+ *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+])
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV],
+[
+ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+ dnl those with the standalone portable GNU libiconv installed).
+
+ AC_ARG_WITH([libiconv-prefix],
+[ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [
+ for dir in `echo "$withval" | tr : ' '`; do
+ if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi
+ if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi
+ done
+ ])
+
+ AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
+ am_cv_func_iconv="no, consider installing GNU libiconv"
+ am_cv_lib_iconv=no
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ am_cv_func_iconv=yes)
+ if test "$am_cv_func_iconv" != yes; then
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS -liconv"
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ am_cv_lib_iconv=yes
+ am_cv_func_iconv=yes)
+ LIBS="$am_save_LIBS"
+ fi
+ ])
+ if test "$am_cv_func_iconv" = yes; then
+ AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
+ AC_MSG_CHECKING([for iconv declaration])
+ AC_CACHE_VAL(am_cv_proto_iconv, [
+ AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+ am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+ am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+ AC_MSG_RESULT([$]{ac_t:-
+ }[$]am_cv_proto_iconv)
+ AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
+ [Define as const if the declaration of iconv() needs const.])
+ fi
+ LIBICONV=
+ if test "$am_cv_lib_iconv" = yes; then
+ LIBICONV="-liconv"
+ fi
+ AC_SUBST(LIBICONV)
+])
+
+# AC_GNU_SOURCE
+# -------------
+# FIXME: Remove thise once we start using Autoconf 2.5x (x>=4).
+AC_DEFUN([AC_GNU_SOURCE],
+[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl
+AC_BEFORE([$0], [AC_TRY_RUN])dnl
+AC_DEFINE([_GNU_SOURCE])
+])
+
+dnl written by Guido Draheim <guidod@gmx.de>, original by Alexandre Oliva
+dnl Version 1.3 (2001/03/02)
+dnl source http://www.gnu.org/software/ac-archive/Miscellaneous/ac_define_dir.html
+
+AC_DEFUN([AC_DEFINE_DIR], [
+ test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+ ac_define_dir=`eval echo [$]$2`
+ ac_define_dir=`eval echo [$]ac_define_dir`
+ ifelse($3, ,
+ AC_DEFINE_UNQUOTED($1, "$ac_define_dir"),
+ AC_DEFINE_UNQUOTED($1, "$ac_define_dir", $3))
+])
+
+dnl See whether we need a declaration for a function.
+dnl The result is highly dependent on the INCLUDES passed in, so make sure
+dnl to use a different cache variable name in this macro if it is invoked
+dnl in a different context somewhere else.
+dnl gcc_AC_CHECK_DECL(SYMBOL,
+dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]])
+AC_DEFUN(gcc_AC_CHECK_DECL,
+[AC_MSG_CHECKING([whether $1 is declared])
+AC_CACHE_VAL(gcc_cv_have_decl_$1,
+[AC_TRY_COMPILE([$4],
+[#ifndef $1
+char *(*pfn) = (char *(*)) $1 ;
+#endif], eval "gcc_cv_have_decl_$1=yes", eval "gcc_cv_have_decl_$1=no")])
+if eval "test \"`echo '$gcc_cv_have_decl_'$1`\" = yes"; then
+ AC_MSG_RESULT(yes) ; ifelse([$2], , :, [$2])
+else
+ AC_MSG_RESULT(no) ; ifelse([$3], , :, [$3])
+fi
+])dnl
+
+dnl Check multiple functions to see whether each needs a declaration.
+dnl Arrange to define HAVE_DECL_<FUNCTION> to 0 or 1 as appropriate.
+dnl gcc_AC_CHECK_DECLS(SYMBOLS,
+dnl [ACTION-IF-NEEDED [, ACTION-IF-NOT-NEEDED [, INCLUDES]]])
+AC_DEFUN(gcc_AC_CHECK_DECLS,
+[for ac_func in $1
+do
+changequote(, )dnl
+ ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+changequote([, ])dnl
+gcc_AC_CHECK_DECL($ac_func,
+ [AC_DEFINE_UNQUOTED($ac_tr_decl, 1) $2],
+ [AC_DEFINE_UNQUOTED($ac_tr_decl, 0) $3],
+dnl It is possible that the include files passed in here are local headers
+dnl which supply a backup declaration for the relevant prototype based on
+dnl the definition of (or lack of) the HAVE_DECL_ macro. If so, this test
+dnl will always return success. E.g. see libiberty.h's handling of
+dnl `basename'. To avoid this, we define the relevant HAVE_DECL_ macro to
+dnl 1 so that any local headers used do not provide their own prototype
+dnl during this test.
+#undef $ac_tr_decl
+#define $ac_tr_decl 1
+ $4
+)
+done
+dnl Automatically generate config.h entries via autoheader.
+if test x = y ; then
+ patsubst(translit([$1], [a-z], [A-Z]), [\w+],
+ [AC_DEFINE([HAVE_DECL_\&], 1,
+ [Define to 1 if we found this declaration otherwise define to 0.])])dnl
+fi
+])
+
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# serial 1
+
+AC_DEFUN(AM_MAINTAINER_MODE,
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT($USE_MAINTAINER_MODE)
+ AM_CONDITIONAL(MAINTAINER_MODE, test $USE_MAINTAINER_MODE = yes)
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+# Define a conditional.
+
+AC_DEFUN(AM_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi])
+
diff --git a/contrib/gdb/gdb/ada-exp.c b/contrib/gdb/gdb/ada-exp.c
new file mode 100644
index 0000000..b8dad7a
--- /dev/null
+++ b/contrib/gdb/gdb/ada-exp.c
@@ -0,0 +1,2642 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ NULL_PTR = 259,
+ CHARLIT = 260,
+ FLOAT = 261,
+ TYPENAME = 262,
+ BLOCKNAME = 263,
+ STRING = 264,
+ NAME = 265,
+ DOT_ID = 266,
+ OBJECT_RENAMING = 267,
+ DOT_ALL = 268,
+ LAST = 269,
+ REGNAME = 270,
+ INTERNAL_VARIABLE = 271,
+ ASSIGN = 272,
+ ELSE = 273,
+ THEN = 274,
+ XOR = 275,
+ OR = 276,
+ _AND_ = 277,
+ DOTDOT = 278,
+ IN = 279,
+ GEQ = 280,
+ LEQ = 281,
+ NOTEQUAL = 282,
+ UNARY = 283,
+ REM = 284,
+ MOD = 285,
+ NOT = 286,
+ ABS = 287,
+ STARSTAR = 288,
+ TICK_LENGTH = 289,
+ TICK_LAST = 290,
+ TICK_FIRST = 291,
+ TICK_ADDRESS = 292,
+ TICK_ACCESS = 293,
+ TICK_MODULUS = 294,
+ TICK_MIN = 295,
+ TICK_MAX = 296,
+ TICK_VAL = 297,
+ TICK_TAG = 298,
+ TICK_SIZE = 299,
+ TICK_RANGE = 300,
+ TICK_POS = 301,
+ ARROW = 302,
+ NEW = 303
+ };
+#endif
+#define INT 258
+#define NULL_PTR 259
+#define CHARLIT 260
+#define FLOAT 261
+#define TYPENAME 262
+#define BLOCKNAME 263
+#define STRING 264
+#define NAME 265
+#define DOT_ID 266
+#define OBJECT_RENAMING 267
+#define DOT_ALL 268
+#define LAST 269
+#define REGNAME 270
+#define INTERNAL_VARIABLE 271
+#define ASSIGN 272
+#define ELSE 273
+#define THEN 274
+#define XOR 275
+#define OR 276
+#define _AND_ 277
+#define DOTDOT 278
+#define IN 279
+#define GEQ 280
+#define LEQ 281
+#define NOTEQUAL 282
+#define UNARY 283
+#define REM 284
+#define MOD 285
+#define NOT 286
+#define ABS 287
+#define STARSTAR 288
+#define TICK_LENGTH 289
+#define TICK_LAST 290
+#define TICK_FIRST 291
+#define TICK_ADDRESS 292
+#define TICK_ACCESS 293
+#define TICK_MODULUS 294
+#define TICK_MIN 295
+#define TICK_MAX 296
+#define TICK_VAL 297
+#define TICK_TAG 298
+#define TICK_SIZE 299
+#define TICK_RANGE 300
+#define TICK_POS 301
+#define ARROW 302
+#define NEW 303
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 38 "ada-exp.y"
+
+
+#include "defs.h"
+#include <string.h>
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "ada-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "frame.h"
+#include "block.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. These are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix
+ options. I presume we are maintaining it to accommodate systems
+ without BISON? (PNH) */
+
+#define yymaxdepth ada_maxdepth
+#define yyparse _ada_parse /* ada_parse calls this after initialization */
+#define yylex ada_lex
+#define yyerror ada_error
+#define yylval ada_lval
+#define yychar ada_char
+#define yydebug ada_debug
+#define yypact ada_pact
+#define yyr1 ada_r1
+#define yyr2 ada_r2
+#define yydef ada_def
+#define yychk ada_chk
+#define yypgo ada_pgo
+#define yyact ada_act
+#define yyexca ada_exca
+#define yyerrflag ada_errflag
+#define yynerrs ada_nerrs
+#define yyps ada_ps
+#define yypv ada_pv
+#define yys ada_s
+#define yy_yys ada_yys
+#define yystate ada_state
+#define yytmp ada_tmp
+#define yyv ada_v
+#define yy_yyv ada_yyv
+#define yyval ada_val
+#define yylloc ada_lloc
+#define yyreds ada_reds /* With YYDEBUG defined */
+#define yytoks ada_toks /* With YYDEBUG defined */
+#define yyname ada_name /* With YYDEBUG defined */
+#define yyrule ada_rule /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+struct name_info {
+ struct symbol* sym;
+ struct minimal_symbol* msym;
+ struct block* block;
+ struct stoken stoken;
+};
+
+/* If expression is in the context of TYPE'(...), then TYPE, else
+ * NULL. */
+static struct type* type_qualifier;
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static struct stoken string_to_operator (struct stoken);
+
+static void write_attribute_call0 (enum ada_attribute);
+
+static void write_attribute_call1 (enum ada_attribute, LONGEST);
+
+static void write_attribute_calln (enum ada_attribute, int);
+
+static void write_object_renaming (struct block*, struct symbol*);
+
+static void write_var_from_name (struct block*, struct name_info);
+
+static LONGEST
+convert_char_literal (struct type*, LONGEST);
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 137 "ada-exp.y"
+typedef union YYSTYPE {
+ LONGEST lval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val;
+ struct {
+ DOUBLEST dval;
+ struct type *type;
+ } typed_val_float;
+ struct type *tval;
+ struct stoken sval;
+ struct name_info ssym;
+ int voidval;
+ struct block *bval;
+ struct internalvar *ivar;
+
+ } YYSTYPE;
+/* Line 191 of yacc.c. */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 214 of yacc.c. */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC xmalloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 44
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 1067
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 68
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 15
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 98
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 184
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 303
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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, 2, 34, 63,
+ 57, 62, 36, 32, 64, 33, 56, 37, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 61,
+ 24, 23, 25, 2, 31, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 58, 2, 67, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 65, 2, 66, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 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, 26, 27,
+ 28, 29, 30, 35, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 59, 60
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 13, 16, 19, 24,
+ 29, 30, 38, 39, 46, 50, 52, 54, 56, 58,
+ 60, 64, 67, 70, 73, 76, 77, 79, 83, 87,
+ 93, 98, 102, 106, 110, 114, 118, 122, 126, 130,
+ 134, 138, 142, 146, 152, 158, 162, 169, 176, 181,
+ 185, 189, 193, 197, 202, 206, 211, 215, 218, 221,
+ 225, 229, 233, 236, 239, 247, 255, 261, 265, 269,
+ 273, 279, 282, 283, 287, 289, 291, 292, 294, 296,
+ 298, 300, 302, 305, 307, 310, 312, 315, 317, 319,
+ 321, 323, 326, 328, 331, 334, 338, 341, 344
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 69, 0, -1, 70, -1, 82, -1, 74, -1, 70,
+ 61, 74, -1, 71, 13, -1, 71, 11, -1, 71,
+ 57, 75, 62, -1, 82, 57, 74, 62, -1, -1,
+ 82, 63, 73, 72, 57, 74, 62, -1, -1, 71,
+ 57, 74, 26, 74, 62, -1, 57, 70, 62, -1,
+ 79, -1, 15, -1, 16, -1, 71, -1, 14, -1,
+ 74, 17, 74, -1, 33, 74, -1, 32, 74, -1,
+ 40, 74, -1, 41, 74, -1, -1, 74, -1, 80,
+ 59, 74, -1, 75, 64, 74, -1, 75, 64, 80,
+ 59, 74, -1, 65, 82, 66, 74, -1, 74, 42,
+ 74, -1, 74, 36, 74, -1, 74, 37, 74, -1,
+ 74, 38, 74, -1, 74, 39, 74, -1, 74, 31,
+ 74, -1, 74, 32, 74, -1, 74, 34, 74, -1,
+ 74, 33, 74, -1, 74, 23, 74, -1, 74, 30,
+ 74, -1, 74, 29, 74, -1, 74, 27, 74, 26,
+ 74, -1, 74, 27, 74, 54, 76, -1, 74, 27,
+ 7, -1, 74, 40, 27, 74, 26, 74, -1, 74,
+ 40, 27, 74, 54, 76, -1, 74, 40, 27, 7,
+ -1, 74, 28, 74, -1, 74, 24, 74, -1, 74,
+ 25, 74, -1, 74, 22, 74, -1, 74, 22, 19,
+ 74, -1, 74, 21, 74, -1, 74, 21, 18, 74,
+ -1, 74, 20, 74, -1, 71, 47, -1, 71, 46,
+ -1, 71, 45, 76, -1, 71, 44, 76, -1, 71,
+ 43, 76, -1, 71, 53, -1, 71, 52, -1, 78,
+ 49, 57, 74, 64, 74, 62, -1, 78, 50, 57,
+ 74, 64, 74, 62, -1, 78, 55, 57, 74, 62,
+ -1, 77, 45, 76, -1, 77, 44, 76, -1, 77,
+ 43, 76, -1, 77, 51, 57, 74, 62, -1, 77,
+ 48, -1, -1, 57, 3, 62, -1, 7, -1, 77,
+ -1, -1, 3, -1, 5, -1, 6, -1, 4, -1,
+ 9, -1, 60, 7, -1, 10, -1, 81, 10, -1,
+ 12, -1, 81, 12, -1, 10, -1, 7, -1, 12,
+ -1, 8, -1, 81, 8, -1, 7, -1, 81, 7,
+ -1, 7, 47, -1, 81, 7, 47, -1, 36, 74,
+ -1, 34, 74, -1, 74, 58, 74, 67, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 208, 208, 209, 215, 216, 221, 225, 232, 240,
+ 248, 248, 259, 263, 267, 270, 273, 280, 288, 291,
+ 298, 302, 306, 310, 314, 318, 321, 323, 325, 327,
+ 331, 341, 345, 349, 353, 357, 361, 365, 369, 373,
+ 377, 381, 385, 389, 393, 399, 406, 411, 419, 429,
+ 433, 437, 441, 445, 449, 453, 457, 461, 463, 469,
+ 471, 473, 475, 477, 479, 481, 483, 485, 487, 489,
+ 491, 493, 497, 499, 504, 511, 513, 519, 527, 539,
+ 547, 555, 582, 586, 587, 589, 590, 594, 595, 596,
+ 599, 601, 606, 607, 608, 610, 617, 619, 621
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INT", "NULL_PTR", "CHARLIT", "FLOAT",
+ "TYPENAME", "BLOCKNAME", "STRING", "NAME", "DOT_ID", "OBJECT_RENAMING",
+ "DOT_ALL", "LAST", "REGNAME", "INTERNAL_VARIABLE", "ASSIGN", "ELSE",
+ "THEN", "XOR", "OR", "_AND_", "'='", "'<'", "'>'", "DOTDOT", "IN",
+ "GEQ", "LEQ", "NOTEQUAL", "'@'", "'+'", "'-'", "'&'", "UNARY", "'*'",
+ "'/'", "REM", "MOD", "NOT", "ABS", "STARSTAR", "TICK_LENGTH",
+ "TICK_LAST", "TICK_FIRST", "TICK_ADDRESS", "TICK_ACCESS",
+ "TICK_MODULUS", "TICK_MIN", "TICK_MAX", "TICK_VAL", "TICK_TAG",
+ "TICK_SIZE", "TICK_RANGE", "TICK_POS", "'.'", "'('", "'['", "ARROW",
+ "NEW", "';'", "')'", "'''", "','", "'{'", "'}'", "']'", "$accept",
+ "start", "exp1", "simple_exp", "@1", "save_qualifier", "exp", "arglist",
+ "tick_arglist", "type_prefix", "opt_type_prefix", "variable",
+ "any_name", "block", "type", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 61, 60, 62, 278, 279, 280, 281,
+ 282, 64, 43, 45, 38, 283, 42, 47, 284, 285,
+ 286, 287, 288, 289, 290, 291, 292, 293, 294, 295,
+ 296, 297, 298, 299, 300, 301, 46, 40, 91, 302,
+ 303, 59, 41, 39, 44, 123, 125, 93
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 68, 69, 69, 70, 70, 71, 71, 71, 71,
+ 72, 71, 73, 71, 71, 71, 71, 71, 74, 71,
+ 74, 74, 74, 74, 74, 75, 75, 75, 75, 75,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 76, 76, 77, 78, 78, 74, 74, 74,
+ 74, 74, 74, 79, 79, 79, 79, 80, 80, 80,
+ 81, 81, 82, 82, 82, 82, 74, 74, 74
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 1, 1, 1, 3, 2, 2, 4, 4,
+ 0, 7, 0, 6, 3, 1, 1, 1, 1, 1,
+ 3, 2, 2, 2, 2, 0, 1, 3, 3, 5,
+ 4, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 5, 5, 3, 6, 6, 4, 3,
+ 3, 3, 3, 4, 3, 4, 3, 2, 2, 3,
+ 3, 3, 2, 2, 7, 7, 5, 3, 3, 3,
+ 5, 2, 0, 3, 1, 1, 0, 1, 1, 1,
+ 1, 1, 2, 1, 2, 1, 2, 1, 1, 1,
+ 1, 2, 1, 2, 2, 3, 2, 2, 4
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 76, 77, 80, 78, 79, 74, 90, 81, 83, 85,
+ 19, 16, 17, 76, 76, 76, 76, 76, 76, 76,
+ 0, 0, 0, 2, 18, 4, 75, 0, 15, 0,
+ 3, 94, 22, 0, 21, 97, 96, 23, 24, 0,
+ 82, 92, 0, 0, 1, 76, 7, 6, 72, 72,
+ 72, 58, 57, 63, 62, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 0, 76, 76, 72, 72,
+ 72, 71, 0, 0, 0, 0, 93, 91, 84, 86,
+ 76, 12, 14, 76, 5, 0, 61, 60, 59, 74,
+ 83, 85, 26, 0, 0, 20, 56, 76, 54, 76,
+ 52, 40, 50, 51, 45, 0, 49, 42, 41, 36,
+ 37, 39, 38, 32, 33, 34, 35, 76, 31, 0,
+ 69, 68, 67, 76, 76, 76, 76, 95, 0, 10,
+ 30, 0, 76, 8, 76, 76, 55, 53, 76, 72,
+ 48, 0, 98, 0, 0, 0, 0, 9, 0, 73,
+ 0, 28, 0, 27, 43, 44, 76, 72, 70, 76,
+ 76, 66, 76, 13, 76, 46, 47, 0, 0, 0,
+ 29, 64, 65, 11
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short yydefgoto[] =
+{
+ -1, 22, 23, 24, 158, 139, 25, 103, 96, 26,
+ 27, 28, 104, 29, 33
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -44
+static const short yypact[] =
+{
+ 251, -44, -44, -44, -44, 15, -44, -44, -44, -44,
+ -44, -44, -44, 251, 251, 251, 251, 251, 251, 251,
+ 17, 2, 31, 10, 55, 947, -18, 20, -44, 118,
+ -29, -44, 374, -29, 374, 18, 18, 374, 374, -21,
+ -44, 32, 66, 16, -44, 251, -44, -44, 24, 24,
+ 24, -44, -44, -44, -44, 133, 251, 251, 173, 212,
+ 251, 251, 251, 290, 251, 251, 251, 251, 251, 251,
+ 251, 251, 251, 251, 251, 59, 251, 251, 24, 24,
+ 24, -44, 35, 38, 40, 47, 58, -44, -44, -44,
+ 251, -44, -44, 251, 947, 107, -44, -44, -44, 56,
+ 52, 57, 915, 3, 68, 979, 1002, 251, 1002, 251,
+ 1002, -20, -20, -20, 1004, 837, -20, -20, -20, 51,
+ 374, 374, 374, -19, -19, -19, -19, 329, -19, 414,
+ -44, -44, -44, 251, 251, 251, 251, -44, 536, -44,
+ 18, 71, 251, -44, 368, 251, 1002, 1002, 251, 24,
+ 1004, 876, -44, 579, 446, 491, 622, -44, 60, -44,
+ 665, 947, 75, 947, -20, -44, 251, 24, -44, 251,
+ 251, -44, 251, -44, 251, -20, -44, 708, 751, 794,
+ 947, -44, -44, -44
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -44, -44, 99, -44, -44, -44, -13, -44, -43, -44,
+ -44, -44, 0, 125, 8
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -93
+static const short yytable[] =
+{
+ 32, 34, 35, 36, 37, 38, 97, 98, 30, 41,
+ 6, 67, 68, 69, 70, -92, 71, 72, 73, 74,
+ 75, 75, 76, 76, 40, 78, 79, 80, 90, 43,
+ 81, 44, 94, 82, 91, 130, 131, 132, 77, 77,
+ 45, 92, 102, 105, 106, 108, 110, 111, 112, 113,
+ 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 31, 128, 129, 143, 46, 144, 47, 83,
+ 84, 45, -92, 86, 87, 85, 77, 138, -92, 31,
+ 140, 95, 93, 68, 69, 70, 127, 71, 72, 73,
+ 74, 75, 133, 76, 146, 134, 147, 135, 48, 49,
+ 50, 51, 52, 31, 136, 137, 165, 53, 54, 77,
+ 141, -87, 55, -92, 151, -88, -89, 172, 39, -92,
+ 153, 154, 155, 156, 176, 86, 87, 145, 88, 160,
+ 89, 161, 163, 159, 174, 164, 1, 2, 3, 4,
+ 99, 6, 7, 100, 162, 101, 42, 10, 11, 12,
+ 0, 0, 0, 175, 0, 0, 177, 178, 0, 179,
+ 0, 180, 0, 0, 0, 13, 14, 15, 0, 16,
+ 0, 0, 0, 17, 18, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 0, 9, 0, 10, 11, 12,
+ 19, 107, 0, 20, 0, -25, 0, -25, 21, 0,
+ 0, 0, 0, 0, 0, 13, 14, 15, 0, 16,
+ 0, 0, 0, 17, 18, 1, 2, 3, 4, 5,
+ 6, 7, 8, 0, 9, 0, 10, 11, 12, 0,
+ 19, 109, 0, 20, 0, 0, 0, 0, 21, 0,
+ 0, 0, 0, 0, 13, 14, 15, 0, 16, 0,
+ 0, 0, 17, 18, 1, 2, 3, 4, 5, 6,
+ 7, 8, 0, 9, 0, 10, 11, 12, 0, 19,
+ 0, 0, 20, 0, 0, 0, 0, 21, 0, 0,
+ 0, 0, 0, 13, 14, 15, 0, 16, 0, 0,
+ 0, 17, 18, 1, 2, 3, 4, 114, 6, 7,
+ 8, 0, 9, 0, 10, 11, 12, 0, 19, 0,
+ 0, 20, 0, 0, 0, 0, 21, 0, 0, 0,
+ 0, 0, 13, 14, 15, 0, 16, 0, 0, 0,
+ 17, 18, 1, 2, 3, 4, 150, 6, 7, 8,
+ 0, 9, 0, 10, 11, 12, 0, 19, 0, 0,
+ 20, 0, 0, 0, 0, 21, 0, 0, 0, 0,
+ 0, 13, 14, 15, 0, 16, 0, 0, 0, 17,
+ 18, 1, 2, 3, 4, 99, 6, 7, 100, 0,
+ 101, 0, 10, 11, 12, 0, 19, 0, 0, 20,
+ 0, 0, 0, 0, 21, 0, 0, 0, 0, 0,
+ 13, 14, 15, 0, 16, 0, 0, 0, 17, 18,
+ 71, 72, 73, 74, 75, 0, 76, 0, 0, 0,
+ 0, 0, 0, 0, 0, 19, 0, 0, 20, 0,
+ 0, 56, 77, 21, 57, 58, 59, 60, 61, 62,
+ 0, 63, 64, 65, 66, 67, 68, 69, 70, 0,
+ 71, 72, 73, 74, 75, 0, 76, 0, 0, 0,
+ 0, 0, 0, 56, 0, 0, 57, 58, 59, 60,
+ 61, 62, 77, 63, 64, 65, 66, 67, 68, 69,
+ 70, 152, 71, 72, 73, 74, 75, 0, 76, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 77, 0, 0, 0, 56, 0,
+ 169, 57, 58, 59, 60, 61, 62, 0, 63, 64,
+ 65, 66, 67, 68, 69, 70, 0, 71, 72, 73,
+ 74, 75, 0, 76, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 77,
+ 0, 0, 0, 56, 0, 170, 57, 58, 59, 60,
+ 61, 62, 0, 63, 64, 65, 66, 67, 68, 69,
+ 70, 0, 71, 72, 73, 74, 75, 0, 76, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 77, 0, 56, 0, 157, 57,
+ 58, 59, 60, 61, 62, 0, 63, 64, 65, 66,
+ 67, 68, 69, 70, 0, 71, 72, 73, 74, 75,
+ 0, 76, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 77, 0, 56,
+ 0, 168, 57, 58, 59, 60, 61, 62, 0, 63,
+ 64, 65, 66, 67, 68, 69, 70, 0, 71, 72,
+ 73, 74, 75, 0, 76, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 77, 0, 56, 0, 171, 57, 58, 59, 60, 61,
+ 62, 0, 63, 64, 65, 66, 67, 68, 69, 70,
+ 0, 71, 72, 73, 74, 75, 0, 76, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 77, 0, 56, 0, 173, 57, 58,
+ 59, 60, 61, 62, 0, 63, 64, 65, 66, 67,
+ 68, 69, 70, 0, 71, 72, 73, 74, 75, 0,
+ 76, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 77, 0, 56, 0,
+ 181, 57, 58, 59, 60, 61, 62, 0, 63, 64,
+ 65, 66, 67, 68, 69, 70, 0, 71, 72, 73,
+ 74, 75, 0, 76, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 77,
+ 0, 56, 0, 182, 57, 58, 59, 60, 61, 62,
+ 0, 63, 64, 65, 66, 67, 68, 69, 70, 0,
+ 71, 72, 73, 74, 75, 0, 76, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 77, 0, 56, 0, 183, 57, 58, 59,
+ 60, 61, 62, 148, 63, 64, 65, 66, 67, 68,
+ 69, 70, 0, 71, 72, 73, 74, 75, 0, 76,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 149, 0, 56, 0, 77, 57, 58, 59, 60,
+ 61, 62, 166, 63, 64, 65, 66, 67, 68, 69,
+ 70, 0, 71, 72, 73, 74, 75, 0, 76, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 167, 0, 56, 0, 77, 57, 58, 59, 60, 61,
+ 62, 142, 63, 64, 65, 66, 67, 68, 69, 70,
+ 0, 71, 72, 73, 74, 75, 0, 76, 0, 0,
+ 0, 0, 0, 0, 56, 0, 0, 57, 58, 59,
+ 60, 61, 62, 77, 63, 64, 65, 66, 67, 68,
+ 69, 70, 0, 71, 72, 73, 74, 75, 0, 76,
+ 0, 0, 0, 0, 0, 0, -93, 0, 0, 57,
+ 58, 59, 60, 61, 62, 77, 63, 64, 65, 66,
+ 67, 68, 69, 70, 0, 71, 72, 73, 74, 75,
+ 0, 76, 0, 0, 0, 60, 61, 62, 0, 63,
+ 64, 65, 66, 67, 68, 69, 70, 77, 71, 72,
+ 73, 74, 75, 0, 76, 0, 0, -74, -74, -74,
+ 0, 31, -74, -74, -74, -74, 0, 0, 0, -74,
+ 77, -92, 0, 0, 0, 0, 0, -92
+};
+
+static const short yycheck[] =
+{
+ 13, 14, 15, 16, 17, 18, 49, 50, 0, 7,
+ 8, 31, 32, 33, 34, 0, 36, 37, 38, 39,
+ 40, 40, 42, 42, 7, 43, 44, 45, 57, 21,
+ 48, 0, 45, 51, 63, 78, 79, 80, 58, 58,
+ 61, 62, 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 47, 76, 77, 62, 11, 64, 13, 49,
+ 50, 61, 57, 7, 8, 55, 58, 90, 63, 47,
+ 93, 57, 66, 32, 33, 34, 27, 36, 37, 38,
+ 39, 40, 57, 42, 107, 57, 109, 57, 43, 44,
+ 45, 46, 47, 47, 57, 47, 149, 52, 53, 58,
+ 3, 59, 57, 57, 127, 59, 59, 57, 19, 63,
+ 133, 134, 135, 136, 167, 7, 8, 59, 10, 142,
+ 12, 144, 145, 62, 59, 148, 3, 4, 5, 6,
+ 7, 8, 9, 10, 144, 12, 21, 14, 15, 16,
+ -1, -1, -1, 166, -1, -1, 169, 170, -1, 172,
+ -1, 174, -1, -1, -1, 32, 33, 34, -1, 36,
+ -1, -1, -1, 40, 41, -1, 3, 4, 5, 6,
+ 7, 8, 9, 10, -1, 12, -1, 14, 15, 16,
+ 57, 18, -1, 60, -1, 62, -1, 64, 65, -1,
+ -1, -1, -1, -1, -1, 32, 33, 34, -1, 36,
+ -1, -1, -1, 40, 41, 3, 4, 5, 6, 7,
+ 8, 9, 10, -1, 12, -1, 14, 15, 16, -1,
+ 57, 19, -1, 60, -1, -1, -1, -1, 65, -1,
+ -1, -1, -1, -1, 32, 33, 34, -1, 36, -1,
+ -1, -1, 40, 41, 3, 4, 5, 6, 7, 8,
+ 9, 10, -1, 12, -1, 14, 15, 16, -1, 57,
+ -1, -1, 60, -1, -1, -1, -1, 65, -1, -1,
+ -1, -1, -1, 32, 33, 34, -1, 36, -1, -1,
+ -1, 40, 41, 3, 4, 5, 6, 7, 8, 9,
+ 10, -1, 12, -1, 14, 15, 16, -1, 57, -1,
+ -1, 60, -1, -1, -1, -1, 65, -1, -1, -1,
+ -1, -1, 32, 33, 34, -1, 36, -1, -1, -1,
+ 40, 41, 3, 4, 5, 6, 7, 8, 9, 10,
+ -1, 12, -1, 14, 15, 16, -1, 57, -1, -1,
+ 60, -1, -1, -1, -1, 65, -1, -1, -1, -1,
+ -1, 32, 33, 34, -1, 36, -1, -1, -1, 40,
+ 41, 3, 4, 5, 6, 7, 8, 9, 10, -1,
+ 12, -1, 14, 15, 16, -1, 57, -1, -1, 60,
+ -1, -1, -1, -1, 65, -1, -1, -1, -1, -1,
+ 32, 33, 34, -1, 36, -1, -1, -1, 40, 41,
+ 36, 37, 38, 39, 40, -1, 42, -1, -1, -1,
+ -1, -1, -1, -1, -1, 57, -1, -1, 60, -1,
+ -1, 17, 58, 65, 20, 21, 22, 23, 24, 25,
+ -1, 27, 28, 29, 30, 31, 32, 33, 34, -1,
+ 36, 37, 38, 39, 40, -1, 42, -1, -1, -1,
+ -1, -1, -1, 17, -1, -1, 20, 21, 22, 23,
+ 24, 25, 58, 27, 28, 29, 30, 31, 32, 33,
+ 34, 67, 36, 37, 38, 39, 40, -1, 42, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 58, -1, -1, -1, 17, -1,
+ 64, 20, 21, 22, 23, 24, 25, -1, 27, 28,
+ 29, 30, 31, 32, 33, 34, -1, 36, 37, 38,
+ 39, 40, -1, 42, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 58,
+ -1, -1, -1, 17, -1, 64, 20, 21, 22, 23,
+ 24, 25, -1, 27, 28, 29, 30, 31, 32, 33,
+ 34, -1, 36, 37, 38, 39, 40, -1, 42, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 58, -1, 17, -1, 62, 20,
+ 21, 22, 23, 24, 25, -1, 27, 28, 29, 30,
+ 31, 32, 33, 34, -1, 36, 37, 38, 39, 40,
+ -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 58, -1, 17,
+ -1, 62, 20, 21, 22, 23, 24, 25, -1, 27,
+ 28, 29, 30, 31, 32, 33, 34, -1, 36, 37,
+ 38, 39, 40, -1, 42, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 58, -1, 17, -1, 62, 20, 21, 22, 23, 24,
+ 25, -1, 27, 28, 29, 30, 31, 32, 33, 34,
+ -1, 36, 37, 38, 39, 40, -1, 42, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 58, -1, 17, -1, 62, 20, 21,
+ 22, 23, 24, 25, -1, 27, 28, 29, 30, 31,
+ 32, 33, 34, -1, 36, 37, 38, 39, 40, -1,
+ 42, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 58, -1, 17, -1,
+ 62, 20, 21, 22, 23, 24, 25, -1, 27, 28,
+ 29, 30, 31, 32, 33, 34, -1, 36, 37, 38,
+ 39, 40, -1, 42, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 58,
+ -1, 17, -1, 62, 20, 21, 22, 23, 24, 25,
+ -1, 27, 28, 29, 30, 31, 32, 33, 34, -1,
+ 36, 37, 38, 39, 40, -1, 42, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 58, -1, 17, -1, 62, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, -1, 36, 37, 38, 39, 40, -1, 42,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 54, -1, 17, -1, 58, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, -1, 36, 37, 38, 39, 40, -1, 42, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 54, -1, 17, -1, 58, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ -1, 36, 37, 38, 39, 40, -1, 42, -1, -1,
+ -1, -1, -1, -1, 17, -1, -1, 20, 21, 22,
+ 23, 24, 25, 58, 27, 28, 29, 30, 31, 32,
+ 33, 34, -1, 36, 37, 38, 39, 40, -1, 42,
+ -1, -1, -1, -1, -1, -1, 17, -1, -1, 20,
+ 21, 22, 23, 24, 25, 58, 27, 28, 29, 30,
+ 31, 32, 33, 34, -1, 36, 37, 38, 39, 40,
+ -1, 42, -1, -1, -1, 23, 24, 25, -1, 27,
+ 28, 29, 30, 31, 32, 33, 34, 58, 36, 37,
+ 38, 39, 40, -1, 42, -1, -1, 43, 44, 45,
+ -1, 47, 48, 49, 50, 51, -1, -1, -1, 55,
+ 58, 57, -1, -1, -1, -1, -1, 63
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 12,
+ 14, 15, 16, 32, 33, 34, 36, 40, 41, 57,
+ 60, 65, 69, 70, 71, 74, 77, 78, 79, 81,
+ 82, 47, 74, 82, 74, 74, 74, 74, 74, 70,
+ 7, 7, 81, 82, 0, 61, 11, 13, 43, 44,
+ 45, 46, 47, 52, 53, 57, 17, 20, 21, 22,
+ 23, 24, 25, 27, 28, 29, 30, 31, 32, 33,
+ 34, 36, 37, 38, 39, 40, 42, 58, 43, 44,
+ 45, 48, 51, 49, 50, 55, 7, 8, 10, 12,
+ 57, 63, 62, 66, 74, 57, 76, 76, 76, 7,
+ 10, 12, 74, 75, 80, 74, 74, 18, 74, 19,
+ 74, 74, 74, 74, 7, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 27, 74, 74,
+ 76, 76, 76, 57, 57, 57, 57, 47, 74, 73,
+ 74, 3, 26, 62, 64, 59, 74, 74, 26, 54,
+ 7, 74, 67, 74, 74, 74, 74, 62, 72, 62,
+ 74, 74, 80, 74, 74, 76, 26, 54, 62, 64,
+ 64, 62, 57, 62, 59, 74, 76, 74, 74, 74,
+ 74, 62, 62, 62
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to xreallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to xreallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 3:
+#line 209 "ada-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 217 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ break;
+
+ case 6:
+#line 222 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_IND); }
+ break;
+
+ case 7:
+#line 226 "ada-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].ssym.stoken);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ }
+ break;
+
+ case 8:
+#line 233 "ada-exp.y"
+ {
+ write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst (yyvsp[-1].lval);
+ write_exp_elt_opcode (OP_FUNCALL);
+ }
+ break;
+
+ case 9:
+#line 241 "ada-exp.y"
+ {
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-3].tval);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+ break;
+
+ case 10:
+#line 248 "ada-exp.y"
+ { type_qualifier = yyvsp[-2].tval; }
+ break;
+
+ case 11:
+#line 249 "ada-exp.y"
+ {
+ /* write_exp_elt_opcode (UNOP_QUAL); */
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ write_exp_elt_type (yyvsp[-6].tval);
+ /* write_exp_elt_opcode (UNOP_QUAL); */
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ type_qualifier = yyvsp[-4].tval;
+ }
+ break;
+
+ case 12:
+#line 259 "ada-exp.y"
+ { yyval.tval = type_qualifier; }
+ break;
+
+ case 13:
+#line 264 "ada-exp.y"
+ { write_exp_elt_opcode (TERNOP_SLICE); }
+ break;
+
+ case 14:
+#line 267 "ada-exp.y"
+ { }
+ break;
+
+ case 16:
+#line 274 "ada-exp.y"
+ { write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_REGISTER);
+ }
+ break;
+
+ case 17:
+#line 281 "ada-exp.y"
+ { write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern (yyvsp[0].ivar);
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ }
+ break;
+
+ case 19:
+#line 292 "ada-exp.y"
+ { write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_LAST);
+ }
+ break;
+
+ case 20:
+#line 299 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ break;
+
+ case 21:
+#line 303 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_NEG); }
+ break;
+
+ case 22:
+#line 307 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_PLUS); }
+ break;
+
+ case 23:
+#line 311 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ break;
+
+ case 24:
+#line 315 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_ABS); }
+ break;
+
+ case 25:
+#line 318 "ada-exp.y"
+ { yyval.lval = 0; }
+ break;
+
+ case 26:
+#line 322 "ada-exp.y"
+ { yyval.lval = 1; }
+ break;
+
+ case 27:
+#line 324 "ada-exp.y"
+ { yyval.lval = 1; }
+ break;
+
+ case 28:
+#line 326 "ada-exp.y"
+ { yyval.lval = yyvsp[-2].lval + 1; }
+ break;
+
+ case 29:
+#line 328 "ada-exp.y"
+ { yyval.lval = yyvsp[-4].lval + 1; }
+ break;
+
+ case 30:
+#line 333 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ break;
+
+ case 31:
+#line 342 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_EXP); }
+ break;
+
+ case 32:
+#line 346 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_MUL); }
+ break;
+
+ case 33:
+#line 350 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_DIV); }
+ break;
+
+ case 34:
+#line 354 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_REM); }
+ break;
+
+ case 35:
+#line 358 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_MOD); }
+ break;
+
+ case 36:
+#line 362 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ break;
+
+ case 37:
+#line 366 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_ADD); }
+ break;
+
+ case 38:
+#line 370 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_CONCAT); }
+ break;
+
+ case 39:
+#line 374 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_SUB); }
+ break;
+
+ case 40:
+#line 378 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ break;
+
+ case 41:
+#line 382 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 42:
+#line 386 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ break;
+
+ case 43:
+#line 390 "ada-exp.y"
+ { /*write_exp_elt_opcode (TERNOP_MBR); */ }
+ break;
+
+ case 44:
+#line 394 "ada-exp.y"
+ { /*write_exp_elt_opcode (BINOP_MBR); */
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ /*write_exp_elt_opcode (BINOP_MBR); */
+ }
+ break;
+
+ case 45:
+#line 400 "ada-exp.y"
+ { /*write_exp_elt_opcode (UNOP_MBR); */
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ write_exp_elt_type (yyvsp[0].tval);
+ /* write_exp_elt_opcode (UNOP_MBR); */
+ /* FIXME: UNOP_MBR should be defined in expression.h */
+ }
+ break;
+
+ case 46:
+#line 407 "ada-exp.y"
+ { /*write_exp_elt_opcode (TERNOP_MBR); */
+ /* FIXME: TERNOP_MBR should be defined in expression.h */
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ break;
+
+ case 47:
+#line 412 "ada-exp.y"
+ { /* write_exp_elt_opcode (BINOP_MBR); */
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ /*write_exp_elt_opcode (BINOP_MBR);*/
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ break;
+
+ case 48:
+#line 420 "ada-exp.y"
+ { /*write_exp_elt_opcode (UNOP_MBR);*/
+ /* FIXME: UNOP_MBR should be defined in expression.h */
+ write_exp_elt_type (yyvsp[0].tval);
+ /* write_exp_elt_opcode (UNOP_MBR);*/
+ /* FIXME: UNOP_MBR should be defined in expression.h */
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ break;
+
+ case 49:
+#line 430 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ break;
+
+ case 50:
+#line 434 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_LESS); }
+ break;
+
+ case 51:
+#line 438 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_GTR); }
+ break;
+
+ case 52:
+#line 442 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ break;
+
+ case 53:
+#line 446 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ break;
+
+ case 54:
+#line 450 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ break;
+
+ case 55:
+#line 454 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ break;
+
+ case 56:
+#line 458 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ break;
+
+ case 57:
+#line 462 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ break;
+
+ case 58:
+#line 464 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (builtin_type_ada_system_address);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+ break;
+
+ case 59:
+#line 470 "ada-exp.y"
+ { write_attribute_call1 (ATR_FIRST, yyvsp[0].lval); }
+ break;
+
+ case 60:
+#line 472 "ada-exp.y"
+ { write_attribute_call1 (ATR_LAST, yyvsp[0].lval); }
+ break;
+
+ case 61:
+#line 474 "ada-exp.y"
+ { write_attribute_call1 (ATR_LENGTH, yyvsp[0].lval); }
+ break;
+
+ case 62:
+#line 476 "ada-exp.y"
+ { write_attribute_call0 (ATR_SIZE); }
+ break;
+
+ case 63:
+#line 478 "ada-exp.y"
+ { write_attribute_call0 (ATR_TAG); }
+ break;
+
+ case 64:
+#line 480 "ada-exp.y"
+ { write_attribute_calln (ATR_MIN, 2); }
+ break;
+
+ case 65:
+#line 482 "ada-exp.y"
+ { write_attribute_calln (ATR_MAX, 2); }
+ break;
+
+ case 66:
+#line 484 "ada-exp.y"
+ { write_attribute_calln (ATR_POS, 1); }
+ break;
+
+ case 67:
+#line 486 "ada-exp.y"
+ { write_attribute_call1 (ATR_FIRST, yyvsp[0].lval); }
+ break;
+
+ case 68:
+#line 488 "ada-exp.y"
+ { write_attribute_call1 (ATR_LAST, yyvsp[0].lval); }
+ break;
+
+ case 69:
+#line 490 "ada-exp.y"
+ { write_attribute_call1 (ATR_LENGTH, yyvsp[0].lval); }
+ break;
+
+ case 70:
+#line 492 "ada-exp.y"
+ { write_attribute_calln (ATR_VAL, 1); }
+ break;
+
+ case 71:
+#line 494 "ada-exp.y"
+ { write_attribute_call0 (ATR_MODULUS); }
+ break;
+
+ case 72:
+#line 498 "ada-exp.y"
+ { yyval.lval = 1; }
+ break;
+
+ case 73:
+#line 500 "ada-exp.y"
+ { yyval.lval = yyvsp[-1].typed_val.val; }
+ break;
+
+ case 74:
+#line 505 "ada-exp.y"
+ { write_exp_elt_opcode (OP_TYPE);
+ write_exp_elt_type (yyvsp[0].tval);
+ write_exp_elt_opcode (OP_TYPE); }
+ break;
+
+ case 76:
+#line 513 "ada-exp.y"
+ { write_exp_elt_opcode (OP_TYPE);
+ write_exp_elt_type (builtin_type_void);
+ write_exp_elt_opcode (OP_TYPE); }
+ break;
+
+ case 77:
+#line 520 "ada-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 78:
+#line 528 "ada-exp.y"
+ { write_exp_elt_opcode (OP_LONG);
+ if (type_qualifier == NULL)
+ write_exp_elt_type (yyvsp[0].typed_val.type);
+ else
+ write_exp_elt_type (type_qualifier);
+ write_exp_elt_longcst
+ (convert_char_literal (type_qualifier, yyvsp[0].typed_val.val));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ break;
+
+ case 79:
+#line 540 "ada-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 80:
+#line 548 "ada-exp.y"
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST)(0));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ break;
+
+ case 81:
+#line 556 "ada-exp.y"
+ { /* Ada strings are converted into array constants
+ a lower bound of 1. Thus, the array upper bound
+ is the string length. */
+ char *sp = yyvsp[0].sval.ptr; int count;
+ if (yyvsp[0].sval.length == 0)
+ { /* One dummy character for the type */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_ada_char);
+ write_exp_elt_longcst ((LONGEST)(0));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ for (count = yyvsp[0].sval.length; count > 0; count -= 1)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_ada_char);
+ write_exp_elt_longcst ((LONGEST)(*sp));
+ sp += 1;
+ write_exp_elt_opcode (OP_LONG);
+ }
+ write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_longcst ((LONGEST) (yyvsp[0].sval.length));
+ write_exp_elt_opcode (OP_ARRAY);
+ }
+ break;
+
+ case 82:
+#line 583 "ada-exp.y"
+ { error ("NEW not implemented."); }
+ break;
+
+ case 83:
+#line 586 "ada-exp.y"
+ { write_var_from_name (NULL, yyvsp[0].ssym); }
+ break;
+
+ case 84:
+#line 588 "ada-exp.y"
+ { write_var_from_name (yyvsp[-1].bval, yyvsp[0].ssym); }
+ break;
+
+ case 85:
+#line 589 "ada-exp.y"
+ { write_object_renaming (NULL, yyvsp[0].ssym.sym); }
+ break;
+
+ case 86:
+#line 591 "ada-exp.y"
+ { write_object_renaming (yyvsp[-1].bval, yyvsp[0].ssym.sym); }
+ break;
+
+ case 87:
+#line 594 "ada-exp.y"
+ { }
+ break;
+
+ case 88:
+#line 595 "ada-exp.y"
+ { }
+ break;
+
+ case 89:
+#line 596 "ada-exp.y"
+ { }
+ break;
+
+ case 90:
+#line 600 "ada-exp.y"
+ { yyval.bval = yyvsp[0].bval; }
+ break;
+
+ case 91:
+#line 602 "ada-exp.y"
+ { yyval.bval = yyvsp[0].bval; }
+ break;
+
+ case 92:
+#line 606 "ada-exp.y"
+ { yyval.tval = yyvsp[0].tval; }
+ break;
+
+ case 93:
+#line 607 "ada-exp.y"
+ { yyval.tval = yyvsp[0].tval; }
+ break;
+
+ case 94:
+#line 609 "ada-exp.y"
+ { yyval.tval = lookup_pointer_type (yyvsp[-1].tval); }
+ break;
+
+ case 95:
+#line 611 "ada-exp.y"
+ { yyval.tval = lookup_pointer_type (yyvsp[-1].tval); }
+ break;
+
+ case 96:
+#line 618 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_IND); }
+ break;
+
+ case 97:
+#line 620 "ada-exp.y"
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ break;
+
+ case 98:
+#line 622 "ada-exp.y"
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ break;
+
+
+ }
+
+/* Line 991 of yacc.c. */
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ 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)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab2;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+
+ /* Suppress GCC warning that yyerrlab1 is unused when no action
+ invokes YYERROR. Doesn't work in C++ */
+#ifndef __cplusplus
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+#endif
+#endif
+
+
+ goto yyerrlab2;
+
+
+/*---------------------------------------------------------------.
+| yyerrlab2 -- pop states until the error token can be shifted. |
+`---------------------------------------------------------------*/
+yyerrlab2:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 625 "ada-exp.y"
+
+
+/* yylex defined in ada-lex.c: Reads one token, getting characters */
+/* through lexptr. */
+
+/* Remap normal flex interface names (yylex) as well as gratuitiously */
+/* global symbol names, so we can have multiple flex-generated parsers */
+/* in gdb. */
+
+/* (See note above on previous definitions for YACC.) */
+
+#define yy_create_buffer ada_yy_create_buffer
+#define yy_delete_buffer ada_yy_delete_buffer
+#define yy_init_buffer ada_yy_init_buffer
+#define yy_load_buffer_state ada_yy_load_buffer_state
+#define yy_switch_to_buffer ada_yy_switch_to_buffer
+#define yyrestart ada_yyrestart
+#define yytext ada_yytext
+#define yywrap ada_yywrap
+
+/* The following kludge was found necessary to prevent conflicts between */
+/* defs.h and non-standard stdlib.h files. */
+#define qsort __qsort__dummy
+#include "ada-lex.c"
+
+int
+ada_parse ()
+{
+ lexer_init (yyin); /* (Re-)initialize lexer. */
+ left_block_context = NULL;
+ type_qualifier = NULL;
+
+ return _ada_parse ();
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+}
+
+/* The operator name corresponding to operator symbol STRING (adds
+ quotes and maps to lower-case). Destroys the previous contents of
+ the array pointed to by STRING.ptr. Error if STRING does not match
+ a valid Ada operator. Assumes that STRING.ptr points to a
+ null-terminated string and that, if STRING is a valid operator
+ symbol, the array pointed to by STRING.ptr contains at least
+ STRING.length+3 characters. */
+
+static struct stoken
+string_to_operator (string)
+ struct stoken string;
+{
+ int i;
+
+ for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+ {
+ if (string.length == strlen (ada_opname_table[i].demangled)-2
+ && strncasecmp (string.ptr, ada_opname_table[i].demangled+1,
+ string.length) == 0)
+ {
+ strncpy (string.ptr, ada_opname_table[i].demangled,
+ string.length+2);
+ string.length += 2;
+ return string;
+ }
+ }
+ error ("Invalid operator symbol `%s'", string.ptr);
+}
+
+/* Emit expression to access an instance of SYM, in block BLOCK (if
+ * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */
+static void
+write_var_from_sym (orig_left_context, block, sym)
+ struct block* orig_left_context;
+ struct block* block;
+ struct symbol* sym;
+{
+ if (orig_left_context == NULL && symbol_read_needs_frame (sym))
+ {
+ if (innermost_block == 0 ||
+ contained_in (block, innermost_block))
+ innermost_block = block;
+ }
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* 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);
+}
+
+/* Emit expression to access an instance of NAME. */
+static void
+write_var_from_name (orig_left_context, name)
+ struct block* orig_left_context;
+ struct name_info name;
+{
+ if (name.msym != NULL)
+ {
+ write_exp_msymbol (name.msym,
+ lookup_function_type (builtin_type_int),
+ builtin_type_int);
+ }
+ else if (name.sym == NULL)
+ {
+ /* Multiple matches: record name and starting block for later
+ resolution by ada_resolve. */
+ /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ write_exp_elt_block (name.block);
+ /* write_exp_elt_name (name.stoken.ptr); */
+ /* FIXME: write_exp_elt_name should be defined in defs.h, located in parse.c */
+ /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ }
+ else
+ write_var_from_sym (orig_left_context, name.block, name.sym);
+}
+
+/* Write a call on parameterless attribute ATR. */
+
+static void
+write_attribute_call0 (atr)
+ enum ada_attribute atr;
+{
+ /* write_exp_elt_opcode (OP_ATTRIBUTE); */
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) atr);
+ /* write_exp_elt_opcode (OP_ATTRIBUTE); */
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+}
+
+/* Write a call on an attribute ATR with one constant integer
+ * parameter. */
+
+static void
+write_attribute_call1 (atr, arg)
+ enum ada_attribute atr;
+ LONGEST arg;
+{
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst (arg);
+ write_exp_elt_opcode (OP_LONG);
+ /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_longcst ((LONGEST) atr);
+ /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+}
+
+/* Write a call on an attribute ATR with N parameters, whose code must have
+ * been generated previously. */
+
+static void
+write_attribute_calln (atr, n)
+ enum ada_attribute atr;
+ int n;
+{
+ /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) n);
+ write_exp_elt_longcst ((LONGEST) atr);
+ /* write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+}
+
+/* Emit expression corresponding to the renamed object designated by
+ * the type RENAMING, which must be the referent of an object renaming
+ * type, in the context of ORIG_LEFT_CONTEXT (?). */
+static void
+write_object_renaming (orig_left_context, renaming)
+ struct block* orig_left_context;
+ struct symbol* renaming;
+{
+ const char* qualification = DEPRECATED_SYMBOL_NAME (renaming);
+ const char* simple_tail;
+ const char* expr = TYPE_FIELD_NAME (SYMBOL_TYPE (renaming), 0);
+ const char* suffix;
+ char* name;
+ struct symbol* sym;
+ enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state;
+
+ /* if orig_left_context is null, then use the currently selected
+ block, otherwise we might fail our symbol lookup below */
+ if (orig_left_context == NULL)
+ orig_left_context = get_selected_block (NULL);
+
+ for (simple_tail = qualification + strlen (qualification);
+ simple_tail != qualification; simple_tail -= 1)
+ {
+ if (*simple_tail == '.')
+ {
+ simple_tail += 1;
+ break;
+ }
+ else if (DEPRECATED_STREQN (simple_tail, "__", 2))
+ {
+ simple_tail += 2;
+ break;
+ }
+ }
+
+ suffix = strstr (expr, "___XE");
+ if (suffix == NULL)
+ goto BadEncoding;
+
+ name = (char*) xmalloc (suffix - expr + 1);
+ /* add_name_string_cleanup (name); */
+ /* FIXME: add_name_string_cleanup should be defined in
+ parser-defs.h, implemented in parse.c */
+ strncpy (name, expr, suffix-expr);
+ name[suffix-expr] = '\000';
+ sym = lookup_symbol (name, orig_left_context, VAR_DOMAIN, 0, NULL);
+ /* if (sym == NULL)
+ error ("Could not find renamed variable: %s", ada_demangle (name));
+ */
+ /* FIXME: ada_demangle should be defined in defs.h, implemented in ada-lang.c */
+ write_var_from_sym (orig_left_context, block_found, sym);
+
+ suffix += 5;
+ slice_state = SIMPLE_INDEX;
+ while (*suffix == 'X')
+ {
+ suffix += 1;
+
+ switch (*suffix) {
+ case 'L':
+ slice_state = LOWER_BOUND;
+ case 'S':
+ suffix += 1;
+ if (isdigit (*suffix))
+ {
+ char* next;
+ long val = strtol (suffix, &next, 10);
+ if (next == suffix)
+ goto BadEncoding;
+ suffix = next;
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_ada_int);
+ write_exp_elt_longcst ((LONGEST) val);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ else
+ {
+ const char* end;
+ char* index_name;
+ int index_len;
+ struct symbol* index_sym;
+
+ end = strchr (suffix, 'X');
+ if (end == NULL)
+ end = suffix + strlen (suffix);
+
+ index_len = simple_tail - qualification + 2 + (suffix - end) + 1;
+ index_name = (char*) xmalloc (index_len);
+ memset (index_name, '\000', index_len);
+ /* add_name_string_cleanup (index_name);*/
+ /* FIXME: add_name_string_cleanup should be defined in
+ parser-defs.h, implemented in parse.c */
+ strncpy (index_name, qualification, simple_tail - qualification);
+ index_name[simple_tail - qualification] = '\000';
+ strncat (index_name, suffix, suffix-end);
+ suffix = end;
+
+ index_sym =
+ lookup_symbol (index_name, NULL, VAR_DOMAIN, 0, NULL);
+ if (index_sym == NULL)
+ error ("Could not find %s", index_name);
+ write_var_from_sym (NULL, block_found, sym);
+ }
+ if (slice_state == SIMPLE_INDEX)
+ {
+ write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_opcode (OP_FUNCALL);
+ }
+ else if (slice_state == LOWER_BOUND)
+ slice_state = UPPER_BOUND;
+ else if (slice_state == UPPER_BOUND)
+ {
+ write_exp_elt_opcode (TERNOP_SLICE);
+ slice_state = SIMPLE_INDEX;
+ }
+ break;
+
+ case 'R':
+ {
+ struct stoken field_name;
+ const char* end;
+ suffix += 1;
+
+ if (slice_state != SIMPLE_INDEX)
+ goto BadEncoding;
+ end = strchr (suffix, 'X');
+ if (end == NULL)
+ end = suffix + strlen (suffix);
+ field_name.length = end - suffix;
+ field_name.ptr = (char*) xmalloc (end - suffix + 1);
+ strncpy (field_name.ptr, suffix, end - suffix);
+ field_name.ptr[end - suffix] = '\000';
+ suffix = end;
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (field_name);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ break;
+ }
+
+ default:
+ goto BadEncoding;
+ }
+ }
+ if (slice_state == SIMPLE_INDEX)
+ return;
+
+ BadEncoding:
+ error ("Internal error in encoding of renaming declaration: %s",
+ DEPRECATED_SYMBOL_NAME (renaming));
+}
+
+/* Convert the character literal whose ASCII value would be VAL to the
+ appropriate value of type TYPE, if there is a translation.
+ Otherwise return VAL. Hence, in an enumeration type ('A', 'B'),
+ the literal 'A' (VAL == 65), returns 0. */
+static LONGEST
+convert_char_literal (struct type* type, LONGEST val)
+{
+ char name[7];
+ int f;
+
+ if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM)
+ return val;
+ sprintf (name, "QU%02x", (int) val);
+ for (f = 0; f < TYPE_NFIELDS (type); f += 1)
+ {
+ if (DEPRECATED_STREQ (name, TYPE_FIELD_NAME (type, f)))
+ return TYPE_FIELD_BITPOS (type, f);
+ }
+ return val;
+}
+
+
diff --git a/contrib/gdb/gdb/ada-exp.y b/contrib/gdb/gdb/ada-exp.y
new file mode 100644
index 0000000..f4cbb37
--- /dev/null
+++ b/contrib/gdb/gdb/ada-exp.y
@@ -0,0 +1,969 @@
+/* YACC parser for Ada expressions, for GDB.
+ Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994, 1997, 2000, 2003
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You 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. */
+
+/* Parse an Ada 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.
+
+ 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 (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator. */
+
+%{
+
+#include "defs.h"
+#include <string.h>
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "ada-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "frame.h"
+#include "block.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. These are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix
+ options. I presume we are maintaining it to accommodate systems
+ without BISON? (PNH) */
+
+#define yymaxdepth ada_maxdepth
+#define yyparse _ada_parse /* ada_parse calls this after initialization */
+#define yylex ada_lex
+#define yyerror ada_error
+#define yylval ada_lval
+#define yychar ada_char
+#define yydebug ada_debug
+#define yypact ada_pact
+#define yyr1 ada_r1
+#define yyr2 ada_r2
+#define yydef ada_def
+#define yychk ada_chk
+#define yypgo ada_pgo
+#define yyact ada_act
+#define yyexca ada_exca
+#define yyerrflag ada_errflag
+#define yynerrs ada_nerrs
+#define yyps ada_ps
+#define yypv ada_pv
+#define yys ada_s
+#define yy_yys ada_yys
+#define yystate ada_state
+#define yytmp ada_tmp
+#define yyv ada_v
+#define yy_yyv ada_yyv
+#define yyval ada_val
+#define yylloc ada_lloc
+#define yyreds ada_reds /* With YYDEBUG defined */
+#define yytoks ada_toks /* With YYDEBUG defined */
+#define yyname ada_name /* With YYDEBUG defined */
+#define yyrule ada_rule /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define YYDEBUG 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+struct name_info {
+ struct symbol* sym;
+ struct minimal_symbol* msym;
+ struct block* block;
+ struct stoken stoken;
+};
+
+/* If expression is in the context of TYPE'(...), then TYPE, else
+ * NULL. */
+static struct type* type_qualifier;
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static struct stoken string_to_operator (struct stoken);
+
+static void write_attribute_call0 (enum ada_attribute);
+
+static void write_attribute_call1 (enum ada_attribute, LONGEST);
+
+static void write_attribute_calln (enum ada_attribute, int);
+
+static void write_object_renaming (struct block*, struct symbol*);
+
+static void write_var_from_name (struct block*, struct name_info);
+
+static LONGEST
+convert_char_literal (struct type*, LONGEST);
+%}
+
+%union
+ {
+ LONGEST lval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val;
+ struct {
+ DOUBLEST dval;
+ struct type *type;
+ } typed_val_float;
+ struct type *tval;
+ struct stoken sval;
+ struct name_info ssym;
+ int voidval;
+ struct block *bval;
+ struct internalvar *ivar;
+
+ }
+
+%type <voidval> exp exp1 simple_exp start variable
+%type <tval> type
+
+%token <typed_val> INT NULL_PTR CHARLIT
+%token <typed_val_float> FLOAT
+%token <tval> TYPENAME
+%token <bval> BLOCKNAME
+
+/* 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 <sval> STRING
+%token <ssym> NAME DOT_ID OBJECT_RENAMING
+%type <bval> block
+%type <lval> arglist tick_arglist
+
+%type <tval> save_qualifier
+
+%token DOT_ALL
+
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+%token <lval> LAST REGNAME
+
+%token <ivar> INTERNAL_VARIABLE
+
+%nonassoc ASSIGN
+%left _AND_ OR XOR THEN ELSE
+%left '=' NOTEQUAL '<' '>' LEQ GEQ IN DOTDOT
+%left '@'
+%left '+' '-' '&'
+%left UNARY
+%left '*' '/' MOD REM
+%right STARSTAR ABS NOT
+ /* The following are right-associative only so that reductions at this
+ precedence have lower precedence than '.' and '('. The syntax still
+ forces a.b.c, e.g., to be LEFT-associated. */
+%right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH
+%right TICK_MAX TICK_MIN TICK_MODULUS
+%right TICK_POS TICK_RANGE TICK_SIZE TICK_TAG TICK_VAL
+%right '.' '(' '[' DOT_ID DOT_ALL
+
+%token ARROW NEW
+
+
+%%
+
+start : exp1
+ | type { write_exp_elt_opcode (OP_TYPE);
+ write_exp_elt_type ($1);
+ write_exp_elt_opcode (OP_TYPE); }
+ ;
+
+/* Expressions, including the sequencing operator. */
+exp1 : exp
+ | exp1 ';' exp
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ ;
+
+/* Expressions, not including the sequencing operator. */
+simple_exp : simple_exp DOT_ALL
+ { write_exp_elt_opcode (UNOP_IND); }
+ ;
+
+simple_exp : simple_exp DOT_ID
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($2.stoken);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ }
+ ;
+
+simple_exp : simple_exp '(' arglist ')'
+ {
+ write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ($3);
+ write_exp_elt_opcode (OP_FUNCALL);
+ }
+ ;
+
+simple_exp : type '(' exp ')'
+ {
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($1);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+ ;
+
+simple_exp : type '\'' save_qualifier { type_qualifier = $1; } '(' exp ')'
+ {
+ /* write_exp_elt_opcode (UNOP_QUAL); */
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ write_exp_elt_type ($1);
+ /* write_exp_elt_opcode (UNOP_QUAL); */
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ type_qualifier = $3;
+ }
+ ;
+
+save_qualifier : { $$ = type_qualifier; }
+ ;
+
+simple_exp :
+ simple_exp '(' exp DOTDOT exp ')'
+ { write_exp_elt_opcode (TERNOP_SLICE); }
+ ;
+
+simple_exp : '(' exp1 ')' { }
+ ;
+
+simple_exp : variable
+ ;
+
+simple_exp: REGNAME /* GDB extension */
+ { write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_REGISTER);
+ }
+ ;
+
+simple_exp: INTERNAL_VARIABLE /* GDB extension */
+ { write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern ($1);
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ }
+ ;
+
+
+exp : simple_exp
+ ;
+
+simple_exp: LAST
+ { write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LAST);
+ }
+ ;
+
+exp : exp ASSIGN exp /* Extension for convenience */
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ ;
+
+exp : '-' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_NEG); }
+ ;
+
+exp : '+' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PLUS); }
+ ;
+
+exp : NOT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ ;
+
+exp : ABS exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_ABS); }
+ ;
+
+arglist : { $$ = 0; }
+ ;
+
+arglist : exp
+ { $$ = 1; }
+ | any_name ARROW exp
+ { $$ = 1; }
+ | arglist ',' exp
+ { $$ = $1 + 1; }
+ | arglist ',' any_name ARROW exp
+ { $$ = $1 + 1; }
+ ;
+
+exp : '{' type '}' exp %prec '.'
+ /* GDB extension */
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+
+exp : exp STARSTAR exp
+ { write_exp_elt_opcode (BINOP_EXP); }
+ ;
+
+exp : exp '*' exp
+ { write_exp_elt_opcode (BINOP_MUL); }
+ ;
+
+exp : exp '/' exp
+ { write_exp_elt_opcode (BINOP_DIV); }
+ ;
+
+exp : exp REM exp /* May need to be fixed to give correct Ada REM */
+ { write_exp_elt_opcode (BINOP_REM); }
+ ;
+
+exp : exp MOD exp
+ { write_exp_elt_opcode (BINOP_MOD); }
+ ;
+
+exp : exp '@' exp /* GDB extension */
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ ;
+
+exp : exp '+' exp
+ { write_exp_elt_opcode (BINOP_ADD); }
+ ;
+
+exp : exp '&' exp
+ { write_exp_elt_opcode (BINOP_CONCAT); }
+ ;
+
+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 LEQ exp
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ ;
+
+exp : exp IN exp DOTDOT exp
+ { /*write_exp_elt_opcode (TERNOP_MBR); */ }
+ /* FIXME: TERNOP_MBR should be defined in
+ expression.h */
+ | exp IN exp TICK_RANGE tick_arglist
+ { /*write_exp_elt_opcode (BINOP_MBR); */
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) $5);
+ /*write_exp_elt_opcode (BINOP_MBR); */
+ }
+ | exp IN TYPENAME %prec TICK_ACCESS
+ { /*write_exp_elt_opcode (UNOP_MBR); */
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ write_exp_elt_type ($3);
+ /* write_exp_elt_opcode (UNOP_MBR); */
+ /* FIXME: UNOP_MBR should be defined in expression.h */
+ }
+ | exp NOT IN exp DOTDOT exp
+ { /*write_exp_elt_opcode (TERNOP_MBR); */
+ /* FIXME: TERNOP_MBR should be defined in expression.h */
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ | exp NOT IN exp TICK_RANGE tick_arglist
+ { /* write_exp_elt_opcode (BINOP_MBR); */
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) $6);
+ /*write_exp_elt_opcode (BINOP_MBR);*/
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ | exp NOT IN TYPENAME %prec TICK_ACCESS
+ { /*write_exp_elt_opcode (UNOP_MBR);*/
+ /* FIXME: UNOP_MBR should be defined in expression.h */
+ write_exp_elt_type ($4);
+ /* write_exp_elt_opcode (UNOP_MBR);*/
+ /* FIXME: UNOP_MBR should be defined in expression.h */
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+ ;
+
+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 _AND_ exp /* Fix for Ada elementwise AND. */
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ ;
+
+exp : exp _AND_ THEN exp %prec _AND_
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ ;
+
+exp : exp OR exp /* Fix for Ada elementwise OR */
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ ;
+
+exp : exp OR ELSE exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ ;
+
+exp : exp XOR exp /* Fix for Ada elementwise XOR */
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ ;
+
+simple_exp : simple_exp TICK_ACCESS
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ | simple_exp TICK_ADDRESS
+ { write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (builtin_type_ada_system_address);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+ | simple_exp TICK_FIRST tick_arglist
+ { write_attribute_call1 (ATR_FIRST, $3); }
+ | simple_exp TICK_LAST tick_arglist
+ { write_attribute_call1 (ATR_LAST, $3); }
+ | simple_exp TICK_LENGTH tick_arglist
+ { write_attribute_call1 (ATR_LENGTH, $3); }
+ | simple_exp TICK_SIZE
+ { write_attribute_call0 (ATR_SIZE); }
+ | simple_exp TICK_TAG
+ { write_attribute_call0 (ATR_TAG); }
+ | opt_type_prefix TICK_MIN '(' exp ',' exp ')'
+ { write_attribute_calln (ATR_MIN, 2); }
+ | opt_type_prefix TICK_MAX '(' exp ',' exp ')'
+ { write_attribute_calln (ATR_MAX, 2); }
+ | opt_type_prefix TICK_POS '(' exp ')'
+ { write_attribute_calln (ATR_POS, 1); }
+ | type_prefix TICK_FIRST tick_arglist
+ { write_attribute_call1 (ATR_FIRST, $3); }
+ | type_prefix TICK_LAST tick_arglist
+ { write_attribute_call1 (ATR_LAST, $3); }
+ | type_prefix TICK_LENGTH tick_arglist
+ { write_attribute_call1 (ATR_LENGTH, $3); }
+ | type_prefix TICK_VAL '(' exp ')'
+ { write_attribute_calln (ATR_VAL, 1); }
+ | type_prefix TICK_MODULUS
+ { write_attribute_call0 (ATR_MODULUS); }
+ ;
+
+tick_arglist : %prec '('
+ { $$ = 1; }
+ | '(' INT ')'
+ { $$ = $2.val; }
+ ;
+
+type_prefix :
+ TYPENAME
+ { write_exp_elt_opcode (OP_TYPE);
+ write_exp_elt_type ($1);
+ write_exp_elt_opcode (OP_TYPE); }
+ ;
+
+opt_type_prefix :
+ type_prefix
+ | /* EMPTY */
+ { write_exp_elt_opcode (OP_TYPE);
+ write_exp_elt_type (builtin_type_void);
+ write_exp_elt_opcode (OP_TYPE); }
+ ;
+
+
+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 : CHARLIT
+ { write_exp_elt_opcode (OP_LONG);
+ if (type_qualifier == NULL)
+ write_exp_elt_type ($1.type);
+ else
+ write_exp_elt_type (type_qualifier);
+ write_exp_elt_longcst
+ (convert_char_literal (type_qualifier, $1.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 : NULL_PTR
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST)(0));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ ;
+
+exp : STRING
+ { /* Ada strings are converted into array constants
+ a lower bound of 1. Thus, the array upper bound
+ is the string length. */
+ char *sp = $1.ptr; int count;
+ if ($1.length == 0)
+ { /* One dummy character for the type */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_ada_char);
+ write_exp_elt_longcst ((LONGEST)(0));
+ write_exp_elt_opcode (OP_LONG);
+ }
+ for (count = $1.length; count > 0; count -= 1)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_ada_char);
+ write_exp_elt_longcst ((LONGEST)(*sp));
+ sp += 1;
+ write_exp_elt_opcode (OP_LONG);
+ }
+ write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_longcst ((LONGEST) ($1.length));
+ write_exp_elt_opcode (OP_ARRAY);
+ }
+ ;
+
+exp : NEW TYPENAME
+ { error ("NEW not implemented."); }
+ ;
+
+variable: NAME { write_var_from_name (NULL, $1); }
+ | block NAME /* GDB extension */
+ { write_var_from_name ($1, $2); }
+ | OBJECT_RENAMING { write_object_renaming (NULL, $1.sym); }
+ | block OBJECT_RENAMING
+ { write_object_renaming ($1, $2.sym); }
+ ;
+
+any_name : NAME { }
+ | TYPENAME { }
+ | OBJECT_RENAMING { }
+ ;
+
+block : BLOCKNAME /* GDB extension */
+ { $$ = $1; }
+ | block BLOCKNAME /* GDB extension */
+ { $$ = $2; }
+ ;
+
+
+type : TYPENAME { $$ = $1; }
+ | block TYPENAME { $$ = $2; }
+ | TYPENAME TICK_ACCESS
+ { $$ = lookup_pointer_type ($1); }
+ | block TYPENAME TICK_ACCESS
+ { $$ = lookup_pointer_type ($2); }
+ ;
+
+/* Some extensions borrowed from C, for the benefit of those who find they
+ can't get used to Ada notation in GDB. */
+
+exp : '*' exp %prec '.'
+ { write_exp_elt_opcode (UNOP_IND); }
+ | '&' exp %prec '.'
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ | exp '[' exp ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ ;
+
+%%
+
+/* yylex defined in ada-lex.c: Reads one token, getting characters */
+/* through lexptr. */
+
+/* Remap normal flex interface names (yylex) as well as gratuitiously */
+/* global symbol names, so we can have multiple flex-generated parsers */
+/* in gdb. */
+
+/* (See note above on previous definitions for YACC.) */
+
+#define yy_create_buffer ada_yy_create_buffer
+#define yy_delete_buffer ada_yy_delete_buffer
+#define yy_init_buffer ada_yy_init_buffer
+#define yy_load_buffer_state ada_yy_load_buffer_state
+#define yy_switch_to_buffer ada_yy_switch_to_buffer
+#define yyrestart ada_yyrestart
+#define yytext ada_yytext
+#define yywrap ada_yywrap
+
+/* The following kludge was found necessary to prevent conflicts between */
+/* defs.h and non-standard stdlib.h files. */
+#define qsort __qsort__dummy
+#include "ada-lex.c"
+
+int
+ada_parse ()
+{
+ lexer_init (yyin); /* (Re-)initialize lexer. */
+ left_block_context = NULL;
+ type_qualifier = NULL;
+
+ return _ada_parse ();
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+}
+
+/* The operator name corresponding to operator symbol STRING (adds
+ quotes and maps to lower-case). Destroys the previous contents of
+ the array pointed to by STRING.ptr. Error if STRING does not match
+ a valid Ada operator. Assumes that STRING.ptr points to a
+ null-terminated string and that, if STRING is a valid operator
+ symbol, the array pointed to by STRING.ptr contains at least
+ STRING.length+3 characters. */
+
+static struct stoken
+string_to_operator (string)
+ struct stoken string;
+{
+ int i;
+
+ for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+ {
+ if (string.length == strlen (ada_opname_table[i].demangled)-2
+ && strncasecmp (string.ptr, ada_opname_table[i].demangled+1,
+ string.length) == 0)
+ {
+ strncpy (string.ptr, ada_opname_table[i].demangled,
+ string.length+2);
+ string.length += 2;
+ return string;
+ }
+ }
+ error ("Invalid operator symbol `%s'", string.ptr);
+}
+
+/* Emit expression to access an instance of SYM, in block BLOCK (if
+ * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */
+static void
+write_var_from_sym (orig_left_context, block, sym)
+ struct block* orig_left_context;
+ struct block* block;
+ struct symbol* sym;
+{
+ if (orig_left_context == NULL && symbol_read_needs_frame (sym))
+ {
+ if (innermost_block == 0 ||
+ contained_in (block, innermost_block))
+ innermost_block = block;
+ }
+
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ /* 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);
+}
+
+/* Emit expression to access an instance of NAME. */
+static void
+write_var_from_name (orig_left_context, name)
+ struct block* orig_left_context;
+ struct name_info name;
+{
+ if (name.msym != NULL)
+ {
+ write_exp_msymbol (name.msym,
+ lookup_function_type (builtin_type_int),
+ builtin_type_int);
+ }
+ else if (name.sym == NULL)
+ {
+ /* Multiple matches: record name and starting block for later
+ resolution by ada_resolve. */
+ /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ write_exp_elt_block (name.block);
+ /* write_exp_elt_name (name.stoken.ptr); */
+ /* FIXME: write_exp_elt_name should be defined in defs.h, located in parse.c */
+ /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ }
+ else
+ write_var_from_sym (orig_left_context, name.block, name.sym);
+}
+
+/* Write a call on parameterless attribute ATR. */
+
+static void
+write_attribute_call0 (atr)
+ enum ada_attribute atr;
+{
+ /* write_exp_elt_opcode (OP_ATTRIBUTE); */
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) atr);
+ /* write_exp_elt_opcode (OP_ATTRIBUTE); */
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+}
+
+/* Write a call on an attribute ATR with one constant integer
+ * parameter. */
+
+static void
+write_attribute_call1 (atr, arg)
+ enum ada_attribute atr;
+ LONGEST arg;
+{
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst (arg);
+ write_exp_elt_opcode (OP_LONG);
+ /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_longcst ((LONGEST) atr);
+ /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+}
+
+/* Write a call on an attribute ATR with N parameters, whose code must have
+ * been generated previously. */
+
+static void
+write_attribute_calln (atr, n)
+ enum ada_attribute atr;
+ int n;
+{
+ /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ write_exp_elt_longcst ((LONGEST) n);
+ write_exp_elt_longcst ((LONGEST) atr);
+ /* write_exp_elt_opcode (OP_ATTRIBUTE);*/
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+}
+
+/* Emit expression corresponding to the renamed object designated by
+ * the type RENAMING, which must be the referent of an object renaming
+ * type, in the context of ORIG_LEFT_CONTEXT (?). */
+static void
+write_object_renaming (orig_left_context, renaming)
+ struct block* orig_left_context;
+ struct symbol* renaming;
+{
+ const char* qualification = DEPRECATED_SYMBOL_NAME (renaming);
+ const char* simple_tail;
+ const char* expr = TYPE_FIELD_NAME (SYMBOL_TYPE (renaming), 0);
+ const char* suffix;
+ char* name;
+ struct symbol* sym;
+ enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state;
+
+ /* if orig_left_context is null, then use the currently selected
+ block, otherwise we might fail our symbol lookup below */
+ if (orig_left_context == NULL)
+ orig_left_context = get_selected_block (NULL);
+
+ for (simple_tail = qualification + strlen (qualification);
+ simple_tail != qualification; simple_tail -= 1)
+ {
+ if (*simple_tail == '.')
+ {
+ simple_tail += 1;
+ break;
+ }
+ else if (DEPRECATED_STREQN (simple_tail, "__", 2))
+ {
+ simple_tail += 2;
+ break;
+ }
+ }
+
+ suffix = strstr (expr, "___XE");
+ if (suffix == NULL)
+ goto BadEncoding;
+
+ name = (char*) malloc (suffix - expr + 1);
+ /* add_name_string_cleanup (name); */
+ /* FIXME: add_name_string_cleanup should be defined in
+ parser-defs.h, implemented in parse.c */
+ strncpy (name, expr, suffix-expr);
+ name[suffix-expr] = '\000';
+ sym = lookup_symbol (name, orig_left_context, VAR_DOMAIN, 0, NULL);
+ /* if (sym == NULL)
+ error ("Could not find renamed variable: %s", ada_demangle (name));
+ */
+ /* FIXME: ada_demangle should be defined in defs.h, implemented in ada-lang.c */
+ write_var_from_sym (orig_left_context, block_found, sym);
+
+ suffix += 5;
+ slice_state = SIMPLE_INDEX;
+ while (*suffix == 'X')
+ {
+ suffix += 1;
+
+ switch (*suffix) {
+ case 'L':
+ slice_state = LOWER_BOUND;
+ case 'S':
+ suffix += 1;
+ if (isdigit (*suffix))
+ {
+ char* next;
+ long val = strtol (suffix, &next, 10);
+ if (next == suffix)
+ goto BadEncoding;
+ suffix = next;
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_ada_int);
+ write_exp_elt_longcst ((LONGEST) val);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ else
+ {
+ const char* end;
+ char* index_name;
+ int index_len;
+ struct symbol* index_sym;
+
+ end = strchr (suffix, 'X');
+ if (end == NULL)
+ end = suffix + strlen (suffix);
+
+ index_len = simple_tail - qualification + 2 + (suffix - end) + 1;
+ index_name = (char*) malloc (index_len);
+ memset (index_name, '\000', index_len);
+ /* add_name_string_cleanup (index_name);*/
+ /* FIXME: add_name_string_cleanup should be defined in
+ parser-defs.h, implemented in parse.c */
+ strncpy (index_name, qualification, simple_tail - qualification);
+ index_name[simple_tail - qualification] = '\000';
+ strncat (index_name, suffix, suffix-end);
+ suffix = end;
+
+ index_sym =
+ lookup_symbol (index_name, NULL, VAR_DOMAIN, 0, NULL);
+ if (index_sym == NULL)
+ error ("Could not find %s", index_name);
+ write_var_from_sym (NULL, block_found, sym);
+ }
+ if (slice_state == SIMPLE_INDEX)
+ {
+ write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_opcode (OP_FUNCALL);
+ }
+ else if (slice_state == LOWER_BOUND)
+ slice_state = UPPER_BOUND;
+ else if (slice_state == UPPER_BOUND)
+ {
+ write_exp_elt_opcode (TERNOP_SLICE);
+ slice_state = SIMPLE_INDEX;
+ }
+ break;
+
+ case 'R':
+ {
+ struct stoken field_name;
+ const char* end;
+ suffix += 1;
+
+ if (slice_state != SIMPLE_INDEX)
+ goto BadEncoding;
+ end = strchr (suffix, 'X');
+ if (end == NULL)
+ end = suffix + strlen (suffix);
+ field_name.length = end - suffix;
+ field_name.ptr = (char*) malloc (end - suffix + 1);
+ strncpy (field_name.ptr, suffix, end - suffix);
+ field_name.ptr[end - suffix] = '\000';
+ suffix = end;
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (field_name);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ break;
+ }
+
+ default:
+ goto BadEncoding;
+ }
+ }
+ if (slice_state == SIMPLE_INDEX)
+ return;
+
+ BadEncoding:
+ error ("Internal error in encoding of renaming declaration: %s",
+ DEPRECATED_SYMBOL_NAME (renaming));
+}
+
+/* Convert the character literal whose ASCII value would be VAL to the
+ appropriate value of type TYPE, if there is a translation.
+ Otherwise return VAL. Hence, in an enumeration type ('A', 'B'),
+ the literal 'A' (VAL == 65), returns 0. */
+static LONGEST
+convert_char_literal (struct type* type, LONGEST val)
+{
+ char name[7];
+ int f;
+
+ if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM)
+ return val;
+ sprintf (name, "QU%02x", (int) val);
+ for (f = 0; f < TYPE_NFIELDS (type); f += 1)
+ {
+ if (DEPRECATED_STREQ (name, TYPE_FIELD_NAME (type, f)))
+ return TYPE_FIELD_BITPOS (type, f);
+ }
+ return val;
+}
diff --git a/contrib/gdb/gdb/ada-lang.c b/contrib/gdb/gdb/ada-lang.c
new file mode 100644
index 0000000..b97321b
--- /dev/null
+++ b/contrib/gdb/gdb/ada-lang.c
@@ -0,0 +1,8254 @@
+/* Ada language support routines for GDB, the GNU debugger. Copyright
+ 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You 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 <stdio.h>
+#include "gdb_string.h"
+#include <ctype.h>
+#include <stdarg.h>
+#include "demangle.h"
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "c-lang.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "breakpoint.h"
+#include "gdbcore.h"
+#include "ada-lang.h"
+#include "ui-out.h"
+#include "block.h"
+#include "infcall.h"
+#include "dictionary.h"
+
+struct cleanup *unresolved_names;
+
+void extract_string (CORE_ADDR addr, char *buf);
+
+static struct type *ada_create_fundamental_type (struct objfile *, int);
+
+static void modify_general_field (char *, LONGEST, int, int);
+
+static struct type *desc_base_type (struct type *);
+
+static struct type *desc_bounds_type (struct type *);
+
+static struct value *desc_bounds (struct value *);
+
+static int fat_pntr_bounds_bitpos (struct type *);
+
+static int fat_pntr_bounds_bitsize (struct type *);
+
+static struct type *desc_data_type (struct type *);
+
+static struct value *desc_data (struct value *);
+
+static int fat_pntr_data_bitpos (struct type *);
+
+static int fat_pntr_data_bitsize (struct type *);
+
+static struct value *desc_one_bound (struct value *, int, int);
+
+static int desc_bound_bitpos (struct type *, int, int);
+
+static int desc_bound_bitsize (struct type *, int, int);
+
+static struct type *desc_index_type (struct type *, int);
+
+static int desc_arity (struct type *);
+
+static int ada_type_match (struct type *, struct type *, int);
+
+static int ada_args_match (struct symbol *, struct value **, int);
+
+static struct value *place_on_stack (struct value *, CORE_ADDR *);
+
+static struct value *convert_actual (struct value *, struct type *,
+ CORE_ADDR *);
+
+static struct value *make_array_descriptor (struct type *, struct value *,
+ CORE_ADDR *);
+
+static void ada_add_block_symbols (struct block *, const char *,
+ domain_enum, struct objfile *, int);
+
+static void fill_in_ada_prototype (struct symbol *);
+
+static int is_nonfunction (struct symbol **, int);
+
+static void add_defn_to_vec (struct symbol *, struct block *);
+
+static struct partial_symbol *ada_lookup_partial_symbol (struct partial_symtab
+ *, const char *, int,
+ domain_enum, int);
+
+static struct symtab *symtab_for_sym (struct symbol *);
+
+static struct value *ada_resolve_subexp (struct expression **, int *, int,
+ struct type *);
+
+static void replace_operator_with_call (struct expression **, int, int, int,
+ struct symbol *, struct block *);
+
+static int possible_user_operator_p (enum exp_opcode, struct value **);
+
+static const char *ada_op_name (enum exp_opcode);
+
+static int numeric_type_p (struct type *);
+
+static int integer_type_p (struct type *);
+
+static int scalar_type_p (struct type *);
+
+static int discrete_type_p (struct type *);
+
+static char *extended_canonical_line_spec (struct symtab_and_line,
+ const char *);
+
+static struct value *evaluate_subexp (struct type *, struct expression *,
+ int *, enum noside);
+
+static struct value *evaluate_subexp_type (struct expression *, int *);
+
+static struct type *ada_create_fundamental_type (struct objfile *, int);
+
+static int is_dynamic_field (struct type *, int);
+
+static struct type *to_fixed_variant_branch_type (struct type *, char *,
+ CORE_ADDR, struct value *);
+
+static struct type *to_fixed_range_type (char *, struct value *,
+ struct objfile *);
+
+static struct type *to_static_fixed_type (struct type *);
+
+static struct value *unwrap_value (struct value *);
+
+static struct type *packed_array_type (struct type *, long *);
+
+static struct type *decode_packed_array_type (struct type *);
+
+static struct value *decode_packed_array (struct value *);
+
+static struct value *value_subscript_packed (struct value *, int,
+ struct value **);
+
+static struct value *coerce_unspec_val_to_type (struct value *, long,
+ struct type *);
+
+static struct value *get_var_value (char *, char *);
+
+static int lesseq_defined_than (struct symbol *, struct symbol *);
+
+static int equiv_types (struct type *, struct type *);
+
+static int is_name_suffix (const char *);
+
+static int wild_match (const char *, int, const char *);
+
+static struct symtabs_and_lines find_sal_from_funcs_and_line (const char *,
+ int,
+ struct symbol
+ **, int);
+
+static int find_line_in_linetable (struct linetable *, int, struct symbol **,
+ int, int *);
+
+static int find_next_line_in_linetable (struct linetable *, int, int, int);
+
+static struct symtabs_and_lines all_sals_for_line (const char *, int,
+ char ***);
+
+static void read_all_symtabs (const char *);
+
+static int is_plausible_func_for_line (struct symbol *, int);
+
+static struct value *ada_coerce_ref (struct value *);
+
+static struct value *value_pos_atr (struct value *);
+
+static struct value *value_val_atr (struct type *, struct value *);
+
+static struct symbol *standard_lookup (const char *, domain_enum);
+
+extern void markTimeStart (int index);
+extern void markTimeStop (int index);
+
+
+
+/* Maximum-sized dynamic type. */
+static unsigned int varsize_limit;
+
+static const char *ada_completer_word_break_characters =
+ " \t\n!@#$%^&*()+=|~`}{[]\";:?/,-";
+
+/* The name of the symbol to use to get the name of the main subprogram */
+#define ADA_MAIN_PROGRAM_SYMBOL_NAME "__gnat_ada_main_program_name"
+
+ /* Utilities */
+
+/* extract_string
+ *
+ * read the string located at ADDR from the inferior and store the
+ * result into BUF
+ */
+void
+extract_string (CORE_ADDR addr, char *buf)
+{
+ int char_index = 0;
+
+ /* Loop, reading one byte at a time, until we reach the '\000'
+ end-of-string marker */
+ do
+ {
+ target_read_memory (addr + char_index * sizeof (char),
+ buf + char_index * sizeof (char), sizeof (char));
+ char_index++;
+ }
+ while (buf[char_index - 1] != '\000');
+}
+
+/* Assuming *OLD_VECT points to an array of *SIZE objects of size
+ ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
+ updating *OLD_VECT and *SIZE as necessary. */
+
+void
+grow_vect (void **old_vect, size_t * size, size_t min_size, int element_size)
+{
+ if (*size < min_size)
+ {
+ *size *= 2;
+ if (*size < min_size)
+ *size = min_size;
+ *old_vect = xrealloc (*old_vect, *size * element_size);
+ }
+}
+
+/* True (non-zero) iff TARGET matches FIELD_NAME up to any trailing
+ suffix of FIELD_NAME beginning "___" */
+
+static int
+field_name_match (const char *field_name, const char *target)
+{
+ int len = strlen (target);
+ return
+ DEPRECATED_STREQN (field_name, target, len)
+ && (field_name[len] == '\0'
+ || (DEPRECATED_STREQN (field_name + len, "___", 3)
+ && !DEPRECATED_STREQ (field_name + strlen (field_name) - 6, "___XVN")));
+}
+
+
+/* The length of the prefix of NAME prior to any "___" suffix. */
+
+int
+ada_name_prefix_len (const char *name)
+{
+ if (name == NULL)
+ return 0;
+ else
+ {
+ const char *p = strstr (name, "___");
+ if (p == NULL)
+ return strlen (name);
+ else
+ return p - name;
+ }
+}
+
+/* SUFFIX is a suffix of STR. False if STR is null. */
+static int
+is_suffix (const char *str, const char *suffix)
+{
+ int len1, len2;
+ if (str == NULL)
+ return 0;
+ len1 = strlen (str);
+ len2 = strlen (suffix);
+ return (len1 >= len2 && DEPRECATED_STREQ (str + len1 - len2, suffix));
+}
+
+/* Create a value of type TYPE whose contents come from VALADDR, if it
+ * is non-null, and whose memory address (in the inferior) is
+ * ADDRESS. */
+struct value *
+value_from_contents_and_address (struct type *type, char *valaddr,
+ CORE_ADDR address)
+{
+ struct value *v = allocate_value (type);
+ if (valaddr == NULL)
+ VALUE_LAZY (v) = 1;
+ else
+ memcpy (VALUE_CONTENTS_RAW (v), valaddr, TYPE_LENGTH (type));
+ VALUE_ADDRESS (v) = address;
+ if (address != 0)
+ VALUE_LVAL (v) = lval_memory;
+ return v;
+}
+
+/* The contents of value VAL, beginning at offset OFFSET, treated as a
+ value of type TYPE. The result is an lval in memory if VAL is. */
+
+static struct value *
+coerce_unspec_val_to_type (struct value *val, long offset, struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ if (VALUE_LVAL (val) == lval_memory)
+ return value_at_lazy (type,
+ VALUE_ADDRESS (val) + VALUE_OFFSET (val) + offset,
+ NULL);
+ else
+ {
+ struct value *result = allocate_value (type);
+ VALUE_LVAL (result) = not_lval;
+ if (VALUE_ADDRESS (val) == 0)
+ memcpy (VALUE_CONTENTS_RAW (result), VALUE_CONTENTS (val) + offset,
+ TYPE_LENGTH (type) > TYPE_LENGTH (VALUE_TYPE (val))
+ ? TYPE_LENGTH (VALUE_TYPE (val)) : TYPE_LENGTH (type));
+ else
+ {
+ VALUE_ADDRESS (result) =
+ VALUE_ADDRESS (val) + VALUE_OFFSET (val) + offset;
+ VALUE_LAZY (result) = 1;
+ }
+ return result;
+ }
+}
+
+static char *
+cond_offset_host (char *valaddr, long offset)
+{
+ if (valaddr == NULL)
+ return NULL;
+ else
+ return valaddr + offset;
+}
+
+static CORE_ADDR
+cond_offset_target (CORE_ADDR address, long offset)
+{
+ if (address == 0)
+ return 0;
+ else
+ return address + offset;
+}
+
+/* Perform execute_command on the result of concatenating all
+ arguments up to NULL. */
+static void
+do_command (const char *arg, ...)
+{
+ int len;
+ char *cmd;
+ const char *s;
+ va_list ap;
+
+ va_start (ap, arg);
+ len = 0;
+ s = arg;
+ cmd = "";
+ for (; s != NULL; s = va_arg (ap, const char *))
+ {
+ char *cmd1;
+ len += strlen (s);
+ cmd1 = alloca (len + 1);
+ strcpy (cmd1, cmd);
+ strcat (cmd1, s);
+ cmd = cmd1;
+ }
+ va_end (ap);
+ execute_command (cmd, 0);
+}
+
+
+ /* Language Selection */
+
+/* If the main program is in Ada, return language_ada, otherwise return LANG
+ (the main program is in Ada iif the adainit symbol is found).
+
+ MAIN_PST is not used. */
+
+enum language
+ada_update_initial_language (enum language lang,
+ struct partial_symtab *main_pst)
+{
+ if (lookup_minimal_symbol ("adainit", (const char *) NULL,
+ (struct objfile *) NULL) != NULL)
+ /* return language_ada; */
+ /* FIXME: language_ada should be defined in defs.h */
+ return language_unknown;
+
+ return lang;
+}
+
+
+ /* Symbols */
+
+/* Table of Ada operators and their GNAT-mangled names. Last entry is pair
+ of NULLs. */
+
+const struct ada_opname_map ada_opname_table[] = {
+ {"Oadd", "\"+\"", BINOP_ADD},
+ {"Osubtract", "\"-\"", BINOP_SUB},
+ {"Omultiply", "\"*\"", BINOP_MUL},
+ {"Odivide", "\"/\"", BINOP_DIV},
+ {"Omod", "\"mod\"", BINOP_MOD},
+ {"Orem", "\"rem\"", BINOP_REM},
+ {"Oexpon", "\"**\"", BINOP_EXP},
+ {"Olt", "\"<\"", BINOP_LESS},
+ {"Ole", "\"<=\"", BINOP_LEQ},
+ {"Ogt", "\">\"", BINOP_GTR},
+ {"Oge", "\">=\"", BINOP_GEQ},
+ {"Oeq", "\"=\"", BINOP_EQUAL},
+ {"One", "\"/=\"", BINOP_NOTEQUAL},
+ {"Oand", "\"and\"", BINOP_BITWISE_AND},
+ {"Oor", "\"or\"", BINOP_BITWISE_IOR},
+ {"Oxor", "\"xor\"", BINOP_BITWISE_XOR},
+ {"Oconcat", "\"&\"", BINOP_CONCAT},
+ {"Oabs", "\"abs\"", UNOP_ABS},
+ {"Onot", "\"not\"", UNOP_LOGICAL_NOT},
+ {"Oadd", "\"+\"", UNOP_PLUS},
+ {"Osubtract", "\"-\"", UNOP_NEG},
+ {NULL, NULL}
+};
+
+/* True if STR should be suppressed in info listings. */
+static int
+is_suppressed_name (const char *str)
+{
+ if (DEPRECATED_STREQN (str, "_ada_", 5))
+ str += 5;
+ if (str[0] == '_' || str[0] == '\000')
+ return 1;
+ else
+ {
+ const char *p;
+ const char *suffix = strstr (str, "___");
+ if (suffix != NULL && suffix[3] != 'X')
+ return 1;
+ if (suffix == NULL)
+ suffix = str + strlen (str);
+ for (p = suffix - 1; p != str; p -= 1)
+ if (isupper (*p))
+ {
+ int i;
+ if (p[0] == 'X' && p[-1] != '_')
+ goto OK;
+ if (*p != 'O')
+ return 1;
+ for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+ if (DEPRECATED_STREQN (ada_opname_table[i].mangled, p,
+ strlen (ada_opname_table[i].mangled)))
+ goto OK;
+ return 1;
+ OK:;
+ }
+ return 0;
+ }
+}
+
+/* The "mangled" form of DEMANGLED, according to GNAT conventions.
+ * The result is valid until the next call to ada_mangle. */
+char *
+ada_mangle (const char *demangled)
+{
+ static char *mangling_buffer = NULL;
+ static size_t mangling_buffer_size = 0;
+ const char *p;
+ int k;
+
+ if (demangled == NULL)
+ return NULL;
+
+ GROW_VECT (mangling_buffer, mangling_buffer_size,
+ 2 * strlen (demangled) + 10);
+
+ k = 0;
+ for (p = demangled; *p != '\0'; p += 1)
+ {
+ if (*p == '.')
+ {
+ mangling_buffer[k] = mangling_buffer[k + 1] = '_';
+ k += 2;
+ }
+ else if (*p == '"')
+ {
+ const struct ada_opname_map *mapping;
+
+ for (mapping = ada_opname_table;
+ mapping->mangled != NULL &&
+ !DEPRECATED_STREQN (mapping->demangled, p, strlen (mapping->demangled));
+ p += 1)
+ ;
+ if (mapping->mangled == NULL)
+ error ("invalid Ada operator name: %s", p);
+ strcpy (mangling_buffer + k, mapping->mangled);
+ k += strlen (mapping->mangled);
+ break;
+ }
+ else
+ {
+ mangling_buffer[k] = *p;
+ k += 1;
+ }
+ }
+
+ mangling_buffer[k] = '\0';
+ return mangling_buffer;
+}
+
+/* Return NAME folded to lower case, or, if surrounded by single
+ * quotes, unfolded, but with the quotes stripped away. Result good
+ * to next call. */
+char *
+ada_fold_name (const char *name)
+{
+ static char *fold_buffer = NULL;
+ static size_t fold_buffer_size = 0;
+
+ int len = strlen (name);
+ GROW_VECT (fold_buffer, fold_buffer_size, len + 1);
+
+ if (name[0] == '\'')
+ {
+ strncpy (fold_buffer, name + 1, len - 2);
+ fold_buffer[len - 2] = '\000';
+ }
+ else
+ {
+ int i;
+ for (i = 0; i <= len; i += 1)
+ fold_buffer[i] = tolower (name[i]);
+ }
+
+ return fold_buffer;
+}
+
+/* Demangle:
+ 1. Discard final __{DIGIT}+ or ${DIGIT}+
+ 2. Convert other instances of embedded "__" to `.'.
+ 3. Discard leading _ada_.
+ 4. Convert operator names to the appropriate quoted symbols.
+ 5. Remove everything after first ___ if it is followed by
+ 'X'.
+ 6. Replace TK__ with __, and a trailing B or TKB with nothing.
+ 7. Put symbols that should be suppressed in <...> brackets.
+ 8. Remove trailing X[bn]* suffix (indicating names in package bodies).
+ The resulting string is valid until the next call of ada_demangle.
+ */
+
+char *
+ada_demangle (const char *mangled)
+{
+ int i, j;
+ int len0;
+ const char *p;
+ char *demangled;
+ int at_start_name;
+ static char *demangling_buffer = NULL;
+ static size_t demangling_buffer_size = 0;
+
+ if (DEPRECATED_STREQN (mangled, "_ada_", 5))
+ mangled += 5;
+
+ if (mangled[0] == '_' || mangled[0] == '<')
+ goto Suppress;
+
+ p = strstr (mangled, "___");
+ if (p == NULL)
+ len0 = strlen (mangled);
+ else
+ {
+ if (p[3] == 'X')
+ len0 = p - mangled;
+ else
+ goto Suppress;
+ }
+ if (len0 > 3 && DEPRECATED_STREQ (mangled + len0 - 3, "TKB"))
+ len0 -= 3;
+ if (len0 > 1 && DEPRECATED_STREQ (mangled + len0 - 1, "B"))
+ len0 -= 1;
+
+ /* Make demangled big enough for possible expansion by operator name. */
+ GROW_VECT (demangling_buffer, demangling_buffer_size, 2 * len0 + 1);
+ demangled = demangling_buffer;
+
+ if (isdigit (mangled[len0 - 1]))
+ {
+ for (i = len0 - 2; i >= 0 && isdigit (mangled[i]); i -= 1)
+ ;
+ if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_')
+ len0 = i - 1;
+ else if (mangled[i] == '$')
+ len0 = i;
+ }
+
+ for (i = 0, j = 0; i < len0 && !isalpha (mangled[i]); i += 1, j += 1)
+ demangled[j] = mangled[i];
+
+ at_start_name = 1;
+ while (i < len0)
+ {
+ if (at_start_name && mangled[i] == 'O')
+ {
+ int k;
+ for (k = 0; ada_opname_table[k].mangled != NULL; k += 1)
+ {
+ int op_len = strlen (ada_opname_table[k].mangled);
+ if (DEPRECATED_STREQN
+ (ada_opname_table[k].mangled + 1, mangled + i + 1,
+ op_len - 1) && !isalnum (mangled[i + op_len]))
+ {
+ strcpy (demangled + j, ada_opname_table[k].demangled);
+ at_start_name = 0;
+ i += op_len;
+ j += strlen (ada_opname_table[k].demangled);
+ break;
+ }
+ }
+ if (ada_opname_table[k].mangled != NULL)
+ continue;
+ }
+ at_start_name = 0;
+
+ if (i < len0 - 4 && DEPRECATED_STREQN (mangled + i, "TK__", 4))
+ i += 2;
+ if (mangled[i] == 'X' && i != 0 && isalnum (mangled[i - 1]))
+ {
+ do
+ i += 1;
+ while (i < len0 && (mangled[i] == 'b' || mangled[i] == 'n'));
+ if (i < len0)
+ goto Suppress;
+ }
+ else if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_')
+ {
+ demangled[j] = '.';
+ at_start_name = 1;
+ i += 2;
+ j += 1;
+ }
+ else
+ {
+ demangled[j] = mangled[i];
+ i += 1;
+ j += 1;
+ }
+ }
+ demangled[j] = '\000';
+
+ for (i = 0; demangled[i] != '\0'; i += 1)
+ if (isupper (demangled[i]) || demangled[i] == ' ')
+ goto Suppress;
+
+ return demangled;
+
+Suppress:
+ GROW_VECT (demangling_buffer, demangling_buffer_size, strlen (mangled) + 3);
+ demangled = demangling_buffer;
+ if (mangled[0] == '<')
+ strcpy (demangled, mangled);
+ else
+ sprintf (demangled, "<%s>", mangled);
+ return demangled;
+
+}
+
+/* Returns non-zero iff SYM_NAME matches NAME, ignoring any trailing
+ * suffixes that encode debugging information or leading _ada_ on
+ * SYM_NAME (see is_name_suffix commentary for the debugging
+ * information that is ignored). If WILD, then NAME need only match a
+ * suffix of SYM_NAME minus the same suffixes. Also returns 0 if
+ * either argument is NULL. */
+
+int
+ada_match_name (const char *sym_name, const char *name, int wild)
+{
+ if (sym_name == NULL || name == NULL)
+ return 0;
+ else if (wild)
+ return wild_match (name, strlen (name), sym_name);
+ else
+ {
+ int len_name = strlen (name);
+ return (DEPRECATED_STREQN (sym_name, name, len_name)
+ && is_name_suffix (sym_name + len_name))
+ || (DEPRECATED_STREQN (sym_name, "_ada_", 5)
+ && DEPRECATED_STREQN (sym_name + 5, name, len_name)
+ && is_name_suffix (sym_name + len_name + 5));
+ }
+}
+
+/* True (non-zero) iff in Ada mode, the symbol SYM should be
+ suppressed in info listings. */
+
+int
+ada_suppress_symbol_printing (struct symbol *sym)
+{
+ if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
+ return 1;
+ else
+ return is_suppressed_name (DEPRECATED_SYMBOL_NAME (sym));
+}
+
+
+ /* Arrays */
+
+/* Names of MAX_ADA_DIMENS bounds in P_BOUNDS fields of
+ array descriptors. */
+
+static char *bound_name[] = {
+ "LB0", "UB0", "LB1", "UB1", "LB2", "UB2", "LB3", "UB3",
+ "LB4", "UB4", "LB5", "UB5", "LB6", "UB6", "LB7", "UB7"
+};
+
+/* Maximum number of array dimensions we are prepared to handle. */
+
+#define MAX_ADA_DIMENS (sizeof(bound_name) / (2*sizeof(char*)))
+
+/* Like modify_field, but allows bitpos > wordlength. */
+
+static void
+modify_general_field (char *addr, LONGEST fieldval, int bitpos, int bitsize)
+{
+ modify_field (addr + sizeof (LONGEST) * bitpos / (8 * sizeof (LONGEST)),
+ fieldval, bitpos % (8 * sizeof (LONGEST)), bitsize);
+}
+
+
+/* The desc_* routines return primitive portions of array descriptors
+ (fat pointers). */
+
+/* The descriptor or array type, if any, indicated by TYPE; removes
+ level of indirection, if needed. */
+static struct type *
+desc_base_type (struct type *type)
+{
+ if (type == NULL)
+ return NULL;
+ CHECK_TYPEDEF (type);
+ if (type != NULL && TYPE_CODE (type) == TYPE_CODE_PTR)
+ return check_typedef (TYPE_TARGET_TYPE (type));
+ else
+ return type;
+}
+
+/* True iff TYPE indicates a "thin" array pointer type. */
+static int
+is_thin_pntr (struct type *type)
+{
+ return
+ is_suffix (ada_type_name (desc_base_type (type)), "___XUT")
+ || is_suffix (ada_type_name (desc_base_type (type)), "___XUT___XVE");
+}
+
+/* The descriptor type for thin pointer type TYPE. */
+static struct type *
+thin_descriptor_type (struct type *type)
+{
+ struct type *base_type = desc_base_type (type);
+ if (base_type == NULL)
+ return NULL;
+ if (is_suffix (ada_type_name (base_type), "___XVE"))
+ return base_type;
+ else
+ {
+ struct type *alt_type = ada_find_parallel_type (base_type, "___XVE");
+ if (alt_type == NULL)
+ return base_type;
+ else
+ return alt_type;
+ }
+}
+
+/* A pointer to the array data for thin-pointer value VAL. */
+static struct value *
+thin_data_pntr (struct value *val)
+{
+ struct type *type = VALUE_TYPE (val);
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ return value_cast (desc_data_type (thin_descriptor_type (type)),
+ value_copy (val));
+ else
+ return value_from_longest (desc_data_type (thin_descriptor_type (type)),
+ VALUE_ADDRESS (val) + VALUE_OFFSET (val));
+}
+
+/* True iff TYPE indicates a "thick" array pointer type. */
+static int
+is_thick_pntr (struct type *type)
+{
+ type = desc_base_type (type);
+ return (type != NULL && TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && lookup_struct_elt_type (type, "P_BOUNDS", 1) != NULL);
+}
+
+/* If TYPE is the type of an array descriptor (fat or thin pointer) or a
+ pointer to one, the type of its bounds data; otherwise, NULL. */
+static struct type *
+desc_bounds_type (struct type *type)
+{
+ struct type *r;
+
+ type = desc_base_type (type);
+
+ if (type == NULL)
+ return NULL;
+ else if (is_thin_pntr (type))
+ {
+ type = thin_descriptor_type (type);
+ if (type == NULL)
+ return NULL;
+ r = lookup_struct_elt_type (type, "BOUNDS", 1);
+ if (r != NULL)
+ return check_typedef (r);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ r = lookup_struct_elt_type (type, "P_BOUNDS", 1);
+ if (r != NULL)
+ return check_typedef (TYPE_TARGET_TYPE (check_typedef (r)));
+ }
+ return NULL;
+}
+
+/* If ARR is an array descriptor (fat or thin pointer), or pointer to
+ one, a pointer to its bounds data. Otherwise NULL. */
+static struct value *
+desc_bounds (struct value *arr)
+{
+ struct type *type = check_typedef (VALUE_TYPE (arr));
+ if (is_thin_pntr (type))
+ {
+ struct type *bounds_type =
+ desc_bounds_type (thin_descriptor_type (type));
+ LONGEST addr;
+
+ if (desc_bounds_type == NULL)
+ error ("Bad GNAT array descriptor");
+
+ /* NOTE: The following calculation is not really kosher, but
+ since desc_type is an XVE-encoded type (and shouldn't be),
+ the correct calculation is a real pain. FIXME (and fix GCC). */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ addr = value_as_long (arr);
+ else
+ addr = VALUE_ADDRESS (arr) + VALUE_OFFSET (arr);
+
+ return
+ value_from_longest (lookup_pointer_type (bounds_type),
+ addr - TYPE_LENGTH (bounds_type));
+ }
+
+ else if (is_thick_pntr (type))
+ return value_struct_elt (&arr, NULL, "P_BOUNDS", NULL,
+ "Bad GNAT array descriptor");
+ else
+ return NULL;
+}
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+ position of the field containing the address of the bounds data. */
+static int
+fat_pntr_bounds_bitpos (struct type *type)
+{
+ return TYPE_FIELD_BITPOS (desc_base_type (type), 1);
+}
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+ size of the field containing the address of the bounds data. */
+static int
+fat_pntr_bounds_bitsize (struct type *type)
+{
+ type = desc_base_type (type);
+
+ if (TYPE_FIELD_BITSIZE (type, 1) > 0)
+ return TYPE_FIELD_BITSIZE (type, 1);
+ else
+ return 8 * TYPE_LENGTH (check_typedef (TYPE_FIELD_TYPE (type, 1)));
+}
+
+/* If TYPE is the type of an array descriptor (fat or thin pointer) or a
+ pointer to one, the type of its array data (a
+ pointer-to-array-with-no-bounds type); otherwise, NULL. Use
+ ada_type_of_array to get an array type with bounds data. */
+static struct type *
+desc_data_type (struct type *type)
+{
+ type = desc_base_type (type);
+
+ /* NOTE: The following is bogus; see comment in desc_bounds. */
+ if (is_thin_pntr (type))
+ return lookup_pointer_type
+ (desc_base_type (TYPE_FIELD_TYPE (thin_descriptor_type (type), 1)));
+ else if (is_thick_pntr (type))
+ return lookup_struct_elt_type (type, "P_ARRAY", 1);
+ else
+ return NULL;
+}
+
+/* If ARR is an array descriptor (fat or thin pointer), a pointer to
+ its array data. */
+static struct value *
+desc_data (struct value *arr)
+{
+ struct type *type = VALUE_TYPE (arr);
+ if (is_thin_pntr (type))
+ return thin_data_pntr (arr);
+ else if (is_thick_pntr (type))
+ return value_struct_elt (&arr, NULL, "P_ARRAY", NULL,
+ "Bad GNAT array descriptor");
+ else
+ return NULL;
+}
+
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+ position of the field containing the address of the data. */
+static int
+fat_pntr_data_bitpos (struct type *type)
+{
+ return TYPE_FIELD_BITPOS (desc_base_type (type), 0);
+}
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+ size of the field containing the address of the data. */
+static int
+fat_pntr_data_bitsize (struct type *type)
+{
+ type = desc_base_type (type);
+
+ if (TYPE_FIELD_BITSIZE (type, 0) > 0)
+ return TYPE_FIELD_BITSIZE (type, 0);
+ else
+ return TARGET_CHAR_BIT * TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0));
+}
+
+/* If BOUNDS is an array-bounds structure (or pointer to one), return
+ the Ith lower bound stored in it, if WHICH is 0, and the Ith upper
+ bound, if WHICH is 1. The first bound is I=1. */
+static struct value *
+desc_one_bound (struct value *bounds, int i, int which)
+{
+ return value_struct_elt (&bounds, NULL, bound_name[2 * i + which - 2], NULL,
+ "Bad GNAT array descriptor bounds");
+}
+
+/* If BOUNDS is an array-bounds structure type, return the bit position
+ of the Ith lower bound stored in it, if WHICH is 0, and the Ith upper
+ bound, if WHICH is 1. The first bound is I=1. */
+static int
+desc_bound_bitpos (struct type *type, int i, int which)
+{
+ return TYPE_FIELD_BITPOS (desc_base_type (type), 2 * i + which - 2);
+}
+
+/* If BOUNDS is an array-bounds structure type, return the bit field size
+ of the Ith lower bound stored in it, if WHICH is 0, and the Ith upper
+ bound, if WHICH is 1. The first bound is I=1. */
+static int
+desc_bound_bitsize (struct type *type, int i, int which)
+{
+ type = desc_base_type (type);
+
+ if (TYPE_FIELD_BITSIZE (type, 2 * i + which - 2) > 0)
+ return TYPE_FIELD_BITSIZE (type, 2 * i + which - 2);
+ else
+ return 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, 2 * i + which - 2));
+}
+
+/* If TYPE is the type of an array-bounds structure, the type of its
+ Ith bound (numbering from 1). Otherwise, NULL. */
+static struct type *
+desc_index_type (struct type *type, int i)
+{
+ type = desc_base_type (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ return lookup_struct_elt_type (type, bound_name[2 * i - 2], 1);
+ else
+ return NULL;
+}
+
+/* The number of index positions in the array-bounds type TYPE. 0
+ if TYPE is NULL. */
+static int
+desc_arity (struct type *type)
+{
+ type = desc_base_type (type);
+
+ if (type != NULL)
+ return TYPE_NFIELDS (type) / 2;
+ return 0;
+}
+
+
+/* Non-zero iff type is a simple array type (or pointer to one). */
+int
+ada_is_simple_array (struct type *type)
+{
+ if (type == NULL)
+ return 0;
+ CHECK_TYPEDEF (type);
+ return (TYPE_CODE (type) == TYPE_CODE_ARRAY
+ || (TYPE_CODE (type) == TYPE_CODE_PTR
+ && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY));
+}
+
+/* Non-zero iff type belongs to a GNAT array descriptor. */
+int
+ada_is_array_descriptor (struct type *type)
+{
+ struct type *data_type = desc_data_type (type);
+
+ if (type == NULL)
+ return 0;
+ CHECK_TYPEDEF (type);
+ return
+ data_type != NULL
+ && ((TYPE_CODE (data_type) == TYPE_CODE_PTR
+ && TYPE_TARGET_TYPE (data_type) != NULL
+ && TYPE_CODE (TYPE_TARGET_TYPE (data_type)) == TYPE_CODE_ARRAY)
+ ||
+ TYPE_CODE (data_type) == TYPE_CODE_ARRAY)
+ && desc_arity (desc_bounds_type (type)) > 0;
+}
+
+/* Non-zero iff type is a partially mal-formed GNAT array
+ descriptor. (FIXME: This is to compensate for some problems with
+ debugging output from GNAT. Re-examine periodically to see if it
+ is still needed. */
+int
+ada_is_bogus_array_descriptor (struct type *type)
+{
+ return
+ type != NULL
+ && TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && (lookup_struct_elt_type (type, "P_BOUNDS", 1) != NULL
+ || lookup_struct_elt_type (type, "P_ARRAY", 1) != NULL)
+ && !ada_is_array_descriptor (type);
+}
+
+
+/* If ARR has a record type in the form of a standard GNAT array descriptor,
+ (fat pointer) returns the type of the array data described---specifically,
+ a pointer-to-array type. If BOUNDS is non-zero, the bounds data are filled
+ in from the descriptor; otherwise, they are left unspecified. If
+ the ARR denotes a null array descriptor and BOUNDS is non-zero,
+ returns NULL. The result is simply the type of ARR if ARR is not
+ a descriptor. */
+struct type *
+ada_type_of_array (struct value *arr, int bounds)
+{
+ if (ada_is_packed_array_type (VALUE_TYPE (arr)))
+ return decode_packed_array_type (VALUE_TYPE (arr));
+
+ if (!ada_is_array_descriptor (VALUE_TYPE (arr)))
+ return VALUE_TYPE (arr);
+
+ if (!bounds)
+ return
+ check_typedef (TYPE_TARGET_TYPE (desc_data_type (VALUE_TYPE (arr))));
+ else
+ {
+ struct type *elt_type;
+ int arity;
+ struct value *descriptor;
+ struct objfile *objf = TYPE_OBJFILE (VALUE_TYPE (arr));
+
+ elt_type = ada_array_element_type (VALUE_TYPE (arr), -1);
+ arity = ada_array_arity (VALUE_TYPE (arr));
+
+ if (elt_type == NULL || arity == 0)
+ return check_typedef (VALUE_TYPE (arr));
+
+ descriptor = desc_bounds (arr);
+ if (value_as_long (descriptor) == 0)
+ return NULL;
+ while (arity > 0)
+ {
+ struct type *range_type = alloc_type (objf);
+ struct type *array_type = alloc_type (objf);
+ struct value *low = desc_one_bound (descriptor, arity, 0);
+ struct value *high = desc_one_bound (descriptor, arity, 1);
+ arity -= 1;
+
+ create_range_type (range_type, VALUE_TYPE (low),
+ (int) value_as_long (low),
+ (int) value_as_long (high));
+ elt_type = create_array_type (array_type, elt_type, range_type);
+ }
+
+ return lookup_pointer_type (elt_type);
+ }
+}
+
+/* If ARR does not represent an array, returns ARR unchanged.
+ Otherwise, returns either a standard GDB array with bounds set
+ appropriately or, if ARR is a non-null fat pointer, a pointer to a standard
+ GDB array. Returns NULL if ARR is a null fat pointer. */
+struct value *
+ada_coerce_to_simple_array_ptr (struct value *arr)
+{
+ if (ada_is_array_descriptor (VALUE_TYPE (arr)))
+ {
+ struct type *arrType = ada_type_of_array (arr, 1);
+ if (arrType == NULL)
+ return NULL;
+ return value_cast (arrType, value_copy (desc_data (arr)));
+ }
+ else if (ada_is_packed_array_type (VALUE_TYPE (arr)))
+ return decode_packed_array (arr);
+ else
+ return arr;
+}
+
+/* If ARR does not represent an array, returns ARR unchanged.
+ Otherwise, returns a standard GDB array describing ARR (which may
+ be ARR itself if it already is in the proper form). */
+struct value *
+ada_coerce_to_simple_array (struct value *arr)
+{
+ if (ada_is_array_descriptor (VALUE_TYPE (arr)))
+ {
+ struct value *arrVal = ada_coerce_to_simple_array_ptr (arr);
+ if (arrVal == NULL)
+ error ("Bounds unavailable for null array pointer.");
+ return value_ind (arrVal);
+ }
+ else if (ada_is_packed_array_type (VALUE_TYPE (arr)))
+ return decode_packed_array (arr);
+ else
+ return arr;
+}
+
+/* If TYPE represents a GNAT array type, return it translated to an
+ ordinary GDB array type (possibly with BITSIZE fields indicating
+ packing). For other types, is the identity. */
+struct type *
+ada_coerce_to_simple_array_type (struct type *type)
+{
+ struct value *mark = value_mark ();
+ struct value *dummy = value_from_longest (builtin_type_long, 0);
+ struct type *result;
+ VALUE_TYPE (dummy) = type;
+ result = ada_type_of_array (dummy, 0);
+ value_free_to_mark (dummy);
+ return result;
+}
+
+/* Non-zero iff TYPE represents a standard GNAT packed-array type. */
+int
+ada_is_packed_array_type (struct type *type)
+{
+ if (type == NULL)
+ return 0;
+ CHECK_TYPEDEF (type);
+ return
+ ada_type_name (type) != NULL
+ && strstr (ada_type_name (type), "___XP") != NULL;
+}
+
+/* Given that TYPE is a standard GDB array type with all bounds filled
+ in, and that the element size of its ultimate scalar constituents
+ (that is, either its elements, or, if it is an array of arrays, its
+ elements' elements, etc.) is *ELT_BITS, return an identical type,
+ but with the bit sizes of its elements (and those of any
+ constituent arrays) recorded in the BITSIZE components of its
+ TYPE_FIELD_BITSIZE values, and with *ELT_BITS set to its total size
+ in bits. */
+static struct type *
+packed_array_type (struct type *type, long *elt_bits)
+{
+ struct type *new_elt_type;
+ struct type *new_type;
+ LONGEST low_bound, high_bound;
+
+ CHECK_TYPEDEF (type);
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY)
+ return type;
+
+ new_type = alloc_type (TYPE_OBJFILE (type));
+ new_elt_type = packed_array_type (check_typedef (TYPE_TARGET_TYPE (type)),
+ elt_bits);
+ create_array_type (new_type, new_elt_type, TYPE_FIELD_TYPE (type, 0));
+ TYPE_FIELD_BITSIZE (new_type, 0) = *elt_bits;
+ TYPE_NAME (new_type) = ada_type_name (type);
+
+ if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0),
+ &low_bound, &high_bound) < 0)
+ low_bound = high_bound = 0;
+ if (high_bound < low_bound)
+ *elt_bits = TYPE_LENGTH (new_type) = 0;
+ else
+ {
+ *elt_bits *= (high_bound - low_bound + 1);
+ TYPE_LENGTH (new_type) =
+ (*elt_bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ }
+
+ /* TYPE_FLAGS (new_type) |= TYPE_FLAG_FIXED_INSTANCE; */
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+ return new_type;
+}
+
+/* The array type encoded by TYPE, where ada_is_packed_array_type (TYPE).
+ */
+static struct type *
+decode_packed_array_type (struct type *type)
+{
+ struct symbol **syms;
+ struct block **blocks;
+ const char *raw_name = ada_type_name (check_typedef (type));
+ char *name = (char *) alloca (strlen (raw_name) + 1);
+ char *tail = strstr (raw_name, "___XP");
+ struct type *shadow_type;
+ long bits;
+ int i, n;
+
+ memcpy (name, raw_name, tail - raw_name);
+ name[tail - raw_name] = '\000';
+
+ /* NOTE: Use ada_lookup_symbol_list because of bug in some versions
+ * of gcc (Solaris, e.g.). FIXME when compiler is fixed. */
+ n = ada_lookup_symbol_list (name, get_selected_block (NULL),
+ VAR_DOMAIN, &syms, &blocks);
+ for (i = 0; i < n; i += 1)
+ if (syms[i] != NULL && SYMBOL_CLASS (syms[i]) == LOC_TYPEDEF
+ && DEPRECATED_STREQ (name, ada_type_name (SYMBOL_TYPE (syms[i]))))
+ break;
+ if (i >= n)
+ {
+ warning ("could not find bounds information on packed array");
+ return NULL;
+ }
+ shadow_type = SYMBOL_TYPE (syms[i]);
+
+ if (TYPE_CODE (shadow_type) != TYPE_CODE_ARRAY)
+ {
+ warning ("could not understand bounds information on packed array");
+ return NULL;
+ }
+
+ if (sscanf (tail + sizeof ("___XP") - 1, "%ld", &bits) != 1)
+ {
+ warning ("could not understand bit size information on packed array");
+ return NULL;
+ }
+
+ return packed_array_type (shadow_type, &bits);
+}
+
+/* Given that ARR is a struct value* indicating a GNAT packed array,
+ returns a simple array that denotes that array. Its type is a
+ standard GDB array type except that the BITSIZEs of the array
+ target types are set to the number of bits in each element, and the
+ type length is set appropriately. */
+
+static struct value *
+decode_packed_array (struct value *arr)
+{
+ struct type *type = decode_packed_array_type (VALUE_TYPE (arr));
+
+ if (type == NULL)
+ {
+ error ("can't unpack array");
+ return NULL;
+ }
+ else
+ return coerce_unspec_val_to_type (arr, 0, type);
+}
+
+
+/* The value of the element of packed array ARR at the ARITY indices
+ given in IND. ARR must be a simple array. */
+
+static struct value *
+value_subscript_packed (struct value *arr, int arity, struct value **ind)
+{
+ int i;
+ int bits, elt_off, bit_off;
+ long elt_total_bit_offset;
+ struct type *elt_type;
+ struct value *v;
+
+ bits = 0;
+ elt_total_bit_offset = 0;
+ elt_type = check_typedef (VALUE_TYPE (arr));
+ for (i = 0; i < arity; i += 1)
+ {
+ if (TYPE_CODE (elt_type) != TYPE_CODE_ARRAY
+ || TYPE_FIELD_BITSIZE (elt_type, 0) == 0)
+ error
+ ("attempt to do packed indexing of something other than a packed array");
+ else
+ {
+ struct type *range_type = TYPE_INDEX_TYPE (elt_type);
+ LONGEST lowerbound, upperbound;
+ LONGEST idx;
+
+ if (get_discrete_bounds (range_type, &lowerbound, &upperbound) < 0)
+ {
+ warning ("don't know bounds of array");
+ lowerbound = upperbound = 0;
+ }
+
+ idx = value_as_long (value_pos_atr (ind[i]));
+ if (idx < lowerbound || idx > upperbound)
+ warning ("packed array index %ld out of bounds", (long) idx);
+ bits = TYPE_FIELD_BITSIZE (elt_type, 0);
+ elt_total_bit_offset += (idx - lowerbound) * bits;
+ elt_type = check_typedef (TYPE_TARGET_TYPE (elt_type));
+ }
+ }
+ elt_off = elt_total_bit_offset / HOST_CHAR_BIT;
+ bit_off = elt_total_bit_offset % HOST_CHAR_BIT;
+
+ v = ada_value_primitive_packed_val (arr, NULL, elt_off, bit_off,
+ bits, elt_type);
+ if (VALUE_LVAL (arr) == lval_internalvar)
+ VALUE_LVAL (v) = lval_internalvar_component;
+ else
+ VALUE_LVAL (v) = VALUE_LVAL (arr);
+ return v;
+}
+
+/* Non-zero iff TYPE includes negative integer values. */
+
+static int
+has_negatives (struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ default:
+ return 0;
+ case TYPE_CODE_INT:
+ return !TYPE_UNSIGNED (type);
+ case TYPE_CODE_RANGE:
+ return TYPE_LOW_BOUND (type) < 0;
+ }
+}
+
+
+/* Create a new value of type TYPE from the contents of OBJ starting
+ at byte OFFSET, and bit offset BIT_OFFSET within that byte,
+ proceeding for BIT_SIZE bits. If OBJ is an lval in memory, then
+ assigning through the result will set the field fetched from. OBJ
+ may also be NULL, in which case, VALADDR+OFFSET must address the
+ start of storage containing the packed value. The value returned
+ in this case is never an lval.
+ Assumes 0 <= BIT_OFFSET < HOST_CHAR_BIT. */
+
+struct value *
+ada_value_primitive_packed_val (struct value *obj, char *valaddr, long offset,
+ int bit_offset, int bit_size,
+ struct type *type)
+{
+ struct value *v;
+ int src, /* Index into the source area. */
+ targ, /* Index into the target area. */
+ i, srcBitsLeft, /* Number of source bits left to move. */
+ nsrc, ntarg, /* Number of source and target bytes. */
+ unusedLS, /* Number of bits in next significant
+ * byte of source that are unused. */
+ accumSize; /* Number of meaningful bits in accum */
+ unsigned char *bytes; /* First byte containing data to unpack. */
+ unsigned char *unpacked;
+ unsigned long accum; /* Staging area for bits being transferred */
+ unsigned char sign;
+ int len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
+ /* Transmit bytes from least to most significant; delta is the
+ * direction the indices move. */
+ int delta = BITS_BIG_ENDIAN ? -1 : 1;
+
+ CHECK_TYPEDEF (type);
+
+ if (obj == NULL)
+ {
+ v = allocate_value (type);
+ bytes = (unsigned char *) (valaddr + offset);
+ }
+ else if (VALUE_LAZY (obj))
+ {
+ v = value_at (type,
+ VALUE_ADDRESS (obj) + VALUE_OFFSET (obj) + offset, NULL);
+ bytes = (unsigned char *) alloca (len);
+ read_memory (VALUE_ADDRESS (v), bytes, len);
+ }
+ else
+ {
+ v = allocate_value (type);
+ bytes = (unsigned char *) VALUE_CONTENTS (obj) + offset;
+ }
+
+ if (obj != NULL)
+ {
+ VALUE_LVAL (v) = VALUE_LVAL (obj);
+ if (VALUE_LVAL (obj) == lval_internalvar)
+ VALUE_LVAL (v) = lval_internalvar_component;
+ VALUE_ADDRESS (v) = VALUE_ADDRESS (obj) + VALUE_OFFSET (obj) + offset;
+ VALUE_BITPOS (v) = bit_offset + VALUE_BITPOS (obj);
+ VALUE_BITSIZE (v) = bit_size;
+ if (VALUE_BITPOS (v) >= HOST_CHAR_BIT)
+ {
+ VALUE_ADDRESS (v) += 1;
+ VALUE_BITPOS (v) -= HOST_CHAR_BIT;
+ }
+ }
+ else
+ VALUE_BITSIZE (v) = bit_size;
+ unpacked = (unsigned char *) VALUE_CONTENTS (v);
+
+ srcBitsLeft = bit_size;
+ nsrc = len;
+ ntarg = TYPE_LENGTH (type);
+ sign = 0;
+ if (bit_size == 0)
+ {
+ memset (unpacked, 0, TYPE_LENGTH (type));
+ return v;
+ }
+ else if (BITS_BIG_ENDIAN)
+ {
+ src = len - 1;
+ if (has_negatives (type) &&
+ ((bytes[0] << bit_offset) & (1 << (HOST_CHAR_BIT - 1))))
+ sign = ~0;
+
+ unusedLS =
+ (HOST_CHAR_BIT - (bit_size + bit_offset) % HOST_CHAR_BIT)
+ % HOST_CHAR_BIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_STRUCT:
+ /* Non-scalar values must be aligned at a byte boundary. */
+ accumSize =
+ (HOST_CHAR_BIT - bit_size % HOST_CHAR_BIT) % HOST_CHAR_BIT;
+ /* And are placed at the beginning (most-significant) bytes
+ * of the target. */
+ targ = src;
+ break;
+ default:
+ accumSize = 0;
+ targ = TYPE_LENGTH (type) - 1;
+ break;
+ }
+ }
+ else
+ {
+ int sign_bit_offset = (bit_size + bit_offset - 1) % 8;
+
+ src = targ = 0;
+ unusedLS = bit_offset;
+ accumSize = 0;
+
+ if (has_negatives (type) && (bytes[len - 1] & (1 << sign_bit_offset)))
+ sign = ~0;
+ }
+
+ accum = 0;
+ while (nsrc > 0)
+ {
+ /* Mask for removing bits of the next source byte that are not
+ * part of the value. */
+ unsigned int unusedMSMask =
+ (1 << (srcBitsLeft >= HOST_CHAR_BIT ? HOST_CHAR_BIT : srcBitsLeft)) -
+ 1;
+ /* Sign-extend bits for this byte. */
+ unsigned int signMask = sign & ~unusedMSMask;
+ accum |=
+ (((bytes[src] >> unusedLS) & unusedMSMask) | signMask) << accumSize;
+ accumSize += HOST_CHAR_BIT - unusedLS;
+ if (accumSize >= HOST_CHAR_BIT)
+ {
+ unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
+ accumSize -= HOST_CHAR_BIT;
+ accum >>= HOST_CHAR_BIT;
+ ntarg -= 1;
+ targ += delta;
+ }
+ srcBitsLeft -= HOST_CHAR_BIT - unusedLS;
+ unusedLS = 0;
+ nsrc -= 1;
+ src += delta;
+ }
+ while (ntarg > 0)
+ {
+ accum |= sign << accumSize;
+ unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
+ accumSize -= HOST_CHAR_BIT;
+ accum >>= HOST_CHAR_BIT;
+ ntarg -= 1;
+ targ += delta;
+ }
+
+ return v;
+}
+
+/* Move N bits from SOURCE, starting at bit offset SRC_OFFSET to
+ TARGET, starting at bit offset TARG_OFFSET. SOURCE and TARGET must
+ not overlap. */
+static void
+move_bits (char *target, int targ_offset, char *source, int src_offset, int n)
+{
+ unsigned int accum, mask;
+ int accum_bits, chunk_size;
+
+ target += targ_offset / HOST_CHAR_BIT;
+ targ_offset %= HOST_CHAR_BIT;
+ source += src_offset / HOST_CHAR_BIT;
+ src_offset %= HOST_CHAR_BIT;
+ if (BITS_BIG_ENDIAN)
+ {
+ accum = (unsigned char) *source;
+ source += 1;
+ accum_bits = HOST_CHAR_BIT - src_offset;
+
+ while (n > 0)
+ {
+ int unused_right;
+ accum = (accum << HOST_CHAR_BIT) + (unsigned char) *source;
+ accum_bits += HOST_CHAR_BIT;
+ source += 1;
+ chunk_size = HOST_CHAR_BIT - targ_offset;
+ if (chunk_size > n)
+ chunk_size = n;
+ unused_right = HOST_CHAR_BIT - (chunk_size + targ_offset);
+ mask = ((1 << chunk_size) - 1) << unused_right;
+ *target =
+ (*target & ~mask)
+ | ((accum >> (accum_bits - chunk_size - unused_right)) & mask);
+ n -= chunk_size;
+ accum_bits -= chunk_size;
+ target += 1;
+ targ_offset = 0;
+ }
+ }
+ else
+ {
+ accum = (unsigned char) *source >> src_offset;
+ source += 1;
+ accum_bits = HOST_CHAR_BIT - src_offset;
+
+ while (n > 0)
+ {
+ accum = accum + ((unsigned char) *source << accum_bits);
+ accum_bits += HOST_CHAR_BIT;
+ source += 1;
+ chunk_size = HOST_CHAR_BIT - targ_offset;
+ if (chunk_size > n)
+ chunk_size = n;
+ mask = ((1 << chunk_size) - 1) << targ_offset;
+ *target = (*target & ~mask) | ((accum << targ_offset) & mask);
+ n -= chunk_size;
+ accum_bits -= chunk_size;
+ accum >>= chunk_size;
+ target += 1;
+ targ_offset = 0;
+ }
+ }
+}
+
+
+/* Store the contents of FROMVAL into the location of TOVAL.
+ Return a new value with the location of TOVAL and contents of
+ FROMVAL. Handles assignment into packed fields that have
+ floating-point or non-scalar types. */
+
+static struct value *
+ada_value_assign (struct value *toval, struct value *fromval)
+{
+ struct type *type = VALUE_TYPE (toval);
+ int bits = VALUE_BITSIZE (toval);
+
+ if (!toval->modifiable)
+ error ("Left operand of assignment is not a modifiable lvalue.");
+
+ COERCE_REF (toval);
+
+ if (VALUE_LVAL (toval) == lval_memory
+ && bits > 0
+ && (TYPE_CODE (type) == TYPE_CODE_FLT
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT))
+ {
+ int len =
+ (VALUE_BITPOS (toval) + bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ char *buffer = (char *) alloca (len);
+ struct value *val;
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ fromval = value_cast (type, fromval);
+
+ read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), buffer, len);
+ if (BITS_BIG_ENDIAN)
+ move_bits (buffer, VALUE_BITPOS (toval),
+ VALUE_CONTENTS (fromval),
+ TYPE_LENGTH (VALUE_TYPE (fromval)) * TARGET_CHAR_BIT -
+ bits, bits);
+ else
+ move_bits (buffer, VALUE_BITPOS (toval), VALUE_CONTENTS (fromval),
+ 0, bits);
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), buffer,
+ len);
+
+ val = value_copy (toval);
+ memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval),
+ TYPE_LENGTH (type));
+ VALUE_TYPE (val) = type;
+
+ return val;
+ }
+
+ return value_assign (toval, fromval);
+}
+
+
+/* The value of the element of array ARR at the ARITY indices given in IND.
+ ARR may be either a simple array, GNAT array descriptor, or pointer
+ thereto. */
+
+struct value *
+ada_value_subscript (struct value *arr, int arity, struct value **ind)
+{
+ int k;
+ struct value *elt;
+ struct type *elt_type;
+
+ elt = ada_coerce_to_simple_array (arr);
+
+ elt_type = check_typedef (VALUE_TYPE (elt));
+ if (TYPE_CODE (elt_type) == TYPE_CODE_ARRAY
+ && TYPE_FIELD_BITSIZE (elt_type, 0) > 0)
+ return value_subscript_packed (elt, arity, ind);
+
+ for (k = 0; k < arity; k += 1)
+ {
+ if (TYPE_CODE (elt_type) != TYPE_CODE_ARRAY)
+ error ("too many subscripts (%d expected)", k);
+ elt = value_subscript (elt, value_pos_atr (ind[k]));
+ }
+ return elt;
+}
+
+/* Assuming ARR is a pointer to a standard GDB array of type TYPE, the
+ value of the element of *ARR at the ARITY indices given in
+ IND. Does not read the entire array into memory. */
+
+struct value *
+ada_value_ptr_subscript (struct value *arr, struct type *type, int arity,
+ struct value **ind)
+{
+ int k;
+
+ for (k = 0; k < arity; k += 1)
+ {
+ LONGEST lwb, upb;
+ struct value *idx;
+
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY)
+ error ("too many subscripts (%d expected)", k);
+ arr = value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ value_copy (arr));
+ get_discrete_bounds (TYPE_INDEX_TYPE (type), &lwb, &upb);
+ if (lwb == 0)
+ idx = ind[k];
+ else
+ idx = value_sub (ind[k], value_from_longest (builtin_type_int, lwb));
+ arr = value_add (arr, idx);
+ type = TYPE_TARGET_TYPE (type);
+ }
+
+ return value_ind (arr);
+}
+
+/* If type is a record type in the form of a standard GNAT array
+ descriptor, returns the number of dimensions for type. If arr is a
+ simple array, returns the number of "array of"s that prefix its
+ type designation. Otherwise, returns 0. */
+
+int
+ada_array_arity (struct type *type)
+{
+ int arity;
+
+ if (type == NULL)
+ return 0;
+
+ type = desc_base_type (type);
+
+ arity = 0;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ return desc_arity (desc_bounds_type (type));
+ else
+ while (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ arity += 1;
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ }
+
+ return arity;
+}
+
+/* If TYPE is a record type in the form of a standard GNAT array
+ descriptor or a simple array type, returns the element type for
+ TYPE after indexing by NINDICES indices, or by all indices if
+ NINDICES is -1. Otherwise, returns NULL. */
+
+struct type *
+ada_array_element_type (struct type *type, int nindices)
+{
+ type = desc_base_type (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ int k;
+ struct type *p_array_type;
+
+ p_array_type = desc_data_type (type);
+
+ k = ada_array_arity (type);
+ if (k == 0)
+ return NULL;
+
+ /* Initially p_array_type = elt_type(*)[]...(k times)...[] */
+ if (nindices >= 0 && k > nindices)
+ k = nindices;
+ p_array_type = TYPE_TARGET_TYPE (p_array_type);
+ while (k > 0 && p_array_type != NULL)
+ {
+ p_array_type = check_typedef (TYPE_TARGET_TYPE (p_array_type));
+ k -= 1;
+ }
+ return p_array_type;
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ while (nindices != 0 && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ type = TYPE_TARGET_TYPE (type);
+ nindices -= 1;
+ }
+ return type;
+ }
+
+ return NULL;
+}
+
+/* The type of nth index in arrays of given type (n numbering from 1). Does
+ not examine memory. */
+
+struct type *
+ada_index_type (struct type *type, int n)
+{
+ type = desc_base_type (type);
+
+ if (n > ada_array_arity (type))
+ return NULL;
+
+ if (ada_is_simple_array (type))
+ {
+ int i;
+
+ for (i = 1; i < n; i += 1)
+ type = TYPE_TARGET_TYPE (type);
+
+ return TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 0));
+ }
+ else
+ return desc_index_type (desc_bounds_type (type), n);
+}
+
+/* Given that arr is an array type, returns the lower bound of the
+ Nth index (numbering from 1) if WHICH is 0, and the upper bound if
+ WHICH is 1. This returns bounds 0 .. -1 if ARR_TYPE is an
+ array-descriptor type. If TYPEP is non-null, *TYPEP is set to the
+ bounds type. It works for other arrays with bounds supplied by
+ run-time quantities other than discriminants. */
+
+LONGEST
+ada_array_bound_from_type (struct type * arr_type, int n, int which,
+ struct type ** typep)
+{
+ struct type *type;
+ struct type *index_type_desc;
+
+ if (ada_is_packed_array_type (arr_type))
+ arr_type = decode_packed_array_type (arr_type);
+
+ if (arr_type == NULL || !ada_is_simple_array (arr_type))
+ {
+ if (typep != NULL)
+ *typep = builtin_type_int;
+ return (LONGEST) - which;
+ }
+
+ if (TYPE_CODE (arr_type) == TYPE_CODE_PTR)
+ type = TYPE_TARGET_TYPE (arr_type);
+ else
+ type = arr_type;
+
+ index_type_desc = ada_find_parallel_type (type, "___XA");
+ if (index_type_desc == NULL)
+ {
+ struct type *range_type;
+ struct type *index_type;
+
+ while (n > 1)
+ {
+ type = TYPE_TARGET_TYPE (type);
+ n -= 1;
+ }
+
+ range_type = TYPE_INDEX_TYPE (type);
+ index_type = TYPE_TARGET_TYPE (range_type);
+ if (TYPE_CODE (index_type) == TYPE_CODE_UNDEF)
+ index_type = builtin_type_long;
+ if (typep != NULL)
+ *typep = index_type;
+ return
+ (LONGEST) (which == 0
+ ? TYPE_LOW_BOUND (range_type)
+ : TYPE_HIGH_BOUND (range_type));
+ }
+ else
+ {
+ struct type *index_type =
+ to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, n - 1),
+ NULL, TYPE_OBJFILE (arr_type));
+ if (typep != NULL)
+ *typep = TYPE_TARGET_TYPE (index_type);
+ return
+ (LONGEST) (which == 0
+ ? TYPE_LOW_BOUND (index_type)
+ : TYPE_HIGH_BOUND (index_type));
+ }
+}
+
+/* Given that arr is an array value, returns the lower bound of the
+ nth index (numbering from 1) if which is 0, and the upper bound if
+ which is 1. This routine will also work for arrays with bounds
+ supplied by run-time quantities other than discriminants. */
+
+struct value *
+ada_array_bound (struct value *arr, int n, int which)
+{
+ struct type *arr_type = VALUE_TYPE (arr);
+
+ if (ada_is_packed_array_type (arr_type))
+ return ada_array_bound (decode_packed_array (arr), n, which);
+ else if (ada_is_simple_array (arr_type))
+ {
+ struct type *type;
+ LONGEST v = ada_array_bound_from_type (arr_type, n, which, &type);
+ return value_from_longest (type, v);
+ }
+ else
+ return desc_one_bound (desc_bounds (arr), n, which);
+}
+
+/* Given that arr is an array value, returns the length of the
+ nth index. This routine will also work for arrays with bounds
+ supplied by run-time quantities other than discriminants. Does not
+ work for arrays indexed by enumeration types with representation
+ clauses at the moment. */
+
+struct value *
+ada_array_length (struct value *arr, int n)
+{
+ struct type *arr_type = check_typedef (VALUE_TYPE (arr));
+ struct type *index_type_desc;
+
+ if (ada_is_packed_array_type (arr_type))
+ return ada_array_length (decode_packed_array (arr), n);
+
+ if (ada_is_simple_array (arr_type))
+ {
+ struct type *type;
+ LONGEST v =
+ ada_array_bound_from_type (arr_type, n, 1, &type) -
+ ada_array_bound_from_type (arr_type, n, 0, NULL) + 1;
+ return value_from_longest (type, v);
+ }
+ else
+ return
+ value_from_longest (builtin_type_ada_int,
+ value_as_long (desc_one_bound (desc_bounds (arr),
+ n, 1))
+ - value_as_long (desc_one_bound (desc_bounds (arr),
+ n, 0)) + 1);
+}
+
+
+ /* Name resolution */
+
+/* The "demangled" name for the user-definable Ada operator corresponding
+ to op. */
+
+static const char *
+ada_op_name (enum exp_opcode op)
+{
+ int i;
+
+ for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+ {
+ if (ada_opname_table[i].op == op)
+ return ada_opname_table[i].demangled;
+ }
+ error ("Could not find operator name for opcode");
+}
+
+
+/* Same as evaluate_type (*EXP), but resolves ambiguous symbol
+ references (OP_UNRESOLVED_VALUES) and converts operators that are
+ user-defined into appropriate function calls. If CONTEXT_TYPE is
+ non-null, it provides a preferred result type [at the moment, only
+ type void has any effect---causing procedures to be preferred over
+ functions in calls]. A null CONTEXT_TYPE indicates that a non-void
+ return type is preferred. The variable unresolved_names contains a list
+ of character strings referenced by expout that should be freed.
+ May change (expand) *EXP. */
+
+void
+ada_resolve (struct expression **expp, struct type *context_type)
+{
+ int pc;
+ pc = 0;
+ ada_resolve_subexp (expp, &pc, 1, context_type);
+}
+
+/* Resolve the operator of the subexpression beginning at
+ position *POS of *EXPP. "Resolving" consists of replacing
+ OP_UNRESOLVED_VALUE with an appropriate OP_VAR_VALUE, replacing
+ built-in operators with function calls to user-defined operators,
+ where appropriate, and (when DEPROCEDURE_P is non-zero), converting
+ function-valued variables into parameterless calls. May expand
+ EXP. The CONTEXT_TYPE functions as in ada_resolve, above. */
+
+static struct value *
+ada_resolve_subexp (struct expression **expp, int *pos, int deprocedure_p,
+ struct type *context_type)
+{
+ int pc = *pos;
+ int i;
+ struct expression *exp; /* Convenience: == *expp */
+ enum exp_opcode op = (*expp)->elts[pc].opcode;
+ struct value **argvec; /* Vector of operand types (alloca'ed). */
+ int nargs; /* Number of operands */
+
+ argvec = NULL;
+ nargs = 0;
+ exp = *expp;
+
+ /* Pass one: resolve operands, saving their types and updating *pos. */
+ switch (op)
+ {
+ case OP_VAR_VALUE:
+ /* case OP_UNRESOLVED_VALUE: */
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ *pos += 4;
+ break;
+
+ case OP_FUNCALL:
+ nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ /* if (exp->elts[pc+3].opcode == OP_UNRESOLVED_VALUE)
+ {
+ *pos += 7;
+
+ argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 1));
+ for (i = 0; i < nargs-1; i += 1)
+ argvec[i] = ada_resolve_subexp (expp, pos, 1, NULL);
+ argvec[i] = NULL;
+ }
+ else
+ {
+ *pos += 3;
+ ada_resolve_subexp (expp, pos, 0, NULL);
+ for (i = 1; i < nargs; i += 1)
+ ada_resolve_subexp (expp, pos, 1, NULL);
+ }
+ */
+ exp = *expp;
+ break;
+
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ /* case UNOP_QUAL:
+ nargs = 1;
+ *pos += 3;
+ ada_resolve_subexp (expp, pos, 1, exp->elts[pc + 1].type);
+ exp = *expp;
+ break;
+ */
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ /* case OP_ATTRIBUTE:
+ nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+ *pos += 4;
+ for (i = 0; i < nargs; i += 1)
+ ada_resolve_subexp (expp, pos, 1, NULL);
+ exp = *expp;
+ break;
+ */
+ case UNOP_ADDR:
+ nargs = 1;
+ *pos += 1;
+ ada_resolve_subexp (expp, pos, 0, NULL);
+ exp = *expp;
+ break;
+
+ case BINOP_ASSIGN:
+ {
+ struct value *arg1;
+ nargs = 2;
+ *pos += 1;
+ arg1 = ada_resolve_subexp (expp, pos, 0, NULL);
+ if (arg1 == NULL)
+ ada_resolve_subexp (expp, pos, 1, NULL);
+ else
+ ada_resolve_subexp (expp, pos, 1, VALUE_TYPE (arg1));
+ break;
+ }
+
+ default:
+ switch (op)
+ {
+ default:
+ error ("Unexpected operator during name resolution");
+ case UNOP_CAST:
+ /* case UNOP_MBR:
+ nargs = 1;
+ *pos += 3;
+ break;
+ */
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_MOD:
+ case BINOP_EXP:
+ case BINOP_CONCAT:
+ case BINOP_LOGICAL_AND:
+ case BINOP_LOGICAL_OR:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+
+ case BINOP_REPEAT:
+ case BINOP_SUBSCRIPT:
+ case BINOP_COMMA:
+ nargs = 2;
+ *pos += 1;
+ break;
+
+ case UNOP_NEG:
+ case UNOP_PLUS:
+ case UNOP_LOGICAL_NOT:
+ case UNOP_ABS:
+ case UNOP_IND:
+ nargs = 1;
+ *pos += 1;
+ break;
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ case OP_VAR_VALUE:
+ *pos += 4;
+ break;
+
+ case OP_TYPE:
+ case OP_BOOL:
+ case OP_LAST:
+ case OP_REGISTER:
+ case OP_INTERNALVAR:
+ *pos += 3;
+ break;
+
+ case UNOP_MEMVAL:
+ *pos += 3;
+ nargs = 1;
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ nargs = 1;
+ *pos += 4 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
+ break;
+
+ case OP_ARRAY:
+ *pos += 4;
+ nargs = longest_to_int (exp->elts[pc + 2].longconst) + 1;
+ nargs -= longest_to_int (exp->elts[pc + 1].longconst);
+ /* A null array contains one dummy element to give the type. */
+ /* if (nargs == 0)
+ nargs = 1;
+ break; */
+
+ case TERNOP_SLICE:
+ /* FIXME: TERNOP_MBR should be defined in expression.h */
+ /* case TERNOP_MBR:
+ *pos += 1;
+ nargs = 3;
+ break;
+ */
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ /* case BINOP_MBR:
+ *pos += 3;
+ nargs = 2;
+ break; */
+ }
+
+ argvec =
+ (struct value * *) alloca (sizeof (struct value *) * (nargs + 1));
+ for (i = 0; i < nargs; i += 1)
+ argvec[i] = ada_resolve_subexp (expp, pos, 1, NULL);
+ argvec[i] = NULL;
+ exp = *expp;
+ break;
+ }
+
+ /* Pass two: perform any resolution on principal operator. */
+ switch (op)
+ {
+ default:
+ break;
+
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ /* case OP_UNRESOLVED_VALUE:
+ {
+ struct symbol** candidate_syms;
+ struct block** candidate_blocks;
+ int n_candidates;
+
+ n_candidates = ada_lookup_symbol_list (exp->elts[pc + 2].name,
+ exp->elts[pc + 1].block,
+ VAR_DOMAIN,
+ &candidate_syms,
+ &candidate_blocks);
+
+ if (n_candidates > 1)
+ { */
+ /* Types tend to get re-introduced locally, so if there
+ are any local symbols that are not types, first filter
+ out all types. *//*
+ int j;
+ for (j = 0; j < n_candidates; j += 1)
+ switch (SYMBOL_CLASS (candidate_syms[j]))
+ {
+ 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_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ goto FoundNonType;
+ default:
+ break;
+ }
+ FoundNonType:
+ if (j < n_candidates)
+ {
+ j = 0;
+ while (j < n_candidates)
+ {
+ if (SYMBOL_CLASS (candidate_syms[j]) == LOC_TYPEDEF)
+ {
+ candidate_syms[j] = candidate_syms[n_candidates-1];
+ candidate_blocks[j] = candidate_blocks[n_candidates-1];
+ n_candidates -= 1;
+ }
+ else
+ j += 1;
+ }
+ }
+ }
+
+ if (n_candidates == 0)
+ error ("No definition found for %s",
+ ada_demangle (exp->elts[pc + 2].name));
+ else if (n_candidates == 1)
+ i = 0;
+ else if (deprocedure_p
+ && ! is_nonfunction (candidate_syms, n_candidates))
+ {
+ i = ada_resolve_function (candidate_syms, candidate_blocks,
+ n_candidates, NULL, 0,
+ exp->elts[pc + 2].name, context_type);
+ if (i < 0)
+ error ("Could not find a match for %s",
+ ada_demangle (exp->elts[pc + 2].name));
+ }
+ else
+ {
+ printf_filtered ("Multiple matches for %s\n",
+ ada_demangle (exp->elts[pc+2].name));
+ user_select_syms (candidate_syms, candidate_blocks,
+ n_candidates, 1);
+ i = 0;
+ }
+
+ exp->elts[pc].opcode = exp->elts[pc + 3].opcode = OP_VAR_VALUE;
+ exp->elts[pc + 1].block = candidate_blocks[i];
+ exp->elts[pc + 2].symbol = candidate_syms[i];
+ if (innermost_block == NULL ||
+ contained_in (candidate_blocks[i], innermost_block))
+ innermost_block = candidate_blocks[i];
+ } */
+ /* FALL THROUGH */
+
+ case OP_VAR_VALUE:
+ if (deprocedure_p &&
+ TYPE_CODE (SYMBOL_TYPE (exp->elts[pc + 2].symbol)) ==
+ TYPE_CODE_FUNC)
+ {
+ replace_operator_with_call (expp, pc, 0, 0,
+ exp->elts[pc + 2].symbol,
+ exp->elts[pc + 1].block);
+ exp = *expp;
+ }
+ break;
+
+ case OP_FUNCALL:
+ {
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ /* if (exp->elts[pc+3].opcode == OP_UNRESOLVED_VALUE)
+ {
+ struct symbol** candidate_syms;
+ struct block** candidate_blocks;
+ int n_candidates;
+
+ n_candidates = ada_lookup_symbol_list (exp->elts[pc + 5].name,
+ exp->elts[pc + 4].block,
+ VAR_DOMAIN,
+ &candidate_syms,
+ &candidate_blocks);
+ if (n_candidates == 1)
+ i = 0;
+ else
+ {
+ i = ada_resolve_function (candidate_syms, candidate_blocks,
+ n_candidates, argvec, nargs-1,
+ exp->elts[pc + 5].name, context_type);
+ if (i < 0)
+ error ("Could not find a match for %s",
+ ada_demangle (exp->elts[pc + 5].name));
+ }
+
+ exp->elts[pc + 3].opcode = exp->elts[pc + 6].opcode = OP_VAR_VALUE;
+ exp->elts[pc + 4].block = candidate_blocks[i];
+ exp->elts[pc + 5].symbol = candidate_syms[i];
+ if (innermost_block == NULL ||
+ contained_in (candidate_blocks[i], innermost_block))
+ innermost_block = candidate_blocks[i];
+ } */
+
+ }
+ break;
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_MOD:
+ case BINOP_CONCAT:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+ case BINOP_EXP:
+ case UNOP_NEG:
+ case UNOP_PLUS:
+ case UNOP_LOGICAL_NOT:
+ case UNOP_ABS:
+ if (possible_user_operator_p (op, argvec))
+ {
+ struct symbol **candidate_syms;
+ struct block **candidate_blocks;
+ int n_candidates;
+
+ n_candidates =
+ ada_lookup_symbol_list (ada_mangle (ada_op_name (op)),
+ (struct block *) NULL, VAR_DOMAIN,
+ &candidate_syms, &candidate_blocks);
+ i =
+ ada_resolve_function (candidate_syms, candidate_blocks,
+ n_candidates, argvec, nargs,
+ ada_op_name (op), NULL);
+ if (i < 0)
+ break;
+
+ replace_operator_with_call (expp, pc, nargs, 1,
+ candidate_syms[i], candidate_blocks[i]);
+ exp = *expp;
+ }
+ break;
+ }
+
+ *pos = pc;
+ return evaluate_subexp_type (exp, pos);
+}
+
+/* Return non-zero if formal type FTYPE matches actual type ATYPE. If
+ MAY_DEREF is non-zero, the formal may be a pointer and the actual
+ a non-pointer. */
+/* The term "match" here is rather loose. The match is heuristic and
+ liberal. FIXME: TOO liberal, in fact. */
+
+static int
+ada_type_match (struct type *ftype, struct type *atype, int may_deref)
+{
+ CHECK_TYPEDEF (ftype);
+ CHECK_TYPEDEF (atype);
+
+ if (TYPE_CODE (ftype) == TYPE_CODE_REF)
+ ftype = TYPE_TARGET_TYPE (ftype);
+ if (TYPE_CODE (atype) == TYPE_CODE_REF)
+ atype = TYPE_TARGET_TYPE (atype);
+
+ if (TYPE_CODE (ftype) == TYPE_CODE_VOID
+ || TYPE_CODE (atype) == TYPE_CODE_VOID)
+ return 1;
+
+ switch (TYPE_CODE (ftype))
+ {
+ default:
+ return 1;
+ case TYPE_CODE_PTR:
+ if (TYPE_CODE (atype) == TYPE_CODE_PTR)
+ return ada_type_match (TYPE_TARGET_TYPE (ftype),
+ TYPE_TARGET_TYPE (atype), 0);
+ else
+ return (may_deref &&
+ ada_type_match (TYPE_TARGET_TYPE (ftype), atype, 0));
+ case TYPE_CODE_INT:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_RANGE:
+ switch (TYPE_CODE (atype))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_RANGE:
+ return 1;
+ default:
+ return 0;
+ }
+
+ case TYPE_CODE_ARRAY:
+ return (TYPE_CODE (atype) == TYPE_CODE_ARRAY
+ || ada_is_array_descriptor (atype));
+
+ case TYPE_CODE_STRUCT:
+ if (ada_is_array_descriptor (ftype))
+ return (TYPE_CODE (atype) == TYPE_CODE_ARRAY
+ || ada_is_array_descriptor (atype));
+ else
+ return (TYPE_CODE (atype) == TYPE_CODE_STRUCT
+ && !ada_is_array_descriptor (atype));
+
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_FLT:
+ return (TYPE_CODE (atype) == TYPE_CODE (ftype));
+ }
+}
+
+/* Return non-zero if the formals of FUNC "sufficiently match" the
+ vector of actual argument types ACTUALS of size N_ACTUALS. FUNC
+ may also be an enumeral, in which case it is treated as a 0-
+ argument function. */
+
+static int
+ada_args_match (struct symbol *func, struct value **actuals, int n_actuals)
+{
+ int i;
+ struct type *func_type = SYMBOL_TYPE (func);
+
+ if (SYMBOL_CLASS (func) == LOC_CONST &&
+ TYPE_CODE (func_type) == TYPE_CODE_ENUM)
+ return (n_actuals == 0);
+ else if (func_type == NULL || TYPE_CODE (func_type) != TYPE_CODE_FUNC)
+ return 0;
+
+ if (TYPE_NFIELDS (func_type) != n_actuals)
+ return 0;
+
+ for (i = 0; i < n_actuals; i += 1)
+ {
+ struct type *ftype = check_typedef (TYPE_FIELD_TYPE (func_type, i));
+ struct type *atype = check_typedef (VALUE_TYPE (actuals[i]));
+
+ if (!ada_type_match (TYPE_FIELD_TYPE (func_type, i),
+ VALUE_TYPE (actuals[i]), 1))
+ return 0;
+ }
+ return 1;
+}
+
+/* False iff function type FUNC_TYPE definitely does not produce a value
+ compatible with type CONTEXT_TYPE. Conservatively returns 1 if
+ FUNC_TYPE is not a valid function type with a non-null return type
+ or an enumerated type. A null CONTEXT_TYPE indicates any non-void type. */
+
+static int
+return_match (struct type *func_type, struct type *context_type)
+{
+ struct type *return_type;
+
+ if (func_type == NULL)
+ return 1;
+
+ /* FIXME: base_type should be declared in gdbtypes.h, implemented in valarith.c */
+ /* if (TYPE_CODE (func_type) == TYPE_CODE_FUNC)
+ return_type = base_type (TYPE_TARGET_TYPE (func_type));
+ else
+ return_type = base_type (func_type); */
+ if (return_type == NULL)
+ return 1;
+
+ /* FIXME: base_type should be declared in gdbtypes.h, implemented in valarith.c */
+ /* context_type = base_type (context_type); */
+
+ if (TYPE_CODE (return_type) == TYPE_CODE_ENUM)
+ return context_type == NULL || return_type == context_type;
+ else if (context_type == NULL)
+ return TYPE_CODE (return_type) != TYPE_CODE_VOID;
+ else
+ return TYPE_CODE (return_type) == TYPE_CODE (context_type);
+}
+
+
+/* Return the index in SYMS[0..NSYMS-1] of symbol for the
+ function (if any) that matches the types of the NARGS arguments in
+ ARGS. If CONTEXT_TYPE is non-null, and there is at least one match
+ that returns type CONTEXT_TYPE, then eliminate other matches. If
+ CONTEXT_TYPE is null, prefer a non-void-returning function.
+ Asks the user if there is more than one match remaining. Returns -1
+ if there is no such symbol or none is selected. NAME is used
+ solely for messages. May re-arrange and modify SYMS in
+ the process; the index returned is for the modified vector. BLOCKS
+ is modified in parallel to SYMS. */
+
+int
+ada_resolve_function (struct symbol *syms[], struct block *blocks[],
+ int nsyms, struct value **args, int nargs,
+ const char *name, struct type *context_type)
+{
+ int k;
+ int m; /* Number of hits */
+ struct type *fallback;
+ struct type *return_type;
+
+ return_type = context_type;
+ if (context_type == NULL)
+ fallback = builtin_type_void;
+ else
+ fallback = NULL;
+
+ m = 0;
+ while (1)
+ {
+ for (k = 0; k < nsyms; k += 1)
+ {
+ struct type *type = check_typedef (SYMBOL_TYPE (syms[k]));
+
+ if (ada_args_match (syms[k], args, nargs)
+ && return_match (SYMBOL_TYPE (syms[k]), return_type))
+ {
+ syms[m] = syms[k];
+ if (blocks != NULL)
+ blocks[m] = blocks[k];
+ m += 1;
+ }
+ }
+ if (m > 0 || return_type == fallback)
+ break;
+ else
+ return_type = fallback;
+ }
+
+ if (m == 0)
+ return -1;
+ else if (m > 1)
+ {
+ printf_filtered ("Multiple matches for %s\n", name);
+ user_select_syms (syms, blocks, m, 1);
+ return 0;
+ }
+ return 0;
+}
+
+/* Returns true (non-zero) iff demangled name N0 should appear before N1 */
+/* in a listing of choices during disambiguation (see sort_choices, below). */
+/* The idea is that overloadings of a subprogram name from the */
+/* same package should sort in their source order. We settle for ordering */
+/* such symbols by their trailing number (__N or $N). */
+static int
+mangled_ordered_before (char *N0, char *N1)
+{
+ if (N1 == NULL)
+ return 0;
+ else if (N0 == NULL)
+ return 1;
+ else
+ {
+ int k0, k1;
+ for (k0 = strlen (N0) - 1; k0 > 0 && isdigit (N0[k0]); k0 -= 1)
+ ;
+ for (k1 = strlen (N1) - 1; k1 > 0 && isdigit (N1[k1]); k1 -= 1)
+ ;
+ if ((N0[k0] == '_' || N0[k0] == '$') && N0[k0 + 1] != '\000'
+ && (N1[k1] == '_' || N1[k1] == '$') && N1[k1 + 1] != '\000')
+ {
+ int n0, n1;
+ n0 = k0;
+ while (N0[n0] == '_' && n0 > 0 && N0[n0 - 1] == '_')
+ n0 -= 1;
+ n1 = k1;
+ while (N1[n1] == '_' && n1 > 0 && N1[n1 - 1] == '_')
+ n1 -= 1;
+ if (n0 == n1 && DEPRECATED_STREQN (N0, N1, n0))
+ return (atoi (N0 + k0 + 1) < atoi (N1 + k1 + 1));
+ }
+ return (strcmp (N0, N1) < 0);
+ }
+}
+
+/* Sort SYMS[0..NSYMS-1] to put the choices in a canonical order by their */
+/* mangled names, rearranging BLOCKS[0..NSYMS-1] according to the same */
+/* permutation. */
+static void
+sort_choices (struct symbol *syms[], struct block *blocks[], int nsyms)
+{
+ int i, j;
+ for (i = 1; i < nsyms; i += 1)
+ {
+ struct symbol *sym = syms[i];
+ struct block *block = blocks[i];
+ int j;
+
+ for (j = i - 1; j >= 0; j -= 1)
+ {
+ if (mangled_ordered_before (DEPRECATED_SYMBOL_NAME (syms[j]),
+ DEPRECATED_SYMBOL_NAME (sym)))
+ break;
+ syms[j + 1] = syms[j];
+ blocks[j + 1] = blocks[j];
+ }
+ syms[j + 1] = sym;
+ blocks[j + 1] = block;
+ }
+}
+
+/* Given a list of NSYMS symbols in SYMS and corresponding blocks in */
+/* BLOCKS, select up to MAX_RESULTS>0 by asking the user (if */
+/* necessary), returning the number selected, and setting the first */
+/* elements of SYMS and BLOCKS to the selected symbols and */
+/* corresponding blocks. Error if no symbols selected. BLOCKS may */
+/* be NULL, in which case it is ignored. */
+
+/* NOTE: Adapted from decode_line_2 in symtab.c, with which it ought
+ to be re-integrated one of these days. */
+
+int
+user_select_syms (struct symbol *syms[], struct block *blocks[], int nsyms,
+ int max_results)
+{
+ int i;
+ int *chosen = (int *) alloca (sizeof (int) * nsyms);
+ int n_chosen;
+ int first_choice = (max_results == 1) ? 1 : 2;
+
+ if (max_results < 1)
+ error ("Request to select 0 symbols!");
+ if (nsyms <= 1)
+ return nsyms;
+
+ printf_unfiltered ("[0] cancel\n");
+ if (max_results > 1)
+ printf_unfiltered ("[1] all\n");
+
+ sort_choices (syms, blocks, nsyms);
+
+ for (i = 0; i < nsyms; i += 1)
+ {
+ if (syms[i] == NULL)
+ continue;
+
+ if (SYMBOL_CLASS (syms[i]) == LOC_BLOCK)
+ {
+ struct symtab_and_line sal = find_function_start_sal (syms[i], 1);
+ printf_unfiltered ("[%d] %s at %s:%d\n",
+ i + first_choice,
+ SYMBOL_PRINT_NAME (syms[i]),
+ sal.symtab == NULL
+ ? "<no source file available>"
+ : sal.symtab->filename, sal.line);
+ continue;
+ }
+ else
+ {
+ int is_enumeral =
+ (SYMBOL_CLASS (syms[i]) == LOC_CONST
+ && SYMBOL_TYPE (syms[i]) != NULL
+ && TYPE_CODE (SYMBOL_TYPE (syms[i])) == TYPE_CODE_ENUM);
+ struct symtab *symtab = symtab_for_sym (syms[i]);
+
+ if (SYMBOL_LINE (syms[i]) != 0 && symtab != NULL)
+ printf_unfiltered ("[%d] %s at %s:%d\n",
+ i + first_choice,
+ SYMBOL_PRINT_NAME (syms[i]),
+ symtab->filename, SYMBOL_LINE (syms[i]));
+ else if (is_enumeral && TYPE_NAME (SYMBOL_TYPE (syms[i])) != NULL)
+ {
+ printf_unfiltered ("[%d] ", i + first_choice);
+ ada_print_type (SYMBOL_TYPE (syms[i]), NULL, gdb_stdout, -1, 0);
+ printf_unfiltered ("'(%s) (enumeral)\n",
+ SYMBOL_PRINT_NAME (syms[i]));
+ }
+ else if (symtab != NULL)
+ printf_unfiltered (is_enumeral
+ ? "[%d] %s in %s (enumeral)\n"
+ : "[%d] %s at %s:?\n",
+ i + first_choice,
+ SYMBOL_PRINT_NAME (syms[i]),
+ symtab->filename);
+ else
+ printf_unfiltered (is_enumeral
+ ? "[%d] %s (enumeral)\n"
+ : "[%d] %s at ?\n",
+ i + first_choice,
+ SYMBOL_PRINT_NAME (syms[i]));
+ }
+ }
+
+ n_chosen = get_selections (chosen, nsyms, max_results, max_results > 1,
+ "overload-choice");
+
+ for (i = 0; i < n_chosen; i += 1)
+ {
+ syms[i] = syms[chosen[i]];
+ if (blocks != NULL)
+ blocks[i] = blocks[chosen[i]];
+ }
+
+ return n_chosen;
+}
+
+/* Read and validate a set of numeric choices from the user in the
+ range 0 .. N_CHOICES-1. Place the results in increasing
+ order in CHOICES[0 .. N-1], and return N.
+
+ The user types choices as a sequence of numbers on one line
+ separated by blanks, encoding them as follows:
+
+ + A choice of 0 means to cancel the selection, throwing an error.
+ + If IS_ALL_CHOICE, a choice of 1 selects the entire set 0 .. N_CHOICES-1.
+ + The user chooses k by typing k+IS_ALL_CHOICE+1.
+
+ The user is not allowed to choose more than MAX_RESULTS values.
+
+ ANNOTATION_SUFFIX, if present, is used to annotate the input
+ prompts (for use with the -f switch). */
+
+int
+get_selections (int *choices, int n_choices, int max_results,
+ int is_all_choice, char *annotation_suffix)
+{
+ int i;
+ char *args;
+ const char *prompt;
+ int n_chosen;
+ int first_choice = is_all_choice ? 2 : 1;
+
+ prompt = getenv ("PS2");
+ if (prompt == NULL)
+ prompt = ">";
+
+ printf_unfiltered ("%s ", prompt);
+ gdb_flush (gdb_stdout);
+
+ args = command_line_input ((char *) NULL, 0, annotation_suffix);
+
+ if (args == NULL)
+ error_no_arg ("one or more choice numbers");
+
+ n_chosen = 0;
+
+ /* Set choices[0 .. n_chosen-1] to the users' choices in ascending
+ order, as given in args. Choices are validated. */
+ while (1)
+ {
+ char *args2;
+ int choice, j;
+
+ while (isspace (*args))
+ args += 1;
+ if (*args == '\0' && n_chosen == 0)
+ error_no_arg ("one or more choice numbers");
+ else if (*args == '\0')
+ break;
+
+ choice = strtol (args, &args2, 10);
+ if (args == args2 || choice < 0
+ || choice > n_choices + first_choice - 1)
+ error ("Argument must be choice number");
+ args = args2;
+
+ if (choice == 0)
+ error ("cancelled");
+
+ if (choice < first_choice)
+ {
+ n_chosen = n_choices;
+ for (j = 0; j < n_choices; j += 1)
+ choices[j] = j;
+ break;
+ }
+ choice -= first_choice;
+
+ for (j = n_chosen - 1; j >= 0 && choice < choices[j]; j -= 1)
+ {
+ }
+
+ if (j < 0 || choice != choices[j])
+ {
+ int k;
+ for (k = n_chosen - 1; k > j; k -= 1)
+ choices[k + 1] = choices[k];
+ choices[j + 1] = choice;
+ n_chosen += 1;
+ }
+ }
+
+ if (n_chosen > max_results)
+ error ("Select no more than %d of the above", max_results);
+
+ return n_chosen;
+}
+
+/* Replace the operator of length OPLEN at position PC in *EXPP with a call */
+/* on the function identified by SYM and BLOCK, and taking NARGS */
+/* arguments. Update *EXPP as needed to hold more space. */
+
+static void
+replace_operator_with_call (struct expression **expp, int pc, int nargs,
+ int oplen, struct symbol *sym,
+ struct block *block)
+{
+ /* A new expression, with 6 more elements (3 for funcall, 4 for function
+ symbol, -oplen for operator being replaced). */
+ struct expression *newexp = (struct expression *)
+ xmalloc (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES ((*expp)->nelts + 7 - oplen));
+ struct expression *exp = *expp;
+
+ newexp->nelts = exp->nelts + 7 - oplen;
+ newexp->language_defn = exp->language_defn;
+ memcpy (newexp->elts, exp->elts, EXP_ELEM_TO_BYTES (pc));
+ memcpy (newexp->elts + pc + 7, exp->elts + pc + oplen,
+ EXP_ELEM_TO_BYTES (exp->nelts - pc - oplen));
+
+ newexp->elts[pc].opcode = newexp->elts[pc + 2].opcode = OP_FUNCALL;
+ newexp->elts[pc + 1].longconst = (LONGEST) nargs;
+
+ newexp->elts[pc + 3].opcode = newexp->elts[pc + 6].opcode = OP_VAR_VALUE;
+ newexp->elts[pc + 4].block = block;
+ newexp->elts[pc + 5].symbol = sym;
+
+ *expp = newexp;
+ xfree (exp);
+}
+
+/* Type-class predicates */
+
+/* True iff TYPE is numeric (i.e., an INT, RANGE (of numeric type), or */
+/* FLOAT.) */
+
+static int
+numeric_type_p (struct type *type)
+{
+ if (type == NULL)
+ return 0;
+ else
+ {
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ return 1;
+ case TYPE_CODE_RANGE:
+ return (type == TYPE_TARGET_TYPE (type)
+ || numeric_type_p (TYPE_TARGET_TYPE (type)));
+ default:
+ return 0;
+ }
+ }
+}
+
+/* True iff TYPE is integral (an INT or RANGE of INTs). */
+
+static int
+integer_type_p (struct type *type)
+{
+ if (type == NULL)
+ return 0;
+ else
+ {
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ return 1;
+ case TYPE_CODE_RANGE:
+ return (type == TYPE_TARGET_TYPE (type)
+ || integer_type_p (TYPE_TARGET_TYPE (type)));
+ default:
+ return 0;
+ }
+ }
+}
+
+/* True iff TYPE is scalar (INT, RANGE, FLOAT, ENUM). */
+
+static int
+scalar_type_p (struct type *type)
+{
+ if (type == NULL)
+ return 0;
+ else
+ {
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLT:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+}
+
+/* True iff TYPE is discrete (INT, RANGE, ENUM). */
+
+static int
+discrete_type_p (struct type *type)
+{
+ if (type == NULL)
+ return 0;
+ else
+ {
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_ENUM:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+}
+
+/* Returns non-zero if OP with operatands in the vector ARGS could be
+ a user-defined function. Errs on the side of pre-defined operators
+ (i.e., result 0). */
+
+static int
+possible_user_operator_p (enum exp_opcode op, struct value *args[])
+{
+ struct type *type0 = check_typedef (VALUE_TYPE (args[0]));
+ struct type *type1 =
+ (args[1] == NULL) ? NULL : check_typedef (VALUE_TYPE (args[1]));
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_MUL:
+ case BINOP_DIV:
+ return (!(numeric_type_p (type0) && numeric_type_p (type1)));
+
+ case BINOP_REM:
+ case BINOP_MOD:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+ return (!(integer_type_p (type0) && integer_type_p (type1)));
+
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+ return (!(scalar_type_p (type0) && scalar_type_p (type1)));
+
+ case BINOP_CONCAT:
+ return ((TYPE_CODE (type0) != TYPE_CODE_ARRAY &&
+ (TYPE_CODE (type0) != TYPE_CODE_PTR ||
+ TYPE_CODE (TYPE_TARGET_TYPE (type0))
+ != TYPE_CODE_ARRAY))
+ || (TYPE_CODE (type1) != TYPE_CODE_ARRAY &&
+ (TYPE_CODE (type1) != TYPE_CODE_PTR ||
+ TYPE_CODE (TYPE_TARGET_TYPE (type1)) != TYPE_CODE_ARRAY)));
+
+ case BINOP_EXP:
+ return (!(numeric_type_p (type0) && integer_type_p (type1)));
+
+ case UNOP_NEG:
+ case UNOP_PLUS:
+ case UNOP_LOGICAL_NOT:
+ case UNOP_ABS:
+ return (!numeric_type_p (type0));
+
+ }
+}
+
+ /* Renaming */
+
+/** NOTE: In the following, we assume that a renaming type's name may
+ * have an ___XD suffix. It would be nice if this went away at some
+ * point. */
+
+/* If TYPE encodes a renaming, returns the renaming suffix, which
+ * is XR for an object renaming, XRP for a procedure renaming, XRE for
+ * an exception renaming, and XRS for a subprogram renaming. Returns
+ * NULL if NAME encodes none of these. */
+const char *
+ada_renaming_type (struct type *type)
+{
+ if (type != NULL && TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ const char *name = type_name_no_tag (type);
+ const char *suffix = (name == NULL) ? NULL : strstr (name, "___XR");
+ if (suffix == NULL
+ || (suffix[5] != '\000' && strchr ("PES_", suffix[5]) == NULL))
+ return NULL;
+ else
+ return suffix + 3;
+ }
+ else
+ return NULL;
+}
+
+/* Return non-zero iff SYM encodes an object renaming. */
+int
+ada_is_object_renaming (struct symbol *sym)
+{
+ const char *renaming_type = ada_renaming_type (SYMBOL_TYPE (sym));
+ return renaming_type != NULL
+ && (renaming_type[2] == '\0' || renaming_type[2] == '_');
+}
+
+/* Assuming that SYM encodes a non-object renaming, returns the original
+ * name of the renamed entity. The name is good until the end of
+ * parsing. */
+const char *
+ada_simple_renamed_entity (struct symbol *sym)
+{
+ struct type *type;
+ const char *raw_name;
+ int len;
+ char *result;
+
+ type = SYMBOL_TYPE (sym);
+ if (type == NULL || TYPE_NFIELDS (type) < 1)
+ error ("Improperly encoded renaming.");
+
+ raw_name = TYPE_FIELD_NAME (type, 0);
+ len = (raw_name == NULL ? 0 : strlen (raw_name)) - 5;
+ if (len <= 0)
+ error ("Improperly encoded renaming.");
+
+ result = xmalloc (len + 1);
+ /* FIXME: add_name_string_cleanup should be defined in parse.c */
+ /* add_name_string_cleanup (result); */
+ strncpy (result, raw_name, len);
+ result[len] = '\000';
+ return result;
+}
+
+
+ /* Evaluation: Function Calls */
+
+/* Copy VAL onto the stack, using and updating *SP as the stack
+ pointer. Return VAL as an lvalue. */
+
+static struct value *
+place_on_stack (struct value *val, CORE_ADDR *sp)
+{
+ CORE_ADDR old_sp = *sp;
+
+#ifdef DEPRECATED_STACK_ALIGN
+ *sp = push_bytes (*sp, VALUE_CONTENTS_RAW (val),
+ DEPRECATED_STACK_ALIGN (TYPE_LENGTH
+ (check_typedef (VALUE_TYPE (val)))));
+#else
+ *sp = push_bytes (*sp, VALUE_CONTENTS_RAW (val),
+ TYPE_LENGTH (check_typedef (VALUE_TYPE (val))));
+#endif
+
+ VALUE_LVAL (val) = lval_memory;
+ if (INNER_THAN (1, 2))
+ VALUE_ADDRESS (val) = *sp;
+ else
+ VALUE_ADDRESS (val) = old_sp;
+
+ return val;
+}
+
+/* Return the value ACTUAL, converted to be an appropriate value for a
+ formal of type FORMAL_TYPE. Use *SP as a stack pointer for
+ allocating any necessary descriptors (fat pointers), or copies of
+ values not residing in memory, updating it as needed. */
+
+static struct value *
+convert_actual (struct value *actual, struct type *formal_type0,
+ CORE_ADDR *sp)
+{
+ struct type *actual_type = check_typedef (VALUE_TYPE (actual));
+ struct type *formal_type = check_typedef (formal_type0);
+ struct type *formal_target =
+ TYPE_CODE (formal_type) == TYPE_CODE_PTR
+ ? check_typedef (TYPE_TARGET_TYPE (formal_type)) : formal_type;
+ struct type *actual_target =
+ TYPE_CODE (actual_type) == TYPE_CODE_PTR
+ ? check_typedef (TYPE_TARGET_TYPE (actual_type)) : actual_type;
+
+ if (ada_is_array_descriptor (formal_target)
+ && TYPE_CODE (actual_target) == TYPE_CODE_ARRAY)
+ return make_array_descriptor (formal_type, actual, sp);
+ else if (TYPE_CODE (formal_type) == TYPE_CODE_PTR)
+ {
+ if (TYPE_CODE (formal_target) == TYPE_CODE_ARRAY
+ && ada_is_array_descriptor (actual_target))
+ return desc_data (actual);
+ else if (TYPE_CODE (actual_type) != TYPE_CODE_PTR)
+ {
+ if (VALUE_LVAL (actual) != lval_memory)
+ {
+ struct value *val;
+ actual_type = check_typedef (VALUE_TYPE (actual));
+ val = allocate_value (actual_type);
+ memcpy ((char *) VALUE_CONTENTS_RAW (val),
+ (char *) VALUE_CONTENTS (actual),
+ TYPE_LENGTH (actual_type));
+ actual = place_on_stack (val, sp);
+ }
+ return value_addr (actual);
+ }
+ }
+ else if (TYPE_CODE (actual_type) == TYPE_CODE_PTR)
+ return ada_value_ind (actual);
+
+ return actual;
+}
+
+
+/* Push a descriptor of type TYPE for array value ARR on the stack at
+ *SP, updating *SP to reflect the new descriptor. Return either
+ an lvalue representing the new descriptor, or (if TYPE is a pointer-
+ to-descriptor type rather than a descriptor type), a struct value*
+ representing a pointer to this descriptor. */
+
+static struct value *
+make_array_descriptor (struct type *type, struct value *arr, CORE_ADDR *sp)
+{
+ struct type *bounds_type = desc_bounds_type (type);
+ struct type *desc_type = desc_base_type (type);
+ struct value *descriptor = allocate_value (desc_type);
+ struct value *bounds = allocate_value (bounds_type);
+ CORE_ADDR bounds_addr;
+ int i;
+
+ for (i = ada_array_arity (check_typedef (VALUE_TYPE (arr))); i > 0; i -= 1)
+ {
+ modify_general_field (VALUE_CONTENTS (bounds),
+ value_as_long (ada_array_bound (arr, i, 0)),
+ desc_bound_bitpos (bounds_type, i, 0),
+ desc_bound_bitsize (bounds_type, i, 0));
+ modify_general_field (VALUE_CONTENTS (bounds),
+ value_as_long (ada_array_bound (arr, i, 1)),
+ desc_bound_bitpos (bounds_type, i, 1),
+ desc_bound_bitsize (bounds_type, i, 1));
+ }
+
+ bounds = place_on_stack (bounds, sp);
+
+ modify_general_field (VALUE_CONTENTS (descriptor),
+ arr,
+ fat_pntr_data_bitpos (desc_type),
+ fat_pntr_data_bitsize (desc_type));
+ modify_general_field (VALUE_CONTENTS (descriptor),
+ VALUE_ADDRESS (bounds),
+ fat_pntr_bounds_bitpos (desc_type),
+ fat_pntr_bounds_bitsize (desc_type));
+
+ descriptor = place_on_stack (descriptor, sp);
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ return value_addr (descriptor);
+ else
+ return descriptor;
+}
+
+
+/* Assuming a dummy frame has been established on the target, perform any
+ conversions needed for calling function FUNC on the NARGS actual
+ parameters in ARGS, other than standard C conversions. Does
+ nothing if FUNC does not have Ada-style prototype data, or if NARGS
+ does not match the number of arguments expected. Use *SP as a
+ stack pointer for additional data that must be pushed, updating its
+ value as needed. */
+
+void
+ada_convert_actuals (struct value *func, int nargs, struct value *args[],
+ CORE_ADDR *sp)
+{
+ int i;
+
+ if (TYPE_NFIELDS (VALUE_TYPE (func)) == 0
+ || nargs != TYPE_NFIELDS (VALUE_TYPE (func)))
+ return;
+
+ for (i = 0; i < nargs; i += 1)
+ args[i] =
+ convert_actual (args[i], TYPE_FIELD_TYPE (VALUE_TYPE (func), i), sp);
+}
+
+
+ /* Symbol Lookup */
+
+
+/* The vectors of symbols and blocks ultimately returned from */
+/* ada_lookup_symbol_list. */
+
+/* Current size of defn_symbols and defn_blocks */
+static size_t defn_vector_size = 0;
+
+/* Current number of symbols found. */
+static int ndefns = 0;
+
+static struct symbol **defn_symbols = NULL;
+static struct block **defn_blocks = NULL;
+
+/* Return the result of a standard (literal, C-like) lookup of NAME in
+ * given DOMAIN. */
+
+static struct symbol *
+standard_lookup (const char *name, domain_enum domain)
+{
+ struct symbol *sym;
+ sym = lookup_symbol (name, (struct block *) NULL, domain, 0, NULL);
+ return sym;
+}
+
+
+/* Non-zero iff there is at least one non-function/non-enumeral symbol */
+/* in SYMS[0..N-1]. We treat enumerals as functions, since they */
+/* contend in overloading in the same way. */
+static int
+is_nonfunction (struct symbol *syms[], int n)
+{
+ int i;
+
+ for (i = 0; i < n; i += 1)
+ if (TYPE_CODE (SYMBOL_TYPE (syms[i])) != TYPE_CODE_FUNC
+ && TYPE_CODE (SYMBOL_TYPE (syms[i])) != TYPE_CODE_ENUM)
+ return 1;
+
+ return 0;
+}
+
+/* If true (non-zero), then TYPE0 and TYPE1 represent equivalent
+ struct types. Otherwise, they may not. */
+
+static int
+equiv_types (struct type *type0, struct type *type1)
+{
+ if (type0 == type1)
+ return 1;
+ if (type0 == NULL || type1 == NULL
+ || TYPE_CODE (type0) != TYPE_CODE (type1))
+ return 0;
+ if ((TYPE_CODE (type0) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type0) == TYPE_CODE_ENUM)
+ && ada_type_name (type0) != NULL && ada_type_name (type1) != NULL
+ && DEPRECATED_STREQ (ada_type_name (type0), ada_type_name (type1)))
+ return 1;
+
+ return 0;
+}
+
+/* True iff SYM0 represents the same entity as SYM1, or one that is
+ no more defined than that of SYM1. */
+
+static int
+lesseq_defined_than (struct symbol *sym0, struct symbol *sym1)
+{
+ if (sym0 == sym1)
+ return 1;
+ if (SYMBOL_DOMAIN (sym0) != SYMBOL_DOMAIN (sym1)
+ || SYMBOL_CLASS (sym0) != SYMBOL_CLASS (sym1))
+ return 0;
+
+ switch (SYMBOL_CLASS (sym0))
+ {
+ case LOC_UNDEF:
+ return 1;
+ case LOC_TYPEDEF:
+ {
+ struct type *type0 = SYMBOL_TYPE (sym0);
+ struct type *type1 = SYMBOL_TYPE (sym1);
+ char *name0 = DEPRECATED_SYMBOL_NAME (sym0);
+ char *name1 = DEPRECATED_SYMBOL_NAME (sym1);
+ int len0 = strlen (name0);
+ return
+ TYPE_CODE (type0) == TYPE_CODE (type1)
+ && (equiv_types (type0, type1)
+ || (len0 < strlen (name1) && DEPRECATED_STREQN (name0, name1, len0)
+ && DEPRECATED_STREQN (name1 + len0, "___XV", 5)));
+ }
+ case LOC_CONST:
+ return SYMBOL_VALUE (sym0) == SYMBOL_VALUE (sym1)
+ && equiv_types (SYMBOL_TYPE (sym0), SYMBOL_TYPE (sym1));
+ default:
+ return 0;
+ }
+}
+
+/* Append SYM to the end of defn_symbols, and BLOCK to the end of
+ defn_blocks, updating ndefns, and expanding defn_symbols and
+ defn_blocks as needed. Do not include SYM if it is a duplicate. */
+
+static void
+add_defn_to_vec (struct symbol *sym, struct block *block)
+{
+ int i;
+ size_t tmp;
+
+ if (SYMBOL_TYPE (sym) != NULL)
+ CHECK_TYPEDEF (SYMBOL_TYPE (sym));
+ for (i = 0; i < ndefns; i += 1)
+ {
+ if (lesseq_defined_than (sym, defn_symbols[i]))
+ return;
+ else if (lesseq_defined_than (defn_symbols[i], sym))
+ {
+ defn_symbols[i] = sym;
+ defn_blocks[i] = block;
+ return;
+ }
+ }
+
+ tmp = defn_vector_size;
+ GROW_VECT (defn_symbols, tmp, ndefns + 2);
+ GROW_VECT (defn_blocks, defn_vector_size, ndefns + 2);
+
+ defn_symbols[ndefns] = sym;
+ defn_blocks[ndefns] = block;
+ ndefns += 1;
+}
+
+/* Look, in partial_symtab PST, for symbol NAME in given domain.
+ Check the global symbols if GLOBAL, the static symbols if not. Do
+ wild-card match if WILD. */
+
+static struct partial_symbol *
+ada_lookup_partial_symbol (struct partial_symtab *pst, const char *name,
+ int global, domain_enum domain, int wild)
+{
+ struct partial_symbol **start;
+ int name_len = strlen (name);
+ int length = (global ? pst->n_global_syms : pst->n_static_syms);
+ int i;
+
+ if (length == 0)
+ {
+ return (NULL);
+ }
+
+ start = (global ?
+ pst->objfile->global_psymbols.list + pst->globals_offset :
+ pst->objfile->static_psymbols.list + pst->statics_offset);
+
+ if (wild)
+ {
+ for (i = 0; i < length; i += 1)
+ {
+ struct partial_symbol *psym = start[i];
+
+ if (SYMBOL_DOMAIN (psym) == domain &&
+ wild_match (name, name_len, DEPRECATED_SYMBOL_NAME (psym)))
+ return psym;
+ }
+ return NULL;
+ }
+ else
+ {
+ if (global)
+ {
+ int U;
+ i = 0;
+ U = length - 1;
+ while (U - i > 4)
+ {
+ int M = (U + i) >> 1;
+ struct partial_symbol *psym = start[M];
+ if (DEPRECATED_SYMBOL_NAME (psym)[0] < name[0])
+ i = M + 1;
+ else if (DEPRECATED_SYMBOL_NAME (psym)[0] > name[0])
+ U = M - 1;
+ else if (strcmp (DEPRECATED_SYMBOL_NAME (psym), name) < 0)
+ i = M + 1;
+ else
+ U = M;
+ }
+ }
+ else
+ i = 0;
+
+ while (i < length)
+ {
+ struct partial_symbol *psym = start[i];
+
+ if (SYMBOL_DOMAIN (psym) == domain)
+ {
+ int cmp = strncmp (name, DEPRECATED_SYMBOL_NAME (psym), name_len);
+
+ if (cmp < 0)
+ {
+ if (global)
+ break;
+ }
+ else if (cmp == 0
+ && is_name_suffix (DEPRECATED_SYMBOL_NAME (psym) + name_len))
+ return psym;
+ }
+ i += 1;
+ }
+
+ if (global)
+ {
+ int U;
+ i = 0;
+ U = length - 1;
+ while (U - i > 4)
+ {
+ int M = (U + i) >> 1;
+ struct partial_symbol *psym = start[M];
+ if (DEPRECATED_SYMBOL_NAME (psym)[0] < '_')
+ i = M + 1;
+ else if (DEPRECATED_SYMBOL_NAME (psym)[0] > '_')
+ U = M - 1;
+ else if (strcmp (DEPRECATED_SYMBOL_NAME (psym), "_ada_") < 0)
+ i = M + 1;
+ else
+ U = M;
+ }
+ }
+ else
+ i = 0;
+
+ while (i < length)
+ {
+ struct partial_symbol *psym = start[i];
+
+ if (SYMBOL_DOMAIN (psym) == domain)
+ {
+ int cmp;
+
+ cmp = (int) '_' - (int) DEPRECATED_SYMBOL_NAME (psym)[0];
+ if (cmp == 0)
+ {
+ cmp = strncmp ("_ada_", DEPRECATED_SYMBOL_NAME (psym), 5);
+ if (cmp == 0)
+ cmp = strncmp (name, DEPRECATED_SYMBOL_NAME (psym) + 5, name_len);
+ }
+
+ if (cmp < 0)
+ {
+ if (global)
+ break;
+ }
+ else if (cmp == 0
+ && is_name_suffix (DEPRECATED_SYMBOL_NAME (psym) + name_len + 5))
+ return psym;
+ }
+ i += 1;
+ }
+
+ }
+ return NULL;
+}
+
+
+/* Find a symbol table containing symbol SYM or NULL if none. */
+static struct symtab *
+symtab_for_sym (struct symbol *sym)
+{
+ struct symtab *s;
+ struct objfile *objfile;
+ struct block *b;
+ struct symbol *tmp_sym;
+ struct dict_iterator iter;
+ int j;
+
+ ALL_SYMTABS (objfile, s)
+ {
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_STATIC:
+ case LOC_TYPEDEF:
+ case LOC_REGISTER:
+ case LOC_LABEL:
+ case LOC_BLOCK:
+ case LOC_CONST_BYTES:
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+ ALL_BLOCK_SYMBOLS (b, iter, tmp_sym) if (sym == tmp_sym)
+ return s;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ ALL_BLOCK_SYMBOLS (b, iter, tmp_sym) if (sym == tmp_sym)
+ return s;
+ break;
+ default:
+ break;
+ }
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ case LOC_TYPEDEF:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ for (j = FIRST_LOCAL_BLOCK;
+ j < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)); j += 1)
+ {
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), j);
+ ALL_BLOCK_SYMBOLS (b, iter, tmp_sym) if (sym == tmp_sym)
+ return s;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return NULL;
+}
+
+/* Return a minimal symbol matching NAME according to Ada demangling
+ rules. Returns NULL if there is no such minimal symbol. */
+
+struct minimal_symbol *
+ada_lookup_minimal_symbol (const char *name)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ int wild_match = (strstr (name, "__") == NULL);
+
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (ada_match_name (DEPRECATED_SYMBOL_NAME (msymbol), name, wild_match)
+ && MSYMBOL_TYPE (msymbol) != mst_solib_trampoline)
+ return msymbol;
+ }
+
+ return NULL;
+}
+
+/* For all subprograms that statically enclose the subprogram of the
+ * selected frame, add symbols matching identifier NAME in DOMAIN
+ * and their blocks to vectors *defn_symbols and *defn_blocks, as for
+ * ada_add_block_symbols (q.v.). If WILD, treat as NAME with a
+ * wildcard prefix. At the moment, this function uses a heuristic to
+ * find the frames of enclosing subprograms: it treats the
+ * pointer-sized value at location 0 from the local-variable base of a
+ * frame as a static link, and then searches up the call stack for a
+ * frame with that same local-variable base. */
+static void
+add_symbols_from_enclosing_procs (const char *name, domain_enum domain,
+ int wild_match)
+{
+#ifdef i386
+ static struct symbol static_link_sym;
+ static struct symbol *static_link;
+
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+ struct frame_info *frame;
+ struct frame_info *target_frame;
+
+ if (static_link == NULL)
+ {
+ /* Initialize the local variable symbol that stands for the
+ * static link (when it exists). */
+ static_link = &static_link_sym;
+ DEPRECATED_SYMBOL_NAME (static_link) = "";
+ SYMBOL_LANGUAGE (static_link) = language_unknown;
+ SYMBOL_CLASS (static_link) = LOC_LOCAL;
+ SYMBOL_DOMAIN (static_link) = VAR_DOMAIN;
+ SYMBOL_TYPE (static_link) = lookup_pointer_type (builtin_type_void);
+ SYMBOL_VALUE (static_link) =
+ -(long) TYPE_LENGTH (SYMBOL_TYPE (static_link));
+ }
+
+ frame = deprecated_selected_frame;
+ while (frame != NULL && ndefns == 0)
+ {
+ struct block *block;
+ struct value *target_link_val = read_var_value (static_link, frame);
+ CORE_ADDR target_link;
+
+ if (target_link_val == NULL)
+ break;
+ QUIT;
+
+ target_link = target_link_val;
+ do
+ {
+ QUIT;
+ frame = get_prev_frame (frame);
+ }
+ while (frame != NULL && DEPRECATED_FRAME_LOCALS_ADDRESS (frame) != target_link);
+
+ if (frame == NULL)
+ break;
+
+ block = get_frame_block (frame, 0);
+ while (block != NULL && block_function (block) != NULL && ndefns == 0)
+ {
+ ada_add_block_symbols (block, name, domain, NULL, wild_match);
+
+ block = BLOCK_SUPERBLOCK (block);
+ }
+ }
+
+ do_cleanups (old_chain);
+#endif
+}
+
+/* True if TYPE is definitely an artificial type supplied to a symbol
+ * for which no debugging information was given in the symbol file. */
+static int
+is_nondebugging_type (struct type *type)
+{
+ char *name = ada_type_name (type);
+ return (name != NULL && DEPRECATED_STREQ (name, "<variable, no debug info>"));
+}
+
+/* Remove any non-debugging symbols in SYMS[0 .. NSYMS-1] that definitely
+ * duplicate other symbols in the list. (The only case I know of where
+ * this happens is when object files containing stabs-in-ecoff are
+ * linked with files containing ordinary ecoff debugging symbols (or no
+ * debugging symbols)). Modifies SYMS to squeeze out deleted symbols,
+ * and applies the same modification to BLOCKS to maintain the
+ * correspondence between SYMS[i] and BLOCKS[i]. Returns the number
+ * of symbols in the modified list. */
+static int
+remove_extra_symbols (struct symbol **syms, struct block **blocks, int nsyms)
+{
+ int i, j;
+
+ i = 0;
+ while (i < nsyms)
+ {
+ if (DEPRECATED_SYMBOL_NAME (syms[i]) != NULL
+ && SYMBOL_CLASS (syms[i]) == LOC_STATIC
+ && is_nondebugging_type (SYMBOL_TYPE (syms[i])))
+ {
+ for (j = 0; j < nsyms; j += 1)
+ {
+ if (i != j
+ && DEPRECATED_SYMBOL_NAME (syms[j]) != NULL
+ && DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (syms[i]), DEPRECATED_SYMBOL_NAME (syms[j]))
+ && SYMBOL_CLASS (syms[i]) == SYMBOL_CLASS (syms[j])
+ && SYMBOL_VALUE_ADDRESS (syms[i])
+ == SYMBOL_VALUE_ADDRESS (syms[j]))
+ {
+ int k;
+ for (k = i + 1; k < nsyms; k += 1)
+ {
+ syms[k - 1] = syms[k];
+ blocks[k - 1] = blocks[k];
+ }
+ nsyms -= 1;
+ goto NextSymbol;
+ }
+ }
+ }
+ i += 1;
+ NextSymbol:
+ ;
+ }
+ return nsyms;
+}
+
+/* Find symbols in DOMAIN matching NAME, in BLOCK0 and enclosing
+ scope and in global scopes, returning the number of matches. Sets
+ *SYMS to point to a vector of matching symbols, with *BLOCKS
+ pointing to the vector of corresponding blocks in which those
+ symbols reside. These two vectors are transient---good only to the
+ next call of ada_lookup_symbol_list. Any non-function/non-enumeral symbol
+ match within the nest of blocks whose innermost member is BLOCK0,
+ is the outermost match returned (no other matches in that or
+ enclosing blocks is returned). If there are any matches in or
+ surrounding BLOCK0, then these alone are returned. */
+
+int
+ada_lookup_symbol_list (const char *name, struct block *block0,
+ domain_enum domain, struct symbol ***syms,
+ struct block ***blocks)
+{
+ struct symbol *sym;
+ struct symtab *s;
+ struct partial_symtab *ps;
+ struct blockvector *bv;
+ struct objfile *objfile;
+ struct block *b;
+ struct block *block;
+ struct minimal_symbol *msymbol;
+ int wild_match = (strstr (name, "__") == NULL);
+ int cacheIfUnique;
+
+#ifdef TIMING
+ markTimeStart (0);
+#endif
+
+ ndefns = 0;
+ cacheIfUnique = 0;
+
+ /* Search specified block and its superiors. */
+
+ block = block0;
+ while (block != NULL)
+ {
+ ada_add_block_symbols (block, name, domain, NULL, wild_match);
+
+ /* If we found a non-function match, assume that's the one. */
+ if (is_nonfunction (defn_symbols, ndefns))
+ goto done;
+
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* If we found ANY matches in the specified BLOCK, we're done. */
+
+ if (ndefns > 0)
+ goto done;
+
+ cacheIfUnique = 1;
+
+ /* Now add symbols from all global blocks: symbol tables, minimal symbol
+ tables, and psymtab's */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ QUIT;
+ if (!s->primary)
+ continue;
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ ada_add_block_symbols (block, name, domain, objfile, wild_match);
+ }
+
+ if (domain == VAR_DOMAIN)
+ {
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (ada_match_name (DEPRECATED_SYMBOL_NAME (msymbol), name, wild_match))
+ {
+ switch (MSYMBOL_TYPE (msymbol))
+ {
+ case mst_solib_trampoline:
+ break;
+ default:
+ s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol));
+ if (s != NULL)
+ {
+ int old_ndefns = ndefns;
+ QUIT;
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ ada_add_block_symbols (block,
+ DEPRECATED_SYMBOL_NAME (msymbol),
+ domain, objfile, wild_match);
+ if (ndefns == old_ndefns)
+ {
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ ada_add_block_symbols (block,
+ DEPRECATED_SYMBOL_NAME (msymbol),
+ domain, objfile,
+ wild_match);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ QUIT;
+ if (!ps->readin
+ && ada_lookup_partial_symbol (ps, name, 1, domain, wild_match))
+ {
+ s = PSYMTAB_TO_SYMTAB (ps);
+ if (!s->primary)
+ continue;
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ ada_add_block_symbols (block, name, domain, objfile, wild_match);
+ }
+ }
+
+ /* Now add symbols from all per-file blocks if we've gotten no hits.
+ (Not strictly correct, but perhaps better than an error).
+ Do the symtabs first, then check the psymtabs */
+
+ if (ndefns == 0)
+ {
+
+ ALL_SYMTABS (objfile, s)
+ {
+ QUIT;
+ if (!s->primary)
+ continue;
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ ada_add_block_symbols (block, name, domain, objfile, wild_match);
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ QUIT;
+ if (!ps->readin
+ && ada_lookup_partial_symbol (ps, name, 0, domain, wild_match))
+ {
+ s = PSYMTAB_TO_SYMTAB (ps);
+ bv = BLOCKVECTOR (s);
+ if (!s->primary)
+ continue;
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ ada_add_block_symbols (block, name, domain,
+ objfile, wild_match);
+ }
+ }
+ }
+
+ /* Finally, we try to find NAME as a local symbol in some lexically
+ enclosing block. We do this last, expecting this case to be
+ rare. */
+ if (ndefns == 0)
+ {
+ add_symbols_from_enclosing_procs (name, domain, wild_match);
+ if (ndefns > 0)
+ goto done;
+ }
+
+done:
+ ndefns = remove_extra_symbols (defn_symbols, defn_blocks, ndefns);
+
+
+ *syms = defn_symbols;
+ *blocks = defn_blocks;
+#ifdef TIMING
+ markTimeStop (0);
+#endif
+ return ndefns;
+}
+
+/* Return a symbol in DOMAIN matching NAME, in BLOCK0 and enclosing
+ * scope and in global scopes, or NULL if none. NAME is folded to
+ * lower case first, unless it is surrounded in single quotes.
+ * Otherwise, the result is as for ada_lookup_symbol_list, but is
+ * disambiguated by user query if needed. */
+
+struct symbol *
+ada_lookup_symbol (const char *name, struct block *block0,
+ domain_enum domain)
+{
+ struct symbol **candidate_syms;
+ struct block **candidate_blocks;
+ int n_candidates;
+
+ n_candidates = ada_lookup_symbol_list (name,
+ block0, domain,
+ &candidate_syms, &candidate_blocks);
+
+ if (n_candidates == 0)
+ return NULL;
+ else if (n_candidates != 1)
+ user_select_syms (candidate_syms, candidate_blocks, n_candidates, 1);
+
+ return candidate_syms[0];
+}
+
+
+/* True iff STR is a possible encoded suffix of a normal Ada name
+ * that is to be ignored for matching purposes. Suffixes of parallel
+ * names (e.g., XVE) are not included here. Currently, the possible suffixes
+ * are given by the regular expression:
+ * (X[nb]*)?(__[0-9]+|\$[0-9]+|___(LJM|X([FDBUP].*|R[^T]?)))?$
+ *
+ */
+static int
+is_name_suffix (const char *str)
+{
+ int k;
+ if (str[0] == 'X')
+ {
+ str += 1;
+ while (str[0] != '_' && str[0] != '\0')
+ {
+ if (str[0] != 'n' && str[0] != 'b')
+ return 0;
+ str += 1;
+ }
+ }
+ if (str[0] == '\000')
+ return 1;
+ if (str[0] == '_')
+ {
+ if (str[1] != '_' || str[2] == '\000')
+ return 0;
+ if (str[2] == '_')
+ {
+ if (DEPRECATED_STREQ (str + 3, "LJM"))
+ return 1;
+ if (str[3] != 'X')
+ return 0;
+ if (str[4] == 'F' || str[4] == 'D' || str[4] == 'B' ||
+ str[4] == 'U' || str[4] == 'P')
+ return 1;
+ if (str[4] == 'R' && str[5] != 'T')
+ return 1;
+ return 0;
+ }
+ for (k = 2; str[k] != '\0'; k += 1)
+ if (!isdigit (str[k]))
+ return 0;
+ return 1;
+ }
+ if (str[0] == '$' && str[1] != '\000')
+ {
+ for (k = 1; str[k] != '\0'; k += 1)
+ if (!isdigit (str[k]))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+/* True if NAME represents a name of the form A1.A2....An, n>=1 and
+ * PATN[0..PATN_LEN-1] = Ak.Ak+1.....An for some k >= 1. Ignores
+ * informational suffixes of NAME (i.e., for which is_name_suffix is
+ * true). */
+static int
+wild_match (const char *patn, int patn_len, const char *name)
+{
+ int name_len;
+ int s, e;
+
+ name_len = strlen (name);
+ if (name_len >= patn_len + 5 && DEPRECATED_STREQN (name, "_ada_", 5)
+ && DEPRECATED_STREQN (patn, name + 5, patn_len)
+ && is_name_suffix (name + patn_len + 5))
+ return 1;
+
+ while (name_len >= patn_len)
+ {
+ if (DEPRECATED_STREQN (patn, name, patn_len) && is_name_suffix (name + patn_len))
+ return 1;
+ do
+ {
+ name += 1;
+ name_len -= 1;
+ }
+ while (name_len > 0
+ && name[0] != '.' && (name[0] != '_' || name[1] != '_'));
+ if (name_len <= 0)
+ return 0;
+ if (name[0] == '_')
+ {
+ if (!islower (name[2]))
+ return 0;
+ name += 2;
+ name_len -= 2;
+ }
+ else
+ {
+ if (!islower (name[1]))
+ return 0;
+ name += 1;
+ name_len -= 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Add symbols from BLOCK matching identifier NAME in DOMAIN to
+ vector *defn_symbols, updating *defn_symbols (if necessary), *SZ (the size of
+ the vector *defn_symbols), and *ndefns (the number of symbols
+ currently stored in *defn_symbols). If WILD, treat as NAME with a
+ wildcard prefix. OBJFILE is the section containing BLOCK. */
+
+static void
+ada_add_block_symbols (struct block *block, const char *name,
+ domain_enum domain, struct objfile *objfile,
+ int wild)
+{
+ struct dict_iterator iter;
+ int name_len = strlen (name);
+ /* A matching argument symbol, if any. */
+ struct symbol *arg_sym;
+ /* Set true when we find a matching non-argument symbol */
+ int found_sym;
+ struct symbol *sym;
+
+ arg_sym = NULL;
+ found_sym = 0;
+ if (wild)
+ {
+ struct symbol *sym;
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ if (SYMBOL_DOMAIN (sym) == domain &&
+ wild_match (name, name_len, DEPRECATED_SYMBOL_NAME (sym)))
+ {
+ 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:
+ case LOC_COMPUTED_ARG:
+ arg_sym = sym;
+ break;
+ case LOC_UNRESOLVED:
+ continue;
+ default:
+ found_sym = 1;
+ fill_in_ada_prototype (sym);
+ add_defn_to_vec (fixup_symbol_section (sym, objfile), block);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ if (SYMBOL_DOMAIN (sym) == domain)
+ {
+ int cmp = strncmp (name, DEPRECATED_SYMBOL_NAME (sym), name_len);
+
+ if (cmp == 0
+ && is_name_suffix (DEPRECATED_SYMBOL_NAME (sym) + name_len))
+ {
+ 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:
+ case LOC_COMPUTED_ARG:
+ arg_sym = sym;
+ break;
+ case LOC_UNRESOLVED:
+ break;
+ default:
+ found_sym = 1;
+ fill_in_ada_prototype (sym);
+ add_defn_to_vec (fixup_symbol_section (sym, objfile),
+ block);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found_sym && arg_sym != NULL)
+ {
+ fill_in_ada_prototype (arg_sym);
+ add_defn_to_vec (fixup_symbol_section (arg_sym, objfile), block);
+ }
+
+ if (!wild)
+ {
+ arg_sym = NULL;
+ found_sym = 0;
+
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ if (SYMBOL_DOMAIN (sym) == domain)
+ {
+ int cmp;
+
+ cmp = (int) '_' - (int) DEPRECATED_SYMBOL_NAME (sym)[0];
+ if (cmp == 0)
+ {
+ cmp = strncmp ("_ada_", DEPRECATED_SYMBOL_NAME (sym), 5);
+ if (cmp == 0)
+ cmp = strncmp (name, DEPRECATED_SYMBOL_NAME (sym) + 5, name_len);
+ }
+
+ if (cmp == 0
+ && is_name_suffix (DEPRECATED_SYMBOL_NAME (sym) + name_len + 5))
+ {
+ 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:
+ case LOC_COMPUTED_ARG:
+ arg_sym = sym;
+ break;
+ case LOC_UNRESOLVED:
+ break;
+ default:
+ found_sym = 1;
+ fill_in_ada_prototype (sym);
+ add_defn_to_vec (fixup_symbol_section (sym, objfile),
+ block);
+ break;
+ }
+ }
+ }
+ }
+
+ /* NOTE: This really shouldn't be needed for _ada_ symbols.
+ They aren't parameters, right? */
+ if (!found_sym && arg_sym != NULL)
+ {
+ fill_in_ada_prototype (arg_sym);
+ add_defn_to_vec (fixup_symbol_section (arg_sym, objfile), block);
+ }
+ }
+}
+
+
+ /* Function Types */
+
+/* Assuming that SYM is the symbol for a function, fill in its type
+ with prototype information, if it is not already there. */
+
+static void
+fill_in_ada_prototype (struct symbol *func)
+{
+ struct block *b;
+ int nargs, nsyms;
+ struct dict_iterator iter;
+ struct type *ftype;
+ struct type *rtype;
+ size_t max_fields;
+ struct symbol *sym;
+
+ if (func == NULL
+ || TYPE_CODE (SYMBOL_TYPE (func)) != TYPE_CODE_FUNC
+ || TYPE_FIELDS (SYMBOL_TYPE (func)) != NULL)
+ return;
+
+ /* We make each function type unique, so that each may have its own */
+ /* parameter types. This particular way of doing so wastes space: */
+ /* it would be nicer to build the argument types while the original */
+ /* function type is being built (FIXME). */
+ rtype = check_typedef (TYPE_TARGET_TYPE (SYMBOL_TYPE (func)));
+ ftype = alloc_type (TYPE_OBJFILE (SYMBOL_TYPE (func)));
+ make_function_type (rtype, &ftype);
+ SYMBOL_TYPE (func) = ftype;
+
+ b = SYMBOL_BLOCK_VALUE (func);
+
+ nargs = 0;
+ max_fields = 8;
+ TYPE_FIELDS (ftype) =
+ (struct field *) xmalloc (sizeof (struct field) * max_fields);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ GROW_VECT (TYPE_FIELDS (ftype), max_fields, nargs + 1);
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_REF_ARG:
+ case LOC_REGPARM_ADDR:
+ TYPE_FIELD_BITPOS (ftype, nargs) = nargs;
+ TYPE_FIELD_BITSIZE (ftype, nargs) = 0;
+ TYPE_FIELD_STATIC_KIND (ftype, nargs) = 0;
+ TYPE_FIELD_TYPE (ftype, nargs) =
+ lookup_pointer_type (check_typedef (SYMBOL_TYPE (sym)));
+ TYPE_FIELD_NAME (ftype, nargs) = DEPRECATED_SYMBOL_NAME (sym);
+ nargs += 1;
+
+ break;
+
+ case LOC_ARG:
+ case LOC_REGPARM:
+ case LOC_LOCAL_ARG:
+ case LOC_BASEREG_ARG:
+ case LOC_COMPUTED_ARG:
+ TYPE_FIELD_BITPOS (ftype, nargs) = nargs;
+ TYPE_FIELD_BITSIZE (ftype, nargs) = 0;
+ TYPE_FIELD_STATIC_KIND (ftype, nargs) = 0;
+ TYPE_FIELD_TYPE (ftype, nargs) = check_typedef (SYMBOL_TYPE (sym));
+ TYPE_FIELD_NAME (ftype, nargs) = DEPRECATED_SYMBOL_NAME (sym);
+ nargs += 1;
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Re-allocate fields vector; if there are no fields, make the */
+ /* fields pointer non-null anyway, to mark that this function type */
+ /* has been filled in. */
+
+ TYPE_NFIELDS (ftype) = nargs;
+ if (nargs == 0)
+ {
+ static struct field dummy_field = { 0, 0, 0, 0 };
+ xfree (TYPE_FIELDS (ftype));
+ TYPE_FIELDS (ftype) = &dummy_field;
+ }
+ else
+ {
+ struct field *fields =
+ (struct field *) TYPE_ALLOC (ftype, nargs * sizeof (struct field));
+ memcpy ((char *) fields,
+ (char *) TYPE_FIELDS (ftype), nargs * sizeof (struct field));
+ xfree (TYPE_FIELDS (ftype));
+ TYPE_FIELDS (ftype) = fields;
+ }
+}
+
+
+ /* Breakpoint-related */
+
+char no_symtab_msg[] =
+ "No symbol table is loaded. Use the \"file\" command.";
+
+/* Assuming that LINE is pointing at the beginning of an argument to
+ 'break', return a pointer to the delimiter for the initial segment
+ of that name. This is the first ':', ' ', or end of LINE.
+*/
+char *
+ada_start_decode_line_1 (char *line)
+{
+ /* [NOTE: strpbrk would be more elegant, but I am reluctant to be
+ the first to use such a library function in GDB code.] */
+ char *p;
+ for (p = line; *p != '\000' && *p != ' ' && *p != ':'; p += 1)
+ ;
+ return p;
+}
+
+/* *SPEC points to a function and line number spec (as in a break
+ command), following any initial file name specification.
+
+ Return all symbol table/line specfications (sals) consistent with the
+ information in *SPEC and FILE_TABLE in the
+ following sense:
+ + FILE_TABLE is null, or the sal refers to a line in the file
+ named by FILE_TABLE.
+ + If *SPEC points to an argument with a trailing ':LINENUM',
+ then the sal refers to that line (or one following it as closely as
+ possible).
+ + If *SPEC does not start with '*', the sal is in a function with
+ that name.
+
+ Returns with 0 elements if no matching non-minimal symbols found.
+
+ If *SPEC begins with a function name of the form <NAME>, then NAME
+ is taken as a literal name; otherwise the function name is subject
+ to the usual mangling.
+
+ *SPEC is updated to point after the function/line number specification.
+
+ FUNFIRSTLINE is non-zero if we desire the first line of real code
+ in each function (this is ignored in the presence of a LINENUM spec.).
+
+ If CANONICAL is non-NULL, and if any of the sals require a
+ 'canonical line spec', then *CANONICAL is set to point to an array
+ of strings, corresponding to and equal in length to the returned
+ list of sals, such that (*CANONICAL)[i] is non-null and contains a
+ canonical line spec for the ith returned sal, if needed. If no
+ canonical line specs are required and CANONICAL is non-null,
+ *CANONICAL is set to NULL.
+
+ A 'canonical line spec' is simply a name (in the format of the
+ breakpoint command) that uniquely identifies a breakpoint position,
+ with no further contextual information or user selection. It is
+ needed whenever the file name, function name, and line number
+ information supplied is insufficient for this unique
+ identification. Currently overloaded functions, the name '*',
+ 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 caller's responsibility to free them. */
+
+struct symtabs_and_lines
+ada_finish_decode_line_1 (char **spec, struct symtab *file_table,
+ int funfirstline, char ***canonical)
+{
+ struct symbol **symbols;
+ struct block **blocks;
+ struct block *block;
+ int n_matches, i, line_num;
+ struct symtabs_and_lines selected;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+ char *name;
+
+ int len;
+ char *lower_name;
+ char *unquoted_name;
+
+ if (file_table == NULL)
+ block = get_selected_block (NULL);
+ else
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_table), STATIC_BLOCK);
+
+ if (canonical != NULL)
+ *canonical = (char **) NULL;
+
+ name = *spec;
+ if (**spec == '*')
+ *spec += 1;
+ else
+ {
+ while (**spec != '\000' &&
+ !strchr (ada_completer_word_break_characters, **spec))
+ *spec += 1;
+ }
+ len = *spec - name;
+
+ line_num = -1;
+ if (file_table != NULL && (*spec)[0] == ':' && isdigit ((*spec)[1]))
+ {
+ line_num = strtol (*spec + 1, spec, 10);
+ while (**spec == ' ' || **spec == '\t')
+ *spec += 1;
+ }
+
+ if (name[0] == '*')
+ {
+ if (line_num == -1)
+ error ("Wild-card function with no line number or file name.");
+
+ return all_sals_for_line (file_table->filename, line_num, canonical);
+ }
+
+ if (name[0] == '\'')
+ {
+ name += 1;
+ len -= 2;
+ }
+
+ if (name[0] == '<')
+ {
+ unquoted_name = (char *) alloca (len - 1);
+ memcpy (unquoted_name, name + 1, len - 2);
+ unquoted_name[len - 2] = '\000';
+ lower_name = NULL;
+ }
+ else
+ {
+ unquoted_name = (char *) alloca (len + 1);
+ memcpy (unquoted_name, name, len);
+ unquoted_name[len] = '\000';
+ lower_name = (char *) alloca (len + 1);
+ for (i = 0; i < len; i += 1)
+ lower_name[i] = tolower (name[i]);
+ lower_name[len] = '\000';
+ }
+
+ n_matches = 0;
+ if (lower_name != NULL)
+ n_matches = ada_lookup_symbol_list (ada_mangle (lower_name), block,
+ VAR_DOMAIN, &symbols, &blocks);
+ if (n_matches == 0)
+ n_matches = ada_lookup_symbol_list (unquoted_name, block,
+ VAR_DOMAIN, &symbols, &blocks);
+ if (n_matches == 0 && line_num >= 0)
+ error ("No line number information found for %s.", unquoted_name);
+ else if (n_matches == 0)
+ {
+#ifdef HPPA_COMPILER_BUG
+ /* FIXME: See comment in symtab.c::decode_line_1 */
+#undef volatile
+ volatile struct symtab_and_line val;
+#define volatile /*nothing */
+#else
+ struct symtab_and_line val;
+#endif
+ struct minimal_symbol *msymbol;
+
+ init_sal (&val);
+
+ msymbol = NULL;
+ if (lower_name != NULL)
+ msymbol = ada_lookup_minimal_symbol (ada_mangle (lower_name));
+ if (msymbol == NULL)
+ msymbol = ada_lookup_minimal_symbol (unquoted_name);
+ if (msymbol != NULL)
+ {
+ val.pc = SYMBOL_VALUE_ADDRESS (msymbol);
+ val.section = SYMBOL_BFD_SECTION (msymbol);
+ if (funfirstline)
+ {
+ val.pc += FUNCTION_START_OFFSET;
+ SKIP_PROLOGUE (val.pc);
+ }
+ selected.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ selected.sals[0] = val;
+ selected.nelts = 1;
+ return selected;
+ }
+
+ if (!have_full_symbols () &&
+ !have_partial_symbols () && !have_minimal_symbols ())
+ error (no_symtab_msg);
+
+ error ("Function \"%s\" not defined.", unquoted_name);
+ return selected; /* for lint */
+ }
+
+ if (line_num >= 0)
+ {
+ return
+ find_sal_from_funcs_and_line (file_table->filename, line_num,
+ symbols, n_matches);
+ }
+ else
+ {
+ selected.nelts =
+ user_select_syms (symbols, blocks, n_matches, n_matches);
+ }
+
+ selected.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line) * selected.nelts);
+ memset (selected.sals, 0, selected.nelts * sizeof (selected.sals[i]));
+ make_cleanup (xfree, selected.sals);
+
+ i = 0;
+ while (i < selected.nelts)
+ {
+ if (SYMBOL_CLASS (symbols[i]) == LOC_BLOCK)
+ selected.sals[i] = find_function_start_sal (symbols[i], funfirstline);
+ else if (SYMBOL_LINE (symbols[i]) != 0)
+ {
+ selected.sals[i].symtab = symtab_for_sym (symbols[i]);
+ selected.sals[i].line = SYMBOL_LINE (symbols[i]);
+ }
+ else if (line_num >= 0)
+ {
+ /* Ignore this choice */
+ symbols[i] = symbols[selected.nelts - 1];
+ blocks[i] = blocks[selected.nelts - 1];
+ selected.nelts -= 1;
+ continue;
+ }
+ else
+ error ("Line number not known for symbol \"%s\"", unquoted_name);
+ i += 1;
+ }
+
+ if (canonical != NULL && (line_num >= 0 || n_matches > 1))
+ {
+ *canonical = (char **) xmalloc (sizeof (char *) * selected.nelts);
+ for (i = 0; i < selected.nelts; i += 1)
+ (*canonical)[i] =
+ extended_canonical_line_spec (selected.sals[i],
+ SYMBOL_PRINT_NAME (symbols[i]));
+ }
+
+ discard_cleanups (old_chain);
+ return selected;
+}
+
+/* The (single) sal corresponding to line LINE_NUM in a symbol table
+ with file name FILENAME that occurs in one of the functions listed
+ in SYMBOLS[0 .. NSYMS-1]. */
+static struct symtabs_and_lines
+find_sal_from_funcs_and_line (const char *filename, int line_num,
+ struct symbol **symbols, int nsyms)
+{
+ struct symtabs_and_lines sals;
+ int best_index, best;
+ struct linetable *best_linetable;
+ struct objfile *objfile;
+ struct symtab *s;
+ struct symtab *best_symtab;
+
+ read_all_symtabs (filename);
+
+ best_index = 0;
+ best_linetable = NULL;
+ best_symtab = NULL;
+ best = 0;
+ ALL_SYMTABS (objfile, s)
+ {
+ struct linetable *l;
+ int ind, exact;
+
+ QUIT;
+
+ if (!DEPRECATED_STREQ (filename, s->filename))
+ continue;
+ l = LINETABLE (s);
+ ind = find_line_in_linetable (l, line_num, symbols, nsyms, &exact);
+ if (ind >= 0)
+ {
+ if (exact)
+ {
+ best_index = ind;
+ best_linetable = l;
+ best_symtab = s;
+ goto done;
+ }
+ if (best == 0 || l->item[ind].line < best)
+ {
+ best = l->item[ind].line;
+ best_index = ind;
+ best_linetable = l;
+ best_symtab = s;
+ }
+ }
+ }
+
+ if (best == 0)
+ error ("Line number not found in designated function.");
+
+done:
+
+ sals.nelts = 1;
+ sals.sals = (struct symtab_and_line *) xmalloc (sizeof (sals.sals[0]));
+
+ init_sal (&sals.sals[0]);
+
+ sals.sals[0].line = best_linetable->item[best_index].line;
+ sals.sals[0].pc = best_linetable->item[best_index].pc;
+ sals.sals[0].symtab = best_symtab;
+
+ return sals;
+}
+
+/* Return the index in LINETABLE of the best match for LINE_NUM whose
+ pc falls within one of the functions denoted by SYMBOLS[0..NSYMS-1].
+ Set *EXACTP to the 1 if the match is exact, and 0 otherwise. */
+static int
+find_line_in_linetable (struct linetable *linetable, int line_num,
+ struct symbol **symbols, int nsyms, int *exactp)
+{
+ int i, len, best_index, best;
+
+ if (line_num <= 0 || linetable == NULL)
+ return -1;
+
+ len = linetable->nitems;
+ for (i = 0, best_index = -1, best = 0; i < len; i += 1)
+ {
+ int k;
+ struct linetable_entry *item = &(linetable->item[i]);
+
+ for (k = 0; k < nsyms; k += 1)
+ {
+ if (symbols[k] != NULL && SYMBOL_CLASS (symbols[k]) == LOC_BLOCK
+ && item->pc >= BLOCK_START (SYMBOL_BLOCK_VALUE (symbols[k]))
+ && item->pc < BLOCK_END (SYMBOL_BLOCK_VALUE (symbols[k])))
+ goto candidate;
+ }
+ continue;
+
+ candidate:
+
+ if (item->line == line_num)
+ {
+ *exactp = 1;
+ return i;
+ }
+
+ if (item->line > line_num && (best == 0 || item->line < best))
+ {
+ best = item->line;
+ best_index = i;
+ }
+ }
+
+ *exactp = 0;
+ return best_index;
+}
+
+/* Find the smallest k >= LINE_NUM such that k is a line number in
+ LINETABLE, and k falls strictly within a named function that begins at
+ or before LINE_NUM. Return -1 if there is no such k. */
+static int
+nearest_line_number_in_linetable (struct linetable *linetable, int line_num)
+{
+ int i, len, best;
+
+ if (line_num <= 0 || linetable == NULL || linetable->nitems == 0)
+ return -1;
+ len = linetable->nitems;
+
+ i = 0;
+ best = INT_MAX;
+ while (i < len)
+ {
+ int k;
+ struct linetable_entry *item = &(linetable->item[i]);
+
+ if (item->line >= line_num && item->line < best)
+ {
+ char *func_name;
+ CORE_ADDR start, end;
+
+ func_name = NULL;
+ find_pc_partial_function (item->pc, &func_name, &start, &end);
+
+ if (func_name != NULL && item->pc < end)
+ {
+ if (item->line == line_num)
+ return line_num;
+ else
+ {
+ struct symbol *sym =
+ standard_lookup (func_name, VAR_DOMAIN);
+ if (is_plausible_func_for_line (sym, line_num))
+ best = item->line;
+ else
+ {
+ do
+ i += 1;
+ while (i < len && linetable->item[i].pc < end);
+ continue;
+ }
+ }
+ }
+ }
+
+ i += 1;
+ }
+
+ return (best == INT_MAX) ? -1 : best;
+}
+
+
+/* Return the next higher index, k, into LINETABLE such that k > IND,
+ entry k in LINETABLE has a line number equal to LINE_NUM, k
+ corresponds to a PC that is in a function different from that
+ corresponding to IND, and falls strictly within a named function
+ that begins at a line at or preceding STARTING_LINE.
+ Return -1 if there is no such k.
+ IND == -1 corresponds to no function. */
+
+static int
+find_next_line_in_linetable (struct linetable *linetable, int line_num,
+ int starting_line, int ind)
+{
+ int i, len;
+
+ if (line_num <= 0 || linetable == NULL || ind >= linetable->nitems)
+ return -1;
+ len = linetable->nitems;
+
+ if (ind >= 0)
+ {
+ CORE_ADDR start, end;
+
+ if (find_pc_partial_function (linetable->item[ind].pc,
+ (char **) NULL, &start, &end))
+ {
+ while (ind < len && linetable->item[ind].pc < end)
+ ind += 1;
+ }
+ else
+ ind += 1;
+ }
+ else
+ ind = 0;
+
+ i = ind;
+ while (i < len)
+ {
+ int k;
+ struct linetable_entry *item = &(linetable->item[i]);
+
+ if (item->line >= line_num)
+ {
+ char *func_name;
+ CORE_ADDR start, end;
+
+ func_name = NULL;
+ find_pc_partial_function (item->pc, &func_name, &start, &end);
+
+ if (func_name != NULL && item->pc < end)
+ {
+ if (item->line == line_num)
+ {
+ struct symbol *sym =
+ standard_lookup (func_name, VAR_DOMAIN);
+ if (is_plausible_func_for_line (sym, starting_line))
+ return i;
+ else
+ {
+ while ((i + 1) < len && linetable->item[i + 1].pc < end)
+ i += 1;
+ }
+ }
+ }
+ }
+ i += 1;
+ }
+
+ return -1;
+}
+
+/* True iff function symbol SYM starts somewhere at or before line #
+ LINE_NUM. */
+static int
+is_plausible_func_for_line (struct symbol *sym, int line_num)
+{
+ struct symtab_and_line start_sal;
+
+ if (sym == NULL)
+ return 0;
+
+ start_sal = find_function_start_sal (sym, 0);
+
+ return (start_sal.line != 0 && line_num >= start_sal.line);
+}
+
+static void
+debug_print_lines (struct linetable *lt)
+{
+ int i;
+
+ if (lt == NULL)
+ return;
+
+ fprintf (stderr, "\t");
+ for (i = 0; i < lt->nitems; i += 1)
+ fprintf (stderr, "(%d->%p) ", lt->item[i].line, (void *) lt->item[i].pc);
+ fprintf (stderr, "\n");
+}
+
+static void
+debug_print_block (struct block *b)
+{
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ fprintf (stderr, "Block: %p; [0x%lx, 0x%lx]",
+ b, BLOCK_START (b), BLOCK_END (b));
+ if (BLOCK_FUNCTION (b) != NULL)
+ fprintf (stderr, " Function: %s", DEPRECATED_SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ fprintf (stderr, "\n");
+ fprintf (stderr, "\t Superblock: %p\n", BLOCK_SUPERBLOCK (b));
+ fprintf (stderr, "\t Symbols:");
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ fprintf (stderr, " %s", DEPRECATED_SYMBOL_NAME (sym));
+ }
+ fprintf (stderr, "\n");
+}
+
+static void
+debug_print_blocks (struct blockvector *bv)
+{
+ int i;
+
+ if (bv == NULL)
+ return;
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i += 1)
+ {
+ fprintf (stderr, "%6d. ", i);
+ debug_print_block (BLOCKVECTOR_BLOCK (bv, i));
+ }
+}
+
+static void
+debug_print_symtab (struct symtab *s)
+{
+ fprintf (stderr, "Symtab %p\n File: %s; Dir: %s\n", s,
+ s->filename, s->dirname);
+ fprintf (stderr, " Blockvector: %p, Primary: %d\n",
+ BLOCKVECTOR (s), s->primary);
+ debug_print_blocks (BLOCKVECTOR (s));
+ fprintf (stderr, " Line table: %p\n", LINETABLE (s));
+ debug_print_lines (LINETABLE (s));
+}
+
+/* Read in all symbol tables corresponding to partial symbol tables
+ with file name FILENAME. */
+static void
+read_all_symtabs (const char *filename)
+{
+ struct partial_symtab *ps;
+ struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ QUIT;
+
+ if (DEPRECATED_STREQ (filename, ps->filename))
+ PSYMTAB_TO_SYMTAB (ps);
+ }
+}
+
+/* All sals corresponding to line LINE_NUM in a symbol table from file
+ FILENAME, as filtered by the user. If CANONICAL is not null, set
+ it to a corresponding array of canonical line specs. */
+static struct symtabs_and_lines
+all_sals_for_line (const char *filename, int line_num, char ***canonical)
+{
+ struct symtabs_and_lines result;
+ struct objfile *objfile;
+ struct symtab *s;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+ size_t len;
+
+ read_all_symtabs (filename);
+
+ result.sals =
+ (struct symtab_and_line *) xmalloc (4 * sizeof (result.sals[0]));
+ result.nelts = 0;
+ len = 4;
+ make_cleanup (free_current_contents, &result.sals);
+
+ ALL_SYMTABS (objfile, s)
+ {
+ int ind, target_line_num;
+
+ QUIT;
+
+ if (!DEPRECATED_STREQ (s->filename, filename))
+ continue;
+
+ target_line_num =
+ nearest_line_number_in_linetable (LINETABLE (s), line_num);
+ if (target_line_num == -1)
+ continue;
+
+ ind = -1;
+ while (1)
+ {
+ ind =
+ find_next_line_in_linetable (LINETABLE (s),
+ target_line_num, line_num, ind);
+
+ if (ind < 0)
+ break;
+
+ GROW_VECT (result.sals, len, result.nelts + 1);
+ init_sal (&result.sals[result.nelts]);
+ result.sals[result.nelts].line = LINETABLE (s)->item[ind].line;
+ result.sals[result.nelts].pc = LINETABLE (s)->item[ind].pc;
+ result.sals[result.nelts].symtab = s;
+ result.nelts += 1;
+ }
+ }
+
+ if (canonical != NULL || result.nelts > 1)
+ {
+ int k;
+ char **func_names = (char **) alloca (result.nelts * sizeof (char *));
+ int first_choice = (result.nelts > 1) ? 2 : 1;
+ int n;
+ int *choices = (int *) alloca (result.nelts * sizeof (int));
+
+ for (k = 0; k < result.nelts; k += 1)
+ {
+ find_pc_partial_function (result.sals[k].pc, &func_names[k],
+ (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
+ if (func_names[k] == NULL)
+ error ("Could not find function for one or more breakpoints.");
+ }
+
+ if (result.nelts > 1)
+ {
+ printf_unfiltered ("[0] cancel\n");
+ if (result.nelts > 1)
+ printf_unfiltered ("[1] all\n");
+ for (k = 0; k < result.nelts; k += 1)
+ printf_unfiltered ("[%d] %s\n", k + first_choice,
+ ada_demangle (func_names[k]));
+
+ n = get_selections (choices, result.nelts, result.nelts,
+ result.nelts > 1, "instance-choice");
+
+ for (k = 0; k < n; k += 1)
+ {
+ result.sals[k] = result.sals[choices[k]];
+ func_names[k] = func_names[choices[k]];
+ }
+ result.nelts = n;
+ }
+
+ if (canonical != NULL)
+ {
+ *canonical = (char **) xmalloc (result.nelts * sizeof (char **));
+ make_cleanup (xfree, *canonical);
+ for (k = 0; k < result.nelts; k += 1)
+ {
+ (*canonical)[k] =
+ extended_canonical_line_spec (result.sals[k], func_names[k]);
+ if ((*canonical)[k] == NULL)
+ error ("Could not locate one or more breakpoints.");
+ make_cleanup (xfree, (*canonical)[k]);
+ }
+ }
+ }
+
+ discard_cleanups (old_chain);
+ return result;
+}
+
+
+/* A canonical line specification of the form FILE:NAME:LINENUM for
+ symbol table and line data SAL. NULL if insufficient
+ information. The caller is responsible for releasing any space
+ allocated. */
+
+static char *
+extended_canonical_line_spec (struct symtab_and_line sal, const char *name)
+{
+ char *r;
+
+ if (sal.symtab == NULL || sal.symtab->filename == NULL || sal.line <= 0)
+ return NULL;
+
+ r = (char *) xmalloc (strlen (name) + strlen (sal.symtab->filename)
+ + sizeof (sal.line) * 3 + 3);
+ sprintf (r, "%s:'%s':%d", sal.symtab->filename, name, sal.line);
+ return r;
+}
+
+#if 0
+int begin_bnum = -1;
+#endif
+int begin_annotate_level = 0;
+
+static void
+begin_cleanup (void *dummy)
+{
+ begin_annotate_level = 0;
+}
+
+static void
+begin_command (char *args, int from_tty)
+{
+ struct minimal_symbol *msym;
+ CORE_ADDR main_program_name_addr;
+ char main_program_name[1024];
+ struct cleanup *old_chain = make_cleanup (begin_cleanup, NULL);
+ begin_annotate_level = 2;
+
+ /* Check that there is a program to debug */
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+
+ /* Check that we are debugging an Ada program */
+ /* if (ada_update_initial_language (language_unknown, NULL) != language_ada)
+ error ("Cannot find the Ada initialization procedure. Is this an Ada main program?");
+ */
+ /* FIXME: language_ada should be defined in defs.h */
+
+ /* Get the address of the name of the main procedure */
+ msym = lookup_minimal_symbol (ADA_MAIN_PROGRAM_SYMBOL_NAME, NULL, NULL);
+
+ if (msym != NULL)
+ {
+ main_program_name_addr = SYMBOL_VALUE_ADDRESS (msym);
+ if (main_program_name_addr == 0)
+ error ("Invalid address for Ada main program name.");
+
+ /* Read the name of the main procedure */
+ extract_string (main_program_name_addr, main_program_name);
+
+ /* Put a temporary breakpoint in the Ada main program and run */
+ do_command ("tbreak ", main_program_name, 0);
+ do_command ("run ", args, 0);
+ }
+ else
+ {
+ /* If we could not find the symbol containing the name of the
+ main program, that means that the compiler that was used to build
+ was not recent enough. In that case, we fallback to the previous
+ mechanism, which is a little bit less reliable, but has proved to work
+ in most cases. The only cases where it will fail is when the user
+ has set some breakpoints which will be hit before the end of the
+ begin command processing (eg in the initialization code).
+
+ The begining of the main Ada subprogram is located by breaking
+ on the adainit procedure. Since we know that the binder generates
+ the call to this procedure exactly 2 calls before the call to the
+ Ada main subprogram, it is then easy to put a breakpoint on this
+ Ada main subprogram once we hit adainit.
+ */
+ do_command ("tbreak adainit", 0);
+ do_command ("run ", args, 0);
+ do_command ("up", 0);
+ do_command ("tbreak +2", 0);
+ do_command ("continue", 0);
+ do_command ("step", 0);
+ }
+
+ do_cleanups (old_chain);
+}
+
+int
+is_ada_runtime_file (char *filename)
+{
+ return (DEPRECATED_STREQN (filename, "s-", 2) ||
+ DEPRECATED_STREQN (filename, "a-", 2) ||
+ DEPRECATED_STREQN (filename, "g-", 2) || DEPRECATED_STREQN (filename, "i-", 2));
+}
+
+/* find the first frame that contains debugging information and that is not
+ part of the Ada run-time, starting from fi and moving upward. */
+
+int
+find_printable_frame (struct frame_info *fi, int level)
+{
+ struct symtab_and_line sal;
+
+ for (; fi != NULL; level += 1, fi = get_prev_frame (fi))
+ {
+ find_frame_sal (fi, &sal);
+ if (sal.symtab && !is_ada_runtime_file (sal.symtab->filename))
+ {
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+ /* libpthread.so contains some debugging information that prevents us
+ from finding the right frame */
+
+ if (sal.symtab->objfile &&
+ DEPRECATED_STREQ (sal.symtab->objfile->name, "/usr/shlib/libpthread.so"))
+ continue;
+#endif
+ deprecated_selected_frame = fi;
+ break;
+ }
+ }
+
+ return level;
+}
+
+void
+ada_report_exception_break (struct breakpoint *b)
+{
+ /* FIXME: break_on_exception should be defined in breakpoint.h */
+ /* if (b->break_on_exception == 1)
+ {
+ /* Assume that cond has 16 elements, the 15th
+ being the exception *//*
+ if (b->cond && b->cond->nelts == 16)
+ {
+ ui_out_text (uiout, "on ");
+ ui_out_field_string (uiout, "exception",
+ SYMBOL_NAME (b->cond->elts[14].symbol));
+ }
+ else
+ ui_out_text (uiout, "on all exceptions");
+ }
+ else if (b->break_on_exception == 2)
+ ui_out_text (uiout, "on unhandled exception");
+ else if (b->break_on_exception == 3)
+ ui_out_text (uiout, "on assert failure");
+ #else
+ if (b->break_on_exception == 1)
+ { */
+ /* Assume that cond has 16 elements, the 15th
+ being the exception *//*
+ if (b->cond && b->cond->nelts == 16)
+ {
+ fputs_filtered ("on ", gdb_stdout);
+ fputs_filtered (SYMBOL_NAME
+ (b->cond->elts[14].symbol), gdb_stdout);
+ }
+ else
+ fputs_filtered ("on all exceptions", gdb_stdout);
+ }
+ else if (b->break_on_exception == 2)
+ fputs_filtered ("on unhandled exception", gdb_stdout);
+ else if (b->break_on_exception == 3)
+ fputs_filtered ("on assert failure", gdb_stdout);
+ */
+}
+
+int
+ada_is_exception_sym (struct symbol *sym)
+{
+ char *type_name = type_name_no_tag (SYMBOL_TYPE (sym));
+
+ return (SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK
+ && SYMBOL_CLASS (sym) != LOC_CONST
+ && type_name != NULL && DEPRECATED_STREQ (type_name, "exception"));
+}
+
+int
+ada_maybe_exception_partial_symbol (struct partial_symbol *sym)
+{
+ return (SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK
+ && SYMBOL_CLASS (sym) != LOC_CONST);
+}
+
+/* If ARG points to an Ada exception or assert breakpoint, rewrite
+ into equivalent form. Return resulting argument string. Set
+ *BREAK_ON_EXCEPTIONP to 1 for ordinary break on exception, 2 for
+ break on unhandled, 3 for assert, 0 otherwise. */
+char *
+ada_breakpoint_rewrite (char *arg, int *break_on_exceptionp)
+{
+ if (arg == NULL)
+ return arg;
+ *break_on_exceptionp = 0;
+ /* FIXME: language_ada should be defined in defs.h */
+ /* if (current_language->la_language == language_ada
+ && DEPRECATED_STREQN (arg, "exception", 9) &&
+ (arg[9] == ' ' || arg[9] == '\t' || arg[9] == '\0'))
+ {
+ char *tok, *end_tok;
+ int toklen;
+
+ *break_on_exceptionp = 1;
+
+ tok = arg+9;
+ while (*tok == ' ' || *tok == '\t')
+ tok += 1;
+
+ end_tok = tok;
+
+ while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+ end_tok += 1;
+
+ toklen = end_tok - tok;
+
+ arg = (char*) xmalloc (sizeof ("__gnat_raise_nodefer_with_msg if "
+ "long_integer(e) = long_integer(&)")
+ + toklen + 1);
+ make_cleanup (xfree, arg);
+ if (toklen == 0)
+ strcpy (arg, "__gnat_raise_nodefer_with_msg");
+ else if (DEPRECATED_STREQN (tok, "unhandled", toklen))
+ {
+ *break_on_exceptionp = 2;
+ strcpy (arg, "__gnat_unhandled_exception");
+ }
+ else
+ {
+ sprintf (arg, "__gnat_raise_nodefer_with_msg if "
+ "long_integer(e) = long_integer(&%.*s)",
+ toklen, tok);
+ }
+ }
+ else if (current_language->la_language == language_ada
+ && DEPRECATED_STREQN (arg, "assert", 6) &&
+ (arg[6] == ' ' || arg[6] == '\t' || arg[6] == '\0'))
+ {
+ char *tok = arg + 6;
+
+ *break_on_exceptionp = 3;
+
+ arg = (char*)
+ xmalloc (sizeof ("system__assertions__raise_assert_failure")
+ + strlen (tok) + 1);
+ make_cleanup (xfree, arg);
+ sprintf (arg, "system__assertions__raise_assert_failure%s", tok);
+ }
+ */
+ return arg;
+}
+
+
+ /* Field Access */
+
+/* True if field number FIELD_NUM in struct or union type TYPE is supposed
+ to be invisible to users. */
+
+int
+ada_is_ignored_field (struct type *type, int field_num)
+{
+ if (field_num < 0 || field_num > TYPE_NFIELDS (type))
+ return 1;
+ else
+ {
+ const char *name = TYPE_FIELD_NAME (type, field_num);
+ return (name == NULL
+ || (name[0] == '_' && !DEPRECATED_STREQN (name, "_parent", 7)));
+ }
+}
+
+/* True iff structure type TYPE has a tag field. */
+
+int
+ada_is_tagged_type (struct type *type)
+{
+ if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT)
+ return 0;
+
+ return (ada_lookup_struct_elt_type (type, "_tag", 1, NULL) != NULL);
+}
+
+/* The type of the tag on VAL. */
+
+struct type *
+ada_tag_type (struct value *val)
+{
+ return ada_lookup_struct_elt_type (VALUE_TYPE (val), "_tag", 0, NULL);
+}
+
+/* The value of the tag on VAL. */
+
+struct value *
+ada_value_tag (struct value *val)
+{
+ return ada_value_struct_elt (val, "_tag", "record");
+}
+
+/* The parent type of TYPE, or NULL if none. */
+
+struct type *
+ada_parent_type (struct type *type)
+{
+ int i;
+
+ CHECK_TYPEDEF (type);
+
+ if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT)
+ return NULL;
+
+ for (i = 0; i < TYPE_NFIELDS (type); i += 1)
+ if (ada_is_parent_field (type, i))
+ return check_typedef (TYPE_FIELD_TYPE (type, i));
+
+ return NULL;
+}
+
+/* True iff field number FIELD_NUM of structure type TYPE contains the
+ parent-type (inherited) fields of a derived type. Assumes TYPE is
+ a structure type with at least FIELD_NUM+1 fields. */
+
+int
+ada_is_parent_field (struct type *type, int field_num)
+{
+ const char *name = TYPE_FIELD_NAME (check_typedef (type), field_num);
+ return (name != NULL &&
+ (DEPRECATED_STREQN (name, "PARENT", 6) || DEPRECATED_STREQN (name, "_parent", 7)));
+}
+
+/* True iff field number FIELD_NUM of structure type TYPE is a
+ transparent wrapper field (which should be silently traversed when doing
+ field selection and flattened when printing). Assumes TYPE is a
+ structure type with at least FIELD_NUM+1 fields. Such fields are always
+ structures. */
+
+int
+ada_is_wrapper_field (struct type *type, int field_num)
+{
+ const char *name = TYPE_FIELD_NAME (type, field_num);
+ return (name != NULL
+ && (DEPRECATED_STREQN (name, "PARENT", 6) || DEPRECATED_STREQ (name, "REP")
+ || DEPRECATED_STREQN (name, "_parent", 7)
+ || name[0] == 'S' || name[0] == 'R' || name[0] == 'O'));
+}
+
+/* True iff field number FIELD_NUM of structure or union type TYPE
+ is a variant wrapper. Assumes TYPE is a structure type with at least
+ FIELD_NUM+1 fields. */
+
+int
+ada_is_variant_part (struct type *type, int field_num)
+{
+ struct type *field_type = TYPE_FIELD_TYPE (type, field_num);
+ return (TYPE_CODE (field_type) == TYPE_CODE_UNION
+ || (is_dynamic_field (type, field_num)
+ && TYPE_CODE (TYPE_TARGET_TYPE (field_type)) ==
+ TYPE_CODE_UNION));
+}
+
+/* Assuming that VAR_TYPE is a variant wrapper (type of the variant part)
+ whose discriminants are contained in the record type OUTER_TYPE,
+ returns the type of the controlling discriminant for the variant. */
+
+struct type *
+ada_variant_discrim_type (struct type *var_type, struct type *outer_type)
+{
+ char *name = ada_variant_discrim_name (var_type);
+ struct type *type = ada_lookup_struct_elt_type (outer_type, name, 1, NULL);
+ if (type == NULL)
+ return builtin_type_int;
+ else
+ return type;
+}
+
+/* Assuming that TYPE is the type of a variant wrapper, and FIELD_NUM is a
+ valid field number within it, returns 1 iff field FIELD_NUM of TYPE
+ represents a 'when others' clause; otherwise 0. */
+
+int
+ada_is_others_clause (struct type *type, int field_num)
+{
+ const char *name = TYPE_FIELD_NAME (type, field_num);
+ return (name != NULL && name[0] == 'O');
+}
+
+/* Assuming that TYPE0 is the type of the variant part of a record,
+ returns the name of the discriminant controlling the variant. The
+ value is valid until the next call to ada_variant_discrim_name. */
+
+char *
+ada_variant_discrim_name (struct type *type0)
+{
+ static char *result = NULL;
+ static size_t result_len = 0;
+ struct type *type;
+ const char *name;
+ const char *discrim_end;
+ const char *discrim_start;
+
+ if (TYPE_CODE (type0) == TYPE_CODE_PTR)
+ type = TYPE_TARGET_TYPE (type0);
+ else
+ type = type0;
+
+ name = ada_type_name (type);
+
+ if (name == NULL || name[0] == '\000')
+ return "";
+
+ for (discrim_end = name + strlen (name) - 6; discrim_end != name;
+ discrim_end -= 1)
+ {
+ if (DEPRECATED_STREQN (discrim_end, "___XVN", 6))
+ break;
+ }
+ if (discrim_end == name)
+ return "";
+
+ for (discrim_start = discrim_end; discrim_start != name + 3;
+ discrim_start -= 1)
+ {
+ if (discrim_start == name + 1)
+ return "";
+ if ((discrim_start > name + 3 && DEPRECATED_STREQN (discrim_start - 3, "___", 3))
+ || discrim_start[-1] == '.')
+ break;
+ }
+
+ GROW_VECT (result, result_len, discrim_end - discrim_start + 1);
+ strncpy (result, discrim_start, discrim_end - discrim_start);
+ result[discrim_end - discrim_start] = '\0';
+ return result;
+}
+
+/* Scan STR for a subtype-encoded number, beginning at position K. Put the
+ position of the character just past the number scanned in *NEW_K,
+ if NEW_K!=NULL. Put the scanned number in *R, if R!=NULL. Return 1
+ if there was a valid number at the given position, and 0 otherwise. A
+ "subtype-encoded" number consists of the absolute value in decimal,
+ followed by the letter 'm' to indicate a negative number. Assumes 0m
+ does not occur. */
+
+int
+ada_scan_number (const char str[], int k, LONGEST * R, int *new_k)
+{
+ ULONGEST RU;
+
+ if (!isdigit (str[k]))
+ return 0;
+
+ /* Do it the hard way so as not to make any assumption about
+ the relationship of unsigned long (%lu scan format code) and
+ LONGEST. */
+ RU = 0;
+ while (isdigit (str[k]))
+ {
+ RU = RU * 10 + (str[k] - '0');
+ k += 1;
+ }
+
+ if (str[k] == 'm')
+ {
+ if (R != NULL)
+ *R = (-(LONGEST) (RU - 1)) - 1;
+ k += 1;
+ }
+ else if (R != NULL)
+ *R = (LONGEST) RU;
+
+ /* NOTE on the above: Technically, C does not say what the results of
+ - (LONGEST) RU or (LONGEST) -RU are for RU == largest positive
+ number representable as a LONGEST (although either would probably work
+ in most implementations). When RU>0, the locution in the then branch
+ above is always equivalent to the negative of RU. */
+
+ if (new_k != NULL)
+ *new_k = k;
+ return 1;
+}
+
+/* Assuming that TYPE is a variant part wrapper type (a VARIANTS field),
+ and FIELD_NUM is a valid field number within it, returns 1 iff VAL is
+ in the range encoded by field FIELD_NUM of TYPE; otherwise 0. */
+
+int
+ada_in_variant (LONGEST val, struct type *type, int field_num)
+{
+ const char *name = TYPE_FIELD_NAME (type, field_num);
+ int p;
+
+ p = 0;
+ while (1)
+ {
+ switch (name[p])
+ {
+ case '\0':
+ return 0;
+ case 'S':
+ {
+ LONGEST W;
+ if (!ada_scan_number (name, p + 1, &W, &p))
+ return 0;
+ if (val == W)
+ return 1;
+ break;
+ }
+ case 'R':
+ {
+ LONGEST L, U;
+ if (!ada_scan_number (name, p + 1, &L, &p)
+ || name[p] != 'T' || !ada_scan_number (name, p + 1, &U, &p))
+ return 0;
+ if (val >= L && val <= U)
+ return 1;
+ break;
+ }
+ case 'O':
+ return 1;
+ default:
+ return 0;
+ }
+ }
+}
+
+/* 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 (non-static) fields.
+ FIELDNO says which field. Differs from value_primitive_field only
+ in that it can handle packed values of arbitrary type. */
+
+struct value *
+ada_value_primitive_field (struct value *arg1, int offset, int fieldno,
+ struct type *arg_type)
+{
+ struct value *v;
+ struct type *type;
+
+ CHECK_TYPEDEF (arg_type);
+ type = TYPE_FIELD_TYPE (arg_type, fieldno);
+
+ /* Handle packed fields */
+
+ if (TYPE_FIELD_BITSIZE (arg_type, fieldno) != 0)
+ {
+ int bit_pos = TYPE_FIELD_BITPOS (arg_type, fieldno);
+ int bit_size = TYPE_FIELD_BITSIZE (arg_type, fieldno);
+
+ return ada_value_primitive_packed_val (arg1, VALUE_CONTENTS (arg1),
+ offset + bit_pos / 8,
+ bit_pos % 8, bit_size, type);
+ }
+ else
+ return value_primitive_field (arg1, offset, fieldno, arg_type);
+}
+
+
+/* Look for a field NAME in ARG. Adjust the address of ARG by OFFSET bytes,
+ and search in it assuming it has (class) type TYPE.
+ If found, return value, else return NULL.
+
+ Searches recursively through wrapper fields (e.g., '_parent'). */
+
+struct value *
+ada_search_struct_field (char *name, struct value *arg, int offset,
+ struct type *type)
+{
+ int i;
+ CHECK_TYPEDEF (type);
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= 0; i -= 1)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+ if (t_field_name == NULL)
+ continue;
+
+ else if (field_name_match (t_field_name, name))
+ return ada_value_primitive_field (arg, offset, i, type);
+
+ else if (ada_is_wrapper_field (type, i))
+ {
+ struct value *v = ada_search_struct_field (name, arg,
+ offset +
+ TYPE_FIELD_BITPOS (type,
+ i) /
+ 8,
+ TYPE_FIELD_TYPE (type,
+ i));
+ if (v != NULL)
+ return v;
+ }
+
+ else if (ada_is_variant_part (type, i))
+ {
+ int j;
+ struct type *field_type = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int var_offset = offset + TYPE_FIELD_BITPOS (type, i) / 8;
+
+ for (j = TYPE_NFIELDS (field_type) - 1; j >= 0; j -= 1)
+ {
+ struct value *v = ada_search_struct_field (name, arg,
+ var_offset
+ +
+ TYPE_FIELD_BITPOS
+ (field_type, j) / 8,
+ TYPE_FIELD_TYPE
+ (field_type, j));
+ if (v != NULL)
+ return v;
+ }
+ }
+ }
+ return NULL;
+}
+
+/* Given ARG, 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.
+
+ The routine searches for NAME among all members of the structure itself
+ and (recursively) among all members of any wrapper members
+ (e.g., '_parent').
+
+ ERR is a name (for use in error messages) that identifies the class
+ of entity that ARG is supposed to be. */
+
+struct value *
+ada_value_struct_elt (struct value *arg, char *name, char *err)
+{
+ struct type *t;
+ struct value *v;
+
+ arg = ada_coerce_ref (arg);
+ t = check_typedef (VALUE_TYPE (arg));
+
+ /* Follow pointers until we get to a non-pointer. */
+
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ {
+ arg = ada_value_ind (arg);
+ t = check_typedef (VALUE_TYPE (arg));
+ }
+
+ 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);
+
+ v = ada_search_struct_field (name, arg, 0, t);
+ if (v == NULL)
+ error ("There is no member named %s.", name);
+
+ return v;
+}
+
+/* Given a type TYPE, look up the type of the component of type named NAME.
+ If DISPP is non-null, add its byte displacement from the beginning of a
+ structure (pointed to by a value) of type TYPE to *DISPP (does not
+ work for packed fields).
+
+ Matches any field whose name has NAME as a prefix, possibly
+ followed by "___".
+
+ 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.
+
+ Looks recursively into variant clauses and parent types.
+
+ If NOERR is nonzero, return NULL if NAME is not suitably defined. */
+
+struct type *
+ada_lookup_struct_elt_type (struct type *type, char *name, int noerr,
+ int *dispp)
+{
+ int i;
+
+ if (name == NULL)
+ goto BadName;
+
+ while (1)
+ {
+ 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");
+ }
+
+ type = to_static_fixed_type (type);
+
+ for (i = 0; i < TYPE_NFIELDS (type); i += 1)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+ struct type *t;
+ int disp;
+
+ if (t_field_name == NULL)
+ continue;
+
+ else if (field_name_match (t_field_name, name))
+ {
+ if (dispp != NULL)
+ *dispp += TYPE_FIELD_BITPOS (type, i) / 8;
+ return check_typedef (TYPE_FIELD_TYPE (type, i));
+ }
+
+ else if (ada_is_wrapper_field (type, i))
+ {
+ disp = 0;
+ t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (type, i), name,
+ 1, &disp);
+ if (t != NULL)
+ {
+ if (dispp != NULL)
+ *dispp += disp + TYPE_FIELD_BITPOS (type, i) / 8;
+ return t;
+ }
+ }
+
+ else if (ada_is_variant_part (type, i))
+ {
+ int j;
+ struct type *field_type = check_typedef (TYPE_FIELD_TYPE (type, i));
+
+ for (j = TYPE_NFIELDS (field_type) - 1; j >= 0; j -= 1)
+ {
+ disp = 0;
+ t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (field_type, j),
+ name, 1, &disp);
+ if (t != NULL)
+ {
+ if (dispp != NULL)
+ *dispp += disp + TYPE_FIELD_BITPOS (type, i) / 8;
+ return t;
+ }
+ }
+ }
+
+ }
+
+BadName:
+ if (!noerr)
+ {
+ 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 ");
+ error ("%s", name == NULL ? "<null>" : name);
+ }
+
+ return NULL;
+}
+
+/* Assuming that VAR_TYPE is the type of a variant part of a record (a union),
+ within a value of type OUTER_TYPE that is stored in GDB at
+ OUTER_VALADDR, determine which variant clause (field number in VAR_TYPE,
+ numbering from 0) is applicable. Returns -1 if none are. */
+
+int
+ada_which_variant_applies (struct type *var_type, struct type *outer_type,
+ char *outer_valaddr)
+{
+ int others_clause;
+ int i;
+ int disp;
+ struct type *discrim_type;
+ char *discrim_name = ada_variant_discrim_name (var_type);
+ LONGEST discrim_val;
+
+ disp = 0;
+ discrim_type =
+ ada_lookup_struct_elt_type (outer_type, discrim_name, 1, &disp);
+ if (discrim_type == NULL)
+ return -1;
+ discrim_val = unpack_long (discrim_type, outer_valaddr + disp);
+
+ others_clause = -1;
+ for (i = 0; i < TYPE_NFIELDS (var_type); i += 1)
+ {
+ if (ada_is_others_clause (var_type, i))
+ others_clause = i;
+ else if (ada_in_variant (discrim_val, var_type, i))
+ return i;
+ }
+
+ return others_clause;
+}
+
+
+
+ /* Dynamic-Sized Records */
+
+/* Strategy: The type ostensibly attached to a value with dynamic size
+ (i.e., a size that is not statically recorded in the debugging
+ data) does not accurately reflect the size or layout of the value.
+ Our strategy is to convert these values to values with accurate,
+ conventional types that are constructed on the fly. */
+
+/* There is a subtle and tricky problem here. In general, we cannot
+ determine the size of dynamic records without its data. However,
+ the 'struct value' data structure, which GDB uses to represent
+ quantities in the inferior process (the target), requires the size
+ of the type at the time of its allocation in order to reserve space
+ for GDB's internal copy of the data. That's why the
+ 'to_fixed_xxx_type' routines take (target) addresses as parameters,
+ rather than struct value*s.
+
+ However, GDB's internal history variables ($1, $2, etc.) are
+ struct value*s containing internal copies of the data that are not, in
+ general, the same as the data at their corresponding addresses in
+ the target. Fortunately, the types we give to these values are all
+ conventional, fixed-size types (as per the strategy described
+ above), so that we don't usually have to perform the
+ 'to_fixed_xxx_type' conversions to look at their values.
+ Unfortunately, there is one exception: if one of the internal
+ history variables is an array whose elements are unconstrained
+ records, then we will need to create distinct fixed types for each
+ element selected. */
+
+/* The upshot of all of this is that many routines take a (type, host
+ address, target address) triple as arguments to represent a value.
+ The host address, if non-null, is supposed to contain an internal
+ copy of the relevant data; otherwise, the program is to consult the
+ target at the target address. */
+
+/* Assuming that VAL0 represents a pointer value, the result of
+ dereferencing it. Differs from value_ind in its treatment of
+ dynamic-sized types. */
+
+struct value *
+ada_value_ind (struct value *val0)
+{
+ struct value *val = unwrap_value (value_ind (val0));
+ return ada_to_fixed_value (VALUE_TYPE (val), 0,
+ VALUE_ADDRESS (val) + VALUE_OFFSET (val), val);
+}
+
+/* The value resulting from dereferencing any "reference to"
+ * qualifiers on VAL0. */
+static struct value *
+ada_coerce_ref (struct value *val0)
+{
+ if (TYPE_CODE (VALUE_TYPE (val0)) == TYPE_CODE_REF)
+ {
+ struct value *val = val0;
+ COERCE_REF (val);
+ val = unwrap_value (val);
+ return ada_to_fixed_value (VALUE_TYPE (val), 0,
+ VALUE_ADDRESS (val) + VALUE_OFFSET (val),
+ val);
+ }
+ else
+ return val0;
+}
+
+/* Return OFF rounded upward if necessary to a multiple of
+ ALIGNMENT (a power of 2). */
+
+static unsigned int
+align_value (unsigned int off, unsigned int alignment)
+{
+ return (off + alignment - 1) & ~(alignment - 1);
+}
+
+/* Return the additional bit offset required by field F of template
+ type TYPE. */
+
+static unsigned int
+field_offset (struct type *type, int f)
+{
+ int n = TYPE_FIELD_BITPOS (type, f);
+ /* Kludge (temporary?) to fix problem with dwarf output. */
+ if (n < 0)
+ return (unsigned int) n & 0xffff;
+ else
+ return n;
+}
+
+
+/* Return the bit alignment required for field #F of template type TYPE. */
+
+static unsigned int
+field_alignment (struct type *type, int f)
+{
+ const char *name = TYPE_FIELD_NAME (type, f);
+ int len = (name == NULL) ? 0 : strlen (name);
+ int align_offset;
+
+ if (len < 8 || !isdigit (name[len - 1]))
+ return TARGET_CHAR_BIT;
+
+ if (isdigit (name[len - 2]))
+ align_offset = len - 2;
+ else
+ align_offset = len - 1;
+
+ if (align_offset < 7 || !DEPRECATED_STREQN ("___XV", name + align_offset - 6, 5))
+ return TARGET_CHAR_BIT;
+
+ return atoi (name + align_offset) * TARGET_CHAR_BIT;
+}
+
+/* Find a type named NAME. Ignores ambiguity. */
+struct type *
+ada_find_any_type (const char *name)
+{
+ struct symbol *sym;
+
+ sym = standard_lookup (name, VAR_DOMAIN);
+ if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ return SYMBOL_TYPE (sym);
+
+ sym = standard_lookup (name, STRUCT_DOMAIN);
+ if (sym != NULL)
+ return SYMBOL_TYPE (sym);
+
+ return NULL;
+}
+
+/* Because of GNAT encoding conventions, several GDB symbols may match a
+ given type name. If the type denoted by TYPE0 is to be preferred to
+ that of TYPE1 for purposes of type printing, return non-zero;
+ otherwise return 0. */
+int
+ada_prefer_type (struct type *type0, struct type *type1)
+{
+ if (type1 == NULL)
+ return 1;
+ else if (type0 == NULL)
+ return 0;
+ else if (TYPE_CODE (type1) == TYPE_CODE_VOID)
+ return 1;
+ else if (TYPE_CODE (type0) == TYPE_CODE_VOID)
+ return 0;
+ else if (ada_is_packed_array_type (type0))
+ return 1;
+ else if (ada_is_array_descriptor (type0)
+ && !ada_is_array_descriptor (type1))
+ return 1;
+ else if (ada_renaming_type (type0) != NULL
+ && ada_renaming_type (type1) == NULL)
+ return 1;
+ return 0;
+}
+
+/* The name of TYPE, which is either its TYPE_NAME, or, if that is
+ null, its TYPE_TAG_NAME. Null if TYPE is null. */
+char *
+ada_type_name (struct type *type)
+{
+ if (type == NULL)
+ return NULL;
+ else if (TYPE_NAME (type) != NULL)
+ return TYPE_NAME (type);
+ else
+ return TYPE_TAG_NAME (type);
+}
+
+/* Find a parallel type to TYPE whose name is formed by appending
+ SUFFIX to the name of TYPE. */
+
+struct type *
+ada_find_parallel_type (struct type *type, const char *suffix)
+{
+ static char *name;
+ static size_t name_len = 0;
+ struct symbol **syms;
+ struct block **blocks;
+ int nsyms;
+ int len;
+ char *typename = ada_type_name (type);
+
+ if (typename == NULL)
+ return NULL;
+
+ len = strlen (typename);
+
+ GROW_VECT (name, name_len, len + strlen (suffix) + 1);
+
+ strcpy (name, typename);
+ strcpy (name + len, suffix);
+
+ return ada_find_any_type (name);
+}
+
+
+/* If TYPE is a variable-size record type, return the corresponding template
+ type describing its fields. Otherwise, return NULL. */
+
+static struct type *
+dynamic_template_type (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+
+ if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT
+ || ada_type_name (type) == NULL)
+ return NULL;
+ else
+ {
+ int len = strlen (ada_type_name (type));
+ if (len > 6 && DEPRECATED_STREQ (ada_type_name (type) + len - 6, "___XVE"))
+ return type;
+ else
+ return ada_find_parallel_type (type, "___XVE");
+ }
+}
+
+/* Assuming that TEMPL_TYPE is a union or struct type, returns
+ non-zero iff field FIELD_NUM of TEMPL_TYPE has dynamic size. */
+
+static int
+is_dynamic_field (struct type *templ_type, int field_num)
+{
+ const char *name = TYPE_FIELD_NAME (templ_type, field_num);
+ return name != NULL
+ && TYPE_CODE (TYPE_FIELD_TYPE (templ_type, field_num)) == TYPE_CODE_PTR
+ && strstr (name, "___XVL") != NULL;
+}
+
+/* Assuming that TYPE is a struct type, returns non-zero iff TYPE
+ contains a variant part. */
+
+static int
+contains_variant_part (struct type *type)
+{
+ int f;
+
+ if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT
+ || TYPE_NFIELDS (type) <= 0)
+ return 0;
+ return ada_is_variant_part (type, TYPE_NFIELDS (type) - 1);
+}
+
+/* A record type with no fields, . */
+static struct type *
+empty_record (struct objfile *objfile)
+{
+ struct type *type = alloc_type (objfile);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ TYPE_NFIELDS (type) = 0;
+ TYPE_FIELDS (type) = NULL;
+ TYPE_NAME (type) = "<empty>";
+ TYPE_TAG_NAME (type) = NULL;
+ TYPE_FLAGS (type) = 0;
+ TYPE_LENGTH (type) = 0;
+ return type;
+}
+
+/* An ordinary record type (with fixed-length fields) that describes
+ the value of type TYPE at VALADDR or ADDRESS (see comments at
+ the beginning of this section) VAL according to GNAT conventions.
+ DVAL0 should describe the (portion of a) record that contains any
+ necessary discriminants. It should be NULL if VALUE_TYPE (VAL) is
+ an outer-level type (i.e., as opposed to a branch of a variant.) A
+ variant field (unless unchecked) is replaced by a particular branch
+ of the variant. */
+/* NOTE: Limitations: For now, we assume that dynamic fields and
+ * variants occupy whole numbers of bytes. However, they need not be
+ * byte-aligned. */
+
+static struct type *
+template_to_fixed_record_type (struct type *type, char *valaddr,
+ CORE_ADDR address, struct value *dval0)
+{
+ struct value *mark = value_mark ();
+ struct value *dval;
+ struct type *rtype;
+ int nfields, bit_len;
+ long off;
+ int f;
+
+ nfields = TYPE_NFIELDS (type);
+ rtype = alloc_type (TYPE_OBJFILE (type));
+ TYPE_CODE (rtype) = TYPE_CODE_STRUCT;
+ INIT_CPLUS_SPECIFIC (rtype);
+ TYPE_NFIELDS (rtype) = nfields;
+ TYPE_FIELDS (rtype) = (struct field *)
+ TYPE_ALLOC (rtype, nfields * sizeof (struct field));
+ memset (TYPE_FIELDS (rtype), 0, sizeof (struct field) * nfields);
+ TYPE_NAME (rtype) = ada_type_name (type);
+ TYPE_TAG_NAME (rtype) = NULL;
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in
+ gdbtypes.h */
+ /* TYPE_FLAGS (rtype) |= TYPE_FLAG_FIXED_INSTANCE; */
+
+ off = 0;
+ bit_len = 0;
+ for (f = 0; f < nfields; f += 1)
+ {
+ int fld_bit_len, bit_incr;
+ off =
+ align_value (off,
+ field_alignment (type, f)) + TYPE_FIELD_BITPOS (type, f);
+ /* NOTE: used to use field_offset above, but that causes
+ * problems with really negative bit positions. So, let's
+ * rediscover why we needed field_offset and fix it properly. */
+ TYPE_FIELD_BITPOS (rtype, f) = off;
+ TYPE_FIELD_BITSIZE (rtype, f) = 0;
+ TYPE_FIELD_STATIC_KIND (rtype, f) = 0;
+
+ if (ada_is_variant_part (type, f))
+ {
+ struct type *branch_type;
+
+ if (dval0 == NULL)
+ dval = value_from_contents_and_address (rtype, valaddr, address);
+ else
+ dval = dval0;
+
+ branch_type =
+ to_fixed_variant_branch_type
+ (TYPE_FIELD_TYPE (type, f),
+ cond_offset_host (valaddr, off / TARGET_CHAR_BIT),
+ cond_offset_target (address, off / TARGET_CHAR_BIT), dval);
+ if (branch_type == NULL)
+ TYPE_NFIELDS (rtype) -= 1;
+ else
+ {
+ TYPE_FIELD_TYPE (rtype, f) = branch_type;
+ TYPE_FIELD_NAME (rtype, f) = "S";
+ }
+ bit_incr = 0;
+ fld_bit_len =
+ TYPE_LENGTH (TYPE_FIELD_TYPE (rtype, f)) * TARGET_CHAR_BIT;
+ }
+ else if (is_dynamic_field (type, f))
+ {
+ if (dval0 == NULL)
+ dval = value_from_contents_and_address (rtype, valaddr, address);
+ else
+ dval = dval0;
+
+ TYPE_FIELD_TYPE (rtype, f) =
+ ada_to_fixed_type
+ (ada_get_base_type
+ (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, f))),
+ cond_offset_host (valaddr, off / TARGET_CHAR_BIT),
+ cond_offset_target (address, off / TARGET_CHAR_BIT), dval);
+ TYPE_FIELD_NAME (rtype, f) = TYPE_FIELD_NAME (type, f);
+ bit_incr = fld_bit_len =
+ TYPE_LENGTH (TYPE_FIELD_TYPE (rtype, f)) * TARGET_CHAR_BIT;
+ }
+ else
+ {
+ TYPE_FIELD_TYPE (rtype, f) = TYPE_FIELD_TYPE (type, f);
+ TYPE_FIELD_NAME (rtype, f) = TYPE_FIELD_NAME (type, f);
+ if (TYPE_FIELD_BITSIZE (type, f) > 0)
+ bit_incr = fld_bit_len =
+ TYPE_FIELD_BITSIZE (rtype, f) = TYPE_FIELD_BITSIZE (type, f);
+ else
+ bit_incr = fld_bit_len =
+ TYPE_LENGTH (TYPE_FIELD_TYPE (type, f)) * TARGET_CHAR_BIT;
+ }
+ if (off + fld_bit_len > bit_len)
+ bit_len = off + fld_bit_len;
+ off += bit_incr;
+ TYPE_LENGTH (rtype) = bit_len / TARGET_CHAR_BIT;
+ }
+ TYPE_LENGTH (rtype) = align_value (TYPE_LENGTH (rtype), TYPE_LENGTH (type));
+
+ value_free_to_mark (mark);
+ if (TYPE_LENGTH (rtype) > varsize_limit)
+ error ("record type with dynamic size is larger than varsize-limit");
+ return rtype;
+}
+
+/* As for template_to_fixed_record_type, but uses no run-time values.
+ As a result, this type can only be approximate, but that's OK,
+ since it is used only for type determinations. Works on both
+ structs and unions.
+ Representation note: to save space, we memoize the result of this
+ function in the TYPE_TARGET_TYPE of the template type. */
+
+static struct type *
+template_to_static_fixed_type (struct type *templ_type)
+{
+ struct type *type;
+ int nfields;
+ int f;
+
+ if (TYPE_TARGET_TYPE (templ_type) != NULL)
+ return TYPE_TARGET_TYPE (templ_type);
+
+ nfields = TYPE_NFIELDS (templ_type);
+ TYPE_TARGET_TYPE (templ_type) = type =
+ alloc_type (TYPE_OBJFILE (templ_type));
+ TYPE_CODE (type) = TYPE_CODE (templ_type);
+ INIT_CPLUS_SPECIFIC (type);
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, nfields * sizeof (struct field));
+ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+ TYPE_NAME (type) = ada_type_name (templ_type);
+ TYPE_TAG_NAME (type) = NULL;
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+ /* TYPE_FLAGS (type) |= TYPE_FLAG_FIXED_INSTANCE; */
+ TYPE_LENGTH (type) = 0;
+
+ for (f = 0; f < nfields; f += 1)
+ {
+ TYPE_FIELD_BITPOS (type, f) = 0;
+ TYPE_FIELD_BITSIZE (type, f) = 0;
+ TYPE_FIELD_STATIC_KIND (type, f) = 0;
+
+ if (is_dynamic_field (templ_type, f))
+ {
+ TYPE_FIELD_TYPE (type, f) =
+ to_static_fixed_type (TYPE_TARGET_TYPE
+ (TYPE_FIELD_TYPE (templ_type, f)));
+ TYPE_FIELD_NAME (type, f) = TYPE_FIELD_NAME (templ_type, f);
+ }
+ else
+ {
+ TYPE_FIELD_TYPE (type, f) =
+ check_typedef (TYPE_FIELD_TYPE (templ_type, f));
+ TYPE_FIELD_NAME (type, f) = TYPE_FIELD_NAME (templ_type, f);
+ }
+ }
+
+ return type;
+}
+
+/* A revision of TYPE0 -- a non-dynamic-sized record with a variant
+ part -- in which the variant part is replaced with the appropriate
+ branch. */
+static struct type *
+to_record_with_fixed_variant_part (struct type *type, char *valaddr,
+ CORE_ADDR address, struct value *dval)
+{
+ struct value *mark = value_mark ();
+ struct type *rtype;
+ struct type *branch_type;
+ int nfields = TYPE_NFIELDS (type);
+
+ if (dval == NULL)
+ return type;
+
+ rtype = alloc_type (TYPE_OBJFILE (type));
+ TYPE_CODE (rtype) = TYPE_CODE_STRUCT;
+ INIT_CPLUS_SPECIFIC (type);
+ TYPE_NFIELDS (rtype) = TYPE_NFIELDS (type);
+ TYPE_FIELDS (rtype) =
+ (struct field *) TYPE_ALLOC (rtype, nfields * sizeof (struct field));
+ memcpy (TYPE_FIELDS (rtype), TYPE_FIELDS (type),
+ sizeof (struct field) * nfields);
+ TYPE_NAME (rtype) = ada_type_name (type);
+ TYPE_TAG_NAME (rtype) = NULL;
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+ /* TYPE_FLAGS (rtype) |= TYPE_FLAG_FIXED_INSTANCE; */
+ TYPE_LENGTH (rtype) = TYPE_LENGTH (type);
+
+ branch_type =
+ to_fixed_variant_branch_type
+ (TYPE_FIELD_TYPE (type, nfields - 1),
+ cond_offset_host (valaddr,
+ TYPE_FIELD_BITPOS (type,
+ nfields - 1) / TARGET_CHAR_BIT),
+ cond_offset_target (address,
+ TYPE_FIELD_BITPOS (type,
+ nfields - 1) / TARGET_CHAR_BIT),
+ dval);
+ if (branch_type == NULL)
+ {
+ TYPE_NFIELDS (rtype) -= 1;
+ TYPE_LENGTH (rtype) -=
+ TYPE_LENGTH (TYPE_FIELD_TYPE (type, nfields - 1));
+ }
+ else
+ {
+ TYPE_FIELD_TYPE (rtype, nfields - 1) = branch_type;
+ TYPE_FIELD_NAME (rtype, nfields - 1) = "S";
+ TYPE_FIELD_BITSIZE (rtype, nfields - 1) = 0;
+ TYPE_FIELD_STATIC_KIND (rtype, nfields - 1) = 0;
+ TYPE_LENGTH (rtype) += TYPE_LENGTH (branch_type);
+ -TYPE_LENGTH (TYPE_FIELD_TYPE (type, nfields - 1));
+ }
+
+ return rtype;
+}
+
+/* An ordinary record type (with fixed-length fields) that describes
+ the value at (TYPE0, VALADDR, ADDRESS) [see explanation at
+ beginning of this section]. Any necessary discriminants' values
+ should be in DVAL, a record value; it should be NULL if the object
+ at ADDR itself contains any necessary discriminant values. A
+ variant field (unless unchecked) is replaced by a particular branch
+ of the variant. */
+
+static struct type *
+to_fixed_record_type (struct type *type0, char *valaddr, CORE_ADDR address,
+ struct value *dval)
+{
+ struct type *templ_type;
+
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+ /* if (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE)
+ return type0;
+ */
+ templ_type = dynamic_template_type (type0);
+
+ if (templ_type != NULL)
+ return template_to_fixed_record_type (templ_type, valaddr, address, dval);
+ else if (contains_variant_part (type0))
+ return to_record_with_fixed_variant_part (type0, valaddr, address, dval);
+ else
+ {
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+ /* TYPE_FLAGS (type0) |= TYPE_FLAG_FIXED_INSTANCE; */
+ return type0;
+ }
+
+}
+
+/* An ordinary record type (with fixed-length fields) that describes
+ the value at (VAR_TYPE0, VALADDR, ADDRESS), where VAR_TYPE0 is a
+ union type. Any necessary discriminants' values should be in DVAL,
+ a record value. That is, this routine selects the appropriate
+ branch of the union at ADDR according to the discriminant value
+ indicated in the union's type name. */
+
+static struct type *
+to_fixed_variant_branch_type (struct type *var_type0, char *valaddr,
+ CORE_ADDR address, struct value *dval)
+{
+ int which;
+ struct type *templ_type;
+ struct type *var_type;
+
+ if (TYPE_CODE (var_type0) == TYPE_CODE_PTR)
+ var_type = TYPE_TARGET_TYPE (var_type0);
+ else
+ var_type = var_type0;
+
+ templ_type = ada_find_parallel_type (var_type, "___XVU");
+
+ if (templ_type != NULL)
+ var_type = templ_type;
+
+ which =
+ ada_which_variant_applies (var_type,
+ VALUE_TYPE (dval), VALUE_CONTENTS (dval));
+
+ if (which < 0)
+ return empty_record (TYPE_OBJFILE (var_type));
+ else if (is_dynamic_field (var_type, which))
+ return
+ to_fixed_record_type
+ (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (var_type, which)),
+ valaddr, address, dval);
+ else if (contains_variant_part (TYPE_FIELD_TYPE (var_type, which)))
+ return
+ to_fixed_record_type
+ (TYPE_FIELD_TYPE (var_type, which), valaddr, address, dval);
+ else
+ return TYPE_FIELD_TYPE (var_type, which);
+}
+
+/* Assuming that TYPE0 is an array type describing the type of a value
+ at ADDR, and that DVAL describes a record containing any
+ discriminants used in TYPE0, returns a type for the value that
+ contains no dynamic components (that is, no components whose sizes
+ are determined by run-time quantities). Unless IGNORE_TOO_BIG is
+ true, gives an error message if the resulting type's size is over
+ varsize_limit.
+*/
+
+static struct type *
+to_fixed_array_type (struct type *type0, struct value *dval,
+ int ignore_too_big)
+{
+ struct type *index_type_desc;
+ struct type *result;
+
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+/* if (ada_is_packed_array_type (type0) /* revisit? *//*
+ || (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE))
+ return type0; */
+
+ index_type_desc = ada_find_parallel_type (type0, "___XA");
+ if (index_type_desc == NULL)
+ {
+ struct type *elt_type0 = check_typedef (TYPE_TARGET_TYPE (type0));
+ /* NOTE: elt_type---the fixed version of elt_type0---should never
+ * depend on the contents of the array in properly constructed
+ * debugging data. */
+ struct type *elt_type = ada_to_fixed_type (elt_type0, 0, 0, dval);
+
+ if (elt_type0 == elt_type)
+ result = type0;
+ else
+ result = create_array_type (alloc_type (TYPE_OBJFILE (type0)),
+ elt_type, TYPE_INDEX_TYPE (type0));
+ }
+ else
+ {
+ int i;
+ struct type *elt_type0;
+
+ elt_type0 = type0;
+ for (i = TYPE_NFIELDS (index_type_desc); i > 0; i -= 1)
+ elt_type0 = TYPE_TARGET_TYPE (elt_type0);
+
+ /* NOTE: result---the fixed version of elt_type0---should never
+ * depend on the contents of the array in properly constructed
+ * debugging data. */
+ result = ada_to_fixed_type (check_typedef (elt_type0), 0, 0, dval);
+ for (i = TYPE_NFIELDS (index_type_desc) - 1; i >= 0; i -= 1)
+ {
+ struct type *range_type =
+ to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, i),
+ dval, TYPE_OBJFILE (type0));
+ result = create_array_type (alloc_type (TYPE_OBJFILE (type0)),
+ result, range_type);
+ }
+ if (!ignore_too_big && TYPE_LENGTH (result) > varsize_limit)
+ error ("array type with dynamic size is larger than varsize-limit");
+ }
+
+/* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+/* TYPE_FLAGS (result) |= TYPE_FLAG_FIXED_INSTANCE; */
+ return result;
+}
+
+
+/* A standard type (containing no dynamically sized components)
+ corresponding to TYPE for the value (TYPE, VALADDR, ADDRESS)
+ DVAL describes a record containing any discriminants used in TYPE0,
+ and may be NULL if there are none. */
+
+struct type *
+ada_to_fixed_type (struct type *type, char *valaddr, CORE_ADDR address,
+ struct value *dval)
+{
+ CHECK_TYPEDEF (type);
+ switch (TYPE_CODE (type))
+ {
+ default:
+ return type;
+ case TYPE_CODE_STRUCT:
+ return to_fixed_record_type (type, valaddr, address, NULL);
+ case TYPE_CODE_ARRAY:
+ return to_fixed_array_type (type, dval, 0);
+ case TYPE_CODE_UNION:
+ if (dval == NULL)
+ return type;
+ else
+ return to_fixed_variant_branch_type (type, valaddr, address, dval);
+ }
+}
+
+/* A standard (static-sized) type corresponding as well as possible to
+ TYPE0, but based on no runtime data. */
+
+static struct type *
+to_static_fixed_type (struct type *type0)
+{
+ struct type *type;
+
+ if (type0 == NULL)
+ return NULL;
+
+ /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+ /* if (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE)
+ return type0;
+ */
+ CHECK_TYPEDEF (type0);
+
+ switch (TYPE_CODE (type0))
+ {
+ default:
+ return type0;
+ case TYPE_CODE_STRUCT:
+ type = dynamic_template_type (type0);
+ if (type != NULL)
+ return template_to_static_fixed_type (type);
+ return type0;
+ case TYPE_CODE_UNION:
+ type = ada_find_parallel_type (type0, "___XVU");
+ if (type != NULL)
+ return template_to_static_fixed_type (type);
+ return type0;
+ }
+}
+
+/* A static approximation of TYPE with all type wrappers removed. */
+static struct type *
+static_unwrap_type (struct type *type)
+{
+ if (ada_is_aligner_type (type))
+ {
+ struct type *type1 = TYPE_FIELD_TYPE (check_typedef (type), 0);
+ if (ada_type_name (type1) == NULL)
+ TYPE_NAME (type1) = ada_type_name (type);
+
+ return static_unwrap_type (type1);
+ }
+ else
+ {
+ struct type *raw_real_type = ada_get_base_type (type);
+ if (raw_real_type == type)
+ return type;
+ else
+ return to_static_fixed_type (raw_real_type);
+ }
+}
+
+/* In some cases, incomplete and private types require
+ cross-references that are not resolved as records (for example,
+ type Foo;
+ type FooP is access Foo;
+ V: FooP;
+ type Foo is array ...;
+ ). In these cases, since there is no mechanism for producing
+ cross-references to such types, we instead substitute for FooP a
+ stub enumeration type that is nowhere resolved, and whose tag is
+ the name of the actual type. Call these types "non-record stubs". */
+
+/* A type equivalent to TYPE that is not a non-record stub, if one
+ exists, otherwise TYPE. */
+struct type *
+ada_completed_type (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM
+ || (TYPE_FLAGS (type) & TYPE_FLAG_STUB) == 0
+ || TYPE_TAG_NAME (type) == NULL)
+ return type;
+ else
+ {
+ char *name = TYPE_TAG_NAME (type);
+ struct type *type1 = ada_find_any_type (name);
+ return (type1 == NULL) ? type : type1;
+ }
+}
+
+/* A value representing the data at VALADDR/ADDRESS as described by
+ type TYPE0, but with a standard (static-sized) type that correctly
+ describes it. If VAL0 is not NULL and TYPE0 already is a standard
+ type, then return VAL0 [this feature is simply to avoid redundant
+ creation of struct values]. */
+
+struct value *
+ada_to_fixed_value (struct type *type0, char *valaddr, CORE_ADDR address,
+ struct value *val0)
+{
+ struct type *type = ada_to_fixed_type (type0, valaddr, address, NULL);
+ if (type == type0 && val0 != NULL)
+ return val0;
+ else
+ return value_from_contents_and_address (type, valaddr, address);
+}
+
+/* A value representing VAL, but with a standard (static-sized) type
+ chosen to approximate the real type of VAL as well as possible, but
+ without consulting any runtime values. For Ada dynamic-sized
+ types, therefore, the type of the result is likely to be inaccurate. */
+
+struct value *
+ada_to_static_fixed_value (struct value *val)
+{
+ struct type *type =
+ to_static_fixed_type (static_unwrap_type (VALUE_TYPE (val)));
+ if (type == VALUE_TYPE (val))
+ return val;
+ else
+ return coerce_unspec_val_to_type (val, 0, type);
+}
+
+
+
+
+
+/* Attributes */
+
+/* Table mapping attribute numbers to names */
+/* NOTE: Keep up to date with enum ada_attribute definition in ada-lang.h */
+
+static const char *attribute_names[] = {
+ "<?>",
+
+ "first",
+ "last",
+ "length",
+ "image",
+ "img",
+ "max",
+ "min",
+ "pos" "tag",
+ "val",
+
+ 0
+};
+
+const char *
+ada_attribute_name (int n)
+{
+ if (n > 0 && n < (int) ATR_END)
+ return attribute_names[n];
+ else
+ return attribute_names[0];
+}
+
+/* Evaluate the 'POS attribute applied to ARG. */
+
+static struct value *
+value_pos_atr (struct value *arg)
+{
+ struct type *type = VALUE_TYPE (arg);
+
+ if (!discrete_type_p (type))
+ error ("'POS only defined on discrete types");
+
+ if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ int i;
+ LONGEST v = value_as_long (arg);
+
+ for (i = 0; i < TYPE_NFIELDS (type); i += 1)
+ {
+ if (v == TYPE_FIELD_BITPOS (type, i))
+ return value_from_longest (builtin_type_ada_int, i);
+ }
+ error ("enumeration value is invalid: can't find 'POS");
+ }
+ else
+ return value_from_longest (builtin_type_ada_int, value_as_long (arg));
+}
+
+/* Evaluate the TYPE'VAL attribute applied to ARG. */
+
+static struct value *
+value_val_atr (struct type *type, struct value *arg)
+{
+ if (!discrete_type_p (type))
+ error ("'VAL only defined on discrete types");
+ if (!integer_type_p (VALUE_TYPE (arg)))
+ error ("'VAL requires integral argument");
+
+ if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ long pos = value_as_long (arg);
+ if (pos < 0 || pos >= TYPE_NFIELDS (type))
+ error ("argument to 'VAL out of range");
+ return value_from_longest (type, TYPE_FIELD_BITPOS (type, pos));
+ }
+ else
+ return value_from_longest (type, value_as_long (arg));
+}
+
+
+ /* Evaluation */
+
+/* True if TYPE appears to be an Ada character type.
+ * [At the moment, this is true only for Character and Wide_Character;
+ * It is a heuristic test that could stand improvement]. */
+
+int
+ada_is_character_type (struct type *type)
+{
+ const char *name = ada_type_name (type);
+ return
+ name != NULL
+ && (TYPE_CODE (type) == TYPE_CODE_CHAR
+ || TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_RANGE)
+ && (DEPRECATED_STREQ (name, "character") || DEPRECATED_STREQ (name, "wide_character")
+ || DEPRECATED_STREQ (name, "unsigned char"));
+}
+
+/* True if TYPE appears to be an Ada string type. */
+
+int
+ada_is_string_type (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ if (type != NULL
+ && TYPE_CODE (type) != TYPE_CODE_PTR
+ && (ada_is_simple_array (type) || ada_is_array_descriptor (type))
+ && ada_array_arity (type) == 1)
+ {
+ struct type *elttype = ada_array_element_type (type, 1);
+
+ return ada_is_character_type (elttype);
+ }
+ else
+ return 0;
+}
+
+
+/* True if TYPE is a struct type introduced by the compiler to force the
+ alignment of a value. Such types have a single field with a
+ distinctive name. */
+
+int
+ada_is_aligner_type (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1
+ && DEPRECATED_STREQ (TYPE_FIELD_NAME (type, 0), "F"));
+}
+
+/* If there is an ___XVS-convention type parallel to SUBTYPE, return
+ the parallel type. */
+
+struct type *
+ada_get_base_type (struct type *raw_type)
+{
+ struct type *real_type_namer;
+ struct type *raw_real_type;
+ struct type *real_type;
+
+ if (raw_type == NULL || TYPE_CODE (raw_type) != TYPE_CODE_STRUCT)
+ return raw_type;
+
+ real_type_namer = ada_find_parallel_type (raw_type, "___XVS");
+ if (real_type_namer == NULL
+ || TYPE_CODE (real_type_namer) != TYPE_CODE_STRUCT
+ || TYPE_NFIELDS (real_type_namer) != 1)
+ return raw_type;
+
+ raw_real_type = ada_find_any_type (TYPE_FIELD_NAME (real_type_namer, 0));
+ if (raw_real_type == NULL)
+ return raw_type;
+ else
+ return raw_real_type;
+}
+
+/* The type of value designated by TYPE, with all aligners removed. */
+
+struct type *
+ada_aligned_type (struct type *type)
+{
+ if (ada_is_aligner_type (type))
+ return ada_aligned_type (TYPE_FIELD_TYPE (type, 0));
+ else
+ return ada_get_base_type (type);
+}
+
+
+/* The address of the aligned value in an object at address VALADDR
+ having type TYPE. Assumes ada_is_aligner_type (TYPE). */
+
+char *
+ada_aligned_value_addr (struct type *type, char *valaddr)
+{
+ if (ada_is_aligner_type (type))
+ return ada_aligned_value_addr (TYPE_FIELD_TYPE (type, 0),
+ valaddr +
+ TYPE_FIELD_BITPOS (type,
+ 0) / TARGET_CHAR_BIT);
+ else
+ return valaddr;
+}
+
+/* The printed representation of an enumeration literal with encoded
+ name NAME. The value is good to the next call of ada_enum_name. */
+const char *
+ada_enum_name (const char *name)
+{
+ char *tmp;
+
+ while (1)
+ {
+ if ((tmp = strstr (name, "__")) != NULL)
+ name = tmp + 2;
+ else if ((tmp = strchr (name, '.')) != NULL)
+ name = tmp + 1;
+ else
+ break;
+ }
+
+ if (name[0] == 'Q')
+ {
+ static char result[16];
+ int v;
+ if (name[1] == 'U' || name[1] == 'W')
+ {
+ if (sscanf (name + 2, "%x", &v) != 1)
+ return name;
+ }
+ else
+ return name;
+
+ if (isascii (v) && isprint (v))
+ sprintf (result, "'%c'", v);
+ else if (name[1] == 'U')
+ sprintf (result, "[\"%02x\"]", v);
+ else
+ sprintf (result, "[\"%04x\"]", v);
+
+ return result;
+ }
+ else
+ return name;
+}
+
+static struct value *
+evaluate_subexp (struct type *expect_type, struct expression *exp, int *pos,
+ enum noside noside)
+{
+ return (*exp->language_defn->evaluate_exp) (expect_type, exp, pos, noside);
+}
+
+/* Evaluate the subexpression of EXP starting at *POS as for
+ evaluate_type, updating *POS to point just past the evaluated
+ expression. */
+
+static struct value *
+evaluate_subexp_type (struct expression *exp, int *pos)
+{
+ return (*exp->language_defn->evaluate_exp)
+ (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+/* If VAL is wrapped in an aligner or subtype wrapper, return the
+ value it wraps. */
+
+static struct value *
+unwrap_value (struct value *val)
+{
+ struct type *type = check_typedef (VALUE_TYPE (val));
+ if (ada_is_aligner_type (type))
+ {
+ struct value *v = value_struct_elt (&val, NULL, "F",
+ NULL, "internal structure");
+ struct type *val_type = check_typedef (VALUE_TYPE (v));
+ if (ada_type_name (val_type) == NULL)
+ TYPE_NAME (val_type) = ada_type_name (type);
+
+ return unwrap_value (v);
+ }
+ else
+ {
+ struct type *raw_real_type =
+ ada_completed_type (ada_get_base_type (type));
+
+ if (type == raw_real_type)
+ return val;
+
+ return
+ coerce_unspec_val_to_type
+ (val, 0, ada_to_fixed_type (raw_real_type, 0,
+ VALUE_ADDRESS (val) + VALUE_OFFSET (val),
+ NULL));
+ }
+}
+
+static struct value *
+cast_to_fixed (struct type *type, struct value *arg)
+{
+ LONGEST val;
+
+ if (type == VALUE_TYPE (arg))
+ return arg;
+ else if (ada_is_fixed_point_type (VALUE_TYPE (arg)))
+ val = ada_float_to_fixed (type,
+ ada_fixed_to_float (VALUE_TYPE (arg),
+ value_as_long (arg)));
+ else
+ {
+ DOUBLEST argd =
+ value_as_double (value_cast (builtin_type_double, value_copy (arg)));
+ val = ada_float_to_fixed (type, argd);
+ }
+
+ return value_from_longest (type, val);
+}
+
+static struct value *
+cast_from_fixed_to_double (struct value *arg)
+{
+ DOUBLEST val = ada_fixed_to_float (VALUE_TYPE (arg),
+ value_as_long (arg));
+ return value_from_double (builtin_type_double, val);
+}
+
+/* Coerce VAL as necessary for assignment to an lval of type TYPE, and
+ * return the converted value. */
+static struct value *
+coerce_for_assign (struct type *type, struct value *val)
+{
+ struct type *type2 = VALUE_TYPE (val);
+ if (type == type2)
+ return val;
+
+ CHECK_TYPEDEF (type2);
+ CHECK_TYPEDEF (type);
+
+ if (TYPE_CODE (type2) == TYPE_CODE_PTR
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ val = ada_value_ind (val);
+ type2 = VALUE_TYPE (val);
+ }
+
+ if (TYPE_CODE (type2) == TYPE_CODE_ARRAY
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ if (TYPE_LENGTH (type2) != TYPE_LENGTH (type)
+ || TYPE_LENGTH (TYPE_TARGET_TYPE (type2))
+ != TYPE_LENGTH (TYPE_TARGET_TYPE (type2)))
+ error ("Incompatible types in assignment");
+ VALUE_TYPE (val) = type;
+ }
+ return val;
+}
+
+struct value *
+ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
+ int *pos, enum noside noside)
+{
+ enum exp_opcode op;
+ enum ada_attribute atr;
+ int tem, tem2, tem3;
+ int pc;
+ struct value *arg1 = NULL, *arg2 = NULL, *arg3;
+ struct type *type;
+ int nargs;
+ struct value **argvec;
+
+ pc = *pos;
+ *pos += 1;
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ default:
+ *pos -= 1;
+ return
+ unwrap_value (evaluate_subexp_standard
+ (expect_type, exp, pos, noside));
+
+ 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 != check_typedef (VALUE_TYPE (arg1)))
+ {
+ if (ada_is_fixed_point_type (type))
+ arg1 = cast_to_fixed (type, arg1);
+ else if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+ arg1 = value_cast (type, cast_from_fixed_to_double (arg1));
+ else if (VALUE_LVAL (arg1) == lval_memory)
+ {
+ /* This is in case of the really obscure (and undocumented,
+ but apparently expected) case of (Foo) Bar.all, where Bar
+ is an integer constant and Foo is a dynamic-sized type.
+ If we don't do this, ARG1 will simply be relabeled with
+ TYPE. */
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (to_static_fixed_type (type), not_lval);
+ arg1 =
+ ada_to_fixed_value
+ (type, 0, VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1), 0);
+ }
+ else
+ arg1 = value_cast (type, arg1);
+ }
+ return arg1;
+
+ /* FIXME: UNOP_QUAL should be defined in expression.h */
+ /* case UNOP_QUAL:
+ (*pos) += 2;
+ type = exp->elts[pc + 1].type;
+ return ada_evaluate_subexp (type, exp, pos, noside);
+ */
+ 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, EVAL_NORMAL);
+ else
+ {
+ if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+ arg2 = cast_to_fixed (VALUE_TYPE (arg1), arg2);
+ else if (ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+ error
+ ("Fixed-point values must be assigned to fixed-point variables");
+ else
+ arg2 = coerce_for_assign (VALUE_TYPE (arg1), arg2);
+ return ada_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, EVAL_NORMAL);
+ else
+ {
+ if ((ada_is_fixed_point_type (VALUE_TYPE (arg1))
+ || ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+ && VALUE_TYPE (arg1) != VALUE_TYPE (arg2))
+ error
+ ("Operands of fixed-point addition must have the same type");
+ return value_cast (VALUE_TYPE (arg1), 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, EVAL_NORMAL);
+ else
+ {
+ if ((ada_is_fixed_point_type (VALUE_TYPE (arg1))
+ || ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+ && VALUE_TYPE (arg1) != VALUE_TYPE (arg2))
+ error
+ ("Operands of fixed-point subtraction must have the same type");
+ return value_cast (VALUE_TYPE (arg1), value_sub (arg1, arg2));
+ }
+
+ case BINOP_MUL:
+ case BINOP_DIV:
+ 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, EVAL_NORMAL);
+ 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
+ {
+ if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+ arg1 = cast_from_fixed_to_double (arg1);
+ if (ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+ arg2 = cast_from_fixed_to_double (arg2);
+ return value_binop (arg1, arg2, op);
+ }
+
+ 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, EVAL_NORMAL);
+ else if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+ return value_cast (VALUE_TYPE (arg1), value_neg (arg1));
+ else
+ return value_neg (arg1);
+
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ /* case OP_UNRESOLVED_VALUE:
+ /* Only encountered when an unresolved symbol occurs in a
+ context other than a function call, in which case, it is
+ illegal. *//*
+ (*pos) += 3;
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ else
+ error ("Unexpected unresolved symbol, %s, during evaluation",
+ ada_demangle (exp->elts[pc + 2].name));
+ */
+ case OP_VAR_VALUE:
+ *pos -= 1;
+ if (noside == EVAL_SKIP)
+ {
+ *pos += 4;
+ goto nosideret;
+ }
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ *pos += 4;
+ return value_zero
+ (to_static_fixed_type
+ (static_unwrap_type (SYMBOL_TYPE (exp->elts[pc + 2].symbol))),
+ not_lval);
+ }
+ else
+ {
+ arg1 =
+ unwrap_value (evaluate_subexp_standard
+ (expect_type, exp, pos, noside));
+ return ada_to_fixed_value (VALUE_TYPE (arg1), 0,
+ VALUE_ADDRESS (arg1) +
+ VALUE_OFFSET (arg1), arg1);
+ }
+
+ 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;
+
+ argvec =
+ (struct value * *) alloca (sizeof (struct value *) * (nargs + 1));
+ for (tem = 0; tem == 0 || tem < nargs; tem += 1)
+ /* At least one element gets inserted for the type */
+ {
+ /* 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 OP_FUNCALL:
+ (*pos) += 2;
+
+ /* Allocate arg vector, including space for the function to be
+ called in argvec[0] and a terminating NULL */
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ argvec =
+ (struct value * *) alloca (sizeof (struct value *) * (nargs + 2));
+
+ /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+ /* FIXME: name should be defined in expresion.h */
+ /* if (exp->elts[*pos].opcode == OP_UNRESOLVED_VALUE)
+ error ("Unexpected unresolved symbol, %s, during evaluation",
+ ada_demangle (exp->elts[pc + 5].name));
+ */
+ if (0)
+ {
+ error ("unexpected code path, FIXME");
+ }
+ else
+ {
+ for (tem = 0; tem <= nargs; tem += 1)
+ argvec[tem] = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ argvec[tem] = 0;
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ }
+
+ if (TYPE_CODE (VALUE_TYPE (argvec[0])) == TYPE_CODE_REF)
+ argvec[0] = value_addr (argvec[0]);
+
+ if (ada_is_packed_array_type (VALUE_TYPE (argvec[0])))
+ argvec[0] = ada_coerce_to_simple_array (argvec[0]);
+
+ type = check_typedef (VALUE_TYPE (argvec[0]));
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ {
+ switch (TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (type))))
+ {
+ case TYPE_CODE_FUNC:
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ break;
+ case TYPE_CODE_ARRAY:
+ break;
+ case TYPE_CODE_STRUCT:
+ if (noside != EVAL_AVOID_SIDE_EFFECTS)
+ argvec[0] = ada_value_ind (argvec[0]);
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ break;
+ default:
+ error ("cannot subscript or call something of type `%s'",
+ ada_type_name (VALUE_TYPE (argvec[0])));
+ break;
+ }
+ }
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_FUNC:
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (TYPE_TARGET_TYPE (type));
+ return call_function_by_hand (argvec[0], nargs, argvec + 1);
+ case TYPE_CODE_STRUCT:
+ {
+ int arity = ada_array_arity (type);
+ type = ada_array_element_type (type, nargs);
+ if (type == NULL)
+ error ("cannot subscript or call a record");
+ if (arity != nargs)
+ error ("wrong number of subscripts; expecting %d", arity);
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (ada_aligned_type (type));
+ return
+ unwrap_value (ada_value_subscript
+ (argvec[0], nargs, argvec + 1));
+ }
+ case TYPE_CODE_ARRAY:
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ type = ada_array_element_type (type, nargs);
+ if (type == NULL)
+ error ("element type of array unknown");
+ else
+ return allocate_value (ada_aligned_type (type));
+ }
+ return
+ unwrap_value (ada_value_subscript
+ (ada_coerce_to_simple_array (argvec[0]),
+ nargs, argvec + 1));
+ case TYPE_CODE_PTR: /* Pointer to array */
+ type = to_fixed_array_type (TYPE_TARGET_TYPE (type), NULL, 1);
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ type = ada_array_element_type (type, nargs);
+ if (type == NULL)
+ error ("element type of array unknown");
+ else
+ return allocate_value (ada_aligned_type (type));
+ }
+ return
+ unwrap_value (ada_value_ptr_subscript (argvec[0], type,
+ nargs, argvec + 1));
+
+ default:
+ error ("Internal error in evaluate_subexp");
+ }
+
+ case TERNOP_SLICE:
+ {
+ struct value *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;
+
+ /* If this is a reference to an array, then dereference it */
+ if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_REF
+ && TYPE_TARGET_TYPE (VALUE_TYPE (array)) != NULL
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (array))) ==
+ TYPE_CODE_ARRAY
+ && !ada_is_array_descriptor (check_typedef (VALUE_TYPE (array))))
+ {
+ array = ada_coerce_ref (array);
+ }
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS &&
+ ada_is_array_descriptor (check_typedef (VALUE_TYPE (array))))
+ {
+ /* Try to dereference the array, in case it is an access to array */
+ struct type *arrType = ada_type_of_array (array, 0);
+ if (arrType != NULL)
+ array = value_at_lazy (arrType, 0, NULL);
+ }
+ if (ada_is_array_descriptor (VALUE_TYPE (array)))
+ array = ada_coerce_to_simple_array (array);
+
+ /* If at this point we have a pointer to an array, it means that
+ it is a pointer to a simple (non-ada) array. We just then
+ dereference it */
+ if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_PTR
+ && TYPE_TARGET_TYPE (VALUE_TYPE (array)) != NULL
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (array))) ==
+ TYPE_CODE_ARRAY)
+ {
+ array = ada_value_ind (array);
+ }
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ /* The following will get the bounds wrong, but only in contexts
+ where the value is not being requested (FIXME?). */
+ return array;
+ else
+ return value_slice (array, lowbound, upper - lowbound + 1);
+ }
+
+ /* FIXME: UNOP_MBR should be defined in expression.h */
+ /* case UNOP_MBR:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ type = exp->elts[pc + 1].type;
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ switch (TYPE_CODE (type))
+ {
+ default:
+ warning ("Membership test incompletely implemented; always returns true");
+ return value_from_longest (builtin_type_int, (LONGEST) 1);
+
+ case TYPE_CODE_RANGE:
+ arg2 = value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_LOW_BOUND (type));
+ arg3 = value_from_longest (builtin_type_int,
+ (LONGEST) TYPE_HIGH_BOUND (type));
+ return
+ value_from_longest (builtin_type_int,
+ (value_less (arg1,arg3)
+ || value_equal (arg1,arg3))
+ && (value_less (arg2,arg1)
+ || value_equal (arg2,arg1)));
+ }
+ */
+ /* FIXME: BINOP_MBR should be defined in expression.h */
+ /* case BINOP_MBR:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (builtin_type_int, not_lval);
+
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+
+ if (tem < 1 || tem > ada_array_arity (VALUE_TYPE (arg2)))
+ error ("invalid dimension number to '%s", "range");
+
+ arg3 = ada_array_bound (arg2, tem, 1);
+ arg2 = ada_array_bound (arg2, tem, 0);
+
+ return
+ value_from_longest (builtin_type_int,
+ (value_less (arg1,arg3)
+ || value_equal (arg1,arg3))
+ && (value_less (arg2,arg1)
+ || value_equal (arg2,arg1)));
+ */
+ /* FIXME: TERNOP_MBR should be defined in expression.h */
+ /* case TERNOP_MBR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg3 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ return
+ value_from_longest (builtin_type_int,
+ (value_less (arg1,arg3)
+ || value_equal (arg1,arg3))
+ && (value_less (arg2,arg1)
+ || value_equal (arg2,arg1)));
+ */
+ /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+ /* case OP_ATTRIBUTE:
+ *pos += 3;
+ atr = (enum ada_attribute) longest_to_int (exp->elts[pc + 2].longconst);
+ switch (atr)
+ {
+ default:
+ error ("unexpected attribute encountered");
+
+ case ATR_FIRST:
+ case ATR_LAST:
+ case ATR_LENGTH:
+ {
+ struct type* type_arg;
+ if (exp->elts[*pos].opcode == OP_TYPE)
+ {
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ arg1 = NULL;
+ type_arg = exp->elts[pc + 5].type;
+ }
+ else
+ {
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ type_arg = NULL;
+ }
+
+ if (exp->elts[*pos].opcode != OP_LONG)
+ error ("illegal operand to '%s", ada_attribute_name (atr));
+ tem = longest_to_int (exp->elts[*pos+2].longconst);
+ *pos += 4;
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (type_arg == NULL)
+ {
+ arg1 = ada_coerce_ref (arg1);
+
+ if (ada_is_packed_array_type (VALUE_TYPE (arg1)))
+ arg1 = ada_coerce_to_simple_array (arg1);
+
+ if (tem < 1 || tem > ada_array_arity (VALUE_TYPE (arg1)))
+ error ("invalid dimension number to '%s",
+ ada_attribute_name (atr));
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ type = ada_index_type (VALUE_TYPE (arg1), tem);
+ if (type == NULL)
+ error ("attempt to take bound of something that is not an array");
+ return allocate_value (type);
+ }
+
+ switch (atr)
+ {
+ default:
+ error ("unexpected attribute encountered");
+ case ATR_FIRST:
+ return ada_array_bound (arg1, tem, 0);
+ case ATR_LAST:
+ return ada_array_bound (arg1, tem, 1);
+ case ATR_LENGTH:
+ return ada_array_length (arg1, tem);
+ }
+ }
+ else if (TYPE_CODE (type_arg) == TYPE_CODE_RANGE
+ || TYPE_CODE (type_arg) == TYPE_CODE_INT)
+ {
+ struct type* range_type;
+ char* name = ada_type_name (type_arg);
+ if (name == NULL)
+ {
+ if (TYPE_CODE (type_arg) == TYPE_CODE_RANGE)
+ range_type = type_arg;
+ else
+ error ("unimplemented type attribute");
+ }
+ else
+ range_type =
+ to_fixed_range_type (name, NULL, TYPE_OBJFILE (type_arg));
+ switch (atr)
+ {
+ default:
+ error ("unexpected attribute encountered");
+ case ATR_FIRST:
+ return value_from_longest (TYPE_TARGET_TYPE (range_type),
+ TYPE_LOW_BOUND (range_type));
+ case ATR_LAST:
+ return value_from_longest (TYPE_TARGET_TYPE (range_type),
+ TYPE_HIGH_BOUND (range_type));
+ }
+ }
+ else if (TYPE_CODE (type_arg) == TYPE_CODE_ENUM)
+ {
+ switch (atr)
+ {
+ default:
+ error ("unexpected attribute encountered");
+ case ATR_FIRST:
+ return value_from_longest
+ (type_arg, TYPE_FIELD_BITPOS (type_arg, 0));
+ case ATR_LAST:
+ return value_from_longest
+ (type_arg,
+ TYPE_FIELD_BITPOS (type_arg,
+ TYPE_NFIELDS (type_arg) - 1));
+ }
+ }
+ else if (TYPE_CODE (type_arg) == TYPE_CODE_FLT)
+ error ("unimplemented type attribute");
+ else
+ {
+ LONGEST low, high;
+
+ if (ada_is_packed_array_type (type_arg))
+ type_arg = decode_packed_array_type (type_arg);
+
+ if (tem < 1 || tem > ada_array_arity (type_arg))
+ error ("invalid dimension number to '%s",
+ ada_attribute_name (atr));
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ type = ada_index_type (type_arg, tem);
+ if (type == NULL)
+ error ("attempt to take bound of something that is not an array");
+ return allocate_value (type);
+ }
+
+ switch (atr)
+ {
+ default:
+ error ("unexpected attribute encountered");
+ case ATR_FIRST:
+ low = ada_array_bound_from_type (type_arg, tem, 0, &type);
+ return value_from_longest (type, low);
+ case ATR_LAST:
+ high = ada_array_bound_from_type (type_arg, tem, 1, &type);
+ return value_from_longest (type, high);
+ case ATR_LENGTH:
+ low = ada_array_bound_from_type (type_arg, tem, 0, &type);
+ high = ada_array_bound_from_type (type_arg, tem, 1, NULL);
+ return value_from_longest (type, high-low+1);
+ }
+ }
+ }
+
+ case ATR_TAG:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return
+ value_zero (ada_tag_type (arg1), not_lval);
+
+ return ada_value_tag (arg1);
+
+ case ATR_MIN:
+ case ATR_MAX:
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (VALUE_TYPE (arg1), not_lval);
+ else
+ return value_binop (arg1, arg2,
+ atr == ATR_MIN ? BINOP_MIN : BINOP_MAX);
+
+ case ATR_MODULUS:
+ {
+ struct type* type_arg = exp->elts[pc + 5].type;
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ *pos += 4;
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (! ada_is_modular_type (type_arg))
+ error ("'modulus must be applied to modular type");
+
+ return value_from_longest (TYPE_TARGET_TYPE (type_arg),
+ ada_modulus (type_arg));
+ }
+
+
+ case ATR_POS:
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (builtin_type_ada_int, not_lval);
+ else
+ return value_pos_atr (arg1);
+
+ case ATR_SIZE:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (builtin_type_ada_int, not_lval);
+ else
+ return value_from_longest (builtin_type_ada_int,
+ TARGET_CHAR_BIT
+ * TYPE_LENGTH (VALUE_TYPE (arg1)));
+
+ case ATR_VAL:
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ type = exp->elts[pc + 5].type;
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (type, not_lval);
+ else
+ return value_val_atr (type, arg1);
+ } */
+ case BINOP_EXP:
+ 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 unwrap_value (value_x_binop (arg1, arg2, op, OP_NULL,
+ EVAL_NORMAL));
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (VALUE_TYPE (arg1), not_lval);
+ else
+ return value_binop (arg1, arg2, op);
+
+ case UNOP_PLUS:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (op, arg1))
+ return unwrap_value (value_x_unop (arg1, op, EVAL_NORMAL));
+ else
+ return arg1;
+
+ case UNOP_ABS:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (value_less (arg1, value_zero (VALUE_TYPE (arg1), not_lval)))
+ return value_neg (arg1);
+ else
+ return 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;
+ type = check_typedef (VALUE_TYPE (arg1));
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ if (ada_is_array_descriptor (type))
+ /* GDB allows dereferencing GNAT array descriptors. */
+ {
+ struct type *arrType = ada_type_of_array (arg1, 0);
+ if (arrType == NULL)
+ error ("Attempt to dereference null array pointer.");
+ return value_at_lazy (arrType, 0, NULL);
+ }
+ else 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
+ (to_static_fixed_type
+ (ada_aligned_type (check_typedef (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.");
+ }
+ arg1 = ada_coerce_ref (arg1);
+ type = check_typedef (VALUE_TYPE (arg1));
+
+ if (ada_is_array_descriptor (type))
+ /* GDB allows dereferencing GNAT array descriptors. */
+ return ada_coerce_to_simple_array (arg1);
+ else
+ return ada_value_ind (arg1);
+
+ 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 (ada_aligned_type
+ (ada_lookup_struct_elt_type (VALUE_TYPE (arg1),
+ &exp->elts[pc +
+ 2].string,
+ 0, NULL)),
+ lval_memory);
+ else
+ return unwrap_value (ada_value_struct_elt (arg1,
+ &exp->elts[pc + 2].string,
+ "record"));
+ case OP_TYPE:
+ /* The value is not supposed to be used. This is here to make it
+ easier to accommodate expressions that contain types. */
+ (*pos) += 2;
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (builtin_type_void);
+ else
+ error ("Attempt to use a type name as an expression");
+
+ 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 (ada_aligned_type
+ (ada_lookup_struct_elt_type (VALUE_TYPE (arg1),
+ &exp->elts[pc +
+ 2].string,
+ 0, NULL)),
+ lval_memory);
+ else
+ return unwrap_value (ada_value_struct_elt (arg1,
+ &exp->elts[pc + 2].string,
+ "record access"));
+ }
+
+nosideret:
+ return value_from_longest (builtin_type_long, (LONGEST) 1);
+}
+
+
+ /* Fixed point */
+
+/* If TYPE encodes an Ada fixed-point type, return the suffix of the
+ type name that encodes the 'small and 'delta information.
+ Otherwise, return NULL. */
+
+static const char *
+fixed_type_info (struct type *type)
+{
+ const char *name = ada_type_name (type);
+ enum type_code code = (type == NULL) ? TYPE_CODE_UNDEF : TYPE_CODE (type);
+
+ if ((code == TYPE_CODE_INT || code == TYPE_CODE_RANGE) && name != NULL)
+ {
+ const char *tail = strstr (name, "___XF_");
+ if (tail == NULL)
+ return NULL;
+ else
+ return tail + 5;
+ }
+ else if (code == TYPE_CODE_RANGE && TYPE_TARGET_TYPE (type) != type)
+ return fixed_type_info (TYPE_TARGET_TYPE (type));
+ else
+ return NULL;
+}
+
+/* Returns non-zero iff TYPE represents an Ada fixed-point type. */
+
+int
+ada_is_fixed_point_type (struct type *type)
+{
+ return fixed_type_info (type) != NULL;
+}
+
+/* Assuming that TYPE is the representation of an Ada fixed-point
+ type, return its delta, or -1 if the type is malformed and the
+ delta cannot be determined. */
+
+DOUBLEST
+ada_delta (struct type *type)
+{
+ const char *encoding = fixed_type_info (type);
+ long num, den;
+
+ if (sscanf (encoding, "_%ld_%ld", &num, &den) < 2)
+ return -1.0;
+ else
+ return (DOUBLEST) num / (DOUBLEST) den;
+}
+
+/* Assuming that ada_is_fixed_point_type (TYPE), return the scaling
+ factor ('SMALL value) associated with the type. */
+
+static DOUBLEST
+scaling_factor (struct type *type)
+{
+ const char *encoding = fixed_type_info (type);
+ unsigned long num0, den0, num1, den1;
+ int n;
+
+ n = sscanf (encoding, "_%lu_%lu_%lu_%lu", &num0, &den0, &num1, &den1);
+
+ if (n < 2)
+ return 1.0;
+ else if (n == 4)
+ return (DOUBLEST) num1 / (DOUBLEST) den1;
+ else
+ return (DOUBLEST) num0 / (DOUBLEST) den0;
+}
+
+
+/* Assuming that X is the representation of a value of fixed-point
+ type TYPE, return its floating-point equivalent. */
+
+DOUBLEST
+ada_fixed_to_float (struct type *type, LONGEST x)
+{
+ return (DOUBLEST) x *scaling_factor (type);
+}
+
+/* The representation of a fixed-point value of type TYPE
+ corresponding to the value X. */
+
+LONGEST
+ada_float_to_fixed (struct type *type, DOUBLEST x)
+{
+ return (LONGEST) (x / scaling_factor (type) + 0.5);
+}
+
+
+ /* VAX floating formats */
+
+/* Non-zero iff TYPE represents one of the special VAX floating-point
+ types. */
+int
+ada_is_vax_floating_type (struct type *type)
+{
+ int name_len =
+ (ada_type_name (type) == NULL) ? 0 : strlen (ada_type_name (type));
+ return
+ name_len > 6
+ && (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_RANGE)
+ && DEPRECATED_STREQN (ada_type_name (type) + name_len - 6, "___XF", 5);
+}
+
+/* The type of special VAX floating-point type this is, assuming
+ ada_is_vax_floating_point */
+int
+ada_vax_float_type_suffix (struct type *type)
+{
+ return ada_type_name (type)[strlen (ada_type_name (type)) - 1];
+}
+
+/* A value representing the special debugging function that outputs
+ VAX floating-point values of the type represented by TYPE. Assumes
+ ada_is_vax_floating_type (TYPE). */
+struct value *
+ada_vax_float_print_function (struct type *type)
+{
+ switch (ada_vax_float_type_suffix (type))
+ {
+ case 'F':
+ return get_var_value ("DEBUG_STRING_F", 0);
+ case 'D':
+ return get_var_value ("DEBUG_STRING_D", 0);
+ case 'G':
+ return get_var_value ("DEBUG_STRING_G", 0);
+ default:
+ error ("invalid VAX floating-point type");
+ }
+}
+
+
+ /* Range types */
+
+/* Scan STR beginning at position K for a discriminant name, and
+ return the value of that discriminant field of DVAL in *PX. If
+ PNEW_K is not null, put the position of the character beyond the
+ name scanned in *PNEW_K. Return 1 if successful; return 0 and do
+ not alter *PX and *PNEW_K if unsuccessful. */
+
+static int
+scan_discrim_bound (char *str, int k, struct value *dval, LONGEST * px,
+ int *pnew_k)
+{
+ static char *bound_buffer = NULL;
+ static size_t bound_buffer_len = 0;
+ char *bound;
+ char *pend;
+ struct value *bound_val;
+
+ if (dval == NULL || str == NULL || str[k] == '\0')
+ return 0;
+
+ pend = strstr (str + k, "__");
+ if (pend == NULL)
+ {
+ bound = str + k;
+ k += strlen (bound);
+ }
+ else
+ {
+ GROW_VECT (bound_buffer, bound_buffer_len, pend - (str + k) + 1);
+ bound = bound_buffer;
+ strncpy (bound_buffer, str + k, pend - (str + k));
+ bound[pend - (str + k)] = '\0';
+ k = pend - str;
+ }
+
+ bound_val = ada_search_struct_field (bound, dval, 0, VALUE_TYPE (dval));
+ if (bound_val == NULL)
+ return 0;
+
+ *px = value_as_long (bound_val);
+ if (pnew_k != NULL)
+ *pnew_k = k;
+ return 1;
+}
+
+/* Value of variable named NAME in the current environment. If
+ no such variable found, then if ERR_MSG is null, returns 0, and
+ otherwise causes an error with message ERR_MSG. */
+static struct value *
+get_var_value (char *name, char *err_msg)
+{
+ struct symbol **syms;
+ struct block **blocks;
+ int nsyms;
+
+ nsyms =
+ ada_lookup_symbol_list (name, get_selected_block (NULL), VAR_DOMAIN,
+ &syms, &blocks);
+
+ if (nsyms != 1)
+ {
+ if (err_msg == NULL)
+ return 0;
+ else
+ error ("%s", err_msg);
+ }
+
+ return value_of_variable (syms[0], blocks[0]);
+}
+
+/* Value of integer variable named NAME in the current environment. If
+ no such variable found, then if ERR_MSG is null, returns 0, and sets
+ *FLAG to 0. If successful, sets *FLAG to 1. */
+LONGEST
+get_int_var_value (char *name, char *err_msg, int *flag)
+{
+ struct value *var_val = get_var_value (name, err_msg);
+
+ if (var_val == 0)
+ {
+ if (flag != NULL)
+ *flag = 0;
+ return 0;
+ }
+ else
+ {
+ if (flag != NULL)
+ *flag = 1;
+ return value_as_long (var_val);
+ }
+}
+
+
+/* Return a range type whose base type is that of the range type named
+ NAME in the current environment, and whose bounds are calculated
+ from NAME according to the GNAT range encoding conventions.
+ Extract discriminant values, if needed, from DVAL. If a new type
+ must be created, allocate in OBJFILE's space. The bounds
+ information, in general, is encoded in NAME, the base type given in
+ the named range type. */
+
+static struct type *
+to_fixed_range_type (char *name, struct value *dval, struct objfile *objfile)
+{
+ struct type *raw_type = ada_find_any_type (name);
+ struct type *base_type;
+ LONGEST low, high;
+ char *subtype_info;
+
+ if (raw_type == NULL)
+ base_type = builtin_type_int;
+ else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE)
+ base_type = TYPE_TARGET_TYPE (raw_type);
+ else
+ base_type = raw_type;
+
+ subtype_info = strstr (name, "___XD");
+ if (subtype_info == NULL)
+ return raw_type;
+ else
+ {
+ static char *name_buf = NULL;
+ static size_t name_len = 0;
+ int prefix_len = subtype_info - name;
+ LONGEST L, U;
+ struct type *type;
+ char *bounds_str;
+ int n;
+
+ GROW_VECT (name_buf, name_len, prefix_len + 5);
+ strncpy (name_buf, name, prefix_len);
+ name_buf[prefix_len] = '\0';
+
+ subtype_info += 5;
+ bounds_str = strchr (subtype_info, '_');
+ n = 1;
+
+ if (*subtype_info == 'L')
+ {
+ if (!ada_scan_number (bounds_str, n, &L, &n)
+ && !scan_discrim_bound (bounds_str, n, dval, &L, &n))
+ return raw_type;
+ if (bounds_str[n] == '_')
+ n += 2;
+ else if (bounds_str[n] == '.') /* FIXME? SGI Workshop kludge. */
+ n += 1;
+ subtype_info += 1;
+ }
+ else
+ {
+ strcpy (name_buf + prefix_len, "___L");
+ L = get_int_var_value (name_buf, "Index bound unknown.", NULL);
+ }
+
+ if (*subtype_info == 'U')
+ {
+ if (!ada_scan_number (bounds_str, n, &U, &n)
+ && !scan_discrim_bound (bounds_str, n, dval, &U, &n))
+ return raw_type;
+ }
+ else
+ {
+ strcpy (name_buf + prefix_len, "___U");
+ U = get_int_var_value (name_buf, "Index bound unknown.", NULL);
+ }
+
+ if (objfile == NULL)
+ objfile = TYPE_OBJFILE (base_type);
+ type = create_range_type (alloc_type (objfile), base_type, L, U);
+ TYPE_NAME (type) = name;
+ return type;
+ }
+}
+
+/* True iff NAME is the name of a range type. */
+int
+ada_is_range_type_name (const char *name)
+{
+ return (name != NULL && strstr (name, "___XD"));
+}
+
+
+ /* Modular types */
+
+/* True iff TYPE is an Ada modular type. */
+int
+ada_is_modular_type (struct type *type)
+{
+ /* FIXME: base_type should be declared in gdbtypes.h, implemented in
+ valarith.c */
+ struct type *subranged_type; /* = base_type (type); */
+
+ return (subranged_type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE
+ && TYPE_CODE (subranged_type) != TYPE_CODE_ENUM
+ && TYPE_UNSIGNED (subranged_type));
+}
+
+/* Assuming ada_is_modular_type (TYPE), the modulus of TYPE. */
+LONGEST
+ada_modulus (struct type * type)
+{
+ return TYPE_HIGH_BOUND (type) + 1;
+}
+
+
+
+ /* Operators */
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+static const struct op_print ada_op_print_tab[] = {
+ {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"or else", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+ {"and then", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+ {"or", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+ {"xor", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+ {"and", 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_CONCAT, PREC_ADD, 0},
+ {"*", BINOP_MUL, PREC_MUL, 0},
+ {"/", BINOP_DIV, PREC_MUL, 0},
+ {"rem", BINOP_REM, PREC_MUL, 0},
+ {"mod", BINOP_MOD, PREC_MUL, 0},
+ {"**", BINOP_EXP, PREC_REPEAT, 0},
+ {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {"+", UNOP_PLUS, PREC_PREFIX, 0},
+ {"not ", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"not ", UNOP_COMPLEMENT, PREC_PREFIX, 0},
+ {"abs ", UNOP_ABS, PREC_PREFIX, 0},
+ {".all", UNOP_IND, PREC_SUFFIX, 1}, /* FIXME: postfix .ALL */
+ {"'access", UNOP_ADDR, PREC_SUFFIX, 1}, /* FIXME: postfix 'ACCESS */
+ {NULL, 0, 0, 0}
+};
+
+ /* Assorted Types and Interfaces */
+
+struct type *builtin_type_ada_int;
+struct type *builtin_type_ada_short;
+struct type *builtin_type_ada_long;
+struct type *builtin_type_ada_long_long;
+struct type *builtin_type_ada_char;
+struct type *builtin_type_ada_float;
+struct type *builtin_type_ada_double;
+struct type *builtin_type_ada_long_double;
+struct type *builtin_type_ada_natural;
+struct type *builtin_type_ada_positive;
+struct type *builtin_type_ada_system_address;
+
+struct type **const (ada_builtin_types[]) =
+{
+
+ &builtin_type_ada_int,
+ &builtin_type_ada_long,
+ &builtin_type_ada_short,
+ &builtin_type_ada_char,
+ &builtin_type_ada_float,
+ &builtin_type_ada_double,
+ &builtin_type_ada_long_long,
+ &builtin_type_ada_long_double,
+ &builtin_type_ada_natural, &builtin_type_ada_positive,
+ /* The following types are carried over from C for convenience. */
+&builtin_type_int,
+ &builtin_type_long,
+ &builtin_type_short,
+ &builtin_type_char,
+ &builtin_type_float,
+ &builtin_type_double,
+ &builtin_type_long_long,
+ &builtin_type_void,
+ &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};
+
+/* Not really used, but needed in the ada_language_defn. */
+static void
+emit_char (int c, struct ui_file *stream, int quoter)
+{
+ ada_emit_char (c, stream, quoter, 1);
+}
+
+const struct language_defn ada_language_defn = {
+ "ada", /* Language name */
+ /* language_ada, */
+ language_unknown,
+ /* FIXME: language_ada should be defined in defs.h */
+ ada_builtin_types,
+ range_check_off,
+ type_check_off,
+ case_sensitive_on, /* Yes, Ada is case-insensitive, but
+ * that's not quite what this means. */
+ ada_parse,
+ ada_error,
+ ada_evaluate_subexp,
+ ada_printchar, /* Print a character constant */
+ ada_printstr, /* Function to print string constant */
+ emit_char, /* Function to print single char (not used) */
+ ada_create_fundamental_type, /* Create fundamental type in this language */
+ ada_print_type, /* Print a type using appropriate syntax */
+ ada_val_print, /* Print a value using appropriate syntax */
+ ada_value_print, /* Print a top-level value */
+ NULL, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* Binary format info */
+#if 0
+ {"8#%lo#", "8#", "o", "#"}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"16#%lx#", "16#", "x", "#"}, /* Hex format info */
+#else
+ /* Copied from c-lang.c. */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+#endif
+ ada_op_print_tab, /* expression operators for printing */
+ 1, /* c-style arrays (FIXME?) */
+ 0, /* String lower bound (FIXME?) */
+ &builtin_type_ada_char,
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+void
+_initialize_ada_language (void)
+{
+ builtin_type_ada_int =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "integer", (struct objfile *) NULL);
+ builtin_type_ada_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long_integer", (struct objfile *) NULL);
+ builtin_type_ada_short =
+ init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short_integer", (struct objfile *) NULL);
+ builtin_type_ada_char =
+ init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "character", (struct objfile *) NULL);
+ builtin_type_ada_float =
+ init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0, "float", (struct objfile *) NULL);
+ builtin_type_ada_double =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long_float", (struct objfile *) NULL);
+ builtin_type_ada_long_long =
+ init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long_long_integer", (struct objfile *) NULL);
+ builtin_type_ada_long_double =
+ init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long_long_float", (struct objfile *) NULL);
+ builtin_type_ada_natural =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "natural", (struct objfile *) NULL);
+ builtin_type_ada_positive =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "positive", (struct objfile *) NULL);
+
+
+ builtin_type_ada_system_address =
+ lookup_pointer_type (init_type (TYPE_CODE_VOID, 1, 0, "void",
+ (struct objfile *) NULL));
+ TYPE_NAME (builtin_type_ada_system_address) = "system__address";
+
+ add_language (&ada_language_defn);
+
+ add_show_from_set
+ (add_set_cmd ("varsize-limit", class_support, var_uinteger,
+ (char *) &varsize_limit,
+ "Set maximum bytes in dynamic-sized object.",
+ &setlist), &showlist);
+ varsize_limit = 65536;
+
+ add_com ("begin", class_breakpoint, begin_command,
+ "Start the debugged program, stopping at the beginning of the\n\
+main program. You may specify command-line arguments to give it, as for\n\
+the \"run\" command (q.v.).");
+}
+
+
+/* Create a fundamental Ada 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 */
+
+static struct type *
+ada_create_fundamental_type (struct objfile *objfile, int typeid)
+{
+ 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 "<?type?>". 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, "<?type?>", objfile);
+ warning ("internal error: no Ada 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, "character", 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_integer", objfile);
+ break;
+ case FT_SIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "short_integer", objfile);
+ 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, "integer", 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_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_integer", objfile);
+ break;
+ case FT_SIGNED_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long_integer", objfile);
+ 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_integer", objfile);
+ break;
+ case FT_SIGNED_LONG_LONG:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+ 0, "long_long_integer", 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, "long_float", objfile);
+ break;
+ case FT_EXT_PREC_FLOAT:
+ type = init_type (TYPE_CODE_FLT,
+ TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long_long_float", objfile);
+ break;
+ }
+ return (type);
+}
+
+void
+ada_dump_symtab (struct symtab *s)
+{
+ int i;
+ fprintf (stderr, "New symtab: [\n");
+ fprintf (stderr, " Name: %s/%s;\n",
+ s->dirname ? s->dirname : "?", s->filename ? s->filename : "?");
+ fprintf (stderr, " Format: %s;\n", s->debugformat);
+ if (s->linetable != NULL)
+ {
+ fprintf (stderr, " Line table (section %d):\n", s->block_line_section);
+ for (i = 0; i < s->linetable->nitems; i += 1)
+ {
+ struct linetable_entry *e = s->linetable->item + i;
+ fprintf (stderr, " %4ld: %8lx\n", (long) e->line, (long) e->pc);
+ }
+ }
+ fprintf (stderr, "]\n");
+}
diff --git a/contrib/gdb/gdb/ada-lang.h b/contrib/gdb/gdb/ada-lang.h
new file mode 100644
index 0000000..54e56bb
--- /dev/null
+++ b/contrib/gdb/gdb/ada-lang.h
@@ -0,0 +1,392 @@
+/* Ada language support definitions for GDB, the GNU debugger.
+ Copyright 1992, 1997 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You 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. */
+
+#if !defined (ADA_LANG_H)
+#define ADA_LANG_H 1
+
+struct partial_symbol;
+
+#include "value.h"
+#include "gdbtypes.h"
+
+struct block;
+
+/* A macro to reorder the bytes of an address depending on the
+ endiannes of the target. */
+#define EXTRACT_ADDRESS(x) ((void *) extract_unsigned_integer (&(x), sizeof (x)))
+/* A macro to reorder the bytes of an int depending on the endiannes
+ of the target */
+#define EXTRACT_INT(x) ((int) extract_signed_integer (&(x), sizeof (x)))
+
+/* Chain of cleanups for arguments of OP_UNRESOLVED_VALUE names. Created in
+ yyparse and freed in ada_resolve. */
+extern struct cleanup *unresolved_names;
+
+/* Corresponding mangled/demangled names and opcodes for Ada user-definable
+ operators. */
+struct ada_opname_map
+{
+ const char *mangled;
+ const char *demangled;
+ enum exp_opcode op;
+};
+
+/* Table of Ada operators in mangled and demangled forms. */
+/* Defined in ada-lang.c */
+extern const struct ada_opname_map ada_opname_table[];
+
+/* The maximum number of tasks known to the Ada runtime */
+extern const int MAX_NUMBER_OF_KNOWN_TASKS;
+
+/* Identifiers for Ada attributes that need special processing. Be sure
+ to update the table attribute_names in ada-lang.c whenever you change this.
+ */
+
+enum ada_attribute
+{
+ /* Invalid attribute for error checking. */
+ ATR_INVALID,
+
+ ATR_FIRST,
+ ATR_LAST,
+ ATR_LENGTH,
+ ATR_IMAGE,
+ ATR_IMG,
+ ATR_MAX,
+ ATR_MIN,
+ ATR_MODULUS,
+ ATR_POS,
+ ATR_SIZE,
+ ATR_TAG,
+ ATR_VAL,
+
+ /* Dummy last attribute. */
+ ATR_END
+};
+
+enum task_states
+{
+ Unactivated,
+ Runnable,
+ Terminated,
+ Activator_Sleep,
+ Acceptor_Sleep,
+ Entry_Caller_Sleep,
+ Async_Select_Sleep,
+ Delay_Sleep,
+ Master_Completion_Sleep,
+ Master_Phase_2_Sleep
+};
+
+extern char *ada_task_states[];
+
+typedef struct
+{
+ char *P_ARRAY;
+ int *P_BOUNDS;
+}
+fat_string;
+
+typedef struct entry_call
+{
+ void *self;
+}
+ *entry_call_link;
+
+struct task_fields
+{
+ int entry_num;
+#if (defined (VXWORKS_TARGET) || !defined (i386)) \
+ && !(defined (VXWORKS_TARGET) && defined (M68K_TARGET))
+ int pad1;
+#endif
+ char state;
+#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET))
+ char pad_8bits;
+#endif
+ void *parent;
+ int priority;
+ int current_priority;
+ fat_string image;
+ entry_call_link call;
+#if (defined (sun) && defined (__SVR4)) && !defined (VXWORKS_TARGET)
+ int pad2;
+ unsigned thread;
+ unsigned lwp;
+#else
+ void *thread;
+ void *lwp;
+#endif
+}
+#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET))
+__attribute__ ((packed))
+#endif
+ ;
+
+struct task_entry
+{
+ void *task_id;
+ int task_num;
+ int known_tasks_index;
+ struct task_entry *next_task;
+ void *thread;
+ void *lwp;
+ int stack_per;
+};
+
+extern struct type *builtin_type_ada_int;
+extern struct type *builtin_type_ada_short;
+extern struct type *builtin_type_ada_long;
+extern struct type *builtin_type_ada_long_long;
+extern struct type *builtin_type_ada_char;
+extern struct type *builtin_type_ada_float;
+extern struct type *builtin_type_ada_double;
+extern struct type *builtin_type_ada_long_double;
+extern struct type *builtin_type_ada_natural;
+extern struct type *builtin_type_ada_positive;
+extern struct type *builtin_type_ada_system_address;
+
+/* Assuming V points to an array of S objects, make sure that it contains at
+ least M objects, updating V and S as necessary. */
+
+#define GROW_VECT(v, s, m) \
+ if ((s) < (m)) grow_vect ((void**) &(v), &(s), (m), sizeof(*(v)));
+
+extern void grow_vect (void **, size_t *, size_t, int);
+
+extern int ada_parse (void); /* Defined in ada-exp.y */
+
+extern void ada_error (char *); /* Defined in ada-exp.y */
+
+ /* Defined in ada-typeprint.c */
+extern void ada_print_type (struct type *, char *, struct ui_file *, int,
+ int);
+
+extern int ada_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+extern int ada_value_print (struct value *, struct ui_file *, int,
+ enum val_prettyprint);
+
+ /* Defined in ada-lang.c */
+
+extern struct value *value_from_contents_and_address (struct type *, char *,
+ CORE_ADDR);
+
+extern void ada_emit_char (int, struct ui_file *, int, int);
+
+extern void ada_printchar (int, struct ui_file *);
+
+extern void ada_printstr (struct ui_file *, char *, unsigned int, int, int);
+
+extern void ada_convert_actuals (struct value *, int, struct value **,
+ CORE_ADDR *);
+
+extern struct value *ada_value_subscript (struct value *, int,
+ struct value **);
+
+extern struct type *ada_array_element_type (struct type *, int);
+
+extern int ada_array_arity (struct type *);
+
+struct type *ada_type_of_array (struct value *, int);
+
+extern struct value *ada_coerce_to_simple_array (struct value *);
+
+extern struct value *ada_coerce_to_simple_array_ptr (struct value *);
+
+extern int ada_is_simple_array (struct type *);
+
+extern int ada_is_array_descriptor (struct type *);
+
+extern int ada_is_bogus_array_descriptor (struct type *);
+
+extern struct type *ada_index_type (struct type *, int);
+
+extern struct value *ada_array_bound (struct value *, int, int);
+
+extern int ada_lookup_symbol_list (const char *, struct block *,
+ domain_enum, struct symbol ***,
+ struct block ***);
+
+extern char *ada_fold_name (const char *);
+
+extern struct symbol *ada_lookup_symbol (const char *, struct block *,
+ domain_enum);
+
+extern struct minimal_symbol *ada_lookup_minimal_symbol (const char *);
+
+extern void ada_resolve (struct expression **, struct type *);
+
+extern int ada_resolve_function (struct symbol **, struct block **, int,
+ struct value **, int, const char *,
+ struct type *);
+
+extern void ada_fill_in_ada_prototype (struct symbol *);
+
+extern int user_select_syms (struct symbol **, struct block **, int, int);
+
+extern int get_selections (int *, int, int, int, char *);
+
+extern char *ada_start_decode_line_1 (char *);
+
+extern struct symtabs_and_lines ada_finish_decode_line_1 (char **,
+ struct symtab *,
+ int, char ***);
+
+extern int ada_scan_number (const char *, int, LONGEST *, int *);
+
+extern struct type *ada_parent_type (struct type *);
+
+extern int ada_is_ignored_field (struct type *, int);
+
+extern int ada_is_packed_array_type (struct type *);
+
+extern struct value *ada_value_primitive_packed_val (struct value *, char *,
+ long, int, int,
+ struct type *);
+
+extern struct type *ada_coerce_to_simple_array_type (struct type *);
+
+extern int ada_is_character_type (struct type *);
+
+extern int ada_is_string_type (struct type *);
+
+extern int ada_is_tagged_type (struct type *);
+
+extern struct type *ada_tag_type (struct value *);
+
+extern struct value *ada_value_tag (struct value *);
+
+extern int ada_is_parent_field (struct type *, int);
+
+extern int ada_is_wrapper_field (struct type *, int);
+
+extern int ada_is_variant_part (struct type *, int);
+
+extern struct type *ada_variant_discrim_type (struct type *, struct type *);
+
+extern int ada_is_others_clause (struct type *, int);
+
+extern int ada_in_variant (LONGEST, struct type *, int);
+
+extern char *ada_variant_discrim_name (struct type *);
+
+extern struct type *ada_lookup_struct_elt_type (struct type *, char *, int,
+ int *);
+
+extern struct value *ada_value_struct_elt (struct value *, char *, char *);
+
+extern struct value *ada_search_struct_field (char *, struct value *, int,
+ struct type *);
+
+extern int ada_is_aligner_type (struct type *);
+
+extern struct type *ada_aligned_type (struct type *);
+
+extern char *ada_aligned_value_addr (struct type *, char *);
+
+extern const char *ada_attribute_name (int);
+
+extern int ada_is_fixed_point_type (struct type *);
+
+extern DOUBLEST ada_delta (struct type *);
+
+extern DOUBLEST ada_fixed_to_float (struct type *, LONGEST);
+
+extern LONGEST ada_float_to_fixed (struct type *, DOUBLEST);
+
+extern int ada_is_vax_floating_type (struct type *);
+
+extern int ada_vax_float_type_suffix (struct type *);
+
+extern struct value *ada_vax_float_print_function (struct type *);
+
+extern struct type *ada_system_address_type (void);
+
+extern int ada_which_variant_applies (struct type *, struct type *, char *);
+
+extern struct value *ada_to_fixed_value (struct type *, char *, CORE_ADDR,
+ struct value *);
+
+extern struct type *ada_to_fixed_type (struct type *, char *, CORE_ADDR,
+ struct value *);
+
+extern int ada_name_prefix_len (const char *);
+
+extern char *ada_type_name (struct type *);
+
+extern struct type *ada_find_parallel_type (struct type *,
+ const char *suffix);
+
+extern LONGEST get_int_var_value (char *, char *, int *);
+
+extern struct type *ada_find_any_type (const char *name);
+
+extern int ada_prefer_type (struct type *, struct type *);
+
+extern struct type *ada_get_base_type (struct type *);
+
+extern struct type *ada_completed_type (struct type *);
+
+extern char *ada_mangle (const char *);
+
+extern const char *ada_enum_name (const char *);
+
+extern int ada_is_modular_type (struct type *);
+
+extern LONGEST ada_modulus (struct type *);
+
+extern struct value *ada_value_ind (struct value *);
+
+extern void ada_print_scalar (struct type *, LONGEST, struct ui_file *);
+
+extern int ada_is_range_type_name (const char *);
+
+extern const char *ada_renaming_type (struct type *);
+
+extern int ada_is_object_renaming (struct symbol *);
+
+extern const char *ada_simple_renamed_entity (struct symbol *);
+
+extern char *ada_breakpoint_rewrite (char *, int *);
+
+/* Tasking-related: ada-tasks.c */
+
+extern int valid_task_id (int);
+
+extern int get_current_task (void);
+
+extern void init_task_list (void);
+
+extern void *get_self_id (void);
+
+extern int get_current_task (void);
+
+extern int get_entry_number (void *);
+
+extern void ada_report_exception_break (struct breakpoint *);
+
+extern int ada_maybe_exception_partial_symbol (struct partial_symbol *sym);
+
+extern int ada_is_exception_sym (struct symbol *sym);
+
+
+#endif
diff --git a/contrib/gdb/gdb/ada-lex.l b/contrib/gdb/gdb/ada-lex.l
new file mode 100644
index 0000000..139e3aa
--- /dev/null
+++ b/contrib/gdb/gdb/ada-lex.l
@@ -0,0 +1,928 @@
+/* FLEX lexer for Ada expressions, for GDB.
+ Copyright (C) 1994, 1997, 2000
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You 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 converted version of this file is to be included in ada-exp.y, */
+/* the Ada parser for gdb. The function yylex obtains characters from */
+/* the global pointer lexptr. It returns a syntactic category for */
+/* each successive token and places a semantic value into yylval */
+/* (ada-lval), defined by the parser. */
+
+/* Run flex with (at least) the -i option (case-insensitive), and the -I */
+/* option (interactive---no unnecessary lookahead). */
+
+DIG [0-9]
+NUM10 ({DIG}({DIG}|_)*)
+HEXDIG [0-9a-f]
+NUM16 ({HEXDIG}({HEXDIG}|_)*)
+OCTDIG [0-7]
+LETTER [a-z_]
+ID ({LETTER}({LETTER}|{DIG})*|"<"{LETTER}({LETTER}|{DIG})*">")
+WHITE [ \t\n]
+TICK ("'"{WHITE}*)
+GRAPHIC [a-z0-9 #&'()*+,-./:;<>=_|!$%?@\[\]\\^`{}~]
+OPER ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs")
+
+EXP (e[+-]{NUM10})
+POSEXP (e"+"?{NUM10})
+
+%{
+#define NUMERAL_WIDTH 256
+#define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
+
+/* Temporary staging for numeric literals. */
+static char numbuf[NUMERAL_WIDTH];
+ static void canonicalizeNumeral (char* s1, const char*);
+static int processInt (const char*, const char*, const char*);
+static int processReal (const char*);
+static int processId (const char*, int);
+static int processAttribute (const char*);
+static int find_dot_all (const char*);
+
+#undef YY_DECL
+#define YY_DECL static int yylex ( void )
+
+#undef YY_INPUT
+#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
+ if ( *lexptr == '\000' ) \
+ (RESULT) = YY_NULL; \
+ else \
+ { \
+ *(BUF) = *lexptr; \
+ (RESULT) = 1; \
+ lexptr += 1; \
+ }
+
+static char *tempbuf = NULL;
+static int tempbufsize = 0;
+static int tempbuf_len;
+static struct block* left_block_context;
+
+static void resize_tempbuf (unsigned int);
+
+static void block_lookup (char*, char*);
+
+static int name_lookup (char*, char*, int*);
+
+static int find_dot_all (const char*);
+
+%}
+
+%s IN_STRING BEFORE_QUAL_QUOTE
+
+%%
+
+{WHITE} { }
+
+"--".* { yyterminate(); }
+
+{NUM10}{POSEXP} {
+ canonicalizeNumeral (numbuf, yytext);
+ return processInt (NULL, numbuf, strrchr(numbuf, 'e')+1);
+ }
+
+{NUM10} {
+ canonicalizeNumeral (numbuf, yytext);
+ return processInt (NULL, numbuf, NULL);
+ }
+
+{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
+ canonicalizeNumeral (numbuf, yytext);
+ return processInt (numbuf,
+ strchr (numbuf, '#') + 1,
+ strrchr(numbuf, '#') + 1);
+ }
+
+{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#" {
+ canonicalizeNumeral (numbuf, yytext);
+ return processInt (numbuf, strchr (numbuf, '#') + 1, NULL);
+ }
+
+"0x"{HEXDIG}+ {
+ canonicalizeNumeral (numbuf, yytext+2);
+ return processInt ("16#", numbuf, NULL);
+ }
+
+
+{NUM10}"."{NUM10}{EXP} {
+ canonicalizeNumeral (numbuf, yytext);
+ return processReal (numbuf);
+ }
+
+{NUM10}"."{NUM10} {
+ canonicalizeNumeral (numbuf, yytext);
+ return processReal (numbuf);
+ }
+
+{NUM10}"#"{NUM16}"."{NUM16}"#"{EXP} {
+ error ("Based real literals not implemented yet.");
+ }
+
+{NUM10}"#"{NUM16}"."{NUM16}"#" {
+ error ("Based real literals not implemented yet.");
+ }
+
+<INITIAL>"'"({GRAPHIC}|\")"'" {
+ yylval.typed_val.type = builtin_type_ada_char;
+ yylval.typed_val.val = yytext[1];
+ return CHARLIT;
+ }
+
+<INITIAL>"'[\""{HEXDIG}{2}"\"]'" {
+ int v;
+ yylval.typed_val.type = builtin_type_ada_char;
+ sscanf (yytext+3, "%2x", &v);
+ yylval.typed_val.val = v;
+ return CHARLIT;
+ }
+
+\"{OPER}\"/{WHITE}*"(" { return processId (yytext, yyleng); }
+
+<INITIAL>\" {
+ tempbuf_len = 0;
+ BEGIN IN_STRING;
+ }
+
+<IN_STRING>{GRAPHIC}*\" {
+ resize_tempbuf (yyleng+tempbuf_len);
+ strncpy (tempbuf+tempbuf_len, yytext, yyleng-1);
+ tempbuf_len += yyleng-1;
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbuf_len;
+ BEGIN INITIAL;
+ return STRING;
+ }
+
+<IN_STRING>{GRAPHIC}*"[\""{HEXDIG}{2}"\"]" {
+ int n;
+ resize_tempbuf (yyleng-5+tempbuf_len+1);
+ strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
+ sscanf(yytext+yyleng-4, "%2x", &n);
+ tempbuf[yyleng-6+tempbuf_len] = (char) n;
+ tempbuf_len += yyleng-5;
+ }
+
+<IN_STRING>{GRAPHIC}*"[\"\"\"]" {
+ int n;
+ resize_tempbuf (yyleng-4+tempbuf_len+1);
+ strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
+ tempbuf[yyleng-5+tempbuf_len] = '"';
+ tempbuf_len += yyleng-4;
+ }
+
+if {
+ while (*lexptr != 'i' && *lexptr != 'I')
+ lexptr -= 1;
+ yyrestart(NULL);
+ return 0;
+ }
+
+ /* ADA KEYWORDS */
+
+abs { return ABS; }
+and { return _AND_; }
+else { return ELSE; }
+in { return IN; }
+mod { return MOD; }
+new { return NEW; }
+not { return NOT; }
+null { return NULL_PTR; }
+or { return OR; }
+rem { return REM; }
+then { return THEN; }
+xor { return XOR; }
+
+ /* ATTRIBUTES */
+
+{TICK}[a-zA-Z][a-zA-Z]+ { return processAttribute (yytext+1); }
+
+ /* PUNCTUATION */
+
+"=>" { return ARROW; }
+".." { return DOTDOT; }
+"**" { return STARSTAR; }
+":=" { return ASSIGN; }
+"/=" { return NOTEQUAL; }
+"<=" { return LEQ; }
+">=" { return GEQ; }
+
+<BEFORE_QUAL_QUOTE>"'" { BEGIN INITIAL; return '\''; }
+
+[-&*+./:<>=|;\[\]] { return yytext[0]; }
+
+"," { if (paren_depth == 0 && comma_terminates)
+ {
+ lexptr -= 1;
+ yyrestart(NULL);
+ return 0;
+ }
+ else
+ return ',';
+ }
+
+"(" { paren_depth += 1; return '('; }
+")" { if (paren_depth == 0)
+ {
+ lexptr -= 1;
+ yyrestart(NULL);
+ return 0;
+ }
+ else
+ {
+ paren_depth -= 1;
+ return ')';
+ }
+ }
+
+"."{WHITE}*all { return DOT_ALL; }
+
+"."{WHITE}*{ID} {
+ processId (yytext+1, yyleng-1);
+ return DOT_ID;
+ }
+
+{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'")? {
+ int all_posn = find_dot_all (yytext);
+ int token_type, segments, k;
+ int quote_follows;
+
+ if (all_posn == -1 && yytext[yyleng-1] == '\'')
+ {
+ quote_follows = 1;
+ do {
+ yyless (yyleng-1);
+ } while (yytext[yyleng-1] == ' ');
+ }
+ else
+ quote_follows = 0;
+
+ if (all_posn >= 0)
+ yyless (all_posn);
+ processId(yytext, yyleng);
+ segments = name_lookup (ada_mangle (yylval.ssym.stoken.ptr),
+ yylval.ssym.stoken.ptr, &token_type);
+ left_block_context = NULL;
+ for (k = yyleng; segments > 0 && k > 0; k -= 1)
+ {
+ if (yytext[k-1] == '.')
+ segments -= 1;
+ quote_follows = 0;
+ }
+ if (k <= 0)
+ error ("confused by name %s", yytext);
+ yyless (k);
+ if (quote_follows)
+ BEGIN BEFORE_QUAL_QUOTE;
+ return token_type;
+ }
+
+ /* GDB EXPRESSION CONSTRUCTS */
+
+
+"'"[^']+"'"{WHITE}*:: {
+ processId(yytext, yyleng-2);
+ block_lookup (yylval.ssym.stoken.ptr, yylval.ssym.stoken.ptr);
+ return BLOCKNAME;
+ }
+
+{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*{WHITE}*:: {
+ processId(yytext, yyleng-2);
+ block_lookup (ada_mangle (yylval.ssym.stoken.ptr),
+ yylval.ssym.stoken.ptr);
+ return BLOCKNAME;
+ }
+
+[{}@] { return yytext[0]; }
+
+"$$" { yylval.lval = -1; return LAST; }
+"$$"{DIG}+ { yylval.lval = -atoi(yytext+2); return LAST; }
+"$" { yylval.lval = 0; return LAST; }
+"$"{DIG}+ { yylval.lval = atoi(yytext+1); return LAST; }
+
+
+ /* REGISTERS AND GDB CONVENIENCE VARIABLES */
+
+"$"({LETTER}|{DIG}|"$")+ {
+ int c;
+ for (c = 0; c < NUM_REGS; c++)
+ if (REGISTER_NAME (c) &&
+ strcmp (yytext + 1, REGISTER_NAME (c)) == 0)
+ {
+ yylval.lval = c;
+ return REGNAME;
+ }
+ yylval.sval.ptr = yytext;
+ yylval.sval.length = yyleng;
+ yylval.ivar =
+ lookup_internalvar (copy_name (yylval.sval) + 1);
+ return INTERNAL_VARIABLE;
+ }
+
+ /* CATCH-ALL ERROR CASE */
+
+. { error ("Invalid character '%s' in expression.", yytext); }
+%%
+
+#include <ctype.h>
+#include <string.h>
+
+/* Initialize the lexer for processing new expression */
+void
+lexer_init (FILE* inp)
+{
+ BEGIN INITIAL;
+ yyrestart (inp);
+}
+
+
+/* Make sure that tempbuf points at an array at least N characters long. */
+
+static void
+resize_tempbuf (n)
+ unsigned int n;
+{
+ if (tempbufsize < n)
+ {
+ tempbufsize = (n+63) & ~63;
+ tempbuf = (char*) xrealloc (tempbuf, tempbufsize);
+ }
+}
+
+/* Copy S2 to S1, removing all underscores, and downcasing all letters. */
+
+static void
+canonicalizeNumeral (s1,s2)
+ char* s1;
+ const char* s2;
+{
+ for (; *s2 != '\000'; s2 += 1)
+ {
+ if (*s2 != '_')
+ {
+ *s1 = tolower(*s2);
+ s1 += 1;
+ }
+ }
+ s1[0] = '\000';
+}
+
+#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
+
+/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
+ where 2 <= BASE <= 16. */
+
+static int
+is_digit_in_base (digit, base)
+ unsigned char digit;
+ int base;
+{
+ if (!isxdigit (digit))
+ return 0;
+ if (base <= 10)
+ return (isdigit (digit) && digit < base + '0');
+ else
+ return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
+}
+
+static int
+digit_to_int (c)
+ unsigned char c;
+{
+ if (isdigit (c))
+ return c - '0';
+ else
+ return tolower (c) - 'a' + 10;
+}
+
+/* As for strtoul, but for ULONGEST results. */
+ULONGEST
+strtoulst (num, trailer, base)
+ const char *num;
+ const char **trailer;
+ int base;
+{
+ unsigned int high_part;
+ ULONGEST result;
+ int i;
+ unsigned char lim;
+
+ if (base < 2 || base > 16)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+ lim = base - 1 + '0';
+
+ result = high_part = 0;
+ for (i = 0; is_digit_in_base (num[i], base); i += 1)
+ {
+ result = result*base + digit_to_int (num[i]);
+ high_part = high_part*base + (unsigned int) (result >> HIGH_BYTE_POSN);
+ result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
+ if (high_part > 0xff)
+ {
+ errno = ERANGE;
+ result = high_part = 0;
+ break;
+ }
+ }
+
+ if (trailer != NULL)
+ *trailer = &num[i];
+
+ return result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
+}
+
+
+
+/* Interprets the prefix of NUM that consists of digits of the given BASE
+ as an integer of that BASE, with the string EXP as an exponent.
+ Puts value in yylval, and returns INT, if the string is valid. Causes
+ an error if the number is improperly formated. BASE, if NULL, defaults
+ to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'. */
+
+static int
+processInt (base0, num0, exp0)
+ const char* num0;
+ const char* base0;
+ const char* exp0;
+{
+ ULONGEST result;
+ long exp;
+ int base;
+
+ char* trailer;
+
+ if (base0 == NULL)
+ base = 10;
+ else
+ {
+ base = strtol (base0, (char**) NULL, 10);
+ if (base < 2 || base > 16)
+ error ("Invalid base: %d.", base);
+ }
+
+ if (exp0 == NULL)
+ exp = 0;
+ else
+ exp = strtol(exp0, (char**) NULL, 10);
+
+ errno = 0;
+ result = strtoulst (num0, &trailer, base);
+ if (errno == ERANGE)
+ error ("Integer literal out of range");
+ if (isxdigit(*trailer))
+ error ("Invalid digit `%c' in based literal", *trailer);
+
+ while (exp > 0)
+ {
+ if (result > (ULONG_MAX / base))
+ error ("Integer literal out of range");
+ result *= base;
+ exp -= 1;
+ }
+
+ if ((result >> (TARGET_INT_BIT-1)) == 0)
+ yylval.typed_val.type = builtin_type_ada_int;
+ else if ((result >> (TARGET_LONG_BIT-1)) == 0)
+ yylval.typed_val.type = builtin_type_ada_long;
+ else if (((result >> (TARGET_LONG_BIT-1)) >> 1) == 0)
+ {
+ /* We have a number representable as an unsigned integer quantity.
+ For consistency with the C treatment, we will treat it as an
+ anonymous modular (unsigned) quantity. Alas, the types are such
+ that we need to store .val as a signed quantity. Sorry
+ for the mess, but C doesn't officially guarantee that a simple
+ assignment does the trick (no, it doesn't; read the reference manual).
+ */
+ yylval.typed_val.type = builtin_type_unsigned_long;
+ if (result & LONGEST_SIGN)
+ yylval.typed_val.val =
+ (LONGEST) (result & ~LONGEST_SIGN)
+ - (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1);
+ else
+ yylval.typed_val.val = (LONGEST) result;
+ return INT;
+ }
+ else
+ yylval.typed_val.type = builtin_type_ada_long_long;
+
+ yylval.typed_val.val = (LONGEST) result;
+ return INT;
+}
+
+static int
+processReal (num0)
+ const char* num0;
+{
+ if (sizeof (DOUBLEST) <= sizeof (float))
+ sscanf (num0, "%g", &yylval.typed_val_float.dval);
+ else if (sizeof (DOUBLEST) <= sizeof (double))
+ sscanf (num0, "%lg", &yylval.typed_val_float.dval);
+ else
+ {
+#ifdef PRINTF_HAS_LONG_DOUBLE
+ sscanf (num0, "%Lg", &yylval.typed_val_float.dval);
+#else
+ /* Scan it into a double, then convert and assign it to the
+ long double. This at least wins with values representable
+ in the range of doubles. */
+ double temp;
+ sscanf (num0, "%lg", &temp);
+ yylval.typed_val_float.dval = temp;
+#endif
+ }
+
+ yylval.typed_val_float.type = builtin_type_ada_float;
+ if (sizeof(DOUBLEST) >= TARGET_DOUBLE_BIT / TARGET_CHAR_BIT)
+ yylval.typed_val_float.type = builtin_type_ada_double;
+ if (sizeof(DOUBLEST) >= TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT)
+ yylval.typed_val_float.type = builtin_type_ada_long_double;
+
+ return FLOAT;
+}
+
+static int
+processId (name0, len)
+ const char *name0;
+ int len;
+{
+ char* name = xmalloc (len + 11);
+ int i0, i;
+
+/* add_name_string_cleanup (name); */
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+ while (len > 0 && isspace (name0[len-1]))
+ len -= 1;
+ i = i0 = 0;
+ while (i0 < len)
+ {
+ if (isalnum (name0[i0]))
+ {
+ name[i] = tolower (name0[i0]);
+ i += 1; i0 += 1;
+ }
+ else switch (name0[i0])
+ {
+ default:
+ name[i] = name0[i0];
+ i += 1; i0 += 1;
+ break;
+ case ' ': case '\t':
+ i0 += 1;
+ break;
+ case '\'':
+ i0 += 1;
+ while (i0 < len && name0[i0] != '\'')
+ {
+ name[i] = name0[i0];
+ i += 1; i0 += 1;
+ }
+ i0 += 1;
+ break;
+ case '<':
+ i0 += 1;
+ while (i0 < len && name0[i0] != '>')
+ {
+ name[i] = name0[i0];
+ i += 1; i0 += 1;
+ }
+ i0 += 1;
+ break;
+ }
+ }
+ name[i] = '\000';
+
+ yylval.ssym.sym = NULL;
+ yylval.ssym.stoken.ptr = name;
+ yylval.ssym.stoken.length = i;
+ return NAME;
+}
+
+static void
+block_lookup (name, err_name)
+ char* name;
+ char* err_name;
+{
+ struct symbol** syms;
+ struct block** blocks;
+ int nsyms;
+ struct symtab *symtab;
+ nsyms = ada_lookup_symbol_list (name, left_block_context,
+ VAR_DOMAIN, &syms, &blocks);
+ if (left_block_context == NULL &&
+ (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK))
+ symtab = lookup_symtab (name);
+ else
+ symtab = NULL;
+
+ if (symtab != NULL)
+ left_block_context = yylval.bval =
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ else if (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK)
+ {
+ if (left_block_context == NULL)
+ error ("No file or function \"%s\".", err_name);
+ else
+ error ("No function \"%s\" in specified context.", err_name);
+ }
+ else
+ {
+ left_block_context = yylval.bval = SYMBOL_BLOCK_VALUE (syms[0]);
+ if (nsyms > 1)
+ warning ("Function name \"%s\" ambiguous here", err_name);
+ }
+}
+
+/* Look up NAME0 (assumed to be mangled) as a name in VAR_DOMAIN,
+ setting *TOKEN_TYPE to NAME or TYPENAME, depending on what is
+ found. Try first the entire name, then the name without the last
+ segment (i.e., after the last .id), etc., and return the number of
+ segments that had to be removed to get a match. Calls error if no
+ matches are found, using ERR_NAME in any error message. When
+ exactly one symbol match is found, it is placed in yylval. */
+
+static int
+name_lookup (name0, err_name, token_type)
+ char* name0;
+ char* err_name;
+ int* token_type;
+{
+ struct symbol** syms;
+ struct block** blocks;
+ struct type* type;
+ int len0 = strlen (name0);
+ char* name = savestring (name0, len0);
+ int nsyms;
+ int segments;
+
+/* add_name_string_cleanup (name);*/
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+ yylval.ssym.stoken.ptr = name;
+ yylval.ssym.stoken.length = strlen (name);
+ for (segments = 0; ; segments += 1)
+ {
+ struct type* preferred_type;
+ int i, preferred_index;
+
+ if (left_block_context == NULL)
+ nsyms = ada_lookup_symbol_list (name, expression_context_block,
+ VAR_DOMAIN, &syms, &blocks);
+ else
+ nsyms = ada_lookup_symbol_list (name, left_block_context,
+ VAR_DOMAIN, &syms, &blocks);
+
+ /* Check for a type definition. */
+
+ /* Look for a symbol that doesn't denote void. This is (I think) a */
+ /* temporary kludge to get around problems in GNAT output. */
+ preferred_index = -1; preferred_type = NULL;
+ for (i = 0; i < nsyms; i += 1)
+ switch (SYMBOL_CLASS (syms[i]))
+ {
+ case LOC_TYPEDEF:
+ if (ada_prefer_type (SYMBOL_TYPE (syms[i]), preferred_type))
+ {
+ preferred_index = i;
+ preferred_type = SYMBOL_TYPE (syms[i]);
+ }
+ break;
+ 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:
+ goto NotType;
+ default:
+ break;
+ }
+ if (preferred_type != NULL)
+ {
+/* if (TYPE_CODE (preferred_type) == TYPE_CODE_VOID)
+ error ("`%s' matches only void type name(s)",
+ ada_demangle (name));
+*/
+/* FIXME: ada_demangle should be defined in defs.h, and is located in ada-lang.c */
+/* else*/ if (ada_is_object_renaming (syms[preferred_index]))
+ {
+ yylval.ssym.sym = syms[preferred_index];
+ *token_type = OBJECT_RENAMING;
+ return segments;
+ }
+ else if (ada_renaming_type (SYMBOL_TYPE (syms[preferred_index]))
+ != NULL)
+ {
+ int result;
+ const char* renaming =
+ ada_simple_renamed_entity (syms[preferred_index]);
+ char* new_name = xmalloc (strlen (renaming) + len0
+ - yylval.ssym.stoken.length + 1);
+/* add_name_string_cleanup (new_name);*/
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+ strcpy (new_name, renaming);
+ strcat (new_name, name0 + yylval.ssym.stoken.length);
+ result = name_lookup (new_name, err_name, token_type);
+ if (result > segments)
+ error ("Confused by renamed symbol.");
+ return result;
+ }
+ else if (segments == 0)
+ {
+ yylval.tval = preferred_type;
+ *token_type = TYPENAME;
+ return 0;
+ }
+ }
+
+ if (segments == 0)
+ {
+ type = lookup_primitive_typename (name);
+ if (type == NULL && DEPRECATED_STREQ ("system__address", name))
+ type = builtin_type_ada_system_address;
+ if (type != NULL)
+ {
+ yylval.tval = type;
+ *token_type = TYPENAME;
+ return 0;
+ }
+ }
+
+ NotType:
+ if (nsyms == 1)
+ {
+ *token_type = NAME;
+ yylval.ssym.sym = syms[0];
+ yylval.ssym.msym = NULL;
+ yylval.ssym.block = blocks[0];
+ return segments;
+ }
+ else if (nsyms == 0) {
+ int i;
+ yylval.ssym.msym = ada_lookup_minimal_symbol (name);
+ if (yylval.ssym.msym != NULL)
+ {
+ yylval.ssym.sym = NULL;
+ yylval.ssym.block = NULL;
+ *token_type = NAME;
+ return segments;
+ }
+
+ for (i = yylval.ssym.stoken.length - 1; i > 0; i -= 1)
+ {
+ if (name[i] == '.')
+ {
+ name[i] = '\0';
+ yylval.ssym.stoken.length = i;
+ break;
+ }
+ else if (name[i] == '_' && name[i-1] == '_')
+ {
+ i -= 1;
+ name[i] = '\0';
+ yylval.ssym.stoken.length = i;
+ break;
+ }
+ }
+ if (i <= 0)
+ {
+ if (!have_full_symbols () && !have_partial_symbols ()
+ && left_block_context == NULL)
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ if (left_block_context == NULL)
+ error ("No definition of \"%s\" in current context.",
+ err_name);
+ else
+ error ("No definition of \"%s\" in specified context.",
+ err_name);
+ }
+ }
+ else
+ {
+ *token_type = NAME;
+ yylval.ssym.sym = NULL;
+ yylval.ssym.msym = NULL;
+ if (left_block_context == NULL)
+ yylval.ssym.block = expression_context_block;
+ else
+ yylval.ssym.block = left_block_context;
+ return segments;
+ }
+ }
+}
+
+/* Returns the position within STR of the '.' in a
+ '.{WHITE}*all' component of a dotted name, or -1 if there is none. */
+static int
+find_dot_all (str)
+ const char* str;
+{
+ int i;
+ for (i = 0; str[i] != '\000'; i += 1)
+ {
+ if (str[i] == '.')
+ {
+ int i0 = i;
+ do
+ i += 1;
+ while (isspace (str[i]));
+ if (strcmp (str+i, "all") == 0
+ && ! isalnum (str[i+3]) && str[i+3] != '_')
+ return i0;
+ }
+ }
+ return -1;
+}
+
+/* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
+ case. */
+
+static int
+subseqMatch (subseq, str)
+ const char* subseq;
+ const char* str;
+{
+ if (subseq[0] == '\0')
+ return 1;
+ else if (str[0] == '\0')
+ return 0;
+ else if (tolower (subseq[0]) == tolower (str[0]))
+ return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
+ else
+ return subseqMatch (subseq, str+1);
+}
+
+
+static struct { const char* name; int code; }
+attributes[] = {
+ { "address", TICK_ADDRESS },
+ { "unchecked_access", TICK_ACCESS },
+ { "unrestricted_access", TICK_ACCESS },
+ { "access", TICK_ACCESS },
+ { "first", TICK_FIRST },
+ { "last", TICK_LAST },
+ { "length", TICK_LENGTH },
+ { "max", TICK_MAX },
+ { "min", TICK_MIN },
+ { "modulus", TICK_MODULUS },
+ { "pos", TICK_POS },
+ { "range", TICK_RANGE },
+ { "size", TICK_SIZE },
+ { "tag", TICK_TAG },
+ { "val", TICK_VAL },
+ { NULL, -1 }
+};
+
+/* Return the syntactic code corresponding to the attribute name or
+ abbreviation STR. */
+
+static int
+processAttribute (str)
+ const char* str;
+{
+ int i, k;
+
+ for (i = 0; attributes[i].code != -1; i += 1)
+ if (strcasecmp (str, attributes[i].name) == 0)
+ return attributes[i].code;
+
+ for (i = 0, k = -1; attributes[i].code != -1; i += 1)
+ if (subseqMatch (str, attributes[i].name))
+ {
+ if (k == -1)
+ k = i;
+ else
+ error ("ambiguous attribute name: `%s'", str);
+ }
+ if (k == -1)
+ error ("unrecognized attribute: `%s'", str);
+
+ return attributes[k].code;
+}
+
+int
+yywrap()
+{
+ return 1;
+}
diff --git a/contrib/gdb/gdb/ada-tasks.c b/contrib/gdb/gdb/ada-tasks.c
new file mode 100644
index 0000000..c883015
--- /dev/null
+++ b/contrib/gdb/gdb/ada-tasks.c
@@ -0,0 +1,819 @@
+/* file ada-tasks.c: Ada tasking control for GDB
+ Copyright 1997 Free Software Foundation, Inc.
+ Contributed by Ada Core Technologies, Inc
+.
+ This file is part of GDB.
+
+ [$Id: ada-tasks.c,v 1.7 2003/06/17 20:58:32 ciceron Exp $]
+ Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.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.
+
+*/
+
+#include <ctype.h>
+#include "defs.h"
+#include "command.h"
+#include "value.h"
+#include "language.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+#include "regcache.h"
+#include "gdbcore.h"
+
+#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks))
+#include <sys/procfs.h>
+#endif
+
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+#include "gregset.h"
+#endif
+
+#include "ada-lang.h"
+
+/* FIXME: move all this conditional compilation in description
+ files or in configure.in */
+
+#if defined (VXWORKS_TARGET)
+#define THREAD_TO_PID(tid,lwpid) (tid)
+
+#elif defined (linux)
+#define THREAD_TO_PID(tid,lwpid) (0)
+
+#elif (defined (sun) && defined (__SVR4))
+#define THREAD_TO_PID thread_to_pid
+
+#elif defined (sgi) || defined (__WIN32__) || defined (hpux)
+#define THREAD_TO_PID(tid,lwpid) ((int)lwpid)
+
+#else
+#define THREAD_TO_PID(tid,lwpid) (0)
+#endif
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers
+#define GET_CURRENT_THREAD dec_thread_get_current_thread
+extern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *);
+#endif
+
+#if defined (_AIX)
+#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers
+#define GET_CURRENT_THREAD aix_thread_get_current_thread
+#endif
+
+#if defined(VXWORKS_TARGET)
+#define GET_CURRENT_THREAD() ((void*)inferior_pid)
+#define THREAD_FETCH_REGISTERS() (-1)
+
+#elif defined (sun) && defined (__SVR4)
+#define GET_CURRENT_THREAD solaris_thread_get_current_thread
+#define THREAD_FETCH_REGISTERS() (-1)
+extern void *GET_CURRENT_THREAD ();
+
+#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__))
+extern void *GET_CURRENT_THREAD ();
+
+#elif defined (__WIN32__) || defined (hpux)
+#define GET_CURRENT_THREAD() (inferior_pid)
+#define THREAD_FETCH_REGISTERS() (-1)
+
+#else
+#define GET_CURRENT_THREAD() (NULL)
+#define THREAD_FETCH_REGISTERS() (-1)
+#endif
+
+#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
+
+#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var))
+/* external declarations */
+
+/* Global visible variables */
+
+struct task_entry *task_list = NULL;
+int ada__tasks_check_symbol_table = 1;
+void *pthread_kern_addr = NULL;
+
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+gdb_gregset_t gregset_saved;
+gdb_fpregset_t fpregset_saved;
+#endif
+
+/* The maximum number of tasks known to the Ada runtime */
+const int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
+
+/* the current task */
+int current_task = -1, current_task_id = -1, current_task_index;
+void *current_thread, *current_lwp;
+
+char *ada_task_states[] = {
+ "Unactivated",
+ "Runnable",
+ "Terminated",
+ "Child Activation Wait",
+ "Accept Statement",
+ "Waiting on entry call",
+ "Async Select Wait",
+ "Delay Sleep",
+ "Child Termination Wait",
+ "Wait Child in Term Alt",
+ "",
+ "",
+ "",
+ "",
+ "Asynchronous Hold"
+};
+
+/* Global internal types */
+
+static char *ada_long_task_states[] = {
+ "Unactivated",
+ "Runnable",
+ "Terminated",
+ "Waiting for child activation",
+ "Blocked in accept statement",
+ "Waiting on entry call",
+ "Asynchronous Selective Wait",
+ "Delay Sleep",
+ "Waiting for children termination",
+ "Waiting for children in terminate alternative",
+ "",
+ "",
+ "",
+ "",
+ "Asynchronous Hold"
+};
+
+/* Global internal variables */
+
+static int highest_task_num = 0;
+int thread_support = 0; /* 1 if the thread library in use is supported */
+static int gdbtk_task_initialization = 0;
+
+static int
+add_task_entry (void *p_task_id, int index)
+{
+ struct task_entry *new_task_entry = NULL;
+ struct task_entry *pt;
+
+ highest_task_num++;
+ new_task_entry = xmalloc (sizeof (struct task_entry));
+ new_task_entry->task_num = highest_task_num;
+ new_task_entry->task_id = p_task_id;
+ new_task_entry->known_tasks_index = index;
+ new_task_entry->next_task = NULL;
+ pt = task_list;
+ if (pt)
+ {
+ while (pt->next_task)
+ pt = pt->next_task;
+ pt->next_task = new_task_entry;
+ pt->stack_per = 0;
+ }
+ else
+ task_list = new_task_entry;
+ return new_task_entry->task_num;
+}
+
+int
+get_entry_number (void *p_task_id)
+{
+ struct task_entry *pt;
+
+ pt = task_list;
+ while (pt != NULL)
+ {
+ if (pt->task_id == p_task_id)
+ return pt->task_num;
+ pt = pt->next_task;
+ }
+ return 0;
+}
+
+static struct task_entry *
+get_thread_entry_vptr (void *thread)
+{
+ struct task_entry *pt;
+
+ pt = task_list;
+ while (pt != NULL)
+ {
+ if (pt->thread == thread)
+ return pt;
+ pt = pt->next_task;
+ }
+ return 0;
+}
+
+static struct task_entry *
+get_entry_vptr (int p_task_num)
+{
+ struct task_entry *pt;
+
+ pt = task_list;
+ while (pt)
+ {
+ if (pt->task_num == p_task_num)
+ return pt;
+ pt = pt->next_task;
+ }
+ return NULL;
+}
+
+void
+init_task_list (void)
+{
+ struct task_entry *pt, *old_pt;
+
+ pt = task_list;
+ while (pt)
+ {
+ old_pt = pt;
+ pt = pt->next_task;
+ xfree (old_pt);
+ };
+ task_list = NULL;
+ highest_task_num = 0;
+}
+
+int
+valid_task_id (int task)
+{
+ return get_entry_vptr (task) != NULL;
+}
+
+void *
+get_self_id (void)
+{
+ struct value *val;
+ void *self_id;
+ int result;
+ struct task_entry *ent;
+ extern int do_not_insert_breakpoints;
+
+#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__))
+ if (thread_support)
+#endif
+ {
+ ent = get_thread_entry_vptr (GET_CURRENT_THREAD ());
+ return ent ? ent->task_id : 0;
+ }
+
+ /* FIXME: calling a function in the inferior with a multithreaded application
+ is not reliable, so return NULL if there is no safe way to get the current
+ task */
+ return NULL;
+}
+
+int
+get_current_task (void)
+{
+ int result;
+
+ /* FIXME: language_ada should be defined in defs.h */
+ /* if (current_language->la_language != language_ada) return -1; */
+
+ result = get_entry_number (get_self_id ());
+
+ /* return -1 if not found */
+ return result == 0 ? -1 : result;
+}
+
+/* Print detailed information about specified task */
+
+static void
+info_task (char *arg, int from_tty)
+{
+ void *temp_task;
+ struct task_entry *pt, *pt2;
+ void *self_id, *caller;
+ struct task_fields atcb, atcb2;
+ struct entry_call call;
+ int bounds[2];
+ char image[256];
+ int num;
+
+ /* FIXME: language_ada should be defined in defs.h */
+ /* if (current_language->la_language != language_ada)
+ {
+ printf_filtered ("The current language does not support tasks.\n");
+ return;
+ }
+ */
+ pt = get_entry_vptr (atoi (arg));
+ if (pt == NULL)
+ {
+ printf_filtered ("Task %s not found.\n", arg);
+ return;
+ }
+
+ temp_task = pt->task_id;
+
+ /* read the atcb in the inferior */
+ READ_MEMORY ((CORE_ADDR) temp_task, atcb);
+
+ /* print the Ada task id */
+ printf_filtered ("Ada Task: %p\n", temp_task);
+
+ /* print the name of the task */
+ if (atcb.image.P_ARRAY != NULL)
+ {
+ READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
+ bounds[1] = EXTRACT_INT (bounds[1]);
+ read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
+ (char *) &image, bounds[1]);
+ printf_filtered ("Name: %.*s\n", bounds[1], image);
+ }
+ else
+ printf_filtered ("<no name>\n");
+
+ /* print the thread id */
+
+ if ((long) pt->thread < 65536)
+ printf_filtered ("Thread: %ld\n", (long int) pt->thread);
+ else
+ printf_filtered ("Thread: %p\n", pt->thread);
+
+ if ((long) pt->lwp != 0)
+ {
+ if ((long) pt->lwp < 65536)
+ printf_filtered ("LWP: %ld\n", (long int) pt->lwp);
+ else
+ printf_filtered ("LWP: %p\n", pt->lwp);
+ }
+
+ /* print the parent gdb task id */
+ num = get_entry_number (EXTRACT_ADDRESS (atcb.parent));
+ if (num != 0)
+ {
+ printf_filtered ("Parent: %d", num);
+ pt2 = get_entry_vptr (num);
+ READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
+
+ /* print the name of the task */
+ if (atcb2.image.P_ARRAY != NULL)
+ {
+ READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
+ bounds);
+ bounds[1] = EXTRACT_INT (bounds[1]);
+ read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
+ (char *) &image, bounds[1]);
+ printf_filtered (" (%.*s)\n", bounds[1], image);
+ }
+ else
+ printf_filtered ("\n");
+ }
+ else
+ printf_filtered ("No parent\n");
+
+ /* print the base priority of the task */
+ printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority));
+
+ /* print the current state of the task */
+
+ /* check if this task is accepting a rendezvous */
+ if (atcb.call == NULL)
+ caller = NULL;
+ else
+ {
+ READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
+ caller = EXTRACT_ADDRESS (call.self);
+ }
+
+ if (caller != NULL)
+ {
+ num = get_entry_number (caller);
+ printf_filtered ("Accepting rendezvous with %d", num);
+
+ if (num != 0)
+ {
+ pt2 = get_entry_vptr (num);
+ READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
+
+ /* print the name of the task */
+ if (atcb2.image.P_ARRAY != NULL)
+ {
+ READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
+ bounds);
+ bounds[1] = EXTRACT_INT (bounds[1]);
+ read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
+ (char *) &image, bounds[1]);
+ printf_filtered (" (%.*s)\n", bounds[1], image);
+ }
+ else
+ printf_filtered ("\n");
+ }
+ else
+ printf_filtered ("\n");
+ }
+ else
+ printf_filtered ("State: %s\n", ada_long_task_states[atcb.state]);
+}
+
+#if 0
+
+/* A useful function that shows the alignment of all the fields in the
+ tasks_fields structure
+ */
+
+print_align (void)
+{
+ struct task_fields tf;
+ void *tf_base = &(tf);
+ void *tf_state = &(tf.state);
+ void *tf_entry_num = &(tf.entry_num);
+ void *tf_parent = &(tf.parent);
+ void *tf_priority = &(tf.priority);
+ void *tf_current_priority = &(tf.current_priority);
+ void *tf_image = &(tf.image);
+ void *tf_call = &(tf.call);
+ void *tf_thread = &(tf.thread);
+ void *tf_lwp = &(tf.lwp);
+ printf_filtered ("\n");
+ printf_filtered ("(tf_base = 0x%x)\n", tf_base);
+ printf_filtered ("task_fields.entry_num at %3d (0x%x)\n",
+ tf_entry_num - tf_base, tf_entry_num);
+ printf_filtered ("task_fields.state at %3d (0x%x)\n",
+ tf_state - tf_base, tf_state);
+ printf_filtered ("task_fields.parent at %3d (0x%x)\n",
+ tf_parent - tf_base, tf_parent);
+ printf_filtered ("task_fields.priority at %3d (0x%x)\n",
+ tf_priority - tf_base, tf_priority);
+ printf_filtered ("task_fields.current_priority at %3d (0x%x)\n",
+ tf_current_priority - tf_base, tf_current_priority);
+ printf_filtered ("task_fields.image at %3d (0x%x)\n",
+ tf_image - tf_base, tf_image);
+ printf_filtered ("task_fields.call at %3d (0x%x)\n",
+ tf_call - tf_base, tf_call);
+ printf_filtered ("task_fields.thread at %3d (0x%x)\n",
+ tf_thread - tf_base, tf_thread);
+ printf_filtered ("task_fields.lwp at %3d (0x%x)\n",
+ tf_lwp - tf_base, tf_lwp);
+ printf_filtered ("\n");
+}
+#endif
+
+/* Print information about currently known tasks */
+
+static void
+info_tasks (char *arg, int from_tty)
+{
+ struct value *val;
+ int i, task_number, state;
+ void *temp_task, *temp_tasks[MAX_NUMBER_OF_KNOWN_TASKS];
+ struct task_entry *pt;
+ void *self_id, *caller, *thread_id = NULL;
+ struct task_fields atcb;
+ struct entry_call call;
+ int bounds[2];
+ char image[256];
+ int size;
+ char car;
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+ pthreadTeb_t thr;
+ gdb_gregset_t regs;
+#endif
+
+ static struct symbol *sym;
+ static struct minimal_symbol *msym;
+ static void *known_tasks_addr = NULL;
+
+ int init_only = gdbtk_task_initialization;
+ gdbtk_task_initialization = 0;
+
+ task_number = 0;
+
+ if (PIDGET (inferior_ptid) == 0)
+ {
+ printf_filtered ("The program is not being run under gdb. ");
+ printf_filtered ("Use 'run' or 'attach' first.\n");
+ return;
+ }
+
+ if (ada__tasks_check_symbol_table)
+ {
+ thread_support = 0;
+#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \
+ defined (_AIX)
+ thread_support = 1;
+#endif
+
+ msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
+ if (msym != NULL)
+ known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym);
+ else
+#ifndef VXWORKS_TARGET
+ return;
+#else
+ {
+ if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0)
+ return;
+ }
+#endif
+
+ ada__tasks_check_symbol_table = 0;
+ }
+
+ if (known_tasks_addr == NULL)
+ return;
+
+#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux))
+ if (thread_support)
+#endif
+ thread_id = GET_CURRENT_THREAD ();
+
+ /* then we get a list of tasks created */
+
+ init_task_list ();
+
+ READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks);
+
+ for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++)
+ {
+ temp_task = EXTRACT_ADDRESS (temp_tasks[i]);
+
+ if (temp_task != NULL)
+ {
+ task_number = get_entry_number (temp_task);
+ if (task_number == 0)
+ task_number = add_task_entry (temp_task, i);
+ }
+ }
+
+ /* Return without printing anything if this function was called in
+ order to init GDBTK tasking. */
+
+ if (init_only)
+ return;
+
+ /* print the header */
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+ printf_filtered
+ (" ID TID P-ID Pri Stack %% State Name\n");
+#else
+ printf_filtered (" ID TID P-ID Pri State Name\n");
+#endif
+
+ /* Now that we have a list of task id's, we can print them */
+ pt = task_list;
+ while (pt)
+ {
+ temp_task = pt->task_id;
+
+ /* read the atcb in the inferior */
+ READ_MEMORY ((CORE_ADDR) temp_task, atcb);
+
+ /* store the thread id for future use */
+ pt->thread = EXTRACT_ADDRESS (atcb.thread);
+
+#if defined (linux)
+ pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0);
+#else
+ pt->lwp = EXTRACT_ADDRESS (atcb.lwp);
+#endif
+
+ /* print a star if this task is the current one */
+ if (thread_id)
+#if defined (__WIN32__) || defined (SGI) || defined (hpux)
+ printf_filtered (pt->lwp == thread_id ? "*" : " ");
+#else
+ printf_filtered (pt->thread == thread_id ? "*" : " ");
+#endif
+
+ /* print the gdb task id */
+ printf_filtered ("%3d", pt->task_num);
+
+ /* print the Ada task id */
+#ifndef VXWORKS_TARGET
+ printf_filtered (" %9lx", (long) temp_task);
+#else
+#ifdef TARGET_64
+ printf_filtered (" %#9lx", (unsigned long) pt->thread & 0x3ffffffffff);
+#else
+ printf_filtered (" %#9lx", (long) pt->thread);
+#endif
+#endif
+
+ /* print the parent gdb task id */
+ printf_filtered
+ (" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent)));
+
+ /* print the base priority of the task */
+ printf_filtered (" %3d", EXTRACT_INT (atcb.priority));
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+ if (pt->task_num == 1 || atcb.state == Terminated)
+ {
+ printf_filtered (" Unknown");
+ goto next;
+ }
+
+ read_memory ((CORE_ADDR) atcb.thread, &thr, sizeof (thr));
+ current_thread = atcb.thread;
+ regs.regs[SP_REGNUM] = 0;
+ if (dec_thread_get_registers (&regs, NULL) == 0)
+ {
+ pt->stack_per = (100 * ((long) thr.__stack_base -
+ regs.regs[SP_REGNUM])) / thr.__stack_size;
+ /* if the thread is terminated but still there, the
+ stack_base/size values are erroneous. Try to patch it */
+ if (pt->stack_per < 0 || pt->stack_per > 100)
+ pt->stack_per = 0;
+ }
+
+ /* print information about stack space used in the thread */
+ if (thr.__stack_size < 1024 * 1024)
+ {
+ size = thr.__stack_size / 1024;
+ car = 'K';
+ }
+ else if (thr.__stack_size < 1024 * 1024 * 1024)
+ {
+ size = thr.__stack_size / 1024 / 1024;
+ car = 'M';
+ }
+ else /* Who knows... */
+ {
+ size = thr.__stack_size / 1024 / 1024 / 1024;
+ car = 'G';
+ }
+ printf_filtered (" %4d%c %2d", size, car, pt->stack_per);
+ next:
+#endif
+
+ /* print the current state of the task */
+
+ /* check if this task is accepting a rendezvous */
+ if (atcb.call == NULL)
+ caller = NULL;
+ else
+ {
+ READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
+ caller = EXTRACT_ADDRESS (call.self);
+ }
+
+ if (caller != NULL)
+ printf_filtered (" Accepting RV with %-4d",
+ get_entry_number (caller));
+ else
+ {
+ state = atcb.state;
+#if defined (__WIN32__) || defined (SGI) || defined (hpux)
+ if (state == Runnable && (thread_id && pt->lwp == thread_id))
+#else
+ if (state == Runnable && (thread_id && pt->thread == thread_id))
+#endif
+ /* Replace "Runnable" by "Running" if this is the current task */
+ printf_filtered (" %-22s", "Running");
+ else
+ printf_filtered (" %-22s", ada_task_states[state]);
+ }
+
+ /* finally, print the name of the task */
+ if (atcb.image.P_ARRAY != NULL)
+ {
+ READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS),
+ bounds);
+ bounds[1] = EXTRACT_INT (bounds[1]);
+ read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
+ (char *) &image, bounds[1]);
+ printf_filtered (" %.*s\n", bounds[1], image);
+ }
+ else
+ printf_filtered (" <no name>\n");
+
+ pt = pt->next_task;
+ }
+}
+
+/* Task list initialization for GDB-Tk. We basically use info_tasks()
+ to initialize our variables, but abort that function before we
+ actually print anything. */
+
+int
+gdbtk_tcl_tasks_initialize (void)
+{
+ gdbtk_task_initialization = 1;
+ info_tasks ("", gdb_stdout);
+
+ return (task_list != NULL);
+}
+
+static void
+info_tasks_command (char *arg, int from_tty)
+{
+ if (arg == NULL || *arg == '\000')
+ info_tasks (arg, from_tty);
+ else
+ info_task (arg, from_tty);
+}
+
+/* Switch from one thread to another. */
+
+static void
+switch_to_thread (ptid_t ptid)
+{
+ if (ptid_equal (ptid, inferior_ptid))
+ return;
+
+ inferior_ptid = ptid;
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc ();
+ select_frame (get_current_frame ());
+}
+
+/* Switch to a specified task. */
+
+static int
+task_switch (void *tid, void *lwpid)
+{
+ int res = 0, pid;
+
+ if (thread_support)
+ {
+ flush_cached_frames ();
+
+ if (current_task != current_task_id)
+ {
+ res = THREAD_FETCH_REGISTERS ();
+ }
+ else
+ {
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+ supply_gregset (&gregset_saved);
+ supply_fpregset (&fpregset_saved);
+#endif
+ }
+
+ if (res == 0)
+ stop_pc = read_pc ();
+ select_frame (get_current_frame ());
+ return res;
+ }
+
+ return -1;
+}
+
+static void
+task_command (char *tidstr, int from_tty)
+{
+ int num;
+ struct task_entry *e;
+
+ if (!tidstr)
+ error ("Please specify a task ID. Use the \"info tasks\" command to\n"
+ "see the IDs of currently known tasks.");
+
+ num = atoi (tidstr);
+ e = get_entry_vptr (num);
+
+ if (e == NULL)
+ error ("Task ID %d not known. Use the \"info tasks\" command to\n"
+ "see the IDs of currently known tasks.", num);
+
+ if (current_task_id == -1)
+ {
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+ fill_gregset (&gregset_saved, -1);
+ fill_fpregset (&fpregset_saved, -1);
+#endif
+ current_task_id = get_current_task ();
+ }
+
+ current_task = num;
+ current_task_index = e->known_tasks_index;
+ current_thread = e->thread;
+ current_lwp = e->lwp;
+ if (task_switch (e->thread, e->lwp) == 0)
+ {
+ /* FIXME: find_printable_frame should be defined in frame.h, and
+ implemented in ada-lang.c */
+ /* find_printable_frame (deprecated_selected_frame, frame_relative_level (deprecated_selected_frame)); */
+ printf_filtered ("[Switching to task %d]\n", num);
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 1);
+ }
+ else
+ printf_filtered ("Unable to switch to task %d\n", num);
+}
+
+void
+_initialize_tasks (void)
+{
+ static struct cmd_list_element *task_cmd_list = NULL;
+ extern struct cmd_list_element *cmdlist;
+
+ add_info ("tasks", info_tasks_command,
+ "Without argument: list all known Ada tasks, with status information.\n"
+ "info tasks n: print detailed information of task n.\n");
+
+ add_prefix_cmd ("task", class_run, task_command,
+ "Use this command to switch between tasks.\n\
+ The new task ID must be currently known.", &task_cmd_list, "task ", 1, &cmdlist);
+}
diff --git a/contrib/gdb/gdb/ada-typeprint.c b/contrib/gdb/gdb/ada-typeprint.c
new file mode 100644
index 0000000..1939354
--- /dev/null
+++ b/contrib/gdb/gdb/ada-typeprint.c
@@ -0,0 +1,852 @@
+/* Support for printing Ada types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1997, 2003 Free Software
+ Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You 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 "defs.h"
+#include "gdb_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 "ada-lang.h"
+
+#include <ctype.h>
+#include "gdb_string.h"
+#include <errno.h>
+
+static int print_record_field_types (struct type *, struct type *,
+ struct ui_file *, int, int);
+
+static void print_array_type (struct type *, struct ui_file *, int, int);
+
+static void print_choices (struct type *, int, struct ui_file *,
+ struct type *);
+
+static void print_range (struct type *, struct ui_file *);
+
+static void print_range_bound (struct type *, char *, int *,
+ struct ui_file *);
+
+static void
+print_dynamic_range_bound (struct type *, const char *, int,
+ const char *, struct ui_file *);
+
+static void print_range_type_named (char *, struct ui_file *);
+
+
+
+static char *name_buffer;
+static int name_buffer_len;
+
+/* The (demangled) Ada name of TYPE. This value persists until the
+ next call. */
+
+static char *
+demangled_type_name (struct type *type)
+{
+ if (ada_type_name (type) == NULL)
+ return NULL;
+ else
+ {
+ char *raw_name = ada_type_name (type);
+ char *s, *q;
+
+ if (name_buffer == NULL || name_buffer_len <= strlen (raw_name))
+ {
+ name_buffer_len = 16 + 2 * strlen (raw_name);
+ name_buffer = xrealloc (name_buffer, name_buffer_len);
+ }
+ strcpy (name_buffer, raw_name);
+
+ s = (char *) strstr (name_buffer, "___");
+ if (s != NULL)
+ *s = '\0';
+
+ s = name_buffer + strlen (name_buffer) - 1;
+ while (s > name_buffer && (s[0] != '_' || s[-1] != '_'))
+ s -= 1;
+
+ if (s == name_buffer)
+ return name_buffer;
+
+ if (!islower (s[1]))
+ return NULL;
+
+ for (s = q = name_buffer; *s != '\0'; q += 1)
+ {
+ if (s[0] == '_' && s[1] == '_')
+ {
+ *q = '.';
+ s += 2;
+ }
+ else
+ {
+ *q = *s;
+ s += 1;
+ }
+ }
+ *q = '\0';
+ return name_buffer;
+ }
+}
+
+
+/* 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
+ada_typedef_print (struct type *type, struct symbol *new,
+ struct ui_file *stream)
+{
+ fprintf_filtered (stream, "type %.*s is ",
+ ada_name_prefix_len (SYMBOL_PRINT_NAME (new)),
+ SYMBOL_PRINT_NAME (new));
+ type_print (type, "", stream, 1);
+}
+
+/* Print range type TYPE on STREAM. */
+
+static void
+print_range (struct type *type, struct ui_file *stream)
+{
+ struct type *target_type;
+ target_type = TYPE_TARGET_TYPE (type);
+ if (target_type == NULL)
+ target_type = type;
+
+ switch (TYPE_CODE (target_type))
+ {
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ break;
+ default:
+ target_type = builtin_type_ada_int;
+ break;
+ }
+
+ if (TYPE_NFIELDS (type) < 2)
+ {
+ /* A range needs at least 2 bounds to be printed. If there are less
+ than 2, just print the type name instead of the range itself.
+ This check handles cases such as characters, for example.
+
+ Note that if the name is not defined, then we don't print anything.
+ */
+ fprintf_filtered (stream, "%.*s",
+ ada_name_prefix_len (TYPE_NAME (type)),
+ TYPE_NAME (type));
+ }
+ else
+ {
+ /* We extract the range type bounds respectively from the first element
+ and the last element of the type->fields array */
+ const LONGEST lower_bound = (LONGEST) TYPE_LOW_BOUND (type);
+ const LONGEST upper_bound =
+ (LONGEST) TYPE_FIELD_BITPOS (type, TYPE_NFIELDS (type) - 1);
+
+ ada_print_scalar (target_type, lower_bound, stream);
+ fprintf_filtered (stream, " .. ");
+ ada_print_scalar (target_type, upper_bound, stream);
+ }
+}
+
+/* Print the number or discriminant bound at BOUNDS+*N on STREAM, and
+ set *N past the bound and its delimiter, if any. */
+
+static void
+print_range_bound (struct type *type, char *bounds, int *n,
+ struct ui_file *stream)
+{
+ LONGEST B;
+ if (ada_scan_number (bounds, *n, &B, n))
+ {
+ ada_print_scalar (type, B, stream);
+ if (bounds[*n] == '_')
+ *n += 2;
+ }
+ else
+ {
+ int bound_len;
+ char *bound = bounds + *n;
+ char *pend;
+
+ pend = strstr (bound, "__");
+ if (pend == NULL)
+ *n += bound_len = strlen (bound);
+ else
+ {
+ bound_len = pend - bound;
+ *n += bound_len + 2;
+ }
+ fprintf_filtered (stream, "%.*s", bound_len, bound);
+ }
+}
+
+/* Assuming NAME[0 .. NAME_LEN-1] is the name of a range type, print
+ the value (if found) of the bound indicated by SUFFIX ("___L" or
+ "___U") according to the ___XD conventions. */
+
+static void
+print_dynamic_range_bound (struct type *type, const char *name, int name_len,
+ const char *suffix, struct ui_file *stream)
+{
+ static char *name_buf = NULL;
+ static size_t name_buf_len = 0;
+ LONGEST B;
+ int OK;
+
+ GROW_VECT (name_buf, name_buf_len, name_len + strlen (suffix) + 1);
+ strncpy (name_buf, name, name_len);
+ strcpy (name_buf + name_len, suffix);
+
+ B = get_int_var_value (name_buf, 0, &OK);
+ if (OK)
+ ada_print_scalar (type, B, stream);
+ else
+ fprintf_filtered (stream, "?");
+}
+
+/* Print the range type named NAME. */
+
+static void
+print_range_type_named (char *name, struct ui_file *stream)
+{
+ struct type *raw_type = ada_find_any_type (name);
+ struct type *base_type;
+ LONGEST low, high;
+ char *subtype_info;
+
+ if (raw_type == NULL)
+ base_type = builtin_type_int;
+ else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE)
+ base_type = TYPE_TARGET_TYPE (raw_type);
+ else
+ base_type = raw_type;
+
+ subtype_info = strstr (name, "___XD");
+ if (subtype_info == NULL && raw_type == NULL)
+ fprintf_filtered (stream, "? .. ?");
+ else if (subtype_info == NULL)
+ print_range (raw_type, stream);
+ else
+ {
+ int prefix_len = subtype_info - name;
+ char *bounds_str;
+ int n;
+
+ subtype_info += 5;
+ bounds_str = strchr (subtype_info, '_');
+ n = 1;
+
+ if (*subtype_info == 'L')
+ {
+ print_range_bound (raw_type, bounds_str, &n, stream);
+ subtype_info += 1;
+ }
+ else
+ print_dynamic_range_bound (raw_type, name, prefix_len, "___L",
+ stream);
+
+ fprintf_filtered (stream, " .. ");
+
+ if (*subtype_info == 'U')
+ print_range_bound (raw_type, bounds_str, &n, stream);
+ else
+ print_dynamic_range_bound (raw_type, name, prefix_len, "___U",
+ stream);
+ }
+}
+
+/* Print enumerated type TYPE on STREAM. */
+
+static void
+print_enum_type (struct type *type, struct ui_file *stream)
+{
+ int len = TYPE_NFIELDS (type);
+ int i, lastval;
+
+ fprintf_filtered (stream, "(");
+ wrap_here (" ");
+
+ lastval = 0;
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (i)
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fputs_filtered (ada_enum_name (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 += 1;
+ }
+ fprintf_filtered (stream, ")");
+}
+
+/* Print representation of Ada fixed-point type TYPE on STREAM. */
+
+static void
+print_fixed_point_type (struct type *type, struct ui_file *stream)
+{
+ DOUBLEST delta = ada_delta (type);
+ DOUBLEST small = ada_fixed_to_float (type, 1.0);
+
+ if (delta < 0.0)
+ fprintf_filtered (stream, "delta ??");
+ else
+ {
+ fprintf_filtered (stream, "delta %g", (double) delta);
+ if (delta != small)
+ fprintf_filtered (stream, " <'small = %g>", (double) small);
+ }
+}
+
+/* Print representation of special VAX floating-point type TYPE on STREAM. */
+
+static void
+print_vax_floating_point_type (struct type *type, struct ui_file *stream)
+{
+ fprintf_filtered (stream, "<float format %c>",
+ ada_vax_float_type_suffix (type));
+}
+
+/* Print simple (constrained) array type TYPE on STREAM. LEVEL is the
+ recursion (indentation) level, in case the element type itself has
+ nested structure, and SHOW is the number of levels of internal
+ structure to show (see ada_print_type). */
+
+static void
+print_array_type (struct type *type, struct ui_file *stream, int show,
+ int level)
+{
+ int bitsize;
+ int n_indices;
+
+ bitsize = 0;
+ fprintf_filtered (stream, "array (");
+
+ n_indices = -1;
+ if (show < 0)
+ fprintf_filtered (stream, "...");
+ else
+ {
+ if (ada_is_packed_array_type (type))
+ type = ada_coerce_to_simple_array_type (type);
+ if (ada_is_simple_array (type))
+ {
+ struct type *range_desc_type =
+ ada_find_parallel_type (type, "___XA");
+ struct type *arr_type;
+
+ bitsize = 0;
+ if (range_desc_type == NULL)
+ {
+ for (arr_type = type; TYPE_CODE (arr_type) == TYPE_CODE_ARRAY;
+ arr_type = TYPE_TARGET_TYPE (arr_type))
+ {
+ if (arr_type != type)
+ fprintf_filtered (stream, ", ");
+ print_range (TYPE_INDEX_TYPE (arr_type), stream);
+ if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
+ bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
+ }
+ }
+ else
+ {
+ int k;
+ n_indices = TYPE_NFIELDS (range_desc_type);
+ for (k = 0, arr_type = type;
+ k < n_indices;
+ k += 1, arr_type = TYPE_TARGET_TYPE (arr_type))
+ {
+ if (k > 0)
+ fprintf_filtered (stream, ", ");
+ print_range_type_named (TYPE_FIELD_NAME
+ (range_desc_type, k), stream);
+ if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
+ bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
+ }
+ }
+ }
+ else
+ {
+ int i, i0;
+ for (i = i0 = ada_array_arity (type); i > 0; i -= 1)
+ fprintf_filtered (stream, "%s<>", i == i0 ? "" : ", ");
+ }
+ }
+
+ fprintf_filtered (stream, ") of ");
+ wrap_here ("");
+ ada_print_type (ada_array_element_type (type, n_indices), "", stream,
+ show == 0 ? 0 : show - 1, level + 1);
+ if (bitsize > 0)
+ fprintf_filtered (stream, " <packed: %d-bit elements>", bitsize);
+}
+
+/* Print the choices encoded by field FIELD_NUM of variant-part TYPE on
+ STREAM, assuming the VAL_TYPE is the type of the values. */
+
+static void
+print_choices (struct type *type, int field_num, struct ui_file *stream,
+ struct type *val_type)
+{
+ int have_output;
+ int p;
+ const char *name = TYPE_FIELD_NAME (type, field_num);
+
+ have_output = 0;
+
+ /* Skip over leading 'V': NOTE soon to be obsolete. */
+ if (name[0] == 'V')
+ {
+ if (!ada_scan_number (name, 1, NULL, &p))
+ goto Huh;
+ }
+ else
+ p = 0;
+
+ while (1)
+ {
+ switch (name[p])
+ {
+ default:
+ return;
+ case 'S':
+ case 'R':
+ case 'O':
+ if (have_output)
+ fprintf_filtered (stream, " | ");
+ have_output = 1;
+ break;
+ }
+
+ switch (name[p])
+ {
+ case 'S':
+ {
+ LONGEST W;
+ if (!ada_scan_number (name, p + 1, &W, &p))
+ goto Huh;
+ ada_print_scalar (val_type, W, stream);
+ break;
+ }
+ case 'R':
+ {
+ LONGEST L, U;
+ if (!ada_scan_number (name, p + 1, &L, &p)
+ || name[p] != 'T' || !ada_scan_number (name, p + 1, &U, &p))
+ goto Huh;
+ ada_print_scalar (val_type, L, stream);
+ fprintf_filtered (stream, " .. ");
+ ada_print_scalar (val_type, U, stream);
+ break;
+ }
+ case 'O':
+ fprintf_filtered (stream, "others");
+ p += 1;
+ break;
+ }
+ }
+
+Huh:
+ fprintf_filtered (stream, "??");
+
+}
+
+/* Assuming that field FIELD_NUM of TYPE is a VARIANTS field whose
+ discriminant is contained in OUTER_TYPE, print its variants on STREAM.
+ LEVEL is the recursion
+ (indentation) level, in case any of the fields themselves have
+ nested structure, and SHOW is the number of levels of internal structure
+ to show (see ada_print_type). For this purpose, fields nested in a
+ variant part are taken to be at the same level as the fields
+ immediately outside the variant part. */
+
+static void
+print_variant_clauses (struct type *type, int field_num,
+ struct type *outer_type, struct ui_file *stream,
+ int show, int level)
+{
+ int i;
+ struct type *var_type;
+ struct type *discr_type;
+
+ var_type = TYPE_FIELD_TYPE (type, field_num);
+ discr_type = ada_variant_discrim_type (var_type, outer_type);
+
+ if (TYPE_CODE (var_type) == TYPE_CODE_PTR)
+ {
+ var_type = TYPE_TARGET_TYPE (var_type);
+ if (TYPE_FLAGS (var_type) & TYPE_FLAG_STUB)
+ {
+ var_type = ada_find_parallel_type (var_type, "___XVU");
+ if (var_type == NULL)
+ return;
+ }
+ }
+
+ for (i = 0; i < TYPE_NFIELDS (var_type); i += 1)
+ {
+ fprintf_filtered (stream, "\n%*swhen ", level + 4, "");
+ print_choices (var_type, i, stream, discr_type);
+ fprintf_filtered (stream, " =>");
+ if (print_record_field_types (TYPE_FIELD_TYPE (var_type, i),
+ outer_type, stream, show, level + 4) <= 0)
+ fprintf_filtered (stream, " null;");
+ }
+}
+
+/* Assuming that field FIELD_NUM of TYPE is a variant part whose
+ discriminants are contained in OUTER_TYPE, print a description of it
+ on STREAM. LEVEL is the recursion (indentation) level, in case any of
+ the fields themselves have nested structure, and SHOW is the number of
+ levels of internal structure to show (see ada_print_type). For this
+ purpose, fields nested in a variant part are taken to be at the same
+ level as the fields immediately outside the variant part. */
+
+static void
+print_variant_part (struct type *type, int field_num, struct type *outer_type,
+ struct ui_file *stream, int show, int level)
+{
+ fprintf_filtered (stream, "\n%*scase %s is", level + 4, "",
+ ada_variant_discrim_name
+ (TYPE_FIELD_TYPE (type, field_num)));
+ print_variant_clauses (type, field_num, outer_type, stream, show,
+ level + 4);
+ fprintf_filtered (stream, "\n%*send case;", level + 4, "");
+}
+
+/* Print a description on STREAM of the fields in record type TYPE, whose
+ discriminants are in OUTER_TYPE. LEVEL is the recursion (indentation)
+ level, in case any of the fields themselves have nested structure,
+ and SHOW is the number of levels of internal structure to show
+ (see ada_print_type). Does not print parent type information of TYPE.
+ Returns 0 if no fields printed, -1 for an incomplete type, else > 0.
+ Prints each field beginning on a new line, but does not put a new line at
+ end. */
+
+static int
+print_record_field_types (struct type *type, struct type *outer_type,
+ struct ui_file *stream, int show, int level)
+{
+ int len, i, flds;
+
+ flds = 0;
+ len = TYPE_NFIELDS (type);
+
+ if (len == 0 && (TYPE_FLAGS (type) & TYPE_FLAG_STUB) != 0)
+ return -1;
+
+ for (i = 0; i < len; i += 1)
+ {
+ QUIT;
+
+ if (ada_is_parent_field (type, i) || ada_is_ignored_field (type, i))
+ ;
+ else if (ada_is_wrapper_field (type, i))
+ flds += print_record_field_types (TYPE_FIELD_TYPE (type, i), type,
+ stream, show, level);
+ else if (ada_is_variant_part (type, i))
+ {
+ print_variant_part (type, i, outer_type, stream, show, level);
+ flds = 1;
+ }
+ else
+ {
+ flds += 1;
+ fprintf_filtered (stream, "\n%*s", level + 4, "");
+ ada_print_type (TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 4);
+ fprintf_filtered (stream, ";");
+ }
+ }
+
+ return flds;
+}
+
+/* Print record type TYPE on STREAM. LEVEL is the recursion (indentation)
+ level, in case the element type itself has nested structure, and SHOW is
+ the number of levels of internal structure to show (see ada_print_type). */
+
+static void
+print_record_type (struct type *type0, struct ui_file *stream, int show,
+ int level)
+{
+ struct type *parent_type;
+ struct type *type;
+
+ type = type0;
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ struct type *type1 = ada_find_parallel_type (type, "___XVE");
+ if (type1 != NULL)
+ type = type1;
+ }
+
+ parent_type = ada_parent_type (type);
+ if (ada_type_name (parent_type) != NULL)
+ fprintf_filtered (stream, "new %s with ",
+ demangled_type_name (parent_type));
+ else if (parent_type == NULL && ada_is_tagged_type (type))
+ fprintf_filtered (stream, "tagged ");
+
+ fprintf_filtered (stream, "record");
+
+ if (show < 0)
+ fprintf_filtered (stream, " ... end record");
+ else
+ {
+ int flds;
+
+ flds = 0;
+ if (parent_type != NULL && ada_type_name (parent_type) == NULL)
+ flds += print_record_field_types (parent_type, parent_type,
+ stream, show, level);
+ flds += print_record_field_types (type, type, stream, show, level);
+
+ if (flds > 0)
+ fprintf_filtered (stream, "\n%*send record", level, "");
+ else if (flds < 0)
+ fprintf_filtered (stream, " <incomplete type> end record");
+ else
+ fprintf_filtered (stream, " null; end record");
+ }
+}
+
+/* Print the unchecked union type TYPE in something resembling Ada
+ format on STREAM. LEVEL is the recursion (indentation) level
+ in case the element type itself has nested structure, and SHOW is the
+ number of levels of internal structure to show (see ada_print_type). */
+static void
+print_unchecked_union_type (struct type *type, struct ui_file *stream,
+ int show, int level)
+{
+ fprintf_filtered (stream, "record (?) is");
+
+ if (show < 0)
+ fprintf_filtered (stream, " ... end record");
+ else if (TYPE_NFIELDS (type) == 0)
+ fprintf_filtered (stream, " null; end record");
+ else
+ {
+ int i;
+
+ fprintf_filtered (stream, "\n%*scase ? is", level + 4, "");
+
+ for (i = 0; i < TYPE_NFIELDS (type); i += 1)
+ {
+ fprintf_filtered (stream, "\n%*swhen ? =>\n%*s", level + 8, "",
+ level + 12, "");
+ ada_print_type (TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 12);
+ fprintf_filtered (stream, ";");
+ }
+
+ fprintf_filtered (stream, "\n%*send case;\n%*send record",
+ level + 4, "", level, "");
+ }
+}
+
+
+
+/* Print function or procedure type TYPE on STREAM. Make it a header
+ for function or procedure NAME if NAME is not null. */
+
+static void
+print_func_type (struct type *type, struct ui_file *stream, char *name)
+{
+ int i, len = TYPE_NFIELDS (type);
+
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
+ fprintf_filtered (stream, "procedure");
+ else
+ fprintf_filtered (stream, "function");
+
+ if (name != NULL && name[0] != '\0')
+ fprintf_filtered (stream, " %s", name);
+
+ if (len > 0)
+ {
+ fprintf_filtered (stream, " (");
+ for (i = 0; i < len; i += 1)
+ {
+ if (i > 0)
+ {
+ fputs_filtered ("; ", stream);
+ wrap_here (" ");
+ }
+ fprintf_filtered (stream, "a%d: ", i + 1);
+ ada_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
+ }
+ fprintf_filtered (stream, ")");
+ }
+
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, " return ");
+ ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0);
+ }
+}
+
+
+/* Print a description of a type TYPE0.
+ Output goes to STREAM (via stdio).
+ If VARSTRING is a non-empty string, print as an Ada variable/field
+ declaration.
+ SHOW+1 is the maximum number of levels of internal type structure
+ to show (this applies to record types, enumerated types, and
+ array types).
+ SHOW is the number of levels of internal type structure to show
+ when there is a type name for the SHOWth deepest level (0th is
+ outer level).
+ When SHOW<0, no inner structure is shown.
+ LEVEL indicates level of recursion (for nested definitions). */
+
+void
+ada_print_type (struct type *type0, char *varstring, struct ui_file *stream,
+ int show, int level)
+{
+ enum type_code code;
+ int demangled_args;
+ struct type *type = ada_completed_type (ada_get_base_type (type0));
+ char *type_name = demangled_type_name (type);
+ int is_var_decl = (varstring != NULL && varstring[0] != '\0');
+
+ if (type == NULL)
+ {
+ if (is_var_decl)
+ fprintf_filtered (stream, "%.*s: ",
+ ada_name_prefix_len (varstring), varstring);
+ fprintf_filtered (stream, "<null type?>");
+ return;
+ }
+
+ if (show > 0)
+ CHECK_TYPEDEF (type);
+
+ if (is_var_decl && TYPE_CODE (type) != TYPE_CODE_FUNC)
+ fprintf_filtered (stream, "%.*s: ",
+ ada_name_prefix_len (varstring), varstring);
+
+ if (type_name != NULL && show <= 0)
+ {
+ fprintf_filtered (stream, "%.*s",
+ ada_name_prefix_len (type_name), type_name);
+ return;
+ }
+
+ if (ada_is_aligner_type (type))
+ ada_print_type (ada_aligned_type (type), "", stream, show, level);
+ else if (ada_is_packed_array_type (type))
+ print_array_type (type, stream, show, level);
+ else
+ switch (TYPE_CODE (type))
+ {
+ default:
+ fprintf_filtered (stream, "<");
+ c_print_type (type, "", stream, show, level);
+ fprintf_filtered (stream, ">");
+ break;
+ case TYPE_CODE_PTR:
+ fprintf_filtered (stream, "access ");
+ ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
+ break;
+ case TYPE_CODE_REF:
+ fprintf_filtered (stream, "<ref> ");
+ ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
+ break;
+ case TYPE_CODE_ARRAY:
+ print_array_type (type, stream, show, level);
+ break;
+ case TYPE_CODE_INT:
+ if (ada_is_fixed_point_type (type))
+ print_fixed_point_type (type, stream);
+ else if (ada_is_vax_floating_type (type))
+ print_vax_floating_point_type (type, stream);
+ else
+ {
+ char *name = ada_type_name (type);
+ if (!ada_is_range_type_name (name))
+ fprintf_filtered (stream, "<%d-byte integer>",
+ TYPE_LENGTH (type));
+ else
+ {
+ fprintf_filtered (stream, "range ");
+ print_range_type_named (name, stream);
+ }
+ }
+ break;
+ case TYPE_CODE_RANGE:
+ if (ada_is_fixed_point_type (type))
+ print_fixed_point_type (type, stream);
+ else if (ada_is_vax_floating_type (type))
+ print_vax_floating_point_type (type, stream);
+ else if (ada_is_modular_type (type))
+ fprintf_filtered (stream, "mod %ld", (long) ada_modulus (type));
+ else
+ {
+ fprintf_filtered (stream, "range ");
+ print_range (type, stream);
+ }
+ break;
+ case TYPE_CODE_FLT:
+ fprintf_filtered (stream, "<%d-byte float>", TYPE_LENGTH (type));
+ break;
+ case TYPE_CODE_ENUM:
+ if (show < 0)
+ fprintf_filtered (stream, "(...)");
+ else
+ print_enum_type (type, stream);
+ break;
+ case TYPE_CODE_STRUCT:
+ if (ada_is_array_descriptor (type))
+ print_array_type (type, stream, show, level);
+ else if (ada_is_bogus_array_descriptor (type))
+ fprintf_filtered (stream,
+ "array (?) of ? (<mal-formed descriptor>)");
+ else
+ print_record_type (type, stream, show, level);
+ break;
+ case TYPE_CODE_UNION:
+ print_unchecked_union_type (type, stream, show, level);
+ break;
+ case TYPE_CODE_FUNC:
+ print_func_type (type, stream, varstring);
+ break;
+ }
+}
diff --git a/contrib/gdb/gdb/ada-valprint.c b/contrib/gdb/gdb/ada-valprint.c
new file mode 100644
index 0000000..f5f4118
--- /dev/null
+++ b/contrib/gdb/gdb/ada-valprint.c
@@ -0,0 +1,987 @@
+/* Support for printing Ada values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1997, 2001
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You 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 <ctype.h>
+#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 "annotate.h"
+#include "ada-lang.h"
+#include "c-lang.h"
+#include "infcall.h"
+
+/* Encapsulates arguments to ada_val_print. */
+struct ada_val_print_args
+{
+ struct type *type;
+ char *valaddr0;
+ int embedded_offset;
+ CORE_ADDR address;
+ struct ui_file *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+};
+
+static void print_record (struct type *, char *, struct ui_file *, int,
+ int, enum val_prettyprint);
+
+static int print_field_values (struct type *, char *, struct ui_file *,
+ int, int, enum val_prettyprint,
+ int, struct type *, char *);
+
+static int print_variant_part (struct type *, int, char *,
+ struct ui_file *, int, int,
+ enum val_prettyprint, int, struct type *,
+ char *);
+
+static void val_print_packed_array_elements (struct type *, char *valaddr,
+ int, struct ui_file *, int, int,
+ enum val_prettyprint);
+
+static void adjust_type_signedness (struct type *);
+
+static int ada_val_print_stub (void *args0);
+
+static int ada_val_print_1 (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+
+/* Make TYPE unsigned if its range of values includes no negatives. */
+static void
+adjust_type_signedness (struct type *type)
+{
+ if (type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE
+ && TYPE_LOW_BOUND (type) >= 0)
+ TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+}
+
+/* Assuming TYPE is a simple array type, prints its lower bound on STREAM,
+ if non-standard (i.e., other than 1 for numbers, other than lower bound
+ of index type for enumerated type). Returns 1 if something printed,
+ otherwise 0. */
+
+static int
+print_optional_low_bound (struct ui_file *stream, struct type *type)
+{
+ struct type *index_type;
+ long low_bound;
+
+ index_type = TYPE_INDEX_TYPE (type);
+ low_bound = 0;
+
+ if (index_type == NULL)
+ return 0;
+ if (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
+ {
+ low_bound = TYPE_LOW_BOUND (index_type);
+ index_type = TYPE_TARGET_TYPE (index_type);
+ }
+ else
+ return 0;
+
+ switch (TYPE_CODE (index_type))
+ {
+ case TYPE_CODE_ENUM:
+ if (low_bound == TYPE_FIELD_BITPOS (index_type, 0))
+ return 0;
+ break;
+ case TYPE_CODE_UNDEF:
+ index_type = builtin_type_long;
+ /* FALL THROUGH */
+ default:
+ if (low_bound == 1)
+ return 0;
+ break;
+ }
+
+ ada_print_scalar (index_type, (LONGEST) low_bound, stream);
+ fprintf_filtered (stream, " => ");
+ return 1;
+}
+
+/* Version of val_print_array_elements for GNAT-style packed arrays.
+ Prints elements of packed array of type TYPE at bit offset
+ BITOFFSET from VALADDR on STREAM. Formats according to FORMAT and
+ separates with commas. RECURSE is the recursion (nesting) level.
+ If PRETTY, uses "prettier" format. TYPE must have been decoded (as
+ by ada_coerce_to_simple_array). */
+
+static void
+val_print_packed_array_elements (struct type *type, char *valaddr,
+ int bitoffset, struct ui_file *stream,
+ int format, 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;
+ unsigned long bitsize = TYPE_FIELD_BITSIZE (type, 0);
+ struct value *mark = value_mark ();
+
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (check_typedef (elttype));
+
+ {
+ LONGEST low, high;
+ if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0), &low, &high) < 0)
+ len = 1;
+ else
+ len = high - low + 1;
+ }
+
+ i = 0;
+ annotate_array_section_begin (i, elttype);
+
+ while (i < len && things_printed < print_max)
+ {
+ struct value *v0, *v1;
+ int i0;
+
+ 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));
+
+ i0 = i;
+ v0 = ada_value_primitive_packed_val (NULL, valaddr,
+ (i0 * bitsize) / HOST_CHAR_BIT,
+ (i0 * bitsize) % HOST_CHAR_BIT,
+ bitsize, elttype);
+ while (1)
+ {
+ i += 1;
+ if (i >= len)
+ break;
+ v1 = ada_value_primitive_packed_val (NULL, valaddr,
+ (i * bitsize) / HOST_CHAR_BIT,
+ (i * bitsize) % HOST_CHAR_BIT,
+ bitsize, elttype);
+ if (memcmp (VALUE_CONTENTS (v0), VALUE_CONTENTS (v1), eltlen) != 0)
+ break;
+ }
+
+ if (i - i0 > repeat_count_threshold)
+ {
+ val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format,
+ 0, recurse + 1, pretty);
+ annotate_elt_rep (i - i0);
+ fprintf_filtered (stream, " <repeats %u times>", i - i0);
+ annotate_elt_rep_end ();
+
+ }
+ else
+ {
+ int j;
+ for (j = i0; j < i; j += 1)
+ {
+ if (j > i0)
+ {
+ 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));
+ }
+ val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format,
+ 0, recurse + 1, pretty);
+ annotate_elt ();
+ }
+ }
+ things_printed += i - i0;
+ }
+ annotate_array_section_end ();
+ if (i < len)
+ {
+ fprintf_filtered (stream, "...");
+ }
+
+ value_free_to_mark (mark);
+}
+
+static struct type *
+printable_val_type (struct type *type, char *valaddr)
+{
+ return ada_to_fixed_type (ada_aligned_type (type), valaddr, 0, NULL);
+}
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. TYPE_LEN is the length in bytes
+ (1 or 2) of the character. */
+
+void
+ada_emit_char (int c, struct ui_file *stream, int quoter, int type_len)
+{
+ if (type_len != 2)
+ type_len = 1;
+
+ c &= (1 << (type_len * TARGET_CHAR_BIT)) - 1;
+
+ if (isascii (c) && isprint (c))
+ {
+ if (c == quoter && c == '"')
+ fprintf_filtered (stream, "[\"%c\"]", quoter);
+ else
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ fprintf_filtered (stream, "[\"%0*x\"]", type_len * 2, c);
+}
+
+/* Character #I of STRING, given that TYPE_LEN is the size in bytes (1
+ or 2) of a character. */
+
+static int
+char_at (char *string, int i, int type_len)
+{
+ if (type_len == 1)
+ return string[i];
+ else
+ return (int) extract_unsigned_integer (string + 2 * i, 2);
+}
+
+void
+ada_printchar (int c, struct ui_file *stream)
+{
+ fputs_filtered ("'", stream);
+ ada_emit_char (c, stream, '\'', 1);
+ fputs_filtered ("'", stream);
+}
+
+/* [From print_type_scalar in typeprint.c]. Print VAL on STREAM in a
+ form appropriate for TYPE. */
+
+void
+ada_print_scalar (struct type *type, LONGEST val, struct ui_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 (ada_enum_name (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:
+ ada_print_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:
+ warning ("internal error: unhandled type in ada_print_scalar");
+ break;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+ gdb_flush (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. TYPE_LEN is the length (1 or 2) of the character type.
+ */
+
+static void
+printstr (struct ui_file *stream, char *string, unsigned int length,
+ int force_ellipses, int type_len)
+{
+ unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", stream);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < print_max; i += 1)
+ {
+ /* 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 &&
+ char_at (string, rep1, type_len) == char_at (string, i,
+ type_len))
+ {
+ rep1 += 1;
+ reps += 1;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\", ", stream);
+ else
+ fputs_filtered ("\", ", stream);
+ in_quotes = 0;
+ }
+ fputs_filtered ("'", stream);
+ ada_emit_char (char_at (string, i, type_len), stream, '\'',
+ type_len);
+ fputs_filtered ("'", stream);
+ fprintf_filtered (stream, " <repeats %u times>", 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;
+ }
+ ada_emit_char (char_at (string, i, type_len), stream, '"',
+ type_len);
+ things_printed += 1;
+ }
+ }
+
+ /* 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);
+}
+
+void
+ada_printstr (struct ui_file *stream, char *string, unsigned int length,
+ int force_ellipses, int width)
+{
+ printstr (stream, string, length, force_ellipses, width);
+}
+
+
+/* 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 as for the printf % codes or 0 for natural format).
+ The data at VALADDR is in target byte order.
+
+ If the data is printed as a string, returns the number of string characters
+ printed.
+
+ If DEREF_REF is nonzero, then dereference references, otherwise just print
+ them like pointers.
+
+ RECURSE indicates the amount of indentation to supply before
+ continuation lines; this amount is roughly twice the value of RECURSE.
+
+ When PRETTY is non-zero, prints record fields on separate lines.
+ (For some reason, the current version of gdb instead uses a global
+ variable---prettyprint_arrays--- to causes a similar effect on
+ arrays.) */
+
+int
+ada_val_print (struct type *type, char *valaddr0, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ struct ada_val_print_args args;
+ args.type = type;
+ args.valaddr0 = valaddr0;
+ args.embedded_offset = embedded_offset;
+ args.address = address;
+ args.stream = stream;
+ args.format = format;
+ args.deref_ref = deref_ref;
+ args.recurse = recurse;
+ args.pretty = pretty;
+
+ return catch_errors (ada_val_print_stub, &args, NULL, RETURN_MASK_ALL);
+}
+
+/* Helper for ada_val_print; used as argument to catch_errors to
+ unmarshal the arguments to ada_val_print_1, which does the work. */
+static int
+ada_val_print_stub (void * args0)
+{
+ struct ada_val_print_args *argsp = (struct ada_val_print_args *) args0;
+ return ada_val_print_1 (argsp->type, argsp->valaddr0,
+ argsp->embedded_offset, argsp->address,
+ argsp->stream, argsp->format, argsp->deref_ref,
+ argsp->recurse, argsp->pretty);
+}
+
+/* See the comment on ada_val_print. This function differs in that it
+ * does not catch evaluation errors (leaving that to ada_val_print). */
+
+static int
+ada_val_print_1 (struct type *type, char *valaddr0, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ unsigned int len;
+ int i;
+ struct type *elttype;
+ unsigned int eltlen;
+ LONGEST val;
+ CORE_ADDR addr;
+ char *valaddr = valaddr0 + embedded_offset;
+
+ CHECK_TYPEDEF (type);
+
+ if (ada_is_array_descriptor (type) || ada_is_packed_array_type (type))
+ {
+ int retn;
+ struct value *mark = value_mark ();
+ struct value *val;
+ val = value_from_contents_and_address (type, valaddr, address);
+ val = ada_coerce_to_simple_array_ptr (val);
+ if (val == NULL)
+ {
+ fprintf_filtered (stream, "(null)");
+ retn = 0;
+ }
+ else
+ retn = ada_val_print_1 (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
+ VALUE_ADDRESS (val), stream, format,
+ deref_ref, recurse, pretty);
+ value_free_to_mark (mark);
+ return retn;
+ }
+
+ valaddr = ada_aligned_value_addr (type, valaddr);
+ embedded_offset -= valaddr - valaddr0 - embedded_offset;
+ type = printable_val_type (type, valaddr);
+
+ switch (TYPE_CODE (type))
+ {
+ default:
+ return c_val_print (type, valaddr0, embedded_offset, address, stream,
+ format, deref_ref, recurse, pretty);
+
+ case TYPE_CODE_INT:
+ case TYPE_CODE_RANGE:
+ if (ada_is_fixed_point_type (type))
+ {
+ LONGEST v = unpack_long (type, valaddr);
+ int len = TYPE_LENGTH (type);
+
+ fprintf_filtered (stream, len < 4 ? "%.11g" : "%.17g",
+ (double) ada_fixed_to_float (type, v));
+ return 0;
+ }
+ else if (ada_is_vax_floating_type (type))
+ {
+ struct value *val =
+ value_from_contents_and_address (type, valaddr, address);
+ struct value *func = ada_vax_float_print_function (type);
+ if (func != 0)
+ {
+ static struct type *parray_of_char = NULL;
+ struct value *printable_val;
+
+ if (parray_of_char == NULL)
+ parray_of_char =
+ make_pointer_type
+ (create_array_type
+ (NULL, builtin_type_char,
+ create_range_type (NULL, builtin_type_int, 0, 32)), NULL);
+
+ printable_val =
+ value_ind (value_cast (parray_of_char,
+ call_function_by_hand (func, 1,
+ &val)));
+
+ fprintf_filtered (stream, "%s", VALUE_CONTENTS (printable_val));
+ return 0;
+ }
+ /* No special printing function. Do as best we can. */
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_RANGE)
+ {
+ struct type *target_type = TYPE_TARGET_TYPE (type);
+ if (TYPE_LENGTH (type) != TYPE_LENGTH (target_type))
+ {
+ /* Obscure case of range type that has different length from
+ its base type. Perform a conversion, or we will get a
+ nonsense value. Actually, we could use the same
+ code regardless of lengths; I'm just avoiding a cast. */
+ struct value *v = value_cast (target_type,
+ value_from_contents_and_address
+ (type, valaddr, 0));
+ return ada_val_print_1 (target_type, VALUE_CONTENTS (v), 0, 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ else
+ return ada_val_print_1 (TYPE_TARGET_TYPE (type),
+ valaddr0, embedded_offset,
+ address, stream, format, deref_ref,
+ recurse, pretty);
+ }
+ else
+ {
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ }
+ else
+ {
+ val_print_type_code_int (type, valaddr, stream);
+ if (ada_is_character_type (type))
+ {
+ fputs_filtered (" ", stream);
+ ada_printchar ((unsigned char) unpack_long (type, valaddr),
+ stream);
+ }
+ }
+ return 0;
+ }
+
+ 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)
+ {
+ const char *name = ada_enum_name (TYPE_FIELD_NAME (type, i));
+ if (name[0] == '\'')
+ fprintf_filtered (stream, "%ld %s", (long) val, name);
+ else
+ fputs_filtered (name, stream);
+ }
+ else
+ {
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_STRUCT:
+ if (ada_is_bogus_array_descriptor (type))
+ {
+ fprintf_filtered (stream, "(...?)");
+ return 0;
+ }
+ else
+ {
+ print_record (type, valaddr, stream, format, recurse, pretty);
+ return 0;
+ }
+
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ {
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (elttype);
+ len = TYPE_LENGTH (type) / eltlen;
+
+ /* For an array of chars, print with string syntax. */
+ if (ada_is_string_type (type) && (format == 0 || format == 's'))
+ {
+ if (prettyprint_arrays)
+ {
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ /* 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;
+ temp_len < len && temp_len < print_max
+ && char_at (valaddr, temp_len, eltlen) != 0;
+ temp_len += 1);
+ len = temp_len;
+ }
+
+ printstr (stream, valaddr, len, 0, eltlen);
+ }
+ else
+ {
+ len = 0;
+ fprintf_filtered (stream, "(");
+ print_optional_low_bound (stream, type);
+ if (TYPE_FIELD_BITSIZE (type, 0) > 0)
+ val_print_packed_array_elements (type, valaddr, 0, stream,
+ format, recurse, pretty);
+ else
+ val_print_array_elements (type, valaddr, address, stream,
+ format, deref_ref, recurse,
+ pretty, 0);
+ fprintf_filtered (stream, ")");
+ }
+ gdb_flush (stream);
+ return len;
+ }
+
+ case TYPE_CODE_REF:
+ elttype = check_typedef (TYPE_TARGET_TYPE (type));
+ if (addressprint)
+ {
+ fprintf_filtered (stream, "@");
+ /* Extract an address, assume that the address is unsigned. */
+ print_address_numeric
+ (extract_unsigned_integer (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)
+ {
+ LONGEST deref_val_int = (LONGEST)
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr);
+ if (deref_val_int != 0)
+ {
+ struct value *deref_val =
+ ada_value_ind (value_from_longest
+ (lookup_pointer_type (elttype),
+ deref_val_int));
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val), 0,
+ VALUE_ADDRESS (deref_val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ }
+ else
+ fputs_filtered ("(null)", stream);
+ }
+ else
+ fputs_filtered ("???", stream);
+ }
+ break;
+ }
+ return 0;
+}
+
+static int
+print_variant_part (struct type *type, int field_num, char *valaddr,
+ struct ui_file *stream, int format, int recurse,
+ enum val_prettyprint pretty, int comma_needed,
+ struct type *outer_type, char *outer_valaddr)
+{
+ struct type *var_type = TYPE_FIELD_TYPE (type, field_num);
+ int which = ada_which_variant_applies (var_type, outer_type, outer_valaddr);
+
+ if (which < 0)
+ return 0;
+ else
+ return print_field_values
+ (TYPE_FIELD_TYPE (var_type, which),
+ valaddr + TYPE_FIELD_BITPOS (type, field_num) / HOST_CHAR_BIT
+ + TYPE_FIELD_BITPOS (var_type, which) / HOST_CHAR_BIT,
+ stream, format, recurse, pretty,
+ comma_needed, outer_type, outer_valaddr);
+}
+
+int
+ada_value_print (struct value *val0, struct ui_file *stream, int format,
+ enum val_prettyprint pretty)
+{
+ char *valaddr = VALUE_CONTENTS (val0);
+ CORE_ADDR address = VALUE_ADDRESS (val0) + VALUE_OFFSET (val0);
+ struct type *type =
+ ada_to_fixed_type (VALUE_TYPE (val0), valaddr, address, NULL);
+ struct value *val =
+ value_from_contents_and_address (type, valaddr, address);
+
+ /* If it is a pointer, indicate what it points to. */
+ 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_LENGTH (TYPE_TARGET_TYPE (type)) == sizeof (char) &&
+ TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT &&
+ !TYPE_UNSIGNED (TYPE_TARGET_TYPE (type)))
+ {
+ /* Print nothing */
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") ");
+ }
+ }
+ else if (ada_is_array_descriptor (type))
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") ");
+ }
+ else if (ada_is_bogus_array_descriptor (type))
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") (...?)");
+ return 0;
+ }
+ return (val_print (type, VALUE_CONTENTS (val), 0, address,
+ stream, format, 1, 0, pretty));
+}
+
+static void
+print_record (struct type *type, char *valaddr, struct ui_file *stream,
+ int format, int recurse, enum val_prettyprint pretty)
+{
+ CHECK_TYPEDEF (type);
+
+ fprintf_filtered (stream, "(");
+
+ if (print_field_values (type, valaddr, stream, format, recurse, pretty,
+ 0, type, valaddr) != 0 && pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+
+ fprintf_filtered (stream, ")");
+}
+
+/* Print out fields of value at VALADDR having structure type TYPE.
+
+ TYPE, VALADDR, STREAM, FORMAT, RECURSE, and PRETTY have the
+ same meanings as in ada_print_value and ada_val_print.
+
+ OUTER_TYPE and OUTER_VALADDR give type and address of enclosing record
+ (used to get discriminant values when printing variant parts).
+
+ COMMA_NEEDED is 1 if fields have been printed at the current recursion
+ level, so that a comma is needed before any field printed by this
+ call.
+
+ Returns 1 if COMMA_NEEDED or any fields were printed. */
+
+static int
+print_field_values (struct type *type, char *valaddr, struct ui_file *stream,
+ int format, int recurse, enum val_prettyprint pretty,
+ int comma_needed, struct type *outer_type,
+ char *outer_valaddr)
+{
+ int i, len;
+
+ len = TYPE_NFIELDS (type);
+
+ for (i = 0; i < len; i += 1)
+ {
+ if (ada_is_ignored_field (type, i))
+ continue;
+
+ if (ada_is_wrapper_field (type, i))
+ {
+ comma_needed =
+ print_field_values (TYPE_FIELD_TYPE (type, i),
+ valaddr
+ + TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT,
+ stream, format, recurse, pretty,
+ comma_needed, type, valaddr);
+ continue;
+ }
+ else if (ada_is_variant_part (type, i))
+ {
+ comma_needed =
+ print_variant_part (type, i, valaddr,
+ stream, format, recurse, pretty, comma_needed,
+ outer_type, outer_valaddr);
+ continue;
+ }
+
+ if (comma_needed)
+ fprintf_filtered (stream, ", ");
+ comma_needed = 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);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus, DMGL_NO_OPTS);
+ fputs_filtered ("\" \"", stream);
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus, DMGL_NO_OPTS);
+ fputs_filtered ("\") \"", stream);
+ }
+ else
+ {
+ annotate_field_begin (TYPE_FIELD_TYPE (type, i));
+ fprintf_filtered (stream, "%.*s",
+ ada_name_prefix_len (TYPE_FIELD_NAME (type, i)),
+ TYPE_FIELD_NAME (type, i));
+ annotate_field_name_end ();
+ fputs_filtered (" => ", stream);
+ annotate_field_value ();
+ }
+
+ if (TYPE_FIELD_PACKED (type, i))
+ {
+ struct value *v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ if (TYPE_CPLUS_SPECIFIC (type) != NULL
+ && TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", stream);
+ }
+ else
+ {
+ int bit_pos = TYPE_FIELD_BITPOS (type, i);
+ int bit_size = TYPE_FIELD_BITSIZE (type, i);
+
+ adjust_type_signedness (TYPE_FIELD_TYPE (type, i));
+ v = ada_value_primitive_packed_val (NULL, valaddr,
+ bit_pos / HOST_CHAR_BIT,
+ bit_pos % HOST_CHAR_BIT,
+ bit_size,
+ TYPE_FIELD_TYPE (type, i));
+ val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0, 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ else
+ ada_val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT,
+ 0, 0, stream, format, 0, recurse + 1, pretty);
+ annotate_field_end ();
+ }
+
+ return comma_needed;
+}
diff --git a/contrib/gdb/gdb/alpha-mdebug-tdep.c b/contrib/gdb/gdb/alpha-mdebug-tdep.c
new file mode 100644
index 0000000..153ed11
--- /dev/null
+++ b/contrib/gdb/gdb/alpha-mdebug-tdep.c
@@ -0,0 +1,386 @@
+/* Target-dependent mdebug code for the ALPHA architecture.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame-unwind.h"
+#include "frame-base.h"
+#include "symtab.h"
+#include "gdbcore.h"
+#include "block.h"
+#include "gdb_assert.h"
+
+#include "alpha-tdep.h"
+
+/* FIXME: Some of this code should perhaps be merged with mips. */
+
+/* *INDENT-OFF* */
+/* 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 | |
+ | | | --- |-------------------------------|<-- 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
+ | |
+*/
+/* *INDENT-ON* */
+
+#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr)
+#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)
+
+/* Locate the mdebug PDR for the given PC. Return null if one can't
+ be found; you'll have to fall back to other methods in that case. */
+
+static alpha_extra_func_info_t
+find_proc_desc (CORE_ADDR pc)
+{
+ struct block *b = block_for_pc (pc);
+ alpha_extra_func_info_t proc_desc = NULL;
+ struct symbol *sym = NULL;
+
+ if (b)
+ {
+ CORE_ADDR startaddr;
+ find_pc_partial_function (pc, NULL, &startaddr, NULL);
+
+ 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_DOMAIN, 0, NULL);
+ }
+
+ if (sym)
+ {
+ proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym);
+
+ /* If we never found a PDR for this function in symbol reading,
+ then examine prologues to find the information. */
+ if (proc_desc->pdr.framereg == -1)
+ proc_desc = NULL;
+ }
+
+ return 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
+alpha_mdebug_after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
+{
+ 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) == ALPHA_SP_REGNUM
+ && PROC_FRAME_OFFSET (proc_desc) == 0)
+ return 0;
+ }
+
+ return alpha_after_prologue (pc);
+}
+
+/* Return non-zero if we *might* be in a function prologue. Return zero
+ if we are definitively *not* in a function prologue. */
+
+static int
+alpha_mdebug_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
+{
+ CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc);
+ return (after_prologue_pc == 0 || pc < after_prologue_pc);
+}
+
+
+/* Frame unwinder that reads mdebug PDRs. */
+
+struct alpha_mdebug_unwind_cache
+{
+ alpha_extra_func_info_t proc_desc;
+ CORE_ADDR vfp;
+ CORE_ADDR *saved_regs;
+};
+
+/* Extract all of the information about the frame from PROC_DESC
+ and store the resulting register save locations in the structure. */
+
+static struct alpha_mdebug_unwind_cache *
+alpha_mdebug_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct alpha_mdebug_unwind_cache *info;
+ alpha_extra_func_info_t proc_desc;
+ ULONGEST vfp;
+ CORE_ADDR pc, reg_position;
+ unsigned long mask;
+ int ireg, returnreg;
+
+ if (*this_prologue_cache)
+ return *this_prologue_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache);
+ *this_prologue_cache = info;
+ pc = frame_pc_unwind (next_frame);
+
+ /* ??? We don't seem to be able to cache the lookup of the PDR
+ from alpha_mdebug_frame_p. It'd be nice if we could change
+ the arguments to that function. Oh well. */
+ proc_desc = find_proc_desc (pc);
+ info->proc_desc = proc_desc;
+ gdb_assert (proc_desc != NULL);
+
+ info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
+
+ /* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */
+ frame_unwind_unsigned_register (next_frame, PROC_FRAME_REG (proc_desc), &vfp);
+ vfp += PROC_FRAME_OFFSET (info->proc_desc);
+ info->vfp = vfp;
+
+ /* Fill in the offsets for the registers which gen_mask says were saved. */
+
+ reg_position = vfp + 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))
+ {
+ /* Clear bit for RA so we don't save it again later. */
+ mask &= ~(1 << returnreg);
+
+ info->saved_regs[returnreg] = reg_position;
+ reg_position += 8;
+ }
+
+ for (ireg = 0; ireg <= 31; ++ireg)
+ if (mask & (1 << ireg))
+ {
+ info->saved_regs[ireg] = reg_position;
+ reg_position += 8;
+ }
+
+ reg_position = vfp + PROC_FREG_OFFSET (proc_desc);
+ mask = PROC_FREG_MASK (proc_desc);
+
+ for (ireg = 0; ireg <= 31; ++ireg)
+ if (mask & (1 << ireg))
+ {
+ info->saved_regs[ALPHA_FP0_REGNUM + ireg] = reg_position;
+ reg_position += 8;
+ }
+
+ return info;
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+ frame. This will be used to create a new GDB frame struct. */
+
+static void
+alpha_mdebug_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct alpha_mdebug_unwind_cache *info
+ = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+ *this_id = frame_id_build (info->vfp, frame_func_unwind (next_frame));
+}
+
+/* Retrieve the value of REGNUM in FRAME. Don't give up! */
+
+static void
+alpha_mdebug_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct alpha_mdebug_unwind_cache *info
+ = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+ /* The PC of the previous frame is stored in the link register of
+ the current frame. Frob regnum so that we pull the value from
+ the correct place. */
+ if (regnum == ALPHA_PC_REGNUM)
+ regnum = PROC_PC_REG (info->proc_desc);
+
+ /* For all registers known to be saved in the current frame,
+ do the obvious and pull the value out. */
+ if (info->saved_regs[regnum])
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = info->saved_regs[regnum];
+ *realnump = -1;
+ if (bufferp != NULL)
+ get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE);
+ return;
+ }
+
+ /* The stack pointer of the previous frame is computed by popping
+ the current stack frame. */
+ if (regnum == ALPHA_SP_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (bufferp != NULL)
+ store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
+ return;
+ }
+
+ /* Otherwise assume the next frame has the same register value. */
+ frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+}
+
+static const struct frame_unwind alpha_mdebug_frame_unwind = {
+ NORMAL_FRAME,
+ alpha_mdebug_frame_this_id,
+ alpha_mdebug_frame_prev_register
+};
+
+const struct frame_unwind *
+alpha_mdebug_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ alpha_extra_func_info_t proc_desc;
+
+ /* If this PC does not map to a PDR, then clearly this isn't an
+ mdebug frame. */
+ proc_desc = find_proc_desc (pc);
+ if (proc_desc == NULL)
+ return NULL;
+
+ /* If we're in the prologue, the PDR for this frame is not yet valid.
+ Say no here and we'll fall back on the heuristic unwinder. */
+ if (alpha_mdebug_in_prologue (pc, proc_desc))
+ return NULL;
+
+ return &alpha_mdebug_frame_unwind;
+}
+
+static CORE_ADDR
+alpha_mdebug_frame_base_address (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct alpha_mdebug_unwind_cache *info
+ = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+ return info->vfp;
+}
+
+static CORE_ADDR
+alpha_mdebug_frame_locals_address (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct alpha_mdebug_unwind_cache *info
+ = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+ return info->vfp - PROC_LOCALOFF (info->proc_desc);
+}
+
+static CORE_ADDR
+alpha_mdebug_frame_args_address (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct alpha_mdebug_unwind_cache *info
+ = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+ return info->vfp - ALPHA_NUM_ARG_REGS * 8;
+}
+
+static const struct frame_base alpha_mdebug_frame_base = {
+ &alpha_mdebug_frame_unwind,
+ alpha_mdebug_frame_base_address,
+ alpha_mdebug_frame_locals_address,
+ alpha_mdebug_frame_args_address
+};
+
+static const struct frame_base *
+alpha_mdebug_frame_base_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ alpha_extra_func_info_t proc_desc;
+
+ /* If this PC does not map to a PDR, then clearly this isn't an
+ mdebug frame. */
+ proc_desc = find_proc_desc (pc);
+ if (proc_desc == NULL)
+ return NULL;
+
+ return &alpha_mdebug_frame_base;
+}
+
+
+void
+alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ frame_unwind_append_sniffer (gdbarch, alpha_mdebug_frame_sniffer);
+ frame_base_append_sniffer (gdbarch, alpha_mdebug_frame_base_sniffer);
+}
diff --git a/contrib/gdb/gdb/alpha-nat.c b/contrib/gdb/gdb/alpha-nat.c
new file mode 100644
index 0000000..0a78d94
--- /dev/null
+++ b/contrib/gdb/gdb/alpha-nat.c
@@ -0,0 +1,272 @@
+/* Low level Alpha interface, for GDB when running native.
+ Copyright 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "regcache.h"
+
+#include "alpha-tdep.h"
+
+#include <sys/ptrace.h>
+#ifdef __linux__
+#include <asm/reg.h>
+#include <alpha/ptrace.h>
+#else
+#include <alpha/coreregs.h>
+#endif
+#include <sys/user.h>
+
+/* Prototypes for local functions. */
+
+static void fetch_osf_core_registers (char *, unsigned, int, CORE_ADDR);
+static void fetch_elf_core_registers (char *, unsigned, int, CORE_ADDR);
+
+/* 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_osf_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR reg_addr)
+{
+ int regno;
+ 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. OSF5 uses different names for the register
+ enum list, need to handle two cases. The actual values are the
+ same. */
+ static int const core_reg_mapping[ALPHA_NUM_REGS] =
+ {
+#ifdef NCF_REGS
+#define EFL NCF_REGS
+ CF_V0, CF_T0, CF_T1, CF_T2, CF_T3, CF_T4, CF_T5, CF_T6,
+ CF_T7, CF_S0, CF_S1, CF_S2, CF_S3, CF_S4, CF_S5, CF_S6,
+ CF_A0, CF_A1, CF_A2, CF_A3, CF_A4, CF_A5, CF_T8, CF_T9,
+ CF_T10, CF_T11, CF_RA, CF_T12, CF_AT, CF_GP, CF_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,
+ CF_PC, -1
+#else
+#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
+#endif
+ };
+
+ for (regno = 0; regno < ALPHA_NUM_REGS; regno++)
+ {
+ if (CANNOT_FETCH_REGISTER (regno))
+ {
+ supply_register (regno, NULL);
+ continue;
+ }
+ addr = 8 * core_reg_mapping[regno];
+ if (addr < 0 || addr >= core_reg_size)
+ {
+ /* ??? UNIQUE is a new addition. Don't generate an error. */
+ if (regno == ALPHA_UNIQUE_REGNUM)
+ {
+ supply_register (regno, NULL);
+ continue;
+ }
+ 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.", REGISTER_NAME (bad_reg));
+ }
+}
+
+static void
+fetch_elf_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR reg_addr)
+{
+ if (core_reg_size < 32 * 8)
+ {
+ error ("Core file register section too small (%u bytes).", core_reg_size);
+ return;
+ }
+
+ switch (which)
+ {
+ case 0: /* integer registers */
+ /* PC is in slot 32; UNIQUE is in slot 33, if present. */
+ alpha_supply_int_regs (-1, core_reg_sect, core_reg_sect + 31*8,
+ (core_reg_size >= 33 * 8
+ ? core_reg_sect + 32*8 : NULL));
+ break;
+
+ case 2: /* floating-point registers */
+ /* FPCR is in slot 32. */
+ alpha_supply_fp_regs (-1, core_reg_sect, core_reg_sect + 31*8);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* Map gdb internal register number to a ptrace ``address''.
+ These ``addresses'' are defined in <sys/ptrace.h>, with
+ the exception of ALPHA_UNIQUE_PTRACE_ADDR. */
+
+#ifndef ALPHA_UNIQUE_PTRACE_ADDR
+#define ALPHA_UNIQUE_PTRACE_ADDR 0
+#endif
+
+CORE_ADDR
+register_addr (int regno, CORE_ADDR blockend)
+{
+ if (regno == PC_REGNUM)
+ return PC;
+ if (regno == ALPHA_UNIQUE_REGNUM)
+ return ALPHA_UNIQUE_PTRACE_ADDR;
+ if (regno < FP0_REGNUM)
+ return GPR_BASE + regno;
+ else
+ return FPR_BASE + regno - FP0_REGNUM;
+}
+
+int
+kernel_u_size (void)
+{
+ return (sizeof (struct user));
+}
+
+#if defined(USE_PROC_FS) || defined(HAVE_GREGSET_T)
+#include <sys/procfs.h>
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* Locate the UNIQUE value within the gregset_t. */
+#ifndef ALPHA_REGSET_UNIQUE
+#define ALPHA_REGSET_UNIQUE(ptr) NULL
+#endif
+
+/*
+ * See the comment in m68k-tdep.c regarding the utility of these functions.
+ */
+
+void
+supply_gregset (gdb_gregset_t *gregsetp)
+{
+ long *regp = ALPHA_REGSET_BASE (gregsetp);
+ void *unique = ALPHA_REGSET_UNIQUE (gregsetp);
+
+ /* PC is in slot 32. */
+ alpha_supply_int_regs (-1, regp, regp + 31, unique);
+}
+
+void
+fill_gregset (gdb_gregset_t *gregsetp, int regno)
+{
+ long *regp = ALPHA_REGSET_BASE (gregsetp);
+ void *unique = ALPHA_REGSET_UNIQUE (gregsetp);
+
+ /* PC is in slot 32. */
+ alpha_fill_int_regs (regno, regp, regp + 31, unique);
+}
+
+/*
+ * Now we do the same thing for floating-point registers.
+ * Again, see the comments in m68k-tdep.c.
+ */
+
+void
+supply_fpregset (gdb_fpregset_t *fpregsetp)
+{
+ long *regp = ALPHA_REGSET_BASE (fpregsetp);
+
+ /* FPCR is in slot 32. */
+ alpha_supply_fp_regs (-1, regp, regp + 31);
+}
+
+void
+fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
+{
+ long *regp = ALPHA_REGSET_BASE (fpregsetp);
+
+ /* FPCR is in slot 32. */
+ alpha_fill_fp_regs (regno, regp, regp + 31);
+}
+#endif
+
+
+/* Register that we are able to handle alpha core file formats. */
+
+static struct core_fns alpha_osf_core_fns =
+{
+ /* This really is bfd_target_unknown_flavour. */
+
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_osf_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+static struct core_fns alpha_elf_core_fns =
+{
+ bfd_target_elf_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_elf_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_alpha (void)
+{
+ add_core_fns (&alpha_osf_core_fns);
+ add_core_fns (&alpha_elf_core_fns);
+}
diff --git a/contrib/gdb/gdb/alpha-tdep.c b/contrib/gdb/gdb/alpha-tdep.c
new file mode 100644
index 0000000..1599eb2
--- /dev/null
+++ b/contrib/gdb/gdb/alpha-tdep.c
@@ -0,0 +1,1615 @@
+/* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "doublest.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "dwarf2-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"
+#include "linespec.h"
+#include "regcache.h"
+#include "reggroups.h"
+#include "arch-utils.h"
+#include "osabi.h"
+#include "block.h"
+
+#include "elf-bfd.h"
+
+#include "alpha-tdep.h"
+
+
+static const char *
+alpha_register_name (int regno)
+{
+ static const char * const register_names[] =
+ {
+ "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
+ "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
+ "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
+ "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "fpcr",
+ "pc", "", "unique"
+ };
+
+ if (regno < 0)
+ return NULL;
+ if (regno >= (sizeof(register_names) / sizeof(*register_names)))
+ return NULL;
+ return register_names[regno];
+}
+
+static int
+alpha_cannot_fetch_register (int regno)
+{
+ return regno == ALPHA_ZERO_REGNUM;
+}
+
+static int
+alpha_cannot_store_register (int regno)
+{
+ return regno == ALPHA_ZERO_REGNUM;
+}
+
+static struct type *
+alpha_register_type (struct gdbarch *gdbarch, int regno)
+{
+ if (regno == ALPHA_SP_REGNUM || regno == ALPHA_GP_REGNUM)
+ return builtin_type_void_data_ptr;
+ if (regno == ALPHA_PC_REGNUM)
+ return builtin_type_void_func_ptr;
+
+ /* Don't need to worry about little vs big endian until
+ some jerk tries to port to alpha-unicosmk. */
+ if (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31)
+ return builtin_type_ieee_double_little;
+
+ return builtin_type_int64;
+}
+
+/* Is REGNUM a member of REGGROUP? */
+
+static int
+alpha_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ /* Filter out any registers eliminated, but whose regnum is
+ reserved for backward compatibility, e.g. the vfp. */
+ if (REGISTER_NAME (regnum) == NULL || *REGISTER_NAME (regnum) == '\0')
+ return 0;
+
+ if (group == all_reggroup)
+ return 1;
+
+ /* Zero should not be saved or restored. Technically it is a general
+ register (just as $f31 would be a float if we represented it), but
+ there's no point displaying it during "info regs", so leave it out
+ of all groups except for "all". */
+ if (regnum == ALPHA_ZERO_REGNUM)
+ return 0;
+
+ /* All other registers are saved and restored. */
+ if (group == save_reggroup || group == restore_reggroup)
+ return 1;
+
+ /* All other groups are non-overlapping. */
+
+ /* Since this is really a PALcode memory slot... */
+ if (regnum == ALPHA_UNIQUE_REGNUM)
+ return group == system_reggroup;
+
+ /* Force the FPCR to be considered part of the floating point state. */
+ if (regnum == ALPHA_FPCR_REGNUM)
+ return group == float_reggroup;
+
+ if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 31)
+ return group == float_reggroup;
+ else
+ return group == general_reggroup;
+}
+
+static int
+alpha_register_byte (int regno)
+{
+ return (regno * 8);
+}
+
+static int
+alpha_register_raw_size (int regno)
+{
+ return 8;
+}
+
+static int
+alpha_register_virtual_size (int regno)
+{
+ return 8;
+}
+
+/* The following represents exactly the conversion performed by
+ the LDS instruction. This applies to both single-precision
+ floating point and 32-bit integers. */
+
+static void
+alpha_lds (void *out, const void *in)
+{
+ ULONGEST mem = extract_unsigned_integer (in, 4);
+ ULONGEST frac = (mem >> 0) & 0x7fffff;
+ ULONGEST sign = (mem >> 31) & 1;
+ ULONGEST exp_msb = (mem >> 30) & 1;
+ ULONGEST exp_low = (mem >> 23) & 0x7f;
+ ULONGEST exp, reg;
+
+ exp = (exp_msb << 10) | exp_low;
+ if (exp_msb)
+ {
+ if (exp_low == 0x7f)
+ exp = 0x7ff;
+ }
+ else
+ {
+ if (exp_low != 0x00)
+ exp |= 0x380;
+ }
+
+ reg = (sign << 63) | (exp << 52) | (frac << 29);
+ store_unsigned_integer (out, 8, reg);
+}
+
+/* Similarly, this represents exactly the conversion performed by
+ the STS instruction. */
+
+static void
+alpha_sts (void *out, const void *in)
+{
+ ULONGEST reg, mem;
+
+ reg = extract_unsigned_integer (in, 8);
+ mem = ((reg >> 32) & 0xc0000000) | ((reg >> 29) & 0x3fffffff);
+ store_unsigned_integer (out, 4, mem);
+}
+
+/* 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. */
+
+static int
+alpha_convert_register_p (int regno, struct type *type)
+{
+ return (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31);
+}
+
+static void
+alpha_register_to_value (struct frame_info *frame, int regnum,
+ struct type *valtype, void *out)
+{
+ char in[MAX_REGISTER_SIZE];
+ frame_register_read (frame, regnum, in);
+ switch (TYPE_LENGTH (valtype))
+ {
+ case 4:
+ alpha_sts (out, in);
+ break;
+ case 8:
+ memcpy (out, in, 8);
+ break;
+ default:
+ error ("Cannot retrieve value from floating point register");
+ }
+}
+
+static void
+alpha_value_to_register (struct frame_info *frame, int regnum,
+ struct type *valtype, const void *in)
+{
+ char out[MAX_REGISTER_SIZE];
+ switch (TYPE_LENGTH (valtype))
+ {
+ case 4:
+ alpha_lds (out, in);
+ break;
+ case 8:
+ memcpy (out, in, 8);
+ break;
+ default:
+ error ("Cannot store value in floating point register");
+ }
+ put_frame_register (frame, regnum, out);
+}
+
+
+/* The alpha passes the first six arguments in the registers, the rest on
+ the stack. The register arguments are stored in ARG_REG_BUFFER, and
+ then moved into the register file; this simplifies the passing of a
+ large struct which extends from the registers to the stack, plus avoids
+ three ptrace invocations per word.
+
+ We don't bother tracking which register values should go in integer
+ regs or fp regs; we load the same values into both.
+
+ If the called function is returning a structure, the address of the
+ structure to be returned is passed as a hidden first argument. */
+
+static CORE_ADDR
+alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int i;
+ int accumulate_size = struct_return ? 8 : 0;
+ struct alpha_arg
+ {
+ char *contents;
+ int len;
+ int offset;
+ };
+ struct alpha_arg *alpha_args
+ = (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
+ struct alpha_arg *m_arg;
+ char arg_reg_buffer[ALPHA_REGISTER_SIZE * ALPHA_NUM_ARG_REGS];
+ int required_arg_regs;
+
+ /* The ABI places the address of the called function in T12. */
+ regcache_cooked_write_signed (regcache, ALPHA_T12_REGNUM, func_addr);
+
+ /* Set the return address register to point to the entry point
+ of the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_signed (regcache, ALPHA_RA_REGNUM, bp_addr);
+
+ /* Lay out the arguments in memory. */
+ for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
+ {
+ struct value *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) == 4)
+ {
+ /* 32-bit values must be sign-extended to 64 bits
+ even if the base data type is unsigned. */
+ arg_type = builtin_type_int32;
+ arg = value_cast (arg_type, arg);
+ }
+ if (TYPE_LENGTH (arg_type) < ALPHA_REGISTER_SIZE)
+ {
+ arg_type = builtin_type_int64;
+ arg = value_cast (arg_type, arg);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ /* "float" arguments loaded in registers must be passed in
+ register format, aka "double". */
+ if (accumulate_size < sizeof (arg_reg_buffer)
+ && TYPE_LENGTH (arg_type) == 4)
+ {
+ arg_type = builtin_type_ieee_double_little;
+ arg = value_cast (arg_type, arg);
+ }
+ /* Tru64 5.1 has a 128-bit long double, and passes this by
+ invisible reference. No one else uses this data type. */
+ else if (TYPE_LENGTH (arg_type) == 16)
+ {
+ /* Allocate aligned storage. */
+ sp = (sp & -16) - 16;
+
+ /* Write the real data into the stack. */
+ write_memory (sp, VALUE_CONTENTS (arg), 16);
+
+ /* Construct the indirection. */
+ arg_type = lookup_pointer_type (arg_type);
+ arg = value_from_pointer (arg_type, sp);
+ }
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ /* ??? The ABI says that complex values are passed as two
+ separate scalar values. This distinction only matters
+ for complex float. However, GCC does not implement this. */
+
+ /* Tru64 5.1 has a 128-bit long double, and passes this by
+ invisible reference. */
+ if (TYPE_LENGTH (arg_type) == 32)
+ {
+ /* Allocate aligned storage. */
+ sp = (sp & -16) - 16;
+
+ /* Write the real data into the stack. */
+ write_memory (sp, VALUE_CONTENTS (arg), 32);
+
+ /* Construct the indirection. */
+ arg_type = lookup_pointer_type (arg_type);
+ arg = value_from_pointer (arg_type, sp);
+ }
+ 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 < sizeof(arg_reg_buffer))
+ accumulate_size = 0;
+ else
+ accumulate_size -= sizeof(arg_reg_buffer);
+ sp -= accumulate_size;
+
+ /* Keep sp aligned to a multiple of 16 as the ABI requires. */
+ sp &= ~15;
+
+ /* `Push' arguments on the stack. */
+ for (i = nargs; m_arg--, --i >= 0;)
+ {
+ char *contents = m_arg->contents;
+ int offset = m_arg->offset;
+ int len = m_arg->len;
+
+ /* Copy the bytes destined for registers into arg_reg_buffer. */
+ if (offset < sizeof(arg_reg_buffer))
+ {
+ if (offset + len <= sizeof(arg_reg_buffer))
+ {
+ memcpy (arg_reg_buffer + offset, contents, len);
+ continue;
+ }
+ else
+ {
+ int tlen = sizeof(arg_reg_buffer) - offset;
+ memcpy (arg_reg_buffer + offset, contents, tlen);
+ offset += tlen;
+ contents += tlen;
+ len -= tlen;
+ }
+ }
+
+ /* Everything else goes to the stack. */
+ write_memory (sp + offset - sizeof(arg_reg_buffer), contents, len);
+ }
+ if (struct_return)
+ store_unsigned_integer (arg_reg_buffer, ALPHA_REGISTER_SIZE, struct_addr);
+
+ /* Load the argument registers. */
+ for (i = 0; i < required_arg_regs; i++)
+ {
+ regcache_cooked_write (regcache, ALPHA_A0_REGNUM + i,
+ arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
+ regcache_cooked_write (regcache, ALPHA_FPA0_REGNUM + i,
+ arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
+ }
+
+ /* Finally, update the stack pointer. */
+ regcache_cooked_write_signed (regcache, ALPHA_SP_REGNUM, sp);
+
+ return sp;
+}
+
+/* Extract from REGCACHE the value about to be returned from a function
+ and copy it into VALBUF. */
+
+static void
+alpha_extract_return_value (struct type *valtype, struct regcache *regcache,
+ void *valbuf)
+{
+ int length = TYPE_LENGTH (valtype);
+ char raw_buffer[ALPHA_REGISTER_SIZE];
+ ULONGEST l;
+
+ switch (TYPE_CODE (valtype))
+ {
+ case TYPE_CODE_FLT:
+ switch (length)
+ {
+ case 4:
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, raw_buffer);
+ alpha_sts (valbuf, raw_buffer);
+ break;
+
+ case 8:
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
+ read_memory (l, valbuf, 16);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "unknown floating point width");
+ }
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ switch (length)
+ {
+ case 8:
+ /* ??? This isn't correct wrt the ABI, but it's what GCC does. */
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM+1,
+ (char *)valbuf + 8);
+ break;
+
+ case 32:
+ regcache_cooked_read_signed (regcache, ALPHA_V0_REGNUM, &l);
+ read_memory (l, valbuf, 32);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "unknown floating point width");
+ }
+ break;
+
+ default:
+ /* Assume everything else degenerates to an integer. */
+ regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
+ store_unsigned_integer (valbuf, length, l);
+ break;
+ }
+}
+
+/* Extract from REGCACHE the address of a structure about to be returned
+ from a function. */
+
+static CORE_ADDR
+alpha_extract_struct_value_address (struct regcache *regcache)
+{
+ ULONGEST addr;
+ regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &addr);
+ return addr;
+}
+
+/* Insert the given value into REGCACHE as if it was being
+ returned by a function. */
+
+static void
+alpha_store_return_value (struct type *valtype, struct regcache *regcache,
+ const void *valbuf)
+{
+ int length = TYPE_LENGTH (valtype);
+ char raw_buffer[ALPHA_REGISTER_SIZE];
+ ULONGEST l;
+
+ switch (TYPE_CODE (valtype))
+ {
+ case TYPE_CODE_FLT:
+ switch (length)
+ {
+ case 4:
+ alpha_lds (raw_buffer, valbuf);
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, raw_buffer);
+ break;
+
+ case 8:
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ /* FIXME: 128-bit long doubles are returned like structures:
+ by writing into indirect storage provided by the caller
+ as the first argument. */
+ error ("Cannot set a 128-bit long double return value.");
+
+ default:
+ internal_error (__FILE__, __LINE__, "unknown floating point width");
+ }
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ switch (length)
+ {
+ case 8:
+ /* ??? This isn't correct wrt the ABI, but it's what GCC does. */
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM+1,
+ (const char *)valbuf + 8);
+ break;
+
+ case 32:
+ /* FIXME: 128-bit long doubles are returned like structures:
+ by writing into indirect storage provided by the caller
+ as the first argument. */
+ error ("Cannot set a 128-bit long double return value.");
+
+ default:
+ internal_error (__FILE__, __LINE__, "unknown floating point width");
+ }
+ break;
+
+ default:
+ /* Assume everything else degenerates to an integer. */
+ /* 32-bit values must be sign-extended to 64 bits
+ even if the base data type is unsigned. */
+ if (length == 4)
+ valtype = builtin_type_int32;
+ l = unpack_long (valtype, valbuf);
+ regcache_cooked_write_unsigned (regcache, ALPHA_V0_REGNUM, l);
+ break;
+ }
+}
+
+
+static const unsigned char *
+alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ static const unsigned char alpha_breakpoint[] =
+ { 0x80, 0, 0, 0 }; /* call_pal bpt */
+
+ *lenptr = sizeof(alpha_breakpoint);
+ return (alpha_breakpoint);
+}
+
+
+/* This returns the PC of the first insn after the prologue.
+ If we can't find the prologue, then return 0. */
+
+CORE_ADDR
+alpha_after_prologue (CORE_ADDR pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_addr, func_end;
+
+ if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ return 0;
+
+ 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;
+}
+
+/* Read an instruction from memory at PC, looking through breakpoints. */
+
+unsigned int
+alpha_read_insn (CORE_ADDR pc)
+{
+ char buf[4];
+ int status;
+
+ status = read_memory_nobpt (pc, buf, 4);
+ if (status)
+ memory_error (status, pc);
+ return extract_unsigned_integer (buf, 4);
+}
+
+/* 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. */
+
+static CORE_ADDR
+alpha_skip_prologue (CORE_ADDR pc)
+{
+ unsigned long inst;
+ int offset;
+ CORE_ADDR post_prologue_pc;
+ char buf[4];
+
+ /* 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 (which all
+ Alpha targets do). */
+ if (target_read_memory (pc, buf, 4))
+ return pc;
+
+ /* 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 = alpha_after_prologue (pc);
+ 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)
+ {
+ inst = alpha_read_insn (pc + offset);
+
+ 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;
+ if ((inst & 0xffe01fff) == 0x43c0153e) /* subq $sp,n,$sp */
+ continue;
+
+ if (((inst & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */
+ || (inst & 0xfc1f0000) == 0x9c1e0000) /* stt reg,n($sp) */
+ && (inst & 0x03e00000) != 0x03e00000) /* reg != $zero */
+ continue;
+
+ if (inst == 0x47de040f) /* bis sp,sp,fp */
+ continue;
+ if (inst == 0x47fe040f) /* bis zero,sp,fp */
+ continue;
+
+ break;
+ }
+ return pc + offset;
+}
+
+
+/* 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 the "pc". This routine returns true on success. */
+
+static int
+alpha_get_longjmp_target (CORE_ADDR *pc)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ CORE_ADDR jb_addr;
+ char raw_buffer[ALPHA_REGISTER_SIZE];
+
+ jb_addr = read_register (ALPHA_A0_REGNUM);
+
+ if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size),
+ raw_buffer, tdep->jb_elt_size))
+ return 0;
+
+ *pc = extract_unsigned_integer (raw_buffer, tdep->jb_elt_size);
+ return 1;
+}
+
+
+/* Frame unwinder for signal trampolines. We use alpha tdep bits that
+ describe the location and shape of the sigcontext structure. After
+ that, all registers are in memory, so it's easy. */
+/* ??? Shouldn't we be able to do this generically, rather than with
+ OSABI data specific to Alpha? */
+
+struct alpha_sigtramp_unwind_cache
+{
+ CORE_ADDR sigcontext_addr;
+};
+
+static struct alpha_sigtramp_unwind_cache *
+alpha_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct alpha_sigtramp_unwind_cache *info;
+ struct gdbarch_tdep *tdep;
+
+ if (*this_prologue_cache)
+ return *this_prologue_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct alpha_sigtramp_unwind_cache);
+ *this_prologue_cache = info;
+
+ tdep = gdbarch_tdep (current_gdbarch);
+ info->sigcontext_addr = tdep->sigcontext_addr (next_frame);
+
+ return info;
+}
+
+/* Return the address of REGNUM in a sigtramp frame. Since this is
+ all arithmetic, it doesn't seem worthwhile to cache it. */
+
+static CORE_ADDR
+alpha_sigtramp_register_address (CORE_ADDR sigcontext_addr, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (regnum >= 0 && regnum < 32)
+ return sigcontext_addr + tdep->sc_regs_offset + regnum * 8;
+ else if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 32)
+ return sigcontext_addr + tdep->sc_fpregs_offset + regnum * 8;
+ else if (regnum == ALPHA_PC_REGNUM)
+ return sigcontext_addr + tdep->sc_pc_offset;
+
+ return 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. */
+
+static void
+alpha_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct alpha_sigtramp_unwind_cache *info
+ = alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+ struct gdbarch_tdep *tdep;
+ CORE_ADDR stack_addr, code_addr;
+
+ /* If the OSABI couldn't locate the sigcontext, give up. */
+ if (info->sigcontext_addr == 0)
+ return;
+
+ /* If we have dynamic signal trampolines, find their start.
+ If we do not, then we must assume there is a symbol record
+ that can provide the start address. */
+ tdep = gdbarch_tdep (current_gdbarch);
+ if (tdep->dynamic_sigtramp_offset)
+ {
+ int offset;
+ code_addr = frame_pc_unwind (next_frame);
+ offset = tdep->dynamic_sigtramp_offset (code_addr);
+ if (offset >= 0)
+ code_addr -= offset;
+ else
+ code_addr = 0;
+ }
+ else
+ code_addr = frame_func_unwind (next_frame);
+
+ /* The stack address is trivially read from the sigcontext. */
+ stack_addr = alpha_sigtramp_register_address (info->sigcontext_addr,
+ ALPHA_SP_REGNUM);
+ stack_addr = get_frame_memory_unsigned (next_frame, stack_addr,
+ ALPHA_REGISTER_SIZE);
+
+ *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Retrieve the value of REGNUM in FRAME. Don't give up! */
+
+static void
+alpha_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct alpha_sigtramp_unwind_cache *info
+ = alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+ CORE_ADDR addr;
+
+ if (info->sigcontext_addr != 0)
+ {
+ /* All integer and fp registers are stored in memory. */
+ addr = alpha_sigtramp_register_address (info->sigcontext_addr, regnum);
+ if (addr != 0)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = addr;
+ *realnump = -1;
+ if (bufferp != NULL)
+ get_frame_memory (next_frame, addr, bufferp, ALPHA_REGISTER_SIZE);
+ return;
+ }
+ }
+
+ /* This extra register may actually be in the sigcontext, but our
+ current description of it in alpha_sigtramp_frame_unwind_cache
+ doesn't include it. Too bad. Fall back on whatever's in the
+ outer frame. */
+ frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+}
+
+static const struct frame_unwind alpha_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ alpha_sigtramp_frame_this_id,
+ alpha_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+alpha_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ /* We shouldn't even bother to try if the OSABI didn't register
+ a sigcontext_addr handler. */
+ if (!gdbarch_tdep (current_gdbarch)->sigcontext_addr)
+ return NULL;
+
+ /* Otherwise we should be in a signal frame. */
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (PC_IN_SIGTRAMP (pc, name))
+ return &alpha_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+/* Fallback alpha frame unwinder. Uses instruction scanning and knows
+ something about the traditional layout of alpha stack frames. */
+
+struct alpha_heuristic_unwind_cache
+{
+ CORE_ADDR *saved_regs;
+ CORE_ADDR vfp;
+ CORE_ADDR start_pc;
+ int return_reg;
+};
+
+/* 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;
+
+/* Attempt to locate the start of the function containing PC. We assume that
+ the previous function ends with an about_to_return insn. Not foolproof by
+ any means, since gcc is happy to put the epilogue in the middle of a
+ function. But we're guessing anyway... */
+
+static CORE_ADDR
+alpha_heuristic_proc_start (CORE_ADDR pc)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ CORE_ADDR last_non_nop = pc;
+ CORE_ADDR fence = pc - heuristic_fence_post;
+ CORE_ADDR orig_pc = pc;
+ CORE_ADDR func;
+
+ if (pc == 0)
+ return 0;
+
+ /* First see if we can find the start of the function from minimal
+ symbol information. This can succeed with a binary that doesn't
+ have debug info, but hasn't been stripped. */
+ func = get_pc_function_start (pc);
+ if (func)
+ return func;
+
+ if (heuristic_fence_post == UINT_MAX
+ || fence < tdep->vm_min_address)
+ fence = tdep->vm_min_address;
+
+ /* Search back for previous return; also stop at a 0, which might be
+ seen for instance before the start of a code section. Don't include
+ nops, since this usually indicates padding between functions. */
+ for (pc -= 4; pc >= fence; pc -= 4)
+ {
+ unsigned int insn = alpha_read_insn (pc);
+ switch (insn)
+ {
+ case 0: /* invalid insn */
+ case 0x6bfa8001: /* ret $31,($26),1 */
+ return last_non_nop;
+
+ case 0x2ffe0000: /* unop: ldq_u $31,0($30) */
+ case 0x47ff041f: /* nop: bis $31,$31,$31 */
+ break;
+
+ default:
+ last_non_nop = pc;
+ break;
+ }
+ }
+
+ /* It's not clear to me why we reach this point when stopping 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 == NO_STOP_QUIETLY)
+ {
+ static int blurb_printed = 0;
+
+ if (fence == tdep->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%s", paddr_nz (orig_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;
+}
+
+static struct alpha_heuristic_unwind_cache *
+alpha_heuristic_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ CORE_ADDR start_pc)
+{
+ struct alpha_heuristic_unwind_cache *info;
+ ULONGEST val;
+ CORE_ADDR limit_pc, cur_pc;
+ int frame_reg, frame_size, return_reg, reg;
+
+ if (*this_prologue_cache)
+ return *this_prologue_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct alpha_heuristic_unwind_cache);
+ *this_prologue_cache = info;
+ info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
+
+ limit_pc = frame_pc_unwind (next_frame);
+ if (start_pc == 0)
+ start_pc = alpha_heuristic_proc_start (limit_pc);
+ info->start_pc = start_pc;
+
+ frame_reg = ALPHA_SP_REGNUM;
+ frame_size = 0;
+ return_reg = -1;
+
+ /* If we've identified a likely place to start, do code scanning. */
+ if (start_pc != 0)
+ {
+ /* Limit the forward search to 50 instructions. */
+ if (start_pc + 200 < limit_pc)
+ limit_pc = start_pc + 200;
+
+ for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
+ {
+ unsigned int word = alpha_read_insn (cur_pc);
+
+ if ((word & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */
+ {
+ if (word & 0x8000)
+ {
+ /* Consider only the first stack allocation instruction
+ to contain the static size of the frame. */
+ if (frame_size == 0)
+ frame_size = (-word) & 0xffff;
+ }
+ else
+ {
+ /* Exit loop if a positive stack adjustment is found, which
+ usually means that the stack cleanup code in the function
+ epilogue is reached. */
+ break;
+ }
+ }
+ else if ((word & 0xfc1f0000) == 0xb41e0000) /* stq reg,n($sp) */
+ {
+ reg = (word & 0x03e00000) >> 21;
+
+ /* Ignore this instruction if we have already encountered
+ an instruction saving the same register earlier in the
+ function code. The current instruction does not tell
+ us where the original value upon function entry is saved.
+ All it says is that the function we are scanning reused
+ that register for some computation of its own, and is now
+ saving its result. */
+ if (info->saved_regs[reg])
+ continue;
+
+ if (reg == 31)
+ continue;
+
+ /* Do not compute the address where the register was saved yet,
+ because we don't know yet if the offset will need to be
+ relative to $sp or $fp (we can not compute the address
+ relative to $sp if $sp is updated during the execution of
+ the current subroutine, for instance when doing some alloca).
+ So just store the offset for the moment, and compute the
+ address later when we know whether this frame has a frame
+ pointer or not. */
+ /* Hack: temporarily add one, so that the offset is non-zero
+ and we can tell which registers have save offsets below. */
+ info->saved_regs[reg] = (word & 0xffff) + 1;
+
+ /* 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.
+ If we encounter a return instruction, we extract the
+ the return address register from it.
+
+ FIXME: Rewriting GDB to access the procedure descriptors,
+ e.g. via the minimal symbol table, might obviate this hack. */
+ if (return_reg == -1
+ && cur_pc < (start_pc + 80)
+ && (reg == ALPHA_T7_REGNUM
+ || reg == ALPHA_T9_REGNUM
+ || reg == ALPHA_RA_REGNUM))
+ return_reg = reg;
+ }
+ else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */
+ return_reg = (word >> 16) & 0x1f;
+ else if (word == 0x47de040f) /* bis sp,sp,fp */
+ frame_reg = ALPHA_GCC_FP_REGNUM;
+ else if (word == 0x47fe040f) /* bis zero,sp,fp */
+ frame_reg = ALPHA_GCC_FP_REGNUM;
+ }
+
+ /* If we haven't found a valid return address register yet, keep
+ searching in the procedure prologue. */
+ if (return_reg == -1)
+ {
+ while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80))
+ {
+ unsigned int word = alpha_read_insn (cur_pc);
+
+ if ((word & 0xfc1f0000) == 0xb41e0000) /* stq reg,n($sp) */
+ {
+ reg = (word & 0x03e00000) >> 21;
+ if (reg == ALPHA_T7_REGNUM
+ || reg == ALPHA_T9_REGNUM
+ || reg == ALPHA_RA_REGNUM)
+ {
+ return_reg = reg;
+ break;
+ }
+ }
+ else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */
+ {
+ return_reg = (word >> 16) & 0x1f;
+ break;
+ }
+
+ cur_pc += 4;
+ }
+ }
+ }
+
+ /* Failing that, do default to the customary RA. */
+ if (return_reg == -1)
+ return_reg = ALPHA_RA_REGNUM;
+ info->return_reg = return_reg;
+
+ frame_unwind_unsigned_register (next_frame, frame_reg, &val);
+ info->vfp = val + frame_size;
+
+ /* Convert offsets to absolute addresses. See above about adding
+ one to the offsets to make all detected offsets non-zero. */
+ for (reg = 0; reg < ALPHA_NUM_REGS; ++reg)
+ if (info->saved_regs[reg])
+ info->saved_regs[reg] += val - 1;
+
+ return info;
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+ frame. This will be used to create a new GDB frame struct. */
+
+static void
+alpha_heuristic_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct alpha_heuristic_unwind_cache *info
+ = alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
+
+ *this_id = frame_id_build (info->vfp, info->start_pc);
+}
+
+/* Retrieve the value of REGNUM in FRAME. Don't give up! */
+
+static void
+alpha_heuristic_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct alpha_heuristic_unwind_cache *info
+ = alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
+
+ /* The PC of the previous frame is stored in the link register of
+ the current frame. Frob regnum so that we pull the value from
+ the correct place. */
+ if (regnum == ALPHA_PC_REGNUM)
+ regnum = info->return_reg;
+
+ /* For all registers known to be saved in the current frame,
+ do the obvious and pull the value out. */
+ if (info->saved_regs[regnum])
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = info->saved_regs[regnum];
+ *realnump = -1;
+ if (bufferp != NULL)
+ get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE);
+ return;
+ }
+
+ /* The stack pointer of the previous frame is computed by popping
+ the current stack frame. */
+ if (regnum == ALPHA_SP_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (bufferp != NULL)
+ store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
+ return;
+ }
+
+ /* Otherwise assume the next frame has the same register value. */
+ frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+}
+
+static const struct frame_unwind alpha_heuristic_frame_unwind = {
+ NORMAL_FRAME,
+ alpha_heuristic_frame_this_id,
+ alpha_heuristic_frame_prev_register
+};
+
+static const struct frame_unwind *
+alpha_heuristic_frame_sniffer (struct frame_info *next_frame)
+{
+ return &alpha_heuristic_frame_unwind;
+}
+
+static CORE_ADDR
+alpha_heuristic_frame_base_address (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct alpha_heuristic_unwind_cache *info
+ = alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
+
+ return info->vfp;
+}
+
+static const struct frame_base alpha_heuristic_frame_base = {
+ &alpha_heuristic_frame_unwind,
+ alpha_heuristic_frame_base_address,
+ alpha_heuristic_frame_base_address,
+ alpha_heuristic_frame_base_address
+};
+
+/* Just like reinit_frame_cache, but with the right arguments to be
+ callable as an sfunc. Used by the "set heuristic-fence-post" command. */
+
+static void
+reinit_frame_cache_sfunc (char *args, int from_tty, struct cmd_list_element *c)
+{
+ reinit_frame_cache ();
+}
+
+
+/* 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 *
+alpha_setup_arbitrary_frame (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]);
+}
+
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+ dummy frame. The frame ID's base needs to match the TOS value
+ saved by save_dummy_frame_tos(), and the PC match the dummy frame's
+ breakpoint. */
+
+static struct frame_id
+alpha_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ ULONGEST base;
+ frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &base);
+ return frame_id_build (base, frame_pc_unwind (next_frame));
+}
+
+static CORE_ADDR
+alpha_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ ULONGEST pc;
+ frame_unwind_unsigned_register (next_frame, ALPHA_PC_REGNUM, &pc);
+ return pc;
+}
+
+
+/* Helper routines for alpha*-nat.c files to move register sets to and
+ from core files. The UNIQUE pointer is allowed to be NULL, as most
+ targets don't supply this value in their core files. */
+
+void
+alpha_supply_int_regs (int regno, const void *r0_r30,
+ const void *pc, const void *unique)
+{
+ int i;
+
+ for (i = 0; i < 31; ++i)
+ if (regno == i || regno == -1)
+ supply_register (i, (const char *)r0_r30 + i*8);
+
+ if (regno == ALPHA_ZERO_REGNUM || regno == -1)
+ supply_register (ALPHA_ZERO_REGNUM, NULL);
+
+ if (regno == ALPHA_PC_REGNUM || regno == -1)
+ supply_register (ALPHA_PC_REGNUM, pc);
+
+ if (regno == ALPHA_UNIQUE_REGNUM || regno == -1)
+ supply_register (ALPHA_UNIQUE_REGNUM, unique);
+}
+
+void
+alpha_fill_int_regs (int regno, void *r0_r30, void *pc, void *unique)
+{
+ int i;
+
+ for (i = 0; i < 31; ++i)
+ if (regno == i || regno == -1)
+ regcache_collect (i, (char *)r0_r30 + i*8);
+
+ if (regno == ALPHA_PC_REGNUM || regno == -1)
+ regcache_collect (ALPHA_PC_REGNUM, pc);
+
+ if (unique && (regno == ALPHA_UNIQUE_REGNUM || regno == -1))
+ regcache_collect (ALPHA_UNIQUE_REGNUM, unique);
+}
+
+void
+alpha_supply_fp_regs (int regno, const void *f0_f30, const void *fpcr)
+{
+ int i;
+
+ for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
+ if (regno == i || regno == -1)
+ supply_register (i, (const char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
+
+ if (regno == ALPHA_FPCR_REGNUM || regno == -1)
+ supply_register (ALPHA_FPCR_REGNUM, fpcr);
+}
+
+void
+alpha_fill_fp_regs (int regno, void *f0_f30, void *fpcr)
+{
+ int i;
+
+ for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
+ if (regno == i || regno == -1)
+ regcache_collect (i, (char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
+
+ if (regno == ALPHA_FPCR_REGNUM || regno == -1)
+ regcache_collect (ALPHA_FPCR_REGNUM, fpcr);
+}
+
+
+/* alpha_software_single_step() is called just before we want to resume
+ the inferior, if we want to single-step it but there is no hardware
+ or kernel single-step support (NetBSD on Alpha, for example). We find
+ the target of the coming instruction and breakpoint it.
+
+ single_step is also called just after the inferior stops. If we had
+ set up a simulated single-step, we undo our damage. */
+
+static CORE_ADDR
+alpha_next_pc (CORE_ADDR pc)
+{
+ unsigned int insn;
+ unsigned int op;
+ int offset;
+ LONGEST rav;
+
+ insn = alpha_read_insn (pc);
+
+ /* Opcode is top 6 bits. */
+ op = (insn >> 26) & 0x3f;
+
+ if (op == 0x1a)
+ {
+ /* Jump format: target PC is:
+ RB & ~3 */
+ return (read_register ((insn >> 16) & 0x1f) & ~3);
+ }
+
+ if ((op & 0x30) == 0x30)
+ {
+ /* Branch format: target PC is:
+ (new PC) + (4 * sext(displacement)) */
+ if (op == 0x30 || /* BR */
+ op == 0x34) /* BSR */
+ {
+ branch_taken:
+ offset = (insn & 0x001fffff);
+ if (offset & 0x00100000)
+ offset |= 0xffe00000;
+ offset *= 4;
+ return (pc + 4 + offset);
+ }
+
+ /* Need to determine if branch is taken; read RA. */
+ rav = (LONGEST) read_register ((insn >> 21) & 0x1f);
+ switch (op)
+ {
+ case 0x38: /* BLBC */
+ if ((rav & 1) == 0)
+ goto branch_taken;
+ break;
+ case 0x3c: /* BLBS */
+ if (rav & 1)
+ goto branch_taken;
+ break;
+ case 0x39: /* BEQ */
+ if (rav == 0)
+ goto branch_taken;
+ break;
+ case 0x3d: /* BNE */
+ if (rav != 0)
+ goto branch_taken;
+ break;
+ case 0x3a: /* BLT */
+ if (rav < 0)
+ goto branch_taken;
+ break;
+ case 0x3b: /* BLE */
+ if (rav <= 0)
+ goto branch_taken;
+ break;
+ case 0x3f: /* BGT */
+ if (rav > 0)
+ goto branch_taken;
+ break;
+ case 0x3e: /* BGE */
+ if (rav >= 0)
+ goto branch_taken;
+ break;
+
+ /* ??? Missing floating-point branches. */
+ }
+ }
+
+ /* Not a branch or branch not taken; target PC is:
+ pc + 4 */
+ return (pc + 4);
+}
+
+void
+alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+{
+ static CORE_ADDR next_pc;
+ typedef char binsn_quantum[BREAKPOINT_MAX];
+ static binsn_quantum break_mem;
+ CORE_ADDR pc;
+
+ if (insert_breakpoints_p)
+ {
+ pc = read_pc ();
+ next_pc = alpha_next_pc (pc);
+
+ target_insert_breakpoint (next_pc, break_mem);
+ }
+ else
+ {
+ target_remove_breakpoint (next_pc, break_mem);
+ write_pc (next_pc);
+ }
+}
+
+
+/* Initialize the current architecture based on INFO. If possible, re-use an
+ architecture from ARCHES, which is a list of architectures already created
+ during this debugging session.
+
+ Called e.g. at program startup, when reading a core file, and when reading
+ a binary file. */
+
+static struct gdbarch *
+alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+
+ /* Try to determine the ABI of the object we are loading. */
+ if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* If it's an ECOFF file, assume it's OSF/1. */
+ if (bfd_get_flavour (info.abfd) == bfd_target_ecoff_flavour)
+ info.osabi = GDB_OSABI_OSF1;
+ }
+
+ /* Find a candidate among extant architectures. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* Lowest text address. This is used by heuristic_proc_start()
+ to decide when to stop looking. */
+ tdep->vm_min_address = (CORE_ADDR) 0x120000000;
+
+ tdep->dynamic_sigtramp_offset = NULL;
+ tdep->sigcontext_addr = NULL;
+ tdep->sc_pc_offset = 2 * 8;
+ tdep->sc_regs_offset = 4 * 8;
+ tdep->sc_fpregs_offset = tdep->sc_regs_offset + 32 * 8 + 8;
+
+ tdep->jb_pc = -1; /* longjmp support not enabled by default */
+
+ /* Type sizes */
+ set_gdbarch_short_bit (gdbarch, 16);
+ set_gdbarch_int_bit (gdbarch, 32);
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_float_bit (gdbarch, 32);
+ set_gdbarch_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+
+ /* Register info */
+ set_gdbarch_num_regs (gdbarch, ALPHA_NUM_REGS);
+ set_gdbarch_sp_regnum (gdbarch, ALPHA_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, ALPHA_PC_REGNUM);
+ set_gdbarch_fp0_regnum (gdbarch, ALPHA_FP0_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, alpha_register_name);
+ set_gdbarch_deprecated_register_byte (gdbarch, alpha_register_byte);
+ set_gdbarch_deprecated_register_raw_size (gdbarch, alpha_register_raw_size);
+ set_gdbarch_deprecated_register_virtual_size (gdbarch, alpha_register_virtual_size);
+ set_gdbarch_register_type (gdbarch, alpha_register_type);
+
+ set_gdbarch_cannot_fetch_register (gdbarch, alpha_cannot_fetch_register);
+ set_gdbarch_cannot_store_register (gdbarch, alpha_cannot_store_register);
+
+ set_gdbarch_convert_register_p (gdbarch, alpha_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, alpha_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, alpha_value_to_register);
+
+ set_gdbarch_register_reggroup_p (gdbarch, alpha_register_reggroup_p);
+
+ /* Prologue heuristics. */
+ set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue);
+
+ /* Disassembler. */
+ set_gdbarch_print_insn (gdbarch, print_insn_alpha);
+
+ /* Call info. */
+
+ set_gdbarch_use_struct_convention (gdbarch, always_use_struct_convention);
+ set_gdbarch_extract_return_value (gdbarch, alpha_extract_return_value);
+ set_gdbarch_store_return_value (gdbarch, alpha_store_return_value);
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch, alpha_extract_struct_value_address);
+
+ /* Settings for calling functions in the inferior. */
+ set_gdbarch_push_dummy_call (gdbarch, alpha_push_dummy_call);
+
+ /* Methods for saving / extracting a dummy frame's ID. */
+ set_gdbarch_unwind_dummy_id (gdbarch, alpha_unwind_dummy_id);
+
+ /* Return the unwound PC value. */
+ set_gdbarch_unwind_pc (gdbarch, alpha_unwind_pc);
+
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, alpha_breakpoint_from_pc);
+ set_gdbarch_decr_pc_after_break (gdbarch, 4);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ /* Now that we have tuned the configuration, set a few final things
+ based on what the OS ABI has told us. */
+
+ if (tdep->jb_pc >= 0)
+ set_gdbarch_get_longjmp_target (gdbarch, alpha_get_longjmp_target);
+
+ frame_unwind_append_sniffer (gdbarch, alpha_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, alpha_heuristic_frame_sniffer);
+
+ frame_base_set_default (gdbarch, &alpha_heuristic_frame_base);
+
+ return gdbarch;
+}
+
+void
+alpha_dwarf2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+ frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+}
+
+extern initialize_file_ftype _initialize_alpha_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_alpha_tdep (void)
+{
+ struct cmd_list_element *c;
+
+ gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, NULL);
+
+ /* 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. */
+ set_cmd_sfunc (c, reinit_frame_cache_sfunc);
+ add_show_from_set (c, &showlist);
+}
diff --git a/contrib/gdb/gdb/alpha-tdep.h b/contrib/gdb/gdb/alpha-tdep.h
new file mode 100644
index 0000000..828a3c6
--- /dev/null
+++ b/contrib/gdb/gdb/alpha-tdep.h
@@ -0,0 +1,110 @@
+/* Common target dependent code for GDB on Alpha systems.
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002, 2003 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 ALPHA_TDEP_H
+#define ALPHA_TDEP_H
+
+/* Say how long (ordinary) registers are. This is a piece of bogosity
+ used in push_word and a few other places;
+ DEPRECATED_REGISTER_RAW_SIZE is the real way to know how big a
+ register is. */
+#define ALPHA_REGISTER_SIZE 8
+
+/* Number of machine registers. */
+#define ALPHA_NUM_REGS 67
+
+/* Total amount of space needed to store our copies of the machine's
+ register state. */
+#define ALPHA_REGISTER_BYTES (ALPHA_NUM_REGS * 8)
+
+/* Register numbers of various important registers. Note that most of
+ these values are "real" register numbers, and correspond to the
+ general registers of the machine. */
+
+#define ALPHA_V0_REGNUM 0 /* Function integer return value */
+#define ALPHA_T7_REGNUM 8 /* Return address register for OSF/1 __add* */
+#define ALPHA_GCC_FP_REGNUM 15 /* Used by gcc as frame register */
+#define ALPHA_A0_REGNUM 16 /* Loc of first arg during a subr call */
+#define ALPHA_T9_REGNUM 23 /* Return address register for OSF/1 __div* */
+#define ALPHA_RA_REGNUM 26 /* Contains return address value */
+#define ALPHA_T12_REGNUM 27 /* Contains start addr of current proc */
+#define ALPHA_GP_REGNUM 29 /* Contains the global pointer */
+#define ALPHA_SP_REGNUM 30 /* Contains address of top of stack */
+#define ALPHA_ZERO_REGNUM 31 /* Read-only register, always 0 */
+#define ALPHA_FP0_REGNUM 32 /* Floating point register 0 */
+#define ALPHA_FPA0_REGNUM 48 /* First float arg during a subr call */
+#define ALPHA_FPCR_REGNUM 63 /* Floating point control register */
+#define ALPHA_PC_REGNUM 64 /* Contains program counter */
+#define ALPHA_UNIQUE_REGNUM 66 /* PAL_rduniq value */
+
+/* The alpha has two different virtual pointers for arguments and locals.
+
+ The virtual argument pointer is pointing to the bottom of the argument
+ transfer area, which is located immediately below the virtual frame
+ pointer. Its size is fixed for the native compiler, it is either zero
+ (for the no arguments case) or large enough to hold all argument registers.
+ gcc uses a variable sized argument transfer area. As it has
+ to stay compatible with the native debugging tools it has to use the same
+ virtual argument pointer and adjust the argument offsets accordingly.
+
+ The virtual local pointer is localoff bytes below the virtual frame
+ pointer, the value of localoff is obtained from the PDR. */
+#define ALPHA_NUM_ARG_REGS 6
+
+/* Target-dependent structure in gdbarch. */
+struct gdbarch_tdep
+{
+ CORE_ADDR vm_min_address; /* Used by alpha_heuristic_proc_start. */
+
+ /* If PC is inside a dynamically-generated signal trampoline function
+ (i.e. one copied onto the user stack at run-time), return how many
+ bytes PC is beyond the start of that function. Otherwise, return -1. */
+ LONGEST (*dynamic_sigtramp_offset) (CORE_ADDR);
+
+ /* Translate a signal handler stack base address into the address of
+ the sigcontext structure for that signal handler. */
+ CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+ /* Offset of registers in `struct sigcontext'. */
+ int sc_pc_offset;
+ int sc_regs_offset;
+ int sc_fpregs_offset;
+
+ int jb_pc; /* Offset to PC value in jump buffer.
+ If htis is negative, longjmp support
+ will be disabled. */
+ size_t jb_elt_size; /* And the size of each entry in the buf. */
+};
+
+extern unsigned int alpha_read_insn (CORE_ADDR pc);
+extern void alpha_software_single_step (enum target_signal, int);
+extern CORE_ADDR alpha_after_prologue (CORE_ADDR pc);
+
+extern void alpha_mdebug_init_abi (struct gdbarch_info, struct gdbarch *);
+extern void alpha_dwarf2_init_abi (struct gdbarch_info, struct gdbarch *);
+
+extern void alpha_supply_int_regs (int, const void *, const void *,
+ const void *);
+extern void alpha_fill_int_regs (int, void *, void *, void *);
+extern void alpha_supply_fp_regs (int, const void *, const void *);
+extern void alpha_fill_fp_regs (int, void *, void *);
+
+#endif /* ALPHA_TDEP_H */
diff --git a/contrib/gdb/gdb/alphabsd-nat.c b/contrib/gdb/gdb/alphabsd-nat.c
new file mode 100644
index 0000000..0781698
--- /dev/null
+++ b/contrib/gdb/gdb/alphabsd-nat.c
@@ -0,0 +1,151 @@
+/* Native-dependent code for Alpha BSD's.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include "alpha-tdep.h"
+#include "alphabsd-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#ifdef HAVE_SYS_PROCFS_H
+#include <sys/procfs.h>
+#endif
+
+#ifndef HAVE_GREGSET_T
+typedef struct reg gregset_t;
+#endif
+
+#ifndef HAVE_FPREGSET_T
+typedef struct fpreg fpregset_t;
+#endif
+
+#include "gregset.h"
+
+/* Provide *regset() wrappers around the generic Alpha BSD register
+ supply/fill routines. */
+
+void
+supply_gregset (gregset_t *gregsetp)
+{
+ alphabsd_supply_reg ((char *) gregsetp, -1);
+}
+
+void
+fill_gregset (gregset_t *gregsetp, int regno)
+{
+ alphabsd_fill_reg ((char *) gregsetp, regno);
+}
+
+void
+supply_fpregset (fpregset_t *fpregsetp)
+{
+ alphabsd_supply_fpreg ((char *) fpregsetp, -1);
+}
+
+void
+fill_fpregset (fpregset_t *fpregsetp, int regno)
+{
+ alphabsd_fill_fpreg ((char *) fpregsetp, regno);
+}
+
+/* Determine if PT_GETREGS fetches this register. */
+
+static int
+getregs_supplies (int regno)
+{
+ return ((regno >= ALPHA_V0_REGNUM && regno <= ALPHA_ZERO_REGNUM)
+ || regno >= PC_REGNUM);
+}
+
+
+/* Fetch register REGNO from the inferior. If REGNO is -1, do this
+ for all registers (including the floating point registers). */
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg gregs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &gregs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ alphabsd_supply_reg ((char *) &gregs, regno);
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ alphabsd_supply_fpreg ((char *) &fpregs, regno);
+ }
+}
+
+/* Store register REGNO back into the inferior. If REGNO is -1, do
+ this for all registers (including the floating point registers). */
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg gregs;
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &gregs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ alphabsd_fill_reg ((char *) &gregs, regno);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &gregs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ alphabsd_fill_fpreg ((char *) &fpregs, regno);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't write floating point status");
+ }
+}
diff --git a/contrib/gdb/gdb/alphabsd-tdep.c b/contrib/gdb/gdb/alphabsd-tdep.c
new file mode 100644
index 0000000..3e0f227
--- /dev/null
+++ b/contrib/gdb/gdb/alphabsd-tdep.c
@@ -0,0 +1,55 @@
+/* Common target dependent code for GDB on Alpha systems running BSD.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "alpha-tdep.h"
+#include "alphabsd-tdep.h"
+
+/* Conviently, GDB uses the same register numbering as the
+ ptrace register structure used by BSD on Alpha. */
+
+void
+alphabsd_supply_reg (char *regs, int regno)
+{
+ /* PC is at slot 32; UNIQUE not present. */
+ alpha_supply_int_regs (regno, regs, regs + 31*8, NULL);
+}
+
+void
+alphabsd_fill_reg (char *regs, int regno)
+{
+ /* PC is at slot 32; UNIQUE not present. */
+ alpha_fill_int_regs (regno, regs, regs + 31*8, NULL);
+}
+
+void
+alphabsd_supply_fpreg (char *fpregs, int regno)
+{
+ /* FPCR is at slot 33; slot 32 unused. */
+ alpha_supply_fp_regs (regno, fpregs, fpregs + 32*8);
+}
+
+void
+alphabsd_fill_fpreg (char *fpregs, int regno)
+{
+ /* FPCR is at slot 33; slot 32 unused. */
+ alpha_fill_fp_regs (regno, fpregs, fpregs + 32*8);
+}
diff --git a/contrib/gdb/gdb/alphabsd-tdep.h b/contrib/gdb/gdb/alphabsd-tdep.h
new file mode 100644
index 0000000..48d8798
--- /dev/null
+++ b/contrib/gdb/gdb/alphabsd-tdep.h
@@ -0,0 +1,33 @@
+/* Common target dependent code for GDB on Alpha systems running BSD.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 ALPHABSD_TDEP_H
+#define ALPHABSD_TDEP_H
+
+void alphabsd_supply_reg (char *, int);
+void alphabsd_fill_reg (char *, int);
+
+void alphabsd_supply_fpreg (char *, int);
+void alphabsd_fill_fpreg (char *, int);
+
+#define SIZEOF_STRUCT_REG (32 * 8)
+#define SIZEOF_STRUCT_FPREG (33 * 8)
+
+#endif /* ALPHABSD_TDEP_H */
diff --git a/contrib/gdb/gdb/alphafbsd-tdep.c b/contrib/gdb/gdb/alphafbsd-tdep.c
new file mode 100644
index 0000000..cc5f0e0
--- /dev/null
+++ b/contrib/gdb/gdb/alphafbsd-tdep.c
@@ -0,0 +1,124 @@
+/* Target-dependent code for FreeBSD/Alpha.
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "osabi.h"
+
+#include "alpha-tdep.h"
+
+static int
+alphafbsd_use_struct_convention (int gcc_p, struct type *type)
+{
+ enum type_code code;
+ int i;
+
+ /* All aggregate types that won't fit in a register must be returned
+ in memory. */
+ if (TYPE_LENGTH (type) > ALPHA_REGISTER_SIZE)
+ return 1;
+
+ /* The only aggregate types that can be returned in a register are
+ structs and unions. Arrays must be returned in memory. */
+ code = TYPE_CODE (type);
+ if (code != TYPE_CODE_STRUCT && code != TYPE_CODE_UNION)
+ return 1;
+
+ /* We need to check if this struct/union is "integer" like. For
+ this to be true, the offset of each adressable subfield must be
+ zero. Note that bit fields are not addressable. */
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ /* If the field bitsize is non-zero, it isn't adressable. */
+ if (TYPE_FIELD_BITPOS (type, i) != 0
+ && TYPE_FIELD_BITSIZE (type, i) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Support for signal handlers. */
+
+/* Return whether PC is in a BSD sigtramp routine. */
+
+CORE_ADDR alphafbsd_sigtramp_start = 0x11ffff68;
+CORE_ADDR alphafbsd_sigtramp_end = 0x11ffffe0;
+
+static int
+alphafbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ return (pc >= alphafbsd_sigtramp_start && pc < alphafbsd_sigtramp_end);
+}
+
+static LONGEST
+alphafbsd_sigtramp_offset (CORE_ADDR pc)
+{
+ return pc - alphafbsd_sigtramp_start;
+}
+
+/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
+ routine, return the address of the associated sigcontext structure. */
+
+static CORE_ADDR
+alphafbsd_sigcontext_addr (struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, ALPHA_SP_REGNUM) + 24;
+}
+
+/* FreeBSD 5.0-RELEASE or later. */
+
+static void
+alphafbsd_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Hook into the DWARF CFI frame unwinder. */
+ alpha_dwarf2_init_abi (info, gdbarch);
+
+ /* Hook into the MDEBUG frame unwinder. */
+ alpha_mdebug_init_abi (info, gdbarch);
+
+ set_gdbarch_use_struct_convention (gdbarch, alphafbsd_use_struct_convention);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, alphafbsd_pc_in_sigtramp);
+
+ tdep->dynamic_sigtramp_offset = alphafbsd_sigtramp_offset;
+ tdep->sigcontext_addr = alphafbsd_sigcontext_addr;
+ tdep->sc_pc_offset = 288;
+ tdep->sc_regs_offset = 24;
+ tdep->sc_fpregs_offset = 320;
+
+ tdep->jb_pc = 2;
+ tdep->jb_elt_size = 8;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_alphafbsd_tdep (void);
+
+void
+_initialize_alphafbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_FREEBSD_ELF,
+ alphafbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/alphanbsd-tdep.c b/contrib/gdb/gdb/alphanbsd-tdep.c
new file mode 100644
index 0000000..28d1bb5
--- /dev/null
+++ b/contrib/gdb/gdb/alphanbsd-tdep.c
@@ -0,0 +1,234 @@
+/* Target-dependent code for NetBSD/Alpha.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame.h"
+#include "regcache.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "solib-svr4.h"
+
+#include "alpha-tdep.h"
+#include "alphabsd-tdep.h"
+#include "nbsd-tdep.h"
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ char *regs, *fpregs;
+ int regno;
+
+ /* Table to map a gdb register number to a trapframe register index. */
+ static const int regmap[] =
+ {
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15,
+ 30, 31, 32, 16,
+ 17, 18, 19, 20,
+ 21, 22, 23, 24,
+ 25, 29, 26
+ };
+#define SIZEOF_TRAPFRAME (33 * 8)
+
+ /* We get everything from one section. */
+ if (which != 0)
+ return;
+
+ regs = core_reg_sect;
+ fpregs = core_reg_sect + SIZEOF_TRAPFRAME;
+
+ if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG))
+ {
+ warning ("Wrong size register set in core file.");
+ return;
+ }
+
+ /* Integer registers. */
+ for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++)
+ supply_register (regno, regs + (regmap[regno] * 8));
+ supply_register (ALPHA_ZERO_REGNUM, NULL);
+ supply_register (PC_REGNUM, regs + (28 * 8));
+
+ /* Floating point registers. */
+ alphabsd_supply_fpreg (fpregs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ switch (which)
+ {
+ case 0: /* Integer registers. */
+ if (core_reg_size != SIZEOF_STRUCT_REG)
+ warning ("Wrong size register set in core file.");
+ else
+ alphabsd_supply_reg (core_reg_sect, -1);
+ break;
+
+ case 2: /* Floating point registers. */
+ if (core_reg_size != SIZEOF_STRUCT_FPREG)
+ warning ("Wrong size FP register set in core file.");
+ else
+ alphabsd_supply_fpreg (core_reg_sect, -1);
+ break;
+
+ default:
+ /* Don't know what kind of register request this is; just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns alphanbsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+static struct core_fns alphanbsd_elfcore_fns =
+{
+ bfd_target_elf_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_elfcore_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+/* Under NetBSD/alpha, signal handler invocations can be identified by the
+ designated code sequence that is used to return from a signal handler.
+ In particular, the return address of a signal handler points to the
+ following code sequence:
+
+ ldq a0, 0(sp)
+ lda sp, 16(sp)
+ lda v0, 295(zero) # __sigreturn14
+ call_pal callsys
+
+ Each instruction has a unique encoding, so we simply attempt to match
+ the instruction the PC is pointing to with any of the above instructions.
+ If there is a hit, we know the offset to the start of the designated
+ sequence and can then check whether we really are executing in the
+ signal trampoline. If not, -1 is returned, otherwise the offset from the
+ start of the return sequence is returned. */
+static const unsigned char sigtramp_retcode[] =
+{
+ 0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */
+ 0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */
+ 0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */
+ 0x83, 0x00, 0x00, 0x00, /* call_pal callsys */
+};
+#define RETCODE_NWORDS 4
+#define RETCODE_SIZE (RETCODE_NWORDS * 4)
+
+LONGEST
+alphanbsd_sigtramp_offset (CORE_ADDR pc)
+{
+ unsigned char ret[RETCODE_SIZE], w[4];
+ LONGEST off;
+ int i;
+
+ if (read_memory_nobpt (pc, (char *) w, 4) != 0)
+ return -1;
+
+ for (i = 0; i < RETCODE_NWORDS; i++)
+ {
+ if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
+ break;
+ }
+ if (i == RETCODE_NWORDS)
+ return (-1);
+
+ off = i * 4;
+ pc -= off;
+
+ if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
+ return -1;
+
+ if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
+ return off;
+
+ return -1;
+}
+
+static int
+alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ return (nbsd_pc_in_sigtramp (pc, func_name)
+ || alphanbsd_sigtramp_offset (pc) >= 0);
+}
+
+static CORE_ADDR
+alphanbsd_sigcontext_addr (struct frame_info *frame)
+{
+ /* FIXME: This is not correct for all versions of NetBSD/alpha.
+ We will probably need to disassemble the trampoline to figure
+ out which trampoline frame type we have. */
+ return get_frame_base (frame);
+}
+
+static void
+alphanbsd_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Hook into the DWARF CFI frame unwinder. */
+ alpha_dwarf2_init_abi (info, gdbarch);
+
+ /* Hook into the MDEBUG frame unwinder. */
+ alpha_mdebug_init_abi (info, gdbarch);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, alphanbsd_pc_in_sigtramp);
+
+ /* NetBSD/alpha does not provide single step support via ptrace(2); we
+ must use software single-stepping. */
+ set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
+
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ nbsd_lp64_solib_svr4_fetch_link_map_offsets);
+
+ tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
+ tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
+
+ tdep->jb_pc = 2;
+ tdep->jb_elt_size = 8;
+}
+
+void
+_initialize_alphanbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
+ alphanbsd_init_abi);
+ gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF,
+ alphanbsd_init_abi);
+
+ add_core_fns (&alphanbsd_core_fns);
+ add_core_fns (&alphanbsd_elfcore_fns);
+}
diff --git a/contrib/gdb/gdb/amd64-nat.c b/contrib/gdb/gdb/amd64-nat.c
new file mode 100644
index 0000000..31b3603
--- /dev/null
+++ b/contrib/gdb/gdb/amd64-nat.c
@@ -0,0 +1,163 @@
+/* Native-dependent code for AMD64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbarch.h"
+#include "regcache.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "i386-tdep.h"
+#include "amd64-tdep.h"
+
+/* The following bits of code help with implementing debugging 32-bit
+ code natively on AMD64. The idea is to define two mappings between
+ the register number as used by GDB and the register set used by the
+ host to represent the general-purpose registers; one for 32-bit
+ code and one for 64-bit code. The mappings are specified by the
+ follwing variables and consist of an array of offsets within the
+ register set indexed by register number, and the number of
+ registers supported by the mapping. We don't need mappings for the
+ floating-point and SSE registers, since the difference between
+ 64-bit and 32-bit variants are negligable. The difference in the
+ number of SSE registers is already handled by the target code. */
+
+/* General-purpose register mapping for native 32-bit code. */
+int *amd64_native_gregset32_reg_offset;
+int amd64_native_gregset32_num_regs = I386_NUM_GREGS;
+
+/* General-purpose register mapping for native 64-bit code. */
+int *amd64_native_gregset64_reg_offset;
+int amd64_native_gregset64_num_regs = AMD64_NUM_GREGS;
+
+/* Return the offset of REGNUM within the appropriate native
+ general-purpose register set. */
+
+static int
+amd64_native_gregset_reg_offset (int regnum)
+{
+ int *reg_offset = amd64_native_gregset64_reg_offset;
+ int num_regs = amd64_native_gregset64_num_regs;
+
+ gdb_assert (regnum >= 0);
+
+ if (gdbarch_ptr_bit (current_gdbarch) == 32)
+ {
+ reg_offset = amd64_native_gregset32_reg_offset;
+ num_regs = amd64_native_gregset32_num_regs;
+ }
+
+ if (num_regs > NUM_REGS)
+ num_regs = NUM_REGS;
+
+ if (regnum < num_regs && regnum < NUM_REGS)
+ return reg_offset[regnum];
+
+ return -1;
+}
+
+/* Return whether the native general-purpose register set supplies
+ register REGNUM. */
+
+int
+amd64_native_gregset_supplies_p (int regnum)
+{
+ return (amd64_native_gregset_reg_offset (regnum) != -1);
+}
+
+
+/* Supply register REGNUM, whose contents are store in BUF, to
+ REGCACHE. If REGNUM is -1, supply all appropriate registers. */
+
+void
+amd64_supply_native_gregset (struct regcache *regcache,
+ const void *gregs, int regnum)
+{
+ const char *regs = gregs;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int num_regs = amd64_native_gregset64_num_regs;
+ int i;
+
+ if (gdbarch_ptr_bit (gdbarch) == 32)
+ num_regs = amd64_native_gregset32_num_regs;
+
+ if (num_regs > NUM_REGS)
+ num_regs = NUM_REGS;
+
+ for (i = 0; i < num_regs; i++)
+ {
+ if (regnum == -1 || regnum == i)
+ {
+ int offset = amd64_native_gregset_reg_offset (i);
+
+ if (offset != -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ }
+ }
+}
+
+/* Collect register REGNUM from REGCACHE and store its contents in
+ GREGS. If REGNUM is -1, collect and store all appropriate
+ registers. */
+
+void
+amd64_collect_native_gregset (const struct regcache *regcache,
+ void *gregs, int regnum)
+{
+ char *regs = gregs;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int num_regs = amd64_native_gregset64_num_regs;
+ int i;
+
+ if (gdbarch_ptr_bit (gdbarch) == 32)
+ {
+ num_regs = amd64_native_gregset32_num_regs;
+
+ /* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and
+ %eip get zero-extended to 64 bits. */
+ for (i = 0; i <= I386_EIP_REGNUM; i++)
+ {
+ if (regnum == -1 || regnum == i)
+ memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
+ }
+ /* Ditto for %cs, %ss, %ds, %es, %fs, and %gs. */
+ for (i = I386_CS_REGNUM; i <= I386_GS_REGNUM; i++)
+ {
+ if (regnum == -1 || regnum == i)
+ memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
+ }
+ }
+
+ if (num_regs > NUM_REGS)
+ num_regs = NUM_REGS;
+
+ for (i = 0; i < num_regs; i++)
+ {
+ if (regnum == -1 || regnum == i)
+ {
+ int offset = amd64_native_gregset_reg_offset (i);
+
+ if (offset != -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ }
+ }
+}
diff --git a/contrib/gdb/gdb/amd64-nat.h b/contrib/gdb/gdb/amd64-nat.h
new file mode 100644
index 0000000..edf6df8
--- /dev/null
+++ b/contrib/gdb/gdb/amd64-nat.h
@@ -0,0 +1,53 @@
+/* Native-dependent code for AMD64.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 AMD64_NAT_H
+#define AMD64_NAT_H 1
+
+struct regcache;
+
+/* General-purpose register set description for native 32-bit code. */
+extern int *amd64_native_gregset32_reg_offset;
+extern int amd64_native_gregset32_num_regs;
+
+/* General-purpose register set description for native 64-bit code. */
+extern int *amd64_native_gregset64_reg_offset;
+extern int amd64_native_gregset64_num_regs;
+
+/* Return whether the native general-purpose register set supplies
+ register REGNUM. */
+
+extern int amd64_native_gregset_supplies_p (int regnum);
+
+/* Supply register REGNUM, whose contents are store in BUF, to
+ REGCACHE. If REGNUM is -1, supply all appropriate registers. */
+
+extern void amd64_supply_native_gregset (struct regcache *regcache,
+ const void *gregs, int regnum);
+
+/* Collect register REGNUM from REGCACHE and store its contents in
+ GREGS. If REGNUM is -1, collect and store all appropriate
+ registers. */
+
+extern void amd64_collect_native_gregset (const struct regcache *regcache,
+ void *gregs, int regnum);
+
+#endif /* amd64-nat.h */
diff --git a/contrib/gdb/gdb/amd64-tdep.c b/contrib/gdb/gdb/amd64-tdep.c
new file mode 100644
index 0000000..e0b2ca0
--- /dev/null
+++ b/contrib/gdb/gdb/amd64-tdep.c
@@ -0,0 +1,1199 @@
+/* Target-dependent code for AMD64.
+
+ Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Contributed by Jiri Smid, SuSE Labs.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "block.h"
+#include "dummy-frame.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "inferior.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "objfiles.h"
+#include "regcache.h"
+#include "regset.h"
+#include "symfile.h"
+
+#include "gdb_assert.h"
+
+#include "amd64-tdep.h"
+#include "i387-tdep.h"
+
+/* Note that the AMD64 architecture was previously known as x86-64.
+ The latter is (forever) engraved into the canonical system name as
+ returned by config.guess, and used as the name for the AMD64 port
+ of GNU/Linux. The BSD's have renamed their ports to amd64; they
+ don't like to shout. For GDB we prefer the amd64_-prefix over the
+ x86_64_-prefix since it's so much easier to type. */
+
+/* Register information. */
+
+struct amd64_register_info
+{
+ char *name;
+ struct type **type;
+};
+
+static struct amd64_register_info amd64_register_info[] =
+{
+ { "rax", &builtin_type_int64 },
+ { "rbx", &builtin_type_int64 },
+ { "rcx", &builtin_type_int64 },
+ { "rdx", &builtin_type_int64 },
+ { "rsi", &builtin_type_int64 },
+ { "rdi", &builtin_type_int64 },
+ { "rbp", &builtin_type_void_data_ptr },
+ { "rsp", &builtin_type_void_data_ptr },
+
+ /* %r8 is indeed register number 8. */
+ { "r8", &builtin_type_int64 },
+ { "r9", &builtin_type_int64 },
+ { "r10", &builtin_type_int64 },
+ { "r11", &builtin_type_int64 },
+ { "r12", &builtin_type_int64 },
+ { "r13", &builtin_type_int64 },
+ { "r14", &builtin_type_int64 },
+ { "r15", &builtin_type_int64 },
+ { "rip", &builtin_type_void_func_ptr },
+ { "eflags", &builtin_type_int32 },
+ { "cs", &builtin_type_int32 },
+ { "ss", &builtin_type_int32 },
+ { "ds", &builtin_type_int32 },
+ { "es", &builtin_type_int32 },
+ { "fs", &builtin_type_int32 },
+ { "gs", &builtin_type_int32 },
+
+ /* %st0 is register number 24. */
+ { "st0", &builtin_type_i387_ext },
+ { "st1", &builtin_type_i387_ext },
+ { "st2", &builtin_type_i387_ext },
+ { "st3", &builtin_type_i387_ext },
+ { "st4", &builtin_type_i387_ext },
+ { "st5", &builtin_type_i387_ext },
+ { "st6", &builtin_type_i387_ext },
+ { "st7", &builtin_type_i387_ext },
+ { "fctrl", &builtin_type_int32 },
+ { "fstat", &builtin_type_int32 },
+ { "ftag", &builtin_type_int32 },
+ { "fiseg", &builtin_type_int32 },
+ { "fioff", &builtin_type_int32 },
+ { "foseg", &builtin_type_int32 },
+ { "fooff", &builtin_type_int32 },
+ { "fop", &builtin_type_int32 },
+
+ /* %xmm0 is register number 40. */
+ { "xmm0", &builtin_type_v4sf },
+ { "xmm1", &builtin_type_v4sf },
+ { "xmm2", &builtin_type_v4sf },
+ { "xmm3", &builtin_type_v4sf },
+ { "xmm4", &builtin_type_v4sf },
+ { "xmm5", &builtin_type_v4sf },
+ { "xmm6", &builtin_type_v4sf },
+ { "xmm7", &builtin_type_v4sf },
+ { "xmm8", &builtin_type_v4sf },
+ { "xmm9", &builtin_type_v4sf },
+ { "xmm10", &builtin_type_v4sf },
+ { "xmm11", &builtin_type_v4sf },
+ { "xmm12", &builtin_type_v4sf },
+ { "xmm13", &builtin_type_v4sf },
+ { "xmm14", &builtin_type_v4sf },
+ { "xmm15", &builtin_type_v4sf },
+ { "mxcsr", &builtin_type_int32 }
+};
+
+/* Total number of registers. */
+#define AMD64_NUM_REGS \
+ (sizeof (amd64_register_info) / sizeof (amd64_register_info[0]))
+
+/* Return the name of register REGNUM. */
+
+static const char *
+amd64_register_name (int regnum)
+{
+ if (regnum >= 0 && regnum < AMD64_NUM_REGS)
+ return amd64_register_info[regnum].name;
+
+ return NULL;
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. */
+
+static struct type *
+amd64_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ gdb_assert (regnum >= 0 && regnum < AMD64_NUM_REGS);
+
+ return *amd64_register_info[regnum].type;
+}
+
+/* DWARF Register Number Mapping as defined in the System V psABI,
+ section 3.6. */
+
+static int amd64_dwarf_regmap[] =
+{
+ /* General Purpose Registers RAX, RDX, RCX, RBX, RSI, RDI. */
+ AMD64_RAX_REGNUM, AMD64_RDX_REGNUM,
+ AMD64_RCX_REGNUM, AMD64_RBX_REGNUM,
+ AMD64_RSI_REGNUM, AMD64_RDI_REGNUM,
+
+ /* Frame Pointer Register RBP. */
+ AMD64_RBP_REGNUM,
+
+ /* Stack Pointer Register RSP. */
+ AMD64_RSP_REGNUM,
+
+ /* Extended Integer Registers 8 - 15. */
+ 8, 9, 10, 11, 12, 13, 14, 15,
+
+ /* Return Address RA. Mapped to RIP. */
+ AMD64_RIP_REGNUM,
+
+ /* SSE Registers 0 - 7. */
+ AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM,
+ AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3,
+ AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5,
+ AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7,
+
+ /* Extended SSE Registers 8 - 15. */
+ AMD64_XMM0_REGNUM + 8, AMD64_XMM0_REGNUM + 9,
+ AMD64_XMM0_REGNUM + 10, AMD64_XMM0_REGNUM + 11,
+ AMD64_XMM0_REGNUM + 12, AMD64_XMM0_REGNUM + 13,
+ AMD64_XMM0_REGNUM + 14, AMD64_XMM0_REGNUM + 15,
+
+ /* Floating Point Registers 0-7. */
+ AMD64_ST0_REGNUM + 0, AMD64_ST0_REGNUM + 1,
+ AMD64_ST0_REGNUM + 2, AMD64_ST0_REGNUM + 3,
+ AMD64_ST0_REGNUM + 4, AMD64_ST0_REGNUM + 5,
+ AMD64_ST0_REGNUM + 6, AMD64_ST0_REGNUM + 7
+};
+
+static const int amd64_dwarf_regmap_len =
+ (sizeof (amd64_dwarf_regmap) / sizeof (amd64_dwarf_regmap[0]));
+
+/* Convert DWARF register number REG to the appropriate register
+ number used by GDB. */
+
+static int
+amd64_dwarf_reg_to_regnum (int reg)
+{
+ int regnum = -1;
+
+ if (reg >= 0 || reg < amd64_dwarf_regmap_len)
+ regnum = amd64_dwarf_regmap[reg];
+
+ if (regnum == -1)
+ warning ("Unmapped DWARF Register #%d encountered\n", reg);
+
+ return regnum;
+}
+
+/* Return nonzero if a value of type TYPE stored in register REGNUM
+ needs any special handling. */
+
+static int
+amd64_convert_register_p (int regnum, struct type *type)
+{
+ return i386_fp_regnum_p (regnum);
+}
+
+
+/* Register classes as defined in the psABI. */
+
+enum amd64_reg_class
+{
+ AMD64_INTEGER,
+ AMD64_SSE,
+ AMD64_SSEUP,
+ AMD64_X87,
+ AMD64_X87UP,
+ AMD64_COMPLEX_X87,
+ AMD64_NO_CLASS,
+ AMD64_MEMORY
+};
+
+/* Return the union class of CLASS1 and CLASS2. See the psABI for
+ details. */
+
+static enum amd64_reg_class
+amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2)
+{
+ /* Rule (a): If both classes are equal, this is the resulting class. */
+ if (class1 == class2)
+ return class1;
+
+ /* Rule (b): If one of the classes is NO_CLASS, the resulting class
+ is the other class. */
+ if (class1 == AMD64_NO_CLASS)
+ return class2;
+ if (class2 == AMD64_NO_CLASS)
+ return class1;
+
+ /* Rule (c): If one of the classes is MEMORY, the result is MEMORY. */
+ if (class1 == AMD64_MEMORY || class2 == AMD64_MEMORY)
+ return AMD64_MEMORY;
+
+ /* Rule (d): If one of the classes is INTEGER, the result is INTEGER. */
+ if (class1 == AMD64_INTEGER || class2 == AMD64_INTEGER)
+ return AMD64_INTEGER;
+
+ /* Rule (e): If one of the classes is X87, X87UP, COMPLEX_X87 class,
+ MEMORY is used as class. */
+ if (class1 == AMD64_X87 || class1 == AMD64_X87UP
+ || class1 == AMD64_COMPLEX_X87 || class2 == AMD64_X87
+ || class2 == AMD64_X87UP || class2 == AMD64_COMPLEX_X87)
+ return AMD64_MEMORY;
+
+ /* Rule (f): Otherwise class SSE is used. */
+ return AMD64_SSE;
+}
+
+static void amd64_classify (struct type *type, enum amd64_reg_class class[2]);
+
+/* Return non-zero if TYPE is a non-POD structure or union type. */
+
+static int
+amd64_non_pod_p (struct type *type)
+{
+ /* ??? A class with a base class certainly isn't POD, but does this
+ catch all non-POD structure types? */
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_N_BASECLASSES (type) > 0)
+ return 1;
+
+ return 0;
+}
+
+/* Classify TYPE according to the rules for aggregate (structures and
+ arrays) and union types, and store the result in CLASS. */
+
+static void
+amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
+{
+ int len = TYPE_LENGTH (type);
+
+ /* 1. If the size of an object is larger than two eightbytes, or in
+ C++, is a non-POD structure or union type, or contains
+ unaligned fields, it has class memory. */
+ if (len > 16 || amd64_non_pod_p (type))
+ {
+ class[0] = class[1] = AMD64_MEMORY;
+ return;
+ }
+
+ /* 2. Both eightbytes get initialized to class NO_CLASS. */
+ class[0] = class[1] = AMD64_NO_CLASS;
+
+ /* 3. Each field of an object is classified recursively so that
+ always two fields are considered. The resulting class is
+ calculated according to the classes of the fields in the
+ eightbyte: */
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ struct type *subtype = check_typedef (TYPE_TARGET_TYPE (type));
+
+ /* All fields in an array have the same type. */
+ amd64_classify (subtype, class);
+ if (len > 8 && class[1] == AMD64_NO_CLASS)
+ class[1] = class[0];
+ }
+ else
+ {
+ int i;
+
+ /* Structure or union. */
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION);
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int pos = TYPE_FIELD_BITPOS (type, i) / 64;
+ enum amd64_reg_class subclass[2];
+
+ /* Ignore static fields. */
+ if (TYPE_FIELD_STATIC (type, i))
+ continue;
+
+ gdb_assert (pos == 0 || pos == 1);
+
+ amd64_classify (subtype, subclass);
+ class[pos] = amd64_merge_classes (class[pos], subclass[0]);
+ if (pos == 0)
+ class[1] = amd64_merge_classes (class[1], subclass[1]);
+ }
+ }
+
+ /* 4. Then a post merger cleanup is done: */
+
+ /* Rule (a): If one of the classes is MEMORY, the whole argument is
+ passed in memory. */
+ if (class[0] == AMD64_MEMORY || class[1] == AMD64_MEMORY)
+ class[0] = class[1] = AMD64_MEMORY;
+
+ /* Rule (b): If SSEUP is not preceeded by SSE, it is converted to
+ SSE. */
+ if (class[0] == AMD64_SSEUP)
+ class[0] = AMD64_SSE;
+ if (class[1] == AMD64_SSEUP && class[0] != AMD64_SSE)
+ class[1] = AMD64_SSE;
+}
+
+/* Classify TYPE, and store the result in CLASS. */
+
+static void
+amd64_classify (struct type *type, enum amd64_reg_class class[2])
+{
+ enum type_code code = TYPE_CODE (type);
+ int len = TYPE_LENGTH (type);
+
+ class[0] = class[1] = AMD64_NO_CLASS;
+
+ /* Arguments of types (signed and unsigned) _Bool, char, short, int,
+ long, long long, and pointers are in the INTEGER class. */
+ if ((code == TYPE_CODE_INT || code == TYPE_CODE_ENUM
+ || code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
+ && (len == 1 || len == 2 || len == 4 || len == 8))
+ class[0] = AMD64_INTEGER;
+
+ /* Arguments of types float, double and __m64 are in class SSE. */
+ else if (code == TYPE_CODE_FLT && (len == 4 || len == 8))
+ /* FIXME: __m64 . */
+ class[0] = AMD64_SSE;
+
+ /* Arguments of types __float128 and __m128 are split into two
+ halves. The least significant ones belong to class SSE, the most
+ significant one to class SSEUP. */
+ /* FIXME: __float128, __m128. */
+
+ /* The 64-bit mantissa of arguments of type long double belongs to
+ class X87, the 16-bit exponent plus 6 bytes of padding belongs to
+ class X87UP. */
+ else if (code == TYPE_CODE_FLT && len == 16)
+ /* Class X87 and X87UP. */
+ class[0] = AMD64_X87, class[1] = AMD64_X87UP;
+
+ /* Aggregates. */
+ else if (code == TYPE_CODE_ARRAY || code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION)
+ amd64_classify_aggregate (type, class);
+}
+
+static enum return_value_convention
+amd64_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache,
+ void *readbuf, const void *writebuf)
+{
+ enum amd64_reg_class class[2];
+ int len = TYPE_LENGTH (type);
+ static int integer_regnum[] = { AMD64_RAX_REGNUM, AMD64_RDX_REGNUM };
+ static int sse_regnum[] = { AMD64_XMM0_REGNUM, AMD64_XMM1_REGNUM };
+ int integer_reg = 0;
+ int sse_reg = 0;
+ int i;
+
+ gdb_assert (!(readbuf && writebuf));
+
+ /* 1. Classify the return type with the classification algorithm. */
+ amd64_classify (type, class);
+
+ /* 2. If the type has class MEMORY, then the caller provides space
+ for the return value and passes the address of this storage in
+ %rdi as if it were the first argument to the function. In
+ effect, this address becomes a hidden first argument. */
+ if (class[0] == AMD64_MEMORY)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ gdb_assert (class[1] != AMD64_MEMORY);
+ gdb_assert (len <= 16);
+
+ for (i = 0; len > 0; i++, len -= 8)
+ {
+ int regnum = -1;
+ int offset = 0;
+
+ switch (class[i])
+ {
+ case AMD64_INTEGER:
+ /* 3. If the class is INTEGER, the next available register
+ of the sequence %rax, %rdx is used. */
+ regnum = integer_regnum[integer_reg++];
+ break;
+
+ case AMD64_SSE:
+ /* 4. If the class is SSE, the next available SSE register
+ of the sequence %xmm0, %xmm1 is used. */
+ regnum = sse_regnum[sse_reg++];
+ break;
+
+ case AMD64_SSEUP:
+ /* 5. If the class is SSEUP, the eightbyte is passed in the
+ upper half of the last used SSE register. */
+ gdb_assert (sse_reg > 0);
+ regnum = sse_regnum[sse_reg - 1];
+ offset = 8;
+ break;
+
+ case AMD64_X87:
+ /* 6. If the class is X87, the value is returned on the X87
+ stack in %st0 as 80-bit x87 number. */
+ regnum = AMD64_ST0_REGNUM;
+ if (writebuf)
+ i387_return_value (gdbarch, regcache);
+ break;
+
+ case AMD64_X87UP:
+ /* 7. If the class is X87UP, the value is returned together
+ with the previous X87 value in %st0. */
+ gdb_assert (i > 0 && class[0] == AMD64_X87);
+ regnum = AMD64_ST0_REGNUM;
+ offset = 8;
+ len = 2;
+ break;
+
+ case AMD64_NO_CLASS:
+ continue;
+
+ default:
+ gdb_assert (!"Unexpected register class.");
+ }
+
+ gdb_assert (regnum != -1);
+
+ if (readbuf)
+ regcache_raw_read_part (regcache, regnum, offset, min (len, 8),
+ (char *) readbuf + i * 8);
+ if (writebuf)
+ regcache_raw_write_part (regcache, regnum, offset, min (len, 8),
+ (const char *) writebuf + i * 8);
+ }
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
+static CORE_ADDR
+amd64_push_arguments (struct regcache *regcache, int nargs,
+ struct value **args, CORE_ADDR sp, int struct_return)
+{
+ static int integer_regnum[] =
+ {
+ AMD64_RDI_REGNUM, /* %rdi */
+ AMD64_RSI_REGNUM, /* %rsi */
+ AMD64_RDX_REGNUM, /* %rdx */
+ AMD64_RCX_REGNUM, /* %rcx */
+ 8, /* %r8 */
+ 9 /* %r9 */
+ };
+ static int sse_regnum[] =
+ {
+ /* %xmm0 ... %xmm7 */
+ AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM,
+ AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3,
+ AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5,
+ AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7,
+ };
+ struct value **stack_args = alloca (nargs * sizeof (struct value *));
+ int num_stack_args = 0;
+ int num_elements = 0;
+ int element = 0;
+ int integer_reg = 0;
+ int sse_reg = 0;
+ int i;
+
+ /* Reserve a register for the "hidden" argument. */
+ if (struct_return)
+ integer_reg++;
+
+ for (i = 0; i < nargs; i++)
+ {
+ struct type *type = VALUE_TYPE (args[i]);
+ int len = TYPE_LENGTH (type);
+ enum amd64_reg_class class[2];
+ int needed_integer_regs = 0;
+ int needed_sse_regs = 0;
+ int j;
+
+ /* Classify argument. */
+ amd64_classify (type, class);
+
+ /* Calculate the number of integer and SSE registers needed for
+ this argument. */
+ for (j = 0; j < 2; j++)
+ {
+ if (class[j] == AMD64_INTEGER)
+ needed_integer_regs++;
+ else if (class[j] == AMD64_SSE)
+ needed_sse_regs++;
+ }
+
+ /* Check whether enough registers are available, and if the
+ argument should be passed in registers at all. */
+ if (integer_reg + needed_integer_regs > ARRAY_SIZE (integer_regnum)
+ || sse_reg + needed_sse_regs > ARRAY_SIZE (sse_regnum)
+ || (needed_integer_regs == 0 && needed_sse_regs == 0))
+ {
+ /* The argument will be passed on the stack. */
+ num_elements += ((len + 7) / 8);
+ stack_args[num_stack_args++] = args[i];
+ }
+ else
+ {
+ /* The argument will be passed in registers. */
+ char *valbuf = VALUE_CONTENTS (args[i]);
+ char buf[8];
+
+ gdb_assert (len <= 16);
+
+ for (j = 0; len > 0; j++, len -= 8)
+ {
+ int regnum = -1;
+ int offset = 0;
+
+ switch (class[j])
+ {
+ case AMD64_INTEGER:
+ regnum = integer_regnum[integer_reg++];
+ break;
+
+ case AMD64_SSE:
+ regnum = sse_regnum[sse_reg++];
+ break;
+
+ case AMD64_SSEUP:
+ gdb_assert (sse_reg > 0);
+ regnum = sse_regnum[sse_reg - 1];
+ offset = 8;
+ break;
+
+ default:
+ gdb_assert (!"Unexpected register class.");
+ }
+
+ gdb_assert (regnum != -1);
+ memset (buf, 0, sizeof buf);
+ memcpy (buf, valbuf + j * 8, min (len, 8));
+ regcache_raw_write_part (regcache, regnum, offset, 8, buf);
+ }
+ }
+ }
+
+ /* Allocate space for the arguments on the stack. */
+ sp -= num_elements * 8;
+
+ /* The psABI says that "The end of the input argument area shall be
+ aligned on a 16 byte boundary." */
+ sp &= ~0xf;
+
+ /* Write out the arguments to the stack. */
+ for (i = 0; i < num_stack_args; i++)
+ {
+ struct type *type = VALUE_TYPE (stack_args[i]);
+ char *valbuf = VALUE_CONTENTS (stack_args[i]);
+ int len = TYPE_LENGTH (type);
+
+ write_memory (sp + element * 8, valbuf, len);
+ element += ((len + 7) / 8);
+ }
+
+ /* The psABI says that "For calls that may call functions that use
+ varargs or stdargs (prototype-less calls or calls to functions
+ containing ellipsis (...) in the declaration) %al is used as
+ hidden argument to specify the number of SSE registers used. */
+ regcache_raw_write_unsigned (regcache, AMD64_RAX_REGNUM, sse_reg);
+ return sp;
+}
+
+static CORE_ADDR
+amd64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ char buf[8];
+
+ /* Pass arguments. */
+ sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return);
+
+ /* Pass "hidden" argument". */
+ if (struct_return)
+ {
+ store_unsigned_integer (buf, 8, struct_addr);
+ regcache_cooked_write (regcache, AMD64_RDI_REGNUM, buf);
+ }
+
+ /* Store return address. */
+ sp -= 8;
+ store_unsigned_integer (buf, 8, bp_addr);
+ write_memory (sp, buf, 8);
+
+ /* Finally, update the stack pointer... */
+ store_unsigned_integer (buf, 8, sp);
+ regcache_cooked_write (regcache, AMD64_RSP_REGNUM, buf);
+
+ /* ...and fake a frame pointer. */
+ regcache_cooked_write (regcache, AMD64_RBP_REGNUM, buf);
+
+ return sp + 16;
+}
+
+
+/* The maximum number of saved registers. This should include %rip. */
+#define AMD64_NUM_SAVED_REGS AMD64_NUM_GREGS
+
+struct amd64_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR sp_offset;
+ CORE_ADDR pc;
+
+ /* Saved registers. */
+ CORE_ADDR saved_regs[AMD64_NUM_SAVED_REGS];
+ CORE_ADDR saved_sp;
+
+ /* Do we have a frame? */
+ int frameless_p;
+};
+
+/* Allocate and initialize a frame cache. */
+
+static struct amd64_frame_cache *
+amd64_alloc_frame_cache (void)
+{
+ struct amd64_frame_cache *cache;
+ int i;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct amd64_frame_cache);
+
+ /* Base address. */
+ cache->base = 0;
+ cache->sp_offset = -8;
+ cache->pc = 0;
+
+ /* Saved registers. We initialize these to -1 since zero is a valid
+ offset (that's where %rbp is supposed to be stored). */
+ for (i = 0; i < AMD64_NUM_SAVED_REGS; i++)
+ cache->saved_regs[i] = -1;
+ cache->saved_sp = 0;
+
+ /* Frameless until proven otherwise. */
+ cache->frameless_p = 1;
+
+ return cache;
+}
+
+/* Do a limited analysis of the prologue at PC and update CACHE
+ accordingly. Bail out early if CURRENT_PC is reached. Return the
+ address where the analysis stopped.
+
+ We will handle only functions beginning with:
+
+ pushq %rbp 0x55
+ movq %rsp, %rbp 0x48 0x89 0xe5
+
+ Any function that doesn't start with this sequence will be assumed
+ to have no prologue and thus no valid frame pointer in %rbp. */
+
+static CORE_ADDR
+amd64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct amd64_frame_cache *cache)
+{
+ static unsigned char proto[3] = { 0x48, 0x89, 0xe5 };
+ unsigned char buf[3];
+ unsigned char op;
+
+ if (current_pc <= pc)
+ return current_pc;
+
+ op = read_memory_unsigned_integer (pc, 1);
+
+ if (op == 0x55) /* pushq %rbp */
+ {
+ /* Take into account that we've executed the `pushq %rbp' that
+ starts this instruction sequence. */
+ cache->saved_regs[AMD64_RBP_REGNUM] = 0;
+ cache->sp_offset += 8;
+
+ /* If that's all, return now. */
+ if (current_pc <= pc + 1)
+ return current_pc;
+
+ /* Check for `movq %rsp, %rbp'. */
+ read_memory (pc + 1, buf, 3);
+ if (memcmp (buf, proto, 3) != 0)
+ return pc + 1;
+
+ /* OK, we actually have a frame. */
+ cache->frameless_p = 0;
+ return pc + 4;
+ }
+
+ return pc;
+}
+
+/* Return PC of first real instruction. */
+
+static CORE_ADDR
+amd64_skip_prologue (CORE_ADDR start_pc)
+{
+ struct amd64_frame_cache cache;
+ CORE_ADDR pc;
+
+ pc = amd64_analyze_prologue (start_pc, 0xffffffffffffffff, &cache);
+ if (cache.frameless_p)
+ return start_pc;
+
+ return pc;
+}
+
+
+/* Normal frames. */
+
+static struct amd64_frame_cache *
+amd64_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct amd64_frame_cache *cache;
+ char buf[8];
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = amd64_alloc_frame_cache ();
+ *this_cache = cache;
+
+ cache->pc = frame_func_unwind (next_frame);
+ if (cache->pc != 0)
+ amd64_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
+
+ if (cache->frameless_p)
+ {
+ /* We didn't find a valid frame. If we're at the start of a
+ function, or somewhere half-way its prologue, the function's
+ frame probably hasn't been fully setup yet. Try to
+ reconstruct the base address for the stack frame by looking
+ at the stack pointer. For truly "frameless" functions this
+ might work too. */
+
+ frame_unwind_register (next_frame, AMD64_RSP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 8) + cache->sp_offset;
+ }
+ else
+ {
+ frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 8);
+ }
+
+ /* Now that we have the base address for the stack frame we can
+ calculate the value of %rsp in the calling frame. */
+ cache->saved_sp = cache->base + 16;
+
+ /* For normal frames, %rip is stored at 8(%rbp). If we don't have a
+ frame we find it at the same offset from the reconstructed base
+ address. */
+ cache->saved_regs[AMD64_RIP_REGNUM] = 8;
+
+ /* Adjust all the saved registers such that they contain addresses
+ instead of offsets. */
+ for (i = 0; i < AMD64_NUM_SAVED_REGS; i++)
+ if (cache->saved_regs[i] != -1)
+ cache->saved_regs[i] += cache->base;
+
+ return cache;
+}
+
+static void
+amd64_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct amd64_frame_cache *cache =
+ amd64_frame_cache (next_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (cache->base + 16, cache->pc);
+}
+
+static void
+amd64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct amd64_frame_cache *cache =
+ amd64_frame_cache (next_frame, this_cache);
+
+ gdb_assert (regnum >= 0);
+
+ if (regnum == SP_REGNUM && cache->saved_sp)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Store the value. */
+ store_unsigned_integer (valuep, 8, cache->saved_sp);
+ }
+ return;
+ }
+
+ if (regnum < AMD64_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = cache->saved_regs[regnum];
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Read the value in from memory. */
+ read_memory (*addrp, valuep,
+ register_size (current_gdbarch, regnum));
+ }
+ return;
+ }
+
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind amd64_frame_unwind =
+{
+ NORMAL_FRAME,
+ amd64_frame_this_id,
+ amd64_frame_prev_register
+};
+
+static const struct frame_unwind *
+amd64_frame_sniffer (struct frame_info *next_frame)
+{
+ return &amd64_frame_unwind;
+}
+
+
+/* Signal trampolines. */
+
+/* FIXME: kettenis/20030419: Perhaps, we can unify the 32-bit and
+ 64-bit variants. This would require using identical frame caches
+ on both platforms. */
+
+static struct amd64_frame_cache *
+amd64_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct amd64_frame_cache *cache;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ CORE_ADDR addr;
+ char buf[8];
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = amd64_alloc_frame_cache ();
+
+ frame_unwind_register (next_frame, AMD64_RSP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 8) - 8;
+
+ addr = tdep->sigcontext_addr (next_frame);
+ gdb_assert (tdep->sc_reg_offset);
+ gdb_assert (tdep->sc_num_regs <= AMD64_NUM_SAVED_REGS);
+ for (i = 0; i < tdep->sc_num_regs; i++)
+ if (tdep->sc_reg_offset[i] != -1)
+ cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+
+ *this_cache = cache;
+ return cache;
+}
+
+static void
+amd64_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct amd64_frame_cache *cache =
+ amd64_sigtramp_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base + 16, frame_pc_unwind (next_frame));
+}
+
+static void
+amd64_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ /* Make sure we've initialized the cache. */
+ amd64_sigtramp_frame_cache (next_frame, this_cache);
+
+ amd64_frame_prev_register (next_frame, this_cache, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind amd64_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ amd64_sigtramp_frame_this_id,
+ amd64_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+amd64_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (PC_IN_SIGTRAMP (pc, name))
+ {
+ gdb_assert (gdbarch_tdep (current_gdbarch)->sigcontext_addr);
+
+ return &amd64_sigtramp_frame_unwind;
+ }
+
+ return NULL;
+}
+
+
+static CORE_ADDR
+amd64_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct amd64_frame_cache *cache =
+ amd64_frame_cache (next_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_base amd64_frame_base =
+{
+ &amd64_frame_unwind,
+ amd64_frame_base_address,
+ amd64_frame_base_address,
+ amd64_frame_base_address
+};
+
+static struct frame_id
+amd64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ char buf[8];
+ CORE_ADDR fp;
+
+ frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf);
+ fp = extract_unsigned_integer (buf, 8);
+
+ return frame_id_build (fp + 16, frame_pc_unwind (next_frame));
+}
+
+/* 16 byte align the SP per frame requirements. */
+
+static CORE_ADDR
+amd64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+ return sp & -(CORE_ADDR)16;
+}
+
+
+/* Supply register REGNUM from the floating-point register set REGSET
+ to register cache REGCACHE. If REGNUM is -1, do this for all
+ registers in REGSET. */
+
+static void
+amd64_supply_fpregset (const struct regset *regset, struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = regset->descr;
+
+ gdb_assert (len == tdep->sizeof_fpregset);
+ amd64_supply_fxsave (regcache, regnum, fpregs);
+}
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+
+static const struct regset *
+amd64_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
+ {
+ if (tdep->fpregset == NULL)
+ {
+ tdep->fpregset = XMALLOC (struct regset);
+ tdep->fpregset->descr = tdep;
+ tdep->fpregset->supply_regset = amd64_supply_fpregset;
+ }
+
+ return tdep->fpregset;
+ }
+
+ return i386_regset_from_core_section (gdbarch, sect_name, sect_size);
+}
+
+
+void
+amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* AMD64 generally uses `fxsave' instead of `fsave' for saving its
+ floating-point registers. */
+ tdep->sizeof_fpregset = I387_SIZEOF_FXSAVE;
+
+ /* AMD64 has an FPU and 16 SSE registers. */
+ tdep->st0_regnum = AMD64_ST0_REGNUM;
+ tdep->num_xmm_regs = 16;
+
+ /* This is what all the fuss is about. */
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+
+ /* In contrast to the i386, on AMD64 a `long double' actually takes
+ up 128 bits, even though it's still based on the i387 extended
+ floating-point format which has only 80 significant bits. */
+ set_gdbarch_long_double_bit (gdbarch, 128);
+
+ set_gdbarch_num_regs (gdbarch, AMD64_NUM_REGS);
+ set_gdbarch_register_name (gdbarch, amd64_register_name);
+ set_gdbarch_register_type (gdbarch, amd64_register_type);
+
+ /* Register numbers of various important registers. */
+ set_gdbarch_sp_regnum (gdbarch, AMD64_RSP_REGNUM); /* %rsp */
+ set_gdbarch_pc_regnum (gdbarch, AMD64_RIP_REGNUM); /* %rip */
+ set_gdbarch_ps_regnum (gdbarch, AMD64_EFLAGS_REGNUM); /* %eflags */
+ set_gdbarch_fp0_regnum (gdbarch, AMD64_ST0_REGNUM); /* %st(0) */
+
+ /* The "default" register numbering scheme for AMD64 is referred to
+ as the "DWARF Register Number Mapping" in the System V psABI.
+ The preferred debugging format for all known AMD64 targets is
+ actually DWARF2, and GCC doesn't seem to support DWARF (that is
+ DWARF-1), but we provide the same mapping just in case. This
+ mapping is also used for stabs, which GCC does support. */
+ set_gdbarch_stab_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
+
+ /* We don't override SDB_REG_RO_REGNUM, since COFF doesn't seem to
+ be in use on any of the supported AMD64 targets. */
+
+ /* Call dummy code. */
+ set_gdbarch_push_dummy_call (gdbarch, amd64_push_dummy_call);
+ set_gdbarch_frame_align (gdbarch, amd64_frame_align);
+ set_gdbarch_frame_red_zone_size (gdbarch, 128);
+
+ set_gdbarch_convert_register_p (gdbarch, amd64_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, i387_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, i387_value_to_register);
+
+ set_gdbarch_return_value (gdbarch, amd64_return_value);
+
+ set_gdbarch_skip_prologue (gdbarch, amd64_skip_prologue);
+
+ /* Avoid wiring in the MMX registers for now. */
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+ tdep->mm0_regnum = -1;
+
+ set_gdbarch_unwind_dummy_id (gdbarch, amd64_unwind_dummy_id);
+
+ /* FIXME: kettenis/20021026: This is ELF-specific. Fine for now,
+ since all supported AMD64 targets are ELF, but that might change
+ in the future. */
+ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
+
+ frame_unwind_append_sniffer (gdbarch, amd64_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, amd64_frame_sniffer);
+ frame_base_set_default (gdbarch, &amd64_frame_base);
+
+ /* If we have a register mapping, enable the generic core file support. */
+ if (tdep->gregset_reg_offset)
+ set_gdbarch_regset_from_core_section (gdbarch,
+ amd64_regset_from_core_section);
+}
+
+
+#define I387_ST0_REGNUM AMD64_ST0_REGNUM
+
+/* The 64-bit FXSAVE format differs from the 32-bit format in the
+ sense that the instruction pointer and data pointer are simply
+ 64-bit offsets into the code segment and the data segment instead
+ of a selector offset pair. The functions below store the upper 32
+ bits of these pointers (instead of just the 16-bits of the segment
+ selector). */
+
+/* Fill register REGNUM in REGCACHE with the appropriate
+ floating-point or SSE register value from *FXSAVE. If REGNUM is
+ -1, do this for all registers. This function masks off any of the
+ reserved bits in *FXSAVE. */
+
+void
+amd64_supply_fxsave (struct regcache *regcache, int regnum,
+ const void *fxsave)
+{
+ i387_supply_fxsave (regcache, regnum, fxsave);
+
+ if (fxsave)
+ {
+ const char *regs = fxsave;
+
+ if (regnum == -1 || regnum == I387_FISEG_REGNUM)
+ regcache_raw_supply (regcache, I387_FISEG_REGNUM, regs + 12);
+ if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
+ regcache_raw_supply (regcache, I387_FOSEG_REGNUM, regs + 20);
+ }
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
+ all registers. This function doesn't touch any of the reserved
+ bits in *FXSAVE. */
+
+void
+amd64_collect_fxsave (const struct regcache *regcache, int regnum,
+ void *fxsave)
+{
+ char *regs = fxsave;
+
+ i387_collect_fxsave (regcache, regnum, fxsave);
+
+ if (regnum == -1 || regnum == I387_FISEG_REGNUM)
+ regcache_raw_collect (regcache, I387_FISEG_REGNUM, regs + 12);
+ if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
+ regcache_raw_collect (regcache, I387_FOSEG_REGNUM, regs + 20);
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
+ this for all registers. This function doesn't touch any of the
+ reserved bits in *FXSAVE. */
+
+void
+amd64_fill_fxsave (char *fxsave, int regnum)
+{
+ amd64_collect_fxsave (current_regcache, regnum, fxsave);
+}
diff --git a/contrib/gdb/gdb/amd64-tdep.h b/contrib/gdb/gdb/amd64-tdep.h
new file mode 100644
index 0000000..042618b
--- /dev/null
+++ b/contrib/gdb/gdb/amd64-tdep.h
@@ -0,0 +1,93 @@
+/* Target-dependent definitions for AMD64.
+
+ Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+ Contributed by Jiri Smid, SuSE Labs.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 AMD64_TDEP_H
+#define AMD64_TDEP_H
+
+struct gdbarch;
+struct frame_info;
+struct regcache;
+
+#include "i386-tdep.h"
+
+/* Register numbers of various important registers. */
+
+enum amd64_regnum
+{
+ AMD64_RAX_REGNUM, /* %rax */
+ AMD64_RBX_REGNUM, /* %rbx */
+ AMD64_RCX_REGNUM, /* %rcx */
+ AMD64_RDX_REGNUM, /* %rdx */
+ AMD64_RSI_REGNUM, /* %rsi */
+ AMD64_RDI_REGNUM, /* %rdi */
+ AMD64_RBP_REGNUM, /* %rbp */
+ AMD64_RSP_REGNUM, /* %rsp */
+ AMD64_R8_REGNUM = 8, /* %r8 */
+ AMD64_R15_REGNUM = 15, /* %r15 */
+ AMD64_RIP_REGNUM, /* %rip */
+ AMD64_EFLAGS_REGNUM, /* %eflags */
+ AMD64_ST0_REGNUM = 24, /* %st0 */
+ AMD64_XMM0_REGNUM = 40, /* %xmm0 */
+ AMD64_XMM1_REGNUM /* %xmm1 */
+};
+
+/* Number of general purpose registers. */
+#define AMD64_NUM_GREGS 24
+
+extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
+
+/* Fill register REGNUM in REGCACHE with the appropriate
+ floating-point or SSE register value from *FXSAVE. If REGNUM is
+ -1, do this for all registers. This function masks off any of the
+ reserved bits in *FXSAVE. */
+
+extern void amd64_supply_fxsave (struct regcache *regcache, int regnum,
+ const void *fxsave);
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
+ all registers. This function doesn't touch any of the reserved
+ bits in *FXSAVE. */
+
+extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum,
+ void *fxsave);
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
+ this for all registers. This function doesn't touch any of the
+ reserved bits in *FXSAVE. */
+
+extern void amd64_fill_fxsave (char *fxsave, int regnum);
+
+
+/* Variables exported from amd64nbsd-tdep.c. */
+extern int amd64nbsd_r_reg_offset[];
+
+/* Variables exported from amd64obsd-tdep.c. */
+extern int amd64obsd_r_reg_offset[];
+
+/* Variables exported from amd64fbsd-tdep.c. */
+extern CORE_ADDR amd64fbsd_sigtramp_start_addr;
+extern CORE_ADDR amd64fbsd_sigtramp_end_addr;
+extern int amd64fbsd_sc_reg_offset[];
+
+#endif /* amd64-tdep.h */
diff --git a/contrib/gdb/gdb/amd64bsd-nat.c b/contrib/gdb/gdb/amd64bsd-nat.c
new file mode 100644
index 0000000..4c7c04a
--- /dev/null
+++ b/contrib/gdb/gdb/amd64bsd-nat.c
@@ -0,0 +1,107 @@
+/* Native-dependent code for AMD64 BSD's.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+/* We include <signal.h> to make sure `struct fxsave64' is defined on
+ NetBSD, since NetBSD's <machine/reg.h> needs it. */
+#include "gdb_assert.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#include "amd64-tdep.h"
+#include "amd64-nat.h"
+
+
+/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
+ for all registers (including the floating-point registers). */
+
+void
+fetch_inferior_registers (int regnum)
+{
+ if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ amd64_supply_native_gregset (current_regcache, &regs, -1);
+ if (regnum != -1)
+ return;
+ }
+
+ if (regnum == -1 || regnum >= AMD64_ST0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ amd64_supply_fxsave (current_regcache, -1, &fpregs);
+ }
+}
+
+/* Store register REGNUM back into the inferior. If REGNUM is -1, do
+ this for all registers (including the floating-point registers). */
+
+void
+store_inferior_registers (int regnum)
+{
+ if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ amd64_collect_native_gregset (current_regcache, &regs, regnum);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ if (regnum != -1)
+ return;
+ }
+
+ if (regnum == -1 || regnum >= AMD64_ST0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ amd64_fill_fxsave ((char *) &fpregs, regnum);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't write floating point status");
+ }
+}
diff --git a/contrib/gdb/gdb/amd64fbsd-nat.c b/contrib/gdb/gdb/amd64fbsd-nat.c
new file mode 100644
index 0000000..f083734
--- /dev/null
+++ b/contrib/gdb/gdb/amd64fbsd-nat.c
@@ -0,0 +1,235 @@
+/* Native-dependent code for FreeBSD/amd64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include "gdb_assert.h"
+#include <signal.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <machine/reg.h>
+
+#ifdef HAVE_SYS_PROCFS_H
+#include <sys/procfs.h>
+#endif
+
+#ifndef HAVE_GREGSET_T
+typedef struct reg gregset_t;
+#endif
+
+#ifndef HAVE_FPREGSET_T
+typedef struct fpreg fpregset_t;
+#endif
+
+#include "gregset.h"
+#include "amd64-tdep.h"
+#include "amd64-nat.h"
+
+
+/* Offset to the gregset_t location where REG is stored. */
+#define REG_OFFSET(reg) offsetof (gregset_t, reg)
+
+/* At reg_offset[REGNUM] you'll find the offset to the gregset_t
+ location where the GDB register REGNUM is stored. Unsupported
+ registers are marked with `-1'. */
+static int reg_offset[] =
+{
+ REG_OFFSET (r_rax),
+ REG_OFFSET (r_rbx),
+ REG_OFFSET (r_rcx),
+ REG_OFFSET (r_rdx),
+ REG_OFFSET (r_rsi),
+ REG_OFFSET (r_rdi),
+ REG_OFFSET (r_rbp),
+ REG_OFFSET (r_rsp),
+ REG_OFFSET (r_r8),
+ REG_OFFSET (r_r9),
+ REG_OFFSET (r_r10),
+ REG_OFFSET (r_r11),
+ REG_OFFSET (r_r12),
+ REG_OFFSET (r_r13),
+ REG_OFFSET (r_r14),
+ REG_OFFSET (r_r15),
+ REG_OFFSET (r_rip),
+ REG_OFFSET (r_rflags),
+ REG_OFFSET (r_cs),
+ REG_OFFSET (r_ss),
+ -1,
+ -1,
+ -1,
+ -1
+};
+
+
+/* Mapping between the general-purpose registers in FreeBSD/amd64
+ `struct reg' format and GDB's register cache layout for
+ FreeBSD/i386.
+
+ Note that most FreeBSD/amd64 registers are 64-bit, while the
+ FreeBSD/i386 registers are all 32-bit, but since we're
+ little-endian we get away with that. */
+
+/* From <machine/reg.h>. */
+static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
+{
+ 14 * 8, 13 * 8, /* %eax, %ecx */
+ 12 * 8, 11 * 8, /* %edx, %ebx */
+ 20 * 8, 10 * 8, /* %esp, %ebp */
+ 9 * 8, 8 * 8, /* %esi, %edi */
+ 17 * 8, 19 * 8, /* %eip, %eflags */
+ 18 * 8, 21 * 8, /* %cs, %ss */
+ -1, -1, -1, -1 /* %ds, %es, %fs, %gs */
+};
+
+
+/* Transfering the registers between GDB, inferiors and core files. */
+
+/* Fill GDB's register array with the general-purpose register values
+ in *GREGSETP. */
+
+void
+supply_gregset (gregset_t *gregsetp)
+{
+ amd64_supply_native_gregset (current_regcache, gregsetp, -1);
+}
+
+/* Fill register REGNUM (if it is a general-purpose register) in
+ *GREGSETPS with the value in GDB's register array. If REGNUM is -1,
+ do this for all registers. */
+
+void
+fill_gregset (gregset_t *gregsetp, int regnum)
+{
+ amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
+}
+
+/* Fill GDB's register array with the floating-point register values
+ in *FPREGSETP. */
+
+void
+supply_fpregset (fpregset_t *fpregsetp)
+{
+ amd64_supply_fxsave (current_regcache, -1, fpregsetp);
+}
+
+/* Fill register REGNUM (if it is a floating-point register) in
+ *FPREGSETP with the value in GDB's register array. If REGNUM is -1,
+ do this for all registers. */
+
+void
+fill_fpregset (fpregset_t *fpregsetp, int regnum)
+{
+ amd64_fill_fxsave ((char *) fpregsetp, regnum);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_amd64fbsd_nat (void);
+
+void
+_initialize_amd64fbsd_nat (void)
+{
+ int offset;
+
+ amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
+ amd64_native_gregset64_reg_offset = reg_offset;
+
+ /* To support the recognition of signal handlers, i386bsd-tdep.c
+ hardcodes some constants. Inclusion of this file means that we
+ are compiling a native debugger, which means that we can use the
+ system header files and sysctl(3) to get at the relevant
+ information. */
+
+#define SC_REG_OFFSET amd64fbsd_sc_reg_offset
+
+ /* We only check the program counter, stack pointer and frame
+ pointer since these members of `struct sigcontext' are essential
+ for providing backtraces. */
+
+#define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
+#define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
+#define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
+
+ /* Override the default value for the offset of the program counter
+ in the sigcontext structure. */
+ offset = offsetof (struct sigcontext, sc_rip);
+
+ if (SC_RIP_OFFSET != offset)
+ {
+ warning ("\
+offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
+Please report this to <bug-gdb@gnu.org>.",
+ offset, SC_RIP_OFFSET);
+ }
+
+ SC_RIP_OFFSET = offset;
+
+ /* Likewise for the stack pointer. */
+ offset = offsetof (struct sigcontext, sc_rsp);
+
+ if (SC_RSP_OFFSET != offset)
+ {
+ warning ("\
+offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
+Please report this to <bug-gdb@gnu.org>.",
+ offset, SC_RSP_OFFSET);
+ }
+
+ SC_RSP_OFFSET = offset;
+
+ /* And the frame pointer. */
+ offset = offsetof (struct sigcontext, sc_rbp);
+
+ if (SC_RBP_OFFSET != offset)
+ {
+ warning ("\
+offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
+Please report this to <bug-gdb@gnu.org>.",
+ offset, SC_RBP_OFFSET);
+ }
+
+ SC_RBP_OFFSET = offset;
+
+ /* FreeBSD provides a kern.ps_strings sysctl that we can use to
+ locate the sigtramp. That way we can still recognize a sigtramp
+ if its location is changed in a new kernel. Of course this is
+ still based on the assumption that the sigtramp is placed
+ directly under the location where the program arguments and
+ environment can be found. */
+ {
+ int mib[2];
+ long ps_strings;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PS_STRINGS;
+ len = sizeof (ps_strings);
+ if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0)
+ {
+ amd64fbsd_sigtramp_start_addr = ps_strings - 32;
+ amd64fbsd_sigtramp_end_addr = ps_strings;
+ }
+ }
+}
diff --git a/contrib/gdb/gdb/amd64fbsd-tdep.c b/contrib/gdb/gdb/amd64fbsd-tdep.c
new file mode 100644
index 0000000..e4e02ab
--- /dev/null
+++ b/contrib/gdb/gdb/amd64fbsd-tdep.c
@@ -0,0 +1,155 @@
+/* Target-dependent code for FreeBSD/amd64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "osabi.h"
+
+#include "gdb_string.h"
+
+#include "amd64-tdep.h"
+#include "solib-svr4.h"
+
+/* Support for signal handlers. */
+
+/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
+ routine, return the address of the associated sigcontext structure. */
+
+static CORE_ADDR
+amd64fbsd_sigcontext_addr (struct frame_info *next_frame)
+{
+ CORE_ADDR sp;
+
+ /* The `struct sigcontext' (which really is an `ucontext_t' on
+ FreeBSD/amd64) lives at a fixed offset in the signal frame. See
+ <machine/sigframe.h>. */
+ sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
+ return sp + 16;
+}
+
+/* FreeBSD 5.1-RELEASE or later. */
+
+/* Mapping between the general-purpose registers in `struct reg'
+ format and GDB's register cache layout.
+
+ Note that some registers are 32-bit, but since we're little-endian
+ we get away with that. */
+
+/* From <machine/reg.h>. */
+static int amd64fbsd_r_reg_offset[] =
+{
+ 14 * 8, /* %rax */
+ 11 * 8, /* %rbx */
+ 13 * 8, /* %rcx */
+ 12 * 8, /* %rdx */
+ 9 * 8, /* %rsi */
+ 8 * 8, /* %rdi */
+ 10 * 8, /* %rbp */
+ 20 * 8, /* %rsp */
+ 7 * 8, /* %r8 ... */
+ 6 * 8,
+ 5 * 8,
+ 4 * 8,
+ 3 * 8,
+ 2 * 8,
+ 1 * 8,
+ 0 * 8, /* ... %r15 */
+ 17 * 8, /* %rip */
+ 19 * 8, /* %eflags */
+ 18 * 8, /* %cs */
+ 21 * 8, /* %ss */
+ -1, /* %ds */
+ -1, /* %es */
+ -1, /* %fs */
+ -1 /* %gs */
+};
+
+/* Location of the signal trampoline. */
+CORE_ADDR amd64fbsd_sigtramp_start_addr = 0x7fffffffffc0;
+CORE_ADDR amd64fbsd_sigtramp_end_addr = 0x7fffffffffe0;
+
+/* From <machine/signal.h>. */
+int amd64fbsd_sc_reg_offset[] =
+{
+ 24 + 6 * 8, /* %rax */
+ 24 + 7 * 8, /* %rbx */
+ 24 + 3 * 8, /* %rcx */
+ 24 + 2 * 8, /* %rdx */
+ 24 + 1 * 8, /* %rsi */
+ 24 + 0 * 8, /* %rdi */
+ 24 + 8 * 8, /* %rbp */
+ 24 + 22 * 8, /* %rsp */
+ 24 + 4 * 8, /* %r8 ... */
+ 24 + 5 * 8,
+ 24 + 9 * 8,
+ 24 + 10 * 8,
+ 24 + 11 * 8,
+ 24 + 12 * 8,
+ 24 + 13 * 8,
+ 24 + 14 * 8, /* ... %r15 */
+ 24 + 19 * 8, /* %rip */
+ 24 + 21 * 8, /* %eflags */
+ 24 + 20 * 8, /* %cs */
+ 24 + 23 * 8, /* %ss */
+ -1, /* %ds */
+ -1, /* %es */
+ -1, /* %fs */
+ -1 /* %gs */
+};
+
+void
+amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Obviously FreeBSD is BSD-based. */
+ i386bsd_init_abi (info, gdbarch);
+
+ tdep->gregset_reg_offset = amd64fbsd_r_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (amd64fbsd_r_reg_offset);
+ tdep->sizeof_gregset = 22 * 8;
+
+ amd64_init_abi (info, gdbarch);
+
+ tdep->sigtramp_start = amd64fbsd_sigtramp_start_addr;
+ tdep->sigtramp_end = amd64fbsd_sigtramp_end_addr;
+ tdep->sigcontext_addr = amd64fbsd_sigcontext_addr;
+ tdep->sc_reg_offset = amd64fbsd_sc_reg_offset;
+ tdep->sc_num_regs = ARRAY_SIZE (amd64fbsd_sc_reg_offset);
+
+ /* FreeBSD uses SVR4-style shared libraries. */
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_lp64_fetch_link_map_offsets);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_amd64fbsd_tdep (void);
+
+void
+_initialize_amd64fbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+ GDB_OSABI_FREEBSD_ELF, amd64fbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/amd64nbsd-nat.c b/contrib/gdb/gdb/amd64nbsd-nat.c
new file mode 100644
index 0000000..df7ceb9
--- /dev/null
+++ b/contrib/gdb/gdb/amd64nbsd-nat.c
@@ -0,0 +1,68 @@
+/* Native-dependent code for NetBSD/amd64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_assert.h"
+
+#include "amd64-tdep.h"
+#include "amd64-nat.h"
+
+/* Mapping between the general-purpose registers in NetBSD/amd64
+ `struct reg' format and GDB's register cache layout for
+ NetBSD/i386.
+
+ Note that most (if not all) NetBSD/amd64 registers are 64-bit,
+ while the NetBSD/i386 registers are all 32-bit, but since we're
+ little-endian we get away with that. */
+
+/* From <machine/reg.h>. */
+static int amd64nbsd32_r_reg_offset[] =
+{
+ 14 * 8, /* %eax */
+ 3 * 8, /* %ecx */
+ 2 * 8, /* %edx */
+ 13 * 8, /* %ebx */
+ 24 * 8, /* %esp */
+ 12 * 8, /* %ebp */
+ 1 * 8, /* %esi */
+ 0 * 8, /* %edi */
+ 21 * 8, /* %eip */
+ 23 * 8, /* %eflags */
+ 22 * 8, /* %cs */
+ 25 * 8, /* %ss */
+ 18 * 8, /* %ds */
+ 17 * 8, /* %es */
+ 16 * 8, /* %fs */
+ 15 * 8 /* %gs */
+};
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_amd64nbsd_nat (void);
+
+void
+_initialize_amd64nbsd_nat (void)
+{
+ amd64_native_gregset32_reg_offset = amd64nbsd32_r_reg_offset;
+ amd64_native_gregset32_num_regs = ARRAY_SIZE (amd64nbsd32_r_reg_offset);
+ amd64_native_gregset64_reg_offset = amd64nbsd_r_reg_offset;
+}
diff --git a/contrib/gdb/gdb/amd64nbsd-tdep.c b/contrib/gdb/gdb/amd64nbsd-tdep.c
new file mode 100644
index 0000000..a04e04f
--- /dev/null
+++ b/contrib/gdb/gdb/amd64nbsd-tdep.c
@@ -0,0 +1,135 @@
+/* Target-dependent code for NetBSD/amd64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "osabi.h"
+
+#include "gdb_assert.h"
+
+#include "amd64-tdep.h"
+#include "nbsd-tdep.h"
+#include "solib-svr4.h"
+
+/* Support for signal handlers. */
+
+/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
+ routine, return the address of the associated sigcontext structure. */
+
+static CORE_ADDR
+amd64nbsd_sigcontext_addr (struct frame_info *next_frame)
+{
+ CORE_ADDR sp;
+
+ /* The stack pointer points at `struct sigcontext' upon entry of a
+ signal trampoline. */
+ sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
+ return sp;
+}
+
+/* NetBSD 2.0 or later. */
+
+/* Mapping between the general-purpose registers in `struct reg'
+ format and GDB's register cache layout. */
+
+/* From <machine/reg.h>. */
+int amd64nbsd_r_reg_offset[] =
+{
+ 14 * 8, /* %rax */
+ 13 * 8, /* %rbx */
+ 3 * 8, /* %rcx */
+ 2 * 8, /* %rdx */
+ 1 * 8, /* %rsi */
+ 0 * 8, /* %rdi */
+ 12 * 8, /* %rbp */
+ 24 * 8, /* %rsp */
+ 4 * 8, /* %r8 .. */
+ 5 * 8,
+ 6 * 8,
+ 7 * 8,
+ 8 * 8,
+ 9 * 8,
+ 10 * 8,
+ 11 * 8, /* ... %r15 */
+ 21 * 8, /* %rip */
+ 23 * 8, /* %eflags */
+ 22 * 8, /* %cs */
+ 25 * 8, /* %ss */
+ 18 * 8, /* %ds */
+ 17 * 8, /* %es */
+ 16 * 8, /* %fs */
+ 15 * 8 /* %gs */
+};
+
+static void
+amd64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int *sc_reg_offset;
+ int i;
+
+ /* Initialize general-purpose register set details first. */
+ tdep->gregset_reg_offset = amd64nbsd_r_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
+ tdep->sizeof_gregset = 26 * 8;
+
+ amd64_init_abi (info, gdbarch);
+
+ tdep->jb_pc_offset = 7 * 8;
+
+ /* NetBSD has its own convention for signal trampolines. */
+ set_gdbarch_pc_in_sigtramp (gdbarch, nbsd_pc_in_sigtramp);
+ tdep->sigcontext_addr = amd64nbsd_sigcontext_addr;
+
+ /* Initialize the array with register offsets in `struct
+ sigcontext'. This `struct sigcontext' has an sc_mcontext member
+ at offset 32, and in <machine/reg.h> we have an explicit comment
+ saying that `struct reg' is the same as mcontext.__gregs. */
+ tdep->sc_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
+ tdep->sc_reg_offset = XCALLOC (tdep->sc_num_regs, int);
+ for (i = 0; i < tdep->sc_num_regs; i++)
+ {
+ if (amd64nbsd_r_reg_offset[i] < 0)
+ tdep->sc_reg_offset[i] = -1;
+ else
+ tdep->sc_reg_offset[i] = 32 + amd64nbsd_r_reg_offset[i];
+ }
+
+ /* NetBSD uses SVR4-style shared libraries. */
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_lp64_fetch_link_map_offsets);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_amd64nbsd_tdep (void);
+
+void
+_initialize_amd64nbsd_ndep (void)
+{
+ /* The NetBSD/amd64 native dependent code makes this assumption. */
+ gdb_assert (ARRAY_SIZE (amd64nbsd_r_reg_offset) == AMD64_NUM_GREGS);
+
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+ GDB_OSABI_NETBSD_ELF, amd64nbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/amd64obsd-nat.c b/contrib/gdb/gdb/amd64obsd-nat.c
new file mode 100644
index 0000000..e8d92fe
--- /dev/null
+++ b/contrib/gdb/gdb/amd64obsd-nat.c
@@ -0,0 +1,68 @@
+/* Native-dependent code for OpenBSD/amd64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_assert.h"
+
+#include "amd64-tdep.h"
+#include "amd64-nat.h"
+
+/* Mapping between the general-purpose registers in OpenBSD/amd64
+ `struct reg' format and GDB's register cache layout for
+ OpenBSD/i386.
+
+ Note that most (if not all) OpenBSD/amd64 registers are 64-bit,
+ while the OpenBSD/i386 registers are all 32-bit, but since we're
+ little-endian we get away with that. */
+
+/* From <machine/reg.h>. */
+static int amd64obsd32_r_reg_offset[] =
+{
+ 14 * 8, /* %eax */
+ 3 * 8, /* %ecx */
+ 2 * 8, /* %edx */
+ 13 * 8, /* %ebx */
+ 15 * 8, /* %esp */
+ 12 * 8, /* %ebp */
+ 1 * 8, /* %esi */
+ 0 * 8, /* %edi */
+ 16 * 8, /* %eip */
+ 17 * 8, /* %eflags */
+ 18 * 8, /* %cs */
+ 19 * 8, /* %ss */
+ 20 * 8, /* %ds */
+ 21 * 8, /* %es */
+ 22 * 8, /* %fs */
+ 23 * 8 /* %gs */
+};
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_amd64obsd_nat (void);
+
+void
+_initialize_amd64obsd_nat (void)
+{
+ amd64_native_gregset32_reg_offset = amd64obsd32_r_reg_offset;
+ amd64_native_gregset32_num_regs = ARRAY_SIZE (amd64obsd32_r_reg_offset);
+ amd64_native_gregset64_reg_offset = amd64obsd_r_reg_offset;
+}
diff --git a/contrib/gdb/gdb/amd64obsd-tdep.c b/contrib/gdb/gdb/amd64obsd-tdep.c
new file mode 100644
index 0000000..198c87e
--- /dev/null
+++ b/contrib/gdb/gdb/amd64obsd-tdep.c
@@ -0,0 +1,224 @@
+/* Target-dependent code for OpenBSD/amd64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbcore.h"
+#include "osabi.h"
+#include "regset.h"
+#include "target.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "amd64-tdep.h"
+#include "i387-tdep.h"
+#include "solib-svr4.h"
+
+/* Support for core dumps. */
+
+static void
+amd64obsd_supply_regset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *regs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = regset->descr;
+
+ gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE);
+
+ i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
+ amd64_supply_fxsave (regcache, regnum, (char *)regs + tdep->sizeof_gregset);
+}
+
+static const struct regset *
+amd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* OpenBSD core dumps don't use seperate register sets for the
+ general-purpose and floating-point registers. */
+
+ if (strcmp (sect_name, ".reg") == 0
+ && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE)
+ {
+ if (tdep->gregset == NULL)
+ {
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = tdep;
+ tdep->gregset->supply_regset = amd64obsd_supply_regset;
+ }
+ return tdep->gregset;
+ }
+
+ return NULL;
+}
+
+
+/* Support for signal handlers. */
+
+static const int amd64obsd_page_size = 4096;
+
+static int
+amd64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
+ const char sigreturn[] =
+ {
+ 0x48, 0xc7, 0xc0,
+ 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */
+ 0xcd, 0x80 /* int $0x80 */
+ };
+ char *buf;
+
+ if (name)
+ return 0;
+
+ /* If we can't read the instructions at START_PC, return zero. */
+ buf = alloca (sizeof sigreturn);
+ if (target_read_memory (start_pc + 0x7, buf, sizeof sigreturn))
+ return 0;
+
+ /* Check for sigreturn(2). */
+ if (memcmp (buf, sigreturn, sizeof sigreturn))
+ return 0;
+
+ return 1;
+}
+
+/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
+ routine, return the address of the associated sigcontext structure. */
+
+static CORE_ADDR
+amd64obsd_sigcontext_addr (struct frame_info *next_frame)
+{
+ /* The %rsp register points at `struct sigcontext' upon entry of a
+ signal trampoline. */
+ return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
+}
+
+/* OpenBSD 3.5 or later. */
+
+/* Mapping between the general-purpose registers in `struct reg'
+ format and GDB's register cache layout. */
+
+/* From <machine/reg.h>. */
+int amd64obsd_r_reg_offset[] =
+{
+ 14 * 8, /* %rax */
+ 13 * 8, /* %rbx */
+ 3 * 8, /* %rcx */
+ 2 * 8, /* %rdx */
+ 1 * 8, /* %rsi */
+ 0 * 8, /* %rdi */
+ 12 * 8, /* %rbp */
+ 15 * 8, /* %rsp */
+ 4 * 8, /* %r8 .. */
+ 5 * 8,
+ 6 * 8,
+ 7 * 8,
+ 8 * 8,
+ 9 * 8,
+ 10 * 8,
+ 11 * 8, /* ... %r15 */
+ 16 * 8, /* %rip */
+ 17 * 8, /* %eflags */
+ 18 * 8, /* %cs */
+ 19 * 8, /* %ss */
+ 20 * 8, /* %ds */
+ 21 * 8, /* %es */
+ 22 * 8, /* %fs */
+ 23 * 8 /* %gs */
+};
+
+/* From <machine/signal.h>. */
+static int amd64obsd_sc_reg_offset[] =
+{
+ 14 * 8, /* %rax */
+ 13 * 8, /* %rbx */
+ 3 * 8, /* %rcx */
+ 2 * 8, /* %rdx */
+ 1 * 8, /* %rsi */
+ 0 * 8, /* %rdi */
+ 12 * 8, /* %rbp */
+ 24 * 8, /* %rsp */
+ 4 * 8, /* %r8 ... */
+ 5 * 8,
+ 6 * 8,
+ 7 * 8,
+ 8 * 8,
+ 9 * 8,
+ 10 * 8,
+ 11 * 8, /* ... %r15 */
+ 21 * 8, /* %rip */
+ 23 * 8, /* %eflags */
+ 22 * 8, /* %cs */
+ 25 * 8, /* %ss */
+ 18 * 8, /* %ds */
+ 17 * 8, /* %es */
+ 16 * 8, /* %fs */
+ 15 * 8 /* %gs */
+};
+
+static void
+amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ amd64_init_abi (info, gdbarch);
+
+ /* Initialize general-purpose register set details. */
+ tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
+ tdep->sizeof_gregset = 24 * 8;
+
+ set_gdbarch_regset_from_core_section (gdbarch,
+ amd64obsd_regset_from_core_section);
+
+ tdep->jb_pc_offset = 7 * 8;
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, amd64obsd_pc_in_sigtramp);
+ tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
+ tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
+ tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
+
+ /* OpenBSD uses SVR4-style shared libraries. */
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_lp64_fetch_link_map_offsets);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_amd64obsd_tdep (void);
+
+void
+_initialize_amd64obsd_tdep (void)
+{
+ /* The OpenBSD/amd64 native dependent code makes this assumption. */
+ gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
+
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+ GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
+
+ /* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+ GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/annotate.c b/contrib/gdb/gdb/annotate.c
new file mode 100644
index 0000000..0ba9b42
--- /dev/null
+++ b/contrib/gdb/gdb/annotate.c
@@ -0,0 +1,585 @@
+/* Annotation routines for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1998, 1999,
+ 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+
+/* Prototypes for local functions. */
+
+extern void _initialize_annotate (void);
+
+static void print_value_flags (struct type *);
+
+static void breakpoint_changed (struct breakpoint *);
+
+void (*annotate_starting_hook) (void);
+void (*annotate_stopped_hook) (void);
+void (*annotate_signalled_hook) (void);
+void (*annotate_signal_hook) (void);
+void (*annotate_exited_hook) (void);
+
+static int ignore_count_changed = 0;
+
+static void
+print_value_flags (struct type *t)
+{
+ if (can_dereference (t))
+ printf_filtered ("*");
+ else
+ printf_filtered ("-");
+}
+
+void
+breakpoints_changed (void)
+{
+ if (annotation_level > 1)
+ {
+ target_terminal_ours ();
+ printf_unfiltered ("\n\032\032breakpoints-invalid\n");
+ if (ignore_count_changed)
+ ignore_count_changed = 0; /* Avoid multiple break annotations. */
+ }
+}
+
+/* The GUI needs to be informed of ignore_count changes, but we don't
+ want to provide successive multiple breakpoints-invalid messages
+ that are all caused by the fact that the ignore count is changing
+ (which could keep the GUI very busy). One is enough, after the
+ target actually "stops". */
+
+void
+annotate_ignore_count_change (void)
+{
+ if (annotation_level > 1)
+ ignore_count_changed = 1;
+}
+
+void
+annotate_breakpoint (int num)
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032breakpoint %d\n", num);
+}
+
+void
+annotate_catchpoint (int num)
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032catchpoint %d\n", num);
+}
+
+void
+annotate_watchpoint (int num)
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032watchpoint %d\n", num);
+}
+
+void
+annotate_starting (void)
+{
+
+ if (annotate_starting_hook)
+ annotate_starting_hook ();
+ else
+ {
+ if (annotation_level > 1)
+ {
+ printf_filtered ("\n\032\032starting\n");
+ }
+ }
+}
+
+void
+annotate_stopped (void)
+{
+ if (annotate_stopped_hook)
+ annotate_stopped_hook ();
+ else
+ {
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032stopped\n");
+ }
+ if (annotation_level > 1 && ignore_count_changed)
+ {
+ ignore_count_changed = 0;
+ breakpoints_changed ();
+ }
+}
+
+void
+annotate_exited (int exitstatus)
+{
+ if (annotate_exited_hook)
+ annotate_exited_hook ();
+ else
+ {
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032exited %d\n", exitstatus);
+ }
+}
+
+void
+annotate_signalled (void)
+{
+ if (annotate_signalled_hook)
+ annotate_signalled_hook ();
+
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signalled\n");
+}
+
+void
+annotate_signal_name (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032signal-name\n");
+}
+
+void
+annotate_signal_name_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032signal-name-end\n");
+}
+
+void
+annotate_signal_string (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032signal-string\n");
+}
+
+void
+annotate_signal_string_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032signal-string-end\n");
+}
+
+void
+annotate_signal (void)
+{
+ if (annotate_signal_hook)
+ annotate_signal_hook ();
+
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032signal\n");
+}
+
+void
+annotate_breakpoints_headers (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032breakpoints-headers\n");
+}
+
+void
+annotate_field (int num)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032field %d\n", num);
+}
+
+void
+annotate_breakpoints_table (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032breakpoints-table\n");
+}
+
+void
+annotate_record (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032record\n");
+}
+
+void
+annotate_breakpoints_table_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032breakpoints-table-end\n");
+}
+
+void
+annotate_frames_invalid (void)
+{
+ if (annotation_level > 1)
+ {
+ target_terminal_ours ();
+ printf_unfiltered ("\n\032\032frames-invalid\n");
+ }
+}
+
+void
+annotate_field_begin (struct type *type)
+{
+ if (annotation_level == 2)
+ {
+ printf_filtered ("\n\032\032field-begin ");
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_field_name_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032field-name-end\n");
+}
+
+void
+annotate_field_value (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032field-value\n");
+}
+
+void
+annotate_field_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032field-end\n");
+}
+
+void
+annotate_quit (void)
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032quit\n");
+}
+
+void
+annotate_error (void)
+{
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032error\n");
+}
+
+void
+annotate_error_begin (void)
+{
+ if (annotation_level > 1)
+ fprintf_filtered (gdb_stderr, "\n\032\032error-begin\n");
+}
+
+void
+annotate_value_history_begin (int histindex, struct type *type)
+{
+ if (annotation_level == 2)
+ {
+ printf_filtered ("\n\032\032value-history-begin %d ", histindex);
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_value_begin (struct type *type)
+{
+ if (annotation_level == 2)
+ {
+ printf_filtered ("\n\032\032value-begin ");
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_value_history_value (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032value-history-value\n");
+}
+
+void
+annotate_value_history_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032value-history-end\n");
+}
+
+void
+annotate_value_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032value-end\n");
+}
+
+void
+annotate_display_begin (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032display-begin\n");
+}
+
+void
+annotate_display_number_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032display-number-end\n");
+}
+
+void
+annotate_display_format (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032display-format\n");
+}
+
+void
+annotate_display_expression (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032display-expression\n");
+}
+
+void
+annotate_display_expression_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032display-expression-end\n");
+}
+
+void
+annotate_display_value (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032display-value\n");
+}
+
+void
+annotate_display_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032display-end\n");
+}
+
+void
+annotate_arg_begin (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032arg-begin\n");
+}
+
+void
+annotate_arg_name_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032arg-name-end\n");
+}
+
+void
+annotate_arg_value (struct type *type)
+{
+ if (annotation_level == 2)
+ {
+ printf_filtered ("\n\032\032arg-value ");
+ print_value_flags (type);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_arg_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032arg-end\n");
+}
+
+void
+annotate_source (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 (int level, CORE_ADDR pc)
+{
+ if (annotation_level == 2)
+ {
+ printf_filtered ("\n\032\032frame-begin %d 0x", level);
+ print_address_numeric (pc, 0, gdb_stdout);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_function_call (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032function-call\n");
+}
+
+void
+annotate_signal_handler_caller (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032signal-handler-caller\n");
+}
+
+void
+annotate_frame_address (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-address\n");
+}
+
+void
+annotate_frame_address_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-address-end\n");
+}
+
+void
+annotate_frame_function_name (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-function-name\n");
+}
+
+void
+annotate_frame_args (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-args\n");
+}
+
+void
+annotate_frame_source_begin (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-source-begin\n");
+}
+
+void
+annotate_frame_source_file (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-source-file\n");
+}
+
+void
+annotate_frame_source_file_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-source-file-end\n");
+}
+
+void
+annotate_frame_source_line (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-source-line\n");
+}
+
+void
+annotate_frame_source_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-source-end\n");
+}
+
+void
+annotate_frame_where (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-where\n");
+}
+
+void
+annotate_frame_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032frame-end\n");
+}
+
+void
+annotate_array_section_begin (int index, struct type *elttype)
+{
+ if (annotation_level == 2)
+ {
+ printf_filtered ("\n\032\032array-section-begin %d ", index);
+ print_value_flags (elttype);
+ printf_filtered ("\n");
+ }
+}
+
+void
+annotate_elt_rep (unsigned int repcount)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032elt-rep %u\n", repcount);
+}
+
+void
+annotate_elt_rep_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032elt-rep-end\n");
+}
+
+void
+annotate_elt (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032elt\n");
+}
+
+void
+annotate_array_section_end (void)
+{
+ if (annotation_level == 2)
+ printf_filtered ("\n\032\032array-section-end\n");
+}
+
+static void
+breakpoint_changed (struct breakpoint *b)
+{
+ breakpoints_changed ();
+}
+
+void
+_initialize_annotate (void)
+{
+ 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 0000000..ac3cec8
--- /dev/null
+++ b/contrib/gdb/gdb/annotate.h
@@ -0,0 +1,106 @@
+/* Annotation routines for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1992, 1994, 1998, 1999, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "symtab.h"
+#include "gdbtypes.h"
+
+extern void breakpoints_changed (void);
+
+extern void annotate_ignore_count_change (void);
+extern void annotate_breakpoint (int);
+extern void annotate_catchpoint (int);
+extern void annotate_watchpoint (int);
+extern void annotate_starting (void);
+extern void annotate_stopped (void);
+extern void annotate_exited (int);
+extern void annotate_signalled (void);
+extern void annotate_signal_name (void);
+extern void annotate_signal_name_end (void);
+extern void annotate_signal_string (void);
+extern void annotate_signal_string_end (void);
+extern void annotate_signal (void);
+
+extern void annotate_breakpoints_headers (void);
+extern void annotate_field (int);
+extern void annotate_breakpoints_table (void);
+extern void annotate_record (void);
+extern void annotate_breakpoints_table_end (void);
+
+extern void annotate_frames_invalid (void);
+
+struct type;
+
+extern void annotate_field_begin (struct type *);
+extern void annotate_field_name_end (void);
+extern void annotate_field_value (void);
+extern void annotate_field_end (void);
+
+extern void annotate_quit (void);
+extern void annotate_error (void);
+extern void annotate_error_begin (void);
+
+extern void annotate_value_history_begin (int, struct type *);
+extern void annotate_value_begin (struct type *);
+extern void annotate_value_history_value (void);
+extern void annotate_value_history_end (void);
+extern void annotate_value_end (void);
+
+extern void annotate_display_begin (void);
+extern void annotate_display_number_end (void);
+extern void annotate_display_format (void);
+extern void annotate_display_expression (void);
+extern void annotate_display_expression_end (void);
+extern void annotate_display_value (void);
+extern void annotate_display_end (void);
+
+extern void annotate_arg_begin (void);
+extern void annotate_arg_name_end (void);
+extern void annotate_arg_value (struct type *);
+extern void annotate_arg_end (void);
+
+extern void annotate_source (char *, int, int, int, CORE_ADDR);
+
+extern void annotate_frame_begin (int, CORE_ADDR);
+extern void annotate_function_call (void);
+extern void annotate_signal_handler_caller (void);
+extern void annotate_frame_address (void);
+extern void annotate_frame_address_end (void);
+extern void annotate_frame_function_name (void);
+extern void annotate_frame_args (void);
+extern void annotate_frame_source_begin (void);
+extern void annotate_frame_source_file (void);
+extern void annotate_frame_source_file_end (void);
+extern void annotate_frame_source_line (void);
+extern void annotate_frame_source_end (void);
+extern void annotate_frame_where (void);
+extern void annotate_frame_end (void);
+
+extern void annotate_array_section_begin (int, struct type *);
+extern void annotate_elt_rep (unsigned int);
+extern void annotate_elt_rep_end (void);
+extern void annotate_elt (void);
+extern void annotate_array_section_end (void);
+
+extern void (*annotate_starting_hook) (void);
+extern void (*annotate_stopped_hook) (void);
+extern void (*annotate_signalled_hook) (void);
+extern void (*annotate_signal_hook) (void);
+extern void (*annotate_exited_hook) (void);
diff --git a/contrib/gdb/gdb/arch-utils.c b/contrib/gdb/gdb/arch-utils.c
new file mode 100644
index 0000000..94ba59b
--- /dev/null
+++ b/contrib/gdb/gdb/arch-utils.c
@@ -0,0 +1,754 @@
+/* Dynamic architecture support for GDB, the GNU debugger.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "buildsym.h"
+#include "gdbcmd.h"
+#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
+#include "gdb_string.h"
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "sim-regno.h"
+
+#include "osabi.h"
+
+#include "version.h"
+
+#include "floatformat.h"
+
+/* Implementation of extract return value that grubs around in the
+ register cache. */
+void
+legacy_extract_return_value (struct type *type, struct regcache *regcache,
+ void *valbuf)
+{
+ char *registers = deprecated_grub_regcache_for_registers (regcache);
+ bfd_byte *buf = valbuf;
+ DEPRECATED_EXTRACT_RETURN_VALUE (type, registers, buf); /* OK */
+}
+
+/* Implementation of store return value that grubs the register cache.
+ Takes a local copy of the buffer to avoid const problems. */
+void
+legacy_store_return_value (struct type *type, struct regcache *regcache,
+ const void *buf)
+{
+ bfd_byte *b = alloca (TYPE_LENGTH (type));
+ gdb_assert (regcache == current_regcache);
+ memcpy (b, buf, TYPE_LENGTH (type));
+ DEPRECATED_STORE_RETURN_VALUE (type, b);
+}
+
+
+int
+always_use_struct_convention (int gcc_p, struct type *value_type)
+{
+ return 1;
+}
+
+
+int
+legacy_register_sim_regno (int regnum)
+{
+ /* Only makes sense to supply raw registers. */
+ gdb_assert (regnum >= 0 && regnum < NUM_REGS);
+ /* NOTE: cagney/2002-05-13: The old code did it this way and it is
+ suspected that some GDB/SIM combinations may rely on this
+ behavour. The default should be one2one_register_sim_regno
+ (below). */
+ if (REGISTER_NAME (regnum) != NULL
+ && REGISTER_NAME (regnum)[0] != '\0')
+ return regnum;
+ else
+ return LEGACY_SIM_REGNO_IGNORE;
+}
+
+int
+generic_return_value_on_stack_not (struct type *type)
+{
+ return 0;
+}
+
+CORE_ADDR
+generic_skip_trampoline_code (CORE_ADDR pc)
+{
+ return 0;
+}
+
+CORE_ADDR
+generic_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ return 0;
+}
+
+int
+generic_in_solib_call_trampoline (CORE_ADDR pc, char *name)
+{
+ return 0;
+}
+
+int
+generic_in_solib_return_trampoline (CORE_ADDR pc, char *name)
+{
+ return 0;
+}
+
+int
+generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ return 0;
+}
+
+#if defined (CALL_DUMMY)
+LONGEST legacy_call_dummy_words[] = CALL_DUMMY;
+#else
+LONGEST legacy_call_dummy_words[1];
+#endif
+int legacy_sizeof_call_dummy_words = sizeof (legacy_call_dummy_words);
+
+void
+generic_remote_translate_xfer_address (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR gdb_addr, int gdb_len,
+ CORE_ADDR * rem_addr, int *rem_len)
+{
+ *rem_addr = gdb_addr;
+ *rem_len = gdb_len;
+}
+
+/* Helper functions for INNER_THAN */
+
+int
+core_addr_lessthan (CORE_ADDR lhs, CORE_ADDR rhs)
+{
+ return (lhs < rhs);
+}
+
+int
+core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs)
+{
+ return (lhs > rhs);
+}
+
+
+/* Helper functions for TARGET_{FLOAT,DOUBLE}_FORMAT */
+
+const struct floatformat *
+default_float_format (struct gdbarch *gdbarch)
+{
+ int byte_order = gdbarch_byte_order (gdbarch);
+ switch (byte_order)
+ {
+ case BFD_ENDIAN_BIG:
+ return &floatformat_ieee_single_big;
+ case BFD_ENDIAN_LITTLE:
+ return &floatformat_ieee_single_little;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "default_float_format: bad byte order");
+ }
+}
+
+
+const struct floatformat *
+default_double_format (struct gdbarch *gdbarch)
+{
+ int byte_order = gdbarch_byte_order (gdbarch);
+ switch (byte_order)
+ {
+ case BFD_ENDIAN_BIG:
+ return &floatformat_ieee_double_big;
+ case BFD_ENDIAN_LITTLE:
+ return &floatformat_ieee_double_little;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "default_double_format: bad byte order");
+ }
+}
+
+/* Misc helper functions for targets. */
+
+CORE_ADDR
+core_addr_identity (CORE_ADDR addr)
+{
+ return addr;
+}
+
+CORE_ADDR
+convert_from_func_ptr_addr_identity (struct gdbarch *gdbarch, CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ return addr;
+}
+
+int
+no_op_reg_to_regnum (int reg)
+{
+ return reg;
+}
+
+CORE_ADDR
+deprecated_init_frame_pc_default (int fromleaf, struct frame_info *prev)
+{
+ if (fromleaf && DEPRECATED_SAVED_PC_AFTER_CALL_P ())
+ return DEPRECATED_SAVED_PC_AFTER_CALL (get_next_frame (prev));
+ else if (get_next_frame (prev) != NULL)
+ return DEPRECATED_FRAME_SAVED_PC (get_next_frame (prev));
+ else
+ return read_pc ();
+}
+
+void
+default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
+{
+ return;
+}
+
+void
+default_coff_make_msymbol_special (int val, struct minimal_symbol *msym)
+{
+ return;
+}
+
+int
+cannot_register_not (int regnum)
+{
+ return 0;
+}
+
+/* Legacy version of target_virtual_frame_pointer(). Assumes that
+ there is an DEPRECATED_FP_REGNUM and that it is the same, cooked or
+ raw. */
+
+void
+legacy_virtual_frame_pointer (CORE_ADDR pc,
+ int *frame_regnum,
+ LONGEST *frame_offset)
+{
+ /* FIXME: cagney/2002-09-13: This code is used when identifying the
+ frame pointer of the current PC. It is assuming that a single
+ register and an offset can determine this. I think it should
+ instead generate a byte code expression as that would work better
+ with things like Dwarf2's CFI. */
+ if (DEPRECATED_FP_REGNUM >= 0 && DEPRECATED_FP_REGNUM < NUM_REGS)
+ *frame_regnum = DEPRECATED_FP_REGNUM;
+ else if (SP_REGNUM >= 0 && SP_REGNUM < NUM_REGS)
+ *frame_regnum = SP_REGNUM;
+ else
+ /* Should this be an internal error? I guess so, it is reflecting
+ an architectural limitation in the current design. */
+ internal_error (__FILE__, __LINE__, "No virtual frame pointer available");
+ *frame_offset = 0;
+}
+
+/* Assume the world is sane, every register's virtual and real size
+ is identical. */
+
+int
+generic_register_size (int regnum)
+{
+ gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS);
+ if (gdbarch_register_type_p (current_gdbarch))
+ return TYPE_LENGTH (gdbarch_register_type (current_gdbarch, regnum));
+ else
+ /* FIXME: cagney/2003-03-01: Once all architectures implement
+ gdbarch_register_type(), this entire function can go away. It
+ is made obsolete by register_size(). */
+ return TYPE_LENGTH (DEPRECATED_REGISTER_VIRTUAL_TYPE (regnum)); /* OK */
+}
+
+/* Assume all registers are adjacent. */
+
+int
+generic_register_byte (int regnum)
+{
+ int byte;
+ int i;
+ gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS);
+ byte = 0;
+ for (i = 0; i < regnum; i++)
+ {
+ byte += generic_register_size (i);
+ }
+ return byte;
+}
+
+
+int
+legacy_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+#if !defined (IN_SIGTRAMP)
+ if (SIGTRAMP_START_P ())
+ return (pc) >= SIGTRAMP_START (pc) && (pc) < SIGTRAMP_END (pc);
+ else
+ return name && strcmp ("_sigtramp", name) == 0;
+#else
+ return IN_SIGTRAMP (pc, name);
+#endif
+}
+
+int
+legacy_convert_register_p (int regnum, struct type *type)
+{
+ return (DEPRECATED_REGISTER_CONVERTIBLE_P ()
+ && DEPRECATED_REGISTER_CONVERTIBLE (regnum));
+}
+
+void
+legacy_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, void *to)
+{
+ char from[MAX_REGISTER_SIZE];
+ get_frame_register (frame, regnum, from);
+ DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (regnum, type, from, to);
+}
+
+void
+legacy_value_to_register (struct frame_info *frame, int regnum,
+ struct type *type, const void *tmp)
+{
+ char to[MAX_REGISTER_SIZE];
+ char *from = alloca (TYPE_LENGTH (type));
+ memcpy (from, from, TYPE_LENGTH (type));
+ DEPRECATED_REGISTER_CONVERT_TO_RAW (type, regnum, from, to);
+ put_frame_register (frame, regnum, to);
+}
+
+int
+default_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
+{
+ if (DEPRECATED_REG_STRUCT_HAS_ADDR_P ()
+ && DEPRECATED_REG_STRUCT_HAS_ADDR (processing_gcc_compilation, type))
+ {
+ CHECK_TYPEDEF (type);
+
+ return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION
+ || TYPE_CODE (type) == TYPE_CODE_SET
+ || TYPE_CODE (type) == TYPE_CODE_BITSTRING);
+ }
+
+ return 0;
+}
+
+
+/* Functions to manipulate the endianness of the target. */
+
+/* ``target_byte_order'' is only used when non- multi-arch.
+ Multi-arch targets obtain the current byte order using the
+ TARGET_BYTE_ORDER gdbarch method.
+
+ The choice of initial value is entirely arbitrary. During startup,
+ the function initialize_current_architecture() updates this value
+ based on default byte-order information extracted from BFD. */
+static int target_byte_order = BFD_ENDIAN_BIG;
+static int target_byte_order_auto = 1;
+
+enum bfd_endian
+selected_byte_order (void)
+{
+ if (target_byte_order_auto)
+ return BFD_ENDIAN_UNKNOWN;
+ else
+ return target_byte_order;
+}
+
+static const char endian_big[] = "big";
+static const char endian_little[] = "little";
+static const char endian_auto[] = "auto";
+static const char *endian_enum[] =
+{
+ endian_big,
+ endian_little,
+ endian_auto,
+ NULL,
+};
+static const char *set_endian_string;
+
+/* Called by ``show endian''. */
+
+static void
+show_endian (char *args, int from_tty)
+{
+ if (target_byte_order_auto)
+ printf_unfiltered ("The target endianness is set automatically (currently %s endian)\n",
+ (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "big" : "little"));
+ else
+ printf_unfiltered ("The target is assumed to be %s endian\n",
+ (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "big" : "little"));
+}
+
+static void
+set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c)
+{
+ if (set_endian_string == endian_auto)
+ {
+ target_byte_order_auto = 1;
+ }
+ else if (set_endian_string == endian_little)
+ {
+ struct gdbarch_info info;
+ target_byte_order_auto = 0;
+ gdbarch_info_init (&info);
+ info.byte_order = BFD_ENDIAN_LITTLE;
+ if (! gdbarch_update_p (info))
+ printf_unfiltered ("Little endian target not supported by GDB\n");
+ }
+ else if (set_endian_string == endian_big)
+ {
+ struct gdbarch_info info;
+ target_byte_order_auto = 0;
+ gdbarch_info_init (&info);
+ info.byte_order = BFD_ENDIAN_BIG;
+ if (! gdbarch_update_p (info))
+ printf_unfiltered ("Big endian target not supported by GDB\n");
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ "set_endian: bad value");
+ show_endian (NULL, from_tty);
+}
+
+/* Functions to manipulate the architecture of the target */
+
+enum set_arch { set_arch_auto, set_arch_manual };
+
+static int target_architecture_auto = 1;
+
+static const char *set_architecture_string;
+
+const char *
+selected_architecture_name (void)
+{
+ if (target_architecture_auto)
+ return NULL;
+ else
+ return set_architecture_string;
+}
+
+/* Called if the user enters ``show architecture'' without an
+ argument. */
+
+static void
+show_architecture (char *args, int from_tty)
+{
+ const char *arch;
+ arch = TARGET_ARCHITECTURE->printable_name;
+ if (target_architecture_auto)
+ printf_filtered ("The target architecture is set automatically (currently %s)\n", arch);
+ else
+ printf_filtered ("The target architecture is assumed to be %s\n", arch);
+}
+
+
+/* Called if the user enters ``set architecture'' with or without an
+ argument. */
+
+static void
+set_architecture (char *ignore_args, int from_tty, struct cmd_list_element *c)
+{
+ if (strcmp (set_architecture_string, "auto") == 0)
+ {
+ target_architecture_auto = 1;
+ }
+ else
+ {
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+ info.bfd_arch_info = bfd_scan_arch (set_architecture_string);
+ if (info.bfd_arch_info == NULL)
+ internal_error (__FILE__, __LINE__,
+ "set_architecture: bfd_scan_arch failed");
+ if (gdbarch_update_p (info))
+ target_architecture_auto = 0;
+ else
+ printf_unfiltered ("Architecture `%s' not recognized.\n",
+ set_architecture_string);
+ }
+ show_architecture (NULL, from_tty);
+}
+
+/* Try to select a global architecture that matches "info". Return
+ non-zero if the attempt succeds. */
+int
+gdbarch_update_p (struct gdbarch_info info)
+{
+ struct gdbarch *new_gdbarch = gdbarch_find_by_info (info);
+
+ /* If there no architecture by that name, reject the request. */
+ if (new_gdbarch == NULL)
+ {
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
+ "Architecture not found\n");
+ return 0;
+ }
+
+ /* If it is the same old architecture, accept the request (but don't
+ swap anything). */
+ if (new_gdbarch == current_gdbarch)
+ {
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
+ "Architecture 0x%08lx (%s) unchanged\n",
+ (long) new_gdbarch,
+ gdbarch_bfd_arch_info (new_gdbarch)->printable_name);
+ return 1;
+ }
+
+ /* It's a new architecture, swap it in. */
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
+ "New architecture 0x%08lx (%s) selected\n",
+ (long) new_gdbarch,
+ gdbarch_bfd_arch_info (new_gdbarch)->printable_name);
+ deprecated_current_gdbarch_select_hack (new_gdbarch);
+
+ return 1;
+}
+
+/* Return the architecture for ABFD. If no suitable architecture
+ could be find, return NULL. */
+
+struct gdbarch *
+gdbarch_from_bfd (bfd *abfd)
+{
+ struct gdbarch *old_gdbarch = current_gdbarch;
+ struct gdbarch *new_gdbarch;
+ struct gdbarch_info info;
+
+ gdbarch_info_init (&info);
+ info.abfd = abfd;
+ return gdbarch_find_by_info (info);
+}
+
+/* Set the dynamic target-system-dependent parameters (architecture,
+ byte-order) using information found in the BFD */
+
+void
+set_gdbarch_from_file (bfd *abfd)
+{
+ struct gdbarch *gdbarch;
+
+ gdbarch = gdbarch_from_bfd (abfd);
+ if (gdbarch == NULL)
+ error ("Architecture of file not recognized.\n");
+ deprecated_current_gdbarch_select_hack (gdbarch);
+}
+
+/* Initialize the current architecture. Update the ``set
+ architecture'' command so that it specifies a list of valid
+ architectures. */
+
+#ifdef DEFAULT_BFD_ARCH
+extern const bfd_arch_info_type DEFAULT_BFD_ARCH;
+static const bfd_arch_info_type *default_bfd_arch = &DEFAULT_BFD_ARCH;
+#else
+static const bfd_arch_info_type *default_bfd_arch;
+#endif
+
+#ifdef DEFAULT_BFD_VEC
+extern const bfd_target DEFAULT_BFD_VEC;
+static const bfd_target *default_bfd_vec = &DEFAULT_BFD_VEC;
+#else
+static const bfd_target *default_bfd_vec;
+#endif
+
+void
+initialize_current_architecture (void)
+{
+ const char **arches = gdbarch_printable_names ();
+
+ /* determine a default architecture and byte order. */
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+
+ /* Find a default architecture. */
+ if (info.bfd_arch_info == NULL
+ && default_bfd_arch != NULL)
+ info.bfd_arch_info = default_bfd_arch;
+ if (info.bfd_arch_info == NULL)
+ {
+ /* Choose the architecture by taking the first one
+ alphabetically. */
+ const char *chosen = arches[0];
+ const char **arch;
+ for (arch = arches; *arch != NULL; arch++)
+ {
+ if (strcmp (*arch, chosen) < 0)
+ chosen = *arch;
+ }
+ if (chosen == NULL)
+ internal_error (__FILE__, __LINE__,
+ "initialize_current_architecture: No arch");
+ info.bfd_arch_info = bfd_scan_arch (chosen);
+ if (info.bfd_arch_info == NULL)
+ internal_error (__FILE__, __LINE__,
+ "initialize_current_architecture: Arch not found");
+ }
+
+ /* Take several guesses at a byte order. */
+ if (info.byte_order == BFD_ENDIAN_UNKNOWN
+ && default_bfd_vec != NULL)
+ {
+ /* Extract BFD's default vector's byte order. */
+ switch (default_bfd_vec->byteorder)
+ {
+ case BFD_ENDIAN_BIG:
+ info.byte_order = BFD_ENDIAN_BIG;
+ break;
+ case BFD_ENDIAN_LITTLE:
+ info.byte_order = BFD_ENDIAN_LITTLE;
+ break;
+ default:
+ break;
+ }
+ }
+ if (info.byte_order == BFD_ENDIAN_UNKNOWN)
+ {
+ /* look for ``*el-*'' in the target name. */
+ const char *chp;
+ chp = strchr (target_name, '-');
+ if (chp != NULL
+ && chp - 2 >= target_name
+ && strncmp (chp - 2, "el", 2) == 0)
+ info.byte_order = BFD_ENDIAN_LITTLE;
+ }
+ if (info.byte_order == BFD_ENDIAN_UNKNOWN)
+ {
+ /* Wire it to big-endian!!! */
+ info.byte_order = BFD_ENDIAN_BIG;
+ }
+
+ if (! gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__,
+ "initialize_current_architecture: Selection of initial architecture failed");
+
+ /* Create the ``set architecture'' command appending ``auto'' to the
+ list of architectures. */
+ {
+ struct cmd_list_element *c;
+ /* Append ``auto''. */
+ int nr;
+ for (nr = 0; arches[nr] != NULL; nr++);
+ arches = xrealloc (arches, sizeof (char*) * (nr + 2));
+ arches[nr + 0] = "auto";
+ arches[nr + 1] = NULL;
+ /* FIXME: add_set_enum_cmd() uses an array of ``char *'' instead
+ of ``const char *''. We just happen to know that the casts are
+ safe. */
+ c = add_set_enum_cmd ("architecture", class_support,
+ arches, &set_architecture_string,
+ "Set architecture of target.",
+ &setlist);
+ set_cmd_sfunc (c, set_architecture);
+ add_alias_cmd ("processor", "architecture", class_support, 1, &setlist);
+ /* Don't use set_from_show - need to print both auto/manual and
+ current setting. */
+ add_cmd ("architecture", class_support, show_architecture,
+ "Show the current target architecture", &showlist);
+ }
+}
+
+
+/* Initialize a gdbarch info to values that will be automatically
+ overridden. Note: Originally, this ``struct info'' was initialized
+ using memset(0). Unfortunately, that ran into problems, namely
+ BFD_ENDIAN_BIG is zero. An explicit initialization function that
+ can explicitly set each field to a well defined value is used. */
+
+void
+gdbarch_info_init (struct gdbarch_info *info)
+{
+ memset (info, 0, sizeof (struct gdbarch_info));
+ info->byte_order = BFD_ENDIAN_UNKNOWN;
+ info->osabi = GDB_OSABI_UNINITIALIZED;
+}
+
+/* Similar to init, but this time fill in the blanks. Information is
+ obtained from the specified architecture, global "set ..." options,
+ and explicitly initialized INFO fields. */
+
+void
+gdbarch_info_fill (struct gdbarch *gdbarch, struct gdbarch_info *info)
+{
+ /* "(gdb) set architecture ...". */
+ if (info->bfd_arch_info == NULL
+ && !target_architecture_auto
+ && gdbarch != NULL)
+ info->bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
+ if (info->bfd_arch_info == NULL
+ && info->abfd != NULL
+ && bfd_get_arch (info->abfd) != bfd_arch_unknown
+ && bfd_get_arch (info->abfd) != bfd_arch_obscure)
+ info->bfd_arch_info = bfd_get_arch_info (info->abfd);
+ if (info->bfd_arch_info == NULL
+ && gdbarch != NULL)
+ info->bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
+
+ /* "(gdb) set byte-order ...". */
+ if (info->byte_order == BFD_ENDIAN_UNKNOWN
+ && !target_byte_order_auto
+ && gdbarch != NULL)
+ info->byte_order = gdbarch_byte_order (gdbarch);
+ /* From the INFO struct. */
+ if (info->byte_order == BFD_ENDIAN_UNKNOWN
+ && info->abfd != NULL)
+ info->byte_order = (bfd_big_endian (info->abfd) ? BFD_ENDIAN_BIG
+ : bfd_little_endian (info->abfd) ? BFD_ENDIAN_LITTLE
+ : BFD_ENDIAN_UNKNOWN);
+ /* From the current target. */
+ if (info->byte_order == BFD_ENDIAN_UNKNOWN
+ && gdbarch != NULL)
+ info->byte_order = gdbarch_byte_order (gdbarch);
+
+ /* "(gdb) set osabi ...". Handled by gdbarch_lookup_osabi. */
+ if (info->osabi == GDB_OSABI_UNINITIALIZED)
+ info->osabi = gdbarch_lookup_osabi (info->abfd);
+ if (info->osabi == GDB_OSABI_UNINITIALIZED
+ && gdbarch != NULL)
+ info->osabi = gdbarch_osabi (gdbarch);
+
+ /* Must have at least filled in the architecture. */
+ gdb_assert (info->bfd_arch_info != NULL);
+}
+
+/* */
+
+extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
+
+void
+_initialize_gdbarch_utils (void)
+{
+ struct cmd_list_element *c;
+ c = add_set_enum_cmd ("endian", class_support,
+ endian_enum, &set_endian_string,
+ "Set endianness of target.",
+ &setlist);
+ set_cmd_sfunc (c, set_endian);
+ /* Don't use set_from_show - need to print both auto/manual and
+ current setting. */
+ add_cmd ("endian", class_support, show_endian,
+ "Show the current byte-order", &showlist);
+}
diff --git a/contrib/gdb/gdb/arch-utils.h b/contrib/gdb/gdb/arch-utils.h
new file mode 100644
index 0000000..0f7a23d
--- /dev/null
+++ b/contrib/gdb/gdb/arch-utils.h
@@ -0,0 +1,167 @@
+/* Dynamic architecture support for GDB, the GNU debugger.
+
+ Copyright 1998, 1999, 2000, 2002, 2003 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDBARCH_UTILS_H
+#define GDBARCH_UTILS_H
+
+struct gdbarch;
+struct frame_info;
+struct minimal_symbol;
+struct type;
+struct gdbarch_info;
+
+/* gdbarch trace variable */
+extern int gdbarch_debug;
+
+/* Implementation of extract return value that grubs around in the
+ register cache. */
+extern gdbarch_extract_return_value_ftype legacy_extract_return_value;
+
+/* Implementation of store return value that grubs the register cache. */
+extern gdbarch_store_return_value_ftype legacy_store_return_value;
+
+/* To return any structure or union type by value, store it at the
+ address passed as an invisible first argument to the function. */
+extern gdbarch_use_struct_convention_ftype always_use_struct_convention;
+
+/* Only structures, unions, and arrays are returned using the struct
+ convention. Note that arrays are never passed by value in the C
+ language family, so that case is irrelevant for C. */
+extern gdbarch_return_value_on_stack_ftype generic_return_value_on_stack_not;
+
+/* Backward compatible call_dummy_words. */
+extern LONGEST legacy_call_dummy_words[];
+extern int legacy_sizeof_call_dummy_words;
+
+/* Typical remote_translate_xfer_address */
+extern gdbarch_remote_translate_xfer_address_ftype generic_remote_translate_xfer_address;
+
+/* The only possible cases for inner_than. */
+extern int core_addr_lessthan (CORE_ADDR lhs, CORE_ADDR rhs);
+extern int core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs);
+
+/* Floating point values. */
+extern const struct floatformat *default_float_format (struct gdbarch *gdbarch);
+extern const struct floatformat *default_double_format (struct gdbarch *gdbarch);
+
+/* Identity functions on a CORE_ADDR. Just return the "addr". */
+
+extern CORE_ADDR core_addr_identity (CORE_ADDR addr);
+extern gdbarch_convert_from_func_ptr_addr_ftype convert_from_func_ptr_addr_identity;
+
+/* No-op conversion of reg to regnum. */
+
+extern int no_op_reg_to_regnum (int reg);
+
+/* Versions of init_frame_pc(). Do nothing; do the default. */
+
+extern CORE_ADDR deprecated_init_frame_pc_default (int fromleaf, struct frame_info *prev);
+
+/* Do nothing version of elf_make_msymbol_special. */
+
+void default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym);
+
+/* Do nothing version of coff_make_msymbol_special. */
+
+void default_coff_make_msymbol_special (int val, struct minimal_symbol *msym);
+
+/* Version of cannot_fetch_register() / cannot_store_register() that
+ always fails. */
+
+int cannot_register_not (int regnum);
+
+/* Legacy version of target_virtual_frame_pointer(). Assumes that
+ there is an DEPRECATED_FP_REGNUM and that it is the same, cooked or
+ raw. */
+
+extern gdbarch_virtual_frame_pointer_ftype legacy_virtual_frame_pointer;
+
+extern CORE_ADDR generic_skip_trampoline_code (CORE_ADDR pc);
+
+extern CORE_ADDR generic_skip_solib_resolver (struct gdbarch *gdbarch,
+ CORE_ADDR pc);
+
+extern int generic_in_solib_call_trampoline (CORE_ADDR pc, char *name);
+
+extern int generic_in_solib_return_trampoline (CORE_ADDR pc, char *name);
+
+extern int generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc);
+
+/* Assume that the world is sane, a registers raw and virtual size
+ both match its type. */
+
+extern int generic_register_size (int regnum);
+
+/* Assume that the world is sane, the registers are all adjacent. */
+extern int generic_register_byte (int regnum);
+
+/* Prop up old targets that use various IN_SIGTRAMP() macros. */
+extern int legacy_pc_in_sigtramp (CORE_ADDR pc, char *name);
+
+/* The orginal register_convert*() functions were overloaded. They
+ were used to both: convert between virtual and raw register formats
+ (something that is discouraged); and to convert a register to the
+ type of a corresponding variable. These legacy functions preserve
+ that overloaded behavour in existing targets. */
+extern int legacy_convert_register_p (int regnum, struct type *type);
+extern void legacy_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, void *to);
+extern void legacy_value_to_register (struct frame_info *frame, int regnum,
+ struct type *type, const void *from);
+
+extern int default_stabs_argument_has_addr (struct gdbarch *gdbarch,
+ struct type *type);
+
+/* For compatibility with older architectures, returns
+ (LEGACY_SIM_REGNO_IGNORE) when the register doesn't have a valid
+ name. */
+
+extern int legacy_register_sim_regno (int regnum);
+
+/* Return the selected byte order, or BFD_ENDIAN_UNKNOWN if no byte
+ order was explicitly selected. */
+extern enum bfd_endian selected_byte_order (void);
+
+/* Return the selected architecture's name, or NULL if no architecture
+ was explicitly selected. */
+extern const char *selected_architecture_name (void);
+
+/* Initialize a ``struct info''. Can't use memset(0) since some
+ default values are not zero. "fill" takes all available
+ information and fills in any unspecified fields. */
+
+extern void gdbarch_info_init (struct gdbarch_info *info);
+extern void gdbarch_info_fill (struct gdbarch *gdbarch,
+ struct gdbarch_info *info);
+
+/* Similar to init, but this time fill in the blanks. Information is
+ obtained from the specified architecture, global "set ..." options,
+ and explicitly initialized INFO fields. */
+extern void gdbarch_info_fill (struct gdbarch *gdbarch,
+ struct gdbarch_info *info);
+
+/* Return the architecture for ABFD. If no suitable architecture
+ could be find, return NULL. */
+
+extern struct gdbarch *gdbarch_from_bfd (bfd *abfd);
+
+#endif
diff --git a/contrib/gdb/gdb/arm-tdep.c b/contrib/gdb/gdb/arm-tdep.c
new file mode 100644
index 0000000..128219f
--- /dev/null
+++ b/contrib/gdb/gdb/arm-tdep.c
@@ -0,0 +1,2983 @@
+/* Common target dependent code for GDB on ARM systems.
+ Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h> /* XXX for isupper () */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
+#include "dis-asm.h" /* For register styles. */
+#include "regcache.h"
+#include "doublest.h"
+#include "value.h"
+#include "arch-utils.h"
+#include "osabi.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+
+#include "arm-tdep.h"
+#include "gdb/sim-arm.h"
+
+#include "elf-bfd.h"
+#include "coff/internal.h"
+#include "elf/arm.h"
+
+#include "gdb_assert.h"
+
+static int arm_debug;
+
+/* Each OS has a different mechanism for accessing the various
+ registers stored in the sigcontext structure.
+
+ SIGCONTEXT_REGISTER_ADDRESS should be defined to the name (or
+ function pointer) which may be used to determine the addresses
+ of the various saved registers in the sigcontext structure.
+
+ For the ARM target, there are three parameters to this function.
+ The first is the pc value of the frame under consideration, the
+ second the stack pointer of this frame, and the last is the
+ register number to fetch.
+
+ If the tm.h file does not define this macro, then it's assumed that
+ no mechanism is needed and we define SIGCONTEXT_REGISTER_ADDRESS to
+ be 0.
+
+ When it comes time to multi-arching this code, see the identically
+ named machinery in ia64-tdep.c for an example of how it could be
+ done. It should not be necessary to modify the code below where
+ this macro is used. */
+
+#ifdef SIGCONTEXT_REGISTER_ADDRESS
+#ifndef SIGCONTEXT_REGISTER_ADDRESS_P
+#define SIGCONTEXT_REGISTER_ADDRESS_P() 1
+#endif
+#else
+#define SIGCONTEXT_REGISTER_ADDRESS(SP,PC,REG) 0
+#define SIGCONTEXT_REGISTER_ADDRESS_P() 0
+#endif
+
+/* Macros for setting and testing a bit in a minimal symbol that marks
+ it as Thumb function. The MSB of the minimal symbol's "info" field
+ is used for this purpose.
+
+ MSYMBOL_SET_SPECIAL Actually sets the "special" bit.
+ MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. */
+
+#define MSYMBOL_SET_SPECIAL(msym) \
+ MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) \
+ | 0x80000000)
+
+#define MSYMBOL_IS_SPECIAL(msym) \
+ (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
+
+/* The list of available "set arm ..." and "show arm ..." commands. */
+static struct cmd_list_element *setarmcmdlist = NULL;
+static struct cmd_list_element *showarmcmdlist = NULL;
+
+/* The type of floating-point to use. Keep this in sync with enum
+ arm_float_model, and the help string in _initialize_arm_tdep. */
+static const char *fp_model_strings[] =
+{
+ "auto",
+ "softfpa",
+ "fpa",
+ "softvfp",
+ "vfp"
+};
+
+/* A variable that can be configured by the user. */
+static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
+static const char *current_fp_model = "auto";
+
+/* Number of different reg name sets (options). */
+static int num_disassembly_options;
+
+/* We have more registers than the disassembler as gdb can print the value
+ of special registers as well.
+ The general register names are overwritten by whatever is being used by
+ the disassembler at the moment. We also adjust the case of cpsr and fps. */
+
+/* Initial value: Register names used in ARM's ISA documentation. */
+static char * arm_register_name_strings[] =
+{"r0", "r1", "r2", "r3", /* 0 1 2 3 */
+ "r4", "r5", "r6", "r7", /* 4 5 6 7 */
+ "r8", "r9", "r10", "r11", /* 8 9 10 11 */
+ "r12", "sp", "lr", "pc", /* 12 13 14 15 */
+ "f0", "f1", "f2", "f3", /* 16 17 18 19 */
+ "f4", "f5", "f6", "f7", /* 20 21 22 23 */
+ "fps", "cpsr" }; /* 24 25 */
+static char **arm_register_names = arm_register_name_strings;
+
+/* Valid register name styles. */
+static const char **valid_disassembly_styles;
+
+/* Disassembly style to use. Default to "std" register names. */
+static const char *disassembly_style;
+/* Index to that option in the opcodes table. */
+static int current_option;
+
+/* This is used to keep the bfd arch_info in sync with the disassembly
+ style. */
+static void set_disassembly_style_sfunc(char *, int,
+ struct cmd_list_element *);
+static void set_disassembly_style (void);
+
+static void convert_from_extended (const struct floatformat *, const void *,
+ void *);
+static void convert_to_extended (const struct floatformat *, void *,
+ const void *);
+
+struct arm_prologue_cache
+{
+ /* The stack pointer at the time this frame was created; i.e. the
+ caller's stack pointer when this function was called. It is used
+ to identify this frame. */
+ CORE_ADDR prev_sp;
+
+ /* The frame base for this frame is just prev_sp + frame offset -
+ frame size. FRAMESIZE is the size of this stack frame, and
+ FRAMEOFFSET if the initial offset from the stack pointer (this
+ frame's stack pointer, not PREV_SP) to the frame base. */
+
+ int framesize;
+ int frameoffset;
+
+ /* The register used to hold the frame pointer for this frame. */
+ int framereg;
+
+ /* Saved register offsets. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Addresses for calling Thumb functions have the bit 0 set.
+ Here are some macros to test, set, or clear bit 0 of addresses. */
+#define IS_THUMB_ADDR(addr) ((addr) & 1)
+#define MAKE_THUMB_ADDR(addr) ((addr) | 1)
+#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
+
+/* Set to true if the 32-bit mode is in use. */
+
+int arm_apcs_32 = 1;
+
+/* Determine if the program counter specified in MEMADDR is in a Thumb
+ function. */
+
+int
+arm_pc_is_thumb (CORE_ADDR memaddr)
+{
+ struct minimal_symbol *sym;
+
+ /* If bit 0 of the address is set, assume this is a Thumb address. */
+ if (IS_THUMB_ADDR (memaddr))
+ return 1;
+
+ /* Thumb functions have a "special" bit set in minimal symbols. */
+ sym = lookup_minimal_symbol_by_pc (memaddr);
+ if (sym)
+ {
+ return (MSYMBOL_IS_SPECIAL (sym));
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/* Remove useless bits from addresses in a running program. */
+static CORE_ADDR
+arm_addr_bits_remove (CORE_ADDR val)
+{
+ if (arm_apcs_32)
+ return (val & (arm_pc_is_thumb (val) ? 0xfffffffe : 0xfffffffc));
+ else
+ return (val & 0x03fffffc);
+}
+
+/* When reading symbols, we need to zap the low bit of the address,
+ which may be set to 1 for Thumb functions. */
+static CORE_ADDR
+arm_smash_text_address (CORE_ADDR val)
+{
+ return val & ~1;
+}
+
+/* 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. */
+
+static CORE_ADDR
+arm_saved_pc_after_call (struct frame_info *frame)
+{
+ return ADDR_BITS_REMOVE (read_register (ARM_LR_REGNUM));
+}
+
+/* Determine whether the function invocation represented by FI has a
+ frame on the stack associated with it. If it does return zero,
+ otherwise return 1. */
+
+static int
+arm_frameless_function_invocation (struct frame_info *fi)
+{
+ CORE_ADDR func_start, after_prologue;
+ int frameless;
+
+ /* Sometimes we have functions that do a little setup (like saving the
+ vN registers with the stmdb instruction, but DO NOT set up a frame.
+ The symbol table will report this as a prologue. However, it is
+ important not to try to parse these partial frames as frames, or we
+ will get really confused.
+
+ So I will demand 3 instructions between the start & end of the
+ prologue before I call it a real prologue, i.e. at least
+ mov ip, sp,
+ stmdb sp!, {}
+ sub sp, ip, #4. */
+
+ func_start = (get_frame_func (fi) + FUNCTION_START_OFFSET);
+ after_prologue = SKIP_PROLOGUE (func_start);
+
+ /* There are some frameless functions whose first two instructions
+ follow the standard APCS form, in which case after_prologue will
+ be func_start + 8. */
+
+ frameless = (after_prologue < func_start + 12);
+ return frameless;
+}
+
+/* A typical Thumb prologue looks like this:
+ push {r7, lr}
+ add sp, sp, #-28
+ add r7, sp, #12
+ Sometimes the latter instruction may be replaced by:
+ mov r7, sp
+
+ or like this:
+ push {r7, lr}
+ mov r7, sp
+ sub sp, #12
+
+ or, on tpcs, like this:
+ sub sp,#16
+ push {r7, lr}
+ (many instructions)
+ mov r7, sp
+ sub sp, #12
+
+ There is always one instruction of three classes:
+ 1 - push
+ 2 - setting of r7
+ 3 - adjusting of sp
+
+ When we have found at least one of each class we are done with the prolog.
+ Note that the "sub sp, #NN" before the push does not count.
+ */
+
+static CORE_ADDR
+thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
+{
+ CORE_ADDR current_pc;
+ /* findmask:
+ bit 0 - push { rlist }
+ bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7)
+ bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp)
+ */
+ int findmask = 0;
+
+ for (current_pc = pc;
+ current_pc + 2 < func_end && current_pc < pc + 40;
+ current_pc += 2)
+ {
+ unsigned short insn = read_memory_unsigned_integer (current_pc, 2);
+
+ if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
+ {
+ findmask |= 1; /* push found */
+ }
+ else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
+ sub sp, #simm */
+ {
+ if ((findmask & 1) == 0) /* before push ? */
+ continue;
+ else
+ findmask |= 4; /* add/sub sp found */
+ }
+ else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
+ {
+ findmask |= 2; /* setting of r7 found */
+ }
+ else if (insn == 0x466f) /* mov r7, sp */
+ {
+ findmask |= 2; /* setting of r7 found */
+ }
+ else if (findmask == (4+2+1))
+ {
+ /* We have found one of each type of prologue instruction */
+ break;
+ }
+ else
+ /* Something in the prolog that we don't care about or some
+ instruction from outside the prolog scheduled here for
+ optimization. */
+ continue;
+ }
+
+ return current_pc;
+}
+
+/* Advance the PC across any function entry prologue instructions to
+ reach some "real" code.
+
+ The 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 insn */
+
+static CORE_ADDR
+arm_skip_prologue (CORE_ADDR pc)
+{
+ unsigned long inst;
+ CORE_ADDR skip_pc;
+ CORE_ADDR func_addr, func_end = 0;
+ char *func_name;
+ struct symtab_and_line sal;
+
+ /* If we're in a dummy frame, don't even try to skip the prologue. */
+ if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+ return pc;
+
+ /* See what the symbol table says. */
+
+ if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+ {
+ struct symbol *sym;
+
+ /* Found a function. */
+ sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL);
+ if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
+ {
+ /* Don't use this trick for assembly source files. */
+ sal = find_pc_line (func_addr, 0);
+ if ((sal.line != 0) && (sal.end < func_end))
+ return sal.end;
+ }
+ }
+
+ /* Check if this is Thumb code. */
+ if (arm_pc_is_thumb (pc))
+ return thumb_skip_prologue (pc, func_end);
+
+ /* Can't find the prologue end in the symbol table, try it the hard way
+ by disassembling the instructions. */
+
+ /* Like arm_scan_prologue, stop no later than pc + 64. */
+ if (func_end == 0 || func_end > pc + 64)
+ func_end = pc + 64;
+
+ for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
+ {
+ inst = read_memory_integer (skip_pc, 4);
+
+ /* "mov ip, sp" is no longer a required part of the prologue. */
+ if (inst == 0xe1a0c00d) /* mov ip, sp */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+ continue;
+
+ /* Some prologues begin with "str lr, [sp, #-4]!". */
+ if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
+ continue;
+
+ if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */
+ continue;
+
+ if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */
+ continue;
+
+ /* Any insns after this point may float into the code, if it makes
+ for better instruction scheduling, so we skip them only if we
+ find them, but still consider the function to be frame-ful. */
+
+ /* We may have either one sfmfd instruction here, or several stfe
+ insns, depending on the version of floating point code we
+ support. */
+ if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */
+ continue;
+
+ if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */
+ continue;
+
+ if ((inst & 0xffffc000) == 0xe54b0000 || /* strb r(0123),[r11,#-nn] */
+ (inst & 0xffffc0f0) == 0xe14b00b0 || /* strh r(0123),[r11,#-nn] */
+ (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */
+ continue;
+
+ if ((inst & 0xffffc000) == 0xe5cd0000 || /* strb r(0123),[sp,#nn] */
+ (inst & 0xffffc0f0) == 0xe1cd00b0 || /* strh r(0123),[sp,#nn] */
+ (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */
+ continue;
+
+ /* Un-recognized instruction; stop scanning. */
+ break;
+ }
+
+ return skip_pc; /* End of prologue */
+}
+
+/* *INDENT-OFF* */
+/* Function: thumb_scan_prologue (helper function for arm_scan_prologue)
+ This function decodes a Thumb function prologue to determine:
+ 1) the size of the stack frame
+ 2) which registers are saved on it
+ 3) the offsets of saved regs
+ 4) the offset from the stack pointer to the frame pointer
+
+ A typical Thumb function prologue would create this stack frame
+ (offsets relative to FP)
+ old SP -> 24 stack parameters
+ 20 LR
+ 16 R7
+ R7 -> 0 local variables (16 bytes)
+ SP -> -12 additional stack space (12 bytes)
+ The frame size would thus be 36 bytes, and the frame offset would be
+ 12 bytes. The frame register is R7.
+
+ The comments for thumb_skip_prolog() describe the algorithm we use
+ to detect the end of the prolog. */
+/* *INDENT-ON* */
+
+static void
+thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
+{
+ CORE_ADDR prologue_start;
+ CORE_ADDR prologue_end;
+ CORE_ADDR current_pc;
+ /* Which register has been copied to register n? */
+ int saved_reg[16];
+ /* findmask:
+ bit 0 - push { rlist }
+ bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7)
+ bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp)
+ */
+ int findmask = 0;
+ int i;
+
+ if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
+ {
+ struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+
+ if (sal.line == 0) /* no line info, use current PC */
+ prologue_end = prev_pc;
+ else if (sal.end < prologue_end) /* next line begins after fn end */
+ prologue_end = sal.end; /* (probably means no prologue) */
+ }
+ else
+ /* We're in the boondocks: allow for
+ 16 pushes, an add, and "mv fp,sp". */
+ prologue_end = prologue_start + 40;
+
+ prologue_end = min (prologue_end, prev_pc);
+
+ /* Initialize the saved register map. When register H is copied to
+ register L, we will put H in saved_reg[L]. */
+ for (i = 0; i < 16; i++)
+ saved_reg[i] = i;
+
+ /* Search the prologue looking for instructions that set up the
+ frame pointer, adjust the stack pointer, and save registers.
+ Do this until all basic prolog instructions are found. */
+
+ cache->framesize = 0;
+ for (current_pc = prologue_start;
+ (current_pc < prologue_end) && ((findmask & 7) != 7);
+ current_pc += 2)
+ {
+ unsigned short insn;
+ int regno;
+ int offset;
+
+ insn = read_memory_unsigned_integer (current_pc, 2);
+
+ if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
+ {
+ int mask;
+ findmask |= 1; /* push found */
+ /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says
+ whether to save LR (R14). */
+ mask = (insn & 0xff) | ((insn & 0x100) << 6);
+
+ /* Calculate offsets of saved R0-R7 and LR. */
+ for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
+ if (mask & (1 << regno))
+ {
+ cache->framesize += 4;
+ cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
+ /* Reset saved register map. */
+ saved_reg[regno] = regno;
+ }
+ }
+ else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
+ sub sp, #simm */
+ {
+ if ((findmask & 1) == 0) /* before push? */
+ continue;
+ else
+ findmask |= 4; /* add/sub sp found */
+
+ offset = (insn & 0x7f) << 2; /* get scaled offset */
+ if (insn & 0x80) /* is it signed? (==subtracting) */
+ {
+ cache->frameoffset += offset;
+ offset = -offset;
+ }
+ cache->framesize -= offset;
+ }
+ else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
+ {
+ findmask |= 2; /* setting of r7 found */
+ cache->framereg = THUMB_FP_REGNUM;
+ /* get scaled offset */
+ cache->frameoffset = (insn & 0xff) << 2;
+ }
+ else if (insn == 0x466f) /* mov r7, sp */
+ {
+ findmask |= 2; /* setting of r7 found */
+ cache->framereg = THUMB_FP_REGNUM;
+ cache->frameoffset = 0;
+ saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM;
+ }
+ else if ((insn & 0xffc0) == 0x4640) /* mov r0-r7, r8-r15 */
+ {
+ int lo_reg = insn & 7; /* dest. register (r0-r7) */
+ int hi_reg = ((insn >> 3) & 7) + 8; /* source register (r8-15) */
+ saved_reg[lo_reg] = hi_reg; /* remember hi reg was saved */
+ }
+ else
+ /* Something in the prolog that we don't care about or some
+ instruction from outside the prolog scheduled here for
+ optimization. */
+ continue;
+ }
+}
+
+/* This function decodes an ARM function prologue to determine:
+ 1) the size of the stack frame
+ 2) which registers are saved on it
+ 3) the offsets of saved regs
+ 4) the offset from the stack pointer to the frame pointer
+ This information is stored in the "extra" fields of the frame_info.
+
+ There are two basic forms for the ARM prologue. The fixed argument
+ function call will look like:
+
+ mov ip, sp
+ stmfd sp!, {fp, ip, lr, pc}
+ sub fp, ip, #4
+ [sub sp, sp, #4]
+
+ Which would create this stack frame (offsets relative to FP):
+ IP -> 4 (caller's stack)
+ FP -> 0 PC (points to address of stmfd instruction + 8 in callee)
+ -4 LR (return address in caller)
+ -8 IP (copy of caller's SP)
+ -12 FP (caller's FP)
+ SP -> -28 Local variables
+
+ The frame size would thus be 32 bytes, and the frame offset would be
+ 28 bytes. The stmfd call can also save any of the vN registers it
+ plans to use, which increases the frame size accordingly.
+
+ Note: The stored PC is 8 off of the STMFD instruction that stored it
+ because the ARM Store instructions always store PC + 8 when you read
+ the PC register.
+
+ A variable argument function call will look like:
+
+ mov ip, sp
+ stmfd sp!, {a1, a2, a3, a4}
+ stmfd sp!, {fp, ip, lr, pc}
+ sub fp, ip, #20
+
+ Which would create this stack frame (offsets relative to FP):
+ IP -> 20 (caller's stack)
+ 16 A4
+ 12 A3
+ 8 A2
+ 4 A1
+ FP -> 0 PC (points to address of stmfd instruction + 8 in callee)
+ -4 LR (return address in caller)
+ -8 IP (copy of caller's SP)
+ -12 FP (caller's FP)
+ SP -> -28 Local variables
+
+ The frame size would thus be 48 bytes, and the frame offset would be
+ 28 bytes.
+
+ There is another potential complication, which is that the optimizer
+ will try to separate the store of fp in the "stmfd" instruction from
+ the "sub fp, ip, #NN" instruction. Almost anything can be there, so
+ we just key on the stmfd, and then scan for the "sub fp, ip, #NN"...
+
+ Also, note, the original version of the ARM toolchain claimed that there
+ should be an
+
+ instruction at the end of the prologue. I have never seen GCC produce
+ this, and the ARM docs don't mention it. We still test for it below in
+ case it happens...
+
+ */
+
+static void
+arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache)
+{
+ int regno, sp_offset, fp_offset, ip_offset;
+ CORE_ADDR prologue_start, prologue_end, current_pc;
+ CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
+
+ /* Assume there is no frame until proven otherwise. */
+ cache->framereg = ARM_SP_REGNUM;
+ cache->framesize = 0;
+ cache->frameoffset = 0;
+
+ /* Check for Thumb prologue. */
+ if (arm_pc_is_thumb (prev_pc))
+ {
+ thumb_scan_prologue (prev_pc, cache);
+ return;
+ }
+
+ /* Find the function prologue. If we can't find the function in
+ the symbol table, peek in the stack frame to find the PC. */
+ if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
+ {
+ /* One way to find the end of the prologue (which works well
+ for unoptimized code) is to do the following:
+
+ struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+
+ if (sal.line == 0)
+ prologue_end = prev_pc;
+ else if (sal.end < prologue_end)
+ prologue_end = sal.end;
+
+ This mechanism is very accurate so long as the optimizer
+ doesn't move any instructions from the function body into the
+ prologue. If this happens, sal.end will be the last
+ instruction in the first hunk of prologue code just before
+ the first instruction that the scheduler has moved from
+ the body to the prologue.
+
+ In order to make sure that we scan all of the prologue
+ instructions, we use a slightly less accurate mechanism which
+ may scan more than necessary. To help compensate for this
+ lack of accuracy, the prologue scanning loop below contains
+ several clauses which'll cause the loop to terminate early if
+ an implausible prologue instruction is encountered.
+
+ The expression
+
+ prologue_start + 64
+
+ is a suitable endpoint since it accounts for the largest
+ possible prologue plus up to five instructions inserted by
+ the scheduler. */
+
+ if (prologue_end > prologue_start + 64)
+ {
+ prologue_end = prologue_start + 64; /* See above. */
+ }
+ }
+ else
+ {
+ /* We have no symbol information. Our only option is to assume this
+ function has a standard stack frame and the normal frame register.
+ Then, we can find the value of our frame pointer on entrance to
+ the callee (or at the present moment if this is the innermost frame).
+ The value stored there should be the address of the stmfd + 8. */
+ CORE_ADDR frame_loc;
+ LONGEST return_value;
+
+ frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
+ if (!safe_read_memory_integer (frame_loc, 4, &return_value))
+ return;
+ else
+ {
+ prologue_start = ADDR_BITS_REMOVE (return_value) - 8;
+ prologue_end = prologue_start + 64; /* See above. */
+ }
+ }
+
+ if (prev_pc < prologue_end)
+ prologue_end = prev_pc;
+
+ /* Now search the prologue looking for instructions that set up the
+ frame pointer, adjust the stack pointer, and save registers.
+
+ Be careful, however, and if it doesn't look like a prologue,
+ don't try to scan it. If, for instance, a frameless function
+ begins with stmfd sp!, then we will tell ourselves there is
+ a frame, which will confuse stack traceback, as well as "finish"
+ and other operations that rely on a knowledge of the stack
+ traceback.
+
+ In the APCS, the prologue should start with "mov ip, sp" so
+ if we don't see this as the first insn, we will stop.
+
+ [Note: This doesn't seem to be true any longer, so it's now an
+ optional part of the prologue. - Kevin Buettner, 2001-11-20]
+
+ [Note further: The "mov ip,sp" only seems to be missing in
+ frameless functions at optimization level "-O2" or above,
+ in which case it is often (but not always) replaced by
+ "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */
+
+ sp_offset = fp_offset = ip_offset = 0;
+
+ for (current_pc = prologue_start;
+ current_pc < prologue_end;
+ current_pc += 4)
+ {
+ unsigned int insn = read_memory_unsigned_integer (current_pc, 4);
+
+ if (insn == 0xe1a0c00d) /* mov ip, sp */
+ {
+ ip_offset = 0;
+ continue;
+ }
+ else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ ip_offset = imm;
+ continue;
+ }
+ else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ ip_offset = -imm;
+ continue;
+ }
+ else if (insn == 0xe52de004) /* str lr, [sp, #-4]! */
+ {
+ sp_offset -= 4;
+ cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset;
+ continue;
+ }
+ else if ((insn & 0xffff0000) == 0xe92d0000)
+ /* stmfd sp!, {..., fp, ip, lr, pc}
+ or
+ stmfd sp!, {a1, a2, a3, a4} */
+ {
+ int mask = insn & 0xffff;
+
+ /* Calculate offsets of saved registers. */
+ for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
+ if (mask & (1 << regno))
+ {
+ sp_offset -= 4;
+ cache->saved_regs[regno].addr = sp_offset;
+ }
+ }
+ else if ((insn & 0xffffc000) == 0xe54b0000 || /* strb rx,[r11,#-n] */
+ (insn & 0xffffc0f0) == 0xe14b00b0 || /* strh rx,[r11,#-n] */
+ (insn & 0xffffc000) == 0xe50b0000) /* str rx,[r11,#-n] */
+ {
+ /* No need to add this to saved_regs -- it's just an arg reg. */
+ continue;
+ }
+ else if ((insn & 0xffffc000) == 0xe5cd0000 || /* strb rx,[sp,#n] */
+ (insn & 0xffffc0f0) == 0xe1cd00b0 || /* strh rx,[sp,#n] */
+ (insn & 0xffffc000) == 0xe58d0000) /* str rx,[sp,#n] */
+ {
+ /* No need to add this to saved_regs -- it's just an arg reg. */
+ continue;
+ }
+ else if ((insn & 0xfffff000) == 0xe24cb000) /* sub fp, ip #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ fp_offset = -imm + ip_offset;
+ cache->framereg = ARM_FP_REGNUM;
+ }
+ else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ sp_offset -= imm;
+ }
+ else if ((insn & 0xffff7fff) == 0xed6d0103) /* stfe f?, [sp, -#c]! */
+ {
+ sp_offset -= 12;
+ regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
+ cache->saved_regs[regno].addr = sp_offset;
+ }
+ else if ((insn & 0xffbf0fff) == 0xec2d0200) /* sfmfd f0, 4, [sp!] */
+ {
+ int n_saved_fp_regs;
+ unsigned int fp_start_reg, fp_bound_reg;
+
+ if ((insn & 0x800) == 0x800) /* N0 is set */
+ {
+ if ((insn & 0x40000) == 0x40000) /* N1 is set */
+ n_saved_fp_regs = 3;
+ else
+ n_saved_fp_regs = 1;
+ }
+ else
+ {
+ if ((insn & 0x40000) == 0x40000) /* N1 is set */
+ n_saved_fp_regs = 2;
+ else
+ n_saved_fp_regs = 4;
+ }
+
+ fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
+ fp_bound_reg = fp_start_reg + n_saved_fp_regs;
+ for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
+ {
+ sp_offset -= 12;
+ cache->saved_regs[fp_start_reg++].addr = sp_offset;
+ }
+ }
+ else if ((insn & 0xf0000000) != 0xe0000000)
+ break; /* Condition not true, exit early */
+ else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */
+ break; /* Don't scan past a block load */
+ else
+ /* The optimizer might shove anything into the prologue,
+ so we just skip what we don't recognize. */
+ continue;
+ }
+
+ /* The frame size is just the negative of the offset (from the
+ original SP) of the last thing thing we pushed on the stack.
+ The frame offset is [new FP] - [new SP]. */
+ cache->framesize = -sp_offset;
+ if (cache->framereg == ARM_FP_REGNUM)
+ cache->frameoffset = fp_offset - sp_offset;
+ else
+ cache->frameoffset = 0;
+}
+
+static struct arm_prologue_cache *
+arm_make_prologue_cache (struct frame_info *next_frame)
+{
+ int reg;
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_fp;
+
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ arm_scan_prologue (next_frame, cache);
+
+ unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
+ if (unwound_fp == 0)
+ return cache;
+
+ cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset;
+
+ /* Calculate actual addresses of saved registers using offsets
+ determined by arm_scan_prologue. */
+ for (reg = 0; reg < NUM_REGS; reg++)
+ if (trad_frame_addr_p (cache->saved_regs, reg))
+ cache->saved_regs[reg].addr += cache->prev_sp;
+
+ return cache;
+}
+
+/* Our frame ID for a normal frame is the current function's starting PC
+ and the caller's SP when we were called. */
+
+static void
+arm_prologue_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+ struct frame_id id;
+ CORE_ADDR func;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ func = frame_func_unwind (next_frame);
+
+ /* This is meant to halt the backtrace at "_start". Make sure we
+ don't halt it at a generic dummy frame. */
+ if (func <= LOWEST_PC)
+ return;
+
+ /* If we've hit a wall, stop. */
+ if (cache->prev_sp == 0)
+ return;
+
+ id = frame_id_build (cache->prev_sp, func);
+
+ /* Check that we're not going round in circles with the same frame
+ ID (but avoid applying the test to sentinel frames which do go
+ round in circles). */
+ if (frame_relative_level (next_frame) >= 0
+ && get_frame_type (next_frame) == NORMAL_FRAME
+ && frame_id_eq (get_frame_id (next_frame), id))
+ return;
+
+ *this_id = id;
+}
+
+static void
+arm_prologue_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int prev_regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ void *valuep)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ /* If we are asked to unwind the PC, then we need to return the LR
+ instead. The saved value of PC points into this frame's
+ prologue, not the next frame's resume location. */
+ if (prev_regnum == ARM_PC_REGNUM)
+ prev_regnum = ARM_LR_REGNUM;
+
+ /* SP is generally not saved to the stack, but this frame is
+ identified by NEXT_FRAME's stack pointer at the time of the call.
+ The value was already reconstructed into PREV_SP. */
+ if (prev_regnum == ARM_SP_REGNUM)
+ {
+ *lvalp = not_lval;
+ if (valuep)
+ store_unsigned_integer (valuep, 4, cache->prev_sp);
+ return;
+ }
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
+}
+
+struct frame_unwind arm_prologue_unwind = {
+ NORMAL_FRAME,
+ arm_prologue_this_id,
+ arm_prologue_prev_register
+};
+
+static const struct frame_unwind *
+arm_prologue_unwind_sniffer (struct frame_info *next_frame)
+{
+ return &arm_prologue_unwind;
+}
+
+static CORE_ADDR
+arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ return cache->prev_sp + cache->frameoffset - cache->framesize;
+}
+
+struct frame_base arm_normal_base = {
+ &arm_prologue_unwind,
+ arm_normal_frame_base,
+ arm_normal_frame_base,
+ arm_normal_frame_base
+};
+
+static struct arm_prologue_cache *
+arm_make_sigtramp_cache (struct frame_info *next_frame)
+{
+ struct arm_prologue_cache *cache;
+ int reg;
+
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+
+ cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ for (reg = 0; reg < NUM_REGS; reg++)
+ cache->saved_regs[reg].addr
+ = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp,
+ frame_pc_unwind (next_frame), reg);
+
+ /* FIXME: What about thumb mode? */
+ cache->framereg = ARM_SP_REGNUM;
+ cache->prev_sp
+ = read_memory_integer (cache->saved_regs[cache->framereg].addr,
+ register_size (current_gdbarch, cache->framereg));
+
+ return cache;
+}
+
+static void
+arm_sigtramp_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_sigtramp_cache (next_frame);
+ cache = *this_cache;
+
+ /* FIXME drow/2003-07-07: This isn't right if we single-step within
+ the sigtramp frame; the PC should be the beginning of the trampoline. */
+ *this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame));
+}
+
+static void
+arm_sigtramp_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int prev_regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ void *valuep)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_sigtramp_cache (next_frame);
+ cache = *this_cache;
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
+}
+
+struct frame_unwind arm_sigtramp_unwind = {
+ SIGTRAMP_FRAME,
+ arm_sigtramp_this_id,
+ arm_sigtramp_prev_register
+};
+
+static const struct frame_unwind *
+arm_sigtramp_unwind_sniffer (struct frame_info *next_frame)
+{
+ /* Note: If an ARM PC_IN_SIGTRAMP method ever needs to compare
+ against the name of the function, the code below will have to be
+ changed to first fetch the name of the function and then pass
+ this name to PC_IN_SIGTRAMP. */
+
+ if (SIGCONTEXT_REGISTER_ADDRESS_P ()
+ && PC_IN_SIGTRAMP (frame_pc_unwind (next_frame), (char *) 0))
+ return &arm_sigtramp_unwind;
+
+ return NULL;
+}
+
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+ dummy frame. The frame ID's base needs to match the TOS value
+ saved by save_dummy_frame_tos() and returned from
+ arm_push_dummy_call, and the PC needs to match the dummy frame's
+ breakpoint. */
+
+static struct frame_id
+arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
+ frame_pc_unwind (next_frame));
+}
+
+/* Given THIS_FRAME, find the previous frame's resume PC (which will
+ be used to construct the previous frame's ID, after looking up the
+ containing function). */
+
+static CORE_ADDR
+arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR pc;
+ pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
+ return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
+}
+
+static CORE_ADDR
+arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
+}
+
+/* DEPRECATED_CALL_DUMMY_WORDS:
+ This sequence of words is the instructions
+
+ mov lr,pc
+ mov pc,r4
+ illegal
+
+ Note this is 12 bytes. */
+
+static LONGEST arm_call_dummy_words[] =
+{
+ 0xe1a0e00f, 0xe1a0f004, 0xe7ffdefe
+};
+
+/* When arguments must be pushed onto the stack, they go on in reverse
+ order. The code below implements a FILO (stack) to do this. */
+
+struct stack_item
+{
+ int len;
+ struct stack_item *prev;
+ void *data;
+};
+
+static struct stack_item *
+push_stack_item (struct stack_item *prev, void *contents, int len)
+{
+ struct stack_item *si;
+ si = xmalloc (sizeof (struct stack_item));
+ si->data = xmalloc (len);
+ si->len = len;
+ si->prev = prev;
+ memcpy (si->data, contents, len);
+ return si;
+}
+
+static struct stack_item *
+pop_stack_item (struct stack_item *si)
+{
+ struct stack_item *dead = si;
+ si = si->prev;
+ xfree (dead->data);
+ xfree (dead);
+ return si;
+}
+
+/* We currently only support passing parameters in integer registers. This
+ conforms with GCC's default model. Several other variants exist and
+ we should probably support some of them based on the selected ABI. */
+
+static CORE_ADDR
+arm_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp, int struct_return,
+ CORE_ADDR struct_addr)
+{
+ int argnum;
+ int argreg;
+ int nstack;
+ struct stack_item *si = NULL;
+
+ /* Set the return address. For the ARM, the return breakpoint is
+ always at BP_ADDR. */
+ /* XXX Fix for Thumb. */
+ regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
+
+ /* Walk through the list of args and determine how large a temporary
+ stack is required. Need to take care here as structs may be
+ passed on the stack, and we have to to push them. */
+ nstack = 0;
+
+ argreg = ARM_A1_REGNUM;
+ nstack = 0;
+
+ /* Some platforms require a double-word aligned stack. Make sure sp
+ is correctly aligned before we start. We always do this even if
+ it isn't really needed -- it can never hurt things. */
+ sp &= ~(CORE_ADDR)(2 * DEPRECATED_REGISTER_SIZE - 1);
+
+ /* The struct_return pointer occupies the first parameter
+ passing register. */
+ if (struct_return)
+ {
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
+ REGISTER_NAME (argreg), paddr (struct_addr));
+ regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
+ argreg++;
+ }
+
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ int len;
+ struct type *arg_type;
+ struct type *target_type;
+ enum type_code typecode;
+ char *val;
+
+ arg_type = check_typedef (VALUE_TYPE (args[argnum]));
+ len = TYPE_LENGTH (arg_type);
+ target_type = TYPE_TARGET_TYPE (arg_type);
+ typecode = TYPE_CODE (arg_type);
+ val = VALUE_CONTENTS (args[argnum]);
+
+ /* If the argument is a pointer to a function, and it is a
+ Thumb function, create a LOCAL copy of the value and set
+ the THUMB bit in it. */
+ if (TYPE_CODE_PTR == typecode
+ && target_type != NULL
+ && TYPE_CODE_FUNC == TYPE_CODE (target_type))
+ {
+ CORE_ADDR regval = extract_unsigned_integer (val, len);
+ if (arm_pc_is_thumb (regval))
+ {
+ val = alloca (len);
+ store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval));
+ }
+ }
+
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ while (len > 0)
+ {
+ int partial_len = len < DEPRECATED_REGISTER_SIZE ? len : DEPRECATED_REGISTER_SIZE;
+
+ if (argreg <= ARM_LAST_ARG_REGNUM)
+ {
+ /* The argument is being passed in a general purpose
+ register. */
+ CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
+ argnum, REGISTER_NAME (argreg),
+ phex (regval, DEPRECATED_REGISTER_SIZE));
+ regcache_cooked_write_unsigned (regcache, argreg, regval);
+ argreg++;
+ }
+ else
+ {
+ /* Push the arguments onto the stack. */
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
+ argnum, nstack);
+ si = push_stack_item (si, val, DEPRECATED_REGISTER_SIZE);
+ nstack += DEPRECATED_REGISTER_SIZE;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+ }
+ }
+ /* If we have an odd number of words to push, then decrement the stack
+ by one word now, so first stack argument will be dword aligned. */
+ if (nstack & 4)
+ sp -= 4;
+
+ while (si)
+ {
+ sp -= si->len;
+ write_memory (sp, si->data, si->len);
+ si = pop_stack_item (si);
+ }
+
+ /* Finally, update teh SP register. */
+ regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp);
+
+ return sp;
+}
+
+static void
+print_fpu_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');
+}
+
+/* Print interesting information about the floating point processor
+ (if present) or emulator. */
+static void
+arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, const char *args)
+{
+ unsigned long status = read_register (ARM_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);
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register N. */
+
+static struct type *
+arm_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
+ {
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return builtin_type_arm_ext_big;
+ else
+ return builtin_type_arm_ext_littlebyte_bigword;
+ }
+ else
+ return builtin_type_int32;
+}
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+
+static int
+arm_register_byte (int regnum)
+{
+ if (regnum < ARM_F0_REGNUM)
+ return regnum * INT_REGISTER_SIZE;
+ else if (regnum < ARM_PS_REGNUM)
+ return (NUM_GREGS * INT_REGISTER_SIZE
+ + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
+ else
+ return (NUM_GREGS * INT_REGISTER_SIZE
+ + NUM_FREGS * FP_REGISTER_SIZE
+ + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
+}
+
+/* Map GDB internal REGNUM onto the Arm simulator register numbers. */
+static int
+arm_register_sim_regno (int regnum)
+{
+ int reg = regnum;
+ gdb_assert (reg >= 0 && reg < NUM_REGS);
+
+ if (reg < NUM_GREGS)
+ return SIM_ARM_R0_REGNUM + reg;
+ reg -= NUM_GREGS;
+
+ if (reg < NUM_FREGS)
+ return SIM_ARM_FP0_REGNUM + reg;
+ reg -= NUM_FREGS;
+
+ if (reg < NUM_SREGS)
+ return SIM_ARM_FPS_REGNUM + reg;
+ reg -= NUM_SREGS;
+
+ internal_error (__FILE__, __LINE__, "Bad REGNUM %d", regnum);
+}
+
+/* NOTE: cagney/2001-08-20: Both convert_from_extended() and
+ convert_to_extended() use floatformat_arm_ext_littlebyte_bigword.
+ It is thought that this is is the floating-point register format on
+ little-endian systems. */
+
+static void
+convert_from_extended (const struct floatformat *fmt, const void *ptr,
+ void *dbl)
+{
+ DOUBLEST d;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d);
+ else
+ floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
+ ptr, &d);
+ floatformat_from_doublest (fmt, &d, dbl);
+}
+
+static void
+convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr)
+{
+ DOUBLEST d;
+ floatformat_to_doublest (fmt, ptr, &d);
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
+ else
+ floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword,
+ &d, dbl);
+}
+
+static int
+condition_true (unsigned long cond, unsigned long status_reg)
+{
+ if (cond == INST_AL || cond == INST_NV)
+ return 1;
+
+ 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);
+ 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 1;
+}
+
+/* Support routines for single stepping. Calculate the next PC value. */
+#define submask(x) ((1L << ((x) + 1)) - 1)
+#define bit(obj,st) (((obj) >> (st)) & 1)
+#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (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 (unsigned long inst, int carry, unsigned long pc_val,
+ unsigned long status_reg)
+{
+ 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 : status_reg))
+ + (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;
+}
+
+/* Return number of 1-bits in VAL. */
+
+static int
+bitcount (unsigned long val)
+{
+ int nbits;
+ for (nbits = 0; val != 0; nbits++)
+ val &= val - 1; /* delete rightmost 1-bit in val */
+ return nbits;
+}
+
+CORE_ADDR
+thumb_get_next_pc (CORE_ADDR pc)
+{
+ unsigned long pc_val = ((unsigned long) pc) + 4; /* PC after prefetch */
+ unsigned short inst1 = read_memory_integer (pc, 2);
+ CORE_ADDR nextpc = pc + 2; /* default is next instruction */
+ unsigned long offset;
+
+ if ((inst1 & 0xff00) == 0xbd00) /* pop {rlist, pc} */
+ {
+ CORE_ADDR sp;
+
+ /* Fetch the saved PC from the stack. It's stored above
+ all of the other registers. */
+ offset = bitcount (bits (inst1, 0, 7)) * DEPRECATED_REGISTER_SIZE;
+ sp = read_register (ARM_SP_REGNUM);
+ nextpc = (CORE_ADDR) read_memory_integer (sp + offset, 4);
+ nextpc = ADDR_BITS_REMOVE (nextpc);
+ if (nextpc == pc)
+ error ("Infinite loop detected");
+ }
+ else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
+ {
+ unsigned long status = read_register (ARM_PS_REGNUM);
+ unsigned long cond = bits (inst1, 8, 11);
+ if (cond != 0x0f && condition_true (cond, status)) /* 0x0f = SWI */
+ nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
+ }
+ else if ((inst1 & 0xf800) == 0xe000) /* unconditional branch */
+ {
+ nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
+ }
+ else if ((inst1 & 0xf800) == 0xf000) /* long branch with link, and blx */
+ {
+ unsigned short inst2 = read_memory_integer (pc + 2, 2);
+ offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
+ nextpc = pc_val + offset;
+ /* For BLX make sure to clear the low bits. */
+ if (bits (inst2, 11, 12) == 1)
+ nextpc = nextpc & 0xfffffffc;
+ }
+ else if ((inst1 & 0xff00) == 0x4700) /* bx REG, blx REG */
+ {
+ if (bits (inst1, 3, 6) == 0x0f)
+ nextpc = pc_val;
+ else
+ nextpc = read_register (bits (inst1, 3, 6));
+
+ nextpc = ADDR_BITS_REMOVE (nextpc);
+ if (nextpc == pc)
+ error ("Infinite loop detected");
+ }
+
+ return nextpc;
+}
+
+CORE_ADDR
+arm_get_next_pc (CORE_ADDR pc)
+{
+ unsigned long pc_val;
+ unsigned long this_instr;
+ unsigned long status;
+ CORE_ADDR nextpc;
+
+ if (arm_pc_is_thumb (pc))
+ return thumb_get_next_pc (pc);
+
+ pc_val = (unsigned long) pc;
+ this_instr = read_memory_integer (pc, 4);
+ status = read_register (ARM_PS_REGNUM);
+ nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */
+
+ if (condition_true (bits (this_instr, 28, 31), status))
+ {
+ 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");
+
+ /* BX <reg>, BLX <reg> */
+ if (bits (this_instr, 4, 28) == 0x12fff1
+ || bits (this_instr, 4, 28) == 0x12fff3)
+ {
+ rn = bits (this_instr, 0, 3);
+ result = (rn == 15) ? pc_val + 8 : read_register (rn);
+ nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
+
+ if (nextpc == pc)
+ error ("Infinite loop detected");
+
+ return nextpc;
+ }
+
+ /* 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, status);
+
+ 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, status)
+ : 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);
+ offset = bitcount (reglist) * 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);
+
+ /* BLX */
+ if (bits (this_instr, 28, 31) == INST_NV)
+ nextpc |= bit (this_instr, 24) << 1;
+
+ 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_filtered (gdb_stderr, "Bad bit-field extraction\n");
+ return (pc);
+ }
+ }
+
+ return nextpc;
+}
+
+/* single_step() is called just before we want to resume the inferior,
+ if we want to single-step it but there is no hardware or kernel
+ single-step support. We find the target of the coming instruction
+ and breakpoint it.
+
+ single_step() is also called just after the inferior stops. If we
+ had set up a simulated single-step, we undo our damage. */
+
+static void
+arm_software_single_step (enum target_signal sig, int insert_bpt)
+{
+ static int next_pc; /* State between setting and unsetting. */
+ static char break_mem[BREAKPOINT_MAX]; /* Temporary storage for mem@bpt */
+
+ if (insert_bpt)
+ {
+ next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
+ target_insert_breakpoint (next_pc, break_mem);
+ }
+ else
+ target_remove_breakpoint (next_pc, break_mem);
+}
+
+#include "bfd-in2.h"
+#include "libcoff.h"
+
+static int
+gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
+{
+ if (arm_pc_is_thumb (memaddr))
+ {
+ static asymbol *asym;
+ static combined_entry_type ce;
+ static struct coff_symbol_struct csym;
+ static struct bfd fake_bfd;
+ static bfd_target fake_target;
+
+ if (csym.native == NULL)
+ {
+ /* Create a fake symbol vector containing a Thumb symbol.
+ This is solely so that the code in print_insn_little_arm()
+ and print_insn_big_arm() in opcodes/arm-dis.c will detect
+ the presence of a Thumb symbol and switch to decoding
+ Thumb instructions. */
+
+ fake_target.flavour = bfd_target_coff_flavour;
+ fake_bfd.xvec = &fake_target;
+ ce.u.syment.n_sclass = C_THUMBEXTFUNC;
+ csym.native = &ce;
+ csym.symbol.the_bfd = &fake_bfd;
+ csym.symbol.name = "fake";
+ asym = (asymbol *) & csym;
+ }
+
+ memaddr = UNMAKE_THUMB_ADDR (memaddr);
+ info->symbols = &asym;
+ }
+ else
+ info->symbols = NULL;
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return print_insn_big_arm (memaddr, info);
+ else
+ return print_insn_little_arm (memaddr, info);
+}
+
+/* The following define instruction sequences that will cause ARM
+ cpu's to take an undefined instruction trap. These are used to
+ signal a breakpoint to GDB.
+
+ The newer ARMv4T cpu's are capable of operating in ARM or Thumb
+ modes. A different instruction is required for each mode. The ARM
+ cpu's can also be big or little endian. Thus four different
+ instructions are needed to support all cases.
+
+ Note: ARMv4 defines several new instructions that will take the
+ undefined instruction trap. ARM7TDMI is nominally ARMv4T, but does
+ not in fact add the new instructions. The new undefined
+ instructions in ARMv4 are all instructions that had no defined
+ behaviour in earlier chips. There is no guarantee that they will
+ raise an exception, but may be treated as NOP's. In practice, it
+ may only safe to rely on instructions matching:
+
+ 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ C C C C 0 1 1 x x x x x x x x x x x x x x x x x x x x 1 x x x x
+
+ Even this may only true if the condition predicate is true. The
+ following use a condition predicate of ALWAYS so it is always TRUE.
+
+ There are other ways of forcing a breakpoint. GNU/Linux, RISC iX,
+ and NetBSD all use a software interrupt rather than an undefined
+ instruction to force a trap. This can be handled by by the
+ abi-specific code during establishment of the gdbarch vector. */
+
+
+/* NOTE rearnsha 2002-02-18: for now we allow a non-multi-arch gdb to
+ override these definitions. */
+#ifndef ARM_LE_BREAKPOINT
+#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
+#endif
+#ifndef ARM_BE_BREAKPOINT
+#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
+#endif
+#ifndef THUMB_LE_BREAKPOINT
+#define THUMB_LE_BREAKPOINT {0xfe,0xdf}
+#endif
+#ifndef THUMB_BE_BREAKPOINT
+#define THUMB_BE_BREAKPOINT {0xdf,0xfe}
+#endif
+
+static const char arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
+static const char arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
+static const char arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
+static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
+
+/* Determine the type and size of breakpoint to insert at PCPTR. Uses
+ the program counter value to determine whether a 16-bit or 32-bit
+ breakpoint should be used. It returns a pointer to a string of
+ bytes that encode a breakpoint instruction, stores the length of
+ the string to *lenptr, and adjusts the program counter (if
+ necessary) to point to the actual memory location where the
+ breakpoint should be inserted. */
+
+/* XXX ??? from old tm-arm.h: if we're using RDP, then we're inserting
+ breakpoints and storing their handles instread of what was in
+ memory. It is nice that this is the same size as a handle -
+ otherwise remote-rdp will have to change. */
+
+static const unsigned char *
+arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (arm_pc_is_thumb (*pcptr))
+ {
+ *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
+ *lenptr = tdep->thumb_breakpoint_size;
+ return tdep->thumb_breakpoint;
+ }
+ else
+ {
+ *lenptr = tdep->arm_breakpoint_size;
+ return tdep->arm_breakpoint;
+ }
+}
+
+/* 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. */
+
+static void
+arm_extract_return_value (struct type *type,
+ struct regcache *regs,
+ void *dst)
+{
+ bfd_byte *valbuf = dst;
+
+ if (TYPE_CODE_FLT == TYPE_CODE (type))
+ {
+ switch (arm_get_fp_model (current_gdbarch))
+ {
+ case ARM_FLOAT_FPA:
+ {
+ /* The value is in register F0 in internal format. We need to
+ extract the raw value and then convert it to the desired
+ internal type. */
+ bfd_byte tmpbuf[FP_REGISTER_SIZE];
+
+ regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
+ convert_from_extended (floatformat_from_type (type), tmpbuf,
+ valbuf);
+ }
+ break;
+
+ case ARM_FLOAT_SOFT_FPA:
+ case ARM_FLOAT_SOFT_VFP:
+ regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
+ if (TYPE_LENGTH (type) > 4)
+ regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
+ valbuf + INT_REGISTER_SIZE);
+ break;
+
+ default:
+ internal_error
+ (__FILE__, __LINE__,
+ "arm_extract_return_value: Floating point model not supported");
+ break;
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_CHAR
+ || TYPE_CODE (type) == TYPE_CODE_BOOL
+ || TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF
+ || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ /* If the the type is a plain integer, then the access is
+ straight-forward. Otherwise we have to play around a bit more. */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+ ULONGEST tmp;
+
+ while (len > 0)
+ {
+ /* By using store_unsigned_integer we avoid having to do
+ anything special for small big-endian values. */
+ regcache_cooked_read_unsigned (regs, regno++, &tmp);
+ store_unsigned_integer (valbuf,
+ (len > INT_REGISTER_SIZE
+ ? INT_REGISTER_SIZE : len),
+ tmp);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+ else
+ {
+ /* For a structure or union the behaviour is as if the value had
+ been stored to word-aligned memory and then loaded into
+ registers with 32-bit load instruction(s). */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
+
+ while (len > 0)
+ {
+ regcache_cooked_read (regs, regno++, tmpbuf);
+ memcpy (valbuf, tmpbuf,
+ len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+}
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value. */
+
+static CORE_ADDR
+arm_extract_struct_value_address (struct regcache *regcache)
+{
+ ULONGEST ret;
+
+ regcache_cooked_read_unsigned (regcache, ARM_A1_REGNUM, &ret);
+ return ret;
+}
+
+/* Will a function return an aggregate type in memory or in a
+ register? Return 0 if an aggregate type can be returned in a
+ register, 1 if it must be returned in memory. */
+
+static int
+arm_use_struct_convention (int gcc_p, struct type *type)
+{
+ int nRc;
+ enum type_code code;
+
+ CHECK_TYPEDEF (type);
+
+ /* In the ARM ABI, "integer" like aggregate types are returned in
+ registers. For an aggregate type to be integer like, its size
+ must be less than or equal to DEPRECATED_REGISTER_SIZE and the
+ offset of each addressable subfield must be zero. Note that bit
+ fields are not addressable, and all addressable subfields of
+ unions always start at offset zero.
+
+ This function is based on the behaviour of GCC 2.95.1.
+ See: gcc/arm.c: arm_return_in_memory() for details.
+
+ Note: All versions of GCC before GCC 2.95.2 do not set up the
+ parameters correctly for a function returning the following
+ structure: struct { float f;}; This should be returned in memory,
+ not a register. Richard Earnshaw sent me a patch, but I do not
+ know of any way to detect if a function like the above has been
+ compiled with the correct calling convention. */
+
+ /* All aggregate types that won't fit in a register must be returned
+ in memory. */
+ if (TYPE_LENGTH (type) > DEPRECATED_REGISTER_SIZE)
+ {
+ return 1;
+ }
+
+ /* The only aggregate types that can be returned in a register are
+ structs and unions. Arrays must be returned in memory. */
+ code = TYPE_CODE (type);
+ if ((TYPE_CODE_STRUCT != code) && (TYPE_CODE_UNION != code))
+ {
+ return 1;
+ }
+
+ /* Assume all other aggregate types can be returned in a register.
+ Run a check for structures, unions and arrays. */
+ nRc = 0;
+
+ if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code))
+ {
+ int i;
+ /* Need to check if this struct/union is "integer" like. For
+ this to be true, its size must be less than or equal to
+ DEPRECATED_REGISTER_SIZE and the offset of each addressable
+ subfield must be zero. Note that bit fields are not
+ addressable, and unions always start at offset zero. If any
+ of the subfields is a floating point type, the struct/union
+ cannot be an integer type. */
+
+ /* For each field in the object, check:
+ 1) Is it FP? --> yes, nRc = 1;
+ 2) Is it addressable (bitpos != 0) and
+ not packed (bitsize == 0)?
+ --> yes, nRc = 1
+ */
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ enum type_code field_type_code;
+ field_type_code = TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, i)));
+
+ /* Is it a floating point type field? */
+ if (field_type_code == TYPE_CODE_FLT)
+ {
+ nRc = 1;
+ break;
+ }
+
+ /* If bitpos != 0, then we have to care about it. */
+ if (TYPE_FIELD_BITPOS (type, i) != 0)
+ {
+ /* Bitfields are not addressable. If the field bitsize is
+ zero, then the field is not packed. Hence it cannot be
+ a bitfield or any other packed type. */
+ if (TYPE_FIELD_BITSIZE (type, i) == 0)
+ {
+ nRc = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ return nRc;
+}
+
+/* Write into appropriate registers a function return value of type
+ TYPE, given in virtual format. */
+
+static void
+arm_store_return_value (struct type *type, struct regcache *regs,
+ const void *src)
+{
+ const bfd_byte *valbuf = src;
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ char buf[MAX_REGISTER_SIZE];
+
+ switch (arm_get_fp_model (current_gdbarch))
+ {
+ case ARM_FLOAT_FPA:
+
+ convert_to_extended (floatformat_from_type (type), buf, valbuf);
+ regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
+ break;
+
+ case ARM_FLOAT_SOFT_FPA:
+ case ARM_FLOAT_SOFT_VFP:
+ regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
+ if (TYPE_LENGTH (type) > 4)
+ regcache_cooked_write (regs, ARM_A1_REGNUM + 1,
+ valbuf + INT_REGISTER_SIZE);
+ break;
+
+ default:
+ internal_error
+ (__FILE__, __LINE__,
+ "arm_store_return_value: Floating point model not supported");
+ break;
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_CHAR
+ || TYPE_CODE (type) == TYPE_CODE_BOOL
+ || TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF
+ || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ if (TYPE_LENGTH (type) <= 4)
+ {
+ /* Values of one word or less are zero/sign-extended and
+ returned in r0. */
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
+ LONGEST val = unpack_long (type, valbuf);
+
+ store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
+ regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
+ }
+ else
+ {
+ /* Integral values greater than one word are stored in consecutive
+ registers starting with r0. This will always be a multiple of
+ the regiser size. */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+
+ while (len > 0)
+ {
+ regcache_cooked_write (regs, regno++, valbuf);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+ }
+ else
+ {
+ /* For a structure or union the behaviour is as if the value had
+ been stored to word-aligned memory and then loaded into
+ registers with 32-bit load instruction(s). */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
+
+ while (len > 0)
+ {
+ memcpy (tmpbuf, valbuf,
+ len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
+ regcache_cooked_write (regs, regno++, tmpbuf);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+}
+
+static int
+arm_get_longjmp_target (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char buf[INT_REGISTER_SIZE];
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ jb_addr = read_register (ARM_A1_REGNUM);
+
+ if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
+ INT_REGISTER_SIZE))
+ return 0;
+
+ *pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE);
+ return 1;
+}
+
+/* Return non-zero if the PC is inside a thumb call thunk. */
+
+int
+arm_in_call_stub (CORE_ADDR pc, char *name)
+{
+ CORE_ADDR start_addr;
+
+ /* Find the starting address of the function containing the PC. If
+ the caller didn't give us a name, look it up at the same time. */
+ if (0 == find_pc_partial_function (pc, name ? NULL : &name,
+ &start_addr, NULL))
+ return 0;
+
+ return strncmp (name, "_call_via_r", 11) == 0;
+}
+
+/* If PC is in a Thumb call or return stub, return the address of the
+ target PC, which is in a register. The thunk functions are called
+ _called_via_xx, where x is the register name. The possible names
+ are r0-r9, sl, fp, ip, sp, and lr. */
+
+CORE_ADDR
+arm_skip_stub (CORE_ADDR pc)
+{
+ char *name;
+ CORE_ADDR start_addr;
+
+ /* Find the starting address and name of the function containing the PC. */
+ if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
+ return 0;
+
+ /* Call thunks always start with "_call_via_". */
+ if (strncmp (name, "_call_via_", 10) == 0)
+ {
+ /* Use the name suffix to determine which register contains the
+ target PC. */
+ static char *table[15] =
+ {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "sl", "fp", "ip", "sp", "lr"
+ };
+ int regno;
+
+ for (regno = 0; regno <= 14; regno++)
+ if (strcmp (&name[10], table[regno]) == 0)
+ return read_register (regno);
+ }
+
+ return 0; /* not a stub */
+}
+
+static void
+set_arm_command (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set arm\" must be followed by an apporpriate subcommand.\n");
+ help_list (setarmcmdlist, "set arm ", all_commands, gdb_stdout);
+}
+
+static void
+show_arm_command (char *args, int from_tty)
+{
+ cmd_show_list (showarmcmdlist, from_tty, "");
+}
+
+enum arm_float_model
+arm_get_fp_model (struct gdbarch *gdbarch)
+{
+ if (arm_fp_model == ARM_FLOAT_AUTO)
+ return gdbarch_tdep (gdbarch)->fp_model;
+
+ return arm_fp_model;
+}
+
+static void
+arm_set_fp (struct gdbarch *gdbarch)
+{
+ enum arm_float_model fp_model = arm_get_fp_model (gdbarch);
+
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE
+ && (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA))
+ {
+ set_gdbarch_double_format (gdbarch,
+ &floatformat_ieee_double_littlebyte_bigword);
+ set_gdbarch_long_double_format
+ (gdbarch, &floatformat_ieee_double_littlebyte_bigword);
+ }
+ else
+ {
+ set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
+ set_gdbarch_long_double_format (gdbarch,
+ &floatformat_ieee_double_little);
+ }
+}
+
+static void
+set_fp_model_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ enum arm_float_model fp_model;
+
+ for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
+ if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
+ {
+ arm_fp_model = fp_model;
+ break;
+ }
+
+ if (fp_model == ARM_FLOAT_LAST)
+ internal_error (__FILE__, __LINE__, "Invalid fp model accepted: %s.",
+ current_fp_model);
+
+ if (gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+ arm_set_fp (current_gdbarch);
+}
+
+static void
+show_fp_model (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (arm_fp_model == ARM_FLOAT_AUTO
+ && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+ printf_filtered (" - the default for the current ABI is \"%s\".\n",
+ fp_model_strings[tdep->fp_model]);
+}
+
+/* If the user changes the register disassembly style used for info
+ register and other commands, we have to also switch the style used
+ in opcodes for disassembly output. This function is run in the "set
+ arm disassembly" command, and does that. */
+
+static void
+set_disassembly_style_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_disassembly_style ();
+}
+
+/* Return the ARM register name corresponding to register I. */
+static const char *
+arm_register_name (int i)
+{
+ return arm_register_names[i];
+}
+
+static void
+set_disassembly_style (void)
+{
+ const char *setname, *setdesc, **regnames;
+ int numregs, j;
+
+ /* Find the style that the user wants in the opcodes table. */
+ int current = 0;
+ numregs = get_arm_regnames (current, &setname, &setdesc, &regnames);
+ while ((disassembly_style != setname)
+ && (current < num_disassembly_options))
+ get_arm_regnames (++current, &setname, &setdesc, &regnames);
+ current_option = current;
+
+ /* Fill our copy. */
+ for (j = 0; j < numregs; j++)
+ arm_register_names[j] = (char *) regnames[j];
+
+ /* Adjust case. */
+ if (isupper (*regnames[ARM_PC_REGNUM]))
+ {
+ arm_register_names[ARM_FPS_REGNUM] = "FPS";
+ arm_register_names[ARM_PS_REGNUM] = "CPSR";
+ }
+ else
+ {
+ arm_register_names[ARM_FPS_REGNUM] = "fps";
+ arm_register_names[ARM_PS_REGNUM] = "cpsr";
+ }
+
+ /* Synchronize the disassembler. */
+ set_arm_regname_option (current);
+}
+
+/* arm_othernames implements the "othernames" command. This is deprecated
+ by the "set arm disassembly" command. */
+
+static void
+arm_othernames (char *names, int n)
+{
+ /* Circle through the various flavors. */
+ current_option = (current_option + 1) % num_disassembly_options;
+
+ disassembly_style = valid_disassembly_styles[current_option];
+ set_disassembly_style ();
+}
+
+/* Test whether the coff symbol specific value corresponds to a Thumb
+ function. */
+
+static int
+coff_sym_is_thumb (int val)
+{
+ return (val == C_THUMBEXT ||
+ val == C_THUMBSTAT ||
+ val == C_THUMBEXTFUNC ||
+ val == C_THUMBSTATFUNC ||
+ val == C_THUMBLABEL);
+}
+
+/* arm_coff_make_msymbol_special()
+ arm_elf_make_msymbol_special()
+
+ These functions test whether the COFF or ELF symbol corresponds to
+ an address in thumb code, and set a "special" bit in a minimal
+ symbol to indicate that it does. */
+
+static void
+arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
+{
+ /* Thumb symbols are of type STT_LOPROC, (synonymous with
+ STT_ARM_TFUNC). */
+ if (ELF_ST_TYPE (((elf_symbol_type *)sym)->internal_elf_sym.st_info)
+ == STT_LOPROC)
+ MSYMBOL_SET_SPECIAL (msym);
+}
+
+static void
+arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
+{
+ if (coff_sym_is_thumb (val))
+ MSYMBOL_SET_SPECIAL (msym);
+}
+
+static void
+arm_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+ write_register_pid (ARM_PC_REGNUM, pc, ptid);
+
+ /* If necessary, set the T bit. */
+ if (arm_apcs_32)
+ {
+ CORE_ADDR val = read_register_pid (ARM_PS_REGNUM, ptid);
+ if (arm_pc_is_thumb (pc))
+ write_register_pid (ARM_PS_REGNUM, val | 0x20, ptid);
+ else
+ write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
+ }
+}
+
+static enum gdb_osabi
+arm_elf_osabi_sniffer (bfd *abfd)
+{
+ unsigned int elfosabi, eflags;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+ elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+ switch (elfosabi)
+ {
+ case ELFOSABI_NONE:
+ /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the
+ file are conforming to the base specification for that machine
+ (there are no OS-specific extensions). In order to determine the
+ real OS in use we must look for OS notes that have been added. */
+ bfd_map_over_sections (abfd,
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ if (osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* Existing ARM tools don't set this field, so look at the EI_FLAGS
+ field for more information. */
+ eflags = EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags);
+ switch (eflags)
+ {
+ case EF_ARM_EABI_VER1:
+ osabi = GDB_OSABI_ARM_EABI_V1;
+ break;
+
+ case EF_ARM_EABI_VER2:
+ osabi = GDB_OSABI_ARM_EABI_V2;
+ break;
+
+ case EF_ARM_EABI_UNKNOWN:
+ /* Assume GNU tools. */
+ osabi = GDB_OSABI_ARM_APCS;
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "arm_elf_osabi_sniffer: Unknown ARM EABI "
+ "version 0x%x", eflags);
+ }
+ }
+ break;
+
+ case ELFOSABI_ARM:
+ /* GNU tools use this value. Check note sections in this case,
+ as well. */
+ bfd_map_over_sections (abfd,
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ if (osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* Assume APCS ABI. */
+ osabi = GDB_OSABI_ARM_APCS;
+ }
+ break;
+
+ case ELFOSABI_FREEBSD:
+ osabi = GDB_OSABI_FREEBSD_ELF;
+ break;
+
+ case ELFOSABI_NETBSD:
+ osabi = GDB_OSABI_NETBSD_ELF;
+ break;
+
+ case ELFOSABI_LINUX:
+ osabi = GDB_OSABI_LINUX;
+ break;
+ }
+
+ return osabi;
+}
+
+
+/* Initialize the current architecture based on INFO. If possible,
+ re-use an architecture from ARCHES, which is a list of
+ architectures already created during this debugging session.
+
+ Called e.g. at program startup, when reading a core file, and when
+ reading a binary file. */
+
+static struct gdbarch *
+arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+
+ /* Try to deterimine the ABI of the object we are loading. */
+
+ if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
+ {
+ switch (bfd_get_flavour (info.abfd))
+ {
+ case bfd_target_aout_flavour:
+ /* Assume it's an old APCS-style ABI. */
+ info.osabi = GDB_OSABI_ARM_APCS;
+ break;
+
+ case bfd_target_coff_flavour:
+ /* Assume it's an old APCS-style ABI. */
+ /* XXX WinCE? */
+ info.osabi = GDB_OSABI_ARM_APCS;
+ break;
+
+ default:
+ /* Leave it as "unknown". */
+ break;
+ }
+ }
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* We used to default to FPA for generic ARM, but almost nobody uses that
+ now, and we now provide a way for the user to force the model. So
+ default to the most useful variant. */
+ tdep->fp_model = ARM_FLOAT_SOFT_FPA;
+
+ /* Breakpoints. */
+ switch (info.byte_order)
+ {
+ case BFD_ENDIAN_BIG:
+ tdep->arm_breakpoint = arm_default_arm_be_breakpoint;
+ tdep->arm_breakpoint_size = sizeof (arm_default_arm_be_breakpoint);
+ tdep->thumb_breakpoint = arm_default_thumb_be_breakpoint;
+ tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_be_breakpoint);
+
+ break;
+
+ case BFD_ENDIAN_LITTLE:
+ tdep->arm_breakpoint = arm_default_arm_le_breakpoint;
+ tdep->arm_breakpoint_size = sizeof (arm_default_arm_le_breakpoint);
+ tdep->thumb_breakpoint = arm_default_thumb_le_breakpoint;
+ tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_le_breakpoint);
+
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "arm_gdbarch_init: bad byte order for float format");
+ }
+
+ /* On ARM targets char defaults to unsigned. */
+ set_gdbarch_char_signed (gdbarch, 0);
+
+ /* This should be low enough for everything. */
+ tdep->lowest_pc = 0x20;
+ tdep->jb_pc = -1; /* Longjump support not enabled by default. */
+
+ set_gdbarch_deprecated_call_dummy_words (gdbarch, arm_call_dummy_words);
+ set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
+
+ set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
+
+ set_gdbarch_write_pc (gdbarch, arm_write_pc);
+
+ /* Frame handling. */
+ set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
+ set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
+
+ set_gdbarch_deprecated_frameless_function_invocation (gdbarch, arm_frameless_function_invocation);
+
+ frame_base_set_default (gdbarch, &arm_normal_base);
+
+ /* Address manipulation. */
+ set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
+ set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
+
+ /* Advance PC across function entry code. */
+ set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
+
+ /* Get the PC when a frame might not be available. */
+ set_gdbarch_deprecated_saved_pc_after_call (gdbarch, arm_saved_pc_after_call);
+
+ /* The stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Breakpoint manipulation. */
+ set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
+
+ /* Information about registers, etc. */
+ set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
+ set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */
+ set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
+ set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
+ set_gdbarch_deprecated_register_bytes (gdbarch,
+ (NUM_GREGS * INT_REGISTER_SIZE
+ + NUM_FREGS * FP_REGISTER_SIZE
+ + NUM_SREGS * STATUS_REGISTER_SIZE));
+ set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
+ set_gdbarch_register_type (gdbarch, arm_register_type);
+
+ /* Internal <-> external register number maps. */
+ set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
+
+ /* Integer registers are 4 bytes. */
+ set_gdbarch_deprecated_register_size (gdbarch, 4);
+ set_gdbarch_register_name (gdbarch, arm_register_name);
+
+ /* Returning results. */
+ set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
+ set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
+ set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention);
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch, arm_extract_struct_value_address);
+
+ /* Single stepping. */
+ /* XXX For an RDI target we should ask the target if it can single-step. */
+ set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
+
+ /* Disassembly. */
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm);
+
+ /* Minsymbol frobbing. */
+ set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special);
+ set_gdbarch_coff_make_msymbol_special (gdbarch,
+ arm_coff_make_msymbol_special);
+
+ /* Hook in the ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ /* Add some default predicates. */
+ frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer);
+ frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
+
+ /* Now we have tuned the configuration, set a few final things,
+ based on what the OS ABI has told us. */
+
+ if (tdep->jb_pc >= 0)
+ set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
+
+ /* Floating point sizes and format. */
+ switch (info.byte_order)
+ {
+ case BFD_ENDIAN_BIG:
+ set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
+ set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
+ set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
+
+ break;
+
+ case BFD_ENDIAN_LITTLE:
+ set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
+ arm_set_fp (gdbarch);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "arm_gdbarch_init: bad byte order for float format");
+ }
+
+ return gdbarch;
+}
+
+static void
+arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep == NULL)
+ return;
+
+ fprintf_unfiltered (file, "arm_dump_tdep: Lowest pc = 0x%lx",
+ (unsigned long) tdep->lowest_pc);
+}
+
+static void
+arm_init_abi_eabi_v1 (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ /* Place-holder. */
+}
+
+static void
+arm_init_abi_eabi_v2 (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ /* Place-holder. */
+}
+
+static void
+arm_init_abi_apcs (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ /* Place-holder. */
+}
+
+extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_arm_tdep (void)
+{
+ struct ui_file *stb;
+ long length;
+ struct cmd_list_element *new_set, *new_show;
+ const char *setname;
+ const char *setdesc;
+ const char **regnames;
+ int numregs, i, j;
+ static char *helptext;
+
+ gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
+
+ /* Register an ELF OS ABI sniffer for ARM binaries. */
+ gdbarch_register_osabi_sniffer (bfd_arch_arm,
+ bfd_target_elf_flavour,
+ arm_elf_osabi_sniffer);
+
+ /* Register some ABI variants for embedded systems. */
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V1,
+ arm_init_abi_eabi_v1);
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V2,
+ arm_init_abi_eabi_v2);
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_APCS,
+ arm_init_abi_apcs);
+
+ /* Get the number of possible sets of register names defined in opcodes. */
+ num_disassembly_options = get_arm_regname_num_options ();
+
+ /* Add root prefix command for all "set arm"/"show arm" commands. */
+ add_prefix_cmd ("arm", no_class, set_arm_command,
+ "Various ARM-specific commands.",
+ &setarmcmdlist, "set arm ", 0, &setlist);
+
+ add_prefix_cmd ("arm", no_class, show_arm_command,
+ "Various ARM-specific commands.",
+ &showarmcmdlist, "show arm ", 0, &showlist);
+
+ /* Sync the opcode insn printer with our register viewer. */
+ parse_arm_disassembler_option ("reg-names-std");
+
+ /* Begin creating the help text. */
+ stb = mem_fileopen ();
+ fprintf_unfiltered (stb, "Set the disassembly style.\n"
+ "The valid values are:\n");
+
+ /* Initialize the array that will be passed to add_set_enum_cmd(). */
+ valid_disassembly_styles
+ = xmalloc ((num_disassembly_options + 1) * sizeof (char *));
+ for (i = 0; i < num_disassembly_options; i++)
+ {
+ numregs = get_arm_regnames (i, &setname, &setdesc, &regnames);
+ valid_disassembly_styles[i] = setname;
+ fprintf_unfiltered (stb, "%s - %s\n", setname,
+ setdesc);
+ /* Copy the default names (if found) and synchronize disassembler. */
+ if (!strcmp (setname, "std"))
+ {
+ disassembly_style = setname;
+ current_option = i;
+ for (j = 0; j < numregs; j++)
+ arm_register_names[j] = (char *) regnames[j];
+ set_arm_regname_option (i);
+ }
+ }
+ /* Mark the end of valid options. */
+ valid_disassembly_styles[num_disassembly_options] = NULL;
+
+ /* Finish the creation of the help text. */
+ fprintf_unfiltered (stb, "The default is \"std\".");
+ helptext = ui_file_xstrdup (stb, &length);
+ ui_file_delete (stb);
+
+ /* Add the deprecated disassembly-flavor command. */
+ new_set = add_set_enum_cmd ("disassembly-flavor", no_class,
+ valid_disassembly_styles,
+ &disassembly_style,
+ helptext,
+ &setlist);
+ set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
+ deprecate_cmd (new_set, "set arm disassembly");
+ deprecate_cmd (add_show_from_set (new_set, &showlist),
+ "show arm disassembly");
+
+ /* And now add the new interface. */
+ new_set = add_set_enum_cmd ("disassembler", no_class,
+ valid_disassembly_styles, &disassembly_style,
+ helptext, &setarmcmdlist);
+
+ set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
+ add_show_from_set (new_set, &showarmcmdlist);
+
+ add_setshow_cmd_full ("apcs32", no_class,
+ var_boolean, (char *) &arm_apcs_32,
+ "Set usage of ARM 32-bit mode.",
+ "Show usage of ARM 32-bit mode.",
+ NULL, NULL,
+ &setlist, &showlist, &new_set, &new_show);
+ deprecate_cmd (new_set, "set arm apcs32");
+ deprecate_cmd (new_show, "show arm apcs32");
+
+ add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
+ "Set usage of ARM 32-bit mode. "
+ "When off, a 26-bit PC will be used.",
+ "Show usage of ARM 32-bit mode. "
+ "When off, a 26-bit PC will be used.",
+ NULL, NULL,
+ &setarmcmdlist, &showarmcmdlist);
+
+ /* Add a command to allow the user to force the FPU model. */
+ new_set = add_set_enum_cmd
+ ("fpu", no_class, fp_model_strings, &current_fp_model,
+ "Set the floating point type.\n"
+ "auto - Determine the FP typefrom the OS-ABI.\n"
+ "softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n"
+ "fpa - FPA co-processor (GCC compiled).\n"
+ "softvfp - Software FP with pure-endian doubles.\n"
+ "vfp - VFP co-processor.",
+ &setarmcmdlist);
+ set_cmd_sfunc (new_set, set_fp_model_sfunc);
+ set_cmd_sfunc (add_show_from_set (new_set, &showarmcmdlist), show_fp_model);
+
+ /* Add the deprecated "othernames" command. */
+ deprecate_cmd (add_com ("othernames", class_obscure, arm_othernames,
+ "Switch to the next set of register names."),
+ "set arm disassembly");
+
+ /* Debugging flag. */
+ add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
+ "Set ARM debugging. "
+ "When on, arm-specific debugging is enabled.",
+ "Show ARM debugging. "
+ "When on, arm-specific debugging is enabled.",
+ NULL, NULL,
+ &setdebuglist, &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/arm-tdep.h b/contrib/gdb/gdb/arm-tdep.h
new file mode 100644
index 0000000..bb30455
--- /dev/null
+++ b/contrib/gdb/gdb/arm-tdep.h
@@ -0,0 +1,149 @@
+/* Common target dependent code for GDB on ARM systems.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* 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. */
+
+enum gdb_regnum {
+ ARM_A1_REGNUM = 0, /* first integer-like argument */
+ ARM_A4_REGNUM = 3, /* last integer-like argument */
+ ARM_AP_REGNUM = 11,
+ ARM_SP_REGNUM = 13, /* Contains address of top of stack */
+ ARM_LR_REGNUM = 14, /* address to return to from a function call */
+ ARM_PC_REGNUM = 15, /* Contains program counter */
+ ARM_F0_REGNUM = 16, /* first floating point register */
+ ARM_F3_REGNUM = 19, /* last floating point argument register */
+ ARM_F7_REGNUM = 23, /* last floating point register */
+ ARM_FPS_REGNUM = 24, /* floating point status register */
+ ARM_PS_REGNUM = 25, /* Contains processor status */
+ ARM_FP_REGNUM = 11, /* Frame register in ARM code, if used. */
+ THUMB_FP_REGNUM = 7, /* Frame register in Thumb code, if used. */
+ ARM_NUM_ARG_REGS = 4,
+ ARM_LAST_ARG_REGNUM = ARM_A4_REGNUM,
+ ARM_NUM_FP_ARG_REGS = 4,
+ ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM
+};
+
+/* Size of integer registers. */
+#define INT_REGISTER_SIZE 4
+
+/* Say how long FP registers are. Used for documentation purposes and
+ code readability in this header. IEEE extended doubles are 80
+ bits. DWORD aligned they use 96 bits. */
+#define FP_REGISTER_SIZE 12
+
+/* Status registers are the same size as general purpose registers.
+ Used for documentation purposes and code readability in this
+ header. */
+#define STATUS_REGISTER_SIZE 4
+
+/* Number of machine registers. The only define actually required
+ is NUM_REGS. The other definitions are used for documentation
+ purposes and code readability. */
+/* For 26 bit ARM code, a fake copy of the PC is placed in register 25 (PS)
+ (and called PS for processor status) so the status bits can be cleared
+ from the PC (register 15). For 32 bit ARM code, a copy of CPSR is placed
+ in PS. */
+#define NUM_FREGS 8 /* Number of floating point registers. */
+#define NUM_SREGS 2 /* Number of status registers. */
+#define NUM_GREGS 16 /* Number of general purpose registers. */
+
+
+/* Instruction condition field values. */
+#define INST_EQ 0x0
+#define INST_NE 0x1
+#define INST_CS 0x2
+#define INST_CC 0x3
+#define INST_MI 0x4
+#define INST_PL 0x5
+#define INST_VS 0x6
+#define INST_VC 0x7
+#define INST_HI 0x8
+#define INST_LS 0x9
+#define INST_GE 0xa
+#define INST_LT 0xb
+#define INST_GT 0xc
+#define INST_LE 0xd
+#define INST_AL 0xe
+#define INST_NV 0xf
+
+#define FLAG_N 0x80000000
+#define FLAG_Z 0x40000000
+#define FLAG_C 0x20000000
+#define FLAG_V 0x10000000
+
+/* Type of floating-point code in use by inferior. There are really 3 models
+ that are traditionally supported (plus the endianness issue), but gcc can
+ only generate 2 of those. The third is APCS_FLOAT, where arguments to
+ functions are passed in floating-point registers.
+
+ In addition to the traditional models, VFP adds two more.
+
+ If you update this enum, don't forget to update fp_model_strings in
+ arm-tdep.c. */
+
+enum arm_float_model
+{
+ ARM_FLOAT_AUTO, /* Automatic detection. Do not set in tdep. */
+ ARM_FLOAT_SOFT_FPA, /* Traditional soft-float (mixed-endian on LE ARM). */
+ ARM_FLOAT_FPA, /* FPA co-processor. GCC calling convention. */
+ ARM_FLOAT_SOFT_VFP, /* Soft-float with pure-endian doubles. */
+ ARM_FLOAT_VFP, /* Full VFP calling convention. */
+ ARM_FLOAT_LAST /* Keep at end. */
+};
+
+/* A method to the setting based on user's choice and ABI setting. */
+enum arm_float_model arm_get_fp_model (struct gdbarch *);
+
+/* Target-dependent structure in gdbarch. */
+struct gdbarch_tdep
+{
+ enum arm_float_model fp_model; /* Floating point calling conventions. */
+
+ CORE_ADDR lowest_pc; /* Lowest address at which instructions
+ will appear. */
+
+ const char *arm_breakpoint; /* Breakpoint pattern for an ARM insn. */
+ int arm_breakpoint_size; /* And its size. */
+ const char *thumb_breakpoint; /* Breakpoint pattern for an ARM insn. */
+ int thumb_breakpoint_size; /* And its size. */
+
+ int jb_pc; /* Offset to PC value in jump buffer.
+ If this is negative, longjmp support
+ will be disabled. */
+ size_t jb_elt_size; /* And the size of each entry in the buf. */
+};
+
+#ifndef LOWEST_PC
+#define LOWEST_PC (gdbarch_tdep (current_gdbarch)->lowest_pc)
+#endif
+
+/* Prototypes for internal interfaces needed by more than one MD file. */
+int arm_pc_is_thumb_dummy (CORE_ADDR);
+
+int arm_pc_is_thumb (CORE_ADDR);
+
+CORE_ADDR thumb_get_next_pc (CORE_ADDR);
+
+CORE_ADDR arm_get_next_pc (CORE_ADDR);
diff --git a/contrib/gdb/gdb/armnbsd-nat.c b/contrib/gdb/gdb/armnbsd-nat.c
new file mode 100644
index 0000000..88396c0
--- /dev/null
+++ b/contrib/gdb/gdb/armnbsd-nat.c
@@ -0,0 +1,464 @@
+/* Native-dependent code for BSD Unix running on ARM's, for GDB.
+ Copyright 1988, 1989, 1991, 1992, 1994, 1996, 1999, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+#ifndef FETCH_INFERIOR_REGISTERS
+#error Not FETCH_INFERIOR_REGISTERS
+#endif /* !FETCH_INFERIOR_REGISTERS */
+
+#include "arm-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+#include "inferior.h"
+#include "regcache.h"
+#include "gdbcore.h"
+
+extern int arm_apcs_32;
+
+static void
+supply_gregset (struct reg *gregset)
+{
+ int regno;
+ CORE_ADDR r_pc;
+
+ /* Integer registers. */
+ for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
+ supply_register (regno, (char *) &gregset->r[regno]);
+
+ supply_register (ARM_SP_REGNUM, (char *) &gregset->r_sp);
+ supply_register (ARM_LR_REGNUM, (char *) &gregset->r_lr);
+ /* This is ok: we're running native... */
+ r_pc = ADDR_BITS_REMOVE (gregset->r_pc);
+ supply_register (ARM_PC_REGNUM, (char *) &r_pc);
+
+ if (arm_apcs_32)
+ supply_register (ARM_PS_REGNUM, (char *) &gregset->r_cpsr);
+ else
+ supply_register (ARM_PS_REGNUM, (char *) &gregset->r_pc);
+}
+
+static void
+supply_fparegset (struct fpreg *fparegset)
+{
+ int regno;
+
+ for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+ supply_register
+ (regno, (char *) &fparegset->fpr[regno - ARM_F0_REGNUM]);
+
+ supply_register (ARM_FPS_REGNUM, (char *) &fparegset->fpr_fpsr);
+}
+
+static void
+fetch_register (int regno)
+{
+ struct reg inferior_registers;
+ int ret;
+
+ ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_registers, 0);
+
+ if (ret < 0)
+ {
+ warning ("unable to fetch general register");
+ return;
+ }
+
+ switch (regno)
+ {
+ case ARM_SP_REGNUM:
+ supply_register (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
+ break;
+
+ case ARM_LR_REGNUM:
+ supply_register (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
+ break;
+
+ case ARM_PC_REGNUM:
+ /* This is ok: we're running native... */
+ inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
+ supply_register (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
+ break;
+
+ case ARM_PS_REGNUM:
+ if (arm_apcs_32)
+ supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
+ else
+ supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_pc);
+ break;
+
+ default:
+ supply_register (regno, (char *) &inferior_registers.r[regno]);
+ break;
+ }
+}
+
+static void
+fetch_regs (void)
+{
+ struct reg inferior_registers;
+ int ret;
+ int regno;
+
+ ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_registers, 0);
+
+ if (ret < 0)
+ {
+ warning ("unable to fetch general registers");
+ return;
+ }
+
+ supply_gregset (&inferior_registers);
+}
+
+static void
+fetch_fp_register (int regno)
+{
+ struct fpreg inferior_fp_registers;
+ int ret;
+
+ ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
+
+ if (ret < 0)
+ {
+ warning ("unable to fetch floating-point register");
+ return;
+ }
+
+ switch (regno)
+ {
+ case ARM_FPS_REGNUM:
+ supply_register (ARM_FPS_REGNUM,
+ (char *) &inferior_fp_registers.fpr_fpsr);
+ break;
+
+ default:
+ supply_register
+ (regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
+ break;
+ }
+}
+
+static void
+fetch_fp_regs (void)
+{
+ struct fpreg inferior_fp_registers;
+ int ret;
+ int regno;
+
+ ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
+
+ if (ret < 0)
+ {
+ warning ("unable to fetch general registers");
+ return;
+ }
+
+ supply_fparegset (&inferior_fp_registers);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno >= 0)
+ {
+ if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
+ fetch_register (regno);
+ else
+ fetch_fp_register (regno);
+ }
+ else
+ {
+ fetch_regs ();
+ fetch_fp_regs ();
+ }
+}
+
+
+static void
+store_register (int regno)
+{
+ struct reg inferior_registers;
+ int ret;
+
+ ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_registers, 0);
+
+ if (ret < 0)
+ {
+ warning ("unable to fetch general registers");
+ return;
+ }
+
+ switch (regno)
+ {
+ case ARM_SP_REGNUM:
+ regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
+ break;
+
+ case ARM_LR_REGNUM:
+ regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
+ break;
+
+ case ARM_PC_REGNUM:
+ if (arm_apcs_32)
+ regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
+ else
+ {
+ unsigned pc_val;
+
+ regcache_collect (ARM_PC_REGNUM, (char *) &pc_val);
+
+ pc_val = ADDR_BITS_REMOVE (pc_val);
+ inferior_registers.r_pc
+ ^= ADDR_BITS_REMOVE (inferior_registers.r_pc);
+ inferior_registers.r_pc |= pc_val;
+ }
+ break;
+
+ case ARM_PS_REGNUM:
+ if (arm_apcs_32)
+ regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
+ else
+ {
+ unsigned psr_val;
+
+ regcache_collect (ARM_PS_REGNUM, (char *) &psr_val);
+
+ psr_val ^= ADDR_BITS_REMOVE (psr_val);
+ inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
+ inferior_registers.r_pc |= psr_val;
+ }
+ break;
+
+ default:
+ regcache_collect (regno, (char *) &inferior_registers.r[regno]);
+ break;
+ }
+
+ ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_registers, 0);
+
+ if (ret < 0)
+ warning ("unable to write register %d to inferior", regno);
+}
+
+static void
+store_regs (void)
+{
+ struct reg inferior_registers;
+ int ret;
+ int regno;
+
+
+ for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
+ regcache_collect (regno, (char *) &inferior_registers.r[regno]);
+
+ regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
+ regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
+
+ if (arm_apcs_32)
+ {
+ regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
+ regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
+ }
+ else
+ {
+ unsigned pc_val;
+ unsigned psr_val;
+
+ regcache_collect (ARM_PC_REGNUM, (char *) &pc_val);
+ regcache_collect (ARM_PS_REGNUM, (char *) &psr_val);
+
+ pc_val = ADDR_BITS_REMOVE (pc_val);
+ psr_val ^= ADDR_BITS_REMOVE (psr_val);
+
+ inferior_registers.r_pc = pc_val | psr_val;
+ }
+
+ ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_registers, 0);
+
+ if (ret < 0)
+ warning ("unable to store general registers");
+}
+
+static void
+store_fp_register (int regno)
+{
+ struct fpreg inferior_fp_registers;
+ int ret;
+
+ ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
+
+ if (ret < 0)
+ {
+ warning ("unable to fetch floating-point registers");
+ return;
+ }
+
+ switch (regno)
+ {
+ case ARM_FPS_REGNUM:
+ regcache_collect (ARM_FPS_REGNUM,
+ (char *) &inferior_fp_registers.fpr_fpsr);
+ break;
+
+ default:
+ regcache_collect
+ (regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
+ break;
+ }
+
+ ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
+
+ if (ret < 0)
+ warning ("unable to write register %d to inferior", regno);
+}
+
+static void
+store_fp_regs (void)
+{
+ struct fpreg inferior_fp_registers;
+ int ret;
+ int regno;
+
+
+ for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+ regcache_collect
+ (regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
+
+ regcache_collect (ARM_FPS_REGNUM, (char *) &inferior_fp_registers.fpr_fpsr);
+
+ ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
+
+ if (ret < 0)
+ warning ("unable to store floating-point registers");
+}
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno >= 0)
+ {
+ if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
+ store_register (regno);
+ else
+ store_fp_register (regno);
+ }
+ else
+ {
+ store_regs ();
+ store_fp_regs ();
+ }
+}
+
+struct md_core
+{
+ struct reg intreg;
+ struct fpreg freg;
+};
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR ignore)
+{
+ struct md_core *core_reg = (struct md_core *) core_reg_sect;
+ int regno;
+ CORE_ADDR r_pc;
+
+ supply_gregset (&core_reg->intreg);
+ supply_fparegset (&core_reg->freg);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR ignore)
+{
+ struct reg gregset;
+ struct fpreg fparegset;
+
+ switch (which)
+ {
+ case 0: /* Integer registers. */
+ if (core_reg_size != sizeof (struct reg))
+ warning ("wrong size of register set in core file");
+ else
+ {
+ /* The memcpy may be unnecessary, but we can't really be sure
+ of the alignment of the data in the core file. */
+ memcpy (&gregset, core_reg_sect, sizeof (gregset));
+ supply_gregset (&gregset);
+ }
+ break;
+
+ case 2:
+ if (core_reg_size != sizeof (struct fpreg))
+ warning ("wrong size of FPA register set in core file");
+ else
+ {
+ /* The memcpy may be unnecessary, but we can't really be sure
+ of the alignment of the data in the core file. */
+ memcpy (&fparegset, core_reg_sect, sizeof (fparegset));
+ supply_fparegset (&fparegset);
+ }
+ break;
+
+ default:
+ /* Don't know what kind of register request this is; just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns arm_netbsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flovour. */
+ default_check_format, /* check_format. */
+ default_core_sniffer, /* core_sniffer. */
+ fetch_core_registers, /* core_read_registers. */
+ NULL
+};
+
+static struct core_fns arm_netbsd_elfcore_fns =
+{
+ bfd_target_elf_flavour, /* core_flovour. */
+ default_check_format, /* check_format. */
+ default_core_sniffer, /* core_sniffer. */
+ fetch_elfcore_registers, /* core_read_registers. */
+ NULL
+};
+
+void
+_initialize_arm_netbsd_nat (void)
+{
+ add_core_fns (&arm_netbsd_core_fns);
+ add_core_fns (&arm_netbsd_elfcore_fns);
+}
diff --git a/contrib/gdb/gdb/armnbsd-tdep.c b/contrib/gdb/gdb/armnbsd-tdep.c
new file mode 100644
index 0000000..0ce46e6
--- /dev/null
+++ b/contrib/gdb/gdb/armnbsd-tdep.c
@@ -0,0 +1,105 @@
+/* Target-specific functions for ARM running under NetBSD.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "osabi.h"
+
+#include "arm-tdep.h"
+#include "nbsd-tdep.h"
+#include "solib-svr4.h"
+
+/* Description of the longjmp buffer. */
+#define ARM_NBSD_JB_PC 24
+#define ARM_NBSD_JB_ELEMENT_SIZE INT_REGISTER_SIZE
+
+/* For compatibility with previous implemenations of GDB on arm/NetBSD,
+ override the default little-endian breakpoint. */
+static const char arm_nbsd_arm_le_breakpoint[] = {0x11, 0x00, 0x00, 0xe6};
+
+static int
+arm_netbsd_aout_in_solib_call_trampoline (CORE_ADDR pc, char *name)
+{
+ if (strcmp (name, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+ return 1;
+
+ return 0;
+}
+
+static void
+arm_netbsd_init_abi_common (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->lowest_pc = 0x8000;
+ tdep->arm_breakpoint = arm_nbsd_arm_le_breakpoint;
+ tdep->arm_breakpoint_size = sizeof (arm_nbsd_arm_le_breakpoint);
+
+ tdep->jb_pc = ARM_NBSD_JB_PC;
+ tdep->jb_elt_size = ARM_NBSD_JB_ELEMENT_SIZE;
+}
+
+static void
+arm_netbsd_aout_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ arm_netbsd_init_abi_common (info, gdbarch);
+
+ set_gdbarch_in_solib_call_trampoline
+ (gdbarch, arm_netbsd_aout_in_solib_call_trampoline);
+ tdep->fp_model = ARM_FLOAT_SOFT_FPA;
+}
+
+static void
+arm_netbsd_elf_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ arm_netbsd_init_abi_common (info, gdbarch);
+
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+
+ tdep->fp_model = ARM_FLOAT_SOFT_VFP;
+}
+
+static enum gdb_osabi
+arm_netbsd_aout_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "a.out-arm-netbsd") == 0)
+ return GDB_OSABI_NETBSD_AOUT;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+void
+_initialize_arm_netbsd_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_arm, bfd_target_aout_flavour,
+ arm_netbsd_aout_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NETBSD_AOUT,
+ arm_netbsd_aout_init_abi);
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NETBSD_ELF,
+ arm_netbsd_elf_init_abi);
+}
diff --git a/contrib/gdb/gdb/auxv.c b/contrib/gdb/gdb/auxv.c
new file mode 100644
index 0000000..a2516b6
--- /dev/null
+++ b/contrib/gdb/gdb/auxv.c
@@ -0,0 +1,300 @@
+/* Auxiliary vector support for GDB, the GNU debugger.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "target.h"
+#include "gdbtypes.h"
+#include "command.h"
+#include "inferior.h"
+#include "valprint.h"
+#include "gdb_assert.h"
+
+#include "auxv.h"
+#include "elf/common.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+
+/* This function is called like a to_xfer_partial hook,
+ but must be called with TARGET_OBJECT_AUXV.
+ It handles access via /proc/PID/auxv, which is the common method.
+ This function is appropriate for doing:
+ #define NATIVE_XFER_AUXV procfs_xfer_auxv
+ for a native target that uses inftarg.c's child_xfer_partial hook. */
+
+LONGEST
+procfs_xfer_auxv (struct target_ops *ops,
+ int /* enum target_object */ object,
+ const char *annex,
+ void *readbuf,
+ const void *writebuf,
+ ULONGEST offset,
+ LONGEST len)
+{
+ char *pathname;
+ int fd;
+ LONGEST n;
+
+ gdb_assert (object == TARGET_OBJECT_AUXV);
+ gdb_assert (readbuf || writebuf);
+
+ pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid));
+ fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY);
+ xfree (pathname);
+ if (fd < 0)
+ return -1;
+
+ if (offset != (ULONGEST) 0
+ && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
+ n = -1;
+ else if (readbuf != NULL)
+ n = read (fd, readbuf, len);
+ else
+ n = write (fd, writebuf, len);
+
+ (void) close (fd);
+
+ return n;
+}
+
+/* Read all the auxv data into a contiguous xmalloc'd buffer,
+ stored in *DATA. Return the size in bytes of this data.
+ If zero, there is no data and *DATA is null.
+ if < 0, there was an error and *DATA is null. */
+LONGEST
+target_auxv_read (struct target_ops *ops, char **data)
+{
+ size_t auxv_alloc = 512, auxv_pos = 0;
+ char *auxv = xmalloc (auxv_alloc);
+ int n;
+
+ while (1)
+ {
+ n = target_read_partial (ops, TARGET_OBJECT_AUXV,
+ NULL, &auxv[auxv_pos], 0,
+ auxv_alloc - auxv_pos);
+ if (n <= 0)
+ break;
+ auxv_pos += n;
+ if (auxv_pos < auxv_alloc) /* Read all there was. */
+ break;
+ gdb_assert (auxv_pos == auxv_alloc);
+ auxv_alloc *= 2;
+ auxv = xrealloc (auxv, auxv_alloc);
+ }
+
+ if (auxv_pos == 0)
+ {
+ xfree (auxv);
+ *data = NULL;
+ return n;
+ }
+
+ *data = auxv;
+ return auxv_pos;
+}
+
+/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
+ Return 0 if *READPTR is already at the end of the buffer.
+ Return -1 if there is insufficient buffer for a whole entry.
+ Return 1 if an entry was read into *TYPEP and *VALP. */
+int
+target_auxv_parse (struct target_ops *ops, char **readptr, char *endptr,
+ CORE_ADDR *typep, CORE_ADDR *valp)
+{
+ const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr);
+ char *ptr = *readptr;
+
+ if (endptr == ptr)
+ return 0;
+
+ if (endptr - ptr < sizeof_auxv_field * 2)
+ return -1;
+
+ *typep = extract_unsigned_integer (ptr, sizeof_auxv_field);
+ ptr += sizeof_auxv_field;
+ *valp = extract_unsigned_integer (ptr, sizeof_auxv_field);
+ ptr += sizeof_auxv_field;
+
+ *readptr = ptr;
+ return 1;
+}
+
+/* Extract the auxiliary vector entry with a_type matching MATCH.
+ Return zero if no such entry was found, or -1 if there was
+ an error getting the information. On success, return 1 after
+ storing the entry's value field in *VALP. */
+int
+target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
+{
+ CORE_ADDR type, val;
+ char *data;
+ int n = target_auxv_read (ops, &data);
+ char *ptr = data;
+ int ents = 0;
+
+ if (n <= 0)
+ return n;
+
+ while (1)
+ switch (target_auxv_parse (ops, &ptr, data + n, &type, &val))
+ {
+ case 1: /* Here's an entry, check it. */
+ if (type == match)
+ {
+ xfree (data);
+ *valp = val;
+ return 1;
+ }
+ break;
+ case 0: /* End of the vector. */
+ xfree (data);
+ return 0;
+ default: /* Bogosity. */
+ xfree (data);
+ return -1;
+ }
+
+ /*NOTREACHED*/
+}
+
+
+/* Print the contents of the target's AUXV on the specified file. */
+int
+fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
+{
+ CORE_ADDR type, val;
+ char *data;
+ int len = target_auxv_read (ops, &data);
+ char *ptr = data;
+ int ents = 0;
+
+ if (len <= 0)
+ return len;
+
+ while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0)
+ {
+ extern int addressprint;
+ const char *name = "???";
+ const char *description = "";
+ enum { dec, hex, str } flavor = hex;
+
+ switch (type)
+ {
+#define TAG(tag, text, kind) \
+ case tag: name = #tag; description = text; flavor = kind; break
+ TAG (AT_NULL, "End of vector", hex);
+ TAG (AT_IGNORE, "Entry should be ignored", hex);
+ TAG (AT_EXECFD, "File descriptor of program", dec);
+ TAG (AT_PHDR, "Program headers for program", hex);
+ TAG (AT_PHENT, "Size of program header entry", dec);
+ TAG (AT_PHNUM, "Number of program headers", dec);
+ TAG (AT_PAGESZ, "System page size", dec);
+ TAG (AT_BASE, "Base address of interpreter", hex);
+ TAG (AT_FLAGS, "Flags", hex);
+ TAG (AT_ENTRY, "Entry point of program", hex);
+ TAG (AT_NOTELF, "Program is not ELF", dec);
+ TAG (AT_UID, "Real user ID", dec);
+ TAG (AT_EUID, "Effective user ID", dec);
+ TAG (AT_GID, "Real group ID", dec);
+ TAG (AT_EGID, "Effective group ID", dec);
+ TAG (AT_CLKTCK, "Frequency of times()", dec);
+ TAG (AT_PLATFORM, "String identifying platform", str);
+ TAG (AT_HWCAP, "Machine-dependent CPU capability hints", hex);
+ TAG (AT_FPUCW, "Used FPU control word", dec);
+ TAG (AT_DCACHEBSIZE, "Data cache block size", dec);
+ TAG (AT_ICACHEBSIZE, "Instruction cache block size", dec);
+ TAG (AT_UCACHEBSIZE, "Unified cache block size", dec);
+ TAG (AT_IGNOREPPC, "Entry should be ignored", dec);
+ TAG (AT_SYSINFO, "Special system info/entry points", hex);
+ TAG (AT_SYSINFO_EHDR, "System-supplied DSO's ELF header", hex);
+ TAG (AT_SECURE, "Boolean, was exec setuid-like?", dec);
+ TAG (AT_SUN_UID, "Effective user ID", dec);
+ TAG (AT_SUN_RUID, "Real user ID", dec);
+ TAG (AT_SUN_GID, "Effective group ID", dec);
+ TAG (AT_SUN_RGID, "Real group ID", dec);
+ TAG (AT_SUN_LDELF, "Dynamic linker's ELF header", hex);
+ TAG (AT_SUN_LDSHDR, "Dynamic linker's section headers", hex);
+ TAG (AT_SUN_LDNAME, "String giving name of dynamic linker", str);
+ TAG (AT_SUN_LPAGESZ, "Large pagesize", dec);
+ TAG (AT_SUN_PLATFORM, "Platform name string", str);
+ TAG (AT_SUN_HWCAP, "Machine-dependent CPU capability hints", hex);
+ TAG (AT_SUN_IFLUSH, "Should flush icache?", dec);
+ TAG (AT_SUN_CPU, "CPU name string", str);
+ TAG (AT_SUN_EMUL_ENTRY, "COFF entry point address", hex);
+ TAG (AT_SUN_EMUL_EXECFD, "COFF executable file descriptor", dec);
+ TAG (AT_SUN_EXECNAME,
+ "Canonicalized file name given to execve", str);
+ TAG (AT_SUN_MMU, "String for name of MMU module", str);
+ TAG (AT_SUN_LDDATA, "Dynamic linker's data segment address", hex);
+ }
+
+ fprintf_filtered (file, "%-4s %-20s %-30s ",
+ paddr_d (type), name, description);
+ switch (flavor)
+ {
+ case dec:
+ fprintf_filtered (file, "%s\n", paddr_d (val));
+ break;
+ case hex:
+ fprintf_filtered (file, "0x%s\n", paddr_nz (val));
+ break;
+ case str:
+ if (addressprint)
+ fprintf_filtered (file, "0x%s", paddr_nz (val));
+ val_print_string (val, -1, 1, file);
+ fprintf_filtered (file, "\n");
+ break;
+ }
+ ++ents;
+ }
+
+ xfree (data);
+
+ return ents;
+}
+
+static void
+info_auxv_command (char *cmd, int from_tty)
+{
+ if (! target_has_stack)
+ error ("The program has no auxiliary information now.");
+ else
+ {
+ int ents = fprint_target_auxv (gdb_stdout, &current_target);
+ if (ents < 0)
+ error ("No auxiliary vector found, or failed reading it.");
+ else if (ents == 0)
+ error ("Auxiliary vector is empty.");
+ }
+}
+
+
+extern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */
+
+void
+_initialize_auxv (void)
+{
+ add_info ("auxv", info_auxv_command,
+ "Display the inferior's auxiliary vector.\n\
+This is information provided by the operating system at program startup.");
+}
diff --git a/contrib/gdb/gdb/auxv.h b/contrib/gdb/gdb/auxv.h
new file mode 100644
index 0000000..4ce0569
--- /dev/null
+++ b/contrib/gdb/gdb/auxv.h
@@ -0,0 +1,75 @@
+/* Auxiliary vector support for GDB, the GNU debugger.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 AUXV_H
+#define AUXV_H
+
+/* See "include/elf/common.h" for the definition of valid AT_* values. */
+
+
+/* Avoid miscellaneous includes in this file, so that it can be
+ included by nm-*.h for the procfs_xfer_auxv decl if that is
+ used in NATIVE_XFER_AUXV. */
+struct target_ops; /* Forward declaration. */
+
+
+/* Read all the auxv data into a contiguous xmalloc'd buffer,
+ stored in *DATA. Return the size in bytes of this data.
+ If zero, there is no data and *DATA is null.
+ if < 0, there was an error and *DATA is null. */
+extern LONGEST target_auxv_read (struct target_ops *ops, char **data);
+
+/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
+ Return 0 if *READPTR is already at the end of the buffer.
+ Return -1 if there is insufficient buffer for a whole entry.
+ Return 1 if an entry was read into *TYPEP and *VALP. */
+extern int target_auxv_parse (struct target_ops *ops,
+ char **readptr, char *endptr,
+ CORE_ADDR *typep, CORE_ADDR *valp);
+
+/* Extract the auxiliary vector entry with a_type matching MATCH.
+ Return zero if no such entry was found, or -1 if there was
+ an error getting the information. On success, return 1 after
+ storing the entry's value field in *VALP. */
+extern int target_auxv_search (struct target_ops *ops,
+ CORE_ADDR match, CORE_ADDR *valp);
+
+/* Print the contents of the target's AUXV on the specified file. */
+extern int fprint_target_auxv (struct ui_file *file, struct target_ops *ops);
+
+
+/* This function is called like a to_xfer_partial hook,
+ but must be called with TARGET_OBJECT_AUXV.
+ It handles access via /proc/PID/auxv, which is the common method.
+ This function is appropriate for doing:
+ #define NATIVE_XFER_AUXV procfs_xfer_auxv
+ for a native target that uses inftarg.c's child_xfer_partial hook. */
+
+extern LONGEST procfs_xfer_auxv (struct target_ops *ops,
+ int /* enum target_object */ object,
+ const char *annex,
+ void *readbuf,
+ const void *writebuf,
+ ULONGEST offset,
+ LONGEST len);
+
+
+#endif
diff --git a/contrib/gdb/gdb/ax-gdb.c b/contrib/gdb/gdb/ax-gdb.c
new file mode 100644
index 0000000..dadad8e
--- /dev/null
+++ b/contrib/gdb/gdb/ax-gdb.c
@@ -0,0 +1,1846 @@
+/* GDB-specific functions for operating on agent expressions.
+
+ Copyright 1998, 1999, 2000, 2001, 2003 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "symfile.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "expression.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "frame.h"
+#include "target.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "gdb_string.h"
+#include "block.h"
+#include "regcache.h"
+
+/* To make sense of this file, you should read doc/agentexpr.texi.
+ Then look at the types and enums in ax-gdb.h. For the code itself,
+ look at gen_expr, towards the bottom; that's the main function that
+ looks at the GDB expressions and calls everything else to generate
+ code.
+
+ I'm beginning to wonder whether it wouldn't be nicer to internally
+ generate trees, with types, and then spit out the bytecode in
+ linear form afterwards; we could generate fewer `swap', `ext', and
+ `zero_ext' bytecodes that way; it would make good constant folding
+ easier, too. But at the moment, I think we should be willing to
+ pay for the simplicity of this code with less-than-optimal bytecode
+ strings.
+
+ Remember, "GBD" stands for "Great Britain, Dammit!" So be careful. */
+
+
+
+/* Prototypes for local functions. */
+
+/* There's a standard order to the arguments of these functions:
+ union exp_element ** --- pointer into expression
+ struct agent_expr * --- agent expression buffer to generate code into
+ struct axs_value * --- describes value left on top of stack */
+
+static struct value *const_var_ref (struct symbol *var);
+static struct value *const_expr (union exp_element **pc);
+static struct value *maybe_const_expr (union exp_element **pc);
+
+static void gen_traced_pop (struct agent_expr *, struct axs_value *);
+
+static void gen_sign_extend (struct agent_expr *, struct type *);
+static void gen_extend (struct agent_expr *, struct type *);
+static void gen_fetch (struct agent_expr *, struct type *);
+static void gen_left_shift (struct agent_expr *, int);
+
+
+static void gen_frame_args_address (struct agent_expr *);
+static void gen_frame_locals_address (struct agent_expr *);
+static void gen_offset (struct agent_expr *ax, int offset);
+static void gen_sym_offset (struct agent_expr *, struct symbol *);
+static void gen_var_ref (struct agent_expr *ax,
+ struct axs_value *value, struct symbol *var);
+
+
+static void gen_int_literal (struct agent_expr *ax,
+ struct axs_value *value,
+ LONGEST k, struct type *type);
+
+
+static void require_rvalue (struct agent_expr *ax, struct axs_value *value);
+static void gen_usual_unary (struct agent_expr *ax, struct axs_value *value);
+static int type_wider_than (struct type *type1, struct type *type2);
+static struct type *max_type (struct type *type1, struct type *type2);
+static void gen_conversion (struct agent_expr *ax,
+ struct type *from, struct type *to);
+static int is_nontrivial_conversion (struct type *from, struct type *to);
+static void gen_usual_arithmetic (struct agent_expr *ax,
+ struct axs_value *value1,
+ struct axs_value *value2);
+static void gen_integral_promotions (struct agent_expr *ax,
+ struct axs_value *value);
+static void gen_cast (struct agent_expr *ax,
+ struct axs_value *value, struct type *type);
+static void gen_scale (struct agent_expr *ax,
+ enum agent_op op, struct type *type);
+static void gen_add (struct agent_expr *ax,
+ struct axs_value *value,
+ struct axs_value *value1,
+ struct axs_value *value2, char *name);
+static void gen_sub (struct agent_expr *ax,
+ struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2);
+static void gen_binop (struct agent_expr *ax,
+ struct axs_value *value,
+ struct axs_value *value1,
+ struct axs_value *value2,
+ enum agent_op op,
+ enum agent_op op_unsigned, int may_carry, char *name);
+static void gen_logical_not (struct agent_expr *ax, struct axs_value *value);
+static void gen_complement (struct agent_expr *ax, struct axs_value *value);
+static void gen_deref (struct agent_expr *, struct axs_value *);
+static void gen_address_of (struct agent_expr *, struct axs_value *);
+static int find_field (struct type *type, char *name);
+static void gen_bitfield_ref (struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *type, int start, int end);
+static void gen_struct_ref (struct agent_expr *ax,
+ struct axs_value *value,
+ char *field,
+ char *operator_name, char *operand_name);
+static void gen_repeat (union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value);
+static void gen_sizeof (union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value);
+static void gen_expr (union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value);
+
+static void agent_command (char *exp, int from_tty);
+
+
+/* Detecting constant expressions. */
+
+/* If the variable reference at *PC is a constant, return its value.
+ Otherwise, return zero.
+
+ Hey, Wally! How can a variable reference be a constant?
+
+ Well, Beav, this function really handles the OP_VAR_VALUE operator,
+ not specifically variable references. GDB uses OP_VAR_VALUE to
+ refer to any kind of symbolic reference: function names, enum
+ elements, and goto labels are all handled through the OP_VAR_VALUE
+ operator, even though they're constants. It makes sense given the
+ situation.
+
+ Gee, Wally, don'cha wonder sometimes if data representations that
+ subvert commonly accepted definitions of terms in favor of heavily
+ context-specific interpretations are really just a tool of the
+ programming hegemony to preserve their power and exclude the
+ proletariat? */
+
+static struct value *
+const_var_ref (struct symbol *var)
+{
+ struct type *type = SYMBOL_TYPE (var);
+
+ switch (SYMBOL_CLASS (var))
+ {
+ case LOC_CONST:
+ return value_from_longest (type, (LONGEST) SYMBOL_VALUE (var));
+
+ case LOC_LABEL:
+ return value_from_pointer (type, (CORE_ADDR) SYMBOL_VALUE_ADDRESS (var));
+
+ default:
+ return 0;
+ }
+}
+
+
+/* If the expression starting at *PC has a constant value, return it.
+ Otherwise, return zero. If we return a value, then *PC will be
+ advanced to the end of it. If we return zero, *PC could be
+ anywhere. */
+static struct value *
+const_expr (union exp_element **pc)
+{
+ enum exp_opcode op = (*pc)->opcode;
+ struct value *v1;
+
+ switch (op)
+ {
+ case OP_LONG:
+ {
+ struct type *type = (*pc)[1].type;
+ LONGEST k = (*pc)[2].longconst;
+ (*pc) += 4;
+ return value_from_longest (type, k);
+ }
+
+ case OP_VAR_VALUE:
+ {
+ struct value *v = const_var_ref ((*pc)[2].symbol);
+ (*pc) += 4;
+ return v;
+ }
+
+ /* We could add more operators in here. */
+
+ case UNOP_NEG:
+ (*pc)++;
+ v1 = const_expr (pc);
+ if (v1)
+ return value_neg (v1);
+ else
+ return 0;
+
+ default:
+ return 0;
+ }
+}
+
+
+/* Like const_expr, but guarantee also that *PC is undisturbed if the
+ expression is not constant. */
+static struct value *
+maybe_const_expr (union exp_element **pc)
+{
+ union exp_element *tentative_pc = *pc;
+ struct value *v = const_expr (&tentative_pc);
+
+ /* If we got a value, then update the real PC. */
+ if (v)
+ *pc = tentative_pc;
+
+ return v;
+}
+
+
+/* Generating bytecode from GDB expressions: general assumptions */
+
+/* Here are a few general assumptions made throughout the code; if you
+ want to make a change that contradicts one of these, then you'd
+ better scan things pretty thoroughly.
+
+ - We assume that all values occupy one stack element. For example,
+ sometimes we'll swap to get at the left argument to a binary
+ operator. If we decide that void values should occupy no stack
+ elements, or that synthetic arrays (whose size is determined at
+ run time, created by the `@' operator) should occupy two stack
+ elements (address and length), then this will cause trouble.
+
+ - We assume the stack elements are infinitely wide, and that we
+ don't have to worry what happens if the user requests an
+ operation that is wider than the actual interpreter's stack.
+ That is, it's up to the interpreter to handle directly all the
+ integer widths the user has access to. (Woe betide the language
+ with bignums!)
+
+ - We don't support side effects. Thus, we don't have to worry about
+ GCC's generalized lvalues, function calls, etc.
+
+ - We don't support floating point. Many places where we switch on
+ some type don't bother to include cases for floating point; there
+ may be even more subtle ways this assumption exists. For
+ example, the arguments to % must be integers.
+
+ - We assume all subexpressions have a static, unchanging type. If
+ we tried to support convenience variables, this would be a
+ problem.
+
+ - All values on the stack should always be fully zero- or
+ sign-extended.
+
+ (I wasn't sure whether to choose this or its opposite --- that
+ only addresses are assumed extended --- but it turns out that
+ neither convention completely eliminates spurious extend
+ operations (if everything is always extended, then you have to
+ extend after add, because it could overflow; if nothing is
+ extended, then you end up producing extends whenever you change
+ sizes), and this is simpler.) */
+
+
+/* Generating bytecode from GDB expressions: the `trace' kludge */
+
+/* The compiler in this file is a general-purpose mechanism for
+ translating GDB expressions into bytecode. One ought to be able to
+ find a million and one uses for it.
+
+ However, at the moment it is HOPELESSLY BRAIN-DAMAGED for the sake
+ of expediency. Let he who is without sin cast the first stone.
+
+ For the data tracing facility, we need to insert `trace' bytecodes
+ before each data fetch; this records all the memory that the
+ expression touches in the course of evaluation, so that memory will
+ be available when the user later tries to evaluate the expression
+ in GDB.
+
+ This should be done (I think) in a post-processing pass, that walks
+ an arbitrary agent expression and inserts `trace' operations at the
+ appropriate points. But it's much faster to just hack them
+ directly into the code. And since we're in a crunch, that's what
+ I've done.
+
+ Setting the flag trace_kludge to non-zero enables the code that
+ emits the trace bytecodes at the appropriate points. */
+static int trace_kludge;
+
+/* Trace the lvalue on the stack, if it needs it. In either case, pop
+ the value. Useful on the left side of a comma, and at the end of
+ an expression being used for tracing. */
+static void
+gen_traced_pop (struct agent_expr *ax, struct axs_value *value)
+{
+ if (trace_kludge)
+ switch (value->kind)
+ {
+ case axs_rvalue:
+ /* We don't trace rvalues, just the lvalues necessary to
+ produce them. So just dispose of this value. */
+ ax_simple (ax, aop_pop);
+ break;
+
+ case axs_lvalue_memory:
+ {
+ int length = TYPE_LENGTH (value->type);
+
+ /* There's no point in trying to use a trace_quick bytecode
+ here, since "trace_quick SIZE pop" is three bytes, whereas
+ "const8 SIZE trace" is also three bytes, does the same
+ thing, and the simplest code which generates that will also
+ work correctly for objects with large sizes. */
+ ax_const_l (ax, length);
+ ax_simple (ax, aop_trace);
+ }
+ break;
+
+ case axs_lvalue_register:
+ /* We need to mention the register somewhere in the bytecode,
+ so ax_reqs will pick it up and add it to the mask of
+ registers used. */
+ ax_reg (ax, value->u.reg);
+ ax_simple (ax, aop_pop);
+ break;
+ }
+ else
+ /* If we're not tracing, just pop the value. */
+ ax_simple (ax, aop_pop);
+}
+
+
+
+/* Generating bytecode from GDB expressions: helper functions */
+
+/* Assume that the lower bits of the top of the stack is a value of
+ type TYPE, and the upper bits are zero. Sign-extend if necessary. */
+static void
+gen_sign_extend (struct agent_expr *ax, struct type *type)
+{
+ /* Do we need to sign-extend this? */
+ if (!TYPE_UNSIGNED (type))
+ ax_ext (ax, TYPE_LENGTH (type) * TARGET_CHAR_BIT);
+}
+
+
+/* Assume the lower bits of the top of the stack hold a value of type
+ TYPE, and the upper bits are garbage. Sign-extend or truncate as
+ needed. */
+static void
+gen_extend (struct agent_expr *ax, struct type *type)
+{
+ int bits = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
+ /* I just had to. */
+ ((TYPE_UNSIGNED (type) ? ax_zero_ext : ax_ext) (ax, bits));
+}
+
+
+/* Assume that the top of the stack contains a value of type "pointer
+ to TYPE"; generate code to fetch its value. Note that TYPE is the
+ target type, not the pointer type. */
+static void
+gen_fetch (struct agent_expr *ax, struct type *type)
+{
+ if (trace_kludge)
+ {
+ /* Record the area of memory we're about to fetch. */
+ ax_trace_quick (ax, TYPE_LENGTH (type));
+ }
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ /* It's a scalar value, so we know how to dereference it. How
+ many bytes long is it? */
+ switch (TYPE_LENGTH (type))
+ {
+ case 8 / TARGET_CHAR_BIT:
+ ax_simple (ax, aop_ref8);
+ break;
+ case 16 / TARGET_CHAR_BIT:
+ ax_simple (ax, aop_ref16);
+ break;
+ case 32 / TARGET_CHAR_BIT:
+ ax_simple (ax, aop_ref32);
+ break;
+ case 64 / TARGET_CHAR_BIT:
+ ax_simple (ax, aop_ref64);
+ break;
+
+ /* Either our caller shouldn't have asked us to dereference
+ that pointer (other code's fault), or we're not
+ implementing something we should be (this code's fault).
+ In any case, it's a bug the user shouldn't see. */
+ default:
+ internal_error (__FILE__, __LINE__,
+ "gen_fetch: strange size");
+ }
+
+ gen_sign_extend (ax, type);
+ break;
+
+ default:
+ /* Either our caller shouldn't have asked us to dereference that
+ pointer (other code's fault), or we're not implementing
+ something we should be (this code's fault). In any case,
+ it's a bug the user shouldn't see. */
+ internal_error (__FILE__, __LINE__,
+ "gen_fetch: bad type code");
+ }
+}
+
+
+/* Generate code to left shift the top of the stack by DISTANCE bits, or
+ right shift it by -DISTANCE bits if DISTANCE < 0. This generates
+ unsigned (logical) right shifts. */
+static void
+gen_left_shift (struct agent_expr *ax, int distance)
+{
+ if (distance > 0)
+ {
+ ax_const_l (ax, distance);
+ ax_simple (ax, aop_lsh);
+ }
+ else if (distance < 0)
+ {
+ ax_const_l (ax, -distance);
+ ax_simple (ax, aop_rsh_unsigned);
+ }
+}
+
+
+
+/* Generating bytecode from GDB expressions: symbol references */
+
+/* Generate code to push the base address of the argument portion of
+ the top stack frame. */
+static void
+gen_frame_args_address (struct agent_expr *ax)
+{
+ int frame_reg;
+ LONGEST frame_offset;
+
+ TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+ ax_reg (ax, frame_reg);
+ gen_offset (ax, frame_offset);
+}
+
+
+/* Generate code to push the base address of the locals portion of the
+ top stack frame. */
+static void
+gen_frame_locals_address (struct agent_expr *ax)
+{
+ int frame_reg;
+ LONGEST frame_offset;
+
+ TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+ ax_reg (ax, frame_reg);
+ gen_offset (ax, frame_offset);
+}
+
+
+/* Generate code to add OFFSET to the top of the stack. Try to
+ generate short and readable code. We use this for getting to
+ variables on the stack, and structure members. If we were
+ programming in ML, it would be clearer why these are the same
+ thing. */
+static void
+gen_offset (struct agent_expr *ax, int offset)
+{
+ /* It would suffice to simply push the offset and add it, but this
+ makes it easier to read positive and negative offsets in the
+ bytecode. */
+ if (offset > 0)
+ {
+ ax_const_l (ax, offset);
+ ax_simple (ax, aop_add);
+ }
+ else if (offset < 0)
+ {
+ ax_const_l (ax, -offset);
+ ax_simple (ax, aop_sub);
+ }
+}
+
+
+/* In many cases, a symbol's value is the offset from some other
+ address (stack frame, base register, etc.) Generate code to add
+ VAR's value to the top of the stack. */
+static void
+gen_sym_offset (struct agent_expr *ax, struct symbol *var)
+{
+ gen_offset (ax, SYMBOL_VALUE (var));
+}
+
+
+/* Generate code for a variable reference to AX. The variable is the
+ symbol VAR. Set VALUE to describe the result. */
+
+static void
+gen_var_ref (struct agent_expr *ax, struct axs_value *value, struct symbol *var)
+{
+ /* Dereference any typedefs. */
+ value->type = check_typedef (SYMBOL_TYPE (var));
+
+ /* I'm imitating the code in read_var_value. */
+ switch (SYMBOL_CLASS (var))
+ {
+ case LOC_CONST: /* A constant, like an enum value. */
+ ax_const_l (ax, (LONGEST) SYMBOL_VALUE (var));
+ value->kind = axs_rvalue;
+ break;
+
+ case LOC_LABEL: /* A goto label, being used as a value. */
+ ax_const_l (ax, (LONGEST) SYMBOL_VALUE_ADDRESS (var));
+ value->kind = axs_rvalue;
+ break;
+
+ case LOC_CONST_BYTES:
+ internal_error (__FILE__, __LINE__,
+ "gen_var_ref: LOC_CONST_BYTES symbols are not supported");
+
+ /* Variable at a fixed location in memory. Easy. */
+ case LOC_STATIC:
+ /* Push the address of the variable. */
+ ax_const_l (ax, SYMBOL_VALUE_ADDRESS (var));
+ value->kind = axs_lvalue_memory;
+ break;
+
+ case LOC_ARG: /* var lives in argument area of frame */
+ gen_frame_args_address (ax);
+ gen_sym_offset (ax, var);
+ value->kind = axs_lvalue_memory;
+ break;
+
+ case LOC_REF_ARG: /* As above, but the frame slot really
+ holds the address of the variable. */
+ gen_frame_args_address (ax);
+ gen_sym_offset (ax, var);
+ /* Don't assume any particular pointer size. */
+ gen_fetch (ax, lookup_pointer_type (builtin_type_void));
+ value->kind = axs_lvalue_memory;
+ break;
+
+ case LOC_LOCAL: /* var lives in locals area of frame */
+ case LOC_LOCAL_ARG:
+ gen_frame_locals_address (ax);
+ gen_sym_offset (ax, var);
+ value->kind = axs_lvalue_memory;
+ break;
+
+ case LOC_BASEREG: /* relative to some base register */
+ case LOC_BASEREG_ARG:
+ ax_reg (ax, SYMBOL_BASEREG (var));
+ gen_sym_offset (ax, var);
+ value->kind = axs_lvalue_memory;
+ break;
+
+ case LOC_TYPEDEF:
+ error ("Cannot compute value of typedef `%s'.",
+ SYMBOL_PRINT_NAME (var));
+ break;
+
+ case LOC_BLOCK:
+ ax_const_l (ax, BLOCK_START (SYMBOL_BLOCK_VALUE (var)));
+ value->kind = axs_rvalue;
+ break;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ /* Don't generate any code at all; in the process of treating
+ this as an lvalue or rvalue, the caller will generate the
+ right code. */
+ value->kind = axs_lvalue_register;
+ value->u.reg = SYMBOL_VALUE (var);
+ break;
+
+ /* A lot like LOC_REF_ARG, but the pointer lives directly in a
+ register, not on the stack. Simpler than LOC_REGISTER and
+ LOC_REGPARM, because it's just like any other case where the
+ thing has a real address. */
+ case LOC_REGPARM_ADDR:
+ ax_reg (ax, SYMBOL_VALUE (var));
+ value->kind = axs_lvalue_memory;
+ break;
+
+ case LOC_UNRESOLVED:
+ {
+ struct minimal_symbol *msym
+ = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (var), NULL, NULL);
+ if (!msym)
+ error ("Couldn't resolve symbol `%s'.", SYMBOL_PRINT_NAME (var));
+
+ /* Push the address of the variable. */
+ ax_const_l (ax, SYMBOL_VALUE_ADDRESS (msym));
+ value->kind = axs_lvalue_memory;
+ }
+ break;
+
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ /* FIXME: cagney/2004-01-26: It should be possible to
+ unconditionally call the SYMBOL_OPS method when available.
+ Unfortunately DWARF 2 stores the frame-base (instead of the
+ function) location in a function's symbol. Oops! For the
+ moment enable this when/where applicable. */
+ SYMBOL_OPS (var)->tracepoint_var_ref (var, ax, value);
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ error ("The variable `%s' has been optimized out.",
+ SYMBOL_PRINT_NAME (var));
+ break;
+
+ default:
+ error ("Cannot find value of botched symbol `%s'.",
+ SYMBOL_PRINT_NAME (var));
+ break;
+ }
+}
+
+
+
+/* Generating bytecode from GDB expressions: literals */
+
+static void
+gen_int_literal (struct agent_expr *ax, struct axs_value *value, LONGEST k,
+ struct type *type)
+{
+ ax_const_l (ax, k);
+ value->kind = axs_rvalue;
+ value->type = type;
+}
+
+
+
+/* Generating bytecode from GDB expressions: unary conversions, casts */
+
+/* Take what's on the top of the stack (as described by VALUE), and
+ try to make an rvalue out of it. Signal an error if we can't do
+ that. */
+static void
+require_rvalue (struct agent_expr *ax, struct axs_value *value)
+{
+ switch (value->kind)
+ {
+ case axs_rvalue:
+ /* It's already an rvalue. */
+ break;
+
+ case axs_lvalue_memory:
+ /* The top of stack is the address of the object. Dereference. */
+ gen_fetch (ax, value->type);
+ break;
+
+ case axs_lvalue_register:
+ /* There's nothing on the stack, but value->u.reg is the
+ register number containing the value.
+
+ When we add floating-point support, this is going to have to
+ change. What about SPARC register pairs, for example? */
+ ax_reg (ax, value->u.reg);
+ gen_extend (ax, value->type);
+ break;
+ }
+
+ value->kind = axs_rvalue;
+}
+
+
+/* Assume the top of the stack is described by VALUE, and perform the
+ usual unary conversions. This is motivated by ANSI 6.2.2, but of
+ course GDB expressions are not ANSI; they're the mishmash union of
+ a bunch of languages. Rah.
+
+ NOTE! This function promises to produce an rvalue only when the
+ incoming value is of an appropriate type. In other words, the
+ consumer of the value this function produces may assume the value
+ is an rvalue only after checking its type.
+
+ The immediate issue is that if the user tries to use a structure or
+ union as an operand of, say, the `+' operator, we don't want to try
+ to convert that structure to an rvalue; require_rvalue will bomb on
+ structs and unions. Rather, we want to simply pass the struct
+ lvalue through unchanged, and let `+' raise an error. */
+
+static void
+gen_usual_unary (struct agent_expr *ax, struct axs_value *value)
+{
+ /* We don't have to generate any code for the usual integral
+ conversions, since values are always represented as full-width on
+ the stack. Should we tweak the type? */
+
+ /* Some types require special handling. */
+ switch (TYPE_CODE (value->type))
+ {
+ /* Functions get converted to a pointer to the function. */
+ case TYPE_CODE_FUNC:
+ value->type = lookup_pointer_type (value->type);
+ value->kind = axs_rvalue; /* Should always be true, but just in case. */
+ break;
+
+ /* Arrays get converted to a pointer to their first element, and
+ are no longer an lvalue. */
+ case TYPE_CODE_ARRAY:
+ {
+ struct type *elements = TYPE_TARGET_TYPE (value->type);
+ value->type = lookup_pointer_type (elements);
+ value->kind = axs_rvalue;
+ /* We don't need to generate any code; the address of the array
+ is also the address of its first element. */
+ }
+ break;
+
+ /* Don't try to convert structures and unions to rvalues. Let the
+ consumer signal an error. */
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return;
+
+ /* If the value is an enum, call it an integer. */
+ case TYPE_CODE_ENUM:
+ value->type = builtin_type_int;
+ break;
+ }
+
+ /* If the value is an lvalue, dereference it. */
+ require_rvalue (ax, value);
+}
+
+
+/* Return non-zero iff the type TYPE1 is considered "wider" than the
+ type TYPE2, according to the rules described in gen_usual_arithmetic. */
+static int
+type_wider_than (struct type *type1, struct type *type2)
+{
+ return (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)
+ || (TYPE_LENGTH (type1) == TYPE_LENGTH (type2)
+ && TYPE_UNSIGNED (type1)
+ && !TYPE_UNSIGNED (type2)));
+}
+
+
+/* Return the "wider" of the two types TYPE1 and TYPE2. */
+static struct type *
+max_type (struct type *type1, struct type *type2)
+{
+ return type_wider_than (type1, type2) ? type1 : type2;
+}
+
+
+/* Generate code to convert a scalar value of type FROM to type TO. */
+static void
+gen_conversion (struct agent_expr *ax, struct type *from, struct type *to)
+{
+ /* Perhaps there is a more graceful way to state these rules. */
+
+ /* If we're converting to a narrower type, then we need to clear out
+ the upper bits. */
+ if (TYPE_LENGTH (to) < TYPE_LENGTH (from))
+ gen_extend (ax, from);
+
+ /* If the two values have equal width, but different signednesses,
+ then we need to extend. */
+ else if (TYPE_LENGTH (to) == TYPE_LENGTH (from))
+ {
+ if (TYPE_UNSIGNED (from) != TYPE_UNSIGNED (to))
+ gen_extend (ax, to);
+ }
+
+ /* If we're converting to a wider type, and becoming unsigned, then
+ we need to zero out any possible sign bits. */
+ else if (TYPE_LENGTH (to) > TYPE_LENGTH (from))
+ {
+ if (TYPE_UNSIGNED (to))
+ gen_extend (ax, to);
+ }
+}
+
+
+/* Return non-zero iff the type FROM will require any bytecodes to be
+ emitted to be converted to the type TO. */
+static int
+is_nontrivial_conversion (struct type *from, struct type *to)
+{
+ struct agent_expr *ax = new_agent_expr (0);
+ int nontrivial;
+
+ /* Actually generate the code, and see if anything came out. At the
+ moment, it would be trivial to replicate the code in
+ gen_conversion here, but in the future, when we're supporting
+ floating point and the like, it may not be. Doing things this
+ way allows this function to be independent of the logic in
+ gen_conversion. */
+ gen_conversion (ax, from, to);
+ nontrivial = ax->len > 0;
+ free_agent_expr (ax);
+ return nontrivial;
+}
+
+
+/* Generate code to perform the "usual arithmetic conversions" (ANSI C
+ 6.2.1.5) for the two operands of an arithmetic operator. This
+ effectively finds a "least upper bound" type for the two arguments,
+ and promotes each argument to that type. *VALUE1 and *VALUE2
+ describe the values as they are passed in, and as they are left. */
+static void
+gen_usual_arithmetic (struct agent_expr *ax, struct axs_value *value1,
+ struct axs_value *value2)
+{
+ /* Do the usual binary conversions. */
+ if (TYPE_CODE (value1->type) == TYPE_CODE_INT
+ && TYPE_CODE (value2->type) == TYPE_CODE_INT)
+ {
+ /* The ANSI integral promotions seem to work this way: Order the
+ integer types by size, and then by signedness: an n-bit
+ unsigned type is considered "wider" than an n-bit signed
+ type. Promote to the "wider" of the two types, and always
+ promote at least to int. */
+ struct type *target = max_type (builtin_type_int,
+ max_type (value1->type, value2->type));
+
+ /* Deal with value2, on the top of the stack. */
+ gen_conversion (ax, value2->type, target);
+
+ /* Deal with value1, not on the top of the stack. Don't
+ generate the `swap' instructions if we're not actually going
+ to do anything. */
+ if (is_nontrivial_conversion (value1->type, target))
+ {
+ ax_simple (ax, aop_swap);
+ gen_conversion (ax, value1->type, target);
+ ax_simple (ax, aop_swap);
+ }
+
+ value1->type = value2->type = target;
+ }
+}
+
+
+/* Generate code to perform the integral promotions (ANSI 6.2.1.1) on
+ the value on the top of the stack, as described by VALUE. Assume
+ the value has integral type. */
+static void
+gen_integral_promotions (struct agent_expr *ax, struct axs_value *value)
+{
+ if (!type_wider_than (value->type, builtin_type_int))
+ {
+ gen_conversion (ax, value->type, builtin_type_int);
+ value->type = builtin_type_int;
+ }
+ else if (!type_wider_than (value->type, builtin_type_unsigned_int))
+ {
+ gen_conversion (ax, value->type, builtin_type_unsigned_int);
+ value->type = builtin_type_unsigned_int;
+ }
+}
+
+
+/* Generate code for a cast to TYPE. */
+static void
+gen_cast (struct agent_expr *ax, struct axs_value *value, struct type *type)
+{
+ /* GCC does allow casts to yield lvalues, so this should be fixed
+ before merging these changes into the trunk. */
+ require_rvalue (ax, value);
+ /* Dereference typedefs. */
+ type = check_typedef (type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ /* It's implementation-defined, and I'll bet this is what GCC
+ does. */
+ break;
+
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_FUNC:
+ error ("Illegal type cast: intended type must be scalar.");
+
+ case TYPE_CODE_ENUM:
+ /* We don't have to worry about the size of the value, because
+ all our integral values are fully sign-extended, and when
+ casting pointers we can do anything we like. Is there any
+ way for us to actually know what GCC actually does with a
+ cast like this? */
+ value->type = type;
+ break;
+
+ case TYPE_CODE_INT:
+ gen_conversion (ax, value->type, type);
+ break;
+
+ case TYPE_CODE_VOID:
+ /* We could pop the value, and rely on everyone else to check
+ the type and notice that this value doesn't occupy a stack
+ slot. But for now, leave the value on the stack, and
+ preserve the "value == stack element" assumption. */
+ break;
+
+ default:
+ error ("Casts to requested type are not yet implemented.");
+ }
+
+ value->type = type;
+}
+
+
+
+/* Generating bytecode from GDB expressions: arithmetic */
+
+/* Scale the integer on the top of the stack by the size of the target
+ of the pointer type TYPE. */
+static void
+gen_scale (struct agent_expr *ax, enum agent_op op, struct type *type)
+{
+ struct type *element = TYPE_TARGET_TYPE (type);
+
+ if (TYPE_LENGTH (element) != 1)
+ {
+ ax_const_l (ax, TYPE_LENGTH (element));
+ ax_simple (ax, op);
+ }
+}
+
+
+/* Generate code for an addition; non-trivial because we deal with
+ pointer arithmetic. We set VALUE to describe the result value; we
+ assume VALUE1 and VALUE2 describe the two operands, and that
+ they've undergone the usual binary conversions. Used by both
+ BINOP_ADD and BINOP_SUBSCRIPT. NAME is used in error messages. */
+static void
+gen_add (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2, char *name)
+{
+ /* Is it INT+PTR? */
+ if (TYPE_CODE (value1->type) == TYPE_CODE_INT
+ && TYPE_CODE (value2->type) == TYPE_CODE_PTR)
+ {
+ /* Swap the values and proceed normally. */
+ ax_simple (ax, aop_swap);
+ gen_scale (ax, aop_mul, value2->type);
+ ax_simple (ax, aop_add);
+ gen_extend (ax, value2->type); /* Catch overflow. */
+ value->type = value2->type;
+ }
+
+ /* Is it PTR+INT? */
+ else if (TYPE_CODE (value1->type) == TYPE_CODE_PTR
+ && TYPE_CODE (value2->type) == TYPE_CODE_INT)
+ {
+ gen_scale (ax, aop_mul, value1->type);
+ ax_simple (ax, aop_add);
+ gen_extend (ax, value1->type); /* Catch overflow. */
+ value->type = value1->type;
+ }
+
+ /* Must be number + number; the usual binary conversions will have
+ brought them both to the same width. */
+ else if (TYPE_CODE (value1->type) == TYPE_CODE_INT
+ && TYPE_CODE (value2->type) == TYPE_CODE_INT)
+ {
+ ax_simple (ax, aop_add);
+ gen_extend (ax, value1->type); /* Catch overflow. */
+ value->type = value1->type;
+ }
+
+ else
+ error ("Illegal combination of types in %s.", name);
+
+ value->kind = axs_rvalue;
+}
+
+
+/* Generate code for an addition; non-trivial because we have to deal
+ with pointer arithmetic. We set VALUE to describe the result
+ value; we assume VALUE1 and VALUE2 describe the two operands, and
+ that they've undergone the usual binary conversions. */
+static void
+gen_sub (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2)
+{
+ if (TYPE_CODE (value1->type) == TYPE_CODE_PTR)
+ {
+ /* Is it PTR - INT? */
+ if (TYPE_CODE (value2->type) == TYPE_CODE_INT)
+ {
+ gen_scale (ax, aop_mul, value1->type);
+ ax_simple (ax, aop_sub);
+ gen_extend (ax, value1->type); /* Catch overflow. */
+ value->type = value1->type;
+ }
+
+ /* Is it PTR - PTR? Strictly speaking, the types ought to
+ match, but this is what the normal GDB expression evaluator
+ tests for. */
+ else if (TYPE_CODE (value2->type) == TYPE_CODE_PTR
+ && (TYPE_LENGTH (TYPE_TARGET_TYPE (value1->type))
+ == TYPE_LENGTH (TYPE_TARGET_TYPE (value2->type))))
+ {
+ ax_simple (ax, aop_sub);
+ gen_scale (ax, aop_div_unsigned, value1->type);
+ value->type = builtin_type_long; /* FIXME --- should be ptrdiff_t */
+ }
+ else
+ error ("\
+First argument of `-' is a pointer, but second argument is neither\n\
+an integer nor a pointer of the same type.");
+ }
+
+ /* Must be number + number. */
+ else if (TYPE_CODE (value1->type) == TYPE_CODE_INT
+ && TYPE_CODE (value2->type) == TYPE_CODE_INT)
+ {
+ ax_simple (ax, aop_sub);
+ gen_extend (ax, value1->type); /* Catch overflow. */
+ value->type = value1->type;
+ }
+
+ else
+ error ("Illegal combination of types in subtraction.");
+
+ value->kind = axs_rvalue;
+}
+
+/* Generate code for a binary operator that doesn't do pointer magic.
+ We set VALUE to describe the result value; we assume VALUE1 and
+ VALUE2 describe the two operands, and that they've undergone the
+ usual binary conversions. MAY_CARRY should be non-zero iff the
+ result needs to be extended. NAME is the English name of the
+ operator, used in error messages */
+static void
+gen_binop (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2, enum agent_op op,
+ enum agent_op op_unsigned, int may_carry, char *name)
+{
+ /* We only handle INT op INT. */
+ if ((TYPE_CODE (value1->type) != TYPE_CODE_INT)
+ || (TYPE_CODE (value2->type) != TYPE_CODE_INT))
+ error ("Illegal combination of types in %s.", name);
+
+ ax_simple (ax,
+ TYPE_UNSIGNED (value1->type) ? op_unsigned : op);
+ if (may_carry)
+ gen_extend (ax, value1->type); /* catch overflow */
+ value->type = value1->type;
+ value->kind = axs_rvalue;
+}
+
+
+static void
+gen_logical_not (struct agent_expr *ax, struct axs_value *value)
+{
+ if (TYPE_CODE (value->type) != TYPE_CODE_INT
+ && TYPE_CODE (value->type) != TYPE_CODE_PTR)
+ error ("Illegal type of operand to `!'.");
+
+ gen_usual_unary (ax, value);
+ ax_simple (ax, aop_log_not);
+ value->type = builtin_type_int;
+}
+
+
+static void
+gen_complement (struct agent_expr *ax, struct axs_value *value)
+{
+ if (TYPE_CODE (value->type) != TYPE_CODE_INT)
+ error ("Illegal type of operand to `~'.");
+
+ gen_usual_unary (ax, value);
+ gen_integral_promotions (ax, value);
+ ax_simple (ax, aop_bit_not);
+ gen_extend (ax, value->type);
+}
+
+
+
+/* Generating bytecode from GDB expressions: * & . -> @ sizeof */
+
+/* Dereference the value on the top of the stack. */
+static void
+gen_deref (struct agent_expr *ax, struct axs_value *value)
+{
+ /* The caller should check the type, because several operators use
+ this, and we don't know what error message to generate. */
+ if (TYPE_CODE (value->type) != TYPE_CODE_PTR)
+ internal_error (__FILE__, __LINE__,
+ "gen_deref: expected a pointer");
+
+ /* We've got an rvalue now, which is a pointer. We want to yield an
+ lvalue, whose address is exactly that pointer. So we don't
+ actually emit any code; we just change the type from "Pointer to
+ T" to "T", and mark the value as an lvalue in memory. Leave it
+ to the consumer to actually dereference it. */
+ value->type = check_typedef (TYPE_TARGET_TYPE (value->type));
+ value->kind = ((TYPE_CODE (value->type) == TYPE_CODE_FUNC)
+ ? axs_rvalue : axs_lvalue_memory);
+}
+
+
+/* Produce the address of the lvalue on the top of the stack. */
+static void
+gen_address_of (struct agent_expr *ax, struct axs_value *value)
+{
+ /* Special case for taking the address of a function. The ANSI
+ standard describes this as a special case, too, so this
+ arrangement is not without motivation. */
+ if (TYPE_CODE (value->type) == TYPE_CODE_FUNC)
+ /* The value's already an rvalue on the stack, so we just need to
+ change the type. */
+ value->type = lookup_pointer_type (value->type);
+ else
+ switch (value->kind)
+ {
+ case axs_rvalue:
+ error ("Operand of `&' is an rvalue, which has no address.");
+
+ case axs_lvalue_register:
+ error ("Operand of `&' is in a register, and has no address.");
+
+ case axs_lvalue_memory:
+ value->kind = axs_rvalue;
+ value->type = lookup_pointer_type (value->type);
+ break;
+ }
+}
+
+
+/* A lot of this stuff will have to change to support C++. But we're
+ not going to deal with that at the moment. */
+
+/* Find the field in the structure type TYPE named NAME, and return
+ its index in TYPE's field array. */
+static int
+find_field (struct type *type, char *name)
+{
+ int i;
+
+ CHECK_TYPEDEF (type);
+
+ /* Make sure this isn't C++. */
+ if (TYPE_N_BASECLASSES (type) != 0)
+ internal_error (__FILE__, __LINE__,
+ "find_field: derived classes supported");
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ char *this_name = TYPE_FIELD_NAME (type, i);
+
+ if (this_name && strcmp (name, this_name) == 0)
+ return i;
+
+ if (this_name[0] == '\0')
+ internal_error (__FILE__, __LINE__,
+ "find_field: anonymous unions not supported");
+ }
+
+ error ("Couldn't find member named `%s' in struct/union `%s'",
+ name, TYPE_TAG_NAME (type));
+
+ return 0;
+}
+
+
+/* Generate code to push the value of a bitfield of a structure whose
+ address is on the top of the stack. START and END give the
+ starting and one-past-ending *bit* numbers of the field within the
+ structure. */
+static void
+gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
+ struct type *type, int start, int end)
+{
+ /* Note that ops[i] fetches 8 << i bits. */
+ static enum agent_op ops[]
+ =
+ {aop_ref8, aop_ref16, aop_ref32, aop_ref64};
+ static int num_ops = (sizeof (ops) / sizeof (ops[0]));
+
+ /* We don't want to touch any byte that the bitfield doesn't
+ actually occupy; we shouldn't make any accesses we're not
+ explicitly permitted to. We rely here on the fact that the
+ bytecode `ref' operators work on unaligned addresses.
+
+ It takes some fancy footwork to get the stack to work the way
+ we'd like. Say we're retrieving a bitfield that requires three
+ fetches. Initially, the stack just contains the address:
+ addr
+ For the first fetch, we duplicate the address
+ addr addr
+ then add the byte offset, do the fetch, and shift and mask as
+ needed, yielding a fragment of the value, properly aligned for
+ the final bitwise or:
+ addr frag1
+ then we swap, and repeat the process:
+ frag1 addr --- address on top
+ frag1 addr addr --- duplicate it
+ frag1 addr frag2 --- get second fragment
+ frag1 frag2 addr --- swap again
+ frag1 frag2 frag3 --- get third fragment
+ Notice that, since the third fragment is the last one, we don't
+ bother duplicating the address this time. Now we have all the
+ fragments on the stack, and we can simply `or' them together,
+ yielding the final value of the bitfield. */
+
+ /* The first and one-after-last bits in the field, but rounded down
+ and up to byte boundaries. */
+ int bound_start = (start / TARGET_CHAR_BIT) * TARGET_CHAR_BIT;
+ int bound_end = (((end + TARGET_CHAR_BIT - 1)
+ / TARGET_CHAR_BIT)
+ * TARGET_CHAR_BIT);
+
+ /* current bit offset within the structure */
+ int offset;
+
+ /* The index in ops of the opcode we're considering. */
+ int op;
+
+ /* The number of fragments we generated in the process. Probably
+ equal to the number of `one' bits in bytesize, but who cares? */
+ int fragment_count;
+
+ /* Dereference any typedefs. */
+ type = check_typedef (type);
+
+ /* Can we fetch the number of bits requested at all? */
+ if ((end - start) > ((1 << num_ops) * 8))
+ internal_error (__FILE__, __LINE__,
+ "gen_bitfield_ref: bitfield too wide");
+
+ /* Note that we know here that we only need to try each opcode once.
+ That may not be true on machines with weird byte sizes. */
+ offset = bound_start;
+ fragment_count = 0;
+ for (op = num_ops - 1; op >= 0; op--)
+ {
+ /* number of bits that ops[op] would fetch */
+ int op_size = 8 << op;
+
+ /* The stack at this point, from bottom to top, contains zero or
+ more fragments, then the address. */
+
+ /* Does this fetch fit within the bitfield? */
+ if (offset + op_size <= bound_end)
+ {
+ /* Is this the last fragment? */
+ int last_frag = (offset + op_size == bound_end);
+
+ if (!last_frag)
+ ax_simple (ax, aop_dup); /* keep a copy of the address */
+
+ /* Add the offset. */
+ gen_offset (ax, offset / TARGET_CHAR_BIT);
+
+ if (trace_kludge)
+ {
+ /* Record the area of memory we're about to fetch. */
+ ax_trace_quick (ax, op_size / TARGET_CHAR_BIT);
+ }
+
+ /* Perform the fetch. */
+ ax_simple (ax, ops[op]);
+
+ /* Shift the bits we have to their proper position.
+ gen_left_shift will generate right shifts when the operand
+ is negative.
+
+ A big-endian field diagram to ponder:
+ byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7
+ +------++------++------++------++------++------++------++------+
+ xxxxAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCxxxxxxxxxxx
+ ^ ^ ^ ^
+ bit number 16 32 48 53
+ These are bit numbers as supplied by GDB. Note that the
+ bit numbers run from right to left once you've fetched the
+ value!
+
+ A little-endian field diagram to ponder:
+ byte 7 byte 6 byte 5 byte 4 byte 3 byte 2 byte 1 byte 0
+ +------++------++------++------++------++------++------++------+
+ xxxxxxxxxxxAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCxxxx
+ ^ ^ ^ ^ ^
+ bit number 48 32 16 4 0
+
+ In both cases, the most significant end is on the left
+ (i.e. normal numeric writing order), which means that you
+ don't go crazy thinking about `left' and `right' shifts.
+
+ We don't have to worry about masking yet:
+ - If they contain garbage off the least significant end, then we
+ must be looking at the low end of the field, and the right
+ shift will wipe them out.
+ - If they contain garbage off the most significant end, then we
+ must be looking at the most significant end of the word, and
+ the sign/zero extension will wipe them out.
+ - If we're in the interior of the word, then there is no garbage
+ on either end, because the ref operators zero-extend. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ gen_left_shift (ax, end - (offset + op_size));
+ else
+ gen_left_shift (ax, offset - start);
+
+ if (!last_frag)
+ /* Bring the copy of the address up to the top. */
+ ax_simple (ax, aop_swap);
+
+ offset += op_size;
+ fragment_count++;
+ }
+ }
+
+ /* Generate enough bitwise `or' operations to combine all the
+ fragments we left on the stack. */
+ while (fragment_count-- > 1)
+ ax_simple (ax, aop_bit_or);
+
+ /* Sign- or zero-extend the value as appropriate. */
+ ((TYPE_UNSIGNED (type) ? ax_zero_ext : ax_ext) (ax, end - start));
+
+ /* This is *not* an lvalue. Ugh. */
+ value->kind = axs_rvalue;
+ value->type = type;
+}
+
+
+/* Generate code to reference the member named FIELD of a structure or
+ union. The top of the stack, as described by VALUE, should have
+ type (pointer to a)* struct/union. OPERATOR_NAME is the name of
+ the operator being compiled, and OPERAND_NAME is the kind of thing
+ it operates on; we use them in error messages. */
+static void
+gen_struct_ref (struct agent_expr *ax, struct axs_value *value, char *field,
+ char *operator_name, char *operand_name)
+{
+ struct type *type;
+ int i;
+
+ /* Follow pointers until we reach a non-pointer. These aren't the C
+ semantics, but they're what the normal GDB evaluator does, so we
+ should at least be consistent. */
+ while (TYPE_CODE (value->type) == TYPE_CODE_PTR)
+ {
+ gen_usual_unary (ax, value);
+ gen_deref (ax, value);
+ }
+ type = check_typedef (value->type);
+
+ /* This must yield a structure or a union. */
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ error ("The left operand of `%s' is not a %s.",
+ operator_name, operand_name);
+
+ /* And it must be in memory; we don't deal with structure rvalues,
+ or structures living in registers. */
+ if (value->kind != axs_lvalue_memory)
+ error ("Structure does not live in memory.");
+
+ i = find_field (type, field);
+
+ /* Is this a bitfield? */
+ if (TYPE_FIELD_PACKED (type, i))
+ gen_bitfield_ref (ax, value, TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_BITPOS (type, i),
+ (TYPE_FIELD_BITPOS (type, i)
+ + TYPE_FIELD_BITSIZE (type, i)));
+ else
+ {
+ gen_offset (ax, TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT);
+ value->kind = axs_lvalue_memory;
+ value->type = TYPE_FIELD_TYPE (type, i);
+ }
+}
+
+
+/* Generate code for GDB's magical `repeat' operator.
+ LVALUE @ INT creates an array INT elements long, and whose elements
+ have the same type as LVALUE, located in memory so that LVALUE is
+ its first element. For example, argv[0]@argc gives you the array
+ of command-line arguments.
+
+ Unfortunately, because we have to know the types before we actually
+ have a value for the expression, we can't implement this perfectly
+ without changing the type system, having values that occupy two
+ stack slots, doing weird things with sizeof, etc. So we require
+ the right operand to be a constant expression. */
+static void
+gen_repeat (union exp_element **pc, struct agent_expr *ax,
+ struct axs_value *value)
+{
+ struct axs_value value1;
+ /* We don't want to turn this into an rvalue, so no conversions
+ here. */
+ gen_expr (pc, ax, &value1);
+ if (value1.kind != axs_lvalue_memory)
+ error ("Left operand of `@' must be an object in memory.");
+
+ /* Evaluate the length; it had better be a constant. */
+ {
+ struct value *v = const_expr (pc);
+ int length;
+
+ if (!v)
+ error ("Right operand of `@' must be a constant, in agent expressions.");
+ if (TYPE_CODE (v->type) != TYPE_CODE_INT)
+ error ("Right operand of `@' must be an integer.");
+ length = value_as_long (v);
+ if (length <= 0)
+ error ("Right operand of `@' must be positive.");
+
+ /* The top of the stack is already the address of the object, so
+ all we need to do is frob the type of the lvalue. */
+ {
+ /* FIXME-type-allocation: need a way to free this type when we are
+ done with it. */
+ struct type *range
+ = create_range_type (0, builtin_type_int, 0, length - 1);
+ struct type *array = create_array_type (0, value1.type, range);
+
+ value->kind = axs_lvalue_memory;
+ value->type = array;
+ }
+ }
+}
+
+
+/* Emit code for the `sizeof' operator.
+ *PC should point at the start of the operand expression; we advance it
+ to the first instruction after the operand. */
+static void
+gen_sizeof (union exp_element **pc, struct agent_expr *ax,
+ struct axs_value *value)
+{
+ /* We don't care about the value of the operand expression; we only
+ care about its type. However, in the current arrangement, the
+ only way to find an expression's type is to generate code for it.
+ So we generate code for the operand, and then throw it away,
+ replacing it with code that simply pushes its size. */
+ int start = ax->len;
+ gen_expr (pc, ax, value);
+
+ /* Throw away the code we just generated. */
+ ax->len = start;
+
+ ax_const_l (ax, TYPE_LENGTH (value->type));
+ value->kind = axs_rvalue;
+ value->type = builtin_type_int;
+}
+
+
+/* Generating bytecode from GDB expressions: general recursive thingy */
+
+/* A gen_expr function written by a Gen-X'er guy.
+ Append code for the subexpression of EXPR starting at *POS_P to AX. */
+static void
+gen_expr (union exp_element **pc, struct agent_expr *ax,
+ struct axs_value *value)
+{
+ /* Used to hold the descriptions of operand expressions. */
+ struct axs_value value1, value2;
+ enum exp_opcode op = (*pc)[0].opcode;
+
+ /* If we're looking at a constant expression, just push its value. */
+ {
+ struct value *v = maybe_const_expr (pc);
+
+ if (v)
+ {
+ ax_const_l (ax, value_as_long (v));
+ value->kind = axs_rvalue;
+ value->type = check_typedef (VALUE_TYPE (v));
+ return;
+ }
+ }
+
+ /* Otherwise, go ahead and generate code for it. */
+ switch (op)
+ {
+ /* Binary arithmetic operators. */
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_SUBSCRIPT:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+ (*pc)++;
+ gen_expr (pc, ax, &value1);
+ gen_usual_unary (ax, &value1);
+ gen_expr (pc, ax, &value2);
+ gen_usual_unary (ax, &value2);
+ gen_usual_arithmetic (ax, &value1, &value2);
+ switch (op)
+ {
+ case BINOP_ADD:
+ gen_add (ax, value, &value1, &value2, "addition");
+ break;
+ case BINOP_SUB:
+ gen_sub (ax, value, &value1, &value2);
+ break;
+ case BINOP_MUL:
+ gen_binop (ax, value, &value1, &value2,
+ aop_mul, aop_mul, 1, "multiplication");
+ break;
+ case BINOP_DIV:
+ gen_binop (ax, value, &value1, &value2,
+ aop_div_signed, aop_div_unsigned, 1, "division");
+ break;
+ case BINOP_REM:
+ gen_binop (ax, value, &value1, &value2,
+ aop_rem_signed, aop_rem_unsigned, 1, "remainder");
+ break;
+ case BINOP_SUBSCRIPT:
+ gen_add (ax, value, &value1, &value2, "array subscripting");
+ if (TYPE_CODE (value->type) != TYPE_CODE_PTR)
+ error ("Illegal combination of types in array subscripting.");
+ gen_deref (ax, value);
+ break;
+ case BINOP_BITWISE_AND:
+ gen_binop (ax, value, &value1, &value2,
+ aop_bit_and, aop_bit_and, 0, "bitwise and");
+ break;
+
+ case BINOP_BITWISE_IOR:
+ gen_binop (ax, value, &value1, &value2,
+ aop_bit_or, aop_bit_or, 0, "bitwise or");
+ break;
+
+ case BINOP_BITWISE_XOR:
+ gen_binop (ax, value, &value1, &value2,
+ aop_bit_xor, aop_bit_xor, 0, "bitwise exclusive-or");
+ break;
+
+ default:
+ /* We should only list operators in the outer case statement
+ that we actually handle in the inner case statement. */
+ internal_error (__FILE__, __LINE__,
+ "gen_expr: op case sets don't match");
+ }
+ break;
+
+ /* Note that we need to be a little subtle about generating code
+ for comma. In C, we can do some optimizations here because
+ we know the left operand is only being evaluated for effect.
+ However, if the tracing kludge is in effect, then we always
+ need to evaluate the left hand side fully, so that all the
+ variables it mentions get traced. */
+ case BINOP_COMMA:
+ (*pc)++;
+ gen_expr (pc, ax, &value1);
+ /* Don't just dispose of the left operand. We might be tracing,
+ in which case we want to emit code to trace it if it's an
+ lvalue. */
+ gen_traced_pop (ax, &value1);
+ gen_expr (pc, ax, value);
+ /* It's the consumer's responsibility to trace the right operand. */
+ break;
+
+ case OP_LONG: /* some integer constant */
+ {
+ struct type *type = (*pc)[1].type;
+ LONGEST k = (*pc)[2].longconst;
+ (*pc) += 4;
+ gen_int_literal (ax, value, k, type);
+ }
+ break;
+
+ case OP_VAR_VALUE:
+ gen_var_ref (ax, value, (*pc)[2].symbol);
+ (*pc) += 4;
+ break;
+
+ case OP_REGISTER:
+ {
+ int reg = (int) (*pc)[1].longconst;
+ (*pc) += 3;
+ value->kind = axs_lvalue_register;
+ value->u.reg = reg;
+ value->type = register_type (current_gdbarch, reg);
+ }
+ break;
+
+ case OP_INTERNALVAR:
+ error ("GDB agent expressions cannot use convenience variables.");
+
+ /* Weirdo operator: see comments for gen_repeat for details. */
+ case BINOP_REPEAT:
+ /* Note that gen_repeat handles its own argument evaluation. */
+ (*pc)++;
+ gen_repeat (pc, ax, value);
+ break;
+
+ case UNOP_CAST:
+ {
+ struct type *type = (*pc)[1].type;
+ (*pc) += 3;
+ gen_expr (pc, ax, value);
+ gen_cast (ax, value, type);
+ }
+ break;
+
+ case UNOP_MEMVAL:
+ {
+ struct type *type = check_typedef ((*pc)[1].type);
+ (*pc) += 3;
+ gen_expr (pc, ax, value);
+ /* I'm not sure I understand UNOP_MEMVAL entirely. I think
+ it's just a hack for dealing with minsyms; you take some
+ integer constant, pretend it's the address of an lvalue of
+ the given type, and dereference it. */
+ if (value->kind != axs_rvalue)
+ /* This would be weird. */
+ internal_error (__FILE__, __LINE__,
+ "gen_expr: OP_MEMVAL operand isn't an rvalue???");
+ value->type = type;
+ value->kind = axs_lvalue_memory;
+ }
+ break;
+
+ case UNOP_NEG:
+ (*pc)++;
+ /* -FOO is equivalent to 0 - FOO. */
+ gen_int_literal (ax, &value1, (LONGEST) 0, builtin_type_int);
+ gen_usual_unary (ax, &value1); /* shouldn't do much */
+ gen_expr (pc, ax, &value2);
+ gen_usual_unary (ax, &value2);
+ gen_usual_arithmetic (ax, &value1, &value2);
+ gen_sub (ax, value, &value1, &value2);
+ break;
+
+ case UNOP_LOGICAL_NOT:
+ (*pc)++;
+ gen_expr (pc, ax, value);
+ gen_logical_not (ax, value);
+ break;
+
+ case UNOP_COMPLEMENT:
+ (*pc)++;
+ gen_expr (pc, ax, value);
+ gen_complement (ax, value);
+ break;
+
+ case UNOP_IND:
+ (*pc)++;
+ gen_expr (pc, ax, value);
+ gen_usual_unary (ax, value);
+ if (TYPE_CODE (value->type) != TYPE_CODE_PTR)
+ error ("Argument of unary `*' is not a pointer.");
+ gen_deref (ax, value);
+ break;
+
+ case UNOP_ADDR:
+ (*pc)++;
+ gen_expr (pc, ax, value);
+ gen_address_of (ax, value);
+ break;
+
+ case UNOP_SIZEOF:
+ (*pc)++;
+ /* Notice that gen_sizeof handles its own operand, unlike most
+ of the other unary operator functions. This is because we
+ have to throw away the code we generate. */
+ gen_sizeof (pc, ax, value);
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ {
+ int length = (*pc)[1].longconst;
+ char *name = &(*pc)[2].string;
+
+ (*pc) += 4 + BYTES_TO_EXP_ELEM (length + 1);
+ gen_expr (pc, ax, value);
+ if (op == STRUCTOP_STRUCT)
+ gen_struct_ref (ax, value, name, ".", "structure or union");
+ else if (op == STRUCTOP_PTR)
+ gen_struct_ref (ax, value, name, "->",
+ "pointer to a structure or union");
+ else
+ /* If this `if' chain doesn't handle it, then the case list
+ shouldn't mention it, and we shouldn't be here. */
+ internal_error (__FILE__, __LINE__,
+ "gen_expr: unhandled struct case");
+ }
+ break;
+
+ case OP_TYPE:
+ error ("Attempt to use a type name as an expression.");
+
+ default:
+ error ("Unsupported operator in expression.");
+ }
+}
+
+
+
+/* Generating bytecode from GDB expressions: driver */
+
+/* Given a GDB expression EXPR, produce a string of agent bytecode
+ which computes its value. Return the agent expression, and set
+ *VALUE to describe its type, and whether it's an lvalue or rvalue. */
+struct agent_expr *
+expr_to_agent (struct expression *expr, struct axs_value *value)
+{
+ struct cleanup *old_chain = 0;
+ struct agent_expr *ax = new_agent_expr (0);
+ union exp_element *pc;
+
+ old_chain = make_cleanup_free_agent_expr (ax);
+
+ pc = expr->elts;
+ trace_kludge = 0;
+ gen_expr (&pc, ax, value);
+
+ /* We have successfully built the agent expr, so cancel the cleanup
+ request. If we add more cleanups that we always want done, this
+ will have to get more complicated. */
+ discard_cleanups (old_chain);
+ return ax;
+}
+
+
+#if 0 /* not used */
+/* Given a GDB expression EXPR denoting an lvalue in memory, produce a
+ string of agent bytecode which will leave its address and size on
+ the top of stack. Return the agent expression.
+
+ Not sure this function is useful at all. */
+struct agent_expr *
+expr_to_address_and_size (struct expression *expr)
+{
+ struct axs_value value;
+ struct agent_expr *ax = expr_to_agent (expr, &value);
+
+ /* Complain if the result is not a memory lvalue. */
+ if (value.kind != axs_lvalue_memory)
+ {
+ free_agent_expr (ax);
+ error ("Expression does not denote an object in memory.");
+ }
+
+ /* Push the object's size on the stack. */
+ ax_const_l (ax, TYPE_LENGTH (value.type));
+
+ return ax;
+}
+#endif
+
+/* Given a GDB expression EXPR, return bytecode to trace its value.
+ The result will use the `trace' and `trace_quick' bytecodes to
+ record the value of all memory touched by the expression. The
+ caller can then use the ax_reqs function to discover which
+ registers it relies upon. */
+struct agent_expr *
+gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
+{
+ struct cleanup *old_chain = 0;
+ struct agent_expr *ax = new_agent_expr (scope);
+ union exp_element *pc;
+ struct axs_value value;
+
+ old_chain = make_cleanup_free_agent_expr (ax);
+
+ pc = expr->elts;
+ trace_kludge = 1;
+ gen_expr (&pc, ax, &value);
+
+ /* Make sure we record the final object, and get rid of it. */
+ gen_traced_pop (ax, &value);
+
+ /* Oh, and terminate. */
+ ax_simple (ax, aop_end);
+
+ /* We have successfully built the agent expr, so cancel the cleanup
+ request. If we add more cleanups that we always want done, this
+ will have to get more complicated. */
+ discard_cleanups (old_chain);
+ return ax;
+}
+
+static void
+agent_command (char *exp, int from_tty)
+{
+ struct cleanup *old_chain = 0;
+ struct expression *expr;
+ struct agent_expr *agent;
+ struct frame_info *fi = get_current_frame (); /* need current scope */
+
+ /* We don't deal with overlay debugging at the moment. We need to
+ think more carefully about this. If you copy this code into
+ another command, change the error message; the user shouldn't
+ have to know anything about agent expressions. */
+ if (overlay_debugging)
+ error ("GDB can't do agent expression translation with overlays.");
+
+ if (exp == 0)
+ error_no_arg ("expression to translate");
+
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ agent = gen_trace_for_expr (get_frame_pc (fi), expr);
+ make_cleanup_free_agent_expr (agent);
+ ax_print (gdb_stdout, agent);
+
+ /* It would be nice to call ax_reqs here to gather some general info
+ about the expression, and then print out the result. */
+
+ do_cleanups (old_chain);
+ dont_repeat ();
+}
+
+
+/* Initialization code. */
+
+void _initialize_ax_gdb (void);
+void
+_initialize_ax_gdb (void)
+{
+ add_cmd ("agent", class_maintenance, agent_command,
+ "Translate an expression into remote agent bytecode.",
+ &maintenancelist);
+}
diff --git a/contrib/gdb/gdb/ax-gdb.h b/contrib/gdb/gdb/ax-gdb.h
new file mode 100644
index 0000000..b091384
--- /dev/null
+++ b/contrib/gdb/gdb/ax-gdb.h
@@ -0,0 +1,113 @@
+/* GDB-specific functions for operating on agent expressions
+ Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 AX_GDB_H
+#define AX_GDB_H
+
+struct expression;
+
+/* Types and enums */
+
+/* GDB stores expressions in the form of a flattened tree (struct
+ expression), so we just walk that tree and generate agent bytecodes
+ as we go along.
+
+ GDB's normal evaluation uses struct value, which contains the
+ expression's value as well as its address or the register it came
+ from. The `+' operator uses the value, whereas the unary `&'
+ operator will use the address portion. The `=' operator will use
+ the address or register number of its left hand side.
+
+ The issues are different when generating agent bytecode. Given a
+ variable reference expression, we should not necessarily generate
+ code to fetch its value, because the next operator may be `=' or
+ unary `&'. Instead, when we recurse on a subexpression, we
+ indicate whether we want that expression to produce an lvalue or an
+ rvalue. If we requested an lvalue, then the recursive call tells
+ us whether it generated code to compute an address on the stack, or
+ whether the lvalue lives in a register.
+
+ The `axs' prefix here means `agent expression, static', because
+ this is all static analysis of the expression, i.e. analysis which
+ doesn't depend on the contents of memory and registers. */
+
+
+/* Different kinds of agent expression static values. */
+enum axs_lvalue_kind
+ {
+ /* We generated code to compute the subexpression's value.
+ Constants and arithmetic operators yield this. */
+ axs_rvalue,
+
+ /* We generated code to yield the subexpression's value's address on
+ the top of the stack. If the caller needs an rvalue, it should
+ call require_rvalue to produce the rvalue from this address. */
+ axs_lvalue_memory,
+
+ /* We didn't generate any code, and the stack is undisturbed,
+ because the subexpression's value lives in a register; u.reg is
+ the register number. If the caller needs an rvalue, it should
+ call require_rvalue to produce the rvalue from this register
+ number. */
+ axs_lvalue_register
+ };
+
+/* Structure describing what we got from a subexpression. Think of
+ this as parallel to value.h's enum lval_type, except that we're
+ describing a value which will exist when the expression is
+ evaluated in the future, not a value we have in our hand. */
+struct axs_value
+ {
+ enum axs_lvalue_kind kind; /* see above */
+
+ /* The type of the subexpression. Even if lvalue == axs_lvalue_memory,
+ this is the type of the value itself; the value on the stack is a
+ "pointer to" an object of this type. */
+ struct type *type;
+
+ union
+ {
+ /* if kind == axs_lvalue_register, this is the register number */
+ int reg;
+ }
+ u;
+ };
+
+
+/* Translating GDB expressions into agent expressions. */
+
+/* Given a GDB expression EXPR, translate it into the agent bytecode,
+ and return it. FLAGS are from enum expr_to_agent_flags. */
+extern struct agent_expr *expr_to_agent (struct expression *EXPR,
+ struct axs_value *VALUE);
+
+/* Given a GDB expression EXPR denoting an lvalue in memory, produce a
+ string of agent bytecode which will leave its address and size on
+ the top of stack. Return the agent expression. */
+extern struct agent_expr *expr_to_address_and_size (struct expression *EXPR);
+
+/* Given a GDB expression EXPR, return bytecode to trace its value.
+ The result will use the `trace' and `trace_quick' bytecodes to
+ record the value of all memory touched by the expression, and leave
+ no values on the stack. The caller can then use the ax_reqs
+ function to discover which registers the expression uses. */
+extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *);
+
+#endif /* AX_GDB_H */
diff --git a/contrib/gdb/gdb/ax-general.c b/contrib/gdb/gdb/ax-general.c
new file mode 100644
index 0000000..c36c76d
--- /dev/null
+++ b/contrib/gdb/gdb/ax-general.c
@@ -0,0 +1,542 @@
+/* Functions for manipulating expressions designed to be executed on the agent
+ Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Despite what the above comment says about this file being part of
+ GDB, we would like to keep these functions free of GDB
+ dependencies, since we want to be able to use them in contexts
+ outside of GDB (test suites, the stub, etc.) */
+
+#include "defs.h"
+#include "ax.h"
+
+#include "value.h"
+#include "gdb_string.h"
+
+static void grow_expr (struct agent_expr *x, int n);
+
+static void append_const (struct agent_expr *x, LONGEST val, int n);
+
+static LONGEST read_const (struct agent_expr *x, int o, int n);
+
+static void generic_ext (struct agent_expr *x, enum agent_op op, int n);
+
+/* Functions for building expressions. */
+
+/* Allocate a new, empty agent expression. */
+struct agent_expr *
+new_agent_expr (CORE_ADDR scope)
+{
+ struct agent_expr *x = xmalloc (sizeof (*x));
+ x->len = 0;
+ x->size = 1; /* Change this to a larger value once
+ reallocation code is tested. */
+ x->buf = xmalloc (x->size);
+ x->scope = scope;
+
+ return x;
+}
+
+/* Free a agent expression. */
+void
+free_agent_expr (struct agent_expr *x)
+{
+ xfree (x->buf);
+ xfree (x);
+}
+
+static void
+do_free_agent_expr_cleanup (void *x)
+{
+ free_agent_expr (x);
+}
+
+struct cleanup *
+make_cleanup_free_agent_expr (struct agent_expr *x)
+{
+ return make_cleanup (do_free_agent_expr_cleanup, x);
+}
+
+
+/* Make sure that X has room for at least N more bytes. This doesn't
+ affect the length, just the allocated size. */
+static void
+grow_expr (struct agent_expr *x, int n)
+{
+ if (x->len + n > x->size)
+ {
+ x->size *= 2;
+ if (x->size < x->len + n)
+ x->size = x->len + n + 10;
+ x->buf = xrealloc (x->buf, x->size);
+ }
+}
+
+
+/* Append the low N bytes of VAL as an N-byte integer to the
+ expression X, in big-endian order. */
+static void
+append_const (struct agent_expr *x, LONGEST val, int n)
+{
+ int i;
+
+ grow_expr (x, n);
+ for (i = n - 1; i >= 0; i--)
+ {
+ x->buf[x->len + i] = val & 0xff;
+ val >>= 8;
+ }
+ x->len += n;
+}
+
+
+/* Extract an N-byte big-endian unsigned integer from expression X at
+ offset O. */
+static LONGEST
+read_const (struct agent_expr *x, int o, int n)
+{
+ int i;
+ LONGEST accum = 0;
+
+ /* Make sure we're not reading off the end of the expression. */
+ if (o + n > x->len)
+ error ("GDB bug: ax-general.c (read_const): incomplete constant");
+
+ for (i = 0; i < n; i++)
+ accum = (accum << 8) | x->buf[o + i];
+
+ return accum;
+}
+
+
+/* Append a simple operator OP to EXPR. */
+void
+ax_simple (struct agent_expr *x, enum agent_op op)
+{
+ grow_expr (x, 1);
+ x->buf[x->len++] = op;
+}
+
+
+/* Append a sign-extension or zero-extension instruction to EXPR, to
+ extend an N-bit value. */
+static void
+generic_ext (struct agent_expr *x, enum agent_op op, int n)
+{
+ /* N must fit in a byte. */
+ if (n < 0 || n > 255)
+ error ("GDB bug: ax-general.c (generic_ext): bit count out of range");
+ /* That had better be enough range. */
+ if (sizeof (LONGEST) * 8 > 255)
+ error ("GDB bug: ax-general.c (generic_ext): opcode has inadequate range");
+
+ grow_expr (x, 2);
+ x->buf[x->len++] = op;
+ x->buf[x->len++] = n;
+}
+
+
+/* Append a sign-extension instruction to EXPR, to extend an N-bit value. */
+void
+ax_ext (struct agent_expr *x, int n)
+{
+ generic_ext (x, aop_ext, n);
+}
+
+
+/* Append a zero-extension instruction to EXPR, to extend an N-bit value. */
+void
+ax_zero_ext (struct agent_expr *x, int n)
+{
+ generic_ext (x, aop_zero_ext, n);
+}
+
+
+/* Append a trace_quick instruction to EXPR, to record N bytes. */
+void
+ax_trace_quick (struct agent_expr *x, int n)
+{
+ /* N must fit in a byte. */
+ if (n < 0 || n > 255)
+ error ("GDB bug: ax-general.c (ax_trace_quick): size out of range for trace_quick");
+
+ grow_expr (x, 2);
+ x->buf[x->len++] = aop_trace_quick;
+ x->buf[x->len++] = n;
+}
+
+
+/* Append a goto op to EXPR. OP is the actual op (must be aop_goto or
+ aop_if_goto). We assume we don't know the target offset yet,
+ because it's probably a forward branch, so we leave space in EXPR
+ for the target, and return the offset in EXPR of that space, so we
+ can backpatch it once we do know the target offset. Use ax_label
+ to do the backpatching. */
+int
+ax_goto (struct agent_expr *x, enum agent_op op)
+{
+ grow_expr (x, 3);
+ x->buf[x->len + 0] = op;
+ x->buf[x->len + 1] = 0xff;
+ x->buf[x->len + 2] = 0xff;
+ x->len += 3;
+ return x->len - 2;
+}
+
+/* Suppose a given call to ax_goto returns some value PATCH. When you
+ know the offset TARGET that goto should jump to, call
+ ax_label (EXPR, PATCH, TARGET)
+ to patch TARGET into the ax_goto instruction. */
+void
+ax_label (struct agent_expr *x, int patch, int target)
+{
+ /* Make sure the value is in range. Don't accept 0xffff as an
+ offset; that's our magic sentinel value for unpatched branches. */
+ if (target < 0 || target >= 0xffff)
+ error ("GDB bug: ax-general.c (ax_label): label target out of range");
+
+ x->buf[patch] = (target >> 8) & 0xff;
+ x->buf[patch + 1] = target & 0xff;
+}
+
+
+/* Assemble code to push a constant on the stack. */
+void
+ax_const_l (struct agent_expr *x, LONGEST l)
+{
+ static enum agent_op ops[]
+ =
+ {aop_const8, aop_const16, aop_const32, aop_const64};
+ int size;
+ int op;
+
+ /* How big is the number? 'op' keeps track of which opcode to use.
+ Notice that we don't really care whether the original number was
+ signed or unsigned; we always reproduce the value exactly, and
+ use the shortest representation. */
+ for (op = 0, size = 8; size < 64; size *= 2, op++)
+ if (-((LONGEST) 1 << size) <= l && l < ((LONGEST) 1 << size))
+ break;
+
+ /* Emit the right opcode... */
+ ax_simple (x, ops[op]);
+
+ /* Emit the low SIZE bytes as an unsigned number. We know that
+ sign-extending this will yield l. */
+ append_const (x, l, size / 8);
+
+ /* Now, if it was negative, and not full-sized, sign-extend it. */
+ if (l < 0 && size < 64)
+ ax_ext (x, size);
+}
+
+
+void
+ax_const_d (struct agent_expr *x, LONGEST d)
+{
+ /* FIXME: floating-point support not present yet. */
+ error ("GDB bug: ax-general.c (ax_const_d): floating point not supported yet");
+}
+
+
+/* Assemble code to push the value of register number REG on the
+ stack. */
+void
+ax_reg (struct agent_expr *x, int reg)
+{
+ /* Make sure the register number is in range. */
+ if (reg < 0 || reg > 0xffff)
+ error ("GDB bug: ax-general.c (ax_reg): register number out of range");
+ grow_expr (x, 3);
+ x->buf[x->len] = aop_reg;
+ x->buf[x->len + 1] = (reg >> 8) & 0xff;
+ x->buf[x->len + 2] = (reg) & 0xff;
+ x->len += 3;
+}
+
+
+
+/* Functions for disassembling agent expressions, and otherwise
+ debugging the expression compiler. */
+
+struct aop_map aop_map[] =
+{
+ {0, 0, 0, 0, 0},
+ {"float", 0, 0, 0, 0}, /* 0x01 */
+ {"add", 0, 0, 2, 1}, /* 0x02 */
+ {"sub", 0, 0, 2, 1}, /* 0x03 */
+ {"mul", 0, 0, 2, 1}, /* 0x04 */
+ {"div_signed", 0, 0, 2, 1}, /* 0x05 */
+ {"div_unsigned", 0, 0, 2, 1}, /* 0x06 */
+ {"rem_signed", 0, 0, 2, 1}, /* 0x07 */
+ {"rem_unsigned", 0, 0, 2, 1}, /* 0x08 */
+ {"lsh", 0, 0, 2, 1}, /* 0x09 */
+ {"rsh_signed", 0, 0, 2, 1}, /* 0x0a */
+ {"rsh_unsigned", 0, 0, 2, 1}, /* 0x0b */
+ {"trace", 0, 0, 2, 0}, /* 0x0c */
+ {"trace_quick", 1, 0, 1, 1}, /* 0x0d */
+ {"log_not", 0, 0, 1, 1}, /* 0x0e */
+ {"bit_and", 0, 0, 2, 1}, /* 0x0f */
+ {"bit_or", 0, 0, 2, 1}, /* 0x10 */
+ {"bit_xor", 0, 0, 2, 1}, /* 0x11 */
+ {"bit_not", 0, 0, 1, 1}, /* 0x12 */
+ {"equal", 0, 0, 2, 1}, /* 0x13 */
+ {"less_signed", 0, 0, 2, 1}, /* 0x14 */
+ {"less_unsigned", 0, 0, 2, 1}, /* 0x15 */
+ {"ext", 1, 0, 1, 1}, /* 0x16 */
+ {"ref8", 0, 8, 1, 1}, /* 0x17 */
+ {"ref16", 0, 16, 1, 1}, /* 0x18 */
+ {"ref32", 0, 32, 1, 1}, /* 0x19 */
+ {"ref64", 0, 64, 1, 1}, /* 0x1a */
+ {"ref_float", 0, 0, 1, 1}, /* 0x1b */
+ {"ref_double", 0, 0, 1, 1}, /* 0x1c */
+ {"ref_long_double", 0, 0, 1, 1}, /* 0x1d */
+ {"l_to_d", 0, 0, 1, 1}, /* 0x1e */
+ {"d_to_l", 0, 0, 1, 1}, /* 0x1f */
+ {"if_goto", 2, 0, 1, 0}, /* 0x20 */
+ {"goto", 2, 0, 0, 0}, /* 0x21 */
+ {"const8", 1, 8, 0, 1}, /* 0x22 */
+ {"const16", 2, 16, 0, 1}, /* 0x23 */
+ {"const32", 4, 32, 0, 1}, /* 0x24 */
+ {"const64", 8, 64, 0, 1}, /* 0x25 */
+ {"reg", 2, 0, 0, 1}, /* 0x26 */
+ {"end", 0, 0, 0, 0}, /* 0x27 */
+ {"dup", 0, 0, 1, 2}, /* 0x28 */
+ {"pop", 0, 0, 1, 0}, /* 0x29 */
+ {"zero_ext", 1, 0, 1, 1}, /* 0x2a */
+ {"swap", 0, 0, 2, 2}, /* 0x2b */
+ {0, 0, 0, 0, 0}, /* 0x2c */
+ {0, 0, 0, 0, 0}, /* 0x2d */
+ {0, 0, 0, 0, 0}, /* 0x2e */
+ {0, 0, 0, 0, 0}, /* 0x2f */
+ {"trace16", 2, 0, 1, 1}, /* 0x30 */
+};
+
+
+/* Disassemble the expression EXPR, writing to F. */
+void
+ax_print (struct ui_file *f, struct agent_expr *x)
+{
+ int i;
+ int is_float = 0;
+
+ /* Check the size of the name array against the number of entries in
+ the enum, to catch additions that people didn't sync. */
+ if ((sizeof (aop_map) / sizeof (aop_map[0]))
+ != aop_last)
+ error ("GDB bug: ax-general.c (ax_print): opcode map out of sync");
+
+ for (i = 0; i < x->len;)
+ {
+ enum agent_op op = x->buf[i];
+
+ if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
+ || !aop_map[op].name)
+ {
+ fprintf_filtered (f, "%3d <bad opcode %02x>\n", i, op);
+ i++;
+ continue;
+ }
+ if (i + 1 + aop_map[op].op_size > x->len)
+ {
+ fprintf_filtered (f, "%3d <incomplete opcode %s>\n",
+ i, aop_map[op].name);
+ break;
+ }
+
+ fprintf_filtered (f, "%3d %s", i, aop_map[op].name);
+ if (aop_map[op].op_size > 0)
+ {
+ fputs_filtered (" ", f);
+
+ print_longest (f, 'd', 0,
+ read_const (x, i + 1, aop_map[op].op_size));
+ }
+ fprintf_filtered (f, "\n");
+ i += 1 + aop_map[op].op_size;
+
+ is_float = (op == aop_float);
+ }
+}
+
+
+/* Given an agent expression AX, fill in an agent_reqs structure REQS
+ describing it. */
+void
+ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs)
+{
+ int i;
+ int height;
+
+ /* Bit vector for registers used. */
+ int reg_mask_len = 1;
+ unsigned char *reg_mask = xmalloc (reg_mask_len * sizeof (reg_mask[0]));
+
+ /* Jump target table. targets[i] is non-zero iff there is a jump to
+ offset i. */
+ char *targets = (char *) alloca (ax->len * sizeof (targets[0]));
+
+ /* Instruction boundary table. boundary[i] is non-zero iff an
+ instruction starts at offset i. */
+ char *boundary = (char *) alloca (ax->len * sizeof (boundary[0]));
+
+ /* Stack height record. iff either targets[i] or boundary[i] is
+ non-zero, heights[i] is the height the stack should have before
+ executing the bytecode at that point. */
+ int *heights = (int *) alloca (ax->len * sizeof (heights[0]));
+
+ /* Pointer to a description of the present op. */
+ struct aop_map *op;
+
+ memset (reg_mask, 0, reg_mask_len * sizeof (reg_mask[0]));
+ memset (targets, 0, ax->len * sizeof (targets[0]));
+ memset (boundary, 0, ax->len * sizeof (boundary[0]));
+
+ reqs->max_height = reqs->min_height = height = 0;
+ reqs->flaw = agent_flaw_none;
+ reqs->max_data_size = 0;
+
+ for (i = 0; i < ax->len; i += 1 + op->op_size)
+ {
+ if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
+ {
+ reqs->flaw = agent_flaw_bad_instruction;
+ xfree (reg_mask);
+ return;
+ }
+
+ op = &aop_map[ax->buf[i]];
+
+ if (!op->name)
+ {
+ reqs->flaw = agent_flaw_bad_instruction;
+ xfree (reg_mask);
+ return;
+ }
+
+ if (i + 1 + op->op_size > ax->len)
+ {
+ reqs->flaw = agent_flaw_incomplete_instruction;
+ xfree (reg_mask);
+ return;
+ }
+
+ /* If this instruction is a jump target, does the current stack
+ height match the stack height at the jump source? */
+ if (targets[i] && (heights[i] != height))
+ {
+ reqs->flaw = agent_flaw_height_mismatch;
+ xfree (reg_mask);
+ return;
+ }
+
+ boundary[i] = 1;
+ heights[i] = height;
+
+ height -= op->consumed;
+ if (height < reqs->min_height)
+ reqs->min_height = height;
+ height += op->produced;
+ if (height > reqs->max_height)
+ reqs->max_height = height;
+
+ if (op->data_size > reqs->max_data_size)
+ reqs->max_data_size = op->data_size;
+
+ /* For jump instructions, check that the target is a valid
+ offset. If it is, record the fact that that location is a
+ jump target, and record the height we expect there. */
+ if (aop_goto == op - aop_map
+ || aop_if_goto == op - aop_map)
+ {
+ int target = read_const (ax, i + 1, 2);
+ if (target < 0 || target >= ax->len)
+ {
+ reqs->flaw = agent_flaw_bad_jump;
+ xfree (reg_mask);
+ return;
+ }
+ /* Have we already found other jumps to the same location? */
+ else if (targets[target])
+ {
+ if (heights[i] != height)
+ {
+ reqs->flaw = agent_flaw_height_mismatch;
+ xfree (reg_mask);
+ return;
+ }
+ }
+ else
+ {
+ targets[target] = 1;
+ heights[target] = height;
+ }
+ }
+
+ /* For unconditional jumps with a successor, check that the
+ successor is a target, and pick up its stack height. */
+ if (aop_goto == op - aop_map
+ && i + 3 < ax->len)
+ {
+ if (!targets[i + 3])
+ {
+ reqs->flaw = agent_flaw_hole;
+ xfree (reg_mask);
+ return;
+ }
+
+ height = heights[i + 3];
+ }
+
+ /* For reg instructions, record the register in the bit mask. */
+ if (aop_reg == op - aop_map)
+ {
+ int reg = read_const (ax, i + 1, 2);
+ int byte = reg / 8;
+
+ /* Grow the bit mask if necessary. */
+ if (byte >= reg_mask_len)
+ {
+ /* It's not appropriate to double here. This isn't a
+ string buffer. */
+ int new_len = byte + 1;
+ reg_mask = xrealloc (reg_mask,
+ new_len * sizeof (reg_mask[0]));
+ memset (reg_mask + reg_mask_len, 0,
+ (new_len - reg_mask_len) * sizeof (reg_mask[0]));
+ reg_mask_len = new_len;
+ }
+
+ reg_mask[byte] |= 1 << (reg % 8);
+ }
+ }
+
+ /* Check that all the targets are on boundaries. */
+ for (i = 0; i < ax->len; i++)
+ if (targets[i] && !boundary[i])
+ {
+ reqs->flaw = agent_flaw_bad_jump;
+ xfree (reg_mask);
+ return;
+ }
+
+ reqs->final_height = height;
+ reqs->reg_mask_len = reg_mask_len;
+ reqs->reg_mask = reg_mask;
+}
diff --git a/contrib/gdb/gdb/ax.h b/contrib/gdb/gdb/ax.h
new file mode 100644
index 0000000..708dba4
--- /dev/null
+++ b/contrib/gdb/gdb/ax.h
@@ -0,0 +1,292 @@
+/* Definitions for expressions designed to be executed on the agent
+ Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 AGENTEXPR_H
+#define AGENTEXPR_H
+
+#include "doublest.h" /* For DOUBLEST. */
+
+/* It's sometimes useful to be able to debug programs that you can't
+ really stop for more than a fraction of a second. To this end, the
+ user can specify a tracepoint (like a breakpoint, but you don't
+ stop at it), and specify a bunch of expressions to record the
+ values of when that tracepoint is reached. As the program runs,
+ GDB collects the values. At any point (possibly while values are
+ still being collected), the user can display the collected values.
+
+ This is used with remote debugging; we don't really support it on
+ native configurations.
+
+ This means that expressions are being evaluated by the remote agent,
+ which doesn't have any access to the symbol table information, and
+ needs to be small and simple.
+
+ The agent_expr routines and datatypes are a bytecode language
+ designed to be executed by the agent. Agent expressions work in
+ terms of fixed-width values, operators, memory references, and
+ register references. You can evaluate a agent expression just given
+ a bunch of memory and register values to sniff at; you don't need
+ any symbolic information like variable names, types, etc.
+
+ GDB translates source expressions, whose meaning depends on
+ symbolic information, into agent bytecode expressions, whose meaning
+ is independent of symbolic information. This means the agent can
+ evaluate them on the fly without reference to data only available
+ to the host GDB. */
+
+
+/* Agent expression data structures. */
+
+/* The type of an element of the agent expression stack.
+ The bytecode operation indicates which element we should access;
+ the value itself has no typing information. GDB generates all
+ bytecode streams, so we don't have to worry about type errors. */
+
+union agent_val
+ {
+ LONGEST l;
+ DOUBLEST d;
+ };
+
+/* A buffer containing a agent expression. */
+struct agent_expr
+ {
+ unsigned char *buf;
+ int len; /* number of characters used */
+ int size; /* allocated size */
+ CORE_ADDR scope;
+ };
+
+
+
+
+/* The actual values of the various bytecode operations.
+
+ Other independent implementations of the agent bytecode engine will
+ rely on the exact values of these enums, and may not be recompiled
+ when we change this table. The numeric values should remain fixed
+ whenever possible. Thus, we assign them values explicitly here (to
+ allow gaps to form safely), and the disassembly table in
+ agentexpr.h behaves like an opcode map. If you want to see them
+ grouped logically, see doc/agentexpr.texi. */
+
+enum agent_op
+ {
+ aop_float = 0x01,
+ aop_add = 0x02,
+ aop_sub = 0x03,
+ aop_mul = 0x04,
+ aop_div_signed = 0x05,
+ aop_div_unsigned = 0x06,
+ aop_rem_signed = 0x07,
+ aop_rem_unsigned = 0x08,
+ aop_lsh = 0x09,
+ aop_rsh_signed = 0x0a,
+ aop_rsh_unsigned = 0x0b,
+ aop_trace = 0x0c,
+ aop_trace_quick = 0x0d,
+ aop_log_not = 0x0e,
+ aop_bit_and = 0x0f,
+ aop_bit_or = 0x10,
+ aop_bit_xor = 0x11,
+ aop_bit_not = 0x12,
+ aop_equal = 0x13,
+ aop_less_signed = 0x14,
+ aop_less_unsigned = 0x15,
+ aop_ext = 0x16,
+ aop_ref8 = 0x17,
+ aop_ref16 = 0x18,
+ aop_ref32 = 0x19,
+ aop_ref64 = 0x1a,
+ aop_ref_float = 0x1b,
+ aop_ref_double = 0x1c,
+ aop_ref_long_double = 0x1d,
+ aop_l_to_d = 0x1e,
+ aop_d_to_l = 0x1f,
+ aop_if_goto = 0x20,
+ aop_goto = 0x21,
+ aop_const8 = 0x22,
+ aop_const16 = 0x23,
+ aop_const32 = 0x24,
+ aop_const64 = 0x25,
+ aop_reg = 0x26,
+ aop_end = 0x27,
+ aop_dup = 0x28,
+ aop_pop = 0x29,
+ aop_zero_ext = 0x2a,
+ aop_swap = 0x2b,
+ aop_trace16 = 0x30,
+ aop_last
+ };
+
+
+
+/* Functions for building expressions. */
+
+/* Allocate a new, empty agent expression. */
+extern struct agent_expr *new_agent_expr (CORE_ADDR);
+
+/* Free a agent expression. */
+extern void free_agent_expr (struct agent_expr *);
+extern struct cleanup *make_cleanup_free_agent_expr (struct agent_expr *);
+
+/* Append a simple operator OP to EXPR. */
+extern void ax_simple (struct agent_expr *EXPR, enum agent_op OP);
+
+/* Append the floating-point prefix, for the next bytecode. */
+#define ax_float(EXPR) (ax_simple ((EXPR), aop_float))
+
+/* Append a sign-extension instruction to EXPR, to extend an N-bit value. */
+extern void ax_ext (struct agent_expr *EXPR, int N);
+
+/* Append a zero-extension instruction to EXPR, to extend an N-bit value. */
+extern void ax_zero_ext (struct agent_expr *EXPR, int N);
+
+/* Append a trace_quick instruction to EXPR, to record N bytes. */
+extern void ax_trace_quick (struct agent_expr *EXPR, int N);
+
+/* Append a goto op to EXPR. OP is the actual op (must be aop_goto or
+ aop_if_goto). We assume we don't know the target offset yet,
+ because it's probably a forward branch, so we leave space in EXPR
+ for the target, and return the offset in EXPR of that space, so we
+ can backpatch it once we do know the target offset. Use ax_label
+ to do the backpatching. */
+extern int ax_goto (struct agent_expr *EXPR, enum agent_op OP);
+
+/* Suppose a given call to ax_goto returns some value PATCH. When you
+ know the offset TARGET that goto should jump to, call
+ ax_label (EXPR, PATCH, TARGET)
+ to patch TARGET into the ax_goto instruction. */
+extern void ax_label (struct agent_expr *EXPR, int patch, int target);
+
+/* Assemble code to push a constant on the stack. */
+extern void ax_const_l (struct agent_expr *EXPR, LONGEST l);
+extern void ax_const_d (struct agent_expr *EXPR, LONGEST d);
+
+/* Assemble code to push the value of register number REG on the
+ stack. */
+extern void ax_reg (struct agent_expr *EXPR, int REG);
+
+
+/* Functions for printing out expressions, and otherwise debugging
+ things. */
+
+/* Disassemble the expression EXPR, writing to F. */
+extern void ax_print (struct ui_file *f, struct agent_expr * EXPR);
+
+/* An entry in the opcode map. */
+struct aop_map
+ {
+
+ /* The name of the opcode. Null means that this entry is not a
+ valid opcode --- a hole in the opcode space. */
+ char *name;
+
+ /* All opcodes take no operands from the bytecode stream, or take
+ unsigned integers of various sizes. If this is a positive number
+ n, then the opcode is followed by an n-byte operand, which should
+ be printed as an unsigned integer. If this is zero, then the
+ opcode takes no operands from the bytecode stream.
+
+ If we get more complicated opcodes in the future, don't add other
+ magic values of this; that's a crock. Add an `enum encoding'
+ field to this, or something like that. */
+ int op_size;
+
+ /* The size of the data operated upon, in bits, for bytecodes that
+ care about that (ref and const). Zero for all others. */
+ int data_size;
+
+ /* Number of stack elements consumed, and number produced. */
+ int consumed, produced;
+ };
+
+/* Map of the bytecodes, indexed by bytecode number. */
+extern struct aop_map aop_map[];
+
+/* Different kinds of flaws an agent expression might have, as
+ detected by agent_reqs. */
+enum agent_flaws
+ {
+ agent_flaw_none = 0, /* code is good */
+
+ /* There is an invalid instruction in the stream. */
+ agent_flaw_bad_instruction,
+
+ /* There is an incomplete instruction at the end of the expression. */
+ agent_flaw_incomplete_instruction,
+
+ /* agent_reqs was unable to prove that every jump target is to a
+ valid offset. Valid offsets are within the bounds of the
+ expression, and to a valid instruction boundary. */
+ agent_flaw_bad_jump,
+
+ /* agent_reqs was unable to prove to its satisfaction that, for each
+ jump target location, the stack will have the same height whether
+ that location is reached via a jump or by straight execution. */
+ agent_flaw_height_mismatch,
+
+ /* agent_reqs was unable to prove that every instruction following
+ an unconditional jump was the target of some other jump. */
+ agent_flaw_hole
+ };
+
+/* Structure describing the requirements of a bytecode expression. */
+struct agent_reqs
+ {
+
+ /* If the following is not equal to agent_flaw_none, the rest of the
+ information in this structure is suspect. */
+ enum agent_flaws flaw;
+
+ /* Number of elements left on stack at end; may be negative if expr
+ only consumes elements. */
+ int final_height;
+
+ /* Maximum and minimum stack height, relative to initial height. */
+ int max_height, min_height;
+
+ /* Largest `ref' or `const' opcode used, in bits. Zero means the
+ expression has no such instructions. */
+ int max_data_size;
+
+ /* Bit vector of registers used. Register R is used iff
+
+ reg_mask[R / 8] & (1 << (R % 8))
+
+ is non-zero. Note! You may not assume that this bitmask is long
+ enough to hold bits for all the registers of the machine; the
+ agent expression code has no idea how many registers the machine
+ has. However, the bitmask is reg_mask_len bytes long, so the
+ valid register numbers run from 0 to reg_mask_len * 8 - 1.
+
+ We're assuming eight-bit bytes. So sue me.
+
+ The caller should free reg_list when done. */
+ int reg_mask_len;
+ unsigned char *reg_mask;
+ };
+
+
+/* Given an agent expression AX, fill in an agent_reqs structure REQS
+ describing it. */
+extern void ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs);
+
+#endif /* AGENTEXPR_H */
diff --git a/contrib/gdb/gdb/bcache.c b/contrib/gdb/gdb/bcache.c
new file mode 100644
index 0000000..cadadb5
--- /dev/null
+++ b/contrib/gdb/gdb/bcache.c
@@ -0,0 +1,439 @@
+/* Implement a cached obstack.
+ Written by Fred Fish <fnf@cygnus.com>
+ Rewritten by Jim Blandy <jimb@cygnus.com>
+
+ Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_obstack.h"
+#include "bcache.h"
+#include "gdb_string.h" /* For memcpy declaration */
+#include "gdb_assert.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+/* The type used to hold a single bcache string. The user data is
+ stored in d.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. I don't know of any really correct way to do this in
+ stock ANSI C, so just do it the same way obstack.h does. */
+
+struct bstring
+{
+ /* Hash chain. */
+ struct bstring *next;
+ /* Assume the data length is no more than 64k. */
+ unsigned short length;
+ /* The half hash hack. This contains the upper 16 bits of the hash
+ value and is used as a pre-check when comparing two strings and
+ avoids the need to do length or memcmp calls. It proves to be
+ roughly 100% effective. */
+ unsigned short half_hash;
+
+ union
+ {
+ char data[1];
+ double dummy;
+ }
+ d;
+};
+
+
+/* The structure for a bcache itself. The bcache is initialized, in
+ bcache_xmalloc(), by filling it with zeros and then setting the
+ corresponding obstack's malloc() and free() methods. */
+
+struct bcache
+{
+ /* All the bstrings are allocated here. */
+ struct obstack cache;
+
+ /* How many hash buckets we're using. */
+ unsigned int num_buckets;
+
+ /* Hash buckets. This table is allocated using malloc, so when we
+ grow the table we can return the old table to the system. */
+ struct bstring **bucket;
+
+ /* Statistics. */
+ unsigned long unique_count; /* number of unique strings */
+ long total_count; /* total number of strings cached, including dups */
+ long unique_size; /* size of unique strings, in bytes */
+ long total_size; /* total number of bytes cached, including dups */
+ long structure_size; /* total size of bcache, including infrastructure */
+ /* Number of times that the hash table is expanded and hence
+ re-built, and the corresponding number of times that a string is
+ [re]hashed as part of entering it into the expanded table. The
+ total number of hashes can be computed by adding TOTAL_COUNT to
+ expand_hash_count. */
+ unsigned long expand_count;
+ unsigned long expand_hash_count;
+ /* Number of times that the half-hash compare hit (compare the upper
+ 16 bits of hash values) hit, but the corresponding combined
+ length/data compare missed. */
+ unsigned long half_hash_miss_count;
+};
+
+/* The old hash function was stolen from SDBM. This is what DB 3.0 uses now,
+ * and is better than the old one.
+ */
+
+unsigned long
+hash(const void *addr, int length)
+{
+ const unsigned char *k, *e;
+ unsigned long h;
+
+ k = (const unsigned char *)addr;
+ e = k+length;
+ for (h=0; k< e;++k)
+ {
+ h *=16777619;
+ h ^= *k;
+ }
+ return (h);
+}
+
+/* Growing the bcache's hash table. */
+
+/* If the average chain length grows beyond this, then we want to
+ resize our hash table. */
+#define CHAIN_LENGTH_THRESHOLD (5)
+
+static void
+expand_hash_table (struct bcache *bcache)
+{
+ /* A table of good hash table sizes. Whenever we grow, we pick the
+ next larger size from this table. sizes[i] is close to 1 << (i+10),
+ so we roughly double the table size each time. After we fall off
+ the end of this table, we just double. Don't laugh --- there have
+ been executables sighted with a gigabyte of debug info. */
+ static unsigned long sizes[] = {
+ 1021, 2053, 4099, 8191, 16381, 32771,
+ 65537, 131071, 262144, 524287, 1048573, 2097143,
+ 4194301, 8388617, 16777213, 33554467, 67108859, 134217757,
+ 268435459, 536870923, 1073741827, 2147483659UL
+ };
+ unsigned int new_num_buckets;
+ struct bstring **new_buckets;
+ unsigned int i;
+
+ /* Count the stats. Every unique item needs to be re-hashed and
+ re-entered. */
+ bcache->expand_count++;
+ bcache->expand_hash_count += bcache->unique_count;
+
+ /* Find the next size. */
+ new_num_buckets = bcache->num_buckets * 2;
+ for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
+ if (sizes[i] > bcache->num_buckets)
+ {
+ new_num_buckets = sizes[i];
+ break;
+ }
+
+ /* Allocate the new table. */
+ {
+ size_t new_size = new_num_buckets * sizeof (new_buckets[0]);
+ new_buckets = (struct bstring **) xmalloc (new_size);
+ memset (new_buckets, 0, new_size);
+
+ bcache->structure_size -= (bcache->num_buckets
+ * sizeof (bcache->bucket[0]));
+ bcache->structure_size += new_size;
+ }
+
+ /* Rehash all existing strings. */
+ for (i = 0; i < bcache->num_buckets; i++)
+ {
+ struct bstring *s, *next;
+
+ for (s = bcache->bucket[i]; s; s = next)
+ {
+ struct bstring **new_bucket;
+ next = s->next;
+
+ new_bucket = &new_buckets[(hash (&s->d.data, s->length)
+ % new_num_buckets)];
+ s->next = *new_bucket;
+ *new_bucket = s;
+ }
+ }
+
+ /* Plug in the new table. */
+ if (bcache->bucket)
+ xfree (bcache->bucket);
+ bcache->bucket = new_buckets;
+ bcache->num_buckets = new_num_buckets;
+}
+
+
+/* Looking up things in the bcache. */
+
+/* The number of bytes needed to allocate a struct bstring whose data
+ is N bytes long. */
+#define BSTRING_SIZE(n) (offsetof (struct bstring, d.data) + (n))
+
+/* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has
+ never seen those bytes before, add a copy of them to BCACHE. In
+ either case, return a pointer to BCACHE's copy of that string. */
+static void *
+bcache_data (const void *addr, int length, struct bcache *bcache)
+{
+ unsigned long full_hash;
+ unsigned short half_hash;
+ int hash_index;
+ struct bstring *s;
+
+ /* If our average chain length is too high, expand the hash table. */
+ if (bcache->unique_count >= bcache->num_buckets * CHAIN_LENGTH_THRESHOLD)
+ expand_hash_table (bcache);
+
+ bcache->total_count++;
+ bcache->total_size += length;
+
+ full_hash = hash (addr, length);
+ half_hash = (full_hash >> 16);
+ hash_index = full_hash % bcache->num_buckets;
+
+ /* Search the hash bucket for a string identical to the caller's.
+ As a short-circuit first compare the upper part of each hash
+ values. */
+ for (s = bcache->bucket[hash_index]; s; s = s->next)
+ {
+ if (s->half_hash == half_hash)
+ {
+ if (s->length == length
+ && ! memcmp (&s->d.data, addr, length))
+ return &s->d.data;
+ else
+ bcache->half_hash_miss_count++;
+ }
+ }
+
+ /* The user's string isn't in the list. Insert it after *ps. */
+ {
+ struct bstring *new
+ = obstack_alloc (&bcache->cache, BSTRING_SIZE (length));
+ memcpy (&new->d.data, addr, length);
+ new->length = length;
+ new->next = bcache->bucket[hash_index];
+ new->half_hash = half_hash;
+ bcache->bucket[hash_index] = new;
+
+ bcache->unique_count++;
+ bcache->unique_size += length;
+ bcache->structure_size += BSTRING_SIZE (length);
+
+ return &new->d.data;
+ }
+}
+
+void *
+deprecated_bcache (const void *addr, int length, struct bcache *bcache)
+{
+ return bcache_data (addr, length, bcache);
+}
+
+const void *
+bcache (const void *addr, int length, struct bcache *bcache)
+{
+ return bcache_data (addr, length, bcache);
+}
+
+/* Allocating and freeing bcaches. */
+
+struct bcache *
+bcache_xmalloc (void)
+{
+ /* Allocate the bcache pre-zeroed. */
+ struct bcache *b = XCALLOC (1, struct bcache);
+ /* We could use obstack_specify_allocation here instead, but
+ gdb_obstack.h specifies the allocation/deallocation
+ functions. */
+ obstack_init (&b->cache);
+ return b;
+}
+
+/* Free all the storage associated with BCACHE. */
+void
+bcache_xfree (struct bcache *bcache)
+{
+ if (bcache == NULL)
+ return;
+ obstack_free (&bcache->cache, 0);
+ xfree (bcache->bucket);
+ xfree (bcache);
+}
+
+
+
+/* Printing statistics. */
+
+static int
+compare_ints (const void *ap, const void *bp)
+{
+ /* Because we know we're comparing two ints which are positive,
+ there's no danger of overflow here. */
+ return * (int *) ap - * (int *) bp;
+}
+
+
+static void
+print_percentage (int portion, int total)
+{
+ if (total == 0)
+ printf_filtered ("(not applicable)\n");
+ else
+ printf_filtered ("%3d%%\n", portion * 100 / total);
+}
+
+
+/* Print statistics on BCACHE's memory usage and efficacity at
+ eliminating duplication. NAME should describe the kind of data
+ BCACHE holds. Statistics are printed using `printf_filtered' and
+ its ilk. */
+void
+print_bcache_statistics (struct bcache *c, char *type)
+{
+ int occupied_buckets;
+ int max_chain_length;
+ int median_chain_length;
+ int max_entry_size;
+ int median_entry_size;
+
+ /* Count the number of occupied buckets, tally the various string
+ lengths, and measure chain lengths. */
+ {
+ unsigned int b;
+ int *chain_length = XCALLOC (c->num_buckets + 1, int);
+ int *entry_size = XCALLOC (c->unique_count + 1, int);
+ int stringi = 0;
+
+ occupied_buckets = 0;
+
+ for (b = 0; b < c->num_buckets; b++)
+ {
+ struct bstring *s = c->bucket[b];
+
+ chain_length[b] = 0;
+
+ if (s)
+ {
+ occupied_buckets++;
+
+ while (s)
+ {
+ gdb_assert (b < c->num_buckets);
+ chain_length[b]++;
+ gdb_assert (stringi < c->unique_count);
+ entry_size[stringi++] = s->length;
+ s = s->next;
+ }
+ }
+ }
+
+ /* To compute the median, we need the set of chain lengths sorted. */
+ qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
+ compare_ints);
+ qsort (entry_size, c->unique_count, sizeof (entry_size[0]),
+ compare_ints);
+
+ if (c->num_buckets > 0)
+ {
+ max_chain_length = chain_length[c->num_buckets - 1];
+ median_chain_length = chain_length[c->num_buckets / 2];
+ }
+ else
+ {
+ max_chain_length = 0;
+ median_chain_length = 0;
+ }
+ if (c->unique_count > 0)
+ {
+ max_entry_size = entry_size[c->unique_count - 1];
+ median_entry_size = entry_size[c->unique_count / 2];
+ }
+ else
+ {
+ max_entry_size = 0;
+ median_entry_size = 0;
+ }
+
+ xfree (chain_length);
+ xfree (entry_size);
+ }
+
+ printf_filtered (" Cached '%s' statistics:\n", type);
+ printf_filtered (" Total object count: %ld\n", c->total_count);
+ printf_filtered (" Unique object count: %lu\n", c->unique_count);
+ printf_filtered (" Percentage of duplicates, by count: ");
+ print_percentage (c->total_count - c->unique_count, c->total_count);
+ printf_filtered ("\n");
+
+ printf_filtered (" Total object size: %ld\n", c->total_size);
+ printf_filtered (" Unique object size: %ld\n", c->unique_size);
+ printf_filtered (" Percentage of duplicates, by size: ");
+ print_percentage (c->total_size - c->unique_size, c->total_size);
+ printf_filtered ("\n");
+
+ printf_filtered (" Max entry size: %d\n", max_entry_size);
+ printf_filtered (" Average entry size: ");
+ if (c->unique_count > 0)
+ printf_filtered ("%ld\n", c->unique_size / c->unique_count);
+ else
+ printf_filtered ("(not applicable)\n");
+ printf_filtered (" Median entry size: %d\n", median_entry_size);
+ printf_filtered ("\n");
+
+ printf_filtered (" Total memory used by bcache, including overhead: %ld\n",
+ c->structure_size);
+ printf_filtered (" Percentage memory overhead: ");
+ print_percentage (c->structure_size - c->unique_size, c->unique_size);
+ printf_filtered (" Net memory savings: ");
+ print_percentage (c->total_size - c->structure_size, c->total_size);
+ printf_filtered ("\n");
+
+ printf_filtered (" Hash table size: %3d\n", c->num_buckets);
+ printf_filtered (" Hash table expands: %lu\n",
+ c->expand_count);
+ printf_filtered (" Hash table hashes: %lu\n",
+ c->total_count + c->expand_hash_count);
+ printf_filtered (" Half hash misses: %lu\n",
+ c->half_hash_miss_count);
+ printf_filtered (" Hash table population: ");
+ print_percentage (occupied_buckets, c->num_buckets);
+ printf_filtered (" Median hash chain length: %3d\n",
+ median_chain_length);
+ printf_filtered (" Average hash chain length: ");
+ if (c->num_buckets > 0)
+ printf_filtered ("%3lu\n", c->unique_count / c->num_buckets);
+ else
+ printf_filtered ("(not applicable)\n");
+ printf_filtered (" Maximum hash chain length: %3d\n", max_chain_length);
+ printf_filtered ("\n");
+}
+
+int
+bcache_memory_used (struct bcache *bcache)
+{
+ return obstack_memory_used (&bcache->cache);
+}
diff --git a/contrib/gdb/gdb/bcache.h b/contrib/gdb/gdb/bcache.h
new file mode 100644
index 0000000..bf69853
--- /dev/null
+++ b/contrib/gdb/gdb/bcache.h
@@ -0,0 +1,170 @@
+/* Include file cached obstack implementation.
+ Written by Fred Fish <fnf@cygnus.com>
+ Rewritten by Jim Blandy <jimb@cygnus.com>
+
+ Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+/* A bcache is a data structure for factoring out duplication in
+ read-only structures. You give the bcache some string of bytes S.
+ If the bcache already contains a copy of S, it hands you back a
+ pointer to its copy. Otherwise, it makes a fresh copy of S, and
+ hands you back a pointer to that. In either case, you can throw
+ away your copy of S, and use the bcache's.
+
+ The "strings" in question are arbitrary strings of bytes --- they
+ can contain zero bytes. You pass in the length explicitly when you
+ call the bcache function.
+
+ This means that you can put ordinary C objects in a bcache.
+ However, if you do this, remember that structs can contain `holes'
+ between members, added for alignment. These bytes usually contain
+ garbage. If you try to bcache two objects which are identical from
+ your code's point of view, but have different garbage values in the
+ structure's holes, then the bcache will treat them as separate
+ strings, and you won't get the nice elimination of duplicates you
+ were hoping for. So, remember to memset your structures full of
+ zeros before bcaching them!
+
+ You shouldn't modify the strings you get from a bcache, because:
+
+ - You don't necessarily know who you're sharing space with. If I
+ stick eight bytes of text in a bcache, and then stick an eight-byte
+ structure in the same bcache, there's no guarantee those two
+ objects don't actually comprise the same sequence of bytes. If
+ they happen to, the bcache will use a single byte string for both
+ of them. Then, modifying the structure will change the string. In
+ bizarre ways.
+
+ - Even if you know for some other reason that all that's okay,
+ there's another problem. A bcache stores all its strings in a hash
+ table. If you modify a string's contents, you will probably change
+ its hash value. This means that the modified string is now in the
+ wrong place in the hash table, and future bcache probes will never
+ find it. So by mutating a string, you give up any chance of
+ sharing its space with future duplicates.
+
+
+ Size of bcache VS hashtab:
+
+ For bcache, the most critical cost is size (or more exactly the
+ overhead added by the bcache). It turns out that the bcache is
+ remarkably efficient.
+
+ Assuming a 32-bit system (the hash table slots are 4 bytes),
+ ignoring alignment, and limit strings to 255 bytes (1 byte length)
+ we get ...
+
+ bcache: This uses a separate linked list to track the hash chain.
+ The numbers show roughly 100% occupancy of the hash table and an
+ average chain length of 4. Spreading the slot cost over the 4
+ chain elements:
+
+ 4 (slot) / 4 (chain length) + 1 (length) + 4 (chain) = 6 bytes
+
+ hashtab: This uses a more traditional re-hash algorithm where the
+ chain is maintained within the hash table. The table occupancy is
+ kept below 75% but we'll assume its perfect:
+
+ 4 (slot) x 4/3 (occupancy) + 1 (length) = 6 1/3 bytes
+
+ So a perfect hashtab has just slightly larger than an average
+ bcache.
+
+ It turns out that an average hashtab is far worse. Two things
+ hurt:
+
+ - Hashtab's occupancy is more like 50% (it ranges between 38% and
+ 75%) giving a per slot cost of 4x2 vs 4x4/3.
+
+ - the string structure needs to be aligned to 8 bytes which for
+ hashtab wastes 7 bytes, while for bcache wastes only 3.
+
+ This gives:
+
+ hashtab: 4 x 2 + 1 + 7 = 16 bytes
+
+ bcache 4 / 4 + 1 + 4 + 3 = 9 bytes
+
+ The numbers of GDB debugging GDB support this. ~40% vs ~70% overhead.
+
+
+ Speed of bcache VS hashtab (the half hash hack):
+
+ While hashtab has a typical chain length of 1, bcache has a chain
+ length of round 4. This means that the bcache will require
+ something like double the number of compares after that initial
+ hash. In both cases the comparison takes the form:
+
+ a.length == b.length && memcmp (a.data, b.data, a.length) == 0
+
+ That is lengths are checked before doing the memcmp.
+
+ For GDB debugging GDB, it turned out that all lengths were 24 bytes
+ (no C++ so only psymbols were cached) and hence, all compares
+ required a call to memcmp. As a hack, two bytes of padding
+ (mentioned above) are used to store the upper 16 bits of the
+ string's hash value and then that is used in the comparison vis:
+
+ a.half_hash == b.half_hash && a.length == b.length && memcmp
+ (a.data, b.data, a.length)
+
+ The numbers from GDB debugging GDB show this to be a remarkable
+ 100% effective (only necessary length and memcmp tests being
+ performed).
+
+ Mind you, looking at the wall clock, the same GDB debugging GDB
+ showed only marginal speed up (0.780 vs 0.773s). Seems GDB is too
+ busy doing something else :-(
+
+*/
+
+
+struct bcache;
+
+/* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has
+ never seen those bytes before, add a copy of them to BCACHE. In
+ either case, return a pointer to BCACHE's copy of that string.
+ Since the cached value is ment to be read-only, return a const
+ buffer. */
+extern void *deprecated_bcache (const void *addr, int length,
+ struct bcache *bcache);
+extern const void *bcache (const void *addr, int length,
+ struct bcache *bcache);
+
+/* Free all the storage used by BCACHE. */
+extern void bcache_xfree (struct bcache *bcache);
+
+/* Create a new bcache object. */
+extern struct bcache *bcache_xmalloc (void);
+
+/* Print statistics on BCACHE's memory usage and efficacity at
+ eliminating duplication. TYPE should be a string describing the
+ kind of data BCACHE holds. Statistics are printed using
+ `printf_filtered' and its ilk. */
+extern void print_bcache_statistics (struct bcache *bcache, char *type);
+extern int bcache_memory_used (struct bcache *bcache);
+
+/* The hash function */
+extern unsigned long hash(const void *addr, int length);
+
+#endif /* BCACHE_H */
diff --git a/contrib/gdb/gdb/bfd-target.c b/contrib/gdb/gdb/bfd-target.c
new file mode 100644
index 0000000..ee16d85
--- /dev/null
+++ b/contrib/gdb/gdb/bfd-target.c
@@ -0,0 +1,131 @@
+/* Very simple "bfd" target, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "target.h"
+#include "bfd-target.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+/* Locate all mappable sections of a BFD file, filling in a target
+ section for each. */
+
+struct section_closure
+{
+ struct section_table *end;
+};
+
+static void
+add_to_section_table (struct bfd *abfd, struct bfd_section *asect,
+ void *closure)
+{
+ struct section_closure *pp = closure;
+ flagword aflag;
+
+ /* NOTE: cagney/2003-10-22: Is this pruning useful? */
+ aflag = bfd_get_section_flags (abfd, asect);
+ if (!(aflag & SEC_ALLOC))
+ return;
+ if (bfd_section_size (abfd, asect) == 0)
+ return;
+ pp->end->bfd = abfd;
+ pp->end->the_bfd_section = asect;
+ pp->end->addr = bfd_section_vma (abfd, asect);
+ pp->end->endaddr = pp->end->addr + bfd_section_size (abfd, asect);
+ pp->end++;
+}
+
+void
+build_target_sections_from_bfd (struct target_ops *targ, struct bfd *abfd)
+{
+ unsigned count;
+ struct section_table *start;
+ struct section_closure cl;
+
+ count = bfd_count_sections (abfd);
+ target_resize_to_sections (targ, count);
+ start = targ->to_sections;
+ cl.end = targ->to_sections;
+ bfd_map_over_sections (abfd, add_to_section_table, &cl);
+ gdb_assert (cl.end - start <= count);
+}
+
+LONGEST
+target_bfd_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_MEMORY:
+ {
+ struct section_table *s = target_section_by_addr (ops, offset);
+ if (s == NULL)
+ return -1;
+ /* If the length extends beyond the section, truncate it. Be
+ careful to not suffer from overflow (wish S contained a
+ length). */
+ if ((offset - s->addr + len) > (s->endaddr - s->addr))
+ len = (s->endaddr - s->addr) - (offset - s->addr);
+ if (readbuf != NULL
+ && !bfd_get_section_contents (s->bfd, s->the_bfd_section,
+ readbuf, offset - s->addr, len))
+ return -1;
+#if 1
+ if (writebuf != NULL)
+ return -1;
+#else
+ /* FIXME: cagney/2003-10-31: The BFD interface doesn't yet
+ take a const buffer. */
+ if (writebuf != NULL
+ && !bfd_set_section_contents (s->bfd, s->the_bfd_section,
+ writebuf, offset - s->addr, len))
+ return -1;
+#endif
+ return len;
+ }
+ default:
+ return -1;
+ }
+}
+
+void
+target_bfd_xclose (struct target_ops *t, int quitting)
+{
+ bfd_close (t->to_data);
+ xfree (t->to_sections);
+ xfree (t);
+}
+
+struct target_ops *
+target_bfd_reopen (struct bfd *bfd)
+{
+ struct target_ops *t = XZALLOC (struct target_ops);
+ t->to_shortname = "bfd";
+ t->to_longname = "BFD backed target";
+ t->to_doc = "You should never see this";
+ t->to_xfer_partial = target_bfd_xfer_partial;
+ t->to_xclose = target_bfd_xclose;
+ t->to_data = bfd;
+ build_target_sections_from_bfd (t, bfd);
+ return t;
+}
diff --git a/contrib/gdb/gdb/bfd-target.h b/contrib/gdb/gdb/bfd-target.h
new file mode 100644
index 0000000..61a51c8
--- /dev/null
+++ b/contrib/gdb/gdb/bfd-target.h
@@ -0,0 +1,39 @@
+/* Very simple "bfd" target, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_TARGET_H
+#define BFD_TARGET_H
+
+struct bfd;
+struct target_ops;
+
+/* Given an existing BFD, re-open it as a "struct target_ops". On
+ close, it will also close the corresponding BFD (which is like
+ freopen and fdopen). */
+struct target_ops *target_bfd_reopen (struct bfd *bfd);
+
+/* Map over ABFD's sections, creating corresponding entries in the
+ target's section table. */
+
+void build_target_sections_from_bfd (struct target_ops *targ,
+ struct bfd *abfd);
+
+#endif
diff --git a/contrib/gdb/gdb/block.c b/contrib/gdb/gdb/block.c
new file mode 100644
index 0000000..28b1181
--- /dev/null
+++ b/contrib/gdb/gdb/block.c
@@ -0,0 +1,295 @@
+/* Block-related functions for the GNU debugger, GDB.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "block.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "gdb_obstack.h"
+#include "cp-support.h"
+
+/* This is used by struct block to store namespace-related info for
+ C++ files, namely using declarations and the current namespace in
+ scope. */
+
+struct block_namespace_info
+{
+ const char *scope;
+ struct using_direct *using;
+};
+
+static void block_initialize_namespace (struct block *block,
+ struct obstack *obstack);
+
+/* 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 (const struct block *a, const struct block *b)
+{
+ if (!a || !b)
+ return 0;
+ return BLOCK_START (a) >= BLOCK_START (b)
+ && BLOCK_END (a) <= BLOCK_END (b);
+}
+
+
+/* Return the symbol for the function which contains a specified
+ lexical block, described by a struct block BL. */
+
+struct symbol *
+block_function (const struct block *bl)
+{
+ while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
+/* Return the blockvector immediately containing the innermost lexical block
+ containing the specified pc value and section, or 0 if there is none.
+ 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_sect (CORE_ADDR pc, struct bfd_section *section,
+ int *pindex, struct symtab *symtab)
+{
+ struct block *b;
+ int bot, top, half;
+ struct blockvector *bl;
+
+ if (symtab == 0) /* if no symtab specified by caller */
+ {
+ /* First search all symtabs for one whose file contains our pc */
+ symtab = find_pc_sect_symtab (pc, section);
+ if (symtab == 0)
+ return 0;
+ }
+
+ bl = BLOCKVECTOR (symtab);
+ 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 blockvector immediately containing the innermost lexical block
+ containing the specified pc value, or 0 if there is none.
+ Backward compatibility, no section. */
+
+struct blockvector *
+blockvector_for_pc (CORE_ADDR pc, int *pindex)
+{
+ return blockvector_for_pc_sect (pc, find_pc_mapped_section (pc),
+ pindex, NULL);
+}
+
+/* Return the innermost lexical block containing the specified pc value
+ in the specified section, or 0 if there is none. */
+
+struct block *
+block_for_pc_sect (CORE_ADDR pc, struct bfd_section *section)
+{
+ struct blockvector *bl;
+ int index;
+
+ bl = blockvector_for_pc_sect (pc, section, &index, NULL);
+ if (bl)
+ return BLOCKVECTOR_BLOCK (bl, index);
+ return 0;
+}
+
+/* Return the innermost lexical block containing the specified pc value,
+ or 0 if there is none. Backward compatibility, no section. */
+
+struct block *
+block_for_pc (CORE_ADDR pc)
+{
+ return block_for_pc_sect (pc, find_pc_mapped_section (pc));
+}
+
+/* Now come some functions designed to deal with C++ namespace issues.
+ The accessors are safe to use even in the non-C++ case. */
+
+/* This returns the namespace that BLOCK is enclosed in, or "" if it
+ isn't enclosed in a namespace at all. This travels the chain of
+ superblocks looking for a scope, if necessary. */
+
+const char *
+block_scope (const struct block *block)
+{
+ for (; block != NULL; block = BLOCK_SUPERBLOCK (block))
+ {
+ if (BLOCK_NAMESPACE (block) != NULL
+ && BLOCK_NAMESPACE (block)->scope != NULL)
+ return BLOCK_NAMESPACE (block)->scope;
+ }
+
+ return "";
+}
+
+/* Set BLOCK's scope member to SCOPE; if needed, allocate memory via
+ OBSTACK. (It won't make a copy of SCOPE, however, so that already
+ has to be allocated correctly.) */
+
+void
+block_set_scope (struct block *block, const char *scope,
+ struct obstack *obstack)
+{
+ block_initialize_namespace (block, obstack);
+
+ BLOCK_NAMESPACE (block)->scope = scope;
+}
+
+/* This returns the first using directives associated to BLOCK, if
+ any. */
+
+/* FIXME: carlton/2003-04-23: This uses the fact that we currently
+ only have using directives in static blocks, because we only
+ generate using directives from anonymous namespaces. Eventually,
+ when we support using directives everywhere, we'll want to replace
+ this by some iterator functions. */
+
+struct using_direct *
+block_using (const struct block *block)
+{
+ const struct block *static_block = block_static_block (block);
+
+ if (static_block == NULL
+ || BLOCK_NAMESPACE (static_block) == NULL)
+ return NULL;
+ else
+ return BLOCK_NAMESPACE (static_block)->using;
+}
+
+/* Set BLOCK's using member to USING; if needed, allocate memory via
+ OBSTACK. (It won't make a copy of USING, however, so that already
+ has to be allocated correctly.) */
+
+void
+block_set_using (struct block *block,
+ struct using_direct *using,
+ struct obstack *obstack)
+{
+ block_initialize_namespace (block, obstack);
+
+ BLOCK_NAMESPACE (block)->using = using;
+}
+
+/* If BLOCK_NAMESPACE (block) is NULL, allocate it via OBSTACK and
+ ititialize its members to zero. */
+
+static void
+block_initialize_namespace (struct block *block, struct obstack *obstack)
+{
+ if (BLOCK_NAMESPACE (block) == NULL)
+ {
+ BLOCK_NAMESPACE (block)
+ = obstack_alloc (obstack, sizeof (struct block_namespace_info));
+ BLOCK_NAMESPACE (block)->scope = NULL;
+ BLOCK_NAMESPACE (block)->using = NULL;
+ }
+}
+
+/* Return the static block associated to BLOCK. Return NULL if block
+ is NULL or if block is a global block. */
+
+const struct block *
+block_static_block (const struct block *block)
+{
+ if (block == NULL || BLOCK_SUPERBLOCK (block) == NULL)
+ return NULL;
+
+ while (BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) != NULL)
+ block = BLOCK_SUPERBLOCK (block);
+
+ return block;
+}
+
+/* Return the static block associated to BLOCK. Return NULL if block
+ is NULL. */
+
+const struct block *
+block_global_block (const struct block *block)
+{
+ if (block == NULL)
+ return NULL;
+
+ while (BLOCK_SUPERBLOCK (block) != NULL)
+ block = BLOCK_SUPERBLOCK (block);
+
+ return block;
+}
+
+/* Allocate a block on OBSTACK, and initialize its elements to
+ zero/NULL. This is useful for creating "dummy" blocks that don't
+ correspond to actual source files.
+
+ Warning: it sets the block's BLOCK_DICT to NULL, which isn't a
+ valid value. If you really don't want the block to have a
+ dictionary, then you should subsequently set its BLOCK_DICT to
+ dict_create_linear (obstack, NULL). */
+
+struct block *
+allocate_block (struct obstack *obstack)
+{
+ struct block *bl = obstack_alloc (obstack, sizeof (struct block));
+
+ BLOCK_START (bl) = 0;
+ BLOCK_END (bl) = 0;
+ BLOCK_FUNCTION (bl) = NULL;
+ BLOCK_SUPERBLOCK (bl) = NULL;
+ BLOCK_DICT (bl) = NULL;
+ BLOCK_NAMESPACE (bl) = NULL;
+ BLOCK_GCC_COMPILED (bl) = 0;
+
+ return bl;
+}
diff --git a/contrib/gdb/gdb/block.h b/contrib/gdb/gdb/block.h
new file mode 100644
index 0000000..a368213
--- /dev/null
+++ b/contrib/gdb/gdb/block.h
@@ -0,0 +1,174 @@
+/* Code dealing with blocks for GDB.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 BLOCK_H
+#define BLOCK_H
+
+/* Opaque declarations. */
+
+struct symbol;
+struct symtab;
+struct block_namespace_info;
+struct using_direct;
+struct obstack;
+struct dictionary;
+
+/* 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 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;
+
+ /* This is used to store the symbols in the block. */
+
+ struct dictionary *dict;
+
+ /* Used for language-specific info. */
+
+ union
+ {
+ struct
+ {
+ /* Contains information about namespace-related info relevant to
+ this block: using directives and the current namespace
+ scope. */
+
+ struct block_namespace_info *namespace;
+ }
+ cplus_specific;
+ }
+ language_specific;
+
+ /* 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;
+};
+
+#define BLOCK_START(bl) (bl)->startaddr
+#define BLOCK_END(bl) (bl)->endaddr
+#define BLOCK_FUNCTION(bl) (bl)->function
+#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
+#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
+#define BLOCK_DICT(bl) (bl)->dict
+#define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.namespace
+
+/* Macro to loop through all symbols in a block BL, in no particular
+ order. ITER helps keep track of the iteration, and should be a
+ struct dict_iterator. SYM points to the current symbol. */
+
+#define ALL_BLOCK_SYMBOLS(block, iter, sym) \
+ ALL_DICT_SYMBOLS (BLOCK_DICT (block), iter, sym)
+
+struct blockvector
+{
+ /* Number of blocks in the list. */
+ 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 */
+
+enum { GLOBAL_BLOCK = 0, STATIC_BLOCK = 1, FIRST_LOCAL_BLOCK = 2 };
+
+extern struct symbol *block_function (const struct block *);
+
+extern int contained_in (const struct block *, const struct block *);
+
+extern struct blockvector *blockvector_for_pc (CORE_ADDR, int *);
+
+extern struct blockvector *blockvector_for_pc_sect (CORE_ADDR, asection *,
+ int *, struct symtab *);
+
+extern struct block *block_for_pc (CORE_ADDR);
+
+extern struct block *block_for_pc_sect (CORE_ADDR, asection *);
+
+extern const char *block_scope (const struct block *block);
+
+extern void block_set_scope (struct block *block, const char *scope,
+ struct obstack *obstack);
+
+extern struct using_direct *block_using (const struct block *block);
+
+extern void block_set_using (struct block *block,
+ struct using_direct *using,
+ struct obstack *obstack);
+
+extern const struct block *block_static_block (const struct block *block);
+
+extern const struct block *block_global_block (const struct block *block);
+
+extern struct block *allocate_block (struct obstack *obstack);
+
+#endif /* BLOCK_H */
diff --git a/contrib/gdb/gdb/blockframe.c b/contrib/gdb/gdb/blockframe.c
new file mode 100644
index 0000000..265bd2e
--- /dev/null
+++ b/contrib/gdb/gdb/blockframe.c
@@ -0,0 +1,643 @@
+/* Get info from stack frames; convert between frames, blocks,
+ functions and pc values.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "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"
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "dummy-frame.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "block.h"
+
+/* Prototypes for exported functions. */
+
+void _initialize_blockframe (void);
+
+/* 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 DEPRECATED_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
+deprecated_inside_entry_file (CORE_ADDR addr)
+{
+ if (addr == 0)
+ return 1;
+ if (symfile_objfile == 0)
+ return 0;
+ if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT
+ || CALL_DUMMY_LOCATION == AT_SYMBOL)
+ {
+ /* Do not stop backtracing if the pc is in the call dummy
+ at the entry point. */
+ /* FIXME: Won't always work with zeros for the last two arguments */
+ if (DEPRECATED_PC_IN_CALL_DUMMY (addr, 0, 0))
+ return 0;
+ }
+ return (addr >= symfile_objfile->ei.deprecated_entry_file_lowpc &&
+ addr < symfile_objfile->ei.deprecated_entry_file_highpc);
+}
+
+/* Test whether PC is in the range of addresses that corresponds to
+ the "main" function. */
+
+int
+inside_main_func (CORE_ADDR pc)
+{
+ struct minimal_symbol *msymbol;
+
+ if (symfile_objfile == 0)
+ return 0;
+
+ msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
+
+ /* If the address range hasn't been set up at symbol reading time,
+ set it up now. */
+
+ if (msymbol != NULL
+ && symfile_objfile->ei.main_func_lowpc == INVALID_ENTRY_LOWPC
+ && symfile_objfile->ei.main_func_highpc == INVALID_ENTRY_HIGHPC)
+ {
+ /* brobecker/2003-10-10: We used to rely on lookup_symbol() to
+ search the symbol associated to the "main" function.
+ Unfortunately, lookup_symbol() uses the current-language
+ la_lookup_symbol_nonlocal function to do the global symbol
+ search. Depending on the language, this can introduce
+ certain side-effects, because certain languages, for instance
+ Ada, may find more than one match. Therefore we prefer to
+ search the "main" function symbol using its address rather
+ than its name. */
+ struct symbol *mainsym =
+ find_pc_function (SYMBOL_VALUE_ADDRESS (msymbol));
+
+ 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));
+ }
+ }
+
+ /* Not in the normal symbol tables, see if "main" is in the partial
+ symbol table. If it's not, then give up. */
+ if (msymbol != NULL && MSYMBOL_TYPE (msymbol) == mst_text)
+ {
+ CORE_ADDR maddr = SYMBOL_VALUE_ADDRESS (msymbol);
+ asection *msect = SYMBOL_BFD_SECTION (msymbol);
+ struct obj_section *osect = find_pc_sect_section (maddr, msect);
+
+ if (osect != NULL)
+ {
+ int i;
+
+ /* Step over other symbols at this same address, and symbols
+ in other sections, to find the next symbol in this
+ section with a different address. */
+ for (i = 1; SYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
+ {
+ if (SYMBOL_VALUE_ADDRESS (msymbol + i) != maddr
+ && SYMBOL_BFD_SECTION (msymbol + i) == msect)
+ break;
+ }
+
+ symfile_objfile->ei.main_func_lowpc = maddr;
+
+ /* Use the lesser of the next minimal symbol in the same
+ section, or the end of the section, as the end of the
+ function. */
+ if (SYMBOL_LINKAGE_NAME (msymbol + i) != NULL
+ && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr)
+ symfile_objfile->ei.main_func_highpc =
+ SYMBOL_VALUE_ADDRESS (msymbol + i);
+ else
+ /* We got the start address from the last msymbol in the
+ objfile. So the end address is the end of the
+ section. */
+ symfile_objfile->ei.main_func_highpc = osect->endaddr;
+ }
+ }
+
+ return (symfile_objfile->ei.main_func_lowpc <= pc
+ && symfile_objfile->ei.main_func_highpc > pc);
+}
+
+/* Test whether THIS_FRAME is inside the process entry point function. */
+
+int
+inside_entry_func (struct frame_info *this_frame)
+{
+ return (get_frame_func (this_frame) == entry_point_address ());
+}
+
+/* Similar to inside_entry_func, but accomodating legacy frame code. */
+
+static int
+legacy_inside_entry_func (CORE_ADDR pc)
+{
+ if (symfile_objfile == 0)
+ return 0;
+
+ if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT)
+ {
+ /* Do not stop backtracing if the program counter is in the call
+ dummy at the entry point. */
+ /* FIXME: This won't always work with zeros for the last two
+ arguments. */
+ if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+ return 0;
+ }
+
+ return (symfile_objfile->ei.entry_func_lowpc <= pc
+ && symfile_objfile->ei.entry_func_highpc > pc);
+}
+
+/* Return nonzero if the function for this frame lacks a prologue.
+ Many machines can define DEPRECATED_FRAMELESS_FUNCTION_INVOCATION
+ to just call this function. */
+
+int
+legacy_frameless_look_for_prologue (struct frame_info *frame)
+{
+ CORE_ADDR func_start;
+
+ func_start = get_frame_func (frame);
+ if (func_start)
+ {
+ func_start += FUNCTION_START_OFFSET;
+ /* NOTE: cagney/2004-02-09: Eliminated per-architecture
+ PROLOGUE_FRAMELESS_P call as architectures with custom
+ implementations had all been deleted. Eventually even this
+ function can go - GDB no longer tries to differentiate
+ between framed, frameless and stackless functions. They are
+ all now considered equally evil :-^. */
+ /* If skipping the prologue ends up skips nothing, there must be
+ no prologue and hence no code creating a frame. There for
+ the function is "frameless" :-/. */
+ return func_start == SKIP_PROLOGUE (func_start);
+ }
+ else if (get_frame_pc (frame) == 0)
+ /* A frame with a zero PC is usually created by dereferencing a
+ NULL function pointer, normally causing an immediate core dump
+ of the inferior. Mark function as frameless, as the inferior
+ has no chance of setting up a stack frame. */
+ return 1;
+ 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;
+}
+
+/* Return the innermost lexical block in execution
+ in a specified stack frame. The frame address is assumed valid.
+
+ If ADDR_IN_BLOCK is non-zero, set *ADDR_IN_BLOCK to the exact code
+ address we used to choose the block. We use this to find a source
+ line, to decide which macro definitions are in scope.
+
+ The value returned in *ADDR_IN_BLOCK isn't necessarily the frame's
+ PC, and may not really be a valid PC at all. For example, in the
+ caller of a function declared to never return, the code at the
+ return address will never be reached, so the call instruction may
+ be the very last instruction in the block. So the address we use
+ to choose the block is actually one byte before the return address
+ --- hopefully pointing us at the call instruction, or its delay
+ slot instruction. */
+
+struct block *
+get_frame_block (struct frame_info *frame, CORE_ADDR *addr_in_block)
+{
+ const CORE_ADDR pc = get_frame_address_in_block (frame);
+
+ if (addr_in_block)
+ *addr_in_block = pc;
+
+ return block_for_pc (pc);
+}
+
+CORE_ADDR
+get_pc_function_start (CORE_ADDR pc)
+{
+ struct block *bl;
+ struct minimal_symbol *msymbol;
+
+ bl = block_for_pc (pc);
+ if (bl)
+ {
+ struct symbol *symbol = block_function (bl);
+
+ if (symbol)
+ {
+ bl = SYMBOL_BLOCK_VALUE (symbol);
+ return BLOCK_START (bl);
+ }
+ }
+
+ msymbol = lookup_minimal_symbol_by_pc (pc);
+ if (msymbol)
+ {
+ CORE_ADDR fstart = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ if (find_pc_section (fstart))
+ return fstart;
+ }
+
+ return 0;
+}
+
+/* Return the symbol for the function executing in frame FRAME. */
+
+struct symbol *
+get_frame_function (struct frame_info *frame)
+{
+ struct block *bl = get_frame_block (frame, 0);
+ if (bl == 0)
+ return 0;
+ return block_function (bl);
+}
+
+
+/* Return the function containing pc value PC in section SECTION.
+ Returns 0 if function is not known. */
+
+struct symbol *
+find_pc_sect_function (CORE_ADDR pc, struct bfd_section *section)
+{
+ struct block *b = block_for_pc_sect (pc, section);
+ if (b == 0)
+ return 0;
+ return block_function (b);
+}
+
+/* Return the function containing pc value PC.
+ Returns 0 if function is not known. Backward compatibility, no section */
+
+struct symbol *
+find_pc_function (CORE_ADDR pc)
+{
+ return find_pc_sect_function (pc, find_pc_mapped_section (pc));
+}
+
+/* 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;
+static struct bfd_section *cache_pc_function_section = NULL;
+
+/* Clear cache, e.g. when symbol table is discarded. */
+
+void
+clear_pc_function_cache (void)
+{
+ cache_pc_function_low = 0;
+ cache_pc_function_high = 0;
+ cache_pc_function_name = (char *) 0;
+ cache_pc_function_section = NULL;
+}
+
+/* Finds the "function" (text symbol) that is smaller than PC but
+ greatest of all of the potential text symbols in SECTION. 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_sect_partial_function (CORE_ADDR pc, asection *section, 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 *osect;
+ int i;
+ CORE_ADDR mapped_pc;
+
+ mapped_pc = overlay_mapped_address (pc, section);
+
+ if (mapped_pc >= cache_pc_function_low
+ && mapped_pc < cache_pc_function_high
+ && section == cache_pc_function_section)
+ goto return_cached_value;
+
+ /* If sigtramp is in the u area, it counts as a function (especially
+ important for step_1). */
+ if (SIGTRAMP_START_P () && PC_IN_SIGTRAMP (mapped_pc, (char *) NULL))
+ {
+ cache_pc_function_low = SIGTRAMP_START (mapped_pc);
+ cache_pc_function_high = SIGTRAMP_END (mapped_pc);
+ cache_pc_function_name = "<sigtramp>";
+ cache_pc_function_section = section;
+ goto return_cached_value;
+ }
+
+ msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
+ pst = find_pc_sect_psymtab (mapped_pc, section);
+ 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_sect_function (mapped_pc, section);
+ 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 = DEPRECATED_SYMBOL_NAME (f);
+ cache_pc_function_section = section;
+ 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_sect_psymbol (pst, mapped_pc, section);
+
+ 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 = DEPRECATED_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. */
+
+ osect = find_pc_sect_section (mapped_pc, section);
+
+ if (!osect)
+ 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 = DEPRECATED_SYMBOL_NAME (msymbol);
+ cache_pc_function_section = section;
+
+ /* Use the lesser of the next minimal symbol in the same section, or
+ the end of the section, as the end of the function. */
+
+ /* Step over other symbols at this same address, and symbols in
+ other sections, to find the next symbol in this section with
+ a different address. */
+
+ for (i = 1; DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL; i++)
+ {
+ if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol)
+ && SYMBOL_BFD_SECTION (msymbol + i) == SYMBOL_BFD_SECTION (msymbol))
+ break;
+ }
+
+ if (DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL
+ && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr)
+ cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i);
+ 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 = osect->endaddr;
+
+ return_cached_value:
+
+ if (address)
+ {
+ if (pc_in_unmapped_range (pc, section))
+ *address = overlay_unmapped_address (cache_pc_function_low, section);
+ else
+ *address = cache_pc_function_low;
+ }
+
+ if (name)
+ *name = cache_pc_function_name;
+
+ if (endaddr)
+ {
+ if (pc_in_unmapped_range (pc, section))
+ {
+ /* Because the high address is actually beyond the end of
+ the function (and therefore possibly beyond the end of
+ the overlay), we must actually convert (high - 1) and
+ then add one to that. */
+
+ *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
+ section);
+ }
+ else
+ *endaddr = cache_pc_function_high;
+ }
+
+ return 1;
+}
+
+/* Backward compatibility, no section argument. */
+
+int
+find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
+ CORE_ADDR *endaddr)
+{
+ struct bfd_section *bfd_section;
+
+ /* To ensure that the symbol returned belongs to the correct setion
+ (and that the last [random] symbol from the previous section
+ isn't returned) try to find the section containing PC. First try
+ the overlay code (which by default returns NULL); and second try
+ the normal section code (which almost always succeeds). */
+ bfd_section = find_pc_overlay (pc);
+ if (bfd_section == NULL)
+ {
+ struct obj_section *obj_section = find_pc_section (pc);
+ if (obj_section == NULL)
+ bfd_section = NULL;
+ else
+ bfd_section = obj_section->the_bfd_section;
+ }
+ return find_pc_sect_partial_function (pc, bfd_section, name, address,
+ endaddr);
+}
+
+/* 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 (struct block *block)
+{
+ struct frame_info *frame;
+ CORE_ADDR start;
+ CORE_ADDR end;
+ CORE_ADDR calling_pc;
+
+ 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;
+ calling_pc = get_frame_address_in_block (frame);
+ if (calling_pc >= start && calling_pc < end)
+ return frame;
+ }
+}
+
+/* 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. */
+
+/* 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 DEPRECATED_FP_REGNUM (or the saved values thereof),
+ respectively, are the things to pass.
+
+ This won't work on the 29k, where SP_REGNUM and
+ DEPRECATED_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 DEPRECATED_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. */
+
+int
+deprecated_pc_in_call_dummy_on_stack (CORE_ADDR pc, CORE_ADDR sp,
+ CORE_ADDR frame_address)
+{
+ return (INNER_THAN ((sp), (pc))
+ && (frame_address != 0)
+ && INNER_THAN ((pc), (frame_address)));
+}
+
+int
+deprecated_pc_in_call_dummy_at_entry_point (CORE_ADDR pc, CORE_ADDR sp,
+ CORE_ADDR frame_address)
+{
+ CORE_ADDR addr = entry_point_address ();
+ return ((pc) >= addr && (pc) <= (addr + DECR_PC_AFTER_BREAK));
+}
+
+/* Returns true for a user frame or a call_function_by_hand dummy
+ frame, and false for the CRT0 start-up frame. Purpose is to
+ terminate backtrace. */
+
+int
+legacy_frame_chain_valid (CORE_ADDR fp, struct frame_info *fi)
+{
+ /* Don't prune CALL_DUMMY frames. */
+ if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+ && DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
+ return 1;
+
+ /* If the new frame pointer is zero, then it isn't valid. */
+ if (fp == 0)
+ return 0;
+
+ /* If the new frame would be inside (younger than) the previous frame,
+ then it isn't valid. */
+ if (INNER_THAN (fp, get_frame_base (fi)))
+ return 0;
+
+ /* If the architecture has a custom DEPRECATED_FRAME_CHAIN_VALID,
+ call it now. */
+ if (DEPRECATED_FRAME_CHAIN_VALID_P ())
+ return DEPRECATED_FRAME_CHAIN_VALID (fp, fi);
+
+ /* If we're already inside the entry function for the main objfile, then it
+ isn't valid. */
+ if (legacy_inside_entry_func (get_frame_pc (fi)))
+ return 0;
+
+ /* If we're inside the entry file, it isn't valid. */
+ /* NOTE/drow 2002-12-25: should there be a way to disable this check? It
+ assumes a single small entry file, and the way some debug readers (e.g.
+ dbxread) figure out which object is the entry file is somewhat hokey. */
+ if (deprecated_inside_entry_file (frame_pc_unwind (fi)))
+ return 0;
+
+ return 1;
+}
diff --git a/contrib/gdb/gdb/breakpoint.c b/contrib/gdb/gdb/breakpoint.c
new file mode 100644
index 0000000..933d902
--- /dev/null
+++ b/contrib/gdb/gdb/breakpoint.c
@@ -0,0 +1,8101 @@
+/* Everything about breakpoints, for GDB.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#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 "gdbthread.h"
+#include "target.h"
+#include "language.h"
+#include "gdb_string.h"
+#include "demangle.h"
+#include "annotate.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "source.h"
+#include "linespec.h"
+#include "completer.h"
+#include "gdb.h"
+#include "ui-out.h"
+#include "cli/cli-script.h"
+#include "gdb_assert.h"
+#include "block.h"
+
+#include "gdb-events.h"
+
+/* Prototypes for local functions. */
+
+static void until_break_command_continuation (struct continuation_arg *arg);
+
+static void catch_command_1 (char *, int, int);
+
+static void enable_delete_command (char *, int);
+
+static void enable_delete_breakpoint (struct breakpoint *);
+
+static void enable_once_command (char *, int);
+
+static void enable_once_breakpoint (struct breakpoint *);
+
+static void disable_command (char *, int);
+
+static void enable_command (char *, int);
+
+static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
+
+static void ignore_command (char *, int);
+
+static int breakpoint_re_set_one (void *);
+
+static void clear_command (char *, int);
+
+static void catch_command (char *, int);
+
+static void watch_command (char *, int);
+
+static int can_use_hardware_watchpoint (struct value *);
+
+extern void break_at_finish_command (char *, int);
+extern void break_at_finish_at_depth_command (char *, int);
+
+extern void tbreak_at_finish_command (char *, int);
+
+static int break_command_1 (char *, int, int, struct breakpoint *);
+
+static void mention (struct breakpoint *);
+
+struct breakpoint *set_raw_breakpoint (struct symtab_and_line, enum bptype);
+
+static void check_duplicates (struct breakpoint *);
+
+static void breakpoint_adjustment_warning (CORE_ADDR, CORE_ADDR, int, int);
+
+static CORE_ADDR adjust_breakpoint_address (CORE_ADDR bpaddr);
+
+static void describe_other_breakpoints (CORE_ADDR, asection *);
+
+static void breakpoints_info (char *, int);
+
+static void breakpoint_1 (int, int);
+
+static bpstat bpstat_alloc (struct breakpoint *, bpstat);
+
+static int breakpoint_cond_eval (void *);
+
+static void cleanup_executing_breakpoints (void *);
+
+static void commands_command (char *, int);
+
+static void condition_command (char *, int);
+
+static int get_number_trailer (char **, int);
+
+static int do_captured_parse_breakpoint (struct ui_out *, void *);
+
+void set_breakpoint_count (int);
+
+typedef enum
+ {
+ mark_inserted,
+ mark_uninserted
+ }
+insertion_state_t;
+
+static int remove_breakpoint (struct bp_location *, insertion_state_t);
+
+static enum print_stop_action print_it_typical (bpstat);
+
+static enum print_stop_action print_bp_stop_message (bpstat bs);
+
+typedef struct
+ {
+ enum exception_event_kind kind;
+ int enable_p;
+ }
+args_for_catchpoint_enable;
+
+static int watchpoint_check (void *);
+
+static int cover_target_enable_exception_callback (void *);
+
+static void maintenance_info_breakpoints (char *, int);
+
+static void create_longjmp_breakpoint (char *);
+
+static void create_overlay_event_breakpoint (char *);
+
+static int hw_breakpoint_used_count (void);
+
+static int hw_watchpoint_used_count (enum bptype, int *);
+
+static void hbreak_command (char *, int);
+
+static void thbreak_command (char *, int);
+
+static void watch_command_1 (char *, int, int);
+
+static void rwatch_command (char *, int);
+
+static void awatch_command (char *, int);
+
+static void do_enable_breakpoint (struct breakpoint *, enum bpdisp);
+
+static void solib_load_unload_1 (char *hookname,
+ int tempflag,
+ char *dll_pathname,
+ char *cond_string, enum bptype bp_kind);
+
+static void create_fork_vfork_event_catchpoint (int tempflag,
+ char *cond_string,
+ enum bptype bp_kind);
+
+static void break_at_finish_at_depth_command_1 (char *arg,
+ int flag, int from_tty);
+
+static void break_at_finish_command_1 (char *arg, int flag, int from_tty);
+
+static void stop_command (char *arg, int from_tty);
+
+static void stopin_command (char *arg, int from_tty);
+
+static void stopat_command (char *arg, int from_tty);
+
+static char *ep_find_event_name_end (char *arg);
+
+static char *ep_parse_optional_if_clause (char **arg);
+
+static char *ep_parse_optional_filename (char **arg);
+
+static void create_exception_catchpoint (int tempflag, char *cond_string,
+ enum exception_event_kind ex_event,
+ struct symtab_and_line *sal);
+
+static void catch_exception_command_1 (enum exception_event_kind ex_event,
+ char *arg, int tempflag, int from_tty);
+
+static void tcatch_command (char *arg, int from_tty);
+
+static void ep_skip_leading_whitespace (char **s);
+
+/* Prototypes for exported functions. */
+
+/* If FALSE, gdb will not use hardware support for watchpoints, even
+ if such is available. */
+static int can_use_hw_watchpoints;
+
+/* If AUTO_BOOLEAN_FALSE, gdb will not attempt to create pending breakpoints.
+ If AUTO_BOOLEAN_TRUE, gdb will automatically create pending breakpoints
+ for unrecognized breakpoint locations.
+ If AUTO_BOOLEAN_AUTO, gdb will query when breakpoints are unrecognized. */
+static enum auto_boolean pending_break_support;
+
+void _initialize_breakpoint (void);
+
+extern int addressprint; /* Print machine addresses? */
+
+/* Are we executing breakpoint commands? */
+static int executing_breakpoint_commands;
+
+/* Are overlay event breakpoints enabled? */
+static int overlay_events_enabled;
+
+/* 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)
+
+/* Similar iterators for the low-level breakpoints. */
+
+#define ALL_BP_LOCATIONS(B) for (B = bp_location_chain; B; B = B->next)
+
+#define ALL_BP_LOCATIONS_SAFE(B,TMP) \
+ for (B = bp_location_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;
+
+/* Chains of all breakpoints defined. */
+
+struct breakpoint *breakpoint_chain;
+
+struct bp_location *bp_location_chain;
+
+/* Number of last breakpoint made. */
+
+int breakpoint_count;
+
+/* Pointer to current exception event record */
+static struct exception_event_record *current_exception_event;
+
+/* Indicator of whether exception catchpoints should be nuked
+ between runs of a program */
+int exception_catchpoints_are_fragile = 0;
+
+/* Indicator of when exception catchpoints set-up should be
+ reinitialized -- e.g. when program is re-run */
+int exception_support_initialized = 0;
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been
+ loaded.
+
+ This function must be used only when SOLIB_HAVE_LOAD_EVENT is TRUE,
+ or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the
+ inferior has stopped in the dynamic linker hook, and becomes
+ invalid as soon as the inferior is continued. Clients should make
+ a copy of this string if they wish to continue the inferior and
+ then access the string. */
+
+#ifndef SOLIB_LOADED_LIBRARY_PATHNAME
+#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) ""
+#endif
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been
+ unloaded.
+
+ This function must be used only when SOLIB_HAVE_UNLOAD_EVENT is
+ TRUE, or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the
+ inferior has stopped in the dynamic linker hook, and becomes
+ invalid as soon as the inferior is continued. Clients should make
+ a copy of this string if they wish to continue the inferior and
+ then access the string. */
+
+#ifndef SOLIB_UNLOADED_LIBRARY_PATHNAME
+#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) ""
+#endif
+
+/* This function is called by the "catch load" command. It allows the
+ debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is loaded. */
+
+#ifndef SOLIB_CREATE_CATCH_LOAD_HOOK
+#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag,filename,cond_string) \
+ error ("catch of library loads not yet implemented on this platform")
+#endif
+
+/* This function is called by the "catch unload" command. It allows
+ the debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is
+ unloaded. */
+
+#ifndef SOLIB_CREATE_CATCH_UNLOAD_HOOK
+#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename,cond_string) \
+ error ("catch of library unloads not yet implemented on this platform")
+#endif
+
+/* Return whether a breakpoint is an active enabled breakpoint. */
+static int
+breakpoint_enabled (struct breakpoint *b)
+{
+ return (b->enable_state == bp_enabled && !b->pending);
+}
+
+/* Set breakpoint count to NUM. */
+
+void
+set_breakpoint_count (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 (void)
+{
+ 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").
+
+ TRAILER is a character which can be found after the number; most
+ commonly this is `-'. If you don't want a trailer, use \0. */
+static int
+get_number_trailer (char **pp, int trailer)
+{
+ int retval = 0; /* default */
+ 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;
+ struct value *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)
+ retval = (int) value_as_long (val);
+ else
+ {
+ printf_filtered ("Convenience variable must have integer value.\n");
+ retval = 0;
+ }
+ }
+ else
+ {
+ if (*p == '-')
+ ++p;
+ while (*p >= '0' && *p <= '9')
+ ++p;
+ if (p == *pp)
+ /* There is no number here. (e.g. "cond a == b"). */
+ {
+ /* Skip non-numeric token */
+ while (*p && !isspace((int) *p))
+ ++p;
+ /* Return zero, which caller must interpret as error. */
+ retval = 0;
+ }
+ else
+ retval = atoi (*pp);
+ }
+ if (!(isspace (*p) || *p == '\0' || *p == trailer))
+ {
+ /* Trailing junk: return 0 and let caller print error msg. */
+ while (!(isspace (*p) || *p == '\0' || *p == trailer))
+ ++p;
+ retval = 0;
+ }
+ while (isspace (*p))
+ p++;
+ *pp = p;
+ return retval;
+}
+
+
+/* Like get_number_trailer, but don't allow a trailer. */
+int
+get_number (char **pp)
+{
+ return get_number_trailer (pp, '\0');
+}
+
+/* Parse a number or a range.
+ * A number will be of the form handled by get_number.
+ * A range will be of the form <number1> - <number2>, and
+ * will represent all the integers between number1 and number2,
+ * inclusive.
+ *
+ * While processing a range, this fuction is called iteratively;
+ * At each call it will return the next value in the range.
+ *
+ * At the beginning of parsing a range, the char pointer PP will
+ * be advanced past <number1> and left pointing at the '-' token.
+ * Subsequent calls will not advance the pointer until the range
+ * is completed. The call that completes the range will advance
+ * pointer PP past <number2>.
+ */
+
+int
+get_number_or_range (char **pp)
+{
+ static int last_retval, end_value;
+ static char *end_ptr;
+ static int in_range = 0;
+
+ if (**pp != '-')
+ {
+ /* Default case: pp is pointing either to a solo number,
+ or to the first number of a range. */
+ last_retval = get_number_trailer (pp, '-');
+ if (**pp == '-')
+ {
+ char **temp;
+
+ /* This is the start of a range (<number1> - <number2>).
+ Skip the '-', parse and remember the second number,
+ and also remember the end of the final token. */
+
+ temp = &end_ptr;
+ end_ptr = *pp + 1;
+ while (isspace ((int) *end_ptr))
+ end_ptr++; /* skip white space */
+ end_value = get_number (temp);
+ if (end_value < last_retval)
+ {
+ error ("inverted range");
+ }
+ else if (end_value == last_retval)
+ {
+ /* degenerate range (number1 == number2). Advance the
+ token pointer so that the range will be treated as a
+ single number. */
+ *pp = end_ptr;
+ }
+ else
+ in_range = 1;
+ }
+ }
+ else if (! in_range)
+ error ("negative value");
+ else
+ {
+ /* pp points to the '-' that betokens a range. All
+ number-parsing has already been done. Return the next
+ integer value (one greater than the saved previous value).
+ Do not advance the token pointer 'pp' until the end of range
+ is reached. */
+
+ if (++last_retval == end_value)
+ {
+ /* End of range reached; advance token pointer. */
+ *pp = end_ptr;
+ in_range = 0;
+ }
+ }
+ return last_retval;
+}
+
+
+
+/* condition N EXP -- set break condition of breakpoint N to EXP. */
+
+static void
+condition_command (char *arg, int from_tty)
+{
+ struct breakpoint *b;
+ char *p;
+ int bnum;
+
+ if (arg == 0)
+ error_no_arg ("breakpoint number");
+
+ p = arg;
+ bnum = get_number (&p);
+ if (bnum == 0)
+ error ("Bad breakpoint argument: '%s'", arg);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (b->cond)
+ {
+ xfree (b->cond);
+ b->cond = 0;
+ }
+ if (b->cond_string != NULL)
+ xfree (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));
+ if (!b->pending)
+ {
+ b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+ if (*arg)
+ error ("Junk at end of expression");
+ }
+ }
+ breakpoints_changed ();
+ breakpoint_modify_event (b->number);
+ return;
+ }
+
+ error ("No breakpoint number %d.", bnum);
+}
+
+static void
+commands_command (char *arg, int from_tty)
+{
+ struct breakpoint *b;
+ char *p;
+ 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)
+ {
+ char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.",
+ bnum);
+ struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
+ l = read_command_lines (tmpbuf, from_tty);
+ do_cleanups (cleanups);
+ free_command_lines (&b->commands);
+ b->commands = l;
+ breakpoints_changed ();
+ breakpoint_modify_event (b->number);
+ return;
+ }
+ error ("No breakpoint number %d.", bnum);
+}
+
+/* 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 (CORE_ADDR memaddr, char *myaddr, unsigned len)
+{
+ int status;
+ struct bp_location *b;
+ CORE_ADDR bp_addr = 0;
+ int bp_size = 0;
+
+ if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
+ /* No breakpoints on this machine. */
+ return target_read_memory (memaddr, myaddr, len);
+
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->owner->type == bp_none)
+ warning ("reading through apparently deleted breakpoint #%d?",
+ b->owner->number);
+
+ if (b->loc_type != bp_loc_software_breakpoint)
+ continue;
+ if (!b->inserted)
+ continue;
+ /* Addresses and length of the part of the breakpoint that
+ we need to copy. */
+ /* XXXX The m68k, sh and h8300 have different local and remote
+ breakpoint values. BREAKPOINT_FROM_PC still manages to
+ correctly determine the breakpoints memory address and size
+ for these targets. */
+ bp_addr = b->address;
+ bp_size = 0;
+ if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
+ continue;
+ if (bp_size == 0)
+ /* bp isn't valid */
+ continue;
+ if (bp_addr + bp_size <= memaddr)
+ /* The breakpoint is entirely before the chunk of memory we
+ are reading. */
+ continue;
+ if (bp_addr >= memaddr + len)
+ /* The breakpoint is entirely after the chunk of memory we are
+ reading. */
+ continue;
+ /* Copy the breakpoint from the shadow contents, and recurse for
+ the things before and after. */
+ {
+ /* Offset within shadow_contents. */
+ int bptoffset = 0;
+
+ if (bp_addr < memaddr)
+ {
+ /* Only copy the second part of the breakpoint. */
+ bp_size -= memaddr - bp_addr;
+ bptoffset = memaddr - bp_addr;
+ bp_addr = memaddr;
+ }
+
+ if (bp_addr + bp_size > memaddr + len)
+ {
+ /* Only copy the first part of the breakpoint. */
+ bp_size -= (bp_addr + bp_size) - (memaddr + len);
+ }
+
+ memcpy (myaddr + bp_addr - memaddr,
+ b->shadow_contents + bptoffset, bp_size);
+
+ if (bp_addr > memaddr)
+ {
+ /* Copy the section of memory before the breakpoint. */
+ status = read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
+ if (status != 0)
+ return status;
+ }
+
+ if (bp_addr + bp_size < memaddr + len)
+ {
+ /* Copy the section of memory after the breakpoint. */
+ status = read_memory_nobpt (bp_addr + bp_size,
+ myaddr + bp_addr + bp_size - memaddr,
+ memaddr + len - (bp_addr + bp_size));
+ if (status != 0)
+ return status;
+ }
+ return 0;
+ }
+ }
+ /* Nothing overlaps. Just call read_memory_noerr. */
+ return target_read_memory (memaddr, myaddr, len);
+}
+
+
+/* A wrapper function for inserting catchpoints. */
+static int
+insert_catchpoint (struct ui_out *uo, void *args)
+{
+ struct breakpoint *b = (struct breakpoint *) args;
+ int val = -1;
+
+ switch (b->type)
+ {
+ case bp_catch_fork:
+ val = target_insert_fork_catchpoint (PIDGET (inferior_ptid));
+ break;
+ case bp_catch_vfork:
+ val = target_insert_vfork_catchpoint (PIDGET (inferior_ptid));
+ break;
+ case bp_catch_exec:
+ val = target_insert_exec_catchpoint (PIDGET (inferior_ptid));
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "unknown breakpoint type");
+ break;
+ }
+
+ if (val < 0)
+ throw_exception (RETURN_ERROR);
+
+ return 0;
+}
+
+/* Insert a low-level "breakpoint" of some type. BPT is the breakpoint.
+ Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS,
+ PROCESS_WARNING, and HW_BREAKPOINT_ERROR are used to report problems.
+
+ NOTE drow/2003-09-09: This routine could be broken down to an object-style
+ method for each breakpoint or catchpoint type. */
+static int
+insert_bp_location (struct bp_location *bpt,
+ struct ui_file *tmp_error_stream,
+ int *disabled_breaks, int *process_warning,
+ int *hw_breakpoint_error)
+{
+ int val = 0;
+
+ /* Permanent breakpoints cannot be inserted or removed. Disabled
+ breakpoints should not be inserted. */
+ if (!breakpoint_enabled (bpt->owner))
+ return 0;
+
+ if (bpt->inserted || bpt->duplicate)
+ return 0;
+
+ if (bpt->loc_type == bp_loc_software_breakpoint
+ || bpt->loc_type == bp_loc_hardware_breakpoint)
+ {
+ /* First check to see if we have to handle an overlay. */
+ if (overlay_debugging == ovly_off
+ || bpt->section == NULL
+ || !(section_is_overlay (bpt->section)))
+ {
+ /* No overlay handling: just set the breakpoint. */
+
+ if (bpt->loc_type == bp_loc_hardware_breakpoint)
+ val = target_insert_hw_breakpoint (bpt->address,
+ bpt->shadow_contents);
+ else
+ val = target_insert_breakpoint (bpt->address,
+ bpt->shadow_contents);
+ }
+ else
+ {
+ /* This breakpoint is in an overlay section.
+ Shall we set a breakpoint at the LMA? */
+ if (!overlay_events_enabled)
+ {
+ /* Yes -- overlay event support is not active,
+ so we must try to set a breakpoint at the LMA.
+ This will not work for a hardware breakpoint. */
+ if (bpt->loc_type == bp_loc_hardware_breakpoint)
+ warning ("hardware breakpoint %d not supported in overlay!\n",
+ bpt->owner->number);
+ else
+ {
+ CORE_ADDR addr = overlay_unmapped_address (bpt->address,
+ bpt->section);
+ /* Set a software (trap) breakpoint at the LMA. */
+ val = target_insert_breakpoint (addr, bpt->shadow_contents);
+ if (val != 0)
+ fprintf_unfiltered (tmp_error_stream,
+ "Overlay breakpoint %d failed: in ROM?",
+ bpt->owner->number);
+ }
+ }
+ /* Shall we set a breakpoint at the VMA? */
+ if (section_is_mapped (bpt->section))
+ {
+ /* Yes. This overlay section is mapped into memory. */
+ if (bpt->loc_type == bp_loc_hardware_breakpoint)
+ val = target_insert_hw_breakpoint (bpt->address,
+ bpt->shadow_contents);
+ else
+ val = target_insert_breakpoint (bpt->address,
+ bpt->shadow_contents);
+ }
+ else
+ {
+ /* No. This breakpoint will not be inserted.
+ No error, but do not mark the bp as 'inserted'. */
+ return 0;
+ }
+ }
+
+ if (val)
+ {
+ /* Can't set the breakpoint. */
+#if defined (DISABLE_UNSETTABLE_BREAK)
+ if (DISABLE_UNSETTABLE_BREAK (bpt->address))
+ {
+ /* See also: disable_breakpoints_in_shlibs. */
+ val = 0;
+ bpt->owner->enable_state = bp_shlib_disabled;
+ if (!*disabled_breaks)
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert breakpoint %d.\n",
+ bpt->owner->number);
+ fprintf_unfiltered (tmp_error_stream,
+ "Temporarily disabling shared library breakpoints:\n");
+ }
+ *disabled_breaks = 1;
+ fprintf_unfiltered (tmp_error_stream,
+ "breakpoint #%d\n", bpt->owner->number);
+ }
+ else
+#endif
+ {
+#ifdef ONE_PROCESS_WRITETEXT
+ *process_warning = 1;
+#endif
+ if (bpt->loc_type == bp_loc_hardware_breakpoint)
+ {
+ *hw_breakpoint_error = 1;
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert hardware breakpoint %d.\n",
+ bpt->owner->number);
+ }
+ else
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert breakpoint %d.\n",
+ bpt->owner->number);
+ fprintf_filtered (tmp_error_stream,
+ "Error accessing memory address ");
+ print_address_numeric (bpt->address, 1, tmp_error_stream);
+ fprintf_filtered (tmp_error_stream, ": %s.\n",
+ safe_strerror (val));
+ }
+
+ }
+ }
+ else
+ bpt->inserted = 1;
+
+ return val;
+ }
+
+ else if (bpt->loc_type == bp_loc_hardware_watchpoint
+ /* NOTE drow/2003-09-08: This state only exists for removing
+ watchpoints. It's not clear that it's necessary... */
+ && bpt->owner->disposition != disp_del_at_next_stop)
+ {
+ /* FIXME drow/2003-09-08: This code sets multiple hardware watchpoints
+ based on the expression. Ideally this should happen at a higher level,
+ and there should be one bp_location for each computed address we
+ must watch. As soon as a many-to-one mapping is available I'll
+ convert this. */
+
+ struct frame_info *saved_frame;
+ int saved_level, within_current_scope;
+ struct value *mark = value_mark ();
+ struct value *v;
+
+ /* Save the current frame and level so we can restore it after
+ evaluating the watchpoint expression on its own frame. */
+ /* FIXME drow/2003-09-09: It would be nice if evaluate_expression
+ took a frame parameter, so that we didn't have to change the
+ selected frame. */
+ saved_frame = deprecated_selected_frame;
+ saved_level = frame_relative_level (deprecated_selected_frame);
+
+ /* Determine if the watchpoint is within scope. */
+ if (bpt->owner->exp_valid_block == NULL)
+ within_current_scope = 1;
+ else
+ {
+ struct frame_info *fi;
+ fi = frame_find_by_id (bpt->owner->watchpoint_frame);
+ within_current_scope = (fi != NULL);
+ if (within_current_scope)
+ select_frame (fi);
+ }
+
+ if (within_current_scope)
+ {
+ /* Evaluate the expression and cut the chain of values
+ produced off from the value chain.
+
+ Make sure the value returned isn't lazy; we use
+ laziness to determine what memory GDB actually needed
+ in order to compute the value of the expression. */
+ v = evaluate_expression (bpt->owner->exp);
+ VALUE_CONTENTS (v);
+ value_release_to_mark (mark);
+
+ bpt->owner->val_chain = v;
+ bpt->inserted = 1;
+
+ /* Look at each value on the value chain. */
+ for (; v; v = v->next)
+ {
+ /* If it's a memory location, and GDB actually needed
+ its contents to evaluate the expression, then we
+ must watch it. */
+ if (VALUE_LVAL (v) == lval_memory
+ && ! VALUE_LAZY (v))
+ {
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ /* We only watch structs and arrays if user asked
+ for it explicitly, never if they just happen to
+ appear in the middle of some value chain. */
+ if (v == bpt->owner->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR addr;
+ int len, type;
+
+ addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ len = TYPE_LENGTH (VALUE_TYPE (v));
+ type = hw_write;
+ if (bpt->owner->type == bp_read_watchpoint)
+ type = hw_read;
+ else if (bpt->owner->type == bp_access_watchpoint)
+ type = hw_access;
+
+ val = target_insert_watchpoint (addr, len, type);
+ if (val == -1)
+ {
+ /* Don't exit the loop, try to insert
+ every value on the value chain. That's
+ because we will be removing all the
+ watches below, and removing a
+ watchpoint we didn't insert could have
+ adverse effects. */
+ bpt->inserted = 0;
+ }
+ val = 0;
+ }
+ }
+ }
+ /* Failure to insert a watchpoint on any memory value in the
+ value chain brings us here. */
+ if (!bpt->inserted)
+ {
+ remove_breakpoint (bpt, mark_uninserted);
+ *hw_breakpoint_error = 1;
+ fprintf_unfiltered (tmp_error_stream,
+ "Could not insert hardware watchpoint %d.\n",
+ bpt->owner->number);
+ val = -1;
+ }
+ }
+ else
+ {
+ printf_filtered ("Hardware watchpoint %d deleted ", bpt->owner->number);
+ printf_filtered ("because the program has left the block \n");
+ printf_filtered ("in which its expression is valid.\n");
+ if (bpt->owner->related_breakpoint)
+ bpt->owner->related_breakpoint->disposition = disp_del_at_next_stop;
+ bpt->owner->disposition = disp_del_at_next_stop;
+ }
+
+ /* Restore the frame and level. */
+ if (saved_frame != deprecated_selected_frame
+ || saved_level != frame_relative_level (deprecated_selected_frame))
+ select_frame (saved_frame);
+
+ return val;
+ }
+
+ else if (ep_is_exception_catchpoint (bpt->owner))
+ {
+ /* FIXME drow/2003-09-09: This code sets both a catchpoint and a
+ breakpoint. Once again, it would be better if this was represented
+ as two bp_locations. */
+
+ /* If we get here, we must have a callback mechanism for exception
+ events -- with g++ style embedded label support, we insert
+ ordinary breakpoints and not catchpoints. */
+ val = target_insert_breakpoint (bpt->address, bpt->shadow_contents);
+ if (val)
+ {
+ /* Couldn't set breakpoint for some reason */
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert catchpoint %d; disabling it.\n",
+ bpt->owner->number);
+ fprintf_filtered (tmp_error_stream,
+ "Error accessing memory address ");
+ print_address_numeric (bpt->address, 1, tmp_error_stream);
+ fprintf_filtered (tmp_error_stream, ": %s.\n",
+ safe_strerror (val));
+ bpt->owner->enable_state = bp_disabled;
+ }
+ else
+ {
+ /* Bp set, now make sure callbacks are enabled */
+ /* Format possible error msg */
+ char *message = xstrprintf ("Error inserting catchpoint %d:\n",
+ bpt->owner->number);
+ struct cleanup *cleanups = make_cleanup (xfree, message);
+ int val;
+ args_for_catchpoint_enable args;
+ args.kind = bpt->owner->type == bp_catch_catch ?
+ EX_EVENT_CATCH : EX_EVENT_THROW;
+ args.enable_p = 1;
+ val = catch_errors (cover_target_enable_exception_callback,
+ &args, message, RETURN_MASK_ALL);
+ do_cleanups (cleanups);
+ if (val != 0 && val != -1)
+ bpt->inserted = 1;
+
+ /* Check if something went wrong; val == 0 can be ignored */
+ if (val == -1)
+ {
+ /* something went wrong */
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert catchpoint %d; disabling it.\n",
+ bpt->owner->number);
+ bpt->owner->enable_state = bp_disabled;
+ }
+ }
+
+ return val;
+ }
+
+ else if (bpt->owner->type == bp_catch_fork
+ || bpt->owner->type == bp_catch_vfork
+ || bpt->owner->type == bp_catch_exec)
+ {
+ char *prefix = xstrprintf ("warning: inserting catchpoint %d: ",
+ bpt->owner->number);
+ struct cleanup *cleanups = make_cleanup (xfree, prefix);
+ val = catch_exceptions (uiout, insert_catchpoint, bpt->owner, prefix,
+ RETURN_MASK_ERROR);
+ do_cleanups (cleanups);
+ if (val < 0)
+ bpt->owner->enable_state = bp_disabled;
+ else
+ bpt->inserted = 1;
+
+ /* We've already printed an error message if there was a problem
+ inserting this catchpoint, and we've disabled the catchpoint,
+ so just return success. */
+ return 0;
+ }
+
+ return 0;
+}
+
+/* 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 (void)
+{
+ struct bp_location *b, *temp;
+ int return_val = 0; /* return success code. */
+ int val = 0;
+ int disabled_breaks = 0;
+ int hw_breakpoint_error = 0;
+ int process_warning = 0;
+
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_error_stream);
+
+ /* Explicitly mark the warning -- this will only be printed if
+ there was an error. */
+ fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+ ALL_BP_LOCATIONS_SAFE (b, temp)
+ {
+ /* Permanent breakpoints cannot be inserted or removed. Disabled
+ breakpoints should not be inserted. */
+ if (!breakpoint_enabled (b->owner))
+ continue;
+
+ /* FIXME drow/2003-10-07: This code should be pushed elsewhere when
+ hardware watchpoints are split into multiple loc breakpoints. */
+ if ((b->loc_type == bp_loc_hardware_watchpoint
+ || b->owner->type == bp_watchpoint) && !b->owner->val)
+ {
+ struct value *val;
+ val = evaluate_expression (b->owner->exp);
+ release_value (val);
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+ b->owner->val = val;
+ }
+
+ val = insert_bp_location (b, tmp_error_stream,
+ &disabled_breaks, &process_warning,
+ &hw_breakpoint_error);
+ if (val)
+ return_val = val;
+ }
+
+ if (return_val)
+ {
+ /* If a hardware breakpoint or watchpoint was inserted, add a
+ message about possibly exhausted resources. */
+ if (hw_breakpoint_error)
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "Could not insert hardware breakpoints:\n\
+You may have requested too many hardware breakpoints/watchpoints.\n");
+ }
+#ifdef ONE_PROCESS_WRITETEXT
+ if (process_warning)
+ fprintf_unfiltered (tmp_error_stream,
+ "The same program may be running in another process.");
+#endif
+ target_terminal_ours_for_output ();
+ error_stream (tmp_error_stream);
+ }
+ return return_val;
+}
+
+int
+remove_breakpoints (void)
+{
+ struct bp_location *b;
+ int val;
+
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->inserted)
+ {
+ val = remove_breakpoint (b, mark_uninserted);
+ if (val != 0)
+ return val;
+ }
+ }
+ return 0;
+}
+
+int
+remove_hw_watchpoints (void)
+{
+ struct bp_location *b;
+ int val;
+
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->inserted && b->loc_type == bp_loc_hardware_watchpoint)
+ {
+ val = remove_breakpoint (b, mark_uninserted);
+ if (val != 0)
+ return val;
+ }
+ }
+ return 0;
+}
+
+int
+reattach_breakpoints (int pid)
+{
+ struct bp_location *b;
+ int val;
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ /* Set inferior_ptid; remove_breakpoint uses this global. */
+ inferior_ptid = pid_to_ptid (pid);
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->inserted)
+ {
+ remove_breakpoint (b, mark_inserted);
+ if (b->loc_type == bp_loc_hardware_breakpoint)
+ val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
+ else
+ val = target_insert_breakpoint (b->address, b->shadow_contents);
+ /* FIXME drow/2003-10-07: This doesn't handle any other kinds of
+ breakpoints. It's wrong for watchpoints, for example. */
+ if (val != 0)
+ {
+ do_cleanups (old_chain);
+ return val;
+ }
+ }
+ }
+ do_cleanups (old_chain);
+ return 0;
+}
+
+void
+update_breakpoints_after_exec (void)
+{
+ struct breakpoint *b;
+ struct breakpoint *temp;
+
+ /* Doing this first prevents the badness of having delete_breakpoint()
+ write a breakpoint's current "shadow contents" to lift the bp. That
+ shadow is NOT valid after an exec()! */
+ mark_breakpoints_out ();
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ /* Solib breakpoints must be explicitly reset after an exec(). */
+ if (b->type == bp_shlib_event)
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
+ /* Thread event breakpoints must be set anew after an exec(),
+ as must overlay event breakpoints. */
+ if (b->type == bp_thread_event || b->type == bp_overlay_event)
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
+ /* Step-resume breakpoints are meaningless after an exec(). */
+ if (b->type == bp_step_resume)
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
+ /* Ditto the sigtramp handler breakpoints. */
+ if (b->type == bp_through_sigtramp)
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
+ /* Ditto the exception-handling catchpoints. */
+ if ((b->type == bp_catch_catch) || (b->type == bp_catch_throw))
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
+ /* Don't delete an exec catchpoint, because else the inferior
+ won't stop when it ought!
+
+ Similarly, we probably ought to keep vfork catchpoints, 'cause
+ on this target, we may not be able to stop when the vfork is
+ seen, but only when the subsequent exec is seen. (And because
+ deleting fork catchpoints here but not vfork catchpoints will
+ seem mysterious to users, keep those too.)
+
+ ??rehrauer: Let's hope that merely clearing out this catchpoint's
+ target address field, if any, is sufficient to have it be reset
+ automagically. Certainly on HP-UX that's true.
+
+ Jim Blandy <jimb@redhat.com>: Actually, zero is a perfectly
+ valid code address on some platforms (like the mn10300
+ simulators). We shouldn't assign any special interpretation to
+ a breakpoint with a zero address. And in fact, GDB doesn't ---
+ I can't see what that comment above is talking about. As far
+ as I can tell, setting the address of a
+ bp_catch_exec/bp_catch_vfork/bp_catch_fork breakpoint to zero
+ is meaningless, since those are implemented with HP-UX kernel
+ hackery, not by storing breakpoint instructions somewhere. */
+ if ((b->type == bp_catch_exec) ||
+ (b->type == bp_catch_vfork) ||
+ (b->type == bp_catch_fork))
+ {
+ b->loc->address = (CORE_ADDR) NULL;
+ continue;
+ }
+
+ /* bp_finish is a special case. The only way we ought to be able
+ to see one of these when an exec() has happened, is if the user
+ caught a vfork, and then said "finish". Ordinarily a finish just
+ carries them to the call-site of the current callee, by setting
+ a temporary bp there and resuming. But in this case, the finish
+ will carry them entirely through the vfork & exec.
+
+ We don't want to allow a bp_finish to remain inserted now. But
+ we can't safely delete it, 'cause finish_command has a handle to
+ the bp on a bpstat, and will later want to delete it. There's a
+ chance (and I've seen it happen) that if we delete the bp_finish
+ here, that its storage will get reused by the time finish_command
+ gets 'round to deleting the "use to be a bp_finish" breakpoint.
+ We really must allow finish_command to delete a bp_finish.
+
+ In the absense of a general solution for the "how do we know
+ it's safe to delete something others may have handles to?"
+ problem, what we'll do here is just uninsert the bp_finish, and
+ let finish_command delete it.
+
+ (We know the bp_finish is "doomed" in the sense that it's
+ momentary, and will be deleted as soon as finish_command sees
+ the inferior stopped. So it doesn't matter that the bp's
+ address is probably bogus in the new a.out, unlike e.g., the
+ solib breakpoints.) */
+
+ if (b->type == bp_finish)
+ {
+ continue;
+ }
+
+ /* Without a symbolic address, we have little hope of the
+ pre-exec() address meaning the same thing in the post-exec()
+ a.out. */
+ if (b->addr_string == NULL)
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
+ /* If this breakpoint has survived the above battery of checks, then
+ it must have a symbolic address. Be sure that it gets reevaluated
+ to a target address, rather than reusing the old evaluation.
+
+ Jim Blandy <jimb@redhat.com>: As explained above in the comment
+ for bp_catch_exec and friends, I'm pretty sure this is entirely
+ unnecessary. A call to breakpoint_re_set_one always recomputes
+ the breakpoint's address from scratch, or deletes it if it can't.
+ So I think this assignment could be deleted without effect. */
+ b->loc->address = (CORE_ADDR) NULL;
+ }
+ /* FIXME what about longjmp breakpoints? Re-create them here? */
+ create_overlay_event_breakpoint ("_ovly_debug_event");
+}
+
+int
+detach_breakpoints (int pid)
+{
+ struct bp_location *b;
+ int val;
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ if (pid == PIDGET (inferior_ptid))
+ error ("Cannot detach breakpoints of inferior_ptid");
+
+ /* Set inferior_ptid; remove_breakpoint uses this global. */
+ inferior_ptid = pid_to_ptid (pid);
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->inserted)
+ {
+ val = remove_breakpoint (b, mark_inserted);
+ if (val != 0)
+ {
+ do_cleanups (old_chain);
+ return val;
+ }
+ }
+ }
+ do_cleanups (old_chain);
+ return 0;
+}
+
+static int
+remove_breakpoint (struct bp_location *b, insertion_state_t is)
+{
+ int val;
+
+ if (b->owner->enable_state == bp_permanent)
+ /* Permanent breakpoints cannot be inserted or removed. */
+ return 0;
+
+ if (b->owner->type == bp_none)
+ warning ("attempted to remove apparently deleted breakpoint #%d?",
+ b->owner->number);
+
+ if (b->loc_type == bp_loc_software_breakpoint
+ || b->loc_type == bp_loc_hardware_breakpoint)
+ {
+ /* "Normal" instruction breakpoint: either the standard
+ trap-instruction bp (bp_breakpoint), or a
+ bp_hardware_breakpoint. */
+
+ /* First check to see if we have to handle an overlay. */
+ if (overlay_debugging == ovly_off
+ || b->section == NULL
+ || !(section_is_overlay (b->section)))
+ {
+ /* No overlay handling: just remove the breakpoint. */
+
+ if (b->loc_type == bp_loc_hardware_breakpoint)
+ val = target_remove_hw_breakpoint (b->address,
+ b->shadow_contents);
+ else
+ val = target_remove_breakpoint (b->address, b->shadow_contents);
+ }
+ else
+ {
+ /* This breakpoint is in an overlay section.
+ Did we set a breakpoint at the LMA? */
+ if (!overlay_events_enabled)
+ {
+ /* Yes -- overlay event support is not active, so we
+ should have set a breakpoint at the LMA. Remove it.
+ */
+ CORE_ADDR addr = overlay_unmapped_address (b->address,
+ b->section);
+ /* Ignore any failures: if the LMA is in ROM, we will
+ have already warned when we failed to insert it. */
+ if (b->loc_type == bp_loc_hardware_breakpoint)
+ target_remove_hw_breakpoint (addr, b->shadow_contents);
+ else
+ target_remove_breakpoint (addr, b->shadow_contents);
+ }
+ /* Did we set a breakpoint at the VMA?
+ If so, we will have marked the breakpoint 'inserted'. */
+ if (b->inserted)
+ {
+ /* Yes -- remove it. Previously we did not bother to
+ remove the breakpoint if the section had been
+ unmapped, but let's not rely on that being safe. We
+ don't know what the overlay manager might do. */
+ if (b->loc_type == bp_loc_hardware_breakpoint)
+ val = target_remove_hw_breakpoint (b->address,
+ b->shadow_contents);
+ else
+ val = target_remove_breakpoint (b->address,
+ b->shadow_contents);
+ }
+ else
+ {
+ /* No -- not inserted, so no need to remove. No error. */
+ val = 0;
+ }
+ }
+ if (val)
+ return val;
+ b->inserted = (is == mark_inserted);
+ }
+ else if (b->loc_type == bp_loc_hardware_watchpoint
+ && breakpoint_enabled (b->owner)
+ && !b->duplicate)
+ {
+ struct value *v;
+ struct value *n;
+
+ b->inserted = (is == mark_inserted);
+ /* Walk down the saved value chain. */
+ for (v = b->owner->val_chain; v; v = v->next)
+ {
+ /* For each memory reference remove the watchpoint
+ at that address. */
+ if (VALUE_LVAL (v) == lval_memory
+ && ! VALUE_LAZY (v))
+ {
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ if (v == b->owner->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR addr;
+ int len, type;
+
+ addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ len = TYPE_LENGTH (VALUE_TYPE (v));
+ type = hw_write;
+ if (b->owner->type == bp_read_watchpoint)
+ type = hw_read;
+ else if (b->owner->type == bp_access_watchpoint)
+ type = hw_access;
+
+ val = target_remove_watchpoint (addr, len, type);
+ if (val == -1)
+ b->inserted = 1;
+ val = 0;
+ }
+ }
+ }
+ /* Failure to remove any of the hardware watchpoints comes here. */
+ if ((is == mark_uninserted) && (b->inserted))
+ warning ("Could not remove hardware watchpoint %d.",
+ b->owner->number);
+
+ /* Free the saved value chain. We will construct a new one
+ the next time the watchpoint is inserted. */
+ for (v = b->owner->val_chain; v; v = n)
+ {
+ n = v->next;
+ value_free (v);
+ }
+ b->owner->val_chain = NULL;
+ }
+ else if ((b->owner->type == bp_catch_fork ||
+ b->owner->type == bp_catch_vfork ||
+ b->owner->type == bp_catch_exec)
+ && breakpoint_enabled (b->owner)
+ && !b->duplicate)
+ {
+ val = -1;
+ switch (b->owner->type)
+ {
+ case bp_catch_fork:
+ val = target_remove_fork_catchpoint (PIDGET (inferior_ptid));
+ break;
+ case bp_catch_vfork:
+ val = target_remove_vfork_catchpoint (PIDGET (inferior_ptid));
+ break;
+ case bp_catch_exec:
+ val = target_remove_exec_catchpoint (PIDGET (inferior_ptid));
+ break;
+ default:
+ warning ("Internal error, %s line %d.", __FILE__, __LINE__);
+ break;
+ }
+ if (val)
+ return val;
+ b->inserted = (is == mark_inserted);
+ }
+ else if ((b->owner->type == bp_catch_catch ||
+ b->owner->type == bp_catch_throw)
+ && breakpoint_enabled (b->owner)
+ && !b->duplicate)
+ {
+
+ val = target_remove_breakpoint (b->address, b->shadow_contents);
+ if (val)
+ return val;
+ b->inserted = (is == mark_inserted);
+ }
+ else if (ep_is_exception_catchpoint (b->owner)
+ && b->inserted /* sometimes previous insert doesn't happen */
+ && breakpoint_enabled (b->owner)
+ && !b->duplicate)
+ {
+
+ val = target_remove_breakpoint (b->address, b->shadow_contents);
+ if (val)
+ return val;
+
+ b->inserted = (is == mark_inserted);
+ }
+
+ return 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints. */
+
+void
+mark_breakpoints_out (void)
+{
+ struct bp_location *bpt;
+
+ ALL_BP_LOCATIONS (bpt)
+ bpt->inserted = 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints and delete any
+ breakpoints which should go away between runs of the program.
+
+ Plus other such housekeeping that has to be done for breakpoints
+ between runs.
+
+ Note: this function gets called at the end of a run (by
+ generic_mourn_inferior) and when a run begins (by
+ init_wait_for_inferior). */
+
+
+
+void
+breakpoint_init_inferior (enum inf_context context)
+{
+ struct breakpoint *b, *temp;
+ struct bp_location *bpt;
+ static int warning_needed = 0;
+
+ ALL_BP_LOCATIONS (bpt)
+ bpt->inserted = 0;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ switch (b->type)
+ {
+ case bp_call_dummy:
+ case bp_watchpoint_scope:
+
+ /* 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.
+
+ Also get rid of scope breakpoints. */
+ delete_breakpoint (b);
+ break;
+
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+
+ /* Likewise for watchpoints on local expressions. */
+ if (b->exp_valid_block != NULL)
+ delete_breakpoint (b);
+ if (context == inf_starting)
+ {
+ /* Reset val field to force reread of starting value
+ in insert_breakpoints. */
+ if (b->val)
+ value_free (b->val);
+ b->val = NULL;
+ }
+ break;
+ default:
+ /* Likewise for exception catchpoints in dynamic-linked
+ executables where required */
+ if (ep_is_exception_catchpoint (b) &&
+ exception_catchpoints_are_fragile)
+ {
+ warning_needed = 1;
+ delete_breakpoint (b);
+ }
+ break;
+ }
+ }
+
+ if (exception_catchpoints_are_fragile)
+ exception_support_initialized = 0;
+
+ /* Don't issue the warning unless it's really needed... */
+ if (warning_needed && (context != inf_exited))
+ {
+ warning ("Exception catchpoints from last run were deleted.");
+ warning ("You must reinsert them explicitly.");
+ warning_needed = 0;
+ }
+}
+
+/* breakpoint_here_p (PC) returns non-zero if an enabled breakpoint
+ exists at PC. It returns ordinary_breakpoint_here if it's an
+ ordinary breakpoint, or permanent_breakpoint_here if it's a
+ permanent breakpoint.
+ - When continuing from a location with an ordinary breakpoint, we
+ actually single step once before calling insert_breakpoints.
+ - When continuing from a localion with a permanent breakpoint, we
+ need to use the `SKIP_PERMANENT_BREAKPOINT' macro, provided by
+ the target, to advance the PC past the breakpoint. */
+
+enum breakpoint_here
+breakpoint_here_p (CORE_ADDR pc)
+{
+ struct bp_location *bpt;
+ int any_breakpoint_here = 0;
+
+ ALL_BP_LOCATIONS (bpt)
+ {
+ if (bpt->loc_type != bp_loc_software_breakpoint
+ && bpt->loc_type != bp_loc_hardware_breakpoint)
+ continue;
+
+ if ((breakpoint_enabled (bpt->owner)
+ || bpt->owner->enable_state == bp_permanent)
+ && bpt->address == pc) /* bp is enabled and matches pc */
+ {
+ if (overlay_debugging
+ && section_is_overlay (bpt->section)
+ && !section_is_mapped (bpt->section))
+ continue; /* unmapped overlay -- can't be a match */
+ else if (bpt->owner->enable_state == bp_permanent)
+ return permanent_breakpoint_here;
+ else
+ any_breakpoint_here = 1;
+ }
+ }
+
+ return any_breakpoint_here ? ordinary_breakpoint_here : 0;
+}
+
+
+/* breakpoint_inserted_here_p (PC) is just like breakpoint_here_p(),
+ but it only returns true if there is actually a breakpoint inserted
+ at PC. */
+
+int
+breakpoint_inserted_here_p (CORE_ADDR pc)
+{
+ struct bp_location *bpt;
+
+ ALL_BP_LOCATIONS (bpt)
+ {
+ if (bpt->loc_type != bp_loc_software_breakpoint
+ && bpt->loc_type != bp_loc_hardware_breakpoint)
+ continue;
+
+ if (bpt->inserted
+ && bpt->address == pc) /* bp is inserted and matches pc */
+ {
+ if (overlay_debugging
+ && section_is_overlay (bpt->section)
+ && !section_is_mapped (bpt->section))
+ continue; /* unmapped overlay -- can't be a match */
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* This function returns non-zero iff there is a software breakpoint
+ inserted at PC. */
+
+int
+software_breakpoint_inserted_here_p (CORE_ADDR pc)
+{
+ struct bp_location *bpt;
+ int any_breakpoint_here = 0;
+
+ ALL_BP_LOCATIONS (bpt)
+ {
+ if (bpt->loc_type != bp_loc_software_breakpoint)
+ continue;
+
+ if ((breakpoint_enabled (bpt->owner)
+ || bpt->owner->enable_state == bp_permanent)
+ && bpt->inserted
+ && bpt->address == pc) /* bp is enabled and matches pc */
+ {
+ if (overlay_debugging
+ && section_is_overlay (bpt->section)
+ && !section_is_mapped (bpt->section))
+ continue; /* unmapped overlay -- can't be a match */
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Return nonzero if FRAME is a dummy frame. We can't use
+ DEPRECATED_PC_IN_CALL_DUMMY because figuring out the saved SP would
+ take too much time, at least using frame_register() on the 68k.
+ This means that for this function to work right a port must use the
+ bp_call_dummy breakpoint. */
+
+int
+deprecated_frame_in_dummy (struct frame_info *frame)
+{
+ struct breakpoint *b;
+
+ /* This function is used by two files: get_frame_type(), after first
+ checking that !DEPRECATED_USE_GENERIC_DUMMY_FRAMES; and
+ sparc-tdep.c, which doesn't yet use generic dummy frames anyway. */
+ gdb_assert (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES);
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->type == bp_call_dummy
+ && frame_id_eq (b->frame_id, get_frame_id (frame))
+ /* We need to check the PC as well as the frame on the sparc,
+ for signals.exp in the testsuite. */
+ && (get_frame_pc (frame)
+ >= (b->loc->address
+ - DEPRECATED_SIZEOF_CALL_DUMMY_WORDS / sizeof (LONGEST) * DEPRECATED_REGISTER_SIZE))
+ && get_frame_pc (frame) <= b->loc->address)
+ return 1;
+ }
+ return 0;
+}
+
+/* breakpoint_thread_match (PC, PTID) returns true if the breakpoint at
+ PC is valid for process/thread PTID. */
+
+int
+breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
+{
+ struct bp_location *bpt;
+ int thread;
+
+ thread = pid_to_thread_id (ptid);
+
+ ALL_BP_LOCATIONS (bpt)
+ {
+ if (bpt->loc_type != bp_loc_software_breakpoint
+ && bpt->loc_type != bp_loc_hardware_breakpoint)
+ continue;
+
+ if ((breakpoint_enabled (bpt->owner)
+ || bpt->owner->enable_state == bp_permanent)
+ && bpt->address == pc
+ && (bpt->owner->thread == -1 || bpt->owner->thread == thread))
+ {
+ if (overlay_debugging
+ && section_is_overlay (bpt->section)
+ && !section_is_mapped (bpt->section))
+ continue; /* unmapped overlay -- can't be a match */
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/* bpstat stuff. External routines' interfaces are documented
+ in breakpoint.h. */
+
+int
+ep_is_catchpoint (struct breakpoint *ep)
+{
+ return
+ (ep->type == bp_catch_load)
+ || (ep->type == bp_catch_unload)
+ || (ep->type == bp_catch_fork)
+ || (ep->type == bp_catch_vfork)
+ || (ep->type == bp_catch_exec)
+ || (ep->type == bp_catch_catch)
+ || (ep->type == bp_catch_throw);
+
+ /* ??rehrauer: Add more kinds here, as are implemented... */
+}
+
+int
+ep_is_shlib_catchpoint (struct breakpoint *ep)
+{
+ return
+ (ep->type == bp_catch_load)
+ || (ep->type == bp_catch_unload);
+}
+
+int
+ep_is_exception_catchpoint (struct breakpoint *ep)
+{
+ return
+ (ep->type == bp_catch_catch)
+ || (ep->type == bp_catch_throw);
+}
+
+/* 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 (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_command_lines (&p->commands);
+ xfree (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 (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 (bs->commands != NULL)
+ tmp->commands = copy_command_lines (bs->commands);
+ if (bs->old_val != NULL)
+ tmp->old_val = value_copy (bs->old_val);
+
+ 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 (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;
+}
+
+/* Find a step_resume breakpoint associated with this bpstat.
+ (If there are multiple step_resume bp's on the list, this function
+ will arbitrarily pick one.)
+
+ It is an error to use this function if BPSTAT doesn't contain a
+ step_resume breakpoint.
+
+ See wait_for_inferior's use of this function. */
+struct breakpoint *
+bpstat_find_step_resume_breakpoint (bpstat bsp)
+{
+ int current_thread;
+
+ if (bsp == NULL)
+ error ("Internal error (bpstat_find_step_resume_breakpoint)");
+
+ current_thread = pid_to_thread_id (inferior_ptid);
+
+ for (; bsp != NULL; bsp = bsp->next)
+ {
+ if ((bsp->breakpoint_at != NULL) &&
+ (bsp->breakpoint_at->type == bp_step_resume) &&
+ (bsp->breakpoint_at->thread == current_thread ||
+ bsp->breakpoint_at->thread == -1))
+ return bsp->breakpoint_at;
+ }
+
+ error ("Internal error (no step_resume breakpoint found)");
+}
+
+
+/* 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 (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 (bpstat bs)
+{
+ for (; bs != NULL; bs = bs->next)
+ {
+ free_command_lines (&bs->commands);
+ 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 */
+static void
+cleanup_executing_breakpoints (void *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 (bpstat *bsp)
+{
+ bpstat bs;
+ struct cleanup *old_chain;
+
+ /* Avoid endless recursion if a `source' command is contained
+ in bs->commands. */
+ if (executing_breakpoint_commands)
+ return;
+
+ executing_breakpoint_commands = 1;
+ old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
+
+top:
+ /* Note that (as of this writing), our callers all appear to
+ be passing us the address of global stop_bpstat. And, if
+ our calls to execute_control_command cause the inferior to
+ proceed, that global (and hence, *bsp) will change.
+
+ We must be careful to not touch *bsp unless the inferior
+ has not proceeded. */
+
+ /* This pointer will iterate over the list of bpstat's. */
+ bs = *bsp;
+
+ breakpoint_proceeded = 0;
+ for (; bs != NULL; bs = bs->next)
+ {
+ struct command_line *cmd;
+ struct cleanup *this_cmd_tree_chain;
+
+ /* Take ownership of the BSP's command tree, if it has one.
+
+ The command tree could legitimately contain commands like
+ 'step' and 'next', which call clear_proceed_status, which
+ frees stop_bpstat's command tree. To make sure this doesn't
+ free the tree we're executing out from under us, we need to
+ take ownership of the tree ourselves. Since a given bpstat's
+ commands are only executed once, we don't need to copy it; we
+ can clear the pointer in the bpstat, and make sure we free
+ the tree when we're done. */
+ cmd = bs->commands;
+ bs->commands = 0;
+ this_cmd_tree_chain = make_cleanup_free_command_lines (&cmd);
+
+ while (cmd != NULL)
+ {
+ execute_control_command (cmd);
+
+ if (breakpoint_proceeded)
+ break;
+ else
+ cmd = cmd->next;
+ }
+
+ /* We can free this command tree now. */
+ do_cleanups (this_cmd_tree_chain);
+
+ 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;
+ }
+ do_cleanups (old_chain);
+}
+
+/* This is the normal print 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 values.
+
+ Current scheme: When we stop, bpstat_print() is called. It loops
+ through the bpstat list of things causing this stop, calling the
+ print_bp_stop_message function on each one. The behavior of the
+ print_bp_stop_message function depends on the print_it field of
+ bpstat. If such field so indicates, call this function here.
+
+ Return values from this routine (ultimately used by bpstat_print()
+ and normal_stop() to decide what to do):
+ PRINT_NOTHING: Means we already printed all we needed to print,
+ don't print anything else.
+ PRINT_SRC_ONLY: Means we printed something, and we do *not* desire
+ that something to be followed by a location.
+ PRINT_SCR_AND_LOC: Means we printed something, and we *do* desire
+ that something to be followed by a location.
+ PRINT_UNKNOWN: Means we printed nothing or we need to do some more
+ analysis. */
+
+static enum print_stop_action
+print_it_typical (bpstat bs)
+{
+ struct cleanup *old_chain, *ui_out_chain;
+ struct ui_stream *stb;
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+ /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+ which has since been deleted. */
+ if (bs->breakpoint_at == NULL)
+ return PRINT_UNKNOWN;
+
+ switch (bs->breakpoint_at->type)
+ {
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ if (bs->breakpoint_at->loc->address != bs->breakpoint_at->loc->requested_address)
+ breakpoint_adjustment_warning (bs->breakpoint_at->loc->requested_address,
+ bs->breakpoint_at->loc->address,
+ bs->breakpoint_at->number, 1);
+ annotate_breakpoint (bs->breakpoint_at->number);
+ ui_out_text (uiout, "\nBreakpoint ");
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "breakpoint-hit");
+ ui_out_field_int (uiout, "bkptno", bs->breakpoint_at->number);
+ ui_out_text (uiout, ", ");
+ return PRINT_SRC_AND_LOC;
+ break;
+
+ case bp_shlib_event:
+ /* Did we stop because the user set the stop_on_solib_events
+ variable? (If so, we report this as a generic, "Stopped due
+ to shlib event" message.) */
+ printf_filtered ("Stopped due to shared library event\n");
+ return PRINT_NOTHING;
+ break;
+
+ case bp_thread_event:
+ /* Not sure how we will get here.
+ GDB should not stop for these breakpoints. */
+ printf_filtered ("Thread Event Breakpoint: gdb should not stop!\n");
+ return PRINT_NOTHING;
+ break;
+
+ case bp_overlay_event:
+ /* By analogy with the thread event, GDB should not stop for these. */
+ printf_filtered ("Overlay Event Breakpoint: gdb should not stop!\n");
+ return PRINT_NOTHING;
+ break;
+
+ case bp_catch_load:
+ annotate_catchpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+ printf_filtered ("loaded");
+ printf_filtered (" %s), ", bs->breakpoint_at->triggered_dll_pathname);
+ return PRINT_SRC_AND_LOC;
+ break;
+
+ case bp_catch_unload:
+ annotate_catchpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+ printf_filtered ("unloaded");
+ printf_filtered (" %s), ", bs->breakpoint_at->triggered_dll_pathname);
+ return PRINT_SRC_AND_LOC;
+ break;
+
+ case bp_catch_fork:
+ annotate_catchpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+ printf_filtered ("forked");
+ printf_filtered (" process %d), ",
+ bs->breakpoint_at->forked_inferior_pid);
+ return PRINT_SRC_AND_LOC;
+ break;
+
+ case bp_catch_vfork:
+ annotate_catchpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+ printf_filtered ("vforked");
+ printf_filtered (" process %d), ",
+ bs->breakpoint_at->forked_inferior_pid);
+ return PRINT_SRC_AND_LOC;
+ break;
+
+ case bp_catch_exec:
+ annotate_catchpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nCatchpoint %d (exec'd %s), ",
+ bs->breakpoint_at->number,
+ bs->breakpoint_at->exec_pathname);
+ return PRINT_SRC_AND_LOC;
+ break;
+
+ case bp_catch_catch:
+ if (current_exception_event &&
+ (CURRENT_EXCEPTION_KIND == EX_EVENT_CATCH))
+ {
+ annotate_catchpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nCatchpoint %d (exception caught), ",
+ bs->breakpoint_at->number);
+ printf_filtered ("throw location ");
+ if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
+ printf_filtered ("%s:%d",
+ CURRENT_EXCEPTION_THROW_FILE,
+ CURRENT_EXCEPTION_THROW_LINE);
+ else
+ printf_filtered ("unknown");
+
+ printf_filtered (", catch location ");
+ if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
+ printf_filtered ("%s:%d",
+ CURRENT_EXCEPTION_CATCH_FILE,
+ CURRENT_EXCEPTION_CATCH_LINE);
+ else
+ printf_filtered ("unknown");
+
+ printf_filtered ("\n");
+ /* don't bother to print location frame info */
+ return PRINT_SRC_ONLY;
+ }
+ else
+ {
+ /* really throw, some other bpstat will handle it */
+ return PRINT_UNKNOWN;
+ }
+ break;
+
+ case bp_catch_throw:
+ if (current_exception_event &&
+ (CURRENT_EXCEPTION_KIND == EX_EVENT_THROW))
+ {
+ annotate_catchpoint (bs->breakpoint_at->number);
+ printf_filtered ("\nCatchpoint %d (exception thrown), ",
+ bs->breakpoint_at->number);
+ printf_filtered ("throw location ");
+ if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
+ printf_filtered ("%s:%d",
+ CURRENT_EXCEPTION_THROW_FILE,
+ CURRENT_EXCEPTION_THROW_LINE);
+ else
+ printf_filtered ("unknown");
+
+ printf_filtered (", catch location ");
+ if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
+ printf_filtered ("%s:%d",
+ CURRENT_EXCEPTION_CATCH_FILE,
+ CURRENT_EXCEPTION_CATCH_LINE);
+ else
+ printf_filtered ("unknown");
+
+ printf_filtered ("\n");
+ /* don't bother to print location frame info */
+ return PRINT_SRC_ONLY;
+ }
+ else
+ {
+ /* really catch, some other bpstat will handle it */
+ return PRINT_UNKNOWN;
+ }
+ break;
+
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ if (bs->old_val != NULL)
+ {
+ annotate_watchpoint (bs->breakpoint_at->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "watchpoint-trigger");
+ mention (bs->breakpoint_at);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "old", stb);
+ ui_out_text (uiout, "\nNew value = ");
+ value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "new", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ }
+ /* More than one watchpoint may have been triggered. */
+ return PRINT_UNKNOWN;
+ break;
+
+ case bp_read_watchpoint:
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "read-watchpoint-trigger");
+ mention (bs->breakpoint_at);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nValue = ");
+ value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "value", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
+ return PRINT_UNKNOWN;
+ break;
+
+ case bp_access_watchpoint:
+ if (bs->old_val != NULL)
+ {
+ annotate_watchpoint (bs->breakpoint_at->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
+ mention (bs->breakpoint_at);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "old", stb);
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ ui_out_text (uiout, "\nNew value = ");
+ }
+ else
+ {
+ mention (bs->breakpoint_at);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nValue = ");
+ }
+ value_print (bs->breakpoint_at->val, stb->stream, 0,Val_pretty_default);
+ ui_out_field_stream (uiout, "new", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
+ return PRINT_UNKNOWN;
+ break;
+
+ /* Fall through, we don't deal with these types of breakpoints
+ here. */
+
+ case bp_finish:
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "function-finished");
+ return PRINT_UNKNOWN;
+ break;
+
+ case bp_until:
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "location-reached");
+ return PRINT_UNKNOWN;
+ break;
+
+ case bp_none:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_step_resume:
+ case bp_through_sigtramp:
+ case bp_watchpoint_scope:
+ case bp_call_dummy:
+ default:
+ return PRINT_UNKNOWN;
+ }
+}
+
+/* Generic routine for printing messages indicating why we
+ stopped. The behavior of this function depends on the value
+ 'print_it' in the bpstat structure. Under some circumstances we
+ may decide not to print anything here and delegate the task to
+ normal_stop(). */
+
+static enum print_stop_action
+print_bp_stop_message (bpstat bs)
+{
+ switch (bs->print_it)
+ {
+ case print_it_noop:
+ /* Nothing should be printed for this bpstat entry. */
+ return PRINT_UNKNOWN;
+ break;
+
+ case print_it_done:
+ /* We still want to print the frame, but we already printed the
+ relevant messages. */
+ return PRINT_SRC_AND_LOC;
+ break;
+
+ case print_it_normal:
+ /* Normal case. Call the breakpoint's print_it method, or
+ print_it_typical. */
+ if (bs->breakpoint_at != NULL && bs->breakpoint_at->ops != NULL
+ && bs->breakpoint_at->ops->print_it != NULL)
+ return bs->breakpoint_at->ops->print_it (bs->breakpoint_at);
+ else
+ return print_it_typical (bs);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "print_bp_stop_message: unrecognized enum value");
+ break;
+ }
+}
+
+/* Print a message indicating what happened. This is called from
+ normal_stop(). The input to this routine is the head of the bpstat
+ list - a list of the eventpoints that caused this stop. This
+ routine calls the generic print routine for printing a message
+ about reasons for stopping. This will print (for example) the
+ "Breakpoint n," part of the output. The return value of this
+ routine is one of:
+
+ PRINT_UNKNOWN: Means we printed nothing
+ PRINT_SRC_AND_LOC: Means we printed something, and expect subsequent
+ code to print the location. An example is
+ "Breakpoint 1, " which should be followed by
+ the location.
+ PRINT_SRC_ONLY: Means we printed something, but there is no need
+ to also print the location part of the message.
+ An example is the catch/throw messages, which
+ don't require a location appended to the end.
+ PRINT_NOTHING: We have done some printing and we don't need any
+ further info to be printed.*/
+
+enum print_stop_action
+bpstat_print (bpstat bs)
+{
+ int 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). */
+ for (; bs; bs = bs->next)
+ {
+ val = print_bp_stop_message (bs);
+ if (val == PRINT_SRC_ONLY
+ || val == PRINT_SRC_AND_LOC
+ || val == PRINT_NOTHING)
+ return val;
+ }
+
+ /* We reached the end of the chain, or we got a null BS to start
+ with and nothing was printed. */
+ return PRINT_UNKNOWN;
+}
+
+/* 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 (void *exp)
+{
+ struct value *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 (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 (void *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 = frame_find_by_id (b->watchpoint_frame);
+ within_current_scope = (fr != NULL);
+ /* in_function_epilogue_p() returns a non-zero value if we're still
+ in the function but the stack frame has already been invalidated.
+ Since we can't rely on the values of local variables after the
+ stack has been destroyed, we are treating the watchpoint in that
+ state as `not changed' without further checking.
+
+ vinschen/2003-09-04: The former implementation left out the case
+ that the watchpoint frame couldn't be found by frame_find_by_id()
+ because the current PC is currently in an epilogue. Calling
+ gdbarch_in_function_epilogue_p() also when fr == NULL fixes that. */
+ if ((!within_current_scope || fr == get_current_frame ())
+ && gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ()))
+ return WP_VALUE_NOT_CHANGED;
+ if (fr && 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);
+ }
+
+ 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. */
+
+ struct value *mark = value_mark ();
+ struct value *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). */
+ /* We print all the stop information in print_it_typical(), but
+ in this case, by the time we call print_it_typical() this bp
+ will be deleted already. So we have no choice but print the
+ information here. */
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "watchpoint-scope");
+ ui_out_text (uiout, "\nWatchpoint ");
+ ui_out_field_int (uiout, "wpnum", bs->breakpoint_at->number);
+ ui_out_text (uiout, " deleted because the program has left the block in\n\
+which its expression is valid.\n");
+
+ if (b->related_breakpoint)
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->disposition = disp_del_at_next_stop;
+
+ return WP_DELETED;
+ }
+}
+
+/* Get a bpstat associated with having just stopped at address
+ BP_ADDR. */
+
+/* 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 (CORE_ADDR bp_addr, ptid_t ptid)
+{
+ struct breakpoint *b, *temp;
+ /* True if we've hit a breakpoint (as opposed to a watchpoint). */
+ int real_breakpoint = 0;
+ /* 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;
+ int thread_id = pid_to_thread_id (ptid);
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
+ 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->type != bp_catch_fork
+ && b->type != bp_catch_vfork
+ && b->type != bp_catch_exec
+ && b->type != bp_catch_catch
+ && b->type != bp_catch_throw) /* a non-watchpoint bp */
+ {
+ if (b->loc->address != bp_addr) /* address doesn't match */
+ continue;
+ if (overlay_debugging /* unmapped overlay section */
+ && section_is_overlay (b->loc->section)
+ && !section_is_mapped (b->loc->section))
+ continue;
+ }
+
+ if (b->type == bp_hardware_breakpoint)
+ {
+ if (b->loc->address != bp_addr)
+ continue;
+ if (overlay_debugging /* unmapped overlay section */
+ && section_is_overlay (b->loc->section)
+ && !section_is_mapped (b->loc->section))
+ continue;
+ }
+
+ /* Is this a catchpoint of a load or unload? If so, did we
+ get a load or unload of the specified library? If not,
+ ignore it. */
+ if ((b->type == bp_catch_load)
+#if defined(SOLIB_HAVE_LOAD_EVENT)
+ && (!SOLIB_HAVE_LOAD_EVENT (PIDGET (inferior_ptid))
+ || ((b->dll_pathname != NULL)
+ && (strcmp (b->dll_pathname,
+ SOLIB_LOADED_LIBRARY_PATHNAME (
+ PIDGET (inferior_ptid)))
+ != 0)))
+#endif
+ )
+ continue;
+
+ if ((b->type == bp_catch_unload)
+#if defined(SOLIB_HAVE_UNLOAD_EVENT)
+ && (!SOLIB_HAVE_UNLOAD_EVENT (PIDGET (inferior_ptid))
+ || ((b->dll_pathname != NULL)
+ && (strcmp (b->dll_pathname,
+ SOLIB_UNLOADED_LIBRARY_PATHNAME (
+ PIDGET (inferior_ptid)))
+ != 0)))
+#endif
+ )
+ continue;
+
+ if ((b->type == bp_catch_fork)
+ && !inferior_has_forked (PIDGET (inferior_ptid),
+ &b->forked_inferior_pid))
+ continue;
+
+ if ((b->type == bp_catch_vfork)
+ && !inferior_has_vforked (PIDGET (inferior_ptid),
+ &b->forked_inferior_pid))
+ continue;
+
+ if ((b->type == bp_catch_exec)
+ && !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname))
+ continue;
+
+ if (ep_is_exception_catchpoint (b) &&
+ !(current_exception_event = target_get_current_exception_event ()))
+ continue;
+
+ /* Come here if it's a watchpoint, or if the break address matches */
+
+ bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */
+
+ /* Watchpoints may change this, if not found to have triggered. */
+ bs->stop = 1;
+ bs->print = 1;
+
+ if (b->type == bp_watchpoint ||
+ b->type == bp_hardware_watchpoint)
+ {
+ char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
+ b->number);
+ struct cleanup *cleanups = make_cleanup (xfree, message);
+ int e = catch_errors (watchpoint_check, bs, message,
+ RETURN_MASK_ALL);
+ do_cleanups (cleanups);
+ switch (e)
+ {
+ case WP_DELETED:
+ /* We've already printed what needs to be printed. */
+ /* Actually this is superfluous, because by the time we
+ call print_it_typical() the wp will be already deleted,
+ and the function will return immediately. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ break;
+ case WP_VALUE_CHANGED:
+ /* Stop. */
+ ++(b->hit_count);
+ 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)
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->disposition = disp_del_at_next_stop;
+ /* 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;
+ struct value *v;
+ int found = 0;
+
+ addr = target_stopped_data_address ();
+ if (addr == 0)
+ continue;
+ for (v = b->val_chain; v; v = v->next)
+ {
+ if (VALUE_LVAL (v) == lval_memory
+ && ! VALUE_LAZY (v))
+ {
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ if (v == b->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR vaddr;
+
+ vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (addr >= vaddr &&
+ addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
+ found = 1;
+ }
+ }
+ }
+ if (found)
+ {
+ char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
+ b->number);
+ struct cleanup *cleanups = make_cleanup (xfree, message);
+ int e = catch_errors (watchpoint_check, bs, message,
+ RETURN_MASK_ALL);
+ do_cleanups (cleanups);
+ switch (e)
+ {
+ case WP_DELETED:
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ break;
+ case WP_VALUE_CHANGED:
+ if (b->type == bp_read_watchpoint)
+ {
+ /* Don't stop: read watchpoints shouldn't fire if
+ the value has changed. This is for targets
+ which cannot set read-only watchpoints. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
+ ++(b->hit_count);
+ break;
+ case WP_VALUE_NOT_CHANGED:
+ /* Stop. */
+ ++(b->hit_count);
+ break;
+ default:
+ /* Can't happen. */
+ case 0:
+ /* Error from catch_errors. */
+ printf_filtered ("Watchpoint %d deleted.\n", b->number);
+ if (b->related_breakpoint)
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->disposition = disp_del_at_next_stop;
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ break;
+ }
+ }
+ else /* found == 0 */
+ {
+ /* This is a case where some watchpoint(s) triggered,
+ but not at the address of this watchpoint (FOUND
+ was left zero). So don't print anything for this
+ watchpoint. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
+ }
+ else
+ {
+ /* By definition, an encountered breakpoint is a triggered
+ breakpoint. */
+ ++(b->hit_count);
+
+ real_breakpoint = 1;
+ }
+
+ if (frame_id_p (b->frame_id)
+ && !frame_id_eq (b->frame_id, get_frame_id (get_current_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 ());
+ value_is_zero
+ = catch_errors (breakpoint_cond_eval, (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;
+ /* Don't consider this a hit. */
+ --(b->hit_count);
+ }
+ else if (b->thread != -1 && b->thread != thread_id)
+ {
+ bs->stop = 0;
+ /* Don't consider this a hit. */
+ --(b->hit_count);
+ }
+ else if (b->ignore_count > 0)
+ {
+ b->ignore_count--;
+ annotate_ignore_count_change ();
+ bs->stop = 0;
+ }
+ else
+ {
+ /* We will stop here */
+ if (b->disposition == disp_disable)
+ b->enable_state = bp_disabled;
+ if (b->silent)
+ bs->print = 0;
+ bs->commands = b->commands;
+ if (bs->commands &&
+ (strcmp ("silent", bs->commands->line) == 0
+ || (xdb_commands && strcmp ("Q", bs->commands->line) == 0)))
+ {
+ bs->commands = bs->commands->next;
+ bs->print = 0;
+ }
+ bs->commands = copy_command_lines (bs->commands);
+ }
+ }
+ /* 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 */
+
+ /* 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 (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,
+
+ /* We caught a shared library event. */
+ catch_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
+#define shlr BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK
+
+/* "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.
+
+ Another possibly interesting property of this table is that
+ there's a partial ordering, priority-like, of the actions. Once
+ you've decided that some action is appropriate, you'll never go
+ back and decide something of a lower priority is better. The
+ ordering is:
+
+ kc < clr sgl shl shlr slr sn sr ss ts
+ sgl < clrs shl shlr slr sn sr ss ts
+ slr < err shl shlr sn sr ss ts
+ clr < clrs err shl shlr sn sr ss ts
+ clrs < err shl shlr sn sr ss ts
+ ss < shl shlr sn sr ts
+ sn < shl shlr sr ts
+ sr < shl shlr ts
+ shl < shlr
+ ts <
+ shlr <
+
+ What I think this means is that we don't need a damned table
+ here. If you just put the rows and columns in the right order,
+ it'd look awfully regular. We could simply walk the bpstat list
+ and choose the highest priority action we find, with a little
+ logic to handle the 'err' cases, and the CLEAR_LONGJMP_RESUME/
+ CLEAR_LONGJMP_RESUME_SINGLE distinction (which breakpoint.h says
+ is messy anyway). */
+
+ /* step_resume entries: a step resume breakpoint overrides another
+ breakpoint of signal handling (see comment in wait_for_inferior
+ at first PC_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 shlr
+ */
+/*no_effect */
+ {kc, ss, sn, sgl, slr, clr, clrs, sr, ts, shl, shlr},
+/*wp_silent */
+ {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
+/*wp_noisy */
+ {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
+/*bp_nostop */
+ {sgl, ss, sn, sgl, slr, clrs, clrs, sr, ts, shl, shlr},
+/*bp_silent */
+ {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
+/*bp_noisy */
+ {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
+/*long_jump */
+ {slr, ss, sn, slr, slr, err, err, sr, ts, shl, shlr},
+/*long_resume */
+ {clr, ss, sn, clrs, err, err, err, sr, ts, shl, shlr},
+/*step_resume */
+ {sr, sr, sr, sr, sr, sr, sr, sr, ts, shl, shlr},
+/*through_sig */
+ {ts, ts, ts, ts, ts, ts, ts, ts, ts, shl, shlr},
+/*shlib */
+ {shl, shl, shl, shl, shl, shl, shl, shl, ts, shl, shlr},
+/*catch_shlib */
+ {shlr, shlr, shlr, shlr, shlr, shlr, shlr, shlr, ts, shlr, shlr}
+ };
+
+#undef kc
+#undef ss
+#undef sn
+#undef sgl
+#undef slr
+#undef clr
+#undef clrs
+#undef err
+#undef sr
+#undef ts
+#undef shl
+#undef shlr
+ 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_none:
+ continue;
+
+ 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_thread_event:
+ case bp_overlay_event:
+ bs_class = bp_nostop;
+ break;
+ case bp_catch_load:
+ case bp_catch_unload:
+ /* Only if this catchpoint triggered should we cause the
+ step-out-of-dld behaviour. Otherwise, we ignore this
+ catchpoint. */
+ if (bs->stop)
+ bs_class = catch_shlib_event;
+ else
+ bs_class = no_effect;
+ break;
+ case bp_catch_fork:
+ case bp_catch_vfork:
+ case bp_catch_exec:
+ if (bs->stop)
+ {
+ if (bs->print)
+ bs_class = bp_noisy;
+ else
+ bs_class = bp_silent;
+ }
+ else
+ /* There was a catchpoint, but we're not stopping.
+ This requires no further action. */
+ bs_class = no_effect;
+ break;
+ case bp_catch_catch:
+ if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_CATCH)
+ bs_class = bp_nostop;
+ else if (bs->stop)
+ bs_class = bs->print ? bp_noisy : bp_silent;
+ break;
+ case bp_catch_throw:
+ if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_THROW)
+ bs_class = bp_nostop;
+ else if (bs->stop)
+ bs_class = bs->print ? bp_noisy : bp_silent;
+ 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 (void)
+{
+ struct breakpoint *b;
+ ALL_BREAKPOINTS (b)
+ if (breakpoint_enabled (b) && b->type == bp_watchpoint)
+ return 1;
+ return 0;
+}
+
+/* Nonzero if there are enabled hardware watchpoints. */
+int
+bpstat_have_active_hw_watchpoints (void)
+{
+ struct bp_location *bpt;
+ ALL_BP_LOCATIONS (bpt)
+ if (breakpoint_enabled (bpt->owner)
+ && bpt->inserted
+ && bpt->loc_type == bp_loc_hardware_watchpoint)
+ return 1;
+ return 0;
+}
+
+
+/* Given a bpstat that records zero or more triggered eventpoints, this
+ function returns another bpstat which contains only the catchpoints
+ on that first list, if any. */
+void
+bpstat_get_triggered_catchpoints (bpstat ep_list, bpstat *cp_list)
+{
+ struct bpstats root_bs[1];
+ bpstat bs = root_bs;
+ struct breakpoint *ep;
+ char *dll_pathname;
+
+ bpstat_clear (cp_list);
+ root_bs->next = NULL;
+
+ for (; ep_list != NULL; ep_list = ep_list->next)
+ {
+ /* Is this eventpoint a catchpoint? If not, ignore it. */
+ ep = ep_list->breakpoint_at;
+ if (ep == NULL)
+ break;
+ if ((ep->type != bp_catch_load) &&
+ (ep->type != bp_catch_unload) &&
+ (ep->type != bp_catch_catch) &&
+ (ep->type != bp_catch_throw))
+ /* pai: (temp) ADD fork/vfork here!! */
+ continue;
+
+ /* Yes; add it to the list. */
+ bs = bpstat_alloc (ep, bs);
+ *bs = *ep_list;
+ bs->next = NULL;
+ bs = root_bs->next;
+
+#if defined(SOLIB_ADD)
+ /* Also, for each triggered catchpoint, tag it with the name of
+ the library that caused this trigger. (We copy the name now,
+ because it's only guaranteed to be available NOW, when the
+ catchpoint triggers. Clients who may wish to know the name
+ later must get it from the catchpoint itself.) */
+ if (ep->triggered_dll_pathname != NULL)
+ xfree (ep->triggered_dll_pathname);
+ if (ep->type == bp_catch_load)
+ dll_pathname = SOLIB_LOADED_LIBRARY_PATHNAME (
+ PIDGET (inferior_ptid));
+ else
+ dll_pathname = SOLIB_UNLOADED_LIBRARY_PATHNAME (
+ PIDGET (inferior_ptid));
+#else
+ dll_pathname = NULL;
+#endif
+ if (dll_pathname)
+ {
+ ep->triggered_dll_pathname = (char *)
+ xmalloc (strlen (dll_pathname) + 1);
+ strcpy (ep->triggered_dll_pathname, dll_pathname);
+ }
+ else
+ ep->triggered_dll_pathname = NULL;
+ }
+
+ *cp_list = bs;
+}
+
+/* Print B to gdb_stdout. */
+static void
+print_one_breakpoint (struct breakpoint *b,
+ CORE_ADDR *last_addr)
+{
+ struct command_line *l;
+ struct symbol *sym;
+ struct ep_type_description
+ {
+ enum bptype type;
+ char *description;
+ };
+ static struct ep_type_description bptypes[] =
+ {
+ {bp_none, "?deleted?"},
+ {bp_breakpoint, "breakpoint"},
+ {bp_hardware_breakpoint, "hw breakpoint"},
+ {bp_until, "until"},
+ {bp_finish, "finish"},
+ {bp_watchpoint, "watchpoint"},
+ {bp_hardware_watchpoint, "hw watchpoint"},
+ {bp_read_watchpoint, "read watchpoint"},
+ {bp_access_watchpoint, "acc watchpoint"},
+ {bp_longjmp, "longjmp"},
+ {bp_longjmp_resume, "longjmp resume"},
+ {bp_step_resume, "step resume"},
+ {bp_through_sigtramp, "sigtramp"},
+ {bp_watchpoint_scope, "watchpoint scope"},
+ {bp_call_dummy, "call dummy"},
+ {bp_shlib_event, "shlib events"},
+ {bp_thread_event, "thread events"},
+ {bp_overlay_event, "overlay events"},
+ {bp_catch_load, "catch load"},
+ {bp_catch_unload, "catch unload"},
+ {bp_catch_fork, "catch fork"},
+ {bp_catch_vfork, "catch vfork"},
+ {bp_catch_exec, "catch exec"},
+ {bp_catch_catch, "catch catch"},
+ {bp_catch_throw, "catch throw"}
+ };
+
+ static char *bpdisps[] =
+ {"del", "dstp", "dis", "keep"};
+ static char bpenables[] = "nynny";
+ char wrap_indent[80];
+ struct ui_stream *stb = ui_out_stream_new (uiout);
+ struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
+ struct cleanup *bkpt_chain;
+
+ annotate_record ();
+ bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "bkpt");
+
+ /* 1 */
+ annotate_field (0);
+ ui_out_field_int (uiout, "number", b->number);
+
+ /* 2 */
+ annotate_field (1);
+ if (((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
+ || ((int) b->type != bptypes[(int) b->type].type))
+ internal_error (__FILE__, __LINE__,
+ "bptypes table does not describe type #%d.",
+ (int) b->type);
+ ui_out_field_string (uiout, "type", bptypes[(int) b->type].description);
+
+ /* 3 */
+ annotate_field (2);
+ ui_out_field_string (uiout, "disp", bpdisps[(int) b->disposition]);
+
+ /* 4 */
+ annotate_field (3);
+ ui_out_field_fmt (uiout, "enabled", "%c", bpenables[(int) b->enable_state]);
+ ui_out_spaces (uiout, 2);
+
+ /* 5 and 6 */
+ strcpy (wrap_indent, " ");
+ if (addressprint)
+ {
+ if (TARGET_ADDR_BIT <= 32)
+ strcat (wrap_indent, " ");
+ else
+ strcat (wrap_indent, " ");
+ }
+
+ if (b->ops != NULL && b->ops->print_one != NULL)
+ b->ops->print_one (b, last_addr);
+ else
+ switch (b->type)
+ {
+ case bp_none:
+ internal_error (__FILE__, __LINE__,
+ "print_one_breakpoint: bp_none encountered\n");
+ break;
+
+ 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). */
+ if (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ print_expression (b->exp, stb->stream);
+ ui_out_field_stream (uiout, "what", stb);
+ break;
+
+ case bp_catch_load:
+ case bp_catch_unload:
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ if (b->dll_pathname == NULL)
+ {
+ ui_out_field_string (uiout, "what", "<any library>");
+ ui_out_spaces (uiout, 1);
+ }
+ else
+ {
+ ui_out_text (uiout, "library \"");
+ ui_out_field_string (uiout, "what", b->dll_pathname);
+ ui_out_text (uiout, "\" ");
+ }
+ break;
+
+ case bp_catch_fork:
+ case bp_catch_vfork:
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ if (b->forked_inferior_pid != 0)
+ {
+ ui_out_text (uiout, "process ");
+ ui_out_field_int (uiout, "what", b->forked_inferior_pid);
+ ui_out_spaces (uiout, 1);
+ }
+
+ case bp_catch_exec:
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ if (b->exec_pathname != NULL)
+ {
+ ui_out_text (uiout, "program \"");
+ ui_out_field_string (uiout, "what", b->exec_pathname);
+ ui_out_text (uiout, "\" ");
+ }
+ break;
+
+ case bp_catch_catch:
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ ui_out_field_string (uiout, "what", "exception catch");
+ ui_out_spaces (uiout, 1);
+ break;
+
+ case bp_catch_throw:
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ ui_out_field_string (uiout, "what", "exception throw");
+ ui_out_spaces (uiout, 1);
+ 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:
+ case bp_thread_event:
+ case bp_overlay_event:
+ if (addressprint)
+ {
+ annotate_field (4);
+ if (b->pending)
+ ui_out_field_string (uiout, "addr", "<PENDING>");
+ else
+ ui_out_field_core_addr (uiout, "addr", b->loc->address);
+ }
+ annotate_field (5);
+ *last_addr = b->loc->address;
+ if (b->source_file)
+ {
+ sym = find_pc_sect_function (b->loc->address, b->loc->section);
+ if (sym)
+ {
+ ui_out_text (uiout, "in ");
+ ui_out_field_string (uiout, "func",
+ SYMBOL_PRINT_NAME (sym));
+ ui_out_wrap_hint (uiout, wrap_indent);
+ ui_out_text (uiout, " at ");
+ }
+ ui_out_field_string (uiout, "file", b->source_file);
+ ui_out_text (uiout, ":");
+ ui_out_field_int (uiout, "line", b->line_number);
+ }
+ else if (b->pending)
+ {
+ ui_out_field_string (uiout, "pending", b->addr_string);
+ }
+ else
+ {
+ print_address_symbolic (b->loc->address, stb->stream, demangle, "");
+ ui_out_field_stream (uiout, "at", stb);
+ }
+ break;
+ }
+
+ if (b->thread != -1)
+ {
+ /* FIXME: This seems to be redundant and lost here; see the
+ "stop only in" line a little further down. */
+ ui_out_text (uiout, " thread ");
+ ui_out_field_int (uiout, "thread", b->thread);
+ }
+
+ ui_out_text (uiout, "\n");
+
+ if (frame_id_p (b->frame_id))
+ {
+ annotate_field (6);
+ ui_out_text (uiout, "\tstop only in stack frame at ");
+ /* FIXME: cagney/2002-12-01: Shouldn't be poeking around inside
+ the frame ID. */
+ ui_out_field_core_addr (uiout, "frame", b->frame_id.stack_addr);
+ ui_out_text (uiout, "\n");
+ }
+
+ if (b->cond)
+ {
+ annotate_field (7);
+ ui_out_text (uiout, "\tstop only if ");
+ print_expression (b->cond, stb->stream);
+ ui_out_field_stream (uiout, "cond", stb);
+ ui_out_text (uiout, "\n");
+ }
+
+ if (b->pending && b->cond_string)
+ {
+ annotate_field (7);
+ ui_out_text (uiout, "\tstop only if ");
+ ui_out_field_string (uiout, "cond", b->cond_string);
+ ui_out_text (uiout, "\n");
+ }
+
+ if (b->thread != -1)
+ {
+ /* FIXME should make an annotation for this */
+ ui_out_text (uiout, "\tstop only in thread ");
+ ui_out_field_int (uiout, "thread", b->thread);
+ ui_out_text (uiout, "\n");
+ }
+
+ if (show_breakpoint_hit_counts && b->hit_count)
+ {
+ /* FIXME should make an annotation for this */
+ if (ep_is_catchpoint (b))
+ ui_out_text (uiout, "\tcatchpoint");
+ else
+ ui_out_text (uiout, "\tbreakpoint");
+ ui_out_text (uiout, " already hit ");
+ ui_out_field_int (uiout, "times", b->hit_count);
+ if (b->hit_count == 1)
+ ui_out_text (uiout, " time\n");
+ else
+ ui_out_text (uiout, " times\n");
+ }
+
+ /* Output the count also if it is zero, but only if this is
+ mi. FIXME: Should have a better test for this. */
+ if (ui_out_is_mi_like_p (uiout))
+ if (show_breakpoint_hit_counts && b->hit_count == 0)
+ ui_out_field_int (uiout, "times", b->hit_count);
+
+ if (b->ignore_count)
+ {
+ annotate_field (8);
+ ui_out_text (uiout, "\tignore next ");
+ ui_out_field_int (uiout, "ignore", b->ignore_count);
+ ui_out_text (uiout, " hits\n");
+ }
+
+ if ((l = b->commands))
+ {
+ struct cleanup *script_chain;
+
+ annotate_field (9);
+ script_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "script");
+ print_command_lines (uiout, l, 4);
+ do_cleanups (script_chain);
+ }
+ do_cleanups (bkpt_chain);
+ do_cleanups (old_chain);
+}
+
+struct captured_breakpoint_query_args
+ {
+ int bnum;
+ };
+
+static int
+do_captured_breakpoint_query (struct ui_out *uiout, void *data)
+{
+ struct captured_breakpoint_query_args *args = data;
+ struct breakpoint *b;
+ CORE_ADDR dummy_addr = 0;
+ ALL_BREAKPOINTS (b)
+ {
+ if (args->bnum == b->number)
+ {
+ print_one_breakpoint (b, &dummy_addr);
+ return GDB_RC_OK;
+ }
+ }
+ return GDB_RC_NONE;
+}
+
+enum gdb_rc
+gdb_breakpoint_query (struct ui_out *uiout, int bnum)
+{
+ struct captured_breakpoint_query_args args;
+ args.bnum = bnum;
+ /* For the moment we don't trust print_one_breakpoint() to not throw
+ an error. */
+ return catch_exceptions (uiout, do_captured_breakpoint_query, &args,
+ NULL, RETURN_MASK_ALL);
+}
+
+/* Return non-zero if B is user settable (breakpoints, watchpoints,
+ catchpoints, et.al.). */
+
+static int
+user_settable_breakpoint (const struct breakpoint *b)
+{
+ return (b->type == bp_breakpoint
+ || b->type == bp_catch_load
+ || b->type == bp_catch_unload
+ || b->type == bp_catch_fork
+ || b->type == bp_catch_vfork
+ || b->type == bp_catch_exec
+ || b->type == bp_catch_catch
+ || b->type == bp_catch_throw
+ || b->type == bp_hardware_breakpoint
+ || b->type == bp_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint
+ || b->type == bp_hardware_watchpoint);
+}
+
+/* Print information on user settable breakpoint (watchpoint, etc)
+ number BNUM. If BNUM is -1 print all user settable breakpoints.
+ If ALLFLAG is non-zero, include non- user settable breakpoints. */
+
+static void
+breakpoint_1 (int bnum, int allflag)
+{
+ struct breakpoint *b;
+ CORE_ADDR last_addr = (CORE_ADDR) -1;
+ int nr_printable_breakpoints;
+ struct cleanup *bkpttbl_chain;
+
+ /* Compute the number of rows in the table. */
+ nr_printable_breakpoints = 0;
+ ALL_BREAKPOINTS (b)
+ if (bnum == -1
+ || bnum == b->number)
+ {
+ if (allflag || user_settable_breakpoint (b))
+ nr_printable_breakpoints++;
+ }
+
+ if (addressprint)
+ bkpttbl_chain
+ = make_cleanup_ui_out_table_begin_end (uiout, 6, nr_printable_breakpoints,
+ "BreakpointTable");
+ else
+ bkpttbl_chain
+ = make_cleanup_ui_out_table_begin_end (uiout, 5, nr_printable_breakpoints,
+ "BreakpointTable");
+
+ if (nr_printable_breakpoints > 0)
+ annotate_breakpoints_headers ();
+ if (nr_printable_breakpoints > 0)
+ annotate_field (0);
+ ui_out_table_header (uiout, 3, ui_left, "number", "Num"); /* 1 */
+ if (nr_printable_breakpoints > 0)
+ annotate_field (1);
+ ui_out_table_header (uiout, 14, ui_left, "type", "Type"); /* 2 */
+ if (nr_printable_breakpoints > 0)
+ annotate_field (2);
+ ui_out_table_header (uiout, 4, ui_left, "disp", "Disp"); /* 3 */
+ if (nr_printable_breakpoints > 0)
+ annotate_field (3);
+ ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb"); /* 4 */
+ if (addressprint)
+ {
+ if (nr_printable_breakpoints > 0)
+ annotate_field (4);
+ if (TARGET_ADDR_BIT <= 32)
+ ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */
+ else
+ ui_out_table_header (uiout, 18, ui_left, "addr", "Address");/* 5 */
+ }
+ if (nr_printable_breakpoints > 0)
+ annotate_field (5);
+ ui_out_table_header (uiout, 40, ui_noalign, "what", "What"); /* 6 */
+ ui_out_table_body (uiout);
+ if (nr_printable_breakpoints > 0)
+ annotate_breakpoints_table ();
+
+ ALL_BREAKPOINTS (b)
+ if (bnum == -1
+ || bnum == b->number)
+ {
+ /* We only print out user settable breakpoints unless the
+ allflag is set. */
+ if (allflag || user_settable_breakpoint (b))
+ print_one_breakpoint (b, &last_addr);
+ }
+
+ do_cleanups (bkpttbl_chain);
+
+ if (nr_printable_breakpoints == 0)
+ {
+ if (bnum == -1)
+ ui_out_message (uiout, 0, "No breakpoints or watchpoints.\n");
+ else
+ ui_out_message (uiout, 0, "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);
+ }
+
+ /* FIXME? Should this be moved up so that it is only called when
+ there have been breakpoints? */
+ annotate_breakpoints_table_end ();
+}
+
+static void
+breakpoints_info (char *bnum_exp, int from_tty)
+{
+ int bnum = -1;
+
+ if (bnum_exp)
+ bnum = parse_and_eval_long (bnum_exp);
+
+ breakpoint_1 (bnum, 0);
+}
+
+static void
+maintenance_info_breakpoints (char *bnum_exp, int from_tty)
+{
+ int bnum = -1;
+
+ if (bnum_exp)
+ bnum = parse_and_eval_long (bnum_exp);
+
+ breakpoint_1 (bnum, 1);
+}
+
+/* Print a message describing any breakpoints set at PC. */
+
+static void
+describe_other_breakpoints (CORE_ADDR pc, asection *section)
+{
+ int others = 0;
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->loc->address == pc) /* address match / overlay match */
+ if (!b->pending && (!overlay_debugging || b->loc->section == section))
+ others++;
+ if (others > 0)
+ {
+ printf_filtered ("Note: breakpoint%s ", (others > 1) ? "s" : "");
+ ALL_BREAKPOINTS (b)
+ if (b->loc->address == pc) /* address match / overlay match */
+ if (!b->pending && (!overlay_debugging || b->loc->section == section))
+ {
+ others--;
+ printf_filtered ("%d%s%s ",
+ b->number,
+ ((b->enable_state == bp_disabled ||
+ b->enable_state == bp_shlib_disabled ||
+ b->enable_state == bp_call_disabled)
+ ? " (disabled)"
+ : b->enable_state == bp_permanent
+ ? " (permanent)"
+ : ""),
+ (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 (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;
+}
+
+/* Return true iff it is meaningful to use the address member of
+ BPT. For some breakpoint types, the address member is irrelevant
+ and it makes no sense to attempt to compare it to other addresses
+ (or use it for any other purpose either).
+
+ More specifically, each of the following breakpoint types will always
+ have a zero valued address and we don't want check_duplicates() to mark
+ breakpoints of any of these types to be a duplicate of an actual
+ breakpoint at address zero:
+
+ bp_watchpoint
+ bp_hardware_watchpoint
+ bp_read_watchpoint
+ bp_access_watchpoint
+ bp_catch_exec
+ bp_longjmp_resume
+ bp_catch_fork
+ bp_catch_vork */
+
+static int
+breakpoint_address_is_meaningful (struct breakpoint *bpt)
+{
+ enum bptype type = bpt->type;
+
+ return (type != bp_watchpoint
+ && type != bp_hardware_watchpoint
+ && type != bp_read_watchpoint
+ && type != bp_access_watchpoint
+ && type != bp_catch_exec
+ && type != bp_longjmp_resume
+ && type != bp_catch_fork
+ && type != bp_catch_vfork);
+}
+
+/* Rescan breakpoints at the same address and section as BPT,
+ marking the first one as "first" and any others as "duplicates".
+ This is so that the bpt instruction is only inserted once.
+ If we have a permanent breakpoint at the same place as BPT, make
+ that one the official one, and the rest as duplicates. */
+
+static void
+check_duplicates (struct breakpoint *bpt)
+{
+ struct bp_location *b;
+ int count = 0;
+ struct bp_location *perm_bp = 0;
+ CORE_ADDR address = bpt->loc->address;
+ asection *section = bpt->loc->section;
+
+ if (! breakpoint_address_is_meaningful (bpt))
+ return;
+
+ ALL_BP_LOCATIONS (b)
+ if (b->owner->enable_state != bp_disabled
+ && b->owner->enable_state != bp_shlib_disabled
+ && !b->owner->pending
+ && b->owner->enable_state != bp_call_disabled
+ && b->address == address /* address / overlay match */
+ && (!overlay_debugging || b->section == section)
+ && breakpoint_address_is_meaningful (b->owner))
+ {
+ /* Have we found a permanent breakpoint? */
+ if (b->owner->enable_state == bp_permanent)
+ {
+ perm_bp = b;
+ break;
+ }
+
+ count++;
+ b->duplicate = count > 1;
+ }
+
+ /* If we found a permanent breakpoint at this address, go over the
+ list again and declare all the other breakpoints there to be the
+ duplicates. */
+ if (perm_bp)
+ {
+ perm_bp->duplicate = 0;
+
+ /* Permanent breakpoint should always be inserted. */
+ if (! perm_bp->inserted)
+ internal_error (__FILE__, __LINE__,
+ "allegedly permanent breakpoint is not "
+ "actually inserted");
+
+ ALL_BP_LOCATIONS (b)
+ if (b != perm_bp)
+ {
+ if (b->owner->enable_state != bp_disabled
+ && b->owner->enable_state != bp_shlib_disabled
+ && !b->owner->pending
+ && b->owner->enable_state != bp_call_disabled
+ && b->address == address /* address / overlay match */
+ && (!overlay_debugging || b->section == section)
+ && breakpoint_address_is_meaningful (b->owner))
+ {
+ if (b->inserted)
+ internal_error (__FILE__, __LINE__,
+ "another breakpoint was inserted on top of "
+ "a permanent breakpoint");
+
+ b->duplicate = 1;
+ }
+ }
+ }
+}
+
+static void
+breakpoint_adjustment_warning (CORE_ADDR from_addr, CORE_ADDR to_addr,
+ int bnum, int have_bnum)
+{
+ char astr1[40];
+ char astr2[40];
+
+ strcpy (astr1, local_hex_string_custom ((unsigned long) from_addr, "08l"));
+ strcpy (astr2, local_hex_string_custom ((unsigned long) to_addr, "08l"));
+ if (have_bnum)
+ warning ("Breakpoint %d address previously adjusted from %s to %s.",
+ bnum, astr1, astr2);
+ else
+ warning ("Breakpoint address adjusted from %s to %s.", astr1, astr2);
+}
+
+/* Adjust a breakpoint's address to account for architectural constraints
+ on breakpoint placement. Return the adjusted address. Note: Very
+ few targets require this kind of adjustment. For most targets,
+ this function is simply the identity function. */
+
+static CORE_ADDR
+adjust_breakpoint_address (CORE_ADDR bpaddr)
+{
+ if (!gdbarch_adjust_breakpoint_address_p (current_gdbarch))
+ {
+ /* Very few targets need any kind of breakpoint adjustment. */
+ return bpaddr;
+ }
+ else
+ {
+ CORE_ADDR adjusted_bpaddr;
+
+ /* Some targets have architectural constraints on the placement
+ of breakpoint instructions. Obtain the adjusted address. */
+ adjusted_bpaddr = gdbarch_adjust_breakpoint_address (current_gdbarch,
+ bpaddr);
+
+ /* An adjusted breakpoint address can significantly alter
+ a user's expectations. Print a warning if an adjustment
+ is required. */
+ if (adjusted_bpaddr != bpaddr)
+ breakpoint_adjustment_warning (bpaddr, adjusted_bpaddr, 0, 0);
+
+ return adjusted_bpaddr;
+ }
+}
+
+/* Allocate a struct bp_location. */
+
+static struct bp_location *
+allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type)
+{
+ struct bp_location *loc, *loc_p;
+
+ loc = xmalloc (sizeof (struct bp_location));
+ memset (loc, 0, sizeof (*loc));
+
+ loc->owner = bpt;
+
+ switch (bp_type)
+ {
+ case bp_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:
+ case bp_thread_event:
+ case bp_overlay_event:
+ case bp_catch_load:
+ case bp_catch_unload:
+ loc->loc_type = bp_loc_software_breakpoint;
+ break;
+ case bp_hardware_breakpoint:
+ loc->loc_type = bp_loc_hardware_breakpoint;
+ break;
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ loc->loc_type = bp_loc_hardware_watchpoint;
+ break;
+ case bp_watchpoint:
+ case bp_catch_fork:
+ case bp_catch_vfork:
+ case bp_catch_exec:
+ case bp_catch_catch:
+ case bp_catch_throw:
+ loc->loc_type = bp_loc_other;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "unknown breakpoint type");
+ }
+
+ /* Add this breakpoint to the end of the chain. */
+
+ loc_p = bp_location_chain;
+ if (loc_p == 0)
+ bp_location_chain = loc;
+ else
+ {
+ while (loc_p->next)
+ loc_p = loc_p->next;
+ loc_p->next = loc;
+ }
+
+ return loc;
+}
+
+/* set_raw_breakpoint() is a low level routine for allocating and
+ partially initializing a breakpoint of type BPTYPE. The newly
+ created breakpoint's address, section, source file name, and line
+ number are provided by SAL. The newly created and partially
+ initialized breakpoint is added to the breakpoint chain and
+ is also returned as the value of this function.
+
+ It is expected that the caller will complete the initialization of
+ the newly created breakpoint struct as well as output any status
+ information regarding the creation of a new breakpoint. In
+ particular, set_raw_breakpoint() does NOT set the breakpoint
+ number! Care should be taken to not allow an error() to occur
+ prior to completing the initialization of the breakpoint. If this
+ should happen, a bogus breakpoint will be left on the chain. */
+
+struct breakpoint *
+set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
+{
+ struct breakpoint *b, *b1;
+
+ b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+ memset (b, 0, sizeof (*b));
+ b->loc = allocate_bp_location (b, bptype);
+ b->loc->requested_address = sal.pc;
+ b->loc->address = adjust_breakpoint_address (b->loc->requested_address);
+ if (sal.symtab == NULL)
+ b->source_file = NULL;
+ else
+ b->source_file = savestring (sal.symtab->filename,
+ strlen (sal.symtab->filename));
+ b->loc->section = sal.section;
+ b->type = bptype;
+ b->language = current_language->la_language;
+ b->input_radix = input_radix;
+ b->thread = -1;
+ b->line_number = sal.line;
+ b->enable_state = bp_enabled;
+ b->next = 0;
+ b->silent = 0;
+ b->ignore_count = 0;
+ b->commands = NULL;
+ b->frame_id = null_frame_id;
+ b->dll_pathname = NULL;
+ b->triggered_dll_pathname = NULL;
+ b->forked_inferior_pid = 0;
+ b->exec_pathname = NULL;
+ b->ops = NULL;
+ b->pending = 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 (b);
+ breakpoints_changed ();
+
+ return b;
+}
+
+
+/* Note that the breakpoint object B describes a permanent breakpoint
+ instruction, hard-wired into the inferior's code. */
+void
+make_breakpoint_permanent (struct breakpoint *b)
+{
+ b->enable_state = bp_permanent;
+
+ /* By definition, permanent breakpoints are already present in the code. */
+ b->loc->inserted = 1;
+}
+
+static struct breakpoint *
+create_internal_breakpoint (CORE_ADDR address, enum bptype type)
+{
+ static int internal_breakpoint_number = -1;
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+
+ init_sal (&sal); /* initialize to zeroes */
+
+ sal.pc = address;
+ sal.section = find_pc_overlay (sal.pc);
+
+ b = set_raw_breakpoint (sal, type);
+ b->number = internal_breakpoint_number--;
+ b->disposition = disp_donttouch;
+
+ return b;
+}
+
+
+static void
+create_longjmp_breakpoint (char *func_name)
+{
+ struct breakpoint *b;
+ struct minimal_symbol *m;
+
+ if (func_name == NULL)
+ b = create_internal_breakpoint (0, bp_longjmp_resume);
+ else
+ {
+ if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
+ return;
+
+ b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
+ }
+
+ b->enable_state = bp_disabled;
+ b->silent = 1;
+ if (func_name)
+ b->addr_string = xstrdup (func_name);
+}
+
+/* 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 (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp)
+ {
+ b->enable_state = bp_enabled;
+ check_duplicates (b);
+ }
+}
+
+void
+disable_longjmp_breakpoint (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp
+ || b->type == bp_longjmp_resume)
+ {
+ b->enable_state = bp_disabled;
+ check_duplicates (b);
+ }
+}
+
+static void
+create_overlay_event_breakpoint (char *func_name)
+{
+ struct breakpoint *b;
+ struct minimal_symbol *m;
+
+ if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
+ return;
+
+ b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m),
+ bp_overlay_event);
+ b->addr_string = xstrdup (func_name);
+
+ if (overlay_debugging == ovly_auto)
+ {
+ b->enable_state = bp_enabled;
+ overlay_events_enabled = 1;
+ }
+ else
+ {
+ b->enable_state = bp_disabled;
+ overlay_events_enabled = 0;
+ }
+}
+
+void
+enable_overlay_breakpoints (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_overlay_event)
+ {
+ b->enable_state = bp_enabled;
+ check_duplicates (b);
+ overlay_events_enabled = 1;
+ }
+}
+
+void
+disable_overlay_breakpoints (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_overlay_event)
+ {
+ b->enable_state = bp_disabled;
+ check_duplicates (b);
+ overlay_events_enabled = 0;
+ }
+}
+
+struct breakpoint *
+create_thread_event_breakpoint (CORE_ADDR address)
+{
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (address, bp_thread_event);
+
+ b->enable_state = bp_enabled;
+ /* addr_string has to be used or breakpoint_re_set will delete me. */
+ xasprintf (&b->addr_string, "*0x%s", paddr (b->loc->address));
+
+ return b;
+}
+
+void
+remove_thread_event_breakpoints (void)
+{
+ struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ if (b->type == bp_thread_event)
+ delete_breakpoint (b);
+}
+
+struct captured_parse_breakpoint_args
+ {
+ char **arg_p;
+ struct symtabs_and_lines *sals_p;
+ char ***addr_string_p;
+ int *not_found_ptr;
+ };
+
+struct lang_and_radix
+ {
+ enum language lang;
+ int radix;
+ };
+
+/* Cleanup helper routine to restore the current language and
+ input radix. */
+static void
+do_restore_lang_radix_cleanup (void *old)
+{
+ struct lang_and_radix *p = old;
+ set_language (p->lang);
+ input_radix = p->radix;
+}
+
+/* Try and resolve a pending breakpoint. */
+static int
+resolve_pending_breakpoint (struct breakpoint *b)
+{
+ /* Try and reparse the breakpoint in case the shared library
+ is now loaded. */
+ struct symtabs_and_lines sals;
+ struct symtab_and_line pending_sal;
+ char **cond_string = (char **) NULL;
+ char *copy_arg = b->addr_string;
+ char **addr_string;
+ char *errmsg;
+ int rc;
+ int not_found = 0;
+ struct ui_file *old_gdb_stderr;
+ struct lang_and_radix old_lr;
+ struct cleanup *old_chain;
+
+ /* Set language, input-radix, then reissue breakpoint command.
+ Ensure the language and input-radix are restored afterwards. */
+ old_lr.lang = current_language->la_language;
+ old_lr.radix = input_radix;
+ old_chain = make_cleanup (do_restore_lang_radix_cleanup, &old_lr);
+
+ set_language (b->language);
+ input_radix = b->input_radix;
+ rc = break_command_1 (b->addr_string, b->flag, b->from_tty, b);
+
+ if (rc == GDB_RC_OK)
+ /* Pending breakpoint has been resolved. */
+ printf_filtered ("Pending breakpoint \"%s\" resolved\n", b->addr_string);
+
+ do_cleanups (old_chain);
+ return rc;
+}
+
+#ifdef SOLIB_ADD
+void
+remove_solib_event_breakpoints (void)
+{
+ struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ if (b->type == bp_shlib_event)
+ delete_breakpoint (b);
+}
+
+struct breakpoint *
+create_solib_event_breakpoint (CORE_ADDR address)
+{
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (address, bp_shlib_event);
+ return b;
+}
+
+/* Disable any breakpoints that are on code in shared libraries. Only
+ apply to enabled breakpoints, disabled ones can just stay disabled. */
+
+void
+disable_breakpoints_in_shlibs (int silent)
+{
+ struct breakpoint *b;
+ int disabled_shlib_breaks = 0;
+
+ /* See also: insert_breakpoints, under DISABLE_UNSETTABLE_BREAK. */
+ ALL_BREAKPOINTS (b)
+ {
+#if defined (PC_SOLIB)
+ if (((b->type == bp_breakpoint) ||
+ (b->type == bp_hardware_breakpoint)) &&
+ breakpoint_enabled (b) &&
+ !b->loc->duplicate &&
+ PC_SOLIB (b->loc->address))
+ {
+ b->enable_state = bp_shlib_disabled;
+ if (!silent)
+ {
+ if (!disabled_shlib_breaks)
+ {
+ target_terminal_ours_for_output ();
+ warning ("Temporarily disabling shared library breakpoints:");
+ }
+ disabled_shlib_breaks = 1;
+ warning ("breakpoint #%d ", b->number);
+ }
+ }
+#endif
+ }
+}
+
+/* Try to reenable any breakpoints in shared libraries. */
+void
+re_enable_breakpoints_in_shlibs (void)
+{
+ struct breakpoint *b, *tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, tmp)
+ {
+ if (b->enable_state == bp_shlib_disabled)
+ {
+ char buf[1], *lib;
+
+ /* Do not reenable the breakpoint if the shared library
+ is still not mapped in. */
+ lib = PC_SOLIB (b->loc->address);
+ if (lib != NULL && target_read_memory (b->loc->address, buf, 1) == 0)
+ b->enable_state = bp_enabled;
+ }
+ else if (b->pending && (b->enable_state == bp_enabled))
+ {
+ if (resolve_pending_breakpoint (b) == GDB_RC_OK)
+ delete_breakpoint (b);
+ }
+ }
+}
+
+#endif
+
+static void
+solib_load_unload_1 (char *hookname, int tempflag, char *dll_pathname,
+ char *cond_string, enum bptype bp_kind)
+{
+ struct breakpoint *b;
+ struct symtabs_and_lines sals;
+ struct cleanup *old_chain;
+ struct cleanup *canonical_strings_chain = NULL;
+ char *addr_start = hookname;
+ char *addr_end = NULL;
+ char **canonical = (char **) NULL;
+ int thread = -1; /* All threads. */
+
+ /* Set a breakpoint on the specified hook. */
+ sals = decode_line_1 (&hookname, 1, (struct symtab *) NULL, 0, &canonical, NULL);
+ addr_end = hookname;
+
+ if (sals.nelts == 0)
+ {
+ warning ("Unable to set a breakpoint on dynamic linker callback.");
+ warning ("Suggest linking with /opt/langtools/lib/end.o.");
+ warning ("GDB will be unable to track shl_load/shl_unload calls");
+ return;
+ }
+ if (sals.nelts != 1)
+ {
+ warning ("Unable to set unique breakpoint on dynamic linker callback.");
+ warning ("GDB will be unable to track shl_load/shl_unload calls");
+ return;
+ }
+
+ /* Make sure that all storage allocated in decode_line_1 gets freed
+ in case the following errors out. */
+ old_chain = make_cleanup (xfree, sals.sals);
+ if (canonical != (char **) NULL)
+ {
+ make_cleanup (xfree, canonical);
+ canonical_strings_chain = make_cleanup (null_cleanup, 0);
+ if (canonical[0] != NULL)
+ make_cleanup (xfree, canonical[0]);
+ }
+
+ resolve_sal_pc (&sals.sals[0]);
+
+ /* Remove the canonical strings from the cleanup, they are needed below. */
+ if (canonical != (char **) NULL)
+ discard_cleanups (canonical_strings_chain);
+
+ b = set_raw_breakpoint (sals.sals[0], bp_kind);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = NULL;
+ b->cond_string = (cond_string == NULL) ?
+ NULL : savestring (cond_string, strlen (cond_string));
+ b->thread = thread;
+
+ if (canonical != (char **) NULL && canonical[0] != NULL)
+ b->addr_string = canonical[0];
+ else if (addr_start)
+ b->addr_string = savestring (addr_start, addr_end - addr_start);
+
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+
+ if (dll_pathname == NULL)
+ b->dll_pathname = NULL;
+ else
+ {
+ b->dll_pathname = (char *) xmalloc (strlen (dll_pathname) + 1);
+ strcpy (b->dll_pathname, dll_pathname);
+ }
+
+ mention (b);
+ do_cleanups (old_chain);
+}
+
+void
+create_solib_load_event_breakpoint (char *hookname, int tempflag,
+ char *dll_pathname, char *cond_string)
+{
+ solib_load_unload_1 (hookname, tempflag, dll_pathname,
+ cond_string, bp_catch_load);
+}
+
+void
+create_solib_unload_event_breakpoint (char *hookname, int tempflag,
+ char *dll_pathname, char *cond_string)
+{
+ solib_load_unload_1 (hookname,tempflag, dll_pathname,
+ cond_string, bp_catch_unload);
+}
+
+static void
+create_fork_vfork_event_catchpoint (int tempflag, char *cond_string,
+ enum bptype bp_kind)
+{
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+ int thread = -1; /* All threads. */
+
+ init_sal (&sal);
+ sal.pc = 0;
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ b = set_raw_breakpoint (sal, bp_kind);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = NULL;
+ b->cond_string = (cond_string == NULL) ?
+ NULL : savestring (cond_string, strlen (cond_string));
+ b->thread = thread;
+ b->addr_string = NULL;
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+ b->forked_inferior_pid = 0;
+
+ mention (b);
+}
+
+void
+create_fork_event_catchpoint (int tempflag, char *cond_string)
+{
+ create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_fork);
+}
+
+void
+create_vfork_event_catchpoint (int tempflag, char *cond_string)
+{
+ create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_vfork);
+}
+
+void
+create_exec_event_catchpoint (int tempflag, char *cond_string)
+{
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+ int thread = -1; /* All threads. */
+
+ init_sal (&sal);
+ sal.pc = 0;
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ b = set_raw_breakpoint (sal, bp_catch_exec);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = NULL;
+ b->cond_string = (cond_string == NULL) ?
+ NULL : savestring (cond_string, strlen (cond_string));
+ b->thread = thread;
+ b->addr_string = NULL;
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+
+ mention (b);
+}
+
+static int
+hw_breakpoint_used_count (void)
+{
+ struct breakpoint *b;
+ int i = 0;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->type == bp_hardware_breakpoint && b->enable_state == bp_enabled)
+ i++;
+ }
+
+ return i;
+}
+
+static int
+hw_watchpoint_used_count (enum bptype type, int *other_type_used)
+{
+ struct breakpoint *b;
+ int i = 0;
+
+ *other_type_used = 0;
+ ALL_BREAKPOINTS (b)
+ {
+ if (breakpoint_enabled (b))
+ {
+ if (b->type == type)
+ i++;
+ else if ((b->type == bp_hardware_watchpoint ||
+ b->type == bp_read_watchpoint ||
+ b->type == bp_access_watchpoint))
+ *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 (CORE_ADDR pc, struct frame_id frame_id)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp_resume)
+ {
+ b->loc->requested_address = pc;
+ b->loc->address = adjust_breakpoint_address (b->loc->requested_address);
+ b->enable_state = bp_enabled;
+ b->frame_id = frame_id;
+ check_duplicates (b);
+ return;
+ }
+}
+
+void
+disable_watchpoints_before_interactive_call_start (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (((b->type == bp_watchpoint)
+ || (b->type == bp_hardware_watchpoint)
+ || (b->type == bp_read_watchpoint)
+ || (b->type == bp_access_watchpoint)
+ || ep_is_exception_catchpoint (b))
+ && breakpoint_enabled (b))
+ {
+ b->enable_state = bp_call_disabled;
+ check_duplicates (b);
+ }
+ }
+}
+
+void
+enable_watchpoints_after_interactive_call_stop (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (((b->type == bp_watchpoint)
+ || (b->type == bp_hardware_watchpoint)
+ || (b->type == bp_read_watchpoint)
+ || (b->type == bp_access_watchpoint)
+ || ep_is_exception_catchpoint (b))
+ && (b->enable_state == bp_call_disabled))
+ {
+ b->enable_state = bp_enabled;
+ check_duplicates (b);
+ }
+ }
+}
+
+
+/* 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 (struct symtab_and_line sal, struct frame_id frame_id,
+ enum bptype type)
+{
+ struct breakpoint *b;
+ b = set_raw_breakpoint (sal, type);
+ b->enable_state = bp_enabled;
+ b->disposition = disp_donttouch;
+ b->frame_id = frame_id;
+
+ /* 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_ptid))
+ b->thread = pid_to_thread_id (inferior_ptid);
+
+ return b;
+}
+
+
+/* Tell the user we have just set a breakpoint B. */
+
+static void
+mention (struct breakpoint *b)
+{
+ int say_where = 0;
+ struct cleanup *old_chain, *ui_out_chain;
+ struct ui_stream *stb;
+
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+ /* 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);
+ breakpoint_create_event (b->number);
+
+ if (b->ops != NULL && b->ops->print_mention != NULL)
+ b->ops->print_mention (b);
+ else
+ switch (b->type)
+ {
+ case bp_none:
+ printf_filtered ("(apparently deleted?) Eventpoint %d: ", b->number);
+ break;
+ case bp_watchpoint:
+ ui_out_text (uiout, "Watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ print_expression (b->exp, stb->stream);
+ ui_out_field_stream (uiout, "exp", stb);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_hardware_watchpoint:
+ ui_out_text (uiout, "Hardware watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ print_expression (b->exp, stb->stream);
+ ui_out_field_stream (uiout, "exp", stb);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_read_watchpoint:
+ ui_out_text (uiout, "Hardware read watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ print_expression (b->exp, stb->stream);
+ ui_out_field_stream (uiout, "exp", stb);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_access_watchpoint:
+ ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ print_expression (b->exp, stb->stream);
+ ui_out_field_stream (uiout, "exp", stb);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_breakpoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered ("Breakpoint %d", b->number);
+ say_where = 1;
+ break;
+ case bp_hardware_breakpoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered ("Hardware assisted breakpoint %d", b->number);
+ say_where = 1;
+ break;
+ case bp_catch_load:
+ case bp_catch_unload:
+ printf_filtered ("Catchpoint %d (%s %s)",
+ b->number,
+ (b->type == bp_catch_load) ? "load" : "unload",
+ (b->dll_pathname != NULL) ?
+ b->dll_pathname : "<any library>");
+ break;
+ case bp_catch_fork:
+ case bp_catch_vfork:
+ printf_filtered ("Catchpoint %d (%s)",
+ b->number,
+ (b->type == bp_catch_fork) ? "fork" : "vfork");
+ break;
+ case bp_catch_exec:
+ printf_filtered ("Catchpoint %d (exec)",
+ b->number);
+ break;
+ case bp_catch_catch:
+ case bp_catch_throw:
+ printf_filtered ("Catchpoint %d (%s)",
+ b->number,
+ (b->type == bp_catch_catch) ? "catch" : "throw");
+ 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:
+ case bp_thread_event:
+ case bp_overlay_event:
+ break;
+ }
+
+ if (say_where)
+ {
+ if (b->pending)
+ {
+ printf_filtered (" (%s) pending.", b->addr_string);
+ }
+ else
+ {
+ if (addressprint || b->source_file == NULL)
+ {
+ printf_filtered (" at ");
+ print_address_numeric (b->loc->address, 1, gdb_stdout);
+ }
+ if (b->source_file)
+ printf_filtered (": file %s, line %d.",
+ b->source_file, b->line_number);
+ }
+ }
+ do_cleanups (old_chain);
+ if (ui_out_is_mi_like_p (uiout))
+ return;
+ printf_filtered ("\n");
+}
+
+
+/* Add SALS.nelts breakpoints to the breakpoint table. For each
+ SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i],
+ COND[i] and COND_STRING[i] values.
+
+ The parameter PENDING_BP points to a pending breakpoint that is
+ the basis of the breakpoints currently being created. The pending
+ breakpoint may contain a separate condition string or commands
+ that were added after the initial pending breakpoint was created.
+
+ NOTE: If the function succeeds, the caller is expected to cleanup
+ the arrays ADDR_STRING, COND_STRING, COND and SALS (but not the
+ array contents). If the function fails (error() is called), the
+ caller is expected to cleanups both the ADDR_STRING, COND_STRING,
+ COND and SALS arrays and each of those arrays contents. */
+
+static void
+create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
+ struct expression **cond, char **cond_string,
+ enum bptype type, enum bpdisp disposition,
+ int thread, int ignore_count, int from_tty,
+ struct breakpoint *pending_bp)
+{
+ if (type == bp_hardware_breakpoint)
+ {
+ int i = hw_breakpoint_used_count ();
+ int 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.");
+ }
+
+ /* Now set all the breakpoints. */
+ {
+ int i;
+ for (i = 0; i < sals.nelts; i++)
+ {
+ struct breakpoint *b;
+ struct symtab_and_line sal = sals.sals[i];
+
+ if (from_tty)
+ describe_other_breakpoints (sal.pc, sal.section);
+
+ b = set_raw_breakpoint (sal, type);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = cond[i];
+ b->thread = thread;
+ if (addr_string[i])
+ b->addr_string = addr_string[i];
+ else
+ /* addr_string has to be used or breakpoint_re_set will delete
+ me. */
+ xasprintf (&b->addr_string, "*0x%s", paddr (b->loc->address));
+ b->cond_string = cond_string[i];
+ b->ignore_count = ignore_count;
+ b->enable_state = bp_enabled;
+ b->disposition = disposition;
+ /* If resolving a pending breakpoint, a check must be made to see if
+ the user has specified a new condition or commands for the
+ breakpoint. A new condition will override any condition that was
+ initially specified with the initial breakpoint command. */
+ if (pending_bp)
+ {
+ char *arg;
+ if (pending_bp->cond_string)
+ {
+ arg = pending_bp->cond_string;
+ b->cond_string = savestring (arg, strlen (arg));
+ b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+ if (*arg)
+ error ("Junk at end of pending breakpoint condition expression");
+ }
+ /* If there are commands associated with the breakpoint, they should
+ be copied too. */
+ if (pending_bp->commands)
+ b->commands = copy_command_lines (pending_bp->commands);
+
+ /* We have to copy over the ignore_count and thread as well. */
+ b->ignore_count = pending_bp->ignore_count;
+ b->thread = pending_bp->thread;
+ }
+ mention (b);
+ }
+ }
+}
+
+/* Parse ARG which is assumed to be a SAL specification possibly
+ followed by conditionals. On return, SALS contains an array of SAL
+ addresses found. ADDR_STRING contains a vector of (canonical)
+ address strings. ARG points to the end of the SAL. */
+
+static void
+parse_breakpoint_sals (char **address,
+ struct symtabs_and_lines *sals,
+ char ***addr_string,
+ int *not_found_ptr)
+{
+ char *addr_start = *address;
+ *addr_string = NULL;
+ /* If no arg given, or if first arg is 'if ', use the default
+ breakpoint. */
+ if ((*address) == NULL
+ || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
+ {
+ if (default_breakpoint_valid)
+ {
+ struct symtab_and_line sal;
+ init_sal (&sal); /* initialize to zeroes */
+ 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;
+ sal.section = find_pc_overlay (sal.pc);
+ sals->sals[0] = sal;
+ sals->nelts = 1;
+ }
+ else
+ error ("No default breakpoint address now.");
+ }
+ else
+ {
+ /* 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.
+ ObjC: However, don't match an Objective-C method name which
+ may have a '+' or '-' succeeded by a '[' */
+
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+ if (default_breakpoint_valid
+ && (!cursal.symtab
+ || ((strchr ("+-", (*address)[0]) != NULL)
+ && ((*address)[1] != '['))))
+ *sals = decode_line_1 (address, 1, default_breakpoint_symtab,
+ default_breakpoint_line, addr_string,
+ not_found_ptr);
+ else
+ *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
+ addr_string, not_found_ptr);
+ }
+ /* For any SAL that didn't have a canonical string, fill one in. */
+ if (sals->nelts > 0 && *addr_string == NULL)
+ *addr_string = xcalloc (sals->nelts, sizeof (char **));
+ if (addr_start != (*address))
+ {
+ int i;
+ for (i = 0; i < sals->nelts; i++)
+ {
+ /* Add the string if not present. */
+ if ((*addr_string)[i] == NULL)
+ (*addr_string)[i] = savestring (addr_start, (*address) - addr_start);
+ }
+ }
+}
+
+
+/* Convert each SAL into a real PC. Verify that the PC can be
+ inserted as a breakpoint. If it can't throw an error. */
+
+static void
+breakpoint_sals_to_pc (struct symtabs_and_lines *sals,
+ char *address)
+{
+ int i;
+ for (i = 0; i < sals->nelts; i++)
+ {
+ resolve_sal_pc (&sals->sals[i]);
+
+ /* It's possible for the PC to be nonzero, but still an illegal
+ value on some targets.
+
+ For example, on HP-UX if you start gdb, and before running the
+ inferior you try to set a breakpoint on a shared library function
+ "foo" where the inferior doesn't call "foo" directly but does
+ pass its address to another function call, then we do find a
+ minimal symbol for the "foo", but it's address is invalid.
+ (Appears to be an index into a table that the loader sets up
+ when the inferior is run.)
+
+ Give the target a chance to bless sals.sals[i].pc before we
+ try to make a breakpoint for it. */
+ if (PC_REQUIRES_RUN_BEFORE_USE (sals->sals[i].pc))
+ {
+ if (address == NULL)
+ error ("Cannot break without a running program.");
+ else
+ error ("Cannot break on %s without a running program.",
+ address);
+ }
+ }
+}
+
+static int
+do_captured_parse_breakpoint (struct ui_out *ui, void *data)
+{
+ struct captured_parse_breakpoint_args *args = data;
+
+ parse_breakpoint_sals (args->arg_p, args->sals_p, args->addr_string_p,
+ args->not_found_ptr);
+
+ return GDB_RC_OK;
+}
+
+/* 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.
+
+ PENDING_BP is non-NULL when this function is being called to resolve
+ a pending breakpoint. */
+
+static int
+break_command_1 (char *arg, int flag, int from_tty, struct breakpoint *pending_bp)
+{
+ int tempflag, hardwareflag;
+ struct symtabs_and_lines sals;
+ struct expression **cond = 0;
+ struct symtab_and_line pending_sal;
+ char **cond_string = (char **) NULL;
+ char *copy_arg;
+ char *err_msg;
+ char *addr_start = arg;
+ char **addr_string;
+ struct cleanup *old_chain;
+ struct cleanup *breakpoint_chain = NULL;
+ struct captured_parse_breakpoint_args parse_args;
+ int i, rc;
+ int pending = 0;
+ int thread = -1;
+ int ignore_count = 0;
+ int not_found = 0;
+
+ hardwareflag = flag & BP_HARDWAREFLAG;
+ tempflag = flag & BP_TEMPFLAG;
+
+ sals.sals = NULL;
+ sals.nelts = 0;
+ addr_string = NULL;
+
+ parse_args.arg_p = &arg;
+ parse_args.sals_p = &sals;
+ parse_args.addr_string_p = &addr_string;
+ parse_args.not_found_ptr = &not_found;
+
+ rc = catch_exceptions_with_msg (uiout, do_captured_parse_breakpoint,
+ &parse_args, NULL, &err_msg,
+ RETURN_MASK_ALL);
+
+ /* If caller is interested in rc value from parse, set value. */
+
+ if (rc != GDB_RC_OK)
+ {
+ /* Check for file or function not found. */
+ if (not_found)
+ {
+ /* If called to resolve pending breakpoint, just return error code. */
+ if (pending_bp)
+ return rc;
+
+ error_output_message (NULL, err_msg);
+ xfree (err_msg);
+
+ /* If pending breakpoint support is turned off, throw error. */
+
+ if (pending_break_support == AUTO_BOOLEAN_FALSE)
+ throw_exception (RETURN_ERROR);
+
+ /* If pending breakpoint support is auto query and the user selects
+ no, then simply return the error code. */
+ if (pending_break_support == AUTO_BOOLEAN_AUTO &&
+ !nquery ("Make breakpoint pending on future shared library load? "))
+ return rc;
+
+ /* At this point, either the user was queried about setting a
+ pending breakpoint and selected yes, or pending breakpoint
+ behavior is on and thus a pending breakpoint is defaulted
+ on behalf of the user. */
+ copy_arg = xstrdup (addr_start);
+ addr_string = &copy_arg;
+ sals.nelts = 1;
+ sals.sals = &pending_sal;
+ pending_sal.pc = 0;
+ pending = 1;
+ }
+ else
+ return rc;
+ }
+ else if (!sals.nelts)
+ return GDB_RC_FAIL;
+
+ /* Create a chain of things that always need to be cleaned up. */
+ old_chain = make_cleanup (null_cleanup, 0);
+
+ if (!pending)
+ {
+ /* Make sure that all storage allocated to SALS gets freed. */
+ make_cleanup (xfree, sals.sals);
+
+ /* Cleanup the addr_string array but not its contents. */
+ make_cleanup (xfree, addr_string);
+ }
+
+ /* Allocate space for all the cond expressions. */
+ cond = xcalloc (sals.nelts, sizeof (struct expression *));
+ make_cleanup (xfree, cond);
+
+ /* Allocate space for all the cond strings. */
+ cond_string = xcalloc (sals.nelts, sizeof (char **));
+ make_cleanup (xfree, cond_string);
+
+ /* ----------------------------- SNIP -----------------------------
+ Anything added to the cleanup chain beyond this point is assumed
+ to be part of a breakpoint. If the breakpoint create succeeds
+ then the memory is not reclaimed. */
+ breakpoint_chain = make_cleanup (null_cleanup, 0);
+
+ /* Mark the contents of the addr_string for cleanup. These go on
+ the breakpoint_chain and only occure if the breakpoint create
+ fails. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ if (addr_string[i] != NULL)
+ make_cleanup (xfree, addr_string[i]);
+ }
+
+ /* Resolve all line numbers to PC's and verify that the addresses
+ are ok for the target. */
+ if (!pending)
+ breakpoint_sals_to_pc (&sals, addr_start);
+
+ /* Verify that condition can be parsed, before setting any
+ breakpoints. Allocate a separate condition expression for each
+ breakpoint. */
+ thread = -1; /* No specific thread yet */
+ if (!pending)
+ {
+ for (i = 0; i < sals.nelts; i++)
+ {
+ char *tok = arg;
+ while (tok && *tok)
+ {
+ char *end_tok;
+ int toklen;
+ char *cond_start = NULL;
+ char *cond_end = NULL;
+ 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[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc),
+ 0);
+ make_cleanup (xfree, cond[i]);
+ cond_end = tok;
+ cond_string[i] = savestring (cond_start,
+ cond_end - cond_start);
+ make_cleanup (xfree, cond_string[i]);
+ }
+ 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.");
+ }
+ }
+ create_breakpoints (sals, addr_string, cond, cond_string,
+ hardwareflag ? bp_hardware_breakpoint
+ : bp_breakpoint,
+ tempflag ? disp_del : disp_donttouch,
+ thread, ignore_count, from_tty,
+ pending_bp);
+ }
+ else
+ {
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+
+ sal.symtab = NULL;
+ sal.pc = 0;
+
+ make_cleanup (xfree, copy_arg);
+
+ b = set_raw_breakpoint (sal, hardwareflag ? bp_hardware_breakpoint
+ : bp_breakpoint);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = *cond;
+ b->thread = thread;
+ b->addr_string = *addr_string;
+ b->cond_string = *cond_string;
+ b->ignore_count = ignore_count;
+ b->pending = 1;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+ b->from_tty = from_tty;
+ b->flag = flag;
+ mention (b);
+ }
+
+ if (sals.nelts > 1)
+ {
+ warning ("Multiple breakpoints were set.");
+ warning ("Use the \"delete\" command to delete unwanted breakpoints.");
+ }
+ /* That's it. Discard the cleanups for data inserted into the
+ breakpoint. */
+ discard_cleanups (breakpoint_chain);
+ /* But cleanup everything else. */
+ do_cleanups (old_chain);
+
+ return GDB_RC_OK;
+}
+
+/* Set a breakpoint of TYPE/DISPOSITION according to ARG (function,
+ linenum or *address) with COND and IGNORE_COUNT. */
+
+struct captured_breakpoint_args
+ {
+ char *address;
+ char *condition;
+ int hardwareflag;
+ int tempflag;
+ int thread;
+ int ignore_count;
+ };
+
+static int
+do_captured_breakpoint (void *data)
+{
+ struct captured_breakpoint_args *args = data;
+ struct symtabs_and_lines sals;
+ struct expression **cond;
+ struct cleanup *old_chain;
+ struct cleanup *breakpoint_chain = NULL;
+ int i;
+ char **addr_string;
+ char **cond_string;
+
+ char *address_end;
+
+ /* Parse the source and lines spec. Delay check that the expression
+ didn't contain trailing garbage until after cleanups are in
+ place. */
+ sals.sals = NULL;
+ sals.nelts = 0;
+ address_end = args->address;
+ addr_string = NULL;
+ parse_breakpoint_sals (&address_end, &sals, &addr_string, 0);
+
+ if (!sals.nelts)
+ return GDB_RC_NONE;
+
+ /* Create a chain of things at always need to be cleaned up. */
+ old_chain = make_cleanup (null_cleanup, 0);
+
+ /* Always have a addr_string array, even if it is empty. */
+ make_cleanup (xfree, addr_string);
+
+ /* Make sure that all storage allocated to SALS gets freed. */
+ make_cleanup (xfree, sals.sals);
+
+ /* Allocate space for all the cond expressions. */
+ cond = xcalloc (sals.nelts, sizeof (struct expression *));
+ make_cleanup (xfree, cond);
+
+ /* Allocate space for all the cond strings. */
+ cond_string = xcalloc (sals.nelts, sizeof (char **));
+ make_cleanup (xfree, cond_string);
+
+ /* ----------------------------- SNIP -----------------------------
+ Anything added to the cleanup chain beyond this point is assumed
+ to be part of a breakpoint. If the breakpoint create goes
+ through then that memory is not cleaned up. */
+ breakpoint_chain = make_cleanup (null_cleanup, 0);
+
+ /* Mark the contents of the addr_string for cleanup. These go on
+ the breakpoint_chain and only occure if the breakpoint create
+ fails. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ if (addr_string[i] != NULL)
+ make_cleanup (xfree, addr_string[i]);
+ }
+
+ /* Wait until now before checking for garbage at the end of the
+ address. That way cleanups can take care of freeing any
+ memory. */
+ if (*address_end != '\0')
+ error ("Garbage %s following breakpoint address", address_end);
+
+ /* Resolve all line numbers to PC's. */
+ breakpoint_sals_to_pc (&sals, args->address);
+
+ /* Verify that conditions can be parsed, before setting any
+ breakpoints. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ if (args->condition != NULL)
+ {
+ char *tok = args->condition;
+ cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
+ if (*tok != '\0')
+ error ("Garbage %s follows condition", tok);
+ make_cleanup (xfree, cond[i]);
+ cond_string[i] = xstrdup (args->condition);
+ }
+ }
+
+ create_breakpoints (sals, addr_string, cond, cond_string,
+ args->hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
+ args->tempflag ? disp_del : disp_donttouch,
+ args->thread, args->ignore_count, 0/*from-tty*/,
+ NULL/*pending_bp*/);
+
+ /* That's it. Discard the cleanups for data inserted into the
+ breakpoint. */
+ discard_cleanups (breakpoint_chain);
+ /* But cleanup everything else. */
+ do_cleanups (old_chain);
+ return GDB_RC_OK;
+}
+
+enum gdb_rc
+gdb_breakpoint (char *address, char *condition,
+ int hardwareflag, int tempflag,
+ int thread, int ignore_count)
+{
+ struct captured_breakpoint_args args;
+ args.address = address;
+ args.condition = condition;
+ args.hardwareflag = hardwareflag;
+ args.tempflag = tempflag;
+ args.thread = thread;
+ args.ignore_count = ignore_count;
+ return catch_errors (do_captured_breakpoint, &args,
+ NULL, RETURN_MASK_ALL);
+}
+
+
+static void
+break_at_finish_at_depth_command_1 (char *arg, int flag, int from_tty)
+{
+ struct frame_info *frame;
+ CORE_ADDR low, high, selected_pc = 0;
+ char *extra_args = NULL;
+ char *level_arg;
+ int extra_args_len = 0, if_arg = 0;
+
+ if (!arg ||
+ (arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
+ {
+
+ if (default_breakpoint_valid)
+ {
+ if (deprecated_selected_frame)
+ {
+ selected_pc = get_frame_pc (deprecated_selected_frame);
+ if (arg)
+ if_arg = 1;
+ }
+ else
+ error ("No selected frame.");
+ }
+ else
+ error ("No default breakpoint address now.");
+ }
+ else
+ {
+ extra_args = strchr (arg, ' ');
+ if (extra_args)
+ {
+ extra_args++;
+ extra_args_len = strlen (extra_args);
+ level_arg = (char *) xmalloc (extra_args - arg);
+ strncpy (level_arg, arg, extra_args - arg - 1);
+ level_arg[extra_args - arg - 1] = '\0';
+ }
+ else
+ {
+ level_arg = (char *) xmalloc (strlen (arg) + 1);
+ strcpy (level_arg, arg);
+ }
+
+ frame = parse_frame_specification (level_arg);
+ if (frame)
+ selected_pc = get_frame_pc (frame);
+ else
+ selected_pc = 0;
+ }
+ if (if_arg)
+ {
+ extra_args = arg;
+ extra_args_len = strlen (arg);
+ }
+
+ if (selected_pc)
+ {
+ if (find_pc_partial_function (selected_pc, (char **) NULL, &low, &high))
+ {
+ char *addr_string;
+ if (extra_args_len)
+ addr_string = xstrprintf ("*0x%s %s", paddr_nz (high), extra_args);
+ else
+ addr_string = xstrprintf ("*0x%s", paddr_nz (high));
+ break_command_1 (addr_string, flag, from_tty, NULL);
+ xfree (addr_string);
+ }
+ else
+ error ("No function contains the specified address");
+ }
+ else
+ error ("Unable to set breakpoint at procedure exit");
+}
+
+
+static void
+break_at_finish_command_1 (char *arg, int flag, int from_tty)
+{
+ char *addr_string, *break_string, *beg_addr_string;
+ CORE_ADDR low, high;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct cleanup *old_chain;
+ char *extra_args = NULL;
+ int extra_args_len = 0;
+ int i, if_arg = 0;
+
+ if (!arg ||
+ (arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
+ {
+ if (default_breakpoint_valid)
+ {
+ if (deprecated_selected_frame)
+ {
+ addr_string = xstrprintf ("*0x%s",
+ paddr_nz (get_frame_pc (deprecated_selected_frame)));
+ if (arg)
+ if_arg = 1;
+ }
+ else
+ error ("No selected frame.");
+ }
+ else
+ error ("No default breakpoint address now.");
+ }
+ else
+ {
+ addr_string = (char *) xmalloc (strlen (arg) + 1);
+ strcpy (addr_string, arg);
+ }
+
+ if (if_arg)
+ {
+ extra_args = arg;
+ extra_args_len = strlen (arg);
+ }
+ else if (arg)
+ {
+ /* get the stuff after the function name or address */
+ extra_args = strchr (arg, ' ');
+ if (extra_args)
+ {
+ extra_args++;
+ extra_args_len = strlen (extra_args);
+ }
+ }
+
+ sals.sals = NULL;
+ sals.nelts = 0;
+
+ beg_addr_string = addr_string;
+ sals = decode_line_1 (&addr_string, 1, (struct symtab *) NULL, 0,
+ (char ***) NULL, NULL);
+
+ xfree (beg_addr_string);
+ old_chain = make_cleanup (xfree, sals.sals);
+ for (i = 0; (i < sals.nelts); i++)
+ {
+ sal = sals.sals[i];
+ if (find_pc_partial_function (sal.pc, (char **) NULL, &low, &high))
+ {
+ break_string;
+ if (extra_args_len)
+ break_string = xstrprintf ("*0x%s %s", paddr_nz (high),
+ extra_args);
+ else
+ break_string = xstrprintf ("*0x%s", paddr_nz (high));
+ break_command_1 (break_string, flag, from_tty, NULL);
+ xfree (break_string);
+ }
+ else
+ error ("No function contains the specified address");
+ }
+ if (sals.nelts > 1)
+ {
+ warning ("Multiple breakpoints were set.\n");
+ warning ("Use the \"delete\" command to delete unwanted breakpoints.");
+ }
+ do_cleanups (old_chain);
+}
+
+
+/* Helper function for break_command_1 and disassemble_command. */
+
+void
+resolve_sal_pc (struct symtab_and_line *sal)
+{
+ CORE_ADDR pc;
+
+ if (sal->pc == 0 && sal->symtab != NULL)
+ {
+ if (!find_line_pc (sal->symtab, sal->line, &pc))
+ error ("No line %d in file \"%s\".",
+ sal->line, sal->symtab->filename);
+ sal->pc = pc;
+ }
+
+ if (sal->section == 0 && sal->symtab != NULL)
+ {
+ struct blockvector *bv;
+ struct block *b;
+ struct symbol *sym;
+ int index;
+
+ bv = blockvector_for_pc_sect (sal->pc, 0, &index, sal->symtab);
+ if (bv != NULL)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, index);
+ sym = block_function (b);
+ if (sym != NULL)
+ {
+ fixup_symbol_section (sym, sal->symtab->objfile);
+ sal->section = SYMBOL_BFD_SECTION (sym);
+ }
+ else
+ {
+ /* It really is worthwhile to have the section, so we'll just
+ have to look harder. This case can be executed if we have
+ line numbers but no functions (as can happen in assembly
+ source). */
+
+ struct minimal_symbol *msym;
+
+ msym = lookup_minimal_symbol_by_pc (sal->pc);
+ if (msym)
+ sal->section = SYMBOL_BFD_SECTION (msym);
+ }
+ }
+ }
+}
+
+void
+break_command (char *arg, int from_tty)
+{
+ break_command_1 (arg, 0, from_tty, NULL);
+}
+
+void
+break_at_finish_command (char *arg, int from_tty)
+{
+ break_at_finish_command_1 (arg, 0, from_tty);
+}
+
+void
+break_at_finish_at_depth_command (char *arg, int from_tty)
+{
+ break_at_finish_at_depth_command_1 (arg, 0, from_tty);
+}
+
+void
+tbreak_command (char *arg, int from_tty)
+{
+ break_command_1 (arg, BP_TEMPFLAG, from_tty, NULL);
+}
+
+void
+tbreak_at_finish_command (char *arg, int from_tty)
+{
+ break_at_finish_command_1 (arg, BP_TEMPFLAG, from_tty);
+}
+
+static void
+hbreak_command (char *arg, int from_tty)
+{
+ break_command_1 (arg, BP_HARDWAREFLAG, from_tty, NULL);
+}
+
+static void
+thbreak_command (char *arg, int from_tty)
+{
+ break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty, NULL);
+}
+
+static void
+stop_command (char *arg, int from_tty)
+{
+ printf_filtered ("Specify the type of breakpoint to set.\n\
+Usage: stop in <function | address>\n\
+ stop at <line>\n");
+}
+
+static void
+stopin_command (char *arg, int from_tty)
+{
+ int badInput = 0;
+
+ if (arg == (char *) NULL)
+ badInput = 1;
+ else if (*arg != '*')
+ {
+ char *argptr = arg;
+ int hasColon = 0;
+
+ /* look for a ':'. If this is a line number specification, then
+ say it is bad, otherwise, it should be an address or
+ function/method name */
+ while (*argptr && !hasColon)
+ {
+ hasColon = (*argptr == ':');
+ argptr++;
+ }
+
+ if (hasColon)
+ badInput = (*argptr != ':'); /* Not a class::method */
+ else
+ badInput = isdigit (*arg); /* a simple line number */
+ }
+
+ if (badInput)
+ printf_filtered ("Usage: stop in <function | address>\n");
+ else
+ break_command_1 (arg, 0, from_tty, NULL);
+}
+
+static void
+stopat_command (char *arg, int from_tty)
+{
+ int badInput = 0;
+
+ if (arg == (char *) NULL || *arg == '*') /* no line number */
+ badInput = 1;
+ else
+ {
+ char *argptr = arg;
+ int hasColon = 0;
+
+ /* look for a ':'. If there is a '::' then get out, otherwise
+ it is probably a line number. */
+ while (*argptr && !hasColon)
+ {
+ hasColon = (*argptr == ':');
+ argptr++;
+ }
+
+ if (hasColon)
+ badInput = (*argptr == ':'); /* we have class::method */
+ else
+ badInput = !isdigit (*arg); /* not a line number */
+ }
+
+ if (badInput)
+ printf_filtered ("Usage: stop at <line>\n");
+ else
+ break_command_1 (arg, 0, from_tty, NULL);
+}
+
+/* accessflag: hw_write: watch write,
+ hw_read: watch read,
+ hw_access: watch access (read or write) */
+static void
+watch_command_1 (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;
+ struct frame_info *prev_frame = NULL;
+ 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 = 0;
+ enum bptype bp_type;
+ int mem_cnt = 0;
+
+ init_sal (&sal); /* initialize to zeroes */
+
+ /* 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 == hw_read)
+ bp_type = bp_read_watchpoint;
+ else if (accessflag == hw_access)
+ 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 support this type of hardware watchpoint.");
+
+ if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
+ error ("Target can only support one kind of HW watchpoint at a time.");
+ }
+
+#if defined(HPUXHPPA)
+ /* On HP-UX if you set a h/w
+ watchpoint before the "run" command, the inferior dies with a e.g.,
+ SIGILL once you start it. I initially believed this was due to a
+ bad interaction between page protection traps and the initial
+ startup sequence by the dynamic linker.
+
+ However, I tried avoiding that by having HP-UX's implementation of
+ TARGET_CAN_USE_HW_WATCHPOINT return FALSE if there was no inferior_ptid
+ yet, which forced slow watches before a "run" or "attach", and it
+ still fails somewhere in the startup code.
+
+ Until I figure out what's happening, I'm disallowing watches altogether
+ before the "run" or "attach" command. We'll tell the user they must
+ set watches after getting the program started. */
+ if (!target_has_execution)
+ {
+ warning ("can't do that without a running program; try \"break main\", \"run\" first");
+ return;
+ }
+#endif /* HPUXHPPA */
+
+ /* Change the type of breakpoint to an ordinary watchpoint if a hardware
+ watchpoint could not be set. */
+ if (!mem_cnt || target_resources_ok <= 0)
+ bp_type = bp_watchpoint;
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (sal, bp_type);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->disposition = disp_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 = get_frame_id (frame);
+ }
+ else
+ {
+ memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
+ }
+
+ /* 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)
+ {
+ if (prev_frame)
+ {
+ struct breakpoint *scope_breakpoint;
+ scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
+ bp_watchpoint_scope);
+
+ scope_breakpoint->enable_state = bp_enabled;
+
+ /* Automatically delete the breakpoint when it hits. */
+ scope_breakpoint->disposition = disp_del;
+
+ /* Only break in the proper frame (help with recursion). */
+ scope_breakpoint->frame_id = get_frame_id (prev_frame);
+
+ /* Set the address at which we will stop. */
+ scope_breakpoint->loc->requested_address
+ = get_frame_pc (prev_frame);
+ scope_breakpoint->loc->address
+ = adjust_breakpoint_address (scope_breakpoint->loc->requested_address);
+
+ /* 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. */
+
+#if !defined(TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT)
+#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(BYTE_SIZE) \
+ ((BYTE_SIZE) <= (DEPRECATED_REGISTER_SIZE))
+#endif
+
+#if !defined(TARGET_REGION_OK_FOR_HW_WATCHPOINT)
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(ADDR,LEN) \
+ (TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(LEN))
+#endif
+
+static int
+can_use_hardware_watchpoint (struct value *v)
+{
+ int found_memory_cnt = 0;
+ struct value *head = v;
+
+ /* Did the user specifically forbid us to use hardware watchpoints? */
+ if (!can_use_hw_watchpoints)
+ return 0;
+
+ /* Make sure that the value of the expression depends only upon
+ memory contents, and values computed from them within GDB. If we
+ find any register references or function calls, we can't use a
+ hardware watchpoint.
+
+ The idea here is that evaluating an expression generates a series
+ of values, one holding the value of every subexpression. (The
+ expression a*b+c has five subexpressions: a, b, a*b, c, and
+ a*b+c.) GDB's values hold almost enough information to establish
+ the criteria given above --- they identify memory lvalues,
+ register lvalues, computed values, etcetera. So we can evaluate
+ the expression, and then scan the chain of values that leaves
+ behind to decide whether we can detect any possible change to the
+ expression's final value using only hardware watchpoints.
+
+ However, I don't think that the values returned by inferior
+ function calls are special in any way. So this function may not
+ notice that an expression involving an inferior function call
+ can't be watched with hardware watchpoints. FIXME. */
+ for (; v; v = v->next)
+ {
+ if (VALUE_LVAL (v) == lval_memory)
+ {
+ if (VALUE_LAZY (v))
+ /* A lazy memory lvalue is one that GDB never needed to fetch;
+ we either just used its address (e.g., `a' in `a.b') or
+ we never needed it at all (e.g., `a' in `a,b'). */
+ ;
+ else
+ {
+ /* Ahh, memory we actually used! Check if we can cover
+ it with hardware watchpoints. */
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ /* We only watch structs and arrays if user asked for it
+ explicitly, never if they just happen to appear in a
+ middle of some value chain. */
+ if (v == head
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ int len = TYPE_LENGTH (VALUE_TYPE (v));
+
+ if (!TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len))
+ return 0;
+ else
+ found_memory_cnt++;
+ }
+ }
+ }
+ else if (v->lval != not_lval && v->modifiable == 0)
+ return 0; /* ??? What does this represent? */
+ else if (v->lval == lval_register)
+ return 0; /* cannot watch a register with a HW watchpoint */
+ }
+
+ /* The expression itself looks suitable for using a hardware
+ watchpoint, but give the target machine a chance to reject it. */
+ return found_memory_cnt;
+}
+
+void
+watch_command_wrapper (char *arg, int from_tty)
+{
+ watch_command (arg, from_tty);
+}
+
+static void
+watch_command (char *arg, int from_tty)
+{
+ watch_command_1 (arg, hw_write, from_tty);
+}
+
+void
+rwatch_command_wrapper (char *arg, int from_tty)
+{
+ rwatch_command (arg, from_tty);
+}
+
+static void
+rwatch_command (char *arg, int from_tty)
+{
+ watch_command_1 (arg, hw_read, from_tty);
+}
+
+void
+awatch_command_wrapper (char *arg, int from_tty)
+{
+ awatch_command (arg, from_tty);
+}
+
+static void
+awatch_command (char *arg, int from_tty)
+{
+ watch_command_1 (arg, hw_access, from_tty);
+}
+
+
+/* Helper routines for the until_command routine in infcmd.c. Here
+ because it uses the mechanisms of breakpoints. */
+
+/* This function is called by fetch_inferior_event via the
+ cmd_continuation pointer, to complete the until command. It takes
+ care of cleaning up the temporary breakpoints set up by the until
+ command. */
+static void
+until_break_command_continuation (struct continuation_arg *arg)
+{
+ struct cleanup *cleanups;
+
+ cleanups = (struct cleanup *) arg->data.pointer;
+ do_exec_cleanups (cleanups);
+}
+
+void
+until_break_command (char *arg, int from_tty, int anywhere)
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct frame_info *prev_frame = get_prev_frame (deprecated_selected_frame);
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+ struct continuation_arg *arg1;
+
+
+ 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, NULL);
+ else
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL,
+ 0, (char ***) NULL, NULL);
+
+ if (sals.nelts != 1)
+ error ("Couldn't get information on specified line.");
+
+ sal = sals.sals[0];
+ xfree (sals.sals); /* malloc'd, so freed */
+
+ if (*arg)
+ error ("Junk at end of arguments.");
+
+ resolve_sal_pc (&sal);
+
+ if (anywhere)
+ /* If the user told us to continue until a specified location,
+ we don't specify a frame at which we need to stop. */
+ breakpoint = set_momentary_breakpoint (sal, null_frame_id, bp_until);
+ else
+ /* Otherwise, specify the current frame, because we want to stop only
+ at the very same frame. */
+ breakpoint = set_momentary_breakpoint (sal,
+ get_frame_id (deprecated_selected_frame),
+ bp_until);
+
+ if (!event_loop_p || !target_can_async_p ())
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ else
+ old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
+
+ /* If we are running asynchronously, and the target supports async
+ execution, we are not waiting for the target to stop, in the call
+ tp proceed, below. This means that we cannot delete the
+ brekpoints until the target has actually stopped. The only place
+ where we get a chance to do that is in fetch_inferior_event, so
+ we must set things up for that. */
+
+ if (event_loop_p && target_can_async_p ())
+ {
+ /* In this case the arg for the continuation is just the point
+ in the exec_cleanups chain from where to start doing
+ cleanups, because all the continuation does is the cleanups in
+ the exec_cleanup_chain. */
+ arg1 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg1->next = NULL;
+ arg1->data.pointer = old_chain;
+
+ add_continuation (until_break_command_continuation, arg1);
+ }
+
+ /* Keep within the current frame, or in frames called by the current
+ one. */
+ if (prev_frame)
+ {
+ sal = find_pc_line (get_frame_pc (prev_frame), 0);
+ sal.pc = get_frame_pc (prev_frame);
+ breakpoint = set_momentary_breakpoint (sal, get_frame_id (prev_frame),
+ bp_until);
+ if (!event_loop_p || !target_can_async_p ())
+ make_cleanup_delete_breakpoint (breakpoint);
+ else
+ make_exec_cleanup_delete_breakpoint (breakpoint);
+ }
+
+ proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
+ /* Do the cleanups now, anly if we are not running asynchronously,
+ of if we are, but the target is still synchronous. */
+ if (!event_loop_p || !target_can_async_p ())
+ do_cleanups (old_chain);
+}
+
+static void
+ep_skip_leading_whitespace (char **s)
+{
+ if ((s == NULL) || (*s == NULL))
+ return;
+ while (isspace (**s))
+ *s += 1;
+}
+
+/* This function examines a string, and attempts to find a token
+ that might be an event name in the leading characters. If a
+ possible match is found, a pointer to the last character of
+ the token is returned. Else, NULL is returned. */
+
+static char *
+ep_find_event_name_end (char *arg)
+{
+ char *s = arg;
+ char *event_name_end = NULL;
+
+ /* If we could depend upon the presense of strrpbrk, we'd use that... */
+ if (arg == NULL)
+ return NULL;
+
+ /* We break out of the loop when we find a token delimiter.
+ Basically, we're looking for alphanumerics and underscores;
+ anything else delimites the token. */
+ while (*s != '\0')
+ {
+ if (!isalnum (*s) && (*s != '_'))
+ break;
+ event_name_end = s;
+ s++;
+ }
+
+ return event_name_end;
+}
+
+
+/* This function attempts to parse an optional "if <cond>" clause
+ from the arg string. If one is not found, it returns NULL.
+
+ Else, it returns a pointer to the condition string. (It does not
+ attempt to evaluate the string against a particular block.) And,
+ it updates arg to point to the first character following the parsed
+ if clause in the arg string. */
+
+static char *
+ep_parse_optional_if_clause (char **arg)
+{
+ char *cond_string;
+
+ if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !isspace ((*arg)[2]))
+ return NULL;
+
+ /* Skip the "if" keyword. */
+ (*arg) += 2;
+
+ /* Skip any extra leading whitespace, and record the start of the
+ condition string. */
+ ep_skip_leading_whitespace (arg);
+ cond_string = *arg;
+
+ /* Assume that the condition occupies the remainder of the arg string. */
+ (*arg) += strlen (cond_string);
+
+ return cond_string;
+}
+
+/* This function attempts to parse an optional filename from the arg
+ string. If one is not found, it returns NULL.
+
+ Else, it returns a pointer to the parsed filename. (This function
+ makes no attempt to verify that a file of that name exists, or is
+ accessible.) And, it updates arg to point to the first character
+ following the parsed filename in the arg string.
+
+ Note that clients needing to preserve the returned filename for
+ future access should copy it to their own buffers. */
+static char *
+ep_parse_optional_filename (char **arg)
+{
+ static char filename[1024];
+ char *arg_p = *arg;
+ int i;
+ char c;
+
+ if ((*arg_p == '\0') || isspace (*arg_p))
+ return NULL;
+
+ for (i = 0;; i++)
+ {
+ c = *arg_p;
+ if (isspace (c))
+ c = '\0';
+ filename[i] = c;
+ if (c == '\0')
+ break;
+ arg_p++;
+ }
+ *arg = arg_p;
+
+ return filename;
+}
+
+/* Commands to deal with catching events, such as signals, exceptions,
+ process start/exit, etc. */
+
+typedef enum
+{
+ catch_fork, catch_vfork
+}
+catch_fork_kind;
+
+static void
+catch_fork_command_1 (catch_fork_kind fork_kind, char *arg, int tempflag,
+ int from_tty)
+{
+ char *cond_string = NULL;
+
+ ep_skip_leading_whitespace (&arg);
+
+ /* The allowed syntax is:
+ catch [v]fork
+ catch [v]fork if <cond>
+
+ First, check if there's an if clause. */
+ cond_string = ep_parse_optional_if_clause (&arg);
+
+ if ((*arg != '\0') && !isspace (*arg))
+ error ("Junk at end of arguments.");
+
+ /* If this target supports it, create a fork or vfork catchpoint
+ and enable reporting of such events. */
+ switch (fork_kind)
+ {
+ case catch_fork:
+ create_fork_event_catchpoint (tempflag, cond_string);
+ break;
+ case catch_vfork:
+ create_vfork_event_catchpoint (tempflag, cond_string);
+ break;
+ default:
+ error ("unsupported or unknown fork kind; cannot catch it");
+ break;
+ }
+}
+
+static void
+catch_exec_command_1 (char *arg, int tempflag, int from_tty)
+{
+ char *cond_string = NULL;
+
+ ep_skip_leading_whitespace (&arg);
+
+ /* The allowed syntax is:
+ catch exec
+ catch exec if <cond>
+
+ First, check if there's an if clause. */
+ cond_string = ep_parse_optional_if_clause (&arg);
+
+ if ((*arg != '\0') && !isspace (*arg))
+ error ("Junk at end of arguments.");
+
+ /* If this target supports it, create an exec catchpoint
+ and enable reporting of such events. */
+ create_exec_event_catchpoint (tempflag, cond_string);
+}
+
+static void
+catch_load_command_1 (char *arg, int tempflag, int from_tty)
+{
+ char *dll_pathname = NULL;
+ char *cond_string = NULL;
+
+ ep_skip_leading_whitespace (&arg);
+
+ /* The allowed syntax is:
+ catch load
+ catch load if <cond>
+ catch load <filename>
+ catch load <filename> if <cond>
+
+ The user is not allowed to specify the <filename> after an
+ if clause.
+
+ We'll ignore the pathological case of a file named "if".
+
+ First, check if there's an if clause. If so, then there
+ cannot be a filename. */
+ cond_string = ep_parse_optional_if_clause (&arg);
+
+ /* If there was an if clause, then there cannot be a filename.
+ Else, there might be a filename and an if clause. */
+ if (cond_string == NULL)
+ {
+ dll_pathname = ep_parse_optional_filename (&arg);
+ ep_skip_leading_whitespace (&arg);
+ cond_string = ep_parse_optional_if_clause (&arg);
+ }
+
+ if ((*arg != '\0') && !isspace (*arg))
+ error ("Junk at end of arguments.");
+
+ /* Create a load breakpoint that only triggers when a load of
+ the specified dll (or any dll, if no pathname was specified)
+ occurs. */
+ SOLIB_CREATE_CATCH_LOAD_HOOK (PIDGET (inferior_ptid), tempflag,
+ dll_pathname, cond_string);
+}
+
+static void
+catch_unload_command_1 (char *arg, int tempflag, int from_tty)
+{
+ char *dll_pathname = NULL;
+ char *cond_string = NULL;
+
+ ep_skip_leading_whitespace (&arg);
+
+ /* The allowed syntax is:
+ catch unload
+ catch unload if <cond>
+ catch unload <filename>
+ catch unload <filename> if <cond>
+
+ The user is not allowed to specify the <filename> after an
+ if clause.
+
+ We'll ignore the pathological case of a file named "if".
+
+ First, check if there's an if clause. If so, then there
+ cannot be a filename. */
+ cond_string = ep_parse_optional_if_clause (&arg);
+
+ /* If there was an if clause, then there cannot be a filename.
+ Else, there might be a filename and an if clause. */
+ if (cond_string == NULL)
+ {
+ dll_pathname = ep_parse_optional_filename (&arg);
+ ep_skip_leading_whitespace (&arg);
+ cond_string = ep_parse_optional_if_clause (&arg);
+ }
+
+ if ((*arg != '\0') && !isspace (*arg))
+ error ("Junk at end of arguments.");
+
+ /* Create an unload breakpoint that only triggers when an unload of
+ the specified dll (or any dll, if no pathname was specified)
+ occurs. */
+ SOLIB_CREATE_CATCH_UNLOAD_HOOK (PIDGET (inferior_ptid), tempflag,
+ dll_pathname, cond_string);
+}
+
+/* Commands to deal with catching exceptions. */
+
+/* Set a breakpoint at the specified callback routine for an
+ exception event callback */
+
+static void
+create_exception_catchpoint (int tempflag, char *cond_string,
+ enum exception_event_kind ex_event,
+ struct symtab_and_line *sal)
+{
+ struct breakpoint *b;
+ int thread = -1; /* All threads. */
+ enum bptype bptype;
+
+ if (!sal) /* no exception support? */
+ return;
+
+ switch (ex_event)
+ {
+ case EX_EVENT_THROW:
+ bptype = bp_catch_throw;
+ break;
+ case EX_EVENT_CATCH:
+ bptype = bp_catch_catch;
+ break;
+ default: /* error condition */
+ error ("Internal error -- invalid catchpoint kind");
+ }
+
+ b = set_raw_breakpoint (*sal, bptype);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = NULL;
+ b->cond_string = (cond_string == NULL) ?
+ NULL : savestring (cond_string, strlen (cond_string));
+ b->thread = thread;
+ b->addr_string = NULL;
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+ mention (b);
+}
+
+static enum print_stop_action
+print_exception_catchpoint (struct breakpoint *b)
+{
+ annotate_catchpoint (b->number);
+
+ if (strstr (b->addr_string, "throw") != NULL)
+ printf_filtered ("\nCatchpoint %d (exception thrown)\n",
+ b->number);
+ else
+ printf_filtered ("\nCatchpoint %d (exception caught)\n",
+ b->number);
+
+ return PRINT_SRC_AND_LOC;
+}
+
+static void
+print_one_exception_catchpoint (struct breakpoint *b, CORE_ADDR *last_addr)
+{
+ if (addressprint)
+ {
+ annotate_field (4);
+ ui_out_field_core_addr (uiout, "addr", b->loc->address);
+ }
+ annotate_field (5);
+ *last_addr = b->loc->address;
+ if (strstr (b->addr_string, "throw") != NULL)
+ ui_out_field_string (uiout, "what", "exception throw");
+ else
+ ui_out_field_string (uiout, "what", "exception catch");
+}
+
+static void
+print_mention_exception_catchpoint (struct breakpoint *b)
+{
+ if (strstr (b->addr_string, "throw") != NULL)
+ printf_filtered ("Catchpoint %d (throw)", b->number);
+ else
+ printf_filtered ("Catchpoint %d (catch)", b->number);
+}
+
+static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
+ print_exception_catchpoint,
+ print_one_exception_catchpoint,
+ print_mention_exception_catchpoint
+};
+
+static int
+handle_gnu_v3_exceptions (int tempflag, char *cond_string,
+ enum exception_event_kind ex_event, int from_tty)
+{
+ char *trigger_func_name, *nameptr;
+ struct symtabs_and_lines sals;
+ struct breakpoint *b;
+
+ if (ex_event == EX_EVENT_CATCH)
+ trigger_func_name = xstrdup ("__cxa_begin_catch");
+ else
+ trigger_func_name = xstrdup ("__cxa_throw");
+
+ nameptr = trigger_func_name;
+ sals = decode_line_1 (&nameptr, 1, NULL, 0, NULL, NULL);
+ if (sals.nelts == 0)
+ {
+ xfree (trigger_func_name);
+ return 0;
+ }
+
+ b = set_raw_breakpoint (sals.sals[0], bp_breakpoint);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = NULL;
+ b->cond_string = (cond_string == NULL) ?
+ NULL : savestring (cond_string, strlen (cond_string));
+ b->thread = -1;
+ b->addr_string = trigger_func_name;
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+ b->ops = &gnu_v3_exception_catchpoint_ops;
+
+ xfree (sals.sals);
+ mention (b);
+ return 1;
+}
+
+/* Deal with "catch catch" and "catch throw" commands */
+
+static void
+catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
+ int tempflag, int from_tty)
+{
+ char *cond_string = NULL;
+ struct symtab_and_line *sal = NULL;
+
+ ep_skip_leading_whitespace (&arg);
+
+ cond_string = ep_parse_optional_if_clause (&arg);
+
+ if ((*arg != '\0') && !isspace (*arg))
+ error ("Junk at end of arguments.");
+
+ if ((ex_event != EX_EVENT_THROW) &&
+ (ex_event != EX_EVENT_CATCH))
+ error ("Unsupported or unknown exception event; cannot catch it");
+
+ if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
+ return;
+
+ /* See if we can find a callback routine */
+ sal = target_enable_exception_callback (ex_event, 1);
+
+ if (sal)
+ {
+ /* We have callbacks from the runtime system for exceptions.
+ Set a breakpoint on the sal found, if no errors */
+ if (sal != (struct symtab_and_line *) -1)
+ create_exception_catchpoint (tempflag, cond_string, ex_event, sal);
+ else
+ return; /* something went wrong with setting up callbacks */
+ }
+
+ warning ("Unsupported with this platform/compiler combination.");
+}
+
+/* Cover routine to allow wrapping target_enable_exception_catchpoints
+ inside a catch_errors */
+
+static int
+cover_target_enable_exception_callback (void *arg)
+{
+ args_for_catchpoint_enable *args = arg;
+ struct symtab_and_line *sal;
+ sal = target_enable_exception_callback (args->kind, args->enable_p);
+ if (sal == NULL)
+ return 0;
+ else if (sal == (struct symtab_and_line *) -1)
+ return -1;
+ else
+ return 1; /*is valid */
+}
+
+static void
+catch_command_1 (char *arg, int tempflag, int from_tty)
+{
+
+ /* The first argument may be an event name, such as "start" or "load".
+ If so, then handle it as such. If it doesn't match an event name,
+ then attempt to interpret it as an exception name. (This latter is
+ the v4.16-and-earlier GDB meaning of the "catch" command.)
+
+ First, try to find the bounds of what might be an event name. */
+ char *arg1_start = arg;
+ char *arg1_end;
+ int arg1_length;
+
+ if (arg1_start == NULL)
+ {
+ /* Old behaviour was to use pre-v-4.16 syntax */
+ /* catch_throw_command_1 (arg1_start, tempflag, from_tty); */
+ /* return; */
+ /* Now, this is not allowed */
+ error ("Catch requires an event name.");
+
+ }
+ arg1_end = ep_find_event_name_end (arg1_start);
+ if (arg1_end == NULL)
+ error ("catch requires an event");
+ arg1_length = arg1_end + 1 - arg1_start;
+
+ /* Try to match what we found against known event names. */
+ if (strncmp (arg1_start, "signal", arg1_length) == 0)
+ {
+ error ("Catch of signal not yet implemented");
+ }
+ else if (strncmp (arg1_start, "catch", arg1_length) == 0)
+ {
+ catch_exception_command_1 (EX_EVENT_CATCH, arg1_end + 1,
+ tempflag, from_tty);
+ }
+ else if (strncmp (arg1_start, "throw", arg1_length) == 0)
+ {
+ catch_exception_command_1 (EX_EVENT_THROW, arg1_end + 1,
+ tempflag, from_tty);
+ }
+ else if (strncmp (arg1_start, "thread_start", arg1_length) == 0)
+ {
+ error ("Catch of thread_start not yet implemented");
+ }
+ else if (strncmp (arg1_start, "thread_exit", arg1_length) == 0)
+ {
+ error ("Catch of thread_exit not yet implemented");
+ }
+ else if (strncmp (arg1_start, "thread_join", arg1_length) == 0)
+ {
+ error ("Catch of thread_join not yet implemented");
+ }
+ else if (strncmp (arg1_start, "start", arg1_length) == 0)
+ {
+ error ("Catch of start not yet implemented");
+ }
+ else if (strncmp (arg1_start, "exit", arg1_length) == 0)
+ {
+ error ("Catch of exit not yet implemented");
+ }
+ else if (strncmp (arg1_start, "fork", arg1_length) == 0)
+ {
+ catch_fork_command_1 (catch_fork, arg1_end + 1, tempflag, from_tty);
+ }
+ else if (strncmp (arg1_start, "vfork", arg1_length) == 0)
+ {
+ catch_fork_command_1 (catch_vfork, arg1_end + 1, tempflag, from_tty);
+ }
+ else if (strncmp (arg1_start, "exec", arg1_length) == 0)
+ {
+ catch_exec_command_1 (arg1_end + 1, tempflag, from_tty);
+ }
+ else if (strncmp (arg1_start, "load", arg1_length) == 0)
+ {
+ catch_load_command_1 (arg1_end + 1, tempflag, from_tty);
+ }
+ else if (strncmp (arg1_start, "unload", arg1_length) == 0)
+ {
+ catch_unload_command_1 (arg1_end + 1, tempflag, from_tty);
+ }
+ else if (strncmp (arg1_start, "stop", arg1_length) == 0)
+ {
+ error ("Catch of stop not yet implemented");
+ }
+
+ /* This doesn't appear to be an event name */
+
+ else
+ {
+ /* Pre-v.4.16 behaviour was to treat the argument
+ as the name of an exception */
+ /* catch_throw_command_1 (arg1_start, tempflag, from_tty); */
+ /* Now this is not allowed */
+ error ("Unknown event kind specified for catch");
+
+ }
+}
+
+/* Used by the gui, could be made a worker for other things. */
+
+struct breakpoint *
+set_breakpoint_sal (struct symtab_and_line sal)
+{
+ struct breakpoint *b;
+ b = set_raw_breakpoint (sal, bp_breakpoint);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = 0;
+ b->thread = -1;
+ return b;
+}
+
+static void
+catch_command (char *arg, int from_tty)
+{
+ catch_command_1 (arg, 0, from_tty);
+}
+
+
+static void
+tcatch_command (char *arg, int from_tty)
+{
+ catch_command_1 (arg, 1, from_tty);
+}
+
+/* Delete breakpoints by address or line. */
+
+static void
+clear_command (char *arg, int from_tty)
+{
+ struct breakpoint *b, *tmp, *prev, *found;
+ int default_match;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ int i;
+
+ if (arg)
+ {
+ sals = decode_line_spec (arg, 1);
+ default_match = 0;
+ }
+ else
+ {
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ make_cleanup (xfree, sals.sals);
+ init_sal (&sal); /* initialize to zeroes */
+ sal.line = default_breakpoint_line;
+ sal.symtab = default_breakpoint_symtab;
+ sal.pc = default_breakpoint_address;
+ if (sal.symtab == 0)
+ error ("No source file specified.");
+
+ sals.sals[0] = sal;
+ sals.nelts = 1;
+
+ default_match = 1;
+ }
+
+ /* For each line spec given, delete bps which correspond
+ to it. Do it in two passes, solely to preserve the current
+ behavior that from_tty is forced true if we delete more than
+ one breakpoint. */
+
+ found = NULL;
+ for (i = 0; i < sals.nelts; i++)
+ {
+ /* If exact pc given, clear bpts at that pc.
+ If line given (pc == 0), clear all bpts on specified line.
+ If defaulting, clear all bpts on default line
+ or at default pc.
+
+ defaulting sal.pc != 0 tests to do
+
+ 0 1 pc
+ 1 1 pc _and_ line
+ 0 0 line
+ 1 0 <can't happen> */
+
+ sal = sals.sals[i];
+ prev = NULL;
+
+ /* Find all matching breakpoints, remove them from the
+ breakpoint chain, and add them to the 'found' chain. */
+ ALL_BREAKPOINTS_SAFE (b, tmp)
+ {
+ /* Are we going to delete b? */
+ if (b->type != bp_none
+ && b->type != bp_watchpoint
+ && b->type != bp_hardware_watchpoint
+ && b->type != bp_read_watchpoint
+ && b->type != bp_access_watchpoint
+ /* Not if b is a watchpoint of any sort... */
+ && (((sal.pc && (b->loc->address == sal.pc))
+ && (!section_is_overlay (b->loc->section)
+ || b->loc->section == sal.section))
+ /* Yes, if sal.pc matches b (modulo overlays). */
+ || ((default_match || (0 == sal.pc))
+ && b->source_file != NULL
+ && sal.symtab != NULL
+ && strcmp (b->source_file, sal.symtab->filename) == 0
+ && b->line_number == sal.line)))
+ /* Yes, if sal source file and line matches b. */
+ {
+ /* Remove it from breakpoint_chain... */
+ if (b == breakpoint_chain)
+ {
+ /* b is at the head of the list */
+ breakpoint_chain = b->next;
+ }
+ else
+ {
+ prev->next = b->next;
+ }
+ /* And add it to 'found' chain. */
+ b->next = found;
+ found = b;
+ }
+ else
+ {
+ /* Keep b, and keep a pointer to it. */
+ prev = b;
+ }
+ }
+ }
+ /* Now go thru the 'found' chain and delete them. */
+ 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);
+ tmp = found->next;
+ delete_breakpoint (found);
+ found = tmp;
+ }
+ if (from_tty)
+ putchar_unfiltered ('\n');
+}
+
+/* Delete breakpoint in BS if they are `delete' breakpoints and
+ all breakpoints that are marked for deletion, whether hit or not.
+ This is called after any breakpoint is hit, or after errors. */
+
+void
+breakpoint_auto_delete (bpstat bs)
+{
+ struct breakpoint *b, *temp;
+
+ for (; bs; bs = bs->next)
+ if (bs->breakpoint_at && bs->breakpoint_at->disposition == disp_del
+ && bs->stop)
+ delete_breakpoint (bs->breakpoint_at);
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ if (b->disposition == disp_del_at_next_stop)
+ delete_breakpoint (b);
+ }
+}
+
+/* Delete a breakpoint and clean up all traces of it in the data
+ structures. */
+
+void
+delete_breakpoint (struct breakpoint *bpt)
+{
+ struct breakpoint *b;
+ bpstat bs;
+ struct bp_location *loc;
+
+ if (bpt == NULL)
+ error ("Internal error (attempted to delete a NULL breakpoint)");
+
+
+ /* Has this bp already been deleted? This can happen because multiple
+ lists can hold pointers to bp's. bpstat lists are especial culprits.
+
+ One example of this happening is a watchpoint's scope bp. When the
+ scope bp triggers, we notice that the watchpoint is out of scope, and
+ delete it. We also delete its scope bp. But the scope bp is marked
+ "auto-deleting", and is already on a bpstat. That bpstat is then
+ checked for auto-deleting bp's, which are deleted.
+
+ A real solution to this problem might involve reference counts in bp's,
+ and/or giving them pointers back to their referencing bpstat's, and
+ teaching delete_breakpoint to only free a bp's storage when no more
+ references were extent. A cheaper bandaid was chosen. */
+ if (bpt->type == bp_none)
+ return;
+
+ if (delete_breakpoint_hook)
+ delete_breakpoint_hook (bpt);
+ breakpoint_delete_event (bpt->number);
+
+ if (bpt->loc->inserted)
+ remove_breakpoint (bpt->loc, mark_inserted);
+
+ if (breakpoint_chain == bpt)
+ breakpoint_chain = bpt->next;
+
+ if (bp_location_chain == bpt->loc)
+ bp_location_chain = bpt->loc->next;
+
+ /* If we have callback-style exception catchpoints, don't go through
+ the adjustments to the C++ runtime library etc. if the inferior
+ isn't actually running. target_enable_exception_callback for a
+ null target ops vector gives an undesirable error message, so we
+ check here and avoid it. Since currently (1997-09-17) only HP-UX aCC's
+ exceptions are supported in this way, it's OK for now. FIXME */
+ if (ep_is_exception_catchpoint (bpt) && target_has_execution)
+ {
+ /* Format possible error msg */
+ char *message = xstrprintf ("Error in deleting catchpoint %d:\n",
+ bpt->number);
+ struct cleanup *cleanups = make_cleanup (xfree, message);
+ args_for_catchpoint_enable args;
+ args.kind = bpt->type == bp_catch_catch ?
+ EX_EVENT_CATCH : EX_EVENT_THROW;
+ args.enable_p = 0;
+ catch_errors (cover_target_enable_exception_callback, &args,
+ message, RETURN_MASK_ALL);
+ do_cleanups (cleanups);
+ }
+
+
+ ALL_BREAKPOINTS (b)
+ if (b->next == bpt)
+ {
+ b->next = bpt->next;
+ break;
+ }
+
+ ALL_BP_LOCATIONS (loc)
+ if (loc->next == bpt->loc)
+ {
+ loc->next = bpt->loc->next;
+ break;
+ }
+
+ check_duplicates (bpt);
+ /* If this breakpoint was inserted, and there is another breakpoint
+ at the same address, we need to insert the other breakpoint. */
+ if (bpt->loc->inserted
+ && bpt->type != bp_hardware_watchpoint
+ && bpt->type != bp_read_watchpoint
+ && bpt->type != bp_access_watchpoint
+ && bpt->type != bp_catch_fork
+ && bpt->type != bp_catch_vfork
+ && bpt->type != bp_catch_exec)
+ {
+ ALL_BREAKPOINTS (b)
+ if (b->loc->address == bpt->loc->address
+ && b->loc->section == bpt->loc->section
+ && !b->loc->duplicate
+ && b->enable_state != bp_disabled
+ && b->enable_state != bp_shlib_disabled
+ && !b->pending
+ && b->enable_state != bp_call_disabled)
+ {
+ int val;
+
+ /* We should never reach this point if there is a permanent
+ breakpoint at the same address as the one being deleted.
+ If there is a permanent breakpoint somewhere, it should
+ always be the only one inserted. */
+ if (b->enable_state == bp_permanent)
+ internal_error (__FILE__, __LINE__,
+ "another breakpoint was inserted on top of "
+ "a permanent breakpoint");
+
+ if (b->type == bp_hardware_breakpoint)
+ val = target_insert_hw_breakpoint (b->loc->address, b->loc->shadow_contents);
+ else
+ val = target_insert_breakpoint (b->loc->address, b->loc->shadow_contents);
+
+ /* If there was an error in the insert, print a message, then stop execution. */
+ if (val != 0)
+ {
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_error_stream);
+
+
+ if (b->type == bp_hardware_breakpoint)
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert hardware breakpoint %d.\n"
+ "You may have requested too many hardware breakpoints.\n",
+ b->number);
+ }
+ else
+ {
+ fprintf_unfiltered (tmp_error_stream, "Cannot insert breakpoint %d.\n", b->number);
+ fprintf_filtered (tmp_error_stream, "Error accessing memory address ");
+ print_address_numeric (b->loc->address, 1, tmp_error_stream);
+ fprintf_filtered (tmp_error_stream, ": %s.\n",
+ safe_strerror (val));
+ }
+
+ fprintf_unfiltered (tmp_error_stream,"The same program may be running in another process.");
+ target_terminal_ours_for_output ();
+ error_stream(tmp_error_stream);
+ }
+ else
+ b->loc->inserted = 1;
+ }
+ }
+
+ free_command_lines (&bpt->commands);
+ if (bpt->cond)
+ xfree (bpt->cond);
+ if (bpt->cond_string != NULL)
+ xfree (bpt->cond_string);
+ if (bpt->addr_string != NULL)
+ xfree (bpt->addr_string);
+ if (bpt->exp != NULL)
+ xfree (bpt->exp);
+ if (bpt->exp_string != NULL)
+ xfree (bpt->exp_string);
+ if (bpt->val != NULL)
+ value_free (bpt->val);
+ if (bpt->source_file != NULL)
+ xfree (bpt->source_file);
+ if (bpt->dll_pathname != NULL)
+ xfree (bpt->dll_pathname);
+ if (bpt->triggered_dll_pathname != NULL)
+ xfree (bpt->triggered_dll_pathname);
+ if (bpt->exec_pathname != NULL)
+ xfree (bpt->exec_pathname);
+
+ /* 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;
+ bs->old_val = NULL;
+ /* bs->commands will be freed later. */
+ }
+ /* On the chance that someone will soon try again to delete this same
+ bp, we mark it as deleted before freeing its storage. */
+ bpt->type = bp_none;
+
+ xfree (bpt->loc);
+ xfree (bpt);
+}
+
+static void
+do_delete_breakpoint_cleanup (void *b)
+{
+ delete_breakpoint (b);
+}
+
+struct cleanup *
+make_cleanup_delete_breakpoint (struct breakpoint *b)
+{
+ return make_cleanup (do_delete_breakpoint_cleanup, b);
+}
+
+struct cleanup *
+make_exec_cleanup_delete_breakpoint (struct breakpoint *b)
+{
+ return make_exec_cleanup (do_delete_breakpoint_cleanup, b);
+}
+
+void
+delete_command (char *arg, int from_tty)
+{
+ struct breakpoint *b, *temp;
+
+ dont_repeat ();
+
+ if (arg == 0)
+ {
+ int breaks_to_delete = 0;
+
+ /* Delete all breakpoints if no argument.
+ Do not delete internal or call-dummy breakpoints, these
+ have to be deleted with an explicit breakpoint number argument. */
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->type != bp_call_dummy &&
+ b->type != bp_shlib_event &&
+ b->type != bp_thread_event &&
+ b->type != bp_overlay_event &&
+ b->number >= 0)
+ breaks_to_delete = 1;
+ }
+
+ /* Ask user only if there are some breakpoints to delete. */
+ if (!from_tty
+ || (breaks_to_delete && query ("Delete all breakpoints? ")))
+ {
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ if (b->type != bp_call_dummy &&
+ b->type != bp_shlib_event &&
+ b->type != bp_thread_event &&
+ b->type != bp_overlay_event &&
+ b->number >= 0)
+ delete_breakpoint (b);
+ }
+ }
+ }
+ 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 (void *bint)
+{
+ /* get past catch_errs */
+ struct breakpoint *b = (struct breakpoint *) bint;
+ struct value *mark;
+ int i;
+ struct symtabs_and_lines sals;
+ char *s;
+ enum enable_state save_enable;
+
+ switch (b->type)
+ {
+ case bp_none:
+ warning ("attempted to reset apparently deleted breakpoint #%d?",
+ b->number);
+ return 0;
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ case bp_catch_load:
+ case bp_catch_unload:
+ if (b->addr_string == NULL)
+ {
+ /* Anything without a string can't be re-set. */
+ delete_breakpoint (b);
+ return 0;
+ }
+ /* HACK: cagney/2001-11-11: kettenis/2001-11-11: MarkK wrote:
+
+ ``And a hack it is, although Apple's Darwin version of GDB
+ contains an almost identical hack to implement a "future
+ break" command. It seems to work in many real world cases,
+ but it is easy to come up with a test case where the patch
+ doesn't help at all.''
+
+ ``It seems that the way GDB implements breakpoints - in -
+ shared - libraries was designed for a.out shared library
+ systems (SunOS 4) where shared libraries were loaded at a
+ fixed address in memory. Since ELF shared libraries can (and
+ will) be loaded at any address in memory, things break.
+ Fixing this is not trivial. Therefore, I'm not sure whether
+ we should add this hack to the branch only. I cannot
+ guarantee that things will be fixed on the trunk in the near
+ future.''
+
+ In case we have a problem, disable this breakpoint. We'll
+ restore its status if we succeed. Don't disable a
+ shlib_disabled breakpoint though. There's a fair chance we
+ can't re-set it if the shared library it's in hasn't been
+ loaded yet. */
+
+ if (b->pending)
+ break;
+
+ save_enable = b->enable_state;
+ if (b->enable_state != bp_shlib_disabled)
+ b->enable_state = bp_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, 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)
+ {
+ xfree (b->cond);
+ /* Avoid re-freeing b->exp if an error during the call
+ to parse_exp_1. */
+ b->cond = NULL;
+ }
+ 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->loc->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
+ && (strcmp (b->source_file, sals.sals[i].symtab->filename) != 0
+ || 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)
+ xfree (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->loc->requested_address = sals.sals[i].pc;
+ b->loc->address
+ = adjust_breakpoint_address (b->loc->requested_address);
+
+ /* Used to check for duplicates here, but that can
+ cause trouble, as it doesn't check for disabled
+ breakpoints. */
+
+ mention (b);
+
+ /* Might be better to do this just once per breakpoint_re_set,
+ rather than once for every breakpoint. */
+ breakpoints_changed ();
+ }
+ b->loc->section = sals.sals[i].section;
+ b->enable_state = save_enable; /* Restore it, this worked. */
+
+
+ /* Now that this is re-enabled, check_duplicates
+ can be used. */
+ check_duplicates (b);
+
+ }
+ xfree (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 function names. */
+
+ /* So for now, just use a global context. */
+ if (b->exp)
+ {
+ xfree (b->exp);
+ /* Avoid re-freeing b->exp if an error during the call to
+ parse_expression. */
+ b->exp = NULL;
+ }
+ b->exp = parse_expression (b->exp_string);
+ b->exp_valid_block = innermost_block;
+ mark = value_mark ();
+ if (b->val)
+ {
+ value_free (b->val);
+ /* Avoid re-freeing b->val if an error during the call to
+ evaluate_expression. */
+ b->val = NULL;
+ }
+ b->val = evaluate_expression (b->exp);
+ release_value (b->val);
+ if (VALUE_LAZY (b->val) && breakpoint_enabled (b))
+ value_fetch_lazy (b->val);
+
+ if (b->cond_string != NULL)
+ {
+ s = b->cond_string;
+ if (b->cond)
+ {
+ xfree (b->cond);
+ /* Avoid re-freeing b->exp if an error during the call
+ to parse_exp_1. */
+ b->cond = NULL;
+ }
+ b->cond = parse_exp_1 (&s, (struct block *) 0, 0);
+ }
+ if (breakpoint_enabled (b))
+ mention (b);
+ value_free_to_mark (mark);
+ break;
+ case bp_catch_catch:
+ case bp_catch_throw:
+ break;
+ /* We needn't really do anything to reset these, since the mask
+ that requests them is unaffected by e.g., new libraries being
+ loaded. */
+ case bp_catch_fork:
+ case bp_catch_vfork:
+ case bp_catch_exec:
+ break;
+
+ default:
+ printf_filtered ("Deleting unknown breakpoint type %d\n", b->type);
+ /* fall through */
+ /* Delete longjmp and overlay event breakpoints; they will be
+ reset later by breakpoint_re_set. */
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_overlay_event:
+ 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:
+
+ /* Like bp_shlib_event, this breakpoint type is special.
+ Once it is set up, we do not want to touch it. */
+ case bp_thread_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 (void)
+{
+ struct breakpoint *b, *temp;
+ enum language save_language;
+ int save_input_radix;
+
+ save_language = current_language->la_language;
+ save_input_radix = input_radix;
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ /* Format possible error msg */
+ char *message = xstrprintf ("Error in re-setting breakpoint %d:\n",
+ b->number);
+ struct cleanup *cleanups = make_cleanup (xfree, message);
+ catch_errors (breakpoint_re_set_one, b, message, RETURN_MASK_ALL);
+ do_cleanups (cleanups);
+ }
+ set_language (save_language);
+ input_radix = save_input_radix;
+
+ if (GET_LONGJMP_TARGET_P ())
+ {
+ create_longjmp_breakpoint ("longjmp");
+ create_longjmp_breakpoint ("_longjmp");
+ create_longjmp_breakpoint ("siglongjmp");
+ create_longjmp_breakpoint ("_siglongjmp");
+ create_longjmp_breakpoint (NULL);
+ }
+
+ create_overlay_event_breakpoint ("_ovly_debug_event");
+}
+
+/* Reset the thread number of this breakpoint:
+
+ - If the breakpoint is for all threads, leave it as-is.
+ - Else, reset it to the current thread for inferior_ptid. */
+void
+breakpoint_re_set_thread (struct breakpoint *b)
+{
+ if (b->thread != -1)
+ {
+ if (in_thread_list (inferior_ptid))
+ b->thread = pid_to_thread_id (inferior_ptid);
+ }
+}
+
+/* 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 (int bptnum, int count, int from_tty)
+{
+ struct breakpoint *b;
+
+ if (count < 0)
+ count = 0;
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bptnum)
+ {
+ b->ignore_count = count;
+ if (from_tty)
+ {
+ 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 ();
+ breakpoint_modify_event (b->number);
+ return;
+ }
+
+ error ("No breakpoint number %d.", bptnum);
+}
+
+/* Clear the ignore counts of all breakpoints. */
+void
+breakpoint_clear_ignore_counts (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ b->ignore_count = 0;
+}
+
+/* Command to set ignore-count of breakpoint N to COUNT. */
+
+static void
+ignore_command (char *args, int from_tty)
+{
+ char *p = args;
+ int num;
+
+ if (p == 0)
+ error_no_arg ("a breakpoint number");
+
+ num = get_number (&p);
+ if (num == 0)
+ error ("bad breakpoint number: '%s'", args);
+ 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);
+ if (from_tty)
+ printf_filtered ("\n");
+}
+
+/* Call FUNCTION on each of the breakpoints
+ whose numbers are given in ARGS. */
+
+static void
+map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
+{
+ char *p = args;
+ char *p1;
+ int num;
+ struct breakpoint *b, *tmp;
+ int match;
+
+ if (p == 0)
+ error_no_arg ("one or more breakpoint numbers");
+
+ while (*p)
+ {
+ match = 0;
+ p1 = p;
+
+ num = get_number_or_range (&p1);
+ if (num == 0)
+ {
+ warning ("bad breakpoint number at or near '%s'", p);
+ }
+ else
+ {
+ ALL_BREAKPOINTS_SAFE (b, tmp)
+ if (b->number == num)
+ {
+ struct breakpoint *related_breakpoint = b->related_breakpoint;
+ match = 1;
+ function (b);
+ if (related_breakpoint)
+ function (related_breakpoint);
+ break;
+ }
+ if (match == 0)
+ printf_unfiltered ("No breakpoint number %d.\n", num);
+ }
+ p = p1;
+ }
+}
+
+/* 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
+disable_breakpoint (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;
+
+ /* You can't disable permanent breakpoints. */
+ if (bpt->enable_state == bp_permanent)
+ return;
+
+ bpt->enable_state = bp_disabled;
+
+ check_duplicates (bpt);
+
+ if (modify_breakpoint_hook)
+ modify_breakpoint_hook (bpt);
+ breakpoint_modify_event (bpt->number);
+}
+
+static void
+disable_command (char *args, int from_tty)
+{
+ struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ switch (bpt->type)
+ {
+ case bp_none:
+ warning ("attempted to disable apparently deleted breakpoint #%d?",
+ bpt->number);
+ continue;
+ case bp_breakpoint:
+ case bp_catch_load:
+ case bp_catch_unload:
+ case bp_catch_fork:
+ case bp_catch_vfork:
+ case bp_catch_exec:
+ case bp_catch_catch:
+ case bp_catch_throw:
+ 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
+do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
+{
+ 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.");
+ }
+
+ if (bpt->pending)
+ {
+ if (bpt->enable_state != bp_enabled)
+ {
+ /* When enabling a pending breakpoint, we need to check if the breakpoint
+ is resolvable since shared libraries could have been loaded
+ after the breakpoint was disabled. */
+ breakpoints_changed ();
+ if (resolve_pending_breakpoint (bpt) == GDB_RC_OK)
+ {
+ delete_breakpoint (bpt);
+ return;
+ }
+ bpt->enable_state = bp_enabled;
+ bpt->disposition = disposition;
+ }
+ }
+ else /* Not a pending breakpoint. */
+ {
+ if (bpt->enable_state != bp_permanent)
+ bpt->enable_state = bp_enabled;
+ bpt->disposition = disposition;
+ check_duplicates (bpt);
+ 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 =
+ fr = frame_find_by_id (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_state = bp_disabled;
+ return;
+ }
+
+ save_selected_frame = deprecated_selected_frame;
+ save_selected_frame_level = frame_relative_level (deprecated_selected_frame);
+ select_frame (fr);
+ }
+
+ 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);
+
+ /* Hack around 'unused var' error for some targets here */
+ (void) mem_cnt, i;
+ 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_state = bp_disabled;
+ value_free_to_mark (mark);
+ return;
+ }
+ }
+
+ if (save_selected_frame_level >= 0)
+ select_frame (save_selected_frame);
+ value_free_to_mark (mark);
+ }
+ }
+
+ if (modify_breakpoint_hook)
+ modify_breakpoint_hook (bpt);
+ breakpoint_modify_event (bpt->number);
+}
+
+void
+enable_breakpoint (struct breakpoint *bpt)
+{
+ do_enable_breakpoint (bpt, bpt->disposition);
+}
+
+/* The enable command enables the specified breakpoints (or all defined
+ breakpoints) so they once again become (or continue to be) effective
+ in stopping the inferior. */
+
+static void
+enable_command (char *args, int from_tty)
+{
+ struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ switch (bpt->type)
+ {
+ case bp_none:
+ warning ("attempted to enable apparently deleted breakpoint #%d?",
+ bpt->number);
+ continue;
+ case bp_breakpoint:
+ case bp_catch_load:
+ case bp_catch_unload:
+ case bp_catch_fork:
+ case bp_catch_vfork:
+ case bp_catch_exec:
+ case bp_catch_catch:
+ case bp_catch_throw:
+ 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);
+}
+
+static void
+enable_once_breakpoint (struct breakpoint *bpt)
+{
+ do_enable_breakpoint (bpt, disp_disable);
+}
+
+static void
+enable_once_command (char *args, int from_tty)
+{
+ map_breakpoint_numbers (args, enable_once_breakpoint);
+}
+
+static void
+enable_delete_breakpoint (struct breakpoint *bpt)
+{
+ do_enable_breakpoint (bpt, disp_del);
+}
+
+static void
+enable_delete_command (char *args, int from_tty)
+{
+ map_breakpoint_numbers (args, enable_delete_breakpoint);
+}
+
+static void
+set_breakpoint_cmd (char *args, int from_tty)
+{
+}
+
+static void
+show_breakpoint_cmd (char *args, int from_tty)
+{
+}
+
+/* Use default_breakpoint_'s, or nothing if they aren't valid. */
+
+struct symtabs_and_lines
+decode_line_spec_1 (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, NULL);
+ else
+ sals = decode_line_1 (&string, funfirstline,
+ (struct symtab *) NULL, 0, (char ***) NULL, NULL);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+void
+_initialize_breakpoint (void)
+{
+ static struct cmd_list_element *breakpoint_set_cmdlist;
+ static struct cmd_list_element *breakpoint_show_cmdlist;
+ struct cmd_list_element *c;
+
+ 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'.");
+ if (xdb_commands)
+ add_com_alias ("bc", "ignore", class_breakpoint, 1);
+
+ 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.");
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ 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);
+ if (xdb_commands)
+ add_com ("ab", 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.");
+
+ add_com_alias ("en", "enable", class_breakpoint, 1);
+
+ 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);
+ if (xdb_commands)
+ add_com ("sb", 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.");
+
+ 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);
+ if (xdb_commands)
+ add_com ("db", class_breakpoint, delete_command,
+ "Delete some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n");
+
+ 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));
+
+ c = 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));
+ set_cmd_completer (c, location_completer);
+
+ 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);
+
+ if (xdb_commands)
+ {
+ add_com_alias ("ba", "break", class_breakpoint, 1);
+ add_com_alias ("bu", "ubreak", class_breakpoint, 1);
+ }
+
+ if (dbx_commands)
+ {
+ add_abbrev_prefix_cmd ("stop", class_breakpoint, stop_command,
+ "Break in function/address or break at a line in the current file.",
+ &stoplist, "stop ", 1, &cmdlist);
+ add_cmd ("in", class_breakpoint, stopin_command,
+ "Break in function or address.\n", &stoplist);
+ add_cmd ("at", class_breakpoint, stopat_command,
+ "Break at a line in the current file.\n", &stoplist);
+ add_com ("status", class_info, 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));
+ }
+
+ 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 (xdb_commands)
+ add_com ("lb", class_breakpoint, 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));
+
+ 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);
+
+ add_com ("catch", class_breakpoint, catch_command,
+ "Set catchpoints to catch events.\n\
+Raised signals may be caught:\n\
+\tcatch signal - all signals\n\
+\tcatch signal <signame> - a particular signal\n\
+Raised exceptions may be caught:\n\
+\tcatch throw - all exceptions, when thrown\n\
+\tcatch throw <exceptname> - a particular exception, when thrown\n\
+\tcatch catch - all exceptions, when caught\n\
+\tcatch catch <exceptname> - a particular exception, when caught\n\
+Thread or process events may be caught:\n\
+\tcatch thread_start - any threads, just after creation\n\
+\tcatch thread_exit - any threads, just before expiration\n\
+\tcatch thread_join - any threads, just after joins\n\
+Process events may be caught:\n\
+\tcatch start - any processes, just after creation\n\
+\tcatch exit - any processes, just before expiration\n\
+\tcatch fork - calls to fork()\n\
+\tcatch vfork - calls to vfork()\n\
+\tcatch exec - calls to exec()\n\
+Dynamically-linked library events may be caught:\n\
+\tcatch load - loads of any library\n\
+\tcatch load <libname> - loads of a particular library\n\
+\tcatch unload - unloads of any library\n\
+\tcatch unload <libname> - unloads of a particular library\n\
+The act of your program's execution stopping may also be caught:\n\
+\tcatch stop\n\n\
+C++ exceptions may be caught:\n\
+\tcatch throw - all exceptions, when thrown\n\
+\tcatch catch - all exceptions, when caught\n\
+\n\
+Do \"help set follow-fork-mode\" for info on debugging your program\n\
+after a fork or vfork is caught.\n\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+
+ add_com ("tcatch", class_breakpoint, tcatch_command,
+ "Set temporary catchpoints to catch events.\n\
+Args like \"catch\" command.\n\
+Like \"catch\" except the catchpoint is only temporary,\n\
+so it will be deleted when hit. Equivalent to \"catch\" followed\n\
+by using \"enable delete\" on the catchpoint number.");
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ add_info ("watchpoints", breakpoints_info,
+ "Synonym for ``info breakpoints''.");
+
+
+ c = add_set_cmd ("can-use-hw-watchpoints", class_support, var_zinteger,
+ (char *) &can_use_hw_watchpoints,
+ "Set debugger's willingness to use watchpoint hardware.\n\
+If zero, gdb will not use hardware for new watchpoints, even if\n\
+such is available. (However, any hardware watchpoints that were\n\
+created before setting this to nonzero, will continue to use watchpoint\n\
+hardware.)",
+ &setlist);
+ add_show_from_set (c, &showlist);
+
+ can_use_hw_watchpoints = 1;
+
+ add_prefix_cmd ("breakpoint", class_maintenance, set_breakpoint_cmd, "\
+Breakpoint specific settings\n\
+Configure various breakpoint-specific variables such as\n\
+pending breakpoint behavior",
+ &breakpoint_set_cmdlist, "set breakpoint ",
+ 0/*allow-unknown*/, &setlist);
+ add_prefix_cmd ("breakpoint", class_maintenance, show_breakpoint_cmd, "\
+Breakpoint specific settings\n\
+Configure various breakpoint-specific variables such as\n\
+pending breakpoint behavior",
+ &breakpoint_show_cmdlist, "show breakpoint ",
+ 0/*allow-unknown*/, &showlist);
+
+ add_setshow_auto_boolean_cmd ("pending", no_class, &pending_break_support, "\
+Set debugger's behavior regarding pending breakpoints.\n\
+If on, an unrecognized breakpoint location will cause gdb to create a\n\
+pending breakpoint. If off, an unrecognized breakpoint location results in\n\
+an error. If auto, an unrecognized breakpoint location results in a\n\
+user-query to see if a pending breakpoint should be created.","\
+Show debugger's behavior regarding pending breakpoints.\n\
+If on, an unrecognized breakpoint location will cause gdb to create a\n\
+pending breakpoint. If off, an unrecognized breakpoint location results in\n\
+an error. If auto, an unrecognized breakpoint location results in a\n\
+user-query to see if a pending breakpoint should be created.",
+ NULL, NULL,
+ &breakpoint_set_cmdlist,
+ &breakpoint_show_cmdlist);
+
+ pending_break_support = AUTO_BOOLEAN_AUTO;
+}
diff --git a/contrib/gdb/gdb/breakpoint.h b/contrib/gdb/gdb/breakpoint.h
new file mode 100644
index 0000000..41bcb0c
--- /dev/null
+++ b/contrib/gdb/gdb/breakpoint.h
@@ -0,0 +1,805 @@
+/* Data structures associated with breakpoints in GDB.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+#include "gdb-events.h"
+
+struct value;
+struct block;
+
+/* 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_none = 0, /* Eventpoint has been deleted. */
+ 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,
+
+ /* Some multi-threaded systems can arrange for a location in the
+ inferior to be executed when certain thread-related events occur
+ (such as thread creation or thread death).
+
+ By placing a breakpoint at one of these locations, GDB will get
+ control when these events occur. GDB can then update its thread
+ lists etc. */
+
+ bp_thread_event,
+
+ /* On the same principal, an overlay manager can arrange to call a
+ magic location in the inferior whenever there is an interesting
+ change in overlay status. GDB can update its overlay tables
+ and fiddle with breakpoints in overlays when this breakpoint
+ is hit. */
+
+ bp_overlay_event,
+
+ /* These breakpoints are used to implement the "catch load" command
+ on platforms whose dynamic linkers support such functionality. */
+ bp_catch_load,
+
+ /* These breakpoints are used to implement the "catch unload" command
+ on platforms whose dynamic linkers support such functionality. */
+ bp_catch_unload,
+
+ /* These are not really breakpoints, but are catchpoints that
+ implement the "catch fork", "catch vfork" and "catch exec" commands
+ on platforms whose kernel support such functionality. (I.e.,
+ kernels which can raise an event when a fork or exec occurs, as
+ opposed to the debugger setting breakpoints on functions named
+ "fork" or "exec".) */
+ bp_catch_fork,
+ bp_catch_vfork,
+ bp_catch_exec,
+
+ /* These are catchpoints to implement "catch catch" and "catch throw"
+ commands for C++ exception handling. */
+ bp_catch_catch,
+ bp_catch_throw
+
+
+ };
+
+/* States of enablement of breakpoint. */
+
+enum enable_state
+ {
+ bp_disabled, /* The eventpoint is inactive, and cannot trigger. */
+ bp_enabled, /* The eventpoint is active, and can trigger. */
+ bp_shlib_disabled, /* The eventpoint's address is in an unloaded solib.
+ The eventpoint will be automatically enabled
+ and reset when that solib is loaded. */
+ bp_call_disabled, /* The eventpoint has been disabled while a call
+ into the inferior is "in flight", because some
+ eventpoints interfere with the implementation of
+ a call on some targets. The eventpoint will be
+ automatically enabled and reset when the call
+ "lands" (either completes, or stops at another
+ eventpoint). */
+ bp_permanent /* There is a breakpoint instruction hard-wired into
+ the target's code. Don't try to write another
+ breakpoint instruction on top of it, or restore
+ its value. Step over it using the architecture's
+ SKIP_INSN macro. */
+ };
+
+
+/* Disposition of breakpoint. Ie: what to do after hitting it. */
+
+enum bpdisp
+ {
+ disp_del, /* Delete it */
+ disp_del_at_next_stop, /* Delete at next stop, whether hit or not */
+ disp_disable, /* Disable it */
+ disp_donttouch /* Leave it alone */
+ };
+
+enum target_hw_bp_type
+ {
+ hw_write = 0, /* Common HW watchpoint */
+ hw_read = 1, /* Read HW watchpoint */
+ hw_access = 2, /* Access HW watchpoint */
+ hw_execute = 3 /* Execute HW breakpoint */
+ };
+
+/* GDB maintains two types of information about each breakpoint (or
+ watchpoint, or other related event). The first type corresponds
+ to struct breakpoint; this is a relatively high-level structure
+ which contains the source location(s), stopping conditions, user
+ commands to execute when the breakpoint is hit, and so forth.
+
+ The second type of information corresponds to struct bp_location.
+ Each breakpoint has one or (eventually) more locations associated
+ with it, which represent target-specific and machine-specific
+ mechanisms for stopping the program. For instance, a watchpoint
+ expression may require multiple hardware watchpoints in order to
+ catch all changes in the value of the expression being watched. */
+
+enum bp_loc_type
+{
+ bp_loc_software_breakpoint,
+ bp_loc_hardware_breakpoint,
+ bp_loc_hardware_watchpoint,
+ bp_loc_other /* Miscellaneous... */
+};
+
+struct bp_location
+{
+ /* Chain pointer to the next breakpoint location. */
+ struct bp_location *next;
+
+ /* Type of this breakpoint location. */
+ enum bp_loc_type loc_type;
+
+ /* Each breakpoint location must belong to exactly one higher-level
+ breakpoint. This and the DUPLICATE flag are more straightforward
+ than reference counting. */
+ struct breakpoint *owner;
+
+ /* Nonzero if this breakpoint is now inserted. */
+ char inserted;
+
+ /* Nonzero if this is not the first breakpoint in the list
+ for the given address. */
+ char duplicate;
+
+ /* If we someday support real thread-specific breakpoints, then
+ the breakpoint location will need a thread identifier. */
+
+ /* Data for specific breakpoint types. These could be a union, but
+ simplicity is more important than memory usage for breakpoints. */
+
+ /* Note that zero is a perfectly valid code address on some platforms
+ (for example, the mn10200 (OBSOLETE) and mn10300 simulators). NULL
+ is not a special value for this field. Valid for all types except
+ bp_loc_other. */
+ CORE_ADDR address;
+
+ /* For any breakpoint type with an address, this is the BFD section
+ associated with the address. Used primarily for overlay debugging. */
+ asection *section;
+
+ /* "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.
+ Valid only for bp_loc_software_breakpoint. */
+ char shadow_contents[BREAKPOINT_MAX];
+
+ /* Address at which breakpoint was requested, either by the user or
+ by GDB for internal breakpoints. This will usually be the same
+ as ``address'' (above) except for cases in which
+ ADJUST_BREAKPOINT_ADDRESS has computed a different address at
+ which to place the breakpoint in order to comply with a
+ processor's architectual constraints. */
+ CORE_ADDR requested_address;
+};
+
+/* This structure is a collection of function pointers that, if available,
+ will be called instead of the performing the default action for this
+ bptype. */
+
+struct breakpoint_ops
+{
+ /* The normal print routine for this breakpoint, called when we
+ hit it. */
+ enum print_stop_action (*print_it) (struct breakpoint *);
+
+ /* Display information about this breakpoint, for "info breakpoints". */
+ void (*print_one) (struct breakpoint *, CORE_ADDR *);
+
+ /* Display information about this breakpoint after setting it (roughly
+ speaking; this is called from "mention"). */
+ void (*print_mention) (struct breakpoint *);
+};
+
+/* 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_state enable_state;
+ /* What to do with this breakpoint after we hit it. */
+ enum bpdisp disposition;
+ /* Number assigned to distinguish breakpoints. */
+ int number;
+
+ /* Location(s) associated with this high-level breakpoint. */
+ struct bp_location *loc;
+
+ /* Line number of this address. */
+
+ int line_number;
+
+ /* Source file name of this address. */
+
+ 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;
+ /* 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. */
+ struct frame_id frame_id;
+ /* Conditional. Break only if this expression's value is nonzero. */
+ struct expression *cond;
+
+ /* String we used to set the breakpoint (malloc'd). */
+ 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. */
+ struct value *val;
+
+ /* Holds the value chain for a hardware watchpoint expression. */
+ struct value *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. */
+ struct frame_id 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;
+
+ /* Filename of a dynamically-linked library (dll), used for
+ bp_catch_load and bp_catch_unload (malloc'd), or NULL if any
+ library is significant. */
+ char *dll_pathname;
+
+ /* Filename of a dll whose state change (e.g., load or unload)
+ triggered this catchpoint. This field is only valid immediately
+ after this catchpoint has triggered. */
+ char *triggered_dll_pathname;
+
+ /* Process id of a child process whose forking triggered this
+ catchpoint. This field is only valid immediately after this
+ catchpoint has triggered. */
+ int forked_inferior_pid;
+
+ /* Filename of a program whose exec triggered this catchpoint.
+ This field is only valid immediately after this catchpoint has
+ triggered. */
+ char *exec_pathname;
+
+ /* Methods associated with this breakpoint. */
+ struct breakpoint_ops *ops;
+
+ /* Was breakpoint issued from a tty? Saved for the use of pending breakpoints. */
+ int from_tty;
+
+ /* Flag value for pending breakpoint.
+ first bit : 0 non-temporary, 1 temporary.
+ second bit : 0 normal breakpoint, 1 hardware breakpoint. */
+ int flag;
+
+ /* Is breakpoint pending on shlib loads? */
+ int pending;
+ };
+
+/* 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 (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 (bpstat);
+
+extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid);
+
+/* 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,
+
+ /* Check the dynamic linker's data structures for new libraries, then
+ resume out of the dynamic linker's callback, stop and print. */
+ BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK,
+
+ /* 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;
+ };
+
+/* The possible return values for print_bpstat, print_it_normal,
+ print_it_done, print_it_noop. */
+enum print_stop_action
+ {
+ PRINT_UNKNOWN = -1,
+ PRINT_SRC_AND_LOC,
+ PRINT_SRC_ONLY,
+ PRINT_NOTHING
+ };
+
+/* Tell what to do about this bpstat. */
+struct bpstat_what bpstat_what (bpstat);
+
+/* Find the bpstat associated with a breakpoint. NULL otherwise. */
+bpstat bpstat_find_breakpoint (bpstat, struct breakpoint *);
+
+/* Find a step_resume breakpoint associated with this bpstat.
+ (If there are multiple step_resume bp's on the list, this function
+ will arbitrarily pick one.)
+
+ It is an error to use this function if BPSTAT doesn't contain a
+ step_resume breakpoint.
+
+ See wait_for_inferior's use of this function.
+ */
+extern struct breakpoint *bpstat_find_step_resume_breakpoint (bpstat);
+
+/* 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 (void);
+
+/* Nonzero if there are enabled hardware watchpoints. */
+extern int bpstat_have_active_hw_watchpoints (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 enum print_stop_action bpstat_print (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 (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 (bpstat *);
+
+/* Modify BS so that the actions will not be performed. */
+extern void bpstat_clear_actions (bpstat);
+
+/* Given a bpstat that records zero or more triggered eventpoints, this
+ function returns another bpstat which contains only the catchpoints
+ on that first list, if any.
+ */
+extern void bpstat_get_triggered_catchpoints (bpstat, bpstat *);
+
+/* Implementation: */
+
+/* Values used to tell the printing routine how to behave for this bpstat. */
+enum bp_print_how
+ {
+ /* This is used when we want to do a normal printing of the reason
+ for stopping. The output will depend on the type of eventpoint
+ we are dealing with. This is the default value, most commonly
+ used. */
+ print_it_normal,
+ /* This is used when nothing should be printed for this bpstat entry. */
+ print_it_noop,
+ /* This is used when everything which needs to be printed has
+ already been printed. But we still want to print the frame. */
+ print_it_done
+ };
+
+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. */
+ struct value *old_val;
+
+ /* Nonzero if this breakpoint tells us to print the frame. */
+ char print;
+
+ /* Nonzero if this breakpoint tells us to stop. */
+ char stop;
+
+ /* Tell bpstat_print and print_bp_stop_message how to print stuff
+ associated with this element of the bpstat chain. */
+ enum bp_print_how print_it;
+ };
+
+enum inf_context
+ {
+ inf_starting,
+ inf_running,
+ inf_exited
+ };
+
+/* The possible return values for breakpoint_here_p.
+ We guarantee that zero always means "no breakpoint here". */
+enum breakpoint_here
+ {
+ no_breakpoint_here = 0,
+ ordinary_breakpoint_here,
+ permanent_breakpoint_here
+ };
+
+
+/* Prototypes for breakpoint-related functions. */
+
+extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
+
+extern int breakpoint_inserted_here_p (CORE_ADDR);
+
+extern int software_breakpoint_inserted_here_p (CORE_ADDR);
+
+/* FIXME: cagney/2002-11-10: The current [generic] dummy-frame code
+ implements a functional superset of this function. The only reason
+ it hasn't been removed is because some architectures still don't
+ use the new framework. Once they have been fixed, this can go. */
+struct frame_info;
+extern int deprecated_frame_in_dummy (struct frame_info *);
+
+extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
+
+extern void until_break_command (char *, int, int);
+
+extern void breakpoint_re_set (void);
+
+extern void breakpoint_re_set_thread (struct breakpoint *);
+
+extern int ep_is_exception_catchpoint (struct breakpoint *);
+
+extern struct breakpoint *set_momentary_breakpoint
+ (struct symtab_and_line, struct frame_id, enum bptype);
+
+extern void set_ignore_count (int, int, int);
+
+extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int);
+
+extern void mark_breakpoints_out (void);
+
+extern void breakpoint_init_inferior (enum inf_context);
+
+extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
+
+extern struct cleanup *make_exec_cleanup_delete_breakpoint (struct breakpoint *);
+
+extern void delete_breakpoint (struct breakpoint *);
+
+extern void breakpoint_auto_delete (bpstat);
+
+extern void breakpoint_clear_ignore_counts (void);
+
+extern void break_command (char *, int);
+
+extern void hbreak_command_wrapper (char *, int);
+extern void thbreak_command_wrapper (char *, int);
+extern void rbreak_command_wrapper (char *, int);
+extern void watch_command_wrapper (char *, int);
+extern void awatch_command_wrapper (char *, int);
+extern void rwatch_command_wrapper (char *, int);
+extern void tbreak_command (char *, int);
+
+extern int insert_breakpoints (void);
+
+extern int remove_breakpoints (void);
+
+/* This function can be used to physically insert eventpoints from the
+ specified traced inferior process, without modifying the breakpoint
+ package's state. This can be useful for those targets which support
+ following the processes of a fork() or vfork() system call, when both
+ of the resulting two processes are to be followed. */
+extern int reattach_breakpoints (int);
+
+/* This function can be used to update the breakpoint package's state
+ after an exec() system call has been executed.
+
+ This function causes the following:
+
+ - All eventpoints are marked "not inserted".
+ - All eventpoints with a symbolic address are reset such that
+ the symbolic address must be reevaluated before the eventpoints
+ can be reinserted.
+ - The solib breakpoints are explicitly removed from the breakpoint
+ list.
+ - A step-resume breakpoint, if any, is explicitly removed from the
+ breakpoint list.
+ - All eventpoints without a symbolic address are removed from the
+ breakpoint list. */
+extern void update_breakpoints_after_exec (void);
+
+/* This function can be used to physically remove hardware breakpoints
+ and watchpoints from the specified traced inferior process, without
+ modifying the breakpoint package's state. This can be useful for
+ those targets which support following the processes of a fork() or
+ vfork() system call, when one of the resulting two processes is to
+ be detached and allowed to run free.
+
+ It is an error to use this function on the process whose id is
+ inferior_ptid. */
+extern int detach_breakpoints (int);
+
+extern void enable_longjmp_breakpoint (void);
+extern void disable_longjmp_breakpoint (void);
+extern void enable_overlay_breakpoints (void);
+extern void disable_overlay_breakpoints (void);
+
+extern void set_longjmp_resume_breakpoint (CORE_ADDR, struct frame_id);
+/* These functions respectively disable or reenable all currently
+ enabled watchpoints. When disabled, the watchpoints are marked
+ call_disabled. When reenabled, they are marked enabled.
+
+ The intended client of these functions is call_function_by_hand.
+
+ The inferior must be stopped, and all breakpoints removed, when
+ these functions are used.
+
+ The need for these functions is that on some targets (e.g., HP-UX),
+ gdb is unable to unwind through the dummy frame that is pushed as
+ part of the implementation of a call command. Watchpoints can
+ cause the inferior to stop in places where this frame is visible,
+ and that can cause execution control to become very confused.
+
+ Note that if a user sets breakpoints in an interactively called
+ function, the call_disabled watchpoints will have been reenabled
+ when the first such breakpoint is reached. However, on targets
+ that are unable to unwind through the call dummy frame, watches
+ of stack-based storage may then be deleted, because gdb will
+ believe that their watched storage is out of scope. (Sigh.) */
+extern void disable_watchpoints_before_interactive_call_start (void);
+
+extern void enable_watchpoints_after_interactive_call_stop (void);
+
+
+extern void clear_breakpoint_hit_counts (void);
+
+extern int get_number (char **);
+
+extern int get_number_or_range (char **);
+
+/* 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 (void);
+
+extern void do_displays (void);
+
+extern void disable_display (int);
+
+extern void clear_displays (void);
+
+extern void disable_breakpoint (struct breakpoint *);
+
+extern void enable_breakpoint (struct breakpoint *);
+
+extern void make_breakpoint_permanent (struct breakpoint *);
+
+extern struct breakpoint *create_solib_event_breakpoint (CORE_ADDR);
+
+extern struct breakpoint *create_thread_event_breakpoint (CORE_ADDR);
+
+extern void remove_solib_event_breakpoints (void);
+
+extern void remove_thread_event_breakpoints (void);
+
+extern void disable_breakpoints_in_shlibs (int silent);
+
+extern void re_enable_breakpoints_in_shlibs (void);
+
+extern void create_solib_load_event_breakpoint (char *, int, char *, char *);
+
+extern void create_solib_unload_event_breakpoint (char *, int,
+ char *, char *);
+
+extern void create_fork_event_catchpoint (int, char *);
+
+extern void create_vfork_event_catchpoint (int, char *);
+
+extern void create_exec_event_catchpoint (int, char *);
+
+/* This function returns TRUE if ep is a catchpoint. */
+extern int ep_is_catchpoint (struct breakpoint *);
+
+/* This function returns TRUE if ep is a catchpoint of a
+ shared library (aka dynamically-linked library) event,
+ such as a library load or unload. */
+extern int ep_is_shlib_catchpoint (struct breakpoint *);
+
+extern struct breakpoint *set_breakpoint_sal (struct symtab_and_line);
+
+/* Enable breakpoints and delete when hit. Called with ARG == NULL
+ deletes all breakpoints. */
+extern void delete_command (char *arg, int from_tty);
+
+/* Pull all H/W watchpoints from the target. Return non-zero if the
+ remove fails. */
+extern int remove_hw_watchpoints (void);
+
+#endif /* !defined (BREAKPOINT_H) */
diff --git a/contrib/gdb/gdb/buildsym.c b/contrib/gdb/gdb/buildsym.c
new file mode 100644
index 0000000..4b362e0
--- /dev/null
+++ b/contrib/gdb/gdb/buildsym.c
@@ -0,0 +1,1151 @@
+/* Support routines for building symbol tables in GDB's internal format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_obstack.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "gdb_assert.h"
+#include "complaints.h"
+#include "gdb_string.h"
+#include "expression.h" /* For "enum exp_opcode" used by... */
+#include "language.h" /* For "local_hex_string" */
+#include "bcache.h"
+#include "filenames.h" /* For DOSish file names */
+#include "macrotab.h"
+#include "demangle.h" /* Needed by SYMBOL_INIT_DEMANGLED_NAME. */
+#include "block.h"
+#include "cp-support.h"
+#include "dictionary.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"
+
+/* List of free `struct pending' structures for reuse. */
+
+static struct pending *free_pendings;
+
+/* Non-zero if symtab has line number info. This prevents an
+ otherwise empty symtab from being tossed. */
+
+static int have_line_numbers;
+
+static int compare_line_numbers (const void *ln1p, const void *ln2p);
+
+
+/* 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
+
+
+/* maintain the lists of symbols and blocks */
+
+/* Add a pending list to free_pendings. */
+void
+add_free_pendings (struct pending *list)
+{
+ struct pending *link = list;
+
+ if (list)
+ {
+ while (link->next) link = link->next;
+ link->next = free_pendings;
+ free_pendings = list;
+ }
+}
+
+/* Add a symbol to one of the lists of symbols. While we're at it, if
+ we're in the C++ case and don't have full namespace debugging info,
+ check to see if it references an anonymous namespace; if so, add an
+ appropriate using directive. */
+
+void
+add_symbol_to_list (struct symbol *symbol, struct pending **listhead)
+{
+ struct pending *link;
+
+ /* If this is an alias for another symbol, don't add it. */
+ if (symbol->ginfo.name && symbol->ginfo.name[0] == '#')
+ return;
+
+ /* 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;
+
+ /* Check to see if we might need to look for a mention of anonymous
+ namespaces. */
+
+ if (SYMBOL_LANGUAGE (symbol) == language_cplus)
+ cp_scan_for_anonymous_namespaces (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 (struct pending *list, char *name, int length)
+{
+ int j;
+ char *pp;
+
+ while (list != NULL)
+ {
+ for (j = list->nsyms; --j >= 0;)
+ {
+ pp = DEPRECATED_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. */
+
+void
+really_free_pendings (void *dummy)
+{
+ struct pending *next, *next1;
+
+ for (next = free_pendings; next; next = next1)
+ {
+ next1 = next->next;
+ xfree ((void *) next);
+ }
+ free_pendings = NULL;
+
+ free_pending_blocks ();
+
+ for (next = file_symbols; next != NULL; next = next1)
+ {
+ next1 = next->next;
+ xfree ((void *) next);
+ }
+ file_symbols = NULL;
+
+ for (next = global_symbols; next != NULL; next = next1)
+ {
+ next1 = next->next;
+ xfree ((void *) next);
+ }
+ global_symbols = NULL;
+
+ if (pending_macros)
+ free_macro_table (pending_macros);
+}
+
+/* This function is called to discard any pending blocks. */
+
+void
+free_pending_blocks (void)
+{
+#if 0 /* Now we make the links in the
+ objfile_obstack, so don't free
+ them. */
+ struct pending_block *bnext, *bnext1;
+
+ for (bnext = pending_blocks; bnext; bnext = bnext1)
+ {
+ bnext1 = bnext->next;
+ xfree ((void *) bnext);
+ }
+#endif
+ pending_blocks = NULL;
+}
+
+/* Take one of the lists of symbols and make a block from it. Keep
+ the order the symbols have in the list (reversed from the input
+ file). Put the block on the list of pending blocks. */
+
+void
+finish_block (struct symbol *symbol, struct pending **listhead,
+ struct pending_block *old_blocks,
+ CORE_ADDR start, CORE_ADDR end,
+ struct objfile *objfile)
+{
+ struct pending *next, *next1;
+ struct block *block;
+ struct pending_block *pblock;
+ struct pending_block *opblock;
+
+ block = allocate_block (&objfile->objfile_obstack);
+
+ if (symbol)
+ {
+ BLOCK_DICT (block) = dict_create_linear (&objfile->objfile_obstack,
+ *listhead);
+ }
+ else
+ {
+ BLOCK_DICT (block) = dict_create_hashed (&objfile->objfile_obstack,
+ *listhead);
+ }
+
+ BLOCK_START (block) = start;
+ BLOCK_END (block) = end;
+ /* Superblock filled in when containing block is made */
+ BLOCK_SUPERBLOCK (block) = NULL;
+ BLOCK_NAMESPACE (block) = NULL;
+
+ 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);
+ struct dict_iterator iter;
+ 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;
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_BASEREG_ARG:
+ case LOC_LOCAL_ARG:
+ case LOC_COMPUTED_ARG:
+ nparams++;
+ break;
+ case LOC_UNDEF:
+ case LOC_CONST:
+ case LOC_STATIC:
+ case LOC_INDIRECT:
+ case LOC_REGISTER:
+ case LOC_LOCAL:
+ case LOC_TYPEDEF:
+ case LOC_LABEL:
+ case LOC_BLOCK:
+ case LOC_CONST_BYTES:
+ case LOC_BASEREG:
+ case LOC_UNRESOLVED:
+ case LOC_OPTIMIZED_OUT:
+ case LOC_COMPUTED:
+ default:
+ break;
+ }
+ }
+ if (nparams > 0)
+ {
+ TYPE_NFIELDS (ftype) = nparams;
+ TYPE_FIELDS (ftype) = (struct field *)
+ TYPE_ALLOC (ftype, nparams * sizeof (struct field));
+
+ iparams = 0;
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ if (iparams == nparams)
+ break;
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_BASEREG_ARG:
+ case LOC_LOCAL_ARG:
+ case LOC_COMPUTED_ARG:
+ TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym);
+ TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0;
+ iparams++;
+ break;
+ case LOC_UNDEF:
+ case LOC_CONST:
+ case LOC_STATIC:
+ case LOC_INDIRECT:
+ case LOC_REGISTER:
+ case LOC_LOCAL:
+ case LOC_TYPEDEF:
+ case LOC_LABEL:
+ case LOC_BLOCK:
+ case LOC_CONST_BYTES:
+ case LOC_BASEREG:
+ case LOC_UNRESOLVED:
+ case LOC_OPTIMIZED_OUT:
+ case LOC_COMPUTED:
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /* If we're in the C++ case, set the block's scope. */
+ if (SYMBOL_LANGUAGE (symbol) == language_cplus)
+ {
+ cp_set_block_scope (symbol, block, &objfile->objfile_obstack);
+ }
+ }
+ 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;
+
+#if 1
+ /* Check to be sure that the blocks have an end address that is
+ greater than starting address */
+
+ if (BLOCK_END (block) < BLOCK_START (block))
+ {
+ if (symbol)
+ {
+ complaint (&symfile_complaints,
+ "block end address less than block start address in %s (patched it)",
+ SYMBOL_PRINT_NAME (symbol));
+ }
+ else
+ {
+ complaint (&symfile_complaints,
+ "block end address 0x%s less than block start address 0x%s (patched it)",
+ paddr_nz (BLOCK_END (block)), paddr_nz (BLOCK_START (block)));
+ }
+ /* Better than nothing */
+ BLOCK_END (block) = BLOCK_START (block);
+ }
+#endif
+
+ /* 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 && 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)
+ {
+ complaint (&symfile_complaints,
+ "inner block not inside outer block in %s",
+ SYMBOL_PRINT_NAME (symbol));
+ }
+ else
+ {
+ complaint (&symfile_complaints,
+ "inner block (0x%s-0x%s) not inside outer block (0x%s-0x%s)",
+ paddr_nz (BLOCK_START (pblock->block)),
+ paddr_nz (BLOCK_END (pblock->block)),
+ paddr_nz (BLOCK_START (block)),
+ paddr_nz (BLOCK_END (block)));
+ }
+ if (BLOCK_START (pblock->block) < BLOCK_START (block))
+ BLOCK_START (pblock->block) = BLOCK_START (block);
+ if (BLOCK_END (pblock->block) > BLOCK_END (block))
+ BLOCK_END (pblock->block) = BLOCK_END (block);
+ }
+#endif
+ BLOCK_SUPERBLOCK (pblock->block) = block;
+ }
+ opblock = pblock;
+ }
+
+ record_pending_block (objfile, block, opblock);
+}
+
+
+/* Record BLOCK on the list of all blocks in the file. Put it after
+ OPBLOCK, or at the beginning if opblock is NULL. This puts the
+ block in the list after all its subblocks.
+
+ Allocate the pending block struct in the objfile_obstack to save
+ time. This wastes a little space. FIXME: Is it worth it? */
+
+void
+record_pending_block (struct objfile *objfile, struct block *block,
+ struct pending_block *opblock)
+{
+ struct pending_block *pblock;
+
+ pblock = (struct pending_block *)
+ obstack_alloc (&objfile->objfile_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 (struct objfile *objfile)
+{
+ struct pending_block *next;
+ struct blockvector *blockvector;
+ 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->objfile_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;
+ xfree (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)))
+ {
+ CORE_ADDR start
+ = BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i));
+
+ complaint (&symfile_complaints, "block at %s out of order",
+ local_hex_string ((LONGEST) start));
+ }
+ }
+ }
+#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 (char *name, char *dirname)
+{
+ 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 (FILENAME_CMP (subfile->name, name) == 0)
+ {
+ 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));
+ memset ((char *) subfile, 0, 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;
+ }
+
+ /* Initialize the debug format string to NULL. We may supply it
+ later via a call to record_debugformat. */
+ subfile->debugformat = NULL;
+
+ /* 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. */
+ /* 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 (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 (void)
+{
+ 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)
+ {
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ tem->name = current_subfile->name;
+}
+
+char *
+pop_subfile (void)
+{
+ char *name;
+ struct subfile_stack *link = subfile_stack;
+
+ if (link == NULL)
+ {
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ name = link->name;
+ subfile_stack = link->next;
+ xfree ((void *) link);
+ return (name);
+}
+
+/* Add a linetable entry for line number LINE and address PC to the
+ line vector for SUBFILE. */
+
+void
+record_line (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;
+ have_line_numbers = 1;
+ }
+
+ 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 = ADDR_BITS_REMOVE(pc);
+}
+
+/* Needed in order to sort line tables from IBM xcoff files. Sigh! */
+
+static int
+compare_line_numbers (const void *ln1p, const void *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 (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;
+ have_line_numbers = 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;
+
+ /* Set up support for C++ namespace support, in case we need it. */
+
+ cp_initialize_namespace ();
+
+ /* Initialize the list of sub source files with one entry for this
+ file (the top-level source file). */
+
+ 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 (CORE_ADDR end_addr, struct objfile *objfile, int section)
+{
+ struct symtab *symtab = NULL;
+ struct blockvector *blockvector;
+ struct subfile *subfile;
+ struct context_stack *cstk;
+ struct subfile *nextsub;
+
+ /* Finish the lexical context of the last function in the file; pop
+ the context stack. */
+
+ if (context_stack_depth > 0)
+ {
+ cstk = pop_context ();
+ /* Make a block for the local symbols within. */
+ finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ cstk->start_addr, end_addr, objfile);
+
+ 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(). */
+ complaint (&symfile_complaints,
+ "Context stack not empty in end_symtab");
+ 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 merge sort!!! */
+ 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
+ && have_line_numbers == 0
+ && pending_macros == 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);
+ cp_finalize_namespace (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK),
+ &objfile->objfile_obstack);
+ }
+
+#ifndef PROCESS_LINENUMBER_HOOK
+#define PROCESS_LINENUMBER_HOOK()
+#endif
+ PROCESS_LINENUMBER_HOOK (); /* Needed for xcoff. */
+
+ /* 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;
+ symtab = NULL;
+
+ /* If we have blocks of symbols, make a symtab. Otherwise, just
+ ignore this file and any line number info in it. */
+ 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;
+ symtab->macro_table = pending_macros;
+ if (subfile->line_vector)
+ {
+ /* Reallocate the line table on the symbol obstack */
+ symtab->linetable = (struct linetable *)
+ obstack_alloc (&objfile->objfile_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->objfile_obstack,
+ strlen (subfile->dirname) + 1);
+ strcpy (symtab->dirname, subfile->dirname);
+ }
+ else
+ {
+ symtab->dirname = NULL;
+ }
+ symtab->free_code = free_linetable;
+ symtab->free_func = 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;
+
+ /* Save the debug format string (if any) in the symtab */
+ if (subfile->debugformat != NULL)
+ {
+ symtab->debugformat = obsavestring (subfile->debugformat,
+ strlen (subfile->debugformat),
+ &objfile->objfile_obstack);
+ }
+
+ /* 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)
+ {
+ xfree ((void *) subfile->name);
+ }
+ if (subfile->dirname != NULL)
+ {
+ xfree ((void *) subfile->dirname);
+ }
+ if (subfile->line_vector != NULL)
+ {
+ xfree ((void *) subfile->line_vector);
+ }
+ if (subfile->debugformat != NULL)
+ {
+ xfree ((void *) subfile->debugformat);
+ }
+
+ nextsub = subfile->next;
+ xfree ((void *) subfile);
+ }
+
+ /* Set this for the main source file. */
+ if (symtab)
+ {
+ symtab->primary = 1;
+ }
+
+ last_source_file = NULL;
+ current_subfile = NULL;
+ pending_macros = 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 (int desc, CORE_ADDR valu)
+{
+ 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->params = param_symbols;
+ new->old_blocks = pending_blocks;
+ new->start_addr = valu;
+ new->name = NULL;
+
+ local_symbols = NULL;
+ param_symbols = NULL;
+
+ return new;
+}
+
+/* Pop a context block. Returns the address of the context block just
+ popped. */
+
+struct context_stack *
+pop_context (void)
+{
+ gdb_assert (context_stack_depth > 0);
+ return (&context_stack[--context_stack_depth]);
+}
+
+
+
+/* Compute a small integer hash code for the given name. */
+
+int
+hashname (char *name)
+{
+ return (hash(name,strlen(name)) % HASHSIZE);
+}
+
+
+void
+record_debugformat (char *format)
+{
+ current_subfile->debugformat = savestring (format, strlen (format));
+}
+
+/* Merge the first symbol list SRCLIST into the second symbol list
+ TARGETLIST by repeated calls to add_symbol_to_list(). This
+ procedure "frees" each link of SRCLIST by adding it to the
+ free_pendings list. Caller must set SRCLIST to a null list after
+ calling this function.
+
+ Void return. */
+
+void
+merge_symbol_lists (struct pending **srclist, struct pending **targetlist)
+{
+ int i;
+
+ if (!srclist || !*srclist)
+ return;
+
+ /* Merge in elements from current link. */
+ for (i = 0; i < (*srclist)->nsyms; i++)
+ add_symbol_to_list ((*srclist)->symbol[i], targetlist);
+
+ /* Recurse on next. */
+ merge_symbol_lists (&(*srclist)->next, targetlist);
+
+ /* "Free" the current link. */
+ (*srclist)->next = free_pendings;
+ free_pendings = (*srclist);
+}
+
+/* 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 (void)
+{
+ free_pendings = NULL;
+ file_symbols = NULL;
+ global_symbols = NULL;
+ pending_blocks = NULL;
+ pending_macros = 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 (void)
+{
+ buildsym_init ();
+}
diff --git a/contrib/gdb/gdb/buildsym.h b/contrib/gdb/gdb/buildsym.h
new file mode 100644
index 0000000..e80d8c6
--- /dev/null
+++ b/contrib/gdb/gdb/buildsym.h
@@ -0,0 +1,293 @@
+/* Build symbol tables in GDB's internal format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+struct objfile;
+struct symbol;
+
+/* 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. */
+
+struct block;
+
+#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;
+ char *debugformat;
+ };
+
+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];
+ };
+
+/* Here are the three lists that symbols are put on. */
+
+/* static at top level, and types */
+
+EXTERN struct pending *file_symbols;
+
+/* global functions and variables */
+
+EXTERN struct pending *global_symbols;
+
+/* everything local to lexical context */
+
+EXTERN struct pending *local_symbols;
+
+/* func params local to lexical context */
+
+EXTERN struct pending *param_symbols;
+
+/* Stack representing unclosed lexical contexts (that will become
+ blocks, eventually). */
+
+struct context_stack
+ {
+ /* Outer locals at the time we entered */
+
+ struct pending *locals;
+
+ /* Pending func params at the time we entered */
+
+ struct pending *params;
+
+ /* 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;
+
+/* Non-zero if the context stack is empty. */
+#define outermost_context_p() (context_stack_depth == 0)
+
+/* 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;
+ };
+
+/* Pointer to the head of a linked list of symbol blocks which have
+ already been finalized (lexical contexts already closed) and which
+ are just waiting to be built into a blockvector when finalizing the
+ associated symtab. */
+
+EXTERN struct pending_block *pending_blocks;
+
+
+struct subfile_stack
+ {
+ 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) (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_free_pendings (struct pending *list);
+
+extern void add_symbol_to_list (struct symbol *symbol,
+ struct pending **listhead);
+
+extern struct symbol *find_symbol_in_list (struct pending *list,
+ char *name, int length);
+
+extern void finish_block (struct symbol *symbol,
+ struct pending **listhead,
+ struct pending_block *old_blocks,
+ CORE_ADDR start, CORE_ADDR end,
+ struct objfile *objfile);
+
+extern void really_free_pendings (void *dummy);
+
+extern void start_subfile (char *name, char *dirname);
+
+extern void patch_subfile_names (struct subfile *subfile, char *name);
+
+extern void push_subfile (void);
+
+extern char *pop_subfile (void);
+
+extern struct symtab *end_symtab (CORE_ADDR end_addr,
+ struct objfile *objfile, int section);
+
+/* Defined in stabsread.c. */
+
+extern void scan_file_globals (struct objfile *objfile);
+
+extern void buildsym_new_init (void);
+
+extern void buildsym_init (void);
+
+extern struct context_stack *push_context (int desc, CORE_ADDR valu);
+
+extern struct context_stack *pop_context (void);
+
+extern void record_line (struct subfile *subfile, int line, CORE_ADDR pc);
+
+extern void start_symtab (char *name, char *dirname, CORE_ADDR start_addr);
+
+extern int hashname (char *name);
+
+extern void free_pending_blocks (void);
+
+/* FIXME: Note that this is used only in buildsym.c and dstread.c,
+ which should be fixed to not need direct access to
+ record_pending_block. */
+
+extern void record_pending_block (struct objfile *objfile,
+ struct block *block,
+ struct pending_block *opblock);
+
+extern void record_debugformat (char *format);
+
+extern void merge_symbol_lists (struct pending **srclist,
+ struct pending **targetlist);
+
+/* The macro table for the compilation unit whose symbols we're
+ currently reading. All the symtabs for this CU will point to this. */
+EXTERN struct macro_table *pending_macros;
+
+#undef EXTERN
+
+#endif /* defined (BUILDSYM_H) */
diff --git a/contrib/gdb/gdb/c-exp.c b/contrib/gdb/gdb/c-exp.c
new file mode 100644
index 0000000..7ee5a45
--- /dev/null
+++ b/contrib/gdb/gdb/c-exp.c
@@ -0,0 +1,3443 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ FLOAT = 259,
+ STRING = 260,
+ NAME = 261,
+ TYPENAME = 262,
+ NAME_OR_INT = 263,
+ STRUCT = 264,
+ CLASS = 265,
+ UNION = 266,
+ ENUM = 267,
+ SIZEOF = 268,
+ UNSIGNED = 269,
+ COLONCOLON = 270,
+ TEMPLATE = 271,
+ ERROR = 272,
+ SIGNED_KEYWORD = 273,
+ LONG = 274,
+ SHORT = 275,
+ INT_KEYWORD = 276,
+ CONST_KEYWORD = 277,
+ VOLATILE_KEYWORD = 278,
+ DOUBLE_KEYWORD = 279,
+ VARIABLE = 280,
+ ASSIGN_MODIFY = 281,
+ TRUEKEYWORD = 282,
+ FALSEKEYWORD = 283,
+ ABOVE_COMMA = 284,
+ OROR = 285,
+ ANDAND = 286,
+ NOTEQUAL = 287,
+ EQUAL = 288,
+ GEQ = 289,
+ LEQ = 290,
+ RSH = 291,
+ LSH = 292,
+ DECREMENT = 293,
+ INCREMENT = 294,
+ UNARY = 295,
+ ARROW = 296,
+ BLOCKNAME = 297,
+ FILENAME = 298
+ };
+#endif
+#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 TRUEKEYWORD 282
+#define FALSEKEYWORD 283
+#define ABOVE_COMMA 284
+#define OROR 285
+#define ANDAND 286
+#define NOTEQUAL 287
+#define EQUAL 288
+#define GEQ 289
+#define LEQ 290
+#define RSH 291
+#define LSH 292
+#define DECREMENT 293
+#define INCREMENT 294
+#define UNARY 295
+#define ARROW 296
+#define BLOCKNAME 297
+#define FILENAME 298
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 39 "c-exp.y"
+
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#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 */
+#include "charset.h"
+#include "block.h"
+#include "cp-support.h"
+
+/* Flag indicating we're dealing with HP-compiled objects */
+extern int hp_som_som_object_present;
+
+/* 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 yyname c_name /* With YYDEBUG defined */
+#define yyrule c_rule /* 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 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 126 "c-exp.y"
+typedef union YYSTYPE {
+ 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 191 of yacc.c. */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+#line 150 "c-exp.y"
+
+/* YYSTYPE gets defined by %union */
+static int parse_number (char *, int, int, YYSTYPE *);
+
+
+/* Line 214 of yacc.c. */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC xmalloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 94
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 804
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 68
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 31
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 159
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 242
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 298
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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, 61, 2, 2, 2, 51, 37, 2,
+ 57, 64, 49, 47, 29, 48, 55, 50, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 67, 2,
+ 40, 31, 41, 32, 46, 2, 2, 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, 63, 36, 2, 2, 2, 2, 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, 35, 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, 30, 33, 34, 38, 39, 42,
+ 43, 44, 45, 52, 53, 54, 58, 59, 60
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 11, 15, 18, 21,
+ 24, 27, 30, 33, 36, 39, 42, 45, 49, 53,
+ 58, 62, 66, 71, 76, 77, 83, 85, 86, 88,
+ 92, 94, 98, 103, 108, 112, 116, 120, 124, 128,
+ 132, 136, 140, 144, 148, 152, 156, 160, 164, 168,
+ 172, 176, 180, 184, 188, 194, 198, 202, 204, 206,
+ 208, 210, 212, 217, 219, 221, 223, 225, 227, 231,
+ 235, 239, 244, 246, 249, 251, 254, 256, 257, 261,
+ 263, 265, 267, 268, 270, 273, 275, 278, 280, 284,
+ 287, 289, 292, 294, 297, 301, 304, 308, 310, 314,
+ 316, 318, 320, 322, 325, 329, 332, 336, 340, 344,
+ 347, 350, 354, 359, 363, 367, 372, 376, 381, 385,
+ 390, 393, 397, 400, 404, 407, 411, 413, 416, 419,
+ 422, 425, 428, 431, 433, 436, 438, 444, 447, 450,
+ 452, 456, 458, 460, 462, 464, 466, 470, 472, 477,
+ 480, 483, 485, 487, 489, 491, 493, 495, 497, 499
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 69, 0, -1, 71, -1, 70, -1, 89, -1, 72,
+ -1, 71, 29, 72, -1, 49, 72, -1, 37, 72,
+ -1, 48, 72, -1, 61, 72, -1, 62, 72, -1,
+ 53, 72, -1, 52, 72, -1, 72, 53, -1, 72,
+ 52, -1, 13, 72, -1, 72, 58, 97, -1, 72,
+ 58, 79, -1, 72, 58, 49, 72, -1, 72, 55,
+ 97, -1, 72, 55, 79, -1, 72, 55, 49, 72,
+ -1, 72, 56, 71, 63, -1, -1, 72, 57, 73,
+ 75, 64, -1, 65, -1, -1, 72, -1, 75, 29,
+ 72, -1, 66, -1, 74, 75, 76, -1, 74, 89,
+ 76, 72, -1, 57, 89, 64, 72, -1, 57, 71,
+ 64, -1, 72, 46, 72, -1, 72, 49, 72, -1,
+ 72, 50, 72, -1, 72, 51, 72, -1, 72, 47,
+ 72, -1, 72, 48, 72, -1, 72, 45, 72, -1,
+ 72, 44, 72, -1, 72, 39, 72, -1, 72, 38,
+ 72, -1, 72, 43, 72, -1, 72, 42, 72, -1,
+ 72, 40, 72, -1, 72, 41, 72, -1, 72, 37,
+ 72, -1, 72, 36, 72, -1, 72, 35, 72, -1,
+ 72, 34, 72, -1, 72, 33, 72, -1, 72, 32,
+ 72, 67, 72, -1, 72, 31, 72, -1, 72, 26,
+ 72, -1, 3, -1, 8, -1, 4, -1, 78, -1,
+ 25, -1, 13, 57, 89, 64, -1, 5, -1, 27,
+ -1, 28, -1, 59, -1, 60, -1, 77, 15, 97,
+ -1, 77, 15, 97, -1, 90, 15, 97, -1, 90,
+ 15, 62, 97, -1, 79, -1, 15, 97, -1, 98,
+ -1, 46, 6, -1, 96, -1, -1, 81, 80, 81,
+ -1, 82, -1, 96, -1, 83, -1, -1, 49, -1,
+ 49, 85, -1, 37, -1, 37, 85, -1, 86, -1,
+ 57, 85, 64, -1, 86, 87, -1, 87, -1, 86,
+ 88, -1, 88, -1, 56, 63, -1, 56, 3, 63,
+ -1, 57, 64, -1, 57, 93, 64, -1, 94, -1,
+ 90, 15, 49, -1, 7, -1, 21, -1, 19, -1,
+ 20, -1, 19, 21, -1, 19, 18, 21, -1, 19,
+ 18, -1, 18, 19, 21, -1, 14, 19, 21, -1,
+ 19, 14, 21, -1, 19, 14, -1, 19, 19, -1,
+ 19, 19, 21, -1, 19, 19, 18, 21, -1, 19,
+ 19, 18, -1, 18, 19, 19, -1, 18, 19, 19,
+ 21, -1, 14, 19, 19, -1, 14, 19, 19, 21,
+ -1, 19, 19, 14, -1, 19, 19, 14, 21, -1,
+ 20, 21, -1, 20, 18, 21, -1, 20, 18, -1,
+ 14, 20, 21, -1, 20, 14, -1, 20, 14, 21,
+ -1, 24, -1, 19, 24, -1, 9, 97, -1, 10,
+ 97, -1, 11, 97, -1, 12, 97, -1, 14, 92,
+ -1, 14, -1, 18, 92, -1, 18, -1, 16, 97,
+ 40, 89, 41, -1, 83, 90, -1, 90, 83, -1,
+ 91, -1, 90, 15, 97, -1, 7, -1, 21, -1,
+ 19, -1, 20, -1, 89, -1, 93, 29, 89, -1,
+ 90, -1, 94, 84, 85, 84, -1, 22, 23, -1,
+ 23, 22, -1, 95, -1, 22, -1, 23, -1, 6,
+ -1, 59, -1, 7, -1, 8, -1, 6, -1, 59,
+ -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 233, 233, 234, 237, 244, 245, 250, 254, 258,
+ 262, 266, 270, 274, 278, 282, 286, 290, 296, 304,
+ 308, 314, 322, 326, 333, 330, 340, 344, 347, 351,
+ 355, 358, 365, 371, 377, 383, 387, 391, 395, 399,
+ 403, 407, 411, 415, 419, 423, 427, 431, 435, 439,
+ 443, 447, 451, 455, 459, 463, 467, 473, 480, 491,
+ 498, 501, 505, 513, 538, 545, 554, 562, 568, 579,
+ 595, 609, 634, 635, 669, 726, 732, 733, 736, 739,
+ 740, 744, 745, 748, 750, 752, 754, 756, 759, 761,
+ 766, 773, 775, 779, 781, 785, 787, 799, 800, 805,
+ 807, 809, 811, 813, 815, 817, 819, 821, 823, 825,
+ 827, 829, 831, 833, 835, 837, 839, 841, 843, 845,
+ 847, 849, 851, 853, 855, 857, 859, 861, 863, 866,
+ 869, 872, 875, 877, 879, 881, 886, 890, 892, 894,
+ 942, 967, 968, 974, 980, 989, 994, 1001, 1002, 1006,
+ 1007, 1010, 1014, 1016, 1020, 1021, 1022, 1023, 1026, 1027
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INT", "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", "TRUEKEYWORD",
+ "FALSEKEYWORD", "','", "ABOVE_COMMA", "'='", "'?'", "OROR", "ANDAND",
+ "'|'", "'^'", "'&'", "NOTEQUAL", "EQUAL", "'<'", "'>'", "GEQ", "LEQ",
+ "RSH", "LSH", "'@'", "'+'", "'-'", "'*'", "'/'", "'%'", "DECREMENT",
+ "INCREMENT", "UNARY", "'.'", "'['", "'('", "ARROW", "BLOCKNAME",
+ "FILENAME", "'!'", "'~'", "']'", "')'", "'{'", "'}'", "':'", "$accept",
+ "start", "type_exp", "exp1", "exp", "@1", "lcurly", "arglist", "rcurly",
+ "block", "variable", "qualified_name", "space_identifier",
+ "const_or_volatile", "cv_with_space_id",
+ "const_or_volatile_or_space_identifier_noopt",
+ "const_or_volatile_or_space_identifier", "abs_decl", "direct_abs_decl",
+ "array_mod", "func_mod", "type", "typebase", "qualified_type",
+ "typename", "nonempty_typelist", "ptype", "const_and_volatile",
+ "const_or_volatile_noopt", "name", "name_not_typename", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 44,
+ 284, 61, 63, 285, 286, 124, 94, 38, 287, 288,
+ 60, 62, 289, 290, 291, 292, 64, 43, 45, 42,
+ 47, 37, 293, 294, 295, 46, 91, 40, 296, 297,
+ 298, 33, 126, 93, 41, 123, 125, 58
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 68, 69, 69, 70, 71, 71, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 73, 72, 74, 75, 75, 75,
+ 76, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 77, 77, 77, 78,
+ 79, 79, 78, 78, 78, 80, 81, 81, 82, 83,
+ 83, 84, 84, 85, 85, 85, 85, 85, 86, 86,
+ 86, 86, 86, 87, 87, 88, 88, 89, 89, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 91, 92, 92, 92, 92, 93, 93, 94, 94, 95,
+ 95, 96, 96, 96, 97, 97, 97, 97, 98, 98
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 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, 1, 1, 3, 3,
+ 3, 4, 1, 2, 1, 2, 1, 0, 3, 1,
+ 1, 1, 0, 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, 3, 2,
+ 2, 3, 4, 3, 3, 4, 3, 4, 3, 4,
+ 2, 3, 2, 3, 2, 3, 1, 2, 2, 2,
+ 2, 2, 2, 1, 2, 1, 5, 2, 2, 1,
+ 3, 1, 1, 1, 1, 1, 3, 1, 4, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 77, 57, 59, 63, 158, 99, 58, 0, 0, 0,
+ 0, 77, 133, 0, 0, 135, 101, 102, 100, 152,
+ 153, 126, 61, 64, 65, 77, 77, 77, 77, 77,
+ 77, 159, 67, 77, 77, 26, 0, 3, 2, 5,
+ 27, 0, 60, 72, 0, 79, 77, 4, 147, 139,
+ 97, 151, 80, 74, 154, 156, 157, 155, 128, 129,
+ 130, 131, 77, 16, 77, 141, 143, 144, 142, 132,
+ 73, 0, 143, 144, 134, 109, 105, 110, 103, 127,
+ 124, 122, 120, 149, 150, 8, 9, 7, 13, 12,
+ 0, 0, 10, 11, 1, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 15, 14,
+ 77, 77, 24, 77, 28, 0, 0, 0, 0, 77,
+ 137, 0, 138, 81, 0, 0, 0, 116, 107, 123,
+ 77, 114, 106, 108, 104, 118, 113, 111, 125, 121,
+ 34, 77, 6, 56, 55, 0, 53, 52, 51, 50,
+ 49, 44, 43, 47, 48, 46, 45, 42, 41, 35,
+ 39, 40, 36, 37, 38, 156, 77, 21, 20, 0,
+ 27, 77, 18, 17, 77, 30, 31, 77, 69, 75,
+ 78, 76, 0, 98, 0, 70, 85, 83, 0, 77,
+ 82, 87, 90, 92, 62, 117, 0, 147, 115, 119,
+ 112, 33, 77, 22, 23, 0, 19, 29, 32, 140,
+ 71, 86, 84, 0, 93, 95, 0, 145, 0, 148,
+ 77, 89, 91, 136, 0, 54, 25, 94, 88, 77,
+ 96, 146
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short yydefgoto[] =
+{
+ -1, 36, 37, 90, 39, 180, 40, 125, 186, 41,
+ 42, 43, 129, 44, 45, 46, 134, 200, 201, 202,
+ 203, 227, 64, 49, 69, 228, 50, 51, 52, 195,
+ 53
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -101
+static const short yypact[] =
+{
+ 320, -101, -101, -101, -101, -101, -101, 30, 30, 30,
+ 30, 383, 45, 30, 30, 200, 152, 36, -101, -11,
+ 17, -101, -101, -101, -101, 320, 320, 320, 320, 320,
+ 320, 29, -101, 320, 320, -101, 84, -101, 39, 597,
+ 257, 56, -101, -101, 57, -101, 172, -101, 68, -101,
+ 55, -101, 67, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, 320, 460, 87, -101, 40, 95, -101, -101,
+ -101, 99, 190, -101, -101, 156, 159, 223, -101, -101,
+ 164, 176, -101, -101, -101, 460, 460, 460, 460, 460,
+ -15, 158, 460, 460, -101, 320, 320, 320, 320, 320,
+ 320, 320, 320, 320, 320, 320, 320, 320, 320, 320,
+ 320, 320, 320, 320, 320, 320, 320, 320, -101, -101,
+ 194, 320, -101, 531, 597, -19, 160, 30, 218, -1,
+ 71, 20, -101, -101, -14, 171, 26, 215, -101, -101,
+ 172, 217, -101, -101, -101, 221, 224, -101, -101, -101,
+ -101, 320, 597, 597, 597, 560, 622, 646, 669, 691,
+ 712, 731, 731, 746, 746, 746, 746, 240, 240, 303,
+ 366, 366, 460, 460, 460, 83, 320, -101, -101, -18,
+ 257, 320, -101, -101, 320, -101, -101, 320, 231, -101,
+ -101, -101, 30, -101, 30, 210, 118, 63, 4, 472,
+ 2, 112, -101, -101, 446, -101, 206, 85, -101, -101,
+ -101, 460, 320, 460, -101, -13, 460, 597, 460, -101,
+ -101, -101, -101, 185, -101, -101, 186, -101, -9, -101,
+ 114, -101, -101, -101, 11, 526, -101, -101, -101, 172,
+ -101, -101
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const short yypgoto[] =
+{
+ -101, -101, -101, 6, 47, -101, -101, 69, 126, -101,
+ -101, -67, -101, 125, -101, -35, 58, -100, -101, 54,
+ 73, 1, 0, -101, 241, -101, -101, -101, 128, -5,
+ -101
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -141
+static const short yytable[] =
+{
+ 48, 47, 58, 59, 60, 61, 38, 223, 70, 71,
+ 184, 95, 83, 132, 95, 133, 184, 54, 55, 56,
+ 239, 19, 20, 196, 19, 20, 54, 55, 56, 132,
+ 48, 91, 54, 55, 56, 197, 54, 55, 56, 84,
+ 48, 126, 198, 199, -66, 214, 130, 185, -77, 150,
+ 80, 236, 65, 177, 81, 240, 182, 82, 63, 137,
+ 193, 138, 48, 135, 66, 67, 68, 224, 95, 193,
+ 57, 127, 85, 86, 87, 88, 89, 19, 20, 57,
+ 92, 93, 194, 131, 94, 57, 192, 124, 194, 57,
+ 19, 20, -82, 19, 20, 132, 221, 222, -99, 226,
+ 234, -77, 136, 128, -82, -99, -99, 19, 20, 19,
+ 20, -82, -82, -76, -77, 178, 139, -77, 183, 198,
+ 199, 5, 188, 7, 8, 9, 10, 179, 12, -99,
+ 14, -77, 15, 16, 17, 18, 19, 20, 21, 140,
+ 207, 206, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 133, 75, 197, 198, 230,
+ 76, 77, 132, 78, 198, 199, 79, 143, 225, 5,
+ 144, 7, 8, 9, 10, 148, 12, 219, 14, 220,
+ 15, 16, 17, 18, 19, 20, 21, 149, 211, 207,
+ 54, 175, 56, 7, 8, 9, 10, 65, 12, 141,
+ 14, 142, 15, 16, 17, 18, 19, 20, 21, 72,
+ 73, 68, 151, 213, 189, -140, 185, 124, 216, 219,
+ 207, 217, -140, -140, 218, 204, 205, 145, 208, 207,
+ 241, 146, 209, 176, 147, 210, -68, 233, 237, 215,
+ 238, 211, 187, 57, 190, 231, 74, 191, 229, 235,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 232, 15, 16, 17, 18, 19,
+ 20, 21, 22, 0, 23, 24, 112, 113, 114, 115,
+ 116, 117, 118, 119, 25, 120, 121, 122, 123, 0,
+ 0, 0, 0, -77, 0, 26, 27, 0, 0, 28,
+ 29, 0, 0, 0, 30, 0, 31, 32, 33, 34,
+ 0, 0, 35, 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, 24, 0,
+ 113, 114, 115, 116, 117, 118, 119, 25, 120, 121,
+ 122, 123, 0, 0, 0, 0, 0, 0, 26, 27,
+ 0, 0, 28, 29, 0, 0, 0, 30, 0, 31,
+ 32, 33, 34, 0, 0, 35, 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, 24, 0, 0, 0, 115, 116, 117, 118, 119,
+ 25, 120, 121, 122, 123, 0, 0, 0, 0, 0,
+ 0, 26, 27, 0, 0, 28, 29, 0, 0, 0,
+ 62, 0, 31, 32, 33, 34, 0, 0, 35, 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, 24, 0, 0, 0, 0, 5,
+ 0, 7, 8, 9, 10, 0, 12, 0, 14, 0,
+ 15, 16, 17, 18, 19, 20, 21, 0, 28, 29,
+ 0, 0, 0, 30, 0, 31, 32, 33, 34, 196,
+ 0, 35, 118, 119, 0, 120, 121, 122, 123, 0,
+ 0, 197, 0, 0, 0, 0, 0, 0, 198, 199,
+ 0, 0, 0, 0, 0, 0, 225, 54, 175, 56,
+ 7, 8, 9, 10, 0, 12, 0, 14, 0, 15,
+ 16, 17, 18, 19, 20, 21, 0, 0, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 181, 120, 121, 122, 123, 0, 96, 0, 0, 0,
+ 57, 97, 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+ 116, 117, 118, 119, 0, 120, 121, 122, 123, 0,
+ 0, 0, 0, 96, 0, 0, 0, 212, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 0, 120, 121, 122, 123, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ 114, 115, 116, 117, 118, 119, 0, 120, 121, 122,
+ 123, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 0, 120, 121, 122, 123, 102, 103, 104, 105, 106,
+ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 0, 120, 121, 122, 123, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 0, 120, 121, 122, 123,
+ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ 114, 115, 116, 117, 118, 119, 0, 120, 121, 122,
+ 123, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 0, 120, 121, 122, 123,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 0, 120, 121, 122, 123
+};
+
+static const short yycheck[] =
+{
+ 0, 0, 7, 8, 9, 10, 0, 3, 13, 14,
+ 29, 29, 23, 48, 29, 50, 29, 6, 7, 8,
+ 29, 22, 23, 37, 22, 23, 6, 7, 8, 64,
+ 30, 30, 6, 7, 8, 49, 6, 7, 8, 22,
+ 40, 40, 56, 57, 15, 63, 46, 66, 46, 64,
+ 14, 64, 7, 120, 18, 64, 123, 21, 11, 19,
+ 49, 21, 62, 62, 19, 20, 21, 63, 29, 49,
+ 59, 15, 25, 26, 27, 28, 29, 22, 23, 59,
+ 33, 34, 62, 15, 0, 59, 15, 40, 62, 59,
+ 22, 23, 37, 22, 23, 130, 196, 197, 15, 199,
+ 15, 46, 15, 46, 49, 22, 23, 22, 23, 22,
+ 23, 56, 57, 46, 46, 120, 21, 46, 123, 56,
+ 57, 7, 127, 9, 10, 11, 12, 121, 14, 46,
+ 16, 46, 18, 19, 20, 21, 22, 23, 24, 40,
+ 140, 140, 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 200, 14, 49, 56, 57,
+ 18, 19, 207, 21, 56, 57, 24, 21, 64, 7,
+ 21, 9, 10, 11, 12, 21, 14, 192, 16, 194,
+ 18, 19, 20, 21, 22, 23, 24, 21, 151, 199,
+ 6, 7, 8, 9, 10, 11, 12, 7, 14, 19,
+ 16, 21, 18, 19, 20, 21, 22, 23, 24, 19,
+ 20, 21, 64, 176, 6, 15, 66, 180, 181, 234,
+ 230, 184, 22, 23, 187, 64, 21, 14, 21, 239,
+ 239, 18, 21, 49, 21, 21, 15, 41, 63, 180,
+ 64, 204, 126, 59, 129, 201, 15, 129, 200, 212,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 201, 18, 19, 20, 21, 22,
+ 23, 24, 25, -1, 27, 28, 46, 47, 48, 49,
+ 50, 51, 52, 53, 37, 55, 56, 57, 58, -1,
+ -1, -1, -1, 46, -1, 48, 49, -1, -1, 52,
+ 53, -1, -1, -1, 57, -1, 59, 60, 61, 62,
+ -1, -1, 65, 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, 28, -1,
+ 47, 48, 49, 50, 51, 52, 53, 37, 55, 56,
+ 57, 58, -1, -1, -1, -1, -1, -1, 48, 49,
+ -1, -1, 52, 53, -1, -1, -1, 57, -1, 59,
+ 60, 61, 62, -1, -1, 65, 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, 28, -1, -1, -1, 49, 50, 51, 52, 53,
+ 37, 55, 56, 57, 58, -1, -1, -1, -1, -1,
+ -1, 48, 49, -1, -1, 52, 53, -1, -1, -1,
+ 57, -1, 59, 60, 61, 62, -1, -1, 65, 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, 28, -1, -1, -1, -1, 7,
+ -1, 9, 10, 11, 12, -1, 14, -1, 16, -1,
+ 18, 19, 20, 21, 22, 23, 24, -1, 52, 53,
+ -1, -1, -1, 57, -1, 59, 60, 61, 62, 37,
+ -1, 65, 52, 53, -1, 55, 56, 57, 58, -1,
+ -1, 49, -1, -1, -1, -1, -1, -1, 56, 57,
+ -1, -1, -1, -1, -1, -1, 64, 6, 7, 8,
+ 9, 10, 11, 12, -1, 14, -1, 16, -1, 18,
+ 19, 20, 21, 22, 23, 24, -1, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 49, 55, 56, 57, 58, -1, 26, -1, -1, -1,
+ 59, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, -1, 55, 56, 57, 58, -1,
+ -1, -1, -1, 26, -1, -1, -1, 67, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, -1, 55, 56, 57, 58, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, -1, 55, 56, 57,
+ 58, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ -1, 55, 56, 57, 58, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, -1, 55, 56, 57, 58, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, -1, 55, 56, 57, 58,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, -1, 55, 56, 57,
+ 58, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, -1, 55, 56, 57, 58,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ -1, 55, 56, 57, 58
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 18, 19, 20, 21, 22,
+ 23, 24, 25, 27, 28, 37, 48, 49, 52, 53,
+ 57, 59, 60, 61, 62, 65, 69, 70, 71, 72,
+ 74, 77, 78, 79, 81, 82, 83, 89, 90, 91,
+ 94, 95, 96, 98, 6, 7, 8, 59, 97, 97,
+ 97, 97, 57, 72, 90, 7, 19, 20, 21, 92,
+ 97, 97, 19, 20, 92, 14, 18, 19, 21, 24,
+ 14, 18, 21, 23, 22, 72, 72, 72, 72, 72,
+ 71, 89, 72, 72, 0, 29, 26, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 55, 56, 57, 58, 72, 75, 89, 15, 46, 80,
+ 90, 15, 83, 83, 84, 89, 15, 19, 21, 21,
+ 40, 19, 21, 21, 21, 14, 18, 21, 21, 21,
+ 64, 64, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 7, 49, 79, 97, 71,
+ 73, 49, 79, 97, 29, 66, 76, 76, 97, 6,
+ 81, 96, 15, 49, 62, 97, 37, 49, 56, 57,
+ 85, 86, 87, 88, 64, 21, 89, 90, 21, 21,
+ 21, 72, 67, 72, 63, 75, 72, 72, 72, 97,
+ 97, 85, 85, 3, 63, 64, 85, 89, 93, 84,
+ 57, 87, 88, 41, 15, 72, 64, 63, 64, 29,
+ 64, 89
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to xreallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to xreallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 238 "c-exp.y"
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(yyvsp[0].tval);
+ write_exp_elt_opcode(OP_TYPE);}
+ break;
+
+ case 6:
+#line 246 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ break;
+
+ case 7:
+#line 251 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_IND); }
+ break;
+
+ case 8:
+#line 255 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ break;
+
+ case 9:
+#line 259 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_NEG); }
+ break;
+
+ case 10:
+#line 263 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ break;
+
+ case 11:
+#line 267 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+ break;
+
+ case 12:
+#line 271 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ break;
+
+ case 13:
+#line 275 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ break;
+
+ case 14:
+#line 279 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+ break;
+
+ case 15:
+#line 283 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+ break;
+
+ case 16:
+#line 287 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ break;
+
+ case 17:
+#line 291 "c-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_PTR); }
+ break;
+
+ case 18:
+#line 297 "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 19:
+#line 305 "c-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_MPTR); }
+ break;
+
+ case 20:
+#line 309 "c-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ break;
+
+ case 21:
+#line 315 "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 22:
+#line 323 "c-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ break;
+
+ case 23:
+#line 327 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ break;
+
+ case 24:
+#line 333 "c-exp.y"
+ { start_arglist (); }
+ break;
+
+ case 25:
+#line 335 "c-exp.y"
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+ break;
+
+ case 26:
+#line 341 "c-exp.y"
+ { start_arglist (); }
+ break;
+
+ case 28:
+#line 348 "c-exp.y"
+ { arglist_len = 1; }
+ break;
+
+ case 29:
+#line 352 "c-exp.y"
+ { arglist_len++; }
+ break;
+
+ case 30:
+#line 356 "c-exp.y"
+ { yyval.lval = end_arglist () - 1; }
+ break;
+
+ case 31:
+#line 359 "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 32:
+#line 366 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ break;
+
+ case 33:
+#line 372 "c-exp.y"
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_CAST); }
+ break;
+
+ case 34:
+#line 378 "c-exp.y"
+ { }
+ break;
+
+ case 35:
+#line 384 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ break;
+
+ case 36:
+#line 388 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_MUL); }
+ break;
+
+ case 37:
+#line 392 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_DIV); }
+ break;
+
+ case 38:
+#line 396 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_REM); }
+ break;
+
+ case 39:
+#line 400 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_ADD); }
+ break;
+
+ case 40:
+#line 404 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_SUB); }
+ break;
+
+ case 41:
+#line 408 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_LSH); }
+ break;
+
+ case 42:
+#line 412 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_RSH); }
+ break;
+
+ case 43:
+#line 416 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ break;
+
+ case 44:
+#line 420 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 45:
+#line 424 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ break;
+
+ case 46:
+#line 428 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ break;
+
+ case 47:
+#line 432 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_LESS); }
+ break;
+
+ case 48:
+#line 436 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_GTR); }
+ break;
+
+ case 49:
+#line 440 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ break;
+
+ case 50:
+#line 444 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ break;
+
+ case 51:
+#line 448 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ break;
+
+ case 52:
+#line 452 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ break;
+
+ case 53:
+#line 456 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ break;
+
+ case 54:
+#line 460 "c-exp.y"
+ { write_exp_elt_opcode (TERNOP_COND); }
+ break;
+
+ case 55:
+#line 464 "c-exp.y"
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ break;
+
+ case 56:
+#line 468 "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 57:
+#line 474 "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 58:
+#line 481 "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 59:
+#line 492 "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 62:
+#line 506 "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 63:
+#line 514 "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 64:
+#line 539 "c-exp.y"
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_bool);
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_opcode (OP_LONG); }
+ break;
+
+ case 65:
+#line 546 "c-exp.y"
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_bool);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_opcode (OP_LONG); }
+ break;
+
+ case 66:
+#line 555 "c-exp.y"
+ {
+ if (yyvsp[0].ssym.sym)
+ yyval.bval = SYMBOL_BLOCK_VALUE (yyvsp[0].ssym.sym);
+ else
+ error ("No file or function \"%s\".",
+ copy_name (yyvsp[0].ssym.stoken));
+ }
+ break;
+
+ case 67:
+#line 563 "c-exp.y"
+ {
+ yyval.bval = yyvsp[0].bval;
+ }
+ break;
+
+ case 68:
+#line 569 "c-exp.y"
+ { struct symbol *tem
+ = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, (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 69:
+#line 580 "c-exp.y"
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, (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 70:
+#line 596 "c-exp.y"
+ {
+ struct type *type = yyvsp[-2].tval;
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
+ 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 71:
+#line 610 "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
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ 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;
+
+ /* Check for valid destructor name. */
+ destructor_name_p (tmp_token.ptr, type);
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (type);
+ write_exp_string (tmp_token);
+ write_exp_elt_opcode (OP_SCOPE);
+ }
+ break;
+
+ case 73:
+#line 636 "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_DOMAIN, (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 74:
+#line 670 "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;
+ 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 727 "c-exp.y"
+ { push_type_address_space (copy_name (yyvsp[0].ssym.stoken));
+ push_type (tp_space_identifier);
+ }
+ break;
+
+ case 83:
+#line 749 "c-exp.y"
+ { push_type (tp_pointer); yyval.voidval = 0; }
+ break;
+
+ case 84:
+#line 751 "c-exp.y"
+ { push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; }
+ break;
+
+ case 85:
+#line 753 "c-exp.y"
+ { push_type (tp_reference); yyval.voidval = 0; }
+ break;
+
+ case 86:
+#line 755 "c-exp.y"
+ { push_type (tp_reference); yyval.voidval = yyvsp[0].voidval; }
+ break;
+
+ case 88:
+#line 760 "c-exp.y"
+ { yyval.voidval = yyvsp[-1].voidval; }
+ break;
+
+ case 89:
+#line 762 "c-exp.y"
+ {
+ push_type_int (yyvsp[0].lval);
+ push_type (tp_array);
+ }
+ break;
+
+ case 90:
+#line 767 "c-exp.y"
+ {
+ push_type_int (yyvsp[0].lval);
+ push_type (tp_array);
+ yyval.voidval = 0;
+ }
+ break;
+
+ case 91:
+#line 774 "c-exp.y"
+ { push_type (tp_function); }
+ break;
+
+ case 92:
+#line 776 "c-exp.y"
+ { push_type (tp_function); }
+ break;
+
+ case 93:
+#line 780 "c-exp.y"
+ { yyval.lval = -1; }
+ break;
+
+ case 94:
+#line 782 "c-exp.y"
+ { yyval.lval = yyvsp[-1].typed_val_int.val; }
+ break;
+
+ case 95:
+#line 786 "c-exp.y"
+ { yyval.voidval = 0; }
+ break;
+
+ case 96:
+#line 788 "c-exp.y"
+ { free (yyvsp[-1].tvec); yyval.voidval = 0; }
+ break;
+
+ case 98:
+#line 801 "c-exp.y"
+ { yyval.tval = lookup_member_type (builtin_type_int, yyvsp[-2].tval); }
+ break;
+
+ case 99:
+#line 806 "c-exp.y"
+ { yyval.tval = yyvsp[0].tsym.type; }
+ break;
+
+ case 100:
+#line 808 "c-exp.y"
+ { yyval.tval = builtin_type_int; }
+ break;
+
+ case 101:
+#line 810 "c-exp.y"
+ { yyval.tval = builtin_type_long; }
+ break;
+
+ case 102:
+#line 812 "c-exp.y"
+ { yyval.tval = builtin_type_short; }
+ break;
+
+ case 103:
+#line 814 "c-exp.y"
+ { yyval.tval = builtin_type_long; }
+ break;
+
+ case 104:
+#line 816 "c-exp.y"
+ { yyval.tval = builtin_type_long; }
+ break;
+
+ case 105:
+#line 818 "c-exp.y"
+ { yyval.tval = builtin_type_long; }
+ break;
+
+ case 106:
+#line 820 "c-exp.y"
+ { yyval.tval = builtin_type_long; }
+ break;
+
+ case 107:
+#line 822 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_long; }
+ break;
+
+ case 108:
+#line 824 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_long; }
+ break;
+
+ case 109:
+#line 826 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_long; }
+ break;
+
+ case 110:
+#line 828 "c-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 111:
+#line 830 "c-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 112:
+#line 832 "c-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 113:
+#line 834 "c-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 114:
+#line 836 "c-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 115:
+#line 838 "c-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 116:
+#line 840 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_long_long; }
+ break;
+
+ case 117:
+#line 842 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_long_long; }
+ break;
+
+ case 118:
+#line 844 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_long_long; }
+ break;
+
+ case 119:
+#line 846 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_long_long; }
+ break;
+
+ case 120:
+#line 848 "c-exp.y"
+ { yyval.tval = builtin_type_short; }
+ break;
+
+ case 121:
+#line 850 "c-exp.y"
+ { yyval.tval = builtin_type_short; }
+ break;
+
+ case 122:
+#line 852 "c-exp.y"
+ { yyval.tval = builtin_type_short; }
+ break;
+
+ case 123:
+#line 854 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_short; }
+ break;
+
+ case 124:
+#line 856 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_short; }
+ break;
+
+ case 125:
+#line 858 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_short; }
+ break;
+
+ case 126:
+#line 860 "c-exp.y"
+ { yyval.tval = builtin_type_double; }
+ break;
+
+ case 127:
+#line 862 "c-exp.y"
+ { yyval.tval = builtin_type_long_double; }
+ break;
+
+ case 128:
+#line 864 "c-exp.y"
+ { yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 129:
+#line 867 "c-exp.y"
+ { yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 130:
+#line 870 "c-exp.y"
+ { yyval.tval = lookup_union (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 131:
+#line 873 "c-exp.y"
+ { yyval.tval = lookup_enum (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 132:
+#line 876 "c-exp.y"
+ { yyval.tval = lookup_unsigned_typename (TYPE_NAME(yyvsp[0].tsym.type)); }
+ break;
+
+ case 133:
+#line 878 "c-exp.y"
+ { yyval.tval = builtin_type_unsigned_int; }
+ break;
+
+ case 134:
+#line 880 "c-exp.y"
+ { yyval.tval = lookup_signed_typename (TYPE_NAME(yyvsp[0].tsym.type)); }
+ break;
+
+ case 135:
+#line 882 "c-exp.y"
+ { yyval.tval = builtin_type_int; }
+ break;
+
+ case 136:
+#line 887 "c-exp.y"
+ { yyval.tval = lookup_template_type(copy_name(yyvsp[-3].sval), yyvsp[-1].tval,
+ expression_context_block);
+ }
+ break;
+
+ case 137:
+#line 891 "c-exp.y"
+ { yyval.tval = follow_types (yyvsp[0].tval); }
+ break;
+
+ case 138:
+#line 893 "c-exp.y"
+ { yyval.tval = follow_types (yyvsp[-1].tval); }
+ break;
+
+ case 140:
+#line 943 "c-exp.y"
+ {
+ struct type *type = yyvsp[-2].tval;
+ struct type *new_type;
+ char *ncopy = alloca (yyvsp[0].sval.length + 1);
+
+ memcpy (ncopy, yyvsp[0].sval.ptr, yyvsp[0].sval.length);
+ ncopy[yyvsp[0].sval.length] = '\0';
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ new_type = cp_lookup_nested_type (type, ncopy,
+ expression_context_block);
+ if (new_type == NULL)
+ error ("No type \"%s\" within class or namespace \"%s\".",
+ ncopy, TYPE_NAME (type));
+
+ yyval.tval = new_type;
+ }
+ break;
+
+ case 142:
+#line 969 "c-exp.y"
+ {
+ yyval.tsym.stoken.ptr = "int";
+ yyval.tsym.stoken.length = 3;
+ yyval.tsym.type = builtin_type_int;
+ }
+ break;
+
+ case 143:
+#line 975 "c-exp.y"
+ {
+ yyval.tsym.stoken.ptr = "long";
+ yyval.tsym.stoken.length = 4;
+ yyval.tsym.type = builtin_type_long;
+ }
+ break;
+
+ case 144:
+#line 981 "c-exp.y"
+ {
+ yyval.tsym.stoken.ptr = "short";
+ yyval.tsym.stoken.length = 5;
+ yyval.tsym.type = builtin_type_short;
+ }
+ break;
+
+ case 145:
+#line 990 "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 146:
+#line 995 "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 148:
+#line 1003 "c-exp.y"
+ { yyval.tval = follow_types (yyvsp[-3].tval); }
+ break;
+
+ case 151:
+#line 1011 "c-exp.y"
+ { push_type (tp_const);
+ push_type (tp_volatile);
+ }
+ break;
+
+ case 152:
+#line 1015 "c-exp.y"
+ { push_type (tp_const); }
+ break;
+
+ case 153:
+#line 1017 "c-exp.y"
+ { push_type (tp_volatile); }
+ break;
+
+ case 154:
+#line 1020 "c-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+ case 155:
+#line 1021 "c-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+ case 156:
+#line 1022 "c-exp.y"
+ { yyval.sval = yyvsp[0].tsym.stoken; }
+ break;
+
+ case 157:
+#line 1023 "c-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+
+ }
+
+/* Line 991 of yacc.c. */
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ 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)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab2;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+
+ /* Suppress GCC warning that yyerrlab1 is unused when no action
+ invokes YYERROR. Doesn't work in C++ */
+#ifndef __cplusplus
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+#endif
+#endif
+
+
+ goto yyerrlab2;
+
+
+/*---------------------------------------------------------------.
+| yyerrlab2 -- pop states until the error token can be shifted. |
+`---------------------------------------------------------------*/
+yyerrlab2:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 1037 "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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ /* FIXME: Shouldn't these be unsigned? We don't deal with negative values
+ here, and we do kind of silly things like cast to unsigned. */
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ ULONGEST un;
+
+ int i = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
+ int long_p = 0;
+
+ /* We have found a "L" or "U" suffix. */
+ int found_suffix = 0;
+
+ ULONGEST 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. */
+ char c;
+ int num = 0; /* number of tokens scanned by scanf */
+ char saved_char = p[len];
+
+ p[len] = 0; /* null-terminate the token */
+ if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
+ num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval,&c);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval,&c);
+ else
+ {
+#ifdef SCANF_HAS_LONG_DOUBLE
+ num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval,&c);
+#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;
+ num = sscanf (p, "%lg%c", &temp,&c);
+ putithere->typed_val_float.dval = temp;
+#endif
+ }
+ p[len] = saved_char; /* restore the input stream */
+ if (num != 1) /* check scanf found ONLY a float ... */
+ return ERROR;
+ /* 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 && (ULONGEST) prevn >= (ULONGEST) 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 = (ULONGEST)n >> 2;
+ if (long_p == 0
+ && (un >> (TARGET_INT_BIT - 2)) == 0)
+ {
+ high_bit = ((ULONGEST)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 = ((ULONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ int shift;
+ if (sizeof (ULONGEST) * HOST_CHAR_BIT < TARGET_LONG_LONG_BIT)
+ /* A long long does not fit in a LONGEST. */
+ shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
+ else
+ shift = (TARGET_LONG_LONG_BIT - 1);
+ high_bit = (ULONGEST) 1 << shift;
+ 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;
+ struct symbol * sym_class = NULL;
+ char * token_string = NULL;
+ int class_prefix = 0;
+ int unquoted_expr;
+
+ retry:
+
+ /* Check if this is a macro invocation that we need to expand. */
+ if (! scanning_macro_expansion ())
+ {
+ char *expanded = macro_expand_next (&lexptr,
+ expression_macro_lookup_func,
+ expression_macro_lookup_baton);
+
+ if (expanded)
+ scan_macro_expansion (expanded);
+ }
+
+ prev_lexptr = lexptr;
+ unquoted_expr = 1;
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
+ if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ switch (c = *tokstart)
+ {
+ case 0:
+ /* If we were just scanning the result of a macro expansion,
+ then we need to resume scanning the original text.
+ Otherwise, we were already scanning the original text, and
+ we're really done. */
+ if (scanning_macro_expansion ())
+ {
+ finished_macro_expansion ();
+ goto retry;
+ }
+ else
+ 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.");
+ else if (! host_char_to_target (c, &c))
+ {
+ int toklen = lexptr - tokstart + 1;
+ char *tok = alloca (toklen + 1);
+ memcpy (tok, tokstart, toklen);
+ tok[toklen] = '\0';
+ error ("There is no character corresponding to %s in the target "
+ "character set `%s'.", tok, target_charset ());
+ }
+
+ yylval.typed_val_int.val = c;
+ yylval.typed_val_int.type = builtin_type_char;
+
+ c = *lexptr++;
+ if (c != '\'')
+ {
+ namelen = skip_quoted (tokstart) - tokstart;
+ if (namelen > 2)
+ {
+ lexptr = tokstart + namelen;
+ unquoted_expr = 0;
+ 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
+ && ! scanning_macro_expansion ())
+ 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;
+ 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 {
+ char *char_start_pos = tokptr;
+
+ /* Grow the static temp buffer if necessary, including allocating
+ the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) 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:
+ c = *tokptr++;
+ if (! host_char_to_target (c, &c))
+ {
+ int len = tokptr - char_start_pos;
+ char *copy = alloca (len + 1);
+ memcpy (copy, char_start_pos, len);
+ copy[len] = '\0';
+
+ error ("There is no character corresponding to `%s' "
+ "in the target character set `%s'.",
+ copy, target_charset ());
+ }
+ tempbuf[tempbufindex++] = c;
+ break;
+ }
+ } 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 == '<');)
+ {
+ /* Template parameter lists are part of the name.
+ FIXME: This mishandles `print $a<4&&$a>3'. */
+
+ if (c == '<')
+ {
+ /* Scan ahead to get rest of the template specification. Note
+ that we look ahead only when the '<' adjoins non-whitespace
+ characters; for comparison expressions, e.g. "a < b > c",
+ there must be spaces before the '<', etc. */
+
+ char * p = find_template_name_end (tokstart + namelen);
+ if (p)
+ namelen = p - tokstart;
+ break;
+ }
+ c = tokstart[++namelen];
+ }
+
+ /* The token "if" terminates the expression and is NOT removed from
+ the input stream. It doesn't count if it appears in the
+ expansion of a macro. */
+ if (namelen == 2
+ && tokstart[0] == 'i'
+ && tokstart[1] == 'f'
+ && ! scanning_macro_expansion ())
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ tryname:
+
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 8:
+ if (strncmp (tokstart, "unsigned", 8) == 0)
+ return UNSIGNED;
+ if (current_language->la_language == language_cplus
+ && strncmp (tokstart, "template", 8) == 0)
+ return TEMPLATE;
+ if (strncmp (tokstart, "volatile", 8) == 0)
+ return VOLATILE_KEYWORD;
+ break;
+ case 6:
+ if (strncmp (tokstart, "struct", 6) == 0)
+ return STRUCT;
+ if (strncmp (tokstart, "signed", 6) == 0)
+ return SIGNED_KEYWORD;
+ if (strncmp (tokstart, "sizeof", 6) == 0)
+ return SIZEOF;
+ if (strncmp (tokstart, "double", 6) == 0)
+ return DOUBLE_KEYWORD;
+ break;
+ case 5:
+ if (current_language->la_language == language_cplus)
+ {
+ if (strncmp (tokstart, "false", 5) == 0)
+ return FALSEKEYWORD;
+ if (strncmp (tokstart, "class", 5) == 0)
+ return CLASS;
+ }
+ if (strncmp (tokstart, "union", 5) == 0)
+ return UNION;
+ if (strncmp (tokstart, "short", 5) == 0)
+ return SHORT;
+ if (strncmp (tokstart, "const", 5) == 0)
+ return CONST_KEYWORD;
+ break;
+ case 4:
+ if (strncmp (tokstart, "enum", 4) == 0)
+ return ENUM;
+ if (strncmp (tokstart, "long", 4) == 0)
+ return LONG;
+ if (current_language->la_language == language_cplus)
+ {
+ if (strncmp (tokstart, "true", 4) == 0)
+ return TRUEKEYWORD;
+ }
+ break;
+ case 3:
+ if (strncmp (tokstart, "int", 3) == 0)
+ return INT_KEYWORD;
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ if (*tokstart == '$')
+ {
+ write_dollar_variable (yylval.sval);
+ return VARIABLE;
+ }
+
+ /* Look ahead and see if we can consume more of the input
+ string to get a reasonable class/namespace spec or a
+ fully-qualified name. This is a kludge to get around the
+ HP aCC compiler's generation of symbol names with embedded
+ colons for namespace and nested classes. */
+
+ /* NOTE: carlton/2003-09-24: I don't entirely understand the
+ HP-specific code, either here or in linespec. Having said that,
+ I suspect that we're actually moving towards their model: we want
+ symbols whose names are fully qualified, which matches the
+ description above. */
+ if (unquoted_expr)
+ {
+ /* Only do it if not inside single quotes */
+ sym_class = parse_nested_classes_for_hpacc (yylval.sval.ptr, yylval.sval.length,
+ &token_string, &class_prefix, &lexptr);
+ if (sym_class)
+ {
+ /* Replace the current token with the bigger one we found */
+ yylval.sval.ptr = token_string;
+ yylval.sval.length = strlen (token_string);
+ }
+ }
+
+ /* 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_DOMAIN,
+ 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)
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return BLOCKNAME;
+ }
+ else if (!sym)
+ { /* See if it's a file name. */
+ struct symtab *symtab;
+
+ symtab = lookup_symtab (tmp);
+
+ if (symtab)
+ {
+ yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ return FILENAME;
+ }
+ }
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ /* NOTE: carlton/2003-09-25: There used to be code here to
+ handle nested types. It didn't work very well. See the
+ comment before qualified_type for more info. */
+ 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;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ 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 0000000..f11b93e
--- /dev/null
+++ b/contrib/gdb/gdb/c-exp.y
@@ -0,0 +1,1811 @@
+/* YACC parser for C expressions, for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2003, 2004
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 (<malloc.h> and <stdlib.h> 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 <ctype.h>
+#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 */
+#include "charset.h"
+#include "block.h"
+#include "cp-support.h"
+
+/* Flag indicating we're dealing with HP-compiled objects */
+extern int hp_som_som_object_present;
+
+/* 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 yyname c_name /* With YYDEBUG defined */
+#define yyrule c_rule /* 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 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+ since the result is stored in the structure being created,
+ other node types do have values. */
+
+%union
+ {
+ LONGEST lval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val_int;
+ struct {
+ DOUBLEST dval;
+ struct type *type;
+ } typed_val_float;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ struct ttype tsym;
+ struct symtoken ssym;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%{
+/* YYSTYPE gets defined by %union */
+static int parse_number (char *, int, int, YYSTYPE *);
+%}
+
+%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
+%type <lval> rcurly
+%type <tval> type typebase qualified_type
+%type <tvec> nonempty_typelist
+/* %type <bval> block */
+
+/* Fancy type parsing. */
+%type <voidval> func_mod direct_abs_decl abs_decl
+%type <tval> ptype
+%type <lval> array_mod
+
+%token <typed_val_int> INT
+%token <typed_val_float> 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 <sval> STRING
+%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
+%token <tsym> TYPENAME
+%type <sval> name
+%type <ssym> name_not_typename
+%type <tsym> 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 <ssym> 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 <voidval> VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+/* C++ */
+%token TRUEKEYWORD
+%token FALSEKEYWORD
+
+
+%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 <ssym> BLOCKNAME
+%token <bval> FILENAME
+%type <bval> 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 : TRUEKEYWORD
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_bool);
+ write_exp_elt_longcst ((LONGEST) 1);
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : FALSEKEYWORD
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_bool);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+/* end of C++. */
+
+block : BLOCKNAME
+ {
+ if ($1.sym)
+ $$ = SYMBOL_BLOCK_VALUE ($1.sym);
+ else
+ error ("No file or function \"%s\".",
+ copy_name ($1.stoken));
+ }
+ | FILENAME
+ {
+ $$ = $1;
+ }
+ ;
+
+block : block COLONCOLON name
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_DOMAIN, (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_DOMAIN, (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
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
+ 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
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ 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;
+
+ /* Check for valid destructor name. */
+ destructor_name_p (tmp_token.ptr, type);
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (type);
+ write_exp_string (tmp_token);
+ write_exp_elt_opcode (OP_SCOPE);
+ }
+ ;
+
+variable: qualified_name
+ | COLONCOLON name
+ {
+ char *name = copy_name ($2);
+ struct symbol *sym;
+ struct minimal_symbol *msymbol;
+
+ sym =
+ lookup_symbol (name, (const struct block *) NULL,
+ VAR_DOMAIN, (int *) NULL,
+ (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;
+ 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));
+ }
+ }
+ ;
+
+space_identifier : '@' NAME
+ { push_type_address_space (copy_name ($2.stoken));
+ push_type (tp_space_identifier);
+ }
+ ;
+
+const_or_volatile: const_or_volatile_noopt
+ |
+ ;
+
+cv_with_space_id : const_or_volatile space_identifier const_or_volatile
+ ;
+
+const_or_volatile_or_space_identifier_noopt: cv_with_space_id
+ | const_or_volatile_noopt
+ ;
+
+const_or_volatile_or_space_identifier:
+ const_or_volatile_or_space_identifier_noopt
+ |
+ ;
+
+abs_decl: '*'
+ { push_type (tp_pointer); $$ = 0; }
+ | '*' abs_decl
+ { push_type (tp_pointer); $$ = $2; }
+ | '&'
+ { push_type (tp_reference); $$ = 0; }
+ | '&' abs_decl
+ { push_type (tp_reference); $$ = $2; }
+ | direct_abs_decl
+ ;
+
+direct_abs_decl: '(' abs_decl ')'
+ { $$ = $2; }
+ | direct_abs_decl array_mod
+ {
+ push_type_int ($2);
+ push_type (tp_array);
+ }
+ | array_mod
+ {
+ push_type_int ($1);
+ push_type (tp_array);
+ $$ = 0;
+ }
+
+ | direct_abs_decl func_mod
+ { push_type (tp_function); }
+ | func_mod
+ { push_type (tp_function); }
+ ;
+
+array_mod: '[' ']'
+ { $$ = -1; }
+ | '[' INT ']'
+ { $$ = $2.val; }
+ ;
+
+func_mod: '(' ')'
+ { $$ = 0; }
+ | '(' nonempty_typelist ')'
+ { free ($2); $$ = 0; }
+ ;
+
+/* We used to try to recognize more pointer to member types here, but
+ that didn't work (shift/reduce conflicts meant that these rules never
+ got executed). The problem is that
+ int (foo::bar::baz::bizzle)
+ is a function type but
+ int (foo::bar::baz::bizzle::*)
+ is a pointer to member type. Stroustrup loses again! */
+
+type : ptype
+ | typebase 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; }
+ | LONG SIGNED_KEYWORD INT_KEYWORD
+ { $$ = builtin_type_long; }
+ | LONG SIGNED_KEYWORD
+ { $$ = builtin_type_long; }
+ | SIGNED_KEYWORD LONG INT_KEYWORD
+ { $$ = builtin_type_long; }
+ | UNSIGNED LONG INT_KEYWORD
+ { $$ = builtin_type_unsigned_long; }
+ | LONG UNSIGNED INT_KEYWORD
+ { $$ = builtin_type_unsigned_long; }
+ | LONG UNSIGNED
+ { $$ = builtin_type_unsigned_long; }
+ | LONG LONG
+ { $$ = builtin_type_long_long; }
+ | LONG LONG INT_KEYWORD
+ { $$ = builtin_type_long_long; }
+ | LONG LONG SIGNED_KEYWORD INT_KEYWORD
+ { $$ = builtin_type_long_long; }
+ | LONG LONG SIGNED_KEYWORD
+ { $$ = builtin_type_long_long; }
+ | SIGNED_KEYWORD LONG LONG
+ { $$ = builtin_type_long_long; }
+ | SIGNED_KEYWORD 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; }
+ | LONG LONG UNSIGNED
+ { $$ = builtin_type_unsigned_long_long; }
+ | LONG LONG UNSIGNED INT_KEYWORD
+ { $$ = builtin_type_unsigned_long_long; }
+ | SHORT INT_KEYWORD
+ { $$ = builtin_type_short; }
+ | SHORT SIGNED_KEYWORD INT_KEYWORD
+ { $$ = builtin_type_short; }
+ | SHORT SIGNED_KEYWORD
+ { $$ = builtin_type_short; }
+ | UNSIGNED SHORT INT_KEYWORD
+ { $$ = builtin_type_unsigned_short; }
+ | SHORT UNSIGNED
+ { $$ = builtin_type_unsigned_short; }
+ | SHORT UNSIGNED 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; }
+ /* It appears that this rule for templates is never
+ reduced; template recognition happens by lookahead
+ in the token processing code in yylex. */
+ | TEMPLATE name '<' type '>'
+ { $$ = lookup_template_type(copy_name($2), $4,
+ expression_context_block);
+ }
+ | const_or_volatile_or_space_identifier_noopt typebase
+ { $$ = follow_types ($2); }
+ | typebase const_or_volatile_or_space_identifier_noopt
+ { $$ = follow_types ($1); }
+ | qualified_type
+ ;
+
+/* FIXME: carlton/2003-09-25: This next bit leads to lots of
+ reduce-reduce conflicts, because the parser doesn't know whether or
+ not to use qualified_name or qualified_type: the rules are
+ identical. If the parser is parsing 'A::B::x', then, when it sees
+ the second '::', it knows that the expression to the left of it has
+ to be a type, so it uses qualified_type. But if it is parsing just
+ 'A::B', then it doesn't have any way of knowing which rule to use,
+ so there's a reduce-reduce conflict; it picks qualified_name, since
+ that occurs earlier in this file than qualified_type.
+
+ There's no good way to fix this with the grammar as it stands; as
+ far as I can tell, some of the problems arise from ambiguities that
+ GDB introduces ('start' can be either an expression or a type), but
+ some of it is inherent to the nature of C++ (you want to treat the
+ input "(FOO)" fairly differently depending on whether FOO is an
+ expression or a type, and if FOO is a complex expression, this can
+ be hard to determine at the right time). Fortunately, it works
+ pretty well in most cases. For example, if you do 'ptype A::B',
+ where A::B is a nested type, then the parser will mistakenly
+ misidentify it as an expression; but evaluate_subexp will get
+ called with 'noside' set to EVAL_AVOID_SIDE_EFFECTS, and everything
+ will work out anyways. But there are situations where the parser
+ will get confused: the most common one that I've run into is when
+ you want to do
+
+ print *((A::B *) x)"
+
+ where the parser doesn't realize that A::B has to be a type until
+ it hits the first right paren, at which point it's too late. (The
+ workaround is to type "print *(('A::B' *) x)" instead.) (And
+ another solution is to fix our symbol-handling code so that the
+ user never wants to type something like that in the first place,
+ because we get all the types right without the user's help!)
+
+ Perhaps we could fix this by making the lexer smarter. Some of
+ this functionality used to be in the lexer, but in a way that
+ worked even less well than the current solution: that attempt
+ involved having the parser sometimes handle '::' and having the
+ lexer sometimes handle it, and without a clear division of
+ responsibility, it quickly degenerated into a big mess. Probably
+ the eventual correct solution will give more of a role to the lexer
+ (ideally via code that is shared between the lexer and
+ decode_line_1), but I'm not holding my breath waiting for somebody
+ to get around to cleaning this up... */
+
+qualified_type: typebase COLONCOLON name
+ {
+ struct type *type = $1;
+ struct type *new_type;
+ char *ncopy = alloca ($3.length + 1);
+
+ memcpy (ncopy, $3.ptr, $3.length);
+ ncopy[$3.length] = '\0';
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
+ error ("`%s' is not defined as an aggregate type.",
+ TYPE_NAME (type));
+
+ new_type = cp_lookup_nested_type (type, ncopy,
+ expression_context_block);
+ if (new_type == NULL)
+ error ("No type \"%s\" within class or namespace \"%s\".",
+ ncopy, TYPE_NAME (type));
+
+ $$ = new_type;
+ }
+ ;
+
+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);
+ $<ivec>$[0] = 1; /* Number of types in vector */
+ $$[1] = $1;
+ }
+ | nonempty_typelist ',' type
+ { int len = sizeof (struct type *) * (++($<ivec>1[0]) + 1);
+ $$ = (struct type **) realloc ((char *) $1, len);
+ $$[$<ivec>$[0]] = $3;
+ }
+ ;
+
+ptype : typebase
+ | ptype const_or_volatile_or_space_identifier abs_decl const_or_volatile_or_space_identifier
+ { $$ = follow_types ($1); }
+ ;
+
+const_and_volatile: CONST_KEYWORD VOLATILE_KEYWORD
+ | VOLATILE_KEYWORD CONST_KEYWORD
+ ;
+
+const_or_volatile_noopt: const_and_volatile
+ { push_type (tp_const);
+ push_type (tp_volatile);
+ }
+ | CONST_KEYWORD
+ { push_type (tp_const); }
+ | VOLATILE_KEYWORD
+ { push_type (tp_volatile); }
+ ;
+
+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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ /* FIXME: Shouldn't these be unsigned? We don't deal with negative values
+ here, and we do kind of silly things like cast to unsigned. */
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ ULONGEST un;
+
+ int i = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
+ int long_p = 0;
+
+ /* We have found a "L" or "U" suffix. */
+ int found_suffix = 0;
+
+ ULONGEST 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. */
+ char c;
+ int num = 0; /* number of tokens scanned by scanf */
+ char saved_char = p[len];
+
+ p[len] = 0; /* null-terminate the token */
+ if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
+ num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval,&c);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval,&c);
+ else
+ {
+#ifdef SCANF_HAS_LONG_DOUBLE
+ num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval,&c);
+#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;
+ num = sscanf (p, "%lg%c", &temp,&c);
+ putithere->typed_val_float.dval = temp;
+#endif
+ }
+ p[len] = saved_char; /* restore the input stream */
+ if (num != 1) /* check scanf found ONLY a float ... */
+ return ERROR;
+ /* 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 && (ULONGEST) prevn >= (ULONGEST) 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 = (ULONGEST)n >> 2;
+ if (long_p == 0
+ && (un >> (TARGET_INT_BIT - 2)) == 0)
+ {
+ high_bit = ((ULONGEST)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 = ((ULONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ int shift;
+ if (sizeof (ULONGEST) * HOST_CHAR_BIT < TARGET_LONG_LONG_BIT)
+ /* A long long does not fit in a LONGEST. */
+ shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
+ else
+ shift = (TARGET_LONG_LONG_BIT - 1);
+ high_bit = (ULONGEST) 1 << shift;
+ 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;
+ struct symbol * sym_class = NULL;
+ char * token_string = NULL;
+ int class_prefix = 0;
+ int unquoted_expr;
+
+ retry:
+
+ /* Check if this is a macro invocation that we need to expand. */
+ if (! scanning_macro_expansion ())
+ {
+ char *expanded = macro_expand_next (&lexptr,
+ expression_macro_lookup_func,
+ expression_macro_lookup_baton);
+
+ if (expanded)
+ scan_macro_expansion (expanded);
+ }
+
+ prev_lexptr = lexptr;
+ unquoted_expr = 1;
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
+ if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ switch (c = *tokstart)
+ {
+ case 0:
+ /* If we were just scanning the result of a macro expansion,
+ then we need to resume scanning the original text.
+ Otherwise, we were already scanning the original text, and
+ we're really done. */
+ if (scanning_macro_expansion ())
+ {
+ finished_macro_expansion ();
+ goto retry;
+ }
+ else
+ 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.");
+ else if (! host_char_to_target (c, &c))
+ {
+ int toklen = lexptr - tokstart + 1;
+ char *tok = alloca (toklen + 1);
+ memcpy (tok, tokstart, toklen);
+ tok[toklen] = '\0';
+ error ("There is no character corresponding to %s in the target "
+ "character set `%s'.", tok, target_charset ());
+ }
+
+ yylval.typed_val_int.val = c;
+ yylval.typed_val_int.type = builtin_type_char;
+
+ c = *lexptr++;
+ if (c != '\'')
+ {
+ namelen = skip_quoted (tokstart) - tokstart;
+ if (namelen > 2)
+ {
+ lexptr = tokstart + namelen;
+ unquoted_expr = 0;
+ 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
+ && ! scanning_macro_expansion ())
+ 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;
+ 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 {
+ char *char_start_pos = tokptr;
+
+ /* Grow the static temp buffer if necessary, including allocating
+ the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) realloc (tempbuf, tempbufsize += 64);
+ }
+ switch (*tokptr)
+ {
+ case '\0':
+ case '"':
+ /* Do nothing, loop will terminate. */
+ break;
+ case '\\':
+ tokptr++;
+ c = parse_escape (&tokptr);
+ if (c == -1)
+ {
+ continue;
+ }
+ tempbuf[tempbufindex++] = c;
+ break;
+ default:
+ c = *tokptr++;
+ if (! host_char_to_target (c, &c))
+ {
+ int len = tokptr - char_start_pos;
+ char *copy = alloca (len + 1);
+ memcpy (copy, char_start_pos, len);
+ copy[len] = '\0';
+
+ error ("There is no character corresponding to `%s' "
+ "in the target character set `%s'.",
+ copy, target_charset ());
+ }
+ tempbuf[tempbufindex++] = c;
+ break;
+ }
+ } 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 == '<');)
+ {
+ /* Template parameter lists are part of the name.
+ FIXME: This mishandles `print $a<4&&$a>3'. */
+
+ if (c == '<')
+ {
+ /* Scan ahead to get rest of the template specification. Note
+ that we look ahead only when the '<' adjoins non-whitespace
+ characters; for comparison expressions, e.g. "a < b > c",
+ there must be spaces before the '<', etc. */
+
+ char * p = find_template_name_end (tokstart + namelen);
+ if (p)
+ namelen = p - tokstart;
+ break;
+ }
+ c = tokstart[++namelen];
+ }
+
+ /* The token "if" terminates the expression and is NOT removed from
+ the input stream. It doesn't count if it appears in the
+ expansion of a macro. */
+ if (namelen == 2
+ && tokstart[0] == 'i'
+ && tokstart[1] == 'f'
+ && ! scanning_macro_expansion ())
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ tryname:
+
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 8:
+ if (strncmp (tokstart, "unsigned", 8) == 0)
+ return UNSIGNED;
+ if (current_language->la_language == language_cplus
+ && strncmp (tokstart, "template", 8) == 0)
+ return TEMPLATE;
+ if (strncmp (tokstart, "volatile", 8) == 0)
+ return VOLATILE_KEYWORD;
+ break;
+ case 6:
+ if (strncmp (tokstart, "struct", 6) == 0)
+ return STRUCT;
+ if (strncmp (tokstart, "signed", 6) == 0)
+ return SIGNED_KEYWORD;
+ if (strncmp (tokstart, "sizeof", 6) == 0)
+ return SIZEOF;
+ if (strncmp (tokstart, "double", 6) == 0)
+ return DOUBLE_KEYWORD;
+ break;
+ case 5:
+ if (current_language->la_language == language_cplus)
+ {
+ if (strncmp (tokstart, "false", 5) == 0)
+ return FALSEKEYWORD;
+ if (strncmp (tokstart, "class", 5) == 0)
+ return CLASS;
+ }
+ if (strncmp (tokstart, "union", 5) == 0)
+ return UNION;
+ if (strncmp (tokstart, "short", 5) == 0)
+ return SHORT;
+ if (strncmp (tokstart, "const", 5) == 0)
+ return CONST_KEYWORD;
+ break;
+ case 4:
+ if (strncmp (tokstart, "enum", 4) == 0)
+ return ENUM;
+ if (strncmp (tokstart, "long", 4) == 0)
+ return LONG;
+ if (current_language->la_language == language_cplus)
+ {
+ if (strncmp (tokstart, "true", 4) == 0)
+ return TRUEKEYWORD;
+ }
+ break;
+ case 3:
+ if (strncmp (tokstart, "int", 3) == 0)
+ return INT_KEYWORD;
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ if (*tokstart == '$')
+ {
+ write_dollar_variable (yylval.sval);
+ return VARIABLE;
+ }
+
+ /* Look ahead and see if we can consume more of the input
+ string to get a reasonable class/namespace spec or a
+ fully-qualified name. This is a kludge to get around the
+ HP aCC compiler's generation of symbol names with embedded
+ colons for namespace and nested classes. */
+
+ /* NOTE: carlton/2003-09-24: I don't entirely understand the
+ HP-specific code, either here or in linespec. Having said that,
+ I suspect that we're actually moving towards their model: we want
+ symbols whose names are fully qualified, which matches the
+ description above. */
+ if (unquoted_expr)
+ {
+ /* Only do it if not inside single quotes */
+ sym_class = parse_nested_classes_for_hpacc (yylval.sval.ptr, yylval.sval.length,
+ &token_string, &class_prefix, &lexptr);
+ if (sym_class)
+ {
+ /* Replace the current token with the bigger one we found */
+ yylval.sval.ptr = token_string;
+ yylval.sval.length = strlen (token_string);
+ }
+ }
+
+ /* 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_DOMAIN,
+ 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)
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return BLOCKNAME;
+ }
+ else if (!sym)
+ { /* See if it's a file name. */
+ struct symtab *symtab;
+
+ symtab = lookup_symtab (tmp);
+
+ if (symtab)
+ {
+ yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ return FILENAME;
+ }
+ }
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ /* NOTE: carlton/2003-09-25: There used to be code here to
+ handle nested types. It didn't work very well. See the
+ comment before qualified_type for more info. */
+ 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;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ 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 0000000..ba34540
--- /dev/null
+++ b/contrib/gdb/gdb/c-lang.c
@@ -0,0 +1,713 @@
+/* C language support routines for GDB, the GNU debugger.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "valprint.h"
+#include "macroscope.h"
+#include "gdb_assert.h"
+#include "charset.h"
+#include "gdb_string.h"
+#include "demangle.h"
+#include "cp-support.h"
+
+extern void _initialize_c_language (void);
+static void c_emit_char (int c, struct ui_file * stream, int quoter);
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ characters and strings is language specific. */
+
+static void
+c_emit_char (int c, struct ui_file *stream, int quoter)
+{
+ const char *escape;
+ int host_char;
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ escape = c_target_char_has_backslash_escape (c);
+ if (escape)
+ {
+ if (quoter == '"' && strcmp (escape, "0") == 0)
+ /* Print nulls embedded in double quoted strings as \000 to
+ prevent ambiguity. */
+ fprintf_filtered (stream, "\\000");
+ else
+ fprintf_filtered (stream, "\\%s", escape);
+ }
+ else if (target_char_to_host (c, &host_char)
+ && host_char_print_literally (host_char))
+ {
+ if (host_char == '\\' || host_char == quoter)
+ fputs_filtered ("\\", stream);
+ fprintf_filtered (stream, "%c", host_char);
+ }
+ else
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+}
+
+void
+c_printchar (int c, struct ui_file *stream)
+{
+ fputc_filtered ('\'', stream);
+ LA_EMIT_CHAR (c, stream, '\'');
+ fputc_filtered ('\'', stream);
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+ LENGTH is -1 if the string is nul terminated. Each character is WIDTH bytes
+ long. 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 (struct ui_file *stream, char *string, unsigned int length,
+ int width, int force_ellipses)
+{
+ unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+
+ /* If the string was not truncated due to `set print elements', and
+ the last byte of it is a null, we don't print that, in traditional C
+ style. */
+ if (!force_ellipses
+ && length > 0
+ && (extract_unsigned_integer (string + (length - 1) * width, width)
+ == '\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;
+ unsigned long current_char;
+
+ QUIT;
+
+ if (need_comma)
+ {
+ fputs_filtered (", ", stream);
+ need_comma = 0;
+ }
+
+ current_char = extract_unsigned_integer (string + i * width, width);
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < length
+ && extract_unsigned_integer (string + rep1 * width, width)
+ == current_char)
+ {
+ ++rep1;
+ ++reps;
+ }
+
+ if (reps > repeat_count_threshold)
+ {
+ if (in_quotes)
+ {
+ if (inspect_it)
+ fputs_filtered ("\\\", ", stream);
+ else
+ fputs_filtered ("\", ", stream);
+ in_quotes = 0;
+ }
+ LA_PRINT_CHAR (current_char, stream);
+ fprintf_filtered (stream, " <repeats %u times>", 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;
+ }
+ LA_EMIT_CHAR (current_char, 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 (struct objfile *objfile, int typeid)
+{
+ 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 "<?type?>". 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, "<?type?>", 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_BOOLEAN:
+ type = init_type (TYPE_CODE_BOOL,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "bool", objfile);
+ break;
+ case FT_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_NOSIGN, "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;
+ case FT_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ 2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0, "complex float", objfile);
+ TYPE_TARGET_TYPE (type)
+ = init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+ 0, "float", objfile);
+ break;
+ case FT_DBL_PREC_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ 2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "complex double", objfile);
+ TYPE_TARGET_TYPE (type)
+ = init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "double", objfile);
+ break;
+ case FT_EXT_PREC_COMPLEX:
+ type = init_type (TYPE_CODE_FLT,
+ 2 * TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "complex long double", objfile);
+ TYPE_TARGET_TYPE (type)
+ = init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "long double", objfile);
+ break;
+ case FT_TEMPLATE_ARG:
+ type = init_type (TYPE_CODE_TEMPLATE_ARG,
+ 0,
+ 0, "<template arg>", objfile);
+ break;
+ }
+ return (type);
+}
+
+/* Preprocessing and parsing C and C++ expressions. */
+
+
+/* When we find that lexptr (the global var defined in parse.c) is
+ pointing at a macro invocation, we expand the invocation, and call
+ scan_macro_expansion to save the old lexptr here and point lexptr
+ into the expanded text. When we reach the end of that, we call
+ end_macro_expansion to pop back to the value we saved here. The
+ macro expansion code promises to return only fully-expanded text,
+ so we don't need to "push" more than one level.
+
+ This is disgusting, of course. It would be cleaner to do all macro
+ expansion beforehand, and then hand that to lexptr. But we don't
+ really know where the expression ends. Remember, in a command like
+
+ (gdb) break *ADDRESS if CONDITION
+
+ we evaluate ADDRESS in the scope of the current frame, but we
+ evaluate CONDITION in the scope of the breakpoint's location. So
+ it's simply wrong to try to macro-expand the whole thing at once. */
+static char *macro_original_text;
+static char *macro_expanded_text;
+
+
+void
+scan_macro_expansion (char *expansion)
+{
+ /* We'd better not be trying to push the stack twice. */
+ gdb_assert (! macro_original_text);
+ gdb_assert (! macro_expanded_text);
+
+ /* Save the old lexptr value, so we can return to it when we're done
+ parsing the expanded text. */
+ macro_original_text = lexptr;
+ lexptr = expansion;
+
+ /* Save the expanded text, so we can free it when we're finished. */
+ macro_expanded_text = expansion;
+}
+
+
+int
+scanning_macro_expansion (void)
+{
+ return macro_original_text != 0;
+}
+
+
+void
+finished_macro_expansion (void)
+{
+ /* There'd better be something to pop back to, and we better have
+ saved a pointer to the start of the expanded text. */
+ gdb_assert (macro_original_text);
+ gdb_assert (macro_expanded_text);
+
+ /* Pop back to the original text. */
+ lexptr = macro_original_text;
+ macro_original_text = 0;
+
+ /* Free the expanded text. */
+ xfree (macro_expanded_text);
+ macro_expanded_text = 0;
+}
+
+
+static void
+scan_macro_cleanup (void *dummy)
+{
+ if (macro_original_text)
+ finished_macro_expansion ();
+}
+
+
+/* We set these global variables before calling c_parse, to tell it
+ how it to find macro definitions for the expression at hand. */
+macro_lookup_ftype *expression_macro_lookup_func;
+void *expression_macro_lookup_baton;
+
+
+static struct macro_definition *
+null_macro_lookup (const char *name, void *baton)
+{
+ return 0;
+}
+
+
+static int
+c_preprocess_and_parse (void)
+{
+ /* Set up a lookup function for the macro expander. */
+ struct macro_scope *scope = 0;
+ struct cleanup *back_to = make_cleanup (free_current_contents, &scope);
+
+ if (expression_context_block)
+ scope = sal_macro_scope (find_pc_line (expression_context_pc, 0));
+ else
+ scope = default_macro_scope ();
+
+ if (scope)
+ {
+ expression_macro_lookup_func = standard_macro_lookup;
+ expression_macro_lookup_baton = (void *) scope;
+ }
+ else
+ {
+ expression_macro_lookup_func = null_macro_lookup;
+ expression_macro_lookup_baton = 0;
+ }
+
+ gdb_assert (! macro_original_text);
+ make_cleanup (scan_macro_cleanup, 0);
+
+ {
+ int result = c_parse ();
+ do_cleanups (back_to);
+ return result;
+ }
+}
+
+
+
+/* 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},
+ {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,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ c_preprocess_and_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_emit_char, /* Print a single char */
+ 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 */
+ NULL, /* Language specific skip_trampoline */
+ NULL, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+struct type **const (cplus_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,
+ &builtin_type_bool,
+ 0
+};
+
+const struct language_defn cplus_language_defn =
+{
+ "c++", /* Language name */
+ language_cplus,
+ cplus_builtin_types,
+ range_check_off,
+ type_check_off,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ c_preprocess_and_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_emit_char, /* Print a single char */
+ 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 */
+ NULL, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ cp_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ cp_lookup_transparent_type, /* lookup_transparent_type */
+ cplus_demangle, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+const struct language_defn asm_language_defn =
+{
+ "asm", /* Language name */
+ language_asm,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ c_preprocess_and_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_emit_char, /* Print a single char */
+ 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 */
+ NULL, /* Language specific skip_trampoline */
+ NULL, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+/* The following language_defn does not represent a real language.
+ It just provides a minimal support a-la-C that should allow users
+ to do some simple operations when debugging applications that use
+ a language currently not supported by GDB. */
+
+const struct language_defn minimal_language_defn =
+{
+ "minimal", /* Language name */
+ language_minimal,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ c_preprocess_and_parse,
+ c_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_emit_char, /* Print a single char */
+ 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 */
+ NULL, /* Language specific skip_trampoline */
+ NULL, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+void
+_initialize_c_language (void)
+{
+ add_language (&c_language_defn);
+ add_language (&cplus_language_defn);
+ add_language (&asm_language_defn);
+ add_language (&minimal_language_defn);
+}
diff --git a/contrib/gdb/gdb/c-lang.h b/contrib/gdb/gdb/c-lang.h
new file mode 100644
index 0000000..dd8f231
--- /dev/null
+++ b/contrib/gdb/gdb/c-lang.h
@@ -0,0 +1,91 @@
+/* C language support definitions for GDB, the GNU debugger.
+ Copyright 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (C_LANG_H)
+#define C_LANG_H 1
+
+struct ui_file;
+
+#include "value.h"
+#include "macroexp.h"
+
+
+extern int c_parse (void); /* Defined in c-exp.y */
+
+extern void c_error (char *); /* Defined in c-exp.y */
+
+/* Defined in c-typeprint.c */
+extern void c_print_type (struct type *, char *, struct ui_file *, int,
+ int);
+
+extern int c_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+extern int c_value_print (struct value *, struct ui_file *, int,
+ enum val_prettyprint);
+
+/* These are in c-lang.c: */
+
+extern void c_printchar (int, struct ui_file *);
+
+extern void c_printstr (struct ui_file * stream, char *string,
+ unsigned int length, int width,
+ int force_ellipses);
+
+extern void scan_macro_expansion (char *expansion);
+extern int scanning_macro_expansion (void);
+extern void finished_macro_expansion (void);
+
+extern macro_lookup_ftype *expression_macro_lookup_func;
+extern void *expression_macro_lookup_baton;
+
+extern struct type *c_create_fundamental_type (struct objfile *, int);
+
+extern struct type **const (c_builtin_types[]);
+
+/* These are in c-typeprint.c: */
+
+extern void c_type_print_base (struct type *, struct ui_file *, int, int);
+
+/* These are in cp-valprint.c */
+
+extern int vtblprint; /* Controls printing of vtbl's */
+
+extern int static_field_print;
+
+extern void cp_print_class_member (char *, struct type *, struct ui_file *,
+ char *);
+
+extern void cp_print_class_method (char *, struct type *, struct ui_file *);
+
+extern void cp_print_value_fields (struct type *, struct type *, char *,
+ int, CORE_ADDR, struct ui_file *, int,
+ int, enum val_prettyprint,
+ struct type **, int);
+
+extern int cp_is_vtbl_ptr_type (struct type *);
+
+extern int cp_is_vtbl_member (struct type *);
+
+
+#endif /* !defined (C_LANG_H) */
diff --git a/contrib/gdb/gdb/c-typeprint.c b/contrib/gdb/gdb/c-typeprint.c
new file mode 100644
index 0000000..2d2ad85
--- /dev/null
+++ b/contrib/gdb/gdb/c-typeprint.c
@@ -0,0 +1,1212 @@
+/* Support for printing C and C++ types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_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 "language.h"
+#include "demangle.h"
+#include "c-lang.h"
+#include "typeprint.h"
+#include "cp-abi.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+
+/* Flag indicating target was compiled by HP compiler */
+extern int hp_som_som_object_present;
+
+static void cp_type_print_method_args (struct type *mtype, char *prefix,
+ char *varstring, int staticp,
+ struct ui_file *stream);
+
+static void c_type_print_args (struct type *, struct ui_file *);
+
+static void cp_type_print_derivation_info (struct ui_file *, struct type *);
+
+static void c_type_print_varspec_prefix (struct type *, struct ui_file *, int,
+ int, int);
+
+/* Print "const", "volatile", or address space modifiers. */
+static void c_type_print_modifier (struct type *, struct ui_file *,
+ int, int);
+
+
+
+
+/* LEVEL is the depth to indent lines by. */
+
+void
+c_print_type (struct type *type, char *varstring, struct ui_file *stream,
+ int show, int level)
+{
+ enum type_code code;
+ int demangled_args;
+ int need_post_space;
+
+ 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);
+ need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
+ c_type_print_varspec_prefix (type, stream, show, 0, need_post_space);
+
+ if (varstring != NULL)
+ {
+ 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);
+ }
+}
+
+/* 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.
+ Note that in case of protected derivation gcc will not say 'protected'
+ but 'private'. The HP's aCC compiler emits specific information for
+ derivation via protected inheritance, so gdb can print it out */
+
+static void
+cp_type_print_derivation_info (struct ui_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"
+ : (TYPE_FIELD_PROTECTED (type, i) ? "protected" : "private"),
+ BASETYPE_VIA_VIRTUAL (type, i) ? " virtual" : "");
+ name = type_name_no_tag (TYPE_BASECLASS (type, i));
+ fprintf_filtered (stream, "%s", name ? name : "(null)");
+ }
+ if (i > 0)
+ {
+ fputs_filtered (" ", stream);
+ }
+}
+
+/* Print the C++ method arguments ARGS to the file STREAM. */
+
+static void
+cp_type_print_method_args (struct type *mtype, char *prefix, char *varstring,
+ int staticp, struct ui_file *stream)
+{
+ struct field *args = TYPE_FIELDS (mtype);
+ int nargs = TYPE_NFIELDS (mtype);
+ int varargs = TYPE_VARARGS (mtype);
+ int i;
+
+ fprintf_symbol_filtered (stream, prefix, language_cplus, DMGL_ANSI);
+ fprintf_symbol_filtered (stream, varstring, language_cplus, DMGL_ANSI);
+ fputs_filtered ("(", stream);
+
+ /* Skip the class variable. */
+ i = staticp ? 0 : 1;
+ if (nargs > i)
+ {
+ while (i < nargs)
+ {
+ type_print (args[i++].type, "", stream, 0);
+
+ if (i == nargs && varargs)
+ fprintf_filtered (stream, ", ...");
+ else if (i < nargs)
+ fprintf_filtered (stream, ", ");
+ }
+ }
+ else if (varargs)
+ fprintf_filtered (stream, "...");
+ else if (current_language->la_language == language_cplus)
+ fprintf_filtered (stream, "void");
+
+ fprintf_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.
+
+ NEED_POST_SPACE is non-zero when a space will be be needed
+ between a trailing qualifier and a field, variable, or function
+ name. */
+
+void
+c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
+ int show, int passed_a_ptr, int need_post_space)
+{
+ 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, show, 1, 1);
+ fprintf_filtered (stream, "*");
+ c_type_print_modifier (type, stream, 1, need_post_space);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 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_filtered (stream, "(");
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 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, show, 1, 0);
+ fprintf_filtered (stream, "&");
+ c_type_print_modifier (type, stream, 1, need_post_space);
+ break;
+
+ case TYPE_CODE_FUNC:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ break;
+
+ case TYPE_CODE_ARRAY:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ break;
+
+ case TYPE_CODE_TYPEDEF:
+ c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
+ 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_TEMPLATE:
+ case TYPE_CODE_NAMESPACE:
+ /* These types need no prefix. They are listed here so that
+ gcc -Wall will reveal any types that haven't been handled. */
+ break;
+ default:
+ error ("type not handled in c_type_print_varspec_prefix()");
+ break;
+ }
+}
+
+/* Print out "const" and "volatile" attributes.
+ TYPE is a pointer to the type being printed out.
+ STREAM is the output destination.
+ NEED_SPACE = 1 indicates an initial white space is needed */
+
+static void
+c_type_print_modifier (struct type *type, struct ui_file *stream,
+ int need_pre_space, int need_post_space)
+{
+ int did_print_modifier = 0;
+ const char *address_space_id;
+
+ /* We don't print `const' qualifiers for references --- since all
+ operators affect the thing referenced, not the reference itself,
+ every reference is `const'. */
+ if (TYPE_CONST (type)
+ && TYPE_CODE (type) != TYPE_CODE_REF)
+ {
+ if (need_pre_space)
+ fprintf_filtered (stream, " ");
+ fprintf_filtered (stream, "const");
+ did_print_modifier = 1;
+ }
+
+ if (TYPE_VOLATILE (type))
+ {
+ if (did_print_modifier || need_pre_space)
+ fprintf_filtered (stream, " ");
+ fprintf_filtered (stream, "volatile");
+ did_print_modifier = 1;
+ }
+
+ address_space_id = address_space_int_to_name (TYPE_INSTANCE_FLAGS (type));
+ if (address_space_id)
+ {
+ if (did_print_modifier || need_pre_space)
+ fprintf_filtered (stream, " ");
+ fprintf_filtered (stream, "@%s", address_space_id);
+ did_print_modifier = 1;
+ }
+
+ if (did_print_modifier && need_post_space)
+ fprintf_filtered (stream, " ");
+}
+
+
+
+
+static void
+c_type_print_args (struct type *type, struct ui_file *stream)
+{
+ int i;
+ struct field *args;
+
+ fprintf_filtered (stream, "(");
+ args = TYPE_FIELDS (type);
+ if (args != NULL)
+ {
+ int i;
+
+ /* FIXME drow/2002-05-31: Always skips the first argument,
+ should we be checking for static members? */
+
+ for (i = 1; i < TYPE_NFIELDS (type); i++)
+ {
+ c_print_type (args[i].type, "", stream, -1, 0);
+ if (i != TYPE_NFIELDS (type))
+ {
+ fprintf_filtered (stream, ",");
+ wrap_here (" ");
+ }
+ }
+ if (TYPE_VARARGS (type))
+ fprintf_filtered (stream, "...");
+ else if (i == 1
+ && (current_language->la_language == language_cplus))
+ fprintf_filtered (stream, "void");
+ }
+ else if (current_language->la_language == language_cplus)
+ {
+ fprintf_filtered (stream, "void");
+ }
+
+ fprintf_filtered (stream, ")");
+}
+
+
+/* Return true iff the j'th overloading of the i'th method of TYPE
+ is a type conversion operator, like `operator int () { ... }'.
+ When listing a class's methods, we don't print the return type of
+ such operators. */
+static int
+is_type_conversion_operator (struct type *type, int i, int j)
+{
+ /* I think the whole idea of recognizing type conversion operators
+ by their name is pretty terrible. But I don't think our present
+ data structure gives us any other way to tell. If you know of
+ some other way, feel free to rewrite this function. */
+ char *name = TYPE_FN_FIELDLIST_NAME (type, i);
+
+ if (strncmp (name, "operator", 8) != 0)
+ return 0;
+
+ name += 8;
+ if (! strchr (" \t\f\n\r", *name))
+ return 0;
+
+ while (strchr (" \t\f\n\r", *name))
+ name++;
+
+ if (!('a' <= *name && *name <= 'z')
+ && !('A' <= *name && *name <= 'Z')
+ && *name != '_')
+ /* If this doesn't look like the start of an identifier, then it
+ isn't a type conversion operator. */
+ return 0;
+ else if (strncmp (name, "new", 3) == 0)
+ name += 3;
+ else if (strncmp (name, "delete", 6) == 0)
+ name += 6;
+ else
+ /* If it doesn't look like new or delete, it's a type conversion
+ operator. */
+ return 1;
+
+ /* Is that really the end of the name? */
+ if (('a' <= *name && *name <= 'z')
+ || ('A' <= *name && *name <= 'Z')
+ || ('0' <= *name && *name <= '9')
+ || *name == '_')
+ /* No, so the identifier following "operator" must be a type name,
+ and this is a type conversion operator. */
+ return 1;
+
+ /* That was indeed the end of the name, so it was `operator new' or
+ `operator delete', neither of which are type conversion operators. */
+ return 0;
+}
+
+
+/* Given a C++ qualified identifier QID, strip off the qualifiers,
+ yielding the unqualified name. The return value is a pointer into
+ the original string.
+
+ It's a pity we don't have this information in some more structured
+ form. Even the author of this function feels that writing little
+ parsers like this everywhere is stupid. */
+static char *
+remove_qualifiers (char *qid)
+{
+ int quoted = 0; /* zero if we're not in quotes;
+ '"' if we're in a double-quoted string;
+ '\'' if we're in a single-quoted string. */
+ int depth = 0; /* number of unclosed parens we've seen */
+ char *parenstack = (char *) alloca (strlen (qid));
+ char *scan;
+ char *last = 0; /* The character after the rightmost
+ `::' token we've seen so far. */
+
+ for (scan = qid; *scan; scan++)
+ {
+ if (quoted)
+ {
+ if (*scan == quoted)
+ quoted = 0;
+ else if (*scan == '\\' && *(scan + 1))
+ scan++;
+ }
+ else if (scan[0] == ':' && scan[1] == ':')
+ {
+ /* If we're inside parenthesis (i.e., an argument list) or
+ angle brackets (i.e., a list of template arguments), then
+ we don't record the position of this :: token, since it's
+ not relevant to the top-level structure we're trying
+ to operate on. */
+ if (depth == 0)
+ {
+ last = scan + 2;
+ scan++;
+ }
+ }
+ else if (*scan == '"' || *scan == '\'')
+ quoted = *scan;
+ else if (*scan == '(')
+ parenstack[depth++] = ')';
+ else if (*scan == '[')
+ parenstack[depth++] = ']';
+ /* We're going to treat <> as a pair of matching characters,
+ since we're more likely to see those in template id's than
+ real less-than characters. What a crock. */
+ else if (*scan == '<')
+ parenstack[depth++] = '>';
+ else if (*scan == ')' || *scan == ']' || *scan == '>')
+ {
+ if (depth > 0 && parenstack[depth - 1] == *scan)
+ depth--;
+ else
+ {
+ /* We're going to do a little error recovery here. If we
+ don't find a match for *scan on the paren stack, but
+ there is something lower on the stack that does match, we
+ pop the stack to that point. */
+ int i;
+
+ for (i = depth - 1; i >= 0; i--)
+ if (parenstack[i] == *scan)
+ {
+ depth = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (last)
+ return last;
+ else
+ /* We didn't find any :: tokens at the top level, so declare the
+ whole thing an unqualified identifier. */
+ return qid;
+}
+
+
+/* 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. */
+
+void
+c_type_print_varspec_suffix (struct type *type, struct ui_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, show,
+ 0, 0);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
+ 0, 0);
+ break;
+
+ case TYPE_CODE_METHOD:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
+ 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, show,
+ 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, "(");
+ if (len == 0
+ && (TYPE_PROTOTYPED (type)
+ || current_language->la_language == language_cplus))
+ {
+ fprintf_filtered (stream, "void");
+ }
+ else
+ 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, show,
+ passed_a_ptr, 0);
+ break;
+
+ case TYPE_CODE_TYPEDEF:
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
+ 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_TEMPLATE:
+ case TYPE_CODE_NAMESPACE:
+ /* These types do not need a suffix. They are listed so that
+ gcc -Wall will report types that may not have been considered. */
+ break;
+ default:
+ error ("type not handled in c_type_print_varspec_suffix()");
+ 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 (struct type *type, struct ui_file *stream, int show,
+ int level)
+{
+ int i;
+ int len, real_len;
+ int lastval;
+ char *mangled_name;
+ char *demangled_name;
+ char *demangled_no_static;
+ enum
+ {
+ s_none, s_public, s_private, s_protected
+ }
+ section_type;
+ int need_access_label = 0;
+ int j, len2;
+
+ QUIT;
+
+ wrap_here (" ");
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", 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)
+ {
+ c_type_print_modifier (type, stream, 0, 1);
+ 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:
+ c_type_print_modifier (type, stream, 0, 1);
+ /* Note TYPE_CODE_STRUCT and TYPE_CODE_CLASS have the same value,
+ * so we use another means for distinguishing them.
+ */
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ switch (TYPE_DECLARED_TYPE (type))
+ {
+ case DECLARED_TYPE_CLASS:
+ fprintf_filtered (stream, "class ");
+ break;
+ case DECLARED_TYPE_UNION:
+ fprintf_filtered (stream, "union ");
+ break;
+ case DECLARED_TYPE_STRUCT:
+ fprintf_filtered (stream, "struct ");
+ break;
+ default:
+ /* If there is a CPLUS_STRUCT, assume class if not
+ * otherwise specified in the declared_type field.
+ */
+ fprintf_filtered (stream, "class ");
+ break;
+ } /* switch */
+ }
+ else
+ {
+ /* If not CPLUS_STRUCT, then assume it's a C struct */
+ fprintf_filtered (stream, "struct ");
+ }
+ goto struct_union;
+
+ case TYPE_CODE_UNION:
+ c_type_print_modifier (type, stream, 0, 1);
+ fprintf_filtered (stream, "union ");
+
+ struct_union:
+
+ /* Print the tag if it exists.
+ * The HP aCC compiler emits
+ * a spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed enum}"
+ * tag for unnamed struct/union/enum's, which we don't
+ * want to print.
+ */
+ if (TYPE_TAG_NAME (type) != NULL &&
+ strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (show > 0)
+ fputs_filtered (" ", stream);
+ }
+ wrap_here (" ");
+ if (show < 0)
+ {
+ /* If we just printed a tag name, no need to print anything else. */
+ if (TYPE_TAG_NAME (type) == NULL)
+ fprintf_filtered (stream, "{...}");
+ }
+ else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
+ {
+ cp_type_print_derivation_info (stream, type);
+
+ fprintf_filtered (stream, "{\n");
+ if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+ {
+ if (TYPE_STUB (type))
+ fprintfi_filtered (level + 4, stream, "<incomplete type>\n");
+ else
+ fprintfi_filtered (level + 4, stream, "<no data fields>\n");
+ }
+
+ /* Start off with no specific section type, so we can print
+ one for the first field we find, and use that section type
+ thereafter until we find another type. */
+
+ section_type = s_none;
+
+ /* For a class, if all members are private, there's no need
+ for a "private:" label; similarly, for a struct or union
+ masquerading as a class, if all members are public, there's
+ no need for a "public:" label. */
+
+ if ((TYPE_DECLARED_TYPE (type) == DECLARED_TYPE_CLASS) ||
+ (TYPE_DECLARED_TYPE (type) == DECLARED_TYPE_TEMPLATE))
+ {
+ QUIT;
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ if (!TYPE_FIELD_PRIVATE (type, i))
+ {
+ need_access_label = 1;
+ break;
+ }
+ QUIT;
+ if (!need_access_label)
+ {
+ len2 = TYPE_NFN_FIELDS (type);
+ for (j = 0; j < len2; j++)
+ {
+ len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+ for (i = 0; i < len; i++)
+ if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type, j), i))
+ {
+ need_access_label = 1;
+ break;
+ }
+ if (need_access_label)
+ break;
+ }
+ }
+ }
+ else if ((TYPE_DECLARED_TYPE (type) == DECLARED_TYPE_STRUCT) ||
+ (TYPE_DECLARED_TYPE (type) == DECLARED_TYPE_UNION))
+ {
+ QUIT;
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ if (TYPE_FIELD_PRIVATE (type, i) || TYPE_FIELD_PROTECTED (type, i))
+ {
+ need_access_label = 1;
+ break;
+ }
+ QUIT;
+ if (!need_access_label)
+ {
+ len2 = TYPE_NFN_FIELDS (type);
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+ for (i = 0; i < len; i++)
+ if (TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type, j), i) ||
+ TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type, j), i))
+ {
+ need_access_label = 1;
+ break;
+ }
+ if (need_access_label)
+ break;
+ }
+ }
+ }
+
+ /* If there is a base class for this type,
+ do not print the field that it occupies. */
+
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ QUIT;
+ /* Don't print out virtual function table. */
+ /* HP ANSI C++ case */
+ if (TYPE_HAS_VTABLE (type)
+ && (strncmp (TYPE_FIELD_NAME (type, i), "__vfp", 5) == 0))
+ continue;
+ /* Other compilers */
+ if (strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5) == 0
+ && 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) && need_access_label)
+ {
+ if (TYPE_FIELD_PROTECTED (type, i))
+ {
+ if (section_type != s_protected)
+ {
+ section_type = s_protected;
+ fprintfi_filtered (level + 2, stream,
+ "protected:\n");
+ }
+ }
+ else if (TYPE_FIELD_PRIVATE (type, i))
+ {
+ if (section_type != s_private)
+ {
+ section_type = s_private;
+ fprintfi_filtered (level + 2, stream, "private:\n");
+ }
+ }
+ else
+ {
+ if (section_type != s_public)
+ {
+ section_type = s_public;
+ fprintfi_filtered (level + 2, stream, "public:\n");
+ }
+ }
+ }
+
+ print_spaces_filtered (level + 4, stream);
+ if (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 blank line
+ between them. Make sure to count only method that we will
+ display; artificial methods will be hidden. */
+ len = TYPE_NFN_FIELDS (type);
+ real_len = 0;
+ for (i = 0; i < len; i++)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ int len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
+ int j;
+ for (j = 0; j < len2; j++)
+ if (!TYPE_FN_FIELD_ARTIFICIAL (f, j))
+ real_len++;
+ }
+ if (real_len > 0 && 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 && strcmp (method_name, name) == 0;
+ for (j = 0; j < len2; j++)
+ {
+ char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
+ int is_full_physname_constructor =
+ is_constructor_name (physname)
+ || is_destructor_name (physname)
+ || method_name[0] == '~';
+
+ /* Do not print out artificial methods. */
+ if (TYPE_FN_FIELD_ARTIFICIAL (f, j))
+ continue;
+
+ 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_filtered (stream, "<undefined type> %s;\n",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+ break;
+ }
+ else if (!is_constructor && /* constructors don't have declared types */
+ !is_full_physname_constructor && /* " " */
+ !is_type_conversion_operator (type, i, j))
+ {
+ 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);
+ else
+ mangled_name = TYPE_FN_FIELD_PHYSNAME (f, j);
+
+ demangled_name =
+ cplus_demangle (mangled_name,
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name == NULL)
+ {
+ /* in some cases (for instance with the HP demangling),
+ if a function has more than 10 arguments,
+ the demangling will fail.
+ Let's try to reconstruct the function signature from
+ the symbol information */
+ if (!TYPE_FN_FIELD_STUB (f, j))
+ {
+ int staticp = TYPE_FN_FIELD_STATIC_P (f, j);
+ struct type *mtype = TYPE_FN_FIELD_TYPE (f, j);
+ cp_type_print_method_args (mtype,
+ "",
+ method_name,
+ staticp,
+ stream);
+ }
+ else
+ fprintf_filtered (stream, "<badly mangled name '%s'>",
+ mangled_name);
+ }
+ else
+ {
+ char *p;
+ char *demangled_no_class
+ = remove_qualifiers (demangled_name);
+
+ /* get rid of the `static' appended by the demangler */
+ p = strstr (demangled_no_class, " static");
+ if (p != NULL)
+ {
+ int length = p - demangled_no_class;
+ demangled_no_static = (char *) xmalloc (length + 1);
+ strncpy (demangled_no_static, demangled_no_class, length);
+ *(demangled_no_static + length) = '\0';
+ fputs_filtered (demangled_no_static, stream);
+ xfree (demangled_no_static);
+ }
+ else
+ fputs_filtered (demangled_no_class, stream);
+ xfree (demangled_name);
+ }
+
+ if (TYPE_FN_FIELD_STUB (f, j))
+ xfree (mangled_name);
+
+ fprintf_filtered (stream, ";\n");
+ }
+ }
+
+ fprintfi_filtered (level, stream, "}");
+
+ if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
+ fprintfi_filtered (level, stream, " (Local at %s:%d)\n",
+ TYPE_LOCALTYPE_FILE (type),
+ TYPE_LOCALTYPE_LINE (type));
+ }
+ if (TYPE_CODE (type) == TYPE_CODE_TEMPLATE)
+ goto go_back;
+ break;
+
+ case TYPE_CODE_ENUM:
+ c_type_print_modifier (type, stream, 0, 1);
+ /* HP C supports sized enums */
+ if (hp_som_som_object_present)
+ switch (TYPE_LENGTH (type))
+ {
+ case 1:
+ fputs_filtered ("char ", stream);
+ break;
+ case 2:
+ fputs_filtered ("short ", stream);
+ break;
+ default:
+ break;
+ }
+ fprintf_filtered (stream, "enum ");
+ /* Print the tag name if it exists.
+ The aCC compiler emits a spurious
+ "{unnamed struct}"/"{unnamed union}"/"{unnamed enum}"
+ tag for unnamed struct/union/enum's, which we don't
+ want to print. */
+ if (TYPE_TAG_NAME (type) != NULL &&
+ strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (show > 0)
+ fputs_filtered (" ", stream);
+ }
+
+ wrap_here (" ");
+ if (show < 0)
+ {
+ /* If we just printed a tag name, no need to print anything else. */
+ if (TYPE_TAG_NAME (type) == NULL)
+ fprintf_filtered (stream, "{...}");
+ }
+ else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
+ {
+ 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 <unknown>");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<unknown type>");
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* This should not occur */
+ fprintf_filtered (stream, "<range type>");
+ break;
+
+ case TYPE_CODE_TEMPLATE:
+ /* Called on "ptype t" where "t" is a template.
+ Prints the template header (with args), e.g.:
+ template <class T1, class T2> class "
+ and then merges with the struct/union/class code to
+ print the rest of the definition. */
+ c_type_print_modifier (type, stream, 0, 1);
+ fprintf_filtered (stream, "template <");
+ for (i = 0; i < TYPE_NTEMPLATE_ARGS (type); i++)
+ {
+ struct template_arg templ_arg;
+ templ_arg = TYPE_TEMPLATE_ARG (type, i);
+ fprintf_filtered (stream, "class %s", templ_arg.name);
+ if (i < TYPE_NTEMPLATE_ARGS (type) - 1)
+ fprintf_filtered (stream, ", ");
+ }
+ fprintf_filtered (stream, "> class ");
+ /* Yuck, factor this out to a subroutine so we can call
+ it and return to the point marked with the "goback:" label... - RT */
+ goto struct_union;
+ go_back:
+ if (TYPE_NINSTANTIATIONS (type) > 0)
+ {
+ fprintf_filtered (stream, "\ntemplate instantiations:\n");
+ for (i = 0; i < TYPE_NINSTANTIATIONS (type); i++)
+ {
+ fprintf_filtered (stream, " ");
+ c_type_print_base (TYPE_INSTANTIATION (type, i), stream, 0, level);
+ if (i < TYPE_NINSTANTIATIONS (type) - 1)
+ fprintf_filtered (stream, "\n");
+ }
+ }
+ break;
+
+ case TYPE_CODE_NAMESPACE:
+ fputs_filtered ("namespace ", stream);
+ fputs_filtered (TYPE_TAG_NAME (type), 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)
+ {
+ c_type_print_modifier (type, stream, 0, 1);
+ fputs_filtered (TYPE_NAME (type), stream);
+ }
+ else
+ {
+ /* At least for dump_symtab, it is important that this not be
+ an error (). */
+ fprintf_filtered (stream, "<invalid type code %d>",
+ 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 0000000..fd42ae0
--- /dev/null
+++ b/contrib/gdb/gdb/c-valprint.c
@@ -0,0 +1,602 @@
+/* Support for printing C values for GDB, the GNU debugger.
+
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "valprint.h"
+#include "language.h"
+#include "c-lang.h"
+#include "cp-abi.h"
+#include "target.h"
+
+
+/* Print function pointer with inferior address ADDRESS onto stdio
+ stream STREAM. */
+
+static void
+print_function_pointer_address (CORE_ADDR address, struct ui_file *stream)
+{
+ CORE_ADDR func_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ address,
+ &current_target);
+
+ /* If the function pointer is represented by a description, print the
+ address of the description. */
+ if (addressprint && func_addr != address)
+ {
+ fputs_filtered ("@", stream);
+ print_address_numeric (address, 1, stream);
+ fputs_filtered (": ", stream);
+ }
+ print_address_demangle (func_addr, stream, demangle);
+}
+
+
+/* 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 (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ 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:
+ elttype = check_typedef (TYPE_TARGET_TYPE (type));
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ {
+ 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)
+ {
+ unsigned int temp_len;
+
+ /* Look for a NULL char. */
+ for (temp_len = 0;
+ (valaddr + embedded_offset)[temp_len]
+ && temp_len < len && temp_len < print_max;
+ temp_len++);
+ len = temp_len;
+ }
+
+ LA_PRINT_STRING (stream, valaddr + embedded_offset, len, eltlen, 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 + embedded_offset, 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 + embedded_offset, 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.) */
+ CORE_ADDR addr
+ = extract_typed_address (valaddr + embedded_offset, type);
+ print_function_pointer_address (addr, stream);
+ break;
+ }
+ elttype = check_typedef (TYPE_TARGET_TYPE (type));
+ if (TYPE_CODE (elttype) == TYPE_CODE_METHOD)
+ {
+ cp_print_class_method (valaddr + embedded_offset, type, stream);
+ }
+ else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
+ {
+ cp_print_class_member (valaddr + embedded_offset,
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
+ stream, "&");
+ }
+ else
+ {
+ addr = unpack_pointer (type, valaddr + embedded_offset);
+ print_unpacked_pointer:
+
+ if (TYPE_CODE (elttype) == TYPE_CODE_FUNC)
+ {
+ /* Try to print what function it points to. */
+ print_function_pointer_address (addr, stream);
+ /* 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. */
+ /* FIXME: need to handle wchar_t here... */
+
+ if (TYPE_LENGTH (elttype) == 1
+ && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && (format == 0 || format == 's')
+ && addr != 0)
+ {
+ i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream);
+ }
+ else if (cp_is_vtbl_member (type))
+ {
+ /* print vtbl's nicely */
+ CORE_ADDR vt_address = unpack_pointer (type, valaddr + embedded_offset);
+
+ 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_PRINT_NAME (msymbol), stream);
+ fputs_filtered (">", stream);
+ }
+ if (vt_address && vtblprint)
+ {
+ struct value *vt_val;
+ struct symbol *wsym = (struct symbol *) NULL;
+ struct type *wtype;
+ struct block *block = (struct block *) NULL;
+ int is_this_fld;
+
+ if (msymbol != NULL)
+ wsym = lookup_symbol (DEPRECATED_SYMBOL_NAME (msymbol), block,
+ VAR_DOMAIN, &is_this_fld, NULL);
+
+ if (wsym)
+ {
+ wtype = SYMBOL_TYPE (wsym);
+ }
+ else
+ {
+ wtype = TYPE_TARGET_TYPE (type);
+ }
+ vt_val = value_at (wtype, vt_address, NULL);
+ val_print (VALUE_TYPE (vt_val), VALUE_CONTENTS (vt_val), 0,
+ 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 + embedded_offset,
+ TYPE_DOMAIN_TYPE (elttype),
+ stream, "");
+ break;
+ }
+ if (addressprint)
+ {
+ CORE_ADDR addr
+ = extract_typed_address (valaddr + embedded_offset, type);
+ fprintf_filtered (stream, "@");
+ print_address_numeric (addr, 1, stream);
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
+ {
+ struct value *deref_val =
+ value_at
+ (TYPE_TARGET_TYPE (type),
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr + embedded_offset),
+ NULL);
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val),
+ 0,
+ VALUE_ADDRESS (deref_val),
+ stream,
+ format,
+ deref_ref,
+ recurse,
+ pretty);
+ }
+ else
+ fputs_filtered ("???", stream);
+ }
+ break;
+
+ case TYPE_CODE_UNION:
+ if (recurse && !unionprint)
+ {
+ fprintf_filtered (stream, "{...}");
+ break;
+ }
+ /* Fall through. */
+ case TYPE_CODE_STRUCT:
+ /*FIXME: Abstract this away */
+ 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.) */
+ int offset = (embedded_offset +
+ TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8);
+ struct type *field_type = TYPE_FIELD_TYPE (type, VTBL_FNADDR_OFFSET);
+ CORE_ADDR addr
+ = extract_typed_address (valaddr + offset, field_type);
+
+ print_function_pointer_address (addr, stream);
+ }
+ else
+ cp_print_value_fields (type, type, valaddr, embedded_offset, address, stream, format,
+ recurse, pretty, NULL, 0);
+ break;
+
+ case TYPE_CODE_ENUM:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ break;
+ }
+ len = TYPE_NFIELDS (type);
+ val = unpack_long (type, valaddr + embedded_offset);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (val == TYPE_FIELD_BITPOS (type, i))
+ {
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ else
+ {
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, 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 + embedded_offset, type, format, 0, stream);
+ else
+ {
+ val = unpack_long (type, valaddr + embedded_offset);
+ if (val == 0)
+ fputs_filtered ("false", stream);
+ else if (val == 1)
+ fputs_filtered ("true", stream);
+ else
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* FIXME: create_range_type does not set the unsigned bit in a
+ range type (I think it probably should copy it from the target
+ type), so we won't print values which are too large to
+ fit in a signed integer correctly. */
+ /* FIXME: Doesn't handle ranges of enums correctly. (Can't just
+ print with the target type, though, because the size of our type
+ and the target type might differ). */
+ /* FALLTHROUGH */
+
+ case TYPE_CODE_INT:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ }
+ else
+ {
+ val_print_type_code_int (type, valaddr + embedded_offset, 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 + embedded_offset),
+ stream);
+ }
+ }
+ break;
+
+ case TYPE_CODE_CHAR:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ }
+ else
+ {
+ val = unpack_long (type, valaddr + embedded_offset);
+ if (TYPE_UNSIGNED (type))
+ fprintf_filtered (stream, "%u", (unsigned int) val);
+ else
+ fprintf_filtered (stream, "%d", (int) val);
+ fputs_filtered (" ", stream);
+ LA_PRINT_CHAR ((unsigned char) val, stream);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ }
+ else
+ {
+ print_floating (valaddr + embedded_offset, type, stream);
+ }
+ break;
+
+ case TYPE_CODE_METHOD:
+ {
+ struct value *v = value_at (type, address, NULL);
+ cp_print_class_method (VALUE_CONTENTS (value_addr (v)),
+ lookup_pointer_type (type), stream);
+ break;
+ }
+
+ case TYPE_CODE_VOID:
+ fprintf_filtered (stream, "void");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<error type>");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+ dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+ and no complete type for struct foo in that file. */
+ fprintf_filtered (stream, "<incomplete type>");
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ if (format)
+ print_scalar_formatted (valaddr + embedded_offset,
+ TYPE_TARGET_TYPE (type),
+ format, 0, stream);
+ else
+ print_floating (valaddr + embedded_offset, TYPE_TARGET_TYPE (type),
+ stream);
+ fprintf_filtered (stream, " + ");
+ if (format)
+ print_scalar_formatted (valaddr + embedded_offset
+ + TYPE_LENGTH (TYPE_TARGET_TYPE (type)),
+ TYPE_TARGET_TYPE (type),
+ format, 0, stream);
+ else
+ print_floating (valaddr + embedded_offset
+ + TYPE_LENGTH (TYPE_TARGET_TYPE (type)),
+ TYPE_TARGET_TYPE (type),
+ stream);
+ fprintf_filtered (stream, " * I");
+ break;
+
+ default:
+ error ("Invalid C/C++ type code %d in symbol table.", TYPE_CODE (type));
+ }
+ gdb_flush (stream);
+ return (0);
+}
+
+int
+c_value_print (struct value *val, struct ui_file *stream, int format,
+ enum val_prettyprint pretty)
+{
+ struct type *type = VALUE_TYPE (val);
+ struct type *real_type;
+ int full, top, using_enc;
+
+ /* 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 &&
+ strcmp (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char") == 0)
+ {
+ /* Print nothing */
+ }
+ else if (objectprint && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
+ {
+
+ if (TYPE_CODE(type) == TYPE_CODE_REF)
+ {
+ /* Copy value, change to pointer, so we don't get an
+ * error about a non-pointer type in value_rtti_target_type
+ */
+ struct value *temparg;
+ temparg=value_copy(val);
+ VALUE_TYPE (temparg) = lookup_pointer_type(TYPE_TARGET_TYPE(type));
+ val=temparg;
+ }
+ /* Pointer to class, check real type of object */
+ fprintf_filtered (stream, "(");
+ real_type = value_rtti_target_type (val, &full, &top, &using_enc);
+ if (real_type)
+ {
+ /* RTTI entry found */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ {
+ /* create a pointer type pointing to the real type */
+ type = lookup_pointer_type (real_type);
+ }
+ else
+ {
+ /* create a reference type referencing the real type */
+ type = lookup_reference_type (real_type);
+ }
+ /* JYG: Need to adjust pointer value. */
+ val->aligner.contents[0] -= top;
+
+ /* Note: When we look up RTTI entries, we don't get any
+ information on const or volatile attributes */
+ }
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") ");
+ }
+ else
+ {
+ /* normal case */
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") ");
+ }
+ }
+ if (objectprint && (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_CLASS))
+ {
+ /* Attempt to determine real type of object */
+ real_type = value_rtti_type (val, &full, &top, &using_enc);
+ if (real_type)
+ {
+ /* We have RTTI information, so use it */
+ val = value_full_object (val, real_type, full, top, using_enc);
+ fprintf_filtered (stream, "(%s%s) ",
+ TYPE_NAME (real_type),
+ full ? "" : " [incomplete object]");
+ /* Print out object: enclosing type is same as real_type if full */
+ return val_print (VALUE_ENCLOSING_TYPE (val), VALUE_CONTENTS_ALL (val), 0,
+ VALUE_ADDRESS (val), stream, format, 1, 0, pretty);
+ /* Note: When we look up RTTI entries, we don't get any information on
+ const or volatile attributes */
+ }
+ else if (type != VALUE_ENCLOSING_TYPE (val))
+ {
+ /* No RTTI information, so let's do our best */
+ fprintf_filtered (stream, "(%s ?) ",
+ TYPE_NAME (VALUE_ENCLOSING_TYPE (val)));
+ return val_print (VALUE_ENCLOSING_TYPE (val), VALUE_CONTENTS_ALL (val), 0,
+ VALUE_ADDRESS (val), stream, format, 1, 0, pretty);
+ }
+ /* Otherwise, we end up at the return outside this "if" */
+ }
+
+ return val_print (type, VALUE_CONTENTS_ALL (val),
+ VALUE_EMBEDDED_OFFSET (val),
+ VALUE_ADDRESS (val) + VALUE_OFFSET (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 0000000..3d2cda1
--- /dev/null
+++ b/contrib/gdb/gdb/call-cmds.h
@@ -0,0 +1,35 @@
+/* ***DEPRECATED*** The gdblib files must not be calling/using things in any
+ of the possible command languages. If necessary, a hook (that may be
+ present or not) must be used and set to the appropriate routine by any
+ command language that cares about it. If you are having to include this
+ file you are possibly doing things the old way. This file will disapear.
+ 2000-12-01 fnasser@redhat.com */
+
+/* Prototypes for GDB commands that are called internally by other functions.
+ Copyright 1992, 2000, 2001 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 CALL_CMDS_H
+#define CALL_CMDS_H
+
+extern void initialize_all_files (void);
+
+extern void core_file_command (char *, int);
+
+extern void break_command (char *, int);
+
+#endif
diff --git a/contrib/gdb/gdb/charset.c b/contrib/gdb/gdb/charset.c
new file mode 100644
index 0000000..2005a49
--- /dev/null
+++ b/contrib/gdb/gdb/charset.c
@@ -0,0 +1,1277 @@
+/* Character set conversion support for GDB.
+
+ Copyright 2001, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "charset.h"
+#include "gdbcmd.h"
+#include "gdb_assert.h"
+
+#include <stddef.h>
+#include "gdb_string.h"
+#include <ctype.h>
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+
+/* How GDB's character set support works
+
+ GDB has two global settings:
+
+ - The `current host character set' is the character set GDB should
+ use in talking to the user, and which (hopefully) the user's
+ terminal knows how to display properly.
+
+ - The `current target character set' is the character set the
+ program being debugged uses.
+
+ There are commands to set each of these, and mechanisms for
+ choosing reasonable default values. GDB has a global list of
+ character sets that it can use as its host or target character
+ sets.
+
+ The header file `charset.h' declares various functions that
+ different pieces of GDB need to perform tasks like:
+
+ - printing target strings and characters to the user's terminal
+ (mostly target->host conversions),
+
+ - building target-appropriate representations of strings and
+ characters the user enters in expressions (mostly host->target
+ conversions),
+
+ and so on.
+
+ Now, many of these operations are specific to a particular
+ host/target character set pair. If GDB supports N character sets,
+ there are N^2 possible pairs. This means that, the larger GDB's
+ repertoire of character sets gets, the more expensive it gets to add
+ new character sets.
+
+ To make sure that GDB can do the right thing for every possible
+ pairing of host and target character set, while still allowing
+ GDB's repertoire to scale, we use a two-tiered approach:
+
+ - We maintain a global table of "translations" --- groups of
+ functions specific to a particular pair of character sets.
+
+ - However, a translation can be incomplete: some functions can be
+ omitted. Where there is not a translation to specify exactly
+ what function to use, we provide reasonable defaults. The
+ default behaviors try to use the "iconv" library functions, which
+ support a wide range of character sets. However, even if iconv
+ is not available, there are fallbacks to support trivial
+ translations: when the host and target character sets are the
+ same. */
+
+
+/* The character set and translation structures. */
+
+
+/* A character set GDB knows about. GDB only supports character sets
+ with stateless encodings, in which every character is one byte
+ long. */
+struct charset {
+
+ /* A singly-linked list of all known charsets. */
+ struct charset *next;
+
+ /* The name of the character set. Comparisons on character set
+ names are case-sensitive. */
+ const char *name;
+
+ /* Non-zero iff this character set can be used as a host character
+ set. At present, GDB basically assumes that the host character
+ set is a superset of ASCII. */
+ int valid_host_charset;
+
+ /* Pointers to charset-specific functions that depend only on a
+ single character set, and data pointers to pass to them. */
+ int (*host_char_print_literally) (void *baton,
+ int host_char);
+ void *host_char_print_literally_baton;
+
+ int (*target_char_to_control_char) (void *baton,
+ int target_char,
+ int *target_ctrl_char);
+ void *target_char_to_control_char_baton;
+};
+
+
+/* A translation from one character set to another. */
+struct translation {
+
+ /* A singly-linked list of all known translations. */
+ struct translation *next;
+
+ /* This structure describes functions going from the FROM character
+ set to the TO character set. Comparisons on character set names
+ are case-sensitive. */
+ const char *from, *to;
+
+ /* Pointers to translation-specific functions, and data pointers to
+ pass to them. These pointers can be zero, indicating that GDB
+ should fall back on the default behavior. We hope the default
+ behavior will be correct for many from/to pairs, reducing the
+ number of translations that need to be registered explicitly. */
+
+ /* TARGET_CHAR is in the `from' charset.
+ Returns a string in the `to' charset. */
+ const char *(*c_target_char_has_backslash_escape) (void *baton,
+ int target_char);
+ void *c_target_char_has_backslash_escape_baton;
+
+ /* HOST_CHAR is in the `from' charset.
+ TARGET_CHAR points to a char in the `to' charset. */
+ int (*c_parse_backslash) (void *baton, int host_char, int *target_char);
+ void *c_parse_backslash_baton;
+
+ /* This is used for the host_char_to_target and target_char_to_host
+ functions. */
+ int (*convert_char) (void *baton, int from, int *to);
+ void *convert_char_baton;
+};
+
+
+
+/* The global lists of character sets and translations. */
+
+
+#ifndef GDB_DEFAULT_HOST_CHARSET
+#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1"
+#endif
+
+#ifndef GDB_DEFAULT_TARGET_CHARSET
+#define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1"
+#endif
+
+static const char *host_charset_name = GDB_DEFAULT_HOST_CHARSET;
+static const char *target_charset_name = GDB_DEFAULT_TARGET_CHARSET;
+
+static const char *host_charset_enum[] =
+{
+ "ASCII",
+ "ISO-8859-1",
+ 0
+};
+
+static const char *target_charset_enum[] =
+{
+ "ASCII",
+ "ISO-8859-1",
+ "EBCDIC-US",
+ "IBM1047",
+ 0
+};
+
+/* The global list of all the charsets GDB knows about. */
+static struct charset *all_charsets;
+
+
+static void
+register_charset (struct charset *cs)
+{
+ struct charset **ptr;
+
+ /* Put the new charset on the end, so that the list ends up in the
+ same order as the registrations in the _initialize function. */
+ for (ptr = &all_charsets; *ptr; ptr = &(*ptr)->next)
+ ;
+
+ cs->next = 0;
+ *ptr = cs;
+}
+
+
+static struct charset *
+lookup_charset (const char *name)
+{
+ struct charset *cs;
+
+ for (cs = all_charsets; cs; cs = cs->next)
+ if (! strcmp (name, cs->name))
+ return cs;
+
+ return NULL;
+}
+
+
+/* The global list of translations. */
+static struct translation *all_translations;
+
+
+static void
+register_translation (struct translation *t)
+{
+ t->next = all_translations;
+ all_translations = t;
+}
+
+
+static struct translation *
+lookup_translation (const char *from, const char *to)
+{
+ struct translation *t;
+
+ for (t = all_translations; t; t = t->next)
+ if (! strcmp (from, t->from)
+ && ! strcmp (to, t->to))
+ return t;
+
+ return 0;
+}
+
+
+
+/* Constructing charsets. */
+
+/* Allocate, initialize and return a straightforward charset.
+ Use this function, rather than creating the structures yourself,
+ so that we can add new fields to the structure in the future without
+ having to tweak all the old charset descriptions. */
+static struct charset *
+simple_charset (const char *name,
+ int valid_host_charset,
+ int (*host_char_print_literally) (void *baton, int host_char),
+ void *host_char_print_literally_baton,
+ int (*target_char_to_control_char) (void *baton,
+ int target_char,
+ int *target_ctrl_char),
+ void *target_char_to_control_char_baton)
+{
+ struct charset *cs = xmalloc (sizeof (*cs));
+
+ memset (cs, 0, sizeof (*cs));
+ cs->name = name;
+ cs->valid_host_charset = valid_host_charset;
+ cs->host_char_print_literally = host_char_print_literally;
+ cs->host_char_print_literally_baton = host_char_print_literally_baton;
+ cs->target_char_to_control_char = target_char_to_control_char;
+ cs->target_char_to_control_char_baton = target_char_to_control_char_baton;
+
+ return cs;
+}
+
+
+
+/* ASCII functions. */
+
+static int
+ascii_print_literally (void *baton, int c)
+{
+ c &= 0xff;
+
+ return (0x20 <= c && c <= 0x7e);
+}
+
+
+static int
+ascii_to_control (void *baton, int c, int *ctrl_char)
+{
+ *ctrl_char = (c & 037);
+ return 1;
+}
+
+
+/* ISO-8859 family functions. */
+
+
+static int
+iso_8859_print_literally (void *baton, int c)
+{
+ c &= 0xff;
+
+ return ((0x20 <= c && c <= 0x7e) /* ascii printables */
+ || (! sevenbit_strings && 0xA0 <= c)); /* iso 8859 printables */
+}
+
+
+static int
+iso_8859_to_control (void *baton, int c, int *ctrl_char)
+{
+ *ctrl_char = (c & 0200) | (c & 037);
+ return 1;
+}
+
+
+/* Construct an ISO-8859-like character set. */
+static struct charset *
+iso_8859_family_charset (const char *name)
+{
+ return simple_charset (name, 1,
+ iso_8859_print_literally, 0,
+ iso_8859_to_control, 0);
+}
+
+
+
+/* EBCDIC family functions. */
+
+
+static int
+ebcdic_print_literally (void *baton, int c)
+{
+ c &= 0xff;
+
+ return (64 <= c && c <= 254);
+}
+
+
+static int
+ebcdic_to_control (void *baton, int c, int *ctrl_char)
+{
+ /* There are no control character equivalents in EBCDIC. Use
+ numeric escapes. */
+ return 0;
+}
+
+
+/* Construct an EBCDIC-like character set. */
+static struct charset *
+ebcdic_family_charset (const char *name)
+{
+ return simple_charset (name, 0,
+ ebcdic_print_literally, 0,
+ ebcdic_to_control, 0);
+}
+
+
+
+
+
+/* Fallback functions using iconv. */
+
+#if defined(HAVE_ICONV)
+
+struct cached_iconv {
+ struct charset *from, *to;
+ iconv_t i;
+};
+
+
+/* Make sure the iconv cache *CI contains an iconv descriptor
+ translating from FROM to TO. If it already does, fine; otherwise,
+ close any existing descriptor, and open up a new one. On success,
+ return zero; on failure, return -1 and set errno. */
+static int
+check_iconv_cache (struct cached_iconv *ci,
+ struct charset *from,
+ struct charset *to)
+{
+ iconv_t i;
+
+ /* Does the cached iconv descriptor match the conversion we're trying
+ to do now? */
+ if (ci->from == from
+ && ci->to == to
+ && ci->i != (iconv_t) 0)
+ return 0;
+
+ /* It doesn't. If we actually had any iconv descriptor open at
+ all, close it now. */
+ if (ci->i != (iconv_t) 0)
+ {
+ i = ci->i;
+ ci->i = (iconv_t) 0;
+
+ if (iconv_close (i) == -1)
+ error ("Error closing `iconv' descriptor for "
+ "`%s'-to-`%s' character conversion: %s",
+ ci->from->name, ci->to->name, safe_strerror (errno));
+ }
+
+ /* Open a new iconv descriptor for the required conversion. */
+ i = iconv_open (to->name, from->name);
+ if (i == (iconv_t) -1)
+ return -1;
+
+ ci->i = i;
+ ci->from = from;
+ ci->to = to;
+
+ return 0;
+}
+
+
+/* Convert FROM_CHAR using the cached iconv conversion *CI. Return
+ non-zero if the conversion was successful, zero otherwise. */
+static int
+cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char)
+{
+ char from;
+ ICONV_CONST char *from_ptr = &from;
+ char to, *to_ptr = &to;
+ size_t from_left = sizeof (from), to_left = sizeof (to);
+
+ gdb_assert (ci->i != (iconv_t) 0);
+
+ from = from_char;
+ if (iconv (ci->i, &from_ptr, &from_left, &to_ptr, &to_left)
+ == (size_t) -1)
+ {
+ /* These all suggest that the input or output character sets
+ have multi-byte encodings of some characters, which means
+ it's unsuitable for use as a GDB character set. We should
+ never have selected it. */
+ gdb_assert (errno != E2BIG && errno != EINVAL);
+
+ /* This suggests a bug in the code managing *CI. */
+ gdb_assert (errno != EBADF);
+
+ /* This seems to mean that there is no equivalent character in
+ the `to' character set. */
+ if (errno == EILSEQ)
+ return 0;
+
+ /* Anything else is mysterious. */
+ internal_error (__FILE__, __LINE__,
+ "Error converting character `%d' from `%s' to `%s' "
+ "character set: %s",
+ from_char, ci->from->name, ci->to->name,
+ safe_strerror (errno));
+ }
+
+ /* If the pointers weren't advanced across the input, that also
+ suggests something was wrong. */
+ gdb_assert (from_left == 0 && to_left == 0);
+
+ *to_char = (unsigned char) to;
+ return 1;
+}
+
+
+static void
+register_iconv_charsets (void)
+{
+ /* Here we should check whether various character sets were
+ recognized by the local iconv implementation.
+
+ The first implementation registered a bunch of character sets
+ recognized by iconv, but then we discovered that iconv on Solaris
+ and iconv on GNU/Linux had no character sets in common. So we
+ replaced them with the hard-coded tables that appear later in the
+ file. */
+}
+
+#endif /* defined (HAVE_ICONV) */
+
+
+/* Fallback routines for systems without iconv. */
+
+#if ! defined (HAVE_ICONV)
+struct cached_iconv { char nothing; };
+
+static int
+check_iconv_cache (struct cached_iconv *ci,
+ struct charset *from,
+ struct charset *to)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+static int
+cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char)
+{
+ /* This function should never be called. */
+ gdb_assert (0);
+}
+
+static void
+register_iconv_charsets (void)
+{
+}
+
+#endif /* ! defined(HAVE_ICONV) */
+
+
+/* Default trivial conversion functions. */
+
+static int
+identity_either_char_to_other (void *baton, int either_char, int *other_char)
+{
+ *other_char = either_char;
+ return 1;
+}
+
+
+
+/* Default non-trivial conversion functions. */
+
+
+static char backslashable[] = "abfnrtv";
+static char *backslashed[] = {"a", "b", "f", "n", "r", "t", "v", "0"};
+static char represented[] = "\a\b\f\n\r\t\v";
+
+
+/* Translate TARGET_CHAR into the host character set, and see if it
+ matches any of our standard escape sequences. */
+static const char *
+default_c_target_char_has_backslash_escape (void *baton, int target_char)
+{
+ int host_char;
+ const char *ix;
+
+ /* If target_char has no equivalent in the host character set,
+ assume it doesn't have a backslashed form. */
+ if (! target_char_to_host (target_char, &host_char))
+ return NULL;
+
+ ix = strchr (represented, host_char);
+ if (ix)
+ return backslashed[ix - represented];
+ else
+ return NULL;
+}
+
+
+/* Translate the backslash the way we would in the host character set,
+ and then try to translate that into the target character set. */
+static int
+default_c_parse_backslash (void *baton, int host_char, int *target_char)
+{
+ const char *ix;
+
+ ix = strchr (backslashable, host_char);
+
+ if (! ix)
+ return 0;
+ else
+ return host_char_to_target (represented[ix - backslashable],
+ target_char);
+}
+
+
+/* Convert using a cached iconv descriptor. */
+static int
+iconv_convert (void *baton, int from_char, int *to_char)
+{
+ struct cached_iconv *ci = baton;
+ return cached_iconv_convert (ci, from_char, to_char);
+}
+
+
+
+/* Conversion tables. */
+
+
+/* I'd much rather fall back on iconv whenever possible. But the
+ character set names you use with iconv aren't standardized at all,
+ a lot of platforms have really meager character set coverage, etc.
+ I wanted to have at least something we could use to exercise the
+ test suite on all platforms.
+
+ In the long run, we should have a configure-time process explore
+ somehow which character sets the host platform supports, and some
+ arrangement that allows GDB users to use platform-indepedent names
+ for character sets. */
+
+
+/* We generated these tables using iconv on a GNU/Linux machine. */
+
+
+static int ascii_to_iso_8859_1_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */
+ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */
+};
+
+
+static int ascii_to_ebcdic_us_table[] = {
+ 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
+ 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
+ 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
+ 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
+ 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */
+ 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
+ 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */
+};
+
+
+static int ascii_to_ibm1047_table[] = {
+ 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
+ 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
+ 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
+ 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
+ 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */
+ 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
+ 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */
+};
+
+
+static int iso_8859_1_to_ascii_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */
+ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */
+};
+
+
+static int iso_8859_1_to_ebcdic_us_table[] = {
+ 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
+ 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
+ 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
+ 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
+ 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */
+ 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
+ 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */
+ 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */
+ 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */
+ -1, -1, 74, -1, -1, -1,106, -1, -1, -1, -1, -1, 95, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */
+};
+
+
+static int iso_8859_1_to_ibm1047_table[] = {
+ 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
+ 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
+ 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
+ 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
+ 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */
+ 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
+ 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */
+ 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */
+ 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */
+ 65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188, /* 176 */
+ 144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171, /* 192 */
+ 100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119, /* 208 */
+ 172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89, /* 224 */
+ 68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87, /* 240 */
+ 140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223 /* 256 */
+};
+
+
+static int ebcdic_us_to_ascii_table[] = {
+ 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */
+ -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, /* 48 */
+ -1, -1, 22, -1, -1, -1, -1, 4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */
+ 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */
+ 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, -1, /* 96 */
+ 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */
+ -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */
+ 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */
+ 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /* 256 */
+};
+
+
+static int ebcdic_us_to_iso_8859_1_table[] = {
+ 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19,157,133, 8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */
+ 128,129,130,131,132, 10, 23, 27,136,137,138,139,140, 5, 6, 7, /* 48 */
+ 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26, /* 64 */
+ 32, -1, -1, -1, -1, -1, -1, -1, -1, -1,162, 46, 60, 40, 43,124, /* 80 */
+ 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59,172, /* 96 */
+ 45, 47, -1, -1, -1, -1, -1, -1, -1, -1,166, 44, 37, 95, 62, 63, /* 112 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */
+ -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */
+ 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */
+ 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,159 /* 256 */
+};
+
+
+static int ebcdic_us_to_ibm1047_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
+ 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */
+ 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94,176, /* 96 */
+ 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */
+ -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ 192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */
+ 208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */
+ 224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */
+ 240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255 /* 256 */
+};
+
+
+static int ibm1047_to_ascii_table[] = {
+ 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */
+ -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, /* 48 */
+ -1, -1, 22, -1, -1, -1, -1, 4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */
+ 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */
+ 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, 94, /* 96 */
+ 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */
+ -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, 91, -1, -1, /* 176 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, /* 192 */
+ 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */
+ 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */
+ 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /* 256 */
+};
+
+
+static int ibm1047_to_iso_8859_1_table[] = {
+ 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19,157,133, 8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */
+ 128,129,130,131,132, 10, 23, 27,136,137,138,139,140, 5, 6, 7, /* 48 */
+ 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26, /* 64 */
+ 32,160,226,228,224,225,227,229,231,241,162, 46, 60, 40, 43,124, /* 80 */
+ 38,233,234,235,232,237,238,239,236,223, 33, 36, 42, 41, 59, 94, /* 96 */
+ 45, 47,194,196,192,193,195,197,199,209,166, 44, 37, 95, 62, 63, /* 112 */
+ 248,201,202,203,200,205,206,207,204, 96, 58, 35, 64, 39, 61, 34, /* 128 */
+ 216, 97, 98, 99,100,101,102,103,104,105,171,187,240,253,254,177, /* 144 */
+ 176,106,107,108,109,110,111,112,113,114,170,186,230,184,198,164, /* 160 */
+ 181,126,115,116,117,118,119,120,121,122,161,191,208, 91,222,174, /* 176 */
+ 172,163,165,183,169,167,182,188,189,190,221,168,175, 93,180,215, /* 192 */
+ 123, 65, 66, 67, 68, 69, 70, 71, 72, 73,173,244,246,242,243,245, /* 208 */
+ 125, 74, 75, 76, 77, 78, 79, 80, 81, 82,185,251,252,249,250,255, /* 224 */
+ 92,247, 83, 84, 85, 86, 87, 88, 89, 90,178,212,214,210,211,213, /* 240 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,179,219,220,217,218,159 /* 256 */
+};
+
+
+static int ibm1047_to_ebcdic_us_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
+ 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */
+ 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94, -1, /* 96 */
+ 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */
+ -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */
+ -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */
+ -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */
+ 95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
+ 192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */
+ 208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */
+ 224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */
+ 240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255 /* 256 */
+};
+
+
+static int
+table_convert_char (void *baton, int from, int *to)
+{
+ int *table = (int *) baton;
+
+ if (0 <= from && from <= 255
+ && table[from] != -1)
+ {
+ *to = table[from];
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static struct translation *
+table_translation (const char *from, const char *to, int *table,
+ const char *(*c_target_char_has_backslash_escape)
+ (void *baton, int target_char),
+ void *c_target_char_has_backslash_escape_baton,
+ int (*c_parse_backslash) (void *baton,
+ int host_char,
+ int *target_char),
+ void *c_parse_backslash_baton)
+{
+ struct translation *t = xmalloc (sizeof (*t));
+
+ memset (t, 0, sizeof (*t));
+ t->from = from;
+ t->to = to;
+ t->c_target_char_has_backslash_escape = c_target_char_has_backslash_escape;
+ t->c_target_char_has_backslash_escape_baton
+ = c_target_char_has_backslash_escape_baton;
+ t->c_parse_backslash = c_parse_backslash;
+ t->c_parse_backslash_baton = c_parse_backslash_baton;
+ t->convert_char = table_convert_char;
+ t->convert_char_baton = (void *) table;
+
+ return t;
+}
+
+
+static struct translation *
+simple_table_translation (const char *from, const char *to, int *table)
+{
+ return table_translation (from, to, table, 0, 0, 0, 0);
+}
+
+
+
+/* Setting and retrieving the host and target charsets. */
+
+
+/* The current host and target character sets. */
+static struct charset *current_host_charset, *current_target_charset;
+
+/* The current functions and batons we should use for the functions in
+ charset.h. */
+
+static const char *(*c_target_char_has_backslash_escape_func)
+ (void *baton, int target_char);
+static void *c_target_char_has_backslash_escape_baton;
+
+static int (*c_parse_backslash_func) (void *baton,
+ int host_char,
+ int *target_char);
+static void *c_parse_backslash_baton;
+
+static int (*host_char_to_target_func) (void *baton,
+ int host_char,
+ int *target_char);
+static void *host_char_to_target_baton;
+
+static int (*target_char_to_host_func) (void *baton,
+ int target_char,
+ int *host_char);
+static void *target_char_to_host_baton;
+
+
+/* Cached iconv conversions, that might be useful to fallback
+ routines. */
+static struct cached_iconv cached_iconv_host_to_target;
+static struct cached_iconv cached_iconv_target_to_host;
+
+
+/* Charset structures manipulation functions. */
+
+static struct charset *
+lookup_charset_or_error (const char *name)
+{
+ struct charset *cs = lookup_charset (name);
+
+ if (! cs)
+ error ("GDB doesn't know of any character set named `%s'.", name);
+
+ return cs;
+}
+
+static void
+check_valid_host_charset (struct charset *cs)
+{
+ if (! cs->valid_host_charset)
+ error ("GDB can't use `%s' as its host character set.", cs->name);
+}
+
+/* Set the host and target character sets to HOST and TARGET. */
+static void
+set_host_and_target_charsets (struct charset *host, struct charset *target)
+{
+ struct translation *h2t, *t2h;
+
+ /* If they're not both initialized yet, then just do nothing for
+ now. As soon as we're done running our initialize function,
+ everything will be initialized. */
+ if (! host || ! target)
+ {
+ current_host_charset = host;
+ current_target_charset = target;
+ return;
+ }
+
+ h2t = lookup_translation (host->name, target->name);
+ t2h = lookup_translation (target->name, host->name);
+
+ /* If the translations don't provide conversion functions, make sure
+ iconv can back them up. Do this *before* modifying any state. */
+ if (host != target)
+ {
+ if (! h2t || ! h2t->convert_char)
+ {
+ if (check_iconv_cache (&cached_iconv_host_to_target, host, target)
+ < 0)
+ error ("GDB can't convert from the `%s' character set to `%s'.",
+ host->name, target->name);
+ }
+ if (! t2h || ! t2h->convert_char)
+ {
+ if (check_iconv_cache (&cached_iconv_target_to_host, target, host)
+ < 0)
+ error ("GDB can't convert from the `%s' character set to `%s'.",
+ target->name, host->name);
+ }
+ }
+
+ if (t2h && t2h->c_target_char_has_backslash_escape)
+ {
+ c_target_char_has_backslash_escape_func
+ = t2h->c_target_char_has_backslash_escape;
+ c_target_char_has_backslash_escape_baton
+ = t2h->c_target_char_has_backslash_escape_baton;
+ }
+ else
+ c_target_char_has_backslash_escape_func
+ = default_c_target_char_has_backslash_escape;
+
+ if (h2t && h2t->c_parse_backslash)
+ {
+ c_parse_backslash_func = h2t->c_parse_backslash;
+ c_parse_backslash_baton = h2t->c_parse_backslash_baton;
+ }
+ else
+ c_parse_backslash_func = default_c_parse_backslash;
+
+ if (h2t && h2t->convert_char)
+ {
+ host_char_to_target_func = h2t->convert_char;
+ host_char_to_target_baton = h2t->convert_char_baton;
+ }
+ else if (host == target)
+ host_char_to_target_func = identity_either_char_to_other;
+ else
+ {
+ host_char_to_target_func = iconv_convert;
+ host_char_to_target_baton = &cached_iconv_host_to_target;
+ }
+
+ if (t2h && t2h->convert_char)
+ {
+ target_char_to_host_func = t2h->convert_char;
+ target_char_to_host_baton = t2h->convert_char_baton;
+ }
+ else if (host == target)
+ target_char_to_host_func = identity_either_char_to_other;
+ else
+ {
+ target_char_to_host_func = iconv_convert;
+ target_char_to_host_baton = &cached_iconv_target_to_host;
+ }
+
+ current_host_charset = host;
+ current_target_charset = target;
+}
+
+/* Do the real work of setting the host charset. */
+static void
+set_host_charset (const char *charset)
+{
+ struct charset *cs = lookup_charset_or_error (charset);
+ check_valid_host_charset (cs);
+ set_host_and_target_charsets (cs, current_target_charset);
+}
+
+/* Do the real work of setting the target charset. */
+static void
+set_target_charset (const char *charset)
+{
+ struct charset *cs = lookup_charset_or_error (charset);
+
+ set_host_and_target_charsets (current_host_charset, cs);
+}
+
+
+/* 'Set charset', 'set host-charset', 'set target-charset', 'show
+ charset' sfunc's. */
+
+/* This is the sfunc for the 'set charset' command. */
+static void
+set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c)
+{
+ struct charset *cs = lookup_charset_or_error (host_charset_name);
+ check_valid_host_charset (cs);
+ /* CAREFUL: set the target charset here as well. */
+ target_charset_name = host_charset_name;
+ set_host_and_target_charsets (cs, cs);
+}
+
+/* 'set host-charset' command sfunc. We need a wrapper here because
+ the function needs to have a specific signature. */
+static void
+set_host_charset_sfunc (char *charset, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_host_charset (host_charset_name);
+}
+
+/* Wrapper for the 'set target-charset' command. */
+static void
+set_target_charset_sfunc (char *charset, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_target_charset (target_charset_name);
+}
+
+/* sfunc for the 'show charset' command. */
+static void
+show_charset (char *arg, int from_tty)
+{
+ if (current_host_charset == current_target_charset)
+ {
+ printf_filtered ("The current host and target character set is `%s'.\n",
+ host_charset ());
+ }
+ else
+ {
+ printf_filtered ("The current host character set is `%s'.\n",
+ host_charset ());
+ printf_filtered ("The current target character set is `%s'.\n",
+ target_charset ());
+ }
+}
+
+
+/* Accessor functions. */
+
+const char *
+host_charset (void)
+{
+ return current_host_charset->name;
+}
+
+const char *
+target_charset (void)
+{
+ return current_target_charset->name;
+}
+
+
+
+/* Public character management functions. */
+
+
+const char *
+c_target_char_has_backslash_escape (int target_char)
+{
+ return ((*c_target_char_has_backslash_escape_func)
+ (c_target_char_has_backslash_escape_baton, target_char));
+}
+
+
+int
+c_parse_backslash (int host_char, int *target_char)
+{
+ return (*c_parse_backslash_func) (c_parse_backslash_baton,
+ host_char, target_char);
+}
+
+
+int
+host_char_print_literally (int host_char)
+{
+ return ((*current_host_charset->host_char_print_literally)
+ (current_host_charset->host_char_print_literally_baton,
+ host_char));
+}
+
+
+int
+target_char_to_control_char (int target_char, int *target_ctrl_char)
+{
+ return ((*current_target_charset->target_char_to_control_char)
+ (current_target_charset->target_char_to_control_char_baton,
+ target_char, target_ctrl_char));
+}
+
+
+int
+host_char_to_target (int host_char, int *target_char)
+{
+ return ((*host_char_to_target_func)
+ (host_char_to_target_baton, host_char, target_char));
+}
+
+
+int
+target_char_to_host (int target_char, int *host_char)
+{
+ return ((*target_char_to_host_func)
+ (target_char_to_host_baton, target_char, host_char));
+}
+
+
+
+/* The charset.c module initialization function. */
+
+extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */
+
+void
+_initialize_charset (void)
+{
+ struct cmd_list_element *new_cmd;
+
+ /* Register all the character set GDB knows about.
+
+ You should use the same names that iconv does, where possible, to
+ take advantage of the iconv-based default behaviors.
+
+ CAUTION: if you register a character set, you must also register
+ as many translations as are necessary to make that character set
+ interoperate correctly with all the other character sets. We do
+ provide default behaviors when no translation is available, or
+ when a translation's function pointer for a particular operation
+ is zero. Hopefully, these defaults will be correct often enough
+ that we won't need to provide too many translations. */
+ register_charset (simple_charset ("ASCII", 1,
+ ascii_print_literally, 0,
+ ascii_to_control, 0));
+ register_charset (iso_8859_family_charset ("ISO-8859-1"));
+ register_charset (ebcdic_family_charset ("EBCDIC-US"));
+ register_charset (ebcdic_family_charset ("IBM1047"));
+ register_iconv_charsets ();
+
+ {
+ struct { char *from; char *to; int *table; } tlist[] = {
+ { "ASCII", "ISO-8859-1", ascii_to_iso_8859_1_table },
+ { "ASCII", "EBCDIC-US", ascii_to_ebcdic_us_table },
+ { "ASCII", "IBM1047", ascii_to_ibm1047_table },
+ { "ISO-8859-1", "ASCII", iso_8859_1_to_ascii_table },
+ { "ISO-8859-1", "EBCDIC-US", iso_8859_1_to_ebcdic_us_table },
+ { "ISO-8859-1", "IBM1047", iso_8859_1_to_ibm1047_table },
+ { "EBCDIC-US", "ASCII", ebcdic_us_to_ascii_table },
+ { "EBCDIC-US", "ISO-8859-1", ebcdic_us_to_iso_8859_1_table },
+ { "EBCDIC-US", "IBM1047", ebcdic_us_to_ibm1047_table },
+ { "IBM1047", "ASCII", ibm1047_to_ascii_table },
+ { "IBM1047", "ISO-8859-1", ibm1047_to_iso_8859_1_table },
+ { "IBM1047", "EBCDIC-US", ibm1047_to_ebcdic_us_table }
+ };
+
+ int i;
+
+ for (i = 0; i < (sizeof (tlist) / sizeof (tlist[0])); i++)
+ register_translation (simple_table_translation (tlist[i].from,
+ tlist[i].to,
+ tlist[i].table));
+ }
+
+ set_host_charset (host_charset_name);
+ set_target_charset (target_charset_name);
+
+ new_cmd = add_set_enum_cmd ("charset",
+ class_support,
+ host_charset_enum,
+ &host_charset_name,
+ "Set the host and target character sets.\n"
+ "The `host character set' is the one used by the system GDB is running on.\n"
+ "The `target character set' is the one used by the program being debugged.\n"
+ "You may only use supersets of ASCII for your host character set; GDB does\n"
+ "not support any others.\n"
+ "To see a list of the character sets GDB supports, type `set charset <TAB>'.",
+ &setlist);
+
+ /* Note that the sfunc below needs to set target_charset_name, because
+ the 'set charset' command sets two variables. */
+ set_cmd_sfunc (new_cmd, set_charset_sfunc);
+ /* Don't use set_from_show - need to print some extra info. */
+ add_cmd ("charset", class_support, show_charset,
+ "Show the host and target character sets.\n"
+ "The `host character set' is the one used by the system GDB is running on.\n"
+ "The `target character set' is the one used by the program being debugged.\n"
+ "You may only use supersets of ASCII for your host character set; GDB does\n"
+ "not support any others.\n"
+ "To see a list of the character sets GDB supports, type `set charset <TAB>'.",
+ &showlist);
+
+
+ new_cmd = add_set_enum_cmd ("host-charset",
+ class_support,
+ host_charset_enum,
+ &host_charset_name,
+ "Set the host character set.\n"
+ "The `host character set' is the one used by the system GDB is running on.\n"
+ "You may only use supersets of ASCII for your host character set; GDB does\n"
+ "not support any others.\n"
+ "To see a list of the character sets GDB supports, type `set host-charset <TAB>'.",
+ &setlist);
+
+ set_cmd_sfunc (new_cmd, set_host_charset_sfunc);
+
+ add_show_from_set (new_cmd, &showlist);
+
+
+
+ new_cmd = add_set_enum_cmd ("target-charset",
+ class_support,
+ target_charset_enum,
+ &target_charset_name,
+ "Set the target character set.\n"
+ "The `target character set' is the one used by the program being debugged.\n"
+ "GDB translates characters and strings between the host and target\n"
+ "character sets as needed.\n"
+ "To see a list of the character sets GDB supports, type `set target-charset'<TAB>",
+ &setlist);
+
+ set_cmd_sfunc (new_cmd, set_target_charset_sfunc);
+ add_show_from_set (new_cmd, &showlist);
+}
diff --git a/contrib/gdb/gdb/charset.h b/contrib/gdb/gdb/charset.h
new file mode 100644
index 0000000..31dbe6f
--- /dev/null
+++ b/contrib/gdb/gdb/charset.h
@@ -0,0 +1,109 @@
+/* Character set conversion support for GDB.
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 CHARSET_H
+#define CHARSET_H
+
+
+/* If the target program uses a different character set than the host,
+ GDB has some support for translating between the two; GDB converts
+ characters and strings to the host character set before displaying
+ them, and converts characters and strings appearing in expressions
+ entered by the user to the target character set.
+
+ At the moment, GDB only supports single-byte, stateless character
+ sets. This includes the ISO-8859 family (ASCII extended with
+ accented characters, and (I think) Cyrillic, for European
+ languages), and the EBCDIC family (used on IBM's mainframes).
+ Unfortunately, it excludes many Asian scripts, the fixed- and
+ variable-width Unicode encodings, and other desireable things.
+ Patches are welcome! (For example, it would be nice if the Java
+ string support could simply get absorbed into some more general
+ multi-byte encoding support.)
+
+ Furthermore, GDB's code pretty much assumes that the host character
+ set is some superset of ASCII; there are plenty if ('0' + n)
+ expressions and the like.
+
+ When the `iconv' library routine supports a character set meeting
+ the requirements above, it's easy to plug an entry into GDB's table
+ that uses iconv to handle the details. */
+
+/* Return the name of the current host/target character set. The
+ result is owned by the charset module; the caller should not free
+ it. */
+const char *host_charset (void);
+const char *target_charset (void);
+
+/* In general, the set of C backslash escapes (\n, \f) is specific to
+ the character set. Not all character sets will have form feed
+ characters, for example.
+
+ The following functions allow GDB to parse and print control
+ characters in a character-set-independent way. They are both
+ language-specific (to C and C++) and character-set-specific.
+ Putting them here is a compromise. */
+
+
+/* If the target character TARGET_CHAR have a backslash escape in the
+ C language (i.e., a character like 'n' or 't'), return the host
+ character string that should follow the backslash. Otherwise,
+ return zero.
+
+ When this function returns non-zero, the string it returns is
+ statically allocated; the caller is not responsible for freeing it. */
+const char *c_target_char_has_backslash_escape (int target_char);
+
+
+/* If the host character HOST_CHAR is a valid backslash escape in the
+ C language for the target character set, return non-zero, and set
+ *TARGET_CHAR to the target character the backslash escape represents.
+ Otherwise, return zero. */
+int c_parse_backslash (int host_char, int *target_char);
+
+
+/* Return non-zero if the host character HOST_CHAR can be printed
+ literally --- that is, if it can be readably printed as itself in a
+ character or string constant. Return zero if it should be printed
+ using some kind of numeric escape, like '\031' in C, '^(25)' in
+ Chill, or #25 in Pascal. */
+int host_char_print_literally (int host_char);
+
+
+/* If the host character HOST_CHAR has an equivalent in the target
+ character set, set *TARGET_CHAR to that equivalent, and return
+ non-zero. Otherwise, return zero. */
+int host_char_to_target (int host_char, int *target_char);
+
+
+/* If the target character TARGET_CHAR has an equivalent in the host
+ character set, set *HOST_CHAR to that equivalent, and return
+ non-zero. Otherwise, return zero. */
+int target_char_to_host (int target_char, int *host_char);
+
+
+/* If the target character TARGET_CHAR has a corresponding control
+ character (also in the target character set), set *TARGET_CTRL_CHAR
+ to the control character, and return non-zero. Otherwise, return
+ zero. */
+int target_char_to_control_char (int target_char, int *target_ctrl_char);
+
+
+#endif /* CHARSET_H */
diff --git a/contrib/gdb/gdb/cli-out.c b/contrib/gdb/gdb/cli-out.c
new file mode 100644
index 0000000..9f48a0a
--- /dev/null
+++ b/contrib/gdb/gdb/cli-out.c
@@ -0,0 +1,405 @@
+/* Output generating routines for GDB CLI.
+
+ Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions.
+ Written by Fernando Nasser 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 "defs.h"
+#include "ui-out.h"
+#include "cli-out.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+
+struct ui_out_data
+ {
+ struct ui_file *stream;
+ struct ui_file *original_stream;
+ int suppress_output;
+ };
+typedef struct ui_out_data cli_out_data;
+
+/* These are the CLI output functions */
+
+static void cli_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows, const char *tblid);
+static void cli_table_body (struct ui_out *uiout);
+static void cli_table_end (struct ui_out *uiout);
+static void cli_table_header (struct ui_out *uiout, int width,
+ enum ui_align alig, const char *col_name,
+ const char *colhdr);
+static void cli_begin (struct ui_out *uiout, enum ui_out_type type,
+ int level, const char *lstid);
+static void cli_end (struct ui_out *uiout, enum ui_out_type type, int level);
+static void cli_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname, int value);
+static void cli_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname);
+static void cli_field_string (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname,
+ const char *string);
+static void cli_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ const char *fldname, const char *format,
+ va_list args);
+static void cli_spaces (struct ui_out *uiout, int numspaces);
+static void cli_text (struct ui_out *uiout, const char *string);
+static void cli_message (struct ui_out *uiout, int verbosity,
+ const char *format, va_list args);
+static void cli_wrap_hint (struct ui_out *uiout, char *identstring);
+static void cli_flush (struct ui_out *uiout);
+static int cli_redirect (struct ui_out *uiout, struct ui_file *outstream);
+
+/* This is the CLI ui-out implementation functions vector */
+
+/* FIXME: This can be initialized dynamically after default is set to
+ handle initial output in main.c */
+
+static struct ui_out_impl cli_ui_out_impl =
+{
+ cli_table_begin,
+ cli_table_body,
+ cli_table_end,
+ cli_table_header,
+ cli_begin,
+ cli_end,
+ cli_field_int,
+ cli_field_skip,
+ cli_field_string,
+ cli_field_fmt,
+ cli_spaces,
+ cli_text,
+ cli_message,
+ cli_wrap_hint,
+ cli_flush,
+ cli_redirect,
+ 0, /* Does not need MI hacks (i.e. needs CLI hacks). */
+};
+
+/* Prototypes for local functions */
+
+extern void _initialize_cli_out (void);
+
+static void field_separator (void);
+
+static void out_field_fmt (struct ui_out *uiout, int fldno,
+ const char *fldname,
+ const char *format,...);
+
+/* local variables */
+
+/* (none yet) */
+
+/* Mark beginning of a table */
+
+void
+cli_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows,
+ const char *tblid)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (nr_rows == 0)
+ data->suppress_output = 1;
+ else
+ /* Only the table suppresses the output and, fortunately, a table
+ is not a recursive data structure. */
+ gdb_assert (data->suppress_output == 0);
+}
+
+/* Mark beginning of a table body */
+
+void
+cli_table_body (struct ui_out *uiout)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ /* first, close the table header line */
+ cli_text (uiout, "\n");
+}
+
+/* Mark end of a table */
+
+void
+cli_table_end (struct ui_out *uiout)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ data->suppress_output = 0;
+}
+
+/* Specify table header */
+
+void
+cli_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
+ const char *col_name,
+ const char *colhdr)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ cli_field_string (uiout, 0, width, alignment, 0, colhdr);
+}
+
+/* Mark beginning of a list */
+
+void
+cli_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level,
+ const char *id)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+}
+
+/* Mark end of a list */
+
+void
+cli_end (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+}
+
+/* output an int field */
+
+void
+cli_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alignment,
+ const char *fldname, int value)
+{
+ char buffer[20]; /* FIXME: how many chars long a %d can become? */
+
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ sprintf (buffer, "%d", value);
+ cli_field_string (uiout, fldno, width, alignment, fldname, buffer);
+}
+
+/* used to ommit a field */
+
+void
+cli_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alignment,
+ const char *fldname)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ cli_field_string (uiout, fldno, width, alignment, fldname, "");
+}
+
+/* other specific cli_field_* end up here so alignment and field
+ separators are both handled by cli_field_string */
+
+void
+cli_field_string (struct ui_out *uiout,
+ int fldno,
+ int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *string)
+{
+ int before = 0;
+ int after = 0;
+
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+
+ if ((align != ui_noalign) && string)
+ {
+ before = width - strlen (string);
+ if (before <= 0)
+ before = 0;
+ else
+ {
+ if (align == ui_right)
+ after = 0;
+ else if (align == ui_left)
+ {
+ after = before;
+ before = 0;
+ }
+ else
+ /* ui_center */
+ {
+ after = before / 2;
+ before -= after;
+ }
+ }
+ }
+
+ if (before)
+ ui_out_spaces (uiout, before);
+ if (string)
+ out_field_fmt (uiout, fldno, fldname, "%s", string);
+ if (after)
+ ui_out_spaces (uiout, after);
+
+ if (align != ui_noalign)
+ field_separator ();
+}
+
+/* This is the only field function that does not align */
+
+void
+cli_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ const char *fldname,
+ const char *format,
+ va_list args)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+
+ vfprintf_filtered (data->stream, format, args);
+
+ if (align != ui_noalign)
+ field_separator ();
+}
+
+void
+cli_spaces (struct ui_out *uiout, int numspaces)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ print_spaces_filtered (numspaces, data->stream);
+}
+
+void
+cli_text (struct ui_out *uiout, const char *string)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ fputs_filtered (string, data->stream);
+}
+
+void
+cli_message (struct ui_out *uiout, int verbosity,
+ const char *format, va_list args)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ if (ui_out_get_verblvl (uiout) >= verbosity)
+ vfprintf_unfiltered (data->stream, format, args);
+}
+
+void
+cli_wrap_hint (struct ui_out *uiout, char *identstring)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ wrap_here (identstring);
+}
+
+void
+cli_flush (struct ui_out *uiout)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ gdb_flush (data->stream);
+}
+
+int
+cli_redirect (struct ui_out *uiout, struct ui_file *outstream)
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ if (outstream != NULL)
+ {
+ data->original_stream = data->stream;
+ data->stream = outstream;
+ }
+ else if (data->original_stream != NULL)
+ {
+ data->stream = data->original_stream;
+ data->original_stream = NULL;
+ }
+
+ return 0;
+}
+
+/* local functions */
+
+/* Like cli_field_fmt, but takes a variable number of args
+ and makes a va_list and does not insert a separator */
+
+/* VARARGS */
+static void
+out_field_fmt (struct ui_out *uiout, int fldno,
+ const char *fldname,
+ const char *format,...)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ va_list args;
+
+ va_start (args, format);
+ vfprintf_filtered (data->stream, format, args);
+
+ va_end (args);
+}
+
+/* access to ui_out format private members */
+
+static void
+field_separator (void)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ fputc_filtered (' ', data->stream);
+}
+
+/* initalize private members at startup */
+
+struct ui_out *
+cli_out_new (struct ui_file *stream)
+{
+ int flags = ui_source_list;
+
+ cli_out_data *data = XMALLOC (cli_out_data);
+ data->stream = stream;
+ data->original_stream = NULL;
+ data->suppress_output = 0;
+ return ui_out_new (&cli_ui_out_impl, data, flags);
+}
+
+struct ui_file *
+cli_out_set_stream (struct ui_out *uiout, struct ui_file *stream)
+{
+ cli_out_data *data = ui_out_data (uiout);
+ struct ui_file *old = data->stream;
+ data->stream = stream;
+ return old;
+}
+
+/* standard gdb initialization hook */
+void
+_initialize_cli_out (void)
+{
+ /* nothing needs to be done */
+}
diff --git a/contrib/gdb/gdb/cli-out.h b/contrib/gdb/gdb/cli-out.h
new file mode 100644
index 0000000..8bca872
--- /dev/null
+++ b/contrib/gdb/gdb/cli-out.h
@@ -0,0 +1,32 @@
+/* Output generating routines for GDB CLI.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 CLI_OUT_H
+#define CLI_OUT_H
+
+struct ui_file;
+
+extern struct ui_out *cli_out_new (struct ui_file *stream);
+
+extern struct ui_file *cli_out_set_stream (struct ui_out *uiout,
+ struct ui_file *stream);
+
+#endif
diff --git a/contrib/gdb/gdb/cli/cli-cmds.c b/contrib/gdb/gdb/cli/cli-cmds.c
new file mode 100644
index 0000000..9378ac8
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-cmds.c
@@ -0,0 +1,1288 @@
+/* GDB CLI commands.
+
+ Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "readline/readline.h"
+#include "readline/tilde.h"
+#include "completer.h"
+#include "target.h" /* For baud_rate, remote_debug and remote_timeout */
+#include "gdb_wait.h" /* For shell escape implementation */
+#include "gdb_regex.h" /* Used by apropos_command */
+#include "gdb_string.h"
+#include "gdb_vfork.h"
+#include "linespec.h"
+#include "expression.h"
+#include "frame.h"
+#include "value.h"
+#include "language.h"
+#include "filenames.h" /* for DOSish file names */
+#include "objfiles.h"
+#include "source.h"
+#include "disasm.h"
+
+#include "ui-out.h"
+
+#include "top.h"
+#include "cli/cli-decode.h"
+#include "cli/cli-script.h"
+#include "cli/cli-setshow.h"
+#include "cli/cli-cmds.h"
+
+#ifdef TUI
+#include "tui/tui.h" /* For tui_active et.al. */
+#endif
+
+#ifndef GDBINIT_FILENAME
+#define GDBINIT_FILENAME ".gdbinit"
+#endif
+
+/* Prototypes for local command functions */
+
+static void complete_command (char *, int);
+
+static void echo_command (char *, int);
+
+static void pwd_command (char *, int);
+
+static void show_version (char *, int);
+
+static void help_command (char *, int);
+
+static void show_command (char *, int);
+
+static void info_command (char *, int);
+
+static void show_debug (char *, int);
+
+static void set_debug (char *, int);
+
+static void show_user (char *, int);
+
+static void make_command (char *, int);
+
+static void shell_escape (char *, int);
+
+static void edit_command (char *, int);
+
+static void list_command (char *, int);
+
+void apropos_command (char *, int);
+
+/* Prototypes for local utility functions */
+
+static void ambiguous_line_spec (struct symtabs_and_lines *);
+
+/* Limit the call depth of user-defined commands */
+int max_user_call_depth;
+
+/* 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 toggle subcommands. */
+
+struct cmd_list_element *togglelist;
+
+/* Chain containing all defined stop subcommands. */
+
+struct cmd_list_element *stoplist;
+
+/* 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;
+
+/* 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. */
+
+struct cmd_list_element *maintenancelist;
+
+/* Chain containing all defined "maintenance info" subcommands. */
+
+struct cmd_list_element *maintenanceinfolist;
+
+/* Chain containing all defined "maintenance print" subcommands. */
+
+struct cmd_list_element *maintenanceprintlist;
+
+struct cmd_list_element *setprintlist;
+
+struct cmd_list_element *showprintlist;
+
+struct cmd_list_element *setdebuglist;
+
+struct cmd_list_element *showdebuglist;
+
+struct cmd_list_element *setchecklist;
+
+struct cmd_list_element *showchecklist;
+
+/* Utility used everywhere when at least one argument is needed and
+ none is supplied. */
+
+void
+error_no_arg (char *why)
+{
+ error ("Argument required (%s).", why);
+}
+
+/* The "info" command is defined as a prefix, with allow_unknown = 0.
+ Therefore, its own definition is called only for "info" with no args. */
+
+static void
+info_command (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 "show" command with no arguments shows all the settings. */
+
+static void
+show_command (char *arg, int from_tty)
+{
+ cmd_show_list (showlist, from_tty, "");
+}
+
+/* Provide documentation on command or list given by COMMAND. FROM_TTY
+ is ignored. */
+
+static void
+help_command (char *command, int from_tty)
+{
+ help_cmd (command, gdb_stdout);
+}
+
+/* String compare function for qsort. */
+static int
+compare_strings (const void *arg1, const void *arg2)
+{
+ const char **s1 = (const char **) arg1;
+ const char **s2 = (const char **) arg2;
+ return strcmp (*s1, *s2);
+}
+
+/* The "complete" command is used by Emacs to implement completion. */
+
+static void
+complete_command (char *arg, int from_tty)
+{
+ int i;
+ int argpoint;
+ char **completions, *point, *arg_prefix;
+
+ dont_repeat ();
+
+ if (arg == NULL)
+ arg = "";
+ argpoint = strlen (arg);
+
+ /* complete_line assumes that its first argument is somewhere within,
+ and except for filenames at the beginning of, the word to be completed.
+ The following crude imitation of readline's word-breaking tries to
+ accomodate this. */
+ point = arg + argpoint;
+ while (point > arg)
+ {
+ if (strchr (rl_completer_word_break_characters, point[-1]) != 0)
+ break;
+ point--;
+ }
+
+ arg_prefix = alloca (point - arg + 1);
+ memcpy (arg_prefix, arg, point - arg);
+ arg_prefix[point - arg] = 0;
+
+ completions = complete_line (point, arg, argpoint);
+
+ if (completions)
+ {
+ int item, size;
+
+ for (size = 0; completions[size]; ++size)
+ ;
+ qsort (completions, size, sizeof (char *), compare_strings);
+
+ /* We do extra processing here since we only want to print each
+ unique item once. */
+ item = 0;
+ while (item < size)
+ {
+ int next_item;
+ printf_unfiltered ("%s%s\n", arg_prefix, completions[item]);
+ next_item = item + 1;
+ while (next_item < size
+ && ! strcmp (completions[item], completions[next_item]))
+ {
+ xfree (completions[next_item]);
+ ++next_item;
+ }
+
+ xfree (completions[item]);
+ item = next_item;
+ }
+
+ xfree (completions);
+ }
+}
+
+int
+is_complete_command (struct cmd_list_element *c)
+{
+ return cmd_cfunc_eq (c, complete_command);
+}
+
+static void
+show_version (char *args, int from_tty)
+{
+ immediate_quit++;
+ print_gdb_version (gdb_stdout);
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+/* Handle the quit command. */
+
+void
+quit_command (char *args, int from_tty)
+{
+ if (!quit_confirm ())
+ error ("Not confirmed.");
+ quit_force (args, from_tty);
+}
+
+static void
+pwd_command (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 (strcmp (gdb_dirbuf, current_directory) != 0)
+ 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 (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 (xfree, dir);
+
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ /* There's too much mess with DOSish names like "d:", "d:.",
+ "d:./foo" etc. Instead of having lots of special #ifdef'ed code,
+ simply get the canonicalized name of the current directory. */
+ dir = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+#endif
+
+ len = strlen (dir);
+ if (IS_DIR_SEPARATOR (dir[len - 1]))
+ {
+ /* Remove the trailing slash unless this is a root directory
+ (including a drive letter on non-Unix systems). */
+ if (!(len == 1) /* "/" */
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ && !(len == 3 && dir[1] == ':') /* "d:/" */
+#endif
+ )
+ len--;
+ }
+
+ dir = savestring (dir, len);
+ if (IS_ABSOLUTE_PATH (dir))
+ current_directory = dir;
+ else
+ {
+ if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
+ current_directory = concat (current_directory, dir, NULL);
+ else
+ current_directory = concat (current_directory, SLASH_STRING, dir, NULL);
+ xfree (dir);
+ }
+
+ /* Now simplify any occurrences of `.' and `..' in the pathname. */
+
+ found_real_path = 0;
+ for (p = current_directory; *p;)
+ {
+ if (IS_DIR_SEPARATOR (p[0]) && p[1] == '.'
+ && (p[2] == 0 || IS_DIR_SEPARATOR (p[2])))
+ strcpy (p, p + 2);
+ else if (IS_DIR_SEPARATOR (p[0]) && p[1] == '.' && p[2] == '.'
+ && (p[3] == 0 || IS_DIR_SEPARATOR (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 && !IS_DIR_SEPARATOR (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);
+}
+
+void
+source_command (char *args, int from_tty)
+{
+ FILE *stream;
+ struct cleanup *old_cleanups;
+ char *file = args;
+
+ if (file == NULL)
+ {
+ error ("source command requires pathname of file to source.");
+ }
+
+ file = tilde_expand (file);
+ old_cleanups = make_cleanup (xfree, file);
+
+ stream = fopen (file, FOPEN_RT);
+ if (!stream)
+ {
+ if (from_tty)
+ perror_with_name (file);
+ else
+ return;
+ }
+
+ script_from_file (stream, file);
+
+ do_cleanups (old_cleanups);
+}
+
+static void
+echo_command (char *text, int from_tty)
+{
+ char *p = text;
+ 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);
+}
+
+static void
+shell_escape (char *arg, int from_tty)
+{
+#ifdef CANT_FORK
+ /* If ARG is NULL, they want an inferior shell, but `system' just
+ reports if the shell is available when passed a NULL arg. */
+ int rc = system (arg ? arg : "");
+
+ if (!arg)
+ arg = "inferior shell";
+
+ if (rc == -1)
+ {
+ fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", arg,
+ safe_strerror (errno));
+ gdb_flush (gdb_stderr);
+ }
+ else if (rc)
+ {
+ fprintf_unfiltered (gdb_stderr, "%s exited with status %d\n", arg, rc);
+ gdb_flush (gdb_stderr);
+ }
+#ifdef GLOBAL_CURDIR
+ /* Make sure to return to the directory GDB thinks it is, in case the
+ shell command we just ran changed it. */
+ chdir (current_directory);
+#endif
+#else /* Can fork. */
+ int rc, status, pid;
+
+ if ((pid = vfork ()) == 0)
+ {
+ 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 (!arg)
+ execl (user_shell, p, (char *) 0);
+ else
+ execl (user_shell, p, "-c", arg, (char *) 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
+edit_command (char *arg, int from_tty)
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct symbol *sym;
+ char *arg1;
+ int cmdlen, log10;
+ unsigned m;
+ char *editor;
+ char *p;
+
+ /* Pull in the current default source line if necessary */
+ if (arg == 0)
+ {
+ set_default_source_symtab_and_line ();
+ sal = get_current_source_symtab_and_line ();
+ }
+
+ /* bare "edit" edits file with present line. */
+
+ if (arg == 0)
+ {
+ if (sal.symtab == 0)
+ error ("No default source file yet.");
+ sal.line += get_lines_to_list () / 2;
+ }
+ else
+ {
+
+ /* Now should only be one argument -- decode it in SAL */
+
+ arg1 = arg;
+ sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
+
+ if (! sals.nelts) return; /* C++ */
+ if (sals.nelts > 1) {
+ ambiguous_line_spec (&sals);
+ xfree (sals.sals);
+ return;
+ }
+
+ sal = sals.sals[0];
+ xfree (sals.sals);
+
+ if (*arg1)
+ error ("Junk at end of line specification.");
+
+ /* 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_PRINT_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 what was given does not imply a symtab, it must be an undebuggable
+ symbol which means no source code. */
+
+ if (sal.symtab == 0)
+ error ("No line number known for %s.", arg);
+ }
+
+ if ((editor = (char *) getenv ("EDITOR")) == NULL)
+ editor = "/bin/ex";
+
+ /* Approximate base-10 log of line to 1 unit for digit count */
+ for(log10=32, m=0x80000000; !(sal.line & m) && log10>0; log10--, m=m>>1);
+ log10 = 1 + (int)((log10 + (0 == ((m-1) & sal.line)))/3.32192809);
+
+ cmdlen = strlen(editor) + 1
+ + (NULL == sal.symtab->dirname ? 0 : strlen(sal.symtab->dirname) + 1)
+ + (NULL == sal.symtab->filename? 0 : strlen(sal.symtab->filename)+ 1)
+ + log10 + 2;
+
+ p = xmalloc(cmdlen);
+ sprintf(p,"%s +%d %s%s",editor,sal.line,
+ (NULL == sal.symtab->dirname ? "./" :
+ (NULL != sal.symtab->filename && *(sal.symtab->filename) != '/') ?
+ sal.symtab->dirname : ""),
+ (NULL == sal.symtab->filename ? "unknown" : sal.symtab->filename)
+ );
+ shell_escape(p, from_tty);
+
+ xfree(p);
+}
+
+static void
+list_command (char *arg, int from_tty)
+{
+ struct symtabs_and_lines sals, sals_end;
+ struct symtab_and_line sal, sal_end, cursal;
+ struct symbol *sym;
+ char *arg1;
+ int no_end = 1;
+ int dummy_end = 0;
+ int dummy_beg = 0;
+ int linenum_beg = 0;
+ char *p;
+
+ /* Pull in the current default source line if necessary */
+ if (arg == 0 || arg[0] == '+' || arg[0] == '-')
+ {
+ set_default_source_symtab_and_line ();
+ cursal = get_current_source_symtab_and_line ();
+ }
+
+ /* "l" or "l +" lists next ten lines. */
+
+ if (arg == 0 || strcmp (arg, "+") == 0)
+ {
+ print_source_lines (cursal.symtab, cursal.line,
+ cursal.line + get_lines_to_list (), 0);
+ return;
+ }
+
+ /* "l -" lists previous ten lines, the ones before the ten just listed. */
+ if (strcmp (arg, "-") == 0)
+ {
+ print_source_lines (cursal.symtab,
+ max (get_first_line_listed () - get_lines_to_list (), 1),
+ get_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. */
+
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+
+ arg1 = arg;
+ if (*arg1 == ',')
+ dummy_beg = 1;
+ else
+ {
+ sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
+
+ if (!sals.nelts)
+ return; /* C++ */
+ if (sals.nelts > 1)
+ {
+ ambiguous_line_spec (&sals);
+ xfree (sals.sals);
+ return;
+ }
+
+ sal = sals.sals[0];
+ xfree (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, 0);
+ else
+ sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0, 0);
+ if (sals_end.nelts == 0)
+ return;
+ if (sals_end.nelts > 1)
+ {
+ ambiguous_line_spec (&sals_end);
+ xfree (sals_end.sals);
+ return;
+ }
+ sal_end = sals_end.sals[0];
+ xfree (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_PRINT_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 - (get_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)
+ {
+ int first_line = sal.line - get_lines_to_list () / 2;
+
+ if (first_line < 1) first_line = 1;
+
+ print_source_lines (sal.symtab,
+ first_line,
+ first_line + get_lines_to_list (),
+ 0);
+ }
+ else
+ print_source_lines (sal.symtab, sal.line,
+ (dummy_end
+ ? sal.line + get_lines_to_list ()
+ : sal_end.line + 1),
+ 0);
+}
+
+/* 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. */
+
+static void
+disassemble_command (char *arg, int from_tty)
+{
+ CORE_ADDR low, high;
+ char *name;
+ CORE_ADDR pc, pc_masked;
+ char *space_index;
+#if 0
+ asection *section;
+#endif
+
+ name = NULL;
+ if (!arg)
+ {
+ if (!deprecated_selected_frame)
+ error ("No frame selected.\n");
+
+ pc = get_frame_pc (deprecated_selected_frame);
+ if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+ error ("No function contains program counter for selected frame.\n");
+#if defined(TUI)
+ /* NOTE: cagney/2003-02-13 The `tui_active' was previously
+ `tui_version'. */
+ if (tui_active)
+ /* FIXME: cagney/2004-02-07: This should be an observer. */
+ low = tui_get_low_disassembly_address (low, pc);
+#endif
+ low += FUNCTION_START_OFFSET;
+ }
+ 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");
+#if defined(TUI)
+ /* NOTE: cagney/2003-02-13 The `tui_active' was previously
+ `tui_version'. */
+ if (tui_active)
+ /* FIXME: cagney/2004-02-07: This should be an observer. */
+ low = tui_get_low_disassembly_address (low, pc);
+#endif
+ low += FUNCTION_START_OFFSET;
+ }
+ else
+ {
+ /* Two arguments. */
+ *space_index = '\0';
+ low = parse_and_eval_address (arg);
+ high = parse_and_eval_address (space_index + 1);
+ }
+
+#if defined(TUI)
+ if (!tui_is_window_visible (DISASSEM_WIN))
+#endif
+ {
+ 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. */
+ gdb_disassembly (uiout, 0, 0, 0, -1, low, high);
+
+ printf_filtered ("End of assembler dump.\n");
+ gdb_flush (gdb_stdout);
+ }
+#if defined(TUI)
+ else
+ {
+ tui_show_assembly (low);
+ }
+#endif
+}
+
+static void
+make_command (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 (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);
+ }
+ }
+}
+
+/* Search through names of commands and documentations for a certain
+ regular expression.
+*/
+void
+apropos_command (char *searchstr, int from_tty)
+{
+ extern struct cmd_list_element *cmdlist; /*This is the main command list*/
+ regex_t pattern;
+ char *pattern_fastmap;
+ char errorbuffer[512];
+ pattern_fastmap = xcalloc (256, sizeof (char));
+ if (searchstr == NULL)
+ error("REGEXP string is empty");
+
+ if (regcomp(&pattern,searchstr,REG_ICASE) == 0)
+ {
+ pattern.fastmap=pattern_fastmap;
+ re_compile_fastmap(&pattern);
+ apropos_cmd (gdb_stdout,cmdlist,&pattern,"");
+ }
+ else
+ {
+ regerror(regcomp(&pattern,searchstr,REG_ICASE),NULL,errorbuffer,512);
+ error("Error in regular expression:%s",errorbuffer);
+ }
+ xfree (pattern_fastmap);
+}
+
+/* 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 (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
+set_debug (char *arg, int from_tty)
+{
+ printf_unfiltered ("\"set debug\" must be followed by the name of a print subcommand.\n");
+ help_list (setdebuglist, "set debug ", -1, gdb_stdout);
+}
+
+static void
+show_debug (char *args, int from_tty)
+{
+ cmd_show_list (showdebuglist, from_tty, "");
+}
+
+void
+init_cmd_lists (void)
+{
+ max_user_call_depth = 1024;
+
+ cmdlist = NULL;
+ infolist = NULL;
+ enablelist = NULL;
+ disablelist = NULL;
+ togglelist = NULL;
+ stoplist = NULL;
+ deletelist = NULL;
+ enablebreaklist = NULL;
+ setlist = NULL;
+ unsetlist = NULL;
+ showlist = NULL;
+ sethistlist = NULL;
+ showhistlist = NULL;
+ unsethistlist = NULL;
+ maintenancelist = NULL;
+ maintenanceinfolist = NULL;
+ maintenanceprintlist = NULL;
+ setprintlist = NULL;
+ showprintlist = NULL;
+ setchecklist = NULL;
+ showchecklist = NULL;
+}
+
+
+void
+init_cli_cmds (void)
+{
+ struct cmd_list_element *c;
+
+ /* Define the classes of commands.
+ They will appear in the help list in the reverse of this order. */
+
+ add_cmd ("internals", class_maintenance, NULL,
+ "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, NULL, "Obscure features.", &cmdlist);
+ add_cmd ("aliases", class_alias, NULL, "Aliases of other commands.", &cmdlist);
+ add_cmd ("user-defined", class_user, NULL, "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, NULL, "Support facilities.", &cmdlist);
+ if (!dbx_commands)
+ add_cmd ("status", class_info, NULL, "Status inquiries.", &cmdlist);
+ add_cmd ("files", class_files, NULL, "Specifying and examining files.", &cmdlist);
+ add_cmd ("breakpoints", class_breakpoint, NULL, "Making program stop at certain points.", &cmdlist);
+ add_cmd ("data", class_vars, NULL, "Examining data.", &cmdlist);
+ add_cmd ("stack", class_stack, NULL, "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, NULL, "Running the program.", &cmdlist);
+
+ /* Define general commands. */
+
+ 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);
+ set_cmd_completer (c, filename_completer);
+
+ 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.");
+
+ 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);
+ set_cmd_completer (c, filename_completer);
+
+ add_com ("quit", class_support, quit_command, "Exit gdb.");
+ c = add_com ("help", class_support, help_command, "Print list of commands.");
+ set_cmd_completer (c, command_completer);
+ add_com_alias ("q", "quit", class_support, 1);
+ add_com_alias ("h", "help", class_support, 1);
+
+ c = add_set_cmd ("verbose", class_support, var_boolean, (char *) &info_verbose,
+ "Set ",
+ &setlist),
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_verbose);
+ set_verbose (NULL, 0, c);
+
+ 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_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);
+
+ c = 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);
+ deprecate_cmd (c, "set debug remote");
+ deprecate_cmd (add_show_from_set (c, &showlist), "show debug remote");
+
+ add_show_from_set (add_set_cmd ("remote", 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.", &setdebuglist),
+ &showdebuglist);
+
+ add_show_from_set (
+ add_set_cmd ("remotetimeout", no_class, var_integer, (char *) &remote_timeout,
+ "Set timeout limit to wait for target to respond.\n\
+This value is used to set the time limit for gdb to wait for a response\n\
+from the target.", &setlist),
+ &showlist);
+
+ add_prefix_cmd ("debug", no_class, set_debug,
+ "Generic command for setting gdb debugging flags",
+ &setdebuglist, "set debug ", 0, &setlist);
+
+ add_prefix_cmd ("debug", no_class, show_debug,
+ "Generic command for showing gdb debugging flags",
+ &showdebuglist, "show debug ", 0, &showlist);
+
+ c = 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.");
+ set_cmd_completer (c, filename_completer);
+
+ c = add_com ("edit", class_files, edit_command,
+ concat ("Edit specified file or function.\n\
+With no argument, edits file containing most recent line listed.\n\
+", "\
+Editing targets can be specified in these ways:\n\
+ FILE:LINENUM, to edit at that line in that file,\n\
+ FUNCTION, to edit at the beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+ *ADDRESS, to edit at the line containing that address.\n\
+Uses EDITOR environment variable contents as editor (or ex as default).",NULL));
+
+ c->completer = location_completer;
+
+ 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));
+
+ if (!xdb_commands)
+ add_com_alias ("l", "list", class_files, 1);
+ else
+ add_com_alias ("v", "list", class_files, 1);
+
+ if (dbx_commands)
+ add_com_alias ("file", "list", class_files, 1);
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+ if (xdb_commands)
+ add_com_alias ("va", "disassemble", class_xdb, 0);
+
+ /* NOTE: cagney/2000-03-20: Being able to enter ``(gdb) !ls'' would
+ be a really useful feature. Unfortunately, the below wont do
+ this. Instead it adds support for the form ``(gdb) ! ls''
+ (i.e. the space is required). If the ``!'' command below is
+ added the complains about no ``!'' command would be replaced by
+ complains about how the ``!'' command is broken :-) */
+ if (xdb_commands)
+ add_com_alias ("!", "shell", class_support, 0);
+
+ c = add_com ("make", class_support, make_command,
+ "Run the ``make'' program using the rest of the line as arguments.");
+ set_cmd_completer (c, filename_completer);
+ add_cmd ("user", no_class, show_user,
+ "Show definitions of user defined commands.\n\
+Argument is the name of the user defined command.\n\
+With no argument, show definitions of all user defined commands.", &showlist);
+ add_com ("apropos", class_support, apropos_command, "Search for commands matching a REGEXP");
+
+ add_show_from_set (
+ add_set_cmd ("max-user-call-depth", no_class, var_integer,
+ (char *) &max_user_call_depth,
+ "Set the max call depth for user-defined commands.\n",
+ &setlist),
+ &showlist);
+}
diff --git a/contrib/gdb/gdb/cli/cli-cmds.h b/contrib/gdb/gdb/cli/cli-cmds.h
new file mode 100644
index 0000000..a6e574e
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-cmds.h
@@ -0,0 +1,125 @@
+/* Header file for GDB CLI command implementation library.
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (CLI_CMDS_H)
+#define CLI_CMDS_H 1
+
+/* 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 toggle subcommands. */
+
+extern struct cmd_list_element *togglelist;
+
+/* Chain containing all defined stop subcommands. */
+
+extern struct cmd_list_element *stoplist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+extern struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+extern struct cmd_list_element *setlist;
+
+/* 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 *setdebuglist;
+
+extern struct cmd_list_element *showdebuglist;
+
+extern struct cmd_list_element *setchecklist;
+
+extern struct cmd_list_element *showchecklist;
+
+/* Exported to gdb/top.c */
+
+void init_cmd_lists (void);
+
+void init_cli_cmds (void);
+
+int is_complete_command (struct cmd_list_element *cmd);
+
+/* Exported to gdb/main.c */
+
+extern void cd_command (char *, int);
+
+/* Exported to gdb/top.c and gdb/main.c */
+
+extern void quit_command (char *, int);
+
+extern void source_command (char *, int);
+
+/* Used everywhere whenever at least one parameter is required and
+ none is specified. */
+
+extern NORETURN void error_no_arg (char *) ATTR_NORETURN;
+
+#endif /* !defined (CLI_CMDS_H) */
diff --git a/contrib/gdb/gdb/cli/cli-decode.c b/contrib/gdb/gdb/cli/cli-decode.c
new file mode 100644
index 0000000..43f2f25
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-decode.c
@@ -0,0 +1,1546 @@
+/* Handle lists of commands, their decoding and documentation, for GDB.
+
+ Copyright 1986, 1989, 1990, 1991, 1998, 2000, 2001, 2002 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include <ctype.h>
+#include "gdb_regex.h"
+#include "gdb_string.h"
+
+#include "ui-out.h"
+
+#include "cli/cli-cmds.h"
+#include "cli/cli-decode.h"
+
+#ifdef TUI
+#include "tui/tui.h" /* For tui_active et.al. */
+#endif
+
+#include "gdb_assert.h"
+
+/* Prototypes for local functions */
+
+static void undef_cmd_error (char *, char *);
+
+static struct cmd_list_element *find_cmd (char *command,
+ int len,
+ struct cmd_list_element *clist,
+ int ignore_help_classes,
+ int *nfound);
+
+static void help_all (struct ui_file *stream);
+
+/* Set the callback function for the specified command. For each both
+ the commands callback and func() are set. The latter set to a
+ bounce function (unless cfunc / sfunc is NULL that is). */
+
+static void
+do_cfunc (struct cmd_list_element *c, char *args, int from_tty)
+{
+ c->function.cfunc (args, from_tty); /* Ok. */
+}
+
+void
+set_cmd_cfunc (struct cmd_list_element *cmd, cmd_cfunc_ftype *cfunc)
+{
+ if (cfunc == NULL)
+ cmd->func = NULL;
+ else
+ cmd->func = do_cfunc;
+ cmd->function.cfunc = cfunc; /* Ok. */
+}
+
+static void
+do_sfunc (struct cmd_list_element *c, char *args, int from_tty)
+{
+ c->function.sfunc (args, from_tty, c); /* Ok. */
+}
+
+void
+set_cmd_sfunc (struct cmd_list_element *cmd, cmd_sfunc_ftype *sfunc)
+{
+ if (sfunc == NULL)
+ cmd->func = NULL;
+ else
+ cmd->func = do_sfunc;
+ cmd->function.sfunc = sfunc; /* Ok. */
+}
+
+int
+cmd_cfunc_eq (struct cmd_list_element *cmd,
+ void (*cfunc) (char *args, int from_tty))
+{
+ return cmd->func == do_cfunc && cmd->function.cfunc == cfunc;
+}
+
+void
+set_cmd_context (struct cmd_list_element *cmd, void *context)
+{
+ cmd->context = context;
+}
+
+void *
+get_cmd_context (struct cmd_list_element *cmd)
+{
+ return cmd->context;
+}
+
+enum cmd_types
+cmd_type (struct cmd_list_element *cmd)
+{
+ return cmd->type;
+}
+
+void
+set_cmd_completer (struct cmd_list_element *cmd,
+ char **(*completer) (char *text, char *word))
+{
+ cmd->completer = completer; /* Ok. */
+}
+
+
+/* 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.
+
+ Returns a pointer to the added command (not necessarily the head
+ of *LIST). */
+
+struct cmd_list_element *
+add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
+ char *doc, struct cmd_list_element **list)
+{
+ struct cmd_list_element *c
+ = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
+ struct cmd_list_element *p;
+
+ delete_cmd (name, list);
+
+ if (*list == NULL || strcmp ((*list)->name, name) >= 0)
+ {
+ c->next = *list;
+ *list = c;
+ }
+ else
+ {
+ p = *list;
+ while (p->next && strcmp (p->next->name, name) <= 0)
+ {
+ p = p->next;
+ }
+ c->next = p->next;
+ p->next = c;
+ }
+
+ c->name = name;
+ c->class = class;
+ set_cmd_cfunc (c, fun);
+ set_cmd_context (c, NULL);
+ c->doc = doc;
+ c->flags = 0;
+ c->replacement = NULL;
+ c->pre_show_hook = NULL;
+ c->hook_pre = NULL;
+ c->hook_post = NULL;
+ c->hook_in = 0;
+ c->prefixlist = NULL;
+ c->prefixname = NULL;
+ c->allow_unknown = 0;
+ c->abbrev_flag = 0;
+ set_cmd_completer (c, 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_pre = NULL;
+ c->hookee_post = NULL;
+ c->cmd_pointer = NULL;
+
+ return c;
+}
+
+/* Deprecates a command CMD.
+ REPLACEMENT is the name of the command which should be used in place
+ of this command, or NULL if no such command exists.
+
+ This function does not check to see if command REPLACEMENT exists
+ since gdb may not have gotten around to adding REPLACEMENT when this
+ function is called.
+
+ Returns a pointer to the deprecated command. */
+
+struct cmd_list_element *
+deprecate_cmd (struct cmd_list_element *cmd, char *replacement)
+{
+ cmd->flags |= (CMD_DEPRECATED | DEPRECATED_WARN_USER);
+
+ if (replacement != NULL)
+ cmd->replacement = replacement;
+ else
+ cmd->replacement = NULL;
+
+ return cmd;
+}
+
+struct cmd_list_element *
+add_alias_cmd (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;
+ struct cmd_list_element *old;
+ 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, NULL, old->doc, list);
+ /* NOTE: Both FUNC and all the FUNCTIONs need to be copied. */
+ c->func = old->func;
+ c->function = old->function;
+ 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 (char *name, enum command_class class, void (*fun) (char *, int),
+ char *doc, struct cmd_list_element **prefixlist,
+ char *prefixname, int allow_unknown,
+ struct cmd_list_element **list)
+{
+ 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 (char *name, enum command_class class,
+ void (*fun) (char *, int), char *doc,
+ struct cmd_list_element **prefixlist, char *prefixname,
+ int allow_unknown, struct cmd_list_element **list)
+{
+ 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 (char *args, int from_tty)
+{
+}
+
+/* This is an empty "sfunc". */
+static void empty_sfunc (char *, int, struct cmd_list_element *);
+
+static void
+empty_sfunc (char *args, int from_tty, struct cmd_list_element *c)
+{
+}
+
+/* Add element named NAME to command list LIST (the list for set/show
+ or some sublist thereof).
+ TYPE is set_cmd or show_cmd.
+ 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. */
+
+static struct cmd_list_element *
+add_set_or_show_cmd (char *name,
+ enum cmd_types type,
+ enum command_class class,
+ var_types var_type,
+ void *var,
+ char *doc,
+ struct cmd_list_element **list)
+{
+ struct cmd_list_element *c = add_cmd (name, class, NULL, doc, list);
+ gdb_assert (type == set_cmd || type == show_cmd);
+ c->type = type;
+ c->var_type = var_type;
+ c->var = var;
+ /* This needs to be something besides NULL so that this isn't
+ treated as a help class. */
+ set_cmd_sfunc (c, empty_sfunc);
+ return c;
+}
+
+/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
+ 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. SET_FUNC and SHOW_FUNC are the callback functions (if
+ non-NULL). SET_DOC and SHOW_DOC are the documentation strings.
+ SET_RESULT and SHOW_RESULT, if not NULL, are set to the resulting
+ command structures. */
+
+void
+add_setshow_cmd_full (char *name,
+ enum command_class class,
+ var_types var_type, void *var,
+ char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func, cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list,
+ struct cmd_list_element **set_result,
+ struct cmd_list_element **show_result)
+{
+ struct cmd_list_element *set;
+ struct cmd_list_element *show;
+ set = add_set_or_show_cmd (name, set_cmd, class, var_type, var,
+ set_doc, set_list);
+ if (set_func != NULL)
+ set_cmd_sfunc (set, set_func);
+ show = add_set_or_show_cmd (name, show_cmd, class, var_type, var,
+ show_doc, show_list);
+ if (show_func != NULL)
+ set_cmd_sfunc (show, show_func);
+
+ if (set_result != NULL)
+ *set_result = set;
+ if (show_result != NULL)
+ *show_result = show;
+}
+
+/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
+ 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. SET_FUNC and SHOW_FUNC are the callback functions (if
+ non-NULL). SET_DOC and SHOW_DOC are the documentation strings. */
+
+void
+add_setshow_cmd (char *name,
+ enum command_class class,
+ var_types var_type, void *var,
+ char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func, cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ add_setshow_cmd_full (name, class, var_type, var, set_doc, show_doc,
+ set_func, show_func, set_list, show_list,
+ NULL, NULL);
+}
+
+struct cmd_list_element *
+add_set_cmd (char *name,
+ enum command_class class,
+ var_types var_type,
+ void *var,
+ char *doc,
+ struct cmd_list_element **list)
+{
+ return add_set_or_show_cmd (name, set_cmd, class, var_type, var, doc, list);
+}
+
+/* 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 (char *name,
+ enum command_class class,
+ const char *enumlist[],
+ const 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;
+}
+
+/* Add an auto-boolean command named NAME to both the set and show
+ command list lists. CLASS is as in add_cmd. VAR is address of the
+ variable which will contain the value. DOC is the documentation
+ string. FUNC is the corresponding callback. */
+void
+add_setshow_auto_boolean_cmd (char *name,
+ enum command_class class,
+ enum auto_boolean *var,
+ char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL };
+ struct cmd_list_element *c;
+ add_setshow_cmd_full (name, class, var_auto_boolean, var,
+ set_doc, show_doc, set_func, show_func,
+ set_list, show_list,
+ &c, NULL);
+ c->enums = auto_boolean_enums;
+}
+
+/* Add element named NAME to both the set and show command LISTs (the
+ list for set/show or some sublist thereof). CLASS is as in
+ add_cmd. VAR is address of the variable which will contain the
+ value. SET_DOC and SHOW_DOR are the documentation strings. */
+void
+add_setshow_boolean_cmd (char *name,
+ enum command_class class,
+ int *var, char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ static const char *boolean_enums[] = { "on", "off", NULL };
+ struct cmd_list_element *c;
+ add_setshow_cmd_full (name, class, var_boolean, var,
+ set_doc, show_doc,
+ set_func, show_func,
+ set_list, show_list,
+ &c, NULL);
+ c->enums = boolean_enums;
+}
+
+/* Add element named NAME to both the set and show command LISTs (the
+ list for set/show or some sublist thereof). CLASS is as in
+ add_cmd. VAR is address of the variable which will contain the
+ value. SET_DOC and SHOW_DOR are the documentation strings. */
+void
+add_setshow_uinteger_cmd (char *name,
+ enum command_class class,
+ unsigned int *var, char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ add_setshow_cmd_full (name, class, var_uinteger, var,
+ set_doc, show_doc,
+ set_func, show_func,
+ set_list, show_list,
+ NULL, NULL);
+}
+
+/* Where SETCMD has already been added, add the corresponding show
+ command to LIST and return a pointer to the added command (not
+ necessarily the head of LIST). */
+/* NOTE: cagney/2002-03-17: The original version of add_show_from_set
+ used memcpy() to clone `set' into `show'. This meant that in
+ addition to all the needed fields (var, name, et.al.) some
+ unnecessary fields were copied (namely the callback function). The
+ function explictly copies relevant fields. For a `set' and `show'
+ command to share the same callback, the caller must set both
+ explicitly. */
+struct cmd_list_element *
+add_show_from_set (struct cmd_list_element *setcmd,
+ struct cmd_list_element **list)
+{
+ char *doc;
+ const static char setstring[] = "Set ";
+
+ /* Create a doc string by replacing "Set " at the start of the
+ `set'' command's doco with "Show ". */
+ gdb_assert (strncmp (setcmd->doc, setstring, sizeof (setstring) - 1) == 0);
+ doc = concat ("Show ", setcmd->doc + sizeof (setstring) - 1, NULL);
+
+ /* Insert the basic command. */
+ return add_set_or_show_cmd (setcmd->name, show_cmd, setcmd->class,
+ setcmd->var_type, setcmd->var, doc, list);
+}
+
+/* Remove the command named NAME from the command list. */
+
+void
+delete_cmd (char *name, struct cmd_list_element **list)
+{
+ struct cmd_list_element *c;
+ struct cmd_list_element *p;
+
+ while (*list && strcmp ((*list)->name, name) == 0)
+ {
+ if ((*list)->hookee_pre)
+ (*list)->hookee_pre->hook_pre = 0; /* Hook slips out of its mouth */
+ if ((*list)->hookee_post)
+ (*list)->hookee_post->hook_post = 0; /* Hook slips out of its bottom */
+ p = (*list)->next;
+ xfree (* list);
+ *list = p;
+ }
+
+ if (*list)
+ for (c = *list; c->next;)
+ {
+ if (strcmp (c->next->name, name) == 0)
+ {
+ if (c->next->hookee_pre)
+ c->next->hookee_pre->hook_pre = 0; /* hooked cmd gets away. */
+ if (c->next->hookee_post)
+ c->next->hookee_post->hook_post = 0; /* remove post hook */
+ /* :( no fishing metaphore */
+ p = c->next->next;
+ xfree (c->next);
+ c->next = p;
+ }
+ else
+ c = c->next;
+ }
+}
+
+/* Shorthands to the commands above. */
+
+/* Add an element to the list of info subcommands. */
+
+struct cmd_list_element *
+add_info (char *name, void (*fun) (char *, int), char *doc)
+{
+ return add_cmd (name, no_class, fun, doc, &infolist);
+}
+
+/* Add an alias to the list of info subcommands. */
+
+struct cmd_list_element *
+add_info_alias (char *name, char *oldname, int abbrev_flag)
+{
+ return add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
+}
+
+/* Add an element to the list of commands. */
+
+struct cmd_list_element *
+add_com (char *name, enum command_class class, void (*fun) (char *, int),
+ char *doc)
+{
+ return add_cmd (name, class, fun, doc, &cmdlist);
+}
+
+/* Add an alias or abbreviation command to the list of commands. */
+
+struct cmd_list_element *
+add_com_alias (char *name, char *oldname, enum command_class class,
+ int abbrev_flag)
+{
+ return add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
+}
+
+/* Recursively walk the commandlist structures, and print out the
+ documentation of commands that match our regex in either their
+ name, or their documentation.
+*/
+void
+apropos_cmd (struct ui_file *stream, struct cmd_list_element *commandlist,
+ struct re_pattern_buffer *regex, char *prefix)
+{
+ struct cmd_list_element *c;
+ int returnvalue=1; /*Needed to avoid double printing*/
+ /* Walk through the commands */
+ for (c=commandlist;c;c=c->next)
+ {
+ if (c->name != NULL)
+ {
+ /* Try to match against the name*/
+ returnvalue=re_search(regex,c->name,strlen(c->name),0,strlen(c->name),NULL);
+ if (returnvalue >= 0)
+ {
+ /* Stolen from help_cmd_list. We don't directly use
+ * help_cmd_list because it doesn't let us print out
+ * single commands
+ */
+ fprintf_filtered (stream, "%s%s -- ", prefix, c->name);
+ print_doc_line (stream, c->doc);
+ fputs_filtered ("\n", stream);
+ returnvalue=0; /*Set this so we don't print it again.*/
+ }
+ }
+ if (c->doc != NULL && returnvalue != 0)
+ {
+ /* Try to match against documentation */
+ if (re_search(regex,c->doc,strlen(c->doc),0,strlen(c->doc),NULL) >=0)
+ {
+ /* Stolen from help_cmd_list. We don't directly use
+ * help_cmd_list because it doesn't let us print out
+ * single commands
+ */
+ fprintf_filtered (stream, "%s%s -- ", prefix, c->name);
+ print_doc_line (stream, c->doc);
+ fputs_filtered ("\n", stream);
+ }
+ }
+ /* Check if this command has subcommands */
+ if (c->prefixlist != NULL)
+ {
+ /* Recursively call ourselves on the subcommand list,
+ passing the right prefix in.
+ */
+ apropos_cmd (stream,*c->prefixlist,regex,c->prefixname);
+ }
+ }
+}
+
+/* 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 (char *command, struct ui_file *stream)
+{
+ struct cmd_list_element *c;
+ extern struct cmd_list_element *cmdlist;
+
+ if (!command)
+ {
+ help_list (cmdlist, "", all_classes, stream);
+ return;
+ }
+
+ if (strcmp (command, "all") == 0)
+ {
+ help_all (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->func is non NULL, we really have a command. Print its
+ documentation and return.
+
+ If c->func is NULL, 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->func != 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->func == NULL)
+ help_list (cmdlist, "", c->class, stream);
+
+ if (c->hook_pre || c->hook_post)
+ fprintf_filtered (stream,
+ "\nThis command has a hook (or hooks) defined:\n");
+
+ if (c->hook_pre)
+ fprintf_filtered (stream,
+ "\tThis command is run after : %s (pre hook)\n",
+ c->hook_pre->name);
+ if (c->hook_post)
+ fprintf_filtered (stream,
+ "\tThis command is run before : %s (post hook)\n",
+ c->hook_post->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 (struct cmd_list_element *list, char *cmdtype,
+ enum command_class class, struct ui_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 ",
+ cmdtype1);
+ wrap_here ("");
+ fprintf_filtered (stream, "that class.");
+ }
+
+ fprintf_filtered (stream, "\nType \"help%s\" followed by %scommand name ",
+ cmdtype1, cmdtype2);
+ wrap_here ("");
+ fputs_filtered ("for ", stream);
+ wrap_here ("");
+ fputs_filtered ("full ", stream);
+ wrap_here ("");
+ fputs_filtered ("documentation.\n", stream);
+ fputs_filtered ("Command name abbreviations are allowed if unambiguous.\n",
+ stream);
+}
+
+static void
+help_all (struct ui_file *stream)
+{
+ struct cmd_list_element *c;
+ extern struct cmd_list_element *cmdlist;
+
+ for (c = cmdlist; c; c = c->next)
+ {
+ if (c->abbrev_flag)
+ continue;
+ /* If this is a prefix command, print it's subcommands */
+ if (c->prefixlist)
+ help_cmd_list (*c->prefixlist, all_commands, c->prefixname, 0, stream);
+
+ /* If this is a class name, print all of the commands in the class */
+ else if (c->func == NULL)
+ help_cmd_list (cmdlist, c->class, "", 0, stream);
+ }
+}
+
+/* Print only the first line of STR on STREAM. */
+void
+print_doc_line (struct ui_file *stream, char *str)
+{
+ static char *line_buffer = 0;
+ static int line_size;
+ 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;
+ xfree (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]);
+ ui_out_text (uiout, line_buffer);
+}
+
+/*
+ * 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 (struct cmd_list_element *list, enum command_class class,
+ char *prefix, int recurse, struct ui_file *stream)
+{
+ struct cmd_list_element *c;
+
+ for (c = list; c; c = c->next)
+ {
+ if (c->abbrev_flag == 0 &&
+ (class == all_commands
+ || (class == all_classes && c->func == NULL)
+ || (class == c->class && c->func != 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);
+ }
+}
+
+
+/* Search the input clist for 'command'. Return the command if
+ found (or NULL if not), and return the number of commands
+ found in nfound */
+
+static struct cmd_list_element *
+find_cmd (char *command, int len, struct cmd_list_element *clist,
+ int ignore_help_classes, int *nfound)
+{
+ struct cmd_list_element *found, *c;
+
+ found = (struct cmd_list_element *) NULL;
+ *nfound = 0;
+ for (c = clist; c; c = c->next)
+ if (!strncmp (command, c->name, len)
+ && (!ignore_help_classes || c->func))
+ {
+ found = c;
+ (*nfound)++;
+ if (c->name[len] == '\0')
+ {
+ *nfound = 1;
+ break;
+ }
+ }
+ return found;
+}
+
+/* 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 (char **text, struct cmd_list_element *clist,
+ struct cmd_list_element **result_list, int ignore_help_classes)
+{
+ char *p, *command;
+ int len, tmp, nfound;
+ struct cmd_list_element *found, *c;
+ char *line = *text;
+
+ 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()". */
+ /* NOTE: cagney/2003-02-13 The `tui_active' was previously
+ `tui_version'. */
+ for (p = *text;
+ *p && (isalnum (*p) || *p == '-' || *p == '_' ||
+#if defined(TUI)
+ (tui_active &&
+ (*p == '+' || *p == '<' || *p == '>' || *p == '$')) ||
+#endif
+ (xdb_commands && (*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 */
+
+
+ command = (char *) alloca (len + 1);
+ for (tmp = 0; tmp < len; tmp++)
+ {
+ char x = (*text)[tmp];
+ command[tmp] = x;
+ }
+ command[len] = '\0';
+
+ /* Look it up. */
+ found = 0;
+ nfound = 0;
+ found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
+
+ /*
+ ** We didn't find the command in the entered case, so lower case it
+ ** and search again.
+ */
+ if (!found || nfound == 0)
+ {
+ for (tmp = 0; tmp < len; tmp++)
+ {
+ char x = command[tmp];
+ command[tmp] = isupper (x) ? tolower (x) : x;
+ }
+ found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
+ }
+
+ /* 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 (found->cmd_pointer)
+ {
+ /* We drop the alias (abbreviation) in favor of the command it is
+ pointing to. If the alias is deprecated, though, we need to
+ warn the user about it before we drop it. Note that while we
+ are warning about the alias, we may also warn about the command
+ itself and we will adjust the appropriate DEPRECATED_WARN_USER
+ flags */
+
+ if (found->flags & DEPRECATED_WARN_USER)
+ deprecated_cmd_warning (&line);
+ 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 properly, 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 (char *cmdtype, char *q)
+{
+ error ("Undefined %scommand: \"%s\". Try \"help%s%.*s\".",
+ cmdtype,
+ q,
+ *cmdtype ? " " : "",
+ (int) 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 (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);
+
+ /* Note: Do not remove trailing whitespace here because this
+ would be wrong for complete_command. Jim Kingdon */
+
+ 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;
+}
+
+/* We are here presumably because an alias or command in *TEXT is
+ deprecated and a warning message should be generated. This function
+ decodes *TEXT and potentially generates a warning message as outlined
+ below.
+
+ Example for 'set endian big' which has a fictitious alias 'seb'.
+
+ If alias wasn't used in *TEXT, and the command is deprecated:
+ "warning: 'set endian big' is deprecated."
+
+ If alias was used, and only the alias is deprecated:
+ "warning: 'seb' an alias for the command 'set endian big' is deprecated."
+
+ If alias was used and command is deprecated (regardless of whether the
+ alias itself is deprecated:
+
+ "warning: 'set endian big' (seb) is deprecated."
+
+ After the message has been sent, clear the appropriate flags in the
+ command and/or the alias so the user is no longer bothered.
+
+*/
+void
+deprecated_cmd_warning (char **text)
+{
+ struct cmd_list_element *alias = NULL;
+ struct cmd_list_element *prefix_cmd = NULL;
+ struct cmd_list_element *cmd = NULL;
+ struct cmd_list_element *c;
+ char *type;
+
+ if (!lookup_cmd_composition (*text, &alias, &prefix_cmd, &cmd))
+ /* return if text doesn't evaluate to a command */
+ return;
+
+ if (!((alias ? (alias->flags & DEPRECATED_WARN_USER) : 0)
+ || (cmd->flags & DEPRECATED_WARN_USER) ) )
+ /* return if nothing is deprecated */
+ return;
+
+ printf_filtered ("Warning:");
+
+ if (alias && !(cmd->flags & CMD_DEPRECATED))
+ printf_filtered (" '%s', an alias for the", alias->name);
+
+ printf_filtered (" command '");
+
+ if (prefix_cmd)
+ printf_filtered ("%s", prefix_cmd->prefixname);
+
+ printf_filtered ("%s", cmd->name);
+
+ if (alias && (cmd->flags & CMD_DEPRECATED))
+ printf_filtered ("' (%s) is deprecated.\n", alias->name);
+ else
+ printf_filtered ("' is deprecated.\n");
+
+
+ /* if it is only the alias that is deprecated, we want to indicate the
+ new alias, otherwise we'll indicate the new command */
+
+ if (alias && !(cmd->flags & CMD_DEPRECATED))
+ {
+ if (alias->replacement)
+ printf_filtered ("Use '%s'.\n\n", alias->replacement);
+ else
+ printf_filtered ("No alternative known.\n\n");
+ }
+ else
+ {
+ if (cmd->replacement)
+ printf_filtered ("Use '%s'.\n\n", cmd->replacement);
+ else
+ printf_filtered ("No alternative known.\n\n");
+ }
+
+ /* We've warned you, now we'll keep quiet */
+ if (alias)
+ alias->flags &= ~DEPRECATED_WARN_USER;
+
+ cmd->flags &= ~DEPRECATED_WARN_USER;
+}
+
+
+
+/* Look up the contents of LINE as a command in the command list 'cmdlist'.
+ Return 1 on success, 0 on failure.
+
+ If LINE refers to an alias, *alias will point to that alias.
+
+ If LINE is a postfix command (i.e. one that is preceeded by a prefix
+ command) set *prefix_cmd.
+
+ Set *cmd to point to the command LINE indicates.
+
+ If any of *alias, *prefix_cmd, or *cmd cannot be determined or do not
+ exist, they are NULL when we return.
+
+*/
+int
+lookup_cmd_composition (char *text,
+ struct cmd_list_element **alias,
+ struct cmd_list_element **prefix_cmd,
+ struct cmd_list_element **cmd)
+{
+ char *p, *command;
+ int len, tmp, nfound;
+ struct cmd_list_element *cur_list;
+ struct cmd_list_element *prev_cmd;
+ *alias = NULL;
+ *prefix_cmd = NULL;
+ *cmd = NULL;
+
+ cur_list = cmdlist;
+
+ while (1)
+ {
+ /* Go through as many command lists as we need to
+ to find the command TEXT refers to. */
+
+ prev_cmd = *cmd;
+
+ 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()". */
+ /* NOTE: cagney/2003-02-13 The `tui_active' was previously
+ `tui_version'. */
+ for (p = text;
+ *p && (isalnum (*p) || *p == '-' || *p == '_' ||
+#if defined(TUI)
+ (tui_active &&
+ (*p == '+' || *p == '<' || *p == '>' || *p == '$')) ||
+#endif
+ (xdb_commands && (*p == '!' || *p == '/' || *p == '?')));
+ p++)
+ ;
+
+ /* If nothing but whitespace, return. */
+ 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 */
+
+ command = (char *) alloca (len + 1);
+ for (tmp = 0; tmp < len; tmp++)
+ {
+ char x = text[tmp];
+ command[tmp] = x;
+ }
+ command[len] = '\0';
+
+ /* Look it up. */
+ *cmd = 0;
+ nfound = 0;
+ *cmd = find_cmd (command, len, cur_list, 1, &nfound);
+
+ /* We didn't find the command in the entered case, so lower case it
+ and search again.
+ */
+ if (!*cmd || nfound == 0)
+ {
+ for (tmp = 0; tmp < len; tmp++)
+ {
+ char x = command[tmp];
+ command[tmp] = isupper (x) ? tolower (x) : x;
+ }
+ *cmd = find_cmd (command, len, cur_list, 1, &nfound);
+ }
+
+ if (*cmd == (struct cmd_list_element *) -1)
+ {
+ return 0; /* ambiguous */
+ }
+
+ if (*cmd == NULL)
+ return 0; /* nothing found */
+ else
+ {
+ if ((*cmd)->cmd_pointer)
+ {
+ /* cmd was actually an alias, we note that an alias was used
+ (by assigning *alais) and we set *cmd.
+ */
+ *alias = *cmd;
+ *cmd = (*cmd)->cmd_pointer;
+ }
+ *prefix_cmd = prev_cmd;
+ }
+ if ((*cmd)->prefixlist)
+ cur_list = *(*cmd)->prefixlist;
+ else
+ return 1;
+
+ text = p;
+ }
+}
+
+/* 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 (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->func
+ || 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)
+ {
+ xfree (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 (const char *enumlist[],
+ char *text,
+ char *word)
+{
+ char **matchlist;
+ int sizeof_matchlist;
+ int matches;
+ int textlen = strlen (text);
+ int i;
+ const char *name;
+
+ sizeof_matchlist = 10;
+ matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *));
+ matches = 0;
+
+ for (i = 0; (name = enumlist[i]) != NULL; i++)
+ if (strncmp (name, text, textlen) == 0)
+ {
+ if (matches == sizeof_matchlist)
+ {
+ sizeof_matchlist *= 2;
+ matchlist = (char **) xrealloc ((char *) matchlist,
+ (sizeof_matchlist
+ * sizeof (char *)));
+ }
+
+ 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)
+ {
+ xfree (matchlist);
+ matchlist = 0;
+ }
+ else
+ {
+ matchlist = (char **) xrealloc ((char *) matchlist, ((matches + 1)
+ * sizeof (char *)));
+ matchlist[matches] = (char *) 0;
+ }
+
+ return matchlist;
+}
+
+
+/* check function pointer */
+int
+cmd_func_p (struct cmd_list_element *cmd)
+{
+ return (cmd->func != NULL);
+}
+
+
+/* call the command function */
+void
+cmd_func (struct cmd_list_element *cmd, char *args, int from_tty)
+{
+ if (cmd_func_p (cmd))
+ (*cmd->func) (cmd, args, from_tty);
+ else
+ error ("Invalid command");
+}
+
+
diff --git a/contrib/gdb/gdb/cli/cli-decode.h b/contrib/gdb/gdb/cli/cli-decode.h
new file mode 100644
index 0000000..d8ab67d
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-decode.h
@@ -0,0 +1,323 @@
+/* Header file for GDB command decoding library.
+
+ Copyright 2000, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (CLI_DECODE_H)
+#define CLI_DECODE_H 1
+
+#include "command.h"
+
+struct re_pattern_buffer;
+
+#if 0
+/* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
+ cmd_types'' can be moved from "command.h" to "cli-decode.h". */
+/* 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;
+#endif
+
+/* This structure records one command'd definition. */
+
+
+/* This flag is used by the code executing commands to warn the user
+ the first time a deprecated command is used, see the 'flags' field in
+ the following struct.
+*/
+#define CMD_DEPRECATED 0x1
+#define DEPRECATED_WARN_USER 0x2
+#define MALLOCED_REPLACEMENT 0x4
+
+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. NULL for command class
+ names and for help topics that are not really commands. NOTE:
+ cagney/2002-02-02: This function signature is evolving. For
+ the moment suggest sticking with either set_cmd_cfunc() or
+ set_cmd_sfunc(). */
+ void (*func) (struct cmd_list_element *c, char *args, int from_tty);
+ /* The command's real callback. At present func() bounces through
+ to one of the below. */
+ union
+ {
+ /* If type is not_set_cmd, call it like this: */
+ cmd_cfunc_ftype *cfunc;
+ /* If type is set_cmd or show_cmd, first set the variables,
+ and then call this: */
+ cmd_sfunc_ftype *sfunc;
+ }
+ function;
+
+ /* Local state (context) for this command. This can be anything. */
+ void *context;
+
+ /* 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;
+
+ /* flags : a bitfield
+
+ bit 0: (LSB) CMD_DEPRECATED, when 1 indicated that this command
+ is deprecated. It may be removed from gdb's command set in the
+ future.
+
+ bit 1: DEPRECATED_WARN_USER, the user needs to be warned that
+ this is a deprecated command. The user should only be warned
+ the first time a command is used.
+
+ bit 2: MALLOCED_REPLACEMENT, when functions are deprecated at
+ compile time (this is the way it should, in general, be done)
+ the memory containing the replacement string is statically
+ allocated. In some cases it makes sense to deprecate commands
+ at runtime (the testsuite is one example). In this case the
+ memory for replacement is malloc'ed. When a command is
+ undeprecated or re-deprecated at runtime we don't want to risk
+ calling free on statically allocated memory, so we check this
+ flag.
+ */
+ int flags;
+
+ /* if this command is deprecated, this is the replacement name */
+ char *replacement;
+
+ /* If this command represents a show command, then this function
+ is called before the variable's value is examined. */
+ void (*pre_show_hook) (struct cmd_list_element *c);
+
+ /* Hook for another command to be executed before this command. */
+ struct cmd_list_element *hook_pre;
+
+ /* Hook for another command to be executed after this command. */
+ struct cmd_list_element *hook_post;
+
+ /* Flag that specifies if this command is already running it's hook. */
+ /* Prevents the possibility of hook recursion. */
+ int hook_in;
+
+ /* 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<tab>" 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) (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. */
+ void *var;
+
+ /* What kind of variable is *VAR? */
+ var_types var_type;
+
+ /* Pointer to NULL terminated list of enumerated values (like argv). */
+ const char **enums;
+
+ /* Pointer to command strings of user-defined commands */
+ struct command_line *user_commands;
+
+ /* Pointer to command that is hooked by this one, (by hook_pre)
+ so the hook can be removed when this one is deleted. */
+ struct cmd_list_element *hookee_pre;
+
+ /* Pointer to command that is hooked by this one, (by hook_post)
+ so the hook can be removed when this one is deleted. */
+ struct cmd_list_element *hookee_post;
+
+ /* 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;
+ };
+
+/* API to the manipulation of command lists. */
+
+extern struct cmd_list_element *add_cmd (char *, enum command_class,
+ void (*fun) (char *, int), char *,
+ struct cmd_list_element **);
+
+extern struct cmd_list_element *add_alias_cmd (char *, char *,
+ enum command_class, int,
+ struct cmd_list_element **);
+
+extern struct cmd_list_element *add_prefix_cmd (char *, enum command_class,
+ void (*fun) (char *, int),
+ char *,
+ struct cmd_list_element **,
+ char *, int,
+ struct cmd_list_element **);
+
+extern struct cmd_list_element *add_abbrev_prefix_cmd (char *,
+ enum command_class,
+ void (*fun) (char *,
+ int),
+ char *,
+ struct cmd_list_element
+ **, char *, int,
+ struct cmd_list_element
+ **);
+
+/* Set the commands corresponding callback. */
+
+extern void set_cmd_cfunc (struct cmd_list_element *cmd,
+ void (*cfunc) (char *args, int from_tty));
+
+extern void set_cmd_sfunc (struct cmd_list_element *cmd,
+ void (*sfunc) (char *args, int from_tty,
+ struct cmd_list_element * c));
+
+extern void set_cmd_completer (struct cmd_list_element *cmd,
+ char **(*completer) (char *text, char *word));
+
+/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
+ around in cmd objects to test the value of the commands sfunc(). */
+extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
+ void (*cfunc) (char *args, int from_tty));
+
+/* Access to the command's local context. */
+extern void set_cmd_context (struct cmd_list_element *cmd, void *context);
+extern void *get_cmd_context (struct cmd_list_element *cmd);
+
+extern struct cmd_list_element *lookup_cmd (char **,
+ struct cmd_list_element *, char *,
+ int, int);
+
+extern struct cmd_list_element *lookup_cmd_1 (char **,
+ struct cmd_list_element *,
+ struct cmd_list_element **,
+ int);
+
+extern struct cmd_list_element *
+ deprecate_cmd (struct cmd_list_element *, char * );
+
+extern void
+ deprecated_cmd_warning (char **);
+
+extern int
+ lookup_cmd_composition (char *text,
+ struct cmd_list_element **alias,
+ struct cmd_list_element **prefix_cmd,
+ struct cmd_list_element **cmd);
+
+extern struct cmd_list_element *add_com (char *, enum command_class,
+ void (*fun) (char *, int), char *);
+
+extern struct cmd_list_element *add_com_alias (char *, char *,
+ enum command_class, int);
+
+extern struct cmd_list_element *add_info (char *, void (*fun) (char *, int),
+ char *);
+
+extern struct cmd_list_element *add_info_alias (char *, char *, int);
+
+extern char **complete_on_cmdlist (struct cmd_list_element *, char *, char *);
+
+extern char **complete_on_enum (const char *enumlist[], char *, char *);
+
+extern void delete_cmd (char *, struct cmd_list_element **);
+
+extern void help_cmd_list (struct cmd_list_element *, enum command_class,
+ char *, int, struct ui_file *);
+
+extern struct cmd_list_element *add_set_cmd (char *name, enum
+ command_class class,
+ var_types var_type, void *var,
+ char *doc,
+ struct cmd_list_element **list);
+
+extern struct cmd_list_element *add_set_enum_cmd (char *name,
+ enum command_class class,
+ const char *enumlist[],
+ const char **var,
+ char *doc,
+ struct cmd_list_element **list);
+
+extern struct cmd_list_element *add_show_from_set (struct cmd_list_element *,
+ struct cmd_list_element
+ **);
+
+/* Functions that implement commands about CLI commands. */
+
+extern void help_cmd (char *, struct ui_file *);
+
+extern void help_list (struct cmd_list_element *, char *,
+ enum command_class, struct ui_file *);
+
+extern void apropos_cmd (struct ui_file *, struct cmd_list_element *,
+ struct re_pattern_buffer *, char *);
+
+/* 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 (char *arg, int from_tty);
+
+/* Exported to cli/cli-setshow.c */
+
+extern void print_doc_line (struct ui_file *, char *);
+
+
+#endif /* !defined (CLI_DECODE_H) */
diff --git a/contrib/gdb/gdb/cli/cli-dump.c b/contrib/gdb/gdb/cli/cli-dump.c
new file mode 100644
index 0000000..ac54aa6
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-dump.c
@@ -0,0 +1,796 @@
+/* Dump-to-file commands, for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "cli/cli-decode.h"
+#include "cli/cli-cmds.h"
+#include "value.h"
+#include "completer.h"
+#include "cli/cli-dump.h"
+#include "gdb_assert.h"
+#include <ctype.h>
+#include "target.h"
+#include "readline/readline.h"
+
+#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
+
+
+char *
+skip_spaces (char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (isspace (*chp))
+ chp++;
+ return chp;
+}
+
+char *
+scan_expression_with_cleanup (char **cmd, const char *def)
+{
+ if ((*cmd) == NULL || (**cmd) == '\0')
+ {
+ char *exp = xstrdup (def);
+ make_cleanup (xfree, exp);
+ return exp;
+ }
+ else
+ {
+ char *exp;
+ char *end;
+
+ end = (*cmd) + strcspn (*cmd, " \t");
+ exp = savestring ((*cmd), end - (*cmd));
+ make_cleanup (xfree, exp);
+ (*cmd) = skip_spaces (end);
+ return exp;
+ }
+}
+
+
+static void
+do_fclose_cleanup (void *arg)
+{
+ FILE *file = arg;
+ fclose (arg);
+}
+
+static struct cleanup *
+make_cleanup_fclose (FILE *file)
+{
+ return make_cleanup (do_fclose_cleanup, file);
+}
+
+char *
+scan_filename_with_cleanup (char **cmd, const char *defname)
+{
+ char *filename;
+ char *fullname;
+
+ /* FIXME: Need to get the ``/a(ppend)'' flag from somewhere. */
+
+ /* File. */
+ if ((*cmd) == NULL)
+ {
+ if (defname == NULL)
+ error ("Missing filename.");
+ filename = xstrdup (defname);
+ make_cleanup (xfree, filename);
+ }
+ else
+ {
+ /* FIXME: should parse a possibly quoted string. */
+ char *end;
+
+ (*cmd) = skip_spaces (*cmd);
+ end = *cmd + strcspn (*cmd, " \t");
+ filename = savestring ((*cmd), end - (*cmd));
+ make_cleanup (xfree, filename);
+ (*cmd) = skip_spaces (end);
+ }
+ gdb_assert (filename != NULL);
+
+ fullname = tilde_expand (filename);
+ make_cleanup (xfree, fullname);
+
+ return fullname;
+}
+
+FILE *
+fopen_with_cleanup (char *filename, const char *mode)
+{
+ FILE *file = fopen (filename, mode);
+ if (file == NULL)
+ perror_with_name (filename);
+ make_cleanup_fclose (file);
+ return file;
+}
+
+static bfd *
+bfd_openr_with_cleanup (const char *filename, const char *target)
+{
+ bfd *ibfd;
+
+ ibfd = bfd_openr (filename, target);
+ if (ibfd == NULL)
+ error ("Failed to open %s: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+
+ make_cleanup_bfd_close (ibfd);
+ if (!bfd_check_format (ibfd, bfd_object))
+ error ("'%s' is not a recognized file format.", filename);
+
+ return ibfd;
+}
+
+static bfd *
+bfd_openw_with_cleanup (char *filename, const char *target, char *mode)
+{
+ bfd *obfd;
+
+ if (*mode == 'w') /* Write: create new file */
+ {
+ obfd = bfd_openw (filename, target);
+ if (obfd == NULL)
+ error ("Failed to open %s: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+ make_cleanup_bfd_close (obfd);
+ if (!bfd_set_format (obfd, bfd_object))
+ error ("bfd_openw_with_cleanup: %s.", bfd_errmsg (bfd_get_error ()));
+ }
+ else if (*mode == 'a') /* Append to existing file */
+ { /* FIXME -- doesn't work... */
+ error ("bfd_openw does not work with append.");
+ }
+ else
+ error ("bfd_openw_with_cleanup: unknown mode %s.", mode);
+
+ return obfd;
+}
+
+struct cmd_list_element *dump_cmdlist;
+struct cmd_list_element *append_cmdlist;
+struct cmd_list_element *srec_cmdlist;
+struct cmd_list_element *ihex_cmdlist;
+struct cmd_list_element *tekhex_cmdlist;
+struct cmd_list_element *binary_dump_cmdlist;
+struct cmd_list_element *binary_append_cmdlist;
+
+static void
+dump_command (char *cmd, int from_tty)
+{
+ printf_unfiltered ("\"dump\" must be followed by a subcommand.\n\n");
+ help_list (dump_cmdlist, "dump ", -1, gdb_stdout);
+}
+
+static void
+append_command (char *cmd, int from_tty)
+{
+ printf_unfiltered ("\"append\" must be followed by a subcommand.\n\n");
+ help_list (dump_cmdlist, "append ", -1, gdb_stdout);
+}
+
+static void
+dump_binary_file (char *filename, char *mode,
+ char *buf, int len)
+{
+ FILE *file;
+ int status;
+
+ file = fopen_with_cleanup (filename, mode);
+ status = fwrite (buf, len, 1, file);
+ if (status != 1)
+ perror_with_name (filename);
+}
+
+static void
+dump_bfd_file (char *filename, char *mode,
+ char *target, CORE_ADDR vaddr,
+ char *buf, int len)
+{
+ bfd *obfd;
+ asection *osection;
+
+ obfd = bfd_openw_with_cleanup (filename, target, mode);
+ osection = bfd_make_section_anyway (obfd, ".newsec");
+ bfd_set_section_size (obfd, osection, len);
+ bfd_set_section_vma (obfd, osection, vaddr);
+ bfd_set_section_alignment (obfd, osection, 0);
+ bfd_set_section_flags (obfd, osection, 0x203);
+ osection->entsize = 0;
+ bfd_set_section_contents (obfd, osection, buf, 0, len);
+}
+
+static void
+dump_memory_to_file (char *cmd, char *mode, char *file_format)
+{
+ struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
+ CORE_ADDR lo;
+ CORE_ADDR hi;
+ ULONGEST count;
+ char *filename;
+ void *buf;
+ char *lo_exp;
+ char *hi_exp;
+ int len;
+
+ /* Open the file. */
+ filename = scan_filename_with_cleanup (&cmd, NULL);
+
+ /* Find the low address. */
+ if (cmd == NULL || *cmd == '\0')
+ error ("Missing start address.");
+ lo_exp = scan_expression_with_cleanup (&cmd, NULL);
+
+ /* Find the second address - rest of line. */
+ if (cmd == NULL || *cmd == '\0')
+ error ("Missing stop address.");
+ hi_exp = cmd;
+
+ lo = parse_and_eval_address (lo_exp);
+ hi = parse_and_eval_address (hi_exp);
+ if (hi <= lo)
+ error ("Invalid memory address range (start >= end).");
+ count = hi - lo;
+
+ /* FIXME: Should use read_memory_partial() and a magic blocking
+ value. */
+ buf = xmalloc (count);
+ make_cleanup (xfree, buf);
+ target_read_memory (lo, buf, count);
+
+ /* Have everything. Open/write the data. */
+ if (file_format == NULL || strcmp (file_format, "binary") == 0)
+ {
+ dump_binary_file (filename, mode, buf, count);
+ }
+ else
+ {
+ dump_bfd_file (filename, mode, file_format, lo, buf, count);
+ }
+
+ do_cleanups (old_cleanups);
+}
+
+static void
+dump_memory_command (char *cmd, char *mode)
+{
+ dump_memory_to_file (cmd, mode, "binary");
+}
+
+static void
+dump_value_to_file (char *cmd, char *mode, char *file_format)
+{
+ struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
+ struct value *val;
+ char *filename;
+
+ /* Open the file. */
+ filename = scan_filename_with_cleanup (&cmd, NULL);
+
+ /* Find the value. */
+ if (cmd == NULL || *cmd == '\0')
+ error ("No value to %s.", *mode == 'a' ? "append" : "dump");
+ val = parse_and_eval (cmd);
+ if (val == NULL)
+ error ("Invalid expression.");
+
+ /* Have everything. Open/write the data. */
+ if (file_format == NULL || strcmp (file_format, "binary") == 0)
+ {
+ dump_binary_file (filename, mode, VALUE_CONTENTS (val),
+ TYPE_LENGTH (VALUE_TYPE (val)));
+ }
+ else
+ {
+ CORE_ADDR vaddr;
+
+ if (VALUE_LVAL (val))
+ {
+ vaddr = VALUE_ADDRESS (val);
+ }
+ else
+ {
+ vaddr = 0;
+ warning ("value is not an lval: address assumed to be zero");
+ }
+
+ dump_bfd_file (filename, mode, file_format, vaddr,
+ VALUE_CONTENTS (val),
+ TYPE_LENGTH (VALUE_TYPE (val)));
+ }
+
+ do_cleanups (old_cleanups);
+}
+
+static void
+dump_value_command (char *cmd, char *mode)
+{
+ dump_value_to_file (cmd, mode, "binary");
+}
+
+static void
+dump_srec_memory (char *args, int from_tty)
+{
+ dump_memory_to_file (args, FOPEN_WB, "srec");
+}
+
+static void
+dump_srec_value (char *args, int from_tty)
+{
+ dump_value_to_file (args, FOPEN_WB, "srec");
+}
+
+static void
+dump_ihex_memory (char *args, int from_tty)
+{
+ dump_memory_to_file (args, FOPEN_WB, "ihex");
+}
+
+static void
+dump_ihex_value (char *args, int from_tty)
+{
+ dump_value_to_file (args, FOPEN_WB, "ihex");
+}
+
+static void
+dump_tekhex_memory (char *args, int from_tty)
+{
+ dump_memory_to_file (args, FOPEN_WB, "tekhex");
+}
+
+static void
+dump_tekhex_value (char *args, int from_tty)
+{
+ dump_value_to_file (args, FOPEN_WB, "tekhex");
+}
+
+static void
+dump_binary_memory (char *args, int from_tty)
+{
+ dump_memory_to_file (args, FOPEN_WB, "binary");
+}
+
+static void
+dump_binary_value (char *args, int from_tty)
+{
+ dump_value_to_file (args, FOPEN_WB, "binary");
+}
+
+static void
+append_binary_memory (char *args, int from_tty)
+{
+ dump_memory_to_file (args, FOPEN_AB, "binary");
+}
+
+static void
+append_binary_value (char *args, int from_tty)
+{
+ dump_value_to_file (args, FOPEN_AB, "binary");
+}
+
+struct dump_context
+{
+ void (*func) (char *cmd, char *mode);
+ char *mode;
+};
+
+static void
+call_dump_func (struct cmd_list_element *c, char *args, int from_tty)
+{
+ struct dump_context *d = get_cmd_context (c);
+ d->func (args, d->mode);
+}
+
+void
+add_dump_command (char *name, void (*func) (char *args, char *mode),
+ char *descr)
+
+{
+ struct cmd_list_element *c;
+ struct dump_context *d;
+
+ c = add_cmd (name, all_commands, NULL, descr, &dump_cmdlist);
+ c->completer = filename_completer;
+ d = XMALLOC (struct dump_context);
+ d->func = func;
+ d->mode = FOPEN_WB;
+ set_cmd_context (c, d);
+ c->func = call_dump_func;
+
+ c = add_cmd (name, all_commands, NULL, descr, &append_cmdlist);
+ c->completer = filename_completer;
+ d = XMALLOC (struct dump_context);
+ d->func = func;
+ d->mode = FOPEN_AB;
+ set_cmd_context (c, d);
+ c->func = call_dump_func;
+
+ /* Replace "Dump " at start of docstring with "Append "
+ (borrowed from add_show_from_set). */
+ if ( c->doc[0] == 'W'
+ && c->doc[1] == 'r'
+ && c->doc[2] == 'i'
+ && c->doc[3] == 't'
+ && c->doc[4] == 'e'
+ && c->doc[5] == ' ')
+ c->doc = concat ("Append ", c->doc + 6, NULL);
+}
+
+/* Opaque data for restore_section_callback. */
+struct callback_data {
+ unsigned long load_offset;
+ CORE_ADDR load_start;
+ CORE_ADDR load_end;
+};
+
+/* Function: restore_section_callback.
+
+ Callback function for bfd_map_over_sections.
+ Selectively loads the sections into memory. */
+
+static void
+restore_section_callback (bfd *ibfd, asection *isec, void *args)
+{
+ struct callback_data *data = args;
+ bfd_vma sec_start = bfd_section_vma (ibfd, isec);
+ bfd_size_type size = bfd_section_size (ibfd, isec);
+ bfd_vma sec_end = sec_start + size;
+ bfd_size_type sec_offset = 0;
+ bfd_size_type sec_load_count = size;
+ struct cleanup *old_chain;
+ char *buf;
+ int ret;
+
+ /* Ignore non-loadable sections, eg. from elf files. */
+ if (!(bfd_get_section_flags (ibfd, isec) & SEC_LOAD))
+ return;
+
+ /* Does the section overlap with the desired restore range? */
+ if (sec_end <= data->load_start
+ || (data->load_end > 0 && sec_start >= data->load_end))
+ {
+ /* No, no useable data in this section. */
+ printf_filtered ("skipping section %s...\n",
+ bfd_section_name (ibfd, isec));
+ return;
+ }
+
+ /* Compare section address range with user-requested
+ address range (if any). Compute where the actual
+ transfer should start and end. */
+ if (sec_start < data->load_start)
+ sec_offset = data->load_start - sec_start;
+ /* Size of a partial transfer: */
+ sec_load_count -= sec_offset;
+ if (data->load_end > 0 && sec_end > data->load_end)
+ sec_load_count -= sec_end - data->load_end;
+
+ /* Get the data. */
+ buf = xmalloc (size);
+ old_chain = make_cleanup (xfree, buf);
+ if (!bfd_get_section_contents (ibfd, isec, buf, 0, size))
+ error ("Failed to read bfd file %s: '%s'.", bfd_get_filename (ibfd),
+ bfd_errmsg (bfd_get_error ()));
+
+ printf_filtered ("Restoring section %s (0x%lx to 0x%lx)",
+ bfd_section_name (ibfd, isec),
+ (unsigned long) sec_start,
+ (unsigned long) sec_end);
+
+ if (data->load_offset != 0 || data->load_start != 0 || data->load_end != 0)
+ printf_filtered (" into memory (0x%s to 0x%s)\n",
+ paddr_nz ((unsigned long) sec_start
+ + sec_offset + data->load_offset),
+ paddr_nz ((unsigned long) sec_start + sec_offset
+ + data->load_offset + sec_load_count));
+ else
+ puts_filtered ("\n");
+
+ /* Write the data. */
+ ret = target_write_memory (sec_start + sec_offset + data->load_offset,
+ buf + sec_offset, sec_load_count);
+ if (ret != 0)
+ warning ("restore: memory write failed (%s).", safe_strerror (ret));
+ do_cleanups (old_chain);
+ return;
+}
+
+static void
+restore_binary_file (char *filename, struct callback_data *data)
+{
+ FILE *file = fopen_with_cleanup (filename, FOPEN_RB);
+ int status;
+ char *buf;
+ long len;
+
+ /* Get the file size for reading. */
+ if (fseek (file, 0, SEEK_END) == 0)
+ len = ftell (file);
+ else
+ perror_with_name (filename);
+
+ if (len <= data->load_start)
+ error ("Start address is greater than length of binary file %s.",
+ filename);
+
+ /* Chop off "len" if it exceeds the requested load_end addr. */
+ if (data->load_end != 0 && data->load_end < len)
+ len = data->load_end;
+ /* Chop off "len" if the requested load_start addr skips some bytes. */
+ if (data->load_start > 0)
+ len -= data->load_start;
+
+ printf_filtered
+ ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
+ filename,
+ (unsigned long) data->load_start + data->load_offset,
+ (unsigned long) data->load_start + data->load_offset + len);
+
+ /* Now set the file pos to the requested load start pos. */
+ if (fseek (file, data->load_start, SEEK_SET) != 0)
+ perror_with_name (filename);
+
+ /* Now allocate a buffer and read the file contents. */
+ buf = xmalloc (len);
+ make_cleanup (xfree, buf);
+ if (fread (buf, 1, len, file) != len)
+ perror_with_name (filename);
+
+ /* Now write the buffer into target memory. */
+ len = target_write_memory (data->load_start + data->load_offset, buf, len);
+ if (len != 0)
+ warning ("restore: memory write failed (%s).", safe_strerror (len));
+ return;
+}
+
+static void
+restore_command (char *args, int from_tty)
+{
+ char *filename;
+ struct callback_data data;
+ bfd *ibfd;
+ int binary_flag = 0;
+
+ if (!target_has_execution)
+ noprocess ();
+
+ data.load_offset = 0;
+ data.load_start = 0;
+ data.load_end = 0;
+
+ /* Parse the input arguments. First is filename (required). */
+ filename = scan_filename_with_cleanup (&args, NULL);
+ if (args != NULL && *args != '\0')
+ {
+ char *binary_string = "binary";
+
+ /* Look for optional "binary" flag. */
+ if (strncmp (args, binary_string, strlen (binary_string)) == 0)
+ {
+ binary_flag = 1;
+ args += strlen (binary_string);
+ args = skip_spaces (args);
+ }
+ /* Parse offset (optional). */
+ if (args != NULL && *args != '\0')
+ data.load_offset =
+ parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
+ if (args != NULL && *args != '\0')
+ {
+ /* Parse start address (optional). */
+ data.load_start =
+ parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
+ if (args != NULL && *args != '\0')
+ {
+ /* Parse end address (optional). */
+ data.load_end = parse_and_eval_long (args);
+ if (data.load_end <= data.load_start)
+ error ("Start must be less than end.");
+ }
+ }
+ }
+
+ if (info_verbose)
+ printf_filtered ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
+ filename, (unsigned long) data.load_offset,
+ (unsigned long) data.load_start,
+ (unsigned long) data.load_end);
+
+ if (binary_flag)
+ {
+ restore_binary_file (filename, &data);
+ }
+ else
+ {
+ /* Open the file for loading. */
+ ibfd = bfd_openr_with_cleanup (filename, NULL);
+
+ /* Process the sections. */
+ bfd_map_over_sections (ibfd, restore_section_callback, &data);
+ }
+ return;
+}
+
+static void
+srec_dump_command (char *cmd, int from_tty)
+{
+ printf_unfiltered ("\"dump srec\" must be followed by a subcommand.\n");
+ help_list (srec_cmdlist, "dump srec ", -1, gdb_stdout);
+}
+
+static void
+ihex_dump_command (char *cmd, int from_tty)
+{
+ printf_unfiltered ("\"dump ihex\" must be followed by a subcommand.\n");
+ help_list (ihex_cmdlist, "dump ihex ", -1, gdb_stdout);
+}
+
+static void
+tekhex_dump_command (char *cmd, int from_tty)
+{
+ printf_unfiltered ("\"dump tekhex\" must be followed by a subcommand.\n");
+ help_list (tekhex_cmdlist, "dump tekhex ", -1, gdb_stdout);
+}
+
+static void
+binary_dump_command (char *cmd, int from_tty)
+{
+ printf_unfiltered ("\"dump binary\" must be followed by a subcommand.\n");
+ help_list (binary_dump_cmdlist, "dump binary ", -1, gdb_stdout);
+}
+
+static void
+binary_append_command (char *cmd, int from_tty)
+{
+ printf_unfiltered ("\"append binary\" must be followed by a subcommand.\n");
+ help_list (binary_append_cmdlist, "append binary ", -1, gdb_stdout);
+}
+
+extern initialize_file_ftype _initialize_cli_dump; /* -Wmissing-prototypes */
+
+void
+_initialize_cli_dump (void)
+{
+ struct cmd_list_element *c;
+ add_prefix_cmd ("dump", class_vars, dump_command, "\
+Dump target code/data to a local file.",
+ &dump_cmdlist, "dump ",
+ 0/*allow-unknown*/,
+ &cmdlist);
+ add_prefix_cmd ("append", class_vars, append_command, "\
+Append target code/data to a local file.",
+ &append_cmdlist, "append ",
+ 0/*allow-unknown*/,
+ &cmdlist);
+
+ add_dump_command ("memory", dump_memory_command, "\
+Write contents of memory to a raw binary file.\n\
+Arguments are FILE START STOP. Writes the contents of memory within the\n\
+range [START .. STOP) to the specifed FILE in raw target ordered bytes.");
+
+ add_dump_command ("value", dump_value_command, "\
+Write the value of an expression to a raw binary file.\n\
+Arguments are FILE EXPRESSION. Writes the value of EXPRESSION to\n\
+the specified FILE in raw target ordered bytes.");
+
+ add_prefix_cmd ("srec", all_commands, srec_dump_command, "\
+Write target code/data to an srec file.",
+ &srec_cmdlist, "dump srec ",
+ 0 /*allow-unknown*/,
+ &dump_cmdlist);
+
+ add_prefix_cmd ("ihex", all_commands, ihex_dump_command, "\
+Write target code/data to an intel hex file.",
+ &ihex_cmdlist, "dump ihex ",
+ 0 /*allow-unknown*/,
+ &dump_cmdlist);
+
+ add_prefix_cmd ("tekhex", all_commands, tekhex_dump_command, "\
+Write target code/data to a tekhex file.",
+ &tekhex_cmdlist, "dump tekhex ",
+ 0 /*allow-unknown*/,
+ &dump_cmdlist);
+
+ add_prefix_cmd ("binary", all_commands, binary_dump_command, "\
+Write target code/data to a raw binary file.",
+ &binary_dump_cmdlist, "dump binary ",
+ 0 /*allow-unknown*/,
+ &dump_cmdlist);
+
+ add_prefix_cmd ("binary", all_commands, binary_append_command, "\
+Append target code/data to a raw binary file.",
+ &binary_append_cmdlist, "append binary ",
+ 0 /*allow-unknown*/,
+ &append_cmdlist);
+
+ add_cmd ("memory", all_commands, dump_srec_memory, "\
+Write contents of memory to an srec file.\n\
+Arguments are FILE START STOP. Writes the contents of memory\n\
+within the range [START .. STOP) to the specifed FILE in srec format.",
+ &srec_cmdlist);
+
+ add_cmd ("value", all_commands, dump_srec_value, "\
+Write the value of an expression to an srec file.\n\
+Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
+to the specified FILE in srec format.",
+ &srec_cmdlist);
+
+ add_cmd ("memory", all_commands, dump_ihex_memory, "\
+Write contents of memory to an ihex file.\n\
+Arguments are FILE START STOP. Writes the contents of memory within\n\
+the range [START .. STOP) to the specifed FILE in intel hex format.",
+ &ihex_cmdlist);
+
+ add_cmd ("value", all_commands, dump_ihex_value, "\
+Write the value of an expression to an ihex file.\n\
+Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
+to the specified FILE in intel hex format.",
+ &ihex_cmdlist);
+
+ add_cmd ("memory", all_commands, dump_tekhex_memory, "\
+Write contents of memory to a tekhex file.\n\
+Arguments are FILE START STOP. Writes the contents of memory\n\
+within the range [START .. STOP) to the specifed FILE in tekhex format.",
+ &tekhex_cmdlist);
+
+ add_cmd ("value", all_commands, dump_tekhex_value, "\
+Write the value of an expression to a tekhex file.\n\
+Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
+to the specified FILE in tekhex format.",
+ &tekhex_cmdlist);
+
+ add_cmd ("memory", all_commands, dump_binary_memory, "\
+Write contents of memory to a raw binary file.\n\
+Arguments are FILE START STOP. Writes the contents of memory\n\
+within the range [START .. STOP) to the specifed FILE in binary format.",
+ &binary_dump_cmdlist);
+
+ add_cmd ("value", all_commands, dump_binary_value, "\
+Write the value of an expression to a raw binary file.\n\
+Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
+to the specified FILE in raw target ordered bytes.",
+ &binary_dump_cmdlist);
+
+ add_cmd ("memory", all_commands, append_binary_memory, "\
+Append contents of memory to a raw binary file.\n\
+Arguments are FILE START STOP. Writes the contents of memory within the\n\
+range [START .. STOP) to the specifed FILE in raw target ordered bytes.",
+ &binary_append_cmdlist);
+
+ add_cmd ("value", all_commands, append_binary_value, "\
+Append the value of an expression to a raw binary file.\n\
+Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
+to the specified FILE in raw target ordered bytes.",
+ &binary_append_cmdlist);
+
+ c = add_com ("restore", class_vars, restore_command,
+ "Restore the contents of FILE to target memory.\n\
+Arguments are FILE OFFSET START END where all except FILE are optional.\n\
+OFFSET will be added to the base address of the file (default zero).\n\
+If START and END are given, only the file contents within that range\n\
+(file relative) will be restored to target memory.");
+ c->completer = filename_completer;
+ /* FIXME: completers for other commands. */
+}
diff --git a/contrib/gdb/gdb/cli/cli-dump.h b/contrib/gdb/gdb/cli/cli-dump.h
new file mode 100644
index 0000000..187e0e0
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-dump.h
@@ -0,0 +1,40 @@
+/* Dump-to-file commands, for GDB, the GNU debugger.
+
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 CLI_DUMP_H
+#define CLI_DUMP_H
+
+extern void add_dump_command (char *name,
+ void (*func) (char *args, char *mode),
+ char *descr);
+
+/* Utilities for doing the dump. */
+extern char *scan_filename_with_cleanup (char **cmd, const char *defname);
+
+extern char *scan_expression_with_cleanup (char **cmd, const char *defname);
+
+extern FILE *fopen_with_cleanup (char *filename, const char *mode);
+
+extern char *skip_spaces (char *inp);
+
+extern struct value *parse_and_eval_with_error (char *exp, const char *fmt, ...) ATTR_FORMAT (printf, 2, 3);
+
+#endif
diff --git a/contrib/gdb/gdb/cli/cli-interp.c b/contrib/gdb/gdb/cli/cli-interp.c
new file mode 100644
index 0000000..6abb24d
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-interp.c
@@ -0,0 +1,157 @@
+/* CLI Definitions for GDB, the GNU debugger.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "interps.h"
+#include "wrapper.h"
+#include "event-top.h"
+#include "ui-out.h"
+#include "cli-out.h"
+#include "top.h" /* for "execute_command" */
+#include "gdb_string.h"
+
+struct ui_out *cli_uiout;
+
+/* These are the ui_out and the interpreter for the console interpreter. */
+
+/* Longjmp-safe wrapper for "execute_command" */
+static int do_captured_execute_command (struct ui_out *uiout, void *data);
+static enum gdb_rc safe_execute_command (struct ui_out *uiout, char *command,
+ int from_tty);
+struct captured_execute_command_args
+{
+ char *command;
+ int from_tty;
+};
+
+/* These implement the cli out interpreter: */
+
+static void *
+cli_interpreter_init (void)
+{
+ return NULL;
+}
+
+static int
+cli_interpreter_resume (void *data)
+{
+ struct ui_file *stream;
+
+ /*sync_execution = 1; */
+
+ /* gdb_setup_readline will change gdb_stdout. If the CLI was previously
+ writing to gdb_stdout, then set it to the new gdb_stdout afterwards. */
+
+ stream = cli_out_set_stream (cli_uiout, gdb_stdout);
+ if (stream != gdb_stdout)
+ {
+ cli_out_set_stream (cli_uiout, stream);
+ stream = NULL;
+ }
+
+ gdb_setup_readline ();
+
+ if (stream != NULL)
+ cli_out_set_stream (cli_uiout, gdb_stdout);
+
+ return 1;
+}
+
+static int
+cli_interpreter_suspend (void *data)
+{
+ gdb_disable_readline ();
+ return 1;
+}
+
+/* Don't display the prompt if we are set quiet. */
+static int
+cli_interpreter_display_prompt_p (void *data)
+{
+ if (interp_quiet_p (NULL))
+ return 0;
+ else
+ return 1;
+}
+
+static int
+cli_interpreter_exec (void *data, const char *command_str)
+{
+ int result;
+ struct ui_file *old_stream;
+
+ /* FIXME: cagney/2003-02-01: Need to const char *propogate
+ safe_execute_command. */
+ char *str = strcpy (alloca (strlen (command_str) + 1), command_str);
+
+ /* gdb_stdout could change between the time cli_uiout was initialized
+ and now. Since we're probably using a different interpreter which has
+ a new ui_file for gdb_stdout, use that one instead of the default.
+
+ It is important that it gets reset everytime, since the user could
+ set gdb to use a different interpreter. */
+ old_stream = cli_out_set_stream (cli_uiout, gdb_stdout);
+ result = safe_execute_command (cli_uiout, str, 1);
+ cli_out_set_stream (cli_uiout, old_stream);
+ return result;
+}
+
+static int
+do_captured_execute_command (struct ui_out *uiout, void *data)
+{
+ struct captured_execute_command_args *args =
+ (struct captured_execute_command_args *) data;
+ execute_command (args->command, args->from_tty);
+ return GDB_RC_OK;
+}
+
+static enum gdb_rc
+safe_execute_command (struct ui_out *uiout, char *command, int from_tty)
+{
+ struct captured_execute_command_args args;
+ args.command = command;
+ args.from_tty = from_tty;
+ return catch_exceptions (uiout, do_captured_execute_command, &args,
+ NULL, RETURN_MASK_ALL);
+}
+
+
+/* standard gdb initialization hook */
+extern initialize_file_ftype _initialize_cli_interp; /* -Wmissing-prototypes */
+
+void
+_initialize_cli_interp (void)
+{
+ static const struct interp_procs procs = {
+ cli_interpreter_init, /* init_proc */
+ cli_interpreter_resume, /* resume_proc */
+ cli_interpreter_suspend, /* suspend_proc */
+ cli_interpreter_exec, /* exec_proc */
+ cli_interpreter_display_prompt_p /* prompt_proc_p */
+ };
+ struct interp *cli_interp;
+
+ /* Create a default uiout builder for the CLI. */
+ cli_uiout = cli_out_new (gdb_stdout);
+ cli_interp = interp_new (INTERP_CONSOLE, NULL, cli_uiout, &procs);
+
+ interp_add (cli_interp);
+}
diff --git a/contrib/gdb/gdb/cli/cli-logging.c b/contrib/gdb/gdb/cli/cli-logging.c
new file mode 100644
index 0000000..db34b0d
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-logging.c
@@ -0,0 +1,205 @@
+/* Command-line output logging for GDB, the GNU debugger.
+
+ Copyright 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ui-out.h"
+
+#include "gdb_string.h"
+
+/* These hold the pushed copies of the gdb output files.
+ If NULL then nothing has yet been pushed. */
+struct saved_output_files
+{
+ struct ui_file *out;
+ struct ui_file *err;
+ struct ui_file *log;
+ struct ui_file *targ;
+};
+static struct saved_output_files saved_output;
+static char *saved_filename;
+
+static char *logging_filename;
+int logging_overwrite, logging_redirect;
+
+/* If we've pushed output files, close them and pop them. */
+static void
+pop_output_files (void)
+{
+ /* Only delete one of the files -- they are all set to the same
+ value. */
+ ui_file_delete (gdb_stdout);
+ gdb_stdout = saved_output.out;
+ gdb_stderr = saved_output.err;
+ gdb_stdlog = saved_output.log;
+ gdb_stdtarg = saved_output.targ;
+ saved_output.out = NULL;
+ saved_output.err = NULL;
+ saved_output.log = NULL;
+ saved_output.targ = NULL;
+
+ ui_out_redirect (uiout, NULL);
+}
+
+/* This is a helper for the `set logging' command. */
+static void
+handle_redirections (int from_tty)
+{
+ struct ui_file *output;
+
+ if (saved_filename != NULL)
+ {
+ fprintf_unfiltered (gdb_stdout, "Already logging to %s.\n",
+ saved_filename);
+ return;
+ }
+
+ output = gdb_fopen (logging_filename, logging_overwrite ? "w" : "a");
+ if (output == NULL)
+ perror_with_name ("set logging");
+
+ /* Redirects everything to gdb_stdout while this is running. */
+ if (!logging_redirect)
+ {
+ output = tee_file_new (gdb_stdout, 0, output, 1);
+ if (output == NULL)
+ perror_with_name ("set logging");
+ if (from_tty)
+ fprintf_unfiltered (gdb_stdout, "Copying output to %s.\n",
+ logging_filename);
+ }
+ else if (from_tty)
+ fprintf_unfiltered (gdb_stdout, "Redirecting output to %s.\n",
+ logging_filename);
+
+ saved_filename = xstrdup (logging_filename);
+ saved_output.out = gdb_stdout;
+ saved_output.err = gdb_stderr;
+ saved_output.log = gdb_stdlog;
+ saved_output.targ = gdb_stdtarg;
+
+ gdb_stdout = output;
+ gdb_stderr = output;
+ gdb_stdlog = output;
+ gdb_stdtarg = output;
+
+ if (ui_out_redirect (uiout, gdb_stdout) < 0)
+ warning ("Current output protocol does not support redirection");
+}
+
+static void
+set_logging_on (char *args, int from_tty)
+{
+ char *rest = args;
+ if (rest && *rest)
+ {
+ xfree (logging_filename);
+ logging_filename = xstrdup (rest);
+ }
+ handle_redirections (from_tty);
+}
+
+static void
+set_logging_off (char *args, int from_tty)
+{
+ if (saved_filename == NULL)
+ return;
+
+ pop_output_files ();
+ if (from_tty)
+ fprintf_unfiltered (gdb_stdout, "Done logging to %s.\n", saved_filename);
+ xfree (saved_filename);
+ saved_filename = NULL;
+}
+
+static void
+set_logging_command (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set logging\" lets you log output to a file.\n");
+ printf_unfiltered ("Usage: set logging on [FILENAME]\n");
+ printf_unfiltered (" set logging off\n");
+ printf_unfiltered (" set logging file FILENAME\n");
+ printf_unfiltered (" set logging overwrite [on|off]\n");
+ printf_unfiltered (" set logging redirect [on|off]\n");
+}
+
+void
+show_logging_command (char *args, int from_tty)
+{
+ if (saved_filename)
+ printf_unfiltered ("Currently logging to \"%s\".\n", saved_filename);
+ if (saved_filename == NULL
+ || strcmp (logging_filename, saved_filename) != 0)
+ printf_unfiltered ("Future logs will be written to %s.\n",
+ logging_filename);
+
+ if (logging_overwrite)
+ printf_unfiltered ("Logs will overwrite the log file.\n");
+ else
+ printf_unfiltered ("Logs will be appended to the log file.\n");
+
+ if (logging_redirect)
+ printf_unfiltered ("Output will be sent only to the log file.\n");
+ else
+ printf_unfiltered ("Output will be logged and displayed.\n");
+}
+
+void
+_initialize_cli_logging (void)
+{
+ static struct cmd_list_element *set_logging_cmdlist, *show_logging_cmdlist;
+
+
+ add_prefix_cmd ("logging", class_support, set_logging_command,
+ "Set logging options", &set_logging_cmdlist,
+ "set logging ", 0, &setlist);
+ add_prefix_cmd ("logging", class_support, show_logging_command,
+ "Show logging options", &show_logging_cmdlist,
+ "show logging ", 0, &showlist);
+ add_setshow_boolean_cmd ("overwrite", class_support, &logging_overwrite,
+ "Set whether logging overwrites or appends "
+ "to the log file.\n",
+ "Show whether logging overwrites or appends "
+ "to the log file.\n",
+ NULL, NULL, &set_logging_cmdlist, &show_logging_cmdlist);
+ add_setshow_boolean_cmd ("redirect", class_support, &logging_redirect,
+ "Set the logging output mode.\n"
+ "If redirect is off, output will go to both the "
+ "screen and the log file.\n"
+ "If redirect is on, output will go only to the log "
+ "file.",
+ "Show the logging output mode.\n"
+ "If redirect is off, output will go to both the "
+ "screen and the log file.\n"
+ "If redirect is on, output will go only to the log "
+ "file.",
+ NULL, NULL, &set_logging_cmdlist, &show_logging_cmdlist);
+ add_setshow_cmd ("file", class_support, var_filename, &logging_filename,
+ "Set the current logfile.", "Show the current logfile.",
+ NULL, NULL, &set_logging_cmdlist, &show_logging_cmdlist);
+ add_cmd ("on", class_support, set_logging_on,
+ "Enable logging.", &set_logging_cmdlist);
+ add_cmd ("off", class_support, set_logging_off,
+ "Disable logging.", &set_logging_cmdlist);
+
+ logging_filename = xstrdup ("gdb.txt");
+}
diff --git a/contrib/gdb/gdb/cli/cli-script.c b/contrib/gdb/gdb/cli/cli-script.c
new file mode 100644
index 0000000..ca0c14f
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-script.c
@@ -0,0 +1,1304 @@
+/* GDB CLI command scripting.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "language.h" /* For value_true */
+#include <ctype.h>
+
+#include "ui-out.h"
+#include "gdb_string.h"
+
+#include "top.h"
+#include "cli/cli-cmds.h"
+#include "cli/cli-decode.h"
+#include "cli/cli-script.h"
+
+/* Prototypes for local functions */
+
+static enum command_control_type
+ recurse_read_control_structure (struct command_line *current_cmd);
+
+static char *insert_args (char *line);
+
+static struct cleanup * setup_user_args (char *p);
+
+static void validate_comname (char *);
+
+/* Level of control structure. */
+static int control_level;
+
+/* Source command state variable. */
+static int source_error_allocated;
+
+/* 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;
+
+
+/* Allocate, initialize a new command line structure for one of the
+ control commands (if/while). */
+
+static struct command_line *
+build_command_line (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 (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_lines (struct ui_out *uiout, struct command_line *cmd,
+ unsigned int depth)
+{
+ struct command_line *list;
+
+ list = cmd;
+ while (list)
+ {
+
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+
+ /* A simple command, print it and continue. */
+ if (list->control_type == simple_control)
+ {
+ ui_out_field_string (uiout, NULL, list->line);
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* loop_continue to jump to the start of a while loop, print it
+ and continue. */
+ if (list->control_type == continue_control)
+ {
+ ui_out_field_string (uiout, NULL, "loop_continue");
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* loop_break to break out of a while loop, print it and continue. */
+ if (list->control_type == break_control)
+ {
+ ui_out_field_string (uiout, NULL, "loop_break");
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* A while command. Recursively print its subcommands and continue. */
+ if (list->control_type == while_control)
+ {
+ ui_out_field_fmt (uiout, NULL, "while %s", list->line);
+ ui_out_text (uiout, "\n");
+ print_command_lines (uiout, *list->body_list, depth + 1);
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+ ui_out_field_string (uiout, NULL, "end");
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* An if command. Recursively print both arms before continueing. */
+ if (list->control_type == if_control)
+ {
+ ui_out_field_fmt (uiout, NULL, "if %s", list->line);
+ ui_out_text (uiout, "\n");
+ /* The true arm. */
+ print_command_lines (uiout, list->body_list[0], depth + 1);
+
+ /* Show the false arm if it exists. */
+ if (list->body_count == 2)
+ {
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+ ui_out_field_string (uiout, NULL, "else");
+ ui_out_text (uiout, "\n");
+ print_command_lines (uiout, list->body_list[1], depth + 1);
+ }
+
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+ ui_out_field_string (uiout, NULL, "end");
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+
+ /* ignore illegal command type and try next */
+ list = list->next;
+ } /* while (list) */
+}
+
+/* Handle pre-post hooks. */
+
+static void
+clear_hook_in_cleanup (void *data)
+{
+ struct cmd_list_element *c = data;
+ c->hook_in = 0; /* Allow hook to work again once it is complete */
+}
+
+void
+execute_cmd_pre_hook (struct cmd_list_element *c)
+{
+ if ((c->hook_pre) && (!c->hook_in))
+ {
+ struct cleanup *cleanups = make_cleanup (clear_hook_in_cleanup, c);
+ c->hook_in = 1; /* Prevent recursive hooking */
+ execute_user_command (c->hook_pre, (char *) 0);
+ do_cleanups (cleanups);
+ }
+}
+
+void
+execute_cmd_post_hook (struct cmd_list_element *c)
+{
+ if ((c->hook_post) && (!c->hook_in))
+ {
+ struct cleanup *cleanups = make_cleanup (clear_hook_in_cleanup, c);
+ c->hook_in = 1; /* Prevent recursive hooking */
+ execute_user_command (c->hook_post, (char *) 0);
+ do_cleanups (cleanups);
+ }
+}
+
+/* Execute the command in CMD. */
+static void
+do_restore_user_call_depth (void * call_depth)
+{
+ int * depth = call_depth;
+ /* We will be returning_to_top_level() at this point, so we want to
+ reset our depth. */
+ (*depth) = 0;
+}
+
+
+void
+execute_user_command (struct cmd_list_element *c, char *args)
+{
+ struct command_line *cmdlines;
+ struct cleanup *old_chain;
+ enum command_control_type ret;
+ static int user_call_depth = 0;
+ extern int max_user_call_depth;
+
+ old_chain = setup_user_args (args);
+
+ cmdlines = c->user_commands;
+ if (cmdlines == 0)
+ /* Null command */
+ return;
+
+ if (++user_call_depth > max_user_call_depth)
+ error ("Max user call depth exceeded -- command aborted\n");
+
+ old_chain = make_cleanup (do_restore_user_call_depth, &user_call_depth);
+
+ /* Set the instream to 0, indicating execution of a
+ user-defined function. */
+ old_chain = make_cleanup (do_restore_instream_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);
+
+ user_call_depth--;
+}
+
+enum command_control_type
+execute_control_command (struct command_line *cmd)
+{
+ struct expression *expr;
+ struct command_line *current;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
+ struct value *val;
+ struct value *val_mark;
+ int loop;
+ enum command_control_type ret;
+ char *new_line;
+
+ /* Start by assuming failure, if a problem is detected, the code
+ below will simply "break" out of the switch. */
+ ret = invalid_control;
+
+ switch (cmd->control_type)
+ {
+ case simple_control:
+ /* A simple command, execute it and return. */
+ new_line = insert_args (cmd->line);
+ if (!new_line)
+ break;
+ 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)
+ break;
+ 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)
+ {
+ int cond_result;
+
+ QUIT;
+
+ /* Evaluate the expression. */
+ val_mark = value_mark ();
+ val = evaluate_expression (expr);
+ cond_result = value_true (val);
+ value_free_to_mark (val_mark);
+
+ /* If the value is false, then break out of the loop. */
+ if (!cond_result)
+ 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)
+ break;
+ 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_mark = value_mark ();
+ 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);
+ value_free_to_mark (val_mark);
+
+ /* 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.");
+ break;
+ }
+
+ do_cleanups (old_chain);
+
+ return ret;
+}
+
+/* "while" command support. Executes a body of statements while the
+ loop condition is nonzero. */
+
+void
+while_command (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. */
+
+void
+if_command (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 (void *ignore)
+{
+ struct user_args *oargs = user_args;
+ if (!user_args)
+ internal_error (__FILE__, __LINE__,
+ "arg_cleanup called with no user args.\n");
+
+ user_args = user_args->next;
+ xfree (oargs);
+}
+
+/* Bind the incomming arguments for a user defined command to
+ $arg0, $arg1 ... $argMAXUSERARGS. */
+
+static struct cleanup *
+setup_user_args (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/*ignored*/);
+
+ if (p == NULL)
+ return old_chain;
+
+ while (*p)
+ {
+ char *start_arg;
+ int squote = 0;
+ int dquote = 0;
+ int bsquote = 0;
+
+ 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)
+ {
+ if (((*p == ' ' || *p == '\t')) && !squote && !dquote && !bsquote)
+ break;
+ else
+ {
+ if (bsquote)
+ bsquote = 0;
+ else if (*p == '\\')
+ bsquote = 1;
+ else if (squote)
+ {
+ if (*p == '\'')
+ squote = 0;
+ }
+ else if (dquote)
+ {
+ if (*p == '"')
+ dquote = 0;
+ }
+ else
+ {
+ if (*p == '\'')
+ squote = 1;
+ else if (*p == '"')
+ dquote = 1;
+ }
+ 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 (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 (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;
+}
+
+
+/* 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 (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);
+
+ xfree (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 (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 || (instream == 0 && readline_hook != NULL))
+ {
+ 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 == 10 && !strncmp (p, "loop_break", 10))
+ {
+ *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 == 13 && !strncmp (p, "loop_continue", 13))
+ {
+ *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
+ structure 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 (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. For input from a
+ terminal, the special command "end" is used to mark the end of the
+ input, and is not included in the returned chain of commands. */
+
+#define END_MESSAGE "End with a line saying just \"end\"."
+
+struct command_line *
+read_command_lines (char *prompt_arg, int from_tty)
+{
+ struct command_line *head, *tail, *next;
+ struct cleanup *old_chain;
+ enum command_control_type ret;
+ enum misc_command_type val;
+
+ control_level = 0;
+ if (readline_begin_hook)
+ {
+ /* Note - intentional to merge messages with no newline */
+ (*readline_begin_hook) ("%s %s\n", prompt_arg, END_MESSAGE);
+ }
+ else if (from_tty && input_from_terminal_p ())
+ {
+ printf_unfiltered ("%s\n%s\n", prompt_arg, END_MESSAGE);
+ gdb_flush (gdb_stdout);
+ }
+
+ 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);
+ }
+ else
+ do_cleanups (old_chain);
+ }
+
+ if (readline_end_hook)
+ {
+ (*readline_end_hook) ();
+ }
+ return (head);
+}
+
+/* Free a chain of struct command_line's. */
+
+void
+free_command_lines (struct command_line **lptr)
+{
+ struct command_line *l = *lptr;
+ 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;
+ xfree (l->line);
+ xfree (l);
+ l = next;
+ }
+ *lptr = NULL;
+}
+
+static void
+do_free_command_lines_cleanup (void *arg)
+{
+ free_command_lines (arg);
+}
+
+struct cleanup *
+make_cleanup_free_command_lines (struct command_line **arg)
+{
+ return make_cleanup (do_free_command_lines_cleanup, arg);
+}
+
+struct command_line *
+copy_command_lines (struct command_line *cmds)
+{
+ struct command_line *result = NULL;
+
+ if (cmds)
+ {
+ result = (struct command_line *) xmalloc (sizeof (struct command_line));
+
+ result->next = copy_command_lines (cmds->next);
+ result->line = xstrdup (cmds->line);
+ result->control_type = cmds->control_type;
+ result->body_count = cmds->body_count;
+ if (cmds->body_count > 0)
+ {
+ int i;
+
+ result->body_list = (struct command_line **)
+ xmalloc (sizeof (struct command_line *) * cmds->body_count);
+
+ for (i = 0; i < cmds->body_count; i++)
+ result->body_list[i] = copy_command_lines (cmds->body_list[i]);
+ }
+ else
+ result->body_list = NULL;
+ }
+
+ return result;
+}
+
+static void
+validate_comname (char *comname)
+{
+ 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 (char *ignore, int from_tty)
+{
+}
+
+void
+define_command (char *comname, int from_tty)
+{
+#define MAX_TMPBUF 128
+ enum cmd_hook_type
+ {
+ CMD_NO_HOOK = 0,
+ CMD_PRE_HOOK,
+ CMD_POST_HOOK
+ };
+ struct command_line *cmds;
+ struct cmd_list_element *c, *newc, *oldc, *hookc = 0;
+ char *tem = comname;
+ char *tem2;
+ char tmpbuf[MAX_TMPBUF];
+ int hook_type = CMD_NO_HOOK;
+ int hook_name_size = 0;
+
+#define HOOK_STRING "hook-"
+#define HOOK_LEN 5
+#define HOOK_POST_STRING "hookpost-"
+#define HOOK_POST_LEN 9
+
+ validate_comname (comname);
+
+ /* Look it up, and verify that we got an exact match. */
+ c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+ if (c && strcmp (comname, c->name) != 0)
+ c = 0;
+
+ if (c)
+ {
+ int q;
+ if (c->class == class_user || c->class == class_alias)
+ q = query ("Redefine command \"%s\"? ", c->name);
+ else
+ q = query ("Really redefine built-in command \"%s\"? ", c->name);
+ if (!q)
+ 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))
+ {
+ hook_type = CMD_PRE_HOOK;
+ hook_name_size = HOOK_LEN;
+ }
+ else if (!strncmp (comname, HOOK_POST_STRING, HOOK_POST_LEN))
+ {
+ hook_type = CMD_POST_HOOK;
+ hook_name_size = HOOK_POST_LEN;
+ }
+
+ if (hook_type != CMD_NO_HOOK)
+ {
+ /* Look up cmd it hooks, and verify that we got an exact match. */
+ tem = comname + hook_name_size;
+ hookc = lookup_cmd (&tem, cmdlist, "", -1, 0);
+ if (hookc && strcmp (comname + hook_name_size, hookc->name) != 0)
+ 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);
+
+ sprintf (tmpbuf, "Type commands for definition of \"%s\".", comname);
+ cmds = read_command_lines (tmpbuf, from_tty);
+
+ 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)
+ {
+ switch (hook_type)
+ {
+ case CMD_PRE_HOOK:
+ hookc->hook_pre = newc; /* Target gets hooked. */
+ newc->hookee_pre = hookc; /* We are marked as hooking target cmd. */
+ break;
+ case CMD_POST_HOOK:
+ hookc->hook_post = newc; /* Target gets hooked. */
+ newc->hookee_post = hookc; /* We are marked as hooking target cmd. */
+ break;
+ default:
+ /* Should never come here as hookc would be 0. */
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ }
+}
+
+void
+document_command (char *comname, int from_tty)
+{
+ struct command_line *doclines;
+ struct cmd_list_element *c;
+ char *tem = comname;
+ char tmpbuf[128];
+
+ validate_comname (comname);
+
+ c = lookup_cmd (&tem, cmdlist, "", 0, 1);
+
+ if (c->class != class_user)
+ error ("Command \"%s\" is built-in.", comname);
+
+ sprintf (tmpbuf, "Type documentation for \"%s\".", comname);
+ doclines = read_command_lines (tmpbuf, from_tty);
+
+ if (c->doc)
+ xfree (c->doc);
+
+ {
+ struct command_line *cl1;
+ 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);
+}
+
+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 (void *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;
+}
+
+static void
+do_fclose_cleanup (void *stream)
+{
+ fclose (stream);
+}
+
+/* Used to implement source_command */
+
+void
+script_from_file (FILE *stream, char *file)
+{
+ struct cleanup *old_cleanups;
+ struct source_cleanup_lines_args old_lines;
+ int needed_length;
+
+ if (stream == NULL)
+ {
+ internal_error (__FILE__, __LINE__, "called with NULL file pointer!");
+ }
+
+ old_cleanups = make_cleanup (do_fclose_cleanup, 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 (xfree, 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);
+}
+
+void
+show_user_1 (struct cmd_list_element *c, struct ui_file *stream)
+{
+ 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);
+
+ print_command_lines (uiout, cmdlines, 1);
+ fputs_filtered ("\n", stream);
+}
+
diff --git a/contrib/gdb/gdb/cli/cli-script.h b/contrib/gdb/gdb/cli/cli-script.h
new file mode 100644
index 0000000..fc5c203
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-script.h
@@ -0,0 +1,56 @@
+/* Header file for GDB CLI command implementation library.
+ Copyright 2000, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (CLI_SCRIPT_H)
+#define CLI_SCRIPT_H 1
+
+struct ui_file;
+struct command_line;
+struct cmd_list_element;
+
+/* Exported to cli/cli-cmds.c */
+
+extern void script_from_file (FILE *stream, char *file);
+
+extern void document_command (char *, int);
+
+extern void define_command (char *, int);
+
+extern void while_command (char *arg, int from_tty);
+
+extern void if_command (char *arg, int from_tty);
+
+extern void show_user_1 (struct cmd_list_element *c, struct ui_file *stream);
+
+/* Exported to gdb/breakpoint.c */
+
+extern enum command_control_type
+ execute_control_command (struct command_line *cmd);
+
+extern void print_command_lines (struct ui_out *,
+ struct command_line *, unsigned int);
+
+extern struct command_line * copy_command_lines (struct command_line *cmds);
+
+struct cleanup *make_cleanup_free_command_lines (struct command_line **arg);
+
+/* Exported to gdb/infrun.c */
+
+extern void execute_user_command (struct cmd_list_element *c, char *args);
+
+#endif /* !defined (CLI_SCRIPT_H) */
diff --git a/contrib/gdb/gdb/cli/cli-setshow.c b/contrib/gdb/gdb/cli/cli-setshow.c
new file mode 100644
index 0000000..62fe36f
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-setshow.c
@@ -0,0 +1,387 @@
+/* Handle set and show GDB commands.
+
+ Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "readline/tilde.h"
+#include "value.h"
+#include <ctype.h>
+#include "gdb_string.h"
+
+#include "ui-out.h"
+
+#include "cli/cli-decode.h"
+#include "cli/cli-cmds.h"
+#include "cli/cli-setshow.h"
+
+/* Prototypes for local functions */
+
+static int parse_binary_operation (char *);
+
+
+static enum auto_boolean
+parse_auto_binary_operation (const char *arg)
+{
+ if (arg != NULL && *arg != '\0')
+ {
+ int length = strlen (arg);
+ while (isspace (arg[length - 1]) && length > 0)
+ length--;
+ if (strncmp (arg, "on", length) == 0
+ || strncmp (arg, "1", length) == 0
+ || strncmp (arg, "yes", length) == 0
+ || strncmp (arg, "enable", length) == 0)
+ return AUTO_BOOLEAN_TRUE;
+ else if (strncmp (arg, "off", length) == 0
+ || strncmp (arg, "0", length) == 0
+ || strncmp (arg, "no", length) == 0
+ || strncmp (arg, "disable", length) == 0)
+ return AUTO_BOOLEAN_FALSE;
+ else if (strncmp (arg, "auto", length) == 0
+ || (strncmp (arg, "-1", length) == 0 && length > 1))
+ return AUTO_BOOLEAN_AUTO;
+ }
+ error ("\"on\", \"off\" or \"auto\" expected.");
+ return AUTO_BOOLEAN_AUTO; /* pacify GCC */
+}
+
+static int
+parse_binary_operation (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) == 0
+ || strncmp (arg, "1", length) == 0
+ || strncmp (arg, "yes", length) == 0
+ || strncmp (arg, "enable", length) == 0)
+ return 1;
+ else if (strncmp (arg, "off", length) == 0
+ || strncmp (arg, "0", length) == 0
+ || strncmp (arg, "no", length) == 0
+ || strncmp (arg, "disable", length) == 0)
+ 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 (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)
+ xfree (*(char **) c->var);
+ *(char **) c->var = new;
+ }
+ break;
+ case var_string_noescape:
+ if (arg == NULL)
+ arg = "";
+ if (*(char **) c->var != NULL)
+ xfree (*(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)
+ xfree (*(char **) c->var);
+ *(char **) c->var = tilde_expand (arg);
+ break;
+ case var_boolean:
+ *(int *) c->var = parse_binary_operation (arg);
+ break;
+ case var_auto_boolean:
+ *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg);
+ break;
+ case var_uinteger:
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ *(unsigned int *) c->var = parse_and_eval_long (arg);
+ if (*(unsigned int *) c->var == 0)
+ *(unsigned int *) c->var = UINT_MAX;
+ break;
+ case var_integer:
+ {
+ unsigned int val;
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ val = parse_and_eval_long (arg);
+ if (val == 0)
+ *(int *) c->var = INT_MAX;
+ else if (val >= INT_MAX)
+ error ("integer %u out of range", val);
+ else
+ *(int *) c->var = val;
+ break;
+ }
+ case var_zinteger:
+ if (arg == NULL)
+ error_no_arg ("integer to set it to.");
+ *(int *) c->var = parse_and_eval_long (arg);
+ break;
+ case var_enum:
+ {
+ int i;
+ int len;
+ int nmatches;
+ const char *match = NULL;
+ char *p;
+
+ /* if no argument was supplied, print an informative error message */
+ if (arg == NULL)
+ {
+ char msg[1024];
+ strcpy (msg, "Requires an argument. Valid arguments are ");
+ for (i = 0; c->enums[i]; i++)
+ {
+ if (i != 0)
+ strcat (msg, ", ");
+ strcat (msg, c->enums[i]);
+ }
+ strcat (msg, ".");
+ error ("%s", msg);
+ }
+
+ 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)
+ {
+ if (c->enums[i][len] == '\0')
+ {
+ match = c->enums[i];
+ nmatches = 1;
+ break; /* exact match. */
+ }
+ else
+ {
+ match = c->enums[i];
+ nmatches++;
+ }
+ }
+
+ if (nmatches <= 0)
+ error ("Undefined item: \"%s\".", arg);
+
+ if (nmatches > 1)
+ error ("Ambiguous item \"%s\".", arg);
+
+ *(const char **) c->var = match;
+ }
+ break;
+ default:
+ error ("gdb internal error: bad var_type in do_setshow_command");
+ }
+ }
+ else if (c->type == show_cmd)
+ {
+ struct cleanup *old_chain;
+ struct ui_stream *stb;
+ int quote;
+
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+ /* Possibly call the pre hook. */
+ if (c->pre_show_hook)
+ (c->pre_show_hook) (c);
+
+ /* Print doc minus "show" at start. */
+ print_doc_line (gdb_stdout, c->doc + 5);
+
+ ui_out_text (uiout, " is ");
+ ui_out_wrap_hint (uiout, " ");
+ quote = 0;
+ switch (c->var_type)
+ {
+ case var_string:
+ {
+ unsigned char *p;
+
+ if (*(unsigned char **) c->var)
+ fputstr_filtered (*(unsigned char **) c->var, '"', stb->stream);
+ quote = 1;
+ }
+ break;
+ case var_string_noescape:
+ case var_filename:
+ case var_enum:
+ if (*(char **) c->var)
+ fputs_filtered (*(char **) c->var, stb->stream);
+ quote = 1;
+ break;
+ case var_boolean:
+ fputs_filtered (*(int *) c->var ? "on" : "off", stb->stream);
+ break;
+ case var_auto_boolean:
+ switch (*(enum auto_boolean*) c->var)
+ {
+ case AUTO_BOOLEAN_TRUE:
+ fputs_filtered ("on", stb->stream);
+ break;
+ case AUTO_BOOLEAN_FALSE:
+ fputs_filtered ("off", stb->stream);
+ break;
+ case AUTO_BOOLEAN_AUTO:
+ fputs_filtered ("auto", stb->stream);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "do_setshow_command: invalid var_auto_boolean");
+ break;
+ }
+ break;
+ case var_uinteger:
+ if (*(unsigned int *) c->var == UINT_MAX)
+ {
+ fputs_filtered ("unlimited", stb->stream);
+ break;
+ }
+ /* else fall through */
+ case var_zinteger:
+ fprintf_filtered (stb->stream, "%u", *(unsigned int *) c->var);
+ break;
+ case var_integer:
+ if (*(int *) c->var == INT_MAX)
+ {
+ fputs_filtered ("unlimited", stb->stream);
+ }
+ else
+ fprintf_filtered (stb->stream, "%d", *(int *) c->var);
+ break;
+
+ default:
+ error ("gdb internal error: bad var_type in do_setshow_command");
+ }
+ if (quote)
+ ui_out_text (uiout, "\"");
+ ui_out_field_stream (uiout, "value", stb);
+ if (quote)
+ ui_out_text (uiout, "\"");
+ ui_out_text (uiout, ".\n");
+ do_cleanups (old_chain);
+ }
+ else
+ error ("gdb internal error: bad cmd_type in do_setshow_command");
+ c->func (c, NULL, from_tty);
+ if (c->type == set_cmd && set_hook)
+ set_hook (c);
+}
+
+/* Show all the settings in a list of show commands. */
+
+void
+cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix)
+{
+ struct cleanup *showlist_chain;
+
+ showlist_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "showlist");
+ 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)
+ {
+ struct cleanup *optionlist_chain
+ = make_cleanup_ui_out_tuple_begin_end (uiout, "optionlist");
+ ui_out_field_string (uiout, "prefix", list->prefixname + 5);
+ cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5);
+ /* Close the tuple. */
+ do_cleanups (optionlist_chain);
+ }
+ if (list->type == show_cmd)
+ {
+ struct cleanup *option_chain
+ = make_cleanup_ui_out_tuple_begin_end (uiout, "option");
+ ui_out_text (uiout, prefix);
+ ui_out_field_string (uiout, "name", list->name);
+ ui_out_text (uiout, ": ");
+ do_setshow_command ((char *) NULL, from_tty, list);
+ /* Close the tuple. */
+ do_cleanups (option_chain);
+ }
+ }
+ /* Close the tuple. */
+ do_cleanups (showlist_chain);
+}
+
diff --git a/contrib/gdb/gdb/cli/cli-setshow.h b/contrib/gdb/gdb/cli/cli-setshow.h
new file mode 100644
index 0000000..470b8b7
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-setshow.h
@@ -0,0 +1,38 @@
+/* Header file for GDB CLI set and show commands implementation.
+ Copyright 2000, 2001 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 (CLI_SETSHOW_H)
+#define CLI_SETSHOW_H 1
+
+struct cmd_list_element;
+
+/* Exported to cli/cli-cmds.c and gdb/top.c */
+
+/* Do a "set" or "show" command. ARG is NULL if no argument, or the text
+ of the argument, and FROM_TTY is nonzero if this command is being entered
+ directly by the user (i.e. these are just like any other
+ command). C is the command list element for the command. */
+extern void do_setshow_command (char *arg, int from_tty,
+ struct cmd_list_element *c);
+
+/* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */
+
+extern void cmd_show_list (struct cmd_list_element *list, int from_tty,
+ char *prefix);
+
+#endif /* !defined (CLI_SETSHOW_H) */
diff --git a/contrib/gdb/gdb/cli/cli-utils.c b/contrib/gdb/gdb/cli/cli-utils.c
new file mode 100644
index 0000000..396d6ea
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-utils.c
@@ -0,0 +1,21 @@
+/* GDB CLI utility library.
+ Copyright 2001 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 "cli/cli-utils.h"
+
diff --git a/contrib/gdb/gdb/cli/cli-utils.h b/contrib/gdb/gdb/cli/cli-utils.h
new file mode 100644
index 0000000..7c318af
--- /dev/null
+++ b/contrib/gdb/gdb/cli/cli-utils.h
@@ -0,0 +1,22 @@
+/* Header file for GDB CLI utility library.
+ Copyright 2001 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 (CLI_UTILS_H)
+# define CLI_UTILS_H 1
+
+#endif /* !defined (CLI_UTILS_H) */
diff --git a/contrib/gdb/gdb/coff-pe-read.c b/contrib/gdb/gdb/coff-pe-read.c
new file mode 100644
index 0000000..2d1e854
--- /dev/null
+++ b/contrib/gdb/gdb/coff-pe-read.c
@@ -0,0 +1,346 @@
+/* Read the export table symbols from a portable executable and
+ convert to internal format, for GDB. Used as a last resort if no
+ debugging symbols recognized.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
+
+#include "coff-pe-read.h"
+
+#include "bfd.h"
+
+#include "defs.h"
+#include "gdbtypes.h"
+
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+/* Internal section information */
+
+struct read_pe_section_data
+{
+ CORE_ADDR vma_offset; /* Offset to loaded address of section. */
+ unsigned long rva_start; /* Start offset within the pe. */
+ unsigned long rva_end; /* End offset within the pe. */
+ enum minimal_symbol_type ms_type; /* Type to assign symbols in section. */
+};
+
+#define PE_SECTION_INDEX_TEXT 0
+#define PE_SECTION_INDEX_DATA 1
+#define PE_SECTION_INDEX_BSS 2
+#define PE_SECTION_TABLE_SIZE 3
+#define PE_SECTION_INDEX_INVALID -1
+
+/* Get the index of the named section in our own array, which contains
+ text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
+ if passed an unrecognised section name. */
+
+static int
+read_pe_section_index (const char *section_name)
+{
+ if (strcmp (section_name, ".text") == 0)
+ {
+ return PE_SECTION_INDEX_TEXT;
+ }
+
+ else if (strcmp (section_name, ".data") == 0)
+ {
+ return PE_SECTION_INDEX_DATA;
+ }
+
+ else if (strcmp (section_name, ".bss") == 0)
+ {
+ return PE_SECTION_INDEX_BSS;
+ }
+
+ else
+ {
+ return PE_SECTION_INDEX_INVALID;
+ }
+}
+
+/* Record the virtual memory address of a section. */
+
+static void
+get_section_vmas (bfd *abfd, asection *sectp, void *context)
+{
+ struct read_pe_section_data *sections = context;
+ int sectix = read_pe_section_index (sectp->name);
+
+ if (sectix != PE_SECTION_INDEX_INVALID)
+ {
+ /* Data within the section start at rva_start in the pe and at
+ bfd_get_section_vma() within memory. Store the offset. */
+
+ sections[sectix].vma_offset
+ = bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
+ }
+}
+
+/* Create a minimal symbol entry for an exported symbol. */
+
+static void
+add_pe_exported_sym (char *sym_name,
+ unsigned long func_rva,
+ const struct read_pe_section_data *section_data,
+ const char *dll_name, struct objfile *objfile)
+{
+ /* Add the stored offset to get the loaded address of the symbol. */
+
+ CORE_ADDR vma = func_rva + section_data->vma_offset;
+
+ char *qualified_name = 0;
+ int dll_name_len = strlen (dll_name);
+ int count;
+
+ /* Generate a (hopefully unique) qualified name using the first part
+ of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
+ used by windbg from the "Microsoft Debugging Tools for Windows". */
+
+ qualified_name = xmalloc (dll_name_len + strlen (sym_name) + 2);
+
+ strncpy (qualified_name, dll_name, dll_name_len);
+ qualified_name[dll_name_len] = '!';
+ strcpy (qualified_name + dll_name_len + 1, sym_name);
+
+ prim_record_minimal_symbol (qualified_name,
+ vma, section_data->ms_type, objfile);
+
+ xfree (qualified_name);
+
+ /* Enter the plain name as well, which might not be unique. */
+ prim_record_minimal_symbol (sym_name, vma, section_data->ms_type, objfile);
+}
+
+/* Truncate a dll_name at the first dot character. */
+
+static void
+read_pe_truncate_name (char *dll_name)
+{
+ while (*dll_name)
+ {
+ if ((*dll_name) == '.')
+ {
+ *dll_name = '\0'; /* truncates and causes loop exit. */
+ }
+
+ else
+ {
+ ++dll_name;
+ }
+ }
+}
+
+/* Low-level support functions, direct from the ld module pe-dll.c. */
+static unsigned int
+pe_get16 (bfd *abfd, int where)
+{
+ unsigned char b[2];
+
+ bfd_seek (abfd, (file_ptr) where, SEEK_SET);
+ bfd_bread (b, (bfd_size_type) 2, abfd);
+ return b[0] + (b[1] << 8);
+}
+
+static unsigned int
+pe_get32 (bfd *abfd, int where)
+{
+ unsigned char b[4];
+
+ bfd_seek (abfd, (file_ptr) where, SEEK_SET);
+ bfd_bread (b, (bfd_size_type) 4, abfd);
+ return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
+}
+
+static unsigned int
+pe_as32 (void *ptr)
+{
+ unsigned char *b = ptr;
+
+ return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
+}
+
+/* Read the (non-debug) export symbol table from a portable
+ executable. Code originally lifted from the ld function
+ pe_implied_import_dll in pe-dll.c. */
+
+void
+read_pe_exported_syms (struct objfile *objfile)
+{
+ bfd *dll = objfile->obfd;
+ unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
+ unsigned long export_rva, export_size, nsections, secptr, expptr;
+ unsigned long exp_funcbase;
+ unsigned char *expdata, *erva;
+ unsigned long name_rvas, ordinals, nexp, ordbase;
+ char *dll_name;
+
+ /* Array elements are for text, data and bss in that order
+ Initialization with start_rva > end_rva guarantees that
+ unused sections won't be matched. */
+ struct read_pe_section_data section_data[PE_SECTION_TABLE_SIZE]
+ = { {0, 1, 0, mst_text},
+ {0, 1, 0, mst_data},
+ {0, 1, 0, mst_bss}
+ };
+
+ struct cleanup *back_to = 0;
+
+ char const *target = bfd_get_target (objfile->obfd);
+
+ if ((strcmp (target, "pe-i386") != 0) && (strcmp (target, "pei-i386") != 0))
+ {
+ /* This is not an i386 format file. Abort now, because the code
+ is untested on anything else. *FIXME* test on further
+ architectures and loosen or remove this test. */
+ return;
+ }
+
+ /* Get pe_header, optional header and numbers of export entries. */
+ pe_header_offset = pe_get32 (dll, 0x3c);
+ opthdr_ofs = pe_header_offset + 4 + 20;
+ num_entries = pe_get32 (dll, opthdr_ofs + 92);
+
+ if (num_entries < 1) /* No exports. */
+ {
+ return;
+ }
+
+ export_rva = pe_get32 (dll, opthdr_ofs + 96);
+ export_size = pe_get32 (dll, opthdr_ofs + 100);
+ nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
+ secptr = (pe_header_offset + 4 + 20 +
+ pe_get16 (dll, pe_header_offset + 4 + 16));
+ expptr = 0;
+
+ /* Get the rva and size of the export section. */
+ for (i = 0; i < nsections; i++)
+ {
+ char sname[8];
+ unsigned long secptr1 = secptr + 40 * i;
+ unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
+ unsigned long vsize = pe_get32 (dll, secptr1 + 16);
+ unsigned long fptr = pe_get32 (dll, secptr1 + 20);
+
+ bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
+ bfd_bread (sname, (bfd_size_type) 8, dll);
+
+ if (vaddr <= export_rva && vaddr + vsize > export_rva)
+ {
+ expptr = fptr + (export_rva - vaddr);
+ if (export_rva + export_size > vaddr + vsize)
+ export_size = vsize - (export_rva - vaddr);
+ break;
+ }
+ }
+
+ if (export_size == 0)
+ {
+ /* Empty export table. */
+ return;
+ }
+
+ /* Scan sections and store the base and size of the relevant sections. */
+ for (i = 0; i < nsections; i++)
+ {
+ unsigned long secptr1 = secptr + 40 * i;
+ unsigned long vsize = pe_get32 (dll, secptr1 + 8);
+ unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
+ unsigned long flags = pe_get32 (dll, secptr1 + 36);
+ char sec_name[9];
+ int sectix;
+
+ sec_name[8] = '\0';
+ bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
+ bfd_bread (sec_name, (bfd_size_type) 8, dll);
+
+ sectix = read_pe_section_index (sec_name);
+
+ if (sectix != PE_SECTION_INDEX_INVALID)
+ {
+ section_data[sectix].rva_start = vaddr;
+ section_data[sectix].rva_end = vaddr + vsize;
+ }
+ }
+
+ expdata = (unsigned char *) xmalloc (export_size);
+ back_to = make_cleanup (xfree, expdata);
+
+ bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
+ bfd_bread (expdata, (bfd_size_type) export_size, dll);
+ erva = expdata - export_rva;
+
+ nexp = pe_as32 (expdata + 24);
+ name_rvas = pe_as32 (expdata + 32);
+ ordinals = pe_as32 (expdata + 36);
+ ordbase = pe_as32 (expdata + 16);
+ exp_funcbase = pe_as32 (expdata + 28);
+
+ /* Use internal dll name instead of full pathname. */
+ dll_name = pe_as32 (expdata + 12) + erva;
+
+ bfd_map_over_sections (dll, get_section_vmas, section_data);
+
+ /* Adjust the vma_offsets in case this PE got relocated. This
+ assumes that *all* sections share the same relocation offset
+ as the text section. */
+ for (i = 0; i < PE_SECTION_TABLE_SIZE; i++)
+ {
+ section_data[i].vma_offset
+ += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ }
+
+ printf_filtered ("Minimal symbols from %s...", dll_name);
+ wrap_here ("");
+
+ /* Truncate name at first dot. Should maybe also convert to all
+ lower case for convenience on Windows. */
+ read_pe_truncate_name (dll_name);
+
+ /* Iterate through the list of symbols. */
+ for (i = 0; i < nexp; i++)
+ {
+ /* Pointer to the names vector. */
+ unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
+
+ /* Pointer to the function address vector. */
+ unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);
+
+ /* Find this symbol's section in our own array. */
+ int sectix = 0;
+
+ for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix)
+ {
+ if ((func_rva >= section_data[sectix].rva_start)
+ && (func_rva < section_data[sectix].rva_end))
+ {
+ add_pe_exported_sym (erva + name_rva,
+ func_rva,
+ section_data + sectix, dll_name, objfile);
+ break;
+ }
+ }
+ }
+
+ /* discard expdata. */
+ do_cleanups (back_to);
+}
diff --git a/contrib/gdb/gdb/coff-pe-read.h b/contrib/gdb/gdb/coff-pe-read.h
new file mode 100644
index 0000000..c5d4e68
--- /dev/null
+++ b/contrib/gdb/gdb/coff-pe-read.h
@@ -0,0 +1,32 @@
+/* Interface to coff-pe-read.c (portable-executable-specific symbol reader).
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
+
+#if !defined (COFF_PE_READ_H)
+#define COFF_PE_READ_H
+
+struct objfile;
+
+/* Read the export table and convert it to minimal symbol table entries */
+extern void read_pe_exported_syms (struct objfile *objfile);
+
+#endif /* !defined (COFF_PE_READ_H) */
diff --git a/contrib/gdb/gdb/coff-solib.c b/contrib/gdb/gdb/coff-solib.c
new file mode 100644
index 0000000..64dca7b
--- /dev/null
+++ b/contrib/gdb/gdb/coff-solib.c
@@ -0,0 +1,134 @@
+/* Handle COFF SVR3 shared libraries for GDB, the GNU Debugger.
+ Copyright 1993, 1994, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "symfile.h"
+#include "objfiles.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, int readsyms)
+
+ DESCRIPTION
+
+ */
+
+void
+coff_solib_add (char *arg_string, int from_tty, struct target_ops *target, int readsyms)
+{
+ asection *libsect;
+
+ if (!readsyms)
+ return;
+
+ 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,
+ NULL, /* no offsets */
+ 0, /* not mainline */
+ OBJF_SHARED); /* flags */
+
+ 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 (void)
+{
+ coff_solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
+}
diff --git a/contrib/gdb/gdb/coff-solib.h b/contrib/gdb/gdb/coff-solib.h
new file mode 100644
index 0000000..d29f96a
--- /dev/null
+++ b/contrib/gdb/gdb/coff-solib.h
@@ -0,0 +1,186 @@
+/* COFF (SVR3) Shared library declarations for GDB, the GNU Debugger.
+ Copyright 1992, 1993, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Forward decl's for prototypes */
+struct target_ops;
+
+/* 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 (void);
+#endif
+
+/* Called to add symbols from a shared library to gdb's symbol table. */
+
+#define SOLIB_ADD(filename, from_tty, targ, readsyms) \
+ coff_solib_add (filename, from_tty, targ, readsyms)
+
+extern void coff_solib_add (char *, int, struct target_ops *, int);
+
+/* 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 (void); /* solib.c */
+
+/* Function to be called to remove the connection between debugger and
+ dynamic linker that was established by SOLIB_CREATE_INFERIOR_HOOK.
+ (This operation does not remove shared library information from
+ the debugger, as CLEAR_SOLIB does.)
+
+ This functionality is presently not implemented for this target.
+ */
+#define SOLIB_REMOVE_INFERIOR_HOOK(PID) (0)
+
+/* This function is called by the "catch load" command. It allows
+ the debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is loaded.
+
+ Presently, this functionality is not implemented.
+ */
+#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag,filename,cond_string) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+
+/* This function is called by the "catch unload" command. It allows
+ the debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is unloaded.
+
+ Presently, this functionality is not implemented.
+ */
+#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename,cond_string) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+
+/* This function returns TRUE if the dynamic linker has just reported
+ a load of a library.
+
+ This function must be used only when the inferior has stopped in
+ the dynamic linker hook, or undefined results are guaranteed.
+
+ Presently, this functionality is not implemented.
+ */
+/*
+ #define SOLIB_HAVE_LOAD_EVENT(pid) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+ */
+
+#define SOLIB_HAVE_LOAD_EVENT(pid) \
+(0)
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been loaded.
+
+ This function must be used only when SOLIB_HAVE_LOAD_EVENT is TRUE,
+ or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the inferior
+ has stopped in the dynamic linker hook, and becomes invalid as soon
+ as the inferior is continued. Clients should make a copy of this
+ string if they wish to continue the inferior and then access the string.
+
+ Presently, this functionality is not implemented.
+ */
+
+/*
+ #define SOLIB_LOADED_LIBRARY_PATHNAME(pid) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+ */
+
+#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) \
+""
+
+/* This function returns TRUE if the dynamic linker has just reported
+ an unload of a library.
+
+ This function must be used only when the inferior has stopped in
+ the dynamic linker hook, or undefined results are guaranteed.
+
+ Presently, this functionality is not implemented.
+ */
+/*
+ #define SOLIB_HAVE_UNLOAD_EVENT(pid) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+ */
+
+#define SOLIB_HAVE_UNLOAD_EVENT(pid) \
+(0)
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been unloaded.
+
+ This function must be used only when SOLIB_HAVE_UNLOAD_EVENT is TRUE,
+ or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the inferior
+ has stopped in the dynamic linker hook, and becomes invalid as soon
+ as the inferior is continued. Clients should make a copy of this
+ string if they wish to continue the inferior and then access the string.
+
+ Presently, this functionality is not implemented.
+ */
+/*
+ #define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+ */
+
+#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) \
+(0)
+
+/* This function returns TRUE if pc is the address of an instruction that
+ lies within the dynamic linker (such as the event hook, or the dld
+ itself).
+
+ This function must be used only when a dynamic linker event has been
+ caught, and the inferior is being stepped out of the hook, or undefined
+ results are guaranteed.
+
+ Presently, this functionality is not implemented.
+ */
+
+/*
+ #define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+ */
+
+#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
+(0)
+
+/* This function must be called when the inferior is killed, and the program
+ restarted. This is not the same as CLEAR_SOLIB, in that it doesn't discard
+ any symbol tables.
+
+ Presently, this functionality is not implemented.
+ */
+#define SOLIB_RESTART() \
+ (0)
+
+/* 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 (CORE_ADDR); /* solib.c */
+#endif
diff --git a/contrib/gdb/gdb/coffread.c b/contrib/gdb/gdb/coffread.c
new file mode 100644
index 0000000..056ba13
--- /dev/null
+++ b/contrib/gdb/gdb/coffread.c
@@ -0,0 +1,2140 @@
+/* Read coff symbol tables and convert to internal format, for GDB.
+ Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ 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 "demangle.h"
+#include "breakpoint.h"
+
+#include "bfd.h"
+#include "gdb_obstack.h"
+
+#include "gdb_string.h"
+#include <ctype.h>
+
+#include "coff/internal.h" /* Internal format of COFF symbols in BFD */
+#include "libcoff.h" /* FIXME secret internal data from BFD */
+#include "objfiles.h"
+#include "buildsym.h"
+#include "gdb-stabs.h"
+#include "stabsread.h"
+#include "complaints.h"
+#include "target.h"
+#include "gdb_assert.h"
+#include "block.h"
+#include "dictionary.h"
+
+#include "coff-pe-read.h"
+
+extern void _initialize_coffread (void);
+
+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))
+
+/* 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;
+
+
+/* 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;
+
+/* This is set if this is a PE format file. */
+
+static int pe_file;
+
+/* 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];
+
+/* 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;
+ };
+
+extern void stabsread_clear_cache (void);
+
+static struct type *coff_read_struct_type (int, int, int);
+
+static struct type *decode_base_type (struct coff_symbol *,
+ unsigned int, union internal_auxent *);
+
+static struct type *decode_type (struct coff_symbol *, unsigned int,
+ union internal_auxent *);
+
+static struct type *decode_function_type (struct coff_symbol *,
+ unsigned int,
+ union internal_auxent *);
+
+static struct type *coff_read_enum_type (int, int, int);
+
+static struct symbol *process_coff_symbol (struct coff_symbol *,
+ union internal_auxent *,
+ struct objfile *);
+
+static void patch_opaque_types (struct symtab *);
+
+static void enter_linenos (long, int, int, struct objfile *);
+
+static void free_linetab (void);
+
+static void free_linetab_cleanup (void *ignore);
+
+static int init_lineno (bfd *, long, int);
+
+static char *getsymname (struct internal_syment *);
+
+static char *coff_getfilename (union internal_auxent *);
+
+static void free_stringtab (void);
+
+static void free_stringtab_cleanup (void *ignore);
+
+static int init_stringtab (bfd *, long);
+
+static void read_one_sym (struct coff_symbol *,
+ struct internal_syment *, union internal_auxent *);
+
+static void coff_symtab_read (long, unsigned int, struct objfile *);
+
+/* 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 (bfd *abfd, asection *sectp, void *csip)
+{
+ struct coff_symfile_info *csi;
+ const char *name;
+
+ csi = (struct coff_symfile_info *) csip;
+ name = bfd_get_section_name (abfd, sectp);
+ if (DEPRECATED_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 (DEPRECATED_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 (xfree, n);
+ }
+ }
+}
+
+/* Return the section_offsets* that CS points to. */
+static int cs_to_section (struct coff_symbol *, struct objfile *);
+
+struct find_targ_sec_arg
+ {
+ int targ_index;
+ asection **resultp;
+ };
+
+static void
+find_targ_sec (bfd *abfd, asection *sect, void *obj)
+{
+ struct find_targ_sec_arg *args = (struct find_targ_sec_arg *) obj;
+ if (sect->target_index == args->targ_index)
+ *args->resultp = sect;
+}
+
+/* Return the section number (SECT_OFF_*) that CS points to. */
+static int
+cs_to_section (struct coff_symbol *cs, struct objfile *objfile)
+{
+ asection *sect = NULL;
+ struct find_targ_sec_arg args;
+ int off = SECT_OFF_TEXT (objfile);
+
+ args.targ_index = cs->c_secnum;
+ args.resultp = &sect;
+ bfd_map_over_sections (objfile->obfd, find_targ_sec, &args);
+ if (sect != NULL)
+ {
+ /* This is the section. Figure out what SECT_OFF_* code it is. */
+ if (bfd_get_section_flags (abfd, sect) & SEC_CODE)
+ off = SECT_OFF_TEXT (objfile);
+ else if (bfd_get_section_flags (abfd, sect) & SEC_LOAD)
+ off = SECT_OFF_DATA (objfile);
+ else
+ /* Just return the bfd section index. */
+ off = sect->index;
+ }
+ return off;
+}
+
+/* Return the address of the section of a COFF symbol. */
+
+static CORE_ADDR cs_section_address (struct coff_symbol *, bfd *);
+
+static CORE_ADDR
+cs_section_address (struct coff_symbol *cs, bfd *abfd)
+{
+ asection *sect = NULL;
+ struct find_targ_sec_arg args;
+ CORE_ADDR addr = 0;
+
+ args.targ_index = cs->c_secnum;
+ args.resultp = &sect;
+ bfd_map_over_sections (abfd, find_targ_sec, &args);
+ if (sect != NULL)
+ addr = bfd_get_section_vma (objfile->obfd, sect);
+ return addr;
+}
+
+/* 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 (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 (int index)
+{
+ struct type **type_addr = coff_lookup_type (index);
+ 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;
+}
+
+/* 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 (char *name)
+{
+ 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 (name, strlen (name)),
+ /* 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);
+ record_debugformat ("COFF");
+}
+
+/* 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 (char *name, CORE_ADDR start_addr, unsigned int size)
+{
+ if (last_source_file != NULL)
+ xfree (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.deprecated_entry_file_lowpc = current_source_start_addr;
+ current_objfile->ei.deprecated_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 (struct objfile *objfile)
+{
+ struct symtab *symtab;
+
+ last_source_start_addr = current_source_start_addr;
+
+ symtab = end_symtab (current_source_end_addr, objfile, SECT_OFF_TEXT (objfile));
+
+ if (symtab != NULL)
+ free_named_symtabs (symtab->filename);
+
+ /* Reinitialize for beginning of new file. */
+ last_source_file = NULL;
+}
+
+static void
+record_minimal_symbol (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 (name, 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 (struct objfile *objfile)
+{
+ /* Allocate struct to keep track of stab reading. */
+ objfile->sym_stab_info = (struct dbx_symfile_info *)
+ xmmalloc (objfile->md, sizeof (struct dbx_symfile_info));
+
+ memset (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. */
+
+static void
+find_linenos (bfd *abfd, struct bfd_section *asect, void *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. */
+
+static void
+coff_symfile_read (struct objfile *objfile, 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);
+ int val;
+ unsigned int num_symbols;
+ int symtab_offset;
+ int stringtab_offset;
+ struct cleanup *back_to, *cleanup_minimal_symbols;
+ int stabstrsize;
+ int len;
+ char * target;
+
+ info = (struct coff_symfile_info *) objfile->sym_private;
+ dbxinfo = 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_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);
+
+ /* We need to know whether this is a PE file, because in PE files,
+ unlike standard COFF files, symbol values are stored as offsets
+ from the section address, rather than as absolute addresses.
+ FIXME: We should use BFD to read the symbol table, and thus avoid
+ this problem. */
+ pe_file =
+ strncmp (bfd_get_target (objfile->obfd), "pe", 2) == 0
+ || strncmp (bfd_get_target (objfile->obfd), "epoc-pe", 7) == 0;
+
+/* End of warning */
+
+ info->min_lineno_offset = 0;
+ info->max_lineno_offset = 0;
+
+ /* Only read line number information if we have symbols.
+
+ On Windows NT, some of the system's DLL's have sections with
+ PointerToLinenumbers fields that are non-zero, but point at
+ random places within the image file. (In the case I found,
+ KERNEL32.DLL's .text section has a line number info pointer that
+ points into the middle of the string `lib\\i386\kernel32.dll'.)
+
+ However, these DLL's also have no symbols. The line number
+ tables are meaningless without symbols. And in fact, GDB never
+ uses the line number information unless there are symbols. So we
+ can avoid spurious error messages (and maybe run a little
+ faster!) by not even reading the line number table unless we have
+ symbols. */
+ if (num_symbols > 0)
+ {
+ /* Read the line number table, all at once. */
+ bfd_map_over_sections (abfd, find_linenos, (void *) info);
+
+ make_cleanup (free_linetab_cleanup, 0 /*ignore*/);
+ 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_cleanup, 0 /*ignore*/);
+ val = init_stringtab (abfd, stringtab_offset);
+ if (val < 0)
+ error ("\"%s\": can't get string table", name);
+
+ init_minimal_symbol_collection ();
+ cleanup_minimal_symbols = make_cleanup_discard_minimal_symbols ();
+
+ /* Now that the executable file is positioned at symbol table,
+ process it and define symbols accordingly. */
+
+ coff_symtab_read ((long) symtab_offset, num_symbols, objfile);
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ /* Free the installed minimal symbol data. */
+ do_cleanups (cleanup_minimal_symbols);
+
+ bfd_map_over_sections (abfd, coff_locate_sections, (void *) info);
+
+ if (info->stabsects)
+ {
+ if (!info->stabstrsect)
+ {
+ error (("The debugging information in `%s' is corrupted.\n"
+ "The file has a `.stabs' section, but no `.stabstr' "
+ "section."),
+ name);
+ }
+
+ /* 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,
+ mainline,
+ info->textaddr, info->textsize,
+ info->stabsects,
+ info->stabstrsect->filepos, stabstrsize);
+ }
+ if (dwarf2_has_info (abfd))
+ {
+ /* DWARF2 sections. */
+ dwarf2_build_psymtabs (objfile, mainline);
+ }
+
+ do_cleanups (back_to);
+}
+
+static void
+coff_new_init (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 (struct objfile *objfile)
+{
+ if (objfile->sym_private != NULL)
+ {
+ xmfree (objfile->md, objfile->sym_private);
+ }
+
+ /* Let stabs reader clean up */
+ stabsread_clear_cache ();
+}
+
+
+/* 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 (long symtab_offset, unsigned int nsyms,
+ struct objfile *objfile)
+{
+ struct context_stack *new;
+ struct coff_symbol coff_symbol;
+ 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;
+ CORE_ADDR fcn_first_line_addr = 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 */
+ xfree (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);
+
+ if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE)
+ {
+ if (last_source_file)
+ coff_end_symtab (objfile);
+
+ coff_start_symtab ("_globals_");
+ 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 (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ 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:
+ complaint (&symfile_complaints, "Bad n_sclass for symbol %s",
+ 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 (filestring);
+ }
+ in_source_file = 1;
+ break;
+
+ /* C_LABEL is used for labels and static functions. Including
+ it here allows gdb to see static functions when no debug
+ info is available. */
+ case C_LABEL:
+ /* However, labels within a function can make weird backtraces,
+ so filter them out (from phdm@macqel.be). */
+ if (within_function)
+ break;
+ case C_STAT:
+ case C_THUMBLABEL:
+ case C_THUMBSTAT:
+ case C_THUMBSTATFUNC:
+ if (cs->c_name[0] == '.')
+ {
+ if (DEPRECATED_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 (objfile->section_offsets, SECT_OFF_TEXT (objfile)),
+ 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_THUMBEXT:
+ case C_THUMBEXTFUNC:
+ 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. */
+
+ 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_EXT
+ || cs->c_sclass == C_THUMBEXT ?
+ mst_bss : mst_file_bss;
+ }
+ else if (cs->c_secnum == N_ABS)
+ {
+ /* Use the correct minimal symbol type (and don't
+ relocate) for absolute values. */
+ ms_type = mst_abs;
+ sec = cs_to_section (cs, objfile);
+ tmpaddr = cs->c_value;
+ }
+ else
+ {
+ sec = cs_to_section (cs, objfile);
+ tmpaddr = cs->c_value;
+ /* Statics in a PE file also get relocated */
+ if (cs->c_sclass == C_EXT
+ || cs->c_sclass == C_THUMBEXTFUNC
+ || cs->c_sclass == C_THUMBEXT
+ || (pe_file && (cs->c_sclass == C_STAT)))
+ tmpaddr += ANOFFSET (objfile->section_offsets, sec);
+
+ if (sec == SECT_OFF_TEXT (objfile))
+ {
+ ms_type =
+ cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXTFUNC
+ || cs->c_sclass == C_THUMBEXT ?
+ mst_text : mst_file_text;
+ tmpaddr = SMASH_TEXT_ADDRESS (tmpaddr);
+ }
+ else if (sec == SECT_OFF_DATA (objfile))
+ {
+ ms_type =
+ cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXT ?
+ mst_data : mst_file_data;
+ }
+ else if (sec == SECT_OFF_BSS (objfile))
+ {
+ ms_type =
+ cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXT ?
+ mst_data : mst_file_data;
+ }
+ else
+ ms_type = mst_unknown;
+ }
+
+ if (cs->c_name[0] != '@' /* Skip tdesc symbols */ )
+ {
+ struct minimal_symbol *msym;
+ msym = prim_record_minimal_symbol_and_info
+ (cs->c_name, tmpaddr, ms_type, NULL,
+ sec, NULL, objfile);
+ if (msym)
+ COFF_MAKE_MSYMBOL_SPECIAL (cs->c_sclass, msym);
+ }
+ if (SDB_TYPE (cs->c_type))
+ {
+ struct symbol *sym;
+ sym = process_coff_symbol
+ (cs, &main_aux, objfile);
+ SYMBOL_VALUE (sym) = tmpaddr;
+ SYMBOL_SECTION (sym) = sec;
+ }
+ }
+ break;
+
+ case C_FCN:
+ if (DEPRECATED_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)
+ complaint (&symfile_complaints,
+ "`.bf' symbol %d has no aux entry", cs->c_symnum);
+ fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+ fcn_first_line_addr = cs->c_value;
+
+ /* 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, objfile);
+ }
+ else if (DEPRECATED_STREQ (cs->c_name, ".ef"))
+ {
+ if (!within_function)
+ error ("Bad coff function information\n");
+ /* 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 */
+ complaint (&symfile_complaints,
+ "`.ef' symbol without matching `.bf' symbol ignored starting at symnum %d",
+ cs->c_symnum);
+ within_function = 0;
+ break;
+ }
+
+ new = pop_context ();
+ /* Stack must be empty now. */
+ if (context_stack_depth > 0 || new == NULL)
+ {
+ complaint (&symfile_complaints,
+ "Unmatched .ef symbol(s) ignored starting at symnum %d",
+ cs->c_symnum);
+ within_function = 0;
+ break;
+ }
+ if (cs->c_naux != 1)
+ {
+ complaint (&symfile_complaints,
+ "`.ef' symbol %d has no aux entry", cs->c_symnum);
+ fcn_last_line = 0x7FFFFFFF;
+ }
+ else
+ {
+ fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+ }
+ /* fcn_first_line is the line number of the opening '{'.
+ Do not record it - because it would affect gdb's idea
+ of the line number of the first statement of the function -
+ except for one-line functions, for which it is also the line
+ number of all the statements and of the closing '}', and
+ for which we do not have any other statement-line-number. */
+ if (fcn_last_line == 1)
+ record_line (current_subfile, fcn_first_line,
+ fcn_first_line_addr);
+ else
+ enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line,
+ objfile);
+
+ 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 (objfile->section_offsets, SECT_OFF_TEXT (objfile)),
+#else
+ fcn_cs_saved.c_value
+ + fcn_aux_saved.x_sym.x_misc.x_fsize
+ + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)),
+#endif
+ objfile
+ );
+ within_function = 0;
+ }
+ break;
+
+ case C_BLOCK:
+ if (DEPRECATED_STREQ (cs->c_name, ".bb"))
+ {
+ tmpaddr = cs->c_value;
+ tmpaddr += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ push_context (++depth, tmpaddr);
+ }
+ else if (DEPRECATED_STREQ (cs->c_name, ".eb"))
+ {
+ if (context_stack_depth <= 0)
+ { /* We attempted to pop an empty context stack */
+ complaint (&symfile_complaints,
+ "`.eb' symbol without matching `.bb' symbol ignored starting at symnum %d",
+ cs->c_symnum);
+ break;
+ }
+
+ new = pop_context ();
+ if (depth-- != new->depth)
+ {
+ complaint (&symfile_complaints,
+ "Mismatched .eb symbol ignored starting at symnum %d",
+ symnum);
+ break;
+ }
+ if (local_symbols && context_stack_depth > 0)
+ {
+ tmpaddr =
+ cs->c_value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ /* 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, objfile);
+ break;
+ }
+ }
+
+ if ((nsyms == 0) && (pe_file))
+ {
+ /* We've got no debugging symbols, but it's is a portable
+ executable, so try to read the export table */
+ read_pe_exported_syms (objfile);
+ }
+
+ 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 (struct coff_symbol *cs,
+ struct internal_syment *sym,
+ union internal_auxent *aux)
+{
+ int i;
+
+ cs->c_symnum = symnum;
+ bfd_bread (temp_sym, local_symesz, 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_bread (temp_aux, local_auxesz, 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_bread (temp_aux, local_auxesz, 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;
+
+#if 0
+ if (cs->c_sclass & 128)
+ printf ("thumb symbol %s, class 0x%x\n", cs->c_name, cs->c_sclass);
+#endif
+
+ symnum += 1 + cs->c_naux;
+
+ /* The PE file format stores symbol values as offsets within the
+ section, rather than as absolute addresses. We correct that
+ here, if the symbol has an appropriate storage class. FIXME: We
+ should use BFD to read the symbols, rather than duplicating the
+ work here. */
+ if (pe_file)
+ {
+ switch (cs->c_sclass)
+ {
+ case C_EXT:
+ case C_THUMBEXT:
+ case C_THUMBEXTFUNC:
+ case C_SECTION:
+ case C_NT_WEAK:
+ case C_STAT:
+ case C_THUMBSTAT:
+ case C_THUMBSTATFUNC:
+ case C_LABEL:
+ case C_THUMBLABEL:
+ case C_BLOCK:
+ case C_FCN:
+ case C_EFCN:
+ if (cs->c_secnum != 0)
+ cs->c_value += cs_section_address (cs, symfile_bfd);
+ break;
+ }
+ }
+}
+
+/* Support for string table handling */
+
+static char *stringtab = NULL;
+
+static int
+init_stringtab (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_bread ((char *) lengthbuf, sizeof lengthbuf, 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_bread (stringtab + sizeof lengthbuf, length - sizeof lengthbuf,
+ abfd);
+ if (val != length - sizeof lengthbuf || stringtab[length - 1] != '\0')
+ return -1;
+
+ return 0;
+}
+
+static void
+free_stringtab (void)
+{
+ if (stringtab)
+ xfree (stringtab);
+ stringtab = NULL;
+}
+
+static void
+free_stringtab_cleanup (void *ignore)
+{
+ free_stringtab ();
+}
+
+static char *
+getsymname (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 (union internal_auxent *aux_entry)
+{
+ static char buffer[BUFSIZ];
+ 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 (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_bread (linetab, size, 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 (void)
+{
+ if (linetab)
+ xfree (linetab);
+ linetab = NULL;
+}
+
+static void
+free_linetab_cleanup (void *ignore)
+{
+ free_linetab ();
+}
+
+#if !defined (L_LNNO32)
+#define L_LNNO32(lp) ((lp)->l_lnno)
+#endif
+
+static void
+enter_linenos (long file_offset, int first_line,
+ int last_line, struct objfile *objfile)
+{
+ char *rawptr;
+ struct internal_lineno lptr;
+
+ if (!linetab)
+ return;
+ if (file_offset < linetab_offset)
+ {
+ complaint (&symfile_complaints,
+ "Line number pointer %ld lower than start of line numbers",
+ 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--;
+
+ /* If the line number table is full (e.g. 64K lines in COFF debug
+ info), the next function's L_LNNO32 might not be zero, so don't
+ overstep the table's end in any case. */
+ while (rawptr <= &linetab[0] + linetab_size)
+ {
+ 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)
+ record_line (current_subfile, first_line + L_LNNO32 (&lptr),
+ lptr.l_addr.l_paddr
+ + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)));
+ else
+ break;
+ }
+}
+
+static void
+patch_type (struct type *type, struct type *real_type)
+{
+ struct type *target = TYPE_TARGET_TYPE (type);
+ 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))
+ xfree (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 (struct symtab *s)
+{
+ struct block *b;
+ struct dict_iterator iter;
+ struct symbol *real_sym;
+
+ /* Go through the per-file symbols only */
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ ALL_BLOCK_SYMBOLS (b, iter, real_sym)
+ {
+ /* 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. */
+ if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF &&
+ SYMBOL_DOMAIN (real_sym) == VAR_DOMAIN &&
+ TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0)
+ {
+ char *name = DEPRECATED_SYMBOL_NAME (real_sym);
+ int hash = hashname (name);
+ struct symbol *sym, *prev;
+
+ prev = 0;
+ for (sym = opaque_type_chain[hash]; sym;)
+ {
+ if (name[0] == DEPRECATED_SYMBOL_NAME (sym)[0] &&
+ strcmp (name + 1, DEPRECATED_SYMBOL_NAME (sym) + 1) == 0)
+ {
+ 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 (struct coff_symbol *cs,
+ union internal_auxent *aux,
+ struct objfile *objfile)
+{
+ struct symbol *sym
+ = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ char *name;
+
+ memset (sym, 0, sizeof (struct symbol));
+ name = cs->c_name;
+ name = EXTERNAL_NAME (name, objfile->obfd);
+ SYMBOL_LANGUAGE (sym) = language_auto;
+ SYMBOL_SET_NAMES (sym, name, strlen (name), objfile);
+
+ /* default assumptions */
+ SYMBOL_VALUE (sym) = cs->c_value;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ SYMBOL_SECTION (sym) = cs_to_section (cs, objfile);
+
+ if (ISFCN (cs->c_type))
+ {
+ SYMBOL_VALUE (sym) += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ 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 || cs->c_sclass == C_THUMBSTAT
+ || cs->c_sclass == C_THUMBSTATFUNC)
+ add_symbol_to_list (sym, &file_symbols);
+ else if (cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXT
+ || cs->c_sclass == C_THUMBEXTFUNC)
+ 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_THUMBEXT:
+ case C_THUMBEXTFUNC:
+ case C_EXT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+ SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ case C_THUMBSTAT:
+ case C_THUMBSTATFUNC:
+ case C_STAT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+ SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ 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_THUMBLABEL:
+ 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 == BFD_ENDIAN_BIG)
+ {
+ /* 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_DOMAIN (sym) = VAR_DOMAIN;
+
+ /* 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 (DEPRECATED_SYMBOL_NAME (sym), NULL);
+ }
+
+ /* 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)
+ {
+ int i = hashname (DEPRECATED_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_DOMAIN (sym) = STRUCT_DOMAIN;
+
+ /* 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 (DEPRECATED_SYMBOL_NAME (sym) != NULL
+ && *DEPRECATED_SYMBOL_NAME (sym) != '~'
+ && *DEPRECATED_SYMBOL_NAME (sym) != '.')
+ TYPE_TAG_NAME (SYMBOL_TYPE (sym)) =
+ concat (DEPRECATED_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 (struct coff_symbol *cs, unsigned int c_type,
+ union internal_auxent *aux)
+{
+ 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;
+ 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
+ {
+ complaint (&symfile_complaints,
+ "Symbol table entry for %s has bad tagndx value",
+ 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 (struct coff_symbol *cs, unsigned int c_type,
+ 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 (struct coff_symbol *cs, unsigned int c_type,
+ 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);
+
+#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:
+ if (cs->c_sclass == C_FIELD
+ && aux->x_sym.x_misc.x_lnsz.x_size > TARGET_LONG_BIT)
+ return lookup_fundamental_type (current_objfile, FT_LONG_LONG);
+ else
+ 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 "<opaque>". 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 "<opaque>". 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 "<opaque>". 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:
+ if (cs->c_sclass == C_FIELD
+ && aux->x_sym.x_misc.x_lnsz.x_size > TARGET_LONG_BIT)
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
+ else
+ return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+ }
+ complaint (&symfile_complaints, "Unexpected type for symbol %s", 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 (int index, int length, int lastsym)
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ struct field field;
+ };
+
+ struct type *type;
+ struct nextfield *list = 0;
+ struct nextfield *new;
+ int nfields = 0;
+ int n;
+ char *name;
+ struct coff_symbol member_sym;
+ 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),
+ &current_objfile->objfile_obstack);
+ FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux);
+ FIELD_BITPOS (list->field) = 8 * ms->c_value;
+ FIELD_BITSIZE (list->field) = 0;
+ FIELD_STATIC_KIND (list->field) = 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),
+ &current_objfile->objfile_obstack);
+ FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux);
+ FIELD_BITPOS (list->field) = ms->c_value;
+ FIELD_BITSIZE (list->field) = sub_aux.x_sym.x_misc.x_lnsz.x_size;
+ FIELD_STATIC_KIND (list->field) = 0;
+ 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. */
+
+static struct type *
+coff_read_enum_type (int index, int length, int lastsym)
+{
+ struct symbol *sym;
+ struct type *type;
+ int nsyms = 0;
+ int done = 0;
+ struct pending **symlist;
+ struct coff_symbol member_sym;
+ struct coff_symbol *ms = &member_sym;
+ struct internal_syment sub_sym;
+ union internal_auxent sub_aux;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+ int n;
+ char *name;
+ int unsigned_enum = 1;
+
+ 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
+ (&current_objfile->objfile_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+
+ DEPRECATED_SYMBOL_NAME (sym) =
+ obsavestring (name, strlen (name),
+ &current_objfile->objfile_obstack);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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) = DEPRECATED_SYMBOL_NAME (xsym);
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+ if (SYMBOL_VALUE (xsym) < 0)
+ unsigned_enum = 0;
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ TYPE_FIELD_STATIC_KIND (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ if (unsigned_enum)
+ TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+
+ return type;
+}
+
+/* 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 */
+ default_symfile_offsets, /* sym_offsets: xlate external to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_coffread (void)
+{
+ add_symtab_fns (&coff_sym_fns);
+}
diff --git a/contrib/gdb/gdb/command.h b/contrib/gdb/gdb/command.h
new file mode 100644
index 0000000..c4a5f20
--- /dev/null
+++ b/contrib/gdb/gdb/command.h
@@ -0,0 +1,299 @@
+/* Header file for command-reading library command.c.
+
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1999,
+ 2000, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (COMMAND_H)
+#define COMMAND_H 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 */
+ class_deprecated, 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_trace,
+ class_alias, class_obscure, class_user, class_maintenance,
+ class_pseudo, class_tui, class_xdb
+};
+
+/* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
+ cmd_types'' can be moved from "command.h" to "cli-decode.h". */
+/* 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,
+
+ /* "on" / "true" / "enable" or "off" / "false" / "disable" or
+ "auto. *VAR is an ``enum auto_boolean''. NOTE: In general a
+ custom show command will need to be implemented - one that for
+ "auto" prints both the "auto" and the current auto-selected
+ value. */
+ var_auto_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;
+
+/* Forward-declarations of the entry-points of cli/cli-decode.c. */
+
+extern struct cmd_list_element *add_cmd (char *, enum command_class,
+ void (*fun) (char *, int), char *,
+ struct cmd_list_element **);
+
+extern struct cmd_list_element *add_alias_cmd (char *, char *,
+ enum command_class, int,
+ struct cmd_list_element **);
+
+extern struct cmd_list_element *add_prefix_cmd (char *, enum command_class,
+ void (*fun) (char *, int),
+ char *,
+ struct cmd_list_element **,
+ char *, int,
+ struct cmd_list_element **);
+
+extern struct cmd_list_element *add_abbrev_prefix_cmd (char *,
+ enum command_class,
+ void (*fun) (char *,
+ int),
+ char *,
+ struct cmd_list_element
+ **, char *, int,
+ struct cmd_list_element
+ **);
+
+/* Set the commands corresponding callback. */
+
+typedef void cmd_cfunc_ftype (char *args, int from_tty);
+extern void set_cmd_cfunc (struct cmd_list_element *cmd,
+ cmd_cfunc_ftype *cfunc);
+
+typedef void cmd_sfunc_ftype (char *args, int from_tty,
+ struct cmd_list_element *c);
+extern void set_cmd_sfunc (struct cmd_list_element *cmd,
+ cmd_sfunc_ftype *sfunc);
+
+extern void set_cmd_completer (struct cmd_list_element *cmd,
+ char **(*completer) (char *text, char *word));
+
+/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
+ around in cmd objects to test the value of the commands sfunc(). */
+extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
+ void (*cfunc) (char *args, int from_tty));
+
+/* Each command object has a local context attached to it. . */
+extern void set_cmd_context (struct cmd_list_element *cmd, void *context);
+extern void *get_cmd_context (struct cmd_list_element *cmd);
+
+
+/* Execute CMD's pre/post hook. Throw an error if the command fails.
+ If already executing this pre/post hook, or there is no pre/post
+ hook, the call is silently ignored. */
+extern void execute_cmd_pre_hook (struct cmd_list_element *cmd);
+extern void execute_cmd_post_hook (struct cmd_list_element *cmd);
+
+/* Return the type of the command. */
+/* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+ the set command passed as a parameter. The clone operation will
+ include (BUG?) any ``set'' command callback, if present. Commands
+ like ``info set'' call all the ``show'' command callbacks.
+ Unfortunately, for ``show'' commands cloned from ``set'', this
+ includes callbacks belonging to ``set'' commands. Making this
+ worse, this only occures if add_show_from_set() is called after
+ add_cmd_sfunc() (BUG?). */
+extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
+
+
+extern struct cmd_list_element *lookup_cmd (char **,
+ struct cmd_list_element *, char *,
+ int, int);
+
+extern struct cmd_list_element *lookup_cmd_1 (char **,
+ struct cmd_list_element *,
+ struct cmd_list_element **,
+ int);
+
+extern struct cmd_list_element *
+ deprecate_cmd (struct cmd_list_element *, char * );
+
+extern void
+ deprecated_cmd_warning (char **);
+
+extern int
+ lookup_cmd_composition (char *text,
+ struct cmd_list_element **alias,
+ struct cmd_list_element **prefix_cmd,
+ struct cmd_list_element **cmd);
+
+extern struct cmd_list_element *add_com (char *, enum command_class,
+ void (*fun) (char *, int), char *);
+
+extern struct cmd_list_element *add_com_alias (char *, char *,
+ enum command_class, int);
+
+extern struct cmd_list_element *add_info (char *, void (*fun) (char *, int),
+ char *);
+
+extern struct cmd_list_element *add_info_alias (char *, char *, int);
+
+extern char **complete_on_cmdlist (struct cmd_list_element *, char *, char *);
+
+extern char **complete_on_enum (const char *enumlist[], char *, char *);
+
+extern void delete_cmd (char *, struct cmd_list_element **);
+
+extern void help_cmd (char *, struct ui_file *);
+
+extern void help_list (struct cmd_list_element *, char *,
+ enum command_class, struct ui_file *);
+
+extern void help_cmd_list (struct cmd_list_element *, enum command_class,
+ char *, int, struct ui_file *);
+
+extern void add_setshow_cmd (char *name,
+ enum command_class class,
+ var_types var_type, void *var,
+ char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list);
+
+extern void add_setshow_cmd_full (char *name,
+ enum command_class class,
+ var_types var_type, void *var,
+ char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list,
+ struct cmd_list_element **set_result,
+ struct cmd_list_element **show_result);
+
+extern struct cmd_list_element *add_set_cmd (char *name, enum
+ command_class class,
+ var_types var_type, void *var,
+ char *doc,
+ struct cmd_list_element **list);
+
+extern struct cmd_list_element *add_set_enum_cmd (char *name,
+ enum command_class class,
+ const char *enumlist[],
+ const char **var,
+ char *doc,
+ struct cmd_list_element **list);
+
+extern void add_setshow_auto_boolean_cmd (char *name,
+ enum command_class class,
+ enum auto_boolean *var,
+ char *set_doc, char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list);
+
+extern void add_setshow_boolean_cmd (char *name,
+ enum command_class class,
+ int *var,
+ char *set_doc,
+ char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list);
+
+extern void add_setshow_uinteger_cmd (char *name,
+ enum command_class class,
+ unsigned int *var,
+ char *set_doc,
+ char *show_doc,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list);
+
+extern struct cmd_list_element *add_show_from_set (struct cmd_list_element *,
+ struct cmd_list_element
+ **);
+
+/* Do a "show" command for each thing on a command list. */
+
+extern void cmd_show_list (struct cmd_list_element *, int, char *);
+
+extern NORETURN void error_no_arg (char *) ATTR_NORETURN;
+
+extern void dont_repeat (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 (char *, int);
+
+/* check function pointer */
+extern int cmd_func_p (struct cmd_list_element *cmd);
+
+/* call the command function */
+extern void cmd_func (struct cmd_list_element *cmd, char *args, int from_tty);
+
+#endif /* !defined (COMMAND_H) */
diff --git a/contrib/gdb/gdb/complaints.c b/contrib/gdb/gdb/complaints.c
new file mode 100644
index 0000000..ed24f43
--- /dev/null
+++ b/contrib/gdb/gdb/complaints.c
@@ -0,0 +1,321 @@
+/* Support for complaint handling during symbol reading in GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1995, 1998, 1999, 2000, 2002 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_assert.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+extern void _initialize_complaints (void);
+
+/* Should each complaint message be self explanatory, or should we assume that
+ a series of complaints is being produced? */
+
+/* case 1: First message of a series that must
+ start off with explanation. case 2: Subsequent message of a series
+ that needs no explanation (the user already knows we have a problem
+ so we can just state our piece). */
+enum complaint_series {
+ /* Isolated self explanatory message. */
+ ISOLATED_MESSAGE,
+ /* First message of a series, includes an explanation. */
+ FIRST_MESSAGE,
+ /* First message of a series, but does not need to include any sort
+ of explanation. */
+ SHORT_FIRST_MESSAGE,
+ /* Subsequent message of a series that needs no explanation (the
+ user already knows we have a problem so we can just state our
+ piece). */
+ SUBSEQUENT_MESSAGE
+};
+
+/* Structure to manage complaints about symbol file contents. */
+
+struct complain
+{
+ const char *file;
+ int line;
+ const char *fmt;
+ int counter;
+ struct complain *next;
+};
+
+/* The explanatory message that should accompany the complaint. The
+ message is in two parts - pre and post - that are printed around
+ the complaint text. */
+struct explanation
+{
+ const char *prefix;
+ const char *postfix;
+};
+
+struct complaints
+{
+ struct complain *root;
+
+ /* Should each complaint be self explanatory, or should we assume
+ that a series of complaints is being produced? case 0: Isolated
+ self explanatory message. case 1: First message of a series that
+ must start off with explanation. case 2: Subsequent message of a
+ series that needs no explanation (the user already knows we have
+ a problem so we can just state our piece). */
+ int series;
+
+ /* The explanatory messages that should accompany the complaint.
+ NOTE: cagney/2002-08-14: In a desperate attempt at being vaguely
+ i18n friendly, this is an array of two messages. When present,
+ the PRE and POST EXPLANATION[SERIES] are used to wrap the
+ message. */
+ const struct explanation *explanation;
+};
+
+static struct complain complaint_sentinel;
+
+/* The symbol table complaint table. */
+
+static struct explanation symfile_explanations[] = {
+ { "During symbol reading, ", "." },
+ { "During symbol reading...", "..."},
+ { "", "..."},
+ { "", "..."},
+ { NULL, NULL }
+};
+
+static struct complaints symfile_complaint_book = {
+ &complaint_sentinel,
+ 0,
+ symfile_explanations
+};
+struct complaints *symfile_complaints = &symfile_complaint_book;
+
+/* Wrapper function to, on-demand, fill in a complaints object. */
+
+static struct complaints *
+get_complaints (struct complaints **c)
+{
+ if ((*c) != NULL)
+ return (*c);
+ (*c) = XMALLOC (struct complaints);
+ (*c)->root = &complaint_sentinel;
+ (*c)->series = ISOLATED_MESSAGE;
+ (*c)->explanation = NULL;
+ return (*c);
+}
+
+static struct complain *
+find_complaint (struct complaints *complaints, const char *file,
+ int line, const char *fmt)
+{
+ struct complain *complaint;
+
+ /* Find the complaint in the table. A more efficient search
+ algorithm (based on hash table or something) could be used. But
+ that can wait until someone shows evidence that this lookup is
+ a real bottle neck. */
+ for (complaint = complaints->root;
+ complaint != NULL;
+ complaint = complaint->next)
+ {
+ if (complaint->fmt == fmt
+ && complaint->file == file
+ && complaint->line == line)
+ return complaint;
+ }
+
+ /* Oops not seen before, fill in a new complaint. */
+ complaint = XMALLOC (struct complain);
+ complaint->fmt = fmt;
+ complaint->file = file;
+ complaint->line = line;
+ complaint->counter = 0;
+ complaint->next = NULL;
+
+ /* File it, return it. */
+ complaint->next = complaints->root;
+ complaints->root = complaint;
+ return 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;
+
+/* Print a complaint, and link the complaint block into a chain for
+ later handling. */
+
+static void
+vcomplaint (struct complaints **c, const char *file, int line, const char *fmt,
+ va_list args)
+{
+ struct complaints *complaints = get_complaints (c);
+ struct complain *complaint = find_complaint (complaints, file, line, fmt);
+ enum complaint_series series;
+ gdb_assert (complaints != NULL);
+
+ complaint->counter++;
+ if (complaint->counter > stop_whining)
+ return;
+
+ if (info_verbose)
+ series = SUBSEQUENT_MESSAGE;
+ else
+ series = complaints->series;
+
+ if (complaint->file != NULL)
+ internal_vwarning (complaint->file, complaint->line, complaint->fmt, args);
+ else if (warning_hook)
+ (*warning_hook) (complaint->fmt, args);
+ else
+ {
+ if (complaints->explanation == NULL)
+ /* A [v]warning() call always appends a newline. */
+ vwarning (complaint->fmt, args);
+ else
+ {
+ char *msg;
+ struct cleanup *cleanups;
+ xvasprintf (&msg, complaint->fmt, args);
+ cleanups = make_cleanup (xfree, msg);
+ wrap_here ("");
+ if (series != SUBSEQUENT_MESSAGE)
+ begin_line ();
+ fprintf_filtered (gdb_stderr, "%s%s%s",
+ complaints->explanation[series].prefix, msg,
+ complaints->explanation[series].postfix);
+ /* Force a line-break after any isolated message. For the
+ other cases, clear_complaints() takes care of any missing
+ trailing newline, the wrap_here() is just a hint. */
+ if (series == ISOLATED_MESSAGE)
+ /* It would be really nice to use begin_line() here.
+ Unfortunately that function doesn't track GDB_STDERR and
+ consequently will sometimes supress a line when it
+ shouldn't. */
+ fputs_filtered ("\n", gdb_stderr);
+ else
+ wrap_here ("");
+ do_cleanups (cleanups);
+ }
+ }
+
+ switch (series)
+ {
+ case ISOLATED_MESSAGE:
+ break;
+ case FIRST_MESSAGE:
+ complaints->series = SUBSEQUENT_MESSAGE;
+ break;
+ case SUBSEQUENT_MESSAGE:
+ case SHORT_FIRST_MESSAGE:
+ complaints->series = SUBSEQUENT_MESSAGE;
+ break;
+ }
+
+ /* 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_stderr);
+}
+
+void
+complaint (struct complaints **complaints, const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vcomplaint (complaints, NULL/*file*/, 0/*line*/, fmt, args);
+ va_end (args);
+}
+
+void
+internal_complaint (struct complaints **complaints, const char *file,
+ int line, const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vcomplaint (complaints, file, line, fmt, args);
+ va_end (args);
+}
+
+/* Clear out / initialize all complaint counters that have ever been
+ incremented. If LESS_VERBOSE is 1, be less verbose about
+ successive complaints, since the messages are appearing all
+ together during a command that is reporting a contiguous block of
+ complaints (rather than being interleaved with other messages). If
+ noisy is 1, we are in a noisy command, and our caller will print
+ enough context for the user to figure it out. */
+
+void
+clear_complaints (struct complaints **c, int less_verbose, int noisy)
+{
+ struct complaints *complaints = get_complaints (c);
+ struct complain *p;
+
+ for (p = complaints->root; p != NULL; p = p->next)
+ {
+ p->counter = 0;
+ }
+
+ switch (complaints->series)
+ {
+ case FIRST_MESSAGE:
+ /* Haven't yet printed anything. */
+ break;
+ case SHORT_FIRST_MESSAGE:
+ /* Haven't yet printed anything. */
+ break;
+ case ISOLATED_MESSAGE:
+ /* The code above, always forces a line-break. No need to do it
+ here. */
+ break;
+ case SUBSEQUENT_MESSAGE:
+ /* It would be really nice to use begin_line() here.
+ Unfortunately that function doesn't track GDB_STDERR and
+ consequently will sometimes supress a line when it shouldn't. */
+ fputs_unfiltered ("\n", gdb_stderr);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ if (!less_verbose)
+ complaints->series = ISOLATED_MESSAGE;
+ else if (!noisy)
+ complaints->series = FIRST_MESSAGE;
+ else
+ complaints->series = SHORT_FIRST_MESSAGE;
+}
+
+void
+_initialize_complaints (void)
+{
+ add_setshow_cmd ("complaints", class_support, var_zinteger,
+ &stop_whining,
+ "Set max number of complaints about incorrect symbols.",
+ "Show max number of complaints about incorrect symbols.",
+ NULL, NULL,
+ &setlist, &showlist);
+
+}
diff --git a/contrib/gdb/gdb/complaints.h b/contrib/gdb/gdb/complaints.h
new file mode 100644
index 0000000..0168b52
--- /dev/null
+++ b/contrib/gdb/gdb/complaints.h
@@ -0,0 +1,53 @@
+/* Definitions for complaint handling during symbol reading in GDB.
+
+ Copyright 1990, 1991, 1992, 1995, 1998, 2000, 2002 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (COMPLAINTS_H)
+#define COMPLAINTS_H
+
+/* Opaque object used to track the number of complaints of a
+ particular category. */
+struct complaints;
+
+/* Predefined categories. */
+extern struct complaints *symfile_complaints;
+
+/* Register a complaint. */
+extern void complaint (struct complaints **complaints, const char *fmt,
+ ...) ATTR_FORMAT (printf, 2, 3);
+extern void internal_complaint (struct complaints **complaints,
+ const char *file, int line, const char *fmt,
+ ...) ATTR_FORMAT (printf, 4, 5);
+
+/* Clear out / initialize all complaint counters that have ever been
+ incremented. If LESS_VERBOSE is 1, be less verbose about
+ successive complaints, since the messages are appearing all
+ together during a command that is reporting a contiguous block of
+ complaints (rather than being interleaved with other messages). If
+ noisy is 1, we are in a noisy command, and our caller will print
+ enough context for the user to figure it out. */
+
+extern void clear_complaints (struct complaints **complaints,
+ int less_verbose, int noisy);
+
+
+#endif /* !defined (COMPLAINTS_H) */
diff --git a/contrib/gdb/gdb/completer.c b/contrib/gdb/gdb/completer.c
new file mode 100644
index 0000000..bcd7239
--- /dev/null
+++ b/contrib/gdb/gdb/completer.c
@@ -0,0 +1,728 @@
+/* Line completion stuff for GDB, the GNU debugger.
+ Copyright 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "filenames.h" /* for DOSish file names */
+#include "language.h"
+
+#include "cli/cli-decode.h"
+
+/* FIXME: This is needed because of lookup_cmd_1().
+ We should be calling a hook instead so we eliminate the CLI dependency. */
+#include "gdbcmd.h"
+
+/* Needed for rl_completer_word_break_characters() and for
+ rl_filename_completion_function. */
+#include "readline/readline.h"
+
+/* readline defines this. */
+#undef savestring
+
+#include "completer.h"
+
+/* Prototypes for local functions */
+static
+char *line_completion_function (const char *text, int matches, char *line_buffer,
+ int point);
+
+/* 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
+ current_language->la_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. */
+
+/* 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. */
+static char *gdb_completer_command_word_break_characters =
+" \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,";
+
+/* When completing on file names, we remove from the list of word
+ break characters any characters that are commonly used in file
+ names, such as '-', '+', '~', etc. Otherwise, readline displays
+ incorrect completion candidates. */
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+/* MS-DOS and MS-Windows use colon as part of the drive spec, and most
+ programs support @foo style response files. */
+static char *gdb_completer_file_name_break_characters = " \t\n*|\"';?><@";
+#else
+static char *gdb_completer_file_name_break_characters = " \t\n*|\"';:?><";
+#endif
+
+/* These are used when completing on locations, which can mix file
+ names and symbol names separated by a colon. */
+static char *gdb_completer_loc_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. */
+static char *gdb_completer_quote_characters = "'";
+
+/* Accessor for some completer data that may interest other files. */
+
+char *
+get_gdb_completer_quote_characters (void)
+{
+ return gdb_completer_quote_characters;
+}
+
+/* Line completion interface function for readline. */
+
+char *
+readline_line_completion_function (const char *text, int matches)
+{
+ return line_completion_function (text, matches, rl_line_buffer, rl_point);
+}
+
+/* This can be used for functions which don't want to complete on symbols
+ but don't want to complete on anything else either. */
+char **
+noop_completer (char *text, char *prefix)
+{
+ return NULL;
+}
+
+/* Complete on filenames. */
+char **
+filename_completer (char *text, char *word)
+{
+ int subsequent_name;
+ char **return_val;
+ int return_val_used;
+ int return_val_alloced;
+
+ return_val_used = 0;
+ /* Small for testing. */
+ return_val_alloced = 1;
+ return_val = (char **) xmalloc (return_val_alloced * sizeof (char *));
+
+ subsequent_name = 0;
+ while (1)
+ {
+ char *p;
+ p = rl_filename_completion_function (text, subsequent_name);
+ if (return_val_used >= return_val_alloced)
+ {
+ return_val_alloced *= 2;
+ return_val =
+ (char **) xrealloc (return_val,
+ return_val_alloced * sizeof (char *));
+ }
+ if (p == NULL)
+ {
+ return_val[return_val_used++] = p;
+ break;
+ }
+ /* We need to set subsequent_name to a non-zero value before the
+ continue line below, because otherwise, if the first file seen
+ by GDB is a backup file whose name ends in a `~', we will loop
+ indefinitely. */
+ subsequent_name = 1;
+ /* 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;
+ xfree (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;
+ xfree (p);
+ }
+ }
+ }
+#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;
+}
+
+/* Complete on locations, which might be of two possible forms:
+
+ file:line
+ or
+ symbol+offset
+
+ This is intended to be used in commands that set breakpoints etc. */
+char **
+location_completer (char *text, char *word)
+{
+ int n_syms = 0, n_files = 0;
+ char ** fn_list = NULL;
+ char ** list = NULL;
+ char *p;
+ int quote_found = 0;
+ int quoted = *text == '\'' || *text == '"';
+ int quote_char = '\0';
+ char *colon = NULL;
+ char *file_to_match = NULL;
+ char *symbol_start = text;
+ char *orig_text = text;
+ size_t text_len;
+
+ /* Do we have an unquoted colon, as in "break foo.c::bar"? */
+ for (p = text; *p != '\0'; ++p)
+ {
+ if (*p == '\\' && p[1] == '\'')
+ p++;
+ else if (*p == '\'' || *p == '"')
+ {
+ quote_found = *p;
+ quote_char = *p++;
+ while (*p != '\0' && *p != quote_found)
+ {
+ if (*p == '\\' && p[1] == quote_found)
+ p++;
+ p++;
+ }
+
+ if (*p == quote_found)
+ quote_found = 0;
+ else
+ break; /* hit the end of text */
+ }
+#if HAVE_DOS_BASED_FILE_SYSTEM
+ /* If we have a DOS-style absolute file name at the beginning of
+ TEXT, and the colon after the drive letter is the only colon
+ we found, pretend the colon is not there. */
+ else if (p < text + 3 && *p == ':' && p == text + 1 + quoted)
+ ;
+#endif
+ else if (*p == ':' && !colon)
+ {
+ colon = p;
+ symbol_start = p + 1;
+ }
+ else if (strchr (current_language->la_word_break_characters(), *p))
+ symbol_start = p + 1;
+ }
+
+ if (quoted)
+ text++;
+ text_len = strlen (text);
+
+ /* Where is the file name? */
+ if (colon)
+ {
+ char *s;
+
+ file_to_match = (char *) xmalloc (colon - text + 1);
+ strncpy (file_to_match, text, colon - text + 1);
+ /* Remove trailing colons and quotes from the file name. */
+ for (s = file_to_match + (colon - text);
+ s > file_to_match;
+ s--)
+ if (*s == ':' || *s == quote_char)
+ *s = '\0';
+ }
+ /* If the text includes a colon, they want completion only on a
+ symbol name after the colon. Otherwise, we need to complete on
+ symbols as well as on files. */
+ if (colon)
+ {
+ list = make_file_symbol_completion_list (symbol_start, word,
+ file_to_match);
+ xfree (file_to_match);
+ }
+ else
+ {
+ list = make_symbol_completion_list (symbol_start, word);
+ /* If text includes characters which cannot appear in a file
+ name, they cannot be asking for completion on files. */
+ if (strcspn (text, gdb_completer_file_name_break_characters) == text_len)
+ fn_list = make_source_files_completion_list (text, text);
+ }
+
+ /* How many completions do we have in both lists? */
+ if (fn_list)
+ for ( ; fn_list[n_files]; n_files++)
+ ;
+ if (list)
+ for ( ; list[n_syms]; n_syms++)
+ ;
+
+ /* Make list[] large enough to hold both lists, then catenate
+ fn_list[] onto the end of list[]. */
+ if (n_syms && n_files)
+ {
+ list = xrealloc (list, (n_syms + n_files + 1) * sizeof (char *));
+ memcpy (list + n_syms, fn_list, (n_files + 1) * sizeof (char *));
+ xfree (fn_list);
+ }
+ else if (n_files)
+ {
+ /* If we only have file names as possible completion, we should
+ bring them in sync with what rl_complete expects. The
+ problem is that if the user types "break /foo/b TAB", and the
+ possible completions are "/foo/bar" and "/foo/baz"
+ rl_complete expects us to return "bar" and "baz", without the
+ leading directories, as possible completions, because `word'
+ starts at the "b". But we ignore the value of `word' when we
+ call make_source_files_completion_list above (because that
+ would not DTRT when the completion results in both symbols
+ and file names), so make_source_files_completion_list returns
+ the full "/foo/bar" and "/foo/baz" strings. This produces
+ wrong results when, e.g., there's only one possible
+ completion, because rl_complete will prepend "/foo/" to each
+ candidate completion. The loop below removes that leading
+ part. */
+ for (n_files = 0; fn_list[n_files]; n_files++)
+ {
+ memmove (fn_list[n_files], fn_list[n_files] + (word - text),
+ strlen (fn_list[n_files]) + 1 - (word - text));
+ }
+ /* Return just the file-name list as the result. */
+ list = fn_list;
+ }
+ else if (!n_syms)
+ {
+ /* No completions at all. As the final resort, try completing
+ on the entire text as a symbol. */
+ list = make_symbol_completion_list (orig_text, word);
+ }
+
+ return list;
+}
+
+/* Complete on command names. Used by "help". */
+char **
+command_completer (char *text, char *word)
+{
+ return complete_on_cmdlist (cmdlist, text, word);
+}
+
+
+/* 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 all at once. Returns a NULL-terminated array
+ of strings. Both the array and each element are allocated with
+ xmalloc. It can also return NULL if there are no completions.
+
+ TEXT is the caller's idea of the "word" we are looking at.
+
+ 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. */
+
+char **
+complete_line (const char *text, char *line_buffer, int point)
+{
+ char **list = NULL;
+ char *tmp_command, *p;
+ /* Pointer within tmp_command which corresponds to text. */
+ char *word;
+ struct cmd_list_element *c, *result_list;
+
+ /* 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 =
+ current_language->la_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. */
+ if (c->completer == filename_completer)
+ {
+ /* Many commands which want to complete on
+ file names accept several file names, as
+ in "run foo bar >>baz". So we don't want
+ to complete the entire text after the
+ command, just the last word. To this
+ end, we need to find the beginning of the
+ file name by starting at `word' and going
+ backwards. */
+ for (p = word;
+ p > tmp_command
+ && strchr (gdb_completer_file_name_break_characters, p[-1]) == NULL;
+ p--)
+ ;
+ rl_completer_word_break_characters =
+ gdb_completer_file_name_break_characters;
+ }
+ else if (c->completer == location_completer)
+ {
+ /* Commands which complete on locations want to
+ see the entire argument. */
+ for (p = word;
+ p > tmp_command
+ && p[-1] != ' ' && p[-1] != '\t';
+ p--)
+ ;
+ }
+ 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. */
+ if (c->completer == filename_completer)
+ {
+ /* See the commentary above about the specifics
+ of file-name completion. */
+ for (p = word;
+ p > tmp_command
+ && strchr (gdb_completer_file_name_break_characters, p[-1]) == NULL;
+ p--)
+ ;
+ rl_completer_word_break_characters =
+ gdb_completer_file_name_break_characters;
+ }
+ else if (c->completer == location_completer)
+ {
+ for (p = word;
+ p > tmp_command
+ && p[-1] != ' ' && p[-1] != '\t';
+ p--)
+ ;
+ }
+ list = (*c->completer) (p, word);
+ }
+ }
+ }
+
+ return list;
+}
+
+/* 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 (const 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;
+
+ 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. */
+ xfree (list);
+ }
+ index = 0;
+ list = complete_line (text, line_buffer, point);
+ }
+
+ /* If we found a list of potential completions during initialization then
+ dole them out one at a time. The vector of completions is NULL
+ terminated, so after returning the last one, return NULL (and continue
+ to do so) each time we are called after that, until a new list is
+ available. */
+
+ 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 =
+ current_language->la_word_break_characters();
+#endif
+
+ return (output);
+}
+
+/* Skip over the possibly quoted word STR (as defined by the quote
+ characters QUOTECHARS and the the word break characters
+ BREAKCHARS). Returns pointer to the location after the "word". If
+ either QUOTECHARS or BREAKCHARS is NULL, use the same values used
+ by the completer. */
+
+char *
+skip_quoted_chars (char *str, char *quotechars, char *breakchars)
+{
+ char quote_char = '\0';
+ char *scan;
+
+ if (quotechars == NULL)
+ quotechars = gdb_completer_quote_characters;
+
+ if (breakchars == NULL)
+ breakchars = current_language->la_word_break_characters();
+
+ 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 (quotechars, *scan))
+ {
+ /* Found start of a quoted string. */
+ quote_char = *scan;
+ }
+ else if (strchr (breakchars, *scan))
+ {
+ break;
+ }
+ }
+
+ return (scan);
+}
+
+/* Skip over the possibly quoted word STR (as defined by the quote
+ characters and word break characters used by the completer).
+ Returns pointer to the location after the "word". */
+
+char *
+skip_quoted (char *str)
+{
+ return skip_quoted_chars (str, NULL, NULL);
+}
diff --git a/contrib/gdb/gdb/completer.h b/contrib/gdb/gdb/completer.h
new file mode 100644
index 0000000..0a8e9fa
--- /dev/null
+++ b/contrib/gdb/gdb/completer.h
@@ -0,0 +1,42 @@
+/* Header for GDB line completion.
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (COMPLETER_H)
+#define COMPLETER_H 1
+
+extern char **complete_line (const char *text, char *line_buffer, int point);
+
+extern char *readline_line_completion_function (const char *text, int matches);
+
+extern char **noop_completer (char *, char *);
+
+extern char **filename_completer (char *, char *);
+
+extern char **location_completer (char *, char *);
+
+extern char **command_completer (char *, char *);
+
+extern char *get_gdb_completer_quote_characters (void);
+
+/* Exported to linespec.c */
+
+extern char *skip_quoted_chars (char *, char *, char *);
+
+extern char *skip_quoted (char *);
+
+#endif /* defined (COMPLETER_H) */
diff --git a/contrib/gdb/gdb/config/alpha/alpha-osf2.mh b/contrib/gdb/gdb/config/alpha/alpha-osf2.mh
new file mode 100644
index 0000000..b853ebb
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/alpha-osf2.mh
@@ -0,0 +1,6 @@
+# Host: Little-endian Alpha running OSF/1-2.x using procfs
+XM_FILE= xm-alphaosf.h
+NAT_FILE= nm-osf2.h
+NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \
+ solib-osf.o solib.o procfs.o proc-api.o proc-events.o proc-flags.o \
+ proc-why.o
diff --git a/contrib/gdb/gdb/config/alpha/alpha-osf3.mh b/contrib/gdb/gdb/config/alpha/alpha-osf3.mh
new file mode 100644
index 0000000..f074444
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/alpha-osf3.mh
@@ -0,0 +1,6 @@
+# Host: Little-endian Alpha running OSF/1-3.x and higher using procfs
+XM_FILE= xm-alphaosf.h
+NAT_FILE= nm-osf3.h
+NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \
+ solib-osf.o solib.o procfs.o proc-api.o proc-events.o proc-flags.o \
+ proc-why.o
diff --git a/contrib/gdb/gdb/config/alpha/alpha.mt b/contrib/gdb/gdb/config/alpha/alpha.mt
new file mode 100644
index 0000000..dfff657
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/alpha.mt
@@ -0,0 +1,2 @@
+TDEPFILES= alpha-tdep.o
+TM_FILE= tm-alpha.h
diff --git a/contrib/gdb/gdb/config/alpha/fbsd.mh b/contrib/gdb/gdb/config/alpha/fbsd.mh
new file mode 100644
index 0000000..7e036e4
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/fbsd.mh
@@ -0,0 +1,5 @@
+# Host: FreeBSD/Alpha
+NATDEPFILES= fork-child.o infptrace.o inftarg.o \
+ solib.o solib-svr4.o solib-legacy.o \
+ corelow.o core-regset.o alphabsd-nat.o
+NAT_FILE= nm-fbsd.h
diff --git a/contrib/gdb/gdb/config/alpha/fbsd.mt b/contrib/gdb/gdb/config/alpha/fbsd.mt
new file mode 100644
index 0000000..24d2fd8
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/fbsd.mt
@@ -0,0 +1,3 @@
+# Target: FreeBSD/Alpha
+TDEPFILES= alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o alphafbsd-tdep.o
+TM_FILE= tm-fbsd.h
diff --git a/contrib/gdb/gdb/config/alpha/nbsd.mh b/contrib/gdb/gdb/config/alpha/nbsd.mh
new file mode 100644
index 0000000..52754a3
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/nbsd.mh
@@ -0,0 +1,4 @@
+# Host: Alpha running NetBSD
+NAT_CLIBS=
+NATDEPFILES= infptrace.o inftarg.o fork-child.o alphabsd-nat.o
+NAT_FILE= nm-nbsd.h
diff --git a/contrib/gdb/gdb/config/alpha/nbsd.mt b/contrib/gdb/gdb/config/alpha/nbsd.mt
new file mode 100644
index 0000000..065a28c
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/nbsd.mt
@@ -0,0 +1,4 @@
+# Target: Alpha running NetBSD
+TDEPFILES= alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o alphanbsd-tdep.o \
+ corelow.o nbsd-tdep.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/alpha/nm-fbsd.h b/contrib/gdb/gdb/config/alpha/nm-fbsd.h
new file mode 100644
index 0000000..2b3975a
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/nm-fbsd.h
@@ -0,0 +1,43 @@
+/* Native-dependent definitions for FreeBSD/Alpha.
+ Copyright 1986, 1987, 1989, 1992, 1996, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_FBSD_H
+#define NM_FBSD_H
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+/* The Alpha does not step over a breakpoint. */
+#define CANNOT_STEP_BREAKPOINT 1
+
+
+/* Shared library support. */
+
+#include "solib.h" /* Support for shared libraries. */
+#include "elf/common.h" /* Additional ELF shared library info. */
+
+#endif /* NM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/alpha/nm-nbsd.h b/contrib/gdb/gdb/config/alpha/nm-nbsd.h
new file mode 100644
index 0000000..10fab6e
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/nm-nbsd.h
@@ -0,0 +1,31 @@
+/* Native-dependent definitions for Alpha running NetBSD, for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "config/nm-nbsd.h"
+
+/* The Alpha does not step over a breakpoint. */
+#define CANNOT_STEP_BREAKPOINT 1
+
+#endif /* NM_NBSD_H */
diff --git a/contrib/gdb/gdb/config/alpha/nm-osf.h b/contrib/gdb/gdb/config/alpha/nm-osf.h
new file mode 100644
index 0000000..326bb30
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/nm-osf.h
@@ -0,0 +1,50 @@
+/* Native definitions for alpha running OSF/1.
+
+ Copyright 1993, 1994, 1995, 1998, 2000, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* 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 3
+
+/* ptrace register ``addresses'' are absolute. */
+
+#define U_REGS_OFFSET 0
+
+/* FIXME: Shouldn't the default definition in inferior.h be int* ? */
+
+#define PTRACE_ARG3_TYPE int*
+
+/* ptrace transfers longs, the ptrace man page is lying. */
+
+#define PTRACE_XFER_TYPE long
+
+/* The alpha does not step over a breakpoint, the manpage is lying again. */
+
+#define CANNOT_STEP_BREAKPOINT 1
+
+/* Support for shared libraries. */
+
+#include "solib.h"
+
+/* Given a pointer to either a gregset_t or fpregset_t, return a
+ pointer to the first register. */
+#define ALPHA_REGSET_BASE(regsetp) ((regsetp)->regs)
diff --git a/contrib/gdb/gdb/config/alpha/nm-osf2.h b/contrib/gdb/gdb/config/alpha/nm-osf2.h
new file mode 100644
index 0000000..1f3932d
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/nm-osf2.h
@@ -0,0 +1,52 @@
+/* Native definitions for alpha running OSF/1-2.x, using procfs.
+ Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 OSF/1 definitions. */
+#include "alpha/nm-osf.h"
+
+/* OSF/1-2.x has optional /proc support, try to use it instead of ptrace. */
+#define USE_PROC_FS
+#define HAVE_OPTIONAL_PROC_FS
+
+/* Don't trace faults under OSF/1, rely on the posting of the appropriate
+ signal if fault tracing is disabled.
+ Tracing T_IFAULT under Alpha OSF/1 causes a `floating point enable'
+ fault from which we cannot continue (except by disabling the
+ tracing).
+ And as OSF/1 doesn't provide the standard fault definitions, the
+ mapping of faults to appropriate signals in procfs_wait is difficult. */
+#define PROCFS_DONT_TRACE_FAULTS
+
+/* Work around some peculiarities in the OSF/1 procfs implementation. */
+#define PROCFS_SIGPEND_OFFSET
+#define PROCFS_NEED_PIOCSSIG_FOR_KILL
+#define PROCFS_DONT_PIOCSSIG_CURSIG
+
+/* Return sizeof user struct to callers in less machine dependent routines */
+
+#define KERNEL_U_SIZE kernel_u_size()
+extern int kernel_u_size (void);
+
+/* poll() doesn't seem to work properly for /proc in this version of the OS.
+ If we only specify POLLPRI, things hang. It seems to get better when we set
+ POLLOUT, but that always returns POLLNVAL!!! Also, POLLOUT causes problems
+ on other OSes. */
+
+#define LOSING_POLL
diff --git a/contrib/gdb/gdb/config/alpha/nm-osf3.h b/contrib/gdb/gdb/config/alpha/nm-osf3.h
new file mode 100644
index 0000000..e2818d5
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/nm-osf3.h
@@ -0,0 +1,27 @@
+/* Native definitions for alpha running OSF/1-3.x and higher, using procfs.
+ 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. */
+
+/* OSF/1-3.x fixes some OSF/1-2.x procfs peculiarities and adds
+ a new one. */
+#include "alpha/nm-osf2.h"
+
+#undef PROCFS_NEED_PIOCSSIG_FOR_KILL
+#undef PROCFS_DONT_PIOCSSIG_CURSIG
+#define PROCFS_NEED_CLEAR_CURSIG_FOR_KILL
diff --git a/contrib/gdb/gdb/config/alpha/tm-alpha.h b/contrib/gdb/gdb/config/alpha/tm-alpha.h
new file mode 100644
index 0000000..0b7878c
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/tm-alpha.h
@@ -0,0 +1,74 @@
+/* Definitions to make GDB run on an Alpha box under OSF1. This is
+ also used by the Alpha/Netware and Alpha GNU/Linux targets.
+
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_ALPHA_H
+#define TM_ALPHA_H
+
+#include "bfd.h"
+#include "coff/sym.h" /* Needed for PDR below. */
+#include "coff/symconst.h"
+
+struct frame_info;
+struct symbol;
+
+/* Special symbol found in blocks associated with routines. We can hang
+ alpha_extra_func_info_t's off of this. */
+
+#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__"
+extern void ecoff_relocate_efi (struct symbol *, CORE_ADDR);
+
+#define RA_REGNUM 26 /* XXXJRT needed by mdebugread.c */
+
+/* Specific information about a procedure.
+ This overlays the ALPHA's PDR records,
+ alpharead.c (ab)uses this to save memory */
+
+typedef struct alpha_extra_func_info
+ {
+ long numargs; /* number of args to procedure (was iopt) */
+ PDR pdr; /* Procedure descriptor record */
+ }
+ *alpha_extra_func_info_t;
+
+/* Define the extra_func_info that mipsread.c needs.
+ FIXME: We should define our own PDR interface, perhaps in a separate
+ header file. This would get rid of the <bfd.h> inclusion in all sources
+ and would abstract the mips/alpha interface from ecoff. */
+#define mips_extra_func_info alpha_extra_func_info
+#define mips_extra_func_info_t alpha_extra_func_info_t
+
+/* It takes two values to specify a frame on the ALPHA. Sigh.
+
+ In fact, at the moment, the *PC* is the primary value that sets up
+ a frame. The PC is looked up to see what function it's in; symbol
+ information from that function tells us which register is the frame
+ pointer base, and what offset from there is the "virtual frame pointer".
+ (This is usually an offset from SP.) FIXME -- this should be cleaned
+ up so that the primary value is the SP, and the PC is used to disambiguate
+ multiple functions with the same SP that are at different stack levels. */
+
+#define SETUP_ARBITRARY_FRAME(argc, argv) \
+ alpha_setup_arbitrary_frame (argc, argv)
+extern struct frame_info *alpha_setup_arbitrary_frame (int, CORE_ADDR *);
+
+#endif /* TM_ALPHA_H */
diff --git a/contrib/gdb/gdb/config/alpha/tm-fbsd.h b/contrib/gdb/gdb/config/alpha/tm-fbsd.h
new file mode 100644
index 0000000..c154366
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/tm-fbsd.h
@@ -0,0 +1,27 @@
+/* Target-dependent definitions for FreeBSD/Alpha.
+
+ Copyright 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_FBSD_H
+#define TM_FBSD_H
+
+#include "alpha/tm-alpha.h"
+
+#endif /* TM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/alpha/tm-nbsd.h b/contrib/gdb/gdb/config/alpha/tm-nbsd.h
new file mode 100644
index 0000000..aaad48c
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/tm-nbsd.h
@@ -0,0 +1,28 @@
+/* Target-dependent definitions for NetBSD/Alpha.
+
+ Copyright 2002, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "alpha/tm-alpha.h"
+#include "solib.h"
+
+#endif /* TM_NBSD_H */
diff --git a/contrib/gdb/gdb/config/alpha/xm-alphaosf.h b/contrib/gdb/gdb/config/alpha/xm-alphaosf.h
new file mode 100644
index 0000000..67d3cc4
--- /dev/null
+++ b/contrib/gdb/gdb/config/alpha/xm-alphaosf.h
@@ -0,0 +1,24 @@
+/* Host definitions for GDB running on an alpha under OSF/1
+ 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. */
+
+/* The alpha has no siginterrupt routine. */
+#define NO_SIGINTERRUPT
+
+#define HAVE_TERMIOS
diff --git a/contrib/gdb/gdb/config/arm/embed.mt b/contrib/gdb/gdb/config/arm/embed.mt
new file mode 100644
index 0000000..c854d17
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/embed.mt
@@ -0,0 +1,7 @@
+# Target: ARM embedded system
+TDEPFILES= arm-tdep.o remote-rdp.o remote-rdi.o
+TDEPLIBS= rdi-share/libangsd.a
+TM_FILE= tm-embed.h
+
+SIM_OBS = remote-sim.o
+SIM = ../sim/arm/libsim.a
diff --git a/contrib/gdb/gdb/config/arm/nbsd.mt b/contrib/gdb/gdb/config/arm/nbsd.mt
new file mode 100644
index 0000000..1e7d4fa
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/nbsd.mt
@@ -0,0 +1,3 @@
+# Target: ARM running NetBSD
+TDEPFILES= arm-tdep.o armnbsd-tdep.o solib.o solib-svr4.o nbsd-tdep.o
+TM_FILE=tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/arm/nbsdaout.mh b/contrib/gdb/gdb/config/arm/nbsdaout.mh
new file mode 100644
index 0000000..100e40b
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/nbsdaout.mh
@@ -0,0 +1,5 @@
+# Host ARM running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o armnbsd-nat.o \
+ solib-sunos.o
+XM_FILE=xm-nbsd.h
+NAT_FILE=nm-nbsdaout.h
diff --git a/contrib/gdb/gdb/config/arm/nbsdelf.mh b/contrib/gdb/gdb/config/arm/nbsdelf.mh
new file mode 100644
index 0000000..481d5cc
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/nbsdelf.mh
@@ -0,0 +1,4 @@
+# Host ARM running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o armnbsd-nat.o
+XM_FILE=xm-nbsd.h
+NAT_FILE=nm-nbsd.h
diff --git a/contrib/gdb/gdb/config/arm/nm-nbsd.h b/contrib/gdb/gdb/config/arm/nm-nbsd.h
new file mode 100644
index 0000000..63be920
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/nm-nbsd.h
@@ -0,0 +1,27 @@
+/* Native-dependent definitions for ARM running NetBSD, for GDB.
+ Copyright 1986, 1987, 1989, 1992, 1994, 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef NM_NBSD_H
+#define NM_NBSD_H
+
+/* Get generic NetBSD native definitions. */
+#include "config/nm-nbsd.h"
+
+#endif /* NM_NBSD_H */
diff --git a/contrib/gdb/gdb/config/arm/nm-nbsdaout.h b/contrib/gdb/gdb/config/arm/nm-nbsdaout.h
new file mode 100644
index 0000000..3f7fee9
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/nm-nbsdaout.h
@@ -0,0 +1,29 @@
+/* Native-dependent definitions for ARM running NetBSD, for GDB.
+ Copyright 1986, 1987, 1989, 1992, 1994, 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef NM_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "arm/nm-nbsd.h"
+
+/* Get generic NetBSD a.out native definitions. */
+#include "config/nm-nbsdaout.h"
+
+#endif /* NM_NBSDAOUT_H */
diff --git a/contrib/gdb/gdb/config/arm/tm-arm.h b/contrib/gdb/gdb/config/arm/tm-arm.h
new file mode 100644
index 0000000..c62a75d
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/tm-arm.h
@@ -0,0 +1,32 @@
+/* Definitions to target GDB to ARM targets.
+ Copyright 1986, 1987, 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_ARM_H
+#define TM_ARM_H
+
+#define GDB_MULTI_ARCH 1
+
+/* Specify that for the native compiler variables for a particular
+ lexical context are listed after the beginning LBRAC instead of
+ before in the executables list of symbols. */
+#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) (!(gcc_p))
+
+#endif /* TM_ARM_H */
diff --git a/contrib/gdb/gdb/config/arm/tm-embed.h b/contrib/gdb/gdb/config/arm/tm-embed.h
new file mode 100644
index 0000000..5990311
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/tm-embed.h
@@ -0,0 +1,52 @@
+/* Definitions to target GDB to ARM embedded systems.
+ Copyright 1986, 1987, 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_ARMEMBED_H
+#define TM_ARMEMBED_H
+
+/* Include the common ARM definitions. */
+#include "arm/tm-arm.h"
+
+/* The remote stub should be able to single-step. */
+#undef SOFTWARE_SINGLE_STEP_P
+#define SOFTWARE_SINGLE_STEP_P() 0
+
+/* The first 0x20 bytes are the trap vectors. */
+#undef LOWEST_PC
+#define LOWEST_PC 0x20
+
+/* Override defaults. */
+
+#undef THUMB_LE_BREAKPOINT
+#define THUMB_LE_BREAKPOINT {0xbe,0xbe}
+#undef THUMB_BE_BREAKPOINT
+#define THUMB_BE_BREAKPOINT {0xbe,0xbe}
+
+/* Functions for dealing with Thumb call thunks. */
+#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) arm_in_call_stub (pc, name)
+#define SKIP_TRAMPOLINE_CODE(pc) arm_skip_stub (pc)
+extern int arm_in_call_stub (CORE_ADDR pc, char *name);
+extern CORE_ADDR arm_skip_stub (CORE_ADDR pc);
+
+#undef IN_SIGTRAMP
+#define IN_SIGTRAMP(pc, name) 0
+
+#endif /* TM_ARMEMBED_H */
diff --git a/contrib/gdb/gdb/config/arm/tm-nbsd.h b/contrib/gdb/gdb/config/arm/tm-nbsd.h
new file mode 100644
index 0000000..97bca68
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/tm-nbsd.h
@@ -0,0 +1,26 @@
+/* Macro definitions for ARM running under NetBSD.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "solib.h"
+
+#endif /* TM_NBSD_H */
diff --git a/contrib/gdb/gdb/config/arm/tm-wince.h b/contrib/gdb/gdb/config/arm/tm-wince.h
new file mode 100644
index 0000000..82f97ad
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/tm-wince.h
@@ -0,0 +1,34 @@
+/* Definitions to target GDB for Windows CE target
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_WINCE_H
+#define TM_WINCE_H
+
+#include "arm/tm-arm.h"
+
+#undef SOFTWARE_SINGLE_STEP_P
+#define SOFTWARE_SINGLE_STEP_P() 1
+
+#undef SOFTWARE_SINGLE_STEP
+#define SOFTWARE_SINGLE_STEP(sig, bp_p) wince_software_single_step (sig, bp_p)
+
+void wince_software_single_step (unsigned int, int);
+
+#endif /* TM_WINCE_H */
diff --git a/contrib/gdb/gdb/config/arm/wince.mt b/contrib/gdb/gdb/config/arm/wince.mt
new file mode 100644
index 0000000..92a77ae
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/wince.mt
@@ -0,0 +1,5 @@
+# Target: Acorn RISC machine (ARM) with simulator
+TDEPFILES= arm-tdep.o wince.o
+TM_FILE= tm-wince.h
+MT_CFLAGS=-DARM -U_X86_ -U_M_IX86 -U__i386__ -U__i486__ -U__i586__ -U__i686__ -DUNICODE -D_WIN32_WCE -DWINCE_STUB='"${target_alias}-stub.exe"'
+TM_CLIBS=-lrapi
diff --git a/contrib/gdb/gdb/config/arm/xm-nbsd.h b/contrib/gdb/gdb/config/arm/xm-nbsd.h
new file mode 100644
index 0000000..d3f76a7
--- /dev/null
+++ b/contrib/gdb/gdb/config/arm/xm-nbsd.h
@@ -0,0 +1,22 @@
+/* Parameters for execution on an ARM 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 "config/xm-nbsd.h"
diff --git a/contrib/gdb/gdb/config/i386/embed.mt b/contrib/gdb/gdb/config/i386/embed.mt
new file mode 100644
index 0000000..6925a83
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/embed.mt
@@ -0,0 +1,3 @@
+# Target: Embedded Intel 386
+TDEPFILES= i386-tdep.o i387-tdep.o
+TM_FILE= tm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/fbsd.mh b/contrib/gdb/gdb/config/i386/fbsd.mh
new file mode 100644
index 0000000..2d0500e
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/fbsd.mh
@@ -0,0 +1,5 @@
+# Host: FreeBSD/i386
+NATDEPFILES= fork-child.o infptrace.o inftarg.o \
+ i386-nat.o i386bsd-nat.o i386fbsd-nat.o gcore.o fbsd-proc.o
+NAT_FILE= nm-fbsd.h
+XM_FILE= xm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/fbsd.mt b/contrib/gdb/gdb/config/i386/fbsd.mt
new file mode 100644
index 0000000..be095e9
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/fbsd.mt
@@ -0,0 +1,4 @@
+# Target: FreeBSD/i386
+TDEPFILES= i386-tdep.o i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-fbsd.h
diff --git a/contrib/gdb/gdb/config/i386/fbsd64.mh b/contrib/gdb/gdb/config/i386/fbsd64.mh
new file mode 100644
index 0000000..6c30e30
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/fbsd64.mh
@@ -0,0 +1,5 @@
+# Host: FreeBSD/amd64
+NATDEPFILES= fork-child.o infptrace.o inftarg.o \
+ amd64-nat.o amd64bsd-nat.o amd64fbsd-nat.o gcore.o fbsd-proc.o
+NAT_FILE= nm-fbsd64.h
+XM_FILE= xm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/fbsd64.mt b/contrib/gdb/gdb/config/i386/fbsd64.mt
new file mode 100644
index 0000000..d4cb24b
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/fbsd64.mt
@@ -0,0 +1,5 @@
+# Target: FreeBSD/amd64
+TDEPFILES= amd64-tdep.o amd64fbsd-tdep.o \
+ i386-tdep.o i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-fbsd.h
diff --git a/contrib/gdb/gdb/config/i386/go32.mh b/contrib/gdb/gdb/config/i386/go32.mh
new file mode 100644
index 0000000..0de5a9f
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/go32.mh
@@ -0,0 +1,13 @@
+# Host: Intel x86 running DJGPP
+MH_CFLAGS=
+
+XM_FILE= xm-go32.h
+
+NAT_FILE= nm-go32.h
+NATDEPFILES= go32-nat.o i386-nat.o
+
+HOST_IPC=
+CC= gcc
+XM_CLIBS= -ldbg
+
+
diff --git a/contrib/gdb/gdb/config/i386/go32.mt b/contrib/gdb/gdb/config/i386/go32.mt
new file mode 100644
index 0000000..9b82c64
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/go32.mt
@@ -0,0 +1,3 @@
+# Target: Intel 386 running DJGPP
+TDEPFILES= i386-tdep.o i387-tdep.o
+TM_FILE= tm-go32.h
diff --git a/contrib/gdb/gdb/config/i386/i386aout.mt b/contrib/gdb/gdb/config/i386/i386aout.mt
new file mode 100644
index 0000000..2a33369
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386aout.mt
@@ -0,0 +1,3 @@
+# Target: Intel 386 with a.out
+TDEPFILES= i386-tdep.o i387-tdep.o
+TM_FILE= tm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/i386gnu.mh b/contrib/gdb/gdb/config/i386/i386gnu.mh
new file mode 100644
index 0000000..c2eb7af
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386gnu.mh
@@ -0,0 +1,33 @@
+# Host: Intel 386 running the GNU Hurd
+NATDEPFILES= i386gnu-nat.o gnu-nat.o corelow.o core-regset.o \
+ fork-child.o solib.o solib-svr4.o solib-legacy.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-i386.h
+NAT_FILE= nm-i386gnu.h
+MH_CFLAGS = -D_GNU_SOURCE
+
+XM_CLIBS = -lshouldbeinlibc
+
+# 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
+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
diff --git a/contrib/gdb/gdb/config/i386/i386gnu.mt b/contrib/gdb/gdb/config/i386/i386gnu.mt
new file mode 100644
index 0000000..2029e99
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386gnu.mt
@@ -0,0 +1,3 @@
+# Target: Intel 386 running the GNU Hurd
+TDEPFILES= i386-tdep.o i387-tdep.o i386gnu-tdep.o
+TM_FILE= tm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/i386lynx.mh b/contrib/gdb/gdb/config/i386/i386lynx.mh
new file mode 100644
index 0000000..edfb1b0
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386lynx.mh
@@ -0,0 +1,6 @@
+# Host: Intel 386 running LynxOS
+
+XM_CLIBS= -lbsd
+
+NAT_FILE= nm-i386lynx.h
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o lynx-nat.o
diff --git a/contrib/gdb/gdb/config/i386/i386lynx.mt b/contrib/gdb/gdb/config/i386/i386lynx.mt
new file mode 100644
index 0000000..6704b43
--- /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/i386nw.mt b/contrib/gdb/gdb/config/i386/i386nw.mt
new file mode 100644
index 0000000..9eafe7d
--- /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-i386.h
diff --git a/contrib/gdb/gdb/config/i386/i386sco.mh b/contrib/gdb/gdb/config/i386/i386sco.mh
new file mode 100644
index 0000000..d039944
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386sco.mh
@@ -0,0 +1,12 @@
+# Host: Intel 386 running SCO Unix (pre-SVR4)
+
+XM_FILE= xm-i386sco.h
+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 0000000..2507e07
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386sco4.mh
@@ -0,0 +1,11 @@
+# Host: Intel 386 running SCO Unix 3.2v4
+
+XM_FILE= xm-i386sco.h
+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 0000000..7b8b827
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386sco5.mh
@@ -0,0 +1,16 @@
+# 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.
+#
+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 solib-svr4.o solib-legacy.o
+
diff --git a/contrib/gdb/gdb/config/i386/i386sol2.mh b/contrib/gdb/gdb/config/i386/i386sol2.mh
new file mode 100644
index 0000000..1245ca7
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386sol2.mh
@@ -0,0 +1,8 @@
+# Host: Intel 386 running Solaris 2 (SVR4)
+
+XM_FILE= xm-i386.h
+
+NAT_FILE= nm-i386sol2.h
+NATDEPFILES= fork-child.o i386v4-nat.o \
+ procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o gcore.o \
+ solib.o solib-svr4.o solib-legacy.o
diff --git a/contrib/gdb/gdb/config/i386/i386sol2.mt b/contrib/gdb/gdb/config/i386/i386sol2.mt
new file mode 100644
index 0000000..863f615
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386sol2.mt
@@ -0,0 +1,3 @@
+# Target: Intel 386 running Solaris 2 (SVR4)
+TDEPFILES= i386-tdep.o i387-tdep.o i386-sol2-tdep.o corelow.o
+TM_FILE= tm-i386sol2.h
diff --git a/contrib/gdb/gdb/config/i386/i386v.mh b/contrib/gdb/gdb/config/i386/i386v.mh
new file mode 100644
index 0000000..7f0ea6e
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386v.mh
@@ -0,0 +1,7 @@
+# Host: Intel 386 running System V
+
+XM_FILE= xm-i386v.h
+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 0000000..1ee5305
--- /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-i386.h
diff --git a/contrib/gdb/gdb/config/i386/i386v4.mh b/contrib/gdb/gdb/config/i386/i386v4.mh
new file mode 100644
index 0000000..a3952bc
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386v4.mh
@@ -0,0 +1,10 @@
+# Host: Intel 386 running SVR4
+
+XM_FILE= xm-i386v4.h
+# for network communication
+XM_CLIBS= -lsocket -lnsl
+
+NAT_FILE= nm-i386v4.h
+NATDEPFILES= corelow.o core-regset.o fork-child.o i386v4-nat.o \
+ solib.o solib-svr4.o solib-legacy.o \
+ procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
diff --git a/contrib/gdb/gdb/config/i386/i386v42mp.mh b/contrib/gdb/gdb/config/i386/i386v42mp.mh
new file mode 100644
index 0000000..4aac5d9
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/i386v42mp.mh
@@ -0,0 +1,20 @@
+# Host: Intel 386 running SVR4
+
+XM_FILE= xm-i386v4.h
+# for network communication
+XM_CLIBS= -lsocket -lnsl
+
+# we don't want nm-i386v4.h since that defines LOSING_POLL which isn't
+# appropriate for i386v42mp
+NAT_FILE= nm-i386v42mp.h
+
+# NATDEPFILES must remain entirely on one line. When building a cross
+# debugger, configure will cause this line to be commented out in the
+# Makefile. Many non-GNU versions of make don't permit the use of a
+# continuation character (backslash) to extend a commented line. As a
+# consequence, make considers subsequent tab-indented lines to be
+# some sort of error.
+NATDEPFILES= corelow.o core-regset.o fork-child.o i386v4-nat.o \
+ gcore.o solib.o solib-svr4.o solib-legacy.o procfs.o proc-api.o \
+ proc-events.o proc-flags.o proc-why.o uw-thread.o
+
diff --git a/contrib/gdb/gdb/config/i386/nbsd.mt b/contrib/gdb/gdb/config/i386/nbsd.mt
new file mode 100644
index 0000000..d6699b5
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nbsd.mt
@@ -0,0 +1,4 @@
+# Target: NetBSD/i386
+TDEPFILES= i386-tdep.o i387-tdep.o i386bsd-tdep.o i386nbsd-tdep.o nbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/i386/nbsd64.mh b/contrib/gdb/gdb/config/i386/nbsd64.mh
new file mode 100644
index 0000000..e10ae7a
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nbsd64.mh
@@ -0,0 +1,5 @@
+# Host: NetBSD/amd64
+NATDEPFILES= fork-child.o infptrace.o inftarg.o \
+ amd64-nat.o amd64bsd-nat.o amd64nbsd-nat.o
+NAT_FILE= nm-nbsd.h
+XM_FILE= xm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/nbsd64.mt b/contrib/gdb/gdb/config/i386/nbsd64.mt
new file mode 100644
index 0000000..3c98211
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nbsd64.mt
@@ -0,0 +1,4 @@
+# Target: NetBSD/amd64
+TDEPFILES= amd64-tdep.o amd64nbsd-tdep.o i386-tdep.o i387-tdep.o nbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/i386/nbsdaout.mh b/contrib/gdb/gdb/config/i386/nbsdaout.mh
new file mode 100644
index 0000000..98e69c4
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nbsdaout.mh
@@ -0,0 +1,5 @@
+# Host: NetBSD/i386 a.out
+NATDEPFILES= fork-child.o infptrace.o inftarg.o i386bsd-nat.o \
+ solib.o solib-sunos.o
+NAT_FILE= nm-nbsdaout.h
+XM_FILE= xm-nbsd.h
diff --git a/contrib/gdb/gdb/config/i386/nbsdelf.mh b/contrib/gdb/gdb/config/i386/nbsdelf.mh
new file mode 100644
index 0000000..0d313dd
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nbsdelf.mh
@@ -0,0 +1,4 @@
+# Host: NetBSD/i386 ELF
+NATDEPFILES= fork-child.o infptrace.o inftarg.o i386bsd-nat.o
+NAT_FILE= nm-nbsd.h
+XM_FILE= xm-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 0000000..4e669ba
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/ncr3000.mh
@@ -0,0 +1,16 @@
+# 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
+
+NAT_FILE= nm-i386v4.h
+NATDEPFILES= corelow.o core-regset.o fork-child.o i386v4-nat.o procfs.o \
+ proc-api.o proc-events.o proc-flags.o proc-why.o
diff --git a/contrib/gdb/gdb/config/i386/ncr3000.mt b/contrib/gdb/gdb/config/i386/ncr3000.mt
new file mode 100644
index 0000000..4773dae
--- /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 solib-svr4.o solib-legacy.o
+TM_FILE= tm-i386.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 0000000..314e3a0
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-fbsd.h
@@ -0,0 +1,148 @@
+/* Native-dependent definitions for FreeBSD/i386.
+
+ Copyright 1986, 1987, 1989, 1992, 1994, 1996, 1997, 2000, 2001, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_FBSD_H
+#define NM_FBSD_H
+
+#ifdef HAVE_PT_GETDBREGS
+#define I386_USE_GENERIC_WATCHPOINTS
+#endif
+
+#include "i386/nm-i386.h"
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+/* Provide access to the i386 hardware debugging registers. */
+
+#define I386_DR_LOW_SET_CONTROL(control) \
+ i386bsd_dr_set_control (control)
+extern void i386bsd_dr_set_control (unsigned long control);
+
+#define I386_DR_LOW_SET_ADDR(regnum, addr) \
+ i386bsd_dr_set_addr (regnum, addr)
+extern void i386bsd_dr_set_addr (int regnum, CORE_ADDR addr);
+
+#define I386_DR_LOW_RESET_ADDR(regnum) \
+ i386bsd_dr_reset_addr (regnum)
+extern void i386bsd_dr_reset_addr (int regnum);
+
+#define I386_DR_LOW_GET_STATUS() \
+ i386bsd_dr_get_status ()
+extern unsigned long i386bsd_dr_get_status (void);
+
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* Override child_resume in `infptrace.c' to work around a kernel bug. */
+#define CHILD_RESUME
+
+/* Override child_pid_to_exec_file in 'inftarg.c'. */
+#define CHILD_PID_TO_EXEC_FILE
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+
+/* Support for the user struct. */
+
+/* Return the size of the user struct. */
+
+#define KERNEL_U_SIZE kernel_u_size ()
+extern int kernel_u_size (void);
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#include <machine/vmparam.h>
+#define KERNEL_U_ADDR USRSTACK
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+ (addr) = register_u_addr ((blockend), (regno))
+extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regno);
+
+
+/* Shared library support. */
+
+#include "solib.h"
+
+/* Make structure definitions match up with those expected in
+ `solib-sunos.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
+
+#endif /* nm-fbsd.h */
diff --git a/contrib/gdb/gdb/config/i386/nm-fbsd64.h b/contrib/gdb/gdb/config/i386/nm-fbsd64.h
new file mode 100644
index 0000000..4c27aff
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-fbsd64.h
@@ -0,0 +1,37 @@
+/* Native-dependent definitions for FreeBSD/amd64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_FBSD64_H
+#define NM_FBSD64_H
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* Override child_pid_to_exec_file in 'inftarg.c'. */
+#define CHILD_PID_TO_EXEC_FILE
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+#endif /* nm-fbsd64.h */
diff --git a/contrib/gdb/gdb/config/i386/nm-go32.h b/contrib/gdb/gdb/config/i386/nm-go32.h
new file mode 100644
index 0000000..5947b74
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-go32.h
@@ -0,0 +1,36 @@
+/* Native definitions for Intel x86 running DJGPP.
+ Copyright 1997, 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 I386_USE_GENERIC_WATCHPOINTS
+
+#include "i386/nm-i386.h"
+
+/* Support for hardware-assisted breakpoints and watchpoints. */
+
+#define I386_DR_LOW_SET_CONTROL(VAL) go32_set_dr7 (VAL)
+extern void go32_set_dr7 (unsigned);
+
+#define I386_DR_LOW_SET_ADDR(N,ADDR) go32_set_dr (N,ADDR)
+extern void go32_set_dr (int, CORE_ADDR);
+
+#define I386_DR_LOW_RESET_ADDR(N)
+
+#define I386_DR_LOW_GET_STATUS() go32_get_dr6 ()
+extern unsigned go32_get_dr6 (void);
diff --git a/contrib/gdb/gdb/config/i386/nm-i386.h b/contrib/gdb/gdb/config/i386/nm-i386.h
new file mode 100644
index 0000000..88eacc8
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386.h
@@ -0,0 +1,122 @@
+/* Native macro definitions for GDB on an Intel i[3456]86.
+ Copyright 2001, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_I386_H
+#define NM_I386_H 1
+
+/* Hardware-assisted breakpoints and watchpoints. */
+
+/* Targets should define this to use the generic x86 watchpoint support. */
+#ifdef I386_USE_GENERIC_WATCHPOINTS
+
+#ifndef TARGET_HAS_HARDWARE_WATCHPOINTS
+#define TARGET_HAS_HARDWARE_WATCHPOINTS
+#endif
+
+/* Clear the reference counts and forget everything we knew about DRi. */
+extern void i386_cleanup_dregs (void);
+
+/* Insert a watchpoint to watch a memory region which starts at
+ address ADDR and whose length is LEN bytes. Watch memory accesses
+ of the type TYPE. Return 0 on success, -1 on failure. */
+extern int i386_insert_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* Remove a watchpoint that watched the memory region which starts at
+ address ADDR, whose length is LEN bytes, and for accesses of the
+ type TYPE. Return 0 on success, -1 on failure. */
+extern int i386_remove_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* Return non-zero if we can watch a memory region that starts at
+ address ADDR and whose length is LEN bytes. */
+extern int i386_region_ok_for_watchpoint (CORE_ADDR addr, int len);
+
+/* Return non-zero if the inferior has some break/watchpoint that
+ triggered. */
+extern int i386_stopped_by_hwbp (void);
+
+/* If the inferior has some break/watchpoint that triggered, return
+ the address associated with that break/watchpoint. Otherwise,
+ return zero. */
+extern CORE_ADDR i386_stopped_data_address (void);
+
+/* Insert a hardware-assisted breakpoint at address ADDR. SHADOW is
+ unused. Return 0 on success, EBUSY on failure. */
+extern int i386_insert_hw_breakpoint (CORE_ADDR addr, void *shadow);
+
+/* Remove a hardware-assisted breakpoint at address ADDR. SHADOW is
+ unused. Return 0 on success, -1 on failure. */
+extern int i386_remove_hw_breakpoint (CORE_ADDR addr, void *shadow);
+
+/* Returns the number of hardware watchpoints of type TYPE that we can
+ set. Value is positive if we can set CNT watchpoints, zero if
+ setting watchpoints of type TYPE is not supported, and negative if
+ CNT is more than the maximum number of watchpoints of type TYPE
+ that we can support. 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 non-zero if other types of watchpoints are
+ currently enabled.
+
+ We always return 1 here because we don't have enough information
+ about possible overlap of addresses that they want to watch. As an
+ extreme example, consider the case where all the watchpoints watch
+ the same address and the same region length: then we can handle a
+ virtually unlimited number of watchpoints, due to debug register
+ sharing implemented via reference counts in i386-nat.c. */
+
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
+
+/* Returns non-zero if we can use hardware watchpoints to watch a
+ region whose address is ADDR and whose length is LEN. */
+
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr, len) \
+ i386_region_ok_for_watchpoint (addr, len)
+
+/* 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 1
+
+#define STOPPED_BY_WATCHPOINT(W) (i386_stopped_data_address () != 0)
+
+#define target_stopped_data_address() i386_stopped_data_address ()
+
+/* Use these macros for watchpoint insertion/removal. */
+
+#define target_insert_watchpoint(addr, len, type) \
+ i386_insert_watchpoint (addr, len, type)
+
+#define target_remove_watchpoint(addr, len, type) \
+ i386_remove_watchpoint (addr, len, type)
+
+#define target_insert_hw_breakpoint(addr, shadow) \
+ i386_insert_hw_breakpoint (addr, shadow)
+
+#define target_remove_hw_breakpoint(addr, shadow) \
+ i386_remove_hw_breakpoint (addr, shadow)
+
+/* child_post_startup_inferior used to
+ reset all debug registers by calling i386_cleanup_dregs (). */
+#define CHILD_POST_STARTUP_INFERIOR
+
+#endif /* I386_USE_GENERIC_WATCHPOINTS */
+
+#endif /* NM_I386_H */
diff --git a/contrib/gdb/gdb/config/i386/nm-i386gnu.h b/contrib/gdb/gdb/config/i386/nm-i386gnu.h
new file mode 100644
index 0000000..4fef763
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386gnu.h
@@ -0,0 +1,38 @@
+/* Native-dependent definitions for Intel 386 running the GNU Hurd
+ Copyright 1994, 1995, 1996, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_I386GNU_H
+#define NM_I386GNU_H
+
+/* Include common definitions for GNU systems. */
+#include "config/nm-gnu.h"
+
+/* Thread flavors used in re-setting the T bit. */
+#define THREAD_STATE_FLAVOR i386_REGS_SEGS_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 attach and detach. */
+#define ATTACH_DETACH 1
+
+#endif /* nm-i386gnu.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 0000000..bc6a234
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386lynx.h
@@ -0,0 +1,26 @@
+/* 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 "config/nm-lynx.h"
+
+#endif /* NM_I386LYNX_H */
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 0000000..ec7a3bd
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386sco.h
@@ -0,0 +1,33 @@
+/* Native support for i386.
+ Copyright 1986, 1987, 1989, 1992, 1994, 1998, 2000
+ 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. */
+
+#ifndef NM_I386SCO_H
+#define NM_I386SCO_H
+
+#include "i386/nm-i386v.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)
+
+#endif /* nm-i386sco.h */
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 0000000..6947f3f
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386sco4.h
@@ -0,0 +1,33 @@
+/* Native support for SCO 3.2v4.
+ Copyright 1993 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. By Ian Lance Taylor
+ <ian@cygnus.com> based on work by Martin Walker <maw@netcom.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. */
+
+/* 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 <sys/ptrace.h>. 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 0000000..65f3176
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386sco5.h
@@ -0,0 +1,78 @@
+/* Native support for SCO OpenServer 5.
+ Copyright 1996, 1998, 2002 Free Software Foundation, Inc.
+ Re-written by J. Kean Johnston <jkj@sco.com>.
+ Originally written by Robert Lipe <robertl@dgii.com>, based on
+ work by Ian Lance Taylor <ian@cygnus.com> and
+ Martin Walker <maw@netcom.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 NM_I386SCO5_H
+#define NM_I386SCO5_H
+
+/* Basically, its a lot like the older versions ... */
+#include "i386/nm-i386sco.h"
+
+/* ... but it can do a lot of SVR4 type stuff too. */
+#define SVR4_SHARED_LIBS
+#include "solib.h" /* Pick up shared library support. */
+
+/* SCO is unlike other SVR4 systems in that it has SVR4 style shared
+ libs, with a slight twist. We expect 3 traps (2 for the exec and
+ one for the dynamic loader). After the third trap we insert the
+ shared library breakpoints, then wait for the 4th trap. */
+
+#undef START_INFERIOR_TRAPS_EXPECTED
+#define START_INFERIOR_TRAPS_EXPECTED 3
+
+/* SCO does not provide <sys/ptrace.h>. However, infptrace.c does not
+ have defaults for these values. */
+
+#define PTRACE_ATTACH 10
+#define PTRACE_DETACH 11
+
+/* Return the size of the user struct. */
+
+#define KERNEL_U_SIZE kernel_u_size ()
+extern int kernel_u_size (void);
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+/* Hardware-assisted breakpoints and watchpoints. */
+
+/* We can also do hardware watchpoints. */
+#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 which
+ caused the trap. But we can continue over it without disabling the
+ trap. */
+#define HAVE_CONTINUABLE_WATCHPOINT 1
+#define HAVE_STEPPABLE_WATCHPOINT
+
+#define STOPPED_BY_WATCHPOINT(W) \
+ i386_stopped_by_watchpoint (PIDGET (inferior_ptid))
+
+#define target_insert_watchpoint(addr, len, type) \
+ i386_insert_watchpoint (PIDGET (inferior_ptid), addr, len, type)
+
+#define target_remove_watchpoint(addr, len, type) \
+ i386_remove_watchpoint (PIDGET (inferior_ptid), addr, len)
+
+#endif /* nm-i386sco5.h */
diff --git a/contrib/gdb/gdb/config/i386/nm-i386sol2.h b/contrib/gdb/gdb/config/i386/nm-i386sol2.h
new file mode 100644
index 0000000..18afa04
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386sol2.h
@@ -0,0 +1,61 @@
+/* Native support for i386 running Solaris 2.
+ Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "config/nm-sysv4.h"
+
+#ifdef NEW_PROC_API /* Solaris 6 and above can do HW watchpoints */
+
+#define TARGET_HAS_HARDWARE_WATCHPOINTS
+
+/* The man page for proc4 on solaris 6 and 7 says that the system
+ can support "thousands" of hardware watchpoints, but gives no
+ method for finding out how many. So just tell GDB 'yes'. */
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(TYPE, CNT, OT) 1
+#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(SIZE) 1
+
+/* When a hardware watchpoint fires off the PC will be left at the
+ instruction following the one which caused the watchpoint.
+ It will *NOT* be necessary for GDB to step over the watchpoint. */
+#define HAVE_CONTINUABLE_WATCHPOINT 1
+
+/* Solaris x86 2.6 and 2.7 targets have a kernel bug when stepping
+ over an instruction that causes a page fault without triggering
+ a hardware watchpoint. The kernel properly notices that it shouldn't
+ stop, because the hardware watchpoint is not triggered, but it forgets
+ the step request and continues the program normally.
+ Work around the problem by removing hardware watchpoints if a step is
+ requested, GDB will check for a hardware watchpoint trigger after the
+ step anyway. */
+#define CANNOT_STEP_HW_WATCHPOINTS
+
+extern int procfs_stopped_by_watchpoint (ptid_t);
+#define STOPPED_BY_WATCHPOINT(W) \
+ procfs_stopped_by_watchpoint(inferior_ptid)
+
+/* Use these macros for watchpoint insertion/deletion. */
+/* type can be 0: write watch, 1: read watch, 2: access watch (read/write) */
+
+extern int procfs_set_watchpoint (ptid_t, CORE_ADDR, int, int, int);
+#define target_insert_watchpoint(ADDR, LEN, TYPE) \
+ procfs_set_watchpoint (inferior_ptid, ADDR, LEN, TYPE, 1)
+#define target_remove_watchpoint(ADDR, LEN, TYPE) \
+ procfs_set_watchpoint (inferior_ptid, ADDR, 0, 0, 0)
+
+#endif /* NEW_PROC_API */
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 0000000..f94c5bb
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386v.h
@@ -0,0 +1,44 @@
+/* Native support for i386 running System V (pre-SVR4).
+
+ Copyright 1986, 1987, 1989, 1992, 1993, 1998, 2000, 2002
+ 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. */
+
+#ifndef NM_I386V_H
+#define NM_I386V_H
+
+/* Support for the user struct. */
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#define REGISTER_U_ADDR(addr, blockend, regnum) \
+ (addr) = register_u_addr ((blockend), (regnum))
+extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regnum);
+
+
+/* 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
+
+#endif /* nm-i386v.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 0000000..356d3cb
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386v4.h
@@ -0,0 +1,26 @@
+/* Native support for i386 running SVR4.
+ Copyright 1986, 1987, 1989, 1992, 1993, 1996
+ 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 "config/nm-sysv4.h"
+
+/* Poll causes GDB to hang, at least under Unixware 1.1.2. */
+#define LOSING_POLL
diff --git a/contrib/gdb/gdb/config/i386/nm-i386v42mp.h b/contrib/gdb/gdb/config/i386/nm-i386v42mp.h
new file mode 100644
index 0000000..f6fced5
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-i386v42mp.h
@@ -0,0 +1,92 @@
+/* Native support for i386 running SVR4.
+ Copyright 1986, 1987, 1989, 1992, 1996, 1997, 1998
+ 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. */
+
+#ifndef NM_I386V42MP_H
+#define NM_I386V42MP_H
+
+#include "config/nm-sysv4.h"
+
+/* define to select for other sysv4.2mp weirdness (see procfs.c) */
+
+#define UNIXWARE
+
+#if 0
+/* The following macros extract process and lwp/thread ids from a
+ composite id.
+
+ For consistency with UnixWare core files, allocate bits 0-15 for
+ process ids and bits 16 and up for lwp ids. Reserve bit 31 for
+ negative return values to indicate exceptions, and use bit 30 as a
+ flag to indicate a user-mode thread, leaving 14 bits for lwp
+ ids. */
+
+/* Number of bits in composite id allocated to process number. */
+#define PIDBITS 16
+
+/* Return the process id stored in composite PID. */
+#define PIDGET(PID) (((PID) & ((1 << PIDBITS) - 1)))
+
+/* Return the thread or lwp id stored in composite PID. */
+#define TIDGET(PID) (((PID) & 0x3fffffff) >> PIDBITS)
+#define LIDGET(PID) TIDGET(PID)
+
+/* Construct a composite id from lwp LID and the process portion of
+ composite PID. */
+#define MERGEPID(PID, LID) (PIDGET(PID) | ((LID) << PIDBITS))
+#define MKLID(PID, LID) MERGEPID(PID, LID)
+
+/* Construct a composite id from thread TID and the process portion of
+ composite PID. */
+#define MKTID(PID, TID) (MERGEPID(PID, TID) | 0x40000000)
+
+/* Return whether PID contains a user-space thread id. */
+#define ISTID(PID) ((PID) & 0x40000000)
+#endif
+
+/* New definitions of the ptid stuff. Due to the way the
+ code is structured in uw-thread.c, I'm overloading the thread id
+ and lwp id onto the lwp field. The tid field is used to indicate
+ whether the lwp is a tid or not.
+
+ FIXME: Check that core file support is not broken. (See original
+ #if 0'd comments above.)
+ FIXME: Restructure uw-thread.c so that the struct ptid fields
+ can be used as intended. */
+
+/* Return the process id stored in composite PID. */
+#define PIDGET(PID) (ptid_get_pid (PID))
+
+/* Return the thread or lwp id stored in composite PID. */
+#define TIDGET(PID) (ptid_get_lwp (PID))
+#define LIDGET(PID) TIDGET(PID)
+
+#define MERGEPID(PID, LID) (ptid_build ((PID), (LID), 0))
+#define MKLID(PID, LID) (ptid_build ((PID), (LID), 0))
+
+/* Construct a composite id from thread TID and the process portion of
+ composite PID. */
+#define MKTID(PID, TID) (ptid_build ((PID), (TID), 1))
+
+/* Return whether PID contains a user-space thread id. */
+#define ISTID(PID) (ptid_get_tid (PID))
+
+#endif /* NM_I386V42MP_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 0000000..fef50f3
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-nbsd.h
@@ -0,0 +1,29 @@
+/* Native-dependent definitions for NetBSD/i386.
+
+ Copyright 1986, 1987, 1989, 1992, 1994, 2000, 2002, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "config/nm-nbsd.h"
+
+#endif /* nm-nbsd.h */
diff --git a/contrib/gdb/gdb/config/i386/nm-nbsdaout.h b/contrib/gdb/gdb/config/i386/nm-nbsdaout.h
new file mode 100644
index 0000000..375a6a0
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-nbsdaout.h
@@ -0,0 +1,31 @@
+/* Native-dependent definitions for NetBSD/i386 a.out.
+
+ Copyright 1986, 1987, 1989, 1992, 1994, 1996, 2000, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "i386/nm-nbsd.h"
+
+/* Get generic NetBSD a.out native definitions. */
+#include "config/nm-nbsdaout.h"
+
+#endif /* nm-nbsdaout.h */
diff --git a/contrib/gdb/gdb/config/i386/nm-nto.h b/contrib/gdb/gdb/config/i386/nm-nto.h
new file mode 100755
index 0000000..34d9903
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-nto.h
@@ -0,0 +1,6 @@
+#ifndef _NM_NTO_H
+#define _NM_NTO_H
+
+/* This file needed to build a native debugger. */
+
+#endif
diff --git a/contrib/gdb/gdb/config/i386/nm-obsd.h b/contrib/gdb/gdb/config/i386/nm-obsd.h
new file mode 100644
index 0000000..4d10b53
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nm-obsd.h
@@ -0,0 +1,112 @@
+/* Native-dependent definitions for OpenBSD/i386.
+
+ Copyright 2001, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_OBSD_H
+#define NM_OBSD_H
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+
+/* Support for the user struct. */
+
+/* Return the size of the user struct. */
+
+#define KERNEL_U_SIZE kernel_u_size ()
+extern int kernel_u_size (void);
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#include <machine/vmparam.h>
+#define KERNEL_U_ADDR USRSTACK
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+ (addr) = register_u_addr ((blockend), (regno))
+extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regno);
+
+
+/* Shared library support. */
+
+#include "solib.h"
+
+/* Make structure definitions match up with those expected in
+ `solib-sunos.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
+
+#endif /* nm-obsd.h */
diff --git a/contrib/gdb/gdb/config/i386/nto.mh b/contrib/gdb/gdb/config/i386/nto.mh
new file mode 100755
index 0000000..f412579
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nto.mh
@@ -0,0 +1,7 @@
+# Host: Intel 386 running QNX.
+
+NAT_FILE= nm-nto.h
+
+NATDEPFILES= nto-procfs.o
+
+XM_FILE= xm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/nto.mt b/contrib/gdb/gdb/config/i386/nto.mt
new file mode 100755
index 0000000..6655f3e
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/nto.mt
@@ -0,0 +1,4 @@
+# Target: Intel 386 running qnx6.
+TDEPFILES = i386-tdep.o i387-tdep.o corelow.o solib.o solib-svr4.o \
+ i386-nto-tdep.o nto-tdep.o remote-nto.o
+TM_FILE = tm-nto.h
diff --git a/contrib/gdb/gdb/config/i386/obsd.mh b/contrib/gdb/gdb/config/i386/obsd.mh
new file mode 100644
index 0000000..50a4fb7
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/obsd.mh
@@ -0,0 +1,4 @@
+# Host: OpenBSD/i386 ELF
+NATDEPFILES= fork-child.o infptrace.o inftarg.o i386bsd-nat.o i386obsd-nat.o
+NAT_FILE= nm-obsd.h
+XM_FILE= xm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/obsd.mt b/contrib/gdb/gdb/config/i386/obsd.mt
new file mode 100644
index 0000000..58e0fc0
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/obsd.mt
@@ -0,0 +1,4 @@
+# Target: OpenBSD/i386
+TDEPFILES= i386-tdep.o i387-tdep.o i386bsd-tdep.o i386obsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/i386/obsd64.mh b/contrib/gdb/gdb/config/i386/obsd64.mh
new file mode 100644
index 0000000..99ccfa2
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/obsd64.mh
@@ -0,0 +1,5 @@
+# Host: OpenBSD/amd64
+NATDEPFILES= fork-child.o infptrace.o inftarg.o \
+ amd64-nat.o amd64bsd-nat.o amd64obsd-nat.o
+NAT_FILE= nm-nbsd.h
+XM_FILE= xm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/obsd64.mt b/contrib/gdb/gdb/config/i386/obsd64.mt
new file mode 100644
index 0000000..16be079
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/obsd64.mt
@@ -0,0 +1,5 @@
+# Target: OpenBSD/amd64
+TDEPFILES= amd64-tdep.o amd64obsd-tdep.o \
+ i386-tdep.o i387-tdep.o i386bsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/i386/obsdaout.mh b/contrib/gdb/gdb/config/i386/obsdaout.mh
new file mode 100644
index 0000000..3577178
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/obsdaout.mh
@@ -0,0 +1,5 @@
+# Host: OpenBSD/i386 a.out
+NATDEPFILES= fork-child.o infptrace.o inftarg.o i386bsd-nat.o i386obsd-nat.o \
+ solib.o solib-sunos.o
+NAT_FILE= nm-obsd.h
+XM_FILE= xm-i386.h
diff --git a/contrib/gdb/gdb/config/i386/tm-fbsd.h b/contrib/gdb/gdb/config/i386/tm-fbsd.h
new file mode 100644
index 0000000..98a2702
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-fbsd.h
@@ -0,0 +1,31 @@
+/* Target-dependent definitions for FreeBSD/i386.
+
+ Copyright 1997, 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_FBSD_H
+#define TM_FBSD_H
+
+#include "solib.h"
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#endif /* tm-fbsd.h */
diff --git a/contrib/gdb/gdb/config/i386/tm-go32.h b/contrib/gdb/gdb/config/i386/tm-go32.h
new file mode 100644
index 0000000..85e0888
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-go32.h
@@ -0,0 +1,28 @@
+/* Target-dependent definitions for Intel x86 running DJGPP.
+ Copyright 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_GO32_H
+#define TM_GO32_H
+
+#undef HAVE_SSE_REGS /* FIXME! go32-nat.c needs to support XMMi registers */
+
+#include "i386/tm-i386.h"
+
+#endif /* TM_GO32_H */
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 0000000..e2bd81f
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-i386.h
@@ -0,0 +1,25 @@
+/* Macro definitions for GDB on an Intel i[345]86.
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_I386_H
+#define TM_I386_H 1
+
+#endif /* ifndef TM_I386_H */
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 0000000..03fe4ff
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-i386lynx.h
@@ -0,0 +1,29 @@
+/* Macro definitions for Intel 386 running under LynxOS.
+ Copyright 1993, 1995, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "config/tm-lynx.h"
+
+/* Most definitions from sysv could be used. */
+#include "i386/tm-i386.h"
+
+#endif /* TM_I386LYNX_H */
diff --git a/contrib/gdb/gdb/config/i386/tm-i386sol2.h b/contrib/gdb/gdb/config/i386/tm-i386sol2.h
new file mode 100644
index 0000000..921df26
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-i386sol2.h
@@ -0,0 +1,34 @@
+/* Macro definitions for GDB on an Intel i386 running Solaris 2.
+ Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_I386SOL2_H
+#define TM_I386SOL2_H 1
+
+#include "i386/tm-i386.h"
+
+/* The SunPRO compiler puts out 0 instead of the address in N_SO symbols,
+ and for SunPRO 3.0, N_FUN symbols too. */
+#define SOFUN_ADDRESS_MAYBE_MISSING
+
+extern char *sunpro_static_transform_name (char *);
+#define STATIC_TRANSFORM_NAME(x) sunpro_static_transform_name (x)
+#define IS_STATIC_TRANSFORM_NAME(name) ((name)[0] == '.')
+
+#endif /* ifndef TM_I386SOL2_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 0000000..8fd4158
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-nbsd.h
@@ -0,0 +1,27 @@
+/* Target-dependent definitions for NetBSD/i386.
+
+ Copyright 1994, 1996, 2000, 2002, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "solib.h"
+
+#endif /* tm-nbsd.h */
diff --git a/contrib/gdb/gdb/config/i386/tm-nto.h b/contrib/gdb/gdb/config/i386/tm-nto.h
new file mode 100755
index 0000000..ff5eb78
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-nto.h
@@ -0,0 +1,33 @@
+/* QNX Neutrino target header.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This code was donated by QNX Software Systems Ltd.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_NTO_H
+#define TM_NTO_H 1
+
+/* Pick up most of what we need from the generic i386 target include file. */
+#include "i386/tm-i386.h"
+#include "tm-nto.h"
+
+#include "solib.h"
+
+#endif /* TM_NTO_H */
diff --git a/contrib/gdb/gdb/config/i386/tm-vxworks.h b/contrib/gdb/gdb/config/i386/tm-vxworks.h
new file mode 100644
index 0000000..f9b6be4
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/tm-vxworks.h
@@ -0,0 +1,28 @@
+/* Target machine description for VxWorks on the 80[3456]86,
+ for GDB, the GNU debugger.
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef TM_VXWORKS_H
+#define TM_VXWORKS_H
+
+#include "i386/tm-i386.h"
+#include "config/tm-vxworks.h"
+
+#endif /* ifndef TM_VXWORKS_H */
diff --git a/contrib/gdb/gdb/config/i386/vxworks.mt b/contrib/gdb/gdb/config/i386/vxworks.mt
new file mode 100644
index 0000000..a14aacc
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/vxworks.mt
@@ -0,0 +1,3 @@
+# Target: i386 running VxWorks
+TDEPFILES= i386-tdep.o i387-tdep.o
+TM_FILE= tm-vxworks.h
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 0000000..dead9f6
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/xm-go32.h
@@ -0,0 +1,26 @@
+/* Host-dependent definitions for Intel x86 running DJGPP.
+ 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. */
+
+#include "i386/xm-i386.h"
+#include "fopen-bin.h"
+
+#define GDBINIT_FILENAME "gdb.ini"
+#define CRLF_SOURCE_FILES
+#define DIRNAME_SEPARATOR ';'
diff --git a/contrib/gdb/gdb/config/i386/xm-i386.h b/contrib/gdb/gdb/config/i386/xm-i386.h
new file mode 100644
index 0000000..de29b26
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/xm-i386.h
@@ -0,0 +1,31 @@
+/* Host-dependent definitions for the i386.
+
+ Copyright 2001, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_I386_H
+#define XM_I386_H
+
+#include "floatformat.h"
+
+#define HOST_FLOAT_FORMAT &floatformat_ieee_single_little
+#define HOST_DOUBLE_FORMAT &floatformat_ieee_double_little
+#define HOST_LONG_DOUBLE_FORMAT &floatformat_i387_ext
+
+#endif /* xm-i386.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 0000000..18b64bf
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/xm-i386sco.h
@@ -0,0 +1,31 @@
+/* Macro defintions for i386, running SCO Unix System V/386 3.2.
+ Copyright 1989, 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. */
+
+/* In 3.2v4 <sys/user.h> requires on <sys/dir.h>. */
+#include <sys/types.h>
+#include <sys/dir.h>
+
+#include "i386/xm-i386v.h"
+
+/* 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
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 0000000..1c32905
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/xm-i386v.h
@@ -0,0 +1,43 @@
+/* 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. */
+
+/* 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-i386v4.h b/contrib/gdb/gdb/config/i386/xm-i386v4.h
new file mode 100644
index 0000000..154986c
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/xm-i386v4.h
@@ -0,0 +1,28 @@
+/* Macro definitions for GDB on an Intel i386 running SVR4.
+ Copyright 1991, 1992, 1994, 1996 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 "config/xm-sysv4.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 0000000..703c261
--- /dev/null
+++ b/contrib/gdb/gdb/config/i386/xm-nbsd.h
@@ -0,0 +1,25 @@
+/* Host-dependent definitions for NetBSD/i386.
+
+ Copyright 1994, 2000, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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-i386.h"
+
+/* Get generic NetBSD host definitions. */
+#include "config/xm-nbsd.h"
diff --git a/contrib/gdb/gdb/config/ia64/fbsd.mh b/contrib/gdb/gdb/config/ia64/fbsd.mh
new file mode 100644
index 0000000..0dd61f2
--- /dev/null
+++ b/contrib/gdb/gdb/config/ia64/fbsd.mh
@@ -0,0 +1,3 @@
+NATDEPFILES= fbsd-proc.o fork-child.o gcore.o \
+ ia64-fbsd-nat.o infptrace.o inftarg.o
+NAT_FILE= nm-fbsd.h
diff --git a/contrib/gdb/gdb/config/ia64/fbsd.mt b/contrib/gdb/gdb/config/ia64/fbsd.mt
new file mode 100644
index 0000000..4b7c232
--- /dev/null
+++ b/contrib/gdb/gdb/config/ia64/fbsd.mt
@@ -0,0 +1,2 @@
+TDEPFILES= corelow.o ia64-fbsd-tdep.o ia64-tdep.o solib.o solib-svr4.o
+TM_FILE= tm-fbsd.h
diff --git a/contrib/gdb/gdb/config/ia64/ia64.mt b/contrib/gdb/gdb/config/ia64/ia64.mt
new file mode 100644
index 0000000..c0f85a4
--- /dev/null
+++ b/contrib/gdb/gdb/config/ia64/ia64.mt
@@ -0,0 +1,2 @@
+TDEPFILES= ia64-tdep.o
+TM_FILE= tm-ia64.h
diff --git a/contrib/gdb/gdb/config/ia64/nm-fbsd.h b/contrib/gdb/gdb/config/ia64/nm-fbsd.h
new file mode 100644
index 0000000..bdac67f
--- /dev/null
+++ b/contrib/gdb/gdb/config/ia64/nm-fbsd.h
@@ -0,0 +1,24 @@
+/* GNU GPL */
+
+#ifndef NM_FBSD_H
+#define NM_FBSD_H
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+/* Override child_pid_to_exec_file in 'inftarg.c'. */
+#define CHILD_PID_TO_EXEC_FILE
+
+#include "target.h"
+
+#define NATIVE_XFER_DIRTY ia64_fbsd_xfer_dirty
+extern LONGEST ia64_fbsd_xfer_dirty(struct target_ops *, enum target_object,
+ const char *, void *, const void *, ULONGEST, LONGEST);
+
+#endif /* NM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/ia64/tm-fbsd.h b/contrib/gdb/gdb/config/ia64/tm-fbsd.h
new file mode 100644
index 0000000..e372a33
--- /dev/null
+++ b/contrib/gdb/gdb/config/ia64/tm-fbsd.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef TM_FBSD_H
+#define TM_FBSD_H
+
+#include "solib.h"
+
+#include "ia64/tm-ia64.h"
+
+#endif /* TM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/ia64/tm-ia64.h b/contrib/gdb/gdb/config/ia64/tm-ia64.h
new file mode 100644
index 0000000..1b2baac
--- /dev/null
+++ b/contrib/gdb/gdb/config/ia64/tm-ia64.h
@@ -0,0 +1,201 @@
+/* Definitions to target GDB to GNU/Linux on an ia64 architecture.
+ Copyright 1992, 1993, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_IA64_H
+#define TM_IA64_H
+
+#define GDB_MULTI_ARCH 1
+
+/* Register numbers of various important registers */
+
+/* General registers; there are 128 of these 64 bit wide registers. The
+ first 32 are static and the last 96 are stacked. */
+#define IA64_GR0_REGNUM 0
+#define IA64_GR1_REGNUM (IA64_GR0_REGNUM+1)
+#define IA64_GR2_REGNUM (IA64_GR0_REGNUM+2)
+#define IA64_GR3_REGNUM (IA64_GR0_REGNUM+3)
+#define IA64_GR4_REGNUM (IA64_GR0_REGNUM+4)
+#define IA64_GR5_REGNUM (IA64_GR0_REGNUM+5)
+#define IA64_GR6_REGNUM (IA64_GR0_REGNUM+6)
+#define IA64_GR7_REGNUM (IA64_GR0_REGNUM+7)
+#define IA64_GR8_REGNUM (IA64_GR0_REGNUM+8)
+#define IA64_GR9_REGNUM (IA64_GR0_REGNUM+9)
+#define IA64_GR10_REGNUM (IA64_GR0_REGNUM+10)
+#define IA64_GR11_REGNUM (IA64_GR0_REGNUM+11)
+#define IA64_GR12_REGNUM (IA64_GR0_REGNUM+12)
+#define IA64_GR31_REGNUM (IA64_GR0_REGNUM+31)
+#define IA64_GR32_REGNUM (IA64_GR0_REGNUM+32)
+#define IA64_GR127_REGNUM (IA64_GR0_REGNUM+127)
+
+/* Floating point registers; 128 82-bit wide registers */
+#define IA64_FR0_REGNUM 128
+#define IA64_FR1_REGNUM (IA64_FR0_REGNUM+1)
+#define IA64_FR2_REGNUM (IA64_FR0_REGNUM+2)
+#define IA64_FR8_REGNUM (IA64_FR0_REGNUM+8)
+#define IA64_FR9_REGNUM (IA64_FR0_REGNUM+9)
+#define IA64_FR10_REGNUM (IA64_FR0_REGNUM+10)
+#define IA64_FR11_REGNUM (IA64_FR0_REGNUM+11)
+#define IA64_FR12_REGNUM (IA64_FR0_REGNUM+12)
+#define IA64_FR13_REGNUM (IA64_FR0_REGNUM+13)
+#define IA64_FR14_REGNUM (IA64_FR0_REGNUM+14)
+#define IA64_FR15_REGNUM (IA64_FR0_REGNUM+15)
+#define IA64_FR16_REGNUM (IA64_FR0_REGNUM+16)
+#define IA64_FR31_REGNUM (IA64_FR0_REGNUM+31)
+#define IA64_FR32_REGNUM (IA64_FR0_REGNUM+32)
+#define IA64_FR127_REGNUM (IA64_FR0_REGNUM+127)
+
+/* Predicate registers; There are 64 of these one bit registers.
+ It'd be more convenient (implementation-wise) to use a single
+ 64 bit word with all of these register in them. Note that there's
+ also a IA64_PR_REGNUM below which contains all the bits and is used for
+ communicating the actual values to the target. */
+
+#define IA64_PR0_REGNUM 256
+#define IA64_PR1_REGNUM (IA64_PR0_REGNUM+1)
+#define IA64_PR2_REGNUM (IA64_PR0_REGNUM+2)
+#define IA64_PR3_REGNUM (IA64_PR0_REGNUM+3)
+#define IA64_PR4_REGNUM (IA64_PR0_REGNUM+4)
+#define IA64_PR5_REGNUM (IA64_PR0_REGNUM+5)
+#define IA64_PR6_REGNUM (IA64_PR0_REGNUM+6)
+#define IA64_PR7_REGNUM (IA64_PR0_REGNUM+7)
+#define IA64_PR8_REGNUM (IA64_PR0_REGNUM+8)
+#define IA64_PR9_REGNUM (IA64_PR0_REGNUM+9)
+#define IA64_PR10_REGNUM (IA64_PR0_REGNUM+10)
+#define IA64_PR11_REGNUM (IA64_PR0_REGNUM+11)
+#define IA64_PR12_REGNUM (IA64_PR0_REGNUM+12)
+#define IA64_PR13_REGNUM (IA64_PR0_REGNUM+13)
+#define IA64_PR14_REGNUM (IA64_PR0_REGNUM+14)
+#define IA64_PR15_REGNUM (IA64_PR0_REGNUM+15)
+#define IA64_PR16_REGNUM (IA64_PR0_REGNUM+16)
+#define IA64_PR17_REGNUM (IA64_PR0_REGNUM+17)
+#define IA64_PR18_REGNUM (IA64_PR0_REGNUM+18)
+#define IA64_PR19_REGNUM (IA64_PR0_REGNUM+19)
+#define IA64_PR20_REGNUM (IA64_PR0_REGNUM+20)
+#define IA64_PR21_REGNUM (IA64_PR0_REGNUM+21)
+#define IA64_PR22_REGNUM (IA64_PR0_REGNUM+22)
+#define IA64_PR23_REGNUM (IA64_PR0_REGNUM+23)
+#define IA64_PR24_REGNUM (IA64_PR0_REGNUM+24)
+#define IA64_PR25_REGNUM (IA64_PR0_REGNUM+25)
+#define IA64_PR26_REGNUM (IA64_PR0_REGNUM+26)
+#define IA64_PR27_REGNUM (IA64_PR0_REGNUM+27)
+#define IA64_PR28_REGNUM (IA64_PR0_REGNUM+28)
+#define IA64_PR29_REGNUM (IA64_PR0_REGNUM+29)
+#define IA64_PR30_REGNUM (IA64_PR0_REGNUM+30)
+#define IA64_PR31_REGNUM (IA64_PR0_REGNUM+31)
+#define IA64_PR32_REGNUM (IA64_PR0_REGNUM+32)
+#define IA64_PR33_REGNUM (IA64_PR0_REGNUM+33)
+#define IA64_PR34_REGNUM (IA64_PR0_REGNUM+34)
+#define IA64_PR35_REGNUM (IA64_PR0_REGNUM+35)
+#define IA64_PR36_REGNUM (IA64_PR0_REGNUM+36)
+#define IA64_PR37_REGNUM (IA64_PR0_REGNUM+37)
+#define IA64_PR38_REGNUM (IA64_PR0_REGNUM+38)
+#define IA64_PR39_REGNUM (IA64_PR0_REGNUM+39)
+#define IA64_PR40_REGNUM (IA64_PR0_REGNUM+40)
+#define IA64_PR41_REGNUM (IA64_PR0_REGNUM+41)
+#define IA64_PR42_REGNUM (IA64_PR0_REGNUM+42)
+#define IA64_PR43_REGNUM (IA64_PR0_REGNUM+43)
+#define IA64_PR44_REGNUM (IA64_PR0_REGNUM+44)
+#define IA64_PR45_REGNUM (IA64_PR0_REGNUM+45)
+#define IA64_PR46_REGNUM (IA64_PR0_REGNUM+46)
+#define IA64_PR47_REGNUM (IA64_PR0_REGNUM+47)
+#define IA64_PR48_REGNUM (IA64_PR0_REGNUM+48)
+#define IA64_PR49_REGNUM (IA64_PR0_REGNUM+49)
+#define IA64_PR50_REGNUM (IA64_PR0_REGNUM+50)
+#define IA64_PR51_REGNUM (IA64_PR0_REGNUM+51)
+#define IA64_PR52_REGNUM (IA64_PR0_REGNUM+52)
+#define IA64_PR53_REGNUM (IA64_PR0_REGNUM+53)
+#define IA64_PR54_REGNUM (IA64_PR0_REGNUM+54)
+#define IA64_PR55_REGNUM (IA64_PR0_REGNUM+55)
+#define IA64_PR56_REGNUM (IA64_PR0_REGNUM+56)
+#define IA64_PR57_REGNUM (IA64_PR0_REGNUM+57)
+#define IA64_PR58_REGNUM (IA64_PR0_REGNUM+58)
+#define IA64_PR59_REGNUM (IA64_PR0_REGNUM+59)
+#define IA64_PR60_REGNUM (IA64_PR0_REGNUM+60)
+#define IA64_PR61_REGNUM (IA64_PR0_REGNUM+61)
+#define IA64_PR62_REGNUM (IA64_PR0_REGNUM+62)
+#define IA64_PR63_REGNUM (IA64_PR0_REGNUM+63)
+
+
+/* Branch registers: 8 64-bit registers for holding branch targets */
+#define IA64_BR0_REGNUM 320
+#define IA64_BR1_REGNUM (IA64_BR0_REGNUM+1)
+#define IA64_BR2_REGNUM (IA64_BR0_REGNUM+2)
+#define IA64_BR3_REGNUM (IA64_BR0_REGNUM+3)
+#define IA64_BR4_REGNUM (IA64_BR0_REGNUM+4)
+#define IA64_BR5_REGNUM (IA64_BR0_REGNUM+5)
+#define IA64_BR6_REGNUM (IA64_BR0_REGNUM+6)
+#define IA64_BR7_REGNUM (IA64_BR0_REGNUM+7)
+
+/* Virtual frame pointer; this matches IA64_FRAME_POINTER_REGNUM in
+ gcc/config/ia64/ia64.h. */
+#define IA64_VFP_REGNUM 328
+
+/* Virtual return address pointer; this matches IA64_RETURN_ADDRESS_POINTER_REGNUM
+ in gcc/config/ia64/ia64.h. */
+#define IA64_VRAP_REGNUM 329
+
+/* Predicate registers: There are 64 of these 1-bit registers. We
+ define a single register which is used to communicate these values
+ to/from the target. We will somehow contrive to make it appear that
+ IA64_PR0_REGNUM thru IA64_PR63_REGNUM hold the actual values. */
+#define IA64_PR_REGNUM 330
+
+/* Instruction pointer: 64 bits wide */
+#define IA64_IP_REGNUM 331
+
+/* Process Status Register */
+#define IA64_PSR_REGNUM 332
+
+/* Current Frame Marker (Raw form may be the cr.ifs) */
+#define IA64_CFM_REGNUM 333
+
+/* Application registers; 128 64-bit wide registers possible, but some
+ of them are reserved */
+#define IA64_AR0_REGNUM 334
+#define IA64_KR0_REGNUM (IA64_AR0_REGNUM+0)
+#define IA64_KR7_REGNUM (IA64_KR0_REGNUM+7)
+
+#define IA64_RSC_REGNUM (IA64_AR0_REGNUM+16)
+#define IA64_BSP_REGNUM (IA64_AR0_REGNUM+17)
+#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM+18)
+#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM+19)
+#define IA64_FCR_REGNUM (IA64_AR0_REGNUM+21)
+#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM+24)
+#define IA64_CSD_REGNUM (IA64_AR0_REGNUM+25)
+#define IA64_SSD_REGNUM (IA64_AR0_REGNUM+26)
+#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM+27)
+#define IA64_FSR_REGNUM (IA64_AR0_REGNUM+28)
+#define IA64_FIR_REGNUM (IA64_AR0_REGNUM+29)
+#define IA64_FDR_REGNUM (IA64_AR0_REGNUM+30)
+#define IA64_CCV_REGNUM (IA64_AR0_REGNUM+32)
+#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM+36)
+#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM+40)
+#define IA64_ITC_REGNUM (IA64_AR0_REGNUM+44)
+#define IA64_PFS_REGNUM (IA64_AR0_REGNUM+64)
+#define IA64_LC_REGNUM (IA64_AR0_REGNUM+65)
+#define IA64_EC_REGNUM (IA64_AR0_REGNUM+66)
+
+/* NAT (Not A Thing) Bits for the general registers; there are 128 of these */
+#define IA64_NAT0_REGNUM 462
+#define IA64_NAT31_REGNUM (IA64_NAT0_REGNUM+31)
+#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM+32)
+#define IA64_NAT127_REGNUM (IA64_NAT0_REGNUM+127)
+
+#endif /* TM_IA64_H */
diff --git a/contrib/gdb/gdb/config/mips/decstation.mh b/contrib/gdb/gdb/config/mips/decstation.mh
new file mode 100644
index 0000000..63de3da
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/decstation.mh
@@ -0,0 +1,4 @@
+# OBSOLETE # Host: Little-endian MIPS machine such as DECstation.
+# OBSOLETE XM_FILE= xm-mips.h
+# OBSOLETE NAT_FILE= nm-mips.h
+# OBSOLETE NATDEPFILES= infptrace.o inftarg.o corelow.o mips-nat.o fork-child.o
diff --git a/contrib/gdb/gdb/config/mips/embed.mt b/contrib/gdb/gdb/config/mips/embed.mt
new file mode 100644
index 0000000..3dad52b
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/embed.mt
@@ -0,0 +1,4 @@
+TDEPFILES= mips-tdep.o remote-mips.o
+TM_FILE= tm-mips.h
+SIM_OBS = remote-sim.o
+SIM = ../sim/mips/libsim.a
diff --git a/contrib/gdb/gdb/config/mips/littlemips.mh b/contrib/gdb/gdb/config/mips/littlemips.mh
new file mode 100644
index 0000000..30c40ad8
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/littlemips.mh
@@ -0,0 +1,3 @@
+# OBSOLETE # Host: Little-endian MIPS machine such as DECstation.
+# OBSOLETE NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o core-aout.o
+# OBSOLETE XM_FILE= xm-mips.h
diff --git a/contrib/gdb/gdb/config/mips/mipsv4.mh b/contrib/gdb/gdb/config/mips/mipsv4.mh
new file mode 100644
index 0000000..1a6104b
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/mipsv4.mh
@@ -0,0 +1,6 @@
+# Host: Mips running SVR4
+XM_FILE= xm-mipsv4.h
+NAT_FILE= ../nm-sysv4.h
+NATDEPFILES= fork-child.o mipsv4-nat.o corelow.o core-regset.o \
+ solib.o solib-svr4.o solib-legacy.o \
+ procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
diff --git a/contrib/gdb/gdb/config/mips/mipsv4.mt b/contrib/gdb/gdb/config/mips/mipsv4.mt
new file mode 100644
index 0000000..13320c2
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/mipsv4.mt
@@ -0,0 +1,3 @@
+# OBSOLETE # Target: MIPS running SVR4
+# OBSOLETE TDEPFILES= mips-tdep.o
+# OBSOLETE TM_FILE= tm-mipsv4.h
diff --git a/contrib/gdb/gdb/config/mips/nbsd.mh b/contrib/gdb/gdb/config/mips/nbsd.mh
new file mode 100644
index 0000000..4556fc6
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nbsd.mh
@@ -0,0 +1,4 @@
+# Host: MIPS running NetBSD
+NAT_CLIBS=
+NATDEPFILES= infptrace.o inftarg.o fork-child.o mipsnbsd-nat.o
+NAT_FILE= nm-nbsd.h
diff --git a/contrib/gdb/gdb/config/mips/nbsd.mt b/contrib/gdb/gdb/config/mips/nbsd.mt
new file mode 100644
index 0000000..eb5d887
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nbsd.mt
@@ -0,0 +1,7 @@
+# Target: MIPS running NetBSD
+TDEPFILES= mips-tdep.o mipsnbsd-tdep.o corelow.o solib.o solib-svr4.o \
+ nbsd-tdep.o
+TM_FILE= tm-nbsd.h
+
+SIM_OBS = remote-sim.o
+SIM = ../sim/mips/libsim.a
diff --git a/contrib/gdb/gdb/config/mips/news-mips.mh b/contrib/gdb/gdb/config/mips/news-mips.mh
new file mode 100644
index 0000000..f2c7f89
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/news-mips.mh
@@ -0,0 +1,3 @@
+# OBSOLETE # Host: Big-endian MIPS machine such as Sony News
+# OBSOLETE NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o mips-nat.o
+# OBSOLETE NAT_FILE= nm-news-mips.h
diff --git a/contrib/gdb/gdb/config/mips/nm-fbsd.h b/contrib/gdb/gdb/config/mips/nm-fbsd.h
new file mode 100644
index 0000000..a23a6d9
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nm-fbsd.h
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Native-dependent definitions for NetBSD/mips.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_FBSD_H
+#define NM_FBSD_H
+
+/* Override child_pid_to_exec_file in 'inftarg.c'. */
+#define CHILD_PID_TO_EXEC_FILE
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+/* Shared library support. */
+
+#include "solib.h"
+
+#endif /* NM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/mips/nm-mips.h b/contrib/gdb/gdb/config/mips/nm-mips.h
new file mode 100644
index 0000000..f20ddf1
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nm-mips.h
@@ -0,0 +1,34 @@
+// OBSOLETE /* Native definitions for GDB on DECstations, Sony News. and MIPS Riscos systems
+// OBSOLETE Copyright 1986, 1987, 1989, 1992, 1995, 1996, 2000
+// OBSOLETE Free Software Foundation, Inc.
+// OBSOLETE Contributed by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+// OBSOLETE and by Alessandro Forin(af@cs.cmu.edu) at CMU
+// OBSOLETE
+// OBSOLETE This file is part of GDB.
+// OBSOLETE
+// OBSOLETE This program is free software; you can redistribute it and/or modify
+// OBSOLETE it under the terms of the GNU General Public License as published by
+// OBSOLETE the Free Software Foundation; either version 2 of the License, or
+// OBSOLETE (at your option) any later version.
+// OBSOLETE
+// OBSOLETE This program is distributed in the hope that it will be useful,
+// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of
+// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// OBSOLETE GNU General Public License for more details.
+// OBSOLETE
+// OBSOLETE You should have received a copy of the GNU General Public License
+// OBSOLETE along with this program; if not, write to the Free Software
+// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330,
+// OBSOLETE Boston, MA 02111-1307, USA. */
+// OBSOLETE
+// OBSOLETE /* Override copies of {fetch,store}_inferior_registers in infptrace.c. */
+// OBSOLETE #define FETCH_INFERIOR_REGISTERS
+// OBSOLETE
+// OBSOLETE /* Figure out where the longjmp will land. We expect that we have just entered
+// OBSOLETE longjmp and haven't yet setup the stack frame, so the args are still in the
+// OBSOLETE argument regs. a0 (CALL_ARG0) points at the jmp_buf structure from which we
+// OBSOLETE extract the pc (JB_PC) that we will land at. The pc is copied into ADDR.
+// OBSOLETE This routine returns true on success */
+// OBSOLETE
+// OBSOLETE #define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
+// OBSOLETE extern int get_longjmp_target (CORE_ADDR *);
diff --git a/contrib/gdb/gdb/config/mips/nm-nbsd.h b/contrib/gdb/gdb/config/mips/nm-nbsd.h
new file mode 100644
index 0000000..67628c2
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nm-nbsd.h
@@ -0,0 +1,28 @@
+/* Native-dependent definitions for NetBSD/mips.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "config/nm-nbsd.h"
+
+#endif /* NM_NBSD_H */
diff --git a/contrib/gdb/gdb/config/mips/nm-news-mips.h b/contrib/gdb/gdb/config/mips/nm-news-mips.h
new file mode 100644
index 0000000..15d9b7b
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nm-news-mips.h
@@ -0,0 +1,43 @@
+// OBSOLETE /* Definitions to make GDB run on a mips box under 4.3bsd.
+// OBSOLETE Copyright 1986, 1987, 1989, 1993, 1996 Free Software Foundation, Inc.
+// OBSOLETE Contributed by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+// OBSOLETE and by Alessandro Forin(af@cs.cmu.edu) at CMU
+// OBSOLETE
+// OBSOLETE This file is part of GDB.
+// OBSOLETE
+// OBSOLETE This program is free software; you can redistribute it and/or modify
+// OBSOLETE it under the terms of the GNU General Public License as published by
+// OBSOLETE the Free Software Foundation; either version 2 of the License, or
+// OBSOLETE (at your option) any later version.
+// OBSOLETE
+// OBSOLETE This program is distributed in the hope that it will be useful,
+// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of
+// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// OBSOLETE GNU General Public License for more details.
+// OBSOLETE
+// OBSOLETE You should have received a copy of the GNU General Public License
+// OBSOLETE along with this program; if not, write to the Free Software
+// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330,
+// OBSOLETE Boston, MA 02111-1307, USA. */
+// OBSOLETE
+// OBSOLETE #ifndef NM_NEWS_MIPS_H
+// OBSOLETE #define NM_NEWS_MIPS_H 1
+// OBSOLETE
+// OBSOLETE /* Needed for RISC NEWS core files. */
+// OBSOLETE #include <machine/machparam.h>
+// OBSOLETE #include <sys/types.h>
+// OBSOLETE #define KERNEL_U_ADDR UADDR
+// OBSOLETE
+// OBSOLETE #define REGISTER_U_ADDR(addr, blockend, regno) \
+// OBSOLETE if (regno < 38) addr = (NBPG*UPAGES) + (regno - 38)*sizeof(int);\
+// OBSOLETE else addr = 0; /* ..somewhere in the pcb */
+// OBSOLETE
+// OBSOLETE /* Kernel is a bit tenacious about sharing text segments, disallowing bpts. */
+// OBSOLETE #define ONE_PROCESS_WRITETEXT
+// OBSOLETE
+// OBSOLETE #include "mips/nm-mips.h"
+// OBSOLETE
+// OBSOLETE /* Apparently not in <sys/types.h> */
+// OBSOLETE typedef int pid_t;
+// OBSOLETE
+// OBSOLETE #endif /* NM_NEWS_MIPS_H */
diff --git a/contrib/gdb/gdb/config/mips/nm-riscos.h b/contrib/gdb/gdb/config/mips/nm-riscos.h
new file mode 100644
index 0000000..dba51b2
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nm-riscos.h
@@ -0,0 +1,60 @@
+// OBSOLETE /* This program is free software; you can redistribute it and/or modify
+// OBSOLETE it under the terms of the GNU General Public License as published by
+// OBSOLETE the Free Software Foundation; either version 2 of the License, or
+// OBSOLETE (at your option) any later version.
+// OBSOLETE
+// OBSOLETE This program is distributed in the hope that it will be useful,
+// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of
+// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// OBSOLETE GNU General Public License for more details.
+// OBSOLETE
+// OBSOLETE You should have received a copy of the GNU General Public License
+// OBSOLETE along with this program; if not, write to the Free Software
+// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330,
+// OBSOLETE Boston, MA 02111-1307, USA. */
+// OBSOLETE
+// OBSOLETE /* MIPS running RISC/os 4.52C. */
+// OBSOLETE
+// OBSOLETE #define PCB_OFFSET(FIELD) ((int)&((struct user*)0)->u_pcb.FIELD)
+// OBSOLETE
+// OBSOLETE /* RISC/os 5.0 defines this in machparam.h. */
+// OBSOLETE #include <bsd43/machine/machparam.h>
+// OBSOLETE #define NBPG BSD43_NBPG
+// OBSOLETE #define UPAGES BSD43_UPAGES
+// OBSOLETE
+// OBSOLETE /* Where is this used? I don't see any uses in mips-nat.c, and I don't think
+// OBSOLETE the uses in infptrace.c are used if FETCH_INFERIOR_REGISTERS is defined.
+// OBSOLETE Does the compiler react badly to "extern CORE_ADDR kernel_u_addr" (even
+// OBSOLETE if never referenced)? */
+// OBSOLETE #define KERNEL_U_ADDR BSD43_UADDR
+// OBSOLETE
+// OBSOLETE #define REGISTER_U_ADDR(addr, blockend, regno) \
+// OBSOLETE if (regno < FP0_REGNUM) \
+// OBSOLETE addr = UPAGES*NBPG-EF_SIZE+4*((regno)+EF_AT-1); \
+// OBSOLETE else if (regno < PC_REGNUM) \
+// OBSOLETE addr = PCB_OFFSET(pcb_fpregs[0]) + 4*(regno-FP0_REGNUM); \
+// OBSOLETE else if (regno == PS_REGNUM) \
+// OBSOLETE addr = UPAGES*NBPG-EF_SIZE+4*EF_SR; \
+// OBSOLETE else if (regno == mips_regnum (current_gdbarch)->badvaddr) \
+// OBSOLETE addr = UPAGES*NBPG-EF_SIZE+4*EF_BADVADDR; \
+// OBSOLETE else if (regno == mips_regnum (current_gdbarch)->lo) \
+// OBSOLETE addr = UPAGES*NBPG-EF_SIZE+4*EF_MDLO; \
+// OBSOLETE else if (regno == mips_regnum (current_gdbarch)->hi) \
+// OBSOLETE addr = UPAGES*NBPG-EF_SIZE+4*EF_MDHI; \
+// OBSOLETE else if (regno == mips_regnum (current_gdbarch)->cause) \
+// OBSOLETE addr = UPAGES*NBPG-EF_SIZE+4*EF_CAUSE; \
+// OBSOLETE else if (regno == mips_regnum (current_gdbarch)->pc) \
+// OBSOLETE addr = UPAGES*NBPG-EF_SIZE+4*EF_EPC; \
+// OBSOLETE else if (regno < mips_regnum (current_gdbarch)->fp_control_status) \
+// OBSOLETE addr = PCB_OFFSET(pcb_fpregs[0]) + 4*(regno-FP0_REGNUM); \
+// OBSOLETE else if (regno == mips_regnum (current_gdbarch)->fp_control_status) \
+// OBSOLETE addr = PCB_OFFSET(pcb_fpc_csr); \
+// OBSOLETE else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) \
+// OBSOLETE addr = PCB_OFFSET(pcb_fpc_eir); \
+// OBSOLETE else \
+// OBSOLETE addr = 0;
+// OBSOLETE
+// OBSOLETE #include "mips/nm-mips.h"
+// OBSOLETE
+// OBSOLETE /* Override copies of {fetch,store}_inferior_registers in infptrace.c. */
+// OBSOLETE #define FETCH_INFERIOR_REGISTERS
diff --git a/contrib/gdb/gdb/config/mips/riscos.mh b/contrib/gdb/gdb/config/mips/riscos.mh
new file mode 100644
index 0000000..0a1c31c
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/riscos.mh
@@ -0,0 +1,16 @@
+# OBSOLETE # Host: MIPS running RISC/os
+# OBSOLETE
+# OBSOLETE XM_FILE= xm-riscos.h
+# OBSOLETE
+# OBSOLETE NAT_FILE= nm-riscos.h
+# OBSOLETE NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o mips-nat.o
+# OBSOLETE
+# OBSOLETE MH_CFLAGS=-Wf,-XNh10000
+# OBSOLETE
+# OBSOLETE # ptrace(2) apparently has problems in the BSD environment. No workaround is
+# OBSOLETE # known except to select the sysv environment. Could we use /proc instead?
+# OBSOLETE # These "sysv environments" and "bsd environments" often end up being a pain.
+# OBSOLETE #
+# OBSOLETE # This is not part of CFLAGS because perhaps not all C compilers have this
+# OBSOLETE # option.
+# OBSOLETE CC= cc -systype sysv
diff --git a/contrib/gdb/gdb/config/mips/tm-fbsd.h b/contrib/gdb/gdb/config/mips/tm-fbsd.h
new file mode 100644
index 0000000..7f69f0b
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/tm-fbsd.h
@@ -0,0 +1,43 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Target-dependent definitions for NetBSD/mips.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_FBSD_H
+#define TM_FBSD_H
+
+#include "mips/tm-mips.h"
+#include "solib.h"
+
+/* We don't want to inherit tm-mips.h's shared library trampoline code. */
+#undef IN_SOLIB_CALL_TRAMPOLINE
+#undef IN_SOLIB_RETURN_TRAMPOLINE
+#undef SKIP_TRAMPOLINE_CODE
+#undef IGNORE_HELPER_CALL
+
+/* XXX undef a bunch of stuff we want to use multi-arch */
+#undef IN_SIGTRAMP
+#endif /* TM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/mips/tm-mips.h b/contrib/gdb/gdb/config/mips/tm-mips.h
new file mode 100644
index 0000000..be0d6b7
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/tm-mips.h
@@ -0,0 +1,119 @@
+/* Definitions to make GDB run on a mips box under 4.3bsd.
+
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Per Bothner (bothner@cs.wisc.edu) at U.Wisconsin
+ and by Alessandro Forin (af@cs.cmu.edu) at CMU..
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_MIPS_H
+#define TM_MIPS_H 1
+
+#define GDB_MULTI_ARCH 1
+
+#include "regcache.h"
+
+struct frame_info;
+struct symbol;
+struct type;
+struct value;
+
+#include <bfd.h>
+#include "coff/sym.h" /* Needed for PDR below. */
+#include "coff/symconst.h"
+
+/* Return non-zero if PC points to an instruction which will cause a step
+ to execute both the instruction at PC and an instruction at PC+4. */
+extern int mips_step_skips_delay (CORE_ADDR);
+#define STEP_SKIPS_DELAY_P (1)
+#define STEP_SKIPS_DELAY(pc) (mips_step_skips_delay (pc))
+
+/* 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 ZERO_REGNUM 0 /* read-only register, always 0 */
+#define V0_REGNUM 2 /* Function integer return value */
+#define A0_REGNUM 4 /* Loc of first arg during a subr call */
+#define T9_REGNUM 25 /* Contains address of callee in PIC */
+#define SP_REGNUM 29 /* Contains address of top of stack */
+#define RA_REGNUM 31 /* Contains return address value */
+#define PS_REGNUM 32 /* Contains processor status */
+#define UNUSED_REGNUM 73 /* Never used, FIXME */
+#define FIRST_EMBED_REGNUM 74 /* First CP0 register for embedded use */
+#define PRID_REGNUM 89 /* Processor ID */
+#define LAST_EMBED_REGNUM 89 /* Last one */
+
+/* Special symbol found in blocks associated with routines. We can hang
+ mips_extra_func_info_t's off of this. */
+
+#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__"
+extern void ecoff_relocate_efi (struct symbol *, CORE_ADDR);
+
+/* Specific information about a procedure.
+ This overlays the MIPS's PDR records,
+ mipsread.c (ab)uses this to save memory */
+
+typedef struct mips_extra_func_info
+ {
+ long numargs; /* number of args to procedure (was iopt) */
+ bfd_vma high_addr; /* upper address bound */
+ long frame_adjust; /* offset of FP from SP (used on MIPS16) */
+ PDR pdr; /* Procedure descriptor record */
+ }
+ *mips_extra_func_info_t;
+
+/* It takes two values to specify a frame on the MIPS.
+
+ In fact, the *PC* is the primary value that sets up a frame. The
+ PC is looked up to see what function it's in; symbol information
+ from that function tells us which register is the frame pointer
+ base, and what offset from there is the "virtual frame pointer".
+ (This is usually an offset from SP.) On most non-MIPS machines,
+ the primary value is the SP, and the PC, if needed, disambiguates
+ multiple functions with the same SP. But on the MIPS we can't do
+ that since the PC is not stored in the same part of the frame every
+ time. This does not seem to be a very clever way to set up frames,
+ but there is nothing we can do about that. */
+
+#define SETUP_ARBITRARY_FRAME(argc, argv) setup_arbitrary_frame (argc, argv)
+extern struct frame_info *setup_arbitrary_frame (int, CORE_ADDR *);
+
+/* These are defined in mdebugread.c and are used in mips-tdep.c */
+extern CORE_ADDR sigtramp_address, sigtramp_end;
+extern void fixup_sigtramp (void);
+
+/* Functions for dealing with MIPS16 call and return stubs. */
+#define IGNORE_HELPER_CALL(pc) mips_ignore_helper (pc)
+extern int mips_ignore_helper (CORE_ADDR pc);
+
+/* Definitions and declarations used by mips-tdep.c and remote-mips.c */
+#define MIPS_INSTLEN 4 /* Length of an instruction */
+#define MIPS16_INSTLEN 2 /* Length of an instruction on MIPS16 */
+#define MIPS_NUMREGS 32 /* Number of integer or float registers */
+typedef unsigned long t_inst; /* Integer big enough to hold an instruction */
+
+#endif /* TM_MIPS_H */
+
+/* Single step based on where the current instruction will take us. */
+extern void mips_software_single_step (enum target_signal, int);
diff --git a/contrib/gdb/gdb/config/mips/tm-mipsv4.h b/contrib/gdb/gdb/config/mips/tm-mipsv4.h
new file mode 100644
index 0000000..9460741
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/tm-mipsv4.h
@@ -0,0 +1,37 @@
+// OBSOLETE /* Target machine description for MIPS running SVR4, for GDB.
+// OBSOLETE Copyright 1994, 1995, 1998, 1999, 2000 Free Software Foundation, Inc.
+// OBSOLETE
+// OBSOLETE This file is part of GDB.
+// OBSOLETE
+// OBSOLETE This program is free software; you can redistribute it and/or modify
+// OBSOLETE it under the terms of the GNU General Public License as published by
+// OBSOLETE the Free Software Foundation; either version 2 of the License, or
+// OBSOLETE (at your option) any later version.
+// OBSOLETE
+// OBSOLETE This program is distributed in the hope that it will be useful,
+// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of
+// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// OBSOLETE GNU General Public License for more details.
+// OBSOLETE
+// OBSOLETE You should have received a copy of the GNU General Public License
+// OBSOLETE along with this program; if not, write to the Free Software
+// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330,
+// OBSOLETE Boston, MA 02111-1307, USA. */
+// OBSOLETE
+// OBSOLETE #include "mips/tm-mips.h"
+// OBSOLETE #include "config/tm-sysv4.h"
+// OBSOLETE
+// OBSOLETE /* The signal handler trampoline is called _sigtramp. */
+// OBSOLETE #undef IN_SIGTRAMP
+// OBSOLETE #define IN_SIGTRAMP(pc, name) ((name) && DEPRECATED_STREQ ("_sigtramp", name))
+// OBSOLETE
+// OBSOLETE /* On entry to the signal handler trampoline, an ucontext is already
+// OBSOLETE pushed on the stack. We can get at the saved registers via the
+// OBSOLETE mcontext which is contained within the ucontext. */
+// OBSOLETE #define SIGFRAME_BASE 0
+// OBSOLETE #define SIGFRAME_REGSAVE_OFF (SIGFRAME_BASE + 40)
+// OBSOLETE #define SIGFRAME_PC_OFF (SIGFRAME_BASE + 40 + 35 * 4)
+// OBSOLETE #define SIGFRAME_FPREGSAVE_OFF (SIGFRAME_BASE + 40 + 36 * 4)
+// OBSOLETE
+// OBSOLETE /* Convert a DWARF register number to a gdb REGNUM. */
+// OBSOLETE #define DWARF_REG_TO_REGNUM(num) ((num) < 32 ? (num) : (num)+FP0_REGNUM-32)
diff --git a/contrib/gdb/gdb/config/mips/tm-nbsd.h b/contrib/gdb/gdb/config/mips/tm-nbsd.h
new file mode 100644
index 0000000..fb30761
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/tm-nbsd.h
@@ -0,0 +1,37 @@
+/* Target-dependent definitions for NetBSD/mips.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mips/tm-mips.h"
+#include "solib.h"
+
+/* We don't want to inherit tm-mips.h's shared library trampoline code. */
+#undef IN_SOLIB_CALL_TRAMPOLINE
+#undef IN_SOLIB_RETURN_TRAMPOLINE
+#undef SKIP_TRAMPOLINE_CODE
+#undef IGNORE_HELPER_CALL
+
+/* XXX undef a bunch of stuff we want to use multi-arch */
+#undef IN_SIGTRAMP
+
+#endif /* TM_NBSD_H */
diff --git a/contrib/gdb/gdb/config/mips/tm-vxmips.h b/contrib/gdb/gdb/config/mips/tm-vxmips.h
new file mode 100644
index 0000000..5eb1043
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/tm-vxmips.h
@@ -0,0 +1,23 @@
+/* Target machine description for VxWorks MIPS's, for GDB, the GNU debugger.
+ Copyright 1996, 1999 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 "mips/tm-mips.h"
+#include "config/tm-vxworks.h"
diff --git a/contrib/gdb/gdb/config/mips/tm-wince.h b/contrib/gdb/gdb/config/mips/tm-wince.h
new file mode 100644
index 0000000..3ea179b
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/tm-wince.h
@@ -0,0 +1,33 @@
+/* Definitions to make GDB run on a Windows CE system.
+
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_WINCE_H
+#define TM_WINCE_H 1
+
+#include "mips/tm-mips.h"
+
+#undef SOFTWARE_SINGLE_STEP_P
+#define SOFTWARE_SINGLE_STEP_P() 1
+#define SOFTWARE_SINGLE_STEP(sig, bp_p) wince_software_single_step (sig, bp_p)
+
+void wince_software_single_step (unsigned int, int);
+
+#endif /* TM_WINCE_H */
diff --git a/contrib/gdb/gdb/config/mips/vxmips.mt b/contrib/gdb/gdb/config/mips/vxmips.mt
new file mode 100644
index 0000000..a20cf96
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/vxmips.mt
@@ -0,0 +1,3 @@
+# Target: MIPS running VxWorks
+TDEPFILES= mips-tdep.o remote-vx.o remote-vxmips.o xdr_ld.o xdr_ptrace.o xdr_rdb.o
+TM_FILE= tm-vxmips.h
diff --git a/contrib/gdb/gdb/config/mips/wince.mt b/contrib/gdb/gdb/config/mips/wince.mt
new file mode 100644
index 0000000..6aa5733
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/wince.mt
@@ -0,0 +1,5 @@
+# Target: Little-endian MIPS machine such as DECstation.
+TDEPFILES= mips-tdep.o wince.o
+TM_FILE= tm-wince.h
+MT_CFLAGS=-DMIPS -U_X86_ -U_M_IX86 -U__i386__ -U__i486__ -U__i586__ -U__i686__ -DUNICODE -D_WIN32_WCE -DWINCE_STUB='"${target_alias}-stub.exe"'
+TM_CLIBS=-lrapi
diff --git a/contrib/gdb/gdb/config/mips/xm-mips.h b/contrib/gdb/gdb/config/mips/xm-mips.h
new file mode 100644
index 0000000..bc3aa6e
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/xm-mips.h
@@ -0,0 +1,59 @@
+// OBSOLETE /* Definitions to make GDB run on a mips box under 4.3bsd.
+// OBSOLETE Copyright 1986, 1987, 1989, 1993, 1994, 1995, 1996, 1998
+// OBSOLETE Free Software Foundation, Inc.
+// OBSOLETE Contributed by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+// OBSOLETE and by Alessandro Forin(af@cs.cmu.edu) at CMU
+// OBSOLETE
+// OBSOLETE This file is part of GDB.
+// OBSOLETE
+// OBSOLETE This program is free software; you can redistribute it and/or modify
+// OBSOLETE it under the terms of the GNU General Public License as published by
+// OBSOLETE the Free Software Foundation; either version 2 of the License, or
+// OBSOLETE (at your option) any later version.
+// OBSOLETE
+// OBSOLETE This program is distributed in the hope that it will be useful,
+// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of
+// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// OBSOLETE GNU General Public License for more details.
+// OBSOLETE
+// OBSOLETE You should have received a copy of the GNU General Public License
+// OBSOLETE along with this program; if not, write to the Free Software
+// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330,
+// OBSOLETE Boston, MA 02111-1307, USA. */
+// OBSOLETE
+// OBSOLETE #ifdef ultrix
+// OBSOLETE /* Needed for DECstation core files. */
+// OBSOLETE #include <machine/param.h>
+// OBSOLETE #define KERNEL_U_ADDR UADDR
+// OBSOLETE
+// OBSOLETE /* Native Ultrix cc has broken long long support. */
+// OBSOLETE #ifndef __GNUC__
+// OBSOLETE #undef CC_HAS_LONG_LONG
+// OBSOLETE #endif
+// OBSOLETE #endif
+// OBSOLETE
+// OBSOLETE #if ! defined (__GNUC__) && ! defined (offsetof)
+// OBSOLETE #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+// OBSOLETE #endif
+// OBSOLETE
+// OBSOLETE /* Only used for core files on DECstations.
+// OBSOLETE First four registers at u.u_ar0 are saved arguments, and
+// OBSOLETE there is no r0 saved. Float registers are saved
+// OBSOLETE in u_pcb.pcb_fpregs, not relative to u.u_ar0. */
+// OBSOLETE
+// OBSOLETE #define REGISTER_U_ADDR(addr, blockend, regno) \
+// OBSOLETE { \
+// OBSOLETE if (regno < FP0_REGNUM) \
+// OBSOLETE addr = blockend + sizeof(int) * (4 + regno - 1); \
+// OBSOLETE else \
+// OBSOLETE addr = offsetof (struct user, u_pcb.pcb_fpregs[0]) + \
+// OBSOLETE sizeof (int) * (regno - FP0_REGNUM); \
+// OBSOLETE }
+// OBSOLETE
+// OBSOLETE /* Kernel is a bit tenacious about sharing text segments, disallowing bpts. */
+// OBSOLETE #define ONE_PROCESS_WRITETEXT
+// OBSOLETE
+// OBSOLETE /* HAVE_SGTTY also works, last we tried.
+// OBSOLETE
+// OBSOLETE But we have termios, at least as of Ultrix 4.2A, so use it. */
+// OBSOLETE #define HAVE_TERMIOS
diff --git a/contrib/gdb/gdb/config/mips/xm-mipsv4.h b/contrib/gdb/gdb/config/mips/xm-mipsv4.h
new file mode 100644
index 0000000..1f39e31
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/xm-mipsv4.h
@@ -0,0 +1,22 @@
+// OBSOLETE /* Definitions for MIPS running SVR4 hosting support.
+// OBSOLETE
+// OBSOLETE Copyright 1994 Free Software Foundation, Inc.
+// OBSOLETE
+// OBSOLETE This file is part of GDB.
+// OBSOLETE
+// OBSOLETE This program is free software; you can redistribute it and/or modify
+// OBSOLETE it under the terms of the GNU General Public License as published by
+// OBSOLETE the Free Software Foundation; either version 2 of the License, or
+// OBSOLETE (at your option) any later version.
+// OBSOLETE
+// OBSOLETE This program is distributed in the hope that it will be useful,
+// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of
+// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// OBSOLETE GNU General Public License for more details.
+// OBSOLETE
+// OBSOLETE You should have received a copy of the GNU General Public License
+// OBSOLETE along with this program; if not, write to the Free Software
+// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330,
+// OBSOLETE Boston, MA 02111-1307, USA. */
+// OBSOLETE
+// OBSOLETE #include "config/xm-sysv4.h"
diff --git a/contrib/gdb/gdb/config/mips/xm-riscos.h b/contrib/gdb/gdb/config/mips/xm-riscos.h
new file mode 100644
index 0000000..d8a6533
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/xm-riscos.h
@@ -0,0 +1,25 @@
+// OBSOLETE /* Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
+// OBSOLETE
+// OBSOLETE This file is part of GDB.
+// OBSOLETE
+// OBSOLETE This program is free software; you can redistribute it and/or modify
+// OBSOLETE it under the terms of the GNU General Public License as published by
+// OBSOLETE the Free Software Foundation; either version 2 of the License, or
+// OBSOLETE (at your option) any later version.
+// OBSOLETE
+// OBSOLETE This program is distributed in the hope that it will be useful,
+// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of
+// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// OBSOLETE GNU General Public License for more details.
+// OBSOLETE
+// OBSOLETE You should have received a copy of the GNU General Public License
+// OBSOLETE along with this program; if not, write to the Free Software
+// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330,
+// OBSOLETE Boston, MA 02111-1307, USA. */
+// OBSOLETE
+// OBSOLETE #define HAVE_TERMIO
+// OBSOLETE
+// OBSOLETE #define USG 1
+// OBSOLETE
+// OBSOLETE /* setjmp.h requires uid_t. */
+// OBSOLETE #include <sys/types.h>
diff --git a/contrib/gdb/gdb/config/nm-gnu.h b/contrib/gdb/gdb/config/nm-gnu.h
new file mode 100644
index 0000000..73a4180
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-gnu.h
@@ -0,0 +1,43 @@
+/* Common declarations for the GNU Hurd
+
+ Copyright 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef __NM_GNU_H__
+#define __NM_GNU_H__
+
+#include <unistd.h>
+#include <mach.h>
+#include <mach/exception.h>
+#include "regcache.h"
+
+extern char *gnu_target_pid_to_str (int pid);
+
+/* Before storing, we need to read all the registers. */
+#define CHILD_PREPARE_TO_STORE() deprecated_read_register_bytes (0, NULL, DEPRECATED_REGISTER_BYTES)
+
+/* Don't do wait_for_inferior on attach. */
+#define ATTACH_NO_WAIT
+
+/* Use SVR4 style shared library support */
+#define SVR4_SHARED_LIBS
+#include "solib.h"
+#define NO_CORE_OPS
+
+#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 0000000..4a55a13
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-lynx.h
@@ -0,0 +1,86 @@
+/* Native-dependent definitions for LynxOS.
+
+ Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+struct target_waitstatus;
+
+#include <sys/conf.h>
+#include <sys/kernel.h>
+/* sys/kernel.h should define this, but doesn't always, sigh. */
+#ifndef __LYNXOS
+#define __LYNXOS
+#endif
+#include <sys/mem.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/itimer.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include "gdbthread.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
+
+/* 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 ptid_t child_wait (ptid_t ptid,
+ struct target_waitstatus *status);
+
+/* Lynx needs a special definition of this so that we can
+ print out the pid and thread number seperately. */
+
+
+/* override child_pid_to_str in inftarg.c */
+#define CHILD_PID_TO_STR
+extern char *lynx_pid_to_str (ptid_t ptid);
+
+#endif /* NM_LYNX_H */
diff --git a/contrib/gdb/gdb/config/nm-nbsd.h b/contrib/gdb/gdb/config/nm-nbsd.h
new file mode 100644
index 0000000..5078c56
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-nbsd.h
@@ -0,0 +1,27 @@
+/* Native-dependent definitions for NetBSD.
+ Copyright 1994, 1996, 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#define PTRACE_ARG3_TYPE char*
+
+#define FETCH_INFERIOR_REGISTERS
+
+#define ATTACH_DETACH
+
+#include "solib.h" /* Support for shared libraries. */
diff --git a/contrib/gdb/gdb/config/nm-nbsdaout.h b/contrib/gdb/gdb/config/nm-nbsdaout.h
new file mode 100644
index 0000000..026f1ed
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-nbsdaout.h
@@ -0,0 +1,72 @@
+/* Native-dependent definitions for NetBSD a.out.
+ Copyright 1994, 1996, 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* 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 0000000..4b4f098
--- /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, 1993, 1998 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. */
+
+/* Use SVR4 style shared library support */
+
+#define SVR4_SHARED_LIBS
+#include "solib.h"
+
+/* 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/powerpc/fbsd.mh b/contrib/gdb/gdb/config/powerpc/fbsd.mh
new file mode 100644
index 0000000..104aff3
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/fbsd.mh
@@ -0,0 +1,5 @@
+# Host: FreeBSD/powerpc
+NATDEPFILES= fbsd-proc.o fork-child.o gcore.o \
+ infptrace.o inftarg.o ppcfbsd-nat.o
+
+NAT_FILE= nm-fbsd.h
diff --git a/contrib/gdb/gdb/config/powerpc/fbsd.mt b/contrib/gdb/gdb/config/powerpc/fbsd.mt
new file mode 100644
index 0000000..856793b
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/fbsd.mt
@@ -0,0 +1,4 @@
+# Target: FreeBSD/powerpc
+TDEPFILES= rs6000-tdep.o ppc-sysv-tdep.o ppcfbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-ppc-eabi.h
diff --git a/contrib/gdb/gdb/config/powerpc/nbsd.mh b/contrib/gdb/gdb/config/powerpc/nbsd.mh
new file mode 100644
index 0000000..26ba24d
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/nbsd.mh
@@ -0,0 +1,3 @@
+# Host: PowerPC, running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o ppcnbsd-nat.o
+NAT_FILE= nm-nbsd.h
diff --git a/contrib/gdb/gdb/config/powerpc/nbsd.mt b/contrib/gdb/gdb/config/powerpc/nbsd.mt
new file mode 100644
index 0000000..d492f9d
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/nbsd.mt
@@ -0,0 +1,7 @@
+# Target: PowerPC, running NetBSD
+TDEPFILES= rs6000-tdep.o ppc-sysv-tdep.o ppcnbsd-tdep.o nbsd-tdep.o corelow.o \
+ solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
+
+SIM_OBS = remote-sim.o
+SIM = ../sim/ppc/libsim.a
diff --git a/contrib/gdb/gdb/config/powerpc/nm-fbsd.h b/contrib/gdb/gdb/config/powerpc/nm-fbsd.h
new file mode 100644
index 0000000..10b6823
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/nm-fbsd.h
@@ -0,0 +1,18 @@
+/* GNU GPL */
+
+#ifndef NM_FBSD_H
+#define NM_FBSD_H
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+/* Override child_pid_to_exec_file in 'inftarg.c'. */
+#define CHILD_PID_TO_EXEC_FILE
+
+#endif /* NM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/powerpc/nm-nbsd.h b/contrib/gdb/gdb/config/powerpc/nm-nbsd.h
new file mode 100644
index 0000000..5de6c9a
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/nm-nbsd.h
@@ -0,0 +1,27 @@
+/* Native-dependent definitions for PowerPC running NetBSD ELF, for GDB.
+ Copyright 2000, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "config/nm-nbsd.h"
+
+#endif
diff --git a/contrib/gdb/gdb/config/powerpc/ppc-eabi.mt b/contrib/gdb/gdb/config/powerpc/ppc-eabi.mt
new file mode 100644
index 0000000..5ef8cd9
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/ppc-eabi.mt
@@ -0,0 +1,3 @@
+# Target: PowerPC running eabi
+TDEPFILES= rs6000-tdep.o monitor.o dsrec.o ppcbug-rom.o dink32-rom.o ppc-bdm.o ocd.o remote-sds.o ppc-sysv-tdep.o solib.o solib-svr4.o
+TM_FILE= tm-ppc-eabi.h
diff --git a/contrib/gdb/gdb/config/powerpc/ppc-sim.mt b/contrib/gdb/gdb/config/powerpc/ppc-sim.mt
new file mode 100644
index 0000000..187bf39
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/ppc-sim.mt
@@ -0,0 +1,6 @@
+# Target: PowerPC running eabi and including the simulator
+TDEPFILES= rs6000-tdep.o monitor.o dsrec.o ppcbug-rom.o dink32-rom.o ppc-bdm.o ocd.o remote-sds.o ppc-sysv-tdep.o solib.o solib-svr4.o
+TM_FILE= tm-ppc-eabi.h
+
+SIM_OBS = remote-sim.o
+SIM = ../sim/ppc/libsim.a
diff --git a/contrib/gdb/gdb/config/powerpc/tm-nbsd.h b/contrib/gdb/gdb/config/powerpc/tm-nbsd.h
new file mode 100644
index 0000000..d167830
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/tm-nbsd.h
@@ -0,0 +1,26 @@
+/* Macro definitions for PowerPC running under NetBSD.
+ Copyright 2000, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "powerpc/tm-ppc-eabi.h"
+
+#endif /* TM_NBSD_H */
diff --git a/contrib/gdb/gdb/config/powerpc/tm-ppc-eabi.h b/contrib/gdb/gdb/config/powerpc/tm-ppc-eabi.h
new file mode 100644
index 0000000..d29b05d
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/tm-ppc-eabi.h
@@ -0,0 +1,40 @@
+/* Macro definitions for Power PC running embedded ABI.
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_PPC_EABI_H
+#define TM_PPC_EABI_H
+
+/* Use generic RS6000 definitions. */
+#include "rs6000/tm-rs6000.h"
+
+#undef PROCESS_LINENUMBER_HOOK
+
+#undef TEXT_SEGMENT_BASE
+#define TEXT_SEGMENT_BASE 1
+
+/* The value of symbols of type N_SO and N_FUN maybe null when
+ it shouldn't be. */
+#define SOFUN_ADDRESS_MAYBE_MISSING
+
+/* Use generic shared library machinery. */
+#include "solib.h"
+
+#endif /* TM_PPC_EABI_H */
diff --git a/contrib/gdb/gdb/config/powerpc/tm-ppcle-eabi.h b/contrib/gdb/gdb/config/powerpc/tm-ppcle-eabi.h
new file mode 100644
index 0000000..cc4c752e
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/tm-ppcle-eabi.h
@@ -0,0 +1,28 @@
+/* Macro definitions for Power PC running embedded ABI
+ in little endian mode.
+ Copyright 1995, 1998 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_PPCLE_EABI_H
+#define TM_PPCLE_EABI_H
+
+/* Use normal ppc-eabi definitions */
+#include "powerpc/tm-ppc-eabi.h"
+
+#endif /* TM_PPCLE_EABI_H */
diff --git a/contrib/gdb/gdb/config/powerpc/tm-ppcle-sim.h b/contrib/gdb/gdb/config/powerpc/tm-ppcle-sim.h
new file mode 100644
index 0000000..02707f4
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/tm-ppcle-sim.h
@@ -0,0 +1,26 @@
+/* Macro definitions for Power PC running embedded ABI under the simulator.
+ 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 TM_PPCLE_SIM_H
+#define TM_PPCLE_SIM_H
+
+#include "powerpc/tm-ppcle-eabi.h"
+
+#endif /* TM_PPCLE_SIM_H */
diff --git a/contrib/gdb/gdb/config/powerpc/tm-vxworks.h b/contrib/gdb/gdb/config/powerpc/tm-vxworks.h
new file mode 100644
index 0000000..69e2dde
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/tm-vxworks.h
@@ -0,0 +1,28 @@
+/* Target machine description for VxWorks on the PowerPC,
+ for GDB, the GNU debugger.
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef TM_VXWORKS_H
+#define TM_VXWORKS_H
+
+#include "powerpc/tm-ppc-eabi.h"
+#include "config/tm-vxworks.h"
+
+#endif /* ifndef TM_VXWORKS_H */
diff --git a/contrib/gdb/gdb/config/powerpc/vxworks.mt b/contrib/gdb/gdb/config/powerpc/vxworks.mt
new file mode 100644
index 0000000..eca028f
--- /dev/null
+++ b/contrib/gdb/gdb/config/powerpc/vxworks.mt
@@ -0,0 +1,3 @@
+# Target: Powerpc running VxWorks
+TDEPFILES= rs6000-tdep.o ppc-sysv-tdep.o solib.o solib-svr4.o
+TM_FILE= tm-vxworks.h
diff --git a/contrib/gdb/gdb/config/rs6000/nm-rs6000.h b/contrib/gdb/gdb/config/rs6000/nm-rs6000.h
new file mode 100644
index 0000000..34bc0fe
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/nm-rs6000.h
@@ -0,0 +1,69 @@
+/* IBM RS/6000 native-dependent macros for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1994, 1996, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+/* Override child_xfer_memory in infptrace.c. */
+
+#define CHILD_XFER_MEMORY
+
+/* When a child process is just starting, we sneak in and relocate
+ the symbol table (and other stuff) after the dynamic linker has
+ figured out where they go. */
+
+#define SOLIB_CREATE_INFERIOR_HOOK(PID) \
+ do { \
+ xcoff_relocate_symtab (PID); \
+ } while (0)
+
+/* When a target process or core-file has been attached, we sneak in
+ and figure out where the shared libraries have got to. */
+
+#define SOLIB_ADD(a, b, c, d) \
+ if (PIDGET (inferior_ptid)) \
+ /* Attach to process. */ \
+ xcoff_relocate_symtab (PIDGET (inferior_ptid)); \
+ else \
+ /* Core file. */ \
+ xcoff_relocate_core (c);
+
+extern void xcoff_relocate_symtab (unsigned int);
+struct target_ops;
+extern void xcoff_relocate_core (struct target_ops *);
+
+/* If ADDR lies in a shared library, return its name. */
+
+#define PC_SOLIB(PC) xcoff_solib_address(PC)
+extern char *xcoff_solib_address (CORE_ADDR);
+
+/* Return sizeof user struct to callers in less machine dependent routines */
+
+#define KERNEL_U_SIZE kernel_u_size()
+extern int kernel_u_size (void);
+
+/* Flag for machine-specific stuff in shared files. FIXME */
+#define DEPRECATED_IBM6000_TARGET
diff --git a/contrib/gdb/gdb/config/rs6000/nm-rs6000ly.h b/contrib/gdb/gdb/config/rs6000/nm-rs6000ly.h
new file mode 100644
index 0000000..51d12f8
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/nm-rs6000ly.h
@@ -0,0 +1,26 @@
+/* Native-dependent definitions for RS6000 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_RS6000LYNX_H
+#define NM_RS6000LYNX_H
+
+#include "config/nm-lynx.h"
+
+#endif /* NM_RS6000LYNX_H */
diff --git a/contrib/gdb/gdb/config/rs6000/rs6000.mh b/contrib/gdb/gdb/config/rs6000/rs6000.mh
new file mode 100644
index 0000000..c57319b
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/rs6000.mh
@@ -0,0 +1,11 @@
+# Host: IBM RS/6000 running AIX
+
+XM_FILE= xm-rs6000.h
+
+NAT_FILE= nm-rs6000.h
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o rs6000-nat.o \
+ xcoffsolib.o
+
+# When compiled with cc, for debugging, this argument should be passed.
+# We have no idea who our current compiler is though, so we skip it.
+# MH_CFLAGS = -bnodelcsect
diff --git a/contrib/gdb/gdb/config/rs6000/rs6000.mt b/contrib/gdb/gdb/config/rs6000/rs6000.mt
new file mode 100644
index 0000000..86b4c58
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/rs6000.mt
@@ -0,0 +1,3 @@
+# Target: IBM RS/6000 running AIX
+TDEPFILES= rs6000-tdep.o xcoffread.o ppc-sysv-tdep.o solib.o solib-svr4.o
+TM_FILE= tm-rs6000.h
diff --git a/contrib/gdb/gdb/config/rs6000/rs6000lynx.mh b/contrib/gdb/gdb/config/rs6000/rs6000lynx.mh
new file mode 100644
index 0000000..096473f
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/rs6000lynx.mh
@@ -0,0 +1,6 @@
+# Host: RS6000 running LynxOS
+
+XM_CLIBS= -lbsd
+
+NAT_FILE= nm-rs6000ly.h
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o lynx-nat.o xcoffread.o
diff --git a/contrib/gdb/gdb/config/rs6000/rs6000lynx.mt b/contrib/gdb/gdb/config/rs6000/rs6000lynx.mt
new file mode 100644
index 0000000..89ed7a2
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/rs6000lynx.mt
@@ -0,0 +1,3 @@
+# Target: IBM RS6000 running LynxOS
+TDEPFILES= coff-solib.o rs6000-tdep.o ppc-sysv-tdep.o solib.o solib-svr4.o
+TM_FILE= tm-rs6000ly.h
diff --git a/contrib/gdb/gdb/config/rs6000/tm-rs6000.h b/contrib/gdb/gdb/config/rs6000/tm-rs6000.h
new file mode 100644
index 0000000..4b8a09d
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/tm-rs6000.h
@@ -0,0 +1,103 @@
+/* Parameters for target execution on an RS6000, for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2004 Free Software Foundation, Inc.
+
+ 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. */
+
+struct frame_info;
+
+#define GDB_MULTI_ARCH 1
+
+/* Minimum possible text address in AIX */
+
+#define TEXT_SEGMENT_BASE 0x10000000
+
+/* Return whether PC in function NAME is in code that should be skipped when
+ single-stepping. */
+
+#define IN_SOLIB_RETURN_TRAMPOLINE(pc, name) \
+ rs6000_in_solib_return_trampoline (pc, name)
+extern int rs6000_in_solib_return_trampoline (CORE_ADDR, char *);
+
+/* If PC is in some function-call trampoline code, return the PC
+ where the function itself actually starts. If not, return NULL. */
+
+#define SKIP_TRAMPOLINE_CODE(pc) rs6000_skip_trampoline_code (pc)
+extern CORE_ADDR rs6000_skip_trampoline_code (CORE_ADDR);
+
+/* AIX has a couple of strange returns from wait(). */
+
+#define CHILD_SPECIAL_WAITSTATUS(ourstatus, hoststatus) ( \
+ /* "stop after load" status. */ \
+ (hoststatus) == 0x57c ? (ourstatus)->kind = TARGET_WAITKIND_LOADED, 1 : \
+ \
+ /* signal 0. I have no idea why wait(2) returns with this status word. */ \
+ /* It looks harmless. */ \
+ (hoststatus) == 0x7f ? (ourstatus)->kind = TARGET_WAITKIND_SPURIOUS, 1 : \
+ \
+ /* A normal waitstatus. Let the usual macros deal with it. */ \
+ 0)
+
+/* In xcoff, we cannot process line numbers when we see them. This is
+ mainly because we don't know the boundaries of the include files. So,
+ we postpone that, and then enter and sort(?) the whole line table at
+ once, when we are closing the current symbol table in end_symtab(). */
+
+#define PROCESS_LINENUMBER_HOOK() aix_process_linenos ()
+extern void aix_process_linenos (void);
+
+/* 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 FP0_REGNUM 32 /* Floating point register 0 */
+#define FPLAST_REGNUM 63 /* Last floating point register */
+
+/* Define other aspects of the stack frame. */
+
+#define DEPRECATED_INIT_FRAME_PC_FIRST(fromleaf, prev) \
+ (fromleaf ? DEPRECATED_SAVED_PC_AFTER_CALL (prev->next) : \
+ prev->next ? DEPRECATED_FRAME_SAVED_PC (prev->next) : read_pc ())
+
+/* Notice when a new child process is started. */
+
+#define TARGET_CREATE_INFERIOR_HOOK rs6000_create_inferior
+extern void rs6000_create_inferior (int);
+
+/* Hook in rs6000-tdep.c for determining the TOC address when
+ calling functions in the inferior. */
+
+extern CORE_ADDR (*rs6000_find_toc_address_hook) (CORE_ADDR);
+
+/* Hook in rs6000-tdep.c to set the current architecture when starting a
+ child process. */
+
+extern void (*rs6000_set_host_arch_hook) (int);
+
+/* We need solib.h for building cross debuggers. However, we don't want
+ to clobber any special solib support required by native debuggers, so
+ only include solib.h if SOLIB_ADD is not defined. */
+#ifndef SOLIB_ADD
+#include "solib.h"
+#endif
diff --git a/contrib/gdb/gdb/config/rs6000/tm-rs6000ly.h b/contrib/gdb/gdb/config/rs6000/tm-rs6000ly.h
new file mode 100644
index 0000000..73ef7f0
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/tm-rs6000ly.h
@@ -0,0 +1,31 @@
+/* Macro definitions for RS6000 running under LynxOS.
+ Copyright 1993, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_RS6000LYNX_H
+#define TM_RS6000LYNX_H
+
+#include "config/tm-lynx.h"
+
+/* Use generic RS6000 definitions. */
+#include "rs6000/tm-rs6000.h"
+
+#define CANNOT_STORE_REGISTER(regno) (regno == PS_REGNUM)
+
+#endif /* TM_RS6000LYNX_H */
diff --git a/contrib/gdb/gdb/config/rs6000/xm-rs6000.h b/contrib/gdb/gdb/config/rs6000/xm-rs6000.h
new file mode 100644
index 0000000..51096e6
--- /dev/null
+++ b/contrib/gdb/gdb/config/rs6000/xm-rs6000.h
@@ -0,0 +1,94 @@
+/* Parameters for hosting on an RS6000, for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+ 2000, 2001 Free Software Foundation, Inc.
+ 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. */
+
+/* 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
+ * <sys/select.h> below.
+ */
+#undef fd_set
+
+#include <sys/select.h>
+
+/* Big end is at the low address */
+
+/* At least as of AIX 3.2, we have termios. */
+#define HAVE_TERMIOS 1
+/* #define HAVE_TERMIO 1 */
+
+#define USG 1
+
+#define FIVE_ARG_PTRACE
+
+/* 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 (int);
+
+/* This doesn't seem to be declared in any header file I can find. */
+char *termdef (int, int);
+
+/* `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 appropriately. */ \
+ \
+void \
+aix_resizewindow (signo) \
+ int signo; \
+{ \
+ 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/s390/s390.mh b/contrib/gdb/gdb/config/s390/s390.mh
new file mode 100644
index 0000000..3db7bd9
--- /dev/null
+++ b/contrib/gdb/gdb/config/s390/s390.mh
@@ -0,0 +1,5 @@
+# Host: S390, running Linux
+NAT_FILE= nm-linux.h
+NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o s390-nat.o \
+ linux-proc.o gcore.o thread-db.o lin-lwp.o proc-service.o linux-nat.o
+LOADLIBES = -ldl -rdynamic
diff --git a/contrib/gdb/gdb/config/s390/s390.mt b/contrib/gdb/gdb/config/s390/s390.mt
new file mode 100644
index 0000000..86b6a33
--- /dev/null
+++ b/contrib/gdb/gdb/config/s390/s390.mt
@@ -0,0 +1,5 @@
+# Target: S390 running Linux
+TM_FILE= tm-linux.h
+TDEPFILES=s390-tdep.o solib.o
+# Post 5.0 tdep-files
+TDEPFILES+=solib-svr4.o solib-legacy.o
diff --git a/contrib/gdb/gdb/config/sparc/fbsd.mh b/contrib/gdb/gdb/config/sparc/fbsd.mh
new file mode 100644
index 0000000..fb491a5
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/fbsd.mh
@@ -0,0 +1,5 @@
+# Host: FreeBSD/sparc64
+NATDEPFILES= sparc64fbsd-nat.o sparc64-nat.o sparc-nat.o \
+ fork-child.o infptrace.o inftarg.o \
+ solib.o solib-svr4.o solib-legacy.o
+NAT_FILE= nm-fbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/fbsd.mt b/contrib/gdb/gdb/config/sparc/fbsd.mt
new file mode 100644
index 0000000..8e4dead
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/fbsd.mt
@@ -0,0 +1,3 @@
+# Target: FreeBSD/sparc64
+TDEPFILES= sparc-tdep.o sparc64-tdep.o sparc64fbsd-tdep.o corelow.o
+TM_FILE= tm-fbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/nbsd.mt b/contrib/gdb/gdb/config/sparc/nbsd.mt
new file mode 100644
index 0000000..25dbeff
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nbsd.mt
@@ -0,0 +1,4 @@
+# Target: NetBSD/sparc
+TDEPFILES= sparc-tdep.o sparcnbsd-tdep.o nbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/nbsd64.mh b/contrib/gdb/gdb/config/sparc/nbsd64.mh
new file mode 100644
index 0000000..e8ac58b
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nbsd64.mh
@@ -0,0 +1,4 @@
+# Host: NetBSD/sparc64
+NATDEPFILES= sparc64nbsd-nat.o sparc-nat.o \
+ fork-child.o infptrace.o inftarg.o
+NAT_FILE= nm-nbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/nbsd64.mt b/contrib/gdb/gdb/config/sparc/nbsd64.mt
new file mode 100644
index 0000000..4a1b13b
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nbsd64.mt
@@ -0,0 +1,5 @@
+# Target: NetBSD/sparc64
+TDEPFILES= sparc64-tdep.o sparc64nbsd-tdep.o \
+ sparc-tdep.o sparcnbsd-tdep.o nbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/nbsdaout.mh b/contrib/gdb/gdb/config/sparc/nbsdaout.mh
new file mode 100644
index 0000000..8944e60
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nbsdaout.mh
@@ -0,0 +1,4 @@
+# Host: NetBSD/sparc a.out
+NATDEPFILES= sparc-nat.o sparcnbsd-nat.o \
+ fork-child.o infptrace.o inftarg.o solib-sunos.o
+NAT_FILE= nm-nbsdaout.h
diff --git a/contrib/gdb/gdb/config/sparc/nbsdelf.mh b/contrib/gdb/gdb/config/sparc/nbsdelf.mh
new file mode 100644
index 0000000..45309ec
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nbsdelf.mh
@@ -0,0 +1,4 @@
+# Host: NetBSD/sparc ELF
+NATDEPFILES= sparc-nat.o sparcnbsd-nat.o \
+ fork-child.o infptrace.o inftarg.o
+NAT_FILE= nm-nbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/nm-fbsd.h b/contrib/gdb/gdb/config/sparc/nm-fbsd.h
new file mode 100644
index 0000000..917cc49
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nm-fbsd.h
@@ -0,0 +1,39 @@
+/* Native-dependent definitions for FreeBSD/sparc64.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+ Contributed by David E. O'Brien <obrien@FreeBSD.org>.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You 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_FBSD_H
+#define NM_FBSD_H
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+
+/* Shared library support. */
+
+#include "solib.h"
+
+#endif /* nm-fbsd.h */
diff --git a/contrib/gdb/gdb/config/sparc/nm-nbsd.h b/contrib/gdb/gdb/config/sparc/nm-nbsd.h
new file mode 100644
index 0000000..c64f505
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nm-nbsd.h
@@ -0,0 +1,42 @@
+/* Native-dependent definitions for NetBSD/sparc.
+
+ Copyright 1986, 1987, 1989, 1992, 1994, 1996, 1999, 2000, 2002,
+ 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "config/nm-nbsd.h"
+
+
+/* Support for StackGhost cookies. */
+
+#include "target.h"
+struct target_ops; /* Fool ARI. */
+
+#define NATIVE_XFER_WCOOKIE sparc_xfer_wcookie
+extern LONGEST sparc_xfer_wcookie (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len);
+
+#endif /* nm-nbsd.h */
diff --git a/contrib/gdb/gdb/config/sparc/nm-nbsdaout.h b/contrib/gdb/gdb/config/sparc/nm-nbsdaout.h
new file mode 100644
index 0000000..9e463f9
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nm-nbsdaout.h
@@ -0,0 +1,30 @@
+/* Native-dependent definitions for NetBSD/sparc a.out.
+
+ Copyright 1999, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "sparc/nm-nbsd.h"
+
+/* Get generic NetBSD a.out native definitions. */
+#include "config/nm-nbsdaout.h"
+
+#endif /* nm-nbsdaout.h */
diff --git a/contrib/gdb/gdb/config/sparc/nm-sol2.h b/contrib/gdb/gdb/config/sparc/nm-sol2.h
new file mode 100644
index 0000000..bc9de3f
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/nm-sol2.h
@@ -0,0 +1,65 @@
+/* Native-dependent definitions for Solaris SPARC.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You 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_SOL2_H
+#define NM_SOL2_H
+
+#define GDB_GREGSET_T prgregset_t
+#define GDB_FPREGSET_T prfpregset_t
+
+/* Shared library support. */
+
+#include "solib.h"
+
+/* Hardware wactchpoints. */
+
+/* Solaris 2.6 and above can do HW watchpoints. */
+#ifdef NEW_PROC_API
+
+#define TARGET_HAS_HARDWARE_WATCHPOINTS
+
+/* The man page for proc(4) on Solaris 2.6 and up says that the system
+ can support "thousands" of hardware watchpoints, but gives no
+ method for finding out how many; It doesn't say anything about the
+ allowed size for the watched area either. So we just tell GDB
+ 'yes'. */
+#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(SIZE) 1
+
+/* When a hardware watchpoint fires off the PC will be left at the
+ instruction following the one which caused the watchpoint. It will
+ *NOT* be necessary for GDB to step over the watchpoint. */
+#define HAVE_CONTINUABLE_WATCHPOINT 1
+
+extern int procfs_stopped_by_watchpoint (ptid_t);
+#define STOPPED_BY_WATCHPOINT(W) \
+ procfs_stopped_by_watchpoint(inferior_ptid)
+
+/* Use these macros for watchpoint insertion/deletion. TYPE can be 0
+ (write watch), 1 (read watch), 2 (access watch (read/write). */
+
+extern int procfs_set_watchpoint (ptid_t, CORE_ADDR, int, int, int);
+#define target_insert_watchpoint(ADDR, LEN, TYPE) \
+ procfs_set_watchpoint (inferior_ptid, ADDR, LEN, TYPE, 1)
+#define target_remove_watchpoint(ADDR, LEN, TYPE) \
+ procfs_set_watchpoint (inferior_ptid, ADDR, 0, 0, 0)
+
+#endif /* NEW_PROC_API */
+
+#endif /* nm-sol2.h */
diff --git a/contrib/gdb/gdb/config/sparc/obsd.mt b/contrib/gdb/gdb/config/sparc/obsd.mt
new file mode 100644
index 0000000..800cb04
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/obsd.mt
@@ -0,0 +1,4 @@
+# Target: OpenBSD/sparc
+TDEPFILES= sparc-tdep.o sparcnbsd-tdep.o sparcobsd-tdep.o nbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/obsd64.mt b/contrib/gdb/gdb/config/sparc/obsd64.mt
new file mode 100644
index 0000000..a692817
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/obsd64.mt
@@ -0,0 +1,5 @@
+# Target: OpenBSD/sparc64
+TDEPFILES= sparc64-tdep.o sparc64nbsd-tdep.o sparc64obsd-tdep.o \
+ sparc-tdep.o sparcnbsd-tdep.o nbsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
diff --git a/contrib/gdb/gdb/config/sparc/sol2-64.mt b/contrib/gdb/gdb/config/sparc/sol2-64.mt
new file mode 100644
index 0000000..92f8489
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/sol2-64.mt
@@ -0,0 +1,3 @@
+# Target: Solaris UltraSPARC
+TDEPFILES= sparc64-tdep.o sparc64-sol2-tdep.o sparc-tdep.o sparc-sol2-tdep.o
+TM_FILE= tm-sol2.h
diff --git a/contrib/gdb/gdb/config/sparc/sol2.mh b/contrib/gdb/gdb/config/sparc/sol2.mh
new file mode 100644
index 0000000..735b9ee
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/sol2.mh
@@ -0,0 +1,6 @@
+# Host: Solaris SPARC & UltraSPARC
+NAT_FILE= nm-sol2.h
+NATDEPFILES= sparc-sol2-nat.o \
+ corelow.o core-regset.o fork-child.o gcore.o \
+ procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o \
+ solib.o solib-svr4.o solib-legacy.o
diff --git a/contrib/gdb/gdb/config/sparc/sol2.mt b/contrib/gdb/gdb/config/sparc/sol2.mt
new file mode 100644
index 0000000..4037956
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/sol2.mt
@@ -0,0 +1,3 @@
+# Target: Solaris SPARC
+TDEPFILES= sparc-tdep.o sparc-sol2-tdep.o
+TM_FILE= tm-sol2.h
diff --git a/contrib/gdb/gdb/config/sparc/sparc.mt b/contrib/gdb/gdb/config/sparc/sparc.mt
new file mode 100644
index 0000000..ea78c97
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/sparc.mt
@@ -0,0 +1,2 @@
+# Target: SPARC
+TDEPFILES= sparc-tdep.o
diff --git a/contrib/gdb/gdb/config/sparc/sparc64.mt b/contrib/gdb/gdb/config/sparc/sparc64.mt
new file mode 100644
index 0000000..b1082be
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/sparc64.mt
@@ -0,0 +1,2 @@
+# Target: UltraSPARC
+TDEPFILES= sparc-tdep.o sparc64-tdep.o
diff --git a/contrib/gdb/gdb/config/sparc/tm-fbsd.h b/contrib/gdb/gdb/config/sparc/tm-fbsd.h
new file mode 100644
index 0000000..f441937
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/tm-fbsd.h
@@ -0,0 +1,27 @@
+/* Target-dependent definitions for FreeBSD/sparc64.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+ Contributed by David E. O'Brien <obrien@FreeBSD.org>.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You 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_FBSD_H
+#define TM_FBSD_H
+
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_TM
+
+#endif /* tm-fbsd.h */
diff --git a/contrib/gdb/gdb/config/sparc/tm-nbsd.h b/contrib/gdb/gdb/config/sparc/tm-nbsd.h
new file mode 100644
index 0000000..301136b
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/tm-nbsd.h
@@ -0,0 +1,30 @@
+/* Target-dependent definitions for NetBSD/sparc.
+
+ Copyright 1994, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_TM
+
+/* Shared library support. */
+#include "solib.h"
+
+#endif /* tm-nbsd.h */
diff --git a/contrib/gdb/gdb/config/sparc/tm-nbsd64.h b/contrib/gdb/gdb/config/sparc/tm-nbsd64.h
new file mode 100644
index 0000000..cc1d6b3
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/tm-nbsd64.h
@@ -0,0 +1,27 @@
+/* Macro definitions for UltraSPARC running under NetBSD.
+ Copyright 1994, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_NBSD64_H
+#define TM_NBSD64_H
+
+#include "sparc/tm-sp64.h" /* sets GDB_MULTI_ARCH */
+#include "solib.h"
+
+#endif /* TM_NBSD64_H */
diff --git a/contrib/gdb/gdb/config/sparc/tm-sol2.h b/contrib/gdb/gdb/config/sparc/tm-sol2.h
new file mode 100644
index 0000000..d111c1a
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/tm-sol2.h
@@ -0,0 +1,40 @@
+/* Target-dependent definitions for Solaris SPARC.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You 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_SOL2_H
+#define TM_SOL2_H
+
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_TM
+
+/* The Sun compilers (Sun ONE Studio, Forte Developer, Sun WorkShop,
+ SunPRO) compiler puts out 0 instead of the address in N_SO stabs.
+ Starting with SunPRO 3.0, the compiler does this for N_FUN stabs
+ too. */
+#define SOFUN_ADDRESS_MAYBE_MISSING
+
+/* The Sun compilers also do "globalization"; see the comment in
+ sparc-tdep.c for more information. */
+extern char *sparc_stabs_unglobalize_name (char *name);
+#define STATIC_TRANSFORM_NAME(name) \
+ sparc_stabs_unglobalize_name (name)
+#define IS_STATIC_TRANSFORM_NAME(name) \
+ ((name) != sparc_stabs_unglobalize_name (name))
+
+#endif /* tm-sol2.h */
diff --git a/contrib/gdb/gdb/config/sparc/tm-vxworks.h b/contrib/gdb/gdb/config/sparc/tm-vxworks.h
new file mode 100644
index 0000000..7b04748
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/tm-vxworks.h
@@ -0,0 +1,31 @@
+/* Target-dependent defenitions for VxWorks SPARC.
+
+ Copyright 1993, 1999, 2004 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. */
+
+#ifndef TM_VXWORKS_H
+#define TM_VXWORKS_H
+
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_TM
+
+/* Get generic VxWorks definitions. */
+#include "config/tm-vxworks.h"
+
+#endif /* tm-vxworks.h */
diff --git a/contrib/gdb/gdb/config/sparc/vxworks.mt b/contrib/gdb/gdb/config/sparc/vxworks.mt
new file mode 100644
index 0000000..175f92e
--- /dev/null
+++ b/contrib/gdb/gdb/config/sparc/vxworks.mt
@@ -0,0 +1,4 @@
+# Target: VxWorks SPARC
+TDEPFILES= sparc-tdep.o \
+ remote-vx.o remote-vxsparc.o xdr_ld.o xdr_ptrace.o xdr_rdb.o
+TM_FILE= tm-vxworks.h
diff --git a/contrib/gdb/gdb/config/tm-lynx.h b/contrib/gdb/gdb/config/tm-lynx.h
new file mode 100644
index 0000000..7fbc06f
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-lynx.h
@@ -0,0 +1,32 @@
+/* Macro definitions for LynxOS targets.
+ Copyright 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. */
+
+#ifndef TM_LYNX_H
+#define TM_LYNX_H
+
+#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-nto.h b/contrib/gdb/gdb/config/tm-nto.h
new file mode 100755
index 0000000..359ff06
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-nto.h
@@ -0,0 +1,61 @@
+/* Target machine sub-description for QNX Neutrino version 6.
+ This is included by other tm-*.h files to specify nto specific
+ stuff.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This code was donated by QNX Software Systems Ltd.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_QNXNTO_H
+#define _TM_QNXNTO_H
+
+#include "tm-sysv4.h"
+
+/* Setup the valid realtime signal range. */
+#define REALTIME_LO 41
+#define REALTIME_HI 56
+
+/* Set up the undefined useable signals. */
+#define RAW_SIGNAL_LO 32
+#define RAW_SIGNAL_HI (REALTIME_LO - 1)
+
+#define TARGET_SIGNAL_RAW_VALUES \
+TARGET_SIGNAL_RAW0, \
+TARGET_SIGNAL_RAW1, \
+TARGET_SIGNAL_RAW2, \
+TARGET_SIGNAL_RAW3, \
+TARGET_SIGNAL_RAW4, \
+TARGET_SIGNAL_RAW5, \
+TARGET_SIGNAL_RAW6, \
+TARGET_SIGNAL_RAW7, \
+TARGET_SIGNAL_RAW8
+
+#define TARGET_SIGNAL_RAW_TABLE \
+{"SIGNAL32", "Signal 32"}, \
+{"SIGNAL33", "Signal 33"}, \
+{"SIGNAL34", "Signal 34"}, \
+{"SIGNAL35", "Signal 35"}, \
+{"SIGNAL36", "Signal 36"}, \
+{"SIGNAL37", "Signal 37"}, \
+{"SIGNAL38", "Signal 38"}, \
+{"SIGNAL39", "Signal 39"}, \
+{"SIGNAL40", "Signal 40"}
+
+#endif /* _TM_QNXNTO_H */
diff --git a/contrib/gdb/gdb/config/tm-sunos.h b/contrib/gdb/gdb/config/tm-sunos.h
new file mode 100644
index 0000000..c8db07e
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-sunos.h
@@ -0,0 +1,32 @@
+/* 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 0000000..9a39af2
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-sysv4.h
@@ -0,0 +1,37 @@
+/* Macro definitions for GDB on all SVR4 target systems.
+ Copyright 1991, 1992, 1993, 1994, 1996, 1997, 2000
+ 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 (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)
diff --git a/contrib/gdb/gdb/config/tm-vxworks.h b/contrib/gdb/gdb/config/tm-vxworks.h
new file mode 100644
index 0000000..9afc0b4
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-vxworks.h
@@ -0,0 +1,23 @@
+/* Target machine description for VxWorks, for GDB, the GNU debugger.
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#define GDBINIT_FILENAME ".vxgdbinit"
+
+#define DEFAULT_PROMPT "(vxgdb) "
diff --git a/contrib/gdb/gdb/config/xm-nbsd.h b/contrib/gdb/gdb/config/xm-nbsd.h
new file mode 100644
index 0000000..c8d00f6
--- /dev/null
+++ b/contrib/gdb/gdb/config/xm-nbsd.h
@@ -0,0 +1,26 @@
+/* Host-dependent definitions for any CPU running NetBSD.
+ Copyright 1993, 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Include this to get things like NGROUPS which <limits.h> doesn't
+ define on some systems. */
+#include <sys/param.h>
+
+/* NetBSD has termios facilities. */
+#define HAVE_TERMIOS
diff --git a/contrib/gdb/gdb/config/xm-sysv4.h b/contrib/gdb/gdb/config/xm-sysv4.h
new file mode 100644
index 0000000..614d403
--- /dev/null
+++ b/contrib/gdb/gdb/config/xm-sysv4.h
@@ -0,0 +1,29 @@
+/* Definitions for running gdb on a host machine running any flavor of SVR4.
+ Copyright 1991, 1992, 1993, 1995, 1998 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
diff --git a/contrib/gdb/gdb/copying.awk b/contrib/gdb/gdb/copying.awk
new file mode 100644
index 0000000..53f7a6f
--- /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 show_copying_command (char *, int);"
+ print ""
+ print "static void show_warranty_command (char *, int);"
+ print ""
+ print "void _initialize_copying (void);"
+ 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 0000000..a78a862
--- /dev/null
+++ b/contrib/gdb/gdb/copying.c
@@ -0,0 +1,323 @@
+/* ==> 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 (char *, int);
+
+static void show_warranty_command (char *, int);
+
+void _initialize_copying (void);
+
+extern int immediate_quit;
+static void
+show_copying_command (char *ignore, int from_tty)
+{
+ immediate_quit++;
+ printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
+ printf_filtered (" Version 2, June 1991\n");
+ printf_filtered ("\n");
+ printf_filtered (" Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n");
+ printf_filtered (" 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 (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 (void)
+{
+ 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 0000000..0329302
--- /dev/null
+++ b/contrib/gdb/gdb/core-aout.c
@@ -0,0 +1,146 @@
+/* Extract registers from a "standard" core file, for GDB.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+#ifdef HAVE_PTRACE_H
+#include <ptrace.h>
+#else
+#ifdef HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include "gdbcore.h"
+#include "value.h" /* For supply_register. */
+#include "regcache.h"
+
+/* These are needed on various systems to expand REGISTER_U_ADDR. */
+#ifndef USG
+#include "gdb_dirent.h"
+#include <sys/file.h>
+#include "gdb_stat.h"
+#include <sys/user.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 <sys/core.h>
+#endif
+
+static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
+
+void _initialize_core_aout (void);
+
+/* 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 (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR reg_addr)
+{
+ int regno;
+ CORE_ADDR addr;
+ int bad_reg = -1;
+ CORE_ADDR reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */
+ int numregs = 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 > 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
+ && 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.", REGISTER_NAME (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. */
+
+CORE_ADDR
+register_addr (int regno, CORE_ADDR blockend)
+{
+ CORE_ADDR addr;
+
+ if (regno < 0 || regno >= 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, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_aout (void)
+{
+ 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 0000000..0600837
--- /dev/null
+++ b/contrib/gdb/gdb/core-regset.c
@@ -0,0 +1,119 @@
+/* Machine independent GDB support for core files on systems using "regsets".
+
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 used by most systems that use ELF for their core
+ dumps. This includes most systems that have SVR4-ish variant of
+ /proc. For these systems, the registers are laid out the same way
+ in core files as in the gregset_t and fpregset_t structures that
+ are used in the interaction with /proc (Irix 4 is an exception and
+ therefore doesn't use this file). Quite a few systems without a
+ SVR4-ish /proc define these structures too, and can make use of
+ this code too. */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "target.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include "gdb_string.h"
+#include <time.h>
+#ifdef HAVE_SYS_PROCFS_H
+#include <sys/procfs.h>
+#endif
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* Provide registers to GDB from a core file.
+
+ CORE_REG_SECT points to an array of bytes, which are the contents
+ of a `note' from a core file which BFD thinks might contain
+ register contents. CORE_REG_SIZE is its size.
+
+ WHICH says which register set corelow suspects this is:
+ 0 --- the general-purpose register set, in gregset_t format
+ 2 --- the floating-point register set, in fpregset_t format
+
+ REG_ADDR is ignored. */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR reg_addr)
+{
+ gdb_gregset_t gregset;
+ gdb_fpregset_t fpregset;
+
+ switch (which)
+ {
+ case 0:
+ if (core_reg_size != sizeof (gregset))
+ warning ("Wrong size gregset in core file.");
+ else
+ {
+ memcpy (&gregset, core_reg_sect, sizeof (gregset));
+ supply_gregset (&gregset);
+ }
+ break;
+
+ case 2:
+ if (core_reg_size != sizeof (fpregset))
+ warning ("Wrong size fpregset in core file.");
+ else
+ {
+ memcpy (&fpregset, core_reg_sect, sizeof (fpregset));
+ if (FP0_REGNUM >= 0)
+ supply_fpregset (&fpregset);
+ }
+ break;
+
+ default:
+ /* We've covered all the kinds of registers we know about here,
+ so this must be something we wouldn't know what to do with
+ anyway. Just ignore it. */
+ break;
+ }
+}
+
+
+/* Register that we are able to handle ELF core file formats using
+ standard procfs "regset" structures. */
+
+static struct core_fns regset_core_fns =
+{
+ bfd_target_elf_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern void _initialize_core_regset (void);
+
+void
+_initialize_core_regset (void)
+{
+ add_core_fns (&regset_core_fns);
+}
diff --git a/contrib/gdb/gdb/corefile.c b/contrib/gdb/gdb/corefile.c
new file mode 100644
index 0000000..572b448
--- /dev/null
+++ b/contrib/gdb/gdb/corefile.c
@@ -0,0 +1,458 @@
+/* Core dump and executable file functions above target vector, for GDB.
+
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1996, 1997,
+ 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <errno.h>
+#include <signal.h>
+#include <fcntl.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 "gdb_stat.h"
+#include "completer.h"
+
+/* Local function declarations. */
+
+extern void _initialize_core (void);
+static void call_extra_exec_file_hooks (char *filename);
+
+/* You can have any number of hooks for `exec_file_command' command to call.
+ If there's only one hook, it is set in exec_file_display hook.
+ If there are two or more hooks, they are set in exec_file_extra_hooks[],
+ and exec_file_display_hook is set to a function that calls all of them.
+ This extra complexity is needed to preserve compatibility with
+ old code that assumed that only one hook could be set, and which called
+ exec_file_display_hook directly. */
+
+typedef void (*hook_type) (char *);
+
+hook_type exec_file_display_hook; /* the original hook */
+static hook_type *exec_file_extra_hooks; /* array of additional hooks */
+static int exec_file_hook_count = 0; /* size of array */
+
+/* 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 (char *filename, int from_tty)
+{
+ struct target_ops *t;
+
+ dont_repeat (); /* Either way, seems bogus. */
+
+ t = find_core_target ();
+ if (t == NULL)
+ error ("GDB can't read core files on this machine.");
+
+ if (!filename)
+ (t->to_detach) (filename, from_tty);
+ else
+ (t->to_open) (filename, from_tty);
+}
+
+
+/* If there are two or more functions that wish to hook into exec_file_command,
+ * this function will call all of the hook functions. */
+
+static void
+call_extra_exec_file_hooks (char *filename)
+{
+ int i;
+
+ for (i = 0; i < exec_file_hook_count; i++)
+ (*exec_file_extra_hooks[i]) (filename);
+}
+
+/* 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 (void (*hook) (char *))
+{
+ hook_type *new_array;
+
+ if (exec_file_display_hook != NULL)
+ {
+ /* There's already a hook installed. Arrange to have both it
+ * and the subsequent hooks called. */
+ if (exec_file_hook_count == 0)
+ {
+ /* If this is the first extra hook, initialize the hook array. */
+ exec_file_extra_hooks = (hook_type *) xmalloc (sizeof (hook_type));
+ exec_file_extra_hooks[0] = exec_file_display_hook;
+ exec_file_display_hook = call_extra_exec_file_hooks;
+ exec_file_hook_count = 1;
+ }
+
+ /* Grow the hook array by one and add the new hook to the end.
+ Yes, it's inefficient to grow it by one each time but since
+ this is hardly ever called it's not a big deal. */
+ exec_file_hook_count++;
+ new_array =
+ (hook_type *) xrealloc (exec_file_extra_hooks,
+ exec_file_hook_count * sizeof (hook_type));
+ exec_file_extra_hooks = new_array;
+ exec_file_extra_hooks[exec_file_hook_count - 1] = hook;
+ }
+ else
+ exec_file_display_hook = hook;
+}
+
+/* The exec file must be closed before running an inferior.
+ If it is needed again after the inferior dies, it must
+ be reopened. */
+
+void
+close_exec_file (void)
+{
+#if 0 /* FIXME */
+ if (exec_bfd)
+ bfd_tempclose (exec_bfd);
+#endif
+}
+
+void
+reopen_exec_file (void)
+{
+#if 0 /* FIXME */
+ if (exec_bfd)
+ bfd_reopen (exec_bfd);
+#else
+ char *filename;
+ int res;
+ struct stat st;
+ long mtime;
+
+ /* Don't do anything if the current target isn't exec. */
+ if (exec_bfd == NULL || strcmp (target_shortname, "exec") != 0)
+ return;
+
+ /* If the timestamp of the exec file has changed, reopen it. */
+ filename = xstrdup (bfd_get_filename (exec_bfd));
+ make_cleanup (xfree, filename);
+ mtime = bfd_get_mtime (exec_bfd);
+ res = stat (filename, &st);
+
+ if (mtime && mtime != st.st_mtime)
+ {
+ exec_open (filename, 0);
+ }
+#endif
+}
+
+/* If we have both a core file and an exec file,
+ print a warning if they don't go together. */
+
+void
+validate_files (void)
+{
+ 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 (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 (int status, CORE_ADDR memaddr)
+{
+ struct ui_file *tmp_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_stream);
+
+ if (status == EIO)
+ {
+ /* Actually, address between memaddr and memaddr + len
+ was out of bounds. */
+ fprintf_unfiltered (tmp_stream, "Cannot access memory at address ");
+ print_address_numeric (memaddr, 1, tmp_stream);
+ }
+ else
+ {
+ fprintf_filtered (tmp_stream, "Error accessing memory address ");
+ print_address_numeric (memaddr, 1, tmp_stream);
+ fprintf_filtered (tmp_stream, ": %s.",
+ safe_strerror (status));
+ }
+
+ error_stream (tmp_stream);
+}
+
+/* Same as target_read_memory, but report an error if can't read. */
+void
+read_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int status;
+ status = target_read_memory (memaddr, myaddr, len);
+ if (status != 0)
+ memory_error (status, memaddr);
+}
+
+/* Argument / return result struct for use with
+ do_captured_read_memory_integer(). MEMADDR and LEN are filled in
+ by gdb_read_memory_integer(). RESULT is the contents that were
+ successfully read from MEMADDR of length LEN. */
+
+struct captured_read_memory_integer_arguments
+{
+ CORE_ADDR memaddr;
+ int len;
+ LONGEST result;
+};
+
+/* Helper function for gdb_read_memory_integer(). DATA must be a
+ pointer to a captured_read_memory_integer_arguments struct.
+ Return 1 if successful. Note that the catch_errors() interface
+ will return 0 if an error occurred while reading memory. This
+ choice of return code is so that we can distinguish between
+ success and failure. */
+
+static int
+do_captured_read_memory_integer (void *data)
+{
+ struct captured_read_memory_integer_arguments *args = (struct captured_read_memory_integer_arguments*) data;
+ CORE_ADDR memaddr = args->memaddr;
+ int len = args->len;
+
+ args->result = read_memory_integer (memaddr, len);
+
+ return 1;
+}
+
+/* Read memory at MEMADDR of length LEN and put the contents in
+ RETURN_VALUE. Return 0 if MEMADDR couldn't be read and non-zero
+ if successful. */
+
+int
+safe_read_memory_integer (CORE_ADDR memaddr, int len, LONGEST *return_value)
+{
+ int status;
+ struct captured_read_memory_integer_arguments args;
+ args.memaddr = memaddr;
+ args.len = len;
+
+ status = catch_errors (do_captured_read_memory_integer, &args,
+ "", RETURN_MASK_ALL);
+ if (status)
+ *return_value = args.result;
+
+ return status;
+}
+
+LONGEST
+read_memory_integer (CORE_ADDR memaddr, int len)
+{
+ char buf[sizeof (LONGEST)];
+
+ read_memory (memaddr, buf, len);
+ return extract_signed_integer (buf, len);
+}
+
+ULONGEST
+read_memory_unsigned_integer (CORE_ADDR memaddr, int len)
+{
+ char buf[sizeof (ULONGEST)];
+
+ read_memory (memaddr, buf, len);
+ return extract_unsigned_integer (buf, len);
+}
+
+void
+read_memory_string (CORE_ADDR memaddr, char *buffer, int max_len)
+{
+ char *cp;
+ int i;
+ int cnt;
+
+ cp = buffer;
+ while (1)
+ {
+ if (cp - buffer >= max_len)
+ {
+ buffer[max_len - 1] = '\0';
+ break;
+ }
+ cnt = max_len - (cp - buffer);
+ if (cnt > 8)
+ cnt = 8;
+ read_memory (memaddr + (int) (cp - buffer), cp, cnt);
+ for (i = 0; i < cnt && *cp; i++, cp++)
+ ; /* null body */
+
+ if (i < cnt && !*cp)
+ break;
+ }
+}
+
+CORE_ADDR
+read_memory_typed_address (CORE_ADDR addr, struct type *type)
+{
+ char *buf = alloca (TYPE_LENGTH (type));
+ read_memory (addr, buf, TYPE_LENGTH (type));
+ return extract_typed_address (buf, type);
+}
+
+/* Same as target_write_memory, but report an error if can't write. */
+void
+write_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int status;
+
+ status = target_write_memory (memaddr, myaddr, len);
+ if (status != 0)
+ memory_error (status, memaddr);
+}
+
+/* Store VALUE at ADDR in the inferior as a LEN-byte unsigned integer. */
+void
+write_memory_unsigned_integer (CORE_ADDR addr, int len, ULONGEST value)
+{
+ char *buf = alloca (len);
+ store_unsigned_integer (buf, len, value);
+ write_memory (addr, buf, len);
+}
+
+/* Store VALUE at ADDR in the inferior as a LEN-byte signed integer. */
+void
+write_memory_signed_integer (CORE_ADDR addr, int len, LONGEST value)
+{
+ char *buf = alloca (len);
+ store_signed_integer (buf, len, value);
+ write_memory (addr, 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 (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 (char *, int, struct cmd_list_element *);
+
+static void
+set_gnutarget_command (char *ignore, int from_tty, struct cmd_list_element *c)
+{
+ if (strcmp (gnutarget_string, "auto") == 0)
+ gnutarget = NULL;
+ else
+ gnutarget = gnutarget_string;
+}
+
+/* Set the gnutarget. */
+void
+set_gnutarget (char *newtarget)
+{
+ if (gnutarget_string != NULL)
+ xfree (gnutarget_string);
+ gnutarget_string = savestring (newtarget, strlen (newtarget));
+ set_gnutarget_command (NULL, 0, NULL);
+}
+
+void
+_initialize_core (void)
+{
+ 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);
+ set_cmd_completer (c, 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);
+ set_cmd_sfunc (c, 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 0000000..9e201cc
--- /dev/null
+++ b/contrib/gdb/gdb/corelow.c
@@ -0,0 +1,654 @@
+/* Core dump and executable file functions below target vector, for GDB.
+
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2003, 2004 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "gdb_string.h"
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h> /* needed for F_OK and friends */
+#endif
+#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 "gdbthread.h"
+#include "regcache.h"
+#include "regset.h"
+#include "symfile.h"
+#include "exec.h"
+#include "readline/readline.h"
+
+#include "gdb_assert.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* 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;
+
+/* The core_fns for a core file handler that is prepared to read the core
+ file currently open on core_bfd. */
+
+static struct core_fns *core_vec = NULL;
+
+/* FIXME: kettenis/20031023: Eventually this variable should
+ disappear. */
+
+struct gdbarch *core_gdbarch = NULL;
+
+static void core_files_info (struct target_ops *);
+
+#ifdef SOLIB_ADD
+static int solib_add_stub (void *);
+#endif
+
+static struct core_fns *sniff_core_bfd (bfd *);
+
+static int gdb_check_format (bfd *);
+
+static void core_open (char *, int);
+
+static void core_detach (char *, int);
+
+static void core_close (int);
+
+static void core_close_cleanup (void *ignore);
+
+static void get_core_registers (int);
+
+static void add_to_thread_list (bfd *, asection *, void *);
+
+static int ignore (CORE_ADDR, char *);
+
+static int core_file_thread_alive (ptid_t tid);
+
+static void init_core_ops (void);
+
+void _initialize_corelow (void);
+
+struct target_ops core_ops;
+
+/* 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 (struct core_fns *cf)
+{
+ cf->next = core_file_fns;
+ core_file_fns = cf;
+}
+
+/* The default function that core file handlers can use to examine a
+ core file BFD and decide whether or not to accept the job of
+ reading the core file. */
+
+int
+default_core_sniffer (struct core_fns *our_fns, bfd *abfd)
+{
+ int result;
+
+ result = (bfd_get_flavour (abfd) == our_fns -> core_flavour);
+ return (result);
+}
+
+/* Walk through the list of core functions to find a set that can
+ handle the core file open on ABFD. Default to the first one in the
+ list if nothing matches. Returns pointer to set that is
+ selected. */
+
+static struct core_fns *
+sniff_core_bfd (bfd *abfd)
+{
+ struct core_fns *cf;
+ struct core_fns *yummy = NULL;
+ int matches = 0;;
+
+ /* Don't sniff if we have support for register sets in CORE_GDBARCH. */
+ if (core_gdbarch && gdbarch_regset_from_core_section_p (core_gdbarch))
+ return NULL;
+
+ for (cf = core_file_fns; cf != NULL; cf = cf->next)
+ {
+ if (cf->core_sniffer (cf, abfd))
+ {
+ yummy = cf;
+ matches++;
+ }
+ }
+ if (matches > 1)
+ {
+ warning ("\"%s\": ambiguous core format, %d handlers match",
+ bfd_get_filename (abfd), matches);
+ }
+ else if (matches == 0)
+ {
+ warning ("\"%s\": no core file handler recognizes format, using default",
+ bfd_get_filename (abfd));
+ }
+ if (yummy == NULL)
+ {
+ yummy = core_file_fns;
+ }
+ return (yummy);
+}
+
+/* The default is to reject every core file format we see. Either
+ BFD has to recognize it, or we have to provide a function in the
+ core file handler that recognizes it. */
+
+int
+default_check_format (bfd *abfd)
+{
+ return (0);
+}
+
+/* Attempt to recognize core file formats that BFD rejects. */
+
+static int
+gdb_check_format (bfd *abfd)
+{
+ struct core_fns *cf;
+
+ for (cf = core_file_fns; cf != NULL; cf = cf->next)
+ {
+ if (cf->check_format (abfd))
+ {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/* Discard all vestiges of any previous core file and mark data and stack
+ spaces as empty. */
+
+static void
+core_close (int quitting)
+{
+ char *name;
+
+ if (core_bfd)
+ {
+ inferior_ptid = null_ptid; /* Avoid confusion from thread stuff */
+
+ /* Clear out solib state while the bfd is still open. See
+ comments in clear_solib in solib.c. */
+#ifdef CLEAR_SOLIB
+ CLEAR_SOLIB ();
+#endif
+
+ name = bfd_get_filename (core_bfd);
+ if (!bfd_close (core_bfd))
+ warning ("cannot close \"%s\": %s",
+ name, bfd_errmsg (bfd_get_error ()));
+ xfree (name);
+ core_bfd = NULL;
+ if (core_ops.to_sections)
+ {
+ xfree (core_ops.to_sections);
+ core_ops.to_sections = NULL;
+ core_ops.to_sections_end = NULL;
+ }
+ }
+ core_vec = NULL;
+ core_gdbarch = NULL;
+}
+
+static void
+core_close_cleanup (void *ignore)
+{
+ core_close (0/*ignored*/);
+}
+
+#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 (void *from_ttyp)
+{
+ SOLIB_ADD (NULL, *(int *) from_ttyp, &current_target, auto_solib_add);
+ 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 (bfd *abfd, asection *asect, void *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 (pid_to_ptid (thread_id));
+
+/* Warning, Will Robinson, looking at BFD private data! */
+
+ if (reg_sect != NULL
+ && asect->filepos == reg_sect->filepos) /* Did we find .reg? */
+ inferior_ptid = pid_to_ptid (thread_id); /* Yes, make it current */
+}
+
+/* This routine opens and sets up the core file bfd. */
+
+static void
+core_open (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);
+ xfree (filename);
+ filename = temp;
+ }
+
+ old_chain = make_cleanup (xfree, filename);
+
+ scratch_chan = open (filename, O_BINARY | ( 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) &&
+ !gdb_check_format (temp_bfd))
+ {
+ /* 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_cleanup, 0 /*ignore*/);
+
+ /* FIXME: kettenis/20031023: This is very dangerous. The
+ CORE_GDBARCH that results from this call may very well be
+ different from CURRENT_GDBARCH. However, its methods may only
+ work if it is selected as the current architecture, because they
+ rely on swapped data (see gdbarch.c). We should get rid of that
+ swapped data. */
+ core_gdbarch = gdbarch_from_bfd (core_bfd);
+
+ /* Find a suitable core file handler to munch on core_bfd */
+ core_vec = sniff_core_bfd (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 ()));
+
+ /* If we have no exec file, try to set the architecture from the
+ core file. We don't do this unconditionally since an exec file
+ typically contains more information that helps us determine the
+ architecture than a core file. */
+ if (!exec_bfd)
+ set_gdbarch_from_file (core_bfd);
+
+ 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)
+ /* NOTE: target_signal_from_host() converts a target signal value
+ into gdb's internal signal value. Unfortunately gdb's internal
+ value is called ``target_signal'' and this function got the
+ name ..._from_host(). */
+ printf_filtered ("Program terminated with signal %d, %s.\n", siggy,
+ target_signal_to_string (target_signal_from_host (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 ());
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 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 (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");
+}
+
+
+/* Try to retrieve registers from a section in core_bfd, and supply
+ them to core_vec->core_read_registers, as the register set numbered
+ WHICH.
+
+ If inferior_ptid is zero, do the single-threaded thing: look for a
+ section named NAME. If inferior_ptid is non-zero, do the
+ multi-threaded thing: look for a section named "NAME/PID", where
+ PID is the shortest ASCII decimal representation of inferior_ptid.
+
+ HUMAN_NAME is a human-readable name for the kind of registers the
+ NAME section contains, for use in error messages.
+
+ If REQUIRED is non-zero, print an error if the core file doesn't
+ have a section by the appropriate name. Otherwise, just do nothing. */
+
+static void
+get_core_register_section (char *name,
+ int which,
+ char *human_name,
+ int required)
+{
+ char section_name[100];
+ struct bfd_section *section;
+ bfd_size_type size;
+ char *contents;
+
+ if (PIDGET (inferior_ptid))
+ sprintf (section_name, "%s/%d", name, PIDGET (inferior_ptid));
+ else
+ strcpy (section_name, name);
+
+ section = bfd_get_section_by_name (core_bfd, section_name);
+ if (! section)
+ {
+ if (required)
+ warning ("Couldn't find %s registers in core file.\n", human_name);
+ return;
+ }
+
+ size = bfd_section_size (core_bfd, section);
+ contents = alloca (size);
+ if (! bfd_get_section_contents (core_bfd, section, contents,
+ (file_ptr) 0, size))
+ {
+ warning ("Couldn't read %s registers from `%s' section in core file.\n",
+ human_name, name);
+ return;
+ }
+
+ if (core_gdbarch && gdbarch_regset_from_core_section_p (core_gdbarch))
+ {
+ const struct regset *regset;
+
+ regset = gdbarch_regset_from_core_section (core_gdbarch, name, size);
+ if (regset == NULL)
+ {
+ if (required)
+ warning ("Couldn't recognize %s registers in core file.\n",
+ human_name);
+ return;
+ }
+
+ regset->supply_regset (regset, current_regcache, -1, contents, size);
+ return;
+ }
+
+ gdb_assert (core_vec);
+ core_vec->core_read_registers (contents, size, which,
+ ((CORE_ADDR)
+ bfd_section_vma (core_bfd, section)));
+}
+
+
+/* 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. */
+
+static void
+get_core_registers (int regno)
+{
+ int status;
+
+ if (!(core_gdbarch && gdbarch_regset_from_core_section_p (core_gdbarch))
+ && (core_vec == NULL || core_vec->core_read_registers == NULL))
+ {
+ fprintf_filtered (gdb_stderr,
+ "Can't fetch registers from this type of core file\n");
+ return;
+ }
+
+ get_core_register_section (".reg", 0, "general-purpose", 1);
+ get_core_register_section (".reg2", 2, "floating-point", 0);
+ get_core_register_section (".reg-xfp", 3, "extended floating-point", 0);
+
+ deprecated_registers_fetched ();
+}
+
+static void
+core_files_info (struct target_ops *t)
+{
+ print_section_info (t, core_bfd);
+}
+
+static LONGEST
+core_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_MEMORY:
+ if (readbuf)
+ return (*ops->to_xfer_memory) (offset, readbuf, len, 0/*read*/,
+ NULL, ops);
+ if (writebuf)
+ return (*ops->to_xfer_memory) (offset, writebuf, len, 1/*write*/,
+ NULL, ops);
+ return -1;
+
+ case TARGET_OBJECT_AUXV:
+ if (readbuf)
+ {
+ /* When the aux vector is stored in core file, BFD
+ represents this with a fake section called ".auxv". */
+
+ struct bfd_section *section;
+ bfd_size_type size;
+ char *contents;
+
+ section = bfd_get_section_by_name (core_bfd, ".auxv");
+ if (section == NULL)
+ return -1;
+
+ size = bfd_section_size (core_bfd, section);
+ if (offset >= size)
+ return 0;
+ size -= offset;
+ if (size > len)
+ size = len;
+ if (size > 0 &&
+ ! bfd_get_section_contents (core_bfd, section, readbuf,
+ (file_ptr) offset, size))
+ {
+ warning ("Couldn't read NT_AUXV note in core file.");
+ return -1;
+ }
+
+ return size;
+ }
+ return -1;
+
+ case TARGET_OBJECT_DIRTY:
+ {
+ ULONGEST addr;
+ addr = *(ULONGEST*)annex + offset;
+ if (readbuf)
+ return (*ops->to_xfer_memory) (addr, readbuf, len, 0/*read*/,
+ NULL, ops);
+ if (writebuf)
+ return (*ops->to_xfer_memory) (addr, writebuf, len, 1/*write*/,
+ NULL, ops);
+ return -1;
+ }
+
+ default:
+ if (ops->beneath != NULL)
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
+ return -1;
+ }
+}
+
+
+/* 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 (CORE_ADDR addr, char *contents)
+{
+ return 0;
+}
+
+
+/* Okay, let's be honest: threads gleaned from a core file aren't
+ exactly lively, are they? On the other hand, if we don't claim
+ that each & every one is alive, then we don't get any of them
+ to appear in an "info thread" command, which is quite a useful
+ behaviour.
+ */
+static int
+core_file_thread_alive (ptid_t tid)
+{
+ return 1;
+}
+
+/* Fill in core_ops with its defined operations and properties. */
+
+static void
+init_core_ops (void)
+{
+ core_ops.to_shortname = "core";
+ core_ops.to_longname = "Local core dump file";
+ core_ops.to_doc =
+ "Use a core file as a target. Specify the filename of the core file.";
+ core_ops.to_open = core_open;
+ core_ops.to_close = core_close;
+ core_ops.to_attach = find_default_attach;
+ core_ops.to_detach = core_detach;
+ core_ops.to_fetch_registers = get_core_registers;
+ core_ops.to_xfer_partial = core_xfer_partial;
+ core_ops.to_xfer_memory = xfer_memory;
+ core_ops.to_files_info = core_files_info;
+ core_ops.to_insert_breakpoint = ignore;
+ core_ops.to_remove_breakpoint = ignore;
+ core_ops.to_create_inferior = find_default_create_inferior;
+ core_ops.to_thread_alive = core_file_thread_alive;
+ core_ops.to_stratum = core_stratum;
+ core_ops.to_has_memory = 1;
+ core_ops.to_has_stack = 1;
+ core_ops.to_has_registers = 1;
+ core_ops.to_magic = OPS_MAGIC;
+}
+
+/* non-zero if we should not do the add_target call in
+ _initialize_corelow; not initialized (i.e., bss) so that
+ the target can initialize it (i.e., data) if appropriate.
+ This needs to be set at compile time because we don't know
+ for sure whether the target's initialize routine is called
+ before us or after us. */
+int coreops_suppress_target;
+
+void
+_initialize_corelow (void)
+{
+ init_core_ops ();
+
+ if (!coreops_suppress_target)
+ add_target (&core_ops);
+}
diff --git a/contrib/gdb/gdb/cp-abi.c b/contrib/gdb/gdb/cp-abi.c
new file mode 100644
index 0000000..a853020
--- /dev/null
+++ b/contrib/gdb/gdb/cp-abi.c
@@ -0,0 +1,252 @@
+/* Generic code for supporting multiple C++ ABI's
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "cp-abi.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "ui-out.h"
+
+#include "gdb_string.h"
+
+static struct cp_abi_ops *find_cp_abi (const char *short_name);
+
+static struct cp_abi_ops current_cp_abi = { "", NULL };
+static struct cp_abi_ops auto_cp_abi = { "auto", NULL };
+
+#define CP_ABI_MAX 8
+static struct cp_abi_ops *cp_abis[CP_ABI_MAX];
+static int num_cp_abis = 0;
+
+enum ctor_kinds
+is_constructor_name (const char *name)
+{
+ if ((current_cp_abi.is_constructor_name) == NULL)
+ error ("ABI doesn't define required function is_constructor_name");
+ return (*current_cp_abi.is_constructor_name) (name);
+}
+
+enum dtor_kinds
+is_destructor_name (const char *name)
+{
+ if ((current_cp_abi.is_destructor_name) == NULL)
+ error ("ABI doesn't define required function is_destructor_name");
+ return (*current_cp_abi.is_destructor_name) (name);
+}
+
+int
+is_vtable_name (const char *name)
+{
+ if ((current_cp_abi.is_vtable_name) == NULL)
+ error ("ABI doesn't define required function is_vtable_name");
+ return (*current_cp_abi.is_vtable_name) (name);
+}
+
+int
+is_operator_name (const char *name)
+{
+ if ((current_cp_abi.is_operator_name) == NULL)
+ error ("ABI doesn't define required function is_operator_name");
+ return (*current_cp_abi.is_operator_name) (name);
+}
+
+int
+baseclass_offset (struct type *type, int index, char *valaddr,
+ CORE_ADDR address)
+{
+ if (current_cp_abi.baseclass_offset == NULL)
+ error ("ABI doesn't define required function baseclass_offset");
+ return (*current_cp_abi.baseclass_offset) (type, index, valaddr, address);
+}
+
+struct value *
+value_virtual_fn_field (struct value **arg1p, struct fn_field *f, int j,
+ struct type *type, int offset)
+{
+ if ((current_cp_abi.virtual_fn_field) == NULL)
+ return NULL;
+ return (*current_cp_abi.virtual_fn_field) (arg1p, f, j, type, offset);
+}
+
+struct type *
+value_rtti_type (struct value *v, int *full, int *top, int *using_enc)
+{
+ if ((current_cp_abi.rtti_type) == NULL)
+ return NULL;
+ return (*current_cp_abi.rtti_type) (v, full, top, using_enc);
+}
+
+/* Set the current C++ ABI to SHORT_NAME. */
+
+static int
+switch_to_cp_abi (const char *short_name)
+{
+ struct cp_abi_ops *abi;
+
+ abi = find_cp_abi (short_name);
+ if (abi == NULL)
+ return 0;
+
+ current_cp_abi = *abi;
+ return 1;
+}
+
+/* Add ABI to the list of supported C++ ABI's. */
+
+int
+register_cp_abi (struct cp_abi_ops *abi)
+{
+ if (num_cp_abis == CP_ABI_MAX)
+ internal_error (__FILE__, __LINE__,
+ "Too many C++ ABIs, please increase CP_ABI_MAX in cp-abi.c");
+
+ cp_abis[num_cp_abis++] = abi;
+
+ return 1;
+}
+
+/* Set the ABI to use in "auto" mode to SHORT_NAME. */
+
+void
+set_cp_abi_as_auto_default (const char *short_name)
+{
+ char *new_longname, *new_doc;
+ struct cp_abi_ops *abi = find_cp_abi (short_name);
+
+ if (abi == NULL)
+ internal_error (__FILE__, __LINE__,
+ "Cannot find C++ ABI \"%s\" to set it as auto default.",
+ short_name);
+
+ if (auto_cp_abi.longname != NULL)
+ xfree ((char *) auto_cp_abi.longname);
+ if (auto_cp_abi.doc != NULL)
+ xfree ((char *) auto_cp_abi.doc);
+
+ auto_cp_abi = *abi;
+
+ auto_cp_abi.shortname = "auto";
+ new_longname = xmalloc (strlen ("currently ") + 1 + strlen (abi->shortname)
+ + 1 + 1);
+ sprintf (new_longname, "currently \"%s\"", abi->shortname);
+ auto_cp_abi.longname = new_longname;
+
+ new_doc = xmalloc (strlen ("Automatically selected; currently ")
+ + 1 + strlen (abi->shortname) + 1 + 1);
+ sprintf (new_doc, "Automatically selected; currently \"%s\"", abi->shortname);
+ auto_cp_abi.doc = new_doc;
+
+ /* Since we copy the current ABI into current_cp_abi instead of
+ using a pointer, if auto is currently the default, we need to
+ reset it. */
+ if (strcmp (current_cp_abi.shortname, "auto") == 0)
+ switch_to_cp_abi ("auto");
+}
+
+/* Return the ABI operations associated with SHORT_NAME. */
+
+static struct cp_abi_ops *
+find_cp_abi (const char *short_name)
+{
+ int i;
+
+ for (i = 0; i < num_cp_abis; i++)
+ if (strcmp (cp_abis[i]->shortname, short_name) == 0)
+ return cp_abis[i];
+
+ return NULL;
+}
+
+/* Display the list of registered C++ ABIs. */
+
+static void
+list_cp_abis (int from_tty)
+{
+ struct cleanup *cleanup_chain;
+ int i;
+ ui_out_text (uiout, "The available C++ ABIs are:\n");
+
+ cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "cp-abi-list");
+ for (i = 0; i < num_cp_abis; i++)
+ {
+ char pad[14];
+ int padcount;
+
+ ui_out_text (uiout, " ");
+ ui_out_field_string (uiout, "cp-abi", cp_abis[i]->shortname);
+
+ padcount = 16 - 2 - strlen (cp_abis[i]->shortname);
+ pad[padcount] = 0;
+ while (padcount > 0)
+ pad[--padcount] = ' ';
+ ui_out_text (uiout, pad);
+
+ ui_out_field_string (uiout, "doc", cp_abis[i]->doc);
+ ui_out_text (uiout, "\n");
+ }
+ do_cleanups (cleanup_chain);
+}
+
+/* Set the current C++ ABI, or display the list of options if no
+ argument is given. */
+
+static void
+set_cp_abi_cmd (char *args, int from_tty)
+{
+ if (args == NULL)
+ {
+ list_cp_abis (from_tty);
+ return;
+ }
+
+ if (!switch_to_cp_abi (args))
+ error ("Could not find \"%s\" in ABI list", args);
+}
+
+/* Show the currently selected C++ ABI. */
+
+static void
+show_cp_abi_cmd (char *args, int from_tty)
+{
+ ui_out_text (uiout, "The currently selected C++ ABI is \"");
+
+ ui_out_field_string (uiout, "cp-abi", current_cp_abi.shortname);
+ ui_out_text (uiout, "\" (");
+ ui_out_field_string (uiout, "longname", current_cp_abi.longname);
+ ui_out_text (uiout, ").\n");
+}
+
+extern initialize_file_ftype _initialize_cp_abi; /* -Wmissing-prototypes */
+
+void
+_initialize_cp_abi (void)
+{
+ register_cp_abi (&auto_cp_abi);
+ switch_to_cp_abi ("auto");
+
+ add_cmd ("cp-abi", class_obscure, set_cp_abi_cmd,
+ "Set the ABI used for inspecting C++ objects.\n"
+ "\"set cp-abi\" with no arguments will list the available ABIs.",
+ &setlist);
+
+ add_cmd ("cp-abi", class_obscure, show_cp_abi_cmd,
+ "Show the ABI used for inspecting C++ objects.", &showlist);
+}
diff --git a/contrib/gdb/gdb/cp-abi.h b/contrib/gdb/gdb/cp-abi.h
new file mode 100644
index 0000000..0413aba
--- /dev/null
+++ b/contrib/gdb/gdb/cp-abi.h
@@ -0,0 +1,172 @@
+/* Abstraction of various C++ ABI's we support, and the info we need
+ to get from them.
+ Contributed by Daniel Berlin <dberlin@redhat.com>
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or
+ modify
+ it under the terms of the GNU General Public License as published
+ by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 CP_ABI_H_
+#define CP_ABI_H_ 1
+
+struct fn_field;
+struct type;
+struct value;
+
+/* The functions here that attempt to determine what sort of thing a
+ mangled name refers to may well be revised in the future. It would
+ certainly be cleaner to carry this information explicitly in GDB's
+ data structures than to derive it from the mangled name. */
+
+
+/* Kinds of constructors. All these values are guaranteed to be
+ non-zero. */
+enum ctor_kinds {
+
+ /* Initialize a complete object, including virtual bases, using
+ memory provided by caller. */
+ complete_object_ctor = 1,
+
+ /* Initialize a base object of some larger object. */
+ base_object_ctor,
+
+ /* An allocating complete-object constructor. */
+ complete_object_allocating_ctor
+};
+
+/* Return non-zero iff NAME is the mangled name of a constructor.
+ Actually, return an `enum ctor_kind' value describing what *kind*
+ of constructor it is. */
+extern enum ctor_kinds is_constructor_name (const char *name);
+
+
+/* Kinds of destructors. All these values are guaranteed to be
+ non-zero. */
+enum dtor_kinds {
+
+ /* A destructor which finalizes the entire object, and then calls
+ `delete' on its storage. */
+ deleting_dtor = 1,
+
+ /* A destructor which finalizes the entire object, but does not call
+ `delete'. */
+ complete_object_dtor,
+
+ /* A destructor which finalizes a subobject of some larger object. */
+ base_object_dtor
+};
+
+/* Return non-zero iff NAME is the mangled name of a destructor.
+ Actually, return an `enum dtor_kind' value describing what *kind*
+ of destructor it is. */
+extern enum dtor_kinds is_destructor_name (const char *name);
+
+
+/* Return non-zero iff NAME is the mangled name of a vtable. */
+extern int is_vtable_name (const char *name);
+
+
+/* Return non-zero iff NAME is the un-mangled name of an operator,
+ perhaps scoped within some class. */
+extern int is_operator_name (const char *name);
+
+
+/* Return an object's virtual function as a value.
+
+ VALUEP is a pointer to a pointer to a value, holding the object
+ whose virtual function we want to invoke. If the ABI requires a
+ virtual function's caller to adjust the `this' pointer by an amount
+ retrieved from the vtable before invoking the function (i.e., we're
+ not using "vtable thunks" to do the adjustment automatically), then
+ this function may set *VALUEP to point to a new object with an
+ appropriately tweaked address.
+
+ The J'th element of the overload set F is the virtual function of
+ *VALUEP we want to invoke.
+
+ TYPE is the base type of *VALUEP whose method we're invoking ---
+ this is the type containing F. OFFSET is the offset of that base
+ type within *VALUEP. */
+extern struct value *value_virtual_fn_field (struct value **valuep,
+ struct fn_field *f, int j,
+ struct type *type, int offset);
+
+
+/* Try to find the run-time type of VALUE, using C++ run-time type
+ information. Return the run-time type, or zero if we can't figure
+ it out.
+
+ If we do find the run-time type:
+ - Set *FULL to non-zero if VALUE already contains the complete
+ run-time object, not just some embedded base class of the object.
+ - Set *TOP and *USING_ENC to indicate where the enclosing object
+ starts relative to VALUE:
+ - If *USING_ENC is zero, then *TOP is the offset from the start
+ of the complete object to the start of the embedded subobject
+ VALUE represents. In other words, the enclosing object starts
+ at VALUE_ADDR (VALUE) + VALUE_OFFSET (VALUE) +
+ VALUE_EMBEDDED_OFFSET (VALUE) + *TOP
+ - If *USING_ENC is non-zero, then *TOP is the offset from the
+ address of the complete object to the enclosing object stored
+ in VALUE. In other words, the enclosing object starts at
+ VALUE_ADDR (VALUE) + VALUE_OFFSET (VALUE) + *TOP.
+ If VALUE's type and enclosing type are the same, then these two
+ cases are equivalent.
+
+ FULL, TOP, and USING_ENC can each be zero, in which case we don't
+ provide the corresponding piece of information. */
+extern struct type *value_rtti_type (struct value *value,
+ int *full, int *top, int *using_enc);
+
+/* 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. */
+
+extern int baseclass_offset (struct type *type, int index, char *valaddr,
+ CORE_ADDR address);
+
+struct cp_abi_ops
+{
+ const char *shortname;
+ const char *longname;
+ const char *doc;
+
+ /* ABI-specific implementations for the functions declared above. */
+ enum ctor_kinds (*is_constructor_name) (const char *name);
+ enum dtor_kinds (*is_destructor_name) (const char *name);
+ int (*is_vtable_name) (const char *name);
+ int (*is_operator_name) (const char *name);
+ struct value *(*virtual_fn_field) (struct value **arg1p, struct fn_field * f,
+ int j, struct type * type, int offset);
+ struct type *(*rtti_type) (struct value *v, int *full, int *top,
+ int *using_enc);
+ int (*baseclass_offset) (struct type *type, int index, char *valaddr,
+ CORE_ADDR address);
+};
+
+
+extern int register_cp_abi (struct cp_abi_ops *abi);
+extern void set_cp_abi_as_auto_default (const char *short_name);
+
+#endif
+
diff --git a/contrib/gdb/gdb/cp-namespace.c b/contrib/gdb/gdb/cp-namespace.c
new file mode 100644
index 0000000..910289f
--- /dev/null
+++ b/contrib/gdb/gdb/cp-namespace.c
@@ -0,0 +1,871 @@
+/* Helper routines for C++ support in GDB.
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by David Carlton and by Kealia, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "cp-support.h"
+#include "gdb_obstack.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "gdb_assert.h"
+#include "block.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "dictionary.h"
+#include "command.h"
+#include "frame.h"
+
+/* When set, the file that we're processing is known to have debugging
+ info for C++ namespaces. */
+
+/* NOTE: carlton/2004-01-13: No currently released version of GCC (the
+ latest of which is 3.3.x at the time of this writing) produces this
+ debug info. GCC 3.4 should, however. */
+
+unsigned char processing_has_namespace_info;
+
+/* This contains our best guess as to the name of the current
+ enclosing namespace(s)/class(es), if any. For example, if we're
+ within the method foo() in the following code:
+
+ namespace N {
+ class C {
+ void foo () {
+ }
+ };
+ }
+
+ then processing_current_prefix should be set to "N::C". If
+ processing_has_namespace_info is false, then this variable might
+ not be reliable. */
+
+const char *processing_current_prefix;
+
+/* List of using directives that are active in the current file. */
+
+static struct using_direct *using_list;
+
+static struct using_direct *cp_add_using (const char *name,
+ unsigned int inner_len,
+ unsigned int outer_len,
+ struct using_direct *next);
+
+static struct using_direct *cp_copy_usings (struct using_direct *using,
+ struct obstack *obstack);
+
+static struct symbol *lookup_namespace_scope (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab,
+ const char *scope,
+ int scope_len);
+
+static struct symbol *lookup_symbol_file (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab,
+ int anonymous_namespace);
+
+static struct type *cp_lookup_transparent_type_loop (const char *name,
+ const char *scope,
+ int scope_len);
+
+static void initialize_namespace_symtab (struct objfile *objfile);
+
+static struct block *get_possible_namespace_block (struct objfile *objfile);
+
+static void free_namespace_block (struct symtab *symtab);
+
+static int check_possible_namespace_symbols_loop (const char *name,
+ int len,
+ struct objfile *objfile);
+
+static int check_one_possible_namespace_symbol (const char *name,
+ int len,
+ struct objfile *objfile);
+
+static
+struct symbol *lookup_possible_namespace_symbol (const char *name,
+ struct symtab **symtab);
+
+static void maintenance_cplus_namespace (char *args, int from_tty);
+
+/* Set up support for dealing with C++ namespace info in the current
+ symtab. */
+
+void cp_initialize_namespace ()
+{
+ processing_has_namespace_info = 0;
+ using_list = NULL;
+}
+
+/* Add all the using directives we've gathered to the current symtab.
+ STATIC_BLOCK should be the symtab's static block; OBSTACK is used
+ for allocation. */
+
+void
+cp_finalize_namespace (struct block *static_block,
+ struct obstack *obstack)
+{
+ if (using_list != NULL)
+ {
+ block_set_using (static_block,
+ cp_copy_usings (using_list, obstack),
+ obstack);
+ using_list = NULL;
+ }
+}
+
+/* Check to see if SYMBOL refers to an object contained within an
+ anonymous namespace; if so, add an appropriate using directive. */
+
+/* Optimize away strlen ("(anonymous namespace)"). */
+
+#define ANONYMOUS_NAMESPACE_LEN 21
+
+void
+cp_scan_for_anonymous_namespaces (const struct symbol *symbol)
+{
+ if (!processing_has_namespace_info
+ && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
+ {
+ const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
+ unsigned int previous_component;
+ unsigned int next_component;
+ const char *len;
+
+ /* Start with a quick-and-dirty check for mention of "(anonymous
+ namespace)". */
+
+ if (!cp_is_anonymous (name))
+ return;
+
+ previous_component = 0;
+ next_component = cp_find_first_component (name + previous_component);
+
+ while (name[next_component] == ':')
+ {
+ if ((next_component - previous_component) == ANONYMOUS_NAMESPACE_LEN
+ && strncmp (name + previous_component,
+ "(anonymous namespace)",
+ ANONYMOUS_NAMESPACE_LEN) == 0)
+ {
+ /* We've found a component of the name that's an
+ anonymous namespace. So add symbols in it to the
+ namespace given by the previous component if there is
+ one, or to the global namespace if there isn't. */
+ cp_add_using_directive (name,
+ previous_component == 0
+ ? 0 : previous_component - 2,
+ next_component);
+ }
+ /* The "+ 2" is for the "::". */
+ previous_component = next_component + 2;
+ next_component = (previous_component
+ + cp_find_first_component (name
+ + previous_component));
+ }
+ }
+}
+
+/* Add a using directive to using_list. NAME is the start of a string
+ that should contain the namespaces we want to add as initial
+ substrings, OUTER_LENGTH is the end of the outer namespace, and
+ INNER_LENGTH is the end of the inner namespace. If the using
+ directive in question has already been added, don't add it
+ twice. */
+
+void
+cp_add_using_directive (const char *name, unsigned int outer_length,
+ unsigned int inner_length)
+{
+ struct using_direct *current;
+ struct using_direct *new;
+
+ /* Has it already been added? */
+
+ for (current = using_list; current != NULL; current = current->next)
+ {
+ if ((strncmp (current->inner, name, inner_length) == 0)
+ && (strlen (current->inner) == inner_length)
+ && (strlen (current->outer) == outer_length))
+ return;
+ }
+
+ using_list = cp_add_using (name, inner_length, outer_length,
+ using_list);
+}
+
+/* Record the namespace that the function defined by SYMBOL was
+ defined in, if necessary. BLOCK is the associated block; use
+ OBSTACK for allocation. */
+
+void
+cp_set_block_scope (const struct symbol *symbol,
+ struct block *block,
+ struct obstack *obstack)
+{
+ /* Make sure that the name was originally mangled: if not, there
+ certainly isn't any namespace information to worry about! */
+
+ if (SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
+ {
+ if (processing_has_namespace_info)
+ {
+ block_set_scope
+ (block, obsavestring (processing_current_prefix,
+ strlen (processing_current_prefix),
+ obstack),
+ obstack);
+ }
+ else
+ {
+ /* Try to figure out the appropriate namespace from the
+ demangled name. */
+
+ /* FIXME: carlton/2003-04-15: If the function in question is
+ a method of a class, the name will actually include the
+ name of the class as well. This should be harmless, but
+ is a little unfortunate. */
+
+ const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
+ unsigned int prefix_len = cp_entire_prefix_len (name);
+
+ block_set_scope (block,
+ obsavestring (name, prefix_len, obstack),
+ obstack);
+ }
+ }
+}
+
+/* Test whether or not NAMESPACE looks like it mentions an anonymous
+ namespace; return nonzero if so. */
+
+int
+cp_is_anonymous (const char *namespace)
+{
+ return (strstr (namespace, "(anonymous namespace)")
+ != NULL);
+}
+
+/* Create a new struct using direct whose inner namespace is the
+ initial substring of NAME of leng INNER_LEN and whose outer
+ namespace is the initial substring of NAME of length OUTER_LENGTH.
+ Set its next member in the linked list to NEXT; allocate all memory
+ using xmalloc. It copies the strings, so NAME can be a temporary
+ string. */
+
+static struct using_direct *
+cp_add_using (const char *name,
+ unsigned int inner_len,
+ unsigned int outer_len,
+ struct using_direct *next)
+{
+ struct using_direct *retval;
+
+ gdb_assert (outer_len < inner_len);
+
+ retval = xmalloc (sizeof (struct using_direct));
+ retval->inner = savestring (name, inner_len);
+ retval->outer = savestring (name, outer_len);
+ retval->next = next;
+
+ return retval;
+}
+
+/* Make a copy of the using directives in the list pointed to by
+ USING, using OBSTACK to allocate memory. Free all memory pointed
+ to by USING via xfree. */
+
+static struct using_direct *
+cp_copy_usings (struct using_direct *using,
+ struct obstack *obstack)
+{
+ if (using == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ struct using_direct *retval
+ = obstack_alloc (obstack, sizeof (struct using_direct));
+ retval->inner = obsavestring (using->inner, strlen (using->inner),
+ obstack);
+ retval->outer = obsavestring (using->outer, strlen (using->outer),
+ obstack);
+ retval->next = cp_copy_usings (using->next, obstack);
+
+ xfree (using->inner);
+ xfree (using->outer);
+ xfree (using);
+
+ return retval;
+ }
+}
+
+/* The C++-specific version of name lookup for static and global
+ names. This makes sure that names get looked for in all namespaces
+ that are in scope. NAME is the natural name of the symbol that
+ we're looking for, LINKAGE_NAME (which is optional) is its linkage
+ name, BLOCK is the block that we're searching within, DOMAIN says
+ what kind of symbols we're looking for, and if SYMTAB is non-NULL,
+ we should store the symtab where we found the symbol in it. */
+
+struct symbol *
+cp_lookup_symbol_nonlocal (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ return lookup_namespace_scope (name, linkage_name, block, domain,
+ symtab, block_scope (block), 0);
+}
+
+/* Lookup NAME at namespace scope (or, in C terms, in static and
+ global variables). SCOPE is the namespace that the current
+ function is defined within; only consider namespaces whose length
+ is at least SCOPE_LEN. Other arguments are as in
+ cp_lookup_symbol_nonlocal.
+
+ For example, if we're within a function A::B::f and looking for a
+ symbol x, this will get called with NAME = "x", SCOPE = "A::B", and
+ SCOPE_LEN = 0. It then calls itself with NAME and SCOPE the same,
+ but with SCOPE_LEN = 1. And then it calls itself with NAME and
+ SCOPE the same, but with SCOPE_LEN = 4. This third call looks for
+ "A::B::x"; if it doesn't find it, then the second call looks for
+ "A::x", and if that call fails, then the first call looks for
+ "x". */
+
+static struct symbol *
+lookup_namespace_scope (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab,
+ const char *scope,
+ int scope_len)
+{
+ char *namespace;
+
+ if (scope[scope_len] != '\0')
+ {
+ /* Recursively search for names in child namespaces first. */
+
+ struct symbol *sym;
+ int new_scope_len = scope_len;
+
+ /* If the current scope is followed by "::", skip past that. */
+ if (new_scope_len != 0)
+ {
+ gdb_assert (scope[new_scope_len] == ':');
+ new_scope_len += 2;
+ }
+ new_scope_len += cp_find_first_component (scope + new_scope_len);
+ sym = lookup_namespace_scope (name, linkage_name, block,
+ domain, symtab,
+ scope, new_scope_len);
+ if (sym != NULL)
+ return sym;
+ }
+
+ /* Okay, we didn't find a match in our children, so look for the
+ name in the current namespace. */
+
+ namespace = alloca (scope_len + 1);
+ strncpy (namespace, scope, scope_len);
+ namespace[scope_len] = '\0';
+ return cp_lookup_symbol_namespace (namespace, name, linkage_name,
+ block, domain, symtab);
+}
+
+/* Look up NAME in the C++ namespace NAMESPACE, applying the using
+ directives that are active in BLOCK. Other arguments are as in
+ cp_lookup_symbol_nonlocal. */
+
+struct symbol *
+cp_lookup_symbol_namespace (const char *namespace,
+ const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ const struct using_direct *current;
+ struct symbol *sym;
+
+ /* First, go through the using directives. If any of them add new
+ names to the namespace we're searching in, see if we can find a
+ match by applying them. */
+
+ for (current = block_using (block);
+ current != NULL;
+ current = current->next)
+ {
+ if (strcmp (namespace, current->outer) == 0)
+ {
+ sym = cp_lookup_symbol_namespace (current->inner,
+ name,
+ linkage_name,
+ block,
+ domain,
+ symtab);
+ if (sym != NULL)
+ return sym;
+ }
+ }
+
+ /* We didn't find anything by applying any of the using directives
+ that are still applicable; so let's see if we've got a match
+ using the current namespace. */
+
+ if (namespace[0] == '\0')
+ {
+ return lookup_symbol_file (name, linkage_name, block,
+ domain, symtab, 0);
+ }
+ else
+ {
+ char *concatenated_name
+ = alloca (strlen (namespace) + 2 + strlen (name) + 1);
+ strcpy (concatenated_name, namespace);
+ strcat (concatenated_name, "::");
+ strcat (concatenated_name, name);
+ sym = lookup_symbol_file (concatenated_name, linkage_name,
+ block, domain, symtab,
+ cp_is_anonymous (namespace));
+ return sym;
+ }
+}
+
+/* Look up NAME in BLOCK's static block and in global blocks. If
+ ANONYMOUS_NAMESPACE is nonzero, the symbol in question is located
+ within an anonymous namespace. Other arguments are as in
+ cp_lookup_symbol_nonlocal. */
+
+static struct symbol *
+lookup_symbol_file (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab,
+ int anonymous_namespace)
+{
+ struct symbol *sym = NULL;
+
+ sym = lookup_symbol_static (name, linkage_name, block, domain, symtab);
+ if (sym != NULL)
+ return sym;
+
+ if (anonymous_namespace)
+ {
+ /* Symbols defined in anonymous namespaces have external linkage
+ but should be treated as local to a single file nonetheless.
+ So we only search the current file's global block. */
+
+ const struct block *global_block = block_global_block (block);
+
+ if (global_block != NULL)
+ sym = lookup_symbol_aux_block (name, linkage_name, global_block,
+ domain, symtab);
+ }
+ else
+ {
+ sym = lookup_symbol_global (name, linkage_name, domain, symtab);
+ }
+
+ if (sym != NULL)
+ return sym;
+
+ /* Now call "lookup_possible_namespace_symbol". Symbols in here
+ claim to be associated to namespaces, but this claim might be
+ incorrect: the names in question might actually correspond to
+ classes instead of namespaces. But if they correspond to
+ classes, then we should have found a match for them above. So if
+ we find them now, they should be genuine. */
+
+ /* FIXME: carlton/2003-06-12: This is a hack and should eventually
+ be deleted: see comments below. */
+
+ if (domain == VAR_DOMAIN)
+ {
+ sym = lookup_possible_namespace_symbol (name, symtab);
+ if (sym != NULL)
+ return sym;
+ }
+
+ return NULL;
+}
+
+/* Look up a type named NESTED_NAME that is nested inside the C++
+ class or namespace given by PARENT_TYPE, from within the context
+ given by BLOCK. Return NULL if there is no such nested type. */
+
+struct type *
+cp_lookup_nested_type (struct type *parent_type,
+ const char *nested_name,
+ const struct block *block)
+{
+ switch (TYPE_CODE (parent_type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_NAMESPACE:
+ {
+ /* NOTE: carlton/2003-11-10: We don't treat C++ class members
+ of classes like, say, data or function members. Instead,
+ they're just represented by symbols whose names are
+ qualified by the name of the surrounding class. This is
+ just like members of namespaces; in particular,
+ lookup_symbol_namespace works when looking them up. */
+
+ const char *parent_name = TYPE_TAG_NAME (parent_type);
+ struct symbol *sym = cp_lookup_symbol_namespace (parent_name,
+ nested_name,
+ NULL,
+ block,
+ VAR_DOMAIN,
+ NULL);
+ if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ return NULL;
+ else
+ return SYMBOL_TYPE (sym);
+ }
+ default:
+ internal_error (__FILE__, __LINE__,
+ "cp_lookup_nested_type called on a non-aggregate type.");
+ }
+}
+
+/* The C++-version of lookup_transparent_type. */
+
+/* FIXME: carlton/2004-01-16: The problem that this is trying to
+ address is that, unfortunately, sometimes NAME is wrong: it may not
+ include the name of namespaces enclosing the type in question.
+ lookup_transparent_type gets called when the the type in question
+ is a declaration, and we're trying to find its definition; but, for
+ declarations, our type name deduction mechanism doesn't work.
+ There's nothing we can do to fix this in general, I think, in the
+ absence of debug information about namespaces (I've filed PR
+ gdb/1511 about this); until such debug information becomes more
+ prevalent, one heuristic which sometimes looks is to search for the
+ definition in namespaces containing the current namespace.
+
+ We should delete this functions once the appropriate debug
+ information becomes more widespread. (GCC 3.4 will be the first
+ released version of GCC with such information.) */
+
+struct type *
+cp_lookup_transparent_type (const char *name)
+{
+ /* First, try the honest way of looking up the definition. */
+ struct type *t = basic_lookup_transparent_type (name);
+ const char *scope;
+
+ if (t != NULL)
+ return t;
+
+ /* If that doesn't work and we're within a namespace, look there
+ instead. */
+ scope = block_scope (get_selected_block (0));
+
+ if (scope[0] == '\0')
+ return NULL;
+
+ return cp_lookup_transparent_type_loop (name, scope, 0);
+}
+
+/* Lookup the the type definition associated to NAME in
+ namespaces/classes containing SCOPE whose name is strictly longer
+ than LENGTH. LENGTH must be the index of the start of a
+ component of SCOPE. */
+
+static struct type *
+cp_lookup_transparent_type_loop (const char *name, const char *scope,
+ int length)
+{
+ int scope_length = length + cp_find_first_component (scope + length);
+ char *full_name;
+
+ /* If the current scope is followed by "::", look in the next
+ component. */
+ if (scope[scope_length] == ':')
+ {
+ struct type *retval
+ = cp_lookup_transparent_type_loop (name, scope, scope_length + 2);
+ if (retval != NULL)
+ return retval;
+ }
+
+ full_name = alloca (scope_length + 2 + strlen (name) + 1);
+ strncpy (full_name, scope, scope_length);
+ strncpy (full_name + scope_length, "::", 2);
+ strcpy (full_name + scope_length + 2, name);
+
+ return basic_lookup_transparent_type (full_name);
+}
+
+/* Now come functions for dealing with symbols associated to
+ namespaces. (They're used to store the namespaces themselves, not
+ objects that live in the namespaces.) These symbols come in two
+ varieties: if we run into a DW_TAG_namespace DIE, then we know that
+ we have a namespace, so dwarf2read.c creates a symbol for it just
+ like normal. But, unfortunately, versions of GCC through at least
+ 3.3 don't generate those DIE's. Our solution is to try to guess
+ their existence by looking at demangled names. This might cause us
+ to misidentify classes as namespaces, however. So we put those
+ symbols in a special block (one per objfile), and we only search
+ that block as a last resort. */
+
+/* FIXME: carlton/2003-06-12: Once versions of GCC that generate
+ DW_TAG_namespace have been out for a year or two, we should get rid
+ of all of this "possible namespace" nonsense. */
+
+/* Allocate everything necessary for the possible namespace block
+ associated to OBJFILE. */
+
+static void
+initialize_namespace_symtab (struct objfile *objfile)
+{
+ struct symtab *namespace_symtab;
+ struct blockvector *bv;
+ struct block *bl;
+
+ namespace_symtab = allocate_symtab ("<<C++-namespaces>>", objfile);
+ namespace_symtab->language = language_cplus;
+ namespace_symtab->free_code = free_nothing;
+ namespace_symtab->dirname = NULL;
+
+ bv = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct blockvector)
+ + FIRST_LOCAL_BLOCK * sizeof (struct block *));
+ BLOCKVECTOR_NBLOCKS (bv) = FIRST_LOCAL_BLOCK + 1;
+ BLOCKVECTOR (namespace_symtab) = bv;
+
+ /* Allocate empty GLOBAL_BLOCK and STATIC_BLOCK. */
+
+ bl = allocate_block (&objfile->objfile_obstack);
+ BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack,
+ NULL);
+ BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+ bl = allocate_block (&objfile->objfile_obstack);
+ BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack,
+ NULL);
+ BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
+
+ /* Allocate the possible namespace block; we put it where the first
+ local block will live, though I don't think there's any need to
+ pretend that it's actually a local block (e.g. by setting
+ BLOCK_SUPERBLOCK appropriately). We don't use the global or
+ static block because we don't want it searched during the normal
+ search of all global/static blocks in lookup_symbol: we only want
+ it used as a last resort. */
+
+ /* NOTE: carlton/2003-09-11: I considered not associating the fake
+ symbols to a block/symtab at all. But that would cause problems
+ with lookup_symbol's SYMTAB argument and with block_found, so
+ having a symtab/block for this purpose seems like the best
+ solution for now. */
+
+ bl = allocate_block (&objfile->objfile_obstack);
+ BLOCK_DICT (bl) = dict_create_hashed_expandable ();
+ BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK) = bl;
+
+ namespace_symtab->free_func = free_namespace_block;
+
+ objfile->cp_namespace_symtab = namespace_symtab;
+}
+
+/* Locate the possible namespace block associated to OBJFILE,
+ allocating it if necessary. */
+
+static struct block *
+get_possible_namespace_block (struct objfile *objfile)
+{
+ if (objfile->cp_namespace_symtab == NULL)
+ initialize_namespace_symtab (objfile);
+
+ return BLOCKVECTOR_BLOCK (BLOCKVECTOR (objfile->cp_namespace_symtab),
+ FIRST_LOCAL_BLOCK);
+}
+
+/* Free the dictionary associated to the possible namespace block. */
+
+static void
+free_namespace_block (struct symtab *symtab)
+{
+ struct block *possible_namespace_block;
+
+ possible_namespace_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab),
+ FIRST_LOCAL_BLOCK);
+ gdb_assert (possible_namespace_block != NULL);
+ dict_free (BLOCK_DICT (possible_namespace_block));
+}
+
+/* Ensure that there are symbols in the possible namespace block
+ associated to OBJFILE for all initial substrings of NAME that look
+ like namespaces or classes. NAME should end in a member variable:
+ it shouldn't consist solely of namespaces. */
+
+void
+cp_check_possible_namespace_symbols (const char *name, struct objfile *objfile)
+{
+ check_possible_namespace_symbols_loop (name,
+ cp_find_first_component (name),
+ objfile);
+}
+
+/* This is a helper loop for cp_check_possible_namespace_symbols; it
+ ensures that there are symbols in the possible namespace block
+ associated to OBJFILE for all namespaces that are initial
+ substrings of NAME of length at least LEN. It returns 1 if a
+ previous loop had already created the shortest such symbol and 0
+ otherwise.
+
+ This function assumes that if there is already a symbol associated
+ to a substring of NAME of a given length, then there are already
+ symbols associated to all substrings of NAME whose length is less
+ than that length. So if cp_check_possible_namespace_symbols has
+ been called once with argument "A::B::C::member", then that will
+ create symbols "A", "A::B", and "A::B::C". If it is then later
+ called with argument "A::B::D::member", then the new call will
+ generate a new symbol for "A::B::D", but once it sees that "A::B"
+ has already been created, it doesn't bother checking to see if "A"
+ has also been created. */
+
+static int
+check_possible_namespace_symbols_loop (const char *name, int len,
+ struct objfile *objfile)
+{
+ if (name[len] == ':')
+ {
+ int done;
+ int next_len = len + 2;
+
+ next_len += cp_find_first_component (name + next_len);
+ done = check_possible_namespace_symbols_loop (name, next_len,
+ objfile);
+
+ if (!done)
+ done = check_one_possible_namespace_symbol (name, len, objfile);
+
+ return done;
+ }
+ else
+ return 0;
+}
+
+/* Check to see if there's already a possible namespace symbol in
+ OBJFILE whose name is the initial substring of NAME of length LEN.
+ If not, create one and return 0; otherwise, return 1. */
+
+static int
+check_one_possible_namespace_symbol (const char *name, int len,
+ struct objfile *objfile)
+{
+ struct block *block = get_possible_namespace_block (objfile);
+ char *name_copy = alloca (len + 1);
+ struct symbol *sym;
+
+ memcpy (name_copy, name, len);
+ name_copy[len] = '\0';
+ sym = lookup_block_symbol (block, name_copy, NULL, VAR_DOMAIN);
+
+ if (sym == NULL)
+ {
+ struct type *type;
+ name_copy = obsavestring (name, len, &objfile->objfile_obstack);
+
+ type = init_type (TYPE_CODE_NAMESPACE, 0, 0, name_copy, objfile);
+
+ TYPE_TAG_NAME (type) = TYPE_NAME (type);
+
+ sym = obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_LANGUAGE (sym) = language_cplus;
+ SYMBOL_SET_NAMES (sym, name_copy, len, objfile);
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+
+ dict_add_symbol (BLOCK_DICT (block), sym);
+
+ return 0;
+ }
+ else
+ return 1;
+}
+
+/* Look for a symbol named NAME in all the possible namespace blocks.
+ If one is found, return it; if SYMTAB is non-NULL, set *SYMTAB to
+ equal the symtab where it was found. */
+
+static struct symbol *
+lookup_possible_namespace_symbol (const char *name, struct symtab **symtab)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct symbol *sym;
+
+ sym = lookup_block_symbol (get_possible_namespace_block (objfile),
+ name, NULL, VAR_DOMAIN);
+
+ if (sym != NULL)
+ {
+ if (symtab != NULL)
+ *symtab = objfile->cp_namespace_symtab;
+
+ return sym;
+ }
+ }
+
+ return NULL;
+}
+
+/* Print out all the possible namespace symbols. */
+
+static void
+maintenance_cplus_namespace (char *args, int from_tty)
+{
+ struct objfile *objfile;
+ printf_unfiltered ("Possible namespaces:\n");
+ ALL_OBJFILES (objfile)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ ALL_BLOCK_SYMBOLS (get_possible_namespace_block (objfile), iter, sym)
+ {
+ printf_unfiltered ("%s\n", SYMBOL_PRINT_NAME (sym));
+ }
+ }
+}
+
+void
+_initialize_cp_namespace (void)
+{
+ add_cmd ("namespace", class_maintenance, maintenance_cplus_namespace,
+ "Print the list of possible C++ namespaces.",
+ &maint_cplus_cmd_list);
+}
diff --git a/contrib/gdb/gdb/cp-support.c b/contrib/gdb/gdb/cp-support.c
new file mode 100644
index 0000000..4344545
--- /dev/null
+++ b/contrib/gdb/gdb/cp-support.c
@@ -0,0 +1,757 @@
+/* Helper routines for C++ support in GDB.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#include "cp-support.h"
+#include "gdb_string.h"
+#include "demangle.h"
+#include "gdb_assert.h"
+#include "gdbcmd.h"
+#include "dictionary.h"
+#include "objfiles.h"
+#include "frame.h"
+#include "symtab.h"
+#include "block.h"
+#include "complaints.h"
+#include "gdbtypes.h"
+
+/* Functions related to demangled name parsing. */
+
+static const char *find_last_component (const char *name);
+
+static unsigned int cp_find_first_component_aux (const char *name,
+ int permissive);
+
+static void demangled_name_complaint (const char *name);
+
+/* Functions/variables related to overload resolution. */
+
+static int sym_return_val_size;
+static int sym_return_val_index;
+static struct symbol **sym_return_val;
+
+static char *remove_params (const char *demangled_name);
+
+static void overload_list_add_symbol (struct symbol *sym,
+ const char *oload_name);
+
+static void make_symbol_overload_list_using (const char *func_name,
+ const char *namespace);
+
+static void make_symbol_overload_list_qualified (const char *func_name);
+
+static void read_in_psymtabs (const char *oload_name);
+
+/* The list of "maint cplus" commands. */
+
+struct cmd_list_element *maint_cplus_cmd_list = NULL;
+
+/* The actual commands. */
+
+static void maint_cplus_command (char *arg, int from_tty);
+static void first_component_command (char *arg, int from_tty);
+
+/* Here are some random pieces of trivia to keep in mind while trying
+ to take apart demangled names:
+
+ - Names can contain function arguments or templates, so the process
+ has to be, to some extent recursive: maybe keep track of your
+ depth based on encountering <> and ().
+
+ - Parentheses don't just have to happen at the end of a name: they
+ can occur even if the name in question isn't a function, because
+ a template argument might be a type that's a function.
+
+ - Conversely, even if you're trying to deal with a function, its
+ demangled name might not end with ')': it could be a const or
+ volatile class method, in which case it ends with "const" or
+ "volatile".
+
+ - Parentheses are also used in anonymous namespaces: a variable
+ 'foo' in an anonymous namespace gets demangled as "(anonymous
+ namespace)::foo".
+
+ - And operator names can contain parentheses or angle brackets. */
+
+/* FIXME: carlton/2003-03-13: We have several functions here with
+ overlapping functionality; can we combine them? Also, do they
+ handle all the above considerations correctly? */
+
+/* Find the last component of the demangled C++ name NAME. NAME
+ must be a method name including arguments, in order to correctly
+ locate the last component.
+
+ This function return a pointer to the first colon before the
+ last component, or NULL if the name had only one component. */
+
+static const char *
+find_last_component (const char *name)
+{
+ const char *p;
+ int depth;
+
+ /* Functions can have local classes, so we need to find the
+ beginning of the last argument list, not the end of the first
+ one. */
+ p = name + strlen (name) - 1;
+ while (p > name && *p != ')')
+ p--;
+
+ if (p == name)
+ return NULL;
+
+ /* P now points at the `)' at the end of the argument list. Walk
+ back to the beginning. */
+ p--;
+ depth = 1;
+ while (p > name && depth > 0)
+ {
+ if (*p == '<' || *p == '(')
+ depth--;
+ else if (*p == '>' || *p == ')')
+ depth++;
+ p--;
+ }
+
+ if (p == name)
+ return NULL;
+
+ while (p > name && *p != ':')
+ p--;
+
+ if (p == name || p == name + 1 || p[-1] != ':')
+ return NULL;
+
+ return p - 1;
+}
+
+/* Return the name of the class containing method PHYSNAME. */
+
+char *
+class_name_from_physname (const char *physname)
+{
+ char *ret = NULL;
+ const char *end;
+ int depth = 0;
+ char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS);
+
+ if (demangled_name == NULL)
+ return NULL;
+
+ end = find_last_component (demangled_name);
+ if (end != NULL)
+ {
+ ret = xmalloc (end - demangled_name + 1);
+ memcpy (ret, demangled_name, end - demangled_name);
+ ret[end - demangled_name] = '\0';
+ }
+
+ xfree (demangled_name);
+ return ret;
+}
+
+/* Return the name of the method whose linkage name is PHYSNAME. */
+
+char *
+method_name_from_physname (const char *physname)
+{
+ char *ret = NULL;
+ const char *end;
+ int depth = 0;
+ char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS);
+
+ if (demangled_name == NULL)
+ return NULL;
+
+ end = find_last_component (demangled_name);
+ if (end != NULL)
+ {
+ char *args;
+ int len;
+
+ /* Skip "::". */
+ end = end + 2;
+
+ /* Find the argument list, if any. */
+ args = strchr (end, '(');
+ if (args == NULL)
+ len = strlen (end + 2);
+ else
+ {
+ args --;
+ while (*args == ' ')
+ args --;
+ len = args - end + 1;
+ }
+ ret = xmalloc (len + 1);
+ memcpy (ret, end, len);
+ ret[len] = 0;
+ }
+
+ xfree (demangled_name);
+ return ret;
+}
+
+/* This returns the length of first component of NAME, which should be
+ the demangled name of a C++ variable/function/method/etc.
+ Specifically, it returns the index of the first colon forming the
+ boundary of the first component: so, given 'A::foo' or 'A::B::foo'
+ it returns the 1, and given 'foo', it returns 0. */
+
+/* The character in NAME indexed by the return value is guaranteed to
+ always be either ':' or '\0'. */
+
+/* NOTE: carlton/2003-03-13: This function is currently only intended
+ for internal use: it's probably not entirely safe when called on
+ user-generated input, because some of the 'index += 2' lines in
+ cp_find_first_component_aux might go past the end of malformed
+ input. */
+
+unsigned int
+cp_find_first_component (const char *name)
+{
+ return cp_find_first_component_aux (name, 0);
+}
+
+/* Helper function for cp_find_first_component. Like that function,
+ it returns the length of the first component of NAME, but to make
+ the recursion easier, it also stops if it reaches an unexpected ')'
+ or '>' if the value of PERMISSIVE is nonzero. */
+
+/* Let's optimize away calls to strlen("operator"). */
+
+#define LENGTH_OF_OPERATOR 8
+
+static unsigned int
+cp_find_first_component_aux (const char *name, int permissive)
+{
+ unsigned int index = 0;
+ /* Operator names can show up in unexpected places. Since these can
+ contain parentheses or angle brackets, they can screw up the
+ recursion. But not every string 'operator' is part of an
+ operater name: e.g. you could have a variable 'cooperator'. So
+ this variable tells us whether or not we should treat the string
+ 'operator' as starting an operator. */
+ int operator_possible = 1;
+
+ for (;; ++index)
+ {
+ switch (name[index])
+ {
+ case '<':
+ /* Template; eat it up. The calls to cp_first_component
+ should only return (I hope!) when they reach the '>'
+ terminating the component or a '::' between two
+ components. (Hence the '+ 2'.) */
+ index += 1;
+ for (index += cp_find_first_component_aux (name + index, 1);
+ name[index] != '>';
+ index += cp_find_first_component_aux (name + index, 1))
+ {
+ if (name[index] != ':')
+ {
+ demangled_name_complaint (name);
+ return strlen (name);
+ }
+ index += 2;
+ }
+ operator_possible = 1;
+ break;
+ case '(':
+ /* Similar comment as to '<'. */
+ index += 1;
+ for (index += cp_find_first_component_aux (name + index, 1);
+ name[index] != ')';
+ index += cp_find_first_component_aux (name + index, 1))
+ {
+ if (name[index] != ':')
+ {
+ demangled_name_complaint (name);
+ return strlen (name);
+ }
+ index += 2;
+ }
+ operator_possible = 1;
+ break;
+ case '>':
+ case ')':
+ if (permissive)
+ return index;
+ else
+ {
+ demangled_name_complaint (name);
+ return strlen (name);
+ }
+ case '\0':
+ case ':':
+ return index;
+ case 'o':
+ /* Operator names can screw up the recursion. */
+ if (operator_possible
+ && strncmp (name + index, "operator", LENGTH_OF_OPERATOR) == 0)
+ {
+ index += LENGTH_OF_OPERATOR;
+ while (isspace(name[index]))
+ ++index;
+ switch (name[index])
+ {
+ /* Skip over one less than the appropriate number of
+ characters: the for loop will skip over the last
+ one. */
+ case '<':
+ if (name[index + 1] == '<')
+ index += 1;
+ else
+ index += 0;
+ break;
+ case '>':
+ case '-':
+ if (name[index + 1] == '>')
+ index += 1;
+ else
+ index += 0;
+ break;
+ case '(':
+ index += 1;
+ break;
+ default:
+ index += 0;
+ break;
+ }
+ }
+ operator_possible = 0;
+ break;
+ case ' ':
+ case ',':
+ case '.':
+ case '&':
+ case '*':
+ /* NOTE: carlton/2003-04-18: I'm not sure what the precise
+ set of relevant characters are here: it's necessary to
+ include any character that can show up before 'operator'
+ in a demangled name, and it's safe to include any
+ character that can't be part of an identifier's name. */
+ operator_possible = 1;
+ break;
+ default:
+ operator_possible = 0;
+ break;
+ }
+ }
+}
+
+/* Complain about a demangled name that we don't know how to parse.
+ NAME is the demangled name in question. */
+
+static void
+demangled_name_complaint (const char *name)
+{
+ complaint (&symfile_complaints,
+ "unexpected demangled name '%s'", name);
+}
+
+/* If NAME is the fully-qualified name of a C++
+ function/variable/method/etc., this returns the length of its
+ entire prefix: all of the namespaces and classes that make up its
+ name. Given 'A::foo', it returns 1, given 'A::B::foo', it returns
+ 4, given 'foo', it returns 0. */
+
+unsigned int
+cp_entire_prefix_len (const char *name)
+{
+ unsigned int current_len = cp_find_first_component (name);
+ unsigned int previous_len = 0;
+
+ while (name[current_len] != '\0')
+ {
+ gdb_assert (name[current_len] == ':');
+ previous_len = current_len;
+ /* Skip the '::'. */
+ current_len += 2;
+ current_len += cp_find_first_component (name + current_len);
+ }
+
+ return previous_len;
+}
+
+/* If FULL_NAME is the demangled name of a C++ function (including an
+ arg list, possibly including namespace/class qualifications),
+ return a new string containing only the function name (without the
+ arg list/class qualifications). Otherwise, return NULL. The
+ caller is responsible for freeing the memory in question. */
+
+char *
+cp_func_name (const char *full_name)
+{
+ const char *previous_component = full_name;
+ const char *next_component;
+
+ if (!full_name)
+ return NULL;
+
+ for (next_component = (previous_component
+ + cp_find_first_component (previous_component));
+ *next_component == ':';
+ next_component = (previous_component
+ + cp_find_first_component (previous_component)))
+ {
+ /* Skip '::'. */
+ previous_component = next_component + 2;
+ }
+
+ return remove_params (previous_component);
+}
+
+/* Overload resolution functions. */
+
+static char *
+remove_params (const char *demangled_name)
+{
+ const char *argp;
+ char *new_name;
+ int depth;
+
+ if (demangled_name == NULL)
+ return NULL;
+
+ /* First find the end of the arg list. */
+ argp = strrchr (demangled_name, ')');
+ if (argp == NULL)
+ return NULL;
+
+ /* Back up to the beginning. */
+ depth = 1;
+
+ while (argp-- > demangled_name)
+ {
+ if (*argp == ')')
+ depth ++;
+ else if (*argp == '(')
+ {
+ depth --;
+
+ if (depth == 0)
+ break;
+ }
+ }
+ if (depth != 0)
+ internal_error (__FILE__, __LINE__,
+ "bad demangled name %s\n", demangled_name);
+ while (argp[-1] == ' ' && argp > demangled_name)
+ argp --;
+
+ new_name = xmalloc (argp - demangled_name + 1);
+ memcpy (new_name, demangled_name, argp - demangled_name);
+ new_name[argp - demangled_name] = '\0';
+ return new_name;
+}
+
+/* Test to see if SYM is a symbol that we haven't seen corresponding
+ to a function named OLOAD_NAME. If so, add it to the current
+ completion list. */
+
+static void
+overload_list_add_symbol (struct symbol *sym, const char *oload_name)
+{
+ int newsize;
+ int i;
+ char *sym_name;
+
+ /* If there is no type information, we can't do anything, so skip */
+ if (SYMBOL_TYPE (sym) == NULL)
+ return;
+
+ /* skip any symbols that we've already considered. */
+ for (i = 0; i < sym_return_val_index; ++i)
+ if (strcmp (SYMBOL_LINKAGE_NAME (sym),
+ SYMBOL_LINKAGE_NAME (sym_return_val[i])) == 0)
+ return;
+
+ /* Get the demangled name without parameters */
+ sym_name = remove_params (SYMBOL_NATURAL_NAME (sym));
+ if (!sym_name)
+ return;
+
+ /* skip symbols that cannot match */
+ if (strcmp (sym_name, oload_name) != 0)
+ {
+ xfree (sym_name);
+ return;
+ }
+
+ xfree (sym_name);
+
+ /* We have a match for an overload instance, so add SYM to the current list
+ * of overload instances */
+ if (sym_return_val_index + 3 > sym_return_val_size)
+ {
+ newsize = (sym_return_val_size *= 2) * sizeof (struct symbol *);
+ sym_return_val = (struct symbol **) xrealloc ((char *) sym_return_val, newsize);
+ }
+ sym_return_val[sym_return_val_index++] = sym;
+ sym_return_val[sym_return_val_index] = NULL;
+}
+
+/* Return a null-terminated list of pointers to function symbols that
+ are named FUNC_NAME and are visible within NAMESPACE. */
+
+struct symbol **
+make_symbol_overload_list (const char *func_name,
+ const char *namespace)
+{
+ struct cleanup *old_cleanups;
+
+ sym_return_val_size = 100;
+ sym_return_val_index = 0;
+ sym_return_val = xmalloc ((sym_return_val_size + 1) *
+ sizeof (struct symbol *));
+ sym_return_val[0] = NULL;
+
+ old_cleanups = make_cleanup (xfree, sym_return_val);
+
+ make_symbol_overload_list_using (func_name, namespace);
+
+ discard_cleanups (old_cleanups);
+
+ return sym_return_val;
+}
+
+/* This applies the using directives to add namespaces to search in,
+ and then searches for overloads in all of those namespaces. It
+ adds the symbols found to sym_return_val. Arguments are as in
+ make_symbol_overload_list. */
+
+static void
+make_symbol_overload_list_using (const char *func_name,
+ const char *namespace)
+{
+ const struct using_direct *current;
+
+ /* First, go through the using directives. If any of them apply,
+ look in the appropriate namespaces for new functions to match
+ on. */
+
+ for (current = block_using (get_selected_block (0));
+ current != NULL;
+ current = current->next)
+ {
+ if (strcmp (namespace, current->outer) == 0)
+ {
+ make_symbol_overload_list_using (func_name,
+ current->inner);
+ }
+ }
+
+ /* Now, add names for this namespace. */
+
+ if (namespace[0] == '\0')
+ {
+ make_symbol_overload_list_qualified (func_name);
+ }
+ else
+ {
+ char *concatenated_name
+ = alloca (strlen (namespace) + 2 + strlen (func_name) + 1);
+ strcpy (concatenated_name, namespace);
+ strcat (concatenated_name, "::");
+ strcat (concatenated_name, func_name);
+ make_symbol_overload_list_qualified (concatenated_name);
+ }
+}
+
+/* This does the bulk of the work of finding overloaded symbols.
+ FUNC_NAME is the name of the overloaded function we're looking for
+ (possibly including namespace info). */
+
+static void
+make_symbol_overload_list_qualified (const char *func_name)
+{
+ struct symbol *sym;
+ struct symtab *s;
+ struct objfile *objfile;
+ const struct block *b, *surrounding_static_block = 0;
+ struct dict_iterator iter;
+ const struct dictionary *dict;
+
+ /* Look through the partial symtabs for all symbols which begin
+ by matching FUNC_NAME. Make sure we read that symbol table in. */
+
+ read_in_psymtabs (func_name);
+
+ /* Search upwards from currently selected frame (so that we can
+ complete on local vars. */
+
+ for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
+ {
+ dict = BLOCK_DICT (b);
+
+ for (sym = dict_iter_name_first (dict, func_name, &iter);
+ sym;
+ sym = dict_iter_name_next (func_name, &iter))
+ {
+ overload_list_add_symbol (sym, func_name);
+ }
+ }
+
+ surrounding_static_block = block_static_block (get_selected_block (0));
+
+ /* 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);
+ dict = BLOCK_DICT (b);
+
+ for (sym = dict_iter_name_first (dict, func_name, &iter);
+ sym;
+ sym = dict_iter_name_next (func_name, &iter))
+ {
+ overload_list_add_symbol (sym, func_name);
+ }
+ }
+
+ ALL_SYMTABS (objfile, s)
+ {
+ QUIT;
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ /* Don't do this block twice. */
+ if (b == surrounding_static_block)
+ continue;
+ dict = BLOCK_DICT (b);
+
+ for (sym = dict_iter_name_first (dict, func_name, &iter);
+ sym;
+ sym = dict_iter_name_next (func_name, &iter))
+ {
+ overload_list_add_symbol (sym, func_name);
+ }
+ }
+}
+
+/* Look through the partial symtabs for all symbols which begin
+ by matching FUNC_NAME. Make sure we read that symbol table in. */
+
+static void
+read_in_psymtabs (const char *func_name)
+{
+ struct partial_symtab *ps;
+ struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (ps->readin)
+ continue;
+
+ if ((lookup_partial_symbol (ps, func_name, NULL, 1, VAR_DOMAIN)
+ != NULL)
+ || (lookup_partial_symbol (ps, func_name, NULL, 0, VAR_DOMAIN)
+ != NULL))
+ psymtab_to_symtab (ps);
+ }
+}
+
+/* Lookup the rtti type for a class name. */
+
+struct type *
+cp_lookup_rtti_type (const char *name, struct block *block)
+{
+ struct symbol * rtti_sym;
+ struct type * rtti_type;
+
+ rtti_sym = lookup_symbol (name, block, STRUCT_DOMAIN, NULL, NULL);
+
+ if (rtti_sym == NULL)
+ {
+ warning ("RTTI symbol not found for class '%s'", name);
+ return NULL;
+ }
+
+ if (SYMBOL_CLASS (rtti_sym) != LOC_TYPEDEF)
+ {
+ warning ("RTTI symbol for class '%s' is not a type", name);
+ return NULL;
+ }
+
+ rtti_type = SYMBOL_TYPE (rtti_sym);
+
+ switch (TYPE_CODE (rtti_type))
+ {
+ case TYPE_CODE_CLASS:
+ break;
+ case TYPE_CODE_NAMESPACE:
+ /* chastain/2003-11-26: the symbol tables often contain fake
+ symbols for namespaces with the same name as the struct.
+ This warning is an indication of a bug in the lookup order
+ or a bug in the way that the symbol tables are populated. */
+ warning ("RTTI symbol for class '%s' is a namespace", name);
+ return NULL;
+ default:
+ warning ("RTTI symbol for class '%s' has bad type", name);
+ return NULL;
+ }
+
+ return rtti_type;
+}
+
+/* Don't allow just "maintenance cplus". */
+
+static void
+maint_cplus_command (char *arg, int from_tty)
+{
+ printf_unfiltered ("\"maintenance cplus\" must be followed by the name of a command.\n");
+ help_list (maint_cplus_cmd_list, "maintenance cplus ", -1, gdb_stdout);
+}
+
+/* This is a front end for cp_find_first_component, for unit testing.
+ Be careful when using it: see the NOTE above
+ cp_find_first_component. */
+
+static void
+first_component_command (char *arg, int from_tty)
+{
+ int len = cp_find_first_component (arg);
+ char *prefix = alloca (len + 1);
+
+ memcpy (prefix, arg, len);
+ prefix[len] = '\0';
+
+ printf_unfiltered ("%s\n", prefix);
+}
+
+extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */
+
+void
+_initialize_cp_support (void)
+{
+ add_prefix_cmd ("cplus", class_maintenance, maint_cplus_command,
+ "C++ maintenance commands.", &maint_cplus_cmd_list,
+ "maintenance cplus ", 0, &maintenancelist);
+ add_alias_cmd ("cp", "cplus", class_maintenance, 1, &maintenancelist);
+
+ add_cmd ("first_component", class_maintenance, first_component_command,
+ "Print the first class/namespace component of NAME.",
+ &maint_cplus_cmd_list);
+
+}
diff --git a/contrib/gdb/gdb/cp-support.h b/contrib/gdb/gdb/cp-support.h
new file mode 100644
index 0000000..bbf911a
--- /dev/null
+++ b/contrib/gdb/gdb/cp-support.h
@@ -0,0 +1,120 @@
+/* Helper routines for C++ support in GDB.
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+ Namespace support contributed by David Carlton.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 CP_SUPPORT_H
+#define CP_SUPPORT_H
+
+/* We need this for 'domain_enum', alas... */
+
+#include "symtab.h"
+
+/* Opaque declarations. */
+
+struct symbol;
+struct obstack;
+struct block;
+struct objfile;
+struct type;
+
+/* This struct is designed to store data from using directives. It
+ says that names from namespace INNER should be visible within
+ namespace OUTER. OUTER should always be a strict initial substring
+ of INNER. These form a linked list; NEXT is the next element of
+ the list. */
+
+struct using_direct
+{
+ char *inner;
+ char *outer;
+ struct using_direct *next;
+};
+
+
+/* Functions from cp-support.c. */
+
+extern char *class_name_from_physname (const char *physname);
+
+extern char *method_name_from_physname (const char *physname);
+
+extern unsigned int cp_find_first_component (const char *name);
+
+extern unsigned int cp_entire_prefix_len (const char *name);
+
+extern char *cp_func_name (const char *full_name);
+
+extern struct symbol **make_symbol_overload_list (const char *,
+ const char *);
+
+extern struct type *cp_lookup_rtti_type (const char *name,
+ struct block *block);
+
+/* Functions/variables from cp-namespace.c. */
+
+extern unsigned char processing_has_namespace_info;
+
+extern const char *processing_current_prefix;
+
+extern int cp_is_anonymous (const char *namespace);
+
+extern void cp_add_using_directive (const char *name,
+ unsigned int outer_length,
+ unsigned int inner_length);
+
+extern void cp_initialize_namespace (void);
+
+extern void cp_finalize_namespace (struct block *static_block,
+ struct obstack *obstack);
+
+extern void cp_set_block_scope (const struct symbol *symbol,
+ struct block *block,
+ struct obstack *obstack);
+
+extern void cp_scan_for_anonymous_namespaces (const struct symbol *symbol);
+
+extern struct symbol *cp_lookup_symbol_nonlocal (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+extern struct symbol *cp_lookup_symbol_namespace (const char *namespace,
+ const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+extern struct type *cp_lookup_nested_type (struct type *parent_type,
+ const char *nested_name,
+ const struct block *block);
+
+extern void cp_check_possible_namespace_symbols (const char *name,
+ struct objfile *objfile);
+
+struct type *cp_lookup_transparent_type (const char *name);
+
+/* The list of "maint cplus" commands. */
+
+extern struct cmd_list_element *maint_cplus_cmd_list;
+
+#endif /* CP_SUPPORT_H */
diff --git a/contrib/gdb/gdb/cp-valprint.c b/contrib/gdb/gdb/cp-valprint.c
new file mode 100644
index 0000000..42a48f5
--- /dev/null
+++ b/contrib/gdb/gdb/cp-valprint.c
@@ -0,0 +1,839 @@
+/* Support for printing C++ values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_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"
+#include "target.h"
+#include "cp-abi.h"
+#include "valprint.h"
+
+/* Indication of presence of HP-compiled object files */
+extern int hp_som_som_object_present; /* defined in symtab.c */
+
+
+int vtblprint; /* Controls printing of vtbl's */
+int objectprint; /* Controls looking up an object's derived type
+ using what we find in its vtables. */
+int static_field_print; /* Controls printing of static fields. */
+
+static struct obstack dont_print_vb_obstack;
+static struct obstack dont_print_statmem_obstack;
+
+extern void _initialize_cp_valprint (void);
+
+static void cp_print_static_field (struct type *, struct value *,
+ struct ui_file *, int, int,
+ enum val_prettyprint);
+
+static void cp_print_value (struct type *, struct type *, char *, int,
+ CORE_ADDR, struct ui_file *, int, int,
+ enum val_prettyprint, struct type **);
+
+static void cp_print_hpacc_virtual_table_entries (struct type *, int *,
+ struct value *,
+ struct ui_file *, int,
+ int,
+ enum val_prettyprint);
+
+
+void
+cp_print_class_method (char *valaddr,
+ struct type *type,
+ struct ui_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, "<unknown>");
+ return;
+ }
+ addr = unpack_pointer (type, 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);
+
+ check_stub_method_group (domain, i);
+ for (j = 0; j < len2; j++)
+ {
+ if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
+ {
+ kind = "virtual ";
+ goto common;
+ }
+ }
+ }
+ }
+ else
+ {
+ sym = find_pc_function (addr);
+ if (sym == 0)
+ {
+ /* 1997-08-01 Currently unsupported with HP aCC */
+ if (hp_som_som_object_present)
+ {
+ fputs_filtered ("?? <not supported with HP aCC>", stream);
+ return;
+ }
+ 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);
+
+ check_stub_method_group (domain, i);
+ for (j = 0; j < len2; j++)
+ {
+ if (strcmp (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))
+ == 0)
+ goto common;
+ }
+ }
+ }
+ common:
+ if (i < len)
+ {
+ char *demangled_name;
+
+ fprintf_filtered (stream, "&");
+ fputs_filtered (kind, stream);
+ demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name == NULL)
+ fprintf_filtered (stream, "<badly mangled name %s>",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+ else
+ {
+ fputs_filtered (demangled_name, stream);
+ xfree (demangled_name);
+ }
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") %d", (int) addr >> 3);
+ }
+}
+
+/* GCC versions after 2.4.5 use this. */
+const char vtbl_ptr_name[] = "__vtbl_ptr_type";
+
+/* HP aCC uses different names. */
+const char hpacc_vtbl_ptr_name[] = "__vfp";
+const char hpacc_vtbl_ptr_type_name[] = "__vftyp";
+
+/* Return truth value for assertion that TYPE is of the type
+ "pointer to virtual function". */
+
+int
+cp_is_vtbl_ptr_type (struct type *type)
+{
+ char *typename = type_name_no_tag (type);
+
+ return (typename != NULL && !strcmp (typename, vtbl_ptr_name));
+}
+
+/* Return truth value for the assertion that TYPE is of the type
+ "pointer to virtual function table". */
+
+int
+cp_is_vtbl_member (struct type *type)
+{
+ /* With older versions of g++, the vtbl field pointed to an array
+ of structures. Nowadays it points directly to the structure. */
+ 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);
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT) /* if not using thunks */
+ {
+ return cp_is_vtbl_ptr_type (type);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_PTR) /* if using thunks */
+ {
+ /* The type name of the thunk pointer is NULL when using dwarf2.
+ We could test for a pointer to a function, but there is
+ no type info for the virtual table either, so it wont help. */
+ 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.
+
+ 2nd argument REAL_TYPE is used to carry over the type of the derived
+ class across the recursion to base classes.
+
+ 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 (struct type *type, struct type *real_type, char *valaddr,
+ int offset, CORE_ADDR address, struct ui_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);
+ int fields_seen = 0;
+
+ CHECK_TYPEDEF (type);
+
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ /* First, print out baseclasses such that we don't print
+ duplicates of virtual baseclasses. */
+
+ if (n_baseclasses > 0)
+ cp_print_value (type, real_type, valaddr, offset, address, stream,
+ format, recurse + 1, pretty, dont_print_vb);
+
+ /* Second, print out data fields */
+
+ /* If there are no data fields, or if the only field is the
+ * vtbl pointer, skip this part */
+ if ((len == n_baseclasses)
+ || ((len - n_baseclasses == 1)
+ && TYPE_HAS_VTABLE (type)
+ && strncmp (TYPE_FIELD_NAME (type, n_baseclasses),
+ hpacc_vtbl_ptr_name, 5) == 0)
+ || !len)
+ fprintf_filtered (stream, "<No data fields>");
+ else
+ {
+ 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 a vtable pointer appears, we'll print it out later */
+ if (TYPE_HAS_VTABLE (type)
+ && strncmp (TYPE_FIELD_NAME (type, i), hpacc_vtbl_ptr_name,
+ 5) == 0)
+ 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 ();
+ /* do not print leading '=' in case of anonymous unions */
+ if (strcmp (TYPE_FIELD_NAME (type, i), ""))
+ fputs_filtered (" = ", stream);
+ annotate_field_value ();
+ }
+
+ if (!TYPE_FIELD_STATIC (type, i) && TYPE_FIELD_PACKED (type, i))
+ {
+ struct value *v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", stream);
+ }
+ else
+ {
+ v = value_from_longest
+ (TYPE_FIELD_TYPE (type, i),
+ unpack_field_as_long (type, valaddr + offset, i));
+
+ val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v),
+ 0, 0, stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ else
+ {
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", stream);
+ }
+ else if (TYPE_FIELD_STATIC (type, i))
+ {
+ struct value *v = value_static_field (type, i);
+ if (v == NULL)
+ fputs_filtered ("<optimized out>", stream);
+ else
+ cp_print_static_field (TYPE_FIELD_TYPE (type, i), v,
+ stream, format, recurse + 1,
+ pretty);
+ }
+ else
+ {
+ val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr, offset + TYPE_FIELD_BITPOS (type, i) / 8,
+ address + TYPE_FIELD_BITPOS (type, i) / 8,
+ 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);
+ }
+ } /* if there are data fields */
+ /* Now print out the virtual table pointer if there is one */
+ if (TYPE_HAS_VTABLE (type)
+ && strncmp (TYPE_FIELD_NAME (type, n_baseclasses),
+ hpacc_vtbl_ptr_name, 5) == 0)
+ {
+ struct value *v;
+ /* First get the virtual table pointer and print it out */
+
+#if 0
+ fputs_filtered ("__vfp = ", stream);
+#endif
+
+ fputs_filtered (", Virtual table at ", stream);
+
+ /* pai: FIXME 32x64 problem? */
+ /* Not sure what the best notation is in the case where there is no
+ baseclass name. */
+ v = value_from_pointer (lookup_pointer_type (builtin_type_unsigned_long),
+ *(unsigned long *) (valaddr + offset));
+
+ val_print (VALUE_TYPE (v), VALUE_CONTENTS (v), 0, 0,
+ stream, format, 0, recurse + 1, pretty);
+ fields_seen = 1;
+
+ if (vtblprint)
+ {
+ /* Print out function pointers in vtable. */
+
+ /* FIXME: then-clause is for non-RRBC layout of virtual
+ * table. The RRBC case in the else-clause is yet to be
+ * implemented. The if (1) below should be changed to a
+ * test for whether the executable we have was compiled
+ * with a version of HP aCC that doesn't have RRBC
+ * support. */
+
+ if (1)
+ {
+ /* no RRBC support; function pointers embedded directly
+ in vtable */
+
+ int vfuncs = count_virtual_fns (real_type);
+
+ fputs_filtered (" {", stream);
+
+ /* FIXME : doesn't work at present */
+#if 0
+ fprintf_filtered (stream, "%d entr%s: ", vfuncs,
+ vfuncs == 1 ? "y" : "ies");
+#else
+ fputs_filtered ("not implemented", stream);
+
+
+#endif
+
+ /* recursive function that prints all virtual function entries */
+#if 0
+ cp_print_hpacc_virtual_table_entries (real_type, &vfuncs, v,
+ stream, format, recurse,
+ pretty);
+#endif
+ fputs_filtered ("}", stream);
+ } /* non-RRBC case */
+ else
+ {
+ /* FIXME -- see comments above */
+ /* RRBC support present; function pointers are found
+ * by indirection through the class segment entries. */
+
+
+ } /* RRBC case */
+ } /* if vtblprint */
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+
+ } /* if vtable exists */
+
+ fprintf_filtered (stream, "}");
+}
+
+/* Special val_print routine to avoid printing multiple copies of virtual
+ baseclasses. */
+
+static void
+cp_print_value (struct type *type, struct type *real_type, char *valaddr,
+ int offset, CORE_ADDR address, struct ui_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);
+ int thisoffset;
+ struct type *thistype;
+
+ 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;
+ int skip;
+ struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
+ char *basename = TYPE_NAME (baseclass);
+ char *base_valaddr;
+
+ 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);
+ }
+
+ thisoffset = offset;
+ thistype = real_type;
+ if (TYPE_HAS_VTABLE (type) && BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ /* Assume HP/Taligent runtime convention */
+ find_rt_vbase_offset (type, TYPE_BASECLASS (type, i),
+ valaddr, offset, &boffset, &skip);
+ if (skip >= 0)
+ error ("Virtual base class offset not found from vtable while"
+ " printing");
+ base_valaddr = valaddr;
+ }
+ else
+ {
+ boffset = baseclass_offset (type, i,
+ valaddr + offset,
+ address);
+ skip = ((boffset == -1) || (boffset + offset) < 0) ? 1 : -1;
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ /* The virtual base class pointer might have been
+ clobbered by the user program. Make sure that it
+ still points to a valid memory location. */
+
+ if (boffset != -1
+ && ((boffset + offset) < 0
+ || (boffset + offset) >= TYPE_LENGTH (type)))
+ {
+ /* FIXME (alloca): unsafe if baseclass is really really large. */
+ base_valaddr = (char *) alloca (TYPE_LENGTH (baseclass));
+ if (target_read_memory (address + boffset, base_valaddr,
+ TYPE_LENGTH (baseclass)) != 0)
+ skip = 1;
+ address = address + boffset;
+ thisoffset = 0;
+ boffset = 0;
+ thistype = baseclass;
+ }
+ else
+ base_valaddr = valaddr;
+ }
+ else
+ base_valaddr = valaddr;
+ }
+
+ /* now do the printing */
+ 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 (skip >= 1)
+ fprintf_filtered (stream, "<invalid address>");
+ else
+ cp_print_value_fields (baseclass, thistype, base_valaddr,
+ thisoffset + 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 (struct type *type,
+ struct value *val,
+ struct ui_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 ("<same as static member of an already"
+ " seen type>",
+ stream);
+ return;
+ }
+ }
+
+ obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val),
+ sizeof (CORE_ADDR));
+
+ CHECK_TYPEDEF (type);
+ cp_print_value_fields (type, type, VALUE_CONTENTS_ALL (val),
+ VALUE_EMBEDDED_OFFSET (val), VALUE_ADDRESS (val),
+ stream, format, recurse, pretty, NULL, 1);
+ return;
+ }
+ val_print (type, VALUE_CONTENTS_ALL (val),
+ VALUE_EMBEDDED_OFFSET (val), VALUE_ADDRESS (val),
+ stream, format, 0, recurse, pretty);
+}
+
+void
+cp_print_class_member (char *valaddr, struct type *domain,
+ struct ui_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;
+ unsigned int i;
+ unsigned len = TYPE_NFIELDS (domain);
+
+ /* @@ Make VAL into bit offset */
+
+ /* Note: HP aCC generates offsets that are the real byte offsets added
+ to a constant bias 0x20000000 (1 << 29). This constant bias gets
+ shifted out in the code below -- joyous happenstance! */
+
+ /* Note: HP cfront uses a constant bias of 1; if we support this
+ compiler ever, we will have to adjust the computation below */
+
+ 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;
+ fputs_filtered (prefix, stream);
+ name = type_name_no_tag (domain);
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ c_type_print_base (domain, stream, 0, 0);
+ 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, "%ld", (long) (val >> 3));
+}
+
+
+/* This function prints out virtual table entries for a class; it
+ * recurses on the base classes to find all virtual functions
+ * available in a class.
+ *
+ * pai/1997-05-21 Note: As the name suggests, it's currently
+ * implemented for HP aCC runtime only. g++ objects are handled
+ * differently and I have made no attempt to fold that logic in
+ * here. The runtime layout is different for the two cases. Also,
+ * this currently has only the code for non-RRBC layouts generated by
+ * the HP aCC compiler; RRBC code is stubbed out and will have to be
+ * added later. */
+
+
+static void
+cp_print_hpacc_virtual_table_entries (struct type *type, int *vfuncs,
+ struct value *v, struct ui_file *stream,
+ int format, int recurse,
+ enum val_prettyprint pretty)
+{
+ int fn, oi;
+
+ /* pai: FIXME this function doesn't work. It should handle a given
+ * virtual function only once (latest redefinition in class hierarchy)
+ */
+
+ /* Recursion on other classes that can share the same vtable */
+ struct type *pbc = primary_base_class (type);
+ if (pbc)
+ cp_print_hpacc_virtual_table_entries (pbc, vfuncs, v, stream, format,
+ recurse, pretty);
+
+ /* Now deal with vfuncs declared in this class */
+ for (fn = 0; fn < TYPE_NFN_FIELDS (type); fn++)
+ for (oi = 0; oi < TYPE_FN_FIELDLIST_LENGTH (type, fn); oi++)
+ if (TYPE_FN_FIELD_VIRTUAL_P (TYPE_FN_FIELDLIST1 (type, fn), oi))
+ {
+ char *vf_name;
+ const char *field_physname;
+
+ /* virtual function offset */
+ int vx = (TYPE_FN_FIELD_VOFFSET (TYPE_FN_FIELDLIST1 (type, fn), oi)
+ - 1);
+
+ /* Get the address of the vfunction entry */
+ struct value *vf = value_copy (v);
+ if (VALUE_LAZY (vf))
+ (void) value_fetch_lazy (vf);
+ /* adjust by offset */
+ vf->aligner.contents[0] += 4 * (HP_ACC_VFUNC_START + vx);
+ vf = value_ind (vf); /* get the entry */
+ VALUE_TYPE (vf) = VALUE_TYPE (v); /* make it a pointer */
+
+ /* print out the entry */
+ val_print (VALUE_TYPE (vf), VALUE_CONTENTS (vf), 0, 0,
+ stream, format, 0, recurse + 1, pretty);
+ field_physname
+ = TYPE_FN_FIELD_PHYSNAME (TYPE_FN_FIELDLIST1 (type, fn), oi);
+ /* pai: (temp) FIXME Maybe this should be DMGL_ANSI */
+ vf_name = cplus_demangle (field_physname, DMGL_ARM);
+ fprintf_filtered (stream, " %s", vf_name);
+ if (--(*vfuncs) > 0)
+ fputs_filtered (", ", stream);
+ }
+}
+
+
+
+void
+_initialize_cp_valprint (void)
+{
+ 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, xfree);
+}
diff --git a/contrib/gdb/gdb/cpu32bug-rom.c b/contrib/gdb/gdb/cpu32bug-rom.c
new file mode 100644
index 0000000..03b3132
--- /dev/null
+++ b/contrib/gdb/gdb/cpu32bug-rom.c
@@ -0,0 +1,180 @@
+/* Remote debugging interface for CPU32Bug Rom monitor for GDB, the GNU debugger.
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001
+ 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"
+#include "regcache.h"
+
+#include "m68k-tdep.h"
+
+static void cpu32bug_open (char *args, int from_tty);
+
+static void
+cpu32bug_supply_register (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' + M68K_D0_REGNUM;
+ break;
+ case 'A':
+ if (regname[1] < '0' || regname[1] > '7')
+ return;
+ regno = regname[1] - '0' + M68K_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 const char *
+cpu32bug_regname (int index)
+{
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "SR", "PC"
+ };
+
+ if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+}
+
+/*
+ * 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;
+
+static void
+init_cpu32bug_cmds (void)
+{
+ cpu32bug_cmds.flags = MO_CLR_BREAK_USES_ADDR;
+ cpu32bug_cmds.init = cpu32bug_inits; /* Init strings */
+ cpu32bug_cmds.cont = "g\r"; /* continue command */
+ cpu32bug_cmds.step = "t\r"; /* single step */
+ cpu32bug_cmds.stop = NULL; /* interrupt command */
+ cpu32bug_cmds.set_break = "br %x\r"; /* set a breakpoint */
+ cpu32bug_cmds.clr_break = "nobr %x\r"; /* clear a breakpoint */
+ cpu32bug_cmds.clr_all_break = "nobr\r"; /* clear all breakpoints */
+ cpu32bug_cmds.fill = "bf %x:%x %x;b\r"; /* fill (start count val) */
+ cpu32bug_cmds.setmem.cmdb = "ms %x %02x\r"; /* setmem.cmdb (addr, value) */
+ cpu32bug_cmds.setmem.cmdw = "ms %x %04x\r"; /* setmem.cmdw (addr, value) */
+ cpu32bug_cmds.setmem.cmdl = "ms %x %08x\r"; /* setmem.cmdl (addr, value) */
+ cpu32bug_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ cpu32bug_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ cpu32bug_cmds.setmem.term = NULL; /* setreg.term */
+ cpu32bug_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ cpu32bug_cmds.getmem.cmdb = "md %x:%x;b\r"; /* getmem.cmdb (addr, len) */
+ cpu32bug_cmds.getmem.cmdw = "md %x:%x;b\r"; /* getmem.cmdw (addr, len) */
+ cpu32bug_cmds.getmem.cmdl = "md %x:%x;b\r"; /* getmem.cmdl (addr, len) */
+ cpu32bug_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
+ cpu32bug_cmds.getmem.resp_delim = " "; /* getmem.resp_delim */
+ cpu32bug_cmds.getmem.term = NULL; /* getmem.term */
+ cpu32bug_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
+ cpu32bug_cmds.setreg.cmd = "rs %s %x\r"; /* setreg.cmd (name, value) */
+ cpu32bug_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ cpu32bug_cmds.setreg.term = NULL; /* setreg.term */
+ cpu32bug_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ cpu32bug_cmds.getreg.cmd = "rs %s\r"; /* getreg.cmd (name) */
+ cpu32bug_cmds.getreg.resp_delim = "="; /* getreg.resp_delim */
+ cpu32bug_cmds.getreg.term = NULL; /* getreg.term */
+ cpu32bug_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
+ cpu32bug_cmds.dump_registers = "rd\r"; /* dump_registers */
+ cpu32bug_cmds.register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
+ cpu32bug_cmds.supply_register = cpu32bug_supply_register; /* supply_register */
+ cpu32bug_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ cpu32bug_cmds.load = "lo\r"; /* download command */
+ cpu32bug_cmds.loadresp = "\n"; /* load response */
+ cpu32bug_cmds.prompt = "CPU32Bug>"; /* monitor command prompt */
+ cpu32bug_cmds.line_term = "\r"; /* end-of-line terminator */
+ cpu32bug_cmds.cmd_end = NULL; /* optional command terminator */
+ cpu32bug_cmds.target = &cpu32bug_ops; /* target operations */
+ cpu32bug_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ cpu32bug_cmds.regnames = NULL; /* registers names */
+ cpu32bug_cmds.regname = cpu32bug_regname;
+ cpu32bug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+}; /* init_cpu32bug_cmds */
+
+static void
+cpu32bug_open (char *args, int from_tty)
+{
+ monitor_open (args, &cpu32bug_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_cpu32bug_rom; /* -Wmissing-prototypes */
+
+void
+_initialize_cpu32bug_rom (void)
+{
+ init_cpu32bug_cmds ();
+ 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/dbug-rom.c b/contrib/gdb/gdb/dbug-rom.c
new file mode 100644
index 0000000..a592334
--- /dev/null
+++ b/contrib/gdb/gdb/dbug-rom.c
@@ -0,0 +1,178 @@
+/* Remote debugging interface to dBUG ROM monitor for GDB, the GNU debugger.
+ Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ Written by Stan Shebs 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. */
+
+/* dBUG is a monitor supplied on various Motorola boards, including
+ m68k, ColdFire, and PowerPC-based designs. The code here assumes
+ the ColdFire, and (as of 9/25/96) has only been tested with a
+ ColdFire IDP board. */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "monitor.h"
+#include "serial.h"
+#include "regcache.h"
+
+#include "m68k-tdep.h"
+
+static void dbug_open (char *args, int from_tty);
+
+static void
+dbug_supply_register (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' + M68K_D0_REGNUM;
+ break;
+ case 'A':
+ if (regname[1] < '0' || regname[1] > '7')
+ return;
+ regno = regname[1] - '0' + M68K_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 const char *
+dbug_regname (int index)
+{
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "SR", "PC"
+ /* no float registers */
+ };
+
+ if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+
+}
+
+static struct target_ops dbug_ops;
+static struct monitor_ops dbug_cmds;
+
+static char *dbug_inits[] =
+{"\r", NULL};
+
+
+static void
+init_dbug_cmds (void)
+{
+ dbug_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_GETMEM_NEEDS_RANGE | MO_FILL_USES_ADDR;
+ dbug_cmds.init = dbug_inits; /* Init strings */
+ dbug_cmds.cont = "go\r"; /* continue command */
+ dbug_cmds.step = "trace\r"; /* single step */
+ dbug_cmds.stop = NULL; /* interrupt command */
+ dbug_cmds.set_break = "br %x\r"; /* set a breakpoint */
+ dbug_cmds.clr_break = "br -r %x\r"; /* clear a breakpoint */
+ dbug_cmds.clr_all_break = "br -r\r"; /* clear all breakpoints */
+ dbug_cmds.fill = "bf.b %x %x %x\r"; /* fill (start end val) */
+ dbug_cmds.setmem.cmdb = "mm.b %x %x\r"; /* setmem.cmdb (addr, value) */
+ dbug_cmds.setmem.cmdw = "mm.w %x %x\r"; /* setmem.cmdw (addr, value) */
+ dbug_cmds.setmem.cmdl = "mm.l %x %x\r"; /* setmem.cmdl (addr, value) */
+ dbug_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ dbug_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */
+ dbug_cmds.setmem.term = NULL; /* setmem.term */
+ dbug_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */
+ dbug_cmds.getmem.cmdb = "md.b %x %x\r"; /* getmem.cmdb (addr, addr2) */
+ dbug_cmds.getmem.cmdw = "md.w %x %x\r"; /* getmem.cmdw (addr, addr2) */
+ dbug_cmds.getmem.cmdl = "md.l %x %x\r"; /* getmem.cmdl (addr, addr2) */
+ dbug_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, addr2) */
+ dbug_cmds.getmem.resp_delim = ":"; /* getmem.resp_delim */
+ dbug_cmds.getmem.term = NULL; /* getmem.term */
+ dbug_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
+ dbug_cmds.setreg.cmd = "rm %s %x\r"; /* setreg.cmd (name, value) */
+ dbug_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ dbug_cmds.setreg.term = NULL; /* setreg.term */
+ dbug_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ dbug_cmds.getreg.cmd = "rd %s\r"; /* getreg.cmd (name) */
+ dbug_cmds.getreg.resp_delim = ":"; /* getreg.resp_delim */
+ dbug_cmds.getreg.term = NULL; /* getreg.term */
+ dbug_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
+ dbug_cmds.dump_registers = "rd\r"; /* dump_registers */
+ dbug_cmds.register_pattern = "\\(\\w+\\) +:\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
+ dbug_cmds.supply_register = dbug_supply_register; /* supply_register */
+ dbug_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ dbug_cmds.load = "dl\r"; /* download command */
+ dbug_cmds.loadresp = "\n"; /* load response */
+ dbug_cmds.prompt = "dBUG>"; /* monitor command prompt */
+ dbug_cmds.line_term = "\r"; /* end-of-line terminator */
+ dbug_cmds.cmd_end = NULL; /* optional command terminator */
+ dbug_cmds.target = &dbug_ops; /* target operations */
+ dbug_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ dbug_cmds.regnames = NULL; /* registers names */
+ dbug_cmds.regname = dbug_regname;
+ dbug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+} /* init_debug_ops */
+
+static void
+dbug_open (char *args, int from_tty)
+{
+ monitor_open (args, &dbug_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_dbug_rom; /* -Wmissing-prototypes */
+
+void
+_initialize_dbug_rom (void)
+{
+ init_dbug_cmds ();
+ init_monitor_ops (&dbug_ops);
+
+ dbug_ops.to_shortname = "dbug";
+ dbug_ops.to_longname = "dBUG monitor";
+ dbug_ops.to_doc = "Debug via the dBUG monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ dbug_ops.to_open = dbug_open;
+
+ add_target (&dbug_ops);
+}
diff --git a/contrib/gdb/gdb/dbxread.c b/contrib/gdb/gdb/dbxread.c
new file mode 100644
index 0000000..efbbf2a
--- /dev/null
+++ b/contrib/gdb/gdb/dbxread.c
@@ -0,0 +1,3577 @@
+/* Read dbx symbol tables and convert to internal format, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004.
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include "gdb_obstack.h"
+#include "gdb_stat.h"
+#include "symtab.h"
+#include "breakpoint.h"
+#include "target.h"
+#include "gdbcore.h" /* for bfd stuff */
+#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "demangle.h"
+#include "language.h" /* Needed for local_hex_string */
+#include "complaints.h"
+#include "cp-abi.h"
+#include "gdb_assert.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)
+
+
+/* Remember what we deduced to be the source language of this psymtab. */
+
+static enum language psymtab_language = language_unknown;
+
+/* 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;
+
+/* Non-zero if there is any line number info in the objfile. Prevents
+ end_psymtab from discarding an otherwise empty psymtab. */
+
+static int has_line_numbers;
+
+/* Complaints about the symbols we have encountered. */
+
+static void
+unknown_symtype_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints, "unknown symbol type %s", arg1);
+}
+
+static void
+lbrac_mismatch_complaint (int arg1)
+{
+ complaint (&symfile_complaints,
+ "N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", arg1);
+}
+
+static void
+repeated_header_complaint (const char *arg1, int arg2)
+{
+ complaint (&symfile_complaints,
+ "\"repeated\" header file %s not previously seen, at symtab pos %d",
+ arg1, arg2);
+}
+
+/* find_text_range --- find start and end of loadable code sections
+
+ The find_text_range function finds the shortest address range that
+ encloses all sections containing executable code, and stores it in
+ objfile's text_addr and text_size members.
+
+ dbx_symfile_read will use this to finish off the partial symbol
+ table, in some cases. */
+
+static void
+find_text_range (bfd * sym_bfd, struct objfile *objfile)
+{
+ asection *sec;
+ int found_any = 0;
+ CORE_ADDR start = 0;
+ CORE_ADDR end = 0;
+
+ for (sec = sym_bfd->sections; sec; sec = sec->next)
+ if (bfd_get_section_flags (sym_bfd, sec) & SEC_CODE)
+ {
+ CORE_ADDR sec_start = bfd_section_vma (sym_bfd, sec);
+ CORE_ADDR sec_end = sec_start + bfd_section_size (sym_bfd, sec);
+
+ if (found_any)
+ {
+ if (sec_start < start)
+ start = sec_start;
+ if (sec_end > end)
+ end = sec_end;
+ }
+ else
+ {
+ start = sec_start;
+ end = sec_end;
+ }
+
+ found_any = 1;
+ }
+
+ if (!found_any)
+ error ("Can't find any code sections in symbol file");
+
+ DBX_TEXT_ADDR (objfile) = start;
+ DBX_TEXT_SIZE (objfile) = end - start;
+}
+
+
+
+/* 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 */
+
+extern void _initialize_dbxread (void);
+
+static void read_ofile_symtab (struct partial_symtab *);
+
+static void dbx_psymtab_to_symtab (struct partial_symtab *);
+
+static void dbx_psymtab_to_symtab_1 (struct partial_symtab *);
+
+static void read_dbx_dynamic_symtab (struct objfile *objfile);
+
+static void read_dbx_symtab (struct objfile *);
+
+static void free_bincl_list (struct objfile *);
+
+static struct partial_symtab *find_corresponding_bincl_psymtab (char *, int);
+
+static void add_bincl_to_list (struct partial_symtab *, char *, int);
+
+static void init_bincl_list (int, struct objfile *);
+
+static char *dbx_next_symbol_text (struct objfile *);
+
+static void fill_symbuf (bfd *);
+
+static void dbx_symfile_init (struct objfile *);
+
+static void dbx_new_init (struct objfile *);
+
+static void dbx_symfile_read (struct objfile *, int);
+
+static void dbx_symfile_finish (struct objfile *);
+
+static void record_minimal_symbol (char *, CORE_ADDR, int, struct objfile *);
+
+static void add_new_header_file (char *, int);
+
+static void add_old_header_file (char *, int);
+
+static void add_this_object_header_file (int);
+
+static struct partial_symtab *start_psymtab (struct objfile *, char *,
+ CORE_ADDR, int,
+ struct partial_symbol **,
+ struct partial_symbol **);
+
+/* Free up old header file tables */
+
+void
+free_header_files (void)
+{
+ if (this_object_header_files)
+ {
+ xfree (this_object_header_files);
+ this_object_header_files = NULL;
+ }
+ n_allocated_this_object_header_files = 0;
+}
+
+/* Allocate new header file tables */
+
+void
+init_header_files (void)
+{
+ 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 (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 (char *name, int instance)
+{
+ struct header_file *p = HEADER_FILES (current_objfile);
+ int i;
+
+ for (i = 0; i < N_HEADER_FILES (current_objfile); i++)
+ if (strcmp (p[i].name, name) == 0 && instance == p[i].instance)
+ {
+ add_this_object_header_file (i);
+ return;
+ }
+ 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 (char *name, int instance)
+{
+ int i;
+ struct header_file *hfile;
+
+ /* Make sure there is room for one more header file. */
+
+ i = N_ALLOCATED_HEADER_FILES (current_objfile);
+
+ if (N_HEADER_FILES (current_objfile) == i)
+ {
+ if (i == 0)
+ {
+ N_ALLOCATED_HEADER_FILES (current_objfile) = 10;
+ HEADER_FILES (current_objfile) = (struct header_file *)
+ xmalloc (10 * sizeof (struct header_file));
+ }
+ else
+ {
+ i *= 2;
+ N_ALLOCATED_HEADER_FILES (current_objfile) = i;
+ HEADER_FILES (current_objfile) = (struct header_file *)
+ xrealloc ((char *) HEADER_FILES (current_objfile),
+ (i * sizeof (struct header_file)));
+ }
+ }
+
+ /* Create an entry for this header file. */
+
+ i = N_HEADER_FILES (current_objfile)++;
+ hfile = HEADER_FILES (current_objfile) + i;
+ hfile->name = savestring (name, strlen (name));
+ hfile->instance = instance;
+ hfile->length = 10;
+ hfile->vector
+ = (struct type **) xmalloc (10 * sizeof (struct type *));
+ memset (hfile->vector, 0, 10 * sizeof (struct type *));
+
+ add_this_object_header_file (i);
+}
+
+#if 0
+static struct type **
+explicit_lookup_type (int real_filenum, int index)
+{
+ struct header_file *f = &HEADER_FILES (current_objfile)[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 (char *name, CORE_ADDR address, int type,
+ struct objfile *objfile)
+{
+ enum minimal_symbol_type ms_type;
+ int section;
+ asection *bfd_section;
+
+ switch (type)
+ {
+ case N_TEXT | N_EXT:
+ ms_type = mst_text;
+ section = SECT_OFF_TEXT (objfile);
+ bfd_section = DBX_TEXT_SECTION (objfile);
+ break;
+ case N_DATA | N_EXT:
+ ms_type = mst_data;
+ section = SECT_OFF_DATA (objfile);
+ bfd_section = DBX_DATA_SECTION (objfile);
+ break;
+ case N_BSS | N_EXT:
+ ms_type = mst_bss;
+ section = SECT_OFF_BSS (objfile);
+ bfd_section = DBX_BSS_SECTION (objfile);
+ break;
+ case N_ABS | N_EXT:
+ ms_type = mst_abs;
+ section = -1;
+ bfd_section = NULL;
+ break;
+#ifdef N_SETV
+ case N_SETV | N_EXT:
+ ms_type = mst_data;
+ section = SECT_OFF_DATA (objfile);
+ bfd_section = DBX_DATA_SECTION (objfile);
+ 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 (objfile);
+ bfd_section = DBX_DATA_SECTION (objfile);
+ break;
+#endif
+ case N_TEXT:
+ case N_NBTEXT:
+ case N_FN:
+ case N_FN_SEQ:
+ ms_type = mst_file_text;
+ section = SECT_OFF_TEXT (objfile);
+ bfd_section = DBX_TEXT_SECTION (objfile);
+ 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' && DEPRECATED_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 (is_vtable_name (tempstring))
+ ms_type = mst_data;
+ }
+ section = SECT_OFF_DATA (objfile);
+ bfd_section = DBX_DATA_SECTION (objfile);
+ break;
+ case N_BSS:
+ ms_type = mst_file_bss;
+ section = SECT_OFF_BSS (objfile);
+ bfd_section = DBX_BSS_SECTION (objfile);
+ break;
+ default:
+ ms_type = mst_unknown;
+ section = -1;
+ bfd_section = NULL;
+ 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
+ (name, address, ms_type, NULL, section, bfd_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.
+
+ 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 (struct objfile *objfile, int mainline)
+{
+ bfd *sym_bfd;
+ int val;
+ struct cleanup *back_to;
+
+ sym_bfd = objfile->obfd;
+
+ /* .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. */
+
+ symfile_relocatable = bfd_get_file_flags (sym_bfd) & HAS_RELOC;
+
+ /* 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 (sym_bfd), "elf", 3))
+ || (0 == strncmp (bfd_get_target (sym_bfd), "som", 3))
+ || (0 == strncmp (bfd_get_target (sym_bfd), "coff", 4))
+ || (0 == strncmp (bfd_get_target (sym_bfd), "pe", 2))
+ || (0 == strncmp (bfd_get_target (sym_bfd), "epoc-pe", 7))
+ || (0 == strncmp (bfd_get_target (sym_bfd), "nlm", 3)));
+
+ val = bfd_seek (sym_bfd, 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);
+
+ free_pending_blocks ();
+ back_to = make_cleanup (really_free_pendings, 0);
+
+ init_minimal_symbol_collection ();
+ make_cleanup_discard_minimal_symbols ();
+
+ /* Read stabs data from executable file and define symbols. */
+
+ read_dbx_symtab (objfile);
+
+ /* Add the dynamic symbols. */
+
+ read_dbx_dynamic_symtab (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 (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 (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 = (struct dbx_symfile_info *)
+ xmmalloc (objfile->md, sizeof (struct dbx_symfile_info));
+ memset (objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info));
+
+ DBX_TEXT_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ DBX_DATA_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".data");
+ DBX_BSS_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".bss");
+
+ /* 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 objfile_obstack.
+ When we blow away the objfile 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 objfile_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 (size_temp, 0, sizeof (size_temp));
+ val = bfd_bread (size_temp, sizeof (size_temp), 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->objfile_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_bread (DBX_STRINGTAB (objfile),
+ DBX_STRINGTAB_SIZE (objfile),
+ 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 (struct objfile *objfile)
+{
+ if (objfile->sym_stab_info != NULL)
+ {
+ if (HEADER_FILES (objfile) != NULL)
+ {
+ int i = N_HEADER_FILES (objfile);
+ struct header_file *hfiles = HEADER_FILES (objfile);
+
+ while (--i >= 0)
+ {
+ xfree (hfiles[i].name);
+ xfree (hfiles[i].vector);
+ }
+ xfree (hfiles);
+ }
+ xmfree (objfile->md, objfile->sym_stab_info);
+ }
+ free_header_files ();
+}
+
+
+/* Buffer for reading the symbol table entries. */
+static struct external_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;
+
+/* This variable stores a global stabs buffer, if we read stabs into
+ memory in one chunk in order to process relocations. */
+static bfd_byte *stabs_data;
+
+/* 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 (bfd *sym_bfd)
+{
+ unsigned int count;
+ int nbytes;
+
+ if (stabs_data)
+ {
+ nbytes = sizeof (symbuf);
+ if (nbytes > symbuf_left)
+ nbytes = symbuf_left;
+ memcpy (symbuf, stabs_data + symbuf_read, nbytes);
+ }
+ else if (symbuf_sections == NULL)
+ {
+ count = sizeof (symbuf);
+ nbytes = bfd_bread (symbuf, count, sym_bfd);
+ }
+ 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_bread (symbuf, count, 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;
+}
+
+static void
+stabs_seek (int sym_offset)
+{
+ if (stabs_data)
+ {
+ symbuf_read += sym_offset;
+ symbuf_left -= sym_offset;
+ }
+ else
+ bfd_seek (symfile_bfd, sym_offset, SEEK_CUR);
+}
+
+#define INTERNALIZE_SYMBOL(intern, extern, abfd) \
+ { \
+ (intern).n_type = bfd_h_get_8 (abfd, (extern)->e_type); \
+ (intern).n_strx = bfd_h_get_32 (abfd, (extern)->e_strx); \
+ (intern).n_desc = bfd_h_get_16 (abfd, (extern)->e_desc); \
+ if (bfd_get_sign_extend_vma (abfd)) \
+ (intern).n_value = bfd_h_get_signed_32 (abfd, (extern)->e_value); \
+ else \
+ (intern).n_value = bfd_h_get_32 (abfd, (extern)->e_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 (struct objfile *objfile)
+{
+ struct internal_nlist nlist;
+
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (symfile_bfd);
+
+ symnum++;
+ INTERNALIZE_SYMBOL (nlist, &symbuf[symbuf_idx], symfile_bfd);
+ OBJSTAT (objfile, n_stabs++);
+
+ symbuf_idx++;
+
+ return nlist.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 (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 (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 (char *name, int instance)
+{
+ struct header_file_location *bincl;
+
+ for (bincl = bincl_list; bincl < next_bincl; bincl++)
+ if (bincl->instance == instance
+ && strcmp (name, bincl->name) == 0)
+ return bincl->pst;
+
+ repeated_header_complaint (name, symnum);
+ return (struct partial_symtab *) 0;
+}
+
+/* Free the storage allocated for the bincl list. */
+
+static void
+free_bincl_list (struct objfile *objfile)
+{
+ xmfree (objfile->md, bincl_list);
+ bincls_allocated = 0;
+}
+
+static void
+do_free_bincl_list_cleanup (void *objfile)
+{
+ free_bincl_list (objfile);
+}
+
+static struct cleanup *
+make_cleanup_free_bincl_list (struct objfile *objfile)
+{
+ return make_cleanup (do_free_bincl_list_cleanup, objfile);
+}
+
+/* Set namestring based on nlist. 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. */
+
+static char *
+set_namestring (struct objfile *objfile, struct internal_nlist nlist)
+{
+ char *namestring;
+
+ if (((unsigned) nlist.n_strx + file_string_table_offset) >=
+ DBX_STRINGTAB_SIZE (objfile))
+ {
+ complaint (&symfile_complaints, "bad string table offset in symbol %d",
+ symnum);
+ namestring = "<bad string table offset>";
+ }
+ else
+ namestring = nlist.n_strx + file_string_table_offset +
+ DBX_STRINGTAB (objfile);
+ return namestring;
+}
+
+/* Scan a SunOs dynamic symbol table for symbols of interest and
+ add them to the minimal symbol table. */
+
+static void
+read_dbx_dynamic_symtab (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 (xfree, 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 (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ type = N_TEXT;
+ }
+ else if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
+ {
+ sym_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ type = N_DATA;
+ }
+ else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
+ {
+ sym_value += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ 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 (xfree, 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 (objfile->section_offsets, SECT_OFF_DATA (objfile));
+
+ 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 (name, address, mst_solib_trampoline,
+ objfile);
+ }
+
+ do_cleanups (back_to);
+}
+
+#ifdef SOFUN_ADDRESS_MAYBE_MISSING
+static CORE_ADDR
+find_stab_function_addr (char *namestring, char *filename,
+ 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 + 2);
+ strncpy (p, namestring, n);
+ p[n] = 0;
+
+ msym = lookup_minimal_symbol (p, filename, objfile);
+ if (msym == NULL)
+ {
+ /* Sun Fortran appends an underscore to the minimal symbol name,
+ try again with an appended underscore if the minimal symbol
+ was not found. */
+ p[n] = '_';
+ p[n + 1] = 0;
+ msym = lookup_minimal_symbol (p, filename, objfile);
+ }
+
+ if (msym == NULL && filename != NULL)
+ {
+ /* Try again without the filename. */
+ p[n] = 0;
+ msym = lookup_minimal_symbol (p, NULL, objfile);
+ }
+ if (msym == NULL && filename != NULL)
+ {
+ /* And try again for Sun Fortran, but without the filename. */
+ p[n] = '_';
+ p[n + 1] = 0;
+ msym = lookup_minimal_symbol (p, NULL, objfile);
+ }
+
+ return msym == NULL ? 0 : SYMBOL_VALUE_ADDRESS (msym);
+}
+#endif /* SOFUN_ADDRESS_MAYBE_MISSING */
+
+static void
+function_outside_compilation_unit_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints,
+ "function `%s' appears to be defined outside of all compilation units",
+ arg1);
+}
+
+/* Setup partial_symtab's describing each source file for which
+ debugging information is available. */
+
+static void
+read_dbx_symtab (struct objfile *objfile)
+{
+ struct external_nlist *bufp = 0; /* =0 avoids gcc -Wall glitch */
+ struct internal_nlist nlist;
+ CORE_ADDR text_addr;
+ int text_size;
+
+ 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;
+ int textlow_not_set;
+ int data_sect_index;
+
+ /* 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;
+
+ text_addr = DBX_TEXT_ADDR (objfile);
+ text_size = DBX_TEXT_SIZE (objfile);
+
+ /* 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;
+ textlow_not_set = 1;
+ has_line_numbers = 0;
+
+ /* FIXME: jimb/2003-09-12: We don't apply the right section's offset
+ to global and static variables. The stab for a global or static
+ variable doesn't give us any indication of which section it's in,
+ so we can't tell immediately which offset in
+ objfile->section_offsets we should apply to the variable's
+ address.
+
+ We could certainly find out which section contains the variable
+ by looking up the variable's unrelocated address with
+ find_pc_section, but that would be expensive; this is the
+ function that constructs the partial symbol tables by examining
+ every symbol in the entire executable, and it's
+ performance-critical. So that expense would not be welcome. I'm
+ not sure what to do about this at the moment.
+
+ What we have done for years is to simply assume that the .data
+ section's offset is appropriate for all global and static
+ variables. Recently, this was expanded to fall back to the .bss
+ section's offset if there is no .data section, and then to the
+ .rodata section's offset. */
+ data_sect_index = objfile->sect_index_data;
+ if (data_sect_index == -1)
+ data_sect_index = SECT_OFF_BSS (objfile);
+ if (data_sect_index == -1)
+ data_sect_index = SECT_OFF_RODATA (objfile);
+
+ /* If data_sect_index is still -1, that's okay. It's perfectly fine
+ for the file to have no .data, no .bss, and no .text at all, if
+ it also has no global or static variables. If it does, we will
+ get an internal error from an ANOFFSET macro below when we try to
+ use data_sect_index. */
+
+ 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 (bfd_h_get_8 (abfd, bufp->e_type) == N_SLINE)
+ {
+ has_line_numbers = 1;
+ continue;
+ }
+
+ INTERNALIZE_SYMBOL (nlist, 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.
+ */
+
+ switch (nlist.n_type)
+ {
+ char *p;
+ /*
+ * Standard, external, non-debugger, symbols
+ */
+
+ case N_TEXT | N_EXT:
+ case N_NBTEXT | N_EXT:
+ nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ goto record_it;
+
+ case N_DATA | N_EXT:
+ case N_NBDATA | N_EXT:
+ nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ 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? */
+ nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ goto record_it;
+
+ case N_ABS | N_EXT:
+ record_it:
+ namestring = set_namestring (objfile, nlist);
+
+ bss_ext_symbol:
+ record_minimal_symbol (namestring, nlist.n_value,
+ nlist.n_type, objfile); /* Always */
+ 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:
+ nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ namestring = set_namestring (objfile, nlist);
+
+ if ((namestring[0] == '-' && namestring[1] == 'l')
+ || (namestring[(nsl = strlen (namestring)) - 1] == 'o'
+ && namestring[nsl - 2] == '.'))
+ {
+ if (objfile->ei.entry_point < nlist.n_value &&
+ objfile->ei.entry_point >= last_o_file_start)
+ {
+ objfile->ei.deprecated_entry_file_lowpc = last_o_file_start;
+ objfile->ei.deprecated_entry_file_highpc = nlist.n_value;
+ }
+ if (past_first_source_file && pst
+ /* The gould NP1 uses low values for .o and -l symbols
+ which are not the address. */
+ && nlist.n_value >= pst->textlow)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size,
+ nlist.n_value > pst->texthigh
+ ? nlist.n_value : pst->texthigh,
+ dependency_list, dependencies_used, textlow_not_set);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+ last_o_file_start = nlist.n_value;
+ }
+ else
+ goto record_it;
+ continue;
+
+ case N_DATA:
+ nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ goto record_it;
+
+ case N_UNDF | N_EXT:
+ if (nlist.n_value != 0)
+ {
+ /* This is a "Fortran COMMON" symbol. See if the target
+ environment knows where it has been relocated to. */
+
+ CORE_ADDR reladdr;
+
+ namestring = set_namestring (objfile, nlist);
+ if (target_lookup_symbol (namestring, &reladdr))
+ {
+ continue; /* Error in lookup; ignore symbol for now. */
+ }
+ nlist.n_type ^= (N_BSS ^ N_UNDF); /* Define it as a bss-symbol */
+ nlist.n_value = reladdr;
+ goto bss_ext_symbol;
+ }
+ continue; /* Just undefined, not COMMON */
+
+ case N_UNDF:
+ if (processing_acc_compilation && nlist.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 + nlist.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;
+ }
+ 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:
+ {
+ CORE_ADDR valu;
+ static int prev_so_symnum = -10;
+ static int first_so_symnum;
+ char *p;
+ int prev_textlow_not_set;
+
+ valu = nlist.n_value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ prev_textlow_not_set = textlow_not_set;
+
+#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 (nlist.n_value == 0)
+ {
+ textlow_not_set = 1;
+ valu = 0;
+ }
+ else
+ textlow_not_set = 0;
+#else
+ textlow_not_set = 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,
+ prev_textlow_not_set);
+ 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 */
+
+ namestring = set_namestring (objfile, nlist);
+
+ /* 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,
+ namestring, valu,
+ first_so_symnum * symbol_size,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ continue;
+ }
+
+ case N_BINCL:
+ {
+ 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 */
+
+ namestring = set_namestring (objfile, nlist);
+ 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;
+
+ if (pst == NULL)
+ {
+ /* FIXME: we should not get here without a PST to work on.
+ Attempt to recover. */
+ complaint (&symfile_complaints,
+ "N_BINCL %s not in entries for any file, at symtab pos %d",
+ namestring, symnum);
+ continue;
+ }
+ add_bincl_to_list (pst, namestring, nlist.n_value);
+
+ /* Mark down an include file in the current psymtab */
+
+ goto record_include_file;
+ }
+
+ case N_SOL:
+ {
+ enum language tmp_language;
+ /* Mark down an include file in the current psymtab */
+
+ namestring = set_namestring (objfile, nlist);
+ 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 && strcmp (namestring, pst->filename) == 0)
+ continue;
+ {
+ int i;
+ for (i = 0; i < includes_used; i++)
+ if (strcmp (namestring, psymtab_include_list[i]) == 0)
+ {
+ i = -1;
+ break;
+ }
+ if (i == -1)
+ continue;
+ }
+
+ record_include_file:
+
+ 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 (psymtab_include_list, 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. */
+
+ namestring = set_namestring (objfile, nlist);
+
+ /* See if this is an end of function stab. */
+ if (pst && nlist.n_type == N_FUN && *namestring == '\000')
+ {
+ CORE_ADDR 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 = nlist.n_value + last_function_start;
+ if (pst->texthigh == 0 || valu > pst->texthigh)
+ pst->texthigh = valu;
+ break;
+ }
+
+ 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':
+ nlist.n_value += ANOFFSET (objfile->section_offsets, data_sect_index);
+#ifdef STATIC_TRANSFORM_NAME
+ namestring = STATIC_TRANSFORM_NAME (namestring);
+#endif
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->static_psymbols,
+ 0, nlist.n_value,
+ psymtab_language, objfile);
+ continue;
+ case 'G':
+ nlist.n_value += ANOFFSET (objfile->section_offsets, data_sect_index);
+ /* The addresses in these entries are reported to be
+ wrong. See the code that reads 'G's for symtabs. */
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->global_psymbols,
+ 0, nlist.n_value,
+ psymtab_language, objfile);
+ continue;
+
+ case 'T':
+ /* When a 'T' entry is defining an anonymous enum, it
+ may have a name which is the empty string, or a
+ single space. Since they're not really defining a
+ symbol, those shouldn't go in the partial symbol
+ table. We do pick up the elements of such enums at
+ 'check_enum:', below. */
+ if (p >= namestring + 2
+ || (p == namestring + 1
+ && namestring[0] != ' '))
+ {
+ add_psymbol_to_list (namestring, p - namestring,
+ STRUCT_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ nlist.n_value, 0,
+ psymtab_language, objfile);
+ if (p[2] == 't')
+ {
+ /* Also a typedef with the same name. */
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ nlist.n_value, 0,
+ psymtab_language, objfile);
+ p += 1;
+ }
+ }
+ goto check_enum;
+ case 't':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ nlist.n_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
+ <name> ":" ("t" | "T") [<number> "="] "e"
+ {<constant> ":" <value> ","} ";". */
+
+ /* 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_DOMAIN, 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_DOMAIN, LOC_CONST,
+ &objfile->static_psymbols, nlist.n_value,
+ 0, psymtab_language, objfile);
+ continue;
+
+ case 'f':
+ if (! pst)
+ {
+ int name_len = p - namestring;
+ char *name = xmalloc (name_len + 1);
+ memcpy (name, namestring, name_len);
+ name[name_len] = '\0';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ /* 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 (nlist.n_value == ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile)))
+ {
+ CORE_ADDR minsym_valu =
+ find_stab_function_addr (namestring, pst->filename, objfile);
+ /* find_stab_function_addr will return 0 if the minimal
+ symbol wasn't found. (Unfortunately, this might also
+ be a valid address.) Anyway, if it *does* return 0,
+ it is likely that the value was set correctly to begin
+ with... */
+ if (minsym_valu != 0)
+ nlist.n_value = minsym_valu;
+ }
+ if (pst && textlow_not_set)
+ {
+ pst->textlow = nlist.n_value;
+ textlow_not_set = 0;
+ }
+#endif
+ /* End kludge. */
+
+ /* Keep track of the start of the last function so we
+ can handle end of function symbols. */
+ last_function_start = nlist.n_value;
+
+ /* 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_not_set
+ || (nlist.n_value < pst->textlow
+ && (nlist.n_value
+ != ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile))))))
+ {
+ pst->textlow = nlist.n_value;
+ textlow_not_set = 0;
+ }
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols,
+ 0, nlist.n_value,
+ 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':
+ if (! pst)
+ {
+ int name_len = p - namestring;
+ char *name = xmalloc (name_len + 1);
+ memcpy (name, namestring, name_len);
+ name[name_len] = '\0';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ /* 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 (nlist.n_value == ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile)))
+ {
+ CORE_ADDR minsym_valu =
+ find_stab_function_addr (namestring, pst->filename, objfile);
+ /* find_stab_function_addr will return 0 if the minimal
+ symbol wasn't found. (Unfortunately, this might also
+ be a valid address.) Anyway, if it *does* return 0,
+ it is likely that the value was set correctly to begin
+ with... */
+ if (minsym_valu != 0)
+ nlist.n_value = minsym_valu;
+ }
+ if (pst && textlow_not_set)
+ {
+ pst->textlow = nlist.n_value;
+ textlow_not_set = 0;
+ }
+#endif
+ /* End kludge. */
+
+ /* Keep track of the start of the last function so we
+ can handle end of function symbols. */
+ last_function_start = nlist.n_value;
+
+ /* 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_not_set
+ || (nlist.n_value < pst->textlow
+ && (nlist.n_value
+ != ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile))))))
+ {
+ pst->textlow = nlist.n_value;
+ textlow_not_set = 0;
+ }
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols,
+ 0, nlist.n_value,
+ 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 '-':
+ case '#': /* for symbol identification (used in live ranges) */
+ 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. */
+
+ complaint (&symfile_complaints, "unknown symbol descriptor `%c'",
+ p[1]);
+
+ /* Ignore it; perhaps it is an extension that we don't
+ know about. */
+ continue;
+ }
+
+ case N_EXCL:
+
+ namestring = set_namestring (objfile, nlist);
+
+ /* Find the corresponding bincl and mark that psymtab on the
+ psymtab dependency list */
+ {
+ struct partial_symtab *needed_pst =
+ find_corresponding_bincl_psymtab (namestring, nlist.n_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 (dependency_list, 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
+ }
+ }
+ }
+ 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, textlow_not_set);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+#endif
+ continue;
+
+ case N_RBRAC:
+#ifdef HANDLE_RBRAC
+ HANDLE_RBRAC (nlist.n_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_ALIAS: /* SunPro F77: alias name, ignore for now. */
+
+ case N_OBJ: /* useless types from Solaris */
+ case N_OPT:
+ case N_PATCH:
+ /* 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. */
+ unknown_symtype_complaint (local_hex_string (nlist.n_type));
+ continue;
+ }
+ }
+
+ /* 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 < nlist.n_value
+ && objfile->ei.entry_point >= last_o_file_start)
+ {
+ objfile->ei.deprecated_entry_file_lowpc = last_o_file_start;
+ objfile->ei.deprecated_entry_file_highpc = nlist.n_value;
+ }
+
+ if (pst)
+ {
+ /* Don't set pst->texthigh lower than it already is. */
+ CORE_ADDR text_end =
+ (lowest_text_address == (CORE_ADDR) -1
+ ? (text_addr + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)))
+ : lowest_text_address)
+ + text_size;
+
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * symbol_size,
+ text_end > pst->texthigh ? text_end : pst->texthigh,
+ dependency_list, dependencies_used, textlow_not_set);
+ }
+
+ 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 *
+start_psymtab (struct objfile *objfile, 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, objfile->section_offsets,
+ filename, textlow, global_syms, static_syms);
+
+ result->read_symtab_private = (char *)
+ obstack_alloc (&objfile->objfile_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 (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 textlow_not_set)
+{
+ 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: if we see a static
+ or global function, and the textlow for the current pst
+ is not set (ie: textlow_not_set), 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, 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 + 2);
+ strncpy (p, last_function_name, n);
+ p[n] = 0;
+
+ minsym = lookup_minimal_symbol (p, pst->filename, objfile);
+ if (minsym == NULL)
+ {
+ /* Sun Fortran appends an underscore to the minimal symbol name,
+ try again with an appended underscore if the minimal symbol
+ was not found. */
+ p[n] = '_';
+ p[n + 1] = 0;
+ minsym = lookup_minimal_symbol (p, pst->filename, objfile);
+ }
+
+ if (minsym)
+ pst->texthigh = SYMBOL_VALUE_ADDRESS (minsym) + MSYMBOL_SIZE (minsym);
+
+ last_function_name = NULL;
+ }
+
+ /* this test will be true if the last .o file is only data */
+ if (textlow_not_set)
+ pst->textlow = pst->texthigh;
+ else
+ {
+ struct partial_symtab *p1;
+
+ /* 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. */
+
+ 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->objfile_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);
+
+ /* Copy the sesction_offsets array from the main psymtab. */
+ subpst->section_offsets = pst->section_offsets;
+ subpst->read_symtab_private =
+ (char *) obstack_alloc (&objfile->objfile_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->objfile_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
+ && has_line_numbers == 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. */
+
+ discard_psymtab (pst);
+
+ /* Indicate that psymtab was thrown away. */
+ pst = (struct partial_symtab *) NULL;
+ }
+ return pst;
+}
+
+static void
+dbx_psymtab_to_symtab_1 (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);
+
+ 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 (struct partial_symtab *pst)
+{
+ bfd *sym_bfd;
+ struct cleanup *back_to = NULL;
+
+ 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;
+
+ if (DBX_STAB_SECTION (pst->objfile))
+ {
+ stabs_data
+ = symfile_relocate_debug_section (pst->objfile->obfd,
+ DBX_STAB_SECTION (pst->objfile),
+ NULL);
+ if (stabs_data)
+ back_to = make_cleanup (free_current_contents, (void *) &stabs_data);
+ }
+
+ dbx_psymtab_to_symtab_1 (pst);
+
+ if (back_to)
+ do_cleanups (back_to);
+
+ /* Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in. */
+ scan_file_globals (pst->objfile);
+
+ /* 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 (struct partial_symtab *pst)
+{
+ char *namestring;
+ struct external_nlist *bufp;
+ struct internal_nlist nlist;
+ unsigned char type;
+ unsigned max_symnum;
+ bfd *abfd;
+ struct objfile *objfile;
+ int sym_offset; /* Offset to start of symbols to read */
+ int sym_size; /* Size of symbols to read */
+ CORE_ADDR text_offset; /* Start of text segment for symbols */
+ int text_size; /* Size of text segment for symbols */
+ struct section_offsets *section_offsets;
+
+ objfile = pst->objfile;
+ sym_offset = LDSYMOFF (pst);
+ sym_size = LDSYMLEN (pst);
+ text_offset = pst->textlow;
+ text_size = pst->texthigh - pst->textlow;
+ /* This cannot be simply objfile->section_offsets because of
+ elfstab_offset_sections() which initializes the psymtab section
+ offsets information in a special way, and that is different from
+ objfile->section_offsets. */
+ 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;
+ symbuf_read = 0;
+ symbuf_left = sym_offset + sym_size;
+
+ /* 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)
+ {
+ stabs_seek (sym_offset - symbol_size);
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx++];
+ INTERNALIZE_SYMBOL (nlist, bufp, abfd);
+ OBJSTAT (objfile, n_stabs++);
+
+ namestring = set_namestring (objfile, nlist);
+
+ processing_gcc_compilation = 0;
+ if (nlist.n_type == N_TEXT)
+ {
+ const char *tempstring = namestring;
+
+ if (DEPRECATED_STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (DEPRECATED_STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+ if (tempstring[0] == bfd_get_symbol_leading_char (symfile_bfd))
+ ++tempstring;
+ if (DEPRECATED_STREQN (tempstring, "__gnu_compiled", 14))
+ processing_gcc_compilation = 2;
+ }
+
+ /* Try to select a C++ demangling based on the compilation unit
+ producer. */
+
+#if 0
+ /* For now, stay with AUTO_DEMANGLING for g++ output, as we don't
+ know whether it will use the old style or v3 mangling. */
+ if (processing_gcc_compilation)
+ {
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ }
+#endif
+ }
+ 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. */
+ stabs_seek (sym_offset);
+ processing_gcc_compilation = 0;
+ }
+
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf (abfd);
+ bufp = &symbuf[symbuf_idx];
+ if (bfd_h_get_8 (abfd, bufp->e_type) != 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++];
+ INTERNALIZE_SYMBOL (nlist, bufp, abfd);
+ OBJSTAT (objfile, n_stabs++);
+
+ type = bfd_h_get_8 (abfd, bufp->e_type);
+
+ namestring = set_namestring (objfile, nlist);
+
+ if (type & N_STAB)
+ {
+ process_one_symbol (type, nlist.n_desc, nlist.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 (DEPRECATED_STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (DEPRECATED_STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+
+#if 0
+ /* For now, stay with AUTO_DEMANGLING for g++ output, as we don't
+ know whether it will use the old style or v3 mangling. */
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+#endif
+ }
+ 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 (objfile));
+
+ 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.
+ Note that these section_offsets are not the
+ objfile->section_offsets but the pst->section_offsets.
+ 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 (int type, int 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
+
+ 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;
+
+ /* This holds the address of the start of a function, without the system
+ peculiarities of function_start_offset. */
+ static CORE_ADDR last_function_start;
+
+ /* If this is nonzero, we've seen an N_SLINE since the start of the
+ current function. We use this to tell us to move the first sline
+ to the beginning of the function regardless of what its given
+ value is. */
+ static int sline_found_in_function = 1;
+
+ /* 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 (objfile));
+
+ /* 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,
+ but this should not be an error (). */
+ return;
+ }
+
+ switch (type)
+ {
+ case N_FUN:
+ case N_FNAME:
+
+ if (*name == '\000')
+ {
+ /* This N_FUN marks the end of a function. This closes off the
+ current block. */
+
+ if (context_stack_depth <= 0)
+ {
+ lbrac_mismatch_complaint (symnum);
+ break;
+ }
+
+ /* The following check is added before recording line 0 at
+ end of function so as to handle hand-generated stabs
+ which may have an N_FUN stabs at the end of the function, but
+ no N_SLINE stabs. */
+ if (sline_found_in_function)
+ record_line (current_subfile, 0, last_function_start + valu);
+
+ within_function = 0;
+ new = pop_context ();
+
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, new->start_addr + valu,
+ objfile);
+
+ /* May be switching to an assembler file which may not be using
+ block relative stabs, so reset the offset. */
+ if (block_address_function_relative)
+ function_start_offset = 0;
+
+ break;
+ }
+
+ sline_found_in_function = 0;
+
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile));
+ valu = SMASH_TEXT_ADDRESS (valu);
+ last_function_start = valu;
+
+ 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 (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;
+
+#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 */
+ complaint (&symfile_complaints, "bad block start address patched");
+ 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 (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;
+
+ if (context_stack_depth <= 0)
+ {
+ lbrac_mismatch_complaint (symnum);
+ break;
+ }
+
+ new = pop_context ();
+ if (desc != new->depth)
+ 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))
+ {
+ if (local_symbols != NULL)
+ {
+ /* GCC development snapshots from March to December of
+ 2000 would output N_LSYM entries after N_LBRAC
+ entries. As a consequence, these symbols are simply
+ discarded. Complain if this is the case. Note that
+ there are some compilers which legitimately put local
+ symbols within an LBRAC/RBRAC block; this complaint
+ might also help sort out problems in which
+ VARIABLES_INSIDE_BLOCK is incorrectly defined. */
+ complaint (&symfile_complaints,
+ "misplaced N_LBRAC entry; discarding local symbols which have no enclosing block");
+ }
+ 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)
+ {
+ complaint (&symfile_complaints,
+ "block start larger than block end");
+ 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 (objfile));
+ 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 (objfile));
+
+ 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 (objfile));
+ 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;
+
+ if (block_address_function_relative)
+ function_start_offset = 0;
+
+ start_stabs ();
+ start_symtab (name, NULL, valu);
+ record_debugformat ("stabs");
+ 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 (objfile));
+ 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
+ /* If this is the first SLINE note in the function, record it at
+ the start of the function instead of at the listed location. */
+ if (within_function && sline_found_in_function == 0)
+ {
+ record_line (current_subfile, desc, last_function_start);
+ sline_found_in_function = 1;
+ }
+ else
+ 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 (objfile));
+ 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:
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ }
+
+ case_N_STSYM: /* Static symbol in data seg */
+ case N_DSLINE: /* Source line number, data seg */
+ valu += ANOFFSET (section_offsets, SECT_OFF_DATA (objfile));
+ 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 (objfile));
+ goto define_a_symbol;
+
+ case_N_ROSYM: /* Static symbol in Read-only data seg */
+ valu += ANOFFSET (section_offsets, SECT_OFF_RODATA (objfile));
+ goto define_a_symbol;
+
+ case N_ENTRY: /* Alternate entry point */
+ /* Relocate for dynamic loading */
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile));
+ 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:
+ 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 (objfile)))
+ {
+ CORE_ADDR minsym_valu =
+ find_stab_function_addr (name, last_source_file, objfile);
+
+ /* find_stab_function_addr will return 0 if the minimal
+ symbol wasn't found. (Unfortunately, this might also
+ be a valid address.) Anyway, if it *does* return 0,
+ it is likely that the value was set correctly to begin
+ with... */
+ if (minsym_valu != 0)
+ valu = minsym_valu;
+ }
+#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 && strncmp (DEPRECATED_SYMBOL_NAME (m), name, l) == 0
+ && DEPRECATED_SYMBOL_NAME (m)[l] == '\0')
+ /* last_pc_address was in this function */
+ valu = SYMBOL_VALUE (m);
+ else if (m && DEPRECATED_SYMBOL_NAME (m + 1)
+ && strncmp (DEPRECATED_SYMBOL_NAME (m + 1), name, l) == 0
+ && DEPRECATED_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 > 1)
+ {
+ complaint (&symfile_complaints,
+ "unmatched N_LBRAC before symtab pos %d", symnum);
+ break;
+ }
+
+ 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);
+ }
+
+ 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 (strcmp (name, GCC2_COMPILED_FLAG_SYMBOL) == 0)
+ {
+ processing_gcc_compilation = 2;
+#if 0 /* Works, but is experimental. -fnf */
+ /* For now, stay with AUTO_DEMANGLING for g++ output, as we don't
+ know whether it will use the old style or v3 mangling. */
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+#endif
+ }
+ else
+ n_opt_found = 1;
+ }
+ break;
+
+ case N_MAIN: /* Name of main routine. */
+ /* FIXME: If one has a symbol file with N_MAIN and then replaces
+ it with a symbol file with "main" and without N_MAIN. I'm
+ not sure exactly what rule to follow but probably something
+ like: N_MAIN takes precedence over "main" no matter what
+ objfile it is in; If there is more than one N_MAIN, choose
+ the one in the symfile_objfile; If there is more than one
+ N_MAIN within a given objfile, complain() and choose
+ arbitrarily. (kingdon) */
+ if (name != NULL)
+ set_main_name (name);
+ break;
+
+ /* The following symbol types can be ignored. */
+ case N_OBJ: /* Solaris 2: Object file dir and name */
+ case N_PATCH: /* Solaris2: Patch Run Time Checker. */
+ /* 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_ALIAS: /* SunPro F77: alias name, ignore for now. */
+ break;
+ }
+
+ /* '#' is a GNU C extension to allow one symbol to refer to another
+ related symbol.
+
+ Generally this is used so that an alias can refer to its main
+ symbol. */
+ if (name[0] == '#')
+ {
+ /* Initialize symbol reference names and determine if this is
+ a definition. If symbol reference is being defined, go
+ ahead and add it. Otherwise, just return sym. */
+
+ char *s = name;
+ int refnum;
+
+ /* If this stab defines a new reference ID that is not on the
+ reference list, then put it on the reference list.
+
+ We go ahead and advance NAME past the reference, even though
+ it is not strictly necessary at this time. */
+ refnum = symbol_reference_defined (&s);
+ if (refnum >= 0)
+ if (!ref_search (refnum))
+ ref_add (refnum, 0, name, valu);
+ name = s;
+ }
+
+
+ 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 (struct objfile *objfile, 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 = 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->objfile_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_bread (DBX_STRINGTAB (objfile), stabstrsize, 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, 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).
+ STABSECT is the BFD section information for the .stab section.
+ 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 (struct objfile *objfile, int mainline,
+ asection *stabsect,
+ 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;
+ struct cleanup *back_to = NULL;
+
+ /* There is already a dbx_symfile_info allocated by our caller.
+ It might even contain some info from the ELF symtab to help us. */
+ info = objfile->sym_stab_info;
+
+ /* Find the first and last text address. dbx_symfile_read seems to
+ want this. */
+ find_text_range (sym_bfd, objfile);
+
+#define ELF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */
+ DBX_SYMBOL_SIZE (objfile) = ELF_STABS_SYMBOL_SIZE;
+ DBX_SYMCOUNT (objfile)
+ = bfd_section_size (objfile->obfd, stabsect) / DBX_SYMBOL_SIZE (objfile);
+ DBX_STRINGTAB_SIZE (objfile) = stabstrsize;
+ DBX_SYMTAB_OFFSET (objfile) = stabsect->filepos;
+ DBX_STAB_SECTION (objfile) = stabsect;
+
+ if (stabstrsize > bfd_get_size (sym_bfd))
+ error ("ridiculous string table size: %d bytes", stabstrsize);
+ DBX_STRINGTAB (objfile) = (char *)
+ obstack_alloc (&objfile->objfile_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_bread (DBX_STRINGTAB (objfile), stabstrsize, 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;
+
+ symbuf_read = 0;
+ symbuf_left = bfd_section_size (objfile->obfd, stabsect);
+ stabs_data = symfile_relocate_debug_section (objfile->obfd, stabsect, NULL);
+ if (stabs_data)
+ back_to = make_cleanup (free_current_contents, (void *) &stabs_data);
+
+ /* 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 should not generate any new
+ minimal symbols, since we will have already read the ELF dynamic symbol
+ table and normal symbol entries won't be in the ".stab" section; but in
+ case it does, it will install them itself. */
+ dbx_symfile_read (objfile, 0);
+
+ if (back_to)
+ do_cleanups (back_to);
+}
+
+/* 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 (struct objfile *objfile, 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 = (struct dbx_symfile_info *)
+ xmalloc (sizeof (struct dbx_symfile_info));
+ memset (objfile->sym_stab_info, 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->objfile_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 ();
+
+ /* Now, do an incremental load */
+
+ processing_acc_compilation = 1;
+ dbx_symfile_read (objfile, 0);
+}
+
+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 */
+ default_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_dbxread (void)
+{
+ 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 0000000..ee69094
--- /dev/null
+++ b/contrib/gdb/gdb/dcache.c
@@ -0,0 +1,604 @@
+/* Caching code for GDB, the GNU debugger.
+
+ Copyright 1992, 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "gdbcore.h"
+#include "target.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 the nocache
+ memory region attribute 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.
+ */
+
+/* NOTE: Interaction of dcache and memory region attributes
+
+ As there is no requirement that memory region attributes be aligned
+ to or be a multiple of the dcache page size, dcache_read_line() and
+ dcache_write_line() must break up the page by memory region. If a
+ chunk does not have the cache attribute set, an invalid memory type
+ is set, etc., then the chunk is skipped. Those chunks are handled
+ in target_xfer_memory() (or target_xfer_memory_partial()).
+
+ This doesn't occur very often. The most common occurance is when
+ the last bit of the .text segment and the first bit of the .data
+ segment fall within the same dcache page with a ro/cacheable memory
+ region defined for the .text segment and a rw/non-cacheable memory
+ region defined for the .data segment. */
+
+/* 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 */
+ CORE_ADDR 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;
+ };
+
+
+/* FIXME: dcache_struct used to have a cache_has_stuff field that was
+ used to record whether the cache had been accessed. This was used
+ to invalidate the cache whenever caching was (re-)enabled (if the
+ cache was disabled and later re-enabled, it could contain stale
+ data). This was not needed because the cache is write through and
+ the code that enables, disables, and deletes memory region all
+ invalidate the cache.
+
+ This is overkill, since it also invalidates cache lines from
+ unrelated regions. One way this could be addressed by adding a
+ new function that takes an address and a length and invalidates
+ only those cache lines that match. */
+
+struct dcache_struct
+ {
+ /* 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;
+ };
+
+static int dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr);
+
+static int dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr);
+
+static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr);
+
+static int dcache_write_line (DCACHE *dcache, struct dcache_block *db);
+
+static int dcache_read_line (DCACHE *dcache, struct dcache_block *db);
+
+static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr);
+
+static int dcache_writeback (DCACHE *dcache);
+
+static void dcache_info (char *exp, int tty);
+
+void _initialize_dcache (void);
+
+static int dcache_enabled_p = 0;
+
+DCACHE *last_cache; /* Used by info dcache */
+
+
+/* Free all the data cache blocks, thus discarding all cached data. */
+
+void
+dcache_invalidate (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;
+ }
+
+ return;
+}
+
+/* If addr is present in the dcache, return the address of the block
+ containing it. */
+
+static struct dcache_block *
+dcache_hit (DCACHE *dcache, CORE_ADDR addr)
+{
+ 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 *dcache, struct dcache_block *db)
+{
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int res;
+ int reg_len;
+ struct mem_region *region;
+
+ if (!db->anydirty)
+ return 1;
+
+ len = LINE_SIZE;
+ memaddr = db->addr;
+ myaddr = db->data;
+
+ while (len > 0)
+ {
+ int s;
+ int e;
+ int dirty_len;
+
+ region = lookup_mem_region(memaddr);
+ if (memaddr + len < region->hi)
+ reg_len = len;
+ else
+ reg_len = region->hi - memaddr;
+
+ if (!region->attrib.cache || region->attrib.mode == MEM_RO)
+ {
+ memaddr += reg_len;
+ myaddr += reg_len;
+ len -= reg_len;
+ continue;
+ }
+
+ while (reg_len > 0)
+ {
+ s = XFORM(memaddr);
+ while (reg_len > 0) {
+ if (db->state[s] == ENTRY_DIRTY)
+ break;
+ s++;
+ reg_len--;
+
+ memaddr++;
+ myaddr++;
+ len--;
+ }
+
+ e = s;
+ while (reg_len > 0) {
+ if (db->state[e] != ENTRY_DIRTY)
+ break;
+ e++;
+ reg_len--;
+ }
+
+ dirty_len = e - s;
+ while (dirty_len > 0)
+ {
+ res = do_xfer_memory(memaddr, myaddr, dirty_len, 1,
+ &region->attrib);
+ if (res <= 0)
+ return 0;
+
+ memset (&db->state[XFORM(memaddr)], ENTRY_OK, res);
+ memaddr += res;
+ myaddr += res;
+ len -= res;
+ dirty_len -= res;
+ }
+ }
+ }
+
+ db->anydirty = 0;
+ return 1;
+}
+
+/* Read cache line */
+static int
+dcache_read_line (DCACHE *dcache, struct dcache_block *db)
+{
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int res;
+ int reg_len;
+ struct mem_region *region;
+
+ /* If there are any dirty bytes in the line, it must be written
+ before a new line can be read */
+ if (db->anydirty)
+ {
+ if (!dcache_write_line (dcache, db))
+ return 0;
+ }
+
+ len = LINE_SIZE;
+ memaddr = db->addr;
+ myaddr = db->data;
+
+ while (len > 0)
+ {
+ region = lookup_mem_region(memaddr);
+ if (memaddr + len < region->hi)
+ reg_len = len;
+ else
+ reg_len = region->hi - memaddr;
+
+ if (!region->attrib.cache || region->attrib.mode == MEM_WO)
+ {
+ memaddr += reg_len;
+ myaddr += reg_len;
+ len -= reg_len;
+ continue;
+ }
+
+ while (reg_len > 0)
+ {
+ res = do_xfer_memory (memaddr, myaddr, reg_len, 0,
+ &region->attrib);
+ if (res <= 0)
+ return 0;
+
+ memaddr += res;
+ myaddr += res;
+ len -= res;
+ reg_len -= res;
+ }
+ }
+
+ memset (db->state, ENTRY_OK, sizeof (db->data));
+ db->anydirty = 0;
+
+ return 1;
+}
+
+/* Get a free cache block, put or keep it on the valid list,
+ and return its address. */
+
+static struct dcache_block *
+dcache_alloc (DCACHE *dcache, CORE_ADDR addr)
+{
+ struct dcache_block *db;
+
+ /* 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;
+
+ if (!dcache_write_line (dcache, db))
+ return NULL;
+
+ dcache->valid_head = db->p;
+ }
+
+ db->addr = MASK(addr);
+ db->refs = 0;
+ db->anydirty = 0;
+ memset (db->state, ENTRY_BAD, sizeof (db->data));
+
+ /* 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;
+}
+
+/* Writeback any dirty lines. */
+static int
+dcache_writeback (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 byte at
+ address ADDR in the remote machine.
+
+ Returns 0 on error. */
+
+static int
+dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr)
+{
+ struct dcache_block *db = dcache_hit (dcache, addr);
+
+ if (!db)
+ {
+ db = dcache_alloc (dcache, addr);
+ if (!db)
+ return 0;
+ }
+
+ if (db->state[XFORM (addr)] == ENTRY_BAD)
+ {
+ if (!dcache_read_line(dcache, db))
+ return 0;
+ }
+
+ *ptr = db->data[XFORM (addr)];
+ return 1;
+}
+
+
+/* Write the byte at PTR into ADDR in the data cache.
+ Return zero on write error.
+ */
+
+static int
+dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr)
+{
+ struct dcache_block *db = dcache_hit (dcache, addr);
+
+ if (!db)
+ {
+ db = dcache_alloc (dcache, addr);
+ if (!db)
+ return 0;
+ }
+
+ db->data[XFORM (addr)] = *ptr;
+ db->state[XFORM (addr)] = ENTRY_DIRTY;
+ db->anydirty = 1;
+ return 1;
+}
+
+/* Initialize the data cache. */
+DCACHE *
+dcache_init (void)
+{
+ int csize = sizeof (struct dcache_block) * DCACHE_SIZE;
+ DCACHE *dcache;
+
+ dcache = (DCACHE *) xmalloc (sizeof (*dcache));
+
+ dcache->the_cache = (struct dcache_block *) xmalloc (csize);
+ memset (dcache->the_cache, 0, csize);
+
+ dcache_invalidate (dcache);
+
+ last_cache = dcache;
+ return dcache;
+}
+
+/* Free a data cache */
+void
+dcache_free (DCACHE *dcache)
+{
+ if (last_cache == dcache)
+ last_cache = NULL;
+
+ xfree (dcache->the_cache);
+ xfree (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 *dcache, CORE_ADDR memaddr, char *myaddr, int len,
+ int should_write)
+{
+ int i;
+ int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, char *ptr);
+ xfunc = should_write ? dcache_poke_byte : dcache_peek_byte;
+
+ for (i = 0; i < len; i++)
+ {
+ if (!xfunc (dcache, memaddr + i, myaddr + i))
+ return 0;
+ }
+
+ /* FIXME: There may be some benefit from moving the cache writeback
+ to a higher layer, as it could occur after a sequence of smaller
+ writes have been completed (as when a stack frame is constructed
+ for an inferior function call). Note that only moving it up one
+ level to target_xfer_memory() (also target_xfer_memory_partial())
+ is not sufficent, since we want to coalesce memory transfers that
+ are "logically" connected but not actually a single call to one
+ of the memory transfer functions. */
+
+ if (should_write)
+ dcache_writeback (dcache);
+
+ return len;
+}
+
+static void
+dcache_info (char *exp, int tty)
+{
+ struct dcache_block *p;
+
+ printf_filtered ("Dcache line width %d, depth %d\n",
+ LINE_SIZE, DCACHE_SIZE);
+
+ if (last_cache)
+ {
+ printf_filtered ("Cache state:\n");
+
+ for (p = last_cache->valid_head; p; p = p->p)
+ {
+ int j;
+ printf_filtered ("Line at %s, referenced %d times\n",
+ paddr (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 (void)
+{
+ add_show_from_set
+ (add_set_cmd ("remotecache", class_support, var_boolean,
+ (char *) &dcache_enabled_p,
+ "\
+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 off.",
+ &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 0000000..5f9da65
--- /dev/null
+++ b/contrib/gdb/gdb/dcache.h
@@ -0,0 +1,43 @@
+/* Declarations for caching. Typically used by remote back ends for
+ caching remote memory.
+
+ Copyright 1992, 1993, 1995, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 struct dcache_struct DCACHE;
+
+/* Invalidate DCACHE. */
+void dcache_invalidate (DCACHE *dcache);
+
+/* Initialize DCACHE. */
+DCACHE *dcache_init (void);
+
+/* Free a DCACHE */
+void dcache_free (DCACHE *);
+
+/* Simple to call from <remote>_xfer_memory */
+
+int dcache_xfer_memory (DCACHE *cache, CORE_ADDR mem, char *my, int len,
+ int should_write);
+
+#endif /* DCACHE_H */
diff --git a/contrib/gdb/gdb/defs.h b/contrib/gdb/gdb/defs.h
new file mode 100644
index 0000000..e49f9e0
--- /dev/null
+++ b/contrib/gdb/gdb/defs.h
@@ -0,0 +1,1335 @@
+/* *INDENT-OFF* */ /* ATTR_FORMAT confuses indent, avoid running it for now */
+/* Basic, host-specific, and target-specific definitions for GDB.
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stdio.h>
+#include <errno.h> /* System call error return status. */
+#include <limits.h>
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#else
+#include <sys/types.h> /* For size_t. */
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* First include ansidecl.h so we can use the various macro definitions
+ here and in all subsequent file inclusions. */
+
+#include "ansidecl.h"
+
+#include "gdb_locale.h"
+
+/* For ``enum target_signal''. */
+#include "gdb/signals.h"
+
+/* 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
+
+#include <stdarg.h> /* For va_list. */
+
+#include "libiberty.h"
+
+/* For BFD64 and bfd_vma. */
+#include "bfd.h"
+
+
+/* The target is partially multi-arched. Both "tm.h" and the
+ multi-arch vector provide definitions. "tm.h" normally overrides
+ the multi-arch vector (but there are a few exceptions). */
+
+#define GDB_MULTI_ARCH_PARTIAL 1
+
+/* The target is partially multi-arched. Both the multi-arch vector
+ and "tm.h" provide definitions. "tm.h" cannot override a definition
+ provided by the multi-arch vector. It is detected as a compilation
+ error.
+
+ This setting is only useful during a multi-arch conversion. */
+
+#define GDB_MULTI_ARCH_TM 2
+
+/* The target is pure multi-arch. The MULTI-ARCH vector provides all
+ definitions. "tm.h" is linked to an empty file. */
+
+#define GDB_MULTI_ARCH_PURE 3
+
+
+
+/* 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;
+
+/* This is to make sure that LONGEST is at least as big as CORE_ADDR. */
+
+#ifndef LONGEST
+
+#ifdef BFD64
+
+#define LONGEST BFD_HOST_64_BIT
+#define ULONGEST BFD_HOST_U_64_BIT
+
+#else /* No BFD64 */
+
+#ifdef CC_HAS_LONG_LONG
+#define LONGEST long long
+#define ULONGEST unsigned long long
+#else
+#ifdef BFD_HOST_64_BIT
+/* BFD_HOST_64_BIT is defined for some hosts that don't have long long
+ (e.g. i386-windows) so try it. */
+#define LONGEST BFD_HOST_64_BIT
+#define ULONGEST BFD_HOST_U_64_BIT
+#else
+#define LONGEST long
+#define ULONGEST unsigned long
+#endif
+#endif
+
+#endif /* No BFD64 */
+
+#endif /* ! LONGEST */
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* Macros to do string compares.
+
+ NOTE: cagney/2000-03-14:
+
+ While old code can continue to refer to these macros, new code is
+ probably better off using strcmp() directly vis: ``strcmp() == 0''
+ and ``strcmp() != 0''.
+
+ This is because modern compilers can directly inline strcmp()
+ making the original justification for these macros - avoid function
+ call overhead by pre-testing the first characters
+ (``*X==*Y?...:0'') - redundant.
+
+ ``Even if [...] testing the first character does have a modest
+ performance improvement, I'd rather that whenever a performance
+ issue is found that we spend the effort on algorithmic
+ optimizations than micro-optimizing.'' J.T. */
+
+/* NOTE: cagney/2003-11-23: All instances of STREQ[N] covered by
+ testing GDB on a stabs system have been replaced by equivalent
+ str[n]cmp calls. To avoid the possability of introducing bugs when
+ making untested changes, the remaining references were deprecated
+ rather than replaced. */
+
+/* DISCLAIMER: cagney/2003-11-23: Simplified definition of these
+ macros so that they just map directly onto strcmp equivalent. I'm
+ not responsible for any breakage due to code that relied on the old
+ underlying implementation. */
+
+#define DEPRECATED_STREQ(a,b) (strcmp ((a), (b)) == 0)
+#define DEPRECATED_STREQN(a,b,c) (strncmp ((a), (b), (c)) == 0)
+
+/* Check if a character is one of the commonly used C++ marker characters. */
+extern int is_cplus_marker (int);
+
+/* enable xdb commands if set */
+extern int xdb_commands;
+
+/* enable dbx commands if set */
+extern int dbx_commands;
+
+/* System root path, used to find libraries etc. */
+extern char *gdb_sysroot;
+
+extern int quit_flag;
+extern int immediate_quit;
+extern int sevenbit_strings;
+
+extern void quit (void);
+
+/* FIXME: cagney/2000-03-13: It has been suggested that the peformance
+ benefits of having a ``QUIT'' macro rather than a function are
+ marginal. If the overhead of a QUIT function call is proving
+ significant then its calling frequency should probably be reduced
+ [kingdon]. A profile analyzing the current situtation is
+ needed. */
+
+#ifdef QUIT
+/* do twice to force compiler warning */
+#define QUIT_FIXME "FIXME"
+#define QUIT_FIXME "ignoring redefinition of QUIT"
+#else
+#define QUIT { \
+ if (quit_flag) quit (); \
+ if (interactive_hook) interactive_hook (); \
+}
+#endif
+
+/* 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_objc, /* Objective-C */
+ language_java, /* Java */
+ language_fortran, /* Fortran */
+ language_m2, /* Modula-2 */
+ language_asm, /* Assembly language */
+ language_scm, /* Scheme / Guile */
+ language_pascal, /* Pascal */
+ language_minimal /* All other languages, minimal support only */
+ };
+
+enum precision_type
+ {
+ single_precision,
+ double_precision,
+ unspecified_precision
+ };
+
+/* A generic, not quite boolean, enumeration. */
+enum auto_boolean
+{
+ AUTO_BOOLEAN_TRUE,
+ AUTO_BOOLEAN_FALSE,
+ AUTO_BOOLEAN_AUTO
+};
+
+/* Potential ways that a function can return a value of a given type. */
+enum return_value_convention
+{
+ /* Where the return value has been squeezed into one or more
+ registers. */
+ RETURN_VALUE_REGISTER_CONVENTION,
+ /* Commonly known as the "struct return convention". The caller
+ passes an additional hidden first parameter to the caller. That
+ parameter contains the address at which the value being returned
+ should be stored. While typically, and historically, used for
+ large structs, this is convention is applied to values of many
+ different types. */
+ RETURN_VALUE_STRUCT_CONVENTION
+};
+
+/* 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) (void *);
+ void *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__ == 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__ == 2 && __GNUC_MINOR__ >= 4))
+#define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y)))
+#else
+#define ATTR_FORMAT(type, x, y) /* nothing */
+#endif
+#endif
+
+/* Be conservative and use enum bitfields only with GCC.
+ This is copied from gcc 3.3.1, system.h. */
+
+#if defined(__GNUC__) && (__GNUC__ >= 2)
+#define ENUM_BITFIELD(TYPE) enum TYPE
+#else
+#define ENUM_BITFIELD(TYPE) unsigned int
+#endif
+
+/* Needed for various prototypes */
+
+struct symtab;
+struct breakpoint;
+struct frame_info;
+
+/* From blockframe.c */
+
+extern int inside_entry_func (struct frame_info *this_frame);
+
+extern int deprecated_inside_entry_file (CORE_ADDR addr);
+
+extern int inside_main_func (CORE_ADDR pc);
+
+/* From utils.c */
+
+extern void initialize_utils (void);
+
+extern void notice_quit (void);
+
+extern int strcmp_iw (const char *, const char *);
+
+extern int strcmp_iw_ordered (const char *, const char *);
+
+extern int streq (const char *, const char *);
+
+extern int subset_compare (char *, char *);
+
+extern char *safe_strerror (int);
+
+extern void init_malloc (void *);
+
+extern void request_quit (int);
+
+extern void do_cleanups (struct cleanup *);
+extern void do_final_cleanups (struct cleanup *);
+extern void do_run_cleanups (struct cleanup *);
+extern void do_exec_cleanups (struct cleanup *);
+extern void do_exec_error_cleanups (struct cleanup *);
+
+extern void discard_cleanups (struct cleanup *);
+extern void discard_final_cleanups (struct cleanup *);
+extern void discard_exec_error_cleanups (struct cleanup *);
+extern void discard_my_cleanups (struct cleanup **, struct cleanup *);
+
+/* NOTE: cagney/2000-03-04: This typedef is strictly for the
+ make_cleanup function declarations below. Do not use this typedef
+ as a cast when passing functions into the make_cleanup() code.
+ Instead either use a bounce function or add a wrapper function.
+ Calling a f(char*) function with f(void*) is non-portable. */
+typedef void (make_cleanup_ftype) (void *);
+
+extern struct cleanup *make_cleanup (make_cleanup_ftype *, void *);
+
+extern struct cleanup *make_cleanup_freeargv (char **);
+
+struct ui_file;
+extern struct cleanup *make_cleanup_ui_file_delete (struct ui_file *);
+
+extern struct cleanup *make_cleanup_close (int fd);
+
+extern struct cleanup *make_cleanup_bfd_close (bfd *abfd);
+
+extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *);
+
+extern struct cleanup *make_my_cleanup (struct cleanup **,
+ make_cleanup_ftype *, void *);
+
+extern struct cleanup *make_run_cleanup (make_cleanup_ftype *, void *);
+
+extern struct cleanup *make_exec_cleanup (make_cleanup_ftype *, void *);
+extern struct cleanup *make_exec_error_cleanup (make_cleanup_ftype *, void *);
+
+extern struct cleanup *save_cleanups (void);
+extern struct cleanup *save_final_cleanups (void);
+extern struct cleanup *save_my_cleanups (struct cleanup **);
+
+extern void restore_cleanups (struct cleanup *);
+extern void restore_final_cleanups (struct cleanup *);
+extern void restore_my_cleanups (struct cleanup **, struct cleanup *);
+
+extern void free_current_contents (void *);
+
+extern void null_cleanup (void *);
+
+extern int myread (int, char *, int);
+
+extern int query (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+extern int nquery (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+extern int yquery (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+
+extern void init_page_info (void);
+
+extern char *gdb_realpath (const char *);
+extern char *xfullpath (const char *);
+
+extern unsigned long gnu_debuglink_crc32 (unsigned long crc,
+ unsigned char *buf, size_t len);
+
+/* From demangle.c */
+
+extern void set_demangling_style (char *);
+
+/* From tm.h */
+
+struct type;
+typedef int (use_struct_convention_fn) (int gcc_p, struct type * value_type);
+extern use_struct_convention_fn generic_use_struct_convention;
+
+
+/* Annotation stuff. */
+
+extern int annotation_level; /* in stack.c */
+
+extern void begin_line (void);
+
+extern void wrap_here (char *);
+
+extern void reinitialize_more_filter (void);
+
+/* Normal results */
+extern struct ui_file *gdb_stdout;
+/* Input stream */
+extern struct ui_file *gdb_stdin;
+/* Serious error notifications */
+extern struct ui_file *gdb_stderr;
+/* Log/debug/trace messages that should bypass normal stdout/stderr
+ filtering. For moment, always call this stream using
+ *_unfiltered. In the very near future that restriction shall be
+ removed - either call shall be unfiltered. (cagney 1999-06-13). */
+extern struct ui_file *gdb_stdlog;
+/* Target output that should bypass normal stdout/stderr filtering.
+ For moment, always call this stream using *_unfiltered. In the
+ very near future that restriction shall be removed - either call
+ shall be unfiltered. (cagney 1999-07-02). */
+extern struct ui_file *gdb_stdtarg;
+extern struct ui_file *gdb_stdtargerr;
+extern struct ui_file *gdb_stdtargin;
+
+#include "ui-file.h"
+
+/* More generic printf like operations. Filtered versions may return
+ non-locally on error. */
+
+extern void fputs_filtered (const char *, struct ui_file *);
+
+extern void fputs_unfiltered (const char *, struct ui_file *);
+
+extern int fputc_filtered (int c, struct ui_file *);
+
+extern int fputc_unfiltered (int c, struct ui_file *);
+
+extern int putchar_filtered (int c);
+
+extern int putchar_unfiltered (int c);
+
+extern void puts_filtered (const char *);
+
+extern void puts_unfiltered (const char *);
+
+extern void puts_filtered_tabular (char *string, int width, int right);
+
+extern void puts_debug (char *prefix, char *string, char *suffix);
+
+extern void vprintf_filtered (const char *, va_list) ATTR_FORMAT (printf, 1, 0);
+
+extern void vfprintf_filtered (struct ui_file *, const char *, va_list) ATTR_FORMAT (printf, 2, 0);
+
+extern void fprintf_filtered (struct ui_file *, const char *, ...) ATTR_FORMAT (printf, 2, 3);
+
+extern void fprintfi_filtered (int, struct ui_file *, const char *, ...) ATTR_FORMAT (printf, 3, 4);
+
+extern void printf_filtered (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+
+extern void printfi_filtered (int, const char *, ...) ATTR_FORMAT (printf, 2, 3);
+
+extern void vprintf_unfiltered (const char *, va_list) ATTR_FORMAT (printf, 1, 0);
+
+extern void vfprintf_unfiltered (struct ui_file *, const char *, va_list) ATTR_FORMAT (printf, 2, 0);
+
+extern void fprintf_unfiltered (struct ui_file *, const char *, ...) ATTR_FORMAT (printf, 2, 3);
+
+extern void printf_unfiltered (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+
+extern void print_spaces (int, struct ui_file *);
+
+extern void print_spaces_filtered (int, struct ui_file *);
+
+extern char *n_spaces (int);
+
+extern void fputstr_filtered (const char *str, int quotr, struct ui_file * stream);
+
+extern void fputstr_unfiltered (const char *str, int quotr, struct ui_file * stream);
+
+extern void fputstrn_unfiltered (const char *str, int n, int quotr, struct ui_file * stream);
+
+/* Display the host ADDR on STREAM formatted as ``0x%x''. */
+extern void gdb_print_host_address (const void *addr, struct ui_file *stream);
+
+/* Convert a CORE_ADDR into a HEX string. paddr() is like %08lx.
+ paddr_nz() is like %lx. paddr_u() is like %lu. paddr_width() is
+ for ``%*''. */
+extern int strlen_paddr (void);
+extern char *paddr (CORE_ADDR addr);
+extern char *paddr_nz (CORE_ADDR addr);
+extern char *paddr_u (CORE_ADDR addr);
+extern char *paddr_d (LONGEST addr);
+
+extern char *phex (ULONGEST l, int sizeof_l);
+extern char *phex_nz (ULONGEST l, int sizeof_l);
+
+/* Like paddr() only print/scan raw CORE_ADDR. The output from
+ core_addr_to_string() can be passed direct to
+ string_to_core_addr(). */
+extern const char *core_addr_to_string (const CORE_ADDR addr);
+extern const char *core_addr_to_string_nz (const CORE_ADDR addr);
+extern CORE_ADDR string_to_core_addr (const char *my_string);
+
+extern void fprintf_symbol_filtered (struct ui_file *, char *,
+ enum language, int);
+
+extern NORETURN void perror_with_name (const char *) ATTR_NORETURN;
+
+extern void print_sys_errmsg (const char *, int);
+
+/* From regex.c or libc. BSD 4.4 declares this with the argument type as
+ "const char *" in unistd.h, so we can't declare the argument
+ as "char *". */
+
+extern char *re_comp (const char *);
+
+/* From symfile.c */
+
+extern void symbol_file_command (char *, int);
+
+/* Remote targets may wish to use this as their load function. */
+extern void generic_load (char *name, int from_tty);
+
+/* Summarise a download */
+extern void print_transfer_performance (struct ui_file *stream,
+ unsigned long data_count,
+ unsigned long write_count,
+ unsigned long time_count);
+
+/* From top.c */
+
+typedef void initialize_file_ftype (void);
+
+extern char *skip_quoted (char *);
+
+extern char *gdb_readline (char *);
+
+extern char *gdb_readline_wrapper (char *);
+
+extern char *command_line_input (char *, int, char *);
+
+extern void print_prompt (void);
+
+extern int input_from_terminal_p (void);
+
+extern int info_verbose;
+
+/* From printcmd.c */
+
+extern void set_next_address (CORE_ADDR);
+
+extern void print_address_symbolic (CORE_ADDR, struct ui_file *, int,
+ char *);
+
+extern int build_address_symbolic (CORE_ADDR addr,
+ int do_demangle,
+ char **name,
+ int *offset,
+ char **filename,
+ int *line,
+ int *unmapped);
+
+extern void print_address_numeric (CORE_ADDR, int, struct ui_file *);
+
+extern void print_address (CORE_ADDR, struct ui_file *);
+
+/* From source.c */
+
+extern int openp (const char *, int, const char *, int, int, char **);
+
+extern int source_full_path_of (char *, char **);
+
+extern void mod_path (char *, char **);
+
+extern void add_path (char *, char **, int);
+
+extern void directory_command (char *, int);
+
+extern char *source_path;
+
+extern void init_source_path (void);
+
+extern void init_last_source_visited (void);
+
+extern char *symtab_to_filename (struct symtab *);
+
+/* From exec.c */
+
+extern void exec_set_section_offsets (bfd_signed_vma text_off,
+ bfd_signed_vma data_off,
+ bfd_signed_vma bss_off);
+
+/* Take over the 'find_mapped_memory' vector from exec.c. */
+extern void exec_set_find_memory_regions (int (*) (int (*) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *));
+
+/* Possible lvalue types. Like enum language, this should be in
+ value.h, but needs to be here for the same reason. */
+
+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
+ };
+
+/* 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 (char *, int);
+
+extern void free_command_lines (struct command_line **);
+
+/* To continue the execution commands when running gdb asynchronously.
+ A continuation structure contains a pointer to a function to be called
+ to finish the command, once the target has stopped. Such mechanism is
+ used bt the finish and until commands, and in the remote protocol
+ when opening an extended-remote connection. */
+
+struct continuation_arg
+ {
+ struct continuation_arg *next;
+ union continuation_data {
+ void *pointer;
+ int integer;
+ long longint;
+ } data;
+ };
+
+struct continuation
+ {
+ void (*continuation_hook) (struct continuation_arg *);
+ struct continuation_arg *arg_list;
+ struct continuation *next;
+ };
+
+/* In infrun.c. */
+extern struct continuation *cmd_continuation;
+/* Used only by the step_1 function. */
+extern struct continuation *intermediate_continuation;
+
+/* From utils.c */
+extern void add_continuation (void (*)(struct continuation_arg *),
+ struct continuation_arg *);
+extern void do_all_continuations (void);
+extern void discard_all_continuations (void);
+
+extern void add_intermediate_continuation (void (*)(struct continuation_arg *),
+ struct continuation_arg *);
+extern void do_all_intermediate_continuations (void);
+extern void discard_all_intermediate_continuations (void);
+
+/* 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
+ };
+
+/* The ptid struct is a collection of the various "ids" necessary
+ for identifying the inferior. This consists of the process id
+ (pid), thread id (tid), and other fields necessary for uniquely
+ identifying the inferior process/thread being debugged. When
+ manipulating ptids, the constructors, accessors, and predicate
+ declared in inferior.h should be used. These are as follows:
+
+ ptid_build - Make a new ptid from a pid, lwp, and tid.
+ pid_to_ptid - Make a new ptid from just a pid.
+ ptid_get_pid - Fetch the pid component of a ptid.
+ ptid_get_lwp - Fetch the lwp component of a ptid.
+ ptid_get_tid - Fetch the tid component of a ptid.
+ ptid_equal - Test to see if two ptids are equal.
+
+ Please do NOT access the struct ptid members directly (except, of
+ course, in the implementation of the above ptid manipulation
+ functions). */
+
+struct ptid
+ {
+ /* Process id */
+ int pid;
+
+ /* Lightweight process id */
+ long lwp;
+
+ /* Thread id */
+ long tid;
+ };
+
+typedef struct ptid ptid_t;
+
+
+
+/* Optional host machine definition. Pure autoconf targets will not
+ need a "xm.h" file. This will be a symlink to one of the xm-*.h
+ files, built by the `configure' script. */
+
+#ifdef GDB_XM_FILE
+#include "xm.h"
+#endif
+
+/* Optional native machine support. Non-native (and possibly pure
+ multi-arch) targets do not need a "nm.h" file. This will be a
+ symlink to one of the nm-*.h files, built by the `configure'
+ script. */
+
+#ifdef GDB_NM_FILE
+#include "nm.h"
+#endif
+
+/* Optional target machine definition. Pure multi-arch configurations
+ do not need a "tm.h" file. This will be a symlink to one of the
+ tm-*.h files, built by the `configure' script. */
+
+#ifdef GDB_TM_FILE
+#include "tm.h"
+#endif
+
+/* 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
+
+/* Defaults for system-wide constants (if not defined by xm.h, we fake it).
+ FIXME: Assumes 2's complement arithmetic */
+
+#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)((int) ~0 ^ INT_MAX)) /* 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
+
+#if !defined (ULONGEST_MAX)
+#define ULONGEST_MAX (~(ULONGEST)0) /* 0xFFFFFFFFFFFFFFFF for 64-bits */
+#endif
+
+#if !defined (LONGEST_MAX) /* 0x7FFFFFFFFFFFFFFF for 64-bits */
+#define LONGEST_MAX ((LONGEST)(ULONGEST_MAX >> 1))
+#endif
+
+/* 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 (LONGEST);
+
+/* Assorted functions we can declare, now that const and volatile are
+ defined. */
+
+extern char *savestring (const char *, size_t);
+
+extern char *msavestring (void *, const char *, size_t);
+
+extern char *mstrsave (void *, const char *);
+
+/* Robust versions of same. Throw an internal error when no memory,
+ guard against stray NULL arguments. */
+extern void *xmmalloc (void *md, size_t size);
+extern void *xmrealloc (void *md, void *ptr, size_t size);
+extern void *xmcalloc (void *md, size_t number, size_t size);
+extern void xmfree (void *md, void *ptr);
+
+/* xmalloc(), xrealloc() and xcalloc() have already been declared in
+ "libiberty.h". */
+extern void xfree (void *);
+
+/* Utility macros to allocate typed memory. Avoids errors like:
+ struct foo *foo = xmalloc (sizeof struct bar); and memset (foo,
+ sizeof (struct foo), 0). */
+#define XZALLOC(TYPE) ((TYPE*) memset (xmalloc (sizeof (TYPE)), 0, sizeof (TYPE)))
+#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
+#define XCALLOC(NMEMB, TYPE) ((TYPE*) xcalloc ((NMEMB), sizeof (TYPE)))
+
+/* Like asprintf/vasprintf but get an internal_error if the call
+ fails. */
+extern void xasprintf (char **ret, const char *format, ...) ATTR_FORMAT (printf, 2, 3);
+extern void xvasprintf (char **ret, const char *format, va_list ap);
+
+/* Like asprintf, but return the string, throw an error if no memory. */
+extern char *xstrprintf (const char *format, ...) ATTR_FORMAT (printf, 1, 2);
+
+extern int parse_escape (char **);
+
+/* Message to be printed before the error message, when an error occurs. */
+
+extern char *error_pre_print;
+
+/* Message to be printed before the error message, when an error occurs. */
+
+extern char *quit_pre_print;
+
+/* Message to be printed before the warning message, when a warning occurs. */
+
+extern char *warning_pre_print;
+
+extern NORETURN void verror (const char *fmt, va_list ap) ATTR_NORETURN;
+
+extern NORETURN void error (const char *fmt, ...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
+
+extern NORETURN void error_silent (const char *fmt, ...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
+
+extern NORETURN void error_stream (struct ui_file *) ATTR_NORETURN;
+
+/* Initialize the error buffer. */
+extern void error_init (void);
+
+/* Returns a freshly allocate buffer containing the last error
+ message. */
+extern char *error_last_message (void);
+
+/* Output arbitrary error message. */
+extern void error_output_message (char *pre_print, char *msg);
+
+extern NORETURN void internal_verror (const char *file, int line,
+ const char *, va_list ap) ATTR_NORETURN;
+
+extern NORETURN void internal_error (const char *file, int line,
+ const char *, ...) ATTR_NORETURN ATTR_FORMAT (printf, 3, 4);
+
+extern void internal_vwarning (const char *file, int line,
+ const char *, va_list ap);
+
+extern void internal_warning (const char *file, int line,
+ const char *, ...) ATTR_FORMAT (printf, 3, 4);
+
+extern NORETURN void nomem (long) ATTR_NORETURN;
+
+/* Reasons for calling throw_exception(). NOTE: all reason values
+ must be less than zero. enum value 0 is reserved for internal use
+ as the return value from an initial setjmp(). The function
+ catch_exceptions() reserves values >= 0 as legal results from its
+ wrapped function. */
+
+enum return_reason
+ {
+ /* User interrupt. */
+ RETURN_QUIT = -2,
+ /* Any other error. */
+ RETURN_ERROR
+ };
+
+#define ALL_CLEANUPS ((struct cleanup *)0)
+
+#define RETURN_MASK(reason) (1 << (int)(-reason))
+#define RETURN_MASK_QUIT RETURN_MASK (RETURN_QUIT)
+#define RETURN_MASK_ERROR RETURN_MASK (RETURN_ERROR)
+#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
+typedef int return_mask;
+
+/* Throw an exception of type RETURN_REASON. Will execute a LONG JUMP
+ to the inner most containing exception handler established using
+ catch_exceptions() (or the legacy catch_errors()).
+
+ Code normally throws an exception using error() et.al. For various
+ reaons, GDB also contains code that throws an exception directly.
+ For instance, the remote*.c targets contain CNTRL-C signal handlers
+ that propogate the QUIT event up the exception chain. ``This could
+ be a good thing or a dangerous thing.'' -- the Existential Wombat. */
+
+extern NORETURN void throw_exception (enum return_reason) ATTR_NORETURN;
+
+/* Call FUNC(UIOUT, FUNC_ARGS) but wrapped within an exception
+ handler. If an exception (enum return_reason) is thrown using
+ throw_exception() than all cleanups installed since
+ catch_exceptions() was entered are invoked, the (-ve) exception
+ value is then returned by catch_exceptions. If FUNC() returns
+ normally (with a postive or zero return value) then that value is
+ returned by catch_exceptions(). It is an internal_error() for
+ FUNC() to return a negative value.
+
+ For the period of the FUNC() call: UIOUT is installed as the output
+ builder; ERRSTRING is installed as the error/quit message; and a
+ new cleanup_chain is established. The old values are restored
+ before catch_exceptions() returns.
+
+ The variant catch_exceptions_with_msg() is the same as
+ catch_exceptions() but adds the ability to return an allocated
+ copy of the gdb error message. This is used when a silent error is
+ issued and the caller wants to manually issue the error message.
+
+ FIXME; cagney/2001-08-13: The need to override the global UIOUT
+ builder variable should just go away.
+
+ This function superseeds catch_errors().
+
+ This function uses SETJMP() and LONGJUMP(). */
+
+struct ui_out;
+typedef int (catch_exceptions_ftype) (struct ui_out *ui_out, void *args);
+extern int catch_exceptions (struct ui_out *uiout,
+ catch_exceptions_ftype *func, void *func_args,
+ char *errstring, return_mask mask);
+extern int catch_exceptions_with_msg (struct ui_out *uiout,
+ catch_exceptions_ftype *func,
+ void *func_args,
+ char *errstring, char **gdberrmsg,
+ return_mask mask);
+
+/* If CATCH_ERRORS_FTYPE throws an error, catch_errors() returns zero
+ otherwize the result from CATCH_ERRORS_FTYPE is returned. It is
+ probably useful for CATCH_ERRORS_FTYPE to always return a non-zero
+ value. It's unfortunate that, catch_errors() does not return an
+ indication of the exact exception that it caught - quit_flag might
+ help.
+
+ This function is superseeded by catch_exceptions(). */
+
+typedef int (catch_errors_ftype) (void *);
+extern int catch_errors (catch_errors_ftype *, void *, char *, return_mask);
+
+/* Template to catch_errors() that wraps calls to command
+ functions. */
+
+typedef void (catch_command_errors_ftype) (char *, int);
+extern int catch_command_errors (catch_command_errors_ftype *func, char *command, int from_tty, return_mask);
+
+extern void warning (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+
+extern void vwarning (const char *, va_list args);
+
+/* List of known OS ABIs. If you change this, make sure to update the
+ table in osabi.c. */
+enum gdb_osabi
+{
+ GDB_OSABI_UNINITIALIZED = -1, /* For struct gdbarch_info. */
+
+ GDB_OSABI_UNKNOWN = 0, /* keep this zero */
+
+ GDB_OSABI_SVR4,
+ GDB_OSABI_HURD,
+ GDB_OSABI_SOLARIS,
+ GDB_OSABI_OSF1,
+ GDB_OSABI_LINUX,
+ GDB_OSABI_FREEBSD_AOUT,
+ GDB_OSABI_FREEBSD_ELF,
+ GDB_OSABI_NETBSD_AOUT,
+ GDB_OSABI_NETBSD_ELF,
+ GDB_OSABI_OPENBSD_ELF,
+ GDB_OSABI_WINCE,
+ GDB_OSABI_GO32,
+ GDB_OSABI_NETWARE,
+ GDB_OSABI_IRIX,
+ GDB_OSABI_LYNXOS,
+ GDB_OSABI_INTERIX,
+ GDB_OSABI_HPUX_ELF,
+ GDB_OSABI_HPUX_SOM,
+
+ GDB_OSABI_ARM_EABI_V1,
+ GDB_OSABI_ARM_EABI_V2,
+ GDB_OSABI_ARM_APCS,
+ GDB_OSABI_QNXNTO,
+
+ GDB_OSABI_CYGWIN,
+
+ GDB_OSABI_INVALID /* keep this last */
+};
+
+/* 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 (const char *);
+#endif
+
+/* From other system libraries */
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#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 (FILE *);
+#endif
+
+#ifndef atof
+extern double atof (const char *); /* X3.159-1989 4.10.1.1 */
+#endif
+
+/* Various possibilities for alloca. */
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* Not GNU C */
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+#pragma alloca
+#else
+
+/* 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 *. */
+extern void *alloca ();
+#endif /* Not _AIX */
+#endif /* Not HAVE_ALLOCA_H */
+#endif /* Not GNU C */
+#endif /* alloca not defined */
+
+/* Is GDB multi-arch? If there's a "tm.h" file, it is not. */
+#ifndef GDB_MULTI_ARCH
+#ifdef GDB_TM_FILE
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_PARTIAL
+#else
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_PURE
+#endif
+#endif
+
+/* Dynamic target-system-dependent parameters for GDB. */
+#include "gdbarch.h"
+
+/* Maximum size of a register. Something small, but large enough for
+ all known ISAs. If it turns out to be too small, make it bigger. */
+
+enum { MAX_REGISTER_SIZE = 16 };
+
+/* Static target-system-dependent parameters for GDB. */
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) 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)
+#define BITS_BIG_ENDIAN (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+#endif
+
+/* In findvar.c. */
+
+extern LONGEST extract_signed_integer (const void *, int);
+
+extern ULONGEST extract_unsigned_integer (const void *, int);
+
+extern int extract_long_unsigned_integer (const void *, int, LONGEST *);
+
+extern CORE_ADDR extract_typed_address (const void *buf, struct type *type);
+
+extern void store_signed_integer (void *, int, LONGEST);
+
+extern void store_unsigned_integer (void *, int, ULONGEST);
+
+extern void store_typed_address (void *buf, struct type *type, CORE_ADDR addr);
+
+
+/* From valops.c */
+
+extern CORE_ADDR push_bytes (CORE_ADDR, char *, int);
+
+extern CORE_ADDR push_word (CORE_ADDR, ULONGEST);
+
+extern int watchdog;
+
+/* Hooks for alternate command interfaces. */
+
+/* The name of the interpreter if specified on the command line. */
+extern char *interpreter_p;
+
+/* If a given interpreter matches INTERPRETER_P then it should update
+ command_loop_hook and init_ui_hook with the per-interpreter
+ implementation. */
+/* FIXME: command_loop_hook and init_ui_hook should be moved here. */
+
+struct target_waitstatus;
+struct cmd_list_element;
+
+/* Should the asynchronous variant of the interpreter (using the
+ event-loop) be enabled? */
+extern int event_loop_p;
+
+extern void (*init_ui_hook) (char *argv0);
+extern void (*command_loop_hook) (void);
+extern void (*show_load_progress) (const char *section,
+ unsigned long section_sent,
+ unsigned long section_size,
+ unsigned long total_sent,
+ unsigned long total_size);
+extern void (*print_frame_info_listing_hook) (struct symtab * s,
+ int line, int stopline,
+ int noerror);
+extern struct frame_info *parse_frame_specification (char *frame_exp);
+extern int (*query_hook) (const char *, va_list);
+extern void (*warning_hook) (const char *, va_list);
+extern void (*flush_hook) (struct ui_file * stream);
+extern void (*create_breakpoint_hook) (struct breakpoint * b);
+extern void (*delete_breakpoint_hook) (struct breakpoint * bpt);
+extern void (*modify_breakpoint_hook) (struct breakpoint * bpt);
+extern void (*interactive_hook) (void);
+extern void (*registers_changed_hook) (void);
+extern void (*readline_begin_hook) (char *,...);
+extern char *(*readline_hook) (char *);
+extern void (*readline_end_hook) (void);
+extern void (*register_changed_hook) (int regno);
+extern void (*memory_changed_hook) (CORE_ADDR addr, int len);
+extern void (*context_hook) (int);
+extern ptid_t (*target_wait_hook) (ptid_t ptid,
+ struct target_waitstatus * status);
+
+extern void (*attach_hook) (void);
+extern void (*detach_hook) (void);
+extern void (*call_command_hook) (struct cmd_list_element * c,
+ char *cmd, int from_tty);
+
+extern void (*set_hook) (struct cmd_list_element * c);
+
+extern NORETURN void (*error_hook) (void) ATTR_NORETURN;
+
+extern void (*error_begin_hook) (void);
+
+extern int (*ui_load_progress_hook) (const char *section, unsigned long num);
+
+
+/* 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_STRING
+#define SLASH_STRING "/"
+#endif
+
+#ifdef __MSDOS__
+# define CANT_FORK
+# define GLOBAL_CURDIR
+#endif
+
+/* Provide default definitions of PIDGET, TIDGET, and MERGEPID.
+ The name ``TIDGET'' is a historical accident. Many uses of TIDGET
+ in the code actually refer to a lightweight process id, i.e,
+ something that can be considered a process id in its own right for
+ certain purposes. */
+
+#ifndef PIDGET
+#define PIDGET(PTID) (ptid_get_pid (PTID))
+#define TIDGET(PTID) (ptid_get_lwp (PTID))
+#define MERGEPID(PID, TID) ptid_build (PID, TID, 0)
+#endif
+
+/* Define well known filenos if the system does not define them. */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+/* 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
+
+/* Ensure that V is aligned to an N byte boundary (B's assumed to be a
+ power of 2). Round up/down when necessary. Examples of correct
+ use include:
+
+ addr = align_up (addr, 8); -- VALUE needs 8 byte alignment
+ write_memory (addr, value, len);
+ addr += len;
+
+ and:
+
+ sp = align_down (sp - len, 16); -- Keep SP 16 byte aligned
+ write_memory (sp, value, len);
+
+ Note that uses such as:
+
+ write_memory (addr, value, len);
+ addr += align_up (len, 8);
+
+ and:
+
+ sp -= align_up (len, 8);
+ write_memory (sp, value, len);
+
+ are typically not correct as they don't ensure that the address (SP
+ or ADDR) is correctly aligned (relying on previous alignment to
+ keep things right). This is also why the methods are called
+ "align_..." instead of "round_..." as the latter reads better with
+ this incorrect coding style. */
+
+extern ULONGEST align_up (ULONGEST v, int n);
+extern ULONGEST align_down (ULONGEST v, int n);
+
+#endif /* #ifndef DEFS_H */
diff --git a/contrib/gdb/gdb/delta68-nat.c b/contrib/gdb/gdb/delta68-nat.c
new file mode 100644
index 0000000..e74a51b
--- /dev/null
+++ b/contrib/gdb/gdb/delta68-nat.c
@@ -0,0 +1,90 @@
+/* Functions specific to running gdb native on a Motorola Delta Series sysV68.
+ Copyright 1993, 1996, 1998, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <sys/signal.h> /* for MAXSIG in sys/user.h */
+#include <sys/types.h> /* for ushort in sys/dir.h */
+#include <sys/dir.h> /* for struct direct in sys/user.h */
+#include <sys/user.h>
+
+#include <nlist.h>
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* Return the address in the core dump or inferior of register REGNO.
+ BLOCKEND is the address of the end of the user structure. */
+
+CORE_ADDR
+register_addr (int regno, CORE_ADDR blockend)
+{
+ static int sysv68reg[] =
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, 15, 16};
+
+ if (regno >= 0 && regno < sizeof (sysv68reg) / sizeof (sysv68reg[0]))
+ return blockend + sysv68reg[regno] * 4;
+ else if (regno < FPC_REGNUM)
+ return offsetof (struct user, u_fpu.regs.reg[regno - FP0_REGNUM][0]);
+ else if (regno == FPC_REGNUM)
+ return offsetof (struct user, u_fpu.regs.control);
+ else if (regno == FPS_REGNUM)
+ return offsetof (struct user, u_fpu.regs.status);
+ else if (regno == FPI_REGNUM)
+ return offsetof (struct user, u_fpu.regs.iaddr);
+ else
+ {
+ fprintf_unfiltered (gdb_stderr, "\
+Internal error: invalid register number %d in REGISTER_U_ADDR\n",
+ regno);
+ return blockend;
+ }
+}
+
+CORE_ADDR kernel_u_addr;
+
+/* Read the value of the u area from the kernel. */
+void
+_initialize_delta68_nat (void)
+{
+ struct nlist nl[2];
+
+ nl[0].n_name = "u";
+ nl[1].n_name = NULL;
+ if (nlist ("/sysV68", nl) == 0 && nl[0].n_scnum != 0)
+ kernel_u_addr = nl[0].n_value;
+ else
+ {
+ perror ("Cannot get kernel u area address");
+ exit (1);
+ }
+}
+
+clear_insn_cache (void)
+{
+#ifdef MCT_TEXT /* in sys/signal.h on sysV68 R3V7.1 */
+ memctl (0, 4096, MCT_TEXT);
+#endif
+}
+
+kernel_u_size (void)
+{
+ return sizeof (struct user);
+}
diff --git a/contrib/gdb/gdb/demangle.c b/contrib/gdb/gdb/demangle.c
new file mode 100644
index 0000000..bcf9b77
--- /dev/null
+++ b/contrib/gdb/gdb/demangle.c
@@ -0,0 +1,203 @@
+/* Basic C++ demangling support for GDB.
+
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001, 2003 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", "hp", 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
+
+extern void _initialize_demangler (void);
+
+/* String name for the current demangling style. Set by the
+ "set demangle-style" command, printed as part of the output by the
+ "show demangle-style" command. */
+
+static char *current_demangling_style_string;
+
+/* The array of names of the known demanglyng styles. Generated by
+ _initialize_demangler from libiberty_demanglers[] array. */
+
+static const char **demangling_style_names;
+
+static void set_demangling_command (char *, int, struct cmd_list_element *);
+
+/* Set current demangling style. Called by the "set demangle-style"
+ 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 (char *ignore, int from_tty, struct cmd_list_element *c)
+{
+ const struct demangler_engine *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 = libiberty_demanglers;
+ dem->demangling_style != unknown_demangling;
+ dem++)
+ {
+ if (strcmp (current_demangling_style_string,
+ dem->demangling_style_name) == 0)
+ {
+ 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 == unknown_demangling)
+ {
+ 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 = libiberty_demanglers;
+ dem->demangling_style != unknown_demangling;
+ dem++)
+ {
+ printf_unfiltered ("%-10s %s\n", dem->demangling_style_name,
+ dem->demangling_style_doc);
+ if (dem->demangling_style == current_demangling_style)
+ {
+ xfree (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 = libiberty_demanglers[0].demangling_style;
+ current_demangling_style_string =
+ savestring (
+ libiberty_demanglers[0].demangling_style_name,
+ strlen (libiberty_demanglers[0].demangling_style_name));
+ warning ("`%s' style demangling chosen as the default.\n",
+ current_demangling_style_string);
+ }
+ }
+}
+
+/* Fake a "set demangle-style" command. */
+
+void
+set_demangling_style (char *style)
+{
+ if (current_demangling_style_string != NULL)
+ {
+ xfree (current_demangling_style_string);
+ }
+ current_demangling_style_string = savestring (style, strlen (style));
+ set_demangling_command ((char *) NULL, 0, (struct cmd_list_element *) NULL);
+}
+
+/* G++ uses a special character to indicate certain internal names. Which
+ character it is depends on the platform:
+ - Usually '$' on systems where the assembler will accept that
+ - Usually '.' otherwise (this includes most sysv4-like systems and most
+ ELF targets)
+ - Occasionally '_' if neither of the above is usable
+
+ We check '$' first because it is the safest, and '.' often has another
+ meaning. We don't currently try to handle '_' because the precise forms
+ of the names are different on those targets. */
+
+static char cplus_markers[] = {'$', '.', '\0'};
+
+int
+is_cplus_marker (int c)
+{
+ return c && strchr (cplus_markers, c) != NULL;
+}
+
+void
+_initialize_demangler (void)
+{
+ struct cmd_list_element *set, *show;
+ int i, ndems;
+
+ /* Fill the demangling_style_names[] array. */
+ for (ndems = 0;
+ libiberty_demanglers[ndems].demangling_style != unknown_demangling;
+ ndems++)
+ ;
+ demangling_style_names = xcalloc (ndems + 1, sizeof (char *));
+ for (i = 0;
+ libiberty_demanglers[i].demangling_style != unknown_demangling;
+ i++)
+ demangling_style_names[i] =
+ xstrdup (libiberty_demanglers[i].demangling_style_name);
+
+ set = add_set_enum_cmd ("demangle-style", class_support,
+ demangling_style_names,
+ (const char **) &current_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_cmd_sfunc (set, set_demangling_command);
+
+ /* Set the default demangling style chosen at compilation time. */
+ set_demangling_style (DEFAULT_DEMANGLING_STYLE);
+}
diff --git a/contrib/gdb/gdb/dictionary.c b/contrib/gdb/gdb/dictionary.c
new file mode 100644
index 0000000..5c085fe
--- /dev/null
+++ b/contrib/gdb/gdb/dictionary.c
@@ -0,0 +1,836 @@
+/* Routines for name->symbol lookups in GDB.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by David Carlton <carlton@bactrian.org> and by Kealia,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_obstack.h"
+#include "symtab.h"
+#include "buildsym.h"
+#include "gdb_assert.h"
+#include "dictionary.h"
+
+/* This file implements dictionaries, which are tables that associate
+ symbols to names. They are represented by an opaque type 'struct
+ dictionary'. That type has various internal implementations, which
+ you can choose between depending on what properties you need
+ (e.g. fast lookup, order-preserving, expandable).
+
+ Each dictionary starts with a 'virtual function table' that
+ contains the functions that actually implement the various
+ operations that dictionaries provide. (Note, however, that, for
+ the sake of client code, we also provide some functions that can be
+ implemented generically in terms of the functions in the vtable.)
+
+ To add a new dictionary implementation <impl>, what you should do
+ is:
+
+ * Add a new element DICT_<IMPL> to dict_type.
+
+ * Create a new structure dictionary_<impl>. If your new
+ implementation is a variant of an existing one, make sure that
+ their structs have the same initial data members. Define accessor
+ macros for your new data members.
+
+ * Implement all the functions in dict_vector as static functions,
+ whose name is the same as the corresponding member of dict_vector
+ plus _<impl>. You don't have to do this for those members where
+ you can reuse existing generic functions
+ (e.g. add_symbol_nonexpandable, free_obstack) or in the case where
+ your new implementation is a variant of an existing implementation
+ and where the variant doesn't affect the member function in
+ question.
+
+ * Define a static const struct dict_vector dict_<impl>_vector.
+
+ * Define a function dict_create_<impl> to create these
+ gizmos. Add its declaration to dictionary.h.
+
+ To add a new operation <op> on all existing implementations, what
+ you should do is:
+
+ * Add a new member <op> to struct dict_vector.
+
+ * If there is useful generic behavior <op>, define a static
+ function <op>_something_informative that implements that behavior.
+ (E.g. add_symbol_nonexpandable, free_obstack.)
+
+ * For every implementation <impl> that should have its own specific
+ behavior for <op>, define a static function <op>_<impl>
+ implementing it.
+
+ * Modify all existing dict_vector_<impl>'s to include the appropriate
+ member.
+
+ * Define a function dict_<op> that looks up <op> in the dict_vector
+ and calls the appropriate function. Add a declaration for
+ dict_<op> to dictionary.h.
+
+*/
+
+/* An enum representing the various implementations of dictionaries.
+ Used only for debugging. */
+
+enum dict_type
+ {
+ /* Symbols are stored in a fixed-size hash table. */
+ DICT_HASHED,
+ /* Symbols are stored in an expandable hash table. */
+ DICT_HASHED_EXPANDABLE,
+ /* Symbols are stored in a fixed-size array. */
+ DICT_LINEAR,
+ /* Symbols are stored in an expandable array. */
+ DICT_LINEAR_EXPANDABLE
+ };
+
+/* The virtual function table. */
+
+struct dict_vector
+{
+ /* The type of the dictionary. This is only here to make debugging
+ a bit easier; it's not actually used. */
+ enum dict_type type;
+ /* The function to free a dictionary. */
+ void (*free) (struct dictionary *dict);
+ /* Add a symbol to a dictionary, if possible. */
+ void (*add_symbol) (struct dictionary *dict, struct symbol *sym);
+ /* Iterator functions. */
+ struct symbol *(*iterator_first) (const struct dictionary *dict,
+ struct dict_iterator *iterator);
+ struct symbol *(*iterator_next) (struct dict_iterator *iterator);
+ /* Functions to iterate over symbols with a given name. */
+ struct symbol *(*iter_name_first) (const struct dictionary *dict,
+ const char *name,
+ struct dict_iterator *iterator);
+ struct symbol *(*iter_name_next) (const char *name,
+ struct dict_iterator *iterator);
+ /* A size function, for maint print symtabs. */
+ int (*size) (const struct dictionary *dict);
+};
+
+/* Now comes the structs used to store the data for different
+ implementations. If two implementations have data in common, put
+ the common data at the top of their structs, ordered in the same
+ way. */
+
+struct dictionary_hashed
+{
+ int nbuckets;
+ struct symbol **buckets;
+};
+
+struct dictionary_hashed_expandable
+{
+ /* How many buckets we currently have. */
+ int nbuckets;
+ struct symbol **buckets;
+ /* How many syms we currently have; we need this so we will know
+ when to add more buckets. */
+ int nsyms;
+};
+
+struct dictionary_linear
+{
+ int nsyms;
+ struct symbol **syms;
+};
+
+struct dictionary_linear_expandable
+{
+ /* How many symbols we currently have. */
+ int nsyms;
+ struct symbol **syms;
+ /* How many symbols we can store before needing to reallocate. */
+ int capacity;
+};
+
+/* And now, the star of our show. */
+
+struct dictionary
+{
+ const struct dict_vector *vector;
+ union
+ {
+ struct dictionary_hashed hashed;
+ struct dictionary_hashed_expandable hashed_expandable;
+ struct dictionary_linear linear;
+ struct dictionary_linear_expandable linear_expandable;
+ }
+ data;
+};
+
+/* Accessor macros. */
+
+#define DICT_VECTOR(d) (d)->vector
+
+/* These can be used for DICT_HASHED_EXPANDABLE, too. */
+
+#define DICT_HASHED_NBUCKETS(d) (d)->data.hashed.nbuckets
+#define DICT_HASHED_BUCKETS(d) (d)->data.hashed.buckets
+#define DICT_HASHED_BUCKET(d,i) DICT_HASHED_BUCKETS (d) [i]
+
+#define DICT_HASHED_EXPANDABLE_NSYMS(d) (d)->data.hashed_expandable.nsyms
+
+/* These can be used for DICT_LINEAR_EXPANDABLEs, too. */
+
+#define DICT_LINEAR_NSYMS(d) (d)->data.linear.nsyms
+#define DICT_LINEAR_SYMS(d) (d)->data.linear.syms
+#define DICT_LINEAR_SYM(d,i) DICT_LINEAR_SYMS (d) [i]
+
+#define DICT_LINEAR_EXPANDABLE_CAPACITY(d) \
+ (d)->data.linear_expandable.capacity
+
+/* The initial size of a DICT_*_EXPANDABLE dictionary. */
+
+#define DICT_EXPANDABLE_INITIAL_CAPACITY 10
+
+/* This calculates the number of buckets we'll use in a hashtable,
+ given the number of symbols that it will contain. */
+
+#define DICT_HASHTABLE_SIZE(n) ((n)/5 + 1)
+
+/* Accessor macros for dict_iterators; they're here rather than
+ dictionary.h because code elsewhere should treat dict_iterators as
+ opaque. */
+
+/* The dictionary that the iterator is associated to. */
+#define DICT_ITERATOR_DICT(iter) (iter)->dict
+/* For linear dictionaries, the index of the last symbol returned; for
+ hashed dictionaries, the bucket of the last symbol returned. */
+#define DICT_ITERATOR_INDEX(iter) (iter)->index
+/* For hashed dictionaries, this points to the last symbol returned;
+ otherwise, this is unused. */
+#define DICT_ITERATOR_CURRENT(iter) (iter)->current
+
+/* Declarations of functions for vectors. */
+
+/* Functions that might work across a range of dictionary types. */
+
+static void add_symbol_nonexpandable (struct dictionary *dict,
+ struct symbol *sym);
+
+static void free_obstack (struct dictionary *dict);
+
+/* Functions for DICT_HASHED and DICT_HASHED_EXPANDABLE
+ dictionaries. */
+
+static struct symbol *iterator_first_hashed (const struct dictionary *dict,
+ struct dict_iterator *iterator);
+
+static struct symbol *iterator_next_hashed (struct dict_iterator *iterator);
+
+static struct symbol *iter_name_first_hashed (const struct dictionary *dict,
+ const char *name,
+ struct dict_iterator *iterator);
+
+static struct symbol *iter_name_next_hashed (const char *name,
+ struct dict_iterator *iterator);
+
+/* Functions only for DICT_HASHED. */
+
+static int size_hashed (const struct dictionary *dict);
+
+/* Functions only for DICT_HASHED_EXPANDABLE. */
+
+static void free_hashed_expandable (struct dictionary *dict);
+
+static void add_symbol_hashed_expandable (struct dictionary *dict,
+ struct symbol *sym);
+
+static int size_hashed_expandable (const struct dictionary *dict);
+
+/* Functions for DICT_LINEAR and DICT_LINEAR_EXPANDABLE
+ dictionaries. */
+
+static struct symbol *iterator_first_linear (const struct dictionary *dict,
+ struct dict_iterator *iterator);
+
+static struct symbol *iterator_next_linear (struct dict_iterator *iterator);
+
+static struct symbol *iter_name_first_linear (const struct dictionary *dict,
+ const char *name,
+ struct dict_iterator *iterator);
+
+static struct symbol *iter_name_next_linear (const char *name,
+ struct dict_iterator *iterator);
+
+static int size_linear (const struct dictionary *dict);
+
+/* Functions only for DICT_LINEAR_EXPANDABLE. */
+
+static void free_linear_expandable (struct dictionary *dict);
+
+static void add_symbol_linear_expandable (struct dictionary *dict,
+ struct symbol *sym);
+
+/* Various vectors that we'll actually use. */
+
+static const struct dict_vector dict_hashed_vector =
+ {
+ DICT_HASHED, /* type */
+ free_obstack, /* free */
+ add_symbol_nonexpandable, /* add_symbol */
+ iterator_first_hashed, /* iteractor_first */
+ iterator_next_hashed, /* iterator_next */
+ iter_name_first_hashed, /* iter_name_first */
+ iter_name_next_hashed, /* iter_name_next */
+ size_hashed, /* size */
+ };
+
+static const struct dict_vector dict_hashed_expandable_vector =
+ {
+ DICT_HASHED_EXPANDABLE, /* type */
+ free_hashed_expandable, /* free */
+ add_symbol_hashed_expandable, /* add_symbol */
+ iterator_first_hashed, /* iteractor_first */
+ iterator_next_hashed, /* iterator_next */
+ iter_name_first_hashed, /* iter_name_first */
+ iter_name_next_hashed, /* iter_name_next */
+ size_hashed_expandable, /* size */
+ };
+
+static const struct dict_vector dict_linear_vector =
+ {
+ DICT_LINEAR, /* type */
+ free_obstack, /* free */
+ add_symbol_nonexpandable, /* add_symbol */
+ iterator_first_linear, /* iteractor_first */
+ iterator_next_linear, /* iterator_next */
+ iter_name_first_linear, /* iter_name_first */
+ iter_name_next_linear, /* iter_name_next */
+ size_linear, /* size */
+ };
+
+static const struct dict_vector dict_linear_expandable_vector =
+ {
+ DICT_LINEAR_EXPANDABLE, /* type */
+ free_linear_expandable, /* free */
+ add_symbol_linear_expandable, /* add_symbol */
+ iterator_first_linear, /* iteractor_first */
+ iterator_next_linear, /* iterator_next */
+ iter_name_first_linear, /* iter_name_first */
+ iter_name_next_linear, /* iter_name_next */
+ size_linear, /* size */
+ };
+
+/* Declarations of helper functions (i.e. ones that don't go into
+ vectors). */
+
+static struct symbol *iterator_hashed_advance (struct dict_iterator *iter);
+
+static void insert_symbol_hashed (struct dictionary *dict,
+ struct symbol *sym);
+
+static void expand_hashtable (struct dictionary *dict);
+
+/* The creation functions. */
+
+/* Create a dictionary implemented via a fixed-size hashtable. All
+ memory it uses is allocated on OBSTACK; the environment is
+ initialized from SYMBOL_LIST. */
+
+struct dictionary *
+dict_create_hashed (struct obstack *obstack,
+ const struct pending *symbol_list)
+{
+ struct dictionary *retval;
+ int nsyms = 0, nbuckets, i;
+ struct symbol **buckets;
+ const struct pending *list_counter;
+
+ retval = obstack_alloc (obstack, sizeof (struct dictionary));
+ DICT_VECTOR (retval) = &dict_hashed_vector;
+
+ /* Calculate the number of symbols, and allocate space for them. */
+ for (list_counter = symbol_list;
+ list_counter != NULL;
+ list_counter = list_counter->next)
+ {
+ nsyms += list_counter->nsyms;
+ }
+ nbuckets = DICT_HASHTABLE_SIZE (nsyms);
+ DICT_HASHED_NBUCKETS (retval) = nbuckets;
+ buckets = obstack_alloc (obstack, nbuckets * sizeof (struct symbol *));
+ memset (buckets, 0, nbuckets * sizeof (struct symbol *));
+ DICT_HASHED_BUCKETS (retval) = buckets;
+
+ /* Now fill the buckets. */
+ for (list_counter = symbol_list;
+ list_counter != NULL;
+ list_counter = list_counter->next)
+ {
+ for (i = list_counter->nsyms - 1; i >= 0; --i)
+ {
+ insert_symbol_hashed (retval, list_counter->symbol[i]);
+ }
+ }
+
+ return retval;
+}
+
+/* Create a dictionary implemented via a hashtable that grows as
+ necessary. The dictionary is initially empty; to add symbols to
+ it, call dict_add_symbol(). Call dict_free() when you're done with
+ it. */
+
+extern struct dictionary *
+dict_create_hashed_expandable (void)
+{
+ struct dictionary *retval;
+
+ retval = xmalloc (sizeof (struct dictionary));
+ DICT_VECTOR (retval) = &dict_hashed_expandable_vector;
+ DICT_HASHED_NBUCKETS (retval) = DICT_EXPANDABLE_INITIAL_CAPACITY;
+ DICT_HASHED_BUCKETS (retval) = xcalloc (DICT_EXPANDABLE_INITIAL_CAPACITY,
+ sizeof (struct symbol *));
+ DICT_HASHED_EXPANDABLE_NSYMS (retval) = 0;
+
+ return retval;
+}
+
+/* Create a dictionary implemented via a fixed-size array. All memory
+ it uses is allocated on OBSTACK; the environment is initialized
+ from the SYMBOL_LIST. The symbols are ordered in the same order
+ that they're found in SYMBOL_LIST. */
+
+struct dictionary *
+dict_create_linear (struct obstack *obstack,
+ const struct pending *symbol_list)
+{
+ struct dictionary *retval;
+ int nsyms = 0, i, j;
+ struct symbol **syms;
+ const struct pending *list_counter;
+
+ retval = obstack_alloc (obstack, sizeof (struct dictionary));
+ DICT_VECTOR (retval) = &dict_linear_vector;
+
+ /* Calculate the number of symbols, and allocate space for them. */
+ for (list_counter = symbol_list;
+ list_counter != NULL;
+ list_counter = list_counter->next)
+ {
+ nsyms += list_counter->nsyms;
+ }
+ DICT_LINEAR_NSYMS (retval) = nsyms;
+ syms = obstack_alloc (obstack, nsyms * sizeof (struct symbol *));
+ DICT_LINEAR_SYMS (retval) = syms;
+
+ /* Now fill in the symbols. Start filling in from the back, so as
+ to preserve the original order of the symbols. */
+ for (list_counter = symbol_list, j = nsyms - 1;
+ list_counter != NULL;
+ list_counter = list_counter->next)
+ {
+ for (i = list_counter->nsyms - 1;
+ i >= 0;
+ --i, --j)
+ {
+ syms[j] = list_counter->symbol[i];
+ }
+ }
+
+ return retval;
+}
+
+/* Create a dictionary implemented via an array that grows as
+ necessary. The dictionary is initially empty; to add symbols to
+ it, call dict_add_symbol(). Call dict_free() when you're done with
+ it. */
+
+struct dictionary *
+dict_create_linear_expandable (void)
+{
+ struct dictionary *retval;
+
+ retval = xmalloc (sizeof (struct dictionary));
+ DICT_VECTOR (retval) = &dict_linear_expandable_vector;
+ DICT_LINEAR_NSYMS (retval) = 0;
+ DICT_LINEAR_EXPANDABLE_CAPACITY (retval)
+ = DICT_EXPANDABLE_INITIAL_CAPACITY;
+ DICT_LINEAR_SYMS (retval)
+ = xmalloc (DICT_LINEAR_EXPANDABLE_CAPACITY (retval)
+ * sizeof (struct symbol *));
+
+ return retval;
+}
+
+/* The functions providing the dictionary interface. */
+
+/* Free the memory used by a dictionary that's not on an obstack. (If
+ any.) */
+
+void
+dict_free (struct dictionary *dict)
+{
+ (DICT_VECTOR (dict))->free (dict);
+}
+
+/* Add SYM to DICT. DICT had better be expandable. */
+
+void
+dict_add_symbol (struct dictionary *dict, struct symbol *sym)
+{
+ (DICT_VECTOR (dict))->add_symbol (dict, sym);
+}
+
+/* Initialize ITERATOR to point at the first symbol in DICT, and
+ return that first symbol, or NULL if DICT is empty. */
+
+struct symbol *
+dict_iterator_first (const struct dictionary *dict,
+ struct dict_iterator *iterator)
+{
+ return (DICT_VECTOR (dict))->iterator_first (dict, iterator);
+}
+
+/* Advance ITERATOR, and return the next symbol, or NULL if there are
+ no more symbols. */
+
+struct symbol *
+dict_iterator_next (struct dict_iterator *iterator)
+{
+ return (DICT_VECTOR (DICT_ITERATOR_DICT (iterator)))
+ ->iterator_next (iterator);
+}
+
+struct symbol *
+dict_iter_name_first (const struct dictionary *dict,
+ const char *name,
+ struct dict_iterator *iterator)
+{
+ return (DICT_VECTOR (dict))->iter_name_first (dict, name, iterator);
+}
+
+struct symbol *
+dict_iter_name_next (const char *name, struct dict_iterator *iterator)
+{
+ return (DICT_VECTOR (DICT_ITERATOR_DICT (iterator)))
+ ->iter_name_next (name, iterator);
+}
+
+int
+dict_size (const struct dictionary *dict)
+{
+ return (DICT_VECTOR (dict))->size (dict);
+}
+
+/* Now come functions (well, one function, currently) that are
+ implemented generically by means of the vtable. Typically, they're
+ rarely used. */
+
+/* Test to see if DICT is empty. */
+
+int
+dict_empty (struct dictionary *dict)
+{
+ struct dict_iterator iter;
+
+ return (dict_iterator_first (dict, &iter) == NULL);
+}
+
+
+/* The functions implementing the dictionary interface. */
+
+/* Generic functions, where appropriate. */
+
+static void
+free_obstack (struct dictionary *dict)
+{
+ /* Do nothing! */
+}
+
+static void
+add_symbol_nonexpandable (struct dictionary *dict, struct symbol *sym)
+{
+ internal_error (__FILE__, __LINE__,
+ "dict_add_symbol: non-expandable dictionary");
+}
+
+/* Functions for DICT_HASHED and DICT_HASHED_EXPANDABLE. */
+
+static struct symbol *
+iterator_first_hashed (const struct dictionary *dict,
+ struct dict_iterator *iterator)
+{
+ DICT_ITERATOR_DICT (iterator) = dict;
+ DICT_ITERATOR_INDEX (iterator) = -1;
+ return iterator_hashed_advance (iterator);
+}
+
+static struct symbol *
+iterator_next_hashed (struct dict_iterator *iterator)
+{
+ const struct dictionary *dict = DICT_ITERATOR_DICT (iterator);
+ struct symbol *next;
+
+ next = DICT_ITERATOR_CURRENT (iterator)->hash_next;
+
+ if (next == NULL)
+ return iterator_hashed_advance (iterator);
+ else
+ {
+ DICT_ITERATOR_CURRENT (iterator) = next;
+ return next;
+ }
+}
+
+static struct symbol *
+iterator_hashed_advance (struct dict_iterator *iterator)
+{
+ const struct dictionary *dict = DICT_ITERATOR_DICT (iterator);
+ int nbuckets = DICT_HASHED_NBUCKETS (dict);
+ int i;
+
+ for (i = DICT_ITERATOR_INDEX (iterator) + 1; i < nbuckets; ++i)
+ {
+ struct symbol *sym = DICT_HASHED_BUCKET (dict, i);
+
+ if (sym != NULL)
+ {
+ DICT_ITERATOR_INDEX (iterator) = i;
+ DICT_ITERATOR_CURRENT (iterator) = sym;
+ return sym;
+ }
+ }
+
+ return NULL;
+}
+
+static struct symbol *
+iter_name_first_hashed (const struct dictionary *dict,
+ const char *name,
+ struct dict_iterator *iterator)
+{
+ unsigned int hash_index
+ = msymbol_hash_iw (name) % DICT_HASHED_NBUCKETS (dict);
+ struct symbol *sym;
+
+ DICT_ITERATOR_DICT (iterator) = dict;
+
+ /* Loop through the symbols in the given bucket, breaking when SYM
+ first matches. If SYM never matches, it will be set to NULL;
+ either way, we have the right return value. */
+
+ for (sym = DICT_HASHED_BUCKET (dict, hash_index);
+ sym != NULL;
+ sym = sym->hash_next)
+ {
+ /* Warning: the order of arguments to strcmp_iw matters! */
+ if (strcmp_iw (SYMBOL_NATURAL_NAME (sym), name) == 0)
+ {
+ break;
+ }
+
+ }
+
+ DICT_ITERATOR_CURRENT (iterator) = sym;
+ return sym;
+}
+
+static struct symbol *
+iter_name_next_hashed (const char *name, struct dict_iterator *iterator)
+{
+ struct symbol *next;
+
+ for (next = DICT_ITERATOR_CURRENT (iterator)->hash_next;
+ next != NULL;
+ next = next->hash_next)
+ {
+ if (strcmp_iw (SYMBOL_NATURAL_NAME (next), name) == 0)
+ break;
+ }
+
+ DICT_ITERATOR_CURRENT (iterator) = next;
+
+ return next;
+}
+
+/* Insert SYM into DICT. */
+
+static void
+insert_symbol_hashed (struct dictionary *dict,
+ struct symbol *sym)
+{
+ unsigned int hash_index;
+ struct symbol **buckets = DICT_HASHED_BUCKETS (dict);
+
+ hash_index = (msymbol_hash_iw (SYMBOL_NATURAL_NAME (sym))
+ % DICT_HASHED_NBUCKETS (dict));
+ sym->hash_next = buckets[hash_index];
+ buckets[hash_index] = sym;
+}
+
+static int
+size_hashed (const struct dictionary *dict)
+{
+ return DICT_HASHED_NBUCKETS (dict);
+}
+
+/* Functions only for DICT_HASHED_EXPANDABLE. */
+
+static void
+free_hashed_expandable (struct dictionary *dict)
+{
+ xfree (DICT_HASHED_BUCKETS (dict));
+ xfree (dict);
+}
+
+static void
+add_symbol_hashed_expandable (struct dictionary *dict,
+ struct symbol *sym)
+{
+ int nsyms = ++DICT_HASHED_EXPANDABLE_NSYMS (dict);
+
+ if (DICT_HASHTABLE_SIZE (nsyms) > DICT_HASHED_NBUCKETS (dict))
+ expand_hashtable (dict);
+
+ insert_symbol_hashed (dict, sym);
+ DICT_HASHED_EXPANDABLE_NSYMS (dict) = nsyms;
+}
+
+static int
+size_hashed_expandable (const struct dictionary *dict)
+{
+ return DICT_HASHED_EXPANDABLE_NSYMS (dict);
+}
+
+static void
+expand_hashtable (struct dictionary *dict)
+{
+ int old_nbuckets = DICT_HASHED_NBUCKETS (dict);
+ struct symbol **old_buckets = DICT_HASHED_BUCKETS (dict);
+ int new_nbuckets = 2*old_nbuckets + 1;
+ struct symbol **new_buckets = xcalloc (new_nbuckets,
+ sizeof (struct symbol *));
+ int i;
+
+ DICT_HASHED_NBUCKETS (dict) = new_nbuckets;
+ DICT_HASHED_BUCKETS (dict) = new_buckets;
+
+ for (i = 0; i < old_nbuckets; ++i) {
+ struct symbol *sym, *next_sym;
+
+ sym = old_buckets[i];
+ if (sym != NULL) {
+ for (next_sym = sym->hash_next;
+ next_sym != NULL;
+ next_sym = sym->hash_next) {
+ insert_symbol_hashed (dict, sym);
+ sym = next_sym;
+ }
+
+ insert_symbol_hashed (dict, sym);
+ }
+ }
+
+ xfree (old_buckets);
+}
+
+/* Functions for DICT_LINEAR and DICT_LINEAR_EXPANDABLE. */
+
+static struct symbol *
+iterator_first_linear (const struct dictionary *dict,
+ struct dict_iterator *iterator)
+{
+ DICT_ITERATOR_DICT (iterator) = dict;
+ DICT_ITERATOR_INDEX (iterator) = 0;
+ return DICT_LINEAR_NSYMS (dict) ? DICT_LINEAR_SYM (dict, 0) : NULL;
+}
+
+static struct symbol *
+iterator_next_linear (struct dict_iterator *iterator)
+{
+ const struct dictionary *dict = DICT_ITERATOR_DICT (iterator);
+
+ if (++DICT_ITERATOR_INDEX (iterator) >= DICT_LINEAR_NSYMS (dict))
+ return NULL;
+ else
+ return DICT_LINEAR_SYM (dict, DICT_ITERATOR_INDEX (iterator));
+}
+
+static struct symbol *
+iter_name_first_linear (const struct dictionary *dict,
+ const char *name,
+ struct dict_iterator *iterator)
+{
+ DICT_ITERATOR_DICT (iterator) = dict;
+ DICT_ITERATOR_INDEX (iterator) = -1;
+
+ return iter_name_next_linear (name, iterator);
+}
+
+static struct symbol *
+iter_name_next_linear (const char *name, struct dict_iterator *iterator)
+{
+ const struct dictionary *dict = DICT_ITERATOR_DICT (iterator);
+ int i, nsyms = DICT_LINEAR_NSYMS (dict);
+ struct symbol *sym, *retval = NULL;
+
+ for (i = DICT_ITERATOR_INDEX (iterator) + 1; i < nsyms; ++i)
+ {
+ sym = DICT_LINEAR_SYM (dict, i);
+ if (strcmp_iw (SYMBOL_NATURAL_NAME (sym), name) == 0)
+ {
+ retval = sym;
+ break;
+ }
+ }
+
+ DICT_ITERATOR_INDEX (iterator) = i;
+
+ return retval;
+}
+
+static int
+size_linear (const struct dictionary *dict)
+{
+ return DICT_LINEAR_NSYMS (dict);
+}
+
+/* Functions only for DICT_LINEAR_EXPANDABLE. */
+
+static void
+free_linear_expandable (struct dictionary *dict)
+{
+ xfree (DICT_LINEAR_SYMS (dict));
+ xfree (dict);
+}
+
+
+static void
+add_symbol_linear_expandable (struct dictionary *dict,
+ struct symbol *sym)
+{
+ int nsyms = ++DICT_LINEAR_NSYMS (dict);
+
+ /* Do we have enough room? If not, grow it. */
+ if (nsyms > DICT_LINEAR_EXPANDABLE_CAPACITY (dict)) {
+ DICT_LINEAR_EXPANDABLE_CAPACITY (dict) *= 2;
+ DICT_LINEAR_SYMS (dict)
+ = xrealloc (DICT_LINEAR_SYMS (dict),
+ DICT_LINEAR_EXPANDABLE_CAPACITY (dict)
+ * sizeof (struct symbol *));
+ }
+
+ DICT_LINEAR_SYM (dict, nsyms - 1) = sym;
+}
diff --git a/contrib/gdb/gdb/dictionary.h b/contrib/gdb/gdb/dictionary.h
new file mode 100644
index 0000000..75edd7f
--- /dev/null
+++ b/contrib/gdb/gdb/dictionary.h
@@ -0,0 +1,156 @@
+/* Routines for name->symbol lookups in GDB.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by David Carlton <carlton@bactrian.org> and by Kealia,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 DICTIONARY_H
+#define DICTIONARY_H
+
+/* An opaque type for dictionaries; only dictionary.c should know
+ about its innards. */
+
+struct dictionary;
+
+/* Other types needed for declarations. */
+
+struct symbol;
+struct obstack;
+struct pending;
+
+
+/* The creation functions for various implementations of
+ dictionaries. */
+
+/* Create a dictionary implemented via a fixed-size hashtable. All
+ memory it uses is allocated on OBSTACK; the environment is
+ initialized from SYMBOL_LIST. */
+
+extern struct dictionary *dict_create_hashed (struct obstack *obstack,
+ const struct pending
+ *symbol_list);
+
+/* Create a dictionary implemented via a hashtable that grows as
+ necessary. The dictionary is initially empty; to add symbols to
+ it, call dict_add_symbol(). Call dict_free() when you're done with
+ it. */
+
+extern struct dictionary *dict_create_hashed_expandable (void);
+
+/* Create a dictionary implemented via a fixed-size array. All memory
+ it uses is allocated on OBSTACK; the environment is initialized
+ from the SYMBOL_LIST. The symbols are ordered in the same order
+ that they're found in SYMBOL_LIST. */
+
+extern struct dictionary *dict_create_linear (struct obstack *obstack,
+ const struct pending
+ *symbol_list);
+
+/* Create a dictionary implemented via an array that grows as
+ necessary. The dictionary is initially empty; to add symbols to
+ it, call dict_add_symbol(). Call dict_free() when you're done with
+ it. */
+
+extern struct dictionary *dict_create_linear_expandable (void);
+
+
+/* The functions providing the interface to dictionaries. Note that
+ the most common parts of the interface, namely symbol lookup, are
+ only provided via iterator functions. */
+
+/* Free the memory used by a dictionary that's not on an obstack. (If
+ any.) */
+
+extern void dict_free (struct dictionary *dict);
+
+/* Add a symbol to an expandable dictionary. */
+
+extern void dict_add_symbol (struct dictionary *dict, struct symbol *sym);
+
+/* Is the dictionary empty? */
+
+extern int dict_empty (struct dictionary *dict);
+
+/* A type containing data that is used when iterating over all symbols
+ in a dictionary. Don't ever look at its innards; this type would
+ be opaque if we didn't need to be able to allocate it on the
+ stack. */
+
+struct dict_iterator
+{
+ /* The dictionary that this iterator is associated to. */
+ const struct dictionary *dict;
+ /* The next two members are data that is used in a way that depends
+ on DICT's implementation type. */
+ int index;
+ struct symbol *current;
+};
+
+/* Initialize ITERATOR to point at the first symbol in DICT, and
+ return that first symbol, or NULL if DICT is empty. */
+
+extern struct symbol *dict_iterator_first (const struct dictionary *dict,
+ struct dict_iterator *iterator);
+
+/* Advance ITERATOR, and return the next symbol, or NULL if there are
+ no more symbols. Don't call this if you've previously received
+ NULL from dict_iterator_first or dict_iterator_next on this
+ iteration. */
+
+extern struct symbol *dict_iterator_next (struct dict_iterator *iterator);
+
+/* Initialize ITERATOR to point at the first symbol in DICT whose
+ SYMBOL_BEST_NAME is NAME (as tested using strcmp_iw), and return
+ that first symbol, or NULL if there are no such symbols. */
+
+extern struct symbol *dict_iter_name_first (const struct dictionary *dict,
+ const char *name,
+ struct dict_iterator *iterator);
+
+/* Advance ITERATOR to point at the next symbol in DICT whose
+ SYMBOL_BEST_NAME is NAME (as tested using strcmp_iw), or NULL if
+ there are no more such symbols. Don't call this if you've
+ previously received NULL from dict_iterator_first or
+ dict_iterator_next on this iteration. And don't call it unless
+ ITERATOR was created by a previous call to dict_iter_name_first
+ with the same NAME. */
+
+extern struct symbol *dict_iter_name_next (const char *name,
+ struct dict_iterator *iterator);
+
+/* Return some notion of the size of the dictionary: the number of
+ symbols if we have that, the number of hash buckets otherwise. */
+
+extern int dict_size (const struct dictionary *dict);
+
+/* Macro to loop through all symbols in a dictionary DICT, in no
+ particular order. ITER is a struct dict_iterator (NOTE: __not__ a
+ struct dict_iterator *), and SYM points to the current symbol.
+
+ It's implemented as a single loop, so you can terminate the loop
+ early by a break if you desire. */
+
+#define ALL_DICT_SYMBOLS(dict, iter, sym) \
+ for ((sym) = dict_iterator_first ((dict), &(iter)); \
+ (sym); \
+ (sym) = dict_iterator_next (&(iter)))
+
+#endif /* DICTIONARY_H */
diff --git a/contrib/gdb/gdb/dink32-rom.c b/contrib/gdb/gdb/dink32-rom.c
new file mode 100644
index 0000000..4a68140
--- /dev/null
+++ b/contrib/gdb/gdb/dink32-rom.c
@@ -0,0 +1,178 @@
+/* Remote debugging interface for DINK32 (PowerPC) ROM monitor for
+ GDB, the GNU debugger.
+ Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "symfile.h" /* For generic_load() */
+#include "inferior.h" /* For write_pc() */
+#include "regcache.h"
+
+static void dink32_open (char *args, int from_tty);
+
+static void
+dink32_supply_register (char *regname, int regnamelen, char *val, int vallen)
+{
+ int regno = 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. */
+
+static char *dink32_regnames[] =
+{
+ "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",
+
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+
+ "srr0", "msr", "cr", "lr", "ctr", "xer", "xer"
+};
+
+static struct target_ops dink32_ops;
+
+static char *dink32_inits[] =
+{"\r", NULL};
+
+static struct monitor_ops dink32_cmds;
+
+static void
+dink32_open (char *args, int from_tty)
+{
+ monitor_open (args, &dink32_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_dink32_rom; /* -Wmissing-prototypes */
+
+void
+_initialize_dink32_rom (void)
+{
+ dink32_cmds.flags = MO_HEX_PREFIX | MO_GETMEM_NEEDS_RANGE | MO_FILL_USES_ADDR | MO_HANDLE_NL | MO_32_REGS_PAIRED | MO_SETREG_INTERACTIVE | MO_SETMEM_INTERACTIVE | MO_GETMEM_16_BOUNDARY | MO_CLR_BREAK_1_BASED | MO_SREC_ACK | MO_SREC_ACK_ROTATE;
+ dink32_cmds.init = dink32_inits;
+ dink32_cmds.cont = "go +\r";
+ dink32_cmds.step = "tr +\r";
+ dink32_cmds.set_break = "bp 0x%x\r";
+ dink32_cmds.clr_break = "bp %d\r";
+#if 0 /* Would need to follow strict alignment rules.. */
+ dink32_cmds.fill = "mf %x %x %x\r";
+#endif
+ dink32_cmds.setmem.cmdb = "mm -b %x\r";
+ dink32_cmds.setmem.cmdw = "mm -w %x\r";
+ dink32_cmds.setmem.cmdl = "mm %x\r";
+ dink32_cmds.setmem.term = " ? ";
+ dink32_cmds.getmem.cmdb = "md %x\r";
+ dink32_cmds.getmem.resp_delim = " ";
+ dink32_cmds.setreg.cmd = "rm %s\r";
+ dink32_cmds.setreg.term = " ? ";
+ dink32_cmds.getreg.cmd = "rd %s\r";
+ dink32_cmds.getreg.resp_delim = ": ";
+ dink32_cmds.dump_registers = "rd r\r";
+ dink32_cmds.register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)";
+ dink32_cmds.supply_register = dink32_supply_register;
+ /* S-record download, via "keyboard port". */
+ dink32_cmds.load = "dl -k\r";
+ dink32_cmds.loadresp = "Set Input Port : set to Keyboard Port\r";
+ dink32_cmds.prompt = "DINK32_603 >>";
+ dink32_cmds.line_term = "\r";
+ dink32_cmds.target = &dink32_ops;
+ dink32_cmds.stopbits = SERIAL_1_STOPBITS;
+ dink32_cmds.regnames = dink32_regnames;
+ dink32_cmds.magic = MONITOR_OPS_MAGIC;
+
+ init_monitor_ops (&dink32_ops);
+
+ dink32_ops.to_shortname = "dink32";
+ dink32_ops.to_longname = "DINK32 monitor";
+ dink32_ops.to_doc = "Debug using the DINK32 monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ dink32_ops.to_open = dink32_open;
+
+ add_target (&dink32_ops);
+}
diff --git a/contrib/gdb/gdb/disasm.c b/contrib/gdb/gdb/disasm.c
new file mode 100644
index 0000000..3cde2ea
--- /dev/null
+++ b/contrib/gdb/gdb/disasm.c
@@ -0,0 +1,395 @@
+/* Disassemble support for GDB.
+
+ Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "target.h"
+#include "value.h"
+#include "ui-out.h"
+#include "gdb_string.h"
+#include "disasm.h"
+#include "gdbcore.h"
+#include "dis-asm.h"
+
+/* Disassemble functions.
+ FIXME: We should get rid of all the duplicate code in gdb that does
+ the same thing: disassemble_command() and the gdbtk variation. */
+
+/* This Structure is used to store line number information.
+ We need a different sort of line table from the normal one cuz we can't
+ depend upon implicit line-end pc's for lines to do the
+ reordering in this function. */
+
+struct dis_line_entry
+{
+ int line;
+ CORE_ADDR start_pc;
+ CORE_ADDR end_pc;
+};
+
+/* Like target_read_memory, but slightly different parameters. */
+static int
+dis_asm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int len,
+ struct disassemble_info *info)
+{
+ return target_read_memory (memaddr, (char *) myaddr, len);
+}
+
+/* Like memory_error with slightly different parameters. */
+static void
+dis_asm_memory_error (int status, bfd_vma memaddr,
+ struct disassemble_info *info)
+{
+ memory_error (status, memaddr);
+}
+
+/* Like print_address with slightly different parameters. */
+static void
+dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
+{
+ print_address (addr, info->stream);
+}
+
+static int
+compare_lines (const void *mle1p, const void *mle2p)
+{
+ struct dis_line_entry *mle1, *mle2;
+ int val;
+
+ mle1 = (struct dis_line_entry *) mle1p;
+ mle2 = (struct dis_line_entry *) mle2p;
+
+ val = mle1->line - mle2->line;
+
+ if (val != 0)
+ return val;
+
+ return mle1->start_pc - mle2->start_pc;
+}
+
+static int
+dump_insns (struct ui_out *uiout, struct disassemble_info * di,
+ CORE_ADDR low, CORE_ADDR high,
+ int how_many, struct ui_stream *stb)
+{
+ int num_displayed = 0;
+ CORE_ADDR pc;
+
+ /* parts of the symbolic representation of the address */
+ int unmapped;
+ int offset;
+ int line;
+ struct cleanup *ui_out_chain;
+
+ for (pc = low; pc < high;)
+ {
+ char *filename = NULL;
+ char *name = NULL;
+
+ QUIT;
+ if (how_many >= 0)
+ {
+ if (num_displayed >= how_many)
+ break;
+ else
+ num_displayed++;
+ }
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_core_addr (uiout, "address", pc);
+
+ if (!build_address_symbolic (pc, 0, &name, &offset, &filename,
+ &line, &unmapped))
+ {
+ /* We don't care now about line, filename and
+ unmapped. But we might in the future. */
+ ui_out_text (uiout, " <");
+ ui_out_field_string (uiout, "func-name", name);
+ ui_out_text (uiout, "+");
+ ui_out_field_int (uiout, "offset", offset);
+ ui_out_text (uiout, ">:\t");
+ }
+ else
+ ui_out_text (uiout, ":\t");
+
+ if (filename != NULL)
+ xfree (filename);
+ if (name != NULL)
+ xfree (name);
+
+ ui_file_rewind (stb->stream);
+ pc += TARGET_PRINT_INSN (pc, di);
+ ui_out_field_stream (uiout, "inst", stb);
+ ui_file_rewind (stb->stream);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
+ }
+ return num_displayed;
+}
+
+/* The idea here is to present a source-O-centric view of a
+ function to the user. This means that things are presented
+ in source order, with (possibly) out of order assembly
+ immediately following. */
+static void
+do_mixed_source_and_assembly (struct ui_out *uiout,
+ struct disassemble_info *di, int nlines,
+ struct linetable_entry *le,
+ CORE_ADDR low, CORE_ADDR high,
+ struct symtab *symtab,
+ int how_many, struct ui_stream *stb)
+{
+ int newlines = 0;
+ struct dis_line_entry *mle;
+ struct symtab_and_line sal;
+ int i;
+ int out_of_order = 0;
+ int next_line = 0;
+ CORE_ADDR pc;
+ int num_displayed = 0;
+ struct cleanup *ui_out_chain;
+ struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
+ struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
+
+ mle = (struct dis_line_entry *) alloca (nlines
+ * sizeof (struct dis_line_entry));
+
+ /* Copy linetable entries for this function into our data
+ structure, creating end_pc's and setting out_of_order as
+ appropriate. */
+
+ /* First, skip all the preceding functions. */
+
+ for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
+
+ /* Now, copy all entries before the end of this function. */
+
+ for (; i < nlines - 1 && le[i].pc < high; i++)
+ {
+ if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
+ continue; /* Ignore duplicates */
+
+ /* Skip any end-of-function markers. */
+ if (le[i].line == 0)
+ continue;
+
+ mle[newlines].line = le[i].line;
+ if (le[i].line > le[i + 1].line)
+ out_of_order = 1;
+ mle[newlines].start_pc = le[i].pc;
+ mle[newlines].end_pc = le[i + 1].pc;
+ newlines++;
+ }
+
+ /* If we're on the last line, and it's part of the function,
+ then we need to get the end pc in a special way. */
+
+ if (i == nlines - 1 && le[i].pc < high)
+ {
+ mle[newlines].line = le[i].line;
+ mle[newlines].start_pc = le[i].pc;
+ sal = find_pc_line (le[i].pc, 0);
+ mle[newlines].end_pc = sal.end;
+ newlines++;
+ }
+
+ /* Now, sort mle by line #s (and, then by addresses within
+ lines). */
+
+ if (out_of_order)
+ qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
+
+ /* Now, for each line entry, emit the specified lines (unless
+ they have been emitted before), followed by the assembly code
+ for that line. */
+
+ ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
+
+ for (i = 0; i < newlines; i++)
+ {
+ /* Print out everything from next_line to the current line. */
+ if (mle[i].line >= next_line)
+ {
+ if (next_line != 0)
+ {
+ /* Just one line to print. */
+ if (next_line == mle[i].line)
+ {
+ ui_out_tuple_chain
+ = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "src_and_asm_line");
+ print_source_lines (symtab, next_line, mle[i].line + 1, 0);
+ }
+ else
+ {
+ /* Several source lines w/o asm instructions associated. */
+ for (; next_line < mle[i].line; next_line++)
+ {
+ struct cleanup *ui_out_list_chain_line;
+ struct cleanup *ui_out_tuple_chain_line;
+
+ ui_out_tuple_chain_line
+ = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "src_and_asm_line");
+ print_source_lines (symtab, next_line, next_line + 1,
+ 0);
+ ui_out_list_chain_line
+ = make_cleanup_ui_out_list_begin_end (uiout,
+ "line_asm_insn");
+ do_cleanups (ui_out_list_chain_line);
+ do_cleanups (ui_out_tuple_chain_line);
+ }
+ /* Print the last line and leave list open for
+ asm instructions to be added. */
+ ui_out_tuple_chain
+ = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "src_and_asm_line");
+ print_source_lines (symtab, next_line, mle[i].line + 1, 0);
+ }
+ }
+ else
+ {
+ ui_out_tuple_chain
+ = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
+ print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
+ }
+
+ next_line = mle[i].line + 1;
+ ui_out_list_chain
+ = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
+ }
+
+ num_displayed += dump_insns (uiout, di, mle[i].start_pc, mle[i].end_pc,
+ how_many, stb);
+
+ /* When we've reached the end of the mle array, or we've seen the last
+ assembly range for this source line, close out the list/tuple. */
+ if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
+ {
+ do_cleanups (ui_out_list_chain);
+ do_cleanups (ui_out_tuple_chain);
+ ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
+ ui_out_list_chain = make_cleanup (null_cleanup, 0);
+ ui_out_text (uiout, "\n");
+ }
+ if (how_many >= 0 && num_displayed >= how_many)
+ break;
+ }
+ do_cleanups (ui_out_chain);
+}
+
+
+static void
+do_assembly_only (struct ui_out *uiout, struct disassemble_info * di,
+ CORE_ADDR low, CORE_ADDR high,
+ int how_many, struct ui_stream *stb)
+{
+ int num_displayed = 0;
+ struct cleanup *ui_out_chain;
+
+ ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
+
+ num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
+
+ do_cleanups (ui_out_chain);
+}
+
+/* Initialize the disassemble info struct ready for the specified
+ stream. */
+
+static int
+fprintf_disasm (void *stream, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+ /* Something non -ve. */
+ return 0;
+}
+
+static struct disassemble_info
+gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
+{
+ struct disassemble_info di;
+ init_disassemble_info (&di, file, fprintf_disasm);
+ di.flavour = bfd_target_unknown_flavour;
+ di.memory_error_func = dis_asm_memory_error;
+ di.print_address_func = dis_asm_print_address;
+ /* NOTE: cagney/2003-04-28: The original code, from the old Insight
+ disassembler had a local optomization here. By default it would
+ access the executable file, instead of the target memory (there
+ was a growing list of exceptions though). Unfortunately, the
+ heuristic was flawed. Commands like "disassemble &variable"
+ didn't work as they relied on the access going to the target.
+ Further, it has been supperseeded by trust-read-only-sections
+ (although that should be superseeded by target_trust..._p()). */
+ di.read_memory_func = dis_asm_read_memory;
+ di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+ di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+ di.endian = gdbarch_byte_order (gdbarch);
+ return di;
+}
+
+void
+gdb_disassembly (struct ui_out *uiout,
+ char *file_string,
+ int line_num,
+ int mixed_source_and_assembly,
+ int how_many, CORE_ADDR low, CORE_ADDR high)
+{
+ struct ui_stream *stb = ui_out_stream_new (uiout);
+ struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (stb);
+ struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stb->stream);
+ /* To collect the instruction outputted from opcodes. */
+ struct symtab *symtab = NULL;
+ struct linetable_entry *le = NULL;
+ int nlines = -1;
+
+ /* Assume symtab is valid for whole PC range */
+ symtab = find_pc_symtab (low);
+
+ if (symtab != NULL && symtab->linetable != NULL)
+ {
+ /* Convert the linetable to a bunch of my_line_entry's. */
+ le = symtab->linetable->item;
+ nlines = symtab->linetable->nitems;
+ }
+
+ if (!mixed_source_and_assembly || nlines <= 0
+ || symtab == NULL || symtab->linetable == NULL)
+ do_assembly_only (uiout, &di, low, high, how_many, stb);
+
+ else if (mixed_source_and_assembly)
+ do_mixed_source_and_assembly (uiout, &di, nlines, le, low,
+ high, symtab, how_many, stb);
+
+ do_cleanups (cleanups);
+ gdb_flush (gdb_stdout);
+}
+
+/* Print the instruction at address MEMADDR in debugged memory,
+ on STREAM. Returns length of the instruction, in bytes. */
+
+int
+gdb_print_insn (CORE_ADDR memaddr, struct ui_file *stream)
+{
+ struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stream);
+ return TARGET_PRINT_INSN (memaddr, &di);
+}
diff --git a/contrib/gdb/gdb/disasm.h b/contrib/gdb/gdb/disasm.h
new file mode 100644
index 0000000..b5dbb84
--- /dev/null
+++ b/contrib/gdb/gdb/disasm.h
@@ -0,0 +1,38 @@
+/* Disassemble support for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 DISASM_H
+#define DISASM_H
+
+struct ui_out;
+struct ui_file;
+
+extern void gdb_disassembly (struct ui_out *uiout,
+ char *file_string,
+ int line_num,
+ int mixed_source_and_assembly,
+ int how_many, CORE_ADDR low, CORE_ADDR high);
+
+/* Print the instruction at address MEMADDR in debugged memory, on
+ STREAM. Returns length of the instruction, in bytes. */
+
+extern int gdb_print_insn (CORE_ADDR memaddr, struct ui_file *stream);
+
+#endif
diff --git a/contrib/gdb/gdb/doc/GDBvn.texi b/contrib/gdb/gdb/doc/GDBvn.texi
new file mode 100644
index 0000000..38987b5
--- /dev/null
+++ b/contrib/gdb/gdb/doc/GDBvn.texi
@@ -0,0 +1 @@
+@set GDBVN 6.1.1
diff --git a/contrib/gdb/gdb/doc/LRS b/contrib/gdb/gdb/doc/LRS
new file mode 100644
index 0000000..7e25d43
--- /dev/null
+++ b/contrib/gdb/gdb/doc/LRS
@@ -0,0 +1,197 @@
+What's LRS?
+===========
+
+LRS, or Live Range Splitting is an optimization technique which allows
+a user variable to reside in different locations during different parts
+of a function.
+
+For example, a variable might reside in the stack for part of a function
+and in a register during a loop and in a different register during
+another loop.
+
+Clearly, if a variable may reside in different locations, then the
+compiler must describe to the debugger where the variable resides for
+any given part of the function.
+
+This document describes the debug format for encoding these extensions
+in stabs.
+
+Since these extensions are gcc specific, these additional symbols and
+stabs can be disabled by the gcc command option -gstabs.
+
+
+GNU extensions for LRS under stabs:
+===================================
+
+
+range symbols:
+-------------
+
+ A range symbol will be used to mark the beginning or end of a
+ live range (the range which describes where a symbol is active,
+ or live). These symbols will later be referenced in the stabs for
+ debug purposes. For simplicity, we'll use the terms "range_start"
+ and "range_end" to identify the range symbols which mark the beginning
+ and end of a live range respectively.
+
+ Any text symbol which would normally appear in the symbol table
+ (eg. a function name) can be used as range symbol. If an address
+ is needed to delimit a live range and does not match any of the
+ values of symbols which would normally appear in the symbol table,
+ a new symbol will be added to the table whose value is that address.
+
+ The three new symbol types described below have been added for this
+ purpose.
+
+ For efficiency, the compiler should use existing symbols as range
+ symbols whenever possible; this reduces the number of additional
+ symbols which need to be added to the symbol table.
+
+
+New debug symbol type for defining ranges:
+------------------------------------------
+
+ range_off - contains PC function offset for start/end of a live range.
+ Its location is relative to the function start and therefore
+ eliminates the need for additional relocation.
+
+ This symbol has a values in the text section, and does not have a name.
+
+ NOTE: the following may not be needed but are included here just
+ in case.
+ range - contains PC value of beginning or end of a live range
+ (relocs required).
+
+ NOTE: the following will be required if we desire LRS debugging
+ to work with old style a.out stabs.
+ range_abs - contains absolute PC value of start/end of a live
+ range. The range_abs debug symbol is provided for
+ completeness, in case there is a need to describe addresses
+ in ROM, etc.
+
+
+Live range:
+-----------
+
+ The compiler and debugger view a variable with multiple homes as
+ a primary symbol and aliases for that symbol. The primary symbol
+ describes the default home of the variable while aliases describe
+ alternate homes for the variable.
+
+ A live range defines the interval of instructions beginning with
+ range_start and ending at range_end-1, and is used to specify a
+ range of instructions where an alias is active or "live". So,
+ the actual end of the range will be one less than the value of the
+ range_end symbol.
+
+ Ranges do not have to be nested. Eg. Two ranges may intersect while
+ each range contains subranges which are not in the other range.
+
+ There does not have to be a 1-1 mapping from range_start to
+ range_end symbols. Eg. Two range_starts can share the same
+ range_end, while one symbol's range_start can be another symbol's
+ range_end.
+
+ When a variable's storage class changes (eg. from stack to register,
+ or from one register to another), a new symbol entry will be
+ added to the symbol table with stabs describing the new type,
+ and appropriate live ranges refering to the variable's initial
+ symbol index.
+
+ For variables which are defined in the source but optimized away,
+ a symbol should be emitted with the live range l(0,0).
+
+ Live ranges for aliases of a particular variable should always
+ be disjoint. Overlapping ranges for aliases of the same variable
+ will be treated as an error by the debugger, and the overlapping
+ range will be ignored.
+
+ If no live range information is given, the live range will be assumed to
+ span the symbol's entire lexical scope.
+
+
+New stabs string identifiers:
+-----------------------------
+
+ "id" in "#id" in the following section refers to a numeric value.
+
+ New stab syntax for live range: l(<ref_from>,<ref_to>)
+
+ <ref_from> - "#id" where #id identifies the text symbol (range symbol) to
+ use as the start of live range (range_start). The value for
+ the referenced text symbol is the starting address of the
+ live range.
+
+ <ref_to> - "#id" where #id identifies the text symbol (range symbol) to
+ use as the end of live range (range_end). The value for
+ the referenced text symbol is ONE BYTE PAST the ending
+ address of the live range.
+
+
+ New stab syntax for identifying symbols.
+
+ <def> - "#id="
+
+ Uses:
+ <def><name>:<typedef1>...
+ When used in front of a symbol name, "#id=" defines a
+ unique reference number for this symbol. The reference
+ number can be used later when defining aliases for this
+ symbol.
+ <def>
+ When used as the entire stab string, "#id=" identifies this
+ nameless symbol as being the symbol for which "#id" refers to.
+
+
+ <ref> - "#id" where "#id" refers to the symbol for which the string
+ "#id=" identifies.
+ Uses:
+ <ref>:<typedef2>;<liverange>;<liverange>...
+ Defines an alias for the symbol identified by the reference
+ number ID.
+ l(<ref1>,<ref2>)
+ When used within a live range, "#id" refers to the text
+ symbol identified by "#id=" to use as the range symbol.
+
+ <liverange> - "l(<ref_from>,<ref_to>)" - specifies a live range for a
+ symbol. Multiple "l" specifiers can be combined to represent
+ mutiple live ranges, separated by semicolons.
+
+
+
+
+Example:
+========
+
+Consider a program of the form:
+
+ void foo(){
+ int a = ...;
+ ...
+ while (b--)
+ c += a;
+ ..
+ d = a;
+ ..
+ }
+
+Assume that "a" lives in the stack at offset -8, except for inside the
+loop where "a" resides in register "r5".
+
+The way to describe this is to create a stab for the variable "a" which
+describes "a" as living in the stack and an alias for the variable "a"
+which describes it as living in register "r5" in the loop.
+
+Let's assume that "#1" and "#2" are symbols which bound the area where
+"a" lives in a register.
+
+The stabs to describe "a" and its alias would look like this:
+
+ .stabs "#3=a:1",128,0,8,-8
+ .stabs "#3:r1;l(#1,#2)",64,0,0,5
+
+
+This design implies that the debugger will keep a chain of aliases for
+any given variable with aliases and that chain will be searched first
+to find out if an alias is active. If no alias is active, then the
+debugger will assume that the main variable is active.
diff --git a/contrib/gdb/gdb/doc/a4rc.sed b/contrib/gdb/gdb/doc/a4rc.sed
new file mode 100644
index 0000000..2292290
--- /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/agentexpr.texi b/contrib/gdb/gdb/doc/agentexpr.texi
new file mode 100644
index 0000000..491ae2e
--- /dev/null
+++ b/contrib/gdb/gdb/doc/agentexpr.texi
@@ -0,0 +1,837 @@
+@c \input texinfo
+@c %**start of header
+@c @setfilename agentexpr.info
+@c @settitle GDB Agent Expressions
+@c @setchapternewpage off
+@c %**end of header
+
+@c Revision: $Id: agentexpr.texi,v 1.2 1998/12/09 21:23:46 jimb Exp $
+
+@node Agent Expressions
+@appendix The GDB Agent Expression Mechanism
+
+In some applications, it is not feasable for the debugger to interrupt
+the program's execution long enough for the developer to learn anything
+helpful about its behavior. If the program's correctness depends on its
+real-time behavior, delays introduced by a debugger might cause the
+program to fail, even when the code itself is correct. It is useful to
+be able to observe the program's behavior without interrupting it.
+
+Using GDB's @code{trace} and @code{collect} commands, the user can
+specify locations in the program, and arbitrary expressions to evaluate
+when those locations are reached. Later, using the @code{tfind}
+command, she can examine the values those expressions had when the
+program hit the trace points. The expressions may also denote objects
+in memory --- structures or arrays, for example --- whose values GDB
+should record; while visiting a particular tracepoint, the user may
+inspect those objects as if they were in memory at that moment.
+However, because GDB records these values without interacting with the
+user, it can do so quickly and unobtrusively, hopefully not disturbing
+the program's behavior.
+
+When GDB is debugging a remote target, the GDB @dfn{agent} code running
+on the target computes the values of the expressions itself. To avoid
+having a full symbolic expression evaluator on the agent, GDB translates
+expressions in the source language into a simpler bytecode language, and
+then sends the bytecode to the agent; the agent then executes the
+bytecode, and records the values for GDB to retrieve later.
+
+The bytecode language is simple; there are forty-odd opcodes, the bulk
+of which are the usual vocabulary of C operands (addition, subtraction,
+shifts, and so on) and various sizes of literals and memory reference
+operations. The bytecode interpreter operates strictly on machine-level
+values --- various sizes of integers and floating point numbers --- and
+requires no information about types or symbols; thus, the interpreter's
+internal data structures are simple, and each bytecode requires only a
+few native machine instructions to implement it. The interpreter is
+small, and strict limits on the memory and time required to evaluate an
+expression are easy to determine, making it suitable for use by the
+debugging agent in real-time applications.
+
+@menu
+* General Bytecode Design:: Overview of the interpreter.
+* Bytecode Descriptions:: What each one does.
+* Using Agent Expressions:: How agent expressions fit into the big picture.
+* Varying Target Capabilities:: How to discover what the target can do.
+* Tracing on Symmetrix:: Special info for implementation on EMC's
+ boxes.
+* Rationale:: Why we did it this way.
+@end menu
+
+
+@c @node Rationale
+@c @section Rationale
+
+
+@node General Bytecode Design
+@section General Bytecode Design
+
+The agent represents bytecode expressions as an array of bytes. Each
+instruction is one byte long (thus the term @dfn{bytecode}). Some
+instructions are followed by operand bytes; for example, the @code{goto}
+instruction is followed by a destination for the jump.
+
+The bytecode interpreter is a stack-based machine; most instructions pop
+their operands off the stack, perform some operation, and push the
+result back on the stack for the next instruction to consume. Each
+element of the stack may contain either a integer or a floating point
+value; these values are as many bits wide as the largest integer that
+can be directly manipulated in the source language. Stack elements
+carry no record of their type; bytecode could push a value as an
+integer, then pop it as a floating point value. However, GDB will not
+generate code which does this. In C, one might define the type of a
+stack element as follows:
+@example
+union agent_val @{
+ LONGEST l;
+ DOUBLEST d;
+@};
+@end example
+@noindent
+where @code{LONGEST} and @code{DOUBLEST} are @code{typedef} names for
+the largest integer and floating point types on the machine.
+
+By the time the bytecode interpreter reaches the end of the expression,
+the value of the expression should be the only value left on the stack.
+For tracing applications, @code{trace} bytecodes in the expression will
+have recorded the necessary data, and the value on the stack may be
+discarded. For other applications, like conditional breakpoints, the
+value may be useful.
+
+Separate from the stack, the interpreter has two registers:
+@table @code
+@item pc
+The address of the next bytecode to execute.
+
+@item start
+The address of the start of the bytecode expression, necessary for
+interpreting the @code{goto} and @code{if_goto} instructions.
+
+@end table
+@noindent
+Neither of these registers is directly visible to the bytecode language
+itself, but they are useful for defining the meanings of the bytecode
+operations.
+
+There are no instructions to perform side effects on the running
+program, or call the program's functions; we assume that these
+expressions are only used for unobtrusive debugging, not for patching
+the running code.
+
+Most bytecode instructions do not distinguish between the various sizes
+of values, and operate on full-width values; the upper bits of the
+values are simply ignored, since they do not usually make a difference
+to the value computed. The exceptions to this rule are:
+@table @asis
+
+@item memory reference instructions (@code{ref}@var{n})
+There are distinct instructions to fetch different word sizes from
+memory. Once on the stack, however, the values are treated as full-size
+integers. They may need to be sign-extended; the @code{ext} instruction
+exists for this purpose.
+
+@item the sign-extension instruction (@code{ext} @var{n})
+These clearly need to know which portion of their operand is to be
+extended to occupy the full length of the word.
+
+@end table
+
+If the interpreter is unable to evaluate an expression completely for
+some reason (a memory location is inaccessible, or a divisor is zero,
+for example), we say that interpretation ``terminates with an error''.
+This means that the problem is reported back to the interpreter's caller
+in some helpful way. In general, code using agent expressions should
+assume that they may attempt to divide by zero, fetch arbitrary memory
+locations, and misbehave in other ways.
+
+Even complicated C expressions compile to a few bytecode instructions;
+for example, the expression @code{x + y * z} would typically produce
+code like the following, assuming that @code{x} and @code{y} live in
+registers, and @code{z} is a global variable holding a 32-bit
+@code{int}:
+@example
+reg 1
+reg 2
+const32 @i{address of z}
+ref32
+ext 32
+mul
+add
+end
+@end example
+
+In detail, these mean:
+@table @code
+
+@item reg 1
+Push the value of register 1 (presumably holding @code{x}) onto the
+stack.
+
+@item reg 2
+Push the value of register 2 (holding @code{y}).
+
+@item const32 @i{address of z}
+Push the address of @code{z} onto the stack.
+
+@item ref32
+Fetch a 32-bit word from the address at the top of the stack; replace
+the address on the stack with the value. Thus, we replace the address
+of @code{z} with @code{z}'s value.
+
+@item ext 32
+Sign-extend the value on the top of the stack from 32 bits to full
+length. This is necessary because @code{z} is a signed integer.
+
+@item mul
+Pop the top two numbers on the stack, multiply them, and push their
+product. Now the top of the stack contains the value of the expression
+@code{y * z}.
+
+@item add
+Pop the top two numbers, add them, and push the sum. Now the top of the
+stack contains the value of @code{x + y * z}.
+
+@item end
+Stop executing; the value left on the stack top is the value to be
+recorded.
+
+@end table
+
+
+@node Bytecode Descriptions
+@section Bytecode Descriptions
+
+Each bytecode description has the following form:
+
+@table @asis
+
+@item @code{add} (0x02): @var{a} @var{b} @result{} @var{a+b}
+
+Pop the top two stack items, @var{a} and @var{b}, as integers; push
+their sum, as an integer.
+
+@end table
+
+In this example, @code{add} is the name of the bytecode, and
+@code{(0x02)} is the one-byte value used to encode the bytecode, in
+hexidecimal. The phrase ``@var{a} @var{b} @result{} @var{a+b}'' shows
+the stack before and after the bytecode executes. Beforehand, the stack
+must contain at least two values, @var{a} and @var{b}; since the top of
+the stack is to the right, @var{b} is on the top of the stack, and
+@var{a} is underneath it. After execution, the bytecode will have
+popped @var{a} and @var{b} from the stack, and replaced them with a
+single value, @var{a+b}. There may be other values on the stack below
+those shown, but the bytecode affects only those shown.
+
+Here is another example:
+
+@table @asis
+
+@item @code{const8} (0x22) @var{n}: @result{} @var{n}
+Push the 8-bit integer constant @var{n} on the stack, without sign
+extension.
+
+@end table
+
+In this example, the bytecode @code{const8} takes an operand @var{n}
+directly from the bytecode stream; the operand follows the @code{const8}
+bytecode itself. We write any such operands immediately after the name
+of the bytecode, before the colon, and describe the exact encoding of
+the operand in the bytecode stream in the body of the bytecode
+description.
+
+For the @code{const8} bytecode, there are no stack items given before
+the @result{}; this simply means that the bytecode consumes no values
+from the stack. If a bytecode consumes no values, or produces no
+values, the list on either side of the @result{} may be empty.
+
+If a value is written as @var{a}, @var{b}, or @var{n}, then the bytecode
+treats it as an integer. If a value is written is @var{addr}, then the
+bytecode treats it as an address.
+
+We do not fully describe the floating point operations here; although
+this design can be extended in a clean way to handle floating point
+values, they are not of immediate interest to the customer, so we avoid
+describing them, to save time.
+
+
+@table @asis
+
+@item @code{float} (0x01): @result{}
+
+Prefix for floating-point bytecodes. Not implemented yet.
+
+@item @code{add} (0x02): @var{a} @var{b} @result{} @var{a+b}
+Pop two integers from the stack, and push their sum, as an integer.
+
+@item @code{sub} (0x03): @var{a} @var{b} @result{} @var{a-b}
+Pop two integers from the stack, subtract the top value from the
+next-to-top value, and push the difference.
+
+@item @code{mul} (0x04): @var{a} @var{b} @result{} @var{a*b}
+Pop two integers from the stack, multiply them, and push the product on
+the stack. Note that, when one multiplies two @var{n}-bit numbers
+yielding another @var{n}-bit number, it is irrelevant whether the
+numbers are signed or not; the results are the same.
+
+@item @code{div_signed} (0x05): @var{a} @var{b} @result{} @var{a/b}
+Pop two signed integers from the stack; divide the next-to-top value by
+the top value, and push the quotient. If the divisor is zero, terminate
+with an error.
+
+@item @code{div_unsigned} (0x06): @var{a} @var{b} @result{} @var{a/b}
+Pop two unsigned integers from the stack; divide the next-to-top value
+by the top value, and push the quotient. If the divisor is zero,
+terminate with an error.
+
+@item @code{rem_signed} (0x07): @var{a} @var{b} @result{} @var{a modulo b}
+Pop two signed integers from the stack; divide the next-to-top value by
+the top value, and push the remainder. If the divisor is zero,
+terminate with an error.
+
+@item @code{rem_unsigned} (0x08): @var{a} @var{b} @result{} @var{a modulo b}
+Pop two unsigned integers from the stack; divide the next-to-top value
+by the top value, and push the remainder. If the divisor is zero,
+terminate with an error.
+
+@item @code{lsh} (0x09): @var{a} @var{b} @result{} @var{a<<b}
+Pop two integers from the stack; let @var{a} be the next-to-top value,
+and @var{b} be the top value. Shift @var{a} left by @var{b} bits, and
+push the result.
+
+@item @code{rsh_signed} (0x0a): @var{a} @var{b} @result{} @code{(signed)}@var{a>>b}
+Pop two integers from the stack; let @var{a} be the next-to-top value,
+and @var{b} be the top value. Shift @var{a} right by @var{b} bits,
+inserting copies of the top bit at the high end, and push the result.
+
+@item @code{rsh_unsigned} (0x0b): @var{a} @var{b} @result{} @var{a>>b}
+Pop two integers from the stack; let @var{a} be the next-to-top value,
+and @var{b} be the top value. Shift @var{a} right by @var{b} bits,
+inserting zero bits at the high end, and push the result.
+
+@item @code{log_not} (0x0e): @var{a} @result{} @var{!a}
+Pop an integer from the stack; if it is zero, push the value one;
+otherwise, push the value zero.
+
+@item @code{bit_and} (0x0f): @var{a} @var{b} @result{} @var{a&b}
+Pop two integers from the stack, and push their bitwise @code{and}.
+
+@item @code{bit_or} (0x10): @var{a} @var{b} @result{} @var{a|b}
+Pop two integers from the stack, and push their bitwise @code{or}.
+
+@item @code{bit_xor} (0x11): @var{a} @var{b} @result{} @var{a^b}
+Pop two integers from the stack, and push their bitwise
+exclusive-@code{or}.
+
+@item @code{bit_not} (0x12): @var{a} @result{} @var{~a}
+Pop an integer from the stack, and push its bitwise complement.
+
+@item @code{equal} (0x13): @var{a} @var{b} @result{} @var{a=b}
+Pop two integers from the stack; if they are equal, push the value one;
+otherwise, push the value zero.
+
+@item @code{less_signed} (0x14): @var{a} @var{b} @result{} @var{a<b}
+Pop two signed integers from the stack; if the next-to-top value is less
+than the top value, push the value one; otherwise, push the value zero.
+
+@item @code{less_unsigned} (0x15): @var{a} @var{b} @result{} @var{a<b}
+Pop two unsigned integers from the stack; if the next-to-top value is less
+than the top value, push the value one; otherwise, push the value zero.
+
+@item @code{ext} (0x16) @var{n}: @var{a} @result{} @var{a}, sign-extended from @var{n} bits
+Pop an unsigned value from the stack; treating it as an @var{n}-bit
+twos-complement value, extend it to full length. This means that all
+bits to the left of bit @var{n-1} (where the least significant bit is bit
+0) are set to the value of bit @var{n-1}. Note that @var{n} may be
+larger than or equal to the width of the stack elements of the bytecode
+engine; in this case, the bytecode should have no effect.
+
+The number of source bits to preserve, @var{n}, is encoded as a single
+byte unsigned integer following the @code{ext} bytecode.
+
+@item @code{zero_ext} (0x2a) @var{n}: @var{a} @result{} @var{a}, zero-extended from @var{n} bits
+Pop an unsigned value from the stack; zero all but the bottom @var{n}
+bits. This means that all bits to the left of bit @var{n-1} (where the
+least significant bit is bit 0) are set to the value of bit @var{n-1}.
+
+The number of source bits to preserve, @var{n}, is encoded as a single
+byte unsigned integer following the @code{zero_ext} bytecode.
+
+@item @code{ref8} (0x17): @var{addr} @result{} @var{a}
+@itemx @code{ref16} (0x18): @var{addr} @result{} @var{a}
+@itemx @code{ref32} (0x19): @var{addr} @result{} @var{a}
+@itemx @code{ref64} (0x1a): @var{addr} @result{} @var{a}
+Pop an address @var{addr} from the stack. For bytecode
+@code{ref}@var{n}, fetch an @var{n}-bit value from @var{addr}, using the
+natural target endianness. Push the fetched value as an unsigned
+integer.
+
+Note that @var{addr} may not be aligned in any particular way; the
+@code{ref@var{n}} bytecodes should operate correctly for any address.
+
+If attempting to access memory at @var{addr} would cause a processor
+exception of some sort, terminate with an error.
+
+@item @code{ref_float} (0x1b): @var{addr} @result{} @var{d}
+@itemx @code{ref_double} (0x1c): @var{addr} @result{} @var{d}
+@itemx @code{ref_long_double} (0x1d): @var{addr} @result{} @var{d}
+@itemx @code{l_to_d} (0x1e): @var{a} @result{} @var{d}
+@itemx @code{d_to_l} (0x1f): @var{d} @result{} @var{a}
+Not implemented yet.
+
+@item @code{dup} (0x28): @var{a} => @var{a} @var{a}
+Push another copy of the stack's top element.
+
+@item @code{swap} (0x2b): @var{a} @var{b} => @var{b} @var{a}
+Exchange the top two items on the stack.
+
+@item @code{pop} (0x29): @var{a} =>
+Discard the top value on the stack.
+
+@item @code{if_goto} (0x20) @var{offset}: @var{a} @result{}
+Pop an integer off the stack; if it is non-zero, branch to the given
+offset in the bytecode string. Otherwise, continue to the next
+instruction in the bytecode stream. In other words, if @var{a} is
+non-zero, set the @code{pc} register to @code{start} + @var{offset}.
+Thus, an offset of zero denotes the beginning of the expression.
+
+The @var{offset} is stored as a sixteen-bit unsigned value, stored
+immediately following the @code{if_goto} bytecode. It is always stored
+most significant byte first, regardless of the target's normal
+endianness. The offset is not guaranteed to fall at any particular
+alignment within the bytecode stream; thus, on machines where fetching a
+16-bit on an unaligned address raises an exception, you should fetch the
+offset one byte at a time.
+
+@item @code{goto} (0x21) @var{offset}: @result{}
+Branch unconditionally to @var{offset}; in other words, set the
+@code{pc} register to @code{start} + @var{offset}.
+
+The offset is stored in the same way as for the @code{if_goto} bytecode.
+
+@item @code{const8} (0x22) @var{n}: @result{} @var{n}
+@itemx @code{const16} (0x23) @var{n}: @result{} @var{n}
+@itemx @code{const32} (0x24) @var{n}: @result{} @var{n}
+@itemx @code{const64} (0x25) @var{n}: @result{} @var{n}
+Push the integer constant @var{n} on the stack, without sign extension.
+To produce a small negative value, push a small twos-complement value,
+and then sign-extend it using the @code{ext} bytecode.
+
+The constant @var{n} is stored in the appropriate number of bytes
+following the @code{const}@var{b} bytecode. The constant @var{n} is
+always stored most significant byte first, regardless of the target's
+normal endianness. The constant is not guaranteed to fall at any
+particular alignment within the bytecode stream; thus, on machines where
+fetching a 16-bit on an unaligned address raises an exception, you
+should fetch @var{n} one byte at a time.
+
+@item @code{reg} (0x26) @var{n}: @result{} @var{a}
+Push the value of register number @var{n}, without sign extension. The
+registers are numbered following GDB's conventions.
+
+The register number @var{n} is encoded as a 16-bit unsigned integer
+immediately following the @code{reg} bytecode. It is always stored most
+significant byte first, regardless of the target's normal endianness.
+The register number is not guaranteed to fall at any particular
+alignment within the bytecode stream; thus, on machines where fetching a
+16-bit on an unaligned address raises an exception, you should fetch the
+register number one byte at a time.
+
+@item @code{trace} (0x0c): @var{addr} @var{size} @result{}
+Record the contents of the @var{size} bytes at @var{addr} in a trace
+buffer, for later retrieval by GDB.
+
+@item @code{trace_quick} (0x0d) @var{size}: @var{addr} @result{} @var{addr}
+Record the contents of the @var{size} bytes at @var{addr} in a trace
+buffer, for later retrieval by GDB. @var{size} is a single byte
+unsigned integer following the @code{trace} opcode.
+
+This bytecode is equivalent to the sequence @code{dup const8 @var{size}
+trace}, but we provide it anyway to save space in bytecode strings.
+
+@item @code{trace16} (0x30) @var{size}: @var{addr} @result{} @var{addr}
+Identical to trace_quick, except that @var{size} is a 16-bit big-endian
+unsigned integer, not a single byte. This should probably have been
+named @code{trace_quick16}, for consistency.
+
+@item @code{end} (0x27): @result{}
+Stop executing bytecode; the result should be the top element of the
+stack. If the purpose of the expression was to compute an lvalue or a
+range of memory, then the next-to-top of the stack is the lvalue's
+address, and the top of the stack is the lvalue's size, in bytes.
+
+@end table
+
+
+@node Using Agent Expressions
+@section Using Agent Expressions
+
+Here is a sketch of a full non-stop debugging cycle, showing how agent
+expressions fit into the process.
+
+@itemize @bullet
+
+@item
+The user selects trace points in the program's code at which GDB should
+collect data.
+
+@item
+The user specifies expressions to evaluate at each trace point. These
+expressions may denote objects in memory, in which case those objects'
+contents are recorded as the program runs, or computed values, in which
+case the values themselves are recorded.
+
+@item
+GDB transmits the tracepoints and their associated expressions to the
+GDB agent, running on the debugging target.
+
+@item
+The agent arranges to be notified when a trace point is hit. Note that,
+on some systems, the target operating system is completely responsible
+for collecting the data; see @ref{Tracing on Symmetrix}.
+
+@item
+When execution on the target reaches a trace point, the agent evaluates
+the expressions associated with that trace point, and records the
+resulting values and memory ranges.
+
+@item
+Later, when the user selects a given trace event and inspects the
+objects and expression values recorded, GDB talks to the agent to
+retrieve recorded data as necessary to meet the user's requests. If the
+user asks to see an object whose contents have not been recorded, GDB
+reports an error.
+
+@end itemize
+
+
+@node Varying Target Capabilities
+@section Varying Target Capabilities
+
+Some targets don't support floating-point, and some would rather not
+have to deal with @code{long long} operations. Also, different targets
+will have different stack sizes, and different bytecode buffer lengths.
+
+Thus, GDB needs a way to ask the target about itself. We haven't worked
+out the details yet, but in general, GDB should be able to send the
+target a packet asking it to describe itself. The reply should be a
+packet whose length is explicit, so we can add new information to the
+packet in future revisions of the agent, without confusing old versions
+of GDB, and it should contain a version number. It should contain at
+least the following information:
+
+@itemize @bullet
+
+@item
+whether floating point is supported
+
+@item
+whether @code{long long} is supported
+
+@item
+maximum acceptable size of bytecode stack
+
+@item
+maximum acceptable length of bytecode expressions
+
+@item
+which registers are actually available for collection
+
+@item
+whether the target supports disabled tracepoints
+
+@end itemize
+
+
+
+@node Tracing on Symmetrix
+@section Tracing on Symmetrix
+
+This section documents the API used by the GDB agent to collect data on
+Symmetrix systems.
+
+Cygnus originally implemented these tracing features to help EMC
+Corporation debug their Symmetrix high-availability disk drives. The
+Symmetrix application code already includes substantial tracing
+facilities; the GDB agent for the Symmetrix system uses those facilities
+for its own data collection, via the API described here.
+
+@deftypefn Function DTC_RESPONSE adbg_find_memory_in_frame (FRAME_DEF *@var{frame}, char *@var{address}, char **@var{buffer}, unsigned int *@var{size})
+Search the trace frame @var{frame} for memory saved from @var{address}.
+If the memory is available, provide the address of the buffer holding
+it; otherwise, provide the address of the next saved area.
+
+@itemize @bullet
+
+@item
+If the memory at @var{address} was saved in @var{frame}, set
+@code{*@var{buffer}} to point to the buffer in which that memory was
+saved, set @code{*@var{size}} to the number of bytes from @var{address}
+that are saved at @code{*@var{buffer}}, and return
+@code{OK_TARGET_RESPONSE}. (Clearly, in this case, the function will
+always set @code{*@var{size}} to a value greater than zero.)
+
+@item
+If @var{frame} does not record any memory at @var{address}, set
+@code{*@var{size}} to the distance from @var{address} to the start of
+the saved region with the lowest address higher than @var{address}. If
+there is no memory saved from any higher address, set @code{*@var{size}}
+to zero. Return @code{NOT_FOUND_TARGET_RESPONSE}.
+@end itemize
+
+These two possibilities allow the caller to either retrieve the data, or
+walk the address space to the next saved area.
+@end deftypefn
+
+This function allows the GDB agent to map the regions of memory saved in
+a particular frame, and retrieve their contents efficiently.
+
+This function also provides a clean interface between the GDB agent and
+the Symmetrix tracing structures, making it easier to adapt the GDB
+agent to future versions of the Symmetrix system, and vice versa. This
+function searches all data saved in @var{frame}, whether the data is
+there at the request of a bytecode expression, or because it falls in
+one of the format's memory ranges, or because it was saved from the top
+of the stack. EMC can arbitrarily change and enhance the tracing
+mechanism, but as long as this function works properly, all collected
+memory is visible to GDB.
+
+The function itself is straightforward to implement. A single pass over
+the trace frame's stack area, memory ranges, and expression blocks can
+yield the address of the buffer (if the requested address was saved),
+and also note the address of the next higher range of memory, to be
+returned when the search fails.
+
+As an example, suppose the trace frame @code{f} has saved sixteen bytes
+from address @code{0x8000} in a buffer at @code{0x1000}, and thirty-two
+bytes from address @code{0xc000} in a buffer at @code{0x1010}. Here are
+some sample calls, and the effect each would have:
+
+@table @code
+
+@item adbg_find_memory_in_frame (f, (char*) 0x8000, &buffer, &size)
+This would set @code{buffer} to @code{0x1000}, set @code{size} to
+sixteen, and return @code{OK_TARGET_RESPONSE}, since @code{f} saves
+sixteen bytes from @code{0x8000} at @code{0x1000}.
+
+@item adbg_find_memory_in_frame (f, (char *) 0x8004, &buffer, &size)
+This would set @code{buffer} to @code{0x1004}, set @code{size} to
+twelve, and return @code{OK_TARGET_RESPONSE}, since @file{f} saves the
+twelve bytes from @code{0x8004} starting four bytes into the buffer at
+@code{0x1000}. This shows that request addresses may fall in the middle
+of saved areas; the function should return the address and size of the
+remainder of the buffer.
+
+@item adbg_find_memory_in_frame (f, (char *) 0x8100, &buffer, &size)
+This would set @code{size} to @code{0x3f00} and return
+@code{NOT_FOUND_TARGET_RESPONSE}, since there is no memory saved in
+@code{f} from the address @code{0x8100}, and the next memory available
+is at @code{0x8100 + 0x3f00}, or @code{0xc000}. This shows that request
+addresses may fall outside of all saved memory ranges; the function
+should indicate the next saved area, if any.
+
+@item adbg_find_memory_in_frame (f, (char *) 0x7000, &buffer, &size)
+This would set @code{size} to @code{0x1000} and return
+@code{NOT_FOUND_TARGET_RESPONSE}, since the next saved memory is at
+@code{0x7000 + 0x1000}, or @code{0x8000}.
+
+@item adbg_find_memory_in_frame (f, (char *) 0xf000, &buffer, &size)
+This would set @code{size} to zero, and return
+@code{NOT_FOUND_TARGET_RESPONSE}. This shows how the function tells the
+caller that no further memory ranges have been saved.
+
+@end table
+
+As another example, here is a function which will print out the
+addresses of all memory saved in the trace frame @code{frame} on the
+Symmetrix INLINES console:
+@example
+void
+print_frame_addresses (FRAME_DEF *frame)
+@{
+ char *addr;
+ char *buffer;
+ unsigned long size;
+
+ addr = 0;
+ for (;;)
+ @{
+ /* Either find out how much memory we have here, or discover
+ where the next saved region is. */
+ if (adbg_find_memory_in_frame (frame, addr, &buffer, &size)
+ == OK_TARGET_RESPONSE)
+ printp ("saved %x to %x\n", addr, addr + size);
+ if (size == 0)
+ break;
+ addr += size;
+ @}
+@}
+@end example
+
+Note that there is not necessarily any connection between the order in
+which the data is saved in the trace frame, and the order in which
+@code{adbg_find_memory_in_frame} will return those memory ranges. The
+code above will always print the saved memory regions in order of
+increasing address, while the underlying frame structure might store the
+data in a random order.
+
+[[This section should cover the rest of the Symmetrix functions the stub
+relies upon, too.]]
+
+@node Rationale
+@section Rationale
+
+Some of the design decisions apparent above are arguable.
+
+@table @b
+
+@item What about stack overflow/underflow?
+GDB should be able to query the target to discover its stack size.
+Given that information, GDB can determine at translation time whether a
+given expression will overflow the stack. But this spec isn't about
+what kinds of error-checking GDB ought to do.
+
+@item Why are you doing everything in LONGEST?
+
+Speed isn't important, but agent code size is; using LONGEST brings in a
+bunch of support code to do things like division, etc. So this is a
+serious concern.
+
+First, note that you don't need different bytecodes for different
+operand sizes. You can generate code without @emph{knowing} how big the
+stack elements actually are on the target. If the target only supports
+32-bit ints, and you don't send any 64-bit bytecodes, everything just
+works. The observation here is that the MIPS and the Alpha have only
+fixed-size registers, and you can still get C's semantics even though
+most instructions only operate on full-sized words. You just need to
+make sure everything is properly sign-extended at the right times. So
+there is no need for 32- and 64-bit variants of the bytecodes. Just
+implement everything using the largest size you support.
+
+GDB should certainly check to see what sizes the target supports, so the
+user can get an error earlier, rather than later. But this information
+is not necessary for correctness.
+
+
+@item Why don't you have @code{>} or @code{<=} operators?
+I want to keep the interpreter small, and we don't need them. We can
+combine the @code{less_} opcodes with @code{log_not}, and swap the order
+of the operands, yielding all four asymmetrical comparison operators.
+For example, @code{(x <= y)} is @code{! (x > y)}, which is @code{! (y <
+x)}.
+
+@item Why do you have @code{log_not}?
+@itemx Why do you have @code{ext}?
+@itemx Why do you have @code{zero_ext}?
+These are all easily synthesized from other instructions, but I expect
+them to be used frequently, and they're simple, so I include them to
+keep bytecode strings short.
+
+@code{log_not} is equivalent to @code{const8 0 equal}; it's used in half
+the relational operators.
+
+@code{ext @var{n}} is equivalent to @code{const8 @var{s-n} lsh const8
+@var{s-n} rsh_signed}, where @var{s} is the size of the stack elements;
+it follows @code{ref@var{m}} and @var{reg} bytecodes when the value
+should be signed. See the next bulleted item.
+
+@code{zero_ext @var{n}} is equivalent to @code{const@var{m} @var{mask}
+log_and}; it's used whenever we push the value of a register, because we
+can't assume the upper bits of the register aren't garbage.
+
+@item Why not have sign-extending variants of the @code{ref} operators?
+Because that would double the number of @code{ref} operators, and we
+need the @code{ext} bytecode anyway for accessing bitfields.
+
+@item Why not have constant-address variants of the @code{ref} operators?
+Because that would double the number of @code{ref} operators again, and
+@code{const32 @var{address} ref32} is only one byte longer.
+
+@item Why do the @code{ref@var{n}} operators have to support unaligned fetches?
+GDB will generate bytecode that fetches multi-byte values at unaligned
+addresses whenever the executable's debugging information tells it to.
+Furthermore, GDB does not know the value the pointer will have when GDB
+generates the bytecode, so it cannot determine whether a particular
+fetch will be aligned or not.
+
+In particular, structure bitfields may be several bytes long, but follow
+no alignment rules; members of packed structures are not necessarily
+aligned either.
+
+In general, there are many cases where unaligned references occur in
+correct C code, either at the programmer's explicit request, or at the
+compiler's discretion. Thus, it is simpler to make the GDB agent
+bytecodes work correctly in all circumstances than to make GDB guess in
+each case whether the compiler did the usual thing.
+
+@item Why are there no side-effecting operators?
+Because our current client doesn't want them? That's a cheap answer. I
+think the real answer is that I'm afraid of implementing function
+calls. We should re-visit this issue after the present contract is
+delivered.
+
+@item Why aren't the @code{goto} ops PC-relative?
+The interpreter has the base address around anyway for PC bounds
+checking, and it seemed simpler.
+
+@item Why is there only one offset size for the @code{goto} ops?
+Offsets are currently sixteen bits. I'm not happy with this situation
+either:
+
+Suppose we have multiple branch ops with different offset sizes. As I
+generate code left-to-right, all my jumps are forward jumps (there are
+no loops in expressions), so I never know the target when I emit the
+jump opcode. Thus, I have to either always assume the largest offset
+size, or do jump relaxation on the code after I generate it, which seems
+like a big waste of time.
+
+I can imagine a reasonable expression being longer than 256 bytes. I
+can't imagine one being longer than 64k. Thus, we need 16-bit offsets.
+This kind of reasoning is so bogus, but relaxation is pathetic.
+
+The other approach would be to generate code right-to-left. Then I'd
+always know my offset size. That might be fun.
+
+@item Where is the function call bytecode?
+
+When we add side-effects, we should add this.
+
+@item Why does the @code{reg} bytecode take a 16-bit register number?
+
+Intel's IA-64 architecture has 128 general-purpose registers,
+and 128 floating-point registers, and I'm sure it has some random
+control registers.
+
+@item Why do we need @code{trace} and @code{trace_quick}?
+Because GDB needs to record all the memory contents and registers an
+expression touches. If the user wants to evaluate an expression
+@code{x->y->z}, the agent must record the values of @code{x} and
+@code{x->y} as well as the value of @code{x->y->z}.
+
+@item Don't the @code{trace} bytecodes make the interpreter less general?
+They do mean that the interpreter contains special-purpose code, but
+that doesn't mean the interpreter can only be used for that purpose. If
+an expression doesn't use the @code{trace} bytecodes, they don't get in
+its way.
+
+@item Why doesn't @code{trace_quick} consume its arguments the way everything else does?
+In general, you do want your operators to consume their arguments; it's
+consistent, and generally reduces the amount of stack rearrangement
+necessary. However, @code{trace_quick} is a kludge to save space; it
+only exists so we needn't write @code{dup const8 @var{SIZE} trace}
+before every memory reference. Therefore, it's okay for it not to
+consume its arguments; it's meant for a specific context in which we
+know exactly what it should do with the stack. If we're going to have a
+kludge, it should be an effective kludge.
+
+@item Why does @code{trace16} exist?
+That opcode was added by the customer that contracted Cygnus for the
+data tracing work. I personally think it is unnecessary; objects that
+large will be quite rare, so it is okay to use @code{dup const16
+@var{size} trace} in those cases.
+
+Whatever we decide to do with @code{trace16}, we should at least leave
+opcode 0x30 reserved, to remain compatible with the customer who added
+it.
+
+@end table
diff --git a/contrib/gdb/gdb/doc/all-cfg.texi b/contrib/gdb/gdb/doc/all-cfg.texi
new file mode 100644
index 0000000..b680ea2
--- /dev/null
+++ b/contrib/gdb/gdb/doc/all-cfg.texi
@@ -0,0 +1,45 @@
+@c GDB MANUAL configuration file.
+@c
+@c Copyright 1993, 1995, 1999, 2002 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 HP PA-RISC target ONLY:
+@clear HPPA
+@c
+@c Refrain from discussing how to configure sw and format doc?
+@clear PRECONFIGURED
+@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 @sc{gdb}
+@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 @sc{gcc}
+@c
+@c Name of GCC program
+@set GCC gcc
diff --git a/contrib/gdb/gdb/doc/annotate.texinfo b/contrib/gdb/gdb/doc/annotate.texinfo
new file mode 100644
index 0000000..2fb79d3
--- /dev/null
+++ b/contrib/gdb/gdb/doc/annotate.texinfo
@@ -0,0 +1,834 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename annotate.info
+
+@c This is a dir.info fragment to support semi-automated addition of
+@c manuals to an info tree.
+@dircategory Software development
+@direntry
+* Annotate: (annotate). The obsolete annotation interface.
+@end direntry
+
+@c
+@include gdb-cfg.texi
+@c
+@settitle @value{GDBN}'s Obsolete Annotations
+@setchapternewpage off
+@c %**end of header
+
+@set EDITION 1.0
+@set DATE July 2003
+
+@c NOTE: cagney/2003-07-28:
+@c Don't make this migration doccument an appendix of GDB's user guide.
+@c By keeping this separate, the size of the user guide is contained. If
+@c the user guide to get much bigger it would need to switch to a larger,
+@c more expensive, form factor and would drive up the manuals publication
+@c cost. Having a smaller cheaper manual helps the GNU Press with its sales.
+
+@ifinfo
+This file documents @value{GDBN}'s obsolete annotations.
+
+Copyright 1994, 1995, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts. A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+
+@end ifinfo
+
+@titlepage
+@title @value{GDBN}'s Obsolete Annotations
+@subtitle Edition @value{EDITION}
+@subtitle @value{DATE}
+@author Free Software Foundation
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1994, 1995, 2000, 2001, 2003 Free Software
+Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts. A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+@end titlepage
+
+@ifinfo
+@node Top
+@top GDB Annotations
+
+This document describes the obsolete level two annotation interface
+implemented in older @value{GDBN} versions.
+
+@ignore
+This is Edition @value{EDITION}, @value{DATE}.
+@end ignore
+@end ifinfo
+
+@menu
+* Annotations Overview:: What annotations are; the general syntax.
+* Limitations:: Limitations of the annotation interface.
+* Migrating to GDB/MI:: Migrating to GDB/MI
+* Server Prefix:: Issuing a command without affecting user state.
+* Value Annotations:: Values are marked as such.
+* Frame Annotations:: Stack frames are annotated.
+* Displays:: @value{GDBN} can be told to display something periodically.
+* Prompting:: Annotations marking @value{GDBN}'s need for input.
+* Errors:: Annotations for error messages.
+* Breakpoint Info:: Information on breakpoints.
+* Invalidation:: Some annotations describe things now invalid.
+* Annotations for Running::
+ Whether the program is running, how it stopped, etc.
+* Source Annotations:: Annotations describing source code.
+
+* GNU Free Documentation License::
+@end menu
+
+@contents
+
+@node Annotations Overview
+@chapter What is an Annotation?
+@cindex annotations
+
+To produce obsolete level two annotations, start @value{GDBN} 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 @value{GDBN}. Currently there is
+no need for @value{GDBN} 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 @value{GDBN} with annotations is:
+
+@smallexample
+$ gdb --annotate=2
+GNU GDB 5.0
+Copyright 2000 Free Software Foundation, Inc.
+GDB is free software, covered by the GNU General Public License,
+and you are welcome to change it and/or 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.
+This GDB was configured as "sparc-sun-sunos4.1.3"
+
+^Z^Zpre-prompt
+(gdb)
+^Z^Zprompt
+quit
+
+^Z^Zpost-prompt
+$
+@end smallexample
+
+Here @samp{quit} is input to @value{GDBN}; the rest is output from
+@value{GDBN}. The three lines beginning @samp{^Z^Z} (where @samp{^Z}
+denotes a @samp{control-z} character) are annotations; the rest is
+output from @value{GDBN}.
+
+@node Limitations
+@chapter Limitations of the Annotation Interface
+
+The level two annotations mechanism is known to have a number of
+technical and architectural limitations. As a consequence, in 2001,
+with the release of @value{GDBN} 5.1 and the addition of @sc{gdb/mi},
+the annotation interface was marked as deprecated.
+
+This chapter discusses the known problems.
+
+@section Dependant on @sc{cli} output
+
+The annotation interface works by interspersing markups with
+@value{GDBN} normal command-line interpreter output. Unfortunately, this
+makes the annotation client dependant on not just the annotations, but
+also the @sc{cli} output. This is because the client is forced to
+assume that specific @value{GDBN} commands provide specific information.
+Any change to @value{GDBN}'s @sc{cli} output modifies or removes that
+information and, consequently, likely breaks the client.
+
+Since the @sc{gdb/mi} output is independant of the @sc{cli}, it does not
+have this problem.
+
+@section Scalability
+
+The annotation interface relies on value annotations (@pxref{Value
+Annotations}) and the display mechanism as a way of obtaining up-to-date
+value information. These mechanisms are not scalable.
+
+In a graphical environment, where many values can be displayed
+simultaneously, a serious performance problem occurs when the client
+tries to first extract from @value{GDBN}, and then re-display, all those
+values. The client should instead only request and update the values
+that changed.
+
+The @sc{gdb/mi} Variable Objects provide just that mechanism.
+
+@section Correctness
+
+The annotation interface assumes that a variable's value can only be
+changed when the target is running. This assumption is not correct. A
+single assignment to a single variable can result in the entire target,
+and all displayed values, needing an update.
+
+The @sc{gdb/mi} Variable Objects include a mechanism for efficiently
+reporting such changes.
+
+@section Reliability
+
+The @sc{gdb/mi} interface includes a dedicated test directory
+(@file{gdb/gdb.mi}), and any addition or fix to @sc{gdb/mi} must include
+testsuite changes.
+
+@section Maintainability
+
+The annotation mechanism was implemented by interspersing @sc{cli} print
+statements with various annotations. As a consequence, any @sc{cli}
+output change can alter the annotation output.
+
+Since the @sc{gdb/mi} output is independant of the @sc{cli}, and the
+@sc{gdb/mi} is increasingly implemented independant of the @sc{cli}
+code, its long term maintenance is much easier.
+
+@node Migrating to GDB/MI
+@chapter Migrating to @sc{gdb/mi}
+
+By using the @samp{interp mi} command, it is possible for annotation
+clients to invoke @sc{gdb/mi} commands, and hence access the
+@sc{gdb/mi}. By doing this, existing annotation clients have a
+migration path from this obsolete interface to @sc{gdb/mi}.
+
+@node Server Prefix
+@chapter The Server Prefix
+@cindex server prefix for annotations
+
+To issue a command to @value{GDBN} 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 @value{GDBN}'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 Value Annotations
+@chapter Values
+
+@emph{Value Annotations have been removed. @sc{gdb/mi} instead provides
+Variable Objects.}
+
+@cindex annotations for values
+When a value is printed in various contexts, @value{GDBN} 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
+
+@smallexample
+^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 smallexample
+
+@noindent
+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:
+
+@smallexample
+^Z^Zvalue-begin @var{value-flags}
+@var{the-value}
+^Z^Zvalue-end
+@end smallexample
+
+@findex arg-begin
+@findex arg-name-end
+@findex arg-value
+@findex arg-end
+When @value{GDBN} prints an argument to a function (for example, in the output
+from the @code{backtrace} command), it annotates it as follows:
+
+@smallexample
+^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 smallexample
+
+@noindent
+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, @value{GDBN} annotates it as follows:
+
+@smallexample
+^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 smallexample
+
+@noindent
+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, @value{GDBN} annotates it as follows:
+
+@smallexample
+^Z^Zarray-section-begin @var{array-index} @var{value-flags}
+@end smallexample
+
+@noindent
+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
+@smallexample
+@samp{,} @var{whitespace} ; @r{omitted for the first element}
+@var{the-value}
+^Z^Zelt
+@end smallexample
+
+or a repeated element
+
+@findex elt-rep
+@findex elt-rep-end
+@smallexample
+@samp{,} @var{whitespace} ; @r{omitted for the first element}
+@var{the-value}
+^Z^Zelt-rep @var{number-of-repetitions}
+@var{repetition-string}
+^Z^Zelt-rep-end
+@end smallexample
+
+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-repetitions} 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 repetition is being depicted.
+
+@findex array-section-end
+Once all the array elements have been output, the array annotation is
+ended with
+
+@smallexample
+^Z^Zarray-section-end
+@end smallexample
+
+@node Frame Annotations
+@chapter Frames
+
+@emph{Value Annotations have been removed. @sc{gdb/mi} instead provides
+a number of frame commands.}
+
+@emph{Frame annotations are no longer available. The @sc{gdb/mi}
+provides @samp{-stack-list-arguments}, @samp{-stack-list-locals}, and
+@samp{-stack-list-frames} commands.}
+
+@cindex annotations for frames
+Whenever @value{GDBN} prints a frame, it annotates it. For example, this applies
+to frames printed when @value{GDBN} stops, output from commands such as
+@code{backtrace} or @code{up}, etc.
+
+@findex frame-begin
+The frame annotation begins with
+
+@smallexample
+^Z^Zframe-begin @var{level} @var{address}
+@var{level-string}
+@end smallexample
+
+@noindent
+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
+@smallexample
+^Z^Zframe-end
+@end smallexample
+
+Between these annotations is the main body of the frame, which can
+consist of
+
+@itemize @bullet
+@item
+@findex function-call
+@smallexample
+^Z^Zfunction-call
+@var{function-call-string}
+@end smallexample
+
+where @var{function-call-string} is text designed to convey to the user
+that this frame is associated with a function call made by @value{GDBN} to a
+function in the program being debugged.
+
+@item
+@findex signal-handler-caller
+@smallexample
+^Z^Zsignal-handler-caller
+@var{signal-handler-caller-string}
+@end smallexample
+
+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
+
+@smallexample
+^Z^Zframe-address
+@var{address}
+^Z^Zframe-address-end
+@var{separator-string}
+@end smallexample
+
+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
+
+@smallexample
+^Z^Zframe-function-name
+@var{function-name}
+^Z^Zframe-args
+@var{arguments}
+@end smallexample
+
+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{Value Annotations}).
+
+@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:
+
+@smallexample
+^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 smallexample
+
+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 @value{GDBN} 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
+
+@smallexample
+^Z^Zframe-where
+@var{information}
+@end smallexample
+
+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 Annotations}) 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
+
+@emph{Display Annotations have been removed. @sc{gdb/mi} instead
+provides Variable Objects.}
+
+@findex display-begin
+@findex display-number-end
+@findex display-format
+@findex display-expression
+@findex display-expression-end
+@findex display-value
+@findex display-end
+@cindex annotations for display
+When @value{GDBN} is told to display something using the @code{display} command,
+the results of the display are annotated:
+
+@smallexample
+^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 smallexample
+
+@noindent
+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 @value{GDBN} Input
+
+@cindex annotations for prompts
+When @value{GDBN} 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:
+
+@smallexample
+^Z^Zpre-prompt
+^Z^Zprompt
+^Z^Zpost-prompt
+@end smallexample
+
+The input types are
+
+@table @code
+@findex pre-prompt
+@findex prompt
+@findex post-prompt
+@item prompt
+When @value{GDBN} is prompting for a command (the main @value{GDBN} prompt).
+
+@findex pre-commands
+@findex commands
+@findex post-commands
+@item commands
+When @value{GDBN} 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 @value{GDBN} wants the user to select between various overloaded functions.
+
+@findex pre-query
+@findex query
+@findex post-query
+@item query
+When @value{GDBN} 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 @value{GDBN} 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
+@cindex annotations for errors, warnings and interrupts
+
+@findex quit
+@smallexample
+^Z^Zquit
+@end smallexample
+
+This annotation occurs right before @value{GDBN} responds to an interrupt.
+
+@findex error
+@smallexample
+^Z^Zerror
+@end smallexample
+
+This annotation occurs right before @value{GDBN} responds to an error.
+
+Quit and error annotations indicate that any annotations which @value{GDBN} 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 @value{GDBN} is immediately returning all the way
+to the top level.
+
+@findex error-begin
+A quit or error annotation may be preceded by
+
+@smallexample
+^Z^Zerror-begin
+@end smallexample
+
+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
+
+@emph{Breakpoint Annotations have been removed. @sc{gdb/mi} instead
+provides breakpoint commands.}
+
+@cindex annotations for breakpoints
+The output from the @code{info breakpoints} command is annotated as follows:
+
+@findex breakpoints-headers
+@findex breakpoints-table
+@smallexample
+^Z^Zbreakpoints-headers
+@var{header-entry}
+^Z^Zbreakpoints-table
+@end smallexample
+
+@noindent
+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
+@smallexample
+^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 smallexample
+
+Note that @var{address} is intended for user consumption---the syntax
+varies depending on the language.
+
+The output ends with
+
+@findex breakpoints-table-end
+@smallexample
+^Z^Zbreakpoints-table-end
+@end smallexample
+
+@node Invalidation
+@chapter Invalidation Notices
+
+@cindex annotations for invalidation messages
+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 Annotations for Running
+@chapter Running the Program
+@cindex annotations for running programs
+
+@findex starting
+@findex stopping
+When the program starts executing due to a @value{GDBN} command such as
+@code{step} or @code{continue},
+
+@smallexample
+^Z^Zstarting
+@end smallexample
+
+is output. When the program stops,
+
+@smallexample
+^Z^Zstopped
+@end smallexample
+
+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:
+
+@smallexample
+@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 smallexample
+
+@noindent
+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 @value{GDBN} 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 Annotations
+@chapter Displaying Source
+@cindex annotations for source display
+
+@findex source
+The following annotation is used instead of displaying source code:
+
+@smallexample
+^Z^Zsource @var{filename}:@var{line}:@var{character}:@var{middle}:@var{addr}
+@end smallexample
+
+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).
+
+@raisesections
+@include fdl.texi
+@lowersections
+
+@ignore
+@node Index
+@unnumbered Index
+
+@printindex fn
+@end ignore
+
+@bye
diff --git a/contrib/gdb/gdb/doc/fdl.texi b/contrib/gdb/gdb/doc/fdl.texi
new file mode 100644
index 0000000..11737cc
--- /dev/null
+++ b/contrib/gdb/gdb/doc/fdl.texi
@@ -0,0 +1,452 @@
+
+@node GNU Free Documentation License
+@appendixsec GNU Free Documentation License
+
+@cindex FDL, GNU Free Documentation License
+@center Version 1.2, November 2002
+
+@display
+Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document @dfn{free} in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of ``copyleft'', which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The ``Document'', below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as ``you''. You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A ``Modified Version'' of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A ``Secondary Section'' is a named appendix or a front-matter section
+of the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject. (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The ``Invariant Sections'' are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The ``Cover Texts'' are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not ``Transparent'' is called ``Opaque''.
+
+Examples of suitable formats for Transparent copies include plain
+@sc{ascii} without markup, Texinfo input format, La@TeX{} input
+format, @acronym{SGML} or @acronym{XML} using a publicly available
+@acronym{DTD}, and standard-conforming simple @acronym{HTML},
+PostScript or @acronym{PDF} designed for human modification. Examples
+of transparent image formats include @acronym{PNG}, @acronym{XCF} and
+@acronym{JPG}. Opaque formats include proprietary formats that can be
+read and edited only by proprietary word processors, @acronym{SGML} or
+@acronym{XML} for which the @acronym{DTD} and/or processing tools are
+not generally available, and the machine-generated @acronym{HTML},
+PostScript or @acronym{PDF} produced by some word processors for
+output purposes only.
+
+The ``Title Page'' means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, ``Title Page'' means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section ``Entitled XYZ'' means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as ``Acknowledgements'',
+``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
+of such a section when you modify the Document means that it remains a
+section ``Entitled XYZ'' according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+@item
+VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+@item
+MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+@enumerate A
+@item
+Use in the Title Page (and on the covers, if any) a title distinct
+from that of the Document, and from those of previous versions
+(which should, if there were any, be listed in the History section
+of the Document). You may use the same title as a previous version
+if the original publisher of that version gives permission.
+
+@item
+List on the Title Page, as authors, one or more persons or entities
+responsible for authorship of the modifications in the Modified
+Version, together with at least five of the principal authors of the
+Document (all of its principal authors, if it has fewer than five),
+unless they release you from this requirement.
+
+@item
+State on the Title page the name of the publisher of the
+Modified Version, as the publisher.
+
+@item
+Preserve all the copyright notices of the Document.
+
+@item
+Add an appropriate copyright notice for your modifications
+adjacent to the other copyright notices.
+
+@item
+Include, immediately after the copyright notices, a license notice
+giving the public permission to use the Modified Version under the
+terms of this License, in the form shown in the Addendum below.
+
+@item
+Preserve in that license notice the full lists of Invariant Sections
+and required Cover Texts given in the Document's license notice.
+
+@item
+Include an unaltered copy of this License.
+
+@item
+Preserve the section Entitled ``History'', Preserve its Title, and add
+to it an item stating at least the title, year, new authors, and
+publisher of the Modified Version as given on the Title Page. If
+there is no section Entitled ``History'' in the Document, create one
+stating the title, year, authors, and publisher of the Document as
+given on its Title Page, then add an item describing the Modified
+Version as stated in the previous sentence.
+
+@item
+Preserve the network location, if any, given in the Document for
+public access to a Transparent copy of the Document, and likewise
+the network locations given in the Document for previous versions
+it was based on. These may be placed in the ``History'' section.
+You may omit a network location for a work that was published at
+least four years before the Document itself, or if the original
+publisher of the version it refers to gives permission.
+
+@item
+For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
+the Title of the section, and preserve in the section all the
+substance and tone of each of the contributor acknowledgements and/or
+dedications given therein.
+
+@item
+Preserve all the Invariant Sections of the Document,
+unaltered in their text and in their titles. Section numbers
+or the equivalent are not considered part of the section titles.
+
+@item
+Delete any section Entitled ``Endorsements''. Such a section
+may not be included in the Modified Version.
+
+@item
+Do not retitle any existing section to be Entitled ``Endorsements'' or
+to conflict in title with any Invariant Section.
+
+@item
+Preserve any Warranty Disclaimers.
+@end enumerate
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled ``Endorsements'', provided it contains
+nothing but endorsements of your Modified Version by various
+parties---for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+@item
+COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled ``History''
+in the various original documents, forming one section Entitled
+``History''; likewise combine any sections Entitled ``Acknowledgements'',
+and any sections Entitled ``Dedications''. You must delete all
+sections Entitled ``Endorsements.''
+
+@item
+COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+@item
+AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an ``aggregate'' if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+@item
+TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled ``Acknowledgements'',
+``Dedications'', or ``History'', the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+@item
+TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document 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.
+
+@item
+FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation 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. See
+@uref{http://www.gnu.org/copyleft/}.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+@end enumerate
+
+@page
+@appendixsubsec ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+@smallexample
+@group
+ Copyright (C) @var{year} @var{your name}.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ Texts. A copy of the license is included in the section entitled ``GNU
+ Free Documentation License''.
+@end group
+@end smallexample
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the ``with...Texts.'' line with this:
+
+@smallexample
+@group
+ with the Invariant Sections being @var{list their titles}, with
+ the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
+ being @var{list}.
+@end group
+@end smallexample
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+@c Local Variables:
+@c ispell-local-pdict: "ispell-dict"
+@c End:
+
diff --git a/contrib/gdb/gdb/doc/gdb.info-1 b/contrib/gdb/gdb/doc/gdb.info-1
new file mode 100644
index 0000000..decf454
--- /dev/null
+++ b/contrib/gdb/gdb/doc/gdb.info-1
@@ -0,0 +1,7636 @@
+This is gdb.info, produced by makeinfo version 4.6 from ./gdb.texinfo.
+
+INFO-DIR-SECTION Software development
+START-INFO-DIR-ENTRY
+* Gdb: (gdb). The GNU debugger.
+END-INFO-DIR-ENTRY
+
+ This file documents the GNU debugger GDB.
+
+ This is the Ninth Edition, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 6.1.1.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+1998,
+1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being "Free Software" and "Free Software Needs Free
+Documentation", with the Front-Cover Texts being "A GNU Manual," and
+with the Back-Cover Texts as in (a) below.
+
+ (a) The Free Software Foundation's Back-Cover Text is: "You have
+freedom to copy and modify this GNU Manual, like GNU software. Copies
+published by the Free Software Foundation raise funds for GNU
+development."
+
+
+File: gdb.info, Node: Top, Next: Summary, Prev: (dir), Up: (dir)
+
+Debugging with GDB
+******************
+
+This file describes GDB, the GNU symbolic debugger.
+
+ This is the Ninth Edition, for GDB Version 6.1.1.
+
+ Copyright (C) 1988-2004 Free Software Foundation, Inc.
+
+* Menu:
+
+* Summary:: Summary of GDB
+* Sample Session:: A sample GDB session
+
+* Invocation:: Getting in and out of GDB
+* Commands:: GDB commands
+* Running:: Running programs under GDB
+* Stopping:: Stopping and continuing
+* Stack:: Examining the stack
+* Source:: Examining source files
+* Data:: Examining data
+* Macros:: Preprocessor Macros
+* Tracepoints:: Debugging remote targets non-intrusively
+* Overlays:: Debugging programs that use overlays
+
+* Languages:: Using GDB with different languages
+
+* Symbols:: Examining the symbol table
+* Altering:: Altering execution
+* GDB Files:: GDB files
+* Targets:: Specifying a debugging target
+* Remote Debugging:: Debugging remote programs
+* Configurations:: Configuration-specific information
+* Controlling GDB:: Controlling GDB
+* Sequences:: Canned sequences of commands
+* TUI:: GDB Text User Interface
+* Interpreters:: Command Interpreters
+* Emacs:: Using GDB under GNU Emacs
+* Annotations:: GDB's annotation interface.
+* GDB/MI:: GDB's Machine Interface.
+
+* GDB Bugs:: Reporting bugs in GDB
+* Formatting Documentation:: How to format and print GDB documentation
+
+* Command Line Editing:: Command Line Editing
+* Using History Interactively:: Using History Interactively
+* Installing GDB:: Installing GDB
+* Maintenance Commands:: Maintenance Commands
+* Remote Protocol:: GDB Remote Serial Protocol
+* Agent Expressions:: The GDB Agent Expression Mechanism
+* Copying:: GNU General Public License says
+ how you can copy and share GDB
+* GNU Free Documentation License:: The license for this documentation
+* Index:: Index
+
+
+File: gdb.info, Node: Summary, Next: Sample Session, Prev: Top, Up: Top
+
+Summary of GDB
+**************
+
+The purpose of a debugger such as GDB 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.
+
+ GDB can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+ * Start your program, specifying anything that might affect its
+ behavior.
+
+ * Make your program stop on specified conditions.
+
+ * Examine what has happened, when your program has stopped.
+
+ * Change things in your program, so you can experiment with
+ correcting the effects of one bug and go on to learn about another.
+
+ You can use GDB to debug programs written in C and C++. For more
+information, see *Note Supported languages: Support. For more
+information, see *Note C and C++: C.
+
+ Support for Modula-2 is partial. For information on Modula-2, see
+*Note Modula-2: Modula-2.
+
+ Debugging Pascal programs which use sets, subranges, file variables,
+or nested functions does not currently work. GDB does not support
+entering expressions, printing values, or similar features using Pascal
+syntax.
+
+ GDB can be used to debug programs written in Fortran, although it
+may be necessary to refer to some variables with a trailing underscore.
+
+ GDB can be used to debug programs written in Objective-C, using
+either the Apple/NeXT or the GNU Objective-C runtime.
+
+* Menu:
+
+* Free Software:: Freely redistributable software
+* Contributors:: Contributors to GDB
+
+
+File: gdb.info, Node: Free Software, Next: Contributors, Up: Summary
+
+Free software
+=============
+
+GDB is "free software", protected by the 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.
+
+Free Software Needs Free Documentation
+======================================
+
+The biggest deficiency in the free software community today is not in
+the software--it is the lack of good free documentation that we can
+include with the free software. Many of our most important programs do
+not come with free reference manuals and free introductory texts.
+Documentation is an essential part of any software package; when an
+important free software package does not come with a free manual and a
+free tutorial, that is a major gap. We have many such gaps today.
+
+ Consider Perl, for instance. The tutorial manuals that people
+normally use are non-free. How did this come about? Because the
+authors of those manuals published them with restrictive terms--no
+copying, no modification, source files not available--which exclude
+them from the free software world.
+
+ That wasn't the first time this sort of thing happened, and it was
+far from the last. Many times we have heard a GNU user eagerly
+describe a manual that he is writing, his intended contribution to the
+community, only to learn that he had ruined everything by signing a
+publication contract to make it non-free.
+
+ Free documentation, like free software, is a matter of freedom, not
+price. The problem with the non-free manual is not that publishers
+charge a price for printed copies--that in itself is fine. (The Free
+Software Foundation sells printed copies of manuals, too.) The problem
+is the restrictions on the use of the manual. Free manuals are
+available in source code form, and give you permission to copy and
+modify. Non-free manuals do not allow this.
+
+ The criteria of freedom for a free manual are roughly the same as for
+free software. Redistribution (including the normal kinds of
+commercial redistribution) must be permitted, so that the manual can
+accompany every copy of the program, both on-line and on paper.
+
+ Permission for modification of the technical content is crucial too.
+When people modify the software, adding or changing features, if they
+are conscientious they will change the manual too--so they can provide
+accurate and clear documentation for the modified program. A manual
+that leaves you no choice but to write a new manual to document a
+changed version of the program is not really available to our community.
+
+ Some kinds of limits on the way modification is handled are
+acceptable. For example, requirements to preserve the original
+author's copyright notice, the distribution terms, or the list of
+authors, are ok. It is also no problem to require modified versions to
+include notice that they were modified. Even entire sections that may
+not be deleted or changed are acceptable, as long as they deal with
+nontechnical topics (like this one). These kinds of restrictions are
+acceptable because they don't obstruct the community's normal use of
+the manual.
+
+ However, it must be possible to modify all the _technical_ content
+of the manual, and then distribute the result in all the usual media,
+through all the usual channels. Otherwise, the restrictions obstruct
+the use of the manual, it is not free, and we need another manual to
+replace it.
+
+ Please spread the word about this issue. Our community continues to
+lose manuals to proprietary publishing. If we spread the word that
+free software needs free reference manuals and free tutorials, perhaps
+the next person who wants to contribute by writing documentation will
+realize, before it is too late, that only free manuals contribute to
+the free software community.
+
+ If you are writing documentation, please insist on publishing it
+under the GNU Free Documentation License or another free documentation
+license. Remember that this decision requires your approval--you don't
+have to let the publisher decide. Some commercial publishers will use
+a free license if you insist, but they will not propose the option; it
+is up to you to raise the issue and say firmly that this is what you
+want. If the publisher you are dealing with refuses, please try other
+publishers. If you're not sure whether a proposed license is free,
+write to <licensing@gnu.org>.
+
+ You can encourage commercial publishers to sell more free, copylefted
+manuals and tutorials by buying them, and particularly by buying copies
+from the publishers that paid for their writing or for major
+improvements. Meanwhile, try to avoid buying non-free documentation at
+all. Check the distribution terms of a manual before you buy it, and
+insist that whoever seeks your business must respect your freedom.
+Check the history of the book, and try to reward the publishers that
+have paid or pay the authors to work on it.
+
+ The Free Software Foundation maintains a list of free documentation
+published by other publishers, at
+<http://www.fsf.org/doc/other-free-books.html>.
+
+
+File: gdb.info, Node: Contributors, Prev: Free Software, Up: Summary
+
+Contributors to GDB
+===================
+
+Richard Stallman was the original author of GDB, and of many other 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
+`ChangeLog' in the GDB distribution approximates a blow-by-blow account.
+
+ Changes much prior to version 2.0 are lost in the mists of time.
+
+ _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!
+
+ So that they may not regard their many labors as thankless, we
+particularly thank those who shepherded GDB through major releases:
+Andrew Cagney (releases 6.1, 6.0, 5.3, 5.2, 5.1 and 5.0); Jim Blandy
+(release 4.18); Jason Molenda (release 4.17); Stan Shebs (release 4.14);
+Fred Fish (releases 4.16, 4.15, 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).
+
+ Richard Stallman, assisted at various times by Peter TerMaat, Chris
+Hanson, and Richard Mlynarik, handled releases through 2.8.
+
+ Michael Tiemann is the author of most of the GNU C++ support in GDB,
+with significant additional contributions from Per Bothner and Daniel
+Berlin. James Clark wrote the GNU C++ demangler. Early work on C++
+was by Peter TerMaat (who also did much general update work leading to
+release 3.0).
+
+ GDB 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.
+
+ Brent Benson of Harris Computer Systems contributed DWARF 2 support.
+
+ 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. Marko Mlinar contributed OpenRISC 1000 support.
+
+ Andreas Schwab contributed M68K GNU/Linux support.
+
+ Rich Schaefer and Peter Schauer helped with support of SunOS shared
+libraries.
+
+ Jay Fenlason and Roland McGrath ensured that GDB and GAS agree about
+several machine instruction sets.
+
+ Patrick Duval, Ted Goldstein, Vikram Koka and Glenn Engel helped
+develop remote debugging. Intel Corporation, Wind River Systems, AMD,
+and ARM contributed remote debugging modules for the i960, VxWorks,
+A29K UDI, and RDI targets, respectively.
+
+ 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, the
+Modula-2 support, and contributed the Languages chapter of this manual.
+
+ Fred Fish wrote most of the support for Unix System Vr4. He also
+enhanced the command-completion support to cover C++ overloaded symbols.
+
+ Hitachi America (now Renesas America), Ltd. sponsored the support for
+H8/300, H8/500, and Super-H processors.
+
+ NEC sponsored the support for the v850, Vr4xxx, and Vr5xxx
+processors.
+
+ Mitsubishi (now Renesas) sponsored the support for D10V, D30V, and
+M32R/D processors.
+
+ Toshiba sponsored the support for the TX39 Mips processor.
+
+ Matsushita sponsored the support for the MN10200 and MN10300
+processors.
+
+ Fujitsu sponsored the support for SPARClite and FR30 processors.
+
+ Kung Hsu, Jeff Law, and Rick Sladkey added support for hardware
+watchpoints.
+
+ Michael Snyder added support for tracepoints.
+
+ Stu Grossman wrote gdbserver.
+
+ Jim Kingdon, Peter Schauer, Ian Taylor, and Stu Grossman made nearly
+innumerable bug fixes and cleanups throughout GDB.
+
+ The following people at the Hewlett-Packard Company contributed
+support for the PA-RISC 2.0 architecture, HP-UX 10.20, 10.30, and 11.0
+(narrow mode), HP's implementation of kernel threads, HP's aC++
+compiler, and the Text User Interface (nee Terminal User Interface):
+Ben Krepp, Richard Title, John Bishop, Susan Macchia, Kathy Mann,
+Satish Pai, India Paul, Steve Rehrauer, and Elena Zannoni. Kim Haase
+provided HP-specific information in this manual.
+
+ DJ Delorie ported GDB to MS-DOS, for the DJGPP project. Robert
+Hoehne made significant contributions to the DJGPP port.
+
+ Cygnus Solutions has sponsored GDB maintenance and much of its
+development since 1991. Cygnus engineers who have worked on GDB
+fulltime include Mark Alexander, Jim Blandy, Per Bothner, Kevin
+Buettner, Edith Epstein, Chris Faylor, Fred Fish, Martin Hunt, Jim
+Ingham, John Gilmore, Stu Grossman, Kung Hsu, Jim Kingdon, John Metzler,
+Fernando Nasser, Geoffrey Noer, Dawn Perchik, Rich Pixley, Zdenek
+Radouch, Keith Seitz, Stan Shebs, David Taylor, and Elena Zannoni. In
+addition, Dave Brolley, Ian Carmichael, Steve Chamberlain, Nick Clifton,
+JT Conklin, Stan Cox, DJ Delorie, Ulrich Drepper, Frank Eigler, Doug
+Evans, Sean Fagan, David Henkel-Wallace, Richard Henderson, Jeff
+Holcomb, Jeff Law, Jim Lemke, Tom Lord, Bob Manson, Michael Meissner,
+Jason Merrill, Catherine Moore, Drew Moseley, Ken Raeburn, Gavin
+Romig-Koch, Rob Savoye, Jamie Smith, Mike Stump, Ian Taylor, Angela
+Thomas, Michael Tiemann, Tom Tromey, Ron Unrau, Jim Wilson, and David
+Zuhn have made contributions both large and small.
+
+ Jim Blandy added support for preprocessor macros, while working for
+Red Hat.
+
+
+File: gdb.info, Node: Sample Session, Next: Invocation, Prev: Summary, Up: Top
+
+A Sample GDB Session
+********************
+
+You can use this manual at your leisure to read all about GDB.
+However, a handful of commands are enough to get started using the
+debugger. This chapter illustrates those commands.
+
+ One of the preliminary versions of GNU `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 `m4'
+session, we define a macro `foo' which expands to `0000'; we then use
+the `m4' built-in `defn' to define `bar' as the same thing. However,
+when we change the open quote string to `<QUOTE>' and the close quote
+string to `<UNQUOTE>', the same procedure fails to define a new synonym
+`baz':
+
+ $ cd gnu/m4
+ $ ./m4
+ define(foo,0000)
+
+ foo
+ 0000
+ define(bar,defn(`foo'))
+
+ bar
+ 0000
+ changequote(<QUOTE>,<UNQUOTE>)
+
+ define(baz,defn(<QUOTE>foo<UNQUOTE>))
+ baz
+ C-d
+ m4: End of input: 0: fatal error: EOF in string
+
+Let us use GDB to try to see what is going on.
+
+ $ gdb m4
+ 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 6.1.1, Copyright 1999 Free Software Foundation, Inc...
+ (gdb)
+
+GDB 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 GDB to use a narrower display width than usual, so that examples
+fit in this manual.
+
+ (gdb) set width 70
+
+We need to see how the `m4' built-in `changequote' works. Having
+looked at the source, we know the relevant subroutine is
+`m4_changequote', so we set a breakpoint there with the GDB `break'
+command.
+
+ (gdb) break m4_changequote
+ Breakpoint 1 at 0x62f4: file builtin.c, line 879.
+
+Using the `run' command, we start `m4' running under GDB control; as
+long as control does not reach the `m4_changequote' subroutine, the
+program runs as usual:
+
+ (gdb) run
+ Starting program: /work/Editorial/gdb/gnu/m4/m4
+ define(foo,0000)
+
+ foo
+ 0000
+
+To trigger the breakpoint, we call `changequote'. GDB suspends
+execution of `m4', displaying information about the context where it
+stops.
+
+ changequote(<QUOTE>,<UNQUOTE>)
+
+ Breakpoint 1, m4_changequote (argc=3, argv=0x33c70)
+ at builtin.c:879
+ 879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3))
+
+Now we use the command `n' (`next') to advance execution to the next
+line of the current function.
+
+ (gdb) n
+ 882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\
+ : nil,
+
+`set_quotes' looks like a promising subroutine. We can go into it by
+using the command `s' (`step') instead of `next'. `step' goes to the
+next line to be executed in _any_ subroutine, so it steps into
+`set_quotes'.
+
+ (gdb) s
+ set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+ 530 if (lquote != def_lquote)
+
+The display that shows the subroutine where `m4' is now suspended (and
+its arguments) is called a stack frame display. It shows a summary of
+the stack. We can use the `backtrace' command (which can also be
+spelled `bt'), to see where we are in the stack as a whole: the
+`backtrace' command displays a stack frame for each active subroutine.
+
+ (gdb) bt
+ #0 set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ 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
+
+We step through a few more lines to see what happens. The first two
+times, we can use `s'; the next two times we use `n' to avoid falling
+into the `xstrdup' subroutine.
+
+ (gdb) s
+ 0x3b5c 532 if (rquote != def_rquote)
+ (gdb) s
+ 0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \
+ def_lquote : xstrdup(lq);
+ (gdb) n
+ 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup(rq);
+ (gdb) n
+ 538 len_lquote = strlen(rquote);
+
+The last line displayed looks a little odd; we can examine the variables
+`lquote' and `rquote' to see if they are in fact the new left and right
+quotes we specified. We use the command `p' (`print') to see their
+values.
+
+ (gdb) p lquote
+ $1 = 0x35d40 "<QUOTE>"
+ (gdb) p rquote
+ $2 = 0x35d50 "<UNQUOTE>"
+
+`lquote' and `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 `l' (`list') command.
+
+ (gdb) 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
+
+Let us step past the two lines that set `len_lquote' and `len_rquote',
+and then examine the values of those variables.
+
+ (gdb) n
+ 539 len_rquote = strlen(lquote);
+ (gdb) n
+ 540 }
+ (gdb) p len_lquote
+ $3 = 9
+ (gdb) p len_rquote
+ $4 = 7
+
+That certainly looks wrong, assuming `len_lquote' and `len_rquote' are
+meant to be the lengths of `lquote' and `rquote' respectively. We can
+set them to better values using the `p' command, since it can print the
+value of any expression--and that expression can include subroutine
+calls and assignments.
+
+ (gdb) p len_lquote=strlen(lquote)
+ $5 = 7
+ (gdb) p len_rquote=strlen(rquote)
+ $6 = 9
+
+Is that enough to fix the problem of using the new quotes with the `m4'
+built-in `defn'? We can allow `m4' to continue executing with the `c'
+(`continue') command, and then try the example that caused trouble
+initially:
+
+ (gdb) c
+ Continuing.
+
+ define(baz,defn(<QUOTE>foo<UNQUOTE>))
+
+ baz
+ 0000
+
+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 `m4' exit by giving it an EOF as input:
+
+ C-d
+ Program exited normally.
+
+The message `Program exited normally.' is from GDB; it indicates `m4'
+has finished executing. We can end our GDB session with the GDB `quit'
+command.
+
+ (gdb) quit
+
+
+File: gdb.info, Node: Invocation, Next: Commands, Prev: Sample Session, Up: Top
+
+Getting In and Out of GDB
+*************************
+
+This chapter discusses how to start GDB, and how to get out of it. The
+essentials are:
+ * type `gdb' to start GDB.
+
+ * type `quit' or `C-d' to exit.
+
+* Menu:
+
+* Invoking GDB:: How to start GDB
+* Quitting GDB:: How to quit GDB
+* Shell Commands:: How to use shell commands inside GDB
+* Logging output:: How to log GDB's output to a file
+
+
+File: gdb.info, Node: Invoking GDB, Next: Quitting GDB, Up: Invocation
+
+Invoking GDB
+============
+
+Invoke GDB by running the program `gdb'. Once started, GDB reads
+commands from the terminal until you tell it to exit.
+
+ You can also run `gdb' with a variety of arguments and options, to
+specify more of your debugging environment at the outset.
+
+ 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.
+
+ The most usual way to start GDB is with one argument, specifying an
+executable program:
+
+ gdb PROGRAM
+
+You can also start with both an executable program and a core file
+specified:
+
+ gdb PROGRAM CORE
+
+ You can, instead, specify a process ID as a second argument, if you
+want to debug a running process:
+
+ gdb PROGRAM 1234
+
+would attach GDB to process `1234' (unless you also have a file named
+`1234'; GDB does check for a core file first).
+
+ Taking advantage of the second command-line argument requires a
+fairly complete operating system; when you use GDB 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. GDB will warn you if it is
+unable to attach or to read core dumps.
+
+ You can optionally have `gdb' pass any arguments after the
+executable file to the inferior using `--args'. This option stops
+option processing.
+ gdb --args gcc -O2 -c foo.c
+ This will cause `gdb' to debug `gcc', and to set `gcc''s
+command-line arguments (*note Arguments::) to `-O2 -c foo.c'.
+
+ You can run `gdb' without printing the front material, which
+describes GDB's non-warranty, by specifying `-silent':
+
+ gdb -silent
+
+You can further control how GDB starts up by using command-line
+options. GDB itself can remind you of the options available.
+
+Type
+
+ gdb -help
+
+to display all available options and briefly describe their use (`gdb
+-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 `-x' option is
+used.
+
+* Menu:
+
+* File Options:: Choosing files
+* Mode Options:: Choosing modes
+
+
+File: gdb.info, Node: File Options, Next: Mode Options, Up: Invoking GDB
+
+Choosing files
+--------------
+
+When GDB 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 `-se' and `-c' (or
+`-p' options respectively. (GDB reads the first argument that does not
+have an associated option flag as equivalent to the `-se' option
+followed by that argument; and the second argument that does not have
+an associated option flag, if any, as equivalent to the `-c'/`-p'
+option followed by that argument.) If the second argument begins with
+a decimal digit, GDB will first attempt to attach to it as a process,
+and if that fails, attempt to open it as a corefile. If you have a
+corefile whose name begins with a digit, you can prevent GDB from
+treating it as a pid by prefixing it with `./', eg. `./12345'.
+
+ If GDB has not been configured to included core file support, such
+as for most embedded targets, then it will complain about a second
+argument and ignore it.
+
+ Many options have both long and short forms; both are shown in the
+following list. GDB 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 `--' rather than
+`-', though we illustrate the more usual convention.)
+
+`-symbols FILE'
+`-s FILE'
+ Read symbol table from file FILE.
+
+`-exec FILE'
+`-e FILE'
+ Use file FILE as the executable file to execute when appropriate,
+ and for examining pure data in conjunction with a core dump.
+
+`-se FILE'
+ Read symbol table from file FILE and use it as the executable file.
+
+`-core FILE'
+`-c FILE'
+ Use file FILE as a core dump to examine.
+
+`-c NUMBER'
+
+`-pid NUMBER'
+`-p NUMBER'
+ Connect to process ID NUMBER, as with the `attach' command. If
+ there is no such process, GDB will attempt to open a core file
+ named NUMBER.
+
+`-command FILE'
+`-x FILE'
+ Execute GDB commands from file FILE. *Note Command files: Command
+ Files.
+
+`-directory DIRECTORY'
+`-d DIRECTORY'
+ Add DIRECTORY to the path to search for source files.
+
+`-m'
+`-mapped'
+ _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
+ `mmap' system call, you can use this option to have GDB write the
+ symbols from your program into a reusable file in the current
+ directory. If the program you are debugging is called
+ `/tmp/fred', the mapped symbol file is `/tmp/fred.syms'. Future
+ GDB 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 `.syms' file is specific to the host machine where GDB is run.
+ It holds an exact image of the internal GDB symbol table. It
+ cannot be shared across multiple host platforms.
+
+`-r'
+`-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.
+
+
+ You typically combine the `-mapped' and `-readnow' options in order
+to build a `.syms' file that contains complete symbol information.
+(*Note Commands to specify files: Files, for information on `.syms'
+files.) A simple GDB invocation to do nothing but build a `.syms' file
+for future use is:
+
+ gdb -batch -nx -mapped -readnow programname
+
+
+File: gdb.info, Node: Mode Options, Prev: File Options, Up: Invoking GDB
+
+Choosing modes
+--------------
+
+You can run GDB in various alternative modes--for example, in batch
+mode or quiet mode.
+
+`-nx'
+`-n'
+ Do not execute commands found in any initialization files.
+ Normally, GDB executes the commands in these files after all the
+ command options and arguments have been processed. *Note Command
+ files: Command Files.
+
+`-quiet'
+`-silent'
+`-q'
+ "Quiet". Do not print the introductory and copyright messages.
+ These messages are also suppressed in batch mode.
+
+`-batch'
+ Run in batch mode. Exit with status `0' after processing all the
+ command files specified with `-x' (and all commands from
+ initialization files, if not inhibited with `-n'). 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
+
+ Program exited normally.
+
+ (which is ordinarily issued whenever a program running under GDB
+ control terminates) is not issued when running in batch mode.
+
+`-nowindows'
+`-nw'
+ "No windows". If GDB comes with a graphical user interface (GUI)
+ built in, then this option tells GDB to only use the command-line
+ interface. If no GUI is available, this option has no effect.
+
+`-windows'
+`-w'
+ If GDB includes a GUI, then this option requires it to be used if
+ possible.
+
+`-cd DIRECTORY'
+ Run GDB using DIRECTORY as its working directory, instead of the
+ current directory.
+
+`-fullname'
+`-f'
+ GNU 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 your program stops). This
+ recognizable format looks like two `\032' 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 `\032' characters as a signal to display the source code
+ for the frame.
+
+`-epoch'
+ The Epoch Emacs-GDB interface sets this option when it runs GDB as
+ a subprocess. It tells GDB to modify its print routines so as to
+ allow Epoch to display values of expressions in a separate window.
+
+`-annotate LEVEL'
+ This option sets the "annotation level" inside GDB. Its effect is
+ identical to using `set annotate LEVEL' (*note Annotations::).
+ The annotation LEVEL controls how much information GDB prints
+ together with its prompt, values of expressions, source lines, and
+ other types of output. Level 0 is the normal, level 1 is for use
+ when GDB is run as a subprocess of GNU Emacs, level 3 is the
+ maximum annotation suitable for programs that control GDB, and
+ level 2 has been deprecated.
+
+ The annotation mechanism has largely been superseeded by GDB/MI
+ (*note GDB/MI::).
+
+`-async'
+ Use the asynchronous event loop for the command-line interface.
+ GDB processes all events, such as user keyboard input, via a
+ special event loop. This allows GDB to accept and process user
+ commands in parallel with the debugged process being run(1), so
+ you don't need to wait for control to return to GDB before you
+ type the next command. (_Note:_ as of version 5.1, the target
+ side of the asynchronous operation is not yet in place, so
+ `-async' does not work fully yet.)
+
+ When the standard input is connected to a terminal device, GDB
+ uses the asynchronous event loop by default, unless disabled by the
+ `-noasync' option.
+
+`-noasync'
+ Disable the asynchronous event loop for the command-line interface.
+
+`--args'
+ Change interpretation of command line so that arguments following
+ the executable file are passed as command line arguments to the
+ inferior. This option stops option processing.
+
+`-baud BPS'
+`-b BPS'
+ Set the line speed (baud rate or bits per second) of any serial
+ interface used by GDB for remote debugging.
+
+`-tty DEVICE'
+`-t DEVICE'
+ Run using DEVICE for your program's standard input and output.
+
+`-tui'
+ Activate the "Text User Interface" when starting. The Text User
+ Interface manages several text windows on the terminal, showing
+ source, assembly, registers and GDB command outputs (*note GDB
+ Text User Interface: TUI.). Alternatively, the Text User
+ Interface can be enabled by invoking the program `gdbtui'. Do not
+ use this option if you run GDB from Emacs (*note Using GDB under
+ GNU Emacs: Emacs.).
+
+`-interpreter INTERP'
+ Use the interpreter INTERP for interface with the controlling
+ program or device. This option is meant to be set by programs
+ which communicate with GDB using it as a back end. *Note Command
+ Interpreters: Interpreters.
+
+ `--interpreter=mi' (or `--interpreter=mi2') causes GDB to use the
+ "GDB/MI interface" (*note The GDB/MI Interface: GDB/MI.) included
+ since GDBN version 6.0. The previous GDB/MI interface, included
+ in GDB version 5.3 and selected with `--interpreter=mi1', is
+ deprecated. Earlier GDB/MI interfaces are no longer supported.
+
+`-write'
+ Open the executable and core files for both reading and writing.
+ This is equivalent to the `set write on' command inside GDB (*note
+ Patching::).
+
+`-statistics'
+ This option causes GDB to print statistics about time and memory
+ usage after it completes each command and returns to the prompt.
+
+`-version'
+ This option causes GDB to print its version number and no-warranty
+ blurb, and exit.
+
+
+ ---------- Footnotes ----------
+
+ (1) GDB built with DJGPP tools for MS-DOS/MS-Windows supports this
+mode of operation, but the event loop is suspended when the debuggee
+runs.
+
+
+File: gdb.info, Node: Quitting GDB, Next: Shell Commands, Prev: Invoking GDB, Up: Invocation
+
+Quitting GDB
+============
+
+`quit [EXPRESSION]'
+`q'
+ To exit GDB, use the `quit' command (abbreviated `q'), or type an
+ end-of-file character (usually `C-d'). If you do not supply
+ EXPRESSION, GDB will terminate normally; otherwise it will
+ terminate using the result of EXPRESSION as the error code.
+
+ An interrupt (often `C-c') does not exit from GDB, but rather
+terminates the action of any GDB command that is in progress and
+returns to GDB command level. It is safe to type the interrupt
+character at any time because GDB does not allow it to take effect
+until a time when it is safe.
+
+ If you have been using GDB to control an attached process or device,
+you can release it with the `detach' command (*note Debugging an
+already-running process: Attach.).
+
+
+File: gdb.info, Node: Shell Commands, Next: Logging output, Prev: Quitting GDB, Up: Invocation
+
+Shell commands
+==============
+
+If you need to execute occasional shell commands during your debugging
+session, there is no need to leave or suspend GDB; you can just use the
+`shell' command.
+
+`shell COMMAND STRING'
+ Invoke a standard shell to execute COMMAND STRING. If it exists,
+ the environment variable `SHELL' determines which shell to run.
+ Otherwise GDB uses the default shell (`/bin/sh' on Unix systems,
+ `COMMAND.COM' on MS-DOS, etc.).
+
+ The utility `make' is often needed in development environments. You
+do not have to use the `shell' command for this purpose in GDB:
+
+`make MAKE-ARGS'
+ Execute the `make' program with the specified arguments. This is
+ equivalent to `shell make MAKE-ARGS'.
+
+
+File: gdb.info, Node: Logging output, Prev: Shell Commands, Up: Invocation
+
+Logging output
+==============
+
+You may want to save the output of GDB commands to a file. There are
+several commands to control GDB's logging.
+
+`set logging on'
+ Enable logging.
+
+`set logging off'
+ Disable logging.
+
+`set logging file FILE'
+ Change the name of the current logfile. The default logfile is
+ `gdb.txt'.
+
+`set logging overwrite [on|off]'
+ By default, GDB will append to the logfile. Set `overwrite' if
+ you want `set logging on' to overwrite the logfile instead.
+
+`set logging redirect [on|off]'
+ By default, GDB output will go to both the terminal and the
+ logfile. Set `redirect' if you want output to go only to the log
+ file.
+
+`show logging'
+ Show the current values of the logging settings.
+
+
+File: gdb.info, Node: Commands, Next: Running, Prev: Invocation, Up: Top
+
+GDB Commands
+************
+
+You can abbreviate a GDB command to the first few letters of the command
+name, if that abbreviation is unambiguous; and you can repeat certain
+GDB commands by typing just <RET>. You can also use the <TAB> key to
+get GDB 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 GDB
+* Completion:: Command completion
+* Help:: How to ask GDB for help
+
+
+File: gdb.info, Node: Command Syntax, Next: Completion, Up: Commands
+
+Command syntax
+==============
+
+A GDB 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 `step' accepts an argument which is the number of times to
+step, as in `step 5'. You can also use the `step' command with no
+arguments. Some commands do not allow any arguments.
+
+ GDB 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, `s' is specially defined as
+equivalent to `step' even though there are other commands whose names
+start with `s'. You can test abbreviations by using them as arguments
+to the `help' command.
+
+ A blank line as input to GDB (typing just <RET>) means to repeat the
+previous command. Certain commands (for example, `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 `list' and `x' commands, when you repeat them with <RET>,
+construct new arguments rather than repeating exactly as typed. This
+permits easy scanning of source or memory.
+
+ GDB can also use <RET> in another way: to partition lengthy output,
+in a way similar to the common utility `more' (*note Screen size:
+Screen Size.). Since it is easy to press one <RET> too many in this
+situation, GDB disables command repetition after any command that
+generates this sort of display.
+
+ Any text from a `#' to the end of the line is a comment; it does
+nothing. This is useful mainly in command files (*note Command files:
+Command Files.).
+
+ The `C-o' binding is useful for repeating a complex sequence of
+commands. This command accepts the current line, like `RET', and then
+fetches the next line relative to the current line from the history for
+editing.
+
+
+File: gdb.info, Node: Completion, Next: Help, Prev: Command Syntax, Up: Commands
+
+Command completion
+==================
+
+GDB 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 GDB
+commands, GDB subcommands, and the names of symbols in your program.
+
+ Press the <TAB> key whenever you want GDB to fill out the rest of a
+word. If there is only one possibility, GDB fills in the word, and
+waits for you to finish the command (or press <RET> to enter it). For
+example, if you type
+
+ (gdb) info bre <TAB>
+
+GDB fills in the rest of the word `breakpoints', since that is the only
+`info' subcommand beginning with `bre':
+
+ (gdb) info breakpoints
+
+You can either press <RET> at this point, to run the `info breakpoints'
+command, or backspace and enter something else, if `breakpoints' does
+not look like the command you expected. (If you were sure you wanted
+`info breakpoints' in the first place, you might as well just type
+<RET> immediately after `info bre', to exploit command abbreviations
+rather than command completion).
+
+ If there is more than one possibility for the next word when you
+press <TAB>, GDB sounds a bell. You can either supply more characters
+and try again, or just press <TAB> a second time; GDB displays all the
+possible completions for that word. For example, you might want to set
+a breakpoint on a subroutine whose name begins with `make_', but when
+you type `b make_<TAB>' GDB just sounds the bell. Typing <TAB> again
+displays all the function names in your program that begin with those
+characters, for example:
+
+ (gdb) b make_ <TAB>
+GDB sounds bell; press <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
+ (gdb) b make_
+
+After displaying the available possibilities, GDB copies your partial
+input (`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 `M-?' rather than pressing <TAB> twice. `M-?' means
+`<META> ?'. You can type this either by holding down a key designated
+as the <META> shift on your keyboard (if there is one) while typing
+`?', or as <ESC> followed by `?'.
+
+ Sometimes the string you need, while logically a "word", may contain
+parentheses or other characters that GDB normally excludes from its
+notion of a word. To permit word completion to work in this situation,
+you may enclose words in `'' (single quote marks) in GDB commands.
+
+ 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 `name' that
+takes an `int' parameter, `name(int)', or the version that takes a
+`float' parameter, `name(float)'. To use the word-completion
+facilities in this situation, type a single quote `'' at the beginning
+of the function name. This alerts GDB that it may need to consider
+more information than usual when you press <TAB> or `M-?' to request
+word completion:
+
+ (gdb) b 'bubble( M-?
+ bubble(double,double) bubble(int,int)
+ (gdb) b 'bubble(
+
+ In some cases, GDB can tell that completing a name requires using
+quotes. When this happens, GDB inserts the quote for you (while
+completing as much as it can) if you do not type the quote in the first
+place:
+
+ (gdb) b bub <TAB>
+GDB alters your input line to the following, and rings a bell:
+ (gdb) b 'bubble(
+
+In general, GDB 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.
+
+ For more information about overloaded functions, see *Note C++
+expressions: C plus plus expressions. You can use the command `set
+overload-resolution off' to disable overload resolution; see *Note GDB
+features for C++: Debugging C plus plus.
+
+
+File: gdb.info, Node: Help, Prev: Completion, Up: Commands
+
+Getting help
+============
+
+You can always ask GDB itself for information on its commands, using
+the command `help'.
+
+`help'
+`h'
+ You can use `help' (abbreviated `h') with no arguments to display
+ a short list of named classes of commands:
+
+ (gdb) help
+ List of classes of commands:
+
+ aliases -- Aliases of other commands
+ breakpoints -- Making program stop at certain points
+ data -- Examining data
+ files -- Specifying and examining files
+ internals -- Maintenance commands
+ obscure -- Obscure features
+ running -- Running the program
+ stack -- Examining the stack
+ status -- Status inquiries
+ support -- Support facilities
+ tracepoints -- Tracing of program execution without
+
+ stopping the program
+ user-defined -- User-defined commands
+
+ 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.
+ (gdb)
+
+`help 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 `status':
+
+ (gdb) help status
+ Status inquiries.
+
+ List of commands:
+
+ info -- Generic command for showing things
+ about the program being debugged
+ show -- Generic command for showing things
+ about the debugger
+
+ Type "help" followed by command name for full
+ documentation.
+ Command name abbreviations are allowed if unambiguous.
+ (gdb)
+
+`help COMMAND'
+ With a command name as `help' argument, GDB displays a short
+ paragraph on how to use that command.
+
+`apropos ARGS'
+ The `apropos ARGS' command searches through all of the GDB
+ commands, and their documentation, for the regular expression
+ specified in ARGS. It prints out all matches found. For example:
+
+ apropos reload
+
+ results in:
+
+ set symbol-reloading -- Set dynamic symbol table reloading
+ multiple times in one run
+ show symbol-reloading -- Show dynamic symbol table reloading
+ multiple times in one run
+
+`complete ARGS'
+ The `complete ARGS' command lists all the possible completions for
+ the beginning of a command. Use ARGS to specify the beginning of
+ the command you want completed. For example:
+
+ complete i
+
+ results in:
+
+ if
+ ignore
+ info
+ inspect
+
+ This is intended for use by GNU Emacs.
+
+ In addition to `help', you can use the GDB commands `info' and
+`show' to inquire about the state of your program, or the state of GDB
+itself. Each command supports many topics of inquiry; this manual
+introduces each of them in the appropriate context. The listings under
+`info' and under `show' in the Index point to all the sub-commands.
+*Note Index::.
+
+`info'
+ This command (abbreviated `i') is for describing the state of your
+ program. For example, you can list the arguments given to your
+ program with `info args', list the registers currently in use with
+ `info registers', or list the breakpoints you have set with `info
+ breakpoints'. You can get a complete list of the `info'
+ sub-commands with `help info'.
+
+`set'
+ You can assign the result of an expression to an environment
+ variable with `set'. For example, you can set the GDB prompt to a
+ $-sign with `set prompt $'.
+
+`show'
+ In contrast to `info', `show' is for describing the state of GDB
+ itself. You can change most of the things you can `show', by
+ using the related command `set'; for example, you can control what
+ number system is used for displays with `set radix', or simply
+ inquire which is currently in use with `show radix'.
+
+ To display all the settable parameters and their current values,
+ you can use `show' with no arguments; you may also use `info set'.
+ Both commands produce the same display.
+
+ Here are three miscellaneous `show' subcommands, all of which are
+exceptional in lacking corresponding `set' commands:
+
+`show version'
+ Show what version of GDB is running. You should include this
+ information in GDB bug-reports. If multiple versions of GDB are
+ in use at your site, you may need to determine which version of
+ GDB you are running; as GDB evolves, new commands are introduced,
+ and old ones may wither away. Also, many system vendors ship
+ variant versions of GDB, and there are variant versions of GDB in
+ GNU/Linux distributions as well. The version number is the same
+ as the one announced when you start GDB.
+
+`show copying'
+ Display information about permission for copying GDB.
+
+`show warranty'
+ Display the GNU "NO WARRANTY" statement, or a warranty, if your
+ version of GDB comes with one.
+
+
+
+File: gdb.info, Node: Running, Next: Stopping, Prev: Commands, Up: Top
+
+Running Programs Under GDB
+**************************
+
+When you run a program under GDB, you must first generate debugging
+information when you compile it.
+
+ You may start GDB with its arguments, if any, in an environment of
+your choice. If you are doing native debugging, you may redirect your
+program's input and output, debug an already running process, or kill a
+child process.
+
+* Menu:
+
+* Compilation:: Compiling for debugging
+* Starting:: Starting your program
+* 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
+
+* Threads:: Debugging programs with multiple threads
+* Processes:: Debugging programs with multiple processes
+
+
+File: gdb.info, Node: Compilation, Next: Starting, Up: Running
+
+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 `-g' option when you
+run the compiler.
+
+ Most compilers do not include information about preprocessor macros
+in the debugging information if you specify the `-g' flag alone,
+because this information is rather large. Version 3.1 of GCC, the GNU
+C compiler, provides macro information if you specify the options
+`-gdwarf-2' and `-g3'; the former option requests debugging information
+in the Dwarf 2 format, and the latter requests "extra information". In
+the future, we hope to find more compact ways to represent macro
+information, so that it can be included with `-g' alone.
+
+ Many C compilers are unable to handle the `-g' and `-O' options
+together. Using those compilers, you cannot generate optimized
+executables containing debugging information.
+
+ GCC, the GNU C compiler, supports `-g' with or without `-O', making
+it possible to debug optimized code. We recommend that you _always_
+use `-g' whenever you compile a program. You may think your program is
+correct, but there is no sense in pushing your luck.
+
+ When you debug a program compiled with `-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, GDB never sees that variable--because the
+compiler optimizes it out of existence.
+
+ Some things do not work as well with `-g -O' as with just `-g',
+particularly on machines with instruction scheduling. If in doubt,
+recompile with `-g' alone, and if this fixes the problem, please report
+it to us as a bug (including a test case!).
+
+ Older versions of the GNU C compiler permitted a variant option
+`-gg' for debugging information. GDB no longer supports this format;
+if your GNU C compiler has this option, do not use it.
+
+
+File: gdb.info, Node: Starting, Next: Arguments, Prev: Compilation, Up: Running
+
+Starting your program
+=====================
+
+`run'
+`r'
+ Use the `run' command to start your program under GDB. You must
+ first specify the program name (except on VxWorks) with an
+ argument to GDB (*note Getting In and Out of GDB: Invocation.), or
+ by using the `file' or `exec-file' command (*note Commands to
+ specify files: Files.).
+
+
+ If you are running your program in an execution environment that
+supports processes, `run' creates an inferior process and makes that
+process run your program. (In environments without processes, `run'
+jumps to the start of your program.)
+
+ The execution of a program is affected by certain information it
+receives from its superior. GDB provides ways to specify this
+information, which you must do _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:
+
+The _arguments._
+ Specify the arguments to give your program as the arguments of the
+ `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 `SHELL' environment variable. *Note
+ Your program's arguments: Arguments.
+
+The _environment._
+ Your program normally inherits its environment from GDB, but you
+ can use the GDB commands `set environment' and `unset environment'
+ to change parts of the environment that affect your program.
+ *Note Your program's environment: Environment.
+
+The _working directory._
+ Your program inherits its working directory from GDB. You can set
+ the GDB working directory with the `cd' command in GDB. *Note
+ Your program's working directory: Working Directory.
+
+The _standard input and output._
+ Your program normally uses the same device for standard input and
+ standard output as GDB is using. You can redirect input and output
+ in the `run' command line, or you can use the `tty' command to set
+ a different device for your program. *Note Your program's input
+ and output: Input/Output.
+
+ _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, GDB is likely to wind up
+ debugging the wrong program.
+
+ When you issue the `run' command, your program begins to execute
+immediately. *Note Stopping and continuing: Stopping, 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 `print' or
+`call' commands. *Note Examining Data: Data.
+
+ If the modification time of your symbol file has changed since the
+last time GDB read its symbols, GDB discards its symbol table, and
+reads it again. When it does this, GDB tries to retain your current
+breakpoints.
+
+
+File: gdb.info, Node: Arguments, Next: Environment, Prev: Starting, Up: Running
+
+Your program's arguments
+========================
+
+The arguments to your program can be specified by the arguments of the
+`run' command. They are passed to a shell, which expands wildcard
+characters and performs redirection of I/O, and thence to your program.
+Your `SHELL' environment variable (if it exists) specifies what shell
+GDB uses. If you do not define `SHELL', GDB uses the default shell
+(`/bin/sh' on Unix).
+
+ On non-Unix systems, the program is usually invoked directly by GDB,
+which emulates I/O redirection via the appropriate system calls, and
+the wildcard characters are expanded by the startup code of the
+program, not by the shell.
+
+ `run' with no arguments uses the same arguments used by the previous
+`run', or those set by the `set args' command.
+
+`set args'
+ Specify the arguments to be used the next time your program is
+ run. If `set args' has no arguments, `run' executes your program
+ with no arguments. Once you have run your program with arguments,
+ using `set args' before the next `run' is the only way to run it
+ again without arguments.
+
+`show args'
+ Show the arguments to give your program when it is started.
+
+
+File: gdb.info, Node: Environment, Next: Working Directory, Prev: Arguments, Up: Running
+
+Your program's environment
+==========================
+
+The "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 GDB over again.
+
+`path DIRECTORY'
+ Add DIRECTORY to the front of the `PATH' environment variable (the
+ search path for executables) that will be passed to your program.
+ The value of `PATH' used by GDB does not change. You may specify
+ several directory names, separated by whitespace or by a
+ system-dependent separator character (`:' on Unix, `;' on MS-DOS
+ and MS-Windows). If DIRECTORY is already in the path, it is moved
+ to the front, so it is searched sooner.
+
+ You can use the string `$cwd' to refer to whatever is the current
+ working directory at the time GDB searches the path. If you use
+ `.' instead, it refers to the directory where you executed the
+ `path' command. GDB replaces `.' in the DIRECTORY argument (with
+ the current path) before adding DIRECTORY to the search path.
+
+`show paths'
+ Display the list of search paths for executables (the `PATH'
+ environment variable).
+
+`show environment [VARNAME]'
+ Print the value of environment variable VARNAME to be given to
+ your program when it starts. If you do not supply VARNAME, print
+ the names and values of all environment variables to be given to
+ your program. You can abbreviate `environment' as `env'.
+
+`set environment VARNAME [=VALUE]'
+ Set environment variable VARNAME to VALUE. The value changes for
+ your program only, not for GDB itself. VALUE may be any string;
+ the values of environment variables are just strings, and any
+ interpretation is supplied by your program itself. The VALUE
+ parameter is optional; if it is eliminated, the variable is set to
+ a null value.
+
+ For example, this command:
+
+ set env USER = foo
+
+ tells the debugged program, when subsequently run, that its user
+ is named `foo'. (The spaces around `=' are used for clarity here;
+ they are not actually required.)
+
+`unset environment VARNAME'
+ Remove variable VARNAME from the environment to be passed to your
+ program. This is different from `set env VARNAME ='; `unset
+ environment' removes the variable from the environment, rather
+ than assigning it an empty value.
+
+ _Warning:_ On Unix systems, GDB runs your program using the shell
+indicated by your `SHELL' environment variable if it exists (or
+`/bin/sh' if not). If your `SHELL' variable names a shell that runs an
+initialization file--such as `.cshrc' for C-shell, or `.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 `.login' or `.profile'.
+
+
+File: gdb.info, Node: Working Directory, Next: Input/Output, Prev: Environment, Up: Running
+
+Your program's working directory
+================================
+
+Each time you start your program with `run', it inherits its working
+directory from the current working directory of GDB. The GDB working
+directory is initially whatever it inherited from its parent process
+(typically the shell), but you can specify a new working directory in
+GDB with the `cd' command.
+
+ The GDB working directory also serves as a default for the commands
+that specify files for GDB to operate on. *Note Commands to specify
+files: Files.
+
+`cd DIRECTORY'
+ Set the GDB working directory to DIRECTORY.
+
+`pwd'
+ Print the GDB working directory.
+
+
+File: gdb.info, Node: Input/Output, Next: Attach, Prev: Working Directory, Up: Running
+
+Your program's input and output
+===============================
+
+By default, the program you run under GDB does input and output to the
+same terminal that GDB uses. GDB 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.
+
+`info terminal'
+ Displays information recorded by GDB about the terminal modes your
+ program is using.
+
+ You can redirect your program's input and/or output using shell
+redirection with the `run' command. For example,
+
+ run > outfile
+
+starts your program, diverting its output to the file `outfile'.
+
+ Another way to specify where your program should do input and output
+is with the `tty' command. This command accepts a file name as
+argument, and causes this file to be the default for future `run'
+commands. It also resets the controlling terminal for the child
+process, for future `run' commands. For example,
+
+ tty /dev/ttyb
+
+directs that processes started with subsequent `run' commands default
+to do input and output on the terminal `/dev/ttyb' and have that as
+their controlling terminal.
+
+ An explicit redirection in `run' overrides the `tty' command's
+effect on the input/output device, but not its effect on the controlling
+terminal.
+
+ When you use the `tty' command or redirect input in the `run'
+command, only the input _for your program_ is affected. The input for
+GDB still comes from your terminal.
+
+
+File: gdb.info, Node: Attach, Next: Kill Process, Prev: Input/Output, Up: Running
+
+Debugging an already-running process
+====================================
+
+`attach PROCESS-ID'
+ This command attaches to a running process--one that was started
+ outside GDB. (`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 `ps' utility, or with
+ the `jobs -l' shell command.
+
+ `attach' does not repeat if you press <RET> a second time after
+ executing the command.
+
+ To use `attach', your program must be running in an environment
+which supports processes; for example, `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 you use `attach', the debugger finds the program running in the
+process first by looking in the current working directory, then (if the
+program is not found) by using the source file search path (*note
+Specifying source directories: Source Path.). You can also use the
+`file' command to load the program. *Note Commands to Specify Files:
+Files.
+
+ The first thing GDB does after arranging to debug the specified
+process is to stop it. You can examine and modify an attached process
+with all the GDB commands that are ordinarily available when you start
+processes with `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 `continue' command after attaching
+GDB to the process.
+
+`detach'
+ When you have finished debugging the attached process, you can use
+ the `detach' command to release it from GDB control. Detaching
+ the process continues its execution. After the `detach' command,
+ that process and GDB become completely independent once more, and
+ you are ready to `attach' another process or start one with `run'.
+ `detach' does not repeat if you press <RET> again after executing
+ the command.
+
+ If you exit GDB or use the `run' command while you have an attached
+process, you kill that process. By default, GDB 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 `set confirm' command (*note Optional
+warnings and messages: Messages/Warnings.).
+
+
+File: gdb.info, Node: Kill Process, Next: Threads, Prev: Attach, Up: Running
+
+Killing the child process
+=========================
+
+`kill'
+ Kill the child process in which your program is running under GDB.
+
+ This command is useful if you wish to debug a core dump instead of a
+running process. GDB ignores any core dump file while your program is
+running.
+
+ On some operating systems, a program cannot be executed outside GDB
+while you have breakpoints set on it inside GDB. You can use the
+`kill' command in this situation to permit running your program outside
+the debugger.
+
+ The `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 `run', GDB notices that the file has changed, and reads
+the symbol table again (while trying to preserve your current
+breakpoint settings).
+
+
+File: gdb.info, Node: Threads, Next: Processes, Prev: Kill Process, Up: Running
+
+Debugging programs with multiple threads
+========================================
+
+In some operating systems, such as HP-UX and Solaris, a single program
+may have more than one "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.
+
+ GDB provides these facilities for debugging multi-thread programs:
+
+ * automatic notification of new threads
+
+ * `thread THREADNO', a command to switch among threads
+
+ * `info threads', a command to inquire about existing threads
+
+ * `thread apply [THREADNO] [ALL] ARGS', a command to apply a command
+ to a list of threads
+
+ * thread-specific breakpoints
+
+ _Warning:_ These facilities are not yet available on every GDB
+ configuration where the operating system supports threads. If
+ your GDB does not support threads, these commands have no effect.
+ For example, a system without thread support shows no output from
+ `info threads', and always rejects the `thread' command, like this:
+
+ (gdb) info threads
+ (gdb) thread 1
+ Thread ID 1 not known. Use the "info threads" command to
+ see the IDs of currently known threads.
+
+ The GDB thread debugging facility allows you to observe all threads
+while your program runs--but whenever GDB takes control, one thread in
+particular is always the focus of debugging. This thread is called the
+"current thread". Debugging commands show program information from the
+perspective of the current thread.
+
+ Whenever GDB detects a new thread in your program, it displays the
+target system's identification for the thread with a message in the
+form `[New SYSTAG]'. SYSTAG is a thread identifier whose form varies
+depending on the particular system. For example, on LynxOS, you might
+see
+
+ [New process 35 thread 27]
+
+when GDB notices a new thread. In contrast, on an SGI system, the
+SYSTAG is simply something like `process 368', with no further
+qualifier.
+
+ For debugging purposes, GDB associates its own thread number--always
+a single integer--with each thread in your program.
+
+`info threads'
+ Display a summary of all threads currently in your program. GDB
+ displays for each thread (in this order):
+
+ 1. the thread number assigned by GDB
+
+ 2. the target system's thread identifier (SYSTAG)
+
+ 3. the current stack frame summary for that thread
+
+ An asterisk `*' to the left of the GDB thread number indicates the
+ current thread.
+
+ For example,
+
+ (gdb) 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
+
+ On HP-UX systems:
+
+ For debugging purposes, GDB associates its own thread number--a
+small integer assigned in thread-creation order--with each thread in
+your program.
+
+ Whenever GDB detects a new thread in your program, it displays both
+GDB's thread number and the target system's identification for the
+thread with a message in the form `[New SYSTAG]'. SYSTAG is a thread
+identifier whose form varies depending on the particular system. For
+example, on HP-UX, you see
+
+ [New thread 2 (system thread 26594)]
+
+when GDB notices a new thread.
+
+`info threads'
+ Display a summary of all threads currently in your program. GDB
+ displays for each thread (in this order):
+
+ 1. the thread number assigned by GDB
+
+ 2. the target system's thread identifier (SYSTAG)
+
+ 3. the current stack frame summary for that thread
+
+ An asterisk `*' to the left of the GDB thread number indicates the
+ current thread.
+
+ For example,
+
+ (gdb) info threads
+ * 3 system thread 26607 worker (wptr=0x7b09c318 "@") \
+
+ at quicksort.c:137
+ 2 system thread 26606 0x7b0030d8 in __ksleep () \
+
+ from /usr/lib/libc.2
+ 1 system thread 27905 0x7b003498 in _brk () \
+
+ from /usr/lib/libc.2
+
+`thread THREADNO'
+ Make thread number THREADNO the current thread. The command
+ argument THREADNO is the internal GDB thread number, as shown in
+ the first field of the `info threads' display. GDB responds by
+ displaying the system identifier of the thread you selected, and
+ its current stack frame summary:
+
+ (gdb) thread 2
+ [Switching to process 35 thread 23]
+ 0x34e5 in sigpause ()
+
+ As with the `[New ...]' message, the form of the text after
+ `Switching to' depends on your system's conventions for identifying
+ threads.
+
+`thread apply [THREADNO] [ALL] ARGS'
+ The `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 THREADNO. THREADNO is the
+ internal GDB thread number, as shown in the first field of the
+ `info threads' display. To apply a command to all threads, use
+ `thread apply all' ARGS.
+
+ Whenever GDB stops your program, due to a breakpoint or a signal, it
+automatically selects the thread where that breakpoint or signal
+happened. GDB alerts you to the context switch with a message of the
+form `[Switching to SYSTAG]' to identify the thread.
+
+ *Note Stopping and starting multi-thread programs: Thread Stops, for
+more information about how GDB behaves when you stop and start programs
+with multiple threads.
+
+ *Note Setting watchpoints: Set Watchpoints, for information about
+watchpoints in programs with multiple threads.
+
+
+File: gdb.info, Node: Processes, Prev: Threads, Up: Running
+
+Debugging programs with multiple processes
+==========================================
+
+On most systems, GDB has no special support for debugging programs
+which create additional processes using the `fork' function. When a
+program forks, GDB 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 `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 `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 GDB on the
+child. While the child is sleeping, use the `ps' program to get its
+process ID. Then tell GDB (a new invocation of GDB if you are also
+debugging the parent process) to attach to the child process (*note
+Attach::). From that point on you can debug the child process just
+like any other process which you attached to.
+
+ On some systems, GDB provides support for debugging programs that
+create additional processes using the `fork' or `vfork' functions.
+Currently, the only platforms with this feature are HP-UX (11.x and
+later only?) and GNU/Linux (kernel version 2.5.60 and later).
+
+ By default, when a program forks, GDB will continue to debug the
+parent process and the child process will run unimpeded.
+
+ If you want to follow the child process instead of the parent
+process, use the command `set follow-fork-mode'.
+
+`set follow-fork-mode MODE'
+ Set the debugger response to a program call of `fork' or `vfork'.
+ A call to `fork' or `vfork' creates a new process. The MODE can
+ be:
+
+ `parent'
+ The original process is debugged after a fork. The child
+ process runs unimpeded. This is the default.
+
+ `child'
+ The new process is debugged after a fork. The parent process
+ runs unimpeded.
+
+
+`show follow-fork-mode'
+ Display the current debugger response to a `fork' or `vfork' call.
+
+ If you ask to debug a child process and a `vfork' is followed by an
+`exec', GDB executes the new target up to the first breakpoint in the
+new target. If you have a breakpoint set on `main' in your original
+program, the breakpoint will also be set on the child process's `main'.
+
+ When a child process is spawned by `vfork', you cannot debug the
+child or parent until an `exec' call completes.
+
+ If you issue a `run' command to GDB after an `exec' call executes,
+the new target restarts. To restart the parent process, use the `file'
+command with the parent executable name as its argument.
+
+ You can use the `catch' command to make GDB stop whenever a `fork',
+`vfork', or `exec' call is made. *Note Setting catchpoints: Set
+Catchpoints.
+
+
+File: gdb.info, Node: Stopping, Next: Stack, Prev: Running, Up: Top
+
+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 GDB, your program may stop for any of several reasons, such
+as a signal, a breakpoint, or reaching a new line after a GDB command
+such as `step'. You may then examine and change variables, set new
+breakpoints or remove old ones, and then continue execution. Usually,
+the messages shown by GDB provide ample explanation of the status of
+your program--but you can also explicitly request this information at
+any time.
+
+`info program'
+ Display information about the status of your program: whether it is
+ running or not, what process it is, and why it stopped.
+
+* Menu:
+
+* Breakpoints:: Breakpoints, watchpoints, and catchpoints
+* Continuing and Stepping:: Resuming execution
+* Signals:: Signals
+* Thread Stops:: Stopping and starting multi-thread programs
+
+
+File: gdb.info, Node: Breakpoints, Next: Continuing and Stepping, Up: Stopping
+
+Breakpoints, watchpoints, and catchpoints
+=========================================
+
+A "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 `break' command and its variants (*note Setting
+breakpoints: Set Breaks.), to specify the place where your program
+should stop by line number, function name or exact address in the
+program.
+
+ In HP-UX, SunOS 4.x, SVR4, and Alpha OSF/1 configurations, you can
+set breakpoints in shared libraries before the executable is run.
+There is a minor limitation on HP-UX systems: you must wait until the
+executable is run in order to set breakpoints in shared library
+routines that are not called directly by the program (for example,
+routines that are arguments in a `pthread_create' call).
+
+ A "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 (*note Setting watchpoints: Set 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 GDB stops at a breakpoint. *Note Automatic
+display: Auto Display.
+
+ A "catchpoint" is another special breakpoint that stops your program
+when a certain kind of event occurs, such as the throwing of a C++
+exception or the loading of a library. As with watchpoints, you use a
+different command to set a catchpoint (*note Setting catchpoints: Set
+Catchpoints.), but aside from that, you can manage a catchpoint like any
+other breakpoint. (To stop when your program receives a signal, use the
+`handle' command; see *Note Signals: Signals.)
+
+ GDB assigns a number to each breakpoint, watchpoint, or catchpoint
+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 "enabled" or "disabled"; if
+disabled, it has no effect on your program until you enable it again.
+
+ Some GDB commands accept a range of breakpoints on which to operate.
+A breakpoint range is either a single breakpoint number, like `5', or
+two such numbers, in increasing order, separated by a hyphen, like
+`5-7'. When a breakpoint range is given to a command, all breakpoint
+in that range are operated on.
+
+* Menu:
+
+* Set Breaks:: Setting breakpoints
+* Set Watchpoints:: Setting watchpoints
+* Set Catchpoints:: Setting catchpoints
+* Delete Breaks:: Deleting breakpoints
+* Disabling:: Disabling breakpoints
+* Conditions:: Break conditions
+* Break Commands:: Breakpoint command lists
+* Breakpoint Menus:: Breakpoint menus
+* Error in Breakpoints:: ``Cannot insert breakpoints''
+* Breakpoint related warnings:: ``Breakpoint address adjusted...''
+
+
+File: gdb.info, Node: Set Breaks, Next: Set Watchpoints, Up: Breakpoints
+
+Setting breakpoints
+-------------------
+
+Breakpoints are set with the `break' command (abbreviated `b'). The
+debugger convenience variable `$bpnum' records the number of the
+breakpoint you've set most recently; see *Note Convenience variables:
+Convenience Vars, for a discussion of what you can do with convenience
+variables.
+
+ You have several ways to say where the breakpoint should go.
+
+`break FUNCTION'
+ Set a breakpoint at entry to function FUNCTION. When using source
+ languages that permit overloading of symbols, such as C++,
+ FUNCTION may refer to more than one possible place to break.
+ *Note Breakpoint menus: Breakpoint Menus, for a discussion of that
+ situation.
+
+`break +OFFSET'
+`break -OFFSET'
+ Set a breakpoint some number of lines forward or back from the
+ position at which execution stopped in the currently selected
+ "stack frame". (*Note Frames: Frames, for a description of stack
+ frames.)
+
+`break LINENUM'
+ Set a breakpoint at line LINENUM in the current source file. The
+ current source file is the last file whose source text was printed.
+ The breakpoint will stop your program just before it executes any
+ of the code on that line.
+
+`break FILENAME:LINENUM'
+ Set a breakpoint at line LINENUM in source file FILENAME.
+
+`break FILENAME:FUNCTION'
+ Set a breakpoint at entry to function FUNCTION found in file
+ FILENAME. Specifying a file name as well as a function name is
+ superfluous except when multiple files contain similarly named
+ functions.
+
+`break *ADDRESS'
+ Set a breakpoint at address ADDRESS. You can use this to set
+ breakpoints in parts of your program which do not have debugging
+ information or source files.
+
+`break'
+ When called without any arguments, `break' sets a breakpoint at
+ the next instruction to be executed in the selected stack frame
+ (*note Examining the Stack: 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 `finish'
+ command in the frame inside the selected frame--except that
+ `finish' does not leave an active breakpoint. If you use `break'
+ without an argument in the innermost frame, GDB stops the next
+ time it reaches the current location; this may be useful inside
+ loops.
+
+ GDB 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.
+
+`break ... if COND'
+ Set a breakpoint with condition COND; evaluate the expression COND
+ each time the breakpoint is reached, and stop only if the value is
+ nonzero--that is, if COND evaluates as true. `...' stands for one
+ of the possible arguments described above (or no argument)
+ specifying where to break. *Note Break conditions: Conditions,
+ for more information on breakpoint conditions.
+
+`tbreak ARGS'
+ Set a breakpoint enabled only for one stop. ARGS are the same as
+ for the `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. *Note Disabling breakpoints:
+ Disabling.
+
+`hbreak ARGS'
+ Set a hardware-assisted breakpoint. ARGS are the same as for the
+ `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 and some x86-based
+ targets. These targets will generate traps when a program
+ accesses some data or instruction address that is assigned to the
+ debug registers. However the hardware breakpoint registers can
+ take a limited number of breakpoints. For example, on the DSU,
+ only two data breakpoints can be set at a time, and GDB will
+ reject this command if more than two are used. Delete or disable
+ unused hardware breakpoints before setting new ones (*note
+ Disabling: Disabling.). *Note Break conditions: Conditions.
+ *Note set remote hardware-breakpoint-limit::.
+
+`thbreak ARGS'
+ Set a hardware-assisted breakpoint enabled only for one stop. ARGS
+ are the same as for the `hbreak' command and the breakpoint is set
+ in the same way. However, like the `tbreak' command, the
+ breakpoint is automatically deleted after the first time your
+ program stops there. Also, like the `hbreak' command, the
+ breakpoint requires hardware support and some target hardware may
+ not have this support. *Note Disabling breakpoints: Disabling.
+ See also *Note Break conditions: Conditions.
+
+`rbreak REGEX'
+ Set breakpoints on all functions matching the regular expression
+ 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 `break' command. You can delete them, disable them,
+ or make them conditional the same way as any other breakpoint.
+
+ The syntax of the regular expression is the standard one used with
+ tools like `grep'. Note that this is different from the syntax
+ used by shells, so for instance `foo*' matches all functions that
+ include an `fo' followed by zero or more `o's. There is an
+ implicit `.*' leading and trailing the regular expression you
+ supply, so to match only functions that begin with `foo', use
+ `^foo'.
+
+ When debugging C++ programs, `rbreak' is useful for setting
+ breakpoints on overloaded functions that are not members of any
+ special classes.
+
+`info breakpoints [N]'
+`info break [N]'
+`info watchpoints [N]'
+ Print a table of all breakpoints, watchpoints, and catchpoints set
+ and not deleted, with the following columns for each breakpoint:
+
+ _Breakpoint Numbers_
+
+ _Type_
+ Breakpoint, watchpoint, or catchpoint.
+
+ _Disposition_
+ Whether the breakpoint is marked to be disabled or deleted
+ when hit.
+
+ _Enabled or Disabled_
+ Enabled breakpoints are marked with `y'. `n' marks
+ breakpoints that are not enabled.
+
+ _Address_
+ Where the breakpoint is in your program, as a memory address.
+ If the breakpoint is pending (see below for details) on a
+ future load of a shared library, the address will be listed
+ as `<PENDING>'.
+
+ _What_
+ Where the breakpoint is in the source for your program, as a
+ file and line number. For a pending breakpoint, the original
+ string passed to the breakpoint command will be listed as it
+ cannot be resolved until the appropriate shared library is
+ loaded in the future.
+
+ If a breakpoint is conditional, `info break' shows the condition on
+ the line following the affected breakpoint; breakpoint commands,
+ if any, are listed after that. A pending breakpoint is allowed to
+ have a condition specified for it. The condition is not parsed
+ for validity until a shared library is loaded that allows the
+ pending breakpoint to resolve to a valid location.
+
+ `info break' with a breakpoint number N as argument lists only
+ that breakpoint. The convenience variable `$_' and the default
+ examining-address for the `x' command are set to the address of
+ the last breakpoint listed (*note Examining memory: Memory.).
+
+ `info break' displays a count of the number of times the breakpoint
+ has been hit. This is especially useful in conjunction with the
+ `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.
+
+ GDB 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 (*note Break
+conditions: Conditions.).
+
+ If a specified breakpoint location cannot be found, it may be due to
+the fact that the location is in a shared library that is yet to be
+loaded. In such a case, you may want GDB to create a special
+breakpoint (known as a "pending breakpoint") that attempts to resolve
+itself in the future when an appropriate shared library gets loaded.
+
+ Pending breakpoints are useful to set at the start of your GDB
+session for locations that you know will be dynamically loaded later by
+the program being debugged. When shared libraries are loaded, a check
+is made to see if the load resolves any pending breakpoint locations.
+If a pending breakpoint location gets resolved, a regular breakpoint is
+created and the original pending breakpoint is removed.
+
+ GDB provides some additional commands for controlling pending
+breakpoint support:
+
+`set breakpoint pending auto'
+ This is the default behavior. When GDB cannot find the breakpoint
+ location, it queries you whether a pending breakpoint should be
+ created.
+
+`set breakpoint pending on'
+ This indicates that an unrecognized breakpoint location should
+ automatically result in a pending breakpoint being created.
+
+`set breakpoint pending off'
+ This indicates that pending breakpoints are not to be created. Any
+ unrecognized breakpoint location results in an error. This
+ setting does not affect any pending breakpoints previously created.
+
+`show breakpoint pending'
+ Show the current behavior setting for creating pending breakpoints.
+
+ Normal breakpoint operations apply to pending breakpoints as well.
+You may specify a condition for a pending breakpoint and/or commands to
+run when the breakpoint is reached. You can also enable or disable the
+pending breakpoint. When you specify a condition for a pending
+breakpoint, the parsing of the condition will be deferred until the
+point where the pending breakpoint location is resolved. Disabling a
+pending breakpoint tells GDB to not attempt to resolve the breakpoint
+on any subsequent shared library load. When a pending breakpoint is
+re-enabled, GDB checks to see if the location is already resolved.
+This is done because any number of shared library loads could have
+occurred since the time the breakpoint was disabled and one or more of
+these loads could resolve the location.
+
+ GDB itself sometimes sets breakpoints in your program for special
+purposes, such as proper handling of `longjmp' (in C programs). These
+internal breakpoints are assigned negative numbers, starting with `-1';
+`info breakpoints' does not display them. You can see these
+breakpoints with the GDB maintenance command `maint info breakpoints'
+(*note maint info breakpoints::).
+
+
+File: gdb.info, Node: Set Watchpoints, Next: Set Catchpoints, Prev: Set Breaks, Up: Breakpoints
+
+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.
+
+ Depending on your system, watchpoints may be implemented in software
+or hardware. GDB does software watchpointing by single-stepping your
+program and testing the variable's value each time, which is hundreds of
+times slower than normal execution. (But this may still be worth it, to
+catch errors where you have no clue what part of your program is the
+culprit.)
+
+ On some systems, such as HP-UX, GNU/Linux and some other x86-based
+targets, GDB includes support for hardware watchpoints, which do not
+slow down the running of your program.
+
+`watch EXPR'
+ Set a watchpoint for an expression. GDB will break when EXPR is
+ written into by the program and its value changes.
+
+`rwatch EXPR'
+ Set a watchpoint that will break when watch EXPR is read by the
+ program.
+
+`awatch EXPR'
+ Set a watchpoint that will break when EXPR is either read or
+ written into by the program.
+
+`info watchpoints'
+ This command prints a list of watchpoints, breakpoints, and
+ catchpoints; it is the same as `info break'.
+
+ GDB sets a "hardware watchpoint" if possible. Hardware watchpoints
+execute very quickly, and the debugger reports a change in value at the
+exact instruction where the change occurs. If GDB cannot set a
+hardware watchpoint, it sets a software watchpoint, which executes more
+slowly and reports the change in value at the next statement, not the
+instruction, after the change occurs.
+
+ When you issue the `watch' command, GDB reports
+
+ Hardware watchpoint NUM: EXPR
+
+if it was able to set a hardware watchpoint.
+
+ Currently, the `awatch' and `rwatch' commands can only set hardware
+watchpoints, because accesses to data that don't change the value of
+the watched expression cannot be detected without examining every
+instruction as it is being executed, and GDB does not do that
+currently. If GDB finds that it is unable to set a hardware breakpoint
+with the `awatch' or `rwatch' command, it will print a message like
+this:
+
+ Expression cannot be implemented with read/access watchpoint.
+
+ Sometimes, GDB cannot set a hardware watchpoint because the data
+type of the watched expression is wider than what a hardware watchpoint
+on the target machine can handle. For example, some systems can only
+watch regions that are up to 4 bytes wide; on such systems you cannot
+set hardware watchpoints for an expression that yields a
+double-precision floating-point number (which is typically 8 bytes
+wide). As a work-around, it might be possible to break the large region
+into a series of smaller ones and watch them with separate watchpoints.
+
+ If you set too many hardware watchpoints, GDB might be unable to
+insert all of them when you resume the execution of your program.
+Since the precise number of active watchpoints is unknown until such
+time as the program is about to be resumed, GDB might not be able to
+warn you about this when you set the watchpoints, and the warning will
+be printed only when the program is resumed:
+
+ Hardware watchpoint NUM: Could not insert watchpoint
+
+If this happens, delete or disable some of the watchpoints.
+
+ The SPARClite DSU will generate traps when a program accesses some
+data or instruction address that is assigned to the debug registers.
+For the data addresses, DSU facilitates the `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 `watch' commands, two with `rwatch' commands, *or*
+two with `awatch' commands, but you cannot set one watchpoint with one
+command and the other with a different command. GDB will reject the
+command if you try to mix watchpoints. Delete or disable unused
+watchpoint commands before setting new ones.
+
+ If you call a function interactively using `print' or `call', any
+watchpoints you have set will be inactive until GDB reaches another
+kind of breakpoint or the call completes.
+
+ GDB automatically deletes watchpoints that watch local (automatic)
+variables, or expressions that involve such variables, when they go out
+of scope, that is, when the execution leaves the block in which these
+variables were defined. In particular, when the program being debugged
+terminates, _all_ local variables go out of scope, and so only
+watchpoints that watch global variables remain set. If you rerun the
+program, you will need to set all such watchpoints again. One way of
+doing that would be to set a code breakpoint at the entry to the `main'
+function and when it breaks, set all the watchpoints.
+
+ _Warning:_ In multi-thread programs, watchpoints have only limited
+ usefulness. With the current watchpoint implementation, GDB can
+ only watch the value of an expression _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, GDB may not notice when a non-current thread's
+ activity changes the expression.
+
+ _HP-UX Warning:_ In multi-thread programs, software watchpoints
+ have only limited usefulness. If GDB creates a software
+ watchpoint, it can only watch the value of an expression _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 software watchpoints as usual. However, GDB may not notice
+ when a non-current thread's activity changes the expression.
+ (Hardware watchpoints, in contrast, watch an expression in all
+ threads.)
+
+ *Note set remote hardware-watchpoint-limit::.
+
+
+File: gdb.info, Node: Set Catchpoints, Next: Delete Breaks, Prev: Set Watchpoints, Up: Breakpoints
+
+Setting catchpoints
+-------------------
+
+You can use "catchpoints" to cause the debugger to stop for certain
+kinds of program events, such as C++ exceptions or the loading of a
+shared library. Use the `catch' command to set a catchpoint.
+
+`catch EVENT'
+ Stop when EVENT occurs. EVENT can be any of the following:
+ `throw'
+ The throwing of a C++ exception.
+
+ `catch'
+ The catching of a C++ exception.
+
+ `exec'
+ A call to `exec'. This is currently only available for HP-UX.
+
+ `fork'
+ A call to `fork'. This is currently only available for HP-UX.
+
+ `vfork'
+ A call to `vfork'. This is currently only available for
+ HP-UX.
+
+ `load'
+ `load LIBNAME'
+ The dynamic loading of any shared library, or the loading of
+ the library LIBNAME. This is currently only available for
+ HP-UX.
+
+ `unload'
+ `unload LIBNAME'
+ The unloading of any dynamically loaded shared library, or
+ the unloading of the library LIBNAME. This is currently only
+ available for HP-UX.
+
+`tcatch EVENT'
+ Set a catchpoint that is enabled only for one stop. The
+ catchpoint is automatically deleted after the first time the event
+ is caught.
+
+
+ Use the `info break' command to list the current catchpoints.
+
+ There are currently some limitations to C++ exception handling
+(`catch throw' and `catch catch') in GDB:
+
+ * If you call a function interactively, GDB 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 either to abort
+ or to simply continue running until it hits a breakpoint, catches
+ a signal that GDB is listening for, or exits. This is the case
+ even if you set a catchpoint for the exception; catchpoints on
+ exceptions are disabled within interactive calls.
+
+ * You cannot raise an exception interactively.
+
+ * You cannot install an exception handler interactively.
+
+ Sometimes `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 _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 GNU C++, exceptions are
+raised by calling a library function named `__raise_exception' which
+has the following ANSI C interface:
+
+ /* ADDR is where the exception identifier is stored.
+ ID is the exception identifier. */
+ void __raise_exception (void **addr, void *id);
+
+To make the debugger catch all exceptions before any stack unwinding
+takes place, set a breakpoint on `__raise_exception' (*note
+Breakpoints; watchpoints; and exceptions: Breakpoints.).
+
+ With a conditional breakpoint (*note Break conditions: Conditions.)
+that depends on the value of 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.
+
+
+File: gdb.info, Node: Delete Breaks, Next: Disabling, Prev: Set Catchpoints, Up: Breakpoints
+
+Deleting breakpoints
+--------------------
+
+It is often necessary to eliminate a breakpoint, watchpoint, or
+catchpoint once it has done its job and you no longer want your program
+to stop there. This is called "deleting" the breakpoint. A breakpoint
+that has been deleted no longer exists; it is forgotten.
+
+ With the `clear' command you can delete breakpoints according to
+where they are in your program. With the `delete' command you can
+delete individual breakpoints, watchpoints, or catchpoints by specifying
+their breakpoint numbers.
+
+ It is not necessary to delete a breakpoint to proceed past it. GDB
+automatically ignores breakpoints on the first instruction to be
+executed when you continue execution without changing the execution
+address.
+
+`clear'
+ Delete any breakpoints at the next instruction to be executed in
+ the selected stack frame (*note Selecting a frame: Selection.).
+ When the innermost frame is selected, this is a good way to delete
+ a breakpoint where your program just stopped.
+
+`clear FUNCTION'
+`clear FILENAME:FUNCTION'
+ Delete any breakpoints set at entry to the function FUNCTION.
+
+`clear LINENUM'
+`clear FILENAME:LINENUM'
+ Delete any breakpoints set at or within the code of the specified
+ line.
+
+`delete [breakpoints] [RANGE...]'
+ Delete the breakpoints, watchpoints, or catchpoints of the
+ breakpoint ranges specified as arguments. If no argument is
+ specified, delete all breakpoints (GDB asks confirmation, unless
+ you have `set confirm off'). You can abbreviate this command as
+ `d'.
+
+
+File: gdb.info, Node: Disabling, Next: Conditions, Prev: Delete Breaks, Up: Breakpoints
+
+Disabling breakpoints
+---------------------
+
+Rather than deleting a breakpoint, watchpoint, or catchpoint, you might
+prefer to "disable" it. This makes the breakpoint inoperative as if it
+had been deleted, but remembers the information on the breakpoint so
+that you can "enable" it again later.
+
+ You disable and enable breakpoints, watchpoints, and catchpoints with
+the `enable' and `disable' commands, optionally specifying one or more
+breakpoint numbers as arguments. Use `info break' or `info watch' to
+print a list of breakpoints, watchpoints, and catchpoints if you do not
+know which numbers to use.
+
+ A breakpoint, watchpoint, or catchpoint can have any of four
+different states of enablement:
+
+ * Enabled. The breakpoint stops your program. A breakpoint set
+ with the `break' command starts out in this state.
+
+ * Disabled. The breakpoint has no effect on your program.
+
+ * Enabled once. The breakpoint stops your program, but then becomes
+ disabled.
+
+ * Enabled for deletion. The breakpoint stops your program, but
+ immediately after it does so it is deleted permanently. A
+ breakpoint set with the `tbreak' command starts out in this state.
+
+ You can use the following commands to enable or disable breakpoints,
+watchpoints, and catchpoints:
+
+`disable [breakpoints] [RANGE...]'
+ 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 `disable' as `dis'.
+
+`enable [breakpoints] [RANGE...]'
+ Enable the specified breakpoints (or all defined breakpoints).
+ They become effective once again in stopping your program.
+
+`enable [breakpoints] once RANGE...'
+ Enable the specified breakpoints temporarily. GDB disables any of
+ these breakpoints immediately after stopping your program.
+
+`enable [breakpoints] delete RANGE...'
+ Enable the specified breakpoints to work once, then die. GDB
+ deletes any of these breakpoints as soon as your program stops
+ there.
+
+ Except for a breakpoint set with `tbreak' (*note Setting
+breakpoints: Set Breaks.), breakpoints that you set are initially
+enabled; subsequently, they become disabled or enabled only when you
+use one of the commands above. (The command `until' can set and delete
+a breakpoint of its own, but it does not change the state of your other
+breakpoints; see *Note Continuing and stepping: Continuing and
+Stepping.)
+
+
+File: gdb.info, Node: Conditions, Next: Break Commands, Prev: Disabling, Up: Breakpoints
+
+Break conditions
+----------------
+
+The simplest sort of breakpoint breaks every time your program reaches a
+specified place. You can also specify a "condition" for a breakpoint.
+A condition is just a Boolean expression in your programming language
+(*note 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 _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 ASSERT, you should set the
+condition `! 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, GDB 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 than break conditions
+for the purpose of performing side effects when a breakpoint is reached
+(*note Breakpoint command lists: Break Commands.).
+
+ Break conditions can be specified when a breakpoint is set, by using
+`if' in the arguments to the `break' command. *Note Setting
+breakpoints: Set Breaks. They can also be changed at any time with the
+`condition' command.
+
+ You can also use the `if' keyword with the `watch' command. The
+`catch' command does not recognize the `if' keyword; `condition' is the
+only way to impose a further condition on a catchpoint.
+
+`condition BNUM EXPRESSION'
+ Specify EXPRESSION as the break condition for breakpoint,
+ watchpoint, or catchpoint number BNUM. After you set a condition,
+ breakpoint BNUM stops your program only if the value of EXPRESSION
+ is true (nonzero, in C). When you use `condition', GDB checks
+ EXPRESSION immediately for syntactic correctness, and to determine
+ whether symbols in it have referents in the context of your
+ breakpoint. If EXPRESSION uses symbols not referenced in the
+ context of the breakpoint, GDB prints an error message:
+
+ No symbol "foo" in current context.
+
+ GDB does not actually evaluate EXPRESSION at the time the
+ `condition' command (or a command that sets a breakpoint with a
+ condition, like `break if ...') is given, however. *Note
+ Expressions: Expressions.
+
+`condition BNUM'
+ Remove the condition from breakpoint number BNUM. It becomes an
+ ordinary unconditional 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 "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
+N, the breakpoint does not stop the next N times your program reaches
+it.
+
+`ignore BNUM COUNT'
+ Set the ignore count of breakpoint number BNUM to COUNT. The next
+ COUNT times the breakpoint is reached, your program's execution
+ does not stop; other than to decrement the ignore count, GDB takes
+ no action.
+
+ To make the breakpoint stop the next time it is reached, specify a
+ count of zero.
+
+ When you use `continue' to resume execution of your program from a
+ breakpoint, you can specify an ignore count directly as an
+ argument to `continue', rather than using `ignore'. *Note
+ 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, GDB
+ resumes checking the condition.
+
+ You could achieve the effect of the ignore count with a condition
+ such as `$foo-- <= 0' using a debugger convenience variable that
+ is decremented each time. *Note Convenience variables:
+ Convenience Vars.
+
+ Ignore counts apply to breakpoints, watchpoints, and catchpoints.
+
+
+File: gdb.info, Node: Break Commands, Next: Breakpoint Menus, Prev: Conditions, Up: Breakpoints
+
+Breakpoint command lists
+------------------------
+
+You can give any breakpoint (or watchpoint or catchpoint) 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.
+
+`commands [BNUM]'
+`... COMMAND-LIST ...'
+`end'
+ Specify a list of commands for breakpoint number BNUM. The
+ commands themselves appear on the following lines. Type a line
+ containing just `end' to terminate the commands.
+
+ To remove all commands from a breakpoint, type `commands' and
+ follow it immediately with `end'; that is, give no commands.
+
+ With no BNUM argument, `commands' refers to the last breakpoint,
+ watchpoint, or catchpoint set (not to the breakpoint most recently
+ encountered).
+
+ Pressing <RET> as a means of repeating the last GDB command is
+disabled within a COMMAND-LIST.
+
+ You can use breakpoint commands to start your program up again.
+Simply use the `continue' command, or `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 `next' or `step'), you may encounter another
+breakpoint--which could have its own command list, leading to
+ambiguities about which list to execute.
+
+ If the first command you specify in a command list is `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. `silent' is meaningful
+only at the beginning of a breakpoint command list.
+
+ The commands `echo', `output', and `printf' allow you to print
+precisely controlled output, and are often useful in silent
+breakpoints. *Note Commands for controlled output: Output.
+
+ For example, here is how you could use breakpoint commands to print
+the value of `x' at entry to `foo' whenever `x' is positive.
+
+ break foo if x>0
+ commands
+ silent
+ printf "x is %d\n",x
+ cont
+ end
+
+ 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 `continue' command so
+that your program does not stop, and start with the `silent' command so
+that no output is produced. Here is an example:
+
+ break 403
+ commands
+ silent
+ set x = y + 4
+ cont
+ end
+
+
+File: gdb.info, Node: Breakpoint Menus, Next: Error in Breakpoints, Prev: Break Commands, Up: Breakpoints
+
+Breakpoint menus
+----------------
+
+Some programming languages (notably C++ and Objective-C) permit a
+single function name to be defined several times, for application in
+different contexts. This is called "overloading". When a function
+name is overloaded, `break FUNCTION' is not enough to tell GDB where
+you want a breakpoint. If you realize this is a problem, you can use
+something like `break FUNCTION(TYPES)' to specify which particular
+version of the function you want. Otherwise, GDB offers you a menu of
+numbered choices for different possible breakpoints, and waits for your
+selection with the prompt `>'. The first two options are always `[0]
+cancel' and `[1] all'. Typing `1' sets a breakpoint at each definition
+of FUNCTION, and typing `0' aborts the `break' command without setting
+any new breakpoints.
+
+ For example, the following session excerpt shows an attempt to set a
+breakpoint at the overloaded symbol `String::after'. We choose three
+particular definitions of that function name:
+
+ (gdb) 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.
+ (gdb)
+
+
+File: gdb.info, Node: Error in Breakpoints, Next: Breakpoint related warnings, Prev: Breakpoint Menus, Up: Breakpoints
+
+"Cannot insert breakpoints"
+---------------------------
+
+Under some operating systems, breakpoints cannot be used in a program if
+any other process is running that program. In this situation,
+attempting to run or continue a program with a breakpoint causes GDB to
+print an error message:
+
+ Cannot insert breakpoints.
+ The same program may be running in another process.
+
+ When this happens, you have three ways to proceed:
+
+ 1. Remove or disable the breakpoints, then continue.
+
+ 2. Suspend GDB, and copy the file containing your program to a new
+ name. Resume GDB and use the `exec-file' command to specify that
+ GDB should run your program under that name. Then start your
+ program again.
+
+ 3. Relink your program so that the text segment is nonsharable, using
+ the linker option `-N'. The operating system limitation may not
+ apply to nonsharable executables.
+
+ A similar message can be printed if you request too many active
+hardware-assisted breakpoints and watchpoints:
+
+ Stopped; cannot insert breakpoints.
+ You may have requested too many hardware breakpoints and watchpoints.
+
+This message is printed when you attempt to resume the program, since
+only then GDB knows exactly how many hardware breakpoints and
+watchpoints it needs to insert.
+
+ When this message is printed, you need to disable or remove some of
+the hardware-assisted breakpoints and watchpoints, and then continue.
+
+
+File: gdb.info, Node: Breakpoint related warnings, Prev: Error in Breakpoints, Up: Breakpoints
+
+"Breakpoint address adjusted..."
+--------------------------------
+
+Some processor architectures place constraints on the addresses at
+which breakpoints may be placed. For architectures thus constrained,
+GDB will attempt to adjust the breakpoint's address to comply with the
+constraints dictated by the architecture.
+
+ One example of such an architecture is the Fujitsu FR-V. The FR-V is
+a VLIW architecture in which a number of RISC-like instructions may be
+bundled together for parallel execution. The FR-V architecture
+constrains the location of a breakpoint instruction within such a
+bundle to the instruction with the lowest address. GDB honors this
+constraint by adjusting a breakpoint's address to the first in the
+bundle.
+
+ It is not uncommon for optimized code to have bundles which contain
+instructions from different source statements, thus it may happen that
+a breakpoint's address will be adjusted from one source statement to
+another. Since this adjustment may significantly alter GDB's
+breakpoint related behavior from what the user expects, a warning is
+printed when the breakpoint is first set and also when the breakpoint
+is hit.
+
+ A warning like the one below is printed when setting a breakpoint
+that's been subject to address adjustment:
+
+ warning: Breakpoint address adjusted from 0x00010414 to 0x00010410.
+
+ Such warnings are printed both for user settable and GDB's internal
+breakpoints. If you see one of these warnings, you should verify that
+a breakpoint set at the adjusted address will have the desired affect.
+If not, the breakpoint in question may be removed and other breakpoints
+may be set which will have the desired behavior. E.g., it may be
+sufficient to place the breakpoint at a later instruction. A
+conditional breakpoint may also be useful in some cases to prevent the
+breakpoint from triggering too often.
+
+ GDB will also issue a warning when stopping at one of these adjusted
+breakpoints:
+
+ warning: Breakpoint 1 address previously adjusted from 0x00010414
+ to 0x00010410.
+
+ When this warning is encountered, it may be too late to take remedial
+action except in cases where the breakpoint is hit earlier or more
+frequently than expected.
+
+
+File: gdb.info, Node: Continuing and Stepping, Next: Signals, Prev: Breakpoints, Up: Stopping
+
+Continuing and stepping
+=======================
+
+"Continuing" means resuming program execution until your program
+completes normally. In contrast, "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 a breakpoint or a signal. (If it
+stops due to a signal, you may want to use `handle', or use `signal 0'
+to resume execution. *Note Signals: Signals.)
+
+`continue [IGNORE-COUNT]'
+`c [IGNORE-COUNT]'
+`fg [IGNORE-COUNT]'
+ Resume program execution, at the address where your program last
+ stopped; any breakpoints set at that address are bypassed. The
+ optional argument IGNORE-COUNT allows you to specify a further
+ number of times to ignore a breakpoint at this location; its
+ effect is like that of `ignore' (*note Break conditions:
+ Conditions.).
+
+ The argument IGNORE-COUNT is meaningful only when your program
+ stopped due to a breakpoint. At other times, the argument to
+ `continue' is ignored.
+
+ The synonyms `c' and `fg' (for "foreground", as the debugged
+ program is deemed to be the foreground program) are provided
+ purely for convenience, and have exactly the same behavior as
+ `continue'.
+
+ To resume execution at a different place, you can use `return'
+(*note Returning from a function: Returning.) to go back to the calling
+function; or `jump' (*note Continuing at a different address: Jumping.)
+to go to an arbitrary location in your program.
+
+ A typical technique for using stepping is to set a breakpoint (*note
+Breakpoints; watchpoints; and catchpoints: Breakpoints.) 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.
+
+`step'
+ Continue running your program until control reaches a different
+ source line, then stop it and return control to GDB. This command
+ is abbreviated `s'.
+
+ _Warning:_ If you use the `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 `stepi' command, described
+ below.
+
+ The `step' command only stops at the first instruction of a source
+ line. This prevents the multiple stops that could otherwise occur
+ in `switch' statements, `for' loops, etc. `step' continues to
+ stop if a function that has debugging information is called within
+ the line. In other words, `step' _steps inside_ any functions
+ called within the line.
+
+ Also, the `step' command only enters a function if there is line
+ number information for the function. Otherwise it acts like the
+ `next' command. This avoids problems when using `cc -gl' on MIPS
+ machines. Previously, `step' entered subroutines if there was any
+ debugging information about the routine.
+
+`step COUNT'
+ Continue running as in `step', but do so COUNT times. If a
+ breakpoint is reached, or a signal not related to stepping occurs
+ before COUNT steps, stepping stops right away.
+
+`next [COUNT]'
+ Continue to the next source line in the current (innermost) stack
+ frame. This is similar to `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 `next'
+ command. This command is abbreviated `n'.
+
+ An argument COUNT is a repeat count, as for `step'.
+
+ The `next' command only stops at the first instruction of a source
+ line. This prevents multiple stops that could otherwise occur in
+ `switch' statements, `for' loops, etc.
+
+`set step-mode'
+`set step-mode on'
+ The `set step-mode on' command causes the `step' command to stop
+ at the first instruction of a function which contains no debug line
+ information rather than stepping over it.
+
+ This is useful in cases where you may be interested in inspecting
+ the machine instructions of a function which has no symbolic info
+ and do not want GDB to automatically skip over this function.
+
+`set step-mode off'
+ Causes the `step' command to step over any functions which
+ contains no debug information. This is the default.
+
+`finish'
+ Continue running until just after function in the selected stack
+ frame returns. Print the returned value (if any).
+
+ Contrast this with the `return' command (*note Returning from a
+ function: Returning.).
+
+`until'
+`u'
+ 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
+ `next' command, except that when `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, `until' makes your program continue execution
+ until it exits the loop. In contrast, a `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.
+
+ `until' always stops your program if it attempts to exit the
+ current stack frame.
+
+ `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 `f'
+ (`frame') command shows that execution is stopped at line `206';
+ yet when we use `until', we get to line `195':
+
+ (gdb) f
+ #0 main (argc=4, argv=0xf7fffae8) at m4.c:206
+ 206 expand_input();
+ (gdb) until
+ 195 for ( ; argc > 0; NEXTARG) {
+
+ 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 `for'-loop is
+ written before the body of the loop. The `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.
+
+ `until' with no argument works by means of single instruction
+ stepping, and hence is slower than `until' with an argument.
+
+`until LOCATION'
+`u LOCATION'
+ Continue running your program until either the specified location
+ is reached, or the current stack frame returns. LOCATION is any of
+ the forms of argument acceptable to `break' (*note Setting
+ breakpoints: Set Breaks.). This form of the command uses
+ breakpoints, and hence is quicker than `until' without an
+ argument. The specified location is actually reached only if it
+ is in the current frame. This implies that `until' can be used to
+ skip over recursive function invocations. For instance in the
+ code below, if the current location is line `96', issuing `until
+ 99' will execute the program up to line `99' in the same
+ invocation of factorial, i.e. after the inner invocations have
+ returned.
+
+ 94 int factorial (int value)
+ 95 {
+ 96 if (value > 1) {
+ 97 value *= factorial (value - 1);
+ 98 }
+ 99 return (value);
+ 100 }
+
+`advance LOCATION'
+ Continue running the program up to the given location. An
+ argument is required, anything of the same form as arguments for
+ the `break' command. Execution will also stop upon exit from the
+ current stack frame. This command is similar to `until', but
+ `advance' will not skip over recursive function calls, and the
+ target location doesn't have to be in the same frame as the
+ current one.
+
+`stepi'
+`stepi ARG'
+`si'
+ Execute one machine instruction, then stop and return to the
+ debugger.
+
+ It is often useful to do `display/i $pc' when stepping by machine
+ instructions. This makes GDB automatically display the next
+ instruction to be executed, each time your program stops. *Note
+ Automatic display: Auto Display.
+
+ An argument is a repeat count, as in `step'.
+
+`nexti'
+`nexti ARG'
+`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 `next'.
+
+
+File: gdb.info, Node: Signals, Next: Thread Stops, Prev: Continuing and Stepping, Up: Stopping
+
+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 `SIGINT' is the signal
+a program gets when you type an interrupt character (often `C-c');
+`SIGSEGV' is the signal a program gets from referencing a place in
+memory far away from all the areas in use; `SIGALRM' occurs when the
+alarm clock timer goes off (which happens only if your program has
+requested an alarm).
+
+ Some signals, including `SIGALRM', are a normal part of the
+functioning of your program. Others, such as `SIGSEGV', indicate
+errors; these signals are "fatal" (they kill your program immediately)
+if the program has not specified in advance some other way to handle
+the signal. `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.
+
+ GDB has the ability to detect any occurrence of a signal in your
+program. You can tell GDB in advance what to do for each kind of
+signal.
+
+ Normally, GDB is set up to let the non-erroneous signals like
+`SIGALRM' be silently passed to your program (so as not to interfere
+with their role in the program's functioning) but to stop your program
+immediately whenever an error signal happens. You can change these
+settings with the `handle' command.
+
+`info signals'
+`info handle'
+ Print a table of all the kinds of signals and how GDB has been
+ told to handle each one. You can use this to see the signal
+ numbers of all the defined types of signals.
+
+ `info handle' is an alias for `info signals'.
+
+`handle SIGNAL KEYWORDS...'
+ Change the way GDB handles signal SIGNAL. SIGNAL can be the
+ number of a signal or its name (with or without the `SIG' at the
+ beginning); a list of signal numbers of the form `LOW-HIGH'; or
+ the word `all', meaning all the known signals. The KEYWORDS say
+ what change to make.
+
+ The keywords allowed by the `handle' command can be abbreviated.
+Their full names are:
+
+`nostop'
+ GDB should not stop your program when this signal happens. It may
+ still print a message telling you that the signal has come in.
+
+`stop'
+ GDB should stop your program when this signal happens. This
+ implies the `print' keyword as well.
+
+`print'
+ GDB should print a message when this signal happens.
+
+`noprint'
+ GDB should not mention the occurrence of the signal at all. This
+ implies the `nostop' keyword as well.
+
+`pass'
+`noignore'
+ GDB 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. `pass' and `noignore' are synonyms.
+
+`nopass'
+`ignore'
+ GDB should not allow your program to see this signal. `nopass'
+ and `ignore' are synonyms.
+
+ When a signal stops your program, the signal is not visible to the
+program until you continue. Your program sees the signal then, if
+`pass' is in effect for the signal in question _at that time_. In
+other words, after GDB reports a signal, you can use the `handle'
+command with `pass' or `nopass' to control whether your program sees
+that signal when you continue.
+
+ The default is set to `nostop', `noprint', `pass' for non-erroneous
+signals such as `SIGALRM', `SIGWINCH' and `SIGCHLD', and to `stop',
+`print', `pass' for the erroneous signals.
+
+ You can also use the `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 `signal 0'. *Note Giving your program a signal:
+Signaling.
+
+
+File: gdb.info, Node: Thread Stops, Prev: Signals, Up: Stopping
+
+Stopping and starting multi-thread programs
+===========================================
+
+When your program has multiple threads (*note Debugging programs with
+multiple threads: Threads.), you can choose whether to set breakpoints
+on all threads, or on a particular thread.
+
+`break LINESPEC thread THREADNO'
+`break LINESPEC thread THREADNO if ...'
+ LINESPEC specifies source lines; there are several ways of writing
+ them, but the effect is always to specify some source line.
+
+ Use the qualifier `thread THREADNO' with a breakpoint command to
+ specify that you only want GDB to stop the program when a
+ particular thread reaches this breakpoint. THREADNO is one of the
+ numeric thread identifiers assigned by GDB, shown in the first
+ column of the `info threads' display.
+
+ If you do not specify `thread THREADNO' when you set a breakpoint,
+ the breakpoint applies to _all_ threads of your program.
+
+ You can use the `thread' qualifier on conditional breakpoints as
+ well; in this case, place `thread THREADNO' before the breakpoint
+ condition, like this:
+
+ (gdb) break frik.c:13 thread 28 if bartab > lim
+
+
+ Whenever your program stops under GDB for any reason, _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.
+
+ There is an unfortunate side effect. If one thread stops for a
+breakpoint, or for some other reason, and another thread is blocked in a
+system call, then the system call may return prematurely. This is a
+consequence of the interaction between multiple threads and the signals
+that GDB uses to implement breakpoints and other events that stop
+execution.
+
+ To handle this problem, your program should check the return value of
+each system call and react appropriately. This is good programming
+style anyways.
+
+ For example, do not write code like this:
+
+ sleep (10);
+
+ The call to `sleep' will return early if a different thread stops at
+a breakpoint or for some other reason.
+
+ Instead, write this:
+
+ int unslept = 10;
+ while (unslept > 0)
+ unslept = sleep (unslept);
+
+ A system call is allowed to return early, so the system is still
+conforming to its specification. But GDB does cause your
+multi-threaded program to behave differently than it would without GDB.
+
+ Also, GDB uses internal breakpoints in the thread library to monitor
+certain events such as thread creation and thread destruction. When
+such an event happens, a system call in another thread may return
+prematurely, even though your program does not appear to stop.
+
+ Conversely, whenever you restart the program, _all_ threads start
+executing. _This is true even when single-stepping_ with commands like
+`step' or `next'.
+
+ In particular, GDB cannot single-step all threads in lockstep.
+Since thread scheduling is up to your debugging target's operating
+system (not controlled by GDB), 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.
+
+ On some OSes, you can lock the OS scheduler and thus allow only a
+single thread to run.
+
+`set scheduler-locking MODE'
+ Set the scheduler locking mode. If it is `off', then there is no
+ locking and any thread may run at any time. If `on', then only the
+ current thread may run when the inferior is resumed. The `step'
+ mode optimizes for single-stepping. It stops other threads from
+ "seizing the prompt" by preempting the current thread while you are
+ stepping. Other threads will only rarely (or never) get a chance
+ to run when you step. They are more likely to run when you `next'
+ over a function call, and they are completely free to run when you
+ use commands like `continue', `until', or `finish'. However,
+ unless another thread hits a breakpoint during its timeslice, they
+ will never steal the GDB prompt away from the thread that you are
+ debugging.
+
+`show scheduler-locking'
+ Display the current scheduler locking mode.
+
+
+File: gdb.info, Node: Stack, Next: Source, Prev: Stopping, Up: Top
+
+Examining the Stack
+*******************
+
+When your program has stopped, the first thing you need to know is
+where it stopped and how it got there.
+
+ 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 "stack frame". The stack frames are allocated
+in a region of memory called the "call stack".
+
+ When your program stops, the GDB commands for examining the stack
+allow you to see all of this information.
+
+ One of the stack frames is "selected" by GDB and many GDB commands
+refer implicitly to the selected frame. In particular, whenever you
+ask GDB for the value of a variable in your program, the value is found
+in the selected frame. There are special GDB commands to select
+whichever frame you are interested in. *Note Selecting a frame:
+Selection.
+
+ When your program stops, GDB automatically selects the currently
+executing frame and describes it briefly, similar to the `frame'
+command (*note Information about a frame: Frame Info.).
+
+* Menu:
+
+* Frames:: Stack frames
+* Backtrace:: Backtraces
+* Selection:: Selecting a frame
+* Frame Info:: Information on a frame
+
+
+File: gdb.info, Node: Frames, Next: Backtrace, Up: Stack
+
+Stack frames
+============
+
+The call stack is divided up into contiguous pieces called "stack
+frames", or "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.
+
+ When your program is started, the stack has only one frame, that of
+the function `main'. This is called the "initial" frame or the
+"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 "innermost" frame. This
+is the most recently created of all the stack frames that still exist.
+
+ 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 "frame pointer register" while
+execution is going on in that frame.
+
+ GDB 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 GDB to give you a way of designating stack frames in GDB
+commands.
+
+ Some compilers provide a way to compile functions so that they
+operate without stack frames. (For example, the gcc option
+ `-fomit-frame-pointer'
+ generates functions without a frame.) This is occasionally done
+with heavily used library functions to save the frame setup time. GDB
+has limited facilities for dealing with these function invocations. If
+the innermost function invocation has no stack frame, GDB 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,
+GDB has no provision for frameless functions elsewhere in the stack.
+
+`frame ARGS'
+ The `frame' command allows you to move from one stack frame to
+ another, and to print the stack frame you select. ARGS may be
+ either the address of the frame or the stack frame number.
+ Without an argument, `frame' prints the current stack frame.
+
+`select-frame'
+ The `select-frame' command allows you to move from one stack frame
+ to another without printing the frame. This is the silent version
+ of `frame'.
+
+
+File: gdb.info, Node: Backtrace, Next: Selection, Prev: Frames, Up: Stack
+
+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.
+
+`backtrace'
+`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 `C-c'.
+
+`backtrace N'
+`bt N'
+ Similar, but print only the innermost N frames.
+
+`backtrace -N'
+`bt -N'
+ Similar, but print only the outermost N frames.
+
+ The names `where' and `info stack' (abbreviated `info s') are
+additional aliases for `backtrace'.
+
+ Each line in the backtrace shows the frame number and the function
+name. The program counter value is also shown--unless you use `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 `bt
+3', so it shows the innermost three frames.
+
+ #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...)
+
+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 `993' of `builtin.c'.
+
+ Most programs have a standard user entry point--a place where system
+libraries and startup code transition into user code. For C this is
+`main'. When GDB finds the entry function in a backtrace it will
+terminate the backtrace, to avoid tracing into highly system-specific
+(and generally uninteresting) code.
+
+ If you need to examine the startup code, or limit the number of
+levels in a backtrace, you can change this behavior:
+
+`set backtrace past-main'
+`set backtrace past-main on'
+ Backtraces will continue past the user entry point.
+
+`set backtrace past-main off'
+ Backtraces will stop when they encounter the user entry point.
+ This is the default.
+
+`show backtrace past-main'
+ Display the current user entry point backtrace policy.
+
+`set backtrace limit N'
+`set backtrace limit 0'
+ Limit the backtrace to N levels. A value of zero means unlimited.
+
+`show backtrace limit'
+ Display the current limit on backtrace levels.
+
+
+File: gdb.info, Node: Selection, Next: Frame Info, Prev: Backtrace, Up: Stack
+
+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.
+
+`frame N'
+`f N'
+ Select frame number 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 `main'.
+
+`frame ADDR'
+`f ADDR'
+ Select the frame at address ADDR. This is useful mainly if the
+ chaining of stack frames has been damaged by a bug, making it
+ impossible for GDB to assign numbers properly to all frames. In
+ addition, this can be useful when your program has multiple stacks
+ and switches between them.
+
+ On the SPARC architecture, `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.
+
+`up N'
+ Move N frames up the stack. For positive numbers N, this advances
+ toward the outermost frame, to higher frame numbers, to frames
+ that have existed longer. N defaults to one.
+
+`down N'
+ Move N frames down the stack. For positive numbers N, this
+ advances toward the innermost frame, to lower frame numbers, to
+ frames that were created more recently. N defaults to one. You
+ may abbreviate `down' as `do'.
+
+ 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.
+
+ For example:
+
+ (gdb) up
+ #1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc)
+ at env.c:10
+ 10 read_input_file (argv[i]);
+
+ After such a printout, the `list' command with no arguments prints
+ten lines centered on the point of execution in the frame. You can
+also edit the program at the point of execution with your favorite
+editing program by typing `edit'. *Note Printing source lines: List,
+for details.
+
+`up-silently N'
+`down-silently N'
+ These two commands are variants of `up' and `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
+ GDB command scripts, where the output might be unnecessary and
+ distracting.
+
+
+File: gdb.info, Node: Frame Info, Prev: Selection, Up: Stack
+
+Information about a frame
+=========================
+
+There are several other commands to print information about the selected
+stack frame.
+
+`frame'
+`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 `f'. With an
+ argument, this command is used to select a stack frame. *Note
+ Selecting a frame: Selection.
+
+`info frame'
+`info f'
+ This command prints a verbose description of the selected stack
+ frame, including:
+
+ * the address of the frame
+
+ * the address of the next frame down (called by this frame)
+
+ * the address of the next frame up (caller of this frame)
+
+ * the language in which the source code corresponding to this
+ frame is written
+
+ * the address of the frame's arguments
+
+ * the address of the frame's local variables
+
+ * the program counter saved in it (the address of execution in
+ the caller frame)
+
+ * which registers were saved in the frame
+
+ The verbose description is useful when something has gone wrong
+ that has made the stack format fail to fit the usual conventions.
+
+`info frame ADDR'
+`info f ADDR'
+ Print a verbose description of the frame at address 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 `frame' command.
+ *Note Selecting a frame: Selection.
+
+`info args'
+ Print the arguments of the selected frame, each on a separate line.
+
+`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.
+
+`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
+ `up', `down', or `frame' commands); then type `info catch'. *Note
+ Setting catchpoints: Set Catchpoints.
+
+
+
+File: gdb.info, Node: Source, Next: Data, Prev: Stack, Up: Top
+
+Examining Source Files
+**********************
+
+GDB can print parts of your program's source, since the debugging
+information recorded in the program tells GDB what source files were
+used to build it. When your program stops, GDB spontaneously prints
+the line where it stopped. Likewise, when you select a stack frame
+(*note Selecting a frame: Selection.), GDB prints the line where
+execution in that frame has stopped. You can print other portions of
+source files by explicit command.
+
+ If you use GDB through its GNU Emacs interface, you may prefer to
+use Emacs facilities to view source; see *Note Using GDB under GNU
+Emacs: Emacs.
+
+* Menu:
+
+* List:: Printing source lines
+* Edit:: Editing source files
+* Search:: Searching source files
+* Source Path:: Specifying source directories
+* Machine Code:: Source and machine code
+
+
+File: gdb.info, Node: List, Next: Edit, Up: Source
+
+Printing source lines
+=====================
+
+To print lines from a source file, use the `list' command (abbreviated
+`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 `list' command most commonly used:
+
+`list LINENUM'
+ Print lines centered around line number LINENUM in the current
+ source file.
+
+`list FUNCTION'
+ Print lines centered around the beginning of function FUNCTION.
+
+`list'
+ Print more lines. If the last lines printed were printed with a
+ `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 (*note Examining the
+ Stack: Stack.), this prints lines centered around that line.
+
+`list -'
+ Print lines just before the lines last printed.
+
+ By default, GDB prints ten source lines with any of these forms of
+the `list' command. You can change this using `set listsize':
+
+`set listsize COUNT'
+ Make the `list' command display COUNT source lines (unless the
+ `list' argument explicitly specifies some other number).
+
+`show listsize'
+ Display the number of lines that `list' prints.
+
+ Repeating a `list' command with <RET> discards the argument, so it
+is equivalent to typing just `list'. This is more useful than listing
+the same lines again. An exception is made for an argument of `-';
+that argument is preserved in repetition so that each repetition moves
+up in the source file.
+
+ In general, the `list' command expects you to supply zero, one or two
+"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 `list':
+
+`list LINESPEC'
+ Print lines centered around the line specified by LINESPEC.
+
+`list FIRST,LAST'
+ Print lines from FIRST to LAST. Both arguments are linespecs.
+
+`list ,LAST'
+ Print lines ending with LAST.
+
+`list FIRST,'
+ Print lines starting with FIRST.
+
+`list +'
+ Print lines just after the lines last printed.
+
+`list -'
+ Print lines just before the lines last printed.
+
+`list'
+ As described in the preceding table.
+
+ Here are the ways of specifying a single source line--all the kinds
+of linespec.
+
+`NUMBER'
+ Specifies line NUMBER of the current source file. When a `list'
+ command has two linespecs, this refers to the same source file as
+ the first linespec.
+
+`+OFFSET'
+ Specifies the line OFFSET lines after the last line printed. When
+ used as the second linespec in a `list' command that has two, this
+ specifies the line OFFSET lines down from the first linespec.
+
+`-OFFSET'
+ Specifies the line OFFSET lines before the last line printed.
+
+`FILENAME:NUMBER'
+ Specifies line NUMBER in the source file FILENAME.
+
+`FUNCTION'
+ Specifies the line that begins the body of the function FUNCTION.
+ For example: in C, this is the line with the open brace.
+
+`FILENAME:FUNCTION'
+ Specifies the line of the open-brace that begins the body of the
+ function FUNCTION in the file FILENAME. You only need the file
+ name with a function name to avoid ambiguity when there are
+ identically named functions in different source files.
+
+`*ADDRESS'
+ Specifies the line containing the program address ADDRESS.
+ ADDRESS may be any expression.
+
+
+File: gdb.info, Node: Edit, Next: Search, Prev: List, Up: Source
+
+Editing source files
+====================
+
+To edit the lines in a source file, use the `edit' command. The
+editing program of your choice is invoked with the current line set to
+the active line in the program. Alternatively, there are several ways
+to specify what part of the file you want to print if you want to see
+other parts of the program.
+
+ Here are the forms of the `edit' command most commonly used:
+
+`edit'
+ Edit the current source file at the active line number in the
+ program.
+
+`edit NUMBER'
+ Edit the current source file with NUMBER as the active line number.
+
+`edit FUNCTION'
+ Edit the file containing FUNCTION at the beginning of its
+ definition.
+
+`edit FILENAME:NUMBER'
+ Specifies line NUMBER in the source file FILENAME.
+
+`edit FILENAME:FUNCTION'
+ Specifies the line that begins the body of the function FUNCTION
+ in the file FILENAME. You only need the file name with a function
+ name to avoid ambiguity when there are identically named functions
+ in different source files.
+
+`edit *ADDRESS'
+ Specifies the line containing the program address ADDRESS.
+ ADDRESS may be any expression.
+
+Choosing your editor
+--------------------
+
+You can customize GDB to use any editor you want (1). By default, it
+is /bin/ex, but you can change this by setting the environment variable
+`EDITOR' before using GDB. For example, to configure GDB to use the
+`vi' editor, you could use these commands with the `sh' shell:
+ EDITOR=/usr/bin/vi
+ export EDITOR
+ gdb ...
+ or in the `csh' shell,
+ setenv EDITOR /usr/bin/vi
+ gdb ...
+
+ ---------- Footnotes ----------
+
+ (1) The only restriction is that your editor (say `ex'), recognizes
+the following command-line syntax:
+ ex +NUMBER file
+ The optional numeric value +NUMBER designates the active line in the
+file.
+
+
+File: gdb.info, Node: Search, Next: Source Path, Prev: Edit, Up: Source
+
+Searching source files
+======================
+
+There are two commands for searching through the current source file
+for a regular expression.
+
+`forward-search REGEXP'
+`search REGEXP'
+ The command `forward-search REGEXP' checks each line, starting
+ with the one following the last line listed, for a match for
+ REGEXP. It lists the line that is found. You can use the synonym
+ `search REGEXP' or abbreviate the command name as `fo'.
+
+`reverse-search REGEXP'
+ The command `reverse-search REGEXP' checks each line, starting
+ with the one before the last line listed and going backward, for a
+ match for REGEXP. It lists the line that is found. You can
+ abbreviate this command as `rev'.
+
+
+File: gdb.info, Node: Source Path, Next: Machine Code, Prev: Search, Up: Source
+
+Specifying source directories
+=============================
+
+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. GDB has a list of directories to search for
+source files; this is called the "source path". Each time GDB 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 _not_ used for this
+purpose. Neither is the current working directory, unless it happens
+to be in the source path.
+
+ If GDB cannot find a source file in the source path, and the object
+program records a directory, GDB tries that directory too. If the
+source path is empty, and there is no record of the compilation
+directory, GDB looks in the current directory as a last resort.
+
+ Whenever you reset or rearrange the source path, GDB clears out any
+information it has cached about where source files are found and where
+each line is in the file.
+
+ When you start GDB, its source path includes only `cdir' and `cwd',
+in that order. To add other directories, use the `directory' command.
+
+`directory DIRNAME ...'
+
+`dir DIRNAME ...'
+ Add directory DIRNAME to the front of the source path. Several
+ directory names may be given to this command, separated by `:'
+ (`;' on MS-DOS and MS-Windows, where `:' usually appears as part
+ of absolute file names) or whitespace. You may specify a
+ directory that is already in the source path; this moves it
+ forward, so GDB searches it sooner.
+
+ You can use the string `$cdir' to refer to the compilation
+ directory (if one is recorded), and `$cwd' to refer to the current
+ working directory. `$cwd' is not the same as `.'--the former
+ tracks the current working directory as it changes during your GDB
+ session, while the latter is immediately expanded to the current
+ directory at the time you add an entry to the source path.
+
+`directory'
+ Reset the source path to empty again. This requires confirmation.
+
+`show directories'
+ Print the source path: show which directories it contains.
+
+ If your source path is cluttered with directories that are no longer
+of interest, GDB may sometimes cause confusion by finding the wrong
+versions of source. You can correct the situation as follows:
+
+ 1. Use `directory' with no argument to reset the source path to empty.
+
+ 2. Use `directory' with suitable arguments to reinstall the
+ directories you want in the source path. You can add all the
+ directories in one command.
+
+
+File: gdb.info, Node: Machine Code, Prev: Source Path, Up: Source
+
+Source and machine code
+=======================
+
+You can use the command `info line' to map source lines to program
+addresses (and vice versa), and the command `disassemble' to display a
+range of addresses as machine instructions. When run under GNU Emacs
+mode, the `info line' command causes the arrow to point to the line
+specified. Also, `info line' prints addresses in symbolic form as well
+as hex.
+
+`info line LINESPEC'
+ Print the starting and ending addresses of the compiled code for
+ source line LINESPEC. You can specify source lines in any of the
+ ways understood by the `list' command (*note Printing source
+ lines: List.).
+
+ For example, we can use `info line' to discover the location of the
+object code for the first line of function `m4_changequote':
+
+ (gdb) info line m4_changequote
+ Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350.
+
+We can also inquire (using `*ADDR' as the form for LINESPEC) what
+source line covers a particular address:
+ (gdb) info line *0x63ff
+ Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404.
+
+ After `info line', the default address for the `x' command is
+changed to the starting address of the line, so that `x/i' is
+sufficient to begin examining the machine code (*note Examining memory:
+Memory.). Also, this address is saved as the value of the convenience
+variable `$_' (*note Convenience variables: Convenience Vars.).
+
+`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; GDB dumps the
+ function surrounding this value. Two arguments specify a range of
+ addresses (first inclusive, second exclusive) to dump.
+
+ The following example shows the disassembly of a range of addresses
+of HP PA-RISC 2.0 code:
+
+ (gdb) disas 0x32c4 0x32e4
+ Dump of assembler code from 0x32c4 to 0x32e4:
+ 0x32c4 <main+204>: addil 0,dp
+ 0x32c8 <main+208>: ldw 0x22c(sr0,r1),r26
+ 0x32cc <main+212>: ldil 0x3000,r31
+ 0x32d0 <main+216>: ble 0x3f8(sr4,r31)
+ 0x32d4 <main+220>: ldo 0(r31),rp
+ 0x32d8 <main+224>: addil -0x800,dp
+ 0x32dc <main+228>: ldo 0x588(r1),r26
+ 0x32e0 <main+232>: ldil 0x3000,r31
+ End of assembler dump.
+
+ Some architectures have more than one commonly-used set of
+instruction mnemonics or other syntax.
+
+`set disassembly-flavor INSTRUCTION-SET'
+ Select the instruction set to use when disassembling the program
+ via the `disassemble' or `x/i' commands.
+
+ Currently this command is only defined for the Intel x86 family.
+ You can set INSTRUCTION-SET to either `intel' or `att'. The
+ default is `att', the AT&T flavor used by default by Unix
+ assemblers for x86-based targets.
+
+
+File: gdb.info, Node: Data, Next: Macros, Prev: Source, Up: Top
+
+Examining Data
+**************
+
+The usual way to examine data in your program is with the `print'
+command (abbreviated `p'), or its synonym `inspect'. It evaluates and
+prints the value of an expression of the language your program is
+written in (*note Using GDB with Different Languages: Languages.).
+
+`print EXPR'
+`print /F EXPR'
+ EXPR is an expression (in the source language). By default the
+ value of EXPR is printed in a format appropriate to its data type;
+ you can choose a different format by specifying `/F', where F is a
+ letter specifying the format; see *Note Output formats: Output
+ Formats.
+
+`print'
+`print /F'
+ If you omit EXPR, GDB displays the last value again (from the
+ "value history"; *note Value history: Value History.). This
+ allows you to conveniently inspect the same value in an
+ alternative format.
+
+ A more low-level way of examining data is with the `x' command. It
+examines data in memory at a specified address and prints it in a
+specified format. *Note Examining memory: Memory.
+
+ If you are interested in information about types, or about how the
+fields of a struct or a class are declared, use the `ptype EXP' command
+rather than `print'. *Note Examining the Symbol Table: Symbols.
+
+* 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
+* Floating Point Hardware:: Floating point hardware
+* Vector Unit:: Vector Unit
+* Auxiliary Vector:: Auxiliary data provided by operating system
+* Memory Region Attributes:: Memory region attributes
+* Dump/Restore Files:: Copy between memory and a file
+* Character Sets:: Debugging programs that use a different
+ character set than GDB does
+
+
+File: gdb.info, Node: Expressions, Next: Variables, Up: Data
+
+Expressions
+===========
+
+`print' and many other GDB 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 GDB.
+This includes conditional expressions, function calls, casts, and
+string constants. It also includes preprocessor macros, if you
+compiled your program to include this information; see *Note
+Compilation::.
+
+ GDB supports array constants in expressions input by the user. The
+syntax is {ELEMENT, ELEMENT...}. For example, you can use the command
+`print {1, 2, 3}' to build up an array in memory that is `malloc'ed in
+the target program.
+
+ Because C is so widespread, most of the expressions shown in
+examples in this manual are in C. *Note Using GDB with Different
+Languages: Languages, for information on how to use expressions in other
+languages.
+
+ In this section, we discuss operators that you can use in GDB
+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.
+
+ GDB supports these operators, in addition to those common to
+programming languages:
+
+`@'
+ `@' is a binary operator for treating parts of memory as arrays.
+ *Note Artificial arrays: Arrays, for more information.
+
+`::'
+ `::' allows you to specify a variable in terms of the file or
+ function where it is defined. *Note Program variables: Variables.
+
+`{TYPE} ADDR'
+ Refers to an object of type TYPE stored at address ADDR in memory.
+ 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 ADDR.
+
+
+File: gdb.info, Node: Variables, Next: Arrays, Prev: Expressions, Up: Data
+
+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
+(*note Selecting a frame: Selection.); they must be either:
+
+ * global (or file-static)
+
+or
+
+ * visible according to the scope rules of the programming language
+ from the point of execution in that frame
+
+This means that in the function
+
+ foo (a)
+ int a;
+ {
+ bar (a);
+ {
+ int b = test ();
+ bar (b);
+ }
+ }
+
+you can examine and use the variable `a' whenever your program is
+executing within the function `foo', but you can only use or examine
+the variable `b' while your program is executing inside the block where
+`b' is declared.
+
+ 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:
+
+ FILE::VARIABLE
+ FUNCTION::VARIABLE
+
+Here FILE or FUNCTION is the name of the context for the static
+VARIABLE. In the case of file names, you can use quotes to make sure
+GDB parses the file name as a single word--for example, to print a
+global value of `x' defined in `f2.c':
+
+ (gdb) p 'f2.c'::x
+
+ This use of `::' is very rarely in conflict with the very similar
+use of the same notation in C++. GDB also supports use of the C++
+scope resolution operator in GDB expressions.
+
+ _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.
+ 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.
+
+ This may also happen when the compiler does significant
+optimizations. To be sure of always seeing accurate values, turn off
+all optimization when compiling.
+
+ Another possible effect of compiler optimizations is to optimize
+unused variables out of existence, or assign variables to registers (as
+opposed to memory addresses). Depending on the support for such cases
+offered by the debug info format used by the compiler, GDB might not be
+able to display values for such local variables. If that happens, GDB
+will print a message like this:
+
+ No symbol "foo" in current context.
+
+ To solve such problems, either recompile without optimizations, or
+use a different debug info format, if the compiler supports several such
+formats. For example, GCC, the GNU C/C++ compiler usually supports the
+`-gstabs+' option. `-gstabs+' produces debug info in a format that is
+superior to formats such as COFF. You may be able to use DWARF 2
+(`-gdwarf-2'), which is also an effective form for debug info. *Note
+Options for Debugging Your Program or GNU CC: (gcc.info)Debugging
+Options.
+
+
+File: gdb.info, Node: Arrays, Next: Output Formats, Prev: Variables, Up: Data
+
+Artificial arrays
+=================
+
+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
+"artificial array", using the binary operator `@'. The left operand of
+`@' 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
+
+ int *array = (int *) malloc (len * sizeof (int));
+
+you can print the contents of `array' with
+
+ p *array@len
+
+ The left operand of `@' must reside in memory. Array values made
+with `@' 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
+(*note 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:
+ (gdb) p/x (short[2])0x12345678
+ $1 = {0x1234, 0x5678}
+
+ As a convenience, if you leave the array length out (as in
+`(TYPE[])VALUE') GDB calculates the size to fill the value (as
+`sizeof(VALUE)/sizeof(TYPE)':
+ (gdb) p/x (short[])0x12345678
+ $2 = {0x1234, 0x5678}
+
+ 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 (*note Convenience variables: Convenience
+Vars.) as a counter in an expression that prints the first interesting
+value, and then repeat that expression via <RET>. For instance,
+suppose you have an array `dtab' of pointers to structures, and you are
+interested in the values of a field `fv' in each structure. Here is an
+example of what you might type:
+
+ set $i = 0
+ p dtab[$i++]->fv
+ <RET>
+ <RET>
+ ...
+
+
+File: gdb.info, Node: Output Formats, Next: Memory, Prev: Arrays, Up: Data
+
+Output formats
+==============
+
+By default, GDB 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 "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
+`print' command with a slash and a format letter. The format letters
+supported are:
+
+`x'
+ Regard the bits of the value as an integer, and print the integer
+ in hexadecimal.
+
+`d'
+ Print as integer in signed decimal.
+
+`u'
+ Print as integer in unsigned decimal.
+
+`o'
+ Print as integer in octal.
+
+`t'
+ Print as integer in binary. The letter `t' stands for "two". (1)
+
+`a'
+ 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:
+
+ (gdb) p/a 0x54320
+ $3 = 0x54320 <_initialize_vx+396>
+
+ The command `info symbol 0x54320' yields similar results. *Note
+ info symbol: Symbols.
+
+`c'
+ Regard as an integer and print it as a character constant.
+
+`f'
+ Regard the bits of the value as a floating point number and print
+ using typical floating point syntax.
+
+ For example, to print the program counter in hex (*note
+Registers::), type
+
+ p/x $pc
+
+Note that no space is required before the slash; this is because command
+names in GDB cannot contain a slash.
+
+ To reprint the last value in the value history with a different
+format, you can use the `print' command with just a format and no
+expression. For example, `p/x' reprints the last value in hex.
+
+ ---------- Footnotes ----------
+
+ (1) `b' cannot be used because these format letters are also used
+with the `x' command, where `b' stands for "byte"; see *Note Examining
+memory: Memory.
+
+
+File: gdb.info, Node: Memory, Next: Auto Display, Prev: Output Formats, Up: Data
+
+Examining memory
+================
+
+You can use the command `x' (for "examine") to examine memory in any of
+several formats, independently of your program's data types.
+
+`x/NFU ADDR'
+`x ADDR'
+`x'
+ Use the `x' command to examine memory.
+
+ N, F, and U are all optional parameters that specify how much memory
+to display and how to format it; ADDR is an expression giving the
+address where you want to start displaying memory. If you use defaults
+for NFU, you need not type the slash `/'. Several commands set
+convenient defaults for ADDR.
+
+N, the repeat count
+ The repeat count is a decimal integer; the default is 1. It
+ specifies how much memory (counting by units U) to display.
+
+F, the display format
+ The display format is one of the formats used by `print', `s'
+ (null-terminated string), or `i' (machine instruction). The
+ default is `x' (hexadecimal) initially. The default changes each
+ time you use either `x' or `print'.
+
+U, the unit size
+ The unit size is any of
+
+ `b'
+ Bytes.
+
+ `h'
+ Halfwords (two bytes).
+
+ `w'
+ Words (four bytes). This is the initial default.
+
+ `g'
+ Giant words (eight bytes).
+
+ Each time you specify a unit size with `x', that size becomes the
+ default unit the next time you use `x'. (For the `s' and `i'
+ formats, the unit size is ignored and is normally not written.)
+
+ADDR, starting display address
+ ADDR is the address where you want GDB 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.
+ *Note Expressions: Expressions, for more information on
+ expressions. The default for ADDR is usually just after the last
+ address examined--but several other commands also set the default
+ address: `info breakpoints' (to the address of the last breakpoint
+ listed), `info line' (to the starting address of a line), and
+ `print' (if you use it to display a value from memory).
+
+ For example, `x/3uh 0x54320' is a request to display three halfwords
+(`h') of memory, formatted as unsigned decimal integers (`u'), starting
+at address `0x54320'. `x/4xw $sp' prints the four words (`w') of
+memory above the stack pointer (here, `$sp'; *note Registers:
+Registers.) in hexadecimal (`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 `4xw' and `4wx' mean exactly the same thing. (However,
+the count N must come first; `wx4' does not work.)
+
+ Even though the unit size U is ignored for the formats `s' and `i',
+you might still want to use a count N; for example, `3i' specifies that
+you want to see three machine instructions, including any operands.
+The command `disassemble' gives an alternative way of inspecting
+machine instructions; see *Note Source and machine code: Machine Code.
+
+ All the defaults for the arguments to `x' are designed to make it
+easy to continue scanning memory with minimal specifications each time
+you use `x'. For example, after you have inspected three machine
+instructions with `x/3i ADDR', you can inspect the next seven with just
+`x/7'. If you use <RET> to repeat the `x' command, the repeat count N
+is used again; the other arguments default as for successive uses of
+`x'.
+
+ The addresses and contents printed by the `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, GDB makes these values available for
+subsequent use in expressions as values of the convenience variables
+`$_' and `$__'. After an `x' command, the last address examined is
+available for use in expressions in the convenience variable `$_'. The
+contents of that address, as examined, are available in the convenience
+variable `$__'.
+
+ If the `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.
+
+
+File: gdb.info, Node: Auto Display, Next: Print Settings, Prev: Memory, Up: Data
+
+Automatic display
+=================
+
+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 "automatic
+display list" so that GDB 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:
+
+ 2: foo = 38
+ 3: bar[5] = (struct hack *) 0x3804
+
+This display shows item numbers, expressions and their current values.
+As with displays you request manually using `x' or `print', you can
+specify the output format you prefer; in fact, `display' decides
+whether to use `print' or `x' depending on how elaborate your format
+specification is--it uses `x' if you specify a unit size, or one of the
+two formats (`i' and `s') that are only supported by `x'; otherwise it
+uses `print'.
+
+`display EXPR'
+ Add the expression EXPR to the list of expressions to display each
+ time your program stops. *Note Expressions: Expressions.
+
+ `display' does not repeat if you press <RET> again after using it.
+
+`display/FMT EXPR'
+ For FMT specifying only a display format and not a size or count,
+ add the expression EXPR to the auto-display list but arrange to
+ display it each time in the specified format FMT. *Note Output
+ formats: Output Formats.
+
+`display/FMT ADDR'
+ For FMT `i' or `s', or including a unit-size or a number of units,
+ add the expression ADDR as a memory address to be examined each
+ time your program stops. Examining means in effect doing `x/FMT
+ ADDR'. *Note Examining memory: Memory.
+
+ For example, `display/i $pc' can be helpful, to see the machine
+instruction about to be executed each time execution stops (`$pc' is a
+common name for the program counter; *note Registers: Registers.).
+
+`undisplay DNUMS...'
+`delete display DNUMS...'
+ Remove item numbers DNUMS from the list of expressions to display.
+
+ `undisplay' does not repeat if you press <RET> after using it.
+ (Otherwise you would just get the error `No display number ...'.)
+
+`disable display DNUMS...'
+ Disable the display of item numbers DNUMS. A disabled display
+ item is not printed automatically, but is not forgotten. It may be
+ enabled again later.
+
+`enable display DNUMS...'
+ Enable display of item numbers DNUMS. It becomes effective once
+ again in auto display of its expression, until you specify
+ otherwise.
+
+`display'
+ Display the current values of the expressions on the list, just as
+ is done when your program stops.
+
+`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.
+
+ 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
+`display last_char' while inside a function with an argument
+`last_char', GDB displays this argument while your program continues to
+stop inside that function. When it stops elsewhere--where there is no
+variable `last_char'--the display is disabled automatically. The next
+time your program stops where `last_char' is meaningful, you can enable
+the display expression once again.
+
+
+File: gdb.info, Node: Print Settings, Next: Value History, Prev: Auto Display, Up: Data
+
+Print settings
+==============
+
+GDB provides the following ways to control how arrays, structures, and
+symbols are printed.
+
+These settings are useful for debugging programs in any language:
+
+`set print address'
+`set print address on'
+ GDB 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 `on'. For example, this is what a stack frame display looks
+ like with `set print address on':
+
+ (gdb) f
+ #0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
+ at input.c:530
+ 530 if (lquote != def_lquote)
+
+`set print address off'
+ Do not print addresses when displaying their contents. For
+ example, this is the same stack frame displayed with `set print
+ address off':
+
+ (gdb) set print addr off
+ (gdb) f
+ #0 set_quotes (lq="<<", rq=">>") at input.c:530
+ 530 if (lquote != def_lquote)
+
+ You can use `set print address off' to eliminate all machine
+ dependent displays from the GDB interface. For example, with
+ `print address off', you should get the same text for backtraces on
+ all machines--whether or not they involve pointer arguments.
+
+`show print address'
+ Show whether or not addresses are to be printed.
+
+ When GDB 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
+`info line', for example `info line *0x4537'. Alternately, you can set
+GDB to print the source file and line number when it prints a symbolic
+address:
+
+`set print symbol-filename on'
+ Tell GDB to print the source file name and line number of a symbol
+ in the symbolic form of an address.
+
+`set print symbol-filename off'
+ Do not print source file name and line number of a symbol. This
+ is the default.
+
+`show print symbol-filename'
+ Show whether or not GDB will print the source file name and line
+ number of a symbol in the symbolic form of an address.
+
+ Another situation where it is helpful to show symbol filenames and
+line numbers is when disassembling code; GDB 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:
+
+`set print max-symbolic-offset MAX-OFFSET'
+ Tell GDB to only display the symbolic form of an address if the
+ offset between the closest earlier symbol and the address is less
+ than MAX-OFFSET. The default is 0, which tells GDB to always
+ print the symbolic form of an address if any symbol precedes it.
+
+`show print max-symbolic-offset'
+ Ask how large the maximum offset is that GDB prints in a symbolic
+ address.
+
+ If you have a pointer and you are not sure where it points, try `set
+print symbol-filename on'. Then you can determine the name and source
+file location of the variable where it points, using `p/a POINTER'.
+This interprets the address in symbolic form. For example, here GDB
+shows that a variable `ptt' points at another variable `t', defined in
+`hi2.c':
+
+ (gdb) set print symbol-filename on
+ (gdb) p/a ptt
+ $4 = 0xe008 <t in hi2.c>
+
+ _Warning:_ For pointers that point to a local variable, `p/a' does
+ not show the symbol name and filename of the referent, even with
+ the appropriate `set print' options turned on.
+
+ Other settings control how different kinds of objects are printed:
+
+`set print array'
+`set print array on'
+ Pretty print arrays. This format is more convenient to read, but
+ uses more space. The default is off.
+
+`set print array off'
+ Return to compressed format for arrays.
+
+`show print array'
+ Show whether compressed or pretty format is selected for displaying
+ arrays.
+
+`set print elements NUMBER-OF-ELEMENTS'
+ Set a limit on how many elements of an array GDB will print. If
+ GDB is printing a large array, it stops printing after it has
+ printed the number of elements set by the `set print elements'
+ command. This limit also applies to the display of strings. When
+ GDB starts, this limit is set to 200. Setting NUMBER-OF-ELEMENTS
+ to zero means that the printing is unlimited.
+
+`show print elements'
+ Display the number of elements of a large array that GDB will
+ print. If the number is 0, then the printing is unlimited.
+
+`set print null-stop'
+ 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. The default is off.
+
+`set print pretty on'
+ Cause GDB to print structures in an indented format with one member
+ per line, like this:
+
+ $1 = {
+ next = 0x0,
+ flags = {
+ sweet = 1,
+ sour = 1
+ },
+ meat = 0x54 "Pork"
+ }
+
+`set print pretty off'
+ Cause GDB to print structures in a compact format, like this:
+
+ $1 = {next = 0x0, flags = {sweet = 1, sour = 1}, \
+ meat = 0x54 "Pork"}
+
+ This is the default format.
+
+`show print pretty'
+ Show which format GDB is using to print structures.
+
+`set print sevenbit-strings on'
+ Print using only seven-bit characters; if this option is set, GDB
+ displays any eight-bit characters (in strings or character values)
+ using the notation `\'NNN. This setting is best if you are
+ working in English (ASCII) and you use the high-order bit of
+ characters as a marker or "meta" bit.
+
+`set print sevenbit-strings off'
+ Print full eight-bit characters. This allows the use of more
+ international character sets, and is the default.
+
+`show print sevenbit-strings'
+ Show whether or not GDB is printing only seven-bit characters.
+
+`set print union on'
+ Tell GDB to print unions which are contained in structures. This
+ is the default setting.
+
+`set print union off'
+ Tell GDB not to print unions which are contained in structures.
+
+`show print union'
+ Ask GDB whether or not it will print unions which are contained in
+ structures.
+
+ For example, given the declarations
+
+ 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}};
+
+ with `set print union on' in effect `p foo' would print
+
+ $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
+
+ and with `set print union off' in effect it would print
+
+ $1 = {it = Tree, form = {...}}
+
+These settings are of interest when debugging C++ programs:
+
+`set print demangle'
+`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 on.
+
+`show print demangle'
+ Show whether C++ names are printed in mangled or demangled form.
+
+`set print asm-demangle'
+`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.
+
+`show print asm-demangle'
+ Show whether C++ names in assembly listings are printed in mangled
+ or demangled form.
+
+`set demangle-style STYLE'
+ Choose among several encoding schemes used by different compilers
+ to represent C++ names. The choices for STYLE are currently:
+
+ `auto'
+ Allow GDB to choose a decoding style by inspecting your
+ program.
+
+ `gnu'
+ Decode based on the GNU C++ compiler (`g++') encoding
+ algorithm. This is the default.
+
+ `hp'
+ Decode based on the HP ANSI C++ (`aCC') encoding algorithm.
+
+ `lucid'
+ Decode based on the Lucid C++ compiler (`lcc') encoding
+ algorithm.
+
+ `arm'
+ Decode using the algorithm in the `C++ Annotated Reference
+ Manual'. *Warning:* this setting alone is not sufficient to
+ allow debugging `cfront'-generated executables. GDB would
+ require further enhancement to permit that.
+
+ If you omit STYLE, you will see a list of possible formats.
+
+`show demangle-style'
+ Display the encoding style currently in use for decoding C++
+ symbols.
+
+`set print object'
+`set print object on'
+ When displaying a pointer to an object, identify the _actual_
+ (derived) type of the object rather than the _declared_ type, using
+ the virtual function table.
+
+`set print object off'
+ Display only the declared type of objects, without reference to the
+ virtual function table. This is the default setting.
+
+`show print object'
+ Show whether actual, or declared, object types are displayed.
+
+`set print static-members'
+`set print static-members on'
+ Print static members when displaying a C++ object. The default is
+ on.
+
+`set print static-members off'
+ Do not print static members when displaying a C++ object.
+
+`show print static-members'
+ Show whether C++ static members are printed, or not.
+
+`set print vtbl'
+`set print vtbl on'
+ Pretty print C++ virtual function tables. The default is off.
+ (The `vtbl' commands do not work on programs compiled with the HP
+ ANSI C++ compiler (`aCC').)
+
+`set print vtbl off'
+ Do not pretty print C++ virtual function tables.
+
+`show print vtbl'
+ Show whether C++ virtual function tables are pretty printed, or
+ not.
+
+
+File: gdb.info, Node: Value History, Next: Convenience Vars, Prev: Print Settings, Up: Data
+
+Value history
+=============
+
+Values printed by the `print' command are saved in the GDB "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 `file' or `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.
+
+ The values printed are given "history numbers" by which you can
+refer to them. These are successive integers starting with one.
+`print' shows you the history number assigned to a value by printing
+`$NUM = ' before the value; here NUM is the history number.
+
+ To refer to any previous value, use `$' followed by the value's
+history number. The way `print' labels its output is designed to
+remind you of this. Just `$' refers to the most recent value in the
+history, and `$$' refers to the value before that. `$$N' refers to the
+Nth value from the end; `$$2' is the value just prior to `$$', `$$1' is
+equivalent to `$$', and `$$0' is equivalent to `$'.
+
+ 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
+
+ p *$
+
+ If you have a chain of structures where the component `next' points
+to the next one, you can print the contents of the next one with this:
+
+ p *$.next
+
+You can print successive links in the chain by repeating this
+command--which you can do by just typing <RET>.
+
+ Note that the history records values, not expressions. If the value
+of `x' is 4 and you type these commands:
+
+ print x
+ set x=5
+
+then the value recorded in the value history by the `print' command
+remains 4 even though the value of `x' has changed.
+
+`show values'
+ Print the last ten values in the value history, with their item
+ numbers. This is like `p $$9' repeated ten times, except that
+ `show values' does not change the history.
+
+`show values N'
+ Print ten history values centered on history item number N.
+
+`show values +'
+ Print ten history values just after the values last printed. If
+ no more values are available, `show values +' produces no display.
+
+ Pressing <RET> to repeat `show values N' has exactly the same effect
+as `show values +'.
+
+
+File: gdb.info, Node: Convenience Vars, Next: Registers, Prev: Value History, Up: Data
+
+Convenience variables
+=====================
+
+GDB provides "convenience variables" that you can use within GDB to
+hold on to a value and refer to it later. These variables exist
+entirely within GDB; 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 `$'. Any name preceded by
+`$' can be used for a convenience variable, unless it is one of the
+predefined machine-specific register names (*note Registers:
+Registers.). (Value history references, in contrast, are _numbers_
+preceded by `$'. *Note 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:
+
+ set $foo = *object_ptr
+
+would save in `$foo' the value contained in the object pointed to by
+`object_ptr'.
+
+ Using a convenience variable for the first time creates it, but its
+value is `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.
+
+`show convenience'
+ Print a list of convenience variables used so far, and their
+ values. Abbreviated `show conv'.
+
+ 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:
+
+ set $i = 0
+ print bar[$i++]->contents
+
+Repeat that command by typing <RET>.
+
+ Some convenience variables are created automatically by GDB and given
+values likely to be useful.
+
+`$_'
+ The variable `$_' is automatically set by the `x' command to the
+ last address examined (*note Examining memory: Memory.). Other
+ commands which provide a default address for `x' to examine also
+ set `$_' to that address; these commands include `info line' and
+ `info breakpoint'. The type of `$_' is `void *' except when set
+ by the `x' command, in which case it is a pointer to the type of
+ `$__'.
+
+`$__'
+ The variable `$__' is automatically set by the `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.
+
+`$_exitcode'
+ The variable `$_exitcode' is automatically set to the exit code
+ when the program being debugged terminates.
+
+ On HP-UX systems, if you refer to a function or variable name that
+begins with a dollar sign, GDB searches for a user or system name
+first, before it searches for a convenience variable.
+
+
+File: gdb.info, Node: Registers, Next: Floating Point Hardware, Prev: Convenience Vars, Up: Data
+
+Registers
+=========
+
+You can refer to machine register contents, in expressions, as variables
+with names starting with `$'. The names of registers are different for
+each machine; use `info registers' to see the names used on your
+machine.
+
+`info registers'
+ Print the names and values of all registers except floating-point
+ and vector registers (in the selected stack frame).
+
+`info all-registers'
+ Print the names and values of all registers, including
+ floating-point and vector registers (in the selected stack frame).
+
+`info registers REGNAME ...'
+ Print the "relativized" value of each specified register REGNAME.
+ As discussed in detail below, register values are normally
+ relative to the selected stack frame. REGNAME may be any register
+ name valid on the machine you are using, with or without the
+ initial `$'.
+
+ GDB 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
+`$pc' and `$sp' are used for the program counter register and the stack
+pointer. `$fp' is used for a register that contains a pointer to the
+current stack frame, and `$ps' is used for a register that contains the
+processor status. For example, you could print the program counter in
+hex with
+
+ p/x $pc
+
+or print the instruction to be executed next with
+
+ x/i $pc
+
+or add four to the stack pointer(1) with
+
+ set $sp += 4
+
+ 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 `info registers'
+command shows the canonical names. For example, on the SPARC, `info
+registers' displays the processor status register as `$psr' but you can
+also refer to it as `$ps'; and on x86-based machines `$ps' is an alias
+for the EFLAGS register.
+
+ GDB 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 _print_ it as a floating point value with `print/f
+$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,
+GDB normally works with the virtual format only (the format that makes
+sense for your program), but the `info registers' command prints the
+data in both formats.
+
+ Normally, register values are relative to the selected stack frame
+(*note Selecting a frame: Selection.). 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 `frame 0').
+
+ However, GDB must deduce where registers are saved, from the machine
+code generated by your compiler. If some registers are not saved, or if
+GDB is unable to locate the saved registers, the selected stack frame
+makes no difference.
+
+ ---------- Footnotes ----------
+
+ (1) 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 `$sp' is
+not allowed when other stack frames are selected. To pop entire frames
+off the stack, regardless of machine architecture, use `return'; see
+*Note Returning from a function: Returning.
+
+
+File: gdb.info, Node: Floating Point Hardware, Next: Vector Unit, Prev: Registers, Up: Data
+
+Floating point hardware
+=======================
+
+Depending on the configuration, GDB may be able to give you more
+information about the status of the floating point hardware.
+
+`info float'
+ Display hardware-dependent information about the floating point
+ unit. The exact contents and layout vary depending on the
+ floating point chip. Currently, `info float' is supported on the
+ ARM and x86 machines.
+
+
+File: gdb.info, Node: Vector Unit, Next: Auxiliary Vector, Prev: Floating Point Hardware, Up: Data
+
+Vector Unit
+===========
+
+Depending on the configuration, GDB may be able to give you more
+information about the status of the vector unit.
+
+`info vector'
+ Display information about the vector unit. The exact contents and
+ layout vary depending on the hardware.
+
+
+File: gdb.info, Node: Auxiliary Vector, Next: Memory Region Attributes, Prev: Vector Unit, Up: Data
+
+Operating system auxiliary vector
+=================================
+
+Some operating systems supply an "auxiliary vector" to programs at
+startup. This is akin to the arguments and environment that you
+specify for a program, but contains a system-dependent variety of
+binary values that tell system libraries important details about the
+hardware, operating system, and process. Each value's purpose is
+identified by an integer tag; the meanings are well-known but
+system-specific. Depending on the configuration and operating system
+facilities, GDB may be able to show you this information.
+
+`info auxv'
+ Display the auxiliary vector of the inferior, which can be either a
+ live process or a core dump file. GDB prints each tag value
+ numerically, and also shows names and text descriptions for
+ recognized tags. Some values in the vector are numbers, some bit
+ masks, and some pointers to strings or other data. GDB displays
+ each value in the most appropriate form for a recognized tag, and
+ in hexadecimal for an unrecognized tag.
+
+
+File: gdb.info, Node: Memory Region Attributes, Next: Dump/Restore Files, Prev: Auxiliary Vector, Up: Data
+
+Memory region attributes
+========================
+
+"Memory region attributes" allow you to describe special handling
+required by regions of your target's memory. GDB uses attributes to
+determine whether to allow certain types of memory accesses; whether to
+use specific width accesses; and whether to cache target memory.
+
+ Defined memory regions can be individually enabled and disabled.
+When a memory region is disabled, GDB uses the default attributes when
+accessing memory in that region. Similarly, if no memory regions have
+been defined, GDB uses the default attributes when accessing all memory.
+
+ When a memory region is defined, it is given a number to identify it;
+to enable, disable, or remove a memory region, you specify that number.
+
+`mem LOWER UPPER ATTRIBUTES...'
+ Define memory region bounded by LOWER and UPPER with attributes
+ ATTRIBUTES.... Note that UPPER == 0 is a special case: it is
+ treated as the the target's maximum memory address. (0xffff on 16
+ bit targets, 0xffffffff on 32 bit targets, etc.)
+
+`delete mem NUMS...'
+ Remove memory regions NUMS....
+
+`disable mem NUMS...'
+ Disable memory regions NUMS.... A disabled memory region is not
+ forgotten. It may be enabled again later.
+
+`enable mem NUMS...'
+ Enable memory regions NUMS....
+
+`info mem'
+ Print a table of all defined memory regions, with the following
+ columns for each region.
+
+ _Memory Region Number_
+
+ _Enabled or Disabled._
+ Enabled memory regions are marked with `y'. Disabled memory
+ regions are marked with `n'.
+
+ _Lo Address_
+ The address defining the inclusive lower bound of the memory
+ region.
+
+ _Hi Address_
+ The address defining the exclusive upper bound of the memory
+ region.
+
+ _Attributes_
+ The list of attributes set for this memory region.
+
+Attributes
+----------
+
+Memory Access Mode
+..................
+
+The access mode attributes set whether GDB may make read or write
+accesses to a memory region.
+
+ While these attributes prevent GDB from performing invalid memory
+accesses, they do nothing to prevent the target system, I/O DMA, etc.
+from accessing memory.
+
+`ro'
+ Memory is read only.
+
+`wo'
+ Memory is write only.
+
+`rw'
+ Memory is read/write. This is the default.
+
+Memory Access Size
+..................
+
+The acccess size attributes tells GDB to use specific sized accesses in
+the memory region. Often memory mapped device registers require
+specific sized accesses. If no access size attribute is specified, GDB
+may use accesses of any size.
+
+`8'
+ Use 8 bit memory accesses.
+
+`16'
+ Use 16 bit memory accesses.
+
+`32'
+ Use 32 bit memory accesses.
+
+`64'
+ Use 64 bit memory accesses.
+
+Data Cache
+..........
+
+The data cache attributes set whether GDB will cache target memory.
+While this generally improves performance by reducing debug protocol
+overhead, it can lead to incorrect results because GDB does not know
+about volatile variables or memory mapped device registers.
+
+`cache'
+ Enable GDB to cache target memory.
+
+`nocache'
+ Disable GDB from caching target memory. This is the default.
+
+
+File: gdb.info, Node: Dump/Restore Files, Next: Character Sets, Prev: Memory Region Attributes, Up: Data
+
+Copy between memory and a file
+==============================
+
+You can use the commands `dump', `append', and `restore' to copy data
+between target memory and a file. The `dump' and `append' commands
+write data to a file, and the `restore' command reads data from a file
+back into the inferior's memory. Files may be in binary, Motorola
+S-record, Intel hex, or Tektronix Hex format; however, GDB can only
+append to binary files.
+
+`dump [FORMAT] memory FILENAME START_ADDR END_ADDR'
+`dump [FORMAT] value FILENAME EXPR'
+ Dump the contents of memory from START_ADDR to END_ADDR, or the
+ value of EXPR, to FILENAME in the given format.
+
+ The FORMAT parameter may be any one of:
+ `binary'
+ Raw binary form.
+
+ `ihex'
+ Intel hex format.
+
+ `srec'
+ Motorola S-record format.
+
+ `tekhex'
+ Tektronix Hex format.
+
+ GDB uses the same definitions of these formats as the GNU binary
+ utilities, like `objdump' and `objcopy'. If FORMAT is omitted,
+ GDB dumps the data in raw binary form.
+
+`append [binary] memory FILENAME START_ADDR END_ADDR'
+`append [binary] value FILENAME EXPR'
+ Append the contents of memory from START_ADDR to END_ADDR, or the
+ value of EXPR, to FILENAME, in raw binary form. (GDB can only
+ append data to files in raw binary form.)
+
+`restore FILENAME [binary] BIAS START END'
+ Restore the contents of file FILENAME into memory. The `restore'
+ command can automatically recognize any known BFD file format,
+ except for raw binary. To restore a raw binary file you must
+ specify the optional keyword `binary' after the filename.
+
+ If BIAS is non-zero, its value will be added to the addresses
+ contained in the file. Binary files always start at address zero,
+ so they will be restored at address BIAS. Other bfd files have a
+ built-in location; they will be restored at offset BIAS from that
+ location.
+
+ If START and/or END are non-zero, then only data between file
+ offset START and file offset END will be restored. These offsets
+ are relative to the addresses in the file, before the BIAS
+ argument is applied.
+
+
+
+File: gdb.info, Node: Character Sets, Prev: Dump/Restore Files, Up: Data
+
+Character Sets
+==============
+
+If the program you are debugging uses a different character set to
+represent characters and strings than the one GDB uses itself, GDB can
+automatically translate between the character sets for you. The
+character set GDB uses we call the "host character set"; the one the
+inferior program uses we call the "target character set".
+
+ For example, if you are running GDB on a GNU/Linux system, which
+uses the ISO Latin 1 character set, but you are using GDB's remote
+protocol (*note Remote Debugging: Remote.) to debug a program running
+on an IBM mainframe, which uses the EBCDIC character set, then the host
+character set is Latin-1, and the target character set is EBCDIC. If
+you give GDB the command `set target-charset EBCDIC-US', then GDB
+translates between EBCDIC and Latin 1 as you print character or string
+values, or use character and string literals in expressions.
+
+ GDB has no way to automatically recognize which character set the
+inferior program uses; you must tell it, using the `set target-charset'
+command, described below.
+
+ Here are the commands for controlling GDB's character set support:
+
+`set target-charset CHARSET'
+ Set the current target character set to CHARSET. We list the
+ character set names GDB recognizes below, but if you type `set
+ target-charset' followed by <TAB><TAB>, GDB will list the target
+ character sets it supports.
+
+`set host-charset CHARSET'
+ Set the current host character set to CHARSET.
+
+ By default, GDB uses a host character set appropriate to the
+ system it is running on; you can override that default using the
+ `set host-charset' command.
+
+ GDB can only use certain character sets as its host character set.
+ We list the character set names GDB recognizes below, and
+ indicate which can be host character sets, but if you type `set
+ target-charset' followed by <TAB><TAB>, GDB will list the host
+ character sets it supports.
+
+`set charset CHARSET'
+ Set the current host and target character sets to CHARSET. As
+ above, if you type `set charset' followed by <TAB><TAB>, GDB will
+ list the name of the character sets that can be used for both host
+ and target.
+
+`show charset'
+ Show the names of the current host and target charsets.
+
+`show host-charset'
+ Show the name of the current host charset.
+
+`show target-charset'
+ Show the name of the current target charset.
+
+
+ GDB currently includes support for the following character sets:
+
+`ASCII'
+ Seven-bit U.S. ASCII. GDB can use this as its host character set.
+
+`ISO-8859-1'
+ The ISO Latin 1 character set. This extends ASCII with accented
+ characters needed for French, German, and Spanish. GDB can use
+ this as its host character set.
+
+`EBCDIC-US'
+`IBM1047'
+ Variants of the EBCDIC character set, used on some of IBM's
+ mainframe operating systems. (GNU/Linux on the S/390 uses U.S.
+ ASCII.) GDB cannot use these as its host character set.
+
+
+ Note that these are all single-byte character sets. More work inside
+GDB is needed to support multi-byte or variable-width character
+encodings, like the UTF-8 and UCS-2 encodings of Unicode.
+
+ Here is an example of GDB's character set support in action. Assume
+that the following source code has been placed in the file
+`charset-test.c':
+
+ #include <stdio.h>
+
+ char ascii_hello[]
+ = {72, 101, 108, 108, 111, 44, 32, 119,
+ 111, 114, 108, 100, 33, 10, 0};
+ char ibm1047_hello[]
+ = {200, 133, 147, 147, 150, 107, 64, 166,
+ 150, 153, 147, 132, 90, 37, 0};
+
+ main ()
+ {
+ printf ("Hello, world!\n");
+ }
+
+ In this program, `ascii_hello' and `ibm1047_hello' are arrays
+containing the string `Hello, world!' followed by a newline, encoded in
+the ASCII and IBM1047 character sets.
+
+ We compile the program, and invoke the debugger on it:
+
+ $ gcc -g charset-test.c -o charset-test
+ $ gdb -nw charset-test
+ GNU gdb 2001-12-19-cvs
+ Copyright 2001 Free Software Foundation, Inc.
+ ...
+ (gdb)
+
+ We can use the `show charset' command to see what character sets GDB
+is currently using to interpret and display characters and strings:
+
+ (gdb) show charset
+ The current host and target character set is `ISO-8859-1'.
+ (gdb)
+
+ For the sake of printing this manual, let's use ASCII as our initial
+character set:
+ (gdb) set charset ASCII
+ (gdb) show charset
+ The current host and target character set is `ASCII'.
+ (gdb)
+
+ Let's assume that ASCII is indeed the correct character set for our
+host system -- in other words, let's assume that if GDB prints
+characters using the ASCII character set, our terminal will display
+them properly. Since our current target character set is also ASCII,
+the contents of `ascii_hello' print legibly:
+
+ (gdb) print ascii_hello
+ $1 = 0x401698 "Hello, world!\n"
+ (gdb) print ascii_hello[0]
+ $2 = 72 'H'
+ (gdb)
+
+ GDB uses the target character set for character and string literals
+you use in expressions:
+
+ (gdb) print '+'
+ $3 = 43 '+'
+ (gdb)
+
+ The ASCII character set uses the number 43 to encode the `+'
+character.
+
+ GDB relies on the user to tell it which character set the target
+program uses. If we print `ibm1047_hello' while our target character
+set is still ASCII, we get jibberish:
+
+ (gdb) print ibm1047_hello
+ $4 = 0x4016a8 "\310\205\223\223\226k@\246\226\231\223\204Z%"
+ (gdb) print ibm1047_hello[0]
+ $5 = 200 '\310'
+ (gdb)
+
+ If we invoke the `set target-charset' followed by <TAB><TAB>, GDB
+tells us the character sets it supports:
+
+ (gdb) set target-charset
+ ASCII EBCDIC-US IBM1047 ISO-8859-1
+ (gdb) set target-charset
+
+ We can select IBM1047 as our target character set, and examine the
+program's strings again. Now the ASCII string is wrong, but GDB
+translates the contents of `ibm1047_hello' from the target character
+set, IBM1047, to the host character set, ASCII, and they display
+correctly:
+
+ (gdb) set target-charset IBM1047
+ (gdb) show charset
+ The current host character set is `ASCII'.
+ The current target character set is `IBM1047'.
+ (gdb) print ascii_hello
+ $6 = 0x401698 "\110\145%%?\054\040\167?\162%\144\041\012"
+ (gdb) print ascii_hello[0]
+ $7 = 72 '\110'
+ (gdb) print ibm1047_hello
+ $8 = 0x4016a8 "Hello, world!\n"
+ (gdb) print ibm1047_hello[0]
+ $9 = 200 'H'
+ (gdb)
+
+ As above, GDB uses the target character set for character and string
+literals you use in expressions:
+
+ (gdb) print '+'
+ $10 = 78 '+'
+ (gdb)
+
+ The IBM1047 character set uses the number 78 to encode the `+'
+character.
+
+
+File: gdb.info, Node: Macros, Next: Tracepoints, Prev: Data, Up: Top
+
+C Preprocessor Macros
+*********************
+
+Some languages, such as C and C++, provide a way to define and invoke
+"preprocessor macros" which expand into strings of tokens. GDB can
+evaluate expressions containing macro invocations, show the result of
+macro expansion, and show a macro's definition, including where it was
+defined.
+
+ You may need to compile your program specially to provide GDB with
+information about preprocessor macros. Most compilers do not include
+macros in their debugging information, even when you compile with the
+`-g' flag. *Note Compilation::.
+
+ A program may define a macro at one point, remove that definition
+later, and then provide a different definition after that. Thus, at
+different points in the program, a macro may have different
+definitions, or have no definition at all. If there is a current stack
+frame, GDB uses the macros in scope at that frame's source code line.
+Otherwise, GDB uses the macros in scope at the current listing location;
+see *Note List::.
+
+ At the moment, GDB does not support the `##' token-splicing
+operator, the `#' stringification operator, or variable-arity macros.
+
+ Whenever GDB evaluates an expression, it always expands any macro
+invocations present in the expression. GDB also provides the following
+commands for working with macros explicitly.
+
+`macro expand EXPRESSION'
+`macro exp EXPRESSION'
+ Show the results of expanding all preprocessor macro invocations in
+ EXPRESSION. Since GDB simply expands macros, but does not parse
+ the result, EXPRESSION need not be a valid expression; it can be
+ any string of tokens.
+
+`macro expand-once EXPRESSION'
+`macro exp1 EXPRESSION'
+ (This command is not yet implemented.) Show the results of
+ expanding those preprocessor macro invocations that appear
+ explicitly in EXPRESSION. Macro invocations appearing in that
+ expansion are left unchanged. This command allows you to see the
+ effect of a particular macro more clearly, without being confused
+ by further expansions. Since GDB simply expands macros, but does
+ not parse the result, EXPRESSION need not be a valid expression; it
+ can be any string of tokens.
+
+`info macro MACRO'
+ Show the definition of the macro named MACRO, and describe the
+ source location where that definition was established.
+
+`macro define MACRO REPLACEMENT-LIST'
+`macro define MACRO(ARGLIST) REPLACEMENT-LIST'
+ (This command is not yet implemented.) Introduce a definition for
+ a preprocessor macro named MACRO, invocations of which are replaced
+ by the tokens given in REPLACEMENT-LIST. The first form of this
+ command defines an "object-like" macro, which takes no arguments;
+ the second form defines a "function-like" macro, which takes the
+ arguments given in ARGLIST.
+
+ A definition introduced by this command is in scope in every
+ expression evaluated in GDB, until it is removed with the `macro
+ undef' command, described below. The definition overrides all
+ definitions for MACRO present in the program being debugged, as
+ well as any previous user-supplied definition.
+
+`macro undef MACRO'
+ (This command is not yet implemented.) Remove any user-supplied
+ definition for the macro named MACRO. This command only affects
+ definitions provided with the `macro define' command, described
+ above; it cannot remove definitions present in the program being
+ debugged.
+
+
+ Here is a transcript showing the above commands in action. First, we
+show our source files:
+
+ $ cat sample.c
+ #include <stdio.h>
+ #include "sample.h"
+
+ #define M 42
+ #define ADD(x) (M + x)
+
+ main ()
+ {
+ #define N 28
+ printf ("Hello, world!\n");
+ #undef N
+ printf ("We're so creative.\n");
+ #define N 1729
+ printf ("Goodbye, world!\n");
+ }
+ $ cat sample.h
+ #define Q <
+ $
+
+ Now, we compile the program using the GNU C compiler, GCC. We pass
+the `-gdwarf-2' and `-g3' flags to ensure the compiler includes
+information about preprocessor macros in the debugging information.
+
+ $ gcc -gdwarf-2 -g3 sample.c -o sample
+ $
+
+ Now, we start GDB on our sample program:
+
+ $ gdb -nw sample
+ GNU gdb 2002-05-06-cvs
+ Copyright 2002 Free Software Foundation, Inc.
+ GDB is free software, ...
+ (gdb)
+
+ We can expand macros and examine their definitions, even when the
+program is not running. GDB uses the current listing position to
+decide which macro definitions are in scope:
+
+ (gdb) list main
+ 3
+ 4 #define M 42
+ 5 #define ADD(x) (M + x)
+ 6
+ 7 main ()
+ 8 {
+ 9 #define N 28
+ 10 printf ("Hello, world!\n");
+ 11 #undef N
+ 12 printf ("We're so creative.\n");
+ (gdb) info macro ADD
+ Defined at /home/jimb/gdb/macros/play/sample.c:5
+ #define ADD(x) (M + x)
+ (gdb) info macro Q
+ Defined at /home/jimb/gdb/macros/play/sample.h:1
+ included at /home/jimb/gdb/macros/play/sample.c:2
+ #define Q <
+ (gdb) macro expand ADD(1)
+ expands to: (42 + 1)
+ (gdb) macro expand-once ADD(1)
+ expands to: once (M + 1)
+ (gdb)
+
+ In the example above, note that `macro expand-once' expands only the
+macro invocation explicit in the original text -- the invocation of
+`ADD' -- but does not expand the invocation of the macro `M', which was
+introduced by `ADD'.
+
+ Once the program is running, GDB uses the macro definitions in force
+at the source line of the current stack frame:
+
+ (gdb) break main
+ Breakpoint 1 at 0x8048370: file sample.c, line 10.
+ (gdb) run
+ Starting program: /home/jimb/gdb/macros/play/sample
+
+ Breakpoint 1, main () at sample.c:10
+ 10 printf ("Hello, world!\n");
+ (gdb)
+
+ At line 10, the definition of the macro `N' at line 9 is in force:
+
+ (gdb) info macro N
+ Defined at /home/jimb/gdb/macros/play/sample.c:9
+ #define N 28
+ (gdb) macro expand N Q M
+ expands to: 28 < 42
+ (gdb) print N Q M
+ $1 = 1
+ (gdb)
+
+ As we step over directives that remove `N''s definition, and then
+give it a new definition, GDB finds the definition (or lack thereof) in
+force at each point:
+
+ (gdb) next
+ Hello, world!
+ 12 printf ("We're so creative.\n");
+ (gdb) info macro N
+ The symbol `N' has no definition as a C/C++ preprocessor macro
+ at /home/jimb/gdb/macros/play/sample.c:12
+ (gdb) next
+ We're so creative.
+ 14 printf ("Goodbye, world!\n");
+ (gdb) info macro N
+ Defined at /home/jimb/gdb/macros/play/sample.c:13
+ #define N 1729
+ (gdb) macro expand N Q M
+ expands to: 1729 < 42
+ (gdb) print N Q M
+ $2 = 0
+ (gdb)
+
+
+File: gdb.info, Node: Tracepoints, Next: Overlays, Prev: Macros, Up: Top
+
+Tracepoints
+***********
+
+In some applications, it is not feasible for the debugger to interrupt
+the program's execution long enough for the developer to learn anything
+helpful about its behavior. If the program's correctness depends on
+its real-time behavior, delays introduced by a debugger might cause the
+program to change its behavior drastically, or perhaps fail, even when
+the code itself is correct. It is useful to be able to observe the
+program's behavior without interrupting it.
+
+ Using GDB's `trace' and `collect' commands, you can specify
+locations in the program, called "tracepoints", and arbitrary
+expressions to evaluate when those tracepoints are reached. Later,
+using the `tfind' command, you can examine the values those expressions
+had when the program hit the tracepoints. The expressions may also
+denote objects in memory--structures or arrays, for example--whose
+values GDB should record; while visiting a particular tracepoint, you
+may inspect those objects as if they were in memory at that moment.
+However, because GDB records these values without interacting with you,
+it can do so quickly and unobtrusively, hopefully not disturbing the
+program's behavior.
+
+ The tracepoint facility is currently available only for remote
+targets. *Note Targets::. In addition, your remote target must know
+how to collect trace data. This functionality is implemented in the
+remote stub; however, none of the stubs distributed with GDB support
+tracepoints as of this writing.
+
+ This chapter describes the tracepoint commands and features.
+
+* Menu:
+
+* Set Tracepoints::
+* Analyze Collected Data::
+* Tracepoint Variables::
+
+
+File: gdb.info, Node: Set Tracepoints, Next: Analyze Collected Data, Up: Tracepoints
+
+Commands to Set Tracepoints
+===========================
+
+Before running such a "trace experiment", an arbitrary number of
+tracepoints can be set. Like a breakpoint (*note Set Breaks::), a
+tracepoint has a number assigned to it by GDB. Like with breakpoints,
+tracepoint numbers are successive integers starting from one. Many of
+the commands associated with tracepoints take the tracepoint number as
+their argument, to identify which tracepoint to work on.
+
+ For each tracepoint, you can specify, in advance, some arbitrary set
+of data that you want the target to collect in the trace buffer when it
+hits that tracepoint. The collected data can include registers, local
+variables, or global data. Later, you can use GDB commands to examine
+the values these data had at the time the tracepoint was hit.
+
+ This section describes commands to set tracepoints and associated
+conditions and actions.
+
+* Menu:
+
+* Create and Delete Tracepoints::
+* Enable and Disable Tracepoints::
+* Tracepoint Passcounts::
+* Tracepoint Actions::
+* Listing Tracepoints::
+* Starting and Stopping Trace Experiment::
+
+
+File: gdb.info, Node: Create and Delete Tracepoints, Next: Enable and Disable Tracepoints, Up: Set Tracepoints
+
+Create and Delete Tracepoints
+-----------------------------
+
+`trace'
+ The `trace' command is very similar to the `break' command. Its
+ argument can be a source line, a function name, or an address in
+ the target program. *Note Set Breaks::. The `trace' command
+ defines a tracepoint, which is a point in the target program where
+ the debugger will briefly stop, collect some data, and then allow
+ the program to continue. Setting a tracepoint or changing its
+ commands doesn't take effect until the next `tstart' command;
+ thus, you cannot change the tracepoint attributes once a trace
+ experiment is running.
+
+ Here are some examples of using the `trace' command:
+
+ (gdb) trace foo.c:121 // a source file and line number
+
+ (gdb) trace +2 // 2 lines forward
+
+ (gdb) trace my_function // first source line of function
+
+ (gdb) trace *my_function // EXACT start address of function
+
+ (gdb) trace *0x2117c4 // an address
+
+ You can abbreviate `trace' as `tr'.
+
+ The convenience variable `$tpnum' records the tracepoint number of
+ the most recently set tracepoint.
+
+`delete tracepoint [NUM]'
+ Permanently delete one or more tracepoints. With no argument, the
+ default is to delete all tracepoints.
+
+ Examples:
+
+ (gdb) delete trace 1 2 3 // remove three tracepoints
+
+ (gdb) delete trace // remove all tracepoints
+
+ You can abbreviate this command as `del tr'.
+
+
+File: gdb.info, Node: Enable and Disable Tracepoints, Next: Tracepoint Passcounts, Prev: Create and Delete Tracepoints, Up: Set Tracepoints
+
+Enable and Disable Tracepoints
+------------------------------
+
+`disable tracepoint [NUM]'
+ Disable tracepoint NUM, or all tracepoints if no argument NUM is
+ given. A disabled tracepoint will have no effect during the next
+ trace experiment, but it is not forgotten. You can re-enable a
+ disabled tracepoint using the `enable tracepoint' command.
+
+`enable tracepoint [NUM]'
+ Enable tracepoint NUM, or all tracepoints. The enabled
+ tracepoints will become effective the next time a trace experiment
+ is run.
+
+
+File: gdb.info, Node: Tracepoint Passcounts, Next: Tracepoint Actions, Prev: Enable and Disable Tracepoints, Up: Set Tracepoints
+
+Tracepoint Passcounts
+---------------------
+
+`passcount [N [NUM]]'
+ Set the "passcount" of a tracepoint. The passcount is a way to
+ automatically stop a trace experiment. If a tracepoint's
+ passcount is N, then the trace experiment will be automatically
+ stopped on the N'th time that tracepoint is hit. If the
+ tracepoint number NUM is not specified, the `passcount' command
+ sets the passcount of the most recently defined tracepoint. If no
+ passcount is given, the trace experiment will run until stopped
+ explicitly by the user.
+
+ Examples:
+
+ (gdb) passcount 5 2 // Stop on the 5th execution of
+ `// tracepoint 2'
+
+ (gdb) passcount 12 // Stop on the 12th execution of the
+ `// most recently defined tracepoint.'
+ (gdb) trace foo
+ (gdb) pass 3
+ (gdb) trace bar
+ (gdb) pass 2
+ (gdb) trace baz
+ (gdb) pass 1 // Stop tracing when foo has been
+ `// executed 3 times OR when bar has'
+ `// been executed 2 times'
+ `// OR when baz has been executed 1 time.'
+
+
+
+File: gdb.info, Node: Tracepoint Actions, Next: Listing Tracepoints, Prev: Tracepoint Passcounts, Up: Set Tracepoints
+
+Tracepoint Action Lists
+-----------------------
+
+`actions [NUM]'
+ This command will prompt for a list of actions to be taken when the
+ tracepoint is hit. If the tracepoint number NUM is not specified,
+ this command sets the actions for the one that was most recently
+ defined (so that you can define a tracepoint and then say
+ `actions' without bothering about its number). You specify the
+ actions themselves on the following lines, one action at a time,
+ and terminate the actions list with a line containing just `end'.
+ So far, the only defined actions are `collect' and
+ `while-stepping'.
+
+ To remove all actions from a tracepoint, type `actions NUM' and
+ follow it immediately with `end'.
+
+ (gdb) collect DATA // collect some data
+
+ (gdb) while-stepping 5 // single-step 5 times, collect data
+
+ (gdb) end // signals the end of actions.
+
+ In the following example, the action list begins with `collect'
+ commands indicating the things to be collected when the tracepoint
+ is hit. Then, in order to single-step and collect additional data
+ following the tracepoint, a `while-stepping' command is used,
+ followed by the list of things to be collected while stepping. The
+ `while-stepping' command is terminated by its own separate `end'
+ command. Lastly, the action list is terminated by an `end'
+ command.
+
+ (gdb) trace foo
+ (gdb) actions
+ Enter actions for tracepoint 1, one per line:
+ > collect bar,baz
+ > collect $regs
+ > while-stepping 12
+ > collect $fp, $sp
+ > end
+ end
+
+`collect EXPR1, EXPR2, ...'
+ Collect values of the given expressions when the tracepoint is hit.
+ This command accepts a comma-separated list of any valid
+ expressions. In addition to global, static, or local variables,
+ the following special arguments are supported:
+
+ `$regs'
+ collect all registers
+
+ `$args'
+ collect all function arguments
+
+ `$locals'
+ collect all local variables.
+
+ You can give several consecutive `collect' commands, each one with
+ a single argument, or one `collect' command with several arguments
+ separated by commas: the effect is the same.
+
+ The command `info scope' (*note info scope: Symbols.) is
+ particularly useful for figuring out what data to collect.
+
+`while-stepping N'
+ Perform N single-step traces after the tracepoint, collecting new
+ data at each step. The `while-stepping' command is followed by
+ the list of what to collect while stepping (followed by its own
+ `end' command):
+
+ > while-stepping 12
+ > collect $regs, myglobal
+ > end
+ >
+
+ You may abbreviate `while-stepping' as `ws' or `stepping'.
+
+
+File: gdb.info, Node: Listing Tracepoints, Next: Starting and Stopping Trace Experiment, Prev: Tracepoint Actions, Up: Set Tracepoints
+
+Listing Tracepoints
+-------------------
+
+`info tracepoints [NUM]'
+ Display information about the tracepoint NUM. If you don't specify
+ a tracepoint number, displays information about all the tracepoints
+ defined so far. For each tracepoint, the following information is
+ shown:
+
+ * its number
+
+ * whether it is enabled or disabled
+
+ * its address
+
+ * its passcount as given by the `passcount N' command
+
+ * its step count as given by the `while-stepping N' command
+
+ * where in the source files is the tracepoint set
+
+ * its action list as given by the `actions' command
+
+ (gdb) info trace
+ Num Enb Address PassC StepC What
+ 1 y 0x002117c4 0 0 <gdb_asm>
+ 2 y 0x0020dc64 0 0 in g_test at g_test.c:1375
+ 3 y 0x0020b1f4 0 0 in get_data at ../foo.c:41
+ (gdb)
+
+ This command can be abbreviated `info tp'.
+
+
+File: gdb.info, Node: Starting and Stopping Trace Experiment, Prev: Listing Tracepoints, Up: Set Tracepoints
+
+Starting and Stopping Trace Experiment
+--------------------------------------
+
+`tstart'
+ This command takes no arguments. It starts the trace experiment,
+ and begins collecting data. This has the side effect of
+ discarding all the data collected in the trace buffer during the
+ previous trace experiment.
+
+`tstop'
+ This command takes no arguments. It ends the trace experiment, and
+ stops collecting data.
+
+ *Note:* a trace experiment and data collection may stop
+ automatically if any tracepoint's passcount is reached (*note
+ Tracepoint Passcounts::), or if the trace buffer becomes full.
+
+`tstatus'
+ This command displays the status of the current trace data
+ collection.
+
+ Here is an example of the commands we described so far:
+
+ (gdb) trace gdb_c_test
+ (gdb) actions
+ Enter actions for tracepoint #1, one per line.
+ > collect $regs,$locals,$args
+ > while-stepping 11
+ > collect $regs
+ > end
+ > end
+ (gdb) tstart
+ [time passes ...]
+ (gdb) tstop
+
+
+File: gdb.info, Node: Analyze Collected Data, Next: Tracepoint Variables, Prev: Set Tracepoints, Up: Tracepoints
+
+Using the collected data
+========================
+
+After the tracepoint experiment ends, you use GDB commands for
+examining the trace data. The basic idea is that each tracepoint
+collects a trace "snapshot" every time it is hit and another snapshot
+every time it single-steps. All these snapshots are consecutively
+numbered from zero and go into a buffer, and you can examine them
+later. The way you examine them is to "focus" on a specific trace
+snapshot. When the remote stub is focused on a trace snapshot, it will
+respond to all GDB requests for memory and registers by reading from
+the buffer which belongs to that snapshot, rather than from _real_
+memory or registers of the program being debugged. This means that
+*all* GDB commands (`print', `info registers', `backtrace', etc.) will
+behave as if we were currently debugging the program state as it was
+when the tracepoint occurred. Any requests for data that are not in
+the buffer will fail.
+
+* Menu:
+
+* tfind:: How to select a trace snapshot
+* tdump:: How to display all data for a snapshot
+* save-tracepoints:: How to save tracepoints for a future run
+
+
+File: gdb.info, Node: tfind, Next: tdump, Up: Analyze Collected Data
+
+`tfind N'
+---------
+
+The basic command for selecting a trace snapshot from the buffer is
+`tfind N', which finds trace snapshot number N, counting from zero. If
+no argument N is given, the next snapshot is selected.
+
+ Here are the various forms of using the `tfind' command.
+
+`tfind start'
+ Find the first snapshot in the buffer. This is a synonym for
+ `tfind 0' (since 0 is the number of the first snapshot).
+
+`tfind none'
+ Stop debugging trace snapshots, resume _live_ debugging.
+
+`tfind end'
+ Same as `tfind none'.
+
+`tfind'
+ No argument means find the next trace snapshot.
+
+`tfind -'
+ Find the previous trace snapshot before the current one. This
+ permits retracing earlier steps.
+
+`tfind tracepoint NUM'
+ Find the next snapshot associated with tracepoint NUM. Search
+ proceeds forward from the last examined trace snapshot. If no
+ argument NUM is given, it means find the next snapshot collected
+ for the same tracepoint as the current snapshot.
+
+`tfind pc ADDR'
+ Find the next snapshot associated with the value ADDR of the
+ program counter. Search proceeds forward from the last examined
+ trace snapshot. If no argument ADDR is given, it means find the
+ next snapshot with the same value of PC as the current snapshot.
+
+`tfind outside ADDR1, ADDR2'
+ Find the next snapshot whose PC is outside the given range of
+ addresses.
+
+`tfind range ADDR1, ADDR2'
+ Find the next snapshot whose PC is between ADDR1 and ADDR2.
+
+`tfind line [FILE:]N'
+ Find the next snapshot associated with the source line N. If the
+ optional argument FILE is given, refer to line N in that source
+ file. Search proceeds forward from the last examined trace
+ snapshot. If no argument N is given, it means find the next line
+ other than the one currently being examined; thus saying `tfind
+ line' repeatedly can appear to have the same effect as stepping
+ from line to line in a _live_ debugging session.
+
+ The default arguments for the `tfind' commands are specifically
+designed to make it easy to scan through the trace buffer. For
+instance, `tfind' with no argument selects the next trace snapshot, and
+`tfind -' with no argument selects the previous trace snapshot. So, by
+giving one `tfind' command, and then simply hitting <RET> repeatedly
+you can examine all the trace snapshots in order. Or, by saying `tfind
+-' and then hitting <RET> repeatedly you can examine the snapshots in
+reverse order. The `tfind line' command with no argument selects the
+snapshot for the next source line executed. The `tfind pc' command with
+no argument selects the next snapshot with the same program counter
+(PC) as the current frame. The `tfind tracepoint' command with no
+argument selects the next trace snapshot collected by the same
+tracepoint as the current one.
+
+ In addition to letting you scan through the trace buffer manually,
+these commands make it easy to construct GDB scripts that scan through
+the trace buffer and print out whatever collected data you are
+interested in. Thus, if we want to examine the PC, FP, and SP
+registers from each trace frame in the buffer, we can say this:
+
+ (gdb) tfind start
+ (gdb) while ($trace_frame != -1)
+ > printf "Frame %d, PC = %08X, SP = %08X, FP = %08X\n", \
+ $trace_frame, $pc, $sp, $fp
+ > tfind
+ > end
+
+ Frame 0, PC = 0020DC64, SP = 0030BF3C, FP = 0030BF44
+ Frame 1, PC = 0020DC6C, SP = 0030BF38, FP = 0030BF44
+ Frame 2, PC = 0020DC70, SP = 0030BF34, FP = 0030BF44
+ Frame 3, PC = 0020DC74, SP = 0030BF30, FP = 0030BF44
+ Frame 4, PC = 0020DC78, SP = 0030BF2C, FP = 0030BF44
+ Frame 5, PC = 0020DC7C, SP = 0030BF28, FP = 0030BF44
+ Frame 6, PC = 0020DC80, SP = 0030BF24, FP = 0030BF44
+ Frame 7, PC = 0020DC84, SP = 0030BF20, FP = 0030BF44
+ Frame 8, PC = 0020DC88, SP = 0030BF1C, FP = 0030BF44
+ Frame 9, PC = 0020DC8E, SP = 0030BF18, FP = 0030BF44
+ Frame 10, PC = 00203F6C, SP = 0030BE3C, FP = 0030BF14
+
+ Or, if we want to examine the variable `X' at each source line in
+the buffer:
+
+ (gdb) tfind start
+ (gdb) while ($trace_frame != -1)
+ > printf "Frame %d, X == %d\n", $trace_frame, X
+ > tfind line
+ > end
+
+ Frame 0, X = 1
+ Frame 7, X = 2
+ Frame 13, X = 255
+
+
+File: gdb.info, Node: tdump, Next: save-tracepoints, Prev: tfind, Up: Analyze Collected Data
+
+`tdump'
+-------
+
+This command takes no arguments. It prints all the data collected at
+the current trace snapshot.
+
+ (gdb) trace 444
+ (gdb) actions
+ Enter actions for tracepoint #2, one per line:
+ > collect $regs, $locals, $args, gdb_long_test
+ > end
+
+ (gdb) tstart
+
+ (gdb) tfind line 444
+ #0 gdb_test (p1=0x11, p2=0x22, p3=0x33, p4=0x44, p5=0x55, p6=0x66)
+ at gdb_test.c:444
+ 444 printp( "%s: arguments = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", )
+
+ (gdb) tdump
+ Data collected at tracepoint 2, trace frame 1:
+ d0 0xc4aa0085 -995491707
+ d1 0x18 24
+ d2 0x80 128
+ d3 0x33 51
+ d4 0x71aea3d 119204413
+ d5 0x22 34
+ d6 0xe0 224
+ d7 0x380035 3670069
+ a0 0x19e24a 1696330
+ a1 0x3000668 50333288
+ a2 0x100 256
+ a3 0x322000 3284992
+ a4 0x3000698 50333336
+ a5 0x1ad3cc 1758156
+ fp 0x30bf3c 0x30bf3c
+ sp 0x30bf34 0x30bf34
+ ps 0x0 0
+ pc 0x20b2c8 0x20b2c8
+ fpcontrol 0x0 0
+ fpstatus 0x0 0
+ fpiaddr 0x0 0
+ p = 0x20e5b4 "gdb-test"
+ p1 = (void *) 0x11
+ p2 = (void *) 0x22
+ p3 = (void *) 0x33
+ p4 = (void *) 0x44
+ p5 = (void *) 0x55
+ p6 = (void *) 0x66
+ gdb_long_test = 17 '\021'
+
+ (gdb)
+
+
+File: gdb.info, Node: save-tracepoints, Prev: tdump, Up: Analyze Collected Data
+
+`save-tracepoints FILENAME'
+---------------------------
+
+This command saves all current tracepoint definitions together with
+their actions and passcounts, into a file `FILENAME' suitable for use
+in a later debugging session. To read the saved tracepoint
+definitions, use the `source' command (*note Command Files::).
+
+
+File: gdb.info, Node: Tracepoint Variables, Prev: Analyze Collected Data, Up: Tracepoints
+
+Convenience Variables for Tracepoints
+=====================================
+
+`(int) $trace_frame'
+ The current trace snapshot (a.k.a. "frame") number, or -1 if no
+ snapshot is selected.
+
+`(int) $tracepoint'
+ The tracepoint for the current trace snapshot.
+
+`(int) $trace_line'
+ The line number for the current trace snapshot.
+
+`(char []) $trace_file'
+ The source file for the current trace snapshot.
+
+`(char []) $trace_func'
+ The name of the function containing `$tracepoint'.
+
+ Note: `$trace_file' is not suitable for use in `printf', use
+`output' instead.
+
+ Here's a simple example of using these convenience variables for
+stepping through all the trace snapshots and printing some of their
+data.
+
+ (gdb) tfind start
+
+ (gdb) while $trace_frame != -1
+ > output $trace_file
+ > printf ", line %d (tracepoint #%d)\n", $trace_line, $tracepoint
+ > tfind
+ > end
+
+
+File: gdb.info, Node: Overlays, Next: Languages, Prev: Tracepoints, Up: Top
+
+Debugging Programs That Use Overlays
+************************************
+
+If your program is too large to fit completely in your target system's
+memory, you can sometimes use "overlays" to work around this problem.
+GDB provides some support for debugging programs that use overlays.
+
+* Menu:
+
+* How Overlays Work:: A general explanation of overlays.
+* Overlay Commands:: Managing overlays in GDB.
+* Automatic Overlay Debugging:: GDB can find out which overlays are
+ mapped by asking the inferior.
+* Overlay Sample Program:: A sample program using overlays.
+
+
+File: gdb.info, Node: How Overlays Work, Next: Overlay Commands, Up: Overlays
+
+How Overlays Work
+=================
+
+Suppose you have a computer whose instruction address space is only 64
+kilobytes long, but which has much more memory which can be accessed by
+other means: special instructions, segment registers, or memory
+management hardware, for example. Suppose further that you want to
+adapt a program which is larger than 64 kilobytes to run on this system.
+
+ One solution is to identify modules of your program which are
+relatively independent, and need not call each other directly; call
+these modules "overlays". Separate the overlays from the main program,
+and place their machine code in the larger memory. Place your main
+program in instruction memory, but leave at least enough space there to
+hold the largest overlay as well.
+
+ Now, to call a function located in an overlay, you must first copy
+that overlay's machine code from the large memory into the space set
+aside for it in the instruction memory, and then jump to its entry point
+there.
+
+ Data Instruction Larger
+ Address Space Address Space Address Space
+ +-----------+ +-----------+ +-----------+
+ | | | | | |
+ +-----------+ +-----------+ +-----------+<-- overlay 1
+ | program | | main | .----| overlay 1 | load address
+ | variables | | program | | +-----------+
+ | and heap | | | | | |
+ +-----------+ | | | +-----------+<-- overlay 2
+ | | +-----------+ | | | load address
+ +-----------+ | | | .-| overlay 2 |
+ | | | | | |
+ mapped --->+-----------+ | | +-----------+
+ address | | | | | |
+ | overlay | <-' | | |
+ | area | <---' +-----------+<-- overlay 3
+ | | <---. | | load address
+ +-----------+ `--| overlay 3 |
+ | | | |
+ +-----------+ | |
+ +-----------+
+ | |
+ +-----------+
+
+ A code overlay
+
+ The diagram (*note A code overlay::) shows a system with separate
+data and instruction address spaces. To map an overlay, the program
+copies its code from the larger address space to the instruction
+address space. Since the overlays shown here all use the same mapped
+address, only one may be mapped at a time. For a system with a single
+address space for data and instructions, the diagram would be similar,
+except that the program variables and heap would share an address space
+with the main program and the overlay area.
+
+ An overlay loaded into instruction memory and ready for use is
+called a "mapped" overlay; its "mapped address" is its address in the
+instruction memory. An overlay not present (or only partially present)
+in instruction memory is called "unmapped"; its "load address" is its
+address in the larger memory. The mapped address is also called the
+"virtual memory address", or "VMA"; the load address is also called the
+"load memory address", or "LMA".
+
+ Unfortunately, overlays are not a completely transparent way to
+adapt a program to limited instruction memory. They introduce a new
+set of global constraints you must keep in mind as you design your
+program:
+
+ * Before calling or returning to a function in an overlay, your
+ program must make sure that overlay is actually mapped.
+ Otherwise, the call or return will transfer control to the right
+ address, but in the wrong overlay, and your program will probably
+ crash.
+
+ * If the process of mapping an overlay is expensive on your system,
+ you will need to choose your overlays carefully to minimize their
+ effect on your program's performance.
+
+ * The executable file you load onto your system must contain each
+ overlay's instructions, appearing at the overlay's load address,
+ not its mapped address. However, each overlay's instructions must
+ be relocated and its symbols defined as if the overlay were at its
+ mapped address. You can use GNU linker scripts to specify
+ different load and relocation addresses for pieces of your
+ program; see *Note Overlay Description: (ld.info)Overlay
+ Description.
+
+ * The procedure for loading executable files onto your system must
+ be able to load their contents into the larger address space as
+ well as the instruction and data spaces.
+
+
+ The overlay system described above is rather simple, and could be
+improved in many ways:
+
+ * If your system has suitable bank switch registers or memory
+ management hardware, you could use those facilities to make an
+ overlay's load area contents simply appear at their mapped address
+ in instruction space. This would probably be faster than copying
+ the overlay to its mapped area in the usual way.
+
+ * If your overlays are small enough, you could set aside more than
+ one overlay area, and have more than one overlay mapped at a time.
+
+ * You can use overlays to manage data, as well as instructions. In
+ general, data overlays are even less transparent to your design
+ than code overlays: whereas code overlays only require care when
+ you call or return to functions, data overlays require care every
+ time you access the data. Also, if you change the contents of a
+ data overlay, you must copy its contents back out to its load
+ address before you can copy a different data overlay into the same
+ mapped area.
+
+
+
+File: gdb.info, Node: Overlay Commands, Next: Automatic Overlay Debugging, Prev: How Overlays Work, Up: Overlays
+
+Overlay Commands
+================
+
+To use GDB's overlay support, each overlay in your program must
+correspond to a separate section of the executable file. The section's
+virtual memory address and load memory address must be the overlay's
+mapped and load addresses. Identifying overlays with sections allows
+GDB to determine the appropriate address of a function or variable,
+depending on whether the overlay is mapped or not.
+
+ GDB's overlay commands all start with the word `overlay'; you can
+abbreviate this as `ov' or `ovly'. The commands are:
+
+`overlay off'
+ Disable GDB's overlay support. When overlay support is disabled,
+ GDB assumes that all functions and variables are always present at
+ their mapped addresses. By default, GDB's overlay support is
+ disabled.
+
+`overlay manual'
+ Enable "manual" overlay debugging. In this mode, GDB relies on
+ you to tell it which overlays are mapped, and which are not, using
+ the `overlay map-overlay' and `overlay unmap-overlay' commands
+ described below.
+
+`overlay map-overlay OVERLAY'
+`overlay map OVERLAY'
+ Tell GDB that OVERLAY is now mapped; OVERLAY must be the name of
+ the object file section containing the overlay. When an overlay
+ is mapped, GDB assumes it can find the overlay's functions and
+ variables at their mapped addresses. GDB assumes that any other
+ overlays whose mapped ranges overlap that of OVERLAY are now
+ unmapped.
+
+`overlay unmap-overlay OVERLAY'
+`overlay unmap OVERLAY'
+ Tell GDB that OVERLAY is no longer mapped; OVERLAY must be the
+ name of the object file section containing the overlay. When an
+ overlay is unmapped, GDB assumes it can find the overlay's
+ functions and variables at their load addresses.
+
+`overlay auto'
+ Enable "automatic" overlay debugging. In this mode, GDB consults
+ a data structure the overlay manager maintains in the inferior to
+ see which overlays are mapped. For details, see *Note Automatic
+ Overlay Debugging::.
+
+`overlay load-target'
+`overlay load'
+ Re-read the overlay table from the inferior. Normally, GDB
+ re-reads the table GDB automatically each time the inferior stops,
+ so this command should only be necessary if you have changed the
+ overlay mapping yourself using GDB. This command is only useful
+ when using automatic overlay debugging.
+
+`overlay list-overlays'
+`overlay list'
+ Display a list of the overlays currently mapped, along with their
+ mapped addresses, load addresses, and sizes.
+
+
+ Normally, when GDB prints a code address, it includes the name of
+the function the address falls in:
+
+ (gdb) print main
+ $3 = {int ()} 0x11a0 <main>
+
+When overlay debugging is enabled, GDB recognizes code in unmapped
+overlays, and prints the names of unmapped functions with asterisks
+around them. For example, if `foo' is a function in an unmapped
+overlay, GDB prints it this way:
+
+ (gdb) overlay list
+ No sections are mapped.
+ (gdb) print foo
+ $5 = {int (int)} 0x100000 <*foo*>
+
+When `foo''s overlay is mapped, GDB prints the function's name normally:
+
+ (gdb) overlay list
+ Section .ov.foo.text, loaded at 0x100000 - 0x100034,
+ mapped at 0x1016 - 0x104a
+ (gdb) print foo
+ $6 = {int (int)} 0x1016 <foo>
+
+ When overlay debugging is enabled, GDB can find the correct address
+for functions and variables in an overlay, whether or not the overlay
+is mapped. This allows most GDB commands, like `break' and
+`disassemble', to work normally, even on unmapped code. However, GDB's
+breakpoint support has some limitations:
+
+ * You can set breakpoints in functions in unmapped overlays, as long
+ as GDB can write to the overlay at its load address.
+
+ * GDB can not set hardware or simulator-based breakpoints in
+ unmapped overlays. However, if you set a breakpoint at the end of
+ your overlay manager (and tell GDB which overlays are now mapped,
+ if you are using manual overlay management), GDB will re-set its
+ breakpoints properly.
+
+
+File: gdb.info, Node: Automatic Overlay Debugging, Next: Overlay Sample Program, Prev: Overlay Commands, Up: Overlays
+
+Automatic Overlay Debugging
+===========================
+
+GDB can automatically track which overlays are mapped and which are
+not, given some simple co-operation from the overlay manager in the
+inferior. If you enable automatic overlay debugging with the `overlay
+auto' command (*note Overlay Commands::), GDB looks in the inferior's
+memory for certain variables describing the current state of the
+overlays.
+
+ Here are the variables your overlay manager must define to support
+GDB's automatic overlay debugging:
+
+`_ovly_table':
+ This variable must be an array of the following structures:
+
+ struct
+ {
+ /* The overlay's mapped address. */
+ unsigned long vma;
+
+ /* The size of the overlay, in bytes. */
+ unsigned long size;
+
+ /* The overlay's load address. */
+ unsigned long lma;
+
+ /* Non-zero if the overlay is currently mapped;
+ zero otherwise. */
+ unsigned long mapped;
+ }
+
+`_novlys':
+ This variable must be a four-byte signed integer, holding the total
+ number of elements in `_ovly_table'.
+
+
+ To decide whether a particular overlay is mapped or not, GDB looks
+for an entry in `_ovly_table' whose `vma' and `lma' members equal the
+VMA and LMA of the overlay's section in the executable file. When GDB
+finds a matching entry, it consults the entry's `mapped' member to
+determine whether the overlay is currently mapped.
+
+ In addition, your overlay manager may define a function called
+`_ovly_debug_event'. If this function is defined, GDB will silently
+set a breakpoint there. If the overlay manager then calls this
+function whenever it has changed the overlay table, this will enable
+GDB to accurately keep track of which overlays are in program memory,
+and update any breakpoints that may be set in overlays. This will
+allow breakpoints to work even if the overlays are kept in ROM or other
+non-writable memory while they are not being executed.
+
+
+File: gdb.info, Node: Overlay Sample Program, Prev: Automatic Overlay Debugging, Up: Overlays
+
+Overlay Sample Program
+======================
+
+When linking a program which uses overlays, you must place the overlays
+at their load addresses, while relocating them to run at their mapped
+addresses. To do this, you must write a linker script (*note Overlay
+Description: (ld.info)Overlay Description.). Unfortunately, since
+linker scripts are specific to a particular host system, target
+architecture, and target memory layout, this manual cannot provide
+portable sample code demonstrating GDB's overlay support.
+
+ However, the GDB source distribution does contain an overlaid
+program, with linker scripts for a few systems, as part of its test
+suite. The program consists of the following files from
+`gdb/testsuite/gdb.base':
+
+`overlays.c'
+ The main program file.
+
+`ovlymgr.c'
+ A simple overlay manager, used by `overlays.c'.
+
+`foo.c'
+`bar.c'
+`baz.c'
+`grbx.c'
+ Overlay modules, loaded and used by `overlays.c'.
+
+`d10v.ld'
+`m32r.ld'
+ Linker scripts for linking the test program on the `d10v-elf' and
+ `m32r-elf' targets.
+
+ You can build the test program using the `d10v-elf' GCC
+cross-compiler like this:
+
+ $ d10v-elf-gcc -g -c overlays.c
+ $ d10v-elf-gcc -g -c ovlymgr.c
+ $ d10v-elf-gcc -g -c foo.c
+ $ d10v-elf-gcc -g -c bar.c
+ $ d10v-elf-gcc -g -c baz.c
+ $ d10v-elf-gcc -g -c grbx.c
+ $ d10v-elf-gcc -g overlays.o ovlymgr.o foo.o bar.o \
+ baz.o grbx.o -Wl,-Td10v.ld -o overlays
+
+ The build process is identical for any other architecture, except
+that you must substitute the appropriate compiler and linker script for
+the target system for `d10v-elf-gcc' and `d10v.ld'.
+
+
+File: gdb.info, Node: Languages, Next: Symbols, Prev: Overlays, Up: Top
+
+Using GDB with Different Languages
+**********************************
+
+Although programming languages generally have common aspects, they are
+rarely expressed in the same manner. For instance, in ANSI C,
+dereferencing a pointer `p' is accomplished by `*p', but in Modula-2,
+it is accomplished by `p^'. Values can also be represented (and
+displayed) differently. Hex numbers in C appear as `0x1ae', while in
+Modula-2 they appear as `1AEH'.
+
+ Language-specific information is built into GDB for some languages,
+allowing you to express operations like the above in your program's
+native language, and allowing GDB 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 "working language".
+
+* Menu:
+
+* Setting:: Switching between source languages
+* Show:: Displaying the language
+* Checks:: Type and range checks
+* Support:: Supported languages
+* Unsupported languages:: Unsupported languages
+
+
+File: gdb.info, Node: Setting, Next: Show, Up: Languages
+
+Switching between source languages
+==================================
+
+There are two ways to control the working language--either have GDB set
+it automatically, or select it manually yourself. You can use the `set
+language' command for either purpose. On startup, GDB 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 GDB
+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 GDB infers the language from the
+name of the file. The language of a source file controls whether C++
+names are demangled--this way `backtrace' can show each frame
+appropriately for its own language. There is no way to set the
+language of a source file from within GDB, but you can set the language
+associated with a filename extension. *Note Displaying the language:
+Show.
+
+ This is most commonly a problem when you use a program, such as
+`cfront' or `f2c', that generates C but is written in another language.
+In that case, make the program use `#line' directives in its C output;
+that way GDB 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 GDB infer the source language
+
+
+File: gdb.info, Node: Filenames, Next: Manually, Up: Setting
+
+List of filename extensions and languages
+-----------------------------------------
+
+If a source file name ends in one of the following extensions, then GDB
+infers that its language is the one indicated.
+
+`.c'
+ C source file
+
+`.C'
+`.cc'
+`.cp'
+`.cpp'
+`.cxx'
+`.c++'
+ C++ source file
+
+`.m'
+ Objective-C source file
+
+`.f'
+`.F'
+ Fortran source file
+
+`.mod'
+ Modula-2 source file
+
+`.s'
+`.S'
+ Assembler source file. This actually behaves almost like C, but
+ GDB does not skip over function prologues when stepping.
+
+ In addition, you may set the language associated with a filename
+extension. *Note Displaying the language: Show.
+
+
+File: gdb.info, Node: Manually, Next: Automatically, Prev: Filenames, Up: Setting
+
+Setting the working language
+----------------------------
+
+If you allow GDB to set the language automatically, expressions are
+interpreted the same way in your debugging session and your program.
+
+ If you wish, you may set the language manually. To do this, issue
+the command `set language LANG', where LANG is the name of a language,
+such as `c' or `modula-2'. For a list of the supported languages, type
+`set language'.
+
+ Setting the language manually prevents GDB 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 GDB was parsing Modula-2, a command such as:
+
+ print a = b + c
+
+might not have the effect you intended. In C, this means to add `b'
+and `c' and place the result in `a'. The result printed would be the
+value of `a'. In Modula-2, this means to compare `a' to the result of
+`b+c', yielding a `BOOLEAN' value.
+
+
+File: gdb.info, Node: Automatically, Prev: Manually, Up: Setting
+
+Having GDB infer the source language
+------------------------------------
+
+To have GDB set the working language automatically, use `set language
+local' or `set language auto'. GDB then infers the working language.
+That is, when your program stops in a frame (usually by encountering a
+breakpoint), GDB 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 GDB 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 `set language auto' in this case
+frees you from having to set the working language manually.
+
+
+File: gdb.info, Node: Show, Next: Checks, Prev: Setting, Up: Languages
+
+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.
+
+`show language'
+ Display the current working language. This is the language you
+ can use with commands such as `print' to build and compute
+ expressions that may involve variables in your program.
+
+`info frame'
+ Display the source language for this frame. This language becomes
+ the working language if you use an identifier from this frame.
+ *Note Information about a frame: Frame Info, to identify the other
+ information listed here.
+
+`info source'
+ Display the source language of this source file. *Note Examining
+ the Symbol Table: Symbols, to identify the other information
+ listed here.
+
+ In unusual circumstances, you may have source files with extensions
+not in the standard list. You can then set the extension associated
+with a language explicitly:
+
+`set extension-language .EXT LANGUAGE'
+ Set source files with extension .EXT to be assumed to be in the
+ source language LANGUAGE.
+
+`info extensions'
+ List all the filename extensions and the associated languages.
+
+
+File: gdb.info, Node: Checks, Next: Support, Prev: Show, Up: Languages
+
+Type and range checking
+=======================
+
+ _Warning:_ In this release, the GDB commands for type and range
+ checking are included, but they do not yet have any effect. This
+ section documents the intended facilities.
+
+ 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.
+
+ GDB can check for conditions like the above if you wish. Although
+GDB does not check the statements in your program, it can check
+expressions entered directly into GDB for evaluation via the `print'
+command, for example. As with the working language, GDB can also
+decide whether or not to check automatically based on your program's
+source language. *Note Supported languages: Support, for the default
+settings of supported languages.
+
+* Menu:
+
+* Type Checking:: An overview of type checking
+* Range Checking:: An overview of range checking
+
+
+File: gdb.info, Node: Type Checking, Next: Range Checking, Up: Checks
+
+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,
+
+ 1 + 2 => 3
+but
+ error--> 1 + 2.3
+
+ The second example fails because the `CARDINAL' 1 is not
+type-compatible with the `REAL' 2.3.
+
+ For the expressions you use in GDB commands, you can tell the GDB
+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, GDB 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 GDB from evaluating an expression. For
+instance, GDB does not know how to add an `int' and a `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. *Note Supported languages: Support, for further details on
+specific languages.
+
+ GDB provides some additional commands for controlling the type
+checker:
+
+`set check type auto'
+ Set type checking on or off based on the current working language.
+ *Note Supported languages: Support, for the default settings for
+ each language.
+
+`set check type on'
+`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 type checking is on, GDB prints a
+ message and aborts evaluation of the expression.
+
+`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, GDB cannot add numbers
+ and structures.
+
+`show type'
+ Show the current setting of the type checker, and whether or not
+ GDB is setting it automatically.
+
+
+File: gdb.info, Node: Range Checking, Prev: Type Checking, Up: Checks
+
+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 GDB commands, you can tell GDB 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 M is the largest
+integer value, and S is the smallest, then
+
+ M + 1 => S
+
+ This, too, is specific to individual languages, and in some cases
+specific to individual compilers or machines. *Note Supported
+languages: Support, for further details on specific languages.
+
+ GDB provides some additional commands for controlling the range
+checker:
+
+`set check range auto'
+ Set range checking on or off based on the current working language.
+ *Note Supported languages: Support, for the default settings for
+ each language.
+
+`set check range on'
+`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 and
+ range checking is on, then a message is printed and evaluation of
+ the expression is aborted.
+
+`set check range warn'
+ Output messages when the GDB 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).
+
+`show range'
+ Show the current setting of the range checker, and whether or not
+ it is being set automatically by GDB.
+
+
+File: gdb.info, Node: Support, Next: Unsupported languages, Prev: Checks, Up: Languages
+
+Supported languages
+===================
+
+GDB supports C, C++, Objective-C, Fortran, Java, assembly, and Modula-2.
+Some GDB features may be used in expressions regardless of the language
+you use: the GDB `@' and `::' operators, and the `{type}addr' construct
+(*note 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 GDB. These sections are not meant to be language
+tutorials or references, but serve only as a reference guide to what the
+GDB 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.
+
+* Menu:
+
+* C:: C and C++
+* Objective-C:: Objective-C
+* Modula-2:: Modula-2
+
+
+File: gdb.info, Node: C, Next: Objective-C, Up: Support
+
+C and C++
+---------
+
+Since C and C++ are so closely related, many features of GDB apply to
+both languages. Whenever this is the case, we discuss those languages
+together.
+
+ The C++ debugging facilities are jointly implemented by the C++
+compiler and GDB. Therefore, to debug your C++ code effectively, you
+must compile your C++ programs with a supported C++ compiler, such as
+GNU `g++', or the HP ANSI C++ compiler (`aCC').
+
+ For best results when using GNU C++, use the DWARF 2 debugging
+format; if it doesn't work on your system, try the stabs+ debugging
+format. You can select those formats explicitly with the `g++'
+command-line options `-gdwarf-2' and `-gstabs+'. *Note Options for
+Debugging Your Program or GNU CC: (gcc.info)Debugging Options.
+
+* Menu:
+
+* C Operators:: C and C++ operators
+* C Constants:: C and C++ constants
+* C plus plus expressions:: C++ expressions
+* C Defaults:: Default settings for C and C++
+* C Checks:: C and C++ type and range checks
+* Debugging C:: GDB and C
+* Debugging C plus plus:: GDB features for C++
+
+
+File: gdb.info, Node: C Operators, Next: C Constants, Up: C
+
+C and C++ operators
+...................
+
+Operators must be defined on values of specific types. For instance,
+`+' is defined on numbers, but not on structures. Operators are often
+defined on groups of types.
+
+ For the purposes of C and C++, the following definitions hold:
+
+ * _Integral types_ include `int' with any of its storage-class
+ specifiers; `char'; `enum'; and, for C++, `bool'.
+
+ * _Floating-point types_ include `float', `double', and `long
+ double' (if supported by the target platform).
+
+ * _Pointer types_ include all types defined as `(TYPE *)'.
+
+ * _Scalar types_ include all of the above.
+
+
+The following operators are supported. They are listed here in order
+of increasing precedence:
+
+`,'
+ 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.
+
+`='
+ Assignment. The value of an assignment expression is the value
+ assigned. Defined on scalar types.
+
+`OP='
+ Used in an expression of the form `A OP= B', and translated to
+ `A = A OP B'. `OP=' and `=' have the same precedence. OP is any
+ one of the operators `|', `^', `&', `<<', `>>', `+', `-', `*',
+ `/', `%'.
+
+`?:'
+ The ternary operator. `A ? B : C' can be thought of as: if A
+ then B else C. A should be of an integral type.
+
+`||'
+ Logical OR. Defined on integral types.
+
+`&&'
+ Logical AND. Defined on integral types.
+
+`|'
+ Bitwise OR. Defined on integral types.
+
+`^'
+ Bitwise exclusive-OR. Defined on integral types.
+
+`&'
+ Bitwise AND. Defined on integral types.
+
+`==, !='
+ Equality and inequality. Defined on scalar types. The value of
+ these expressions is 0 for false and non-zero for true.
+
+`<, >, <=, >='
+ 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.
+
+`<<, >>'
+ left shift, and right shift. Defined on integral types.
+
+`@'
+ The GDB "artificial array" operator (*note Expressions:
+ Expressions.).
+
+`+, -'
+ Addition and subtraction. Defined on integral types,
+ floating-point types and pointer types.
+
+`*, /, %'
+ Multiplication, division, and modulus. Multiplication and
+ division are defined on integral and floating-point types.
+ Modulus is defined on integral types.
+
+`++, --'
+ 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.
+
+`*'
+ Pointer dereferencing. Defined on pointer types. Same precedence
+ as `++'.
+
+`&'
+ Address operator. Defined on variables. Same precedence as `++'.
+
+ For debugging C++, GDB implements a use of `&' beyond what is
+ allowed in the C++ language itself: you can use `&(&REF)' (or, if
+ you prefer, simply `&&REF') to examine the address where a C++
+ reference variable (declared with `&REF') is stored.
+
+`-'
+ Negative. Defined on integral and floating-point types. Same
+ precedence as `++'.
+
+`!'
+ Logical negation. Defined on integral types. Same precedence as
+ `++'.
+
+`~'
+ Bitwise complement operator. Defined on integral types. Same
+ precedence as `++'.
+
+`., ->'
+ Structure member, and pointer-to-structure member. For
+ convenience, GDB regards the two as equivalent, choosing whether
+ to dereference a pointer based on the stored type information.
+ Defined on `struct' and `union' data.
+
+`.*, ->*'
+ Dereferences of pointers to members.
+
+`[]'
+ Array indexing. `A[I]' is defined as `*(A+I)'. Same precedence
+ as `->'.
+
+`()'
+ Function parameter list. Same precedence as `->'.
+
+`::'
+ C++ scope resolution operator. Defined on `struct', `union', and
+ `class' types.
+
+`::'
+ Doubled colons also represent the GDB scope operator (*note
+ Expressions: Expressions.). Same precedence as `::', above.
+
+ If an operator is redefined in the user code, GDB usually attempts
+to invoke the redefined version instead of using the operator's
+predefined meaning.
+
+* Menu:
+
+* C Constants::
+
+
+File: gdb.info, Node: C Constants, Next: C plus plus expressions, Prev: C Operators, Up: C
+
+C and C++ constants
+...................
+
+GDB allows you to express the constants of C and C++ in the following
+ways:
+
+ * Integer constants are a sequence of digits. Octal constants are
+ specified by a leading `0' (i.e. zero), and hexadecimal constants
+ by a leading `0x' or `0X'. Constants may also end with a letter
+ `l', specifying that the constant should be treated as a `long'
+ value.
+
+ * 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:
+ `e[[+]|-]NNN', where NNN is another sequence of digits. The `+'
+ is optional for positive exponents. A floating-point constant may
+ also end with a letter `f' or `F', specifying that the constant
+ should be treated as being of the `float' (as opposed to the
+ default `double') type; or with a letter `l' or `L', which
+ specifies a `long double' constant.
+
+ * Enumerated constants consist of enumerated identifiers, or their
+ integral equivalents.
+
+ * Character constants are a single character surrounded by single
+ quotes (`''), or a number--the ordinal value of the corresponding
+ character (usually its ASCII value). Within quotes, the single
+ character may be represented by a letter or by "escape sequences",
+ which are of the form `\NNN', where NNN is the octal representation
+ of the character's ordinal value; or of the form `\X', where `X'
+ is a predefined special character--for example, `\n' for newline.
+
+ * String constants are a sequence of character constants surrounded
+ by double quotes (`"'). Any valid character constant (as described
+ above) may appear. Double quotes within the string must be
+ preceded by a backslash, so for instance `"a\"b'c"' is a string of
+ five characters.
+
+ * Pointer constants are an integral value. You can also write
+ pointers to constants using the C operator `&'.
+
+ * Array constants are comma-separated lists surrounded by braces `{'
+ and `}'; for example, `{1,2,3}' is a three-element array of
+ integers, `{{1,2}, {3,4}, {5,6}}' is a three-by-two array, and
+ `{&"hi", &"there", &"fred"}' is a three-element array of pointers.
+
+* Menu:
+
+* C plus plus expressions::
+* C Defaults::
+* C Checks::
+
+* Debugging C::
+
+
+File: gdb.info, Node: C plus plus expressions, Next: C Defaults, Prev: C Constants, Up: C
+
+C++ expressions
+...............
+
+GDB expression handling can interpret most C++ expressions.
+
+ _Warning:_ GDB can only debug C++ code if you use the proper
+ compiler and the proper debug format. Currently, GDB works best
+ when debugging C++ code that is compiled with GCC 2.95.3 or with
+ GCC 3.1 or newer, using the options `-gdwarf-2' or `-gstabs+'.
+ DWARF 2 is preferred over stabs+. Most configurations of GCC emit
+ either DWARF 2 or stabs+ as their default debug format, so you
+ usually don't need to specify a debug format explicitly. Other
+ compilers and/or debug formats are likely to work badly or not at
+ all when using GDB to debug C++ code.
+
+ 1. Member function calls are allowed; you can use expressions like
+
+ count = aml->GetOriginal(x, y)
+
+ 2. While a member function is active (in the selected stack frame),
+ your expressions have the same namespace available as the member
+ function; that is, GDB allows implicit references to the class
+ instance pointer `this' following the same rules as C++.
+
+ 3. You can call overloaded functions; GDB resolves the function call
+ to the right definition, with some restrictions. GDB does not
+ perform overload resolution involving user-defined type
+ conversions, calls to constructors, or instantiations of templates
+ that do not exist in the program. It also cannot handle ellipsis
+ argument lists or default arguments.
+
+ It does perform integral conversions and promotions, floating-point
+ promotions, arithmetic conversions, pointer conversions,
+ conversions of class objects to base classes, and standard
+ conversions such as those of functions or arrays to pointers; it
+ requires an exact match on the number of function arguments.
+
+ Overload resolution is always performed, unless you have specified
+ `set overload-resolution off'. *Note GDB features for C++:
+ Debugging C plus plus.
+
+ You must specify `set overload-resolution off' in order to use an
+ explicit function signature to call an overloaded function, as in
+ p 'foo(char,int)'('x', 13)
+
+ The GDB command-completion facility can simplify this; see *Note
+ Command completion: Completion.
+
+ 4. GDB 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 GDB 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 _address_ of a reference variable is always
+ shown, unless you have specified `set print address off'.
+
+ 5. GDB supports the C++ name resolution operator `::'--your
+ expressions can use it just as expressions in your program do.
+ Since one scope may be defined in another, you can use `::'
+ repeatedly if necessary, for example in an expression like
+ `SCOPE1::SCOPE2::NAME'. GDB also allows resolving name scope by
+ reference to source files, in both C and C++ debugging (*note
+ Program variables: Variables.).
+
+ In addition, when used with HP's C++ compiler, GDB supports calling
+virtual functions correctly, printing out virtual bases of objects,
+calling functions in a base subobject, casting objects, and invoking
+user-defined operators.
+
+
+File: gdb.info, Node: C Defaults, Next: C Checks, Prev: C plus plus expressions, Up: C
+
+C and C++ defaults
+..................
+
+If you allow GDB to set type and range checking automatically, they
+both default to `off' whenever the working language changes to C or
+C++. This happens regardless of whether you or GDB selects the working
+language.
+
+ If you allow GDB to set the language automatically, it recognizes
+source files whose names end with `.c', `.C', or `.cc', etc, and when
+GDB enters code compiled from one of these files, it sets the working
+language to C or C++. *Note Having GDB infer the source language:
+Automatically, for further details.
+
+
+File: gdb.info, Node: C Checks, Next: Debugging C, Prev: C Defaults, Up: C
+
+C and C++ type and range checks
+...............................
+
+By default, when GDB parses C or C++ expressions, type checking is not
+used. However, if you turn type checking on, GDB considers two
+variables type equivalent if:
+
+ * The two variables are structured and have the same structure,
+ union, or enumerated tag.
+
+ * The two variables have the same type name, or types that have been
+ declared equivalent through `typedef'.
+
+
+ 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.
+
+
+File: gdb.info, Node: Debugging C, Next: Debugging C plus plus, Prev: C Checks, Up: C
+
+GDB and C
+.........
+
+The `set print union' and `show print union' commands apply to the
+`union' type. When set to `on', any `union' that is inside a `struct'
+or `class' is also printed. Otherwise, it appears as `{...}'.
+
+ The `@' operator aids in the debugging of dynamic arrays, formed
+with pointers and a memory allocation function. *Note Expressions:
+Expressions.
+
+* Menu:
+
+* Debugging C plus plus::
+
+
+File: gdb.info, Node: Debugging C plus plus, Prev: Debugging C, Up: C
+
+GDB features for C++
+....................
+
+Some GDB commands are particularly useful with C++, and some are
+designed specifically for use with C++. Here is a summary:
+
+`breakpoint menus'
+ When you want a breakpoint in a function whose name is overloaded,
+ GDB breakpoint menus help you specify which function definition
+ you want. *Note Breakpoint menus: Breakpoint Menus.
+
+`rbreak REGEX'
+ Setting breakpoints using regular expressions is helpful for
+ setting breakpoints on overloaded functions that are not members
+ of any special classes. *Note Setting breakpoints: Set Breaks.
+
+`catch throw'
+`catch catch'
+ Debug C++ exception handling using these commands. *Note Setting
+ catchpoints: Set Catchpoints.
+
+`ptype TYPENAME'
+ Print inheritance relationships as well as other information for
+ type TYPENAME. *Note Examining the Symbol Table: Symbols.
+
+`set print demangle'
+`show print demangle'
+`set print asm-demangle'
+`show print asm-demangle'
+ Control whether C++ symbols display in their source form, both when
+ displaying code as C++ source and when displaying disassemblies.
+ *Note Print settings: Print Settings.
+
+`set print object'
+`show print object'
+ Choose whether to print derived (actual) or declared types of
+ objects. *Note Print settings: Print Settings.
+
+`set print vtbl'
+`show print vtbl'
+ Control the format for printing virtual function tables. *Note
+ Print settings: Print Settings. (The `vtbl' commands do not work
+ on programs compiled with the HP ANSI C++ compiler (`aCC').)
+
+`set overload-resolution on'
+ Enable overload resolution for C++ expression evaluation. The
+ default is on. For overloaded functions, GDB evaluates the
+ arguments and searches for a function whose signature matches the
+ argument types, using the standard C++ conversion rules (see *Note
+ C++ expressions: C plus plus expressions, for details). If it
+ cannot find a match, it emits a message.
+
+`set overload-resolution off'
+ Disable overload resolution for C++ expression evaluation. For
+ overloaded functions that are not class member functions, GDB
+ chooses the first function of the specified name that it finds in
+ the symbol table, whether or not its arguments are of the correct
+ type. For overloaded functions that are class member functions,
+ GDB searches for a function whose signature _exactly_ matches the
+ argument types.
+
+`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 `SYMBOL(TYPES)' rather than just SYMBOL. You can also
+ use the GDB command-line word completion facilities to list the
+ available choices, or to finish the type list for you. *Note
+ Command completion: Completion, for details on how to do this.
+
+
+File: gdb.info, Node: Objective-C, Next: Modula-2, Prev: C, Up: Support
+
+Objective-C
+-----------
+
+This section provides information about some commands and command
+options that are useful for debugging Objective-C code.
+
+* Menu:
+
+* Method Names in Commands::
+* The Print Command with Objective-C::
+
+
+File: gdb.info, Node: Method Names in Commands, Next: The Print Command with Objective-C, Prev: Objective-C, Up: Objective-C
+
+Method Names in Commands
+........................
+
+The following commands have been extended to accept Objective-C method
+names as line specifications:
+
+ * `clear'
+
+ * `break'
+
+ * `info line'
+
+ * `jump'
+
+ * `list'
+
+ A fully qualified Objective-C method name is specified as
+
+ -[CLASS METHODNAME]
+
+ where the minus sign is used to indicate an instance method and a
+plus sign (not shown) is used to indicate a class method. The class
+name CLASS and method name METHODNAME are enclosed in brackets, similar
+to the way messages are specified in Objective-C source code. For
+example, to set a breakpoint at the `create' instance method of class
+`Fruit' in the program currently being debugged, enter:
+
+ break -[Fruit create]
+
+ To list ten program lines around the `initialize' class method,
+enter:
+
+ list +[NSText initialize]
+
+ In the current version of GDB, the plus or minus sign is required.
+In future versions of GDB, the plus or minus sign will be optional, but
+you can use it to narrow the search. It is also possible to specify
+just a method name:
+
+ break create
+
+ You must specify the complete method name, including any colons. If
+your program's source files contain more than one `create' method,
+you'll be presented with a numbered list of classes that implement that
+method. Indicate your choice by number, or type `0' to exit if none
+apply.
+
+ As another example, to clear a breakpoint established at the
+`makeKeyAndOrderFront:' method of the `NSWindow' class, enter:
+
+ clear -[NSWindow makeKeyAndOrderFront:]
+
+
+File: gdb.info, Node: The Print Command with Objective-C, Prev: Method Names in Commands, Up: Objective-C
+
+The Print Command With Objective-C
+..................................
+
+The print command has also been extended to accept methods. For
+example:
+
+ print -[OBJECT hash]
+
+will tell GDB to send the `hash' message to OBJECT and print the
+result. Also, an additional command has been added, `print-object' or
+`po' for short, which is meant to print the description of an object.
+However, this command may only work with certain Objective-C libraries
+that have a particular hook function, `_NSPrintForDebugger', defined.
+
+
+File: gdb.info, Node: Modula-2, Prev: Objective-C, Up: Support
+
+Modula-2
+--------
+
+The extensions made to GDB to support Modula-2 only support output from
+the 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 GDB
+reads in the executable's symbol table.
+
+* 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 `::' and `.'
+* GDB/M2:: GDB and Modula-2
+
+
+File: gdb.info, Node: M2 Operators, Next: Built-In Func/Proc, Up: Modula-2
+
+Operators
+.........
+
+Operators must be defined on values of specific types. For instance,
+`+' 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:
+
+ * _Integral types_ consist of `INTEGER', `CARDINAL', and their
+ subranges.
+
+ * _Character types_ consist of `CHAR' and its subranges.
+
+ * _Floating-point types_ consist of `REAL'.
+
+ * _Pointer types_ consist of anything declared as `POINTER TO TYPE'.
+
+ * _Scalar types_ consist of all of the above.
+
+ * _Set types_ consist of `SET' and `BITSET' types.
+
+ * _Boolean types_ consist of `BOOLEAN'.
+
+The following operators are supported, and appear in order of
+increasing precedence:
+
+`,'
+ Function argument or array index separator.
+
+`:='
+ Assignment. The value of VAR `:=' VALUE is VALUE.
+
+`<, >'
+ Less than, greater than on integral, floating-point, or enumerated
+ types.
+
+`<=, >='
+ 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 `<'.
+
+`=, <>, #'
+ Equality and two ways of expressing inequality, valid on scalar
+ types. Same precedence as `<'. In GDB scripts, only `<>' is
+ available for inequality, since `#' conflicts with the script
+ comment character.
+
+`IN'
+ Set membership. Defined on set types and the types of their
+ members. Same precedence as `<'.
+
+`OR'
+ Boolean disjunction. Defined on boolean types.
+
+`AND, &'
+ Boolean conjunction. Defined on boolean types.
+
+`@'
+ The GDB "artificial array" operator (*note Expressions:
+ Expressions.).
+
+`+, -'
+ Addition and subtraction on integral and floating-point types, or
+ union and difference on set types.
+
+`*'
+ Multiplication on integral and floating-point types, or set
+ intersection on set types.
+
+`/'
+ Division on floating-point types, or symmetric set difference on
+ set types. Same precedence as `*'.
+
+`DIV, MOD'
+ Integer division and remainder. Defined on integral types. Same
+ precedence as `*'.
+
+`-'
+ Negative. Defined on `INTEGER' and `REAL' data.
+
+`^'
+ Pointer dereferencing. Defined on pointer types.
+
+`NOT'
+ Boolean negation. Defined on boolean types. Same precedence as
+ `^'.
+
+`.'
+ `RECORD' field selector. Defined on `RECORD' data. Same
+ precedence as `^'.
+
+`[]'
+ Array indexing. Defined on `ARRAY' data. Same precedence as `^'.
+
+`()'
+ Procedure argument list. Defined on `PROCEDURE' objects. Same
+ precedence as `^'.
+
+`::, .'
+ GDB and Modula-2 scope operators.
+
+ _Warning:_ Sets and their operations are not yet supported, so GDB
+ treats the use of the operator `IN', or the use of operators `+',
+ `-', `*', `/', `=', , `<>', `#', `<=', and `>=' on sets as an
+ error.
+
+
+File: gdb.info, Node: Built-In Func/Proc, Next: M2 Constants, Prev: M2 Operators, Up: Modula-2
+
+Built-in functions and procedures
+.................................
+
+Modula-2 also makes available several built-in procedures and functions.
+In describing these, the following metavariables are used:
+
+A
+ represents an `ARRAY' variable.
+
+C
+ represents a `CHAR' constant or variable.
+
+I
+ represents a variable or constant of integral type.
+
+M
+ represents an identifier that belongs to a set. Generally used in
+ the same function with the metavariable S. The type of S should
+ be `SET OF MTYPE' (where MTYPE is the type of M).
+
+N
+ represents a variable or constant of integral or floating-point
+ type.
+
+R
+ represents a variable or constant of floating-point type.
+
+T
+ represents a type.
+
+V
+ represents a variable.
+
+X
+ represents a variable or constant of one of many types. See the
+ explanation of the function for details.
+
+ All Modula-2 built-in procedures also return a result, described
+below.
+
+`ABS(N)'
+ Returns the absolute value of N.
+
+`CAP(C)'
+ If C is a lower case letter, it returns its upper case equivalent,
+ otherwise it returns its argument.
+
+`CHR(I)'
+ Returns the character whose ordinal value is I.
+
+`DEC(V)'
+ Decrements the value in the variable V by one. Returns the new
+ value.
+
+`DEC(V,I)'
+ Decrements the value in the variable V by I. Returns the new
+ value.
+
+`EXCL(M,S)'
+ Removes the element M from the set S. Returns the new set.
+
+`FLOAT(I)'
+ Returns the floating point equivalent of the integer I.
+
+`HIGH(A)'
+ Returns the index of the last member of A.
+
+`INC(V)'
+ Increments the value in the variable V by one. Returns the new
+ value.
+
+`INC(V,I)'
+ Increments the value in the variable V by I. Returns the new
+ value.
+
+`INCL(M,S)'
+ Adds the element M to the set S if it is not already there.
+ Returns the new set.
+
+`MAX(T)'
+ Returns the maximum value of the type T.
+
+`MIN(T)'
+ Returns the minimum value of the type T.
+
+`ODD(I)'
+ Returns boolean TRUE if I is an odd number.
+
+`ORD(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). X must be of an ordered
+ type, which include integral, character and enumerated types.
+
+`SIZE(X)'
+ Returns the size of its argument. X can be a variable or a type.
+
+`TRUNC(R)'
+ Returns the integral part of R.
+
+`VAL(T,I)'
+ Returns the member of the type T whose ordinal value is I.
+
+ _Warning:_ Sets and their operations are not yet supported, so
+ GDB treats the use of procedures `INCL' and `EXCL' as an error.
+
diff --git a/contrib/gdb/gdb/doc/gdb.info-2 b/contrib/gdb/gdb/doc/gdb.info-2
new file mode 100644
index 0000000..4dcf435
--- /dev/null
+++ b/contrib/gdb/gdb/doc/gdb.info-2
@@ -0,0 +1,9133 @@
+This is gdb.info, produced by makeinfo version 4.6 from ./gdb.texinfo.
+
+INFO-DIR-SECTION Software development
+START-INFO-DIR-ENTRY
+* Gdb: (gdb). The GNU debugger.
+END-INFO-DIR-ENTRY
+
+ This file documents the GNU debugger GDB.
+
+ This is the Ninth Edition, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 6.1.1.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+1998,
+1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being "Free Software" and "Free Software Needs Free
+Documentation", with the Front-Cover Texts being "A GNU Manual," and
+with the Back-Cover Texts as in (a) below.
+
+ (a) The Free Software Foundation's Back-Cover Text is: "You have
+freedom to copy and modify this GNU Manual, like GNU software. Copies
+published by the Free Software Foundation raise funds for GNU
+development."
+
+
+File: gdb.info, Node: M2 Constants, Next: M2 Defaults, Prev: Built-In Func/Proc, Up: Modula-2
+
+Constants
+.........
+
+GDB allows you to express the constants of Modula-2 in the following
+ways:
+
+ * 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 `H', and octal integers by a trailing `B'.
+
+ * 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 `E[+|-]NNN', where
+ `[+|-]NNN' is the desired exponent. All of the digits of the
+ floating point constant must be valid decimal (base 10) digits.
+
+ * Character constants consist of a single character enclosed by a
+ pair of like quotes, either single (`'') or double (`"'). They may
+ also be expressed by their ordinal value (their ASCII value,
+ usually) followed by a `C'.
+
+ * String constants consist of a sequence of characters enclosed by a
+ pair of like quotes, either single (`'') or double (`"'). Escape
+ sequences in the style of C are also allowed. *Note C and C++
+ constants: C Constants, for a brief explanation of escape
+ sequences.
+
+ * Enumerated constants consist of an enumerated identifier.
+
+ * Boolean constants consist of the identifiers `TRUE' and `FALSE'.
+
+ * Pointer constants consist of integral values only.
+
+ * Set constants are not yet supported.
+
+
+File: gdb.info, Node: M2 Defaults, Next: Deviations, Prev: M2 Constants, Up: Modula-2
+
+Modula-2 defaults
+.................
+
+If type and range checking are set automatically by GDB, they both
+default to `on' whenever the working language changes to Modula-2.
+This happens regardless of whether you or GDB selected the working
+language.
+
+ If you allow GDB to set the language automatically, then entering
+code compiled from a file whose name ends with `.mod' sets the working
+language to Modula-2. *Note Having GDB set the language automatically:
+Automatically, for further details.
+
+
+File: gdb.info, Node: Deviations, Next: M2 Checks, Prev: M2 Defaults, Up: Modula-2
+
+Deviations from standard Modula-2
+.................................
+
+A few changes have been made to make Modula-2 programs easier to debug.
+This is done primarily via loosening its type strictness:
+
+ * 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.)
+
+ * C escape sequences can be used in strings and characters to
+ represent non-printable characters. GDB prints out strings with
+ these escape sequences embedded. Single non-printable characters
+ are printed using the `CHR(NNN)' format.
+
+ * The assignment operator (`:=') returns the value of its right-hand
+ argument.
+
+ * All built-in procedures both modify _and_ return their argument.
+
+
+File: gdb.info, Node: M2 Checks, Next: M2 Scope, Prev: Deviations, Up: Modula-2
+
+Modula-2 type and range checks
+..............................
+
+ _Warning:_ in this release, GDB does not yet perform type or range
+ checking.
+
+ GDB considers two Modula-2 variables type equivalent if:
+
+ * They are of types that have been declared equivalent via a `TYPE
+ T1 = T2' statement
+
+ * They have been declared on the same line. (Note: This is true of
+ the GNU Modula-2 compiler, but it may not be true of other
+ compilers.)
+
+ 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.
+
+
+File: gdb.info, Node: M2 Scope, Next: GDB/M2, Prev: M2 Checks, Up: Modula-2
+
+The scope operators `::' and `.'
+................................
+
+There are a few subtle differences between the Modula-2 scope operator
+(`.') and the GDB scope operator (`::'). The two have similar syntax:
+
+
+ MODULE . ID
+ SCOPE :: ID
+
+where SCOPE is the name of a module or a procedure, MODULE the name of
+a module, and ID is any declared identifier within your program, except
+another module.
+
+ Using the `::' operator makes GDB search the scope specified by
+SCOPE for the identifier ID. If it is not found in the specified
+scope, then GDB searches all scopes enclosing the one specified by
+SCOPE.
+
+ Using the `.' operator makes GDB search the current scope for the
+identifier specified by ID that was imported from the definition module
+specified by MODULE. With this operator, it is an error if the
+identifier ID was not imported from definition module MODULE, or if ID
+is not an identifier in MODULE.
+
+
+File: gdb.info, Node: GDB/M2, Prev: M2 Scope, Up: Modula-2
+
+GDB and Modula-2
+................
+
+Some GDB commands have little use when debugging Modula-2 programs.
+Five subcommands of `set print' and `show print' apply specifically to
+C and C++: `vtbl', `demangle', `asm-demangle', `object', and `union'.
+The first four apply to C++, and the last to the C `union' type, which
+has no direct analogue in Modula-2.
+
+ The `@' operator (*note Expressions: Expressions.), while available
+with any language, is not useful with Modula-2. Its intent is to aid
+the debugging of "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 `{TYPE}ADREXP' is still useful.
+
+ In GDB scripts, the Modula-2 inequality operator `#' is interpreted
+as the beginning of a comment. Use `<>' instead.
+
+
+File: gdb.info, Node: Unsupported languages, Prev: Support, Up: Languages
+
+Unsupported languages
+=====================
+
+In addition to the other fully-supported programming languages, GDB
+also provides a pseudo-language, called `minimal'. It does not
+represent a real programming language, but provides a set of
+capabilities close to what the C or assembly languages provide. This
+should allow most simple operations to be performed while debugging an
+application that uses a language currently not supported by GDB.
+
+ If the language is set to `auto', GDB will automatically select this
+language if the current frame corresponds to an unsupported language.
+
+
+File: gdb.info, Node: Symbols, Next: Altering, Prev: Languages, Up: Top
+
+Examining the Symbol Table
+**************************
+
+The commands described in this chapter 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. GDB finds it in your
+program's symbol table, in the file indicated when you started GDB
+(*note Choosing files: File Options.), or by one of the file-management
+commands (*note Commands to specify files: Files.).
+
+ Occasionally, you may need to refer to symbols that contain unusual
+characters, which GDB ordinarily treats as word delimiters. The most
+frequent case is in referring to static variables in other source files
+(*note Program variables: Variables.). File names are recorded in
+object files as debugging symbols, but GDB would ordinarily parse a
+typical file name, like `foo.c', as the three words `foo' `.' `c'. To
+allow GDB to recognize `foo.c' as a single symbol, enclose it in single
+quotes; for example,
+
+ p 'foo.c'::x
+
+looks up the value of `x' in the scope of the file `foo.c'.
+
+`info address SYMBOL'
+ Describe where the data for 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 `print &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.
+
+`info symbol ADDR'
+ Print the name of a symbol which is stored at the address ADDR.
+ If no symbol is stored exactly at ADDR, GDB prints the nearest
+ symbol and an offset from it:
+
+ (gdb) info symbol 0x54320
+ _initialize_vx + 396 in section .text
+
+ This is the opposite of the `info address' command. You can use
+ it to find out the name of a variable or a function given its
+ address.
+
+`whatis EXPR'
+ Print the data type of expression EXPR. EXPR is not actually
+ evaluated, and any side-effecting operations (such as assignments
+ or function calls) inside it do not take place. *Note
+ Expressions: Expressions.
+
+`whatis'
+ Print the data type of `$', the last value in the value history.
+
+`ptype TYPENAME'
+ Print a description of data type TYPENAME. TYPENAME may be the
+ name of a type, or for C code it may have the form `class
+ CLASS-NAME', `struct STRUCT-TAG', `union UNION-TAG' or `enum
+ ENUM-TAG'.
+
+`ptype EXPR'
+`ptype'
+ Print a description of the type of expression EXPR. `ptype'
+ differs from `whatis' by printing a detailed description, instead
+ of just the name of the type.
+
+ For example, for this variable declaration:
+
+ struct complex {double real; double imag;} v;
+
+ the two commands give this output:
+
+ (gdb) whatis v
+ type = struct complex
+ (gdb) ptype v
+ type = struct complex {
+ double real;
+ double imag;
+ }
+
+ As with `whatis', using `ptype' without an argument refers to the
+ type of `$', the last value in the value history.
+
+`info types REGEXP'
+`info types'
+ Print a brief description of all types whose names match 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, `i type value' gives information on all types in your
+ program whose names include the string `value', but `i type
+ ^value$' gives information only on types whose complete name is
+ `value'.
+
+ This command differs from `ptype' in two ways: first, like
+ `whatis', it does not print a detailed description; second, it
+ lists all source files where a type is defined.
+
+`info scope ADDR'
+ List all the variables local to a particular scope. This command
+ accepts a location--a function name, a source line, or an address
+ preceded by a `*', and prints all the variables local to the scope
+ defined by that location. For example:
+
+ (gdb) info scope command_line_handler
+ Scope for command_line_handler:
+ Symbol rl is an argument at stack/frame offset 8, length 4.
+ Symbol linebuffer is in static storage at address 0x150a18, length 4.
+ Symbol linelength is in static storage at address 0x150a1c, length 4.
+ Symbol p is a local variable in register $esi, length 4.
+ Symbol p1 is a local variable in register $ebx, length 4.
+ Symbol nline is a local variable in register $edx, length 4.
+ Symbol repeat is a local variable at frame offset -8, length 4.
+
+ This command is especially useful for determining what data to
+ collect during a "trace experiment", see *Note collect: Tracepoint
+ Actions.
+
+`info source'
+ Show information about the current source file--that is, the
+ source file for the function containing the current point of
+ execution:
+ * the name of the source file, and the directory containing it,
+
+ * the directory it was compiled in,
+
+ * its length, in lines,
+
+ * which programming language it is written in,
+
+ * whether the executable includes debugging information for
+ that file, and if so, what format the information is in
+ (e.g., STABS, Dwarf 2, etc.), and
+
+ * whether the debugging information includes information about
+ preprocessor macros.
+
+`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.
+
+`info functions'
+ Print the names and data types of all defined functions.
+
+`info functions REGEXP'
+ Print the names and data types of all defined functions whose
+ names contain a match for regular expression REGEXP. Thus, `info
+ fun step' finds all functions whose names include `step'; `info
+ fun ^step' finds those whose names start with `step'. If a
+ function name contains characters that conflict with the regular
+ expression language (eg. `operator*()'), they may be quoted with
+ a backslash.
+
+`info variables'
+ Print the names and data types of all variables that are declared
+ outside of functions (i.e. excluding local variables).
+
+`info variables REGEXP'
+ Print the names and data types of all variables (except for local
+ variables) whose names contain a match for regular expression
+ REGEXP.
+
+`info classes'
+`info classes REGEXP'
+ Display all Objective-C classes in your program, or (with the
+ REGEXP argument) all those matching a particular regular
+ expression.
+
+`info selectors'
+`info selectors REGEXP'
+ Display all Objective-C selectors in your program, or (with the
+ REGEXP argument) all those matching a particular regular
+ expression.
+
+ Some systems allow individual object files that make up your
+ program to be replaced without stopping and restarting your
+ program. For example, in VxWorks you can simply recompile a
+ defective object file and keep on running. If you are running on
+ one of these systems, you can allow GDB to reload the symbols for
+ automatically relinked modules:
+
+ `set symbol-reloading on'
+ Replace symbol definitions for the corresponding source file
+ when an object file with a particular name is seen again.
+
+ `set symbol-reloading off'
+ Do not replace symbol definitions when encountering object
+ files of the same name more than once. This is the default
+ state; if you are not running on a system that permits
+ automatic relinking of modules, you should leave
+ `symbol-reloading' off, since otherwise GDB may discard
+ symbols when linking large programs, that may contain several
+ modules (from different directories or libraries) with the
+ same name.
+
+ `show symbol-reloading'
+ Show the current `on' or `off' setting.
+
+`set opaque-type-resolution on'
+ Tell GDB to resolve opaque types. An opaque type is a type
+ declared as a pointer to a `struct', `class', or `union'--for
+ example, `struct MyType *'--that is used in one source file
+ although the full declaration of `struct MyType' is in another
+ source file. The default is on.
+
+ A change in the setting of this subcommand will not take effect
+ until the next time symbols for a file are loaded.
+
+`set opaque-type-resolution off'
+ Tell GDB not to resolve opaque types. In this case, the type is
+ printed as follows:
+ {<no data fields>}
+
+`show opaque-type-resolution'
+ Show whether opaque types are resolved or not.
+
+`maint print symbols FILENAME'
+`maint print psymbols FILENAME'
+`maint print msymbols FILENAME'
+ Write a dump of debugging symbol data into the file FILENAME.
+ These commands are used to debug the GDB symbol-reading code. Only
+ symbols with debugging data are included. If you use `maint print
+ symbols', GDB includes all the symbols for which it has already
+ collected full details: that is, FILENAME reflects symbols for
+ only those files whose symbols GDB has read. You can use the
+ command `info sources' to find out which files these are. If you
+ use `maint print psymbols' instead, the dump shows information
+ about symbols that GDB only knows partially--that is, symbols
+ defined in files that GDB has skimmed, but not yet read
+ completely. Finally, `maint print msymbols' dumps just the
+ minimal symbol information required for each object file from
+ which GDB has read some symbols. *Note Commands to specify files:
+ Files, for a discussion of how GDB reads symbols (in the
+ description of `symbol-file').
+
+`maint info symtabs [ REGEXP ]'
+`maint info psymtabs [ REGEXP ]'
+ List the `struct symtab' or `struct partial_symtab' structures
+ whose names match REGEXP. If REGEXP is not given, list them all.
+ The output includes expressions which you can copy into a GDB
+ debugging this one to examine a particular structure in more
+ detail. For example:
+
+ (gdb) maint info psymtabs dwarf2read
+ { objfile /home/gnu/build/gdb/gdb
+ ((struct objfile *) 0x82e69d0)
+ { psymtab /home/gnu/src/gdb/dwarf2read.c
+ ((struct partial_symtab *) 0x8474b10)
+ readin no
+ fullname (null)
+ text addresses 0x814d3c8 -- 0x8158074
+ globals (* (struct partial_symbol **) 0x8507a08 @ 9)
+ statics (* (struct partial_symbol **) 0x40e95b78 @ 2882)
+ dependencies (none)
+ }
+ }
+ (gdb) maint info symtabs
+ (gdb)
+
+ We see that there is one partial symbol table whose filename
+ contains the string `dwarf2read', belonging to the `gdb'
+ executable; and we see that GDB has not read in any symtabs yet at
+ all. If we set a breakpoint on a function, that will cause GDB to
+ read the symtab for the compilation unit containing that function:
+
+ (gdb) break dwarf2_psymtab_to_symtab
+ Breakpoint 1 at 0x814e5da: file /home/gnu/src/gdb/dwarf2read.c,
+ line 1574.
+ (gdb) maint info symtabs
+ { objfile /home/gnu/build/gdb/gdb
+ ((struct objfile *) 0x82e69d0)
+ { symtab /home/gnu/src/gdb/dwarf2read.c
+ ((struct symtab *) 0x86c1f38)
+ dirname (null)
+ fullname (null)
+ blockvector ((struct blockvector *) 0x86c1bd0) (primary)
+ debugformat DWARF 2
+ }
+ }
+ (gdb)
+
+
+File: gdb.info, Node: Altering, Next: GDB Files, Prev: Symbols, Up: Top
+
+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 GDB features for altering execution of
+the program.
+
+ For example, you can store new values into variables or memory
+locations, give your program a signal, restart it at a different
+address, or even return prematurely from a function.
+
+* Menu:
+
+* Assignment:: Assignment to variables
+* Jumping:: Continuing at a different address
+* Signaling:: Giving your program a signal
+* Returning:: Returning from a function
+* Calling:: Calling your program's functions
+* Patching:: Patching your program
+
+
+File: gdb.info, Node: Assignment, Next: Jumping, Up: Altering
+
+Assignment to variables
+=======================
+
+To alter the value of a variable, evaluate an assignment expression.
+*Note Expressions: Expressions. For example,
+
+ print x=4
+
+stores the value 4 into the variable `x', and then prints the value of
+the assignment expression (which is 4). *Note Using GDB with Different
+Languages: Languages, for more information on operators in supported
+languages.
+
+ If you are not interested in seeing the value of the assignment, use
+the `set' command instead of the `print' command. `set' is really the
+same as `print' except that the expression's value is not printed and
+is not put in the value history (*note Value history: Value History.).
+The expression is evaluated only for its effects.
+
+ If the beginning of the argument string of the `set' command appears
+identical to a `set' subcommand, use the `set variable' command instead
+of just `set'. This command is identical to `set' except for its lack
+of subcommands. For example, if your program has a variable `width',
+you get an error if you try to set a new value with just `set
+width=13', because GDB has the command `set width':
+
+ (gdb) whatis width
+ type = double
+ (gdb) p width
+ $4 = 13
+ (gdb) set width=47
+ Invalid syntax in expression.
+
+The invalid expression, of course, is `=47'. In order to actually set
+the program's variable `width', use
+
+ (gdb) set var width=47
+
+ Because the `set' command has many subcommands that can conflict
+with the names of program variables, it is a good idea to use the `set
+variable' command instead of just `set'. For example, if your program
+has a variable `g', you run into problems if you try to set a new value
+with just `set g=4', because GDB has the command `set gnutarget',
+abbreviated `set g':
+
+ (gdb) whatis g
+ type = double
+ (gdb) p g
+ $1 = 1
+ (gdb) set g=4
+ (gdb) p g
+ $2 = 1
+ (gdb) r
+ The program being debugged has been started already.
+ Start it from the beginning? (y or n) y
+ Starting program: /home/smith/cc_progs/a.out
+ "/home/smith/cc_progs/a.out": can't open to read symbols:
+ Invalid bfd target.
+ (gdb) show g
+ The current BFD target is "=4".
+
+The program variable `g' did not change, and you silently set the
+`gnutarget' to an invalid value. In order to set the variable `g', use
+
+ (gdb) set var g=4
+
+ GDB 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.
+
+ To store values into arbitrary places in memory, use the `{...}'
+construct to generate a value of specified type at a specified address
+(*note Expressions: Expressions.). For example, `{int}0x83040' refers
+to memory location `0x83040' as an integer (which implies a certain size
+and representation in memory), and
+
+ set {int}0x83040 = 4
+
+stores the value 4 into that memory location.
+
+
+File: gdb.info, Node: Jumping, Next: Signaling, Prev: Assignment, Up: Altering
+
+Continuing at a different address
+=================================
+
+Ordinarily, when you continue your program, you do so at the place where
+it stopped, with the `continue' command. You can instead continue at
+an address of your own choosing, with the following commands:
+
+`jump LINESPEC'
+ Resume execution at line LINESPEC. Execution stops again
+ immediately if there is a breakpoint there. *Note Printing source
+ lines: List, for a description of the different forms of LINESPEC.
+ It is common practice to use the `tbreak' command in conjunction
+ with `jump'. *Note Setting breakpoints: Set Breaks.
+
+ The `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 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 `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.
+
+`jump *ADDRESS'
+ Resume execution at the instruction at address ADDRESS.
+
+ On many systems, you can get much the same effect as the `jump'
+command by storing a new value into the register `$pc'. The difference
+is that this does not start your program running; it only changes the
+address of where it _will_ run when you continue. For example,
+
+ set $pc = 0x485
+
+makes the next `continue' command or stepping command execute at
+address `0x485', rather than at the address where your program stopped.
+*Note Continuing and stepping: Continuing and Stepping.
+
+ The most common occasion to use the `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.
+
+
+File: gdb.info, Node: Signaling, Next: Returning, Prev: Jumping, Up: Altering
+
+Giving your program a signal
+============================
+
+`signal SIGNAL'
+ Resume execution where your program stopped, but immediately give
+ it the signal SIGNAL. SIGNAL can be the name or the number of a
+ signal. For example, on many systems `signal 2' and `signal
+ SIGINT' are both ways of sending an interrupt signal.
+
+ Alternatively, if 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 `continue' command; `signal 0' causes it to resume
+ without a signal.
+
+ `signal' does not repeat when you press <RET> a second time after
+ executing the command.
+
+ Invoking the `signal' command is not the same as invoking the `kill'
+utility from the shell. Sending a signal with `kill' causes GDB to
+decide what to do with the signal depending on the signal handling
+tables (*note Signals::). The `signal' command passes the signal
+directly to your program.
+
+
+File: gdb.info, Node: Returning, Next: Calling, Prev: Signaling, Up: Altering
+
+Returning from a function
+=========================
+
+`return'
+`return EXPRESSION'
+ You can cancel execution of a function call with the `return'
+ command. If you give an EXPRESSION argument, its value is used as
+ the function's return value.
+
+ When you use `return', GDB 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 `return'.
+
+ This pops the selected stack frame (*note Selecting a frame:
+Selection.), 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 `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 `finish' command (*note Continuing and
+stepping: Continuing and Stepping.) resumes execution until the
+selected stack frame returns naturally.
+
+
+File: gdb.info, Node: Calling, Next: Patching, Prev: Returning, Up: Altering
+
+Calling program functions
+=========================
+
+`call EXPR'
+ Evaluate the expression EXPR without displaying `void' returned
+ values.
+
+ You can use this variant of the `print' command if you want to
+execute a function from your program, but without cluttering the output
+with `void' returned values. If the result is not void, it is printed
+and saved in the value history.
+
+
+File: gdb.info, Node: Patching, Prev: Calling, Up: Altering
+
+Patching programs
+=================
+
+By default, GDB opens the file containing your program's executable
+code (or the corefile) 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 `set write' command. For example, you might want
+to turn on internal debugging flags, or even to make emergency repairs.
+
+`set write on'
+`set write off'
+ If you specify `set write on', GDB opens executable and core files
+ for both reading and writing; if you specify `set write off' (the
+ default), GDB opens them read-only.
+
+ If you have already loaded a file, you must load it again (using
+ the `exec-file' or `core-file' command) after changing `set
+ write', for your new setting to take effect.
+
+`show write'
+ Display whether executable files and core files are opened for
+ writing as well as reading.
+
+
+File: gdb.info, Node: GDB Files, Next: Targets, Prev: Altering, Up: Top
+
+GDB Files
+*********
+
+GDB 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. To
+debug a core dump of a previous run, you must also tell GDB the name of
+the core dump file.
+
+* Menu:
+
+* Files:: Commands to specify files
+* Separate Debug Files:: Debugging information in separate files
+* Symbol Errors:: Errors reading symbol files
+
+
+File: gdb.info, Node: Files, Next: Separate Debug Files, Up: GDB Files
+
+Commands to specify files
+=========================
+
+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 GDB's
+start-up commands (*note Getting In and Out of GDB: Invocation.).
+
+ Occasionally it is necessary to change to a different file during a
+GDB session. Or you may run GDB and forget to specify a file you want
+to use. In these situations the GDB commands to specify new files are
+useful.
+
+`file FILENAME'
+ Use 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 `run' command. If you do not
+ specify a directory and the file is not found in the GDB working
+ directory, GDB uses the environment variable `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 GDB and your program, using the `path' command.
+
+ On systems with memory-mapped files, an auxiliary file named
+ `FILENAME.syms' may hold symbol table information for FILENAME.
+ If so, GDB maps in the symbol table from `FILENAME.syms', starting
+ up more quickly. See the descriptions of the file options
+ `-mapped' and `-readnow' (available on the command line, and with
+ the commands `file', `symbol-file', or `add-symbol-file',
+ described below), for more information.
+
+`file'
+ `file' with no argument makes GDB discard any information it has
+ on both executable file and the symbol table.
+
+`exec-file [ FILENAME ]'
+ Specify that the program to be run (but not the symbol table) is
+ found in FILENAME. GDB searches the environment variable `PATH'
+ if necessary to locate your program. Omitting FILENAME means to
+ discard information on the executable file.
+
+`symbol-file [ FILENAME ]'
+ Read symbol table information from file FILENAME. `PATH' is
+ searched when necessary. Use the `file' command to get both symbol
+ table and program to run from the same file.
+
+ `symbol-file' with no argument clears out GDB information on your
+ program's symbol table.
+
+ The `symbol-file' command causes GDB 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
+ GDB.
+
+ `symbol-file' does not repeat if you press <RET> again after
+ executing it once.
+
+ When GDB 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 GNU
+ compiler, or other compilers that adhere to the local conventions.
+ Best results are usually obtained from GNU compilers; for example,
+ using `gcc' you can generate debugging information for optimized
+ code.
+
+ For most kinds of object files, with the exception of old SVR3
+ systems using COFF, the `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 GDB
+ 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 `set verbose' command can turn
+ these pauses into messages if desired. *Note Optional warnings
+ and messages: Messages/Warnings.)
+
+ We have not implemented the two-stage strategy for COFF yet. When
+ the symbol table is stored in COFF format, `symbol-file' reads the
+ symbol table data in full right away. Note that "stabs-in-COFF"
+ still does the two-stage strategy, since the debug info is actually
+ in stabs format.
+
+`symbol-file FILENAME [ -readnow ] [ -mapped ]'
+`file FILENAME [ -readnow ] [ -mapped ]'
+ You can override the GDB two-stage strategy for reading symbol
+ tables by using the `-readnow' option with any of the commands that
+ load symbol table information, if you want to be sure GDB has the
+ entire symbol table available.
+
+ If memory-mapped files are available on your system through the
+ `mmap' system call, you can use another option, `-mapped', to
+ cause GDB to write the symbols for your program into a reusable
+ file. Future GDB 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 `-mapped' option has the same
+ effect as starting GDB with the `-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 MYPROG is called
+ `MYPROG.syms'. Once this file exists (so long as it is newer than
+ the corresponding executable), GDB always attempts to use it when
+ you debug MYPROG; no special options or commands are needed.
+
+ The `.syms' file is specific to the host machine where you run
+ GDB. It holds an exact image of the internal GDB symbol table.
+ It cannot be shared across multiple host platforms.
+
+`core-file [ FILENAME ]'
+ 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; GDB
+ can access the executable file itself for other parts.
+
+ `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 GDB. 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
+ `kill' command (*note Killing the child process: Kill Process.).
+
+`add-symbol-file FILENAME ADDRESS'
+`add-symbol-file FILENAME ADDRESS [ -readnow ] [ -mapped ]'
+`add-symbol-file FILENAME -sSECTION ADDRESS ...'
+ The `add-symbol-file' command reads additional symbol table
+ information from the file FILENAME. You would use this command
+ when FILENAME has been dynamically loaded (by some other means)
+ into the program that is running. ADDRESS should be the memory
+ address at which the file has been loaded; GDB cannot figure this
+ out for itself. You can additionally specify an arbitrary number
+ of `-sSECTION ADDRESS' pairs, to give an explicit section name and
+ base address for that section. You can specify any ADDRESS as an
+ expression.
+
+ The symbol table of the file FILENAME is added to the symbol table
+ originally read with the `symbol-file' command. You can use the
+ `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 `symbol-file' command without any arguments.
+
+ Although FILENAME is typically a shared library file, an
+ executable file, or some other object file which has been fully
+ relocated for loading into a process, you can also load symbolic
+ information from relocatable `.o' files, as long as:
+
+ * the file's symbolic information refers only to linker symbols
+ defined in that file, not to symbols defined by other object
+ files,
+
+ * every section the file's symbolic information refers to has
+ actually been loaded into the inferior, as it appears in the
+ file, and
+
+ * you can determine the address at which every section was
+ loaded, and provide these to the `add-symbol-file' command.
+
+ Some embedded operating systems, like Sun Chorus and VxWorks, can
+ load relocatable files into an already running program; such
+ systems typically make the requirements above easy to meet.
+ However, it's important to recognize that many native systems use
+ complex link procedures (`.linkonce' section factoring and C++
+ constructor table assembly, for example) that make the
+ requirements difficult to meet. In general, one cannot assume
+ that using `add-symbol-file' to read a relocatable object file's
+ symbolic information will have the same effect as linking the
+ relocatable object file into the program in the normal way.
+
+ `add-symbol-file' does not repeat if you press <RET> after using
+ it.
+
+ You can use the `-mapped' and `-readnow' options just as with the
+ `symbol-file' command, to change how GDB manages the symbol table
+ information for FILENAME.
+
+`add-shared-symbol-file'
+ The `add-shared-symbol-file' command can be used only under
+ Harris' CXUX operating system for the Motorola 88k. GDB
+ automatically looks for shared libraries, however if GDB does not
+ find yours, you can run `add-shared-symbol-file'. It takes no
+ arguments.
+
+`section'
+ The `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,
+ described below, lists all the sections and their addresses.
+
+`info files'
+`info target'
+ `info files' and `info target' are synonymous; both print the
+ current target (*note Specifying a Debugging Target: Targets.),
+ including the names of the executable and core dump files
+ currently in use by GDB, and the files from which symbols were
+ loaded. The command `help target' lists all possible targets
+ rather than current ones.
+
+`maint info sections'
+ Another command that can give you extra information about program
+ sections is `maint info sections'. In addition to the section
+ information displayed by `info files', this command displays the
+ flags and file offset of each section in the executable and core
+ dump files. In addition, `maint info sections' provides the
+ following command options (which may be arbitrarily combined):
+
+ `ALLOBJ'
+ Display sections for all loaded object files, including
+ shared libraries.
+
+ `SECTIONS'
+ Display info only for named SECTIONS.
+
+ `SECTION-FLAGS'
+ Display info only for sections for which SECTION-FLAGS are
+ true. The section flags that GDB currently knows about are:
+ `ALLOC'
+ Section will have space allocated in the process when
+ loaded. Set for all sections except those containing
+ debug information.
+
+ `LOAD'
+ Section will be loaded from the file into the child
+ process memory. Set for pre-initialized code and data,
+ clear for `.bss' sections.
+
+ `RELOC'
+ Section needs to be relocated before loading.
+
+ `READONLY'
+ Section cannot be modified by the child process.
+
+ `CODE'
+ Section contains executable code only.
+
+ `DATA'
+ Section contains data only (no executable code).
+
+ `ROM'
+ Section will reside in ROM.
+
+ `CONSTRUCTOR'
+ Section contains data for constructor/destructor lists.
+
+ `HAS_CONTENTS'
+ Section is not empty.
+
+ `NEVER_LOAD'
+ An instruction to the linker to not output the section.
+
+ `COFF_SHARED_LIBRARY'
+ A notification to the linker that the section contains
+ COFF shared library information.
+
+ `IS_COMMON'
+ Section contains common symbols.
+
+`set trust-readonly-sections on'
+ Tell GDB that readonly sections in your object file really are
+ read-only (i.e. that their contents will not change). In that
+ case, GDB can fetch values from these sections out of the object
+ file, rather than from the target program. For some targets
+ (notably embedded ones), this can be a significant enhancement to
+ debugging performance.
+
+ The default is off.
+
+`set trust-readonly-sections off'
+ Tell GDB not to trust readonly sections. This means that the
+ contents of the section might change while the program is running,
+ and must therefore be fetched from the target when needed.
+
+ All file-specifying commands allow both absolute and relative file
+names as arguments. GDB always converts the file name to an absolute
+file name and remembers it that way.
+
+ GDB supports HP-UX, SunOS, SVr4, Irix 5, and IBM RS/6000 shared
+libraries.
+
+ GDB automatically loads symbol definitions from shared libraries
+when you use the `run' command, or when you examine a core file.
+(Before you issue the `run' command, GDB does not understand references
+to a function in a shared library, however--unless you are debugging a
+core file).
+
+ On HP-UX, if the program loads a library explicitly, GDB
+automatically loads the symbols at the time of the `shl_load' call.
+
+ There are times, however, when you may wish to not automatically load
+symbol definitions from shared libraries, such as when they are
+particularly large or there are many of them.
+
+ To control the automatic loading of shared library symbols, use the
+commands:
+
+`set auto-solib-add MODE'
+ If MODE is `on', symbols from all shared object libraries will be
+ loaded automatically when the inferior begins execution, you
+ attach to an independently started inferior, or when the dynamic
+ linker informs GDB that a new library has been loaded. If MODE is
+ `off', symbols must be loaded manually, using the `sharedlibrary'
+ command. The default value is `on'.
+
+`show auto-solib-add'
+ Display the current autoloading mode.
+
+ To explicitly load shared library symbols, use the `sharedlibrary'
+command:
+
+`info share'
+`info sharedlibrary'
+ Print the names of the shared libraries which are currently loaded.
+
+`sharedlibrary REGEX'
+`share 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 `run'. If REGEX is omitted all shared libraries
+ required by your program are loaded.
+
+ On some systems, such as HP-UX systems, GDB supports autoloading
+shared library symbols until a limiting threshold size is reached.
+This provides the benefit of allowing autoloading to remain on by
+default, but avoids autoloading excessively large shared libraries, up
+to a threshold that is initially set, but which you can modify if you
+wish.
+
+ Beyond that threshold, symbols from shared libraries must be
+explicitly loaded. To load these symbols, use the command
+`sharedlibrary FILENAME'. The base address of the shared library is
+determined automatically by GDB and need not be specified.
+
+ To display or set the threshold, use the commands:
+
+`set auto-solib-limit THRESHOLD'
+ Set the autoloading size threshold, in an integral number of
+ megabytes. If THRESHOLD is nonzero and shared library autoloading
+ is enabled, symbols from all shared object libraries will be
+ loaded until the total size of the loaded shared library symbols
+ exceeds this threshold. Otherwise, symbols must be loaded
+ manually, using the `sharedlibrary' command. The default
+ threshold is 100 (i.e. 100 Mb).
+
+`show auto-solib-limit'
+ Display the current autoloading size threshold, in megabytes.
+
+ Shared libraries are also supported in many cross or remote debugging
+configurations. A copy of the target's libraries need to be present on
+the host system; they need to be the same as the target libraries,
+although the copies on the target can be stripped as long as the copies
+on the host are not.
+
+ You need to tell GDB where the target libraries are, so that it can
+load the correct copies--otherwise, it may try to load the host's
+libraries. GDB has two variables to specify the search directories for
+target libraries.
+
+`set solib-absolute-prefix PATH'
+ If this variable is set, PATH will be used as a prefix for any
+ absolute shared library paths; many runtime loaders store the
+ absolute paths to the shared library in the target program's
+ memory. If you use `solib-absolute-prefix' to find shared
+ libraries, they need to be laid out in the same way that they are
+ on the target, with e.g. a `/usr/lib' hierarchy under PATH.
+
+ You can set the default value of `solib-absolute-prefix' by using
+ the configure-time `--with-sysroot' option.
+
+`show solib-absolute-prefix'
+ Display the current shared library prefix.
+
+`set solib-search-path PATH'
+ If this variable is set, PATH is a colon-separated list of
+ directories to search for shared libraries. `solib-search-path'
+ is used after `solib-absolute-prefix' fails to locate the library,
+ or if the path to the library is relative instead of absolute. If
+ you want to use `solib-search-path' instead of
+ `solib-absolute-prefix', be sure to set `solib-absolute-prefix' to
+ a nonexistant directory to prevent GDB from finding your host's
+ libraries.
+
+`show solib-search-path'
+ Display the current shared library search path.
+
+
+File: gdb.info, Node: Separate Debug Files, Next: Symbol Errors, Prev: Files, Up: GDB Files
+
+Debugging Information in Separate Files
+=======================================
+
+GDB allows you to put a program's debugging information in a file
+separate from the executable itself, in a way that allows GDB to find
+and load the debugging information automatically. Since debugging
+information can be very large -- sometimes larger than the executable
+code itself -- some systems distribute debugging information for their
+executables in separate files, which users can install only when they
+need to debug a problem.
+
+ If an executable's debugging information has been extracted to a
+separate file, the executable should contain a "debug link" giving the
+name of the debugging information file (with no directory components),
+and a checksum of its contents. (The exact form of a debug link is
+described below.) If the full name of the directory containing the
+executable is EXECDIR, and the executable has a debug link that
+specifies the name DEBUGFILE, then GDB will automatically search for
+the debugging information file in three places:
+
+ * the directory containing the executable file (that is, it will look
+ for a file named `EXECDIR/DEBUGFILE',
+
+ * a subdirectory of that directory named `.debug' (that is, the file
+ `EXECDIR/.debug/DEBUGFILE', and
+
+ * a subdirectory of the global debug file directory that includes the
+ executable's full path, and the name from the link (that is, the
+ file `GLOBALDEBUGDIR/EXECDIR/DEBUGFILE', where GLOBALDEBUGDIR is
+ the global debug file directory, and EXECDIR has been turned into
+ a relative path).
+
+GDB checks under each of these names for a debugging information file
+whose checksum matches that given in the link, and reads the debugging
+information from the first one it finds.
+
+ So, for example, if you ask GDB to debug `/usr/bin/ls', which has a
+link containing the name `ls.debug', and the global debug directory is
+`/usr/lib/debug', then GDB will look for debug information in
+`/usr/bin/ls.debug', `/usr/bin/.debug/ls.debug', and
+`/usr/lib/debug/usr/bin/ls.debug'.
+
+ You can set the global debugging info directory's name, and view the
+name GDB is currently using.
+
+`set debug-file-directory DIRECTORY'
+ Set the directory which GDB searches for separate debugging
+ information files to DIRECTORY.
+
+`show debug-file-directory'
+ Show the directory GDB searches for separate debugging information
+ files.
+
+
+ A debug link is a special section of the executable file named
+`.gnu_debuglink'. The section must contain:
+
+ * A filename, with any leading directory components removed,
+ followed by a zero byte,
+
+ * zero to three bytes of padding, as needed to reach the next
+ four-byte boundary within the section, and
+
+ * a four-byte CRC checksum, stored in the same endianness used for
+ the executable file itself. The checksum is computed on the
+ debugging information file's full contents by the function given
+ below, passing zero as the CRC argument.
+
+ Any executable file format can carry a debug link, as long as it can
+contain a section named `.gnu_debuglink' with the contents described
+above.
+
+ The debugging information file itself should be an ordinary
+executable, containing a full set of linker symbols, sections, and
+debugging information. The sections of the debugging information file
+should have the same names, addresses and sizes as the original file,
+but they need not contain any data -- much like a `.bss' section in an
+ordinary executable.
+
+ As of December 2002, there is no standard GNU utility to produce
+separated executable / debugging information file pairs. Ulrich
+Drepper's `elfutils' package, starting with version 0.53, contains a
+version of the `strip' command such that the command `strip foo -f
+foo.debug' removes the debugging information from the executable file
+`foo', places it in the file `foo.debug', and leaves behind a debug
+link in `foo'.
+
+ Since there are many different ways to compute CRC's (different
+polynomials, reversals, byte ordering, etc.), the simplest way to
+describe the CRC used in `.gnu_debuglink' sections is to give the
+complete code for a function that computes it:
+
+ unsigned long
+ gnu_debuglink_crc32 (unsigned long crc,
+ unsigned char *buf, size_t len)
+ {
+ static const unsigned long crc32_table[256] =
+ {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ };
+ unsigned char *end;
+
+ crc = ~crc & 0xffffffff;
+ for (end = buf + len; buf < end; ++buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc & 0xffffffff;
+ }
+
+
+File: gdb.info, Node: Symbol Errors, Prev: Separate Debug Files, Up: GDB Files
+
+Errors reading symbol files
+===========================
+
+While reading a symbol file, GDB occasionally encounters problems, such
+as symbol types it does not recognize, or known bugs in compiler
+output. By default, GDB 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 GDB to print only one
+message about each such type of problem, no matter how many times the
+problem occurs; or you can ask GDB to print more messages, to see how
+many times the problems occur, with the `set complaints' command (*note
+Optional warnings and messages: Messages/Warnings.).
+
+ The messages currently printed, and their meanings, include:
+
+`inner block not inside outer block in 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.
+
+ GDB circumvents the problem by treating the inner block as if it
+ had the same scope as the outer block. In the error message,
+ SYMBOL may be shown as "`(don't know)'" if the outer block is not a
+ function.
+
+`block at 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.
+
+ GDB 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 `set
+ verbose on'. *Note Optional warnings and messages:
+ Messages/Warnings.)
+
+`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.
+
+ GDB circumvents the problem by treating the symbol scope block as
+ starting on the previous source line.
+
+`bad string table offset in symbol N'
+ Symbol number N contains a pointer into the string table which is
+ larger than the size of the string table.
+
+ GDB circumvents the problem by considering the symbol to have the
+ name `foo', which may cause other problems if many symbols end up
+ with this name.
+
+`unknown symbol type `0xNN''
+ The symbol information contains new data types that GDB does not
+ yet know how to read. `0xNN' is the symbol type of the
+ uncomprehended information, in hexadecimal.
+
+ GDB 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 `gdb' with itself, breakpoint
+ on `complain', then go up to the function `read_dbx_symtab' and
+ examine `*bufp' to see the symbol.
+
+`stub type has NULL name'
+ GDB could not find the full definition for a struct or class.
+
+`const/volatile indicator missing (ok if using g++ v1.x), got...'
+ The symbol information for a C++ member function is missing some
+ information that recent versions of the compiler should have
+ output for it.
+
+`info mismatch between compiler and debugger'
+ GDB could not parse a type specification output by the compiler.
+
+
+
+File: gdb.info, Node: Targets, Next: Remote Debugging, Prev: GDB Files, Up: Top
+
+Specifying a Debugging Target
+*****************************
+
+A "target" is the execution environment occupied by your program.
+
+ Often, GDB 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 `file' or `core' commands. When you need more flexibility--for
+example, running GDB on a physically separate host, or controlling a
+standalone system over a serial port or a realtime system over a TCP/IP
+connection--you can use the `target' command to specify one of the
+target types configured for GDB (*note Commands for managing targets:
+Target Commands.).
+
+* Menu:
+
+* Active Targets:: Active targets
+* Target Commands:: Commands for managing targets
+* Byte Order:: Choosing target byte order
+* Remote:: Remote debugging
+* KOD:: Kernel Object Display
+
+
+File: gdb.info, Node: Active Targets, Next: Target Commands, Up: Targets
+
+Active targets
+==============
+
+There are three classes of targets: processes, core files, and
+executable files. GDB 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 `gdb a.out', then the executable file
+`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 GDB
+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.)
+
+ When you type `run', your executable file becomes an active process
+target as well. When a process target is active, all GDB commands
+requesting memory addresses refer to that target; addresses in an
+active core file or executable file target are obscured while the
+process target is active.
+
+ Use the `core-file' and `exec-file' commands to select a new core
+file or executable target (*note Commands to specify files: Files.).
+To specify as a target a process that is already running, use the
+`attach' command (*note Debugging an already-running process: Attach.).
+
+
+File: gdb.info, Node: Target Commands, Next: Byte Order, Prev: Active Targets, Up: Targets
+
+Commands for managing targets
+=============================
+
+`target TYPE PARAMETERS'
+ Connects the GDB host environment to a target machine or process.
+ A target is typically a protocol for talking to debugging
+ facilities. You use the argument TYPE to specify the type or
+ protocol of the target machine.
+
+ Further 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.
+
+ The `target' command does not repeat if you press <RET> again
+ after executing the command.
+
+`help target'
+ Displays the names of all targets available. To display targets
+ currently selected, use either `info target' or `info files'
+ (*note Commands to specify files: Files.).
+
+`help target NAME'
+ Describe a particular target, including any parameters necessary to
+ select it.
+
+`set gnutarget ARGS'
+ GDB uses its own library BFD to read your files. GDB knows
+ whether it is reading an "executable", a "core", or a ".o" file;
+ however, you can specify the file format with the `set gnutarget'
+ command. Unlike most `target' commands, with `gnutarget' the
+ `target' refers to a program, not a machine.
+
+ _Warning:_ To specify a file format with `set gnutarget', you
+ must know the actual BFD name.
+
+ *Note Commands to specify files: Files.
+
+`show gnutarget'
+ Use the `show gnutarget' command to display what file format
+ `gnutarget' is set to read. If you have not set `gnutarget', GDB
+ will determine the file format for each file automatically, and
+ `show gnutarget' displays `The current BDF target is "auto"'.
+
+ Here are some common targets (available, or not, depending on the GDB
+configuration):
+
+`target exec PROGRAM'
+ An executable file. `target exec PROGRAM' is the same as
+ `exec-file PROGRAM'.
+
+`target core FILENAME'
+ A core dump file. `target core FILENAME' is the same as
+ `core-file FILENAME'.
+
+`target remote DEV'
+ Remote serial target in GDB-specific protocol. The argument DEV
+ specifies what serial device to use for the connection (e.g.
+ `/dev/ttya'). *Note Remote debugging: Remote. `target remote'
+ 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.
+
+`target sim'
+ Builtin CPU simulator. GDB includes simulators for most
+ architectures. In general,
+ target sim
+ load
+ run
+
+ works; however, you cannot assume that a specific memory map,
+ device drivers, or even basic I/O is available, although some
+ simulators do provide these. For info about any
+ processor-specific simulator details, see the appropriate section
+ in *Note Embedded Processors: Embedded Processors.
+
+
+ Some configurations may include these targets as well:
+
+`target nrom DEV'
+ NetROM ROM emulator. This target only supports downloading.
+
+
+ Different targets are available on different configurations of GDB;
+your configuration may have more or fewer targets.
+
+ Many remote targets require you to download the executable's code
+once you've successfully established a connection.
+
+`load FILENAME'
+ Depending on what remote debugging facilities are configured into
+ GDB, the `load' command may be available. Where it exists, it is
+ meant to make FILENAME (an executable) available for debugging on
+ the remote system--by downloading, or dynamic linking, for example.
+ `load' also records the FILENAME symbol table in GDB, like the
+ `add-symbol-file' command.
+
+ If your GDB does not have a `load' command, attempting to execute
+ it gets the error message "`You can't do that when your target is
+ ...'"
+
+ 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.
+
+ `load' does not repeat if you press <RET> again after using it.
+
+
+File: gdb.info, Node: Byte Order, Next: Remote, Prev: Target Commands, Up: Targets
+
+Choosing target byte order
+==========================
+
+Some types of processors, such as the MIPS, PowerPC, and Renesas SH,
+offer the ability to run either big-endian or little-endian byte
+orders. Usually the executable or symbol will include a bit to
+designate the endian-ness, and you will not need to worry about which
+to use. However, you may still find it useful to adjust GDB's idea of
+processor endian-ness manually.
+
+`set endian big'
+ Instruct GDB to assume the target is big-endian.
+
+`set endian little'
+ Instruct GDB to assume the target is little-endian.
+
+`set endian auto'
+ Instruct GDB to use the byte order associated with the executable.
+
+`show endian'
+ Display GDB's current idea of the target byte order.
+
+
+ Note that these commands merely adjust interpretation of symbolic
+data on the host, and that they have absolutely no effect on the target
+system.
+
+
+File: gdb.info, Node: Remote, Next: KOD, Prev: Byte Order, Up: Targets
+
+Remote debugging
+================
+
+If you are trying to debug a program running on a machine that cannot
+run GDB 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 GDB have special serial or TCP/IP interfaces
+to make this work with particular debugging targets. In addition, GDB
+comes with a generic serial protocol (specific to GDB, 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 GDB.
+
+ Other remote targets may be available in your configuration of GDB;
+use `help target' to list them.
+
+
+File: gdb.info, Node: KOD, Prev: Remote, Up: Targets
+
+Kernel Object Display
+=====================
+
+Some targets support kernel object display. Using this facility, GDB
+communicates specially with the underlying operating system and can
+display information about operating system-level objects such as
+mutexes and other synchronization objects. Exactly which objects can be
+displayed is determined on a per-OS basis.
+
+ Use the `set os' command to set the operating system. This tells
+GDB which kernel object display module to initialize:
+
+ (gdb) set os cisco
+
+ The associated command `show os' displays the operating system set
+with the `set os' command; if no operating system has been set, `show
+os' will display an empty string `""'.
+
+ If `set os' succeeds, GDB will display some information about the
+operating system, and will create a new `info' command which can be
+used to query the target. The `info' command is named after the
+operating system:
+
+ (gdb) info cisco
+ List of Cisco Kernel Objects
+ Object Description
+ any Any and all objects
+
+ Further subcommands can be used to query about particular objects
+known by the kernel.
+
+ There is currently no way to determine whether a given operating
+system is supported other than to try setting it with `set os NAME',
+where NAME is the name of the operating system you want to try.
+
+
+File: gdb.info, Node: Remote Debugging, Next: Configurations, Prev: Targets, Up: Top
+
+Debugging remote programs
+*************************
+
+* Menu:
+
+* Connecting:: Connecting to a remote target
+* Server:: Using the gdbserver program
+* NetWare:: Using the gdbserve.nlm program
+* Remote configuration:: Remote configuration
+* remote stub:: Implementing a remote stub
+
+
+File: gdb.info, Node: Connecting, Next: Server, Up: Remote Debugging
+
+Connecting to a remote target
+=============================
+
+On the GDB host machine, you will need an unstripped copy of your
+program, since GDB needs symobl and debugging information. Start up
+GDB as usual, using the name of the local copy of your program as the
+first argument.
+
+ If you're using a serial line, you may want to give GDB the `--baud'
+option, or use the `set remotebaud' command before the `target' command.
+
+ After that, use `target remote' to establish communications with the
+target machine. Its argument specifies how to communicate--either via
+a devicename attached to a direct serial line, or a TCP or UDP port
+(possibly 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 `/dev/ttyb':
+
+ target remote /dev/ttyb
+
+ To use a TCP connection, use an argument of the form `HOST:PORT' or
+`tcp:HOST:PORT'. For example, to connect to port 2828 on a terminal
+server named `manyfarms':
+
+ target remote manyfarms:2828
+
+ If your remote target is actually running on the same machine as
+your debugger session (e.g. a simulator of your target running on the
+same host), you can omit the hostname. For example, to connect to port
+1234 on your local machine:
+
+ target remote :1234
+
+Note that the colon is still required here.
+
+ To use a UDP connection, use an argument of the form
+`udp:HOST:PORT'. For example, to connect to UDP port 2828 on a
+terminal server named `manyfarms':
+
+ target remote udp:manyfarms:2828
+
+ When using a UDP connection for remote debugging, you should keep in
+mind that the `U' stands for "Unreliable". UDP can silently drop
+packets on busy or unreliable networks, which will cause havoc with
+your debugging session.
+
+ Now you can use all the usual commands to examine and change data
+and to step and continue the remote program.
+
+ Whenever GDB is waiting for the remote program, if you type the
+interrupt character (often <C-C>), GDB 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, GDB displays this prompt:
+
+ Interrupted while waiting for the program.
+ Give up (and stop debugging it)? (y or n)
+
+ If you type `y', GDB abandons the remote debugging session. (If you
+decide you want to try again later, you can use `target remote' again
+to connect once more.) If you type `n', GDB goes back to waiting.
+
+`detach'
+ When you have finished debugging the remote program, you can use
+ the `detach' command to release it from GDB control. Detaching
+ from the target normally resumes its execution, but the results
+ will depend on your particular remote stub. After the `detach'
+ command, GDB is free to connect to another target.
+
+`disconnect'
+ The `disconnect' command behaves like `detach', except that the
+ target is generally not resumed. It will wait for GDB (this
+ instance or another one) to connect and continue debugging. After
+ the `disconnect' command, GDB is again free to connect to another
+ target.
+
+
+File: gdb.info, Node: Server, Next: NetWare, Prev: Connecting, Up: Remote Debugging
+
+Using the `gdbserver' program
+=============================
+
+`gdbserver' is a control program for Unix-like systems, which allows
+you to connect your program with a remote GDB via `target remote'--but
+without linking in the usual debugging stub.
+
+ `gdbserver' is not a complete replacement for the debugging stubs,
+because it requires essentially the same operating-system facilities
+that GDB itself does. In fact, a system that can run `gdbserver' to
+connect to a remote GDB could also run GDB locally! `gdbserver' is
+sometimes useful nevertheless, because it is a much smaller program
+than GDB itself. It is also easier to port than all of GDB, so you may
+be able to get started more quickly on a new system by using
+`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 `gdbserver' to
+make a similar choice for debugging.
+
+ GDB and `gdbserver' communicate via either a serial line or a TCP
+connection, using the standard GDB remote serial protocol.
+
+_On the target machine,_
+ you need to have a copy of the program you want to debug.
+ `gdbserver' does not need your program's symbol table, so you can
+ strip the program if necessary to save space. GDB on the host
+ system does all the symbol handling.
+
+ To use the server, you must tell it how to communicate with GDB;
+ the name of your program; and the arguments for your program. The
+ usual syntax is:
+
+ target> gdbserver COMM PROGRAM [ ARGS ... ]
+
+ 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 `foo.txt' and communicate with GDB over the serial port
+ `/dev/com1':
+
+ target> gdbserver /dev/com1 emacs foo.txt
+
+ `gdbserver' waits passively for the host GDB to communicate with
+ it.
+
+ To use a TCP connection instead of a serial line:
+
+ target> gdbserver host:2345 emacs foo.txt
+
+ The only difference from the previous example is the first
+ argument, specifying that you are communicating with the host GDB
+ via TCP. The `host:2345' argument means that `gdbserver' is to
+ expect a TCP connection from machine `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 TCP ports already in use on the target system (for example,
+ `23' is reserved for `telnet').(1) You must use the same port
+ number with the host GDB `target remote' command.
+
+ On some targets, `gdbserver' can also attach to running programs.
+ This is accomplished via the `--attach' argument. The syntax is:
+
+ target> gdbserver COMM --attach PID
+
+ PID is the process ID of a currently running process. It isn't
+ necessary to point `gdbserver' at a binary for the running process.
+
+ You can debug processes by name instead of process ID if your
+ target has the `pidof' utility:
+
+ target> gdbserver COMM --attach `pidof PROGRAM`
+
+ In case more than one copy of PROGRAM is running, or PROGRAM has
+ multiple threads, most versions of `pidof' support the `-s' option
+ to only return the first process ID.
+
+_On the host machine,_
+ connect to your target (*note Connecting to a remote target:
+ Connecting.). For TCP connections, you must start up `gdbserver'
+ prior to using the `target remote' command. Otherwise you may get
+ an error whose text depends on the host system, but which usually
+ looks something like `Connection refused'. You don't need to use
+ the `load' command in GDB when using gdbserver, since the program
+ is already on the target.
+
+
+ ---------- Footnotes ----------
+
+ (1) If you choose a port number that conflicts with another service,
+`gdbserver' prints an error message and exits.
+
+
+File: gdb.info, Node: NetWare, Next: Remote configuration, Prev: Server, Up: Remote Debugging
+
+Using the `gdbserve.nlm' program
+================================
+
+`gdbserve.nlm' is a control program for NetWare systems, which allows
+you to connect your program with a remote GDB via `target remote'.
+
+ GDB and `gdbserve.nlm' communicate via a serial line, using the
+standard GDB remote serial protocol.
+
+_On the target machine,_
+ you need to have a copy of the program you want to debug.
+ `gdbserve.nlm' does not need your program's symbol table, so you
+ can strip the program if necessary to save space. GDB on the host
+ system does all the symbol handling.
+
+ To use the server, you must tell it how to communicate with GDB;
+ the name of your program; and the arguments for your program. The
+ syntax is:
+
+ load gdbserve [ BOARD=BOARD ] [ PORT=PORT ]
+ [ BAUD=BAUD ] PROGRAM [ ARGS ... ]
+
+ BOARD and PORT specify the serial line; BAUD specifies the baud
+ rate used by the connection. PORT and NODE default to 0, BAUD
+ defaults to 9600bps.
+
+ For example, to debug Emacs with the argument `foo.txt'and
+ communicate with GDB over serial port number 2 or board 1 using a
+ 19200bps connection:
+
+ load gdbserve BOARD=1 PORT=2 BAUD=19200 emacs foo.txt
+
+__
+ On the GDB host machine, connect to your target (*note Connecting
+ to a remote target: Connecting.).
+
+
+
+File: gdb.info, Node: Remote configuration, Next: remote stub, Prev: NetWare, Up: Remote Debugging
+
+Remote configuration
+====================
+
+The following configuration options are available when debugging remote
+programs:
+
+`set remote hardware-watchpoint-limit LIMIT'
+`set remote hardware-breakpoint-limit LIMIT'
+ Restrict GDB to using LIMIT remote hardware breakpoint or
+ watchpoints. A limit of -1, the default, is treated as unlimited.
+
+
+File: gdb.info, Node: remote stub, Prev: Remote configuration, Up: Remote Debugging
+
+Implementing a remote stub
+==========================
+
+The stub files provided with GDB implement the target side of the
+communication protocol, and the GDB side is implemented in the GDB
+source 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. `sparc-stub.c' is the best
+organized, and therefore the easiest to read.)
+
+ To debug a program running on another machine (the debugging
+"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:
+
+ 1. A startup routine to set up the C runtime environment; these
+ usually have a name like `crt0'. The startup routine may be
+ supplied by your hardware supplier, or you may have to write your
+ own.
+
+ 2. A C subroutine library to support your program's subroutine calls,
+ notably managing input and output.
+
+ 3. 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.
+
+ The next step is to arrange for your program to use a serial port to
+communicate with the machine where GDB is running (the "host" machine).
+In general terms, the scheme looks like this:
+
+_On the host,_
+ GDB already understands how to use this protocol; when everything
+ else is set up, you can simply use the `target remote' command
+ (*note Specifying a Debugging Target: Targets.).
+
+_On the target,_
+ you must link with your program a few special-purpose subroutines
+ that implement the GDB remote serial protocol. The file
+ containing these subroutines is called a "debugging stub".
+
+ On certain remote targets, you can use an auxiliary program
+ `gdbserver' instead of linking a stub into your program. *Note
+ Using the `gdbserver' program: Server, for details.
+
+ The debugging stub is specific to the architecture of the remote
+machine; for example, use `sparc-stub.c' to debug programs on SPARC
+boards.
+
+ These working remote stubs are distributed with GDB:
+
+`i386-stub.c'
+ For Intel 386 and compatible architectures.
+
+`m68k-stub.c'
+ For Motorola 680x0 architectures.
+
+`sh-stub.c'
+ For Renesas SH architectures.
+
+`sparc-stub.c'
+ For SPARC architectures.
+
+`sparcl-stub.c'
+ For Fujitsu SPARCLITE architectures.
+
+
+ The `README' file in the GDB 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
+
+
+File: gdb.info, Node: Stub Contents, Next: Bootstrapping, Up: remote stub
+
+What the stub can do for you
+----------------------------
+
+The debugging stub for your architecture supplies these three
+subroutines:
+
+`set_debug_traps'
+ This routine arranges for `handle_exception' to run when your
+ program stops. You must call this subroutine explicitly near the
+ beginning of your program.
+
+`handle_exception'
+ This is the central workhorse, but your program never calls it
+ explicitly--the setup code arranges for `handle_exception' to run
+ when a trap is triggered.
+
+ `handle_exception' takes control when your program stops during
+ execution (for example, on a breakpoint), and mediates
+ communications with GDB on the host machine. This is where the
+ communications protocol is implemented; `handle_exception' acts as
+ the GDB 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
+ GDB needs, until you execute a GDB command that makes your program
+ resume; at that point, `handle_exception' returns control to your
+ own code on the target machine.
+
+`breakpoint'
+ Use this auxiliary subroutine to make your program contain a
+ breakpoint. Depending on the particular situation, this may be
+ the only way for GDB 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
+ `handle_exception'--in effect, to GDB. 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 `breakpoint' from
+ your own program--simply running `target remote' from the host GDB
+ session gets control.
+
+ Call `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.
+
+
+File: gdb.info, Node: Bootstrapping, Next: Debug Session, Prev: Stub Contents, Up: remote stub
+
+What you must do for the stub
+-----------------------------
+
+The debugging stubs that come with GDB 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.
+
+`int getDebugChar()'
+ Write this subroutine to read a single character from the serial
+ port. It may be identical to `getchar' for your target system; a
+ different name is used to allow you to distinguish the two if you
+ wish.
+
+`void putDebugChar(int)'
+ Write this subroutine to write a single character to the serial
+ port. It may be identical to `putchar' for your target system; a
+ different name is used to allow you to distinguish the two if you
+ wish.
+
+ If you want GDB 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 `^C' (`\003', the control-C character).
+That is the character which GDB uses to tell the remote system to stop.
+
+ Getting the debugging target to return the proper status to GDB
+probably requires changes to the standard stub; one quick and dirty way
+is to just execute a breakpoint instruction (the "dirty" part is that
+GDB reports a `SIGTRAP' instead of a `SIGINT').
+
+ Other routines you need to supply are:
+
+`void exceptionHandler (int EXCEPTION_NUMBER, void *EXCEPTION_ADDRESS)'
+ Write this function to install 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 ROM, containing entries which point to a table in RAM).
+ 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 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
+ EXCEPTION_ADDRESS, it should be a simple jump, not a jump to
+ subroutine.
+
+ For the 386, 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 SPARC and 68k stubs are able to mask interrupts themselves
+ without help from `exceptionHandler'.
+
+`void flush_i_cache()'
+ On 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, GDB requires this
+ function to make certain that the state of your program is stable.
+
+You must also make sure this library routine is available:
+
+`void *memset(void *, int, int)'
+ This is the standard library function `memset' that sets an area of
+ memory to a known value. If you have one of the free versions of
+ `libc.a', `memset' can be found there; otherwise, you must either
+ obtain it from your hardware manufacturer, or write your own.
+
+ 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 `gcc' generates as inline code.
+
+
+File: gdb.info, Node: Debug Session, Prev: Bootstrapping, Up: remote stub
+
+Putting it all together
+-----------------------
+
+In summary, when your program is ready to debug, you must follow these
+steps.
+
+ 1. Make sure you have defined the supporting low-level routines
+ (*note What you must do for the stub: Bootstrapping.):
+ `getDebugChar', `putDebugChar',
+ `flush_i_cache', `memset', `exceptionHandler'.
+
+ 2. Insert these lines near the top of your program:
+
+ set_debug_traps();
+ breakpoint();
+
+ 3. For the 680x0 stub only, you need to provide a variable called
+ `exceptionHook'. Normally you just use:
+
+ void (*exceptionHook)() = 0;
+
+ but if before calling `set_debug_traps', you set it to point to a
+ function in your program, that function is called when `GDB'
+ continues after stopping on a trap (for example, bus error). The
+ function indicated by `exceptionHook' is called with one
+ parameter: an `int' which is the exception number.
+
+ 4. Compile and link together: your program, the GDB debugging stub for
+ your target architecture, and the supporting subroutines.
+
+ 5. Make sure you have a serial connection between your target machine
+ and the GDB host, and identify the serial port on the host.
+
+ 6. Download your program to your target machine (or get it there by
+ whatever means the manufacturer provides), and start it.
+
+ 7. Start GDB on the host, and connect to the target (*note Connecting
+ to a remote target: Connecting.).
+
+
+
+File: gdb.info, Node: Configurations, Next: Controlling GDB, Prev: Remote Debugging, Up: Top
+
+Configuration-Specific Information
+**********************************
+
+While nearly all GDB commands are available for all native and cross
+versions of the debugger, there are some exceptions. This chapter
+describes things that are only available in certain configurations.
+
+ There are three major categories of configurations: native
+configurations, where the host and target are the same, embedded
+operating system configurations, which are usually the same for several
+different processor architectures, and bare embedded processors, which
+are quite different from each other.
+
+* Menu:
+
+* Native::
+* Embedded OS::
+* Embedded Processors::
+* Architectures::
+
+
+File: gdb.info, Node: Native, Next: Embedded OS, Up: Configurations
+
+Native
+======
+
+This section describes details specific to particular native
+configurations.
+
+* Menu:
+
+* HP-UX:: HP-UX
+* SVR4 Process Information:: SVR4 process information
+* DJGPP Native:: Features specific to the DJGPP port
+* Cygwin Native:: Features specific to the Cygwin port
+
+
+File: gdb.info, Node: HP-UX, Next: SVR4 Process Information, Up: Native
+
+HP-UX
+-----
+
+On HP-UX systems, if you refer to a function or variable name that
+begins with a dollar sign, GDB searches for a user or system name
+first, before it searches for a convenience variable.
+
+
+File: gdb.info, Node: SVR4 Process Information, Next: DJGPP Native, Prev: HP-UX, Up: Native
+
+SVR4 process information
+------------------------
+
+Many versions of SVR4 provide a facility called `/proc' that can be
+used to examine the image of a running process using file-system
+subroutines. If GDB is configured for an operating system with this
+facility, the command `info proc' is available to report on several
+kinds of information about the process running your program. `info
+proc' works only on SVR4 systems that include the `procfs' code. This
+includes OSF/1 (Digital Unix), Solaris, Irix, and Unixware, but not
+HP-UX or GNU/Linux, for example.
+
+`info proc'
+ Summarize available information about the process.
+
+`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.
+
+
+File: gdb.info, Node: DJGPP Native, Next: Cygwin Native, Prev: SVR4 Process Information, Up: Native
+
+Features for Debugging DJGPP Programs
+-------------------------------------
+
+DJGPP is the port of GNU development tools to MS-DOS and MS-Windows.
+DJGPP programs are 32-bit protected-mode programs that use the "DPMI"
+(DOS Protected-Mode Interface) API to run on top of real-mode DOS
+systems and their emulations.
+
+ GDB supports native debugging of DJGPP programs, and defines a few
+commands specific to the DJGPP port. This subsection describes those
+commands.
+
+`info dos'
+ This is a prefix of DJGPP-specific commands which print
+ information about the target system and important OS structures.
+
+`info dos sysinfo'
+ This command displays assorted information about the underlying
+ platform: the CPU type and features, the OS version and flavor, the
+ DPMI version, and the available conventional and DPMI memory.
+
+`info dos gdt'
+`info dos ldt'
+`info dos idt'
+ These 3 commands display entries from, respectively, Global, Local,
+ and Interrupt Descriptor Tables (GDT, LDT, and IDT). The
+ descriptor tables are data structures which store a descriptor for
+ each segment that is currently in use. The segment's selector is
+ an index into a descriptor table; the table entry for that index
+ holds the descriptor's base address and limit, and its attributes
+ and access rights.
+
+ A typical DJGPP program uses 3 segments: a code segment, a data
+ segment (used for both data and the stack), and a DOS segment
+ (which allows access to DOS/BIOS data structures and absolute
+ addresses in conventional memory). However, the DPMI host will
+ usually define additional segments in order to support the DPMI
+ environment.
+
+ These commands allow to display entries from the descriptor tables.
+ Without an argument, all entries from the specified table are
+ displayed. An argument, which should be an integer expression,
+ means display a single entry whose index is given by the argument.
+ For example, here's a convenient way to display information about
+ the debugged program's data segment:
+
+ `(gdb) info dos ldt $ds'
+ `0x13f: base=0x11970000 limit=0x0009ffff 32-Bit Data (Read/Write, Exp-up)'
+
+
+ This comes in handy when you want to see whether a pointer is
+ outside the data segment's limit (i.e. "garbled").
+
+`info dos pde'
+`info dos pte'
+ These two commands display entries from, respectively, the Page
+ Directory and the Page Tables. Page Directories and Page Tables
+ are data structures which control how virtual memory addresses are
+ mapped into physical addresses. A Page Table includes an entry
+ for every page of memory that is mapped into the program's address
+ space; there may be several Page Tables, each one holding up to
+ 4096 entries. A Page Directory has up to 4096 entries, one each
+ for every Page Table that is currently in use.
+
+ Without an argument, `info dos pde' displays the entire Page
+ Directory, and `info dos pte' displays all the entries in all of
+ the Page Tables. An argument, an integer expression, given to the
+ `info dos pde' command means display only that entry from the Page
+ Directory table. An argument given to the `info dos pte' command
+ means display entries from a single Page Table, the one pointed to
+ by the specified entry in the Page Directory.
+
+ These commands are useful when your program uses "DMA" (Direct
+ Memory Access), which needs physical addresses to program the DMA
+ controller.
+
+ These commands are supported only with some DPMI servers.
+
+`info dos address-pte ADDR'
+ This command displays the Page Table entry for a specified linear
+ address. The argument linear address ADDR should already have the
+ appropriate segment's base address added to it, because this
+ command accepts addresses which may belong to _any_ segment. For
+ example, here's how to display the Page Table entry for the page
+ where the variable `i' is stored:
+
+ `(gdb) info dos address-pte __djgpp_base_address + (char *)&i'
+ `Page Table entry for address 0x11a00d30:'
+ `Base=0x02698000 Dirty Acc. Not-Cached Write-Back Usr Read-Write +0xd30'
+
+
+ This says that `i' is stored at offset `0xd30' from the page whose
+ physical base address is `0x02698000', and prints all the
+ attributes of that page.
+
+ Note that you must cast the addresses of variables to a `char *',
+ since otherwise the value of `__djgpp_base_address', the base
+ address of all variables and functions in a DJGPP program, will be
+ added using the rules of C pointer arithmetics: if `i' is declared
+ an `int', GDB will add 4 times the value of `__djgpp_base_address'
+ to the address of `i'.
+
+ Here's another example, it displays the Page Table entry for the
+ transfer buffer:
+
+ `(gdb) info dos address-pte *((unsigned *)&_go32_info_block + 3)'
+ `Page Table entry for address 0x29110:'
+ `Base=0x00029000 Dirty Acc. Not-Cached Write-Back Usr Read-Write +0x110'
+
+
+ (The `+ 3' offset is because the transfer buffer's address is the
+ 3rd member of the `_go32_info_block' structure.) The output of
+ this command clearly shows that addresses in conventional memory
+ are mapped 1:1, i.e. the physical and linear addresses are
+ identical.
+
+ This command is supported only with some DPMI servers.
+
+
+File: gdb.info, Node: Cygwin Native, Prev: DJGPP Native, Up: Native
+
+Features for Debugging MS Windows PE executables
+------------------------------------------------
+
+GDB supports native debugging of MS Windows programs, including DLLs
+with and without symbolic debugging information. There are various
+additional Cygwin-specific commands, described in this subsection. The
+subsubsection *note Non-debug DLL symbols:: describes working with DLLs
+that have no debugging symbols.
+
+`info w32'
+ This is a prefix of MS Windows specific commands which print
+ information about the target system and important OS structures.
+
+`info w32 selector'
+ This command displays information returned by the Win32 API
+ `GetThreadSelectorEntry' function. It takes an optional argument
+ that is evaluated to a long value to give the information about
+ this given selector. Without argument, this command displays
+ information about the the six segment registers.
+
+`info dll'
+ This is a Cygwin specific alias of info shared.
+
+`dll-symbols'
+ This command loads symbols from a dll similarly to add-sym command
+ but without the need to specify a base address.
+
+`set new-console MODE'
+ If MODE is `on' the debuggee will be started in a new console on
+ next start. If MODE is `off'i, the debuggee will be started in
+ the same console as the debugger.
+
+`show new-console'
+ Displays whether a new console is used when the debuggee is
+ started.
+
+`set new-group MODE'
+ This boolean value controls whether the debuggee should start a
+ new group or stay in the same group as the debugger. This affects
+ the way the Windows OS handles Ctrl-C.
+
+`show new-group'
+ Displays current value of new-group boolean.
+
+`set debugevents'
+ This boolean value adds debug output concerning events seen by the
+ debugger.
+
+`set debugexec'
+ This boolean value adds debug output concerning execute events
+ seen by the debugger.
+
+`set debugexceptions'
+ This boolean value adds debug ouptut concerning exception events
+ seen by the debugger.
+
+`set debugmemory'
+ This boolean value adds debug ouptut concerning memory events seen
+ by the debugger.
+
+`set shell'
+ This boolean values specifies whether the debuggee is called via a
+ shell or directly (default value is on).
+
+`show shell'
+ Displays if the debuggee will be started with a shell.
+
+
+* Menu:
+
+* Non-debug DLL symbols:: Support for DLLs without debugging symbols
+
+
+File: gdb.info, Node: Non-debug DLL symbols, Up: Cygwin Native
+
+Support for DLLs without debugging symbols
+..........................................
+
+Very often on windows, some of the DLLs that your program relies on do
+not include symbolic debugging information (for example,
+`kernel32.dll'). When GDB doesn't recognize any debugging symbols in a
+DLL, it relies on the minimal amount of symbolic information contained
+in the DLL's export table. This subsubsection describes working with
+such symbols, known internally to GDB as "minimal symbols".
+
+ Note that before the debugged program has started execution, no DLLs
+will have been loaded. The easiest way around this problem is simply to
+start the program -- either by setting a breakpoint or letting the
+program run once to completion. It is also possible to force GDB to
+load a particular DLL before starting the executable -- see the shared
+library information in *note Files:: or the `dll-symbols' command in
+*note Cygwin Native::. Currently, explicitly loading symbols from a DLL
+with no debugging information will cause the symbol names to be
+duplicated in GDB's lookup table, which may adversely affect symbol
+lookup performance.
+
+DLL name prefixes
+.................
+
+In keeping with the naming conventions used by the Microsoft debugging
+tools, DLL export symbols are made available with a prefix based on the
+DLL name, for instance `KERNEL32!CreateFileA'. The plain name is also
+entered into the symbol table, so `CreateFileA' is often sufficient. In
+some cases there will be name clashes within a program (particularly if
+the executable itself includes full debugging symbols) necessitating
+the use of the fully qualified name when referring to the contents of
+the DLL. Use single-quotes around the name to avoid the exclamation
+mark ("!") being interpreted as a language operator.
+
+ Note that the internal name of the DLL may be all upper-case, even
+though the file name of the DLL is lower-case, or vice-versa. Since
+symbols within GDB are _case-sensitive_ this may cause some confusion.
+If in doubt, try the `info functions' and `info variables' commands or
+even `maint print msymbols' (see *note Symbols::). Here's an example:
+
+ (gdb) info function CreateFileA
+ All functions matching regular expression "CreateFileA":
+
+ Non-debugging symbols:
+ 0x77e885f4 CreateFileA
+ 0x77e885f4 KERNEL32!CreateFileA
+
+ (gdb) info function !
+ All functions matching regular expression "!":
+
+ Non-debugging symbols:
+ 0x6100114c cygwin1!__assert
+ 0x61004034 cygwin1!_dll_crt0@0
+ 0x61004240 cygwin1!dll_crt0(per_process *)
+ [etc...]
+
+Working with minimal symbols
+............................
+
+Symbols extracted from a DLL's export table do not contain very much
+type information. All that GDB can do is guess whether a symbol refers
+to a function or variable depending on the linker section that contains
+the symbol. Also note that the actual contents of the memory contained
+in a DLL are not available unless the program is running. This means
+that you cannot examine the contents of a variable or disassemble a
+function within a DLL without a running program.
+
+ Variables are generally treated as pointers and dereferenced
+automatically. For this reason, it is often necessary to prefix a
+variable name with the address-of operator ("&") and provide explicit
+type information in the command. Here's an example of the type of
+problem:
+
+ (gdb) print 'cygwin1!__argv'
+ $1 = 268572168
+
+ (gdb) x 'cygwin1!__argv'
+ 0x10021610: "\230y\""
+
+ And two possible solutions:
+
+ (gdb) print ((char **)'cygwin1!__argv')[0]
+ $2 = 0x22fd98 "/cygdrive/c/mydirectory/myprogram"
+
+ (gdb) x/2x &'cygwin1!__argv'
+ 0x610c0aa8 <cygwin1!__argv>: 0x10021608 0x00000000
+ (gdb) x/x 0x10021608
+ 0x10021608: 0x0022fd98
+ (gdb) x/s 0x0022fd98
+ 0x22fd98: "/cygdrive/c/mydirectory/myprogram"
+
+ Setting a break point within a DLL is possible even before the
+program starts execution. However, under these circumstances, GDB can't
+examine the initial instructions of the function in order to skip the
+function's frame set-up code. You can work around this by using "*&" to
+set the breakpoint at a raw memory address:
+
+ (gdb) break *&'python22!PyOS_Readline'
+ Breakpoint 1 at 0x1e04eff0
+
+ The author of these extensions is not entirely convinced that
+setting a break point within a shared DLL like `kernel32.dll' is
+completely safe.
+
+
+File: gdb.info, Node: Embedded OS, Next: Embedded Processors, Prev: Native, Up: Configurations
+
+Embedded Operating Systems
+==========================
+
+This section describes configurations involving the debugging of
+embedded operating systems that are available for several different
+architectures.
+
+* Menu:
+
+* VxWorks:: Using GDB with VxWorks
+
+ GDB includes the ability to debug programs running on various
+real-time operating systems.
+
+
+File: gdb.info, Node: VxWorks, Up: Embedded OS
+
+Using GDB with VxWorks
+----------------------
+
+`target vxworks MACHINENAME'
+ A VxWorks system, attached via TCP/IP. The argument MACHINENAME
+ is the target system's machine name or IP address.
+
+
+ On VxWorks, `load' links FILENAME dynamically on the current target
+system as well as adding its symbols in GDB.
+
+ GDB 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. GDB uses code that runs on
+both the Unix host and on the VxWorks target. The program `gdb' is
+installed and executed on the Unix host. (It may be installed with the
+name `vxgdb', to distinguish it from a GDB for debugging programs on
+the host itself.)
+
+`VxWorks-timeout ARGS'
+ All VxWorks-based targets now support the option `vxworks-timeout'.
+ This option is set by the user, and ARGS represents the number of
+ seconds GDB 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.
+
+ The following information on connecting to VxWorks was current when
+this manual was produced; newer releases of VxWorks may use revised
+procedures.
+
+ To use GDB with VxWorks, you must rebuild your VxWorks kernel to
+include the remote debugging interface routines in the VxWorks library
+`rdb.a'. To do this, define `INCLUDE_RDB' in the VxWorks configuration
+file `configAll.h' and rebuild your VxWorks kernel. The resulting
+kernel contains `rdb.a', and spawns the source debugging task
+`tRdbTask' when VxWorks is booted. For more information on configuring
+and remaking VxWorks, see the manufacturer's manual.
+
+ Once you have included `rdb.a' in your VxWorks system image and set
+your Unix execution search path to find GDB, you are ready to run GDB.
+From your Unix host, run `gdb' (or `vxgdb', depending on your
+installation).
+
+ GDB comes up showing the prompt:
+
+ (vxgdb)
+
+* Menu:
+
+* VxWorks Connection:: Connecting to VxWorks
+* VxWorks Download:: VxWorks download
+* VxWorks Attach:: Running tasks
+
+
+File: gdb.info, Node: VxWorks Connection, Next: VxWorks Download, Up: VxWorks
+
+Connecting to VxWorks
+.....................
+
+The GDB command `target' lets you connect to a VxWorks target on the
+network. To connect to a target whose host name is "`tt'", type:
+
+ (vxgdb) target vxworks tt
+
+ GDB displays messages like these:
+
+ Attaching remote machine across net...
+ Connected to tt.
+
+ GDB then attempts to read the symbol tables of any object modules
+loaded into the VxWorks target since it was last booted. GDB locates
+these files by searching the directories listed in the command search
+path (*note Your program's environment: Environment.); if it fails to
+find an object file, it displays a message such as:
+
+ prog.o: No such file or directory.
+
+ When this happens, add the appropriate directory to the search path
+with the GDB command `path', and execute the `target' command again.
+
+
+File: gdb.info, Node: VxWorks Download, Next: VxWorks Attach, Prev: VxWorks Connection, Up: VxWorks
+
+VxWorks download
+................
+
+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 GDB `load' command
+to download a file from Unix to VxWorks incrementally. The object file
+given as an argument to the `load' command is actually opened twice:
+first by the VxWorks target in order to download the code, then by GDB
+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 `prog.o' may reside in `VXPATH/vw/demo/rdb' in
+VxWorks and in `HOSTPATH/vw/demo/rdb' on the host. To load this
+program, type this on VxWorks:
+
+ -> cd "VXPATH/vw/demo/rdb"
+
+Then, in GDB, type:
+
+ (vxgdb) cd HOSTPATH/vw/demo/rdb
+ (vxgdb) load prog.o
+
+ GDB displays a response similar to this:
+
+ Reading symbol data from wherever/vw/demo/rdb/prog.o... done.
+
+ You can also use the `load' command to reload an object module after
+editing and recompiling the corresponding source file. Note that this
+makes GDB 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's data
+structures that reference the target system's symbol table.)
+
+
+File: gdb.info, Node: VxWorks Attach, Prev: VxWorks Download, Up: VxWorks
+
+Running tasks
+.............
+
+You can also attach to an existing task using the `attach' command as
+follows:
+
+ (vxgdb) attach TASK
+
+where 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.
+
+
+File: gdb.info, Node: Embedded Processors, Next: Architectures, Prev: Embedded OS, Up: Configurations
+
+Embedded Processors
+===================
+
+This section goes into details specific to particular embedded
+configurations.
+
+* Menu:
+
+* ARM:: ARM
+* H8/300:: Renesas H8/300
+* H8/500:: Renesas H8/500
+* M32R/D:: Renesas M32R/D
+* M68K:: Motorola M68K
+* MIPS Embedded:: MIPS Embedded
+* OpenRISC 1000:: OpenRisc 1000
+* PA:: HP PA Embedded
+* PowerPC: PowerPC
+* SH:: Renesas SH
+* Sparclet:: Tsqware Sparclet
+* Sparclite:: Fujitsu Sparclite
+* ST2000:: Tandem ST2000
+* Z8000:: Zilog Z8000
+
+
+File: gdb.info, Node: ARM, Next: H8/300, Up: Embedded Processors
+
+ARM
+---
+
+`target rdi DEV'
+ ARM Angel monitor, via RDI library interface to ADP protocol. You
+ may use this target to communicate with both boards running the
+ Angel monitor, or with the EmbeddedICE JTAG debug device.
+
+`target rdp DEV'
+ ARM Demon monitor.
+
+
+
+File: gdb.info, Node: H8/300, Next: H8/500, Prev: ARM, Up: Embedded Processors
+
+Renesas H8/300
+--------------
+
+`target hms DEV'
+ A Renesas SH, H8/300, or H8/500 board, attached via serial line to
+ your host. Use special commands `device' and `speed' to control
+ the serial line and the communications speed used.
+
+`target e7000 DEV'
+ E7000 emulator for Renesas H8 and SH.
+
+`target sh3 DEV'
+`target sh3e DEV'
+ Renesas SH-3 and SH-3E target systems.
+
+
+ When you select remote debugging to a Renesas SH, H8/300, or H8/500
+board, the `load' command downloads your program to the Renesas board
+and also opens it as the current executable target for GDB on your host
+(like the `file' command).
+
+ GDB needs to know these things to talk to your Renesas SH, H8/300,
+or H8/500:
+
+ 1. that you want to use `target hms', the remote debugging interface
+ for Renesas microprocessors, or `target e7000', the in-circuit
+ emulator for the Renesas SH and the Renesas 300H. (`target hms' is
+ the default when GDB is configured specifically for the Renesas SH,
+ H8/300, or H8/500.)
+
+ 2. what serial device connects your host to your Renesas board (the
+ first serial device available on your host is the default).
+
+ 3. what speed to use over the serial device.
+
+* Menu:
+
+* Renesas Boards:: Connecting to Renesas boards.
+* Renesas ICE:: Using the E7000 In-Circuit Emulator.
+* Renesas Special:: Special GDB commands for Renesas micros.
+
+
+File: gdb.info, Node: Renesas Boards, Next: Renesas ICE, Up: H8/300
+
+Connecting to Renesas boards
+............................
+
+Use the special `GDB' command `device PORT' if you need to explicitly
+set the serial device. The default PORT is the first available port on
+your host. This is only necessary on Unix hosts, where it is typically
+something like `/dev/ttya'.
+
+ `GDB' has another special command to set the communications speed:
+`speed 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 `mode'
+command (for instance, `mode com2:9600,n,8,1,p' for a 9600bps
+connection).
+
+ The `device' and `speed' commands are available only when you use a
+Unix host to debug your Renesas microprocessor programs. If you use a
+DOS host, GDB depends on an auxiliary terminate-and-stay-resident
+program called `asynctsr' to communicate with the development board
+through a PC serial port. You must also use the DOS `mode' command to
+set up the serial port on the DOS side.
+
+ The following sample session illustrates the steps needed to start a
+program under GDB control on an H8/300. The example uses a sample
+H8/300 program called `t.x'. The procedure is the same for the Renesas
+SH and the H8/500.
+
+ First hook up your development board. In this example, we use a
+board attached to serial port `COM2'; if you use a different serial
+port, substitute its name in the argument of the `mode' command. When
+you call `asynctsr', the auxiliary comms program used by the debugger,
+you give it just the numeric part of the serial port's name; for
+example, `asyncstr 2' below runs `asyncstr' on `COM2'.
+
+ 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
+
+ _Warning:_ We have noticed a bug in PC-NFS that conflicts with
+ `asynctsr'. If you also run PC-NFS on your DOS host, you may need
+ to disable it, or even boot without it, to use `asynctsr' to
+ control your development board.
+
+ Now that serial communications are set up, and the development board
+is connected, you can start up GDB. Call `gdb' with the name of your
+program as the argument. `GDB' prompts you, as usual, with the prompt
+`(gdb)'. Use two special commands to begin your debugging session:
+`target hms' to specify cross-debugging to the Renesas board, and the
+`load' command to download your program to the board. `load' displays
+the names of the program's sections, and a `*' for each 2K of data
+downloaded. (If you want to refresh GDB data on symbols or on the
+executable file without downloading, use the GDB commands `file' or
+`symbol-file'. These commands, and `load' itself, are described in
+*Note Commands to specify files: Files.)
+
+ (eg-C:\H8300\TEST) gdb 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 6.1.1, 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 *
+
+ At this point, you're ready to run or debug your program. From here
+on, you can use all the usual GDB commands. The `break' command sets
+breakpoints; the `run' command starts your program; `print' or `x'
+display data; the `continue' command resumes execution after stopping
+at a breakpoint. You can use the `help' command at any time to find
+out more about GDB commands.
+
+ Remember, however, that _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 RESET switch!
+
+ Use the RESET button on the development board
+ * to interrupt your program (don't use `ctl-C' on the DOS host--it
+ has no way to pass an interrupt signal to the development board);
+ and
+
+ * to return to the GDB command prompt after your program finishes
+ normally. The communications protocol provides no other way for
+ GDB to detect program completion.
+
+ In either case, GDB sees the effect of a RESET on the development
+board as a "normal exit" of your program.
+
+
+File: gdb.info, Node: Renesas ICE, Next: Renesas Special, Prev: Renesas Boards, Up: H8/300
+
+Using the E7000 in-circuit emulator
+...................................
+
+You can use the E7000 in-circuit emulator to develop code for either the
+Renesas SH or the H8/300H. Use one of these forms of the `target
+e7000' command to connect GDB to your E7000:
+
+`target e7000 PORT SPEED'
+ Use this form if your E7000 is connected to a serial port. The
+ PORT argument identifies what serial port to use (for example,
+ `com2'). The third argument is the line speed in bits per second
+ (for example, `9600').
+
+`target e7000 HOSTNAME'
+ If your E7000 is installed as a host on a TCP/IP network, you can
+ just specify its hostname; GDB uses `telnet' to connect.
+
+
+File: gdb.info, Node: Renesas Special, Prev: Renesas ICE, Up: H8/300
+
+Special GDB commands for Renesas micros
+.......................................
+
+Some GDB commands are available only for the H8/300:
+
+`set machine h8300'
+`set machine h8300h'
+ Condition GDB for one of the two variants of the H8/300
+ architecture with `set machine'. You can use `show machine' to
+ check which variant is currently in effect.
+
+
+
+File: gdb.info, Node: H8/500, Next: M32R/D, Prev: H8/300, Up: Embedded Processors
+
+H8/500
+------
+
+`set memory MOD'
+`show memory'
+ Specify which H8/500 memory model (MOD) you are using with `set
+ memory'; check which memory model is in effect with `show memory'.
+ The accepted values for MOD are `small', `big', `medium', and
+ `compact'.
+
+
+
+File: gdb.info, Node: M32R/D, Next: M68K, Prev: H8/500, Up: Embedded Processors
+
+Renesas M32R/D
+--------------
+
+`target m32r DEV'
+ Renesas M32R/D ROM monitor.
+
+`target m32rsdi DEV'
+ Renesas M32R SDI server, connected via parallel port to the board.
+
+
+
+File: gdb.info, Node: M68K, Next: MIPS Embedded, Prev: M32R/D, Up: Embedded Processors
+
+M68k
+----
+
+The Motorola m68k configuration includes ColdFire support, and target
+command for the following ROM monitors.
+
+`target abug DEV'
+ ABug ROM monitor for M68K.
+
+`target cpu32bug DEV'
+ CPU32BUG monitor, running on a CPU32 (M68K) board.
+
+`target dbug DEV'
+ dBUG ROM monitor for Motorola ColdFire.
+
+`target est DEV'
+ EST-300 ICE monitor, running on a CPU32 (M68K) board.
+
+`target rom68k DEV'
+ ROM 68K monitor, running on an M68K IDP board.
+
+
+`target rombug DEV'
+ ROMBUG ROM monitor for OS/9000.
+
+
+
+File: gdb.info, Node: MIPS Embedded, Next: OpenRISC 1000, Prev: M68K, Up: Embedded Processors
+
+MIPS Embedded
+-------------
+
+GDB can use the MIPS remote debugging protocol to talk to a MIPS board
+attached to a serial line. This is available when you configure GDB
+with `--target=mips-idt-ecoff'.
+
+ Use these GDB commands to specify the connection to your target
+board:
+
+`target mips PORT'
+ To run a program on the board, start up `gdb' with the name of
+ your program as the argument. To connect to the board, use the
+ command `target mips PORT', where 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 `load' command to
+ download it. You can then use all the usual GDB commands.
+
+ For example, this sequence connects to the target board through a
+ serial port, and loads and runs a program called PROG through the
+ debugger:
+
+ host$ gdb PROG
+ GDB is free software and ...
+ (gdb) target mips /dev/ttyb
+ (gdb) load PROG
+ (gdb) run
+
+`target mips HOSTNAME:PORTNUMBER'
+ On some GDB 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
+ `HOSTNAME:PORTNUMBER'.
+
+`target pmon PORT'
+ PMON ROM monitor.
+
+`target ddb PORT'
+ NEC's DDB variant of PMON for Vr4300.
+
+`target lsi PORT'
+ LSI variant of PMON.
+
+`target r3900 DEV'
+ Densan DVE-R3900 ROM monitor for Toshiba R3900 Mips.
+
+`target array DEV'
+ Array Tech LSI33K RAID controller board.
+
+
+GDB also supports these special commands for MIPS targets:
+
+`set processor ARGS'
+`show processor'
+ Use the `set processor' command to set the type of MIPS processor
+ when you want to access processor-type-specific registers. For
+ example, `set processor R3041' tells GDB to use the CPU registers
+ appropriate for the 3041 chip. Use the `show processor' command
+ to see what MIPS processor GDB is using. Use the `info reg'
+ command to see what registers GDB is using.
+
+`set mipsfpu double'
+`set mipsfpu single'
+`set mipsfpu none'
+`show mipsfpu'
+ If your target board does not support the MIPS floating point
+ coprocessor, you should use the command `set mipsfpu none' (if you
+ need this, you may wish to put the command in your GDB init file).
+ This tells GDB how to find the return value of functions which
+ return floating point values. It also allows GDB 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 R4650 processor, use
+ the command `set mipsfpu single'. The default double precision
+ floating point coprocessor may be selected using `set mipsfpu
+ double'.
+
+ In previous versions the only choices were double precision or no
+ floating point, so `set mipsfpu on' will select double precision
+ and `set mipsfpu off' will select no floating point.
+
+ As usual, you can inquire about the `mipsfpu' variable with `show
+ mipsfpu'.
+
+`set remotedebug N'
+`show remotedebug'
+ You can see some debugging information about communications with
+ the board by setting the `remotedebug' variable. If you set it to
+ `1' using `set remotedebug 1', every packet is displayed. If you
+ set it to `2', every character is displayed. You can check the
+ current value at any time with the command `show remotedebug'.
+
+`set timeout SECONDS'
+`set retransmit-timeout SECONDS'
+`show timeout'
+`show retransmit-timeout'
+ You can control the timeout used while waiting for a packet, in
+ the MIPS remote protocol, with the `set timeout SECONDS' command.
+ The default is 5 seconds. Similarly, you can control the timeout
+ used while waiting for an acknowledgement of a packet with the `set
+ retransmit-timeout SECONDS' command. The default is 3 seconds.
+ You can inspect both values with `show timeout' and `show
+ retransmit-timeout'. (These commands are _only_ available when
+ GDB is configured for `--target=mips-idt-ecoff'.)
+
+ The timeout set by `set timeout' does not apply when GDB is
+ waiting for your program to stop. In that case, GDB waits forever
+ because it has no way of knowing how long the program is going to
+ run before stopping.
+
+
+File: gdb.info, Node: OpenRISC 1000, Next: PA, Prev: MIPS Embedded, Up: Embedded Processors
+
+OpenRISC 1000
+-------------
+
+See OR1k Architecture document (`www.opencores.org') for more
+information about platform and commands.
+
+`target jtag jtag://HOST:PORT'
+ Connects to remote JTAG server. JTAG remote server can be either
+ an or1ksim or JTAG server, connected via parallel port to the
+ board.
+
+ Example: `target jtag jtag://localhost:9999'
+
+`or1ksim COMMAND'
+ If connected to `or1ksim' OpenRISC 1000 Architectural Simulator,
+ proprietary commands can be executed.
+
+`info or1k spr'
+ Displays spr groups.
+
+`info or1k spr GROUP'
+`info or1k spr GROUPNO'
+ Displays register names in selected group.
+
+`info or1k spr GROUP REGISTER'
+`info or1k spr REGISTER'
+`info or1k spr GROUPNO REGISTERNO'
+`info or1k spr REGISTERNO'
+ Shows information about specified spr register.
+
+`spr GROUP REGISTER VALUE'
+`spr REGISTER VALUE'
+`spr GROUPNO REGISTERNO VALUE'
+`spr REGISTERNO VALUE'
+ Writes VALUE to specified spr register.
+
+ Some implementations of OpenRISC 1000 Architecture also have
+hardware trace. It is very similar to GDB trace, except it does not
+interfere with normal program execution and is thus much faster.
+Hardware breakpoints/watchpoint triggers can be set using:
+`$LEA/$LDATA'
+ Load effective address/data
+
+`$SEA/$SDATA'
+ Store effective address/data
+
+`$AEA/$ADATA'
+ Access effective address ($SEA or $LEA) or data ($SDATA/$LDATA)
+
+`$FETCH'
+ Fetch data
+
+ When triggered, it can capture low level data, like: `PC', `LSEA',
+`LDATA', `SDATA', `READSPR', `WRITESPR', `INSTR'.
+
+ `htrace' commands:
+`hwatch CONDITIONAL'
+ Set hardware watchpoint on combination of Load/Store Effecive
+ Address(es) or Data. For example:
+
+ `hwatch ($LEA == my_var) && ($LDATA < 50) || ($SEA == my_var) &&
+ ($SDATA >= 50)'
+
+ `hwatch ($LEA == my_var) && ($LDATA < 50) || ($SEA == my_var) &&
+ ($SDATA >= 50)'
+
+`htrace info'
+ Display information about current HW trace configuration.
+
+`htrace trigger CONDITIONAL'
+ Set starting criteria for HW trace.
+
+`htrace qualifier CONDITIONAL'
+ Set acquisition qualifier for HW trace.
+
+`htrace stop CONDITIONAL'
+ Set HW trace stopping criteria.
+
+`htrace record [DATA]*'
+ Selects the data to be recorded, when qualifier is met and HW
+ trace was triggered.
+
+`htrace enable'
+`htrace disable'
+ Enables/disables the HW trace.
+
+`htrace rewind [FILENAME]'
+ Clears currently recorded trace data.
+
+ If filename is specified, new trace file is made and any newly
+ collected data will be written there.
+
+`htrace print [START [LEN]]'
+ Prints trace buffer, using current record configuration.
+
+`htrace mode continuous'
+ Set continuous trace mode.
+
+`htrace mode suspend'
+ Set suspend trace mode.
+
+
+
+File: gdb.info, Node: PowerPC, Next: SH, Prev: PA, Up: Embedded Processors
+
+PowerPC
+-------
+
+`target dink32 DEV'
+ DINK32 ROM monitor.
+
+`target ppcbug DEV'
+
+`target ppcbug1 DEV'
+ PPCBUG ROM monitor for PowerPC.
+
+`target sds DEV'
+ SDS monitor, running on a PowerPC board (such as Motorola's ADS).
+
+
+
+File: gdb.info, Node: PA, Next: PowerPC, Prev: OpenRISC 1000, Up: Embedded Processors
+
+HP PA Embedded
+--------------
+
+`target op50n DEV'
+ OP50N monitor, running on an OKI HPPA board.
+
+`target w89k DEV'
+ W89K monitor, running on a Winbond HPPA board.
+
+
+
+File: gdb.info, Node: SH, Next: Sparclet, Prev: PowerPC, Up: Embedded Processors
+
+Renesas SH
+----------
+
+`target hms DEV'
+ A Renesas SH board attached via serial line to your host. Use
+ special commands `device' and `speed' to control the serial line
+ and the communications speed used.
+
+`target e7000 DEV'
+ E7000 emulator for Renesas SH.
+
+`target sh3 DEV'
+
+`target sh3e DEV'
+ Renesas SH-3 and SH-3E target systems.
+
+
+
+File: gdb.info, Node: Sparclet, Next: Sparclite, Prev: SH, Up: Embedded Processors
+
+Tsqware Sparclet
+----------------
+
+GDB enables developers to debug tasks running on Sparclet targets from
+a Unix host. GDB uses code that runs on both the Unix host and on the
+Sparclet target. The program `gdb' is installed and executed on the
+Unix host.
+
+`remotetimeout ARGS'
+ GDB supports the option `remotetimeout'. This option is set by
+ the user, and ARGS represents the number of seconds GDB waits for
+ responses.
+
+ When compiling for debugging, include the options `-g' to get debug
+information and `-Ttext' to relocate the program to where you wish to
+load it on the target. You may also want to add the options `-n' or
+`-N' in order to reduce the size of the sections. Example:
+
+ sparclet-aout-gcc prog.c -Ttext 0x12010000 -g -o prog -N
+
+ You can use `objdump' to verify that the addresses are what you
+intended:
+
+ sparclet-aout-objdump --headers --syms prog
+
+ Once you have set your Unix execution search path to find GDB, you
+are ready to run GDB. From your Unix host, run `gdb' (or
+`sparclet-aout-gdb', depending on your installation).
+
+ GDB comes up showing the prompt:
+
+ (gdbslet)
+
+* Menu:
+
+* Sparclet File:: Setting the file to debug
+* Sparclet Connection:: Connecting to Sparclet
+* Sparclet Download:: Sparclet download
+* Sparclet Execution:: Running and debugging
+
+
+File: gdb.info, Node: Sparclet File, Next: Sparclet Connection, Up: Sparclet
+
+Setting file to debug
+.....................
+
+The GDB command `file' lets you choose with program to debug.
+
+ (gdbslet) file prog
+
+ GDB then attempts to read the symbol table of `prog'. GDB locates
+the file by searching the directories listed in the command search path.
+If the file was compiled with debug information (option "-g"), source
+files will be searched as well. GDB locates the source files by
+searching the directories listed in the directory search path (*note
+Your program's environment: Environment.). If it fails to find a file,
+it displays a message such as:
+
+ prog: No such file or directory.
+
+ When this happens, add the appropriate directories to the search
+paths with the GDB commands `path' and `dir', and execute the `target'
+command again.
+
+
+File: gdb.info, Node: Sparclet Connection, Next: Sparclet Download, Prev: Sparclet File, Up: Sparclet
+
+Connecting to Sparclet
+......................
+
+The GDB command `target' lets you connect to a Sparclet target. To
+connect to a target on serial port "`ttya'", type:
+
+ (gdbslet) target sparclet /dev/ttya
+ Remote target sparclet connected to /dev/ttya
+ main () at ../prog.c:3
+
+ GDB displays messages like these:
+
+ Connected to ttya.
+
+
+File: gdb.info, Node: Sparclet Download, Next: Sparclet Execution, Prev: Sparclet Connection, Up: Sparclet
+
+Sparclet download
+.................
+
+Once connected to the Sparclet target, you can use the GDB `load'
+command to download the file from the host to the target. The file
+name and load offset should be given as arguments to the `load' command.
+Since the file format is aout, the program must be loaded to the
+starting address. You can use `objdump' to find out what this value
+is. The load offset is an offset which is added to the VMA (virtual
+memory address) of each of the file's sections. For instance, if the
+program `prog' was linked to text address 0x1201000, with data at
+0x12010160 and bss at 0x12010170, in GDB, type:
+
+ (gdbslet) load prog 0x12010000
+ Loading section .text, size 0xdb0 vma 0x12010000
+
+ If the code is loaded at a different address then what the program
+was linked to, you may need to use the `section' and `add-symbol-file'
+commands to tell GDB where to map the symbol table.
+
+
+File: gdb.info, Node: Sparclet Execution, Prev: Sparclet Download, Up: Sparclet
+
+Running and debugging
+.....................
+
+You can now begin debugging the task using GDB's execution control
+commands, `b', `step', `run', etc. See the GDB manual for the list of
+commands.
+
+ (gdbslet) b main
+ Breakpoint 1 at 0x12010000: file prog.c, line 3.
+ (gdbslet) run
+ Starting program: prog
+ Breakpoint 1, main (argc=1, argv=0xeffff21c) at prog.c:3
+ 3 char *symarg = 0;
+ (gdbslet) step
+ 4 char *execarg = "hello!";
+ (gdbslet)
+
+
+File: gdb.info, Node: Sparclite, Next: ST2000, Prev: Sparclet, Up: Embedded Processors
+
+Fujitsu Sparclite
+-----------------
+
+`target sparclite 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 DEV using GDB standard remote protocol.
+
+
+
+File: gdb.info, Node: ST2000, Next: Z8000, Prev: Sparclite, Up: Embedded Processors
+
+Tandem ST2000
+-------------
+
+GDB may be used with a Tandem ST2000 phone switch, running Tandem's
+STDBUG protocol.
+
+ To connect your ST2000 to the host system, see the manufacturer's
+manual. Once the ST2000 is physically attached, you can run:
+
+ target st2000 DEV SPEED
+
+to establish it as your debugging environment. DEV is normally the
+name of a serial device, such as `/dev/ttya', connected to the ST2000
+via a serial line. You can instead specify DEV as a TCP connection
+(for example, to a serial line attached via a terminal concentrator)
+using the syntax `HOSTNAME:PORTNUMBER'.
+
+ The `load' and `attach' commands are _not_ defined for this target;
+you must load your program into the ST2000 as you normally would for
+standalone operation. GDB reads debugging information (such as
+symbols) from a separate, debugging version of the program available on
+your host computer.
+
+ These auxiliary GDB commands are available to help you with the
+ST2000 environment:
+
+`st2000 COMMAND'
+ Send a COMMAND to the STDBUG monitor. See the manufacturer's
+ manual for available commands.
+
+`connect'
+ 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 GDB command prompt:
+ `<RET>~.' (Return, followed by tilde and period) or `<RET>~<C-d>'
+ (Return, followed by tilde and control-D).
+
+
+File: gdb.info, Node: Z8000, Prev: ST2000, Up: Embedded Processors
+
+Zilog Z8000
+-----------
+
+When configured for debugging Zilog Z8000 targets, GDB includes a Z8000
+simulator.
+
+ For the Z8000 family, `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.
+
+`target sim ARGS'
+ Debug programs on a simulated CPU. If the simulator supports setup
+ options, specify them via ARGS.
+
+After specifying this target, you can debug programs for the simulated
+CPU in the same style as programs for your host computer; use the
+`file' command to load a new program image, the `run' command to run
+your program, and so on.
+
+ As well as making available all the usual machine registers (*note
+Registers: Registers.), the Z8000 simulator provides three additional
+items of information as specially named registers:
+
+`cycles'
+ Counts clock-ticks in the simulator.
+
+`insts'
+ Counts instructions run in the simulator.
+
+`time'
+ Execution time in 60ths of a second.
+
+
+ You can refer to these values in GDB expressions with the usual
+conventions; for example, `b fputc if $cycles>5000' sets a conditional
+breakpoint that suspends only after at least 5000 simulated clock ticks.
+
+
+File: gdb.info, Node: Architectures, Prev: Embedded Processors, Up: Configurations
+
+Architectures
+=============
+
+This section describes characteristics of architectures that affect all
+uses of GDB with the architecture, both native and cross.
+
+* Menu:
+
+* A29K::
+* Alpha::
+* MIPS::
+
+
+File: gdb.info, Node: A29K, Next: Alpha, Up: Architectures
+
+A29K
+----
+
+`set rstack_high_address ADDRESS'
+ On AMD 29000 family processors, registers are saved in a separate
+ "register stack". There is no way for GDB to determine the extent
+ of this stack. Normally, GDB just assumes that the stack is
+ "large enough". This may result in GDB 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 `set rstack_high_address' command. The argument
+ should be an address, which you probably want to precede with `0x'
+ to specify in hexadecimal.
+
+`show rstack_high_address'
+ Display the current limit of the register stack, on AMD 29000
+ family processors.
+
+
+
+File: gdb.info, Node: Alpha, Next: MIPS, Prev: A29K, Up: Architectures
+
+Alpha
+-----
+
+See the following section.
+
+
+File: gdb.info, Node: MIPS, Prev: Alpha, Up: Architectures
+
+MIPS
+----
+
+Alpha- and MIPS-based computers use an unusual stack frame, which
+sometimes requires GDB to search backward in the object code to find
+the beginning of a function.
+
+ To improve response time (especially for embedded applications, where
+GDB 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:
+
+`set heuristic-fence-post LIMIT'
+ Restrict GDB to examining at most LIMIT bytes in its search for
+ the beginning of a function. A value of 0 (the default) means
+ there is no limit. However, except for 0, the larger the limit
+ the more bytes `heuristic-fence-post' must search and therefore
+ the longer it takes to run.
+
+`show heuristic-fence-post'
+ Display the current limit.
+
+These commands are available _only_ when GDB is configured for
+debugging programs on Alpha or MIPS processors.
+
+
+File: gdb.info, Node: Controlling GDB, Next: Sequences, Prev: Configurations, Up: Top
+
+Controlling GDB
+***************
+
+You can alter the way GDB interacts with you by using the `set'
+command. For commands controlling how GDB displays data, see *Note
+Print settings: Print Settings. Other settings are described here.
+
+* Menu:
+
+* Prompt:: Prompt
+* Editing:: Command editing
+* History:: Command history
+* Screen Size:: Screen size
+* Numbers:: Numbers
+* ABI:: Configuring the current ABI
+* Messages/Warnings:: Optional warnings and messages
+* Debugging Output:: Optional messages about internal happenings
+
+
+File: gdb.info, Node: Prompt, Next: Editing, Up: Controlling GDB
+
+Prompt
+======
+
+GDB indicates its readiness to read a command by printing a string
+called the "prompt". This string is normally `(gdb)'. You can change
+the prompt string with the `set prompt' command. For instance, when
+debugging GDB with GDB, it is useful to change the prompt in one of the
+GDB sessions so that you can always tell which one you are talking to.
+
+ _Note:_ `set prompt' does not add 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.
+
+`set prompt NEWPROMPT'
+ Directs GDB to use NEWPROMPT as its prompt string henceforth.
+
+`show prompt'
+ Prints a line of the form: `Gdb's prompt is: YOUR-PROMPT'
+
+
+File: gdb.info, Node: Editing, Next: History, Prev: Prompt, Up: Controlling GDB
+
+Command editing
+===============
+
+GDB reads its input commands via the "readline" interface. This GNU
+library provides consistent behavior for programs which provide a
+command line interface to the user. Advantages are GNU Emacs-style or
+"vi"-style inline editing of commands, `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 GDB with the
+command `set'.
+
+`set editing'
+`set editing on'
+ Enable command line editing (enabled by default).
+
+`set editing off'
+ Disable command line editing.
+
+`show editing'
+ Show whether command line editing is enabled.
+
+
+File: gdb.info, Node: History, Next: Screen Size, Prev: Editing, Up: Controlling GDB
+
+Command history
+===============
+
+GDB 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 GDB command history facility.
+
+`set history filename FNAME'
+ Set the name of the GDB command history file to FNAME. This is
+ the file where GDB 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
+ `GDBHISTFILE', or to `./.gdb_history' (`./_gdb_history' on MS-DOS)
+ if this variable is not set.
+
+`set history save'
+`set history save on'
+ Record command history in a file, whose name may be specified with
+ the `set history filename' command. By default, this option is
+ disabled.
+
+`set history save off'
+ Stop recording command history in a file.
+
+`set history size SIZE'
+ Set the number of commands which GDB keeps in its history list.
+ This defaults to the value of the environment variable `HISTSIZE',
+ or to 256 if this variable is not set.
+
+ History expansion assigns special meaning to the character `!'.
+
+ Since `!' is also the logical not operator in C, history expansion
+is off by default. If you decide to enable history expansion with the
+`set history expansion on' command, you may sometimes need to follow
+`!' (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 `!=' and `!(',
+even when history expansion is enabled.
+
+ The commands to control history expansion are:
+
+`set history expansion on'
+`set history expansion'
+ Enable history expansion. History expansion is off by default.
+
+`set history expansion off'
+ Disable history expansion.
+
+ The readline code comes with more complete documentation of
+ editing and history expansion features. Users unfamiliar with GNU
+ Emacs or `vi' may wish to read it.
+
+`show history'
+`show history filename'
+`show history save'
+`show history size'
+`show history expansion'
+ These commands display the state of the GDB history parameters.
+ `show history' by itself displays all four states.
+
+`show commands'
+ Display the last ten commands in the command history.
+
+`show commands N'
+ Print ten commands centered on command number N.
+
+`show commands +'
+ Print ten commands just after the commands last printed.
+
+
+File: gdb.info, Node: Screen Size, Next: Numbers, Prev: History, Up: Controlling GDB
+
+Screen size
+===========
+
+Certain commands to GDB may produce large amounts of information output
+to the screen. To help you read all of it, GDB pauses and asks you for
+input at the end of each page of output. Type <RET> when you want to
+continue the output, or `q' to discard the remaining output. Also, the
+screen width setting determines when to wrap lines of output.
+Depending on what is being printed, GDB tries to break the line at a
+readable place, rather than simply letting it overflow onto the
+following line.
+
+ Normally GDB knows the size of the screen from the terminal driver
+software. For example, on Unix GDB uses the termcap data base together
+with the value of the `TERM' environment variable and the `stty rows'
+and `stty cols' settings. If this is not correct, you can override it
+with the `set height' and `set width' commands:
+
+`set height LPP'
+`show height'
+`set width CPL'
+`show width'
+ These `set' commands specify a screen height of LPP lines and a
+ screen width of CPL characters. The associated `show' commands
+ display the current settings.
+
+ If you specify a height of zero lines, GDB 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 `set width 0' to prevent GDB from
+ wrapping its output.
+
+
+File: gdb.info, Node: Numbers, Next: ABI, Prev: Screen Size, Up: Controlling GDB
+
+Numbers
+=======
+
+You can always enter numbers in octal, decimal, or hexadecimal in GDB
+by the usual conventions: octal numbers begin with `0', decimal numbers
+end with `.', and hexadecimal numbers begin with `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 `set radix' command.
+
+`set input-radix BASE'
+ Set the default base for numeric input. Supported choices for
+ BASE are decimal 8, 10, or 16. BASE must itself be specified
+ either unambiguously or using the current default radix; for
+ example, any of
+
+ set radix 012
+ set radix 10.
+ set radix 0xa
+
+ sets the base to decimal. On the other hand, `set radix 10'
+ leaves the radix unchanged no matter what it was.
+
+`set output-radix BASE'
+ Set the default base for numeric display. Supported choices for
+ BASE are decimal 8, 10, or 16. BASE must itself be specified
+ either unambiguously or using the current default radix.
+
+`show input-radix'
+ Display the current default base for numeric input.
+
+`show output-radix'
+ Display the current default base for numeric display.
+
+
+File: gdb.info, Node: ABI, Next: Messages/Warnings, Prev: Numbers, Up: Controlling GDB
+
+Configuring the current ABI
+===========================
+
+GDB can determine the "ABI" (Application Binary Interface) of your
+application automatically. However, sometimes you need to override its
+conclusions. Use these commands to manage GDB's view of the current
+ABI.
+
+ One GDB configuration can debug binaries for multiple operating
+system targets, either via remote debugging or native emulation. GDB
+will autodetect the "OS ABI" (Operating System ABI) in use, but you can
+override its conclusion using the `set osabi' command. One example
+where this is useful is in debugging of binaries which use an alternate
+C library (e.g. UCLIBC for GNU/Linux) which does not have the same
+identifying marks that the standard C library for your platform
+provides.
+
+`show osabi'
+ Show the OS ABI currently in use.
+
+`set osabi'
+ With no argument, show the list of registered available OS ABI's.
+
+`set osabi ABI'
+ Set the current OS ABI to ABI.
+
+ Generally, the way that an argument of type `float' is passed to a
+function depends on whether the function is prototyped. For a
+prototyped (i.e. ANSI/ISO style) function, `float' arguments are passed
+unchanged, according to the architecture's convention for `float'. For
+unprototyped (i.e. K&R style) functions, `float' arguments are first
+promoted to type `double' and then passed.
+
+ Unfortunately, some forms of debug information do not reliably
+indicate whether a function is prototyped. If GDB calls a function
+that is not marked as prototyped, it consults `set
+coerce-float-to-double'.
+
+`set coerce-float-to-double'
+`set coerce-float-to-double on'
+ Arguments of type `float' will be promoted to `double' when passed
+ to an unprototyped function. This is the default setting.
+
+`set coerce-float-to-double off'
+ Arguments of type `float' will be passed directly to unprototyped
+ functions.
+
+ GDB needs to know the ABI used for your program's C++ objects. The
+correct C++ ABI depends on which C++ compiler was used to build your
+application. GDB only fully supports programs with a single C++ ABI;
+if your program contains code using multiple C++ ABI's or if GDB can
+not identify your program's ABI correctly, you can tell GDB which ABI
+to use. Currently supported ABI's include "gnu-v2", for `g++' versions
+before 3.0, "gnu-v3", for `g++' versions 3.0 and later, and "hpaCC" for
+the HP ANSI C++ compiler. Other C++ compilers may use the "gnu-v2" or
+"gnu-v3" ABI's as well. The default setting is "auto".
+
+`show cp-abi'
+ Show the C++ ABI currently in use.
+
+`set cp-abi'
+ With no argument, show the list of supported C++ ABI's.
+
+`set cp-abi ABI'
+`set cp-abi auto'
+ Set the current C++ ABI to ABI, or return to automatic detection.
+
+
+File: gdb.info, Node: Messages/Warnings, Next: Debugging Output, Prev: ABI, Up: Controlling GDB
+
+Optional warnings and messages
+==============================
+
+By default, GDB is silent about its inner workings. If you are running
+on a slow machine, you may want to use the `set verbose' command. This
+makes GDB tell you when it does a lengthy internal operation, so you
+will not think it has crashed.
+
+ Currently, the messages controlled by `set verbose' are those which
+announce that the symbol table for a source file is being read; see
+`symbol-file' in *Note Commands to specify files: Files.
+
+`set verbose on'
+ Enables GDB output of certain informational messages.
+
+`set verbose off'
+ Disables GDB output of certain informational messages.
+
+`show verbose'
+ Displays whether `set verbose' is on or off.
+
+ By default, if GDB 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 (*note Errors reading symbol files: Symbol
+Errors.).
+
+`set complaints LIMIT'
+ Permits GDB to output LIMIT complaints about each type of unusual
+ symbols before becoming silent about the problem. Set LIMIT to
+ zero to suppress all complaints; set it to a large number to
+ prevent complaints from being suppressed.
+
+`show complaints'
+ Displays how many symbol complaints GDB is permitted to produce.
+
+
+ By default, GDB 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:
+
+ (gdb) run
+ The program being debugged has been started already.
+ Start it from the beginning? (y or n)
+
+ If you are willing to unflinchingly face the consequences of your own
+commands, you can disable this "feature":
+
+`set confirm off'
+ Disables confirmation requests.
+
+`set confirm on'
+ Enables confirmation requests (the default).
+
+`show confirm'
+ Displays state of confirmation requests.
+
+
+
+File: gdb.info, Node: Debugging Output, Prev: Messages/Warnings, Up: Controlling GDB
+
+Optional messages about internal happenings
+===========================================
+
+`set debug arch'
+ Turns on or off display of gdbarch debugging info. The default is
+ off
+
+`show debug arch'
+ Displays the current state of displaying gdbarch debugging info.
+
+`set debug event'
+ Turns on or off display of GDB event debugging info. The default
+ is off.
+
+`show debug event'
+ Displays the current state of displaying GDB event debugging info.
+
+`set debug expression'
+ Turns on or off display of GDB expression debugging info. The
+ default is off.
+
+`show debug expression'
+ Displays the current state of displaying GDB expression debugging
+ info.
+
+`set debug frame'
+ Turns on or off display of GDB frame debugging info. The default
+ is off.
+
+`show debug frame'
+ Displays the current state of displaying GDB frame debugging info.
+
+`set debug overload'
+ Turns on or off display of GDB C++ overload debugging info. This
+ includes info such as ranking of functions, etc. The default is
+ off.
+
+`show debug overload'
+ Displays the current state of displaying GDB C++ overload
+ debugging info.
+
+`set debug remote'
+ Turns on or off display of reports on all packets sent back and
+ forth across the serial line to the remote machine. The info is
+ printed on the GDB standard output stream. The default is off.
+
+`show debug remote'
+ Displays the state of display of remote packets.
+
+`set debug serial'
+ Turns on or off display of GDB serial debugging info. The default
+ is off.
+
+`show debug serial'
+ Displays the current state of displaying GDB serial debugging info.
+
+`set debug target'
+ Turns on or off display of GDB target debugging info. This info
+ includes what is going on at the target level of GDB, as it
+ happens. The default is off.
+
+`show debug target'
+ Displays the current state of displaying GDB target debugging info.
+
+`set debug varobj'
+ Turns on or off display of GDB variable object debugging info. The
+ default is off.
+
+`show debug varobj'
+ Displays the current state of displaying GDB variable object
+ debugging info.
+
+
+File: gdb.info, Node: Sequences, Next: TUI, Prev: Controlling GDB, Up: Top
+
+Canned Sequences of Commands
+****************************
+
+Aside from breakpoint commands (*note Breakpoint command lists: Break
+Commands.), GDB 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
+
+
+File: gdb.info, Node: Define, Next: Hooks, Up: Sequences
+
+User-defined commands
+=====================
+
+A "user-defined command" is a sequence of GDB commands to which you
+assign a new name as a command. This is done with the `define'
+command. 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
+
+This 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
+functions calls.
+
+`define COMMANDNAME'
+ Define a command named 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 GDB command
+ lines, which are given following the `define' command. The end of
+ these commands is marked by a line containing `end'.
+
+`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
+ `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 `end'.
+
+`while'
+ The syntax is similar to `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 `end'. The
+ commands are executed repeatedly as long as the expression
+ evaluates to true.
+
+`document COMMANDNAME'
+ Document the user-defined command COMMANDNAME, so that it can be
+ accessed by `help'. The command COMMANDNAME must already be
+ defined. This command reads lines of documentation just as
+ `define' reads the lines of the command definition, ending with
+ `end'. After the `document' command is finished, `help' on command
+ COMMANDNAME displays the documentation you have written.
+
+ You may use the `document' command again to change the
+ documentation of a command. Redefining the command with `define'
+ does not change the documentation.
+
+`help user-defined'
+ List all user-defined commands, with the first line of the
+ documentation (if any) for each.
+
+`show user'
+`show user COMMANDNAME'
+ Display the GDB commands used to define COMMANDNAME (but not its
+ documentation). If no COMMANDNAME is given, display the
+ definitions for all user-defined commands.
+
+`show max-user-call-depth'
+`set max-user-call-depth'
+ The value of `max-user-call-depth' controls how many recursion
+ levels are allowed in user-defined commands before GDB suspects an
+ infinite recursion and aborts the command.
+
+
+ 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
+GDB commands that normally print messages to say what they are doing
+omit the messages when used in a user-defined command.
+
+
+File: gdb.info, Node: Hooks, Next: Command Files, Prev: Define, Up: Sequences
+
+User-defined command hooks
+==========================
+
+You may define "hooks", which are a special kind of user-defined
+command. Whenever you run the command `foo', if the user-defined
+command `hook-foo' exists, it is executed (with no arguments) before
+that command.
+
+ A hook may also be defined which is run after the command you
+executed. Whenever you run the command `foo', if the user-defined
+command `hookpost-foo' exists, it is executed (with no arguments) after
+that command. Post-execution hooks may exist simultaneously with
+pre-execution hooks, for the same command.
+
+ It is valid for a hook to call the command which it hooks. If this
+occurs, the hook is not re-executed, thereby avoiding infinte recursion.
+
+ In addition, a pseudo-command, `stop' exists. Defining
+(`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.
+
+ For example, to ignore `SIGALRM' signals while single-stepping, but
+treat them normally during normal execution, you could define:
+
+ define hook-stop
+ handle SIGALRM nopass
+ end
+
+ define hook-run
+ handle SIGALRM pass
+ end
+
+ define hook-continue
+ handle SIGLARM pass
+ end
+
+ As a further example, to hook at the begining and end of the `echo'
+command, and to add extra text to the beginning and end of the message,
+you could define:
+
+ define hook-echo
+ echo <<<---
+ end
+
+ define hookpost-echo
+ echo --->>>\n
+ end
+
+ (gdb) echo Hello World
+ <<<---Hello World--->>>
+ (gdb)
+
+ You can define a hook for any single-word command in GDB, but not
+for command aliases; you should define a hook for the basic command
+name, e.g. `backtrace' rather than `bt'. If an error occurs during
+the execution of your hook, execution of GDB commands stops and GDB
+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 `define' command.
+
+
+File: gdb.info, Node: Command Files, Next: Output, Prev: Hooks, Up: Sequences
+
+Command files
+=============
+
+A command file for GDB is a file of lines that are GDB commands.
+Comments (lines starting with `#') 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.
+
+ When you start GDB, it automatically executes commands from its
+"init files", normally called `.gdbinit'(1). During startup, GDB does
+the following:
+
+ 1. Reads the init file (if any) in your home directory(2).
+
+ 2. Processes command line options and operands.
+
+ 3. Reads the init file (if any) in the current working directory.
+
+ 4. Reads command files specified by the `-x' option.
+
+ The init file in your home directory can set options (such as `set
+complaints') that affect subsequent processing of command line options
+and operands. Init files are not executed if you use the `-nx' option
+(*note Choosing modes: Mode Options.).
+
+ On some configurations of GDB, the init file is known by a different
+name (these are typically environments where a specialized form of GDB
+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:
+
+ * VxWorks (Wind River Systems real-time OS): `.vxgdbinit'
+
+ * OS68K (Enea Data Systems real-time OS): `.os68gdbinit'
+
+ * ES-1800 (Ericsson Telecom AB M68000 emulator): `.esgdbinit'
+
+ You can also request the execution of a command file with the
+`source' command:
+
+`source FILENAME'
+ Execute the command file FILENAME.
+
+ 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 and control is returned to the console.
+
+ Commands that would ask for confirmation if used interactively
+proceed without asking when used in a command file. Many GDB commands
+that normally print messages to say what they are doing omit the
+messages when called from command files.
+
+ GDB also accepts command input from standard input. In this mode,
+normal output goes to standard output and error output goes to standard
+error. Errors in a command file supplied on standard input do not
+terminate execution of the command file -- execution continues with the
+next command.
+
+ gdb < cmds > log 2>&1
+
+ (The syntax above will vary depending on the shell used.) This
+example will execute commands from the file `cmds'. All output and
+errors would be directed to `log'.
+
+ ---------- Footnotes ----------
+
+ (1) The DJGPP port of GDB uses the name `gdb.ini' instead, due to the
+limitations of file names imposed by DOS filesystems.
+
+ (2) On DOS/Windows systems, the home directory is the one pointed to
+by the `HOME' environment variable.
+
+
+File: gdb.info, Node: Output, Prev: Command Files, Up: Sequences
+
+Commands for controlled output
+==============================
+
+During the execution of a command file or a user-defined command, normal
+GDB 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.
+
+`echo TEXT'
+ Print TEXT. Nonprinting characters can be included in TEXT using
+ C escape sequences, such as `\n' to print a newline. *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 ` and foo = ', use
+ the command `echo \ and foo = \ '.
+
+ A backslash at the end of TEXT can be used, as in C, to continue
+ the command onto subsequent lines. For example,
+
+ echo This is some text\n\
+ which is continued\n\
+ onto several lines.\n
+
+ produces the same output as
+
+ echo This is some text\n
+ echo which is continued\n
+ echo onto several lines.\n
+
+`output EXPRESSION'
+ Print the value of EXPRESSION and nothing but that value: no
+ newlines, no `$NN = '. The value is not entered in the value
+ history either. *Note Expressions: Expressions, for more
+ information on expressions.
+
+`output/FMT EXPRESSION'
+ Print the value of EXPRESSION in format FMT. You can use the same
+ formats as for `print'. *Note Output formats: Output Formats, for
+ more information.
+
+`printf STRING, EXPRESSIONS...'
+ Print the values of the EXPRESSIONS under the control of STRING.
+ The EXPRESSIONS are separated by commas and may be either numbers
+ or pointers. Their values are printed as specified by STRING,
+ exactly as if your program were to execute the C subroutine
+
+ printf (STRING, EXPRESSIONS...);
+
+ For example, you can print two values in hex like this:
+
+ printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo
+
+ 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.
+
+
+File: gdb.info, Node: Interpreters, Next: Emacs, Prev: TUI, Up: Top
+
+Command Interpreters
+********************
+
+GDB supports multiple command interpreters, and some command
+infrastructure to allow users or user interface writers to switch
+between interpreters or run commands in other interpreters.
+
+ GDB currently supports two command interpreters, the console
+interpreter (sometimes called the command-line interpreter or CLI) and
+the machine interface interpreter (or GDB/MI). This manual describes
+both of these interfaces in great detail.
+
+ By default, GDB will start with the console interpreter. However,
+the user may choose to start GDB with another interpreter by specifying
+the `-i' or `--interpreter' startup options. Defined interpreters
+include:
+
+`console'
+ The traditional console or command-line interpreter. This is the
+ most often used interpreter with GDB. With no interpreter
+ specified at runtime, GDB will use this interpreter.
+
+`mi'
+ The newest GDB/MI interface (currently `mi2'). Used primarily by
+ programs wishing to use GDB as a backend for a debugger GUI or an
+ IDE. For more information, see *Note The GDB/MI Interface: GDB/MI.
+
+`mi2'
+ The current GDB/MI interface.
+
+`mi1'
+ The GDB/MI interface included in GDB 5.1, 5.2, and 5.3.
+
+
+ The interpreter being used by GDB may not be dynamically switched at
+runtime. Although possible, this could lead to a very precarious
+situation. Consider an IDE using GDB/MI. If a user enters the command
+"interpreter-set console" in a console view, GDB would switch to using
+the console interpreter, rendering the IDE inoperable!
+
+ Although you may only choose a single interpreter at startup, you
+may execute commands in any interpreter from the current interpreter
+using the appropriate command. If you are running the console
+interpreter, simply use the `interpreter-exec' command:
+
+ interpreter-exec mi "-data-list-register-names"
+
+ GDB/MI has a similar command, although it is only available in
+versions of GDB which support GDB/MI version 2 (or greater).
+
+
+File: gdb.info, Node: TUI, Next: Interpreters, Prev: Sequences, Up: Top
+
+GDB Text User Interface
+***********************
+
+* Menu:
+
+* TUI Overview:: TUI overview
+* TUI Keys:: TUI key bindings
+* TUI Single Key Mode:: TUI single key mode
+* TUI Commands:: TUI specific commands
+* TUI Configuration:: TUI configuration variables
+
+ The GDB Text User Interface, TUI in short, is a terminal interface
+which uses the `curses' library to show the source file, the assembly
+output, the program registers and GDB commands in separate text windows.
+
+ The TUI is enabled by invoking GDB using either `gdbtui' or `gdb
+-tui'.
+
+
+File: gdb.info, Node: TUI Overview, Next: TUI Keys, Up: TUI
+
+TUI overview
+============
+
+The TUI has two display modes that can be switched while GDB runs:
+
+ * A curses (or TUI) mode in which it displays several text windows
+ on the terminal.
+
+ * A standard mode which corresponds to the GDB configured without
+ the TUI.
+
+ In the TUI mode, GDB can display several text window on the terminal:
+
+_command_
+ This window is the GDB command window with the GDB prompt and the
+ GDB outputs. The GDB input is still managed using readline but
+ through the TUI. The _command_ window is always visible.
+
+_source_
+ The source window shows the source file of the program. The
+ current line as well as active breakpoints are displayed in this
+ window.
+
+_assembly_
+ The assembly window shows the disassembly output of the program.
+
+_register_
+ This window shows the processor registers. It detects when a
+ register is changed and when this is the case, registers that have
+ changed are highlighted.
+
+
+ The source and assembly windows show the current program position by
+highlighting the current line and marking them with the `>' marker.
+Breakpoints are also indicated with two markers. A first one indicates
+the breakpoint type:
+
+`B'
+ Breakpoint which was hit at least once.
+
+`b'
+ Breakpoint which was never hit.
+
+`H'
+ Hardware breakpoint which was hit at least once.
+
+`h'
+ Hardware breakpoint which was never hit.
+
+
+ The second marker indicates whether the breakpoint is enabled or not:
+
+`+'
+ Breakpoint is enabled.
+
+`-'
+ Breakpoint is disabled.
+
+
+ The source, assembly and register windows are attached to the thread
+and the frame position. They are updated when the current thread
+changes, when the frame changes or when the program counter changes.
+These three windows are arranged by the TUI according to several
+layouts. The layout defines which of these three windows are visible.
+The following layouts are available:
+
+ * source
+
+ * assembly
+
+ * source and assembly
+
+ * source and registers
+
+ * assembly and registers
+
+
+ On top of the command window a status line gives various information
+concerning the current process begin debugged. The status line is
+updated when the information it shows changes. The following fields
+are displayed:
+
+_target_
+ Indicates the current gdb target (*note Specifying a Debugging
+ Target: Targets.).
+
+_process_
+ Gives information about the current process or thread number.
+ When no process is being debugged, this field is set to `No
+ process'.
+
+_function_
+ Gives the current function name for the selected frame. The name
+ is demangled if demangling is turned on (*note Print Settings::).
+ When there is no symbol corresponding to the current program
+ counter the string `??' is displayed.
+
+_line_
+ Indicates the current line number for the selected frame. When
+ the current line number is not known the string `??' is displayed.
+
+_pc_
+ Indicates the current program counter address.
+
+
+
+File: gdb.info, Node: TUI Keys, Next: TUI Single Key Mode, Prev: TUI Overview, Up: TUI
+
+TUI Key Bindings
+================
+
+The TUI installs several key bindings in the readline keymaps (*note
+Command Line Editing::). They allow to leave or enter in the TUI mode
+or they operate directly on the TUI layout and windows. The TUI also
+provides a _SingleKey_ keymap which binds several keys directly to GDB
+commands. The following key bindings are installed for both TUI mode
+and the GDB standard mode.
+
+`C-x C-a'
+`C-x a'
+`C-x A'
+ Enter or leave the TUI mode. When the TUI mode is left, the
+ curses window management is left and GDB operates using its
+ standard mode writing on the terminal directly. When the TUI mode
+ is entered, the control is given back to the curses windows. The
+ screen is then refreshed.
+
+`C-x 1'
+ Use a TUI layout with only one window. The layout will either be
+ `source' or `assembly'. When the TUI mode is not active, it will
+ switch to the TUI mode.
+
+ Think of this key binding as the Emacs `C-x 1' binding.
+
+`C-x 2'
+ Use a TUI layout with at least two windows. When the current
+ layout shows already two windows, a next layout with two windows
+ is used. When a new layout is chosen, one window will always be
+ common to the previous layout and the new one.
+
+ Think of it as the Emacs `C-x 2' binding.
+
+`C-x o'
+ Change the active window. The TUI associates several key bindings
+ (like scrolling and arrow keys) to the active window. This command
+ gives the focus to the next TUI window.
+
+ Think of it as the Emacs `C-x o' binding.
+
+`C-x s'
+ Use the TUI _SingleKey_ keymap that binds single key to gdb
+ commands (*note TUI Single Key Mode::).
+
+
+ The following key bindings are handled only by the TUI mode:
+
+<PgUp>
+ Scroll the active window one page up.
+
+<PgDn>
+ Scroll the active window one page down.
+
+<Up>
+ Scroll the active window one line up.
+
+<Down>
+ Scroll the active window one line down.
+
+<Left>
+ Scroll the active window one column left.
+
+<Right>
+ Scroll the active window one column right.
+
+<C-L>
+ Refresh the screen.
+
+
+ In the TUI mode, the arrow keys are used by the active window for
+scrolling. This means they are available for readline when the active
+window is the command window. When the command window does not have
+the focus, it is necessary to use other readline key bindings such as
+<C-p>, <C-n>, <C-b> and <C-f>.
+
+
+File: gdb.info, Node: TUI Single Key Mode, Next: TUI Commands, Prev: TUI Keys, Up: TUI
+
+TUI Single Key Mode
+===================
+
+The TUI provides a _SingleKey_ mode in which it installs a particular
+key binding in the readline keymaps to connect single keys to some gdb
+commands.
+
+`c'
+ continue
+
+`d'
+ down
+
+`f'
+ finish
+
+`n'
+ next
+
+`q'
+ exit the _SingleKey_ mode.
+
+`r'
+ run
+
+`s'
+ step
+
+`u'
+ up
+
+`v'
+ info locals
+
+`w'
+ where
+
+
+ Other keys temporarily switch to the GDB command prompt. The key
+that was pressed is inserted in the editing buffer so that it is
+possible to type most GDB commands without interaction with the TUI
+_SingleKey_ mode. Once the command is entered the TUI _SingleKey_ mode
+is restored. The only way to permanently leave this mode is by hitting
+<q> or `<C-x> <s>'.
+
+
+File: gdb.info, Node: TUI Commands, Next: TUI Configuration, Prev: TUI Single Key Mode, Up: TUI
+
+TUI specific commands
+=====================
+
+The TUI has specific commands to control the text windows. These
+commands are always available, that is they do not depend on the
+current terminal mode in which GDB runs. When GDB is in the standard
+mode, using these commands will automatically switch in the TUI mode.
+
+`info win'
+ List and give the size of all displayed windows.
+
+`layout next'
+ Display the next layout.
+
+`layout prev'
+ Display the previous layout.
+
+`layout src'
+ Display the source window only.
+
+`layout asm'
+ Display the assembly window only.
+
+`layout split'
+ Display the source and assembly window.
+
+`layout regs'
+ Display the register window together with the source or assembly
+ window.
+
+`focus next | prev | src | asm | regs | split'
+ Set the focus to the named window. This command allows to change
+ the active window so that scrolling keys can be affected to
+ another window.
+
+`refresh'
+ Refresh the screen. This is similar to using <C-L> key.
+
+`tui reg float'
+ Show the floating point registers in the register window.
+
+`tui reg general'
+ Show the general registers in the register window.
+
+`tui reg next'
+ Show the next register group. The list of register groups as well
+ as their order is target specific. The predefined register groups
+ are the following: `general', `float', `system', `vector', `all',
+ `save', `restore'.
+
+`tui reg system'
+ Show the system registers in the register window.
+
+`update'
+ Update the source window and the current execution point.
+
+`winheight NAME +COUNT'
+`winheight NAME -COUNT'
+ Change the height of the window NAME by COUNT lines. Positive
+ counts increase the height, while negative counts decrease it.
+
+
+
+File: gdb.info, Node: TUI Configuration, Prev: TUI Commands, Up: TUI
+
+TUI configuration variables
+===========================
+
+The TUI has several configuration variables that control the appearance
+of windows on the terminal.
+
+`set tui border-kind KIND'
+ Select the border appearance for the source, assembly and register
+ windows. The possible values are the following:
+ `space'
+ Use a space character to draw the border.
+
+ `ascii'
+ Use ascii characters + - and | to draw the border.
+
+ `acs'
+ Use the Alternate Character Set to draw the border. The
+ border is drawn using character line graphics if the terminal
+ supports them.
+
+
+`set tui active-border-mode MODE'
+ Select the attributes to display the border of the active window.
+ The possible values are `normal', `standout', `reverse', `half',
+ `half-standout', `bold' and `bold-standout'.
+
+`set tui border-mode MODE'
+ Select the attributes to display the border of other windows. The
+ MODE can be one of the following:
+ `normal'
+ Use normal attributes to display the border.
+
+ `standout'
+ Use standout mode.
+
+ `reverse'
+ Use reverse video mode.
+
+ `half'
+ Use half bright mode.
+
+ `half-standout'
+ Use half bright and standout mode.
+
+ `bold'
+ Use extra bright or bold mode.
+
+ `bold-standout'
+ Use extra bright or bold and standout mode.
+
+
+
+
+File: gdb.info, Node: Emacs, Next: Annotations, Prev: Interpreters, Up: Top
+
+Using GDB under GNU Emacs
+*************************
+
+A special interface allows you to use GNU Emacs to view (and edit) the
+source files for the program you are debugging with GDB.
+
+ To use this interface, use the command `M-x gdb' in Emacs. Give the
+executable file you want to debug as an argument. This command starts
+GDB as a subprocess of Emacs, with input and output through a newly
+created Emacs buffer.
+
+ Using GDB under Emacs is just like using GDB normally except for two
+things:
+
+ * All "terminal" input and output goes through the Emacs buffer.
+
+ This applies both to GDB 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, `C-c C-c' for an interrupt, `C-c C-z' for a stop.
+
+ * GDB displays source code through Emacs.
+
+ Each time GDB displays a stack frame, Emacs automatically finds the
+source file for that frame and puts an arrow (`=>') at the left margin
+of the current line. Emacs uses a separate buffer for source display,
+and splits the screen to show both your GDB session and the source.
+
+ Explicit GDB `list' or search commands still produce output as
+usual, but you probably have no reason to use them from Emacs.
+
+ If you specify an absolute file name when prompted for the `M-x gdb'
+argument, then Emacs sets your current working directory to where your
+program resides. If you only specify the file name, then Emacs sets
+your current working directory to to the directory associated with the
+previous buffer. In this case, GDB may find your program by searching
+your environment's `PATH' variable, but on some operating systems it
+might not find the source. So, although the GDB input and output
+session proceeds normally, the auxiliary buffer does not display the
+current source and line of execution.
+
+ The initial working directory of GDB is printed on the top line of
+the GDB I/O buffer and this serves as a default for the commands that
+specify files for GDB to operate on. *Note Commands to specify files:
+Files.
+
+ By default, `M-x gdb' calls the program called `gdb'. If you need
+to call GDB by a different name (for example, if you keep several
+configurations around, with different names) you can customize the
+Emacs variable `gud-gdb-command-name' to run the one you want.
+
+ In the GDB I/O buffer, you can use these special Emacs commands in
+addition to the standard Shell mode commands:
+
+`C-h m'
+ Describe the features of Emacs' GDB Mode.
+
+`C-c C-s'
+ Execute to another source line, like the GDB `step' command; also
+ update the display window to show the current file and location.
+
+`C-c C-n'
+ Execute to next source line in this function, skipping all function
+ calls, like the GDB `next' command. Then update the display window
+ to show the current file and location.
+
+`C-c C-i'
+ Execute one instruction, like the GDB `stepi' command; update
+ display window accordingly.
+
+`C-c C-f'
+ Execute until exit from the selected stack frame, like the GDB
+ `finish' command.
+
+`C-c C-r'
+ Continue execution of your program, like the GDB `continue'
+ command.
+
+`C-c <'
+ Go up the number of frames indicated by the numeric argument
+ (*note Numeric Arguments: (Emacs)Arguments.), like the GDB `up'
+ command.
+
+`C-c >'
+ Go down the number of frames indicated by the numeric argument,
+ like the GDB `down' command.
+
+ In any source file, the Emacs command `C-x SPC' (`gud-break') tells
+GDB to set a breakpoint on the source line point is on.
+
+ If you type `M-x speedbar', then Emacs displays a separate frame
+which shows a backtrace when the GDB I/O buffer is current. Move point
+to any frame in the stack and type <RET> to make it become the current
+frame and display the associated source in the source buffer.
+Alternatively, click `Mouse-2' to make the selected frame become the
+current one.
+
+ If you accidentally delete the source-display buffer, an easy way to
+get it back is to type the command `f' in the GDB 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 GDB
+communicates with Emacs in terms of line numbers. If you add or delete
+lines from the text, the line numbers that GDB knows cease to
+correspond properly with the code.
+
+ The description given here is for GNU Emacs version 21.3 and a more
+detailed description of its interaction with GDB is given in the Emacs
+manual (*note Debuggers: (Emacs)Debuggers.).
+
+
+File: gdb.info, Node: GDB/MI, Next: GDB Bugs, Prev: Annotations, Up: Top
+
+The GDB/MI Interface
+********************
+
+Function and Purpose
+====================
+
+GDB/MI is a line based machine oriented text interface to GDB. It is
+specifically intended to support the development of systems which use
+the debugger as just one small component of a larger system.
+
+ This chapter is a specification of the GDB/MI interface. It is
+written in the form of a reference manual.
+
+ Note that GDB/MI is still under construction, so some of the
+features described below are incomplete and subject to change.
+
+Notation and Terminology
+========================
+
+This chapter uses the following notation:
+
+ * `|' separates two alternatives.
+
+ * `[ SOMETHING ]' indicates that SOMETHING is optional: it may or
+ may not be given.
+
+ * `( GROUP )*' means that GROUP inside the parentheses may repeat
+ zero or more times.
+
+ * `( GROUP )+' means that GROUP inside the parentheses may repeat
+ one or more times.
+
+ * `"STRING"' means a literal STRING.
+
+Acknowledgments
+===============
+
+In alphabetic order: Andrew Cagney, Fernando Nasser, Stan Shebs and
+Elena Zannoni.
+
+* Menu:
+
+* GDB/MI Command Syntax::
+* GDB/MI Compatibility with CLI::
+* GDB/MI Output Records::
+* GDB/MI Command Description Format::
+* GDB/MI Breakpoint Table Commands::
+* GDB/MI Data Manipulation::
+* GDB/MI Program Control::
+* GDB/MI Miscellaneous Commands::
+* GDB/MI Stack Manipulation::
+* GDB/MI Symbol Query::
+* GDB/MI Target Manipulation::
+* GDB/MI Thread Commands::
+* GDB/MI Tracepoint Commands::
+* GDB/MI Variable Objects::
+
+
+File: gdb.info, Node: GDB/MI Command Syntax, Next: GDB/MI Compatibility with CLI, Up: GDB/MI
+
+GDB/MI Command Syntax
+=====================
+
+* Menu:
+
+* GDB/MI Input Syntax::
+* GDB/MI Output Syntax::
+* GDB/MI Simple Examples::
+
+
+File: gdb.info, Node: GDB/MI Input Syntax, Next: GDB/MI Output Syntax, Up: GDB/MI Command Syntax
+
+GDB/MI Input Syntax
+-------------------
+
+`COMMAND ==>'
+ `CLI-COMMAND | MI-COMMAND'
+
+`CLI-COMMAND ==>'
+ `[ TOKEN ] CLI-COMMAND NL', where CLI-COMMAND is any existing GDB
+ CLI command.
+
+`MI-COMMAND ==>'
+ `[ TOKEN ] "-" OPERATION ( " " OPTION )* `[' " --" `]' ( " "
+ PARAMETER )* NL'
+
+`TOKEN ==>'
+ "any sequence of digits"
+
+`OPTION ==>'
+ `"-" PARAMETER [ " " PARAMETER ]'
+
+`PARAMETER ==>'
+ `NON-BLANK-SEQUENCE | C-STRING'
+
+`OPERATION ==>'
+ _any of the operations described in this chapter_
+
+`NON-BLANK-SEQUENCE ==>'
+ _anything, provided it doesn't contain special characters such as
+ "-", NL, """ and of course " "_
+
+`C-STRING ==>'
+ `""" SEVEN-BIT-ISO-C-STRING-CONTENT """'
+
+`NL ==>'
+ `CR | CR-LF'
+
+Notes:
+
+ * The CLI commands are still handled by the MI interpreter; their
+ output is described below.
+
+ * The `TOKEN', when present, is passed back when the command
+ finishes.
+
+ * Some MI commands accept optional arguments as part of the parameter
+ list. Each option is identified by a leading `-' (dash) and may be
+ followed by an optional argument parameter. Options occur first
+ in the parameter list and can be delimited from normal parameters
+ using `--' (this is useful when some parameters begin with a dash).
+
+ Pragmatics:
+
+ * We want easy access to the existing CLI syntax (for debugging).
+
+ * We want it to be easy to spot a MI operation.
+
+
+File: gdb.info, Node: GDB/MI Output Syntax, Next: GDB/MI Simple Examples, Prev: GDB/MI Input Syntax, Up: GDB/MI Command Syntax
+
+GDB/MI Output Syntax
+--------------------
+
+The output from GDB/MI consists of zero or more out-of-band records
+followed, optionally, by a single result record. This result record is
+for the most recent command. The sequence of output records is
+terminated by `(gdb)'.
+
+ If an input command was prefixed with a `TOKEN' then the
+corresponding output for that command will also be prefixed by that same
+TOKEN.
+
+`OUTPUT ==>'
+ `( OUT-OF-BAND-RECORD )* [ RESULT-RECORD ] "(gdb)" NL'
+
+`RESULT-RECORD ==>'
+ ` [ TOKEN ] "^" RESULT-CLASS ( "," RESULT )* NL'
+
+`OUT-OF-BAND-RECORD ==>'
+ `ASYNC-RECORD | STREAM-RECORD'
+
+`ASYNC-RECORD ==>'
+ `EXEC-ASYNC-OUTPUT | STATUS-ASYNC-OUTPUT | NOTIFY-ASYNC-OUTPUT'
+
+`EXEC-ASYNC-OUTPUT ==>'
+ `[ TOKEN ] "*" ASYNC-OUTPUT'
+
+`STATUS-ASYNC-OUTPUT ==>'
+ `[ TOKEN ] "+" ASYNC-OUTPUT'
+
+`NOTIFY-ASYNC-OUTPUT ==>'
+ `[ TOKEN ] "=" ASYNC-OUTPUT'
+
+`ASYNC-OUTPUT ==>'
+ `ASYNC-CLASS ( "," RESULT )* NL'
+
+`RESULT-CLASS ==>'
+ `"done" | "running" | "connected" | "error" | "exit"'
+
+`ASYNC-CLASS ==>'
+ `"stopped" | OTHERS' (where OTHERS will be added depending on the
+ needs--this is still in development).
+
+`RESULT ==>'
+ ` VARIABLE "=" VALUE'
+
+`VARIABLE ==>'
+ ` STRING '
+
+`VALUE ==>'
+ ` CONST | TUPLE | LIST '
+
+`CONST ==>'
+ `C-STRING'
+
+`TUPLE ==>'
+ ` "{}" | "{" RESULT ( "," RESULT )* "}" '
+
+`LIST ==>'
+ ` "[]" | "[" VALUE ( "," VALUE )* "]" | "[" RESULT ( "," RESULT )*
+ "]" '
+
+`STREAM-RECORD ==>'
+ `CONSOLE-STREAM-OUTPUT | TARGET-STREAM-OUTPUT | LOG-STREAM-OUTPUT'
+
+`CONSOLE-STREAM-OUTPUT ==>'
+ `"~" C-STRING'
+
+`TARGET-STREAM-OUTPUT ==>'
+ `"@" C-STRING'
+
+`LOG-STREAM-OUTPUT ==>'
+ `"&" C-STRING'
+
+`NL ==>'
+ `CR | CR-LF'
+
+`TOKEN ==>'
+ _any sequence of digits_.
+
+Notes:
+
+ * All output sequences end in a single line containing a period.
+
+ * The `TOKEN' is from the corresponding request. If an execution
+ command is interrupted by the `-exec-interrupt' command, the TOKEN
+ associated with the `*stopped' message is the one of the original
+ execution command, not the one of the interrupt command.
+
+ * STATUS-ASYNC-OUTPUT contains on-going status information about the
+ progress of a slow operation. It can be discarded. All status
+ output is prefixed by `+'.
+
+ * EXEC-ASYNC-OUTPUT contains asynchronous state change on the target
+ (stopped, started, disappeared). All async output is prefixed by
+ `*'.
+
+ * NOTIFY-ASYNC-OUTPUT contains supplementary information that the
+ client should handle (e.g., a new breakpoint information). All
+ notify output is prefixed by `='.
+
+ * CONSOLE-STREAM-OUTPUT is output that should be displayed as is in
+ the console. It is the textual response to a CLI command. All
+ the console output is prefixed by `~'.
+
+ * TARGET-STREAM-OUTPUT is the output produced by the target program.
+ All the target output is prefixed by `@'.
+
+ * LOG-STREAM-OUTPUT is output text coming from GDB's internals, for
+ instance messages that should be displayed as part of an error
+ log. All the log output is prefixed by `&'.
+
+ * New GDB/MI commands should only output LISTS containing VALUES.
+
+
+ *Note GDB/MI Stream Records: GDB/MI Stream Records, for more details
+about the various output records.
+
+
+File: gdb.info, Node: GDB/MI Simple Examples, Prev: GDB/MI Output Syntax, Up: GDB/MI Command Syntax
+
+Simple Examples of GDB/MI Interaction
+-------------------------------------
+
+This subsection presents several simple examples of interaction using
+the GDB/MI interface. In these examples, `->' means that the following
+line is passed to GDB/MI as input, while `<-' means the output received
+from GDB/MI.
+
+Target Stop
+...........
+
+Here's an example of stopping the inferior process:
+
+ -> -stop
+ <- (gdb)
+
+and later:
+
+ <- *stop,reason="stop",address="0x123",source="a.c:123"
+ <- (gdb)
+
+Simple CLI Command
+..................
+
+Here's an example of a simple CLI command being passed through GDB/MI
+and on to the CLI.
+
+ -> print 1+2
+ <- &"print 1+2\n"
+ <- ~"$1 = 3\n"
+ <- ^done
+ <- (gdb)
+
+Command With Side Effects
+.........................
+
+ -> -symbol-file xyz.exe
+ <- *breakpoint,nr="3",address="0x123",source="a.c:123"
+ <- (gdb)
+
+A Bad Command
+.............
+
+Here's what happens if you pass a non-existent command:
+
+ -> -rubbish
+ <- ^error,msg="Undefined MI command: rubbish"
+ <- (gdb)
+
+
+File: gdb.info, Node: GDB/MI Compatibility with CLI, Next: GDB/MI Output Records, Prev: GDB/MI Command Syntax, Up: GDB/MI
+
+GDB/MI Compatibility with CLI
+=============================
+
+To help users familiar with GDB's existing CLI interface, GDB/MI
+accepts existing CLI commands. As specified by the syntax, such
+commands can be directly entered into the GDB/MI interface and GDB will
+respond.
+
+ This mechanism is provided as an aid to developers of GDB/MI clients
+and not as a reliable interface into the CLI. Since the command is
+being interpreteted in an environment that assumes GDB/MI behaviour,
+the exact output of such commands is likely to end up being an
+un-supported hybrid of GDB/MI and CLI output.
+
+
+File: gdb.info, Node: GDB/MI Output Records, Next: GDB/MI Command Description Format, Prev: GDB/MI Compatibility with CLI, Up: GDB/MI
+
+GDB/MI Output Records
+=====================
+
+* Menu:
+
+* GDB/MI Result Records::
+* GDB/MI Stream Records::
+* GDB/MI Out-of-band Records::
+
+
+File: gdb.info, Node: GDB/MI Result Records, Next: GDB/MI Stream Records, Up: GDB/MI Output Records
+
+GDB/MI Result Records
+---------------------
+
+In addition to a number of out-of-band notifications, the response to a
+GDB/MI command includes one of the following result indications:
+
+`"^done" [ "," RESULTS ]'
+ The synchronous operation was successful, `RESULTS' are the return
+ values.
+
+`"^running"'
+ The asynchronous operation was successfully started. The target is
+ running.
+
+`"^error" "," C-STRING'
+ The operation failed. The `C-STRING' contains the corresponding
+ error message.
+
+
+File: gdb.info, Node: GDB/MI Stream Records, Next: GDB/MI Out-of-band Records, Prev: GDB/MI Result Records, Up: GDB/MI Output Records
+
+GDB/MI Stream Records
+---------------------
+
+GDB internally maintains a number of output streams: the console, the
+target, and the log. The output intended for each of these streams is
+funneled through the GDB/MI interface using "stream records".
+
+ Each stream record begins with a unique "prefix character" which
+identifies its stream (*note GDB/MI Output Syntax: GDB/MI Output
+Syntax.). In addition to the prefix, each stream record contains a
+`STRING-OUTPUT'. This is either raw text (with an implicit new line)
+or a quoted C string (which does not contain an implicit newline).
+
+`"~" STRING-OUTPUT'
+ The console output stream contains text that should be displayed
+ in the CLI console window. It contains the textual responses to
+ CLI commands.
+
+`"@" STRING-OUTPUT'
+ The target output stream contains any textual output from the
+ running target.
+
+`"&" STRING-OUTPUT'
+ The log stream contains debugging messages being produced by GDB's
+ internals.
+
+
+File: gdb.info, Node: GDB/MI Out-of-band Records, Prev: GDB/MI Stream Records, Up: GDB/MI Output Records
+
+GDB/MI Out-of-band Records
+--------------------------
+
+"Out-of-band" records are used to notify the GDB/MI client of
+additional changes that have occurred. Those changes can either be a
+consequence of GDB/MI (e.g., a breakpoint modified) or a result of
+target activity (e.g., target stopped).
+
+ The following is a preliminary list of possible out-of-band records.
+
+`"*" "stop"'
+
+
+File: gdb.info, Node: GDB/MI Command Description Format, Next: GDB/MI Breakpoint Table Commands, Prev: GDB/MI Output Records, Up: GDB/MI
+
+GDB/MI Command Description Format
+=================================
+
+The remaining sections describe blocks of commands. Each block of
+commands is laid out in a fashion similar to this section.
+
+ Note the the line breaks shown in the examples are here only for
+readability. They don't appear in the real output. Also note that the
+commands with a non-available example (N.A.) are not yet implemented.
+
+Motivation
+----------
+
+The motivation for this collection of commands.
+
+Introduction
+------------
+
+A brief introduction to this collection of commands as a whole.
+
+Commands
+--------
+
+For each command in the block, the following is described:
+
+Synopsis
+........
+
+ -command ARGS...
+
+GDB Command
+...........
+
+The corresponding GDB CLI command.
+
+Result
+......
+
+Out-of-band
+...........
+
+Notes
+.....
+
+Example
+.......
+
+
+File: gdb.info, Node: GDB/MI Breakpoint Table Commands, Next: GDB/MI Data Manipulation, Prev: GDB/MI Command Description Format, Up: GDB/MI
+
+GDB/MI Breakpoint table commands
+================================
+
+This section documents GDB/MI commands for manipulating breakpoints.
+
+The `-break-after' Command
+--------------------------
+
+Synopsis
+........
+
+ -break-after NUMBER COUNT
+
+ The breakpoint number NUMBER is not in effect until it has been hit
+COUNT times. To see how this is reflected in the output of the
+`-break-list' command, see the description of the `-break-list' command
+below.
+
+GDB Command
+...........
+
+The corresponding GDB command is `ignore'.
+
+Example
+.......
+
+ (gdb)
+ -break-insert main
+ ^done,bkpt={number="1",addr="0x000100d0",file="hello.c",line="5"}
+ (gdb)
+ -break-after 1 3
+ ~
+ ^done
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="1",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ addr="0x000100d0",func="main",file="hello.c",line="5",times="0",
+ ignore="3"}]}
+ (gdb)
+
+The `-break-condition' Command
+------------------------------
+
+Synopsis
+........
+
+ -break-condition NUMBER EXPR
+
+ Breakpoint NUMBER will stop the program only if the condition in
+EXPR is true. The condition becomes part of the `-break-list' output
+(see the description of the `-break-list' command below).
+
+GDB Command
+...........
+
+The corresponding GDB command is `condition'.
+
+Example
+.......
+
+ (gdb)
+ -break-condition 1 1
+ ^done
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="1",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ addr="0x000100d0",func="main",file="hello.c",line="5",cond="1",
+ times="0",ignore="3"}]}
+ (gdb)
+
+The `-break-delete' Command
+---------------------------
+
+Synopsis
+........
+
+ -break-delete ( BREAKPOINT )+
+
+ Delete the breakpoint(s) whose number(s) are specified in the
+argument list. This is obviously reflected in the breakpoint list.
+
+GDB command
+...........
+
+The corresponding GDB command is `delete'.
+
+Example
+.......
+
+ (gdb)
+ -break-delete 1
+ ^done
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="0",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[]}
+ (gdb)
+
+The `-break-disable' Command
+----------------------------
+
+Synopsis
+........
+
+ -break-disable ( BREAKPOINT )+
+
+ Disable the named BREAKPOINT(s). The field `enabled' in the break
+list is now set to `n' for the named BREAKPOINT(s).
+
+GDB Command
+...........
+
+The corresponding GDB command is `disable'.
+
+Example
+.......
+
+ (gdb)
+ -break-disable 2
+ ^done
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="1",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="2",type="breakpoint",disp="keep",enabled="n",
+ addr="0x000100d0",func="main",file="hello.c",line="5",times="0"}]}
+ (gdb)
+
+The `-break-enable' Command
+---------------------------
+
+Synopsis
+........
+
+ -break-enable ( BREAKPOINT )+
+
+ Enable (previously disabled) BREAKPOINT(s).
+
+GDB Command
+...........
+
+The corresponding GDB command is `enable'.
+
+Example
+.......
+
+ (gdb)
+ -break-enable 2
+ ^done
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="1",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
+ addr="0x000100d0",func="main",file="hello.c",line="5",times="0"}]}
+ (gdb)
+
+The `-break-info' Command
+-------------------------
+
+Synopsis
+........
+
+ -break-info BREAKPOINT
+
+ Get information about a single breakpoint.
+
+GDB command
+...........
+
+The corresponding GDB command is `info break BREAKPOINT'.
+
+Example
+.......
+
+N.A.
+
+The `-break-insert' Command
+---------------------------
+
+Synopsis
+........
+
+ -break-insert [ -t ] [ -h ] [ -r ]
+ [ -c CONDITION ] [ -i IGNORE-COUNT ]
+ [ -p THREAD ] [ LINE | ADDR ]
+
+If specified, LINE, can be one of:
+
+ * function
+
+ * filename:linenum
+
+ * filename:function
+
+ * *address
+
+ The possible optional parameters of this command are:
+
+`-t'
+ Insert a tempoary breakpoint.
+
+`-h'
+ Insert a hardware breakpoint.
+
+`-c CONDITION'
+ Make the breakpoint conditional on CONDITION.
+
+`-i IGNORE-COUNT'
+ Initialize the IGNORE-COUNT.
+
+`-r'
+ Insert a regular breakpoint in all the functions whose names match
+ the given regular expression. Other flags are not applicable to
+ regular expresson.
+
+Result
+......
+
+The result is in the form:
+
+ ^done,bkptno="NUMBER",func="FUNCNAME",
+ file="FILENAME",line="LINENO"
+
+where NUMBER is the GDB number for this breakpoint, FUNCNAME is the
+name of the function where the breakpoint was inserted, FILENAME is the
+name of the source file which contains this function, and LINENO is the
+source line number within that file.
+
+ Note: this format is open to change.
+
+GDB Command
+...........
+
+The corresponding GDB commands are `break', `tbreak', `hbreak',
+`thbreak', and `rbreak'.
+
+Example
+.......
+
+ (gdb)
+ -break-insert main
+ ^done,bkpt={number="1",addr="0x0001072c",file="recursive2.c",line="4"}
+ (gdb)
+ -break-insert -t foo
+ ^done,bkpt={number="2",addr="0x00010774",file="recursive2.c",line="11"}
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="2",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ addr="0x0001072c", func="main",file="recursive2.c",line="4",times="0"},
+ bkpt={number="2",type="breakpoint",disp="del",enabled="y",
+ addr="0x00010774",func="foo",file="recursive2.c",line="11",times="0"}]}
+ (gdb)
+ -break-insert -r foo.*
+ ~int foo(int, int);
+ ^done,bkpt={number="3",addr="0x00010774",file="recursive2.c",line="11"}
+ (gdb)
+
+The `-break-list' Command
+-------------------------
+
+Synopsis
+........
+
+ -break-list
+
+ Displays the list of inserted breakpoints, showing the following
+fields:
+
+`Number'
+ number of the breakpoint
+
+`Type'
+ type of the breakpoint: `breakpoint' or `watchpoint'
+
+`Disposition'
+ should the breakpoint be deleted or disabled when it is hit: `keep'
+ or `nokeep'
+
+`Enabled'
+ is the breakpoint enabled or no: `y' or `n'
+
+`Address'
+ memory location at which the breakpoint is set
+
+`What'
+ logical location of the breakpoint, expressed by function name,
+ file name, line number
+
+`Times'
+ number of times the breakpoint has been hit
+
+ If there are no breakpoints or watchpoints, the `BreakpointTable'
+`body' field is an empty list.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info break'.
+
+Example
+.......
+
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="2",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ addr="0x000100d0",func="main",file="hello.c",line="5",times="0"},
+ bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
+ addr="0x00010114",func="foo",file="hello.c",line="13",times="0"}]}
+ (gdb)
+
+ Here's an example of the result when there are no breakpoints:
+
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="0",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[]}
+ (gdb)
+
+The `-break-watch' Command
+--------------------------
+
+Synopsis
+........
+
+ -break-watch [ -a | -r ]
+
+ Create a watchpoint. With the `-a' option it will create an
+"access" watchpoint, i.e. a watchpoint that triggers either on a read
+from or on a write to the memory location. With the `-r' option, the
+watchpoint created is a "read" watchpoint, i.e. it will trigger only
+when the memory location is accessed for reading. Without either of
+the options, the watchpoint created is a regular watchpoint, i.e. it
+will trigger when the memory location is accessed for writing. *Note
+Setting watchpoints: Set Watchpoints.
+
+ Note that `-break-list' will report a single list of watchpoints and
+breakpoints inserted.
+
+GDB Command
+...........
+
+The corresponding GDB commands are `watch', `awatch', and `rwatch'.
+
+Example
+.......
+
+Setting a watchpoint on a variable in the `main' function:
+
+ (gdb)
+ -break-watch x
+ ^done,wpt={number="2",exp="x"}
+ (gdb)
+ -exec-continue
+ ^running
+ ^done,reason="watchpoint-trigger",wpt={number="2",exp="x"},
+ value={old="-268439212",new="55"},
+ frame={func="main",args=[],file="recursive2.c",line="5"}
+ (gdb)
+
+ Setting a watchpoint on a variable local to a function. GDB will
+stop the program execution twice: first for the variable changing
+value, then for the watchpoint going out of scope.
+
+ (gdb)
+ -break-watch C
+ ^done,wpt={number="5",exp="C"}
+ (gdb)
+ -exec-continue
+ ^running
+ ^done,reason="watchpoint-trigger",
+ wpt={number="5",exp="C"},value={old="-276895068",new="3"},
+ frame={func="callee4",args=[],
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="13"}
+ (gdb)
+ -exec-continue
+ ^running
+ ^done,reason="watchpoint-scope",wpnum="5",
+ frame={func="callee3",args=[{name="strarg",
+ value="0x11940 \"A string argument.\""}],
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="18"}
+ (gdb)
+
+ Listing breakpoints and watchpoints, at different points in the
+program execution. Note that once the watchpoint goes out of scope, it
+is deleted.
+
+ (gdb)
+ -break-watch C
+ ^done,wpt={number="2",exp="C"}
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="2",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ addr="0x00010734",func="callee4",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8",times="1"},
+ bkpt={number="2",type="watchpoint",disp="keep",
+ enabled="y",addr="",what="C",times="0"}]}
+ (gdb)
+ -exec-continue
+ ^running
+ ^done,reason="watchpoint-trigger",wpt={number="2",exp="C"},
+ value={old="-276895068",new="3"},
+ frame={func="callee4",args=[],
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="13"}
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="2",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ addr="0x00010734",func="callee4",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8",times="1"},
+ bkpt={number="2",type="watchpoint",disp="keep",
+ enabled="y",addr="",what="C",times="-5"}]}
+ (gdb)
+ -exec-continue
+ ^running
+ ^done,reason="watchpoint-scope",wpnum="2",
+ frame={func="callee3",args=[{name="strarg",
+ value="0x11940 \"A string argument.\""}],
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="18"}
+ (gdb)
+ -break-list
+ ^done,BreakpointTable={nr_rows="1",nr_cols="6",
+ hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},
+ {width="14",alignment="-1",col_name="type",colhdr="Type"},
+ {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
+ {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
+ {width="10",alignment="-1",col_name="addr",colhdr="Address"},
+ {width="40",alignment="2",col_name="what",colhdr="What"}],
+ body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ addr="0x00010734",func="callee4",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8",times="1"}]}
+ (gdb)
+
+
+File: gdb.info, Node: GDB/MI Data Manipulation, Next: GDB/MI Program Control, Prev: GDB/MI Breakpoint Table Commands, Up: GDB/MI
+
+GDB/MI Data Manipulation
+========================
+
+This section describes the GDB/MI commands that manipulate data:
+examine memory and registers, evaluate expressions, etc.
+
+The `-data-disassemble' Command
+-------------------------------
+
+Synopsis
+........
+
+ -data-disassemble
+ [ -s START-ADDR -e END-ADDR ]
+ | [ -f FILENAME -l LINENUM [ -n LINES ] ]
+ -- MODE
+
+Where:
+
+`START-ADDR'
+ is the beginning address (or `$pc')
+
+`END-ADDR'
+ is the end address
+
+`FILENAME'
+ is the name of the file to disassemble
+
+`LINENUM'
+ is the line number to disassemble around
+
+`LINES'
+ is the the number of disassembly lines to be produced. If it is
+ -1, the whole function will be disassembled, in case no END-ADDR is
+ specified. If END-ADDR is specified as a non-zero value, and
+ LINES is lower than the number of disassembly lines between
+ START-ADDR and END-ADDR, only LINES lines are displayed; if LINES
+ is higher than the number of lines between START-ADDR and
+ END-ADDR, only the lines up to END-ADDR are displayed.
+
+`MODE'
+ is either 0 (meaning only disassembly) or 1 (meaning mixed source
+ and disassembly).
+
+Result
+......
+
+The output for each instruction is composed of four fields:
+
+ * Address
+
+ * Func-name
+
+ * Offset
+
+ * Instruction
+
+ Note that whatever included in the instruction field, is not
+manipulated directely by GDB/MI, i.e. it is not possible to adjust its
+format.
+
+GDB Command
+...........
+
+There's no direct mapping from this command to the CLI.
+
+Example
+.......
+
+Disassemble from the current value of `$pc' to `$pc + 20':
+
+ (gdb)
+ -data-disassemble -s $pc -e "$pc + 20" -- 0
+ ^done,
+ asm_insns=[
+ {address="0x000107c0",func-name="main",offset="4",
+ inst="mov 2, %o0"},
+ {address="0x000107c4",func-name="main",offset="8",
+ inst="sethi %hi(0x11800), %o2"},
+ {address="0x000107c8",func-name="main",offset="12",
+ inst="or %o2, 0x140, %o1\t! 0x11940 <_lib_version+8>"},
+ {address="0x000107cc",func-name="main",offset="16",
+ inst="sethi %hi(0x11800), %o2"},
+ {address="0x000107d0",func-name="main",offset="20",
+ inst="or %o2, 0x168, %o4\t! 0x11968 <_lib_version+48>"}]
+ (gdb)
+
+ Disassemble the whole `main' function. Line 32 is part of `main'.
+
+ -data-disassemble -f basics.c -l 32 -- 0
+ ^done,asm_insns=[
+ {address="0x000107bc",func-name="main",offset="0",
+ inst="save %sp, -112, %sp"},
+ {address="0x000107c0",func-name="main",offset="4",
+ inst="mov 2, %o0"},
+ {address="0x000107c4",func-name="main",offset="8",
+ inst="sethi %hi(0x11800), %o2"},
+ [...]
+ {address="0x0001081c",func-name="main",offset="96",inst="ret "},
+ {address="0x00010820",func-name="main",offset="100",inst="restore "}]
+ (gdb)
+
+ Disassemble 3 instructions from the start of `main':
+
+ (gdb)
+ -data-disassemble -f basics.c -l 32 -n 3 -- 0
+ ^done,asm_insns=[
+ {address="0x000107bc",func-name="main",offset="0",
+ inst="save %sp, -112, %sp"},
+ {address="0x000107c0",func-name="main",offset="4",
+ inst="mov 2, %o0"},
+ {address="0x000107c4",func-name="main",offset="8",
+ inst="sethi %hi(0x11800), %o2"}]
+ (gdb)
+
+ Disassemble 3 instructions from the start of `main' in mixed mode:
+
+ (gdb)
+ -data-disassemble -f basics.c -l 32 -n 3 -- 1
+ ^done,asm_insns=[
+ src_and_asm_line={line="31",
+ file="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb/ \
+ testsuite/gdb.mi/basics.c",line_asm_insn=[
+ {address="0x000107bc",func-name="main",offset="0",
+ inst="save %sp, -112, %sp"}]},
+ src_and_asm_line={line="32",
+ file="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb/ \
+ testsuite/gdb.mi/basics.c",line_asm_insn=[
+ {address="0x000107c0",func-name="main",offset="4",
+ inst="mov 2, %o0"},
+ {address="0x000107c4",func-name="main",offset="8",
+ inst="sethi %hi(0x11800), %o2"}]}]
+ (gdb)
+
+The `-data-evaluate-expression' Command
+---------------------------------------
+
+Synopsis
+........
+
+ -data-evaluate-expression EXPR
+
+ Evaluate EXPR as an expression. The expression could contain an
+inferior function call. The function call will execute synchronously.
+If the expression contains spaces, it must be enclosed in double quotes.
+
+GDB Command
+...........
+
+The corresponding GDB commands are `print', `output', and `call'. In
+`gdbtk' only, there's a corresponding `gdb_eval' command.
+
+Example
+.......
+
+In the following example, the numbers that precede the commands are the
+"tokens" described in *Note GDB/MI Command Syntax: GDB/MI Command
+Syntax. Notice how GDB/MI returns the same tokens in its output.
+
+ 211-data-evaluate-expression A
+ 211^done,value="1"
+ (gdb)
+ 311-data-evaluate-expression &A
+ 311^done,value="0xefffeb7c"
+ (gdb)
+ 411-data-evaluate-expression A+3
+ 411^done,value="4"
+ (gdb)
+ 511-data-evaluate-expression "A + 3"
+ 511^done,value="4"
+ (gdb)
+
+The `-data-list-changed-registers' Command
+------------------------------------------
+
+Synopsis
+........
+
+ -data-list-changed-registers
+
+ Display a list of the registers that have changed.
+
+GDB Command
+...........
+
+GDB doesn't have a direct analog for this command; `gdbtk' has the
+corresponding command `gdb_changed_register_list'.
+
+Example
+.......
+
+On a PPC MBX board:
+
+ (gdb)
+ -exec-continue
+ ^running
+
+ (gdb)
+ *stopped,reason="breakpoint-hit",bkptno="1",frame={func="main",
+ args=[],file="try.c",line="5"}
+ (gdb)
+ -data-list-changed-registers
+ ^done,changed-registers=["0","1","2","4","5","6","7","8","9",
+ "10","11","13","14","15","16","17","18","19","20","21","22","23",
+ "24","25","26","27","28","30","31","64","65","66","67","69"]
+ (gdb)
+
+The `-data-list-register-names' Command
+---------------------------------------
+
+Synopsis
+........
+
+ -data-list-register-names [ ( REGNO )+ ]
+
+ Show a list of register names for the current target. If no
+arguments are given, it shows a list of the names of all the registers.
+If integer numbers are given as arguments, it will print a list of the
+names of the registers corresponding to the arguments. To ensure
+consistency between a register name and its number, the output list may
+include empty register names.
+
+GDB Command
+...........
+
+GDB does not have a command which corresponds to
+`-data-list-register-names'. In `gdbtk' there is a corresponding
+command `gdb_regnames'.
+
+Example
+.......
+
+For the PPC MBX board:
+ (gdb)
+ -data-list-register-names
+ ^done,register-names=["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","f0","f1","f2","f3","f4","f5","f6","f7","f8","f9",
+ "f10","f11","f12","f13","f14","f15","f16","f17","f18","f19","f20",
+ "f21","f22","f23","f24","f25","f26","f27","f28","f29","f30","f31",
+ "", "pc","ps","cr","lr","ctr","xer"]
+ (gdb)
+ -data-list-register-names 1 2 3
+ ^done,register-names=["r1","r2","r3"]
+ (gdb)
+
+The `-data-list-register-values' Command
+----------------------------------------
+
+Synopsis
+........
+
+ -data-list-register-values FMT [ ( REGNO )*]
+
+ Display the registers' contents. FMT is the format according to
+which the registers' contents are to be returned, followed by an
+optional list of numbers specifying the registers to display. A
+missing list of numbers indicates that the contents of all the
+registers must be returned.
+
+ Allowed formats for FMT are:
+
+`x'
+ Hexadecimal
+
+`o'
+ Octal
+
+`t'
+ Binary
+
+`d'
+ Decimal
+
+`r'
+ Raw
+
+`N'
+ Natural
+
+GDB Command
+...........
+
+The corresponding GDB commands are `info reg', `info all-reg', and (in
+`gdbtk') `gdb_fetch_registers'.
+
+Example
+.......
+
+For a PPC MBX board (note: line breaks are for readability only, they
+don't appear in the actual output):
+
+ (gdb)
+ -data-list-register-values r 64 65
+ ^done,register-values=[{number="64",value="0xfe00a300"},
+ {number="65",value="0x00029002"}]
+ (gdb)
+ -data-list-register-values x
+ ^done,register-values=[{number="0",value="0xfe0043c8"},
+ {number="1",value="0x3fff88"},{number="2",value="0xfffffffe"},
+ {number="3",value="0x0"},{number="4",value="0xa"},
+ {number="5",value="0x3fff68"},{number="6",value="0x3fff58"},
+ {number="7",value="0xfe011e98"},{number="8",value="0x2"},
+ {number="9",value="0xfa202820"},{number="10",value="0xfa202808"},
+ {number="11",value="0x1"},{number="12",value="0x0"},
+ {number="13",value="0x4544"},{number="14",value="0xffdfffff"},
+ {number="15",value="0xffffffff"},{number="16",value="0xfffffeff"},
+ {number="17",value="0xefffffed"},{number="18",value="0xfffffffe"},
+ {number="19",value="0xffffffff"},{number="20",value="0xffffffff"},
+ {number="21",value="0xffffffff"},{number="22",value="0xfffffff7"},
+ {number="23",value="0xffffffff"},{number="24",value="0xffffffff"},
+ {number="25",value="0xffffffff"},{number="26",value="0xfffffffb"},
+ {number="27",value="0xffffffff"},{number="28",value="0xf7bfffff"},
+ {number="29",value="0x0"},{number="30",value="0xfe010000"},
+ {number="31",value="0x0"},{number="32",value="0x0"},
+ {number="33",value="0x0"},{number="34",value="0x0"},
+ {number="35",value="0x0"},{number="36",value="0x0"},
+ {number="37",value="0x0"},{number="38",value="0x0"},
+ {number="39",value="0x0"},{number="40",value="0x0"},
+ {number="41",value="0x0"},{number="42",value="0x0"},
+ {number="43",value="0x0"},{number="44",value="0x0"},
+ {number="45",value="0x0"},{number="46",value="0x0"},
+ {number="47",value="0x0"},{number="48",value="0x0"},
+ {number="49",value="0x0"},{number="50",value="0x0"},
+ {number="51",value="0x0"},{number="52",value="0x0"},
+ {number="53",value="0x0"},{number="54",value="0x0"},
+ {number="55",value="0x0"},{number="56",value="0x0"},
+ {number="57",value="0x0"},{number="58",value="0x0"},
+ {number="59",value="0x0"},{number="60",value="0x0"},
+ {number="61",value="0x0"},{number="62",value="0x0"},
+ {number="63",value="0x0"},{number="64",value="0xfe00a300"},
+ {number="65",value="0x29002"},{number="66",value="0x202f04b5"},
+ {number="67",value="0xfe0043b0"},{number="68",value="0xfe00b3e4"},
+ {number="69",value="0x20002b03"}]
+ (gdb)
+
+The `-data-read-memory' Command
+-------------------------------
+
+Synopsis
+........
+
+ -data-read-memory [ -o BYTE-OFFSET ]
+ ADDRESS WORD-FORMAT WORD-SIZE
+ NR-ROWS NR-COLS [ ASCHAR ]
+
+where:
+
+`ADDRESS'
+ An expression specifying the address of the first memory word to be
+ read. Complex expressions containing embedded white space should
+ be quoted using the C convention.
+
+`WORD-FORMAT'
+ The format to be used to print the memory words. The notation is
+ the same as for GDB's `print' command (*note Output formats:
+ Output Formats.).
+
+`WORD-SIZE'
+ The size of each memory word in bytes.
+
+`NR-ROWS'
+ The number of rows in the output table.
+
+`NR-COLS'
+ The number of columns in the output table.
+
+`ASCHAR'
+ If present, indicates that each row should include an ASCII dump.
+ The value of ASCHAR is used as a padding character when a byte is
+ not a member of the printable ASCII character set (printable ASCII
+ characters are those whose code is between 32 and 126,
+ inclusively).
+
+`BYTE-OFFSET'
+ An offset to add to the ADDRESS before fetching memory.
+
+ This command displays memory contents as a table of NR-ROWS by
+NR-COLS words, each word being WORD-SIZE bytes. In total, `NR-ROWS *
+NR-COLS * WORD-SIZE' bytes are read (returned as `total-bytes').
+Should less than the requested number of bytes be returned by the
+target, the missing words are identified using `N/A'. The number of
+bytes read from the target is returned in `nr-bytes' and the starting
+address used to read memory in `addr'.
+
+ The address of the next/previous row or page is available in
+`next-row' and `prev-row', `next-page' and `prev-page'.
+
+GDB Command
+...........
+
+The corresponding GDB command is `x'. `gdbtk' has `gdb_get_mem' memory
+read command.
+
+Example
+.......
+
+Read six bytes of memory starting at `bytes+6' but then offset by `-6'
+bytes. Format as three rows of two columns. One byte per word.
+Display each word in hex.
+
+ (gdb)
+ 9-data-read-memory -o -6 -- bytes+6 x 1 3 2
+ 9^done,addr="0x00001390",nr-bytes="6",total-bytes="6",
+ next-row="0x00001396",prev-row="0x0000138e",next-page="0x00001396",
+ prev-page="0x0000138a",memory=[
+ {addr="0x00001390",data=["0x00","0x01"]},
+ {addr="0x00001392",data=["0x02","0x03"]},
+ {addr="0x00001394",data=["0x04","0x05"]}]
+ (gdb)
+
+ Read two bytes of memory starting at address `shorts + 64' and
+display as a single word formatted in decimal.
+
+ (gdb)
+ 5-data-read-memory shorts+64 d 2 1 1
+ 5^done,addr="0x00001510",nr-bytes="2",total-bytes="2",
+ next-row="0x00001512",prev-row="0x0000150e",
+ next-page="0x00001512",prev-page="0x0000150e",memory=[
+ {addr="0x00001510",data=["128"]}]
+ (gdb)
+
+ Read thirty two bytes of memory starting at `bytes+16' and format as
+eight rows of four columns. Include a string encoding with `x' used as
+the non-printable character.
+
+ (gdb)
+ 4-data-read-memory bytes+16 x 1 8 4 x
+ 4^done,addr="0x000013a0",nr-bytes="32",total-bytes="32",
+ next-row="0x000013c0",prev-row="0x0000139c",
+ next-page="0x000013c0",prev-page="0x00001380",memory=[
+ {addr="0x000013a0",data=["0x10","0x11","0x12","0x13"],ascii="xxxx"},
+ {addr="0x000013a4",data=["0x14","0x15","0x16","0x17"],ascii="xxxx"},
+ {addr="0x000013a8",data=["0x18","0x19","0x1a","0x1b"],ascii="xxxx"},
+ {addr="0x000013ac",data=["0x1c","0x1d","0x1e","0x1f"],ascii="xxxx"},
+ {addr="0x000013b0",data=["0x20","0x21","0x22","0x23"],ascii=" !\"#"},
+ {addr="0x000013b4",data=["0x24","0x25","0x26","0x27"],ascii="$%&'"},
+ {addr="0x000013b8",data=["0x28","0x29","0x2a","0x2b"],ascii="()*+"},
+ {addr="0x000013bc",data=["0x2c","0x2d","0x2e","0x2f"],ascii=",-./"}]
+ (gdb)
+
+The `-display-delete' Command
+-----------------------------
+
+Synopsis
+........
+
+ -display-delete NUMBER
+
+ Delete the display NUMBER.
+
+GDB Command
+...........
+
+The corresponding GDB command is `delete display'.
+
+Example
+.......
+
+N.A.
+
+The `-display-disable' Command
+------------------------------
+
+Synopsis
+........
+
+ -display-disable NUMBER
+
+ Disable display NUMBER.
+
+GDB Command
+...........
+
+The corresponding GDB command is `disable display'.
+
+Example
+.......
+
+N.A.
+
+The `-display-enable' Command
+-----------------------------
+
+Synopsis
+........
+
+ -display-enable NUMBER
+
+ Enable display NUMBER.
+
+GDB Command
+...........
+
+The corresponding GDB command is `enable display'.
+
+Example
+.......
+
+N.A.
+
+The `-display-insert' Command
+-----------------------------
+
+Synopsis
+........
+
+ -display-insert EXPRESSION
+
+ Display EXPRESSION every time the program stops.
+
+GDB Command
+...........
+
+The corresponding GDB command is `display'.
+
+Example
+.......
+
+N.A.
+
+The `-display-list' Command
+---------------------------
+
+Synopsis
+........
+
+ -display-list
+
+ List the displays. Do not show the current values.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info display'.
+
+Example
+.......
+
+N.A.
+
+The `-environment-cd' Command
+-----------------------------
+
+Synopsis
+........
+
+ -environment-cd PATHDIR
+
+ Set GDB's working directory.
+
+GDB Command
+...........
+
+The corresponding GDB command is `cd'.
+
+Example
+.......
+
+ (gdb)
+ -environment-cd /kwikemart/marge/ezannoni/flathead-dev/devo/gdb
+ ^done
+ (gdb)
+
+The `-environment-directory' Command
+------------------------------------
+
+Synopsis
+........
+
+ -environment-directory [ -r ] [ PATHDIR ]+
+
+ Add directories PATHDIR to beginning of search path for source files.
+If the `-r' option is used, the search path is reset to the default
+search path. If directories PATHDIR are supplied in addition to the
+`-r' option, the search path is first reset and then addition occurs as
+normal. Multiple directories may be specified, separated by blanks.
+Specifying multiple directories in a single command results in the
+directories added to the beginning of the search path in the same order
+they were presented in the command. If blanks are needed as part of a
+directory name, double-quotes should be used around the name. In the
+command output, the path will show up separated by the system
+directory-separator character. The directory-seperator character must
+not be used in any directory name. If no directories are specified,
+the current search path is displayed.
+
+GDB Command
+...........
+
+The corresponding GDB command is `dir'.
+
+Example
+.......
+
+ (gdb)
+ -environment-directory /kwikemart/marge/ezannoni/flathead-dev/devo/gdb
+ ^done,source-path="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb:$cdir:$cwd"
+ (gdb)
+ -environment-directory ""
+ ^done,source-path="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb:$cdir:$cwd"
+ (gdb)
+ -environment-directory -r /home/jjohnstn/src/gdb /usr/src
+ ^done,source-path="/home/jjohnstn/src/gdb:/usr/src:$cdir:$cwd"
+ (gdb)
+ -environment-directory -r
+ ^done,source-path="$cdir:$cwd"
+ (gdb)
+
+The `-environment-path' Command
+-------------------------------
+
+Synopsis
+........
+
+ -environment-path [ -r ] [ PATHDIR ]+
+
+ Add directories PATHDIR to beginning of search path for object files.
+If the `-r' option is used, the search path is reset to the original
+search path that existed at gdb start-up. If directories PATHDIR are
+supplied in addition to the `-r' option, the search path is first reset
+and then addition occurs as normal. Multiple directories may be
+specified, separated by blanks. Specifying multiple directories in a
+single command results in the directories added to the beginning of the
+search path in the same order they were presented in the command. If
+blanks are needed as part of a directory name, double-quotes should be
+used around the name. In the command output, the path will show up
+separated by the system directory-separator character. The
+directory-seperator character must not be used in any directory name.
+If no directories are specified, the current path is displayed.
+
+GDB Command
+...........
+
+The corresponding GDB command is `path'.
+
+Example
+.......
+
+ (gdb)
+ -environment-path
+ ^done,path="/usr/bin"
+ (gdb)
+ -environment-path /kwikemart/marge/ezannoni/flathead-dev/ppc-eabi/gdb /bin
+ ^done,path="/kwikemart/marge/ezannoni/flathead-dev/ppc-eabi/gdb:/bin:/usr/bin"
+ (gdb)
+ -environment-path -r /usr/local/bin
+ ^done,path="/usr/local/bin:/usr/bin"
+ (gdb)
+
+The `-environment-pwd' Command
+------------------------------
+
+Synopsis
+........
+
+ -environment-pwd
+
+ Show the current working directory.
+
+GDB command
+...........
+
+The corresponding GDB command is `pwd'.
+
+Example
+.......
+
+ (gdb)
+ -environment-pwd
+ ^done,cwd="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb"
+ (gdb)
+
+
+File: gdb.info, Node: GDB/MI Program Control, Next: GDB/MI Miscellaneous Commands, Prev: GDB/MI Data Manipulation, Up: GDB/MI
+
+GDB/MI Program control
+======================
+
+Program termination
+...................
+
+As a result of execution, the inferior program can run to completion, if
+it doesn't encounter any breakpoints. In this case the output will
+include an exit code, if the program has exited exceptionally.
+
+Examples
+........
+
+Program exited normally:
+
+ (gdb)
+ -exec-run
+ ^running
+ (gdb)
+ x = 55
+ *stopped,reason="exited-normally"
+ (gdb)
+
+Program exited exceptionally:
+
+ (gdb)
+ -exec-run
+ ^running
+ (gdb)
+ x = 55
+ *stopped,reason="exited",exit-code="01"
+ (gdb)
+
+ Another way the program can terminate is if it receives a signal
+such as `SIGINT'. In this case, GDB/MI displays this:
+
+ (gdb)
+ *stopped,reason="exited-signalled",signal-name="SIGINT",
+ signal-meaning="Interrupt"
+
+The `-exec-abort' Command
+-------------------------
+
+Synopsis
+........
+
+ -exec-abort
+
+ Kill the inferior running program.
+
+GDB Command
+...........
+
+The corresponding GDB command is `kill'.
+
+Example
+.......
+
+N.A.
+
+The `-exec-arguments' Command
+-----------------------------
+
+Synopsis
+........
+
+ -exec-arguments ARGS
+
+ Set the inferior program arguments, to be used in the next
+`-exec-run'.
+
+GDB Command
+...........
+
+The corresponding GDB command is `set args'.
+
+Example
+.......
+
+Don't have one around.
+
+The `-exec-continue' Command
+----------------------------
+
+Synopsis
+........
+
+ -exec-continue
+
+ Asynchronous command. Resumes the execution of the inferior program
+until a breakpoint is encountered, or until the inferior exits.
+
+GDB Command
+...........
+
+The corresponding GDB corresponding is `continue'.
+
+Example
+.......
+
+ -exec-continue
+ ^running
+ (gdb)
+ @Hello world
+ *stopped,reason="breakpoint-hit",bkptno="2",frame={func="foo",args=[],
+ file="hello.c",line="13"}
+ (gdb)
+
+The `-exec-finish' Command
+--------------------------
+
+Synopsis
+........
+
+ -exec-finish
+
+ Asynchronous command. Resumes the execution of the inferior program
+until the current function is exited. Displays the results returned by
+the function.
+
+GDB Command
+...........
+
+The corresponding GDB command is `finish'.
+
+Example
+.......
+
+Function returning `void'.
+
+ -exec-finish
+ ^running
+ (gdb)
+ @hello from foo
+ *stopped,reason="function-finished",frame={func="main",args=[],
+ file="hello.c",line="7"}
+ (gdb)
+
+ Function returning other than `void'. The name of the internal GDB
+variable storing the result is printed, together with the value itself.
+
+ -exec-finish
+ ^running
+ (gdb)
+ *stopped,reason="function-finished",frame={addr="0x000107b0",func="foo",
+ args=[{name="a",value="1"],{name="b",value="9"}},
+ file="recursive2.c",line="14"},
+ gdb-result-var="$1",return-value="0"
+ (gdb)
+
+The `-exec-interrupt' Command
+-----------------------------
+
+Synopsis
+........
+
+ -exec-interrupt
+
+ Asynchronous command. Interrupts the background execution of the
+target. Note how the token associated with the stop message is the one
+for the execution command that has been interrupted. The token for the
+interrupt itself only appears in the `^done' output. If the user is
+trying to interrupt a non-running program, an error message will be
+printed.
+
+GDB Command
+...........
+
+The corresponding GDB command is `interrupt'.
+
+Example
+.......
+
+ (gdb)
+ 111-exec-continue
+ 111^running
+
+ (gdb)
+ 222-exec-interrupt
+ 222^done
+ (gdb)
+ 111*stopped,signal-name="SIGINT",signal-meaning="Interrupt",
+ frame={addr="0x00010140",func="foo",args=[],file="try.c",line="13"}
+ (gdb)
+
+ (gdb)
+ -exec-interrupt
+ ^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
+ (gdb)
+
+The `-exec-next' Command
+------------------------
+
+Synopsis
+........
+
+ -exec-next
+
+ Asynchronous command. Resumes execution of the inferior program,
+stopping when the beginning of the next source line is reached.
+
+GDB Command
+...........
+
+The corresponding GDB command is `next'.
+
+Example
+.......
+
+ -exec-next
+ ^running
+ (gdb)
+ *stopped,reason="end-stepping-range",line="8",file="hello.c"
+ (gdb)
+
+The `-exec-next-instruction' Command
+------------------------------------
+
+Synopsis
+........
+
+ -exec-next-instruction
+
+ Asynchronous command. Executes one machine instruction. If the
+instruction is a function call continues until the function returns. If
+the program stops at an instruction in the middle of a source line, the
+address will be printed as well.
+
+GDB Command
+...........
+
+The corresponding GDB command is `nexti'.
+
+Example
+.......
+
+ (gdb)
+ -exec-next-instruction
+ ^running
+
+ (gdb)
+ *stopped,reason="end-stepping-range",
+ addr="0x000100d4",line="5",file="hello.c"
+ (gdb)
+
+The `-exec-return' Command
+--------------------------
+
+Synopsis
+........
+
+ -exec-return
+
+ Makes current function return immediately. Doesn't execute the
+inferior. Displays the new current frame.
+
+GDB Command
+...........
+
+The corresponding GDB command is `return'.
+
+Example
+.......
+
+ (gdb)
+ 200-break-insert callee4
+ 200^done,bkpt={number="1",addr="0x00010734",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8"}
+ (gdb)
+ 000-exec-run
+ 000^running
+ (gdb)
+ 000*stopped,reason="breakpoint-hit",bkptno="1",
+ frame={func="callee4",args=[],
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8"}
+ (gdb)
+ 205-break-delete
+ 205^done
+ (gdb)
+ 111-exec-return
+ 111^done,frame={level="0",func="callee3",
+ args=[{name="strarg",
+ value="0x11940 \"A string argument.\""}],
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="18"}
+ (gdb)
+
+The `-exec-run' Command
+-----------------------
+
+Synopsis
+........
+
+ -exec-run
+
+ Asynchronous command. Starts execution of the inferior from the
+beginning. The inferior executes until either a breakpoint is
+encountered or the program exits.
+
+GDB Command
+...........
+
+The corresponding GDB command is `run'.
+
+Example
+.......
+
+ (gdb)
+ -break-insert main
+ ^done,bkpt={number="1",addr="0x0001072c",file="recursive2.c",line="4"}
+ (gdb)
+ -exec-run
+ ^running
+ (gdb)
+ *stopped,reason="breakpoint-hit",bkptno="1",
+ frame={func="main",args=[],file="recursive2.c",line="4"}
+ (gdb)
+
+The `-exec-show-arguments' Command
+----------------------------------
+
+Synopsis
+........
+
+ -exec-show-arguments
+
+ Print the arguments of the program.
+
+GDB Command
+...........
+
+The corresponding GDB command is `show args'.
+
+Example
+.......
+
+N.A.
+
+The `-exec-step' Command
+------------------------
+
+Synopsis
+........
+
+ -exec-step
+
+ Asynchronous command. Resumes execution of the inferior program,
+stopping when the beginning of the next source line is reached, if the
+next source line is not a function call. If it is, stop at the first
+instruction of the called function.
+
+GDB Command
+...........
+
+The corresponding GDB command is `step'.
+
+Example
+.......
+
+Stepping into a function:
+
+ -exec-step
+ ^running
+ (gdb)
+ *stopped,reason="end-stepping-range",
+ frame={func="foo",args=[{name="a",value="10"},
+ {name="b",value="0"}],file="recursive2.c",line="11"}
+ (gdb)
+
+ Regular stepping:
+
+ -exec-step
+ ^running
+ (gdb)
+ *stopped,reason="end-stepping-range",line="14",file="recursive2.c"
+ (gdb)
+
+The `-exec-step-instruction' Command
+------------------------------------
+
+Synopsis
+........
+
+ -exec-step-instruction
+
+ Asynchronous command. Resumes the inferior which executes one
+machine instruction. The output, once GDB has stopped, will vary
+depending on whether we have stopped in the middle of a source line or
+not. In the former case, the address at which the program stopped will
+be printed as well.
+
+GDB Command
+...........
+
+The corresponding GDB command is `stepi'.
+
+Example
+.......
+
+ (gdb)
+ -exec-step-instruction
+ ^running
+
+ (gdb)
+ *stopped,reason="end-stepping-range",
+ frame={func="foo",args=[],file="try.c",line="10"}
+ (gdb)
+ -exec-step-instruction
+ ^running
+
+ (gdb)
+ *stopped,reason="end-stepping-range",
+ frame={addr="0x000100f4",func="foo",args=[],file="try.c",line="10"}
+ (gdb)
+
+The `-exec-until' Command
+-------------------------
+
+Synopsis
+........
+
+ -exec-until [ LOCATION ]
+
+ Asynchronous command. Executes the inferior until the LOCATION
+specified in the argument is reached. If there is no argument, the
+inferior executes until a source line greater than the current one is
+reached. The reason for stopping in this case will be
+`location-reached'.
+
+GDB Command
+...........
+
+The corresponding GDB command is `until'.
+
+Example
+.......
+
+ (gdb)
+ -exec-until recursive2.c:6
+ ^running
+ (gdb)
+ x = 55
+ *stopped,reason="location-reached",frame={func="main",args=[],
+ file="recursive2.c",line="6"}
+ (gdb)
+
+The `-file-exec-and-symbols' Command
+------------------------------------
+
+Synopsis
+........
+
+ -file-exec-and-symbols FILE
+
+ Specify the executable file to be debugged. This file is the one
+from which the symbol table is also read. If no file is specified, the
+command clears the executable and symbol information. If breakpoints
+are set when using this command with no arguments, GDB will produce
+error messages. Otherwise, no output is produced, except a completion
+notification.
+
+GDB Command
+...........
+
+The corresponding GDB command is `file'.
+
+Example
+.......
+
+ (gdb)
+ -file-exec-and-symbols /kwikemart/marge/ezannoni/TRUNK/mbx/hello.mbx
+ ^done
+ (gdb)
+
+The `-file-exec-file' Command
+-----------------------------
+
+Synopsis
+........
+
+ -file-exec-file FILE
+
+ Specify the executable file to be debugged. Unlike
+`-file-exec-and-symbols', the symbol table is _not_ read from this
+file. If used without argument, GDB clears the information about the
+executable file. No output is produced, except a completion
+notification.
+
+GDB Command
+...........
+
+The corresponding GDB command is `exec-file'.
+
+Example
+.......
+
+ (gdb)
+ -file-exec-file /kwikemart/marge/ezannoni/TRUNK/mbx/hello.mbx
+ ^done
+ (gdb)
+
+The `-file-list-exec-sections' Command
+--------------------------------------
+
+Synopsis
+........
+
+ -file-list-exec-sections
+
+ List the sections of the current executable file.
+
+GDB Command
+...........
+
+The GDB command `info file' shows, among the rest, the same information
+as this command. `gdbtk' has a corresponding command `gdb_load_info'.
+
+Example
+.......
+
+N.A.
+
+The `-file-list-exec-source-file' Command
+-----------------------------------------
+
+Synopsis
+........
+
+ -file-list-exec-source-file
+
+ List the line number, the current source file, and the absolute path
+to the current source file for the current executable.
+
+GDB Command
+...........
+
+There's no GDB command which directly corresponds to this one.
+
+Example
+.......
+
+ (gdb)
+ 123-file-list-exec-source-file
+ 123^done,line="1",file="foo.c",fullname="/home/bar/foo.c"
+ (gdb)
+
+The `-file-list-exec-source-files' Command
+------------------------------------------
+
+Synopsis
+........
+
+ -file-list-exec-source-files
+
+ List the source files for the current executable.
+
+GDB Command
+...........
+
+There's no GDB command which directly corresponds to this one. `gdbtk'
+has an analogous command `gdb_listfiles'.
+
+Example
+.......
+
+N.A.
+
+The `-file-list-shared-libraries' Command
+-----------------------------------------
+
+Synopsis
+........
+
+ -file-list-shared-libraries
+
+ List the shared libraries in the program.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info shared'.
+
+Example
+.......
+
+N.A.
+
+The `-file-list-symbol-files' Command
+-------------------------------------
+
+Synopsis
+........
+
+ -file-list-symbol-files
+
+ List symbol files.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info file' (part of it).
+
+Example
+.......
+
+N.A.
+
+The `-file-symbol-file' Command
+-------------------------------
+
+Synopsis
+........
+
+ -file-symbol-file FILE
+
+ Read symbol table info from the specified FILE argument. When used
+without arguments, clears GDB's symbol table info. No output is
+produced, except for a completion notification.
+
+GDB Command
+...........
+
+The corresponding GDB command is `symbol-file'.
+
+Example
+.......
+
+ (gdb)
+ -file-symbol-file /kwikemart/marge/ezannoni/TRUNK/mbx/hello.mbx
+ ^done
+ (gdb)
+
+
+File: gdb.info, Node: GDB/MI Miscellaneous Commands, Next: GDB/MI Stack Manipulation, Prev: GDB/MI Program Control, Up: GDB/MI
+
+Miscellaneous GDB commands in GDB/MI
+====================================
+
+The `-gdb-exit' Command
+-----------------------
+
+Synopsis
+........
+
+ -gdb-exit
+
+ Exit GDB immediately.
+
+GDB Command
+...........
+
+Approximately corresponds to `quit'.
+
+Example
+.......
+
+ (gdb)
+ -gdb-exit
+
+The `-gdb-set' Command
+----------------------
+
+Synopsis
+........
+
+ -gdb-set
+
+ Set an internal GDB variable.
+
+GDB Command
+...........
+
+The corresponding GDB command is `set'.
+
+Example
+.......
+
+ (gdb)
+ -gdb-set $foo=3
+ ^done
+ (gdb)
+
+The `-gdb-show' Command
+-----------------------
+
+Synopsis
+........
+
+ -gdb-show
+
+ Show the current value of a GDB variable.
+
+GDB command
+...........
+
+The corresponding GDB command is `show'.
+
+Example
+.......
+
+ (gdb)
+ -gdb-show annotate
+ ^done,value="0"
+ (gdb)
+
+The `-gdb-version' Command
+--------------------------
+
+Synopsis
+........
+
+ -gdb-version
+
+ Show version information for GDB. Used mostly in testing.
+
+GDB Command
+...........
+
+There's no equivalent GDB command. GDB by default shows this
+information when you start an interactive session.
+
+Example
+.......
+
+ (gdb)
+ -gdb-version
+ ~GNU gdb 5.2.1
+ ~Copyright 2000 Free Software Foundation, Inc.
+ ~GDB is free software, covered by the GNU General Public License, and
+ ~you are welcome to change it and/or 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.
+ ~This GDB was configured as
+ "--host=sparc-sun-solaris2.5.1 --target=ppc-eabi".
+ ^done
+ (gdb)
+
+The `-interpreter-exec' Command
+-------------------------------
+
+Synopsis
+--------
+
+ -interpreter-exec INTERPRETER COMMAND
+
+ Execute the specified COMMAND in the given INTERPRETER.
+
+GDB Command
+-----------
+
+The corresponding GDB command is `interpreter-exec'.
+
+Example
+-------
+
+ (gdb)
+ -interpreter-exec console "break main"
+ &"During symbol reading, couldn't parse type; debugger out of date?.\n"
+ &"During symbol reading, bad structure-type format.\n"
+ ~"Breakpoint 1 at 0x8074fc6: file ../../src/gdb/main.c, line 743.\n"
+ ^done
+ (gdb)
+
+
+File: gdb.info, Node: GDB/MI Stack Manipulation, Next: GDB/MI Symbol Query, Prev: GDB/MI Miscellaneous Commands, Up: GDB/MI
+
+GDB/MI Stack Manipulation Commands
+==================================
+
+The `-stack-info-frame' Command
+-------------------------------
+
+Synopsis
+........
+
+ -stack-info-frame
+
+ Get info on the current frame.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info frame' or `frame' (without
+arguments).
+
+Example
+.......
+
+N.A.
+
+The `-stack-info-depth' Command
+-------------------------------
+
+Synopsis
+........
+
+ -stack-info-depth [ MAX-DEPTH ]
+
+ Return the depth of the stack. If the integer argument MAX-DEPTH is
+specified, do not count beyond MAX-DEPTH frames.
+
+GDB Command
+...........
+
+There's no equivalent GDB command.
+
+Example
+.......
+
+For a stack with frame levels 0 through 11:
+
+ (gdb)
+ -stack-info-depth
+ ^done,depth="12"
+ (gdb)
+ -stack-info-depth 4
+ ^done,depth="4"
+ (gdb)
+ -stack-info-depth 12
+ ^done,depth="12"
+ (gdb)
+ -stack-info-depth 11
+ ^done,depth="11"
+ (gdb)
+ -stack-info-depth 13
+ ^done,depth="12"
+ (gdb)
+
+The `-stack-list-arguments' Command
+-----------------------------------
+
+Synopsis
+........
+
+ -stack-list-arguments SHOW-VALUES
+ [ LOW-FRAME HIGH-FRAME ]
+
+ Display a list of the arguments for the frames between LOW-FRAME and
+HIGH-FRAME (inclusive). If LOW-FRAME and HIGH-FRAME are not provided,
+list the arguments for the whole call stack.
+
+ The SHOW-VALUES argument must have a value of 0 or 1. A value of 0
+means that only the names of the arguments are listed, a value of 1
+means that both names and values of the arguments are printed.
+
+GDB Command
+...........
+
+GDB does not have an equivalent command. `gdbtk' has a `gdb_get_args'
+command which partially overlaps with the functionality of
+`-stack-list-arguments'.
+
+Example
+.......
+
+ (gdb)
+ -stack-list-frames
+ ^done,
+ stack=[
+ frame={level="0",addr="0x00010734",func="callee4",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8"},
+ frame={level="1",addr="0x0001076c",func="callee3",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="17"},
+ frame={level="2",addr="0x0001078c",func="callee2",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="22"},
+ frame={level="3",addr="0x000107b4",func="callee1",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="27"},
+ frame={level="4",addr="0x000107e0",func="main",
+ file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="32"}]
+ (gdb)
+ -stack-list-arguments 0
+ ^done,
+ stack-args=[
+ frame={level="0",args=[]},
+ frame={level="1",args=[name="strarg"]},
+ frame={level="2",args=[name="intarg",name="strarg"]},
+ frame={level="3",args=[name="intarg",name="strarg",name="fltarg"]},
+ frame={level="4",args=[]}]
+ (gdb)
+ -stack-list-arguments 1
+ ^done,
+ stack-args=[
+ frame={level="0",args=[]},
+ frame={level="1",
+ args=[{name="strarg",value="0x11940 \"A string argument.\""}]},
+ frame={level="2",args=[
+ {name="intarg",value="2"},
+ {name="strarg",value="0x11940 \"A string argument.\""}]},
+ {frame={level="3",args=[
+ {name="intarg",value="2"},
+ {name="strarg",value="0x11940 \"A string argument.\""},
+ {name="fltarg",value="3.5"}]},
+ frame={level="4",args=[]}]
+ (gdb)
+ -stack-list-arguments 0 2 2
+ ^done,stack-args=[frame={level="2",args=[name="intarg",name="strarg"]}]
+ (gdb)
+ -stack-list-arguments 1 2 2
+ ^done,stack-args=[frame={level="2",
+ args=[{name="intarg",value="2"},
+ {name="strarg",value="0x11940 \"A string argument.\""}]}]
+ (gdb)
+
+The `-stack-list-frames' Command
+--------------------------------
+
+Synopsis
+........
+
+ -stack-list-frames [ LOW-FRAME HIGH-FRAME ]
+
+ List the frames currently on the stack. For each frame it displays
+the following info:
+
+`LEVEL'
+ The frame number, 0 being the topmost frame, i.e. the innermost
+ function.
+
+`ADDR'
+ The `$pc' value for that frame.
+
+`FUNC'
+ Function name.
+
+`FILE'
+ File name of the source file where the function lives.
+
+`LINE'
+ Line number corresponding to the `$pc'.
+
+ If invoked without arguments, this command prints a backtrace for the
+whole stack. If given two integer arguments, it shows the frames whose
+levels are between the two arguments (inclusive). If the two arguments
+are equal, it shows the single frame at the corresponding level.
+
+GDB Command
+...........
+
+The corresponding GDB commands are `backtrace' and `where'.
+
+Example
+.......
+
+Full stack backtrace:
+
+ (gdb)
+ -stack-list-frames
+ ^done,stack=
+ [frame={level="0",addr="0x0001076c",func="foo",
+ file="recursive2.c",line="11"},
+ frame={level="1",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="2",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="3",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="4",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="5",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="6",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="7",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="8",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="9",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="10",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="11",addr="0x00010738",func="main",
+ file="recursive2.c",line="4"}]
+ (gdb)
+
+ Show frames between LOW_FRAME and HIGH_FRAME:
+
+ (gdb)
+ -stack-list-frames 3 5
+ ^done,stack=
+ [frame={level="3",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="4",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"},
+ frame={level="5",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"}]
+ (gdb)
+
+ Show a single frame:
+
+ (gdb)
+ -stack-list-frames 3 3
+ ^done,stack=
+ [frame={level="3",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"}]
+ (gdb)
+
+The `-stack-list-locals' Command
+--------------------------------
+
+Synopsis
+........
+
+ -stack-list-locals PRINT-VALUES
+
+ Display the local variable names for the current frame. With an
+argument of 0 or `--no-values', prints only the names of the variables.
+With argument of 1 or `--all-values', prints also their values. With
+argument of 2 or `--simple-values', prints the name, type and value for
+simple data types and the name and type for arrays, structures and
+unions. In this last case, the idea is that the user can see the value
+of simple data types immediately and he can create variable objects for
+other data types if he wishes to explore their values in more detail.
+
+GDB Command
+...........
+
+`info locals' in GDB, `gdb_get_locals' in `gdbtk'.
+
+Example
+.......
+
+ (gdb)
+ -stack-list-locals 0
+ ^done,locals=[name="A",name="B",name="C"]
+ (gdb)
+ -stack-list-locals --all-values
+ ^done,locals=[{name="A",value="1"},{name="B",value="2"},
+ {name="C",value="{1, 2, 3}"}]
+ -stack-list-locals --simple-values
+ ^done,locals=[{name="A",type="int",value="1"},
+ {name="B",type="int",value="2"},{name="C",type="int [3]"}]
+ (gdb)
+
+The `-stack-select-frame' Command
+---------------------------------
+
+Synopsis
+........
+
+ -stack-select-frame FRAMENUM
+
+ Change the current frame. Select a different frame FRAMENUM on the
+stack.
+
+GDB Command
+...........
+
+The corresponding GDB commands are `frame', `up', `down',
+`select-frame', `up-silent', and `down-silent'.
+
+Example
+.......
+
+ (gdb)
+ -stack-select-frame 2
+ ^done
+ (gdb)
+
+
+File: gdb.info, Node: GDB/MI Symbol Query, Next: GDB/MI Target Manipulation, Prev: GDB/MI Stack Manipulation, Up: GDB/MI
+
+GDB/MI Symbol Query Commands
+============================
+
+The `-symbol-info-address' Command
+----------------------------------
+
+Synopsis
+........
+
+ -symbol-info-address SYMBOL
+
+ Describe where SYMBOL is stored.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info address'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-info-file' Command
+-------------------------------
+
+Synopsis
+........
+
+ -symbol-info-file
+
+ Show the file for the symbol.
+
+GDB Command
+...........
+
+There's no equivalent GDB command. `gdbtk' has `gdb_find_file'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-info-function' Command
+-----------------------------------
+
+Synopsis
+........
+
+ -symbol-info-function
+
+ Show which function the symbol lives in.
+
+GDB Command
+...........
+
+`gdb_get_function' in `gdbtk'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-info-line' Command
+-------------------------------
+
+Synopsis
+........
+
+ -symbol-info-line
+
+ Show the core addresses of the code for a source line.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info line'. `gdbtk' has the
+`gdb_get_line' and `gdb_get_file' commands.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-info-symbol' Command
+---------------------------------
+
+Synopsis
+........
+
+ -symbol-info-symbol ADDR
+
+ Describe what symbol is at location ADDR.
+
+GDB Command
+...........
+
+The corresponding GDB command is `info symbol'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-list-functions' Command
+------------------------------------
+
+Synopsis
+........
+
+ -symbol-list-functions
+
+ List the functions in the executable.
+
+GDB Command
+...........
+
+`info functions' in GDB, `gdb_listfunc' and `gdb_search' in `gdbtk'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-list-lines' Command
+--------------------------------
+
+Synopsis
+........
+
+ -symbol-list-lines FILENAME
+
+ Print the list of lines that contain code and their associated
+program addresses for the given source filename. The entries are
+sorted in ascending PC order.
+
+GDB Command
+...........
+
+There is no corresponding GDB command.
+
+Example
+.......
+
+ (gdb)
+ -symbol-list-lines basics.c
+ ^done,lines=[{pc="0x08048554",line="7"},{pc="0x0804855a",line="8"}]
+ (gdb)
+
+The `-symbol-list-types' Command
+--------------------------------
+
+Synopsis
+........
+
+ -symbol-list-types
+
+ List all the type names.
+
+GDB Command
+...........
+
+The corresponding commands are `info types' in GDB, `gdb_search' in
+`gdbtk'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-list-variables' Command
+------------------------------------
+
+Synopsis
+........
+
+ -symbol-list-variables
+
+ List all the global and static variable names.
+
+GDB Command
+...........
+
+`info variables' in GDB, `gdb_search' in `gdbtk'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-locate' Command
+----------------------------
+
+Synopsis
+........
+
+ -symbol-locate
+
+GDB Command
+...........
+
+`gdb_loc' in `gdbtk'.
+
+Example
+.......
+
+N.A.
+
+The `-symbol-type' Command
+--------------------------
+
+Synopsis
+........
+
+ -symbol-type VARIABLE
+
+ Show type of VARIABLE.
+
+GDB Command
+...........
+
+The corresponding GDB command is `ptype', `gdbtk' has
+`gdb_obj_variable'.
+
+Example
+.......
+
+N.A.
+
+
+File: gdb.info, Node: GDB/MI Target Manipulation, Next: GDB/MI Thread Commands, Prev: GDB/MI Symbol Query, Up: GDB/MI
+
+GDB/MI Target Manipulation Commands
+===================================
+
+The `-target-attach' Command
+----------------------------
+
+Synopsis
+........
+
+ -target-attach PID | FILE
+
+ Attach to a process PID or a file FILE outside of GDB.
+
+GDB command
+...........
+
+The corresponding GDB command is `attach'.
+
+Example
+.......
+
+N.A.
+
+The `-target-compare-sections' Command
+--------------------------------------
+
+Synopsis
+........
+
+ -target-compare-sections [ SECTION ]
+
+ Compare data of section SECTION on target to the exec file. Without
+the argument, all sections are compared.
+
+GDB Command
+...........
+
+The GDB equivalent is `compare-sections'.
+
+Example
+.......
+
+N.A.
+
+The `-target-detach' Command
+----------------------------
+
+Synopsis
+........
+
+ -target-detach
+
+ Disconnect from the remote target. There's no output.
+
+GDB command
+...........
+
+The corresponding GDB command is `detach'.
+
+Example
+.......
+
+ (gdb)
+ -target-detach
+ ^done
+ (gdb)
+
+The `-target-disconnect' Command
+--------------------------------
+
+Synopsis
+........
+
+ -target-disconnect
+
+ Disconnect from the remote target. There's no output.
+
+GDB command
+...........
+
+The corresponding GDB command is `disconnect'.
+
+Example
+.......
+
+ (gdb)
+ -target-disconnect
+ ^done
+ (gdb)
+
+The `-target-download' Command
+------------------------------
+
+Synopsis
+........
+
+ -target-download
+
+ Loads the executable onto the remote target. It prints out an
+update message every half second, which includes the fields:
+
+`section'
+ The name of the section.
+
+`section-sent'
+ The size of what has been sent so far for that section.
+
+`section-size'
+ The size of the section.
+
+`total-sent'
+ The total size of what was sent so far (the current and the
+ previous sections).
+
+`total-size'
+ The size of the overall executable to download.
+
+Each message is sent as status record (*note GDB/MI Output Syntax:
+GDB/MI Output Syntax.).
+
+ In addition, it prints the name and size of the sections, as they are
+downloaded. These messages include the following fields:
+
+`section'
+ The name of the section.
+
+`section-size'
+ The size of the section.
+
+`total-size'
+ The size of the overall executable to download.
+
+At the end, a summary is printed.
+
+GDB Command
+...........
+
+The corresponding GDB command is `load'.
+
+Example
+.......
+
+Note: each status message appears on a single line. Here the messages
+have been broken down so that they can fit onto a page.
+
+ (gdb)
+ -target-download
+ +download,{section=".text",section-size="6668",total-size="9880"}
+ +download,{section=".text",section-sent="512",section-size="6668",
+ total-sent="512",total-size="9880"}
+ +download,{section=".text",section-sent="1024",section-size="6668",
+ total-sent="1024",total-size="9880"}
+ +download,{section=".text",section-sent="1536",section-size="6668",
+ total-sent="1536",total-size="9880"}
+ +download,{section=".text",section-sent="2048",section-size="6668",
+ total-sent="2048",total-size="9880"}
+ +download,{section=".text",section-sent="2560",section-size="6668",
+ total-sent="2560",total-size="9880"}
+ +download,{section=".text",section-sent="3072",section-size="6668",
+ total-sent="3072",total-size="9880"}
+ +download,{section=".text",section-sent="3584",section-size="6668",
+ total-sent="3584",total-size="9880"}
+ +download,{section=".text",section-sent="4096",section-size="6668",
+ total-sent="4096",total-size="9880"}
+ +download,{section=".text",section-sent="4608",section-size="6668",
+ total-sent="4608",total-size="9880"}
+ +download,{section=".text",section-sent="5120",section-size="6668",
+ total-sent="5120",total-size="9880"}
+ +download,{section=".text",section-sent="5632",section-size="6668",
+ total-sent="5632",total-size="9880"}
+ +download,{section=".text",section-sent="6144",section-size="6668",
+ total-sent="6144",total-size="9880"}
+ +download,{section=".text",section-sent="6656",section-size="6668",
+ total-sent="6656",total-size="9880"}
+ +download,{section=".init",section-size="28",total-size="9880"}
+ +download,{section=".fini",section-size="28",total-size="9880"}
+ +download,{section=".data",section-size="3156",total-size="9880"}
+ +download,{section=".data",section-sent="512",section-size="3156",
+ total-sent="7236",total-size="9880"}
+ +download,{section=".data",section-sent="1024",section-size="3156",
+ total-sent="7748",total-size="9880"}
+ +download,{section=".data",section-sent="1536",section-size="3156",
+ total-sent="8260",total-size="9880"}
+ +download,{section=".data",section-sent="2048",section-size="3156",
+ total-sent="8772",total-size="9880"}
+ +download,{section=".data",section-sent="2560",section-size="3156",
+ total-sent="9284",total-size="9880"}
+ +download,{section=".data",section-sent="3072",section-size="3156",
+ total-sent="9796",total-size="9880"}
+ ^done,address="0x10004",load-size="9880",transfer-rate="6586",
+ write-rate="429"
+ (gdb)
+
+The `-target-exec-status' Command
+---------------------------------
+
+Synopsis
+........
+
+ -target-exec-status
+
+ Provide information on the state of the target (whether it is
+running or not, for instance).
+
+GDB Command
+...........
+
+There's no equivalent GDB command.
+
+Example
+.......
+
+N.A.
+
+The `-target-list-available-targets' Command
+--------------------------------------------
+
+Synopsis
+........
+
+ -target-list-available-targets
+
+ List the possible targets to connect to.
+
+GDB Command
+...........
+
+The corresponding GDB command is `help target'.
+
+Example
+.......
+
+N.A.
+
+The `-target-list-current-targets' Command
+------------------------------------------
+
+Synopsis
+........
+
+ -target-list-current-targets
+
+ Describe the current target.
+
+GDB Command
+...........
+
+The corresponding information is printed by `info file' (among other
+things).
+
+Example
+.......
+
+N.A.
+
+The `-target-list-parameters' Command
+-------------------------------------
+
+Synopsis
+........
+
+ -target-list-parameters
+
+GDB Command
+...........
+
+No equivalent.
+
+Example
+.......
+
+N.A.
+
+The `-target-select' Command
+----------------------------
+
+Synopsis
+........
+
+ -target-select TYPE PARAMETERS ...
+
+ Connect GDB to the remote target. This command takes two args:
+
+`TYPE'
+ The type of target, for instance `async', `remote', etc.
+
+`PARAMETERS'
+ Device names, host names and the like. *Note Commands for
+ managing targets: Target Commands, for more details.
+
+ The output is a connection notification, followed by the address at
+which the target program is, in the following form:
+
+ ^connected,addr="ADDRESS",func="FUNCTION NAME",
+ args=[ARG LIST]
+
+GDB Command
+...........
+
+The corresponding GDB command is `target'.
+
+Example
+.......
+
+ (gdb)
+ -target-select async /dev/ttya
+ ^connected,addr="0xfe00a300",func="??",args=[]
+ (gdb)
+
+
+File: gdb.info, Node: GDB/MI Thread Commands, Next: GDB/MI Tracepoint Commands, Prev: GDB/MI Target Manipulation, Up: GDB/MI
+
+GDB/MI Thread Commands
+======================
+
+The `-thread-info' Command
+--------------------------
+
+Synopsis
+........
+
+ -thread-info
+
+GDB command
+...........
+
+No equivalent.
+
+Example
+.......
+
+N.A.
+
+The `-thread-list-all-threads' Command
+--------------------------------------
+
+Synopsis
+........
+
+ -thread-list-all-threads
+
+GDB Command
+...........
+
+The equivalent GDB command is `info threads'.
+
+Example
+.......
+
+N.A.
+
+The `-thread-list-ids' Command
+------------------------------
+
+Synopsis
+........
+
+ -thread-list-ids
+
+ Produces a list of the currently known GDB thread ids. At the end
+of the list it also prints the total number of such threads.
+
+GDB Command
+...........
+
+Part of `info threads' supplies the same information.
+
+Example
+.......
+
+No threads present, besides the main process:
+
+ (gdb)
+ -thread-list-ids
+ ^done,thread-ids={},number-of-threads="0"
+ (gdb)
+
+ Several threads:
+
+ (gdb)
+ -thread-list-ids
+ ^done,thread-ids={thread-id="3",thread-id="2",thread-id="1"},
+ number-of-threads="3"
+ (gdb)
+
+The `-thread-select' Command
+----------------------------
+
+Synopsis
+........
+
+ -thread-select THREADNUM
+
+ Make THREADNUM the current thread. It prints the number of the new
+current thread, and the topmost frame for that thread.
+
+GDB Command
+...........
+
+The corresponding GDB command is `thread'.
+
+Example
+.......
+
+ (gdb)
+ -exec-next
+ ^running
+ (gdb)
+ *stopped,reason="end-stepping-range",thread-id="2",line="187",
+ file="../../../devo/gdb/testsuite/gdb.threads/linux-dp.c"
+ (gdb)
+ -thread-list-ids
+ ^done,
+ thread-ids={thread-id="3",thread-id="2",thread-id="1"},
+ number-of-threads="3"
+ (gdb)
+ -thread-select 3
+ ^done,new-thread-id="3",
+ frame={level="0",func="vprintf",
+ args=[{name="format",value="0x8048e9c \"%*s%c %d %c\\n\""},
+ {name="arg",value="0x2"}],file="vprintf.c",line="31"}
+ (gdb)
+
+
+File: gdb.info, Node: GDB/MI Tracepoint Commands, Next: GDB/MI Variable Objects, Prev: GDB/MI Thread Commands, Up: GDB/MI
+
+GDB/MI Tracepoint Commands
+==========================
+
+The tracepoint commands are not yet implemented.
+
+
+File: gdb.info, Node: GDB/MI Variable Objects, Prev: GDB/MI Tracepoint Commands, Up: GDB/MI
+
+GDB/MI Variable Objects
+=======================
+
+Motivation for Variable Objects in GDB/MI
+-----------------------------------------
+
+For the implementation of a variable debugger window (locals, watched
+expressions, etc.), we are proposing the adaptation of the existing code
+used by `Insight'.
+
+ The two main reasons for that are:
+
+ 1. It has been proven in practice (it is already on its second
+ generation).
+
+ 2. It will shorten development time (needless to say how important it
+ is now).
+
+ The original interface was designed to be used by Tcl code, so it was
+slightly changed so it could be used through GDB/MI. This section
+describes the GDB/MI operations that will be available and gives some
+hints about their use.
+
+ _Note_: In addition to the set of operations described here, we
+expect the GUI implementation of a variable window to require, at
+least, the following operations:
+
+ * `-gdb-show' `output-radix'
+
+ * `-stack-list-arguments'
+
+ * `-stack-list-locals'
+
+ * `-stack-select-frame'
+
+Introduction to Variable Objects in GDB/MI
+------------------------------------------
+
+The basic idea behind variable objects is the creation of a named object
+to represent a variable, an expression, a memory location or even a CPU
+register. For each object created, a set of operations is available for
+examining or changing its properties.
+
+ Furthermore, complex data types, such as C structures, are
+represented in a tree format. For instance, the `struct' type variable
+is the root and the children will represent the struct members. If a
+child is itself of a complex type, it will also have children of its
+own. Appropriate language differences are handled for C, C++ and Java.
+
+ When returning the actual values of the objects, this facility allows
+for the individual selection of the display format used in the result
+creation. It can be chosen among: binary, decimal, hexadecimal, octal
+and natural. Natural refers to a default format automatically chosen
+based on the variable type (like decimal for an `int', hex for
+pointers, etc.).
+
+ The following is the complete set of GDB/MI operations defined to
+access this functionality:
+
+*Operation* *Description*
+`-var-create' create a variable object
+`-var-delete' delete the variable object and its children
+`-var-set-format' set the display format of this variable
+`-var-show-format' show the display format of this variable
+`-var-info-num-children' tells how many children this object has
+`-var-list-children' return a list of the object's children
+`-var-info-type' show the type of this variable object
+`-var-info-expression' print what this variable object represents
+`-var-show-attributes' is this variable editable? does it exist
+ here?
+`-var-evaluate-expression' get the value of this variable
+`-var-assign' set the value of this variable
+`-var-update' update the variable and its children
+
+ In the next subsection we describe each operation in detail and
+suggest how it can be used.
+
+Description And Use of Operations on Variable Objects
+-----------------------------------------------------
+
+The `-var-create' Command
+-------------------------
+
+Synopsis
+........
+
+ -var-create {NAME | "-"}
+ {FRAME-ADDR | "*"} EXPRESSION
+
+ This operation creates a variable object, which allows the
+monitoring of a variable, the result of an expression, a memory cell or
+a CPU register.
+
+ The NAME parameter is the string by which the object can be
+referenced. It must be unique. If `-' is specified, the varobj system
+will generate a string "varNNNNNN" automatically. It will be unique
+provided that one does not specify NAME on that format. The command
+fails if a duplicate name is found.
+
+ The frame under which the expression should be evaluated can be
+specified by FRAME-ADDR. A `*' indicates that the current frame should
+be used.
+
+ EXPRESSION is any expression valid on the current language set (must
+not begin with a `*'), or one of the following:
+
+ * `*ADDR', where ADDR is the address of a memory cell
+
+ * `*ADDR-ADDR' -- a memory address range (TBD)
+
+ * `$REGNAME' -- a CPU register name
+
+Result
+......
+
+This operation returns the name, number of children and the type of the
+object created. Type is returned as a string as the ones generated by
+the GDB CLI:
+
+ name="NAME",numchild="N",type="TYPE"
+
+The `-var-delete' Command
+-------------------------
+
+Synopsis
+........
+
+ -var-delete NAME
+
+ Deletes a previously created variable object and all of its children.
+
+ Returns an error if the object NAME is not found.
+
+The `-var-set-format' Command
+-----------------------------
+
+Synopsis
+........
+
+ -var-set-format NAME FORMAT-SPEC
+
+ Sets the output format for the value of the object NAME to be
+FORMAT-SPEC.
+
+ The syntax for the FORMAT-SPEC is as follows:
+
+ FORMAT-SPEC ==>
+ {binary | decimal | hexadecimal | octal | natural}
+
+The `-var-show-format' Command
+------------------------------
+
+Synopsis
+........
+
+ -var-show-format NAME
+
+ Returns the format used to display the value of the object NAME.
+
+ FORMAT ==>
+ FORMAT-SPEC
+
+The `-var-info-num-children' Command
+------------------------------------
+
+Synopsis
+........
+
+ -var-info-num-children NAME
+
+ Returns the number of children of a variable object NAME:
+
+ numchild=N
+
+The `-var-list-children' Command
+--------------------------------
+
+Synopsis
+........
+
+ -var-list-children [PRINT-VALUES] NAME
+
+ Returns a list of the children of the specified variable object.
+With just the variable object name as an argument or with an optional
+preceding argument of 0 or `--no-values', prints only the names of the
+variables. With an optional preceding argument of 1 or `--all-values',
+also prints their values.
+
+Example
+.......
+
+ (gdb)
+ -var-list-children n
+ numchild=N,children=[{name=NAME,
+ numchild=N,type=TYPE},(repeats N times)]
+ (gdb)
+ -var-list-children --all-values n
+ numchild=N,children=[{name=NAME,
+ numchild=N,value=VALUE,type=TYPE},(repeats N times)]
+
+The `-var-info-type' Command
+----------------------------
+
+Synopsis
+........
+
+ -var-info-type NAME
+
+ Returns the type of the specified variable NAME. The type is
+returned as a string in the same format as it is output by the GDB CLI:
+
+ type=TYPENAME
+
+The `-var-info-expression' Command
+----------------------------------
+
+Synopsis
+........
+
+ -var-info-expression NAME
+
+ Returns what is represented by the variable object NAME:
+
+ lang=LANG-SPEC,exp=EXPRESSION
+
+where LANG-SPEC is `{"C" | "C++" | "Java"}'.
+
+The `-var-show-attributes' Command
+----------------------------------
+
+Synopsis
+........
+
+ -var-show-attributes NAME
+
+ List attributes of the specified variable object NAME:
+
+ status=ATTR [ ( ,ATTR )* ]
+
+where ATTR is `{ { editable | noneditable } | TBD }'.
+
+The `-var-evaluate-expression' Command
+--------------------------------------
+
+Synopsis
+........
+
+ -var-evaluate-expression NAME
+
+ Evaluates the expression that is represented by the specified
+variable object and returns its value as a string in the current format
+specified for the object:
+
+ value=VALUE
+
+ Note that one must invoke `-var-list-children' for a variable before
+the value of a child variable can be evaluated.
+
+The `-var-assign' Command
+-------------------------
+
+Synopsis
+........
+
+ -var-assign NAME EXPRESSION
+
+ Assigns the value of EXPRESSION to the variable object specified by
+NAME. The object must be `editable'. If the variable's value is
+altered by the assign, the variable will show up in any subsequent
+`-var-update' list.
+
+Example
+.......
+
+ (gdb)
+ -var-assign var1 3
+ ^done,value="3"
+ (gdb)
+ -var-update *
+ ^done,changelist=[{name="var1",in_scope="true",type_changed="false"}]
+ (gdb)
+
+The `-var-update' Command
+-------------------------
+
+Synopsis
+........
+
+ -var-update {NAME | "*"}
+
+ Update the value of the variable object NAME by evaluating its
+expression after fetching all the new values from memory or registers.
+A `*' causes all existing variable objects to be updated.
+
+
+File: gdb.info, Node: Annotations, Next: GDB/MI, Prev: Emacs, Up: Top
+
+GDB Annotations
+***************
+
+This chapter describes annotations in GDB. Annotations were designed
+to interface GDB to graphical user interfaces or other similar programs
+which want to interact with GDB at a relatively high level.
+
+ The annotation mechanism has largely been superseeded by GDB/MI
+(*note GDB/MI::).
+
+* Menu:
+
+* Annotations Overview:: What annotations are; the general syntax.
+* Server Prefix:: Issuing a command without affecting user state.
+* Prompting:: Annotations marking GDB's need for input.
+* Errors:: Annotations for error messages.
+* Invalidation:: Some annotations describe things now invalid.
+* Annotations for Running::
+ Whether the program is running, how it stopped, etc.
+* Source Annotations:: Annotations describing source code.
+
+
+File: gdb.info, Node: Annotations Overview, Next: Server Prefix, Up: Annotations
+
+What is an Annotation?
+======================
+
+Annotations start with a newline character, two `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 `control-z'
+characters denotes literal output from GDB. Currently there is no need
+for GDB to output a newline followed by two `control-z' characters, but
+if there was such a need, the annotations could be extended with an
+`escape' annotation which means those three characters as output.
+
+ The annotation LEVEL, which is specified using the `--annotate'
+command line option (*note Mode Options::), controls how much
+information GDB prints together with its prompt, values of expressions,
+source lines, and other types of output. Level 0 is for no anntations,
+level 1 is for use when GDB is run as a subprocess of GNU Emacs, level
+3 is the maximum annotation suitable for programs that control GDB, and
+level 2 annotations have been made obsolete (*note Limitations of the
+Annotation Interface: (annotate)Limitations.). This chapter describes
+level 3 annotations.
+
+ A simple example of starting up GDB with annotations is:
+
+ $ gdb --annotate=3
+ GNU gdb 6.0
+ Copyright 2003 Free Software Foundation, Inc.
+ GDB is free software, covered by the GNU General Public License,
+ and you are welcome to change it and/or 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.
+ This GDB was configured as "i386-pc-linux-gnu"
+
+ ^Z^Zpre-prompt
+ (gdb)
+ ^Z^Zprompt
+ quit
+
+ ^Z^Zpost-prompt
+ $
+
+ Here `quit' is input to GDB; the rest is output from GDB. The three
+lines beginning `^Z^Z' (where `^Z' denotes a `control-z' character) are
+annotations; the rest is output from GDB.
+
+
+File: gdb.info, Node: Server Prefix, Next: Prompting, Prev: Annotations Overview, Up: Annotations
+
+The Server Prefix
+=================
+
+To issue a command to GDB without affecting certain aspects of the
+state which is seen by users, prefix it with `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 <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 `output' command instead of the `print' command.
+
+
+File: gdb.info, Node: Prompting, Next: Errors, Prev: Server Prefix, Up: Annotations
+
+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 "input type". Each
+input type has three annotations: a `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 `post-' annotation
+which denotes the end of any echo which may (or may not) be associated
+with the input. For example, the `prompt' input type features the
+following annotations:
+
+ ^Z^Zpre-prompt
+ ^Z^Zprompt
+ ^Z^Zpost-prompt
+
+ The input types are
+
+`prompt'
+ When GDB is prompting for a command (the main GDB prompt).
+
+`commands'
+ When GDB prompts for a set of commands, like in the `commands'
+ command. The annotations are repeated for each command which is
+ input.
+
+`overload-choice'
+ When GDB wants the user to select between various overloaded
+ functions.
+
+`query'
+ When GDB wants the user to confirm a potentially dangerous
+ operation.
+
+`prompt-for-continue'
+ When GDB is asking the user to press return to continue. Note:
+ Don't expect this to work well; instead use `set height 0' to
+ disable prompting. This is because the counting of lines is buggy
+ in the presence of annotations.
+
+
+File: gdb.info, Node: Errors, Next: Invalidation, Prev: Prompting, Up: Annotations
+
+Errors
+======
+
+ ^Z^Zquit
+
+ This annotation occurs right before GDB responds to an interrupt.
+
+ ^Z^Zerror
+
+ 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
+`value-history-begin' annotation is followed by a `error', one cannot
+expect to receive the matching `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.
+
+ A quit or error annotation may be preceded by
+
+ ^Z^Zerror-begin
+
+ Any output between that and the quit or error annotation is the error
+message.
+
+ Warning messages are not yet annotated.
+
+
+File: gdb.info, Node: Invalidation, Next: Annotations for Running, Prev: Errors, Up: Annotations
+
+Invalidation Notices
+====================
+
+The following annotations say that certain pieces of state may have
+changed.
+
+`^Z^Zframes-invalid'
+ The frames (for example, output from the `backtrace' command) may
+ have changed.
+
+`^Z^Zbreakpoints-invalid'
+ The breakpoints may have changed. For example, the user just
+ added or deleted a breakpoint.
+
+
+File: gdb.info, Node: Annotations for Running, Next: Source Annotations, Prev: Invalidation, Up: Annotations
+
+Running the Program
+===================
+
+When the program starts executing due to a GDB command such as `step'
+or `continue',
+
+ ^Z^Zstarting
+
+ is output. When the program stops,
+
+ ^Z^Zstopped
+
+ is output. Before the `stopped' annotation, a variety of
+annotations describe how the program stopped.
+
+`^Z^Zexited EXIT-STATUS'
+ The program exited, and EXIT-STATUS is the exit status (zero for
+ successful exit, otherwise nonzero).
+
+`^Z^Zsignalled'
+ The program exited with a signal. After the `^Z^Zsignalled', the
+ annotation continues:
+
+ INTRO-TEXT
+ ^Z^Zsignal-name
+ NAME
+ ^Z^Zsignal-name-end
+ MIDDLE-TEXT
+ ^Z^Zsignal-string
+ STRING
+ ^Z^Zsignal-string-end
+ END-TEXT
+
+ where NAME is the name of the signal, such as `SIGILL' or
+ `SIGSEGV', and STRING is the explanation of the signal, such as
+ `Illegal Instruction' or `Segmentation fault'. INTRO-TEXT,
+ MIDDLE-TEXT, and END-TEXT are for the user's benefit and have no
+ particular format.
+
+`^Z^Zsignal'
+ The syntax of this annotation is just like `signalled', but GDB is
+ just saying that the program received the signal, not that it was
+ terminated with it.
+
+`^Z^Zbreakpoint NUMBER'
+ The program hit breakpoint number NUMBER.
+
+`^Z^Zwatchpoint NUMBER'
+ The program hit watchpoint number NUMBER.
+
+
+File: gdb.info, Node: Source Annotations, Prev: Annotations for Running, Up: Annotations
+
+Displaying Source
+=================
+
+The following annotation is used instead of displaying source code:
+
+ ^Z^Zsource FILENAME:LINE:CHARACTER:MIDDLE:ADDR
+
+ where FILENAME is an absolute file name indicating which source
+file, LINE is the line number within that file (where 1 is the first
+line in the file), 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), MIDDLE is
+`middle' if ADDR is in the middle of the line, or `beg' if ADDR is at
+the beginning of the line, and ADDR is the address in the target
+program associated with the source which is being displayed. ADDR is
+in the form `0x' followed by one or more lowercase hex digits (note
+that this does not depend on the language).
+
+
+File: gdb.info, Node: GDB Bugs, Next: Formatting Documentation, Prev: GDB/MI, Up: Top
+
+Reporting Bugs in GDB
+*********************
+
+Your bug reports play an essential role in making GDB 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 GDB work
+better. Bug reports are your contribution to the maintenance of GDB.
+
+ 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
+
+
+File: gdb.info, Node: Bug Criteria, Next: Bug Reporting, Up: GDB Bugs
+
+Have you found a bug?
+=====================
+
+If you are not sure whether you have found a bug, here are some
+guidelines:
+
+ * If the debugger gets a fatal signal, for any input whatever, that
+ is a GDB bug. Reliable debuggers never crash.
+
+ * If GDB produces an error message for valid input, that is a bug.
+ (Note that if you're cross debugging, the problem may also be
+ somewhere in the connection to the target.)
+
+ * If GDB 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".
+
+ * If you are an experienced user of debugging tools, your suggestions
+ for improvement of GDB are welcome in any case.
+
+
+File: gdb.info, Node: Bug Reporting, Prev: Bug Criteria, Up: GDB Bugs
+
+How to report bugs
+==================
+
+A number of companies and individuals offer support for GNU products.
+If you obtained GDB 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 `etc/SERVICE' in the GNU Emacs distribution.
+
+ In any event, we also recommend that you submit bug reports for GDB.
+The prefered method is to submit them directly using GDB's Bugs web
+page (http://www.gnu.org/software/gdb/bugs/). Alternatively, the
+e-mail gateway <bug-gdb@gnu.org> can be used.
+
+ *Do not send bug reports to `info-gdb', or to `help-gdb', or to any
+newsgroups.* Most users of GDB do not want to receive bug reports.
+Those that do have arranged to receive `bug-gdb'.
+
+ The mailing list `bug-gdb' has a newsgroup `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.
+
+ The fundamental principle of reporting bugs usefully is this:
+*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. It may be that the bug has been reported previously, but
+neither you nor we can know that unless your bug report is complete and
+self-contained.
+
+ Sometimes people give a few sketchy facts and ask, "Does this ring a
+bell?" Those bug reports are useless, and we urge everyone to _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:
+
+ * The version of GDB. GDB announces it if you start with no
+ arguments; you can also print it at any time using `show version'.
+
+ Without this, we will not know whether there is any point in
+ looking for the bug in the current version of GDB.
+
+ * The type of machine you are using, and the operating system name
+ and version number.
+
+ * What compiler (and its version) was used to compile GDB--e.g.
+ "gcc-2.8.1".
+
+ * What compiler (and its version) was used to compile the program
+ you are debugging--e.g. "gcc-2.8.1", or "HP92453-01 A.10.32.03 HP
+ C Compiler". For GCC, you can say `gcc --version' to get this
+ information; for other compilers, see the documentation for those
+ compilers.
+
+ * The command arguments you gave the compiler to compile your
+ example and observe the bug. For example, did you use `-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.
+
+ * A complete input script, and all necessary source files, that will
+ reproduce the bug.
+
+ * 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 GDB 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 GDB 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.
+
+ * If you wish to suggest changes to the GDB source, send us context
+ diffs. If you even discuss something in the GDB 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.
+
+
+ Here are some things that are not necessary:
+
+ * 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 _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.
+
+ * 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 GDB 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.
+
+ * 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.
+
+
+File: gdb.info, Node: Command Line Editing, Next: Using History Interactively, Prev: Formatting Documentation, Up: Top
+
+Command Line Editing
+********************
+
+This chapter describes the basic features of the GNU 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.
+* Bindable Readline Commands:: A description of most of the Readline commands
+ available for binding
+* Readline vi Mode:: A short description of how to make Readline
+ behave like the vi editor.
+
+
+File: gdb.info, Node: Introduction and Notation, Next: Readline Interaction, Up: Command Line Editing
+
+Introduction to Line Editing
+============================
+
+The following paragraphs describe the notation used to represent
+keystrokes.
+
+ The text `C-k' is read as `Control-K' and describes the character
+produced when the <k> key is pressed while the Control key is depressed.
+
+ The text `M-k' is read as `Meta-K' and describes the character
+produced when the Meta key (if you have one) is depressed, and the <k>
+key is pressed. The Meta key is labeled <ALT> on many keyboards. On
+keyboards with two keys labeled <ALT> (usually to either side of the
+space bar), the <ALT> on the left side is generally set to work as a
+Meta key. The <ALT> key on the right may also be configured to work as
+a Meta key or may be configured as some other modifier, such as a
+Compose key for typing accented characters.
+
+ If you do not have a Meta or <ALT> key, or another key working as a
+Meta key, the identical keystroke can be generated by typing <ESC>
+_first_, and then typing <k>. Either process is known as "metafying"
+the <k> key.
+
+ The text `M-C-k' is read as `Meta-Control-k' and describes the
+character produced by "metafying" `C-k'.
+
+ In addition, several keys have their own names. Specifically,
+<DEL>, <ESC>, <LFD>, <SPC>, <RET>, and <TAB> all stand for themselves
+when seen in this text, or in an init file (*note Readline Init File::).
+If your keyboard lacks a <LFD> key, typing <C-j> will produce the
+desired character. The <RET> key may be labeled <Return> or <Enter> on
+some keyboards.
+
+
+File: gdb.info, Node: Readline Interaction, Next: Readline Init File, Prev: Introduction and Notation, Up: Command Line Editing
+
+Readline Interaction
+====================
+
+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 <RET>. You do not have to be at the end of
+the line to press <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.
+* Searching:: Searching through previous lines.
+
+
+File: gdb.info, Node: Readline Bare Essentials, Next: Readline Movement Commands, Up: Readline Interaction
+
+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 your erase
+character to back up and delete the mistyped character.
+
+ Sometimes you may mistype a character, and not notice the error
+until you have typed several other characters. In that case, you can
+type `C-b' to move the cursor to the left, and then correct your
+mistake. Afterwards, you can move the cursor to the right with `C-f'.
+
+ When you add text in the middle of a line, you will notice that
+characters to the right of the cursor are `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 are `pulled
+back' to fill in the blank space created by the removal of the text. A
+list of the bare essentials for editing the text of an input line
+follows.
+
+`C-b'
+ Move back one character.
+
+`C-f'
+ Move forward one character.
+
+<DEL> or <Backspace>
+ Delete the character to the left of the cursor.
+
+`C-d'
+ Delete the character underneath the cursor.
+
+Printing characters
+ Insert the character into the line at the cursor.
+
+`C-_' or `C-x C-u'
+ Undo the last editing command. You can undo all the way back to an
+ empty line.
+
+(Depending on your configuration, the <Backspace> key be set to delete
+the character to the left of the cursor and the <DEL> key set to delete
+the character underneath the cursor, like `C-d', rather than the
+character to the left of the cursor.)
+
+
+File: gdb.info, Node: Readline Movement Commands, Next: Readline Killing Commands, Prev: Readline Bare Essentials, Up: Readline Interaction
+
+Readline Movement Commands
+--------------------------
+
+The above table describes the most basic 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 `C-b', `C-f', `C-d', and
+<DEL>. Here are some commands for moving more rapidly about the line.
+
+`C-a'
+ Move to the start of the line.
+
+`C-e'
+ Move to the end of the line.
+
+`M-f'
+ Move forward a word, where a word is composed of letters and
+ digits.
+
+`M-b'
+ Move backward a word.
+
+`C-l'
+ Clear the screen, reprinting the current line at the top.
+
+ Notice how `C-f' moves forward a character, while `M-f' moves
+forward a word. It is a loose convention that control keystrokes
+operate on characters while meta keystrokes operate on words.
+
+
+File: gdb.info, Node: Readline Killing Commands, Next: Readline Arguments, Prev: Readline Movement Commands, Up: Readline Interaction
+
+Readline Killing Commands
+-------------------------
+
+"Killing" text means to delete the text from the line, but to save it
+away for later use, usually by "yanking" (re-inserting) it back into
+the line. (`Cut' and `paste' are more recent jargon for `kill' and
+`yank'.)
+
+ 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.
+
+ When you use a kill command, the text is saved in a "kill-ring".
+Any number of consecutive kills save all of the killed text together, so
+that when you yank it back, you get it all. 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.
+
+ Here is the list of commands for killing text.
+
+`C-k'
+ Kill the text from the current cursor position to the end of the
+ line.
+
+`M-d'
+ Kill from the cursor to the end of the current word, or, if between
+ words, to the end of the next word. Word boundaries are the same
+ as those used by `M-f'.
+
+`M-<DEL>'
+ Kill from the cursor the start of the current word, or, if between
+ words, to the start of the previous word. Word boundaries are the
+ same as those used by `M-b'.
+
+`C-w'
+ Kill from the cursor to the previous whitespace. This is
+ different than `M-<DEL>' because the word boundaries differ.
+
+
+ Here is how to "yank" the text back into the line. Yanking means to
+copy the most-recently-killed text from the kill buffer.
+
+`C-y'
+ Yank the most recently killed text back into the buffer at the
+ cursor.
+
+`M-y'
+ Rotate the kill-ring, and yank the new top. You can only do this
+ if the prior command is `C-y' or `M-y'.
+
+
+File: gdb.info, Node: Readline Arguments, Next: Searching, Prev: Readline Killing Commands, Up: Readline Interaction
+
+Readline Arguments
+------------------
+
+You can pass numeric arguments to Readline commands. Sometimes the
+argument acts as a repeat count, other times it is the 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 `M-- C-k'.
+
+ The general way to pass numeric arguments to a command is to type
+meta digits before the command. If the first `digit' typed is a minus
+sign (`-'), 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 `C-d' command an argument of 10, you could type `M-1 0 C-d', which
+will delete the next ten characters on the input line.
+
diff --git a/contrib/gdb/gdb/doc/gdb.info-3 b/contrib/gdb/gdb/doc/gdb.info-3
new file mode 100644
index 0000000..ada53b4
--- /dev/null
+++ b/contrib/gdb/gdb/doc/gdb.info-3
@@ -0,0 +1,6665 @@
+This is gdb.info, produced by makeinfo version 4.6 from ./gdb.texinfo.
+
+INFO-DIR-SECTION Software development
+START-INFO-DIR-ENTRY
+* Gdb: (gdb). The GNU debugger.
+END-INFO-DIR-ENTRY
+
+ This file documents the GNU debugger GDB.
+
+ This is the Ninth Edition, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 6.1.1.
+
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+1998,
+1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being "Free Software" and "Free Software Needs Free
+Documentation", with the Front-Cover Texts being "A GNU Manual," and
+with the Back-Cover Texts as in (a) below.
+
+ (a) The Free Software Foundation's Back-Cover Text is: "You have
+freedom to copy and modify this GNU Manual, like GNU software. Copies
+published by the Free Software Foundation raise funds for GNU
+development."
+
+
+File: gdb.info, Node: Searching, Prev: Readline Arguments, Up: Readline Interaction
+
+Searching for Commands in the History
+-------------------------------------
+
+Readline provides commands for searching through the command history
+for lines containing a specified string. There are two search modes:
+"incremental" and "non-incremental".
+
+ Incremental searches begin before the user has finished typing the
+search string. As each character of the search string is typed,
+Readline displays the next entry from the history matching the string
+typed so far. An incremental search requires only as many characters
+as needed to find the desired history entry. To search backward in the
+history for a particular string, type `C-r'. Typing `C-s' searches
+forward through the history. The characters present in the value of
+the `isearch-terminators' variable are used to terminate an incremental
+search. If that variable has not been assigned a value, the <ESC> and
+`C-J' characters will terminate an incremental search. `C-g' will
+abort an incremental search and restore the original line. When the
+search is terminated, the history entry containing the search string
+becomes the current line.
+
+ To find other matching entries in the history list, type `C-r' or
+`C-s' as appropriate. This will search backward or forward in the
+history for the next entry matching the search string typed so far.
+Any other key sequence bound to a Readline command will terminate the
+search and execute that command. For instance, a <RET> will terminate
+the search and accept the line, thereby executing the command from the
+history list. A movement command will terminate the search, make the
+last line found the current line, and begin editing.
+
+ Readline remembers the last incremental search string. If two
+`C-r's are typed without any intervening characters defining a new
+search string, any remembered search string is used.
+
+ Non-incremental searches read the entire search string before
+starting to search for matching history lines. The search string may be
+typed by the user or be part of the contents of the current line.
+
+
+File: gdb.info, Node: Readline Init File, Next: Bindable Readline Commands, Prev: Readline Interaction, Up: Command Line Editing
+
+Readline Init File
+==================
+
+Although the Readline library comes with a set of Emacs-like
+keybindings installed by default, it is possible to use a different set
+of keybindings. Any user can customize programs that use Readline by
+putting commands in an "inputrc" file, conventionally in his home
+directory. The name of this file is taken from the value of the
+environment variable `INPUTRC'. If that variable is unset, the default
+is `~/.inputrc'.
+
+ When a program which uses the Readline library starts up, the init
+file is read, and the key bindings are set.
+
+ In addition, the `C-x C-r' command re-reads this init file, thus
+incorporating any changes that you might have made to it.
+
+* Menu:
+
+* Readline Init File Syntax:: Syntax for the commands in the inputrc file.
+
+* Conditional Init Constructs:: Conditional key bindings in the inputrc file.
+
+* Sample Init File:: An example inputrc file.
+
+
+File: gdb.info, Node: Readline Init File Syntax, Next: Conditional Init Constructs, Up: Readline Init File
+
+Readline Init File Syntax
+-------------------------
+
+There are only a few basic constructs allowed in the Readline init
+file. Blank lines are ignored. Lines beginning with a `#' are
+comments. Lines beginning with a `$' indicate conditional constructs
+(*note Conditional Init Constructs::). Other lines denote variable
+settings and key bindings.
+
+Variable Settings
+ You can modify the run-time behavior of Readline by altering the
+ values of variables in Readline using the `set' command within the
+ init file. The syntax is simple:
+
+ set VARIABLE VALUE
+
+ Here, for example, is how to change from the default Emacs-like
+ key binding to use `vi' line editing commands:
+
+ set editing-mode vi
+
+ Variable names and values, where appropriate, are recognized
+ without regard to case.
+
+ A great deal of run-time behavior is changeable with the following
+ variables.
+
+ `bell-style'
+ Controls what happens when Readline wants to ring the
+ terminal bell. If set to `none', Readline never rings the
+ bell. If set to `visible', Readline uses a visible bell if
+ one is available. If set to `audible' (the default),
+ Readline attempts to ring the terminal's bell.
+
+ `comment-begin'
+ The string to insert at the beginning of the line when the
+ `insert-comment' command is executed. The default value is
+ `"#"'.
+
+ `completion-ignore-case'
+ If set to `on', Readline performs filename matching and
+ completion in a case-insensitive fashion. The default value
+ is `off'.
+
+ `completion-query-items'
+ The number of possible completions that determines when the
+ user is asked whether he wants to see the list of
+ possibilities. If the number of possible completions is
+ greater than this value, Readline will ask the user whether
+ or not he wishes to view them; otherwise, they are simply
+ listed. This variable must be set to an integer value
+ greater than or equal to 0. The default limit is `100'.
+
+ `convert-meta'
+ If set to `on', Readline will convert characters with the
+ eighth bit set to an ASCII key sequence by stripping the
+ eighth bit and prefixing an <ESC> character, converting them
+ to a meta-prefixed key sequence. The default value is `on'.
+
+ `disable-completion'
+ If set to `On', Readline will inhibit word completion.
+ Completion characters will be inserted into the line as if
+ they had been mapped to `self-insert'. The default is `off'.
+
+ `editing-mode'
+ The `editing-mode' variable controls which default set of key
+ bindings is used. By default, Readline starts up in Emacs
+ editing mode, where the keystrokes are most similar to Emacs.
+ This variable can be set to either `emacs' or `vi'.
+
+ `enable-keypad'
+ When set to `on', Readline will try to enable the application
+ keypad when it is called. Some systems need this to enable
+ the arrow keys. The default is `off'.
+
+ `expand-tilde'
+ If set to `on', tilde expansion is performed when Readline
+ attempts word completion. The default is `off'.
+
+ If set to `on', the history code attempts to place point at
+ the same location on each history line retrived with
+ `previous-history' or `next-history'.
+
+ `horizontal-scroll-mode'
+ This variable can be set to either `on' or `off'. Setting it
+ to `on' means that the text of the lines being edited will
+ scroll horizontally on a single screen line when they are
+ longer than the width of the screen, instead of wrapping onto
+ a new screen line. By default, this variable is set to `off'.
+
+ `input-meta'
+ If set to `on', Readline will enable eight-bit input (it will
+ not clear the eighth bit in the characters it reads),
+ regardless of what the terminal claims it can support. The
+ default value is `off'. The name `meta-flag' is a synonym
+ for this variable.
+
+ `isearch-terminators'
+ The string of characters that should terminate an incremental
+ search without subsequently executing the character as a
+ command (*note Searching::). If this variable has not been
+ given a value, the characters <ESC> and `C-J' will terminate
+ an incremental search.
+
+ `keymap'
+ Sets Readline's idea of the current keymap for key binding
+ commands. Acceptable `keymap' names are `emacs',
+ `emacs-standard', `emacs-meta', `emacs-ctlx', `vi', `vi-move',
+ `vi-command', and `vi-insert'. `vi' is equivalent to
+ `vi-command'; `emacs' is equivalent to `emacs-standard'. The
+ default value is `emacs'. The value of the `editing-mode'
+ variable also affects the default keymap.
+
+ `mark-directories'
+ If set to `on', completed directory names have a slash
+ appended. The default is `on'.
+
+ `mark-modified-lines'
+ This variable, when set to `on', causes Readline to display an
+ asterisk (`*') at the start of history lines which have been
+ modified. This variable is `off' by default.
+
+ `mark-symlinked-directories'
+ If set to `on', completed names which are symbolic links to
+ directories have a slash appended (subject to the value of
+ `mark-directories'). The default is `off'.
+
+ `match-hidden-files'
+ This variable, when set to `on', causes Readline to match
+ files whose names begin with a `.' (hidden files) when
+ performing filename completion, unless the leading `.' is
+ supplied by the user in the filename to be completed. This
+ variable is `on' by default.
+
+ `output-meta'
+ If set to `on', Readline will display characters with the
+ eighth bit set directly rather than as a meta-prefixed escape
+ sequence. The default is `off'.
+
+ `page-completions'
+ If set to `on', Readline uses an internal `more'-like pager
+ to display a screenful of possible completions at a time.
+ This variable is `on' by default.
+
+ `print-completions-horizontally'
+ If set to `on', Readline will display completions with matches
+ sorted horizontally in alphabetical order, rather than down
+ the screen. The default is `off'.
+
+ `show-all-if-ambiguous'
+ This alters the default behavior of the completion functions.
+ If set to `on', words which have more than one possible
+ completion cause the matches to be listed immediately instead
+ of ringing the bell. The default value is `off'.
+
+ `visible-stats'
+ If set to `on', a character denoting a file's type is
+ appended to the filename when listing possible completions.
+ The default is `off'.
+
+
+Key Bindings
+ The syntax for controlling key bindings in the init file is
+ simple. First you need to find the name of the command that you
+ want to change. The following sections contain tables of the
+ command name, the default keybinding, if any, and a short
+ description of what the command does.
+
+ Once you know the name of the command, simply place on a line in
+ the init file the name of the key you wish to bind the command to,
+ a colon, and then the name of the command. The name of the key
+ can be expressed in different ways, depending on what you find most
+ comfortable.
+
+ In addition to command names, readline allows keys to be bound to
+ a string that is inserted when the key is pressed (a MACRO).
+
+ KEYNAME: FUNCTION-NAME or MACRO
+ KEYNAME is the name of a key spelled out in English. For
+ example:
+ Control-u: universal-argument
+ Meta-Rubout: backward-kill-word
+ Control-o: "> output"
+
+ In the above example, `C-u' is bound to the function
+ `universal-argument', `M-DEL' is bound to the function
+ `backward-kill-word', and `C-o' is bound to run the macro
+ expressed on the right hand side (that is, to insert the text
+ `> output' into the line).
+
+ A number of symbolic character names are recognized while
+ processing this key binding syntax: DEL, ESC, ESCAPE, LFD,
+ NEWLINE, RET, RETURN, RUBOUT, SPACE, SPC, and TAB.
+
+ "KEYSEQ": FUNCTION-NAME or MACRO
+ KEYSEQ differs from KEYNAME above in that strings denoting an
+ entire key sequence can be specified, by placing the key
+ sequence in double quotes. Some GNU Emacs style key escapes
+ can be used, as in the following example, but the special
+ character names are not recognized.
+
+ "\C-u": universal-argument
+ "\C-x\C-r": re-read-init-file
+ "\e[11~": "Function Key 1"
+
+ In the above example, `C-u' is again bound to the function
+ `universal-argument' (just as it was in the first example),
+ `C-x C-r' is bound to the function `re-read-init-file', and
+ `<ESC> <[> <1> <1> <~>' is bound to insert the text `Function
+ Key 1'.
+
+
+ The following GNU Emacs style escape sequences are available when
+ specifying key sequences:
+
+ `\C-'
+ control prefix
+
+ `\M-'
+ meta prefix
+
+ `\e'
+ an escape character
+
+ `\\'
+ backslash
+
+ `\"'
+ <">, a double quotation mark
+
+ `\''
+ <'>, a single quote or apostrophe
+
+ In addition to the GNU Emacs style escape sequences, a second set
+ of backslash escapes is available:
+
+ `\a'
+ alert (bell)
+
+ `\b'
+ backspace
+
+ `\d'
+ delete
+
+ `\f'
+ form feed
+
+ `\n'
+ newline
+
+ `\r'
+ carriage return
+
+ `\t'
+ horizontal tab
+
+ `\v'
+ vertical tab
+
+ `\NNN'
+ the eight-bit character whose value is the octal value NNN
+ (one to three digits)
+
+ `\xHH'
+ the eight-bit character whose value is the hexadecimal value
+ HH (one or two hex digits)
+
+ When entering the text of a macro, single or double quotes must be
+ used to indicate a macro definition. Unquoted text is assumed to
+ be a function name. In the macro body, the backslash escapes
+ described above are expanded. Backslash will quote any other
+ character in the macro text, including `"' and `''. For example,
+ the following binding will make `C-x \' insert a single `\' into
+ the line:
+ "\C-x\\": "\\"
+
+
+
+File: gdb.info, Node: Conditional Init Constructs, Next: Sample Init File, Prev: Readline Init File Syntax, Up: Readline Init File
+
+Conditional Init Constructs
+---------------------------
+
+Readline implements a facility similar in spirit to the conditional
+compilation features of the C preprocessor which allows key bindings
+and variable settings to be performed as the result of tests. There
+are four parser directives used.
+
+`$if'
+ The `$if' construct allows bindings to be made based on the
+ editing mode, the terminal being used, or the application using
+ Readline. The text of the test extends to the end of the line; no
+ characters are required to isolate it.
+
+ `mode'
+ The `mode=' form of the `$if' directive is used to test
+ whether Readline is in `emacs' or `vi' mode. This may be
+ used in conjunction with the `set keymap' command, for
+ instance, to set bindings in the `emacs-standard' and
+ `emacs-ctlx' keymaps only if Readline is starting out in
+ `emacs' mode.
+
+ `term'
+ The `term=' form may be used to include terminal-specific key
+ bindings, perhaps to bind the key sequences output by the
+ terminal's function keys. The word on the right side of the
+ `=' is tested against both the full name of the terminal and
+ the portion of the terminal name before the first `-'. This
+ allows `sun' to match both `sun' and `sun-cmd', for instance.
+
+ `application'
+ The APPLICATION construct is used to include
+ application-specific settings. Each program using the
+ Readline library sets the APPLICATION NAME, and you can test
+ for a particular value. This could be used to bind key
+ sequences to functions useful for a specific program. For
+ instance, the following command adds a key sequence that
+ quotes the current or previous word in Bash:
+ $if Bash
+ # Quote the current or previous word
+ "\C-xq": "\eb\"\ef\""
+ $endif
+
+`$endif'
+ This command, as seen in the previous example, terminates an `$if'
+ command.
+
+`$else'
+ Commands in this branch of the `$if' directive are executed if the
+ test fails.
+
+`$include'
+ This directive takes a single filename as an argument and reads
+ commands and bindings from that file. For example, the following
+ directive reads from `/etc/inputrc':
+ $include /etc/inputrc
+
+
+File: gdb.info, Node: Sample Init File, Prev: Conditional Init Constructs, Up: Readline Init File
+
+Sample Init File
+----------------
+
+Here is an example of an INPUTRC file. This illustrates key binding,
+variable assignment, and conditional syntax.
+
+
+ # This file controls the behaviour of line input editing for
+ # programs that use the GNU Readline library. Existing
+ # programs include FTP, Bash, and GDB.
+ #
+ # You can re-read the inputrc file with C-x C-r.
+ # Lines beginning with '#' are comments.
+ #
+ # First, include any systemwide bindings and variable
+ # assignments from /etc/Inputrc
+ $include /etc/Inputrc
+
+ #
+ # Set various bindings for emacs mode.
+
+ set editing-mode emacs
+
+ $if mode=emacs
+
+ Meta-Control-h: backward-kill-word Text after the function name is ignored
+
+ #
+ # Arrow keys in keypad mode
+ #
+ #"\M-OD": backward-char
+ #"\M-OC": forward-char
+ #"\M-OA": previous-history
+ #"\M-OB": next-history
+ #
+ # Arrow keys in ANSI mode
+ #
+ "\M-[D": backward-char
+ "\M-[C": forward-char
+ "\M-[A": previous-history
+ "\M-[B": next-history
+ #
+ # Arrow keys in 8 bit keypad mode
+ #
+ #"\M-\C-OD": backward-char
+ #"\M-\C-OC": forward-char
+ #"\M-\C-OA": previous-history
+ #"\M-\C-OB": next-history
+ #
+ # Arrow keys in 8 bit ANSI mode
+ #
+ #"\M-\C-[D": backward-char
+ #"\M-\C-[C": forward-char
+ #"\M-\C-[A": previous-history
+ #"\M-\C-[B": next-history
+
+ C-q: quoted-insert
+
+ $endif
+
+ # An old-style binding. This happens to be the default.
+ TAB: complete
+
+ # Macros that are convenient for shell interaction
+ $if Bash
+ # edit the path
+ "\C-xp": "PATH=${PATH}\e\C-e\C-a\ef\C-f"
+ # prepare to type a quoted word --
+ # insert open and close double quotes
+ # and move to just after the open quote
+ "\C-x\"": "\"\"\C-b"
+ # insert a backslash (testing backslash escapes
+ # in sequences and macros)
+ "\C-x\\": "\\"
+ # Quote the current or previous word
+ "\C-xq": "\eb\"\ef\""
+ # Add a binding to refresh the line, which is unbound
+ "\C-xr": redraw-current-line
+ # Edit variable on current line.
+ "\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y="
+ $endif
+
+ # use a visible bell if one is available
+ set bell-style visible
+
+ # don't strip characters to 7 bits when reading
+ set input-meta on
+
+ # allow iso-latin1 characters to be inserted rather
+ # than converted to prefix-meta sequences
+ set convert-meta off
+
+ # display characters with the eighth bit set directly
+ # rather than as meta-prefixed characters
+ set output-meta on
+
+ # if there are more than 150 possible completions for
+ # a word, ask the user if he wants to see all of them
+ set completion-query-items 150
+
+ # For FTP
+ $if Ftp
+ "\C-xg": "get \M-?"
+ "\C-xt": "put \M-?"
+ "\M-.": yank-last-arg
+ $endif
+
+
+File: gdb.info, Node: Bindable Readline Commands, Next: Readline vi Mode, Prev: Readline Init File, Up: Command Line Editing
+
+Bindable Readline Commands
+==========================
+
+* 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.
+* Keyboard Macros:: Saving and re-executing typed characters
+* Miscellaneous Commands:: Other miscellaneous commands.
+
+ This section describes Readline commands that may be bound to key
+sequences. Command names without an accompanying key sequence are
+unbound by default.
+
+ In the following descriptions, "point" refers to the current cursor
+position, and "mark" refers to a cursor position saved by the
+`set-mark' command. The text between the point and mark is referred to
+as the "region".
+
+
+File: gdb.info, Node: Commands For Moving, Next: Commands For History, Up: Bindable Readline Commands
+
+Commands For Moving
+-------------------
+
+`beginning-of-line (C-a)'
+ Move to the start of the current line.
+
+`end-of-line (C-e)'
+ Move to the end of the line.
+
+`forward-char (C-f)'
+ Move forward a character.
+
+`backward-char (C-b)'
+ Move back a character.
+
+`forward-word (M-f)'
+ Move forward to the end of the next word. Words are composed of
+ letters and digits.
+
+`backward-word (M-b)'
+ Move back to the start of the current or previous word. Words are
+ composed of letters and digits.
+
+`clear-screen (C-l)'
+ Clear the screen and redraw the current line, leaving the current
+ line at the top of the screen.
+
+`redraw-current-line ()'
+ Refresh the current line. By default, this is unbound.
+
+
+
+File: gdb.info, Node: Commands For History, Next: Commands For Text, Prev: Commands For Moving, Up: Bindable Readline Commands
+
+Commands For Manipulating The History
+-------------------------------------
+
+`accept-line (Newline or Return)'
+ Accept the line regardless of where the cursor is. If this line is
+ non-empty, it may be added to the history list for future recall
+ with `add_history()'. If this line is a modified history line,
+ the history line is restored to its original state.
+
+`previous-history (C-p)'
+ Move `back' through the history list, fetching the previous
+ command.
+
+`next-history (C-n)'
+ Move `forward' through the history list, fetching the next command.
+
+`beginning-of-history (M-<)'
+ Move to the first line in the history.
+
+`end-of-history (M->)'
+ Move to the end of the input history, i.e., the line currently
+ being entered.
+
+`reverse-search-history (C-r)'
+ Search backward starting at the current line and moving `up'
+ through the history as necessary. This is an incremental search.
+
+`forward-search-history (C-s)'
+ Search forward starting at the current line and moving `down'
+ through the the history as necessary. This is an incremental
+ search.
+
+`non-incremental-reverse-search-history (M-p)'
+ Search backward starting at the current line and moving `up'
+ through the history as necessary using a non-incremental search
+ for a string supplied by the user.
+
+`non-incremental-forward-search-history (M-n)'
+ Search forward starting at the current line and moving `down'
+ through the the history as necessary using a non-incremental search
+ for a string supplied by the user.
+
+`history-search-forward ()'
+ Search forward through the history for the string of characters
+ between the start of the current line and the point. This is a
+ non-incremental search. By default, this command is unbound.
+
+`history-search-backward ()'
+ Search backward through the history for the string of characters
+ between the start of the current line and the point. This is a
+ non-incremental search. By default, this command is unbound.
+
+`yank-nth-arg (M-C-y)'
+ Insert the first argument to the previous command (usually the
+ second word on the previous line) at point. With an argument N,
+ insert the Nth word from the previous command (the words in the
+ previous command begin with word 0). A negative argument inserts
+ the Nth word from the end of the previous command.
+
+`yank-last-arg (M-. or M-_)'
+ Insert last argument to the previous command (the last word of the
+ previous history entry). With an argument, behave exactly like
+ `yank-nth-arg'. Successive calls to `yank-last-arg' move back
+ through the history list, inserting the last argument of each line
+ in turn.
+
+
+
+File: gdb.info, Node: Commands For Text, Next: Commands For Killing, Prev: Commands For History, Up: Bindable Readline Commands
+
+Commands For Changing Text
+--------------------------
+
+`delete-char (C-d)'
+ Delete the character at point. If point is at the beginning of
+ the line, there are no characters in the line, and the last
+ character typed was not bound to `delete-char', then return EOF.
+
+`backward-delete-char (Rubout)'
+ Delete the character behind the cursor. A numeric argument means
+ to kill the characters instead of deleting them.
+
+`forward-backward-delete-char ()'
+ Delete the character under the cursor, unless the cursor is at the
+ end of the line, in which case the character behind the cursor is
+ deleted. By default, this is not bound to a key.
+
+`quoted-insert (C-q or C-v)'
+ Add the next character typed to the line verbatim. This is how to
+ insert key sequences like `C-q', for example.
+
+`tab-insert (M-<TAB>)'
+ Insert a tab character.
+
+`self-insert (a, b, A, 1, !, ...)'
+ Insert yourself.
+
+`transpose-chars (C-t)'
+ Drag the character before the cursor forward over the character at
+ the cursor, moving the cursor forward as well. If the insertion
+ point is at the end of the line, then this transposes the last two
+ characters of the line. Negative arguments have no effect.
+
+`transpose-words (M-t)'
+ Drag the word before point past the word after point, moving point
+ past that word as well. If the insertion point is at the end of
+ the line, this transposes the last two words on the line.
+
+`upcase-word (M-u)'
+ Uppercase the current (or following) word. With a negative
+ argument, uppercase the previous word, but do not move the cursor.
+
+`downcase-word (M-l)'
+ Lowercase the current (or following) word. With a negative
+ argument, lowercase the previous word, but do not move the cursor.
+
+`capitalize-word (M-c)'
+ Capitalize the current (or following) word. With a negative
+ argument, capitalize the previous word, but do not move the cursor.
+
+`overwrite-mode ()'
+ Toggle overwrite mode. With an explicit positive numeric argument,
+ switches to overwrite mode. With an explicit non-positive numeric
+ argument, switches to insert mode. This command affects only
+ `emacs' mode; `vi' mode does overwrite differently. Each call to
+ `readline()' starts in insert mode.
+
+ In overwrite mode, characters bound to `self-insert' replace the
+ text at point rather than pushing the text to the right.
+ Characters bound to `backward-delete-char' replace the character
+ before point with a space.
+
+ By default, this command is unbound.
+
+
+
+File: gdb.info, Node: Commands For Killing, Next: Numeric Arguments, Prev: Commands For Text, Up: Bindable Readline Commands
+
+Killing And Yanking
+-------------------
+
+`kill-line (C-k)'
+ Kill the text from point to the end of the line.
+
+`backward-kill-line (C-x Rubout)'
+ Kill backward to the beginning of the line.
+
+`unix-line-discard (C-u)'
+ Kill backward from the cursor to the beginning of the current line.
+
+`kill-whole-line ()'
+ Kill all characters on the current line, no matter where point is.
+ By default, this is unbound.
+
+`kill-word (M-d)'
+ Kill from point to the end of the current word, or if between
+ words, to the end of the next word. Word boundaries are the same
+ as `forward-word'.
+
+`backward-kill-word (M-<DEL>)'
+ Kill the word behind point. Word boundaries are the same as
+ `backward-word'.
+
+`unix-word-rubout (C-w)'
+ Kill the word behind point, using white space as a word boundary.
+ The killed text is saved on the kill-ring.
+
+`delete-horizontal-space ()'
+ Delete all spaces and tabs around point. By default, this is
+ unbound.
+
+`kill-region ()'
+ Kill the text in the current region. By default, this command is
+ unbound.
+
+`copy-region-as-kill ()'
+ Copy the text in the region to the kill buffer, so it can be yanked
+ right away. By default, this command is unbound.
+
+`copy-backward-word ()'
+ Copy the word before point to the kill buffer. The word
+ boundaries are the same as `backward-word'. By default, this
+ command is unbound.
+
+`copy-forward-word ()'
+ Copy the word following point to the kill buffer. The word
+ boundaries are the same as `forward-word'. By default, this
+ command is unbound.
+
+`yank (C-y)'
+ Yank the top of the kill ring into the buffer at point.
+
+`yank-pop (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'.
+
+
+File: gdb.info, Node: Numeric Arguments, Next: Commands For Completion, Prev: Commands For Killing, Up: Bindable Readline Commands
+
+Specifying Numeric Arguments
+----------------------------
+
+`digit-argument (M-0, M-1, ... M--)'
+ Add this digit to the argument already accumulating, or start a new
+ argument. `M--' starts a negative argument.
+
+`universal-argument ()'
+ This is another way to specify an argument. If this command is
+ followed by one or more digits, optionally with a leading minus
+ sign, those digits define the argument. If the command is
+ followed by digits, executing `universal-argument' again ends the
+ numeric argument, but is otherwise ignored. As a special case, if
+ this command is immediately followed by a character that is
+ neither a digit or minus sign, the argument count for the next
+ command is multiplied by four. The argument count is initially
+ one, so executing this function the first time makes the argument
+ count four, a second time makes the argument count sixteen, and so
+ on. By default, this is not bound to a key.
+
+
+File: gdb.info, Node: Commands For Completion, Next: Keyboard Macros, Prev: Numeric Arguments, Up: Bindable Readline Commands
+
+Letting Readline Type For You
+-----------------------------
+
+`complete (<TAB>)'
+ Attempt to perform completion on the text before point. The
+ actual completion performed is application-specific. The default
+ is filename completion.
+
+`possible-completions (M-?)'
+ List the possible completions of the text before point.
+
+`insert-completions (M-*)'
+ Insert all completions of the text before point that would have
+ been generated by `possible-completions'.
+
+`menu-complete ()'
+ Similar to `complete', but replaces the word to be completed with
+ a single match from the list of possible completions. Repeated
+ execution of `menu-complete' steps through the list of possible
+ completions, inserting each match in turn. At the end of the list
+ of completions, the bell is rung (subject to the setting of
+ `bell-style') and the original text is restored. An argument of N
+ moves N positions forward in the list of matches; a negative
+ argument may be used to move backward through the list. This
+ command is intended to be bound to <TAB>, but is unbound by
+ default.
+
+`delete-char-or-list ()'
+ Deletes the character under the cursor if not at the beginning or
+ end of the line (like `delete-char'). If at the end of the line,
+ behaves identically to `possible-completions'. This command is
+ unbound by default.
+
+
+
+File: gdb.info, Node: Keyboard Macros, Next: Miscellaneous Commands, Prev: Commands For Completion, Up: Bindable Readline Commands
+
+Keyboard Macros
+---------------
+
+`start-kbd-macro (C-x ()'
+ Begin saving the characters typed into the current keyboard macro.
+
+`end-kbd-macro (C-x ))'
+ Stop saving the characters typed into the current keyboard macro
+ and save the definition.
+
+`call-last-kbd-macro (C-x e)'
+ Re-execute the last keyboard macro defined, by making the
+ characters in the macro appear as if typed at the keyboard.
+
+
+
+File: gdb.info, Node: Miscellaneous Commands, Prev: Keyboard Macros, Up: Bindable Readline Commands
+
+Some Miscellaneous Commands
+---------------------------
+
+`re-read-init-file (C-x C-r)'
+ Read in the contents of the INPUTRC file, and incorporate any
+ bindings or variable assignments found there.
+
+`abort (C-g)'
+ Abort the current editing command and ring the terminal's bell
+ (subject to the setting of `bell-style').
+
+`do-uppercase-version (M-a, M-b, M-X, ...)'
+ If the metafied character X is lowercase, run the command that is
+ bound to the corresponding uppercase character.
+
+`prefix-meta (<ESC>)'
+ Metafy the next character typed. This is for keyboards without a
+ meta key. Typing `<ESC> f' is equivalent to typing `M-f'.
+
+`undo (C-_ or C-x C-u)'
+ Incremental undo, separately remembered for each line.
+
+`revert-line (M-r)'
+ Undo all changes made to this line. This is like executing the
+ `undo' command enough times to get back to the beginning.
+
+`tilde-expand (M-~)'
+ Perform tilde expansion on the current word.
+
+`set-mark (C-@)'
+ Set the mark to the point. If a numeric argument is supplied, the
+ mark is set to that position.
+
+`exchange-point-and-mark (C-x C-x)'
+ Swap the point with the mark. The current cursor position is set
+ to the saved position, and the old cursor position is saved as the
+ mark.
+
+`character-search (C-])'
+ A character is read and point is moved to the next occurrence of
+ that character. A negative count searches for previous
+ occurrences.
+
+`character-search-backward (M-C-])'
+ A character is read and point is moved to the previous occurrence
+ of that character. A negative count searches for subsequent
+ occurrences.
+
+`insert-comment (M-#)'
+ Without a numeric argument, the value of the `comment-begin'
+ variable is inserted at the beginning of the current line. If a
+ numeric argument is supplied, this command acts as a toggle: if
+ the characters at the beginning of the line do not match the value
+ of `comment-begin', the value is inserted, otherwise the
+ characters in `comment-begin' are deleted from the beginning of
+ the line. In either case, the line is accepted as if a newline
+ had been typed.
+
+`dump-functions ()'
+ Print all of the functions and their key bindings to the Readline
+ output stream. If a numeric argument is supplied, the output is
+ formatted in such a way that it can be made part of an INPUTRC
+ file. This command is unbound by default.
+
+`dump-variables ()'
+ Print all of the settable variables and their values to the
+ Readline output stream. If a numeric argument is supplied, the
+ output is formatted in such a way that it can be made part of an
+ INPUTRC file. This command is unbound by default.
+
+`dump-macros ()'
+ Print all of the Readline key sequences bound to macros and the
+ strings they output. If a numeric argument is supplied, the
+ output is formatted in such a way that it can be made part of an
+ INPUTRC file. This command is unbound by default.
+
+`emacs-editing-mode (C-e)'
+ When in `vi' command mode, this causes a switch to `emacs' editing
+ mode.
+
+`vi-editing-mode (M-C-j)'
+ When in `emacs' editing mode, this causes a switch to `vi' editing
+ mode.
+
+
+
+File: gdb.info, Node: Readline vi Mode, Prev: Bindable Readline Commands, Up: Command Line Editing
+
+Readline vi Mode
+================
+
+While the Readline library does not have a full set of `vi' editing
+functions, it does contain enough to allow simple editing of the line.
+The Readline `vi' mode behaves as specified in the POSIX 1003.2
+standard.
+
+ In order to switch interactively between `emacs' and `vi' editing
+modes, use the command `M-C-j' (bound to emacs-editing-mode when in
+`vi' mode and to vi-editing-mode in `emacs' mode). The Readline
+default is `emacs' mode.
+
+ When you enter a line in `vi' mode, you are already placed in
+`insertion' mode, as if you had typed an `i'. Pressing <ESC> switches
+you into `command' mode, where you can edit the text of the line with
+the standard `vi' movement keys, move to previous history lines with
+`k' and subsequent lines with `j', and so forth.
+
+
+File: gdb.info, Node: Using History Interactively, Next: Installing GDB, Prev: Command Line Editing, Up: Top
+
+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.
+
+* Menu:
+
+* History Interaction:: What it feels like using History as a user.
+
+
+File: gdb.info, Node: History Interaction, Up: Using History Interactively
+
+History Expansion
+=================
+
+The History library provides a history expansion feature that is similar
+to the history expansion provided by `csh'. This section describes the
+syntax used to manipulate the history information.
+
+ History expansions introduce words from the history list into the
+input stream, making it easy to repeat commands, insert the arguments
+to a previous command into the current input line, or fix errors in
+previous commands quickly.
+
+ History expansion takes place in two parts. The first is to
+determine which line from the history list 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 history is
+called the "event", and the portions of that line that are acted upon
+are called "words". Various "modifiers" are available to manipulate
+the selected words. The line is broken into words in the same fashion
+that Bash does, so that several words surrounded by quotes are
+considered one word. History expansions are introduced by the
+appearance of the history expansion character, which is `!' by default.
+
+* Menu:
+
+* Event Designators:: How to specify which history line to use.
+* Word Designators:: Specifying which words are of interest.
+* Modifiers:: Modifying the results of substitution.
+
+
+File: gdb.info, Node: Event Designators, Next: Word Designators, Up: History Interaction
+
+Event Designators
+-----------------
+
+An event designator is a reference to a command line entry in the
+history list.
+
+`!'
+ Start a history substitution, except when followed by a space, tab,
+ the end of the line, `=' or `('.
+
+`!N'
+ Refer to command line N.
+
+`!-N'
+ Refer to the command N lines back.
+
+`!!'
+ Refer to the previous command. This is a synonym for `!-1'.
+
+`!STRING'
+ Refer to the most recent command starting with STRING.
+
+`!?STRING[?]'
+ Refer to the most recent command containing STRING. The trailing
+ `?' may be omitted if the STRING is followed immediately by a
+ newline.
+
+`^STRING1^STRING2^'
+ Quick Substitution. Repeat the last command, replacing STRING1
+ with STRING2. Equivalent to `!!:s/STRING1/STRING2/'.
+
+`!#'
+ The entire command line typed so far.
+
+
+
+File: gdb.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction
+
+Word Designators
+----------------
+
+Word designators are used to select desired words from the event. A
+`:' separates the event specification from the word designator. It may
+be omitted if the word designator begins with a `^', `$', `*', `-', or
+`%'. Words are numbered from the beginning of the line, with the first
+word being denoted by 0 (zero). Words are inserted into the current
+line separated by single spaces.
+
+ For example,
+
+`!!'
+ designates the preceding command. When you type this, the
+ preceding command is repeated in toto.
+
+`!!:$'
+ designates the last argument of the preceding command. This may be
+ shortened to `!$'.
+
+`!fi:2'
+ designates the second argument of the most recent command starting
+ with the letters `fi'.
+
+ Here are the word designators:
+
+`0 (zero)'
+ The `0'th word. For many applications, this is the command word.
+
+`N'
+ The Nth word.
+
+`^'
+ The first argument; that is, word 1.
+
+`$'
+ The last argument.
+
+`%'
+ The word matched by the most recent `?STRING?' search.
+
+`X-Y'
+ A range of words; `-Y' abbreviates `0-Y'.
+
+`*'
+ All of the words, except the `0'th. This is a synonym for `1-$'.
+ It is not an error to use `*' if there is just one word in the
+ event; the empty string is returned in that case.
+
+`X*'
+ Abbreviates `X-$'
+
+`X-'
+ Abbreviates `X-$' like `X*', but omits the last word.
+
+
+ If a word designator is supplied without an event specification, the
+previous command is used as the event.
+
+
+File: gdb.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction
+
+Modifiers
+---------
+
+After the optional word designator, you can add a sequence of one or
+more of the following modifiers, each preceded by a `:'.
+
+`h'
+ Remove a trailing pathname component, leaving only the head.
+
+`t'
+ Remove all leading pathname components, leaving the tail.
+
+`r'
+ Remove a trailing suffix of the form `.SUFFIX', leaving the
+ basename.
+
+`e'
+ Remove all but the trailing suffix.
+
+`p'
+ Print the new command but do not execute it.
+
+`s/OLD/NEW/'
+ Substitute NEW for the first occurrence of OLD in the event line.
+ Any delimiter may be used in place of `/'. The delimiter may be
+ quoted in OLD and NEW with a single backslash. If `&' appears in
+ NEW, it is replaced by OLD. A single backslash will quote the
+ `&'. The final delimiter is optional if it is the last character
+ on the input line.
+
+`&'
+ Repeat the previous substitution.
+
+`g'
+ Cause changes to be applied over the entire event line. Used in
+ conjunction with `s', as in `gs/OLD/NEW/', or with `&'.
+
+
+
+File: gdb.info, Node: Formatting Documentation, Next: Command Line Editing, Prev: GDB Bugs, Up: Top
+
+Formatting 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(1). 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-6.1.1/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-6.1.1', in the case of version 6.1.1), 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 either read or 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-6.1.1/gdb') and type:
+
+ make gdb.dvi
+
+ Then give `gdb.dvi' to your DVI printing program.
+
+ ---------- Footnotes ----------
+
+ (1) In `gdb-6.1.1/gdb/refcard.ps' of the version 6.1.1 release.
+
+
+File: gdb.info, Node: Installing GDB, Next: Maintenance Commands, Prev: Using History Interactively, Up: Top
+
+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 6.1.1 distribution is in the
+`gdb-6.1.1' directory. That directory contains:
+
+`gdb-6.1.1/configure (and supporting files)'
+ script for configuring GDB and all its supporting libraries
+
+`gdb-6.1.1/gdb'
+ the source specific to GDB itself
+
+`gdb-6.1.1/bfd'
+ source for the Binary File Descriptor library
+
+`gdb-6.1.1/include'
+ GNU include files
+
+`gdb-6.1.1/libiberty'
+ source for the `-liberty' free software library
+
+`gdb-6.1.1/opcodes'
+ source for the library of opcode tables and disassemblers
+
+`gdb-6.1.1/readline'
+ source for the GNU command-line interface
+
+`gdb-6.1.1/glob'
+ source for the GNU filename pattern-matching subroutine
+
+`gdb-6.1.1/mmalloc'
+ source for the GNU memory-mapped malloc package
+
+ 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-6.1.1' 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-6.1.1
+ ./configure HOST
+ make
+
+where HOST is an identifier such as `sun4' or `decstation', that
+identifies the platform where GDB will run. (You can often leave off
+HOST; `configure' tries to guess the correct value by examining your
+system.)
+
+ Running `configure HOST' and then running `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-6.1.1'
+source directory for version 6.1.1, `configure' creates configuration
+files for every directory level underneath (unless you tell it not to,
+with the `--norecursion' option).
+
+ You should run the `configure' script from the top directory in the
+source tree, the `gdb-VERSION-NUMBER' directory. If you run
+`configure' from one of the subdirectories, you will configure only
+that subdirectory. That is usually not what you want. In particular,
+if you run the first `configure' from the `gdb' subdirectory of the
+`gdb-VERSION-NUMBER' directory, you will omit the configuration of
+`bfd', `readline', and other sibling directories of the `gdb'
+subdirectory. This leads to build errors about missing include files
+such as `bfd/bfd.h'.
+
+ 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.
+
+* Menu:
+
+* Separate Objdir:: Compiling GDB in another directory
+* Config Names:: Specifying names for hosts and targets
+* Configure Options:: Summary of options for configure
+
+
+File: gdb.info, Node: Separate Objdir, Next: Config Names, Up: Installing GDB
+
+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 (GNU `make' does), 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 is
+assumed.)
+
+ For example, with version 6.1.1, you can build GDB in a separate
+directory for a Sun 4 like this:
+
+ cd gdb-6.1.1
+ mkdir ../gdb-sun4
+ cd ../gdb-sun4
+ ../gdb-6.1.1/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'.
+
+ Make sure that your path to the `configure' script has just one
+instance of `gdb' in it. If your path to `configure' looks like
+`../gdb-6.1.1/gdb/configure', you are configuring only one subdirectory
+of GDB, not the whole package. This leads to build errors about
+missing include files such as `bfd/bfd.h'.
+
+ 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-6.1.1' (or in a separate configured directory configured with
+`--srcdir=DIRNAME/gdb-6.1.1'), 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.
+
+
+File: gdb.info, Node: Config Names, Next: Configure Options, Prev: Separate Objdir, Up: Installing GDB
+
+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 as
+the value for TARGET 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 i386-linux
+ i386-pc-linux-gnu
+ % sh config.sub alpha-linux
+ alpha-unknown-linux-gnu
+ % sh config.sub hp9k700
+ hppa1.1-hp-hpux
+ % sh config.sub sun4
+ sparc-sun-sunos4.1.1
+ % sh config.sub sun3
+ m68k-sun-sunos4.1.1
+ % sh config.sub i986v
+ Invalid configuration `i986v': machine `i986v' not recognized
+
+`config.sub' is also distributed in the GDB source directory
+(`gdb-6.1.1', for version 6.1.1).
+
+
+File: gdb.info, Node: Configure Options, Prev: Config Names, Up: Installing GDB
+
+`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]
+ [--exec-prefix=DIR]
+ [--srcdir=DIRNAME]
+ [--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'.
+
+`--exec-prefix=DIR'
+ Configure the source to install programs under directory `DIR'.
+
+`--srcdir=DIRNAME'
+ *Warning: using this option requires GNU `make', or another `make'
+ that 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 DIRNAME. `configure' creates
+ directories under the working directory in parallel to the source
+ directories below DIRNAME.
+
+`--norecursion'
+ Configure only the directory level where `configure' is executed;
+ do not propagate configuration to subdirectories.
+
+`--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.
+
+ There are many other options available as well, but they are
+generally needed for special purposes only.
+
+
+File: gdb.info, Node: Maintenance Commands, Next: Remote Protocol, Prev: Installing GDB, Up: Top
+
+Maintenance Commands
+********************
+
+In addition to commands intended for GDB users, GDB includes a number
+of commands intended for GDB developers. These commands are provided
+here for reference.
+
+`maint info breakpoints'
+ Using the same format as `info breakpoints', display both the
+ breakpoints you've set explicitly, and those GDB is using for
+ internal purposes. Internal breakpoints are shown with negative
+ breakpoint numbers. The type column identifies what kind of
+ breakpoint is shown:
+
+ `breakpoint'
+ Normal, explicitly set breakpoint.
+
+ `watchpoint'
+ Normal, explicitly set watchpoint.
+
+ `longjmp'
+ Internal breakpoint, used to handle correctly stepping through
+ `longjmp' calls.
+
+ `longjmp resume'
+ Internal breakpoint at the target of a `longjmp'.
+
+ `until'
+ Temporary internal breakpoint used by the GDB `until' command.
+
+ `finish'
+ Temporary internal breakpoint used by the GDB `finish'
+ command.
+
+ `shlib events'
+ Shared library events.
+
+
+`maint internal-error'
+`maint internal-warning'
+ Cause GDB to call the internal function `internal_error' or
+ `internal_warning' and hence behave as though an internal error or
+ internal warning has been detected. In addition to reporting the
+ internal problem, these functions give the user the opportunity to
+ either quit GDB or create a core file of the current GDB session.
+
+ (gdb) maint internal-error testing, 1, 2
+ .../maint.c:121: internal-error: testing, 1, 2
+ A problem internal to GDB has been detected. Further
+ debugging may prove unreliable.
+ Quit this debugging session? (y or n) n
+ Create a core file? (y or n) n
+ (gdb)
+
+ Takes an optional parameter that is used as the text of the error
+ or warning message.
+
+`maint print dummy-frames'
+ Prints the contents of GDB's internal dummy-frame stack.
+
+ (gdb) b add
+ ...
+ (gdb) print add(2,3)
+ Breakpoint 2, add (a=2, b=3) at ...
+ 58 return (a + b);
+ The program being debugged stopped while in a function called from GDB.
+ ...
+ (gdb) maint print dummy-frames
+ 0x1a57c80: pc=0x01014068 fp=0x0200bddc sp=0x0200bdd6
+ top=0x0200bdd4 id={stack=0x200bddc,code=0x101405c}
+ call_lo=0x01014000 call_hi=0x01014001
+ (gdb)
+
+ Takes an optional file parameter.
+
+`maint print registers'
+`maint print raw-registers'
+`maint print cooked-registers'
+`maint print register-groups'
+ Print GDB's internal register data structures.
+
+ The command `maint print raw-registers' includes the contents of
+ the raw register cache; the command `maint print cooked-registers'
+ includes the (cooked) value of all registers; and the command
+ `maint print register-groups' includes the groups that each
+ register is a member of. *Note Registers: (gdbint)Registers.
+
+ Takes an optional file parameter.
+
+`maint print reggroups'
+ Print GDB's internal register group data structures.
+
+ Takes an optional file parameter.
+
+ (gdb) maint print reggroups
+ Group Type
+ general user
+ float user
+ all user
+ vector user
+ system user
+ save internal
+ restore internal
+
+`maint set profile'
+`maint show profile'
+ Control profiling of GDB.
+
+ Profiling will be disabled until you use the `maint set profile'
+ command to enable it. When you enable profiling, the system will
+ begin collecting timing and execution count data; when you disable
+ profiling or exit GDB, the results will be written to a log file.
+ Remember that if you use profiling, GDB will overwrite the
+ profiling log file (often called `gmon.out'). If you have a
+ record of important profiling data in a `gmon.out' file, be sure
+ to move it to a safe location.
+
+ Configuring with `--enable-profiling' arranges for GDB to be
+ compiled with the `-pg' compiler option.
+
+
+
+File: gdb.info, Node: Remote Protocol, Next: Agent Expressions, Prev: Maintenance Commands, Up: Top
+
+GDB Remote Serial Protocol
+**************************
+
+* Menu:
+
+* Overview::
+* Packets::
+* Stop Reply Packets::
+* General Query Packets::
+* Register Packet Format::
+* Examples::
+* File-I/O remote protocol extension::
+
+
+File: gdb.info, Node: Overview, Next: Packets, Up: Remote Protocol
+
+Overview
+========
+
+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 GDB.
+
+ In the examples below, `->' and `<-' are used to indicate
+transmitted and received data respectfully.
+
+ All GDB commands and responses (other than acknowledgments) are sent
+as a PACKET. A PACKET is introduced with the character `$', the actual
+PACKET-DATA, and the terminating character `#' followed by a two-digit
+CHECKSUM:
+
+ `$'PACKET-DATA`#'CHECKSUM
+
+The two-digit CHECKSUM is computed as the modulo 256 sum of all
+characters between the leading `$' and the trailing `#' (an eight bit
+unsigned checksum).
+
+ Implementors should note that prior to GDB 5.0 the protocol
+specification also included an optional two-digit SEQUENCE-ID:
+
+ `$'SEQUENCE-ID`:'PACKET-DATA`#'CHECKSUM
+
+That SEQUENCE-ID was appended to the acknowledgment. GDB has never
+output SEQUENCE-IDs. Stubs that handle packets added since GDB 5.0
+must not accept SEQUENCE-ID.
+
+ When either the host or the target machine receives a packet, the
+first response expected is an acknowledgment: either `+' (to indicate
+the package was received correctly) or `-' (to request retransmission):
+
+ -> `$'PACKET-DATA`#'CHECKSUM
+ <- `+'
+
+The host (GDB) sends COMMANDs, and the target (the debugging stub
+incorporated in your program) sends a RESPONSE. In the case of step
+and continue COMMANDs, the response is only sent when the operation has
+completed (the target has again stopped).
+
+ PACKET-DATA consists of a sequence of characters with the exception
+of `#' and `$' (see `X' packet for additional exceptions).
+
+ Fields within the packet should be separated using `,' `;' or `:'.
+Except where otherwise noted all numbers are represented in HEX with
+leading zeros suppressed.
+
+ Implementors should note that prior to GDB 5.0, the character `:'
+could not appear as the third character in a packet (as it would
+potentially conflict with the SEQUENCE-ID).
+
+ Response DATA 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 repetitions of the character preceding the
+`*'. The encoding is `n+29', yielding a printable character where `n
+>=3' (which is where rle starts to win). The printable characters `$',
+`#', `+' and `-' or with a numeric value greater than 126 should not be
+used.
+
+ So:
+ "`0* '"
+
+means the same as "0000".
+
+ The error response returned for some packets includes a two character
+error number. That number is not well defined.
+
+ For any COMMAND not supported by the stub, an empty response
+(`$#00') should be returned. That way it is possible to extend the
+protocol. A newer GDB can tell if a packet is supported based on that
+response.
+
+ A stub is required to support the `g', `G', `m', `M', `c', and `s'
+COMMANDs. All other COMMANDs are optional.
+
+
+File: gdb.info, Node: Packets, Next: Stop Reply Packets, Prev: Overview, Up: Remote Protocol
+
+Packets
+=======
+
+The following table provides a complete list of all currently defined
+COMMANDs and their corresponding response DATA.
+
+`!' -- extended mode
+ Enable extended mode. In extended mode, the remote server is made
+ persistent. The `R' packet is used to restart the program being
+ debugged.
+
+ Reply:
+ `OK'
+ The remote target both supports and has enabled extended mode.
+
+`?' -- last signal
+ Indicate the reason the target halted. The reply is the same as
+ for step and continue.
+
+ Reply: *Note Stop Reply Packets::, for the reply specifications.
+
+`a' -- reserved
+ Reserved for future use.
+
+`A'ARGLEN`,'ARGNUM`,'ARG`,...' -- set program arguments *(reserved)*
+ Initialized `argv[]' array passed into program. ARGLEN specifies
+ the number of bytes in the hex encoded byte stream ARG. See
+ `gdbserver' for more details.
+
+ Reply:
+ `OK'
+
+ `ENN'
+
+`b'BAUD -- set baud *(deprecated)*
+ Change the serial line speed to BAUD.
+
+ JTC: _When does the transport layer state change? When it's
+ received, or after the ACK is transmitted. In either case, there
+ are problems if the command or the acknowledgment packet is
+ dropped._
+
+ Stan: _If people really wanted to add something like this, and get
+ it working for the first time, they ought to modify ser-unix.c to
+ send some kind of out-of-band message to a specially-setup stub
+ and have the switch happen "in between" packets, so that from
+ remote protocol's point of view, nothing actually happened._
+
+`B'ADDR,MODE -- set breakpoint *(deprecated)*
+ Set (MODE is `S') or clear (MODE is `C') a breakpoint at ADDR.
+
+ This packet has been replaced by the `Z' and `z' packets (*note
+ insert breakpoint or watchpoint packet::).
+
+`c'ADDR -- continue
+ ADDR is address to resume. If ADDR is omitted, resume at current
+ address.
+
+ Reply: *Note Stop Reply Packets::, for the reply specifications.
+
+`C'SIG`;'ADDR -- continue with signal
+ Continue with signal SIG (hex signal number). If `;'ADDR is
+ omitted, resume at same address.
+
+ Reply: *Note Stop Reply Packets::, for the reply specifications.
+
+`d' -- toggle debug *(deprecated)*
+ Toggle debug flag.
+
+`D' -- detach
+ Detach GDB from the remote system. Sent to the remote target
+ before GDB disconnects via the `detach' command.
+
+ Reply:
+ `_no response_'
+ GDB does not check for any response after sending this packet.
+
+`e' -- reserved
+ Reserved for future use.
+
+`E' -- reserved
+ Reserved for future use.
+
+`f' -- reserved
+ Reserved for future use.
+
+`F'RC`,'EE`,'CF`;'XX -- Reply to target's F packet.
+ This packet is send by GDB as reply to a `F' request packet sent
+ by the target. This is part of the File-I/O protocol extension.
+ *Note File-I/O remote protocol extension::, for the specification.
+
+`g' -- read registers
+ Read general registers.
+
+ Reply:
+ `XX...'
+ Each byte of register data is described by two hex digits.
+ The bytes with the register are transmitted in target byte
+ order. The size of each register and their position within
+ the `g' PACKET are determined by the GDB internal macros
+ DEPRECATED_REGISTER_RAW_SIZE and REGISTER_NAME macros. The
+ specification of several standard `g' packets is specified
+ below.
+
+ `ENN'
+ for an error.
+
+`G'XX... -- write regs
+ *Note read registers packet::, for a description of the XX...
+ data.
+
+ Reply:
+ `OK'
+ for success
+
+ `ENN'
+ for an error
+
+`h' -- reserved
+ Reserved for future use.
+
+`H'CT... -- set thread
+ Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
+ C depends on the operation to be performed: it should be `c' for
+ step and continue operations, `g' for other operations. The
+ thread designator T... may be -1, meaning all the threads, a
+ thread number, or zero which means pick any thread.
+
+ Reply:
+ `OK'
+ for success
+
+ `ENN'
+ for an error
+
+`i'ADDR`,'NNN -- cycle step *(draft)*
+ Step the remote target by a single clock cycle. If `,'NNN is
+ present, cycle step NNN cycles. If ADDR is present, cycle step
+ starting at that address.
+
+`I' -- signal then cycle step *(reserved)*
+ *Note step with signal packet::. *Note cycle step packet::.
+
+`j' -- reserved
+ Reserved for future use.
+
+`J' -- reserved
+ Reserved for future use.
+
+`k' -- kill request
+ FIXME: _There is no description of how to operate when a specific
+ thread context has been selected (i.e. does 'k' kill only that
+ thread?)_.
+
+`K' -- reserved
+ Reserved for future use.
+
+`l' -- reserved
+ Reserved for future use.
+
+`L' -- reserved
+ Reserved for future use.
+
+`m'ADDR`,'LENGTH -- read memory
+ Read LENGTH bytes of memory starting at address ADDR. Neither GDB
+ nor the stub assume that sized memory transfers are assumed using
+ word aligned accesses. FIXME: _A word aligned memory transfer
+ mechanism is needed._
+
+ Reply:
+ `XX...'
+ XX... is mem contents. Can be fewer bytes than requested if
+ able to read only part of the data. Neither GDB nor the stub
+ assume that sized memory transfers are assumed using word
+ aligned accesses. FIXME: _A word aligned memory transfer
+ mechanism is needed._
+
+ `ENN'
+ NN is errno
+
+`M'ADDR,LENGTH`:'XX... -- write mem
+ Write LENGTH bytes of memory starting at address ADDR. XX... is
+ the data.
+
+ Reply:
+ `OK'
+ for success
+
+ `ENN'
+ for an error (this includes the case where only part of the
+ data was written).
+
+`n' -- reserved
+ Reserved for future use.
+
+`N' -- reserved
+ Reserved for future use.
+
+`o' -- reserved
+ Reserved for future use.
+
+`O' -- reserved
+ Reserved for future use.
+
+`p'N... -- read reg *(reserved)*
+ *Note write register packet::.
+
+ Reply:
+ `R....'
+ The hex encoded value of the register in target byte order.
+
+`P'N...`='R... -- write register
+ 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
+
+`q'QUERY -- general query
+ Request info about QUERY. In general GDB queries have a leading
+ upper case letter. Custom vendor queries should use a company
+ prefix (in lower case) ex: `qfsf.var'. QUERY may optionally be
+ followed by a `,' or `;' separated list. Stubs must ensure that
+ they match the full QUERY name.
+
+ Reply:
+ `XX...'
+ Hex encoded data from query. The reply can not be empty.
+
+ `ENN'
+ error reply
+
+ `'
+ Indicating an unrecognized QUERY.
+
+`Q'VAR`='VAL -- general set
+ Set value of VAR to VAL.
+
+ *Note general query packet::, for a discussion of naming
+ conventions.
+
+`r' -- reset *(deprecated)*
+ Reset the entire system.
+
+`R'XX -- remote restart
+ Restart the program being debugged. XX, while needed, is ignored.
+ This packet is only available in extended mode.
+
+ Reply:
+ `_no reply_'
+ The `R' packet has no reply.
+
+`s'ADDR -- step
+ ADDR is address to resume. If ADDR is omitted, resume at same
+ address.
+
+ Reply: *Note Stop Reply Packets::, for the reply specifications.
+
+`S'SIG`;'ADDR -- step with signal
+ Like `C' but step not continue.
+
+ Reply: *Note Stop Reply Packets::, for the reply specifications.
+
+`t'ADDR`:'PP`,'MM -- search
+ Search backwards starting at address ADDR for a match with pattern
+ PP and mask MM. PP and MM are 4 bytes. ADDR must be at least 3
+ digits.
+
+`T'XX -- thread alive
+ Find out if the thread XX is alive.
+
+ Reply:
+ `OK'
+ thread is still alive
+
+ `ENN'
+ thread is dead
+
+`u' -- reserved
+ Reserved for future use.
+
+`U' -- reserved
+ Reserved for future use.
+
+`v' -- verbose packet prefix
+ Packets starting with `v' are identified by a multi-letter name,
+ up to the first `;' or `?' (or the end of the packet).
+
+`vCont'[;ACTION[`:'TID]]... -- extended resume
+ Resume the inferior. Different actions may be specified for each
+ thread. If an action is specified with no TID, then it is applied
+ to any threads that don't have a specific action specified; if no
+ default action is specified then other threads should remain
+ stopped. Specifying multiple default actions is an error;
+ specifying no actions is also an error. Thread IDs are specified
+ in hexadecimal. Currently supported actions are:
+
+ `c'
+ Continue.
+
+ `CSIG'
+ Continue with signal SIG. SIG should be two hex digits.
+
+ `s'
+ Step.
+
+ `SSIG'
+ Step with signal SIG. SIG should be two hex digits.
+
+ The optional ADDR argument normally associated with these packets
+ is not supported in `vCont'.
+
+ Reply: *Note Stop Reply Packets::, for the reply specifications.
+
+`vCont?' -- extended resume query
+ Query support for the `vCont' packet.
+
+ Reply:
+ ``vCont'[;ACTION]...'
+ The `vCont' packet is supported. Each ACTION is a supported
+ command in the `vCont' packet.
+
+ `'
+ The `vCont' packet is not supported.
+
+`V' -- reserved
+ Reserved for future use.
+
+`w' -- reserved
+ Reserved for future use.
+
+`W' -- reserved
+ Reserved for future use.
+
+`x' -- reserved
+ Reserved for future use.
+
+`X'ADDR`,'LENGTH:XX... -- write mem (binary)
+ ADDR is address, LENGTH is number of bytes, XX... is binary data.
+ The characters `$', `#', and `0x7d' are escaped using `0x7d'.
+
+ Reply:
+ `OK'
+ for success
+
+ `ENN'
+ for an error
+
+`y' -- reserved
+ Reserved for future use.
+
+`Y' reserved
+ Reserved for future use.
+
+`z'TYPE`,'ADDR`,'LENGTH -- remove breakpoint or watchpoint *(draft)*
+`Z'TYPE`,'ADDR`,'LENGTH -- insert breakpoint or watchpoint *(draft)*
+ Insert (`Z') or remove (`z') a TYPE breakpoint or watchpoint
+ starting at address ADDRESS and covering the next LENGTH bytes.
+
+ Each breakpoint and watchpoint packet TYPE is documented
+ separately.
+
+ _Implementation notes: A remote target shall return an empty string
+ for an unrecognized breakpoint or watchpoint packet TYPE. A
+ remote target shall support either both or neither of a given
+ `Z'TYPE... and `z'TYPE... packet pair. To avoid potential
+ problems with duplicate packets, the operations should be
+ implemented in an idempotent way._
+
+`z'`0'`,'ADDR`,'LENGTH -- remove memory breakpoint *(draft)*
+
+`Z'`0'`,'ADDR`,'LENGTH -- insert memory breakpoint *(draft)*
+ Insert (`Z0') or remove (`z0') a memory breakpoint at address
+ `addr' of size `length'.
+
+ A memory breakpoint is implemented by replacing the instruction at
+ ADDR with a software breakpoint or trap instruction. The `length'
+ is used by targets that indicates the size of the breakpoint (in
+ bytes) that should be inserted (e.g., the ARM and MIPS can insert
+ either a 2 or 4 byte breakpoint).
+
+ _Implementation note: It is possible for a target to copy or move
+ code that contains memory breakpoints (e.g., when implementing
+ overlays). The behavior of this packet, in the presence of such a
+ target, is not defined._
+
+ Reply:
+ `OK'
+ success
+
+ `'
+ not supported
+
+ `ENN'
+ for an error
+
+`z'`1'`,'ADDR`,'LENGTH -- remove hardware breakpoint *(draft)*
+
+`Z'`1'`,'ADDR`,'LENGTH -- insert hardware breakpoint *(draft)*
+ Insert (`Z1') or remove (`z1') a hardware breakpoint at address
+ `addr' of size `length'.
+
+ A hardware breakpoint is implemented using a mechanism that is not
+ dependant on being able to modify the target's memory.
+
+ _Implementation note: A hardware breakpoint is not affected by code
+ movement._
+
+ Reply:
+ `OK'
+ success
+
+ `'
+ not supported
+
+ `ENN'
+ for an error
+
+`z'`2'`,'ADDR`,'LENGTH -- remove write watchpoint *(draft)*
+
+`Z'`2'`,'ADDR`,'LENGTH -- insert write watchpoint *(draft)*
+ Insert (`Z2') or remove (`z2') a write watchpoint.
+
+ Reply:
+ `OK'
+ success
+
+ `'
+ not supported
+
+ `ENN'
+ for an error
+
+`z'`3'`,'ADDR`,'LENGTH -- remove read watchpoint *(draft)*
+
+`Z'`3'`,'ADDR`,'LENGTH -- insert read watchpoint *(draft)*
+ Insert (`Z3') or remove (`z3') a read watchpoint.
+
+ Reply:
+ `OK'
+ success
+
+ `'
+ not supported
+
+ `ENN'
+ for an error
+
+`z'`4'`,'ADDR`,'LENGTH -- remove access watchpoint *(draft)*
+
+`Z'`4'`,'ADDR`,'LENGTH -- insert access watchpoint *(draft)*
+ Insert (`Z4') or remove (`z4') an access watchpoint.
+
+ Reply:
+ `OK'
+ success
+
+ `'
+ not supported
+
+ `ENN'
+ for an error
+
+
+
+File: gdb.info, Node: Stop Reply Packets, Next: General Query Packets, Prev: Packets, Up: Remote Protocol
+
+Stop Reply Packets
+==================
+
+The `C', `c', `S', `s' and `?' packets can receive any of the below as
+a reply. In the case of the `C', `c', `S' and `s' packets, that reply
+is only returned when the target halts. In the below the exact meaning
+of `signal number' is poorly defined. In general one of the UNIX
+signal numbering conventions is used.
+
+`SAA'
+ AA is the signal number
+
+``T'AAN...`:'R...`;'N...`:'R...`;'N...`:'R...`;''
+ AA = two hex digit signal number; N... = register number (hex),
+ R... = target byte ordered register contents, size defined by
+ `DEPRECATED_REGISTER_RAW_SIZE'; N... = `thread', R... = thread
+ process ID, this is a hex integer; N... = (`watch' | `rwatch' |
+ `awatch', R... = data address, 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.
+
+`WAA'
+ The process exited, and AA is the exit status. This is only
+ applicable to certain targets.
+
+`XAA'
+ The process terminated with signal AA.
+
+`OXX...'
+ 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.
+
+`FCALL-ID`,'PARAMETER...'
+ CALL-ID is the identifier which says which host system call should
+ be called. This is just the name of the function. Translation
+ into the correct system call is only applicable as it's defined in
+ GDB. *Note File-I/O remote protocol extension::, for a list of
+ implemented system calls.
+
+ PARAMETER... is a list of parameters as defined for this very
+ system call.
+
+ The target replies with this packet when it expects GDB to call a
+ host system call on behalf of the target. GDB replies with an
+ appropriate `F' packet and keeps up waiting for the next reply
+ packet from the target. The latest `C', `c', `S' or `s' action is
+ expected to be continued. *Note File-I/O remote protocol
+ extension::, for more details.
+
+
+
+File: gdb.info, Node: General Query Packets, Next: Register Packet Format, Prev: Stop Reply Packets, Up: Remote Protocol
+
+General Query Packets
+=====================
+
+The following set and query packets have already been defined.
+
+`q'`C' -- current thread
+ Return the current thread id.
+
+ Reply:
+ ``QC'PID'
+ Where PID is a HEX encoded 16 bit process id.
+
+ `*'
+ Any other reply implies the old pid.
+
+`q'`fThreadInfo' - all thread ids
+ `q'`sThreadInfo'
+
+ Obtain a list of active thread ids from the target (OS). Since
+ there may be too many active threads to fit into one reply packet,
+ this query works iteratively: it may require more than one
+ query/reply sequence to obtain the entire list of threads. The
+ first query of the sequence will be the `qf'`ThreadInfo' query;
+ subsequent queries in the sequence will be the `qs'`ThreadInfo'
+ query.
+
+ NOTE: replaces the `qL' query (see below).
+
+ Reply:
+ ``m'ID'
+ A single thread id
+
+ ``m'ID,ID...'
+ a comma-separated list of thread ids
+
+ ``l''
+ (lower case 'el') denotes end of list.
+
+ In response to each query, the target will reply with a list of
+ one or more thread ids, in big-endian hex, separated by commas.
+ GDB will respond to each reply with a request for more thread ids
+ (using the `qs' form of the query), until the target responds with
+ `l' (lower-case el, for `'last'').
+
+`q'`ThreadExtraInfo'`,'ID -- extra thread info
+ Where ID is a thread-id in big-endian hex. Obtain a printable
+ string description of a thread's attributes from the target OS.
+ This string may contain anything that the target OS thinks is
+ interesting for GDB to tell the user about the thread. The string
+ is displayed in GDB's `info threads' display. Some examples of
+ possible thread extra info strings are "Runnable", or "Blocked on
+ Mutex".
+
+ Reply:
+ `XX...'
+ Where XX... is a hex encoding of ASCII data, comprising the
+ printable string containing the extra information about the
+ thread's attributes.
+
+`q'`L'STARTFLAGTHREADCOUNTNEXTTHREAD -- query LIST or THREADLIST *(deprecated)*
+ Obtain thread information from RTOS. Where: STARTFLAG (one hex
+ digit) is one to indicate the first query and zero to indicate a
+ subsequent query; THREADCOUNT (two hex digits) is the maximum
+ number of threads the response packet can contain; and NEXTTHREAD
+ (eight hex digits), for subsequent queries (STARTFLAG is zero), is
+ returned in the response as ARGTHREAD.
+
+ NOTE: this query is replaced by the `q'`fThreadInfo' query (see
+ above).
+
+ Reply:
+ ``q'`M'COUNTDONEARGTHREADTHREAD...'
+ Where: COUNT (two hex digits) is the number of threads being
+ returned; DONE (one hex digit) is zero to indicate more
+ threads and one indicates no further threads; ARGTHREADID
+ (eight hex digits) is NEXTTHREAD from the request packet;
+ THREAD... is a sequence of thread IDs from the target.
+ THREADID (eight hex digits). See
+ `remote.c:parse_threadlist_response()'.
+
+`q'`CRC:'ADDR`,'LENGTH -- compute CRC of memory block
+ Reply:
+ ``E'NN'
+ An error (such as memory fault)
+
+ ``C'CRC32'
+ A 32 bit cyclic redundancy check of the specified memory
+ region.
+
+`q'`Offsets' -- query sect offs
+ Get section offsets that the target used when re-locating the
+ downloaded image. _Note: while a `Bss' offset is included in the
+ response, GDB ignores this and instead applies the `Data' offset
+ to the `Bss' section._
+
+ Reply:
+ ``Text='XXX`;Data='YYY`;Bss='ZZZ'
+
+`q'`P'MODETHREADID -- thread info request
+ Returns information on THREADID. Where: MODE is a hex encoded 32
+ bit mode; THREADID is a hex encoded 64 bit thread ID.
+
+ Reply:
+ `*'
+
+ See `remote.c:remote_unpack_thread_info_response()'.
+
+`q'`Rcmd,'COMMAND -- remote command
+ COMMAND (hex encoded) is passed to the local interpreter for
+ execution. Invalid commands should be reported using the output
+ string. Before the final result packet, the target may also
+ respond with a number of intermediate `O'OUTPUT console output
+ packets. _Implementors should note that providing access to a
+ stubs's interpreter may have security implications_.
+
+ Reply:
+ `OK'
+ A command response with no output.
+
+ `OUTPUT'
+ A command response with the hex encoded output string OUTPUT.
+
+ ``E'NN'
+ Indicate a badly formed request.
+
+ ``''
+ When `q'`Rcmd' is not recognized.
+
+`qSymbol::' -- symbol lookup
+ Notify the target that GDB is prepared to serve symbol lookup
+ requests. Accept requests from the target for the values of
+ symbols.
+
+ Reply:
+ ``OK''
+ The target does not need to look up any (more) symbols.
+
+ ``qSymbol:'SYM_NAME'
+ The target requests the value of symbol SYM_NAME (hex
+ encoded). GDB may provide the value by using the
+ `qSymbol:'SYM_VALUE:SYM_NAME message, described below.
+
+`qSymbol:'SYM_VALUE:SYM_NAME -- symbol value
+ Set the value of SYM_NAME to SYM_VALUE.
+
+ SYM_NAME (hex encoded) is the name of a symbol whose value the
+ target has previously requested.
+
+ SYM_VALUE (hex) is the value for symbol SYM_NAME. If GDB cannot
+ supply a value for SYM_NAME, then this field will be empty.
+
+ Reply:
+ ``OK''
+ The target does not need to look up any (more) symbols.
+
+ ``qSymbol:'SYM_NAME'
+ The target requests the value of a new symbol SYM_NAME (hex
+ encoded). GDB will continue to supply the values of symbols
+ (if available), until the target ceases to request them.
+
+`qPart':OBJECT:`read':ANNEX:OFFSET,LENGTH -- read special data
+ Read uninterpreted bytes from the target's special data area
+ identified by the keyword `object'. Request LENGTH bytes starting
+ at OFFSET bytes into the data. The content and encoding of ANNEX
+ is specific to the object; it can supply additional details about
+ what data to access.
+
+ Here are the specific requests of this form defined so far. All
+ ``qPart':OBJECT:`read':...' requests use the same reply formats,
+ listed below.
+
+ `qPart':`auxv':`read'::OFFSET,LENGTH
+ Access the target's "auxiliary vector". *Note Auxiliary
+ Vector::. Note ANNEX must be empty.
+
+ Reply:
+ `OK'
+ The OFFSET in the request is at the end of the data. There
+ is no more data to be read.
+
+ XX...
+ Hex encoded data bytes read. This may be fewer bytes than
+ the LENGTH in the request.
+
+ `E00'
+ The request was malformed, or ANNEX was invalid.
+
+ `E'NN
+ The offset was invalid, or there was an error encountered
+ reading the data. NN is a hex-encoded `errno' value.
+
+ `""' (empty)
+ An empty reply indicates the OBJECT or ANNEX string was not
+ recognized by the stub.
+
+`qPart':OBJECT:`write':ANNEX:OFFSET:DATA...
+ Write uninterpreted bytes into the target's special data area
+ identified by the keyword `object', starting at OFFSET bytes into
+ the data. DATA... is the hex-encoded data to be written. The
+ content and encoding of ANNEX is specific to the object; it can
+ supply additional details about what data to access.
+
+ No requests of this form are presently in use. This specification
+ serves as a placeholder to document the common format that new
+ specific request specifications ought to use.
+
+ Reply:
+ NN
+ NN (hex encoded) is the number of bytes written. This may be
+ fewer bytes than supplied in the request.
+
+ `E00'
+ The request was malformed, or ANNEX was invalid.
+
+ `E'NN
+ The offset was invalid, or there was an error encountered
+ writing the data. NN is a hex-encoded `errno' value.
+
+ `""' (empty)
+ An empty reply indicates the OBJECT or ANNEX string was not
+ recognized by the stub, or that the object does not support
+ writing.
+
+`qPart':OBJECT:OPERATION:...
+ Requests of this form may be added in the future. When a stub does
+ not recognize the OBJECT keyword, or its support for OBJECT does
+ not recognize the OPERATION keyword, the stub must respond with an
+ empty packet.
+
+
+File: gdb.info, Node: Register Packet Format, Next: Examples, Prev: General Query Packets, Up: Remote Protocol
+
+Register Packet Format
+======================
+
+The following `g'/`G' packets have previously been defined. In the
+below, some thirty-two bit registers are transferred as sixty-four
+bits. Those registers should be zero/sign extended (which?) to fill
+the space allocated. Register bytes are transfered in target byte
+order. The two nibbles within a register byte are transfered
+most-significant - least-significant.
+
+MIPS32
+ All registers are transfered as thirty-two bit quantities in the
+ order: 32 general-purpose; sr; lo; hi; bad; cause; pc; 32
+ floating-point registers; fsr; fir; fp.
+
+MIPS64
+ All registers are transfered as sixty-four bit quantities
+ (including thirty-two bit registers such as `sr'). The ordering
+ is the same as `MIPS32'.
+
+
+
+File: gdb.info, Node: Examples, Next: File-I/O remote protocol extension, Prev: Register Packet Format, Up: Remote Protocol
+
+Examples
+========
+
+Example sequence of a target being re-started. Notice how the restart
+does not get any direct output:
+
+ -> `R00'
+ <- `+'
+ _target restarts_
+ -> `?'
+ <- `+'
+ <- `T001:1234123412341234'
+ -> `+'
+
+ Example sequence of a target being stepped by a single instruction:
+
+ -> `G1445...'
+ <- `+'
+ -> `s'
+ <- `+'
+ _time passes_
+ <- `T001:1234123412341234'
+ -> `+'
+ -> `g'
+ <- `+'
+ <- `1455...'
+ -> `+'
+
+
+File: gdb.info, Node: File-I/O remote protocol extension, Prev: Examples, Up: Remote Protocol
+
+File-I/O remote protocol extension
+==================================
+
+* Menu:
+
+* File-I/O Overview::
+* Protocol basics::
+* The F request packet::
+* The F reply packet::
+* Memory transfer::
+* The Ctrl-C message::
+* Console I/O::
+* The isatty call::
+* The system call::
+* List of supported calls::
+* Protocol specific representation of datatypes::
+* Constants::
+* File-I/O Examples::
+
+
+File: gdb.info, Node: File-I/O Overview, Next: Protocol basics, Up: File-I/O remote protocol extension
+
+File-I/O Overview
+-----------------
+
+The File I/O remote protocol extension (short: File-I/O) allows the
+target to use the hosts file system and console I/O when calling various
+system calls. System calls on the target system are translated into a
+remote protocol packet to the host system which then performs the needed
+actions and returns with an adequate response packet to the target
+system. This simulates file system operations even on targets that
+lack file systems.
+
+ The protocol is defined host- and target-system independent. It uses
+it's own independent representation of datatypes and values. Both, GDB
+and the target's GDB stub are responsible for translating the system
+dependent values into the unified protocol values when data is
+transmitted.
+
+ The communication is synchronous. A system call is possible only
+when GDB is waiting for the `C', `c', `S' or `s' packets. While GDB
+handles the request for a system call, the target is stopped to allow
+deterministic access to the target's memory. Therefore File-I/O is not
+interuptible by target signals. It is possible to interrupt File-I/O
+by a user interrupt (Ctrl-C), though.
+
+ The target's request to perform a host system call does not finish
+the latest `C', `c', `S' or `s' action. That means, after finishing
+the system call, the target returns to continuing the previous activity
+(continue, step). No additional continue or step request from GDB is
+required.
+
+ (gdb) continue
+ <- target requests 'system call X'
+ target is stopped, GDB executes system call
+ -> GDB returns result
+ ... target continues, GDB returns to wait for the target
+ <- target hits breakpoint and sends a Txx packet
+
+ The protocol is only used for files on the host file system and for
+I/O on the console. Character or block special devices, pipes, named
+pipes or sockets or any other communication method on the host system
+are not supported by this protocol.
+
+
+File: gdb.info, Node: Protocol basics, Next: The F request packet, Prev: File-I/O Overview, Up: File-I/O remote protocol extension
+
+Protocol basics
+---------------
+
+The File-I/O protocol uses the `F' packet, as request as well as as
+reply packet. Since a File-I/O system call can only occur when GDB is
+waiting for the continuing or stepping target, the File-I/O request is
+a reply that GDB has to expect as a result of a former `C', `c', `S' or
+`s' packet. This `F' packet contains all information needed to allow
+GDB to call the appropriate host system call:
+
+ * A unique identifier for the requested system call.
+
+ * All parameters to the system call. Pointers are given as addresses
+ in the target memory address space. Pointers to strings are given
+ as pointer/length pair. Numerical values are given as they are.
+ Numerical control values are given in a protocol specific
+ representation.
+
+
+ At that point GDB has to perform the following actions.
+
+ * If parameter pointer values are given, which point to data needed
+ as input to a system call, GDB requests this data from the target
+ with a standard `m' packet request. This additional communication
+ has to be expected by the target implementation and is handled as
+ any other `m' packet.
+
+ * GDB translates all value from protocol representation to host
+ representation as needed. Datatypes are coerced into the host
+ types.
+
+ * GDB calls the system call
+
+ * It then coerces datatypes back to protocol representation.
+
+ * If pointer parameters in the request packet point to buffer space
+ in which a system call is expected to copy data to, the data is
+ transmitted to the target using a `M' or `X' packet. This packet
+ has to be expected by the target implementation and is handled as
+ any other `M' or `X' packet.
+
+
+ Eventually GDB replies with another `F' packet which contains all
+necessary information for the target to continue. This at least
+contains
+
+ * Return value.
+
+ * `errno', if has been changed by the system call.
+
+ * "Ctrl-C" flag.
+
+
+ After having done the needed type and value coercion, the target
+continues the latest continue or step action.
+
+
+File: gdb.info, Node: The F request packet, Next: The F reply packet, Prev: Protocol basics, Up: File-I/O remote protocol extension
+
+The `F' request packet
+----------------------
+
+The `F' request packet has the following format:
+
+ `F'CALL-ID`,'PARAMETER...
+
+ CALL-ID is the identifier to indicate the host system call to be
+ called. This is just the name of the function.
+
+ PARAMETER... are the parameters to the system call.
+
+
+ Parameters are hexadecimal integer values, either the real values in
+case of scalar datatypes, as pointers to target buffer space in case of
+compound datatypes and unspecified memory areas or as pointer/length
+pairs in case of string parameters. These are appended to the call-id,
+each separated from its predecessor by a comma. All values are
+transmitted in ASCII string representation, pointer/length pairs
+separated by a slash.
+
+
+File: gdb.info, Node: The F reply packet, Next: Memory transfer, Prev: The F request packet, Up: File-I/O remote protocol extension
+
+The `F' reply packet
+--------------------
+
+The `F' reply packet has the following format:
+
+ `F'RETCODE`,'ERRNO`,'CTRL-C FLAG`;'CALL SPECIFIC ATTACHMENT
+
+ RETCODE is the return code of the system call as hexadecimal value.
+
+ ERRNO is the errno set by the call, in protocol specific
+ representation. This parameter can be omitted if the call was
+ successful.
+
+ CTRL-C FLAG is only send if the user requested a break. In this
+ case, ERRNO must be send as well, even if the call was successful.
+ The CTRL-C FLAG itself consists of the character 'C':
+
+ F0,0,C
+
+ or, if the call was interupted before the host call has been
+ performed:
+
+ F-1,4,C
+
+ assuming 4 is the protocol specific representation of `EINTR'.
+
+
+
+File: gdb.info, Node: Memory transfer, Next: The Ctrl-C message, Prev: The F reply packet, Up: File-I/O remote protocol extension
+
+Memory transfer
+---------------
+
+Structured data which is transferred using a memory read or write as
+e.g. a `struct stat' is expected to be in a protocol specific format
+with all scalar multibyte datatypes being big endian. This should be
+done by the target before the `F' packet is sent resp. by GDB before it
+transfers memory to the target. Transferred pointers to structured
+data should point to the already coerced data at any time.
+
+
+File: gdb.info, Node: The Ctrl-C message, Next: Console I/O, Prev: Memory transfer, Up: File-I/O remote protocol extension
+
+The Ctrl-C message
+------------------
+
+A special case is, if the CTRL-C FLAG is set in the GDB reply packet.
+In this case the target should behave, as if it had gotten a break
+message. The meaning for the target is "system call interupted by
+`SIGINT'". Consequentially, the target should actually stop (as with a
+break message) and return to GDB with a `T02' packet. In this case,
+it's important for the target to know, in which state the system call
+was interrupted. Since this action is by design not an atomic
+operation, we have to differ between two cases:
+
+ * The system call hasn't been performed on the host yet.
+
+ * The system call on the host has been finished.
+
+
+ These two states can be distinguished by the target by the value of
+the returned `errno'. If it's the protocol representation of `EINTR',
+the system call hasn't been performed. This is equivalent to the
+`EINTR' handling on POSIX systems. In any other case, the target may
+presume that the system call has been finished -- successful or not --
+and should behave as if the break message arrived right after the
+system call.
+
+ GDB must behave reliable. If the system call has not been called
+yet, GDB may send the `F' reply immediately, setting `EINTR' as `errno'
+in the packet. If the system call on the host has been finished before
+the user requests a break, the full action must be finshed by GDB.
+This requires sending `M' or `X' packets as they fit. The `F' packet
+may only be send when either nothing has happened or the full action
+has been completed.
+
+
+File: gdb.info, Node: Console I/O, Next: The isatty call, Prev: The Ctrl-C message, Up: File-I/O remote protocol extension
+
+Console I/O
+-----------
+
+By default and if not explicitely closed by the target system, the file
+descriptors 0, 1 and 2 are connected to the GDB console. Output on the
+GDB console is handled as any other file output operation (`write(1,
+...)' or `write(2, ...)'). Console input is handled by GDB so that
+after the target read request from file descriptor 0 all following
+typing is buffered until either one of the following conditions is met:
+
+ * The user presses `Ctrl-C'. The behaviour is as explained above,
+ the `read' system call is treated as finished.
+
+ * The user presses `Enter'. This is treated as end of input with a
+ trailing line feed.
+
+ * The user presses `Ctrl-D'. This is treated as end of input. No
+ trailing character, especially no Ctrl-D is appended to the input.
+
+
+ If the user has typed more characters as fit in the buffer given to
+the read call, the trailing characters are buffered in GDB until either
+another `read(0, ...)' is requested by the target or debugging is
+stopped on users request.
+
+
+File: gdb.info, Node: The isatty call, Next: The system call, Prev: Console I/O, Up: File-I/O remote protocol extension
+
+The isatty(3) call
+------------------
+
+A special case in this protocol is the library call `isatty' which is
+implemented as it's own call inside of this protocol. It returns 1 to
+the target if the file descriptor given as parameter is attached to the
+GDB console, 0 otherwise. Implementing through system calls would
+require implementing `ioctl' and would be more complex than needed.
+
+
+File: gdb.info, Node: The system call, Next: List of supported calls, Prev: The isatty call, Up: File-I/O remote protocol extension
+
+The system(3) call
+------------------
+
+The other special case in this protocol is the `system' call which is
+implemented as it's own call, too. GDB is taking over the full task of
+calling the necessary host calls to perform the `system' call. The
+return value of `system' is simplified before it's returned to the
+target. Basically, the only signal transmitted back is `EINTR' in case
+the user pressed `Ctrl-C'. Otherwise the return value consists
+entirely of the exit status of the called command.
+
+ Due to security concerns, the `system' call is refused to be called
+by GDB by default. The user has to allow this call explicitly by
+entering
+
+``set remote system-call-allowed 1''
+
+ Disabling the `system' call is done by
+
+``set remote system-call-allowed 0''
+
+ The current setting is shown by typing
+
+``show remote system-call-allowed''
+
+
+File: gdb.info, Node: List of supported calls, Next: Protocol specific representation of datatypes, Prev: The system call, Up: File-I/O remote protocol extension
+
+List of supported calls
+-----------------------
+
+* Menu:
+
+* open::
+* close::
+* read::
+* write::
+* lseek::
+* rename::
+* unlink::
+* stat/fstat::
+* gettimeofday::
+* isatty::
+* system::
+
+
+File: gdb.info, Node: open, Next: close, Up: List of supported calls
+
+open
+....
+
+Synopsis:
+ int open(const char *pathname, int flags);
+ int open(const char *pathname, int flags, mode_t mode);
+
+Request:
+ Fopen,pathptr/len,flags,mode
+
+`flags' is the bitwise or of the following values:
+
+`O_CREAT'
+ If the file does not exist it will be created. The host rules
+ apply as far as file ownership and time stamps are concerned.
+
+`O_EXCL'
+ When used with O_CREAT, if the file already exists it is an error
+ and open() fails.
+
+`O_TRUNC'
+ If the file already exists and the open mode allows writing
+ (O_RDWR or O_WRONLY is given) it will be truncated to length 0.
+
+`O_APPEND'
+ The file is opened in append mode.
+
+`O_RDONLY'
+ The file is opened for reading only.
+
+`O_WRONLY'
+ The file is opened for writing only.
+
+`O_RDWR'
+ The file is opened for reading and writing.
+
+ Each other bit is silently ignored.
+
+
+`mode' is the bitwise or of the following values:
+
+`S_IRUSR'
+ User has read permission.
+
+`S_IWUSR'
+ User has write permission.
+
+`S_IRGRP'
+ Group has read permission.
+
+`S_IWGRP'
+ Group has write permission.
+
+`S_IROTH'
+ Others have read permission.
+
+`S_IWOTH'
+ Others have write permission.
+
+ Each other bit is silently ignored.
+
+
+Return value:
+ open returns the new file descriptor or -1 if an error
+ occured.
+
+Errors:
+
+
+`EEXIST'
+ pathname already exists and O_CREAT and O_EXCL were used.
+
+`EISDIR'
+ pathname refers to a directory.
+
+`EACCES'
+ The requested access is not allowed.
+
+`ENAMETOOLONG'
+ pathname was too long.
+
+`ENOENT'
+ A directory component in pathname does not exist.
+
+`ENODEV'
+ pathname refers to a device, pipe, named pipe or socket.
+
+`EROFS'
+ pathname refers to a file on a read-only filesystem and write
+ access was requested.
+
+`EFAULT'
+ pathname is an invalid pointer value.
+
+`ENOSPC'
+ No space on device to create the file.
+
+`EMFILE'
+ The process already has the maximum number of files open.
+
+`ENFILE'
+ The limit on the total number of files open on the system has been
+ reached.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: close, Next: read, Prev: open, Up: List of supported calls
+
+close
+.....
+
+Synopsis:
+ int close(int fd);
+
+Request:
+ Fclose,fd
+
+Return value:
+ close returns zero on success, or -1 if an error occurred.
+
+Errors:
+
+
+`EBADF'
+ fd isn't a valid open file descriptor.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: read, Next: write, Prev: close, Up: List of supported calls
+
+read
+....
+
+Synopsis:
+ int read(int fd, void *buf, unsigned int count);
+
+Request:
+ Fread,fd,bufptr,count
+
+Return value:
+ On success, the number of bytes read is returned.
+ Zero indicates end of file. If count is zero, read
+ returns zero as well. On error, -1 is returned.
+
+Errors:
+
+
+`EBADF'
+ fd is not a valid file descriptor or is not open for reading.
+
+`EFAULT'
+ buf is an invalid pointer value.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: write, Next: lseek, Prev: read, Up: List of supported calls
+
+write
+.....
+
+Synopsis:
+ int write(int fd, const void *buf, unsigned int count);
+
+Request:
+ Fwrite,fd,bufptr,count
+
+Return value:
+ On success, the number of bytes written are returned.
+ Zero indicates nothing was written. On error, -1
+ is returned.
+
+Errors:
+
+
+`EBADF'
+ fd is not a valid file descriptor or is not open for writing.
+
+`EFAULT'
+ buf is an invalid pointer value.
+
+`EFBIG'
+ An attempt was made to write a file that exceeds the host specific
+ maximum file size allowed.
+
+`ENOSPC'
+ No space on device to write the data.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: lseek, Next: rename, Prev: write, Up: List of supported calls
+
+lseek
+.....
+
+Synopsis:
+ long lseek (int fd, long offset, int flag);
+
+Request:
+ Flseek,fd,offset,flag
+
+ `flag' is one of:
+
+`SEEK_SET'
+ The offset is set to offset bytes.
+
+`SEEK_CUR'
+ The offset is set to its current location plus offset bytes.
+
+`SEEK_END'
+ The offset is set to the size of the file plus offset bytes.
+
+Return value:
+ On success, the resulting unsigned offset in bytes from
+ the beginning of the file is returned. Otherwise, a
+ value of -1 is returned.
+
+Errors:
+
+
+`EBADF'
+ fd is not a valid open file descriptor.
+
+`ESPIPE'
+ fd is associated with the GDB console.
+
+`EINVAL'
+ flag is not a proper value.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: rename, Next: unlink, Prev: lseek, Up: List of supported calls
+
+rename
+......
+
+Synopsis:
+ int rename(const char *oldpath, const char *newpath);
+
+Request:
+ Frename,oldpathptr/len,newpathptr/len
+
+Return value:
+ On success, zero is returned. On error, -1 is returned.
+
+Errors:
+
+
+`EISDIR'
+ newpath is an existing directory, but oldpath is not a directory.
+
+`EEXIST'
+ newpath is a non-empty directory.
+
+`EBUSY'
+ oldpath or newpath is a directory that is in use by some process.
+
+`EINVAL'
+ An attempt was made to make a directory a subdirectory of itself.
+
+`ENOTDIR'
+ A component used as a directory in oldpath or new path is not a
+ directory. Or oldpath is a directory and newpath exists but is
+ not a directory.
+
+`EFAULT'
+ oldpathptr or newpathptr are invalid pointer values.
+
+`EACCES'
+ No access to the file or the path of the file.
+
+`ENAMETOOLONG'
+ oldpath or newpath was too long.
+
+`ENOENT'
+ A directory component in oldpath or newpath does not exist.
+
+`EROFS'
+ The file is on a read-only filesystem.
+
+`ENOSPC'
+ The device containing the file has no room for the new directory
+ entry.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: unlink, Next: stat/fstat, Prev: rename, Up: List of supported calls
+
+unlink
+......
+
+Synopsis:
+ int unlink(const char *pathname);
+
+Request:
+ Funlink,pathnameptr/len
+
+Return value:
+ On success, zero is returned. On error, -1 is returned.
+
+Errors:
+
+
+`EACCES'
+ No access to the file or the path of the file.
+
+`EPERM'
+ The system does not allow unlinking of directories.
+
+`EBUSY'
+ The file pathname cannot be unlinked because it's being used by
+ another process.
+
+`EFAULT'
+ pathnameptr is an invalid pointer value.
+
+`ENAMETOOLONG'
+ pathname was too long.
+
+`ENOENT'
+ A directory component in pathname does not exist.
+
+`ENOTDIR'
+ A component of the path is not a directory.
+
+`EROFS'
+ The file is on a read-only filesystem.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: stat/fstat, Next: gettimeofday, Prev: unlink, Up: List of supported calls
+
+stat/fstat
+..........
+
+Synopsis:
+ int stat(const char *pathname, struct stat *buf);
+ int fstat(int fd, struct stat *buf);
+
+Request:
+ Fstat,pathnameptr/len,bufptr
+ Ffstat,fd,bufptr
+
+Return value:
+ On success, zero is returned. On error, -1 is returned.
+
+Errors:
+
+
+`EBADF'
+ fd is not a valid open file.
+
+`ENOENT'
+ A directory component in pathname does not exist or the path is an
+ empty string.
+
+`ENOTDIR'
+ A component of the path is not a directory.
+
+`EFAULT'
+ pathnameptr is an invalid pointer value.
+
+`EACCES'
+ No access to the file or the path of the file.
+
+`ENAMETOOLONG'
+ pathname was too long.
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: gettimeofday, Next: isatty, Prev: stat/fstat, Up: List of supported calls
+
+gettimeofday
+............
+
+Synopsis:
+ int gettimeofday(struct timeval *tv, void *tz);
+
+Request:
+ Fgettimeofday,tvptr,tzptr
+
+Return value:
+ On success, 0 is returned, -1 otherwise.
+
+Errors:
+
+
+`EINVAL'
+ tz is a non-NULL pointer.
+
+`EFAULT'
+ tvptr and/or tzptr is an invalid pointer value.
+
+
+File: gdb.info, Node: isatty, Next: system, Prev: gettimeofday, Up: List of supported calls
+
+isatty
+......
+
+Synopsis:
+ int isatty(int fd);
+
+Request:
+ Fisatty,fd
+
+Return value:
+ Returns 1 if fd refers to the GDB console, 0 otherwise.
+
+Errors:
+
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: system, Prev: isatty, Up: List of supported calls
+
+system
+......
+
+Synopsis:
+ int system(const char *command);
+
+Request:
+ Fsystem,commandptr/len
+
+Return value:
+ The value returned is -1 on error and the return status
+ of the command otherwise. Only the exit status of the
+ command is returned, which is extracted from the hosts
+ system return value by calling WEXITSTATUS(retval).
+ In case /bin/sh could not be executed, 127 is returned.
+
+Errors:
+
+
+`EINTR'
+ The call was interrupted by the user.
+
+
+File: gdb.info, Node: Protocol specific representation of datatypes, Next: Constants, Prev: List of supported calls, Up: File-I/O remote protocol extension
+
+Protocol specific representation of datatypes
+---------------------------------------------
+
+* Menu:
+
+* Integral datatypes::
+* Pointer values::
+* struct stat::
+* struct timeval::
+
+
+File: gdb.info, Node: Integral datatypes, Next: Pointer values, Up: Protocol specific representation of datatypes
+
+Integral datatypes
+..................
+
+The integral datatypes used in the system calls are
+
+ int, unsigned int, long, unsigned long, mode_t and time_t
+
+ `Int', `unsigned int', `mode_t' and `time_t' are implemented as 32
+bit values in this protocol.
+
+ `Long' and `unsigned long' are implemented as 64 bit types.
+
+ *Note Limits::, for corresponding MIN and MAX values (similar to
+those in `limits.h') to allow range checking on host and target.
+
+ `time_t' datatypes are defined as seconds since the Epoch.
+
+ All integral datatypes transferred as part of a memory read or write
+of a structured datatype e.g. a `struct stat' have to be given in big
+endian byte order.
+
+
+File: gdb.info, Node: Pointer values, Next: struct stat, Prev: Integral datatypes, Up: Protocol specific representation of datatypes
+
+Pointer values
+..............
+
+Pointers to target data are transmitted as they are. An exception is
+made for pointers to buffers for which the length isn't transmitted as
+part of the function call, namely strings. Strings are transmitted as
+a pointer/length pair, both as hex values, e.g.
+
+ `1aaf/12'
+
+which is a pointer to data of length 18 bytes at position 0x1aaf. The
+length is defined as the full string length in bytes, including the
+trailing null byte. Example:
+
+ ``hello, world'' at address 0x123456
+
+is transmitted as
+
+ `123456/d'
+
+
+File: gdb.info, Node: struct stat, Next: struct timeval, Prev: Pointer values, Up: Protocol specific representation of datatypes
+
+struct stat
+...........
+
+The buffer of type struct stat used by the target and GDB is defined as
+follows:
+
+ struct stat {
+ unsigned int st_dev; /* device */
+ unsigned int st_ino; /* inode */
+ mode_t st_mode; /* protection */
+ unsigned int st_nlink; /* number of hard links */
+ unsigned int st_uid; /* user ID of owner */
+ unsigned int st_gid; /* group ID of owner */
+ unsigned int st_rdev; /* device type (if inode device) */
+ unsigned long st_size; /* total size, in bytes */
+ unsigned long st_blksize; /* blocksize for filesystem I/O */
+ unsigned long st_blocks; /* number of blocks allocated */
+ time_t st_atime; /* time of last access */
+ time_t st_mtime; /* time of last modification */
+ time_t st_ctime; /* time of last change */
+ };
+
+ The integral datatypes are conforming to the definitions given in the
+approriate section (see *Note Integral datatypes::, for details) so this
+structure is of size 64 bytes.
+
+ The values of several fields have a restricted meaning and/or range
+of values.
+
+ st_dev: 0 file
+ 1 console
+
+ st_ino: No valid meaning for the target. Transmitted unchanged.
+
+ st_mode: Valid mode bits are described in Appendix C. Any other
+ bits have currently no meaning for the target.
+
+ st_uid: No valid meaning for the target. Transmitted unchanged.
+
+ st_gid: No valid meaning for the target. Transmitted unchanged.
+
+ st_rdev: No valid meaning for the target. Transmitted unchanged.
+
+ st_atime, st_mtime, st_ctime:
+ These values have a host and file system dependent
+ accuracy. Especially on Windows hosts the file systems
+ don't support exact timing values.
+
+ The target gets a struct stat of the above representation and is
+responsible to coerce it to the target representation before continuing.
+
+ Note that due to size differences between the host and target
+representation of stat members, these members could eventually get
+truncated on the target.
+
+
+File: gdb.info, Node: struct timeval, Prev: struct stat, Up: Protocol specific representation of datatypes
+
+struct timeval
+..............
+
+The buffer of type struct timeval used by the target and GDB is defined
+as follows:
+
+ struct timeval {
+ time_t tv_sec; /* second */
+ long tv_usec; /* microsecond */
+ };
+
+ The integral datatypes are conforming to the definitions given in the
+approriate section (see *Note Integral datatypes::, for details) so this
+structure is of size 8 bytes.
+
+
+File: gdb.info, Node: Constants, Next: File-I/O Examples, Prev: Protocol specific representation of datatypes, Up: File-I/O remote protocol extension
+
+Constants
+---------
+
+The following values are used for the constants inside of the protocol.
+GDB and target are resposible to translate these values before and
+after the call as needed.
+
+* Menu:
+
+* Open flags::
+* mode_t values::
+* Errno values::
+* Lseek flags::
+* Limits::
+
+
+File: gdb.info, Node: Open flags, Next: mode_t values, Up: Constants
+
+Open flags
+..........
+
+All values are given in hexadecimal representation.
+
+ O_RDONLY 0x0
+ O_WRONLY 0x1
+ O_RDWR 0x2
+ O_APPEND 0x8
+ O_CREAT 0x200
+ O_TRUNC 0x400
+ O_EXCL 0x800
+
+
+File: gdb.info, Node: mode_t values, Next: Errno values, Prev: Open flags, Up: Constants
+
+mode_t values
+.............
+
+All values are given in octal representation.
+
+ S_IFREG 0100000
+ S_IFDIR 040000
+ S_IRUSR 0400
+ S_IWUSR 0200
+ S_IXUSR 0100
+ S_IRGRP 040
+ S_IWGRP 020
+ S_IXGRP 010
+ S_IROTH 04
+ S_IWOTH 02
+ S_IXOTH 01
+
+
+File: gdb.info, Node: Errno values, Next: Lseek flags, Prev: mode_t values, Up: Constants
+
+Errno values
+............
+
+All values are given in decimal representation.
+
+ EPERM 1
+ ENOENT 2
+ EINTR 4
+ EBADF 9
+ EACCES 13
+ EFAULT 14
+ EBUSY 16
+ EEXIST 17
+ ENODEV 19
+ ENOTDIR 20
+ EISDIR 21
+ EINVAL 22
+ ENFILE 23
+ EMFILE 24
+ EFBIG 27
+ ENOSPC 28
+ ESPIPE 29
+ EROFS 30
+ ENAMETOOLONG 91
+ EUNKNOWN 9999
+
+ EUNKNOWN is used as a fallback error value if a host system returns
+any error value not in the list of supported error numbers.
+
+
+File: gdb.info, Node: Lseek flags, Next: Limits, Prev: Errno values, Up: Constants
+
+Lseek flags
+...........
+
+ SEEK_SET 0
+ SEEK_CUR 1
+ SEEK_END 2
+
+
+File: gdb.info, Node: Limits, Prev: Lseek flags, Up: Constants
+
+Limits
+......
+
+All values are given in decimal representation.
+
+ INT_MIN -2147483648
+ INT_MAX 2147483647
+ UINT_MAX 4294967295
+ LONG_MIN -9223372036854775808
+ LONG_MAX 9223372036854775807
+ ULONG_MAX 18446744073709551615
+
+
+File: gdb.info, Node: File-I/O Examples, Prev: Constants, Up: File-I/O remote protocol extension
+
+File-I/O Examples
+-----------------
+
+Example sequence of a write call, file descriptor 3, buffer is at target
+address 0x1234, 6 bytes should be written:
+
+ <- `Fwrite,3,1234,6'
+ _request memory read from target_
+ -> `m1234,6'
+ <- XXXXXX
+ _return "6 bytes written"_
+ -> `F6'
+
+ Example sequence of a read call, file descriptor 3, buffer is at
+target address 0x1234, 6 bytes should be read:
+
+ <- `Fread,3,1234,6'
+ _request memory write to target_
+ -> `X1234,6:XXXXXX'
+ _return "6 bytes read"_
+ -> `F6'
+
+ Example sequence of a read call, call fails on the host due to
+invalid file descriptor (EBADF):
+
+ <- `Fread,3,1234,6'
+ -> `F-1,9'
+
+ Example sequence of a read call, user presses Ctrl-C before syscall
+on host is called:
+
+ <- `Fread,3,1234,6'
+ -> `F-1,4,C'
+ <- `T02'
+
+ Example sequence of a read call, user presses Ctrl-C after syscall on
+host is called:
+
+ <- `Fread,3,1234,6'
+ -> `X1234,6:XXXXXX'
+ <- `T02'
+
+
+File: gdb.info, Node: Agent Expressions, Next: Copying, Prev: Remote Protocol, Up: Top
+
+The GDB Agent Expression Mechanism
+**********************************
+
+In some applications, it is not feasable for the debugger to interrupt
+the program's execution long enough for the developer to learn anything
+helpful about its behavior. If the program's correctness depends on its
+real-time behavior, delays introduced by a debugger might cause the
+program to fail, even when the code itself is correct. It is useful to
+be able to observe the program's behavior without interrupting it.
+
+ Using GDB's `trace' and `collect' commands, the user can specify
+locations in the program, and arbitrary expressions to evaluate when
+those locations are reached. Later, using the `tfind' command, she can
+examine the values those expressions had when the program hit the trace
+points. The expressions may also denote objects in memory --
+structures or arrays, for example -- whose values GDB should record;
+while visiting a particular tracepoint, the user may inspect those
+objects as if they were in memory at that moment. However, because GDB
+records these values without interacting with the user, it can do so
+quickly and unobtrusively, hopefully not disturbing the program's
+behavior.
+
+ When GDB is debugging a remote target, the GDB "agent" code running
+on the target computes the values of the expressions itself. To avoid
+having a full symbolic expression evaluator on the agent, GDB translates
+expressions in the source language into a simpler bytecode language, and
+then sends the bytecode to the agent; the agent then executes the
+bytecode, and records the values for GDB to retrieve later.
+
+ The bytecode language is simple; there are forty-odd opcodes, the
+bulk of which are the usual vocabulary of C operands (addition,
+subtraction, shifts, and so on) and various sizes of literals and
+memory reference operations. The bytecode interpreter operates
+strictly on machine-level values -- various sizes of integers and
+floating point numbers -- and requires no information about types or
+symbols; thus, the interpreter's internal data structures are simple,
+and each bytecode requires only a few native machine instructions to
+implement it. The interpreter is small, and strict limits on the
+memory and time required to evaluate an expression are easy to
+determine, making it suitable for use by the debugging agent in
+real-time applications.
+
+* Menu:
+
+* General Bytecode Design:: Overview of the interpreter.
+* Bytecode Descriptions:: What each one does.
+* Using Agent Expressions:: How agent expressions fit into the big picture.
+* Varying Target Capabilities:: How to discover what the target can do.
+* Tracing on Symmetrix:: Special info for implementation on EMC's
+ boxes.
+* Rationale:: Why we did it this way.
+
+
+File: gdb.info, Node: General Bytecode Design, Next: Bytecode Descriptions, Up: Agent Expressions
+
+General Bytecode Design
+=======================
+
+The agent represents bytecode expressions as an array of bytes. Each
+instruction is one byte long (thus the term "bytecode"). Some
+instructions are followed by operand bytes; for example, the `goto'
+instruction is followed by a destination for the jump.
+
+ The bytecode interpreter is a stack-based machine; most instructions
+pop their operands off the stack, perform some operation, and push the
+result back on the stack for the next instruction to consume. Each
+element of the stack may contain either a integer or a floating point
+value; these values are as many bits wide as the largest integer that
+can be directly manipulated in the source language. Stack elements
+carry no record of their type; bytecode could push a value as an
+integer, then pop it as a floating point value. However, GDB will not
+generate code which does this. In C, one might define the type of a
+stack element as follows:
+ union agent_val {
+ LONGEST l;
+ DOUBLEST d;
+ };
+
+where `LONGEST' and `DOUBLEST' are `typedef' names for the largest
+integer and floating point types on the machine.
+
+ By the time the bytecode interpreter reaches the end of the
+expression, the value of the expression should be the only value left
+on the stack. For tracing applications, `trace' bytecodes in the
+expression will have recorded the necessary data, and the value on the
+stack may be discarded. For other applications, like conditional
+breakpoints, the value may be useful.
+
+ Separate from the stack, the interpreter has two registers:
+`pc'
+ The address of the next bytecode to execute.
+
+`start'
+ The address of the start of the bytecode expression, necessary for
+ interpreting the `goto' and `if_goto' instructions.
+
+
+Neither of these registers is directly visible to the bytecode language
+itself, but they are useful for defining the meanings of the bytecode
+operations.
+
+ There are no instructions to perform side effects on the running
+program, or call the program's functions; we assume that these
+expressions are only used for unobtrusive debugging, not for patching
+the running code.
+
+ Most bytecode instructions do not distinguish between the various
+sizes of values, and operate on full-width values; the upper bits of the
+values are simply ignored, since they do not usually make a difference
+to the value computed. The exceptions to this rule are:
+memory reference instructions (`ref'N)
+ There are distinct instructions to fetch different word sizes from
+ memory. Once on the stack, however, the values are treated as
+ full-size integers. They may need to be sign-extended; the `ext'
+ instruction exists for this purpose.
+
+the sign-extension instruction (`ext' N)
+ These clearly need to know which portion of their operand is to be
+ extended to occupy the full length of the word.
+
+
+ If the interpreter is unable to evaluate an expression completely for
+some reason (a memory location is inaccessible, or a divisor is zero,
+for example), we say that interpretation "terminates with an error".
+This means that the problem is reported back to the interpreter's caller
+in some helpful way. In general, code using agent expressions should
+assume that they may attempt to divide by zero, fetch arbitrary memory
+locations, and misbehave in other ways.
+
+ Even complicated C expressions compile to a few bytecode
+instructions; for example, the expression `x + y * z' would typically
+produce code like the following, assuming that `x' and `y' live in
+registers, and `z' is a global variable holding a 32-bit `int':
+ reg 1
+ reg 2
+ const32 address of z
+ ref32
+ ext 32
+ mul
+ add
+ end
+
+ In detail, these mean:
+`reg 1'
+ Push the value of register 1 (presumably holding `x') onto the
+ stack.
+
+`reg 2'
+ Push the value of register 2 (holding `y').
+
+`const32 address of z'
+ Push the address of `z' onto the stack.
+
+`ref32'
+ Fetch a 32-bit word from the address at the top of the stack;
+ replace the address on the stack with the value. Thus, we replace
+ the address of `z' with `z''s value.
+
+`ext 32'
+ Sign-extend the value on the top of the stack from 32 bits to full
+ length. This is necessary because `z' is a signed integer.
+
+`mul'
+ Pop the top two numbers on the stack, multiply them, and push their
+ product. Now the top of the stack contains the value of the
+ expression `y * z'.
+
+`add'
+ Pop the top two numbers, add them, and push the sum. Now the top
+ of the stack contains the value of `x + y * z'.
+
+`end'
+ Stop executing; the value left on the stack top is the value to be
+ recorded.
+
+
+
+File: gdb.info, Node: Bytecode Descriptions, Next: Using Agent Expressions, Prev: General Bytecode Design, Up: Agent Expressions
+
+Bytecode Descriptions
+=====================
+
+Each bytecode description has the following form:
+
+`add' (0x02): A B => A+B
+ Pop the top two stack items, A and B, as integers; push their sum,
+ as an integer.
+
+
+ In this example, `add' is the name of the bytecode, and `(0x02)' is
+the one-byte value used to encode the bytecode, in hexidecimal. The
+phrase "A B => A+B" shows the stack before and after the bytecode
+executes. Beforehand, the stack must contain at least two values, A
+and B; since the top of the stack is to the right, B is on the top of
+the stack, and A is underneath it. After execution, the bytecode will
+have popped A and B from the stack, and replaced them with a single
+value, A+B. There may be other values on the stack below those shown,
+but the bytecode affects only those shown.
+
+ Here is another example:
+
+`const8' (0x22) N: => N
+ Push the 8-bit integer constant N on the stack, without sign
+ extension.
+
+
+ In this example, the bytecode `const8' takes an operand N directly
+from the bytecode stream; the operand follows the `const8' bytecode
+itself. We write any such operands immediately after the name of the
+bytecode, before the colon, and describe the exact encoding of the
+operand in the bytecode stream in the body of the bytecode description.
+
+ For the `const8' bytecode, there are no stack items given before the
+=>; this simply means that the bytecode consumes no values from the
+stack. If a bytecode consumes no values, or produces no values, the
+list on either side of the => may be empty.
+
+ If a value is written as A, B, or N, then the bytecode treats it as
+an integer. If a value is written is ADDR, then the bytecode treats it
+as an address.
+
+ We do not fully describe the floating point operations here; although
+this design can be extended in a clean way to handle floating point
+values, they are not of immediate interest to the customer, so we avoid
+describing them, to save time.
+
+`float' (0x01): =>
+ Prefix for floating-point bytecodes. Not implemented yet.
+
+`add' (0x02): A B => A+B
+ Pop two integers from the stack, and push their sum, as an integer.
+
+`sub' (0x03): A B => A-B
+ Pop two integers from the stack, subtract the top value from the
+ next-to-top value, and push the difference.
+
+`mul' (0x04): A B => A*B
+ Pop two integers from the stack, multiply them, and push the
+ product on the stack. Note that, when one multiplies two N-bit
+ numbers yielding another N-bit number, it is irrelevant whether the
+ numbers are signed or not; the results are the same.
+
+`div_signed' (0x05): A B => A/B
+ Pop two signed integers from the stack; divide the next-to-top
+ value by the top value, and push the quotient. If the divisor is
+ zero, terminate with an error.
+
+`div_unsigned' (0x06): A B => A/B
+ Pop two unsigned integers from the stack; divide the next-to-top
+ value by the top value, and push the quotient. If the divisor is
+ zero, terminate with an error.
+
+`rem_signed' (0x07): A B => A MODULO B
+ Pop two signed integers from the stack; divide the next-to-top
+ value by the top value, and push the remainder. If the divisor is
+ zero, terminate with an error.
+
+`rem_unsigned' (0x08): A B => A MODULO B
+ Pop two unsigned integers from the stack; divide the next-to-top
+ value by the top value, and push the remainder. If the divisor is
+ zero, terminate with an error.
+
+`lsh' (0x09): A B => A<<B
+ Pop two integers from the stack; let A be the next-to-top value,
+ and B be the top value. Shift A left by B bits, and push the
+ result.
+
+`rsh_signed' (0x0a): A B => `(signed)'A>>B
+ Pop two integers from the stack; let A be the next-to-top value,
+ and B be the top value. Shift A right by B bits, inserting copies
+ of the top bit at the high end, and push the result.
+
+`rsh_unsigned' (0x0b): A B => A>>B
+ Pop two integers from the stack; let A be the next-to-top value,
+ and B be the top value. Shift A right by B bits, inserting zero
+ bits at the high end, and push the result.
+
+`log_not' (0x0e): A => !A
+ Pop an integer from the stack; if it is zero, push the value one;
+ otherwise, push the value zero.
+
+`bit_and' (0x0f): A B => A&B
+ Pop two integers from the stack, and push their bitwise `and'.
+
+`bit_or' (0x10): A B => A|B
+ Pop two integers from the stack, and push their bitwise `or'.
+
+`bit_xor' (0x11): A B => A^B
+ Pop two integers from the stack, and push their bitwise
+ exclusive-`or'.
+
+`bit_not' (0x12): A => ~A
+ Pop an integer from the stack, and push its bitwise complement.
+
+`equal' (0x13): A B => A=B
+ Pop two integers from the stack; if they are equal, push the value
+ one; otherwise, push the value zero.
+
+`less_signed' (0x14): A B => A<B
+ Pop two signed integers from the stack; if the next-to-top value
+ is less than the top value, push the value one; otherwise, push
+ the value zero.
+
+`less_unsigned' (0x15): A B => A<B
+ Pop two unsigned integers from the stack; if the next-to-top value
+ is less than the top value, push the value one; otherwise, push
+ the value zero.
+
+`ext' (0x16) N: A => A, sign-extended from N bits
+ Pop an unsigned value from the stack; treating it as an N-bit
+ twos-complement value, extend it to full length. This means that
+ all bits to the left of bit N-1 (where the least significant bit
+ is bit 0) are set to the value of bit N-1. Note that N may be
+ larger than or equal to the width of the stack elements of the
+ bytecode engine; in this case, the bytecode should have no effect.
+
+ The number of source bits to preserve, N, is encoded as a single
+ byte unsigned integer following the `ext' bytecode.
+
+`zero_ext' (0x2a) N: A => A, zero-extended from N bits
+ Pop an unsigned value from the stack; zero all but the bottom N
+ bits. This means that all bits to the left of bit N-1 (where the
+ least significant bit is bit 0) are set to the value of bit N-1.
+
+ The number of source bits to preserve, N, is encoded as a single
+ byte unsigned integer following the `zero_ext' bytecode.
+
+`ref8' (0x17): ADDR => A
+`ref16' (0x18): ADDR => A
+`ref32' (0x19): ADDR => A
+`ref64' (0x1a): ADDR => A
+ Pop an address ADDR from the stack. For bytecode `ref'N, fetch an
+ N-bit value from ADDR, using the natural target endianness. Push
+ the fetched value as an unsigned integer.
+
+ Note that ADDR may not be aligned in any particular way; the
+ `refN' bytecodes should operate correctly for any address.
+
+ If attempting to access memory at ADDR would cause a processor
+ exception of some sort, terminate with an error.
+
+`ref_float' (0x1b): ADDR => D
+`ref_double' (0x1c): ADDR => D
+`ref_long_double' (0x1d): ADDR => D
+`l_to_d' (0x1e): A => D
+`d_to_l' (0x1f): D => A
+ Not implemented yet.
+
+`dup' (0x28): A => A A
+ Push another copy of the stack's top element.
+
+`swap' (0x2b): A B => B A
+ Exchange the top two items on the stack.
+
+`pop' (0x29): A =>
+ Discard the top value on the stack.
+
+`if_goto' (0x20) OFFSET: A =>
+ Pop an integer off the stack; if it is non-zero, branch to the
+ given offset in the bytecode string. Otherwise, continue to the
+ next instruction in the bytecode stream. In other words, if A is
+ non-zero, set the `pc' register to `start' + OFFSET. Thus, an
+ offset of zero denotes the beginning of the expression.
+
+ The OFFSET is stored as a sixteen-bit unsigned value, stored
+ immediately following the `if_goto' bytecode. It is always stored
+ most significant byte first, regardless of the target's normal
+ endianness. The offset is not guaranteed to fall at any particular
+ alignment within the bytecode stream; thus, on machines where
+ fetching a 16-bit on an unaligned address raises an exception, you
+ should fetch the offset one byte at a time.
+
+`goto' (0x21) OFFSET: =>
+ Branch unconditionally to OFFSET; in other words, set the `pc'
+ register to `start' + OFFSET.
+
+ The offset is stored in the same way as for the `if_goto' bytecode.
+
+`const8' (0x22) N: => N
+`const16' (0x23) N: => N
+`const32' (0x24) N: => N
+`const64' (0x25) N: => N
+ Push the integer constant N on the stack, without sign extension.
+ To produce a small negative value, push a small twos-complement
+ value, and then sign-extend it using the `ext' bytecode.
+
+ The constant N is stored in the appropriate number of bytes
+ following the `const'B bytecode. The constant N is always stored
+ most significant byte first, regardless of the target's normal
+ endianness. The constant is not guaranteed to fall at any
+ particular alignment within the bytecode stream; thus, on machines
+ where fetching a 16-bit on an unaligned address raises an
+ exception, you should fetch N one byte at a time.
+
+`reg' (0x26) N: => A
+ Push the value of register number N, without sign extension. The
+ registers are numbered following GDB's conventions.
+
+ The register number N is encoded as a 16-bit unsigned integer
+ immediately following the `reg' bytecode. It is always stored most
+ significant byte first, regardless of the target's normal
+ endianness. The register number is not guaranteed to fall at any
+ particular alignment within the bytecode stream; thus, on machines
+ where fetching a 16-bit on an unaligned address raises an
+ exception, you should fetch the register number one byte at a time.
+
+`trace' (0x0c): ADDR SIZE =>
+ Record the contents of the SIZE bytes at ADDR in a trace buffer,
+ for later retrieval by GDB.
+
+`trace_quick' (0x0d) SIZE: ADDR => ADDR
+ Record the contents of the SIZE bytes at ADDR in a trace buffer,
+ for later retrieval by GDB. SIZE is a single byte unsigned
+ integer following the `trace' opcode.
+
+ This bytecode is equivalent to the sequence `dup const8 SIZE
+ trace', but we provide it anyway to save space in bytecode strings.
+
+`trace16' (0x30) SIZE: ADDR => ADDR
+ Identical to trace_quick, except that SIZE is a 16-bit big-endian
+ unsigned integer, not a single byte. This should probably have
+ been named `trace_quick16', for consistency.
+
+`end' (0x27): =>
+ Stop executing bytecode; the result should be the top element of
+ the stack. If the purpose of the expression was to compute an
+ lvalue or a range of memory, then the next-to-top of the stack is
+ the lvalue's address, and the top of the stack is the lvalue's
+ size, in bytes.
+
+
+
+File: gdb.info, Node: Using Agent Expressions, Next: Varying Target Capabilities, Prev: Bytecode Descriptions, Up: Agent Expressions
+
+Using Agent Expressions
+=======================
+
+Here is a sketch of a full non-stop debugging cycle, showing how agent
+expressions fit into the process.
+
+ * The user selects trace points in the program's code at which GDB
+ should collect data.
+
+ * The user specifies expressions to evaluate at each trace point.
+ These expressions may denote objects in memory, in which case
+ those objects' contents are recorded as the program runs, or
+ computed values, in which case the values themselves are recorded.
+
+ * GDB transmits the tracepoints and their associated expressions to
+ the GDB agent, running on the debugging target.
+
+ * The agent arranges to be notified when a trace point is hit. Note
+ that, on some systems, the target operating system is completely
+ responsible for collecting the data; see *Note Tracing on
+ Symmetrix::.
+
+ * When execution on the target reaches a trace point, the agent
+ evaluates the expressions associated with that trace point, and
+ records the resulting values and memory ranges.
+
+ * Later, when the user selects a given trace event and inspects the
+ objects and expression values recorded, GDB talks to the agent to
+ retrieve recorded data as necessary to meet the user's requests.
+ If the user asks to see an object whose contents have not been
+ recorded, GDB reports an error.
+
+
+
+File: gdb.info, Node: Varying Target Capabilities, Next: Tracing on Symmetrix, Prev: Using Agent Expressions, Up: Agent Expressions
+
+Varying Target Capabilities
+===========================
+
+Some targets don't support floating-point, and some would rather not
+have to deal with `long long' operations. Also, different targets will
+have different stack sizes, and different bytecode buffer lengths.
+
+ Thus, GDB needs a way to ask the target about itself. We haven't
+worked out the details yet, but in general, GDB should be able to send
+the target a packet asking it to describe itself. The reply should be a
+packet whose length is explicit, so we can add new information to the
+packet in future revisions of the agent, without confusing old versions
+of GDB, and it should contain a version number. It should contain at
+least the following information:
+
+ * whether floating point is supported
+
+ * whether `long long' is supported
+
+ * maximum acceptable size of bytecode stack
+
+ * maximum acceptable length of bytecode expressions
+
+ * which registers are actually available for collection
+
+ * whether the target supports disabled tracepoints
+
+
+
+File: gdb.info, Node: Tracing on Symmetrix, Next: Rationale, Prev: Varying Target Capabilities, Up: Agent Expressions
+
+Tracing on Symmetrix
+====================
+
+This section documents the API used by the GDB agent to collect data on
+Symmetrix systems.
+
+ Cygnus originally implemented these tracing features to help EMC
+Corporation debug their Symmetrix high-availability disk drives. The
+Symmetrix application code already includes substantial tracing
+facilities; the GDB agent for the Symmetrix system uses those facilities
+for its own data collection, via the API described here.
+
+ - Function: DTC_RESPONSE adbg_find_memory_in_frame (FRAME_DEF *FRAME,
+ char *ADDRESS, char **BUFFER, unsigned int *SIZE)
+ Search the trace frame FRAME for memory saved from ADDRESS. If
+ the memory is available, provide the address of the buffer holding
+ it; otherwise, provide the address of the next saved area.
+
+ * If the memory at ADDRESS was saved in FRAME, set `*BUFFER' to
+ point to the buffer in which that memory was saved, set
+ `*SIZE' to the number of bytes from ADDRESS that are saved at
+ `*BUFFER', and return `OK_TARGET_RESPONSE'. (Clearly, in
+ this case, the function will always set `*SIZE' to a value
+ greater than zero.)
+
+ * If FRAME does not record any memory at ADDRESS, set `*SIZE'
+ to the distance from ADDRESS to the start of the saved region
+ with the lowest address higher than ADDRESS. If there is no
+ memory saved from any higher address, set `*SIZE' to zero.
+ Return `NOT_FOUND_TARGET_RESPONSE'.
+
+ These two possibilities allow the caller to either retrieve the
+ data, or walk the address space to the next saved area.
+
+ This function allows the GDB agent to map the regions of memory
+saved in a particular frame, and retrieve their contents efficiently.
+
+ This function also provides a clean interface between the GDB agent
+and the Symmetrix tracing structures, making it easier to adapt the GDB
+agent to future versions of the Symmetrix system, and vice versa. This
+function searches all data saved in FRAME, whether the data is there at
+the request of a bytecode expression, or because it falls in one of the
+format's memory ranges, or because it was saved from the top of the
+stack. EMC can arbitrarily change and enhance the tracing mechanism,
+but as long as this function works properly, all collected memory is
+visible to GDB.
+
+ The function itself is straightforward to implement. A single pass
+over the trace frame's stack area, memory ranges, and expression blocks
+can yield the address of the buffer (if the requested address was
+saved), and also note the address of the next higher range of memory,
+to be returned when the search fails.
+
+ As an example, suppose the trace frame `f' has saved sixteen bytes
+from address `0x8000' in a buffer at `0x1000', and thirty-two bytes
+from address `0xc000' in a buffer at `0x1010'. Here are some sample
+calls, and the effect each would have:
+
+`adbg_find_memory_in_frame (f, (char*) 0x8000, &buffer, &size)'
+ This would set `buffer' to `0x1000', set `size' to sixteen, and
+ return `OK_TARGET_RESPONSE', since `f' saves sixteen bytes from
+ `0x8000' at `0x1000'.
+
+`adbg_find_memory_in_frame (f, (char *) 0x8004, &buffer, &size)'
+ This would set `buffer' to `0x1004', set `size' to twelve, and
+ return `OK_TARGET_RESPONSE', since `f' saves the twelve bytes from
+ `0x8004' starting four bytes into the buffer at `0x1000'. This
+ shows that request addresses may fall in the middle of saved
+ areas; the function should return the address and size of the
+ remainder of the buffer.
+
+`adbg_find_memory_in_frame (f, (char *) 0x8100, &buffer, &size)'
+ This would set `size' to `0x3f00' and return
+ `NOT_FOUND_TARGET_RESPONSE', since there is no memory saved in `f'
+ from the address `0x8100', and the next memory available is at
+ `0x8100 + 0x3f00', or `0xc000'. This shows that request addresses
+ may fall outside of all saved memory ranges; the function should
+ indicate the next saved area, if any.
+
+`adbg_find_memory_in_frame (f, (char *) 0x7000, &buffer, &size)'
+ This would set `size' to `0x1000' and return
+ `NOT_FOUND_TARGET_RESPONSE', since the next saved memory is at
+ `0x7000 + 0x1000', or `0x8000'.
+
+`adbg_find_memory_in_frame (f, (char *) 0xf000, &buffer, &size)'
+ This would set `size' to zero, and return
+ `NOT_FOUND_TARGET_RESPONSE'. This shows how the function tells the
+ caller that no further memory ranges have been saved.
+
+
+ As another example, here is a function which will print out the
+addresses of all memory saved in the trace frame `frame' on the
+Symmetrix INLINES console:
+ void
+ print_frame_addresses (FRAME_DEF *frame)
+ {
+ char *addr;
+ char *buffer;
+ unsigned long size;
+
+ addr = 0;
+ for (;;)
+ {
+ /* Either find out how much memory we have here, or discover
+ where the next saved region is. */
+ if (adbg_find_memory_in_frame (frame, addr, &buffer, &size)
+ == OK_TARGET_RESPONSE)
+ printp ("saved %x to %x\n", addr, addr + size);
+ if (size == 0)
+ break;
+ addr += size;
+ }
+ }
+
+ Note that there is not necessarily any connection between the order
+in which the data is saved in the trace frame, and the order in which
+`adbg_find_memory_in_frame' will return those memory ranges. The code
+above will always print the saved memory regions in order of increasing
+address, while the underlying frame structure might store the data in a
+random order.
+
+ [[This section should cover the rest of the Symmetrix functions the
+stub relies upon, too.]]
+
+
+File: gdb.info, Node: Rationale, Prev: Tracing on Symmetrix, Up: Agent Expressions
+
+Rationale
+=========
+
+Some of the design decisions apparent above are arguable.
+
+What about stack overflow/underflow?
+ GDB should be able to query the target to discover its stack size.
+ Given that information, GDB can determine at translation time
+ whether a given expression will overflow the stack. But this spec
+ isn't about what kinds of error-checking GDB ought to do.
+
+Why are you doing everything in LONGEST?
+ Speed isn't important, but agent code size is; using LONGEST
+ brings in a bunch of support code to do things like division, etc.
+ So this is a serious concern.
+
+ First, note that you don't need different bytecodes for different
+ operand sizes. You can generate code without _knowing_ how big the
+ stack elements actually are on the target. If the target only
+ supports 32-bit ints, and you don't send any 64-bit bytecodes,
+ everything just works. The observation here is that the MIPS and
+ the Alpha have only fixed-size registers, and you can still get
+ C's semantics even though most instructions only operate on
+ full-sized words. You just need to make sure everything is
+ properly sign-extended at the right times. So there is no need
+ for 32- and 64-bit variants of the bytecodes. Just implement
+ everything using the largest size you support.
+
+ GDB should certainly check to see what sizes the target supports,
+ so the user can get an error earlier, rather than later. But this
+ information is not necessary for correctness.
+
+Why don't you have `>' or `<=' operators?
+ I want to keep the interpreter small, and we don't need them. We
+ can combine the `less_' opcodes with `log_not', and swap the order
+ of the operands, yielding all four asymmetrical comparison
+ operators. For example, `(x <= y)' is `! (x > y)', which is `! (y
+ < x)'.
+
+Why do you have `log_not'?
+Why do you have `ext'?
+Why do you have `zero_ext'?
+ These are all easily synthesized from other instructions, but I
+ expect them to be used frequently, and they're simple, so I
+ include them to keep bytecode strings short.
+
+ `log_not' is equivalent to `const8 0 equal'; it's used in half the
+ relational operators.
+
+ `ext N' is equivalent to `const8 S-N lsh const8 S-N rsh_signed',
+ where S is the size of the stack elements; it follows `refM' and
+ REG bytecodes when the value should be signed. See the next
+ bulleted item.
+
+ `zero_ext N' is equivalent to `constM MASK log_and'; it's used
+ whenever we push the value of a register, because we can't assume
+ the upper bits of the register aren't garbage.
+
+Why not have sign-extending variants of the `ref' operators?
+ Because that would double the number of `ref' operators, and we
+ need the `ext' bytecode anyway for accessing bitfields.
+
+Why not have constant-address variants of the `ref' operators?
+ Because that would double the number of `ref' operators again, and
+ `const32 ADDRESS ref32' is only one byte longer.
+
+Why do the `refN' operators have to support unaligned fetches?
+ GDB will generate bytecode that fetches multi-byte values at
+ unaligned addresses whenever the executable's debugging
+ information tells it to. Furthermore, GDB does not know the value
+ the pointer will have when GDB generates the bytecode, so it
+ cannot determine whether a particular fetch will be aligned or not.
+
+ In particular, structure bitfields may be several bytes long, but
+ follow no alignment rules; members of packed structures are not
+ necessarily aligned either.
+
+ In general, there are many cases where unaligned references occur
+ in correct C code, either at the programmer's explicit request, or
+ at the compiler's discretion. Thus, it is simpler to make the GDB
+ agent bytecodes work correctly in all circumstances than to make
+ GDB guess in each case whether the compiler did the usual thing.
+
+Why are there no side-effecting operators?
+ Because our current client doesn't want them? That's a cheap
+ answer. I think the real answer is that I'm afraid of
+ implementing function calls. We should re-visit this issue after
+ the present contract is delivered.
+
+Why aren't the `goto' ops PC-relative?
+ The interpreter has the base address around anyway for PC bounds
+ checking, and it seemed simpler.
+
+Why is there only one offset size for the `goto' ops?
+ Offsets are currently sixteen bits. I'm not happy with this
+ situation either:
+
+ Suppose we have multiple branch ops with different offset sizes.
+ As I generate code left-to-right, all my jumps are forward jumps
+ (there are no loops in expressions), so I never know the target
+ when I emit the jump opcode. Thus, I have to either always assume
+ the largest offset size, or do jump relaxation on the code after I
+ generate it, which seems like a big waste of time.
+
+ I can imagine a reasonable expression being longer than 256 bytes.
+ I can't imagine one being longer than 64k. Thus, we need 16-bit
+ offsets. This kind of reasoning is so bogus, but relaxation is
+ pathetic.
+
+ The other approach would be to generate code right-to-left. Then
+ I'd always know my offset size. That might be fun.
+
+Where is the function call bytecode?
+ When we add side-effects, we should add this.
+
+Why does the `reg' bytecode take a 16-bit register number?
+ Intel's IA-64 architecture has 128 general-purpose registers, and
+ 128 floating-point registers, and I'm sure it has some random
+ control registers.
+
+Why do we need `trace' and `trace_quick'?
+ Because GDB needs to record all the memory contents and registers
+ an expression touches. If the user wants to evaluate an expression
+ `x->y->z', the agent must record the values of `x' and `x->y' as
+ well as the value of `x->y->z'.
+
+Don't the `trace' bytecodes make the interpreter less general?
+ They do mean that the interpreter contains special-purpose code,
+ but that doesn't mean the interpreter can only be used for that
+ purpose. If an expression doesn't use the `trace' bytecodes, they
+ don't get in its way.
+
+Why doesn't `trace_quick' consume its arguments the way everything else does?
+ In general, you do want your operators to consume their arguments;
+ it's consistent, and generally reduces the amount of stack
+ rearrangement necessary. However, `trace_quick' is a kludge to
+ save space; it only exists so we needn't write `dup const8 SIZE
+ trace' before every memory reference. Therefore, it's okay for it
+ not to consume its arguments; it's meant for a specific context in
+ which we know exactly what it should do with the stack. If we're
+ going to have a kludge, it should be an effective kludge.
+
+Why does `trace16' exist?
+ That opcode was added by the customer that contracted Cygnus for
+ the data tracing work. I personally think it is unnecessary;
+ objects that large will be quite rare, so it is okay to use `dup
+ const16 SIZE trace' in those cases.
+
+ Whatever we decide to do with `trace16', we should at least leave
+ opcode 0x30 reserved, to remain compatible with the customer who
+ added it.
+
+
+
+File: gdb.info, Node: Copying, Next: GNU Free Documentation License, Prev: Agent Expressions, Up: Top
+
+GNU GENERAL PUBLIC LICENSE
+**************************
+
+ Version 2, June 1991
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.
+
+ 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
+
+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.
+
+ ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES.
+ Copyright (C) YEAR NAME OF AUTHOR
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, 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) YEAR 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.
+
+ SIGNATURE OF TY COON, 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.
+
+
+File: gdb.info, Node: GNU Free Documentation License, Next: Index, Prev: Copying, Up: Top
+
+GNU Free Documentation License
+******************************
+
+ Version 1.2, November 2002
+ Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ 0. PREAMBLE
+
+ The purpose of this License is to make a manual, textbook, or other
+ functional and useful document "free" in the sense of freedom: to
+ assure everyone the effective freedom to copy and redistribute it,
+ with or without modifying it, either commercially or
+ noncommercially. Secondarily, this License preserves for the
+ author and publisher a way to get credit for their work, while not
+ being considered responsible for modifications made by others.
+
+ This License is a kind of "copyleft", which means that derivative
+ works of the document must themselves be free in the same sense.
+ It complements the GNU General Public License, which is a copyleft
+ license designed for free software.
+
+ We have designed this License in order to use it for manuals for
+ free software, because free software needs free documentation: a
+ free program should come with manuals providing the same freedoms
+ that the software does. But this License is not limited to
+ software manuals; it can be used for any textual work, regardless
+ of subject matter or whether it is published as a printed book.
+ We recommend this License principally for works whose purpose is
+ instruction or reference.
+
+ 1. APPLICABILITY AND DEFINITIONS
+
+ This License applies to any manual or other work, in any medium,
+ that contains a notice placed by the copyright holder saying it
+ can be distributed under the terms of this License. Such a notice
+ grants a world-wide, royalty-free license, unlimited in duration,
+ to use that work under the conditions stated herein. The
+ "Document", below, refers to any such manual or work. Any member
+ of the public is a licensee, and is addressed as "you". You
+ accept the license if you copy, modify or distribute the work in a
+ way requiring permission under copyright law.
+
+ A "Modified Version" of the Document means any work containing the
+ Document or a portion of it, either copied verbatim, or with
+ modifications and/or translated into another language.
+
+ A "Secondary Section" is a named appendix or a front-matter section
+ of the Document that deals exclusively with the relationship of the
+ publishers or authors of the Document to the Document's overall
+ subject (or to related matters) and contains nothing that could
+ fall directly within that overall subject. (Thus, if the Document
+ is in part a textbook of mathematics, a Secondary Section may not
+ explain any mathematics.) The relationship could be a matter of
+ historical connection with the subject or with related matters, or
+ of legal, commercial, philosophical, ethical or political position
+ regarding them.
+
+ The "Invariant Sections" are certain Secondary Sections whose
+ titles are designated, as being those of Invariant Sections, in
+ the notice that says that the Document is released under this
+ License. If a section does not fit the above definition of
+ Secondary then it is not allowed to be designated as Invariant.
+ The Document may contain zero Invariant Sections. If the Document
+ does not identify any Invariant Sections then there are none.
+
+ The "Cover Texts" are certain short passages of text that are
+ listed, as Front-Cover Texts or Back-Cover Texts, in the notice
+ that says that the Document is released under this License. A
+ Front-Cover Text may be at most 5 words, and a Back-Cover Text may
+ be at most 25 words.
+
+ A "Transparent" copy of the Document means a machine-readable copy,
+ represented in a format whose specification is available to the
+ general public, that is suitable for revising the document
+ straightforwardly with generic text editors or (for images
+ composed of pixels) generic paint programs or (for drawings) some
+ widely available drawing editor, and that is suitable for input to
+ text formatters or for automatic translation to a variety of
+ formats suitable for input to text formatters. A copy made in an
+ otherwise Transparent file format whose markup, or absence of
+ markup, has been arranged to thwart or discourage subsequent
+ modification by readers is not Transparent. An image format is
+ not Transparent if used for any substantial amount of text. A
+ copy that is not "Transparent" is called "Opaque".
+
+ Examples of suitable formats for Transparent copies include plain
+ ASCII without markup, Texinfo input format, LaTeX input format,
+ SGML or XML using a publicly available DTD, and
+ standard-conforming simple HTML, PostScript or PDF designed for
+ human modification. Examples of transparent image formats include
+ PNG, XCF and JPG. Opaque formats include proprietary formats that
+ can be read and edited only by proprietary word processors, SGML or
+ XML for which the DTD and/or processing tools are not generally
+ available, and the machine-generated HTML, PostScript or PDF
+ produced by some word processors for output purposes only.
+
+ The "Title Page" means, for a printed book, the title page itself,
+ plus such following pages as are needed to hold, legibly, the
+ material this License requires to appear in the title page. For
+ works in formats which do not have any title page as such, "Title
+ Page" means the text near the most prominent appearance of the
+ work's title, preceding the beginning of the body of the text.
+
+ A section "Entitled XYZ" means a named subunit of the Document
+ whose title either is precisely XYZ or contains XYZ in parentheses
+ following text that translates XYZ in another language. (Here XYZ
+ stands for a specific section name mentioned below, such as
+ "Acknowledgements", "Dedications", "Endorsements", or "History".)
+ To "Preserve the Title" of such a section when you modify the
+ Document means that it remains a section "Entitled XYZ" according
+ to this definition.
+
+ The Document may include Warranty Disclaimers next to the notice
+ which states that this License applies to the Document. These
+ Warranty Disclaimers are considered to be included by reference in
+ this License, but only as regards disclaiming warranties: any other
+ implication that these Warranty Disclaimers may have is void and
+ has no effect on the meaning of this License.
+
+ 2. VERBATIM COPYING
+
+ You may copy and distribute the Document in any medium, either
+ commercially or noncommercially, provided that this License, the
+ copyright notices, and the license notice saying this License
+ applies to the Document are reproduced in all copies, and that you
+ add no other conditions whatsoever to those of this License. You
+ may not use technical measures to obstruct or control the reading
+ or further copying of the copies you make or distribute. However,
+ you may accept compensation in exchange for copies. If you
+ distribute a large enough number of copies you must also follow
+ the conditions in section 3.
+
+ You may also lend copies, under the same conditions stated above,
+ and you may publicly display copies.
+
+ 3. COPYING IN QUANTITY
+
+ If you publish printed copies (or copies in media that commonly
+ have printed covers) of the Document, numbering more than 100, and
+ the Document's license notice requires Cover Texts, you must
+ enclose the copies in covers that carry, clearly and legibly, all
+ these Cover Texts: Front-Cover Texts on the front cover, and
+ Back-Cover Texts on the back cover. Both covers must also clearly
+ and legibly identify you as the publisher of these copies. The
+ front cover must present the full title with all words of the
+ title equally prominent and visible. You may add other material
+ on the covers in addition. Copying with changes limited to the
+ covers, as long as they preserve the title of the Document and
+ satisfy these conditions, can be treated as verbatim copying in
+ other respects.
+
+ If the required texts for either cover are too voluminous to fit
+ legibly, you should put the first ones listed (as many as fit
+ reasonably) on the actual cover, and continue the rest onto
+ adjacent pages.
+
+ If you publish or distribute Opaque copies of the Document
+ numbering more than 100, you must either include a
+ machine-readable Transparent copy along with each Opaque copy, or
+ state in or with each Opaque copy a computer-network location from
+ which the general network-using public has access to download
+ using public-standard network protocols a complete Transparent
+ copy of the Document, free of added material. If you use the
+ latter option, you must take reasonably prudent steps, when you
+ begin distribution of Opaque copies in quantity, to ensure that
+ this Transparent copy will remain thus accessible at the stated
+ location until at least one year after the last time you
+ distribute an Opaque copy (directly or through your agents or
+ retailers) of that edition to the public.
+
+ It is requested, but not required, that you contact the authors of
+ the Document well before redistributing any large number of
+ copies, to give them a chance to provide you with an updated
+ version of the Document.
+
+ 4. MODIFICATIONS
+
+ You may copy and distribute a Modified Version of the Document
+ under the conditions of sections 2 and 3 above, provided that you
+ release the Modified Version under precisely this License, with
+ the Modified Version filling the role of the Document, thus
+ licensing distribution and modification of the Modified Version to
+ whoever possesses a copy of it. In addition, you must do these
+ things in the Modified Version:
+
+ A. Use in the Title Page (and on the covers, if any) a title
+ distinct from that of the Document, and from those of
+ previous versions (which should, if there were any, be listed
+ in the History section of the Document). You may use the
+ same title as a previous version if the original publisher of
+ that version gives permission.
+
+ B. List on the Title Page, as authors, one or more persons or
+ entities responsible for authorship of the modifications in
+ the Modified Version, together with at least five of the
+ principal authors of the Document (all of its principal
+ authors, if it has fewer than five), unless they release you
+ from this requirement.
+
+ C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+
+ D. Preserve all the copyright notices of the Document.
+
+ E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+
+ F. Include, immediately after the copyright notices, a license
+ notice giving the public permission to use the Modified
+ Version under the terms of this License, in the form shown in
+ the Addendum below.
+
+ G. Preserve in that license notice the full lists of Invariant
+ Sections and required Cover Texts given in the Document's
+ license notice.
+
+ H. Include an unaltered copy of this License.
+
+ I. Preserve the section Entitled "History", Preserve its Title,
+ and add to it an item stating at least the title, year, new
+ authors, and publisher of the Modified Version as given on
+ the Title Page. If there is no section Entitled "History" in
+ the Document, create one stating the title, year, authors,
+ and publisher of the Document as given on its Title Page,
+ then add an item describing the Modified Version as stated in
+ the previous sentence.
+
+ J. Preserve the network location, if any, given in the Document
+ for public access to a Transparent copy of the Document, and
+ likewise the network locations given in the Document for
+ previous versions it was based on. These may be placed in
+ the "History" section. You may omit a network location for a
+ work that was published at least four years before the
+ Document itself, or if the original publisher of the version
+ it refers to gives permission.
+
+ K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the
+ section all the substance and tone of each of the contributor
+ acknowledgements and/or dedications given therein.
+
+ L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section
+ titles.
+
+ M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+
+ N. Do not retitle any existing section to be Entitled
+ "Endorsements" or to conflict in title with any Invariant
+ Section.
+
+ O. Preserve any Warranty Disclaimers.
+
+ If the Modified Version includes new front-matter sections or
+ appendices that qualify as Secondary Sections and contain no
+ material copied from the Document, you may at your option
+ designate some or all of these sections as invariant. To do this,
+ add their titles to the list of Invariant Sections in the Modified
+ Version's license notice. These titles must be distinct from any
+ other section titles.
+
+ You may add a section Entitled "Endorsements", provided it contains
+ nothing but endorsements of your Modified Version by various
+ parties--for example, statements of peer review or that the text
+ has been approved by an organization as the authoritative
+ definition of a standard.
+
+ You may add a passage of up to five words as a Front-Cover Text,
+ and a passage of up to 25 words as a Back-Cover Text, to the end
+ of the list of Cover Texts in the Modified Version. Only one
+ passage of Front-Cover Text and one of Back-Cover Text may be
+ added by (or through arrangements made by) any one entity. If the
+ Document already includes a cover text for the same cover,
+ previously added by you or by arrangement made by the same entity
+ you are acting on behalf of, you may not add another; but you may
+ replace the old one, on explicit permission from the previous
+ publisher that added the old one.
+
+ The author(s) and publisher(s) of the Document do not by this
+ License give permission to use their names for publicity for or to
+ assert or imply endorsement of any Modified Version.
+
+ 5. COMBINING DOCUMENTS
+
+ You may combine the Document with other documents released under
+ this License, under the terms defined in section 4 above for
+ modified versions, provided that you include in the combination
+ all of the Invariant Sections of all of the original documents,
+ unmodified, and list them all as Invariant Sections of your
+ combined work in its license notice, and that you preserve all
+ their Warranty Disclaimers.
+
+ The combined work need only contain one copy of this License, and
+ multiple identical Invariant Sections may be replaced with a single
+ copy. If there are multiple Invariant Sections with the same name
+ but different contents, make the title of each such section unique
+ by adding at the end of it, in parentheses, the name of the
+ original author or publisher of that section if known, or else a
+ unique number. Make the same adjustment to the section titles in
+ the list of Invariant Sections in the license notice of the
+ combined work.
+
+ In the combination, you must combine any sections Entitled
+ "History" in the various original documents, forming one section
+ Entitled "History"; likewise combine any sections Entitled
+ "Acknowledgements", and any sections Entitled "Dedications". You
+ must delete all sections Entitled "Endorsements."
+
+ 6. COLLECTIONS OF DOCUMENTS
+
+ You may make a collection consisting of the Document and other
+ documents released under this License, and replace the individual
+ copies of this License in the various documents with a single copy
+ that is included in the collection, provided that you follow the
+ rules of this License for verbatim copying of each of the
+ documents in all other respects.
+
+ You may extract a single document from such a collection, and
+ distribute it individually under this License, provided you insert
+ a copy of this License into the extracted document, and follow
+ this License in all other respects regarding verbatim copying of
+ that document.
+
+ 7. AGGREGATION WITH INDEPENDENT WORKS
+
+ A compilation of the Document or its derivatives with other
+ separate and independent documents or works, in or on a volume of
+ a storage or distribution medium, is called an "aggregate" if the
+ copyright resulting from the compilation is not used to limit the
+ legal rights of the compilation's users beyond what the individual
+ works permit. When the Document is included in an aggregate, this
+ License does not apply to the other works in the aggregate which
+ are not themselves derivative works of the Document.
+
+ If the Cover Text requirement of section 3 is applicable to these
+ copies of the Document, then if the Document is less than one half
+ of the entire aggregate, the Document's Cover Texts may be placed
+ on covers that bracket the Document within the aggregate, or the
+ electronic equivalent of covers if the Document is in electronic
+ form. Otherwise they must appear on printed covers that bracket
+ the whole aggregate.
+
+ 8. TRANSLATION
+
+ Translation is considered a kind of modification, so you may
+ distribute translations of the Document under the terms of section
+ 4. Replacing Invariant Sections with translations requires special
+ permission from their copyright holders, but you may include
+ translations of some or all Invariant Sections in addition to the
+ original versions of these Invariant Sections. You may include a
+ translation of this License, and all the license notices in the
+ Document, and any Warranty Disclaimers, provided that you also
+ include the original English version of this License and the
+ original versions of those notices and disclaimers. In case of a
+ disagreement between the translation and the original version of
+ this License or a notice or disclaimer, the original version will
+ prevail.
+
+ If a section in the Document is Entitled "Acknowledgements",
+ "Dedications", or "History", the requirement (section 4) to
+ Preserve its Title (section 1) will typically require changing the
+ actual title.
+
+ 9. TERMINATION
+
+ You may not copy, modify, sublicense, or distribute the Document
+ except as expressly provided for under this License. Any other
+ attempt to copy, modify, sublicense or distribute the Document 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.
+
+ 10. FUTURE REVISIONS OF THIS LICENSE
+
+ The Free Software Foundation may publish new, revised versions of
+ the GNU Free Documentation 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. See
+ `http://www.gnu.org/copyleft/'.
+
+ Each version of the License is given a distinguishing version
+ number. If the Document specifies that a particular numbered
+ version of this License "or any later version" applies to it, you
+ have the option of following the terms and conditions either of
+ that specified version or of any later version that has been
+ published (not as a draft) by the Free Software Foundation. If
+ the Document does not specify a version number of this License,
+ you may choose any version ever published (not as a draft) by the
+ Free Software Foundation.
+
+ADDENDUM: How to use this License for your documents
+====================================================
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and license
+notices just after the title page:
+
+ Copyright (C) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ Texts. A copy of the license is included in the section entitled ``GNU
+ Free Documentation License''.
+
+ If you have Invariant Sections, Front-Cover Texts and Back-Cover
+Texts, replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with
+ the Front-Cover Texts being LIST, and with the Back-Cover Texts
+ being LIST.
+
+ If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+ If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License, to
+permit their use in free software.
+
+
+File: gdb.info, Node: Index, Prev: GNU Free Documentation License, Up: Top
+
+Index
+*****
+
+* Menu:
+
+* ! packet: Packets.
+* "No symbol "foo" in current context": Variables.
+* # (a comment): Command Syntax.
+* # in Modula-2: GDB/M2.
+* $: Value History.
+* $$: Value History.
+* $_ and info breakpoints: Set Breaks.
+* $_ and info line: Machine Code.
+* $_, $__, and value history: Memory.
+* $_, convenience variable: Convenience Vars.
+* $__, convenience variable: Convenience Vars.
+* $_exitcode, convenience variable: Convenience Vars.
+* $bpnum, convenience variable: Set Breaks.
+* $cdir, convenience variable: Source Path.
+* $cwdr, convenience variable: Source Path.
+* $tpnum: Create and Delete Tracepoints.
+* $trace_file: Tracepoint Variables.
+* $trace_frame: Tracepoint Variables.
+* $trace_func: Tracepoint Variables.
+* $trace_line: Tracepoint Variables.
+* $tracepoint: Tracepoint Variables.
+* --annotate: Mode Options.
+* --args: Mode Options.
+* --async: Mode Options.
+* --batch: Mode Options.
+* --baud: Mode Options.
+* --cd: Mode Options.
+* --command: File Options.
+* --core: File Options.
+* --directory: File Options.
+* --epoch: Mode Options.
+* --exec: File Options.
+* --fullname: Mode Options.
+* --interpreter: Mode Options.
+* --mapped: File Options.
+* --noasync: Mode Options.
+* --nowindows: Mode Options.
+* --nx: Mode Options.
+* --pid: File Options.
+* --quiet: Mode Options.
+* --readnow: File Options.
+* --se: File Options.
+* --silent: Mode Options.
+* --statistics: Mode Options.
+* --symbols: File Options.
+* --tty: Mode Options.
+* --tui: Mode Options.
+* --version: Mode Options.
+* --windows: Mode Options.
+* --write: Mode Options.
+* -b: Mode Options.
+* -break-after: GDB/MI Breakpoint Table Commands.
+* -break-condition: GDB/MI Breakpoint Table Commands.
+* -break-delete: GDB/MI Breakpoint Table Commands.
+* -break-disable: GDB/MI Breakpoint Table Commands.
+* -break-enable: GDB/MI Breakpoint Table Commands.
+* -break-info: GDB/MI Breakpoint Table Commands.
+* -break-insert: GDB/MI Breakpoint Table Commands.
+* -break-list: GDB/MI Breakpoint Table Commands.
+* -break-watch: GDB/MI Breakpoint Table Commands.
+* -c: File Options.
+* -d: File Options.
+* -data-disassemble: GDB/MI Data Manipulation.
+* -data-evaluate-expression: GDB/MI Data Manipulation.
+* -data-list-changed-registers: GDB/MI Data Manipulation.
+* -data-list-register-names: GDB/MI Data Manipulation.
+* -data-list-register-values: GDB/MI Data Manipulation.
+* -data-read-memory: GDB/MI Data Manipulation.
+* -display-delete: GDB/MI Data Manipulation.
+* -display-disable: GDB/MI Data Manipulation.
+* -display-enable: GDB/MI Data Manipulation.
+* -display-insert: GDB/MI Data Manipulation.
+* -display-list: GDB/MI Data Manipulation.
+* -e: File Options.
+* -environment-cd: GDB/MI Data Manipulation.
+* -environment-directory: GDB/MI Data Manipulation.
+* -environment-path: GDB/MI Data Manipulation.
+* -environment-pwd: GDB/MI Data Manipulation.
+* -exec-abort: GDB/MI Program Control.
+* -exec-arguments: GDB/MI Program Control.
+* -exec-continue: GDB/MI Program Control.
+* -exec-finish: GDB/MI Program Control.
+* -exec-interrupt: GDB/MI Program Control.
+* -exec-next: GDB/MI Program Control.
+* -exec-next-instruction: GDB/MI Program Control.
+* -exec-return: GDB/MI Program Control.
+* -exec-run: GDB/MI Program Control.
+* -exec-show-arguments: GDB/MI Program Control.
+* -exec-step: GDB/MI Program Control.
+* -exec-step-instruction: GDB/MI Program Control.
+* -exec-until: GDB/MI Program Control.
+* -f: Mode Options.
+* -file-exec-and-symbols: GDB/MI Program Control.
+* -file-exec-file: GDB/MI Program Control.
+* -file-list-exec-sections: GDB/MI Program Control.
+* -file-list-exec-source-file: GDB/MI Program Control.
+* -file-list-exec-source-files: GDB/MI Program Control.
+* -file-list-shared-libraries: GDB/MI Program Control.
+* -file-list-symbol-files: GDB/MI Program Control.
+* -file-symbol-file: GDB/MI Program Control.
+* -gdb-exit: GDB/MI Miscellaneous Commands.
+* -gdb-set: GDB/MI Miscellaneous Commands.
+* -gdb-show: GDB/MI Miscellaneous Commands.
+* -gdb-version: GDB/MI Miscellaneous Commands.
+* -interpreter-exec: GDB/MI Miscellaneous Commands.
+* -m: File Options.
+* -n: Mode Options.
+* -nw: Mode Options.
+* -p: File Options.
+* -q: Mode Options.
+* -r: File Options.
+* -s: File Options.
+* -stack-info-depth: GDB/MI Stack Manipulation.
+* -stack-info-frame: GDB/MI Stack Manipulation.
+* -stack-list-arguments: GDB/MI Stack Manipulation.
+* -stack-list-frames: GDB/MI Stack Manipulation.
+* -stack-list-locals: GDB/MI Stack Manipulation.
+* -stack-select-frame: GDB/MI Stack Manipulation.
+* -symbol-info-address: GDB/MI Symbol Query.
+* -symbol-info-file: GDB/MI Symbol Query.
+* -symbol-info-function: GDB/MI Symbol Query.
+* -symbol-info-line: GDB/MI Symbol Query.
+* -symbol-info-symbol: GDB/MI Symbol Query.
+* -symbol-list-functions: GDB/MI Symbol Query.
+* -symbol-list-lines: GDB/MI Symbol Query.
+* -symbol-list-types: GDB/MI Symbol Query.
+* -symbol-list-variables: GDB/MI Symbol Query.
+* -symbol-locate: GDB/MI Symbol Query.
+* -symbol-type: GDB/MI Symbol Query.
+* -t: Mode Options.
+* -target-attach: GDB/MI Target Manipulation.
+* -target-compare-sections: GDB/MI Target Manipulation.
+* -target-detach: GDB/MI Target Manipulation.
+* -target-disconnect: GDB/MI Target Manipulation.
+* -target-download: GDB/MI Target Manipulation.
+* -target-exec-status: GDB/MI Target Manipulation.
+* -target-list-available-targets: GDB/MI Target Manipulation.
+* -target-list-current-targets: GDB/MI Target Manipulation.
+* -target-list-parameters: GDB/MI Target Manipulation.
+* -target-select: GDB/MI Target Manipulation.
+* -thread-info: GDB/MI Thread Commands.
+* -thread-list-all-threads: GDB/MI Thread Commands.
+* -thread-list-ids: GDB/MI Thread Commands.
+* -thread-select: GDB/MI Thread Commands.
+* -var-assign: GDB/MI Variable Objects.
+* -var-create: GDB/MI Variable Objects.
+* -var-delete: GDB/MI Variable Objects.
+* -var-evaluate-expression: GDB/MI Variable Objects.
+* -var-info-expression: GDB/MI Variable Objects.
+* -var-info-num-children: GDB/MI Variable Objects.
+* -var-info-type: GDB/MI Variable Objects.
+* -var-list-children: GDB/MI Variable Objects.
+* -var-set-format: GDB/MI Variable Objects.
+* -var-show-attributes: GDB/MI Variable Objects.
+* -var-show-format: GDB/MI Variable Objects.
+* -var-update: GDB/MI Variable Objects.
+* -w: Mode Options.
+* -x: File Options.
+* ., Modula-2 scope operator: M2 Scope.
+* .debug subdirectories: Separate Debug Files.
+* .esgdbinit: Command Files.
+* .gdbinit: Command Files.
+* .gnu_debuglink sections: Separate Debug Files.
+* .o files, reading symbols from: Files.
+* .os68gdbinit: Command Files.
+* .vxgdbinit: Command Files.
+* /proc: SVR4 Process Information.
+* ? packet: Packets.
+* @, referencing memory as an array: Arrays.
+* ^done: GDB/MI Result Records.
+* ^error: GDB/MI Result Records.
+* ^running: GDB/MI Result Records.
+* _NSPrintForDebugger, and printing Objective-C objects: The Print Command with Objective-C.
+* A packet: Packets.
+* abbreviation: Command Syntax.
+* abort (C-g): Miscellaneous Commands.
+* accept-line (Newline or Return): Commands For History.
+* acknowledgment, for GDB remote: Overview.
+* actions: Tracepoint Actions.
+* active targets: Active Targets.
+* adbg_find_memory_in_frame: Tracing on Symmetrix.
+* add-shared-symbol-file: Files.
+* add-symbol-file: Files.
+* address of a symbol: Symbols.
+* advance LOCATION: Continuing and Stepping.
+* Alpha stack: MIPS.
+* AMD 29K register stack: A29K.
+* annotations: Annotations Overview.
+* annotations for errors, warnings and interrupts: Errors.
+* annotations for invalidation messages: Invalidation.
+* annotations for prompts: Prompting.
+* annotations for running programs: Annotations for Running.
+* annotations for source display: Source Annotations.
+* append: Dump/Restore Files.
+* append data to a file: Dump/Restore Files.
+* apropos: Help.
+* arguments (to your program): Arguments.
+* artificial array: Arrays.
+* ASCII character set: Character Sets.
+* assembly instructions: Machine Code.
+* assignment: Assignment.
+* async output in GDB/MI: GDB/MI Output Syntax.
+* AT&T disassembly flavor: Machine Code.
+* attach: Attach.
+* attach to a program by name: Server.
+* automatic display: Auto Display.
+* automatic overlay debugging: Automatic Overlay Debugging.
+* automatic thread selection: Threads.
+* auxiliary vector: Auxiliary Vector.
+* awatch: Set Watchpoints.
+* b (break): Set Breaks.
+* B packet: Packets.
+* b packet: Packets.
+* backtrace: Backtrace.
+* backtrace limit: Backtrace.
+* backtraces: Backtrace.
+* backward-char (C-b): Commands For Moving.
+* backward-delete-char (Rubout): Commands For Text.
+* backward-kill-line (C-x Rubout): Commands For Killing.
+* backward-kill-word (M-<DEL>): Commands For Killing.
+* backward-word (M-b): Commands For Moving.
+* beginning-of-history (M-<): Commands For History.
+* beginning-of-line (C-a): Commands For Moving.
+* bell-style: Readline Init File Syntax.
+* break: Set Breaks.
+* break ... thread THREADNO: Thread Stops.
+* break in overloaded functions: Debugging C plus plus.
+* break, and Objective-C: Method Names in Commands.
+* breakpoint: Annotations for Running.
+* breakpoint address adjusted: Breakpoint related warnings.
+* breakpoint commands: Break Commands.
+* breakpoint commands for GDB/MI: GDB/MI Breakpoint Table Commands.
+* breakpoint conditions: Conditions.
+* breakpoint numbers: Breakpoints.
+* breakpoint on events: Breakpoints.
+* breakpoint on memory address: Breakpoints.
+* breakpoint on variable modification: Breakpoints.
+* breakpoint ranges: Breakpoints.
+* breakpoint subroutine, remote: Stub Contents.
+* breakpoints: Breakpoints.
+* breakpoints and threads: Thread Stops.
+* breakpoints in overlays: Overlay Commands.
+* breakpoints-invalid: Invalidation.
+* bt (backtrace): Backtrace.
+* bug criteria: Bug Criteria.
+* bug reports: Bug Reporting.
+* bugs in GDB: GDB Bugs.
+* c (continue): Continuing and Stepping.
+* c (SingleKey TUI key): TUI Single Key Mode.
+* C and C++: C.
+* C and C++ checks: C Checks.
+* C and C++ constants: C Constants.
+* C and C++ defaults: C Defaults.
+* C and C++ operators: C Operators.
+* C packet: Packets.
+* c packet: Packets.
+* C++: C.
+* C++ compilers: C plus plus expressions.
+* C++ exception handling: Debugging C plus plus.
+* C++ scope resolution: Variables.
+* C++ symbol decoding style: Print Settings.
+* C++ symbol display: Debugging C plus plus.
+* C-L: TUI Keys.
+* C-o (operate-and-get-next): Command Syntax.
+* C-x 1: TUI Keys.
+* C-x 2: TUI Keys.
+* C-x A: TUI Keys.
+* C-x a: TUI Keys.
+* C-x C-a: TUI Keys.
+* C-x o: TUI Keys.
+* C-x s: TUI Keys.
+* call: Calling.
+* call overloaded functions: C plus plus expressions.
+* call stack: Stack.
+* call-last-kbd-macro (C-x e): Keyboard Macros.
+* calling functions: Calling.
+* calling make: Shell Commands.
+* capitalize-word (M-c): Commands For Text.
+* casts, to view memory: Expressions.
+* catch: Set Catchpoints.
+* catch catch: Set Catchpoints.
+* catch exceptions, list active handlers: Frame Info.
+* catch exec: Set Catchpoints.
+* catch fork: Set Catchpoints.
+* catch load: Set Catchpoints.
+* catch throw: Set Catchpoints.
+* catch unload: Set Catchpoints.
+* catch vfork: Set Catchpoints.
+* catchpoints: Breakpoints.
+* catchpoints, setting: Set Catchpoints.
+* cd: Working Directory.
+* cdir: Source Path.
+* character sets: Character Sets.
+* character-search (C-]): Miscellaneous Commands.
+* character-search-backward (M-C-]): Miscellaneous Commands.
+* charset: Character Sets.
+* checks, range: Type Checking.
+* checks, type: Checks.
+* checksum, for GDB remote: Overview.
+* choosing target byte order: Byte Order.
+* clear: Delete Breaks.
+* clear, and Objective-C: Method Names in Commands.
+* clear-screen (C-l): Commands For Moving.
+* clearing breakpoints, watchpoints, catchpoints: Delete Breaks.
+* close, file-i/o system call: close.
+* collect (tracepoints): Tracepoint Actions.
+* collected data discarded: Starting and Stopping Trace Experiment.
+* colon, doubled as scope operator: M2 Scope.
+* colon-colon, context for variables/functions: Variables.
+* colon-colon, in Modula-2: M2 Scope.
+* command editing: Readline Bare Essentials.
+* command files: Command Files.
+* command hooks: Hooks.
+* command interpreters: Interpreters.
+* command line editing: Editing.
+* commands <1>: Prompting.
+* commands: Break Commands.
+* commands for C++: Debugging C plus plus.
+* commands to STDBUG (ST2000): ST2000.
+* comment: Command Syntax.
+* comment-begin: Readline Init File Syntax.
+* compatibility, GDB/MI and CLI: GDB/MI Compatibility with CLI.
+* compilation directory: Source Path.
+* compiling, on Sparclet: Sparclet.
+* complete: Help.
+* complete (<TAB>): Commands For Completion.
+* completion: Completion.
+* completion of quoted strings: Completion.
+* completion-query-items: Readline Init File Syntax.
+* condition: Conditions.
+* conditional breakpoints: Conditions.
+* configuring GDB: Installing GDB.
+* configuring GDB, and source tree subdirectories: Installing GDB.
+* confirmation: Messages/Warnings.
+* connect (to STDBUG): ST2000.
+* console i/o as part of file-i/o: Console I/O.
+* console interpreter: Interpreters.
+* console output in GDB/MI: GDB/MI Output Syntax.
+* constants, in file-i/o protocol: Constants.
+* continue: Continuing and Stepping.
+* continuing: Continuing and Stepping.
+* continuing threads: Thread Stops.
+* control C, and remote debugging: Bootstrapping.
+* controlling terminal: Input/Output.
+* convenience variables: Convenience Vars.
+* convenience variables for tracepoints: Tracepoint Variables.
+* convert-meta: Readline Init File Syntax.
+* copy-backward-word (): Commands For Killing.
+* copy-forward-word (): Commands For Killing.
+* copy-region-as-kill (): Commands For Killing.
+* core: Files.
+* core dump file: Files.
+* core-file: Files.
+* crash of debugger: Bug Criteria.
+* ctrl-c message, in file-i/o protocol: The Ctrl-C message.
+* current directory: Source Path.
+* current stack frame: Frames.
+* current thread: Threads.
+* cwd: Source Path.
+* Cygwin-specific commands: Cygwin Native.
+* d (delete): Delete Breaks.
+* d (SingleKey TUI key): TUI Single Key Mode.
+* D packet: Packets.
+* d packet: Packets.
+* data manipulation, in GDB/MI: GDB/MI Data Manipulation.
+* debug formats and C++: C plus plus expressions.
+* debug links: Separate Debug Files.
+* debugger crash: Bug Criteria.
+* debugging C++ programs: C plus plus expressions.
+* debugging information directory, global: Separate Debug Files.
+* debugging information in separate files: Separate Debug Files.
+* debugging optimized code: Compilation.
+* debugging stub, example: remote stub.
+* debugging target: Targets.
+* define: Define.
+* defining macros interactively: Macros.
+* definition, showing a macro's: Macros.
+* delete: Delete Breaks.
+* delete breakpoints: Delete Breaks.
+* delete display: Auto Display.
+* delete mem: Memory Region Attributes.
+* delete tracepoint: Create and Delete Tracepoints.
+* delete-char (C-d): Commands For Text.
+* delete-char-or-list (): Commands For Completion.
+* delete-horizontal-space (): Commands For Killing.
+* deleting breakpoints, watchpoints, catchpoints: Delete Breaks.
+* demangling: Print Settings.
+* descriptor tables display: DJGPP Native.
+* detach: Attach.
+* detach (remote): Connecting.
+* device: Renesas Boards.
+* digit-argument (M-0, M-1, ... M--): Numeric Arguments.
+* dir: Source Path.
+* direct memory access (DMA) on MS-DOS: DJGPP Native.
+* directories for source files: Source Path.
+* directory: Source Path.
+* directory, compilation: Source Path.
+* directory, current: Source Path.
+* dis (disable): Disabling.
+* disable: Disabling.
+* disable breakpoints: Disabling.
+* disable display: Auto Display.
+* disable mem: Memory Region Attributes.
+* disable tracepoint: Enable and Disable Tracepoints.
+* disable-completion: Readline Init File Syntax.
+* disassemble: Machine Code.
+* disconnect: Connecting.
+* display: Auto Display.
+* display of expressions: Auto Display.
+* DJGPP debugging: DJGPP Native.
+* dll-symbols: Cygwin Native.
+* DLLs with no debugging symbols: Non-debug DLL symbols.
+* do (down): Selection.
+* do-uppercase-version (M-a, M-b, M-X, ...): Miscellaneous Commands.
+* document: Define.
+* documentation: Formatting Documentation.
+* Down: TUI Keys.
+* down: Selection.
+* down-silently: Selection.
+* downcase-word (M-l): Commands For Text.
+* download to H8/300 or H8/500: H8/300.
+* download to Renesas SH: H8/300.
+* download to Sparclet: Sparclet Download.
+* download to VxWorks: VxWorks Download.
+* dump: Dump/Restore Files.
+* dump all data collected at tracepoint: tdump.
+* dump data to a file: Dump/Restore Files.
+* dump-functions (): Miscellaneous Commands.
+* dump-macros (): Miscellaneous Commands.
+* dump-variables (): Miscellaneous Commands.
+* dump/restore files: Dump/Restore Files.
+* dynamic linking: Files.
+* e (edit): Edit.
+* EBCDIC character set: Character Sets.
+* echo: Output.
+* edit: Edit.
+* editing: Editing.
+* editing command lines: Readline Bare Essentials.
+* editing source files: Edit.
+* editing-mode: Readline Init File Syntax.
+* else: Define.
+* Emacs: Emacs.
+* enable: Disabling.
+* enable breakpoints: Disabling.
+* enable display: Auto Display.
+* enable mem: Memory Region Attributes.
+* enable tracepoint: Enable and Disable Tracepoints.
+* enable-keypad: Readline Init File Syntax.
+* end: Break Commands.
+* end-kbd-macro (C-x )): Keyboard Macros.
+* end-of-history (M->): Commands For History.
+* end-of-line (C-e): Commands For Moving.
+* entering numbers: Numbers.
+* environment (of your program): Environment.
+* errno values, in file-i/o protocol: Errno values.
+* error: Errors.
+* error on valid input: Bug Criteria.
+* error-begin: Errors.
+* event designators: Event Designators.
+* event handling: Set Catchpoints.
+* examining data: Data.
+* examining memory: Memory.
+* exception handlers: Set Catchpoints.
+* exception handlers, how to list: Frame Info.
+* exceptionHandler: Bootstrapping.
+* exchange-point-and-mark (C-x C-x): Miscellaneous Commands.
+* exec-file: Files.
+* executable file: Files.
+* exited: Annotations for Running.
+* exiting GDB: Quitting GDB.
+* expand-tilde: Readline Init File Syntax.
+* expanding preprocessor macros: Macros.
+* expressions: Expressions.
+* expressions in C or C++: C.
+* expressions in C++: C plus plus expressions.
+* expressions in Modula-2: Modula-2.
+* f (frame): Selection.
+* f (SingleKey TUI key): TUI Single Key Mode.
+* F packet: Packets.
+* F reply packet: The F reply packet.
+* F request packet: The F request packet.
+* fatal signal: Bug Criteria.
+* fatal signals: Signals.
+* FDL, GNU Free Documentation License: GNU Free Documentation License.
+* fg (resume foreground execution): Continuing and Stepping.
+* file: Files.
+* file-i/o examples: File-I/O Examples.
+* file-i/o overview: File-I/O Overview.
+* File-I/O remote protocol extension: File-I/O remote protocol extension.
+* file-i/o reply packet: The F reply packet.
+* file-i/o request packet: The F request packet.
+* find trace snapshot: tfind.
+* finish: Continuing and Stepping.
+* flinching: Messages/Warnings.
+* float promotion: ABI.
+* floating point: Floating Point Hardware.
+* floating point registers: Registers.
+* floating point, MIPS remote: MIPS Embedded.
+* flush_i_cache: Bootstrapping.
+* focus: TUI Commands.
+* focus of debugging: Threads.
+* foo: Symbol Errors.
+* fork, debugging programs which call: Processes.
+* format options: Print Settings.
+* formatted output: Output Formats.
+* Fortran: Summary.
+* forward-backward-delete-char (): Commands For Text.
+* forward-char (C-f): Commands For Moving.
+* forward-search: Search.
+* forward-search-history (C-s): Commands For History.
+* forward-word (M-f): Commands For Moving.
+* frame number: Frames.
+* frame pointer: Frames.
+* frame, command: Frames.
+* frame, definition: Frames.
+* frame, selecting: Selection.
+* frameless execution: Frames.
+* frames-invalid: Invalidation.
+* free memory information (MS-DOS): DJGPP Native.
+* fstat, file-i/o system call: stat/fstat.
+* Fujitsu: remote stub.
+* full symbol tables, listing GDB's internal: Symbols.
+* functions without line info, and stepping: Continuing and Stepping.
+* G packet: Packets.
+* g packet: Packets.
+* g++, GNU C++ compiler: C.
+* garbled pointers: DJGPP Native.
+* GCC and C++: C plus plus expressions.
+* GDB bugs, reporting: Bug Reporting.
+* GDB reference card: Formatting Documentation.
+* gdb.ini: Command Files.
+* GDB/MI, breakpoint commands: GDB/MI Breakpoint Table Commands.
+* GDB/MI, compatibility with CLI: GDB/MI Compatibility with CLI.
+* GDB/MI, data manipulation: GDB/MI Data Manipulation.
+* GDB/MI, input syntax: GDB/MI Input Syntax.
+* GDB/MI, its purpose: GDB/MI.
+* GDB/MI, out-of-band records: GDB/MI Out-of-band Records.
+* GDB/MI, output syntax: GDB/MI Output Syntax.
+* GDB/MI, result records: GDB/MI Result Records.
+* GDB/MI, simple examples: GDB/MI Simple Examples.
+* GDB/MI, stream records: GDB/MI Stream Records.
+* GDBHISTFILE: History.
+* gdbserve.nlm: NetWare.
+* gdbserver: Server.
+* GDT: DJGPP Native.
+* getDebugChar: Bootstrapping.
+* gettimeofday, file-i/o system call: gettimeofday.
+* global debugging information directory: Separate Debug Files.
+* GNU C++: C.
+* GNU Emacs: Emacs.
+* gnu_debuglink_crc32: Separate Debug Files.
+* h (help): Help.
+* H packet: Packets.
+* H8/300 or H8/500 download: H8/300.
+* handle: Signals.
+* handle_exception: Stub Contents.
+* handling signals: Signals.
+* hardware watchpoints: Set Watchpoints.
+* hbreak: Set Breaks.
+* help: Help.
+* help target: Target Commands.
+* help user-defined: Define.
+* heuristic-fence-post (Alpha, MIPS): MIPS.
+* history events: Event Designators.
+* history expansion <1>: History Interaction.
+* history expansion: History.
+* history file: History.
+* history number: Value History.
+* history save: History.
+* history size: History.
+* history substitution: History.
+* history-preserve-point: Readline Init File Syntax.
+* history-search-backward (): Commands For History.
+* history-search-forward (): Commands For History.
+* hook: Hooks.
+* hook-: Hooks.
+* hookpost: Hooks.
+* hookpost-: Hooks.
+* hooks, for commands: Hooks.
+* hooks, post-command: Hooks.
+* hooks, pre-command: Hooks.
+* horizontal-scroll-mode: Readline Init File Syntax.
+* host character set: Character Sets.
+* htrace disable: OpenRISC 1000.
+* htrace enable: OpenRISC 1000.
+* htrace info: OpenRISC 1000.
+* htrace mode continuous: OpenRISC 1000.
+* htrace mode suspend: OpenRISC 1000.
+* htrace print: OpenRISC 1000.
+* htrace qualifier: OpenRISC 1000.
+* htrace record: OpenRISC 1000.
+* htrace rewind: OpenRISC 1000.
+* htrace stop: OpenRISC 1000.
+* htrace trigger: OpenRISC 1000.
+* hwatch: OpenRISC 1000.
+* i (info): Help.
+* I packet: Packets.
+* i packet: Packets.
+* i/o: Input/Output.
+* i386: remote stub.
+* i386-stub.c: remote stub.
+* IBM1047 character set: Character Sets.
+* IDT: DJGPP Native.
+* if: Define.
+* ignore: Conditions.
+* ignore count (of breakpoint): Conditions.
+* INCLUDE_RDB: VxWorks.
+* info: Help.
+* info address: Symbols.
+* info all-registers: Registers.
+* info args: Frame Info.
+* info auxv: Auxiliary Vector.
+* info breakpoints: Set Breaks.
+* info catch: Frame Info.
+* info cisco: KOD.
+* info classes: Symbols.
+* info display: Auto Display.
+* info dll: Cygwin Native.
+* info dos: DJGPP Native.
+* info extensions: Show.
+* info f (info frame): Frame Info.
+* info files: Files.
+* info float: Floating Point Hardware.
+* info frame: Frame Info.
+* info frame, show the source language: Show.
+* info functions: Symbols.
+* info line: Machine Code.
+* info line, and Objective-C: Method Names in Commands.
+* info locals: Frame Info.
+* info macro: Macros.
+* info mem: Memory Region Attributes.
+* info or1k spr: OpenRISC 1000.
+* info proc: SVR4 Process Information.
+* info proc mappings: SVR4 Process Information.
+* info program: Stopping.
+* info registers: Registers.
+* info s (info stack): Backtrace.
+* info scope: Symbols.
+* info selectors: Symbols.
+* info set: Help.
+* info share: Files.
+* info sharedlibrary: Files.
+* info signals: Signals.
+* info source: Symbols.
+* info source, show the source language: Show.
+* info sources: Symbols.
+* info stack: Backtrace.
+* info symbol: Symbols.
+* info target: Files.
+* info terminal: Input/Output.
+* info threads: Threads.
+* info tracepoints: Listing Tracepoints.
+* info types: Symbols.
+* info variables: Symbols.
+* info vector: Vector Unit.
+* info w32: Cygwin Native.
+* info watchpoints: Set Watchpoints.
+* info win: TUI Commands.
+* information about tracepoints: Listing Tracepoints.
+* inheritance: Debugging C plus plus.
+* init file: Command Files.
+* init file name: Command Files.
+* initial frame: Frames.
+* initialization file, readline: Readline Init File.
+* innermost frame: Frames.
+* input syntax for GDB/MI: GDB/MI Input Syntax.
+* input-meta: Readline Init File Syntax.
+* insert-comment (M-#): Miscellaneous Commands.
+* insert-completions (M-*): Commands For Completion.
+* inspect: Data.
+* installation: Installing GDB.
+* instructions, assembly: Machine Code.
+* integral datatypes, in file-i/o protocol: Integral datatypes.
+* Intel: remote stub.
+* Intel disassembly flavor: Machine Code.
+* interaction, readline: Readline Interaction.
+* internal commands: Maintenance Commands.
+* internal GDB breakpoints: Set Breaks.
+* interpreter-exec: Interpreters.
+* interrupt: Quitting GDB.
+* interrupting remote programs: Connecting.
+* interrupting remote targets: Bootstrapping.
+* invalid input: Bug Criteria.
+* invoke another interpreter: Interpreters.
+* isatty call, file-i/o protocol: The isatty call.
+* isatty, file-i/o system call: isatty.
+* isearch-terminators: Readline Init File Syntax.
+* ISO 8859-1 character set: Character Sets.
+* ISO Latin 1 character set: Character Sets.
+* jump: Jumping.
+* jump, and Objective-C: Method Names in Commands.
+* k packet: Packets.
+* kernel object display: KOD.
+* keymap: Readline Init File Syntax.
+* kill: Kill Process.
+* kill ring: Readline Killing Commands.
+* kill-line (C-k): Commands For Killing.
+* kill-region (): Commands For Killing.
+* kill-whole-line (): Commands For Killing.
+* kill-word (M-d): Commands For Killing.
+* killing text: Readline Killing Commands.
+* KOD: KOD.
+* l (list): List.
+* languages: Languages.
+* last tracepoint number: Create and Delete Tracepoints.
+* latest breakpoint: Set Breaks.
+* layout asm: TUI Commands.
+* layout next: TUI Commands.
+* layout prev: TUI Commands.
+* layout regs: TUI Commands.
+* layout split: TUI Commands.
+* layout src: TUI Commands.
+* LDT: DJGPP Native.
+* leaving GDB: Quitting GDB.
+* Left: TUI Keys.
+* limits, in file-i/o protocol: Limits.
+* linespec: List.
+* list: List.
+* list of supported file-i/o calls: List of supported calls.
+* list output in GDB/MI: GDB/MI Output Syntax.
+* list, and Objective-C: Method Names in Commands.
+* listing GDB's internal symbol tables: Symbols.
+* listing machine instructions: Machine Code.
+* listing mapped overlays: Overlay Commands.
+* load address, overlay's: How Overlays Work.
+* load FILENAME: Target Commands.
+* local variables: Symbols.
+* locate address: Output Formats.
+* log output in GDB/MI: GDB/MI Output Syntax.
+* logging GDB output: Logging output.
+* lseek flags, in file-i/o protocol: Lseek flags.
+* lseek, file-i/o system call: lseek.
+* M packet: Packets.
+* m packet: Packets.
+* m680x0: remote stub.
+* m68k-stub.c: remote stub.
+* machine instructions: Machine Code.
+* macro define: Macros.
+* macro definition, showing: Macros.
+* macro expand: Macros.
+* macro expand-once: Macros.
+* macro expansion, showing the results of preprocessor: Macros.
+* macro undef: Macros.
+* macros, example of debugging with: Macros.
+* macros, user-defined: Macros.
+* maint info breakpoints: Maintenance Commands.
+* maint info psymtabs: Symbols.
+* maint info sections: Files.
+* maint info symtabs: Symbols.
+* maint internal-error: Maintenance Commands.
+* maint internal-warning: Maintenance Commands.
+* maint print cooked-registers: Maintenance Commands.
+* maint print dummy-frames: Maintenance Commands.
+* maint print psymbols: Symbols.
+* maint print raw-registers: Maintenance Commands.
+* maint print reggroups: Maintenance Commands.
+* maint print register-groups: Maintenance Commands.
+* maint print registers: Maintenance Commands.
+* maint print symbols: Symbols.
+* maint set profile: Maintenance Commands.
+* maint show profile: Maintenance Commands.
+* maintenance commands: Maintenance Commands.
+* make: Shell Commands.
+* manual overlay debugging: Overlay Commands.
+* map an overlay: Overlay Commands.
+* mapped: Files.
+* mapped address: How Overlays Work.
+* mapped overlays: How Overlays Work.
+* mark-modified-lines: Readline Init File Syntax.
+* mark-symlinked-directories: Readline Init File Syntax.
+* match-hidden-files: Readline Init File Syntax.
+* mem: Memory Region Attributes.
+* member functions: C plus plus expressions.
+* memory models, H8/500: H8/500.
+* memory region attributes: Memory Region Attributes.
+* memory tracing: Breakpoints.
+* memory transfer, in file-i/o protocol: Memory transfer.
+* memory, viewing as typed object: Expressions.
+* memory-mapped symbol file: Files.
+* memset: Bootstrapping.
+* menu-complete (): Commands For Completion.
+* meta-flag: Readline Init File Syntax.
+* mi interpreter: Interpreters.
+* mi1 interpreter: Interpreters.
+* mi2 interpreter: Interpreters.
+* minimal language: Unsupported languages.
+* Minimal symbols and DLLs: Non-debug DLL symbols.
+* MIPS boards: MIPS Embedded.
+* MIPS remote floating point: MIPS Embedded.
+* MIPS remotedebug protocol: MIPS Embedded.
+* MIPS stack: MIPS.
+* mode_t values, in file-i/o protocol: mode_t values.
+* Modula-2: Summary.
+* Modula-2 built-ins: Built-In Func/Proc.
+* Modula-2 checks: M2 Checks.
+* Modula-2 constants: Built-In Func/Proc.
+* Modula-2 defaults: M2 Defaults.
+* Modula-2 operators: M2 Operators.
+* Modula-2, deviations from: Deviations.
+* Modula-2, GDB support: Modula-2.
+* Motorola 680x0: remote stub.
+* MS Windows debugging: Cygwin Native.
+* MS-DOS system info: DJGPP Native.
+* MS-DOS-specific commands: DJGPP Native.
+* multiple processes: Processes.
+* multiple targets: Active Targets.
+* multiple threads: Threads.
+* n (next): Continuing and Stepping.
+* n (SingleKey TUI key): TUI Single Key Mode.
+* names of symbols: Symbols.
+* namespace in C++: C plus plus expressions.
+* native Cygwin debugging: Cygwin Native.
+* native DJGPP debugging: DJGPP Native.
+* negative breakpoint numbers: Set Breaks.
+* New SYSTAG message: Threads.
+* New SYSTAG message, on HP-UX: Threads.
+* next: Continuing and Stepping.
+* next-history (C-n): Commands For History.
+* nexti: Continuing and Stepping.
+* ni (nexti): Continuing and Stepping.
+* non-incremental-forward-search-history (M-n): Commands For History.
+* non-incremental-reverse-search-history (M-p): Commands For History.
+* notation, readline: Readline Bare Essentials.
+* notational conventions, for GDB/MI: GDB/MI.
+* notify output in GDB/MI: GDB/MI Output Syntax.
+* number representation: Numbers.
+* numbers for breakpoints: Breakpoints.
+* object files, relocatable, reading symbols from: Files.
+* Objective-C: Objective-C.
+* online documentation: Help.
+* open flags, in file-i/o protocol: Open flags.
+* open, file-i/o system call: open.
+* OpenRISC 1000: OpenRISC 1000.
+* OpenRISC 1000 htrace: OpenRISC 1000.
+* operations allowed on pending breakpoints: Set Breaks.
+* optimized code, debugging: Compilation.
+* or1k boards: OpenRISC 1000.
+* or1ksim: OpenRISC 1000.
+* OS ABI: ABI.
+* out-of-band records in GDB/MI: GDB/MI Out-of-band Records.
+* outermost frame: Frames.
+* output: Output.
+* output formats: Output Formats.
+* output syntax of GDB/MI: GDB/MI Output Syntax.
+* output-meta: Readline Init File Syntax.
+* overlay area: How Overlays Work.
+* overlay auto: Overlay Commands.
+* overlay example program: Overlay Sample Program.
+* overlay load-target: Overlay Commands.
+* overlay manual: Overlay Commands.
+* overlay map-overlay: Overlay Commands.
+* overlay off: Overlay Commands.
+* overlay unmap-overlay: Overlay Commands.
+* overlays: Overlays.
+* overlays, setting breakpoints in: Overlay Commands.
+* overload-choice: Prompting.
+* overloaded functions, calling: C plus plus expressions.
+* overloaded functions, overload resolution: Debugging C plus plus.
+* overloading: Breakpoint Menus.
+* overloading in C++: Debugging C plus plus.
+* overwrite-mode (): Commands For Text.
+* P packet: Packets.
+* p packet: Packets.
+* packets, reporting on stdout: Debugging Output.
+* page tables display (MS-DOS): DJGPP Native.
+* page-completions: Readline Init File Syntax.
+* partial symbol dump: Symbols.
+* partial symbol tables, listing GDB's internal: Symbols.
+* Pascal: Summary.
+* passcount: Tracepoint Passcounts.
+* patching binaries: Patching.
+* path: Environment.
+* pauses in output: Screen Size.
+* pending breakpoints: Set Breaks.
+* PgDn: TUI Keys.
+* PgUp: TUI Keys.
+* physical address from linear address: DJGPP Native.
+* pipes: Starting.
+* po (print-object): The Print Command with Objective-C.
+* pointer values, in file-i/o protocol: Pointer values.
+* pointer, finding referent: Print Settings.
+* possible-completions (M-?): Commands For Completion.
+* post-commands: Prompting.
+* post-overload-choice: Prompting.
+* post-prompt: Prompting.
+* post-prompt-for-continue: Prompting.
+* post-query: Prompting.
+* pre-commands: Prompting.
+* pre-overload-choice: Prompting.
+* pre-prompt: Prompting.
+* pre-prompt-for-continue: Prompting.
+* pre-query: Prompting.
+* prefix-meta (<ESC>): Miscellaneous Commands.
+* premature return from system calls: Thread Stops.
+* preprocessor macro expansion, showing the results of: Macros.
+* previous-history (C-p): Commands For History.
+* print: Data.
+* print an Objective-C object description: The Print Command with Objective-C.
+* print settings: Print Settings.
+* print-object: The Print Command with Objective-C.
+* printf: Output.
+* printing data: Data.
+* process image: SVR4 Process Information.
+* processes, multiple: Processes.
+* profiling GDB: Maintenance Commands.
+* prompt <1>: Prompting.
+* prompt: Prompt.
+* prompt-for-continue: Prompting.
+* protocol basics, file-i/o: Protocol basics.
+* protocol specific representation of datatypes, in file-i/o protocol: Protocol specific representation of datatypes.
+* protocol, GDB remote serial: Overview.
+* ptype: Symbols.
+* putDebugChar: Bootstrapping.
+* pwd: Working Directory.
+* q (quit): Quitting GDB.
+* q (SingleKey TUI key): TUI Single Key Mode.
+* Q packet: Packets.
+* q packet: Packets.
+* query: Prompting.
+* quit: Errors.
+* quit [EXPRESSION]: Quitting GDB.
+* quoted-insert (C-q or C-v): Commands For Text.
+* quotes in commands: Completion.
+* quoting names: Symbols.
+* r (run): Starting.
+* r (SingleKey TUI key): TUI Single Key Mode.
+* R packet: Packets.
+* r packet: Packets.
+* raise exceptions: Set Catchpoints.
+* range checking: Type Checking.
+* ranges of breakpoints: Breakpoints.
+* rbreak: Set Breaks.
+* re-read-init-file (C-x C-r): Miscellaneous Commands.
+* read, file-i/o system call: read.
+* reading symbols from relocatable object files: Files.
+* reading symbols immediately: Files.
+* readline: Editing.
+* readnow: Files.
+* recent tracepoint number: Create and Delete Tracepoints.
+* redirection: Input/Output.
+* redraw-current-line (): Commands For Moving.
+* reference card: Formatting Documentation.
+* reference declarations: C plus plus expressions.
+* refresh: TUI Commands.
+* register stack, AMD29K: A29K.
+* registers: Registers.
+* regular expression: Set Breaks.
+* reloading symbols: Symbols.
+* reloading the overlay table: Overlay Commands.
+* relocatable object files, reading symbols from: Files.
+* remote connection without stubs: Server.
+* remote debugging: Remote.
+* remote programs, interrupting: Connecting.
+* remote protocol, field separator: Overview.
+* remote serial debugging summary: Debug Session.
+* remote serial debugging, overview: remote stub.
+* remote serial protocol: Overview.
+* remote serial stub: Stub Contents.
+* remote serial stub list: remote stub.
+* remote serial stub, initialization: Stub Contents.
+* remote serial stub, main routine: Stub Contents.
+* remote stub, example: remote stub.
+* remote stub, support routines: Bootstrapping.
+* remotedebug, MIPS protocol: MIPS Embedded.
+* remotetimeout: Sparclet.
+* remove actions from a tracepoint: Tracepoint Actions.
+* rename, file-i/o system call: rename.
+* Renesas: remote stub.
+* Renesas SH download: H8/300.
+* repeating command sequences: Command Syntax.
+* repeating commands: Command Syntax.
+* reporting bugs in GDB: GDB Bugs.
+* response time, MIPS debugging: MIPS.
+* restore: Dump/Restore Files.
+* restore data from a file: Dump/Restore Files.
+* result records in GDB/MI: GDB/MI Result Records.
+* resuming execution: Continuing and Stepping.
+* RET (repeat last command): Command Syntax.
+* retransmit-timeout, MIPS protocol: MIPS Embedded.
+* return: Returning.
+* returning from a function: Returning.
+* reverse-search: Search.
+* reverse-search-history (C-r): Commands For History.
+* revert-line (M-r): Miscellaneous Commands.
+* Right: TUI Keys.
+* run: Starting.
+* running: Starting.
+* running and debugging Sparclet programs: Sparclet Execution.
+* running VxWorks tasks: VxWorks Attach.
+* running, on Sparclet: Sparclet.
+* rwatch: Set Watchpoints.
+* s (SingleKey TUI key): TUI Single Key Mode.
+* s (step): Continuing and Stepping.
+* S packet: Packets.
+* s packet: Packets.
+* save tracepoints for future sessions: save-tracepoints.
+* save-tracepoints: save-tracepoints.
+* saving symbol table: Files.
+* scope: M2 Scope.
+* search: Search.
+* searching: Search.
+* section: Files.
+* segment descriptor tables: DJGPP Native.
+* select trace snapshot: tfind.
+* select-frame: Frames.
+* selected frame: Stack.
+* selecting frame silently: Frames.
+* self-insert (a, b, A, 1, !, ...): Commands For Text.
+* separate debugging information files: Separate Debug Files.
+* sequence-id, for GDB remote: Overview.
+* serial connections, debugging: Debugging Output.
+* serial device, Renesas micros: Renesas Boards.
+* serial line speed, Renesas micros: Renesas Boards.
+* serial line, target remote: Connecting.
+* serial protocol, GDB remote: Overview.
+* server prefix for annotations: Server Prefix.
+* set: Help.
+* set args: Arguments.
+* set auto-solib-add: Files.
+* set auto-solib-limit: Files.
+* set backtrace limit: Backtrace.
+* set backtrace past-main: Backtrace.
+* set breakpoint pending: Set Breaks.
+* set charset: Character Sets.
+* set check range: Range Checking.
+* set check type: Type Checking.
+* set check, range: Range Checking.
+* set check, type: Type Checking.
+* set coerce-float-to-double: ABI.
+* set complaints: Messages/Warnings.
+* set confirm: Messages/Warnings.
+* set cp-abi: ABI.
+* set debug arch: Debugging Output.
+* set debug event: Debugging Output.
+* set debug expression: Debugging Output.
+* set debug frame: Debugging Output.
+* set debug overload: Debugging Output.
+* set debug remote: Debugging Output.
+* set debug serial: Debugging Output.
+* set debug target: Debugging Output.
+* set debug varobj: Debugging Output.
+* set debug-file-directory: Separate Debug Files.
+* set debugevents: Cygwin Native.
+* set debugexceptions: Cygwin Native.
+* set debugexec: Cygwin Native.
+* set debugmemory: Cygwin Native.
+* set demangle-style: Print Settings.
+* set disassembly-flavor: Machine Code.
+* set editing: Editing.
+* set endian auto: Byte Order.
+* set endian big: Byte Order.
+* set endian little: Byte Order.
+* set environment: Environment.
+* set extension-language: Show.
+* set follow-fork-mode: Processes.
+* set gnutarget: Target Commands.
+* set height: Screen Size.
+* set history expansion: History.
+* set history filename: History.
+* set history save: History.
+* set history size: History.
+* set host-charset: Character Sets.
+* set input-radix: Numbers.
+* set language: Manually.
+* set listsize: List.
+* set logging: Logging output.
+* set machine: Renesas Special.
+* set max-user-call-depth: Define.
+* set memory MOD: H8/500.
+* set mipsfpu: MIPS Embedded.
+* set new-console: Cygwin Native.
+* set new-group: Cygwin Native.
+* set opaque-type-resolution: Symbols.
+* set os: KOD.
+* set osabi: ABI.
+* set output-radix: Numbers.
+* set overload-resolution: Debugging C plus plus.
+* set print address: Print Settings.
+* set print array: Print Settings.
+* set print asm-demangle: Print Settings.
+* set print demangle: Print Settings.
+* set print elements: Print Settings.
+* set print max-symbolic-offset: Print Settings.
+* set print null-stop: Print Settings.
+* set print object: Print Settings.
+* set print pretty: Print Settings.
+* set print sevenbit-strings: Print Settings.
+* set print static-members: Print Settings.
+* set print symbol-filename: Print Settings.
+* set print union: Print Settings.
+* set print vtbl: Print Settings.
+* set processor ARGS: MIPS Embedded.
+* set prompt: Prompt.
+* set remote hardware-breakpoint-limit: Remote configuration.
+* set remote hardware-watchpoint-limit: Remote configuration.
+* set remote system-call-allowed 0: The system call.
+* set remote system-call-allowed 1: The system call.
+* set remotedebug, MIPS protocol: MIPS Embedded.
+* set retransmit-timeout: MIPS Embedded.
+* set rstack_high_address: A29K.
+* set shell: Cygwin Native.
+* set solib-absolute-prefix: Files.
+* set solib-search-path: Files.
+* set step-mode: Continuing and Stepping.
+* set symbol-reloading: Symbols.
+* set target-charset: Character Sets.
+* set timeout: MIPS Embedded.
+* set tracepoint: Create and Delete Tracepoints.
+* set trust-readonly-sections: Files.
+* set tui active-border-mode: TUI Configuration.
+* set tui border-kind: TUI Configuration.
+* set tui border-mode: TUI Configuration.
+* set variable: Assignment.
+* set verbose: Messages/Warnings.
+* set width: Screen Size.
+* set write: Patching.
+* set-mark (C-@): Miscellaneous Commands.
+* set_debug_traps: Stub Contents.
+* setting variables: Assignment.
+* setting watchpoints: Set Watchpoints.
+* SH: remote stub.
+* sh-stub.c: remote stub.
+* share: Files.
+* shared libraries: Files.
+* sharedlibrary: Files.
+* shell: Shell Commands.
+* shell escape: Shell Commands.
+* show: Help.
+* show args: Arguments.
+* show auto-solib-add: Files.
+* show auto-solib-limit: Files.
+* show backtrace limit: Backtrace.
+* show backtrace past-main: Backtrace.
+* show breakpoint pending: Set Breaks.
+* show charset: Character Sets.
+* show check range: Range Checking.
+* show check type: Type Checking.
+* show complaints: Messages/Warnings.
+* show confirm: Messages/Warnings.
+* show convenience: Convenience Vars.
+* show copying: Help.
+* show cp-abi: ABI.
+* show debug arch: Debugging Output.
+* show debug event: Debugging Output.
+* show debug expression: Debugging Output.
+* show debug frame: Debugging Output.
+* show debug overload: Debugging Output.
+* show debug remote: Debugging Output.
+* show debug serial: Debugging Output.
+* show debug target: Debugging Output.
+* show debug varobj: Debugging Output.
+* show debug-file-directory: Separate Debug Files.
+* show demangle-style: Print Settings.
+* show directories: Source Path.
+* show editing: Editing.
+* show environment: Environment.
+* show gnutarget: Target Commands.
+* show height: Screen Size.
+* show history: History.
+* show host-charset: Character Sets.
+* show input-radix: Numbers.
+* show language: Show.
+* show listsize: List.
+* show logging: Logging output.
+* show machine: Renesas Special.
+* show max-user-call-depth: Define.
+* show mipsfpu: MIPS Embedded.
+* show new-console: Cygwin Native.
+* show new-group: Cygwin Native.
+* show opaque-type-resolution: Symbols.
+* show os: KOD.
+* show osabi: ABI.
+* show output-radix: Numbers.
+* show paths: Environment.
+* show print address: Print Settings.
+* show print array: Print Settings.
+* show print asm-demangle: Print Settings.
+* show print demangle: Print Settings.
+* show print elements: Print Settings.
+* show print max-symbolic-offset: Print Settings.
+* show print object: Print Settings.
+* show print pretty: Print Settings.
+* show print sevenbit-strings: Print Settings.
+* show print static-members: Print Settings.
+* show print symbol-filename: Print Settings.
+* show print union: Print Settings.
+* show print vtbl: Print Settings.
+* show processor: MIPS Embedded.
+* show prompt: Prompt.
+* show remote system-call-allowed: The system call.
+* show remotedebug, MIPS protocol: MIPS Embedded.
+* show retransmit-timeout: MIPS Embedded.
+* show rstack_high_address: A29K.
+* show shell: Cygwin Native.
+* show solib-absolute-prefix: Files.
+* show solib-search-path: Files.
+* show symbol-reloading: Symbols.
+* show target-charset: Character Sets.
+* show timeout: MIPS Embedded.
+* show user: Define.
+* show values: Value History.
+* show verbose: Messages/Warnings.
+* show version: Help.
+* show warranty: Help.
+* show width: Screen Size.
+* show write: Patching.
+* show-all-if-ambiguous: Readline Init File Syntax.
+* shows: History.
+* si (stepi): Continuing and Stepping.
+* signal <1>: Annotations for Running.
+* signal: Signaling.
+* signal-name: Annotations for Running.
+* signal-name-end: Annotations for Running.
+* signal-string: Annotations for Running.
+* signal-string-end: Annotations for Running.
+* signalled: Annotations for Running.
+* signals: Signals.
+* silent: Break Commands.
+* sim: Z8000.
+* simulator, Z8000: Z8000.
+* size of screen: Screen Size.
+* software watchpoints: Set Watchpoints.
+* source <1>: Source Annotations.
+* source: Command Files.
+* source path: Source Path.
+* Sparc: remote stub.
+* sparc-stub.c: remote stub.
+* sparcl-stub.c: remote stub.
+* Sparclet: Sparclet.
+* SparcLite: remote stub.
+* speed: Renesas Boards.
+* spr: OpenRISC 1000.
+* ST2000 auxiliary commands: ST2000.
+* st2000 CMD: ST2000.
+* stack frame: Frames.
+* stack on Alpha: MIPS.
+* stack on MIPS: MIPS.
+* stack traces: Backtrace.
+* stacking targets: Active Targets.
+* start a new trace experiment: Starting and Stopping Trace Experiment.
+* start-kbd-macro (C-x (): Keyboard Macros.
+* starting <1>: Annotations for Running.
+* starting: Starting.
+* stat, file-i/o system call: stat/fstat.
+* status of trace data collection: Starting and Stopping Trace Experiment.
+* status output in GDB/MI: GDB/MI Output Syntax.
+* STDBUG commands (ST2000): ST2000.
+* step: Continuing and Stepping.
+* stepi: Continuing and Stepping.
+* stepping: Continuing and Stepping.
+* stepping into functions with no line info: Continuing and Stepping.
+* stop a running trace experiment: Starting and Stopping Trace Experiment.
+* stop reply packets: Stop Reply Packets.
+* stop, a pseudo-command: Hooks.
+* stopped threads: Thread Stops.
+* stopping: Annotations for Running.
+* stream records in GDB/MI: GDB/MI Stream Records.
+* struct stat, in file-i/o protocol: struct stat.
+* struct timeval, in file-i/o protocol: struct timeval.
+* stub example, remote debugging: remote stub.
+* stupid questions: Messages/Warnings.
+* switching threads: Threads.
+* switching threads automatically: Threads.
+* symbol decoding style, C++: Print Settings.
+* symbol dump: Symbols.
+* symbol from address: Symbols.
+* symbol names: Symbols.
+* symbol overloading: Breakpoint Menus.
+* symbol table: Files.
+* symbol tables, listing GDB's internal: Symbols.
+* symbol-file: Files.
+* symbols, reading from relocatable object files: Files.
+* symbols, reading immediately: Files.
+* sysinfo: DJGPP Native.
+* system call, file-i/o protocol: The system call.
+* system calls and thread breakpoints: Thread Stops.
+* system, file-i/o system call: system.
+* T packet: Packets.
+* t packet: Packets.
+* T packet reply: Stop Reply Packets.
+* target: Targets.
+* target abug: M68K.
+* target array: MIPS Embedded.
+* target byte order: Byte Order.
+* target character set: Character Sets.
+* target core: Target Commands.
+* target cpu32bug: M68K.
+* target dbug: M68K.
+* target ddb PORT: MIPS Embedded.
+* target dink32: PowerPC.
+* target e7000, with H8/300: H8/300.
+* target e7000, with Renesas ICE: Renesas ICE.
+* target e7000, with Renesas SH: SH.
+* target est: M68K.
+* target exec: Target Commands.
+* target hms, and serial protocol: Renesas Boards.
+* target hms, with H8/300: H8/300.
+* target hms, with Renesas SH: SH.
+* target jtag: OpenRISC 1000.
+* target lsi PORT: MIPS Embedded.
+* target m32r: M32R/D.
+* target m32rsdi: M32R/D.
+* target mips PORT: MIPS Embedded.
+* target nrom: Target Commands.
+* target op50n: PA.
+* target output in GDB/MI: GDB/MI Output Syntax.
+* target pmon PORT: MIPS Embedded.
+* target ppcbug: PowerPC.
+* target ppcbug1: PowerPC.
+* target r3900: MIPS Embedded.
+* target rdi: ARM.
+* target rdp: ARM.
+* target remote: Target Commands.
+* target rom68k: M68K.
+* target rombug: M68K.
+* target sds: PowerPC.
+* target sh3, with H8/300: H8/300.
+* target sh3, with SH: SH.
+* target sh3e, with H8/300: H8/300.
+* target sh3e, with SH: SH.
+* target sim: Target Commands.
+* target sim, with Z8000: Z8000.
+* target sparclite: Sparclite.
+* target vxworks: VxWorks.
+* target w89k: PA.
+* tbreak: Set Breaks.
+* TCP port, target remote: Connecting.
+* tdump: tdump.
+* terminal: Input/Output.
+* Text User Interface: TUI.
+* tfind: tfind.
+* thbreak: Set Breaks.
+* this, inside C++ member functions: C plus plus expressions.
+* thread apply: Threads.
+* thread breakpoints: Thread Stops.
+* thread breakpoints and system calls: Thread Stops.
+* thread identifier (GDB): Threads.
+* thread identifier (system): Threads.
+* thread identifier (system), on HP-UX: Threads.
+* thread number: Threads.
+* thread THREADNO: Threads.
+* threads and watchpoints: Set Watchpoints.
+* threads of execution: Threads.
+* threads, automatic switching: Threads.
+* threads, continuing: Thread Stops.
+* threads, stopped: Thread Stops.
+* timeout, MIPS protocol: MIPS Embedded.
+* trace: Create and Delete Tracepoints.
+* trace experiment, status of: Starting and Stopping Trace Experiment.
+* tracebacks: Backtrace.
+* tracepoint actions: Tracepoint Actions.
+* tracepoint data, display: tdump.
+* tracepoint deletion: Create and Delete Tracepoints.
+* tracepoint number: Create and Delete Tracepoints.
+* tracepoint pass count: Tracepoint Passcounts.
+* tracepoint variables: Tracepoint Variables.
+* tracepoints: Tracepoints.
+* translating between character sets: Character Sets.
+* transpose-chars (C-t): Commands For Text.
+* transpose-words (M-t): Commands For Text.
+* tstart: Starting and Stopping Trace Experiment.
+* tstatus: Starting and Stopping Trace Experiment.
+* tstop: Starting and Stopping Trace Experiment.
+* tty: Input/Output.
+* TUI: TUI.
+* TUI commands: TUI Commands.
+* TUI configuration variables: TUI Configuration.
+* TUI key bindings: TUI Keys.
+* tui reg: TUI Commands.
+* TUI single key mode: TUI Single Key Mode.
+* type casting memory: Expressions.
+* type checking: Checks.
+* type conversions in C++: C plus plus expressions.
+* u (SingleKey TUI key): TUI Single Key Mode.
+* u (until): Continuing and Stepping.
+* UDP port, target remote: Connecting.
+* undisplay: Auto Display.
+* undo (C-_ or C-x C-u): Miscellaneous Commands.
+* universal-argument (): Numeric Arguments.
+* unix-line-discard (C-u): Commands For Killing.
+* unix-word-rubout (C-w): Commands For Killing.
+* unknown address, locating: Output Formats.
+* unlink, file-i/o system call: unlink.
+* unmap an overlay: Overlay Commands.
+* unmapped overlays: How Overlays Work.
+* unset environment: Environment.
+* unsupported languages: Unsupported languages.
+* until: Continuing and Stepping.
+* Up: TUI Keys.
+* up: Selection.
+* up-silently: Selection.
+* upcase-word (M-u): Commands For Text.
+* update: TUI Commands.
+* user-defined command: Define.
+* user-defined macros: Macros.
+* v (SingleKey TUI key): TUI Single Key Mode.
+* value history: Value History.
+* variable name conflict: Variables.
+* variable objects in GDB/MI: GDB/MI Variable Objects.
+* variable values, wrong: Variables.
+* variables, readline: Readline Init File Syntax.
+* variables, setting: Assignment.
+* vCont packet: Packets.
+* vCont? packet: Packets.
+* vector unit: Vector Unit.
+* vector, auxiliary: Auxiliary Vector.
+* version number: Help.
+* visible-stats: Readline Init File Syntax.
+* VxWorks: VxWorks.
+* vxworks-timeout: VxWorks.
+* w (SingleKey TUI key): TUI Single Key Mode.
+* watch: Set Watchpoints.
+* watchpoint: Annotations for Running.
+* watchpoints: Breakpoints.
+* watchpoints and threads: Set Watchpoints.
+* whatis: Symbols.
+* where: Backtrace.
+* while: Define.
+* while-stepping (tracepoints): Tracepoint Actions.
+* wild pointer, interpreting: Print Settings.
+* winheight: TUI Commands.
+* word completion: Completion.
+* working directory: Source Path.
+* working directory (of your program): Working Directory.
+* working language: Languages.
+* write, file-i/o system call: write.
+* writing into corefiles: Patching.
+* writing into executables: Patching.
+* wrong values: Variables.
+* x (examine memory): Memory.
+* X packet: Packets.
+* x(examine), and info line: Machine Code.
+* yank (C-y): Commands For Killing.
+* yank-last-arg (M-. or M-_): Commands For History.
+* yank-nth-arg (M-C-y): Commands For History.
+* yank-pop (M-y): Commands For Killing.
+* yanking text: Readline Killing Commands.
+* z packet: Packets.
+* Z packets: Packets.
+* Z0 packet: Packets.
+* z0 packet: Packets.
+* Z1 packet: Packets.
+* z1 packet: Packets.
+* Z2 packet: Packets.
+* z2 packet: Packets.
+* Z3 packet: Packets.
+* z3 packet: Packets.
+* Z4 packet: Packets.
+* z4 packet: Packets.
+* Z8000: Z8000.
+* Zilog Z8000 simulator: Z8000.
+* {TYPE}: Expressions.
+
+
diff --git a/contrib/gdb/gdb/doc/gdb.texinfo b/contrib/gdb/gdb/doc/gdb.texinfo
new file mode 100644
index 0000000..772d1eb
--- /dev/null
+++ b/contrib/gdb/gdb/doc/gdb.texinfo
@@ -0,0 +1,21780 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+@c 1999, 2000, 2001, 2002, 2003, 2004
+@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
+@settitle Debugging with @value{GDBN}
+@setchapternewpage odd
+@c %**end of header
+
+@iftex
+@c @smallbook
+@c @cropmarks
+@end iftex
+
+@finalout
+@syncodeindex ky cp
+
+@c readline appendices use @vindex, @findex and @ftable,
+@c annotate.texi and gdbmi use @findex.
+@syncodeindex vr cp
+@syncodeindex fn cp
+
+@c !!set GDB manual's edition---not the same as GDB version!
+@c This is updated by GNU Press.
+@set EDITION Ninth
+
+@c !!set GDB edit command default editor
+@set EDITOR /bin/ex
+
+@c THIS MANUAL REQUIRES TEXINFO 4.0 OR LATER.
+
+@c This is a dir.info fragment to support semi-automated addition of
+@c manuals to an info tree.
+@dircategory Software development
+@direntry
+* Gdb: (gdb). The GNU debugger.
+@end direntry
+
+@ifinfo
+This file documents the @sc{gnu} debugger @value{GDBN}.
+
+
+This is the @value{EDITION} Edition, 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, 1996, 1998,@*
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being ``Free Software'' and ``Free Software Needs
+Free Documentation'', with the Front-Cover Texts being ``A GNU Manual,''
+and with the Back-Cover Texts as in (a) below.
+
+(a) The Free Software Foundation's Back-Cover Text is: ``You have
+freedom to copy and modify this GNU Manual, like GNU software. Copies
+published by the Free Software Foundation raise funds for GNU
+development.''
+@end ifinfo
+
+@titlepage
+@title Debugging with @value{GDBN}
+@subtitle The @sc{gnu} Source-Level Debugger
+@sp 1
+@subtitle @value{EDITION} Edition, for @value{GDBN} version @value{GDBVN}
+@author Richard Stallman, Roland Pesch, Stan Shebs, et al.
+@page
+@tex
+{\parskip=0pt
+\hfill (Send bugs and comments on @value{GDBN} to bug-gdb\@gnu.org.)\par
+\hfill {\it Debugging with @value{GDBN}}\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+@sp 2
+Published by the Free Software Foundation @*
+59 Temple Place - Suite 330, @*
+Boston, MA 02111-1307 USA @*
+ISBN 1-882114-77-9 @*
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being ``Free Software'' and ``Free Software Needs
+Free Documentation'', with the Front-Cover Texts being ``A GNU Manual,''
+and with the Back-Cover Texts as in (a) below.
+
+(a) The Free Software Foundation's Back-Cover Text is: ``You have
+freedom to copy and modify this GNU Manual, like GNU software. Copies
+published by the Free Software Foundation raise funds for GNU
+development.''
+@end titlepage
+@page
+
+@ifnottex
+@node Top, Summary, (dir), (dir)
+
+@top Debugging with @value{GDBN}
+
+This file describes @value{GDBN}, the @sc{gnu} symbolic debugger.
+
+This is the @value{EDITION} Edition, for @value{GDBN} Version
+@value{GDBVN}.
+
+Copyright (C) 1988-2004 Free Software Foundation, Inc.
+
+@menu
+* Summary:: Summary of @value{GDBN}
+* Sample Session:: A sample @value{GDBN} session
+
+* 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
+* Macros:: Preprocessor Macros
+* Tracepoints:: Debugging remote targets non-intrusively
+* Overlays:: Debugging programs that use overlays
+
+* Languages:: Using @value{GDBN} with different languages
+
+* Symbols:: Examining the symbol table
+* Altering:: Altering execution
+* GDB Files:: @value{GDBN} files
+* Targets:: Specifying a debugging target
+* Remote Debugging:: Debugging remote programs
+* Configurations:: Configuration-specific information
+* Controlling GDB:: Controlling @value{GDBN}
+* Sequences:: Canned sequences of commands
+* TUI:: @value{GDBN} Text User Interface
+* Interpreters:: Command Interpreters
+* Emacs:: Using @value{GDBN} under @sc{gnu} Emacs
+* Annotations:: @value{GDBN}'s annotation interface.
+* GDB/MI:: @value{GDBN}'s Machine Interface.
+
+* GDB Bugs:: Reporting bugs in @value{GDBN}
+* Formatting Documentation:: How to format and print @value{GDBN} documentation
+
+* Command Line Editing:: Command Line Editing
+* Using History Interactively:: Using History Interactively
+* Installing GDB:: Installing GDB
+* Maintenance Commands:: Maintenance Commands
+* Remote Protocol:: GDB Remote Serial Protocol
+* Agent Expressions:: The GDB Agent Expression Mechanism
+* Copying:: GNU General Public License says
+ how you can copy and share GDB
+* GNU Free Documentation License:: The license for this documentation
+* Index:: Index
+@end menu
+
+@end ifnottex
+
+@contents
+
+@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
+
+You can use @value{GDBN} to debug programs written in C and C@t{++}.
+For more information, see @ref{Support,,Supported languages}.
+For more information, see @ref{C,,C and C++}.
+
+@cindex Modula-2
+Support for Modula-2 is partial. For information on Modula-2, see
+@ref{Modula-2,,Modula-2}.
+
+@cindex Pascal
+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.
+
+@cindex Fortran
+@value{GDBN} can be used to debug programs written in Fortran, although
+it may be necessary to refer to some variables with a trailing
+underscore.
+
+@value{GDBN} can be used to debug programs written in Objective-C,
+using either the Apple/NeXT or the GNU Objective-C runtime.
+
+@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.
+
+@unnumberedsec Free Software Needs Free Documentation
+
+The biggest deficiency in the free software community today is not in
+the software---it is the lack of good free documentation that we can
+include with the free software. Many of our most important
+programs do not come with free reference manuals and free introductory
+texts. Documentation is an essential part of any software package;
+when an important free software package does not come with a free
+manual and a free tutorial, that is a major gap. We have many such
+gaps today.
+
+Consider Perl, for instance. The tutorial manuals that people
+normally use are non-free. How did this come about? Because the
+authors of those manuals published them with restrictive terms---no
+copying, no modification, source files not available---which exclude
+them from the free software world.
+
+That wasn't the first time this sort of thing happened, and it was far
+from the last. Many times we have heard a GNU user eagerly describe a
+manual that he is writing, his intended contribution to the community,
+only to learn that he had ruined everything by signing a publication
+contract to make it non-free.
+
+Free documentation, like free software, is a matter of freedom, not
+price. The problem with the non-free manual is not that publishers
+charge a price for printed copies---that in itself is fine. (The Free
+Software Foundation sells printed copies of manuals, too.) The
+problem is the restrictions on the use of the manual. Free manuals
+are available in source code form, and give you permission to copy and
+modify. Non-free manuals do not allow this.
+
+The criteria of freedom for a free manual are roughly the same as for
+free software. Redistribution (including the normal kinds of
+commercial redistribution) must be permitted, so that the manual can
+accompany every copy of the program, both on-line and on paper.
+
+Permission for modification of the technical content is crucial too.
+When people modify the software, adding or changing features, if they
+are conscientious they will change the manual too---so they can
+provide accurate and clear documentation for the modified program. A
+manual that leaves you no choice but to write a new manual to document
+a changed version of the program is not really available to our
+community.
+
+Some kinds of limits on the way modification is handled are
+acceptable. For example, requirements to preserve the original
+author's copyright notice, the distribution terms, or the list of
+authors, are ok. It is also no problem to require modified versions
+to include notice that they were modified. Even entire sections that
+may not be deleted or changed are acceptable, as long as they deal
+with nontechnical topics (like this one). These kinds of restrictions
+are acceptable because they don't obstruct the community's normal use
+of the manual.
+
+However, it must be possible to modify all the @emph{technical}
+content of the manual, and then distribute the result in all the usual
+media, through all the usual channels. Otherwise, the restrictions
+obstruct the use of the manual, it is not free, and we need another
+manual to replace it.
+
+Please spread the word about this issue. Our community continues to
+lose manuals to proprietary publishing. If we spread the word that
+free software needs free reference manuals and free tutorials, perhaps
+the next person who wants to contribute by writing documentation will
+realize, before it is too late, that only free manuals contribute to
+the free software community.
+
+If you are writing documentation, please insist on publishing it under
+the GNU Free Documentation License or another free documentation
+license. Remember that this decision requires your approval---you
+don't have to let the publisher decide. Some commercial publishers
+will use a free license if you insist, but they will not propose the
+option; it is up to you to raise the issue and say firmly that this is
+what you want. If the publisher you are dealing with refuses, please
+try other publishers. If you're not sure whether a proposed license
+is free, write to @email{licensing@@gnu.org}.
+
+You can encourage commercial publishers to sell more free, copylefted
+manuals and tutorials by buying them, and particularly by buying
+copies from the publishers that paid for their writing or for major
+improvements. Meanwhile, try to avoid buying non-free documentation
+at all. Check the distribution terms of a manual before you buy it,
+and insist that whoever seeks your business must respect your freedom.
+Check the history of the book, and try to reward the publishers that
+have paid or pay the authors to work on it.
+
+The Free Software Foundation maintains a list of free documentation
+published by other publishers, at
+@url{http://www.fsf.org/doc/other-free-books.html}.
+
+@node Contributors
+@unnumberedsec Contributors to @value{GDBN}
+
+Richard Stallman was the original author of @value{GDBN}, 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 many labors as thankless, we
+particularly thank those who shepherded @value{GDBN} through major
+releases:
+Andrew Cagney (releases 6.1, 6.0, 5.3, 5.2, 5.1 and 5.0);
+Jim Blandy (release 4.18);
+Jason Molenda (release 4.17);
+Stan Shebs (release 4.14);
+Fred Fish (releases 4.16, 4.15, 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).
+
+Richard Stallman, assisted at various times by Peter TerMaat, Chris
+Hanson, and Richard Mlynarik, handled releases through 2.8.
+
+Michael Tiemann is the author of most of the @sc{gnu} C@t{++} support
+in @value{GDBN}, with significant additional contributions from Per
+Bothner and Daniel Berlin. James Clark wrote the @sc{gnu} C@t{++}
+demangler. Early work on C@t{++} was by Peter TerMaat (who also did
+much general update work leading to release 3.0).
+
+@value{GDBN} 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.
+
+Brent Benson of Harris Computer Systems contributed DWARF 2 support.
+
+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.
+Marko Mlinar contributed OpenRISC 1000 support.
+
+Andreas Schwab contributed M68K @sc{gnu}/Linux 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, Wind River Systems, AMD, and ARM
+contributed remote debugging modules for the i960, VxWorks, A29K UDI,
+and RDI targets, respectively.
+
+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, the
+Modula-2 support, and contributed the Languages chapter of this manual.
+
+Fred Fish wrote most of the support for Unix System Vr4.
+He also enhanced the command-completion support to cover C@t{++} overloaded
+symbols.
+
+Hitachi America (now Renesas America), Ltd. sponsored the support for
+H8/300, H8/500, and Super-H processors.
+
+NEC sponsored the support for the v850, Vr4xxx, and Vr5xxx processors.
+
+Mitsubishi (now Renesas) sponsored the support for D10V, D30V, and M32R/D
+processors.
+
+Toshiba sponsored the support for the TX39 Mips processor.
+
+Matsushita sponsored the support for the MN10200 and MN10300 processors.
+
+Fujitsu sponsored the support for SPARClite and FR30 processors.
+
+Kung Hsu, Jeff Law, and Rick Sladkey added support for hardware
+watchpoints.
+
+Michael Snyder added support for tracepoints.
+
+Stu Grossman wrote gdbserver.
+
+Jim Kingdon, Peter Schauer, Ian Taylor, and Stu Grossman made
+nearly innumerable bug fixes and cleanups throughout @value{GDBN}.
+
+The following people at the Hewlett-Packard Company contributed
+support for the PA-RISC 2.0 architecture, HP-UX 10.20, 10.30, and 11.0
+(narrow mode), HP's implementation of kernel threads, HP's aC@t{++}
+compiler, and the Text User Interface (nee Terminal User Interface):
+Ben Krepp, Richard Title, John Bishop, Susan Macchia, Kathy Mann,
+Satish Pai, India Paul, Steve Rehrauer, and Elena Zannoni. Kim Haase
+provided HP-specific information in this manual.
+
+DJ Delorie ported @value{GDBN} to MS-DOS, for the DJGPP project.
+Robert Hoehne made significant contributions to the DJGPP port.
+
+Cygnus Solutions has sponsored @value{GDBN} maintenance and much of its
+development since 1991. Cygnus engineers who have worked on @value{GDBN}
+fulltime include Mark Alexander, Jim Blandy, Per Bothner, Kevin
+Buettner, Edith Epstein, Chris Faylor, Fred Fish, Martin Hunt, Jim
+Ingham, John Gilmore, Stu Grossman, Kung Hsu, Jim Kingdon, John Metzler,
+Fernando Nasser, Geoffrey Noer, Dawn Perchik, Rich Pixley, Zdenek
+Radouch, Keith Seitz, Stan Shebs, David Taylor, and Elena Zannoni. In
+addition, Dave Brolley, Ian Carmichael, Steve Chamberlain, Nick Clifton,
+JT Conklin, Stan Cox, DJ Delorie, Ulrich Drepper, Frank Eigler, Doug
+Evans, Sean Fagan, David Henkel-Wallace, Richard Henderson, Jeff
+Holcomb, Jeff Law, Jim Lemke, Tom Lord, Bob Manson, Michael Meissner,
+Jason Merrill, Catherine Moore, Drew Moseley, Ken Raeburn, Gavin
+Romig-Koch, Rob Savoye, Jamie Smith, Mike Stump, Ian Taylor, Angela
+Thomas, Michael Tiemann, Tom Tromey, Ron Unrau, Jim Wilson, and David
+Zuhn have made contributions both large and small.
+
+Jim Blandy added support for preprocessor macros, while working for Red
+Hat.
+
+@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{<QUOTE>} and the close quote string to @code{<UNQUOTE>}, 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(<QUOTE>,<UNQUOTE>)}
+
+@b{define(baz,defn(<QUOTE>foo<UNQUOTE>))}
+@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 1999 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(<QUOTE>,<UNQUOTE>)}
+
+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 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ 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 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ 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 "<QUOTE>"
+(@value{GDBP}) @b{p rquote}
+$2 = 0x35d50 "<UNQUOTE>"
+@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(<QUOTE>foo<UNQUOTE>))}
+
+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
+
+@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 @value{GDBN}.
+@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}
+* Logging output:: How to log @value{GDBN}'s output to a file
+@end menu
+
+@node Invoking GDB
+@section Invoking @value{GDBN}
+
+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.
+
+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.
+
+The most usual way to start @value{GDBN} is with one argument,
+specifying an executable program:
+
+@smallexample
+@value{GDBP} @var{program}
+@end smallexample
+
+@noindent
+You can also start with both an executable program and a core file
+specified:
+
+@smallexample
+@value{GDBP} @var{program} @var{core}
+@end smallexample
+
+You can, instead, specify a process ID as a second argument, if you want
+to debug a running process:
+
+@smallexample
+@value{GDBP} @var{program} 1234
+@end smallexample
+
+@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. @value{GDBN}
+will warn you if it is unable to attach or to read core dumps.
+
+You can optionally have @code{@value{GDBP}} pass any arguments after the
+executable file to the inferior using @code{--args}. This option stops
+option processing.
+@smallexample
+gdb --args gcc -O2 -c foo.c
+@end smallexample
+This will cause @code{@value{GDBP}} to debug @code{gcc}, and to set
+@code{gcc}'s command-line arguments (@pxref{Arguments}) to @samp{-O2 -c foo.c}.
+
+You can run @code{@value{GDBP}} without printing the front material, which describes
+@value{GDBN}'s non-warranty, by specifying @code{-silent}:
+
+@smallexample
+@value{GDBP} -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
+
+@smallexample
+@value{GDBP} -help
+@end smallexample
+
+@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
+* File Options:: Choosing files
+* Mode Options:: Choosing modes
+@end menu
+
+@node File Options
+@subsection Choosing files
+
+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} (or @samp{-p} 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}/@samp{-p} option followed by that argument.)
+If the second argument begins with a decimal digit, @value{GDBN} will
+first attempt to attach to it as a process, and if that fails, attempt
+to open it as a corefile. If you have a corefile whose name begins with
+a digit, you can prevent @value{GDBN} from treating it as a pid by
+prefixing it with @file{./}, eg. @file{./12345}.
+
+If @value{GDBN} has not been configured to included core file support,
+such as for most embedded targets, then it will complain about a second
+argument and ignore it.
+
+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.)
+
+@c NOTE: the @cindex entries here use double dashes ON PURPOSE. This
+@c way, both those who look for -foo and --foo in the index, will find
+@c it.
+
+@table @code
+@item -symbols @var{file}
+@itemx -s @var{file}
+@cindex @code{--symbols}
+@cindex @code{-s}
+Read symbol table from file @var{file}.
+
+@item -exec @var{file}
+@itemx -e @var{file}
+@cindex @code{--exec}
+@cindex @code{-e}
+Use file @var{file} as the executable file to execute when appropriate,
+and for examining pure data in conjunction with a core dump.
+
+@item -se @var{file}
+@cindex @code{--se}
+Read symbol table from file @var{file} and use it as the executable
+file.
+
+@item -core @var{file}
+@itemx -c @var{file}
+@cindex @code{--core}
+@cindex @code{-c}
+Use file @var{file} as a core dump to examine.
+
+@item -c @var{number}
+@item -pid @var{number}
+@itemx -p @var{number}
+@cindex @code{--pid}
+@cindex @code{-p}
+Connect to process ID @var{number}, as with the @code{attach} command.
+If there is no such process, @value{GDBN} will attempt to open a core
+file named @var{number}.
+
+@item -command @var{file}
+@itemx -x @var{file}
+@cindex @code{--command}
+@cindex @code{-x}
+Execute @value{GDBN} commands from file @var{file}. @xref{Command
+Files,, Command files}.
+
+@item -directory @var{directory}
+@itemx -d @var{directory}
+@cindex @code{--directory}
+@cindex @code{-d}
+Add @var{directory} to the path to search for source files.
+
+@item -m
+@itemx -mapped
+@cindex @code{--mapped}
+@cindex @code{-m}
+@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{/tmp/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.
+
+@item -r
+@itemx -readnow
+@cindex @code{--readnow}
+@cindex @code{-r}
+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
+
+You typically combine the @code{-mapped} and @code{-readnow} options in
+order to build a @file{.syms} file that contains complete symbol
+information. (@xref{Files,,Commands to specify files}, for information
+on @file{.syms} files.) A simple @value{GDBN} invocation to do nothing
+but build a @file{.syms} file for future use is:
+
+@smallexample
+gdb -batch -nx -mapped -readnow programname
+@end smallexample
+
+@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
+@cindex @code{--nx}
+@cindex @code{-n}
+Do not execute commands found in any initialization files. Normally,
+@value{GDBN} executes the commands in these files after all the command
+options and arguments have been processed. @xref{Command Files,,Command
+files}.
+
+@item -quiet
+@itemx -silent
+@itemx -q
+@cindex @code{--quiet}
+@cindex @code{--silent}
+@cindex @code{-q}
+``Quiet''. Do not print the introductory and copyright messages. These
+messages are also suppressed in batch mode.
+
+@item -batch
+@cindex @code{--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
+
+@smallexample
+Program exited normally.
+@end smallexample
+
+@noindent
+(which is ordinarily issued whenever a program running under
+@value{GDBN} control terminates) is not issued when running in batch
+mode.
+
+@item -nowindows
+@itemx -nw
+@cindex @code{--nowindows}
+@cindex @code{-nw}
+``No windows''. If @value{GDBN} comes with a graphical user interface
+(GUI) built in, then this option tells @value{GDBN} to only use the command-line
+interface. If no GUI is available, this option has no effect.
+
+@item -windows
+@itemx -w
+@cindex @code{--windows}
+@cindex @code{-w}
+If @value{GDBN} includes a GUI, then this option requires it to be
+used if possible.
+
+@item -cd @var{directory}
+@cindex @code{--cd}
+Run @value{GDBN} using @var{directory} as its working directory,
+instead of the current directory.
+
+@item -fullname
+@itemx -f
+@cindex @code{--fullname}
+@cindex @code{-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.
+
+@item -epoch
+@cindex @code{--epoch}
+The Epoch Emacs-@value{GDBN} interface sets this option when it runs
+@value{GDBN} as a subprocess. It tells @value{GDBN} to modify its print
+routines so as to allow Epoch to display values of expressions in a
+separate window.
+
+@item -annotate @var{level}
+@cindex @code{--annotate}
+This option sets the @dfn{annotation level} inside @value{GDBN}. Its
+effect is identical to using @samp{set annotate @var{level}}
+(@pxref{Annotations}). The annotation @var{level} controls how much
+information @value{GDBN} prints together with its prompt, values of
+expressions, source lines, and other types of output. Level 0 is the
+normal, level 1 is for use when @value{GDBN} is run as a subprocess of
+@sc{gnu} Emacs, level 3 is the maximum annotation suitable for programs
+that control @value{GDBN}, and level 2 has been deprecated.
+
+The annotation mechanism has largely been superseeded by @sc{gdb/mi}
+(@pxref{GDB/MI}).
+
+@item -async
+@cindex @code{--async}
+Use the asynchronous event loop for the command-line interface.
+@value{GDBN} processes all events, such as user keyboard input, via a
+special event loop. This allows @value{GDBN} to accept and process user
+commands in parallel with the debugged process being
+run@footnote{@value{GDBN} built with @sc{djgpp} tools for
+MS-DOS/MS-Windows supports this mode of operation, but the event loop is
+suspended when the debuggee runs.}, so you don't need to wait for
+control to return to @value{GDBN} before you type the next command.
+(@emph{Note:} as of version 5.1, the target side of the asynchronous
+operation is not yet in place, so @samp{-async} does not work fully
+yet.)
+@c FIXME: when the target side of the event loop is done, the above NOTE
+@c should be removed.
+
+When the standard input is connected to a terminal device, @value{GDBN}
+uses the asynchronous event loop by default, unless disabled by the
+@samp{-noasync} option.
+
+@item -noasync
+@cindex @code{--noasync}
+Disable the asynchronous event loop for the command-line interface.
+
+@item --args
+@cindex @code{--args}
+Change interpretation of command line so that arguments following the
+executable file are passed as command line arguments to the inferior.
+This option stops option processing.
+
+@item -baud @var{bps}
+@itemx -b @var{bps}
+@cindex @code{--baud}
+@cindex @code{-b}
+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}
+@itemx -t @var{device}
+@cindex @code{--tty}
+@cindex @code{-t}
+Run using @var{device} for your program's standard input and output.
+@c FIXME: kingdon thinks there is more to -tty. Investigate.
+
+@c resolve the situation of these eventually
+@item -tui
+@cindex @code{--tui}
+Activate the @dfn{Text User Interface} when starting. The Text User
+Interface manages several text windows on the terminal, showing
+source, assembly, registers and @value{GDBN} command outputs
+(@pxref{TUI, ,@value{GDBN} Text User Interface}). Alternatively, the
+Text User Interface can be enabled by invoking the program
+@samp{gdbtui}. Do not use this option if you run @value{GDBN} from
+Emacs (@pxref{Emacs, ,Using @value{GDBN} under @sc{gnu} Emacs}).
+
+@c @item -xdb
+@c @cindex @code{--xdb}
+@c Run in XDB compatibility mode, allowing the use of certain XDB commands.
+@c For information, see the file @file{xdb_trans.html}, which is usually
+@c installed in the directory @code{/opt/langtools/wdb/doc} on HP-UX
+@c systems.
+
+@item -interpreter @var{interp}
+@cindex @code{--interpreter}
+Use the interpreter @var{interp} for interface with the controlling
+program or device. This option is meant to be set by programs which
+communicate with @value{GDBN} using it as a back end.
+@xref{Interpreters, , Command Interpreters}.
+
+@samp{--interpreter=mi} (or @samp{--interpreter=mi2}) causes
+@value{GDBN} to use the @dfn{@sc{gdb/mi} interface} (@pxref{GDB/MI, ,
+The @sc{gdb/mi} Interface}) included since @var{GDBN} version 6.0. The
+previous @sc{gdb/mi} interface, included in @value{GDBN} version 5.3 and
+selected with @samp{--interpreter=mi1}, is deprecated. Earlier
+@sc{gdb/mi} interfaces are no longer supported.
+
+@item -write
+@cindex @code{--write}
+Open the executable and core files for both reading and writing. This
+is equivalent to the @samp{set write on} command inside @value{GDBN}
+(@pxref{Patching}).
+
+@item -statistics
+@cindex @code{--statistics}
+This option causes @value{GDBN} to print statistics about time and
+memory usage after it completes each command and returns to the prompt.
+
+@item -version
+@cindex @code{--version}
+This option causes @value{GDBN} to print its version number and
+no-warranty blurb, and exit.
+
+@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 @r{(@code{quit})}
+@item quit @r{[}@var{expression}@r{]}
+@itemx q
+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.
+
+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}).
+
+@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 standard shell to execute @var{command string}.
+If it exists, the environment variable @code{SHELL} determines which
+shell to run. Otherwise @value{GDBN} uses the default shell
+(@file{/bin/sh} on Unix systems, @file{COMMAND.COM} on MS-DOS, etc.).
+@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 Logging output
+@section Logging output
+@cindex logging @value{GDBN} output
+
+You may want to save the output of @value{GDBN} commands to a file.
+There are several commands to control @value{GDBN}'s logging.
+
+@table @code
+@kindex set logging
+@item set logging on
+Enable logging.
+@item set logging off
+Disable logging.
+@item set logging file @var{file}
+Change the name of the current logfile. The default logfile is @file{gdb.txt}.
+@item set logging overwrite [on|off]
+By default, @value{GDBN} will append to the logfile. Set @code{overwrite} if
+you want @code{set logging on} to overwrite the logfile instead.
+@item set logging redirect [on|off]
+By default, @value{GDBN} output will go to both the terminal and the logfile.
+Set @code{redirect} if you want output to go only to the log file.
+@kindex show logging
+@item show logging
+Show the current values of the logging settings.
+@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 commands 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 @r{(repeat last command)}
+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 # @r{(a comment)}
+@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}).
+
+@cindex repeating command sequences
+@kindex C-o @r{(operate-and-get-next)}
+The @kbd{C-o} binding is useful for repeating a complex sequence of
+commands. This command accepts the current line, like @kbd{RET}, and
+then fetches the next line relative to the current line from the history
+for editing.
+
+@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...
+@smallexample
+(@value{GDBP}) info bre @key{TAB}
+@end smallexample
+
+@noindent
+@value{GDBN} fills in the rest of the word @samp{breakpoints}, since that is
+the only @code{info} subcommand beginning with @samp{bre}:
+
+@smallexample
+(@value{GDBP}) info breakpoints
+@end smallexample
+
+@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:
+
+@smallexample
+(@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 smallexample
+
+@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 either by holding down a
+key designated as the @key{META} shift on your keyboard (if there is
+one) while typing @kbd{?}, or 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.
+
+The most likely situation where you might need this is in typing the
+name of a C@t{++} function. This is because C@t{++} 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:
+
+@smallexample
+(@value{GDBP}) b 'bubble( @kbd{M-?}
+bubble(double,double) bubble(int,int)
+(@value{GDBP}) b 'bubble(
+@end smallexample
+
+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:
+
+@smallexample
+(@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 smallexample
+
+@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.
+
+For more information about overloaded functions, see @ref{C plus plus
+expressions, ,C@t{++} expressions}. You can use the command @code{set
+overload-resolution off} to disable overload resolution;
+see @ref{Debugging C plus plus, ,@value{GDBN} features for C@t{++}}.
+
+
+@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 @r{(@code{help})}
+@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:
+
+aliases -- Aliases of other commands
+breakpoints -- Making program stop at certain points
+data -- Examining data
+files -- Specifying and examining files
+internals -- Maintenance commands
+obscure -- Obscure features
+running -- Running the program
+stack -- Examining the stack
+status -- Status inquiries
+support -- Support facilities
+tracepoints -- Tracing of program execution without@*
+ stopping the program
+user-defined -- User-defined commands
+
+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
+@c the above line break eliminates huge line overfull...
+
+@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.
+info -- Generic command for showing things
+ about the program being debugged
+show -- Generic command for showing things
+ about the debugger
+
+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 apropos
+@item apropos @var{args}
+The @code{apropos @var{args}} command searches through all of the @value{GDBN}
+commands, and their documentation, for the regular expression specified in
+@var{args}. It prints out all matches found. For example:
+
+@smallexample
+apropos reload
+@end smallexample
+
+@noindent
+results in:
+
+@smallexample
+@c @group
+set symbol-reloading -- Set dynamic symbol table reloading
+ multiple times in one run
+show symbol-reloading -- Show dynamic symbol table reloading
+ multiple times in one run
+@c @end group
+@end smallexample
+
+@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
+@group
+if
+ignore
+info
+inspect
+@end group
+@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 @r{(@code{info})}
+@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 expression 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 need to determine which
+version of @value{GDBN} you are running; as @value{GDBN} evolves, new
+commands are introduced, and old ones may wither away. Also, many
+system vendors ship variant versions of @value{GDBN}, and there are
+variant versions of @value{GDBN} in @sc{gnu}/Linux distributions as well.
+The version number is the same as the one 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, or a warranty,
+if your version of @value{GDBN} comes with one.
+
+@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.
+
+You may start @value{GDBN} with its arguments, if any, in an environment
+of your choice. If you are doing native debugging, you may redirect
+your program's input and output, debug an already running process, or
+kill a child process.
+
+@menu
+* Compilation:: Compiling for debugging
+* Starting:: Starting your program
+* 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
+
+* Threads:: Debugging programs with multiple threads
+* Processes:: Debugging programs with multiple processes
+@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.
+
+Most compilers do not include information about preprocessor macros in
+the debugging information if you specify the @option{-g} flag alone,
+because this information is rather large. Version 3.1 of @value{NGCC},
+the @sc{gnu} C compiler, provides macro information if you specify the
+options @option{-gdwarf-2} and @option{-g3}; the former option requests
+debugging information in the Dwarf 2 format, and the latter requests
+``extra information''. In the future, we hope to find more compact ways
+to represent macro information, so that it can be included with
+@option{-g} alone.
+
+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
+@kindex r @r{(@code{run})}
+@item run
+@itemx r
+Use the @code{run} command to start your program under @value{GDBN}.
+You must first specify the program name (except on VxWorks) 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
+
+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
+
+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.
+
+@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
+the default shell (@file{/bin/sh} on Unix).
+
+On non-Unix systems, the program is usually invoked directly by
+@value{GDBN}, which emulates I/O redirection via the appropriate system
+calls, and the wildcard characters are expanded by the startup code of
+the program, not by the shell.
+
+@code{run} with no arguments uses the same arguments used by the previous
+@code{run}, or those set by the @code{set args} command.
+
+@table @code
+@kindex set args
+@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) that will be passed to your program.
+The value of @code{PATH} used by @value{GDBN} does not change.
+You may specify several directory names, separated by whitespace or by a
+system-dependent separator character (@samp{:} on Unix, @samp{;} on
+MS-DOS and MS-Windows). 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{[}=@var{value}@r{]}
+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:
+
+@smallexample
+set env USER = foo
+@end smallexample
+
+@noindent
+tells the debugged 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:} On Unix systems, @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,
+
+@smallexample
+run > outfile
+@end smallexample
+
+@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,
+
+@smallexample
+tty /dev/ttyb
+@end smallexample
+
+@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 you use @code{attach}, the debugger finds the program running in
+the process first by looking in the current working directory, then (if
+the program is not found) by using the source file search path
+(@pxref{Source Path, ,Specifying source directories}). You can also use
+the @code{file} command to load the program. @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
+@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.
+
+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 Threads
+@section Debugging programs with multiple threads
+
+@cindex threads of execution
+@cindex multiple threads
+@cindex switching threads
+In some operating systems, such as HP-UX and Solaris, 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.
+
+@cindex @code{New} @var{systag} message
+@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
+
+@smallexample
+[New process 35 thread 27]
+@end smallexample
+
+@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
+
+On HP-UX systems:
+
+@cindex thread number
+@cindex thread identifier (GDB)
+For debugging purposes, @value{GDBN} associates its own thread
+number---a small integer assigned in thread-creation order---with each
+thread in your program.
+
+@cindex @code{New} @var{systag} message, on HP-UX
+@cindex thread identifier (system), on HP-UX
+@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
+both @value{GDBN}'s thread number and 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
+HP-UX, you see
+
+@smallexample
+[New thread 2 (system thread 26594)]
+@end smallexample
+
+@noindent
+when @value{GDBN} notices a new thread.
+
+@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 system thread 26607 worker (wptr=0x7b09c318 "@@") \@*
+ at quicksort.c:137
+ 2 system thread 26606 0x7b0030d8 in __ksleep () \@*
+ from /usr/lib/libc.2
+ 1 system thread 27905 0x7b003498 in _brk () \@*
+ from /usr/lib/libc.2
+@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.
+
+@node Processes
+@section Debugging programs with multiple processes
+
+@cindex fork, debugging programs which call
+@cindex multiple processes
+@cindex processes, multiple
+On most systems, @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 (@pxref{Attach}). From that point on you can debug
+the child process just like any other process which you attached to.
+
+On some systems, @value{GDBN} provides support for debugging programs that
+create additional processes using the @code{fork} or @code{vfork} functions.
+Currently, the only platforms with this feature are HP-UX (11.x and later
+only?) and GNU/Linux (kernel version 2.5.60 and later).
+
+By default, when a program forks, @value{GDBN} will continue to debug
+the parent process and the child process will run unimpeded.
+
+If you want to follow the child process instead of the parent process,
+use the command @w{@code{set follow-fork-mode}}.
+
+@table @code
+@kindex set follow-fork-mode
+@item set follow-fork-mode @var{mode}
+Set the debugger response to a program call of @code{fork} or
+@code{vfork}. A call to @code{fork} or @code{vfork} creates a new
+process. The @var{mode} can be:
+
+@table @code
+@item parent
+The original process is debugged after a fork. The child process runs
+unimpeded. This is the default.
+
+@item child
+The new process is debugged after a fork. The parent process runs
+unimpeded.
+
+@end table
+
+@item show follow-fork-mode
+Display the current debugger response to a @code{fork} or @code{vfork} call.
+@end table
+
+If you ask to debug a child process and a @code{vfork} is followed by an
+@code{exec}, @value{GDBN} executes the new target up to the first
+breakpoint in the new target. If you have a breakpoint set on
+@code{main} in your original program, the breakpoint will also be set on
+the child process's @code{main}.
+
+When a child process is spawned by @code{vfork}, you cannot debug the
+child or parent until an @code{exec} call completes.
+
+If you issue a @code{run} command to @value{GDBN} after an @code{exec}
+call executes, the new target restarts. To restart the parent process,
+use the @code{file} command with the parent executable name as its
+argument.
+
+You can use the @code{catch} command to make @value{GDBN} stop whenever
+a @code{fork}, @code{vfork}, or @code{exec} call is made. @xref{Set
+Catchpoints, ,Setting catchpoints}.
+
+@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 a signal, 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, what process it is, and why it stopped.
+@end table
+
+@menu
+* Breakpoints:: Breakpoints, watchpoints, and catchpoints
+* Continuing and Stepping:: Resuming execution
+* Signals:: Signals
+* Thread Stops:: Stopping and starting multi-thread programs
+@end menu
+
+@node Breakpoints
+@section Breakpoints, watchpoints, and catchpoints
+
+@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.
+
+In HP-UX, SunOS 4.x, SVR4, and Alpha OSF/1 configurations, you can set
+breakpoints in shared libraries before the executable is run. There is
+a minor limitation on HP-UX systems: you must wait until the executable
+is run in order to set breakpoints in shared library routines that are
+not called directly by the program (for example, routines that are
+arguments in a @code{pthread_create} call).
+
+@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 catchpoints
+@cindex breakpoint on events
+A @dfn{catchpoint} is another special breakpoint that stops your program
+when a certain kind of event occurs, such as the throwing of a C@t{++}
+exception or the loading of a library. As with watchpoints, you use a
+different command to set a catchpoint (@pxref{Set Catchpoints, ,Setting
+catchpoints}), but aside from that, you can manage a catchpoint like any
+other breakpoint. (To stop when your program receives a signal, use the
+@code{handle} command; see @ref{Signals, ,Signals}.)
+
+@cindex breakpoint numbers
+@cindex numbers for breakpoints
+@value{GDBN} assigns a number to each breakpoint, watchpoint, or
+catchpoint 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.
+
+@cindex breakpoint ranges
+@cindex ranges of breakpoints
+Some @value{GDBN} commands accept a range of breakpoints on which to
+operate. A breakpoint range is either a single breakpoint number, like
+@samp{5}, or two such numbers, in increasing order, separated by a
+hyphen, like @samp{5-7}. When a breakpoint range is given to a command,
+all breakpoint in that range are operated on.
+
+@menu
+* Set Breaks:: Setting breakpoints
+* Set Watchpoints:: Setting watchpoints
+* Set Catchpoints:: Setting catchpoints
+* Delete Breaks:: Deleting breakpoints
+* Disabling:: Disabling breakpoints
+* Conditions:: Break conditions
+* Break Commands:: Breakpoint command lists
+* Breakpoint Menus:: Breakpoint menus
+* Error in Breakpoints:: ``Cannot insert breakpoints''
+* Breakpoint related warnings:: ``Breakpoint address adjusted...''
+@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 @r{(@code{break})}
+@vindex $bpnum@r{, convenience variable}
+@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 breakpoint 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}.
+When using source languages that permit overloading of symbols, such as
+C@t{++}, @var{function} may refer to more than one possible place to break.
+@xref{Breakpoint Menus,,Breakpoint menus}, for a discussion of that situation.
+
+@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 @dfn{stack frame}.
+(@xref{Frames, ,Frames}, for a description of stack frames.)
+
+@item break @var{linenum}
+Set a breakpoint at line @var{linenum} in the current source file.
+The current source file is the last file whose source text was printed.
+The breakpoint will stop 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 and some x86-based targets. These targets
+will generate traps when a program accesses some data or instruction
+address that is assigned to the debug registers. However the hardware
+breakpoint registers can take a limited number of breakpoints. For
+example, on the DSU, only two data breakpoints can be set at a time, and
+@value{GDBN} will reject this command if more than two are used. Delete
+or disable unused hardware breakpoints before setting new ones
+(@pxref{Disabling, ,Disabling}). @xref{Conditions, ,Break conditions}.
+@xref{set remote hardware-breakpoint-limit}.
+
+
+@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}.
+See also @ref{Conditions, ,Break conditions}.
+
+@kindex rbreak
+@cindex regular expression
+@item rbreak @var{regex}
+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.
+
+The syntax of the regular expression is the standard one used with tools
+like @file{grep}. Note that this is different from the syntax used by
+shells, so for instance @code{foo*} matches all functions that include
+an @code{fo} followed by zero or more @code{o}s. There is an implicit
+@code{.*} leading and trailing the regular expression you supply, so to
+match only functions that begin with @code{foo}, use @code{^foo}.
+
+When debugging C@t{++} programs, @code{rbreak} is useful for setting
+breakpoints on overloaded functions that are not members of any special
+classes.
+
+@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, watchpoints, and catchpoints set and
+not deleted, with the following columns for each breakpoint:
+
+@table @emph
+@item Breakpoint Numbers
+@item Type
+Breakpoint, watchpoint, or catchpoint.
+@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. If the
+breakpoint is pending (see below for details) on a future load of a shared library, the address
+will be listed as @samp{<PENDING>}.
+@item What
+Where the breakpoint is in the source for your program, as a file and
+line number. For a pending breakpoint, the original string passed to
+the breakpoint command will be listed as it cannot be resolved until
+the appropriate shared library is loaded in the future.
+@end table
+
+@noindent
+If a breakpoint is conditional, @code{info break} shows the condition on
+the line following the affected breakpoint; breakpoint commands, if any,
+are listed after that. A pending breakpoint is allowed to have a condition
+specified for it. The condition is not parsed for validity until a shared
+library is loaded that allows the pending breakpoint to resolve to a
+valid location.
+
+@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} 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 pending breakpoints
+If a specified breakpoint location cannot be found, it may be due to the fact
+that the location is in a shared library that is yet to be loaded. In such
+a case, you may want @value{GDBN} to create a special breakpoint (known as
+a @dfn{pending breakpoint}) that
+attempts to resolve itself in the future when an appropriate shared library
+gets loaded.
+
+Pending breakpoints are useful to set at the start of your
+@value{GDBN} session for locations that you know will be dynamically loaded
+later by the program being debugged. When shared libraries are loaded,
+a check is made to see if the load resolves any pending breakpoint locations.
+If a pending breakpoint location gets resolved,
+a regular breakpoint is created and the original pending breakpoint is removed.
+
+@value{GDBN} provides some additional commands for controlling pending
+breakpoint support:
+
+@kindex set breakpoint pending
+@kindex show breakpoint pending
+@table @code
+@item set breakpoint pending auto
+This is the default behavior. When @value{GDBN} cannot find the breakpoint
+location, it queries you whether a pending breakpoint should be created.
+
+@item set breakpoint pending on
+This indicates that an unrecognized breakpoint location should automatically
+result in a pending breakpoint being created.
+
+@item set breakpoint pending off
+This indicates that pending breakpoints are not to be created. Any
+unrecognized breakpoint location results in an error. This setting does
+not affect any pending breakpoints previously created.
+
+@item show breakpoint pending
+Show the current behavior setting for creating pending breakpoints.
+@end table
+
+@cindex operations allowed on pending breakpoints
+Normal breakpoint operations apply to pending breakpoints as well. You may
+specify a condition for a pending breakpoint and/or commands to run when the
+breakpoint is reached. You can also enable or disable
+the pending breakpoint. When you specify a condition for a pending breakpoint,
+the parsing of the condition will be deferred until the point where the
+pending breakpoint location is resolved. Disabling a pending breakpoint
+tells @value{GDBN} to not attempt to resolve the breakpoint on any subsequent
+shared library load. When a pending breakpoint is re-enabled,
+@value{GDBN} checks to see if the location is already resolved.
+This is done because any number of shared library loads could have
+occurred since the time the breakpoint was disabled and one or more
+of these loads could resolve the location.
+
+@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} (@pxref{maint info breakpoints}).
+
+
+@node Set Watchpoints
+@subsection Setting watchpoints
+
+@cindex setting watchpoints
+@cindex software watchpoints
+@cindex hardware 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.
+
+Depending on your system, watchpoints may be implemented in software or
+hardware. @value{GDBN} does software watchpointing by single-stepping your
+program and testing the variable's value each time, which is hundreds of
+times slower than normal execution. (But this may still be worth it, to
+catch errors where you have no clue what part of your program is the
+culprit.)
+
+On some systems, such as HP-UX, @sc{gnu}/Linux and some other x86-based targets,
+@value{GDBN} includes support for
+hardware watchpoints, which do not slow down the running of your
+program.
+
+@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.
+
+@kindex rwatch
+@item rwatch @var{expr}
+Set a watchpoint that will break when watch @var{expr} is read by the program.
+
+@kindex awatch
+@item awatch @var{expr}
+Set a watchpoint that will break when @var{expr} is either read or written into
+by the program.
+
+@kindex info watchpoints
+@item info watchpoints
+This command prints a list of watchpoints, breakpoints, and catchpoints;
+it is the same as @code{info break}.
+@end table
+
+@value{GDBN} sets a @dfn{hardware watchpoint} if possible. Hardware
+watchpoints execute very quickly, and the debugger reports a change in
+value at the exact instruction where the change occurs. If @value{GDBN}
+cannot set a hardware watchpoint, it sets a software watchpoint, which
+executes more slowly and reports the change in value at the next
+statement, not the instruction, after the change occurs.
+
+When you issue the @code{watch} command, @value{GDBN} reports
+
+@smallexample
+Hardware watchpoint @var{num}: @var{expr}
+@end smallexample
+
+@noindent
+if it was able to set a hardware watchpoint.
+
+Currently, the @code{awatch} and @code{rwatch} commands can only set
+hardware watchpoints, because accesses to data that don't change the
+value of the watched expression cannot be detected without examining
+every instruction as it is being executed, and @value{GDBN} does not do
+that currently. If @value{GDBN} finds that it is unable to set a
+hardware breakpoint with the @code{awatch} or @code{rwatch} command, it
+will print a message like this:
+
+@smallexample
+Expression cannot be implemented with read/access watchpoint.
+@end smallexample
+
+Sometimes, @value{GDBN} cannot set a hardware watchpoint because the
+data type of the watched expression is wider than what a hardware
+watchpoint on the target machine can handle. For example, some systems
+can only watch regions that are up to 4 bytes wide; on such systems you
+cannot set hardware watchpoints for an expression that yields a
+double-precision floating-point number (which is typically 8 bytes
+wide). As a work-around, it might be possible to break the large region
+into a series of smaller ones and watch them with separate watchpoints.
+
+If you set too many hardware watchpoints, @value{GDBN} might be unable
+to insert all of them when you resume the execution of your program.
+Since the precise number of active watchpoints is unknown until such
+time as the program is about to be resumed, @value{GDBN} might not be
+able to warn you about this when you set the watchpoints, and the
+warning will be printed only when the program is resumed:
+
+@smallexample
+Hardware watchpoint @var{num}: Could not insert watchpoint
+@end smallexample
+
+@noindent
+If this happens, delete or disable some of the watchpoints.
+
+The SPARClite DSU will generate traps when a program accesses some data
+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{GDBN} will reject the command if you try to mix watchpoints.
+Delete or disable unused watchpoint commands before setting new ones.
+
+If you call a function interactively using @code{print} or @code{call},
+any watchpoints you have set will be inactive until @value{GDBN} reaches another
+kind of breakpoint or the call completes.
+
+@value{GDBN} automatically deletes watchpoints that watch local
+(automatic) variables, or expressions that involve such variables, when
+they go out of scope, that is, when the execution leaves the block in
+which these variables were defined. In particular, when the program
+being debugged terminates, @emph{all} local variables go out of scope,
+and so only watchpoints that watch global variables remain set. If you
+rerun the program, you will need to set all such watchpoints again. One
+way of doing that would be to set a code breakpoint at the entry to the
+@code{main} function and when it breaks, set all the watchpoints.
+
+@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.
+
+@c FIXME: this is almost identical to the previous paragraph.
+@emph{HP-UX Warning:} In multi-thread programs, software watchpoints
+have only limited usefulness. If @value{GDBN} creates a software
+watchpoint, it 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
+software watchpoints as usual. However, @value{GDBN} may not notice
+when a non-current thread's activity changes the expression. (Hardware
+watchpoints, in contrast, watch an expression in all threads.)
+@end quotation
+
+@xref{set remote hardware-watchpoint-limit}.
+
+@node Set Catchpoints
+@subsection Setting catchpoints
+@cindex catchpoints, setting
+@cindex exception handlers
+@cindex event handling
+
+You can use @dfn{catchpoints} to cause the debugger to stop for certain
+kinds of program events, such as C@t{++} exceptions or the loading of a
+shared library. Use the @code{catch} command to set a catchpoint.
+
+@table @code
+@kindex catch
+@item catch @var{event}
+Stop when @var{event} occurs. @var{event} can be any of the following:
+@table @code
+@item throw
+@kindex catch throw
+The throwing of a C@t{++} exception.
+
+@item catch
+@kindex catch catch
+The catching of a C@t{++} exception.
+
+@item exec
+@kindex catch exec
+A call to @code{exec}. This is currently only available for HP-UX.
+
+@item fork
+@kindex catch fork
+A call to @code{fork}. This is currently only available for HP-UX.
+
+@item vfork
+@kindex catch vfork
+A call to @code{vfork}. This is currently only available for HP-UX.
+
+@item load
+@itemx load @var{libname}
+@kindex catch load
+The dynamic loading of any shared library, or the loading of the library
+@var{libname}. This is currently only available for HP-UX.
+
+@item unload
+@itemx unload @var{libname}
+@kindex catch unload
+The unloading of any dynamically loaded shared library, or the unloading
+of the library @var{libname}. This is currently only available for HP-UX.
+@end table
+
+@item tcatch @var{event}
+Set a catchpoint that is enabled only for one stop. The catchpoint is
+automatically deleted after the first time the event is caught.
+
+@end table
+
+Use the @code{info break} command to list the current catchpoints.
+
+There are currently some limitations to C@t{++} exception handling
+(@code{catch throw} and @code{catch catch}) 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 either to abort or to
+simply continue running until it hits a breakpoint, catches a signal
+that @value{GDBN} is listening for, or exits. This is the case even if
+you set a catchpoint for the exception; catchpoints on exceptions are
+disabled within interactive calls.
+
+@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@t{++}, exceptions are
+raised by calling a library function named @code{__raise_exception}
+which has the following ANSI C interface:
+
+@smallexample
+ /* @var{addr} is where the exception identifier is stored.
+ @var{id} is the exception identifier. */
+ void __raise_exception (void **addr, void *id);
+@end smallexample
+
+@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.
+
+
+@node Delete Breaks
+@subsection Deleting breakpoints
+
+@cindex clearing breakpoints, watchpoints, catchpoints
+@cindex deleting breakpoints, watchpoints, catchpoints
+It is often necessary to eliminate a breakpoint, watchpoint, or
+catchpoint 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, watchpoints, or catchpoints 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
+@kindex clear
+@item 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 @r{(@code{delete})}
+@item delete @r{[}breakpoints@r{]} @r{[}@var{range}@dots{}@r{]}
+Delete the breakpoints, watchpoints, or catchpoints of the breakpoint
+ranges 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, watchpoint, or catchpoint, 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, watchpoints, and catchpoints 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, watchpoints, and
+catchpoints if you do not know which numbers to use.
+
+A breakpoint, watchpoint, or catchpoint 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.
+@item
+Enabled for deletion. The breakpoint stops your program, but
+immediately after it does so it is deleted permanently. A breakpoint
+set with the @code{tbreak} command starts out in this state.
+@end itemize
+
+You can use the following commands to enable or disable breakpoints,
+watchpoints, and catchpoints:
+
+@table @code
+@kindex disable breakpoints
+@kindex disable
+@kindex dis @r{(@code{disable})}
+@item disable @r{[}breakpoints@r{]} @r{[}@var{range}@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{range}@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{range}@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{range}@dots{}
+Enable the specified breakpoints to work once, then die. @value{GDBN}
+deletes any of these breakpoints as soon as your program stops there.
+@end table
+
+@c FIXME: I think the following ``Except for [...] @code{tbreak}'' is
+@c confusing: tbreak is also initially enabled.
+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 than break
+conditions 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.
+
+You can also use the @code{if} keyword with the @code{watch} command.
+The @code{catch} command does not recognize the @code{if} keyword;
+@code{condition} is the only way to impose a further condition on a
+catchpoint.
+
+@table @code
+@kindex condition
+@item condition @var{bnum} @var{expression}
+Specify @var{expression} as the break condition for breakpoint,
+watchpoint, or catchpoint 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. If @var{expression} uses
+symbols not referenced in the context of the breakpoint, @value{GDBN}
+prints an error message:
+
+@smallexample
+No symbol "foo" in current context.
+@end smallexample
+
+@noindent
+@value{GDBN} does
+not actually evaluate @var{expression} at the time the @code{condition}
+command (or a command that sets a breakpoint with a condition, like
+@code{break if @dots{}}) 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
+
+Ignore counts apply to breakpoints, watchpoints, and catchpoints.
+
+
+@node Break Commands
+@subsection Breakpoint command lists
+
+@cindex breakpoint commands
+You can give any breakpoint (or watchpoint or catchpoint) 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, watchpoint, or catchpoint 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.
+
+@smallexample
+break foo if x>0
+commands
+silent
+printf "x is %d\n",x
+cont
+end
+@end smallexample
+
+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:
+
+@smallexample
+break 403
+commands
+silent
+set x = y + 4
+cont
+end
+@end smallexample
+
+@node Breakpoint Menus
+@subsection Breakpoint menus
+@cindex overloading
+@cindex symbol overloading
+
+Some programming languages (notably C@t{++} and Objective-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
+@group
+(@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 group
+@end smallexample
+
+@c @ifclear BARETARGET
+@node Error in Breakpoints
+@subsection ``Cannot insert breakpoints''
+@c
+@c FIXME!! 14/6/95 Is there a real example of this? Let's use it.
+@c
+Under some operating systems, breakpoints cannot be used in a program if
+any other process is running that program. In this situation,
+attempting to run or continue a program with a breakpoint causes
+@value{GDBN} to print an error message:
+
+@smallexample
+Cannot insert breakpoints.
+The same program may be running in another process.
+@end smallexample
+
+When this happens, you have three ways to proceed:
+
+@enumerate
+@item
+Remove or disable the breakpoints, then continue.
+
+@item
+Suspend @value{GDBN}, and copy the file containing your program to a new
+name. Resume @value{GDBN} and use the @code{exec-file} command to specify
+that @value{GDBN} should run your program under that name.
+Then start your program again.
+
+@item
+Relink your program so that the text segment is nonsharable, using the
+linker option @samp{-N}. The operating system limitation may not apply
+to nonsharable executables.
+@end enumerate
+@c @end ifclear
+
+A similar message can be printed if you request too many active
+hardware-assisted breakpoints and watchpoints:
+
+@c FIXME: the precise wording of this message may change; the relevant
+@c source change is not committed yet (Sep 3, 1999).
+@smallexample
+Stopped; cannot insert breakpoints.
+You may have requested too many hardware breakpoints and watchpoints.
+@end smallexample
+
+@noindent
+This message is printed when you attempt to resume the program, since
+only then @value{GDBN} knows exactly how many hardware breakpoints and
+watchpoints it needs to insert.
+
+When this message is printed, you need to disable or remove some of the
+hardware-assisted breakpoints and watchpoints, and then continue.
+
+@node Breakpoint related warnings
+@subsection ``Breakpoint address adjusted...''
+@cindex breakpoint address adjusted
+
+Some processor architectures place constraints on the addresses at
+which breakpoints may be placed. For architectures thus constrained,
+@value{GDBN} will attempt to adjust the breakpoint's address to comply
+with the constraints dictated by the architecture.
+
+One example of such an architecture is the Fujitsu FR-V. The FR-V is
+a VLIW architecture in which a number of RISC-like instructions may be
+bundled together for parallel execution. The FR-V architecture
+constrains the location of a breakpoint instruction within such a
+bundle to the instruction with the lowest address. @value{GDBN}
+honors this constraint by adjusting a breakpoint's address to the
+first in the bundle.
+
+It is not uncommon for optimized code to have bundles which contain
+instructions from different source statements, thus it may happen that
+a breakpoint's address will be adjusted from one source statement to
+another. Since this adjustment may significantly alter @value{GDBN}'s
+breakpoint related behavior from what the user expects, a warning is
+printed when the breakpoint is first set and also when the breakpoint
+is hit.
+
+A warning like the one below is printed when setting a breakpoint
+that's been subject to address adjustment:
+
+@smallexample
+warning: Breakpoint address adjusted from 0x00010414 to 0x00010410.
+@end smallexample
+
+Such warnings are printed both for user settable and @value{GDBN}'s
+internal breakpoints. If you see one of these warnings, you should
+verify that a breakpoint set at the adjusted address will have the
+desired affect. If not, the breakpoint in question may be removed and
+other breakpoints may be set which will have the desired behavior.
+E.g., it may be sufficient to place the breakpoint at a later
+instruction. A conditional breakpoint may also be useful in some
+cases to prevent the breakpoint from triggering too often.
+
+@value{GDBN} will also issue a warning when stopping at one of these
+adjusted breakpoints:
+
+@smallexample
+warning: Breakpoint 1 address previously adjusted from 0x00010414
+to 0x00010410.
+@end smallexample
+
+When this warning is encountered, it may be too late to take remedial
+action except in cases where the breakpoint is hit earlier or more
+frequently than expected.
+
+@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 a breakpoint or a signal. (If
+it stops due to a signal, you may want to use @code{handle}, or use
+@samp{signal 0} to resume execution. @xref{Signals, ,Signals}.)
+
+@table @code
+@kindex continue
+@kindex c @r{(@code{continue})}
+@kindex fg @r{(resume foreground execution)}
+@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} (for @dfn{foreground}, as the
+debugged program is deemed to be the foreground program) 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
+(@pxref{Breakpoints, ,Breakpoints; watchpoints; and catchpoints}) 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 @r{(@code{step})}
+@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 only stops at the first instruction of a source
+line. This prevents the multiple stops that could otherwise occur in
+@code{switch} statements, @code{for} loops, etc. @code{step} continues
+to stop if a function that has debugging information is called within
+the line. In other words, @code{step} @emph{steps inside} any functions
+called within the line.
+
+Also, the @code{step} command only enters a function if there is line
+number information for the function. Otherwise it acts like the
+@code{next} command. This avoids problems when using @code{cc -gl}
+on MIPS machines. Previously, @code{step} entered subroutines if there
+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, or a signal not related to stepping occurs before
+@var{count} steps, stepping stops right away.
+
+@kindex next
+@kindex n @r{(@code{next})}
+@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 only stops at the first instruction of a
+source line. This prevents multiple stops that could otherwise occur in
+@code{switch} statements, @code{for} loops, etc.
+
+@kindex set step-mode
+@item set step-mode
+@cindex functions without line info, and stepping
+@cindex stepping into functions with no line info
+@itemx set step-mode on
+The @code{set step-mode on} command causes the @code{step} command to
+stop at the first instruction of a function which contains no debug line
+information rather than stepping over it.
+
+This is useful in cases where you may be interested in inspecting the
+machine instructions of a function which has no symbolic info and do not
+want @value{GDBN} to automatically skip over this function.
+
+@item set step-mode off
+Causes the @code{step} command to step over any functions which contains no
+debug information. This is the default.
+
+@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
+@kindex u @r{(@code{until})}
+@item until
+@itemx u
+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}:
+
+@smallexample
+(@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 smallexample
+
+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. The specified
+location is actually reached only if it is in the current frame. This
+implies that @code{until} can be used to skip over recursive function
+invocations. For instance in the code below, if the current location is
+line @code{96}, issuing @code{until 99} will execute the program up to
+line @code{99} in the same invocation of factorial, i.e. after the inner
+invocations have returned.
+
+@smallexample
+94 int factorial (int value)
+95 @{
+96 if (value > 1) @{
+97 value *= factorial (value - 1);
+98 @}
+99 return (value);
+100 @}
+@end smallexample
+
+
+@kindex advance @var{location}
+@itemx advance @var{location}
+Continue running the program up to the given location. An argument is
+required, anything of the same form as arguments for the @code{break}
+command. Execution will also stop upon exit from the current stack
+frame. This command is similar to @code{until}, but @code{advance} will
+not skip over recursive function calls, and the target location doesn't
+have to be in the same frame as the current one.
+
+
+@kindex stepi
+@kindex si @r{(@code{stepi})}
+@item stepi
+@itemx stepi @var{arg}
+@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 @r{(@code{nexti})}
+@item nexti
+@itemx nexti @var{arg}
+@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
+
+@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 character (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} (they 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 let the non-erroneous signals like
+@code{SIGALRM} be silently passed to your program
+(so as not to interfere with their role in the program's functioning)
+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
+@itemx info handle
+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 an 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); a list of signal numbers of the form
+@samp{@var{low}-@var{high}}; or the word @samp{all}, meaning all the
+known signals. 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
+@itemx noignore
+@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. @code{pass} and @code{noignore} are synonyms.
+
+@item nopass
+@itemx ignore
+@value{GDBN} should not allow your program to see this signal.
+@code{nopass} and @code{ignore} are synonyms.
+@end table
+@c @end group
+
+When a signal stops your program, the signal is not visible to the
+program 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.
+
+The default is set to @code{nostop}, @code{noprint}, @code{pass} for
+non-erroneous signals such as @code{SIGALRM}, @code{SIGWINCH} and
+@code{SIGCHLD}, and to @code{stop}, @code{print}, @code{pass} for the
+erroneous signals.
+
+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}.
+
+@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
+(@value{GDBP}) 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 thread breakpoints and system calls
+@cindex system calls and thread breakpoints
+@cindex premature return from system calls
+There is an unfortunate side effect. If one thread stops for a
+breakpoint, or for some other reason, and another thread is blocked in a
+system call, then the system call may return prematurely. This is a
+consequence of the interaction between multiple threads and the signals
+that @value{GDBN} uses to implement breakpoints and other events that
+stop execution.
+
+To handle this problem, your program should check the return value of
+each system call and react appropriately. This is good programming
+style anyways.
+
+For example, do not write code like this:
+
+@smallexample
+ sleep (10);
+@end smallexample
+
+The call to @code{sleep} will return early if a different thread stops
+at a breakpoint or for some other reason.
+
+Instead, write this:
+
+@smallexample
+ int unslept = 10;
+ while (unslept > 0)
+ unslept = sleep (unslept);
+@end smallexample
+
+A system call is allowed to return early, so the system is still
+conforming to its specification. But @value{GDBN} does cause your
+multi-threaded program to behave differently than it would without
+@value{GDBN}.
+
+Also, @value{GDBN} uses internal breakpoints in the thread library to
+monitor certain events such as thread creation and thread destruction.
+When such an event happens, a system call in another thread may return
+prematurely, even though your program does not appear to stop.
+
+@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.
+
+On some OSes, you can lock the OS scheduler and thus allow only a single
+thread to run.
+
+@table @code
+@item set scheduler-locking @var{mode}
+Set the scheduler locking mode. If it is @code{off}, then there is no
+locking and any thread may run at any time. If @code{on}, then only the
+current thread may run when the inferior is resumed. The @code{step}
+mode optimizes for single-stepping. It stops other threads from
+``seizing the prompt'' by preempting the current thread while you are
+stepping. Other threads will only rarely (or never) get a chance to run
+when you step. They are more likely to run when you @samp{next} over a
+function call, and they are completely free to run when you use commands
+like @samp{continue}, @samp{until}, or @samp{finish}. However, unless another
+thread hits a breakpoint during its timeslice, they will never steal the
+@value{GDBN} prompt away from the thread that you are debugging.
+
+@item show scheduler-locking
+Display the current scheduler locking mode.
+@end table
+
+
+@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
+
+@end menu
+
+@node Frames
+@section Stack frames
+
+@cindex frame, definition
+@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 The -fomit-frame-pointer below perennially causes hbox overflow
+@c underflow problems.
+@cindex frameless execution
+Some compilers provide a way to compile functions so that they operate
+without stack frames. (For example, the @value{GCC} option
+@smallexample
+@samp{-fomit-frame-pointer}
+@end smallexample
+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@r{, command}
+@cindex current stack 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 or the stack frame number. Without an argument,
+@code{frame} prints the current stack frame.
+
+@kindex select-frame
+@cindex selecting frame silently
+@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
+
+@cindex backtraces
+@cindex tracebacks
+@cindex stack traces
+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 @r{(@code{backtrace})}
+@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 @r{(@code{info stack})}
+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}.
+
+@kindex set backtrace past-main
+@kindex show backtrace past-main
+@kindex set backtrace limit
+@kindex show backtrace limit
+
+Most programs have a standard user entry point---a place where system
+libraries and startup code transition into user code. For C this is
+@code{main}. When @value{GDBN} finds the entry function in a backtrace
+it will terminate the backtrace, to avoid tracing into highly
+system-specific (and generally uninteresting) code.
+
+If you need to examine the startup code, or limit the number of levels
+in a backtrace, you can change this behavior:
+
+@table @code
+@item set backtrace past-main
+@itemx set backtrace past-main on
+Backtraces will continue past the user entry point.
+
+@item set backtrace past-main off
+Backtraces will stop when they encounter the user entry point. This is the
+default.
+
+@item show backtrace past-main
+Display the current user entry point backtrace policy.
+
+@item set backtrace limit @var{n}
+@itemx set backtrace limit 0
+@cindex backtrace limit
+Limit the backtrace to @var{n} levels. A value of zero means
+unlimited.
+
+@item show backtrace limit
+Display the current limit on backtrace levels.
+@end table
+
+@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@r{, selecting}
+@kindex f @r{(@code{frame})}
+@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.
+
+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.
+
+@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 @r{(@code{down})}
+@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.
+You can also edit the program at the point of execution with your favorite
+editing program by typing @code{edit}.
+@xref{List, ,Printing source lines},
+for details.
+
+@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 @r{(@code{info frame})}
+@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 address of the frame's local variables
+@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.
+
+@kindex info catch
+@cindex catch exceptions, list active handlers
+@cindex exception handlers, how to list
+@item info catch
+Print a list of all the exception handlers that are active in the
+current stack frame at the current point of execution. To see other
+exception handlers, visit the associated frame (using the @code{up},
+@code{down}, or @code{frame} commands); then type @code{info catch}.
+@xref{Set Catchpoints, , Setting catchpoints}.
+
+@end table
+
+
+@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.
+
+If you use @value{GDBN} through its @sc{gnu} Emacs interface, you may
+prefer to use Emacs facilities to view source; see @ref{Emacs, ,Using
+@value{GDBN} under @sc{gnu} Emacs}.
+
+@menu
+* List:: Printing source lines
+* Edit:: Editing source files
+* Search:: Searching source files
+* Source Path:: Specifying source directories
+* Machine Code:: Source and machine code
+@end menu
+
+@node List
+@section Printing source lines
+
+@kindex list
+@kindex l @r{(@code{list})}
+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
+
+@node Edit
+@section Editing source files
+@cindex editing source files
+
+@kindex edit
+@kindex e @r{(@code{edit})}
+To edit the lines in a source file, use the @code{edit} command.
+The editing program of your choice
+is invoked with the current line set to
+the active line in the program.
+Alternatively, there are several ways to specify what part of the file you
+want to print if you want to see other parts of the program.
+
+Here are the forms of the @code{edit} command most commonly used:
+
+@table @code
+@item edit
+Edit the current source file at the active line number in the program.
+
+@item edit @var{number}
+Edit the current source file with @var{number} as the active line number.
+
+@item edit @var{function}
+Edit the file containing @var{function} at the beginning of its definition.
+
+@item edit @var{filename}:@var{number}
+Specifies line @var{number} in the source file @var{filename}.
+
+@item edit @var{filename}:@var{function}
+Specifies the line 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 edit *@var{address}
+Specifies the line containing the program address @var{address}.
+@var{address} may be any expression.
+@end table
+
+@subsection Choosing your editor
+You can customize @value{GDBN} to use any editor you want
+@footnote{
+The only restriction is that your editor (say @code{ex}), recognizes the
+following command-line syntax:
+@smallexample
+ex +@var{number} file
+@end smallexample
+The optional numeric value +@var{number} designates the active line in
+the file.}. By default, it is @value{EDITOR}, but you can change this
+by setting the environment variable @code{EDITOR} before using
+@value{GDBN}. For example, to configure @value{GDBN} to use the
+@code{vi} editor, you could use these commands with the @code{sh} shell:
+@smallexample
+EDITOR=/usr/bin/vi
+export EDITOR
+gdb ...
+@end smallexample
+or in the @code{csh} shell,
+@smallexample
+setenv EDITOR /usr/bin/vi
+gdb ...
+@end smallexample
+
+@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
+
+@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 includes only @samp{cdir}
+and @samp{cwd}, in that order.
+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{:}
+(@samp{;} on MS-DOS and MS-Windows, where @samp{:} usually appears as
+part of absolute file names) 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
+@vindex $cdir@r{, convenience variable}
+@vindex $cwdr@r{, convenience variable}
+@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 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}:
+
+@c FIXME: I think this example should also show the addresses in
+@c symbolic form, as they usually would be displayed.
+@smallexample
+(@value{GDBP}) info line m4_changequote
+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}
+@kindex x@r{(examine), and} 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
+
+The following example shows the disassembly of a range of addresses of
+HP PA-RISC 2.0 code:
+
+@smallexample
+(@value{GDBP}) disas 0x32c4 0x32e4
+Dump of assembler code from 0x32c4 to 0x32e4:
+0x32c4 <main+204>: addil 0,dp
+0x32c8 <main+208>: ldw 0x22c(sr0,r1),r26
+0x32cc <main+212>: ldil 0x3000,r31
+0x32d0 <main+216>: ble 0x3f8(sr4,r31)
+0x32d4 <main+220>: ldo 0(r31),rp
+0x32d8 <main+224>: addil -0x800,dp
+0x32dc <main+228>: ldo 0x588(r1),r26
+0x32e0 <main+232>: ldil 0x3000,r31
+End of assembler dump.
+@end smallexample
+
+Some architectures have more than one commonly-used set of instruction
+mnemonics or other syntax.
+
+@table @code
+@kindex set disassembly-flavor
+@cindex assembly instructions
+@cindex instructions, assembly
+@cindex machine instructions
+@cindex listing machine instructions
+@cindex Intel disassembly flavor
+@cindex AT&T disassembly flavor
+@item set disassembly-flavor @var{instruction-set}
+Select the instruction set to use when disassembling the
+program via the @code{disassemble} or @code{x/i} commands.
+
+Currently this command is only defined for the Intel x86 family. You
+can set @var{instruction-set} to either @code{intel} or @code{att}.
+The default is @code{att}, the AT&T flavor used by default by Unix
+assemblers for x86-based targets.
+@end table
+
+
+@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}. 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}).
+
+@table @code
+@item print @var{expr}
+@itemx print /@var{f} @var{expr}
+@var{expr} is an expression (in the source language). By default the
+value of @var{expr} 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; see @ref{Output Formats,,Output
+formats}.
+
+@item print
+@itemx print /@var{f}
+If you omit @var{expr}, @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 or a class 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
+* Floating Point Hardware:: Floating point hardware
+* Vector Unit:: Vector Unit
+* Auxiliary Vector:: Auxiliary data provided by operating system
+* Memory Region Attributes:: Memory region attributes
+* Dump/Restore Files:: Copy between memory and a file
+* Character Sets:: Debugging programs that use a different
+ character set than GDB does
+@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 also includes preprocessor macros, if
+you compiled your program to include this information; see
+@ref{Compilation}.
+
+@value{GDBN} supports array constants in expressions input by
+the user. The syntax is @{@var{element}, @var{element}@dots{}@}. For example,
+you can use the command @code{print @{1, 2, 3@}} to build up an array in
+memory that is @code{malloc}ed in the target program.
+
+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?
+
+@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 file-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
+
+@smallexample
+foo (a)
+ int a;
+@{
+ bar (a);
+ @{
+ int b = test ();
+ bar (b);
+ @}
+@}
+@end smallexample
+
+@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, context for variables/functions
+@iftex
+@c info cannot cope with a :: index entry, but why deprive hard copy readers?
+@cindex @code{::}, context for variables/functions
+@end iftex
+@smallexample
+@var{file}::@var{variable}
+@var{function}::@var{variable}
+@end smallexample
+
+@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}:
+
+@smallexample
+(@value{GDBP}) p 'f2.c'::x
+@end smallexample
+
+@cindex C@t{++} scope resolution
+This use of @samp{::} is very rarely in conflict with the very similar
+use of the same notation in C@t{++}. @value{GDBN} also supports use of the C@t{++}
+scope resolution operator in @value{GDBN} expressions.
+@c FIXME: Um, so what happens in one of those rare cases where it's in
+@c conflict?? --mew
+
+@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.
+
+This may also happen when the compiler does significant optimizations.
+To be sure of always seeing accurate values, turn off all optimization
+when compiling.
+
+@cindex ``No symbol "foo" in current context''
+Another possible effect of compiler optimizations is to optimize
+unused variables out of existence, or assign variables to registers (as
+opposed to memory addresses). Depending on the support for such cases
+offered by the debug info format used by the compiler, @value{GDBN}
+might not be able to display values for such local variables. If that
+happens, @value{GDBN} will print a message like this:
+
+@smallexample
+No symbol "foo" in current context.
+@end smallexample
+
+To solve such problems, either recompile without optimizations, or use a
+different debug info format, if the compiler supports several such
+formats. For example, @value{NGCC}, the @sc{gnu} C/C@t{++} compiler
+usually supports the @option{-gstabs+} option. @option{-gstabs+}
+produces debug info in a format that is superior to formats such as
+COFF. You may be able to use DWARF 2 (@option{-gdwarf-2}), which is also
+an effective form for debug info. @xref{Debugging Options,,Options
+for Debugging Your Program or @sc{gnu} CC, gcc.info, Using @sc{gnu} CC}.
+
+
+@node Arrays
+@section Artificial arrays
+
+@cindex artificial array
+@kindex @@@r{, referencing memory as an array}
+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
+
+@smallexample
+int *array = (int *) malloc (len * sizeof (int));
+@end smallexample
+
+@noindent
+you can print the contents of @code{array} with
+
+@smallexample
+p *array@@len
+@end smallexample
+
+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:
+@smallexample
+(@value{GDBP}) p/x (short[2])0x12345678
+$1 = @{0x1234, 0x5678@}
+@end smallexample
+
+As a convenience, if you leave the array length out (as in
+@samp{(@var{type}[])@var{value}}) @value{GDBN} calculates the size to fill
+the value (as @samp{sizeof(@var{value})/sizeof(@var{type})}:
+@smallexample
+(@value{GDBP}) p/x (short[])0x12345678
+$2 = @{0x1234, 0x5678@}
+@end smallexample
+
+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:
+
+@smallexample
+set $i = 0
+p dtab[$i++]->fv
+@key{RET}
+@key{RET}
+@dots{}
+@end smallexample
+
+@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'';
+see @ref{Memory,,Examining memory}.}
+
+@item a
+@cindex unknown address, locating
+@cindex locate address
+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:
+
+@smallexample
+(@value{GDBP}) p/a 0x54320
+$3 = 0x54320 <_initialize_vx+396>
+@end smallexample
+
+@noindent
+The command @code{info symbol 0x54320} yields similar results.
+@xref{Symbols, info symbol}.
+
+@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
+
+@smallexample
+p/x $pc
+@end smallexample
+
+@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 @r{(examine memory)}
+@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, ,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; see @ref{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:
+
+@smallexample
+2: foo = 38
+3: bar[5] = (struct hack *) 0x3804
+@end smallexample
+
+@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{expr}
+Add the expression @var{expr} 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{expr}
+For @var{fmt} specifying only a display format and not a size or
+count, add the expression @var{expr} 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, ,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}:
+
+@smallexample
+(@value{GDBP}) set print symbol-filename on
+(@value{GDBP}) p/a ptt
+$4 = 0xe008 <t in hi2.c>
+@end smallexample
+
+@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.
+When @value{GDBN} starts, this limit is set to 200.
+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.
+The default is off.
+
+@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
+
+@need 1000
+@noindent
+These settings are of interest when debugging C@t{++} programs:
+
+@table @code
+@cindex demangling
+@kindex set print demangle
+@item set print demangle
+@itemx set print demangle on
+Print C@t{++} 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 on.
+
+@kindex show print demangle
+@item show print demangle
+Show whether C@t{++} 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@t{++} 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@t{++} names in assembly listings are printed in mangled
+or demangled form.
+
+@kindex set demangle-style
+@cindex C@t{++} symbol decoding style
+@cindex symbol decoding style, C@t{++}
+@item set demangle-style @var{style}
+Choose among several encoding schemes used by different compilers to
+represent C@t{++} names. The choices for @var{style} are currently:
+
+@table @code
+@item auto
+Allow @value{GDBN} to choose a decoding style by inspecting your program.
+
+@item gnu
+Decode based on the @sc{gnu} C@t{++} compiler (@code{g++}) encoding algorithm.
+This is the default.
+
+@item hp
+Decode based on the HP ANSI C@t{++} (@code{aCC}) encoding algorithm.
+
+@item lucid
+Decode based on the Lucid C@t{++} compiler (@code{lcc}) encoding algorithm.
+
+@item arm
+Decode using the algorithm in the @cite{C@t{++} 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.
+
+@end table
+If you omit @var{style}, you will see a list of possible formats.
+
+@kindex show demangle-style
+@item show demangle-style
+Display the encoding style currently in use for decoding C@t{++} 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@t{++} object. The default is on.
+
+@item set print static-members off
+Do not print static members when displaying a C@t{++} object.
+
+@kindex show print static-members
+@item show print static-members
+Show whether C@t{++} static members are printed, or not.
+
+@c These don't work with HP ANSI C++ yet.
+@kindex set print vtbl
+@item set print vtbl
+@itemx set print vtbl on
+Pretty print C@t{++} virtual function tables. The default is off.
+(The @code{vtbl} commands do not work on programs compiled with the HP
+ANSI C@t{++} compiler (@code{aCC}).)
+
+@item set print vtbl off
+Do not pretty print C@t{++} virtual function tables.
+
+@kindex show print vtbl
+@item show print vtbl
+Show whether C@t{++} virtual function tables are pretty printed, or not.
+@end table
+
+@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
+
+@smallexample
+p *$
+@end smallexample
+
+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:
+
+@smallexample
+p *$.next
+@end smallexample
+
+@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:
+
+@smallexample
+print x
+set x=5
+@end smallexample
+
+@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, ,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:
+
+@smallexample
+set $foo = *object_ptr
+@end smallexample
+
+@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 conv}.
+@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:
+
+@smallexample
+set $i = 0
+print bar[$i++]->contents
+@end smallexample
+
+@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
+@vindex $_@r{, convenience variable}
+@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{$__}.
+
+@vindex $__@r{, convenience variable}
+@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
+@vindex $_exitcode@r{, convenience variable}
+The variable @code{$_exitcode} is automatically set to the exit code when
+the program being debugged terminates.
+@end table
+
+On HP-UX systems, if you refer to a function or variable name that
+begins with a dollar sign, @value{GDBN} searches for a user or system
+name first, before it searches for a convenience variable.
+
+@node 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
+and vector 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
+and vector registers (in the selected stack frame).
+
+@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
+
+@smallexample
+p/x $pc
+@end smallexample
+
+@noindent
+or print the instruction to be executed next with
+
+@smallexample
+x/i $pc
+@end smallexample
+
+@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};
+see @ref{Returning, ,Returning from a function}.} with
+
+@smallexample
+set $sp += 4
+@end smallexample
+
+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}; and on x86-based machines @code{$ps}
+is an alias for the @sc{eflags} register.
+
+@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.
+
+@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
+
+@node Vector Unit
+@section Vector Unit
+@cindex vector unit
+
+Depending on the configuration, @value{GDBN} may be able to give you
+more information about the status of the vector unit.
+
+@table @code
+@kindex info vector
+@item info vector
+Display information about the vector unit. The exact contents and
+layout vary depending on the hardware.
+@end table
+
+@node Auxiliary Vector
+@section Operating system auxiliary vector
+@cindex auxiliary vector
+@cindex vector, auxiliary
+
+Some operating systems supply an @dfn{auxiliary vector} to programs at
+startup. This is akin to the arguments and environment that you
+specify for a program, but contains a system-dependent variety of
+binary values that tell system libraries important details about the
+hardware, operating system, and process. Each value's purpose is
+identified by an integer tag; the meanings are well-known but system-specific.
+Depending on the configuration and operating system facilities,
+@value{GDBN} may be able to show you this information.
+
+@table @code
+@kindex info auxv
+@item info auxv
+Display the auxiliary vector of the inferior, which can be either a
+live process or a core dump file. @value{GDBN} prints each tag value
+numerically, and also shows names and text descriptions for recognized
+tags. Some values in the vector are numbers, some bit masks, and some
+pointers to strings or other data. @value{GDBN} displays each value in the
+most appropriate form for a recognized tag, and in hexadecimal for
+an unrecognized tag.
+@end table
+
+@node Memory Region Attributes
+@section Memory region attributes
+@cindex memory region attributes
+
+@dfn{Memory region attributes} allow you to describe special handling
+required by regions of your target's memory. @value{GDBN} uses attributes
+to determine whether to allow certain types of memory accesses; whether to
+use specific width accesses; and whether to cache target memory.
+
+Defined memory regions can be individually enabled and disabled. When a
+memory region is disabled, @value{GDBN} uses the default attributes when
+accessing memory in that region. Similarly, if no memory regions have
+been defined, @value{GDBN} uses the default attributes when accessing
+all memory.
+
+When a memory region is defined, it is given a number to identify it;
+to enable, disable, or remove a memory region, you specify that number.
+
+@table @code
+@kindex mem
+@item mem @var{lower} @var{upper} @var{attributes}@dots{}
+Define memory region bounded by @var{lower} and @var{upper} with
+attributes @var{attributes}@dots{}. Note that @var{upper} == 0 is a
+special case: it is treated as the the target's maximum memory address.
+(0xffff on 16 bit targets, 0xffffffff on 32 bit targets, etc.)
+
+@kindex delete mem
+@item delete mem @var{nums}@dots{}
+Remove memory regions @var{nums}@dots{}.
+
+@kindex disable mem
+@item disable mem @var{nums}@dots{}
+Disable memory regions @var{nums}@dots{}.
+A disabled memory region is not forgotten.
+It may be enabled again later.
+
+@kindex enable mem
+@item enable mem @var{nums}@dots{}
+Enable memory regions @var{nums}@dots{}.
+
+@kindex info mem
+@item info mem
+Print a table of all defined memory regions, with the following columns
+for each region.
+
+@table @emph
+@item Memory Region Number
+@item Enabled or Disabled.
+Enabled memory regions are marked with @samp{y}.
+Disabled memory regions are marked with @samp{n}.
+
+@item Lo Address
+The address defining the inclusive lower bound of the memory region.
+
+@item Hi Address
+The address defining the exclusive upper bound of the memory region.
+
+@item Attributes
+The list of attributes set for this memory region.
+@end table
+@end table
+
+
+@subsection Attributes
+
+@subsubsection Memory Access Mode
+The access mode attributes set whether @value{GDBN} may make read or
+write accesses to a memory region.
+
+While these attributes prevent @value{GDBN} from performing invalid
+memory accesses, they do nothing to prevent the target system, I/O DMA,
+etc. from accessing memory.
+
+@table @code
+@item ro
+Memory is read only.
+@item wo
+Memory is write only.
+@item rw
+Memory is read/write. This is the default.
+@end table
+
+@subsubsection Memory Access Size
+The acccess size attributes tells @value{GDBN} to use specific sized
+accesses in the memory region. Often memory mapped device registers
+require specific sized accesses. If no access size attribute is
+specified, @value{GDBN} may use accesses of any size.
+
+@table @code
+@item 8
+Use 8 bit memory accesses.
+@item 16
+Use 16 bit memory accesses.
+@item 32
+Use 32 bit memory accesses.
+@item 64
+Use 64 bit memory accesses.
+@end table
+
+@c @subsubsection Hardware/Software Breakpoints
+@c The hardware/software breakpoint attributes set whether @value{GDBN}
+@c will use hardware or software breakpoints for the internal breakpoints
+@c used by the step, next, finish, until, etc. commands.
+@c
+@c @table @code
+@c @item hwbreak
+@c Always use hardware breakpoints
+@c @item swbreak (default)
+@c @end table
+
+@subsubsection Data Cache
+The data cache attributes set whether @value{GDBN} will cache target
+memory. While this generally improves performance by reducing debug
+protocol overhead, it can lead to incorrect results because @value{GDBN}
+does not know about volatile variables or memory mapped device
+registers.
+
+@table @code
+@item cache
+Enable @value{GDBN} to cache target memory.
+@item nocache
+Disable @value{GDBN} from caching target memory. This is the default.
+@end table
+
+@c @subsubsection Memory Write Verification
+@c The memory write verification attributes set whether @value{GDBN}
+@c will re-reads data after each write to verify the write was successful.
+@c
+@c @table @code
+@c @item verify
+@c @item noverify (default)
+@c @end table
+
+@node Dump/Restore Files
+@section Copy between memory and a file
+@cindex dump/restore files
+@cindex append data to a file
+@cindex dump data to a file
+@cindex restore data from a file
+
+You can use the commands @code{dump}, @code{append}, and
+@code{restore} to copy data between target memory and a file. The
+@code{dump} and @code{append} commands write data to a file, and the
+@code{restore} command reads data from a file back into the inferior's
+memory. Files may be in binary, Motorola S-record, Intel hex, or
+Tektronix Hex format; however, @value{GDBN} can only append to binary
+files.
+
+@table @code
+
+@kindex dump
+@item dump @r{[}@var{format}@r{]} memory @var{filename} @var{start_addr} @var{end_addr}
+@itemx dump @r{[}@var{format}@r{]} value @var{filename} @var{expr}
+Dump the contents of memory from @var{start_addr} to @var{end_addr},
+or the value of @var{expr}, to @var{filename} in the given format.
+
+The @var{format} parameter may be any one of:
+@table @code
+@item binary
+Raw binary form.
+@item ihex
+Intel hex format.
+@item srec
+Motorola S-record format.
+@item tekhex
+Tektronix Hex format.
+@end table
+
+@value{GDBN} uses the same definitions of these formats as the
+@sc{gnu} binary utilities, like @samp{objdump} and @samp{objcopy}. If
+@var{format} is omitted, @value{GDBN} dumps the data in raw binary
+form.
+
+@kindex append
+@item append @r{[}binary@r{]} memory @var{filename} @var{start_addr} @var{end_addr}
+@itemx append @r{[}binary@r{]} value @var{filename} @var{expr}
+Append the contents of memory from @var{start_addr} to @var{end_addr},
+or the value of @var{expr}, to @var{filename}, in raw binary form.
+(@value{GDBN} can only append data to files in raw binary form.)
+
+@kindex restore
+@item restore @var{filename} @r{[}binary@r{]} @var{bias} @var{start} @var{end}
+Restore the contents of file @var{filename} into memory. The
+@code{restore} command can automatically recognize any known @sc{bfd}
+file format, except for raw binary. To restore a raw binary file you
+must specify the optional keyword @code{binary} after the filename.
+
+If @var{bias} is non-zero, its value will be added to the addresses
+contained in the file. Binary files always start at address zero, so
+they will be restored at address @var{bias}. Other bfd files have
+a built-in location; they will be restored at offset @var{bias}
+from that location.
+
+If @var{start} and/or @var{end} are non-zero, then only data between
+file offset @var{start} and file offset @var{end} will be restored.
+These offsets are relative to the addresses in the file, before
+the @var{bias} argument is applied.
+
+@end table
+
+@node Character Sets
+@section Character Sets
+@cindex character sets
+@cindex charset
+@cindex translating between character sets
+@cindex host character set
+@cindex target character set
+
+If the program you are debugging uses a different character set to
+represent characters and strings than the one @value{GDBN} uses itself,
+@value{GDBN} can automatically translate between the character sets for
+you. The character set @value{GDBN} uses we call the @dfn{host
+character set}; the one the inferior program uses we call the
+@dfn{target character set}.
+
+For example, if you are running @value{GDBN} on a @sc{gnu}/Linux system, which
+uses the ISO Latin 1 character set, but you are using @value{GDBN}'s
+remote protocol (@pxref{Remote,Remote Debugging}) to debug a program
+running on an IBM mainframe, which uses the @sc{ebcdic} character set,
+then the host character set is Latin-1, and the target character set is
+@sc{ebcdic}. If you give @value{GDBN} the command @code{set
+target-charset EBCDIC-US}, then @value{GDBN} translates between
+@sc{ebcdic} and Latin 1 as you print character or string values, or use
+character and string literals in expressions.
+
+@value{GDBN} has no way to automatically recognize which character set
+the inferior program uses; you must tell it, using the @code{set
+target-charset} command, described below.
+
+Here are the commands for controlling @value{GDBN}'s character set
+support:
+
+@table @code
+@item set target-charset @var{charset}
+@kindex set target-charset
+Set the current target character set to @var{charset}. We list the
+character set names @value{GDBN} recognizes below, but if you type
+@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} will
+list the target character sets it supports.
+@end table
+
+@table @code
+@item set host-charset @var{charset}
+@kindex set host-charset
+Set the current host character set to @var{charset}.
+
+By default, @value{GDBN} uses a host character set appropriate to the
+system it is running on; you can override that default using the
+@code{set host-charset} command.
+
+@value{GDBN} can only use certain character sets as its host character
+set. We list the character set names @value{GDBN} recognizes below, and
+indicate which can be host character sets, but if you type
+@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} will
+list the host character sets it supports.
+
+@item set charset @var{charset}
+@kindex set charset
+Set the current host and target character sets to @var{charset}. As
+above, if you type @code{set charset} followed by @key{TAB}@key{TAB},
+@value{GDBN} will list the name of the character sets that can be used
+for both host and target.
+
+
+@item show charset
+@kindex show charset
+Show the names of the current host and target charsets.
+
+@itemx show host-charset
+@kindex show host-charset
+Show the name of the current host charset.
+
+@itemx show target-charset
+@kindex show target-charset
+Show the name of the current target charset.
+
+@end table
+
+@value{GDBN} currently includes support for the following character
+sets:
+
+@table @code
+
+@item ASCII
+@cindex ASCII character set
+Seven-bit U.S. @sc{ascii}. @value{GDBN} can use this as its host
+character set.
+
+@item ISO-8859-1
+@cindex ISO 8859-1 character set
+@cindex ISO Latin 1 character set
+The ISO Latin 1 character set. This extends @sc{ascii} with accented
+characters needed for French, German, and Spanish. @value{GDBN} can use
+this as its host character set.
+
+@item EBCDIC-US
+@itemx IBM1047
+@cindex EBCDIC character set
+@cindex IBM1047 character set
+Variants of the @sc{ebcdic} character set, used on some of IBM's
+mainframe operating systems. (@sc{gnu}/Linux on the S/390 uses U.S. @sc{ascii}.)
+@value{GDBN} cannot use these as its host character set.
+
+@end table
+
+Note that these are all single-byte character sets. More work inside
+GDB is needed to support multi-byte or variable-width character
+encodings, like the UTF-8 and UCS-2 encodings of Unicode.
+
+Here is an example of @value{GDBN}'s character set support in action.
+Assume that the following source code has been placed in the file
+@file{charset-test.c}:
+
+@smallexample
+#include <stdio.h>
+
+char ascii_hello[]
+ = @{72, 101, 108, 108, 111, 44, 32, 119,
+ 111, 114, 108, 100, 33, 10, 0@};
+char ibm1047_hello[]
+ = @{200, 133, 147, 147, 150, 107, 64, 166,
+ 150, 153, 147, 132, 90, 37, 0@};
+
+main ()
+@{
+ printf ("Hello, world!\n");
+@}
+@end smallexample
+
+In this program, @code{ascii_hello} and @code{ibm1047_hello} are arrays
+containing the string @samp{Hello, world!} followed by a newline,
+encoded in the @sc{ascii} and @sc{ibm1047} character sets.
+
+We compile the program, and invoke the debugger on it:
+
+@smallexample
+$ gcc -g charset-test.c -o charset-test
+$ gdb -nw charset-test
+GNU gdb 2001-12-19-cvs
+Copyright 2001 Free Software Foundation, Inc.
+@dots{}
+(gdb)
+@end smallexample
+
+We can use the @code{show charset} command to see what character sets
+@value{GDBN} is currently using to interpret and display characters and
+strings:
+
+@smallexample
+(gdb) show charset
+The current host and target character set is `ISO-8859-1'.
+(gdb)
+@end smallexample
+
+For the sake of printing this manual, let's use @sc{ascii} as our
+initial character set:
+@smallexample
+(gdb) set charset ASCII
+(gdb) show charset
+The current host and target character set is `ASCII'.
+(gdb)
+@end smallexample
+
+Let's assume that @sc{ascii} is indeed the correct character set for our
+host system --- in other words, let's assume that if @value{GDBN} prints
+characters using the @sc{ascii} character set, our terminal will display
+them properly. Since our current target character set is also
+@sc{ascii}, the contents of @code{ascii_hello} print legibly:
+
+@smallexample
+(gdb) print ascii_hello
+$1 = 0x401698 "Hello, world!\n"
+(gdb) print ascii_hello[0]
+$2 = 72 'H'
+(gdb)
+@end smallexample
+
+@value{GDBN} uses the target character set for character and string
+literals you use in expressions:
+
+@smallexample
+(gdb) print '+'
+$3 = 43 '+'
+(gdb)
+@end smallexample
+
+The @sc{ascii} character set uses the number 43 to encode the @samp{+}
+character.
+
+@value{GDBN} relies on the user to tell it which character set the
+target program uses. If we print @code{ibm1047_hello} while our target
+character set is still @sc{ascii}, we get jibberish:
+
+@smallexample
+(gdb) print ibm1047_hello
+$4 = 0x4016a8 "\310\205\223\223\226k@@\246\226\231\223\204Z%"
+(gdb) print ibm1047_hello[0]
+$5 = 200 '\310'
+(gdb)
+@end smallexample
+
+If we invoke the @code{set target-charset} followed by @key{TAB}@key{TAB},
+@value{GDBN} tells us the character sets it supports:
+
+@smallexample
+(gdb) set target-charset
+ASCII EBCDIC-US IBM1047 ISO-8859-1
+(gdb) set target-charset
+@end smallexample
+
+We can select @sc{ibm1047} as our target character set, and examine the
+program's strings again. Now the @sc{ascii} string is wrong, but
+@value{GDBN} translates the contents of @code{ibm1047_hello} from the
+target character set, @sc{ibm1047}, to the host character set,
+@sc{ascii}, and they display correctly:
+
+@smallexample
+(gdb) set target-charset IBM1047
+(gdb) show charset
+The current host character set is `ASCII'.
+The current target character set is `IBM1047'.
+(gdb) print ascii_hello
+$6 = 0x401698 "\110\145%%?\054\040\167?\162%\144\041\012"
+(gdb) print ascii_hello[0]
+$7 = 72 '\110'
+(gdb) print ibm1047_hello
+$8 = 0x4016a8 "Hello, world!\n"
+(gdb) print ibm1047_hello[0]
+$9 = 200 'H'
+(gdb)
+@end smallexample
+
+As above, @value{GDBN} uses the target character set for character and
+string literals you use in expressions:
+
+@smallexample
+(gdb) print '+'
+$10 = 78 '+'
+(gdb)
+@end smallexample
+
+The @sc{ibm1047} character set uses the number 78 to encode the @samp{+}
+character.
+
+
+@node Macros
+@chapter C Preprocessor Macros
+
+Some languages, such as C and C@t{++}, provide a way to define and invoke
+``preprocessor macros'' which expand into strings of tokens.
+@value{GDBN} can evaluate expressions containing macro invocations, show
+the result of macro expansion, and show a macro's definition, including
+where it was defined.
+
+You may need to compile your program specially to provide @value{GDBN}
+with information about preprocessor macros. Most compilers do not
+include macros in their debugging information, even when you compile
+with the @option{-g} flag. @xref{Compilation}.
+
+A program may define a macro at one point, remove that definition later,
+and then provide a different definition after that. Thus, at different
+points in the program, a macro may have different definitions, or have
+no definition at all. If there is a current stack frame, @value{GDBN}
+uses the macros in scope at that frame's source code line. Otherwise,
+@value{GDBN} uses the macros in scope at the current listing location;
+see @ref{List}.
+
+At the moment, @value{GDBN} does not support the @code{##}
+token-splicing operator, the @code{#} stringification operator, or
+variable-arity macros.
+
+Whenever @value{GDBN} evaluates an expression, it always expands any
+macro invocations present in the expression. @value{GDBN} also provides
+the following commands for working with macros explicitly.
+
+@table @code
+
+@kindex macro expand
+@cindex macro expansion, showing the results of preprocessor
+@cindex preprocessor macro expansion, showing the results of
+@cindex expanding preprocessor macros
+@item macro expand @var{expression}
+@itemx macro exp @var{expression}
+Show the results of expanding all preprocessor macro invocations in
+@var{expression}. Since @value{GDBN} simply expands macros, but does
+not parse the result, @var{expression} need not be a valid expression;
+it can be any string of tokens.
+
+@kindex macro expand-once
+@item macro expand-once @var{expression}
+@itemx macro exp1 @var{expression}
+@i{(This command is not yet implemented.)} Show the results of
+expanding those preprocessor macro invocations that appear explicitly in
+@var{expression}. Macro invocations appearing in that expansion are
+left unchanged. This command allows you to see the effect of a
+particular macro more clearly, without being confused by further
+expansions. Since @value{GDBN} simply expands macros, but does not
+parse the result, @var{expression} need not be a valid expression; it
+can be any string of tokens.
+
+@kindex info macro
+@cindex macro definition, showing
+@cindex definition, showing a macro's
+@item info macro @var{macro}
+Show the definition of the macro named @var{macro}, and describe the
+source location where that definition was established.
+
+@kindex macro define
+@cindex user-defined macros
+@cindex defining macros interactively
+@cindex macros, user-defined
+@item macro define @var{macro} @var{replacement-list}
+@itemx macro define @var{macro}(@var{arglist}) @var{replacement-list}
+@i{(This command is not yet implemented.)} Introduce a definition for a
+preprocessor macro named @var{macro}, invocations of which are replaced
+by the tokens given in @var{replacement-list}. The first form of this
+command defines an ``object-like'' macro, which takes no arguments; the
+second form defines a ``function-like'' macro, which takes the arguments
+given in @var{arglist}.
+
+A definition introduced by this command is in scope in every expression
+evaluated in @value{GDBN}, until it is removed with the @command{macro
+undef} command, described below. The definition overrides all
+definitions for @var{macro} present in the program being debugged, as
+well as any previous user-supplied definition.
+
+@kindex macro undef
+@item macro undef @var{macro}
+@i{(This command is not yet implemented.)} Remove any user-supplied
+definition for the macro named @var{macro}. This command only affects
+definitions provided with the @command{macro define} command, described
+above; it cannot remove definitions present in the program being
+debugged.
+
+@end table
+
+@cindex macros, example of debugging with
+Here is a transcript showing the above commands in action. First, we
+show our source files:
+
+@smallexample
+$ cat sample.c
+#include <stdio.h>
+#include "sample.h"
+
+#define M 42
+#define ADD(x) (M + x)
+
+main ()
+@{
+#define N 28
+ printf ("Hello, world!\n");
+#undef N
+ printf ("We're so creative.\n");
+#define N 1729
+ printf ("Goodbye, world!\n");
+@}
+$ cat sample.h
+#define Q <
+$
+@end smallexample
+
+Now, we compile the program using the @sc{gnu} C compiler, @value{NGCC}.
+We pass the @option{-gdwarf-2} and @option{-g3} flags to ensure the
+compiler includes information about preprocessor macros in the debugging
+information.
+
+@smallexample
+$ gcc -gdwarf-2 -g3 sample.c -o sample
+$
+@end smallexample
+
+Now, we start @value{GDBN} on our sample program:
+
+@smallexample
+$ gdb -nw sample
+GNU gdb 2002-05-06-cvs
+Copyright 2002 Free Software Foundation, Inc.
+GDB is free software, @dots{}
+(gdb)
+@end smallexample
+
+We can expand macros and examine their definitions, even when the
+program is not running. @value{GDBN} uses the current listing position
+to decide which macro definitions are in scope:
+
+@smallexample
+(gdb) list main
+3
+4 #define M 42
+5 #define ADD(x) (M + x)
+6
+7 main ()
+8 @{
+9 #define N 28
+10 printf ("Hello, world!\n");
+11 #undef N
+12 printf ("We're so creative.\n");
+(gdb) info macro ADD
+Defined at /home/jimb/gdb/macros/play/sample.c:5
+#define ADD(x) (M + x)
+(gdb) info macro Q
+Defined at /home/jimb/gdb/macros/play/sample.h:1
+ included at /home/jimb/gdb/macros/play/sample.c:2
+#define Q <
+(gdb) macro expand ADD(1)
+expands to: (42 + 1)
+(gdb) macro expand-once ADD(1)
+expands to: once (M + 1)
+(gdb)
+@end smallexample
+
+In the example above, note that @command{macro expand-once} expands only
+the macro invocation explicit in the original text --- the invocation of
+@code{ADD} --- but does not expand the invocation of the macro @code{M},
+which was introduced by @code{ADD}.
+
+Once the program is running, GDB uses the macro definitions in force at
+the source line of the current stack frame:
+
+@smallexample
+(gdb) break main
+Breakpoint 1 at 0x8048370: file sample.c, line 10.
+(gdb) run
+Starting program: /home/jimb/gdb/macros/play/sample
+
+Breakpoint 1, main () at sample.c:10
+10 printf ("Hello, world!\n");
+(gdb)
+@end smallexample
+
+At line 10, the definition of the macro @code{N} at line 9 is in force:
+
+@smallexample
+(gdb) info macro N
+Defined at /home/jimb/gdb/macros/play/sample.c:9
+#define N 28
+(gdb) macro expand N Q M
+expands to: 28 < 42
+(gdb) print N Q M
+$1 = 1
+(gdb)
+@end smallexample
+
+As we step over directives that remove @code{N}'s definition, and then
+give it a new definition, @value{GDBN} finds the definition (or lack
+thereof) in force at each point:
+
+@smallexample
+(gdb) next
+Hello, world!
+12 printf ("We're so creative.\n");
+(gdb) info macro N
+The symbol `N' has no definition as a C/C++ preprocessor macro
+at /home/jimb/gdb/macros/play/sample.c:12
+(gdb) next
+We're so creative.
+14 printf ("Goodbye, world!\n");
+(gdb) info macro N
+Defined at /home/jimb/gdb/macros/play/sample.c:13
+#define N 1729
+(gdb) macro expand N Q M
+expands to: 1729 < 42
+(gdb) print N Q M
+$2 = 0
+(gdb)
+@end smallexample
+
+
+@node Tracepoints
+@chapter Tracepoints
+@c This chapter is based on the documentation written by Michael
+@c Snyder, David Taylor, Jim Blandy, and Elena Zannoni.
+
+@cindex tracepoints
+In some applications, it is not feasible for the debugger to interrupt
+the program's execution long enough for the developer to learn
+anything helpful about its behavior. If the program's correctness
+depends on its real-time behavior, delays introduced by a debugger
+might cause the program to change its behavior drastically, or perhaps
+fail, even when the code itself is correct. It is useful to be able
+to observe the program's behavior without interrupting it.
+
+Using @value{GDBN}'s @code{trace} and @code{collect} commands, you can
+specify locations in the program, called @dfn{tracepoints}, and
+arbitrary expressions to evaluate when those tracepoints are reached.
+Later, using the @code{tfind} command, you can examine the values
+those expressions had when the program hit the tracepoints. The
+expressions may also denote objects in memory---structures or arrays,
+for example---whose values @value{GDBN} should record; while visiting
+a particular tracepoint, you may inspect those objects as if they were
+in memory at that moment. However, because @value{GDBN} records these
+values without interacting with you, it can do so quickly and
+unobtrusively, hopefully not disturbing the program's behavior.
+
+The tracepoint facility is currently available only for remote
+targets. @xref{Targets}. In addition, your remote target must know how
+to collect trace data. This functionality is implemented in the remote
+stub; however, none of the stubs distributed with @value{GDBN} support
+tracepoints as of this writing.
+
+This chapter describes the tracepoint commands and features.
+
+@menu
+* Set Tracepoints::
+* Analyze Collected Data::
+* Tracepoint Variables::
+@end menu
+
+@node Set Tracepoints
+@section Commands to Set Tracepoints
+
+Before running such a @dfn{trace experiment}, an arbitrary number of
+tracepoints can be set. Like a breakpoint (@pxref{Set Breaks}), a
+tracepoint has a number assigned to it by @value{GDBN}. Like with
+breakpoints, tracepoint numbers are successive integers starting from
+one. Many of the commands associated with tracepoints take the
+tracepoint number as their argument, to identify which tracepoint to
+work on.
+
+For each tracepoint, you can specify, in advance, some arbitrary set
+of data that you want the target to collect in the trace buffer when
+it hits that tracepoint. The collected data can include registers,
+local variables, or global data. Later, you can use @value{GDBN}
+commands to examine the values these data had at the time the
+tracepoint was hit.
+
+This section describes commands to set tracepoints and associated
+conditions and actions.
+
+@menu
+* Create and Delete Tracepoints::
+* Enable and Disable Tracepoints::
+* Tracepoint Passcounts::
+* Tracepoint Actions::
+* Listing Tracepoints::
+* Starting and Stopping Trace Experiment::
+@end menu
+
+@node Create and Delete Tracepoints
+@subsection Create and Delete Tracepoints
+
+@table @code
+@cindex set tracepoint
+@kindex trace
+@item trace
+The @code{trace} command is very similar to the @code{break} command.
+Its argument can be a source line, a function name, or an address in
+the target program. @xref{Set Breaks}. The @code{trace} command
+defines a tracepoint, which is a point in the target program where the
+debugger will briefly stop, collect some data, and then allow the
+program to continue. Setting a tracepoint or changing its commands
+doesn't take effect until the next @code{tstart} command; thus, you
+cannot change the tracepoint attributes once a trace experiment is
+running.
+
+Here are some examples of using the @code{trace} command:
+
+@smallexample
+(@value{GDBP}) @b{trace foo.c:121} // a source file and line number
+
+(@value{GDBP}) @b{trace +2} // 2 lines forward
+
+(@value{GDBP}) @b{trace my_function} // first source line of function
+
+(@value{GDBP}) @b{trace *my_function} // EXACT start address of function
+
+(@value{GDBP}) @b{trace *0x2117c4} // an address
+@end smallexample
+
+@noindent
+You can abbreviate @code{trace} as @code{tr}.
+
+@vindex $tpnum
+@cindex last tracepoint number
+@cindex recent tracepoint number
+@cindex tracepoint number
+The convenience variable @code{$tpnum} records the tracepoint number
+of the most recently set tracepoint.
+
+@kindex delete tracepoint
+@cindex tracepoint deletion
+@item delete tracepoint @r{[}@var{num}@r{]}
+Permanently delete one or more tracepoints. With no argument, the
+default is to delete all tracepoints.
+
+Examples:
+
+@smallexample
+(@value{GDBP}) @b{delete trace 1 2 3} // remove three tracepoints
+
+(@value{GDBP}) @b{delete trace} // remove all tracepoints
+@end smallexample
+
+@noindent
+You can abbreviate this command as @code{del tr}.
+@end table
+
+@node Enable and Disable Tracepoints
+@subsection Enable and Disable Tracepoints
+
+@table @code
+@kindex disable tracepoint
+@item disable tracepoint @r{[}@var{num}@r{]}
+Disable tracepoint @var{num}, or all tracepoints if no argument
+@var{num} is given. A disabled tracepoint will have no effect during
+the next trace experiment, but it is not forgotten. You can re-enable
+a disabled tracepoint using the @code{enable tracepoint} command.
+
+@kindex enable tracepoint
+@item enable tracepoint @r{[}@var{num}@r{]}
+Enable tracepoint @var{num}, or all tracepoints. The enabled
+tracepoints will become effective the next time a trace experiment is
+run.
+@end table
+
+@node Tracepoint Passcounts
+@subsection Tracepoint Passcounts
+
+@table @code
+@kindex passcount
+@cindex tracepoint pass count
+@item passcount @r{[}@var{n} @r{[}@var{num}@r{]]}
+Set the @dfn{passcount} of a tracepoint. The passcount is a way to
+automatically stop a trace experiment. If a tracepoint's passcount is
+@var{n}, then the trace experiment will be automatically stopped on
+the @var{n}'th time that tracepoint is hit. If the tracepoint number
+@var{num} is not specified, the @code{passcount} command sets the
+passcount of the most recently defined tracepoint. If no passcount is
+given, the trace experiment will run until stopped explicitly by the
+user.
+
+Examples:
+
+@smallexample
+(@value{GDBP}) @b{passcount 5 2} // Stop on the 5th execution of
+@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// tracepoint 2}
+
+(@value{GDBP}) @b{passcount 12} // Stop on the 12th execution of the
+@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// most recently defined tracepoint.}
+(@value{GDBP}) @b{trace foo}
+(@value{GDBP}) @b{pass 3}
+(@value{GDBP}) @b{trace bar}
+(@value{GDBP}) @b{pass 2}
+(@value{GDBP}) @b{trace baz}
+(@value{GDBP}) @b{pass 1} // Stop tracing when foo has been
+@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// executed 3 times OR when bar has}
+@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// been executed 2 times}
+@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// OR when baz has been executed 1 time.}
+@end smallexample
+@end table
+
+@node Tracepoint Actions
+@subsection Tracepoint Action Lists
+
+@table @code
+@kindex actions
+@cindex tracepoint actions
+@item actions @r{[}@var{num}@r{]}
+This command will prompt for a list of actions to be taken when the
+tracepoint is hit. If the tracepoint number @var{num} is not
+specified, this command sets the actions for the one that was most
+recently defined (so that you can define a tracepoint and then say
+@code{actions} without bothering about its number). You specify the
+actions themselves on the following lines, one action at a time, and
+terminate the actions list with a line containing just @code{end}. So
+far, the only defined actions are @code{collect} and
+@code{while-stepping}.
+
+@cindex remove actions from a tracepoint
+To remove all actions from a tracepoint, type @samp{actions @var{num}}
+and follow it immediately with @samp{end}.
+
+@smallexample
+(@value{GDBP}) @b{collect @var{data}} // collect some data
+
+(@value{GDBP}) @b{while-stepping 5} // single-step 5 times, collect data
+
+(@value{GDBP}) @b{end} // signals the end of actions.
+@end smallexample
+
+In the following example, the action list begins with @code{collect}
+commands indicating the things to be collected when the tracepoint is
+hit. Then, in order to single-step and collect additional data
+following the tracepoint, a @code{while-stepping} command is used,
+followed by the list of things to be collected while stepping. The
+@code{while-stepping} command is terminated by its own separate
+@code{end} command. Lastly, the action list is terminated by an
+@code{end} command.
+
+@smallexample
+(@value{GDBP}) @b{trace foo}
+(@value{GDBP}) @b{actions}
+Enter actions for tracepoint 1, one per line:
+> collect bar,baz
+> collect $regs
+> while-stepping 12
+ > collect $fp, $sp
+ > end
+end
+@end smallexample
+
+@kindex collect @r{(tracepoints)}
+@item collect @var{expr1}, @var{expr2}, @dots{}
+Collect values of the given expressions when the tracepoint is hit.
+This command accepts a comma-separated list of any valid expressions.
+In addition to global, static, or local variables, the following
+special arguments are supported:
+
+@table @code
+@item $regs
+collect all registers
+
+@item $args
+collect all function arguments
+
+@item $locals
+collect all local variables.
+@end table
+
+You can give several consecutive @code{collect} commands, each one
+with a single argument, or one @code{collect} command with several
+arguments separated by commas: the effect is the same.
+
+The command @code{info scope} (@pxref{Symbols, info scope}) is
+particularly useful for figuring out what data to collect.
+
+@kindex while-stepping @r{(tracepoints)}
+@item while-stepping @var{n}
+Perform @var{n} single-step traces after the tracepoint, collecting
+new data at each step. The @code{while-stepping} command is
+followed by the list of what to collect while stepping (followed by
+its own @code{end} command):
+
+@smallexample
+> while-stepping 12
+ > collect $regs, myglobal
+ > end
+>
+@end smallexample
+
+@noindent
+You may abbreviate @code{while-stepping} as @code{ws} or
+@code{stepping}.
+@end table
+
+@node Listing Tracepoints
+@subsection Listing Tracepoints
+
+@table @code
+@kindex info tracepoints
+@cindex information about tracepoints
+@item info tracepoints @r{[}@var{num}@r{]}
+Display information about the tracepoint @var{num}. If you don't specify
+a tracepoint number, displays information about all the tracepoints
+defined so far. For each tracepoint, the following information is
+shown:
+
+@itemize @bullet
+@item
+its number
+@item
+whether it is enabled or disabled
+@item
+its address
+@item
+its passcount as given by the @code{passcount @var{n}} command
+@item
+its step count as given by the @code{while-stepping @var{n}} command
+@item
+where in the source files is the tracepoint set
+@item
+its action list as given by the @code{actions} command
+@end itemize
+
+@smallexample
+(@value{GDBP}) @b{info trace}
+Num Enb Address PassC StepC What
+1 y 0x002117c4 0 0 <gdb_asm>
+2 y 0x0020dc64 0 0 in g_test at g_test.c:1375
+3 y 0x0020b1f4 0 0 in get_data at ../foo.c:41
+(@value{GDBP})
+@end smallexample
+
+@noindent
+This command can be abbreviated @code{info tp}.
+@end table
+
+@node Starting and Stopping Trace Experiment
+@subsection Starting and Stopping Trace Experiment
+
+@table @code
+@kindex tstart
+@cindex start a new trace experiment
+@cindex collected data discarded
+@item tstart
+This command takes no arguments. It starts the trace experiment, and
+begins collecting data. This has the side effect of discarding all
+the data collected in the trace buffer during the previous trace
+experiment.
+
+@kindex tstop
+@cindex stop a running trace experiment
+@item tstop
+This command takes no arguments. It ends the trace experiment, and
+stops collecting data.
+
+@strong{Note:} a trace experiment and data collection may stop
+automatically if any tracepoint's passcount is reached
+(@pxref{Tracepoint Passcounts}), or if the trace buffer becomes full.
+
+@kindex tstatus
+@cindex status of trace data collection
+@cindex trace experiment, status of
+@item tstatus
+This command displays the status of the current trace data
+collection.
+@end table
+
+Here is an example of the commands we described so far:
+
+@smallexample
+(@value{GDBP}) @b{trace gdb_c_test}
+(@value{GDBP}) @b{actions}
+Enter actions for tracepoint #1, one per line.
+> collect $regs,$locals,$args
+> while-stepping 11
+ > collect $regs
+ > end
+> end
+(@value{GDBP}) @b{tstart}
+ [time passes @dots{}]
+(@value{GDBP}) @b{tstop}
+@end smallexample
+
+
+@node Analyze Collected Data
+@section Using the collected data
+
+After the tracepoint experiment ends, you use @value{GDBN} commands
+for examining the trace data. The basic idea is that each tracepoint
+collects a trace @dfn{snapshot} every time it is hit and another
+snapshot every time it single-steps. All these snapshots are
+consecutively numbered from zero and go into a buffer, and you can
+examine them later. The way you examine them is to @dfn{focus} on a
+specific trace snapshot. When the remote stub is focused on a trace
+snapshot, it will respond to all @value{GDBN} requests for memory and
+registers by reading from the buffer which belongs to that snapshot,
+rather than from @emph{real} memory or registers of the program being
+debugged. This means that @strong{all} @value{GDBN} commands
+(@code{print}, @code{info registers}, @code{backtrace}, etc.) will
+behave as if we were currently debugging the program state as it was
+when the tracepoint occurred. Any requests for data that are not in
+the buffer will fail.
+
+@menu
+* tfind:: How to select a trace snapshot
+* tdump:: How to display all data for a snapshot
+* save-tracepoints:: How to save tracepoints for a future run
+@end menu
+
+@node tfind
+@subsection @code{tfind @var{n}}
+
+@kindex tfind
+@cindex select trace snapshot
+@cindex find trace snapshot
+The basic command for selecting a trace snapshot from the buffer is
+@code{tfind @var{n}}, which finds trace snapshot number @var{n},
+counting from zero. If no argument @var{n} is given, the next
+snapshot is selected.
+
+Here are the various forms of using the @code{tfind} command.
+
+@table @code
+@item tfind start
+Find the first snapshot in the buffer. This is a synonym for
+@code{tfind 0} (since 0 is the number of the first snapshot).
+
+@item tfind none
+Stop debugging trace snapshots, resume @emph{live} debugging.
+
+@item tfind end
+Same as @samp{tfind none}.
+
+@item tfind
+No argument means find the next trace snapshot.
+
+@item tfind -
+Find the previous trace snapshot before the current one. This permits
+retracing earlier steps.
+
+@item tfind tracepoint @var{num}
+Find the next snapshot associated with tracepoint @var{num}. Search
+proceeds forward from the last examined trace snapshot. If no
+argument @var{num} is given, it means find the next snapshot collected
+for the same tracepoint as the current snapshot.
+
+@item tfind pc @var{addr}
+Find the next snapshot associated with the value @var{addr} of the
+program counter. Search proceeds forward from the last examined trace
+snapshot. If no argument @var{addr} is given, it means find the next
+snapshot with the same value of PC as the current snapshot.
+
+@item tfind outside @var{addr1}, @var{addr2}
+Find the next snapshot whose PC is outside the given range of
+addresses.
+
+@item tfind range @var{addr1}, @var{addr2}
+Find the next snapshot whose PC is between @var{addr1} and
+@var{addr2}. @c FIXME: Is the range inclusive or exclusive?
+
+@item tfind line @r{[}@var{file}:@r{]}@var{n}
+Find the next snapshot associated with the source line @var{n}. If
+the optional argument @var{file} is given, refer to line @var{n} in
+that source file. Search proceeds forward from the last examined
+trace snapshot. If no argument @var{n} is given, it means find the
+next line other than the one currently being examined; thus saying
+@code{tfind line} repeatedly can appear to have the same effect as
+stepping from line to line in a @emph{live} debugging session.
+@end table
+
+The default arguments for the @code{tfind} commands are specifically
+designed to make it easy to scan through the trace buffer. For
+instance, @code{tfind} with no argument selects the next trace
+snapshot, and @code{tfind -} with no argument selects the previous
+trace snapshot. So, by giving one @code{tfind} command, and then
+simply hitting @key{RET} repeatedly you can examine all the trace
+snapshots in order. Or, by saying @code{tfind -} and then hitting
+@key{RET} repeatedly you can examine the snapshots in reverse order.
+The @code{tfind line} command with no argument selects the snapshot
+for the next source line executed. The @code{tfind pc} command with
+no argument selects the next snapshot with the same program counter
+(PC) as the current frame. The @code{tfind tracepoint} command with
+no argument selects the next trace snapshot collected by the same
+tracepoint as the current one.
+
+In addition to letting you scan through the trace buffer manually,
+these commands make it easy to construct @value{GDBN} scripts that
+scan through the trace buffer and print out whatever collected data
+you are interested in. Thus, if we want to examine the PC, FP, and SP
+registers from each trace frame in the buffer, we can say this:
+
+@smallexample
+(@value{GDBP}) @b{tfind start}
+(@value{GDBP}) @b{while ($trace_frame != -1)}
+> printf "Frame %d, PC = %08X, SP = %08X, FP = %08X\n", \
+ $trace_frame, $pc, $sp, $fp
+> tfind
+> end
+
+Frame 0, PC = 0020DC64, SP = 0030BF3C, FP = 0030BF44
+Frame 1, PC = 0020DC6C, SP = 0030BF38, FP = 0030BF44
+Frame 2, PC = 0020DC70, SP = 0030BF34, FP = 0030BF44
+Frame 3, PC = 0020DC74, SP = 0030BF30, FP = 0030BF44
+Frame 4, PC = 0020DC78, SP = 0030BF2C, FP = 0030BF44
+Frame 5, PC = 0020DC7C, SP = 0030BF28, FP = 0030BF44
+Frame 6, PC = 0020DC80, SP = 0030BF24, FP = 0030BF44
+Frame 7, PC = 0020DC84, SP = 0030BF20, FP = 0030BF44
+Frame 8, PC = 0020DC88, SP = 0030BF1C, FP = 0030BF44
+Frame 9, PC = 0020DC8E, SP = 0030BF18, FP = 0030BF44
+Frame 10, PC = 00203F6C, SP = 0030BE3C, FP = 0030BF14
+@end smallexample
+
+Or, if we want to examine the variable @code{X} at each source line in
+the buffer:
+
+@smallexample
+(@value{GDBP}) @b{tfind start}
+(@value{GDBP}) @b{while ($trace_frame != -1)}
+> printf "Frame %d, X == %d\n", $trace_frame, X
+> tfind line
+> end
+
+Frame 0, X = 1
+Frame 7, X = 2
+Frame 13, X = 255
+@end smallexample
+
+@node tdump
+@subsection @code{tdump}
+@kindex tdump
+@cindex dump all data collected at tracepoint
+@cindex tracepoint data, display
+
+This command takes no arguments. It prints all the data collected at
+the current trace snapshot.
+
+@smallexample
+(@value{GDBP}) @b{trace 444}
+(@value{GDBP}) @b{actions}
+Enter actions for tracepoint #2, one per line:
+> collect $regs, $locals, $args, gdb_long_test
+> end
+
+(@value{GDBP}) @b{tstart}
+
+(@value{GDBP}) @b{tfind line 444}
+#0 gdb_test (p1=0x11, p2=0x22, p3=0x33, p4=0x44, p5=0x55, p6=0x66)
+at gdb_test.c:444
+444 printp( "%s: arguments = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", )
+
+(@value{GDBP}) @b{tdump}
+Data collected at tracepoint 2, trace frame 1:
+d0 0xc4aa0085 -995491707
+d1 0x18 24
+d2 0x80 128
+d3 0x33 51
+d4 0x71aea3d 119204413
+d5 0x22 34
+d6 0xe0 224
+d7 0x380035 3670069
+a0 0x19e24a 1696330
+a1 0x3000668 50333288
+a2 0x100 256
+a3 0x322000 3284992
+a4 0x3000698 50333336
+a5 0x1ad3cc 1758156
+fp 0x30bf3c 0x30bf3c
+sp 0x30bf34 0x30bf34
+ps 0x0 0
+pc 0x20b2c8 0x20b2c8
+fpcontrol 0x0 0
+fpstatus 0x0 0
+fpiaddr 0x0 0
+p = 0x20e5b4 "gdb-test"
+p1 = (void *) 0x11
+p2 = (void *) 0x22
+p3 = (void *) 0x33
+p4 = (void *) 0x44
+p5 = (void *) 0x55
+p6 = (void *) 0x66
+gdb_long_test = 17 '\021'
+
+(@value{GDBP})
+@end smallexample
+
+@node save-tracepoints
+@subsection @code{save-tracepoints @var{filename}}
+@kindex save-tracepoints
+@cindex save tracepoints for future sessions
+
+This command saves all current tracepoint definitions together with
+their actions and passcounts, into a file @file{@var{filename}}
+suitable for use in a later debugging session. To read the saved
+tracepoint definitions, use the @code{source} command (@pxref{Command
+Files}).
+
+@node Tracepoint Variables
+@section Convenience Variables for Tracepoints
+@cindex tracepoint variables
+@cindex convenience variables for tracepoints
+
+@table @code
+@vindex $trace_frame
+@item (int) $trace_frame
+The current trace snapshot (a.k.a.@: @dfn{frame}) number, or -1 if no
+snapshot is selected.
+
+@vindex $tracepoint
+@item (int) $tracepoint
+The tracepoint for the current trace snapshot.
+
+@vindex $trace_line
+@item (int) $trace_line
+The line number for the current trace snapshot.
+
+@vindex $trace_file
+@item (char []) $trace_file
+The source file for the current trace snapshot.
+
+@vindex $trace_func
+@item (char []) $trace_func
+The name of the function containing @code{$tracepoint}.
+@end table
+
+Note: @code{$trace_file} is not suitable for use in @code{printf},
+use @code{output} instead.
+
+Here's a simple example of using these convenience variables for
+stepping through all the trace snapshots and printing some of their
+data.
+
+@smallexample
+(@value{GDBP}) @b{tfind start}
+
+(@value{GDBP}) @b{while $trace_frame != -1}
+> output $trace_file
+> printf ", line %d (tracepoint #%d)\n", $trace_line, $tracepoint
+> tfind
+> end
+@end smallexample
+
+@node Overlays
+@chapter Debugging Programs That Use Overlays
+@cindex overlays
+
+If your program is too large to fit completely in your target system's
+memory, you can sometimes use @dfn{overlays} to work around this
+problem. @value{GDBN} provides some support for debugging programs that
+use overlays.
+
+@menu
+* How Overlays Work:: A general explanation of overlays.
+* Overlay Commands:: Managing overlays in @value{GDBN}.
+* Automatic Overlay Debugging:: @value{GDBN} can find out which overlays are
+ mapped by asking the inferior.
+* Overlay Sample Program:: A sample program using overlays.
+@end menu
+
+@node How Overlays Work
+@section How Overlays Work
+@cindex mapped overlays
+@cindex unmapped overlays
+@cindex load address, overlay's
+@cindex mapped address
+@cindex overlay area
+
+Suppose you have a computer whose instruction address space is only 64
+kilobytes long, but which has much more memory which can be accessed by
+other means: special instructions, segment registers, or memory
+management hardware, for example. Suppose further that you want to
+adapt a program which is larger than 64 kilobytes to run on this system.
+
+One solution is to identify modules of your program which are relatively
+independent, and need not call each other directly; call these modules
+@dfn{overlays}. Separate the overlays from the main program, and place
+their machine code in the larger memory. Place your main program in
+instruction memory, but leave at least enough space there to hold the
+largest overlay as well.
+
+Now, to call a function located in an overlay, you must first copy that
+overlay's machine code from the large memory into the space set aside
+for it in the instruction memory, and then jump to its entry point
+there.
+
+@c NB: In the below the mapped area's size is greater or equal to the
+@c size of all overlays. This is intentional to remind the developer
+@c that overlays don't necessarily need to be the same size.
+
+@smallexample
+@group
+ Data Instruction Larger
+Address Space Address Space Address Space
++-----------+ +-----------+ +-----------+
+| | | | | |
++-----------+ +-----------+ +-----------+<-- overlay 1
+| program | | main | .----| overlay 1 | load address
+| variables | | program | | +-----------+
+| and heap | | | | | |
++-----------+ | | | +-----------+<-- overlay 2
+| | +-----------+ | | | load address
++-----------+ | | | .-| overlay 2 |
+ | | | | | |
+ mapped --->+-----------+ | | +-----------+
+ address | | | | | |
+ | overlay | <-' | | |
+ | area | <---' +-----------+<-- overlay 3
+ | | <---. | | load address
+ +-----------+ `--| overlay 3 |
+ | | | |
+ +-----------+ | |
+ +-----------+
+ | |
+ +-----------+
+
+ @anchor{A code overlay}A code overlay
+@end group
+@end smallexample
+
+The diagram (@pxref{A code overlay}) shows a system with separate data
+and instruction address spaces. To map an overlay, the program copies
+its code from the larger address space to the instruction address space.
+Since the overlays shown here all use the same mapped address, only one
+may be mapped at a time. For a system with a single address space for
+data and instructions, the diagram would be similar, except that the
+program variables and heap would share an address space with the main
+program and the overlay area.
+
+An overlay loaded into instruction memory and ready for use is called a
+@dfn{mapped} overlay; its @dfn{mapped address} is its address in the
+instruction memory. An overlay not present (or only partially present)
+in instruction memory is called @dfn{unmapped}; its @dfn{load address}
+is its address in the larger memory. The mapped address is also called
+the @dfn{virtual memory address}, or @dfn{VMA}; the load address is also
+called the @dfn{load memory address}, or @dfn{LMA}.
+
+Unfortunately, overlays are not a completely transparent way to adapt a
+program to limited instruction memory. They introduce a new set of
+global constraints you must keep in mind as you design your program:
+
+@itemize @bullet
+
+@item
+Before calling or returning to a function in an overlay, your program
+must make sure that overlay is actually mapped. Otherwise, the call or
+return will transfer control to the right address, but in the wrong
+overlay, and your program will probably crash.
+
+@item
+If the process of mapping an overlay is expensive on your system, you
+will need to choose your overlays carefully to minimize their effect on
+your program's performance.
+
+@item
+The executable file you load onto your system must contain each
+overlay's instructions, appearing at the overlay's load address, not its
+mapped address. However, each overlay's instructions must be relocated
+and its symbols defined as if the overlay were at its mapped address.
+You can use GNU linker scripts to specify different load and relocation
+addresses for pieces of your program; see @ref{Overlay Description,,,
+ld.info, Using ld: the GNU linker}.
+
+@item
+The procedure for loading executable files onto your system must be able
+to load their contents into the larger address space as well as the
+instruction and data spaces.
+
+@end itemize
+
+The overlay system described above is rather simple, and could be
+improved in many ways:
+
+@itemize @bullet
+
+@item
+If your system has suitable bank switch registers or memory management
+hardware, you could use those facilities to make an overlay's load area
+contents simply appear at their mapped address in instruction space.
+This would probably be faster than copying the overlay to its mapped
+area in the usual way.
+
+@item
+If your overlays are small enough, you could set aside more than one
+overlay area, and have more than one overlay mapped at a time.
+
+@item
+You can use overlays to manage data, as well as instructions. In
+general, data overlays are even less transparent to your design than
+code overlays: whereas code overlays only require care when you call or
+return to functions, data overlays require care every time you access
+the data. Also, if you change the contents of a data overlay, you
+must copy its contents back out to its load address before you can copy a
+different data overlay into the same mapped area.
+
+@end itemize
+
+
+@node Overlay Commands
+@section Overlay Commands
+
+To use @value{GDBN}'s overlay support, each overlay in your program must
+correspond to a separate section of the executable file. The section's
+virtual memory address and load memory address must be the overlay's
+mapped and load addresses. Identifying overlays with sections allows
+@value{GDBN} to determine the appropriate address of a function or
+variable, depending on whether the overlay is mapped or not.
+
+@value{GDBN}'s overlay commands all start with the word @code{overlay};
+you can abbreviate this as @code{ov} or @code{ovly}. The commands are:
+
+@table @code
+@item overlay off
+@kindex overlay off
+Disable @value{GDBN}'s overlay support. When overlay support is
+disabled, @value{GDBN} assumes that all functions and variables are
+always present at their mapped addresses. By default, @value{GDBN}'s
+overlay support is disabled.
+
+@item overlay manual
+@kindex overlay manual
+@cindex manual overlay debugging
+Enable @dfn{manual} overlay debugging. In this mode, @value{GDBN}
+relies on you to tell it which overlays are mapped, and which are not,
+using the @code{overlay map-overlay} and @code{overlay unmap-overlay}
+commands described below.
+
+@item overlay map-overlay @var{overlay}
+@itemx overlay map @var{overlay}
+@kindex overlay map-overlay
+@cindex map an overlay
+Tell @value{GDBN} that @var{overlay} is now mapped; @var{overlay} must
+be the name of the object file section containing the overlay. When an
+overlay is mapped, @value{GDBN} assumes it can find the overlay's
+functions and variables at their mapped addresses. @value{GDBN} assumes
+that any other overlays whose mapped ranges overlap that of
+@var{overlay} are now unmapped.
+
+@item overlay unmap-overlay @var{overlay}
+@itemx overlay unmap @var{overlay}
+@kindex overlay unmap-overlay
+@cindex unmap an overlay
+Tell @value{GDBN} that @var{overlay} is no longer mapped; @var{overlay}
+must be the name of the object file section containing the overlay.
+When an overlay is unmapped, @value{GDBN} assumes it can find the
+overlay's functions and variables at their load addresses.
+
+@item overlay auto
+@kindex overlay auto
+Enable @dfn{automatic} overlay debugging. In this mode, @value{GDBN}
+consults a data structure the overlay manager maintains in the inferior
+to see which overlays are mapped. For details, see @ref{Automatic
+Overlay Debugging}.
+
+@item overlay load-target
+@itemx overlay load
+@kindex overlay load-target
+@cindex reloading the overlay table
+Re-read the overlay table from the inferior. Normally, @value{GDBN}
+re-reads the table @value{GDBN} automatically each time the inferior
+stops, so this command should only be necessary if you have changed the
+overlay mapping yourself using @value{GDBN}. This command is only
+useful when using automatic overlay debugging.
+
+@item overlay list-overlays
+@itemx overlay list
+@cindex listing mapped overlays
+Display a list of the overlays currently mapped, along with their mapped
+addresses, load addresses, and sizes.
+
+@end table
+
+Normally, when @value{GDBN} prints a code address, it includes the name
+of the function the address falls in:
+
+@smallexample
+(gdb) print main
+$3 = @{int ()@} 0x11a0 <main>
+@end smallexample
+@noindent
+When overlay debugging is enabled, @value{GDBN} recognizes code in
+unmapped overlays, and prints the names of unmapped functions with
+asterisks around them. For example, if @code{foo} is a function in an
+unmapped overlay, @value{GDBN} prints it this way:
+
+@smallexample
+(gdb) overlay list
+No sections are mapped.
+(gdb) print foo
+$5 = @{int (int)@} 0x100000 <*foo*>
+@end smallexample
+@noindent
+When @code{foo}'s overlay is mapped, @value{GDBN} prints the function's
+name normally:
+
+@smallexample
+(gdb) overlay list
+Section .ov.foo.text, loaded at 0x100000 - 0x100034,
+ mapped at 0x1016 - 0x104a
+(gdb) print foo
+$6 = @{int (int)@} 0x1016 <foo>
+@end smallexample
+
+When overlay debugging is enabled, @value{GDBN} can find the correct
+address for functions and variables in an overlay, whether or not the
+overlay is mapped. This allows most @value{GDBN} commands, like
+@code{break} and @code{disassemble}, to work normally, even on unmapped
+code. However, @value{GDBN}'s breakpoint support has some limitations:
+
+@itemize @bullet
+@item
+@cindex breakpoints in overlays
+@cindex overlays, setting breakpoints in
+You can set breakpoints in functions in unmapped overlays, as long as
+@value{GDBN} can write to the overlay at its load address.
+@item
+@value{GDBN} can not set hardware or simulator-based breakpoints in
+unmapped overlays. However, if you set a breakpoint at the end of your
+overlay manager (and tell @value{GDBN} which overlays are now mapped, if
+you are using manual overlay management), @value{GDBN} will re-set its
+breakpoints properly.
+@end itemize
+
+
+@node Automatic Overlay Debugging
+@section Automatic Overlay Debugging
+@cindex automatic overlay debugging
+
+@value{GDBN} can automatically track which overlays are mapped and which
+are not, given some simple co-operation from the overlay manager in the
+inferior. If you enable automatic overlay debugging with the
+@code{overlay auto} command (@pxref{Overlay Commands}), @value{GDBN}
+looks in the inferior's memory for certain variables describing the
+current state of the overlays.
+
+Here are the variables your overlay manager must define to support
+@value{GDBN}'s automatic overlay debugging:
+
+@table @asis
+
+@item @code{_ovly_table}:
+This variable must be an array of the following structures:
+
+@smallexample
+struct
+@{
+ /* The overlay's mapped address. */
+ unsigned long vma;
+
+ /* The size of the overlay, in bytes. */
+ unsigned long size;
+
+ /* The overlay's load address. */
+ unsigned long lma;
+
+ /* Non-zero if the overlay is currently mapped;
+ zero otherwise. */
+ unsigned long mapped;
+@}
+@end smallexample
+
+@item @code{_novlys}:
+This variable must be a four-byte signed integer, holding the total
+number of elements in @code{_ovly_table}.
+
+@end table
+
+To decide whether a particular overlay is mapped or not, @value{GDBN}
+looks for an entry in @w{@code{_ovly_table}} whose @code{vma} and
+@code{lma} members equal the VMA and LMA of the overlay's section in the
+executable file. When @value{GDBN} finds a matching entry, it consults
+the entry's @code{mapped} member to determine whether the overlay is
+currently mapped.
+
+In addition, your overlay manager may define a function called
+@code{_ovly_debug_event}. If this function is defined, @value{GDBN}
+will silently set a breakpoint there. If the overlay manager then
+calls this function whenever it has changed the overlay table, this
+will enable @value{GDBN} to accurately keep track of which overlays
+are in program memory, and update any breakpoints that may be set
+in overlays. This will allow breakpoints to work even if the
+overlays are kept in ROM or other non-writable memory while they
+are not being executed.
+
+@node Overlay Sample Program
+@section Overlay Sample Program
+@cindex overlay example program
+
+When linking a program which uses overlays, you must place the overlays
+at their load addresses, while relocating them to run at their mapped
+addresses. To do this, you must write a linker script (@pxref{Overlay
+Description,,, ld.info, Using ld: the GNU linker}). Unfortunately,
+since linker scripts are specific to a particular host system, target
+architecture, and target memory layout, this manual cannot provide
+portable sample code demonstrating @value{GDBN}'s overlay support.
+
+However, the @value{GDBN} source distribution does contain an overlaid
+program, with linker scripts for a few systems, as part of its test
+suite. The program consists of the following files from
+@file{gdb/testsuite/gdb.base}:
+
+@table @file
+@item overlays.c
+The main program file.
+@item ovlymgr.c
+A simple overlay manager, used by @file{overlays.c}.
+@item foo.c
+@itemx bar.c
+@itemx baz.c
+@itemx grbx.c
+Overlay modules, loaded and used by @file{overlays.c}.
+@item d10v.ld
+@itemx m32r.ld
+Linker scripts for linking the test program on the @code{d10v-elf}
+and @code{m32r-elf} targets.
+@end table
+
+You can build the test program using the @code{d10v-elf} GCC
+cross-compiler like this:
+
+@smallexample
+$ d10v-elf-gcc -g -c overlays.c
+$ d10v-elf-gcc -g -c ovlymgr.c
+$ d10v-elf-gcc -g -c foo.c
+$ d10v-elf-gcc -g -c bar.c
+$ d10v-elf-gcc -g -c baz.c
+$ d10v-elf-gcc -g -c grbx.c
+$ d10v-elf-gcc -g overlays.o ovlymgr.o foo.o bar.o \
+ baz.o grbx.o -Wl,-Td10v.ld -o overlays
+@end smallexample
+
+The build process is identical for any other architecture, except that
+you must substitute the appropriate compiler and linker script for the
+target system for @code{d10v-elf-gcc} and @code{d10v.ld}.
+
+
+@node Languages
+@chapter Using @value{GDBN} with Different Languages
+@cindex languages
+
+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}.
+
+@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
+* Checks:: Type and range checks
+* Support:: Supported languages
+* Unsupported languages:: Unsupported 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@t{++} 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}, but you can
+set the language associated with a filename extension. @xref{Show, ,
+Displaying the language}.
+
+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
+
+@item .c
+C source file
+
+@item .C
+@itemx .cc
+@itemx .cp
+@itemx .cpp
+@itemx .cxx
+@itemx .c++
+C@t{++} source file
+
+@item .m
+Objective-C source file
+
+@item .f
+@itemx .F
+Fortran source file
+
+@item .mod
+Modula-2 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
+
+In addition, you may set the language associated with a filename
+extension. @xref{Show, , Displaying the language}.
+
+@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
+@code{c} or @code{modula-2}.
+For a list of the supported languages, type @samp{set language}.
+
+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:
+
+@smallexample
+print a = b + c
+@end smallexample
+
+@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.
+
+@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@r{, show the source language}
+@kindex info source@r{, show the source language}
+@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
+
+In unusual circumstances, you may have source files with extensions
+not in the standard list. You can then set the extension associated
+with a language explicitly:
+
+@kindex set extension-language
+@kindex info extensions
+@table @code
+@item set extension-language @var{.ext} @var{language}
+Set source files with extension @var{.ext} to be assumed to be in
+the source language @var{language}.
+
+@item info extensions
+List all the filename extensions and the associated languages.
+@end table
+
+@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@r{, type}
+@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 type checking is on, @value{GDBN} prints a
+message and aborts evaluation of the expression.
+
+@item set check type warn
+Cause the type checker to issue warnings, but to always attempt to
+evaluate the expression. Evaluating the expression may still
+be impossible for other reasons. For example, @value{GDBN} cannot add
+numbers and structures.
+
+@item show type
+Show the current setting of the type checker, and whether or not @value{GDBN}
+is setting it automatically.
+@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
+
+@smallexample
+@var{m} + 1 @result{} @var{s}
+@end smallexample
+
+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@r{, range}
+@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 and range checking is on,
+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
+
+@node Support
+@section Supported languages
+
+@value{GDBN} supports C, C@t{++}, Objective-C, Fortran, Java, assembly, and Modula-2.
+@c This is false ...
+Some @value{GDBN} features may be used in expressions regardless of the
+language you use: the @value{GDBN} @code{@@} and @code{::} operators,
+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.
+
+@menu
+* C:: C and C@t{++}
+* Objective-C:: Objective-C
+* Modula-2:: Modula-2
+@end menu
+
+@node C
+@subsection C and C@t{++}
+
+@cindex C and C@t{++}
+@cindex expressions in C or C@t{++}
+
+Since C and C@t{++} are so closely related, many features of @value{GDBN} apply
+to both languages. Whenever this is the case, we discuss those languages
+together.
+
+@cindex C@t{++}
+@cindex @code{g++}, @sc{gnu} C@t{++} compiler
+@cindex @sc{gnu} C@t{++}
+The C@t{++} debugging facilities are jointly implemented by the C@t{++}
+compiler and @value{GDBN}. Therefore, to debug your C@t{++} code
+effectively, you must compile your C@t{++} programs with a supported
+C@t{++} compiler, such as @sc{gnu} @code{g++}, or the HP ANSI C@t{++}
+compiler (@code{aCC}).
+
+For best results when using @sc{gnu} C@t{++}, use the DWARF 2 debugging
+format; if it doesn't work on your system, try the stabs+ debugging
+format. You can select those formats explicitly with the @code{g++}
+command-line options @option{-gdwarf-2} and @option{-gstabs+}.
+@xref{Debugging Options,,Options for Debugging Your Program or @sc{gnu}
+CC, gcc.info, Using @sc{gnu} CC}.
+
+@menu
+* C Operators:: C and C@t{++} operators
+* C Constants:: C and C@t{++} constants
+* C plus plus expressions:: C@t{++} expressions
+* C Defaults:: Default settings for C and C@t{++}
+* C Checks:: C and C@t{++} type and range checks
+* Debugging C:: @value{GDBN} and C
+* Debugging C plus plus:: @value{GDBN} features for C@t{++}
+@end menu
+
+@node C Operators
+@subsubsection C and C@t{++} operators
+
+@cindex C and C@t{++} 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 C and C@t{++}, the following definitions hold:
+
+@itemize @bullet
+
+@item
+@emph{Integral types} include @code{int} with any of its storage-class
+specifiers; @code{char}; @code{enum}; and, for C@t{++}, @code{bool}.
+
+@item
+@emph{Floating-point types} include @code{float}, @code{double}, and
+@code{long double} (if supported by the target platform).
+
+@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 precedence.
+@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{++}.
+
+For debugging C@t{++}, @value{GDBN} implements a use of @samp{&} beyond what is
+allowed in the C@t{++} language itself: you can use @samp{&(&@var{ref})}
+(or, if you prefer, simply @samp{&&@var{ref}}) to examine the address
+where a C@t{++} reference variable (declared with @samp{&@var{ref}}) is
+stored.
+
+@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 .*@r{, }->*
+Dereferences of pointers to members.
+
+@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{->}.
+
+@item ::
+C@t{++} scope resolution operator. Defined on @code{struct}, @code{union},
+and @code{class} types.
+
+@item ::
+Doubled colons also represent the @value{GDBN} scope operator
+(@pxref{Expressions, ,Expressions}). Same precedence as @code{::},
+above.
+@end table
+
+If an operator is redefined in the user code, @value{GDBN} usually
+attempts to invoke the redefined version instead of using the operator's
+predefined meaning.
+
+@menu
+* C Constants::
+@end menu
+
+@node C Constants
+@subsubsection C and C@t{++} constants
+
+@cindex C and C@t{++} constants
+
+@value{GDBN} allows you to express the constants of C and C@t{++} in the
+following ways:
+
+@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.
+A floating-point constant may also end with a letter @samp{f} or
+@samp{F}, specifying that the constant should be treated as being of
+the @code{float} (as opposed to the default @code{double}) type; or with
+a letter @samp{l} or @samp{L}, which specifies a @code{long double}
+constant.
+
+@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{"}). Any valid character constant (as described
+above) may appear. Double quotes within the string must be preceded by
+a backslash, so for instance @samp{"a\"b'c"} is a string of five
+characters.
+
+@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
+
+@menu
+* C plus plus expressions::
+* C Defaults::
+* C Checks::
+
+* Debugging C::
+@end menu
+
+@node C plus plus expressions
+@subsubsection C@t{++} expressions
+
+@cindex expressions in C@t{++}
+@value{GDBN} expression handling can interpret most C@t{++} expressions.
+
+@cindex debugging C@t{++} programs
+@cindex C@t{++} compilers
+@cindex debug formats and C@t{++}
+@cindex @value{NGCC} and C@t{++}
+@quotation
+@emph{Warning:} @value{GDBN} can only debug C@t{++} code if you use the
+proper compiler and the proper debug format. Currently, @value{GDBN}
+works best when debugging C@t{++} code that is compiled with
+@value{NGCC} 2.95.3 or with @value{NGCC} 3.1 or newer, using the options
+@option{-gdwarf-2} or @option{-gstabs+}. DWARF 2 is preferred over
+stabs+. Most configurations of @value{NGCC} emit either DWARF 2 or
+stabs+ as their default debug format, so you usually don't need to
+specify a debug format explicitly. Other compilers and/or debug formats
+are likely to work badly or not at all when using @value{GDBN} to debug
+C@t{++} code.
+@end quotation
+
+@enumerate
+
+@cindex member functions
+@item
+Member function calls are allowed; you can use expressions like
+
+@smallexample
+count = aml->GetOriginal(x, y)
+@end smallexample
+
+@vindex this@r{, inside C@t{++} member functions}
+@cindex namespace in C@t{++}
+@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@t{++}.
+
+@cindex call overloaded functions
+@cindex overloaded functions, calling
+@cindex type conversions in C@t{++}
+@item
+You can call overloaded functions; @value{GDBN} resolves the function
+call to the right definition, with some restrictions. @value{GDBN} does not
+perform overload resolution involving user-defined type conversions,
+calls to constructors, or instantiations of templates that do not exist
+in the program. It also cannot handle ellipsis argument lists or
+default arguments.
+
+It does perform integral conversions and promotions, floating-point
+promotions, arithmetic conversions, pointer conversions, conversions of
+class objects to base classes, and standard conversions such as those of
+functions or arrays to pointers; it requires an exact match on the
+number of function arguments.
+
+Overload resolution is always performed, unless you have specified
+@code{set overload-resolution off}. @xref{Debugging C plus plus,
+,@value{GDBN} features for C@t{++}}.
+
+You must specify @code{set overload-resolution off} in order to use an
+explicit function signature to call an overloaded function, as in
+@smallexample
+p 'foo(char,int)'('x', 13)
+@end smallexample
+
+The @value{GDBN} command-completion facility can simplify this;
+see @ref{Completion, ,Command completion}.
+
+@cindex reference declarations
+@item
+@value{GDBN} understands variables declared as C@t{++} references; you can use
+them in expressions just as you do in C@t{++} 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@t{++} 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@t{++}
+debugging (@pxref{Variables, ,Program variables}).
+@end enumerate
+
+In addition, when used with HP's C@t{++} compiler, @value{GDBN} supports
+calling virtual functions correctly, printing out virtual bases of
+objects, calling functions in a base subobject, casting objects, and
+invoking user-defined operators.
+
+@node C Defaults
+@subsubsection C and C@t{++} defaults
+
+@cindex C and C@t{++} defaults
+
+If you allow @value{GDBN} to set type and range checking automatically, they
+both default to @code{off} whenever the working language changes to
+C or C@t{++}. 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}, etc, and when @value{GDBN} enters code compiled from one of
+these files, it sets the working language to C or C@t{++}.
+@xref{Automatically, ,Having @value{GDBN} infer the source language},
+for further details.
+
+@c Type checking is (a) primarily motivated by Modula-2, and (b)
+@c unimplemented. If (b) changes, it might make sense to let this node
+@c appear even if Mod-2 does not, but meanwhile ignore it. roland 16jul93.
+
+@node C Checks
+@subsubsection C and C@t{++} type and range checks
+
+@cindex C and C@t{++} checks
+
+By default, when @value{GDBN} parses C or C@t{++} expressions, type checking
+is not used. However, if you turn type checking on, @value{GDBN}
+considers two variables type equivalent if:
+
+@itemize @bullet
+@item
+The two variables are structured and have the same structure, union, or
+enumerated tag.
+
+@item
+The two variables have the same type name, or types that have been
+declared equivalent through @code{typedef}.
+
+@ignore
+@c leaving this out because neither J Gilmore nor R Pesch understand it.
+@c FIXME--beers?
+@item
+The two @code{struct}, @code{union}, or @code{enum} variables are
+declared in the same declaration. (Note: this may not be true for all C
+compilers.)
+@end ignore
+@end itemize
+
+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.
+
+@node Debugging C
+@subsubsection @value{GDBN} and C
+
+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} or @code{class} 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}.
+
+@menu
+* Debugging C plus plus::
+@end menu
+
+@node Debugging C plus plus
+@subsubsection @value{GDBN} features for C@t{++}
+
+@cindex commands for C@t{++}
+
+Some @value{GDBN} commands are particularly useful with C@t{++}, and some are
+designed specifically for use with C@t{++}. 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@t{++}
+@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@t{++} exception handling
+@item catch throw
+@itemx catch catch
+Debug C@t{++} exception handling using these commands. @xref{Set
+Catchpoints, , Setting catchpoints}.
+
+@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@t{++} symbol display
+@item set print demangle
+@itemx show print demangle
+@itemx set print asm-demangle
+@itemx show print asm-demangle
+Control whether C@t{++} symbols display in their source form, both when
+displaying code as C@t{++} 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}.
+(The @code{vtbl} commands do not work on programs compiled with the HP
+ANSI C@t{++} compiler (@code{aCC}).)
+
+@kindex set overload-resolution
+@cindex overloaded functions, overload resolution
+@item set overload-resolution on
+Enable overload resolution for C@t{++} expression evaluation. The default
+is on. For overloaded functions, @value{GDBN} evaluates the arguments
+and searches for a function whose signature matches the argument types,
+using the standard C@t{++} conversion rules (see @ref{C plus plus expressions, ,C@t{++}
+expressions}, for details). If it cannot find a match, it emits a
+message.
+
+@item set overload-resolution off
+Disable overload resolution for C@t{++} expression evaluation. For
+overloaded functions that are not class member functions, @value{GDBN}
+chooses the first function of the specified name that it finds in the
+symbol table, whether or not its arguments are of the correct type. For
+overloaded functions that are class member functions, @value{GDBN}
+searches for a function whose signature @emph{exactly} matches the
+argument types.
+
+@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@t{++}: 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
+
+@node Objective-C
+@subsection Objective-C
+
+@cindex Objective-C
+This section provides information about some commands and command
+options that are useful for debugging Objective-C code.
+
+@menu
+* Method Names in Commands::
+* The Print Command with Objective-C::
+@end menu
+
+@node Method Names in Commands, The Print Command with Objective-C, Objective-C, Objective-C
+@subsubsection Method Names in Commands
+
+The following commands have been extended to accept Objective-C method
+names as line specifications:
+
+@kindex clear@r{, and Objective-C}
+@kindex break@r{, and Objective-C}
+@kindex info line@r{, and Objective-C}
+@kindex jump@r{, and Objective-C}
+@kindex list@r{, and Objective-C}
+@itemize
+@item @code{clear}
+@item @code{break}
+@item @code{info line}
+@item @code{jump}
+@item @code{list}
+@end itemize
+
+A fully qualified Objective-C method name is specified as
+
+@smallexample
+-[@var{Class} @var{methodName}]
+@end smallexample
+
+where the minus sign is used to indicate an instance method and a
+plus sign (not shown) is used to indicate a class method. The class
+name @var{Class} and method name @var{methodName} are enclosed in
+brackets, similar to the way messages are specified in Objective-C
+source code. For example, to set a breakpoint at the @code{create}
+instance method of class @code{Fruit} in the program currently being
+debugged, enter:
+
+@smallexample
+break -[Fruit create]
+@end smallexample
+
+To list ten program lines around the @code{initialize} class method,
+enter:
+
+@smallexample
+list +[NSText initialize]
+@end smallexample
+
+In the current version of @value{GDBN}, the plus or minus sign is
+required. In future versions of @value{GDBN}, the plus or minus
+sign will be optional, but you can use it to narrow the search. It
+is also possible to specify just a method name:
+
+@smallexample
+break create
+@end smallexample
+
+You must specify the complete method name, including any colons. If
+your program's source files contain more than one @code{create} method,
+you'll be presented with a numbered list of classes that implement that
+method. Indicate your choice by number, or type @samp{0} to exit if
+none apply.
+
+As another example, to clear a breakpoint established at the
+@code{makeKeyAndOrderFront:} method of the @code{NSWindow} class, enter:
+
+@smallexample
+clear -[NSWindow makeKeyAndOrderFront:]
+@end smallexample
+
+@node The Print Command with Objective-C
+@subsubsection The Print Command With Objective-C
+@kindex print-object
+@kindex po @r{(@code{print-object})}
+
+The print command has also been extended to accept methods. For example:
+
+@smallexample
+print -[@var{object} hash]
+@end smallexample
+
+@cindex print an Objective-C object description
+@cindex @code{_NSPrintForDebugger}, and printing Objective-C objects
+@noindent
+will tell @value{GDBN} to send the @code{hash} message to @var{object}
+and print the result. Also, an additional command has been added,
+@code{print-object} or @code{po} for short, which is meant to print
+the description of an object. However, this command may only work
+with certain Objective-C libraries that have a particular hook
+function, @code{_NSPrintForDebugger}, defined.
+
+@node Modula-2, , Objective-C, Support
+@subsection Modula-2
+
+@cindex Modula-2, @value{GDBN} support
+
+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 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 conjunction. 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
+
+
+@node Built-In Func/Proc
+@subsubsection Built-in functions and procedures
+@cindex Modula-2 built-ins
+
+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} by one. 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} by one. 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 @sc{ascii} value (on machines supporting the
+@sc{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 @sc{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@t{++} 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
+@cindex @code{.}, Modula-2 scope operator
+@cindex colon, doubled as scope operator
+@ifinfo
+@vindex colon-colon@r{, in Modula-2}
+@c Info cannot handle :: but TeX can.
+@end ifinfo
+@iftex
+@vindex ::@r{, in Modula-2}
+@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:
+
+@smallexample
+
+@var{module} . @var{id}
+@var{scope} :: @var{id}
+@end smallexample
+
+@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@t{++}: @samp{vtbl}, @samp{demangle},
+@samp{asm-demangle}, @samp{object}, and @samp{union}. The first four
+apply to C@t{++}, 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
+with 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@t{++}. However, because an
+address can be specified by an integral constant, the construct
+@samp{@{@var{type}@}@var{adrexp}} is still useful.
+
+@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.
+
+@node Unsupported languages
+@section Unsupported languages
+
+@cindex unsupported languages
+@cindex minimal language
+In addition to the other fully-supported programming languages,
+@value{GDBN} also provides a pseudo-language, called @code{minimal}.
+It does not represent a real programming language, but provides a set
+of capabilities close to what the C or assembly languages provide.
+This should allow most simple operations to be performed while debugging
+an application that uses a language currently not supported by @value{GDBN}.
+
+If the language is set to @code{auto}, @value{GDBN} will automatically
+select this language if the current frame corresponds to an unsupported
+language.
+
+@node Symbols
+@chapter Examining the Symbol Table
+
+The commands described in this chapter 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,
+
+@smallexample
+p 'foo.c'::x
+@end smallexample
+
+@noindent
+looks up the value of @code{x} in the scope of the file @file{foo.c}.
+
+@table @code
+@kindex info address
+@cindex address of a symbol
+@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 info symbol
+@cindex symbol from address
+@item info symbol @var{addr}
+Print the name of a symbol which is stored at the address @var{addr}.
+If no symbol is stored exactly at @var{addr}, @value{GDBN} prints the
+nearest symbol and an offset from it:
+
+@smallexample
+(@value{GDBP}) info symbol 0x54320
+_initialize_vx + 396 in section .text
+@end smallexample
+
+@noindent
+This is the opposite of the @code{info address} command. You can use
+it to find out the name of a variable or a function given its address.
+
+@kindex whatis
+@item whatis @var{expr}
+Print the data type of expression @var{expr}. @var{expr} 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 @samp{class
+@var{class-name}}, @samp{struct @var{struct-tag}}, @samp{union
+@var{union-tag}} or @samp{enum @var{enum-tag}}.
+
+@item ptype @var{expr}
+@itemx ptype
+Print a description of the type of expression @var{expr}. @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:
+
+@smallexample
+struct complex @{double real; double imag;@} v;
+@end smallexample
+
+@noindent
+the two commands give this output:
+
+@smallexample
+@group
+(@value{GDBP}) whatis v
+type = struct complex
+(@value{GDBP}) ptype v
+type = struct complex @{
+ double real;
+ double imag;
+@}
+@end group
+@end smallexample
+
+@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 names match @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
+names include 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 scope
+@cindex local variables
+@item info scope @var{addr}
+List all the variables local to a particular scope. This command
+accepts a location---a function name, a source line, or an address
+preceded by a @samp{*}, and prints all the variables local to the
+scope defined by that location. For example:
+
+@smallexample
+(@value{GDBP}) @b{info scope command_line_handler}
+Scope for command_line_handler:
+Symbol rl is an argument at stack/frame offset 8, length 4.
+Symbol linebuffer is in static storage at address 0x150a18, length 4.
+Symbol linelength is in static storage at address 0x150a1c, length 4.
+Symbol p is a local variable in register $esi, length 4.
+Symbol p1 is a local variable in register $ebx, length 4.
+Symbol nline is a local variable in register $edx, length 4.
+Symbol repeat is a local variable at frame offset -8, length 4.
+@end smallexample
+
+@noindent
+This command is especially useful for determining what data to collect
+during a @dfn{trace experiment}, see @ref{Tracepoint Actions,
+collect}.
+
+@kindex info source
+@item info source
+Show information about the current source file---that is, the source file for
+the function containing the current point of execution:
+@itemize @bullet
+@item
+the name of the source file, and the directory containing it,
+@item
+the directory it was compiled in,
+@item
+its length, in lines,
+@item
+which programming language it is written in,
+@item
+whether the executable includes debugging information for that file, and
+if so, what format the information is in (e.g., STABS, Dwarf 2, etc.), and
+@item
+whether the debugging information includes information about
+preprocessor macros.
+@end itemize
+
+
+@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}. If a function name contains characters
+that conflict with the regular expression language (eg.
+@samp{operator*()}), they may be quoted with a backslash.
+
+@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}.
+
+@kindex info classes
+@item info classes
+@itemx info classes @var{regexp}
+Display all Objective-C classes in your program, or
+(with the @var{regexp} argument) all those matching a particular regular
+expression.
+
+@kindex info selectors
+@item info selectors
+@itemx info selectors @var{regexp}
+Display all Objective-C selectors in your program, or
+(with the @var{regexp} argument) all those matching a particular regular
+expression.
+
+@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@t{++} program, or (with the @var{regexp} argument) a
+specific set of methods found in the various C@t{++} classes. Many
+C@t{++} 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. For example,
+in VxWorks you can simply recompile a defective object file and keep on
+running. If you are running on one of these systems, you can allow
+@value{GDBN} to reload the symbols for automatically relinked modules:
+
+@table @code
+@kindex set symbol-reloading
+@item set symbol-reloading on
+Replace symbol definitions for the corresponding source file when an
+object file with a particular name is seen again.
+
+@item set symbol-reloading off
+Do not replace symbol definitions when encountering object files of the
+same name more than once. This is the default state; if you are not
+running on a system that permits automatic relinking of modules, you
+should leave @code{symbol-reloading} off, since otherwise @value{GDBN}
+may discard symbols when linking large programs, that may contain
+several modules (from different directories or libraries) with the same
+name.
+
+@kindex show symbol-reloading
+@item show symbol-reloading
+Show the current @code{on} or @code{off} setting.
+@end table
+
+@kindex set opaque-type-resolution
+@item set opaque-type-resolution on
+Tell @value{GDBN} to resolve opaque types. An opaque type is a type
+declared as a pointer to a @code{struct}, @code{class}, or
+@code{union}---for example, @code{struct MyType *}---that is used in one
+source file although the full declaration of @code{struct MyType} is in
+another source file. The default is on.
+
+A change in the setting of this subcommand will not take effect until
+the next time symbols for a file are loaded.
+
+@item set opaque-type-resolution off
+Tell @value{GDBN} not to resolve opaque types. In this case, the type
+is printed as follows:
+@smallexample
+@{<no data fields>@}
+@end smallexample
+
+@kindex show opaque-type-resolution
+@item show opaque-type-resolution
+Show whether opaque types are resolved or not.
+
+@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}).
+
+@kindex maint info symtabs
+@kindex maint info psymtabs
+@cindex listing @value{GDBN}'s internal symbol tables
+@cindex symbol tables, listing @value{GDBN}'s internal
+@cindex full symbol tables, listing @value{GDBN}'s internal
+@cindex partial symbol tables, listing @value{GDBN}'s internal
+@item maint info symtabs @r{[} @var{regexp} @r{]}
+@itemx maint info psymtabs @r{[} @var{regexp} @r{]}
+
+List the @code{struct symtab} or @code{struct partial_symtab}
+structures whose names match @var{regexp}. If @var{regexp} is not
+given, list them all. The output includes expressions which you can
+copy into a @value{GDBN} debugging this one to examine a particular
+structure in more detail. For example:
+
+@smallexample
+(@value{GDBP}) maint info psymtabs dwarf2read
+@{ objfile /home/gnu/build/gdb/gdb
+ ((struct objfile *) 0x82e69d0)
+ @{ psymtab /home/gnu/src/gdb/dwarf2read.c
+ ((struct partial_symtab *) 0x8474b10)
+ readin no
+ fullname (null)
+ text addresses 0x814d3c8 -- 0x8158074
+ globals (* (struct partial_symbol **) 0x8507a08 @@ 9)
+ statics (* (struct partial_symbol **) 0x40e95b78 @@ 2882)
+ dependencies (none)
+ @}
+@}
+(@value{GDBP}) maint info symtabs
+(@value{GDBP})
+@end smallexample
+@noindent
+We see that there is one partial symbol table whose filename contains
+the string @samp{dwarf2read}, belonging to the @samp{gdb} executable;
+and we see that @value{GDBN} has not read in any symtabs yet at all.
+If we set a breakpoint on a function, that will cause @value{GDBN} to
+read the symtab for the compilation unit containing that function:
+
+@smallexample
+(@value{GDBP}) break dwarf2_psymtab_to_symtab
+Breakpoint 1 at 0x814e5da: file /home/gnu/src/gdb/dwarf2read.c,
+line 1574.
+(@value{GDBP}) maint info symtabs
+@{ objfile /home/gnu/build/gdb/gdb
+ ((struct objfile *) 0x82e69d0)
+ @{ symtab /home/gnu/src/gdb/dwarf2read.c
+ ((struct symtab *) 0x86c1f38)
+ dirname (null)
+ fullname (null)
+ blockvector ((struct blockvector *) 0x86c1bd0) (primary)
+ debugformat DWARF 2
+ @}
+@}
+(@value{GDBP})
+@end smallexample
+@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, give your program a signal, restart it at a different
+address, or even return prematurely from a function.
+
+@menu
+* Assignment:: Assignment to variables
+* Jumping:: Continuing at a different address
+* Signaling:: Giving your program a signal
+* 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,
+
+@smallexample
+print x=4
+@end smallexample
+
+@noindent
+stores the value 4 into the variable @code{x}, and then prints the
+value of the assignment expression (which is 4).
+@xref{Languages, ,Using @value{GDBN} with Different Languages}, for more
+information on operators in supported languages.
+
+@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}:
+
+@smallexample
+(@value{GDBP}) whatis width
+type = double
+(@value{GDBP}) p width
+$4 = 13
+(@value{GDBP}) set width=47
+Invalid syntax in expression.
+@end smallexample
+
+@noindent
+The invalid expression, of course, is @samp{=47}. In
+order to actually set the program's variable @code{width}, use
+
+@smallexample
+(@value{GDBP}) set var width=47
+@end smallexample
+
+Because the @code{set} command has many subcommands that can conflict
+with the names of program variables, it is a good idea to use the
+@code{set variable} command instead of just @code{set}. For example, if
+your program has a variable @code{g}, you run into problems if you try
+to set a new value with just @samp{set g=4}, because @value{GDBN} has
+the command @code{set gnutarget}, abbreviated @code{set g}:
+
+@smallexample
+@group
+(@value{GDBP}) whatis g
+type = double
+(@value{GDBP}) p g
+$1 = 1
+(@value{GDBP}) set g=4
+(@value{GDBP}) p g
+$2 = 1
+(@value{GDBP}) r
+The program being debugged has been started already.
+Start it from the beginning? (y or n) y
+Starting program: /home/smith/cc_progs/a.out
+"/home/smith/cc_progs/a.out": can't open to read symbols:
+ Invalid bfd target.
+(@value{GDBP}) show g
+The current BFD target is "=4".
+@end group
+@end smallexample
+
+@noindent
+The program variable @code{g} did not change, and you silently set the
+@code{gnutarget} to an invalid value. In order to set the variable
+@code{g}, use
+
+@smallexample
+(@value{GDBP}) set var g=4
+@end smallexample
+
+@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
+
+@smallexample
+set @{int@}0x83040 = 4
+@end smallexample
+
+@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}. It is common practice to use the @code{tbreak} command
+in conjunction with @code{jump}. @xref{Set Breaks, ,Setting
+breakpoints}.
+
+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
+
+@c Doesn't work on HP-UX; have to set $pcoqh and $pcoqt.
+On many systems, 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,
+
+@smallexample
+set $pc = 0x485
+@end smallexample
+
+@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.
+
+@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.
+
+
+@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.
+
+@node Patching
+@section Patching programs
+
+@cindex patching binaries
+@cindex writing into executables
+@cindex writing into corefiles
+
+By default, @value{GDBN} opens the file containing your program's
+executable code (or the corefile) 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 and
+core 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} or @code{core-file} command) after changing @code{set
+write}, for your new setting to take effect.
+
+@item show write
+@kindex show write
+Display whether executable files and core files 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. To debug a core dump of a previous run, you must also tell
+@value{GDBN} the name of the core dump file.
+
+@menu
+* Files:: Commands to specify files
+* Separate Debug Files:: Debugging information in separate files
+* Symbol Errors:: Errors reading symbol files
+@end menu
+
+@node Files
+@section Commands to specify files
+
+@cindex symbol table
+@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}}).
+
+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 named
+@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.
+
+For most kinds of object files, with the exception of old SVR3 systems
+using COFF, 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. Note that ``stabs-in-COFF''
+still does the two-stage strategy, since the debug info is actually
+in stabs format.
+
+@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.
+
+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}).
+
+@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{]}
+@itemx add-symbol-file @var{filename} @r{-s}@var{section} @var{address} @dots{}
+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 additionally specify an arbitrary number
+of @samp{@r{-s}@var{section} @var{address}} pairs, to give an explicit
+section name and base address for that section. You can specify any
+@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 without any arguments.
+
+@cindex relocatable object files, reading symbols from
+@cindex object files, relocatable, reading symbols from
+@cindex reading symbols from relocatable object files
+@cindex symbols, reading from relocatable object files
+@cindex @file{.o} files, reading symbols from
+Although @var{filename} is typically a shared library file, an
+executable file, or some other object file which has been fully
+relocated for loading into a process, you can also load symbolic
+information from relocatable @file{.o} files, as long as:
+
+@itemize @bullet
+@item
+the file's symbolic information refers only to linker symbols defined in
+that file, not to symbols defined by other object files,
+@item
+every section the file's symbolic information refers to has actually
+been loaded into the inferior, as it appears in the file, and
+@item
+you can determine the address at which every section was loaded, and
+provide these to the @code{add-symbol-file} command.
+@end itemize
+
+@noindent
+Some embedded operating systems, like Sun Chorus and VxWorks, can load
+relocatable files into an already running program; such systems
+typically make the requirements above easy to meet. However, it's
+important to recognize that many native systems use complex link
+procedures (@code{.linkonce} section factoring and C@t{++} constructor table
+assembly, for example) that make the requirements difficult to meet. In
+general, one cannot assume that using @code{add-symbol-file} to read a
+relocatable object file's symbolic information will have the same effect
+as linking the relocatable object file into the program in the normal
+way.
+
+@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.
+
+@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 @code{info files} command, described below, 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 names of the executable and core dump files 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.
+
+@kindex maint info sections
+@item maint info sections
+Another command that can give you extra information about program sections
+is @code{maint info sections}. In addition to the section information
+displayed by @code{info files}, this command displays the flags and file
+offset of each section in the executable and core dump files. In addition,
+@code{maint info sections} provides the following command options (which
+may be arbitrarily combined):
+
+@table @code
+@item ALLOBJ
+Display sections for all loaded object files, including shared libraries.
+@item @var{sections}
+Display info only for named @var{sections}.
+@item @var{section-flags}
+Display info only for sections for which @var{section-flags} are true.
+The section flags that @value{GDBN} currently knows about are:
+@table @code
+@item ALLOC
+Section will have space allocated in the process when loaded.
+Set for all sections except those containing debug information.
+@item LOAD
+Section will be loaded from the file into the child process memory.
+Set for pre-initialized code and data, clear for @code{.bss} sections.
+@item RELOC
+Section needs to be relocated before loading.
+@item READONLY
+Section cannot be modified by the child process.
+@item CODE
+Section contains executable code only.
+@item DATA
+Section contains data only (no executable code).
+@item ROM
+Section will reside in ROM.
+@item CONSTRUCTOR
+Section contains data for constructor/destructor lists.
+@item HAS_CONTENTS
+Section is not empty.
+@item NEVER_LOAD
+An instruction to the linker to not output the section.
+@item COFF_SHARED_LIBRARY
+A notification to the linker that the section contains
+COFF shared library information.
+@item IS_COMMON
+Section contains common symbols.
+@end table
+@end table
+@kindex set trust-readonly-sections
+@item set trust-readonly-sections on
+Tell @value{GDBN} that readonly sections in your object file
+really are read-only (i.e.@: that their contents will not change).
+In that case, @value{GDBN} can fetch values from these sections
+out of the object file, rather than from the target program.
+For some targets (notably embedded ones), this can be a significant
+enhancement to debugging performance.
+
+The default is off.
+
+@item set trust-readonly-sections off
+Tell @value{GDBN} not to trust readonly sections. This means that
+the contents of the section might change while the program is running,
+and must therefore be fetched from the target when needed.
+@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.
+
+@cindex shared libraries
+@value{GDBN} supports HP-UX, 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).
+
+On HP-UX, if the program loads a library explicitly, @value{GDBN}
+automatically loads the symbols at the time of the @code{shl_load} call.
+
+@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
+
+There are times, however, when you may wish to not automatically load
+symbol definitions from shared libraries, such as when they are
+particularly large or there are many of them.
+
+To control the automatic loading of shared library symbols, use the
+commands:
+
+@table @code
+@kindex set auto-solib-add
+@item set auto-solib-add @var{mode}
+If @var{mode} is @code{on}, symbols from all shared object libraries
+will be loaded automatically when the inferior begins execution, you
+attach to an independently started inferior, or when the dynamic linker
+informs @value{GDBN} that a new library has been loaded. If @var{mode}
+is @code{off}, symbols must be loaded manually, using the
+@code{sharedlibrary} command. The default value is @code{on}.
+
+@kindex show auto-solib-add
+@item show auto-solib-add
+Display the current autoloading mode.
+@end table
+
+To explicitly load shared library symbols, use the @code{sharedlibrary}
+command:
+
+@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
+
+On some systems, such as HP-UX systems, @value{GDBN} supports
+autoloading shared library symbols until a limiting threshold size is
+reached. This provides the benefit of allowing autoloading to remain on
+by default, but avoids autoloading excessively large shared libraries,
+up to a threshold that is initially set, but which you can modify if you
+wish.
+
+Beyond that threshold, symbols from shared libraries must be explicitly
+loaded. To load these symbols, use the command @code{sharedlibrary
+@var{filename}}. The base address of the shared library is determined
+automatically by @value{GDBN} and need not be specified.
+
+To display or set the threshold, use the commands:
+
+@table @code
+@kindex set auto-solib-limit
+@item set auto-solib-limit @var{threshold}
+Set the autoloading size threshold, in an integral number of megabytes.
+If @var{threshold} is nonzero and shared library autoloading is enabled,
+symbols from all shared object libraries will be loaded until the total
+size of the loaded shared library symbols exceeds this threshold.
+Otherwise, symbols must be loaded manually, using the
+@code{sharedlibrary} command. The default threshold is 100 (i.e.@: 100
+Mb).
+
+@kindex show auto-solib-limit
+@item show auto-solib-limit
+Display the current autoloading size threshold, in megabytes.
+@end table
+
+Shared libraries are also supported in many cross or remote debugging
+configurations. A copy of the target's libraries need to be present on the
+host system; they need to be the same as the target libraries, although the
+copies on the target can be stripped as long as the copies on the host are
+not.
+
+You need to tell @value{GDBN} where the target libraries are, so that it can
+load the correct copies---otherwise, it may try to load the host's libraries.
+@value{GDBN} has two variables to specify the search directories for target
+libraries.
+
+@table @code
+@kindex set solib-absolute-prefix
+@item set solib-absolute-prefix @var{path}
+If this variable is set, @var{path} will be used as a prefix for any
+absolute shared library paths; many runtime loaders store the absolute
+paths to the shared library in the target program's memory. If you use
+@samp{solib-absolute-prefix} to find shared libraries, they need to be laid
+out in the same way that they are on the target, with e.g.@: a
+@file{/usr/lib} hierarchy under @var{path}.
+
+You can set the default value of @samp{solib-absolute-prefix} by using the
+configure-time @samp{--with-sysroot} option.
+
+@kindex show solib-absolute-prefix
+@item show solib-absolute-prefix
+Display the current shared library prefix.
+
+@kindex set solib-search-path
+@item set solib-search-path @var{path}
+If this variable is set, @var{path} is a colon-separated list of directories
+to search for shared libraries. @samp{solib-search-path} is used after
+@samp{solib-absolute-prefix} fails to locate the library, or if the path to
+the library is relative instead of absolute. If you want to use
+@samp{solib-search-path} instead of @samp{solib-absolute-prefix}, be sure to
+set @samp{solib-absolute-prefix} to a nonexistant directory to prevent
+@value{GDBN} from finding your host's libraries.
+
+@kindex show solib-search-path
+@item show solib-search-path
+Display the current shared library search path.
+@end table
+
+
+@node Separate Debug Files
+@section Debugging Information in Separate Files
+@cindex separate debugging information files
+@cindex debugging information in separate files
+@cindex @file{.debug} subdirectories
+@cindex debugging information directory, global
+@cindex global debugging information directory
+
+@value{GDBN} allows you to put a program's debugging information in a
+file separate from the executable itself, in a way that allows
+@value{GDBN} to find and load the debugging information automatically.
+Since debugging information can be very large --- sometimes larger
+than the executable code itself --- some systems distribute debugging
+information for their executables in separate files, which users can
+install only when they need to debug a problem.
+
+If an executable's debugging information has been extracted to a
+separate file, the executable should contain a @dfn{debug link} giving
+the name of the debugging information file (with no directory
+components), and a checksum of its contents. (The exact form of a
+debug link is described below.) If the full name of the directory
+containing the executable is @var{execdir}, and the executable has a
+debug link that specifies the name @var{debugfile}, then @value{GDBN}
+will automatically search for the debugging information file in three
+places:
+
+@itemize @bullet
+@item
+the directory containing the executable file (that is, it will look
+for a file named @file{@var{execdir}/@var{debugfile}},
+@item
+a subdirectory of that directory named @file{.debug} (that is, the
+file @file{@var{execdir}/.debug/@var{debugfile}}, and
+@item
+a subdirectory of the global debug file directory that includes the
+executable's full path, and the name from the link (that is, the file
+@file{@var{globaldebugdir}/@var{execdir}/@var{debugfile}}, where
+@var{globaldebugdir} is the global debug file directory, and
+@var{execdir} has been turned into a relative path).
+@end itemize
+@noindent
+@value{GDBN} checks under each of these names for a debugging
+information file whose checksum matches that given in the link, and
+reads the debugging information from the first one it finds.
+
+So, for example, if you ask @value{GDBN} to debug @file{/usr/bin/ls},
+which has a link containing the name @file{ls.debug}, and the global
+debug directory is @file{/usr/lib/debug}, then @value{GDBN} will look
+for debug information in @file{/usr/bin/ls.debug},
+@file{/usr/bin/.debug/ls.debug}, and
+@file{/usr/lib/debug/usr/bin/ls.debug}.
+
+You can set the global debugging info directory's name, and view the
+name @value{GDBN} is currently using.
+
+@table @code
+
+@kindex set debug-file-directory
+@item set debug-file-directory @var{directory}
+Set the directory which @value{GDBN} searches for separate debugging
+information files to @var{directory}.
+
+@kindex show debug-file-directory
+@item show debug-file-directory
+Show the directory @value{GDBN} searches for separate debugging
+information files.
+
+@end table
+
+@cindex @code{.gnu_debuglink} sections
+@cindex debug links
+A debug link is a special section of the executable file named
+@code{.gnu_debuglink}. The section must contain:
+
+@itemize
+@item
+A filename, with any leading directory components removed, followed by
+a zero byte,
+@item
+zero to three bytes of padding, as needed to reach the next four-byte
+boundary within the section, and
+@item
+a four-byte CRC checksum, stored in the same endianness used for the
+executable file itself. The checksum is computed on the debugging
+information file's full contents by the function given below, passing
+zero as the @var{crc} argument.
+@end itemize
+
+Any executable file format can carry a debug link, as long as it can
+contain a section named @code{.gnu_debuglink} with the contents
+described above.
+
+The debugging information file itself should be an ordinary
+executable, containing a full set of linker symbols, sections, and
+debugging information. The sections of the debugging information file
+should have the same names, addresses and sizes as the original file,
+but they need not contain any data --- much like a @code{.bss} section
+in an ordinary executable.
+
+As of December 2002, there is no standard GNU utility to produce
+separated executable / debugging information file pairs. Ulrich
+Drepper's @file{elfutils} package, starting with version 0.53,
+contains a version of the @code{strip} command such that the command
+@kbd{strip foo -f foo.debug} removes the debugging information from
+the executable file @file{foo}, places it in the file
+@file{foo.debug}, and leaves behind a debug link in @file{foo}.
+
+Since there are many different ways to compute CRC's (different
+polynomials, reversals, byte ordering, etc.), the simplest way to
+describe the CRC used in @code{.gnu_debuglink} sections is to give the
+complete code for a function that computes it:
+
+@kindex @code{gnu_debuglink_crc32}
+@smallexample
+unsigned long
+gnu_debuglink_crc32 (unsigned long crc,
+ unsigned char *buf, size_t len)
+@{
+ static const unsigned long crc32_table[256] =
+ @{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ @};
+ unsigned char *end;
+
+ crc = ~crc & 0xffffffff;
+ for (end = buf + len; buf < end; ++buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc & 0xffffffff;
+@}
+@end smallexample
+
+
+@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
+uncomprehended 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 a struct or class.
+
+@item const/volatile indicator missing (ok if using g++ v1.x), got@dots{}
+The symbol information for a C@t{++} member function is missing some
+information that recent versions of the compiler should have output for
+it.
+
+@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.
+
+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 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
+* Byte Order:: Choosing target byte order
+* Remote:: Remote debugging
+* KOD:: Kernel Object Display
+
+@end menu
+
+@node Active Targets
+@section Active targets
+
+@cindex stacking targets
+@cindex active targets
+@cindex multiple targets
+
+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.)
+
+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 active core file or executable file target are obscured while the
+process target is active.
+
+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}).
+
+@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 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.
+
+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.
+
+@quotation
+@emph{Warning:} To specify a file format with @code{set gnutarget},
+you must know the actual BFD name.
+@end quotation
+
+@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 @samp{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}}.
+
+@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}}.
+
+@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}
+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.
+
+@kindex target sim
+@item target sim
+Builtin CPU simulator. @value{GDBN} includes simulators for most architectures.
+In general,
+@smallexample
+ target sim
+ load
+ run
+@end smallexample
+@noindent
+works; however, you cannot assume that a specific memory map, device
+drivers, or even basic I/O is available, although some simulators do
+provide these. For info about any processor-specific simulator details,
+see the appropriate section in @ref{Embedded Processors, ,Embedded
+Processors}.
+
+@end table
+
+Some configurations may include these targets as well:
+
+@table @code
+
+@kindex target nrom
+@item target nrom @var{dev}
+NetROM ROM emulator. This target only supports downloading.
+
+@end table
+
+Different targets are available on different configurations of @value{GDBN};
+your configuration may have more or fewer targets.
+
+Many remote targets require you to download the executable's code
+once you've successfully established a connection.
+
+@table @code
+
+@kindex load @var{filename}
+@item load @var{filename}
+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{}}''
+
+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.
+
+@code{load} does not repeat if you press @key{RET} again after using it.
+@end table
+
+@node Byte Order
+@section Choosing target byte order
+
+@cindex choosing target byte order
+@cindex target byte order
+
+Some types of processors, such as the MIPS, PowerPC, and Renesas SH,
+offer the ability to run either big-endian or little-endian byte
+orders. Usually the executable or symbol will include a bit to
+designate the endian-ness, and you will not need to worry about
+which to use. However, you may still find it useful to adjust
+@value{GDBN}'s idea of processor endian-ness manually.
+
+@table @code
+@kindex set endian big
+@item set endian big
+Instruct @value{GDBN} to assume the target is big-endian.
+
+@kindex set endian little
+@item set endian little
+Instruct @value{GDBN} to assume the target is little-endian.
+
+@kindex set endian auto
+@item set endian auto
+Instruct @value{GDBN} to use the byte order associated with the
+executable.
+
+@item show endian
+Display @value{GDBN}'s current idea of the target byte order.
+
+@end table
+
+Note that these commands merely adjust interpretation of symbolic
+data on the host, and that they have absolutely no effect on the
+target system.
+
+@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.
+
+@node KOD
+@section Kernel Object Display
+@cindex kernel object display
+@cindex KOD
+
+Some targets support kernel object display. Using this facility,
+@value{GDBN} communicates specially with the underlying operating system
+and can display information about operating system-level objects such as
+mutexes and other synchronization objects. Exactly which objects can be
+displayed is determined on a per-OS basis.
+
+@kindex set os
+Use the @code{set os} command to set the operating system. This tells
+@value{GDBN} which kernel object display module to initialize:
+
+@smallexample
+(@value{GDBP}) set os cisco
+@end smallexample
+
+@kindex show os
+The associated command @code{show os} displays the operating system
+set with the @code{set os} command; if no operating system has been
+set, @code{show os} will display an empty string @samp{""}.
+
+If @code{set os} succeeds, @value{GDBN} will display some information
+about the operating system, and will create a new @code{info} command
+which can be used to query the target. The @code{info} command is named
+after the operating system:
+
+@kindex info cisco
+@smallexample
+(@value{GDBP}) info cisco
+List of Cisco Kernel Objects
+Object Description
+any Any and all objects
+@end smallexample
+
+Further subcommands can be used to query about particular objects known
+by the kernel.
+
+There is currently no way to determine whether a given operating
+system is supported other than to try setting it with @kbd{set os
+@var{name}}, where @var{name} is the name of the operating system you
+want to try.
+
+
+@node Remote Debugging
+@chapter Debugging remote programs
+
+@menu
+* Connecting:: Connecting to a remote target
+* Server:: Using the gdbserver program
+* NetWare:: Using the gdbserve.nlm program
+* Remote configuration:: Remote configuration
+* remote stub:: Implementing a remote stub
+@end menu
+
+@node Connecting
+@section Connecting to a remote target
+
+On the @value{GDBN} host machine, you will need an unstripped copy of
+your program, since @value{GDBN} needs symobl and debugging information.
+Start up @value{GDBN} as usual, using the name of the local copy of your
+program as the first argument.
+
+@cindex serial line, @code{target remote}
+If you're using a serial line, you may want to give @value{GDBN} the
+@w{@samp{--baud}} option, or use the @code{set remotebaud} command
+before the @code{target} command.
+
+After that, use @code{target remote} to establish communications with
+the target machine. Its argument specifies how to communicate---either
+via a devicename attached to a direct serial line, or a TCP or UDP port
+(possibly 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}:
+
+@smallexample
+target remote /dev/ttyb
+@end smallexample
+
+@cindex TCP port, @code{target remote}
+To use a TCP connection, use an argument of the form
+@code{@var{host}:@var{port}} or @code{tcp:@var{host}:@var{port}}.
+For example, to connect to port 2828 on a
+terminal server named @code{manyfarms}:
+
+@smallexample
+target remote manyfarms:2828
+@end smallexample
+
+If your remote target is actually running on the same machine as
+your debugger session (e.g.@: a simulator of your target running on
+the same host), you can omit the hostname. For example, to connect
+to port 1234 on your local machine:
+
+@smallexample
+target remote :1234
+@end smallexample
+@noindent
+
+Note that the colon is still required here.
+
+@cindex UDP port, @code{target remote}
+To use a UDP connection, use an argument of the form
+@code{udp:@var{host}:@var{port}}. For example, to connect to UDP port 2828
+on a terminal server named @code{manyfarms}:
+
+@smallexample
+target remote udp:manyfarms:2828
+@end smallexample
+
+When using a UDP connection for remote debugging, you should keep in mind
+that the `U' stands for ``Unreliable''. UDP can silently drop packets on
+busy or unreliable networks, which will cause havoc with your debugging
+session.
+
+Now you can use all the usual commands to examine and change data and to
+step and continue the remote program.
+
+@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:
+
+@smallexample
+Interrupted while waiting for the program.
+Give up (and stop debugging it)? (y or n)
+@end smallexample
+
+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.
+
+@table @code
+@kindex detach (remote)
+@item detach
+When you have finished debugging the remote program, you can use the
+@code{detach} command to release it from @value{GDBN} control.
+Detaching from the target normally resumes its execution, but the results
+will depend on your particular remote stub. After the @code{detach}
+command, @value{GDBN} is free to connect to another target.
+
+@kindex disconnect
+@item disconnect
+The @code{disconnect} command behaves like @code{detach}, except that
+the target is generally not resumed. It will wait for @value{GDBN}
+(this instance or another one) to connect and continue debugging. After
+the @code{disconnect} command, @value{GDBN} is again free to connect to
+another target.
+@end table
+
+@node Server
+@section 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 usual
+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.
+
+On some targets, @code{gdbserver} can also attach to running programs.
+This is accomplished via the @code{--attach} argument. The syntax is:
+
+@smallexample
+target> gdbserver @var{comm} --attach @var{pid}
+@end smallexample
+
+@var{pid} is the process ID of a currently running process. It isn't necessary
+to point @code{gdbserver} at a binary for the running process.
+
+@pindex pidof
+@cindex attach to a program by name
+You can debug processes by name instead of process ID if your target has the
+@code{pidof} utility:
+
+@smallexample
+target> gdbserver @var{comm} --attach `pidof @var{PROGRAM}`
+@end smallexample
+
+In case more than one copy of @var{PROGRAM} is running, or @var{PROGRAM}
+has multiple threads, most versions of @code{pidof} support the
+@code{-s} option to only return the first process ID.
+
+@item On the host machine,
+connect to your target (@pxref{Connecting,,Connecting to a remote 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}. You don't need to use the @code{load}
+command in @value{GDBN} when using gdbserver, since the program is
+already on the target.
+
+@end table
+
+@node NetWare
+@section 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@dmn{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@dmn{bps} connection:
+
+@smallexample
+load gdbserve BOARD=1 PORT=2 BAUD=19200 emacs foo.txt
+@end smallexample
+
+@item
+On the @value{GDBN} host machine, connect to your target (@pxref{Connecting,,
+Connecting to a remote target}).
+
+@end table
+
+@node Remote configuration
+@section Remote configuration
+
+The following configuration options are available when debugging remote
+programs:
+
+@table @code
+@kindex set remote hardware-watchpoint-limit
+@kindex set remote hardware-breakpoint-limit
+@anchor{set remote hardware-watchpoint-limit}
+@anchor{set remote hardware-breakpoint-limit}
+@item set remote hardware-watchpoint-limit @var{limit}
+@itemx set remote hardware-breakpoint-limit @var{limit}
+Restrict @value{GDBN} to using @var{limit} remote hardware breakpoint or
+watchpoints. A limit of -1, the default, is treated as unlimited.
+@end table
+
+@node remote stub
+@section Implementing a remote stub
+
+@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.)
+
+@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
+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}.
+
+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 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 i386-stub.c
+@cindex @file{i386-stub.c}
+@cindex Intel
+@cindex i386
+For Intel 386 and compatible architectures.
+
+@item m68k-stub.c
+@cindex @file{m68k-stub.c}
+@cindex Motorola 680x0
+@cindex m680x0
+For Motorola 680x0 architectures.
+
+@item sh-stub.c
+@cindex @file{sh-stub.c}
+@cindex Renesas
+@cindex SH
+For Renesas SH architectures.
+
+@item sparc-stub.c
+@cindex @file{sparc-stub.c}
+@cindex Sparc
+For @sc{sparc} architectures.
+
+@item sparcl-stub.c
+@cindex @file{sparcl-stub.c}
+@cindex Fujitsu
+@cindex SparcLite
+For Fujitsu @sc{sparclite} 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
+@end menu
+
+@node Stub Contents
+@subsection 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
+@subsection 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 interrupts themselves without
+help from @code{exceptionHandler}.
+
+@item void flush_i_cache()
+@kindex flush_i_cache
+On @sc{sparc} and @sc{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{@value{GCC}} generates as inline code.
+
+
+@node Debug Session
+@subsection 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 defined 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:
+
+@smallexample
+set_debug_traps();
+breakpoint();
+@end smallexample
+
+@item
+For the 680x0 stub only, you need to provide a variable called
+@code{exceptionHook}. Normally you just use:
+
+@smallexample
+void (*exceptionHook)() = 0;
+@end smallexample
+
+@noindent
+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
+Start @value{GDBN} on the host, and connect to the target
+(@pxref{Connecting,,Connecting to a remote target}).
+
+@end enumerate
+
+@node Configurations
+@chapter Configuration-Specific Information
+
+While nearly all @value{GDBN} commands are available for all native and
+cross versions of the debugger, there are some exceptions. This chapter
+describes things that are only available in certain configurations.
+
+There are three major categories of configurations: native
+configurations, where the host and target are the same, embedded
+operating system configurations, which are usually the same for several
+different processor architectures, and bare embedded processors, which
+are quite different from each other.
+
+@menu
+* Native::
+* Embedded OS::
+* Embedded Processors::
+* Architectures::
+@end menu
+
+@node Native
+@section Native
+
+This section describes details specific to particular native
+configurations.
+
+@menu
+* HP-UX:: HP-UX
+* SVR4 Process Information:: SVR4 process information
+* DJGPP Native:: Features specific to the DJGPP port
+* Cygwin Native:: Features specific to the Cygwin port
+@end menu
+
+@node HP-UX
+@subsection HP-UX
+
+On HP-UX systems, if you refer to a function or variable name that
+begins with a dollar sign, @value{GDBN} searches for a user or system
+name first, before it searches for a convenience variable.
+
+@node SVR4 Process Information
+@subsection SVR4 process information
+
+@kindex /proc
+@cindex process image
+
+Many versions of SVR4 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 include the
+@code{procfs} code. This includes OSF/1 (Digital Unix), Solaris, Irix,
+and Unixware, but not HP-UX or @sc{gnu}/Linux, for example.
+
+@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.
+@ignore
+@comment These sub-options of 'info proc' were not included when
+@comment procfs.c was re-written. Keep their descriptions around
+@comment against the day when someone finds the time to put them back in.
+@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 ignore
+@end table
+
+@node DJGPP Native
+@subsection Features for Debugging @sc{djgpp} Programs
+@cindex @sc{djgpp} debugging
+@cindex native @sc{djgpp} debugging
+@cindex MS-DOS-specific commands
+
+@sc{djgpp} is the port of @sc{gnu} development tools to MS-DOS and
+MS-Windows. @sc{djgpp} programs are 32-bit protected-mode programs
+that use the @dfn{DPMI} (DOS Protected-Mode Interface) API to run on
+top of real-mode DOS systems and their emulations.
+
+@value{GDBN} supports native debugging of @sc{djgpp} programs, and
+defines a few commands specific to the @sc{djgpp} port. This
+subsection describes those commands.
+
+@table @code
+@kindex info dos
+@item info dos
+This is a prefix of @sc{djgpp}-specific commands which print
+information about the target system and important OS structures.
+
+@kindex sysinfo
+@cindex MS-DOS system info
+@cindex free memory information (MS-DOS)
+@item info dos sysinfo
+This command displays assorted information about the underlying
+platform: the CPU type and features, the OS version and flavor, the
+DPMI version, and the available conventional and DPMI memory.
+
+@cindex GDT
+@cindex LDT
+@cindex IDT
+@cindex segment descriptor tables
+@cindex descriptor tables display
+@item info dos gdt
+@itemx info dos ldt
+@itemx info dos idt
+These 3 commands display entries from, respectively, Global, Local,
+and Interrupt Descriptor Tables (GDT, LDT, and IDT). The descriptor
+tables are data structures which store a descriptor for each segment
+that is currently in use. The segment's selector is an index into a
+descriptor table; the table entry for that index holds the
+descriptor's base address and limit, and its attributes and access
+rights.
+
+A typical @sc{djgpp} program uses 3 segments: a code segment, a data
+segment (used for both data and the stack), and a DOS segment (which
+allows access to DOS/BIOS data structures and absolute addresses in
+conventional memory). However, the DPMI host will usually define
+additional segments in order to support the DPMI environment.
+
+@cindex garbled pointers
+These commands allow to display entries from the descriptor tables.
+Without an argument, all entries from the specified table are
+displayed. An argument, which should be an integer expression, means
+display a single entry whose index is given by the argument. For
+example, here's a convenient way to display information about the
+debugged program's data segment:
+
+@smallexample
+@exdent @code{(@value{GDBP}) info dos ldt $ds}
+@exdent @code{0x13f: base=0x11970000 limit=0x0009ffff 32-Bit Data (Read/Write, Exp-up)}
+@end smallexample
+
+@noindent
+This comes in handy when you want to see whether a pointer is outside
+the data segment's limit (i.e.@: @dfn{garbled}).
+
+@cindex page tables display (MS-DOS)
+@item info dos pde
+@itemx info dos pte
+These two commands display entries from, respectively, the Page
+Directory and the Page Tables. Page Directories and Page Tables are
+data structures which control how virtual memory addresses are mapped
+into physical addresses. A Page Table includes an entry for every
+page of memory that is mapped into the program's address space; there
+may be several Page Tables, each one holding up to 4096 entries. A
+Page Directory has up to 4096 entries, one each for every Page Table
+that is currently in use.
+
+Without an argument, @kbd{info dos pde} displays the entire Page
+Directory, and @kbd{info dos pte} displays all the entries in all of
+the Page Tables. An argument, an integer expression, given to the
+@kbd{info dos pde} command means display only that entry from the Page
+Directory table. An argument given to the @kbd{info dos pte} command
+means display entries from a single Page Table, the one pointed to by
+the specified entry in the Page Directory.
+
+@cindex direct memory access (DMA) on MS-DOS
+These commands are useful when your program uses @dfn{DMA} (Direct
+Memory Access), which needs physical addresses to program the DMA
+controller.
+
+These commands are supported only with some DPMI servers.
+
+@cindex physical address from linear address
+@item info dos address-pte @var{addr}
+This command displays the Page Table entry for a specified linear
+address. The argument linear address @var{addr} should already have the
+appropriate segment's base address added to it, because this command
+accepts addresses which may belong to @emph{any} segment. For
+example, here's how to display the Page Table entry for the page where
+the variable @code{i} is stored:
+
+@smallexample
+@exdent @code{(@value{GDBP}) info dos address-pte __djgpp_base_address + (char *)&i}
+@exdent @code{Page Table entry for address 0x11a00d30:}
+@exdent @code{Base=0x02698000 Dirty Acc. Not-Cached Write-Back Usr Read-Write +0xd30}
+@end smallexample
+
+@noindent
+This says that @code{i} is stored at offset @code{0xd30} from the page
+whose physical base address is @code{0x02698000}, and prints all the
+attributes of that page.
+
+Note that you must cast the addresses of variables to a @code{char *},
+since otherwise the value of @code{__djgpp_base_address}, the base
+address of all variables and functions in a @sc{djgpp} program, will
+be added using the rules of C pointer arithmetics: if @code{i} is
+declared an @code{int}, @value{GDBN} will add 4 times the value of
+@code{__djgpp_base_address} to the address of @code{i}.
+
+Here's another example, it displays the Page Table entry for the
+transfer buffer:
+
+@smallexample
+@exdent @code{(@value{GDBP}) info dos address-pte *((unsigned *)&_go32_info_block + 3)}
+@exdent @code{Page Table entry for address 0x29110:}
+@exdent @code{Base=0x00029000 Dirty Acc. Not-Cached Write-Back Usr Read-Write +0x110}
+@end smallexample
+
+@noindent
+(The @code{+ 3} offset is because the transfer buffer's address is the
+3rd member of the @code{_go32_info_block} structure.) The output of
+this command clearly shows that addresses in conventional memory are
+mapped 1:1, i.e.@: the physical and linear addresses are identical.
+
+This command is supported only with some DPMI servers.
+@end table
+
+@node Cygwin Native
+@subsection Features for Debugging MS Windows PE executables
+@cindex MS Windows debugging
+@cindex native Cygwin debugging
+@cindex Cygwin-specific commands
+
+@value{GDBN} supports native debugging of MS Windows programs, including
+DLLs with and without symbolic debugging information. There are various
+additional Cygwin-specific commands, described in this subsection. The
+subsubsection @pxref{Non-debug DLL symbols} describes working with DLLs
+that have no debugging symbols.
+
+
+@table @code
+@kindex info w32
+@item info w32
+This is a prefix of MS Windows specific commands which print
+information about the target system and important OS structures.
+
+@item info w32 selector
+This command displays information returned by
+the Win32 API @code{GetThreadSelectorEntry} function.
+It takes an optional argument that is evaluated to
+a long value to give the information about this given selector.
+Without argument, this command displays information
+about the the six segment registers.
+
+@kindex info dll
+@item info dll
+This is a Cygwin specific alias of info shared.
+
+@kindex dll-symbols
+@item dll-symbols
+This command loads symbols from a dll similarly to
+add-sym command but without the need to specify a base address.
+
+@kindex set new-console
+@item set new-console @var{mode}
+If @var{mode} is @code{on} the debuggee will
+be started in a new console on next start.
+If @var{mode} is @code{off}i, the debuggee will
+be started in the same console as the debugger.
+
+@kindex show new-console
+@item show new-console
+Displays whether a new console is used
+when the debuggee is started.
+
+@kindex set new-group
+@item set new-group @var{mode}
+This boolean value controls whether the debuggee should
+start a new group or stay in the same group as the debugger.
+This affects the way the Windows OS handles
+Ctrl-C.
+
+@kindex show new-group
+@item show new-group
+Displays current value of new-group boolean.
+
+@kindex set debugevents
+@item set debugevents
+This boolean value adds debug output concerning events seen by the debugger.
+
+@kindex set debugexec
+@item set debugexec
+This boolean value adds debug output concerning execute events
+seen by the debugger.
+
+@kindex set debugexceptions
+@item set debugexceptions
+This boolean value adds debug ouptut concerning exception events
+seen by the debugger.
+
+@kindex set debugmemory
+@item set debugmemory
+This boolean value adds debug ouptut concerning memory events
+seen by the debugger.
+
+@kindex set shell
+@item set shell
+This boolean values specifies whether the debuggee is called
+via a shell or directly (default value is on).
+
+@kindex show shell
+@item show shell
+Displays if the debuggee will be started with a shell.
+
+@end table
+
+@menu
+* Non-debug DLL symbols:: Support for DLLs without debugging symbols
+@end menu
+
+@node Non-debug DLL symbols
+@subsubsection Support for DLLs without debugging symbols
+@cindex DLLs with no debugging symbols
+@cindex Minimal symbols and DLLs
+
+Very often on windows, some of the DLLs that your program relies on do
+not include symbolic debugging information (for example,
+@file{kernel32.dll}). When @value{GDBN} doesn't recognize any debugging
+symbols in a DLL, it relies on the minimal amount of symbolic
+information contained in the DLL's export table. This subsubsection
+describes working with such symbols, known internally to @value{GDBN} as
+``minimal symbols''.
+
+Note that before the debugged program has started execution, no DLLs
+will have been loaded. The easiest way around this problem is simply to
+start the program --- either by setting a breakpoint or letting the
+program run once to completion. It is also possible to force
+@value{GDBN} to load a particular DLL before starting the executable ---
+see the shared library information in @pxref{Files} or the
+@code{dll-symbols} command in @pxref{Cygwin Native}. Currently,
+explicitly loading symbols from a DLL with no debugging information will
+cause the symbol names to be duplicated in @value{GDBN}'s lookup table,
+which may adversely affect symbol lookup performance.
+
+@subsubsection DLL name prefixes
+
+In keeping with the naming conventions used by the Microsoft debugging
+tools, DLL export symbols are made available with a prefix based on the
+DLL name, for instance @code{KERNEL32!CreateFileA}. The plain name is
+also entered into the symbol table, so @code{CreateFileA} is often
+sufficient. In some cases there will be name clashes within a program
+(particularly if the executable itself includes full debugging symbols)
+necessitating the use of the fully qualified name when referring to the
+contents of the DLL. Use single-quotes around the name to avoid the
+exclamation mark (``!'') being interpreted as a language operator.
+
+Note that the internal name of the DLL may be all upper-case, even
+though the file name of the DLL is lower-case, or vice-versa. Since
+symbols within @value{GDBN} are @emph{case-sensitive} this may cause
+some confusion. If in doubt, try the @code{info functions} and
+@code{info variables} commands or even @code{maint print msymbols} (see
+@pxref{Symbols}). Here's an example:
+
+@smallexample
+(gdb) info function CreateFileA
+All functions matching regular expression "CreateFileA":
+
+Non-debugging symbols:
+0x77e885f4 CreateFileA
+0x77e885f4 KERNEL32!CreateFileA
+@end smallexample
+
+@smallexample
+(gdb) info function !
+All functions matching regular expression "!":
+
+Non-debugging symbols:
+0x6100114c cygwin1!__assert
+0x61004034 cygwin1!_dll_crt0@@0
+0x61004240 cygwin1!dll_crt0(per_process *)
+[etc...]
+@end smallexample
+
+@subsubsection Working with minimal symbols
+
+Symbols extracted from a DLL's export table do not contain very much
+type information. All that @value{GDBN} can do is guess whether a symbol
+refers to a function or variable depending on the linker section that
+contains the symbol. Also note that the actual contents of the memory
+contained in a DLL are not available unless the program is running. This
+means that you cannot examine the contents of a variable or disassemble
+a function within a DLL without a running program.
+
+Variables are generally treated as pointers and dereferenced
+automatically. For this reason, it is often necessary to prefix a
+variable name with the address-of operator (``&'') and provide explicit
+type information in the command. Here's an example of the type of
+problem:
+
+@smallexample
+(gdb) print 'cygwin1!__argv'
+$1 = 268572168
+@end smallexample
+
+@smallexample
+(gdb) x 'cygwin1!__argv'
+0x10021610: "\230y\""
+@end smallexample
+
+And two possible solutions:
+
+@smallexample
+(gdb) print ((char **)'cygwin1!__argv')[0]
+$2 = 0x22fd98 "/cygdrive/c/mydirectory/myprogram"
+@end smallexample
+
+@smallexample
+(gdb) x/2x &'cygwin1!__argv'
+0x610c0aa8 <cygwin1!__argv>: 0x10021608 0x00000000
+(gdb) x/x 0x10021608
+0x10021608: 0x0022fd98
+(gdb) x/s 0x0022fd98
+0x22fd98: "/cygdrive/c/mydirectory/myprogram"
+@end smallexample
+
+Setting a break point within a DLL is possible even before the program
+starts execution. However, under these circumstances, @value{GDBN} can't
+examine the initial instructions of the function in order to skip the
+function's frame set-up code. You can work around this by using ``*&''
+to set the breakpoint at a raw memory address:
+
+@smallexample
+(gdb) break *&'python22!PyOS_Readline'
+Breakpoint 1 at 0x1e04eff0
+@end smallexample
+
+The author of these extensions is not entirely convinced that setting a
+break point within a shared DLL like @file{kernel32.dll} is completely
+safe.
+
+@node Embedded OS
+@section Embedded Operating Systems
+
+This section describes configurations involving the debugging of
+embedded operating systems that are available for several different
+architectures.
+
+@menu
+* VxWorks:: Using @value{GDBN} with VxWorks
+@end menu
+
+@value{GDBN} includes the ability to debug programs running on
+various real-time operating systems.
+
+@node VxWorks
+@subsection Using @value{GDBN} with VxWorks
+
+@cindex VxWorks
+
+@table @code
+
+@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.
+
+@end table
+
+On VxWorks, @code{load} links @var{filename} dynamically on the
+current target system as well as adding its symbols in @value{GDBN}.
+
+@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{@value{GDBP}} 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{@value{GDBP}} (or
+@code{vxgdb}, depending on your installation).
+
+@value{GDBN} comes up showing the prompt:
+
+@smallexample
+(vxgdb)
+@end smallexample
+
+@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:
+
+@smallexample
+(vxgdb) target vxworks tt
+@end smallexample
+
+@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:
+
+@smallexample
+prog.o: No such file or directory.
+@end smallexample
+
+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:
+
+@smallexample
+-> cd "@var{vxpath}/vw/demo/rdb"
+@end smallexample
+
+@noindent
+Then, in @value{GDBN}, type:
+
+@smallexample
+(vxgdb) cd @var{hostpath}/vw/demo/rdb
+(vxgdb) load prog.o
+@end smallexample
+
+@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's 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:
+
+@smallexample
+(vxgdb) attach @var{task}
+@end smallexample
+
+@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.
+
+@node Embedded Processors
+@section Embedded Processors
+
+This section goes into details specific to particular embedded
+configurations.
+
+
+@menu
+* ARM:: ARM
+* H8/300:: Renesas H8/300
+* H8/500:: Renesas H8/500
+* M32R/D:: Renesas M32R/D
+* M68K:: Motorola M68K
+* MIPS Embedded:: MIPS Embedded
+* OpenRISC 1000:: OpenRisc 1000
+* PA:: HP PA Embedded
+* PowerPC: PowerPC
+* SH:: Renesas SH
+* Sparclet:: Tsqware Sparclet
+* Sparclite:: Fujitsu Sparclite
+* ST2000:: Tandem ST2000
+* Z8000:: Zilog Z8000
+@end menu
+
+@node ARM
+@subsection ARM
+
+@table @code
+
+@kindex target rdi
+@item target rdi @var{dev}
+ARM Angel monitor, via RDI library interface to ADP protocol. You may
+use this target to communicate with both boards running the Angel
+monitor, or with the EmbeddedICE JTAG debug device.
+
+@kindex target rdp
+@item target rdp @var{dev}
+ARM Demon monitor.
+
+@end table
+
+@node H8/300
+@subsection Renesas H8/300
+
+@table @code
+
+@kindex target hms@r{, with H8/300}
+@item target hms @var{dev}
+A Renesas SH, H8/300, or H8/500 board, attached via serial line to your host.
+Use special commands @code{device} and @code{speed} to control the serial
+line and the communications speed used.
+
+@kindex target e7000@r{, with H8/300}
+@item target e7000 @var{dev}
+E7000 emulator for Renesas H8 and SH.
+
+@kindex target sh3@r{, with H8/300}
+@kindex target sh3e@r{, with H8/300}
+@item target sh3 @var{dev}
+@itemx target sh3e @var{dev}
+Renesas SH-3 and SH-3E target systems.
+
+@end table
+
+@cindex download to H8/300 or H8/500
+@cindex H8/300 or H8/500 download
+@cindex download to Renesas SH
+@cindex Renesas SH download
+When you select remote debugging to a Renesas SH, H8/300, or H8/500
+board, the @code{load} command downloads your program to the Renesas
+board and also opens it as the current executable target for
+@value{GDBN} on your host (like the @code{file} command).
+
+@value{GDBN} needs to know these things to talk to your
+Renesas SH, H8/300, or H8/500:
+
+@enumerate
+@item
+that you want to use @samp{target hms}, the remote debugging interface
+for Renesas microprocessors, or @samp{target e7000}, the in-circuit
+emulator for the Renesas SH and the Renesas 300H. (@samp{target hms} is
+the default when @value{GDBN} is configured specifically for the Renesas SH,
+H8/300, or H8/500.)
+
+@item
+what serial device connects your host to your Renesas board (the first
+serial device available on your host is the default).
+
+@item
+what speed to use over the serial device.
+@end enumerate
+
+@menu
+* Renesas Boards:: Connecting to Renesas boards.
+* Renesas ICE:: Using the E7000 In-Circuit Emulator.
+* Renesas Special:: Special @value{GDBN} commands for Renesas micros.
+@end menu
+
+@node Renesas Boards
+@subsubsection Connecting to Renesas boards
+
+@c only for Unix hosts
+@kindex device
+@cindex serial device, Renesas micros
+Use the special @code{@value{GDBN}} 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, Renesas micros
+@code{@value{GDBN}} 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 @value{GDBN} with
+the DOS @code{mode} command (for instance,
+@w{@kbd{mode com2:9600,n,8,1,p}} for a 9600@dmn{bps} connection).
+
+The @samp{device} and @samp{speed} commands are available only when you
+use a Unix host to debug your Renesas microprocessor programs. If you
+use a DOS host,
+@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.
+
+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 Renesas 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
+debugger, 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}.
+
+@smallexample
+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 smallexample
+
+@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@r{, and serial protocol}
+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{GDBN}} 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 Renesas 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
+@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 1992 Free Software Foundation, Inc...
+(@value{GDBP}) target hms
+Connected to remote H8/300 HMS system.
+(@value{GDBP}) 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.
+
+@node Renesas ICE
+@subsubsection Using the E7000 in-circuit emulator
+
+@kindex target e7000@r{, with Renesas ICE}
+You can use the E7000 in-circuit emulator to develop code for either the
+Renesas 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 Renesas Special
+@subsubsection Special @value{GDBN} commands for Renesas micros
+
+Some @value{GDBN} commands are available only for the H8/300:
+
+@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.
+
+@end table
+
+@node H8/500
+@subsection H8/500
+
+@table @code
+
+@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
+
+@node M32R/D
+@subsection Renesas M32R/D
+
+@table @code
+
+@kindex target m32r
+@item target m32r @var{dev}
+Renesas M32R/D ROM monitor.
+
+@kindex target m32rsdi
+@item target m32rsdi @var{dev}
+Renesas M32R SDI server, connected via parallel port to the board.
+
+@end table
+
+@node M68K
+@subsection M68k
+
+The Motorola m68k configuration includes ColdFire support, and
+target command for the following ROM monitors.
+
+@table @code
+
+@kindex target abug
+@item target abug @var{dev}
+ABug ROM monitor for M68K.
+
+@kindex target cpu32bug
+@item target cpu32bug @var{dev}
+CPU32BUG monitor, running on a CPU32 (M68K) board.
+
+@kindex target dbug
+@item target dbug @var{dev}
+dBUG ROM monitor for Motorola ColdFire.
+
+@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 M68K IDP board.
+
+@end table
+
+@table @code
+
+@kindex target rombug
+@item target rombug @var{dev}
+ROMBUG ROM monitor for OS/9000.
+
+@end table
+
+@node MIPS Embedded
+@subsection MIPS Embedded
+
+@cindex MIPS boards
+@value{GDBN} can use the MIPS remote debugging protocol to talk to a
+MIPS board attached to a serial line. This is available when
+you configure @value{GDBN} with @samp{--target=mips-idt-ecoff}.
+
+@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:
+
+@smallexample
+host$ @value{GDBP} @var{prog}
+@value{GDBN} is free software and @dots{}
+(@value{GDBP}) target mips /dev/ttyb
+(@value{GDBP}) load @var{prog}
+(@value{GDBP}) run
+@end smallexample
+
+@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}}.
+
+@item target pmon @var{port}
+@kindex target pmon @var{port}
+PMON ROM monitor.
+
+@item target ddb @var{port}
+@kindex target ddb @var{port}
+NEC's DDB variant of PMON for Vr4300.
+
+@item target lsi @var{port}
+@kindex target lsi @var{port}
+LSI variant of PMON.
+
+@kindex target r3900
+@item target r3900 @var{dev}
+Densan DVE-R3900 ROM monitor for Toshiba R3900 Mips.
+
+@kindex target array
+@item target array @var{dev}
+Array Tech LSI33K RAID controller board.
+
+@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 CPU 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{GDBN} init
+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@r{, MIPS protocol}
+@kindex show remotedebug@r{, MIPS protocol}
+@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
+
+@node OpenRISC 1000
+@subsection OpenRISC 1000
+@cindex OpenRISC 1000
+
+@cindex or1k boards
+See OR1k Architecture document (@uref{www.opencores.org}) for more information
+about platform and commands.
+
+@table @code
+
+@kindex target jtag
+@item target jtag jtag://@var{host}:@var{port}
+
+Connects to remote JTAG server.
+JTAG remote server can be either an or1ksim or JTAG server,
+connected via parallel port to the board.
+
+Example: @code{target jtag jtag://localhost:9999}
+
+@kindex or1ksim
+@item or1ksim @var{command}
+If connected to @code{or1ksim} OpenRISC 1000 Architectural
+Simulator, proprietary commands can be executed.
+
+@kindex info or1k spr
+@item info or1k spr
+Displays spr groups.
+
+@item info or1k spr @var{group}
+@itemx info or1k spr @var{groupno}
+Displays register names in selected group.
+
+@item info or1k spr @var{group} @var{register}
+@itemx info or1k spr @var{register}
+@itemx info or1k spr @var{groupno} @var{registerno}
+@itemx info or1k spr @var{registerno}
+Shows information about specified spr register.
+
+@kindex spr
+@item spr @var{group} @var{register} @var{value}
+@itemx spr @var{register @var{value}}
+@itemx spr @var{groupno} @var{registerno @var{value}}
+@itemx spr @var{registerno @var{value}}
+Writes @var{value} to specified spr register.
+@end table
+
+Some implementations of OpenRISC 1000 Architecture also have hardware trace.
+It is very similar to @value{GDBN} trace, except it does not interfere with normal
+program execution and is thus much faster. Hardware breakpoints/watchpoint
+triggers can be set using:
+@table @code
+@item $LEA/$LDATA
+Load effective address/data
+@item $SEA/$SDATA
+Store effective address/data
+@item $AEA/$ADATA
+Access effective address ($SEA or $LEA) or data ($SDATA/$LDATA)
+@item $FETCH
+Fetch data
+@end table
+
+When triggered, it can capture low level data, like: @code{PC}, @code{LSEA},
+@code{LDATA}, @code{SDATA}, @code{READSPR}, @code{WRITESPR}, @code{INSTR}.
+
+@code{htrace} commands:
+@cindex OpenRISC 1000 htrace
+@table @code
+@kindex hwatch
+@item hwatch @var{conditional}
+Set hardware watchpoint on combination of Load/Store Effecive Address(es)
+or Data. For example:
+
+@code{hwatch ($LEA == my_var) && ($LDATA < 50) || ($SEA == my_var) && ($SDATA >= 50)}
+
+@code{hwatch ($LEA == my_var) && ($LDATA < 50) || ($SEA == my_var) && ($SDATA >= 50)}
+
+@kindex htrace info
+@item htrace info
+Display information about current HW trace configuration.
+
+@kindex htrace trigger
+@item htrace trigger @var{conditional}
+Set starting criteria for HW trace.
+
+@kindex htrace qualifier
+@item htrace qualifier @var{conditional}
+Set acquisition qualifier for HW trace.
+
+@kindex htrace stop
+@item htrace stop @var{conditional}
+Set HW trace stopping criteria.
+
+@kindex htrace record
+@item htrace record [@var{data}]*
+Selects the data to be recorded, when qualifier is met and HW trace was
+triggered.
+
+@kindex htrace enable
+@item htrace enable
+@kindex htrace disable
+@itemx htrace disable
+Enables/disables the HW trace.
+
+@kindex htrace rewind
+@item htrace rewind [@var{filename}]
+Clears currently recorded trace data.
+
+If filename is specified, new trace file is made and any newly collected data
+will be written there.
+
+@kindex htrace print
+@item htrace print [@var{start} [@var{len}]]
+Prints trace buffer, using current record configuration.
+
+@kindex htrace mode continuous
+@item htrace mode continuous
+Set continuous trace mode.
+
+@kindex htrace mode suspend
+@item htrace mode suspend
+Set suspend trace mode.
+
+@end table
+
+@node PowerPC
+@subsection PowerPC
+
+@table @code
+
+@kindex target dink32
+@item target dink32 @var{dev}
+DINK32 ROM monitor.
+
+@kindex target ppcbug
+@item target ppcbug @var{dev}
+@kindex target ppcbug1
+@item target ppcbug1 @var{dev}
+PPCBUG ROM monitor for PowerPC.
+
+@kindex target sds
+@item target sds @var{dev}
+SDS monitor, running on a PowerPC board (such as Motorola's ADS).
+
+@end table
+
+@node PA
+@subsection HP PA Embedded
+
+@table @code
+
+@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.
+
+@end table
+
+@node SH
+@subsection Renesas SH
+
+@table @code
+
+@kindex target hms@r{, with Renesas SH}
+@item target hms @var{dev}
+A Renesas SH board attached via serial line to your host. Use special
+commands @code{device} and @code{speed} to control the serial line and
+the communications speed used.
+
+@kindex target e7000@r{, with Renesas SH}
+@item target e7000 @var{dev}
+E7000 emulator for Renesas SH.
+
+@kindex target sh3@r{, with SH}
+@kindex target sh3e@r{, with SH}
+@item target sh3 @var{dev}
+@item target sh3e @var{dev}
+Renesas SH-3 and SH-3E target systems.
+
+@end table
+
+@node Sparclet
+@subsection Tsqware Sparclet
+
+@cindex Sparclet
+
+@value{GDBN} enables developers to debug tasks running on
+Sparclet targets from a Unix host.
+@value{GDBN} uses code that runs on
+both the Unix host and on the Sparclet target. The program
+@code{@value{GDBP}} is installed and executed on the Unix host.
+
+@table @code
+@item remotetimeout @var{args}
+@kindex remotetimeout
+@value{GDBN} supports the option @code{remotetimeout}.
+This option is set by the user, and @var{args} represents the number of
+seconds @value{GDBN} waits for responses.
+@end table
+
+@cindex compiling, on Sparclet
+When compiling for debugging, include the options @samp{-g} to get debug
+information and @samp{-Ttext} to relocate the program to where you wish to
+load it on the target. You may also want to add the options @samp{-n} or
+@samp{-N} in order to reduce the size of the sections. Example:
+
+@smallexample
+sparclet-aout-gcc prog.c -Ttext 0x12010000 -g -o prog -N
+@end smallexample
+
+You can use @code{objdump} to verify that the addresses are what you intended:
+
+@smallexample
+sparclet-aout-objdump --headers --syms prog
+@end smallexample
+
+@cindex running, on Sparclet
+Once you have set
+your Unix execution search path to find @value{GDBN}, you are ready to
+run @value{GDBN}. From your Unix host, run @code{@value{GDBP}}
+(or @code{sparclet-aout-gdb}, depending on your installation).
+
+@value{GDBN} comes up showing the prompt:
+
+@smallexample
+(gdbslet)
+@end smallexample
+
+@menu
+* Sparclet File:: Setting the file to debug
+* Sparclet Connection:: Connecting to Sparclet
+* Sparclet Download:: Sparclet download
+* Sparclet Execution:: Running and debugging
+@end menu
+
+@node Sparclet File
+@subsubsection Setting file to debug
+
+The @value{GDBN} command @code{file} lets you choose with program to debug.
+
+@smallexample
+(gdbslet) file prog
+@end smallexample
+
+@need 1000
+@value{GDBN} then attempts to read the symbol table of @file{prog}.
+@value{GDBN} locates
+the file by searching the directories listed in the command search
+path.
+If the file was compiled with debug information (option "-g"), source
+files will be searched as well.
+@value{GDBN} locates
+the source files by searching the directories listed in the directory search
+path (@pxref{Environment, ,Your program's environment}).
+If it fails
+to find a file, it displays a message such as:
+
+@smallexample
+prog: No such file or directory.
+@end smallexample
+
+When this happens, add the appropriate directories to the search paths with
+the @value{GDBN} commands @code{path} and @code{dir}, and execute the
+@code{target} command again.
+
+@node Sparclet Connection
+@subsubsection Connecting to Sparclet
+
+The @value{GDBN} command @code{target} lets you connect to a Sparclet target.
+To connect to a target on serial port ``@code{ttya}'', type:
+
+@smallexample
+(gdbslet) target sparclet /dev/ttya
+Remote target sparclet connected to /dev/ttya
+main () at ../prog.c:3
+@end smallexample
+
+@need 750
+@value{GDBN} displays messages like these:
+
+@smallexample
+Connected to ttya.
+@end smallexample
+
+@node Sparclet Download
+@subsubsection Sparclet download
+
+@cindex download to Sparclet
+Once connected to the Sparclet target,
+you can use the @value{GDBN}
+@code{load} command to download the file from the host to the target.
+The file name and load offset should be given as arguments to the @code{load}
+command.
+Since the file format is aout, the program must be loaded to the starting
+address. You can use @code{objdump} to find out what this value is. The load
+offset is an offset which is added to the VMA (virtual memory address)
+of each of the file's sections.
+For instance, if the program
+@file{prog} was linked to text address 0x1201000, with data at 0x12010160
+and bss at 0x12010170, in @value{GDBN}, type:
+
+@smallexample
+(gdbslet) load prog 0x12010000
+Loading section .text, size 0xdb0 vma 0x12010000
+@end smallexample
+
+If the code is loaded at a different address then what the program was linked
+to, you may need to use the @code{section} and @code{add-symbol-file} commands
+to tell @value{GDBN} where to map the symbol table.
+
+@node Sparclet Execution
+@subsubsection Running and debugging
+
+@cindex running and debugging Sparclet programs
+You can now begin debugging the task using @value{GDBN}'s execution control
+commands, @code{b}, @code{step}, @code{run}, etc. See the @value{GDBN}
+manual for the list of commands.
+
+@smallexample
+(gdbslet) b main
+Breakpoint 1 at 0x12010000: file prog.c, line 3.
+(gdbslet) run
+Starting program: prog
+Breakpoint 1, main (argc=1, argv=0xeffff21c) at prog.c:3
+3 char *symarg = 0;
+(gdbslet) step
+4 char *execarg = "hello!";
+(gdbslet)
+@end smallexample
+
+@node Sparclite
+@subsection Fujitsu Sparclite
+
+@table @code
+
+@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
+
+@node ST2000
+@subsection Tandem ST2000
+
+@value{GDBN} may be used with a Tandem ST2000 phone switch, running Tandem's
+STDBUG protocol.
+
+To connect your ST2000 to the host system, see the manufacturer's
+manual. Once the ST2000 is physically attached, you can run:
+
+@smallexample
+target st2000 @var{dev} @var{speed}
+@end smallexample
+
+@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
+
+@node Z8000
+@subsection Zilog Z8000
+
+@cindex Z8000
+@cindex simulator, Z8000
+@cindex Zilog Z8000 simulator
+
+When configured for debugging Zilog Z8000 targets, @value{GDBN} includes
+a Z8000 simulator.
+
+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.
+
+@table @code
+@item target sim @var{args}
+@kindex sim
+@kindex target sim@r{, with Z8000}
+Debug programs on a simulated CPU. If the simulator supports setup
+options, specify them via @var{args}.
+@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
+(@pxref{Registers, ,Registers}), the Z8000 simulator 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.
+
+@node Architectures
+@section Architectures
+
+This section describes characteristics of architectures that affect
+all uses of @value{GDBN} with the architecture, both native and cross.
+
+@menu
+* A29K::
+* Alpha::
+* MIPS::
+@end menu
+
+@node A29K
+@subsection A29K
+
+@table @code
+
+@kindex set rstack_high_address
+@cindex AMD 29K register stack
+@cindex register stack, AMD29K
+@item set rstack_high_address @var{address}
+On AMD 29000 family processors, registers are saved in a separate
+@dfn{register stack}. There is no way for @value{GDBN} to determine the
+extent of this stack. Normally, @value{GDBN} just assumes that the
+stack is ``large enough''. This may result in @value{GDBN} referencing
+memory locations that do not exist. If necessary, you can get around
+this problem by specifying the ending address of the register stack with
+the @code{set rstack_high_address} command. The argument should be an
+address, which you probably want to precede with @samp{0x} to specify in
+hexadecimal.
+
+@kindex show rstack_high_address
+@item show rstack_high_address
+Display the current limit of the register stack, on AMD 29000 family
+processors.
+
+@end table
+
+@node Alpha
+@subsection Alpha
+
+See the following section.
+
+@node MIPS
+@subsection MIPS
+
+@cindex stack on Alpha
+@cindex stack on MIPS
+@cindex Alpha stack
+@cindex MIPS stack
+Alpha- and 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} (Alpha, 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 Alpha or MIPS processors.
+
+
+@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, see @ref{Print Settings, ,Print settings}. Other settings are
+described here.
+
+@menu
+* Prompt:: Prompt
+* Editing:: Command editing
+* History:: Command history
+* Screen Size:: Screen size
+* Numbers:: Numbers
+* ABI:: Configuring the current ABI
+* Messages/Warnings:: Optional warnings and messages
+* Debugging Output:: Optional messages about internal happenings
+@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} does not add 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} (@file{./_gdb_history} on MS-DOS) 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 shows
+@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 terminal
+driver software. For example, on Unix @value{GDBN} uses 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 ABI
+@section Configuring the current ABI
+
+@value{GDBN} can determine the @dfn{ABI} (Application Binary Interface) of your
+application automatically. However, sometimes you need to override its
+conclusions. Use these commands to manage @value{GDBN}'s view of the
+current ABI.
+
+@cindex OS ABI
+@kindex set osabi
+@kindex show osabi
+
+One @value{GDBN} configuration can debug binaries for multiple operating
+system targets, either via remote debugging or native emulation.
+@value{GDBN} will autodetect the @dfn{OS ABI} (Operating System ABI) in use,
+but you can override its conclusion using the @code{set osabi} command.
+One example where this is useful is in debugging of binaries which use
+an alternate C library (e.g.@: @sc{uClibc} for @sc{gnu}/Linux) which does
+not have the same identifying marks that the standard C library for your
+platform provides.
+
+@table @code
+@item show osabi
+Show the OS ABI currently in use.
+
+@item set osabi
+With no argument, show the list of registered available OS ABI's.
+
+@item set osabi @var{abi}
+Set the current OS ABI to @var{abi}.
+@end table
+
+@cindex float promotion
+@kindex set coerce-float-to-double
+
+Generally, the way that an argument of type @code{float} is passed to a
+function depends on whether the function is prototyped. For a prototyped
+(i.e.@: ANSI/ISO style) function, @code{float} arguments are passed unchanged,
+according to the architecture's convention for @code{float}. For unprototyped
+(i.e.@: K&R style) functions, @code{float} arguments are first promoted to type
+@code{double} and then passed.
+
+Unfortunately, some forms of debug information do not reliably indicate whether
+a function is prototyped. If @value{GDBN} calls a function that is not marked
+as prototyped, it consults @kbd{set coerce-float-to-double}.
+
+@table @code
+@item set coerce-float-to-double
+@itemx set coerce-float-to-double on
+Arguments of type @code{float} will be promoted to @code{double} when passed
+to an unprototyped function. This is the default setting.
+
+@item set coerce-float-to-double off
+Arguments of type @code{float} will be passed directly to unprototyped
+functions.
+@end table
+
+@kindex set cp-abi
+@kindex show cp-abi
+@value{GDBN} needs to know the ABI used for your program's C@t{++}
+objects. The correct C@t{++} ABI depends on which C@t{++} compiler was
+used to build your application. @value{GDBN} only fully supports
+programs with a single C@t{++} ABI; if your program contains code using
+multiple C@t{++} ABI's or if @value{GDBN} can not identify your
+program's ABI correctly, you can tell @value{GDBN} which ABI to use.
+Currently supported ABI's include ``gnu-v2'', for @code{g++} versions
+before 3.0, ``gnu-v3'', for @code{g++} versions 3.0 and later, and
+``hpaCC'' for the HP ANSI C@t{++} compiler. Other C@t{++} compilers may
+use the ``gnu-v2'' or ``gnu-v3'' ABI's as well. The default setting is
+``auto''.
+
+@table @code
+@item show cp-abi
+Show the C@t{++} ABI currently in use.
+
+@item set cp-abi
+With no argument, show the list of supported C@t{++} ABI's.
+
+@item set cp-abi @var{abi}
+@itemx set cp-abi auto
+Set the current C@t{++} ABI to @var{abi}, or return to automatic detection.
+@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:
+
+@smallexample
+(@value{GDBP}) run
+The program being debugged has been started already.
+Start it from the beginning? (y or n)
+@end smallexample
+
+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 Debugging Output
+@section Optional messages about internal happenings
+@table @code
+@kindex set debug arch
+@item set debug arch
+Turns on or off display of gdbarch debugging info. The default is off
+@kindex show debug arch
+@item show debug arch
+Displays the current state of displaying gdbarch debugging info.
+@kindex set debug event
+@item set debug event
+Turns on or off display of @value{GDBN} event debugging info. The
+default is off.
+@kindex show debug event
+@item show debug event
+Displays the current state of displaying @value{GDBN} event debugging
+info.
+@kindex set debug expression
+@item set debug expression
+Turns on or off display of @value{GDBN} expression debugging info. The
+default is off.
+@kindex show debug expression
+@item show debug expression
+Displays the current state of displaying @value{GDBN} expression
+debugging info.
+@kindex set debug frame
+@item set debug frame
+Turns on or off display of @value{GDBN} frame debugging info. The
+default is off.
+@kindex show debug frame
+@item show debug frame
+Displays the current state of displaying @value{GDBN} frame debugging
+info.
+@kindex set debug overload
+@item set debug overload
+Turns on or off display of @value{GDBN} C@t{++} overload debugging
+info. This includes info such as ranking of functions, etc. The default
+is off.
+@kindex show debug overload
+@item show debug overload
+Displays the current state of displaying @value{GDBN} C@t{++} overload
+debugging info.
+@kindex set debug remote
+@cindex packets, reporting on stdout
+@cindex serial connections, debugging
+@item set debug remote
+Turns on or off display of reports on all packets sent back and forth across
+the serial line to the remote machine. The info is printed on the
+@value{GDBN} standard output stream. The default is off.
+@kindex show debug remote
+@item show debug remote
+Displays the state of display of remote packets.
+@kindex set debug serial
+@item set debug serial
+Turns on or off display of @value{GDBN} serial debugging info. The
+default is off.
+@kindex show debug serial
+@item show debug serial
+Displays the current state of displaying @value{GDBN} serial debugging
+info.
+@kindex set debug target
+@item set debug target
+Turns on or off display of @value{GDBN} target debugging info. This info
+includes what is going on at the target level of GDB, as it happens. The
+default is off.
+@kindex show debug target
+@item show debug target
+Displays the current state of displaying @value{GDBN} target debugging
+info.
+@kindex set debug varobj
+@item set debug varobj
+Turns on or off display of @value{GDBN} variable object debugging
+info. The default is off.
+@kindex show debug varobj
+@item show debug varobj
+Displays the current state of displaying @value{GDBN} variable object
+debugging info.
+@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.
+
+@kindex show max-user-call-depth
+@kindex set max-user-call-depth
+@item show max-user-call-depth
+@itemx set max-user-call-depth
+The value of @code{max-user-call-depth} controls how many recursion
+levels are allowed in user-defined commands before GDB suspects an
+infinite recursion and aborts the command.
+
+@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 hooks
+@cindex hooks, for commands
+@cindex hooks, pre-command
+
+@kindex hook
+@kindex hook-
+You may define @dfn{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.
+
+@cindex hooks, post-command
+@kindex hookpost
+@kindex hookpost-
+A hook may also be defined which is run after the command you executed.
+Whenever you run the command @samp{foo}, if the user-defined command
+@samp{hookpost-foo} exists, it is executed (with no arguments) after
+that command. Post-execution hooks may exist simultaneously with
+pre-execution hooks, for the same command.
+
+It is valid for a hook to call the command which it hooks. If this
+occurs, the hook is not re-executed, thereby avoiding infinte recursion.
+
+@c It would be nice if hookpost could be passed a parameter indicating
+@c if the command it hooks executed properly or not. FIXME!
+
+@kindex stop@r{, a pseudo-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.
+
+For example, to ignore @code{SIGALRM} signals while
+single-stepping, but treat them normally during normal execution,
+you could define:
+
+@smallexample
+define hook-stop
+handle SIGALRM nopass
+end
+
+define hook-run
+handle SIGALRM pass
+end
+
+define hook-continue
+handle SIGLARM pass
+end
+@end smallexample
+
+As a further example, to hook at the begining and end of the @code{echo}
+command, and to add extra text to the beginning and end of the message,
+you could define:
+
+@smallexample
+define hook-echo
+echo <<<---
+end
+
+define hookpost-echo
+echo --->>>\n
+end
+
+(@value{GDBP}) echo Hello World
+<<<---Hello World--->>>
+(@value{GDBP})
+
+@end smallexample
+
+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{.gdbinit}
+@cindex @file{gdb.ini}
+When you start @value{GDBN}, it automatically executes commands from its
+@dfn{init files}, normally called @file{.gdbinit}@footnote{The DJGPP
+port of @value{GDBN} uses the name @file{gdb.ini} instead, due to the
+limitations of file names imposed by DOS filesystems.}.
+During startup, @value{GDBN} does the following:
+
+@enumerate
+@item
+Reads the init file (if any) in your home directory@footnote{On
+DOS/Windows systems, the home directory is the one pointed to by the
+@code{HOME} environment variable.}.
+
+@item
+Processes command line options and operands.
+
+@item
+Reads the init file (if any) in the current working directory.
+
+@item
+Reads command files specified by the @samp{-x} option.
+@end enumerate
+
+The init file in your home directory can set options (such as @samp{set
+complaints}) that affect subsequent processing of command line options
+and operands. Init files are not executed if you use the @samp{-nx}
+option (@pxref{Mode Options, ,Choosing modes}).
+
+@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:
+
+@cindex @file{.vxgdbinit}
+@itemize @bullet
+@item
+VxWorks (Wind River Systems real-time OS): @file{.vxgdbinit}
+
+@cindex @file{.os68gdbinit}
+@item
+OS68K (Enea Data Systems real-time OS): @file{.os68gdbinit}
+
+@cindex @file{.esgdbinit}
+@item
+ES-1800 (Ericsson Telecom AB M68000 emulator): @file{.esgdbinit}
+@end itemize
+
+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 and control is returned to the console.
+
+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.
+
+@value{GDBN} also accepts command input from standard input. In this
+mode, normal output goes to standard output and error output goes to
+standard error. Errors in a command file supplied on standard input do
+not terminate execution of the command file --- execution continues with
+the next command.
+
+@smallexample
+gdb < cmds > log 2>&1
+@end smallexample
+
+(The syntax above will vary depending on the shell used.) This example
+will execute commands from the file @file{cmds}. All output and errors
+would be directed to @file{log}.
+
+@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,
+
+@smallexample
+echo This is some text\n\
+which is continued\n\
+onto several lines.\n
+@end smallexample
+
+produces the same output as
+
+@smallexample
+echo This is some text\n
+echo which is continued\n
+echo onto several lines.\n
+@end smallexample
+
+@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
+@c FIXME: the above implies that at least all ANSI C formats are
+@c supported, but it isn't true: %E and %G don't work (or so it seems).
+@c Either this is a bug, or the manual should document what formats are
+@c supported.
+
+@smallexample
+printf (@var{string}, @var{expressions}@dots{});
+@end smallexample
+
+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
+
+@node Interpreters
+@chapter Command Interpreters
+@cindex command interpreters
+
+@value{GDBN} supports multiple command interpreters, and some command
+infrastructure to allow users or user interface writers to switch
+between interpreters or run commands in other interpreters.
+
+@value{GDBN} currently supports two command interpreters, the console
+interpreter (sometimes called the command-line interpreter or @sc{cli})
+and the machine interface interpreter (or @sc{gdb/mi}). This manual
+describes both of these interfaces in great detail.
+
+By default, @value{GDBN} will start with the console interpreter.
+However, the user may choose to start @value{GDBN} with another
+interpreter by specifying the @option{-i} or @option{--interpreter}
+startup options. Defined interpreters include:
+
+@table @code
+@item console
+@cindex console interpreter
+The traditional console or command-line interpreter. This is the most often
+used interpreter with @value{GDBN}. With no interpreter specified at runtime,
+@value{GDBN} will use this interpreter.
+
+@item mi
+@cindex mi interpreter
+The newest @sc{gdb/mi} interface (currently @code{mi2}). Used primarily
+by programs wishing to use @value{GDBN} as a backend for a debugger GUI
+or an IDE. For more information, see @ref{GDB/MI, ,The @sc{gdb/mi}
+Interface}.
+
+@item mi2
+@cindex mi2 interpreter
+The current @sc{gdb/mi} interface.
+
+@item mi1
+@cindex mi1 interpreter
+The @sc{gdb/mi} interface included in @value{GDBN} 5.1, 5.2, and 5.3.
+
+@end table
+
+@cindex invoke another interpreter
+The interpreter being used by @value{GDBN} may not be dynamically
+switched at runtime. Although possible, this could lead to a very
+precarious situation. Consider an IDE using @sc{gdb/mi}. If a user
+enters the command "interpreter-set console" in a console view,
+@value{GDBN} would switch to using the console interpreter, rendering
+the IDE inoperable!
+
+@kindex interpreter-exec
+Although you may only choose a single interpreter at startup, you may execute
+commands in any interpreter from the current interpreter using the appropriate
+command. If you are running the console interpreter, simply use the
+@code{interpreter-exec} command:
+
+@smallexample
+interpreter-exec mi "-data-list-register-names"
+@end smallexample
+
+@sc{gdb/mi} has a similar command, although it is only available in versions of
+@value{GDBN} which support @sc{gdb/mi} version 2 (or greater).
+
+@node TUI
+@chapter @value{GDBN} Text User Interface
+@cindex TUI
+@cindex Text User Interface
+
+@menu
+* TUI Overview:: TUI overview
+* TUI Keys:: TUI key bindings
+* TUI Single Key Mode:: TUI single key mode
+* TUI Commands:: TUI specific commands
+* TUI Configuration:: TUI configuration variables
+@end menu
+
+The @value{GDBN} Text User Interface, TUI in short, is a terminal
+interface which uses the @code{curses} library to show the source
+file, the assembly output, the program registers and @value{GDBN}
+commands in separate text windows.
+
+The TUI is enabled by invoking @value{GDBN} using either
+@pindex gdbtui
+@samp{gdbtui} or @samp{gdb -tui}.
+
+@node TUI Overview
+@section TUI overview
+
+The TUI has two display modes that can be switched while
+@value{GDBN} runs:
+
+@itemize @bullet
+@item
+A curses (or TUI) mode in which it displays several text
+windows on the terminal.
+
+@item
+A standard mode which corresponds to the @value{GDBN} configured without
+the TUI.
+@end itemize
+
+In the TUI mode, @value{GDBN} can display several text window
+on the terminal:
+
+@table @emph
+@item command
+This window is the @value{GDBN} command window with the @value{GDBN}
+prompt and the @value{GDBN} outputs. The @value{GDBN} input is still
+managed using readline but through the TUI. The @emph{command}
+window is always visible.
+
+@item source
+The source window shows the source file of the program. The current
+line as well as active breakpoints are displayed in this window.
+
+@item assembly
+The assembly window shows the disassembly output of the program.
+
+@item register
+This window shows the processor registers. It detects when
+a register is changed and when this is the case, registers that have
+changed are highlighted.
+
+@end table
+
+The source and assembly windows show the current program position
+by highlighting the current line and marking them with the @samp{>} marker.
+Breakpoints are also indicated with two markers. A first one
+indicates the breakpoint type:
+
+@table @code
+@item B
+Breakpoint which was hit at least once.
+
+@item b
+Breakpoint which was never hit.
+
+@item H
+Hardware breakpoint which was hit at least once.
+
+@item h
+Hardware breakpoint which was never hit.
+
+@end table
+
+The second marker indicates whether the breakpoint is enabled or not:
+
+@table @code
+@item +
+Breakpoint is enabled.
+
+@item -
+Breakpoint is disabled.
+
+@end table
+
+The source, assembly and register windows are attached to the thread
+and the frame position. They are updated when the current thread
+changes, when the frame changes or when the program counter changes.
+These three windows are arranged by the TUI according to several
+layouts. The layout defines which of these three windows are visible.
+The following layouts are available:
+
+@itemize @bullet
+@item
+source
+
+@item
+assembly
+
+@item
+source and assembly
+
+@item
+source and registers
+
+@item
+assembly and registers
+
+@end itemize
+
+On top of the command window a status line gives various information
+concerning the current process begin debugged. The status line is
+updated when the information it shows changes. The following fields
+are displayed:
+
+@table @emph
+@item target
+Indicates the current gdb target
+(@pxref{Targets, ,Specifying a Debugging Target}).
+
+@item process
+Gives information about the current process or thread number.
+When no process is being debugged, this field is set to @code{No process}.
+
+@item function
+Gives the current function name for the selected frame.
+The name is demangled if demangling is turned on (@pxref{Print Settings}).
+When there is no symbol corresponding to the current program counter
+the string @code{??} is displayed.
+
+@item line
+Indicates the current line number for the selected frame.
+When the current line number is not known the string @code{??} is displayed.
+
+@item pc
+Indicates the current program counter address.
+
+@end table
+
+@node TUI Keys
+@section TUI Key Bindings
+@cindex TUI key bindings
+
+The TUI installs several key bindings in the readline keymaps
+(@pxref{Command Line Editing}).
+They allow to leave or enter in the TUI mode or they operate
+directly on the TUI layout and windows. The TUI also provides
+a @emph{SingleKey} keymap which binds several keys directly to
+@value{GDBN} commands. The following key bindings
+are installed for both TUI mode and the @value{GDBN} standard mode.
+
+@table @kbd
+@kindex C-x C-a
+@item C-x C-a
+@kindex C-x a
+@itemx C-x a
+@kindex C-x A
+@itemx C-x A
+Enter or leave the TUI mode. When the TUI mode is left,
+the curses window management is left and @value{GDBN} operates using
+its standard mode writing on the terminal directly. When the TUI
+mode is entered, the control is given back to the curses windows.
+The screen is then refreshed.
+
+@kindex C-x 1
+@item C-x 1
+Use a TUI layout with only one window. The layout will
+either be @samp{source} or @samp{assembly}. When the TUI mode
+is not active, it will switch to the TUI mode.
+
+Think of this key binding as the Emacs @kbd{C-x 1} binding.
+
+@kindex C-x 2
+@item C-x 2
+Use a TUI layout with at least two windows. When the current
+layout shows already two windows, a next layout with two windows is used.
+When a new layout is chosen, one window will always be common to the
+previous layout and the new one.
+
+Think of it as the Emacs @kbd{C-x 2} binding.
+
+@kindex C-x o
+@item C-x o
+Change the active window. The TUI associates several key bindings
+(like scrolling and arrow keys) to the active window. This command
+gives the focus to the next TUI window.
+
+Think of it as the Emacs @kbd{C-x o} binding.
+
+@kindex C-x s
+@item C-x s
+Use the TUI @emph{SingleKey} keymap that binds single key to gdb commands
+(@pxref{TUI Single Key Mode}).
+
+@end table
+
+The following key bindings are handled only by the TUI mode:
+
+@table @key
+@kindex PgUp
+@item PgUp
+Scroll the active window one page up.
+
+@kindex PgDn
+@item PgDn
+Scroll the active window one page down.
+
+@kindex Up
+@item Up
+Scroll the active window one line up.
+
+@kindex Down
+@item Down
+Scroll the active window one line down.
+
+@kindex Left
+@item Left
+Scroll the active window one column left.
+
+@kindex Right
+@item Right
+Scroll the active window one column right.
+
+@kindex C-L
+@item C-L
+Refresh the screen.
+
+@end table
+
+In the TUI mode, the arrow keys are used by the active window
+for scrolling. This means they are available for readline when the
+active window is the command window. When the command window
+does not have the focus, it is necessary to use other readline
+key bindings such as @key{C-p}, @key{C-n}, @key{C-b} and @key{C-f}.
+
+@node TUI Single Key Mode
+@section TUI Single Key Mode
+@cindex TUI single key mode
+
+The TUI provides a @emph{SingleKey} mode in which it installs a particular
+key binding in the readline keymaps to connect single keys to
+some gdb commands.
+
+@table @kbd
+@kindex c @r{(SingleKey TUI key)}
+@item c
+continue
+
+@kindex d @r{(SingleKey TUI key)}
+@item d
+down
+
+@kindex f @r{(SingleKey TUI key)}
+@item f
+finish
+
+@kindex n @r{(SingleKey TUI key)}
+@item n
+next
+
+@kindex q @r{(SingleKey TUI key)}
+@item q
+exit the @emph{SingleKey} mode.
+
+@kindex r @r{(SingleKey TUI key)}
+@item r
+run
+
+@kindex s @r{(SingleKey TUI key)}
+@item s
+step
+
+@kindex u @r{(SingleKey TUI key)}
+@item u
+up
+
+@kindex v @r{(SingleKey TUI key)}
+@item v
+info locals
+
+@kindex w @r{(SingleKey TUI key)}
+@item w
+where
+
+@end table
+
+Other keys temporarily switch to the @value{GDBN} command prompt.
+The key that was pressed is inserted in the editing buffer so that
+it is possible to type most @value{GDBN} commands without interaction
+with the TUI @emph{SingleKey} mode. Once the command is entered the TUI
+@emph{SingleKey} mode is restored. The only way to permanently leave
+this mode is by hitting @key{q} or @samp{@key{C-x} @key{s}}.
+
+
+@node TUI Commands
+@section TUI specific commands
+@cindex TUI commands
+
+The TUI has specific commands to control the text windows.
+These commands are always available, that is they do not depend on
+the current terminal mode in which @value{GDBN} runs. When @value{GDBN}
+is in the standard mode, using these commands will automatically switch
+in the TUI mode.
+
+@table @code
+@item info win
+@kindex info win
+List and give the size of all displayed windows.
+
+@item layout next
+@kindex layout next
+Display the next layout.
+
+@item layout prev
+@kindex layout prev
+Display the previous layout.
+
+@item layout src
+@kindex layout src
+Display the source window only.
+
+@item layout asm
+@kindex layout asm
+Display the assembly window only.
+
+@item layout split
+@kindex layout split
+Display the source and assembly window.
+
+@item layout regs
+@kindex layout regs
+Display the register window together with the source or assembly window.
+
+@item focus next | prev | src | asm | regs | split
+@kindex focus
+Set the focus to the named window.
+This command allows to change the active window so that scrolling keys
+can be affected to another window.
+
+@item refresh
+@kindex refresh
+Refresh the screen. This is similar to using @key{C-L} key.
+
+@item tui reg float
+@kindex tui reg
+Show the floating point registers in the register window.
+
+@item tui reg general
+Show the general registers in the register window.
+
+@item tui reg next
+Show the next register group. The list of register groups as well as
+their order is target specific. The predefined register groups are the
+following: @code{general}, @code{float}, @code{system}, @code{vector},
+@code{all}, @code{save}, @code{restore}.
+
+@item tui reg system
+Show the system registers in the register window.
+
+@item update
+@kindex update
+Update the source window and the current execution point.
+
+@item winheight @var{name} +@var{count}
+@itemx winheight @var{name} -@var{count}
+@kindex winheight
+Change the height of the window @var{name} by @var{count}
+lines. Positive counts increase the height, while negative counts
+decrease it.
+
+@end table
+
+@node TUI Configuration
+@section TUI configuration variables
+@cindex TUI configuration variables
+
+The TUI has several configuration variables that control the
+appearance of windows on the terminal.
+
+@table @code
+@item set tui border-kind @var{kind}
+@kindex set tui border-kind
+Select the border appearance for the source, assembly and register windows.
+The possible values are the following:
+@table @code
+@item space
+Use a space character to draw the border.
+
+@item ascii
+Use ascii characters + - and | to draw the border.
+
+@item acs
+Use the Alternate Character Set to draw the border. The border is
+drawn using character line graphics if the terminal supports them.
+
+@end table
+
+@item set tui active-border-mode @var{mode}
+@kindex set tui active-border-mode
+Select the attributes to display the border of the active window.
+The possible values are @code{normal}, @code{standout}, @code{reverse},
+@code{half}, @code{half-standout}, @code{bold} and @code{bold-standout}.
+
+@item set tui border-mode @var{mode}
+@kindex set tui border-mode
+Select the attributes to display the border of other windows.
+The @var{mode} can be one of the following:
+@table @code
+@item normal
+Use normal attributes to display the border.
+
+@item standout
+Use standout mode.
+
+@item reverse
+Use reverse video mode.
+
+@item half
+Use half bright mode.
+
+@item half-standout
+Use half bright and standout mode.
+
+@item bold
+Use extra bright or bold mode.
+
+@item bold-standout
+Use extra bright or bold and standout mode.
+
+@end table
+
+@end table
+
+@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.
+@c (Do not use the @code{-tui} option to run @value{GDBN} from Emacs.)
+
+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.
+
+If you specify an absolute file name when prompted for the @kbd{M-x
+gdb} argument, then Emacs sets your current working directory to where
+your program resides. If you only specify the file name, then Emacs
+sets your current working directory to to the directory associated
+with the previous buffer. In this case, @value{GDBN} may find your
+program by searching your environment's @code{PATH} variable, but on
+some operating systems it might not find the source. So, although the
+@value{GDBN} input and output session proceeds normally, the auxiliary
+buffer does not display the current source and line of execution.
+
+The initial working directory of @value{GDBN} is printed on the top
+line of the @value{GDBN} I/O buffer and this serves as a default for
+the commands that specify files for @value{GDBN} to operate
+on. @xref{Files, ,Commands to specify files}.
+
+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
+customize the Emacs variable @code{gud-gdb-command-name} to run the
+one you want.
+
+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 C-c C-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 C-c C-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 C-c C-i
+Execute one instruction, like the @value{GDBN} @code{stepi} 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 C-c C-r
+Continue execution of your program, like the @value{GDBN} @code{continue}
+command.
+
+@item C-c <
+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.
+
+@item C-c >
+Go down the number of frames indicated by the numeric argument, like the
+@value{GDBN} @code{down} command.
+@end table
+
+In any source file, the Emacs command @kbd{C-x SPC} (@code{gud-break})
+tells @value{GDBN} to set a breakpoint on the source line point is on.
+
+If you type @kbd{M-x speedbar}, then Emacs displays a separate frame which
+shows a backtrace when the @value{GDBN} I/O buffer is current. Move
+point to any frame in the stack and type @key{RET} to make it become the
+current frame and display the associated source in the source buffer.
+Alternatively, click @kbd{Mouse-2} to make the selected frame become the
+current one.
+
+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.
+
+The description given here is for GNU Emacs version 21.3 and a more
+detailed description of its interaction with @value{GDBN} is given in
+the Emacs manual (@pxref{Debuggers,,, Emacs, The @sc{gnu} Emacs Manual}).
+
+@c The following dropped because Epoch is nonstandard. Reactivate
+@c if/when v19 does something similar. ---doc@cygnus.com 19dec1990
+@ignore
+@kindex Emacs Epoch environment
+@kindex Epoch
+@kindex inspect
+
+Version 18 of @sc{gnu} Emacs has a built-in window system
+called the @code{epoch}
+environment. Users of this environment can use a new command,
+@code{inspect} which performs identically to @code{print} except that
+each value is printed in its own window.
+@end ignore
+
+
+@node GDB/MI
+@chapter The @sc{gdb/mi} Interface
+
+@unnumberedsec Function and Purpose
+
+@cindex @sc{gdb/mi}, its purpose
+@sc{gdb/mi} is a line based machine oriented text interface to @value{GDBN}. It is
+specifically intended to support the development of systems which use
+the debugger as just one small component of a larger system.
+
+This chapter is a specification of the @sc{gdb/mi} interface. It is written
+in the form of a reference manual.
+
+Note that @sc{gdb/mi} is still under construction, so some of the
+features described below are incomplete and subject to change.
+
+@unnumberedsec Notation and Terminology
+
+@cindex notational conventions, for @sc{gdb/mi}
+This chapter uses the following notation:
+
+@itemize @bullet
+@item
+@code{|} separates two alternatives.
+
+@item
+@code{[ @var{something} ]} indicates that @var{something} is optional:
+it may or may not be given.
+
+@item
+@code{( @var{group} )*} means that @var{group} inside the parentheses
+may repeat zero or more times.
+
+@item
+@code{( @var{group} )+} means that @var{group} inside the parentheses
+may repeat one or more times.
+
+@item
+@code{"@var{string}"} means a literal @var{string}.
+@end itemize
+
+@ignore
+@heading Dependencies
+@end ignore
+
+@heading Acknowledgments
+
+In alphabetic order: Andrew Cagney, Fernando Nasser, Stan Shebs and
+Elena Zannoni.
+
+@menu
+* GDB/MI Command Syntax::
+* GDB/MI Compatibility with CLI::
+* GDB/MI Output Records::
+* GDB/MI Command Description Format::
+* GDB/MI Breakpoint Table Commands::
+* GDB/MI Data Manipulation::
+* GDB/MI Program Control::
+* GDB/MI Miscellaneous Commands::
+@ignore
+* GDB/MI Kod Commands::
+* GDB/MI Memory Overlay Commands::
+* GDB/MI Signal Handling Commands::
+@end ignore
+* GDB/MI Stack Manipulation::
+* GDB/MI Symbol Query::
+* GDB/MI Target Manipulation::
+* GDB/MI Thread Commands::
+* GDB/MI Tracepoint Commands::
+* GDB/MI Variable Objects::
+@end menu
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Command Syntax
+@section @sc{gdb/mi} Command Syntax
+
+@menu
+* GDB/MI Input Syntax::
+* GDB/MI Output Syntax::
+* GDB/MI Simple Examples::
+@end menu
+
+@node GDB/MI Input Syntax
+@subsection @sc{gdb/mi} Input Syntax
+
+@cindex input syntax for @sc{gdb/mi}
+@cindex @sc{gdb/mi}, input syntax
+@table @code
+@item @var{command} @expansion{}
+@code{@var{cli-command} | @var{mi-command}}
+
+@item @var{cli-command} @expansion{}
+@code{[ @var{token} ] @var{cli-command} @var{nl}}, where
+@var{cli-command} is any existing @value{GDBN} CLI command.
+
+@item @var{mi-command} @expansion{}
+@code{[ @var{token} ] "-" @var{operation} ( " " @var{option} )*
+@code{[} " --" @code{]} ( " " @var{parameter} )* @var{nl}}
+
+@item @var{token} @expansion{}
+"any sequence of digits"
+
+@item @var{option} @expansion{}
+@code{"-" @var{parameter} [ " " @var{parameter} ]}
+
+@item @var{parameter} @expansion{}
+@code{@var{non-blank-sequence} | @var{c-string}}
+
+@item @var{operation} @expansion{}
+@emph{any of the operations described in this chapter}
+
+@item @var{non-blank-sequence} @expansion{}
+@emph{anything, provided it doesn't contain special characters such as
+"-", @var{nl}, """ and of course " "}
+
+@item @var{c-string} @expansion{}
+@code{""" @var{seven-bit-iso-c-string-content} """}
+
+@item @var{nl} @expansion{}
+@code{CR | CR-LF}
+@end table
+
+@noindent
+Notes:
+
+@itemize @bullet
+@item
+The CLI commands are still handled by the @sc{mi} interpreter; their
+output is described below.
+
+@item
+The @code{@var{token}}, when present, is passed back when the command
+finishes.
+
+@item
+Some @sc{mi} commands accept optional arguments as part of the parameter
+list. Each option is identified by a leading @samp{-} (dash) and may be
+followed by an optional argument parameter. Options occur first in the
+parameter list and can be delimited from normal parameters using
+@samp{--} (this is useful when some parameters begin with a dash).
+@end itemize
+
+Pragmatics:
+
+@itemize @bullet
+@item
+We want easy access to the existing CLI syntax (for debugging).
+
+@item
+We want it to be easy to spot a @sc{mi} operation.
+@end itemize
+
+@node GDB/MI Output Syntax
+@subsection @sc{gdb/mi} Output Syntax
+
+@cindex output syntax of @sc{gdb/mi}
+@cindex @sc{gdb/mi}, output syntax
+The output from @sc{gdb/mi} consists of zero or more out-of-band records
+followed, optionally, by a single result record. This result record
+is for the most recent command. The sequence of output records is
+terminated by @samp{(@value{GDBP})}.
+
+If an input command was prefixed with a @code{@var{token}} then the
+corresponding output for that command will also be prefixed by that same
+@var{token}.
+
+@table @code
+@item @var{output} @expansion{}
+@code{( @var{out-of-band-record} )* [ @var{result-record} ] "(gdb)" @var{nl}}
+
+@item @var{result-record} @expansion{}
+@code{ [ @var{token} ] "^" @var{result-class} ( "," @var{result} )* @var{nl}}
+
+@item @var{out-of-band-record} @expansion{}
+@code{@var{async-record} | @var{stream-record}}
+
+@item @var{async-record} @expansion{}
+@code{@var{exec-async-output} | @var{status-async-output} | @var{notify-async-output}}
+
+@item @var{exec-async-output} @expansion{}
+@code{[ @var{token} ] "*" @var{async-output}}
+
+@item @var{status-async-output} @expansion{}
+@code{[ @var{token} ] "+" @var{async-output}}
+
+@item @var{notify-async-output} @expansion{}
+@code{[ @var{token} ] "=" @var{async-output}}
+
+@item @var{async-output} @expansion{}
+@code{@var{async-class} ( "," @var{result} )* @var{nl}}
+
+@item @var{result-class} @expansion{}
+@code{"done" | "running" | "connected" | "error" | "exit"}
+
+@item @var{async-class} @expansion{}
+@code{"stopped" | @var{others}} (where @var{others} will be added
+depending on the needs---this is still in development).
+
+@item @var{result} @expansion{}
+@code{ @var{variable} "=" @var{value}}
+
+@item @var{variable} @expansion{}
+@code{ @var{string} }
+
+@item @var{value} @expansion{}
+@code{ @var{const} | @var{tuple} | @var{list} }
+
+@item @var{const} @expansion{}
+@code{@var{c-string}}
+
+@item @var{tuple} @expansion{}
+@code{ "@{@}" | "@{" @var{result} ( "," @var{result} )* "@}" }
+
+@item @var{list} @expansion{}
+@code{ "[]" | "[" @var{value} ( "," @var{value} )* "]" | "["
+@var{result} ( "," @var{result} )* "]" }
+
+@item @var{stream-record} @expansion{}
+@code{@var{console-stream-output} | @var{target-stream-output} | @var{log-stream-output}}
+
+@item @var{console-stream-output} @expansion{}
+@code{"~" @var{c-string}}
+
+@item @var{target-stream-output} @expansion{}
+@code{"@@" @var{c-string}}
+
+@item @var{log-stream-output} @expansion{}
+@code{"&" @var{c-string}}
+
+@item @var{nl} @expansion{}
+@code{CR | CR-LF}
+
+@item @var{token} @expansion{}
+@emph{any sequence of digits}.
+@end table
+
+@noindent
+Notes:
+
+@itemize @bullet
+@item
+All output sequences end in a single line containing a period.
+
+@item
+The @code{@var{token}} is from the corresponding request. If an execution
+command is interrupted by the @samp{-exec-interrupt} command, the
+@var{token} associated with the @samp{*stopped} message is the one of the
+original execution command, not the one of the interrupt command.
+
+@item
+@cindex status output in @sc{gdb/mi}
+@var{status-async-output} contains on-going status information about the
+progress of a slow operation. It can be discarded. All status output is
+prefixed by @samp{+}.
+
+@item
+@cindex async output in @sc{gdb/mi}
+@var{exec-async-output} contains asynchronous state change on the target
+(stopped, started, disappeared). All async output is prefixed by
+@samp{*}.
+
+@item
+@cindex notify output in @sc{gdb/mi}
+@var{notify-async-output} contains supplementary information that the
+client should handle (e.g., a new breakpoint information). All notify
+output is prefixed by @samp{=}.
+
+@item
+@cindex console output in @sc{gdb/mi}
+@var{console-stream-output} is output that should be displayed as is in the
+console. It is the textual response to a CLI command. All the console
+output is prefixed by @samp{~}.
+
+@item
+@cindex target output in @sc{gdb/mi}
+@var{target-stream-output} is the output produced by the target program.
+All the target output is prefixed by @samp{@@}.
+
+@item
+@cindex log output in @sc{gdb/mi}
+@var{log-stream-output} is output text coming from @value{GDBN}'s internals, for
+instance messages that should be displayed as part of an error log. All
+the log output is prefixed by @samp{&}.
+
+@item
+@cindex list output in @sc{gdb/mi}
+New @sc{gdb/mi} commands should only output @var{lists} containing
+@var{values}.
+
+
+@end itemize
+
+@xref{GDB/MI Stream Records, , @sc{gdb/mi} Stream Records}, for more
+details about the various output records.
+
+@node GDB/MI Simple Examples
+@subsection Simple Examples of @sc{gdb/mi} Interaction
+@cindex @sc{gdb/mi}, simple examples
+
+This subsection presents several simple examples of interaction using
+the @sc{gdb/mi} interface. In these examples, @samp{->} means that the
+following line is passed to @sc{gdb/mi} as input, while @samp{<-} means
+the output received from @sc{gdb/mi}.
+
+@subsubheading Target Stop
+@c Ummm... There is no "-stop" command. This assumes async, no?
+Here's an example of stopping the inferior process:
+
+@smallexample
+-> -stop
+<- (@value{GDBP})
+@end smallexample
+
+@noindent
+and later:
+
+@smallexample
+<- *stop,reason="stop",address="0x123",source="a.c:123"
+<- (@value{GDBP})
+@end smallexample
+
+@subsubheading Simple CLI Command
+
+Here's an example of a simple CLI command being passed through
+@sc{gdb/mi} and on to the CLI.
+
+@smallexample
+-> print 1+2
+<- &"print 1+2\n"
+<- ~"$1 = 3\n"
+<- ^done
+<- (@value{GDBP})
+@end smallexample
+
+@subsubheading Command With Side Effects
+
+@smallexample
+-> -symbol-file xyz.exe
+<- *breakpoint,nr="3",address="0x123",source="a.c:123"
+<- (@value{GDBP})
+@end smallexample
+
+@subsubheading A Bad Command
+
+Here's what happens if you pass a non-existent command:
+
+@smallexample
+-> -rubbish
+<- ^error,msg="Undefined MI command: rubbish"
+<- (@value{GDBP})
+@end smallexample
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Compatibility with CLI
+@section @sc{gdb/mi} Compatibility with CLI
+
+@cindex compatibility, @sc{gdb/mi} and CLI
+@cindex @sc{gdb/mi}, compatibility with CLI
+To help users familiar with @value{GDBN}'s existing CLI interface, @sc{gdb/mi}
+accepts existing CLI commands. As specified by the syntax, such
+commands can be directly entered into the @sc{gdb/mi} interface and @value{GDBN} will
+respond.
+
+This mechanism is provided as an aid to developers of @sc{gdb/mi}
+clients and not as a reliable interface into the CLI. Since the command
+is being interpreteted in an environment that assumes @sc{gdb/mi}
+behaviour, the exact output of such commands is likely to end up being
+an un-supported hybrid of @sc{gdb/mi} and CLI output.
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Output Records
+@section @sc{gdb/mi} Output Records
+
+@menu
+* GDB/MI Result Records::
+* GDB/MI Stream Records::
+* GDB/MI Out-of-band Records::
+@end menu
+
+@node GDB/MI Result Records
+@subsection @sc{gdb/mi} Result Records
+
+@cindex result records in @sc{gdb/mi}
+@cindex @sc{gdb/mi}, result records
+In addition to a number of out-of-band notifications, the response to a
+@sc{gdb/mi} command includes one of the following result indications:
+
+@table @code
+@findex ^done
+@item "^done" [ "," @var{results} ]
+The synchronous operation was successful, @code{@var{results}} are the return
+values.
+
+@item "^running"
+@findex ^running
+@c Is this one correct? Should it be an out-of-band notification?
+The asynchronous operation was successfully started. The target is
+running.
+
+@item "^error" "," @var{c-string}
+@findex ^error
+The operation failed. The @code{@var{c-string}} contains the corresponding
+error message.
+@end table
+
+@node GDB/MI Stream Records
+@subsection @sc{gdb/mi} Stream Records
+
+@cindex @sc{gdb/mi}, stream records
+@cindex stream records in @sc{gdb/mi}
+@value{GDBN} internally maintains a number of output streams: the console, the
+target, and the log. The output intended for each of these streams is
+funneled through the @sc{gdb/mi} interface using @dfn{stream records}.
+
+Each stream record begins with a unique @dfn{prefix character} which
+identifies its stream (@pxref{GDB/MI Output Syntax, , @sc{gdb/mi} Output
+Syntax}). In addition to the prefix, each stream record contains a
+@code{@var{string-output}}. This is either raw text (with an implicit new
+line) or a quoted C string (which does not contain an implicit newline).
+
+@table @code
+@item "~" @var{string-output}
+The console output stream contains text that should be displayed in the
+CLI console window. It contains the textual responses to CLI commands.
+
+@item "@@" @var{string-output}
+The target output stream contains any textual output from the running
+target.
+
+@item "&" @var{string-output}
+The log stream contains debugging messages being produced by @value{GDBN}'s
+internals.
+@end table
+
+@node GDB/MI Out-of-band Records
+@subsection @sc{gdb/mi} Out-of-band Records
+
+@cindex out-of-band records in @sc{gdb/mi}
+@cindex @sc{gdb/mi}, out-of-band records
+@dfn{Out-of-band} records are used to notify the @sc{gdb/mi} client of
+additional changes that have occurred. Those changes can either be a
+consequence of @sc{gdb/mi} (e.g., a breakpoint modified) or a result of
+target activity (e.g., target stopped).
+
+The following is a preliminary list of possible out-of-band records.
+
+@table @code
+@item "*" "stop"
+@end table
+
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Command Description Format
+@section @sc{gdb/mi} Command Description Format
+
+The remaining sections describe blocks of commands. Each block of
+commands is laid out in a fashion similar to this section.
+
+Note the the line breaks shown in the examples are here only for
+readability. They don't appear in the real output.
+Also note that the commands with a non-available example (N.A.@:) are
+not yet implemented.
+
+@subheading Motivation
+
+The motivation for this collection of commands.
+
+@subheading Introduction
+
+A brief introduction to this collection of commands as a whole.
+
+@subheading Commands
+
+For each command in the block, the following is described:
+
+@subsubheading Synopsis
+
+@smallexample
+ -command @var{args}@dots{}
+@end smallexample
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} CLI command.
+
+@subsubheading Result
+
+@subsubheading Out-of-band
+
+@subsubheading Notes
+
+@subsubheading Example
+
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Breakpoint Table Commands
+@section @sc{gdb/mi} Breakpoint table commands
+
+@cindex breakpoint commands for @sc{gdb/mi}
+@cindex @sc{gdb/mi}, breakpoint commands
+This section documents @sc{gdb/mi} commands for manipulating
+breakpoints.
+
+@subheading The @code{-break-after} Command
+@findex -break-after
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-after @var{number} @var{count}
+@end smallexample
+
+The breakpoint number @var{number} is not in effect until it has been
+hit @var{count} times. To see how this is reflected in the output of
+the @samp{-break-list} command, see the description of the
+@samp{-break-list} command below.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{ignore}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-insert main
+^done,bkpt=@{number="1",addr="0x000100d0",file="hello.c",line="5"@}
+(@value{GDBP})
+-break-after 1 3
+~
+^done
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="1",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+addr="0x000100d0",func="main",file="hello.c",line="5",times="0",
+ignore="3"@}]@}
+(@value{GDBP})
+@end smallexample
+
+@ignore
+@subheading The @code{-break-catch} Command
+@findex -break-catch
+
+@subheading The @code{-break-commands} Command
+@findex -break-commands
+@end ignore
+
+
+@subheading The @code{-break-condition} Command
+@findex -break-condition
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-condition @var{number} @var{expr}
+@end smallexample
+
+Breakpoint @var{number} will stop the program only if the condition in
+@var{expr} is true. The condition becomes part of the
+@samp{-break-list} output (see the description of the @samp{-break-list}
+command below).
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{condition}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-condition 1 1
+^done
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="1",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+addr="0x000100d0",func="main",file="hello.c",line="5",cond="1",
+times="0",ignore="3"@}]@}
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-break-delete} Command
+@findex -break-delete
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-delete ( @var{breakpoint} )+
+@end smallexample
+
+Delete the breakpoint(s) whose number(s) are specified in the argument
+list. This is obviously reflected in the breakpoint list.
+
+@subsubheading @value{GDBN} command
+
+The corresponding @value{GDBN} command is @samp{delete}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-delete 1
+^done
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="0",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[]@}
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-break-disable} Command
+@findex -break-disable
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-disable ( @var{breakpoint} )+
+@end smallexample
+
+Disable the named @var{breakpoint}(s). The field @samp{enabled} in the
+break list is now set to @samp{n} for the named @var{breakpoint}(s).
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{disable}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-disable 2
+^done
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="1",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="2",type="breakpoint",disp="keep",enabled="n",
+addr="0x000100d0",func="main",file="hello.c",line="5",times="0"@}]@}
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-break-enable} Command
+@findex -break-enable
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-enable ( @var{breakpoint} )+
+@end smallexample
+
+Enable (previously disabled) @var{breakpoint}(s).
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{enable}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-enable 2
+^done
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="1",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="2",type="breakpoint",disp="keep",enabled="y",
+addr="0x000100d0",func="main",file="hello.c",line="5",times="0"@}]@}
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-break-info} Command
+@findex -break-info
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-info @var{breakpoint}
+@end smallexample
+
+@c REDUNDANT???
+Get information about a single breakpoint.
+
+@subsubheading @value{GDBN} command
+
+The corresponding @value{GDBN} command is @samp{info break @var{breakpoint}}.
+
+@subsubheading Example
+N.A.
+
+@subheading The @code{-break-insert} Command
+@findex -break-insert
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-insert [ -t ] [ -h ] [ -r ]
+ [ -c @var{condition} ] [ -i @var{ignore-count} ]
+ [ -p @var{thread} ] [ @var{line} | @var{addr} ]
+@end smallexample
+
+@noindent
+If specified, @var{line}, can be one of:
+
+@itemize @bullet
+@item function
+@c @item +offset
+@c @item -offset
+@c @item linenum
+@item filename:linenum
+@item filename:function
+@item *address
+@end itemize
+
+The possible optional parameters of this command are:
+
+@table @samp
+@item -t
+Insert a tempoary breakpoint.
+@item -h
+Insert a hardware breakpoint.
+@item -c @var{condition}
+Make the breakpoint conditional on @var{condition}.
+@item -i @var{ignore-count}
+Initialize the @var{ignore-count}.
+@item -r
+Insert a regular breakpoint in all the functions whose names match the
+given regular expression. Other flags are not applicable to regular
+expresson.
+@end table
+
+@subsubheading Result
+
+The result is in the form:
+
+@smallexample
+ ^done,bkptno="@var{number}",func="@var{funcname}",
+ file="@var{filename}",line="@var{lineno}"
+@end smallexample
+
+@noindent
+where @var{number} is the @value{GDBN} number for this breakpoint, @var{funcname}
+is the name of the function where the breakpoint was inserted,
+@var{filename} is the name of the source file which contains this
+function, and @var{lineno} is the source line number within that file.
+
+Note: this format is open to change.
+@c An out-of-band breakpoint instead of part of the result?
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{break}, @samp{tbreak},
+@samp{hbreak}, @samp{thbreak}, and @samp{rbreak}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-insert main
+^done,bkpt=@{number="1",addr="0x0001072c",file="recursive2.c",line="4"@}
+(@value{GDBP})
+-break-insert -t foo
+^done,bkpt=@{number="2",addr="0x00010774",file="recursive2.c",line="11"@}
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="2",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+addr="0x0001072c", func="main",file="recursive2.c",line="4",times="0"@},
+bkpt=@{number="2",type="breakpoint",disp="del",enabled="y",
+addr="0x00010774",func="foo",file="recursive2.c",line="11",times="0"@}]@}
+(@value{GDBP})
+-break-insert -r foo.*
+~int foo(int, int);
+^done,bkpt=@{number="3",addr="0x00010774",file="recursive2.c",line="11"@}
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-break-list} Command
+@findex -break-list
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-list
+@end smallexample
+
+Displays the list of inserted breakpoints, showing the following fields:
+
+@table @samp
+@item Number
+number of the breakpoint
+@item Type
+type of the breakpoint: @samp{breakpoint} or @samp{watchpoint}
+@item Disposition
+should the breakpoint be deleted or disabled when it is hit: @samp{keep}
+or @samp{nokeep}
+@item Enabled
+is the breakpoint enabled or no: @samp{y} or @samp{n}
+@item Address
+memory location at which the breakpoint is set
+@item What
+logical location of the breakpoint, expressed by function name, file
+name, line number
+@item Times
+number of times the breakpoint has been hit
+@end table
+
+If there are no breakpoints or watchpoints, the @code{BreakpointTable}
+@code{body} field is an empty list.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info break}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="2",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+addr="0x000100d0",func="main",file="hello.c",line="5",times="0"@},
+bkpt=@{number="2",type="breakpoint",disp="keep",enabled="y",
+addr="0x00010114",func="foo",file="hello.c",line="13",times="0"@}]@}
+(@value{GDBP})
+@end smallexample
+
+Here's an example of the result when there are no breakpoints:
+
+@smallexample
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="0",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[]@}
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-break-watch} Command
+@findex -break-watch
+
+@subsubheading Synopsis
+
+@smallexample
+ -break-watch [ -a | -r ]
+@end smallexample
+
+Create a watchpoint. With the @samp{-a} option it will create an
+@dfn{access} watchpoint, i.e. a watchpoint that triggers either on a
+read from or on a write to the memory location. With the @samp{-r}
+option, the watchpoint created is a @dfn{read} watchpoint, i.e. it will
+trigger only when the memory location is accessed for reading. Without
+either of the options, the watchpoint created is a regular watchpoint,
+i.e. it will trigger when the memory location is accessed for writing.
+@xref{Set Watchpoints, , Setting watchpoints}.
+
+Note that @samp{-break-list} will report a single list of watchpoints and
+breakpoints inserted.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{watch}, @samp{awatch}, and
+@samp{rwatch}.
+
+@subsubheading Example
+
+Setting a watchpoint on a variable in the @code{main} function:
+
+@smallexample
+(@value{GDBP})
+-break-watch x
+^done,wpt=@{number="2",exp="x"@}
+(@value{GDBP})
+-exec-continue
+^running
+^done,reason="watchpoint-trigger",wpt=@{number="2",exp="x"@},
+value=@{old="-268439212",new="55"@},
+frame=@{func="main",args=[],file="recursive2.c",line="5"@}
+(@value{GDBP})
+@end smallexample
+
+Setting a watchpoint on a variable local to a function. @value{GDBN} will stop
+the program execution twice: first for the variable changing value, then
+for the watchpoint going out of scope.
+
+@smallexample
+(@value{GDBP})
+-break-watch C
+^done,wpt=@{number="5",exp="C"@}
+(@value{GDBP})
+-exec-continue
+^running
+^done,reason="watchpoint-trigger",
+wpt=@{number="5",exp="C"@},value=@{old="-276895068",new="3"@},
+frame=@{func="callee4",args=[],
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="13"@}
+(@value{GDBP})
+-exec-continue
+^running
+^done,reason="watchpoint-scope",wpnum="5",
+frame=@{func="callee3",args=[@{name="strarg",
+value="0x11940 \"A string argument.\""@}],
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="18"@}
+(@value{GDBP})
+@end smallexample
+
+Listing breakpoints and watchpoints, at different points in the program
+execution. Note that once the watchpoint goes out of scope, it is
+deleted.
+
+@smallexample
+(@value{GDBP})
+-break-watch C
+^done,wpt=@{number="2",exp="C"@}
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="2",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+addr="0x00010734",func="callee4",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8",times="1"@},
+bkpt=@{number="2",type="watchpoint",disp="keep",
+enabled="y",addr="",what="C",times="0"@}]@}
+(@value{GDBP})
+-exec-continue
+^running
+^done,reason="watchpoint-trigger",wpt=@{number="2",exp="C"@},
+value=@{old="-276895068",new="3"@},
+frame=@{func="callee4",args=[],
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="13"@}
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="2",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+addr="0x00010734",func="callee4",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8",times="1"@},
+bkpt=@{number="2",type="watchpoint",disp="keep",
+enabled="y",addr="",what="C",times="-5"@}]@}
+(@value{GDBP})
+-exec-continue
+^running
+^done,reason="watchpoint-scope",wpnum="2",
+frame=@{func="callee3",args=[@{name="strarg",
+value="0x11940 \"A string argument.\""@}],
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="18"@}
+(@value{GDBP})
+-break-list
+^done,BreakpointTable=@{nr_rows="1",nr_cols="6",
+hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@},
+@{width="14",alignment="-1",col_name="type",colhdr="Type"@},
+@{width="4",alignment="-1",col_name="disp",colhdr="Disp"@},
+@{width="3",alignment="-1",col_name="enabled",colhdr="Enb"@},
+@{width="10",alignment="-1",col_name="addr",colhdr="Address"@},
+@{width="40",alignment="2",col_name="what",colhdr="What"@}],
+body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+addr="0x00010734",func="callee4",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8",times="1"@}]@}
+(@value{GDBP})
+@end smallexample
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Data Manipulation
+@section @sc{gdb/mi} Data Manipulation
+
+@cindex data manipulation, in @sc{gdb/mi}
+@cindex @sc{gdb/mi}, data manipulation
+This section describes the @sc{gdb/mi} commands that manipulate data:
+examine memory and registers, evaluate expressions, etc.
+
+@c REMOVED FROM THE INTERFACE.
+@c @subheading -data-assign
+@c Change the value of a program variable. Plenty of side effects.
+@c @subsubheading GDB command
+@c set variable
+@c @subsubheading Example
+@c N.A.
+
+@subheading The @code{-data-disassemble} Command
+@findex -data-disassemble
+
+@subsubheading Synopsis
+
+@smallexample
+ -data-disassemble
+ [ -s @var{start-addr} -e @var{end-addr} ]
+ | [ -f @var{filename} -l @var{linenum} [ -n @var{lines} ] ]
+ -- @var{mode}
+@end smallexample
+
+@noindent
+Where:
+
+@table @samp
+@item @var{start-addr}
+is the beginning address (or @code{$pc})
+@item @var{end-addr}
+is the end address
+@item @var{filename}
+is the name of the file to disassemble
+@item @var{linenum}
+is the line number to disassemble around
+@item @var{lines}
+is the the number of disassembly lines to be produced. If it is -1,
+the whole function will be disassembled, in case no @var{end-addr} is
+specified. If @var{end-addr} is specified as a non-zero value, and
+@var{lines} is lower than the number of disassembly lines between
+@var{start-addr} and @var{end-addr}, only @var{lines} lines are
+displayed; if @var{lines} is higher than the number of lines between
+@var{start-addr} and @var{end-addr}, only the lines up to @var{end-addr}
+are displayed.
+@item @var{mode}
+is either 0 (meaning only disassembly) or 1 (meaning mixed source and
+disassembly).
+@end table
+
+@subsubheading Result
+
+The output for each instruction is composed of four fields:
+
+@itemize @bullet
+@item Address
+@item Func-name
+@item Offset
+@item Instruction
+@end itemize
+
+Note that whatever included in the instruction field, is not manipulated
+directely by @sc{gdb/mi}, i.e. it is not possible to adjust its format.
+
+@subsubheading @value{GDBN} Command
+
+There's no direct mapping from this command to the CLI.
+
+@subsubheading Example
+
+Disassemble from the current value of @code{$pc} to @code{$pc + 20}:
+
+@smallexample
+(@value{GDBP})
+-data-disassemble -s $pc -e "$pc + 20" -- 0
+^done,
+asm_insns=[
+@{address="0x000107c0",func-name="main",offset="4",
+inst="mov 2, %o0"@},
+@{address="0x000107c4",func-name="main",offset="8",
+inst="sethi %hi(0x11800), %o2"@},
+@{address="0x000107c8",func-name="main",offset="12",
+inst="or %o2, 0x140, %o1\t! 0x11940 <_lib_version+8>"@},
+@{address="0x000107cc",func-name="main",offset="16",
+inst="sethi %hi(0x11800), %o2"@},
+@{address="0x000107d0",func-name="main",offset="20",
+inst="or %o2, 0x168, %o4\t! 0x11968 <_lib_version+48>"@}]
+(@value{GDBP})
+@end smallexample
+
+Disassemble the whole @code{main} function. Line 32 is part of
+@code{main}.
+
+@smallexample
+-data-disassemble -f basics.c -l 32 -- 0
+^done,asm_insns=[
+@{address="0x000107bc",func-name="main",offset="0",
+inst="save %sp, -112, %sp"@},
+@{address="0x000107c0",func-name="main",offset="4",
+inst="mov 2, %o0"@},
+@{address="0x000107c4",func-name="main",offset="8",
+inst="sethi %hi(0x11800), %o2"@},
+[@dots{}]
+@{address="0x0001081c",func-name="main",offset="96",inst="ret "@},
+@{address="0x00010820",func-name="main",offset="100",inst="restore "@}]
+(@value{GDBP})
+@end smallexample
+
+Disassemble 3 instructions from the start of @code{main}:
+
+@smallexample
+(@value{GDBP})
+-data-disassemble -f basics.c -l 32 -n 3 -- 0
+^done,asm_insns=[
+@{address="0x000107bc",func-name="main",offset="0",
+inst="save %sp, -112, %sp"@},
+@{address="0x000107c0",func-name="main",offset="4",
+inst="mov 2, %o0"@},
+@{address="0x000107c4",func-name="main",offset="8",
+inst="sethi %hi(0x11800), %o2"@}]
+(@value{GDBP})
+@end smallexample
+
+Disassemble 3 instructions from the start of @code{main} in mixed mode:
+
+@smallexample
+(@value{GDBP})
+-data-disassemble -f basics.c -l 32 -n 3 -- 1
+^done,asm_insns=[
+src_and_asm_line=@{line="31",
+file="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb/ \
+ testsuite/gdb.mi/basics.c",line_asm_insn=[
+@{address="0x000107bc",func-name="main",offset="0",
+inst="save %sp, -112, %sp"@}]@},
+src_and_asm_line=@{line="32",
+file="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb/ \
+ testsuite/gdb.mi/basics.c",line_asm_insn=[
+@{address="0x000107c0",func-name="main",offset="4",
+inst="mov 2, %o0"@},
+@{address="0x000107c4",func-name="main",offset="8",
+inst="sethi %hi(0x11800), %o2"@}]@}]
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-data-evaluate-expression} Command
+@findex -data-evaluate-expression
+
+@subsubheading Synopsis
+
+@smallexample
+ -data-evaluate-expression @var{expr}
+@end smallexample
+
+Evaluate @var{expr} as an expression. The expression could contain an
+inferior function call. The function call will execute synchronously.
+If the expression contains spaces, it must be enclosed in double quotes.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{print}, @samp{output}, and
+@samp{call}. In @code{gdbtk} only, there's a corresponding
+@samp{gdb_eval} command.
+
+@subsubheading Example
+
+In the following example, the numbers that precede the commands are the
+@dfn{tokens} described in @ref{GDB/MI Command Syntax, ,@sc{gdb/mi}
+Command Syntax}. Notice how @sc{gdb/mi} returns the same tokens in its
+output.
+
+@smallexample
+211-data-evaluate-expression A
+211^done,value="1"
+(@value{GDBP})
+311-data-evaluate-expression &A
+311^done,value="0xefffeb7c"
+(@value{GDBP})
+411-data-evaluate-expression A+3
+411^done,value="4"
+(@value{GDBP})
+511-data-evaluate-expression "A + 3"
+511^done,value="4"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-data-list-changed-registers} Command
+@findex -data-list-changed-registers
+
+@subsubheading Synopsis
+
+@smallexample
+ -data-list-changed-registers
+@end smallexample
+
+Display a list of the registers that have changed.
+
+@subsubheading @value{GDBN} Command
+
+@value{GDBN} doesn't have a direct analog for this command; @code{gdbtk}
+has the corresponding command @samp{gdb_changed_register_list}.
+
+@subsubheading Example
+
+On a PPC MBX board:
+
+@smallexample
+(@value{GDBP})
+-exec-continue
+^running
+
+(@value{GDBP})
+*stopped,reason="breakpoint-hit",bkptno="1",frame=@{func="main",
+args=[],file="try.c",line="5"@}
+(@value{GDBP})
+-data-list-changed-registers
+^done,changed-registers=["0","1","2","4","5","6","7","8","9",
+"10","11","13","14","15","16","17","18","19","20","21","22","23",
+"24","25","26","27","28","30","31","64","65","66","67","69"]
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-data-list-register-names} Command
+@findex -data-list-register-names
+
+@subsubheading Synopsis
+
+@smallexample
+ -data-list-register-names [ ( @var{regno} )+ ]
+@end smallexample
+
+Show a list of register names for the current target. If no arguments
+are given, it shows a list of the names of all the registers. If
+integer numbers are given as arguments, it will print a list of the
+names of the registers corresponding to the arguments. To ensure
+consistency between a register name and its number, the output list may
+include empty register names.
+
+@subsubheading @value{GDBN} Command
+
+@value{GDBN} does not have a command which corresponds to
+@samp{-data-list-register-names}. In @code{gdbtk} there is a
+corresponding command @samp{gdb_regnames}.
+
+@subsubheading Example
+
+For the PPC MBX board:
+@smallexample
+(@value{GDBP})
+-data-list-register-names
+^done,register-names=["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","f0","f1","f2","f3","f4","f5","f6","f7","f8","f9",
+"f10","f11","f12","f13","f14","f15","f16","f17","f18","f19","f20",
+"f21","f22","f23","f24","f25","f26","f27","f28","f29","f30","f31",
+"", "pc","ps","cr","lr","ctr","xer"]
+(@value{GDBP})
+-data-list-register-names 1 2 3
+^done,register-names=["r1","r2","r3"]
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-data-list-register-values} Command
+@findex -data-list-register-values
+
+@subsubheading Synopsis
+
+@smallexample
+ -data-list-register-values @var{fmt} [ ( @var{regno} )*]
+@end smallexample
+
+Display the registers' contents. @var{fmt} is the format according to
+which the registers' contents are to be returned, followed by an optional
+list of numbers specifying the registers to display. A missing list of
+numbers indicates that the contents of all the registers must be returned.
+
+Allowed formats for @var{fmt} are:
+
+@table @code
+@item x
+Hexadecimal
+@item o
+Octal
+@item t
+Binary
+@item d
+Decimal
+@item r
+Raw
+@item N
+Natural
+@end table
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{info reg}, @samp{info
+all-reg}, and (in @code{gdbtk}) @samp{gdb_fetch_registers}.
+
+@subsubheading Example
+
+For a PPC MBX board (note: line breaks are for readability only, they
+don't appear in the actual output):
+
+@smallexample
+(@value{GDBP})
+-data-list-register-values r 64 65
+^done,register-values=[@{number="64",value="0xfe00a300"@},
+@{number="65",value="0x00029002"@}]
+(@value{GDBP})
+-data-list-register-values x
+^done,register-values=[@{number="0",value="0xfe0043c8"@},
+@{number="1",value="0x3fff88"@},@{number="2",value="0xfffffffe"@},
+@{number="3",value="0x0"@},@{number="4",value="0xa"@},
+@{number="5",value="0x3fff68"@},@{number="6",value="0x3fff58"@},
+@{number="7",value="0xfe011e98"@},@{number="8",value="0x2"@},
+@{number="9",value="0xfa202820"@},@{number="10",value="0xfa202808"@},
+@{number="11",value="0x1"@},@{number="12",value="0x0"@},
+@{number="13",value="0x4544"@},@{number="14",value="0xffdfffff"@},
+@{number="15",value="0xffffffff"@},@{number="16",value="0xfffffeff"@},
+@{number="17",value="0xefffffed"@},@{number="18",value="0xfffffffe"@},
+@{number="19",value="0xffffffff"@},@{number="20",value="0xffffffff"@},
+@{number="21",value="0xffffffff"@},@{number="22",value="0xfffffff7"@},
+@{number="23",value="0xffffffff"@},@{number="24",value="0xffffffff"@},
+@{number="25",value="0xffffffff"@},@{number="26",value="0xfffffffb"@},
+@{number="27",value="0xffffffff"@},@{number="28",value="0xf7bfffff"@},
+@{number="29",value="0x0"@},@{number="30",value="0xfe010000"@},
+@{number="31",value="0x0"@},@{number="32",value="0x0"@},
+@{number="33",value="0x0"@},@{number="34",value="0x0"@},
+@{number="35",value="0x0"@},@{number="36",value="0x0"@},
+@{number="37",value="0x0"@},@{number="38",value="0x0"@},
+@{number="39",value="0x0"@},@{number="40",value="0x0"@},
+@{number="41",value="0x0"@},@{number="42",value="0x0"@},
+@{number="43",value="0x0"@},@{number="44",value="0x0"@},
+@{number="45",value="0x0"@},@{number="46",value="0x0"@},
+@{number="47",value="0x0"@},@{number="48",value="0x0"@},
+@{number="49",value="0x0"@},@{number="50",value="0x0"@},
+@{number="51",value="0x0"@},@{number="52",value="0x0"@},
+@{number="53",value="0x0"@},@{number="54",value="0x0"@},
+@{number="55",value="0x0"@},@{number="56",value="0x0"@},
+@{number="57",value="0x0"@},@{number="58",value="0x0"@},
+@{number="59",value="0x0"@},@{number="60",value="0x0"@},
+@{number="61",value="0x0"@},@{number="62",value="0x0"@},
+@{number="63",value="0x0"@},@{number="64",value="0xfe00a300"@},
+@{number="65",value="0x29002"@},@{number="66",value="0x202f04b5"@},
+@{number="67",value="0xfe0043b0"@},@{number="68",value="0xfe00b3e4"@},
+@{number="69",value="0x20002b03"@}]
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-data-read-memory} Command
+@findex -data-read-memory
+
+@subsubheading Synopsis
+
+@smallexample
+ -data-read-memory [ -o @var{byte-offset} ]
+ @var{address} @var{word-format} @var{word-size}
+ @var{nr-rows} @var{nr-cols} [ @var{aschar} ]
+@end smallexample
+
+@noindent
+where:
+
+@table @samp
+@item @var{address}
+An expression specifying the address of the first memory word to be
+read. Complex expressions containing embedded white space should be
+quoted using the C convention.
+
+@item @var{word-format}
+The format to be used to print the memory words. The notation is the
+same as for @value{GDBN}'s @code{print} command (@pxref{Output Formats,
+,Output formats}).
+
+@item @var{word-size}
+The size of each memory word in bytes.
+
+@item @var{nr-rows}
+The number of rows in the output table.
+
+@item @var{nr-cols}
+The number of columns in the output table.
+
+@item @var{aschar}
+If present, indicates that each row should include an @sc{ascii} dump. The
+value of @var{aschar} is used as a padding character when a byte is not a
+member of the printable @sc{ascii} character set (printable @sc{ascii}
+characters are those whose code is between 32 and 126, inclusively).
+
+@item @var{byte-offset}
+An offset to add to the @var{address} before fetching memory.
+@end table
+
+This command displays memory contents as a table of @var{nr-rows} by
+@var{nr-cols} words, each word being @var{word-size} bytes. In total,
+@code{@var{nr-rows} * @var{nr-cols} * @var{word-size}} bytes are read
+(returned as @samp{total-bytes}). Should less than the requested number
+of bytes be returned by the target, the missing words are identified
+using @samp{N/A}. The number of bytes read from the target is returned
+in @samp{nr-bytes} and the starting address used to read memory in
+@samp{addr}.
+
+The address of the next/previous row or page is available in
+@samp{next-row} and @samp{prev-row}, @samp{next-page} and
+@samp{prev-page}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{x}. @code{gdbtk} has
+@samp{gdb_get_mem} memory read command.
+
+@subsubheading Example
+
+Read six bytes of memory starting at @code{bytes+6} but then offset by
+@code{-6} bytes. Format as three rows of two columns. One byte per
+word. Display each word in hex.
+
+@smallexample
+(@value{GDBP})
+9-data-read-memory -o -6 -- bytes+6 x 1 3 2
+9^done,addr="0x00001390",nr-bytes="6",total-bytes="6",
+next-row="0x00001396",prev-row="0x0000138e",next-page="0x00001396",
+prev-page="0x0000138a",memory=[
+@{addr="0x00001390",data=["0x00","0x01"]@},
+@{addr="0x00001392",data=["0x02","0x03"]@},
+@{addr="0x00001394",data=["0x04","0x05"]@}]
+(@value{GDBP})
+@end smallexample
+
+Read two bytes of memory starting at address @code{shorts + 64} and
+display as a single word formatted in decimal.
+
+@smallexample
+(@value{GDBP})
+5-data-read-memory shorts+64 d 2 1 1
+5^done,addr="0x00001510",nr-bytes="2",total-bytes="2",
+next-row="0x00001512",prev-row="0x0000150e",
+next-page="0x00001512",prev-page="0x0000150e",memory=[
+@{addr="0x00001510",data=["128"]@}]
+(@value{GDBP})
+@end smallexample
+
+Read thirty two bytes of memory starting at @code{bytes+16} and format
+as eight rows of four columns. Include a string encoding with @samp{x}
+used as the non-printable character.
+
+@smallexample
+(@value{GDBP})
+4-data-read-memory bytes+16 x 1 8 4 x
+4^done,addr="0x000013a0",nr-bytes="32",total-bytes="32",
+next-row="0x000013c0",prev-row="0x0000139c",
+next-page="0x000013c0",prev-page="0x00001380",memory=[
+@{addr="0x000013a0",data=["0x10","0x11","0x12","0x13"],ascii="xxxx"@},
+@{addr="0x000013a4",data=["0x14","0x15","0x16","0x17"],ascii="xxxx"@},
+@{addr="0x000013a8",data=["0x18","0x19","0x1a","0x1b"],ascii="xxxx"@},
+@{addr="0x000013ac",data=["0x1c","0x1d","0x1e","0x1f"],ascii="xxxx"@},
+@{addr="0x000013b0",data=["0x20","0x21","0x22","0x23"],ascii=" !\"#"@},
+@{addr="0x000013b4",data=["0x24","0x25","0x26","0x27"],ascii="$%&'"@},
+@{addr="0x000013b8",data=["0x28","0x29","0x2a","0x2b"],ascii="()*+"@},
+@{addr="0x000013bc",data=["0x2c","0x2d","0x2e","0x2f"],ascii=",-./"@}]
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-display-delete} Command
+@findex -display-delete
+
+@subsubheading Synopsis
+
+@smallexample
+ -display-delete @var{number}
+@end smallexample
+
+Delete the display @var{number}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{delete display}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-display-disable} Command
+@findex -display-disable
+
+@subsubheading Synopsis
+
+@smallexample
+ -display-disable @var{number}
+@end smallexample
+
+Disable display @var{number}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{disable display}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-display-enable} Command
+@findex -display-enable
+
+@subsubheading Synopsis
+
+@smallexample
+ -display-enable @var{number}
+@end smallexample
+
+Enable display @var{number}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{enable display}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-display-insert} Command
+@findex -display-insert
+
+@subsubheading Synopsis
+
+@smallexample
+ -display-insert @var{expression}
+@end smallexample
+
+Display @var{expression} every time the program stops.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{display}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-display-list} Command
+@findex -display-list
+
+@subsubheading Synopsis
+
+@smallexample
+ -display-list
+@end smallexample
+
+List the displays. Do not show the current values.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info display}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-environment-cd} Command
+@findex -environment-cd
+
+@subsubheading Synopsis
+
+@smallexample
+ -environment-cd @var{pathdir}
+@end smallexample
+
+Set @value{GDBN}'s working directory.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{cd}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-environment-cd /kwikemart/marge/ezannoni/flathead-dev/devo/gdb
+^done
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-environment-directory} Command
+@findex -environment-directory
+
+@subsubheading Synopsis
+
+@smallexample
+ -environment-directory [ -r ] [ @var{pathdir} ]+
+@end smallexample
+
+Add directories @var{pathdir} to beginning of search path for source files.
+If the @samp{-r} option is used, the search path is reset to the default
+search path. If directories @var{pathdir} are supplied in addition to the
+@samp{-r} option, the search path is first reset and then addition
+occurs as normal.
+Multiple directories may be specified, separated by blanks. Specifying
+multiple directories in a single command
+results in the directories added to the beginning of the
+search path in the same order they were presented in the command.
+If blanks are needed as
+part of a directory name, double-quotes should be used around
+the name. In the command output, the path will show up separated
+by the system directory-separator character. The directory-seperator
+character must not be used
+in any directory name.
+If no directories are specified, the current search path is displayed.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{dir}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-environment-directory /kwikemart/marge/ezannoni/flathead-dev/devo/gdb
+^done,source-path="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb:$cdir:$cwd"
+(@value{GDBP})
+-environment-directory ""
+^done,source-path="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb:$cdir:$cwd"
+(@value{GDBP})
+-environment-directory -r /home/jjohnstn/src/gdb /usr/src
+^done,source-path="/home/jjohnstn/src/gdb:/usr/src:$cdir:$cwd"
+(@value{GDBP})
+-environment-directory -r
+^done,source-path="$cdir:$cwd"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-environment-path} Command
+@findex -environment-path
+
+@subsubheading Synopsis
+
+@smallexample
+ -environment-path [ -r ] [ @var{pathdir} ]+
+@end smallexample
+
+Add directories @var{pathdir} to beginning of search path for object files.
+If the @samp{-r} option is used, the search path is reset to the original
+search path that existed at gdb start-up. If directories @var{pathdir} are
+supplied in addition to the
+@samp{-r} option, the search path is first reset and then addition
+occurs as normal.
+Multiple directories may be specified, separated by blanks. Specifying
+multiple directories in a single command
+results in the directories added to the beginning of the
+search path in the same order they were presented in the command.
+If blanks are needed as
+part of a directory name, double-quotes should be used around
+the name. In the command output, the path will show up separated
+by the system directory-separator character. The directory-seperator
+character must not be used
+in any directory name.
+If no directories are specified, the current path is displayed.
+
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{path}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-environment-path
+^done,path="/usr/bin"
+(@value{GDBP})
+-environment-path /kwikemart/marge/ezannoni/flathead-dev/ppc-eabi/gdb /bin
+^done,path="/kwikemart/marge/ezannoni/flathead-dev/ppc-eabi/gdb:/bin:/usr/bin"
+(@value{GDBP})
+-environment-path -r /usr/local/bin
+^done,path="/usr/local/bin:/usr/bin"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-environment-pwd} Command
+@findex -environment-pwd
+
+@subsubheading Synopsis
+
+@smallexample
+ -environment-pwd
+@end smallexample
+
+Show the current working directory.
+
+@subsubheading @value{GDBN} command
+
+The corresponding @value{GDBN} command is @samp{pwd}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-environment-pwd
+^done,cwd="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb"
+(@value{GDBP})
+@end smallexample
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Program Control
+@section @sc{gdb/mi} Program control
+
+@subsubheading Program termination
+
+As a result of execution, the inferior program can run to completion, if
+it doesn't encounter any breakpoints. In this case the output will
+include an exit code, if the program has exited exceptionally.
+
+@subsubheading Examples
+
+@noindent
+Program exited normally:
+
+@smallexample
+(@value{GDBP})
+-exec-run
+^running
+(@value{GDBP})
+x = 55
+*stopped,reason="exited-normally"
+(@value{GDBP})
+@end smallexample
+
+@noindent
+Program exited exceptionally:
+
+@smallexample
+(@value{GDBP})
+-exec-run
+^running
+(@value{GDBP})
+x = 55
+*stopped,reason="exited",exit-code="01"
+(@value{GDBP})
+@end smallexample
+
+Another way the program can terminate is if it receives a signal such as
+@code{SIGINT}. In this case, @sc{gdb/mi} displays this:
+
+@smallexample
+(@value{GDBP})
+*stopped,reason="exited-signalled",signal-name="SIGINT",
+signal-meaning="Interrupt"
+@end smallexample
+
+
+@subheading The @code{-exec-abort} Command
+@findex -exec-abort
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-abort
+@end smallexample
+
+Kill the inferior running program.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{kill}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-exec-arguments} Command
+@findex -exec-arguments
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-arguments @var{args}
+@end smallexample
+
+Set the inferior program arguments, to be used in the next
+@samp{-exec-run}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{set args}.
+
+@subsubheading Example
+
+@c FIXME!
+Don't have one around.
+
+
+@subheading The @code{-exec-continue} Command
+@findex -exec-continue
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-continue
+@end smallexample
+
+Asynchronous command. Resumes the execution of the inferior program
+until a breakpoint is encountered, or until the inferior exits.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} corresponding is @samp{continue}.
+
+@subsubheading Example
+
+@smallexample
+-exec-continue
+^running
+(@value{GDBP})
+@@Hello world
+*stopped,reason="breakpoint-hit",bkptno="2",frame=@{func="foo",args=[],
+file="hello.c",line="13"@}
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-finish} Command
+@findex -exec-finish
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-finish
+@end smallexample
+
+Asynchronous command. Resumes the execution of the inferior program
+until the current function is exited. Displays the results returned by
+the function.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{finish}.
+
+@subsubheading Example
+
+Function returning @code{void}.
+
+@smallexample
+-exec-finish
+^running
+(@value{GDBP})
+@@hello from foo
+*stopped,reason="function-finished",frame=@{func="main",args=[],
+file="hello.c",line="7"@}
+(@value{GDBP})
+@end smallexample
+
+Function returning other than @code{void}. The name of the internal
+@value{GDBN} variable storing the result is printed, together with the
+value itself.
+
+@smallexample
+-exec-finish
+^running
+(@value{GDBP})
+*stopped,reason="function-finished",frame=@{addr="0x000107b0",func="foo",
+args=[@{name="a",value="1"],@{name="b",value="9"@}@},
+file="recursive2.c",line="14"@},
+gdb-result-var="$1",return-value="0"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-interrupt} Command
+@findex -exec-interrupt
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-interrupt
+@end smallexample
+
+Asynchronous command. Interrupts the background execution of the target.
+Note how the token associated with the stop message is the one for the
+execution command that has been interrupted. The token for the interrupt
+itself only appears in the @samp{^done} output. If the user is trying to
+interrupt a non-running program, an error message will be printed.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{interrupt}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+111-exec-continue
+111^running
+
+(@value{GDBP})
+222-exec-interrupt
+222^done
+(@value{GDBP})
+111*stopped,signal-name="SIGINT",signal-meaning="Interrupt",
+frame=@{addr="0x00010140",func="foo",args=[],file="try.c",line="13"@}
+(@value{GDBP})
+
+(@value{GDBP})
+-exec-interrupt
+^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-next} Command
+@findex -exec-next
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-next
+@end smallexample
+
+Asynchronous command. Resumes execution of the inferior program, stopping
+when the beginning of the next source line is reached.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{next}.
+
+@subsubheading Example
+
+@smallexample
+-exec-next
+^running
+(@value{GDBP})
+*stopped,reason="end-stepping-range",line="8",file="hello.c"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-next-instruction} Command
+@findex -exec-next-instruction
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-next-instruction
+@end smallexample
+
+Asynchronous command. Executes one machine instruction. If the
+instruction is a function call continues until the function returns. If
+the program stops at an instruction in the middle of a source line, the
+address will be printed as well.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{nexti}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-exec-next-instruction
+^running
+
+(@value{GDBP})
+*stopped,reason="end-stepping-range",
+addr="0x000100d4",line="5",file="hello.c"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-return} Command
+@findex -exec-return
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-return
+@end smallexample
+
+Makes current function return immediately. Doesn't execute the inferior.
+Displays the new current frame.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{return}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+200-break-insert callee4
+200^done,bkpt=@{number="1",addr="0x00010734",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8"@}
+(@value{GDBP})
+000-exec-run
+000^running
+(@value{GDBP})
+000*stopped,reason="breakpoint-hit",bkptno="1",
+frame=@{func="callee4",args=[],
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8"@}
+(@value{GDBP})
+205-break-delete
+205^done
+(@value{GDBP})
+111-exec-return
+111^done,frame=@{level="0",func="callee3",
+args=[@{name="strarg",
+value="0x11940 \"A string argument.\""@}],
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="18"@}
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-run} Command
+@findex -exec-run
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-run
+@end smallexample
+
+Asynchronous command. Starts execution of the inferior from the
+beginning. The inferior executes until either a breakpoint is
+encountered or the program exits.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{run}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-break-insert main
+^done,bkpt=@{number="1",addr="0x0001072c",file="recursive2.c",line="4"@}
+(@value{GDBP})
+-exec-run
+^running
+(@value{GDBP})
+*stopped,reason="breakpoint-hit",bkptno="1",
+frame=@{func="main",args=[],file="recursive2.c",line="4"@}
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-show-arguments} Command
+@findex -exec-show-arguments
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-show-arguments
+@end smallexample
+
+Print the arguments of the program.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{show args}.
+
+@subsubheading Example
+N.A.
+
+@c @subheading -exec-signal
+
+@subheading The @code{-exec-step} Command
+@findex -exec-step
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-step
+@end smallexample
+
+Asynchronous command. Resumes execution of the inferior program, stopping
+when the beginning of the next source line is reached, if the next
+source line is not a function call. If it is, stop at the first
+instruction of the called function.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{step}.
+
+@subsubheading Example
+
+Stepping into a function:
+
+@smallexample
+-exec-step
+^running
+(@value{GDBP})
+*stopped,reason="end-stepping-range",
+frame=@{func="foo",args=[@{name="a",value="10"@},
+@{name="b",value="0"@}],file="recursive2.c",line="11"@}
+(@value{GDBP})
+@end smallexample
+
+Regular stepping:
+
+@smallexample
+-exec-step
+^running
+(@value{GDBP})
+*stopped,reason="end-stepping-range",line="14",file="recursive2.c"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-step-instruction} Command
+@findex -exec-step-instruction
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-step-instruction
+@end smallexample
+
+Asynchronous command. Resumes the inferior which executes one machine
+instruction. The output, once @value{GDBN} has stopped, will vary depending on
+whether we have stopped in the middle of a source line or not. In the
+former case, the address at which the program stopped will be printed as
+well.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{stepi}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-exec-step-instruction
+^running
+
+(@value{GDBP})
+*stopped,reason="end-stepping-range",
+frame=@{func="foo",args=[],file="try.c",line="10"@}
+(@value{GDBP})
+-exec-step-instruction
+^running
+
+(@value{GDBP})
+*stopped,reason="end-stepping-range",
+frame=@{addr="0x000100f4",func="foo",args=[],file="try.c",line="10"@}
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-exec-until} Command
+@findex -exec-until
+
+@subsubheading Synopsis
+
+@smallexample
+ -exec-until [ @var{location} ]
+@end smallexample
+
+Asynchronous command. Executes the inferior until the @var{location}
+specified in the argument is reached. If there is no argument, the inferior
+executes until a source line greater than the current one is reached.
+The reason for stopping in this case will be @samp{location-reached}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{until}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-exec-until recursive2.c:6
+^running
+(@value{GDBP})
+x = 55
+*stopped,reason="location-reached",frame=@{func="main",args=[],
+file="recursive2.c",line="6"@}
+(@value{GDBP})
+@end smallexample
+
+@ignore
+@subheading -file-clear
+Is this going away????
+@end ignore
+
+
+@subheading The @code{-file-exec-and-symbols} Command
+@findex -file-exec-and-symbols
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-exec-and-symbols @var{file}
+@end smallexample
+
+Specify the executable file to be debugged. This file is the one from
+which the symbol table is also read. If no file is specified, the
+command clears the executable and symbol information. If breakpoints
+are set when using this command with no arguments, @value{GDBN} will produce
+error messages. Otherwise, no output is produced, except a completion
+notification.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{file}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-file-exec-and-symbols /kwikemart/marge/ezannoni/TRUNK/mbx/hello.mbx
+^done
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-file-exec-file} Command
+@findex -file-exec-file
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-exec-file @var{file}
+@end smallexample
+
+Specify the executable file to be debugged. Unlike
+@samp{-file-exec-and-symbols}, the symbol table is @emph{not} read
+from this file. If used without argument, @value{GDBN} clears the information
+about the executable file. No output is produced, except a completion
+notification.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{exec-file}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-file-exec-file /kwikemart/marge/ezannoni/TRUNK/mbx/hello.mbx
+^done
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-file-list-exec-sections} Command
+@findex -file-list-exec-sections
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-list-exec-sections
+@end smallexample
+
+List the sections of the current executable file.
+
+@subsubheading @value{GDBN} Command
+
+The @value{GDBN} command @samp{info file} shows, among the rest, the same
+information as this command. @code{gdbtk} has a corresponding command
+@samp{gdb_load_info}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-file-list-exec-source-file} Command
+@findex -file-list-exec-source-file
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-list-exec-source-file
+@end smallexample
+
+List the line number, the current source file, and the absolute path
+to the current source file for the current executable.
+
+@subsubheading @value{GDBN} Command
+
+There's no @value{GDBN} command which directly corresponds to this one.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+123-file-list-exec-source-file
+123^done,line="1",file="foo.c",fullname="/home/bar/foo.c"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-file-list-exec-source-files} Command
+@findex -file-list-exec-source-files
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-list-exec-source-files
+@end smallexample
+
+List the source files for the current executable.
+
+@subsubheading @value{GDBN} Command
+
+There's no @value{GDBN} command which directly corresponds to this one.
+@code{gdbtk} has an analogous command @samp{gdb_listfiles}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-file-list-shared-libraries} Command
+@findex -file-list-shared-libraries
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-list-shared-libraries
+@end smallexample
+
+List the shared libraries in the program.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info shared}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-file-list-symbol-files} Command
+@findex -file-list-symbol-files
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-list-symbol-files
+@end smallexample
+
+List symbol files.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info file} (part of it).
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-file-symbol-file} Command
+@findex -file-symbol-file
+
+@subsubheading Synopsis
+
+@smallexample
+ -file-symbol-file @var{file}
+@end smallexample
+
+Read symbol table info from the specified @var{file} argument. When
+used without arguments, clears @value{GDBN}'s symbol table info. No output is
+produced, except for a completion notification.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{symbol-file}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-file-symbol-file /kwikemart/marge/ezannoni/TRUNK/mbx/hello.mbx
+^done
+(@value{GDBP})
+@end smallexample
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Miscellaneous Commands
+@section Miscellaneous @value{GDBN} commands in @sc{gdb/mi}
+
+@c @subheading -gdb-complete
+
+@subheading The @code{-gdb-exit} Command
+@findex -gdb-exit
+
+@subsubheading Synopsis
+
+@smallexample
+ -gdb-exit
+@end smallexample
+
+Exit @value{GDBN} immediately.
+
+@subsubheading @value{GDBN} Command
+
+Approximately corresponds to @samp{quit}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-gdb-exit
+@end smallexample
+
+@subheading The @code{-gdb-set} Command
+@findex -gdb-set
+
+@subsubheading Synopsis
+
+@smallexample
+ -gdb-set
+@end smallexample
+
+Set an internal @value{GDBN} variable.
+@c IS THIS A DOLLAR VARIABLE? OR SOMETHING LIKE ANNOTATE ?????
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{set}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-gdb-set $foo=3
+^done
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-gdb-show} Command
+@findex -gdb-show
+
+@subsubheading Synopsis
+
+@smallexample
+ -gdb-show
+@end smallexample
+
+Show the current value of a @value{GDBN} variable.
+
+@subsubheading @value{GDBN} command
+
+The corresponding @value{GDBN} command is @samp{show}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-gdb-show annotate
+^done,value="0"
+(@value{GDBP})
+@end smallexample
+
+@c @subheading -gdb-source
+
+
+@subheading The @code{-gdb-version} Command
+@findex -gdb-version
+
+@subsubheading Synopsis
+
+@smallexample
+ -gdb-version
+@end smallexample
+
+Show version information for @value{GDBN}. Used mostly in testing.
+
+@subsubheading @value{GDBN} Command
+
+There's no equivalent @value{GDBN} command. @value{GDBN} by default shows this
+information when you start an interactive session.
+
+@subsubheading Example
+
+@c This example modifies the actual output from GDB to avoid overfull
+@c box in TeX.
+@smallexample
+(@value{GDBP})
+-gdb-version
+~GNU gdb 5.2.1
+~Copyright 2000 Free Software Foundation, Inc.
+~GDB is free software, covered by the GNU General Public License, and
+~you are welcome to change it and/or 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.
+~This GDB was configured as
+ "--host=sparc-sun-solaris2.5.1 --target=ppc-eabi".
+^done
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-interpreter-exec} Command
+@findex -interpreter-exec
+
+@subheading Synopsis
+
+@smallexample
+-interpreter-exec @var{interpreter} @var{command}
+@end smallexample
+
+Execute the specified @var{command} in the given @var{interpreter}.
+
+@subheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{interpreter-exec}.
+
+@subheading Example
+
+@smallexample
+(@value{GDBP})
+-interpreter-exec console "break main"
+&"During symbol reading, couldn't parse type; debugger out of date?.\n"
+&"During symbol reading, bad structure-type format.\n"
+~"Breakpoint 1 at 0x8074fc6: file ../../src/gdb/main.c, line 743.\n"
+^done
+(@value{GDBP})
+@end smallexample
+
+@ignore
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Kod Commands
+@section @sc{gdb/mi} Kod Commands
+
+The Kod commands are not implemented.
+
+@c @subheading -kod-info
+
+@c @subheading -kod-list
+
+@c @subheading -kod-list-object-types
+
+@c @subheading -kod-show
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Memory Overlay Commands
+@section @sc{gdb/mi} Memory Overlay Commands
+
+The memory overlay commands are not implemented.
+
+@c @subheading -overlay-auto
+
+@c @subheading -overlay-list-mapping-state
+
+@c @subheading -overlay-list-overlays
+
+@c @subheading -overlay-map
+
+@c @subheading -overlay-off
+
+@c @subheading -overlay-on
+
+@c @subheading -overlay-unmap
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Signal Handling Commands
+@section @sc{gdb/mi} Signal Handling Commands
+
+Signal handling commands are not implemented.
+
+@c @subheading -signal-handle
+
+@c @subheading -signal-list-handle-actions
+
+@c @subheading -signal-list-signal-types
+@end ignore
+
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Stack Manipulation
+@section @sc{gdb/mi} Stack Manipulation Commands
+
+
+@subheading The @code{-stack-info-frame} Command
+@findex -stack-info-frame
+
+@subsubheading Synopsis
+
+@smallexample
+ -stack-info-frame
+@end smallexample
+
+Get info on the current frame.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info frame} or @samp{frame}
+(without arguments).
+
+@subsubheading Example
+N.A.
+
+@subheading The @code{-stack-info-depth} Command
+@findex -stack-info-depth
+
+@subsubheading Synopsis
+
+@smallexample
+ -stack-info-depth [ @var{max-depth} ]
+@end smallexample
+
+Return the depth of the stack. If the integer argument @var{max-depth}
+is specified, do not count beyond @var{max-depth} frames.
+
+@subsubheading @value{GDBN} Command
+
+There's no equivalent @value{GDBN} command.
+
+@subsubheading Example
+
+For a stack with frame levels 0 through 11:
+
+@smallexample
+(@value{GDBP})
+-stack-info-depth
+^done,depth="12"
+(@value{GDBP})
+-stack-info-depth 4
+^done,depth="4"
+(@value{GDBP})
+-stack-info-depth 12
+^done,depth="12"
+(@value{GDBP})
+-stack-info-depth 11
+^done,depth="11"
+(@value{GDBP})
+-stack-info-depth 13
+^done,depth="12"
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-stack-list-arguments} Command
+@findex -stack-list-arguments
+
+@subsubheading Synopsis
+
+@smallexample
+ -stack-list-arguments @var{show-values}
+ [ @var{low-frame} @var{high-frame} ]
+@end smallexample
+
+Display a list of the arguments for the frames between @var{low-frame}
+and @var{high-frame} (inclusive). If @var{low-frame} and
+@var{high-frame} are not provided, list the arguments for the whole call
+stack.
+
+The @var{show-values} argument must have a value of 0 or 1. A value of
+0 means that only the names of the arguments are listed, a value of 1
+means that both names and values of the arguments are printed.
+
+@subsubheading @value{GDBN} Command
+
+@value{GDBN} does not have an equivalent command. @code{gdbtk} has a
+@samp{gdb_get_args} command which partially overlaps with the
+functionality of @samp{-stack-list-arguments}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-stack-list-frames
+^done,
+stack=[
+frame=@{level="0",addr="0x00010734",func="callee4",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="8"@},
+frame=@{level="1",addr="0x0001076c",func="callee3",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="17"@},
+frame=@{level="2",addr="0x0001078c",func="callee2",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="22"@},
+frame=@{level="3",addr="0x000107b4",func="callee1",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="27"@},
+frame=@{level="4",addr="0x000107e0",func="main",
+file="../../../devo/gdb/testsuite/gdb.mi/basics.c",line="32"@}]
+(@value{GDBP})
+-stack-list-arguments 0
+^done,
+stack-args=[
+frame=@{level="0",args=[]@},
+frame=@{level="1",args=[name="strarg"]@},
+frame=@{level="2",args=[name="intarg",name="strarg"]@},
+frame=@{level="3",args=[name="intarg",name="strarg",name="fltarg"]@},
+frame=@{level="4",args=[]@}]
+(@value{GDBP})
+-stack-list-arguments 1
+^done,
+stack-args=[
+frame=@{level="0",args=[]@},
+frame=@{level="1",
+ args=[@{name="strarg",value="0x11940 \"A string argument.\""@}]@},
+frame=@{level="2",args=[
+@{name="intarg",value="2"@},
+@{name="strarg",value="0x11940 \"A string argument.\""@}]@},
+@{frame=@{level="3",args=[
+@{name="intarg",value="2"@},
+@{name="strarg",value="0x11940 \"A string argument.\""@},
+@{name="fltarg",value="3.5"@}]@},
+frame=@{level="4",args=[]@}]
+(@value{GDBP})
+-stack-list-arguments 0 2 2
+^done,stack-args=[frame=@{level="2",args=[name="intarg",name="strarg"]@}]
+(@value{GDBP})
+-stack-list-arguments 1 2 2
+^done,stack-args=[frame=@{level="2",
+args=[@{name="intarg",value="2"@},
+@{name="strarg",value="0x11940 \"A string argument.\""@}]@}]
+(@value{GDBP})
+@end smallexample
+
+@c @subheading -stack-list-exception-handlers
+
+
+@subheading The @code{-stack-list-frames} Command
+@findex -stack-list-frames
+
+@subsubheading Synopsis
+
+@smallexample
+ -stack-list-frames [ @var{low-frame} @var{high-frame} ]
+@end smallexample
+
+List the frames currently on the stack. For each frame it displays the
+following info:
+
+@table @samp
+@item @var{level}
+The frame number, 0 being the topmost frame, i.e. the innermost function.
+@item @var{addr}
+The @code{$pc} value for that frame.
+@item @var{func}
+Function name.
+@item @var{file}
+File name of the source file where the function lives.
+@item @var{line}
+Line number corresponding to the @code{$pc}.
+@end table
+
+If invoked without arguments, this command prints a backtrace for the
+whole stack. If given two integer arguments, it shows the frames whose
+levels are between the two arguments (inclusive). If the two arguments
+are equal, it shows the single frame at the corresponding level.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{backtrace} and @samp{where}.
+
+@subsubheading Example
+
+Full stack backtrace:
+
+@smallexample
+(@value{GDBP})
+-stack-list-frames
+^done,stack=
+[frame=@{level="0",addr="0x0001076c",func="foo",
+ file="recursive2.c",line="11"@},
+frame=@{level="1",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="2",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="3",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="4",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="5",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="6",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="7",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="8",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="9",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="10",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="11",addr="0x00010738",func="main",
+ file="recursive2.c",line="4"@}]
+(@value{GDBP})
+@end smallexample
+
+Show frames between @var{low_frame} and @var{high_frame}:
+
+@smallexample
+(@value{GDBP})
+-stack-list-frames 3 5
+^done,stack=
+[frame=@{level="3",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="4",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@},
+frame=@{level="5",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@}]
+(@value{GDBP})
+@end smallexample
+
+Show a single frame:
+
+@smallexample
+(@value{GDBP})
+-stack-list-frames 3 3
+^done,stack=
+[frame=@{level="3",addr="0x000107a4",func="foo",
+ file="recursive2.c",line="14"@}]
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-stack-list-locals} Command
+@findex -stack-list-locals
+
+@subsubheading Synopsis
+
+@smallexample
+ -stack-list-locals @var{print-values}
+@end smallexample
+
+Display the local variable names for the current frame. With an
+argument of 0 or @code{--no-values}, prints only the names of the variables.
+With argument of 1 or @code{--all-values}, prints also their values. With
+argument of 2 or @code{--simple-values}, prints the name, type and value for
+simple data types and the name and type for arrays, structures and
+unions. In this last case, the idea is that the user can see the
+value of simple data types immediately and he can create variable
+objects for other data types if he wishes to explore their values in
+more detail.
+
+@subsubheading @value{GDBN} Command
+
+@samp{info locals} in @value{GDBN}, @samp{gdb_get_locals} in @code{gdbtk}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-stack-list-locals 0
+^done,locals=[name="A",name="B",name="C"]
+(@value{GDBP})
+-stack-list-locals --all-values
+^done,locals=[@{name="A",value="1"@},@{name="B",value="2"@},
+ @{name="C",value="@{1, 2, 3@}"@}]
+-stack-list-locals --simple-values
+^done,locals=[@{name="A",type="int",value="1"@},
+ @{name="B",type="int",value="2"@},@{name="C",type="int [3]"@}]
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-stack-select-frame} Command
+@findex -stack-select-frame
+
+@subsubheading Synopsis
+
+@smallexample
+ -stack-select-frame @var{framenum}
+@end smallexample
+
+Change the current frame. Select a different frame @var{framenum} on
+the stack.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{frame}, @samp{up},
+@samp{down}, @samp{select-frame}, @samp{up-silent}, and @samp{down-silent}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-stack-select-frame 2
+^done
+(@value{GDBP})
+@end smallexample
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Symbol Query
+@section @sc{gdb/mi} Symbol Query Commands
+
+
+@subheading The @code{-symbol-info-address} Command
+@findex -symbol-info-address
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-address @var{symbol}
+@end smallexample
+
+Describe where @var{symbol} is stored.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info address}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-info-file} Command
+@findex -symbol-info-file
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-file
+@end smallexample
+
+Show the file for the symbol.
+
+@subsubheading @value{GDBN} Command
+
+There's no equivalent @value{GDBN} command. @code{gdbtk} has
+@samp{gdb_find_file}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-info-function} Command
+@findex -symbol-info-function
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-function
+@end smallexample
+
+Show which function the symbol lives in.
+
+@subsubheading @value{GDBN} Command
+
+@samp{gdb_get_function} in @code{gdbtk}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-info-line} Command
+@findex -symbol-info-line
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-line
+@end smallexample
+
+Show the core addresses of the code for a source line.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info line}.
+@code{gdbtk} has the @samp{gdb_get_line} and @samp{gdb_get_file} commands.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-info-symbol} Command
+@findex -symbol-info-symbol
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-symbol @var{addr}
+@end smallexample
+
+Describe what symbol is at location @var{addr}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info symbol}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-list-functions} Command
+@findex -symbol-list-functions
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-list-functions
+@end smallexample
+
+List the functions in the executable.
+
+@subsubheading @value{GDBN} Command
+
+@samp{info functions} in @value{GDBN}, @samp{gdb_listfunc} and
+@samp{gdb_search} in @code{gdbtk}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-list-lines} Command
+@findex -symbol-list-lines
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-list-lines @var{filename}
+@end smallexample
+
+Print the list of lines that contain code and their associated program
+addresses for the given source filename. The entries are sorted in
+ascending PC order.
+
+@subsubheading @value{GDBN} Command
+
+There is no corresponding @value{GDBN} command.
+
+@subsubheading Example
+@smallexample
+(@value{GDBP})
+-symbol-list-lines basics.c
+^done,lines=[@{pc="0x08048554",line="7"@},@{pc="0x0804855a",line="8"@}]
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-symbol-list-types} Command
+@findex -symbol-list-types
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-list-types
+@end smallexample
+
+List all the type names.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding commands are @samp{info types} in @value{GDBN},
+@samp{gdb_search} in @code{gdbtk}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-list-variables} Command
+@findex -symbol-list-variables
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-list-variables
+@end smallexample
+
+List all the global and static variable names.
+
+@subsubheading @value{GDBN} Command
+
+@samp{info variables} in @value{GDBN}, @samp{gdb_search} in @code{gdbtk}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-locate} Command
+@findex -symbol-locate
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-locate
+@end smallexample
+
+@subsubheading @value{GDBN} Command
+
+@samp{gdb_loc} in @code{gdbtk}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-symbol-type} Command
+@findex -symbol-type
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-type @var{variable}
+@end smallexample
+
+Show type of @var{variable}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{ptype}, @code{gdbtk} has
+@samp{gdb_obj_variable}.
+
+@subsubheading Example
+N.A.
+
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Target Manipulation
+@section @sc{gdb/mi} Target Manipulation Commands
+
+
+@subheading The @code{-target-attach} Command
+@findex -target-attach
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-attach @var{pid} | @var{file}
+@end smallexample
+
+Attach to a process @var{pid} or a file @var{file} outside of @value{GDBN}.
+
+@subsubheading @value{GDBN} command
+
+The corresponding @value{GDBN} command is @samp{attach}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-target-compare-sections} Command
+@findex -target-compare-sections
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-compare-sections [ @var{section} ]
+@end smallexample
+
+Compare data of section @var{section} on target to the exec file.
+Without the argument, all sections are compared.
+
+@subsubheading @value{GDBN} Command
+
+The @value{GDBN} equivalent is @samp{compare-sections}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-target-detach} Command
+@findex -target-detach
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-detach
+@end smallexample
+
+Disconnect from the remote target. There's no output.
+
+@subsubheading @value{GDBN} command
+
+The corresponding @value{GDBN} command is @samp{detach}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-target-detach
+^done
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-target-disconnect} Command
+@findex -target-disconnect
+
+@subsubheading Synopsis
+
+@example
+ -target-disconnect
+@end example
+
+Disconnect from the remote target. There's no output.
+
+@subsubheading @value{GDBN} command
+
+The corresponding @value{GDBN} command is @samp{disconnect}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-target-disconnect
+^done
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-target-download} Command
+@findex -target-download
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-download
+@end smallexample
+
+Loads the executable onto the remote target.
+It prints out an update message every half second, which includes the fields:
+
+@table @samp
+@item section
+The name of the section.
+@item section-sent
+The size of what has been sent so far for that section.
+@item section-size
+The size of the section.
+@item total-sent
+The total size of what was sent so far (the current and the previous sections).
+@item total-size
+The size of the overall executable to download.
+@end table
+
+@noindent
+Each message is sent as status record (@pxref{GDB/MI Output Syntax, ,
+@sc{gdb/mi} Output Syntax}).
+
+In addition, it prints the name and size of the sections, as they are
+downloaded. These messages include the following fields:
+
+@table @samp
+@item section
+The name of the section.
+@item section-size
+The size of the section.
+@item total-size
+The size of the overall executable to download.
+@end table
+
+@noindent
+At the end, a summary is printed.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{load}.
+
+@subsubheading Example
+
+Note: each status message appears on a single line. Here the messages
+have been broken down so that they can fit onto a page.
+
+@smallexample
+(@value{GDBP})
+-target-download
++download,@{section=".text",section-size="6668",total-size="9880"@}
++download,@{section=".text",section-sent="512",section-size="6668",
+total-sent="512",total-size="9880"@}
++download,@{section=".text",section-sent="1024",section-size="6668",
+total-sent="1024",total-size="9880"@}
++download,@{section=".text",section-sent="1536",section-size="6668",
+total-sent="1536",total-size="9880"@}
++download,@{section=".text",section-sent="2048",section-size="6668",
+total-sent="2048",total-size="9880"@}
++download,@{section=".text",section-sent="2560",section-size="6668",
+total-sent="2560",total-size="9880"@}
++download,@{section=".text",section-sent="3072",section-size="6668",
+total-sent="3072",total-size="9880"@}
++download,@{section=".text",section-sent="3584",section-size="6668",
+total-sent="3584",total-size="9880"@}
++download,@{section=".text",section-sent="4096",section-size="6668",
+total-sent="4096",total-size="9880"@}
++download,@{section=".text",section-sent="4608",section-size="6668",
+total-sent="4608",total-size="9880"@}
++download,@{section=".text",section-sent="5120",section-size="6668",
+total-sent="5120",total-size="9880"@}
++download,@{section=".text",section-sent="5632",section-size="6668",
+total-sent="5632",total-size="9880"@}
++download,@{section=".text",section-sent="6144",section-size="6668",
+total-sent="6144",total-size="9880"@}
++download,@{section=".text",section-sent="6656",section-size="6668",
+total-sent="6656",total-size="9880"@}
++download,@{section=".init",section-size="28",total-size="9880"@}
++download,@{section=".fini",section-size="28",total-size="9880"@}
++download,@{section=".data",section-size="3156",total-size="9880"@}
++download,@{section=".data",section-sent="512",section-size="3156",
+total-sent="7236",total-size="9880"@}
++download,@{section=".data",section-sent="1024",section-size="3156",
+total-sent="7748",total-size="9880"@}
++download,@{section=".data",section-sent="1536",section-size="3156",
+total-sent="8260",total-size="9880"@}
++download,@{section=".data",section-sent="2048",section-size="3156",
+total-sent="8772",total-size="9880"@}
++download,@{section=".data",section-sent="2560",section-size="3156",
+total-sent="9284",total-size="9880"@}
++download,@{section=".data",section-sent="3072",section-size="3156",
+total-sent="9796",total-size="9880"@}
+^done,address="0x10004",load-size="9880",transfer-rate="6586",
+write-rate="429"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-target-exec-status} Command
+@findex -target-exec-status
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-exec-status
+@end smallexample
+
+Provide information on the state of the target (whether it is running or
+not, for instance).
+
+@subsubheading @value{GDBN} Command
+
+There's no equivalent @value{GDBN} command.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-target-list-available-targets} Command
+@findex -target-list-available-targets
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-list-available-targets
+@end smallexample
+
+List the possible targets to connect to.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{help target}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-target-list-current-targets} Command
+@findex -target-list-current-targets
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-list-current-targets
+@end smallexample
+
+Describe the current target.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding information is printed by @samp{info file} (among
+other things).
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-target-list-parameters} Command
+@findex -target-list-parameters
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-list-parameters
+@end smallexample
+
+@c ????
+
+@subsubheading @value{GDBN} Command
+
+No equivalent.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-target-select} Command
+@findex -target-select
+
+@subsubheading Synopsis
+
+@smallexample
+ -target-select @var{type} @var{parameters @dots{}}
+@end smallexample
+
+Connect @value{GDBN} to the remote target. This command takes two args:
+
+@table @samp
+@item @var{type}
+The type of target, for instance @samp{async}, @samp{remote}, etc.
+@item @var{parameters}
+Device names, host names and the like. @xref{Target Commands, ,
+Commands for managing targets}, for more details.
+@end table
+
+The output is a connection notification, followed by the address at
+which the target program is, in the following form:
+
+@smallexample
+^connected,addr="@var{address}",func="@var{function name}",
+ args=[@var{arg list}]
+@end smallexample
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{target}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-target-select async /dev/ttya
+^connected,addr="0xfe00a300",func="??",args=[]
+(@value{GDBP})
+@end smallexample
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Thread Commands
+@section @sc{gdb/mi} Thread Commands
+
+
+@subheading The @code{-thread-info} Command
+@findex -thread-info
+
+@subsubheading Synopsis
+
+@smallexample
+ -thread-info
+@end smallexample
+
+@subsubheading @value{GDBN} command
+
+No equivalent.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-thread-list-all-threads} Command
+@findex -thread-list-all-threads
+
+@subsubheading Synopsis
+
+@smallexample
+ -thread-list-all-threads
+@end smallexample
+
+@subsubheading @value{GDBN} Command
+
+The equivalent @value{GDBN} command is @samp{info threads}.
+
+@subsubheading Example
+N.A.
+
+
+@subheading The @code{-thread-list-ids} Command
+@findex -thread-list-ids
+
+@subsubheading Synopsis
+
+@smallexample
+ -thread-list-ids
+@end smallexample
+
+Produces a list of the currently known @value{GDBN} thread ids. At the
+end of the list it also prints the total number of such threads.
+
+@subsubheading @value{GDBN} Command
+
+Part of @samp{info threads} supplies the same information.
+
+@subsubheading Example
+
+No threads present, besides the main process:
+
+@smallexample
+(@value{GDBP})
+-thread-list-ids
+^done,thread-ids=@{@},number-of-threads="0"
+(@value{GDBP})
+@end smallexample
+
+
+Several threads:
+
+@smallexample
+(@value{GDBP})
+-thread-list-ids
+^done,thread-ids=@{thread-id="3",thread-id="2",thread-id="1"@},
+number-of-threads="3"
+(@value{GDBP})
+@end smallexample
+
+
+@subheading The @code{-thread-select} Command
+@findex -thread-select
+
+@subsubheading Synopsis
+
+@smallexample
+ -thread-select @var{threadnum}
+@end smallexample
+
+Make @var{threadnum} the current thread. It prints the number of the new
+current thread, and the topmost frame for that thread.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{thread}.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-exec-next
+^running
+(@value{GDBP})
+*stopped,reason="end-stepping-range",thread-id="2",line="187",
+file="../../../devo/gdb/testsuite/gdb.threads/linux-dp.c"
+(@value{GDBP})
+-thread-list-ids
+^done,
+thread-ids=@{thread-id="3",thread-id="2",thread-id="1"@},
+number-of-threads="3"
+(@value{GDBP})
+-thread-select 3
+^done,new-thread-id="3",
+frame=@{level="0",func="vprintf",
+args=[@{name="format",value="0x8048e9c \"%*s%c %d %c\\n\""@},
+@{name="arg",value="0x2"@}],file="vprintf.c",line="31"@}
+(@value{GDBP})
+@end smallexample
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Tracepoint Commands
+@section @sc{gdb/mi} Tracepoint Commands
+
+The tracepoint commands are not yet implemented.
+
+@c @subheading -trace-actions
+
+@c @subheading -trace-delete
+
+@c @subheading -trace-disable
+
+@c @subheading -trace-dump
+
+@c @subheading -trace-enable
+
+@c @subheading -trace-exists
+
+@c @subheading -trace-find
+
+@c @subheading -trace-frame-number
+
+@c @subheading -trace-info
+
+@c @subheading -trace-insert
+
+@c @subheading -trace-list
+
+@c @subheading -trace-pass-count
+
+@c @subheading -trace-save
+
+@c @subheading -trace-start
+
+@c @subheading -trace-stop
+
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Variable Objects
+@section @sc{gdb/mi} Variable Objects
+
+
+@subheading Motivation for Variable Objects in @sc{gdb/mi}
+
+For the implementation of a variable debugger window (locals, watched
+expressions, etc.), we are proposing the adaptation of the existing code
+used by @code{Insight}.
+
+The two main reasons for that are:
+
+@enumerate 1
+@item
+It has been proven in practice (it is already on its second generation).
+
+@item
+It will shorten development time (needless to say how important it is
+now).
+@end enumerate
+
+The original interface was designed to be used by Tcl code, so it was
+slightly changed so it could be used through @sc{gdb/mi}. This section
+describes the @sc{gdb/mi} operations that will be available and gives some
+hints about their use.
+
+@emph{Note}: In addition to the set of operations described here, we
+expect the @sc{gui} implementation of a variable window to require, at
+least, the following operations:
+
+@itemize @bullet
+@item @code{-gdb-show} @code{output-radix}
+@item @code{-stack-list-arguments}
+@item @code{-stack-list-locals}
+@item @code{-stack-select-frame}
+@end itemize
+
+@subheading Introduction to Variable Objects in @sc{gdb/mi}
+
+@cindex variable objects in @sc{gdb/mi}
+The basic idea behind variable objects is the creation of a named object
+to represent a variable, an expression, a memory location or even a CPU
+register. For each object created, a set of operations is available for
+examining or changing its properties.
+
+Furthermore, complex data types, such as C structures, are represented
+in a tree format. For instance, the @code{struct} type variable is the
+root and the children will represent the struct members. If a child
+is itself of a complex type, it will also have children of its own.
+Appropriate language differences are handled for C, C@t{++} and Java.
+
+When returning the actual values of the objects, this facility allows
+for the individual selection of the display format used in the result
+creation. It can be chosen among: binary, decimal, hexadecimal, octal
+and natural. Natural refers to a default format automatically
+chosen based on the variable type (like decimal for an @code{int}, hex
+for pointers, etc.).
+
+The following is the complete set of @sc{gdb/mi} operations defined to
+access this functionality:
+
+@multitable @columnfractions .4 .6
+@item @strong{Operation}
+@tab @strong{Description}
+
+@item @code{-var-create}
+@tab create a variable object
+@item @code{-var-delete}
+@tab delete the variable object and its children
+@item @code{-var-set-format}
+@tab set the display format of this variable
+@item @code{-var-show-format}
+@tab show the display format of this variable
+@item @code{-var-info-num-children}
+@tab tells how many children this object has
+@item @code{-var-list-children}
+@tab return a list of the object's children
+@item @code{-var-info-type}
+@tab show the type of this variable object
+@item @code{-var-info-expression}
+@tab print what this variable object represents
+@item @code{-var-show-attributes}
+@tab is this variable editable? does it exist here?
+@item @code{-var-evaluate-expression}
+@tab get the value of this variable
+@item @code{-var-assign}
+@tab set the value of this variable
+@item @code{-var-update}
+@tab update the variable and its children
+@end multitable
+
+In the next subsection we describe each operation in detail and suggest
+how it can be used.
+
+@subheading Description And Use of Operations on Variable Objects
+
+@subheading The @code{-var-create} Command
+@findex -var-create
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-create @{@var{name} | "-"@}
+ @{@var{frame-addr} | "*"@} @var{expression}
+@end smallexample
+
+This operation creates a variable object, which allows the monitoring of
+a variable, the result of an expression, a memory cell or a CPU
+register.
+
+The @var{name} parameter is the string by which the object can be
+referenced. It must be unique. If @samp{-} is specified, the varobj
+system will generate a string ``varNNNNNN'' automatically. It will be
+unique provided that one does not specify @var{name} on that format.
+The command fails if a duplicate name is found.
+
+The frame under which the expression should be evaluated can be
+specified by @var{frame-addr}. A @samp{*} indicates that the current
+frame should be used.
+
+@var{expression} is any expression valid on the current language set (must not
+begin with a @samp{*}), or one of the following:
+
+@itemize @bullet
+@item
+@samp{*@var{addr}}, where @var{addr} is the address of a memory cell
+
+@item
+@samp{*@var{addr}-@var{addr}} --- a memory address range (TBD)
+
+@item
+@samp{$@var{regname}} --- a CPU register name
+@end itemize
+
+@subsubheading Result
+
+This operation returns the name, number of children and the type of the
+object created. Type is returned as a string as the ones generated by
+the @value{GDBN} CLI:
+
+@smallexample
+ name="@var{name}",numchild="N",type="@var{type}"
+@end smallexample
+
+
+@subheading The @code{-var-delete} Command
+@findex -var-delete
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-delete @var{name}
+@end smallexample
+
+Deletes a previously created variable object and all of its children.
+
+Returns an error if the object @var{name} is not found.
+
+
+@subheading The @code{-var-set-format} Command
+@findex -var-set-format
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-set-format @var{name} @var{format-spec}
+@end smallexample
+
+Sets the output format for the value of the object @var{name} to be
+@var{format-spec}.
+
+The syntax for the @var{format-spec} is as follows:
+
+@smallexample
+ @var{format-spec} @expansion{}
+ @{binary | decimal | hexadecimal | octal | natural@}
+@end smallexample
+
+
+@subheading The @code{-var-show-format} Command
+@findex -var-show-format
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-show-format @var{name}
+@end smallexample
+
+Returns the format used to display the value of the object @var{name}.
+
+@smallexample
+ @var{format} @expansion{}
+ @var{format-spec}
+@end smallexample
+
+
+@subheading The @code{-var-info-num-children} Command
+@findex -var-info-num-children
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-info-num-children @var{name}
+@end smallexample
+
+Returns the number of children of a variable object @var{name}:
+
+@smallexample
+ numchild=@var{n}
+@end smallexample
+
+
+@subheading The @code{-var-list-children} Command
+@findex -var-list-children
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-list-children [@var{print-values}] @var{name}
+@end smallexample
+
+Returns a list of the children of the specified variable object. With
+just the variable object name as an argument or with an optional
+preceding argument of 0 or @code{--no-values}, prints only the names of the
+variables. With an optional preceding argument of 1 or @code{--all-values},
+also prints their values.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+ -var-list-children n
+ numchild=@var{n},children=[@{name=@var{name},
+ numchild=@var{n},type=@var{type}@},@r{(repeats N times)}]
+(@value{GDBP})
+ -var-list-children --all-values n
+ numchild=@var{n},children=[@{name=@var{name},
+ numchild=@var{n},value=@var{value},type=@var{type}@},@r{(repeats N times)}]
+@end smallexample
+
+
+@subheading The @code{-var-info-type} Command
+@findex -var-info-type
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-info-type @var{name}
+@end smallexample
+
+Returns the type of the specified variable @var{name}. The type is
+returned as a string in the same format as it is output by the
+@value{GDBN} CLI:
+
+@smallexample
+ type=@var{typename}
+@end smallexample
+
+
+@subheading The @code{-var-info-expression} Command
+@findex -var-info-expression
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-info-expression @var{name}
+@end smallexample
+
+Returns what is represented by the variable object @var{name}:
+
+@smallexample
+ lang=@var{lang-spec},exp=@var{expression}
+@end smallexample
+
+@noindent
+where @var{lang-spec} is @code{@{"C" | "C++" | "Java"@}}.
+
+@subheading The @code{-var-show-attributes} Command
+@findex -var-show-attributes
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-show-attributes @var{name}
+@end smallexample
+
+List attributes of the specified variable object @var{name}:
+
+@smallexample
+ status=@var{attr} [ ( ,@var{attr} )* ]
+@end smallexample
+
+@noindent
+where @var{attr} is @code{@{ @{ editable | noneditable @} | TBD @}}.
+
+@subheading The @code{-var-evaluate-expression} Command
+@findex -var-evaluate-expression
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-evaluate-expression @var{name}
+@end smallexample
+
+Evaluates the expression that is represented by the specified variable
+object and returns its value as a string in the current format specified
+for the object:
+
+@smallexample
+ value=@var{value}
+@end smallexample
+
+Note that one must invoke @code{-var-list-children} for a variable
+before the value of a child variable can be evaluated.
+
+@subheading The @code{-var-assign} Command
+@findex -var-assign
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-assign @var{name} @var{expression}
+@end smallexample
+
+Assigns the value of @var{expression} to the variable object specified
+by @var{name}. The object must be @samp{editable}. If the variable's
+value is altered by the assign, the variable will show up in any
+subsequent @code{-var-update} list.
+
+@subsubheading Example
+
+@smallexample
+(@value{GDBP})
+-var-assign var1 3
+^done,value="3"
+(@value{GDBP})
+-var-update *
+^done,changelist=[@{name="var1",in_scope="true",type_changed="false"@}]
+(@value{GDBP})
+@end smallexample
+
+@subheading The @code{-var-update} Command
+@findex -var-update
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-update @{@var{name} | "*"@}
+@end smallexample
+
+Update the value of the variable object @var{name} by evaluating its
+expression after fetching all the new values from memory or registers.
+A @samp{*} causes all existing variable objects to be updated.
+
+
+@node Annotations
+@chapter @value{GDBN} Annotations
+
+This chapter describes annotations in @value{GDBN}. Annotations were
+designed to interface @value{GDBN} to graphical user interfaces or other
+similar programs which want to interact with @value{GDBN} at a
+relatively high level.
+
+The annotation mechanism has largely been superseeded by @sc{gdb/mi}
+(@pxref{GDB/MI}).
+
+@ignore
+This is Edition @value{EDITION}, @value{DATE}.
+@end ignore
+
+@menu
+* Annotations Overview:: What annotations are; the general syntax.
+* Server Prefix:: Issuing a command without affecting user state.
+* Prompting:: Annotations marking @value{GDBN}'s need for input.
+* Errors:: Annotations for error messages.
+* Invalidation:: Some annotations describe things now invalid.
+* Annotations for Running::
+ Whether the program is running, how it stopped, etc.
+* Source Annotations:: Annotations describing source code.
+@end menu
+
+@node Annotations Overview
+@section What is an Annotation?
+@cindex annotations
+
+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 @value{GDBN}. Currently there is
+no need for @value{GDBN} 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.
+
+The annotation @var{level}, which is specified using the
+@option{--annotate} command line option (@pxref{Mode Options}), controls
+how much information @value{GDBN} prints together with its prompt,
+values of expressions, source lines, and other types of output. Level 0
+is for no anntations, level 1 is for use when @value{GDBN} is run as a
+subprocess of @sc{gnu} Emacs, level 3 is the maximum annotation suitable
+for programs that control @value{GDBN}, and level 2 annotations have
+been made obsolete (@pxref{Limitations, , Limitations of the Annotation
+Interface, annotate, GDB's Obsolete Annotations}). This chapter
+describes level 3 annotations.
+
+A simple example of starting up @value{GDBN} with annotations is:
+
+@smallexample
+$ @kbd{gdb --annotate=3}
+GNU gdb 6.0
+Copyright 2003 Free Software Foundation, Inc.
+GDB is free software, covered by the GNU General Public License,
+and you are welcome to change it and/or 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.
+This GDB was configured as "i386-pc-linux-gnu"
+
+^Z^Zpre-prompt
+(gdb)
+^Z^Zprompt
+@kbd{quit}
+
+^Z^Zpost-prompt
+$
+@end smallexample
+
+Here @samp{quit} is input to @value{GDBN}; the rest is output from
+@value{GDBN}. The three lines beginning @samp{^Z^Z} (where @samp{^Z}
+denotes a @samp{control-z} character) are annotations; the rest is
+output from @value{GDBN}.
+
+@node Server Prefix
+@section The Server Prefix
+@cindex server prefix for annotations
+
+To issue a command to @value{GDBN} 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 @value{GDBN}'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 Prompting
+@section Annotation for @value{GDBN} Input
+
+@cindex annotations for prompts
+When @value{GDBN} 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:
+
+@smallexample
+^Z^Zpre-prompt
+^Z^Zprompt
+^Z^Zpost-prompt
+@end smallexample
+
+The input types are
+
+@table @code
+@findex pre-prompt
+@findex prompt
+@findex post-prompt
+@item prompt
+When @value{GDBN} is prompting for a command (the main @value{GDBN} prompt).
+
+@findex pre-commands
+@findex commands
+@findex post-commands
+@item commands
+When @value{GDBN} 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 @value{GDBN} wants the user to select between various overloaded functions.
+
+@findex pre-query
+@findex query
+@findex post-query
+@item query
+When @value{GDBN} 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 @value{GDBN} 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
+@section Errors
+@cindex annotations for errors, warnings and interrupts
+
+@findex quit
+@smallexample
+^Z^Zquit
+@end smallexample
+
+This annotation occurs right before @value{GDBN} responds to an interrupt.
+
+@findex error
+@smallexample
+^Z^Zerror
+@end smallexample
+
+This annotation occurs right before @value{GDBN} responds to an error.
+
+Quit and error annotations indicate that any annotations which @value{GDBN} 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 @value{GDBN} is immediately returning all the way
+to the top level.
+
+@findex error-begin
+A quit or error annotation may be preceded by
+
+@smallexample
+^Z^Zerror-begin
+@end smallexample
+
+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 Invalidation
+@section Invalidation Notices
+
+@cindex annotations for invalidation messages
+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 Annotations for Running
+@section Running the Program
+@cindex annotations for running programs
+
+@findex starting
+@findex stopping
+When the program starts executing due to a @value{GDBN} command such as
+@code{step} or @code{continue},
+
+@smallexample
+^Z^Zstarting
+@end smallexample
+
+is output. When the program stops,
+
+@smallexample
+^Z^Zstopped
+@end smallexample
+
+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:
+
+@smallexample
+@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 smallexample
+
+@noindent
+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 @value{GDBN} 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 Annotations
+@section Displaying Source
+@cindex annotations for source display
+
+@findex source
+The following annotation is used instead of displaying source code:
+
+@smallexample
+^Z^Zsource @var{filename}:@var{line}:@var{character}:@var{middle}:@var{addr}
+@end smallexample
+
+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 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. (Note that if you're cross debugging, the problem may also be
+somewhere in the connection to the target.)
+
+@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.
+@c should add a web page ref...
+
+In any event, we also recommend that you submit bug reports for
+@value{GDBN}. The prefered method is to submit them directly using
+@uref{http://www.gnu.org/software/gdb/bugs/, @value{GDBN}'s Bugs web
+page}. Alternatively, the @email{bug-gdb@@gnu.org, e-mail gateway} can
+be used.
+
+@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.
+
+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. It may be that the bug has been reported previously, but neither
+you nor we can know that unless your bug report is complete and
+self-contained.
+
+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.8.1''.
+
+@item
+What compiler (and its version) was used to compile the program you are
+debugging---e.g. ``@value{GCC}--2.8.1'', or ``HP92453-01 A.10.32.03 HP
+C Compiler''. For GCC, you can say @code{gcc --version} to get this
+information; for other compilers, see the documentation for those
+compilers.
+
+@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.texinfo
+@c Use -I with makeinfo to point to the appropriate directory,
+@c environment var TEXINPUTS with TeX.
+@include rluser.texinfo
+@include inc-hist.texinfo
+
+
+@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:
+
+@smallexample
+make refcard.dvi
+@end smallexample
+
+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-@value{GDBVN}/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:
+
+@smallexample
+cd gdb
+make gdb.info
+@end smallexample
+
+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 type:
+
+@smallexample
+make gdb.dvi
+@end smallexample
+
+Then give @file{gdb.dvi} to your @sc{dvi} printing program.
+
+@node Installing GDB
+@appendix Installing @value{GDBN}
+@cindex configuring @value{GDBN}
+@cindex installation
+@cindex configuring @value{GDBN}, and source tree subdirectories
+
+@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:
+
+@smallexample
+cd gdb-@value{GDBVN}
+./configure @var{host}
+make
+@end smallexample
+
+@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:
+
+@smallexample
+sh configure @var{host}
+@end smallexample
+
+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 should run the @code{configure} script from the top directory in the
+source tree, the @file{gdb-@var{version-number}} directory. If you run
+@code{configure} from one of the subdirectories, you will configure only
+that subdirectory. That is usually not what you want. In particular,
+if you run the first @code{configure} from the @file{gdb} subdirectory
+of the @file{gdb-@var{version-number}} directory, you will omit the
+configuration of @file{bfd}, @file{readline}, and other sibling
+directories of the @file{gdb} subdirectory. This leads to build errors
+about missing include files such as @file{bfd/bfd.h}.
+
+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:
+
+@smallexample
+@group
+cd gdb-@value{GDBVN}
+mkdir ../gdb-sun4
+cd ../gdb-sun4
+../gdb-@value{GDBVN}/configure sun4
+make
+@end group
+@end smallexample
+
+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}.
+
+Make sure that your path to the @file{configure} script has just one
+instance of @file{gdb} in it. If your path to @file{configure} looks
+like @file{../gdb-@value{GDBVN}/gdb/configure}, you are configuring only
+one subdirectory of @value{GDBN}, not the whole package. This leads to
+build errors about missing include files such as @file{bfd/bfd.h}.
+
+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:
+
+@smallexample
+@var{architecture}-@var{vendor}-@var{os}
+@end smallexample
+
+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 i386-linux
+i386-pc-linux-gnu
+% sh config.sub alpha-linux
+alpha-unknown-linux-gnu
+% sh config.sub hp9k700
+hppa1.1-hp-hpux
+% sh config.sub sun4
+sparc-sun-sunos4.1.1
+% sh config.sub sun3
+m68k-sun-sunos4.1.1
+% sh config.sub i986v
+Invalid configuration `i986v': machine `i986v' 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}.
+
+@smallexample
+configure @r{[}--help@r{]}
+ @r{[}--prefix=@var{dir}@r{]}
+ @r{[}--exec-prefix=@var{dir}@r{]}
+ @r{[}--srcdir=@var{dirname}@r{]}
+ @r{[}--norecursion@r{]} @r{[}--rm@r{]}
+ @r{[}--target=@var{target}@r{]}
+ @var{host}
+@end smallexample
+
+@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}}.
+
+@item --exec-prefix=@var{dir}
+Configure the source to install programs 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 --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
+
+There are many other options available as well, but they are generally
+needed for special purposes only.
+
+@node Maintenance Commands
+@appendix Maintenance Commands
+@cindex maintenance commands
+@cindex internal commands
+
+In addition to commands intended for @value{GDBN} users, @value{GDBN}
+includes a number of commands intended for @value{GDBN} developers.
+These commands are provided here for reference.
+
+@table @code
+@kindex maint info breakpoints
+@item @anchor{maint info breakpoints}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.
+
+@item shlib events
+Shared library events.
+
+@end table
+
+@kindex maint internal-error
+@kindex maint internal-warning
+@item maint internal-error
+@itemx maint internal-warning
+Cause @value{GDBN} to call the internal function @code{internal_error}
+or @code{internal_warning} and hence behave as though an internal error
+or internal warning has been detected. In addition to reporting the
+internal problem, these functions give the user the opportunity to
+either quit @value{GDBN} or create a core file of the current
+@value{GDBN} session.
+
+@smallexample
+(gdb) @kbd{maint internal-error testing, 1, 2}
+@dots{}/maint.c:121: internal-error: testing, 1, 2
+A problem internal to GDB has been detected. Further
+debugging may prove unreliable.
+Quit this debugging session? (y or n) @kbd{n}
+Create a core file? (y or n) @kbd{n}
+(gdb)
+@end smallexample
+
+Takes an optional parameter that is used as the text of the error or
+warning message.
+
+@kindex maint print dummy-frames
+@item maint print dummy-frames
+
+Prints the contents of @value{GDBN}'s internal dummy-frame stack.
+
+@smallexample
+(gdb) @kbd{b add}
+@dots{}
+(gdb) @kbd{print add(2,3)}
+Breakpoint 2, add (a=2, b=3) at @dots{}
+58 return (a + b);
+The program being debugged stopped while in a function called from GDB.
+@dots{}
+(gdb) @kbd{maint print dummy-frames}
+0x1a57c80: pc=0x01014068 fp=0x0200bddc sp=0x0200bdd6
+ top=0x0200bdd4 id=@{stack=0x200bddc,code=0x101405c@}
+ call_lo=0x01014000 call_hi=0x01014001
+(gdb)
+@end smallexample
+
+Takes an optional file parameter.
+
+@kindex maint print registers
+@kindex maint print raw-registers
+@kindex maint print cooked-registers
+@kindex maint print register-groups
+@item maint print registers
+@itemx maint print raw-registers
+@itemx maint print cooked-registers
+@itemx maint print register-groups
+Print @value{GDBN}'s internal register data structures.
+
+The command @code{maint print raw-registers} includes the contents of
+the raw register cache; the command @code{maint print cooked-registers}
+includes the (cooked) value of all registers; and the command
+@code{maint print register-groups} includes the groups that each
+register is a member of. @xref{Registers,, Registers, gdbint,
+@value{GDBN} Internals}.
+
+Takes an optional file parameter.
+
+@kindex maint print reggroups
+@item maint print reggroups
+Print @value{GDBN}'s internal register group data structures.
+
+Takes an optional file parameter.
+
+@smallexample
+(gdb) @kbd{maint print reggroups}
+ Group Type
+ general user
+ float user
+ all user
+ vector user
+ system user
+ save internal
+ restore internal
+@end smallexample
+
+@kindex maint set profile
+@kindex maint show profile
+@cindex profiling GDB
+@item maint set profile
+@itemx maint show profile
+Control profiling of @value{GDBN}.
+
+Profiling will be disabled until you use the @samp{maint set profile}
+command to enable it. When you enable profiling, the system will begin
+collecting timing and execution count data; when you disable profiling or
+exit @value{GDBN}, the results will be written to a log file. Remember that
+if you use profiling, @value{GDBN} will overwrite the profiling log file
+(often called @file{gmon.out}). If you have a record of important profiling
+data in a @file{gmon.out} file, be sure to move it to a safe location.
+
+Configuring with @samp{--enable-profiling} arranges for @value{GDBN} to be
+compiled with the @samp{-pg} compiler option.
+
+@end table
+
+
+@node Remote Protocol
+@appendix @value{GDBN} Remote Serial Protocol
+
+@menu
+* Overview::
+* Packets::
+* Stop Reply Packets::
+* General Query Packets::
+* Register Packet Format::
+* Examples::
+* File-I/O remote protocol extension::
+@end menu
+
+@node Overview
+@section Overview
+
+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}.
+
+In the examples below, @samp{->} and @samp{<-} are used to indicate
+transmitted and received data respectfully.
+
+@cindex protocol, @value{GDBN} remote serial
+@cindex serial protocol, @value{GDBN} remote
+@cindex remote serial protocol
+All @value{GDBN} commands and responses (other than acknowledgments) are
+sent as a @var{packet}. A @var{packet} is introduced with the character
+@samp{$}, the actual @var{packet-data}, and the terminating character
+@samp{#} followed by a two-digit @var{checksum}:
+
+@smallexample
+@code{$}@var{packet-data}@code{#}@var{checksum}
+@end smallexample
+@noindent
+
+@cindex checksum, for @value{GDBN} remote
+@noindent
+The two-digit @var{checksum} is computed as the modulo 256 sum of all
+characters between the leading @samp{$} and the trailing @samp{#} (an
+eight bit unsigned checksum).
+
+Implementors should note that prior to @value{GDBN} 5.0 the protocol
+specification also included an optional two-digit @var{sequence-id}:
+
+@smallexample
+@code{$}@var{sequence-id}@code{:}@var{packet-data}@code{#}@var{checksum}
+@end smallexample
+
+@cindex sequence-id, for @value{GDBN} remote
+@noindent
+That @var{sequence-id} was appended to the acknowledgment. @value{GDBN}
+has never output @var{sequence-id}s. Stubs that handle packets added
+since @value{GDBN} 5.0 must not accept @var{sequence-id}.
+
+@cindex acknowledgment, for @value{GDBN} remote
+When either the host or the target machine receives a packet, the first
+response expected is an acknowledgment: either @samp{+} (to indicate
+the package was received correctly) or @samp{-} (to request
+retransmission):
+
+@smallexample
+-> @code{$}@var{packet-data}@code{#}@var{checksum}
+<- @code{+}
+@end smallexample
+@noindent
+
+The host (@value{GDBN}) sends @var{command}s, and the target (the
+debugging stub incorporated in your program) sends a @var{response}. In
+the case of step and continue @var{command}s, the response is only sent
+when the operation has completed (the target has again stopped).
+
+@var{packet-data} consists of a sequence of characters with the
+exception of @samp{#} and @samp{$} (see @samp{X} packet for additional
+exceptions).
+
+Fields within the packet should be separated using @samp{,} @samp{;} or
+@cindex remote protocol, field separator
+@samp{:}. Except where otherwise noted all numbers are represented in
+@sc{hex} with leading zeros suppressed.
+
+Implementors should note that prior to @value{GDBN} 5.0, the character
+@samp{:} could not appear as the third character in a packet (as it
+would potentially conflict with the @var{sequence-id}).
+
+Response @var{data} can be run-length encoded to save space. A @samp{*}
+means that the next character is an @sc{ascii} encoding giving a repeat count
+which stands for that many repetitions of the character preceding the
+@samp{*}. The encoding is @code{n+29}, yielding a printable character
+where @code{n >=3} (which is where rle starts to win). The printable
+characters @samp{$}, @samp{#}, @samp{+} and @samp{-} or with a numeric
+value greater than 126 should not be used.
+
+So:
+@smallexample
+"@code{0* }"
+@end smallexample
+@noindent
+means the same as "0000".
+
+The error response returned for some packets includes a two character
+error number. That number is not well defined.
+
+For any @var{command} not supported by the stub, an empty response
+(@samp{$#00}) should be returned. That way it is possible to extend the
+protocol. A newer @value{GDBN} can tell if a packet is supported based
+on that response.
+
+A stub is required to support the @samp{g}, @samp{G}, @samp{m}, @samp{M},
+@samp{c}, and @samp{s} @var{command}s. All other @var{command}s are
+optional.
+
+@node Packets
+@section Packets
+
+The following table provides a complete list of all currently defined
+@var{command}s and their corresponding response @var{data}.
+
+@table @r
+
+@item @code{!} --- extended mode
+@cindex @code{!} packet
+
+Enable extended mode. In extended mode, the remote server is made
+persistent. The @samp{R} packet is used to restart the program being
+debugged.
+
+Reply:
+@table @samp
+@item OK
+The remote target both supports and has enabled extended mode.
+@end table
+
+@item @code{?} --- last signal
+@cindex @code{?} packet
+
+Indicate the reason the target halted. The reply is the same as for
+step and continue.
+
+Reply:
+@xref{Stop Reply Packets}, for the reply specifications.
+
+@item @code{a} --- reserved
+
+Reserved for future use.
+
+@item @code{A}@var{arglen}@code{,}@var{argnum}@code{,}@var{arg}@code{,@dots{}} --- set program arguments @strong{(reserved)}
+@cindex @code{A} packet
+
+Initialized @samp{argv[]} array passed into program. @var{arglen}
+specifies the number of bytes in the hex encoded byte stream @var{arg}.
+See @code{gdbserver} for more details.
+
+Reply:
+@table @samp
+@item OK
+@item E@var{NN}
+@end table
+
+@item @code{b}@var{baud} --- set baud @strong{(deprecated)}
+@cindex @code{b} packet
+
+Change the serial line speed to @var{baud}.
+
+JTC: @emph{When does the transport layer state change? When it's
+received, or after the ACK is transmitted. In either case, there are
+problems if the command or the acknowledgment packet is dropped.}
+
+Stan: @emph{If people really wanted to add something like this, and get
+it working for the first time, they ought to modify ser-unix.c to send
+some kind of out-of-band message to a specially-setup stub and have the
+switch happen "in between" packets, so that from remote protocol's point
+of view, nothing actually happened.}
+
+@item @code{B}@var{addr},@var{mode} --- set breakpoint @strong{(deprecated)}
+@cindex @code{B} packet
+
+Set (@var{mode} is @samp{S}) or clear (@var{mode} is @samp{C}) a
+breakpoint at @var{addr}.
+
+This packet has been replaced by the @samp{Z} and @samp{z} packets
+(@pxref{insert breakpoint or watchpoint packet}).
+
+@item @code{c}@var{addr} --- continue
+@cindex @code{c} packet
+
+@var{addr} is address to resume. If @var{addr} is omitted, resume at
+current address.
+
+Reply:
+@xref{Stop Reply Packets}, for the reply specifications.
+
+@item @code{C}@var{sig}@code{;}@var{addr} --- continue with signal
+@cindex @code{C} packet
+
+Continue with signal @var{sig} (hex signal number). If
+@code{;}@var{addr} is omitted, resume at same address.
+
+Reply:
+@xref{Stop Reply Packets}, for the reply specifications.
+
+@item @code{d} --- toggle debug @strong{(deprecated)}
+@cindex @code{d} packet
+
+Toggle debug flag.
+
+@item @code{D} --- detach
+@cindex @code{D} packet
+
+Detach @value{GDBN} from the remote system. Sent to the remote target
+before @value{GDBN} disconnects via the @code{detach} command.
+
+Reply:
+@table @samp
+@item @emph{no response}
+@value{GDBN} does not check for any response after sending this packet.
+@end table
+
+@item @code{e} --- reserved
+
+Reserved for future use.
+
+@item @code{E} --- reserved
+
+Reserved for future use.
+
+@item @code{f} --- reserved
+
+Reserved for future use.
+
+@item @code{F}@var{RC}@code{,}@var{EE}@code{,}@var{CF}@code{;}@var{XX} --- Reply to target's F packet.
+@cindex @code{F} packet
+
+This packet is send by @value{GDBN} as reply to a @code{F} request packet
+sent by the target. This is part of the File-I/O protocol extension.
+@xref{File-I/O remote protocol extension}, for the specification.
+
+@item @code{g} --- read registers
+@anchor{read registers packet}
+@cindex @code{g} packet
+
+Read general registers.
+
+Reply:
+@table @samp
+@item @var{XX@dots{}}
+Each byte of register data is described by two hex digits. The bytes
+with the register are transmitted in target byte order. The size of
+each register and their position within the @samp{g} @var{packet} are
+determined by the @value{GDBN} internal macros
+@var{DEPRECATED_REGISTER_RAW_SIZE} and @var{REGISTER_NAME} macros. The
+specification of several standard @code{g} packets is specified below.
+@item E@var{NN}
+for an error.
+@end table
+
+@item @code{G}@var{XX@dots{}} --- write regs
+@cindex @code{G} packet
+
+@xref{read registers packet}, for a description of the @var{XX@dots{}}
+data.
+
+Reply:
+@table @samp
+@item OK
+for success
+@item E@var{NN}
+for an error
+@end table
+
+@item @code{h} --- reserved
+
+Reserved for future use.
+
+@item @code{H}@var{c}@var{t@dots{}} --- set thread
+@cindex @code{H} packet
+
+Set thread for subsequent operations (@samp{m}, @samp{M}, @samp{g},
+@samp{G}, et.al.). @var{c} depends on the operation to be performed: it
+should be @samp{c} for step and continue operations, @samp{g} for other
+operations. The thread designator @var{t@dots{}} may be -1, meaning all
+the threads, a thread number, or zero which means pick any thread.
+
+Reply:
+@table @samp
+@item OK
+for success
+@item E@var{NN}
+for an error
+@end table
+
+@c FIXME: JTC:
+@c 'H': How restrictive (or permissive) is the thread model. If a
+@c thread is selected and stopped, are other threads allowed
+@c to continue to execute? As I mentioned above, I think the
+@c semantics of each command when a thread is selected must be
+@c described. For example:
+@c
+@c 'g': If the stub supports threads and a specific thread is
+@c selected, returns the register block from that thread;
+@c otherwise returns current registers.
+@c
+@c 'G' If the stub supports threads and a specific thread is
+@c selected, sets the registers of the register block of
+@c that thread; otherwise sets current registers.
+
+@item @code{i}@var{addr}@code{,}@var{nnn} --- cycle step @strong{(draft)}
+@anchor{cycle step packet}
+@cindex @code{i} packet
+
+Step the remote target by a single clock cycle. If @code{,}@var{nnn} is
+present, cycle step @var{nnn} cycles. If @var{addr} is present, cycle
+step starting at that address.
+
+@item @code{I} --- signal then cycle step @strong{(reserved)}
+@cindex @code{I} packet
+
+@xref{step with signal packet}. @xref{cycle step packet}.
+
+@item @code{j} --- reserved
+
+Reserved for future use.
+
+@item @code{J} --- reserved
+
+Reserved for future use.
+
+@item @code{k} --- kill request
+@cindex @code{k} packet
+
+FIXME: @emph{There is no description of how to operate when a specific
+thread context has been selected (i.e.@: does 'k' kill only that
+thread?)}.
+
+@item @code{K} --- reserved
+
+Reserved for future use.
+
+@item @code{l} --- reserved
+
+Reserved for future use.
+
+@item @code{L} --- reserved
+
+Reserved for future use.
+
+@item @code{m}@var{addr}@code{,}@var{length} --- read memory
+@cindex @code{m} packet
+
+Read @var{length} bytes of memory starting at address @var{addr}.
+Neither @value{GDBN} nor the stub assume that sized memory transfers are
+assumed using word aligned accesses. FIXME: @emph{A word aligned memory
+transfer mechanism is needed.}
+
+Reply:
+@table @samp
+@item @var{XX@dots{}}
+@var{XX@dots{}} is mem contents. Can be fewer bytes than requested if able
+to read only part of the data. Neither @value{GDBN} nor the stub assume
+that sized memory transfers are assumed using word aligned
+accesses. FIXME: @emph{A word aligned memory transfer mechanism is
+needed.}
+@item E@var{NN}
+@var{NN} is errno
+@end table
+
+@item @code{M}@var{addr},@var{length}@code{:}@var{XX@dots{}} --- write mem
+@cindex @code{M} packet
+
+Write @var{length} bytes of memory starting at address @var{addr}.
+@var{XX@dots{}} is the data.
+
+Reply:
+@table @samp
+@item OK
+for success
+@item E@var{NN}
+for an error (this includes the case where only part of the data was
+written).
+@end table
+
+@item @code{n} --- reserved
+
+Reserved for future use.
+
+@item @code{N} --- reserved
+
+Reserved for future use.
+
+@item @code{o} --- reserved
+
+Reserved for future use.
+
+@item @code{O} --- reserved
+
+Reserved for future use.
+
+@item @code{p}@var{n@dots{}} --- read reg @strong{(reserved)}
+@cindex @code{p} packet
+
+@xref{write register packet}.
+
+Reply:
+@table @samp
+@item @var{r@dots{}.}
+The hex encoded value of the register in target byte order.
+@end table
+
+@item @code{P}@var{n@dots{}}@code{=}@var{r@dots{}} --- write register
+@anchor{write register packet}
+@cindex @code{P} packet
+
+Write register @var{n@dots{}} with value @var{r@dots{}}, which contains two hex
+digits for each byte in the register (target byte order).
+
+Reply:
+@table @samp
+@item OK
+for success
+@item E@var{NN}
+for an error
+@end table
+
+@item @code{q}@var{query} --- general query
+@anchor{general query packet}
+@cindex @code{q} packet
+
+Request info about @var{query}. In general @value{GDBN} queries have a
+leading upper case letter. Custom vendor queries should use a company
+prefix (in lower case) ex: @samp{qfsf.var}. @var{query} may optionally
+be followed by a @samp{,} or @samp{;} separated list. Stubs must ensure
+that they match the full @var{query} name.
+
+Reply:
+@table @samp
+@item @var{XX@dots{}}
+Hex encoded data from query. The reply can not be empty.
+@item E@var{NN}
+error reply
+@item
+Indicating an unrecognized @var{query}.
+@end table
+
+@item @code{Q}@var{var}@code{=}@var{val} --- general set
+@cindex @code{Q} packet
+
+Set value of @var{var} to @var{val}.
+
+@xref{general query packet}, for a discussion of naming conventions.
+
+@item @code{r} --- reset @strong{(deprecated)}
+@cindex @code{r} packet
+
+Reset the entire system.
+
+@item @code{R}@var{XX} --- remote restart
+@cindex @code{R} packet
+
+Restart the program being debugged. @var{XX}, while needed, is ignored.
+This packet is only available in extended mode.
+
+Reply:
+@table @samp
+@item @emph{no reply}
+The @samp{R} packet has no reply.
+@end table
+
+@item @code{s}@var{addr} --- step
+@cindex @code{s} packet
+
+@var{addr} is address to resume. If @var{addr} is omitted, resume at
+same address.
+
+Reply:
+@xref{Stop Reply Packets}, for the reply specifications.
+
+@item @code{S}@var{sig}@code{;}@var{addr} --- step with signal
+@anchor{step with signal packet}
+@cindex @code{S} packet
+
+Like @samp{C} but step not continue.
+
+Reply:
+@xref{Stop Reply Packets}, for the reply specifications.
+
+@item @code{t}@var{addr}@code{:}@var{PP}@code{,}@var{MM} --- search
+@cindex @code{t} packet
+
+Search backwards starting at address @var{addr} for a match with pattern
+@var{PP} and mask @var{MM}. @var{PP} and @var{MM} are 4 bytes.
+@var{addr} must be at least 3 digits.
+
+@item @code{T}@var{XX} --- thread alive
+@cindex @code{T} packet
+
+Find out if the thread XX is alive.
+
+Reply:
+@table @samp
+@item OK
+thread is still alive
+@item E@var{NN}
+thread is dead
+@end table
+
+@item @code{u} --- reserved
+
+Reserved for future use.
+
+@item @code{U} --- reserved
+
+Reserved for future use.
+
+@item @code{v} --- verbose packet prefix
+
+Packets starting with @code{v} are identified by a multi-letter name,
+up to the first @code{;} or @code{?} (or the end of the packet).
+
+@item @code{vCont}[;@var{action}[@code{:}@var{tid}]]... --- extended resume
+@cindex @code{vCont} packet
+
+Resume the inferior. Different actions may be specified for each thread.
+If an action is specified with no @var{tid}, then it is applied to any
+threads that don't have a specific action specified; if no default action is
+specified then other threads should remain stopped. Specifying multiple
+default actions is an error; specifying no actions is also an error.
+Thread IDs are specified in hexadecimal. Currently supported actions are:
+
+@table @code
+@item c
+Continue.
+@item C@var{sig}
+Continue with signal @var{sig}. @var{sig} should be two hex digits.
+@item s
+Step.
+@item S@var{sig}
+Step with signal @var{sig}. @var{sig} should be two hex digits.
+@end table
+
+The optional @var{addr} argument normally associated with these packets is
+not supported in @code{vCont}.
+
+Reply:
+@xref{Stop Reply Packets}, for the reply specifications.
+
+@item @code{vCont?} --- extended resume query
+@cindex @code{vCont?} packet
+
+Query support for the @code{vCont} packet.
+
+Reply:
+@table @samp
+@item @code{vCont}[;@var{action}]...
+The @code{vCont} packet is supported. Each @var{action} is a supported
+command in the @code{vCont} packet.
+@item
+The @code{vCont} packet is not supported.
+@end table
+
+@item @code{V} --- reserved
+
+Reserved for future use.
+
+@item @code{w} --- reserved
+
+Reserved for future use.
+
+@item @code{W} --- reserved
+
+Reserved for future use.
+
+@item @code{x} --- reserved
+
+Reserved for future use.
+
+@item @code{X}@var{addr}@code{,}@var{length}@var{:}@var{XX@dots{}} --- write mem (binary)
+@cindex @code{X} packet
+
+@var{addr} is address, @var{length} is number of bytes, @var{XX@dots{}}
+is binary data. The characters @code{$}, @code{#}, and @code{0x7d} are
+escaped using @code{0x7d}.
+
+Reply:
+@table @samp
+@item OK
+for success
+@item E@var{NN}
+for an error
+@end table
+
+@item @code{y} --- reserved
+
+Reserved for future use.
+
+@item @code{Y} reserved
+
+Reserved for future use.
+
+@item @code{z}@var{type}@code{,}@var{addr}@code{,}@var{length} --- remove breakpoint or watchpoint @strong{(draft)}
+@itemx @code{Z}@var{type}@code{,}@var{addr}@code{,}@var{length} --- insert breakpoint or watchpoint @strong{(draft)}
+@anchor{insert breakpoint or watchpoint packet}
+@cindex @code{z} packet
+@cindex @code{Z} packets
+
+Insert (@code{Z}) or remove (@code{z}) a @var{type} breakpoint or
+watchpoint starting at address @var{address} and covering the next
+@var{length} bytes.
+
+Each breakpoint and watchpoint packet @var{type} is documented
+separately.
+
+@emph{Implementation notes: A remote target shall return an empty string
+for an unrecognized breakpoint or watchpoint packet @var{type}. A
+remote target shall support either both or neither of a given
+@code{Z}@var{type}@dots{} and @code{z}@var{type}@dots{} packet pair. To
+avoid potential problems with duplicate packets, the operations should
+be implemented in an idempotent way.}
+
+@item @code{z}@code{0}@code{,}@var{addr}@code{,}@var{length} --- remove memory breakpoint @strong{(draft)}
+@item @code{Z}@code{0}@code{,}@var{addr}@code{,}@var{length} --- insert memory breakpoint @strong{(draft)}
+@cindex @code{z0} packet
+@cindex @code{Z0} packet
+
+Insert (@code{Z0}) or remove (@code{z0}) a memory breakpoint at address
+@code{addr} of size @code{length}.
+
+A memory breakpoint is implemented by replacing the instruction at
+@var{addr} with a software breakpoint or trap instruction. The
+@code{length} is used by targets that indicates the size of the
+breakpoint (in bytes) that should be inserted (e.g., the @sc{arm} and
+@sc{mips} can insert either a 2 or 4 byte breakpoint).
+
+@emph{Implementation note: It is possible for a target to copy or move
+code that contains memory breakpoints (e.g., when implementing
+overlays). The behavior of this packet, in the presence of such a
+target, is not defined.}
+
+Reply:
+@table @samp
+@item OK
+success
+@item
+not supported
+@item E@var{NN}
+for an error
+@end table
+
+@item @code{z}@code{1}@code{,}@var{addr}@code{,}@var{length} --- remove hardware breakpoint @strong{(draft)}
+@item @code{Z}@code{1}@code{,}@var{addr}@code{,}@var{length} --- insert hardware breakpoint @strong{(draft)}
+@cindex @code{z1} packet
+@cindex @code{Z1} packet
+
+Insert (@code{Z1}) or remove (@code{z1}) a hardware breakpoint at
+address @code{addr} of size @code{length}.
+
+A hardware breakpoint is implemented using a mechanism that is not
+dependant on being able to modify the target's memory.
+
+@emph{Implementation note: A hardware breakpoint is not affected by code
+movement.}
+
+Reply:
+@table @samp
+@item OK
+success
+@item
+not supported
+@item E@var{NN}
+for an error
+@end table
+
+@item @code{z}@code{2}@code{,}@var{addr}@code{,}@var{length} --- remove write watchpoint @strong{(draft)}
+@item @code{Z}@code{2}@code{,}@var{addr}@code{,}@var{length} --- insert write watchpoint @strong{(draft)}
+@cindex @code{z2} packet
+@cindex @code{Z2} packet
+
+Insert (@code{Z2}) or remove (@code{z2}) a write watchpoint.
+
+Reply:
+@table @samp
+@item OK
+success
+@item
+not supported
+@item E@var{NN}
+for an error
+@end table
+
+@item @code{z}@code{3}@code{,}@var{addr}@code{,}@var{length} --- remove read watchpoint @strong{(draft)}
+@item @code{Z}@code{3}@code{,}@var{addr}@code{,}@var{length} --- insert read watchpoint @strong{(draft)}
+@cindex @code{z3} packet
+@cindex @code{Z3} packet
+
+Insert (@code{Z3}) or remove (@code{z3}) a read watchpoint.
+
+Reply:
+@table @samp
+@item OK
+success
+@item
+not supported
+@item E@var{NN}
+for an error
+@end table
+
+@item @code{z}@code{4}@code{,}@var{addr}@code{,}@var{length} --- remove access watchpoint @strong{(draft)}
+@item @code{Z}@code{4}@code{,}@var{addr}@code{,}@var{length} --- insert access watchpoint @strong{(draft)}
+@cindex @code{z4} packet
+@cindex @code{Z4} packet
+
+Insert (@code{Z4}) or remove (@code{z4}) an access watchpoint.
+
+Reply:
+@table @samp
+@item OK
+success
+@item
+not supported
+@item E@var{NN}
+for an error
+@end table
+
+@end table
+
+@node Stop Reply Packets
+@section Stop Reply Packets
+@cindex stop reply packets
+
+The @samp{C}, @samp{c}, @samp{S}, @samp{s} and @samp{?} packets can
+receive any of the below as a reply. In the case of the @samp{C},
+@samp{c}, @samp{S} and @samp{s} packets, that reply is only returned
+when the target halts. In the below the exact meaning of @samp{signal
+number} is poorly defined. In general one of the UNIX signal numbering
+conventions is used.
+
+@table @samp
+
+@item S@var{AA}
+@var{AA} is the signal number
+
+@item @code{T}@var{AA}@var{n...}@code{:}@var{r...}@code{;}@var{n...}@code{:}@var{r...}@code{;}@var{n...}@code{:}@var{r...}@code{;}
+@cindex @code{T} packet reply
+
+@var{AA} = two hex digit signal number; @var{n...} = register number
+(hex), @var{r...} = target byte ordered register contents, size defined
+by @code{DEPRECATED_REGISTER_RAW_SIZE}; @var{n...} = @samp{thread},
+@var{r...} = thread process ID, this is a hex integer; @var{n...} =
+(@samp{watch} | @samp{rwatch} | @samp{awatch}, @var{r...} = data
+address, this is a hex integer; @var{n...} = other string not starting
+with valid hex digit. @value{GDBN} should ignore this @var{n...},
+@var{r...} pair and go on to the next. This way we can extend the
+protocol.
+
+@item W@var{AA}
+
+The process exited, and @var{AA} is the exit status. This is only
+applicable to certain targets.
+
+@item X@var{AA}
+
+The process terminated with signal @var{AA}.
+
+@item O@var{XX@dots{}}
+
+@var{XX@dots{}} is hex encoding of @sc{ascii} data. This can happen at
+any time while the program is running and the debugger should continue
+to wait for @samp{W}, @samp{T}, etc.
+
+@item F@var{call-id}@code{,}@var{parameter@dots{}}
+
+@var{call-id} is the identifier which says which host system call should
+be called. This is just the name of the function. Translation into the
+correct system call is only applicable as it's defined in @value{GDBN}.
+@xref{File-I/O remote protocol extension}, for a list of implemented
+system calls.
+
+@var{parameter@dots{}} is a list of parameters as defined for this very
+system call.
+
+The target replies with this packet when it expects @value{GDBN} to call
+a host system call on behalf of the target. @value{GDBN} replies with
+an appropriate @code{F} packet and keeps up waiting for the next reply
+packet from the target. The latest @samp{C}, @samp{c}, @samp{S} or
+@samp{s} action is expected to be continued.
+@xref{File-I/O remote protocol extension}, for more details.
+
+@end table
+
+@node General Query Packets
+@section General Query Packets
+
+The following set and query packets have already been defined.
+
+@table @r
+
+@item @code{q}@code{C} --- current thread
+
+Return the current thread id.
+
+Reply:
+@table @samp
+@item @code{QC}@var{pid}
+Where @var{pid} is a HEX encoded 16 bit process id.
+@item *
+Any other reply implies the old pid.
+@end table
+
+@item @code{q}@code{fThreadInfo} -- all thread ids
+
+@code{q}@code{sThreadInfo}
+
+Obtain a list of active thread ids from the target (OS). Since there
+may be too many active threads to fit into one reply packet, this query
+works iteratively: it may require more than one query/reply sequence to
+obtain the entire list of threads. The first query of the sequence will
+be the @code{qf}@code{ThreadInfo} query; subsequent queries in the
+sequence will be the @code{qs}@code{ThreadInfo} query.
+
+NOTE: replaces the @code{qL} query (see below).
+
+Reply:
+@table @samp
+@item @code{m}@var{id}
+A single thread id
+@item @code{m}@var{id},@var{id}@dots{}
+a comma-separated list of thread ids
+@item @code{l}
+(lower case 'el') denotes end of list.
+@end table
+
+In response to each query, the target will reply with a list of one or
+more thread ids, in big-endian hex, separated by commas. @value{GDBN}
+will respond to each reply with a request for more thread ids (using the
+@code{qs} form of the query), until the target responds with @code{l}
+(lower-case el, for @code{'last'}).
+
+@item @code{q}@code{ThreadExtraInfo}@code{,}@var{id} --- extra thread info
+
+Where @var{id} is a thread-id in big-endian hex. Obtain a printable
+string description of a thread's attributes from the target OS. This
+string may contain anything that the target OS thinks is interesting for
+@value{GDBN} to tell the user about the thread. The string is displayed
+in @value{GDBN}'s @samp{info threads} display. Some examples of
+possible thread extra info strings are ``Runnable'', or ``Blocked on
+Mutex''.
+
+Reply:
+@table @samp
+@item @var{XX@dots{}}
+Where @var{XX@dots{}} is a hex encoding of @sc{ascii} data, comprising
+the printable string containing the extra information about the thread's
+attributes.
+@end table
+
+@item @code{q}@code{L}@var{startflag}@var{threadcount}@var{nextthread} --- query @var{LIST} or @var{threadLIST} @strong{(deprecated)}
+
+Obtain thread information from RTOS. Where: @var{startflag} (one hex
+digit) is one to indicate the first query and zero to indicate a
+subsequent query; @var{threadcount} (two hex digits) is the maximum
+number of threads the response packet can contain; and @var{nextthread}
+(eight hex digits), for subsequent queries (@var{startflag} is zero), is
+returned in the response as @var{argthread}.
+
+NOTE: this query is replaced by the @code{q}@code{fThreadInfo} query
+(see above).
+
+Reply:
+@table @samp
+@item @code{q}@code{M}@var{count}@var{done}@var{argthread}@var{thread@dots{}}
+Where: @var{count} (two hex digits) is the number of threads being
+returned; @var{done} (one hex digit) is zero to indicate more threads
+and one indicates no further threads; @var{argthreadid} (eight hex
+digits) is @var{nextthread} from the request packet; @var{thread@dots{}}
+is a sequence of thread IDs from the target. @var{threadid} (eight hex
+digits). See @code{remote.c:parse_threadlist_response()}.
+@end table
+
+@item @code{q}@code{CRC:}@var{addr}@code{,}@var{length} --- compute CRC of memory block
+
+Reply:
+@table @samp
+@item @code{E}@var{NN}
+An error (such as memory fault)
+@item @code{C}@var{CRC32}
+A 32 bit cyclic redundancy check of the specified memory region.
+@end table
+
+@item @code{q}@code{Offsets} --- query sect offs
+
+Get section offsets that the target used when re-locating the downloaded
+image. @emph{Note: while a @code{Bss} offset is included in the
+response, @value{GDBN} ignores this and instead applies the @code{Data}
+offset to the @code{Bss} section.}
+
+Reply:
+@table @samp
+@item @code{Text=}@var{xxx}@code{;Data=}@var{yyy}@code{;Bss=}@var{zzz}
+@end table
+
+@item @code{q}@code{P}@var{mode}@var{threadid} --- thread info request
+
+Returns information on @var{threadid}. Where: @var{mode} is a hex
+encoded 32 bit mode; @var{threadid} is a hex encoded 64 bit thread ID.
+
+Reply:
+@table @samp
+@item *
+@end table
+
+See @code{remote.c:remote_unpack_thread_info_response()}.
+
+@item @code{q}@code{Rcmd,}@var{command} --- remote command
+
+@var{command} (hex encoded) is passed to the local interpreter for
+execution. Invalid commands should be reported using the output string.
+Before the final result packet, the target may also respond with a
+number of intermediate @code{O}@var{output} console output packets.
+@emph{Implementors should note that providing access to a stubs's
+interpreter may have security implications}.
+
+Reply:
+@table @samp
+@item OK
+A command response with no output.
+@item @var{OUTPUT}
+A command response with the hex encoded output string @var{OUTPUT}.
+@item @code{E}@var{NN}
+Indicate a badly formed request.
+@item @samp{}
+When @samp{q}@samp{Rcmd} is not recognized.
+@end table
+
+@item @code{qSymbol::} --- symbol lookup
+
+Notify the target that @value{GDBN} is prepared to serve symbol lookup
+requests. Accept requests from the target for the values of symbols.
+
+Reply:
+@table @samp
+@item @code{OK}
+The target does not need to look up any (more) symbols.
+@item @code{qSymbol:}@var{sym_name}
+The target requests the value of symbol @var{sym_name} (hex encoded).
+@value{GDBN} may provide the value by using the
+@code{qSymbol:}@var{sym_value}:@var{sym_name} message, described below.
+@end table
+
+@item @code{qSymbol:}@var{sym_value}:@var{sym_name} --- symbol value
+
+Set the value of @var{sym_name} to @var{sym_value}.
+
+@var{sym_name} (hex encoded) is the name of a symbol whose value the
+target has previously requested.
+
+@var{sym_value} (hex) is the value for symbol @var{sym_name}. If
+@value{GDBN} cannot supply a value for @var{sym_name}, then this field
+will be empty.
+
+Reply:
+@table @samp
+@item @code{OK}
+The target does not need to look up any (more) symbols.
+@item @code{qSymbol:}@var{sym_name}
+The target requests the value of a new symbol @var{sym_name} (hex
+encoded). @value{GDBN} will continue to supply the values of symbols
+(if available), until the target ceases to request them.
+@end table
+
+@item @code{qPart}:@var{object}:@code{read}:@var{annex}:@var{offset},@var{length} --- read special data
+
+Read uninterpreted bytes from the target's special data area
+identified by the keyword @code{object}.
+Request @var{length} bytes starting at @var{offset} bytes into the data.
+The content and encoding of @var{annex} is specific to the object;
+it can supply additional details about what data to access.
+
+Here are the specific requests of this form defined so far.
+All @samp{@code{qPart}:@var{object}:@code{read}:@dots{}}
+requests use the same reply formats, listed below.
+
+@table @asis
+@item @code{qPart}:@code{auxv}:@code{read}::@var{offset},@var{length}
+Access the target's @dfn{auxiliary vector}. @xref{Auxiliary Vector}.
+Note @var{annex} must be empty.
+@end table
+
+Reply:
+@table @asis
+@item @code{OK}
+The @var{offset} in the request is at the end of the data.
+There is no more data to be read.
+
+@item @var{XX@dots{}}
+Hex encoded data bytes read.
+This may be fewer bytes than the @var{length} in the request.
+
+@item @code{E00}
+The request was malformed, or @var{annex} was invalid.
+
+@item @code{E}@var{nn}
+The offset was invalid, or there was an error encountered reading the data.
+@var{nn} is a hex-encoded @code{errno} value.
+
+@item @code{""} (empty)
+An empty reply indicates the @var{object} or @var{annex} string was not
+recognized by the stub.
+@end table
+
+@item @code{qPart}:@var{object}:@code{write}:@var{annex}:@var{offset}:@var{data@dots{}}
+
+Write uninterpreted bytes into the target's special data area
+identified by the keyword @code{object},
+starting at @var{offset} bytes into the data.
+@var{data@dots{}} is the hex-encoded data to be written.
+The content and encoding of @var{annex} is specific to the object;
+it can supply additional details about what data to access.
+
+No requests of this form are presently in use. This specification
+serves as a placeholder to document the common format that new
+specific request specifications ought to use.
+
+Reply:
+@table @asis
+@item @var{nn}
+@var{nn} (hex encoded) is the number of bytes written.
+This may be fewer bytes than supplied in the request.
+
+@item @code{E00}
+The request was malformed, or @var{annex} was invalid.
+
+@item @code{E}@var{nn}
+The offset was invalid, or there was an error encountered writing the data.
+@var{nn} is a hex-encoded @code{errno} value.
+
+@item @code{""} (empty)
+An empty reply indicates the @var{object} or @var{annex} string was not
+recognized by the stub, or that the object does not support writing.
+@end table
+
+@item @code{qPart}:@var{object}:@var{operation}:@dots{}
+Requests of this form may be added in the future. When a stub does
+not recognize the @var{object} keyword, or its support for
+@var{object} does not recognize the @var{operation} keyword,
+the stub must respond with an empty packet.
+@end table
+
+@node Register Packet Format
+@section Register Packet Format
+
+The following @samp{g}/@samp{G} packets have previously been defined.
+In the below, some thirty-two bit registers are transferred as
+sixty-four bits. Those registers should be zero/sign extended (which?)
+to fill the space allocated. Register bytes are transfered in target
+byte order. The two nibbles within a register byte are transfered
+most-significant - least-significant.
+
+@table @r
+
+@item MIPS32
+
+All registers are transfered as thirty-two bit quantities in the order:
+32 general-purpose; sr; lo; hi; bad; cause; pc; 32 floating-point
+registers; fsr; fir; fp.
+
+@item MIPS64
+
+All registers are transfered as sixty-four bit quantities (including
+thirty-two bit registers such as @code{sr}). The ordering is the same
+as @code{MIPS32}.
+
+@end table
+
+@node Examples
+@section Examples
+
+Example sequence of a target being re-started. Notice how the restart
+does not get any direct output:
+
+@smallexample
+-> @code{R00}
+<- @code{+}
+@emph{target restarts}
+-> @code{?}
+<- @code{+}
+<- @code{T001:1234123412341234}
+-> @code{+}
+@end smallexample
+
+Example sequence of a target being stepped by a single instruction:
+
+@smallexample
+-> @code{G1445@dots{}}
+<- @code{+}
+-> @code{s}
+<- @code{+}
+@emph{time passes}
+<- @code{T001:1234123412341234}
+-> @code{+}
+-> @code{g}
+<- @code{+}
+<- @code{1455@dots{}}
+-> @code{+}
+@end smallexample
+
+@node File-I/O remote protocol extension
+@section File-I/O remote protocol extension
+@cindex File-I/O remote protocol extension
+
+@menu
+* File-I/O Overview::
+* Protocol basics::
+* The F request packet::
+* The F reply packet::
+* Memory transfer::
+* The Ctrl-C message::
+* Console I/O::
+* The isatty call::
+* The system call::
+* List of supported calls::
+* Protocol specific representation of datatypes::
+* Constants::
+* File-I/O Examples::
+@end menu
+
+@node File-I/O Overview
+@subsection File-I/O Overview
+@cindex file-i/o overview
+
+The File I/O remote protocol extension (short: File-I/O) allows the
+target to use the hosts file system and console I/O when calling various
+system calls. System calls on the target system are translated into a
+remote protocol packet to the host system which then performs the needed
+actions and returns with an adequate response packet to the target system.
+This simulates file system operations even on targets that lack file systems.
+
+The protocol is defined host- and target-system independent. It uses
+it's own independent representation of datatypes and values. Both,
+@value{GDBN} and the target's @value{GDBN} stub are responsible for
+translating the system dependent values into the unified protocol values
+when data is transmitted.
+
+The communication is synchronous. A system call is possible only
+when GDB is waiting for the @samp{C}, @samp{c}, @samp{S} or @samp{s}
+packets. While @value{GDBN} handles the request for a system call,
+the target is stopped to allow deterministic access to the target's
+memory. Therefore File-I/O is not interuptible by target signals. It
+is possible to interrupt File-I/O by a user interrupt (Ctrl-C), though.
+
+The target's request to perform a host system call does not finish
+the latest @samp{C}, @samp{c}, @samp{S} or @samp{s} action. That means,
+after finishing the system call, the target returns to continuing the
+previous activity (continue, step). No additional continue or step
+request from @value{GDBN} is required.
+
+@smallexample
+(gdb) continue
+ <- target requests 'system call X'
+ target is stopped, @value{GDBN} executes system call
+ -> GDB returns result
+ ... target continues, GDB returns to wait for the target
+ <- target hits breakpoint and sends a Txx packet
+@end smallexample
+
+The protocol is only used for files on the host file system and
+for I/O on the console. Character or block special devices, pipes,
+named pipes or sockets or any other communication method on the host
+system are not supported by this protocol.
+
+@node Protocol basics
+@subsection Protocol basics
+@cindex protocol basics, file-i/o
+
+The File-I/O protocol uses the @code{F} packet, as request as well
+as as reply packet. Since a File-I/O system call can only occur when
+@value{GDBN} is waiting for the continuing or stepping target, the
+File-I/O request is a reply that @value{GDBN} has to expect as a result
+of a former @samp{C}, @samp{c}, @samp{S} or @samp{s} packet.
+This @code{F} packet contains all information needed to allow @value{GDBN}
+to call the appropriate host system call:
+
+@itemize @bullet
+@item
+A unique identifier for the requested system call.
+
+@item
+All parameters to the system call. Pointers are given as addresses
+in the target memory address space. Pointers to strings are given as
+pointer/length pair. Numerical values are given as they are.
+Numerical control values are given in a protocol specific representation.
+
+@end itemize
+
+At that point @value{GDBN} has to perform the following actions.
+
+@itemize @bullet
+@item
+If parameter pointer values are given, which point to data needed as input
+to a system call, @value{GDBN} requests this data from the target with a
+standard @code{m} packet request. This additional communication has to be
+expected by the target implementation and is handled as any other @code{m}
+packet.
+
+@item
+@value{GDBN} translates all value from protocol representation to host
+representation as needed. Datatypes are coerced into the host types.
+
+@item
+@value{GDBN} calls the system call
+
+@item
+It then coerces datatypes back to protocol representation.
+
+@item
+If pointer parameters in the request packet point to buffer space in which
+a system call is expected to copy data to, the data is transmitted to the
+target using a @code{M} or @code{X} packet. This packet has to be expected
+by the target implementation and is handled as any other @code{M} or @code{X}
+packet.
+
+@end itemize
+
+Eventually @value{GDBN} replies with another @code{F} packet which contains all
+necessary information for the target to continue. This at least contains
+
+@itemize @bullet
+@item
+Return value.
+
+@item
+@code{errno}, if has been changed by the system call.
+
+@item
+``Ctrl-C'' flag.
+
+@end itemize
+
+After having done the needed type and value coercion, the target continues
+the latest continue or step action.
+
+@node The F request packet
+@subsection The @code{F} request packet
+@cindex file-i/o request packet
+@cindex @code{F} request packet
+
+The @code{F} request packet has the following format:
+
+@table @samp
+
+@smallexample
+@code{F}@var{call-id}@code{,}@var{parameter@dots{}}
+@end smallexample
+
+@var{call-id} is the identifier to indicate the host system call to be called.
+This is just the name of the function.
+
+@var{parameter@dots{}} are the parameters to the system call.
+
+@end table
+
+Parameters are hexadecimal integer values, either the real values in case
+of scalar datatypes, as pointers to target buffer space in case of compound
+datatypes and unspecified memory areas or as pointer/length pairs in case
+of string parameters. These are appended to the call-id, each separated
+from its predecessor by a comma. All values are transmitted in ASCII
+string representation, pointer/length pairs separated by a slash.
+
+@node The F reply packet
+@subsection The @code{F} reply packet
+@cindex file-i/o reply packet
+@cindex @code{F} reply packet
+
+The @code{F} reply packet has the following format:
+
+@table @samp
+
+@smallexample
+@code{F}@var{retcode}@code{,}@var{errno}@code{,}@var{Ctrl-C flag}@code{;}@var{call specific attachment}
+@end smallexample
+
+@var{retcode} is the return code of the system call as hexadecimal value.
+
+@var{errno} is the errno set by the call, in protocol specific representation.
+This parameter can be omitted if the call was successful.
+
+@var{Ctrl-C flag} is only send if the user requested a break. In this
+case, @var{errno} must be send as well, even if the call was successful.
+The @var{Ctrl-C flag} itself consists of the character 'C':
+
+@smallexample
+F0,0,C
+@end smallexample
+
+@noindent
+or, if the call was interupted before the host call has been performed:
+
+@smallexample
+F-1,4,C
+@end smallexample
+
+@noindent
+assuming 4 is the protocol specific representation of @code{EINTR}.
+
+@end table
+
+@node Memory transfer
+@subsection Memory transfer
+@cindex memory transfer, in file-i/o protocol
+
+Structured data which is transferred using a memory read or write as e.g.@:
+a @code{struct stat} is expected to be in a protocol specific format with
+all scalar multibyte datatypes being big endian. This should be done by
+the target before the @code{F} packet is sent resp.@: by @value{GDBN} before
+it transfers memory to the target. Transferred pointers to structured
+data should point to the already coerced data at any time.
+
+@node The Ctrl-C message
+@subsection The Ctrl-C message
+@cindex ctrl-c message, in file-i/o protocol
+
+A special case is, if the @var{Ctrl-C flag} is set in the @value{GDBN}
+reply packet. In this case the target should behave, as if it had
+gotten a break message. The meaning for the target is ``system call
+interupted by @code{SIGINT}''. Consequentially, the target should actually stop
+(as with a break message) and return to @value{GDBN} with a @code{T02}
+packet. In this case, it's important for the target to know, in which
+state the system call was interrupted. Since this action is by design
+not an atomic operation, we have to differ between two cases:
+
+@itemize @bullet
+@item
+The system call hasn't been performed on the host yet.
+
+@item
+The system call on the host has been finished.
+
+@end itemize
+
+These two states can be distinguished by the target by the value of the
+returned @code{errno}. If it's the protocol representation of @code{EINTR}, the system
+call hasn't been performed. This is equivalent to the @code{EINTR} handling
+on POSIX systems. In any other case, the target may presume that the
+system call has been finished --- successful or not --- and should behave
+as if the break message arrived right after the system call.
+
+@value{GDBN} must behave reliable. If the system call has not been called
+yet, @value{GDBN} may send the @code{F} reply immediately, setting @code{EINTR} as
+@code{errno} in the packet. If the system call on the host has been finished
+before the user requests a break, the full action must be finshed by
+@value{GDBN}. This requires sending @code{M} or @code{X} packets as they fit.
+The @code{F} packet may only be send when either nothing has happened
+or the full action has been completed.
+
+@node Console I/O
+@subsection Console I/O
+@cindex console i/o as part of file-i/o
+
+By default and if not explicitely closed by the target system, the file
+descriptors 0, 1 and 2 are connected to the @value{GDBN} console. Output
+on the @value{GDBN} console is handled as any other file output operation
+(@code{write(1, @dots{})} or @code{write(2, @dots{})}). Console input is handled
+by @value{GDBN} so that after the target read request from file descriptor
+0 all following typing is buffered until either one of the following
+conditions is met:
+
+@itemize @bullet
+@item
+The user presses @kbd{Ctrl-C}. The behaviour is as explained above, the
+@code{read}
+system call is treated as finished.
+
+@item
+The user presses @kbd{Enter}. This is treated as end of input with a trailing
+line feed.
+
+@item
+The user presses @kbd{Ctrl-D}. This is treated as end of input. No trailing
+character, especially no Ctrl-D is appended to the input.
+
+@end itemize
+
+If the user has typed more characters as fit in the buffer given to
+the read call, the trailing characters are buffered in @value{GDBN} until
+either another @code{read(0, @dots{})} is requested by the target or debugging
+is stopped on users request.
+
+@node The isatty call
+@subsection The isatty(3) call
+@cindex isatty call, file-i/o protocol
+
+A special case in this protocol is the library call @code{isatty} which
+is implemented as it's own call inside of this protocol. It returns
+1 to the target if the file descriptor given as parameter is attached
+to the @value{GDBN} console, 0 otherwise. Implementing through system calls
+would require implementing @code{ioctl} and would be more complex than
+needed.
+
+@node The system call
+@subsection The system(3) call
+@cindex system call, file-i/o protocol
+
+The other special case in this protocol is the @code{system} call which
+is implemented as it's own call, too. @value{GDBN} is taking over the full
+task of calling the necessary host calls to perform the @code{system}
+call. The return value of @code{system} is simplified before it's returned
+to the target. Basically, the only signal transmitted back is @code{EINTR}
+in case the user pressed @kbd{Ctrl-C}. Otherwise the return value consists
+entirely of the exit status of the called command.
+
+Due to security concerns, the @code{system} call is refused to be called
+by @value{GDBN} by default. The user has to allow this call explicitly by
+entering
+
+@table @samp
+@kindex set remote system-call-allowed 1
+@item @code{set remote system-call-allowed 1}
+@end table
+
+Disabling the @code{system} call is done by
+
+@table @samp
+@kindex set remote system-call-allowed 0
+@item @code{set remote system-call-allowed 0}
+@end table
+
+The current setting is shown by typing
+
+@table @samp
+@kindex show remote system-call-allowed
+@item @code{show remote system-call-allowed}
+@end table
+
+@node List of supported calls
+@subsection List of supported calls
+@cindex list of supported file-i/o calls
+
+@menu
+* open::
+* close::
+* read::
+* write::
+* lseek::
+* rename::
+* unlink::
+* stat/fstat::
+* gettimeofday::
+* isatty::
+* system::
+@end menu
+
+@node open
+@unnumberedsubsubsec open
+@cindex open, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int open(const char *pathname, int flags);
+int open(const char *pathname, int flags, mode_t mode);
+
+@exdent Request:
+Fopen,pathptr/len,flags,mode
+@end smallexample
+
+@noindent
+@code{flags} is the bitwise or of the following values:
+
+@table @code
+@item O_CREAT
+If the file does not exist it will be created. The host
+rules apply as far as file ownership and time stamps
+are concerned.
+
+@item O_EXCL
+When used with O_CREAT, if the file already exists it is
+an error and open() fails.
+
+@item O_TRUNC
+If the file already exists and the open mode allows
+writing (O_RDWR or O_WRONLY is given) it will be
+truncated to length 0.
+
+@item O_APPEND
+The file is opened in append mode.
+
+@item O_RDONLY
+The file is opened for reading only.
+
+@item O_WRONLY
+The file is opened for writing only.
+
+@item O_RDWR
+The file is opened for reading and writing.
+
+@noindent
+Each other bit is silently ignored.
+
+@end table
+
+@noindent
+@code{mode} is the bitwise or of the following values:
+
+@table @code
+@item S_IRUSR
+User has read permission.
+
+@item S_IWUSR
+User has write permission.
+
+@item S_IRGRP
+Group has read permission.
+
+@item S_IWGRP
+Group has write permission.
+
+@item S_IROTH
+Others have read permission.
+
+@item S_IWOTH
+Others have write permission.
+
+@noindent
+Each other bit is silently ignored.
+
+@end table
+
+@smallexample
+@exdent Return value:
+open returns the new file descriptor or -1 if an error
+occured.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EEXIST
+pathname already exists and O_CREAT and O_EXCL were used.
+
+@item EISDIR
+pathname refers to a directory.
+
+@item EACCES
+The requested access is not allowed.
+
+@item ENAMETOOLONG
+pathname was too long.
+
+@item ENOENT
+A directory component in pathname does not exist.
+
+@item ENODEV
+pathname refers to a device, pipe, named pipe or socket.
+
+@item EROFS
+pathname refers to a file on a read-only filesystem and
+write access was requested.
+
+@item EFAULT
+pathname is an invalid pointer value.
+
+@item ENOSPC
+No space on device to create the file.
+
+@item EMFILE
+The process already has the maximum number of files open.
+
+@item ENFILE
+The limit on the total number of files open on the system
+has been reached.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node close
+@unnumberedsubsubsec close
+@cindex close, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int close(int fd);
+
+@exdent Request:
+Fclose,fd
+
+@exdent Return value:
+close returns zero on success, or -1 if an error occurred.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EBADF
+fd isn't a valid open file descriptor.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node read
+@unnumberedsubsubsec read
+@cindex read, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int read(int fd, void *buf, unsigned int count);
+
+@exdent Request:
+Fread,fd,bufptr,count
+
+@exdent Return value:
+On success, the number of bytes read is returned.
+Zero indicates end of file. If count is zero, read
+returns zero as well. On error, -1 is returned.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EBADF
+fd is not a valid file descriptor or is not open for
+reading.
+
+@item EFAULT
+buf is an invalid pointer value.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node write
+@unnumberedsubsubsec write
+@cindex write, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int write(int fd, const void *buf, unsigned int count);
+
+@exdent Request:
+Fwrite,fd,bufptr,count
+
+@exdent Return value:
+On success, the number of bytes written are returned.
+Zero indicates nothing was written. On error, -1
+is returned.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EBADF
+fd is not a valid file descriptor or is not open for
+writing.
+
+@item EFAULT
+buf is an invalid pointer value.
+
+@item EFBIG
+An attempt was made to write a file that exceeds the
+host specific maximum file size allowed.
+
+@item ENOSPC
+No space on device to write the data.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node lseek
+@unnumberedsubsubsec lseek
+@cindex lseek, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+long lseek (int fd, long offset, int flag);
+
+@exdent Request:
+Flseek,fd,offset,flag
+@end smallexample
+
+@code{flag} is one of:
+
+@table @code
+@item SEEK_SET
+The offset is set to offset bytes.
+
+@item SEEK_CUR
+The offset is set to its current location plus offset
+bytes.
+
+@item SEEK_END
+The offset is set to the size of the file plus offset
+bytes.
+@end table
+
+@smallexample
+@exdent Return value:
+On success, the resulting unsigned offset in bytes from
+the beginning of the file is returned. Otherwise, a
+value of -1 is returned.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EBADF
+fd is not a valid open file descriptor.
+
+@item ESPIPE
+fd is associated with the @value{GDBN} console.
+
+@item EINVAL
+flag is not a proper value.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node rename
+@unnumberedsubsubsec rename
+@cindex rename, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int rename(const char *oldpath, const char *newpath);
+
+@exdent Request:
+Frename,oldpathptr/len,newpathptr/len
+
+@exdent Return value:
+On success, zero is returned. On error, -1 is returned.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EISDIR
+newpath is an existing directory, but oldpath is not a
+directory.
+
+@item EEXIST
+newpath is a non-empty directory.
+
+@item EBUSY
+oldpath or newpath is a directory that is in use by some
+process.
+
+@item EINVAL
+An attempt was made to make a directory a subdirectory
+of itself.
+
+@item ENOTDIR
+A component used as a directory in oldpath or new
+path is not a directory. Or oldpath is a directory
+and newpath exists but is not a directory.
+
+@item EFAULT
+oldpathptr or newpathptr are invalid pointer values.
+
+@item EACCES
+No access to the file or the path of the file.
+
+@item ENAMETOOLONG
+
+oldpath or newpath was too long.
+
+@item ENOENT
+A directory component in oldpath or newpath does not exist.
+
+@item EROFS
+The file is on a read-only filesystem.
+
+@item ENOSPC
+The device containing the file has no room for the new
+directory entry.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node unlink
+@unnumberedsubsubsec unlink
+@cindex unlink, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int unlink(const char *pathname);
+
+@exdent Request:
+Funlink,pathnameptr/len
+
+@exdent Return value:
+On success, zero is returned. On error, -1 is returned.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EACCES
+No access to the file or the path of the file.
+
+@item EPERM
+The system does not allow unlinking of directories.
+
+@item EBUSY
+The file pathname cannot be unlinked because it's
+being used by another process.
+
+@item EFAULT
+pathnameptr is an invalid pointer value.
+
+@item ENAMETOOLONG
+pathname was too long.
+
+@item ENOENT
+A directory component in pathname does not exist.
+
+@item ENOTDIR
+A component of the path is not a directory.
+
+@item EROFS
+The file is on a read-only filesystem.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node stat/fstat
+@unnumberedsubsubsec stat/fstat
+@cindex fstat, file-i/o system call
+@cindex stat, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int stat(const char *pathname, struct stat *buf);
+int fstat(int fd, struct stat *buf);
+
+@exdent Request:
+Fstat,pathnameptr/len,bufptr
+Ffstat,fd,bufptr
+
+@exdent Return value:
+On success, zero is returned. On error, -1 is returned.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EBADF
+fd is not a valid open file.
+
+@item ENOENT
+A directory component in pathname does not exist or the
+path is an empty string.
+
+@item ENOTDIR
+A component of the path is not a directory.
+
+@item EFAULT
+pathnameptr is an invalid pointer value.
+
+@item EACCES
+No access to the file or the path of the file.
+
+@item ENAMETOOLONG
+pathname was too long.
+
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node gettimeofday
+@unnumberedsubsubsec gettimeofday
+@cindex gettimeofday, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int gettimeofday(struct timeval *tv, void *tz);
+
+@exdent Request:
+Fgettimeofday,tvptr,tzptr
+
+@exdent Return value:
+On success, 0 is returned, -1 otherwise.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EINVAL
+tz is a non-NULL pointer.
+
+@item EFAULT
+tvptr and/or tzptr is an invalid pointer value.
+@end table
+
+@node isatty
+@unnumberedsubsubsec isatty
+@cindex isatty, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int isatty(int fd);
+
+@exdent Request:
+Fisatty,fd
+
+@exdent Return value:
+Returns 1 if fd refers to the @value{GDBN} console, 0 otherwise.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node system
+@unnumberedsubsubsec system
+@cindex system, file-i/o system call
+
+@smallexample
+@exdent Synopsis:
+int system(const char *command);
+
+@exdent Request:
+Fsystem,commandptr/len
+
+@exdent Return value:
+The value returned is -1 on error and the return status
+of the command otherwise. Only the exit status of the
+command is returned, which is extracted from the hosts
+system return value by calling WEXITSTATUS(retval).
+In case /bin/sh could not be executed, 127 is returned.
+
+@exdent Errors:
+@end smallexample
+
+@table @code
+@item EINTR
+The call was interrupted by the user.
+@end table
+
+@node Protocol specific representation of datatypes
+@subsection Protocol specific representation of datatypes
+@cindex protocol specific representation of datatypes, in file-i/o protocol
+
+@menu
+* Integral datatypes::
+* Pointer values::
+* struct stat::
+* struct timeval::
+@end menu
+
+@node Integral datatypes
+@unnumberedsubsubsec Integral datatypes
+@cindex integral datatypes, in file-i/o protocol
+
+The integral datatypes used in the system calls are
+
+@smallexample
+int@r{,} unsigned int@r{,} long@r{,} unsigned long@r{,} mode_t @r{and} time_t
+@end smallexample
+
+@code{Int}, @code{unsigned int}, @code{mode_t} and @code{time_t} are
+implemented as 32 bit values in this protocol.
+
+@code{Long} and @code{unsigned long} are implemented as 64 bit types.
+
+@xref{Limits}, for corresponding MIN and MAX values (similar to those
+in @file{limits.h}) to allow range checking on host and target.
+
+@code{time_t} datatypes are defined as seconds since the Epoch.
+
+All integral datatypes transferred as part of a memory read or write of a
+structured datatype e.g.@: a @code{struct stat} have to be given in big endian
+byte order.
+
+@node Pointer values
+@unnumberedsubsubsec Pointer values
+@cindex pointer values, in file-i/o protocol
+
+Pointers to target data are transmitted as they are. An exception
+is made for pointers to buffers for which the length isn't
+transmitted as part of the function call, namely strings. Strings
+are transmitted as a pointer/length pair, both as hex values, e.g.@:
+
+@smallexample
+@code{1aaf/12}
+@end smallexample
+
+@noindent
+which is a pointer to data of length 18 bytes at position 0x1aaf.
+The length is defined as the full string length in bytes, including
+the trailing null byte. Example:
+
+@smallexample
+``hello, world'' at address 0x123456
+@end smallexample
+
+@noindent
+is transmitted as
+
+@smallexample
+@code{123456/d}
+@end smallexample
+
+@node struct stat
+@unnumberedsubsubsec struct stat
+@cindex struct stat, in file-i/o protocol
+
+The buffer of type struct stat used by the target and @value{GDBN} is defined
+as follows:
+
+@smallexample
+struct stat @{
+ unsigned int st_dev; /* device */
+ unsigned int st_ino; /* inode */
+ mode_t st_mode; /* protection */
+ unsigned int st_nlink; /* number of hard links */
+ unsigned int st_uid; /* user ID of owner */
+ unsigned int st_gid; /* group ID of owner */
+ unsigned int st_rdev; /* device type (if inode device) */
+ unsigned long st_size; /* total size, in bytes */
+ unsigned long st_blksize; /* blocksize for filesystem I/O */
+ unsigned long st_blocks; /* number of blocks allocated */
+ time_t st_atime; /* time of last access */
+ time_t st_mtime; /* time of last modification */
+ time_t st_ctime; /* time of last change */
+@};
+@end smallexample
+
+The integral datatypes are conforming to the definitions given in the
+approriate section (see @ref{Integral datatypes}, for details) so this
+structure is of size 64 bytes.
+
+The values of several fields have a restricted meaning and/or
+range of values.
+
+@smallexample
+st_dev: 0 file
+ 1 console
+
+st_ino: No valid meaning for the target. Transmitted unchanged.
+
+st_mode: Valid mode bits are described in Appendix C. Any other
+ bits have currently no meaning for the target.
+
+st_uid: No valid meaning for the target. Transmitted unchanged.
+
+st_gid: No valid meaning for the target. Transmitted unchanged.
+
+st_rdev: No valid meaning for the target. Transmitted unchanged.
+
+st_atime, st_mtime, st_ctime:
+ These values have a host and file system dependent
+ accuracy. Especially on Windows hosts the file systems
+ don't support exact timing values.
+@end smallexample
+
+The target gets a struct stat of the above representation and is
+responsible to coerce it to the target representation before
+continuing.
+
+Note that due to size differences between the host and target
+representation of stat members, these members could eventually
+get truncated on the target.
+
+@node struct timeval
+@unnumberedsubsubsec struct timeval
+@cindex struct timeval, in file-i/o protocol
+
+The buffer of type struct timeval used by the target and @value{GDBN}
+is defined as follows:
+
+@smallexample
+struct timeval @{
+ time_t tv_sec; /* second */
+ long tv_usec; /* microsecond */
+@};
+@end smallexample
+
+The integral datatypes are conforming to the definitions given in the
+approriate section (see @ref{Integral datatypes}, for details) so this
+structure is of size 8 bytes.
+
+@node Constants
+@subsection Constants
+@cindex constants, in file-i/o protocol
+
+The following values are used for the constants inside of the
+protocol. @value{GDBN} and target are resposible to translate these
+values before and after the call as needed.
+
+@menu
+* Open flags::
+* mode_t values::
+* Errno values::
+* Lseek flags::
+* Limits::
+@end menu
+
+@node Open flags
+@unnumberedsubsubsec Open flags
+@cindex open flags, in file-i/o protocol
+
+All values are given in hexadecimal representation.
+
+@smallexample
+ O_RDONLY 0x0
+ O_WRONLY 0x1
+ O_RDWR 0x2
+ O_APPEND 0x8
+ O_CREAT 0x200
+ O_TRUNC 0x400
+ O_EXCL 0x800
+@end smallexample
+
+@node mode_t values
+@unnumberedsubsubsec mode_t values
+@cindex mode_t values, in file-i/o protocol
+
+All values are given in octal representation.
+
+@smallexample
+ S_IFREG 0100000
+ S_IFDIR 040000
+ S_IRUSR 0400
+ S_IWUSR 0200
+ S_IXUSR 0100
+ S_IRGRP 040
+ S_IWGRP 020
+ S_IXGRP 010
+ S_IROTH 04
+ S_IWOTH 02
+ S_IXOTH 01
+@end smallexample
+
+@node Errno values
+@unnumberedsubsubsec Errno values
+@cindex errno values, in file-i/o protocol
+
+All values are given in decimal representation.
+
+@smallexample
+ EPERM 1
+ ENOENT 2
+ EINTR 4
+ EBADF 9
+ EACCES 13
+ EFAULT 14
+ EBUSY 16
+ EEXIST 17
+ ENODEV 19
+ ENOTDIR 20
+ EISDIR 21
+ EINVAL 22
+ ENFILE 23
+ EMFILE 24
+ EFBIG 27
+ ENOSPC 28
+ ESPIPE 29
+ EROFS 30
+ ENAMETOOLONG 91
+ EUNKNOWN 9999
+@end smallexample
+
+ EUNKNOWN is used as a fallback error value if a host system returns
+ any error value not in the list of supported error numbers.
+
+@node Lseek flags
+@unnumberedsubsubsec Lseek flags
+@cindex lseek flags, in file-i/o protocol
+
+@smallexample
+ SEEK_SET 0
+ SEEK_CUR 1
+ SEEK_END 2
+@end smallexample
+
+@node Limits
+@unnumberedsubsubsec Limits
+@cindex limits, in file-i/o protocol
+
+All values are given in decimal representation.
+
+@smallexample
+ INT_MIN -2147483648
+ INT_MAX 2147483647
+ UINT_MAX 4294967295
+ LONG_MIN -9223372036854775808
+ LONG_MAX 9223372036854775807
+ ULONG_MAX 18446744073709551615
+@end smallexample
+
+@node File-I/O Examples
+@subsection File-I/O Examples
+@cindex file-i/o examples
+
+Example sequence of a write call, file descriptor 3, buffer is at target
+address 0x1234, 6 bytes should be written:
+
+@smallexample
+<- @code{Fwrite,3,1234,6}
+@emph{request memory read from target}
+-> @code{m1234,6}
+<- XXXXXX
+@emph{return "6 bytes written"}
+-> @code{F6}
+@end smallexample
+
+Example sequence of a read call, file descriptor 3, buffer is at target
+address 0x1234, 6 bytes should be read:
+
+@smallexample
+<- @code{Fread,3,1234,6}
+@emph{request memory write to target}
+-> @code{X1234,6:XXXXXX}
+@emph{return "6 bytes read"}
+-> @code{F6}
+@end smallexample
+
+Example sequence of a read call, call fails on the host due to invalid
+file descriptor (EBADF):
+
+@smallexample
+<- @code{Fread,3,1234,6}
+-> @code{F-1,9}
+@end smallexample
+
+Example sequence of a read call, user presses Ctrl-C before syscall on
+host is called:
+
+@smallexample
+<- @code{Fread,3,1234,6}
+-> @code{F-1,4,C}
+<- @code{T02}
+@end smallexample
+
+Example sequence of a read call, user presses Ctrl-C after syscall on
+host is called:
+
+@smallexample
+<- @code{Fread,3,1234,6}
+-> @code{X1234,6:XXXXXX}
+<- @code{T02}
+@end smallexample
+
+@include agentexpr.texi
+
+@include gpl.texi
+
+@raisesections
+@include fdl.texi
+@lowersections
+
+@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
+
+@bye
diff --git a/contrib/gdb/gdb/doc/gdbint.texinfo b/contrib/gdb/gdb/doc/gdbint.texinfo
new file mode 100644
index 0000000..2fe4b29
--- /dev/null
+++ b/contrib/gdb/gdb/doc/gdbint.texinfo
@@ -0,0 +1,6757 @@
+\input texinfo @c -*- texinfo -*-
+@setfilename gdbint.info
+@include gdb-cfg.texi
+@dircategory Software development
+@direntry
+* Gdb-Internals: (gdbint). The GNU debugger's internals.
+@end direntry
+
+@ifinfo
+This file documents the internals of the GNU debugger @value{GDBN}.
+Copyright 1990,1991,1992,1993,1994,1996,1998,1999,2000,2001,2002,2003,2004
+ Free Software Foundation, Inc.
+Contributed by Cygnus Solutions. Written by John Gilmore.
+Second Edition by Stan Shebs.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts. A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+@end ifinfo
+
+@setchapternewpage off
+@settitle @value{GDBN} Internals
+
+@syncodeindex fn cp
+@syncodeindex vr cp
+
+@titlepage
+@title @value{GDBN} Internals
+@subtitle{A guide to the internals of the GNU debugger}
+@author John Gilmore
+@author Cygnus Solutions
+@author Second Edition:
+@author Stan Shebs
+@author Cygnus Solutions
+@page
+@tex
+\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision$} % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Solutions\par
+\hfill \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990,1991,1992,1993,1994,1996,1998,1999,2000,2001,
+ 2002, 2003, 2004 Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts. A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+@end titlepage
+
+@contents
+
+@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, @value{GDBN}. It
+includes description of @value{GDBN}'s key algorithms and operations, as well
+as the mechanisms that adapt @value{GDBN} to specific hosts and targets.
+
+@menu
+* Requirements::
+* Overall Structure::
+* Algorithms::
+* User Interface::
+* libgdb::
+* Symbol Handling::
+* Language Support::
+* Host Definition::
+* Target Architecture Definition::
+* Target Vector Definition::
+* Native Debugging::
+* Support Libraries::
+* Coding::
+* Porting GDB::
+* Releasing GDB::
+* Testsuite::
+* Hints::
+
+* GDB Observers:: @value{GDBN} Currently available observers
+* GNU Free Documentation License:: The license for this documentation
+* Index::
+@end menu
+
+@node Requirements
+
+@chapter Requirements
+@cindex requirements for @value{GDBN}
+
+Before diving into the internals, you should understand the formal
+requirements and other expectations for @value{GDBN}. Although some
+of these may seem obvious, there have been proposals for @value{GDBN}
+that have run counter to these requirements.
+
+First of all, @value{GDBN} is a debugger. It's not designed to be a
+front panel for embedded systems. It's not a text editor. It's not a
+shell. It's not a programming environment.
+
+@value{GDBN} is an interactive tool. Although a batch mode is
+available, @value{GDBN}'s primary role is to interact with a human
+programmer.
+
+@value{GDBN} should be responsive to the user. A programmer hot on
+the trail of a nasty bug, and operating under a looming deadline, is
+going to be very impatient of everything, including the response time
+to debugger commands.
+
+@value{GDBN} should be relatively permissive, such as for expressions.
+While the compiler should be picky (or have the option to be made
+picky), since source code lives for a long time usually, the
+programmer doing debugging shouldn't be spending time figuring out to
+mollify the debugger.
+
+@value{GDBN} will be called upon to deal with really large programs.
+Executable sizes of 50 to 100 megabytes occur regularly, and we've
+heard reports of programs approaching 1 gigabyte in size.
+
+@value{GDBN} should be able to run everywhere. No other debugger is
+available for even half as many configurations as @value{GDBN}
+supports.
+
+
+@node Overall Structure
+
+@chapter Overall Structure
+
+@value{GDBN} consists of three major subsystems: user interface,
+symbol handling (the @dfn{symbol side}), and target system handling (the
+@dfn{target side}).
+
+The user interface consists of several actual interfaces, plus
+supporting code.
+
+The symbol side consists of object file readers, debugging info
+interpreters, symbol table management, source language expression
+parsing, type and value printing.
+
+The target side consists of execution control, stack frame analysis, and
+physical target manipulation.
+
+The target side/symbol side division is not formal, and there are a
+number of exceptions. For instance, core file support involves symbolic
+elements (the basic core file reader is in BFD) and target elements (it
+supplies the contents of memory and the values of registers). Instead,
+this division is useful for understanding how the minor subsystems
+should fit together.
+
+@section The Symbol Side
+
+The symbolic side of @value{GDBN} can be thought of as ``everything
+you can do in @value{GDBN} without having a live program running''.
+For instance, you can look at the types of variables, and evaluate
+many kinds of expressions.
+
+@section The Target Side
+
+The target side of @value{GDBN} is the ``bits and bytes manipulator''.
+Although it may make reference to symbolic info here and there, most
+of the target side will run with only a stripped executable
+available---or even no executable at all, in remote debugging cases.
+
+Operations such as disassembly, stack frame crawls, and register
+display, are able to work with no symbolic info at all. In some cases,
+such as disassembly, @value{GDBN} will use symbolic info to present addresses
+relative to symbols rather than as raw numbers, but it will work either
+way.
+
+@section Configurations
+
+@cindex host
+@cindex target
+@dfn{Host} refers to attributes of the system where @value{GDBN} 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 @value{GDBN} work ``native'' on a particular machine, you
+have to include all three kinds of information.
+
+
+@node Algorithms
+
+@chapter Algorithms
+@cindex algorithms
+
+@value{GDBN} uses a number of debugging-specific algorithms. They are
+often not very complicated, but get lost in the thicket of special
+cases and real-world issues. This chapter describes the basic
+algorithms and mentions some of the specific target definitions that
+they use.
+
+@section Frames
+
+@cindex frame
+@cindex call stack frame
+A frame is a construct that @value{GDBN} uses to keep track of calling
+and called functions.
+
+@findex create_new_frame
+@vindex FRAME_FP
+@code{FRAME_FP} in the machine description has no meaning to the
+machine-independent part of @value{GDBN}, except that it is used when
+setting up a new frame from scratch, as follows:
+
+@smallexample
+create_new_frame (read_register (DEPRECATED_FP_REGNUM), read_pc ()));
+@end smallexample
+
+@cindex frame pointer register
+Other than that, all the meaning imparted to @code{DEPRECATED_FP_REGNUM}
+is imparted by the machine-dependent code. So,
+@code{DEPRECATED_FP_REGNUM} can have any value that is convenient for
+the code that creates new frames. (@code{create_new_frame} calls
+@code{DEPRECATED_INIT_EXTRA_FRAME_INFO} if it is defined; that is where
+you should use the @code{DEPRECATED_FP_REGNUM} value, if your frames are
+nonstandard.)
+
+@cindex frame chain
+Given a @value{GDBN} frame, define @code{DEPRECATED_FRAME_CHAIN} to
+determine the address of the calling function's frame. This will be
+used to create a new @value{GDBN} frame struct, and then
+@code{DEPRECATED_INIT_EXTRA_FRAME_INFO} and
+@code{DEPRECATED_INIT_FRAME_PC} will be called for the new frame.
+
+@section Breakpoint Handling
+
+@cindex breakpoints
+In general, a breakpoint is a user-designated location in the program
+where the user wants to regain control if program execution ever reaches
+that location.
+
+There are two main ways to implement breakpoints; either as ``hardware''
+breakpoints or as ``software'' breakpoints.
+
+@cindex hardware breakpoints
+@cindex program counter
+Hardware breakpoints are sometimes available as a builtin debugging
+features with some chips. Typically these work by having dedicated
+register into which the breakpoint address may be stored. If the PC
+(shorthand for @dfn{program counter})
+ever matches a value in a breakpoint registers, the CPU raises an
+exception and reports it to @value{GDBN}.
+
+Another possibility is when an emulator is in use; many emulators
+include circuitry that watches the address lines coming out from the
+processor, and force it to stop if the address matches a breakpoint's
+address.
+
+A third possibility is that the target already has the ability to do
+breakpoints somehow; for instance, a ROM monitor may do its own
+software breakpoints. So although these are not literally ``hardware
+breakpoints'', from @value{GDBN}'s point of view they work the same;
+@value{GDBN} need not do anything more than set the breakpoint and wait
+for something to happen.
+
+Since they depend on hardware resources, hardware breakpoints may be
+limited in number; when the user asks for more, @value{GDBN} will
+start trying to set software breakpoints. (On some architectures,
+notably the 32-bit x86 platforms, @value{GDBN} cannot always know
+whether there's enough hardware resources to insert all the hardware
+breakpoints and watchpoints. On those platforms, @value{GDBN} prints
+an error message only when the program being debugged is continued.)
+
+@cindex software breakpoints
+Software breakpoints require @value{GDBN} to do somewhat more work.
+The basic theory is that @value{GDBN} will replace a program
+instruction with a trap, illegal divide, or some other instruction
+that will cause an exception, and then when it's encountered,
+@value{GDBN} will take the exception and stop the program. When the
+user says to continue, @value{GDBN} will restore the original
+instruction, single-step, re-insert the trap, and continue on.
+
+Since it literally overwrites the program being tested, the program area
+must be writable, so this technique won't work on programs in ROM. It
+can also distort the behavior of programs that examine themselves,
+although such a situation would be highly unusual.
+
+Also, the software breakpoint instruction should be the smallest size of
+instruction, so it doesn't overwrite an instruction that might be a jump
+target, and cause disaster when the program jumps into the middle of the
+breakpoint instruction. (Strictly speaking, the breakpoint must be no
+larger than the smallest interval between instructions that may be jump
+targets; perhaps there is an architecture where only even-numbered
+instructions may jumped to.) Note that it's possible for an instruction
+set not to have any instructions usable for a software breakpoint,
+although in practice only the ARC has failed to define such an
+instruction.
+
+@findex BREAKPOINT
+The basic definition of the software breakpoint is the macro
+@code{BREAKPOINT}.
+
+Basic breakpoint object handling is in @file{breakpoint.c}. However,
+much of the interesting breakpoint action is in @file{infrun.c}.
+
+@section Single Stepping
+
+@section Signal Handling
+
+@section Thread Handling
+
+@section Inferior Function Calls
+
+@section Longjmp Support
+
+@cindex @code{longjmp} debugging
+@value{GDBN} 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 output of the @samp{maint info breakpoint}
+command.
+
+@findex GET_LONGJMP_TARGET
+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-@var{target}.h} file. Look in @file{tm-sun4os4.h} and
+@file{sparc-tdep.c} for examples of how to do this.
+
+@section Watchpoints
+@cindex watchpoints
+
+Watchpoints are a special kind of breakpoints (@pxref{Algorithms,
+breakpoints}) which break when data is accessed rather than when some
+instruction is executed. When you have data which changes without
+your knowing what code does that, watchpoints are the silver bullet to
+hunt down and kill such bugs.
+
+@cindex hardware watchpoints
+@cindex software watchpoints
+Watchpoints can be either hardware-assisted or not; the latter type is
+known as ``software watchpoints.'' @value{GDBN} always uses
+hardware-assisted watchpoints if they are available, and falls back on
+software watchpoints otherwise. Typical situations where @value{GDBN}
+will use software watchpoints are:
+
+@itemize @bullet
+@item
+The watched memory region is too large for the underlying hardware
+watchpoint support. For example, each x86 debug register can watch up
+to 4 bytes of memory, so trying to watch data structures whose size is
+more than 16 bytes will cause @value{GDBN} to use software
+watchpoints.
+
+@item
+The value of the expression to be watched depends on data held in
+registers (as opposed to memory).
+
+@item
+Too many different watchpoints requested. (On some architectures,
+this situation is impossible to detect until the debugged program is
+resumed.) Note that x86 debug registers are used both for hardware
+breakpoints and for watchpoints, so setting too many hardware
+breakpoints might cause watchpoint insertion to fail.
+
+@item
+No hardware-assisted watchpoints provided by the target
+implementation.
+@end itemize
+
+Software watchpoints are very slow, since @value{GDBN} needs to
+single-step the program being debugged and test the value of the
+watched expression(s) after each instruction. The rest of this
+section is mostly irrelevant for software watchpoints.
+
+@value{GDBN} uses several macros and primitives to support hardware
+watchpoints:
+
+@table @code
+@findex TARGET_HAS_HARDWARE_WATCHPOINTS
+@item TARGET_HAS_HARDWARE_WATCHPOINTS
+If defined, the target supports hardware watchpoints.
+
+@findex TARGET_CAN_USE_HARDWARE_WATCHPOINT
+@item TARGET_CAN_USE_HARDWARE_WATCHPOINT (@var{type}, @var{count}, @var{other})
+Return the number of hardware watchpoints of type @var{type} that are
+possible to be set. The value is positive if @var{count} watchpoints
+of this type can be set, zero if setting watchpoints of this type is
+not supported, and negative if @var{count} is more than the maximum
+number of watchpoints of type @var{type} that can be set. @var{other}
+is non-zero if other types of watchpoints are currently enabled (there
+are architectures which cannot set watchpoints of different types at
+the same time).
+
+@findex TARGET_REGION_OK_FOR_HW_WATCHPOINT
+@item TARGET_REGION_OK_FOR_HW_WATCHPOINT (@var{addr}, @var{len})
+Return non-zero if hardware watchpoints can be used to watch a region
+whose address is @var{addr} and whose length in bytes is @var{len}.
+
+@findex TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT
+@item TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT (@var{size})
+Return non-zero if hardware watchpoints can be used to watch a region
+whose size is @var{size}. @value{GDBN} only uses this macro as a
+fall-back, in case @code{TARGET_REGION_OK_FOR_HW_WATCHPOINT} is not
+defined.
+
+@findex TARGET_DISABLE_HW_WATCHPOINTS
+@item TARGET_DISABLE_HW_WATCHPOINTS (@var{pid})
+Disables watchpoints in the process identified by @var{pid}. This is
+used, e.g., on HP-UX which provides operations to disable and enable
+the page-level memory protection that implements hardware watchpoints
+on that platform.
+
+@findex TARGET_ENABLE_HW_WATCHPOINTS
+@item TARGET_ENABLE_HW_WATCHPOINTS (@var{pid})
+Enables watchpoints in the process identified by @var{pid}. This is
+used, e.g., on HP-UX which provides operations to disable and enable
+the page-level memory protection that implements hardware watchpoints
+on that platform.
+
+@findex target_insert_watchpoint
+@findex target_remove_watchpoint
+@item target_insert_watchpoint (@var{addr}, @var{len}, @var{type})
+@itemx target_remove_watchpoint (@var{addr}, @var{len}, @var{type})
+Insert or remove a hardware watchpoint starting at @var{addr}, for
+@var{len} bytes. @var{type} is the watchpoint type, one of the
+possible values of the enumerated data type @code{target_hw_bp_type},
+defined by @file{breakpoint.h} as follows:
+
+@smallexample
+ enum target_hw_bp_type
+ @{
+ hw_write = 0, /* Common (write) HW watchpoint */
+ hw_read = 1, /* Read HW watchpoint */
+ hw_access = 2, /* Access (read or write) HW watchpoint */
+ hw_execute = 3 /* Execute HW breakpoint */
+ @};
+@end smallexample
+
+@noindent
+These two macros should return 0 for success, non-zero for failure.
+
+@cindex insert or remove hardware breakpoint
+@findex target_remove_hw_breakpoint
+@findex target_insert_hw_breakpoint
+@item target_remove_hw_breakpoint (@var{addr}, @var{shadow})
+@itemx target_insert_hw_breakpoint (@var{addr}, @var{shadow})
+Insert or remove a hardware-assisted breakpoint at address @var{addr}.
+Returns zero for success, non-zero for failure. @var{shadow} is the
+real contents of the byte where the breakpoint has been inserted; it
+is generally not valid when hardware breakpoints are used, but since
+no other code touches these values, the implementations of the above
+two macros can use them for their internal purposes.
+
+@findex target_stopped_data_address
+@item target_stopped_data_address ()
+If the inferior has some watchpoint that triggered, return the address
+associated with that watchpoint. Otherwise, return zero.
+
+@findex HAVE_STEPPABLE_WATCHPOINT
+@item HAVE_STEPPABLE_WATCHPOINT
+If defined to a non-zero value, it is not necessary to disable a
+watchpoint to step over it.
+
+@findex HAVE_NONSTEPPABLE_WATCHPOINT
+@item HAVE_NONSTEPPABLE_WATCHPOINT
+If defined to a non-zero value, @value{GDBN} should disable a
+watchpoint to step the inferior over it.
+
+@findex HAVE_CONTINUABLE_WATCHPOINT
+@item HAVE_CONTINUABLE_WATCHPOINT
+If defined to a non-zero value, it is possible to continue the
+inferior after a watchpoint has been hit.
+
+@findex CANNOT_STEP_HW_WATCHPOINTS
+@item CANNOT_STEP_HW_WATCHPOINTS
+If this is defined to a non-zero value, @value{GDBN} will remove all
+watchpoints before stepping the inferior.
+
+@findex STOPPED_BY_WATCHPOINT
+@item STOPPED_BY_WATCHPOINT (@var{wait_status})
+Return non-zero if stopped by a watchpoint. @var{wait_status} is of
+the type @code{struct target_waitstatus}, defined by @file{target.h}.
+@end table
+
+@subsection x86 Watchpoints
+@cindex x86 debug registers
+@cindex watchpoints, on x86
+
+The 32-bit Intel x86 (a.k.a.@: ia32) processors feature special debug
+registers designed to facilitate debugging. @value{GDBN} provides a
+generic library of functions that x86-based ports can use to implement
+support for watchpoints and hardware-assisted breakpoints. This
+subsection documents the x86 watchpoint facilities in @value{GDBN}.
+
+To use the generic x86 watchpoint support, a port should do the
+following:
+
+@itemize @bullet
+@findex I386_USE_GENERIC_WATCHPOINTS
+@item
+Define the macro @code{I386_USE_GENERIC_WATCHPOINTS} somewhere in the
+target-dependent headers.
+
+@item
+Include the @file{config/i386/nm-i386.h} header file @emph{after}
+defining @code{I386_USE_GENERIC_WATCHPOINTS}.
+
+@item
+Add @file{i386-nat.o} to the value of the Make variable
+@code{NATDEPFILES} (@pxref{Native Debugging, NATDEPFILES}) or
+@code{TDEPFILES} (@pxref{Target Architecture Definition, TDEPFILES}).
+
+@item
+Provide implementations for the @code{I386_DR_LOW_*} macros described
+below. Typically, each macro should call a target-specific function
+which does the real work.
+@end itemize
+
+The x86 watchpoint support works by maintaining mirror images of the
+debug registers. Values are copied between the mirror images and the
+real debug registers via a set of macros which each target needs to
+provide:
+
+@table @code
+@findex I386_DR_LOW_SET_CONTROL
+@item I386_DR_LOW_SET_CONTROL (@var{val})
+Set the Debug Control (DR7) register to the value @var{val}.
+
+@findex I386_DR_LOW_SET_ADDR
+@item I386_DR_LOW_SET_ADDR (@var{idx}, @var{addr})
+Put the address @var{addr} into the debug register number @var{idx}.
+
+@findex I386_DR_LOW_RESET_ADDR
+@item I386_DR_LOW_RESET_ADDR (@var{idx})
+Reset (i.e.@: zero out) the address stored in the debug register
+number @var{idx}.
+
+@findex I386_DR_LOW_GET_STATUS
+@item I386_DR_LOW_GET_STATUS
+Return the value of the Debug Status (DR6) register. This value is
+used immediately after it is returned by
+@code{I386_DR_LOW_GET_STATUS}, so as to support per-thread status
+register values.
+@end table
+
+For each one of the 4 debug registers (whose indices are from 0 to 3)
+that store addresses, a reference count is maintained by @value{GDBN},
+to allow sharing of debug registers by several watchpoints. This
+allows users to define several watchpoints that watch the same
+expression, but with different conditions and/or commands, without
+wasting debug registers which are in short supply. @value{GDBN}
+maintains the reference counts internally, targets don't have to do
+anything to use this feature.
+
+The x86 debug registers can each watch a region that is 1, 2, or 4
+bytes long. The ia32 architecture requires that each watched region
+be appropriately aligned: 2-byte region on 2-byte boundary, 4-byte
+region on 4-byte boundary. However, the x86 watchpoint support in
+@value{GDBN} can watch unaligned regions and regions larger than 4
+bytes (up to 16 bytes) by allocating several debug registers to watch
+a single region. This allocation of several registers per a watched
+region is also done automatically without target code intervention.
+
+The generic x86 watchpoint support provides the following API for the
+@value{GDBN}'s application code:
+
+@table @code
+@findex i386_region_ok_for_watchpoint
+@item i386_region_ok_for_watchpoint (@var{addr}, @var{len})
+The macro @code{TARGET_REGION_OK_FOR_HW_WATCHPOINT} is set to call
+this function. It counts the number of debug registers required to
+watch a given region, and returns a non-zero value if that number is
+less than 4, the number of debug registers available to x86
+processors.
+
+@findex i386_stopped_data_address
+@item i386_stopped_data_address (void)
+The macros @code{STOPPED_BY_WATCHPOINT} and
+@code{target_stopped_data_address} are set to call this function. The
+argument passed to @code{STOPPED_BY_WATCHPOINT} is ignored. This
+function examines the breakpoint condition bits in the DR6 Debug
+Status register, as returned by the @code{I386_DR_LOW_GET_STATUS}
+macro, and returns the address associated with the first bit that is
+set in DR6.
+
+@findex i386_insert_watchpoint
+@findex i386_remove_watchpoint
+@item i386_insert_watchpoint (@var{addr}, @var{len}, @var{type})
+@itemx i386_remove_watchpoint (@var{addr}, @var{len}, @var{type})
+Insert or remove a watchpoint. The macros
+@code{target_insert_watchpoint} and @code{target_remove_watchpoint}
+are set to call these functions. @code{i386_insert_watchpoint} first
+looks for a debug register which is already set to watch the same
+region for the same access types; if found, it just increments the
+reference count of that debug register, thus implementing debug
+register sharing between watchpoints. If no such register is found,
+the function looks for a vacant debug register, sets its mirrored
+value to @var{addr}, sets the mirrored value of DR7 Debug Control
+register as appropriate for the @var{len} and @var{type} parameters,
+and then passes the new values of the debug register and DR7 to the
+inferior by calling @code{I386_DR_LOW_SET_ADDR} and
+@code{I386_DR_LOW_SET_CONTROL}. If more than one debug register is
+required to cover the given region, the above process is repeated for
+each debug register.
+
+@code{i386_remove_watchpoint} does the opposite: it resets the address
+in the mirrored value of the debug register and its read/write and
+length bits in the mirrored value of DR7, then passes these new
+values to the inferior via @code{I386_DR_LOW_RESET_ADDR} and
+@code{I386_DR_LOW_SET_CONTROL}. If a register is shared by several
+watchpoints, each time a @code{i386_remove_watchpoint} is called, it
+decrements the reference count, and only calls
+@code{I386_DR_LOW_RESET_ADDR} and @code{I386_DR_LOW_SET_CONTROL} when
+the count goes to zero.
+
+@findex i386_insert_hw_breakpoint
+@findex i386_remove_hw_breakpoint
+@item i386_insert_hw_breakpoint (@var{addr}, @var{shadow}
+@itemx i386_remove_hw_breakpoint (@var{addr}, @var{shadow})
+These functions insert and remove hardware-assisted breakpoints. The
+macros @code{target_insert_hw_breakpoint} and
+@code{target_remove_hw_breakpoint} are set to call these functions.
+These functions work like @code{i386_insert_watchpoint} and
+@code{i386_remove_watchpoint}, respectively, except that they set up
+the debug registers to watch instruction execution, and each
+hardware-assisted breakpoint always requires exactly one debug
+register.
+
+@findex i386_stopped_by_hwbp
+@item i386_stopped_by_hwbp (void)
+This function returns non-zero if the inferior has some watchpoint or
+hardware breakpoint that triggered. It works like
+@code{i386_stopped_data_address}, except that it doesn't return the
+address whose watchpoint triggered.
+
+@findex i386_cleanup_dregs
+@item i386_cleanup_dregs (void)
+This function clears all the reference counts, addresses, and control
+bits in the mirror images of the debug registers. It doesn't affect
+the actual debug registers in the inferior process.
+@end table
+
+@noindent
+@strong{Notes:}
+@enumerate 1
+@item
+x86 processors support setting watchpoints on I/O reads or writes.
+However, since no target supports this (as of March 2001), and since
+@code{enum target_hw_bp_type} doesn't even have an enumeration for I/O
+watchpoints, this feature is not yet available to @value{GDBN} running
+on x86.
+
+@item
+x86 processors can enable watchpoints locally, for the current task
+only, or globally, for all the tasks. For each debug register,
+there's a bit in the DR7 Debug Control register that determines
+whether the associated address is watched locally or globally. The
+current implementation of x86 watchpoint support in @value{GDBN}
+always sets watchpoints to be locally enabled, since global
+watchpoints might interfere with the underlying OS and are probably
+unavailable in many platforms.
+@end enumerate
+
+@section Observing changes in @value{GDBN} internals
+@cindex observer pattern interface
+@cindex notifications about changes in internals
+
+In order to function properly, several modules need to be notified when
+some changes occur in the @value{GDBN} internals. Traditionally, these
+modules have relied on several paradigms, the most common ones being
+hooks and gdb-events. Unfortunately, none of these paradigms was
+versatile enough to become the standard notification mechanism in
+@value{GDBN}. The fact that they only supported one ``client'' was also
+a strong limitation.
+
+A new paradigm, based on the Observer pattern of the @cite{Design
+Patterns} book, has therefore been implemented. The goal was to provide
+a new interface overcoming the issues with the notification mechanisms
+previously available. This new interface needed to be strongly typed,
+easy to extend, and versatile enough to be used as the standard
+interface when adding new notifications.
+
+See @ref{GDB Observers} for a brief description of the observers
+currently implemented in GDB. The rationale for the current
+implementation is also briefly discussed.
+
+@node User Interface
+
+@chapter User Interface
+
+@value{GDBN} has several user interfaces. Although the command-line interface
+is the most common and most familiar, there are others.
+
+@section Command Interpreter
+
+@cindex command interpreter
+@cindex CLI
+The command interpreter in @value{GDBN} is fairly simple. It is designed to
+allow for the set of commands to be augmented dynamically, and also
+has a recursive subcommand capability, where the first argument to
+a command may itself direct a lookup on a different command list.
+
+For instance, the @samp{set} command just starts a lookup on the
+@code{setlist} command list, while @samp{set thread} recurses
+to the @code{set_thread_cmd_list}.
+
+@findex add_cmd
+@findex add_com
+To add commands in general, use @code{add_cmd}. @code{add_com} adds to
+the main command list, and should be used for those commands. The usual
+place to add commands is in the @code{_initialize_@var{xyz}} routines at
+the ends of most source files.
+
+@findex add_setshow_cmd
+@findex add_setshow_cmd_full
+To add paired @samp{set} and @samp{show} commands, use
+@code{add_setshow_cmd} or @code{add_setshow_cmd_full}. The former is
+a slightly simpler interface which is useful when you don't need to
+further modify the new command structures, while the latter returns
+the new command structures for manipulation.
+
+@cindex deprecating commands
+@findex deprecate_cmd
+Before removing commands from the command set it is a good idea to
+deprecate them for some time. Use @code{deprecate_cmd} on commands or
+aliases to set the deprecated flag. @code{deprecate_cmd} takes a
+@code{struct cmd_list_element} as it's first argument. You can use the
+return value from @code{add_com} or @code{add_cmd} to deprecate the
+command immediately after it is created.
+
+The first time a command is used the user will be warned and offered a
+replacement (if one exists). Note that the replacement string passed to
+@code{deprecate_cmd} should be the full name of the command, i.e. the
+entire string the user should type at the command line.
+
+@section UI-Independent Output---the @code{ui_out} Functions
+@c This section is based on the documentation written by Fernando
+@c Nasser <fnasser@redhat.com>.
+
+@cindex @code{ui_out} functions
+The @code{ui_out} functions present an abstraction level for the
+@value{GDBN} output code. They hide the specifics of different user
+interfaces supported by @value{GDBN}, and thus free the programmer
+from the need to write several versions of the same code, one each for
+every UI, to produce output.
+
+@subsection Overview and Terminology
+
+In general, execution of each @value{GDBN} command produces some sort
+of output, and can even generate an input request.
+
+Output can be generated for the following purposes:
+
+@itemize @bullet
+@item
+to display a @emph{result} of an operation;
+
+@item
+to convey @emph{info} or produce side-effects of a requested
+operation;
+
+@item
+to provide a @emph{notification} of an asynchronous event (including
+progress indication of a prolonged asynchronous operation);
+
+@item
+to display @emph{error messages} (including warnings);
+
+@item
+to show @emph{debug data};
+
+@item
+to @emph{query} or prompt a user for input (a special case).
+@end itemize
+
+@noindent
+This section mainly concentrates on how to build result output,
+although some of it also applies to other kinds of output.
+
+Generation of output that displays the results of an operation
+involves one or more of the following:
+
+@itemize @bullet
+@item
+output of the actual data
+
+@item
+formatting the output as appropriate for console output, to make it
+easily readable by humans
+
+@item
+machine oriented formatting--a more terse formatting to allow for easy
+parsing by programs which read @value{GDBN}'s output
+
+@item
+annotation, whose purpose is to help legacy GUIs to identify interesting
+parts in the output
+@end itemize
+
+The @code{ui_out} routines take care of the first three aspects.
+Annotations are provided by separate annotation routines. Note that use
+of annotations for an interface between a GUI and @value{GDBN} is
+deprecated.
+
+Output can be in the form of a single item, which we call a @dfn{field};
+a @dfn{list} consisting of identical fields; a @dfn{tuple} consisting of
+non-identical fields; or a @dfn{table}, which is a tuple consisting of a
+header and a body. In a BNF-like form:
+
+@table @code
+@item <table> @expansion{}
+@code{<header> <body>}
+@item <header> @expansion{}
+@code{@{ <column> @}}
+@item <column> @expansion{}
+@code{<width> <alignment> <title>}
+@item <body> @expansion{}
+@code{@{<row>@}}
+@end table
+
+
+@subsection General Conventions
+
+Most @code{ui_out} routines are of type @code{void}, the exceptions are
+@code{ui_out_stream_new} (which returns a pointer to the newly created
+object) and the @code{make_cleanup} routines.
+
+The first parameter is always the @code{ui_out} vector object, a pointer
+to a @code{struct ui_out}.
+
+The @var{format} parameter is like in @code{printf} family of functions.
+When it is present, there must also be a variable list of arguments
+sufficient used to satisfy the @code{%} specifiers in the supplied
+format.
+
+When a character string argument is not used in a @code{ui_out} function
+call, a @code{NULL} pointer has to be supplied instead.
+
+
+@subsection Table, Tuple and List Functions
+
+@cindex list output functions
+@cindex table output functions
+@cindex tuple output functions
+This section introduces @code{ui_out} routines for building lists,
+tuples and tables. The routines to output the actual data items
+(fields) are presented in the next section.
+
+To recap: A @dfn{tuple} is a sequence of @dfn{fields}, each field
+containing information about an object; a @dfn{list} is a sequence of
+fields where each field describes an identical object.
+
+Use the @dfn{table} functions when your output consists of a list of
+rows (tuples) and the console output should include a heading. Use this
+even when you are listing just one object but you still want the header.
+
+@cindex nesting level in @code{ui_out} functions
+Tables can not be nested. Tuples and lists can be nested up to a
+maximum of five levels.
+
+The overall structure of the table output code is something like this:
+
+@smallexample
+ ui_out_table_begin
+ ui_out_table_header
+ @dots{}
+ ui_out_table_body
+ ui_out_tuple_begin
+ ui_out_field_*
+ @dots{}
+ ui_out_tuple_end
+ @dots{}
+ ui_out_table_end
+@end smallexample
+
+Here is the description of table-, tuple- and list-related @code{ui_out}
+functions:
+
+@deftypefun void ui_out_table_begin (struct ui_out *@var{uiout}, int @var{nbrofcols}, int @var{nr_rows}, const char *@var{tblid})
+The function @code{ui_out_table_begin} marks the beginning of the output
+of a table. It should always be called before any other @code{ui_out}
+function for a given table. @var{nbrofcols} is the number of columns in
+the table. @var{nr_rows} is the number of rows in the table.
+@var{tblid} is an optional string identifying the table. The string
+pointed to by @var{tblid} is copied by the implementation of
+@code{ui_out_table_begin}, so the application can free the string if it
+was @code{malloc}ed.
+
+The companion function @code{ui_out_table_end}, described below, marks
+the end of the table's output.
+@end deftypefun
+
+@deftypefun void ui_out_table_header (struct ui_out *@var{uiout}, int @var{width}, enum ui_align @var{alignment}, const char *@var{colhdr})
+@code{ui_out_table_header} provides the header information for a single
+table column. You call this function several times, one each for every
+column of the table, after @code{ui_out_table_begin}, but before
+@code{ui_out_table_body}.
+
+The value of @var{width} gives the column width in characters. The
+value of @var{alignment} is one of @code{left}, @code{center}, and
+@code{right}, and it specifies how to align the header: left-justify,
+center, or right-justify it. @var{colhdr} points to a string that
+specifies the column header; the implementation copies that string, so
+column header strings in @code{malloc}ed storage can be freed after the
+call.
+@end deftypefun
+
+@deftypefun void ui_out_table_body (struct ui_out *@var{uiout})
+This function delimits the table header from the table body.
+@end deftypefun
+
+@deftypefun void ui_out_table_end (struct ui_out *@var{uiout})
+This function signals the end of a table's output. It should be called
+after the table body has been produced by the list and field output
+functions.
+
+There should be exactly one call to @code{ui_out_table_end} for each
+call to @code{ui_out_table_begin}, otherwise the @code{ui_out} functions
+will signal an internal error.
+@end deftypefun
+
+The output of the tuples that represent the table rows must follow the
+call to @code{ui_out_table_body} and precede the call to
+@code{ui_out_table_end}. You build a tuple by calling
+@code{ui_out_tuple_begin} and @code{ui_out_tuple_end}, with suitable
+calls to functions which actually output fields between them.
+
+@deftypefun void ui_out_tuple_begin (struct ui_out *@var{uiout}, const char *@var{id})
+This function marks the beginning of a tuple output. @var{id} points
+to an optional string that identifies the tuple; it is copied by the
+implementation, and so strings in @code{malloc}ed storage can be freed
+after the call.
+@end deftypefun
+
+@deftypefun void ui_out_tuple_end (struct ui_out *@var{uiout})
+This function signals an end of a tuple output. There should be exactly
+one call to @code{ui_out_tuple_end} for each call to
+@code{ui_out_tuple_begin}, otherwise an internal @value{GDBN} error will
+be signaled.
+@end deftypefun
+
+@deftypefun struct cleanup *make_cleanup_ui_out_tuple_begin_end (struct ui_out *@var{uiout}, const char *@var{id})
+This function first opens the tuple and then establishes a cleanup
+(@pxref{Coding, Cleanups}) to close the tuple. It provides a convenient
+and correct implementation of the non-portable@footnote{The function
+cast is not portable ISO C.} code sequence:
+@smallexample
+struct cleanup *old_cleanup;
+ui_out_tuple_begin (uiout, "...");
+old_cleanup = make_cleanup ((void(*)(void *)) ui_out_tuple_end,
+ uiout);
+@end smallexample
+@end deftypefun
+
+@deftypefun void ui_out_list_begin (struct ui_out *@var{uiout}, const char *@var{id})
+This function marks the beginning of a list output. @var{id} points to
+an optional string that identifies the list; it is copied by the
+implementation, and so strings in @code{malloc}ed storage can be freed
+after the call.
+@end deftypefun
+
+@deftypefun void ui_out_list_end (struct ui_out *@var{uiout})
+This function signals an end of a list output. There should be exactly
+one call to @code{ui_out_list_end} for each call to
+@code{ui_out_list_begin}, otherwise an internal @value{GDBN} error will
+be signaled.
+@end deftypefun
+
+@deftypefun struct cleanup *make_cleanup_ui_out_list_begin_end (struct ui_out *@var{uiout}, const char *@var{id})
+Similar to @code{make_cleanup_ui_out_tuple_begin_end}, this function
+opens a list and then establishes cleanup (@pxref{Coding, Cleanups})
+that will close the list.list.
+@end deftypefun
+
+@subsection Item Output Functions
+
+@cindex item output functions
+@cindex field output functions
+@cindex data output
+The functions described below produce output for the actual data
+items, or fields, which contain information about the object.
+
+Choose the appropriate function accordingly to your particular needs.
+
+@deftypefun void ui_out_field_fmt (struct ui_out *@var{uiout}, char *@var{fldname}, char *@var{format}, ...)
+This is the most general output function. It produces the
+representation of the data in the variable-length argument list
+according to formatting specifications in @var{format}, a
+@code{printf}-like format string. The optional argument @var{fldname}
+supplies the name of the field. The data items themselves are
+supplied as additional arguments after @var{format}.
+
+This generic function should be used only when it is not possible to
+use one of the specialized versions (see below).
+@end deftypefun
+
+@deftypefun void ui_out_field_int (struct ui_out *@var{uiout}, const char *@var{fldname}, int @var{value})
+This function outputs a value of an @code{int} variable. It uses the
+@code{"%d"} output conversion specification. @var{fldname} specifies
+the name of the field.
+@end deftypefun
+
+@deftypefun void ui_out_field_fmt_int (struct ui_out *@var{uiout}, int @var{width}, enum ui_align @var{alignment}, const char *@var{fldname}, int @var{value})
+This function outputs a value of an @code{int} variable. It differs from
+@code{ui_out_field_int} in that the caller specifies the desired @var{width} and @var{alignment} of the output.
+@var{fldname} specifies
+the name of the field.
+@end deftypefun
+
+@deftypefun void ui_out_field_core_addr (struct ui_out *@var{uiout}, const char *@var{fldname}, CORE_ADDR @var{address})
+This function outputs an address.
+@end deftypefun
+
+@deftypefun void ui_out_field_string (struct ui_out *@var{uiout}, const char *@var{fldname}, const char *@var{string})
+This function outputs a string using the @code{"%s"} conversion
+specification.
+@end deftypefun
+
+Sometimes, there's a need to compose your output piece by piece using
+functions that operate on a stream, such as @code{value_print} or
+@code{fprintf_symbol_filtered}. These functions accept an argument of
+the type @code{struct ui_file *}, a pointer to a @code{ui_file} object
+used to store the data stream used for the output. When you use one
+of these functions, you need a way to pass their results stored in a
+@code{ui_file} object to the @code{ui_out} functions. To this end,
+you first create a @code{ui_stream} object by calling
+@code{ui_out_stream_new}, pass the @code{stream} member of that
+@code{ui_stream} object to @code{value_print} and similar functions,
+and finally call @code{ui_out_field_stream} to output the field you
+constructed. When the @code{ui_stream} object is no longer needed,
+you should destroy it and free its memory by calling
+@code{ui_out_stream_delete}.
+
+@deftypefun struct ui_stream *ui_out_stream_new (struct ui_out *@var{uiout})
+This function creates a new @code{ui_stream} object which uses the
+same output methods as the @code{ui_out} object whose pointer is
+passed in @var{uiout}. It returns a pointer to the newly created
+@code{ui_stream} object.
+@end deftypefun
+
+@deftypefun void ui_out_stream_delete (struct ui_stream *@var{streambuf})
+This functions destroys a @code{ui_stream} object specified by
+@var{streambuf}.
+@end deftypefun
+
+@deftypefun void ui_out_field_stream (struct ui_out *@var{uiout}, const char *@var{fieldname}, struct ui_stream *@var{streambuf})
+This function consumes all the data accumulated in
+@code{streambuf->stream} and outputs it like
+@code{ui_out_field_string} does. After a call to
+@code{ui_out_field_stream}, the accumulated data no longer exists, but
+the stream is still valid and may be used for producing more fields.
+@end deftypefun
+
+@strong{Important:} If there is any chance that your code could bail
+out before completing output generation and reaching the point where
+@code{ui_out_stream_delete} is called, it is necessary to set up a
+cleanup, to avoid leaking memory and other resources. Here's a
+skeleton code to do that:
+
+@smallexample
+ struct ui_stream *mybuf = ui_out_stream_new (uiout);
+ struct cleanup *old = make_cleanup (ui_out_stream_delete, mybuf);
+ ...
+ do_cleanups (old);
+@end smallexample
+
+If the function already has the old cleanup chain set (for other kinds
+of cleanups), you just have to add your cleanup to it:
+
+@smallexample
+ mybuf = ui_out_stream_new (uiout);
+ make_cleanup (ui_out_stream_delete, mybuf);
+@end smallexample
+
+Note that with cleanups in place, you should not call
+@code{ui_out_stream_delete} directly, or you would attempt to free the
+same buffer twice.
+
+@subsection Utility Output Functions
+
+@deftypefun void ui_out_field_skip (struct ui_out *@var{uiout}, const char *@var{fldname})
+This function skips a field in a table. Use it if you have to leave
+an empty field without disrupting the table alignment. The argument
+@var{fldname} specifies a name for the (missing) filed.
+@end deftypefun
+
+@deftypefun void ui_out_text (struct ui_out *@var{uiout}, const char *@var{string})
+This function outputs the text in @var{string} in a way that makes it
+easy to be read by humans. For example, the console implementation of
+this method filters the text through a built-in pager, to prevent it
+from scrolling off the visible portion of the screen.
+
+Use this function for printing relatively long chunks of text around
+the actual field data: the text it produces is not aligned according
+to the table's format. Use @code{ui_out_field_string} to output a
+string field, and use @code{ui_out_message}, described below, to
+output short messages.
+@end deftypefun
+
+@deftypefun void ui_out_spaces (struct ui_out *@var{uiout}, int @var{nspaces})
+This function outputs @var{nspaces} spaces. It is handy to align the
+text produced by @code{ui_out_text} with the rest of the table or
+list.
+@end deftypefun
+
+@deftypefun void ui_out_message (struct ui_out *@var{uiout}, int @var{verbosity}, const char *@var{format}, ...)
+This function produces a formatted message, provided that the current
+verbosity level is at least as large as given by @var{verbosity}. The
+current verbosity level is specified by the user with the @samp{set
+verbositylevel} command.@footnote{As of this writing (April 2001),
+setting verbosity level is not yet implemented, and is always returned
+as zero. So calling @code{ui_out_message} with a @var{verbosity}
+argument more than zero will cause the message to never be printed.}
+@end deftypefun
+
+@deftypefun void ui_out_wrap_hint (struct ui_out *@var{uiout}, char *@var{indent})
+This function gives the console output filter (a paging filter) a hint
+of where to break lines which are too long. Ignored for all other
+output consumers. @var{indent}, if non-@code{NULL}, is the string to
+be printed to indent the wrapped text on the next line; it must remain
+accessible until the next call to @code{ui_out_wrap_hint}, or until an
+explicit newline is produced by one of the other functions. If
+@var{indent} is @code{NULL}, the wrapped text will not be indented.
+@end deftypefun
+
+@deftypefun void ui_out_flush (struct ui_out *@var{uiout})
+This function flushes whatever output has been accumulated so far, if
+the UI buffers output.
+@end deftypefun
+
+
+@subsection Examples of Use of @code{ui_out} functions
+
+@cindex using @code{ui_out} functions
+@cindex @code{ui_out} functions, usage examples
+This section gives some practical examples of using the @code{ui_out}
+functions to generalize the old console-oriented code in
+@value{GDBN}. The examples all come from functions defined on the
+@file{breakpoints.c} file.
+
+This example, from the @code{breakpoint_1} function, shows how to
+produce a table.
+
+The original code was:
+
+@smallexample
+ 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 ();
+ @}
+@end smallexample
+
+Here's the new version:
+
+@smallexample
+ nr_printable_breakpoints = @dots{};
+
+ if (addressprint)
+ ui_out_table_begin (ui, 6, nr_printable_breakpoints, "BreakpointTable");
+ else
+ ui_out_table_begin (ui, 5, nr_printable_breakpoints, "BreakpointTable");
+
+ if (nr_printable_breakpoints > 0)
+ annotate_breakpoints_headers ();
+ if (nr_printable_breakpoints > 0)
+ annotate_field (0);
+ ui_out_table_header (uiout, 3, ui_left, "number", "Num"); /* 1 */
+ if (nr_printable_breakpoints > 0)
+ annotate_field (1);
+ ui_out_table_header (uiout, 14, ui_left, "type", "Type"); /* 2 */
+ if (nr_printable_breakpoints > 0)
+ annotate_field (2);
+ ui_out_table_header (uiout, 4, ui_left, "disp", "Disp"); /* 3 */
+ if (nr_printable_breakpoints > 0)
+ annotate_field (3);
+ ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb"); /* 4 */
+ if (addressprint)
+ @{
+ if (nr_printable_breakpoints > 0)
+ annotate_field (4);
+ if (TARGET_ADDR_BIT <= 32)
+ ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */
+ else
+ ui_out_table_header (uiout, 18, ui_left, "addr", "Address");/* 5 */
+ @}
+ if (nr_printable_breakpoints > 0)
+ annotate_field (5);
+ ui_out_table_header (uiout, 40, ui_noalign, "what", "What"); /* 6 */
+ ui_out_table_body (uiout);
+ if (nr_printable_breakpoints > 0)
+ annotate_breakpoints_table ();
+@end smallexample
+
+This example, from the @code{print_one_breakpoint} function, shows how
+to produce the actual data for the table whose structure was defined
+in the above example. The original code was:
+
+@smallexample
+ annotate_record ();
+ annotate_field (0);
+ printf_filtered ("%-3d ", b->number);
+ annotate_field (1);
+ if ((int)b->type > (sizeof(bptypes)/sizeof(bptypes[0]))
+ || ((int) b->type != bptypes[(int) b->type].type))
+ internal_error ("bptypes table does not describe type #%d.",
+ (int)b->type);
+ printf_filtered ("%-14s ", bptypes[(int)b->type].description);
+ annotate_field (2);
+ printf_filtered ("%-4s ", bpdisps[(int)b->disposition]);
+ annotate_field (3);
+ printf_filtered ("%-3c ", bpenables[(int)b->enable]);
+ @dots{}
+@end smallexample
+
+This is the new version:
+
+@smallexample
+ annotate_record ();
+ ui_out_tuple_begin (uiout, "bkpt");
+ annotate_field (0);
+ ui_out_field_int (uiout, "number", b->number);
+ annotate_field (1);
+ if (((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
+ || ((int) b->type != bptypes[(int) b->type].type))
+ internal_error ("bptypes table does not describe type #%d.",
+ (int) b->type);
+ ui_out_field_string (uiout, "type", bptypes[(int)b->type].description);
+ annotate_field (2);
+ ui_out_field_string (uiout, "disp", bpdisps[(int)b->disposition]);
+ annotate_field (3);
+ ui_out_field_fmt (uiout, "enabled", "%c", bpenables[(int)b->enable]);
+ @dots{}
+@end smallexample
+
+This example, also from @code{print_one_breakpoint}, shows how to
+produce a complicated output field using the @code{print_expression}
+functions which requires a stream to be passed. It also shows how to
+automate stream destruction with cleanups. The original code was:
+
+@smallexample
+ annotate_field (5);
+ print_expression (b->exp, gdb_stdout);
+@end smallexample
+
+The new version is:
+
+@smallexample
+ struct ui_stream *stb = ui_out_stream_new (uiout);
+ struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
+ ...
+ annotate_field (5);
+ print_expression (b->exp, stb->stream);
+ ui_out_field_stream (uiout, "what", local_stream);
+@end smallexample
+
+This example, also from @code{print_one_breakpoint}, shows how to use
+@code{ui_out_text} and @code{ui_out_field_string}. The original code
+was:
+
+@smallexample
+ annotate_field (5);
+ if (b->dll_pathname == NULL)
+ printf_filtered ("<any library> ");
+ else
+ printf_filtered ("library \"%s\" ", b->dll_pathname);
+@end smallexample
+
+It became:
+
+@smallexample
+ annotate_field (5);
+ if (b->dll_pathname == NULL)
+ @{
+ ui_out_field_string (uiout, "what", "<any library>");
+ ui_out_spaces (uiout, 1);
+ @}
+ else
+ @{
+ ui_out_text (uiout, "library \"");
+ ui_out_field_string (uiout, "what", b->dll_pathname);
+ ui_out_text (uiout, "\" ");
+ @}
+@end smallexample
+
+The following example from @code{print_one_breakpoint} shows how to
+use @code{ui_out_field_int} and @code{ui_out_spaces}. The original
+code was:
+
+@smallexample
+ annotate_field (5);
+ if (b->forked_inferior_pid != 0)
+ printf_filtered ("process %d ", b->forked_inferior_pid);
+@end smallexample
+
+It became:
+
+@smallexample
+ annotate_field (5);
+ if (b->forked_inferior_pid != 0)
+ @{
+ ui_out_text (uiout, "process ");
+ ui_out_field_int (uiout, "what", b->forked_inferior_pid);
+ ui_out_spaces (uiout, 1);
+ @}
+@end smallexample
+
+Here's an example of using @code{ui_out_field_string}. The original
+code was:
+
+@smallexample
+ annotate_field (5);
+ if (b->exec_pathname != NULL)
+ printf_filtered ("program \"%s\" ", b->exec_pathname);
+@end smallexample
+
+It became:
+
+@smallexample
+ annotate_field (5);
+ if (b->exec_pathname != NULL)
+ @{
+ ui_out_text (uiout, "program \"");
+ ui_out_field_string (uiout, "what", b->exec_pathname);
+ ui_out_text (uiout, "\" ");
+ @}
+@end smallexample
+
+Finally, here's an example of printing an address. The original code:
+
+@smallexample
+ annotate_field (4);
+ printf_filtered ("%s ",
+ local_hex_string_custom ((unsigned long) b->address, "08l"));
+@end smallexample
+
+It became:
+
+@smallexample
+ annotate_field (4);
+ ui_out_field_core_addr (uiout, "Address", b->address);
+@end smallexample
+
+
+@section Console Printing
+
+@section TUI
+
+@node libgdb
+
+@chapter libgdb
+
+@section libgdb 1.0
+@cindex @code{libgdb}
+@code{libgdb} 1.0 was an abortive project of years ago. The theory was
+to provide an API to @value{GDBN}'s functionality.
+
+@section libgdb 2.0
+@cindex @code{libgdb}
+@code{libgdb} 2.0 is an ongoing effort to update @value{GDBN} so that is
+better able to support graphical and other environments.
+
+Since @code{libgdb} development is on-going, its architecture is still
+evolving. The following components have so far been identified:
+
+@itemize @bullet
+@item
+Observer - @file{gdb-events.h}.
+@item
+Builder - @file{ui-out.h}
+@item
+Event Loop - @file{event-loop.h}
+@item
+Library - @file{gdb.h}
+@end itemize
+
+The model that ties these components together is described below.
+
+@section The @code{libgdb} Model
+
+A client of @code{libgdb} interacts with the library in two ways.
+
+@itemize @bullet
+@item
+As an observer (using @file{gdb-events}) receiving notifications from
+@code{libgdb} of any internal state changes (break point changes, run
+state, etc).
+@item
+As a client querying @code{libgdb} (using the @file{ui-out} builder) to
+obtain various status values from @value{GDBN}.
+@end itemize
+
+Since @code{libgdb} could have multiple clients (e.g. a GUI supporting
+the existing @value{GDBN} CLI), those clients must co-operate when
+controlling @code{libgdb}. In particular, a client must ensure that
+@code{libgdb} is idle (i.e. no other client is using @code{libgdb})
+before responding to a @file{gdb-event} by making a query.
+
+@section CLI support
+
+At present @value{GDBN}'s CLI is very much entangled in with the core of
+@code{libgdb}. Consequently, a client wishing to include the CLI in
+their interface needs to carefully co-ordinate its own and the CLI's
+requirements.
+
+It is suggested that the client set @code{libgdb} up to be bi-modal
+(alternate between CLI and client query modes). The notes below sketch
+out the theory:
+
+@itemize @bullet
+@item
+The client registers itself as an observer of @code{libgdb}.
+@item
+The client create and install @code{cli-out} builder using its own
+versions of the @code{ui-file} @code{gdb_stderr}, @code{gdb_stdtarg} and
+@code{gdb_stdout} streams.
+@item
+The client creates a separate custom @code{ui-out} builder that is only
+used while making direct queries to @code{libgdb}.
+@end itemize
+
+When the client receives input intended for the CLI, it simply passes it
+along. Since the @code{cli-out} builder is installed by default, all
+the CLI output in response to that command is routed (pronounced rooted)
+through to the client controlled @code{gdb_stdout} et.@: al.@: streams.
+At the same time, the client is kept abreast of internal changes by
+virtue of being a @code{libgdb} observer.
+
+The only restriction on the client is that it must wait until
+@code{libgdb} becomes idle before initiating any queries (using the
+client's custom builder).
+
+@section @code{libgdb} components
+
+@subheading Observer - @file{gdb-events.h}
+@file{gdb-events} provides the client with a very raw mechanism that can
+be used to implement an observer. At present it only allows for one
+observer and that observer must, internally, handle the need to delay
+the processing of any event notifications until after @code{libgdb} has
+finished the current command.
+
+@subheading Builder - @file{ui-out.h}
+@file{ui-out} provides the infrastructure necessary for a client to
+create a builder. That builder is then passed down to @code{libgdb}
+when doing any queries.
+
+@subheading Event Loop - @file{event-loop.h}
+@c There could be an entire section on the event-loop
+@file{event-loop}, currently non-re-entrant, provides a simple event
+loop. A client would need to either plug its self into this loop or,
+implement a new event-loop that GDB would use.
+
+The event-loop will eventually be made re-entrant. This is so that
+@value{GDBN} can better handle the problem of some commands blocking
+instead of returning.
+
+@subheading Library - @file{gdb.h}
+@file{libgdb} is the most obvious component of this system. It provides
+the query interface. Each function is parameterized by a @code{ui-out}
+builder. The result of the query is constructed using that builder
+before the query function returns.
+
+@node Symbol Handling
+
+@chapter Symbol Handling
+
+Symbols are a key part of @value{GDBN}'s operation. Symbols include variables,
+functions, and types.
+
+@section Symbol Reading
+
+@cindex symbol reading
+@cindex reading of symbols
+@cindex symbol files
+@value{GDBN} reads symbols from @dfn{symbol files}. The usual symbol
+file is the file containing the program which @value{GDBN} is
+debugging. @value{GDBN} can be directed to use a different file for
+symbols (with the @samp{symbol-file} command), and it can also read
+more symbols via the @samp{add-file} and @samp{load} commands, or while
+reading symbols from shared libraries.
+
+@findex find_sym_fns
+Symbol files are initially opened by code in @file{symfile.c} using
+the BFD library (@pxref{Support Libraries}). BFD identifies the type
+of the file by examining its header. @code{find_sym_fns} then uses
+this identification to locate a set of symbol-reading functions.
+
+@findex add_symtab_fns
+@cindex @code{sym_fns} structure
+@cindex adding a symbol-reading module
+Symbol-reading modules identify themselves to @value{GDBN} 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{xyz}_symfile_init(struct sym_fns *sf)
+
+@cindex secondary symbol file
+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{xyz}_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{xyz}_symfile_init}, but it can call
+@code{error} if it detects an unavoidable problem.
+
+@item @var{xyz}_new_init()
+
+Called from @code{symbol_file_add} when discarding existing symbols.
+This function needs only handle the symbol-reading module's internal
+state; the symbol table data structures visible to the rest of
+@value{GDBN} will be discarded by @code{symbol_file_add}. It has no
+arguments and no result. It may be called after
+@code{@var{xyz}_symfile_init}, if a new symbol table is being read, or
+may be called alone if all symbols are simply being discarded.
+
+@item @var{xyz}_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 @code{struct sym_fns} originally passed to
+@code{@var{xyz}_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{xyz}_symfile_read is called, these psymtabs will contain a pointer
+to a function @code{@var{xyz}_psymtab_to_symtab}, which can be called
+from any point in the @value{GDBN} symbol-handling code.
+
+@table @code
+@item @var{xyz}_psymtab_to_symtab (struct partial_symtab *pst)
+
+Called from @code{psymtab_to_symtab} (or the @code{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, @code{pst->readin} should have been set to 1, and
+@code{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
+
+@section Partial Symbol Tables
+
+@value{GDBN} has three types of symbol tables:
+
+@itemize @bullet
+@cindex full symbol table
+@cindex symtabs
+@item
+Full symbol tables (@dfn{symtabs}). These contain the main
+information about symbols and addresses.
+
+@cindex psymtabs
+@item
+Partial symbol tables (@dfn{psymtabs}). These contain enough
+information to know when to read the corresponding part of the full
+symbol table.
+
+@cindex minimal symbol table
+@cindex minsymtabs
+@item
+Minimal symbol tables (@dfn{msymtabs}). These contain information
+gleaned from non-debugging symbols.
+@end itemize
+
+@cindex partial symbol table
+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 @value{GDBN} 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.
+@c (@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 @code{enum} values declared at file scope.
+
+The psymtab also contains the range of instruction addresses that the
+full symbol table would represent.
+
+@cindex finding a symbol
+@cindex symbol lookup
+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
+@findex find_pc_function
+@findex find_pc_line
+@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.
+
+@cindex lookup_symbol
+@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 @value{GDBN} 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.
+
+@section Types
+
+@unnumberedsubsec Fundamental Types (e.g., @code{FT_VOID}, @code{FT_BOOLEAN}).
+
+@cindex fundamental types
+These are the fundamental types that @value{GDBN} 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 @value{GDBN} knows about for all the languages that @value{GDBN}
+knows about.
+
+@unnumberedsubsec Type Codes (e.g., @code{TYPE_CODE_PTR}, @code{TYPE_CODE_ARRAY}).
+
+@cindex type codes
+Each time @value{GDBN} builds an internal type, it marks it with one
+of these types. The type may be a fundamental type, such as
+@code{TYPE_CODE_INT}, or a derived type, such as @code{TYPE_CODE_PTR}
+which is a pointer to another type. Typically, several @code{FT_*}
+types map to one @code{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.
+
+@unnumberedsubsec Builtin Types (e.g., @code{builtin_type_void}, @code{builtin_type_char}).
+
+These are instances of type structs that roughly correspond to
+fundamental types and are created as global types for @value{GDBN} to
+use for various ugly historical reasons. We eventually want to
+eliminate these. Note for example that @code{builtin_type_int}
+initialized in @file{gdbtypes.c} is basically the same as a
+@code{TYPE_CODE_INT} type that is initialized in @file{c-lang.c} for
+an @code{FT_INTEGER} fundamental type. The difference is that the
+@code{builtin_type} is not associated with any particular objfile, and
+only one instance exists, while @file{c-lang.c} builds as many
+@code{TYPE_CODE_INT} types as needed, with each one associated with
+some particular objfile.
+
+@section Object File Formats
+@cindex object file formats
+
+@subsection a.out
+
+@cindex @code{a.out} format
+The @code{a.out} format is the original file format for Unix. It
+consists of three sections: @code{text}, @code{data}, and @code{bss},
+which are for program code, initialized data, and uninitialized data,
+respectively.
+
+The @code{a.out} format is so simple that it doesn't have any reserved
+place for debugging information. (Hey, the original Unix hackers used
+@samp{adb}, which is a machine-language debugger!) The only debugging
+format for @code{a.out} is stabs, which is encoded as a set of normal
+symbols with distinctive attributes.
+
+The basic @code{a.out} reader is in @file{dbxread.c}.
+
+@subsection COFF
+
+@cindex COFF format
+The COFF format was introduced with System V Release 3 (SVR3) Unix.
+COFF files may have multiple sections, each prefixed by a header. The
+number of sections is limited.
+
+The COFF specification includes support for debugging. Although this
+was a step forward, the debugging information was woefully limited. For
+instance, it was not possible to represent code that came from an
+included file.
+
+The COFF reader is in @file{coffread.c}.
+
+@subsection ECOFF
+
+@cindex ECOFF format
+ECOFF is an extended COFF originally introduced for Mips and Alpha
+workstations.
+
+The basic ECOFF reader is in @file{mipsread.c}.
+
+@subsection XCOFF
+
+@cindex XCOFF 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 @code{dbx}-style stabs whose strings are located in the
+@code{.debug} section (rather than the string table). For more
+information, see @ref{Top,,,stabs,The Stabs Debugging Format}.
+
+The shared library scheme has a 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).
+
+@subsection PE
+
+@cindex PE-COFF format
+Windows 95 and NT use the PE (@dfn{Portable Executable}) format for their
+executables. PE is basically COFF with additional headers.
+
+While BFD includes special PE support, @value{GDBN} needs only the basic
+COFF reader.
+
+@subsection ELF
+
+@cindex ELF format
+The ELF format came with System V Release 4 (SVR4) Unix. ELF is similar
+to COFF in being organized into a number of sections, but it removes
+many of COFF's limitations.
+
+The basic ELF reader is in @file{elfread.c}.
+
+@subsection SOM
+
+@cindex SOM format
+SOM is HP's object file and debug format (not to be confused with IBM's
+SOM, which is a cross-language ABI).
+
+The SOM reader is in @file{hpread.c}.
+
+@subsection Other File Formats
+
+@cindex Netware Loadable Module format
+Other file formats that have been supported by @value{GDBN} include Netware
+Loadable Modules (@file{nlmread.c}).
+
+@section Debugging File Formats
+
+This section describes characteristics of debugging information that
+are independent of the object file format.
+
+@subsection stabs
+
+@cindex stabs debugging info
+@code{stabs} started out as special symbols within the @code{a.out}
+format. Since then, it has been encapsulated into other file
+formats, such as COFF and ELF.
+
+While @file{dbxread.c} does some of the basic stab processing,
+including for encapsulated versions, @file{stabsread.c} does
+the real work.
+
+@subsection COFF
+
+@cindex COFF debugging info
+The basic COFF definition includes debugging information. The level
+of support is minimal and non-extensible, and is not often used.
+
+@subsection Mips debug (Third Eye)
+
+@cindex ECOFF debugging info
+ECOFF includes a definition of a special debug format.
+
+The file @file{mdebugread.c} implements reading for this format.
+
+@subsection DWARF 1
+
+@cindex DWARF 1 debugging info
+DWARF 1 is a debugging format that was originally designed to be
+used with ELF in SVR4 systems.
+
+@c GCC_PRODUCER
+@c GPLUS_PRODUCER
+@c LCC_PRODUCER
+@c If defined, these are the producer strings in a DWARF 1 file. All of
+@c these have reasonable defaults already.
+
+The DWARF 1 reader is in @file{dwarfread.c}.
+
+@subsection DWARF 2
+
+@cindex DWARF 2 debugging info
+DWARF 2 is an improved but incompatible version of DWARF 1.
+
+The DWARF 2 reader is in @file{dwarf2read.c}.
+
+@subsection SOM
+
+@cindex SOM debugging info
+Like COFF, the SOM definition includes debugging information.
+
+@section Adding a New Symbol Reader to @value{GDBN}
+
+@cindex adding debugging info reader
+If you are using an existing object file format (@code{a.out}, COFF, ELF, etc),
+there is probably little to be done.
+
+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.
+
+You must then arrange for the BFD code to provide access to the
+debugging symbols. Generally @value{GDBN} will have to call swapping routines
+from BFD and a few other BFD internal routines to locate the debugging
+information. As much as possible, @value{GDBN} 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/lib@var{xyz}.h}, which is included by @value{GDBN}.
+
+
+@node Language Support
+
+@chapter Language Support
+
+@cindex language support
+@value{GDBN}'s language support is mainly driven by the symbol reader,
+although it is possible for the user to set the source language
+manually.
+
+@value{GDBN} chooses the source language by looking at the extension
+of the file recorded in the debug info; @file{.c} means C, @file{.f}
+means Fortran, etc. It may also use a special-purpose language
+identifier if the debug format supports it, like with DWARF.
+
+@section Adding a Source Language to @value{GDBN}
+
+@cindex adding source language
+To add other languages to @value{GDBN}'s expression parser, follow the
+following steps:
+
+@table @emph
+@item Create the expression parser.
+
+@cindex expression parser
+This should reside in a file @file{@var{lang}-exp.y}. Routines for
+building parsed expressions into a @code{union exp_element} list are in
+@file{parse.c}.
+
+@cindex language parser
+Since we can't depend upon everyone having Bison, and YACC produces
+parsers that define a bunch of global names, the following lines
+@strong{must} be included at the top of the YACC parser, to prevent the
+various parsers from defining the same global names:
+
+@smallexample
+#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 smallexample
+
+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 @value{GDBN}
+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
+
+@cindex expression evaluation routines
+@findex evaluate_subexp
+@findex prefixify_subexp
+@findex length_of_subexp
+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 the @code{evaluate_subexp} function
+defined in the file @file{eval.c}. 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.
+
+@vindex current_language
+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.
+
+@findex _initialize_language
+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 @value{GDBN} is built for.
+
+@findex allocate_symtab
+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.
+
+@findex print_subexp
+@findex op_print_tab
+Add helper code to @code{print_subexp} (in @file{expprint.c}) 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
+
+@findex parse_exp_1
+Add a call to @code{@var{lang}_parse()} and @code{@var{lang}_error} in
+@code{parse_exp_1} (defined in @file{parse.c}).
+
+@item Use macros to trim code
+
+@cindex trimming language-dependent code
+The user has the option of building @value{GDBN} for some or all of the
+languages. If the user decides to build @value{GDBN} 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 @value{GDBN}
+is not build for @var{lang}, then @file{@var{lang}-exp.tab.o} (the
+compiled form of your parser) is not linked into @value{GDBN} at all.
+
+See the file @file{configure.in} for how @value{GDBN} 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 Host Definition
+
+@chapter Host Definition
+
+With the advent of Autoconf, it's rarely necessary to have host
+definition machinery anymore. The following information is provided,
+mainly, as an historical reference.
+
+@section Adding a New Host
+
+@cindex adding a new host
+@cindex host, adding
+@value{GDBN}'s host configuration support normally happens via Autoconf.
+New host-specific definitions should not be needed. Older hosts
+@value{GDBN} still use the host-specific definitions and files listed
+below, but these mostly exist for historical reasons, and will
+eventually disappear.
+
+@table @file
+@item gdb/config/@var{arch}/@var{xyz}.mh
+This file once contained both host and native configuration information
+(@pxref{Native Debugging}) for the machine @var{xyz}. The host
+configuration information is now handed by Autoconf.
+
+Host configuration information included a definition of
+@code{XM_FILE=xm-@var{xyz}.h} and possibly definitions for @code{CC},
+@code{SYSV_DEFINE}, @code{XM_CFLAGS}, @code{XM_ADD_FILES},
+@code{XM_CLIBS}, @code{XM_CDEPS}, etc.; see @file{Makefile.in}.
+
+New host only configurations do not need this file.
+
+@item gdb/config/@var{arch}/xm-@var{xyz}.h
+This file once contained definitions and includes required when hosting
+gdb on machine @var{xyz}. Those definitions and includes are now
+handled by Autoconf.
+
+New host and native configurations do not need this file.
+
+@emph{Maintainer's note: Some hosts continue to use the @file{xm-xyz.h}
+file to define the macros @var{HOST_FLOAT_FORMAT},
+@var{HOST_DOUBLE_FORMAT} and @var{HOST_LONG_DOUBLE_FORMAT}. That code
+also needs to be replaced with either an Autoconf or run-time test.}
+
+@end table
+
+@subheading Generic Host Support Files
+
+@cindex generic host support
+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{xyz}.h} file. If these routines work for
+the @var{xyz} 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{xyz}-xdep.c}, and put @code{@var{xyz}-xdep.o}
+into @code{XDEPFILES}.
+
+@table @file
+@cindex remote debugging support
+@cindex serial line support
+@item ser-unix.c
+This contains serial line support for Unix systems. This is always
+included, via the makefile variable @code{SER_HARDWIRE}; override this
+variable in the @file{.mh} file to avoid it.
+
+@item ser-go32.c
+This contains serial line support for 32-bit programs running under DOS,
+using the DJGPP (a.k.a.@: GO32) execution environment.
+
+@cindex TCP remote support
+@item ser-tcp.c
+This contains generic TCP support using sockets.
+@end table
+
+@section Host Conditionals
+
+When @value{GDBN} 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:
+
+@ftable @code
+@item @value{GDBN}INIT_FILENAME
+The default name of @value{GDBN}'s initialization file (normally
+@file{.gdbinit}).
+
+@item NO_STD_REGS
+This macro is deprecated.
+
+@item NO_SYS_FILE
+Define this if your system does not have a @code{<sys/file.h>}.
+
+@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 ALIGN_STACK_ON_STARTUP
+@cindex stack alignment
+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 CRLF_SOURCE_FILES
+@cindex DOS text files
+Define this if host files use @code{\r\n} rather than @code{\n} as a
+line terminator. This will cause source file listings to omit @code{\r}
+characters when printing and it will allow @code{\r\n} line endings of files
+which are ``sourced'' by gdb. It must be possible to open files in binary
+mode using @code{O_BINARY} or, for fopen, @code{"rb"}.
+
+@item DEFAULT_PROMPT
+@cindex prompt
+The default value of the prompt string (normally @code{"(gdb) "}).
+
+@item DEV_TTY
+@cindex terminal device
+The name of the generic TTY device, defaults to @code{"/dev/tty"}.
+
+@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.
+
+@item FOPEN_RB
+Define this if binary files are opened the same way as text files.
+
+@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 HAVE_MMAP
+@findex 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_TERMIO
+Define this if the host system has @code{termio.h}.
+
+@item INT_MAX
+@itemx INT_MIN
+@itemx LONG_MAX
+@itemx UINT_MAX
+@itemx ULONG_MAX
+Values for host-side constants.
+
+@item ISATTY
+Substitute for isatty, if not available.
+
+@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
+@cindex @code{long long} data type
+Define this if the host C compiler supports @code{long long}. This is set
+by the @code{configure} script.
+
+@item PRINTF_HAS_LONG_LONG
+Define this if the host can handle printing of long long integers via
+the printf format conversion specifier @code{ll}. This is set by the
+@code{configure} script.
+
+@item HAVE_LONG_DOUBLE
+Define this if the host C compiler supports @code{long double}. This is
+set by the @code{configure} script.
+
+@item PRINTF_HAS_LONG_DOUBLE
+Define this if the host can handle printing of long double float-point
+numbers via the printf format conversion specifier @code{Lg}. This is
+set by the @code{configure} script.
+
+@item SCANF_HAS_LONG_DOUBLE
+Define this if the host can handle the parsing of long double
+float-point numbers via the scanf format conversion specifier
+@code{Lg}. This is set by the @code{configure} script.
+
+@item LSEEK_NOT_LINEAR
+Define this if @code{lseek (n)} does not necessarily move to byte number
+@code{n} in the file. This is only used when reading source files. It
+is normally faster to define @code{CRLF_SOURCE_FILES} when possible.
+
+@item L_SET
+This macro is used as the argument to @code{lseek} (or, most commonly,
+@code{bfd_seek}). FIXME, should be replaced by SEEK_SET instead,
+which is the POSIX equivalent.
+
+@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 NO_SIGINTERRUPT
+@findex siginterrupt
+Define this to indicate that @code{siginterrupt} is not available.
+
+@item SEEK_CUR
+@itemx SEEK_SET
+Define these to appropriate value for the system @code{lseek}, if not already
+defined.
+
+@item STOP_SIGNAL
+This is the signal for stopping @value{GDBN}. Defaults to
+@code{SIGTSTP}. (Only redefined for the Convex.)
+
+@item USE_O_NOCTTY
+Define this if the interior's tty should be opened with the @code{O_NOCTTY}
+flag. (FIXME: This should be a native-only flag, but @file{inflow.c} is
+always linked in.)
+
+@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}, and
+@file{utils.c} for other things, at the moment.)
+
+@item lint
+Define this to help placate @code{lint} in some situations.
+
+@item volatile
+Define this to override the defaults of @code{__volatile__} or
+@code{/**/}.
+@end ftable
+
+
+@node Target Architecture Definition
+
+@chapter Target Architecture Definition
+
+@cindex target architecture definition
+@value{GDBN}'s target architecture defines what sort of
+machine-language programs @value{GDBN} can work with, and how it works
+with them.
+
+The target architecture object is implemented as the C structure
+@code{struct gdbarch *}. The structure, and its methods, are generated
+using the Bourne shell script @file{gdbarch.sh}.
+
+@section Operating System ABI Variant Handling
+@cindex OS ABI variants
+
+@value{GDBN} provides a mechanism for handling variations in OS
+ABIs. An OS ABI variant may have influence over any number of
+variables in the target architecture definition. There are two major
+components in the OS ABI mechanism: sniffers and handlers.
+
+A @dfn{sniffer} examines a file matching a BFD architecture/flavour pair
+(the architecture may be wildcarded) in an attempt to determine the
+OS ABI of that file. Sniffers with a wildcarded architecture are considered
+to be @dfn{generic}, while sniffers for a specific architecture are
+considered to be @dfn{specific}. A match from a specific sniffer
+overrides a match from a generic sniffer. Multiple sniffers for an
+architecture/flavour may exist, in order to differentiate between two
+different operating systems which use the same basic file format. The
+OS ABI framework provides a generic sniffer for ELF-format files which
+examines the @code{EI_OSABI} field of the ELF header, as well as note
+sections known to be used by several operating systems.
+
+@cindex fine-tuning @code{gdbarch} structure
+A @dfn{handler} is used to fine-tune the @code{gdbarch} structure for the
+selected OS ABI. There may be only one handler for a given OS ABI
+for each BFD architecture.
+
+The following OS ABI variants are defined in @file{osabi.h}:
+
+@table @code
+
+@findex GDB_OSABI_UNKNOWN
+@item GDB_OSABI_UNKNOWN
+The ABI of the inferior is unknown. The default @code{gdbarch}
+settings for the architecture will be used.
+
+@findex GDB_OSABI_SVR4
+@item GDB_OSABI_SVR4
+UNIX System V Release 4
+
+@findex GDB_OSABI_HURD
+@item GDB_OSABI_HURD
+GNU using the Hurd kernel
+
+@findex GDB_OSABI_SOLARIS
+@item GDB_OSABI_SOLARIS
+Sun Solaris
+
+@findex GDB_OSABI_OSF1
+@item GDB_OSABI_OSF1
+OSF/1, including Digital UNIX and Compaq Tru64 UNIX
+
+@findex GDB_OSABI_LINUX
+@item GDB_OSABI_LINUX
+GNU using the Linux kernel
+
+@findex GDB_OSABI_FREEBSD_AOUT
+@item GDB_OSABI_FREEBSD_AOUT
+FreeBSD using the a.out executable format
+
+@findex GDB_OSABI_FREEBSD_ELF
+@item GDB_OSABI_FREEBSD_ELF
+FreeBSD using the ELF executable format
+
+@findex GDB_OSABI_NETBSD_AOUT
+@item GDB_OSABI_NETBSD_AOUT
+NetBSD using the a.out executable format
+
+@findex GDB_OSABI_NETBSD_ELF
+@item GDB_OSABI_NETBSD_ELF
+NetBSD using the ELF executable format
+
+@findex GDB_OSABI_WINCE
+@item GDB_OSABI_WINCE
+Windows CE
+
+@findex GDB_OSABI_GO32
+@item GDB_OSABI_GO32
+DJGPP
+
+@findex GDB_OSABI_NETWARE
+@item GDB_OSABI_NETWARE
+Novell NetWare
+
+@findex GDB_OSABI_ARM_EABI_V1
+@item GDB_OSABI_ARM_EABI_V1
+ARM Embedded ABI version 1
+
+@findex GDB_OSABI_ARM_EABI_V2
+@item GDB_OSABI_ARM_EABI_V2
+ARM Embedded ABI version 2
+
+@findex GDB_OSABI_ARM_APCS
+@item GDB_OSABI_ARM_APCS
+Generic ARM Procedure Call Standard
+
+@end table
+
+Here are the functions that make up the OS ABI framework:
+
+@deftypefun const char *gdbarch_osabi_name (enum gdb_osabi @var{osabi})
+Return the name of the OS ABI corresponding to @var{osabi}.
+@end deftypefun
+
+@deftypefun void gdbarch_register_osabi (enum bfd_architecture @var{arch}, unsigned long @var{machine}, enum gdb_osabi @var{osabi}, void (*@var{init_osabi})(struct gdbarch_info @var{info}, struct gdbarch *@var{gdbarch}))
+Register the OS ABI handler specified by @var{init_osabi} for the
+architecture, machine type and OS ABI specified by @var{arch},
+@var{machine} and @var{osabi}. In most cases, a value of zero for the
+machine type, which implies the architecture's default machine type,
+will suffice.
+@end deftypefun
+
+@deftypefun void gdbarch_register_osabi_sniffer (enum bfd_architecture @var{arch}, enum bfd_flavour @var{flavour}, enum gdb_osabi (*@var{sniffer})(bfd *@var{abfd}))
+Register the OS ABI file sniffer specified by @var{sniffer} for the
+BFD architecture/flavour pair specified by @var{arch} and @var{flavour}.
+If @var{arch} is @code{bfd_arch_unknown}, the sniffer is considered to
+be generic, and is allowed to examine @var{flavour}-flavoured files for
+any architecture.
+@end deftypefun
+
+@deftypefun enum gdb_osabi gdbarch_lookup_osabi (bfd *@var{abfd})
+Examine the file described by @var{abfd} to determine its OS ABI.
+The value @code{GDB_OSABI_UNKNOWN} is returned if the OS ABI cannot
+be determined.
+@end deftypefun
+
+@deftypefun void gdbarch_init_osabi (struct gdbarch info @var{info}, struct gdbarch *@var{gdbarch}, enum gdb_osabi @var{osabi})
+Invoke the OS ABI handler corresponding to @var{osabi} to fine-tune the
+@code{gdbarch} structure specified by @var{gdbarch}. If a handler
+corresponding to @var{osabi} has not been registered for @var{gdbarch}'s
+architecture, a warning will be issued and the debugging session will continue
+with the defaults already established for @var{gdbarch}.
+@end deftypefun
+
+@section Registers and Memory
+
+@value{GDBN}'s model of the target machine is rather simple.
+@value{GDBN} assumes the machine includes a bank of registers and a
+block of memory. Each register may have a different size.
+
+@value{GDBN} does not have a magical way to match up with the
+compiler's idea of which registers are which; however, it is critical
+that they do match up accurately. The only way to make this work is
+to get accurate information about the order that the compiler uses,
+and to reflect that in the @code{REGISTER_NAME} and related macros.
+
+@value{GDBN} can handle big-endian, little-endian, and bi-endian architectures.
+
+@section Pointers Are Not Always Addresses
+@cindex pointer representation
+@cindex address representation
+@cindex word-addressed machines
+@cindex separate data and code address spaces
+@cindex spaces, separate data and code address
+@cindex address spaces, separate data and code
+@cindex code pointers, word-addressed
+@cindex converting between pointers and addresses
+@cindex D10V addresses
+
+On almost all 32-bit architectures, the representation of a pointer is
+indistinguishable from the representation of some fixed-length number
+whose value is the byte address of the object pointed to. On such
+machines, the words ``pointer'' and ``address'' can be used interchangeably.
+However, architectures with smaller word sizes are often cramped for
+address space, so they may choose a pointer representation that breaks this
+identity, and allows a larger code address space.
+
+For example, the Renesas D10V is a 16-bit VLIW processor whose
+instructions are 32 bits long@footnote{Some D10V instructions are
+actually pairs of 16-bit sub-instructions. However, since you can't
+jump into the middle of such a pair, code addresses can only refer to
+full 32 bit instructions, which is what matters in this explanation.}.
+If the D10V used ordinary byte addresses to refer to code locations,
+then the processor would only be able to address 64kb of instructions.
+However, since instructions must be aligned on four-byte boundaries, the
+low two bits of any valid instruction's byte address are always
+zero---byte addresses waste two bits. So instead of byte addresses,
+the D10V uses word addresses---byte addresses shifted right two bits---to
+refer to code. Thus, the D10V can use 16-bit words to address 256kb of
+code space.
+
+However, this means that code pointers and data pointers have different
+forms on the D10V. The 16-bit word @code{0xC020} refers to byte address
+@code{0xC020} when used as a data address, but refers to byte address
+@code{0x30080} when used as a code address.
+
+(The D10V also uses separate code and data address spaces, which also
+affects the correspondence between pointers and addresses, but we're
+going to ignore that here; this example is already too long.)
+
+To cope with architectures like this---the D10V is not the only
+one!---@value{GDBN} tries to distinguish between @dfn{addresses}, which are
+byte numbers, and @dfn{pointers}, which are the target's representation
+of an address of a particular type of data. In the example above,
+@code{0xC020} is the pointer, which refers to one of the addresses
+@code{0xC020} or @code{0x30080}, depending on the type imposed upon it.
+@value{GDBN} provides functions for turning a pointer into an address
+and vice versa, in the appropriate way for the current architecture.
+
+Unfortunately, since addresses and pointers are identical on almost all
+processors, this distinction tends to bit-rot pretty quickly. Thus,
+each time you port @value{GDBN} to an architecture which does
+distinguish between pointers and addresses, you'll probably need to
+clean up some architecture-independent code.
+
+Here are functions which convert between pointers and addresses:
+
+@deftypefun CORE_ADDR extract_typed_address (void *@var{buf}, struct type *@var{type})
+Treat the bytes at @var{buf} as a pointer or reference of type
+@var{type}, and return the address it represents, in a manner
+appropriate for the current architecture. This yields an address
+@value{GDBN} can use to read target memory, disassemble, etc. Note that
+@var{buf} refers to a buffer in @value{GDBN}'s memory, not the
+inferior's.
+
+For example, if the current architecture is the Intel x86, this function
+extracts a little-endian integer of the appropriate length from
+@var{buf} and returns it. However, if the current architecture is the
+D10V, this function will return a 16-bit integer extracted from
+@var{buf}, multiplied by four if @var{type} is a pointer to a function.
+
+If @var{type} is not a pointer or reference type, then this function
+will signal an internal error.
+@end deftypefun
+
+@deftypefun CORE_ADDR store_typed_address (void *@var{buf}, struct type *@var{type}, CORE_ADDR @var{addr})
+Store the address @var{addr} in @var{buf}, in the proper format for a
+pointer of type @var{type} in the current architecture. Note that
+@var{buf} refers to a buffer in @value{GDBN}'s memory, not the
+inferior's.
+
+For example, if the current architecture is the Intel x86, this function
+stores @var{addr} unmodified as a little-endian integer of the
+appropriate length in @var{buf}. However, if the current architecture
+is the D10V, this function divides @var{addr} by four if @var{type} is
+a pointer to a function, and then stores it in @var{buf}.
+
+If @var{type} is not a pointer or reference type, then this function
+will signal an internal error.
+@end deftypefun
+
+@deftypefun CORE_ADDR value_as_address (struct value *@var{val})
+Assuming that @var{val} is a pointer, return the address it represents,
+as appropriate for the current architecture.
+
+This function actually works on integral values, as well as pointers.
+For pointers, it performs architecture-specific conversions as
+described above for @code{extract_typed_address}.
+@end deftypefun
+
+@deftypefun CORE_ADDR value_from_pointer (struct type *@var{type}, CORE_ADDR @var{addr})
+Create and return a value representing a pointer of type @var{type} to
+the address @var{addr}, as appropriate for the current architecture.
+This function performs architecture-specific conversions as described
+above for @code{store_typed_address}.
+@end deftypefun
+
+Here are some macros which architectures can define to indicate the
+relationship between pointers and addresses. These have default
+definitions, appropriate for architectures on which all pointers are
+simple unsigned byte addresses.
+
+@deftypefn {Target Macro} CORE_ADDR POINTER_TO_ADDRESS (struct type *@var{type}, char *@var{buf})
+Assume that @var{buf} holds a pointer of type @var{type}, in the
+appropriate format for the current architecture. Return the byte
+address the pointer refers to.
+
+This function may safely assume that @var{type} is either a pointer or a
+C@t{++} reference type.
+@end deftypefn
+
+@deftypefn {Target Macro} void ADDRESS_TO_POINTER (struct type *@var{type}, char *@var{buf}, CORE_ADDR @var{addr})
+Store in @var{buf} a pointer of type @var{type} representing the address
+@var{addr}, in the appropriate format for the current architecture.
+
+This function may safely assume that @var{type} is either a pointer or a
+C@t{++} reference type.
+@end deftypefn
+
+@section Address Classes
+@cindex address classes
+@cindex DW_AT_byte_size
+@cindex DW_AT_address_class
+
+Sometimes information about different kinds of addresses is available
+via the debug information. For example, some programming environments
+define addresses of several different sizes. If the debug information
+distinguishes these kinds of address classes through either the size
+info (e.g, @code{DW_AT_byte_size} in @w{DWARF 2}) or through an explicit
+address class attribute (e.g, @code{DW_AT_address_class} in @w{DWARF 2}), the
+following macros should be defined in order to disambiguate these
+types within @value{GDBN} as well as provide the added information to
+a @value{GDBN} user when printing type expressions.
+
+@deftypefn {Target Macro} int ADDRESS_CLASS_TYPE_FLAGS (int @var{byte_size}, int @var{dwarf2_addr_class})
+Returns the type flags needed to construct a pointer type whose size
+is @var{byte_size} and whose address class is @var{dwarf2_addr_class}.
+This function is normally called from within a symbol reader. See
+@file{dwarf2read.c}.
+@end deftypefn
+
+@deftypefn {Target Macro} char *ADDRESS_CLASS_TYPE_FLAGS_TO_NAME (int @var{type_flags})
+Given the type flags representing an address class qualifier, return
+its name.
+@end deftypefn
+@deftypefn {Target Macro} int ADDRESS_CLASS_NAME_to_TYPE_FLAGS (int @var{name}, int *var{type_flags_ptr})
+Given an address qualifier name, set the @code{int} refererenced by @var{type_flags_ptr} to the type flags
+for that address class qualifier.
+@end deftypefn
+
+Since the need for address classes is rather rare, none of
+the address class macros defined by default. Predicate
+macros are provided to detect when they are defined.
+
+Consider a hypothetical architecture in which addresses are normally
+32-bits wide, but 16-bit addresses are also supported. Furthermore,
+suppose that the @w{DWARF 2} information for this architecture simply
+uses a @code{DW_AT_byte_size} value of 2 to indicate the use of one
+of these "short" pointers. The following functions could be defined
+to implement the address class macros:
+
+@smallexample
+somearch_address_class_type_flags (int byte_size,
+ int dwarf2_addr_class)
+@{
+ if (byte_size == 2)
+ return TYPE_FLAG_ADDRESS_CLASS_1;
+ else
+ return 0;
+@}
+
+static char *
+somearch_address_class_type_flags_to_name (int type_flags)
+@{
+ if (type_flags & TYPE_FLAG_ADDRESS_CLASS_1)
+ return "short";
+ else
+ return NULL;
+@}
+
+int
+somearch_address_class_name_to_type_flags (char *name,
+ int *type_flags_ptr)
+@{
+ if (strcmp (name, "short") == 0)
+ @{
+ *type_flags_ptr = TYPE_FLAG_ADDRESS_CLASS_1;
+ return 1;
+ @}
+ else
+ return 0;
+@}
+@end smallexample
+
+The qualifier @code{@@short} is used in @value{GDBN}'s type expressions
+to indicate the presence of one of these "short" pointers. E.g, if
+the debug information indicates that @code{short_ptr_var} is one of these
+short pointers, @value{GDBN} might show the following behavior:
+
+@smallexample
+(gdb) ptype short_ptr_var
+type = int * @@short
+@end smallexample
+
+
+@section Raw and Virtual Register Representations
+@cindex raw register representation
+@cindex virtual register representation
+@cindex representations, raw and virtual registers
+
+@emph{Maintainer note: This section is pretty much obsolete. The
+functionality described here has largely been replaced by
+pseudo-registers and the mechanisms described in @ref{Target
+Architecture Definition, , Using Different Register and Memory Data
+Representations}. See also @uref{http://www.gnu.org/software/gdb/bugs/,
+Bug Tracking Database} and
+@uref{http://sources.redhat.com/gdb/current/ari/, ARI Index} for more
+up-to-date information.}
+
+Some architectures use one representation for a value when it lives in a
+register, but use a different representation when it lives in memory.
+In @value{GDBN}'s terminology, the @dfn{raw} representation is the one used in
+the target registers, and the @dfn{virtual} representation is the one
+used in memory, and within @value{GDBN} @code{struct value} objects.
+
+@emph{Maintainer note: Notice that the same mechanism is being used to
+both convert a register to a @code{struct value} and alternative
+register forms.}
+
+For almost all data types on almost all architectures, the virtual and
+raw representations are identical, and no special handling is needed.
+However, they do occasionally differ. For example:
+
+@itemize @bullet
+@item
+The x86 architecture supports an 80-bit @code{long double} type. However, when
+we store those values in memory, they occupy twelve bytes: the
+floating-point number occupies the first ten, and the final two bytes
+are unused. This keeps the values aligned on four-byte boundaries,
+allowing more efficient access. Thus, the x86 80-bit floating-point
+type is the raw representation, and the twelve-byte loosely-packed
+arrangement is the virtual representation.
+
+@item
+Some 64-bit MIPS targets present 32-bit registers to @value{GDBN} as 64-bit
+registers, with garbage in their upper bits. @value{GDBN} ignores the top 32
+bits. Thus, the 64-bit form, with garbage in the upper 32 bits, is the
+raw representation, and the trimmed 32-bit representation is the
+virtual representation.
+@end itemize
+
+In general, the raw representation is determined by the architecture, or
+@value{GDBN}'s interface to the architecture, while the virtual representation
+can be chosen for @value{GDBN}'s convenience. @value{GDBN}'s register file,
+@code{registers}, holds the register contents in raw format, and the
+@value{GDBN} remote protocol transmits register values in raw format.
+
+Your architecture may define the following macros to request
+conversions between the raw and virtual format:
+
+@deftypefn {Target Macro} int REGISTER_CONVERTIBLE (int @var{reg})
+Return non-zero if register number @var{reg}'s value needs different raw
+and virtual formats.
+
+You should not use @code{REGISTER_CONVERT_TO_VIRTUAL} for a register
+unless this macro returns a non-zero value for that register.
+@end deftypefn
+
+@deftypefn {Target Macro} int DEPRECATED_REGISTER_RAW_SIZE (int @var{reg})
+The size of register number @var{reg}'s raw value. This is the number
+of bytes the register will occupy in @code{registers}, or in a @value{GDBN}
+remote protocol packet.
+@end deftypefn
+
+@deftypefn {Target Macro} int DEPRECATED_REGISTER_VIRTUAL_SIZE (int @var{reg})
+The size of register number @var{reg}'s value, in its virtual format.
+This is the size a @code{struct value}'s buffer will have, holding that
+register's value.
+@end deftypefn
+
+@deftypefn {Target Macro} struct type *DEPRECATED_REGISTER_VIRTUAL_TYPE (int @var{reg})
+This is the type of the virtual representation of register number
+@var{reg}. Note that there is no need for a macro giving a type for the
+register's raw form; once the register's value has been obtained, @value{GDBN}
+always uses the virtual form.
+@end deftypefn
+
+@deftypefn {Target Macro} void REGISTER_CONVERT_TO_VIRTUAL (int @var{reg}, struct type *@var{type}, char *@var{from}, char *@var{to})
+Convert the value of register number @var{reg} to @var{type}, which
+should always be @code{DEPRECATED_REGISTER_VIRTUAL_TYPE (@var{reg})}. The buffer
+at @var{from} holds the register's value in raw format; the macro should
+convert the value to virtual format, and place it at @var{to}.
+
+Note that @code{REGISTER_CONVERT_TO_VIRTUAL} and
+@code{REGISTER_CONVERT_TO_RAW} take their @var{reg} and @var{type}
+arguments in different orders.
+
+You should only use @code{REGISTER_CONVERT_TO_VIRTUAL} with registers
+for which the @code{REGISTER_CONVERTIBLE} macro returns a non-zero
+value.
+@end deftypefn
+
+@deftypefn {Target Macro} void REGISTER_CONVERT_TO_RAW (struct type *@var{type}, int @var{reg}, char *@var{from}, char *@var{to})
+Convert the value of register number @var{reg} to @var{type}, which
+should always be @code{DEPRECATED_REGISTER_VIRTUAL_TYPE (@var{reg})}. The buffer
+at @var{from} holds the register's value in raw format; the macro should
+convert the value to virtual format, and place it at @var{to}.
+
+Note that REGISTER_CONVERT_TO_VIRTUAL and REGISTER_CONVERT_TO_RAW take
+their @var{reg} and @var{type} arguments in different orders.
+@end deftypefn
+
+
+@section Using Different Register and Memory Data Representations
+@cindex register representation
+@cindex memory representation
+@cindex representations, register and memory
+@cindex register data formats, converting
+@cindex @code{struct value}, converting register contents to
+
+@emph{Maintainer's note: The way GDB manipulates registers is undergoing
+significant change. Many of the macros and functions refered to in this
+section are likely to be subject to further revision. See
+@uref{http://sources.redhat.com/gdb/current/ari/, A.R. Index} and
+@uref{http://www.gnu.org/software/gdb/bugs, Bug Tracking Database} for
+further information. cagney/2002-05-06.}
+
+Some architectures can represent a data object in a register using a
+form that is different to the objects more normal memory representation.
+For example:
+
+@itemize @bullet
+
+@item
+The Alpha architecture can represent 32 bit integer values in
+floating-point registers.
+
+@item
+The x86 architecture supports 80-bit floating-point registers. The
+@code{long double} data type occupies 96 bits in memory but only 80 bits
+when stored in a register.
+
+@end itemize
+
+In general, the register representation of a data type is determined by
+the architecture, or @value{GDBN}'s interface to the architecture, while
+the memory representation is determined by the Application Binary
+Interface.
+
+For almost all data types on almost all architectures, the two
+representations are identical, and no special handling is needed.
+However, they do occasionally differ. Your architecture may define the
+following macros to request conversions between the register and memory
+representations of a data type:
+
+@deftypefn {Target Macro} int CONVERT_REGISTER_P (int @var{reg})
+Return non-zero if the representation of a data value stored in this
+register may be different to the representation of that same data value
+when stored in memory.
+
+When non-zero, the macros @code{REGISTER_TO_VALUE} and
+@code{VALUE_TO_REGISTER} are used to perform any necessary conversion.
+@end deftypefn
+
+@deftypefn {Target Macro} void REGISTER_TO_VALUE (int @var{reg}, struct type *@var{type}, char *@var{from}, char *@var{to})
+Convert the value of register number @var{reg} to a data object of type
+@var{type}. The buffer at @var{from} holds the register's value in raw
+format; the converted value should be placed in the buffer at @var{to}.
+
+Note that @code{REGISTER_TO_VALUE} and @code{VALUE_TO_REGISTER} take
+their @var{reg} and @var{type} arguments in different orders.
+
+You should only use @code{REGISTER_TO_VALUE} with registers for which
+the @code{CONVERT_REGISTER_P} macro returns a non-zero value.
+@end deftypefn
+
+@deftypefn {Target Macro} void VALUE_TO_REGISTER (struct type *@var{type}, int @var{reg}, char *@var{from}, char *@var{to})
+Convert a data value of type @var{type} to register number @var{reg}'
+raw format.
+
+Note that @code{REGISTER_TO_VALUE} and @code{VALUE_TO_REGISTER} take
+their @var{reg} and @var{type} arguments in different orders.
+
+You should only use @code{VALUE_TO_REGISTER} with registers for which
+the @code{CONVERT_REGISTER_P} macro returns a non-zero value.
+@end deftypefn
+
+@deftypefn {Target Macro} void REGISTER_CONVERT_TO_TYPE (int @var{regnum}, struct type *@var{type}, char *@var{buf})
+See @file{mips-tdep.c}. It does not do what you want.
+@end deftypefn
+
+
+@section Frame Interpretation
+
+@section Inferior Call Setup
+
+@section Compiler Characteristics
+
+@section Target Conditionals
+
+This section describes the macros that you can use to define the target
+machine.
+
+@table @code
+
+@item ADDR_BITS_REMOVE (addr)
+@findex ADDR_BITS_REMOVE
+If a raw machine instruction address includes any bits that are not
+really part of the address, then define this macro to expand into an
+expression that zeroes those bits in @var{addr}. This is only used for
+addresses of instructions, and even then not in all contexts.
+
+For example, the two low-order bits of the PC on the Hewlett-Packard PA
+2.0 architecture contain the privilege level of the corresponding
+instruction. Since instructions must always be aligned on four-byte
+boundaries, the processor masks out these bits to generate the actual
+address of the instruction. ADDR_BITS_REMOVE should filter out these
+bits with an expression such as @code{((addr) & ~3)}.
+
+@item ADDRESS_CLASS_NAME_TO_TYPE_FLAGS (@var{name}, @var{type_flags_ptr})
+@findex ADDRESS_CLASS_NAME_TO_TYPE_FLAGS
+If @var{name} is a valid address class qualifier name, set the @code{int}
+referenced by @var{type_flags_ptr} to the mask representing the qualifier
+and return 1. If @var{name} is not a valid address class qualifier name,
+return 0.
+
+The value for @var{type_flags_ptr} should be one of
+@code{TYPE_FLAG_ADDRESS_CLASS_1}, @code{TYPE_FLAG_ADDRESS_CLASS_2}, or
+possibly some combination of these values or'd together.
+@xref{Target Architecture Definition, , Address Classes}.
+
+@item ADDRESS_CLASS_NAME_TO_TYPE_FLAGS_P ()
+@findex ADDRESS_CLASS_NAME_TO_TYPE_FLAGS_P
+Predicate which indicates whether @code{ADDRESS_CLASS_NAME_TO_TYPE_FLAGS}
+has been defined.
+
+@item ADDRESS_CLASS_TYPE_FLAGS (@var{byte_size}, @var{dwarf2_addr_class})
+@findex ADDRESS_CLASS_TYPE_FLAGS (@var{byte_size}, @var{dwarf2_addr_class})
+Given a pointers byte size (as described by the debug information) and
+the possible @code{DW_AT_address_class} value, return the type flags
+used by @value{GDBN} to represent this address class. The value
+returned should be one of @code{TYPE_FLAG_ADDRESS_CLASS_1},
+@code{TYPE_FLAG_ADDRESS_CLASS_2}, or possibly some combination of these
+values or'd together.
+@xref{Target Architecture Definition, , Address Classes}.
+
+@item ADDRESS_CLASS_TYPE_FLAGS_P ()
+@findex ADDRESS_CLASS_TYPE_FLAGS_P
+Predicate which indicates whether @code{ADDRESS_CLASS_TYPE_FLAGS} has
+been defined.
+
+@item ADDRESS_CLASS_TYPE_FLAGS_TO_NAME (@var{type_flags})
+@findex ADDRESS_CLASS_TYPE_FLAGS_TO_NAME
+Return the name of the address class qualifier associated with the type
+flags given by @var{type_flags}.
+
+@item ADDRESS_CLASS_TYPE_FLAGS_TO_NAME_P ()
+@findex ADDRESS_CLASS_TYPE_FLAGS_TO_NAME_P
+Predicate which indicates whether @code{ADDRESS_CLASS_TYPE_FLAGS_TO_NAME} has
+been defined.
+@xref{Target Architecture Definition, , Address Classes}.
+
+@item ADDRESS_TO_POINTER (@var{type}, @var{buf}, @var{addr})
+@findex ADDRESS_TO_POINTER
+Store in @var{buf} a pointer of type @var{type} representing the address
+@var{addr}, in the appropriate format for the current architecture.
+This macro may safely assume that @var{type} is either a pointer or a
+C@t{++} reference type.
+@xref{Target Architecture Definition, , Pointers Are Not Always Addresses}.
+
+@item BELIEVE_PCC_PROMOTION
+@findex BELIEVE_PCC_PROMOTION
+Define if the compiler promotes a @code{short} or @code{char}
+parameter to an @code{int}, but still reports the parameter as its
+original type, rather than the promoted type.
+
+@item BELIEVE_PCC_PROMOTION_TYPE
+@findex BELIEVE_PCC_PROMOTION_TYPE
+Define this if @value{GDBN} should believe the type of a @code{short}
+argument when compiled by @code{pcc}, but look within a full int space to get
+its value. Only defined for Sun-3 at present.
+
+@item BITS_BIG_ENDIAN
+@findex BITS_BIG_ENDIAN
+Define this if the numbering of bits in the targets does @strong{not} match the
+endianness of the target byte order. A value of 1 means that the bits
+are numbered in a big-endian bit order, 0 means little-endian.
+
+@item BREAKPOINT
+@findex BREAKPOINT
+This is the character array initializer for the bit pattern to put into
+memory where a breakpoint is set. Although it's common to use a trap
+instruction for a breakpoint, it's not required; for instance, the bit
+pattern could be an invalid instruction. The breakpoint must be no
+longer than the shortest instruction of the architecture.
+
+@code{BREAKPOINT} has been deprecated in favor of
+@code{BREAKPOINT_FROM_PC}.
+
+@item BIG_BREAKPOINT
+@itemx LITTLE_BREAKPOINT
+@findex LITTLE_BREAKPOINT
+@findex BIG_BREAKPOINT
+Similar to BREAKPOINT, but used for bi-endian targets.
+
+@code{BIG_BREAKPOINT} and @code{LITTLE_BREAKPOINT} have been deprecated in
+favor of @code{BREAKPOINT_FROM_PC}.
+
+@item DEPRECATED_REMOTE_BREAKPOINT
+@itemx DEPRECATED_LITTLE_REMOTE_BREAKPOINT
+@itemx DEPRECATED_BIG_REMOTE_BREAKPOINT
+@findex DEPRECATED_BIG_REMOTE_BREAKPOINT
+@findex DEPRECATED_LITTLE_REMOTE_BREAKPOINT
+@findex DEPRECATED_REMOTE_BREAKPOINT
+Specify the breakpoint instruction sequence for a remote target.
+@code{DEPRECATED_REMOTE_BREAKPOINT},
+@code{DEPRECATED_BIG_REMOTE_BREAKPOINT} and
+@code{DEPRECATED_LITTLE_REMOTE_BREAKPOINT} have been deprecated in
+favor of @code{BREAKPOINT_FROM_PC} (@pxref{BREAKPOINT_FROM_PC}).
+
+@item BREAKPOINT_FROM_PC (@var{pcptr}, @var{lenptr})
+@findex BREAKPOINT_FROM_PC
+@anchor{BREAKPOINT_FROM_PC} Use the program counter to determine the
+contents and size of a breakpoint instruction. It returns a pointer to
+a string of bytes that encode a breakpoint instruction, stores the
+length of the string to @code{*@var{lenptr}}, and adjusts the program
+counter (if necessary) to point to the actual memory location where the
+breakpoint should be inserted.
+
+Although it is common to use a trap instruction for a breakpoint, it's
+not required; for instance, the bit pattern could be an invalid
+instruction. The breakpoint must be no longer than the shortest
+instruction of the architecture.
+
+Replaces all the other @var{BREAKPOINT} macros.
+
+@item MEMORY_INSERT_BREAKPOINT (@var{addr}, @var{contents_cache})
+@itemx MEMORY_REMOVE_BREAKPOINT (@var{addr}, @var{contents_cache})
+@findex MEMORY_REMOVE_BREAKPOINT
+@findex MEMORY_INSERT_BREAKPOINT
+Insert or remove memory based breakpoints. Reasonable defaults
+(@code{default_memory_insert_breakpoint} and
+@code{default_memory_remove_breakpoint} respectively) have been
+provided so that it is not necessary to define these for most
+architectures. Architectures which may want to define
+@code{MEMORY_INSERT_BREAKPOINT} and @code{MEMORY_REMOVE_BREAKPOINT} will
+likely have instructions that are oddly sized or are not stored in a
+conventional manner.
+
+It may also be desirable (from an efficiency standpoint) to define
+custom breakpoint insertion and removal routines if
+@code{BREAKPOINT_FROM_PC} needs to read the target's memory for some
+reason.
+
+@item ADJUST_BREAKPOINT_ADDRESS (@var{address})
+@findex ADJUST_BREAKPOINT_ADDRESS
+@cindex breakpoint address adjusted
+Given an address at which a breakpoint is desired, return a breakpoint
+address adjusted to account for architectural constraints on
+breakpoint placement. This method is not needed by most targets.
+
+The FR-V target (see @file{frv-tdep.c}) requires this method.
+The FR-V is a VLIW architecture in which a number of RISC-like
+instructions are grouped (packed) together into an aggregate
+instruction or instruction bundle. When the processor executes
+one of these bundles, the component instructions are executed
+in parallel.
+
+In the course of optimization, the compiler may group instructions
+from distinct source statements into the same bundle. The line number
+information associated with one of the latter statements will likely
+refer to some instruction other than the first one in the bundle. So,
+if the user attempts to place a breakpoint on one of these latter
+statements, @value{GDBN} must be careful to @emph{not} place the break
+instruction on any instruction other than the first one in the bundle.
+(Remember though that the instructions within a bundle execute
+in parallel, so the @emph{first} instruction is the instruction
+at the lowest address and has nothing to do with execution order.)
+
+The FR-V's @code{ADJUST_BREAKPOINT_ADDRESS} method will adjust a
+breakpoint's address by scanning backwards for the beginning of
+the bundle, returning the address of the bundle.
+
+Since the adjustment of a breakpoint may significantly alter a user's
+expectation, @value{GDBN} prints a warning when an adjusted breakpoint
+is initially set and each time that that breakpoint is hit.
+
+@item DEPRECATED_CALL_DUMMY_WORDS
+@findex DEPRECATED_CALL_DUMMY_WORDS
+Pointer to an array of @code{LONGEST} words of data containing
+host-byte-ordered @code{DEPRECATED_REGISTER_SIZE} sized values that
+partially specify the sequence of instructions needed for an inferior
+function call.
+
+Should be deprecated in favor of a macro that uses target-byte-ordered
+data.
+
+This method has been replaced by @code{push_dummy_code}
+(@pxref{push_dummy_code}).
+
+@item DEPRECATED_SIZEOF_CALL_DUMMY_WORDS
+@findex DEPRECATED_SIZEOF_CALL_DUMMY_WORDS
+The size of @code{DEPRECATED_CALL_DUMMY_WORDS}. This must return a
+positive value. See also @code{DEPRECATED_CALL_DUMMY_LENGTH}.
+
+This method has been replaced by @code{push_dummy_code}
+(@pxref{push_dummy_code}).
+
+@item CALL_DUMMY
+@findex CALL_DUMMY
+A static initializer for @code{DEPRECATED_CALL_DUMMY_WORDS}.
+Deprecated.
+
+This method has been replaced by @code{push_dummy_code}
+(@pxref{push_dummy_code}).
+
+@item CALL_DUMMY_LOCATION
+@findex CALL_DUMMY_LOCATION
+See the file @file{inferior.h}.
+
+This method has been replaced by @code{push_dummy_code}
+(@pxref{push_dummy_code}).
+
+@item CANNOT_FETCH_REGISTER (@var{regno})
+@findex CANNOT_FETCH_REGISTER
+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 (@var{regno})
+@findex CANNOT_STORE_REGISTER
+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,
+@value{GDBN} will assume that all registers may be written.
+
+@item DO_DEFERRED_STORES
+@itemx CLEAR_DEFERRED_STORES
+@findex CLEAR_DEFERRED_STORES
+@findex DO_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 int CONVERT_REGISTER_P(@var{regnum})
+@findex CONVERT_REGISTER_P
+Return non-zero if register @var{regnum} can represent data values in a
+non-standard form.
+@xref{Target Architecture Definition, , Using Different Register and Memory Data Representations}.
+
+@item DECR_PC_AFTER_BREAK
+@findex 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
+@code{BREAKPOINT}, though not always. For most targets this value will be 0.
+
+@item DISABLE_UNSETTABLE_BREAK (@var{addr})
+@findex DISABLE_UNSETTABLE_BREAK
+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 PRINT_FLOAT_INFO()
+@findex PRINT_FLOAT_INFO
+If defined, then the @samp{info float} command will print information about
+the processor's floating point unit.
+
+@item print_registers_info (@var{gdbarch}, @var{frame}, @var{regnum}, @var{all})
+@findex print_registers_info
+If defined, pretty print the value of the register @var{regnum} for the
+specified @var{frame}. If the value of @var{regnum} is -1, pretty print
+either all registers (@var{all} is non zero) or a select subset of
+registers (@var{all} is zero).
+
+The default method prints one register per line, and if @var{all} is
+zero omits floating-point registers.
+
+@item PRINT_VECTOR_INFO()
+@findex PRINT_VECTOR_INFO
+If defined, then the @samp{info vector} command will call this function
+to print information about the processor's vector unit.
+
+By default, the @samp{info vector} command will print all vector
+registers (the register's type having the vector attribute).
+
+@item DWARF_REG_TO_REGNUM
+@findex DWARF_REG_TO_REGNUM
+Convert DWARF register number into @value{GDBN} regnum. If not defined,
+no conversion will be performed.
+
+@item DWARF2_REG_TO_REGNUM
+@findex DWARF2_REG_TO_REGNUM
+Convert DWARF2 register number into @value{GDBN} regnum. If not
+defined, no conversion will be performed.
+
+@item ECOFF_REG_TO_REGNUM
+@findex ECOFF_REG_TO_REGNUM
+Convert ECOFF register number into @value{GDBN} regnum. If not defined,
+no conversion will be performed.
+
+@item END_OF_TEXT_DEFAULT
+@findex END_OF_TEXT_DEFAULT
+This is an expression that should designate the end of the text section.
+@c (? FIXME ?)
+
+@item EXTRACT_RETURN_VALUE(@var{type}, @var{regbuf}, @var{valbuf})
+@findex EXTRACT_RETURN_VALUE
+Define this to extract a function's return value of type @var{type} from
+the raw register state @var{regbuf} and copy that, in virtual format,
+into @var{valbuf}.
+
+This method has been deprecated in favour of @code{gdbarch_return_value}
+(@pxref{gdbarch_return_value}).
+
+@item DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS(@var{regbuf})
+@findex DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS
+@anchor{DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS}
+When defined, extract from the array @var{regbuf} (containing the raw
+register state) the @code{CORE_ADDR} at which a function should return
+its structure value.
+
+@xref{gdbarch_return_value}.
+
+@item DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P()
+@findex DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P
+Predicate for @code{DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS}.
+
+@item DEPRECATED_FP_REGNUM
+@findex DEPRECATED_FP_REGNUM
+If the virtual frame pointer is kept in a register, then define this
+macro to be the number (greater than or equal to zero) of that register.
+
+This should only need to be defined if @code{DEPRECATED_TARGET_READ_FP}
+is not defined.
+
+@item DEPRECATED_FRAMELESS_FUNCTION_INVOCATION(@var{fi})
+@findex DEPRECATED_FRAMELESS_FUNCTION_INVOCATION
+Define this to an expression that returns 1 if the function invocation
+represented by @var{fi} does not have a stack frame associated with it.
+Otherwise return 0.
+
+@item frame_align (@var{address})
+@anchor{frame_align}
+@findex frame_align
+Define this to adjust @var{address} so that it meets the alignment
+requirements for the start of a new stack frame. A stack frame's
+alignment requirements are typically stronger than a target processors
+stack alignment requirements (@pxref{DEPRECATED_STACK_ALIGN}).
+
+This function is used to ensure that, when creating a dummy frame, both
+the initial stack pointer and (if needed) the address of the return
+value are correctly aligned.
+
+Unlike @code{DEPRECATED_STACK_ALIGN}, this function always adjusts the
+address in the direction of stack growth.
+
+By default, no frame based stack alignment is performed.
+
+@item int frame_red_zone_size
+
+The number of bytes, beyond the innermost-stack-address, reserved by the
+@sc{abi}. A function is permitted to use this scratch area (instead of
+allocating extra stack space).
+
+When performing an inferior function call, to ensure that it does not
+modify this area, @value{GDBN} adjusts the innermost-stack-address by
+@var{frame_red_zone_size} bytes before pushing parameters onto the
+stack.
+
+By default, zero bytes are allocated. The value must be aligned
+(@pxref{frame_align}).
+
+The @sc{amd64} (nee x86-64) @sc{abi} documentation refers to the
+@emph{red zone} when describing this scratch area.
+@cindex red zone
+
+@item DEPRECATED_FRAME_CHAIN(@var{frame})
+@findex DEPRECATED_FRAME_CHAIN
+Given @var{frame}, return a pointer to the calling frame.
+
+@item DEPRECATED_FRAME_CHAIN_VALID(@var{chain}, @var{thisframe})
+@findex DEPRECATED_FRAME_CHAIN_VALID
+Define this to be an expression that returns zero if the given frame is an
+outermost frame, with no caller, and nonzero otherwise. Most normal
+situations can be handled without defining this macro, including @code{NULL}
+chain pointers, dummy frames, and frames whose PC values are inside the
+startup file (e.g.@: @file{crt0.o}), inside @code{main}, or inside
+@code{_start}.
+
+@item DEPRECATED_FRAME_INIT_SAVED_REGS(@var{frame})
+@findex DEPRECATED_FRAME_INIT_SAVED_REGS
+See @file{frame.h}. Determines the address of all registers in the
+current stack frame storing each in @code{frame->saved_regs}. Space for
+@code{frame->saved_regs} shall be allocated by
+@code{DEPRECATED_FRAME_INIT_SAVED_REGS} using
+@code{frame_saved_regs_zalloc}.
+
+@code{FRAME_FIND_SAVED_REGS} is deprecated.
+
+@item FRAME_NUM_ARGS (@var{fi})
+@findex FRAME_NUM_ARGS
+For the frame described by @var{fi} return the number of arguments that
+are being passed. If the number of arguments is not known, return
+@code{-1}.
+
+@item DEPRECATED_FRAME_SAVED_PC(@var{frame})
+@findex DEPRECATED_FRAME_SAVED_PC
+@anchor{DEPRECATED_FRAME_SAVED_PC} Given @var{frame}, return the pc
+saved there. This is the return address.
+
+This method is deprecated. @xref{unwind_pc}.
+
+@item CORE_ADDR unwind_pc (struct frame_info *@var{this_frame})
+@findex unwind_pc
+@anchor{unwind_pc} Return the instruction address, in @var{this_frame}'s
+caller, at which execution will resume after @var{this_frame} returns.
+This is commonly refered to as the return address.
+
+The implementation, which must be frame agnostic (work with any frame),
+is typically no more than:
+
+@smallexample
+ULONGEST pc;
+frame_unwind_unsigned_register (this_frame, D10V_PC_REGNUM, &pc);
+return d10v_make_iaddr (pc);
+@end smallexample
+
+@noindent
+@xref{DEPRECATED_FRAME_SAVED_PC}, which this method replaces.
+
+@item CORE_ADDR unwind_sp (struct frame_info *@var{this_frame})
+@findex unwind_sp
+@anchor{unwind_sp} Return the frame's inner most stack address. This is
+commonly refered to as the frame's @dfn{stack pointer}.
+
+The implementation, which must be frame agnostic (work with any frame),
+is typically no more than:
+
+@smallexample
+ULONGEST sp;
+frame_unwind_unsigned_register (this_frame, D10V_SP_REGNUM, &sp);
+return d10v_make_daddr (sp);
+@end smallexample
+
+@noindent
+@xref{TARGET_READ_SP}, which this method replaces.
+
+@item FUNCTION_EPILOGUE_SIZE
+@findex 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 FUNCTION_START_OFFSET
+@findex FUNCTION_START_OFFSET
+An integer, giving the offset in bytes from a function's address (as
+used in the values of symbols, function pointers, etc.), and the
+function's first genuine instruction.
+
+This is zero on almost all machines: the function's address is usually
+the address of its first instruction. However, on the VAX, for example,
+each function starts with two bytes containing a bitmask indicating
+which registers to save upon entry to the function. The VAX @code{call}
+instructions check this value, and save the appropriate registers
+automatically. Thus, since the offset from the function's address to
+its first instruction is two bytes, @code{FUNCTION_START_OFFSET} would
+be 2 on the VAX.
+
+@item GCC_COMPILED_FLAG_SYMBOL
+@itemx GCC2_COMPILED_FLAG_SYMBOL
+@findex GCC2_COMPILED_FLAG_SYMBOL
+@findex GCC_COMPILED_FLAG_SYMBOL
+If defined, these are the names of the symbols that @value{GDBN} will
+look for to detect that GCC compiled the file. The default symbols
+are @code{gcc_compiled.} and @code{gcc2_compiled.},
+respectively. (Currently only defined for the Delta 68.)
+
+@item @value{GDBN}_MULTI_ARCH
+@findex @value{GDBN}_MULTI_ARCH
+If defined and non-zero, enables support for multiple architectures
+within @value{GDBN}.
+
+This support can be enabled at two levels. At level one, only
+definitions for previously undefined macros are provided; at level two,
+a multi-arch definition of all architecture dependent macros will be
+defined.
+
+@item @value{GDBN}_TARGET_IS_HPPA
+@findex @value{GDBN}_TARGET_IS_HPPA
+This determines whether horrible kludge code in @file{dbxread.c} and
+@file{partial-stab.h} is used to mangle multiple-symbol-table files from
+HPPA's. This should all be ripped out, and a scheme like @file{elfread.c}
+used instead.
+
+@item GET_LONGJMP_TARGET
+@findex 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
+the header file @file{setjmp.h} is needed to define it.
+
+This macro determines the target PC address that @code{longjmp} will jump to,
+assuming that we have just stopped at a @code{longjmp} breakpoint. It takes a
+@code{CORE_ADDR *} as argument, and stores the target PC value through this
+pointer. It examines the current state of the machine as needed.
+
+@item DEPRECATED_GET_SAVED_REGISTER
+@findex DEPRECATED_GET_SAVED_REGISTER
+Define this if you need to supply your own definition for the function
+@code{DEPRECATED_GET_SAVED_REGISTER}.
+
+@item DEPRECATED_IBM6000_TARGET
+@findex DEPRECATED_IBM6000_TARGET
+Shows that we are configured for an IBM RS/6000 system. This
+conditional should be eliminated (FIXME) and replaced by
+feature-specific macros. It was introduced in a haste and we are
+repenting at leisure.
+
+@item I386_USE_GENERIC_WATCHPOINTS
+An x86-based target can define this to use the generic x86 watchpoint
+support; see @ref{Algorithms, I386_USE_GENERIC_WATCHPOINTS}.
+
+@item SYMBOLS_CAN_START_WITH_DOLLAR
+@findex SYMBOLS_CAN_START_WITH_DOLLAR
+Some systems have routines whose names start with @samp{$}. Giving this
+macro a non-zero value tells @value{GDBN}'s expression parser to check for such
+routines when parsing tokens that begin with @samp{$}.
+
+On HP-UX, certain system routines (millicode) have names beginning with
+@samp{$} or @samp{$$}. For example, @code{$$dyncall} is a millicode
+routine that handles inter-space procedure calls on PA-RISC.
+
+@item DEPRECATED_INIT_EXTRA_FRAME_INFO (@var{fromleaf}, @var{frame})
+@findex DEPRECATED_INIT_EXTRA_FRAME_INFO
+If additional information about the frame is required this should be
+stored in @code{frame->extra_info}. Space for @code{frame->extra_info}
+is allocated using @code{frame_extra_info_zalloc}.
+
+@item DEPRECATED_INIT_FRAME_PC (@var{fromleaf}, @var{prev})
+@findex DEPRECATED_INIT_FRAME_PC
+This is a C statement that sets the pc of the frame pointed to by
+@var{prev}. [By default...]
+
+@item INNER_THAN (@var{lhs}, @var{rhs})
+@findex INNER_THAN
+Returns non-zero if stack address @var{lhs} is inner than (nearer to the
+stack top) stack address @var{rhs}. Define this as @code{lhs < rhs} if
+the target's stack grows downward in memory, or @code{lhs > rsh} if the
+stack grows upward.
+
+@item gdbarch_in_function_epilogue_p (@var{gdbarch}, @var{pc})
+@findex gdbarch_in_function_epilogue_p
+Returns non-zero if the given @var{pc} is in the epilogue of a function.
+The epilogue of a function is defined as the part of a function where
+the stack frame of the function already has been destroyed up to the
+final `return from function call' instruction.
+
+@item SIGTRAMP_START (@var{pc})
+@findex SIGTRAMP_START
+@itemx SIGTRAMP_END (@var{pc})
+@findex SIGTRAMP_END
+Define these to be the start and end address of the @code{sigtramp} for the
+given @var{pc}. On machines where the address is just a compile time
+constant, the macro expansion will typically just ignore the supplied
+@var{pc}.
+
+@item IN_SOLIB_CALL_TRAMPOLINE (@var{pc}, @var{name})
+@findex IN_SOLIB_CALL_TRAMPOLINE
+Define this to evaluate to nonzero if the program is stopped in the
+trampoline that connects to a shared library.
+
+@item IN_SOLIB_RETURN_TRAMPOLINE (@var{pc}, @var{name})
+@findex IN_SOLIB_RETURN_TRAMPOLINE
+Define this to evaluate to nonzero if the program is stopped in the
+trampoline that returns from a shared library.
+
+@item IN_SOLIB_DYNSYM_RESOLVE_CODE (@var{pc})
+@findex IN_SOLIB_DYNSYM_RESOLVE_CODE
+Define this to evaluate to nonzero if the program is stopped in the
+dynamic linker.
+
+@item SKIP_SOLIB_RESOLVER (@var{pc})
+@findex SKIP_SOLIB_RESOLVER
+Define this to evaluate to the (nonzero) address at which execution
+should continue to get past the dynamic linker's symbol resolution
+function. A zero value indicates that it is not important or necessary
+to set a breakpoint to get through the dynamic linker and that single
+stepping will suffice.
+
+@item INTEGER_TO_ADDRESS (@var{type}, @var{buf})
+@findex INTEGER_TO_ADDRESS
+@cindex converting integers to addresses
+Define this when the architecture needs to handle non-pointer to address
+conversions specially. Converts that value to an address according to
+the current architectures conventions.
+
+@emph{Pragmatics: When the user copies a well defined expression from
+their source code and passes it, as a parameter, to @value{GDBN}'s
+@code{print} command, they should get the same value as would have been
+computed by the target program. Any deviation from this rule can cause
+major confusion and annoyance, and needs to be justified carefully. In
+other words, @value{GDBN} doesn't really have the freedom to do these
+conversions in clever and useful ways. It has, however, been pointed
+out that users aren't complaining about how @value{GDBN} casts integers
+to pointers; they are complaining that they can't take an address from a
+disassembly listing and give it to @code{x/i}. Adding an architecture
+method like @code{INTEGER_TO_ADDRESS} certainly makes it possible for
+@value{GDBN} to ``get it right'' in all circumstances.}
+
+@xref{Target Architecture Definition, , Pointers Are Not Always
+Addresses}.
+
+@item NO_HIF_SUPPORT
+@findex NO_HIF_SUPPORT
+(Specific to the a29k.)
+
+@item POINTER_TO_ADDRESS (@var{type}, @var{buf})
+@findex POINTER_TO_ADDRESS
+Assume that @var{buf} holds a pointer of type @var{type}, in the
+appropriate format for the current architecture. Return the byte
+address the pointer refers to.
+@xref{Target Architecture Definition, , Pointers Are Not Always Addresses}.
+
+@item REGISTER_CONVERTIBLE (@var{reg})
+@findex REGISTER_CONVERTIBLE
+Return non-zero if @var{reg} uses different raw and virtual formats.
+@xref{Target Architecture Definition, , Raw and Virtual Register Representations}.
+
+@item REGISTER_TO_VALUE(@var{regnum}, @var{type}, @var{from}, @var{to})
+@findex REGISTER_TO_VALUE
+Convert the raw contents of register @var{regnum} into a value of type
+@var{type}.
+@xref{Target Architecture Definition, , Using Different Register and Memory Data Representations}.
+
+@item DEPRECATED_REGISTER_RAW_SIZE (@var{reg})
+@findex DEPRECATED_REGISTER_RAW_SIZE
+Return the raw size of @var{reg}; defaults to the size of the register's
+virtual type.
+@xref{Target Architecture Definition, , Raw and Virtual Register Representations}.
+
+@item register_reggroup_p (@var{gdbarch}, @var{regnum}, @var{reggroup})
+@findex register_reggroup_p
+@cindex register groups
+Return non-zero if register @var{regnum} is a member of the register
+group @var{reggroup}.
+
+By default, registers are grouped as follows:
+
+@table @code
+@item float_reggroup
+Any register with a valid name and a floating-point type.
+@item vector_reggroup
+Any register with a valid name and a vector type.
+@item general_reggroup
+Any register with a valid name and a type other than vector or
+floating-point. @samp{float_reggroup}.
+@item save_reggroup
+@itemx restore_reggroup
+@itemx all_reggroup
+Any register with a valid name.
+@end table
+
+@item DEPRECATED_REGISTER_VIRTUAL_SIZE (@var{reg})
+@findex DEPRECATED_REGISTER_VIRTUAL_SIZE
+Return the virtual size of @var{reg}; defaults to the size of the
+register's virtual type.
+Return the virtual size of @var{reg}.
+@xref{Target Architecture Definition, , Raw and Virtual Register Representations}.
+
+@item DEPRECATED_REGISTER_VIRTUAL_TYPE (@var{reg})
+@findex REGISTER_VIRTUAL_TYPE
+Return the virtual type of @var{reg}.
+@xref{Target Architecture Definition, , Raw and Virtual Register Representations}.
+
+@item struct type *register_type (@var{gdbarch}, @var{reg})
+@findex register_type
+If defined, return the type of register @var{reg}. This function
+superseeds @code{DEPRECATED_REGISTER_VIRTUAL_TYPE}. @xref{Target Architecture
+Definition, , Raw and Virtual Register Representations}.
+
+@item REGISTER_CONVERT_TO_VIRTUAL(@var{reg}, @var{type}, @var{from}, @var{to})
+@findex REGISTER_CONVERT_TO_VIRTUAL
+Convert the value of register @var{reg} from its raw form to its virtual
+form.
+@xref{Target Architecture Definition, , Raw and Virtual Register Representations}.
+
+@item REGISTER_CONVERT_TO_RAW(@var{type}, @var{reg}, @var{from}, @var{to})
+@findex REGISTER_CONVERT_TO_RAW
+Convert the value of register @var{reg} from its virtual form to its raw
+form.
+@xref{Target Architecture Definition, , Raw and Virtual Register Representations}.
+
+@item const struct regset *regset_from_core_section (struct gdbarch * @var{gdbarch}, const char * @var{sect_name}, size_t @var{sect_size})
+@findex regset_from_core_section
+Return the appropriate register set for a core file section with name
+@var{sect_name} and size @var{sect_size}.
+
+
+@item RETURN_VALUE_ON_STACK(@var{type})
+@findex RETURN_VALUE_ON_STACK
+@cindex returning structures by value
+@cindex structures, returning by value
+
+Return non-zero if values of type TYPE are returned on the stack, using
+the ``struct convention'' (i.e., the caller provides a pointer to a
+buffer in which the callee should store the return value). This
+controls how the @samp{finish} command finds a function's return value,
+and whether an inferior function call reserves space on the stack for
+the return value.
+
+The full logic @value{GDBN} uses here is kind of odd.
+
+@itemize @bullet
+@item
+If the type being returned by value is not a structure, union, or array,
+and @code{RETURN_VALUE_ON_STACK} returns zero, then @value{GDBN}
+concludes the value is not returned using the struct convention.
+
+@item
+Otherwise, @value{GDBN} calls @code{USE_STRUCT_CONVENTION} (see below).
+If that returns non-zero, @value{GDBN} assumes the struct convention is
+in use.
+@end itemize
+
+In other words, to indicate that a given type is returned by value using
+the struct convention, that type must be either a struct, union, array,
+or something @code{RETURN_VALUE_ON_STACK} likes, @emph{and} something
+that @code{USE_STRUCT_CONVENTION} likes.
+
+Note that, in C and C@t{++}, arrays are never returned by value. In those
+languages, these predicates will always see a pointer type, never an
+array type. All the references above to arrays being returned by value
+apply only to other languages.
+
+@item SOFTWARE_SINGLE_STEP_P()
+@findex SOFTWARE_SINGLE_STEP_P
+Define this as 1 if the target does not have a hardware single-step
+mechanism. The macro @code{SOFTWARE_SINGLE_STEP} must also be defined.
+
+@item SOFTWARE_SINGLE_STEP(@var{signal}, @var{insert_breapoints_p})
+@findex SOFTWARE_SINGLE_STEP
+A function that inserts or removes (depending on
+@var{insert_breapoints_p}) breakpoints at each possible destinations of
+the next instruction. See @file{sparc-tdep.c} and @file{rs6000-tdep.c}
+for examples.
+
+@item SOFUN_ADDRESS_MAYBE_MISSING
+@findex SOFUN_ADDRESS_MAYBE_MISSING
+Somebody clever observed that, the more actual addresses you have in the
+debug information, the more time the linker has to spend relocating
+them. So whenever there's some other way the debugger could find the
+address it needs, you should omit it from the debug info, to make
+linking faster.
+
+@code{SOFUN_ADDRESS_MAYBE_MISSING} indicates that a particular set of
+hacks of this sort are in use, affecting @code{N_SO} and @code{N_FUN}
+entries in stabs-format debugging information. @code{N_SO} stabs mark
+the beginning and ending addresses of compilation units in the text
+segment. @code{N_FUN} stabs mark the starts and ends of functions.
+
+@code{SOFUN_ADDRESS_MAYBE_MISSING} means two things:
+
+@itemize @bullet
+@item
+@code{N_FUN} stabs have an address of zero. Instead, you should find the
+addresses where the function starts by taking the function name from
+the stab, and then looking that up in the minsyms (the
+linker/assembler symbol table). In other words, the stab has the
+name, and the linker/assembler symbol table is the only place that carries
+the address.
+
+@item
+@code{N_SO} stabs have an address of zero, too. You just look at the
+@code{N_FUN} stabs that appear before and after the @code{N_SO} stab,
+and guess the starting and ending addresses of the compilation unit from
+them.
+@end itemize
+
+@item PCC_SOL_BROKEN
+@findex PCC_SOL_BROKEN
+(Used only in the Convex target.)
+
+@item PC_IN_SIGTRAMP (@var{pc}, @var{name})
+@findex PC_IN_SIGTRAMP
+@cindex sigtramp
+The @dfn{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 function, given a program counter value in @var{pc} and the
+(possibly NULL) name of the function in which that @var{pc} resides,
+returns nonzero if the @var{pc} and/or @var{name} show that we are in
+sigtramp.
+
+@item PC_LOAD_SEGMENT
+@findex PC_LOAD_SEGMENT
+If defined, print information about the load segment for the program
+counter. (Defined only for the RS/6000.)
+
+@item PC_REGNUM
+@findex PC_REGNUM
+If the program counter is kept in a register, then define this macro to
+be the number (greater than or equal to zero) of that register.
+
+This should only need to be defined if @code{TARGET_READ_PC} and
+@code{TARGET_WRITE_PC} are not defined.
+
+@item PARM_BOUNDARY
+@findex PARM_BOUNDARY
+If non-zero, round arguments to a boundary of this many bits before
+pushing them on the stack.
+
+@item stabs_argument_has_addr (@var{gdbarch}, @var{type})
+@findex stabs_argument_has_addr
+@findex DEPRECATED_REG_STRUCT_HAS_ADDR
+@anchor{stabs_argument_has_addr} Define this to return nonzero if a
+function argument of type @var{type} is passed by reference instead of
+value.
+
+This method replaces @code{DEPRECATED_REG_STRUCT_HAS_ADDR}
+(@pxref{DEPRECATED_REG_STRUCT_HAS_ADDR}).
+
+@item PROCESS_LINENUMBER_HOOK
+@findex PROCESS_LINENUMBER_HOOK
+A hook defined for XCOFF reading.
+
+@item PROLOGUE_FIRSTLINE_OVERLAP
+@findex PROLOGUE_FIRSTLINE_OVERLAP
+(Only used in unsupported Convex configuration.)
+
+@item PS_REGNUM
+@findex PS_REGNUM
+If defined, this is the number of the processor status register. (This
+definition is only used in generic code when parsing "$ps".)
+
+@item DEPRECATED_POP_FRAME
+@findex DEPRECATED_POP_FRAME
+@findex frame_pop
+If defined, used by @code{frame_pop} to remove a stack frame. This
+method has been superseeded by generic code.
+
+@item push_dummy_call (@var{gdbarch}, @var{func_addr}, @var{regcache}, @var{pc_addr}, @var{nargs}, @var{args}, @var{sp}, @var{struct_return}, @var{struct_addr})
+@findex push_dummy_call
+@findex DEPRECATED_PUSH_ARGUMENTS.
+@anchor{push_dummy_call} Define this to push the dummy frame's call to
+the inferior function onto the stack. In addition to pushing
+@var{nargs}, the code should push @var{struct_addr} (when
+@var{struct_return}), and the return address (@var{bp_addr}).
+
+Returns the updated top-of-stack pointer.
+
+This method replaces @code{DEPRECATED_PUSH_ARGUMENTS}.
+
+@item CORE_ADDR push_dummy_code (@var{gdbarch}, @var{sp}, @var{funaddr}, @var{using_gcc}, @var{args}, @var{nargs}, @var{value_type}, @var{real_pc}, @var{bp_addr})
+@findex push_dummy_code
+@findex DEPRECATED_FIX_CALL_DUMMY
+@anchor{push_dummy_code} Given a stack based call dummy, push the
+instruction sequence (including space for a breakpoint) to which the
+called function should return.
+
+Set @var{bp_addr} to the address at which the breakpoint instruction
+should be inserted, @var{real_pc} to the resume address when starting
+the call sequence, and return the updated inner-most stack address.
+
+By default, the stack is grown sufficient to hold a frame-aligned
+(@pxref{frame_align}) breakpoint, @var{bp_addr} is set to the address
+reserved for that breakpoint, and @var{real_pc} set to @var{funaddr}.
+
+This method replaces @code{DEPRECATED_CALL_DUMMY_WORDS},
+@code{DEPRECATED_SIZEOF_CALL_DUMMY_WORDS}, @code{CALL_DUMMY},
+@code{CALL_DUMMY_LOCATION}, @code{DEPRECATED_REGISTER_SIZE},
+@code{GDB_TARGET_IS_HPPA},
+@code{DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET}, and
+@code{DEPRECATED_FIX_CALL_DUMMY}.
+
+@item DEPRECATED_PUSH_DUMMY_FRAME
+@findex DEPRECATED_PUSH_DUMMY_FRAME
+Used in @samp{call_function_by_hand} to create an artificial stack frame.
+
+@item DEPRECATED_REGISTER_BYTES
+@findex DEPRECATED_REGISTER_BYTES
+The total amount of space needed to store @value{GDBN}'s copy of the
+machine's register state.
+
+This is no longer needed. @value{GDBN} instead computes the size of the
+register buffer at run-time.
+
+@item REGISTER_NAME(@var{i})
+@findex REGISTER_NAME
+Return the name of register @var{i} as a string. May return @code{NULL}
+or @code{NUL} to indicate that register @var{i} is not valid.
+
+@item DEPRECATED_REG_STRUCT_HAS_ADDR (@var{gcc_p}, @var{type})
+@findex DEPRECATED_REG_STRUCT_HAS_ADDR
+@anchor{DEPRECATED_REG_STRUCT_HAS_ADDR}Define this to return 1 if the
+given type will be passed by pointer rather than directly.
+
+This method has been replaced by @code{stabs_argument_has_addr}
+(@pxref{stabs_argument_has_addr}).
+
+@item SAVE_DUMMY_FRAME_TOS (@var{sp})
+@findex SAVE_DUMMY_FRAME_TOS
+@anchor{SAVE_DUMMY_FRAME_TOS} Used in @samp{call_function_by_hand} to
+notify the target dependent code of the top-of-stack value that will be
+passed to the the inferior code. This is the value of the @code{SP}
+after both the dummy frame and space for parameters/results have been
+allocated on the stack. @xref{unwind_dummy_id}.
+
+@item SDB_REG_TO_REGNUM
+@findex SDB_REG_TO_REGNUM
+Define this to convert sdb register numbers into @value{GDBN} regnums. If not
+defined, no conversion will be done.
+
+@item enum return_value_convention gdbarch_return_value (struct gdbarch *@var{gdbarch}, struct type *@var{valtype}, struct regcache *@var{regcache}, void *@var{readbuf}, const void *@var{writebuf})
+@findex gdbarch_return_value
+@anchor{gdbarch_return_value} Given a function with a return-value of
+type @var{rettype}, return which return-value convention that function
+would use.
+
+@value{GDBN} currently recognizes two function return-value conventions:
+@code{RETURN_VALUE_REGISTER_CONVENTION} where the return value is found
+in registers; and @code{RETURN_VALUE_STRUCT_CONVENTION} where the return
+value is found in memory and the address of that memory location is
+passed in as the function's first parameter.
+
+If the register convention is being used, and @var{writebuf} is
+non-@code{NULL}, also copy the return-value in @var{writebuf} into
+@var{regcache}.
+
+If the register convention is being used, and @var{readbuf} is
+non-@code{NULL}, also copy the return value from @var{regcache} into
+@var{readbuf} (@var{regcache} contains a copy of the registers from the
+just returned function).
+
+@xref{DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS}, for a description of how
+return-values that use the struct convention are handled.
+
+@emph{Maintainer note: This method replaces separate predicate, extract,
+store methods. By having only one method, the logic needed to determine
+the return-value convention need only be implemented in one place. If
+@value{GDBN} were written in an @sc{oo} language, this method would
+instead return an object that knew how to perform the register
+return-value extract and store.}
+
+@emph{Maintainer note: This method does not take a @var{gcc_p}
+parameter, and such a parameter should not be added. If an architecture
+that requires per-compiler or per-function information be identified,
+then the replacement of @var{rettype} with @code{struct value}
+@var{function} should be persued.}
+
+@emph{Maintainer note: The @var{regcache} parameter limits this methods
+to the inner most frame. While replacing @var{regcache} with a
+@code{struct frame_info} @var{frame} parameter would remove that
+limitation there has yet to be a demonstrated need for such a change.}
+
+@item SKIP_PERMANENT_BREAKPOINT
+@findex SKIP_PERMANENT_BREAKPOINT
+Advance the inferior's PC past a permanent breakpoint. @value{GDBN} normally
+steps over a breakpoint by removing it, stepping one instruction, and
+re-inserting the breakpoint. However, permanent breakpoints are
+hardwired into the inferior, and can't be removed, so this strategy
+doesn't work. Calling @code{SKIP_PERMANENT_BREAKPOINT} adjusts the processor's
+state so that execution will resume just after the breakpoint. This
+macro does the right thing even when the breakpoint is in the delay slot
+of a branch or jump.
+
+@item SKIP_PROLOGUE (@var{pc})
+@findex SKIP_PROLOGUE
+A C expression that returns the address of the ``real'' code beyond the
+function entry prologue found at @var{pc}.
+
+@item SKIP_TRAMPOLINE_CODE (@var{pc})
+@findex SKIP_TRAMPOLINE_CODE
+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
+@findex SP_REGNUM
+If the stack-pointer is kept in a register, then define this macro to be
+the number (greater than or equal to zero) of that register, or -1 if
+there is no such register.
+
+@item STAB_REG_TO_REGNUM
+@findex STAB_REG_TO_REGNUM
+Define this to convert stab register numbers (as gotten from `r'
+declarations) into @value{GDBN} regnums. If not defined, no conversion will be
+done.
+
+@item DEPRECATED_STACK_ALIGN (@var{addr})
+@anchor{DEPRECATED_STACK_ALIGN}
+@findex DEPRECATED_STACK_ALIGN
+Define this to increase @var{addr} so that it meets the alignment
+requirements for the processor's stack.
+
+Unlike @ref{frame_align}, this function always adjusts @var{addr}
+upwards.
+
+By default, no stack alignment is performed.
+
+@item STEP_SKIPS_DELAY (@var{addr})
+@findex STEP_SKIPS_DELAY
+Define this to return true if the address is of an instruction with a
+delay slot. If a breakpoint has been placed in the instruction's delay
+slot, @value{GDBN} will single-step over that instruction before resuming
+normally. Currently only defined for the Mips.
+
+@item STORE_RETURN_VALUE (@var{type}, @var{regcache}, @var{valbuf})
+@findex STORE_RETURN_VALUE
+A C expression that writes the function return value, found in
+@var{valbuf}, into the @var{regcache}. @var{type} is the type of the
+value that is to be returned.
+
+This method has been deprecated in favour of @code{gdbarch_return_value}
+(@pxref{gdbarch_return_value}).
+
+@item SUN_FIXED_LBRAC_BUG
+@findex SUN_FIXED_LBRAC_BUG
+(Used only for Sun-3 and Sun-4 targets.)
+
+@item SYMBOL_RELOADING_DEFAULT
+@findex SYMBOL_RELOADING_DEFAULT
+The default value of the ``symbol-reloading'' variable. (Never defined in
+current sources.)
+
+@item TARGET_CHAR_BIT
+@findex TARGET_CHAR_BIT
+Number of bits in a char; defaults to 8.
+
+@item TARGET_CHAR_SIGNED
+@findex TARGET_CHAR_SIGNED
+Non-zero if @code{char} is normally signed on this architecture; zero if
+it should be unsigned.
+
+The ISO C standard requires the compiler to treat @code{char} as
+equivalent to either @code{signed char} or @code{unsigned char}; any
+character in the standard execution set is supposed to be positive.
+Most compilers treat @code{char} as signed, but @code{char} is unsigned
+on the IBM S/390, RS6000, and PowerPC targets.
+
+@item TARGET_COMPLEX_BIT
+@findex TARGET_COMPLEX_BIT
+Number of bits in a complex number; defaults to @code{2 * TARGET_FLOAT_BIT}.
+
+At present this macro is not used.
+
+@item TARGET_DOUBLE_BIT
+@findex TARGET_DOUBLE_BIT
+Number of bits in a double float; defaults to @code{8 * TARGET_CHAR_BIT}.
+
+@item TARGET_DOUBLE_COMPLEX_BIT
+@findex TARGET_DOUBLE_COMPLEX_BIT
+Number of bits in a double complex; defaults to @code{2 * TARGET_DOUBLE_BIT}.
+
+At present this macro is not used.
+
+@item TARGET_FLOAT_BIT
+@findex TARGET_FLOAT_BIT
+Number of bits in a float; defaults to @code{4 * TARGET_CHAR_BIT}.
+
+@item TARGET_INT_BIT
+@findex TARGET_INT_BIT
+Number of bits in an integer; defaults to @code{4 * TARGET_CHAR_BIT}.
+
+@item TARGET_LONG_BIT
+@findex TARGET_LONG_BIT
+Number of bits in a long integer; defaults to @code{4 * TARGET_CHAR_BIT}.
+
+@item TARGET_LONG_DOUBLE_BIT
+@findex TARGET_LONG_DOUBLE_BIT
+Number of bits in a long double float;
+defaults to @code{2 * TARGET_DOUBLE_BIT}.
+
+@item TARGET_LONG_LONG_BIT
+@findex TARGET_LONG_LONG_BIT
+Number of bits in a long long integer; defaults to @code{2 * TARGET_LONG_BIT}.
+
+@item TARGET_PTR_BIT
+@findex TARGET_PTR_BIT
+Number of bits in a pointer; defaults to @code{TARGET_INT_BIT}.
+
+@item TARGET_SHORT_BIT
+@findex TARGET_SHORT_BIT
+Number of bits in a short integer; defaults to @code{2 * TARGET_CHAR_BIT}.
+
+@item TARGET_READ_PC
+@findex TARGET_READ_PC
+@itemx TARGET_WRITE_PC (@var{val}, @var{pid})
+@findex TARGET_WRITE_PC
+@anchor{TARGET_WRITE_PC}
+@itemx TARGET_READ_SP
+@findex TARGET_READ_SP
+@itemx TARGET_READ_FP
+@findex TARGET_READ_FP
+@findex read_pc
+@findex write_pc
+@findex read_sp
+@findex read_fp
+@anchor{TARGET_READ_SP} These change the behavior of @code{read_pc},
+@code{write_pc}, @code{read_sp} and @code{deprecated_read_fp}. For most
+targets, these may be left undefined. @value{GDBN} 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.
+
+@xref{unwind_sp}, which replaces @code{TARGET_READ_SP}.
+
+@item TARGET_VIRTUAL_FRAME_POINTER(@var{pc}, @var{regp}, @var{offsetp})
+@findex TARGET_VIRTUAL_FRAME_POINTER
+Returns a @code{(register, offset)} pair representing the virtual frame
+pointer in use at the code address @var{pc}. If virtual frame pointers
+are not used, a default definition simply returns
+@code{DEPRECATED_FP_REGNUM}, with an offset of zero.
+
+@item TARGET_HAS_HARDWARE_WATCHPOINTS
+If non-zero, the target has support for hardware-assisted
+watchpoints. @xref{Algorithms, watchpoints}, for more details and
+other related macros.
+
+@item TARGET_PRINT_INSN (@var{addr}, @var{info})
+@findex TARGET_PRINT_INSN
+This is the function used by @value{GDBN} to print an assembly
+instruction. It prints the instruction at address @var{addr} in
+debugged memory and returns the length of the instruction, in bytes. If
+a target doesn't define its own printing routine, it defaults to an
+accessor function for the global pointer
+@code{deprecated_tm_print_insn}. This usually points to a function in
+the @code{opcodes} library (@pxref{Support Libraries, ,Opcodes}).
+@var{info} is a structure (of type @code{disassemble_info}) defined in
+@file{include/dis-asm.h} used to pass information to the instruction
+decoding routine.
+
+@item struct frame_id unwind_dummy_id (struct frame_info *@var{frame})
+@findex unwind_dummy_id
+@anchor{unwind_dummy_id} Given @var{frame} return a @code{struct
+frame_id} that uniquely identifies an inferior function call's dummy
+frame. The value returned must match the dummy frame stack value
+previously saved using @code{SAVE_DUMMY_FRAME_TOS}.
+@xref{SAVE_DUMMY_FRAME_TOS}.
+
+@item USE_STRUCT_CONVENTION (@var{gcc_p}, @var{type})
+@findex USE_STRUCT_CONVENTION
+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.
+
+This method has been deprecated in favour of @code{gdbarch_return_value}
+(@pxref{gdbarch_return_value}).
+
+@item VALUE_TO_REGISTER(@var{type}, @var{regnum}, @var{from}, @var{to})
+@findex VALUE_TO_REGISTER
+Convert a value of type @var{type} into the raw contents of register
+@var{regnum}'s.
+@xref{Target Architecture Definition, , Using Different Register and Memory Data Representations}.
+
+@item VARIABLES_INSIDE_BLOCK (@var{desc}, @var{gcc_p})
+@findex VARIABLES_INSIDE_BLOCK
+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 @value{GDBN} 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 (@var{desc}, @var{gcc_p})
+@findex OS9K_VARIABLES_INSIDE_BLOCK
+Similarly, for OS/9000. Defaults to 1.
+@end table
+
+Motorola M68K target conditionals.
+
+@ftable @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}.
+
+@item NAME_OF_MALLOC
+@findex NAME_OF_MALLOC
+A string containing the name of the function to call in order to
+allocate some memory in the inferior. The default value is "malloc".
+
+@end ftable
+
+@section Adding a New Target
+
+@cindex adding a target
+The following files add a target to @value{GDBN}:
+
+@table @file
+@vindex TDEPFILES
+@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{}} and @samp{TDEPLIBS=@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},
+but these are now deprecated, replaced by autoconf, and may go away in
+future versions of @value{GDBN}.
+
+@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. This is vastly preferable, since it is easier to understand
+and debug.
+
+@item gdb/@var{arch}-tdep.c
+@itemx gdb/@var{arch}-tdep.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{@var{ttt}-tdep.h}. It can be shared among many targets that use
+the same processor.
+
+@item gdb/config/@var{arch}/tm-@var{ttt}.h
+(@file{tm.h} is a link to this file, created by @code{configure}). Contains
+macro definitions about the target machine's registers, stack frame
+format and instructions.
+
+New targets do not need this file and should not create it.
+
+@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{ttt}.h}. It can be shared among many targets that use the
+same processor.
+
+New targets do not need this file and should not create it.
+
+@end table
+
+If you are adding a new operating system for an existing CPU chip, add a
+@file{config/tm-@var{os}.h} file that describes the operating system
+facilities that are unusual (extra symbol table info; the breakpoint
+instruction needed; etc.). Then write a @file{@var{arch}/tm-@var{os}.h}
+that just @code{#include}s @file{tm-@var{arch}.h} and
+@file{config/tm-@var{os}.h}.
+
+
+@section Converting an existing Target Architecture to Multi-arch
+@cindex converting targets to multi-arch
+
+This section describes the current accepted best practice for converting
+an existing target architecture to the multi-arch framework.
+
+The process consists of generating, testing, posting and committing a
+sequence of patches. Each patch must contain a single change, for
+instance:
+
+@itemize @bullet
+
+@item
+Directly convert a group of functions into macros (the conversion does
+not change the behavior of any of the functions).
+
+@item
+Replace a non-multi-arch with a multi-arch mechanism (e.g.,
+@code{FRAME_INFO}).
+
+@item
+Enable multi-arch level one.
+
+@item
+Delete one or more files.
+
+@end itemize
+
+@noindent
+There isn't a size limit on a patch, however, a developer is strongly
+encouraged to keep the patch size down.
+
+Since each patch is well defined, and since each change has been tested
+and shows no regressions, the patches are considered @emph{fairly}
+obvious. Such patches, when submitted by developers listed in the
+@file{MAINTAINERS} file, do not need approval. Occasional steps in the
+process may be more complicated and less clear. The developer is
+expected to use their judgment and is encouraged to seek advice as
+needed.
+
+@subsection Preparation
+
+The first step is to establish control. Build (with @option{-Werror}
+enabled) and test the target so that there is a baseline against which
+the debugger can be compared.
+
+At no stage can the test results regress or @value{GDBN} stop compiling
+with @option{-Werror}.
+
+@subsection Add the multi-arch initialization code
+
+The objective of this step is to establish the basic multi-arch
+framework. It involves
+
+@itemize @bullet
+
+@item
+The addition of a @code{@var{arch}_gdbarch_init} function@footnote{The
+above is from the original example and uses K&R C. @value{GDBN}
+has since converted to ISO C but lets ignore that.} that creates
+the architecture:
+@smallexample
+static struct gdbarch *
+d10v_gdbarch_init (info, arches)
+ struct gdbarch_info info;
+ struct gdbarch_list *arches;
+@{
+ struct gdbarch *gdbarch;
+ /* there is only one d10v architecture */
+ if (arches != NULL)
+ return arches->gdbarch;
+ gdbarch = gdbarch_alloc (&info, NULL);
+ return gdbarch;
+@}
+@end smallexample
+@noindent
+@emph{}
+
+@item
+A per-architecture dump function to print any architecture specific
+information:
+@smallexample
+static void
+mips_dump_tdep (struct gdbarch *current_gdbarch,
+ struct ui_file *file)
+@{
+ @dots{} code to print architecture specific info @dots{}
+@}
+@end smallexample
+
+@item
+A change to @code{_initialize_@var{arch}_tdep} to register this new
+architecture:
+@smallexample
+void
+_initialize_mips_tdep (void)
+@{
+ gdbarch_register (bfd_arch_mips, mips_gdbarch_init,
+ mips_dump_tdep);
+@end smallexample
+
+@item
+Add the macro @code{GDB_MULTI_ARCH}, defined as 0 (zero), to the file@*
+@file{config/@var{arch}/tm-@var{arch}.h}.
+
+@end itemize
+
+@subsection Update multi-arch incompatible mechanisms
+
+Some mechanisms do not work with multi-arch. They include:
+
+@table @code
+@item FRAME_FIND_SAVED_REGS
+Replaced with @code{DEPRECATED_FRAME_INIT_SAVED_REGS}
+@end table
+
+@noindent
+At this stage you could also consider converting the macros into
+functions.
+
+@subsection Prepare for multi-arch level to one
+
+Temporally set @code{GDB_MULTI_ARCH} to @code{GDB_MULTI_ARCH_PARTIAL}
+and then build and start @value{GDBN} (the change should not be
+committed). @value{GDBN} may not build, and once built, it may die with
+an internal error listing the architecture methods that must be
+provided.
+
+Fix any build problems (patch(es)).
+
+Convert all the architecture methods listed, which are only macros, into
+functions (patch(es)).
+
+Update @code{@var{arch}_gdbarch_init} to set all the missing
+architecture methods and wrap the corresponding macros in @code{#if
+!GDB_MULTI_ARCH} (patch(es)).
+
+@subsection Set multi-arch level one
+
+Change the value of @code{GDB_MULTI_ARCH} to GDB_MULTI_ARCH_PARTIAL (a
+single patch).
+
+Any problems with throwing ``the switch'' should have been fixed
+already.
+
+@subsection Convert remaining macros
+
+Suggest converting macros into functions (and setting the corresponding
+architecture method) in small batches.
+
+@subsection Set multi-arch level to two
+
+This should go smoothly.
+
+@subsection Delete the TM file
+
+The @file{tm-@var{arch}.h} can be deleted. @file{@var{arch}.mt} and
+@file{configure.in} updated.
+
+
+@node Target Vector Definition
+
+@chapter Target Vector Definition
+@cindex target vector
+
+The target vector defines the interface between @value{GDBN}'s
+abstract handling of target systems, and the nitty-gritty code that
+actually exercises control over a process or a serial port.
+@value{GDBN} includes some 30-40 different target vectors; however,
+each configuration of @value{GDBN} includes only a few of them.
+
+@section File Targets
+
+Both executables and core files have target vectors.
+
+@section Standard Protocol and Remote Stubs
+
+@value{GDBN}'s file @file{remote.c} talks a serial protocol to code
+that runs in the target system. @value{GDBN} provides several sample
+@dfn{stubs} that can be integrated into target programs or operating
+systems for this purpose; they are named @file{*-stub.c}.
+
+The @value{GDBN} 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
+@code{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
+set up 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 @value{GDBN}.
+
+@section ROM Monitor Interface
+
+@section Custom Protocols
+
+@section Transport Layer
+
+@section Builtin Simulator
+
+
+@node Native Debugging
+
+@chapter Native Debugging
+@cindex native debugging
+
+Several files control @value{GDBN}'s configuration for native support:
+
+@table @file
+@vindex NATDEPFILES
+@item gdb/config/@var{arch}/@var{xyz}.mh
+Specifies Makefile fragments needed by a @emph{native} configuration on
+machine @var{xyz}. 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{xyz}, by defining @samp{NAT_FILE= nm-@var{xyz}.h}. You can also
+define @samp{NAT_CFLAGS}, @samp{NAT_ADD_FILES}, @samp{NAT_CLIBS},
+@samp{NAT_CDEPS}, etc.; see @file{Makefile.in}.
+
+@emph{Maintainer's note: The @file{.mh} suffix is because this file
+originally contained @file{Makefile} fragments for hosting @value{GDBN}
+on machine @var{xyz}. While the file is no longer used for this
+purpose, the @file{.mh} suffix remains. Perhaps someone will
+eventually rename these fragments so that they have a @file{.mn}
+suffix.}
+
+@item gdb/config/@var{arch}/nm-@var{xyz}.h
+(@file{nm.h} is a link to this file, created by @code{configure}). Contains C
+macro definitions describing the native system environment, such as
+child process control and core file support.
+
+@item gdb/@var{xyz}-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
+
+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{xyz}.h} file. If these routines work for
+the @var{xyz} 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 @file{@var{xyz}-nat.c}, and put @file{@var{xyz}-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.
+@end table
+
+@section Native core file Support
+@cindex native core files
+
+@table @file
+@findex fetch_core_registers
+@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{xyz}-nat.c} (or
+@code{REGISTER_U_ADDR} in @code{nm-@var{xyz}.h}).
+
+@item core-aout.c::register_addr()
+If your @code{nm-@var{xyz}.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 @value{GDBN}
+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{xyz}-nat.c} file, and be sure @code{@var{xyz}-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 @value{GDBN} 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 @code{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 @value{GDBN}, 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{xyz}-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 @value{GDBN}'s ``registers'' array.
+
+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.
+
+@section ptrace
+
+@section /proc
+
+@section win32
+
+@section shared libraries
+
+@section Native Conditionals
+@cindex native conditionals
+
+When @value{GDBN} 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
+@findex ATTACH_DETACH
+If defined, then @value{GDBN} will include support for the @code{attach} and
+@code{detach} commands.
+
+@item CHILD_PREPARE_TO_STORE
+@findex 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
+@findex 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 FILES_INFO_HOOK
+@findex FILES_INFO_HOOK
+(Only defined for Convex.)
+
+@item FP0_REGNUM
+@findex FP0_REGNUM
+This macro is normally defined to be the number of the first floating
+point register, if the machine has such registers. As such, it would
+appear only in target-specific code. However, @file{/proc} support uses this
+to decide whether floats are in use on this target.
+
+@item GET_LONGJMP_TARGET
+@findex 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
+@file{setjmp.h} is needed to define it.
+
+This macro determines the target PC address that @code{longjmp} will jump to,
+assuming that we have just stopped at a longjmp breakpoint. It takes a
+@code{CORE_ADDR *} as argument, and stores the target PC value through this
+pointer. It examines the current state of the machine as needed.
+
+@item I386_USE_GENERIC_WATCHPOINTS
+An x86-based machine can define this to use the generic x86 watchpoint
+support; see @ref{Algorithms, I386_USE_GENERIC_WATCHPOINTS}.
+
+@item KERNEL_U_ADDR
+@findex 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. @value{GDBN}
+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
+@findex KERNEL_U_ADDR_BSD
+Define this to cause @value{GDBN} 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
+@findex KERNEL_U_ADDR_HPUX
+Define this to cause @value{GDBN} 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 ONE_PROCESS_WRITETEXT
+@findex ONE_PROCESS_WRITETEXT
+Define this to be able to, when a breakpoint insertion fails, warn the
+user that another process may be running with the same executable.
+
+@item PROC_NAME_FMT
+@findex 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
+@findex PTRACE_FP_BUG
+See @file{mach386-xdep.c}.
+
+@item PTRACE_ARG3_TYPE
+@findex 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
+@findex REGISTER_U_ADDR
+Defines the offset of the registers in the ``u area''.
+
+@item SHELL_COMMAND_CONCAT
+@findex SHELL_COMMAND_CONCAT
+If defined, is a string to prefix on the shell command used to start the
+inferior.
+
+@item SHELL_FILE
+@findex SHELL_FILE
+If defined, this is the name of the shell to use to run the inferior.
+Defaults to @code{"/bin/sh"}.
+
+@item SOLIB_ADD (@var{filename}, @var{from_tty}, @var{targ}, @var{readsyms})
+@findex SOLIB_ADD
+Define this to expand into an expression that will cause the symbols in
+@var{filename} to be added to @value{GDBN}'s symbol table. If
+@var{readsyms} is zero symbols are not read but any necessary low level
+processing for @var{filename} is still done.
+
+@item SOLIB_CREATE_INFERIOR_HOOK
+@findex 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
+@findex START_INFERIOR_TRAPS_EXPECTED
+When starting an inferior, @value{GDBN} 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 SVR4_SHARED_LIBS
+@findex SVR4_SHARED_LIBS
+Define this to indicate that SVR4-style shared libraries are in use.
+
+@item USE_PROC_FS
+@findex USE_PROC_FS
+This determines whether small routines in @file{*-tdep.c}, which
+translate register values between @value{GDBN}'s internal
+representation and the @file{/proc} representation, are compiled.
+
+@item U_REGS_OFFSET
+@findex 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 @code{u.u_ar0} @emph{is} the location of the registers.
+
+@item CLEAR_SOLIB
+@findex CLEAR_SOLIB
+See @file{objfiles.c}.
+
+@item DEBUG_PTRACE
+@findex DEBUG_PTRACE
+Define this to debug @code{ptrace} calls.
+@end table
+
+
+@node Support Libraries
+
+@chapter Support Libraries
+
+@section BFD
+@cindex BFD library
+
+BFD provides support for @value{GDBN} 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). @value{GDBN} simply
+calls BFD to read or write section @var{x} at byte offset @var{y} for
+length @var{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
+@value{GDBN} uses an internal interface of BFD to determine where to find the
+symbol information in an executable file or symbol-file. @value{GDBN} itself
+handles the reading of symbols, since BFD does not ``understand'' debug
+symbols, but @value{GDBN} uses BFD's cached information to find the symbols,
+string table, etc.
+@end table
+
+@section opcodes
+@cindex opcodes library
+
+The opcodes library provides @value{GDBN}'s disassembler. (It's a separate
+library because it's also used in binutils, for @file{objdump}).
+
+@section readline
+
+@section mmalloc
+
+@section libiberty
+@cindex @code{libiberty} library
+
+The @code{libiberty} library provides a set of functions and features
+that integrate and improve on functionality found in modern operating
+systems. Broadly speaking, such features can be divided into three
+groups: supplemental functions (functions that may be missing in some
+environments and operating systems), replacement functions (providing
+a uniform and easier to use interface for commonly used standard
+functions), and extensions (which provide additional functionality
+beyond standard functions).
+
+@value{GDBN} uses various features provided by the @code{libiberty}
+library, for instance the C@t{++} demangler, the @acronym{IEEE}
+floating format support functions, the input options parser
+@samp{getopt}, the @samp{obstack} extension, and other functions.
+
+@subsection @code{obstacks} in @value{GDBN}
+@cindex @code{obstacks}
+
+The obstack mechanism provides a convenient way to allocate and free
+chunks of memory. Each obstack is a pool of memory that is managed
+like a stack. Objects (of any nature, size and alignment) are
+allocated and freed in a @acronym{LIFO} fashion on an obstack (see
+@code{libiberty}'s documenatation for a more detailed explanation of
+@code{obstacks}).
+
+The most noticeable use of the @code{obstacks} in @value{GDBN} is in
+object files. There is an obstack associated with each internal
+representation of an object file. Lots of things get allocated on
+these @code{obstacks}: dictionary entries, blocks, blockvectors,
+symbols, minimal symbols, types, vectors of fundamental types, class
+fields of types, object files section lists, object files section
+offets lists, line tables, symbol tables, partial symbol tables,
+string tables, symbol table private data, macros tables, debug
+information sections and entries, import and export lists (som),
+unwind information (hppa), dwarf2 location expressions data. Plus
+various strings such as directory names strings, debug format strings,
+names of types.
+
+An essential and convenient property of all data on @code{obstacks} is
+that memory for it gets allocated (with @code{obstack_alloc}) at
+various times during a debugging sesssion, but it is released all at
+once using the @code{obstack_free} function. The @code{obstack_free}
+function takes a pointer to where in the stack it must start the
+deletion from (much like the cleanup chains have a pointer to where to
+start the cleanups). Because of the stack like structure of the
+@code{obstacks}, this allows to free only a top portion of the
+obstack. There are a few instances in @value{GDBN} where such thing
+happens. Calls to @code{obstack_free} are done after some local data
+is allocated to the obstack. Only the local data is deleted from the
+obstack. Of course this assumes that nothing between the
+@code{obstack_alloc} and the @code{obstack_free} allocates anything
+else on the same obstack. For this reason it is best and safest to
+use temporary @code{obstacks}.
+
+Releasing the whole obstack is also not safe per se. It is safe only
+under the condition that we know the @code{obstacks} memory is no
+longer needed. In @value{GDBN} we get rid of the @code{obstacks} only
+when we get rid of the whole objfile(s), for instance upon reading a
+new symbol file.
+
+@section gnu-regex
+@cindex regular expressions library
+
+Regex conditionals.
+
+@table @code
+@item C_ALLOCA
+
+@item NFAILURES
+
+@item RE_NREGS
+
+@item SIGN_EXTEND_CHAR
+
+@item SWITCH_ENUM_BUG
+
+@item SYNTAX_TABLE
+
+@item Sword
+
+@item sparc
+@end table
+
+@section include
+
+@node Coding
+
+@chapter Coding
+
+This chapter covers topics that are lower-level than the major
+algorithms of @value{GDBN}.
+
+@section Cleanups
+@cindex cleanups
+
+Cleanups are a structured way to deal with things that need to be done
+later.
+
+When your code does something (e.g., @code{xmalloc} some memory, or
+@code{open} a file) that needs to be undone later (e.g., @code{xfree}
+the memory or @code{close} the file), it can make a cleanup. The
+cleanup will be done at some future point: when the command is finished
+and control returns to the top level; when an error occurs and the stack
+is unwound; or when your code decides it's time to explicitly perform
+cleanups. Alternatively you can elect to discard the cleanups you
+created.
+
+Syntax:
+
+@table @code
+@item struct cleanup *@var{old_chain};
+Declare a variable which will hold a cleanup chain handle.
+
+@findex make_cleanup
+@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 later be passed to @code{do_cleanups} or
+@code{discard_cleanups}. Unless you are going to call
+@code{do_cleanups} or @code{discard_cleanups}, you can ignore the result
+from @code{make_cleanup}.
+
+@findex do_cleanups
+@item do_cleanups (@var{old_chain});
+Do all cleanups added to the chain since the corresponding
+@code{make_cleanup} call was made.
+
+@findex discard_cleanups
+@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
+
+Cleanups are implemented as a chain. The handle returned by
+@code{make_cleanups} includes the cleanup passed to the call and any
+later cleanups appended to the chain (but not yet discarded or
+performed). E.g.:
+
+@smallexample
+make_cleanup (a, 0);
+@{
+ struct cleanup *old = make_cleanup (b, 0);
+ make_cleanup (c, 0)
+ ...
+ do_cleanups (old);
+@}
+@end smallexample
+
+@noindent
+will call @code{c()} and @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
+
+Your function should explicitly do or discard the cleanups it creates.
+Failing to do this leads to non-deterministic behavior since the caller
+will arbitrarily do or discard your functions cleanups. This need leads
+to two common cleanup styles.
+
+The first style is try/finally. Before it exits, your code-block calls
+@code{do_cleanups} with the old cleanup chain and thus ensures that your
+code-block's cleanups are always performed. For instance, the following
+code-segment avoids a memory leak problem (even when @code{error} is
+called and a forced stack unwind occurs) by ensuring that the
+@code{xfree} will always be called:
+
+@smallexample
+struct cleanup *old = make_cleanup (null_cleanup, 0);
+data = xmalloc (sizeof blah);
+make_cleanup (xfree, data);
+... blah blah ...
+do_cleanups (old);
+@end smallexample
+
+The second style is try/except. Before it exits, your code-block calls
+@code{discard_cleanups} with the old cleanup chain and thus ensures that
+any created cleanups are not performed. For instance, the following
+code segment, ensures that the file will be closed but only if there is
+an error:
+
+@smallexample
+FILE *file = fopen ("afile", "r");
+struct cleanup *old = make_cleanup (close_file, file);
+... blah blah ...
+discard_cleanups (old);
+return file;
+@end smallexample
+
+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).
+
+@section Per-architecture module data
+@cindex per-architecture module data
+@cindex multi-arch data
+@cindex data-pointer, per-architecture/per-module
+
+The multi-arch framework includes a mechanism for adding module specific
+per-architecture data-pointers to the @code{struct gdbarch} architecture
+object.
+
+A module registers one or more per-architecture data-pointers using the
+function @code{register_gdbarch_data}:
+
+@deftypefun struct gdbarch_data *register_gdbarch_data (gdbarch_data_init_ftype *@var{init})
+
+The @var{init} function is used to obtain an initial value for a
+per-architecture data-pointer. The function is called, after the
+architecture has been created, when the data-pointer is still
+uninitialized (@code{NULL}) and its value has been requested via a call
+to @code{gdbarch_data}. A data-pointer can also be initialize
+explicitly using @code{set_gdbarch_data}.
+
+Any memory required by the @var{init} function should be allocated
+using @code{GDBARCH_OBSTACK_ZALLOC}. That memory is automatically
+released when the corresponding architecture is deleted.
+
+The function @code{register_gdbarch_data} returns a @code{struct
+gdbarch_data} that is used to identify the data-pointer that was added
+to the module.
+
+@end deftypefun
+
+A typical module has an @code{init} function of the form:
+
+@smallexample
+struct nozel @{ int total; @};
+static struct gdbarch_data *nozel_handle;
+static void *
+nozel_init (struct gdbarch *gdbarch)
+@{
+ struct nozel *data = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct nozel);
+ @dots{}
+ return data;
+@}
+@end smallexample
+
+Since uninitialized (@code{NULL}) data-pointers are initialized
+on-demand, an @code{init} function is free to call other modules that
+use data-pointers. Those modules data-pointers will be initialized as
+needed. Care should be taken to ensure that the @code{init} call graph
+does not contain cycles.
+
+The data-pointer is registered with the call:
+
+@smallexample
+void
+_initialize_nozel (void)
+@{
+ nozel_handle = register_gdbarch_data (nozel_init);
+@dots{}
+@end smallexample
+
+The per-architecture data-pointer is accessed using the function:
+
+@deftypefun void *gdbarch_data (struct gdbarch *@var{gdbarch}, struct gdbarch_data *@var{data_handle})
+Given the architecture @var{arch} and module data handle
+@var{data_handle} (returned by @code{register_gdbarch_data}, this
+function returns the current value of the per-architecture data-pointer.
+@end deftypefun
+
+The non-@code{NULL} data-pointer returned by @code{gdbarch_data} should
+be saved in a local variable and then used directly:
+
+@smallexample
+int
+nozel_total (struct gdbarch *gdbarch)
+@{
+ int total;
+ struct nozel *data = gdbarch_data (gdbarch, nozel_handle);
+ @dots{}
+ return total;
+@}
+@end smallexample
+
+It is also possible to directly initialize the data-pointer using:
+
+@deftypefun void set_gdbarch_data (struct gdbarch *@var{gdbarch}, struct gdbarch_data *@var{handle}, void *@var{pointer})
+Set the still @code{NULL} data-pointer corresponding to @var{handle}
+to the non-@code{NULL} @var{pointer} value.
+@end deftypefun
+
+This function is used by modules that require a mechanism for explicitly
+setting the per-architecture data-pointer during architecture creation:
+
+@smallexample
+/* Always return a non-NULL nozel. */
+static struct nozel *
+gdbarch_nozel (struct gdbarch *gdbarch)
+@{
+ struct nozel *nozel = gdbarch_data (gdbarch, nozel_handle);
+ if (nozel == NULL)
+ @{
+ nozel = nozel_init (gdbarch);
+ set_gdbarch_data (gdbarch, nozel_handle, nozel);
+ @}
+ return nozel;
+@}
+@end smallexample
+
+@smallexample
+/* Called during architecture creation. */
+extern void
+set_gdbarch_nozel (struct gdbarch *gdbarch, int total)
+@{
+ struct nozel *data = gdbarch_nozel (gdbarch);
+ @dots{}
+ data->total = total;
+@}
+@end smallexample
+
+@smallexample
+void
+_initialize_nozel (void)
+@{
+ nozel_handle = register_gdbarch_data (nozel_init);
+ @dots{}
+@end smallexample
+
+@noindent
+Note that an @code{init} function still needs to be registered. It is
+used to initialize the data-pointer when the architecture creation phase
+fail to set an initial value.
+
+
+@section Wrapping Output Lines
+@cindex line wrap in output
+
+@findex wrap_here
+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.
+
+@section @value{GDBN} Coding Standards
+@cindex coding standards
+
+@value{GDBN} follows the GNU coding standards, as described in
+@file{etc/standards.texi}. This file is also available for anonymous
+FTP from GNU archive sites. @value{GDBN} takes a strict interpretation
+of the standard; in general, when the GNU standard recommends a practice
+but does not require it, @value{GDBN} requires it.
+
+@value{GDBN} follows an additional set of coding standards specific to
+@value{GDBN}, as described in the following sections.
+
+
+@subsection ISO C
+
+@value{GDBN} assumes an ISO/IEC 9899:1990 (a.k.a.@: ISO C90) compliant
+compiler.
+
+@value{GDBN} does not assume an ISO C or POSIX compliant C library.
+
+
+@subsection Memory Management
+
+@value{GDBN} does not use the functions @code{malloc}, @code{realloc},
+@code{calloc}, @code{free} and @code{asprintf}.
+
+@value{GDBN} uses the functions @code{xmalloc}, @code{xrealloc} and
+@code{xcalloc} when allocating memory. Unlike @code{malloc} et.al.@:
+these functions do not return when the memory pool is empty. Instead,
+they unwind the stack using cleanups. These functions return
+@code{NULL} when requested to allocate a chunk of memory of size zero.
+
+@emph{Pragmatics: By using these functions, the need to check every
+memory allocation is removed. These functions provide portable
+behavior.}
+
+@value{GDBN} does not use the function @code{free}.
+
+@value{GDBN} uses the function @code{xfree} to return memory to the
+memory pool. Consistent with ISO-C, this function ignores a request to
+free a @code{NULL} pointer.
+
+@emph{Pragmatics: On some systems @code{free} fails when passed a
+@code{NULL} pointer.}
+
+@value{GDBN} can use the non-portable function @code{alloca} for the
+allocation of small temporary values (such as strings).
+
+@emph{Pragmatics: This function is very non-portable. Some systems
+restrict the memory being allocated to no more than a few kilobytes.}
+
+@value{GDBN} uses the string function @code{xstrdup} and the print
+function @code{xasprintf}.
+
+@emph{Pragmatics: @code{asprintf} and @code{strdup} can fail. Print
+functions such as @code{sprintf} are very prone to buffer overflow
+errors.}
+
+
+@subsection Compiler Warnings
+@cindex compiler warnings
+
+With few exceptions, developers should include the configuration option
+@samp{--enable-gdb-build-warnings=,-Werror} when building @value{GDBN}.
+The exceptions are listed in the file @file{gdb/MAINTAINERS}.
+
+This option causes @value{GDBN} (when built using GCC) to be compiled
+with a carefully selected list of compiler warning flags. Any warnings
+from those flags being treated as errors.
+
+The current list of warning flags includes:
+
+@table @samp
+@item -Wimplicit
+Since @value{GDBN} coding standard requires all functions to be declared
+using a prototype, the flag has the side effect of ensuring that
+prototyped functions are always visible with out resorting to
+@samp{-Wstrict-prototypes}.
+
+@item -Wreturn-type
+Such code often appears to work except on instruction set architectures
+that use register windows.
+
+@item -Wcomment
+
+@item -Wtrigraphs
+
+@item -Wformat
+@itemx -Wformat-nonliteral
+Since @value{GDBN} uses the @code{format printf} attribute on all
+@code{printf} like functions these check not just @code{printf} calls
+but also calls to functions such as @code{fprintf_unfiltered}.
+
+@item -Wparentheses
+This warning includes uses of the assignment operator within an
+@code{if} statement.
+
+@item -Wpointer-arith
+
+@item -Wuninitialized
+
+@item -Wunused-label
+This warning has the additional benefit of detecting the absence of the
+@code{case} reserved word in a switch statement:
+@smallexample
+enum @{ FD_SCHEDULED, NOTHING_SCHEDULED @} sched;
+@dots{}
+switch (sched)
+ @{
+ case FD_SCHEDULED:
+ @dots{};
+ break;
+ NOTHING_SCHEDULED:
+ @dots{};
+ break;
+ @}
+@end smallexample
+
+@item -Wunused-function
+@end table
+
+@emph{Pragmatics: Due to the way that @value{GDBN} is implemented most
+functions have unused parameters. Consequently the warning
+@samp{-Wunused-parameter} is precluded from the list. The macro
+@code{ATTRIBUTE_UNUSED} is not used as it leads to false negatives ---
+it is not an error to have @code{ATTRIBUTE_UNUSED} on a parameter that
+is being used. The options @samp{-Wall} and @samp{-Wunused} are also
+precluded because they both include @samp{-Wunused-parameter}.}
+
+@emph{Pragmatics: @value{GDBN} has not simply accepted the warnings
+enabled by @samp{-Wall -Werror -W...}. Instead it is selecting warnings
+when and where their benefits can be demonstrated.}
+
+@subsection Formatting
+
+@cindex source code formatting
+The standard GNU recommendations for formatting must be followed
+strictly.
+
+A function declaration should not have its name in column zero. A
+function definition should have its name in column zero.
+
+@smallexample
+/* Declaration */
+static void foo (void);
+/* Definition */
+void
+foo (void)
+@{
+@}
+@end smallexample
+
+@emph{Pragmatics: This simplifies scripting. Function definitions can
+be found using @samp{^function-name}.}
+
+There must be a space between a function or macro name and the opening
+parenthesis of its argument list (except for macro definitions, as
+required by C). There must not be a space after an open paren/bracket
+or before a close paren/bracket.
+
+While additional whitespace is generally helpful for reading, do not use
+more than one blank line to separate blocks, and avoid adding whitespace
+after the end of a program line (as of 1/99, some 600 lines had
+whitespace after the semicolon). Excess whitespace causes difficulties
+for @code{diff} and @code{patch} utilities.
+
+Pointers are declared using the traditional K&R C style:
+
+@smallexample
+void *foo;
+@end smallexample
+
+@noindent
+and not:
+
+@smallexample
+void * foo;
+void* foo;
+@end smallexample
+
+@subsection Comments
+
+@cindex comment formatting
+The standard GNU requirements on comments must be followed strictly.
+
+Block comments must appear in the following form, with no @code{/*}- or
+@code{*/}-only lines, and no leading @code{*}:
+
+@smallexample
+/* 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 @value{GDBN} should read more commands. */
+@end smallexample
+
+(Note that this format is encouraged by Emacs; tabbing for a multi-line
+comment works correctly, and @kbd{M-q} fills the block consistently.)
+
+Put a blank line between the block comments preceding function or
+variable definitions, and the definition itself.
+
+In general, put function-body comments on lines by themselves, rather
+than trying to fit them into the 20 characters left at the end of a
+line, since either the comment or the code will inevitably get longer
+than will fit, and then somebody will have to move it anyhow.
+
+@subsection C Usage
+
+@cindex C data types
+Code must not 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.
+
+@cindex function usage
+Use functions freely. There are only a handful of compute-bound areas
+in @value{GDBN} that might be affected by the overhead of a function
+call, mainly in symbol reading. Most of @value{GDBN}'s performance is
+limited by the target interface (whether serial line or system call).
+
+However, use functions with moderation. A thousand one-line functions
+are just as hard to understand as a single thousand-line function.
+
+@emph{Macros are bad, M'kay.}
+(But if you have to use a macro, make sure that the macro arguments are
+protected with parentheses.)
+
+@cindex types
+
+Declarations like @samp{struct foo *} should be used in preference to
+declarations like @samp{typedef struct foo @{ @dots{} @} *foo_ptr}.
+
+
+@subsection Function Prototypes
+@cindex function prototypes
+
+Prototypes must be used when both @emph{declaring} and @emph{defining}
+a function. Prototypes for @value{GDBN} functions must include both the
+argument type and name, with the name matching that used in the actual
+function definition.
+
+All external functions should have a declaration in a header file that
+callers include, except for @code{_initialize_*} functions, which must
+be external so that @file{init.c} construction works, but shouldn't be
+visible to random source files.
+
+Where a source file needs a forward declaration of a static function,
+that declaration must appear in a block near the top of the source file.
+
+
+@subsection Internal Error Recovery
+
+During its execution, @value{GDBN} can encounter two types of errors.
+User errors and internal errors. User errors include not only a user
+entering an incorrect command but also problems arising from corrupt
+object files and system errors when interacting with the target.
+Internal errors include situations where @value{GDBN} has detected, at
+run time, a corrupt or erroneous situation.
+
+When reporting an internal error, @value{GDBN} uses
+@code{internal_error} and @code{gdb_assert}.
+
+@value{GDBN} must not call @code{abort} or @code{assert}.
+
+@emph{Pragmatics: There is no @code{internal_warning} function. Either
+the code detected a user error, recovered from it and issued a
+@code{warning} or the code failed to correctly recover from the user
+error and issued an @code{internal_error}.}
+
+@subsection File Names
+
+Any file used when building the core of @value{GDBN} must be in lower
+case. Any file used when building the core of @value{GDBN} must be 8.3
+unique. These requirements apply to both source and generated files.
+
+@emph{Pragmatics: The core of @value{GDBN} must be buildable on many
+platforms including DJGPP and MacOS/HFS. Every time an unfriendly file
+is introduced to the build process both @file{Makefile.in} and
+@file{configure.in} need to be modified accordingly. Compare the
+convoluted conversion process needed to transform @file{COPYING} into
+@file{copying.c} with the conversion needed to transform
+@file{version.in} into @file{version.c}.}
+
+Any file non 8.3 compliant file (that is not used when building the core
+of @value{GDBN}) must be added to @file{gdb/config/djgpp/fnchange.lst}.
+
+@emph{Pragmatics: This is clearly a compromise.}
+
+When @value{GDBN} has a local version of a system header file (ex
+@file{string.h}) the file name based on the POSIX header prefixed with
+@file{gdb_} (@file{gdb_string.h}). These headers should be relatively
+independent: they should use only macros defined by @file{configure},
+the compiler, or the host; they should include only system headers; they
+should refer only to system types. They may be shared between multiple
+programs, e.g.@: @value{GDBN} and @sc{gdbserver}.
+
+For other files @samp{-} is used as the separator.
+
+
+@subsection Include Files
+
+A @file{.c} file should include @file{defs.h} first.
+
+A @file{.c} file should directly include the @code{.h} file of every
+declaration and/or definition it directly refers to. It cannot rely on
+indirect inclusion.
+
+A @file{.h} file should directly include the @code{.h} file of every
+declaration and/or definition it directly refers to. It cannot rely on
+indirect inclusion. Exception: The file @file{defs.h} does not need to
+be directly included.
+
+An external declaration should only appear in one include file.
+
+An external declaration should never appear in a @code{.c} file.
+Exception: a declaration for the @code{_initialize} function that
+pacifies @option{-Wmissing-declaration}.
+
+A @code{typedef} definition should only appear in one include file.
+
+An opaque @code{struct} declaration can appear in multiple @file{.h}
+files. Where possible, a @file{.h} file should use an opaque
+@code{struct} declaration instead of an include.
+
+All @file{.h} files should be wrapped in:
+
+@smallexample
+#ifndef INCLUDE_FILE_NAME_H
+#define INCLUDE_FILE_NAME_H
+header body
+#endif
+@end smallexample
+
+
+@subsection Clean Design and Portable Implementation
+
+@cindex design
+In addition to getting the syntax right, there's the little question of
+semantics. Some things are done in certain ways in @value{GDBN} because long
+experience has shown that the more obvious ways caused various kinds of
+trouble.
+
+@cindex assumptions about targets
+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
+@value{GDBN}, or one of the swap routines defined in @file{bfd.h},
+such as @code{bfd_get_32}.
+
+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.
+
+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.
+
+@cindex portability
+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.
+
+@cindex system dependencies
+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.
+
+Adding code that handles specific architectures, operating systems,
+target interfaces, or hosts, is not acceptable in generic code.
+
+@cindex portable file name handling
+@cindex file names, portability
+One particularly notorious area where system dependencies tend to
+creep in is handling of file names. The mainline @value{GDBN} code
+assumes Posix semantics of file names: absolute file names begin with
+a forward slash @file{/}, slashes are used to separate leading
+directories, case-sensitive file names. These assumptions are not
+necessarily true on non-Posix systems such as MS-Windows. To avoid
+system-dependent code where you need to take apart or construct a file
+name, use the following portable macros:
+
+@table @code
+@findex HAVE_DOS_BASED_FILE_SYSTEM
+@item HAVE_DOS_BASED_FILE_SYSTEM
+This preprocessing symbol is defined to a non-zero value on hosts
+whose filesystems belong to the MS-DOS/MS-Windows family. Use this
+symbol to write conditional code which should only be compiled for
+such hosts.
+
+@findex IS_DIR_SEPARATOR
+@item IS_DIR_SEPARATOR (@var{c})
+Evaluates to a non-zero value if @var{c} is a directory separator
+character. On Unix and GNU/Linux systems, only a slash @file{/} is
+such a character, but on Windows, both @file{/} and @file{\} will
+pass.
+
+@findex IS_ABSOLUTE_PATH
+@item IS_ABSOLUTE_PATH (@var{file})
+Evaluates to a non-zero value if @var{file} is an absolute file name.
+For Unix and GNU/Linux hosts, a name which begins with a slash
+@file{/} is absolute. On DOS and Windows, @file{d:/foo} and
+@file{x:\bar} are also absolute file names.
+
+@findex FILENAME_CMP
+@item FILENAME_CMP (@var{f1}, @var{f2})
+Calls a function which compares file names @var{f1} and @var{f2} as
+appropriate for the underlying host filesystem. For Posix systems,
+this simply calls @code{strcmp}; on case-insensitive filesystems it
+will call @code{strcasecmp} instead.
+
+@findex DIRNAME_SEPARATOR
+@item DIRNAME_SEPARATOR
+Evaluates to a character which separates directories in
+@code{PATH}-style lists, typically held in environment variables.
+This character is @samp{:} on Unix, @samp{;} on DOS and Windows.
+
+@findex SLASH_STRING
+@item SLASH_STRING
+This evaluates to a constant string you should use to produce an
+absolute filename from leading directories and the file's basename.
+@code{SLASH_STRING} is @code{"/"} on most systems, but might be
+@code{"\\"} for some Windows-based ports.
+@end table
+
+In addition to using these macros, be sure to use portable library
+functions whenever possible. For example, to extract a directory or a
+basename part from a file name, use the @code{dirname} and
+@code{basename} library functions (available in @code{libiberty} for
+platforms which don't provide them), instead of searching for a slash
+with @code{strrchr}.
+
+Another way to generalize @value{GDBN} along a particular interface is with an
+attribute struct. For example, @value{GDBN} has been generalized to handle
+multiple kinds of remote interfaces---not by @code{#ifdef}s everywhere, but
+by defining the @code{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.,
+@code{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 @value{GDBN}'s access to multiple source languages.
+
+Please avoid duplicating code. For example, in @value{GDBN} 3.x all
+the code interfacing between @code{ptrace} and the rest of
+@value{GDBN} was duplicated in @file{*-dep.c}, and so changing
+something was very painful. In @value{GDBN} 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, @code{#if defined}, etc.), and machines which are
+radically different don't need to use @file{infptrace.c} at all.
+
+All debugging code must be controllable using the @samp{set debug
+@var{module}} command. Do not use @code{printf} to print trace
+messages. Use @code{fprintf_unfiltered(gdb_stdlog, ...}. Do not use
+@code{#ifdef DEBUG}.
+
+
+@node Porting GDB
+
+@chapter Porting @value{GDBN}
+@cindex porting to new machines
+
+Most of the work in making @value{GDBN} 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{xyz} (e.g., @samp{sun4}), and its full three-part configuration
+name is @code{@var{arch}-@var{xvend}-@var{xos}} (e.g.,
+@samp{sparc-sun-sunos4}). In particular:
+
+@itemize @bullet
+@item
+In the top level directory, edit @file{config.sub} and add @var{arch},
+@var{xvend}, and @var{xos} to the lists of supported architectures,
+vendors, and operating systems near the bottom of the file. Also, add
+@var{xyz} as an alias that maps to
+@code{@var{arch}-@var{xvend}-@var{xos}}. You can test your changes by
+running
+
+@smallexample
+./config.sub @var{xyz}
+@end smallexample
+
+@noindent
+and
+
+@smallexample
+./config.sub @code{@var{arch}-@var{xvend}-@var{xos}}
+@end smallexample
+
+@noindent
+which should both respond with @code{@var{arch}-@var{xvend}-@var{xos}}
+and no error messages.
+
+@noindent
+You need to port BFD, if that hasn't been done already. Porting BFD is
+beyond the scope of this manual.
+
+@item
+To configure @value{GDBN} itself, edit @file{gdb/configure.host} to recognize
+your system and set @code{gdb_host} to @var{xyz}, and (unless your
+desired target is already available) also edit @file{gdb/configure.tgt},
+setting @code{gdb_target} to something appropriate (for instance,
+@var{xyz}).
+
+@emph{Maintainer's note: Work in progress. The file
+@file{gdb/configure.host} originally needed to be modified when either a
+new native target or a new host machine was being added to @value{GDBN}.
+Recent changes have removed this requirement. The file now only needs
+to be modified when adding a new native configuration. This will likely
+changed again in the future.}
+
+@item
+Finally, you'll need to specify and define @value{GDBN}'s host-, native-, and
+target-dependent @file{.h} and @file{.c} files used for your
+configuration.
+@end itemize
+
+@node Releasing GDB
+
+@chapter Releasing @value{GDBN}
+@cindex making a new release of gdb
+
+@section Versions and Branches
+
+@subsection Version Identifiers
+
+@value{GDBN}'s version is determined by the file @file{gdb/version.in}.
+
+@value{GDBN}'s mainline uses ISO dates to differentiate between
+versions. The CVS repository uses @var{YYYY}-@var{MM}-@var{DD}-cvs
+while the corresponding snapshot uses @var{YYYYMMDD}.
+
+@value{GDBN}'s release branch uses a slightly more complicated scheme.
+When the branch is first cut, the mainline version identifier is
+prefixed with the @var{major}.@var{minor} from of the previous release
+series but with .90 appended. As draft releases are drawn from the
+branch, the minor minor number (.90) is incremented. Once the first
+release (@var{M}.@var{N}) has been made, the version prefix is updated
+to @var{M}.@var{N}.0.90 (dot zero, dot ninety). Follow on releases have
+an incremented minor minor version number (.0).
+
+Using 5.1 (previous) and 5.2 (current), the example below illustrates a
+typical sequence of version identifiers:
+
+@table @asis
+@item 5.1.1
+final release from previous branch
+@item 2002-03-03-cvs
+main-line the day the branch is cut
+@item 5.1.90-2002-03-03-cvs
+corresponding branch version
+@item 5.1.91
+first draft release candidate
+@item 5.1.91-2002-03-17-cvs
+updated branch version
+@item 5.1.92
+second draft release candidate
+@item 5.1.92-2002-03-31-cvs
+updated branch version
+@item 5.1.93
+final release candidate (see below)
+@item 5.2
+official release
+@item 5.2.0.90-2002-04-07-cvs
+updated CVS branch version
+@item 5.2.1
+second official release
+@end table
+
+Notes:
+
+@itemize @bullet
+@item
+Minor minor minor draft release candidates such as 5.2.0.91 have been
+omitted from the example. Such release candidates are, typically, never
+made.
+@item
+For 5.1.93 the bziped tar ball @file{gdb-5.1.93.tar.bz2} is just the
+official @file{gdb-5.2.tar} renamed and compressed.
+@end itemize
+
+To avoid version conflicts, vendors are expected to modify the file
+@file{gdb/version.in} to include a vendor unique alphabetic identifier
+(an official @value{GDBN} release never uses alphabetic characters in
+its version identifer).
+
+Since @value{GDBN} does not make minor minor minor releases (e.g.,
+5.1.0.1) the conflict between that and a minor minor draft release
+identifier (e.g., 5.1.0.90) is avoided.
+
+
+@subsection Branches
+
+@value{GDBN} draws a release series (5.2, 5.2.1, @dots{}) from a single
+release branch (gdb_5_2-branch). Since minor minor minor releases
+(5.1.0.1) are not made, the need to branch the release branch is avoided
+(it also turns out that the effort required for such a a branch and
+release is significantly greater than the effort needed to create a new
+release from the head of the release branch).
+
+Releases 5.0 and 5.1 used branch and release tags of the form:
+
+@smallexample
+gdb_N_M-YYYY-MM-DD-branchpoint
+gdb_N_M-YYYY-MM-DD-branch
+gdb_M_N-YYYY-MM-DD-release
+@end smallexample
+
+Release 5.2 is trialing the branch and release tags:
+
+@smallexample
+gdb_N_M-YYYY-MM-DD-branchpoint
+gdb_N_M-branch
+gdb_M_N-YYYY-MM-DD-release
+@end smallexample
+
+@emph{Pragmatics: The branchpoint and release tags need to identify when
+a branch and release are made. The branch tag, denoting the head of the
+branch, does not have this criteria.}
+
+
+@section Branch Commit Policy
+
+The branch commit policy is pretty slack. @value{GDBN} releases 5.0,
+5.1 and 5.2 all used the below:
+
+@itemize @bullet
+@item
+The @file{gdb/MAINTAINERS} file still holds.
+@item
+Don't fix something on the branch unless/until it is also fixed in the
+trunk. If this isn't possible, mentioning it in the @file{gdb/PROBLEMS}
+file is better than committing a hack.
+@item
+When considering a patch for the branch, suggested criteria include:
+Does it fix a build? Does it fix the sequence @kbd{break main; run}
+when debugging a static binary?
+@item
+The further a change is from the core of @value{GDBN}, the less likely
+the change will worry anyone (e.g., target specific code).
+@item
+Only post a proposal to change the core of @value{GDBN} after you've
+sent individual bribes to all the people listed in the
+@file{MAINTAINERS} file @t{;-)}
+@end itemize
+
+@emph{Pragmatics: Provided updates are restricted to non-core
+functionality there is little chance that a broken change will be fatal.
+This means that changes such as adding a new architectures or (within
+reason) support for a new host are considered acceptable.}
+
+
+@section Obsoleting code
+
+Before anything else, poke the other developers (and around the source
+code) to see if there is anything that can be removed from @value{GDBN}
+(an old target, an unused file).
+
+Obsolete code is identified by adding an @code{OBSOLETE} prefix to every
+line. Doing this means that it is easy to identify something that has
+been obsoleted when greping through the sources.
+
+The process is done in stages --- this is mainly to ensure that the
+wider @value{GDBN} community has a reasonable opportunity to respond.
+Remember, everything on the Internet takes a week.
+
+@enumerate
+@item
+Post the proposal on @email{gdb@@sources.redhat.com, the GDB mailing
+list} Creating a bug report to track the task's state, is also highly
+recommended.
+@item
+Wait a week or so.
+@item
+Post the proposal on @email{gdb-announce@@sources.redhat.com, the GDB
+Announcement mailing list}.
+@item
+Wait a week or so.
+@item
+Go through and edit all relevant files and lines so that they are
+prefixed with the word @code{OBSOLETE}.
+@item
+Wait until the next GDB version, containing this obsolete code, has been
+released.
+@item
+Remove the obsolete code.
+@end enumerate
+
+@noindent
+@emph{Maintainer note: While removing old code is regrettable it is
+hopefully better for @value{GDBN}'s long term development. Firstly it
+helps the developers by removing code that is either no longer relevant
+or simply wrong. Secondly since it removes any history associated with
+the file (effectively clearing the slate) the developer has a much freer
+hand when it comes to fixing broken files.}
+
+
+
+@section Before the Branch
+
+The most important objective at this stage is to find and fix simple
+changes that become a pain to track once the branch is created. For
+instance, configuration problems that stop @value{GDBN} from even
+building. If you can't get the problem fixed, document it in the
+@file{gdb/PROBLEMS} file.
+
+@subheading Prompt for @file{gdb/NEWS}
+
+People always forget. Send a post reminding them but also if you know
+something interesting happened add it yourself. The @code{schedule}
+script will mention this in its e-mail.
+
+@subheading Review @file{gdb/README}
+
+Grab one of the nightly snapshots and then walk through the
+@file{gdb/README} looking for anything that can be improved. The
+@code{schedule} script will mention this in its e-mail.
+
+@subheading Refresh any imported files.
+
+A number of files are taken from external repositories. They include:
+
+@itemize @bullet
+@item
+@file{texinfo/texinfo.tex}
+@item
+@file{config.guess} et.@: al.@: (see the top-level @file{MAINTAINERS}
+file)
+@item
+@file{etc/standards.texi}, @file{etc/make-stds.texi}
+@end itemize
+
+@subheading Check the ARI
+
+@uref{http://sources.redhat.com/gdb/ari,,A.R.I.} is an @code{awk} script
+(Awk Regression Index ;-) that checks for a number of errors and coding
+conventions. The checks include things like using @code{malloc} instead
+of @code{xmalloc} and file naming problems. There shouldn't be any
+regressions.
+
+@subsection Review the bug data base
+
+Close anything obviously fixed.
+
+@subsection Check all cross targets build
+
+The targets are listed in @file{gdb/MAINTAINERS}.
+
+
+@section Cut the Branch
+
+@subheading Create the branch
+
+@smallexample
+$ u=5.1
+$ v=5.2
+$ V=`echo $v | sed 's/\./_/g'`
+$ D=`date -u +%Y-%m-%d`
+$ echo $u $V $D
+5.1 5_2 2002-03-03
+$ echo cvs -f -d :ext:sources.redhat.com:/cvs/src rtag \
+-D $D-gmt gdb_$V-$D-branchpoint insight+dejagnu
+cvs -f -d :ext:sources.redhat.com:/cvs/src rtag
+-D 2002-03-03-gmt gdb_5_2-2002-03-03-branchpoint insight+dejagnu
+$ ^echo ^^
+...
+$ echo cvs -f -d :ext:sources.redhat.com:/cvs/src rtag \
+-b -r gdb_$V-$D-branchpoint gdb_$V-branch insight+dejagnu
+cvs -f -d :ext:sources.redhat.com:/cvs/src rtag \
+-b -r gdb_5_2-2002-03-03-branchpoint gdb_5_2-branch insight+dejagnu
+$ ^echo ^^
+...
+$
+@end smallexample
+
+@itemize @bullet
+@item
+by using @kbd{-D YYYY-MM-DD-gmt} the branch is forced to an exact
+date/time.
+@item
+the trunk is first taged so that the branch point can easily be found
+@item
+Insight (which includes GDB) and dejagnu are all tagged at the same time
+@item
+@file{version.in} gets bumped to avoid version number conflicts
+@item
+the reading of @file{.cvsrc} is disabled using @file{-f}
+@end itemize
+
+@subheading Update @file{version.in}
+
+@smallexample
+$ u=5.1
+$ v=5.2
+$ V=`echo $v | sed 's/\./_/g'`
+$ echo $u $v$V
+5.1 5_2
+$ cd /tmp
+$ echo cvs -f -d :ext:sources.redhat.com:/cvs/src co \
+-r gdb_$V-branch src/gdb/version.in
+cvs -f -d :ext:sources.redhat.com:/cvs/src co
+ -r gdb_5_2-branch src/gdb/version.in
+$ ^echo ^^
+U src/gdb/version.in
+$ cd src/gdb
+$ echo $u.90-0000-00-00-cvs > version.in
+$ cat version.in
+5.1.90-0000-00-00-cvs
+$ cvs -f commit version.in
+@end smallexample
+
+@itemize @bullet
+@item
+@file{0000-00-00} is used as a date to pump prime the version.in update
+mechanism
+@item
+@file{.90} and the previous branch version are used as fairly arbitrary
+initial branch version number
+@end itemize
+
+
+@subheading Update the web and news pages
+
+Something?
+
+@subheading Tweak cron to track the new branch
+
+The file @file{gdbadmin/cron/crontab} contains gdbadmin's cron table.
+This file needs to be updated so that:
+
+@itemize @bullet
+@item
+a daily timestamp is added to the file @file{version.in}
+@item
+the new branch is included in the snapshot process
+@end itemize
+
+@noindent
+See the file @file{gdbadmin/cron/README} for how to install the updated
+cron table.
+
+The file @file{gdbadmin/ss/README} should also be reviewed to reflect
+any changes. That file is copied to both the branch/ and current/
+snapshot directories.
+
+
+@subheading Update the NEWS and README files
+
+The @file{NEWS} file needs to be updated so that on the branch it refers
+to @emph{changes in the current release} while on the trunk it also
+refers to @emph{changes since the current release}.
+
+The @file{README} file needs to be updated so that it refers to the
+current release.
+
+@subheading Post the branch info
+
+Send an announcement to the mailing lists:
+
+@itemize @bullet
+@item
+@email{gdb-announce@@sources.redhat.com, GDB Announcement mailing list}
+@item
+@email{gdb@@sources.redhat.com, GDB Discsussion mailing list} and
+@email{gdb-testers@@sources.redhat.com, GDB Discsussion mailing list}
+@end itemize
+
+@emph{Pragmatics: The branch creation is sent to the announce list to
+ensure that people people not subscribed to the higher volume discussion
+list are alerted.}
+
+The announcement should include:
+
+@itemize @bullet
+@item
+the branch tag
+@item
+how to check out the branch using CVS
+@item
+the date/number of weeks until the release
+@item
+the branch commit policy
+still holds.
+@end itemize
+
+@section Stabilize the branch
+
+Something goes here.
+
+@section Create a Release
+
+The process of creating and then making available a release is broken
+down into a number of stages. The first part addresses the technical
+process of creating a releasable tar ball. The later stages address the
+process of releasing that tar ball.
+
+When making a release candidate just the first section is needed.
+
+@subsection Create a release candidate
+
+The objective at this stage is to create a set of tar balls that can be
+made available as a formal release (or as a less formal release
+candidate).
+
+@subsubheading Freeze the branch
+
+Send out an e-mail notifying everyone that the branch is frozen to
+@email{gdb-patches@@sources.redhat.com}.
+
+@subsubheading Establish a few defaults.
+
+@smallexample
+$ b=gdb_5_2-branch
+$ v=5.2
+$ t=/sourceware/snapshot-tmp/gdbadmin-tmp
+$ echo $t/$b/$v
+/sourceware/snapshot-tmp/gdbadmin-tmp/gdb_5_2-branch/5.2
+$ mkdir -p $t/$b/$v
+$ cd $t/$b/$v
+$ pwd
+/sourceware/snapshot-tmp/gdbadmin-tmp/gdb_5_2-branch/5.2
+$ which autoconf
+/home/gdbadmin/bin/autoconf
+$
+@end smallexample
+
+@noindent
+Notes:
+
+@itemize @bullet
+@item
+Check the @code{autoconf} version carefully. You want to be using the
+version taken from the @file{binutils} snapshot directory, which can be
+found at @uref{ftp://sources.redhat.com/pub/binutils/}. It is very
+unlikely that a system installed version of @code{autoconf} (e.g.,
+@file{/usr/bin/autoconf}) is correct.
+@end itemize
+
+@subsubheading Check out the relevant modules:
+
+@smallexample
+$ for m in gdb insight dejagnu
+do
+( mkdir -p $m && cd $m && cvs -q -f -d /cvs/src co -P -r $b $m )
+done
+$
+@end smallexample
+
+@noindent
+Note:
+
+@itemize @bullet
+@item
+The reading of @file{.cvsrc} is disabled (@file{-f}) so that there isn't
+any confusion between what is written here and what your local
+@code{cvs} really does.
+@end itemize
+
+@subsubheading Update relevant files.
+
+@table @file
+
+@item gdb/NEWS
+
+Major releases get their comments added as part of the mainline. Minor
+releases should probably mention any significant bugs that were fixed.
+
+Don't forget to include the @file{ChangeLog} entry.
+
+@smallexample
+$ emacs gdb/src/gdb/NEWS
+...
+c-x 4 a
+...
+c-x c-s c-x c-c
+$ cp gdb/src/gdb/NEWS insight/src/gdb/NEWS
+$ cp gdb/src/gdb/ChangeLog insight/src/gdb/ChangeLog
+@end smallexample
+
+@item gdb/README
+
+You'll need to update:
+
+@itemize @bullet
+@item
+the version
+@item
+the update date
+@item
+who did it
+@end itemize
+
+@smallexample
+$ emacs gdb/src/gdb/README
+...
+c-x 4 a
+...
+c-x c-s c-x c-c
+$ cp gdb/src/gdb/README insight/src/gdb/README
+$ cp gdb/src/gdb/ChangeLog insight/src/gdb/ChangeLog
+@end smallexample
+
+@emph{Maintainer note: Hopefully the @file{README} file was reviewed
+before the initial branch was cut so just a simple substitute is needed
+to get it updated.}
+
+@emph{Maintainer note: Other projects generate @file{README} and
+@file{INSTALL} from the core documentation. This might be worth
+pursuing.}
+
+@item gdb/version.in
+
+@smallexample
+$ echo $v > gdb/src/gdb/version.in
+$ cat gdb/src/gdb/version.in
+5.2
+$ emacs gdb/src/gdb/version.in
+...
+c-x 4 a
+... Bump to version ...
+c-x c-s c-x c-c
+$ cp gdb/src/gdb/version.in insight/src/gdb/version.in
+$ cp gdb/src/gdb/ChangeLog insight/src/gdb/ChangeLog
+@end smallexample
+
+@item dejagnu/src/dejagnu/configure.in
+
+Dejagnu is more complicated. The version number is a parameter to
+@code{AM_INIT_AUTOMAKE}. Tweak it to read something like gdb-5.1.91.
+
+Don't forget to re-generate @file{configure}.
+
+Don't forget to include a @file{ChangeLog} entry.
+
+@smallexample
+$ emacs dejagnu/src/dejagnu/configure.in
+...
+c-x 4 a
+...
+c-x c-s c-x c-c
+$ ( cd dejagnu/src/dejagnu && autoconf )
+@end smallexample
+
+@end table
+
+@subsubheading Do the dirty work
+
+This is identical to the process used to create the daily snapshot.
+
+@smallexample
+$ for m in gdb insight
+do
+( cd $m/src && gmake -f src-release $m.tar )
+done
+$ ( m=dejagnu; cd $m/src && gmake -f src-release $m.tar.bz2 )
+@end smallexample
+
+If the top level source directory does not have @file{src-release}
+(@value{GDBN} version 5.3.1 or earlier), try these commands instead:
+
+@smallexample
+$ for m in gdb insight
+do
+( cd $m/src && gmake -f Makefile.in $m.tar )
+done
+$ ( m=dejagnu; cd $m/src && gmake -f Makefile.in $m.tar.bz2 )
+@end smallexample
+
+@subsubheading Check the source files
+
+You're looking for files that have mysteriously disappeared.
+@kbd{distclean} has the habit of deleting files it shouldn't. Watch out
+for the @file{version.in} update @kbd{cronjob}.
+
+@smallexample
+$ ( cd gdb/src && cvs -f -q -n update )
+M djunpack.bat
+? gdb-5.1.91.tar
+? proto-toplev
+@dots{} lots of generated files @dots{}
+M gdb/ChangeLog
+M gdb/NEWS
+M gdb/README
+M gdb/version.in
+@dots{} lots of generated files @dots{}
+$
+@end smallexample
+
+@noindent
+@emph{Don't worry about the @file{gdb.info-??} or
+@file{gdb/p-exp.tab.c}. They were generated (and yes @file{gdb.info-1}
+was also generated only something strange with CVS means that they
+didn't get supressed). Fixing it would be nice though.}
+
+@subsubheading Create compressed versions of the release
+
+@smallexample
+$ cp */src/*.tar .
+$ cp */src/*.bz2 .
+$ ls -F
+dejagnu/ dejagnu-gdb-5.2.tar.bz2 gdb/ gdb-5.2.tar insight/ insight-5.2.tar
+$ for m in gdb insight
+do
+bzip2 -v -9 -c $m-$v.tar > $m-$v.tar.bz2
+gzip -v -9 -c $m-$v.tar > $m-$v.tar.gz
+done
+$
+@end smallexample
+
+@noindent
+Note:
+
+@itemize @bullet
+@item
+A pipe such as @kbd{bunzip2 < xxx.bz2 | gzip -9 > xxx.gz} is not since,
+in that mode, @code{gzip} does not know the name of the file and, hence,
+can not include it in the compressed file. This is also why the release
+process runs @code{tar} and @code{bzip2} as separate passes.
+@end itemize
+
+@subsection Sanity check the tar ball
+
+Pick a popular machine (Solaris/PPC?) and try the build on that.
+
+@smallexample
+$ bunzip2 < gdb-5.2.tar.bz2 | tar xpf -
+$ cd gdb-5.2
+$ ./configure
+$ make
+@dots{}
+$ ./gdb/gdb ./gdb/gdb
+GNU gdb 5.2
+@dots{}
+(gdb) b main
+Breakpoint 1 at 0x80732bc: file main.c, line 734.
+(gdb) run
+Starting program: /tmp/gdb-5.2/gdb/gdb
+
+Breakpoint 1, main (argc=1, argv=0xbffff8b4) at main.c:734
+734 catch_errors (captured_main, &args, "", RETURN_MASK_ALL);
+(gdb) print args
+$1 = @{argc = 136426532, argv = 0x821b7f0@}
+(gdb)
+@end smallexample
+
+@subsection Make a release candidate available
+
+If this is a release candidate then the only remaining steps are:
+
+@enumerate
+@item
+Commit @file{version.in} and @file{ChangeLog}
+@item
+Tweak @file{version.in} (and @file{ChangeLog} to read
+@var{L}.@var{M}.@var{N}-0000-00-00-cvs so that the version update
+process can restart.
+@item
+Make the release candidate available in
+@uref{ftp://sources.redhat.com/pub/gdb/snapshots/branch}
+@item
+Notify the relevant mailing lists ( @email{gdb@@sources.redhat.com} and
+@email{gdb-testers@@sources.redhat.com} that the candidate is available.
+@end enumerate
+
+@subsection Make a formal release available
+
+(And you thought all that was required was to post an e-mail.)
+
+@subsubheading Install on sware
+
+Copy the new files to both the release and the old release directory:
+
+@smallexample
+$ cp *.bz2 *.gz ~ftp/pub/gdb/old-releases/
+$ cp *.bz2 *.gz ~ftp/pub/gdb/releases
+@end smallexample
+
+@noindent
+Clean up the releases directory so that only the most recent releases
+are available (e.g. keep 5.2 and 5.2.1 but remove 5.1):
+
+@smallexample
+$ cd ~ftp/pub/gdb/releases
+$ rm @dots{}
+@end smallexample
+
+@noindent
+Update the file @file{README} and @file{.message} in the releases
+directory:
+
+@smallexample
+$ vi README
+@dots{}
+$ rm -f .message
+$ ln README .message
+@end smallexample
+
+@subsubheading Update the web pages.
+
+@table @file
+
+@item htdocs/download/ANNOUNCEMENT
+This file, which is posted as the official announcement, includes:
+@itemize @bullet
+@item
+General announcement
+@item
+News. If making an @var{M}.@var{N}.1 release, retain the news from
+earlier @var{M}.@var{N} release.
+@item
+Errata
+@end itemize
+
+@item htdocs/index.html
+@itemx htdocs/news/index.html
+@itemx htdocs/download/index.html
+These files include:
+@itemize @bullet
+@item
+announcement of the most recent release
+@item
+news entry (remember to update both the top level and the news directory).
+@end itemize
+These pages also need to be regenerate using @code{index.sh}.
+
+@item download/onlinedocs/
+You need to find the magic command that is used to generate the online
+docs from the @file{.tar.bz2}. The best way is to look in the output
+from one of the nightly @code{cron} jobs and then just edit accordingly.
+Something like:
+
+@smallexample
+$ ~/ss/update-web-docs \
+ ~ftp/pub/gdb/releases/gdb-5.2.tar.bz2 \
+ $PWD/www \
+ /www/sourceware/htdocs/gdb/download/onlinedocs \
+ gdb
+@end smallexample
+
+@item download/ari/
+Just like the online documentation. Something like:
+
+@smallexample
+$ /bin/sh ~/ss/update-web-ari \
+ ~ftp/pub/gdb/releases/gdb-5.2.tar.bz2 \
+ $PWD/www \
+ /www/sourceware/htdocs/gdb/download/ari \
+ gdb
+@end smallexample
+
+@end table
+
+@subsubheading Shadow the pages onto gnu
+
+Something goes here.
+
+
+@subsubheading Install the @value{GDBN} tar ball on GNU
+
+At the time of writing, the GNU machine was @kbd{gnudist.gnu.org} in
+@file{~ftp/gnu/gdb}.
+
+@subsubheading Make the @file{ANNOUNCEMENT}
+
+Post the @file{ANNOUNCEMENT} file you created above to:
+
+@itemize @bullet
+@item
+@email{gdb-announce@@sources.redhat.com, GDB Announcement mailing list}
+@item
+@email{info-gnu@@gnu.org, General GNU Announcement list} (but delay it a
+day or so to let things get out)
+@item
+@email{bug-gdb@@gnu.org, GDB Bug Report mailing list}
+@end itemize
+
+@subsection Cleanup
+
+The release is out but you're still not finished.
+
+@subsubheading Commit outstanding changes
+
+In particular you'll need to commit any changes to:
+
+@itemize @bullet
+@item
+@file{gdb/ChangeLog}
+@item
+@file{gdb/version.in}
+@item
+@file{gdb/NEWS}
+@item
+@file{gdb/README}
+@end itemize
+
+@subsubheading Tag the release
+
+Something like:
+
+@smallexample
+$ d=`date -u +%Y-%m-%d`
+$ echo $d
+2002-01-24
+$ ( cd insight/src/gdb && cvs -f -q update )
+$ ( cd insight/src && cvs -f -q tag gdb_5_2-$d-release )
+@end smallexample
+
+Insight is used since that contains more of the release than
+@value{GDBN} (@code{dejagnu} doesn't get tagged but I think we can live
+with that).
+
+@subsubheading Mention the release on the trunk
+
+Just put something in the @file{ChangeLog} so that the trunk also
+indicates when the release was made.
+
+@subsubheading Restart @file{gdb/version.in}
+
+If @file{gdb/version.in} does not contain an ISO date such as
+@kbd{2002-01-24} then the daily @code{cronjob} won't update it. Having
+committed all the release changes it can be set to
+@file{5.2.0_0000-00-00-cvs} which will restart things (yes the @kbd{_}
+is important - it affects the snapshot process).
+
+Don't forget the @file{ChangeLog}.
+
+@subsubheading Merge into trunk
+
+The files committed to the branch may also need changes merged into the
+trunk.
+
+@subsubheading Revise the release schedule
+
+Post a revised release schedule to @email{gdb@@sources.redhat.com, GDB
+Discussion List} with an updated announcement. The schedule can be
+generated by running:
+
+@smallexample
+$ ~/ss/schedule `date +%s` schedule
+@end smallexample
+
+@noindent
+The first parameter is approximate date/time in seconds (from the epoch)
+of the most recent release.
+
+Also update the schedule @code{cronjob}.
+
+@section Post release
+
+Remove any @code{OBSOLETE} code.
+
+@node Testsuite
+
+@chapter Testsuite
+@cindex test suite
+
+The testsuite is an important component of the @value{GDBN} package.
+While it is always worthwhile to encourage user testing, in practice
+this is rarely sufficient; users typically use only a small subset of
+the available commands, and it has proven all too common for a change
+to cause a significant regression that went unnoticed for some time.
+
+The @value{GDBN} testsuite uses the DejaGNU testing framework.
+DejaGNU is built using @code{Tcl} and @code{expect}. The tests
+themselves are calls to various @code{Tcl} procs; the framework runs all the
+procs and summarizes the passes and fails.
+
+@section Using the Testsuite
+
+@cindex running the test suite
+To run the testsuite, simply go to the @value{GDBN} object directory (or to the
+testsuite's objdir) and type @code{make check}. This just sets up some
+environment variables and invokes DejaGNU's @code{runtest} script. While
+the testsuite is running, you'll get mentions of which test file is in use,
+and a mention of any unexpected passes or fails. When the testsuite is
+finished, you'll get a summary that looks like this:
+
+@smallexample
+ === gdb Summary ===
+
+# of expected passes 6016
+# of unexpected failures 58
+# of unexpected successes 5
+# of expected failures 183
+# of unresolved testcases 3
+# of untested testcases 5
+@end smallexample
+
+The ideal test run consists of expected passes only; however, reality
+conspires to keep us from this ideal. Unexpected failures indicate
+real problems, whether in @value{GDBN} or in the testsuite. Expected
+failures are still failures, but ones which have been decided are too
+hard to deal with at the time; for instance, a test case might work
+everywhere except on AIX, and there is no prospect of the AIX case
+being fixed in the near future. Expected failures should not be added
+lightly, since you may be masking serious bugs in @value{GDBN}.
+Unexpected successes are expected fails that are passing for some
+reason, while unresolved and untested cases often indicate some minor
+catastrophe, such as the compiler being unable to deal with a test
+program.
+
+When making any significant change to @value{GDBN}, you should run the
+testsuite before and after the change, to confirm that there are no
+regressions. Note that truly complete testing would require that you
+run the testsuite with all supported configurations and a variety of
+compilers; however this is more than really necessary. In many cases
+testing with a single configuration is sufficient. Other useful
+options are to test one big-endian (Sparc) and one little-endian (x86)
+host, a cross config with a builtin simulator (powerpc-eabi,
+mips-elf), or a 64-bit host (Alpha).
+
+If you add new functionality to @value{GDBN}, please consider adding
+tests for it as well; this way future @value{GDBN} hackers can detect
+and fix their changes that break the functionality you added.
+Similarly, if you fix a bug that was not previously reported as a test
+failure, please add a test case for it. Some cases are extremely
+difficult to test, such as code that handles host OS failures or bugs
+in particular versions of compilers, and it's OK not to try to write
+tests for all of those.
+
+@section Testsuite Organization
+
+@cindex test suite organization
+The testsuite is entirely contained in @file{gdb/testsuite}. While the
+testsuite includes some makefiles and configury, these are very minimal,
+and used for little besides cleaning up, since the tests themselves
+handle the compilation of the programs that @value{GDBN} will run. The file
+@file{testsuite/lib/gdb.exp} contains common utility procs useful for
+all @value{GDBN} tests, while the directory @file{testsuite/config} contains
+configuration-specific files, typically used for special-purpose
+definitions of procs like @code{gdb_load} and @code{gdb_start}.
+
+The tests themselves are to be found in @file{testsuite/gdb.*} and
+subdirectories of those. The names of the test files must always end
+with @file{.exp}. DejaGNU collects the test files by wildcarding
+in the test directories, so both subdirectories and individual files
+get chosen and run in alphabetical order.
+
+The following table lists the main types of subdirectories and what they
+are for. Since DejaGNU finds test files no matter where they are
+located, and since each test file sets up its own compilation and
+execution environment, this organization is simply for convenience and
+intelligibility.
+
+@table @file
+@item gdb.base
+This is the base testsuite. The tests in it should apply to all
+configurations of @value{GDBN} (but generic native-only tests may live here).
+The test programs should be in the subset of C that is valid K&R,
+ANSI/ISO, and C@t{++} (@code{#ifdef}s are allowed if necessary, for instance
+for prototypes).
+
+@item gdb.@var{lang}
+Language-specific tests for any language @var{lang} besides C. Examples are
+@file{gdb.cp} and @file{gdb.java}.
+
+@item gdb.@var{platform}
+Non-portable tests. The tests are specific to a specific configuration
+(host or target), such as HP-UX or eCos. Example is @file{gdb.hp}, for
+HP-UX.
+
+@item gdb.@var{compiler}
+Tests specific to a particular compiler. As of this writing (June
+1999), there aren't currently any groups of tests in this category that
+couldn't just as sensibly be made platform-specific, but one could
+imagine a @file{gdb.gcc}, for tests of @value{GDBN}'s handling of GCC
+extensions.
+
+@item gdb.@var{subsystem}
+Tests that exercise a specific @value{GDBN} subsystem in more depth. For
+instance, @file{gdb.disasm} exercises various disassemblers, while
+@file{gdb.stabs} tests pathways through the stabs symbol reader.
+@end table
+
+@section Writing Tests
+@cindex writing tests
+
+In many areas, the @value{GDBN} tests are already quite comprehensive; you
+should be able to copy existing tests to handle new cases.
+
+You should try to use @code{gdb_test} whenever possible, since it
+includes cases to handle all the unexpected errors that might happen.
+However, it doesn't cost anything to add new test procedures; for
+instance, @file{gdb.base/exprs.exp} defines a @code{test_expr} that
+calls @code{gdb_test} multiple times.
+
+Only use @code{send_gdb} and @code{gdb_expect} when absolutely
+necessary, such as when @value{GDBN} has several valid responses to a command.
+
+The source language programs do @emph{not} need to be in a consistent
+style. Since @value{GDBN} is used to debug programs written in many different
+styles, it's worth having a mix of styles in the testsuite; for
+instance, some @value{GDBN} bugs involving the display of source lines would
+never manifest themselves if the programs used GNU coding style
+uniformly.
+
+@node Hints
+
+@chapter Hints
+
+Check the @file{README} file, it often has useful information that does not
+appear anywhere else in the directory.
+
+@menu
+* Getting Started:: Getting started working on @value{GDBN}
+* Debugging GDB:: Debugging @value{GDBN} with itself
+@end menu
+
+@node Getting Started,,, Hints
+
+@section Getting Started
+
+@value{GDBN} 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.
+
+This manual, the @value{GDBN} Internals manual, has information which applies
+generally to many parts of @value{GDBN}.
+
+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 @value{GDBN}; feel
+free to submit a bug report, with a suggested comment if you can figure
+out what the comment should say. 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 documents all the available macros.
+@c (@pxref{Host Conditionals}, @pxref{Target
+@c Conditionals}, @pxref{Native Conditionals}, and @pxref{Obsolete
+@c Conditionals})
+
+Start with the header files. Once you have some idea of how
+@value{GDBN}'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.
+
+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 @value{GDBN}, 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.
+
+Once you have a part of @value{GDBN} 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.
+
+@cindex command implementation
+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 @value{GDBN} 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 @value{GDBN} on itself and set a
+breakpoint in @code{execute_command}.
+
+@cindex @code{bug-gdb} mailing list
+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
+@value{GDBN}''---if we had some magic secret we would put it in this manual.
+Suggestions for improving the manual are always welcome, of course.
+
+@node Debugging GDB,,,Hints
+
+@section Debugging @value{GDBN} with itself
+@cindex debugging @value{GDBN}
+
+If @value{GDBN} 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 @kbd{@w{./gdb
+./gdb}}, which works on Suns and such, you can copy @file{gdb} to
+@file{gdb2} and then type @kbd{@w{./gdb ./gdb2}}.
+
+When you run @value{GDBN} in the @value{GDBN} source directory, it will read a
+@file{.gdbinit} file that sets up some simple things to make debugging
+gdb easier. The @code{info} command, when executed without a subcommand
+in a @value{GDBN} being debugged by gdb, will pop you back up to the top level
+gdb. See @file{.gdbinit} for details.
+
+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 @value{GDBN} with your local cc, or
+have run @code{fixincludes} if you are compiling with gcc.
+
+@section Submitting Patches
+
+@cindex submitting patches
+Thanks for thinking of offering your changes back to the community of
+@value{GDBN} 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 @value{GDBN} maintainers will only install ``cleanly designed'' patches.
+This manual summarizes what we believe to be clean design for @value{GDBN}.
+
+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.
+
+@cindex legal papers for code contributions
+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 documents for doing this by sending mail to @code{gnu@@gnu.org}
+and asking for it. We 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 @value{GDBN}, but GAS, Emacs, GCC,
+etc) can be
+contributed with only one piece of legalese pushed through the
+bureaucracy and filed with the FSF. We can't start merging changes until
+this paperwork is received by the FSF (their rules, which we follow
+since we 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 @code{patch}.
+Each message sent to me should include the changes to C code and
+header files for a single feature, plus @file{ChangeLog} entries for
+each directory where files were modified, and diffs for any changes
+needed to the manuals (@file{gdb/doc/gdb.texinfo} or
+@file{gdb/doc/gdbint.texinfo}). If there are a lot of changes for a
+single feature, they can be split down into multiple messages.
+
+In this way, if we read and like the feature, we can add it to the
+sources with a single patch command, do some testing, and check it in.
+If you leave out the @file{ChangeLog}, we have to write one. If you leave
+out the doc, we have to puzzle out what needs documenting. Etc., etc.
+
+The reason to send each change in a separate message is that we will not
+install some of the changes. They'll be returned to you with questions
+or comments. If we're doing our job correctly, the 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
+the acceptable changes can be installed while one or more changes are
+being reworked. If multiple features are sent in a single message, we
+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 we get a lot
+of bug reports and a lot of patches, and many of them don't get
+installed because we 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 as time
+permits, which, since the maintainers have many demands to meet, may not
+be for quite some time.
+
+Please send patches directly to
+@email{gdb-patches@@sources.redhat.com, the @value{GDBN} maintainers}.
+
+@section Obsolete Conditionals
+@cindex obsolete code
+
+Fragments of old code in @value{GDBN} 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 @value{GDBN}
+gets the info portably from there. The values in @value{GDBN}'s configuration
+files should be moved into BFD configuration files (if needed there),
+and deleted from all of @value{GDBN}'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
+
+@include observer.texi
+@raisesections
+@include fdl.texi
+@lowersections
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@bye
diff --git a/contrib/gdb/gdb/doc/gpl.texi b/contrib/gdb/gdb/doc/gpl.texi
new file mode 100644
index 0000000..be7ddc2
--- /dev/null
+++ b/contrib/gdb/gdb/doc/gpl.texi
@@ -0,0 +1,409 @@
+@ignore
+@c Set file name and title for man page.
+@setfilename gpl
+@settitle GNU General Public License
+@c man begin SEEALSO
+gfdl(7), fsf-funding(7).
+@c man end
+@c man begin COPYRIGHT
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@c man end
+@end ignore
+@node Copying
+@c man begin DESCRIPTION
+@appendix GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec 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.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING,@*DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifnottex
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifnottex
+
+@enumerate 0
+@item
+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.
+
+@item
+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.
+
+@item
+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:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+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.
+
+@item
+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.)
+@end enumerate
+
+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.
+
+@item
+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:
+
+@enumerate a
+@item
+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,
+
+@item
+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,
+
+@item
+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.)
+@end enumerate
+
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifnottex
+@center NO WARRANTY
+@end ifnottex
+
+@item
+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.
+
+@item
+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 enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifnottex
+@center END OF TERMS AND CONDITIONS
+@end ifnottex
+
+@page
+@unnumberedsec 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.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) @var{year} @var{name of author}
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+@end smallexample
+
+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:
+
+@smallexample
+Gnomovision version 69, Copyright (C) @var{year} @var{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.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{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:
+
+@smallexample
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end smallexample
+
+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.
+@c man end
diff --git a/contrib/gdb/gdb/doc/lpsrc.sed b/contrib/gdb/gdb/doc/lpsrc.sed
new file mode 100644
index 0000000..1c7af4a
--- /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/observer.texi b/contrib/gdb/gdb/doc/observer.texi
new file mode 100644
index 0000000..de48a19
--- /dev/null
+++ b/contrib/gdb/gdb/doc/observer.texi
@@ -0,0 +1,70 @@
+@c -*-texinfo-*-
+@node GDB Observers
+@appendix @value{GDBN} Currently available observers
+
+@section Implementation rationale
+@cindex observers implementation rationale
+
+An @dfn{observer} is an entity which is interested in being notified
+when GDB reaches certain states, or certain events occur in GDB.
+The entity being observed is called the @dfn{subject}. To receive
+notifications, the observer attaches a callback to the subject.
+One subject can have several observers.
+
+@file{observer.c} implements an internal generic low-level event
+notification mechanism. This generic event notification mechanism is
+then re-used to implement the exported high-level notification
+management routines for all possible notifications.
+
+The current implementation of the generic observer provides support
+for contextual data. This contextual data is given to the subject
+when attaching the callback. In return, the subject will provide
+this contextual data back to the observer as a parameter of the
+callback.
+
+Note that the current support for the contextual data is only partial,
+as it lacks a mechanism that would deallocate this data when the
+callback is detached. This is not a problem so far, as this contextual
+data is only used internally to hold a function pointer. Later on, if
+a certain observer needs to provide support for user-level contextual
+data, then the generic notification mechanism will need to be
+enhanced to allow the observer to provide a routine to deallocate the
+data when attaching the callback.
+
+The observer implementation is also currently not reentrant.
+In particular, it is therefore not possible to call the attach
+or detach routines during a notification.
+
+@section @code{normal_stop} Notifications
+@cindex @code{normal_stop} observer
+@cindex notification about inferior execution stop
+
+@value{GDBN} notifies all @code{normal_stop} observers when the
+inferior execution has just stopped, the associated messages and
+annotations have been printed, and the control is about to be returned
+to the user.
+
+Note that the @code{normal_stop} notification is not emitted when
+the execution stops due to a breakpoint, and this breakpoint has
+a condition that is not met. If the breakpoint has any associated
+commands list, the commands are executed after the notification
+is emitted.
+
+The following interface is available to manage @code{normal_stop}
+observers:
+
+@deftypefun extern struct observer *observer_attach_normal_stop (observer_normal_stop_ftype *@var{f})
+Attach the given @code{normal_stop} callback function @var{f} and
+return the associated observer.
+@end deftypefun
+
+@deftypefun extern void observer_detach_normal_stop (struct observer *@var{observer});
+Remove @var{observer} from the list of observers to be notified when
+a @code{normal_stop} event occurs.
+@end deftypefun
+
+@deftypefun extern void observer_notify_normal_stop (void);
+Send a notification to all @code{normal_stop} observers.
+@end deftypefun
+
+
diff --git a/contrib/gdb/gdb/doc/psrc.sed b/contrib/gdb/gdb/doc/psrc.sed
new file mode 100644
index 0000000..9bb557e
--- /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.tex b/contrib/gdb/gdb/doc/refcard.tex
new file mode 100644
index 0000000..a8de900
--- /dev/null
+++ b/contrib/gdb/gdb/doc/refcard.tex
@@ -0,0 +1,647 @@
+%%%%%%%%%%%%%%%% gdb-refcard.tex %%%%%%%%%%%%%%%%
+
+%This file is TeX source for a reference card describing GDB, the GNU debugger.
+%Copyright 1991, 1992, 1993, 1996, 1998, 1999, 2000
+%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 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 can find a copy of the GNU General Public License at the URL
+%http://www.gnu.org/copyleft/gpl.html; or write to the Free Software
+%Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+%
+%You can contact the maintainer at: doc@cygnus.com
+%
+% Documentation Department
+% Cygnus Solutions
+% 1325 Chesapeake Terrace
+% Sunnyvale, CA 94089 USA
+%
+% +1 800 CYGNUS-1
+%
+%
+%
+% 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 5}\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 1998,2000 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 event}&break at {\it event}, which may be {\tt catch}, {\tt throw},
+{\tt exec}, {\tt fork}, {\tt vfork}, {\tt load}, or {\tt unload}.\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}&register values \opt{for regs {\it rn\/}} in
+selected frame; {\tt all-reg} includes floating point\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} \&&copy 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
+Copyright \copyright 1991,'92,'93,'98,2000 Free Software Foundation, Inc.
+Author: Roland H. Pesch
+
+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.
+
+Please contribute to development of this card by
+annotating it. Improvements can be sent to bug-gdb@gnu.org.
+
+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/stabs.texinfo b/contrib/gdb/gdb/doc/stabs.texinfo
new file mode 100644
index 0000000..d43ef37
--- /dev/null
+++ b/contrib/gdb/gdb/doc/stabs.texinfo
@@ -0,0 +1,4046 @@
+\input texinfo
+@setfilename stabs.info
+
+@c @finalout
+
+@c This is a dir.info fragment to support semi-automated addition of
+@c manuals to an info tree.
+@dircategory Software development
+@direntry
+* Stabs: (stabs). The "stabs" debugging information format.
+@end direntry
+
+@ifinfo
+This document describes the stabs debugging symbol tables.
+
+Copyright 1992,1993,1994,1995,1997,1998,2000,2001
+ Free Software Foundation, Inc.
+Contributed by Cygnus Support. Written by Julia Menapace, Jim Kingdon,
+and David MacKenzie.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts. A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+@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.130 $} % 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,1994,1995,1997,1998,2000,2001 Free Software Foundation, Inc.
+Contributed by Cygnus Support.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts. A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+@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 anomalies
+* Stab Sections:: In some object file formats, stabs are
+ in sections.
+* Symbol Types Index:: Index of symbolic stab symbol type names.
+* GNU Free Documentation License:: The license for this documentation
+@end menu
+@end ifinfo
+
+@c TeX can handle the contents at the start but makeinfo 3.12 can not
+@iftex
+@contents
+@end iftex
+
+@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}.
+
+A @var{type-number} is often a single number. The GNU and Sun tools
+additionally permit a @var{type-number} to be a pair
+(@var{file-number},@var{filetype-number}) (the parentheses appear in the
+string, and serve to distinguish the two cases). The @var{file-number}
+is 0 for the base source file, 1 for the first included file, 2 for the
+next, and so on. The @var{filetype-number} is a number starting with
+1 which is incremented for each new type defined in the file.
+(Separating the file number and the type number permits the
+@code{N_BINCL} optimization to succeed more often; see @ref{Include
+Files}).
+
+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@t{++}
+(@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@t{++} 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.
+
+@item V
+Indicate that this type is a vector instead of an array. The only
+major difference between vectors and arrays is that vectors are
+passed by value instead of by reference (vector coprocessor extension).
+
+@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@t{++} 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 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 occurrence is replaced by an @code{N_EXCL} symbol. I believe
+the GNU linker and the Sun (both SunOS4 and Solaris) linker are the only
+ones which supports this feature.
+
+A linker which supports this feature will set 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 any file numbers. The
+value of an @code{N_EXCL} symbol is the same as the value of the
+@code{N_BINCL} symbol it replaces. This information can be used to
+match up @code{N_EXCL} and @code{N_BINCL} symbols which have the same
+filename. 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.
+
+If functions can appear in different sections, then the debugger may not
+be able to find the end of a function. Recent versions of GCC will mark
+the end of a function with an @code{N_FUN} symbol with an empty string
+for the name. The value is the address of the end of the current
+function. Without such a symbol, there is no indication of the address
+of the end of a function, and you must assume that it ended at the
+starting address of the next function or at the end of the text section
+for the program.
+
+@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
+
+See @ref{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 convoluted, 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 seat belts 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 precision?).
+
+@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@t{++} 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 passed 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. Separate 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 emitted 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
+@samp{@var{name}:@var{type}, @var{bit offset from the start of the
+struct}, @var{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 stand-alone 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@t{++} 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@t{++} 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). (The Sun
+documentation mentions using @code{N_GSYM} in some cases).
+
+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 information 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 @samp{@var{name}:@var{type}, @var{bit
+offset into the union}, @var{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@t{++} 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::
+* Inheritance::
+* Virtual Base Classes::
+* Static Members::
+@end menu
+
+@node Class Names
+@section C@t{++} Class Names
+
+In C@t{++}, 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@t{++} 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@t{++}, 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@t{++}
+
+<< the examples that follow are based on a01.C >>
+
+
+C@t{++} 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@t{++} 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@t{++} language features are an extension of the
+stabs describing C. Stabs representing C@t{++} 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@t{++} 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 relevant to C@t{++} 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@t{++} 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@t{++} 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, preceded 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@t{++} 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@t{++} 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@t{++} 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_descriptor(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 emitted. Since the
+compiler knows it will be emitted 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 used to describe a class method. This is a function which takes
+an extra argument as its first argument, for the @code{this} pointer.
+
+If the @samp{#} is immediately followed by another @samp{#}, the second
+one will be followed by the return type and a semicolon. The class and
+argument types are not specified, and must be determined by demangling
+the name of the method if it is available.
+
+Otherwise, the single @samp{#} is followed by the class type, a comma,
+the return type, a comma, and zero or more parameter types separated by
+commas. The list of arguments is terminated by a semicolon. In the
+debugging output generated by gcc, a final argument type of @code{void}
+indicates a method which does not take a variable number of arguments.
+If the final argument type of @code{void} does not appear, the method
+was declared with an ellipsis.
+
+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 used together with the @samp{*} type
+descriptor for a pointer-to-non-static-member-data type. It is followed
+by type information for the class (or union), a comma, and type
+information for the member data.
+
+The following C@t{++} source:
+
+@smallexample
+typedef int A::*int_in_a;
+@end smallexample
+
+generates the following stab:
+
+@smallexample
+.stabs "int_in_a:t20=*21=@@19,1",128,0,0,0
+@end smallexample
+
+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@t{++} 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 accessible. The example that follows
+contrasts public, protected and privately accessible fields and shows
+how these protections are encoded in C@t{++} 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@t{++} 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 embedded 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@t{++} 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)virtual(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)modifier(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@t{++} 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@t{++}
+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
+inheritance 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 preceded 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 Inheritance
+@section Inheritance
+
+Stabs describing C@t{++} derived classes include additional sections that
+describe the inheritance 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 inheritance 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 embedded 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
+visibility 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)inheritance_public(no)base_offset(0),
+ base_class_type_ref(A);
+ base_virtual(yes)inheritance_public(no)base_offset(NIL),
+ base_class_type_ref(B);
+ base_virtual(no)inheritance_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 concatenation 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 inheritance. 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@t{++} 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@t{++} @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@t{++} 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@t{++}). 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@t{++}); see @ref{Method Type Descriptor}.
+
+@item *
+Pointer; see @ref{Miscellaneous Types}.
+
+@item &
+Reference (C@t{++}).
+
+@item @@
+Type Attributes (AIX); see @ref{String Field}. Member (class and variable)
+type (GNU C@t{++}); 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
+qualified 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@t{++} 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@t{++} 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@t{++} @code{catch} clause
+
+GNU C@t{++} @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.
+
+<<?looking at structs and unions in C I didn't see these>>
+@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 emitted 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 over-compensates 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 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 may be 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.
+
+The GNU linker is able to optimize stabs information by merging
+duplicate strings and removing duplicate header file information
+(@pxref{Include Files}). When some versions of the GNU linker optimize
+stabs in sections, they remove the leading @code{N_UNDF} symbol and
+arranges for all the @code{n_strx} fields to be relative to the start of
+the @code{.stabstr} section.
+
+@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.
+
+@raisesections
+@include fdl.texi
+@lowersections
+
+@node Symbol Types Index
+@unnumbered Symbol Types Index
+
+@printindex fn
+
+@c TeX can handle the contents at the start but makeinfo 3.12 can not
+@ifinfo
+@contents
+@end ifinfo
+@ifhtml
+@contents
+@end ifhtml
+
+@bye
diff --git a/contrib/gdb/gdb/doublest.c b/contrib/gdb/gdb/doublest.c
new file mode 100644
index 0000000..3f283e1
--- /dev/null
+++ b/contrib/gdb/gdb/doublest.c
@@ -0,0 +1,824 @@
+/* Floating point routines for GDB, the GNU debugger.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 converting target fp numbers into host DOUBLEST format. */
+
+/* XXX - This code should really be in libiberty/floatformat.c,
+ however configuration issues with libiberty made this very
+ difficult to do in the available time. */
+
+#include "defs.h"
+#include "doublest.h"
+#include "floatformat.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdbtypes.h"
+#include <math.h> /* ldexp */
+
+/* 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
+
+static unsigned long get_field (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 (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. */
+ if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ {
+ /* We start counting from the other end (i.e, from the high bytes
+ rather than the low bytes). As such, we need to be concerned
+ with what happens if bit 0 doesn't start on a byte boundary.
+ I.e, we need to properly handle the case where total_len is
+ not evenly divisible by 8. So we compute ``excess'' which
+ represents the number of bits from the end of our starting
+ byte needed to get to bit 0. */
+ int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
+ cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
+ - ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
+ cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
+ - FLOATFORMAT_CHAR_BIT;
+ }
+ else
+ {
+ cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+ cur_bitshift =
+ ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+ }
+ if (cur_bitshift > -FLOATFORMAT_CHAR_BIT)
+ result = *(data + cur_byte) >> (-cur_bitshift);
+ else
+ result = 0;
+ cur_bitshift += FLOATFORMAT_CHAR_BIT;
+ if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ ++cur_byte;
+ else
+ --cur_byte;
+
+ /* Move towards the most significant part of the field. */
+ while (cur_bitshift < len)
+ {
+ result |= (unsigned long)*(data + cur_byte) << cur_bitshift;
+ cur_bitshift += FLOATFORMAT_CHAR_BIT;
+ if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ ++cur_byte;
+ else
+ --cur_byte;
+ }
+ if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
+ /* Mask out bits which are not part of the field */
+ result &= ((1UL << len) - 1);
+ return result;
+}
+
+/* Convert from FMT to a DOUBLEST.
+ FROM is the address of the extended float.
+ Store the DOUBLEST in *TO. */
+
+static void
+convert_floatformat_to_doublest (const struct floatformat *fmt,
+ const void *from,
+ DOUBLEST *to)
+{
+ unsigned char *ufrom = (unsigned char *) from;
+ DOUBLEST dto;
+ long exponent;
+ unsigned long mant;
+ unsigned int mant_bits, mant_off;
+ int mant_bits_left;
+ int special_exponent; /* It's a NaN, denorm or zero */
+
+ /* If the mantissa bits are not contiguous from one end of the
+ mantissa to the other, we need to make a private copy of the
+ source bytes that is in the right order since the unpacking
+ algorithm assumes that the bits are contiguous.
+
+ Swap the bytes individually rather than accessing them through
+ "long *" since we have no guarantee that they start on a long
+ alignment, and also sizeof(long) for the host could be different
+ than sizeof(long) for the target. FIXME: Assumes sizeof(long)
+ for the target is 4. */
+
+ if (fmt->byteorder == floatformat_littlebyte_bigword)
+ {
+ static unsigned char *newfrom;
+ unsigned char *swapin, *swapout;
+ int longswaps;
+
+ longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
+ longswaps >>= 3;
+
+ if (newfrom == NULL)
+ {
+ newfrom = (unsigned char *) xmalloc (fmt->totalsize);
+ }
+ swapout = newfrom;
+ swapin = ufrom;
+ ufrom = newfrom;
+ while (longswaps-- > 0)
+ {
+ /* This is ugly, but efficient */
+ *swapout++ = swapin[4];
+ *swapout++ = swapin[5];
+ *swapout++ = swapin[6];
+ *swapout++ = swapin[7];
+ *swapout++ = swapin[0];
+ *swapout++ = swapin[1];
+ *swapout++ = swapin[2];
+ *swapout++ = swapin[3];
+ swapin += 8;
+ }
+ }
+
+ 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;
+
+ special_exponent = exponent == 0 || exponent == fmt->exp_nan;
+
+ /* Don't bias NaNs. Use minimum exponent for denorms. For simplicity,
+ we don't check for zero as the exponent doesn't matter. Note the cast
+ to int; exp_bias is unsigned, so it's important to make sure the
+ operation is done in signed arithmetic. */
+ if (!special_exponent)
+ exponent -= fmt->exp_bias;
+ else if (exponent == 0)
+ exponent = 1 - fmt->exp_bias;
+
+ /* Build the result algebraically. Might go infinite, underflow, etc;
+ who cares. */
+
+/* If this format uses a hidden bit, explicitly add it in now. Otherwise,
+ increment the exponent by one to account for the integer bit. */
+
+ if (!special_exponent)
+ {
+ if (fmt->intbit == floatformat_intbit_no)
+ dto = ldexp (1.0, exponent);
+ else
+ exponent++;
+ }
+
+ while (mant_bits_left > 0)
+ {
+ mant_bits = min (mant_bits_left, 32);
+
+ mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
+ mant_off, mant_bits);
+
+ dto += ldexp ((double) mant, exponent - mant_bits);
+ exponent -= mant_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;
+ *to = dto;
+}
+
+static void put_field (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 (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. */
+ if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ {
+ int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
+ cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
+ - ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
+ cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
+ - FLOATFORMAT_CHAR_BIT;
+ }
+ else
+ {
+ cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+ cur_bitshift =
+ ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+ }
+ if (cur_bitshift > -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 || order == floatformat_littlebyte_bigword)
+ ++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 || order == floatformat_littlebyte_bigword)
+ ++cur_byte;
+ else
+ --cur_byte;
+ }
+}
+
+#ifdef HAVE_LONG_DOUBLE
+/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR.
+ The range of the returned value is >= 0.5 and < 1.0. This is equivalent to
+ frexp, but operates on the long double data type. */
+
+static long double ldfrexp (long double value, int *eptr);
+
+static long double
+ldfrexp (long double value, int *eptr)
+{
+ long double tmp;
+ int exp;
+
+ /* Unfortunately, there are no portable functions for extracting the exponent
+ of a long double, so we have to do it iteratively by multiplying or dividing
+ by two until the fraction is between 0.5 and 1.0. */
+
+ if (value < 0.0l)
+ value = -value;
+
+ tmp = 1.0l;
+ exp = 0;
+
+ if (value >= tmp) /* Value >= 1.0 */
+ while (value >= tmp)
+ {
+ tmp *= 2.0l;
+ exp++;
+ }
+ else if (value != 0.0l) /* Value < 1.0 and > 0.0 */
+ {
+ while (value < tmp)
+ {
+ tmp /= 2.0l;
+ exp--;
+ }
+ tmp *= 2.0l;
+ exp++;
+ }
+
+ *eptr = exp;
+ return value / tmp;
+}
+#endif /* HAVE_LONG_DOUBLE */
+
+
+/* The converse: convert the DOUBLEST *FROM to an extended float
+ and store where TO points. Neither FROM nor TO have any alignment
+ restrictions. */
+
+static void
+convert_doublest_to_floatformat (CONST struct floatformat *fmt,
+ const DOUBLEST *from,
+ void *to)
+{
+ DOUBLEST dfrom;
+ int exponent;
+ DOUBLEST 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 - 1)
+ / FLOATFORMAT_CHAR_BIT);
+ if (dfrom == 0)
+ return; /* Result is zero */
+ if (dfrom != dfrom) /* Result is NaN */
+ {
+ /* 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;
+ }
+
+ if (dfrom + dfrom == dfrom && dfrom != 0.0) /* Result is Infinity */
+ {
+ /* Infinity exponent is same as NaN's. */
+ put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+ fmt->exp_len, fmt->exp_nan);
+ /* Infinity mantissa is all zeroes. */
+ put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
+ fmt->man_len, 0);
+ return;
+ }
+
+#ifdef HAVE_LONG_DOUBLE
+ mant = ldfrexp (dfrom, &exponent);
+#else
+ mant = frexp (dfrom, &exponent);
+#endif
+
+ 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) & 0xffffffffL;
+ 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 <<= 1;
+ mant_long &= 0xffffffffL;
+ /* If we are processing the top 32 mantissa bits of a doublest
+ so as to convert to a float value with implied integer bit,
+ we will only be putting 31 of those 32 bits into the
+ final value due to the discarding of the top bit. In the
+ case of a small float value where the number of mantissa
+ bits is less than 32, discarding the top bit does not alter
+ the number of bits we will be adding to the result. */
+ if (mant_bits == 32)
+ mant_bits -= 1;
+ }
+
+ 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;
+ }
+ if (fmt->byteorder == floatformat_littlebyte_bigword)
+ {
+ int count;
+ unsigned char *swaplow = uto;
+ unsigned char *swaphigh = uto + 4;
+ unsigned char tmp;
+
+ for (count = 0; count < 4; count++)
+ {
+ tmp = *swaplow;
+ *swaplow++ = *swaphigh;
+ *swaphigh++ = tmp;
+ }
+ }
+}
+
+/* Check if VAL (which is assumed to be a floating point number whose
+ format is described by FMT) is negative. */
+
+int
+floatformat_is_negative (const struct floatformat *fmt, char *val)
+{
+ unsigned char *uval = (unsigned char *) val;
+ gdb_assert (fmt != NULL);
+ return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
+}
+
+/* Check if VAL is "not a number" (NaN) for FMT. */
+
+int
+floatformat_is_nan (const struct floatformat *fmt, char *val)
+{
+ unsigned char *uval = (unsigned char *) val;
+ long exponent;
+ unsigned long mant;
+ unsigned int mant_bits, mant_off;
+ int mant_bits_left;
+
+ gdb_assert (fmt != NULL);
+
+ if (! fmt->exp_nan)
+ return 0;
+
+ exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
+ fmt->exp_start, fmt->exp_len);
+
+ if (exponent != fmt->exp_nan)
+ return 0;
+
+ mant_bits_left = fmt->man_len;
+ mant_off = fmt->man_start;
+
+ while (mant_bits_left > 0)
+ {
+ mant_bits = min (mant_bits_left, 32);
+
+ mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+ mant_off, mant_bits);
+
+ /* If there is an explicit integer bit, mask it off. */
+ if (mant_off == fmt->man_start
+ && fmt->intbit == floatformat_intbit_yes)
+ mant &= ~(1 << (mant_bits - 1));
+
+ if (mant)
+ return 1;
+
+ mant_off += mant_bits;
+ mant_bits_left -= mant_bits;
+ }
+
+ return 0;
+}
+
+/* Convert the mantissa of VAL (which is assumed to be a floating
+ point number whose format is described by FMT) into a hexadecimal
+ and store it in a static string. Return a pointer to that string. */
+
+char *
+floatformat_mantissa (const struct floatformat *fmt, char *val)
+{
+ unsigned char *uval = (unsigned char *) val;
+ unsigned long mant;
+ unsigned int mant_bits, mant_off;
+ int mant_bits_left;
+ static char res[50];
+ char buf[9];
+
+ /* Make sure we have enough room to store the mantissa. */
+ gdb_assert (fmt != NULL);
+ gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
+
+ mant_off = fmt->man_start;
+ mant_bits_left = fmt->man_len;
+ mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
+
+ mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+ mant_off, mant_bits);
+
+ sprintf (res, "%lx", mant);
+
+ mant_off += mant_bits;
+ mant_bits_left -= mant_bits;
+
+ while (mant_bits_left > 0)
+ {
+ mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+ mant_off, 32);
+
+ sprintf (buf, "%08lx", mant);
+ strcat (res, buf);
+
+ mant_off += 32;
+ mant_bits_left -= 32;
+ }
+
+ return res;
+}
+
+
+/* Convert TO/FROM target to the hosts DOUBLEST floating-point format.
+
+ If the host and target formats agree, we just copy the raw data
+ into the appropriate type of variable and return, letting the host
+ increase precision as necessary. Otherwise, we call the conversion
+ routine and let it do the dirty work. */
+
+#ifndef HOST_FLOAT_FORMAT
+#define HOST_FLOAT_FORMAT 0
+#endif
+#ifndef HOST_DOUBLE_FORMAT
+#define HOST_DOUBLE_FORMAT 0
+#endif
+#ifndef HOST_LONG_DOUBLE_FORMAT
+#define HOST_LONG_DOUBLE_FORMAT 0
+#endif
+
+static const struct floatformat *host_float_format = HOST_FLOAT_FORMAT;
+static const struct floatformat *host_double_format = HOST_DOUBLE_FORMAT;
+static const struct floatformat *host_long_double_format = HOST_LONG_DOUBLE_FORMAT;
+
+void
+floatformat_to_doublest (const struct floatformat *fmt,
+ const void *in, DOUBLEST *out)
+{
+ gdb_assert (fmt != NULL);
+ if (fmt == host_float_format)
+ {
+ float val;
+ memcpy (&val, in, sizeof (val));
+ *out = val;
+ }
+ else if (fmt == host_double_format)
+ {
+ double val;
+ memcpy (&val, in, sizeof (val));
+ *out = val;
+ }
+ else if (fmt == host_long_double_format)
+ {
+ long double val;
+ memcpy (&val, in, sizeof (val));
+ *out = val;
+ }
+ else
+ convert_floatformat_to_doublest (fmt, in, out);
+}
+
+void
+floatformat_from_doublest (const struct floatformat *fmt,
+ const DOUBLEST *in, void *out)
+{
+ gdb_assert (fmt != NULL);
+ if (fmt == host_float_format)
+ {
+ float val = *in;
+ memcpy (out, &val, sizeof (val));
+ }
+ else if (fmt == host_double_format)
+ {
+ double val = *in;
+ memcpy (out, &val, sizeof (val));
+ }
+ else if (fmt == host_long_double_format)
+ {
+ long double val = *in;
+ memcpy (out, &val, sizeof (val));
+ }
+ else
+ convert_doublest_to_floatformat (fmt, in, out);
+}
+
+
+/* Return a floating-point format for a floating-point variable of
+ length LEN. Return NULL, if no suitable floating-point format
+ could be found.
+
+ We need this functionality since information about the
+ floating-point format of a type is not always available to GDB; the
+ debug information typically only tells us the size of a
+ floating-point type.
+
+ FIXME: kettenis/2001-10-28: In many places, particularly in
+ target-dependent code, the format of floating-point types is known,
+ but not passed on by GDB. This should be fixed. */
+
+static const struct floatformat *
+floatformat_from_length (int len)
+{
+ if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT)
+ return TARGET_FLOAT_FORMAT;
+ else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT)
+ return TARGET_DOUBLE_FORMAT;
+ else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT)
+ return TARGET_LONG_DOUBLE_FORMAT;
+ /* On i386 the 'long double' type takes 96 bits,
+ while the real number of used bits is only 80,
+ both in processor and in memory.
+ The code below accepts the real bit size. */
+ else if ((TARGET_LONG_DOUBLE_FORMAT != NULL)
+ && (len * TARGET_CHAR_BIT ==
+ TARGET_LONG_DOUBLE_FORMAT->totalsize))
+ return TARGET_LONG_DOUBLE_FORMAT;
+
+ return NULL;
+}
+
+const struct floatformat *
+floatformat_from_type (const struct type *type)
+{
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
+ if (TYPE_FLOATFORMAT (type) != NULL)
+ return TYPE_FLOATFORMAT (type);
+ else
+ return floatformat_from_length (TYPE_LENGTH (type));
+}
+
+/* If the host doesn't define NAN, use zero instead. */
+#ifndef NAN
+#define NAN 0.0
+#endif
+
+/* Extract a floating-point number of length LEN from a target-order
+ byte-stream at ADDR. Returns the value as type DOUBLEST. */
+
+static DOUBLEST
+extract_floating_by_length (const void *addr, int len)
+{
+ const struct floatformat *fmt = floatformat_from_length (len);
+ DOUBLEST val;
+
+ if (fmt == NULL)
+ {
+ warning ("Can't extract a floating-point number of %d bytes.", len);
+ return NAN;
+ }
+
+ floatformat_to_doublest (fmt, addr, &val);
+ return val;
+}
+
+DOUBLEST
+deprecated_extract_floating (const void *addr, int len)
+{
+ return extract_floating_by_length (addr, len);
+}
+
+/* Store VAL as a floating-point number of length LEN to a
+ target-order byte-stream at ADDR. */
+
+static void
+store_floating_by_length (void *addr, int len, DOUBLEST val)
+{
+ const struct floatformat *fmt = floatformat_from_length (len);
+
+ if (fmt == NULL)
+ {
+ warning ("Can't store a floating-point number of %d bytes.", len);
+ memset (addr, 0, len);
+ return;
+ }
+
+ floatformat_from_doublest (fmt, &val, addr);
+}
+
+void
+deprecated_store_floating (void *addr, int len, DOUBLEST val)
+{
+ store_floating_by_length (addr, len, val);
+}
+
+/* Extract a floating-point number of type TYPE from a target-order
+ byte-stream at ADDR. Returns the value as type DOUBLEST. */
+
+DOUBLEST
+extract_typed_floating (const void *addr, const struct type *type)
+{
+ DOUBLEST retval;
+
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
+
+ if (TYPE_FLOATFORMAT (type) == NULL)
+ /* Not all code remembers to set the FLOATFORMAT (language
+ specific code? stabs?) so handle that here as a special case. */
+ return extract_floating_by_length (addr, TYPE_LENGTH (type));
+
+ floatformat_to_doublest (TYPE_FLOATFORMAT (type), addr, &retval);
+ return retval;
+}
+
+/* Store VAL as a floating-point number of type TYPE to a target-order
+ byte-stream at ADDR. */
+
+void
+store_typed_floating (void *addr, const struct type *type, DOUBLEST val)
+{
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
+
+ /* FIXME: kettenis/2001-10-28: It is debatable whether we should
+ zero out any remaining bytes in the target buffer when TYPE is
+ longer than the actual underlying floating-point format. Perhaps
+ we should store a fixed bitpattern in those remaining bytes,
+ instead of zero, or perhaps we shouldn't touch those remaining
+ bytes at all.
+
+ NOTE: cagney/2001-10-28: With the way things currently work, it
+ isn't a good idea to leave the end bits undefined. This is
+ because GDB writes out the entire sizeof(<floating>) bits of the
+ floating-point type even though the value might only be stored
+ in, and the target processor may only refer to, the first N <
+ TYPE_LENGTH (type) bits. If the end of the buffer wasn't
+ initialized, GDB would write undefined data to the target. An
+ errant program, refering to that undefined data, would then
+ become non-deterministic.
+
+ See also the function convert_typed_floating below. */
+ memset (addr, 0, TYPE_LENGTH (type));
+
+ if (TYPE_FLOATFORMAT (type) == NULL)
+ /* Not all code remembers to set the FLOATFORMAT (language
+ specific code? stabs?) so handle that here as a special case. */
+ store_floating_by_length (addr, TYPE_LENGTH (type), val);
+ else
+ floatformat_from_doublest (TYPE_FLOATFORMAT (type), &val, addr);
+}
+
+/* Convert a floating-point number of type FROM_TYPE from a
+ target-order byte-stream at FROM to a floating-point number of type
+ TO_TYPE, and store it to a target-order byte-stream at TO. */
+
+void
+convert_typed_floating (const void *from, const struct type *from_type,
+ void *to, const struct type *to_type)
+{
+ const struct floatformat *from_fmt = floatformat_from_type (from_type);
+ const struct floatformat *to_fmt = floatformat_from_type (to_type);
+
+ gdb_assert (TYPE_CODE (from_type) == TYPE_CODE_FLT);
+ gdb_assert (TYPE_CODE (to_type) == TYPE_CODE_FLT);
+
+ if (from_fmt == NULL || to_fmt == NULL)
+ {
+ /* If we don't know the floating-point format of FROM_TYPE or
+ TO_TYPE, there's not much we can do. We might make the
+ assumption that if the length of FROM_TYPE and TO_TYPE match,
+ their floating-point format would match too, but that
+ assumption might be wrong on targets that support
+ floating-point types that only differ in endianness for
+ example. So we warn instead, and zero out the target buffer. */
+ warning ("Can't convert floating-point number to desired type.");
+ memset (to, 0, TYPE_LENGTH (to_type));
+ }
+ else if (from_fmt == to_fmt)
+ {
+ /* We're in business. The floating-point format of FROM_TYPE
+ and TO_TYPE match. However, even though the floating-point
+ format matches, the length of the type might still be
+ different. Make sure we don't overrun any buffers. See
+ comment in store_typed_floating for a discussion about
+ zeroing out remaining bytes in the target buffer. */
+ memset (to, 0, TYPE_LENGTH (to_type));
+ memcpy (to, from, min (TYPE_LENGTH (from_type), TYPE_LENGTH (to_type)));
+ }
+ else
+ {
+ /* The floating-point types don't match. The best we can do
+ (aport from simulating the target FPU) is converting to the
+ widest floating-point type supported by the host, and then
+ again to the desired type. */
+ DOUBLEST d;
+
+ floatformat_to_doublest (from_fmt, from, &d);
+ floatformat_from_doublest (to_fmt, &d, to);
+ }
+}
diff --git a/contrib/gdb/gdb/doublest.h b/contrib/gdb/gdb/doublest.h
new file mode 100644
index 0000000..668efa7
--- /dev/null
+++ b/contrib/gdb/gdb/doublest.h
@@ -0,0 +1,90 @@
+/* Floating point definitions for GDB.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 DOUBLEST_H
+#define DOUBLEST_H
+
+struct type;
+
+/* Setup definitions for host and target floating point formats. We need to
+ consider the format for `float', `double', and `long double' for both target
+ and host. We need to do this so that we know what kind of conversions need
+ to be done when converting target numbers to and from the hosts DOUBLEST
+ data type. */
+
+/* This is used to indicate that we don't know the format of the floating point
+ number. Typically, this is useful for native ports, where the actual format
+ is irrelevant, since no conversions will be taking place. */
+
+#include "floatformat.h" /* For struct floatformat */
+
+/* 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 void floatformat_to_doublest (const struct floatformat *,
+ const void *in, DOUBLEST *out);
+extern void floatformat_from_doublest (const struct floatformat *,
+ const DOUBLEST *in, void *out);
+
+extern int floatformat_is_negative (const struct floatformat *, char *);
+extern int floatformat_is_nan (const struct floatformat *, char *);
+extern char *floatformat_mantissa (const struct floatformat *, char *);
+
+/* These functions have been replaced by extract_typed_floating and
+ store_typed_floating.
+
+ Most calls are passing in TYPE_LENGTH (TYPE) so can be changed to
+ just pass the TYPE. The remainder pass in the length of a
+ register, those calls should instead pass in the floating point
+ type that corresponds to that length. */
+
+extern DOUBLEST deprecated_extract_floating (const void *addr, int len);
+extern void deprecated_store_floating (void *addr, int len, DOUBLEST val);
+
+/* Given TYPE, return its floatformat. TYPE_FLOATFORMAT() may return
+ NULL. type_floatformat() detects that and returns a floatformat
+ based on the type size when FLOATFORMAT is NULL. */
+
+const struct floatformat *floatformat_from_type (const struct type *type);
+
+extern DOUBLEST extract_typed_floating (const void *addr,
+ const struct type *type);
+extern void store_typed_floating (void *addr, const struct type *type,
+ DOUBLEST val);
+extern void convert_typed_floating (const void *from,
+ const struct type *from_type,
+ void *to, const struct type *to_type);
+
+#endif
diff --git a/contrib/gdb/gdb/dpx2-nat.c b/contrib/gdb/gdb/dpx2-nat.c
new file mode 100644
index 0000000..488c06a
--- /dev/null
+++ b/contrib/gdb/gdb/dpx2-nat.c
@@ -0,0 +1,83 @@
+/* DPX2 host interface.
+ Copyright 1988, 1989, 1991, 1993, 1995, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_string.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <sys/reg.h>
+#include <sys/utsname.h>
+
+
+/* This table must line up with REGISTER_NAME in "m68k-tdep.c". */
+/* symbols like 'A0' come from <sys/reg.h> */
+static int regmap[] =
+{
+ R0, R1, R2, R3, R4, R5, R6, R7,
+ A0, A1, A2, A3, A4, A5, A6, SP,
+ PS, PC,
+ FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7,
+ FP_CR, FP_SR, FP_IAR
+};
+
+/* blockend is the value of u.u_ar0, and points to the
+ * place where D0 is stored
+ */
+
+int
+dpx2_register_u_addr (int blockend, int regnum)
+{
+ if (regnum < FP0_REGNUM)
+ return (blockend + 4 * regmap[regnum]);
+ else
+ return (int) &(((struct user *) 0)->u_fpstate[regmap[regnum]]);
+}
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values.
+ Unfortunately this is not provided in the system header files.
+ To make matters worse, this value also differs between
+ the dpx/2200 and dpx/2300 models and nlist is not available on the dpx2.
+ We use utsname() to decide on which model we are running.
+ FIXME: This breaks cross examination of core files (it would not be hard
+ to check whether u.u_ar0 is between 0x7fff5000 and 0x7fffc000 and if so
+ use 0x7fff5000 and if not use 0x7fffc000. FIXME). */
+
+#define KERNEL_U_ADDR_200 0x7fff5000
+#define KERNEL_U_ADDR_300 0x7fffc000
+
+CORE_ADDR kernel_u_addr;
+
+void
+_initialize_dpx2_nat (void)
+{
+ struct utsname uts;
+
+ if (uname (&uts) == 0 && strcmp (uts.machine, "DPX/2200") == 0)
+ kernel_u_addr = KERNEL_U_ADDR_200;
+ else
+ kernel_u_addr = KERNEL_U_ADDR_300;
+}
diff --git a/contrib/gdb/gdb/dsrec.c b/contrib/gdb/gdb/dsrec.c
new file mode 100644
index 0000000..1422600
--- /dev/null
+++ b/contrib/gdb/gdb/dsrec.c
@@ -0,0 +1,313 @@
+/* S-record download support for GDB, the GNU debugger.
+ Copyright 1995, 1996, 1997, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "srec.h"
+#include <time.h>
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+extern void report_transfer_performance (unsigned long, time_t, time_t);
+
+extern int remote_debug;
+
+static int make_srec (char *srec, CORE_ADDR targ_addr, bfd * abfd,
+ asection * sect, int sectoff, int *maxrecsize,
+ int flags);
+
+/* Download an executable by converting it to S records. DESC is a
+ `struct serial *' to send the data to. FILE is the name of the
+ file to be loaded. LOAD_OFFSET is the offset into memory to load
+ data into. It is usually specified by the user and is useful with
+ the a.out file format. MAXRECSIZE is the length in chars of the
+ largest S-record the host can accomodate. This is measured from
+ the starting `S' to the last char of the checksum. FLAGS is
+ various random flags, and HASHMARK is non-zero to cause a `#' to be
+ printed out for each record loaded. WAITACK, if non-NULL, is a
+ function that waits for an acknowledgement after each S-record, and
+ returns non-zero if the ack is read correctly. */
+
+void
+load_srec (struct serial *desc, const char *file, bfd_vma load_offset,
+ int maxrecsize,
+ int flags, int hashmark, int (*waitack) (void))
+{
+ bfd *abfd;
+ asection *s;
+ char *srec;
+ int i;
+ int reclen;
+ time_t start_time, end_time;
+ unsigned long data_count = 0;
+
+ srec = (char *) alloca (maxrecsize + 1);
+
+ 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;
+ }
+
+ start_time = time (NULL);
+
+ /* Write a type 0 header record. no data for a type 0, and there
+ is no data, so len is 0. */
+
+ reclen = maxrecsize;
+ make_srec (srec, 0, NULL, (asection *) 1, 0, &reclen, flags);
+ if (remote_debug)
+ {
+ srec[reclen] = '\0';
+ puts_debug ("sent -->", srec, "<--");
+ }
+ serial_write (desc, srec, reclen);
+
+ for (s = abfd->sections; s; s = s->next)
+ if (s->flags & SEC_LOAD)
+ {
+ int numbytes;
+ bfd_vma addr = bfd_get_section_vma (abfd, s) + load_offset;
+ bfd_size_type size = bfd_get_section_size_before_reloc (s);
+ char *section_name = (char *) bfd_get_section_name (abfd, s);
+ /* Both GDB and BFD have mechanisms for printing addresses.
+ In the below, GDB's is used so that the address is
+ consistent with the rest of GDB. BFD's printf_vma() could
+ have also been used. cagney 1999-09-01 */
+ printf_filtered ("%s\t: 0x%s .. 0x%s ",
+ section_name,
+ paddr (addr),
+ paddr (addr + size));
+ gdb_flush (gdb_stdout);
+
+ data_count += size;
+
+ for (i = 0; i < size; i += numbytes)
+ {
+ reclen = maxrecsize;
+ numbytes = make_srec (srec, (CORE_ADDR) (addr + i), abfd, s,
+ i, &reclen, flags);
+
+ if (remote_debug)
+ {
+ srec[reclen] = '\0';
+ puts_debug ("sent -->", srec, "<--");
+ }
+
+ /* Repeatedly send the S-record until a good
+ acknowledgement is sent back. */
+ do
+ {
+ serial_write (desc, srec, reclen);
+ if (ui_load_progress_hook)
+ if (ui_load_progress_hook (section_name, (unsigned long) i))
+ error ("Canceled the download");
+ }
+ while (waitack != NULL && !waitack ());
+
+ if (hashmark)
+ {
+ putchar_unfiltered ('#');
+ gdb_flush (gdb_stdout);
+ }
+ } /* Per-packet (or S-record) loop */
+
+ if (ui_load_progress_hook)
+ if (ui_load_progress_hook (section_name, (unsigned long) i))
+ error ("Canceled the download");
+ putchar_unfiltered ('\n');
+ }
+
+ if (hashmark)
+ putchar_unfiltered ('\n');
+
+ end_time = time (NULL);
+
+ /* Write a terminator record. */
+
+ reclen = maxrecsize;
+ make_srec (srec, abfd->start_address, NULL, NULL, 0, &reclen, flags);
+
+ if (remote_debug)
+ {
+ srec[reclen] = '\0';
+ puts_debug ("sent -->", srec, "<--");
+ }
+
+ serial_write (desc, srec, reclen);
+
+ /* Some monitors need these to wake up properly. (Which ones? -sts) */
+ serial_write (desc, "\r\r", 2);
+ if (remote_debug)
+ puts_debug ("sent -->", "\r\r", "<---");
+
+ serial_flush_input (desc);
+
+ report_transfer_performance (data_count, start_time, end_time);
+}
+
+/*
+ * 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<type><length><address><data><checksum>
+ *
+ * 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
+make_srec (char *srec, CORE_ADDR targ_addr, bfd *abfd, asection *sect,
+ int sectoff, int *maxrecsize, int flags)
+{
+ unsigned char checksum;
+ int tmp;
+ const static char hextab[] = "0123456789ABCDEF";
+ const static char data_code_table[] = "123";
+ const static char term_code_table[] = "987";
+ const static char header_code_table[] = "000";
+ char const *code_table;
+ int addr_size;
+ int payload_size;
+ char *binbuf;
+ char *p;
+
+ if (sect)
+ {
+ tmp = flags; /* Data or header record */
+ code_table = abfd ? data_code_table : header_code_table;
+ binbuf = alloca (*maxrecsize / 2);
+ }
+ else
+ {
+ tmp = flags >> SREC_TERM_SHIFT; /* Term record */
+ code_table = term_code_table;
+ binbuf = NULL;
+ }
+
+ if ((tmp & SREC_2_BYTE_ADDR) && (targ_addr <= 0xffff))
+ addr_size = 2;
+ else if ((tmp & SREC_3_BYTE_ADDR) && (targ_addr <= 0xffffff))
+ addr_size = 3;
+ else if (tmp & SREC_4_BYTE_ADDR)
+ addr_size = 4;
+ else
+ internal_error (__FILE__, __LINE__,
+ "make_srec: Bad address (0x%s), or bad flags (0x%x).",
+ paddr (targ_addr), flags);
+
+ /* Now that we know the address size, we can figure out how much
+ data this record can hold. */
+
+ if (sect && abfd)
+ {
+ payload_size = (*maxrecsize - (1 + 1 + 2 + addr_size * 2 + 2)) / 2;
+ payload_size = min (payload_size, sect->_raw_size - sectoff);
+
+ bfd_get_section_contents (abfd, sect, binbuf, sectoff, payload_size);
+ }
+ else
+ payload_size = 0; /* Term or header packets have no payload */
+
+ /* Output the header. */
+ snprintf (srec, (*maxrecsize) + 1, "S%c%02X%0*X",
+ code_table[addr_size - 2],
+ addr_size + payload_size + 1,
+ addr_size * 2, (int) targ_addr);
+
+ /* 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;
+
+ checksum += (payload_size + addr_size + 1 /* Packet length */
+ + (targ_addr & 0xff) /* Address... */
+ + ((targ_addr >> 8) & 0xff)
+ + ((targ_addr >> 16) & 0xff)
+ + ((targ_addr >> 24) & 0xff));
+
+ /* NOTE: cagney/2003-08-10: The equation is old. Check that the
+ recent snprintf changes match that equation. */
+ gdb_assert (strlen (srec) == 1 + 1 + 2 + addr_size * 2);
+ p = srec + 1 + 1 + 2 + addr_size * 2;
+
+ /* Build the Srecord. */
+ for (tmp = 0; tmp < payload_size; tmp++)
+ {
+ unsigned char k;
+
+ k = binbuf[tmp];
+ *p++ = hextab[k >> 4];
+ *p++ = hextab[k & 0xf];
+ checksum += k;
+ }
+
+ checksum = ~checksum;
+
+ *p++ = hextab[checksum >> 4];
+ *p++ = hextab[checksum & 0xf];
+ *p++ = '\r';
+
+ *maxrecsize = p - srec;
+ return payload_size;
+}
diff --git a/contrib/gdb/gdb/dummy-frame.c b/contrib/gdb/gdb/dummy-frame.c
new file mode 100644
index 0000000..3b10c51
--- /dev/null
+++ b/contrib/gdb/gdb/dummy-frame.c
@@ -0,0 +1,466 @@
+/* Code dealing with dummy stack frames, for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "dummy-frame.h"
+#include "regcache.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdb_assert.h"
+#include "frame-unwind.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+static void dummy_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id);
+
+/* Dummy frame. This saves the processor state just prior to setting
+ up the inferior function call. Older targets save the registers
+ on the target stack (but that really slows down function calls). */
+
+struct dummy_frame
+{
+ struct dummy_frame *next;
+
+ /* These values belong to the caller (the previous frame, the frame
+ that this unwinds back to). */
+ CORE_ADDR pc;
+ CORE_ADDR fp;
+ CORE_ADDR sp;
+ CORE_ADDR top;
+ struct frame_id id;
+ struct regcache *regcache;
+
+ /* Address range of the call dummy code. Look for PC in the range
+ [LO..HI) (after allowing for DECR_PC_AFTER_BREAK). */
+ CORE_ADDR call_lo;
+ CORE_ADDR call_hi;
+};
+
+static struct dummy_frame *dummy_frame_stack = NULL;
+
+/* Function: find_dummy_frame(pc, fp, sp)
+
+ Search the stack of dummy frames for one matching the given PC and
+ FP/SP. Unlike pc_in_dummy_frame(), this function doesn't need to
+ adjust for DECR_PC_AFTER_BREAK. This is because it is only legal
+ to call this function after the PC has been adjusted. */
+
+static struct dummy_frame *
+find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
+{
+ struct dummy_frame *dummyframe;
+
+ for (dummyframe = dummy_frame_stack; dummyframe != NULL;
+ dummyframe = dummyframe->next)
+ {
+ /* Does the PC fall within the dummy frame's breakpoint
+ instruction. If not, discard this one. */
+ if (!(pc >= dummyframe->call_lo && pc < dummyframe->call_hi))
+ continue;
+ /* Does the FP match? */
+ if (dummyframe->top != 0)
+ {
+ /* If the target architecture explicitly saved the
+ top-of-stack before the inferior function call, assume
+ that that same architecture will always pass in an FP
+ (frame base) value that eactly matches that saved TOS.
+ Don't check the saved SP and SP as they can lead to false
+ hits. */
+ if (fp != dummyframe->top)
+ continue;
+ }
+ else
+ {
+ /* An older target that hasn't explicitly or implicitly
+ saved the dummy frame's top-of-stack. Try matching the
+ FP against the saved SP and FP. NOTE: If you're trying
+ to fix a problem with GDB not correctly finding a dummy
+ frame, check the comments that go with FRAME_ALIGN() and
+ UNWIND_DUMMY_ID(). */
+ if (fp != dummyframe->fp && fp != dummyframe->sp)
+ continue;
+ }
+ /* The FP matches this dummy frame. */
+ return dummyframe;
+ }
+
+ return NULL;
+}
+
+struct regcache *
+deprecated_find_dummy_frame_regcache (CORE_ADDR pc, CORE_ADDR fp)
+{
+ struct dummy_frame *dummy = find_dummy_frame (pc, fp);
+ if (dummy != NULL)
+ return dummy->regcache;
+ else
+ return NULL;
+}
+
+char *
+deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
+{
+ struct regcache *regcache = deprecated_find_dummy_frame_regcache (pc, fp);
+ if (regcache == NULL)
+ return NULL;
+ return deprecated_grub_regcache_for_registers (regcache);
+}
+
+/* Function: pc_in_call_dummy (pc, sp, fp)
+
+ Return true if the PC falls in a dummy frame created by gdb for an
+ inferior call. The code below which allows DECR_PC_AFTER_BREAK is
+ for infrun.c, which may give the function a PC without that
+ subtracted out. */
+
+int
+generic_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp)
+{
+ return pc_in_dummy_frame (pc);
+}
+
+/* Return non-zero if the PC falls in a dummy frame.
+
+ The code below which allows DECR_PC_AFTER_BREAK is for infrun.c,
+ which may give the function a PC without that subtracted out.
+
+ FIXME: cagney/2002-11-23: This is silly. Surely "infrun.c" can
+ figure out what the real PC (as in the resume address) is BEFORE
+ calling this function (Oh, and I'm not even sure that this function
+ is called with an decremented PC, the call to pc_in_call_dummy() in
+ that file is conditional on
+ !DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET_P yet generic dummy
+ targets set DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET. True?). */
+
+int
+pc_in_dummy_frame (CORE_ADDR pc)
+{
+ struct dummy_frame *dummyframe;
+ for (dummyframe = dummy_frame_stack;
+ dummyframe != NULL;
+ dummyframe = dummyframe->next)
+ {
+ if ((pc >= dummyframe->call_lo)
+ && (pc < dummyframe->call_hi + DECR_PC_AFTER_BREAK))
+ return 1;
+ }
+ return 0;
+}
+
+/* Function: read_register_dummy
+ Find a saved register from before GDB calls a function in the inferior */
+
+CORE_ADDR
+deprecated_read_register_dummy (CORE_ADDR pc, CORE_ADDR fp, int regno)
+{
+ struct regcache *dummy_regs = deprecated_find_dummy_frame_regcache (pc, fp);
+
+ if (dummy_regs)
+ {
+ /* NOTE: cagney/2002-08-12: Replaced a call to
+ regcache_raw_read_as_address() with a call to
+ regcache_cooked_read_unsigned(). The old, ...as_address
+ function was eventually calling extract_unsigned_integer (nee
+ extract_address) to unpack the registers value. The below is
+ doing an unsigned extract so that it is functionally
+ equivalent. The read needs to be cooked as, otherwise, it
+ will never correctly return the value of a register in the
+ [NUM_REGS .. NUM_REGS+NUM_PSEUDO_REGS) range. */
+ ULONGEST val;
+ regcache_cooked_read_unsigned (dummy_regs, regno, &val);
+ return val;
+ }
+ else
+ return 0;
+}
+
+/* Save all the registers on the dummy frame stack. Most ports save the
+ registers on the target stack. This results in lots of unnecessary memory
+ references, which are slow when debugging via a serial line. Instead, we
+ save all the registers internally, and never write them to the stack. The
+ registers get restored when the called function returns to the entry point,
+ where a breakpoint is laying in wait. */
+
+void
+generic_push_dummy_frame (void)
+{
+ struct dummy_frame *dummy_frame;
+ CORE_ADDR fp = get_frame_base (get_current_frame ());
+
+ /* check to see if there are stale dummy frames,
+ perhaps left over from when a longjump took us out of a
+ function that was called by the debugger */
+
+ dummy_frame = dummy_frame_stack;
+ while (dummy_frame)
+ if (INNER_THAN (dummy_frame->fp, fp)) /* stale -- destroy! */
+ {
+ dummy_frame_stack = dummy_frame->next;
+ regcache_xfree (dummy_frame->regcache);
+ xfree (dummy_frame);
+ dummy_frame = dummy_frame_stack;
+ }
+ else
+ dummy_frame = dummy_frame->next;
+
+ dummy_frame = xmalloc (sizeof (struct dummy_frame));
+ dummy_frame->regcache = regcache_xmalloc (current_gdbarch);
+
+ dummy_frame->pc = read_pc ();
+ dummy_frame->sp = read_sp ();
+ dummy_frame->top = 0;
+ dummy_frame->fp = fp;
+ dummy_frame->id = get_frame_id (get_current_frame ());
+ regcache_cpy (dummy_frame->regcache, current_regcache);
+ dummy_frame->next = dummy_frame_stack;
+ dummy_frame_stack = dummy_frame;
+}
+
+void
+generic_save_dummy_frame_tos (CORE_ADDR sp)
+{
+ dummy_frame_stack->top = sp;
+}
+
+/* Record the upper/lower bounds on the address of the call dummy. */
+
+void
+generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi)
+{
+ dummy_frame_stack->call_lo = lo;
+ dummy_frame_stack->call_hi = hi;
+}
+
+/* Restore the machine state from either the saved dummy stack or a
+ real stack frame. */
+
+void
+generic_pop_current_frame (void (*popper) (struct frame_info * frame))
+{
+ struct frame_info *frame = get_current_frame ();
+ if (get_frame_type (frame) == DUMMY_FRAME)
+ /* NOTE: cagney/2002-22-23: Does this ever occure? Surely a dummy
+ frame will have already been poped by the "infrun.c" code. */
+ generic_pop_dummy_frame ();
+ else
+ (*popper) (frame);
+}
+
+/* Discard the innermost dummy frame from the dummy frame stack
+ (passed in as a parameter). */
+
+static void
+discard_innermost_dummy (struct dummy_frame **stack)
+{
+ struct dummy_frame *tbd = (*stack);
+ (*stack) = (*stack)->next;
+ regcache_xfree (tbd->regcache);
+ xfree (tbd);
+}
+
+void
+generic_pop_dummy_frame (void)
+{
+ struct dummy_frame *dummy_frame = dummy_frame_stack;
+
+ /* FIXME: what if the first frame isn't the right one, eg..
+ because one call-by-hand function has done a longjmp into another one? */
+
+ if (!dummy_frame)
+ error ("Can't pop dummy frame!");
+ regcache_cpy (current_regcache, dummy_frame->regcache);
+ flush_cached_frames ();
+
+ discard_innermost_dummy (&dummy_frame_stack);
+}
+
+/* Given a call-dummy dummy-frame, return the registers. Here the
+ register value is taken from the local copy of the register buffer. */
+
+static void
+dummy_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimized,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnum, void *bufferp)
+{
+ struct dummy_frame *dummy;
+ struct frame_id id;
+
+ /* Call the ID method which, if at all possible, will set the
+ prologue cache. */
+ dummy_frame_this_id (next_frame, this_prologue_cache, &id);
+ dummy = (*this_prologue_cache);
+ gdb_assert (dummy != NULL);
+
+ /* Describe the register's location. Generic dummy frames always
+ have the register value in an ``expression''. */
+ *optimized = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnum = -1;
+
+ /* If needed, find and return the value of the register. */
+ if (bufferp != NULL)
+ {
+ /* Return the actual value. */
+ /* Use the regcache_cooked_read() method so that it, on the fly,
+ constructs either a raw or pseudo register from the raw
+ register cache. */
+ regcache_cooked_read (dummy->regcache, regnum, bufferp);
+ }
+}
+
+/* Assuming that THIS frame is a dummy (remember, the NEXT and not
+ THIS frame is passed in), return the ID of THIS frame. That ID is
+ determined by examining the NEXT frame's unwound registers using
+ the method unwind_dummy_id(). As a side effect, THIS dummy frame's
+ dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */
+
+static void
+dummy_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct dummy_frame *dummy = (*this_prologue_cache);
+ if (dummy != NULL)
+ {
+ (*this_id) = dummy->id;
+ return;
+ }
+ /* When unwinding a normal frame, the stack structure is determined
+ by analyzing the frame's function's code (be it using brute force
+ prologue analysis, or the dwarf2 CFI). In the case of a dummy
+ frame, that simply isn't possible. The The PC is either the
+ program entry point, or some random address on the stack. Trying
+ to use that PC to apply standard frame ID unwind techniques is
+ just asking for trouble. */
+ if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+ {
+ /* Use an architecture specific method to extract the prev's
+ dummy ID from the next frame. Note that this method uses
+ frame_register_unwind to obtain the register values needed to
+ determine the dummy frame's ID. */
+ (*this_id) = gdbarch_unwind_dummy_id (current_gdbarch, next_frame);
+ }
+ else if (frame_relative_level (next_frame) < 0)
+ {
+ /* We're unwinding a sentinel frame, the PC of which is pointing
+ at a stack dummy. Fake up the dummy frame's ID using the
+ same sequence as is found a traditional unwinder. Once all
+ architectures supply the unwind_dummy_id method, this code
+ can go away. */
+ (*this_id) = frame_id_build (deprecated_read_fp (), read_pc ());
+ }
+ else if (legacy_frame_p (current_gdbarch)
+ && get_prev_frame (next_frame))
+ {
+ /* Things are looking seriously grim! Assume that the legacy
+ get_prev_frame code has already created THIS frame and linked
+ it in to the frame chain (a pretty bold assumption), extract
+ the ID from THIS base / pc. */
+ (*this_id) = frame_id_build (get_frame_base (get_prev_frame (next_frame)),
+ get_frame_pc (get_prev_frame (next_frame)));
+ }
+ else
+ {
+ /* Ouch! We're not trying to find the innermost frame's ID yet
+ we're trying to unwind to a dummy. The architecture must
+ provide the unwind_dummy_id() method. Abandon the unwind
+ process but only after first warning the user. */
+ internal_warning (__FILE__, __LINE__,
+ "Missing unwind_dummy_id architecture method");
+ (*this_id) = null_frame_id;
+ return;
+ }
+ (*this_prologue_cache) = find_dummy_frame ((*this_id).code_addr,
+ (*this_id).stack_addr);
+}
+
+static struct frame_unwind dummy_frame_unwind =
+{
+ DUMMY_FRAME,
+ dummy_frame_this_id,
+ dummy_frame_prev_register
+};
+
+const struct frame_unwind *
+dummy_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
+ ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
+ : pc_in_dummy_frame (pc))
+ return &dummy_frame_unwind;
+ else
+ return NULL;
+}
+
+static void
+fprint_dummy_frames (struct ui_file *file)
+{
+ struct dummy_frame *s;
+ for (s = dummy_frame_stack; s != NULL; s = s->next)
+ {
+ gdb_print_host_address (s, file);
+ fprintf_unfiltered (file, ":");
+ fprintf_unfiltered (file, " pc=0x%s", paddr (s->pc));
+ fprintf_unfiltered (file, " fp=0x%s", paddr (s->fp));
+ fprintf_unfiltered (file, " sp=0x%s", paddr (s->sp));
+ fprintf_unfiltered (file, " top=0x%s", paddr (s->top));
+ fprintf_unfiltered (file, " id=");
+ fprint_frame_id (file, s->id);
+ fprintf_unfiltered (file, " call_lo=0x%s", paddr (s->call_lo));
+ fprintf_unfiltered (file, " call_hi=0x%s", paddr (s->call_hi));
+ fprintf_unfiltered (file, "\n");
+ }
+}
+
+static void
+maintenance_print_dummy_frames (char *args, int from_tty)
+{
+ if (args == NULL)
+ fprint_dummy_frames (gdb_stdout);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print dummy-frames");
+ fprint_dummy_frames (file);
+ ui_file_delete (file);
+ }
+}
+
+extern void _initialize_dummy_frame (void);
+
+void
+_initialize_dummy_frame (void)
+{
+ add_cmd ("dummy-frames", class_maintenance, maintenance_print_dummy_frames,
+ "Print the contents of the internal dummy-frame stack.",
+ &maintenanceprintlist);
+
+}
diff --git a/contrib/gdb/gdb/dummy-frame.h b/contrib/gdb/gdb/dummy-frame.h
new file mode 100644
index 0000000..cde9eb7
--- /dev/null
+++ b/contrib/gdb/gdb/dummy-frame.h
@@ -0,0 +1,86 @@
+/* Code dealing with dummy stack frames, for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (DUMMY_FRAME_H)
+#define DUMMY_FRAME_H 1
+
+struct frame_info;
+struct regcache;
+struct frame_unwind;
+struct frame_id;
+
+/* GENERIC DUMMY FRAMES
+
+ The following code serves to maintain the dummy stack frames for
+ inferior function calls (ie. when gdb calls into the inferior via
+ call_function_by_hand). This code saves the machine state before
+ the call in host memory, so we must maintain an independent stack
+ and keep it consistant etc. I am attempting to make this code
+ generic enough to be used by many targets.
+
+ The cheapest and most generic way to do CALL_DUMMY on a new target
+ is probably to define CALL_DUMMY to be empty,
+ DEPRECATED_CALL_DUMMY_LENGTH to zero, and CALL_DUMMY_LOCATION to
+ AT_ENTRY. Then you must remember to define PUSH_RETURN_ADDRESS,
+ because no call instruction will be being executed by the target.
+ Also DEPRECATED_FRAME_CHAIN_VALID as
+ generic_{file,func}_frame_chain_valid and do not set
+ DEPRECATED_FIX_CALL_DUMMY. */
+
+/* If the PC falls in a dummy frame, return a dummy frame
+ unwinder. */
+
+extern const struct frame_unwind *dummy_frame_sniffer (struct frame_info *next_frame);
+
+/* Does the PC fall in a dummy frame?
+
+ This function is used by "frame.c" when creating a new `struct
+ frame_info'.
+
+ Note that there is also very similar code in breakpoint.c (where
+ the bpstat stop reason is computed). It is looking for a PC
+ falling on a dummy_frame breakpoint. Perhaphs this, and that code
+ should be combined?
+
+ Architecture dependant code, that has access to a frame, should not
+ use this function. Instead (get_frame_type() == DUMMY_FRAME)
+ should be used.
+
+ Hmm, but what about threads? When the dummy-frame code tries to
+ relocate a dummy frame's saved registers it definitly needs to
+ differentiate between threads (otherwize it will do things like
+ clean-up the wrong threads frames). However, when just trying to
+ identify a dummy-frame that shouldn't matter. The wost that can
+ happen is that a thread is marked as sitting in a dummy frame when,
+ in reality, its corrupted its stack, to the point that a PC is
+ pointing into a dummy frame. */
+
+extern int pc_in_dummy_frame (CORE_ADDR pc);
+
+/* Return the regcache that belongs to the dummy-frame identifed by PC
+ and FP, or NULL if no such frame exists. */
+/* FIXME: cagney/2002-11-08: The function only exists because of
+ deprecated_generic_get_saved_register. Eliminate that function and
+ this, to, can go. */
+
+extern struct regcache *deprecated_find_dummy_frame_regcache (CORE_ADDR pc,
+ CORE_ADDR fp);
+#endif /* !defined (DUMMY_FRAME_H) */
diff --git a/contrib/gdb/gdb/dve3900-rom.c b/contrib/gdb/gdb/dve3900-rom.c
new file mode 100644
index 0000000..fe2fced
--- /dev/null
+++ b/contrib/gdb/gdb/dve3900-rom.c
@@ -0,0 +1,1069 @@
+/* Remote debugging interface for Densan DVE-R3900 ROM monitor for
+ GDB, the GNU debugger.
+ Copyright 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "inferior.h"
+#include "command.h"
+#include "gdb_string.h"
+#include <time.h>
+#include "regcache.h"
+#include "mips-tdep.h"
+
+/* Type of function passed to bfd_map_over_sections. */
+
+typedef void (*section_map_func) (bfd * abfd, asection * sect, void *obj);
+
+/* Packet escape character used by Densan monitor. */
+
+#define PESC 0xdc
+
+/* Maximum packet size. This is actually smaller than necessary
+ just to be safe. */
+
+#define MAXPSIZE 1024
+
+/* External functions. */
+
+extern void report_transfer_performance (unsigned long, time_t, time_t);
+
+/* Certain registers are "bitmapped", in that the monitor can only display
+ them or let the user modify them as a series of named bitfields.
+ This structure describes a field in a bitmapped register. */
+
+struct bit_field
+ {
+ char *prefix; /* string appearing before the value */
+ char *suffix; /* string appearing after the value */
+ char *user_name; /* name used by human when entering field value */
+ int length; /* number of bits in the field */
+ int start; /* starting (least significant) bit number of field */
+ };
+
+/* Local functions for register manipulation. */
+
+static void r3900_supply_register (char *regname, int regnamelen,
+ char *val, int vallen);
+static void fetch_bad_vaddr (void);
+static unsigned long fetch_fields (struct bit_field *bf);
+static void fetch_bitmapped_register (int regno, struct bit_field *bf);
+static void r3900_fetch_registers (int regno);
+static void store_bitmapped_register (int regno, struct bit_field *bf);
+static void r3900_store_registers (int regno);
+
+/* Local functions for fast binary loading. */
+
+static void write_long (char *buf, long n);
+static void write_long_le (char *buf, long n);
+static int debug_readchar (int hex);
+static void debug_write (unsigned char *buf, int buflen);
+static void ignore_packet (void);
+static void send_packet (char type, unsigned char *buf, int buflen, int seq);
+static void process_read_request (unsigned char *buf, int buflen);
+static void count_section (bfd * abfd, asection * s,
+ unsigned int *section_count);
+static void load_section (bfd * abfd, asection * s, unsigned int *data_count);
+static void r3900_load (char *filename, int from_tty);
+
+/* Miscellaneous local functions. */
+
+static void r3900_open (char *args, int from_tty);
+
+
+/* Pointers to static functions in monitor.c for fetching and storing
+ registers. We can't use these function in certain cases where the Densan
+ monitor acts perversely: for registers that it displays in bit-map
+ format, and those that can't be modified at all. In those cases
+ we have to use our own functions to fetch and store their values. */
+
+static void (*orig_monitor_fetch_registers) (int regno);
+static void (*orig_monitor_store_registers) (int regno);
+
+/* Pointer to static function in monitor. for loading programs.
+ We use this function for loading S-records via the serial link. */
+
+static void (*orig_monitor_load) (char *file, int from_tty);
+
+/* This flag is set if a fast ethernet download should be used. */
+
+static int ethernet = 0;
+
+/* 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. */
+
+static char *r3900_regnames[] =
+{
+ "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",
+
+ "S", /* PS_REGNUM */
+ "l", /* MIPS_EMBED_LO_REGNUM */
+ "h", /* MIPS_EMBED_HI_REGNUM */
+ "B", /* MIPS_EMBED_BADVADDR_REGNUM */
+ "Pcause", /* MIPS_EMBED_CAUSE_REGNUM */
+ "p" /* MIPS_EMBED_PC_REGNUM */
+};
+
+
+/* Table of register names produced by monitor's register dump command. */
+
+static struct reg_entry
+ {
+ char *name;
+ int regno;
+ }
+reg_table[] =
+{
+ {
+ "r0_zero", 0
+ }
+ ,
+ {
+ "r1_at", 1
+ }
+ ,
+ {
+ "r2_v0", 2
+ }
+ ,
+ {
+ "r3_v1", 3
+ }
+ ,
+ {
+ "r4_a0", 4
+ }
+ ,
+ {
+ "r5_a1", 5
+ }
+ ,
+ {
+ "r6_a2", 6
+ }
+ ,
+ {
+ "r7_a3", 7
+ }
+ ,
+ {
+ "r8_t0", 8
+ }
+ ,
+ {
+ "r9_t1", 9
+ }
+ ,
+ {
+ "r10_t2", 10
+ }
+ ,
+ {
+ "r11_t3", 11
+ }
+ ,
+ {
+ "r12_t4", 12
+ }
+ ,
+ {
+ "r13_t5", 13
+ }
+ ,
+ {
+ "r14_t6", 14
+ }
+ ,
+ {
+ "r15_t7", 15
+ }
+ ,
+ {
+ "r16_s0", 16
+ }
+ ,
+ {
+ "r17_s1", 17
+ }
+ ,
+ {
+ "r18_s2", 18
+ }
+ ,
+ {
+ "r19_s3", 19
+ }
+ ,
+ {
+ "r20_s4", 20
+ }
+ ,
+ {
+ "r21_s5", 21
+ }
+ ,
+ {
+ "r22_s6", 22
+ }
+ ,
+ {
+ "r23_s7", 23
+ }
+ ,
+ {
+ "r24_t8", 24
+ }
+ ,
+ {
+ "r25_t9", 25
+ }
+ ,
+ {
+ "r26_k0", 26
+ }
+ ,
+ {
+ "r27_k1", 27
+ }
+ ,
+ {
+ "r28_gp", 28
+ }
+ ,
+ {
+ "r29_sp", 29
+ }
+ ,
+ {
+ "r30_fp", 30
+ }
+ ,
+ {
+ "r31_ra", 31
+ }
+ ,
+ {
+ "HI", MIPS_EMBED_HI_REGNUM
+ }
+ ,
+ {
+ "LO", MIPS_EMBED_LO_REGNUM
+ }
+ ,
+ {
+ "PC", MIPS_EMBED_PC_REGNUM
+ }
+ ,
+ {
+ "BadV", MIPS_EMBED_BADVADDR_REGNUM
+ }
+ ,
+ {
+ NULL, 0
+ }
+};
+
+
+/* The monitor displays the cache register along with the status register,
+ as if they were a single register. So when we want to fetch the
+ status register, parse but otherwise ignore the fields of the
+ cache register that the monitor displays. Register fields that should
+ be ignored have a length of zero in the tables below. */
+
+static struct bit_field status_fields[] =
+{
+ /* Status register portion */
+ {"SR[<CU=", " ", "cu", 4, 28},
+ {"RE=", " ", "re", 1, 25},
+ {"BEV=", " ", "bev", 1, 22},
+ {"TS=", " ", "ts", 1, 21},
+ {"Nmi=", " ", "nmi", 1, 20},
+ {"INT=", " ", "int", 6, 10},
+ {"SW=", ">]", "sw", 2, 8},
+ {"[<KUO=", " ", "kuo", 1, 5},
+ {"IEO=", " ", "ieo", 1, 4},
+ {"KUP=", " ", "kup", 1, 3},
+ {"IEP=", " ", "iep", 1, 2},
+ {"KUC=", " ", "kuc", 1, 1},
+ {"IEC=", ">]", "iec", 1, 0},
+
+ /* Cache register portion (dummy for parsing only) */
+ {"CR[<IalO=", " ", "ialo", 0, 13},
+ {"DalO=", " ", "dalo", 0, 12},
+ {"IalP=", " ", "ialp", 0, 11},
+ {"DalP=", " ", "dalp", 0, 10},
+ {"IalC=", " ", "ialc", 0, 9},
+ {"DalC=", ">] ", "dalc", 0, 8},
+
+ {NULL, NULL, 0, 0} /* end of table marker */
+};
+
+
+#if 0 /* FIXME: Enable when we add support for modifying cache register. */
+static struct bit_field cache_fields[] =
+{
+ /* Status register portion (dummy for parsing only) */
+ {"SR[<CU=", " ", "cu", 0, 28},
+ {"RE=", " ", "re", 0, 25},
+ {"BEV=", " ", "bev", 0, 22},
+ {"TS=", " ", "ts", 0, 21},
+ {"Nmi=", " ", "nmi", 0, 20},
+ {"INT=", " ", "int", 0, 10},
+ {"SW=", ">]", "sw", 0, 8},
+ {"[<KUO=", " ", "kuo", 0, 5},
+ {"IEO=", " ", "ieo", 0, 4},
+ {"KUP=", " ", "kup", 0, 3},
+ {"IEP=", " ", "iep", 0, 2},
+ {"KUC=", " ", "kuc", 0, 1},
+ {"IEC=", ">]", "iec", 0, 0},
+
+ /* Cache register portion */
+ {"CR[<IalO=", " ", "ialo", 1, 13},
+ {"DalO=", " ", "dalo", 1, 12},
+ {"IalP=", " ", "ialp", 1, 11},
+ {"DalP=", " ", "dalp", 1, 10},
+ {"IalC=", " ", "ialc", 1, 9},
+ {"DalC=", ">] ", "dalc", 1, 8},
+
+ {NULL, NULL, NULL, 0, 0} /* end of table marker */
+};
+#endif
+
+
+static struct bit_field cause_fields[] =
+{
+ {"<BD=", " ", "bd", 1, 31},
+ {"CE=", " ", "ce", 2, 28},
+ {"IP=", " ", "ip", 6, 10},
+ {"SW=", " ", "sw", 2, 8},
+ {"EC=", ">]", "ec", 5, 2},
+
+ {NULL, NULL, NULL, 0, 0} /* end of table marker */
+};
+
+
+/* The monitor prints register values in the form
+
+ regname = xxxx xxxx
+
+ We look up the register name in a table, and remove the embedded space in
+ the hex value before passing it to monitor_supply_register. */
+
+static void
+r3900_supply_register (char *regname, int regnamelen, char *val, int vallen)
+{
+ int regno = -1;
+ int i;
+ char valbuf[10];
+ char *p;
+
+ /* Perform some sanity checks on the register name and value. */
+ if (regnamelen < 2 || regnamelen > 7 || vallen != 9)
+ return;
+
+ /* Look up the register name. */
+ for (i = 0; reg_table[i].name != NULL; i++)
+ {
+ int rlen = strlen (reg_table[i].name);
+ if (rlen == regnamelen && strncmp (regname, reg_table[i].name, rlen) == 0)
+ {
+ regno = reg_table[i].regno;
+ break;
+ }
+ }
+ if (regno == -1)
+ return;
+
+ /* Copy the hex value to a buffer and eliminate the embedded space. */
+ for (i = 0, p = valbuf; i < vallen; i++)
+ if (val[i] != ' ')
+ *p++ = val[i];
+ *p = '\0';
+
+ monitor_supply_register (regno, valbuf);
+}
+
+
+/* Fetch the BadVaddr register. Unlike the other registers, this
+ one can't be modified, and the monitor won't even prompt to let
+ you modify it. */
+
+static void
+fetch_bad_vaddr (void)
+{
+ char buf[20];
+
+ monitor_printf ("xB\r");
+ monitor_expect ("BadV=", NULL, 0);
+ monitor_expect_prompt (buf, sizeof (buf));
+ monitor_supply_register (mips_regnum (current_gdbarch)->badvaddr, buf);
+}
+
+
+/* Read a series of bit fields from the monitor, and return their
+ combined binary value. */
+
+static unsigned long
+fetch_fields (struct bit_field *bf)
+{
+ char buf[20];
+ unsigned long val = 0;
+ unsigned long bits;
+
+ for (; bf->prefix != NULL; bf++)
+ {
+ monitor_expect (bf->prefix, NULL, 0); /* get prefix */
+ monitor_expect (bf->suffix, buf, sizeof (buf)); /* hex value, suffix */
+ if (bf->length != 0)
+ {
+ bits = strtoul (buf, NULL, 16); /* get field value */
+ bits &= ((1 << bf->length) - 1); /* mask out useless bits */
+ val |= bits << bf->start; /* insert into register */
+ }
+
+ }
+
+ return val;
+}
+
+
+static void
+fetch_bitmapped_register (int regno, struct bit_field *bf)
+{
+ unsigned long val;
+ unsigned char regbuf[MAX_REGISTER_SIZE];
+ char *regname = NULL;
+
+ if (regno >= sizeof (r3900_regnames) / sizeof (r3900_regnames[0]))
+ internal_error (__FILE__, __LINE__,
+ "fetch_bitmapped_register: regno out of bounds");
+ else
+ regname = r3900_regnames[regno];
+
+ monitor_printf ("x%s\r", regname);
+ val = fetch_fields (bf);
+ monitor_printf (".\r");
+ monitor_expect_prompt (NULL, 0);
+
+ /* supply register stores in target byte order, so swap here */
+
+ store_unsigned_integer (regbuf, DEPRECATED_REGISTER_RAW_SIZE (regno), val);
+ supply_register (regno, regbuf);
+
+}
+
+
+/* Fetch all registers (if regno is -1), or one register from the
+ monitor. For most registers, we can use the generic monitor_
+ monitor_fetch_registers function. But others are displayed in
+ a very unusual fashion by the monitor, and must be handled specially. */
+
+static void
+r3900_fetch_registers (int regno)
+{
+ if (regno == mips_regnum (current_gdbarch)->badvaddr)
+ fetch_bad_vaddr ();
+ else if (regno == PS_REGNUM)
+ fetch_bitmapped_register (PS_REGNUM, status_fields);
+ else if (regno == mips_regnum (current_gdbarch)->cause)
+ fetch_bitmapped_register (mips_regnum (current_gdbarch)->cause,
+ cause_fields);
+ else
+ orig_monitor_fetch_registers (regno);
+}
+
+
+/* Write the new value of the bitmapped register to the monitor. */
+
+static void
+store_bitmapped_register (int regno, struct bit_field *bf)
+{
+ unsigned long oldval, newval;
+ char *regname = NULL;
+
+ if (regno >= sizeof (r3900_regnames) / sizeof (r3900_regnames[0]))
+ internal_error (__FILE__, __LINE__,
+ "fetch_bitmapped_register: regno out of bounds");
+ else
+ regname = r3900_regnames[regno];
+
+ /* Fetch the current value of the register. */
+ monitor_printf ("x%s\r", regname);
+ oldval = fetch_fields (bf);
+ newval = read_register (regno);
+
+ /* To save time, write just the fields that have changed. */
+ for (; bf->prefix != NULL; bf++)
+ {
+ if (bf->length != 0)
+ {
+ unsigned long oldbits, newbits, mask;
+
+ mask = (1 << bf->length) - 1;
+ oldbits = (oldval >> bf->start) & mask;
+ newbits = (newval >> bf->start) & mask;
+ if (oldbits != newbits)
+ monitor_printf ("%s %lx ", bf->user_name, newbits);
+ }
+ }
+
+ monitor_printf (".\r");
+ monitor_expect_prompt (NULL, 0);
+}
+
+
+static void
+r3900_store_registers (int regno)
+{
+ if (regno == PS_REGNUM)
+ store_bitmapped_register (PS_REGNUM, status_fields);
+ else if (regno == mips_regnum (current_gdbarch)->cause)
+ store_bitmapped_register (mips_regnum (current_gdbarch)->cause,
+ cause_fields);
+ else
+ orig_monitor_store_registers (regno);
+}
+
+
+/* Write a 4-byte integer to the buffer in big-endian order. */
+
+static void
+write_long (char *buf, long n)
+{
+ buf[0] = (n >> 24) & 0xff;
+ buf[1] = (n >> 16) & 0xff;
+ buf[2] = (n >> 8) & 0xff;
+ buf[3] = n & 0xff;
+}
+
+
+/* Write a 4-byte integer to the buffer in little-endian order. */
+
+static void
+write_long_le (char *buf, long n)
+{
+ buf[0] = n & 0xff;
+ buf[1] = (n >> 8) & 0xff;
+ buf[2] = (n >> 16) & 0xff;
+ buf[3] = (n >> 24) & 0xff;
+}
+
+
+/* Read a character from the monitor. If remote debugging is on,
+ print the received character. If HEX is non-zero, print the
+ character in hexadecimal; otherwise, print it in ASCII. */
+
+static int
+debug_readchar (int hex)
+{
+ char buf[10];
+ int c = monitor_readchar ();
+
+ if (remote_debug > 0)
+ {
+ if (hex)
+ sprintf (buf, "[%02x]", c & 0xff);
+ else if (c == '\0')
+ strcpy (buf, "\\0");
+ else
+ {
+ buf[0] = c;
+ buf[1] = '\0';
+ }
+ puts_debug ("Read -->", buf, "<--");
+ }
+ return c;
+}
+
+
+/* Send a buffer of characters to the monitor. If remote debugging is on,
+ print the sent buffer in hex. */
+
+static void
+debug_write (unsigned char *buf, int buflen)
+{
+ char s[10];
+
+ monitor_write (buf, buflen);
+
+ if (remote_debug > 0)
+ {
+ while (buflen-- > 0)
+ {
+ sprintf (s, "[%02x]", *buf & 0xff);
+ puts_debug ("Sent -->", s, "<--");
+ buf++;
+ }
+ }
+}
+
+
+/* Ignore a packet sent to us by the monitor. It send packets
+ when its console is in "communications interface" mode. A packet
+ is of this form:
+
+ start of packet flag (one byte: 0xdc)
+ packet type (one byte)
+ length (low byte)
+ length (high byte)
+ data (length bytes)
+
+ The last two bytes of the data field are a checksum, but we don't
+ bother to verify it.
+ */
+
+static void
+ignore_packet (void)
+{
+ int c = -1;
+ int len;
+
+ /* Ignore lots of trash (messages about section addresses, for example)
+ until we see the start of a packet. */
+ for (len = 0; len < 256; len++)
+ {
+ c = debug_readchar (0);
+ if (c == PESC)
+ break;
+ }
+ if (len == 8)
+ error ("Packet header byte not found; %02x seen instead.", c);
+
+ /* Read the packet type and length. */
+ c = debug_readchar (1); /* type */
+
+ c = debug_readchar (1); /* low byte of length */
+ len = c & 0xff;
+
+ c = debug_readchar (1); /* high byte of length */
+ len += (c & 0xff) << 8;
+
+ /* Ignore the rest of the packet. */
+ while (len-- > 0)
+ c = debug_readchar (1);
+}
+
+
+/* Encapsulate some data into a packet and send it to the monitor.
+
+ The 'p' packet is a special case. This is a packet we send
+ in response to a read ('r') packet from the monitor. This function
+ appends a one-byte sequence number to the data field of such a packet.
+ */
+
+static void
+send_packet (char type, unsigned char *buf, int buflen, int seq)
+{
+ unsigned char hdr[4];
+ int len = buflen;
+ int sum, i;
+
+ /* If this is a 'p' packet, add one byte for a sequence number. */
+ if (type == 'p')
+ len++;
+
+ /* If the buffer has a non-zero length, add two bytes for a checksum. */
+ if (len > 0)
+ len += 2;
+
+ /* Write the packet header. */
+ hdr[0] = PESC;
+ hdr[1] = type;
+ hdr[2] = len & 0xff;
+ hdr[3] = (len >> 8) & 0xff;
+ debug_write (hdr, sizeof (hdr));
+
+ if (len)
+ {
+ /* Write the packet data. */
+ debug_write (buf, buflen);
+
+ /* Write the sequence number if this is a 'p' packet. */
+ if (type == 'p')
+ {
+ hdr[0] = seq;
+ debug_write (hdr, 1);
+ }
+
+ /* Write the checksum. */
+ sum = 0;
+ for (i = 0; i < buflen; i++)
+ {
+ int tmp = (buf[i] & 0xff);
+ if (i & 1)
+ sum += tmp;
+ else
+ sum += tmp << 8;
+ }
+ if (type == 'p')
+ {
+ if (buflen & 1)
+ sum += (seq & 0xff);
+ else
+ sum += (seq & 0xff) << 8;
+ }
+ sum = (sum & 0xffff) + ((sum >> 16) & 0xffff);
+ sum += (sum >> 16) & 1;
+ sum = ~sum;
+
+ hdr[0] = (sum >> 8) & 0xff;
+ hdr[1] = sum & 0xff;
+ debug_write (hdr, 2);
+ }
+}
+
+
+/* Respond to an expected read request from the monitor by sending
+ data in chunks. Handle all acknowledgements and handshaking packets.
+
+ The monitor expects a response consisting of a one or more 'p' packets,
+ each followed by a portion of the data requested. The 'p' packet
+ contains only a four-byte integer, the value of which is the number
+ of bytes of data we are about to send. Following the 'p' packet,
+ the monitor expects the data bytes themselves in raw, unpacketized,
+ form, without even a checksum.
+ */
+
+static void
+process_read_request (unsigned char *buf, int buflen)
+{
+ unsigned char len[4];
+ int i, chunk;
+ unsigned char seq;
+
+ /* Discard the read request. FIXME: we have to hope it's for
+ the exact number of bytes we want to send; should check for this. */
+ ignore_packet ();
+
+ for (i = chunk = 0, seq = 0; i < buflen; i += chunk, seq++)
+ {
+ /* Don't send more than MAXPSIZE bytes at a time. */
+ chunk = buflen - i;
+ if (chunk > MAXPSIZE)
+ chunk = MAXPSIZE;
+
+ /* Write a packet containing the number of bytes we are sending. */
+ write_long_le (len, chunk);
+ send_packet ('p', len, sizeof (len), seq);
+
+ /* Write the data in raw form following the packet. */
+ debug_write (&buf[i], chunk);
+
+ /* Discard the ACK packet. */
+ ignore_packet ();
+ }
+
+ /* Send an "end of data" packet. */
+ send_packet ('e', "", 0, 0);
+}
+
+
+/* Count loadable sections (helper function for r3900_load). */
+
+static void
+count_section (bfd *abfd, asection *s, unsigned int *section_count)
+{
+ if (s->flags & SEC_LOAD && bfd_section_size (abfd, s) != 0)
+ (*section_count)++;
+}
+
+
+/* Load a single BFD section (helper function for r3900_load).
+
+ WARNING: this code is filled with assumptions about how
+ the Densan monitor loads programs. The monitor issues
+ packets containing read requests, but rather than respond
+ to them in an general way, we expect them to following
+ a certain pattern.
+
+ For example, we know that the monitor will start loading by
+ issuing an 8-byte read request for the binary file header.
+ We know this is coming and ignore the actual contents
+ of the read request packet.
+ */
+
+static void
+load_section (bfd *abfd, asection *s, unsigned int *data_count)
+{
+ if (s->flags & SEC_LOAD)
+ {
+ bfd_size_type section_size = bfd_section_size (abfd, s);
+ bfd_vma section_base = bfd_section_lma (abfd, s);
+ unsigned char *buffer;
+ unsigned char header[8];
+
+ /* Don't output zero-length sections. */
+ if (section_size == 0)
+ return;
+ if (data_count)
+ *data_count += section_size;
+
+ /* Print some fluff about the section being loaded. */
+ printf_filtered ("Loading section %s, size 0x%lx lma ",
+ bfd_section_name (abfd, s), (long) section_size);
+ print_address_numeric (section_base, 1, gdb_stdout);
+ printf_filtered ("\n");
+ gdb_flush (gdb_stdout);
+
+ /* Write the section header (location and size). */
+ write_long (&header[0], (long) section_base);
+ write_long (&header[4], (long) section_size);
+ process_read_request (header, sizeof (header));
+
+ /* Read the section contents into a buffer, write it out,
+ then free the buffer. */
+ buffer = (unsigned char *) xmalloc (section_size);
+ bfd_get_section_contents (abfd, s, buffer, 0, section_size);
+ process_read_request (buffer, section_size);
+ xfree (buffer);
+ }
+}
+
+
+/* When the ethernet is used as the console port on the Densan board,
+ we can use the "Rm" command to do a fast binary load. The format
+ of the download data is:
+
+ number of sections (4 bytes)
+ starting address (4 bytes)
+ repeat for each section:
+ location address (4 bytes)
+ section size (4 bytes)
+ binary data
+
+ The 4-byte fields are all in big-endian order.
+
+ Using this command is tricky because we have to put the monitor
+ into a special funky "communications interface" mode, in which
+ it sends and receives packets of data along with the normal prompt.
+ */
+
+static void
+r3900_load (char *filename, int from_tty)
+{
+ bfd *abfd;
+ unsigned int data_count = 0;
+ time_t start_time, end_time; /* for timing of download */
+ int section_count = 0;
+ unsigned char buffer[8];
+
+ /* If we are not using the ethernet, use the normal monitor load,
+ which sends S-records over the serial link. */
+ if (!ethernet)
+ {
+ orig_monitor_load (filename, from_tty);
+ return;
+ }
+
+ /* Open the file. */
+ if (filename == NULL || filename[0] == 0)
+ filename = get_exec_file (1);
+ abfd = bfd_openr (filename, 0);
+ if (!abfd)
+ error ("Unable to open file %s\n", filename);
+ if (bfd_check_format (abfd, bfd_object) == 0)
+ error ("File is not an object file\n");
+
+ /* Output the "vconsi" command to get the monitor in the communication
+ state where it will accept a load command. This will cause
+ the monitor to emit a packet before each prompt, so ignore the packet. */
+ monitor_printf ("vconsi\r");
+ ignore_packet ();
+ monitor_expect_prompt (NULL, 0);
+
+ /* Output the "Rm" (load) command and respond to the subsequent "open"
+ packet by sending an ACK packet. */
+ monitor_printf ("Rm\r");
+ ignore_packet ();
+ send_packet ('a', "", 0, 0);
+
+ /* Output the fast load header (number of sections and starting address). */
+ bfd_map_over_sections ((bfd *) abfd, (section_map_func) count_section,
+ &section_count);
+ write_long (&buffer[0], (long) section_count);
+ if (exec_bfd)
+ write_long (&buffer[4], (long) bfd_get_start_address (exec_bfd));
+ else
+ write_long (&buffer[4], 0);
+ process_read_request (buffer, sizeof (buffer));
+
+ /* Output the section data. */
+ start_time = time (NULL);
+ bfd_map_over_sections (abfd, (section_map_func) load_section, &data_count);
+ end_time = time (NULL);
+
+ /* Acknowledge the close packet and put the monitor back into
+ "normal" mode so it won't send packets any more. */
+ ignore_packet ();
+ send_packet ('a', "", 0, 0);
+ monitor_expect_prompt (NULL, 0);
+ monitor_printf ("vconsx\r");
+ monitor_expect_prompt (NULL, 0);
+
+ /* Print start address and download performance information. */
+ printf_filtered ("Start address 0x%lx\n", (long) bfd_get_start_address (abfd));
+ report_transfer_performance (data_count, start_time, end_time);
+
+ /* Finally, make the PC point at the start address */
+ if (exec_bfd)
+ write_pc (bfd_get_start_address (exec_bfd));
+
+ inferior_ptid = null_ptid; /* 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 ();
+}
+
+
+/* Commands to send to the monitor when first connecting:
+ * The bare carriage return forces a prompt from the monitor
+ (monitor doesn't prompt immediately after a reset).
+ * The "vconsx" switches the monitor back to interactive mode
+ in case an aborted download had left it in packet mode.
+ * The "Xtr" command causes subsequent "t" (trace) commands to display
+ the general registers only.
+ * The "Xxr" command does the same thing for the "x" (examine
+ registers) command.
+ * The "bx" command clears all breakpoints.
+ */
+
+static char *r3900_inits[] =
+{"\r", "vconsx\r", "Xtr\r", "Xxr\r", "bx\r", NULL};
+static char *dummy_inits[] =
+{NULL};
+
+static struct target_ops r3900_ops;
+static struct monitor_ops r3900_cmds;
+
+static void
+r3900_open (char *args, int from_tty)
+{
+ char buf[64];
+ int i;
+
+ monitor_open (args, &r3900_cmds, from_tty);
+
+ /* We have to handle sending the init strings ourselves, because
+ the first two strings we send (carriage returns) may not be echoed
+ by the monitor, but the rest will be. */
+ monitor_printf_noecho ("\r\r");
+ for (i = 0; r3900_inits[i] != NULL; i++)
+ {
+ monitor_printf (r3900_inits[i]);
+ monitor_expect_prompt (NULL, 0);
+ }
+
+ /* Attempt to determine whether the console device is ethernet or serial.
+ This will tell us which kind of load to use (S-records over a serial
+ link, or the Densan fast binary multi-section format over the net). */
+
+ ethernet = 0;
+ monitor_printf ("v\r");
+ if (monitor_expect ("console device :", NULL, 0) != -1)
+ if (monitor_expect ("\n", buf, sizeof (buf)) != -1)
+ if (strstr (buf, "ethernet") != NULL)
+ ethernet = 1;
+ monitor_expect_prompt (NULL, 0);
+}
+
+void
+_initialize_r3900_rom (void)
+{
+ r3900_cmds.flags = MO_NO_ECHO_ON_OPEN |
+ MO_ADDR_BITS_REMOVE |
+ MO_CLR_BREAK_USES_ADDR |
+ MO_GETMEM_READ_SINGLE |
+ MO_PRINT_PROGRAM_OUTPUT;
+
+ r3900_cmds.init = dummy_inits;
+ r3900_cmds.cont = "g\r";
+ r3900_cmds.step = "t\r";
+ r3900_cmds.set_break = "b %A\r"; /* COREADDR */
+ r3900_cmds.clr_break = "b %A,0\r"; /* COREADDR */
+ r3900_cmds.fill = "fx %A s %x %x\r"; /* COREADDR, len, val */
+
+ r3900_cmds.setmem.cmdb = "sx %A %x\r"; /* COREADDR, val */
+ r3900_cmds.setmem.cmdw = "sh %A %x\r"; /* COREADDR, val */
+ r3900_cmds.setmem.cmdl = "sw %A %x\r"; /* COREADDR, val */
+
+ r3900_cmds.getmem.cmdb = "sx %A\r"; /* COREADDR */
+ r3900_cmds.getmem.cmdw = "sh %A\r"; /* COREADDR */
+ r3900_cmds.getmem.cmdl = "sw %A\r"; /* COREADDR */
+ r3900_cmds.getmem.resp_delim = " : ";
+ r3900_cmds.getmem.term = " ";
+ r3900_cmds.getmem.term_cmd = ".\r";
+
+ r3900_cmds.setreg.cmd = "x%s %x\r"; /* regname, val */
+
+ r3900_cmds.getreg.cmd = "x%s\r"; /* regname */
+ r3900_cmds.getreg.resp_delim = "=";
+ r3900_cmds.getreg.term = " ";
+ r3900_cmds.getreg.term_cmd = ".\r";
+
+ r3900_cmds.dump_registers = "x\r";
+ r3900_cmds.register_pattern =
+ "\\([a-zA-Z0-9_]+\\) *=\\([0-9a-f]+ [0-9a-f]+\\b\\)";
+ r3900_cmds.supply_register = r3900_supply_register;
+ /* S-record download, via "keyboard port". */
+ r3900_cmds.load = "r0\r";
+ r3900_cmds.prompt = "#";
+ r3900_cmds.line_term = "\r";
+ r3900_cmds.target = &r3900_ops;
+ r3900_cmds.stopbits = SERIAL_1_STOPBITS;
+ r3900_cmds.regnames = r3900_regnames;
+ r3900_cmds.magic = MONITOR_OPS_MAGIC;
+
+ init_monitor_ops (&r3900_ops);
+
+ r3900_ops.to_shortname = "r3900";
+ r3900_ops.to_longname = "R3900 monitor";
+ r3900_ops.to_doc = "Debug using the DVE R3900 monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ r3900_ops.to_open = r3900_open;
+
+ /* Override the functions to fetch and store registers. But save the
+ addresses of the default functions, because we will use those functions
+ for "normal" registers. */
+
+ orig_monitor_fetch_registers = r3900_ops.to_fetch_registers;
+ orig_monitor_store_registers = r3900_ops.to_store_registers;
+ r3900_ops.to_fetch_registers = r3900_fetch_registers;
+ r3900_ops.to_store_registers = r3900_store_registers;
+
+ /* Override the load function, but save the address of the default
+ function to use when loading S-records over a serial link. */
+ orig_monitor_load = r3900_ops.to_load;
+ r3900_ops.to_load = r3900_load;
+
+ add_target (&r3900_ops);
+}
diff --git a/contrib/gdb/gdb/dwarf2-frame.c b/contrib/gdb/gdb/dwarf2-frame.c
new file mode 100644
index 0000000..51a631d
--- /dev/null
+++ b/contrib/gdb/gdb/dwarf2-frame.c
@@ -0,0 +1,1621 @@
+/* Frame unwinder for frames with DWARF Call Frame Information.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Mark Kettenis.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "dwarf2expr.h"
+#include "elf/dwarf2.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "gdbcore.h"
+#include "gdbtypes.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "regcache.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "complaints.h"
+#include "dwarf2-frame.h"
+
+/* Call Frame Information (CFI). */
+
+/* Common Information Entry (CIE). */
+
+struct dwarf2_cie
+{
+ /* Offset into the .debug_frame section where this CIE was found.
+ Used to identify this CIE. */
+ ULONGEST cie_pointer;
+
+ /* Constant that is factored out of all advance location
+ instructions. */
+ ULONGEST code_alignment_factor;
+
+ /* Constants that is factored out of all offset instructions. */
+ LONGEST data_alignment_factor;
+
+ /* Return address column. */
+ ULONGEST return_address_register;
+
+ /* Instruction sequence to initialize a register set. */
+ unsigned char *initial_instructions;
+ unsigned char *end;
+
+ /* Encoding of addresses. */
+ unsigned char encoding;
+
+ /* True if a 'z' augmentation existed. */
+ unsigned char saw_z_augmentation;
+
+ struct dwarf2_cie *next;
+};
+
+/* Frame Description Entry (FDE). */
+
+struct dwarf2_fde
+{
+ /* CIE for this FDE. */
+ struct dwarf2_cie *cie;
+
+ /* First location associated with this FDE. */
+ CORE_ADDR initial_location;
+
+ /* Number of bytes of program instructions described by this FDE. */
+ CORE_ADDR address_range;
+
+ /* Instruction sequence. */
+ unsigned char *instructions;
+ unsigned char *end;
+
+ struct dwarf2_fde *next;
+};
+
+static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc);
+
+
+/* Structure describing a frame state. */
+
+struct dwarf2_frame_state
+{
+ /* Each register save state can be described in terms of a CFA slot,
+ another register, or a location expression. */
+ struct dwarf2_frame_state_reg_info
+ {
+ struct dwarf2_frame_state_reg *reg;
+ int num_regs;
+
+ /* Used to implement DW_CFA_remember_state. */
+ struct dwarf2_frame_state_reg_info *prev;
+ } regs;
+
+ LONGEST cfa_offset;
+ ULONGEST cfa_reg;
+ unsigned char *cfa_exp;
+ enum {
+ CFA_UNSET,
+ CFA_REG_OFFSET,
+ CFA_EXP
+ } cfa_how;
+
+ /* The PC described by the current frame state. */
+ CORE_ADDR pc;
+
+ /* Initial register set from the CIE.
+ Used to implement DW_CFA_restore. */
+ struct dwarf2_frame_state_reg_info initial;
+
+ /* The information we care about from the CIE. */
+ LONGEST data_align;
+ ULONGEST code_align;
+ ULONGEST retaddr_column;
+};
+
+/* Store the length the expression for the CFA in the `cfa_reg' field,
+ which is unused in that case. */
+#define cfa_exp_len cfa_reg
+
+/* Assert that the register set RS is large enough to store NUM_REGS
+ columns. If necessary, enlarge the register set. */
+
+static void
+dwarf2_frame_state_alloc_regs (struct dwarf2_frame_state_reg_info *rs,
+ int num_regs)
+{
+ size_t size = sizeof (struct dwarf2_frame_state_reg);
+
+ if (num_regs <= rs->num_regs)
+ return;
+
+ rs->reg = (struct dwarf2_frame_state_reg *)
+ xrealloc (rs->reg, num_regs * size);
+
+ /* Initialize newly allocated registers. */
+ memset (rs->reg + rs->num_regs, 0, (num_regs - rs->num_regs) * size);
+ rs->num_regs = num_regs;
+}
+
+/* Copy the register columns in register set RS into newly allocated
+ memory and return a pointer to this newly created copy. */
+
+static struct dwarf2_frame_state_reg *
+dwarf2_frame_state_copy_regs (struct dwarf2_frame_state_reg_info *rs)
+{
+ size_t size = rs->num_regs * sizeof (struct dwarf2_frame_state_reg_info);
+ struct dwarf2_frame_state_reg *reg;
+
+ reg = (struct dwarf2_frame_state_reg *) xmalloc (size);
+ memcpy (reg, rs->reg, size);
+
+ return reg;
+}
+
+/* Release the memory allocated to register set RS. */
+
+static void
+dwarf2_frame_state_free_regs (struct dwarf2_frame_state_reg_info *rs)
+{
+ if (rs)
+ {
+ dwarf2_frame_state_free_regs (rs->prev);
+
+ xfree (rs->reg);
+ xfree (rs);
+ }
+}
+
+/* Release the memory allocated to the frame state FS. */
+
+static void
+dwarf2_frame_state_free (void *p)
+{
+ struct dwarf2_frame_state *fs = p;
+
+ dwarf2_frame_state_free_regs (fs->initial.prev);
+ dwarf2_frame_state_free_regs (fs->regs.prev);
+ xfree (fs->initial.reg);
+ xfree (fs->regs.reg);
+ xfree (fs);
+}
+
+
+/* Helper functions for execute_stack_op. */
+
+static CORE_ADDR
+read_reg (void *baton, int reg)
+{
+ struct frame_info *next_frame = (struct frame_info *) baton;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int regnum;
+ char *buf;
+
+ regnum = DWARF2_REG_TO_REGNUM (reg);
+
+ buf = (char *) alloca (register_size (gdbarch, regnum));
+ frame_unwind_register (next_frame, regnum, buf);
+ return extract_typed_address (buf, builtin_type_void_data_ptr);
+}
+
+static void
+read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len)
+{
+ read_memory (addr, buf, len);
+}
+
+static void
+no_get_frame_base (void *baton, unsigned char **start, size_t *length)
+{
+ internal_error (__FILE__, __LINE__,
+ "Support for DW_OP_fbreg is unimplemented");
+}
+
+static CORE_ADDR
+no_get_tls_address (void *baton, CORE_ADDR offset)
+{
+ internal_error (__FILE__, __LINE__,
+ "Support for DW_OP_GNU_push_tls_address is unimplemented");
+}
+
+static CORE_ADDR
+execute_stack_op (unsigned char *exp, ULONGEST len,
+ struct frame_info *next_frame, CORE_ADDR initial)
+{
+ struct dwarf_expr_context *ctx;
+ CORE_ADDR result;
+
+ ctx = new_dwarf_expr_context ();
+ ctx->baton = next_frame;
+ ctx->read_reg = read_reg;
+ ctx->read_mem = read_mem;
+ ctx->get_frame_base = no_get_frame_base;
+ ctx->get_tls_address = no_get_tls_address;
+
+ dwarf_expr_push (ctx, initial);
+ dwarf_expr_eval (ctx, exp, len);
+ result = dwarf_expr_fetch (ctx, 0);
+
+ if (ctx->in_reg)
+ result = read_reg (next_frame, result);
+
+ free_dwarf_expr_context (ctx);
+
+ return result;
+}
+
+
+static void
+execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
+ struct frame_info *next_frame,
+ struct dwarf2_frame_state *fs)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ int bytes_read;
+
+ while (insn_ptr < insn_end && fs->pc <= pc)
+ {
+ unsigned char insn = *insn_ptr++;
+ ULONGEST utmp, reg;
+ LONGEST offset;
+
+ if ((insn & 0xc0) == DW_CFA_advance_loc)
+ fs->pc += (insn & 0x3f) * fs->code_align;
+ else if ((insn & 0xc0) == DW_CFA_offset)
+ {
+ reg = insn & 0x3f;
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+ offset = utmp * fs->data_align;
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ }
+ else if ((insn & 0xc0) == DW_CFA_restore)
+ {
+ gdb_assert (fs->initial.reg);
+ reg = insn & 0x3f;
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg] = fs->initial.reg[reg];
+ }
+ else
+ {
+ switch (insn)
+ {
+ case DW_CFA_set_loc:
+ fs->pc = dwarf2_read_address (insn_ptr, insn_end, &bytes_read);
+ insn_ptr += bytes_read;
+ break;
+
+ case DW_CFA_advance_loc1:
+ utmp = extract_unsigned_integer (insn_ptr, 1);
+ fs->pc += utmp * fs->code_align;
+ insn_ptr++;
+ break;
+ case DW_CFA_advance_loc2:
+ utmp = extract_unsigned_integer (insn_ptr, 2);
+ fs->pc += utmp * fs->code_align;
+ insn_ptr += 2;
+ break;
+ case DW_CFA_advance_loc4:
+ utmp = extract_unsigned_integer (insn_ptr, 4);
+ fs->pc += utmp * fs->code_align;
+ insn_ptr += 4;
+ break;
+
+ case DW_CFA_offset_extended:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+ offset = utmp * fs->data_align;
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ break;
+
+ case DW_CFA_restore_extended:
+ gdb_assert (fs->initial.reg);
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg] = fs->initial.reg[reg];
+ break;
+
+ case DW_CFA_undefined:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNDEFINED;
+ break;
+
+ case DW_CFA_same_value:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAME_VALUE;
+ break;
+
+ case DW_CFA_register:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
+ fs->regs.reg[reg].loc.reg = utmp;
+ break;
+
+ case DW_CFA_remember_state:
+ {
+ struct dwarf2_frame_state_reg_info *new_rs;
+
+ new_rs = XMALLOC (struct dwarf2_frame_state_reg_info);
+ *new_rs = fs->regs;
+ fs->regs.reg = dwarf2_frame_state_copy_regs (&fs->regs);
+ fs->regs.prev = new_rs;
+ }
+ break;
+
+ case DW_CFA_restore_state:
+ {
+ struct dwarf2_frame_state_reg_info *old_rs = fs->regs.prev;
+
+ gdb_assert (old_rs);
+
+ xfree (fs->regs.reg);
+ fs->regs = *old_rs;
+ xfree (old_rs);
+ }
+ break;
+
+ case DW_CFA_def_cfa:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+ fs->cfa_offset = utmp;
+ fs->cfa_how = CFA_REG_OFFSET;
+ break;
+
+ case DW_CFA_def_cfa_register:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
+ fs->cfa_how = CFA_REG_OFFSET;
+ break;
+
+ case DW_CFA_def_cfa_offset:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_offset);
+ /* cfa_how deliberately not set. */
+ break;
+
+ case DW_CFA_nop:
+ break;
+
+ case DW_CFA_def_cfa_expression:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_exp_len);
+ fs->cfa_exp = insn_ptr;
+ fs->cfa_how = CFA_EXP;
+ insn_ptr += fs->cfa_exp_len;
+ break;
+
+ case DW_CFA_expression:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+ fs->regs.reg[reg].loc.exp = insn_ptr;
+ fs->regs.reg[reg].exp_len = utmp;
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_EXP;
+ insn_ptr += utmp;
+ break;
+
+ case DW_CFA_offset_extended_sf:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
+ insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
+ offset += fs->data_align;
+ dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ break;
+
+ case DW_CFA_def_cfa_sf:
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
+ insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
+ fs->cfa_offset = offset * fs->data_align;
+ fs->cfa_how = CFA_REG_OFFSET;
+ break;
+
+ case DW_CFA_def_cfa_offset_sf:
+ insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
+ fs->cfa_offset = offset * fs->data_align;
+ /* cfa_how deliberately not set. */
+ break;
+
+ case DW_CFA_GNU_args_size:
+ /* Ignored. */
+ insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "Unknown CFI encountered.");
+ }
+ }
+ }
+
+ /* Don't allow remember/restore between CIE and FDE programs. */
+ dwarf2_frame_state_free_regs (fs->regs.prev);
+ fs->regs.prev = NULL;
+}
+
+
+/* Architecture-specific operations. */
+
+/* Per-architecture data key. */
+static struct gdbarch_data *dwarf2_frame_data;
+
+struct dwarf2_frame_ops
+{
+ /* Pre-initialize the register state REG for register REGNUM. */
+ void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *);
+};
+
+/* Default architecture-specific register state initialization
+ function. */
+
+static void
+dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg)
+{
+ /* If we have a register that acts as a program counter, mark it as
+ a destination for the return address. If we have a register that
+ serves as the stack pointer, arrange for it to be filled with the
+ call frame address (CFA). The other registers are marked as
+ unspecified.
+
+ We copy the return address to the program counter, since many
+ parts in GDB assume that it is possible to get the return address
+ by unwinding the program counter register. However, on ISA's
+ with a dedicated return address register, the CFI usually only
+ contains information to unwind that return address register.
+
+ The reason we're treating the stack pointer special here is
+ because in many cases GCC doesn't emit CFI for the stack pointer
+ and implicitly assumes that it is equal to the CFA. This makes
+ some sense since the DWARF specification (version 3, draft 8,
+ p. 102) says that:
+
+ "Typically, the CFA is defined to be the value of the stack
+ pointer at the call site in the previous frame (which may be
+ different from its value on entry to the current frame)."
+
+ However, this isn't true for all platforms supported by GCC
+ (e.g. IBM S/390 and zSeries). Those architectures should provide
+ their own architecture-specific initialization function. */
+
+ if (regnum == PC_REGNUM)
+ reg->how = DWARF2_FRAME_REG_RA;
+ else if (regnum == SP_REGNUM)
+ reg->how = DWARF2_FRAME_REG_CFA;
+}
+
+/* Return a default for the architecture-specific operations. */
+
+static void *
+dwarf2_frame_init (struct gdbarch *gdbarch)
+{
+ struct dwarf2_frame_ops *ops;
+
+ ops = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct dwarf2_frame_ops);
+ ops->init_reg = dwarf2_frame_default_init_reg;
+ return ops;
+}
+
+static struct dwarf2_frame_ops *
+dwarf2_frame_ops (struct gdbarch *gdbarch)
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+ if (ops == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ ops = dwarf2_frame_init (gdbarch);
+ set_gdbarch_data (gdbarch, dwarf2_frame_data, ops);
+ }
+ return ops;
+}
+
+/* Set the architecture-specific register state initialization
+ function for GDBARCH to INIT_REG. */
+
+void
+dwarf2_frame_set_init_reg (struct gdbarch *gdbarch,
+ void (*init_reg) (struct gdbarch *, int,
+ struct dwarf2_frame_state_reg *))
+{
+ struct dwarf2_frame_ops *ops;
+
+ ops = dwarf2_frame_ops (gdbarch);
+ ops->init_reg = init_reg;
+}
+
+/* Pre-initialize the register state REG for register REGNUM. */
+
+static void
+dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg)
+{
+ struct dwarf2_frame_ops *ops;
+
+ ops = dwarf2_frame_ops (gdbarch);
+ ops->init_reg (gdbarch, regnum, reg);
+}
+
+
+struct dwarf2_frame_cache
+{
+ /* DWARF Call Frame Address. */
+ CORE_ADDR cfa;
+
+ /* Saved registers, indexed by GDB register number, not by DWARF
+ register number. */
+ struct dwarf2_frame_state_reg *reg;
+};
+
+static struct dwarf2_frame_cache *
+dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct cleanup *old_chain;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ const int num_regs = NUM_REGS + NUM_PSEUDO_REGS;
+ struct dwarf2_frame_cache *cache;
+ struct dwarf2_frame_state *fs;
+ struct dwarf2_fde *fde;
+
+ if (*this_cache)
+ return *this_cache;
+
+ /* Allocate a new cache. */
+ cache = FRAME_OBSTACK_ZALLOC (struct dwarf2_frame_cache);
+ cache->reg = FRAME_OBSTACK_CALLOC (num_regs, struct dwarf2_frame_state_reg);
+
+ /* Allocate and initialize the frame state. */
+ fs = XMALLOC (struct dwarf2_frame_state);
+ memset (fs, 0, sizeof (struct dwarf2_frame_state));
+ old_chain = make_cleanup (dwarf2_frame_state_free, fs);
+
+ /* Unwind the PC.
+
+ Note that if NEXT_FRAME is never supposed to return (i.e. a call
+ to abort), the compiler might optimize away the instruction at
+ NEXT_FRAME's return address. As a result the return address will
+ point at some random instruction, and the CFI for that
+ instruction is probably worthless to us. GCC's unwinder solves
+ this problem by substracting 1 from the return address to get an
+ address in the middle of a presumed call instruction (or the
+ instruction in the associated delay slot). This should only be
+ done for "normal" frames and not for resume-type frames (signal
+ handlers, sentinel frames, dummy frames). The function
+ frame_unwind_address_in_block does just this. It's not clear how
+ reliable the method is though; there is the potential for the
+ register state pre-call being different to that on return. */
+ fs->pc = frame_unwind_address_in_block (next_frame);
+
+ /* Find the correct FDE. */
+ fde = dwarf2_frame_find_fde (&fs->pc);
+ gdb_assert (fde != NULL);
+
+ /* Extract any interesting information from the CIE. */
+ fs->data_align = fde->cie->data_alignment_factor;
+ fs->code_align = fde->cie->code_alignment_factor;
+ fs->retaddr_column = fde->cie->return_address_register;
+
+ /* First decode all the insns in the CIE. */
+ execute_cfa_program (fde->cie->initial_instructions,
+ fde->cie->end, next_frame, fs);
+
+ /* Save the initialized register set. */
+ fs->initial = fs->regs;
+ fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs);
+
+ /* Then decode the insns in the FDE up to our target PC. */
+ execute_cfa_program (fde->instructions, fde->end, next_frame, fs);
+
+ /* Caclulate the CFA. */
+ switch (fs->cfa_how)
+ {
+ case CFA_REG_OFFSET:
+ cache->cfa = read_reg (next_frame, fs->cfa_reg);
+ cache->cfa += fs->cfa_offset;
+ break;
+
+ case CFA_EXP:
+ cache->cfa =
+ execute_stack_op (fs->cfa_exp, fs->cfa_exp_len, next_frame, 0);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "Unknown CFA rule.");
+ }
+
+ /* Initialize the register state. */
+ {
+ int regnum;
+
+ for (regnum = 0; regnum < num_regs; regnum++)
+ dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum]);
+ }
+
+ /* Go through the DWARF2 CFI generated table and save its register
+ location information in the cache. Note that we don't skip the
+ return address column; it's perfectly all right for it to
+ correspond to a real register. If it doesn't correspond to a
+ real register, or if we shouldn't treat it as such,
+ DWARF2_REG_TO_REGNUM should be defined to return a number outside
+ the range [0, NUM_REGS). */
+ {
+ int column; /* CFI speak for "register number". */
+
+ for (column = 0; column < fs->regs.num_regs; column++)
+ {
+ /* Use the GDB register number as the destination index. */
+ int regnum = DWARF2_REG_TO_REGNUM (column);
+
+ /* If there's no corresponding GDB register, ignore it. */
+ if (regnum < 0 || regnum >= num_regs)
+ continue;
+
+ /* NOTE: cagney/2003-09-05: CFI should specify the disposition
+ of all debug info registers. If it doesn't, complain (but
+ not too loudly). It turns out that GCC assumes that an
+ unspecified register implies "same value" when CFI (draft
+ 7) specifies nothing at all. Such a register could equally
+ be interpreted as "undefined". Also note that this check
+ isn't sufficient; it only checks that all registers in the
+ range [0 .. max column] are specified, and won't detect
+ problems when a debug info register falls outside of the
+ table. We need a way of iterating through all the valid
+ DWARF2 register numbers. */
+ if (fs->regs.reg[column].how == DWARF2_FRAME_REG_UNSPECIFIED)
+ complaint (&symfile_complaints,
+ "Incomplete CFI data; unspecified registers at 0x%s",
+ paddr (fs->pc));
+ else
+ cache->reg[regnum] = fs->regs.reg[column];
+ }
+ }
+
+ /* Eliminate any DWARF2_FRAME_REG_RA rules. */
+ {
+ int regnum;
+
+ for (regnum = 0; regnum < num_regs; regnum++)
+ {
+ if (cache->reg[regnum].how == DWARF2_FRAME_REG_RA)
+ {
+ struct dwarf2_frame_state_reg *retaddr_reg =
+ &fs->regs.reg[fs->retaddr_column];
+
+ /* It seems rather bizarre to specify an "empty" column as
+ the return adress column. However, this is exactly
+ what GCC does on some targets. It turns out that GCC
+ assumes that the return address can be found in the
+ register corresponding to the return address column.
+ Incidentally, that's how should treat a return address
+ column specifying "same value" too. */
+ if (fs->retaddr_column < fs->regs.num_regs
+ && retaddr_reg->how != DWARF2_FRAME_REG_UNSPECIFIED
+ && retaddr_reg->how != DWARF2_FRAME_REG_SAME_VALUE)
+ cache->reg[regnum] = *retaddr_reg;
+ else
+ {
+ cache->reg[regnum].loc.reg = fs->retaddr_column;
+ cache->reg[regnum].how = DWARF2_FRAME_REG_SAVED_REG;
+ }
+ }
+ }
+ }
+
+ do_cleanups (old_chain);
+
+ *this_cache = cache;
+ return cache;
+}
+
+static void
+dwarf2_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct dwarf2_frame_cache *cache =
+ dwarf2_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->cfa, frame_func_unwind (next_frame));
+}
+
+static void
+dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct dwarf2_frame_cache *cache =
+ dwarf2_frame_cache (next_frame, this_cache);
+
+ switch (cache->reg[regnum].how)
+ {
+ case DWARF2_FRAME_REG_UNDEFINED:
+ /* If CFI explicitly specified that the value isn't defined,
+ mark it as optimized away; the value isn't available. */
+ *optimizedp = 1;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ /* In some cases, for example %eflags on the i386, we have
+ to provide a sane value, even though this register wasn't
+ saved. Assume we can get it from NEXT_FRAME. */
+ frame_unwind_register (next_frame, regnum, valuep);
+ }
+ break;
+
+ case DWARF2_FRAME_REG_SAVED_OFFSET:
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = cache->cfa + cache->reg[regnum].loc.offset;
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Read the value in from memory. */
+ read_memory (*addrp, valuep, register_size (gdbarch, regnum));
+ }
+ break;
+
+ case DWARF2_FRAME_REG_SAVED_REG:
+ regnum = DWARF2_REG_TO_REGNUM (cache->reg[regnum].loc.reg);
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+ break;
+
+ case DWARF2_FRAME_REG_SAVED_EXP:
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = execute_stack_op (cache->reg[regnum].loc.exp,
+ cache->reg[regnum].exp_len,
+ next_frame, cache->cfa);
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Read the value in from memory. */
+ read_memory (*addrp, valuep, register_size (gdbarch, regnum));
+ }
+ break;
+
+ case DWARF2_FRAME_REG_UNSPECIFIED:
+ /* GCC, in its infinite wisdom decided to not provide unwind
+ information for registers that are "same value". Since
+ DWARF2 (3 draft 7) doesn't define such behavior, said
+ registers are actually undefined (which is different to CFI
+ "undefined"). Code above issues a complaint about this.
+ Here just fudge the books, assume GCC, and that the value is
+ more inner on the stack. */
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+ break;
+
+ case DWARF2_FRAME_REG_SAME_VALUE:
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+ break;
+
+ case DWARF2_FRAME_REG_CFA:
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Store the value. */
+ store_typed_address (valuep, builtin_type_void_data_ptr, cache->cfa);
+ }
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "Unknown register rule.");
+ }
+}
+
+static const struct frame_unwind dwarf2_frame_unwind =
+{
+ NORMAL_FRAME,
+ dwarf2_frame_this_id,
+ dwarf2_frame_prev_register
+};
+
+const struct frame_unwind *
+dwarf2_frame_sniffer (struct frame_info *next_frame)
+{
+ /* Grab an address that is guarenteed to reside somewhere within the
+ function. frame_pc_unwind(), for a no-return next function, can
+ end up returning something past the end of this function's body. */
+ CORE_ADDR block_addr = frame_unwind_address_in_block (next_frame);
+ if (dwarf2_frame_find_fde (&block_addr))
+ return &dwarf2_frame_unwind;
+
+ return NULL;
+}
+
+
+/* There is no explicitly defined relationship between the CFA and the
+ location of frame's local variables and arguments/parameters.
+ Therefore, frame base methods on this page should probably only be
+ used as a last resort, just to avoid printing total garbage as a
+ response to the "info frame" command. */
+
+static CORE_ADDR
+dwarf2_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct dwarf2_frame_cache *cache =
+ dwarf2_frame_cache (next_frame, this_cache);
+
+ return cache->cfa;
+}
+
+static const struct frame_base dwarf2_frame_base =
+{
+ &dwarf2_frame_unwind,
+ dwarf2_frame_base_address,
+ dwarf2_frame_base_address,
+ dwarf2_frame_base_address
+};
+
+const struct frame_base *
+dwarf2_frame_base_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ if (dwarf2_frame_find_fde (&pc))
+ return &dwarf2_frame_base;
+
+ return NULL;
+}
+
+/* A minimal decoding of DWARF2 compilation units. We only decode
+ what's needed to get to the call frame information. */
+
+struct comp_unit
+{
+ /* Keep the bfd convenient. */
+ bfd *abfd;
+
+ struct objfile *objfile;
+
+ /* Linked list of CIEs for this object. */
+ struct dwarf2_cie *cie;
+
+ /* Address size for this unit - from unit header. */
+ unsigned char addr_size;
+
+ /* Pointer to the .debug_frame section loaded into memory. */
+ char *dwarf_frame_buffer;
+
+ /* Length of the loaded .debug_frame section. */
+ unsigned long dwarf_frame_size;
+
+ /* Pointer to the .debug_frame section. */
+ asection *dwarf_frame_section;
+
+ /* Base for DW_EH_PE_datarel encodings. */
+ bfd_vma dbase;
+
+ /* Base for DW_EH_PE_textrel encodings. */
+ bfd_vma tbase;
+};
+
+const struct objfile_data *dwarf2_frame_objfile_data;
+
+static unsigned int
+read_1_byte (bfd *bfd, char *buf)
+{
+ return bfd_get_8 (abfd, (bfd_byte *) buf);
+}
+
+static unsigned int
+read_4_bytes (bfd *abfd, char *buf)
+{
+ return bfd_get_32 (abfd, (bfd_byte *) buf);
+}
+
+static ULONGEST
+read_8_bytes (bfd *abfd, char *buf)
+{
+ return bfd_get_64 (abfd, (bfd_byte *) buf);
+}
+
+static ULONGEST
+read_unsigned_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr)
+{
+ ULONGEST result;
+ unsigned int num_read;
+ int shift;
+ unsigned char byte;
+
+ result = 0;
+ shift = 0;
+ num_read = 0;
+
+ do
+ {
+ byte = bfd_get_8 (abfd, (bfd_byte *) buf);
+ buf++;
+ num_read++;
+ result |= ((byte & 0x7f) << shift);
+ shift += 7;
+ }
+ while (byte & 0x80);
+
+ *bytes_read_ptr = num_read;
+
+ return result;
+}
+
+static LONGEST
+read_signed_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr)
+{
+ LONGEST result;
+ int shift;
+ unsigned int num_read;
+ unsigned char byte;
+
+ result = 0;
+ shift = 0;
+ num_read = 0;
+
+ do
+ {
+ byte = bfd_get_8 (abfd, (bfd_byte *) buf);
+ buf++;
+ num_read++;
+ result |= ((byte & 0x7f) << shift);
+ shift += 7;
+ }
+ while (byte & 0x80);
+
+ if ((shift < 32) && (byte & 0x40))
+ result |= -(1 << shift);
+
+ *bytes_read_ptr = num_read;
+
+ return result;
+}
+
+static ULONGEST
+read_initial_length (bfd *abfd, char *buf, unsigned int *bytes_read_ptr)
+{
+ LONGEST result;
+
+ result = bfd_get_32 (abfd, (bfd_byte *) buf);
+ if (result == 0xffffffff)
+ {
+ result = bfd_get_64 (abfd, (bfd_byte *) buf + 4);
+ *bytes_read_ptr = 12;
+ }
+ else
+ *bytes_read_ptr = 4;
+
+ return result;
+}
+
+
+/* Pointer encoding helper functions. */
+
+/* GCC supports exception handling based on DWARF2 CFI. However, for
+ technical reasons, it encodes addresses in its FDE's in a different
+ way. Several "pointer encodings" are supported. The encoding
+ that's used for a particular FDE is determined by the 'R'
+ augmentation in the associated CIE. The argument of this
+ augmentation is a single byte.
+
+ The address can be encoded as 2 bytes, 4 bytes, 8 bytes, or as a
+ LEB128. This is encoded in bits 0, 1 and 2. Bit 3 encodes whether
+ the address is signed or unsigned. Bits 4, 5 and 6 encode how the
+ address should be interpreted (absolute, relative to the current
+ position in the FDE, ...). Bit 7, indicates that the address
+ should be dereferenced. */
+
+static unsigned char
+encoding_for_size (unsigned int size)
+{
+ switch (size)
+ {
+ case 2:
+ return DW_EH_PE_udata2;
+ case 4:
+ return DW_EH_PE_udata4;
+ case 8:
+ return DW_EH_PE_udata8;
+ default:
+ internal_error (__FILE__, __LINE__, "Unsupported address size");
+ }
+}
+
+static unsigned int
+size_of_encoded_value (unsigned char encoding)
+{
+ if (encoding == DW_EH_PE_omit)
+ return 0;
+
+ switch (encoding & 0x07)
+ {
+ case DW_EH_PE_absptr:
+ return TYPE_LENGTH (builtin_type_void_data_ptr);
+ case DW_EH_PE_udata2:
+ return 2;
+ case DW_EH_PE_udata4:
+ return 4;
+ case DW_EH_PE_udata8:
+ return 8;
+ default:
+ internal_error (__FILE__, __LINE__, "Invalid or unsupported encoding");
+ }
+}
+
+static CORE_ADDR
+read_encoded_value (struct comp_unit *unit, unsigned char encoding,
+ char *buf, unsigned int *bytes_read_ptr)
+{
+ int ptr_len = size_of_encoded_value (DW_EH_PE_absptr);
+ ptrdiff_t offset;
+ CORE_ADDR base;
+
+ /* GCC currently doesn't generate DW_EH_PE_indirect encodings for
+ FDE's. */
+ if (encoding & DW_EH_PE_indirect)
+ internal_error (__FILE__, __LINE__,
+ "Unsupported encoding: DW_EH_PE_indirect");
+
+ *bytes_read_ptr = 0;
+
+ switch (encoding & 0x70)
+ {
+ case DW_EH_PE_absptr:
+ base = 0;
+ break;
+ case DW_EH_PE_pcrel:
+ base = bfd_get_section_vma (unit->bfd, unit->dwarf_frame_section);
+ base += (buf - unit->dwarf_frame_buffer);
+ break;
+ case DW_EH_PE_datarel:
+ base = unit->dbase;
+ break;
+ case DW_EH_PE_textrel:
+ base = unit->tbase;
+ break;
+ case DW_EH_PE_funcrel:
+ /* FIXME: kettenis/20040501: For now just pretend
+ DW_EH_PE_funcrel is equivalent to DW_EH_PE_absptr. For
+ reading the initial location of an FDE it should be treated
+ as such, and currently that's the only place where this code
+ is used. */
+ base = 0;
+ break;
+ case DW_EH_PE_aligned:
+ base = 0;
+ offset = buf - unit->dwarf_frame_buffer;
+ if ((offset % ptr_len) != 0)
+ {
+ *bytes_read_ptr = ptr_len - (offset % ptr_len);
+ buf += *bytes_read_ptr;
+ }
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "Invalid or unsupported encoding");
+ }
+
+ if ((encoding & 0x0f) == 0x00)
+ encoding |= encoding_for_size (ptr_len);
+
+ switch (encoding & 0x0f)
+ {
+ case DW_EH_PE_udata2:
+ *bytes_read_ptr += 2;
+ return (base + bfd_get_16 (unit->abfd, (bfd_byte *) buf));
+ case DW_EH_PE_udata4:
+ *bytes_read_ptr += 4;
+ return (base + bfd_get_32 (unit->abfd, (bfd_byte *) buf));
+ case DW_EH_PE_udata8:
+ *bytes_read_ptr += 8;
+ return (base + bfd_get_64 (unit->abfd, (bfd_byte *) buf));
+ case DW_EH_PE_sdata2:
+ *bytes_read_ptr += 2;
+ return (base + bfd_get_signed_16 (unit->abfd, (bfd_byte *) buf));
+ case DW_EH_PE_sdata4:
+ *bytes_read_ptr += 4;
+ return (base + bfd_get_signed_32 (unit->abfd, (bfd_byte *) buf));
+ case DW_EH_PE_sdata8:
+ *bytes_read_ptr += 8;
+ return (base + bfd_get_signed_64 (unit->abfd, (bfd_byte *) buf));
+ default:
+ internal_error (__FILE__, __LINE__, "Invalid or unsupported encoding");
+ }
+}
+
+
+/* GCC uses a single CIE for all FDEs in a .debug_frame section.
+ That's why we use a simple linked list here. */
+
+static struct dwarf2_cie *
+find_cie (struct comp_unit *unit, ULONGEST cie_pointer)
+{
+ struct dwarf2_cie *cie = unit->cie;
+
+ while (cie)
+ {
+ if (cie->cie_pointer == cie_pointer)
+ return cie;
+
+ cie = cie->next;
+ }
+
+ return NULL;
+}
+
+static void
+add_cie (struct comp_unit *unit, struct dwarf2_cie *cie)
+{
+ cie->next = unit->cie;
+ unit->cie = cie;
+}
+
+/* Find the FDE for *PC. Return a pointer to the FDE, and store the
+ inital location associated with it into *PC. */
+
+static struct dwarf2_fde *
+dwarf2_frame_find_fde (CORE_ADDR *pc)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct dwarf2_fde *fde;
+ CORE_ADDR offset;
+
+ fde = objfile_data (objfile, dwarf2_frame_objfile_data);
+ if (fde == NULL)
+ continue;
+
+ gdb_assert (objfile->section_offsets);
+ offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ while (fde)
+ {
+ if (*pc >= fde->initial_location + offset
+ && *pc < fde->initial_location + offset + fde->address_range)
+ {
+ *pc = fde->initial_location + offset;
+ return fde;
+ }
+
+ fde = fde->next;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+add_fde (struct comp_unit *unit, struct dwarf2_fde *fde)
+{
+ fde->next = objfile_data (unit->objfile, dwarf2_frame_objfile_data);
+ set_objfile_data (unit->objfile, dwarf2_frame_objfile_data, fde);
+}
+
+#ifdef CC_HAS_LONG_LONG
+#define DW64_CIE_ID 0xffffffffffffffffULL
+#else
+#define DW64_CIE_ID ~0
+#endif
+
+static char *decode_frame_entry (struct comp_unit *unit, char *start,
+ int eh_frame_p);
+
+/* Decode the next CIE or FDE. Return NULL if invalid input, otherwise
+ the next byte to be processed. */
+static char *
+decode_frame_entry_1 (struct comp_unit *unit, char *start, int eh_frame_p)
+{
+ char *buf;
+ LONGEST length;
+ unsigned int bytes_read;
+ int dwarf64_p;
+ ULONGEST cie_id;
+ ULONGEST cie_pointer;
+ char *end;
+
+ buf = start;
+ length = read_initial_length (unit->abfd, buf, &bytes_read);
+ buf += bytes_read;
+ end = buf + length;
+
+ /* Are we still within the section? */
+ if (end > unit->dwarf_frame_buffer + unit->dwarf_frame_size)
+ return NULL;
+
+ if (length == 0)
+ return end;
+
+ /* Distinguish between 32 and 64-bit encoded frame info. */
+ dwarf64_p = (bytes_read == 12);
+
+ /* In a .eh_frame section, zero is used to distinguish CIEs from FDEs. */
+ if (eh_frame_p)
+ cie_id = 0;
+ else if (dwarf64_p)
+ cie_id = DW64_CIE_ID;
+ else
+ cie_id = DW_CIE_ID;
+
+ if (dwarf64_p)
+ {
+ cie_pointer = read_8_bytes (unit->abfd, buf);
+ buf += 8;
+ }
+ else
+ {
+ cie_pointer = read_4_bytes (unit->abfd, buf);
+ buf += 4;
+ }
+
+ if (cie_pointer == cie_id)
+ {
+ /* This is a CIE. */
+ struct dwarf2_cie *cie;
+ char *augmentation;
+
+ /* Record the offset into the .debug_frame section of this CIE. */
+ cie_pointer = start - unit->dwarf_frame_buffer;
+
+ /* Check whether we've already read it. */
+ if (find_cie (unit, cie_pointer))
+ return end;
+
+ cie = (struct dwarf2_cie *)
+ obstack_alloc (&unit->objfile->objfile_obstack,
+ sizeof (struct dwarf2_cie));
+ cie->initial_instructions = NULL;
+ cie->cie_pointer = cie_pointer;
+
+ /* The encoding for FDE's in a normal .debug_frame section
+ depends on the target address size as specified in the
+ Compilation Unit Header. */
+ cie->encoding = encoding_for_size (unit->addr_size);
+
+ /* Check version number. */
+ if (read_1_byte (unit->abfd, buf) != DW_CIE_VERSION)
+ return NULL;
+ buf += 1;
+
+ /* Interpret the interesting bits of the augmentation. */
+ augmentation = buf;
+ buf = augmentation + strlen (augmentation) + 1;
+
+ /* The GCC 2.x "eh" augmentation has a pointer immediately
+ following the augmentation string, so it must be handled
+ first. */
+ if (augmentation[0] == 'e' && augmentation[1] == 'h')
+ {
+ /* Skip. */
+ buf += TYPE_LENGTH (builtin_type_void_data_ptr);
+ augmentation += 2;
+ }
+
+ cie->code_alignment_factor =
+ read_unsigned_leb128 (unit->abfd, buf, &bytes_read);
+ buf += bytes_read;
+
+ cie->data_alignment_factor =
+ read_signed_leb128 (unit->abfd, buf, &bytes_read);
+ buf += bytes_read;
+
+ cie->return_address_register = read_1_byte (unit->abfd, buf);
+ buf += 1;
+
+ cie->saw_z_augmentation = (*augmentation == 'z');
+ if (cie->saw_z_augmentation)
+ {
+ ULONGEST length;
+
+ length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read);
+ buf += bytes_read;
+ if (buf > end)
+ return NULL;
+ cie->initial_instructions = buf + length;
+ augmentation++;
+ }
+
+ while (*augmentation)
+ {
+ /* "L" indicates a byte showing how the LSDA pointer is encoded. */
+ if (*augmentation == 'L')
+ {
+ /* Skip. */
+ buf++;
+ augmentation++;
+ }
+
+ /* "R" indicates a byte indicating how FDE addresses are encoded. */
+ else if (*augmentation == 'R')
+ {
+ cie->encoding = *buf++;
+ augmentation++;
+ }
+
+ /* "P" indicates a personality routine in the CIE augmentation. */
+ else if (*augmentation == 'P')
+ {
+ /* Skip. */
+ buf += size_of_encoded_value (*buf++);
+ augmentation++;
+ }
+
+ /* Otherwise we have an unknown augmentation.
+ Bail out unless we saw a 'z' prefix. */
+ else
+ {
+ if (cie->initial_instructions == NULL)
+ return end;
+
+ /* Skip unknown augmentations. */
+ buf = cie->initial_instructions;
+ break;
+ }
+ }
+
+ cie->initial_instructions = buf;
+ cie->end = end;
+
+ add_cie (unit, cie);
+ }
+ else
+ {
+ /* This is a FDE. */
+ struct dwarf2_fde *fde;
+
+ /* In an .eh_frame section, the CIE pointer is the delta between the
+ address within the FDE where the CIE pointer is stored and the
+ address of the CIE. Convert it to an offset into the .eh_frame
+ section. */
+ if (eh_frame_p)
+ {
+ cie_pointer = buf - unit->dwarf_frame_buffer - cie_pointer;
+ cie_pointer -= (dwarf64_p ? 8 : 4);
+ }
+
+ /* In either case, validate the result is still within the section. */
+ if (cie_pointer >= unit->dwarf_frame_size)
+ return NULL;
+
+ fde = (struct dwarf2_fde *)
+ obstack_alloc (&unit->objfile->objfile_obstack,
+ sizeof (struct dwarf2_fde));
+ fde->cie = find_cie (unit, cie_pointer);
+ if (fde->cie == NULL)
+ {
+ decode_frame_entry (unit, unit->dwarf_frame_buffer + cie_pointer,
+ eh_frame_p);
+ fde->cie = find_cie (unit, cie_pointer);
+ }
+
+ gdb_assert (fde->cie != NULL);
+
+ fde->initial_location =
+ read_encoded_value (unit, fde->cie->encoding, buf, &bytes_read);
+ buf += bytes_read;
+
+ fde->address_range =
+ read_encoded_value (unit, fde->cie->encoding & 0x0f, buf, &bytes_read);
+ buf += bytes_read;
+
+ /* A 'z' augmentation in the CIE implies the presence of an
+ augmentation field in the FDE as well. The only thing known
+ to be in here at present is the LSDA entry for EH. So we
+ can skip the whole thing. */
+ if (fde->cie->saw_z_augmentation)
+ {
+ ULONGEST length;
+
+ length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read);
+ buf += bytes_read + length;
+ if (buf > end)
+ return NULL;
+ }
+
+ fde->instructions = buf;
+ fde->end = end;
+
+ add_fde (unit, fde);
+ }
+
+ return end;
+}
+
+/* Read a CIE or FDE in BUF and decode it. */
+static char *
+decode_frame_entry (struct comp_unit *unit, char *start, int eh_frame_p)
+{
+ enum { NONE, ALIGN4, ALIGN8, FAIL } workaround = NONE;
+ char *ret;
+ const char *msg;
+ ptrdiff_t start_offset;
+
+ while (1)
+ {
+ ret = decode_frame_entry_1 (unit, start, eh_frame_p);
+ if (ret != NULL)
+ break;
+
+ /* We have corrupt input data of some form. */
+
+ /* ??? Try, weakly, to work around compiler/assembler/linker bugs
+ and mismatches wrt padding and alignment of debug sections. */
+ /* Note that there is no requirement in the standard for any
+ alignment at all in the frame unwind sections. Testing for
+ alignment before trying to interpret data would be incorrect.
+
+ However, GCC traditionally arranged for frame sections to be
+ sized such that the FDE length and CIE fields happen to be
+ aligned (in theory, for performance). This, unfortunately,
+ was done with .align directives, which had the side effect of
+ forcing the section to be aligned by the linker.
+
+ This becomes a problem when you have some other producer that
+ creates frame sections that are not as strictly aligned. That
+ produces a hole in the frame info that gets filled by the
+ linker with zeros.
+
+ The GCC behaviour is arguably a bug, but it's effectively now
+ part of the ABI, so we're now stuck with it, at least at the
+ object file level. A smart linker may decide, in the process
+ of compressing duplicate CIE information, that it can rewrite
+ the entire output section without this extra padding. */
+
+ start_offset = start - unit->dwarf_frame_buffer;
+ if (workaround < ALIGN4 && (start_offset & 3) != 0)
+ {
+ start += 4 - (start_offset & 3);
+ workaround = ALIGN4;
+ continue;
+ }
+ if (workaround < ALIGN8 && (start_offset & 7) != 0)
+ {
+ start += 8 - (start_offset & 7);
+ workaround = ALIGN8;
+ continue;
+ }
+
+ /* Nothing left to try. Arrange to return as if we've consumed
+ the entire input section. Hopefully we'll get valid info from
+ the other of .debug_frame/.eh_frame. */
+ workaround = FAIL;
+ ret = unit->dwarf_frame_buffer + unit->dwarf_frame_size;
+ break;
+ }
+
+ switch (workaround)
+ {
+ case NONE:
+ break;
+
+ case ALIGN4:
+ complaint (&symfile_complaints,
+ "Corrupt data in %s:%s; align 4 workaround apparently succeeded",
+ unit->dwarf_frame_section->owner->filename,
+ unit->dwarf_frame_section->name);
+ break;
+
+ case ALIGN8:
+ complaint (&symfile_complaints,
+ "Corrupt data in %s:%s; align 8 workaround apparently succeeded",
+ unit->dwarf_frame_section->owner->filename,
+ unit->dwarf_frame_section->name);
+ break;
+
+ default:
+ complaint (&symfile_complaints,
+ "Corrupt data in %s:%s",
+ unit->dwarf_frame_section->owner->filename,
+ unit->dwarf_frame_section->name);
+ break;
+ }
+
+ return ret;
+}
+
+
+/* FIXME: kettenis/20030504: This still needs to be integrated with
+ dwarf2read.c in a better way. */
+
+/* Imported from dwarf2read.c. */
+extern asection *dwarf_frame_section;
+extern asection *dwarf_eh_frame_section;
+
+/* Imported from dwarf2read.c. */
+extern char *dwarf2_read_section (struct objfile *objfile, asection *sectp);
+
+void
+dwarf2_build_frame_info (struct objfile *objfile)
+{
+ struct comp_unit unit;
+ char *frame_ptr;
+
+ /* Build a minimal decoding of the DWARF2 compilation unit. */
+ unit.abfd = objfile->obfd;
+ unit.objfile = objfile;
+ unit.addr_size = objfile->obfd->arch_info->bits_per_address / 8;
+ unit.dbase = 0;
+ unit.tbase = 0;
+
+ /* First add the information from the .eh_frame section. That way,
+ the FDEs from that section are searched last. */
+ if (dwarf_eh_frame_section)
+ {
+ asection *got, *txt;
+
+ unit.cie = NULL;
+ unit.dwarf_frame_buffer = dwarf2_read_section (objfile,
+ dwarf_eh_frame_section);
+
+ unit.dwarf_frame_size
+ = bfd_get_section_size_before_reloc (dwarf_eh_frame_section);
+ unit.dwarf_frame_section = dwarf_eh_frame_section;
+
+ /* FIXME: kettenis/20030602: This is the DW_EH_PE_datarel base
+ that is used for the i386/amd64 target, which currently is
+ the only target in GCC that supports/uses the
+ DW_EH_PE_datarel encoding. */
+ got = bfd_get_section_by_name (unit.abfd, ".got");
+ if (got)
+ unit.dbase = got->vma;
+
+ /* GCC emits the DW_EH_PE_textrel encoding type on sh and ia64
+ so far. */
+ txt = bfd_get_section_by_name (unit.abfd, ".text");
+ if (txt)
+ unit.tbase = txt->vma;
+
+ frame_ptr = unit.dwarf_frame_buffer;
+ while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size)
+ frame_ptr = decode_frame_entry (&unit, frame_ptr, 1);
+ }
+
+ if (dwarf_frame_section)
+ {
+ unit.cie = NULL;
+ unit.dwarf_frame_buffer = dwarf2_read_section (objfile,
+ dwarf_frame_section);
+ unit.dwarf_frame_size
+ = bfd_get_section_size_before_reloc (dwarf_frame_section);
+ unit.dwarf_frame_section = dwarf_frame_section;
+
+ frame_ptr = unit.dwarf_frame_buffer;
+ while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size)
+ frame_ptr = decode_frame_entry (&unit, frame_ptr, 0);
+ }
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_dwarf2_frame (void);
+
+void
+_initialize_dwarf2_frame (void)
+{
+ dwarf2_frame_data = register_gdbarch_data (dwarf2_frame_init);
+ dwarf2_frame_objfile_data = register_objfile_data ();
+}
diff --git a/contrib/gdb/gdb/dwarf2-frame.h b/contrib/gdb/gdb/dwarf2-frame.h
new file mode 100644
index 0000000..1ae44b5
--- /dev/null
+++ b/contrib/gdb/gdb/dwarf2-frame.h
@@ -0,0 +1,98 @@
+/* Frame unwinder for frames with DWARF Call Frame Information.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Mark Kettenis.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 DWARF2_FRAME_H
+#define DWARF2_FRAME_H 1
+
+struct gdbarch;
+struct objfile;
+struct frame_info;
+
+/* Register rule. */
+
+enum dwarf2_frame_reg_rule
+{
+ /* Make certain that 0 maps onto the correct enum value; the
+ corresponding structure is being initialized using memset zero.
+ This indicates that CFI didn't provide any information at all
+ about a register, leaving how to obtain its value totally
+ unspecified. */
+ DWARF2_FRAME_REG_UNSPECIFIED = 0,
+
+ /* The term "undefined" comes from the DWARF2 CFI spec which this
+ code is moddeling; it indicates that the register's value is
+ "undefined". GCC uses the less formal term "unsaved". Its
+ definition is a combination of REG_UNDEFINED and REG_UNSPECIFIED.
+ The failure to differentiate the two helps explain a few problems
+ with the CFI generated by GCC. */
+ DWARF2_FRAME_REG_UNDEFINED,
+ DWARF2_FRAME_REG_SAVED_OFFSET,
+ DWARF2_FRAME_REG_SAVED_REG,
+ DWARF2_FRAME_REG_SAVED_EXP,
+ DWARF2_FRAME_REG_SAME_VALUE,
+
+ /* These aren't defined by the DWARF2 CFI specification, but are
+ used internally by GDB. */
+ DWARF2_FRAME_REG_RA, /* Return Address. */
+ DWARF2_FRAME_REG_CFA /* Call Frame Address. */
+};
+
+/* Register state. */
+
+struct dwarf2_frame_state_reg
+{
+ /* Each register save state can be described in terms of a CFA slot,
+ another register, or a location expression. */
+ union {
+ LONGEST offset;
+ ULONGEST reg;
+ unsigned char *exp;
+ } loc;
+ ULONGEST exp_len;
+ enum dwarf2_frame_reg_rule how;
+};
+
+/* Set the architecture-specific register state initialization
+ function for GDBARCH to INIT_REG. */
+
+extern void dwarf2_frame_set_init_reg (struct gdbarch *gdbarch,
+ void (*init_reg) (struct gdbarch *, int,
+ struct dwarf2_frame_state_reg *));
+
+/* Return the frame unwind methods for the function that contains PC,
+ or NULL if it can't be handled by DWARF CFI frame unwinder. */
+
+extern const struct frame_unwind *
+ dwarf2_frame_sniffer (struct frame_info *next_frame);
+
+/* Return the frame base methods for the function that contains PC, or
+ NULL if it can't be handled by the DWARF CFI frame unwinder. */
+
+extern const struct frame_base *
+ dwarf2_frame_base_sniffer (struct frame_info *next_frame);
+
+/* Register the DWARF CFI for OBJFILE. */
+
+void dwarf2_frame_build_info (struct objfile *objfile);
+
+#endif /* dwarf2-frame.h */
diff --git a/contrib/gdb/gdb/dwarf2expr.c b/contrib/gdb/gdb/dwarf2expr.c
new file mode 100644
index 0000000..50baced
--- /dev/null
+++ b/contrib/gdb/gdb/dwarf2expr.c
@@ -0,0 +1,670 @@
+/* Dwarf2 Expression Evaluator
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Daniel Berlin (dan@dberlin.org)
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbcore.h"
+#include "elf/dwarf2.h"
+#include "dwarf2expr.h"
+
+/* Local prototypes. */
+
+static void execute_stack_op (struct dwarf_expr_context *,
+ unsigned char *, unsigned char *);
+
+/* Create a new context for the expression evaluator. */
+
+struct dwarf_expr_context *
+new_dwarf_expr_context (void)
+{
+ struct dwarf_expr_context *retval;
+ retval = xcalloc (1, sizeof (struct dwarf_expr_context));
+ retval->stack_len = 0;
+ retval->stack_allocated = 10;
+ retval->stack = xmalloc (retval->stack_allocated * sizeof (CORE_ADDR));
+ return retval;
+}
+
+/* Release the memory allocated to CTX. */
+
+void
+free_dwarf_expr_context (struct dwarf_expr_context *ctx)
+{
+ xfree (ctx->stack);
+ xfree (ctx);
+}
+
+/* Expand the memory allocated to CTX's stack to contain at least
+ NEED more elements than are currently used. */
+
+static void
+dwarf_expr_grow_stack (struct dwarf_expr_context *ctx, size_t need)
+{
+ if (ctx->stack_len + need > ctx->stack_allocated)
+ {
+ size_t newlen = ctx->stack_len + need + 10;
+ ctx->stack = xrealloc (ctx->stack,
+ newlen * sizeof (CORE_ADDR));
+ ctx->stack_allocated = newlen;
+ }
+}
+
+/* Push VALUE onto CTX's stack. */
+
+void
+dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value)
+{
+ dwarf_expr_grow_stack (ctx, 1);
+ ctx->stack[ctx->stack_len++] = value;
+}
+
+/* Pop the top item off of CTX's stack. */
+
+void
+dwarf_expr_pop (struct dwarf_expr_context *ctx)
+{
+ if (ctx->stack_len <= 0)
+ error ("dwarf expression stack underflow");
+ ctx->stack_len--;
+}
+
+/* Retrieve the N'th item on CTX's stack. */
+
+CORE_ADDR
+dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n)
+{
+ if (ctx->stack_len < n)
+ error ("Asked for position %d of stack, stack only has %d elements on it\n",
+ n, ctx->stack_len);
+ return ctx->stack[ctx->stack_len - (1 + n)];
+
+}
+
+/* Evaluate the expression at ADDR (LEN bytes long) using the context
+ CTX. */
+
+void
+dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr,
+ size_t len)
+{
+ execute_stack_op (ctx, addr, addr + len);
+}
+
+/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
+ by R, and return the new value of BUF. Verify that it doesn't extend
+ past BUF_END. */
+
+unsigned char *
+read_uleb128 (unsigned char *buf, unsigned char *buf_end, ULONGEST * r)
+{
+ unsigned shift = 0;
+ ULONGEST result = 0;
+ unsigned char byte;
+
+ while (1)
+ {
+ if (buf >= buf_end)
+ error ("read_uleb128: Corrupted DWARF expression.");
+
+ byte = *buf++;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ *r = result;
+ return buf;
+}
+
+/* Decode the signed LEB128 constant at BUF into the variable pointed to
+ by R, and return the new value of BUF. Verify that it doesn't extend
+ past BUF_END. */
+
+unsigned char *
+read_sleb128 (unsigned char *buf, unsigned char *buf_end, LONGEST * r)
+{
+ unsigned shift = 0;
+ LONGEST result = 0;
+ unsigned char byte;
+
+ while (1)
+ {
+ if (buf >= buf_end)
+ error ("read_sleb128: Corrupted DWARF expression.");
+
+ byte = *buf++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ if ((byte & 0x80) == 0)
+ break;
+ }
+ if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
+ result |= -(1 << shift);
+
+ *r = result;
+ return buf;
+}
+
+/* Read an address from BUF, and verify that it doesn't extend past
+ BUF_END. The address is returned, and *BYTES_READ is set to the
+ number of bytes read from BUF. */
+
+CORE_ADDR
+dwarf2_read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read)
+{
+ CORE_ADDR result;
+
+ if (buf_end - buf < TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+ error ("dwarf2_read_address: Corrupted DWARF expression.");
+
+ *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
+ /* NOTE: cagney/2003-05-22: This extract is assuming that a DWARF 2
+ address is always unsigned. That may or may not be true. */
+ result = extract_unsigned_integer (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ return result;
+}
+
+/* Return the type of an address, for unsigned arithmetic. */
+
+static struct type *
+unsigned_address_type (void)
+{
+ switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+ {
+ case 2:
+ return builtin_type_uint16;
+ case 4:
+ return builtin_type_uint32;
+ case 8:
+ return builtin_type_uint64;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "Unsupported address size.\n");
+ }
+}
+
+/* Return the type of an address, for signed arithmetic. */
+
+static struct type *
+signed_address_type (void)
+{
+ switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+ {
+ case 2:
+ return builtin_type_int16;
+ case 4:
+ return builtin_type_int32;
+ case 8:
+ return builtin_type_int64;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "Unsupported address size.\n");
+ }
+}
+
+/* The engine for the expression evaluator. Using the context in CTX,
+ evaluate the expression between OP_PTR and OP_END. */
+
+static void
+execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
+ unsigned char *op_end)
+{
+ ctx->in_reg = 0;
+
+ while (op_ptr < op_end)
+ {
+ enum dwarf_location_atom op = *op_ptr++;
+ CORE_ADDR result;
+ ULONGEST uoffset, reg;
+ LONGEST offset;
+ int bytes_read;
+
+ switch (op)
+ {
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ result = op - DW_OP_lit0;
+ break;
+
+ case DW_OP_addr:
+ result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
+ op_ptr += bytes_read;
+ break;
+
+ case DW_OP_const1u:
+ result = extract_unsigned_integer (op_ptr, 1);
+ op_ptr += 1;
+ break;
+ case DW_OP_const1s:
+ result = extract_signed_integer (op_ptr, 1);
+ op_ptr += 1;
+ break;
+ case DW_OP_const2u:
+ result = extract_unsigned_integer (op_ptr, 2);
+ op_ptr += 2;
+ break;
+ case DW_OP_const2s:
+ result = extract_signed_integer (op_ptr, 2);
+ op_ptr += 2;
+ break;
+ case DW_OP_const4u:
+ result = extract_unsigned_integer (op_ptr, 4);
+ op_ptr += 4;
+ break;
+ case DW_OP_const4s:
+ result = extract_signed_integer (op_ptr, 4);
+ op_ptr += 4;
+ break;
+ case DW_OP_const8u:
+ result = extract_unsigned_integer (op_ptr, 8);
+ op_ptr += 8;
+ break;
+ case DW_OP_const8s:
+ result = extract_signed_integer (op_ptr, 8);
+ op_ptr += 8;
+ break;
+ case DW_OP_constu:
+ op_ptr = read_uleb128 (op_ptr, op_end, &uoffset);
+ result = uoffset;
+ break;
+ case DW_OP_consts:
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ result = offset;
+ break;
+
+ /* The DW_OP_reg operations are required to occur alone in
+ location expressions. */
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ if (op_ptr != op_end && *op_ptr != DW_OP_piece)
+ error ("DWARF-2 expression error: DW_OP_reg operations must be "
+ "used either alone or in conjuction with DW_OP_piece.");
+
+ result = op - DW_OP_reg0;
+ ctx->in_reg = 1;
+
+ break;
+
+ case DW_OP_regx:
+ op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+ if (op_ptr != op_end && *op_ptr != DW_OP_piece)
+ error ("DWARF-2 expression error: DW_OP_reg operations must be "
+ "used either alone or in conjuction with DW_OP_piece.");
+
+ result = reg;
+ ctx->in_reg = 1;
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ {
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ result = (ctx->read_reg) (ctx->baton, op - DW_OP_breg0);
+ result += offset;
+ }
+ break;
+ case DW_OP_bregx:
+ {
+ op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ result = (ctx->read_reg) (ctx->baton, reg);
+ result += offset;
+ }
+ break;
+ case DW_OP_fbreg:
+ {
+ unsigned char *datastart;
+ size_t datalen;
+ unsigned int before_stack_len;
+
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ /* Rather than create a whole new context, we simply
+ record the stack length before execution, then reset it
+ afterwards, effectively erasing whatever the recursive
+ call put there. */
+ before_stack_len = ctx->stack_len;
+ /* FIXME: cagney/2003-03-26: This code should be using
+ get_frame_base_address(), and then implement a dwarf2
+ specific this_base method. */
+ (ctx->get_frame_base) (ctx->baton, &datastart, &datalen);
+ dwarf_expr_eval (ctx, datastart, datalen);
+ result = dwarf_expr_fetch (ctx, 0);
+ if (ctx->in_reg)
+ result = (ctx->read_reg) (ctx->baton, result);
+ result = result + offset;
+ ctx->stack_len = before_stack_len;
+ ctx->in_reg = 0;
+ }
+ break;
+ case DW_OP_dup:
+ result = dwarf_expr_fetch (ctx, 0);
+ break;
+
+ case DW_OP_drop:
+ dwarf_expr_pop (ctx);
+ goto no_push;
+
+ case DW_OP_pick:
+ offset = *op_ptr++;
+ result = dwarf_expr_fetch (ctx, offset);
+ break;
+
+ case DW_OP_over:
+ result = dwarf_expr_fetch (ctx, 1);
+ break;
+
+ case DW_OP_rot:
+ {
+ CORE_ADDR t1, t2, t3;
+
+ if (ctx->stack_len < 3)
+ error ("Not enough elements for DW_OP_rot. Need 3, have %d\n",
+ ctx->stack_len);
+ t1 = ctx->stack[ctx->stack_len - 1];
+ t2 = ctx->stack[ctx->stack_len - 2];
+ t3 = ctx->stack[ctx->stack_len - 3];
+ ctx->stack[ctx->stack_len - 1] = t2;
+ ctx->stack[ctx->stack_len - 2] = t3;
+ ctx->stack[ctx->stack_len - 3] = t1;
+ goto no_push;
+ }
+
+ case DW_OP_deref:
+ case DW_OP_deref_size:
+ case DW_OP_abs:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_plus_uconst:
+ /* Unary operations. */
+ result = dwarf_expr_fetch (ctx, 0);
+ dwarf_expr_pop (ctx);
+
+ switch (op)
+ {
+ case DW_OP_deref:
+ {
+ char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ int bytes_read;
+
+ (ctx->read_mem) (ctx->baton, buf, result,
+ TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ result = dwarf2_read_address (buf,
+ buf + (TARGET_ADDR_BIT
+ / TARGET_CHAR_BIT),
+ &bytes_read);
+ }
+ break;
+
+ case DW_OP_deref_size:
+ {
+ char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ int bytes_read;
+
+ (ctx->read_mem) (ctx->baton, buf, result, *op_ptr++);
+ result = dwarf2_read_address (buf,
+ buf + (TARGET_ADDR_BIT
+ / TARGET_CHAR_BIT),
+ &bytes_read);
+ }
+ break;
+
+ case DW_OP_abs:
+ if ((signed int) result < 0)
+ result = -result;
+ break;
+ case DW_OP_neg:
+ result = -result;
+ break;
+ case DW_OP_not:
+ result = ~result;
+ break;
+ case DW_OP_plus_uconst:
+ op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+ result += reg;
+ break;
+ }
+ break;
+
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_or:
+ case DW_OP_plus:
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ case DW_OP_le:
+ case DW_OP_ge:
+ case DW_OP_eq:
+ case DW_OP_lt:
+ case DW_OP_gt:
+ case DW_OP_ne:
+ {
+ /* Binary operations. Use the value engine to do computations in
+ the right width. */
+ CORE_ADDR first, second;
+ enum exp_opcode binop;
+ struct value *val1, *val2;
+
+ second = dwarf_expr_fetch (ctx, 0);
+ dwarf_expr_pop (ctx);
+
+ first = dwarf_expr_fetch (ctx, 0);
+ dwarf_expr_pop (ctx);
+
+ val1 = value_from_longest (unsigned_address_type (), first);
+ val2 = value_from_longest (unsigned_address_type (), second);
+
+ switch (op)
+ {
+ case DW_OP_and:
+ binop = BINOP_BITWISE_AND;
+ break;
+ case DW_OP_div:
+ binop = BINOP_DIV;
+ case DW_OP_minus:
+ binop = BINOP_SUB;
+ break;
+ case DW_OP_mod:
+ binop = BINOP_MOD;
+ break;
+ case DW_OP_mul:
+ binop = BINOP_MUL;
+ break;
+ case DW_OP_or:
+ binop = BINOP_BITWISE_IOR;
+ break;
+ case DW_OP_plus:
+ binop = BINOP_ADD;
+ break;
+ case DW_OP_shl:
+ binop = BINOP_LSH;
+ break;
+ case DW_OP_shr:
+ binop = BINOP_RSH;
+ case DW_OP_shra:
+ binop = BINOP_RSH;
+ val1 = value_from_longest (signed_address_type (), first);
+ break;
+ case DW_OP_xor:
+ binop = BINOP_BITWISE_XOR;
+ break;
+ case DW_OP_le:
+ binop = BINOP_LEQ;
+ break;
+ case DW_OP_ge:
+ binop = BINOP_GEQ;
+ break;
+ case DW_OP_eq:
+ binop = BINOP_EQUAL;
+ break;
+ case DW_OP_lt:
+ binop = BINOP_LESS;
+ break;
+ case DW_OP_gt:
+ binop = BINOP_GTR;
+ break;
+ case DW_OP_ne:
+ binop = BINOP_NOTEQUAL;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "Can't be reached.");
+ }
+ result = value_as_long (value_binop (val1, val2, binop));
+ }
+ break;
+
+ case DW_OP_GNU_push_tls_address:
+ /* Variable is at a constant offset in the thread-local
+ storage block into the objfile for the current thread and
+ the dynamic linker module containing this expression. Here
+ we return returns the offset from that base. The top of the
+ stack has the offset from the beginning of the thread
+ control block at which the variable is located. Nothing
+ should follow this operator, so the top of stack would be
+ returned. */
+ result = dwarf_expr_fetch (ctx, 0);
+ dwarf_expr_pop (ctx);
+ result = (ctx->get_tls_address) (ctx->baton, result);
+ break;
+
+ case DW_OP_skip:
+ offset = extract_signed_integer (op_ptr, 2);
+ op_ptr += 2;
+ op_ptr += offset;
+ goto no_push;
+
+ case DW_OP_bra:
+ offset = extract_signed_integer (op_ptr, 2);
+ op_ptr += 2;
+ if (dwarf_expr_fetch (ctx, 0) != 0)
+ op_ptr += offset;
+ dwarf_expr_pop (ctx);
+ goto no_push;
+
+ case DW_OP_nop:
+ goto no_push;
+
+ default:
+ error ("Unhandled dwarf expression opcode 0x%x", op);
+ }
+
+ /* Most things push a result value. */
+ dwarf_expr_push (ctx, result);
+ no_push:;
+ }
+}
diff --git a/contrib/gdb/gdb/dwarf2expr.h b/contrib/gdb/gdb/dwarf2expr.h
new file mode 100644
index 0000000..0a60edb
--- /dev/null
+++ b/contrib/gdb/gdb/dwarf2expr.h
@@ -0,0 +1,96 @@
+/* Dwarf2 Expression Evaluator
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Daniel Berlin (dan@dberlin.org)
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (DWARF2EXPR_H)
+#define DWARF2EXPR_H
+
+/* The expression evaluator works with a dwarf_expr_context, describing
+ its current state and its callbacks. */
+struct dwarf_expr_context
+{
+ /* The stack of values, allocated with xmalloc. */
+ CORE_ADDR *stack;
+
+ /* The number of values currently pushed on the stack, and the
+ number of elements allocated to the stack. */
+ int stack_len, stack_allocated;
+
+ /* An opaque argument provided by the caller, which will be passed
+ to all of the callback functions. */
+ void *baton;
+
+ /* Return the value of register number REGNUM. */
+ CORE_ADDR (*read_reg) (void *baton, int regnum);
+
+ /* Read LENGTH bytes at ADDR into BUF. */
+ void (*read_mem) (void *baton, char *buf, CORE_ADDR addr,
+ size_t length);
+
+ /* Return the location expression for the frame base attribute, in
+ START and LENGTH. The result must be live until the current
+ expression evaluation is complete. */
+ void (*get_frame_base) (void *baton, unsigned char **start,
+ size_t *length);
+
+ /* Return the thread-local storage address for
+ DW_OP_GNU_push_tls_address. */
+ CORE_ADDR (*get_tls_address) (void *baton, CORE_ADDR offset);
+
+#if 0
+ /* Not yet implemented. */
+
+ /* Return the location expression for the dwarf expression
+ subroutine in the die at OFFSET in the current compilation unit.
+ The result must be live until the current expression evaluation
+ is complete. */
+ unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length);
+
+ /* Return the `object address' for DW_OP_push_object_address. */
+ CORE_ADDR (*get_object_address) (void *baton);
+#endif
+
+ /* The current depth of dwarf expression recursion, via DW_OP_call*,
+ DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum
+ depth we'll tolerate before raising an error. */
+ int recursion_depth, max_recursion_depth;
+
+ /* Non-zero if the result is in a register. The register number
+ will be on the expression stack. */
+ int in_reg;
+};
+
+struct dwarf_expr_context *new_dwarf_expr_context (void);
+void free_dwarf_expr_context (struct dwarf_expr_context *ctx);
+
+void dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value);
+void dwarf_expr_pop (struct dwarf_expr_context *ctx);
+void dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr,
+ size_t len);
+CORE_ADDR dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n);
+
+
+unsigned char *read_uleb128 (unsigned char *buf, unsigned char *buf_end,
+ ULONGEST * r);
+unsigned char *read_sleb128 (unsigned char *buf, unsigned char *buf_end,
+ LONGEST * r);
+CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end,
+ int *bytes_read);
+
+#endif
diff --git a/contrib/gdb/gdb/dwarf2loc.c b/contrib/gdb/gdb/dwarf2loc.c
new file mode 100644
index 0000000..cdbeb10
--- /dev/null
+++ b/contrib/gdb/gdb/dwarf2loc.c
@@ -0,0 +1,548 @@
+/* DWARF 2 location expression support for GDB.
+ Copyright 2003 Free Software Foundation, Inc.
+ Contributed by Daniel Jacobowitz, MontaVista Software, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ui-out.h"
+#include "value.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "inferior.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "regcache.h"
+#include "objfiles.h"
+
+#include "elf/dwarf2.h"
+#include "dwarf2expr.h"
+#include "dwarf2loc.h"
+
+#include "gdb_string.h"
+
+#ifndef DWARF2_REG_TO_REGNUM
+#define DWARF2_REG_TO_REGNUM(REG) (REG)
+#endif
+
+/* A helper function for dealing with location lists. Given a
+ symbol baton (BATON) and a pc value (PC), find the appropriate
+ location expression, set *LOCEXPR_LENGTH, and return a pointer
+ to the beginning of the expression. Returns NULL on failure.
+
+ For now, only return the first matching location expression; there
+ can be more than one in the list. */
+
+static char *
+find_location_expression (struct dwarf2_loclist_baton *baton,
+ size_t *locexpr_length, CORE_ADDR pc)
+{
+ CORE_ADDR low, high;
+ char *loc_ptr, *buf_end;
+ unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
+ CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+ /* Adjust base_address for relocatable objects. */
+ CORE_ADDR base_offset = ANOFFSET (baton->objfile->section_offsets,
+ SECT_OFF_TEXT (baton->objfile));
+ CORE_ADDR base_address = baton->base_address + base_offset;
+
+ loc_ptr = baton->data;
+ buf_end = baton->data + baton->size;
+
+ while (1)
+ {
+ low = dwarf2_read_address (loc_ptr, buf_end, &length);
+ loc_ptr += length;
+ high = dwarf2_read_address (loc_ptr, buf_end, &length);
+ loc_ptr += length;
+
+ /* An end-of-list entry. */
+ if (low == 0 && high == 0)
+ return NULL;
+
+ /* A base-address-selection entry. */
+ if ((low & base_mask) == base_mask)
+ {
+ base_address = high;
+ continue;
+ }
+
+ /* Otherwise, a location expression entry. */
+ low += base_address;
+ high += base_address;
+
+ length = extract_unsigned_integer (loc_ptr, 2);
+ loc_ptr += 2;
+
+ if (pc >= low && pc < high)
+ {
+ *locexpr_length = length;
+ return loc_ptr;
+ }
+
+ loc_ptr += length;
+ }
+}
+
+/* This is the baton used when performing dwarf2 expression
+ evaluation. */
+struct dwarf_expr_baton
+{
+ struct frame_info *frame;
+ struct objfile *objfile;
+};
+
+/* Helper functions for dwarf2_evaluate_loc_desc. */
+
+/* Using the frame specified in BATON, read register REGNUM. The lval
+ type will be returned in LVALP, and for lval_memory the register
+ save address will be returned in ADDRP. */
+static CORE_ADDR
+dwarf_expr_read_reg (void *baton, int dwarf_regnum)
+{
+ struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
+ CORE_ADDR result, save_addr;
+ enum lval_type lval_type;
+ char *buf;
+ int optimized, regnum, realnum, regsize;
+
+ regnum = DWARF2_REG_TO_REGNUM (dwarf_regnum);
+ regsize = register_size (current_gdbarch, regnum);
+ buf = (char *) alloca (regsize);
+
+ frame_register (debaton->frame, regnum, &optimized, &lval_type, &save_addr,
+ &realnum, buf);
+ /* NOTE: cagney/2003-05-22: This extract is assuming that a DWARF 2
+ address is always unsigned. That may or may not be true. */
+ result = extract_unsigned_integer (buf, regsize);
+
+ return result;
+}
+
+/* Read memory at ADDR (length LEN) into BUF. */
+
+static void
+dwarf_expr_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len)
+{
+ read_memory (addr, buf, len);
+}
+
+/* Using the frame specified in BATON, find the location expression
+ describing the frame base. Return a pointer to it in START and
+ its length in LENGTH. */
+static void
+dwarf_expr_frame_base (void *baton, unsigned char **start, size_t * length)
+{
+ /* FIXME: cagney/2003-03-26: This code should be using
+ get_frame_base_address(), and then implement a dwarf2 specific
+ this_base method. */
+ struct symbol *framefunc;
+ struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
+
+ framefunc = get_frame_function (debaton->frame);
+
+ if (SYMBOL_OPS (framefunc) == &dwarf2_loclist_funcs)
+ {
+ struct dwarf2_loclist_baton *symbaton;
+ symbaton = SYMBOL_LOCATION_BATON (framefunc);
+ *start = find_location_expression (symbaton, length,
+ get_frame_pc (debaton->frame));
+ }
+ else
+ {
+ struct dwarf2_locexpr_baton *symbaton;
+ symbaton = SYMBOL_LOCATION_BATON (framefunc);
+ *length = symbaton->size;
+ *start = symbaton->data;
+ }
+
+ if (*start == NULL)
+ error ("Could not find the frame base for \"%s\".",
+ SYMBOL_NATURAL_NAME (framefunc));
+}
+
+/* Using the objfile specified in BATON, find the address for the
+ current thread's thread-local storage with offset OFFSET. */
+static CORE_ADDR
+dwarf_expr_tls_address (void *baton, CORE_ADDR offset)
+{
+ struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
+ CORE_ADDR addr;
+
+ if (target_get_thread_local_address_p ())
+ addr = target_get_thread_local_address (inferior_ptid,
+ debaton->objfile,
+ offset);
+ /* It wouldn't be wrong here to try a gdbarch method, too; finding
+ TLS is an ABI-specific thing. But we don't do that yet. */
+ else
+ error ("Cannot find thread-local variables on this target");
+
+ return addr;
+}
+
+/* Evaluate a location description, starting at DATA and with length
+ SIZE, to find the current location of variable VAR in the context
+ of FRAME. */
+static struct value *
+dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
+ unsigned char *data, unsigned short size,
+ struct objfile *objfile)
+{
+ CORE_ADDR result;
+ struct value *retval;
+ struct dwarf_expr_baton baton;
+ struct dwarf_expr_context *ctx;
+
+ if (size == 0)
+ {
+ retval = allocate_value (SYMBOL_TYPE (var));
+ VALUE_LVAL (retval) = not_lval;
+ VALUE_OPTIMIZED_OUT (retval) = 1;
+ }
+
+ baton.frame = frame;
+ baton.objfile = objfile;
+
+ ctx = new_dwarf_expr_context ();
+ ctx->baton = &baton;
+ ctx->read_reg = dwarf_expr_read_reg;
+ ctx->read_mem = dwarf_expr_read_mem;
+ ctx->get_frame_base = dwarf_expr_frame_base;
+ ctx->get_tls_address = dwarf_expr_tls_address;
+
+ dwarf_expr_eval (ctx, data, size);
+ result = dwarf_expr_fetch (ctx, 0);
+
+ if (ctx->in_reg)
+ {
+ int regnum = DWARF2_REG_TO_REGNUM (result);
+ retval = value_from_register (SYMBOL_TYPE (var), regnum, frame);
+ }
+ else
+ {
+ retval = allocate_value (SYMBOL_TYPE (var));
+ VALUE_BFD_SECTION (retval) = SYMBOL_BFD_SECTION (var);
+
+ VALUE_LVAL (retval) = lval_memory;
+ VALUE_LAZY (retval) = 1;
+ VALUE_ADDRESS (retval) = result;
+ }
+
+ free_dwarf_expr_context (ctx);
+
+ return retval;
+}
+
+
+
+
+
+/* Helper functions and baton for dwarf2_loc_desc_needs_frame. */
+
+struct needs_frame_baton
+{
+ int needs_frame;
+};
+
+/* Reads from registers do require a frame. */
+static CORE_ADDR
+needs_frame_read_reg (void *baton, int regnum)
+{
+ struct needs_frame_baton *nf_baton = baton;
+ nf_baton->needs_frame = 1;
+ return 1;
+}
+
+/* Reads from memory do not require a frame. */
+static void
+needs_frame_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len)
+{
+ memset (buf, 0, len);
+}
+
+/* Frame-relative accesses do require a frame. */
+static void
+needs_frame_frame_base (void *baton, unsigned char **start, size_t * length)
+{
+ static char lit0 = DW_OP_lit0;
+ struct needs_frame_baton *nf_baton = baton;
+
+ *start = &lit0;
+ *length = 1;
+
+ nf_baton->needs_frame = 1;
+}
+
+/* Thread-local accesses do require a frame. */
+static CORE_ADDR
+needs_frame_tls_address (void *baton, CORE_ADDR offset)
+{
+ struct needs_frame_baton *nf_baton = baton;
+ nf_baton->needs_frame = 1;
+ return 1;
+}
+
+/* Return non-zero iff the location expression at DATA (length SIZE)
+ requires a frame to evaluate. */
+
+static int
+dwarf2_loc_desc_needs_frame (unsigned char *data, unsigned short size)
+{
+ struct needs_frame_baton baton;
+ struct dwarf_expr_context *ctx;
+ int in_reg;
+
+ baton.needs_frame = 0;
+
+ ctx = new_dwarf_expr_context ();
+ ctx->baton = &baton;
+ ctx->read_reg = needs_frame_read_reg;
+ ctx->read_mem = needs_frame_read_mem;
+ ctx->get_frame_base = needs_frame_frame_base;
+ ctx->get_tls_address = needs_frame_tls_address;
+
+ dwarf_expr_eval (ctx, data, size);
+
+ in_reg = ctx->in_reg;
+
+ free_dwarf_expr_context (ctx);
+
+ return baton.needs_frame || in_reg;
+}
+
+static void
+dwarf2_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+ struct axs_value * value, unsigned char *data,
+ int size)
+{
+ if (size == 0)
+ error ("Symbol \"%s\" has been optimized out.",
+ SYMBOL_PRINT_NAME (symbol));
+
+ if (size == 1
+ && data[0] >= DW_OP_reg0
+ && data[0] <= DW_OP_reg31)
+ {
+ value->kind = axs_lvalue_register;
+ value->u.reg = data[0] - DW_OP_reg0;
+ }
+ else if (data[0] == DW_OP_regx)
+ {
+ ULONGEST reg;
+ read_uleb128 (data + 1, data + size, &reg);
+ value->kind = axs_lvalue_register;
+ value->u.reg = reg;
+ }
+ else if (data[0] == DW_OP_fbreg)
+ {
+ /* And this is worse than just minimal; we should honor the frame base
+ as above. */
+ int frame_reg;
+ LONGEST frame_offset;
+ unsigned char *buf_end;
+
+ buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
+ if (buf_end != data + size)
+ error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
+ SYMBOL_PRINT_NAME (symbol));
+
+ TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+ ax_reg (ax, frame_reg);
+ ax_const_l (ax, frame_offset);
+ ax_simple (ax, aop_add);
+
+ ax_const_l (ax, frame_offset);
+ ax_simple (ax, aop_add);
+ value->kind = axs_lvalue_memory;
+ }
+ else
+ error ("Unsupported DWARF opcode in the location of \"%s\".",
+ SYMBOL_PRINT_NAME (symbol));
+}
+
+/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
+ evaluator to calculate the location. */
+static struct value *
+locexpr_read_variable (struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+ struct value *val;
+ val = dwarf2_evaluate_loc_desc (symbol, frame, dlbaton->data, dlbaton->size,
+ dlbaton->objfile);
+
+ return val;
+}
+
+/* Return non-zero iff we need a frame to evaluate SYMBOL. */
+static int
+locexpr_read_needs_frame (struct symbol *symbol)
+{
+ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+ return dwarf2_loc_desc_needs_frame (dlbaton->data, dlbaton->size);
+}
+
+/* Print a natural-language description of SYMBOL to STREAM. */
+static int
+locexpr_describe_location (struct symbol *symbol, struct ui_file *stream)
+{
+ /* FIXME: be more extensive. */
+ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ if (dlbaton->size == 1
+ && dlbaton->data[0] >= DW_OP_reg0
+ && dlbaton->data[0] <= DW_OP_reg31)
+ {
+ int regno = DWARF2_REG_TO_REGNUM (dlbaton->data[0] - DW_OP_reg0);
+ fprintf_filtered (stream,
+ "a variable in register %s", REGISTER_NAME (regno));
+ return 1;
+ }
+
+ /* The location expression for a TLS variable looks like this (on a
+ 64-bit LE machine):
+
+ DW_AT_location : 10 byte block: 3 4 0 0 0 0 0 0 0 e0
+ (DW_OP_addr: 4; DW_OP_GNU_push_tls_address)
+
+ 0x3 is the encoding for DW_OP_addr, which has an operand as long
+ as the size of an address on the target machine (here is 8
+ bytes). 0xe0 is the encoding for DW_OP_GNU_push_tls_address.
+ The operand represents the offset at which the variable is within
+ the thread local storage. */
+
+ if (dlbaton->size > 1
+ && dlbaton->data[dlbaton->size - 1] == DW_OP_GNU_push_tls_address)
+ if (dlbaton->data[0] == DW_OP_addr)
+ {
+ int bytes_read;
+ CORE_ADDR offset = dwarf2_read_address (&dlbaton->data[1],
+ &dlbaton->data[dlbaton->size - 1],
+ &bytes_read);
+ fprintf_filtered (stream,
+ "a thread-local variable at offset %s in the "
+ "thread-local storage for `%s'",
+ paddr_nz (offset), dlbaton->objfile->name);
+ return 1;
+ }
+
+
+ fprintf_filtered (stream,
+ "a variable with complex or multiple locations (DWARF2)");
+ return 1;
+}
+
+
+/* Describe the location of SYMBOL as an agent value in VALUE, generating
+ any necessary bytecode in AX.
+
+ NOTE drow/2003-02-26: This function is extremely minimal, because
+ doing it correctly is extremely complicated and there is no
+ publicly available stub with tracepoint support for me to test
+ against. When there is one this function should be revisited. */
+
+static void
+locexpr_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+ struct axs_value * value)
+{
+ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ dwarf2_tracepoint_var_ref (symbol, ax, value, dlbaton->data, dlbaton->size);
+}
+
+/* The set of location functions used with the DWARF-2 expression
+ evaluator. */
+const struct symbol_ops dwarf2_locexpr_funcs = {
+ locexpr_read_variable,
+ locexpr_read_needs_frame,
+ locexpr_describe_location,
+ locexpr_tracepoint_var_ref
+};
+
+
+/* Wrapper functions for location lists. These generally find
+ the appropriate location expression and call something above. */
+
+/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
+ evaluator to calculate the location. */
+static struct value *
+loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+ struct value *val;
+ unsigned char *data;
+ size_t size;
+
+ data = find_location_expression (dlbaton, &size,
+ frame ? get_frame_pc (frame) : 0);
+ if (data == NULL)
+ error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+ val = dwarf2_evaluate_loc_desc (symbol, frame, data, size, dlbaton->objfile);
+
+ return val;
+}
+
+/* Return non-zero iff we need a frame to evaluate SYMBOL. */
+static int
+loclist_read_needs_frame (struct symbol *symbol)
+{
+ /* If there's a location list, then assume we need to have a frame
+ to choose the appropriate location expression. With tracking of
+ global variables this is not necessarily true, but such tracking
+ is disabled in GCC at the moment until we figure out how to
+ represent it. */
+
+ return 1;
+}
+
+/* Print a natural-language description of SYMBOL to STREAM. */
+static int
+loclist_describe_location (struct symbol *symbol, struct ui_file *stream)
+{
+ /* FIXME: Could print the entire list of locations. */
+ fprintf_filtered (stream, "a variable with multiple locations");
+ return 1;
+}
+
+/* Describe the location of SYMBOL as an agent value in VALUE, generating
+ any necessary bytecode in AX. */
+static void
+loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+ struct axs_value * value)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+ unsigned char *data;
+ size_t size;
+
+ data = find_location_expression (dlbaton, &size, ax->scope);
+ if (data == NULL)
+ error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+ dwarf2_tracepoint_var_ref (symbol, ax, value, data, size);
+}
+
+/* The set of location functions used with the DWARF-2 expression
+ evaluator and location lists. */
+const struct symbol_ops dwarf2_loclist_funcs = {
+ loclist_read_variable,
+ loclist_read_needs_frame,
+ loclist_describe_location,
+ loclist_tracepoint_var_ref
+};
diff --git a/contrib/gdb/gdb/dwarf2loc.h b/contrib/gdb/gdb/dwarf2loc.h
new file mode 100644
index 0000000..ce0a8ef
--- /dev/null
+++ b/contrib/gdb/gdb/dwarf2loc.h
@@ -0,0 +1,70 @@
+/* Dwarf2 location expression support for GDB.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (DWARF2LOC_H)
+#define DWARF2LOC_H
+
+struct symbol_ops;
+
+/* This header is private to the DWARF-2 reader. It is shared between
+ dwarf2read.c and dwarf2loc.c. */
+
+/* The symbol location baton types used by the DWARF-2 reader (i.e.
+ SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol). "struct
+ dwarf2_locexpr_baton" is for a symbol with a single location
+ expression; "struct dwarf2_loclist_baton" is for a symbol with a
+ location list. */
+
+struct dwarf2_locexpr_baton
+{
+ /* Pointer to the start of the location expression. */
+ unsigned char *data;
+
+ /* Length of the location expression. */
+ unsigned short size;
+
+ /* The objfile containing the symbol whose location we're computing. */
+ struct objfile *objfile;
+};
+
+struct dwarf2_loclist_baton
+{
+ /* The initial base address for the location list, based on the compilation
+ unit. */
+ CORE_ADDR base_address;
+
+ /* Pointer to the start of the location list. */
+ unsigned char *data;
+
+ /* Length of the location list. */
+ unsigned short size;
+
+ /* The objfile containing the symbol whose location we're computing. */
+ /* Used (only???) by thread local variables. The objfile in which
+ this symbol is defined. To find a thread-local variable (e.g., a
+ variable declared with the `__thread' storage class), we may need
+ to know which object file it's in. */
+ struct objfile *objfile;
+};
+
+extern const struct symbol_ops dwarf2_locexpr_funcs;
+extern const struct symbol_ops dwarf2_loclist_funcs;
+
+#endif
diff --git a/contrib/gdb/gdb/dwarf2read.c b/contrib/gdb/gdb/dwarf2read.c
new file mode 100644
index 0000000..cc69ede
--- /dev/null
+++ b/contrib/gdb/gdb/dwarf2read.c
@@ -0,0 +1,8067 @@
+/* DWARF 2 debugging format support for GDB.
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004
+ Free Software Foundation, Inc.
+
+ Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
+ Inc. with support from Florida State University (under contract
+ with the Ada Joint Program Office), and Silicon Graphics, Inc.
+ Initial contribution by Brent Benson, Harris Computer Systems, Inc.,
+ based on Fred Fish's (Cygnus Support) implementation of DWARF 1
+ support in dwarfread.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. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "objfiles.h"
+#include "elf/dwarf2.h"
+#include "buildsym.h"
+#include "demangle.h"
+#include "expression.h"
+#include "filenames.h" /* for DOSish file names */
+#include "macrotab.h"
+#include "language.h"
+#include "complaints.h"
+#include "bcache.h"
+#include "dwarf2expr.h"
+#include "dwarf2loc.h"
+#include "cp-support.h"
+
+#include <fcntl.h>
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include <sys/types.h>
+
+#ifndef DWARF2_REG_TO_REGNUM
+#define DWARF2_REG_TO_REGNUM(REG) (REG)
+#endif
+
+#if 0
+/* .debug_info header for a compilation unit
+ Because of alignment constraints, this structure has padding and cannot
+ be mapped directly onto the beginning of the .debug_info section. */
+typedef struct comp_unit_header
+ {
+ unsigned int length; /* length of the .debug_info
+ contribution */
+ unsigned short version; /* version number -- 2 for DWARF
+ version 2 */
+ unsigned int abbrev_offset; /* offset into .debug_abbrev section */
+ unsigned char addr_size; /* byte size of an address -- 4 */
+ }
+_COMP_UNIT_HEADER;
+#define _ACTUAL_COMP_UNIT_HEADER_SIZE 11
+#endif
+
+/* .debug_pubnames header
+ Because of alignment constraints, this structure has padding and cannot
+ be mapped directly onto the beginning of the .debug_info section. */
+typedef struct pubnames_header
+ {
+ unsigned int length; /* length of the .debug_pubnames
+ contribution */
+ unsigned char version; /* version number -- 2 for DWARF
+ version 2 */
+ unsigned int info_offset; /* offset into .debug_info section */
+ unsigned int info_size; /* byte size of .debug_info section
+ portion */
+ }
+_PUBNAMES_HEADER;
+#define _ACTUAL_PUBNAMES_HEADER_SIZE 13
+
+/* .debug_pubnames header
+ Because of alignment constraints, this structure has padding and cannot
+ be mapped directly onto the beginning of the .debug_info section. */
+typedef struct aranges_header
+ {
+ unsigned int length; /* byte len of the .debug_aranges
+ contribution */
+ unsigned short version; /* version number -- 2 for DWARF
+ version 2 */
+ unsigned int info_offset; /* offset into .debug_info section */
+ unsigned char addr_size; /* byte size of an address */
+ unsigned char seg_size; /* byte size of segment descriptor */
+ }
+_ARANGES_HEADER;
+#define _ACTUAL_ARANGES_HEADER_SIZE 12
+
+/* .debug_line statement program prologue
+ Because of alignment constraints, this structure has padding and cannot
+ be mapped directly onto the beginning of the .debug_info section. */
+typedef struct statement_prologue
+ {
+ unsigned int total_length; /* byte length of the statement
+ information */
+ unsigned short version; /* version number -- 2 for DWARF
+ version 2 */
+ unsigned int prologue_length; /* # bytes between prologue &
+ stmt program */
+ unsigned char minimum_instruction_length; /* byte size of
+ smallest instr */
+ unsigned char default_is_stmt; /* initial value of is_stmt
+ register */
+ char line_base;
+ unsigned char line_range;
+ unsigned char opcode_base; /* number assigned to first special
+ opcode */
+ unsigned char *standard_opcode_lengths;
+ }
+_STATEMENT_PROLOGUE;
+
+/* offsets and sizes of debugging sections */
+
+static unsigned int dwarf_info_size;
+static unsigned int dwarf_abbrev_size;
+static unsigned int dwarf_line_size;
+static unsigned int dwarf_pubnames_size;
+static unsigned int dwarf_aranges_size;
+static unsigned int dwarf_loc_size;
+static unsigned int dwarf_macinfo_size;
+static unsigned int dwarf_str_size;
+static unsigned int dwarf_ranges_size;
+unsigned int dwarf_frame_size;
+unsigned int dwarf_eh_frame_size;
+
+static asection *dwarf_info_section;
+static asection *dwarf_abbrev_section;
+static asection *dwarf_line_section;
+static asection *dwarf_pubnames_section;
+static asection *dwarf_aranges_section;
+static asection *dwarf_loc_section;
+static asection *dwarf_macinfo_section;
+static asection *dwarf_str_section;
+static asection *dwarf_ranges_section;
+asection *dwarf_frame_section;
+asection *dwarf_eh_frame_section;
+
+/* names of the debugging sections */
+
+#define INFO_SECTION ".debug_info"
+#define ABBREV_SECTION ".debug_abbrev"
+#define LINE_SECTION ".debug_line"
+#define PUBNAMES_SECTION ".debug_pubnames"
+#define ARANGES_SECTION ".debug_aranges"
+#define LOC_SECTION ".debug_loc"
+#define MACINFO_SECTION ".debug_macinfo"
+#define STR_SECTION ".debug_str"
+#define RANGES_SECTION ".debug_ranges"
+#define FRAME_SECTION ".debug_frame"
+#define EH_FRAME_SECTION ".eh_frame"
+
+/* local data types */
+
+/* We hold several abbreviation tables in memory at the same time. */
+#ifndef ABBREV_HASH_SIZE
+#define ABBREV_HASH_SIZE 121
+#endif
+
+/* The data in a compilation unit header, after target2host
+ translation, looks like this. */
+struct comp_unit_head
+ {
+ unsigned long length;
+ short version;
+ unsigned int abbrev_offset;
+ unsigned char addr_size;
+ unsigned char signed_addr_p;
+ unsigned int offset_size; /* size of file offsets; either 4 or 8 */
+ unsigned int initial_length_size; /* size of the length field; either
+ 4 or 12 */
+
+ /* Offset to the first byte of this compilation unit header in the
+ * .debug_info section, for resolving relative reference dies. */
+
+ unsigned int offset;
+
+ /* Pointer to this compilation unit header in the .debug_info
+ * section */
+
+ char *cu_head_ptr;
+
+ /* Pointer to the first die of this compilatio unit. This will
+ * be the first byte following the compilation unit header. */
+
+ char *first_die_ptr;
+
+ /* Pointer to the next compilation unit header in the program. */
+
+ struct comp_unit_head *next;
+
+ /* DWARF abbreviation table associated with this compilation unit */
+
+ struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
+
+ /* Base address of this compilation unit. */
+
+ CORE_ADDR base_address;
+
+ /* Non-zero if base_address has been set. */
+
+ int base_known;
+ };
+
+/* Internal state when decoding a particular compilation unit. */
+struct dwarf2_cu
+{
+ /* The objfile containing this compilation unit. */
+ struct objfile *objfile;
+
+ /* The header of the compilation unit.
+
+ FIXME drow/2003-11-10: Some of the things from the comp_unit_head
+ should be moved to the dwarf2_cu structure; for instance the abbrevs
+ hash table. */
+ struct comp_unit_head header;
+
+ struct function_range *first_fn, *last_fn, *cached_fn;
+
+ /* The language we are debugging. */
+ enum language language;
+ const struct language_defn *language_defn;
+
+ /* 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;
+
+ /* 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_<TYPENAME> 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. */
+ struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */
+};
+
+/* The line number information for a compilation unit (found in the
+ .debug_line section) begins with a "statement program header",
+ which contains the following information. */
+struct line_header
+{
+ unsigned int total_length;
+ unsigned short version;
+ unsigned int header_length;
+ unsigned char minimum_instruction_length;
+ unsigned char default_is_stmt;
+ int line_base;
+ unsigned char line_range;
+ unsigned char opcode_base;
+
+ /* standard_opcode_lengths[i] is the number of operands for the
+ standard opcode whose value is i. This means that
+ standard_opcode_lengths[0] is unused, and the last meaningful
+ element is standard_opcode_lengths[opcode_base - 1]. */
+ unsigned char *standard_opcode_lengths;
+
+ /* The include_directories table. NOTE! These strings are not
+ allocated with xmalloc; instead, they are pointers into
+ debug_line_buffer. If you try to free them, `free' will get
+ indigestion. */
+ unsigned int num_include_dirs, include_dirs_size;
+ char **include_dirs;
+
+ /* The file_names table. NOTE! These strings are not allocated
+ with xmalloc; instead, they are pointers into debug_line_buffer.
+ Don't try to free them directly. */
+ unsigned int num_file_names, file_names_size;
+ struct file_entry
+ {
+ char *name;
+ unsigned int dir_index;
+ unsigned int mod_time;
+ unsigned int length;
+ } *file_names;
+
+ /* The start and end of the statement program following this
+ header. These point into dwarf_line_buffer. */
+ char *statement_program_start, *statement_program_end;
+};
+
+/* When we construct a partial symbol table entry we only
+ need this much information. */
+struct partial_die_info
+ {
+ enum dwarf_tag tag;
+ unsigned char has_children;
+ unsigned char is_external;
+ unsigned char is_declaration;
+ unsigned char has_type;
+ unsigned int offset;
+ unsigned int abbrev;
+ char *name;
+ int has_pc_info;
+ CORE_ADDR lowpc;
+ CORE_ADDR highpc;
+ struct dwarf_block *locdesc;
+ unsigned int language;
+ char *sibling;
+ };
+
+/* This data structure holds the information of an abbrev. */
+struct abbrev_info
+ {
+ unsigned int number; /* number identifying abbrev */
+ enum dwarf_tag tag; /* dwarf tag */
+ int has_children; /* boolean */
+ unsigned int num_attrs; /* number of attributes */
+ struct attr_abbrev *attrs; /* an array of attribute descriptions */
+ struct abbrev_info *next; /* next in chain */
+ };
+
+struct attr_abbrev
+ {
+ enum dwarf_attribute name;
+ enum dwarf_form form;
+ };
+
+/* This data structure holds a complete die structure. */
+struct die_info
+ {
+ enum dwarf_tag tag; /* Tag indicating type of die */
+ unsigned int abbrev; /* Abbrev number */
+ unsigned int offset; /* Offset in .debug_info section */
+ unsigned int num_attrs; /* Number of attributes */
+ struct attribute *attrs; /* An array of attributes */
+ struct die_info *next_ref; /* Next die in ref hash table */
+
+ /* The dies in a compilation unit form an n-ary tree. PARENT
+ points to this die's parent; CHILD points to the first child of
+ this node; and all the children of a given node are chained
+ together via their SIBLING fields, terminated by a die whose
+ tag is zero. */
+ struct die_info *child; /* Its first child, if any. */
+ struct die_info *sibling; /* Its next sibling, if any. */
+ struct die_info *parent; /* Its parent, if any. */
+
+ struct type *type; /* Cached type information */
+ };
+
+/* Attributes have a name and a value */
+struct attribute
+ {
+ enum dwarf_attribute name;
+ enum dwarf_form form;
+ union
+ {
+ char *str;
+ struct dwarf_block *blk;
+ unsigned long unsnd;
+ long int snd;
+ CORE_ADDR addr;
+ }
+ u;
+ };
+
+struct function_range
+{
+ const char *name;
+ CORE_ADDR lowpc, highpc;
+ int seen_line;
+ struct function_range *next;
+};
+
+/* Get at parts of an attribute structure */
+
+#define DW_STRING(attr) ((attr)->u.str)
+#define DW_UNSND(attr) ((attr)->u.unsnd)
+#define DW_BLOCK(attr) ((attr)->u.blk)
+#define DW_SND(attr) ((attr)->u.snd)
+#define DW_ADDR(attr) ((attr)->u.addr)
+
+/* Blocks are a bunch of untyped bytes. */
+struct dwarf_block
+ {
+ unsigned int size;
+ char *data;
+ };
+
+#ifndef ATTR_ALLOC_CHUNK
+#define ATTR_ALLOC_CHUNK 4
+#endif
+
+/* A hash table of die offsets for following references. */
+#ifndef REF_HASH_SIZE
+#define REF_HASH_SIZE 1021
+#endif
+
+static struct die_info *die_ref_table[REF_HASH_SIZE];
+
+/* Obstack for allocating temporary storage used during symbol reading. */
+static struct obstack dwarf2_tmp_obstack;
+
+/* Allocate fields for structs, unions and enums in this size. */
+#ifndef DW_FIELD_ALLOC_CHUNK
+#define DW_FIELD_ALLOC_CHUNK 4
+#endif
+
+/* Actually data from the sections. */
+static char *dwarf_info_buffer;
+static char *dwarf_abbrev_buffer;
+static char *dwarf_line_buffer;
+static char *dwarf_str_buffer;
+static char *dwarf_macinfo_buffer;
+static char *dwarf_ranges_buffer;
+static char *dwarf_loc_buffer;
+
+/* A zeroed version of a partial die for initialization purposes. */
+static struct partial_die_info zeroed_partial_die;
+
+/* FIXME: decode_locdesc sets these variables to describe the location
+ to the caller. These ought to be a structure or something. If
+ none of the flags are set, the object lives at the address returned
+ by decode_locdesc. */
+
+static int isreg; /* Object lives in register.
+ decode_locdesc's return value is
+ the register number. */
+
+/* We put a pointer to this structure in the read_symtab_private field
+ of the psymtab.
+ The complete dwarf information for an objfile is kept in the
+ objfile_obstack, so that absolute die references can be handled.
+ Most of the information in this structure is related to an entire
+ object file and could be passed via the sym_private field of the objfile.
+ It is however conceivable that dwarf2 might not be the only type
+ of symbols read from an object file. */
+
+struct dwarf2_pinfo
+ {
+ /* Pointer to start of dwarf info buffer for the objfile. */
+
+ char *dwarf_info_buffer;
+
+ /* Offset in dwarf_info_buffer for this compilation unit. */
+
+ unsigned long dwarf_info_offset;
+
+ /* Pointer to start of dwarf abbreviation buffer for the objfile. */
+
+ char *dwarf_abbrev_buffer;
+
+ /* Size of dwarf abbreviation section for the objfile. */
+
+ unsigned int dwarf_abbrev_size;
+
+ /* Pointer to start of dwarf line buffer for the objfile. */
+
+ char *dwarf_line_buffer;
+
+ /* Size of dwarf_line_buffer, in bytes. */
+
+ unsigned int dwarf_line_size;
+
+ /* Pointer to start of dwarf string buffer for the objfile. */
+
+ char *dwarf_str_buffer;
+
+ /* Size of dwarf string section for the objfile. */
+
+ unsigned int dwarf_str_size;
+
+ /* Pointer to start of dwarf macro buffer for the objfile. */
+
+ char *dwarf_macinfo_buffer;
+
+ /* Size of dwarf macinfo section for the objfile. */
+
+ unsigned int dwarf_macinfo_size;
+
+ /* Pointer to start of dwarf ranges buffer for the objfile. */
+
+ char *dwarf_ranges_buffer;
+
+ /* Size of dwarf ranges buffer for the objfile. */
+
+ unsigned int dwarf_ranges_size;
+
+ /* Pointer to start of dwarf locations buffer for the objfile. */
+
+ char *dwarf_loc_buffer;
+
+ /* Size of dwarf locations buffer for the objfile. */
+
+ unsigned int dwarf_loc_size;
+ };
+
+#define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
+#define DWARF_INFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_info_buffer)
+#define DWARF_INFO_OFFSET(p) (PST_PRIVATE(p)->dwarf_info_offset)
+#define DWARF_ABBREV_BUFFER(p) (PST_PRIVATE(p)->dwarf_abbrev_buffer)
+#define DWARF_ABBREV_SIZE(p) (PST_PRIVATE(p)->dwarf_abbrev_size)
+#define DWARF_LINE_BUFFER(p) (PST_PRIVATE(p)->dwarf_line_buffer)
+#define DWARF_LINE_SIZE(p) (PST_PRIVATE(p)->dwarf_line_size)
+#define DWARF_STR_BUFFER(p) (PST_PRIVATE(p)->dwarf_str_buffer)
+#define DWARF_STR_SIZE(p) (PST_PRIVATE(p)->dwarf_str_size)
+#define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer)
+#define DWARF_MACINFO_SIZE(p) (PST_PRIVATE(p)->dwarf_macinfo_size)
+#define DWARF_RANGES_BUFFER(p) (PST_PRIVATE(p)->dwarf_ranges_buffer)
+#define DWARF_RANGES_SIZE(p) (PST_PRIVATE(p)->dwarf_ranges_size)
+#define DWARF_LOC_BUFFER(p) (PST_PRIVATE(p)->dwarf_loc_buffer)
+#define DWARF_LOC_SIZE(p) (PST_PRIVATE(p)->dwarf_loc_size)
+
+/* FIXME: We might want to set this from BFD via bfd_arch_bits_per_byte,
+ but this would require a corresponding change in unpack_field_as_long
+ and friends. */
+static int bits_per_byte = 8;
+
+/* The routines that read and process dies 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. */
+struct field_info
+ {
+ /* List of data member and baseclasses fields. */
+ struct nextfield
+ {
+ struct nextfield *next;
+ int accessibility;
+ int virtuality;
+ struct field field;
+ }
+ *fields;
+
+ /* Number of fields. */
+ int nfields;
+
+ /* Number of baseclasses. */
+ int nbaseclasses;
+
+ /* Set if the accesibility of one of the fields is not public. */
+ int non_public_fields;
+
+ /* Member function fields array, entries are allocated in the order they
+ are encountered in the object file. */
+ struct nextfnfield
+ {
+ struct nextfnfield *next;
+ struct fn_field fnfield;
+ }
+ *fnfields;
+
+ /* Member function fieldlist array, contains name of possibly overloaded
+ member function, number of overloaded member functions and a pointer
+ to the head of the member function field chain. */
+ struct fnfieldlist
+ {
+ char *name;
+ int length;
+ struct nextfnfield *head;
+ }
+ *fnfieldlists;
+
+ /* Number of entries in the fnfieldlists array. */
+ int nfnfields;
+ };
+
+/* Various complaints about symbol reading that don't abort the process */
+
+static void
+dwarf2_statement_list_fits_in_line_number_section_complaint (void)
+{
+ complaint (&symfile_complaints,
+ "statement list doesn't fit in .debug_line section");
+}
+
+static void
+dwarf2_complex_location_expr_complaint (void)
+{
+ complaint (&symfile_complaints, "location expression too complex");
+}
+
+static void
+dwarf2_const_value_length_mismatch_complaint (const char *arg1, int arg2,
+ int arg3)
+{
+ complaint (&symfile_complaints,
+ "const value length mismatch for '%s', got %d, expected %d", arg1,
+ arg2, arg3);
+}
+
+static void
+dwarf2_macros_too_long_complaint (void)
+{
+ complaint (&symfile_complaints,
+ "macro info runs off end of `.debug_macinfo' section");
+}
+
+static void
+dwarf2_macro_malformed_definition_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints,
+ "macro debug info contains a malformed macro definition:\n`%s'",
+ arg1);
+}
+
+static void
+dwarf2_invalid_attrib_class_complaint (const char *arg1, const char *arg2)
+{
+ complaint (&symfile_complaints,
+ "invalid attribute class or form for '%s' in '%s'", arg1, arg2);
+}
+
+/* local function prototypes */
+
+static void dwarf2_locate_sections (bfd *, asection *, void *);
+
+#if 0
+static void dwarf2_build_psymtabs_easy (struct objfile *, int);
+#endif
+
+static void dwarf2_build_psymtabs_hard (struct objfile *, int);
+
+static char *scan_partial_symbols (char *, CORE_ADDR *, CORE_ADDR *,
+ struct dwarf2_cu *,
+ const char *namespace);
+
+static void add_partial_symbol (struct partial_die_info *, struct dwarf2_cu *,
+ const char *namespace);
+
+static int pdi_needs_namespace (enum dwarf_tag tag, const char *namespace);
+
+static char *add_partial_namespace (struct partial_die_info *pdi,
+ char *info_ptr,
+ CORE_ADDR *lowpc, CORE_ADDR *highpc,
+ struct dwarf2_cu *cu,
+ const char *namespace);
+
+static char *add_partial_structure (struct partial_die_info *struct_pdi,
+ char *info_ptr,
+ struct dwarf2_cu *cu,
+ const char *namespace);
+
+static char *add_partial_enumeration (struct partial_die_info *enum_pdi,
+ char *info_ptr,
+ struct dwarf2_cu *cu,
+ const char *namespace);
+
+static char *locate_pdi_sibling (struct partial_die_info *orig_pdi,
+ char *info_ptr,
+ bfd *abfd,
+ struct dwarf2_cu *cu);
+
+static void dwarf2_psymtab_to_symtab (struct partial_symtab *);
+
+static void psymtab_to_symtab_1 (struct partial_symtab *);
+
+char *dwarf2_read_section (struct objfile *, asection *);
+
+static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu);
+
+static void dwarf2_empty_abbrev_table (void *);
+
+static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int,
+ struct dwarf2_cu *);
+
+static char *read_partial_die (struct partial_die_info *,
+ bfd *, char *, struct dwarf2_cu *);
+
+static char *read_full_die (struct die_info **, bfd *, char *,
+ struct dwarf2_cu *, int *);
+
+static char *read_attribute (struct attribute *, struct attr_abbrev *,
+ bfd *, char *, struct dwarf2_cu *);
+
+static char *read_attribute_value (struct attribute *, unsigned,
+ bfd *, char *, struct dwarf2_cu *);
+
+static unsigned int read_1_byte (bfd *, char *);
+
+static int read_1_signed_byte (bfd *, char *);
+
+static unsigned int read_2_bytes (bfd *, char *);
+
+static unsigned int read_4_bytes (bfd *, char *);
+
+static unsigned long read_8_bytes (bfd *, char *);
+
+static CORE_ADDR read_address (bfd *, char *ptr, struct dwarf2_cu *,
+ int *bytes_read);
+
+static LONGEST read_initial_length (bfd *, char *,
+ struct comp_unit_head *, int *bytes_read);
+
+static LONGEST read_offset (bfd *, char *, const struct comp_unit_head *,
+ int *bytes_read);
+
+static char *read_n_bytes (bfd *, char *, unsigned int);
+
+static char *read_string (bfd *, char *, unsigned int *);
+
+static char *read_indirect_string (bfd *, char *, const struct comp_unit_head *,
+ unsigned int *);
+
+static unsigned long read_unsigned_leb128 (bfd *, char *, unsigned int *);
+
+static long read_signed_leb128 (bfd *, char *, unsigned int *);
+
+static void set_cu_language (unsigned int, struct dwarf2_cu *);
+
+static struct attribute *dwarf2_attr (struct die_info *, unsigned int,
+ struct dwarf2_cu *);
+
+static int die_is_declaration (struct die_info *, struct dwarf2_cu *cu);
+
+static struct die_info *die_specification (struct die_info *die,
+ struct dwarf2_cu *);
+
+static void free_line_header (struct line_header *lh);
+
+static struct line_header *(dwarf_decode_line_header
+ (unsigned int offset,
+ bfd *abfd, struct dwarf2_cu *cu));
+
+static void dwarf_decode_lines (struct line_header *, char *, bfd *,
+ struct dwarf2_cu *);
+
+static void dwarf2_start_subfile (char *, char *);
+
+static struct symbol *new_symbol (struct die_info *, struct type *,
+ struct dwarf2_cu *);
+
+static void dwarf2_const_value (struct attribute *, struct symbol *,
+ struct dwarf2_cu *);
+
+static void dwarf2_const_value_data (struct attribute *attr,
+ struct symbol *sym,
+ int bits);
+
+static struct type *die_type (struct die_info *, struct dwarf2_cu *);
+
+static struct type *die_containing_type (struct die_info *,
+ struct dwarf2_cu *);
+
+#if 0
+static struct type *type_at_offset (unsigned int, struct objfile *);
+#endif
+
+static struct type *tag_type_to_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_type_die (struct die_info *, struct dwarf2_cu *);
+
+static char *determine_prefix (struct die_info *die, struct dwarf2_cu *);
+
+static char *typename_concat (const char *prefix, const char *suffix);
+
+static void read_typedef (struct die_info *, struct dwarf2_cu *);
+
+static void read_base_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_subrange_type (struct die_info *die, struct dwarf2_cu *cu);
+
+static void read_file_scope (struct die_info *, struct dwarf2_cu *);
+
+static void read_func_scope (struct die_info *, struct dwarf2_cu *);
+
+static void read_lexical_block_scope (struct die_info *, struct dwarf2_cu *);
+
+static int dwarf2_get_pc_bounds (struct die_info *,
+ CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *);
+
+static void get_scope_pc_bounds (struct die_info *,
+ CORE_ADDR *, CORE_ADDR *,
+ struct dwarf2_cu *);
+
+static void dwarf2_add_field (struct field_info *, struct die_info *,
+ struct dwarf2_cu *);
+
+static void dwarf2_attach_fields_to_type (struct field_info *,
+ struct type *, struct dwarf2_cu *);
+
+static void dwarf2_add_member_fn (struct field_info *,
+ struct die_info *, struct type *,
+ struct dwarf2_cu *);
+
+static void dwarf2_attach_fn_fields_to_type (struct field_info *,
+ struct type *, struct dwarf2_cu *);
+
+static void read_structure_type (struct die_info *, struct dwarf2_cu *);
+
+static void process_structure_scope (struct die_info *, struct dwarf2_cu *);
+
+static char *determine_class_name (struct die_info *die, struct dwarf2_cu *cu);
+
+static void read_common_block (struct die_info *, struct dwarf2_cu *);
+
+static void read_namespace (struct die_info *die, struct dwarf2_cu *);
+
+static const char *namespace_name (struct die_info *die,
+ int *is_anonymous, struct dwarf2_cu *);
+
+static void read_enumeration_type (struct die_info *, struct dwarf2_cu *);
+
+static void process_enumeration_scope (struct die_info *, struct dwarf2_cu *);
+
+static struct type *dwarf_base_type (int, int, struct dwarf2_cu *);
+
+static CORE_ADDR decode_locdesc (struct dwarf_block *, struct dwarf2_cu *);
+
+static void read_array_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_tag_pointer_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_tag_ptr_to_member_type (struct die_info *,
+ struct dwarf2_cu *);
+
+static void read_tag_reference_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_tag_const_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_tag_volatile_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_tag_string_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_subroutine_type (struct die_info *, struct dwarf2_cu *);
+
+static struct die_info *read_comp_unit (char *, bfd *, struct dwarf2_cu *);
+
+static struct die_info *read_die_and_children (char *info_ptr, bfd *abfd,
+ struct dwarf2_cu *,
+ char **new_info_ptr,
+ struct die_info *parent);
+
+static struct die_info *read_die_and_siblings (char *info_ptr, bfd *abfd,
+ struct dwarf2_cu *,
+ char **new_info_ptr,
+ struct die_info *parent);
+
+static void free_die_list (struct die_info *);
+
+static struct cleanup *make_cleanup_free_die_list (struct die_info *);
+
+static void process_die (struct die_info *, struct dwarf2_cu *);
+
+static char *dwarf2_linkage_name (struct die_info *, struct dwarf2_cu *);
+
+static char *dwarf2_name (struct die_info *die, struct dwarf2_cu *);
+
+static struct die_info *dwarf2_extension (struct die_info *die,
+ struct dwarf2_cu *);
+
+static char *dwarf_tag_name (unsigned int);
+
+static char *dwarf_attr_name (unsigned int);
+
+static char *dwarf_form_name (unsigned int);
+
+static char *dwarf_stack_op_name (unsigned int);
+
+static char *dwarf_bool_name (unsigned int);
+
+static char *dwarf_type_encoding_name (unsigned int);
+
+#if 0
+static char *dwarf_cfi_name (unsigned int);
+
+struct die_info *copy_die (struct die_info *);
+#endif
+
+static struct die_info *sibling_die (struct die_info *);
+
+static void dump_die (struct die_info *);
+
+static void dump_die_list (struct die_info *);
+
+static void store_in_ref_table (unsigned int, struct die_info *);
+
+static void dwarf2_empty_hash_tables (void);
+
+static unsigned int dwarf2_get_ref_die_offset (struct attribute *,
+ struct dwarf2_cu *);
+
+static int dwarf2_get_attr_constant_value (struct attribute *, int);
+
+static struct die_info *follow_die_ref (unsigned int);
+
+static struct type *dwarf2_fundamental_type (struct objfile *, int,
+ struct dwarf2_cu *);
+
+/* memory allocation interface */
+
+static void dwarf2_free_tmp_obstack (void *);
+
+static struct dwarf_block *dwarf_alloc_block (void);
+
+static struct abbrev_info *dwarf_alloc_abbrev (void);
+
+static struct die_info *dwarf_alloc_die (void);
+
+static void initialize_cu_func_list (struct dwarf2_cu *);
+
+static void add_to_cu_func_list (const char *, CORE_ADDR, CORE_ADDR,
+ struct dwarf2_cu *);
+
+static void dwarf_decode_macros (struct line_header *, unsigned int,
+ char *, bfd *, struct dwarf2_cu *);
+
+static int attr_form_is_block (struct attribute *);
+
+static void
+dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
+ struct dwarf2_cu *cu);
+
+/* Try to locate the sections we need for DWARF 2 debugging
+ information and return true if we have enough to do something. */
+
+int
+dwarf2_has_info (bfd *abfd)
+{
+ dwarf_info_section = 0;
+ dwarf_abbrev_section = 0;
+ dwarf_line_section = 0;
+ dwarf_str_section = 0;
+ dwarf_macinfo_section = 0;
+ dwarf_frame_section = 0;
+ dwarf_eh_frame_section = 0;
+ dwarf_ranges_section = 0;
+ dwarf_loc_section = 0;
+
+ bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
+ return (dwarf_info_section != NULL && dwarf_abbrev_section != NULL);
+}
+
+/* This function is mapped across the sections and remembers the
+ offset and size of each of the debugging sections we are interested
+ in. */
+
+static void
+dwarf2_locate_sections (bfd *ignore_abfd, asection *sectp, void *ignore_ptr)
+{
+ if (strcmp (sectp->name, INFO_SECTION) == 0)
+ {
+ dwarf_info_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_info_section = sectp;
+ }
+ else if (strcmp (sectp->name, ABBREV_SECTION) == 0)
+ {
+ dwarf_abbrev_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_abbrev_section = sectp;
+ }
+ else if (strcmp (sectp->name, LINE_SECTION) == 0)
+ {
+ dwarf_line_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_line_section = sectp;
+ }
+ else if (strcmp (sectp->name, PUBNAMES_SECTION) == 0)
+ {
+ dwarf_pubnames_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_pubnames_section = sectp;
+ }
+ else if (strcmp (sectp->name, ARANGES_SECTION) == 0)
+ {
+ dwarf_aranges_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_aranges_section = sectp;
+ }
+ else if (strcmp (sectp->name, LOC_SECTION) == 0)
+ {
+ dwarf_loc_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_loc_section = sectp;
+ }
+ else if (strcmp (sectp->name, MACINFO_SECTION) == 0)
+ {
+ dwarf_macinfo_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_macinfo_section = sectp;
+ }
+ else if (strcmp (sectp->name, STR_SECTION) == 0)
+ {
+ dwarf_str_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_str_section = sectp;
+ }
+ else if (strcmp (sectp->name, FRAME_SECTION) == 0)
+ {
+ dwarf_frame_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_frame_section = sectp;
+ }
+ else if (strcmp (sectp->name, EH_FRAME_SECTION) == 0)
+ {
+ flagword aflag = bfd_get_section_flags (ignore_abfd, sectp);
+ if (aflag & SEC_HAS_CONTENTS)
+ {
+ dwarf_eh_frame_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_eh_frame_section = sectp;
+ }
+ }
+ else if (strcmp (sectp->name, RANGES_SECTION) == 0)
+ {
+ dwarf_ranges_size = bfd_get_section_size_before_reloc (sectp);
+ dwarf_ranges_section = sectp;
+ }
+}
+
+/* Build a partial symbol table. */
+
+void
+dwarf2_build_psymtabs (struct objfile *objfile, int mainline)
+{
+
+ /* We definitely need the .debug_info and .debug_abbrev sections */
+
+ dwarf_info_buffer = dwarf2_read_section (objfile, dwarf_info_section);
+ dwarf_abbrev_buffer = dwarf2_read_section (objfile, dwarf_abbrev_section);
+
+ if (dwarf_line_section)
+ dwarf_line_buffer = dwarf2_read_section (objfile, dwarf_line_section);
+ else
+ dwarf_line_buffer = NULL;
+
+ if (dwarf_str_section)
+ dwarf_str_buffer = dwarf2_read_section (objfile, dwarf_str_section);
+ else
+ dwarf_str_buffer = NULL;
+
+ if (dwarf_macinfo_section)
+ dwarf_macinfo_buffer = dwarf2_read_section (objfile,
+ dwarf_macinfo_section);
+ else
+ dwarf_macinfo_buffer = NULL;
+
+ if (dwarf_ranges_section)
+ dwarf_ranges_buffer = dwarf2_read_section (objfile, dwarf_ranges_section);
+ else
+ dwarf_ranges_buffer = NULL;
+
+ if (dwarf_loc_section)
+ dwarf_loc_buffer = dwarf2_read_section (objfile, dwarf_loc_section);
+ else
+ dwarf_loc_buffer = NULL;
+
+ if (mainline
+ || (objfile->global_psymbols.size == 0
+ && objfile->static_psymbols.size == 0))
+ {
+ init_psymbol_list (objfile, 1024);
+ }
+
+#if 0
+ if (dwarf_aranges_offset && dwarf_pubnames_offset)
+ {
+ /* Things are significantly easier if we have .debug_aranges and
+ .debug_pubnames sections */
+
+ dwarf2_build_psymtabs_easy (objfile, mainline);
+ }
+ else
+#endif
+ /* only test this case for now */
+ {
+ /* In this case we have to work a bit harder */
+ dwarf2_build_psymtabs_hard (objfile, mainline);
+ }
+}
+
+#if 0
+/* Build the partial symbol table from the information in the
+ .debug_pubnames and .debug_aranges sections. */
+
+static void
+dwarf2_build_psymtabs_easy (struct objfile *objfile, int mainline)
+{
+ bfd *abfd = objfile->obfd;
+ char *aranges_buffer, *pubnames_buffer;
+ char *aranges_ptr, *pubnames_ptr;
+ unsigned int entry_length, version, info_offset, info_size;
+
+ pubnames_buffer = dwarf2_read_section (objfile,
+ dwarf_pubnames_section);
+ pubnames_ptr = pubnames_buffer;
+ while ((pubnames_ptr - pubnames_buffer) < dwarf_pubnames_size)
+ {
+ struct comp_unit_head cu_header;
+ int bytes_read;
+
+ entry_length = read_initial_length (abfd, pubnames_ptr, &cu_header,
+ &bytes_read);
+ pubnames_ptr += bytes_read;
+ version = read_1_byte (abfd, pubnames_ptr);
+ pubnames_ptr += 1;
+ info_offset = read_4_bytes (abfd, pubnames_ptr);
+ pubnames_ptr += 4;
+ info_size = read_4_bytes (abfd, pubnames_ptr);
+ pubnames_ptr += 4;
+ }
+
+ aranges_buffer = dwarf2_read_section (objfile,
+ dwarf_aranges_section);
+
+}
+#endif
+
+/* Read in the comp unit header information from the debug_info at
+ info_ptr. */
+
+static char *
+read_comp_unit_head (struct comp_unit_head *cu_header,
+ char *info_ptr, bfd *abfd)
+{
+ int signed_addr;
+ int bytes_read;
+ cu_header->length = read_initial_length (abfd, info_ptr, cu_header,
+ &bytes_read);
+ info_ptr += bytes_read;
+ cu_header->version = read_2_bytes (abfd, info_ptr);
+ info_ptr += 2;
+ cu_header->abbrev_offset = read_offset (abfd, info_ptr, cu_header,
+ &bytes_read);
+ info_ptr += bytes_read;
+ cu_header->addr_size = read_1_byte (abfd, info_ptr);
+ info_ptr += 1;
+ signed_addr = bfd_get_sign_extend_vma (abfd);
+ if (signed_addr < 0)
+ internal_error (__FILE__, __LINE__,
+ "read_comp_unit_head: dwarf from non elf file");
+ cu_header->signed_addr_p = signed_addr;
+ return info_ptr;
+}
+
+/* Build the partial symbol table by doing a quick pass through the
+ .debug_info and .debug_abbrev sections. */
+
+static void
+dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
+{
+ /* Instead of reading this into a big buffer, we should probably use
+ mmap() on architectures that support it. (FIXME) */
+ bfd *abfd = objfile->obfd;
+ char *info_ptr, *abbrev_ptr;
+ char *beg_of_comp_unit;
+ struct partial_die_info comp_unit_die;
+ struct partial_symtab *pst;
+ struct cleanup *back_to;
+ CORE_ADDR lowpc, highpc, baseaddr;
+
+ info_ptr = dwarf_info_buffer;
+ abbrev_ptr = dwarf_abbrev_buffer;
+
+ /* We use dwarf2_tmp_obstack for objects that don't need to survive
+ the partial symbol scan, like attribute values.
+
+ We could reduce our peak memory consumption during partial symbol
+ table construction by freeing stuff from this obstack more often
+ --- say, after processing each compilation unit, or each die ---
+ but it turns out that this saves almost nothing. For an
+ executable with 11Mb of Dwarf 2 data, I found about 64k allocated
+ on dwarf2_tmp_obstack. Some investigation showed:
+
+ 1) 69% of the attributes used forms DW_FORM_addr, DW_FORM_data*,
+ DW_FORM_flag, DW_FORM_[su]data, and DW_FORM_ref*. These are
+ all fixed-length values not requiring dynamic allocation.
+
+ 2) 30% of the attributes used the form DW_FORM_string. For
+ DW_FORM_string, read_attribute simply hands back a pointer to
+ the null-terminated string in dwarf_info_buffer, so no dynamic
+ allocation is needed there either.
+
+ 3) The remaining 1% of the attributes all used DW_FORM_block1.
+ 75% of those were DW_AT_frame_base location lists for
+ functions; the rest were DW_AT_location attributes, probably
+ for the global variables.
+
+ Anyway, what this all means is that the memory the dwarf2
+ reader uses as temporary space reading partial symbols is about
+ 0.5% as much as we use for dwarf_*_buffer. That's noise. */
+
+ obstack_init (&dwarf2_tmp_obstack);
+ back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL);
+
+ /* Since the objects we're extracting from dwarf_info_buffer vary in
+ length, only the individual functions to extract them (like
+ read_comp_unit_head and read_partial_die) can really know whether
+ the buffer is large enough to hold another complete object.
+
+ At the moment, they don't actually check that. If
+ dwarf_info_buffer holds just one extra byte after the last
+ compilation unit's dies, then read_comp_unit_head will happily
+ read off the end of the buffer. read_partial_die is similarly
+ casual. Those functions should be fixed.
+
+ For this loop condition, simply checking whether there's any data
+ left at all should be sufficient. */
+ while (info_ptr < dwarf_info_buffer + dwarf_info_size)
+ {
+ struct dwarf2_cu cu;
+ beg_of_comp_unit = info_ptr;
+
+ cu.objfile = objfile;
+ info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd);
+
+ if (cu.header.version != 2)
+ {
+ error ("Dwarf Error: wrong version in compilation unit header (is %d, should be %d) [in module %s]", cu.header.version, 2, bfd_get_filename (abfd));
+ return;
+ }
+ if (cu.header.abbrev_offset >= dwarf_abbrev_size)
+ {
+ error ("Dwarf Error: bad offset (0x%lx) in compilation unit header (offset 0x%lx + 6) [in module %s]",
+ (long) cu.header.abbrev_offset,
+ (long) (beg_of_comp_unit - dwarf_info_buffer),
+ bfd_get_filename (abfd));
+ return;
+ }
+ if (beg_of_comp_unit + cu.header.length + cu.header.initial_length_size
+ > dwarf_info_buffer + dwarf_info_size)
+ {
+ error ("Dwarf Error: bad length (0x%lx) in compilation unit header (offset 0x%lx + 0) [in module %s]",
+ (long) cu.header.length,
+ (long) (beg_of_comp_unit - dwarf_info_buffer),
+ bfd_get_filename (abfd));
+ return;
+ }
+ /* Complete the cu_header */
+ cu.header.offset = beg_of_comp_unit - dwarf_info_buffer;
+ cu.header.first_die_ptr = info_ptr;
+ cu.header.cu_head_ptr = beg_of_comp_unit;
+
+ cu.list_in_scope = &file_symbols;
+
+ /* Read the abbrevs for this compilation unit into a table */
+ dwarf2_read_abbrevs (abfd, &cu);
+ make_cleanup (dwarf2_empty_abbrev_table, cu.header.dwarf2_abbrevs);
+
+ /* Read the compilation unit die */
+ info_ptr = read_partial_die (&comp_unit_die, abfd, info_ptr,
+ &cu);
+
+ /* Set the language we're debugging */
+ set_cu_language (comp_unit_die.language, &cu);
+
+ /* Allocate a new partial symbol table structure */
+ pst = start_psymtab_common (objfile, objfile->section_offsets,
+ comp_unit_die.name ? comp_unit_die.name : "",
+ comp_unit_die.lowpc,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+
+ pst->read_symtab_private = (char *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct dwarf2_pinfo));
+ DWARF_INFO_BUFFER (pst) = dwarf_info_buffer;
+ DWARF_INFO_OFFSET (pst) = beg_of_comp_unit - dwarf_info_buffer;
+ DWARF_ABBREV_BUFFER (pst) = dwarf_abbrev_buffer;
+ DWARF_ABBREV_SIZE (pst) = dwarf_abbrev_size;
+ DWARF_LINE_BUFFER (pst) = dwarf_line_buffer;
+ DWARF_LINE_SIZE (pst) = dwarf_line_size;
+ DWARF_STR_BUFFER (pst) = dwarf_str_buffer;
+ DWARF_STR_SIZE (pst) = dwarf_str_size;
+ DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer;
+ DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
+ DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer;
+ DWARF_RANGES_SIZE (pst) = dwarf_ranges_size;
+ DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer;
+ DWARF_LOC_SIZE (pst) = dwarf_loc_size;
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ /* Store the function that reads in the rest of the symbol table */
+ pst->read_symtab = dwarf2_psymtab_to_symtab;
+
+ /* Check if comp unit has_children.
+ If so, read the rest of the partial symbols from this comp unit.
+ If not, there's no more debug_info for this comp unit. */
+ if (comp_unit_die.has_children)
+ {
+ lowpc = ((CORE_ADDR) -1);
+ highpc = ((CORE_ADDR) 0);
+
+ info_ptr = scan_partial_symbols (info_ptr, &lowpc, &highpc,
+ &cu, NULL);
+
+ /* If we didn't find a lowpc, set it to highpc to avoid
+ complaints from `maint check'. */
+ if (lowpc == ((CORE_ADDR) -1))
+ lowpc = highpc;
+
+ /* If the compilation unit didn't have an explicit address range,
+ then use the information extracted from its child dies. */
+ if (! comp_unit_die.has_pc_info)
+ {
+ comp_unit_die.lowpc = lowpc;
+ comp_unit_die.highpc = highpc;
+ }
+ }
+ pst->textlow = comp_unit_die.lowpc + baseaddr;
+ pst->texthigh = comp_unit_die.highpc + baseaddr;
+
+ pst->n_global_syms = objfile->global_psymbols.next -
+ (objfile->global_psymbols.list + pst->globals_offset);
+ pst->n_static_syms = objfile->static_psymbols.next -
+ (objfile->static_psymbols.list + pst->statics_offset);
+ sort_pst_symbols (pst);
+
+ /* 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);
+
+ info_ptr = beg_of_comp_unit + cu.header.length
+ + cu.header.initial_length_size;
+ }
+ do_cleanups (back_to);
+}
+
+/* Read in all interesting dies to the end of the compilation unit or
+ to the end of the current namespace. NAMESPACE is NULL if we
+ haven't yet encountered any DW_TAG_namespace entries; otherwise,
+ it's the name of the current namespace. In particular, it's the
+ empty string if we're currently in the global namespace but have
+ previously encountered a DW_TAG_namespace. */
+
+static char *
+scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc,
+ CORE_ADDR *highpc, struct dwarf2_cu *cu,
+ const char *namespace)
+{
+ struct objfile *objfile = cu->objfile;
+ bfd *abfd = objfile->obfd;
+ struct partial_die_info pdi;
+
+ /* Now, march along the PDI's, descending into ones which have
+ interesting children but skipping the children of the other ones,
+ until we reach the end of the compilation unit. */
+
+ while (1)
+ {
+ /* This flag tells whether or not info_ptr has gotten updated
+ inside the loop. */
+ int info_ptr_updated = 0;
+
+ info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu);
+
+ /* Anonymous namespaces have no name but have interesting
+ children, so we need to look at them. Ditto for anonymous
+ enums. */
+
+ if (pdi.name != NULL || pdi.tag == DW_TAG_namespace
+ || pdi.tag == DW_TAG_enumeration_type)
+ {
+ switch (pdi.tag)
+ {
+ case DW_TAG_subprogram:
+ if (pdi.has_pc_info)
+ {
+ if (pdi.lowpc < *lowpc)
+ {
+ *lowpc = pdi.lowpc;
+ }
+ if (pdi.highpc > *highpc)
+ {
+ *highpc = pdi.highpc;
+ }
+ if (!pdi.is_declaration)
+ {
+ add_partial_symbol (&pdi, cu, namespace);
+ }
+ }
+ break;
+ case DW_TAG_variable:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ if (!pdi.is_declaration)
+ {
+ add_partial_symbol (&pdi, cu, namespace);
+ }
+ break;
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ if (!pdi.is_declaration)
+ {
+ info_ptr = add_partial_structure (&pdi, info_ptr, cu,
+ namespace);
+ info_ptr_updated = 1;
+ }
+ break;
+ case DW_TAG_enumeration_type:
+ if (!pdi.is_declaration)
+ {
+ info_ptr = add_partial_enumeration (&pdi, info_ptr, cu,
+ namespace);
+ info_ptr_updated = 1;
+ }
+ break;
+ case DW_TAG_base_type:
+ case DW_TAG_subrange_type:
+ /* File scope base type definitions are added to the partial
+ symbol table. */
+ add_partial_symbol (&pdi, cu, namespace);
+ break;
+ case DW_TAG_namespace:
+ /* We've hit a DW_TAG_namespace entry, so we know this
+ file has been compiled using a compiler that
+ generates them; update NAMESPACE to reflect that. */
+ if (namespace == NULL)
+ namespace = "";
+ info_ptr = add_partial_namespace (&pdi, info_ptr, lowpc, highpc,
+ cu, namespace);
+ info_ptr_updated = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (pdi.tag == 0)
+ break;
+
+ /* If the die has a sibling, skip to the sibling, unless another
+ function has already updated info_ptr for us. */
+
+ /* NOTE: carlton/2003-06-16: This is a bit hackish, but whether
+ or not we want to update this depends on enough stuff (not
+ only pdi.tag but also whether or not pdi.name is NULL) that
+ this seems like the easiest way to handle the issue. */
+
+ if (!info_ptr_updated)
+ info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu);
+ }
+
+ return info_ptr;
+}
+
+static void
+add_partial_symbol (struct partial_die_info *pdi,
+ struct dwarf2_cu *cu, const char *namespace)
+{
+ struct objfile *objfile = cu->objfile;
+ CORE_ADDR addr = 0;
+ char *actual_name = pdi->name;
+ const struct partial_symbol *psym = NULL;
+ CORE_ADDR baseaddr;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ /* If we're not in the global namespace and if the namespace name
+ isn't encoded in a mangled actual_name, add it. */
+
+ if (pdi_needs_namespace (pdi->tag, namespace))
+ {
+ actual_name = alloca (strlen (pdi->name) + 2 + strlen (namespace) + 1);
+ strcpy (actual_name, namespace);
+ strcat (actual_name, "::");
+ strcat (actual_name, pdi->name);
+ }
+
+ switch (pdi->tag)
+ {
+ case DW_TAG_subprogram:
+ if (pdi->is_external)
+ {
+ /*prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr,
+ mst_text, objfile); */
+ psym = add_psymbol_to_list (actual_name, strlen (actual_name),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols,
+ 0, pdi->lowpc + baseaddr,
+ cu->language, objfile);
+ }
+ else
+ {
+ /*prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr,
+ mst_file_text, objfile); */
+ psym = add_psymbol_to_list (actual_name, strlen (actual_name),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols,
+ 0, pdi->lowpc + baseaddr,
+ cu->language, objfile);
+ }
+ break;
+ case DW_TAG_variable:
+ if (pdi->is_external)
+ {
+ /* Global Variable.
+ Don't enter into the minimal symbol tables as there is
+ a minimal symbol table entry from the ELF symbols already.
+ Enter into partial symbol table if it has a location
+ descriptor or a type.
+ If the location descriptor is missing, new_symbol will create
+ a LOC_UNRESOLVED symbol, the address of the variable will then
+ be determined from the minimal symbol table whenever the variable
+ is referenced.
+ The address for the partial symbol table entry is not
+ used by GDB, but it comes in handy for debugging partial symbol
+ table building. */
+
+ if (pdi->locdesc)
+ addr = decode_locdesc (pdi->locdesc, cu);
+ if (pdi->locdesc || pdi->has_type)
+ psym = add_psymbol_to_list (actual_name, strlen (actual_name),
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->global_psymbols,
+ 0, addr + baseaddr,
+ cu->language, objfile);
+ }
+ else
+ {
+ /* Static Variable. Skip symbols without location descriptors. */
+ if (pdi->locdesc == NULL)
+ return;
+ addr = decode_locdesc (pdi->locdesc, cu);
+ /*prim_record_minimal_symbol (actual_name, addr + baseaddr,
+ mst_file_data, objfile); */
+ psym = add_psymbol_to_list (actual_name, strlen (actual_name),
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->static_psymbols,
+ 0, addr + baseaddr,
+ cu->language, objfile);
+ }
+ break;
+ case DW_TAG_typedef:
+ case DW_TAG_base_type:
+ case DW_TAG_subrange_type:
+ add_psymbol_to_list (actual_name, strlen (actual_name),
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ 0, (CORE_ADDR) 0, cu->language, objfile);
+ break;
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ /* Skip aggregate types without children, these are external
+ references. */
+ /* NOTE: carlton/2003-10-07: See comment in new_symbol about
+ static vs. global. */
+ if (pdi->has_children == 0)
+ return;
+ add_psymbol_to_list (actual_name, strlen (actual_name),
+ STRUCT_DOMAIN, LOC_TYPEDEF,
+ cu->language == language_cplus
+ ? &objfile->global_psymbols
+ : &objfile->static_psymbols,
+ 0, (CORE_ADDR) 0, cu->language, objfile);
+
+ if (cu->language == language_cplus)
+ {
+ /* For C++, these implicitly act as typedefs as well. */
+ add_psymbol_to_list (actual_name, strlen (actual_name),
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->global_psymbols,
+ 0, (CORE_ADDR) 0, cu->language, objfile);
+ }
+ break;
+ case DW_TAG_enumerator:
+ add_psymbol_to_list (actual_name, strlen (actual_name),
+ VAR_DOMAIN, LOC_CONST,
+ cu->language == language_cplus
+ ? &objfile->global_psymbols
+ : &objfile->static_psymbols,
+ 0, (CORE_ADDR) 0, cu->language, objfile);
+ break;
+ default:
+ break;
+ }
+
+ /* Check to see if we should scan the name for possible namespace
+ info. Only do this if this is C++, if we don't have namespace
+ debugging info in the file, if the psym is of an appropriate type
+ (otherwise we'll have psym == NULL), and if we actually had a
+ mangled name to begin with. */
+
+ if (cu->language == language_cplus
+ && namespace == NULL
+ && psym != NULL
+ && SYMBOL_CPLUS_DEMANGLED_NAME (psym) != NULL)
+ cp_check_possible_namespace_symbols (SYMBOL_CPLUS_DEMANGLED_NAME (psym),
+ objfile);
+}
+
+/* Determine whether a die of type TAG living in the C++ namespace
+ NAMESPACE needs to have the name of the namespace prepended to the
+ name listed in the die. */
+
+static int
+pdi_needs_namespace (enum dwarf_tag tag, const char *namespace)
+{
+ if (namespace == NULL || namespace[0] == '\0')
+ return 0;
+
+ switch (tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_enumerator:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Read a partial die corresponding to a namespace; also, add a symbol
+ corresponding to that namespace to the symbol table. NAMESPACE is
+ the name of the enclosing namespace. */
+
+static char *
+add_partial_namespace (struct partial_die_info *pdi, char *info_ptr,
+ CORE_ADDR *lowpc, CORE_ADDR *highpc,
+ struct dwarf2_cu *cu, const char *namespace)
+{
+ struct objfile *objfile = cu->objfile;
+ const char *new_name = pdi->name;
+ char *full_name;
+
+ /* Calculate the full name of the namespace that we just entered. */
+
+ if (new_name == NULL)
+ new_name = "(anonymous namespace)";
+ full_name = alloca (strlen (namespace) + 2 + strlen (new_name) + 1);
+ strcpy (full_name, namespace);
+ if (*namespace != '\0')
+ strcat (full_name, "::");
+ strcat (full_name, new_name);
+
+ /* FIXME: carlton/2003-10-07: We can't just replace this by a call
+ to add_partial_symbol, because we don't have a way to pass in the
+ full name to that function; that might be a flaw in
+ add_partial_symbol's interface. */
+
+ add_psymbol_to_list (full_name, strlen (full_name),
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->global_psymbols,
+ 0, 0, cu->language, objfile);
+
+ /* Now scan partial symbols in that namespace. */
+
+ if (pdi->has_children)
+ info_ptr = scan_partial_symbols (info_ptr, lowpc, highpc, cu, full_name);
+
+ return info_ptr;
+}
+
+/* Read a partial die corresponding to a class or structure. */
+
+static char *
+add_partial_structure (struct partial_die_info *struct_pdi, char *info_ptr,
+ struct dwarf2_cu *cu,
+ const char *namespace)
+{
+ bfd *abfd = cu->objfile->obfd;
+ char *actual_class_name = NULL;
+
+ if (cu->language == language_cplus
+ && (namespace == NULL || namespace[0] == '\0')
+ && struct_pdi->name != NULL
+ && struct_pdi->has_children)
+ {
+ /* See if we can figure out if the class lives in a namespace
+ (or is nested within another class.) We do this by looking
+ for a member function; its demangled name will contain
+ namespace info, if there is any. */
+
+ /* NOTE: carlton/2003-10-07: Getting the info this way changes
+ what template types look like, because the demangler
+ frequently doesn't give the same name as the debug info. We
+ could fix this by only using the demangled name to get the
+ prefix (but see comment in read_structure_type). */
+
+ /* FIXME: carlton/2004-01-23: If NAMESPACE equals "", we have
+ the appropriate debug information, so it would be nice to be
+ able to avoid this hack. But NAMESPACE may not be the
+ namespace where this class was defined: NAMESPACE reflects
+ where STRUCT_PDI occurs in the tree of dies, but because of
+ DW_AT_specification, that may not actually tell us where the
+ class is defined. (See the comment in read_func_scope for an
+ example of how this could occur.)
+
+ Unfortunately, our current partial symtab data structures are
+ completely unable to deal with DW_AT_specification. So, for
+ now, the best thing to do is to get nesting information from
+ places other than the tree structure of dies if there's any
+ chance that a DW_AT_specification is involved. :-( */
+
+ char *next_child = info_ptr;
+
+ while (1)
+ {
+ struct partial_die_info child_pdi;
+
+ next_child = read_partial_die (&child_pdi, abfd, next_child,
+ cu);
+ if (!child_pdi.tag)
+ break;
+ if (child_pdi.tag == DW_TAG_subprogram)
+ {
+ actual_class_name = class_name_from_physname (child_pdi.name);
+ if (actual_class_name != NULL)
+ struct_pdi->name = actual_class_name;
+ break;
+ }
+ else
+ {
+ next_child = locate_pdi_sibling (&child_pdi, next_child,
+ abfd, cu);
+ }
+ }
+ }
+
+ add_partial_symbol (struct_pdi, cu, namespace);
+ xfree (actual_class_name);
+
+ return locate_pdi_sibling (struct_pdi, info_ptr, abfd, cu);
+}
+
+/* Read a partial die corresponding to an enumeration type. */
+
+static char *
+add_partial_enumeration (struct partial_die_info *enum_pdi, char *info_ptr,
+ struct dwarf2_cu *cu, const char *namespace)
+{
+ struct objfile *objfile = cu->objfile;
+ bfd *abfd = objfile->obfd;
+ struct partial_die_info pdi;
+
+ if (enum_pdi->name != NULL)
+ add_partial_symbol (enum_pdi, cu, namespace);
+
+ while (1)
+ {
+ info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu);
+ if (pdi.tag == 0)
+ break;
+ if (pdi.tag != DW_TAG_enumerator || pdi.name == NULL)
+ complaint (&symfile_complaints, "malformed enumerator DIE ignored");
+ else
+ add_partial_symbol (&pdi, cu, namespace);
+ }
+
+ return info_ptr;
+}
+
+/* Locate ORIG_PDI's sibling; INFO_PTR should point to the next DIE
+ after ORIG_PDI. */
+
+static char *
+locate_pdi_sibling (struct partial_die_info *orig_pdi, char *info_ptr,
+ bfd *abfd, struct dwarf2_cu *cu)
+{
+ /* Do we know the sibling already? */
+
+ if (orig_pdi->sibling)
+ return orig_pdi->sibling;
+
+ /* Are there any children to deal with? */
+
+ if (!orig_pdi->has_children)
+ return info_ptr;
+
+ /* Okay, we don't know the sibling, but we have children that we
+ want to skip. So read children until we run into one without a
+ tag; return whatever follows it. */
+
+ while (1)
+ {
+ struct partial_die_info pdi;
+
+ info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu);
+
+ if (pdi.tag == 0)
+ return info_ptr;
+ else
+ info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu);
+ }
+}
+
+/* Expand this partial symbol table into a full symbol table. */
+
+static void
+dwarf2_psymtab_to_symtab (struct partial_symtab *pst)
+{
+ /* FIXME: This is barely more than a stub. */
+ if (pst != NULL)
+ {
+ if (pst->readin)
+ {
+ warning ("bug: psymtab for %s is already read in.", pst->filename);
+ }
+ else
+ {
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...", pst->filename);
+ gdb_flush (gdb_stdout);
+ }
+
+ psymtab_to_symtab_1 (pst);
+
+ /* Finish up the debug error message. */
+ if (info_verbose)
+ printf_filtered ("done.\n");
+ }
+ }
+}
+
+static void
+psymtab_to_symtab_1 (struct partial_symtab *pst)
+{
+ struct objfile *objfile = pst->objfile;
+ bfd *abfd = objfile->obfd;
+ struct dwarf2_cu cu;
+ struct die_info *dies;
+ unsigned long offset;
+ CORE_ADDR lowpc, highpc;
+ struct die_info *child_die;
+ char *info_ptr;
+ struct symtab *symtab;
+ struct cleanup *back_to;
+ struct attribute *attr;
+ CORE_ADDR baseaddr;
+
+ /* Set local variables from the partial symbol table info. */
+ offset = DWARF_INFO_OFFSET (pst);
+ dwarf_info_buffer = DWARF_INFO_BUFFER (pst);
+ dwarf_abbrev_buffer = DWARF_ABBREV_BUFFER (pst);
+ dwarf_abbrev_size = DWARF_ABBREV_SIZE (pst);
+ dwarf_line_buffer = DWARF_LINE_BUFFER (pst);
+ dwarf_line_size = DWARF_LINE_SIZE (pst);
+ dwarf_str_buffer = DWARF_STR_BUFFER (pst);
+ dwarf_str_size = DWARF_STR_SIZE (pst);
+ dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst);
+ dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
+ dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst);
+ dwarf_ranges_size = DWARF_RANGES_SIZE (pst);
+ dwarf_loc_buffer = DWARF_LOC_BUFFER (pst);
+ dwarf_loc_size = DWARF_LOC_SIZE (pst);
+ info_ptr = dwarf_info_buffer + offset;
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ /* We're in the global namespace. */
+ processing_current_prefix = "";
+
+ obstack_init (&dwarf2_tmp_obstack);
+ back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL);
+
+ buildsym_init ();
+ make_cleanup (really_free_pendings, NULL);
+
+ cu.objfile = objfile;
+
+ /* read in the comp_unit header */
+ info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd);
+
+ /* Read the abbrevs for this compilation unit */
+ dwarf2_read_abbrevs (abfd, &cu);
+ make_cleanup (dwarf2_empty_abbrev_table, cu.header.dwarf2_abbrevs);
+
+ cu.header.offset = offset;
+
+ cu.list_in_scope = &file_symbols;
+
+ dies = read_comp_unit (info_ptr, abfd, &cu);
+
+ make_cleanup_free_die_list (dies);
+
+ /* Find the base address of the compilation unit for range lists and
+ location lists. It will normally be specified by DW_AT_low_pc.
+ In DWARF-3 draft 4, the base address could be overridden by
+ DW_AT_entry_pc. It's been removed, but GCC still uses this for
+ compilation units with discontinuous ranges. */
+
+ cu.header.base_known = 0;
+ cu.header.base_address = 0;
+
+ attr = dwarf2_attr (dies, DW_AT_entry_pc, &cu);
+ if (attr)
+ {
+ cu.header.base_address = DW_ADDR (attr);
+ cu.header.base_known = 1;
+ }
+ else
+ {
+ attr = dwarf2_attr (dies, DW_AT_low_pc, &cu);
+ if (attr)
+ {
+ cu.header.base_address = DW_ADDR (attr);
+ cu.header.base_known = 1;
+ }
+ }
+
+ /* Do line number decoding in read_file_scope () */
+ process_die (dies, &cu);
+
+ /* Some compilers don't define a DW_AT_high_pc attribute for the
+ compilation unit. If the DW_AT_high_pc is missing, synthesize
+ it, by scanning the DIE's below the compilation unit. */
+ get_scope_pc_bounds (dies, &lowpc, &highpc, &cu);
+
+ symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile));
+
+ /* Set symtab language to language from DW_AT_language.
+ If the compilation is from a C file generated by language preprocessors,
+ do not set the language if it was already deduced by start_subfile. */
+ if (symtab != NULL
+ && !(cu.language == language_c && symtab->language != language_c))
+ {
+ symtab->language = cu.language;
+ }
+ pst->symtab = symtab;
+ pst->readin = 1;
+
+ do_cleanups (back_to);
+}
+
+/* Process a die and its children. */
+
+static void
+process_die (struct die_info *die, struct dwarf2_cu *cu)
+{
+ switch (die->tag)
+ {
+ case DW_TAG_padding:
+ break;
+ case DW_TAG_compile_unit:
+ read_file_scope (die, cu);
+ break;
+ case DW_TAG_subprogram:
+ read_subroutine_type (die, cu);
+ read_func_scope (die, cu);
+ break;
+ case DW_TAG_inlined_subroutine:
+ /* FIXME: These are ignored for now.
+ They could be used to set breakpoints on all inlined instances
+ of a function and make GDB `next' properly over inlined functions. */
+ break;
+ case DW_TAG_lexical_block:
+ case DW_TAG_try_block:
+ case DW_TAG_catch_block:
+ read_lexical_block_scope (die, cu);
+ break;
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ read_structure_type (die, cu);
+ process_structure_scope (die, cu);
+ break;
+ case DW_TAG_enumeration_type:
+ read_enumeration_type (die, cu);
+ process_enumeration_scope (die, cu);
+ break;
+
+ /* FIXME drow/2004-03-14: These initialize die->type, but do not create
+ a symbol or process any children. Therefore it doesn't do anything
+ that won't be done on-demand by read_type_die. */
+ case DW_TAG_subroutine_type:
+ read_subroutine_type (die, cu);
+ break;
+ case DW_TAG_array_type:
+ read_array_type (die, cu);
+ break;
+ case DW_TAG_pointer_type:
+ read_tag_pointer_type (die, cu);
+ break;
+ case DW_TAG_ptr_to_member_type:
+ read_tag_ptr_to_member_type (die, cu);
+ break;
+ case DW_TAG_reference_type:
+ read_tag_reference_type (die, cu);
+ break;
+ case DW_TAG_string_type:
+ read_tag_string_type (die, cu);
+ break;
+ /* END FIXME */
+
+ case DW_TAG_base_type:
+ read_base_type (die, cu);
+ /* Add a typedef symbol for the type definition, if it has a
+ DW_AT_name. */
+ new_symbol (die, die->type, cu);
+ break;
+ case DW_TAG_subrange_type:
+ read_subrange_type (die, cu);
+ /* Add a typedef symbol for the type definition, if it has a
+ DW_AT_name. */
+ new_symbol (die, die->type, cu);
+ break;
+ case DW_TAG_common_block:
+ read_common_block (die, cu);
+ break;
+ case DW_TAG_common_inclusion:
+ break;
+ case DW_TAG_namespace:
+ processing_has_namespace_info = 1;
+ read_namespace (die, cu);
+ break;
+ case DW_TAG_imported_declaration:
+ case DW_TAG_imported_module:
+ /* FIXME: carlton/2002-10-16: Eventually, we should use the
+ information contained in these. DW_TAG_imported_declaration
+ dies shouldn't have children; DW_TAG_imported_module dies
+ shouldn't in the C++ case, but conceivably could in the
+ Fortran case, so we'll have to replace this gdb_assert if
+ Fortran compilers start generating that info. */
+ processing_has_namespace_info = 1;
+ gdb_assert (die->child == NULL);
+ break;
+ default:
+ new_symbol (die, NULL, cu);
+ break;
+ }
+}
+
+static void
+initialize_cu_func_list (struct dwarf2_cu *cu)
+{
+ cu->first_fn = cu->last_fn = cu->cached_fn = NULL;
+}
+
+static void
+read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct comp_unit_head *cu_header = &cu->header;
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+ CORE_ADDR lowpc = ((CORE_ADDR) -1);
+ CORE_ADDR highpc = ((CORE_ADDR) 0);
+ struct attribute *attr;
+ char *name = "<unknown>";
+ char *comp_dir = NULL;
+ struct die_info *child_die;
+ bfd *abfd = objfile->obfd;
+ struct line_header *line_header = 0;
+ CORE_ADDR baseaddr;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ get_scope_pc_bounds (die, &lowpc, &highpc, cu);
+
+ /* If we didn't find a lowpc, set it to highpc to avoid complaints
+ from finish_block. */
+ if (lowpc == ((CORE_ADDR) -1))
+ lowpc = highpc;
+ lowpc += baseaddr;
+ highpc += baseaddr;
+
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr)
+ {
+ name = DW_STRING (attr);
+ }
+ attr = dwarf2_attr (die, DW_AT_comp_dir, cu);
+ if (attr)
+ {
+ comp_dir = DW_STRING (attr);
+ if (comp_dir)
+ {
+ /* Irix 6.2 native cc prepends <machine>.: to the compilation
+ directory, get rid of it. */
+ char *cp = strchr (comp_dir, ':');
+
+ if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/')
+ comp_dir = cp + 1;
+ }
+ }
+
+ if (objfile->ei.entry_point >= lowpc &&
+ objfile->ei.entry_point < highpc)
+ {
+ objfile->ei.deprecated_entry_file_lowpc = lowpc;
+ objfile->ei.deprecated_entry_file_highpc = highpc;
+ }
+
+ attr = dwarf2_attr (die, DW_AT_language, cu);
+ if (attr)
+ {
+ set_cu_language (DW_UNSND (attr), cu);
+ }
+
+ /* We assume that we're processing GCC output. */
+ processing_gcc_compilation = 2;
+#if 0
+ /* FIXME:Do something here. */
+ if (dip->at_producer != NULL)
+ {
+ handle_producer (dip->at_producer);
+ }
+#endif
+
+ /* The compilation unit may be in a different language or objfile,
+ zero out all remembered fundamental types. */
+ memset (cu->ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *));
+
+ start_symtab (name, comp_dir, lowpc);
+ record_debugformat ("DWARF 2");
+
+ initialize_cu_func_list (cu);
+
+ /* Process all dies in compilation unit. */
+ if (die->child != NULL)
+ {
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ process_die (child_die, cu);
+ child_die = sibling_die (child_die);
+ }
+ }
+
+ /* Decode line number information if present. */
+ attr = dwarf2_attr (die, DW_AT_stmt_list, cu);
+ if (attr)
+ {
+ unsigned int line_offset = DW_UNSND (attr);
+ line_header = dwarf_decode_line_header (line_offset, abfd, cu);
+ if (line_header)
+ {
+ make_cleanup ((make_cleanup_ftype *) free_line_header,
+ (void *) line_header);
+ dwarf_decode_lines (line_header, comp_dir, abfd, cu);
+ }
+ }
+
+ /* Decode macro information, if present. Dwarf 2 macro information
+ refers to information in the line number info statement program
+ header, so we can only read it if we've read the header
+ successfully. */
+ attr = dwarf2_attr (die, DW_AT_macro_info, cu);
+ if (attr && line_header)
+ {
+ unsigned int macro_offset = DW_UNSND (attr);
+ dwarf_decode_macros (line_header, macro_offset,
+ comp_dir, abfd, cu);
+ }
+ do_cleanups (back_to);
+}
+
+static void
+add_to_cu_func_list (const char *name, CORE_ADDR lowpc, CORE_ADDR highpc,
+ struct dwarf2_cu *cu)
+{
+ struct function_range *thisfn;
+
+ thisfn = (struct function_range *)
+ obstack_alloc (&dwarf2_tmp_obstack, sizeof (struct function_range));
+ thisfn->name = name;
+ thisfn->lowpc = lowpc;
+ thisfn->highpc = highpc;
+ thisfn->seen_line = 0;
+ thisfn->next = NULL;
+
+ if (cu->last_fn == NULL)
+ cu->first_fn = thisfn;
+ else
+ cu->last_fn->next = thisfn;
+
+ cu->last_fn = thisfn;
+}
+
+static void
+read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct context_stack *new;
+ CORE_ADDR lowpc;
+ CORE_ADDR highpc;
+ struct die_info *child_die;
+ struct attribute *attr;
+ char *name;
+ const char *previous_prefix = processing_current_prefix;
+ struct cleanup *back_to = NULL;
+ CORE_ADDR baseaddr;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ name = dwarf2_linkage_name (die, cu);
+
+ /* Ignore functions with missing or empty names and functions with
+ missing or invalid low and high pc attributes. */
+ if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu))
+ return;
+
+ if (cu->language == language_cplus)
+ {
+ struct die_info *spec_die = die_specification (die, cu);
+
+ /* NOTE: carlton/2004-01-23: We have to be careful in the
+ presence of DW_AT_specification. For example, with GCC 3.4,
+ given the code
+
+ namespace N {
+ void foo() {
+ // Definition of N::foo.
+ }
+ }
+
+ then we'll have a tree of DIEs like this:
+
+ 1: DW_TAG_compile_unit
+ 2: DW_TAG_namespace // N
+ 3: DW_TAG_subprogram // declaration of N::foo
+ 4: DW_TAG_subprogram // definition of N::foo
+ DW_AT_specification // refers to die #3
+
+ Thus, when processing die #4, we have to pretend that we're
+ in the context of its DW_AT_specification, namely the contex
+ of die #3. */
+
+ if (spec_die != NULL)
+ {
+ char *specification_prefix = determine_prefix (spec_die, cu);
+ processing_current_prefix = specification_prefix;
+ back_to = make_cleanup (xfree, specification_prefix);
+ }
+ }
+
+ lowpc += baseaddr;
+ highpc += baseaddr;
+
+ /* Record the function range for dwarf_decode_lines. */
+ add_to_cu_func_list (name, lowpc, highpc, cu);
+
+ if (objfile->ei.entry_point >= lowpc &&
+ objfile->ei.entry_point < highpc)
+ {
+ objfile->ei.entry_func_lowpc = lowpc;
+ objfile->ei.entry_func_highpc = highpc;
+ }
+
+ new = push_context (0, lowpc);
+ new->name = new_symbol (die, die->type, cu);
+
+ /* If there is a location expression for DW_AT_frame_base, record
+ it. */
+ attr = dwarf2_attr (die, DW_AT_frame_base, cu);
+ if (attr)
+ /* FIXME: cagney/2004-01-26: The DW_AT_frame_base's location
+ expression is being recorded directly in the function's symbol
+ and not in a separate frame-base object. I guess this hack is
+ to avoid adding some sort of frame-base adjunct/annex to the
+ function's symbol :-(. The problem with doing this is that it
+ results in a function symbol with a location expression that
+ has nothing to do with the location of the function, ouch! The
+ relationship should be: a function's symbol has-a frame base; a
+ frame-base has-a location expression. */
+ dwarf2_symbol_mark_computed (attr, new->name, cu);
+
+ cu->list_in_scope = &local_symbols;
+
+ if (die->child != NULL)
+ {
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ process_die (child_die, cu);
+ child_die = sibling_die (child_die);
+ }
+ }
+
+ new = pop_context ();
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ lowpc, highpc, objfile);
+
+ /* In C++, we can have functions nested inside functions (e.g., when
+ a function declares a class that has methods). This means that
+ when we finish processing a function scope, we may need to go
+ back to building a containing block's symbol lists. */
+ local_symbols = new->locals;
+ param_symbols = new->params;
+
+ /* If we've finished processing a top-level function, subsequent
+ symbols go in the file symbol list. */
+ if (outermost_context_p ())
+ cu->list_in_scope = &file_symbols;
+
+ processing_current_prefix = previous_prefix;
+ if (back_to != NULL)
+ do_cleanups (back_to);
+}
+
+/* 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 (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct context_stack *new;
+ CORE_ADDR lowpc, highpc;
+ struct die_info *child_die;
+ CORE_ADDR baseaddr;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ /* Ignore blocks with missing or invalid low and high pc attributes. */
+ /* ??? Perhaps consider discontiguous blocks defined by DW_AT_ranges
+ as multiple lexical blocks? Handling children in a sane way would
+ be nasty. Might be easier to properly extend generic blocks to
+ describe ranges. */
+ if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu))
+ return;
+ lowpc += baseaddr;
+ highpc += baseaddr;
+
+ push_context (0, lowpc);
+ if (die->child != NULL)
+ {
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ process_die (child_die, cu);
+ child_die = sibling_die (child_die);
+ }
+ }
+ new = pop_context ();
+
+ if (local_symbols != NULL)
+ {
+ finish_block (0, &local_symbols, new->old_blocks, new->start_addr,
+ highpc, objfile);
+ }
+ local_symbols = new->locals;
+}
+
+/* Get low and high pc attributes from a die. Return 1 if the attributes
+ are present and valid, otherwise, return 0. Return -1 if the range is
+ discontinuous, i.e. derived from DW_AT_ranges information. */
+static int
+dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
+ CORE_ADDR *highpc, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct comp_unit_head *cu_header = &cu->header;
+ struct attribute *attr;
+ bfd *obfd = objfile->obfd;
+ CORE_ADDR low = 0;
+ CORE_ADDR high = 0;
+ int ret = 0;
+
+ attr = dwarf2_attr (die, DW_AT_high_pc, cu);
+ if (attr)
+ {
+ high = DW_ADDR (attr);
+ attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+ if (attr)
+ low = DW_ADDR (attr);
+ else
+ /* Found high w/o low attribute. */
+ return 0;
+
+ /* Found consecutive range of addresses. */
+ ret = 1;
+ }
+ else
+ {
+ attr = dwarf2_attr (die, DW_AT_ranges, cu);
+ if (attr != NULL)
+ {
+ unsigned int addr_size = cu_header->addr_size;
+ CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+ /* Value of the DW_AT_ranges attribute is the offset in the
+ .debug_ranges section. */
+ unsigned int offset = DW_UNSND (attr);
+ /* Base address selection entry. */
+ CORE_ADDR base;
+ int found_base;
+ int dummy;
+ char *buffer;
+ CORE_ADDR marker;
+ int low_set;
+
+ found_base = cu_header->base_known;
+ base = cu_header->base_address;
+
+ if (offset >= dwarf_ranges_size)
+ {
+ complaint (&symfile_complaints,
+ "Offset %d out of bounds for DW_AT_ranges attribute",
+ offset);
+ return 0;
+ }
+ buffer = dwarf_ranges_buffer + offset;
+
+ /* Read in the largest possible address. */
+ marker = read_address (obfd, buffer, cu, &dummy);
+ if ((marker & mask) == mask)
+ {
+ /* If we found the largest possible address, then
+ read the base address. */
+ base = read_address (obfd, buffer + addr_size, cu, &dummy);
+ buffer += 2 * addr_size;
+ offset += 2 * addr_size;
+ found_base = 1;
+ }
+
+ low_set = 0;
+
+ while (1)
+ {
+ CORE_ADDR range_beginning, range_end;
+
+ range_beginning = read_address (obfd, buffer, cu, &dummy);
+ buffer += addr_size;
+ range_end = read_address (obfd, buffer, cu, &dummy);
+ buffer += addr_size;
+ offset += 2 * addr_size;
+
+ /* An end of list marker is a pair of zero addresses. */
+ if (range_beginning == 0 && range_end == 0)
+ /* Found the end of list entry. */
+ break;
+
+ /* Each base address selection entry is a pair of 2 values.
+ The first is the largest possible address, the second is
+ the base address. Check for a base address here. */
+ if ((range_beginning & mask) == mask)
+ {
+ /* If we found the largest possible address, then
+ read the base address. */
+ base = read_address (obfd, buffer + addr_size, cu, &dummy);
+ found_base = 1;
+ continue;
+ }
+
+ if (!found_base)
+ {
+ /* We have no valid base address for the ranges
+ data. */
+ complaint (&symfile_complaints,
+ "Invalid .debug_ranges data (no base address)");
+ return 0;
+ }
+
+ range_beginning += base;
+ range_end += base;
+
+ /* FIXME: This is recording everything as a low-high
+ segment of consecutive addresses. We should have a
+ data structure for discontiguous block ranges
+ instead. */
+ if (! low_set)
+ {
+ low = range_beginning;
+ high = range_end;
+ low_set = 1;
+ }
+ else
+ {
+ if (range_beginning < low)
+ low = range_beginning;
+ if (range_end > high)
+ high = range_end;
+ }
+ }
+
+ if (! low_set)
+ /* If the first entry is an end-of-list marker, the range
+ describes an empty scope, i.e. no instructions. */
+ return 0;
+
+ ret = -1;
+ }
+ }
+
+ if (high < low)
+ return 0;
+
+ /* When using the GNU linker, .gnu.linkonce. sections are used to
+ eliminate duplicate copies of functions and vtables and such.
+ The linker will arbitrarily choose one and discard the others.
+ The AT_*_pc values for such functions refer to local labels in
+ these sections. If the section from that file was discarded, the
+ labels are not in the output, so the relocs get a value of 0.
+ If this is a discarded function, mark the pc bounds as invalid,
+ so that GDB will ignore it. */
+ if (low == 0 && (bfd_get_file_flags (obfd) & HAS_RELOC) == 0)
+ return 0;
+
+ *lowpc = low;
+ *highpc = high;
+ return ret;
+}
+
+/* Get the low and high pc's represented by the scope DIE, and store
+ them in *LOWPC and *HIGHPC. If the correct values can't be
+ determined, set *LOWPC to -1 and *HIGHPC to 0. */
+
+static void
+get_scope_pc_bounds (struct die_info *die,
+ CORE_ADDR *lowpc, CORE_ADDR *highpc,
+ struct dwarf2_cu *cu)
+{
+ CORE_ADDR best_low = (CORE_ADDR) -1;
+ CORE_ADDR best_high = (CORE_ADDR) 0;
+ CORE_ADDR current_low, current_high;
+
+ if (dwarf2_get_pc_bounds (die, &current_low, &current_high, cu))
+ {
+ best_low = current_low;
+ best_high = current_high;
+ }
+ else
+ {
+ struct die_info *child = die->child;
+
+ while (child && child->tag)
+ {
+ switch (child->tag) {
+ case DW_TAG_subprogram:
+ if (dwarf2_get_pc_bounds (child, &current_low, &current_high, cu))
+ {
+ best_low = min (best_low, current_low);
+ best_high = max (best_high, current_high);
+ }
+ break;
+ case DW_TAG_namespace:
+ /* FIXME: carlton/2004-01-16: Should we do this for
+ DW_TAG_class_type/DW_TAG_structure_type, too? I think
+ that current GCC's always emit the DIEs corresponding
+ to definitions of methods of classes as children of a
+ DW_TAG_compile_unit or DW_TAG_namespace (as opposed to
+ the DIEs giving the declarations, which could be
+ anywhere). But I don't see any reason why the
+ standards says that they have to be there. */
+ get_scope_pc_bounds (child, &current_low, &current_high, cu);
+
+ if (current_low != ((CORE_ADDR) -1))
+ {
+ best_low = min (best_low, current_low);
+ best_high = max (best_high, current_high);
+ }
+ break;
+ default:
+ /* Ignore. */
+ break;
+ }
+
+ child = sibling_die (child);
+ }
+ }
+
+ *lowpc = best_low;
+ *highpc = best_high;
+}
+
+/* Add an aggregate field to the field list. */
+
+static void
+dwarf2_add_field (struct field_info *fip, struct die_info *die,
+ struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct nextfield *new_field;
+ struct attribute *attr;
+ struct field *fp;
+ char *fieldname = "";
+
+ /* Allocate a new field list entry and link it in. */
+ new_field = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (xfree, new_field);
+ memset (new_field, 0, sizeof (struct nextfield));
+ new_field->next = fip->fields;
+ fip->fields = new_field;
+ fip->nfields++;
+
+ /* Handle accessibility and virtuality of field.
+ The default accessibility for members is public, the default
+ accessibility for inheritance is private. */
+ if (die->tag != DW_TAG_inheritance)
+ new_field->accessibility = DW_ACCESS_public;
+ else
+ new_field->accessibility = DW_ACCESS_private;
+ new_field->virtuality = DW_VIRTUALITY_none;
+
+ attr = dwarf2_attr (die, DW_AT_accessibility, cu);
+ if (attr)
+ new_field->accessibility = DW_UNSND (attr);
+ if (new_field->accessibility != DW_ACCESS_public)
+ fip->non_public_fields = 1;
+ attr = dwarf2_attr (die, DW_AT_virtuality, cu);
+ if (attr)
+ new_field->virtuality = DW_UNSND (attr);
+
+ fp = &new_field->field;
+
+ if (die->tag == DW_TAG_member && ! die_is_declaration (die, cu))
+ {
+ /* Data member other than a C++ static data member. */
+
+ /* Get type of field. */
+ fp->type = die_type (die, cu);
+
+ FIELD_STATIC_KIND (*fp) = 0;
+
+ /* Get bit size of field (zero if none). */
+ attr = dwarf2_attr (die, DW_AT_bit_size, cu);
+ if (attr)
+ {
+ FIELD_BITSIZE (*fp) = DW_UNSND (attr);
+ }
+ else
+ {
+ FIELD_BITSIZE (*fp) = 0;
+ }
+
+ /* Get bit offset of field. */
+ attr = dwarf2_attr (die, DW_AT_data_member_location, cu);
+ if (attr)
+ {
+ FIELD_BITPOS (*fp) =
+ decode_locdesc (DW_BLOCK (attr), cu) * bits_per_byte;
+ }
+ else
+ FIELD_BITPOS (*fp) = 0;
+ attr = dwarf2_attr (die, DW_AT_bit_offset, cu);
+ if (attr)
+ {
+ if (BITS_BIG_ENDIAN)
+ {
+ /* For big endian bits, the DW_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. */
+ FIELD_BITPOS (*fp) += DW_UNSND (attr);
+ }
+ else
+ {
+ /* For little endian bits, 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. */
+ int anonymous_size;
+ int bit_offset = DW_UNSND (attr);
+
+ attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr)
+ {
+ /* The size of the anonymous object containing
+ the bit field is explicit, so use the
+ indicated size (in bytes). */
+ anonymous_size = DW_UNSND (attr);
+ }
+ else
+ {
+ /* The size of the anonymous object containing
+ the bit field must be inferred from the type
+ attribute of the data member containing the
+ bit field. */
+ anonymous_size = TYPE_LENGTH (fp->type);
+ }
+ FIELD_BITPOS (*fp) += anonymous_size * bits_per_byte
+ - bit_offset - FIELD_BITSIZE (*fp);
+ }
+ }
+
+ /* Get name of field. */
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ fieldname = DW_STRING (attr);
+ fp->name = obsavestring (fieldname, strlen (fieldname),
+ &objfile->objfile_obstack);
+
+ /* Change accessibility for artificial fields (e.g. virtual table
+ pointer or virtual base class pointer) to private. */
+ if (dwarf2_attr (die, DW_AT_artificial, cu))
+ {
+ new_field->accessibility = DW_ACCESS_private;
+ fip->non_public_fields = 1;
+ }
+ }
+ else if (die->tag == DW_TAG_member || die->tag == DW_TAG_variable)
+ {
+ /* C++ static member. */
+
+ /* NOTE: carlton/2002-11-05: It should be a DW_TAG_member that
+ is a declaration, but all versions of G++ as of this writing
+ (so through at least 3.2.1) incorrectly generate
+ DW_TAG_variable tags. */
+
+ char *physname;
+
+ /* Get name of field. */
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ fieldname = DW_STRING (attr);
+ else
+ return;
+
+ /* Get physical name. */
+ physname = dwarf2_linkage_name (die, cu);
+
+ SET_FIELD_PHYSNAME (*fp, obsavestring (physname, strlen (physname),
+ &objfile->objfile_obstack));
+ FIELD_TYPE (*fp) = die_type (die, cu);
+ FIELD_NAME (*fp) = obsavestring (fieldname, strlen (fieldname),
+ &objfile->objfile_obstack);
+ }
+ else if (die->tag == DW_TAG_inheritance)
+ {
+ /* C++ base class field. */
+ attr = dwarf2_attr (die, DW_AT_data_member_location, cu);
+ if (attr)
+ FIELD_BITPOS (*fp) = (decode_locdesc (DW_BLOCK (attr), cu)
+ * bits_per_byte);
+ FIELD_BITSIZE (*fp) = 0;
+ FIELD_STATIC_KIND (*fp) = 0;
+ FIELD_TYPE (*fp) = die_type (die, cu);
+ FIELD_NAME (*fp) = type_name_no_tag (fp->type);
+ fip->nbaseclasses++;
+ }
+}
+
+/* Create the vector of fields, and attach it to the type. */
+
+static void
+dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
+ struct dwarf2_cu *cu)
+{
+ int nfields = fip->nfields;
+
+ /* Record the field count, allocate space for the array of fields,
+ and create blank accessibility 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 (fip->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);
+ }
+
+ /* If the type has baseclasses, allocate and clear a bit vector for
+ TYPE_FIELD_VIRTUAL_BITS. */
+ if (fip->nbaseclasses)
+ {
+ int num_bytes = B_BYTES (fip->nbaseclasses);
+ char *pointer;
+
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ pointer = (char *) TYPE_ALLOC (type, num_bytes);
+ TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer;
+ B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), fip->nbaseclasses);
+ TYPE_N_BASECLASSES (type) = fip->nbaseclasses;
+ }
+
+ /* 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->fields->field;
+ switch (fip->fields->accessibility)
+ {
+ case DW_ACCESS_private:
+ SET_TYPE_FIELD_PRIVATE (type, nfields);
+ break;
+
+ case DW_ACCESS_protected:
+ SET_TYPE_FIELD_PROTECTED (type, nfields);
+ break;
+
+ case DW_ACCESS_public:
+ break;
+
+ default:
+ /* Unknown accessibility. Complain and treat it as public. */
+ {
+ complaint (&symfile_complaints, "unsupported accessibility %d",
+ fip->fields->accessibility);
+ }
+ break;
+ }
+ if (nfields < fip->nbaseclasses)
+ {
+ switch (fip->fields->virtuality)
+ {
+ case DW_VIRTUALITY_virtual:
+ case DW_VIRTUALITY_pure_virtual:
+ SET_TYPE_FIELD_VIRTUAL (type, nfields);
+ break;
+ }
+ }
+ fip->fields = fip->fields->next;
+ }
+}
+
+/* Add a member function to the proper fieldlist. */
+
+static void
+dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
+ struct type *type, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct attribute *attr;
+ struct fnfieldlist *flp;
+ int i;
+ struct fn_field *fnp;
+ char *fieldname;
+ char *physname;
+ struct nextfnfield *new_fnfield;
+
+ /* Get name of member function. */
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ fieldname = DW_STRING (attr);
+ else
+ return;
+
+ /* Get the mangled name. */
+ physname = dwarf2_linkage_name (die, cu);
+
+ /* Look up member function name in fieldlist. */
+ for (i = 0; i < fip->nfnfields; i++)
+ {
+ if (strcmp (fip->fnfieldlists[i].name, fieldname) == 0)
+ break;
+ }
+
+ /* Create new list element if necessary. */
+ if (i < fip->nfnfields)
+ flp = &fip->fnfieldlists[i];
+ else
+ {
+ if ((fip->nfnfields % DW_FIELD_ALLOC_CHUNK) == 0)
+ {
+ fip->fnfieldlists = (struct fnfieldlist *)
+ xrealloc (fip->fnfieldlists,
+ (fip->nfnfields + DW_FIELD_ALLOC_CHUNK)
+ * sizeof (struct fnfieldlist));
+ if (fip->nfnfields == 0)
+ make_cleanup (free_current_contents, &fip->fnfieldlists);
+ }
+ flp = &fip->fnfieldlists[fip->nfnfields];
+ flp->name = fieldname;
+ flp->length = 0;
+ flp->head = NULL;
+ fip->nfnfields++;
+ }
+
+ /* Create a new member function field and chain it to the field list
+ entry. */
+ new_fnfield = (struct nextfnfield *) xmalloc (sizeof (struct nextfnfield));
+ make_cleanup (xfree, new_fnfield);
+ memset (new_fnfield, 0, sizeof (struct nextfnfield));
+ new_fnfield->next = flp->head;
+ flp->head = new_fnfield;
+ flp->length++;
+
+ /* Fill in the member function field info. */
+ fnp = &new_fnfield->fnfield;
+ fnp->physname = obsavestring (physname, strlen (physname),
+ &objfile->objfile_obstack);
+ fnp->type = alloc_type (objfile);
+ if (die->type && TYPE_CODE (die->type) == TYPE_CODE_FUNC)
+ {
+ int nparams = TYPE_NFIELDS (die->type);
+
+ /* TYPE is the domain of this method, and DIE->TYPE is the type
+ of the method itself (TYPE_CODE_METHOD). */
+ smash_to_method_type (fnp->type, type,
+ TYPE_TARGET_TYPE (die->type),
+ TYPE_FIELDS (die->type),
+ TYPE_NFIELDS (die->type),
+ TYPE_VARARGS (die->type));
+
+ /* Handle static member functions.
+ Dwarf2 has no clean way to discern C++ static and non-static
+ member functions. G++ helps GDB by marking the first
+ parameter for non-static member functions (which is the
+ this pointer) as artificial. We obtain this information
+ from read_subroutine_type via TYPE_FIELD_ARTIFICIAL. */
+ if (nparams == 0 || TYPE_FIELD_ARTIFICIAL (die->type, 0) == 0)
+ fnp->voffset = VOFFSET_STATIC;
+ }
+ else
+ complaint (&symfile_complaints, "member function type missing for '%s'",
+ physname);
+
+ /* Get fcontext from DW_AT_containing_type if present. */
+ if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL)
+ fnp->fcontext = die_containing_type (die, cu);
+
+ /* dwarf2 doesn't have stubbed physical names, so the setting of is_const
+ and is_volatile is irrelevant, as it is needed by gdb_mangle_name only. */
+
+ /* Get accessibility. */
+ attr = dwarf2_attr (die, DW_AT_accessibility, cu);
+ if (attr)
+ {
+ switch (DW_UNSND (attr))
+ {
+ case DW_ACCESS_private:
+ fnp->is_private = 1;
+ break;
+ case DW_ACCESS_protected:
+ fnp->is_protected = 1;
+ break;
+ }
+ }
+
+ /* Check for artificial methods. */
+ attr = dwarf2_attr (die, DW_AT_artificial, cu);
+ if (attr && DW_UNSND (attr) != 0)
+ fnp->is_artificial = 1;
+
+ /* Get index in virtual function table if it is a virtual member function. */
+ attr = dwarf2_attr (die, DW_AT_vtable_elem_location, cu);
+ if (attr)
+ {
+ /* Support the .debug_loc offsets */
+ if (attr_form_is_block (attr))
+ {
+ fnp->voffset = decode_locdesc (DW_BLOCK (attr), cu) + 2;
+ }
+ else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
+ {
+ dwarf2_complex_location_expr_complaint ();
+ }
+ else
+ {
+ dwarf2_invalid_attrib_class_complaint ("DW_AT_vtable_elem_location",
+ fieldname);
+ }
+ }
+}
+
+/* Create the vector of member function fields, and attach it to the type. */
+
+static void
+dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type,
+ struct dwarf2_cu *cu)
+{
+ struct fnfieldlist *flp;
+ int total_length = 0;
+ int i;
+
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+ TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * fip->nfnfields);
+
+ for (i = 0, flp = fip->fnfieldlists; i < fip->nfnfields; i++, flp++)
+ {
+ struct nextfnfield *nfp = flp->head;
+ struct fn_fieldlist *fn_flp = &TYPE_FN_FIELDLIST (type, i);
+ int k;
+
+ TYPE_FN_FIELDLIST_NAME (type, i) = flp->name;
+ TYPE_FN_FIELDLIST_LENGTH (type, i) = flp->length;
+ fn_flp->fn_fields = (struct fn_field *)
+ TYPE_ALLOC (type, sizeof (struct fn_field) * flp->length);
+ for (k = flp->length; (k--, nfp); nfp = nfp->next)
+ fn_flp->fn_fields[k] = nfp->fnfield;
+
+ total_length += flp->length;
+ }
+
+ TYPE_NFN_FIELDS (type) = fip->nfnfields;
+ TYPE_NFN_FIELDS_TOTAL (type) = total_length;
+}
+
+/* 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.
+
+ NOTE: 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_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct type *type;
+ struct attribute *attr;
+ const char *previous_prefix = processing_current_prefix;
+ struct cleanup *back_to = NULL;
+
+ if (die->type)
+ return;
+
+ type = alloc_type (objfile);
+
+ INIT_CPLUS_SPECIFIC (type);
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ {
+ if (cu->language == language_cplus)
+ {
+ char *new_prefix = determine_class_name (die, cu);
+ TYPE_TAG_NAME (type) = obsavestring (new_prefix,
+ strlen (new_prefix),
+ &objfile->objfile_obstack);
+ back_to = make_cleanup (xfree, new_prefix);
+ processing_current_prefix = new_prefix;
+ }
+ else
+ {
+ TYPE_TAG_NAME (type) = DW_STRING (attr);
+ }
+ }
+
+ if (die->tag == DW_TAG_structure_type)
+ {
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ }
+ else if (die->tag == DW_TAG_union_type)
+ {
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ }
+ else
+ {
+ /* FIXME: TYPE_CODE_CLASS is currently defined to TYPE_CODE_STRUCT
+ in gdbtypes.h. */
+ TYPE_CODE (type) = TYPE_CODE_CLASS;
+ }
+
+ attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr)
+ {
+ TYPE_LENGTH (type) = DW_UNSND (attr);
+ }
+ else
+ {
+ TYPE_LENGTH (type) = 0;
+ }
+
+ /* We need to add the type field to the die immediately so we don't
+ infinitely recurse when dealing with pointers to the structure
+ type within the structure itself. */
+ die->type = type;
+
+ if (die->child != NULL && ! die_is_declaration (die, cu))
+ {
+ struct field_info fi;
+ struct die_info *child_die;
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+
+ memset (&fi, 0, sizeof (struct field_info));
+
+ child_die = die->child;
+
+ while (child_die && child_die->tag)
+ {
+ if (child_die->tag == DW_TAG_member
+ || child_die->tag == DW_TAG_variable)
+ {
+ /* NOTE: carlton/2002-11-05: A C++ static data member
+ should be a DW_TAG_member that is a declaration, but
+ all versions of G++ as of this writing (so through at
+ least 3.2.1) incorrectly generate DW_TAG_variable
+ tags for them instead. */
+ dwarf2_add_field (&fi, child_die, cu);
+ }
+ else if (child_die->tag == DW_TAG_subprogram)
+ {
+ /* C++ member function. */
+ read_type_die (child_die, cu);
+ dwarf2_add_member_fn (&fi, child_die, type, cu);
+ }
+ else if (child_die->tag == DW_TAG_inheritance)
+ {
+ /* C++ base class field. */
+ dwarf2_add_field (&fi, child_die, cu);
+ }
+ child_die = sibling_die (child_die);
+ }
+
+ /* Attach fields and member functions to the type. */
+ if (fi.nfields)
+ dwarf2_attach_fields_to_type (&fi, type, cu);
+ if (fi.nfnfields)
+ {
+ dwarf2_attach_fn_fields_to_type (&fi, type, cu);
+
+ /* Get the type which refers to the base class (possibly this
+ class itself) which contains the vtable pointer for the current
+ class from the DW_AT_containing_type attribute. */
+
+ if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL)
+ {
+ struct type *t = die_containing_type (die, cu);
+
+ TYPE_VPTR_BASETYPE (type) = t;
+ if (type == t)
+ {
+ static const char vptr_name[] =
+ {'_', 'v', 'p', 't', 'r', '\0'};
+ int i;
+
+ /* Our own class provides vtbl ptr. */
+ for (i = TYPE_NFIELDS (t) - 1;
+ i >= TYPE_N_BASECLASSES (t);
+ --i)
+ {
+ char *fieldname = TYPE_FIELD_NAME (t, i);
+
+ if ((strncmp (fieldname, vptr_name,
+ strlen (vptr_name) - 1)
+ == 0)
+ && is_cplus_marker (fieldname[strlen (vptr_name)]))
+ {
+ TYPE_VPTR_FIELDNO (type) = i;
+ break;
+ }
+ }
+
+ /* Complain if virtual function table field not found. */
+ if (i < TYPE_N_BASECLASSES (t))
+ complaint (&symfile_complaints,
+ "virtual function table pointer not found when defining class '%s'",
+ TYPE_TAG_NAME (type) ? TYPE_TAG_NAME (type) :
+ "");
+ }
+ else
+ {
+ TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
+ }
+ }
+ }
+
+ do_cleanups (back_to);
+ }
+ else
+ {
+ /* No children, must be stub. */
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+ }
+
+ processing_current_prefix = previous_prefix;
+ if (back_to != NULL)
+ do_cleanups (back_to);
+}
+
+static void
+process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ const char *previous_prefix = processing_current_prefix;
+ struct die_info *child_die = die->child;
+
+ if (TYPE_TAG_NAME (die->type) != NULL)
+ processing_current_prefix = TYPE_TAG_NAME (die->type);
+
+ /* NOTE: carlton/2004-03-16: GCC 3.4 (or at least one of its
+ snapshots) has been known to create a die giving a declaration
+ for a class that has, as a child, a die giving a definition for a
+ nested class. So we have to process our children even if the
+ current die is a declaration. Normally, of course, a declaration
+ won't have any children at all. */
+
+ while (child_die != NULL && child_die->tag)
+ {
+ if (child_die->tag == DW_TAG_member
+ || child_die->tag == DW_TAG_variable
+ || child_die->tag == DW_TAG_inheritance)
+ {
+ /* Do nothing. */
+ }
+ else
+ process_die (child_die, cu);
+
+ child_die = sibling_die (child_die);
+ }
+
+ if (die->child != NULL && ! die_is_declaration (die, cu))
+ new_symbol (die, die->type, cu);
+
+ processing_current_prefix = previous_prefix;
+}
+
+/* Given a DW_AT_enumeration_type die, set its type. We do not
+ complete the type's fields yet, or create any symbols. */
+
+static void
+read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct type *type;
+ struct attribute *attr;
+
+ if (die->type)
+ return;
+
+ type = alloc_type (objfile);
+
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ {
+ const char *name = DW_STRING (attr);
+
+ if (processing_has_namespace_info)
+ {
+ TYPE_TAG_NAME (type) = obconcat (&objfile->objfile_obstack,
+ processing_current_prefix,
+ processing_current_prefix[0] == '\0'
+ ? "" : "::",
+ name);
+ }
+ else
+ {
+ TYPE_TAG_NAME (type) = obsavestring (name, strlen (name),
+ &objfile->objfile_obstack);
+ }
+ }
+
+ attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr)
+ {
+ TYPE_LENGTH (type) = DW_UNSND (attr);
+ }
+ else
+ {
+ TYPE_LENGTH (type) = 0;
+ }
+
+ die->type = type;
+}
+
+/* Determine the name of the type represented by DIE, which should be
+ a named C++ compound type. Return the name in question; the caller
+ is responsible for xfree()'ing it. */
+
+static char *
+determine_class_name (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct cleanup *back_to = NULL;
+ struct die_info *spec_die = die_specification (die, cu);
+ char *new_prefix = NULL;
+
+ /* If this is the definition of a class that is declared by another
+ die, then processing_current_prefix may not be accurate; see
+ read_func_scope for a similar example. */
+ if (spec_die != NULL)
+ {
+ char *specification_prefix = determine_prefix (spec_die, cu);
+ processing_current_prefix = specification_prefix;
+ back_to = make_cleanup (xfree, specification_prefix);
+ }
+
+ /* If we don't have namespace debug info, guess the name by trying
+ to demangle the names of members, just like we did in
+ add_partial_structure. */
+ if (!processing_has_namespace_info)
+ {
+ struct die_info *child;
+
+ for (child = die->child;
+ child != NULL && child->tag != 0;
+ child = sibling_die (child))
+ {
+ if (child->tag == DW_TAG_subprogram)
+ {
+ new_prefix = class_name_from_physname (dwarf2_linkage_name
+ (child, cu));
+
+ if (new_prefix != NULL)
+ break;
+ }
+ }
+ }
+
+ if (new_prefix == NULL)
+ {
+ const char *name = dwarf2_name (die, cu);
+ new_prefix = typename_concat (processing_current_prefix,
+ name ? name : "<<anonymous>>");
+ }
+
+ if (back_to != NULL)
+ do_cleanups (back_to);
+
+ return new_prefix;
+}
+
+/* Given a pointer to a die which begins an enumeration, process all
+ the dies that define the members of the enumeration, and create the
+ symbol for the enumeration type.
+
+ NOTE: We reverse the order of the element list. */
+
+static void
+process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct die_info *child_die;
+ struct field *fields;
+ struct attribute *attr;
+ struct symbol *sym;
+ int num_fields;
+ int unsigned_enum = 1;
+
+ num_fields = 0;
+ fields = NULL;
+ if (die->child != NULL)
+ {
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ if (child_die->tag != DW_TAG_enumerator)
+ {
+ process_die (child_die, cu);
+ }
+ else
+ {
+ attr = dwarf2_attr (child_die, DW_AT_name, cu);
+ if (attr)
+ {
+ sym = new_symbol (child_die, die->type, cu);
+ if (SYMBOL_VALUE (sym) < 0)
+ unsigned_enum = 0;
+
+ if ((num_fields % DW_FIELD_ALLOC_CHUNK) == 0)
+ {
+ fields = (struct field *)
+ xrealloc (fields,
+ (num_fields + DW_FIELD_ALLOC_CHUNK)
+ * sizeof (struct field));
+ }
+
+ FIELD_NAME (fields[num_fields]) = DEPRECATED_SYMBOL_NAME (sym);
+ FIELD_TYPE (fields[num_fields]) = NULL;
+ FIELD_BITPOS (fields[num_fields]) = SYMBOL_VALUE (sym);
+ FIELD_BITSIZE (fields[num_fields]) = 0;
+ FIELD_STATIC_KIND (fields[num_fields]) = 0;
+
+ num_fields++;
+ }
+ }
+
+ child_die = sibling_die (child_die);
+ }
+
+ if (num_fields)
+ {
+ TYPE_NFIELDS (die->type) = num_fields;
+ TYPE_FIELDS (die->type) = (struct field *)
+ TYPE_ALLOC (die->type, sizeof (struct field) * num_fields);
+ memcpy (TYPE_FIELDS (die->type), fields,
+ sizeof (struct field) * num_fields);
+ xfree (fields);
+ }
+ if (unsigned_enum)
+ TYPE_FLAGS (die->type) |= TYPE_FLAG_UNSIGNED;
+ }
+
+ new_symbol (die, die->type, cu);
+}
+
+/* Extract all information from a DW_TAG_array_type DIE and put it in
+ the DIE's type field. For now, this only handles one dimensional
+ arrays. */
+
+static void
+read_array_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct die_info *child_die;
+ struct type *type = NULL;
+ struct type *element_type, *range_type, *index_type;
+ struct type **range_types = NULL;
+ struct attribute *attr;
+ int ndim = 0;
+ struct cleanup *back_to;
+
+ /* Return if we've already decoded this type. */
+ if (die->type)
+ {
+ return;
+ }
+
+ element_type = die_type (die, cu);
+
+ /* Irix 6.2 native cc creates array types without children for
+ arrays with unspecified length. */
+ if (die->child == NULL)
+ {
+ index_type = dwarf2_fundamental_type (objfile, FT_INTEGER, cu);
+ range_type = create_range_type (NULL, index_type, 0, -1);
+ die->type = create_array_type (NULL, element_type, range_type);
+ return;
+ }
+
+ back_to = make_cleanup (null_cleanup, NULL);
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ if (child_die->tag == DW_TAG_subrange_type)
+ {
+ read_subrange_type (child_die, cu);
+
+ if (child_die->type != NULL)
+ {
+ /* The range type was succesfully read. Save it for
+ the array type creation. */
+ if ((ndim % DW_FIELD_ALLOC_CHUNK) == 0)
+ {
+ range_types = (struct type **)
+ xrealloc (range_types, (ndim + DW_FIELD_ALLOC_CHUNK)
+ * sizeof (struct type *));
+ if (ndim == 0)
+ make_cleanup (free_current_contents, &range_types);
+ }
+ range_types[ndim++] = child_die->type;
+ }
+ }
+ child_die = sibling_die (child_die);
+ }
+
+ /* Dwarf2 dimensions are output from left to right, create the
+ necessary array types in backwards order. */
+ type = element_type;
+ while (ndim-- > 0)
+ type = create_array_type (NULL, type, range_types[ndim]);
+
+ /* Understand Dwarf2 support for vector types (like they occur on
+ the PowerPC w/ AltiVec). Gcc just adds another attribute to the
+ array type. This is not part of the Dwarf2/3 standard yet, but a
+ custom vendor extension. The main difference between a regular
+ array and the vector variant is that vectors are passed by value
+ to functions. */
+ attr = dwarf2_attr (die, DW_AT_GNU_vector, cu);
+ if (attr)
+ TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
+
+ do_cleanups (back_to);
+
+ /* Install the type in the die. */
+ die->type = type;
+}
+
+/* First cut: install each common block member as a global variable. */
+
+static void
+read_common_block (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct die_info *child_die;
+ struct attribute *attr;
+ struct symbol *sym;
+ CORE_ADDR base = (CORE_ADDR) 0;
+
+ attr = dwarf2_attr (die, DW_AT_location, cu);
+ if (attr)
+ {
+ /* Support the .debug_loc offsets */
+ if (attr_form_is_block (attr))
+ {
+ base = decode_locdesc (DW_BLOCK (attr), cu);
+ }
+ else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
+ {
+ dwarf2_complex_location_expr_complaint ();
+ }
+ else
+ {
+ dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
+ "common block member");
+ }
+ }
+ if (die->child != NULL)
+ {
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ sym = new_symbol (child_die, NULL, cu);
+ attr = dwarf2_attr (child_die, DW_AT_data_member_location, cu);
+ if (attr)
+ {
+ SYMBOL_VALUE_ADDRESS (sym) =
+ base + decode_locdesc (DW_BLOCK (attr), cu);
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ child_die = sibling_die (child_die);
+ }
+ }
+}
+
+/* Read a C++ namespace. */
+
+static void
+read_namespace (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ const char *previous_prefix = processing_current_prefix;
+ const char *name;
+ int is_anonymous;
+ struct die_info *current_die;
+
+ name = namespace_name (die, &is_anonymous, cu);
+
+ /* Now build the name of the current namespace. */
+
+ if (previous_prefix[0] == '\0')
+ {
+ processing_current_prefix = name;
+ }
+ else
+ {
+ /* We need temp_name around because processing_current_prefix
+ is a const char *. */
+ char *temp_name = alloca (strlen (previous_prefix)
+ + 2 + strlen(name) + 1);
+ strcpy (temp_name, previous_prefix);
+ strcat (temp_name, "::");
+ strcat (temp_name, name);
+
+ processing_current_prefix = temp_name;
+ }
+
+ /* Add a symbol associated to this if we haven't seen the namespace
+ before. Also, add a using directive if it's an anonymous
+ namespace. */
+
+ if (dwarf2_extension (die, cu) == NULL)
+ {
+ struct type *type;
+
+ /* FIXME: carlton/2003-06-27: Once GDB is more const-correct,
+ this cast will hopefully become unnecessary. */
+ type = init_type (TYPE_CODE_NAMESPACE, 0, 0,
+ (char *) processing_current_prefix,
+ objfile);
+ TYPE_TAG_NAME (type) = TYPE_NAME (type);
+
+ new_symbol (die, type, cu);
+ die->type = type;
+
+ if (is_anonymous)
+ cp_add_using_directive (processing_current_prefix,
+ strlen (previous_prefix),
+ strlen (processing_current_prefix));
+ }
+
+ if (die->child != NULL)
+ {
+ struct die_info *child_die = die->child;
+
+ while (child_die && child_die->tag)
+ {
+ process_die (child_die, cu);
+ child_die = sibling_die (child_die);
+ }
+ }
+
+ processing_current_prefix = previous_prefix;
+}
+
+/* Return the name of the namespace represented by DIE. Set
+ *IS_ANONYMOUS to tell whether or not the namespace is an anonymous
+ namespace. */
+
+static const char *
+namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *cu)
+{
+ struct die_info *current_die;
+ const char *name = NULL;
+
+ /* Loop through the extensions until we find a name. */
+
+ for (current_die = die;
+ current_die != NULL;
+ current_die = dwarf2_extension (die, cu))
+ {
+ name = dwarf2_name (current_die, cu);
+ if (name != NULL)
+ break;
+ }
+
+ /* Is it an anonymous namespace? */
+
+ *is_anonymous = (name == NULL);
+ if (*is_anonymous)
+ name = "(anonymous namespace)";
+
+ return name;
+}
+
+/* Extract all information from a DW_TAG_pointer_type DIE and add to
+ the user defined type vector. */
+
+static void
+read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct comp_unit_head *cu_header = &cu->header;
+ struct type *type;
+ struct attribute *attr_byte_size;
+ struct attribute *attr_address_class;
+ int byte_size, addr_class;
+
+ if (die->type)
+ {
+ return;
+ }
+
+ type = lookup_pointer_type (die_type (die, cu));
+
+ attr_byte_size = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr_byte_size)
+ byte_size = DW_UNSND (attr_byte_size);
+ else
+ byte_size = cu_header->addr_size;
+
+ attr_address_class = dwarf2_attr (die, DW_AT_address_class, cu);
+ if (attr_address_class)
+ addr_class = DW_UNSND (attr_address_class);
+ else
+ addr_class = DW_ADDR_none;
+
+ /* If the pointer size or address class is different than the
+ default, create a type variant marked as such and set the
+ length accordingly. */
+ if (TYPE_LENGTH (type) != byte_size || addr_class != DW_ADDR_none)
+ {
+ if (ADDRESS_CLASS_TYPE_FLAGS_P ())
+ {
+ int type_flags;
+
+ type_flags = ADDRESS_CLASS_TYPE_FLAGS (byte_size, addr_class);
+ gdb_assert ((type_flags & ~TYPE_FLAG_ADDRESS_CLASS_ALL) == 0);
+ type = make_type_with_address_space (type, type_flags);
+ }
+ else if (TYPE_LENGTH (type) != byte_size)
+ {
+ complaint (&symfile_complaints, "invalid pointer size %d", byte_size);
+ }
+ else {
+ /* Should we also complain about unhandled address classes? */
+ }
+ }
+
+ TYPE_LENGTH (type) = byte_size;
+ die->type = type;
+}
+
+/* Extract all information from a DW_TAG_ptr_to_member_type DIE and add to
+ the user defined type vector. */
+
+static void
+read_tag_ptr_to_member_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct type *type;
+ struct type *to_type;
+ struct type *domain;
+
+ if (die->type)
+ {
+ return;
+ }
+
+ type = alloc_type (objfile);
+ to_type = die_type (die, cu);
+ domain = die_containing_type (die, cu);
+ smash_to_member_type (type, domain, to_type);
+
+ die->type = type;
+}
+
+/* Extract all information from a DW_TAG_reference_type DIE and add to
+ the user defined type vector. */
+
+static void
+read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct comp_unit_head *cu_header = &cu->header;
+ struct type *type;
+ struct attribute *attr;
+
+ if (die->type)
+ {
+ return;
+ }
+
+ type = lookup_reference_type (die_type (die, cu));
+ attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr)
+ {
+ TYPE_LENGTH (type) = DW_UNSND (attr);
+ }
+ else
+ {
+ TYPE_LENGTH (type) = cu_header->addr_size;
+ }
+ die->type = type;
+}
+
+static void
+read_tag_const_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct type *base_type;
+
+ if (die->type)
+ {
+ return;
+ }
+
+ base_type = die_type (die, cu);
+ die->type = make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0);
+}
+
+static void
+read_tag_volatile_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct type *base_type;
+
+ if (die->type)
+ {
+ return;
+ }
+
+ base_type = die_type (die, cu);
+ die->type = make_cv_type (TYPE_CONST (base_type), 1, base_type, 0);
+}
+
+/* Extract all information from a DW_TAG_string_type DIE and add to
+ the user defined type vector. It isn't really a user defined type,
+ but it behaves like one, with other DIE's using an AT_user_def_type
+ attribute to reference it. */
+
+static void
+read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct type *type, *range_type, *index_type, *char_type;
+ struct attribute *attr;
+ unsigned int length;
+
+ if (die->type)
+ {
+ return;
+ }
+
+ attr = dwarf2_attr (die, DW_AT_string_length, cu);
+ if (attr)
+ {
+ length = DW_UNSND (attr);
+ }
+ else
+ {
+ /* check for the DW_AT_byte_size attribute */
+ attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr)
+ {
+ length = DW_UNSND (attr);
+ }
+ else
+ {
+ length = 1;
+ }
+ }
+ index_type = dwarf2_fundamental_type (objfile, FT_INTEGER, cu);
+ range_type = create_range_type (NULL, index_type, 1, length);
+ if (cu->language == language_fortran)
+ {
+ /* Need to create a unique string type for bounds
+ information */
+ type = create_string_type (0, range_type);
+ }
+ else
+ {
+ char_type = dwarf2_fundamental_type (objfile, FT_CHAR, cu);
+ type = create_string_type (char_type, range_type);
+ }
+ die->type = type;
+}
+
+/* Handle DIES due to C code like:
+
+ struct foo
+ {
+ int (*funcp)(int a, long l);
+ int b;
+ };
+
+ ('funcp' generates a DW_TAG_subroutine_type DIE)
+ */
+
+static void
+read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct type *type; /* Type that this function returns */
+ struct type *ftype; /* Function that returns above type */
+ struct attribute *attr;
+
+ /* Decode the type that this subroutine returns */
+ if (die->type)
+ {
+ return;
+ }
+ type = die_type (die, cu);
+ ftype = lookup_function_type (type);
+
+ /* All functions in C++ have prototypes. */
+ attr = dwarf2_attr (die, DW_AT_prototyped, cu);
+ if ((attr && (DW_UNSND (attr) != 0))
+ || cu->language == language_cplus)
+ TYPE_FLAGS (ftype) |= TYPE_FLAG_PROTOTYPED;
+
+ if (die->child != NULL)
+ {
+ struct die_info *child_die;
+ int nparams = 0;
+ int iparams = 0;
+
+ /* Count the number of parameters.
+ FIXME: GDB currently ignores vararg functions, but knows about
+ vararg member functions. */
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ if (child_die->tag == DW_TAG_formal_parameter)
+ nparams++;
+ else if (child_die->tag == DW_TAG_unspecified_parameters)
+ TYPE_FLAGS (ftype) |= TYPE_FLAG_VARARGS;
+ child_die = sibling_die (child_die);
+ }
+
+ /* Allocate storage for parameters and fill them in. */
+ TYPE_NFIELDS (ftype) = nparams;
+ TYPE_FIELDS (ftype) = (struct field *)
+ TYPE_ALLOC (ftype, nparams * sizeof (struct field));
+
+ child_die = die->child;
+ while (child_die && child_die->tag)
+ {
+ if (child_die->tag == DW_TAG_formal_parameter)
+ {
+ /* Dwarf2 has no clean way to discern C++ static and non-static
+ member functions. G++ helps GDB by marking the first
+ parameter for non-static member functions (which is the
+ this pointer) as artificial. We pass this information
+ to dwarf2_add_member_fn via TYPE_FIELD_ARTIFICIAL. */
+ attr = dwarf2_attr (child_die, DW_AT_artificial, cu);
+ if (attr)
+ TYPE_FIELD_ARTIFICIAL (ftype, iparams) = DW_UNSND (attr);
+ else
+ TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0;
+ TYPE_FIELD_TYPE (ftype, iparams) = die_type (child_die, cu);
+ iparams++;
+ }
+ child_die = sibling_die (child_die);
+ }
+ }
+
+ die->type = ftype;
+}
+
+static void
+read_typedef (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct attribute *attr;
+ char *name = NULL;
+
+ if (!die->type)
+ {
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ {
+ name = DW_STRING (attr);
+ }
+ die->type = init_type (TYPE_CODE_TYPEDEF, 0, TYPE_FLAG_TARGET_STUB, name, objfile);
+ TYPE_TARGET_TYPE (die->type) = die_type (die, cu);
+ }
+}
+
+/* Find a representation of a given base type and install
+ it in the TYPE field of the die. */
+
+static void
+read_base_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct type *type;
+ struct attribute *attr;
+ int encoding = 0, size = 0;
+
+ /* If we've already decoded this die, this is a no-op. */
+ if (die->type)
+ {
+ return;
+ }
+
+ attr = dwarf2_attr (die, DW_AT_encoding, cu);
+ if (attr)
+ {
+ encoding = DW_UNSND (attr);
+ }
+ attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr)
+ {
+ size = DW_UNSND (attr);
+ }
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ {
+ enum type_code code = TYPE_CODE_INT;
+ int type_flags = 0;
+
+ switch (encoding)
+ {
+ case DW_ATE_address:
+ /* Turn DW_ATE_address into a void * pointer. */
+ code = TYPE_CODE_PTR;
+ type_flags |= TYPE_FLAG_UNSIGNED;
+ break;
+ case DW_ATE_boolean:
+ code = TYPE_CODE_BOOL;
+ type_flags |= TYPE_FLAG_UNSIGNED;
+ break;
+ case DW_ATE_complex_float:
+ code = TYPE_CODE_COMPLEX;
+ break;
+ case DW_ATE_float:
+ code = TYPE_CODE_FLT;
+ break;
+ case DW_ATE_signed:
+ case DW_ATE_signed_char:
+ break;
+ case DW_ATE_unsigned:
+ case DW_ATE_unsigned_char:
+ type_flags |= TYPE_FLAG_UNSIGNED;
+ break;
+ default:
+ complaint (&symfile_complaints, "unsupported DW_AT_encoding: '%s'",
+ dwarf_type_encoding_name (encoding));
+ break;
+ }
+ type = init_type (code, size, type_flags, DW_STRING (attr), objfile);
+ if (encoding == DW_ATE_address)
+ TYPE_TARGET_TYPE (type) = dwarf2_fundamental_type (objfile, FT_VOID,
+ cu);
+ else if (encoding == DW_ATE_complex_float)
+ {
+ if (size == 32)
+ TYPE_TARGET_TYPE (type)
+ = dwarf2_fundamental_type (objfile, FT_EXT_PREC_FLOAT, cu);
+ else if (size == 16)
+ TYPE_TARGET_TYPE (type)
+ = dwarf2_fundamental_type (objfile, FT_DBL_PREC_FLOAT, cu);
+ else if (size == 8)
+ TYPE_TARGET_TYPE (type)
+ = dwarf2_fundamental_type (objfile, FT_FLOAT, cu);
+ }
+ }
+ else
+ {
+ type = dwarf_base_type (encoding, size, cu);
+ }
+ die->type = type;
+}
+
+/* Read the given DW_AT_subrange DIE. */
+
+static void
+read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct type *base_type;
+ struct type *range_type;
+ struct attribute *attr;
+ int low = 0;
+ int high = -1;
+
+ /* If we have already decoded this die, then nothing more to do. */
+ if (die->type)
+ return;
+
+ base_type = die_type (die, cu);
+ if (base_type == NULL)
+ {
+ complaint (&symfile_complaints,
+ "DW_AT_type missing from DW_TAG_subrange_type");
+ return;
+ }
+
+ if (TYPE_CODE (base_type) == TYPE_CODE_VOID)
+ base_type = alloc_type (NULL);
+
+ if (cu->language == language_fortran)
+ {
+ /* FORTRAN implies a lower bound of 1, if not given. */
+ low = 1;
+ }
+
+ attr = dwarf2_attr (die, DW_AT_lower_bound, cu);
+ if (attr)
+ low = dwarf2_get_attr_constant_value (attr, 0);
+
+ attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
+ if (attr)
+ {
+ if (attr->form == DW_FORM_block1)
+ {
+ /* GCC encodes arrays with unspecified or dynamic length
+ with a DW_FORM_block1 attribute.
+ FIXME: GDB does not yet know how to handle dynamic
+ arrays properly, treat them as arrays with unspecified
+ length for now.
+
+ FIXME: jimb/2003-09-22: GDB does not really know
+ how to handle arrays of unspecified length
+ either; we just represent them as zero-length
+ arrays. Choose an appropriate upper bound given
+ the lower bound we've computed above. */
+ high = low - 1;
+ }
+ else
+ high = dwarf2_get_attr_constant_value (attr, 1);
+ }
+
+ range_type = create_range_type (NULL, base_type, low, high);
+
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ TYPE_NAME (range_type) = DW_STRING (attr);
+
+ attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (attr)
+ TYPE_LENGTH (range_type) = DW_UNSND (attr);
+
+ die->type = range_type;
+}
+
+
+/* Read a whole compilation unit into a linked list of dies. */
+
+static struct die_info *
+read_comp_unit (char *info_ptr, bfd *abfd, struct dwarf2_cu *cu)
+{
+ /* Reset die reference table; we are
+ building new ones now. */
+ dwarf2_empty_hash_tables ();
+
+ return read_die_and_children (info_ptr, abfd, cu, &info_ptr, NULL);
+}
+
+/* Read a single die and all its descendents. Set the die's sibling
+ field to NULL; set other fields in the die correctly, and set all
+ of the descendents' fields correctly. Set *NEW_INFO_PTR to the
+ location of the info_ptr after reading all of those dies. PARENT
+ is the parent of the die in question. */
+
+static struct die_info *
+read_die_and_children (char *info_ptr, bfd *abfd,
+ struct dwarf2_cu *cu,
+ char **new_info_ptr,
+ struct die_info *parent)
+{
+ struct die_info *die;
+ char *cur_ptr;
+ int has_children;
+
+ cur_ptr = read_full_die (&die, abfd, info_ptr, cu, &has_children);
+ store_in_ref_table (die->offset, die);
+
+ if (has_children)
+ {
+ die->child = read_die_and_siblings (cur_ptr, abfd, cu,
+ new_info_ptr, die);
+ }
+ else
+ {
+ die->child = NULL;
+ *new_info_ptr = cur_ptr;
+ }
+
+ die->sibling = NULL;
+ die->parent = parent;
+ return die;
+}
+
+/* Read a die, all of its descendents, and all of its siblings; set
+ all of the fields of all of the dies correctly. Arguments are as
+ in read_die_and_children. */
+
+static struct die_info *
+read_die_and_siblings (char *info_ptr, bfd *abfd,
+ struct dwarf2_cu *cu,
+ char **new_info_ptr,
+ struct die_info *parent)
+{
+ struct die_info *first_die, *last_sibling;
+ char *cur_ptr;
+
+ cur_ptr = info_ptr;
+ first_die = last_sibling = NULL;
+
+ while (1)
+ {
+ struct die_info *die
+ = read_die_and_children (cur_ptr, abfd, cu, &cur_ptr, parent);
+
+ if (!first_die)
+ {
+ first_die = die;
+ }
+ else
+ {
+ last_sibling->sibling = die;
+ }
+
+ if (die->tag == 0)
+ {
+ *new_info_ptr = cur_ptr;
+ return first_die;
+ }
+ else
+ {
+ last_sibling = die;
+ }
+ }
+}
+
+/* Free a linked list of dies. */
+
+static void
+free_die_list (struct die_info *dies)
+{
+ struct die_info *die, *next;
+
+ die = dies;
+ while (die)
+ {
+ if (die->child != NULL)
+ free_die_list (die->child);
+ next = die->sibling;
+ xfree (die->attrs);
+ xfree (die);
+ die = next;
+ }
+}
+
+static void
+do_free_die_list_cleanup (void *dies)
+{
+ free_die_list (dies);
+}
+
+static struct cleanup *
+make_cleanup_free_die_list (struct die_info *dies)
+{
+ return make_cleanup (do_free_die_list_cleanup, dies);
+}
+
+
+/* Read the contents of the section at OFFSET and of size SIZE from the
+ object file specified by OBJFILE into the objfile_obstack and return it. */
+
+char *
+dwarf2_read_section (struct objfile *objfile, asection *sectp)
+{
+ bfd *abfd = objfile->obfd;
+ char *buf, *retbuf;
+ bfd_size_type size = bfd_get_section_size_before_reloc (sectp);
+
+ if (size == 0)
+ return NULL;
+
+ buf = (char *) obstack_alloc (&objfile->objfile_obstack, size);
+ retbuf
+ = (char *) symfile_relocate_debug_section (abfd, sectp, (bfd_byte *) buf);
+ if (retbuf != NULL)
+ return retbuf;
+
+ if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
+ || bfd_bread (buf, size, abfd) != size)
+ error ("Dwarf Error: Can't read DWARF data from '%s'",
+ bfd_get_filename (abfd));
+
+ return buf;
+}
+
+/* In DWARF version 2, the description of the debugging information is
+ stored in a separate .debug_abbrev section. Before we read any
+ dies from a section we read in all abbreviations and install them
+ in a hash table. */
+
+static void
+dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu)
+{
+ struct comp_unit_head *cu_header = &cu->header;
+ char *abbrev_ptr;
+ struct abbrev_info *cur_abbrev;
+ unsigned int abbrev_number, bytes_read, abbrev_name;
+ unsigned int abbrev_form, hash_number;
+
+ /* Initialize dwarf2 abbrevs */
+ memset (cu_header->dwarf2_abbrevs, 0,
+ ABBREV_HASH_SIZE*sizeof (struct abbrev_info *));
+
+ abbrev_ptr = dwarf_abbrev_buffer + cu_header->abbrev_offset;
+ abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+
+ /* loop until we reach an abbrev number of 0 */
+ while (abbrev_number)
+ {
+ cur_abbrev = dwarf_alloc_abbrev ();
+
+ /* read in abbrev header */
+ cur_abbrev->number = abbrev_number;
+ cur_abbrev->tag = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr);
+ abbrev_ptr += 1;
+
+ /* now read in declarations */
+ abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ while (abbrev_name)
+ {
+ if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0)
+ {
+ cur_abbrev->attrs = (struct attr_abbrev *)
+ xrealloc (cur_abbrev->attrs,
+ (cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK)
+ * sizeof (struct attr_abbrev));
+ }
+ cur_abbrev->attrs[cur_abbrev->num_attrs].name = abbrev_name;
+ cur_abbrev->attrs[cur_abbrev->num_attrs++].form = abbrev_form;
+ abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ }
+
+ hash_number = abbrev_number % ABBREV_HASH_SIZE;
+ cur_abbrev->next = cu_header->dwarf2_abbrevs[hash_number];
+ cu_header->dwarf2_abbrevs[hash_number] = cur_abbrev;
+
+ /* Get next abbreviation.
+ Under Irix6 the abbreviations for a compilation unit are not
+ always properly terminated with an abbrev number of 0.
+ Exit loop if we encounter an abbreviation which we have
+ already read (which means we are about to read the abbreviations
+ for the next compile unit) or if the end of the abbreviation
+ table is reached. */
+ if ((unsigned int) (abbrev_ptr - dwarf_abbrev_buffer)
+ >= dwarf_abbrev_size)
+ break;
+ abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ if (dwarf2_lookup_abbrev (abbrev_number, cu) != NULL)
+ break;
+ }
+}
+
+/* Empty the abbrev table for a new compilation unit. */
+
+static void
+dwarf2_empty_abbrev_table (void *ptr_to_abbrevs_table)
+{
+ int i;
+ struct abbrev_info *abbrev, *next;
+ struct abbrev_info **abbrevs;
+
+ abbrevs = (struct abbrev_info **)ptr_to_abbrevs_table;
+
+ for (i = 0; i < ABBREV_HASH_SIZE; ++i)
+ {
+ next = NULL;
+ abbrev = abbrevs[i];
+ while (abbrev)
+ {
+ next = abbrev->next;
+ xfree (abbrev->attrs);
+ xfree (abbrev);
+ abbrev = next;
+ }
+ abbrevs[i] = NULL;
+ }
+}
+
+/* Lookup an abbrev_info structure in the abbrev hash table. */
+
+static struct abbrev_info *
+dwarf2_lookup_abbrev (unsigned int number, struct dwarf2_cu *cu)
+{
+ struct comp_unit_head *cu_header = &cu->header;
+ unsigned int hash_number;
+ struct abbrev_info *abbrev;
+
+ hash_number = number % ABBREV_HASH_SIZE;
+ abbrev = cu_header->dwarf2_abbrevs[hash_number];
+
+ while (abbrev)
+ {
+ if (abbrev->number == number)
+ return abbrev;
+ else
+ abbrev = abbrev->next;
+ }
+ return NULL;
+}
+
+/* Read a minimal amount of information into the minimal die structure. */
+
+static char *
+read_partial_die (struct partial_die_info *part_die, bfd *abfd,
+ char *info_ptr, struct dwarf2_cu *cu)
+{
+ unsigned int abbrev_number, bytes_read, i;
+ struct abbrev_info *abbrev;
+ struct attribute attr;
+ struct attribute spec_attr;
+ int found_spec_attr = 0;
+ int has_low_pc_attr = 0;
+ int has_high_pc_attr = 0;
+
+ *part_die = zeroed_partial_die;
+ abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ if (!abbrev_number)
+ return info_ptr;
+
+ abbrev = dwarf2_lookup_abbrev (abbrev_number, cu);
+ if (!abbrev)
+ {
+ error ("Dwarf Error: Could not find abbrev number %d [in module %s]", abbrev_number,
+ bfd_get_filename (abfd));
+ }
+ part_die->offset = info_ptr - dwarf_info_buffer;
+ part_die->tag = abbrev->tag;
+ part_die->has_children = abbrev->has_children;
+ part_die->abbrev = abbrev_number;
+
+ for (i = 0; i < abbrev->num_attrs; ++i)
+ {
+ info_ptr = read_attribute (&attr, &abbrev->attrs[i], abfd, info_ptr, cu);
+
+ /* Store the data if it is of an attribute we want to keep in a
+ partial symbol table. */
+ switch (attr.name)
+ {
+ case DW_AT_name:
+
+ /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */
+ if (part_die->name == NULL)
+ part_die->name = DW_STRING (&attr);
+ break;
+ case DW_AT_MIPS_linkage_name:
+ part_die->name = DW_STRING (&attr);
+ break;
+ case DW_AT_low_pc:
+ has_low_pc_attr = 1;
+ part_die->lowpc = DW_ADDR (&attr);
+ break;
+ case DW_AT_high_pc:
+ has_high_pc_attr = 1;
+ part_die->highpc = DW_ADDR (&attr);
+ break;
+ case DW_AT_location:
+ /* Support the .debug_loc offsets */
+ if (attr_form_is_block (&attr))
+ {
+ part_die->locdesc = DW_BLOCK (&attr);
+ }
+ else if (attr.form == DW_FORM_data4 || attr.form == DW_FORM_data8)
+ {
+ dwarf2_complex_location_expr_complaint ();
+ }
+ else
+ {
+ dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
+ "partial symbol information");
+ }
+ break;
+ case DW_AT_language:
+ part_die->language = DW_UNSND (&attr);
+ break;
+ case DW_AT_external:
+ part_die->is_external = DW_UNSND (&attr);
+ break;
+ case DW_AT_declaration:
+ part_die->is_declaration = DW_UNSND (&attr);
+ break;
+ case DW_AT_type:
+ part_die->has_type = 1;
+ break;
+ case DW_AT_abstract_origin:
+ case DW_AT_specification:
+ found_spec_attr = 1;
+ spec_attr = attr;
+ break;
+ case DW_AT_sibling:
+ /* Ignore absolute siblings, they might point outside of
+ the current compile unit. */
+ if (attr.form == DW_FORM_ref_addr)
+ complaint (&symfile_complaints, "ignoring absolute DW_AT_sibling");
+ else
+ part_die->sibling =
+ dwarf_info_buffer + dwarf2_get_ref_die_offset (&attr, cu);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* If we found a reference attribute and the die has no name, try
+ to find a name in the referred to die. */
+
+ if (found_spec_attr && part_die->name == NULL)
+ {
+ struct partial_die_info spec_die;
+ char *spec_ptr;
+
+ spec_ptr = dwarf_info_buffer
+ + dwarf2_get_ref_die_offset (&spec_attr, cu);
+ read_partial_die (&spec_die, abfd, spec_ptr, cu);
+ if (spec_die.name)
+ {
+ part_die->name = spec_die.name;
+
+ /* Copy DW_AT_external attribute if it is set. */
+ if (spec_die.is_external)
+ part_die->is_external = spec_die.is_external;
+ }
+ }
+
+ /* When using the GNU linker, .gnu.linkonce. sections are used to
+ eliminate duplicate copies of functions and vtables and such.
+ The linker will arbitrarily choose one and discard the others.
+ The AT_*_pc values for such functions refer to local labels in
+ these sections. If the section from that file was discarded, the
+ labels are not in the output, so the relocs get a value of 0.
+ If this is a discarded function, mark the pc bounds as invalid,
+ so that GDB will ignore it. */
+ if (has_low_pc_attr && has_high_pc_attr
+ && part_die->lowpc < part_die->highpc
+ && (part_die->lowpc != 0
+ || (bfd_get_file_flags (abfd) & HAS_RELOC)))
+ part_die->has_pc_info = 1;
+ return info_ptr;
+}
+
+/* Read the die from the .debug_info section buffer. Set DIEP to
+ point to a newly allocated die with its information, except for its
+ child, sibling, and parent fields. Set HAS_CHILDREN to tell
+ whether the die has children or not. */
+
+static char *
+read_full_die (struct die_info **diep, bfd *abfd, char *info_ptr,
+ struct dwarf2_cu *cu, int *has_children)
+{
+ unsigned int abbrev_number, bytes_read, i, offset;
+ struct abbrev_info *abbrev;
+ struct die_info *die;
+
+ offset = info_ptr - dwarf_info_buffer;
+ abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ if (!abbrev_number)
+ {
+ die = dwarf_alloc_die ();
+ die->tag = 0;
+ die->abbrev = abbrev_number;
+ die->type = NULL;
+ *diep = die;
+ *has_children = 0;
+ return info_ptr;
+ }
+
+ abbrev = dwarf2_lookup_abbrev (abbrev_number, cu);
+ if (!abbrev)
+ {
+ error ("Dwarf Error: could not find abbrev number %d [in module %s]",
+ abbrev_number,
+ bfd_get_filename (abfd));
+ }
+ die = dwarf_alloc_die ();
+ die->offset = offset;
+ die->tag = abbrev->tag;
+ die->abbrev = abbrev_number;
+ die->type = NULL;
+
+ die->num_attrs = abbrev->num_attrs;
+ die->attrs = (struct attribute *)
+ xmalloc (die->num_attrs * sizeof (struct attribute));
+
+ for (i = 0; i < abbrev->num_attrs; ++i)
+ {
+ info_ptr = read_attribute (&die->attrs[i], &abbrev->attrs[i],
+ abfd, info_ptr, cu);
+ }
+
+ *diep = die;
+ *has_children = abbrev->has_children;
+ return info_ptr;
+}
+
+/* Read an attribute value described by an attribute form. */
+
+static char *
+read_attribute_value (struct attribute *attr, unsigned form,
+ bfd *abfd, char *info_ptr,
+ struct dwarf2_cu *cu)
+{
+ struct comp_unit_head *cu_header = &cu->header;
+ unsigned int bytes_read;
+ struct dwarf_block *blk;
+
+ attr->form = form;
+ switch (form)
+ {
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ DW_ADDR (attr) = read_address (abfd, info_ptr, cu, &bytes_read);
+ info_ptr += bytes_read;
+ break;
+ case DW_FORM_block2:
+ blk = dwarf_alloc_block ();
+ blk->size = read_2_bytes (abfd, info_ptr);
+ info_ptr += 2;
+ blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+ info_ptr += blk->size;
+ DW_BLOCK (attr) = blk;
+ break;
+ case DW_FORM_block4:
+ blk = dwarf_alloc_block ();
+ blk->size = read_4_bytes (abfd, info_ptr);
+ info_ptr += 4;
+ blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+ info_ptr += blk->size;
+ DW_BLOCK (attr) = blk;
+ break;
+ case DW_FORM_data2:
+ DW_UNSND (attr) = read_2_bytes (abfd, info_ptr);
+ info_ptr += 2;
+ break;
+ case DW_FORM_data4:
+ DW_UNSND (attr) = read_4_bytes (abfd, info_ptr);
+ info_ptr += 4;
+ break;
+ case DW_FORM_data8:
+ DW_UNSND (attr) = read_8_bytes (abfd, info_ptr);
+ info_ptr += 8;
+ break;
+ case DW_FORM_string:
+ DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ break;
+ case DW_FORM_strp:
+ DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header,
+ &bytes_read);
+ info_ptr += bytes_read;
+ break;
+ case DW_FORM_block:
+ blk = dwarf_alloc_block ();
+ blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+ info_ptr += blk->size;
+ DW_BLOCK (attr) = blk;
+ break;
+ case DW_FORM_block1:
+ blk = dwarf_alloc_block ();
+ blk->size = read_1_byte (abfd, info_ptr);
+ info_ptr += 1;
+ blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+ info_ptr += blk->size;
+ DW_BLOCK (attr) = blk;
+ break;
+ case DW_FORM_data1:
+ DW_UNSND (attr) = read_1_byte (abfd, info_ptr);
+ info_ptr += 1;
+ break;
+ case DW_FORM_flag:
+ DW_UNSND (attr) = read_1_byte (abfd, info_ptr);
+ info_ptr += 1;
+ break;
+ case DW_FORM_sdata:
+ DW_SND (attr) = read_signed_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ break;
+ case DW_FORM_udata:
+ DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ break;
+ case DW_FORM_ref1:
+ DW_UNSND (attr) = read_1_byte (abfd, info_ptr);
+ info_ptr += 1;
+ break;
+ case DW_FORM_ref2:
+ DW_UNSND (attr) = read_2_bytes (abfd, info_ptr);
+ info_ptr += 2;
+ break;
+ case DW_FORM_ref4:
+ DW_UNSND (attr) = read_4_bytes (abfd, info_ptr);
+ info_ptr += 4;
+ break;
+ case DW_FORM_ref8:
+ DW_UNSND (attr) = read_8_bytes (abfd, info_ptr);
+ info_ptr += 8;
+ break;
+ case DW_FORM_ref_udata:
+ DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ break;
+ case DW_FORM_indirect:
+ form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ info_ptr = read_attribute_value (attr, form, abfd, info_ptr, cu);
+ break;
+ default:
+ error ("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]",
+ dwarf_form_name (form),
+ bfd_get_filename (abfd));
+ }
+ return info_ptr;
+}
+
+/* Read an attribute described by an abbreviated attribute. */
+
+static char *
+read_attribute (struct attribute *attr, struct attr_abbrev *abbrev,
+ bfd *abfd, char *info_ptr, struct dwarf2_cu *cu)
+{
+ attr->name = abbrev->name;
+ return read_attribute_value (attr, abbrev->form, abfd, info_ptr, cu);
+}
+
+/* read dwarf information from a buffer */
+
+static unsigned int
+read_1_byte (bfd *abfd, char *buf)
+{
+ return bfd_get_8 (abfd, (bfd_byte *) buf);
+}
+
+static int
+read_1_signed_byte (bfd *abfd, char *buf)
+{
+ return bfd_get_signed_8 (abfd, (bfd_byte *) buf);
+}
+
+static unsigned int
+read_2_bytes (bfd *abfd, char *buf)
+{
+ return bfd_get_16 (abfd, (bfd_byte *) buf);
+}
+
+static int
+read_2_signed_bytes (bfd *abfd, char *buf)
+{
+ return bfd_get_signed_16 (abfd, (bfd_byte *) buf);
+}
+
+static unsigned int
+read_4_bytes (bfd *abfd, char *buf)
+{
+ return bfd_get_32 (abfd, (bfd_byte *) buf);
+}
+
+static int
+read_4_signed_bytes (bfd *abfd, char *buf)
+{
+ return bfd_get_signed_32 (abfd, (bfd_byte *) buf);
+}
+
+static unsigned long
+read_8_bytes (bfd *abfd, char *buf)
+{
+ return bfd_get_64 (abfd, (bfd_byte *) buf);
+}
+
+static CORE_ADDR
+read_address (bfd *abfd, char *buf, struct dwarf2_cu *cu, int *bytes_read)
+{
+ struct comp_unit_head *cu_header = &cu->header;
+ CORE_ADDR retval = 0;
+
+ if (cu_header->signed_addr_p)
+ {
+ switch (cu_header->addr_size)
+ {
+ case 2:
+ retval = bfd_get_signed_16 (abfd, (bfd_byte *) buf);
+ break;
+ case 4:
+ retval = bfd_get_signed_32 (abfd, (bfd_byte *) buf);
+ break;
+ case 8:
+ retval = bfd_get_signed_64 (abfd, (bfd_byte *) buf);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "read_address: bad switch, signed [in module %s]",
+ bfd_get_filename (abfd));
+ }
+ }
+ else
+ {
+ switch (cu_header->addr_size)
+ {
+ case 2:
+ retval = bfd_get_16 (abfd, (bfd_byte *) buf);
+ break;
+ case 4:
+ retval = bfd_get_32 (abfd, (bfd_byte *) buf);
+ break;
+ case 8:
+ retval = bfd_get_64 (abfd, (bfd_byte *) buf);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "read_address: bad switch, unsigned [in module %s]",
+ bfd_get_filename (abfd));
+ }
+ }
+
+ *bytes_read = cu_header->addr_size;
+ return retval;
+}
+
+/* Read the initial length from a section. The (draft) DWARF 3
+ specification allows the initial length to take up either 4 bytes
+ or 12 bytes. If the first 4 bytes are 0xffffffff, then the next 8
+ bytes describe the length and all offsets will be 8 bytes in length
+ instead of 4.
+
+ An older, non-standard 64-bit format is also handled by this
+ function. The older format in question stores the initial length
+ as an 8-byte quantity without an escape value. Lengths greater
+ than 2^32 aren't very common which means that the initial 4 bytes
+ is almost always zero. Since a length value of zero doesn't make
+ sense for the 32-bit format, this initial zero can be considered to
+ be an escape value which indicates the presence of the older 64-bit
+ format. As written, the code can't detect (old format) lengths
+ greater than 4GB. If it becomes necessary to handle lengths somewhat
+ larger than 4GB, we could allow other small values (such as the
+ non-sensical values of 1, 2, and 3) to also be used as escape values
+ indicating the presence of the old format.
+
+ The value returned via bytes_read should be used to increment
+ the relevant pointer after calling read_initial_length().
+
+ As a side effect, this function sets the fields initial_length_size
+ and offset_size in cu_header to the values appropriate for the
+ length field. (The format of the initial length field determines
+ the width of file offsets to be fetched later with fetch_offset().)
+
+ [ Note: read_initial_length() and read_offset() are based on the
+ document entitled "DWARF Debugging Information Format", revision
+ 3, draft 8, dated November 19, 2001. This document was obtained
+ from:
+
+ http://reality.sgiweb.org/davea/dwarf3-draft8-011125.pdf
+
+ This document is only a draft and is subject to change. (So beware.)
+
+ Details regarding the older, non-standard 64-bit format were
+ determined empirically by examining 64-bit ELF files produced
+ by the SGI toolchain on an IRIX 6.5 machine.
+
+ - Kevin, July 16, 2002
+ ] */
+
+static LONGEST
+read_initial_length (bfd *abfd, char *buf, struct comp_unit_head *cu_header,
+ int *bytes_read)
+{
+ LONGEST retval = 0;
+
+ retval = bfd_get_32 (abfd, (bfd_byte *) buf);
+
+ if (retval == 0xffffffff)
+ {
+ retval = bfd_get_64 (abfd, (bfd_byte *) buf + 4);
+ *bytes_read = 12;
+ if (cu_header != NULL)
+ {
+ cu_header->initial_length_size = 12;
+ cu_header->offset_size = 8;
+ }
+ }
+ else if (retval == 0)
+ {
+ /* Handle (non-standard) 64-bit DWARF2 formats such as that used
+ by IRIX. */
+ retval = bfd_get_64 (abfd, (bfd_byte *) buf);
+ *bytes_read = 8;
+ if (cu_header != NULL)
+ {
+ cu_header->initial_length_size = 8;
+ cu_header->offset_size = 8;
+ }
+ }
+ else
+ {
+ *bytes_read = 4;
+ if (cu_header != NULL)
+ {
+ cu_header->initial_length_size = 4;
+ cu_header->offset_size = 4;
+ }
+ }
+
+ return retval;
+}
+
+/* Read an offset from the data stream. The size of the offset is
+ given by cu_header->offset_size. */
+
+static LONGEST
+read_offset (bfd *abfd, char *buf, const struct comp_unit_head *cu_header,
+ int *bytes_read)
+{
+ LONGEST retval = 0;
+
+ switch (cu_header->offset_size)
+ {
+ case 4:
+ retval = bfd_get_32 (abfd, (bfd_byte *) buf);
+ *bytes_read = 4;
+ break;
+ case 8:
+ retval = bfd_get_64 (abfd, (bfd_byte *) buf);
+ *bytes_read = 8;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "read_offset: bad switch [in module %s]",
+ bfd_get_filename (abfd));
+ }
+
+ return retval;
+}
+
+static char *
+read_n_bytes (bfd *abfd, char *buf, unsigned int size)
+{
+ /* If the size of a host char is 8 bits, we can return a pointer
+ to the buffer, otherwise we have to copy the data to a buffer
+ allocated on the temporary obstack. */
+ gdb_assert (HOST_CHAR_BIT == 8);
+ return buf;
+}
+
+static char *
+read_string (bfd *abfd, char *buf, unsigned int *bytes_read_ptr)
+{
+ /* If the size of a host char is 8 bits, we can return a pointer
+ to the string, otherwise we have to copy the string to a buffer
+ allocated on the temporary obstack. */
+ gdb_assert (HOST_CHAR_BIT == 8);
+ if (*buf == '\0')
+ {
+ *bytes_read_ptr = 1;
+ return NULL;
+ }
+ *bytes_read_ptr = strlen (buf) + 1;
+ return buf;
+}
+
+static char *
+read_indirect_string (bfd *abfd, char *buf,
+ const struct comp_unit_head *cu_header,
+ unsigned int *bytes_read_ptr)
+{
+ LONGEST str_offset = read_offset (abfd, buf, cu_header,
+ (int *) bytes_read_ptr);
+
+ if (dwarf_str_buffer == NULL)
+ {
+ error ("DW_FORM_strp used without .debug_str section [in module %s]",
+ bfd_get_filename (abfd));
+ return NULL;
+ }
+ if (str_offset >= dwarf_str_size)
+ {
+ error ("DW_FORM_strp pointing outside of .debug_str section [in module %s]",
+ bfd_get_filename (abfd));
+ return NULL;
+ }
+ gdb_assert (HOST_CHAR_BIT == 8);
+ if (dwarf_str_buffer[str_offset] == '\0')
+ return NULL;
+ return dwarf_str_buffer + str_offset;
+}
+
+static unsigned long
+read_unsigned_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr)
+{
+ unsigned long result;
+ unsigned int num_read;
+ int i, shift;
+ unsigned char byte;
+
+ result = 0;
+ shift = 0;
+ num_read = 0;
+ i = 0;
+ while (1)
+ {
+ byte = bfd_get_8 (abfd, (bfd_byte *) buf);
+ buf++;
+ num_read++;
+ result |= ((unsigned long)(byte & 127) << shift);
+ if ((byte & 128) == 0)
+ {
+ break;
+ }
+ shift += 7;
+ }
+ *bytes_read_ptr = num_read;
+ return result;
+}
+
+static long
+read_signed_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr)
+{
+ long result;
+ int i, shift, size, num_read;
+ unsigned char byte;
+
+ result = 0;
+ shift = 0;
+ size = 32;
+ num_read = 0;
+ i = 0;
+ while (1)
+ {
+ byte = bfd_get_8 (abfd, (bfd_byte *) buf);
+ buf++;
+ num_read++;
+ result |= ((long)(byte & 127) << shift);
+ shift += 7;
+ if ((byte & 128) == 0)
+ {
+ break;
+ }
+ }
+ if ((shift < size) && (byte & 0x40))
+ {
+ result |= -(1 << shift);
+ }
+ *bytes_read_ptr = num_read;
+ return result;
+}
+
+static void
+set_cu_language (unsigned int lang, struct dwarf2_cu *cu)
+{
+ switch (lang)
+ {
+ case DW_LANG_C89:
+ case DW_LANG_C:
+ cu->language = language_c;
+ break;
+ case DW_LANG_C_plus_plus:
+ cu->language = language_cplus;
+ break;
+ case DW_LANG_Fortran77:
+ case DW_LANG_Fortran90:
+ case DW_LANG_Fortran95:
+ cu->language = language_fortran;
+ break;
+ case DW_LANG_Mips_Assembler:
+ cu->language = language_asm;
+ break;
+ case DW_LANG_Java:
+ cu->language = language_java;
+ break;
+ case DW_LANG_Ada83:
+ case DW_LANG_Ada95:
+ case DW_LANG_Cobol74:
+ case DW_LANG_Cobol85:
+ case DW_LANG_Pascal83:
+ case DW_LANG_Modula2:
+ default:
+ cu->language = language_minimal;
+ break;
+ }
+ cu->language_defn = language_def (cu->language);
+}
+
+/* Return the named attribute or NULL if not there. */
+
+static struct attribute *
+dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
+{
+ unsigned int i;
+ struct attribute *spec = NULL;
+
+ for (i = 0; i < die->num_attrs; ++i)
+ {
+ if (die->attrs[i].name == name)
+ {
+ return &die->attrs[i];
+ }
+ if (die->attrs[i].name == DW_AT_specification
+ || die->attrs[i].name == DW_AT_abstract_origin)
+ spec = &die->attrs[i];
+ }
+ if (spec)
+ {
+ struct die_info *ref_die =
+ follow_die_ref (dwarf2_get_ref_die_offset (spec, cu));
+
+ if (ref_die)
+ return dwarf2_attr (ref_die, name, cu);
+ }
+
+ return NULL;
+}
+
+static int
+die_is_declaration (struct die_info *die, struct dwarf2_cu *cu)
+{
+ return (dwarf2_attr (die, DW_AT_declaration, cu)
+ && ! dwarf2_attr (die, DW_AT_specification, cu));
+}
+
+/* Return the die giving the specification for DIE, if there is
+ one. */
+
+static struct die_info *
+die_specification (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *spec_attr = dwarf2_attr (die, DW_AT_specification, cu);
+
+ if (spec_attr == NULL)
+ return NULL;
+ else
+ return follow_die_ref (dwarf2_get_ref_die_offset (spec_attr, cu));
+}
+
+/* Free the line_header structure *LH, and any arrays and strings it
+ refers to. */
+static void
+free_line_header (struct line_header *lh)
+{
+ if (lh->standard_opcode_lengths)
+ xfree (lh->standard_opcode_lengths);
+
+ /* Remember that all the lh->file_names[i].name pointers are
+ pointers into debug_line_buffer, and don't need to be freed. */
+ if (lh->file_names)
+ xfree (lh->file_names);
+
+ /* Similarly for the include directory names. */
+ if (lh->include_dirs)
+ xfree (lh->include_dirs);
+
+ xfree (lh);
+}
+
+
+/* Add an entry to LH's include directory table. */
+static void
+add_include_dir (struct line_header *lh, char *include_dir)
+{
+ /* Grow the array if necessary. */
+ if (lh->include_dirs_size == 0)
+ {
+ lh->include_dirs_size = 1; /* for testing */
+ lh->include_dirs = xmalloc (lh->include_dirs_size
+ * sizeof (*lh->include_dirs));
+ }
+ else if (lh->num_include_dirs >= lh->include_dirs_size)
+ {
+ lh->include_dirs_size *= 2;
+ lh->include_dirs = xrealloc (lh->include_dirs,
+ (lh->include_dirs_size
+ * sizeof (*lh->include_dirs)));
+ }
+
+ lh->include_dirs[lh->num_include_dirs++] = include_dir;
+}
+
+
+/* Add an entry to LH's file name table. */
+static void
+add_file_name (struct line_header *lh,
+ char *name,
+ unsigned int dir_index,
+ unsigned int mod_time,
+ unsigned int length)
+{
+ struct file_entry *fe;
+
+ /* Grow the array if necessary. */
+ if (lh->file_names_size == 0)
+ {
+ lh->file_names_size = 1; /* for testing */
+ lh->file_names = xmalloc (lh->file_names_size
+ * sizeof (*lh->file_names));
+ }
+ else if (lh->num_file_names >= lh->file_names_size)
+ {
+ lh->file_names_size *= 2;
+ lh->file_names = xrealloc (lh->file_names,
+ (lh->file_names_size
+ * sizeof (*lh->file_names)));
+ }
+
+ fe = &lh->file_names[lh->num_file_names++];
+ fe->name = name;
+ fe->dir_index = dir_index;
+ fe->mod_time = mod_time;
+ fe->length = length;
+}
+
+
+/* Read the statement program header starting at OFFSET in
+ dwarf_line_buffer, according to the endianness of ABFD. Return a
+ pointer to a struct line_header, allocated using xmalloc.
+
+ NOTE: the strings in the include directory and file name tables of
+ the returned object point into debug_line_buffer, and must not be
+ freed. */
+static struct line_header *
+dwarf_decode_line_header (unsigned int offset, bfd *abfd,
+ struct dwarf2_cu *cu)
+{
+ struct cleanup *back_to;
+ struct line_header *lh;
+ char *line_ptr;
+ int bytes_read;
+ int i;
+ char *cur_dir, *cur_file;
+
+ if (dwarf_line_buffer == NULL)
+ {
+ complaint (&symfile_complaints, "missing .debug_line section");
+ return 0;
+ }
+
+ /* Make sure that at least there's room for the total_length field. That
+ could be 12 bytes long, but we're just going to fudge that. */
+ if (offset + 4 >= dwarf_line_size)
+ {
+ dwarf2_statement_list_fits_in_line_number_section_complaint ();
+ return 0;
+ }
+
+ lh = xmalloc (sizeof (*lh));
+ memset (lh, 0, sizeof (*lh));
+ back_to = make_cleanup ((make_cleanup_ftype *) free_line_header,
+ (void *) lh);
+
+ line_ptr = dwarf_line_buffer + offset;
+
+ /* read in the header */
+ lh->total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
+ line_ptr += bytes_read;
+ if (line_ptr + lh->total_length > dwarf_line_buffer + dwarf_line_size)
+ {
+ dwarf2_statement_list_fits_in_line_number_section_complaint ();
+ return 0;
+ }
+ lh->statement_program_end = line_ptr + lh->total_length;
+ lh->version = read_2_bytes (abfd, line_ptr);
+ line_ptr += 2;
+ lh->header_length = read_offset (abfd, line_ptr, &cu->header, &bytes_read);
+ line_ptr += bytes_read;
+ lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ lh->default_is_stmt = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ lh->line_base = read_1_signed_byte (abfd, line_ptr);
+ line_ptr += 1;
+ lh->line_range = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ lh->opcode_base = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ lh->standard_opcode_lengths
+ = (unsigned char *) xmalloc (lh->opcode_base * sizeof (unsigned char));
+
+ lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
+ for (i = 1; i < lh->opcode_base; ++i)
+ {
+ lh->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ }
+
+ /* Read directory table */
+ while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
+ {
+ line_ptr += bytes_read;
+ add_include_dir (lh, cur_dir);
+ }
+ line_ptr += bytes_read;
+
+ /* Read file name table */
+ while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
+ {
+ unsigned int dir_index, mod_time, length;
+
+ line_ptr += bytes_read;
+ dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+
+ add_file_name (lh, cur_file, dir_index, mod_time, length);
+ }
+ line_ptr += bytes_read;
+ lh->statement_program_start = line_ptr;
+
+ if (line_ptr > dwarf_line_buffer + dwarf_line_size)
+ complaint (&symfile_complaints,
+ "line number info header doesn't fit in `.debug_line' section");
+
+ discard_cleanups (back_to);
+ return lh;
+}
+
+/* This function exists to work around a bug in certain compilers
+ (particularly GCC 2.95), in which the first line number marker of a
+ function does not show up until after the prologue, right before
+ the second line number marker. This function shifts ADDRESS down
+ to the beginning of the function if necessary, and is called on
+ addresses passed to record_line. */
+
+static CORE_ADDR
+check_cu_functions (CORE_ADDR address, struct dwarf2_cu *cu)
+{
+ struct function_range *fn;
+
+ /* Find the function_range containing address. */
+ if (!cu->first_fn)
+ return address;
+
+ if (!cu->cached_fn)
+ cu->cached_fn = cu->first_fn;
+
+ fn = cu->cached_fn;
+ while (fn)
+ if (fn->lowpc <= address && fn->highpc > address)
+ goto found;
+ else
+ fn = fn->next;
+
+ fn = cu->first_fn;
+ while (fn && fn != cu->cached_fn)
+ if (fn->lowpc <= address && fn->highpc > address)
+ goto found;
+ else
+ fn = fn->next;
+
+ return address;
+
+ found:
+ if (fn->seen_line)
+ return address;
+ if (address != fn->lowpc)
+ complaint (&symfile_complaints,
+ "misplaced first line number at 0x%lx for '%s'",
+ (unsigned long) address, fn->name);
+ fn->seen_line = 1;
+ return fn->lowpc;
+}
+
+/* Decode the line number information for the compilation unit whose
+ line number info is at OFFSET in the .debug_line section.
+ The compilation directory of the file is passed in COMP_DIR. */
+
+static void
+dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
+ struct dwarf2_cu *cu)
+{
+ char *line_ptr;
+ char *line_end;
+ unsigned int bytes_read;
+ unsigned char op_code, extended_op, adj_opcode;
+ CORE_ADDR baseaddr;
+ struct objfile *objfile = cu->objfile;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ line_ptr = lh->statement_program_start;
+ line_end = lh->statement_program_end;
+
+ /* Read the statement sequences until there's nothing left. */
+ while (line_ptr < line_end)
+ {
+ /* state machine registers */
+ CORE_ADDR address = 0;
+ unsigned int file = 1;
+ unsigned int line = 1;
+ unsigned int column = 0;
+ int is_stmt = lh->default_is_stmt;
+ int basic_block = 0;
+ int end_sequence = 0;
+
+ /* Start a subfile for the current file of the state machine. */
+ if (lh->num_file_names >= file)
+ {
+ /* lh->include_dirs and lh->file_names are 0-based, but the
+ directory and file name numbers in the statement program
+ are 1-based. */
+ struct file_entry *fe = &lh->file_names[file - 1];
+ char *dir;
+ if (fe->dir_index)
+ dir = lh->include_dirs[fe->dir_index - 1];
+ else
+ dir = comp_dir;
+ dwarf2_start_subfile (fe->name, dir);
+ }
+
+ /* Decode the table. */
+ while (!end_sequence)
+ {
+ op_code = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+
+ if (op_code >= lh->opcode_base)
+ { /* Special operand. */
+ adj_opcode = op_code - lh->opcode_base;
+ address += (adj_opcode / lh->line_range)
+ * lh->minimum_instruction_length;
+ line += lh->line_base + (adj_opcode % lh->line_range);
+ /* append row to matrix using current values */
+ record_line (current_subfile, line,
+ check_cu_functions (address, cu));
+ basic_block = 1;
+ }
+ else switch (op_code)
+ {
+ case DW_LNS_extended_op:
+ line_ptr += 1; /* ignore length */
+ extended_op = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ switch (extended_op)
+ {
+ case DW_LNE_end_sequence:
+ end_sequence = 1;
+ record_line (current_subfile, 0, address);
+ break;
+ case DW_LNE_set_address:
+ address = read_address (abfd, line_ptr, cu, &bytes_read);
+ line_ptr += bytes_read;
+ address += baseaddr;
+ break;
+ case DW_LNE_define_file:
+ {
+ char *cur_file;
+ unsigned int dir_index, mod_time, length;
+
+ cur_file = read_string (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ dir_index =
+ read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ mod_time =
+ read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ length =
+ read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ add_file_name (lh, cur_file, dir_index, mod_time, length);
+ }
+ break;
+ default:
+ complaint (&symfile_complaints,
+ "mangled .debug_line section");
+ return;
+ }
+ break;
+ case DW_LNS_copy:
+ record_line (current_subfile, line,
+ check_cu_functions (address, cu));
+ basic_block = 0;
+ break;
+ case DW_LNS_advance_pc:
+ address += lh->minimum_instruction_length
+ * read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ break;
+ case DW_LNS_advance_line:
+ line += read_signed_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ break;
+ case DW_LNS_set_file:
+ {
+ /* lh->include_dirs and lh->file_names are 0-based,
+ but the directory and file name numbers in the
+ statement program are 1-based. */
+ struct file_entry *fe;
+ char *dir;
+ file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ fe = &lh->file_names[file - 1];
+ if (fe->dir_index)
+ dir = lh->include_dirs[fe->dir_index - 1];
+ else
+ dir = comp_dir;
+ dwarf2_start_subfile (fe->name, dir);
+ }
+ break;
+ case DW_LNS_set_column:
+ column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ break;
+ case DW_LNS_negate_stmt:
+ is_stmt = (!is_stmt);
+ break;
+ case DW_LNS_set_basic_block:
+ basic_block = 1;
+ break;
+ /* Add to the address register of the state machine the
+ address increment value corresponding to special opcode
+ 255. Ie, this value is scaled by the minimum instruction
+ length since special opcode 255 would have scaled the
+ the increment. */
+ case DW_LNS_const_add_pc:
+ address += (lh->minimum_instruction_length
+ * ((255 - lh->opcode_base) / lh->line_range));
+ break;
+ case DW_LNS_fixed_advance_pc:
+ address += read_2_bytes (abfd, line_ptr);
+ line_ptr += 2;
+ break;
+ default:
+ { /* Unknown standard opcode, ignore it. */
+ int i;
+ for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++)
+ {
+ (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Start a subfile for DWARF. FILENAME is the name of the file and
+ DIRNAME the name of the source directory which contains FILENAME
+ or NULL if not known.
+ This routine tries to keep line numbers from identical absolute and
+ relative file names in a common subfile.
+
+ Using the `list' example from the GDB testsuite, which resides in
+ /srcdir and compiling it with Irix6.2 cc in /compdir using a filename
+ of /srcdir/list0.c yields the following debugging information for list0.c:
+
+ DW_AT_name: /srcdir/list0.c
+ DW_AT_comp_dir: /compdir
+ files.files[0].name: list0.h
+ files.files[0].dir: /srcdir
+ files.files[1].name: list0.c
+ files.files[1].dir: /srcdir
+
+ The line number information for list0.c has to end up in a single
+ subfile, so that `break /srcdir/list0.c:1' works as expected. */
+
+static void
+dwarf2_start_subfile (char *filename, char *dirname)
+{
+ /* If the filename isn't absolute, try to match an existing subfile
+ with the full pathname. */
+
+ if (!IS_ABSOLUTE_PATH (filename) && dirname != NULL)
+ {
+ struct subfile *subfile;
+ char *fullname = concat (dirname, "/", filename, NULL);
+
+ for (subfile = subfiles; subfile; subfile = subfile->next)
+ {
+ if (FILENAME_CMP (subfile->name, fullname) == 0)
+ {
+ current_subfile = subfile;
+ xfree (fullname);
+ return;
+ }
+ }
+ xfree (fullname);
+ }
+ start_subfile (filename, dirname);
+}
+
+static void
+var_decode_location (struct attribute *attr, struct symbol *sym,
+ struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct comp_unit_head *cu_header = &cu->header;
+
+ /* NOTE drow/2003-01-30: There used to be a comment and some special
+ code here to turn a symbol with DW_AT_external and a
+ SYMBOL_VALUE_ADDRESS of 0 into a LOC_UNRESOLVED symbol. This was
+ necessary for platforms (maybe Alpha, certainly PowerPC GNU/Linux
+ with some versions of binutils) where shared libraries could have
+ relocations against symbols in their debug information - the
+ minimal symbol would have the right address, but the debug info
+ would not. It's no longer necessary, because we will explicitly
+ apply relocations when we read in the debug information now. */
+
+ /* A DW_AT_location attribute with no contents indicates that a
+ variable has been optimized away. */
+ if (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0)
+ {
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+ return;
+ }
+
+ /* Handle one degenerate form of location expression specially, to
+ preserve GDB's previous behavior when section offsets are
+ specified. If this is just a DW_OP_addr then mark this symbol
+ as LOC_STATIC. */
+
+ if (attr_form_is_block (attr)
+ && DW_BLOCK (attr)->size == 1 + cu_header->addr_size
+ && DW_BLOCK (attr)->data[0] == DW_OP_addr)
+ {
+ int dummy;
+
+ SYMBOL_VALUE_ADDRESS (sym) =
+ read_address (objfile->obfd, DW_BLOCK (attr)->data + 1, cu, &dummy);
+ fixup_symbol_section (sym, objfile);
+ SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets,
+ SYMBOL_SECTION (sym));
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ return;
+ }
+
+ /* NOTE drow/2002-01-30: It might be worthwhile to have a static
+ expression evaluator, and use LOC_COMPUTED only when necessary
+ (i.e. when the value of a register or memory location is
+ referenced, or a thread-local block, etc.). Then again, it might
+ not be worthwhile. I'm assuming that it isn't unless performance
+ or memory numbers show me otherwise. */
+
+ dwarf2_symbol_mark_computed (attr, sym, cu);
+ SYMBOL_CLASS (sym) = LOC_COMPUTED;
+}
+
+/* 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.
+ If TYPE is NULL, determine symbol type from the die, otherwise
+ used the passed type. */
+
+static struct symbol *
+new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct symbol *sym = NULL;
+ char *name;
+ struct attribute *attr = NULL;
+ struct attribute *attr2 = NULL;
+ CORE_ADDR baseaddr;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ if (die->tag != DW_TAG_namespace)
+ name = dwarf2_linkage_name (die, cu);
+ else
+ name = TYPE_NAME (type);
+
+ if (name)
+ {
+ sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ OBJSTAT (objfile, n_syms++);
+ memset (sym, 0, sizeof (struct symbol));
+
+ /* Cache this symbol's name and the name's demangled form (if any). */
+ SYMBOL_LANGUAGE (sym) = cu->language;
+ SYMBOL_SET_NAMES (sym, name, strlen (name), objfile);
+
+ /* Default assumptions.
+ Use the passed type or decode it from the die. */
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ if (type != NULL)
+ SYMBOL_TYPE (sym) = type;
+ else
+ SYMBOL_TYPE (sym) = die_type (die, cu);
+ attr = dwarf2_attr (die, DW_AT_decl_line, cu);
+ if (attr)
+ {
+ SYMBOL_LINE (sym) = DW_UNSND (attr);
+ }
+ switch (die->tag)
+ {
+ case DW_TAG_label:
+ attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+ if (attr)
+ {
+ SYMBOL_VALUE_ADDRESS (sym) = DW_ADDR (attr) + baseaddr;
+ }
+ SYMBOL_CLASS (sym) = LOC_LABEL;
+ break;
+ case DW_TAG_subprogram:
+ /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
+ finish_block. */
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ attr2 = dwarf2_attr (die, DW_AT_external, cu);
+ if (attr2 && (DW_UNSND (attr2) != 0))
+ {
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ add_symbol_to_list (sym, cu->list_in_scope);
+ }
+ break;
+ case DW_TAG_variable:
+ /* Compilation with minimal debug info may result in variables
+ with missing type entries. Change the misleading `void' type
+ to something sensible. */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_VOID)
+ SYMBOL_TYPE (sym) = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / HOST_CHAR_BIT, 0,
+ "<variable, no debug info>",
+ objfile);
+ attr = dwarf2_attr (die, DW_AT_const_value, cu);
+ if (attr)
+ {
+ dwarf2_const_value (attr, sym, cu);
+ attr2 = dwarf2_attr (die, DW_AT_external, cu);
+ if (attr2 && (DW_UNSND (attr2) != 0))
+ add_symbol_to_list (sym, &global_symbols);
+ else
+ add_symbol_to_list (sym, cu->list_in_scope);
+ break;
+ }
+ attr = dwarf2_attr (die, DW_AT_location, cu);
+ if (attr)
+ {
+ var_decode_location (attr, sym, cu);
+ attr2 = dwarf2_attr (die, DW_AT_external, cu);
+ if (attr2 && (DW_UNSND (attr2) != 0))
+ add_symbol_to_list (sym, &global_symbols);
+ else
+ add_symbol_to_list (sym, cu->list_in_scope);
+ }
+ else
+ {
+ /* We do not know the address of this symbol.
+ If it is an external symbol and we have type information
+ for it, enter the symbol as a LOC_UNRESOLVED symbol.
+ The address of the variable will then be determined from
+ the minimal symbol table whenever the variable is
+ referenced. */
+ attr2 = dwarf2_attr (die, DW_AT_external, cu);
+ if (attr2 && (DW_UNSND (attr2) != 0)
+ && dwarf2_attr (die, DW_AT_type, cu) != NULL)
+ {
+ SYMBOL_CLASS (sym) = LOC_UNRESOLVED;
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ }
+ break;
+ case DW_TAG_formal_parameter:
+ attr = dwarf2_attr (die, DW_AT_location, cu);
+ if (attr)
+ {
+ var_decode_location (attr, sym, cu);
+ /* FIXME drow/2003-07-31: Is LOC_COMPUTED_ARG necessary? */
+ if (SYMBOL_CLASS (sym) == LOC_COMPUTED)
+ SYMBOL_CLASS (sym) = LOC_COMPUTED_ARG;
+ }
+ attr = dwarf2_attr (die, DW_AT_const_value, cu);
+ if (attr)
+ {
+ dwarf2_const_value (attr, sym, cu);
+ }
+ add_symbol_to_list (sym, cu->list_in_scope);
+ break;
+ case DW_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 DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN;
+
+ /* Make sure that the symbol includes appropriate enclosing
+ classes/namespaces in its name. These are calculated in
+ read_structure_type, and the correct name is saved in
+ the type. */
+
+ if (cu->language == language_cplus)
+ {
+ struct type *type = SYMBOL_TYPE (sym);
+
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ /* FIXME: carlton/2003-11-10: Should this use
+ SYMBOL_SET_NAMES instead? (The same problem also
+ arises a further down in the function.) */
+ SYMBOL_LINKAGE_NAME (sym)
+ = obsavestring (TYPE_TAG_NAME (type),
+ strlen (TYPE_TAG_NAME (type)),
+ &objfile->objfile_obstack);
+ }
+ }
+
+ {
+ /* NOTE: carlton/2003-11-10: C++ class symbols shouldn't
+ really ever be static objects: otherwise, if you try
+ to, say, break of a class's method and you're in a file
+ which doesn't mention that class, it won't work unless
+ the check for all static symbols in lookup_symbol_aux
+ saves you. See the OtherFileClass tests in
+ gdb.c++/namespace.exp. */
+
+ struct pending **list_to_add;
+
+ list_to_add = (cu->list_in_scope == &file_symbols
+ && cu->language == language_cplus
+ ? &global_symbols : cu->list_in_scope);
+
+ add_symbol_to_list (sym, list_to_add);
+
+ /* The semantics of C++ state that "struct foo { ... }" also
+ defines a typedef for "foo". Synthesize a typedef symbol so
+ that "ptype foo" works as expected. */
+ if (cu->language == language_cplus)
+ {
+ struct symbol *typedef_sym = (struct symbol *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ *typedef_sym = *sym;
+ SYMBOL_DOMAIN (typedef_sym) = VAR_DOMAIN;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym)) =
+ obsavestring (SYMBOL_NATURAL_NAME (sym),
+ strlen (SYMBOL_NATURAL_NAME (sym)),
+ &objfile->objfile_obstack);
+ add_symbol_to_list (typedef_sym, list_to_add);
+ }
+ }
+ break;
+ case DW_TAG_typedef:
+ if (processing_has_namespace_info
+ && processing_current_prefix[0] != '\0')
+ {
+ SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->objfile_obstack,
+ processing_current_prefix,
+ "::",
+ name);
+ }
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ add_symbol_to_list (sym, cu->list_in_scope);
+ break;
+ case DW_TAG_base_type:
+ case DW_TAG_subrange_type:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ add_symbol_to_list (sym, cu->list_in_scope);
+ break;
+ case DW_TAG_enumerator:
+ if (processing_has_namespace_info
+ && processing_current_prefix[0] != '\0')
+ {
+ SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->objfile_obstack,
+ processing_current_prefix,
+ "::",
+ name);
+ }
+ attr = dwarf2_attr (die, DW_AT_const_value, cu);
+ if (attr)
+ {
+ dwarf2_const_value (attr, sym, cu);
+ }
+ {
+ /* NOTE: carlton/2003-11-10: See comment above in the
+ DW_TAG_class_type, etc. block. */
+
+ struct pending **list_to_add;
+
+ list_to_add = (cu->list_in_scope == &file_symbols
+ && cu->language == language_cplus
+ ? &global_symbols : cu->list_in_scope);
+
+ add_symbol_to_list (sym, list_to_add);
+ }
+ break;
+ case DW_TAG_namespace:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ add_symbol_to_list (sym, &global_symbols);
+ 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. */
+ complaint (&symfile_complaints, "unsupported tag: '%s'",
+ dwarf_tag_name (die->tag));
+ break;
+ }
+ }
+ return (sym);
+}
+
+/* Copy constant value from an attribute to a symbol. */
+
+static void
+dwarf2_const_value (struct attribute *attr, struct symbol *sym,
+ struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct comp_unit_head *cu_header = &cu->header;
+ struct dwarf_block *blk;
+
+ switch (attr->form)
+ {
+ case DW_FORM_addr:
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != cu_header->addr_size)
+ dwarf2_const_value_length_mismatch_complaint (DEPRECATED_SYMBOL_NAME (sym),
+ cu_header->addr_size,
+ TYPE_LENGTH (SYMBOL_TYPE
+ (sym)));
+ SYMBOL_VALUE_BYTES (sym) = (char *)
+ obstack_alloc (&objfile->objfile_obstack, cu_header->addr_size);
+ /* NOTE: cagney/2003-05-09: In-lined store_address call with
+ it's body - store_unsigned_integer. */
+ store_unsigned_integer (SYMBOL_VALUE_BYTES (sym), cu_header->addr_size,
+ DW_ADDR (attr));
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ break;
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_block:
+ blk = DW_BLOCK (attr);
+ if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != blk->size)
+ dwarf2_const_value_length_mismatch_complaint (DEPRECATED_SYMBOL_NAME (sym),
+ blk->size,
+ TYPE_LENGTH (SYMBOL_TYPE
+ (sym)));
+ SYMBOL_VALUE_BYTES (sym) = (char *)
+ obstack_alloc (&objfile->objfile_obstack, blk->size);
+ memcpy (SYMBOL_VALUE_BYTES (sym), blk->data, blk->size);
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ break;
+
+ /* The DW_AT_const_value attributes are supposed to carry the
+ symbol's value "represented as it would be on the target
+ architecture." By the time we get here, it's already been
+ converted to host endianness, so we just need to sign- or
+ zero-extend it as appropriate. */
+ case DW_FORM_data1:
+ dwarf2_const_value_data (attr, sym, 8);
+ break;
+ case DW_FORM_data2:
+ dwarf2_const_value_data (attr, sym, 16);
+ break;
+ case DW_FORM_data4:
+ dwarf2_const_value_data (attr, sym, 32);
+ break;
+ case DW_FORM_data8:
+ dwarf2_const_value_data (attr, sym, 64);
+ break;
+
+ case DW_FORM_sdata:
+ SYMBOL_VALUE (sym) = DW_SND (attr);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ break;
+
+ case DW_FORM_udata:
+ SYMBOL_VALUE (sym) = DW_UNSND (attr);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ break;
+
+ default:
+ complaint (&symfile_complaints,
+ "unsupported const value attribute form: '%s'",
+ dwarf_form_name (attr->form));
+ SYMBOL_VALUE (sym) = 0;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ break;
+ }
+}
+
+
+/* Given an attr with a DW_FORM_dataN value in host byte order, sign-
+ or zero-extend it as appropriate for the symbol's type. */
+static void
+dwarf2_const_value_data (struct attribute *attr,
+ struct symbol *sym,
+ int bits)
+{
+ LONGEST l = DW_UNSND (attr);
+
+ if (bits < sizeof (l) * 8)
+ {
+ if (TYPE_UNSIGNED (SYMBOL_TYPE (sym)))
+ l &= ((LONGEST) 1 << bits) - 1;
+ else
+ l = (l << (sizeof (l) * 8 - bits)) >> (sizeof (l) * 8 - bits);
+ }
+
+ SYMBOL_VALUE (sym) = l;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+}
+
+
+/* Return the type of the die in question using its DW_AT_type attribute. */
+
+static struct type *
+die_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct type *type;
+ struct attribute *type_attr;
+ struct die_info *type_die;
+ unsigned int ref;
+
+ type_attr = dwarf2_attr (die, DW_AT_type, cu);
+ if (!type_attr)
+ {
+ /* A missing DW_AT_type represents a void type. */
+ return dwarf2_fundamental_type (cu->objfile, FT_VOID, cu);
+ }
+ else
+ {
+ ref = dwarf2_get_ref_die_offset (type_attr, cu);
+ type_die = follow_die_ref (ref);
+ if (!type_die)
+ {
+ error ("Dwarf Error: Cannot find referent at offset %d [in module %s]",
+ ref, cu->objfile->name);
+ return NULL;
+ }
+ }
+ type = tag_type_to_type (type_die, cu);
+ if (!type)
+ {
+ dump_die (type_die);
+ error ("Dwarf Error: Problem turning type die at offset into gdb type [in module %s]",
+ cu->objfile->name);
+ }
+ return type;
+}
+
+/* Return the containing type of the die in question using its
+ DW_AT_containing_type attribute. */
+
+static struct type *
+die_containing_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct type *type = NULL;
+ struct attribute *type_attr;
+ struct die_info *type_die = NULL;
+ unsigned int ref;
+
+ type_attr = dwarf2_attr (die, DW_AT_containing_type, cu);
+ if (type_attr)
+ {
+ ref = dwarf2_get_ref_die_offset (type_attr, cu);
+ type_die = follow_die_ref (ref);
+ if (!type_die)
+ {
+ error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", ref,
+ cu->objfile->name);
+ return NULL;
+ }
+ type = tag_type_to_type (type_die, cu);
+ }
+ if (!type)
+ {
+ if (type_die)
+ dump_die (type_die);
+ error ("Dwarf Error: Problem turning containing type into gdb type [in module %s]",
+ cu->objfile->name);
+ }
+ return type;
+}
+
+#if 0
+static struct type *
+type_at_offset (unsigned int offset, struct dwarf2_cu *cu)
+{
+ struct die_info *die;
+ struct type *type;
+
+ die = follow_die_ref (offset);
+ if (!die)
+ {
+ error ("Dwarf Error: Cannot find type referent at offset %d.", offset);
+ return NULL;
+ }
+ type = tag_type_to_type (die, cu);
+ return type;
+}
+#endif
+
+static struct type *
+tag_type_to_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ if (die->type)
+ {
+ return die->type;
+ }
+ else
+ {
+ read_type_die (die, cu);
+ if (!die->type)
+ {
+ dump_die (die);
+ error ("Dwarf Error: Cannot find type of die [in module %s]",
+ cu->objfile->name);
+ }
+ return die->type;
+ }
+}
+
+static void
+read_type_die (struct die_info *die, struct dwarf2_cu *cu)
+{
+ char *prefix = determine_prefix (die, cu);
+ const char *old_prefix = processing_current_prefix;
+ struct cleanup *back_to = make_cleanup (xfree, prefix);
+ processing_current_prefix = prefix;
+
+ switch (die->tag)
+ {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ read_structure_type (die, cu);
+ break;
+ case DW_TAG_enumeration_type:
+ read_enumeration_type (die, cu);
+ break;
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ read_subroutine_type (die, cu);
+ break;
+ case DW_TAG_array_type:
+ read_array_type (die, cu);
+ break;
+ case DW_TAG_pointer_type:
+ read_tag_pointer_type (die, cu);
+ break;
+ case DW_TAG_ptr_to_member_type:
+ read_tag_ptr_to_member_type (die, cu);
+ break;
+ case DW_TAG_reference_type:
+ read_tag_reference_type (die, cu);
+ break;
+ case DW_TAG_const_type:
+ read_tag_const_type (die, cu);
+ break;
+ case DW_TAG_volatile_type:
+ read_tag_volatile_type (die, cu);
+ break;
+ case DW_TAG_string_type:
+ read_tag_string_type (die, cu);
+ break;
+ case DW_TAG_typedef:
+ read_typedef (die, cu);
+ break;
+ case DW_TAG_subrange_type:
+ read_subrange_type (die, cu);
+ break;
+ case DW_TAG_base_type:
+ read_base_type (die, cu);
+ break;
+ default:
+ complaint (&symfile_complaints, "unexepected tag in read_type_die: '%s'",
+ dwarf_tag_name (die->tag));
+ break;
+ }
+
+ processing_current_prefix = old_prefix;
+ do_cleanups (back_to);
+}
+
+/* Return the name of the namespace/class that DIE is defined within,
+ or "" if we can't tell. The caller should xfree the result. */
+
+/* NOTE: carlton/2004-01-23: See read_func_scope (and the comment
+ therein) for an example of how to use this function to deal with
+ DW_AT_specification. */
+
+static char *
+determine_prefix (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct die_info *parent;
+
+ if (cu->language != language_cplus)
+ return NULL;
+
+ parent = die->parent;
+
+ if (parent == NULL)
+ {
+ return xstrdup ("");
+ }
+ else
+ {
+ switch (parent->tag) {
+ case DW_TAG_namespace:
+ {
+ /* FIXME: carlton/2004-03-05: Should I follow extension dies
+ before doing this check? */
+ if (parent->type != NULL && TYPE_TAG_NAME (parent->type) != NULL)
+ {
+ return xstrdup (TYPE_TAG_NAME (parent->type));
+ }
+ else
+ {
+ int dummy;
+ char *parent_prefix = determine_prefix (parent, cu);
+ char *retval = typename_concat (parent_prefix,
+ namespace_name (parent, &dummy,
+ cu));
+ xfree (parent_prefix);
+ return retval;
+ }
+ }
+ break;
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ {
+ if (parent->type != NULL && TYPE_TAG_NAME (parent->type) != NULL)
+ {
+ return xstrdup (TYPE_TAG_NAME (parent->type));
+ }
+ else
+ {
+ const char *old_prefix = processing_current_prefix;
+ char *new_prefix = determine_prefix (parent, cu);
+ char *retval;
+
+ processing_current_prefix = new_prefix;
+ retval = determine_class_name (parent, cu);
+ processing_current_prefix = old_prefix;
+
+ xfree (new_prefix);
+ return retval;
+ }
+ }
+ default:
+ return determine_prefix (parent, cu);
+ }
+ }
+}
+
+/* Return a newly-allocated string formed by concatenating PREFIX,
+ "::", and SUFFIX, except that if PREFIX is NULL or the empty
+ string, just return a copy of SUFFIX. */
+
+static char *
+typename_concat (const char *prefix, const char *suffix)
+{
+ if (prefix == NULL || prefix[0] == '\0')
+ return xstrdup (suffix);
+ else
+ {
+ char *retval = xmalloc (strlen (prefix) + 2 + strlen (suffix) + 1);
+
+ strcpy (retval, prefix);
+ strcat (retval, "::");
+ strcat (retval, suffix);
+
+ return retval;
+ }
+}
+
+static struct type *
+dwarf_base_type (int encoding, int size, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+
+ /* FIXME - this should not produce a new (struct type *)
+ every time. It should cache base types. */
+ struct type *type;
+ switch (encoding)
+ {
+ case DW_ATE_address:
+ type = dwarf2_fundamental_type (objfile, FT_VOID, cu);
+ return type;
+ case DW_ATE_boolean:
+ type = dwarf2_fundamental_type (objfile, FT_BOOLEAN, cu);
+ return type;
+ case DW_ATE_complex_float:
+ if (size == 16)
+ {
+ type = dwarf2_fundamental_type (objfile, FT_DBL_PREC_COMPLEX, cu);
+ }
+ else
+ {
+ type = dwarf2_fundamental_type (objfile, FT_COMPLEX, cu);
+ }
+ return type;
+ case DW_ATE_float:
+ if (size == 8)
+ {
+ type = dwarf2_fundamental_type (objfile, FT_DBL_PREC_FLOAT, cu);
+ }
+ else
+ {
+ type = dwarf2_fundamental_type (objfile, FT_FLOAT, cu);
+ }
+ return type;
+ case DW_ATE_signed:
+ switch (size)
+ {
+ case 1:
+ type = dwarf2_fundamental_type (objfile, FT_SIGNED_CHAR, cu);
+ break;
+ case 2:
+ type = dwarf2_fundamental_type (objfile, FT_SIGNED_SHORT, cu);
+ break;
+ default:
+ case 4:
+ type = dwarf2_fundamental_type (objfile, FT_SIGNED_INTEGER, cu);
+ break;
+ }
+ return type;
+ case DW_ATE_signed_char:
+ type = dwarf2_fundamental_type (objfile, FT_SIGNED_CHAR, cu);
+ return type;
+ case DW_ATE_unsigned:
+ switch (size)
+ {
+ case 1:
+ type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_CHAR, cu);
+ break;
+ case 2:
+ type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_SHORT, cu);
+ break;
+ default:
+ case 4:
+ type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_INTEGER, cu);
+ break;
+ }
+ return type;
+ case DW_ATE_unsigned_char:
+ type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_CHAR, cu);
+ return type;
+ default:
+ type = dwarf2_fundamental_type (objfile, FT_SIGNED_INTEGER, cu);
+ return type;
+ }
+}
+
+#if 0
+struct die_info *
+copy_die (struct die_info *old_die)
+{
+ struct die_info *new_die;
+ int i, num_attrs;
+
+ new_die = (struct die_info *) xmalloc (sizeof (struct die_info));
+ memset (new_die, 0, sizeof (struct die_info));
+
+ new_die->tag = old_die->tag;
+ new_die->has_children = old_die->has_children;
+ new_die->abbrev = old_die->abbrev;
+ new_die->offset = old_die->offset;
+ new_die->type = NULL;
+
+ num_attrs = old_die->num_attrs;
+ new_die->num_attrs = num_attrs;
+ new_die->attrs = (struct attribute *)
+ xmalloc (num_attrs * sizeof (struct attribute));
+
+ for (i = 0; i < old_die->num_attrs; ++i)
+ {
+ new_die->attrs[i].name = old_die->attrs[i].name;
+ new_die->attrs[i].form = old_die->attrs[i].form;
+ new_die->attrs[i].u.addr = old_die->attrs[i].u.addr;
+ }
+
+ new_die->next = NULL;
+ return new_die;
+}
+#endif
+
+/* Return sibling of die, NULL if no sibling. */
+
+static struct die_info *
+sibling_die (struct die_info *die)
+{
+ return die->sibling;
+}
+
+/* Get linkage name of a die, return NULL if not found. */
+
+static char *
+dwarf2_linkage_name (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+
+ attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu);
+ if (attr && DW_STRING (attr))
+ return DW_STRING (attr);
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ return DW_STRING (attr);
+ return NULL;
+}
+
+/* Get name of a die, return NULL if not found. */
+
+static char *
+dwarf2_name (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+
+ attr = dwarf2_attr (die, DW_AT_name, cu);
+ if (attr && DW_STRING (attr))
+ return DW_STRING (attr);
+ return NULL;
+}
+
+/* Return the die that this die in an extension of, or NULL if there
+ is none. */
+
+static struct die_info *
+dwarf2_extension (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+ struct die_info *extension_die;
+ unsigned int ref;
+
+ attr = dwarf2_attr (die, DW_AT_extension, cu);
+ if (attr == NULL)
+ return NULL;
+
+ ref = dwarf2_get_ref_die_offset (attr, cu);
+ extension_die = follow_die_ref (ref);
+ if (!extension_die)
+ {
+ error ("Dwarf Error: Cannot find referent at offset %d.", ref);
+ }
+
+ return extension_die;
+}
+
+/* Convert a DIE tag into its string name. */
+
+static char *
+dwarf_tag_name (unsigned tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_padding:
+ return "DW_TAG_padding";
+ case DW_TAG_array_type:
+ return "DW_TAG_array_type";
+ case DW_TAG_class_type:
+ return "DW_TAG_class_type";
+ case DW_TAG_entry_point:
+ return "DW_TAG_entry_point";
+ case DW_TAG_enumeration_type:
+ return "DW_TAG_enumeration_type";
+ case DW_TAG_formal_parameter:
+ return "DW_TAG_formal_parameter";
+ case DW_TAG_imported_declaration:
+ return "DW_TAG_imported_declaration";
+ case DW_TAG_label:
+ return "DW_TAG_label";
+ case DW_TAG_lexical_block:
+ return "DW_TAG_lexical_block";
+ case DW_TAG_member:
+ return "DW_TAG_member";
+ case DW_TAG_pointer_type:
+ return "DW_TAG_pointer_type";
+ case DW_TAG_reference_type:
+ return "DW_TAG_reference_type";
+ case DW_TAG_compile_unit:
+ return "DW_TAG_compile_unit";
+ case DW_TAG_string_type:
+ return "DW_TAG_string_type";
+ case DW_TAG_structure_type:
+ return "DW_TAG_structure_type";
+ case DW_TAG_subroutine_type:
+ return "DW_TAG_subroutine_type";
+ case DW_TAG_typedef:
+ return "DW_TAG_typedef";
+ case DW_TAG_union_type:
+ return "DW_TAG_union_type";
+ case DW_TAG_unspecified_parameters:
+ return "DW_TAG_unspecified_parameters";
+ case DW_TAG_variant:
+ return "DW_TAG_variant";
+ case DW_TAG_common_block:
+ return "DW_TAG_common_block";
+ case DW_TAG_common_inclusion:
+ return "DW_TAG_common_inclusion";
+ case DW_TAG_inheritance:
+ return "DW_TAG_inheritance";
+ case DW_TAG_inlined_subroutine:
+ return "DW_TAG_inlined_subroutine";
+ case DW_TAG_module:
+ return "DW_TAG_module";
+ case DW_TAG_ptr_to_member_type:
+ return "DW_TAG_ptr_to_member_type";
+ case DW_TAG_set_type:
+ return "DW_TAG_set_type";
+ case DW_TAG_subrange_type:
+ return "DW_TAG_subrange_type";
+ case DW_TAG_with_stmt:
+ return "DW_TAG_with_stmt";
+ case DW_TAG_access_declaration:
+ return "DW_TAG_access_declaration";
+ case DW_TAG_base_type:
+ return "DW_TAG_base_type";
+ case DW_TAG_catch_block:
+ return "DW_TAG_catch_block";
+ case DW_TAG_const_type:
+ return "DW_TAG_const_type";
+ case DW_TAG_constant:
+ return "DW_TAG_constant";
+ case DW_TAG_enumerator:
+ return "DW_TAG_enumerator";
+ case DW_TAG_file_type:
+ return "DW_TAG_file_type";
+ case DW_TAG_friend:
+ return "DW_TAG_friend";
+ case DW_TAG_namelist:
+ return "DW_TAG_namelist";
+ case DW_TAG_namelist_item:
+ return "DW_TAG_namelist_item";
+ case DW_TAG_packed_type:
+ return "DW_TAG_packed_type";
+ case DW_TAG_subprogram:
+ return "DW_TAG_subprogram";
+ case DW_TAG_template_type_param:
+ return "DW_TAG_template_type_param";
+ case DW_TAG_template_value_param:
+ return "DW_TAG_template_value_param";
+ case DW_TAG_thrown_type:
+ return "DW_TAG_thrown_type";
+ case DW_TAG_try_block:
+ return "DW_TAG_try_block";
+ case DW_TAG_variant_part:
+ return "DW_TAG_variant_part";
+ case DW_TAG_variable:
+ return "DW_TAG_variable";
+ case DW_TAG_volatile_type:
+ return "DW_TAG_volatile_type";
+ case DW_TAG_dwarf_procedure:
+ return "DW_TAG_dwarf_procedure";
+ case DW_TAG_restrict_type:
+ return "DW_TAG_restrict_type";
+ case DW_TAG_interface_type:
+ return "DW_TAG_interface_type";
+ case DW_TAG_namespace:
+ return "DW_TAG_namespace";
+ case DW_TAG_imported_module:
+ return "DW_TAG_imported_module";
+ case DW_TAG_unspecified_type:
+ return "DW_TAG_unspecified_type";
+ case DW_TAG_partial_unit:
+ return "DW_TAG_partial_unit";
+ case DW_TAG_imported_unit:
+ return "DW_TAG_imported_unit";
+ case DW_TAG_MIPS_loop:
+ return "DW_TAG_MIPS_loop";
+ case DW_TAG_format_label:
+ return "DW_TAG_format_label";
+ case DW_TAG_function_template:
+ return "DW_TAG_function_template";
+ case DW_TAG_class_template:
+ return "DW_TAG_class_template";
+ default:
+ return "DW_TAG_<unknown>";
+ }
+}
+
+/* Convert a DWARF attribute code into its string name. */
+
+static char *
+dwarf_attr_name (unsigned attr)
+{
+ switch (attr)
+ {
+ case DW_AT_sibling:
+ return "DW_AT_sibling";
+ case DW_AT_location:
+ return "DW_AT_location";
+ case DW_AT_name:
+ return "DW_AT_name";
+ case DW_AT_ordering:
+ return "DW_AT_ordering";
+ case DW_AT_subscr_data:
+ return "DW_AT_subscr_data";
+ case DW_AT_byte_size:
+ return "DW_AT_byte_size";
+ case DW_AT_bit_offset:
+ return "DW_AT_bit_offset";
+ case DW_AT_bit_size:
+ return "DW_AT_bit_size";
+ case DW_AT_element_list:
+ return "DW_AT_element_list";
+ case DW_AT_stmt_list:
+ return "DW_AT_stmt_list";
+ case DW_AT_low_pc:
+ return "DW_AT_low_pc";
+ case DW_AT_high_pc:
+ return "DW_AT_high_pc";
+ case DW_AT_language:
+ return "DW_AT_language";
+ case DW_AT_member:
+ return "DW_AT_member";
+ case DW_AT_discr:
+ return "DW_AT_discr";
+ case DW_AT_discr_value:
+ return "DW_AT_discr_value";
+ case DW_AT_visibility:
+ return "DW_AT_visibility";
+ case DW_AT_import:
+ return "DW_AT_import";
+ case DW_AT_string_length:
+ return "DW_AT_string_length";
+ case DW_AT_common_reference:
+ return "DW_AT_common_reference";
+ case DW_AT_comp_dir:
+ return "DW_AT_comp_dir";
+ case DW_AT_const_value:
+ return "DW_AT_const_value";
+ case DW_AT_containing_type:
+ return "DW_AT_containing_type";
+ case DW_AT_default_value:
+ return "DW_AT_default_value";
+ case DW_AT_inline:
+ return "DW_AT_inline";
+ case DW_AT_is_optional:
+ return "DW_AT_is_optional";
+ case DW_AT_lower_bound:
+ return "DW_AT_lower_bound";
+ case DW_AT_producer:
+ return "DW_AT_producer";
+ case DW_AT_prototyped:
+ return "DW_AT_prototyped";
+ case DW_AT_return_addr:
+ return "DW_AT_return_addr";
+ case DW_AT_start_scope:
+ return "DW_AT_start_scope";
+ case DW_AT_stride_size:
+ return "DW_AT_stride_size";
+ case DW_AT_upper_bound:
+ return "DW_AT_upper_bound";
+ case DW_AT_abstract_origin:
+ return "DW_AT_abstract_origin";
+ case DW_AT_accessibility:
+ return "DW_AT_accessibility";
+ case DW_AT_address_class:
+ return "DW_AT_address_class";
+ case DW_AT_artificial:
+ return "DW_AT_artificial";
+ case DW_AT_base_types:
+ return "DW_AT_base_types";
+ case DW_AT_calling_convention:
+ return "DW_AT_calling_convention";
+ case DW_AT_count:
+ return "DW_AT_count";
+ case DW_AT_data_member_location:
+ return "DW_AT_data_member_location";
+ case DW_AT_decl_column:
+ return "DW_AT_decl_column";
+ case DW_AT_decl_file:
+ return "DW_AT_decl_file";
+ case DW_AT_decl_line:
+ return "DW_AT_decl_line";
+ case DW_AT_declaration:
+ return "DW_AT_declaration";
+ case DW_AT_discr_list:
+ return "DW_AT_discr_list";
+ case DW_AT_encoding:
+ return "DW_AT_encoding";
+ case DW_AT_external:
+ return "DW_AT_external";
+ case DW_AT_frame_base:
+ return "DW_AT_frame_base";
+ case DW_AT_friend:
+ return "DW_AT_friend";
+ case DW_AT_identifier_case:
+ return "DW_AT_identifier_case";
+ case DW_AT_macro_info:
+ return "DW_AT_macro_info";
+ case DW_AT_namelist_items:
+ return "DW_AT_namelist_items";
+ case DW_AT_priority:
+ return "DW_AT_priority";
+ case DW_AT_segment:
+ return "DW_AT_segment";
+ case DW_AT_specification:
+ return "DW_AT_specification";
+ case DW_AT_static_link:
+ return "DW_AT_static_link";
+ case DW_AT_type:
+ return "DW_AT_type";
+ case DW_AT_use_location:
+ return "DW_AT_use_location";
+ case DW_AT_variable_parameter:
+ return "DW_AT_variable_parameter";
+ case DW_AT_virtuality:
+ return "DW_AT_virtuality";
+ case DW_AT_vtable_elem_location:
+ return "DW_AT_vtable_elem_location";
+ case DW_AT_allocated:
+ return "DW_AT_allocated";
+ case DW_AT_associated:
+ return "DW_AT_associated";
+ case DW_AT_data_location:
+ return "DW_AT_data_location";
+ case DW_AT_stride:
+ return "DW_AT_stride";
+ case DW_AT_entry_pc:
+ return "DW_AT_entry_pc";
+ case DW_AT_use_UTF8:
+ return "DW_AT_use_UTF8";
+ case DW_AT_extension:
+ return "DW_AT_extension";
+ case DW_AT_ranges:
+ return "DW_AT_ranges";
+ case DW_AT_trampoline:
+ return "DW_AT_trampoline";
+ case DW_AT_call_column:
+ return "DW_AT_call_column";
+ case DW_AT_call_file:
+ return "DW_AT_call_file";
+ case DW_AT_call_line:
+ return "DW_AT_call_line";
+#ifdef MIPS
+ case DW_AT_MIPS_fde:
+ return "DW_AT_MIPS_fde";
+ case DW_AT_MIPS_loop_begin:
+ return "DW_AT_MIPS_loop_begin";
+ case DW_AT_MIPS_tail_loop_begin:
+ return "DW_AT_MIPS_tail_loop_begin";
+ case DW_AT_MIPS_epilog_begin:
+ return "DW_AT_MIPS_epilog_begin";
+ case DW_AT_MIPS_loop_unroll_factor:
+ return "DW_AT_MIPS_loop_unroll_factor";
+ case DW_AT_MIPS_software_pipeline_depth:
+ return "DW_AT_MIPS_software_pipeline_depth";
+#endif
+ case DW_AT_MIPS_linkage_name:
+ return "DW_AT_MIPS_linkage_name";
+
+ case DW_AT_sf_names:
+ return "DW_AT_sf_names";
+ case DW_AT_src_info:
+ return "DW_AT_src_info";
+ case DW_AT_mac_info:
+ return "DW_AT_mac_info";
+ case DW_AT_src_coords:
+ return "DW_AT_src_coords";
+ case DW_AT_body_begin:
+ return "DW_AT_body_begin";
+ case DW_AT_body_end:
+ return "DW_AT_body_end";
+ case DW_AT_GNU_vector:
+ return "DW_AT_GNU_vector";
+ default:
+ return "DW_AT_<unknown>";
+ }
+}
+
+/* Convert a DWARF value form code into its string name. */
+
+static char *
+dwarf_form_name (unsigned form)
+{
+ switch (form)
+ {
+ case DW_FORM_addr:
+ return "DW_FORM_addr";
+ case DW_FORM_block2:
+ return "DW_FORM_block2";
+ case DW_FORM_block4:
+ return "DW_FORM_block4";
+ case DW_FORM_data2:
+ return "DW_FORM_data2";
+ case DW_FORM_data4:
+ return "DW_FORM_data4";
+ case DW_FORM_data8:
+ return "DW_FORM_data8";
+ case DW_FORM_string:
+ return "DW_FORM_string";
+ case DW_FORM_block:
+ return "DW_FORM_block";
+ case DW_FORM_block1:
+ return "DW_FORM_block1";
+ case DW_FORM_data1:
+ return "DW_FORM_data1";
+ case DW_FORM_flag:
+ return "DW_FORM_flag";
+ case DW_FORM_sdata:
+ return "DW_FORM_sdata";
+ case DW_FORM_strp:
+ return "DW_FORM_strp";
+ case DW_FORM_udata:
+ return "DW_FORM_udata";
+ case DW_FORM_ref_addr:
+ return "DW_FORM_ref_addr";
+ case DW_FORM_ref1:
+ return "DW_FORM_ref1";
+ case DW_FORM_ref2:
+ return "DW_FORM_ref2";
+ case DW_FORM_ref4:
+ return "DW_FORM_ref4";
+ case DW_FORM_ref8:
+ return "DW_FORM_ref8";
+ case DW_FORM_ref_udata:
+ return "DW_FORM_ref_udata";
+ case DW_FORM_indirect:
+ return "DW_FORM_indirect";
+ default:
+ return "DW_FORM_<unknown>";
+ }
+}
+
+/* Convert a DWARF stack opcode into its string name. */
+
+static char *
+dwarf_stack_op_name (unsigned op)
+{
+ switch (op)
+ {
+ case DW_OP_addr:
+ return "DW_OP_addr";
+ case DW_OP_deref:
+ return "DW_OP_deref";
+ case DW_OP_const1u:
+ return "DW_OP_const1u";
+ case DW_OP_const1s:
+ return "DW_OP_const1s";
+ case DW_OP_const2u:
+ return "DW_OP_const2u";
+ case DW_OP_const2s:
+ return "DW_OP_const2s";
+ case DW_OP_const4u:
+ return "DW_OP_const4u";
+ case DW_OP_const4s:
+ return "DW_OP_const4s";
+ case DW_OP_const8u:
+ return "DW_OP_const8u";
+ case DW_OP_const8s:
+ return "DW_OP_const8s";
+ case DW_OP_constu:
+ return "DW_OP_constu";
+ case DW_OP_consts:
+ return "DW_OP_consts";
+ case DW_OP_dup:
+ return "DW_OP_dup";
+ case DW_OP_drop:
+ return "DW_OP_drop";
+ case DW_OP_over:
+ return "DW_OP_over";
+ case DW_OP_pick:
+ return "DW_OP_pick";
+ case DW_OP_swap:
+ return "DW_OP_swap";
+ case DW_OP_rot:
+ return "DW_OP_rot";
+ case DW_OP_xderef:
+ return "DW_OP_xderef";
+ case DW_OP_abs:
+ return "DW_OP_abs";
+ case DW_OP_and:
+ return "DW_OP_and";
+ case DW_OP_div:
+ return "DW_OP_div";
+ case DW_OP_minus:
+ return "DW_OP_minus";
+ case DW_OP_mod:
+ return "DW_OP_mod";
+ case DW_OP_mul:
+ return "DW_OP_mul";
+ case DW_OP_neg:
+ return "DW_OP_neg";
+ case DW_OP_not:
+ return "DW_OP_not";
+ case DW_OP_or:
+ return "DW_OP_or";
+ case DW_OP_plus:
+ return "DW_OP_plus";
+ case DW_OP_plus_uconst:
+ return "DW_OP_plus_uconst";
+ case DW_OP_shl:
+ return "DW_OP_shl";
+ case DW_OP_shr:
+ return "DW_OP_shr";
+ case DW_OP_shra:
+ return "DW_OP_shra";
+ case DW_OP_xor:
+ return "DW_OP_xor";
+ case DW_OP_bra:
+ return "DW_OP_bra";
+ case DW_OP_eq:
+ return "DW_OP_eq";
+ case DW_OP_ge:
+ return "DW_OP_ge";
+ case DW_OP_gt:
+ return "DW_OP_gt";
+ case DW_OP_le:
+ return "DW_OP_le";
+ case DW_OP_lt:
+ return "DW_OP_lt";
+ case DW_OP_ne:
+ return "DW_OP_ne";
+ case DW_OP_skip:
+ return "DW_OP_skip";
+ case DW_OP_lit0:
+ return "DW_OP_lit0";
+ case DW_OP_lit1:
+ return "DW_OP_lit1";
+ case DW_OP_lit2:
+ return "DW_OP_lit2";
+ case DW_OP_lit3:
+ return "DW_OP_lit3";
+ case DW_OP_lit4:
+ return "DW_OP_lit4";
+ case DW_OP_lit5:
+ return "DW_OP_lit5";
+ case DW_OP_lit6:
+ return "DW_OP_lit6";
+ case DW_OP_lit7:
+ return "DW_OP_lit7";
+ case DW_OP_lit8:
+ return "DW_OP_lit8";
+ case DW_OP_lit9:
+ return "DW_OP_lit9";
+ case DW_OP_lit10:
+ return "DW_OP_lit10";
+ case DW_OP_lit11:
+ return "DW_OP_lit11";
+ case DW_OP_lit12:
+ return "DW_OP_lit12";
+ case DW_OP_lit13:
+ return "DW_OP_lit13";
+ case DW_OP_lit14:
+ return "DW_OP_lit14";
+ case DW_OP_lit15:
+ return "DW_OP_lit15";
+ case DW_OP_lit16:
+ return "DW_OP_lit16";
+ case DW_OP_lit17:
+ return "DW_OP_lit17";
+ case DW_OP_lit18:
+ return "DW_OP_lit18";
+ case DW_OP_lit19:
+ return "DW_OP_lit19";
+ case DW_OP_lit20:
+ return "DW_OP_lit20";
+ case DW_OP_lit21:
+ return "DW_OP_lit21";
+ case DW_OP_lit22:
+ return "DW_OP_lit22";
+ case DW_OP_lit23:
+ return "DW_OP_lit23";
+ case DW_OP_lit24:
+ return "DW_OP_lit24";
+ case DW_OP_lit25:
+ return "DW_OP_lit25";
+ case DW_OP_lit26:
+ return "DW_OP_lit26";
+ case DW_OP_lit27:
+ return "DW_OP_lit27";
+ case DW_OP_lit28:
+ return "DW_OP_lit28";
+ case DW_OP_lit29:
+ return "DW_OP_lit29";
+ case DW_OP_lit30:
+ return "DW_OP_lit30";
+ case DW_OP_lit31:
+ return "DW_OP_lit31";
+ case DW_OP_reg0:
+ return "DW_OP_reg0";
+ case DW_OP_reg1:
+ return "DW_OP_reg1";
+ case DW_OP_reg2:
+ return "DW_OP_reg2";
+ case DW_OP_reg3:
+ return "DW_OP_reg3";
+ case DW_OP_reg4:
+ return "DW_OP_reg4";
+ case DW_OP_reg5:
+ return "DW_OP_reg5";
+ case DW_OP_reg6:
+ return "DW_OP_reg6";
+ case DW_OP_reg7:
+ return "DW_OP_reg7";
+ case DW_OP_reg8:
+ return "DW_OP_reg8";
+ case DW_OP_reg9:
+ return "DW_OP_reg9";
+ case DW_OP_reg10:
+ return "DW_OP_reg10";
+ case DW_OP_reg11:
+ return "DW_OP_reg11";
+ case DW_OP_reg12:
+ return "DW_OP_reg12";
+ case DW_OP_reg13:
+ return "DW_OP_reg13";
+ case DW_OP_reg14:
+ return "DW_OP_reg14";
+ case DW_OP_reg15:
+ return "DW_OP_reg15";
+ case DW_OP_reg16:
+ return "DW_OP_reg16";
+ case DW_OP_reg17:
+ return "DW_OP_reg17";
+ case DW_OP_reg18:
+ return "DW_OP_reg18";
+ case DW_OP_reg19:
+ return "DW_OP_reg19";
+ case DW_OP_reg20:
+ return "DW_OP_reg20";
+ case DW_OP_reg21:
+ return "DW_OP_reg21";
+ case DW_OP_reg22:
+ return "DW_OP_reg22";
+ case DW_OP_reg23:
+ return "DW_OP_reg23";
+ case DW_OP_reg24:
+ return "DW_OP_reg24";
+ case DW_OP_reg25:
+ return "DW_OP_reg25";
+ case DW_OP_reg26:
+ return "DW_OP_reg26";
+ case DW_OP_reg27:
+ return "DW_OP_reg27";
+ case DW_OP_reg28:
+ return "DW_OP_reg28";
+ case DW_OP_reg29:
+ return "DW_OP_reg29";
+ case DW_OP_reg30:
+ return "DW_OP_reg30";
+ case DW_OP_reg31:
+ return "DW_OP_reg31";
+ case DW_OP_breg0:
+ return "DW_OP_breg0";
+ case DW_OP_breg1:
+ return "DW_OP_breg1";
+ case DW_OP_breg2:
+ return "DW_OP_breg2";
+ case DW_OP_breg3:
+ return "DW_OP_breg3";
+ case DW_OP_breg4:
+ return "DW_OP_breg4";
+ case DW_OP_breg5:
+ return "DW_OP_breg5";
+ case DW_OP_breg6:
+ return "DW_OP_breg6";
+ case DW_OP_breg7:
+ return "DW_OP_breg7";
+ case DW_OP_breg8:
+ return "DW_OP_breg8";
+ case DW_OP_breg9:
+ return "DW_OP_breg9";
+ case DW_OP_breg10:
+ return "DW_OP_breg10";
+ case DW_OP_breg11:
+ return "DW_OP_breg11";
+ case DW_OP_breg12:
+ return "DW_OP_breg12";
+ case DW_OP_breg13:
+ return "DW_OP_breg13";
+ case DW_OP_breg14:
+ return "DW_OP_breg14";
+ case DW_OP_breg15:
+ return "DW_OP_breg15";
+ case DW_OP_breg16:
+ return "DW_OP_breg16";
+ case DW_OP_breg17:
+ return "DW_OP_breg17";
+ case DW_OP_breg18:
+ return "DW_OP_breg18";
+ case DW_OP_breg19:
+ return "DW_OP_breg19";
+ case DW_OP_breg20:
+ return "DW_OP_breg20";
+ case DW_OP_breg21:
+ return "DW_OP_breg21";
+ case DW_OP_breg22:
+ return "DW_OP_breg22";
+ case DW_OP_breg23:
+ return "DW_OP_breg23";
+ case DW_OP_breg24:
+ return "DW_OP_breg24";
+ case DW_OP_breg25:
+ return "DW_OP_breg25";
+ case DW_OP_breg26:
+ return "DW_OP_breg26";
+ case DW_OP_breg27:
+ return "DW_OP_breg27";
+ case DW_OP_breg28:
+ return "DW_OP_breg28";
+ case DW_OP_breg29:
+ return "DW_OP_breg29";
+ case DW_OP_breg30:
+ return "DW_OP_breg30";
+ case DW_OP_breg31:
+ return "DW_OP_breg31";
+ case DW_OP_regx:
+ return "DW_OP_regx";
+ case DW_OP_fbreg:
+ return "DW_OP_fbreg";
+ case DW_OP_bregx:
+ return "DW_OP_bregx";
+ case DW_OP_piece:
+ return "DW_OP_piece";
+ case DW_OP_deref_size:
+ return "DW_OP_deref_size";
+ case DW_OP_xderef_size:
+ return "DW_OP_xderef_size";
+ case DW_OP_nop:
+ return "DW_OP_nop";
+ /* DWARF 3 extensions. */
+ case DW_OP_push_object_address:
+ return "DW_OP_push_object_address";
+ case DW_OP_call2:
+ return "DW_OP_call2";
+ case DW_OP_call4:
+ return "DW_OP_call4";
+ case DW_OP_call_ref:
+ return "DW_OP_call_ref";
+ /* GNU extensions. */
+ case DW_OP_GNU_push_tls_address:
+ return "DW_OP_GNU_push_tls_address";
+ default:
+ return "OP_<unknown>";
+ }
+}
+
+static char *
+dwarf_bool_name (unsigned mybool)
+{
+ if (mybool)
+ return "TRUE";
+ else
+ return "FALSE";
+}
+
+/* Convert a DWARF type code into its string name. */
+
+static char *
+dwarf_type_encoding_name (unsigned enc)
+{
+ switch (enc)
+ {
+ case DW_ATE_address:
+ return "DW_ATE_address";
+ case DW_ATE_boolean:
+ return "DW_ATE_boolean";
+ case DW_ATE_complex_float:
+ return "DW_ATE_complex_float";
+ case DW_ATE_float:
+ return "DW_ATE_float";
+ case DW_ATE_signed:
+ return "DW_ATE_signed";
+ case DW_ATE_signed_char:
+ return "DW_ATE_signed_char";
+ case DW_ATE_unsigned:
+ return "DW_ATE_unsigned";
+ case DW_ATE_unsigned_char:
+ return "DW_ATE_unsigned_char";
+ case DW_ATE_imaginary_float:
+ return "DW_ATE_imaginary_float";
+ default:
+ return "DW_ATE_<unknown>";
+ }
+}
+
+/* Convert a DWARF call frame info operation to its string name. */
+
+#if 0
+static char *
+dwarf_cfi_name (unsigned cfi_opc)
+{
+ switch (cfi_opc)
+ {
+ case DW_CFA_advance_loc:
+ return "DW_CFA_advance_loc";
+ case DW_CFA_offset:
+ return "DW_CFA_offset";
+ case DW_CFA_restore:
+ return "DW_CFA_restore";
+ case DW_CFA_nop:
+ return "DW_CFA_nop";
+ case DW_CFA_set_loc:
+ return "DW_CFA_set_loc";
+ case DW_CFA_advance_loc1:
+ return "DW_CFA_advance_loc1";
+ case DW_CFA_advance_loc2:
+ return "DW_CFA_advance_loc2";
+ case DW_CFA_advance_loc4:
+ return "DW_CFA_advance_loc4";
+ case DW_CFA_offset_extended:
+ return "DW_CFA_offset_extended";
+ case DW_CFA_restore_extended:
+ return "DW_CFA_restore_extended";
+ case DW_CFA_undefined:
+ return "DW_CFA_undefined";
+ case DW_CFA_same_value:
+ return "DW_CFA_same_value";
+ case DW_CFA_register:
+ return "DW_CFA_register";
+ case DW_CFA_remember_state:
+ return "DW_CFA_remember_state";
+ case DW_CFA_restore_state:
+ return "DW_CFA_restore_state";
+ case DW_CFA_def_cfa:
+ return "DW_CFA_def_cfa";
+ case DW_CFA_def_cfa_register:
+ return "DW_CFA_def_cfa_register";
+ case DW_CFA_def_cfa_offset:
+ return "DW_CFA_def_cfa_offset";
+
+ /* DWARF 3 */
+ case DW_CFA_def_cfa_expression:
+ return "DW_CFA_def_cfa_expression";
+ case DW_CFA_expression:
+ return "DW_CFA_expression";
+ case DW_CFA_offset_extended_sf:
+ return "DW_CFA_offset_extended_sf";
+ case DW_CFA_def_cfa_sf:
+ return "DW_CFA_def_cfa_sf";
+ case DW_CFA_def_cfa_offset_sf:
+ return "DW_CFA_def_cfa_offset_sf";
+
+ /* SGI/MIPS specific */
+ case DW_CFA_MIPS_advance_loc8:
+ return "DW_CFA_MIPS_advance_loc8";
+
+ /* GNU extensions */
+ case DW_CFA_GNU_window_save:
+ return "DW_CFA_GNU_window_save";
+ case DW_CFA_GNU_args_size:
+ return "DW_CFA_GNU_args_size";
+ case DW_CFA_GNU_negative_offset_extended:
+ return "DW_CFA_GNU_negative_offset_extended";
+
+ default:
+ return "DW_CFA_<unknown>";
+ }
+}
+#endif
+
+static void
+dump_die (struct die_info *die)
+{
+ unsigned int i;
+
+ fprintf_unfiltered (gdb_stderr, "Die: %s (abbrev = %d, offset = %d)\n",
+ dwarf_tag_name (die->tag), die->abbrev, die->offset);
+ fprintf_unfiltered (gdb_stderr, "\thas children: %s\n",
+ dwarf_bool_name (die->child != NULL));
+
+ fprintf_unfiltered (gdb_stderr, "\tattributes:\n");
+ for (i = 0; i < die->num_attrs; ++i)
+ {
+ fprintf_unfiltered (gdb_stderr, "\t\t%s (%s) ",
+ dwarf_attr_name (die->attrs[i].name),
+ dwarf_form_name (die->attrs[i].form));
+ switch (die->attrs[i].form)
+ {
+ case DW_FORM_ref_addr:
+ case DW_FORM_addr:
+ fprintf_unfiltered (gdb_stderr, "address: ");
+ print_address_numeric (DW_ADDR (&die->attrs[i]), 1, gdb_stderr);
+ break;
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ fprintf_unfiltered (gdb_stderr, "block: size %d", DW_BLOCK (&die->attrs[i])->size);
+ break;
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_udata:
+ case DW_FORM_sdata:
+ fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));
+ break;
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ fprintf_unfiltered (gdb_stderr, "string: \"%s\"",
+ DW_STRING (&die->attrs[i])
+ ? DW_STRING (&die->attrs[i]) : "");
+ break;
+ case DW_FORM_flag:
+ if (DW_UNSND (&die->attrs[i]))
+ fprintf_unfiltered (gdb_stderr, "flag: TRUE");
+ else
+ fprintf_unfiltered (gdb_stderr, "flag: FALSE");
+ break;
+ case DW_FORM_indirect:
+ /* the reader will have reduced the indirect form to
+ the "base form" so this form should not occur */
+ fprintf_unfiltered (gdb_stderr, "unexpected attribute form: DW_FORM_indirect");
+ break;
+ default:
+ fprintf_unfiltered (gdb_stderr, "unsupported attribute form: %d.",
+ die->attrs[i].form);
+ }
+ fprintf_unfiltered (gdb_stderr, "\n");
+ }
+}
+
+static void
+dump_die_list (struct die_info *die)
+{
+ while (die)
+ {
+ dump_die (die);
+ if (die->child != NULL)
+ dump_die_list (die->child);
+ if (die->sibling != NULL)
+ dump_die_list (die->sibling);
+ }
+}
+
+static void
+store_in_ref_table (unsigned int offset, struct die_info *die)
+{
+ int h;
+ struct die_info *old;
+
+ h = (offset % REF_HASH_SIZE);
+ old = die_ref_table[h];
+ die->next_ref = old;
+ die_ref_table[h] = die;
+}
+
+
+static void
+dwarf2_empty_hash_tables (void)
+{
+ memset (die_ref_table, 0, sizeof (die_ref_table));
+}
+
+static unsigned int
+dwarf2_get_ref_die_offset (struct attribute *attr, struct dwarf2_cu *cu)
+{
+ unsigned int result = 0;
+
+ switch (attr->form)
+ {
+ case DW_FORM_ref_addr:
+ result = DW_ADDR (attr);
+ break;
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ result = cu->header.offset + DW_UNSND (attr);
+ break;
+ default:
+ complaint (&symfile_complaints,
+ "unsupported die ref attribute form: '%s'",
+ dwarf_form_name (attr->form));
+ }
+ return result;
+}
+
+/* Return the constant value held by the given attribute. Return -1
+ if the value held by the attribute is not constant. */
+
+static int
+dwarf2_get_attr_constant_value (struct attribute *attr, int default_value)
+{
+ if (attr->form == DW_FORM_sdata)
+ return DW_SND (attr);
+ else if (attr->form == DW_FORM_udata
+ || attr->form == DW_FORM_data1
+ || attr->form == DW_FORM_data2
+ || attr->form == DW_FORM_data4
+ || attr->form == DW_FORM_data8)
+ return DW_UNSND (attr);
+ else
+ {
+ complaint (&symfile_complaints, "Attribute value is not a constant (%s)",
+ dwarf_form_name (attr->form));
+ return default_value;
+ }
+}
+
+static struct die_info *
+follow_die_ref (unsigned int offset)
+{
+ struct die_info *die;
+ int h;
+
+ h = (offset % REF_HASH_SIZE);
+ die = die_ref_table[h];
+ while (die)
+ {
+ if (die->offset == offset)
+ {
+ return die;
+ }
+ die = die->next_ref;
+ }
+ return NULL;
+}
+
+static struct type *
+dwarf2_fundamental_type (struct objfile *objfile, int typeid,
+ struct dwarf2_cu *cu)
+{
+ if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+ {
+ error ("Dwarf Error: internal error - invalid fundamental type id %d [in module %s]",
+ typeid, objfile->name);
+ }
+
+ /* 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 (cu->ftypes[typeid] == NULL)
+ {
+ cu->ftypes[typeid] = cu->language_defn->la_fund_type (objfile, typeid);
+ }
+
+ return (cu->ftypes[typeid]);
+}
+
+/* Decode simple location descriptions.
+ Given a pointer to a dwarf block that defines a location, compute
+ the location and return the value.
+
+ NOTE drow/2003-11-18: This function is called in two situations
+ now: for the address of static or global variables (partial symbols
+ only) and for offsets into structures which are expected to be
+ (more or less) constant. The partial symbol case should go away,
+ and only the constant case should remain. That will let this
+ function complain more accurately. A few special modes are allowed
+ without complaint for global variables (for instance, global
+ register values and thread-local values).
+
+ A location description containing no operations indicates that the
+ object is optimized out. The return value is 0 for that case.
+ FIXME drow/2003-11-16: No callers check for this case any more; soon all
+ callers will only want a very basic result and this can become a
+ complaint.
+
+ When the result is a register number, the global isreg flag is set,
+ otherwise it is cleared.
+
+ Note that stack[0] is unused except as a default error return.
+ Note that stack overflow is not yet handled. */
+
+static CORE_ADDR
+decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct comp_unit_head *cu_header = &cu->header;
+ int i;
+ int size = blk->size;
+ char *data = blk->data;
+ CORE_ADDR stack[64];
+ int stacki;
+ unsigned int bytes_read, unsnd;
+ unsigned char op;
+
+ i = 0;
+ stacki = 0;
+ stack[stacki] = 0;
+ isreg = 0;
+
+ while (i < size)
+ {
+ op = data[i++];
+ switch (op)
+ {
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ stack[++stacki] = op - DW_OP_lit0;
+ break;
+
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ isreg = 1;
+ stack[++stacki] = op - DW_OP_reg0;
+ if (i < size)
+ dwarf2_complex_location_expr_complaint ();
+ break;
+
+ case DW_OP_regx:
+ isreg = 1;
+ unsnd = read_unsigned_leb128 (NULL, (data + i), &bytes_read);
+ i += bytes_read;
+ stack[++stacki] = unsnd;
+ if (i < size)
+ dwarf2_complex_location_expr_complaint ();
+ break;
+
+ case DW_OP_addr:
+ stack[++stacki] = read_address (objfile->obfd, &data[i],
+ cu, &bytes_read);
+ i += bytes_read;
+ break;
+
+ case DW_OP_const1u:
+ stack[++stacki] = read_1_byte (objfile->obfd, &data[i]);
+ i += 1;
+ break;
+
+ case DW_OP_const1s:
+ stack[++stacki] = read_1_signed_byte (objfile->obfd, &data[i]);
+ i += 1;
+ break;
+
+ case DW_OP_const2u:
+ stack[++stacki] = read_2_bytes (objfile->obfd, &data[i]);
+ i += 2;
+ break;
+
+ case DW_OP_const2s:
+ stack[++stacki] = read_2_signed_bytes (objfile->obfd, &data[i]);
+ i += 2;
+ break;
+
+ case DW_OP_const4u:
+ stack[++stacki] = read_4_bytes (objfile->obfd, &data[i]);
+ i += 4;
+ break;
+
+ case DW_OP_const4s:
+ stack[++stacki] = read_4_signed_bytes (objfile->obfd, &data[i]);
+ i += 4;
+ break;
+
+ case DW_OP_constu:
+ stack[++stacki] = read_unsigned_leb128 (NULL, (data + i),
+ &bytes_read);
+ i += bytes_read;
+ break;
+
+ case DW_OP_consts:
+ stack[++stacki] = read_signed_leb128 (NULL, (data + i), &bytes_read);
+ i += bytes_read;
+ break;
+
+ case DW_OP_dup:
+ stack[stacki + 1] = stack[stacki];
+ stacki++;
+ break;
+
+ case DW_OP_plus:
+ stack[stacki - 1] += stack[stacki];
+ stacki--;
+ break;
+
+ case DW_OP_plus_uconst:
+ stack[stacki] += read_unsigned_leb128 (NULL, (data + i), &bytes_read);
+ i += bytes_read;
+ break;
+
+ case DW_OP_minus:
+ stack[stacki - 1] -= stack[stacki];
+ stacki--;
+ break;
+
+ case DW_OP_deref:
+ /* If we're not the last op, then we definitely can't encode
+ this using GDB's address_class enum. This is valid for partial
+ global symbols, although the variable's address will be bogus
+ in the psymtab. */
+ if (i < size)
+ dwarf2_complex_location_expr_complaint ();
+ break;
+
+ case DW_OP_GNU_push_tls_address:
+ /* The top of the stack has the offset from the beginning
+ of the thread control block at which the variable is located. */
+ /* Nothing should follow this operator, so the top of stack would
+ be returned. */
+ /* This is valid for partial global symbols, but the variable's
+ address will be bogus in the psymtab. */
+ if (i < size)
+ dwarf2_complex_location_expr_complaint ();
+ break;
+
+ default:
+ complaint (&symfile_complaints, "unsupported stack op: '%s'",
+ dwarf_stack_op_name (op));
+ return (stack[stacki]);
+ }
+ }
+ return (stack[stacki]);
+}
+
+/* memory allocation interface */
+
+static void
+dwarf2_free_tmp_obstack (void *ignore)
+{
+ obstack_free (&dwarf2_tmp_obstack, NULL);
+}
+
+static struct dwarf_block *
+dwarf_alloc_block (void)
+{
+ struct dwarf_block *blk;
+
+ blk = (struct dwarf_block *)
+ obstack_alloc (&dwarf2_tmp_obstack, sizeof (struct dwarf_block));
+ return (blk);
+}
+
+static struct abbrev_info *
+dwarf_alloc_abbrev (void)
+{
+ struct abbrev_info *abbrev;
+
+ abbrev = (struct abbrev_info *) xmalloc (sizeof (struct abbrev_info));
+ memset (abbrev, 0, sizeof (struct abbrev_info));
+ return (abbrev);
+}
+
+static struct die_info *
+dwarf_alloc_die (void)
+{
+ struct die_info *die;
+
+ die = (struct die_info *) xmalloc (sizeof (struct die_info));
+ memset (die, 0, sizeof (struct die_info));
+ return (die);
+}
+
+
+/* Macro support. */
+
+
+/* Return the full name of file number I in *LH's file name table.
+ Use COMP_DIR as the name of the current directory of the
+ compilation. The result is allocated using xmalloc; the caller is
+ responsible for freeing it. */
+static char *
+file_full_name (int file, struct line_header *lh, const char *comp_dir)
+{
+ struct file_entry *fe = &lh->file_names[file - 1];
+
+ if (IS_ABSOLUTE_PATH (fe->name))
+ return xstrdup (fe->name);
+ else
+ {
+ const char *dir;
+ int dir_len;
+ char *full_name;
+
+ if (fe->dir_index)
+ dir = lh->include_dirs[fe->dir_index - 1];
+ else
+ dir = comp_dir;
+
+ if (dir)
+ {
+ dir_len = strlen (dir);
+ full_name = xmalloc (dir_len + 1 + strlen (fe->name) + 1);
+ strcpy (full_name, dir);
+ full_name[dir_len] = '/';
+ strcpy (full_name + dir_len + 1, fe->name);
+ return full_name;
+ }
+ else
+ return xstrdup (fe->name);
+ }
+}
+
+
+static struct macro_source_file *
+macro_start_file (int file, int line,
+ struct macro_source_file *current_file,
+ const char *comp_dir,
+ struct line_header *lh, struct objfile *objfile)
+{
+ /* The full name of this source file. */
+ char *full_name = file_full_name (file, lh, comp_dir);
+
+ /* We don't create a macro table for this compilation unit
+ at all until we actually get a filename. */
+ if (! pending_macros)
+ pending_macros = new_macro_table (&objfile->objfile_obstack,
+ objfile->macro_cache);
+
+ if (! current_file)
+ /* If we have no current file, then this must be the start_file
+ directive for the compilation unit's main source file. */
+ current_file = macro_set_main (pending_macros, full_name);
+ else
+ current_file = macro_include (current_file, line, full_name);
+
+ xfree (full_name);
+
+ return current_file;
+}
+
+
+/* Copy the LEN characters at BUF to a xmalloc'ed block of memory,
+ followed by a null byte. */
+static char *
+copy_string (const char *buf, int len)
+{
+ char *s = xmalloc (len + 1);
+ memcpy (s, buf, len);
+ s[len] = '\0';
+
+ return s;
+}
+
+
+static const char *
+consume_improper_spaces (const char *p, const char *body)
+{
+ if (*p == ' ')
+ {
+ complaint (&symfile_complaints,
+ "macro definition contains spaces in formal argument list:\n`%s'",
+ body);
+
+ while (*p == ' ')
+ p++;
+ }
+
+ return p;
+}
+
+
+static void
+parse_macro_definition (struct macro_source_file *file, int line,
+ const char *body)
+{
+ const char *p;
+
+ /* The body string takes one of two forms. For object-like macro
+ definitions, it should be:
+
+ <macro name> " " <definition>
+
+ For function-like macro definitions, it should be:
+
+ <macro name> "() " <definition>
+ or
+ <macro name> "(" <arg name> ( "," <arg name> ) * ") " <definition>
+
+ Spaces may appear only where explicitly indicated, and in the
+ <definition>.
+
+ The Dwarf 2 spec says that an object-like macro's name is always
+ followed by a space, but versions of GCC around March 2002 omit
+ the space when the macro's definition is the empty string.
+
+ The Dwarf 2 spec says that there should be no spaces between the
+ formal arguments in a function-like macro's formal argument list,
+ but versions of GCC around March 2002 include spaces after the
+ commas. */
+
+
+ /* Find the extent of the macro name. The macro name is terminated
+ by either a space or null character (for an object-like macro) or
+ an opening paren (for a function-like macro). */
+ for (p = body; *p; p++)
+ if (*p == ' ' || *p == '(')
+ break;
+
+ if (*p == ' ' || *p == '\0')
+ {
+ /* It's an object-like macro. */
+ int name_len = p - body;
+ char *name = copy_string (body, name_len);
+ const char *replacement;
+
+ if (*p == ' ')
+ replacement = body + name_len + 1;
+ else
+ {
+ dwarf2_macro_malformed_definition_complaint (body);
+ replacement = body + name_len;
+ }
+
+ macro_define_object (file, line, name, replacement);
+
+ xfree (name);
+ }
+ else if (*p == '(')
+ {
+ /* It's a function-like macro. */
+ char *name = copy_string (body, p - body);
+ int argc = 0;
+ int argv_size = 1;
+ char **argv = xmalloc (argv_size * sizeof (*argv));
+
+ p++;
+
+ p = consume_improper_spaces (p, body);
+
+ /* Parse the formal argument list. */
+ while (*p && *p != ')')
+ {
+ /* Find the extent of the current argument name. */
+ const char *arg_start = p;
+
+ while (*p && *p != ',' && *p != ')' && *p != ' ')
+ p++;
+
+ if (! *p || p == arg_start)
+ dwarf2_macro_malformed_definition_complaint (body);
+ else
+ {
+ /* Make sure argv has room for the new argument. */
+ if (argc >= argv_size)
+ {
+ argv_size *= 2;
+ argv = xrealloc (argv, argv_size * sizeof (*argv));
+ }
+
+ argv[argc++] = copy_string (arg_start, p - arg_start);
+ }
+
+ p = consume_improper_spaces (p, body);
+
+ /* Consume the comma, if present. */
+ if (*p == ',')
+ {
+ p++;
+
+ p = consume_improper_spaces (p, body);
+ }
+ }
+
+ if (*p == ')')
+ {
+ p++;
+
+ if (*p == ' ')
+ /* Perfectly formed definition, no complaints. */
+ macro_define_function (file, line, name,
+ argc, (const char **) argv,
+ p + 1);
+ else if (*p == '\0')
+ {
+ /* Complain, but do define it. */
+ dwarf2_macro_malformed_definition_complaint (body);
+ macro_define_function (file, line, name,
+ argc, (const char **) argv,
+ p);
+ }
+ else
+ /* Just complain. */
+ dwarf2_macro_malformed_definition_complaint (body);
+ }
+ else
+ /* Just complain. */
+ dwarf2_macro_malformed_definition_complaint (body);
+
+ xfree (name);
+ {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ xfree (argv[i]);
+ }
+ xfree (argv);
+ }
+ else
+ dwarf2_macro_malformed_definition_complaint (body);
+}
+
+
+static void
+dwarf_decode_macros (struct line_header *lh, unsigned int offset,
+ char *comp_dir, bfd *abfd,
+ struct dwarf2_cu *cu)
+{
+ char *mac_ptr, *mac_end;
+ struct macro_source_file *current_file = 0;
+
+ if (dwarf_macinfo_buffer == NULL)
+ {
+ complaint (&symfile_complaints, "missing .debug_macinfo section");
+ return;
+ }
+
+ mac_ptr = dwarf_macinfo_buffer + offset;
+ mac_end = dwarf_macinfo_buffer + dwarf_macinfo_size;
+
+ for (;;)
+ {
+ enum dwarf_macinfo_record_type macinfo_type;
+
+ /* Do we at least have room for a macinfo type byte? */
+ if (mac_ptr >= mac_end)
+ {
+ dwarf2_macros_too_long_complaint ();
+ return;
+ }
+
+ macinfo_type = read_1_byte (abfd, mac_ptr);
+ mac_ptr++;
+
+ switch (macinfo_type)
+ {
+ /* A zero macinfo type indicates the end of the macro
+ information. */
+ case 0:
+ return;
+
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ {
+ int bytes_read;
+ int line;
+ char *body;
+
+ line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ body = read_string (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ if (! current_file)
+ complaint (&symfile_complaints,
+ "debug info gives macro %s outside of any file: %s",
+ macinfo_type ==
+ DW_MACINFO_define ? "definition" : macinfo_type ==
+ DW_MACINFO_undef ? "undefinition" :
+ "something-or-other", body);
+ else
+ {
+ if (macinfo_type == DW_MACINFO_define)
+ parse_macro_definition (current_file, line, body);
+ else if (macinfo_type == DW_MACINFO_undef)
+ macro_undef (current_file, line, body);
+ }
+ }
+ break;
+
+ case DW_MACINFO_start_file:
+ {
+ int bytes_read;
+ int line, file;
+
+ line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ current_file = macro_start_file (file, line,
+ current_file, comp_dir,
+ lh, cu->objfile);
+ }
+ break;
+
+ case DW_MACINFO_end_file:
+ if (! current_file)
+ complaint (&symfile_complaints,
+ "macro debug info has an unmatched `close_file' directive");
+ else
+ {
+ current_file = current_file->included_by;
+ if (! current_file)
+ {
+ enum dwarf_macinfo_record_type next_type;
+
+ /* GCC circa March 2002 doesn't produce the zero
+ type byte marking the end of the compilation
+ unit. Complain if it's not there, but exit no
+ matter what. */
+
+ /* Do we at least have room for a macinfo type byte? */
+ if (mac_ptr >= mac_end)
+ {
+ dwarf2_macros_too_long_complaint ();
+ return;
+ }
+
+ /* We don't increment mac_ptr here, so this is just
+ a look-ahead. */
+ next_type = read_1_byte (abfd, mac_ptr);
+ if (next_type != 0)
+ complaint (&symfile_complaints,
+ "no terminating 0-type entry for macros in `.debug_macinfo' section");
+
+ return;
+ }
+ }
+ break;
+
+ case DW_MACINFO_vendor_ext:
+ {
+ int bytes_read;
+ int constant;
+ char *string;
+
+ constant = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ string = read_string (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ /* We don't recognize any vendor extensions. */
+ }
+ break;
+ }
+ }
+}
+
+/* Check if the attribute's form is a DW_FORM_block*
+ if so return true else false. */
+static int
+attr_form_is_block (struct attribute *attr)
+{
+ return (attr == NULL ? 0 :
+ attr->form == DW_FORM_block1
+ || attr->form == DW_FORM_block2
+ || attr->form == DW_FORM_block4
+ || attr->form == DW_FORM_block);
+}
+
+static void
+dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
+ struct dwarf2_cu *cu)
+{
+ if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
+ {
+ struct dwarf2_loclist_baton *baton;
+
+ baton = obstack_alloc (&cu->objfile->objfile_obstack,
+ sizeof (struct dwarf2_loclist_baton));
+ baton->objfile = cu->objfile;
+
+ /* We don't know how long the location list is, but make sure we
+ don't run off the edge of the section. */
+ baton->size = dwarf_loc_size - DW_UNSND (attr);
+ baton->data = dwarf_loc_buffer + DW_UNSND (attr);
+ baton->base_address = cu->header.base_address;
+ if (cu->header.base_known == 0)
+ complaint (&symfile_complaints,
+ "Location list used without specifying the CU base address.");
+
+ SYMBOL_OPS (sym) = &dwarf2_loclist_funcs;
+ SYMBOL_LOCATION_BATON (sym) = baton;
+ }
+ else
+ {
+ struct dwarf2_locexpr_baton *baton;
+
+ baton = obstack_alloc (&cu->objfile->objfile_obstack,
+ sizeof (struct dwarf2_locexpr_baton));
+ baton->objfile = cu->objfile;
+
+ if (attr_form_is_block (attr))
+ {
+ /* Note that we're just copying the block's data pointer
+ here, not the actual data. We're still pointing into the
+ dwarf_info_buffer for SYM's objfile; right now we never
+ release that buffer, but when we do clean up properly
+ this may need to change. */
+ baton->size = DW_BLOCK (attr)->size;
+ baton->data = DW_BLOCK (attr)->data;
+ }
+ else
+ {
+ dwarf2_invalid_attrib_class_complaint ("location description",
+ SYMBOL_NATURAL_NAME (sym));
+ baton->size = 0;
+ baton->data = NULL;
+ }
+
+ SYMBOL_OPS (sym) = &dwarf2_locexpr_funcs;
+ SYMBOL_LOCATION_BATON (sym) = baton;
+ }
+}
diff --git a/contrib/gdb/gdb/dwarfread.c b/contrib/gdb/gdb/dwarfread.c
new file mode 100644
index 0000000..c245108
--- /dev/null
+++ b/contrib/gdb/gdb/dwarfread.c
@@ -0,0 +1,3816 @@
+/* DWARF debugging format support for GDB.
+
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004 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. */
+
+/*
+ If you are looking for DWARF-2 support, you are in the wrong file.
+ Go look in dwarf2read.c. This file is for the original DWARF,
+ also known as DWARF-1.
+
+ DWARF-1 is slowly headed for obsoletion.
+
+ In gcc HEAD 2003-11-29 16:28:31 UTC, no targets prefer dwarf-1.
+
+ In gcc 3.3.2, these targets prefer dwarf-1:
+
+ i[34567]86-sequent-ptx4*
+ i[34567]86-sequent-sysv4*
+ mips-sni-sysv4
+ sparc-hal-solaris2*
+
+ In gcc 3.2.2, these targets prefer dwarf-1:
+
+ i[34567]86-dg-dgux*
+ i[34567]86-sequent-ptx4*
+ i[34567]86-sequent-sysv4*
+ m88k-dg-dgux*
+ mips-sni-sysv4
+ sparc-hal-solaris2*
+
+ In gcc 2.95.3, these targets prefer dwarf-1:
+
+ i[34567]86-dg-dgux*
+ i[34567]86-ncr-sysv4*
+ i[34567]86-sequent-ptx4*
+ i[34567]86-sequent-sysv4*
+ i[34567]86-*-osf1*
+ i[34567]86-*-sco3.2v5*
+ i[34567]86-*-sysv4*
+ i860-alliant-*
+ i860-*-sysv4*
+ m68k-atari-sysv4*
+ m68k-cbm-sysv4*
+ m68k-*-sysv4*
+ m88k-dg-dgux*
+ m88k-*-sysv4*
+ mips-sni-sysv4
+ mips-*-gnu*
+ sh-*-elf*
+ sh-*-rtemself*
+ sparc-hal-solaris2*
+ sparc-*-sysv4*
+
+ Some non-gcc compilers produce dwarf-1:
+
+ PR gdb/1179 was from a user with Diab C++ 4.3.
+ Other users have also reported using Diab compilers with dwarf-1.
+ On 2003-06-09 the gdb list received a report from a user
+ with Absoft ProFortran f77 which is dwarf-1.
+
+ -- chastain 2003-12-01
+*/
+
+/*
+
+ 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 "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 <fcntl.h>
+#include "gdb_string.h"
+
+/* 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. */
+
+static void
+bad_die_ref_complaint (int arg1, const char *arg2, int arg3)
+{
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit",
+ arg1, arg2, arg3);
+}
+
+static void
+unknown_attribute_form_complaint (int arg1, const char *arg2, int arg3)
+{
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", arg1, arg2,
+ arg3);
+}
+
+static void
+dup_user_type_definition_complaint (int arg1, const char *arg2)
+{
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", internal error: duplicate user type definition",
+ arg1, arg2);
+}
+
+static void
+bad_array_element_type_complaint (int arg1, const char *arg2, int arg3)
+{
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", arg1,
+ arg2, arg3);
+}
+
+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
+
+/* 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 <dwarf.h> 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)
+
+/* 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 <name>_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;
+
+ /* Kludge to identify register variables */
+
+ unsigned int isreg;
+
+ /* Kludge to identify optimized out variables */
+
+ unsigned int optimized_out;
+
+ /* Kludge to identify basereg references.
+ Nonzero if we have an offset relative to a basereg. */
+
+ unsigned int offreg;
+
+ /* Kludge to identify which base register is it relative to. */
+
+ unsigned int basereg;
+ };
+
+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 */
+
+/* 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_<TYPENAME> 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 void free_utypes (void *);
+
+static int attribute_size (unsigned int);
+
+static CORE_ADDR target_to_host (char *, int, int, struct objfile *);
+
+static void add_enum_psymbol (struct dieinfo *, struct objfile *);
+
+static void handle_producer (char *);
+
+static void read_file_scope (struct dieinfo *, char *, char *,
+ struct objfile *);
+
+static void read_func_scope (struct dieinfo *, char *, char *,
+ struct objfile *);
+
+static void read_lexical_block_scope (struct dieinfo *, char *, char *,
+ struct objfile *);
+
+static void scan_partial_symbols (char *, char *, struct objfile *);
+
+static void scan_compilation_units (char *, char *, file_ptr, file_ptr,
+ struct objfile *);
+
+static void add_partial_symbol (struct dieinfo *, struct objfile *);
+
+static void basicdieinfo (struct dieinfo *, char *, struct objfile *);
+
+static void completedieinfo (struct dieinfo *, struct objfile *);
+
+static void dwarf_psymtab_to_symtab (struct partial_symtab *);
+
+static void psymtab_to_symtab_1 (struct partial_symtab *);
+
+static void read_ofile_symtab (struct partial_symtab *);
+
+static void process_dies (char *, char *, struct objfile *);
+
+static void read_structure_scope (struct dieinfo *, char *, char *,
+ struct objfile *);
+
+static struct type *decode_array_element_type (char *);
+
+static struct type *decode_subscript_data_item (char *, char *);
+
+static void dwarf_read_array_type (struct dieinfo *);
+
+static void read_tag_pointer_type (struct dieinfo *dip);
+
+static void read_tag_string_type (struct dieinfo *dip);
+
+static void read_subroutine_type (struct dieinfo *, char *, char *);
+
+static void read_enumeration (struct dieinfo *, char *, char *,
+ struct objfile *);
+
+static struct type *struct_type (struct dieinfo *, char *, char *,
+ struct objfile *);
+
+static struct type *enum_type (struct dieinfo *, struct objfile *);
+
+static void decode_line_numbers (char *);
+
+static struct type *decode_die_type (struct dieinfo *);
+
+static struct type *decode_mod_fund_type (char *);
+
+static struct type *decode_mod_u_d_type (char *);
+
+static struct type *decode_modified_type (char *, unsigned int, int);
+
+static struct type *decode_fund_type (unsigned int);
+
+static char *create_name (char *, struct obstack *);
+
+static struct type *lookup_utype (DIE_REF);
+
+static struct type *alloc_utype (DIE_REF, struct type *);
+
+static struct symbol *new_symbol (struct dieinfo *, struct objfile *);
+
+static void synthesize_typedef (struct dieinfo *, struct objfile *,
+ struct type *);
+
+static int locval (struct dieinfo *);
+
+static void set_cu_language (struct dieinfo *);
+
+static struct type *dwarf_fundamental_type (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 (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 (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_MODULA2:
+ cu_language = language_m2;
+ break;
+ case LANG_FORTRAN77:
+ case LANG_FORTRAN90:
+ cu_language = language_fortran;
+ break;
+ case LANG_ADA83:
+ case LANG_COBOL74:
+ case LANG_COBOL85:
+ 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,
+ 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 (struct objfile *objfile, 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_bread (dbbase, dbsize, abfd) != dbsize))
+ {
+ xfree (dbbase);
+ error ("can't read DWARF data from '%s'", bfd_get_filename (abfd));
+ }
+ back_to = make_cleanup (xfree, 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 = objfile->section_offsets;
+ baseaddr = ANOFFSET (objfile->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 (struct dieinfo *dip, char *thisdie, char *enddie,
+ struct objfile *objfile)
+{
+ 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)
+{
+ struct type *type = NULL;
+ int utypeidx;
+
+ utypeidx = (die_ref - dbroff) / 4;
+ if ((utypeidx < 0) || (utypeidx >= numutypes))
+ {
+ bad_die_ref_complaint (DIE_ID, DIE_NAME, die_ref);
+ }
+ 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 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);
+ bad_die_ref_complaint (DIE_ID, DIE_NAME, die_ref);
+ }
+ else if (*typep != NULL)
+ {
+ utypep = *typep;
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", internal error: duplicate 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 (void *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 (void *dummy)
+{
+ xfree (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 (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)
+ {
+ type = lookup_utype (dip->at_user_def_type);
+ if (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_VOID);
+ }
+ 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 (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;
+
+ type = lookup_utype (dip->die_ref);
+ if (type == 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;
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", missing class, structure, or union 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->objfile_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:
+ /* Static fields can be either TAG_global_variable (GCC) or else
+ TAG_member with no location (Diab). We could treat the latter like
+ the former... but since we don't support the former, just avoid
+ crashing on the latter for now. */
+ if (mbr.at_location == NULL)
+ break;
+
+ /* 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->objfile_obstack);
+ FIELD_TYPE (list->field) = decode_die_type (&mbr);
+ FIELD_BITPOS (list->field) = 8 * locval (&mbr);
+ FIELD_STATIC_KIND (list->field) = 0;
+ /* Handle bit fields. */
+ FIELD_BITSIZE (list->field) = 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. */
+ FIELD_BITPOS (list->field) += 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);
+ }
+ FIELD_BITPOS (list->field) +=
+ 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 (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_STUB (type))
+ {
+ 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 (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;
+ nbytes = attribute_size (attribute);
+ if (nbytes == -1)
+ {
+ bad_array_element_type_complaint (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);
+ typep = lookup_utype (die_ref);
+ if (typep == NULL)
+ {
+ typep = alloc_utype (die_ref, NULL);
+ }
+ break;
+ case AT_mod_u_d_type:
+ typep = decode_mod_u_d_type (scan);
+ break;
+ default:
+ bad_array_element_type_complaint (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 (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. */
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", can't decode 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:
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet",
+ 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:
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", unknown array subscript format %x", 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 (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? */
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", array not row major; not handled correctly",
+ DIE_ID, DIE_NAME);
+ }
+ sub = dip->at_subscr_data;
+ if (sub != 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);
+ utype = lookup_utype (dip->die_ref);
+ if (utype == 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. */
+ dup_user_type_definition_complaint (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 (struct dieinfo *dip)
+{
+ struct type *type;
+ struct type *utype;
+
+ type = decode_die_type (dip);
+ utype = lookup_utype (dip->die_ref);
+ if (utype == 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: Possably a poor assumption */
+ TYPE_LENGTH (utype) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ 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 (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)
+ {
+ dup_user_type_definition_complaint (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 (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. */
+
+ ftype = lookup_utype (dip->die_ref);
+ if (ftype == 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
+ {
+ dup_user_type_definition_complaint (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 (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 domain VAR_DOMAIN 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 (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;
+
+ type = lookup_utype (dip->die_ref);
+ if (type == 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->objfile_obstack,
+ "", "", dip->at_name);
+ }
+ if (dip->at_byte_size != 0)
+ {
+ TYPE_LENGTH (type) = dip->at_byte_size;
+ }
+ scan = dip->at_element_list;
+ if (scan != 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;
+ FIELD_TYPE (list->field) = NULL;
+ FIELD_BITSIZE (list->field) = 0;
+ FIELD_STATIC_KIND (list->field) = 0;
+ FIELD_BITPOS (list->field) =
+ 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->objfile_obstack);
+ scan += strlen (scan) + 1;
+ nfields++;
+ /* Handcraft a new symbol for this enum member. */
+ sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (sym) = create_name (list->field.name,
+ &objfile->objfile_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_VALUE (sym) = FIELD_BITPOS (list->field);
+ 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->objfile_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 (struct dieinfo *dip, char *thisdie, char *enddie,
+ struct objfile *objfile)
+{
+ 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)
+ {
+ complaint (&symfile_complaints, "DIE @ 0x%x, AT_name tag missing",
+ 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;
+ }
+ 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 (char *producer)
+{
+
+ /* If this compilation unit was compiled with g++ or gcc, then set the
+ processing_gcc_compilation flag. */
+
+ if (DEPRECATED_STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER)))
+ {
+ char version = producer[strlen (GCC_PRODUCER)];
+ processing_gcc_compilation = (version == '2' ? 2 : 1);
+ }
+ else
+ {
+ processing_gcc_compilation =
+ strncmp (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)) == 0;
+ }
+
+ /* 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 (DEPRECATED_STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)))
+ {
+#if 0
+ /* For now, stay with AUTO_DEMANGLING for g++ output, as we don't
+ know whether it will use the old style or v3 mangling. */
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+#endif
+ }
+ else if (DEPRECATED_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 (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.deprecated_entry_file_lowpc = dip->at_low_pc;
+ objfile->ei.deprecated_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);
+ record_debugformat ("DWARF 1");
+ 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 (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;
+ }
+ /* I think that these are always text, not data, addresses. */
+ di.at_low_pc = SMASH_TEXT_ADDRESS (di.at_low_pc);
+ di.at_high_pc = SMASH_TEXT_ADDRESS (di.at_high_pc);
+ 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:
+
+ <table length><base address><source statement entry>
+ 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:
+
+ <line number><statement position><address delta>
+ 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 (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 (struct dieinfo *dip)
+
+ 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 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 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 (struct dieinfo *dip)
+{
+ unsigned short nbytes;
+ unsigned short locsize;
+ auto long stack[64];
+ int stacki;
+ char *loc;
+ char *end;
+ int loc_atom_code;
+ int loc_value_size;
+
+ loc = dip->at_location;
+ 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;
+ dip->isreg = 0;
+ dip->offreg = 0;
+ dip->optimized_out = 1;
+ loc_value_size = TARGET_FT_LONG_SIZE (current_objfile);
+ while (loc < end)
+ {
+ dip->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;
+ dip->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. */
+ dip->offreg = 1;
+ dip->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) */
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%lx not handled",
+ DIE_ID, DIE_NAME, stack[stacki]);
+ break;
+ case OP_DEREF4: /* pop, deref and push 4 bytes (as a long) */
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%lx not handled",
+ 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 (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_bread (dbbase, dbsize, abfd) != dbsize))
+ {
+ xfree (dbbase);
+ error ("can't read DWARF data");
+ }
+ back_to = make_cleanup (xfree, 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_bread (lnsizedata, sizeof (lnsizedata), 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_bread (lnbase, lnsize, abfd) != lnsize))
+ {
+ xfree (lnbase);
+ error ("can't read DWARF line numbers");
+ }
+ make_cleanup (xfree, 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 (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);
+ }
+ 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 (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 (struct dieinfo *dip, struct objfile *objfile)
+{
+ char *scan;
+ char *listend;
+ unsigned short blocksz;
+ int nbytes;
+
+ scan = dip->at_element_list;
+ if (scan != 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_DOMAIN, 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 (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_DOMAIN, 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_DOMAIN, 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_DOMAIN, 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_DOMAIN, 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_DOMAIN, 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_DOMAIN, 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_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ 0, 0, cu_language, objfile);
+ }
+ break;
+ }
+}
+/* *INDENT-OFF* */
+/*
+
+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.
+ */
+/* *INDENT-ON* */
+
+
+
+static void
+scan_partial_symbols (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))
+ {
+ bad_die_ref_complaint (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 (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->objfile_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 (struct dieinfo *dip, struct objfile *objfile)
+{
+ struct symbol *sym = NULL;
+
+ if (dip->at_name != NULL)
+ {
+ sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ OBJSTAT (objfile, n_syms++);
+ memset (sym, 0, sizeof (struct symbol));
+ /* default assumptions */
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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_SET_NAMES (sym, dip->at_name, strlen (dip->at_name), objfile);
+ 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));
+ if (dip->at_prototyped)
+ TYPE_FLAGS (SYMBOL_TYPE (sym)) |= TYPE_FLAG_PROTOTYPED;
+ 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_ADDRESS (sym) = locval (dip);
+ 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)
+ {
+ int loc = locval (dip);
+ if (dip->optimized_out)
+ {
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+ }
+ else if (dip->isreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ }
+ else if (dip->offreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_BASEREG;
+ SYMBOL_BASEREG (sym) = dip->basereg;
+ }
+ else
+ {
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) += baseaddr;
+ }
+ if (SYMBOL_CLASS (sym) == LOC_STATIC)
+ {
+ /* LOC_STATIC address class MUST use SYMBOL_VALUE_ADDRESS,
+ which may store to a bigger location than SYMBOL_VALUE. */
+ SYMBOL_VALUE_ADDRESS (sym) = loc;
+ }
+ else
+ {
+ SYMBOL_VALUE (sym) = loc;
+ }
+ add_symbol_to_list (sym, list_in_scope);
+ }
+ break;
+ case TAG_formal_parameter:
+ if (dip->at_location != NULL)
+ {
+ SYMBOL_VALUE (sym) = locval (dip);
+ }
+ add_symbol_to_list (sym, list_in_scope);
+ if (dip->isreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ }
+ else if (dip->offreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_BASEREG_ARG;
+ SYMBOL_BASEREG (sym) = dip->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_DOMAIN (sym) = STRUCT_DOMAIN;
+ add_symbol_to_list (sym, list_in_scope);
+ break;
+ case TAG_typedef:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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 (struct dieinfo *dip, struct objfile *objfile,
+ struct type *type)
+{
+ struct symbol *sym = NULL;
+
+ if (dip->at_name != NULL)
+ {
+ sym = (struct symbol *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol));
+ OBJSTAT (objfile, n_syms++);
+ memset (sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (sym) = create_name (dip->at_name,
+ &objfile->objfile_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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 (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 (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 (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);
+ typep = lookup_utype (die_ref);
+ if (typep == NULL)
+ {
+ typep = alloc_utype (die_ref, NULL);
+ }
+ break;
+ default:
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)",
+ 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:
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", type modifier 'const' ignored", DIE_ID,
+ DIE_NAME); /* FIXME */
+ break;
+ case MOD_volatile:
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", type modifier 'volatile' ignored",
+ DIE_ID, DIE_NAME); /* FIXME */
+ break;
+ default:
+ if (!(MOD_lo_user <= (unsigned char) modifier))
+#if 0
+/* This part of the test would always be true, and it triggers a compiler
+ warning. */
+ && (unsigned char) modifier <= MOD_hi_user))
+#endif
+ {
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", unknown type modifier %u", 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 (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))
+ {
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x",
+ 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 (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 (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)))
+ {
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", malformed DIE, bad length (%ld bytes)",
+ 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 (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;
+ nbytes = attribute_size (attr);
+ if (nbytes == -1)
+ {
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes",
+ 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:
+ unknown_attribute_form_complaint (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 (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:
+ complaint (&symfile_complaints,
+ "DIE @ 0x%x \"%s\", no bfd support for %d byte data object",
+ 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 (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:
+ unknown_attribute_form_complaint (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 0000000..83a1862
--- /dev/null
+++ b/contrib/gdb/gdb/elfread.c
@@ -0,0 +1,745 @@
+/* Read ELF (Executable and Linking Format) object files for GDB.
+
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004 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"
+
+extern void _initialize_elfread (void);
+
+/* The struct elfinfo is available only during ELF symbol table and
+ psymtab reading. It is destroyed at the completion 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 */
+ };
+
+static void free_elfinfo (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 (bfd *ignore_abfd, asection *sectp, void *eip)
+{
+ struct elfinfo *ei;
+
+ ei = (struct elfinfo *) eip;
+ if (strcmp (sectp->name, ".debug") == 0)
+ {
+ ei->dboffset = sectp->filepos;
+ ei->dbsize = bfd_get_section_size_before_reloc (sectp);
+ }
+ else if (strcmp (sectp->name, ".line") == 0)
+ {
+ ei->lnoffset = sectp->filepos;
+ ei->lnsize = bfd_get_section_size_before_reloc (sectp);
+ }
+ else if (strcmp (sectp->name, ".stab") == 0)
+ {
+ ei->stabsect = sectp;
+ }
+ else if (strcmp (sectp->name, ".stab.index") == 0)
+ {
+ ei->stabindexsect = sectp;
+ }
+ else if (strcmp (sectp->name, ".mdebug") == 0)
+ {
+ ei->mdebugsect = sectp;
+ }
+}
+
+static struct minimal_symbol *
+record_minimal_symbol (char *name, CORE_ADDR address,
+ enum minimal_symbol_type ms_type,
+ asection *bfd_section, struct objfile *objfile)
+{
+ if (ms_type == mst_text || ms_type == mst_file_text)
+ address = SMASH_TEXT_ADDRESS (address);
+
+ return prim_record_minimal_symbol_and_info
+ (name, address, ms_type, NULL, bfd_section->index, bfd_section, objfile);
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ elf_symtab_read -- read the symbol table of an ELF file
+
+ SYNOPSIS
+
+ void elf_symtab_read (struct objfile *objfile, int dynamic)
+
+ DESCRIPTION
+
+ Given an objfile and a flag that specifies whether or not the objfile
+ 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 (struct objfile *objfile, int dynamic)
+{
+ long storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ long number_of_symbols;
+ long i;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr;
+ CORE_ADDR offset;
+ 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 objfile_obstack. */
+ char *filesymname = obsavestring ("", 0, &objfile->objfile_obstack);
+#endif
+ struct dbx_symfile_info *dbx = objfile->sym_stab_info;
+ int stripped = (bfd_get_symcount (objfile->obfd) == 0);
+
+ if (dynamic)
+ {
+ storage_needed = bfd_get_dynamic_symtab_upper_bound (objfile->obfd);
+
+ /* Nothing to be done if there is no dynamic symtab. */
+ if (storage_needed < 0)
+ return;
+ }
+ else
+ {
+ storage_needed = bfd_get_symtab_upper_bound (objfile->obfd);
+ if (storage_needed < 0)
+ error ("Can't read symbols from %s: %s", bfd_get_filename (objfile->obfd),
+ bfd_errmsg (bfd_get_error ()));
+ }
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (xfree, symbol_table);
+ if (dynamic)
+ number_of_symbols = bfd_canonicalize_dynamic_symtab (objfile->obfd,
+ symbol_table);
+ else
+ number_of_symbols = bfd_canonicalize_symtab (objfile->obfd, symbol_table);
+ if (number_of_symbols < 0)
+ error ("Can't read symbols from %s: %s", bfd_get_filename (objfile->obfd),
+ 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;
+ }
+
+ offset = ANOFFSET (objfile->section_offsets, sym->section->index);
+ 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,
+ plus the desired section offset.
+ 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 += offset;
+ msym = record_minimal_symbol
+ ((char *) sym->name, symaddr,
+ mst_solib_trampoline, sym->section, 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->objfile_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 the section offset. */
+ if (sym->section != &bfd_abs_section)
+ {
+ symaddr += offset;
+ }
+ /* 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 addresses
+ 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;
+ }
+
+ /* If it is an Irix dynamic symbol, skip section name
+ symbols, relocate all others by section offset. */
+ if (ms_type != mst_abs)
+ {
+ if (sym->name[0] == '.')
+ continue;
+ symaddr += offset;
+ }
+ }
+ 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 (deleted) 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 | BSF_WEAK))
+ {
+ 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. */
+ int special_local_sect;
+ if (strcmp ("Bbss.bss", sym->name) == 0)
+ special_local_sect = SECT_OFF_BSS (objfile);
+ else if (strcmp ("Ddata.data", sym->name) == 0)
+ special_local_sect = SECT_OFF_DATA (objfile);
+ else if (strcmp ("Drodata.rodata", sym->name) == 0)
+ special_local_sect = SECT_OFF_RODATA (objfile);
+ else
+ special_local_sect = -1;
+ if (special_local_sect >= 0)
+ {
+ /* Found a special local symbol. Allocate a
+ sectinfo, if needed, and fill it in. */
+ if (sectinfo == NULL)
+ {
+ int max_index;
+ size_t size;
+
+ max_index
+ = max (SECT_OFF_BSS (objfile),
+ max (SECT_OFF_DATA (objfile),
+ SECT_OFF_RODATA (objfile)));
+
+ /* max_index is the largest index we'll
+ use into this array, so we must
+ allocate max_index+1 elements for it.
+ However, 'struct stab_section_info'
+ already includes one element, so we
+ need to allocate max_index aadditional
+ elements. */
+ size = (sizeof (struct stab_section_info)
+ + (sizeof (CORE_ADDR)
+ * max_index));
+ sectinfo = (struct stab_section_info *)
+ xmmalloc (objfile->md, size);
+ memset (sectinfo, 0, size);
+ sectinfo->num_sections = max_index;
+ if (filesym == NULL)
+ {
+ complaint (&symfile_complaints,
+ "elf/stab section information %s without a preceding file symbol",
+ sym->name);
+ }
+ else
+ {
+ sectinfo->filename =
+ (char *) filesym->name;
+ }
+ }
+ if (sectinfo->sections[special_local_sect] != 0)
+ complaint (&symfile_complaints,
+ "duplicated elf/stab section information for %s",
+ sectinfo->filename);
+ /* BFD symbols are section relative. */
+ symaddr = sym->value + sym->section->vma;
+ /* Relocate non-absolute symbols by the
+ section offset. */
+ if (sym->section != &bfd_abs_section)
+ symaddr += offset;
+ sectinfo->sections[special_local_sect] = 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. */
+ }
+ msym = record_minimal_symbol
+ ((char *) sym->name, symaddr,
+ ms_type, sym->section, objfile);
+ if (msym)
+ {
+ /* Pass symbol size field in via BFD. FIXME!!! */
+ unsigned long size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+ MSYMBOL_SIZE(msym) = size;
+ }
+#ifdef SOFUN_ADDRESS_MAYBE_MISSING
+ if (msym != NULL)
+ msym->filename = filesymname;
+#endif
+ ELF_MAKE_MSYMBOL_SPECIAL (sym, msym);
+ }
+ }
+ 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 (struct objfile *objfile, 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 ();
+
+ memset ((char *) &ei, 0, sizeof (ei));
+
+ /* Allocate struct to keep track of the symfile */
+ objfile->sym_stab_info = (struct dbx_symfile_info *)
+ xmmalloc (objfile->md, sizeof (struct dbx_symfile_info));
+ memset ((char *) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info));
+ make_cleanup (free_elfinfo, (void *) objfile);
+
+ /* Process the normal ELF symbol table first. This may write some
+ chain of info into the dbx_symfile_info in objfile->sym_stab_info,
+ which can later be used by elfstab_offset_sections. */
+
+ elf_symtab_read (objfile, 0);
+
+ /* Add the dynamic symbols. */
+
+ elf_symtab_read (objfile, 1);
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. The debug readers below this point
+ should not generate new minimal symbols; if they do it's their
+ responsibility to install them. "mdebug" appears to be the only one
+ which will do this. */
+
+ install_minimal_symbols (objfile);
+ do_cleanups (back_to);
+
+ /* Now process debugging information, which is contained in
+ special ELF sections. */
+
+ /* If we are reinitializing, or if we have never loaded syms yet,
+ set table to empty. MAINLINE is cleared so that *_read_psymtab
+ functions do not all also re-initialize the psymbol table. */
+ if (mainline)
+ {
+ init_psymbol_list (objfile, 0);
+ mainline = 0;
+ }
+
+ /* We first have to find them... */
+ bfd_map_over_sections (abfd, elf_locate_sections, (void *) & ei);
+
+ /* ELF debugging information is inserted into the psymtab in the
+ order of least informative first - most informative last. Since
+ the psymtab table is searched `most recent insertion first' this
+ increases the probability that more detailed debug information
+ for a section is found.
+
+ For instance, an object file might contain both .mdebug (XCOFF)
+ and .debug_info (DWARF2) sections then .mdebug is inserted first
+ (searched last) and DWARF2 is inserted last (searched first). If
+ we don't do this then the XCOFF info is found first - for code in
+ an included file XCOFF info is useless. */
+
+ 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);
+ }
+ 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,
+ mainline,
+ ei.stabsect,
+ str_sect->filepos,
+ bfd_section_size (abfd, str_sect));
+ }
+ if (dwarf2_has_info (abfd))
+ {
+ /* DWARF 2 sections */
+ dwarf2_build_psymtabs (objfile, mainline);
+ }
+ else if (ei.dboffset && ei.lnoffset)
+ {
+ /* DWARF sections */
+ dwarf_build_psymtabs (objfile,
+ mainline,
+ ei.dboffset, ei.dbsize,
+ ei.lnoffset, ei.lnsize);
+ }
+
+ /* FIXME: kettenis/20030504: This still needs to be integrated with
+ dwarf2read.c in a better way. */
+ dwarf2_build_frame_info (objfile);
+}
+
+/* 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 (void *objp)
+{
+ struct objfile *objfile = (struct objfile *) objp;
+ struct dbx_symfile_info *dbxinfo = objfile->sym_stab_info;
+ struct stab_section_info *ssi, *nssi;
+
+ ssi = dbxinfo->stab_section_info;
+ while (ssi)
+ {
+ nssi = ssi->next;
+ xmfree (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 (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 (struct objfile *objfile)
+{
+ if (objfile->sym_stab_info != NULL)
+ {
+ xmfree (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 (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;
+}
+
+/* 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 (struct objfile *objfile, struct partial_symtab *pst)
+{
+ char *filename = pst->filename;
+ struct dbx_symfile_info *dbx = 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]
+ && strcmp (filename, maybe->filename) == 0)
+ {
+ /* 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)
+ {
+ complaint (&symfile_complaints,
+ "elf/stab section information questionable for %s", 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->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+ for (i = 0; i < maybe->num_sections; i++)
+ (pst->section_offsets)->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, */
+ complaint (&symfile_complaints,
+ "elf/stab section information missing for %s", 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 */
+ default_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_elfread (void)
+{
+ 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 0000000..b629388
--- /dev/null
+++ b/contrib/gdb/gdb/environ.c
@@ -0,0 +1,186 @@
+/* environ.c -- library for manipulating environments for GNU.
+
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 2000,
+ 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#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"
+
+
+/* Return a new environment object. */
+
+struct environ *
+make_environ (void)
+{
+ 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 (struct environ *e)
+{
+ char **vector = e->vector;
+
+ while (*vector)
+ xfree (*vector++);
+
+ xfree (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 (struct environ *e)
+{
+ extern char **environ;
+ 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)
+ {
+ int len = strlen (e->vector[i]);
+ 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 (struct environ *e)
+{
+ return e->vector;
+}
+
+/* Return the value in environment E of variable VAR. */
+
+char *
+get_in_environ (const struct environ *e, const char *var)
+{
+ int len = strlen (var);
+ char **vector = e->vector;
+ char *s;
+
+ for (; (s = *vector) != NULL; vector++)
+ if (strncmp (s, var, len) == 0 && s[len] == '=')
+ return &s[len + 1];
+
+ return 0;
+}
+
+/* Store the value in E of VAR as VALUE. */
+
+void
+set_in_environ (struct environ *e, const char *var, const char *value)
+{
+ int i;
+ int len = strlen (var);
+ char **vector = e->vector;
+ char *s;
+
+ for (i = 0; (s = vector[i]) != NULL; i++)
+ if (strncmp (s, var, len) == 0 && 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
+ xfree (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 (struct environ *e, char *var)
+{
+ int len = strlen (var);
+ char **vector = e->vector;
+ char *s;
+
+ for (; (s = *vector) != NULL; vector++)
+ {
+ if (DEPRECATED_STREQN (s, var, len) && s[len] == '=')
+ {
+ xfree (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 0000000..1aa1394
--- /dev/null
+++ b/contrib/gdb/gdb/environ.h
@@ -0,0 +1,51 @@
+/* Header for environment manipulation library.
+ Copyright 1989, 1992, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#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 (void);
+
+extern void free_environ (struct environ *);
+
+extern void init_environ (struct environ *);
+
+extern char *get_in_environ (const struct environ *, const char *);
+
+extern void set_in_environ (struct environ *, const char *, const char *);
+
+extern void unset_in_environ (struct environ *, char *);
+
+extern char **environ_vector (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 0000000..452aeb7
--- /dev/null
+++ b/contrib/gdb/gdb/eval.c
@@ -0,0 +1,2275 @@
+/* Evaluate expressions for GDB.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "language.h" /* For CAST_IS_CONVERSION */
+#include "f-lang.h" /* for array bound stuff */
+#include "cp-abi.h"
+#include "infcall.h"
+#include "objc-lang.h"
+#include "block.h"
+#include "parser-defs.h"
+
+/* Defined in symtab.c */
+extern int hp_som_som_object_present;
+
+/* This is defined in valops.c */
+extern int overload_resolution;
+
+/* JYG: lookup rtti type of STRUCTOP_PTR when this is set to continue
+ on with successful lookup for member/method of the rtti type. */
+extern int objectprint;
+
+/* Prototypes for local functions. */
+
+static struct value *evaluate_subexp_for_sizeof (struct expression *, int *);
+
+static struct value *evaluate_subexp_for_address (struct expression *,
+ int *, enum noside);
+
+static struct value *evaluate_subexp (struct type *, struct expression *,
+ int *, enum noside);
+
+static char *get_label (struct expression *, int *);
+
+static struct value *evaluate_struct_tuple (struct value *,
+ struct expression *, int *,
+ enum noside, int);
+
+static LONGEST init_array_element (struct value *, struct value *,
+ struct expression *, int *, enum noside,
+ LONGEST, LONGEST);
+
+static struct value *
+evaluate_subexp (struct type *expect_type, struct expression *exp,
+ int *pos, enum noside noside)
+{
+ return (*exp->language_defn->la_exp_desc->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 (char *exp)
+{
+ struct expression *expr = parse_expression (exp);
+ CORE_ADDR addr;
+ struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_address (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 (char **expptr)
+{
+ struct expression *expr = parse_exp_1 (expptr, (struct block *) 0, 0);
+ CORE_ADDR addr;
+ struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_address (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return addr;
+}
+
+/* Like parse_and_eval_address, but treats the value of the expression
+ as an integer, not an address, returns a LONGEST, not a CORE_ADDR */
+LONGEST
+parse_and_eval_long (char *exp)
+{
+ struct expression *expr = parse_expression (exp);
+ LONGEST retval;
+ struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ retval = value_as_long (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return (retval);
+}
+
+struct value *
+parse_and_eval (char *exp)
+{
+ struct expression *expr = parse_expression (exp);
+ struct value *val;
+ 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. */
+
+struct value *
+parse_to_comma_and_eval (char **expp)
+{
+ struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1);
+ struct value *val;
+ 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. */
+
+struct value *
+evaluate_expression (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. */
+
+struct value *
+evaluate_type (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 (struct expression *exp, int *pos)
+{
+ if (exp->elts[*pos].opcode == OP_LABELED)
+ {
+ int pc = (*pos)++;
+ char *name = &exp->elts[pc + 2].string;
+ int tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ return name;
+ }
+ else
+ return NULL;
+}
+
+/* This function evaluates tuples (in (the deleted) Chill) or
+ brace-initializers (in C/C++) for structure types. */
+
+static struct value *
+evaluate_struct_tuple (struct value *struct_val,
+ struct expression *exp,
+ int *pos, enum noside noside, int nargs)
+{
+ struct type *struct_type = check_typedef (VALUE_TYPE (struct_val));
+ struct type *substruct_type = struct_type;
+ struct type *field_type;
+ int fieldno = -1;
+ int variantno = -1;
+ int subfieldno = -1;
+ while (--nargs >= 0)
+ {
+ int pc = *pos;
+ struct value *val = NULL;
+ int nlabels = 0;
+ int bitpos, bitsize;
+ 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 && DEPRECATED_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 (DEPRECATED_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
+ (the deleted) 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 (struct value *array, struct value *element,
+ struct expression *exp, int *pos,
+ enum noside noside, LONGEST low_bound, LONGEST high_bound)
+{
+ 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;
+}
+
+struct value *
+evaluate_subexp_standard (struct type *expect_type,
+ struct expression *exp, int *pos,
+ enum noside noside)
+{
+ enum exp_opcode op;
+ int tem, tem2, tem3;
+ int pc, pc2 = 0, oldpos;
+ struct value *arg1 = NULL;
+ struct value *arg2 = NULL;
+ struct value *arg3;
+ struct type *type;
+ int nargs;
+ struct value **argvec;
+ int upper, lower, retcode;
+ int code;
+ int ix;
+ long mem_offset;
+ struct type **arg_types;
+ int save_pos1;
+
+ 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_aggregate_elt (exp->elts[pc + 1].type,
+ &exp->elts[pc + 3].string,
+ noside);
+ 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;
+
+ /* JYG: We used to just return value_zero of the symbol type
+ if we're asked to avoid side effects. Otherwise we return
+ value_of_variable (...). However I'm not sure if
+ value_of_variable () has any side effect.
+ We need a full value object returned here for whatis_exp ()
+ to call evaluate_type () and then pass the full value to
+ value_rtti_target_type () if we are dealing with a pointer
+ or reference to a base class and print object is on. */
+
+ 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:
+ {
+ int regno = longest_to_int (exp->elts[pc + 1].longconst);
+ struct value *val = value_of_register (regno, get_selected_frame ());
+ (*pos) += 2;
+ if (val == NULL)
+ error ("Value of register %s not available.",
+ frame_map_regnum_to_name (get_selected_frame (), regno));
+ else
+ return val;
+ }
+ 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_OBJC_NSSTRING: /* Objective C Foundation Class NSString constant. */
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ if (noside == EVAL_SKIP)
+ {
+ goto nosideret;
+ }
+ return (struct value *) value_nsstring (&exp->elts[pc + 2].string, tem + 1);
+
+ case OP_BITSTRING:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos)
+ += 3 + BYTES_TO_EXP_ELEM ((tem + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_bitstring (&exp->elts[pc + 2].string, tem);
+ 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)
+ {
+ struct value *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);
+ struct value *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;)
+ {
+ struct value *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
+ {
+ if (index > high_bound)
+ /* to avoid memory corruption */
+ error ("Too many array elements");
+ 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)
+ {
+ struct value *set = allocate_value (expect_type);
+ char *valaddr = VALUE_CONTENTS_RAW (set);
+ struct type *element_type = TYPE_INDEX_TYPE (type);
+ struct type *check_type = element_type;
+ LONGEST low_bound, high_bound;
+
+ /* get targettype of elementtype */
+ while (TYPE_CODE (check_type) == TYPE_CODE_RANGE ||
+ TYPE_CODE (check_type) == TYPE_CODE_TYPEDEF)
+ check_type = TYPE_TARGET_TYPE (check_type);
+
+ 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;
+ struct type *range_low_type, *range_high_type;
+ struct value *elem_val;
+ if (exp->elts[*pos].opcode == BINOP_RANGE)
+ {
+ (*pos)++;
+ elem_val = evaluate_subexp (element_type, exp, pos, noside);
+ range_low_type = VALUE_TYPE (elem_val);
+ range_low = value_as_long (elem_val);
+ elem_val = evaluate_subexp (element_type, exp, pos, noside);
+ range_high_type = VALUE_TYPE (elem_val);
+ range_high = value_as_long (elem_val);
+ }
+ else
+ {
+ elem_val = evaluate_subexp (element_type, exp, pos, noside);
+ range_low_type = range_high_type = VALUE_TYPE (elem_val);
+ range_low = range_high = value_as_long (elem_val);
+ }
+ /* check types of elements to avoid mixture of elements from
+ different types. Also check if type of element is "compatible"
+ with element type of powerset */
+ if (TYPE_CODE (range_low_type) == TYPE_CODE_RANGE)
+ range_low_type = TYPE_TARGET_TYPE (range_low_type);
+ if (TYPE_CODE (range_high_type) == TYPE_CODE_RANGE)
+ range_high_type = TYPE_TARGET_TYPE (range_high_type);
+ if ((TYPE_CODE (range_low_type) != TYPE_CODE (range_high_type)) ||
+ (TYPE_CODE (range_low_type) == TYPE_CODE_ENUM &&
+ (range_low_type != range_high_type)))
+ /* different element modes */
+ error ("POWERSET tuple elements of different mode");
+ if ((TYPE_CODE (check_type) != TYPE_CODE (range_low_type)) ||
+ (TYPE_CODE (check_type) == TYPE_CODE_ENUM &&
+ range_low_type != check_type))
+ error ("incompatible POWERSET tuple elements");
+ 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 = (struct value **) alloca (sizeof (struct value *) * 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:
+ {
+ struct value *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:
+ {
+ struct value *array = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ int lowbound
+ = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+ int length
+ = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+ return value_slice (array, lowbound, length);
+ }
+
+ case TERNOP_COND:
+ /* Skip third and second args to evaluate the first one. */
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ 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_OBJC_SELECTOR:
+ { /* Objective C @selector operator. */
+ char *sel = &exp->elts[pc + 2].string;
+ int len = longest_to_int (exp->elts[pc + 1].longconst);
+
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (len + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (sel[len] != 0)
+ sel[len] = 0; /* Make sure it's terminated. */
+ return value_from_longest (lookup_pointer_type (builtin_type_void),
+ lookup_child_selector (sel));
+ }
+
+ case OP_OBJC_MSGCALL:
+ { /* Objective C message (method) call. */
+
+ static CORE_ADDR responds_selector = 0;
+ static CORE_ADDR method_selector = 0;
+
+ CORE_ADDR selector = 0;
+
+ int using_gcc = 0;
+ int struct_return = 0;
+ int sub_no_side = 0;
+
+ static struct value *msg_send = NULL;
+ static struct value *msg_send_stret = NULL;
+ static int gnu_runtime = 0;
+
+ struct value *target = NULL;
+ struct value *method = NULL;
+ struct value *called_method = NULL;
+
+ struct type *selector_type = NULL;
+
+ struct value *ret = NULL;
+ CORE_ADDR addr = 0;
+
+ selector = exp->elts[pc + 1].longconst;
+ nargs = exp->elts[pc + 2].longconst;
+ argvec = (struct value **) alloca (sizeof (struct value *)
+ * (nargs + 5));
+
+ (*pos) += 3;
+
+ selector_type = lookup_pointer_type (builtin_type_void);
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ sub_no_side = EVAL_NORMAL;
+ else
+ sub_no_side = noside;
+
+ target = evaluate_subexp (selector_type, exp, pos, sub_no_side);
+
+ if (value_as_long (target) == 0)
+ return value_from_longest (builtin_type_long, 0);
+
+ if (lookup_minimal_symbol ("objc_msg_lookup", 0, 0))
+ gnu_runtime = 1;
+
+ /* Find the method dispatch (Apple runtime) or method lookup
+ (GNU runtime) function for Objective-C. These will be used
+ to lookup the symbol information for the method. If we
+ can't find any symbol information, then we'll use these to
+ call the method, otherwise we can call the method
+ directly. The msg_send_stret function is used in the special
+ case of a method that returns a structure (Apple runtime
+ only). */
+ if (gnu_runtime)
+ {
+ struct type *type;
+ type = lookup_pointer_type (builtin_type_void);
+ type = lookup_function_type (type);
+ type = lookup_pointer_type (type);
+ type = lookup_function_type (type);
+ type = lookup_pointer_type (type);
+
+ msg_send = find_function_in_inferior ("objc_msg_lookup");
+ msg_send_stret = find_function_in_inferior ("objc_msg_lookup");
+
+ msg_send = value_from_pointer (type, value_as_address (msg_send));
+ msg_send_stret = value_from_pointer (type,
+ value_as_address (msg_send_stret));
+ }
+ else
+ {
+ msg_send = find_function_in_inferior ("objc_msgSend");
+ /* Special dispatcher for methods returning structs */
+ msg_send_stret = find_function_in_inferior ("objc_msgSend_stret");
+ }
+
+ /* Verify the target object responds to this method. The
+ standard top-level 'Object' class uses a different name for
+ the verification method than the non-standard, but more
+ often used, 'NSObject' class. Make sure we check for both. */
+
+ responds_selector = lookup_child_selector ("respondsToSelector:");
+ if (responds_selector == 0)
+ responds_selector = lookup_child_selector ("respondsTo:");
+
+ if (responds_selector == 0)
+ error ("no 'respondsTo:' or 'respondsToSelector:' method");
+
+ method_selector = lookup_child_selector ("methodForSelector:");
+ if (method_selector == 0)
+ method_selector = lookup_child_selector ("methodFor:");
+
+ if (method_selector == 0)
+ error ("no 'methodFor:' or 'methodForSelector:' method");
+
+ /* Call the verification method, to make sure that the target
+ class implements the desired method. */
+
+ argvec[0] = msg_send;
+ argvec[1] = target;
+ argvec[2] = value_from_longest (builtin_type_long, responds_selector);
+ argvec[3] = value_from_longest (builtin_type_long, selector);
+ argvec[4] = 0;
+
+ ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+ if (gnu_runtime)
+ {
+ /* Function objc_msg_lookup returns a pointer. */
+ argvec[0] = ret;
+ ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+ }
+ if (value_as_long (ret) == 0)
+ error ("Target does not respond to this message selector.");
+
+ /* Call "methodForSelector:" method, to get the address of a
+ function method that implements this selector for this
+ class. If we can find a symbol at that address, then we
+ know the return type, parameter types etc. (that's a good
+ thing). */
+
+ argvec[0] = msg_send;
+ argvec[1] = target;
+ argvec[2] = value_from_longest (builtin_type_long, method_selector);
+ argvec[3] = value_from_longest (builtin_type_long, selector);
+ argvec[4] = 0;
+
+ ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+ if (gnu_runtime)
+ {
+ argvec[0] = ret;
+ ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+ }
+
+ /* ret should now be the selector. */
+
+ addr = value_as_long (ret);
+ if (addr)
+ {
+ struct symbol *sym = NULL;
+ /* Is it a high_level symbol? */
+
+ sym = find_pc_function (addr);
+ if (sym != NULL)
+ method = value_of_variable (sym, 0);
+ }
+
+ /* If we found a method with symbol information, check to see
+ if it returns a struct. Otherwise assume it doesn't. */
+
+ if (method)
+ {
+ struct block *b;
+ CORE_ADDR funaddr;
+ struct type *value_type;
+
+ funaddr = find_function_addr (method, &value_type);
+
+ b = block_for_pc (funaddr);
+
+ /* If compiled without -g, assume GCC 2. */
+ using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
+
+ CHECK_TYPEDEF (value_type);
+
+ if ((value_type == NULL)
+ || (TYPE_CODE(value_type) == TYPE_CODE_ERROR))
+ {
+ if (expect_type != NULL)
+ value_type = expect_type;
+ }
+
+ struct_return = using_struct_return (value_type, using_gcc);
+ }
+ else if (expect_type != NULL)
+ {
+ struct_return = using_struct_return (check_typedef (expect_type), using_gcc);
+ }
+
+ /* Found a function symbol. Now we will substitute its
+ value in place of the message dispatcher (obj_msgSend),
+ so that we call the method directly instead of thru
+ the dispatcher. The main reason for doing this is that
+ we can now evaluate the return value and parameter values
+ according to their known data types, in case we need to
+ do things like promotion, dereferencing, special handling
+ of structs and doubles, etc.
+
+ We want to use the type signature of 'method', but still
+ jump to objc_msgSend() or objc_msgSend_stret() to better
+ mimic the behavior of the runtime. */
+
+ if (method)
+ {
+ if (TYPE_CODE (VALUE_TYPE (method)) != TYPE_CODE_FUNC)
+ error ("method address has symbol information with non-function type; skipping");
+ if (struct_return)
+ VALUE_ADDRESS (method) = value_as_address (msg_send_stret);
+ else
+ VALUE_ADDRESS (method) = value_as_address (msg_send);
+ called_method = method;
+ }
+ else
+ {
+ if (struct_return)
+ called_method = msg_send_stret;
+ else
+ called_method = msg_send;
+ }
+
+ 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 *type = VALUE_TYPE (called_method);
+ if (type && TYPE_CODE (type) == TYPE_CODE_PTR)
+ type = TYPE_TARGET_TYPE (type);
+ type = TYPE_TARGET_TYPE (type);
+
+ if (type)
+ {
+ if ((TYPE_CODE (type) == TYPE_CODE_ERROR) && expect_type)
+ return allocate_value (expect_type);
+ else
+ return allocate_value (type);
+ }
+ else
+ error ("Expression of type other than \"method returning ...\" used as a method");
+ }
+
+ /* Now depending on whether we found a symbol for the method,
+ we will either call the runtime dispatcher or the method
+ directly. */
+
+ argvec[0] = called_method;
+ argvec[1] = target;
+ argvec[2] = value_from_longest (builtin_type_long, selector);
+ /* User-supplied arguments. */
+ for (tem = 0; tem < nargs; tem++)
+ argvec[tem + 3] = evaluate_subexp_with_coercion (exp, pos, noside);
+ argvec[tem + 3] = 0;
+
+ if (gnu_runtime && (method != NULL))
+ {
+ /* Function objc_msg_lookup returns a pointer. */
+ VALUE_TYPE (argvec[0]) = lookup_function_type
+ (lookup_pointer_type (VALUE_TYPE (argvec[0])));
+ argvec[0] = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
+ }
+
+ ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
+ return ret;
+ }
+ break;
+
+ 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 = (struct value **) alloca (sizeof (struct value *) * (nargs + 3));
+ if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+ {
+ LONGEST fnptr;
+
+ /* 1997-08-01 Currently we do not support function invocation
+ via pointers-to-methods with HP aCC. Pointer does not point
+ to the function, but possibly to some thunk. */
+ if (hp_som_som_object_present)
+ {
+ error ("Not implemented: function invocation through pointer to method with HP aCC");
+ }
+
+ 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)
+ {
+ struct value *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
+ {
+ /* Non-method function call */
+ save_pos1 = *pos;
+ 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++)
+ {
+ /* pai: FIXME This seems to be coercing arguments before
+ * overload resolution has been done! */
+ argvec[tem] = evaluate_subexp (TYPE_FIELD_TYPE (type, tem - 1),
+ exp, pos, noside);
+ }
+ }
+ }
+
+ /* Evaluate arguments */
+ 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;
+ char tstr[256];
+
+ /* Method invocation : stuff "this" as first parameter */
+ argvec[1] = arg2;
+ /* Name of method from expression */
+ strcpy (tstr, &exp->elts[pc2 + 2].string);
+
+ if (overload_resolution && (exp->language_defn->la_language == language_cplus))
+ {
+ /* Language is C++, do some overload resolution before evaluation */
+ struct value *valp = NULL;
+
+ /* Prepare list of argument types for overload resolution */
+ arg_types = (struct type **) alloca (nargs * (sizeof (struct type *)));
+ for (ix = 1; ix <= nargs; ix++)
+ arg_types[ix - 1] = VALUE_TYPE (argvec[ix]);
+
+ (void) find_overload_match (arg_types, nargs, tstr,
+ 1 /* method */ , 0 /* strict match */ ,
+ &arg2 /* the object */ , NULL,
+ &valp, NULL, &static_memfuncp);
+
+
+ argvec[1] = arg2; /* the ``this'' pointer */
+ argvec[0] = valp; /* use the method found after overload resolution */
+ }
+ else
+ /* Non-C++ case -- or no overload resolution */
+ {
+ struct value *temp = arg2;
+ argvec[0] = value_struct_elt (&temp, argvec + 1, tstr,
+ &static_memfuncp,
+ op == STRUCTOP_STRUCT
+ ? "structure" : "structure pointer");
+ /* value_struct_elt updates temp with the correct value
+ of the ``this'' pointer if necessary, so modify argvec[1] to
+ reflect any ``this'' changes. */
+ arg2 = value_from_longest (lookup_pointer_type(VALUE_TYPE (temp)),
+ VALUE_ADDRESS (temp) + VALUE_OFFSET (temp)
+ + VALUE_EMBEDDED_OFFSET (temp));
+ argvec[1] = arg2; /* the ``this'' pointer */
+ }
+
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ nargs--;
+ argvec++;
+ }
+ }
+ else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+ {
+ argvec[1] = arg2;
+ argvec[0] = arg1;
+ }
+ else if (op == OP_VAR_VALUE)
+ {
+ /* Non-member function being called */
+ /* fn: This can only be done for C++ functions. A C-style function
+ in a C++ program, for instance, does not have the fields that
+ are expected here */
+
+ if (overload_resolution && (exp->language_defn->la_language == language_cplus))
+ {
+ /* Language is C++, do some overload resolution before evaluation */
+ struct symbol *symp;
+
+ /* Prepare list of argument types for overload resolution */
+ arg_types = (struct type **) alloca (nargs * (sizeof (struct type *)));
+ for (ix = 1; ix <= nargs; ix++)
+ arg_types[ix - 1] = VALUE_TYPE (argvec[ix]);
+
+ (void) find_overload_match (arg_types, nargs, NULL /* no need for name */ ,
+ 0 /* not method */ , 0 /* strict match */ ,
+ NULL, exp->elts[save_pos1+2].symbol /* the function */ ,
+ NULL, &symp, NULL);
+
+ /* Now fix the expression being evaluated */
+ exp->elts[save_pos1+2].symbol = symp;
+ argvec[0] = evaluate_subexp_with_coercion (exp, &save_pos1, noside);
+ }
+ else
+ {
+ /* Not C++, or no overload resolution allowed */
+ /* nothing to be done; argvec already correctly set up */
+ }
+ }
+ else
+ {
+ /* It is probably a C-style function */
+ /* nothing to be done; argvec already correctly set up */
+ }
+
+ do_call_it:
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (argvec[0] == NULL)
+ error ("Cannot evaluate function -- may be inlined");
+ 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);
+ /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve */
+
+ 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 = (struct value **) alloca (sizeof (struct value *) * (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
+ {
+ struct value *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;
+
+ /* JYG: if print object is on we need to replace the base type
+ with rtti type in order to continue on with successful
+ lookup of member / method only available in the rtti type. */
+ {
+ struct type *type = VALUE_TYPE (arg1);
+ struct type *real_type;
+ int full, top, using_enc;
+
+ if (objectprint && TYPE_TARGET_TYPE(type) &&
+ (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
+ {
+ real_type = value_rtti_target_type (arg1, &full, &top, &using_enc);
+ if (real_type)
+ {
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ real_type = lookup_pointer_type (real_type);
+ else
+ real_type = lookup_reference_type (real_type);
+
+ arg1 = value_cast (real_type, arg1);
+ }
+ }
+ }
+
+ 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
+ {
+ struct value *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);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ /* With HP aCC, pointers to methods do not point to the function code */
+ if (hp_som_som_object_present &&
+ (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR) &&
+ (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) == TYPE_CODE_METHOD))
+ error ("Pointers to methods not supported with HP aCC"); /* 1997-08-19 */
+
+ mem_offset = value_as_long (arg2);
+ goto handle_pointer_to_member;
+
+ case STRUCTOP_MPTR:
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ /* With HP aCC, pointers to methods do not point to the function code */
+ if (hp_som_som_object_present &&
+ (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR) &&
+ (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) == TYPE_CODE_METHOD))
+ error ("Pointers to methods not supported with HP aCC"); /* 1997-08-19 */
+
+ mem_offset = value_as_long (arg2);
+
+ handle_pointer_to_member:
+ /* HP aCC generates offsets that have bit #29 set; turn it off to get
+ a real offset to the member. */
+ if (hp_som_som_object_present)
+ {
+ if (!mem_offset) /* no bias -> really null */
+ error ("Attempted dereference of null pointer-to-member");
+ mem_offset &= ~0x20000000;
+ }
+ 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_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ value_as_long (arg1) + mem_offset);
+ 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, noside);
+ 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);
+
+ /* Do special stuff for HP aCC pointers to members */
+ if (hp_som_som_object_present)
+ {
+ /* 1997-08-19 Can't assign HP aCC pointers to methods. No details of
+ the implementation yet; but the pointer appears to point to a code
+ sequence (thunk) in memory -- in any case it is *not* the address
+ of the function as it would be in a naive implementation. */
+ if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) &&
+ (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_METHOD))
+ error ("Assignment to pointers to methods not implemented with HP aCC");
+
+ /* HP aCC pointers to data members require a constant bias */
+ if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) &&
+ (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_MEMBER))
+ {
+ unsigned int *ptr = (unsigned int *) VALUE_CONTENTS (arg2); /* forces evaluation */
+ *ptr |= 0x20000000; /* set 29th bit */
+ }
+ }
+
+ 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, noside);
+ 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, noside);
+ 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, noside);
+ 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, noside);
+ 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, noside);
+ 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 (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+ else
+ {
+ /* If the user attempts to subscript something that is not an
+ array or pointer type (like a plain int variable for example),
+ then report this as an error. */
+
+ COERCE_REF (arg1);
+ type = check_typedef (VALUE_TYPE (arg1));
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY
+ && TYPE_CODE (type) != TYPE_CODE_PTR)
+ {
+ if (TYPE_NAME (type))
+ error ("cannot subscript something of type `%s'",
+ TYPE_NAME (type));
+ else
+ error ("cannot subscript requested type");
+ }
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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;
+ type = check_typedef (VALUE_TYPE (arg2));
+ if (TYPE_CODE (type) != 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, noside);
+ 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, noside);
+ 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, noside);
+ else
+ return value_from_longest (LA_BOOL_TYPE,
+ (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 ((TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) &&
+ ((TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_METHOD) ||
+ (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_MEMBER)))
+ error ("Attempt to dereference pointer to member without an object");
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (unop_user_defined_p (op, arg1))
+ return value_x_unop (arg1, op, noside);
+ else 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 (NULL_TYPE, exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+ else
+ {
+ struct value *retvalp = evaluate_subexp_for_address (exp, pos, noside);
+ /* If HP aCC object, use bias for pointers to members */
+ if (hp_som_som_object_present &&
+ (TYPE_CODE (VALUE_TYPE (retvalp)) == TYPE_CODE_PTR) &&
+ (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (retvalp))) == TYPE_CODE_MEMBER))
+ {
+ unsigned int *ptr = (unsigned int *) VALUE_CONTENTS (retvalp); /* forces evaluation */
+ *ptr |= 0x20000000; /* set 29th bit */
+ }
+ return retvalp;
+ }
+
+ 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_address (arg1),
+ NULL);
+
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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, noside);
+ }
+ 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_OBJC_SELF:
+ (*pos) += 1;
+ return value_of_local ("self", 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; 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 struct value *
+evaluate_subexp_for_address (struct expression *exp, int *pos,
+ enum noside noside)
+{
+ enum exp_opcode op;
+ 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)
+ {
+ struct value *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.
+
+ */
+
+struct value *
+evaluate_subexp_with_coercion (struct expression *exp,
+ int *pos, enum noside noside)
+{
+ enum exp_opcode op;
+ int pc;
+ struct value *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 (check_typedef (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 struct value *
+evaluate_subexp_for_sizeof (struct expression *exp, int *pos)
+{
+ enum exp_opcode op;
+ int pc;
+ struct type *type;
+ struct value *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));
+ if (TYPE_CODE (type) != TYPE_CODE_PTR
+ && TYPE_CODE (type) != TYPE_CODE_REF
+ && TYPE_CODE (type) != TYPE_CODE_ARRAY)
+ error ("Attempt to take contents of a non-pointer value.");
+ 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 (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 (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/event-loop.c b/contrib/gdb/gdb/event-loop.c
new file mode 100644
index 0000000..c8d12f9
--- /dev/null
+++ b/contrib/gdb/gdb/event-loop.c
@@ -0,0 +1,1158 @@
+/* Event loop machinery for GDB, the GNU debugger.
+ Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "event-loop.h"
+#include "event-top.h"
+
+#ifdef HAVE_POLL
+#if defined (HAVE_POLL_H)
+#include <poll.h>
+#elif defined (HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+#endif
+
+#include <sys/types.h>
+#include "gdb_string.h"
+#include <errno.h>
+#include <sys/time.h>
+
+typedef struct gdb_event gdb_event;
+typedef void (event_handler_func) (int);
+
+/* Event for the GDB event system. Events are queued by calling
+ async_queue_event and serviced later on by gdb_do_one_event. An
+ event can be, for instance, a file descriptor becoming ready to be
+ read. Servicing an event simply means that the procedure PROC will
+ be called. We have 2 queues, one for file handlers that we listen
+ to in the event loop, and one for the file handlers+events that are
+ ready. The procedure PROC associated with each event is always the
+ same (handle_file_event). Its duty is to invoke the handler
+ associated with the file descriptor whose state change generated
+ the event, plus doing other cleanups and such. */
+
+struct gdb_event
+ {
+ event_handler_func *proc; /* Procedure to call to service this event. */
+ int fd; /* File descriptor that is ready. */
+ struct gdb_event *next_event; /* Next in list of events or NULL. */
+ };
+
+/* Information about each file descriptor we register with the event
+ loop. */
+
+typedef struct file_handler
+ {
+ int fd; /* File descriptor. */
+ int mask; /* Events we want to monitor: POLLIN, etc. */
+ int ready_mask; /* Events that have been seen since
+ the last time. */
+ handler_func *proc; /* Procedure to call when fd is ready. */
+ gdb_client_data client_data; /* Argument to pass to proc. */
+ int error; /* Was an error detected on this fd? */
+ struct file_handler *next_file; /* Next registered file descriptor. */
+ }
+file_handler;
+
+/* PROC is a function to be invoked when the READY flag is set. This
+ happens when there has been a signal and the corresponding signal
+ handler has 'triggered' this async_signal_handler for
+ execution. The actual work to be done in response to a signal will
+ be carried out by PROC at a later time, within process_event. This
+ provides a deferred execution of signal handlers.
+ Async_init_signals takes care of setting up such an
+ asyn_signal_handler for each interesting signal. */
+typedef struct async_signal_handler
+ {
+ int ready; /* If ready, call this handler from the main event loop,
+ using invoke_async_handler. */
+ struct async_signal_handler *next_handler; /* Ptr to next handler */
+ sig_handler_func *proc; /* Function to call to do the work */
+ gdb_client_data client_data; /* Argument to async_handler_func */
+ }
+async_signal_handler;
+
+
+/* Event queue:
+ - the first event in the queue is the head of the queue.
+ It will be the next to be serviced.
+ - the last event in the queue
+
+ Events can be inserted at the front of the queue or at the end of
+ the queue. Events will be extracted from the queue for processing
+ starting from the head. Therefore, events inserted at the head of
+ the queue will be processed in a last in first out fashion, while
+ those inserted at the tail of the queue will be processed in a first
+ in first out manner. All the fields are NULL if the queue is
+ empty. */
+
+static struct
+ {
+ gdb_event *first_event; /* First pending event */
+ gdb_event *last_event; /* Last pending event */
+ }
+event_queue;
+
+/* Gdb_notifier is just a list of file descriptors gdb is interested in.
+ These are the input file descriptor, and the target file
+ descriptor. We have two flavors of the notifier, one for platforms
+ that have the POLL function, the other for those that don't, and
+ only support SELECT. Each of the elements in the gdb_notifier list is
+ basically a description of what kind of events gdb is interested
+ in, for each fd. */
+
+/* As of 1999-04-30 only the input file descriptor is registered with the
+ event loop. */
+
+/* Do we use poll or select ? */
+#ifdef HAVE_POLL
+#define USE_POLL 1
+#else
+#define USE_POLL 0
+#endif /* HAVE_POLL */
+
+static unsigned char use_poll = USE_POLL;
+
+static struct
+ {
+ /* Ptr to head of file handler list. */
+ file_handler *first_file_handler;
+
+#ifdef HAVE_POLL
+ /* Ptr to array of pollfd structures. */
+ struct pollfd *poll_fds;
+
+ /* Timeout in milliseconds for calls to poll(). */
+ int poll_timeout;
+#endif
+
+ /* Masks to be used in the next call to select.
+ Bits are set in response to calls to create_file_handler. */
+ fd_set check_masks[3];
+
+ /* What file descriptors were found ready by select. */
+ fd_set ready_masks[3];
+
+ /* Number of file descriptors to monitor. (for poll) */
+ /* Number of valid bits (highest fd value + 1). (for select) */
+ int num_fds;
+
+ /* Time structure for calls to select(). */
+ struct timeval select_timeout;
+
+ /* Flag to tell whether the timeout should be used. */
+ int timeout_valid;
+ }
+gdb_notifier;
+
+/* Structure associated with a timer. PROC will be executed at the
+ first occasion after WHEN. */
+struct gdb_timer
+ {
+ struct timeval when;
+ int timer_id;
+ struct gdb_timer *next;
+ timer_handler_func *proc; /* Function to call to do the work */
+ gdb_client_data client_data; /* Argument to async_handler_func */
+ }
+gdb_timer;
+
+/* List of currently active timers. It is sorted in order of
+ increasing timers. */
+static struct
+ {
+ /* Pointer to first in timer list. */
+ struct gdb_timer *first_timer;
+
+ /* Id of the last timer created. */
+ int num_timers;
+ }
+timer_list;
+
+/* All the async_signal_handlers gdb is interested in are kept onto
+ this list. */
+static struct
+ {
+ /* Pointer to first in handler list. */
+ async_signal_handler *first_handler;
+
+ /* Pointer to last in handler list. */
+ async_signal_handler *last_handler;
+ }
+sighandler_list;
+
+/* Are any of the handlers ready? Check this variable using
+ check_async_ready. This is used by process_event, to determine
+ whether or not to invoke the invoke_async_signal_handler
+ function. */
+static int async_handler_ready = 0;
+
+static void create_file_handler (int fd, int mask, handler_func * proc, gdb_client_data client_data);
+static void invoke_async_signal_handler (void);
+static void handle_file_event (int event_file_desc);
+static int gdb_wait_for_event (void);
+static int check_async_ready (void);
+static void async_queue_event (gdb_event * event_ptr, queue_position position);
+static gdb_event *create_file_event (int fd);
+static int process_event (void);
+static void handle_timer_event (int dummy);
+static void poll_timers (void);
+
+
+/* Insert an event object into the gdb event queue at
+ the specified position.
+ POSITION can be head or tail, with values TAIL, HEAD.
+ EVENT_PTR points to the event to be inserted into the queue.
+ The caller must allocate memory for the event. It is freed
+ after the event has ben handled.
+ Events in the queue will be processed head to tail, therefore,
+ events inserted at the head of the queue will be processed
+ as last in first out. Event appended at the tail of the queue
+ will be processed first in first out. */
+static void
+async_queue_event (gdb_event * event_ptr, queue_position position)
+{
+ if (position == TAIL)
+ {
+ /* The event will become the new last_event. */
+
+ event_ptr->next_event = NULL;
+ if (event_queue.first_event == NULL)
+ event_queue.first_event = event_ptr;
+ else
+ event_queue.last_event->next_event = event_ptr;
+ event_queue.last_event = event_ptr;
+ }
+ else if (position == HEAD)
+ {
+ /* The event becomes the new first_event. */
+
+ event_ptr->next_event = event_queue.first_event;
+ if (event_queue.first_event == NULL)
+ event_queue.last_event = event_ptr;
+ event_queue.first_event = event_ptr;
+ }
+}
+
+/* Create a file event, to be enqueued in the event queue for
+ processing. The procedure associated to this event is always
+ handle_file_event, which will in turn invoke the one that was
+ associated to FD when it was registered with the event loop. */
+static gdb_event *
+create_file_event (int fd)
+{
+ gdb_event *file_event_ptr;
+
+ file_event_ptr = (gdb_event *) xmalloc (sizeof (gdb_event));
+ file_event_ptr->proc = handle_file_event;
+ file_event_ptr->fd = fd;
+ return (file_event_ptr);
+}
+
+/* Process one event.
+ The event can be the next one to be serviced in the event queue,
+ or an asynchronous event handler can be invoked in response to
+ the reception of a signal.
+ If an event was processed (either way), 1 is returned otherwise
+ 0 is returned.
+ Scan the queue from head to tail, processing therefore the high
+ priority events first, by invoking the associated event handler
+ procedure. */
+static int
+process_event (void)
+{
+ gdb_event *event_ptr, *prev_ptr;
+ event_handler_func *proc;
+ int fd;
+
+ /* First let's see if there are any asynchronous event handlers that
+ are ready. These would be the result of invoking any of the
+ signal handlers. */
+
+ if (check_async_ready ())
+ {
+ invoke_async_signal_handler ();
+ return 1;
+ }
+
+ /* Look in the event queue to find an event that is ready
+ to be processed. */
+
+ for (event_ptr = event_queue.first_event; event_ptr != NULL;
+ event_ptr = event_ptr->next_event)
+ {
+ /* Call the handler for the event. */
+
+ proc = event_ptr->proc;
+ fd = event_ptr->fd;
+
+ /* Let's get rid of the event from the event queue. We need to
+ do this now because while processing the event, the proc
+ function could end up calling 'error' and therefore jump out
+ to the caller of this function, gdb_do_one_event. In that
+ case, we would have on the event queue an event wich has been
+ processed, but not deleted. */
+
+ if (event_queue.first_event == event_ptr)
+ {
+ event_queue.first_event = event_ptr->next_event;
+ if (event_ptr->next_event == NULL)
+ event_queue.last_event = NULL;
+ }
+ else
+ {
+ prev_ptr = event_queue.first_event;
+ while (prev_ptr->next_event != event_ptr)
+ prev_ptr = prev_ptr->next_event;
+
+ prev_ptr->next_event = event_ptr->next_event;
+ if (event_ptr->next_event == NULL)
+ event_queue.last_event = prev_ptr;
+ }
+ xfree (event_ptr);
+
+ /* Now call the procedure associated with the event. */
+ (*proc) (fd);
+ return 1;
+ }
+
+ /* this is the case if there are no event on the event queue. */
+ return 0;
+}
+
+/* Process one high level event. If nothing is ready at this time,
+ wait for something to happen (via gdb_wait_for_event), then process
+ it. Returns >0 if something was done otherwise returns <0 (this
+ can happen if there are no event sources to wait for). If an error
+ occurs catch_errors() which calls this function returns zero. */
+
+int
+gdb_do_one_event (void *data)
+{
+ /* Any events already waiting in the queue? */
+ if (process_event ())
+ {
+ return 1;
+ }
+
+ /* Are any timers that are ready? If so, put an event on the queue. */
+ poll_timers ();
+
+ /* Wait for a new event. If gdb_wait_for_event returns -1,
+ we should get out because this means that there are no
+ event sources left. This will make the event loop stop,
+ and the application exit. */
+
+ if (gdb_wait_for_event () < 0)
+ {
+ return -1;
+ }
+
+ /* Handle any new events occurred while waiting. */
+ if (process_event ())
+ {
+ return 1;
+ }
+
+ /* If gdb_wait_for_event has returned 1, it means that one
+ event has been handled. We break out of the loop. */
+ return 1;
+}
+
+/* Start up the event loop. This is the entry point to the event loop
+ from the command loop. */
+
+void
+start_event_loop (void)
+{
+ /* Loop until there is nothing to do. This is the entry point to the
+ event loop engine. gdb_do_one_event, called via catch_errors()
+ will process one event for each invocation. It blocks waits for
+ an event and then processes it. >0 when an event is processed, 0
+ when catch_errors() caught an error and <0 when there are no
+ longer any event sources registered. */
+ while (1)
+ {
+ int gdb_result;
+
+ gdb_result = catch_errors (gdb_do_one_event, 0, "", RETURN_MASK_ALL);
+ if (gdb_result < 0)
+ break;
+
+ /* If we long-jumped out of do_one_event, we probably
+ didn't get around to resetting the prompt, which leaves
+ readline in a messed-up state. Reset it here. */
+
+ if (gdb_result == 0)
+ {
+ /* FIXME: this should really be a call to a hook that is
+ interface specific, because interfaces can display the
+ prompt in their own way. */
+ display_gdb_prompt (0);
+ /* This call looks bizarre, but it is required. If the user
+ entered a command that caused an error,
+ after_char_processing_hook won't be called from
+ rl_callback_read_char_wrapper. Using a cleanup there
+ won't work, since we want this function to be called
+ after a new prompt is printed. */
+ if (after_char_processing_hook)
+ (*after_char_processing_hook) ();
+ /* Maybe better to set a flag to be checked somewhere as to
+ whether display the prompt or not. */
+ }
+ }
+
+ /* We are done with the event loop. There are no more event sources
+ to listen to. So we exit GDB. */
+ return;
+}
+
+
+/* Wrapper function for create_file_handler, so that the caller
+ doesn't have to know implementation details about the use of poll
+ vs. select. */
+void
+add_file_handler (int fd, handler_func * proc, gdb_client_data client_data)
+{
+#ifdef HAVE_POLL
+ struct pollfd fds;
+#endif
+
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ /* Check to see if poll () is usable. If not, we'll switch to
+ use select. This can happen on systems like
+ m68k-motorola-sys, `poll' cannot be used to wait for `stdin'.
+ On m68k-motorola-sysv, tty's are not stream-based and not
+ `poll'able. */
+ fds.fd = fd;
+ fds.events = POLLIN;
+ if (poll (&fds, 1, 0) == 1 && (fds.revents & POLLNVAL))
+ use_poll = 0;
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif /* HAVE_POLL */
+ }
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ create_file_handler (fd, POLLIN, proc, client_data);
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif
+ }
+ else
+ create_file_handler (fd, GDB_READABLE | GDB_EXCEPTION, proc, client_data);
+}
+
+/* Add a file handler/descriptor to the list of descriptors we are
+ interested in.
+ FD is the file descriptor for the file/stream to be listened to.
+ For the poll case, MASK is a combination (OR) of
+ POLLIN, POLLRDNORM, POLLRDBAND, POLLPRI, POLLOUT, POLLWRNORM,
+ POLLWRBAND: these are the events we are interested in. If any of them
+ occurs, proc should be called.
+ For the select case, MASK is a combination of READABLE, WRITABLE, EXCEPTION.
+ PROC is the procedure that will be called when an event occurs for
+ FD. CLIENT_DATA is the argument to pass to PROC. */
+static void
+create_file_handler (int fd, int mask, handler_func * proc, gdb_client_data client_data)
+{
+ file_handler *file_ptr;
+
+ /* Do we already have a file handler for this file? (We may be
+ changing its associated procedure). */
+ for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
+ file_ptr = file_ptr->next_file)
+ {
+ if (file_ptr->fd == fd)
+ break;
+ }
+
+ /* It is a new file descriptor. Add it to the list. Otherwise, just
+ change the data associated with it. */
+ if (file_ptr == NULL)
+ {
+ file_ptr = (file_handler *) xmalloc (sizeof (file_handler));
+ file_ptr->fd = fd;
+ file_ptr->ready_mask = 0;
+ file_ptr->next_file = gdb_notifier.first_file_handler;
+ gdb_notifier.first_file_handler = file_ptr;
+
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ gdb_notifier.num_fds++;
+ if (gdb_notifier.poll_fds)
+ gdb_notifier.poll_fds =
+ (struct pollfd *) xrealloc (gdb_notifier.poll_fds,
+ (gdb_notifier.num_fds
+ * sizeof (struct pollfd)));
+ else
+ gdb_notifier.poll_fds =
+ (struct pollfd *) xmalloc (sizeof (struct pollfd));
+ (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->fd = fd;
+ (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->events = mask;
+ (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->revents = 0;
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif /* HAVE_POLL */
+ }
+ else
+ {
+ if (mask & GDB_READABLE)
+ FD_SET (fd, &gdb_notifier.check_masks[0]);
+ else
+ FD_CLR (fd, &gdb_notifier.check_masks[0]);
+
+ if (mask & GDB_WRITABLE)
+ FD_SET (fd, &gdb_notifier.check_masks[1]);
+ else
+ FD_CLR (fd, &gdb_notifier.check_masks[1]);
+
+ if (mask & GDB_EXCEPTION)
+ FD_SET (fd, &gdb_notifier.check_masks[2]);
+ else
+ FD_CLR (fd, &gdb_notifier.check_masks[2]);
+
+ if (gdb_notifier.num_fds <= fd)
+ gdb_notifier.num_fds = fd + 1;
+ }
+ }
+
+ file_ptr->proc = proc;
+ file_ptr->client_data = client_data;
+ file_ptr->mask = mask;
+}
+
+/* Remove the file descriptor FD from the list of monitored fd's:
+ i.e. we don't care anymore about events on the FD. */
+void
+delete_file_handler (int fd)
+{
+ file_handler *file_ptr, *prev_ptr = NULL;
+ int i;
+#ifdef HAVE_POLL
+ int j;
+ struct pollfd *new_poll_fds;
+#endif
+
+ /* Find the entry for the given file. */
+
+ for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
+ file_ptr = file_ptr->next_file)
+ {
+ if (file_ptr->fd == fd)
+ break;
+ }
+
+ if (file_ptr == NULL)
+ return;
+
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ /* Create a new poll_fds array by copying every fd's information but the
+ one we want to get rid of. */
+
+ new_poll_fds =
+ (struct pollfd *) xmalloc ((gdb_notifier.num_fds - 1) * sizeof (struct pollfd));
+
+ for (i = 0, j = 0; i < gdb_notifier.num_fds; i++)
+ {
+ if ((gdb_notifier.poll_fds + i)->fd != fd)
+ {
+ (new_poll_fds + j)->fd = (gdb_notifier.poll_fds + i)->fd;
+ (new_poll_fds + j)->events = (gdb_notifier.poll_fds + i)->events;
+ (new_poll_fds + j)->revents = (gdb_notifier.poll_fds + i)->revents;
+ j++;
+ }
+ }
+ xfree (gdb_notifier.poll_fds);
+ gdb_notifier.poll_fds = new_poll_fds;
+ gdb_notifier.num_fds--;
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif /* HAVE_POLL */
+ }
+ else
+ {
+ if (file_ptr->mask & GDB_READABLE)
+ FD_CLR (fd, &gdb_notifier.check_masks[0]);
+ if (file_ptr->mask & GDB_WRITABLE)
+ FD_CLR (fd, &gdb_notifier.check_masks[1]);
+ if (file_ptr->mask & GDB_EXCEPTION)
+ FD_CLR (fd, &gdb_notifier.check_masks[2]);
+
+ /* Find current max fd. */
+
+ if ((fd + 1) == gdb_notifier.num_fds)
+ {
+ gdb_notifier.num_fds--;
+ for (i = gdb_notifier.num_fds; i; i--)
+ {
+ if (FD_ISSET (i - 1, &gdb_notifier.check_masks[0])
+ || FD_ISSET (i - 1, &gdb_notifier.check_masks[1])
+ || FD_ISSET (i - 1, &gdb_notifier.check_masks[2]))
+ break;
+ }
+ gdb_notifier.num_fds = i;
+ }
+ }
+
+ /* Deactivate the file descriptor, by clearing its mask,
+ so that it will not fire again. */
+
+ file_ptr->mask = 0;
+
+ /* Get rid of the file handler in the file handler list. */
+ if (file_ptr == gdb_notifier.first_file_handler)
+ gdb_notifier.first_file_handler = file_ptr->next_file;
+ else
+ {
+ for (prev_ptr = gdb_notifier.first_file_handler;
+ prev_ptr->next_file != file_ptr;
+ prev_ptr = prev_ptr->next_file)
+ ;
+ prev_ptr->next_file = file_ptr->next_file;
+ }
+ xfree (file_ptr);
+}
+
+/* Handle the given event by calling the procedure associated to the
+ corresponding file handler. Called by process_event indirectly,
+ through event_ptr->proc. EVENT_FILE_DESC is file descriptor of the
+ event in the front of the event queue. */
+static void
+handle_file_event (int event_file_desc)
+{
+ file_handler *file_ptr;
+ int mask;
+#ifdef HAVE_POLL
+ int error_mask;
+ int error_mask_returned;
+#endif
+
+ /* Search the file handler list to find one that matches the fd in
+ the event. */
+ for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
+ file_ptr = file_ptr->next_file)
+ {
+ if (file_ptr->fd == event_file_desc)
+ {
+ /* With poll, the ready_mask could have any of three events
+ set to 1: POLLHUP, POLLERR, POLLNVAL. These events cannot
+ be used in the requested event mask (events), but they
+ can be returned in the return mask (revents). We need to
+ check for those event too, and add them to the mask which
+ will be passed to the handler. */
+
+ /* See if the desired events (mask) match the received
+ events (ready_mask). */
+
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ error_mask = POLLHUP | POLLERR | POLLNVAL;
+ mask = (file_ptr->ready_mask & file_ptr->mask) |
+ (file_ptr->ready_mask & error_mask);
+ error_mask_returned = mask & error_mask;
+
+ if (error_mask_returned != 0)
+ {
+ /* Work in progress. We may need to tell somebody what
+ kind of error we had. */
+ if (error_mask_returned & POLLHUP)
+ printf_unfiltered ("Hangup detected on fd %d\n", file_ptr->fd);
+ if (error_mask_returned & POLLERR)
+ printf_unfiltered ("Error detected on fd %d\n", file_ptr->fd);
+ if (error_mask_returned & POLLNVAL)
+ printf_unfiltered ("Invalid or non-`poll'able fd %d\n", file_ptr->fd);
+ file_ptr->error = 1;
+ }
+ else
+ file_ptr->error = 0;
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif /* HAVE_POLL */
+ }
+ else
+ {
+ if (file_ptr->ready_mask & GDB_EXCEPTION)
+ {
+ printf_unfiltered ("Exception condition detected on fd %d\n", file_ptr->fd);
+ file_ptr->error = 1;
+ }
+ else
+ file_ptr->error = 0;
+ mask = file_ptr->ready_mask & file_ptr->mask;
+ }
+
+ /* Clear the received events for next time around. */
+ file_ptr->ready_mask = 0;
+
+ /* If there was a match, then call the handler. */
+ if (mask != 0)
+ (*file_ptr->proc) (file_ptr->error, file_ptr->client_data);
+ break;
+ }
+ }
+}
+
+/* Called by gdb_do_one_event to wait for new events on the
+ monitored file descriptors. Queue file events as they are
+ detected by the poll.
+ If there are no events, this function will block in the
+ call to poll.
+ Return -1 if there are no files descriptors to monitor,
+ otherwise return 0. */
+static int
+gdb_wait_for_event (void)
+{
+ file_handler *file_ptr;
+ gdb_event *file_event_ptr;
+ int num_found = 0;
+ int i;
+
+ /* Make sure all output is done before getting another event. */
+ gdb_flush (gdb_stdout);
+ gdb_flush (gdb_stderr);
+
+ if (gdb_notifier.num_fds == 0)
+ return -1;
+
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ num_found =
+ poll (gdb_notifier.poll_fds,
+ (unsigned long) gdb_notifier.num_fds,
+ gdb_notifier.timeout_valid ? gdb_notifier.poll_timeout : -1);
+
+ /* Don't print anything if we get out of poll because of a
+ signal. */
+ if (num_found == -1 && errno != EINTR)
+ perror_with_name ("Poll");
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif /* HAVE_POLL */
+ }
+ else
+ {
+ gdb_notifier.ready_masks[0] = gdb_notifier.check_masks[0];
+ gdb_notifier.ready_masks[1] = gdb_notifier.check_masks[1];
+ gdb_notifier.ready_masks[2] = gdb_notifier.check_masks[2];
+ num_found = select (gdb_notifier.num_fds,
+ &gdb_notifier.ready_masks[0],
+ &gdb_notifier.ready_masks[1],
+ &gdb_notifier.ready_masks[2],
+ gdb_notifier.timeout_valid
+ ? &gdb_notifier.select_timeout : NULL);
+
+ /* Clear the masks after an error from select. */
+ if (num_found == -1)
+ {
+ FD_ZERO (&gdb_notifier.ready_masks[0]);
+ FD_ZERO (&gdb_notifier.ready_masks[1]);
+ FD_ZERO (&gdb_notifier.ready_masks[2]);
+ /* Dont print anything is we got a signal, let gdb handle it. */
+ if (errno != EINTR)
+ perror_with_name ("Select");
+ }
+ }
+
+ /* Enqueue all detected file events. */
+
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ for (i = 0; (i < gdb_notifier.num_fds) && (num_found > 0); i++)
+ {
+ if ((gdb_notifier.poll_fds + i)->revents)
+ num_found--;
+ else
+ continue;
+
+ for (file_ptr = gdb_notifier.first_file_handler;
+ file_ptr != NULL;
+ file_ptr = file_ptr->next_file)
+ {
+ if (file_ptr->fd == (gdb_notifier.poll_fds + i)->fd)
+ break;
+ }
+
+ if (file_ptr)
+ {
+ /* Enqueue an event only if this is still a new event for
+ this fd. */
+ if (file_ptr->ready_mask == 0)
+ {
+ file_event_ptr = create_file_event (file_ptr->fd);
+ async_queue_event (file_event_ptr, TAIL);
+ }
+ }
+
+ file_ptr->ready_mask = (gdb_notifier.poll_fds + i)->revents;
+ }
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif /* HAVE_POLL */
+ }
+ else
+ {
+ for (file_ptr = gdb_notifier.first_file_handler;
+ (file_ptr != NULL) && (num_found > 0);
+ file_ptr = file_ptr->next_file)
+ {
+ int mask = 0;
+
+ if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[0]))
+ mask |= GDB_READABLE;
+ if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[1]))
+ mask |= GDB_WRITABLE;
+ if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[2]))
+ mask |= GDB_EXCEPTION;
+
+ if (!mask)
+ continue;
+ else
+ num_found--;
+
+ /* Enqueue an event only if this is still a new event for
+ this fd. */
+
+ if (file_ptr->ready_mask == 0)
+ {
+ file_event_ptr = create_file_event (file_ptr->fd);
+ async_queue_event (file_event_ptr, TAIL);
+ }
+ file_ptr->ready_mask = mask;
+ }
+ }
+ return 0;
+}
+
+
+/* Create an asynchronous handler, allocating memory for it.
+ Return a pointer to the newly created handler.
+ This pointer will be used to invoke the handler by
+ invoke_async_signal_handler.
+ PROC is the function to call with CLIENT_DATA argument
+ whenever the handler is invoked. */
+async_signal_handler *
+create_async_signal_handler (sig_handler_func * proc, gdb_client_data client_data)
+{
+ async_signal_handler *async_handler_ptr;
+
+ async_handler_ptr =
+ (async_signal_handler *) xmalloc (sizeof (async_signal_handler));
+ async_handler_ptr->ready = 0;
+ async_handler_ptr->next_handler = NULL;
+ async_handler_ptr->proc = proc;
+ async_handler_ptr->client_data = client_data;
+ if (sighandler_list.first_handler == NULL)
+ sighandler_list.first_handler = async_handler_ptr;
+ else
+ sighandler_list.last_handler->next_handler = async_handler_ptr;
+ sighandler_list.last_handler = async_handler_ptr;
+ return async_handler_ptr;
+}
+
+/* Mark the handler (ASYNC_HANDLER_PTR) as ready. This information will
+ be used when the handlers are invoked, after we have waited for
+ some event. The caller of this function is the interrupt handler
+ associated with a signal. */
+void
+mark_async_signal_handler (async_signal_handler * async_handler_ptr)
+{
+ ((async_signal_handler *) async_handler_ptr)->ready = 1;
+ async_handler_ready = 1;
+}
+
+/* Call all the handlers that are ready. */
+static void
+invoke_async_signal_handler (void)
+{
+ async_signal_handler *async_handler_ptr;
+
+ if (async_handler_ready == 0)
+ return;
+ async_handler_ready = 0;
+
+ /* Invoke ready handlers. */
+
+ while (1)
+ {
+ for (async_handler_ptr = sighandler_list.first_handler;
+ async_handler_ptr != NULL;
+ async_handler_ptr = async_handler_ptr->next_handler)
+ {
+ if (async_handler_ptr->ready)
+ break;
+ }
+ if (async_handler_ptr == NULL)
+ break;
+ async_handler_ptr->ready = 0;
+ (*async_handler_ptr->proc) (async_handler_ptr->client_data);
+ }
+
+ return;
+}
+
+/* Delete an asynchronous handler (ASYNC_HANDLER_PTR).
+ Free the space allocated for it. */
+void
+delete_async_signal_handler (async_signal_handler ** async_handler_ptr)
+{
+ async_signal_handler *prev_ptr;
+
+ if (sighandler_list.first_handler == (*async_handler_ptr))
+ {
+ sighandler_list.first_handler = (*async_handler_ptr)->next_handler;
+ if (sighandler_list.first_handler == NULL)
+ sighandler_list.last_handler = NULL;
+ }
+ else
+ {
+ prev_ptr = sighandler_list.first_handler;
+ while (prev_ptr->next_handler != (*async_handler_ptr) && prev_ptr)
+ prev_ptr = prev_ptr->next_handler;
+ prev_ptr->next_handler = (*async_handler_ptr)->next_handler;
+ if (sighandler_list.last_handler == (*async_handler_ptr))
+ sighandler_list.last_handler = prev_ptr;
+ }
+ xfree ((*async_handler_ptr));
+ (*async_handler_ptr) = NULL;
+}
+
+/* Is it necessary to call invoke_async_signal_handler? */
+static int
+check_async_ready (void)
+{
+ return async_handler_ready;
+}
+
+/* Create a timer that will expire in MILLISECONDS from now. When the
+ timer is ready, PROC will be executed. At creation, the timer is
+ aded to the timers queue. This queue is kept sorted in order of
+ increasing timers. Return a handle to the timer struct. */
+int
+create_timer (int milliseconds, timer_handler_func * proc, gdb_client_data client_data)
+{
+ struct gdb_timer *timer_ptr, *timer_index, *prev_timer;
+ struct timeval time_now, delta;
+
+ /* compute seconds */
+ delta.tv_sec = milliseconds / 1000;
+ /* compute microseconds */
+ delta.tv_usec = (milliseconds % 1000) * 1000;
+
+ gettimeofday (&time_now, NULL);
+
+ timer_ptr = (struct gdb_timer *) xmalloc (sizeof (gdb_timer));
+ timer_ptr->when.tv_sec = time_now.tv_sec + delta.tv_sec;
+ timer_ptr->when.tv_usec = time_now.tv_usec + delta.tv_usec;
+ /* carry? */
+ if (timer_ptr->when.tv_usec >= 1000000)
+ {
+ timer_ptr->when.tv_sec += 1;
+ timer_ptr->when.tv_usec -= 1000000;
+ }
+ timer_ptr->proc = proc;
+ timer_ptr->client_data = client_data;
+ timer_list.num_timers++;
+ timer_ptr->timer_id = timer_list.num_timers;
+
+ /* Now add the timer to the timer queue, making sure it is sorted in
+ increasing order of expiration. */
+
+ for (timer_index = timer_list.first_timer;
+ timer_index != NULL;
+ timer_index = timer_index->next)
+ {
+ /* If the seconds field is greater or if it is the same, but the
+ microsecond field is greater. */
+ if ((timer_index->when.tv_sec > timer_ptr->when.tv_sec) ||
+ ((timer_index->when.tv_sec == timer_ptr->when.tv_sec)
+ && (timer_index->when.tv_usec > timer_ptr->when.tv_usec)))
+ break;
+ }
+
+ if (timer_index == timer_list.first_timer)
+ {
+ timer_ptr->next = timer_list.first_timer;
+ timer_list.first_timer = timer_ptr;
+
+ }
+ else
+ {
+ for (prev_timer = timer_list.first_timer;
+ prev_timer->next != timer_index;
+ prev_timer = prev_timer->next)
+ ;
+
+ prev_timer->next = timer_ptr;
+ timer_ptr->next = timer_index;
+ }
+
+ gdb_notifier.timeout_valid = 0;
+ return timer_ptr->timer_id;
+}
+
+/* There is a chance that the creator of the timer wants to get rid of
+ it before it expires. */
+void
+delete_timer (int id)
+{
+ struct gdb_timer *timer_ptr, *prev_timer = NULL;
+
+ /* Find the entry for the given timer. */
+
+ for (timer_ptr = timer_list.first_timer; timer_ptr != NULL;
+ timer_ptr = timer_ptr->next)
+ {
+ if (timer_ptr->timer_id == id)
+ break;
+ }
+
+ if (timer_ptr == NULL)
+ return;
+ /* Get rid of the timer in the timer list. */
+ if (timer_ptr == timer_list.first_timer)
+ timer_list.first_timer = timer_ptr->next;
+ else
+ {
+ for (prev_timer = timer_list.first_timer;
+ prev_timer->next != timer_ptr;
+ prev_timer = prev_timer->next)
+ ;
+ prev_timer->next = timer_ptr->next;
+ }
+ xfree (timer_ptr);
+
+ gdb_notifier.timeout_valid = 0;
+}
+
+/* When a timer event is put on the event queue, it will be handled by
+ this function. Just call the assiciated procedure and delete the
+ timer event from the event queue. Repeat this for each timer that
+ has expired. */
+static void
+handle_timer_event (int dummy)
+{
+ struct timeval time_now;
+ struct gdb_timer *timer_ptr, *saved_timer;
+
+ gettimeofday (&time_now, NULL);
+ timer_ptr = timer_list.first_timer;
+
+ while (timer_ptr != NULL)
+ {
+ if ((timer_ptr->when.tv_sec > time_now.tv_sec) ||
+ ((timer_ptr->when.tv_sec == time_now.tv_sec) &&
+ (timer_ptr->when.tv_usec > time_now.tv_usec)))
+ break;
+
+ /* Get rid of the timer from the beginning of the list. */
+ timer_list.first_timer = timer_ptr->next;
+ saved_timer = timer_ptr;
+ timer_ptr = timer_ptr->next;
+ /* Call the procedure associated with that timer. */
+ (*saved_timer->proc) (saved_timer->client_data);
+ xfree (saved_timer);
+ }
+
+ gdb_notifier.timeout_valid = 0;
+}
+
+/* Check whether any timers in the timers queue are ready. If at least
+ one timer is ready, stick an event onto the event queue. Even in
+ case more than one timer is ready, one event is enough, because the
+ handle_timer_event() will go through the timers list and call the
+ procedures associated with all that have expired. Update the
+ timeout for the select() or poll() as well. */
+static void
+poll_timers (void)
+{
+ struct timeval time_now, delta;
+ gdb_event *event_ptr;
+
+ if (timer_list.first_timer != NULL)
+ {
+ gettimeofday (&time_now, NULL);
+ delta.tv_sec = timer_list.first_timer->when.tv_sec - time_now.tv_sec;
+ delta.tv_usec = timer_list.first_timer->when.tv_usec - time_now.tv_usec;
+ /* borrow? */
+ if (delta.tv_usec < 0)
+ {
+ delta.tv_sec -= 1;
+ delta.tv_usec += 1000000;
+ }
+
+ /* Oops it expired already. Tell select / poll to return
+ immediately. (Cannot simply test if delta.tv_sec is negative
+ because time_t might be unsigned.) */
+ if (timer_list.first_timer->when.tv_sec < time_now.tv_sec
+ || (timer_list.first_timer->when.tv_sec == time_now.tv_sec
+ && timer_list.first_timer->when.tv_usec < time_now.tv_usec))
+ {
+ delta.tv_sec = 0;
+ delta.tv_usec = 0;
+ }
+
+ if (delta.tv_sec == 0 && delta.tv_usec == 0)
+ {
+ event_ptr = (gdb_event *) xmalloc (sizeof (gdb_event));
+ event_ptr->proc = handle_timer_event;
+ event_ptr->fd = timer_list.first_timer->timer_id;
+ async_queue_event (event_ptr, TAIL);
+ }
+
+ /* Now we need to update the timeout for select/ poll, because we
+ don't want to sit there while this timer is expiring. */
+ if (use_poll)
+ {
+#ifdef HAVE_POLL
+ gdb_notifier.poll_timeout = delta.tv_sec * 1000;
+#else
+ internal_error (__FILE__, __LINE__,
+ "use_poll without HAVE_POLL");
+#endif /* HAVE_POLL */
+ }
+ else
+ {
+ gdb_notifier.select_timeout.tv_sec = delta.tv_sec;
+ gdb_notifier.select_timeout.tv_usec = delta.tv_usec;
+ }
+ gdb_notifier.timeout_valid = 1;
+ }
+ else
+ gdb_notifier.timeout_valid = 0;
+}
diff --git a/contrib/gdb/gdb/event-loop.h b/contrib/gdb/gdb/event-loop.h
new file mode 100644
index 0000000..748f486
--- /dev/null
+++ b/contrib/gdb/gdb/event-loop.h
@@ -0,0 +1,96 @@
+/* Definitions used by the GDB event loop.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+ Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 event loop listens for events from multiple event sources. When
+ an event arrives, it is queued and processed by calling the
+ appropriate event handler. The event loop then continues to listen
+ for more events. An event loop completes when there are no event
+ sources to listen on. External event sources can be plugged into
+ the loop.
+
+ There are 3 main components:
+ - a list of file descriptors to be monitored, GDB_NOTIFIER.
+ - a list of events that have occurred, EVENT_QUEUE.
+ - a list of signal handling functions, SIGHANDLER_LIST.
+
+ GDB_NOTIFIER keeps track of the event sources. Event sources for
+ gdb are currently the UI and the target. Gdb communicates with the
+ command line user interface via the readline library and usually
+ communicates with remote targets via a serial port. Serial ports
+ are represented in GDB as file descriptors and select/poll calls.
+ For native targets instead, the communication consists of calls to
+ ptrace and waits (via signals) or calls to poll/select (via file
+ descriptors). In the current gdb, the code handling events related
+ to the target resides in the wait_for_inferior function and in
+ various target specific files (*-tdep.c).
+
+ EVENT_QUEUE keeps track of the events that have happened during the
+ last iteration of the event loop, and need to be processed. An
+ event is represented by a procedure to be invoked in order to
+ process the event. The queue is scanned head to tail. If the
+ event of interest is a change of state in a file descriptor, then a
+ call to poll or select will be made to detect it.
+
+ If the events generate signals, they are also queued by special
+ functions that are invoked through traditional signal handlers.
+ The actions to be taken is response to such events will be executed
+ when the SIGHANDLER_LIST is scanned, the next time through the
+ infinite loop.
+
+ Corollary tasks are the creation and deletion of event sources. */
+
+typedef void *gdb_client_data;
+struct async_signal_handler;
+typedef void (handler_func) (int, gdb_client_data);
+typedef void (sig_handler_func) (gdb_client_data);
+typedef void (timer_handler_func) (gdb_client_data);
+
+/* Where to add an event onto the event queue, by queue_event. */
+typedef enum
+ {
+ /* Add at tail of queue. It will be processed in first in first
+ out order. */
+ TAIL,
+ /* Add at head of queue. It will be processed in last in first out
+ order. */
+ HEAD
+ }
+queue_position;
+
+/* Tell create_file_handler what events we are interested in.
+ This is used by the select version of the event loop. */
+
+#define GDB_READABLE (1<<1)
+#define GDB_WRITABLE (1<<2)
+#define GDB_EXCEPTION (1<<3)
+
+/* Exported functions from event-loop.c */
+
+extern void start_event_loop (void);
+extern int gdb_do_one_event (void *data);
+extern void delete_file_handler (int fd);
+extern void add_file_handler (int fd, handler_func * proc, gdb_client_data client_data);
+extern void mark_async_signal_handler (struct async_signal_handler *async_handler_ptr);
+extern struct async_signal_handler *
+ create_async_signal_handler (sig_handler_func * proc, gdb_client_data client_data);
+extern void delete_async_signal_handler (struct async_signal_handler **async_handler_ptr);
+extern int create_timer (int milliseconds, timer_handler_func * proc, gdb_client_data client_data);
+extern void delete_timer (int id);
diff --git a/contrib/gdb/gdb/event-top.c b/contrib/gdb/gdb/event-top.c
new file mode 100644
index 0000000..f4ba015
--- /dev/null
+++ b/contrib/gdb/gdb/event-top.c
@@ -0,0 +1,1187 @@
+/* Top level stuff for GDB, the GNU debugger.
+ Copyright 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+ Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "top.h"
+#include "inferior.h"
+#include "target.h"
+#include "terminal.h" /* for job_control */
+#include "event-loop.h"
+#include "event-top.h"
+#include "interps.h"
+#include <signal.h>
+
+/* For dont_repeat() */
+#include "gdbcmd.h"
+
+/* readline include files */
+#include "readline/readline.h"
+#include "readline/history.h"
+
+/* readline defines this. */
+#undef savestring
+
+static void rl_callback_read_char_wrapper (gdb_client_data client_data);
+static void command_line_handler (char *rl);
+static void command_line_handler_continuation (struct continuation_arg *arg);
+static void change_line_handler (void);
+static void change_annotation_level (void);
+static void command_handler (char *command);
+static void async_do_nothing (gdb_client_data arg);
+static void async_disconnect (gdb_client_data arg);
+static void async_stop_sig (gdb_client_data arg);
+static void async_float_handler (gdb_client_data arg);
+
+/* Signal handlers. */
+static void handle_sigquit (int sig);
+static void handle_sighup (int sig);
+static void handle_sigfpe (int sig);
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+static void handle_sigwinch (int sig);
+#endif
+
+/* Functions to be invoked by the event loop in response to
+ signals. */
+static void async_do_nothing (gdb_client_data);
+static void async_disconnect (gdb_client_data);
+static void async_float_handler (gdb_client_data);
+static void async_stop_sig (gdb_client_data);
+
+/* Readline offers an alternate interface, via callback
+ functions. These are all included in the file callback.c in the
+ readline distribution. This file provides (mainly) a function, which
+ the event loop uses as callback (i.e. event handler) whenever an event
+ is detected on the standard input file descriptor.
+ readline_callback_read_char is called (by the GDB event loop) whenever
+ there is a new character ready on the input stream. This function
+ incrementally builds a buffer internal to readline where it
+ accumulates the line read up to the point of invocation. In the
+ special case in which the character read is newline, the function
+ invokes a GDB supplied callback routine, which does the processing of
+ a full command line. This latter routine is the asynchronous analog
+ of the old command_line_input in gdb. Instead of invoking (and waiting
+ for) readline to read the command line and pass it back to
+ command_loop for processing, the new command_line_handler function has
+ the command line already available as its parameter. INPUT_HANDLER is
+ to be set to the function that readline will invoke when a complete
+ line of input is ready. CALL_READLINE is to be set to the function
+ that readline offers as callback to the event_loop. */
+
+void (*input_handler) (char *);
+void (*call_readline) (gdb_client_data);
+
+/* Important variables for the event loop. */
+
+/* This is used to determine if GDB is using the readline library or
+ its own simplified form of readline. It is used by the asynchronous
+ form of the set editing command.
+ ezannoni: as of 1999-04-29 I expect that this
+ variable will not be used after gdb is changed to use the event
+ loop as default engine, and event-top.c is merged into top.c. */
+int async_command_editing_p;
+
+/* This variable contains the new prompt that the user sets with the
+ set prompt command. */
+char *new_async_prompt;
+
+/* This is the annotation suffix that will be used when the
+ annotation_level is 2. */
+char *async_annotation_suffix;
+
+/* This is used to display the notification of the completion of an
+ asynchronous execution command. */
+int exec_done_display_p = 0;
+
+/* This is the file descriptor for the input stream that GDB uses to
+ read commands from. */
+int input_fd;
+
+/* This is the prompt stack. Prompts will be pushed on the stack as
+ needed by the different 'kinds' of user inputs GDB is asking
+ for. See event-loop.h. */
+struct prompts the_prompts;
+
+/* signal handling variables */
+/* Each of these is a pointer to a function that the event loop will
+ invoke if the corresponding signal has received. The real signal
+ handlers mark these functions as ready to be executed and the event
+ loop, in a later iteration, calls them. See the function
+ invoke_async_signal_handler. */
+void *sigint_token;
+#ifdef SIGHUP
+void *sighup_token;
+#endif
+void *sigquit_token;
+void *sigfpe_token;
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+void *sigwinch_token;
+#endif
+#ifdef STOP_SIGNAL
+void *sigtstp_token;
+#endif
+
+/* Structure to save a partially entered command. This is used when
+ the user types '\' at the end of a command line. This is necessary
+ because each line of input is handled by a different call to
+ command_line_handler, and normally there is no state retained
+ between different calls. */
+int more_to_come = 0;
+
+struct readline_input_state
+ {
+ char *linebuffer;
+ char *linebuffer_ptr;
+ }
+readline_input_state;
+
+/* This hook is called by rl_callback_read_char_wrapper after each
+ character is processed. */
+void (*after_char_processing_hook) ();
+
+
+/* Wrapper function for calling into the readline library. The event
+ loop expects the callback function to have a paramter, while readline
+ expects none. */
+static void
+rl_callback_read_char_wrapper (gdb_client_data client_data)
+{
+ rl_callback_read_char ();
+ if (after_char_processing_hook)
+ (*after_char_processing_hook) ();
+}
+
+/* Initialize all the necessary variables, start the event loop,
+ register readline, and stdin, start the loop. */
+void
+cli_command_loop (void)
+{
+ int length;
+ char *a_prompt;
+ char *gdb_prompt = get_prompt ();
+
+ /* If we are using readline, set things up and display the first
+ prompt, otherwise just print the prompt. */
+ if (async_command_editing_p)
+ {
+ /* Tell readline what the prompt to display is and what function it
+ will need to call after a whole line is read. This also displays
+ the first prompt. */
+ length = strlen (PREFIX (0)) + strlen (gdb_prompt) + strlen (SUFFIX (0)) + 1;
+ a_prompt = (char *) xmalloc (length);
+ strcpy (a_prompt, PREFIX (0));
+ strcat (a_prompt, gdb_prompt);
+ strcat (a_prompt, SUFFIX (0));
+ rl_callback_handler_install (a_prompt, input_handler);
+ }
+ else
+ display_gdb_prompt (0);
+
+ /* Now it's time to start the event loop. */
+ start_event_loop ();
+}
+
+/* Change the function to be invoked every time there is a character
+ ready on stdin. This is used when the user sets the editing off,
+ therefore bypassing readline, and letting gdb handle the input
+ itself, via gdb_readline2. Also it is used in the opposite case in
+ which the user sets editing on again, by restoring readline
+ handling of the input. */
+static void
+change_line_handler (void)
+{
+ /* NOTE: this operates on input_fd, not instream. If we are reading
+ commands from a file, instream will point to the file. However in
+ async mode, we always read commands from a file with editing
+ off. This means that the 'set editing on/off' will have effect
+ only on the interactive session. */
+
+ if (async_command_editing_p)
+ {
+ /* Turn on editing by using readline. */
+ call_readline = rl_callback_read_char_wrapper;
+ input_handler = command_line_handler;
+ }
+ else
+ {
+ /* Turn off editing by using gdb_readline2. */
+ rl_callback_handler_remove ();
+ call_readline = gdb_readline2;
+
+ /* Set up the command handler as well, in case we are called as
+ first thing from .gdbinit. */
+ input_handler = command_line_handler;
+ }
+}
+
+/* Displays the prompt. The prompt that is displayed is the current
+ top of the prompt stack, if the argument NEW_PROMPT is
+ 0. Otherwise, it displays whatever NEW_PROMPT is. This is used
+ after each gdb command has completed, and in the following cases:
+ 1. when the user enters a command line which is ended by '\'
+ indicating that the command will continue on the next line.
+ In that case the prompt that is displayed is the empty string.
+ 2. When the user is entering 'commands' for a breakpoint, or
+ actions for a tracepoint. In this case the prompt will be '>'
+ 3. Other????
+ FIXME: 2. & 3. not implemented yet for async. */
+void
+display_gdb_prompt (char *new_prompt)
+{
+ int prompt_length = 0;
+ char *gdb_prompt = get_prompt ();
+
+ /* Each interpreter has its own rules on displaying the command
+ prompt. */
+ if (!current_interp_display_prompt_p ())
+ return;
+
+ if (target_executing && sync_execution)
+ {
+ /* This is to trick readline into not trying to display the
+ prompt. Even though we display the prompt using this
+ function, readline still tries to do its own display if we
+ don't call rl_callback_handler_install and
+ rl_callback_handler_remove (which readline detects because a
+ global variable is not set). If readline did that, it could
+ mess up gdb signal handlers for SIGINT. Readline assumes
+ that between calls to rl_set_signals and rl_clear_signals gdb
+ doesn't do anything with the signal handlers. Well, that's
+ not the case, because when the target executes we change the
+ SIGINT signal handler. If we allowed readline to display the
+ prompt, the signal handler change would happen exactly
+ between the calls to the above two functions.
+ Calling rl_callback_handler_remove(), does the job. */
+
+ rl_callback_handler_remove ();
+ return;
+ }
+
+ if (!new_prompt)
+ {
+ /* Just use the top of the prompt stack. */
+ prompt_length = strlen (PREFIX (0)) +
+ strlen (SUFFIX (0)) +
+ strlen (gdb_prompt) + 1;
+
+ new_prompt = (char *) alloca (prompt_length);
+
+ /* Prefix needs to have new line at end. */
+ strcpy (new_prompt, PREFIX (0));
+ strcat (new_prompt, gdb_prompt);
+ /* Suffix needs to have a new line at end and \032 \032 at
+ beginning. */
+ strcat (new_prompt, SUFFIX (0));
+ }
+
+ if (async_command_editing_p)
+ {
+ rl_callback_handler_remove ();
+ rl_callback_handler_install (new_prompt, input_handler);
+ }
+ /* new_prompt at this point can be the top of the stack or the one passed in */
+ else if (new_prompt)
+ {
+ /* 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 (new_prompt, gdb_stdout);
+ gdb_flush (gdb_stdout);
+ }
+}
+
+/* Used when the user requests a different annotation level, with
+ 'set annotate'. It pushes a new prompt (with prefix and suffix) on top
+ of the prompt stack, if the annotation level desired is 2, otherwise
+ it pops the top of the prompt stack when we want the annotation level
+ to be the normal ones (1 or 0). */
+static void
+change_annotation_level (void)
+{
+ char *prefix, *suffix;
+
+ if (!PREFIX (0) || !PROMPT (0) || !SUFFIX (0))
+ {
+ /* The prompt stack has not been initialized to "", we are
+ using gdb w/o the --async switch */
+ warning ("Command has same effect as set annotate");
+ return;
+ }
+
+ if (annotation_level > 1)
+ {
+ if (!strcmp (PREFIX (0), "") && !strcmp (SUFFIX (0), ""))
+ {
+ /* Push a new prompt if the previous annotation_level was not >1. */
+ prefix = (char *) alloca (strlen (async_annotation_suffix) + 10);
+ strcpy (prefix, "\n\032\032pre-");
+ strcat (prefix, async_annotation_suffix);
+ strcat (prefix, "\n");
+
+ suffix = (char *) alloca (strlen (async_annotation_suffix) + 6);
+ strcpy (suffix, "\n\032\032");
+ strcat (suffix, async_annotation_suffix);
+ strcat (suffix, "\n");
+
+ push_prompt (prefix, (char *) 0, suffix);
+ }
+ }
+ else
+ {
+ if (strcmp (PREFIX (0), "") && strcmp (SUFFIX (0), ""))
+ {
+ /* Pop the top of the stack, we are going back to annotation < 1. */
+ pop_prompt ();
+ }
+ }
+}
+
+/* Pushes a new prompt on the prompt stack. Each prompt has three
+ parts: prefix, prompt, suffix. Usually prefix and suffix are empty
+ strings, except when the annotation level is 2. Memory is allocated
+ within savestring for the new prompt. */
+void
+push_prompt (char *prefix, char *prompt, char *suffix)
+{
+ the_prompts.top++;
+ PREFIX (0) = savestring (prefix, strlen (prefix));
+
+ /* Note that this function is used by the set annotate 2
+ command. This is why we take care of saving the old prompt
+ in case a new one is not specified. */
+ if (prompt)
+ PROMPT (0) = savestring (prompt, strlen (prompt));
+ else
+ PROMPT (0) = savestring (PROMPT (-1), strlen (PROMPT (-1)));
+
+ SUFFIX (0) = savestring (suffix, strlen (suffix));
+}
+
+/* Pops the top of the prompt stack, and frees the memory allocated for it. */
+void
+pop_prompt (void)
+{
+ /* If we are not during a 'synchronous' execution command, in which
+ case, the top prompt would be empty. */
+ if (strcmp (PROMPT (0), ""))
+ /* This is for the case in which the prompt is set while the
+ annotation level is 2. The top prompt will be changed, but when
+ we return to annotation level < 2, we want that new prompt to be
+ in effect, until the user does another 'set prompt'. */
+ if (strcmp (PROMPT (0), PROMPT (-1)))
+ {
+ xfree (PROMPT (-1));
+ PROMPT (-1) = savestring (PROMPT (0), strlen (PROMPT (0)));
+ }
+
+ xfree (PREFIX (0));
+ xfree (PROMPT (0));
+ xfree (SUFFIX (0));
+ the_prompts.top--;
+}
+
+/* When there is an event ready on the stdin file desriptor, instead
+ of calling readline directly throught the callback function, or
+ instead of calling gdb_readline2, give gdb a chance to detect
+ errors and do something. */
+void
+stdin_event_handler (int error, gdb_client_data client_data)
+{
+ if (error)
+ {
+ printf_unfiltered ("error detected on stdin\n");
+ delete_file_handler (input_fd);
+ discard_all_continuations ();
+ /* If stdin died, we may as well kill gdb. */
+ quit_command ((char *) 0, stdin == instream);
+ }
+ else
+ (*call_readline) (client_data);
+}
+
+/* Re-enable stdin after the end of an execution command in
+ synchronous mode, or after an error from the target, and we aborted
+ the exec operation. */
+
+void
+async_enable_stdin (void *dummy)
+{
+ /* See NOTE in async_disable_stdin() */
+ /* FIXME: cagney/1999-09-27: Call this before clearing
+ sync_execution. Current target_terminal_ours() implementations
+ check for sync_execution before switching the terminal. */
+ target_terminal_ours ();
+ pop_prompt ();
+ sync_execution = 0;
+}
+
+/* Disable reads from stdin (the console) marking the command as
+ synchronous. */
+
+void
+async_disable_stdin (void)
+{
+ sync_execution = 1;
+ push_prompt ("", "", "");
+ /* FIXME: cagney/1999-09-27: At present this call is technically
+ redundant since infcmd.c and infrun.c both already call
+ target_terminal_inferior(). As the terminal handling (in
+ sync/async mode) is refined, the duplicate calls can be
+ eliminated (Here or in infcmd.c/infrun.c). */
+ target_terminal_inferior ();
+ /* Add the reinstate of stdin to the list of cleanups to be done
+ in case the target errors out and dies. These cleanups are also
+ done in case of normal successful termination of the execution
+ command, by complete_execution(). */
+ make_exec_error_cleanup (async_enable_stdin, NULL);
+}
+
+
+/* Handles a gdb command. This function is called by
+ command_line_handler, which has processed one or more input lines
+ into COMMAND. */
+/* NOTE: 1999-04-30 This is the asynchronous version of the command_loop
+ function. The command_loop function will be obsolete when we
+ switch to use the event loop at every execution of gdb. */
+static void
+command_handler (char *command)
+{
+ struct cleanup *old_chain;
+ int stdin_is_tty = ISATTY (stdin);
+ struct continuation_arg *arg1;
+ struct continuation_arg *arg2;
+ long time_at_cmd_start;
+#ifdef HAVE_SBRK
+ long space_at_cmd_start = 0;
+#endif
+ extern int display_time;
+ extern int display_space;
+
+ quit_flag = 0;
+ if (instream == stdin && stdin_is_tty)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup (null_cleanup, 0);
+
+ /* If readline returned a NULL command, it means that the
+ connection with the terminal is gone. This happens at the
+ end of a testsuite run, after Expect has hung up
+ but GDB is still alive. In such a case, we just quit gdb
+ killing the inferior program too. */
+ if (command == 0)
+ quit_command ((char *) 0, stdin == instream);
+
+ time_at_cmd_start = get_run_time ();
+
+ if (display_space)
+ {
+#ifdef HAVE_SBRK
+ char *lim = (char *) sbrk (0);
+ space_at_cmd_start = lim - lim_at_start;
+#endif
+ }
+
+ execute_command (command, instream == stdin);
+
+ /* Set things up for this function to be compete later, once the
+ execution has completed, if we are doing an execution command,
+ otherwise, just go ahead and finish. */
+ if (target_can_async_p () && target_executing)
+ {
+ arg1 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg2 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg1->next = arg2;
+ arg2->next = NULL;
+ arg1->data.longint = time_at_cmd_start;
+#ifdef HAVE_SBRK
+ arg2->data.longint = space_at_cmd_start;
+#endif
+ add_continuation (command_line_handler_continuation, arg1);
+ }
+
+ /* Do any commands attached to breakpoint we stopped at. Only if we
+ are always running synchronously. Or if we have just executed a
+ command that doesn't start the target. */
+ if (!target_can_async_p () || !target_executing)
+ {
+ 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
+ char *lim = (char *) sbrk (0);
+ long space_now = lim - lim_at_start;
+ 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
+ }
+ }
+}
+
+/* Do any commands attached to breakpoint we stopped at. Only if we
+ are always running synchronously. Or if we have just executed a
+ command that doesn't start the target. */
+void
+command_line_handler_continuation (struct continuation_arg *arg)
+{
+ extern int display_time;
+ extern int display_space;
+
+ long time_at_cmd_start = arg->data.longint;
+ long space_at_cmd_start = arg->next->data.longint;
+
+ bpstat_do_actions (&stop_bpstat);
+ /*do_cleanups (old_chain); *//*?????FIXME????? */
+
+ 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
+ char *lim = (char *) sbrk (0);
+ long space_now = lim - lim_at_start;
+ 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
+ }
+}
+
+/* Handle a complete line of input. This is called by the callback
+ mechanism within the readline library. Deal with incomplete commands
+ as well, by saving the partial input in a global buffer. */
+
+/* NOTE: 1999-04-30 This is the asynchronous version of the
+ command_line_input function. command_line_input will become
+ obsolete once we use the event loop as the default mechanism in
+ GDB. */
+static void
+command_line_handler (char *rl)
+{
+ static char *linebuffer = 0;
+ static unsigned linelength = 0;
+ char *p;
+ char *p1;
+ extern char *line;
+ extern int linesize;
+ char *nline;
+ char got_eof = 0;
+
+
+ int repeat = (instream == stdin);
+
+ if (annotation_level > 1 && instream == stdin)
+ {
+ printf_unfiltered ("\n\032\032post-");
+ puts_unfiltered (async_annotation_suffix);
+ printf_unfiltered ("\n");
+ }
+
+ if (linebuffer == 0)
+ {
+ linelength = 80;
+ linebuffer = (char *) xmalloc (linelength);
+ }
+
+ p = linebuffer;
+
+ if (more_to_come)
+ {
+ strcpy (linebuffer, readline_input_state.linebuffer);
+ p = readline_input_state.linebuffer_ptr;
+ xfree (readline_input_state.linebuffer);
+ more_to_come = 0;
+ pop_prompt ();
+ }
+
+#ifdef STOP_SIGNAL
+ if (job_control)
+ signal (STOP_SIGNAL, handle_stop_sig);
+#endif
+
+ /* 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 we are in this case, then command_handler will call quit
+ and exit from gdb. */
+ if (!rl || rl == (char *) EOF)
+ {
+ got_eof = 1;
+ command_handler (0);
+ }
+ 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++;
+
+ xfree (rl); /* Allocated in readline. */
+
+ if (p > linebuffer && *(p - 1) == '\\')
+ {
+ p--; /* Put on top of '\'. */
+
+ readline_input_state.linebuffer = savestring (linebuffer,
+ strlen (linebuffer));
+ readline_input_state.linebuffer_ptr = p;
+
+ /* We will not invoke a execute_command if there is more
+ input expected to complete the command. So, we need to
+ print an empty prompt here. */
+ more_to_come = 1;
+ push_prompt ("", "", "");
+ display_gdb_prompt (0);
+ return;
+ }
+
+#ifdef STOP_SIGNAL
+ if (job_control)
+ signal (STOP_SIGNAL, SIG_DFL);
+#endif
+
+#define SERVER_COMMAND_LENGTH 7
+ server_command =
+ (p - linebuffer > SERVER_COMMAND_LENGTH)
+ && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
+ 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';
+ command_handler (linebuffer + SERVER_COMMAND_LENGTH);
+ display_gdb_prompt (0);
+ return;
+ }
+
+ /* 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)
+ {
+ xfree (history_value);
+ return;
+ }
+ if (strlen (history_value) > linelength)
+ {
+ linelength = strlen (history_value) + 1;
+ linebuffer = (char *) xrealloc (linebuffer, linelength);
+ }
+ strcpy (linebuffer, history_value);
+ p = linebuffer + strlen (linebuffer);
+ xfree (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 && *p != '\\')
+ {
+ command_handler (line);
+ display_gdb_prompt (0);
+ return;
+ }
+
+ for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
+ if (repeat && !*p1)
+ {
+ command_handler (line);
+ display_gdb_prompt (0);
+ return;
+ }
+
+ *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);
+ if (!more_to_come)
+ {
+ command_handler (line);
+ display_gdb_prompt (0);
+ }
+ return;
+ }
+
+ command_handler (linebuffer);
+ display_gdb_prompt (0);
+ return;
+}
+
+/* Does reading of input from terminal w/o the editing features
+ provided by the readline library. */
+
+/* NOTE: 1999-04-30 Asynchronous version of gdb_readline. gdb_readline
+ will become obsolete when the event loop is made the default
+ execution for gdb. */
+void
+gdb_readline2 (gdb_client_data client_data)
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+ static int done_once = 0;
+
+ /* Unbuffer the input stream, so that, later on, the calls to fgetc
+ fetch only one char at the time from the stream. The fgetc's will
+ get up to the first newline, but there may be more chars in the
+ stream after '\n'. If we buffer the input and fgetc drains the
+ stream, getting stuff beyond the newline as well, a select, done
+ afterwards will not trigger. */
+ if (!done_once && !ISATTY (instream))
+ {
+ setbuf (instream, NULL);
+ done_once = 1;
+ }
+
+ result = (char *) xmalloc (result_size);
+
+ /* We still need the while loop here, even though it would seem
+ obvious to invoke gdb_readline2 at every character entered. If
+ not using the readline library, the terminal is in cooked mode,
+ which sends the characters all at once. Poll will notice that the
+ input fd has changed state only after enter is pressed. At this
+ point we still need to fetch all the chars entered. */
+
+ 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;
+ xfree (result);
+ (*input_handler) (0);
+ }
+
+ if (c == '\n')
+#ifndef CRLF_SOURCE_FILES
+ break;
+#else
+ {
+ if (input_index > 0 && result[input_index - 1] == '\r')
+ input_index--;
+ break;
+ }
+#endif
+
+ result[input_index++] = c;
+ while (input_index >= result_size)
+ {
+ result_size *= 2;
+ result = (char *) xrealloc (result, result_size);
+ }
+ }
+
+ result[input_index++] = '\0';
+ (*input_handler) (result);
+}
+
+
+/* Initialization of signal handlers and tokens. There is a function
+ handle_sig* for each of the signals GDB cares about. Specifically:
+ SIGINT, SIGFPE, SIGQUIT, SIGTSTP, SIGHUP, SIGWINCH. These
+ functions are the actual signal handlers associated to the signals
+ via calls to signal(). The only job for these functions is to
+ enqueue the appropriate event/procedure with the event loop. Such
+ procedures are the old signal handlers. The event loop will take
+ care of invoking the queued procedures to perform the usual tasks
+ associated with the reception of the signal. */
+/* NOTE: 1999-04-30 This is the asynchronous version of init_signals.
+ init_signals will become obsolete as we move to have to event loop
+ as the default for gdb. */
+void
+async_init_signals (void)
+{
+ signal (SIGINT, handle_sigint);
+ sigint_token =
+ create_async_signal_handler (async_request_quit, NULL);
+
+ /* 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, handle_sigquit);
+ sigquit_token =
+ create_async_signal_handler (async_do_nothing, NULL);
+#ifdef SIGHUP
+ if (signal (SIGHUP, handle_sighup) != SIG_IGN)
+ sighup_token =
+ create_async_signal_handler (async_disconnect, NULL);
+ else
+ sighup_token =
+ create_async_signal_handler (async_do_nothing, NULL);
+#endif
+ signal (SIGFPE, handle_sigfpe);
+ sigfpe_token =
+ create_async_signal_handler (async_float_handler, NULL);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+ signal (SIGWINCH, handle_sigwinch);
+ sigwinch_token =
+ create_async_signal_handler (SIGWINCH_HANDLER, NULL);
+#endif
+#ifdef STOP_SIGNAL
+ sigtstp_token =
+ create_async_signal_handler (async_stop_sig, NULL);
+#endif
+
+}
+
+void
+mark_async_signal_handler_wrapper (void *token)
+{
+ mark_async_signal_handler ((struct async_signal_handler *) token);
+}
+
+/* Tell the event loop what to do if SIGINT is received.
+ See event-signal.c. */
+void
+handle_sigint (int sig)
+{
+ signal (sig, handle_sigint);
+
+ /* If immediate_quit is set, we go ahead and process the SIGINT right
+ away, even if we usually would defer this to the event loop. The
+ assumption here is that it is safe to process ^C immediately if
+ immediate_quit is set. If we didn't, SIGINT would be really
+ processed only the next time through the event loop. To get to
+ that point, though, the command that we want to interrupt needs to
+ finish first, which is unacceptable. */
+ if (immediate_quit)
+ async_request_quit (0);
+ else
+ /* If immediate quit is not set, we process SIGINT the next time
+ through the loop, which is fine. */
+ mark_async_signal_handler_wrapper (sigint_token);
+}
+
+/* Do the quit. All the checks have been done by the caller. */
+void
+async_request_quit (gdb_client_data arg)
+{
+ quit_flag = 1;
+ quit ();
+}
+
+/* Tell the event loop what to do if SIGQUIT is received.
+ See event-signal.c. */
+static void
+handle_sigquit (int sig)
+{
+ mark_async_signal_handler_wrapper (sigquit_token);
+ signal (sig, handle_sigquit);
+}
+
+/* Called by the event loop in response to a SIGQUIT. */
+static void
+async_do_nothing (gdb_client_data arg)
+{
+ /* Empty function body. */
+}
+
+#ifdef SIGHUP
+/* Tell the event loop what to do if SIGHUP is received.
+ See event-signal.c. */
+static void
+handle_sighup (int sig)
+{
+ mark_async_signal_handler_wrapper (sighup_token);
+ signal (sig, handle_sighup);
+}
+
+/* Called by the event loop to process a SIGHUP */
+static void
+async_disconnect (gdb_client_data arg)
+{
+ catch_errors (quit_cover, NULL,
+ "Could not kill the program being debugged",
+ RETURN_MASK_ALL);
+ signal (SIGHUP, SIG_DFL); /*FIXME: ??????????? */
+ kill (getpid (), SIGHUP);
+}
+#endif
+
+#ifdef STOP_SIGNAL
+void
+handle_stop_sig (int sig)
+{
+ mark_async_signal_handler_wrapper (sigtstp_token);
+ signal (sig, handle_stop_sig);
+}
+
+static void
+async_stop_sig (gdb_client_data arg)
+{
+ char *prompt = get_prompt ();
+#if STOP_SIGNAL == SIGTSTP
+ signal (SIGTSTP, SIG_DFL);
+#if HAVE_SIGPROCMASK
+ {
+ sigset_t zero;
+
+ sigemptyset (&zero);
+ sigprocmask (SIG_SETMASK, &zero, 0);
+ }
+#elif HAVE_SIGSETMASK
+ sigsetmask (0);
+#endif
+ kill (getpid (), SIGTSTP);
+ signal (SIGTSTP, handle_stop_sig);
+#else
+ signal (STOP_SIGNAL, handle_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 */
+
+/* Tell the event loop what to do if SIGFPE is received.
+ See event-signal.c. */
+static void
+handle_sigfpe (int sig)
+{
+ mark_async_signal_handler_wrapper (sigfpe_token);
+ signal (sig, handle_sigfpe);
+}
+
+/* Event loop will call this functin to process a SIGFPE. */
+static void
+async_float_handler (gdb_client_data arg)
+{
+ /* This message is based on ANSI C, section 4.7. Note that integer
+ divide by zero causes this, so "float" is a misnomer. */
+ error ("Erroneous arithmetic operation.");
+}
+
+/* Tell the event loop what to do if SIGWINCH is received.
+ See event-signal.c. */
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+static void
+handle_sigwinch (int sig)
+{
+ mark_async_signal_handler_wrapper (sigwinch_token);
+ signal (sig, handle_sigwinch);
+}
+#endif
+
+
+/* Called by do_setshow_command. */
+void
+set_async_editing_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ change_line_handler ();
+}
+
+/* Called by do_setshow_command. */
+void
+set_async_annotation_level (char *args, int from_tty, struct cmd_list_element *c)
+{
+ change_annotation_level ();
+}
+
+/* Called by do_setshow_command. */
+void
+set_async_prompt (char *args, int from_tty, struct cmd_list_element *c)
+{
+ PROMPT (0) = savestring (new_async_prompt, strlen (new_async_prompt));
+}
+
+/* Set things up for readline to be invoked via the alternate
+ interface, i.e. via a callback function (rl_callback_read_char),
+ and hook up instream to the event loop. */
+void
+gdb_setup_readline (void)
+{
+ /* This function is a noop for the sync case. The assumption is that
+ the sync setup is ALL done in gdb_init, and we would only mess it up
+ here. The sync stuff should really go away over time. */
+
+ if (event_loop_p)
+ {
+ gdb_stdout = stdio_fileopen (stdout);
+ gdb_stderr = stdio_fileopen (stderr);
+ gdb_stdlog = gdb_stderr; /* for moment */
+ gdb_stdtarg = gdb_stderr; /* for moment */
+
+ /* If the input stream is connected to a terminal, turn on
+ editing. */
+ if (ISATTY (instream))
+ {
+ /* Tell gdb that we will be using the readline library. This
+ could be overwritten by a command in .gdbinit like 'set
+ editing on' or 'off'. */
+ async_command_editing_p = 1;
+
+ /* When a character is detected on instream by select or
+ poll, readline will be invoked via this callback
+ function. */
+ call_readline = rl_callback_read_char_wrapper;
+ }
+ else
+ {
+ async_command_editing_p = 0;
+ call_readline = gdb_readline2;
+ }
+
+ /* When readline has read an end-of-line character, it passes
+ the complete line to gdb for processing. command_line_handler
+ is the function that does this. */
+ input_handler = command_line_handler;
+
+ /* Tell readline to use the same input stream that gdb uses. */
+ rl_instream = instream;
+
+ /* Get a file descriptor for the input stream, so that we can
+ register it with the event loop. */
+ input_fd = fileno (instream);
+
+ /* Now we need to create the event sources for the input file
+ descriptor. */
+ /* At this point in time, this is the only event source that we
+ register with the even loop. Another source is going to be
+ the target program (inferior), but that must be registered
+ only when it actually exists (I.e. after we say 'run' or
+ after we connect to a remote target. */
+ add_file_handler (input_fd, stdin_event_handler, 0);
+ }
+}
+
+/* Disable command input through the standard CLI channels. Used in
+ the suspend proc for interpreters that use the standard gdb readline
+ interface, like the cli & the mi. */
+void
+gdb_disable_readline (void)
+{
+ if (event_loop_p)
+ {
+ /* FIXME - It is too heavyweight to delete and remake these
+ every time you run an interpreter that needs readline.
+ It is probably better to have the interpreters cache these,
+ which in turn means that this needs to be moved into interpreter
+ specific code. */
+
+#if 0
+ ui_file_delete (gdb_stdout);
+ ui_file_delete (gdb_stderr);
+ gdb_stdlog = NULL;
+ gdb_stdtarg = NULL;
+#endif
+
+ rl_callback_handler_remove ();
+ delete_file_handler (input_fd);
+ }
+}
diff --git a/contrib/gdb/gdb/event-top.h b/contrib/gdb/gdb/event-top.h
new file mode 100644
index 0000000..7e48a6c
--- /dev/null
+++ b/contrib/gdb/gdb/event-top.h
@@ -0,0 +1,124 @@
+/* Definitions used by event-top.c, for GDB, the GNU debugger.
+
+ Copyright 1999, 2001, 2003 Free Software Foundation, Inc.
+
+ Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 EVENT_TOP_H
+#define EVENT_TOP_H
+
+struct cmd_list_element;
+
+/* Stack for prompts. Each prompt is composed as a prefix, a prompt
+ and a suffix. The prompt to be displayed at any given time is the
+ one on top of the stack. A stack is necessary because of cases in
+ which the execution of a gdb command requires further input from
+ the user, like for instance 'commands' for breakpoints and
+ 'actions' for tracepoints. In these cases, the prompt is '>' and
+ gdb should process input using the asynchronous readline interface
+ and the event loop. In order to achieve this, we need to save
+ somewhere the state of GDB, i.e. that it is processing user input
+ as part of a command and not as part of the top level command loop.
+ The prompt stack represents part of the saved state. Another part
+ would be the function that readline would invoke after a whole line
+ of input has ben entered. This second piece would be something
+ like, for instance, where to return within the code for the actions
+ commands after a line has been read. This latter portion has not
+ beeen implemented yet. The need for a 3-part prompt arises from
+ the annotation level. When this is set to 2, the prompt is
+ actually composed of a prefix, the prompt itself and a suffix. */
+
+/* At any particular time there will be always at least one prompt on
+ the stack, the one being currently displayed by gdb. If gdb is
+ using annotation level equal 2, there will be 2 prompts on the
+ stack: the usual one, w/o prefix and suffix (at top - 1), and the
+ 'composite' one with prefix and suffix added (at top). At this
+ time, this is the only use of the prompt stack. Resetting annotate
+ to 0 or 1, pops the top of the stack, resetting its size to one
+ element. The MAXPROMPTS limit is safe, for now. Once other cases
+ are dealt with (like the different prompts used for 'commands' or
+ 'actions') this array implementation of the prompt stack may have
+ to change. */
+
+#define MAXPROMPTS 10
+struct prompts
+ {
+ struct
+ {
+ char *prefix;
+ char *prompt;
+ char *suffix;
+ }
+ prompt_stack[MAXPROMPTS];
+ int top;
+ };
+
+#define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt
+#define PREFIX(X) the_prompts.prompt_stack[the_prompts.top + X].prefix
+#define SUFFIX(X) the_prompts.prompt_stack[the_prompts.top + X].suffix
+
+/* Exported functions from event-top.c.
+ FIXME: these should really go into top.h. */
+
+extern void display_gdb_prompt (char *new_prompt);
+void gdb_setup_readline (void);
+void gdb_disable_readline (void);
+extern void async_init_signals (void);
+extern void set_async_editing_command (char *args, int from_tty,
+ struct cmd_list_element *c);
+extern void set_async_annotation_level (char *args, int from_tty,
+ struct cmd_list_element *c);
+extern void set_async_prompt (char *args, int from_tty,
+ struct cmd_list_element *c);
+
+/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
+#ifndef STOP_SIGNAL
+#include <signal.h>
+#ifdef SIGTSTP
+#define STOP_SIGNAL SIGTSTP
+extern void handle_stop_sig (int sig);
+#endif
+#endif
+extern void handle_sigint (int sig);
+extern void pop_prompt (void);
+extern void push_prompt (char *prefix, char *prompt, char *suffix);
+extern void gdb_readline2 (void *client_data);
+extern void mark_async_signal_handler_wrapper (void *token);
+extern void async_request_quit (void *arg);
+extern void stdin_event_handler (int error, void *client_data);
+extern void async_disable_stdin (void);
+extern void async_enable_stdin (void *dummy);
+
+/* Exported variables from event-top.c.
+ FIXME: these should really go into top.h. */
+
+extern int async_command_editing_p;
+extern int exec_done_display_p;
+extern char *async_annotation_suffix;
+extern char *new_async_prompt;
+extern struct prompts the_prompts;
+extern void (*call_readline) (void *);
+extern void (*input_handler) (char *);
+extern int input_fd;
+extern void (*after_char_processing_hook) (void);
+
+extern void cli_command_loop (void);
+
+#endif
diff --git a/contrib/gdb/gdb/exc_request.defs b/contrib/gdb/gdb/exc_request.defs
new file mode 100644
index 0000000..9b5ed2e
--- /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 <mach/std_types.defs>
+
+#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 0000000..418b0b3
--- /dev/null
+++ b/contrib/gdb/gdb/exec.c
@@ -0,0 +1,761 @@
+/* Work with executable files, for GDB.
+
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "completer.h"
+#include "value.h"
+#include "exec.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <fcntl.h>
+#include "readline/readline.h"
+#include "gdb_string.h"
+
+#include "gdbcore.h"
+
+#include <ctype.h>
+#include "gdb_stat.h"
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#include "xcoffsolib.h"
+
+struct vmap *map_vmap (bfd *, bfd *);
+
+void (*file_changed_hook) (char *);
+
+/* Prototypes for local functions */
+
+static void exec_close (int);
+
+static void file_command (char *, int);
+
+static void set_section_command (char *, int);
+
+static void exec_files_info (struct target_ops *);
+
+static int ignore (CORE_ADDR, char *);
+
+static void init_exec_ops (void);
+
+void _initialize_exec (void);
+
+/* The target vector for executable files. */
+
+struct target_ops exec_ops;
+
+/* 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;
+
+struct vmap *vmap;
+
+void
+exec_open (char *args, int from_tty)
+{
+ target_preopen (from_tty);
+ exec_file_attach (args, from_tty);
+}
+
+static void
+exec_close (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);
+ xfree (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 ()));
+ xfree (name);
+ exec_bfd = NULL;
+ }
+
+ if (exec_ops.to_sections)
+ {
+ xfree (exec_ops.to_sections);
+ exec_ops.to_sections = NULL;
+ exec_ops.to_sections_end = NULL;
+ }
+}
+
+void
+exec_file_clear (int from_tty)
+{
+ /* Remove exec file. */
+ unpush_target (&exec_ops);
+
+ if (from_tty)
+ printf_unfiltered ("No executable file now.\n");
+}
+
+/* Process the first arg in ARGS as the new exec file.
+
+ This function is intended to be behave essentially the same
+ as exec_file_command, except that the latter will detect when
+ a target is being debugged, and will ask the user whether it
+ should be shut down first. (If the answer is "no", then the
+ new file is ignored.)
+
+ This file is used by exec_file_command, to do the work of opening
+ and processing the exec file after any prompting has happened.
+
+ And, it is used by child_attach, when the attach command was
+ given a pid but not a exec pathname, and the attach command could
+ figure out the pathname from the pid. (In this case, we shouldn't
+ ask the user whether the current target should be shut down --
+ we're supplying the exec pathname late for good reason.)
+
+ ARGS is assumed to be the filename. */
+
+void
+exec_file_attach (char *filename, int from_tty)
+{
+ /* Remove any previous exec file. */
+ unpush_target (&exec_ops);
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (!filename)
+ {
+ if (from_tty)
+ printf_unfiltered ("No executable file now.\n");
+ }
+ else
+ {
+ char *scratch_pathname;
+ int scratch_chan;
+
+ scratch_chan = openp (getenv ("PATH"), 1, filename,
+ write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0,
+ &scratch_pathname);
+#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__)
+ if (scratch_chan < 0)
+ {
+ char *exename = alloca (strlen (filename) + 5);
+ strcat (strcpy (exename, filename), ".exe");
+ scratch_chan = openp (getenv ("PATH"), 1, exename, write_files ?
+ O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0, &scratch_pathname);
+ }
+#endif
+ 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 = xstrdup (scratch_pathname);
+ make_cleanup (xfree, 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 DEPRECATED_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 /* DEPRECATED_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 DEPRECATED_HPUX_TEXT_END
+ DEPRECATED_HPUX_TEXT_END (&exec_ops);
+#endif
+
+ validate_files ();
+
+ set_gdbarch_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);
+ }
+}
+
+/* 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.
+
+ If ARGS is NULL, we just want to close the exec file. */
+
+static void
+exec_file_command (char *args, int from_tty)
+{
+ char **argv;
+ char *filename;
+
+ target_preopen (from_tty);
+
+ if (args)
+ {
+ /* 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 (argv);
+
+ for (; (*argv != NULL) && (**argv == '-'); argv++)
+ {;
+ }
+ if (*argv == NULL)
+ error ("No executable file name was specified");
+
+ filename = tilde_expand (*argv);
+ make_cleanup (xfree, filename);
+ exec_file_attach (filename, from_tty);
+ }
+ else
+ exec_file_attach (NULL, from_tty);
+}
+
+/* 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 (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);
+ if (file_changed_hook)
+ file_changed_hook (arg);
+}
+
+
+/* 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 (bfd *abfd, struct bfd_section *asect,
+ void *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 (struct bfd *some_bfd, struct section_table **start,
+ struct section_table **end)
+{
+ unsigned count;
+
+ count = bfd_count_sections (some_bfd);
+ if (*start)
+ xfree (* 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)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ /* We could realloc the table, but it probably loses for most files. */
+ return 0;
+}
+
+static void
+bfdsec_to_vmap (struct bfd *abfd, struct bfd_section *sect, void *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 (DEPRECATED_STREQ (bfd_section_name (abfd, sect), ".text"))
+ {
+ vp->tstart = bfd_section_vma (abfd, sect);
+ vp->tend = vp->tstart + bfd_section_size (abfd, sect);
+ vp->tvma = bfd_section_vma (abfd, sect);
+ vp->toffs = sect->filepos;
+ }
+ else if (DEPRECATED_STREQ (bfd_section_name (abfd, sect), ".data"))
+ {
+ vp->dstart = bfd_section_vma (abfd, sect);
+ vp->dend = vp->dstart + bfd_section_size (abfd, sect);
+ vp->dvma = bfd_section_vma (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 (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 (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ int res;
+ struct section_table *p;
+ CORE_ADDR nextsectaddr, memend;
+ asection *section = NULL;
+
+ if (len <= 0)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ if (overlay_debugging)
+ {
+ section = find_pc_overlay (memaddr);
+ if (pc_in_unmapped_range (memaddr, section))
+ memaddr = overlay_mapped_address (memaddr, section);
+ }
+
+ memend = memaddr + len;
+ nextsectaddr = memend;
+
+ for (p = target->to_sections; p < target->to_sections_end; p++)
+ {
+ if (overlay_debugging && section && p->the_bfd_section &&
+ strcmp (section->name, p->the_bfd_section->name) != 0)
+ continue; /* not the section we need */
+ if (memaddr >= p->addr)
+ {
+ if (memend <= p->endaddr)
+ {
+ /* Entire transfer is within this section. */
+ if (write)
+ res = bfd_set_section_contents (p->bfd, p->the_bfd_section,
+ myaddr, memaddr - p->addr,
+ len);
+ else
+ res = bfd_get_section_contents (p->bfd, p->the_bfd_section,
+ myaddr, memaddr - p->addr,
+ len);
+ return (res != 0) ? len : 0;
+ }
+ else if (memaddr >= p->endaddr)
+ {
+ /* This section ends before the transfer starts. */
+ continue;
+ }
+ else
+ {
+ /* This section overlaps the transfer. Just do half. */
+ len = p->endaddr - memaddr;
+ if (write)
+ res = bfd_set_section_contents (p->bfd, p->the_bfd_section,
+ myaddr, memaddr - p->addr,
+ len);
+ else
+ res = bfd_get_section_contents (p->bfd, p->the_bfd_section,
+ myaddr, memaddr - p->addr,
+ len);
+ return (res != 0) ? len : 0;
+ }
+ }
+ else
+ nextsectaddr = min (nextsectaddr, p->addr);
+ }
+
+ if (nextsectaddr >= memend)
+ return 0; /* We can't help */
+ else
+ return -(nextsectaddr - memaddr); /* Next boundary where we can help */
+}
+
+
+void
+print_section_info (struct target_ops *t, bfd *abfd)
+{
+ struct section_table *p;
+ /* FIXME: "016l" is not wide enough when TARGET_ADDR_BIT > 64. */
+ char *fmt = TARGET_ADDR_BIT <= 32 ? "08l" : "016l";
+
+ 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++)
+ {
+ printf_filtered ("\t%s", local_hex_string_custom (p->addr, fmt));
+ printf_filtered (" - %s", local_hex_string_custom (p->endaddr, fmt));
+
+ /* FIXME: A format of "08l" is not wide enough for file offsets
+ larger than 4GB. OTOH, making it "016l" isn't desirable either
+ since most output will then be much wider than necessary. It
+ may make sense to test the size of the file and choose the
+ format string accordingly. */
+ if (info_verbose)
+ printf_filtered (" @ %s",
+ local_hex_string_custom (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 (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 %*s %*s %*s %*s %8.8s %s\n",
+ strlen_paddr (), "tstart",
+ strlen_paddr (), "tend",
+ strlen_paddr (), "dstart",
+ strlen_paddr (), "dend",
+ "section",
+ "file(member)");
+
+ for (vp = vmap; vp; vp = vp->nxt)
+ printf_unfiltered ("\t0x%s 0x%s 0x%s 0x%s %s%s%s%s\n",
+ paddr (vp->tstart),
+ paddr (vp->tend),
+ paddr (vp->dstart),
+ paddr (vp->dend),
+ vp->name,
+ *vp->member ? "(" : "", vp->member,
+ *vp->member ? ")" : "");
+ }
+}
+
+/* msnyder 5/21/99:
+ exec_set_section_offsets sets the offsets of all the sections
+ in the exec objfile. */
+
+void
+exec_set_section_offsets (bfd_signed_vma text_off, bfd_signed_vma data_off,
+ bfd_signed_vma bss_off)
+{
+ struct section_table *sect;
+
+ for (sect = exec_ops.to_sections;
+ sect < exec_ops.to_sections_end;
+ sect++)
+ {
+ flagword flags;
+
+ flags = bfd_get_section_flags (exec_bfd, sect->the_bfd_section);
+
+ if (flags & SEC_CODE)
+ {
+ sect->addr += text_off;
+ sect->endaddr += text_off;
+ }
+ else if (flags & (SEC_DATA | SEC_LOAD))
+ {
+ sect->addr += data_off;
+ sect->endaddr += data_off;
+ }
+ else if (flags & SEC_ALLOC)
+ {
+ sect->addr += bss_off;
+ sect->endaddr += bss_off;
+ }
+ }
+}
+
+static void
+set_section_command (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 (CORE_ADDR addr, char *contents)
+{
+ return 0;
+}
+
+/* Find mapped memory. */
+
+extern void
+exec_set_find_memory_regions (int (*func) (int (*) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *))
+{
+ exec_ops.to_find_memory_regions = func;
+}
+
+static char *exec_make_note_section (bfd *, int *);
+
+/* Fill in the exec file target vector. Very few entries need to be
+ defined. */
+
+static void
+init_exec_ops (void)
+{
+ exec_ops.to_shortname = "exec";
+ exec_ops.to_longname = "Local exec file";
+ exec_ops.to_doc = "Use an executable file as a target.\n\
+Specify the filename of the executable file.";
+ exec_ops.to_open = exec_open;
+ exec_ops.to_close = exec_close;
+ exec_ops.to_attach = find_default_attach;
+ exec_ops.to_xfer_memory = xfer_memory;
+ exec_ops.to_files_info = exec_files_info;
+ exec_ops.to_insert_breakpoint = ignore;
+ exec_ops.to_remove_breakpoint = ignore;
+ exec_ops.to_create_inferior = find_default_create_inferior;
+ exec_ops.to_stratum = file_stratum;
+ exec_ops.to_has_memory = 1;
+ exec_ops.to_make_corefile_notes = exec_make_note_section;
+ exec_ops.to_magic = OPS_MAGIC;
+}
+
+void
+_initialize_exec (void)
+{
+ struct cmd_list_element *c;
+
+ init_exec_ops ();
+
+ if (!dbx_commands)
+ {
+ 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);
+ set_cmd_completer (c, 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);
+ set_cmd_completer (c, 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);
+}
+
+static char *
+exec_make_note_section (bfd *obfd, int *note_size)
+{
+ error ("Can't create a corefile");
+}
diff --git a/contrib/gdb/gdb/exec.h b/contrib/gdb/gdb/exec.h
new file mode 100644
index 0000000..d086251
--- /dev/null
+++ b/contrib/gdb/gdb/exec.h
@@ -0,0 +1,39 @@
+/* Work with executable files, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 EXEC_H
+#define EXEC_H
+
+#include "target.h"
+
+struct section_table;
+struct target_ops;
+struct bfd;
+
+extern struct target_ops exec_ops;
+
+/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
+ Returns 0 if OK, 1 on error. */
+
+extern int build_section_table (struct bfd *, struct section_table **,
+ struct section_table **);
+
+#endif
diff --git a/contrib/gdb/gdb/expprint.c b/contrib/gdb/gdb/expprint.c
new file mode 100644
index 0000000..5949475
--- /dev/null
+++ b/contrib/gdb/gdb/expprint.c
@@ -0,0 +1,1069 @@
+/* Print in infix form a struct expression.
+
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "user-regs.h" /* For user_reg_map_regnum_to_name. */
+#include "target.h"
+#include "gdb_string.h"
+#include "block.h"
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+void
+print_expression (struct expression *exp, struct ui_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. */
+
+void
+print_subexp (struct expression *exp, int *pos,
+ struct ui_file *stream, enum precedence prec)
+{
+ exp->language_defn->la_exp_desc->print_subexp (exp, pos, stream, prec);
+}
+
+/* Standard implementation of print_subexp for use in language_defn
+ vectors. */
+void
+print_subexp_standard (struct expression *exp, int *pos,
+ struct ui_file *stream, enum precedence prec)
+{
+ unsigned tem;
+ const struct op_print *op_print_tab;
+ int pc;
+ unsigned nargs;
+ 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;
+ struct value *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_PRINT_NAME (BLOCK_FUNCTION (b)) != NULL)
+ {
+ fputs_filtered (SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)), stream);
+ fputs_filtered ("::", stream);
+ }
+ fputs_filtered (SYMBOL_PRINT_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:
+ {
+ int regnum = longest_to_int (exp->elts[pc + 1].longconst);
+ const char *name = user_reg_map_regnum_to_name (current_gdbarch,
+ regnum);
+ (*pos) += 2;
+ fprintf_filtered (stream, "$%s", name);
+ 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, 1, 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_unfiltered (stream, "B'<unimplemented>'");
+ return;
+
+ case OP_OBJC_NSSTRING: /* Objective-C Foundation Class NSString constant. */
+ nargs = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
+ fputs_filtered ("@\"", stream);
+ LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 1, 0);
+ fputs_filtered ("\"", stream);
+ return;
+
+ case OP_OBJC_MSGCALL:
+ { /* Objective C message (method) call. */
+ char *selector;
+ (*pos) += 3;
+ nargs = longest_to_int (exp->elts[pc + 2].longconst);
+ fprintf_unfiltered (stream, "[");
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ if (0 == target_read_string (exp->elts[pc + 1].longconst,
+ &selector, 1024, NULL))
+ {
+ error ("bad selector");
+ return;
+ }
+ if (nargs)
+ {
+ char *s, *nextS;
+ s = alloca (strlen (selector) + 1);
+ strcpy (s, selector);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ nextS = strchr (s, ':');
+ *nextS = '\0';
+ fprintf_unfiltered (stream, " %s: ", s);
+ s = nextS + 1;
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ }
+ else
+ {
+ fprintf_unfiltered (stream, " %s", selector);
+ }
+ fprintf_unfiltered (stream, "]");
+ /* "selector" was malloc'd by target_read_string. Free it. */
+ xfree (selector);
+ 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, 1, 0);
+ (*pos) = pc;
+ }
+ else
+ {
+ 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_LABELED:
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ /* Gcc support both these syntaxes. Unsure which is preferred. */
+#if 1
+ fputs_filtered (&exp->elts[pc + 2].string, stream);
+ fputs_filtered (": ", stream);
+#else
+ fputs_filtered (".", stream);
+ fputs_filtered (&exp->elts[pc + 2].string, stream);
+ fputs_filtered ("=", stream);
+#endif
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ return;
+
+ case TERNOP_COND:
+ if ((int) prec > (int) PREC_COMMA)
+ fputs_filtered ("(", stream);
+ /* 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 (TYPE_CODE (exp->elts[pc + 1].type) == 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,
+ NULL);
+ 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;
+
+ /* Objective-C ops */
+
+ case OP_OBJC_SELF:
+ ++(*pos);
+ fputs_filtered ("self", stream); /* The ObjC equivalent of "this". */
+ 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 (enum exp_opcode op)
+{
+ int tem;
+ 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;
+}
+
+/* Support for dumping the raw data from expressions in a human readable
+ form. */
+
+static char *op_name (struct expression *, enum exp_opcode);
+static int dump_subexp_body (struct expression *exp, struct ui_file *, int);
+
+/* Name for OPCODE, when it appears in expression EXP. */
+
+static char *
+op_name (struct expression *exp, enum exp_opcode opcode)
+{
+ return exp->language_defn->la_exp_desc->op_name (opcode);
+}
+
+/* Default name for the standard operator OPCODE (i.e., one defined in
+ the definition of enum exp_opcode). */
+
+char *
+op_name_standard (enum exp_opcode opcode)
+{
+ switch (opcode)
+ {
+ default:
+ {
+ static char buf[30];
+
+ sprintf (buf, "<unknown %d>", opcode);
+ return buf;
+ }
+ case OP_NULL:
+ return "OP_NULL";
+ case BINOP_ADD:
+ return "BINOP_ADD";
+ case BINOP_SUB:
+ return "BINOP_SUB";
+ case BINOP_MUL:
+ return "BINOP_MUL";
+ case BINOP_DIV:
+ return "BINOP_DIV";
+ case BINOP_REM:
+ return "BINOP_REM";
+ case BINOP_MOD:
+ return "BINOP_MOD";
+ case BINOP_LSH:
+ return "BINOP_LSH";
+ case BINOP_RSH:
+ return "BINOP_RSH";
+ case BINOP_LOGICAL_AND:
+ return "BINOP_LOGICAL_AND";
+ case BINOP_LOGICAL_OR:
+ return "BINOP_LOGICAL_OR";
+ case BINOP_BITWISE_AND:
+ return "BINOP_BITWISE_AND";
+ case BINOP_BITWISE_IOR:
+ return "BINOP_BITWISE_IOR";
+ case BINOP_BITWISE_XOR:
+ return "BINOP_BITWISE_XOR";
+ case BINOP_EQUAL:
+ return "BINOP_EQUAL";
+ case BINOP_NOTEQUAL:
+ return "BINOP_NOTEQUAL";
+ case BINOP_LESS:
+ return "BINOP_LESS";
+ case BINOP_GTR:
+ return "BINOP_GTR";
+ case BINOP_LEQ:
+ return "BINOP_LEQ";
+ case BINOP_GEQ:
+ return "BINOP_GEQ";
+ case BINOP_REPEAT:
+ return "BINOP_REPEAT";
+ case BINOP_ASSIGN:
+ return "BINOP_ASSIGN";
+ case BINOP_COMMA:
+ return "BINOP_COMMA";
+ case BINOP_SUBSCRIPT:
+ return "BINOP_SUBSCRIPT";
+ case MULTI_SUBSCRIPT:
+ return "MULTI_SUBSCRIPT";
+ case BINOP_EXP:
+ return "BINOP_EXP";
+ case BINOP_MIN:
+ return "BINOP_MIN";
+ case BINOP_MAX:
+ return "BINOP_MAX";
+ case STRUCTOP_MEMBER:
+ return "STRUCTOP_MEMBER";
+ case STRUCTOP_MPTR:
+ return "STRUCTOP_MPTR";
+ case BINOP_INTDIV:
+ return "BINOP_INTDIV";
+ case BINOP_ASSIGN_MODIFY:
+ return "BINOP_ASSIGN_MODIFY";
+ case BINOP_VAL:
+ return "BINOP_VAL";
+ case BINOP_INCL:
+ return "BINOP_INCL";
+ case BINOP_EXCL:
+ return "BINOP_EXCL";
+ case BINOP_CONCAT:
+ return "BINOP_CONCAT";
+ case BINOP_RANGE:
+ return "BINOP_RANGE";
+ case BINOP_END:
+ return "BINOP_END";
+ case TERNOP_COND:
+ return "TERNOP_COND";
+ case TERNOP_SLICE:
+ return "TERNOP_SLICE";
+ case TERNOP_SLICE_COUNT:
+ return "TERNOP_SLICE_COUNT";
+ case OP_LONG:
+ return "OP_LONG";
+ case OP_DOUBLE:
+ return "OP_DOUBLE";
+ case OP_VAR_VALUE:
+ return "OP_VAR_VALUE";
+ case OP_LAST:
+ return "OP_LAST";
+ case OP_REGISTER:
+ return "OP_REGISTER";
+ case OP_INTERNALVAR:
+ return "OP_INTERNALVAR";
+ case OP_FUNCALL:
+ return "OP_FUNCALL";
+ case OP_STRING:
+ return "OP_STRING";
+ case OP_BITSTRING:
+ return "OP_BITSTRING";
+ case OP_ARRAY:
+ return "OP_ARRAY";
+ case UNOP_CAST:
+ return "UNOP_CAST";
+ case UNOP_MEMVAL:
+ return "UNOP_MEMVAL";
+ case UNOP_NEG:
+ return "UNOP_NEG";
+ case UNOP_LOGICAL_NOT:
+ return "UNOP_LOGICAL_NOT";
+ case UNOP_COMPLEMENT:
+ return "UNOP_COMPLEMENT";
+ case UNOP_IND:
+ return "UNOP_IND";
+ case UNOP_ADDR:
+ return "UNOP_ADDR";
+ case UNOP_PREINCREMENT:
+ return "UNOP_PREINCREMENT";
+ case UNOP_POSTINCREMENT:
+ return "UNOP_POSTINCREMENT";
+ case UNOP_PREDECREMENT:
+ return "UNOP_PREDECREMENT";
+ case UNOP_POSTDECREMENT:
+ return "UNOP_POSTDECREMENT";
+ case UNOP_SIZEOF:
+ return "UNOP_SIZEOF";
+ case UNOP_LOWER:
+ return "UNOP_LOWER";
+ case UNOP_UPPER:
+ return "UNOP_UPPER";
+ case UNOP_LENGTH:
+ return "UNOP_LENGTH";
+ case UNOP_PLUS:
+ return "UNOP_PLUS";
+ case UNOP_CAP:
+ return "UNOP_CAP";
+ case UNOP_CHR:
+ return "UNOP_CHR";
+ case UNOP_ORD:
+ return "UNOP_ORD";
+ case UNOP_ABS:
+ return "UNOP_ABS";
+ case UNOP_FLOAT:
+ return "UNOP_FLOAT";
+ case UNOP_HIGH:
+ return "UNOP_HIGH";
+ case UNOP_MAX:
+ return "UNOP_MAX";
+ case UNOP_MIN:
+ return "UNOP_MIN";
+ case UNOP_ODD:
+ return "UNOP_ODD";
+ case UNOP_TRUNC:
+ return "UNOP_TRUNC";
+ case OP_BOOL:
+ return "OP_BOOL";
+ case OP_M2_STRING:
+ return "OP_M2_STRING";
+ case STRUCTOP_STRUCT:
+ return "STRUCTOP_STRUCT";
+ case STRUCTOP_PTR:
+ return "STRUCTOP_PTR";
+ case OP_THIS:
+ return "OP_THIS";
+ case OP_OBJC_SELF:
+ return "OP_OBJC_SELF";
+ case OP_SCOPE:
+ return "OP_SCOPE";
+ case OP_TYPE:
+ return "OP_TYPE";
+ case OP_LABELED:
+ return "OP_LABELED";
+ }
+}
+
+void
+dump_raw_expression (struct expression *exp, struct ui_file *stream,
+ char *note)
+{
+ int elt;
+ char *opcode_name;
+ char *eltscan;
+ int eltsize;
+
+ fprintf_filtered (stream, "Dump of expression @ ");
+ gdb_print_host_address (exp, stream);
+ fprintf_filtered (stream, "'\n\tLanguage %s, %d elements, %ld bytes each.\n",
+ exp->language_defn->la_name, exp->nelts,
+ (long) sizeof (union exp_element));
+ 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);
+ opcode_name = op_name (exp, exp->elts[elt].opcode);
+
+ fprintf_filtered (stream, "%20s ", opcode_name);
+ print_longest (stream, 'd', 0, exp->elts[elt].longconst);
+ fprintf_filtered (stream, " ");
+
+ 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");
+ }
+}
+
+/* Dump the subexpression of prefix expression EXP whose operator is at
+ position ELT onto STREAM. Returns the position of the next
+ subexpression in EXP. */
+
+int
+dump_subexp (struct expression *exp, struct ui_file *stream, int elt)
+{
+ static int indent = 0;
+ int i;
+
+ fprintf_filtered (stream, "\n");
+ fprintf_filtered (stream, "\t%5d ", elt);
+
+ for (i = 1; i <= indent; i++)
+ fprintf_filtered (stream, " ");
+ indent += 2;
+
+ fprintf_filtered (stream, "%-20s ", op_name (exp, exp->elts[elt].opcode));
+
+ elt = dump_subexp_body (exp, stream, elt);
+
+ indent -= 2;
+
+ return elt;
+}
+
+/* Dump the operands of prefix expression EXP whose opcode is at
+ position ELT onto STREAM. Returns the position of the next
+ subexpression in EXP. */
+
+static int
+dump_subexp_body (struct expression *exp, struct ui_file *stream, int elt)
+{
+ return exp->language_defn->la_exp_desc->dump_subexp_body (exp, stream, elt);
+}
+
+/* Default value for subexp_body in exp_descriptor vector. */
+
+int
+dump_subexp_body_standard (struct expression *exp,
+ struct ui_file *stream, int elt)
+{
+ int opcode = exp->elts[elt++].opcode;
+
+ switch (opcode)
+ {
+ case TERNOP_COND:
+ case TERNOP_SLICE:
+ case TERNOP_SLICE_COUNT:
+ elt = dump_subexp (exp, stream, elt);
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_MOD:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ case BINOP_LOGICAL_AND:
+ case BINOP_LOGICAL_OR:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+ case BINOP_REPEAT:
+ case BINOP_ASSIGN:
+ case BINOP_COMMA:
+ case BINOP_SUBSCRIPT:
+ case BINOP_EXP:
+ case BINOP_MIN:
+ case BINOP_MAX:
+ case BINOP_INTDIV:
+ case BINOP_ASSIGN_MODIFY:
+ case BINOP_VAL:
+ case BINOP_INCL:
+ case BINOP_EXCL:
+ case BINOP_CONCAT:
+ case BINOP_IN:
+ case BINOP_RANGE:
+ case BINOP_END:
+ elt = dump_subexp (exp, stream, elt);
+ case UNOP_NEG:
+ case UNOP_LOGICAL_NOT:
+ case UNOP_COMPLEMENT:
+ case UNOP_IND:
+ case UNOP_ADDR:
+ case UNOP_PREINCREMENT:
+ case UNOP_POSTINCREMENT:
+ case UNOP_PREDECREMENT:
+ case UNOP_POSTDECREMENT:
+ case UNOP_SIZEOF:
+ case UNOP_PLUS:
+ case UNOP_CAP:
+ case UNOP_CHR:
+ case UNOP_ORD:
+ case UNOP_ABS:
+ case UNOP_FLOAT:
+ case UNOP_HIGH:
+ case UNOP_MAX:
+ case UNOP_MIN:
+ case UNOP_ODD:
+ case UNOP_TRUNC:
+ case UNOP_LOWER:
+ case UNOP_UPPER:
+ case UNOP_LENGTH:
+ case UNOP_CARD:
+ case UNOP_CHMAX:
+ case UNOP_CHMIN:
+ elt = dump_subexp (exp, stream, elt);
+ break;
+ case OP_LONG:
+ fprintf_filtered (stream, "Type @");
+ gdb_print_host_address (exp->elts[elt].type, stream);
+ fprintf_filtered (stream, " (");
+ type_print (exp->elts[elt].type, NULL, stream, 0);
+ fprintf_filtered (stream, "), value %ld (0x%lx)",
+ (long) exp->elts[elt + 1].longconst,
+ (long) exp->elts[elt + 1].longconst);
+ elt += 3;
+ break;
+ case OP_DOUBLE:
+ fprintf_filtered (stream, "Type @");
+ gdb_print_host_address (exp->elts[elt].type, stream);
+ fprintf_filtered (stream, " (");
+ type_print (exp->elts[elt].type, NULL, stream, 0);
+ fprintf_filtered (stream, "), value %g",
+ (double) exp->elts[elt + 1].doubleconst);
+ elt += 3;
+ break;
+ case OP_VAR_VALUE:
+ fprintf_filtered (stream, "Block @");
+ gdb_print_host_address (exp->elts[elt].block, stream);
+ fprintf_filtered (stream, ", symbol @");
+ gdb_print_host_address (exp->elts[elt + 1].symbol, stream);
+ fprintf_filtered (stream, " (%s)",
+ DEPRECATED_SYMBOL_NAME (exp->elts[elt + 1].symbol));
+ elt += 3;
+ break;
+ case OP_LAST:
+ fprintf_filtered (stream, "History element %ld",
+ (long) exp->elts[elt].longconst);
+ elt += 2;
+ break;
+ case OP_REGISTER:
+ fprintf_filtered (stream, "Register %ld",
+ (long) exp->elts[elt].longconst);
+ elt += 2;
+ break;
+ case OP_INTERNALVAR:
+ fprintf_filtered (stream, "Internal var @");
+ gdb_print_host_address (exp->elts[elt].internalvar, stream);
+ fprintf_filtered (stream, " (%s)",
+ exp->elts[elt].internalvar->name);
+ elt += 2;
+ break;
+ case OP_FUNCALL:
+ {
+ int i, nargs;
+
+ nargs = longest_to_int (exp->elts[elt].longconst);
+
+ fprintf_filtered (stream, "Number of args: %d", nargs);
+ elt += 2;
+
+ for (i = 1; i <= nargs + 1; i++)
+ elt = dump_subexp (exp, stream, elt);
+ }
+ break;
+ case OP_ARRAY:
+ {
+ int lower, upper;
+ int i;
+
+ lower = longest_to_int (exp->elts[elt].longconst);
+ upper = longest_to_int (exp->elts[elt + 1].longconst);
+
+ fprintf_filtered (stream, "Bounds [%d:%d]", lower, upper);
+ elt += 3;
+
+ for (i = 1; i <= upper - lower + 1; i++)
+ elt = dump_subexp (exp, stream, elt);
+ }
+ break;
+ case UNOP_MEMVAL:
+ case UNOP_CAST:
+ fprintf_filtered (stream, "Type @");
+ gdb_print_host_address (exp->elts[elt].type, stream);
+ fprintf_filtered (stream, " (");
+ type_print (exp->elts[elt].type, NULL, stream, 0);
+ fprintf_filtered (stream, ")");
+ elt = dump_subexp (exp, stream, elt + 2);
+ break;
+ case OP_TYPE:
+ fprintf_filtered (stream, "Type @");
+ gdb_print_host_address (exp->elts[elt].type, stream);
+ fprintf_filtered (stream, " (");
+ type_print (exp->elts[elt].type, NULL, stream, 0);
+ fprintf_filtered (stream, ")");
+ elt += 2;
+ break;
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ {
+ char *elem_name;
+ int len;
+
+ len = longest_to_int (exp->elts[elt].longconst);
+ elem_name = &exp->elts[elt + 1].string;
+
+ fprintf_filtered (stream, "Element name: `%.*s'", len, elem_name);
+ elt = dump_subexp (exp, stream, elt + 3 + BYTES_TO_EXP_ELEM (len + 1));
+ }
+ break;
+ case OP_SCOPE:
+ {
+ char *elem_name;
+ int len;
+
+ fprintf_filtered (stream, "Type @");
+ gdb_print_host_address (exp->elts[elt].type, stream);
+ fprintf_filtered (stream, " (");
+ type_print (exp->elts[elt].type, NULL, stream, 0);
+ fprintf_filtered (stream, ") ");
+
+ len = longest_to_int (exp->elts[elt + 1].longconst);
+ elem_name = &exp->elts[elt + 2].string;
+
+ fprintf_filtered (stream, "Field name: `%.*s'", len, elem_name);
+ elt += 4 + BYTES_TO_EXP_ELEM (len + 1);
+ }
+ break;
+ default:
+ case OP_NULL:
+ case STRUCTOP_MEMBER:
+ case STRUCTOP_MPTR:
+ case MULTI_SUBSCRIPT:
+ case OP_F77_UNDETERMINED_ARGLIST:
+ case OP_COMPLEX:
+ case OP_STRING:
+ case OP_BITSTRING:
+ case OP_BOOL:
+ case OP_M2_STRING:
+ case OP_THIS:
+ case OP_LABELED:
+ case OP_NAME:
+ case OP_EXPRSTRING:
+ fprintf_filtered (stream, "Unknown format");
+ }
+
+ return elt;
+}
+
+void
+dump_prefix_expression (struct expression *exp, struct ui_file *stream)
+{
+ int elt;
+
+ fprintf_filtered (stream, "Dump of expression @ ");
+ gdb_print_host_address (exp, stream);
+ fputs_filtered (", after conversion to prefix form:\nExpression: `", stream);
+ if (exp->elts[0].opcode != OP_TYPE)
+ print_expression (exp, stream);
+ else
+ fputs_filtered ("Type printing not yet supported....", stream);
+ fprintf_filtered (stream, "'\n\tLanguage %s, %d elements, %ld bytes each.\n",
+ exp->language_defn->la_name, exp->nelts,
+ (long) sizeof (union exp_element));
+ fputs_filtered ("\n", stream);
+
+ for (elt = 0; elt < exp->nelts;)
+ elt = dump_subexp (exp, stream, elt);
+ fputs_filtered ("\n", stream);
+}
diff --git a/contrib/gdb/gdb/expression.h b/contrib/gdb/gdb/expression.h
new file mode 100644
index 0000000..03b45c2
--- /dev/null
+++ b/contrib/gdb/gdb/expression.h
@@ -0,0 +1,419 @@
+/* Definitions for expressions stored in reversed prefix form, for GDB.
+
+ Copyright 1986, 1989, 1992, 1994, 2000, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+
+#include "symtab.h" /* Needed for "struct block" type. */
+#include "doublest.h" /* Needed for DOUBLEST. */
+
+
+/* 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_MAX, /* >? */
+
+ /* 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 (the deleted) Chill and Pascal. */
+ BINOP_IN, /* Returns 1 iff ARG1 IN ARG2. */
+
+ /* This is the "colon operator" used various places in (the
+ deleted) 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. (the deleted) Chill syntax:
+ OP1(OP2:OP3). Return elements OP2 through OP3 of OP1. */
+ TERNOP_SLICE,
+
+ /* A sub-string/sub-array. (The deleted) 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. <OP><dimension><OP>.
+ 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,
+
+ /* OP_OBJC_MSGCALL is followed by a string in the next exp_element and then an
+ integer. The string is the selector string. The integer is the number
+ of arguments to the message call. That many plus one values are used,
+ the first one being the object pointer. This is an Objective C message */
+ OP_OBJC_MSGCALL,
+
+ /* 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 <name> ( <stuff> ) */
+ 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,
+
+ /* (The deleted) 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,
+
+ /* Objective-C: OP_OBJC_SELF is just a placeholder for the class instance
+ variable. It just comes in a tight (OP_OBJC_SELF, OP_OBJC_SELF) pair. */
+ OP_OBJC_SELF,
+
+ /* Objective C: "@selector" pseudo-operator */
+ OP_OBJC_SELECTOR,
+
+ /* 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 (the deleted)
+ Chill).
+
+ The gcc C syntax is NAME:VALUE or .NAME=VALUE, the (the
+ deleted) Chill syntax is .NAME:VALUE. Multiple labels (as in
+ the (the deleted) Chill syntax .NAME1,.NAME2:VALUE) is
+ represented as if it were .NAME1:(.NAME2:VALUE) (though that is
+ not valid (the deleted) Chill syntax).
+
+ The NAME is represented as for STRUCTOP_STRUCT; VALUE follows. */
+ OP_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,
+
+ /* An Objective C Foundation Class NSString constant */
+ OP_OBJC_NSSTRING,
+
+ /* First extension operator. Individual language modules define
+ extra operators they need as constants with values
+ OP_LANGUAGE_SPECIFIC0 + k, for k >= 0, using a separate
+ enumerated type definition:
+ enum foo_extension_operator {
+ BINOP_MOGRIFY = OP_EXTENDED0,
+ BINOP_FROB,
+ ...
+ }; */
+ OP_EXTENDED0,
+
+ /* Last possible extension operator. Defined to provide an
+ explicit and finite number of extended operators. */
+ OP_EXTENDED_LAST = 0xff
+ /* NOTE: Eventually, we expect to convert to an object-oriented
+ formulation for expression operators that does away with the
+ need for these extension operators, and indeed for this
+ entire enumeration type. Therefore, consider the OP_EXTENDED
+ definitions to be a temporary measure. */
+ };
+
+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 (char *);
+
+extern struct expression *parse_exp_1 (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_<whatever>, 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
+ (struct type *, struct expression *, int *, enum noside);
+
+/* From expprint.c */
+
+extern void print_expression (struct expression *, struct ui_file *);
+
+extern char *op_string (enum exp_opcode);
+
+extern void dump_raw_expression (struct expression *, struct ui_file *, char *);
+extern void dump_prefix_expression (struct expression *, struct ui_file *);
+
+#endif /* !defined (EXPRESSION_H) */
diff --git a/contrib/gdb/gdb/f-exp.c b/contrib/gdb/gdb/f-exp.c
new file mode 100644
index 0000000..250de12
--- /dev/null
+++ b/contrib/gdb/gdb/f-exp.c
@@ -0,0 +1,2564 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ FLOAT = 259,
+ STRING_LITERAL = 260,
+ BOOLEAN_LITERAL = 261,
+ NAME = 262,
+ TYPENAME = 263,
+ NAME_OR_INT = 264,
+ SIZEOF = 265,
+ ERROR = 266,
+ INT_KEYWORD = 267,
+ INT_S2_KEYWORD = 268,
+ LOGICAL_S1_KEYWORD = 269,
+ LOGICAL_S2_KEYWORD = 270,
+ LOGICAL_KEYWORD = 271,
+ REAL_KEYWORD = 272,
+ REAL_S8_KEYWORD = 273,
+ REAL_S16_KEYWORD = 274,
+ COMPLEX_S8_KEYWORD = 275,
+ COMPLEX_S16_KEYWORD = 276,
+ COMPLEX_S32_KEYWORD = 277,
+ BOOL_AND = 278,
+ BOOL_OR = 279,
+ BOOL_NOT = 280,
+ CHARACTER = 281,
+ VARIABLE = 282,
+ ASSIGN_MODIFY = 283,
+ ABOVE_COMMA = 284,
+ NOTEQUAL = 285,
+ EQUAL = 286,
+ GEQ = 287,
+ LEQ = 288,
+ GREATERTHAN = 289,
+ LESSTHAN = 290,
+ RSH = 291,
+ LSH = 292,
+ UNARY = 293
+ };
+#endif
+#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 NOTEQUAL 285
+#define EQUAL 286
+#define GEQ 287
+#define LEQ 288
+#define GREATERTHAN 289
+#define LESSTHAN 290
+#define RSH 291
+#define LSH 292
+#define UNARY 293
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 44 "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 */
+#include "block.h"
+#include <ctype.h>
+
+/* 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 yyname f_name /* With YYDEBUG defined */
+#define yyrule f_rule /* 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 yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static void growbuf_by_size (int);
+
+static int match_string_literal (void);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 130 "f-exp.y"
+typedef union YYSTYPE {
+ 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 191 of yacc.c. */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+#line 151 "f-exp.y"
+
+/* YYSTYPE gets defined by %union */
+static int parse_number (char *, int, int, YYSTYPE *);
+
+
+/* Line 214 of yacc.c. */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC xmalloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 46
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 460
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 55
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 17
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 80
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 125
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 293
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 13, 16, 19, 22,
+ 25, 28, 31, 32, 38, 39, 41, 43, 47, 51,
+ 55, 59, 64, 68, 72, 76, 80, 84, 88, 92,
+ 96, 100, 104, 108, 112, 116, 120, 124, 128, 132,
+ 136, 140, 144, 148, 150, 152, 154, 156, 158, 163,
+ 165, 167, 169, 171, 173, 176, 178, 181, 183, 186,
+ 188, 192, 195, 197, 200, 204, 206, 208, 210, 212,
+ 214, 216, 218, 220, 222, 224, 226, 228, 230, 232,
+ 236
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 56, 0, -1, 58, -1, 57, -1, 64, -1, 51,
+ 58, 52, -1, 47, 58, -1, 35, 58, -1, 46,
+ 58, -1, 25, 58, -1, 53, 58, -1, 10, 58,
+ -1, -1, 58, 51, 59, 60, 52, -1, -1, 58,
+ -1, 61, -1, 60, 29, 58, -1, 58, 54, 58,
+ -1, 58, 29, 58, -1, 51, 62, 52, -1, 51,
+ 64, 52, 58, -1, 58, 44, 58, -1, 58, 47,
+ 58, -1, 58, 48, 58, -1, 58, 49, 58, -1,
+ 58, 45, 58, -1, 58, 46, 58, -1, 58, 43,
+ 58, -1, 58, 42, 58, -1, 58, 37, 58, -1,
+ 58, 36, 58, -1, 58, 39, 58, -1, 58, 38,
+ 58, -1, 58, 41, 58, -1, 58, 40, 58, -1,
+ 58, 35, 58, -1, 58, 34, 58, -1, 58, 33,
+ 58, -1, 58, 23, 58, -1, 58, 24, 58, -1,
+ 58, 31, 58, -1, 58, 28, 58, -1, 3, -1,
+ 9, -1, 4, -1, 63, -1, 27, -1, 10, 51,
+ 64, 52, -1, 6, -1, 5, -1, 71, -1, 65,
+ -1, 69, -1, 69, 66, -1, 47, -1, 47, 66,
+ -1, 35, -1, 35, 66, -1, 67, -1, 51, 66,
+ 52, -1, 67, 68, -1, 68, -1, 51, 52, -1,
+ 51, 70, 52, -1, 8, -1, 12, -1, 13, -1,
+ 26, -1, 16, -1, 15, -1, 14, -1, 17, -1,
+ 18, -1, 19, -1, 20, -1, 21, -1, 22, -1,
+ 64, -1, 70, 29, 64, -1, 7, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 228, 228, 229, 232, 238, 243, 247, 251, 255,
+ 259, 263, 273, 272, 280, 283, 287, 291, 295, 300,
+ 304, 308, 316, 320, 324, 328, 332, 336, 340, 344,
+ 348, 352, 356, 360, 364, 368, 372, 376, 380, 384,
+ 389, 393, 397, 403, 410, 419, 426, 429, 432, 440,
+ 447, 455, 499, 502, 503, 546, 548, 550, 552, 554,
+ 557, 559, 561, 565, 567, 572, 574, 576, 578, 580,
+ 582, 584, 586, 588, 590, 592, 594, 596, 604, 609,
+ 624
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INT", "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", "'='", "'?'", "'|'", "'^'", "'&'", "NOTEQUAL", "EQUAL",
+ "GEQ", "LEQ", "GREATERTHAN", "LESSTHAN", "RSH", "LSH", "'@'", "'+'",
+ "'-'", "'*'", "'/'", "'%'", "UNARY", "'('", "')'", "'~'", "':'",
+ "$accept", "start", "type_exp", "exp", "@1", "arglist", "substring",
+ "complexnum", "variable", "type", "ptype", "abs_decl",
+ "direct_abs_decl", "func_mod", "typebase", "nonempty_typelist",
+ "name_not_typename", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 44,
+ 284, 61, 63, 124, 94, 38, 285, 286, 287, 288,
+ 289, 290, 291, 292, 64, 43, 45, 42, 47, 37,
+ 293, 40, 41, 126, 58
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 55, 56, 56, 57, 58, 58, 58, 58, 58,
+ 58, 58, 59, 58, 60, 60, 60, 60, 61, 62,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 63, 64, 65, 65, 66, 66, 66, 66, 66,
+ 67, 67, 67, 68, 68, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 70, 70,
+ 71
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 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, 3,
+ 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 0, 43, 45, 50, 49, 80, 65, 44, 0, 66,
+ 67, 71, 70, 69, 72, 73, 74, 75, 76, 77,
+ 0, 68, 47, 0, 0, 0, 0, 0, 0, 3,
+ 2, 46, 4, 52, 53, 51, 0, 11, 9, 7,
+ 8, 6, 0, 0, 0, 10, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 12, 57,
+ 55, 0, 54, 59, 62, 0, 0, 5, 20, 0,
+ 39, 40, 42, 41, 38, 37, 36, 31, 30, 33,
+ 32, 35, 34, 29, 28, 22, 26, 27, 23, 24,
+ 25, 14, 58, 56, 63, 78, 0, 0, 0, 61,
+ 48, 19, 21, 15, 0, 16, 60, 0, 64, 0,
+ 0, 13, 79, 18, 17
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 28, 29, 42, 101, 114, 115, 43, 31, 105,
+ 33, 72, 73, 74, 34, 107, 35
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -59
+static const short yypact[] =
+{
+ 77, -59, -59, -59, -59, -59, -59, -59, 128, -59,
+ -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ 137, -59, -59, 137, 137, 137, 77, 137, 2, -59,
+ 311, -59, -59, -59, -34, -59, 77, -45, -45, -45,
+ -45, -45, 281, -43, -36, -45, -59, 137, 137, 137,
+ 137, 137, 137, 137, 137, 137, 137, 137, 137, 137,
+ 137, 137, 137, 137, 137, 137, 137, 137, -59, -34,
+ -34, 208, -59, -44, -59, -33, 137, -59, -59, 137,
+ 357, 338, 311, 311, 392, 409, 163, 223, 223, -10,
+ -10, -10, -10, 24, 24, 60, -37, -37, -45, -45,
+ -45, 137, -59, -59, -59, -59, -31, -26, 232, -59,
+ 188, 311, -45, 252, -24, -59, -59, 399, -59, 137,
+ 137, -59, -59, 311, 311
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -59, -59, -59, 0, -59, -59, -59, -59, -59, 4,
+ -59, -27, -59, -58, -59, -59, -59
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 30, 69, 46, 117, 32, 120, 68, 108, 37, 78,
+ 65, 66, 67, 70, 68, 109, 79, 71, 0, 110,
+ 38, 116, 0, 39, 40, 41, 118, 45, 121, 0,
+ 44, 0, 60, 61, 62, 63, 64, 65, 66, 67,
+ 75, 68, 102, 103, 106, 0, 0, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100, 62, 63,
+ 64, 65, 66, 67, 0, 68, 111, 0, 0, 112,
+ 1, 2, 3, 4, 5, 6, 7, 8, 0, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 0, 113, 20, 21, 22, 63, 64, 65, 66, 67,
+ 112, 68, 23, 0, 0, 0, 0, 0, 0, 123,
+ 124, 122, 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, 36,
+ 0, 27, 0, 24, 25, 0, 0, 0, 26, 0,
+ 27, 1, 2, 3, 4, 5, 0, 7, 8, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 20, 68, 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, 69, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 70, 0, 0, 21, 71,
+ 104, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 0, 68, 47, 48, 0, 0, 0,
+ 49, 0, 0, 50, 104, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 0, 68, 47, 48, 119, 0, 0, 49,
+ 76, 0, 50, 0, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 0, 68, 77, 47, 48, 0, 0, 0, 49,
+ 0, 0, 50, 0, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 47, 68, 0, 0, 0, 0, 0, 0, 0,
+ 0, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 0, 68,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 6, 68, 0,
+ 0, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 0, 0, 0, 21, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 0, 68, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 0,
+ 68
+};
+
+static const yysigned_char yycheck[] =
+{
+ 0, 35, 0, 29, 0, 29, 51, 51, 8, 52,
+ 47, 48, 49, 47, 51, 73, 52, 51, -1, 52,
+ 20, 52, -1, 23, 24, 25, 52, 27, 52, -1,
+ 26, -1, 42, 43, 44, 45, 46, 47, 48, 49,
+ 36, 51, 69, 70, 71, -1, -1, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 44, 45,
+ 46, 47, 48, 49, -1, 51, 76, -1, -1, 79,
+ 3, 4, 5, 6, 7, 8, 9, 10, -1, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ -1, 101, 25, 26, 27, 45, 46, 47, 48, 49,
+ 110, 51, 35, -1, -1, -1, -1, -1, -1, 119,
+ 120, 117, -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
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 25, 26, 27, 35, 46, 47, 51, 53, 56, 57,
+ 58, 63, 64, 65, 69, 71, 51, 58, 58, 58,
+ 58, 58, 58, 62, 64, 58, 0, 23, 24, 28,
+ 31, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 51, 35,
+ 47, 51, 66, 67, 68, 64, 29, 52, 52, 52,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 59, 66, 66, 52, 64, 66, 70, 51, 68,
+ 52, 58, 58, 58, 60, 61, 52, 29, 52, 54,
+ 29, 52, 64, 58, 58
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to xreallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to xreallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 233 "f-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 239 "f-exp.y"
+ { }
+ break;
+
+ case 6:
+#line 244 "f-exp.y"
+ { write_exp_elt_opcode (UNOP_IND); }
+ break;
+
+ case 7:
+#line 248 "f-exp.y"
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ break;
+
+ case 8:
+#line 252 "f-exp.y"
+ { write_exp_elt_opcode (UNOP_NEG); }
+ break;
+
+ case 9:
+#line 256 "f-exp.y"
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ break;
+
+ case 10:
+#line 260 "f-exp.y"
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+ break;
+
+ case 11:
+#line 264 "f-exp.y"
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ break;
+
+ case 12:
+#line 273 "f-exp.y"
+ { start_arglist (); }
+ break;
+
+ case 13:
+#line 275 "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 15:
+#line 284 "f-exp.y"
+ { arglist_len = 1; }
+ break;
+
+ case 16:
+#line 288 "f-exp.y"
+ { arglist_len = 2;}
+ break;
+
+ case 17:
+#line 292 "f-exp.y"
+ { arglist_len++; }
+ break;
+
+ case 18:
+#line 296 "f-exp.y"
+ { }
+ break;
+
+ case 19:
+#line 301 "f-exp.y"
+ { }
+ break;
+
+ case 20:
+#line 305 "f-exp.y"
+ { write_exp_elt_opcode(OP_COMPLEX); }
+ break;
+
+ case 21:
+#line 309 "f-exp.y"
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_CAST); }
+ break;
+
+ case 22:
+#line 317 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ break;
+
+ case 23:
+#line 321 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_MUL); }
+ break;
+
+ case 24:
+#line 325 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_DIV); }
+ break;
+
+ case 25:
+#line 329 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_REM); }
+ break;
+
+ case 26:
+#line 333 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_ADD); }
+ break;
+
+ case 27:
+#line 337 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_SUB); }
+ break;
+
+ case 28:
+#line 341 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_LSH); }
+ break;
+
+ case 29:
+#line 345 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_RSH); }
+ break;
+
+ case 30:
+#line 349 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ break;
+
+ case 31:
+#line 353 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 32:
+#line 357 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ break;
+
+ case 33:
+#line 361 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ break;
+
+ case 34:
+#line 365 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_LESS); }
+ break;
+
+ case 35:
+#line 369 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_GTR); }
+ break;
+
+ case 36:
+#line 373 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ break;
+
+ case 37:
+#line 377 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ break;
+
+ case 38:
+#line 381 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ break;
+
+ case 39:
+#line 385 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ break;
+
+ case 40:
+#line 390 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ break;
+
+ case 41:
+#line 394 "f-exp.y"
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ break;
+
+ case 42:
+#line 398 "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 43:
+#line 404 "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 44:
+#line 411 "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 45:
+#line 420 "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 48:
+#line 433 "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 49:
+#line 441 "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 50:
+#line 448 "f-exp.y"
+ {
+ write_exp_elt_opcode (OP_STRING);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_STRING);
+ }
+ break;
+
+ case 51:
+#line 456 "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;
+ 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 54:
+#line 504 "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 55:
+#line 547 "f-exp.y"
+ { push_type (tp_pointer); yyval.voidval = 0; }
+ break;
+
+ case 56:
+#line 549 "f-exp.y"
+ { push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; }
+ break;
+
+ case 57:
+#line 551 "f-exp.y"
+ { push_type (tp_reference); yyval.voidval = 0; }
+ break;
+
+ case 58:
+#line 553 "f-exp.y"
+ { push_type (tp_reference); yyval.voidval = yyvsp[0].voidval; }
+ break;
+
+ case 60:
+#line 558 "f-exp.y"
+ { yyval.voidval = yyvsp[-1].voidval; }
+ break;
+
+ case 61:
+#line 560 "f-exp.y"
+ { push_type (tp_function); }
+ break;
+
+ case 62:
+#line 562 "f-exp.y"
+ { push_type (tp_function); }
+ break;
+
+ case 63:
+#line 566 "f-exp.y"
+ { yyval.voidval = 0; }
+ break;
+
+ case 64:
+#line 568 "f-exp.y"
+ { free (yyvsp[-1].tvec); yyval.voidval = 0; }
+ break;
+
+ case 65:
+#line 573 "f-exp.y"
+ { yyval.tval = yyvsp[0].tsym.type; }
+ break;
+
+ case 66:
+#line 575 "f-exp.y"
+ { yyval.tval = builtin_type_f_integer; }
+ break;
+
+ case 67:
+#line 577 "f-exp.y"
+ { yyval.tval = builtin_type_f_integer_s2; }
+ break;
+
+ case 68:
+#line 579 "f-exp.y"
+ { yyval.tval = builtin_type_f_character; }
+ break;
+
+ case 69:
+#line 581 "f-exp.y"
+ { yyval.tval = builtin_type_f_logical;}
+ break;
+
+ case 70:
+#line 583 "f-exp.y"
+ { yyval.tval = builtin_type_f_logical_s2;}
+ break;
+
+ case 71:
+#line 585 "f-exp.y"
+ { yyval.tval = builtin_type_f_logical_s1;}
+ break;
+
+ case 72:
+#line 587 "f-exp.y"
+ { yyval.tval = builtin_type_f_real;}
+ break;
+
+ case 73:
+#line 589 "f-exp.y"
+ { yyval.tval = builtin_type_f_real_s8;}
+ break;
+
+ case 74:
+#line 591 "f-exp.y"
+ { yyval.tval = builtin_type_f_real_s16;}
+ break;
+
+ case 75:
+#line 593 "f-exp.y"
+ { yyval.tval = builtin_type_f_complex_s8;}
+ break;
+
+ case 76:
+#line 595 "f-exp.y"
+ { yyval.tval = builtin_type_f_complex_s16;}
+ break;
+
+ case 77:
+#line 597 "f-exp.y"
+ { yyval.tval = builtin_type_f_complex_s32;}
+ break;
+
+ case 78:
+#line 605 "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 610 "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;
+
+
+ }
+
+/* Line 991 of yacc.c. */
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ 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)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab2;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+
+ /* Suppress GCC warning that yyerrlab1 is unused when no action
+ invokes YYERROR. Doesn't work in C++ */
+#ifndef __cplusplus
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+#endif
+#endif
+
+
+ goto yyerrlab2;
+
+
+/*---------------------------------------------------------------.
+| yyerrlab2 -- pop states until the error token can be shifted. |
+`---------------------------------------------------------------*/
+yyerrlab2:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 634 "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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+ int long_p = 0;
+ ULONGEST 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 = xstrdup (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 (isupper (c))
+ c = tolower (c);
+ if (len == 0 && c == 'l')
+ long_p = 1;
+ else if (len == 0 && c == 'u')
+ unsigned_p = 1;
+ else
+ {
+ int i;
+ if (c >= '0' && c <= '9')
+ i = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ i = c - 'a' + 10;
+ else
+ return ERROR; /* Char not a digit */
+ if (i >= base)
+ return ERROR; /* Invalid digit in this base */
+ n *= base;
+ n += i;
+ }
+ /* 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 = ((ULONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ high_bit = ((ULONGEST)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:
+
+ prev_lexptr = lexptr;
+
+ 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 (strncmp (tokstart, boolean_values[i].name,
+ strlen (boolean_values[i].name)) == 0)
+ {
+ 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 (strncmp (tokstart, dot_ops[i].operator, strlen (dot_ops[i].operator)) == 0)
+ {
+ 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;
+ 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 (strncmp (tokstart, f77_keywords[i].operator,
+ strlen(f77_keywords[i].operator)) == 0)
+ {
+ /* 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_DOMAIN,
+ 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;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ 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 0000000..adff33b
--- /dev/null
+++ b/contrib/gdb/gdb/f-exp.y
@@ -0,0 +1,1188 @@
+/* YACC parser for Fortran expressions, for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1993, 1994, 1995, 1996, 2000, 2001
+ 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 (<malloc.h> and <stdlib.h> 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 */
+#include "block.h"
+#include <ctype.h>
+
+/* 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 yyname f_name /* With YYDEBUG defined */
+#define yyrule f_rule /* 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 yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static void growbuf_by_size (int);
+
+static int match_string_literal (void);
+
+%}
+
+/* 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 (char *, int, int, YYSTYPE *);
+%}
+
+%type <voidval> exp type_exp start variable
+%type <tval> type typebase
+%type <tvec> nonempty_typelist
+/* %type <bval> block */
+
+/* Fancy type parsing. */
+%type <voidval> func_mod direct_abs_decl abs_decl
+%type <tval> ptype
+
+%token <typed_val> INT
+%token <dval> 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 <sval> STRING_LITERAL
+%token <lval> BOOLEAN_LITERAL
+%token <ssym> NAME
+%token <tsym> TYPENAME
+%type <sval> name
+%type <ssym> name_not_typename
+%type <tsym> 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 <ssym> 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 <lval> CHARACTER
+
+%token <voidval> VARIABLE
+
+%token <opcode> 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;
+ 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 ($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);
+ $<ivec>$[0] = 1; /* Number of types in vector */
+ $$[1] = $1;
+ }
+ | nonempty_typelist ',' type
+ { int len = sizeof (struct type *) * (++($<ivec>1[0]) + 1);
+ $$ = (struct type **) realloc ((char *) $1, len);
+ $$[$<ivec>$[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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+ int long_p = 0;
+ ULONGEST 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 = xstrdup (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 (isupper (c))
+ c = tolower (c);
+ if (len == 0 && c == 'l')
+ long_p = 1;
+ else if (len == 0 && c == 'u')
+ unsigned_p = 1;
+ else
+ {
+ int i;
+ if (c >= '0' && c <= '9')
+ i = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ i = c - 'a' + 10;
+ else
+ return ERROR; /* Char not a digit */
+ if (i >= base)
+ return ERROR; /* Invalid digit in this base */
+ n *= base;
+ n += i;
+ }
+ /* 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 = ((ULONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ high_bit = ((ULONGEST)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:
+
+ prev_lexptr = lexptr;
+
+ 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 (strncmp (tokstart, boolean_values[i].name,
+ strlen (boolean_values[i].name)) == 0)
+ {
+ 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 (strncmp (tokstart, dot_ops[i].operator, strlen (dot_ops[i].operator)) == 0)
+ {
+ 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;
+ 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 (strncmp (tokstart, f77_keywords[i].operator,
+ strlen(f77_keywords[i].operator)) == 0)
+ {
+ /* 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_DOMAIN,
+ 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;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ 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 0000000..1e7cd45
--- /dev/null
+++ b/contrib/gdb/gdb/f-lang.c
@@ -0,0 +1,986 @@
+/* Fortran language support routines for GDB, the GNU debugger.
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ 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"
+#include "valprint.h"
+#include "value.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;
+
+/* Following is dubious stuff that had been in the xcoff reader. */
+
+struct saved_fcn
+ {
+ long line_offset; /* Line offset for function */
+ struct saved_fcn *next;
+ };
+
+
+struct saved_bf_symnum
+ {
+ long symnum_fcn; /* Symnum of function (i.e. .function directive) */
+ long symnum_bf; /* Symnum of .bf for this function */
+ struct saved_bf_symnum *next;
+ };
+
+typedef struct saved_fcn SAVED_FUNCTION, *SAVED_FUNCTION_PTR;
+typedef struct saved_bf_symnum SAVED_BF, *SAVED_BF_PTR;
+
+/* Local functions */
+
+extern void _initialize_f_language (void);
+#if 0
+static void clear_function_list (void);
+static long get_bf_for_fcn (long);
+static void clear_bf_list (void);
+static void patch_all_commons_by_name (char *, CORE_ADDR, int);
+static SAVED_F77_COMMON_PTR find_first_common_named (char *);
+static void add_common_entry (struct symbol *);
+static void add_common_block (char *, CORE_ADDR, int, char *);
+static SAVED_FUNCTION *allocate_saved_function_node (void);
+static SAVED_BF_PTR allocate_saved_bf_node (void);
+static COMMON_ENTRY_PTR allocate_common_entry_node (void);
+static SAVED_F77_COMMON_PTR allocate_saved_f77_common_node (void);
+static void patch_common_entries (SAVED_F77_COMMON_PTR, CORE_ADDR, int);
+#endif
+
+static struct type *f_create_fundamental_type (struct objfile *, int);
+static void f_printstr (struct ui_file * stream, char *string,
+ unsigned int length, int width,
+ int force_ellipses);
+static void f_printchar (int c, struct ui_file * stream);
+static void f_emit_char (int c, struct ui_file * stream, int quoter);
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ characters and strings is language specific.
+ 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_emit_char (int c, struct ui_file *stream, int quoter)
+{
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (c == '\\' || c == quoter)
+ fputs_filtered ("\\", stream);
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+}
+
+/* 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 (int c, struct ui_file *stream)
+{
+ fputs_filtered ("'", stream);
+ LA_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 (struct ui_file *stream, char *string, unsigned int length,
+ int width, int force_ellipses)
+{
+ unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+
+ 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;
+ }
+ f_printchar (string[i], stream);
+ fprintf_filtered (stream, " <repeats %u times>", 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;
+ }
+ LA_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 (struct objfile *objfile, int typeid)
+{
+ 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 "<?type?>". 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, "<?type?>", 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
+};
+
+/* This is declared in c-lang.h but it is silly to import that file for what
+ is already just a hack. */
+extern int c_value_print (struct value *, struct ui_file *, int,
+ enum val_prettyprint);
+
+const struct language_defn f_language_defn =
+{
+ "fortran",
+ language_fortran,
+ f_builtin_types,
+ range_check_on,
+ type_check_on,
+ case_sensitive_off,
+ &exp_descriptor_standard,
+ f_parse, /* parser */
+ f_error, /* parser error function */
+ f_printchar, /* Print character constant */
+ f_printstr, /* function to print string constant */
+ f_emit_char, /* Function to print a single character */
+ 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 */
+ NULL, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+static void
+build_fortran_types (void)
+{
+ 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;
+}
+
+void
+_initialize_f_language (void)
+{
+ build_fortran_types ();
+
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_character);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_logical);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_logical_s1);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_logical_s2);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_integer);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_integer_s2);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_real);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_real_s8);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_real_s16);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_complex_s8);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_complex_s16);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_complex_s32);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_f_void);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_string);
+ deprecated_register_gdbarch_swap (NULL, 0, build_fortran_types);
+
+ 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);
+}
+
+#if 0
+static SAVED_BF_PTR
+allocate_saved_bf_node (void)
+{
+ SAVED_BF_PTR new;
+
+ new = (SAVED_BF_PTR) xmalloc (sizeof (SAVED_BF));
+ return (new);
+}
+
+static SAVED_FUNCTION *
+allocate_saved_function_node (void)
+{
+ SAVED_FUNCTION *new;
+
+ new = (SAVED_FUNCTION *) xmalloc (sizeof (SAVED_FUNCTION));
+ return (new);
+}
+
+static SAVED_F77_COMMON_PTR
+allocate_saved_f77_common_node (void)
+{
+ SAVED_F77_COMMON_PTR new;
+
+ new = (SAVED_F77_COMMON_PTR) xmalloc (sizeof (SAVED_F77_COMMON));
+ return (new);
+}
+
+static COMMON_ENTRY_PTR
+allocate_common_entry_node (void)
+{
+ COMMON_ENTRY_PTR new;
+
+ new = (COMMON_ENTRY_PTR) xmalloc (sizeof (COMMON_ENTRY));
+ return (new);
+}
+#endif
+
+SAVED_F77_COMMON_PTR head_common_list = NULL; /* Ptr to 1st saved COMMON */
+SAVED_F77_COMMON_PTR tail_common_list = NULL; /* Ptr to last saved COMMON */
+SAVED_F77_COMMON_PTR current_common = NULL; /* Ptr to current COMMON */
+
+#if 0
+static SAVED_BF_PTR saved_bf_list = NULL; /* Ptr to (.bf,function)
+ list */
+static SAVED_BF_PTR saved_bf_list_end = NULL; /* Ptr to above list's end */
+static SAVED_BF_PTR current_head_bf_list = NULL; /* Current head of above list
+ */
+
+static SAVED_BF_PTR tmp_bf_ptr; /* Generic temporary for use
+ in macros */
+
+/* The following function simply enters a given common block onto
+ the global common block chain */
+
+static void
+add_common_block (char *name, CORE_ADDR offset, int secnum, char *func_stab)
+{
+ SAVED_F77_COMMON_PTR tmp;
+ char *c, *local_copy_func_stab;
+
+ /* If the COMMON block we are trying to add has a blank
+ name (i.e. "#BLNK_COM") then we set it to __BLANK
+ because the darn "#" character makes GDB's input
+ parser have fits. */
+
+
+ if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0
+ || strcmp (name, BLANK_COMMON_NAME_MF77) == 0)
+ {
+
+ xfree (name);
+ name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1);
+ strcpy (name, BLANK_COMMON_NAME_LOCAL);
+ }
+
+ tmp = allocate_saved_f77_common_node ();
+
+ local_copy_func_stab = xmalloc (strlen (func_stab) + 1);
+ strcpy (local_copy_func_stab, func_stab);
+
+ tmp->name = xmalloc (strlen (name) + 1);
+
+ /* local_copy_func_stab is a stabstring, let us first extract the
+ function name from the stab by NULLing out the ':' character. */
+
+
+ c = NULL;
+ c = strchr (local_copy_func_stab, ':');
+
+ if (c)
+ *c = '\0';
+ else
+ error ("Malformed function STAB found in add_common_block()");
+
+
+ tmp->owning_function = xmalloc (strlen (local_copy_func_stab) + 1);
+
+ strcpy (tmp->owning_function, local_copy_func_stab);
+
+ strcpy (tmp->name, name);
+ tmp->offset = offset;
+ tmp->next = NULL;
+ tmp->entries = NULL;
+ tmp->secnum = secnum;
+
+ current_common = tmp;
+
+ if (head_common_list == NULL)
+ {
+ head_common_list = tail_common_list = tmp;
+ }
+ else
+ {
+ tail_common_list->next = tmp;
+ tail_common_list = tmp;
+ }
+}
+#endif
+
+/* The following function simply enters a given common entry onto
+ the "current_common" block that has been saved away. */
+
+#if 0
+static void
+add_common_entry (struct symbol *entry_sym_ptr)
+{
+ COMMON_ENTRY_PTR tmp;
+
+
+
+ /* The order of this list is important, since
+ we expect the entries to appear in decl.
+ order when we later issue "info common" calls */
+
+ tmp = allocate_common_entry_node ();
+
+ tmp->next = NULL;
+ tmp->symbol = entry_sym_ptr;
+
+ if (current_common == NULL)
+ error ("Attempt to add COMMON entry with no block open!");
+ else
+ {
+ if (current_common->entries == NULL)
+ {
+ current_common->entries = tmp;
+ current_common->end_of_entries = tmp;
+ }
+ else
+ {
+ current_common->end_of_entries->next = tmp;
+ current_common->end_of_entries = tmp;
+ }
+ }
+}
+#endif
+
+/* This routine finds the first encountred COMMON block named "name" */
+
+#if 0
+static SAVED_F77_COMMON_PTR
+find_first_common_named (char *name)
+{
+
+ SAVED_F77_COMMON_PTR tmp;
+
+ tmp = head_common_list;
+
+ while (tmp != NULL)
+ {
+ if (strcmp (tmp->name, name) == 0)
+ return (tmp);
+ else
+ tmp = tmp->next;
+ }
+ return (NULL);
+}
+#endif
+
+/* This routine finds the first encountred COMMON block named "name"
+ that belongs to function funcname */
+
+SAVED_F77_COMMON_PTR
+find_common_for_function (char *name, char *funcname)
+{
+
+ SAVED_F77_COMMON_PTR tmp;
+
+ tmp = head_common_list;
+
+ while (tmp != NULL)
+ {
+ if (DEPRECATED_STREQ (tmp->name, name)
+ && DEPRECATED_STREQ (tmp->owning_function, funcname))
+ return (tmp);
+ else
+ tmp = tmp->next;
+ }
+ return (NULL);
+}
+
+
+#if 0
+
+/* The following function is called to patch up the offsets
+ for the statics contained in the COMMON block named
+ "name." */
+
+static void
+patch_common_entries (SAVED_F77_COMMON_PTR blk, CORE_ADDR offset, int secnum)
+{
+ COMMON_ENTRY_PTR entry;
+
+ blk->offset = offset; /* Keep this around for future use. */
+
+ entry = blk->entries;
+
+ while (entry != NULL)
+ {
+ SYMBOL_VALUE (entry->symbol) += offset;
+ SYMBOL_SECTION (entry->symbol) = secnum;
+
+ entry = entry->next;
+ }
+ blk->secnum = secnum;
+}
+
+/* Patch all commons named "name" that need patching.Since COMMON
+ blocks occur with relative infrequency, we simply do a linear scan on
+ the name. Eventually, the best way to do this will be a
+ hashed-lookup. Secnum is the section number for the .bss section
+ (which is where common data lives). */
+
+static void
+patch_all_commons_by_name (char *name, CORE_ADDR offset, int secnum)
+{
+
+ SAVED_F77_COMMON_PTR tmp;
+
+ /* For blank common blocks, change the canonical reprsentation
+ of a blank name */
+
+ if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0
+ || strcmp (name, BLANK_COMMON_NAME_MF77) == 0)
+ {
+ xfree (name);
+ name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1);
+ strcpy (name, BLANK_COMMON_NAME_LOCAL);
+ }
+
+ tmp = head_common_list;
+
+ while (tmp != NULL)
+ {
+ if (COMMON_NEEDS_PATCHING (tmp))
+ if (strcmp (tmp->name, name) == 0)
+ patch_common_entries (tmp, offset, secnum);
+
+ tmp = tmp->next;
+ }
+}
+#endif
+
+/* This macro adds the symbol-number for the start of the function
+ (the symbol number of the .bf) referenced by symnum_fcn to a
+ list. This list, in reality should be a FIFO queue but since
+ #line pragmas sometimes cause line ranges to get messed up
+ we simply create a linear list. This list can then be searched
+ first by a queueing algorithm and upon failure fall back to
+ a linear scan. */
+
+#if 0
+#define ADD_BF_SYMNUM(bf_sym,fcn_sym) \
+ \
+ if (saved_bf_list == NULL) \
+{ \
+ tmp_bf_ptr = allocate_saved_bf_node(); \
+ \
+ tmp_bf_ptr->symnum_bf = (bf_sym); \
+ tmp_bf_ptr->symnum_fcn = (fcn_sym); \
+ tmp_bf_ptr->next = NULL; \
+ \
+ current_head_bf_list = saved_bf_list = tmp_bf_ptr; \
+ saved_bf_list_end = tmp_bf_ptr; \
+ } \
+else \
+{ \
+ tmp_bf_ptr = allocate_saved_bf_node(); \
+ \
+ tmp_bf_ptr->symnum_bf = (bf_sym); \
+ tmp_bf_ptr->symnum_fcn = (fcn_sym); \
+ tmp_bf_ptr->next = NULL; \
+ \
+ saved_bf_list_end->next = tmp_bf_ptr; \
+ saved_bf_list_end = tmp_bf_ptr; \
+ }
+#endif
+
+/* This function frees the entire (.bf,function) list */
+
+#if 0
+static void
+clear_bf_list (void)
+{
+
+ SAVED_BF_PTR tmp = saved_bf_list;
+ SAVED_BF_PTR next = NULL;
+
+ while (tmp != NULL)
+ {
+ next = tmp->next;
+ xfree (tmp);
+ tmp = next;
+ }
+ saved_bf_list = NULL;
+}
+#endif
+
+int global_remote_debug;
+
+#if 0
+
+static long
+get_bf_for_fcn (long the_function)
+{
+ SAVED_BF_PTR tmp;
+ int nprobes = 0;
+
+ /* First use a simple queuing algorithm (i.e. look and see if the
+ item at the head of the queue is the one you want) */
+
+ if (saved_bf_list == NULL)
+ internal_error (__FILE__, __LINE__,
+ "cannot get .bf node off empty list");
+
+ if (current_head_bf_list != NULL)
+ if (current_head_bf_list->symnum_fcn == the_function)
+ {
+ if (global_remote_debug)
+ fprintf_unfiltered (gdb_stderr, "*");
+
+ tmp = current_head_bf_list;
+ current_head_bf_list = current_head_bf_list->next;
+ return (tmp->symnum_bf);
+ }
+
+ /* If the above did not work (probably because #line directives were
+ used in the sourcefile and they messed up our internal tables) we now do
+ the ugly linear scan */
+
+ if (global_remote_debug)
+ fprintf_unfiltered (gdb_stderr, "\ndefaulting to linear scan\n");
+
+ nprobes = 0;
+ tmp = saved_bf_list;
+ while (tmp != NULL)
+ {
+ nprobes++;
+ if (tmp->symnum_fcn == the_function)
+ {
+ if (global_remote_debug)
+ fprintf_unfiltered (gdb_stderr, "Found in %d probes\n", nprobes);
+ current_head_bf_list = tmp->next;
+ return (tmp->symnum_bf);
+ }
+ tmp = tmp->next;
+ }
+
+ return (-1);
+}
+
+static SAVED_FUNCTION_PTR saved_function_list = NULL;
+static SAVED_FUNCTION_PTR saved_function_list_end = NULL;
+
+static void
+clear_function_list (void)
+{
+ SAVED_FUNCTION_PTR tmp = saved_function_list;
+ SAVED_FUNCTION_PTR next = NULL;
+
+ while (tmp != NULL)
+ {
+ next = tmp->next;
+ xfree (tmp);
+ tmp = next;
+ }
+
+ saved_function_list = NULL;
+}
+#endif
diff --git a/contrib/gdb/gdb/f-lang.h b/contrib/gdb/gdb/f-lang.h
new file mode 100644
index 0000000..d929b91
--- /dev/null
+++ b/contrib/gdb/gdb/f-lang.h
@@ -0,0 +1,98 @@
+/* Fortran language support definitions for GDB, the GNU debugger.
+ Copyright 1992, 1993, 1994, 1995, 1998, 2000
+ 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 (void);
+
+extern void f_error (char *); /* Defined in f-exp.y */
+
+extern void f_print_type (struct type *, char *, struct ui_file *, int,
+ int);
+
+extern int f_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_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 (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 (struct type *, int *);
+
+extern int f77_get_dynamic_lowerbound (struct type *, int *);
+
+extern void f77_get_dynamic_array_length (struct type *);
+
+extern int calc_f77_array_dims (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 0000000..9e148fb
--- /dev/null
+++ b/contrib/gdb/gdb/f-typeprint.c
@@ -0,0 +1,406 @@
+/* Support for printing Fortran types for GDB, the GNU debugger.
+
+ Copyright 1986, 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1998,
+ 2000, 2001, 2002, 2003 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 "gdb_obstack.h"
+#include "bfd.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "f-lang.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+
+#if 0 /* Currently unused */
+static void f_type_print_args (struct type *, struct ui_file *);
+#endif
+
+static void print_equivalent_f77_float_type (struct type *,
+ struct ui_file *);
+
+static void f_type_print_varspec_suffix (struct type *, struct ui_file *,
+ int, int, int);
+
+void f_type_print_varspec_prefix (struct type *, struct ui_file *,
+ int, int);
+
+void f_type_print_base (struct type *, struct ui_file *, int, int);
+
+
+/* LEVEL is the depth to indent lines by. */
+
+void
+f_print_type (struct type *type, char *varstring, struct ui_file *stream,
+ int show, int level)
+{
+ 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 (struct type *type, struct ui_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;
+ }
+}
+
+/* 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 (struct type *type, struct ui_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;
+ }
+}
+
+static void
+print_equivalent_f77_float_type (struct type *type, struct ui_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 (struct type *type, struct ui_file *stream, int show,
+ int level)
+{
+ int retcode;
+ int upper_bound;
+
+ QUIT;
+
+ wrap_here (" ");
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", 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_REF:
+ fprintf_filtered (stream, "REF 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 <unknown>");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<unknown type>");
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* This should not occur */
+ fprintf_filtered (stream, "<range type>");
+ 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 (strcmp (TYPE_NAME (type), "char") == 0)
+ 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 0000000..805590f
--- /dev/null
+++ b/contrib/gdb/gdb/f-valprint.c
@@ -0,0 +1,782 @@
+/* Support for printing Fortran values for GDB, the GNU debugger.
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2003
+ 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 "valprint.h"
+#include "language.h"
+#include "f-lang.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "block.h"
+
+#if 0
+static int there_is_a_visible_common_named (char *);
+#endif
+
+extern void _initialize_f_valprint (void);
+static void info_common_command (char *, int);
+static void list_all_visible_commons (char *);
+static void f77_print_array (struct type *, char *, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+static void f77_print_array_1 (int, int, struct type *, char *,
+ CORE_ADDR, struct ui_file *, int, int, int,
+ enum val_prettyprint,
+ int *elts);
+static void f77_create_arrayprint_offset_tbl (struct type *,
+ struct ui_file *);
+static void f77_get_dynamic_length_of_aggregate (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 (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 = get_frame_base (deprecated_selected_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 = get_frame_base (deprecated_selected_frame);
+ if (current_frame_addr > 0)
+ {
+ ptr_to_lower_bound =
+ read_memory_typed_address (current_frame_addr +
+ TYPE_ARRAY_LOWER_BOUND_VALUE (type),
+ builtin_type_void_data_ptr);
+ *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 (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 = get_frame_base (deprecated_selected_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 = get_frame_base (deprecated_selected_frame);
+ if (current_frame_addr > 0)
+ {
+ ptr_to_upper_bound =
+ read_memory_typed_address (current_frame_addr +
+ TYPE_ARRAY_UPPER_BOUND_VALUE (type),
+ builtin_type_void_data_ptr);
+ *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 */
+
+static void
+f77_get_dynamic_length_of_aggregate (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". */
+
+static void
+f77_create_arrayprint_offset_tbl (struct type *type, struct ui_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, "<assumed size array> ");
+
+ 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. */
+
+static void
+f77_print_array_1 (int nss, int ndimensions, struct type *type, char *valaddr,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty,
+ int *elts)
+{
+ int i;
+
+ if (nss != ndimensions)
+ {
+ for (i = 0; (i < F77_DIM_SIZE (nss) && (*elts) < print_max); i++)
+ {
+ fprintf_filtered (stream, "( ");
+ f77_print_array_1 (nss + 1, ndimensions, TYPE_TARGET_TYPE (type),
+ valaddr + i * F77_DIM_OFFSET (nss),
+ address + i * F77_DIM_OFFSET (nss),
+ stream, format, deref_ref, recurse, pretty, elts);
+ fprintf_filtered (stream, ") ");
+ }
+ if (*elts >= print_max && i < F77_DIM_SIZE (nss))
+ fprintf_filtered (stream, "...");
+ }
+ else
+ {
+ for (i = 0; i < F77_DIM_SIZE (nss) && (*elts) < print_max;
+ i++, (*elts)++)
+ {
+ val_print (TYPE_TARGET_TYPE (type),
+ valaddr + i * F77_DIM_OFFSET (ndimensions),
+ 0,
+ address + i * F77_DIM_OFFSET (ndimensions),
+ stream, format, deref_ref, recurse, pretty);
+
+ if (i != (F77_DIM_SIZE (nss) - 1))
+ fprintf_filtered (stream, ", ");
+
+ if ((*elts == print_max - 1) && (i != (F77_DIM_SIZE (nss) - 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() */
+
+static void
+f77_print_array (struct type *type, char *valaddr, CORE_ADDR address,
+ struct ui_file *stream, int format, int deref_ref, int recurse,
+ enum val_prettyprint pretty)
+{
+ int ndimensions;
+ int elts = 0;
+
+ 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, &elts);
+}
+
+
+/* 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 (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ 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), 1, 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;
+
+ 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')
+ 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, -1, TYPE_LENGTH (elttype), 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_REF:
+ elttype = check_typedef (TYPE_TARGET_TYPE (type));
+ if (addressprint)
+ {
+ CORE_ADDR addr
+ = extract_typed_address (valaddr + embedded_offset, type);
+ fprintf_filtered (stream, "@");
+ print_address_numeric (addr, 1, stream);
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
+ {
+ struct value *deref_val =
+ value_at
+ (TYPE_TARGET_TYPE (type),
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr + embedded_offset),
+ NULL);
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val),
+ 0,
+ VALUE_ADDRESS (deref_val),
+ stream,
+ format,
+ deref_ref,
+ recurse,
+ pretty);
+ }
+ else
+ fputs_filtered ("???", stream);
+ }
+ 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, "<error type>");
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* FIXME, we should not ever have to print one of these yet. */
+ fprintf_filtered (stream, "<range type>");
+ 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, 0, 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_LENGTH (type), type, stream);
+ fputs_filtered (")", stream);
+ break;
+
+ case TYPE_CODE_UNDEF:
+ /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+ dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+ and no complete type for struct foo in that file. */
+ fprintf_filtered (stream, "<incomplete type>");
+ break;
+
+ default:
+ error ("Invalid F77 type code %d in symbol table.", TYPE_CODE (type));
+ }
+ gdb_flush (stream);
+ return 0;
+}
+
+static void
+list_all_visible_commons (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 (strcmp (tmp->owning_function, funname) == 0)
+ 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 (char *comname, int from_tty)
+{
+ SAVED_F77_COMMON_PTR the_common;
+ COMMON_ENTRY_PTR entry;
+ struct frame_info *fi;
+ char *funname = 0;
+ struct symbol *func;
+
+ /* 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 = deprecated_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 (get_frame_pc (fi));
+ if (func)
+ {
+ /* In certain pathological cases, the symtabs give the wrong
+ function (when we are in the first function in a file which
+ is compiled without debugging symbols, the previous function
+ is compiled with debugging symbols, and the "foo.o" symbol
+ that is supposed to tell us where the file with debugging symbols
+ ends has been truncated by ar because it is longer than 15
+ characters).
+
+ So look in the minimal symbol tables as well, and if it comes
+ up with a larger address for the function use that instead.
+ I don't think this can ever cause any problems; there shouldn't
+ be any minimal symbols in the middle of a function.
+ FIXME: (Not necessarily true. What about text labels) */
+
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (fi));
+
+ if (msymbol != NULL
+ && (SYMBOL_VALUE_ADDRESS (msymbol)
+ > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+ funname = DEPRECATED_SYMBOL_NAME (msymbol);
+ else
+ funname = DEPRECATED_SYMBOL_NAME (func);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol =
+ lookup_minimal_symbol_by_pc (get_frame_pc (fi));
+
+ if (msymbol != NULL)
+ funname = DEPRECATED_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 (strcmp (comname, BLANK_COMMON_NAME_LOCAL) == 0)
+ printf_filtered ("Contents of blank COMMON block:\n");
+ else
+ printf_filtered ("Contents of F77 COMMON block '%s':\n", comname);
+
+ printf_filtered ("\n");
+ entry = the_common->entries;
+
+ while (entry != NULL)
+ {
+ printf_filtered ("%s = ", DEPRECATED_SYMBOL_NAME (entry->symbol));
+ print_variable_value (entry->symbol, fi, gdb_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'. */
+
+#if 0
+static int
+there_is_a_visible_common_named (char *comname)
+{
+ SAVED_F77_COMMON_PTR the_common;
+ struct frame_info *fi;
+ char *funname = 0;
+ struct symbol *func;
+
+ if (comname == NULL)
+ error ("Cannot deal with NULL common name!");
+
+ fi = deprecated_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 = DEPRECATED_SYMBOL_NAME (msymbol);
+ else
+ funname = DEPRECATED_SYMBOL_NAME (func);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol =
+ lookup_minimal_symbol_by_pc (fi->pc);
+
+ if (msymbol != NULL)
+ funname = DEPRECATED_SYMBOL_NAME (msymbol);
+ }
+
+ the_common = find_common_for_function (comname, funname);
+
+ return (the_common ? 1 : 0);
+}
+#endif
+
+void
+_initialize_f_valprint (void)
+{
+ add_info ("common", info_common_command,
+ "Print out the values contained in a Fortran COMMON block.");
+ if (xdb_commands)
+ add_com ("lc", class_info, info_common_command,
+ "Print out the values contained in a Fortran COMMON block.");
+}
diff --git a/contrib/gdb/gdb/fbsd-proc.c b/contrib/gdb/gdb/fbsd-proc.c
new file mode 100644
index 0000000..16813a9
--- /dev/null
+++ b/contrib/gdb/gdb/fbsd-proc.c
@@ -0,0 +1,166 @@
+/* FreeBSD-specific methods for using the /proc file system.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "inferior.h"
+#include "gdb_string.h"
+
+#include <sys/procfs.h>
+#include <sys/types.h>
+
+#include "elf-bfd.h"
+
+#include "gregset.h"
+
+char *
+child_pid_to_exec_file (int pid)
+{
+ char *path;
+ char *buf;
+
+ xasprintf (&path, "/proc/%d/file", pid);
+ buf = xcalloc (MAXPATHLEN, sizeof (char));
+ make_cleanup (xfree, path);
+ make_cleanup (xfree, buf);
+
+ if (readlink (path, buf, MAXPATHLEN) > 0)
+ return buf;
+
+ return NULL;
+}
+
+static int
+read_mapping (FILE *mapfile, unsigned long *start, unsigned long *end,
+ char *protection)
+{
+ /* FreeBSD 5.1-RELEASE uses a 256-byte buffer. */
+ char buf[256];
+ int resident, privateresident;
+ unsigned long obj;
+ int ret = EOF;
+
+ /* As of FreeBSD 5.0-RELEASE, the layout is described in
+ /usr/src/sys/fs/procfs/procfs_map.c. Somewhere in 5.1-CURRENT a
+ new column was added to the procfs map. Therefore we can't use
+ fscanf since we need to support older releases too. */
+ if (fgets (buf, sizeof buf, mapfile) != NULL)
+ ret = sscanf (buf, "%lx %lx %d %d %lx %s", start, end,
+ &resident, &privateresident, &obj, protection);
+
+ return (ret != 0 && ret != EOF);
+}
+
+static int
+fbsd_find_memory_regions (int (*func) (CORE_ADDR, unsigned long,
+ int, int, int, void *),
+ void *obfd)
+{
+ pid_t pid = ptid_get_pid (inferior_ptid);
+ char *mapfilename;
+ FILE *mapfile;
+ unsigned long start, end, size;
+ char protection[4];
+ int read, write, exec;
+
+ xasprintf (&mapfilename, "/proc/%ld/map", (long) pid);
+ mapfile = fopen (mapfilename, "r");
+ if (mapfile == NULL)
+ error ("Couldn't open %s\n", mapfilename);
+
+ if (info_verbose)
+ fprintf_filtered (gdb_stdout,
+ "Reading memory regions from %s\n", mapfilename);
+
+ /* Now iterate until end-of-file. */
+ while (read_mapping (mapfile, &start, &end, &protection[0]))
+ {
+ size = end - start;
+
+ read = (strchr (protection, 'r') != 0);
+ write = (strchr (protection, 'w') != 0);
+ exec = (strchr (protection, 'x') != 0);
+
+ if (info_verbose)
+ {
+ fprintf_filtered (gdb_stdout,
+ "Save segment, %ld bytes at 0x%s (%c%c%c)\n",
+ size, paddr_nz (start),
+ read ? 'r' : '-',
+ write ? 'w' : '-',
+ exec ? 'x' : '-');
+ }
+
+ /* Invoke the callback function to create the corefile segment. */
+ func (start, size, read, write, exec, obfd);
+ }
+
+ fclose (mapfile);
+ return 0;
+}
+
+static char *
+fbsd_make_corefile_notes (bfd *obfd, int *note_size)
+{
+ gregset_t gregs;
+ fpregset_t fpregs;
+ char *note_data = NULL;
+ Elf_Internal_Ehdr *i_ehdrp;
+
+ /* Put a "FreeBSD" label in the ELF header. */
+ i_ehdrp = elf_elfheader (obfd);
+ i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+
+ fill_gregset (&gregs, -1);
+ note_data = elfcore_write_prstatus (obfd, note_data, note_size,
+ ptid_get_pid (inferior_ptid),
+ stop_signal, &gregs);
+
+ fill_fpregset (&fpregs, -1);
+ note_data = elfcore_write_prfpreg (obfd, note_data, note_size,
+ &fpregs, sizeof (fpregs));
+
+ if (get_exec_file (0))
+ {
+ char *fname = strrchr (get_exec_file (0), '/') + 1;
+ char *psargs = xstrdup (fname);
+
+ if (get_inferior_args ())
+ psargs = reconcat (psargs, psargs, " ", get_inferior_args (), NULL);
+
+ note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
+ fname, psargs);
+ }
+
+ make_cleanup (xfree, note_data);
+ return note_data;
+}
+
+
+void
+_initialize_fbsd_proc (void)
+{
+ extern void inftarg_set_find_memory_regions ();
+ extern void inftarg_set_make_corefile_notes ();
+
+ inftarg_set_find_memory_regions (fbsd_find_memory_regions);
+ inftarg_set_make_corefile_notes (fbsd_make_corefile_notes);
+}
diff --git a/contrib/gdb/gdb/findvar.c b/contrib/gdb/gdb/findvar.c
new file mode 100644
index 0000000..cb1ef65
--- /dev/null
+++ b/contrib/gdb/gdb/findvar.c
@@ -0,0 +1,808 @@
+/* Find a variable's value in memory, for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "gdb_assert.h"
+#include "floatformat.h"
+#include "symfile.h" /* for overlay functions */
+#include "regcache.h"
+#include "user-regs.h"
+#include "block.h"
+
+/* Basic byte-swapping routines. GDB has needed these for a long time...
+ All extract a target-format integer at ADDR which is LEN bytes long. */
+
+#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 (const void *addr, int len)
+{
+ LONGEST retval;
+ const unsigned char *p;
+ const unsigned char *startaddr = addr;
+ const unsigned char *endaddr = startaddr + len;
+
+ if (len > (int) sizeof (LONGEST))
+ error ("\
+That operation is not available on integers of more than %d bytes.",
+ (int) sizeof (LONGEST));
+
+ /* Start at the most significant end of the integer, and work towards
+ the least significant. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ 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;
+}
+
+ULONGEST
+extract_unsigned_integer (const void *addr, int len)
+{
+ ULONGEST retval;
+ const unsigned char *p;
+ const unsigned char *startaddr = addr;
+ const unsigned char *endaddr = startaddr + len;
+
+ if (len > (int) sizeof (ULONGEST))
+ error ("\
+That operation is not available on integers of more than %d bytes.",
+ (int) sizeof (ULONGEST));
+
+ /* Start at the most significant end of the integer, and work towards
+ the least significant. */
+ retval = 0;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ 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 (const void *addr, int orig_len, LONGEST *pval)
+{
+ char *p, *first_addr;
+ int len;
+
+ len = orig_len;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ 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;
+}
+
+
+/* Treat the bytes at BUF as a pointer of type TYPE, and return the
+ address it represents. */
+CORE_ADDR
+extract_typed_address (const void *buf, struct type *type)
+{
+ if (TYPE_CODE (type) != TYPE_CODE_PTR
+ && TYPE_CODE (type) != TYPE_CODE_REF)
+ internal_error (__FILE__, __LINE__,
+ "extract_typed_address: "
+ "type is not a pointer or reference");
+
+ return POINTER_TO_ADDRESS (type, buf);
+}
+
+
+void
+store_signed_integer (void *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 == BFD_ENDIAN_BIG)
+ {
+ 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 (void *addr, int len, ULONGEST 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 == BFD_ENDIAN_BIG)
+ {
+ for (p = endaddr - 1; p >= startaddr; --p)
+ {
+ *p = val & 0xff;
+ val >>= 8;
+ }
+ }
+ else
+ {
+ for (p = startaddr; p < endaddr; ++p)
+ {
+ *p = val & 0xff;
+ val >>= 8;
+ }
+ }
+}
+
+/* Store the address ADDR as a pointer of type TYPE at BUF, in target
+ form. */
+void
+store_typed_address (void *buf, struct type *type, CORE_ADDR addr)
+{
+ if (TYPE_CODE (type) != TYPE_CODE_PTR
+ && TYPE_CODE (type) != TYPE_CODE_REF)
+ internal_error (__FILE__, __LINE__,
+ "store_typed_address: "
+ "type is not a pointer or reference");
+
+ ADDRESS_TO_POINTER (type, buf, addr);
+}
+
+
+
+/* Return a `value' with the contents of (virtual or cooked) register
+ REGNUM as found in the specified FRAME. The register's type is
+ determined by register_type().
+
+ NOTE: returns NULL if register value is not available. Caller will
+ check return value or die! */
+
+struct value *
+value_of_register (int regnum, struct frame_info *frame)
+{
+ CORE_ADDR addr;
+ int optim;
+ struct value *reg_val;
+ int realnum;
+ char raw_buffer[MAX_REGISTER_SIZE];
+ enum lval_type lval;
+
+ /* User registers lie completely outside of the range of normal
+ registers. Catch them early so that the target never sees them. */
+ if (regnum >= NUM_REGS + NUM_PSEUDO_REGS)
+ return value_of_user_reg (regnum, frame);
+
+ frame_register (frame, regnum, &optim, &lval, &addr, &realnum, raw_buffer);
+
+ /* FIXME: cagney/2002-05-15: This test is just bogus.
+
+ It indicates that the target failed to supply a value for a
+ register because it was "not available" at this time. Problem
+ is, the target still has the register and so get saved_register()
+ may be returning a value saved on the stack. */
+
+ if (register_cached (regnum) < 0)
+ return NULL; /* register value not available */
+
+ reg_val = allocate_value (register_type (current_gdbarch, regnum));
+
+ /* Convert raw data to virtual format if necessary. */
+
+ if (DEPRECATED_REGISTER_CONVERTIBLE_P ()
+ && DEPRECATED_REGISTER_CONVERTIBLE (regnum))
+ {
+ DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (regnum, register_type (current_gdbarch, regnum),
+ raw_buffer, VALUE_CONTENTS_RAW (reg_val));
+ }
+ else if (DEPRECATED_REGISTER_RAW_SIZE (regnum) == DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum))
+ memcpy (VALUE_CONTENTS_RAW (reg_val), raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ else
+ internal_error (__FILE__, __LINE__,
+ "Register \"%s\" (%d) has conflicting raw (%d) and virtual (%d) size",
+ REGISTER_NAME (regnum),
+ regnum,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum),
+ DEPRECATED_REGISTER_VIRTUAL_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;
+}
+
+/* Given a pointer of type TYPE in target form in BUF, return the
+ address it represents. */
+CORE_ADDR
+unsigned_pointer_to_address (struct type *type, const void *buf)
+{
+ return extract_unsigned_integer (buf, TYPE_LENGTH (type));
+}
+
+CORE_ADDR
+signed_pointer_to_address (struct type *type, const void *buf)
+{
+ return extract_signed_integer (buf, TYPE_LENGTH (type));
+}
+
+/* Given an address, store it as a pointer of type TYPE in target
+ format in BUF. */
+void
+unsigned_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr)
+{
+ store_unsigned_integer (buf, TYPE_LENGTH (type), addr);
+}
+
+void
+address_to_signed_pointer (struct type *type, void *buf, CORE_ADDR addr)
+{
+ store_signed_integer (buf, TYPE_LENGTH (type), addr);
+}
+
+/* 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 (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_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ /* FIXME: cagney/2004-01-26: It should be possible to
+ unconditionally call the SYMBOL_OPS method when available.
+ Unfortunately DWARF 2 stores the frame-base (instead of the
+ function) location in a function's symbol. Oops! For the
+ moment enable this when/where applicable. */
+ return SYMBOL_OPS (sym)->read_needs_frame (sym);
+
+ 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_HP_THREAD_LOCAL_STATIC:
+ return 1;
+
+ case LOC_UNDEF:
+ case LOC_CONST:
+ case LOC_STATIC:
+ case LOC_INDIRECT:
+ 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 deprecated_selected_frame. */
+
+struct value *
+read_var_value (struct symbol *var, struct frame_info *frame)
+{
+ struct value *v;
+ struct type *type = SYMBOL_TYPE (var);
+ CORE_ADDR addr;
+ int len;
+
+ v = allocate_value (type);
+ VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */
+ VALUE_BFD_SECTION (v) = SYMBOL_BFD_SECTION (var);
+
+ len = TYPE_LENGTH (type);
+
+
+ /* FIXME drow/2003-09-06: this call to the selected frame should be
+ pushed upwards to the callers. */
+ if (frame == NULL)
+ frame = deprecated_safe_get_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. */
+ if (overlay_debugging)
+ {
+ CORE_ADDR addr
+ = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var),
+ SYMBOL_BFD_SECTION (var));
+ store_typed_address (VALUE_CONTENTS_RAW (v), type, addr);
+ }
+ else
+ store_typed_address (VALUE_CONTENTS_RAW (v), type,
+ SYMBOL_VALUE_ADDRESS (var));
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ 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:
+ if (overlay_debugging)
+ addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var),
+ SYMBOL_BFD_SECTION (var));
+ else
+ addr = SYMBOL_VALUE_ADDRESS (var);
+ break;
+
+ case LOC_INDIRECT:
+ {
+ /* The import slot does not have a real address in it from the
+ dynamic loader (dld.sl on HP-UX), if the target hasn't
+ begun execution yet, so check for that. */
+ CORE_ADDR locaddr;
+ struct value *loc;
+ if (!target_has_execution)
+ error ("\
+Attempt to access variable defined in different shared object or load module when\n\
+addresses have not been bound by the dynamic loader. Try again when executable is running.");
+
+ locaddr = SYMBOL_VALUE_ADDRESS (var);
+ loc = value_at (lookup_pointer_type (type), locaddr, NULL);
+ addr = value_as_address (loc);
+ }
+
+ case LOC_ARG:
+ if (frame == NULL)
+ return 0;
+ addr = get_frame_args_address (frame);
+ if (!addr)
+ return 0;
+ addr += SYMBOL_VALUE (var);
+ break;
+
+ case LOC_REF_ARG:
+ {
+ struct value *ref;
+ CORE_ADDR argref;
+ if (frame == NULL)
+ return 0;
+ argref = get_frame_args_address (frame);
+ if (!argref)
+ return 0;
+ argref += SYMBOL_VALUE (var);
+ ref = value_at (lookup_pointer_type (type), argref, NULL);
+ addr = value_as_address (ref);
+ break;
+ }
+
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ if (frame == NULL)
+ return 0;
+ addr = get_frame_locals_address (frame);
+ addr += SYMBOL_VALUE (var);
+ break;
+
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ case LOC_HP_THREAD_LOCAL_STATIC:
+ {
+ struct value *regval;
+
+ regval = value_from_register (lookup_pointer_type (type),
+ SYMBOL_BASEREG (var), frame);
+ if (regval == NULL)
+ error ("Value of base register not available.");
+ addr = value_as_address (regval);
+ addr += SYMBOL_VALUE (var);
+ break;
+ }
+
+ case LOC_TYPEDEF:
+ error ("Cannot look up value of a typedef");
+ break;
+
+ case LOC_BLOCK:
+ if (overlay_debugging)
+ VALUE_ADDRESS (v) = symbol_overlayed_address
+ (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_BFD_SECTION (var));
+ else
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ return v;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ {
+ struct block *b;
+ int regno = SYMBOL_VALUE (var);
+ struct value *regval;
+
+ if (frame == NULL)
+ return 0;
+ b = get_frame_block (frame, 0);
+
+ if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR)
+ {
+ regval = value_from_register (lookup_pointer_type (type),
+ regno,
+ frame);
+
+ if (regval == NULL)
+ error ("Value of register variable not available.");
+
+ addr = value_as_address (regval);
+ VALUE_LVAL (v) = lval_memory;
+ }
+ else
+ {
+ regval = value_from_register (type, regno, frame);
+
+ if (regval == NULL)
+ error ("Value of register variable not available.");
+ return regval;
+ }
+ }
+ break;
+
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ /* FIXME: cagney/2004-01-26: It should be possible to
+ unconditionally call the SYMBOL_OPS method when available.
+ Unfortunately DWARF 2 stores the frame-base (instead of the
+ function) location in a function's symbol. Oops! For the
+ moment enable this when/where applicable. */
+ if (frame == 0 && SYMBOL_OPS (var)->read_needs_frame (var))
+ return 0;
+ return SYMBOL_OPS (var)->read_variable (var, frame);
+
+ case LOC_UNRESOLVED:
+ {
+ struct minimal_symbol *msym;
+
+ msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (var), NULL, NULL);
+ if (msym == NULL)
+ return 0;
+ if (overlay_debugging)
+ addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (msym),
+ SYMBOL_BFD_SECTION (msym));
+ else
+ 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.
+
+ NOTE: returns NULL if register value is not available.
+ Caller will check return value or die! */
+
+struct value *
+value_from_register (struct type *type, int regnum, struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct value *v = allocate_value (type);
+ CHECK_TYPEDEF (type);
+
+ if (TYPE_LENGTH (type) == 0)
+ {
+ /* It doesn't matter much what we return for this: since the
+ length is zero, it could be anything. But if allowed to see
+ a zero-length type, the register-finding loop below will set
+ neither mem_stor nor reg_stor, and then report an internal
+ error.
+
+ Zero-length types can legitimately arise from declarations
+ like 'struct {}' (a GCC extension, not valid ISO C). GDB may
+ also create them when it finds bogus debugging information;
+ for example, in GCC 2.95.4 and binutils 2.11.93.0.2, the
+ STABS BINCL->EXCL compression process can create bad type
+ numbers. GDB reads these as TYPE_CODE_UNDEF types, with zero
+ length. (That bug is actually the only known way to get a
+ zero-length value allocated to a register --- which is what
+ it takes to make it here.)
+
+ We'll just attribute the value to the original register. */
+ VALUE_LVAL (v) = lval_register;
+ VALUE_ADDRESS (v) = regnum;
+ VALUE_REGNO (v) = regnum;
+ }
+ else if (CONVERT_REGISTER_P (regnum, type))
+ {
+ /* The ISA/ABI need to something weird when obtaining the
+ specified value from this register. It might need to
+ re-order non-adjacent, starting with REGNUM (see MIPS and
+ i386). It might need to convert the [float] register into
+ the corresponding [integer] type (see Alpha). The assumption
+ is that REGISTER_TO_VALUE populates the entire value
+ including the location. */
+ REGISTER_TO_VALUE (frame, regnum, type, VALUE_CONTENTS_RAW (v));
+ VALUE_LVAL (v) = lval_reg_frame_relative;
+ VALUE_FRAME_ID (v) = get_frame_id (frame);
+ VALUE_FRAME_REGNUM (v) = regnum;
+ }
+ else
+ {
+ int local_regnum;
+ int mem_stor = 0, reg_stor = 0;
+ int mem_tracking = 1;
+ CORE_ADDR last_addr = 0;
+ CORE_ADDR first_addr = 0;
+ int first_realnum = regnum;
+ int len = TYPE_LENGTH (type);
+ int value_bytes_copied;
+ int optimized = 0;
+ char *value_bytes = (char *) alloca (len + MAX_REGISTER_SIZE);
+
+ /* Copy all of the data out, whereever it may be. */
+ for (local_regnum = regnum, value_bytes_copied = 0;
+ value_bytes_copied < len;
+ (value_bytes_copied += DEPRECATED_REGISTER_RAW_SIZE (local_regnum),
+ ++local_regnum))
+ {
+ int realnum;
+ int optim;
+ enum lval_type lval;
+ CORE_ADDR addr;
+ frame_register (frame, local_regnum, &optim, &lval, &addr,
+ &realnum, value_bytes + value_bytes_copied);
+ optimized += optim;
+ if (register_cached (local_regnum) == -1)
+ return NULL; /* register value not available */
+
+ if (regnum == local_regnum)
+ {
+ first_addr = addr;
+ first_realnum = realnum;
+ }
+ if (lval == lval_register)
+ reg_stor++;
+ else
+ {
+ mem_stor++;
+
+ mem_tracking = (mem_tracking
+ && (regnum == local_regnum
+ || addr == last_addr));
+ }
+ last_addr = addr;
+ }
+
+ /* FIXME: cagney/2003-06-04: Shouldn't this always use
+ lval_reg_frame_relative? If it doesn't and the register's
+ location changes (say after a resume) then this value is
+ going to have wrong information. */
+ 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_ID (v) = get_frame_id (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;
+ VALUE_REGNO (v) = first_realnum;
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ "value_from_register: Value not stored anywhere!");
+
+ VALUE_OPTIMIZED_OUT (v) = optimized;
+
+ /* Any structure stored in more than one register will always be
+ an integral number of registers. Otherwise, you need to do
+ some fiddling with the last register copied here for little
+ endian machines. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && len < DEPRECATED_REGISTER_RAW_SIZE (regnum))
+ /* Big-endian, and we want less than full size. */
+ VALUE_OFFSET (v) = DEPRECATED_REGISTER_RAW_SIZE (regnum) - len;
+ else
+ VALUE_OFFSET (v) = 0;
+ memcpy (VALUE_CONTENTS_RAW (v), value_bytes + 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. */
+
+struct value *
+locate_var_value (struct symbol *var, struct frame_info *frame)
+{
+ CORE_ADDR addr = 0;
+ struct type *type = SYMBOL_TYPE (var);
+ struct value *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_PRINT_NAME (var));
+
+ if (VALUE_LAZY (lazy_value)
+ || TYPE_CODE (type) == TYPE_CODE_FUNC)
+ {
+ struct value *val;
+
+ addr = VALUE_ADDRESS (lazy_value);
+ val = value_from_pointer (lookup_pointer_type (type), addr);
+ VALUE_BFD_SECTION (val) = VALUE_BFD_SECTION (lazy_value);
+ return val;
+ }
+
+ /* Not a memory address; check what the problem was. */
+ switch (VALUE_LVAL (lazy_value))
+ {
+ case lval_register:
+ gdb_assert (REGISTER_NAME (VALUE_REGNO (lazy_value)) != NULL
+ && *REGISTER_NAME (VALUE_REGNO (lazy_value)) != '\0');
+ error("Address requested for identifier "
+ "\"%s\" which is in register $%s",
+ SYMBOL_PRINT_NAME (var),
+ REGISTER_NAME (VALUE_REGNO (lazy_value)));
+ break;
+
+ case lval_reg_frame_relative:
+ gdb_assert (REGISTER_NAME (VALUE_FRAME_REGNUM (lazy_value)) != NULL
+ && *REGISTER_NAME (VALUE_FRAME_REGNUM (lazy_value)) != '\0');
+ error("Address requested for identifier "
+ "\"%s\" which is in frame register $%s",
+ SYMBOL_PRINT_NAME (var),
+ REGISTER_NAME (VALUE_FRAME_REGNUM (lazy_value)));
+ break;
+
+ default:
+ error ("Can't take address of \"%s\" which isn't an lvalue.",
+ SYMBOL_PRINT_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 0000000..e1d32b0
--- /dev/null
+++ b/contrib/gdb/gdb/fork-child.c
@@ -0,0 +1,469 @@
+/* Fork a Unix child process, and set up to debug it, for GDB.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001 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 "gdb_wait.h"
+#include "gdb_vfork.h"
+#include "gdbcore.h"
+#include "terminal.h"
+#include "gdbthread.h"
+#include "command.h" /* for dont_repeat () */
+
+#include <signal.h>
+
+/* This just gets used as a default if we can't find SHELL */
+#ifndef SHELL_FILE
+#define SHELL_FILE "/bin/sh"
+#endif
+
+extern char **environ;
+
+/* This function breaks up an argument string into an argument
+ * vector suitable for passing to execvp().
+ * E.g., on "run a b c d" this routine would get as input
+ * the string "a b c d", and as output it would fill in argv with
+ * the four arguments "a", "b", "c", "d".
+ */
+static void
+breakup_args (char *scratch, char **argv)
+{
+ char *cp = scratch;
+
+ for (;;)
+ {
+
+ /* Scan past leading separators */
+ while (*cp == ' ' || *cp == '\t' || *cp == '\n')
+ {
+ cp++;
+ }
+
+ /* Break if at end of string */
+ if (*cp == '\0')
+ break;
+
+ /* Take an arg */
+ *argv++ = cp;
+
+ /* Scan for next arg separator */
+ cp = strchr (cp, ' ');
+ if (cp == NULL)
+ cp = strchr (cp, '\t');
+ if (cp == NULL)
+ cp = strchr (cp, '\n');
+
+ /* No separators => end of string => break */
+ if (cp == NULL)
+ break;
+
+ /* Replace the separator with a terminator */
+ *cp++ = '\0';
+ }
+
+ /* execv requires a null-terminated arg vector */
+ *argv = NULL;
+
+}
+
+/* When executing a command under the given shell, return non-zero
+ if the '!' character should be escaped when embedded in a quoted
+ command-line argument. */
+
+static int
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+ const int shell_file_len = strlen (shell_file);
+
+ /* Bang should be escaped only in C Shells. For now, simply check
+ that the shell name ends with 'csh', which covers at least csh
+ and tcsh. This should be good enough for now. */
+
+ if (shell_file_len < 3)
+ return 0;
+
+ if (shell_file[shell_file_len - 3] == 'c'
+ && shell_file[shell_file_len - 2] == 's'
+ && shell_file[shell_file_len - 1] == 'h')
+ return 1;
+
+ return 0;
+}
+
+/* Start an inferior Unix child process and sets inferior_ptid 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(). */
+
+/* This function is NOT-REENTRANT. Some of the variables have been
+ made static to ensure that they survive the vfork() call. */
+
+void
+fork_inferior (char *exec_file_arg, char *allargs, char **env,
+ void (*traceme_fun) (void), void (*init_trace_fun) (int),
+ void (*pre_trace_fun) (void), char *shell_file_arg)
+{
+ 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;
+ static char *shell_file;
+ static char *exec_file;
+ char **save_our_env;
+ int shell = 0;
+ static char **argv;
+
+ /* If no exec file handed to us, get it from the exec-file command -- with
+ a good, common error message if none is specified. */
+ exec_file = exec_file_arg;
+ if (exec_file == 0)
+ exec_file = get_exec_file (1);
+
+ /* STARTUP_WITH_SHELL is defined in inferior.h.
+ * If 0, we'll just do a fork/exec, no shell, so don't
+ * bother figuring out what shell.
+ */
+ shell_file = shell_file_arg;
+ if (STARTUP_WITH_SHELL)
+ {
+ /* Figure out what shell to start up the user program under. */
+ if (shell_file == NULL)
+ shell_file = getenv ("SHELL");
+ if (shell_file == NULL)
+ shell_file = default_shell_file;
+ shell = 1;
+ }
+
+ /* 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
+
+ if (!shell)
+ {
+ /* We're going to call execvp. Create argv */
+ /* Largest case: every other character is a separate arg */
+ argv = (char **) xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) * sizeof (*argv));
+ argv[0] = exec_file;
+ breakup_args (allargs, &argv[1]);
+
+ }
+ else
+ {
+
+ /* We're going to call a shell */
+
+ /* Now add exec_file, quoting as necessary. */
+
+ char *p;
+ int need_to_quote;
+ const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+ strcat (shell_command, "exec ");
+
+ /* 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 ' ':
+ 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 if (*p == '!' && escape_bang)
+ 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 there's any initialization of the target layers that must happen
+ to prepare to handle the child we're about fork, do it now...
+ */
+ if (pre_trace_fun != NULL)
+ (*pre_trace_fun) ();
+
+ /* Create the child process. Note that the apparent call to vfork()
+ below *might* actually be a call to fork() due to the fact that
+ autoconf will ``#define vfork fork'' on certain platforms. */
+ if (debug_fork)
+ pid = fork ();
+ else
+ pid = vfork ();
+
+ 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) ();
+ /* The call above set this process (the "child") as debuggable
+ * by the original gdb process (the "parent"). Since processes
+ * (unlike people) can have only one parent, if you are
+ * debugging gdb itself (and your debugger is thus _already_ the
+ * controller/parent for this child), code from here on out
+ * is undebuggable. Indeed, you probably got an error message
+ * saying "not parent". Sorry--you'll have to use print statements!
+ */
+
+ /* 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;
+
+ /* If we decided above to start up with a shell,
+ * we exec the shell,
+ * "-c" says to interpret the next arg as a shell command
+ * to execute, and this command is "exec <target-program> <args>".
+ * "-f" means "fast startup" to the c-shell, which means
+ * don't do .cshrc file. Doing .cshrc may cause fork/exec
+ * events which will confuse debugger start-up code.
+ */
+ if (shell)
+ {
+ execlp (shell_file, shell_file, "-c", shell_command, (char *) 0);
+
+ /* If we get here, it's an error */
+ fprintf_unfiltered (gdb_stderr, "Cannot exec %s: %s.\n", shell_file,
+ safe_strerror (errno));
+ gdb_flush (gdb_stderr);
+ _exit (0177);
+ }
+ else
+ {
+ /* Otherwise, we directly exec the target program with execvp. */
+ int i;
+ char *errstring;
+
+ execvp (exec_file, argv);
+
+ /* If we get here, it's an error */
+ errstring = safe_strerror (errno);
+ fprintf_unfiltered (gdb_stderr, "Cannot exec %s ", exec_file);
+
+ i = 1;
+ while (argv[i] != NULL)
+ {
+ if (i != 1)
+ fprintf_unfiltered (gdb_stderr, " ");
+ fprintf_unfiltered (gdb_stderr, "%s", argv[i]);
+ i++;
+ }
+ fprintf_unfiltered (gdb_stderr, ".\n");
+ /* This extra info seems to be useless
+ fprintf_unfiltered (gdb_stderr, "Got error %s.\n", errstring);
+ */
+ 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_ptid = pid_to_ptid (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 dependent 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 (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;
+
+ if (STARTUP_WITH_SHELL)
+ inferior_ignoring_startup_exec_events = ntraps;
+ else
+ inferior_ignoring_startup_exec_events = 0;
+ inferior_ignoring_leading_exec_events =
+ target_reported_exec_events_per_exec_call () - 1;
+
+ while (1)
+ {
+ /* Make wait_for_inferior be quiet */
+ stop_soon = STOP_QUIETLY;
+ 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;
+ }
+
+ pending_execs = pending_execs - 1;
+ if (0 == pending_execs)
+ break;
+
+ resume (0, TARGET_SIGNAL_0); /* Just make it go on */
+ }
+ }
+ stop_soon = NO_STOP_QUIETLY;
+}
diff --git a/contrib/gdb/gdb/frame-base.c b/contrib/gdb/gdb/frame-base.c
new file mode 100644
index 0000000..66a0106
--- /dev/null
+++ b/contrib/gdb/gdb/frame-base.c
@@ -0,0 +1,150 @@
+/* Definitions for frame address handler, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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-base.h"
+#include "frame.h"
+
+/* A default frame base implementations. If it wasn't for the old
+ DEPRECATED_FRAME_LOCALS_ADDRESS and DEPRECATED_FRAME_ARGS_ADDRESS,
+ these could be combined into a single function. All architectures
+ really need to override this. */
+
+static CORE_ADDR
+default_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct frame_info *this_frame = get_prev_frame (next_frame);
+ return get_frame_base (this_frame); /* sigh! */
+}
+
+static CORE_ADDR
+default_frame_locals_address (struct frame_info *next_frame, void **this_cache)
+{
+ if (DEPRECATED_FRAME_LOCALS_ADDRESS_P ())
+ {
+ /* This is bad. The computation of per-frame locals address
+ should use a per-frame frame-base. */
+ struct frame_info *this_frame = get_prev_frame (next_frame);
+ return DEPRECATED_FRAME_LOCALS_ADDRESS (this_frame);
+ }
+ return default_frame_base_address (next_frame, this_cache);
+}
+
+static CORE_ADDR
+default_frame_args_address (struct frame_info *next_frame, void **this_cache)
+{
+ if (DEPRECATED_FRAME_ARGS_ADDRESS_P ())
+ {
+ struct frame_info *this_frame = get_prev_frame (next_frame);
+ return DEPRECATED_FRAME_ARGS_ADDRESS (this_frame);
+ }
+ return default_frame_base_address (next_frame, this_cache);
+}
+
+const struct frame_base default_frame_base = {
+ NULL, /* No parent. */
+ default_frame_base_address,
+ default_frame_locals_address,
+ default_frame_args_address
+};
+
+static struct gdbarch_data *frame_base_data;
+
+struct frame_base_table
+{
+ frame_base_sniffer_ftype **sniffer;
+ const struct frame_base *default_base;
+ int nr;
+};
+
+static void *
+frame_base_init (struct gdbarch *gdbarch)
+{
+ struct frame_base_table *table = XCALLOC (1, struct frame_base_table);
+ table->default_base = &default_frame_base;
+ return table;
+}
+
+static struct frame_base_table *
+frame_base_table (struct gdbarch *gdbarch)
+{
+ struct frame_base_table *table = gdbarch_data (gdbarch, frame_base_data);
+ if (table == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ table = frame_base_init (gdbarch);
+ set_gdbarch_data (gdbarch, frame_base_data, table);
+ }
+ return table;
+}
+
+/* Append a predicate to the end of the table. */
+static void
+append_predicate (struct frame_base_table *table,
+ frame_base_sniffer_ftype *sniffer)
+{
+ table->sniffer = xrealloc (table->sniffer,
+ ((table->nr + 1)
+ * sizeof (frame_base_sniffer_ftype *)));
+ table->sniffer[table->nr] = sniffer;
+ table->nr++;
+}
+
+void
+frame_base_append_sniffer (struct gdbarch *gdbarch,
+ frame_base_sniffer_ftype *sniffer)
+{
+ struct frame_base_table *table = frame_base_table (gdbarch);
+ append_predicate (table, sniffer);
+}
+
+void
+frame_base_set_default (struct gdbarch *gdbarch,
+ const struct frame_base *default_base)
+{
+ struct frame_base_table *table = frame_base_table (gdbarch);
+ table->default_base = default_base;
+}
+
+const struct frame_base *
+frame_base_find_by_frame (struct frame_info *next_frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct frame_base_table *table = frame_base_table (gdbarch);
+ int i;
+ for (i = 0; i < table->nr; i++)
+ {
+ const struct frame_base *desc = NULL;
+ desc = table->sniffer[i] (next_frame);
+ if (desc != NULL)
+ return desc;
+ }
+ return table->default_base;
+}
+
+extern initialize_file_ftype _initialize_frame_base; /* -Wmissing-prototypes */
+
+void
+_initialize_frame_base (void)
+{
+ frame_base_data = register_gdbarch_data (frame_base_init);
+}
diff --git a/contrib/gdb/gdb/frame-base.h b/contrib/gdb/gdb/frame-base.h
new file mode 100644
index 0000000..680e9d5
--- /dev/null
+++ b/contrib/gdb/gdb/frame-base.h
@@ -0,0 +1,93 @@
+/* Definitions for a frame base, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_BASE_H)
+#define FRAME_BASE_H 1
+
+struct frame_info;
+struct frame_id;
+struct frame_unwind;
+struct frame_base;
+struct gdbarch;
+struct regcache;
+
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+ and that this is a `normal frame'; use the NEXT frame, and its
+ register unwind method, to determine the address of THIS frame's
+ `base'.
+
+ The exact meaning of `base' is highly dependant on the type of the
+ debug info. It is assumed that dwarf2, stabs, ... will each
+ provide their own methods.
+
+ A typical implmentation will return the same value for base,
+ locals-base and args-base. That value, however, will likely be
+ different to the frame ID's stack address. */
+
+/* A generic base address. */
+
+typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *next_frame,
+ void **this_base_cache);
+
+/* The base address of the frame's local variables. */
+
+typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *next_frame,
+ void **this_base_cache);
+
+/* The base address of the frame's arguments / parameters. */
+
+typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *next_frame,
+ void **this_base_cache);
+
+struct frame_base
+{
+ /* If non-NULL, a low-level unwinder that shares its implementation
+ with this high-level frame-base method. */
+ const struct frame_unwind *unwind;
+ frame_this_base_ftype *this_base;
+ frame_this_locals_ftype *this_locals;
+ frame_this_args_ftype *this_args;
+};
+
+/* Given the NEXT frame, return the frame base methods for THIS frame,
+ or NULL if it can't handle THIS frame. */
+
+typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *next_frame);
+
+/* Append a frame base sniffer to the list. The sniffers are polled
+ in the order that they are appended. */
+
+extern void frame_base_append_sniffer (struct gdbarch *gdbarch,
+ frame_base_sniffer_ftype *sniffer);
+
+/* Set the default frame base. If all else fails, this one is
+ returned. If this isn't set, the default is to use legacy code
+ that uses things like the frame ID's base (ulgh!). */
+
+extern void frame_base_set_default (struct gdbarch *gdbarch,
+ const struct frame_base *def);
+
+/* Iterate through the list of frame base handlers until one returns
+ an implementation. */
+
+extern const struct frame_base *frame_base_find_by_frame (struct frame_info *next_frame);
+
+#endif
diff --git a/contrib/gdb/gdb/frame-unwind.c b/contrib/gdb/gdb/frame-unwind.c
new file mode 100644
index 0000000..82eaf7c
--- /dev/null
+++ b/contrib/gdb/gdb/frame-unwind.c
@@ -0,0 +1,99 @@
+/* Definitions for frame unwinder, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame-unwind.h"
+#include "gdb_assert.h"
+#include "dummy-frame.h"
+
+static struct gdbarch_data *frame_unwind_data;
+
+struct frame_unwind_table
+{
+ frame_unwind_sniffer_ftype **sniffer;
+ int nr;
+};
+
+/* Append a predicate to the end of the table. */
+static void
+append_predicate (struct frame_unwind_table *table,
+ frame_unwind_sniffer_ftype *sniffer)
+{
+ table->sniffer = xrealloc (table->sniffer, ((table->nr + 1)
+ * sizeof (frame_unwind_sniffer_ftype *)));
+ table->sniffer[table->nr] = sniffer;
+ table->nr++;
+}
+
+static void *
+frame_unwind_init (struct gdbarch *gdbarch)
+{
+ struct frame_unwind_table *table = XCALLOC (1, struct frame_unwind_table);
+ append_predicate (table, dummy_frame_sniffer);
+ return table;
+}
+
+void
+frame_unwind_append_sniffer (struct gdbarch *gdbarch,
+ frame_unwind_sniffer_ftype *sniffer)
+{
+ struct frame_unwind_table *table =
+ gdbarch_data (gdbarch, frame_unwind_data);
+ if (table == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ table = frame_unwind_init (gdbarch);
+ set_gdbarch_data (gdbarch, frame_unwind_data, table);
+ }
+ append_predicate (table, sniffer);
+}
+
+const struct frame_unwind *
+frame_unwind_find_by_frame (struct frame_info *next_frame)
+{
+ int i;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
+ if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES && legacy_frame_p (gdbarch))
+ /* Seriously old code. Don't even try to use this new mechanism.
+ (Note: The variable USE_GENERIC_DUMMY_FRAMES is deprecated, not
+ the dummy frame mechanism. All architectures should be using
+ generic dummy frames). */
+ return legacy_saved_regs_unwind;
+ for (i = 0; i < table->nr; i++)
+ {
+ const struct frame_unwind *desc;
+ desc = table->sniffer[i] (next_frame);
+ if (desc != NULL)
+ return desc;
+ }
+ return legacy_saved_regs_unwind;
+}
+
+extern initialize_file_ftype _initialize_frame_unwind; /* -Wmissing-prototypes */
+
+void
+_initialize_frame_unwind (void)
+{
+ frame_unwind_data = register_gdbarch_data (frame_unwind_init);
+}
diff --git a/contrib/gdb/gdb/frame-unwind.h b/contrib/gdb/gdb/frame-unwind.h
new file mode 100644
index 0000000..8d17280
--- /dev/null
+++ b/contrib/gdb/gdb/frame-unwind.h
@@ -0,0 +1,141 @@
+/* Definitions for a frame unwinder, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_UNWIND_H)
+#define FRAME_UNWIND_H 1
+
+struct frame_info;
+struct frame_id;
+struct frame_unwind;
+struct gdbarch;
+struct regcache;
+
+#include "frame.h" /* For enum frame_type. */
+
+/* The following unwind functions assume a chain of frames forming the
+ sequence: (outer) prev <-> this <-> next (inner). All the
+ functions are called with called with the next frame's `struct
+ frame_info' and and this frame's prologue cache.
+
+ THIS frame's register values can be obtained by unwinding NEXT
+ frame's registers (a recursive operation).
+
+ THIS frame's prologue cache can be used to cache information such
+ as where this frame's prologue stores the previous frame's
+ registers. */
+
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+ use the NEXT frame, and its register unwind method, to determine
+ the frame ID of THIS frame.
+
+ A frame ID provides an invariant that can be used to re-identify an
+ instance of a frame. It is a combination of the frame's `base' and
+ the frame's function's code address.
+
+ Traditionally, THIS frame's ID was determined by examining THIS
+ frame's function's prologue, and identifying the register/offset
+ used as THIS frame's base.
+
+ Example: An examination of THIS frame's prologue reveals that, on
+ entry, it saves the PC(+12), SP(+8), and R1(+4) registers
+ (decrementing the SP by 12). Consequently, the frame ID's base can
+ be determined by adding 12 to the THIS frame's stack-pointer, and
+ the value of THIS frame's SP can be obtained by unwinding the NEXT
+ frame's SP.
+
+ THIS_PROLOGUE_CACHE can be used to share any prolog analysis data
+ with the other unwind methods. Memory for that cache should be
+ allocated using frame_obstack_zalloc(). */
+
+typedef void (frame_this_id_ftype) (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id);
+
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+ use the NEXT frame, and its register unwind method, to unwind THIS
+ frame's registers (returning the value of the specified register
+ REGNUM in the previous frame).
+
+ Traditionally, THIS frame's registers were unwound by examining
+ THIS frame's function's prologue and identifying which registers
+ that prolog code saved on the stack.
+
+ Example: An examination of THIS frame's prologue reveals that, on
+ entry, it saves the PC(+12), SP(+8), and R1(+4) registers
+ (decrementing the SP by 12). Consequently, the value of the PC
+ register in the previous frame is found in memory at SP+12, and
+ THIS frame's SP can be obtained by unwinding the NEXT frame's SP.
+
+ Why not pass in THIS_FRAME? By passing in NEXT frame and THIS
+ cache, the supplied parameters are consistent with the sibling
+ function THIS_ID.
+
+ Can the code call ``frame_register (get_prev_frame (NEXT_FRAME))''?
+ Won't the call frame_register (THIS_FRAME) be faster? Well,
+ ignoring the possability that the previous frame does not yet
+ exist, the ``frame_register (FRAME)'' function is expanded to
+ ``frame_register_unwind (get_next_frame (FRAME)'' and hence that
+ call will expand to ``frame_register_unwind (get_next_frame
+ (get_prev_frame (NEXT_FRAME)))''. Might as well call
+ ``frame_register_unwind (NEXT_FRAME)'' directly.
+
+ THIS_PROLOGUE_CACHE can be used to share any prolog analysis data
+ with the other unwind methods. Memory for that cache should be
+ allocated using frame_obstack_zalloc(). */
+
+typedef void (frame_prev_register_ftype) (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int prev_regnum,
+ int *optimized,
+ enum lval_type * lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep);
+
+struct frame_unwind
+{
+ /* The frame's type. Should this instead be a collection of
+ predicates that test the frame for various attributes? */
+ enum frame_type type;
+ /* Should an attribute indicating the frame's address-in-block go
+ here? */
+ frame_this_id_ftype *this_id;
+ frame_prev_register_ftype *prev_register;
+};
+
+/* Given the NEXT frame, take a wiff of THIS frame's registers (namely
+ the PC and attributes) and if it is the applicable unwinder return
+ the unwind methods, or NULL if it is not. */
+
+typedef const struct frame_unwind *(frame_unwind_sniffer_ftype) (struct frame_info *next_frame);
+
+/* Add a frame sniffer to the list. The predicates are polled in the
+ order that they are appended. The initial list contains the dummy
+ frame sniffer. */
+
+extern void frame_unwind_append_sniffer (struct gdbarch *gdbarch,
+ frame_unwind_sniffer_ftype *sniffer);
+
+/* Iterate through the next frame's sniffers until one returns with an
+ unwinder implementation. */
+
+extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_frame);
+
+#endif
diff --git a/contrib/gdb/gdb/frame.c b/contrib/gdb/gdb/frame.c
new file mode 100644
index 0000000..a032c47
--- /dev/null
+++ b/contrib/gdb/gdb/frame.c
@@ -0,0 +1,2363 @@
+/* Cache and manage frames for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
+ 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "target.h"
+#include "value.h"
+#include "inferior.h" /* for inferior_ptid */
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "user-regs.h"
+#include "gdb_obstack.h"
+#include "dummy-frame.h"
+#include "sentinel-frame.h"
+#include "gdbcore.h"
+#include "annotate.h"
+#include "language.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+/* 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)
+ 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
+{
+ /* Level of this frame. The inner-most (youngest) frame is at level
+ 0. As you move towards the outer-most (oldest) frame, the level
+ increases. This is a cached value. It could just as easily be
+ computed by counting back from the selected frame to the inner
+ most frame. */
+ /* NOTE: cagney/2002-04-05: Perhaphs a level of ``-1'' should be
+ reserved to indicate a bogus frame - one that has been created
+ just to keep GDB happy (GDB always needs a frame). For the
+ moment leave this as speculation. */
+ int level;
+
+ /* The frame's type. */
+ /* FIXME: cagney/2003-04-02: Should instead be returning
+ ->unwind->type. Unfortunately, legacy code is still explicitly
+ setting the type using the method deprecated_set_frame_type.
+ Eliminate that method and this field can be eliminated. */
+ enum frame_type type;
+
+ /* 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 previous frame, not the address
+ where the sp was saved. */
+ /* Allocated by frame_saved_regs_zalloc () which is called /
+ initialized by DEPRECATED_FRAME_INIT_SAVED_REGS(). */
+ CORE_ADDR *saved_regs; /*NUM_REGS + NUM_PSEUDO_REGS*/
+
+ /* Anything extra for this structure that may have been defined in
+ the machine dependent files. */
+ /* Allocated by frame_extra_info_zalloc () which is called /
+ initialized by DEPRECATED_INIT_EXTRA_FRAME_INFO */
+ struct frame_extra_info *extra_info;
+
+ /* The frame's low-level unwinder and corresponding cache. The
+ low-level unwinder is responsible for unwinding register values
+ for the previous frame. The low-level unwind methods are
+ selected based on the presence, or otherwize, of register unwind
+ information such as CFI. */
+ void *prologue_cache;
+ const struct frame_unwind *unwind;
+
+ /* Cached copy of the previous frame's resume address. */
+ struct {
+ int p;
+ CORE_ADDR value;
+ } prev_pc;
+
+ /* Cached copy of the previous frame's function address. */
+ struct
+ {
+ CORE_ADDR addr;
+ int p;
+ } prev_func;
+
+ /* This frame's ID. */
+ struct
+ {
+ int p;
+ struct frame_id value;
+ } this_id;
+
+ /* The frame's high-level base methods, and corresponding cache.
+ The high level base methods are selected based on the frame's
+ debug info. */
+ const struct frame_base *base;
+ void *base_cache;
+
+ /* Pointers to the next (down, inner, younger) and previous (up,
+ outer, older) frame_info's in the frame cache. */
+ struct frame_info *next; /* down, inner, younger */
+ int prev_p;
+ struct frame_info *prev; /* up, outer, older */
+};
+
+/* Flag to control debugging. */
+
+static int frame_debug;
+
+/* Flag to indicate whether backtraces should stop at main et.al. */
+
+static int backtrace_past_main;
+static unsigned int backtrace_limit = UINT_MAX;
+
+
+void
+fprint_frame_id (struct ui_file *file, struct frame_id id)
+{
+ fprintf_unfiltered (file, "{stack=0x%s,code=0x%s,special=0x%s}",
+ paddr_nz (id.stack_addr),
+ paddr_nz (id.code_addr),
+ paddr_nz (id.special_addr));
+}
+
+static void
+fprint_frame_type (struct ui_file *file, enum frame_type type)
+{
+ switch (type)
+ {
+ case UNKNOWN_FRAME:
+ fprintf_unfiltered (file, "UNKNOWN_FRAME");
+ return;
+ case NORMAL_FRAME:
+ fprintf_unfiltered (file, "NORMAL_FRAME");
+ return;
+ case DUMMY_FRAME:
+ fprintf_unfiltered (file, "DUMMY_FRAME");
+ return;
+ case SIGTRAMP_FRAME:
+ fprintf_unfiltered (file, "SIGTRAMP_FRAME");
+ return;
+ default:
+ fprintf_unfiltered (file, "<unknown type>");
+ return;
+ };
+}
+
+static void
+fprint_frame (struct ui_file *file, struct frame_info *fi)
+{
+ if (fi == NULL)
+ {
+ fprintf_unfiltered (file, "<NULL frame>");
+ return;
+ }
+ fprintf_unfiltered (file, "{");
+ fprintf_unfiltered (file, "level=%d", fi->level);
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "type=");
+ fprint_frame_type (file, fi->type);
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "unwind=");
+ if (fi->unwind != NULL)
+ gdb_print_host_address (fi->unwind, file);
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "pc=");
+ if (fi->next != NULL && fi->next->prev_pc.p)
+ fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_pc.value));
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "id=");
+ if (fi->this_id.p)
+ fprint_frame_id (file, fi->this_id.value);
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "func=");
+ if (fi->next != NULL && fi->next->prev_func.p)
+ fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_func.addr));
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, "}");
+}
+
+/* Return a frame uniq ID that can be used to, later, re-find the
+ frame. */
+
+struct frame_id
+get_frame_id (struct frame_info *fi)
+{
+ if (fi == NULL)
+ {
+ return null_frame_id;
+ }
+ if (!fi->this_id.p)
+ {
+ gdb_assert (!legacy_frame_p (current_gdbarch));
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
+ fi->level);
+ /* Find the unwinder. */
+ if (fi->unwind == NULL)
+ {
+ fi->unwind = frame_unwind_find_by_frame (fi->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type
+ using the method deprecated_set_frame_type(). */
+ fi->type = fi->unwind->type;
+ }
+ /* Find THIS frame's ID. */
+ fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
+ fi->this_id.p = 1;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame_id (gdb_stdlog, fi->this_id.value);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+ }
+ return fi->this_id.value;
+}
+
+const struct frame_id null_frame_id; /* All zeros. */
+
+struct frame_id
+frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
+ CORE_ADDR special_addr)
+{
+ struct frame_id id;
+ id.stack_addr = stack_addr;
+ id.code_addr = code_addr;
+ id.special_addr = special_addr;
+ return id;
+}
+
+struct frame_id
+frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
+{
+ return frame_id_build_special (stack_addr, code_addr, 0);
+}
+
+int
+frame_id_p (struct frame_id l)
+{
+ int p;
+ /* The .code can be NULL but the .stack cannot. */
+ p = (l.stack_addr != 0);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", p);
+ }
+ return p;
+}
+
+int
+frame_id_eq (struct frame_id l, struct frame_id r)
+{
+ int eq;
+ if (l.stack_addr == 0 || r.stack_addr == 0)
+ /* Like a NaN, if either ID is invalid, the result is false. */
+ eq = 0;
+ else if (l.stack_addr != r.stack_addr)
+ /* If .stack addresses are different, the frames are different. */
+ eq = 0;
+ else if (l.code_addr == 0 || r.code_addr == 0)
+ /* A zero code addr is a wild card, always succeed. */
+ eq = 1;
+ else if (l.code_addr != r.code_addr)
+ /* If .code addresses are different, the frames are different. */
+ eq = 0;
+ else if (l.special_addr == 0 || r.special_addr == 0)
+ /* A zero special addr is a wild card (or unused), always succeed. */
+ eq = 1;
+ else if (l.special_addr == r.special_addr)
+ /* Frames are equal. */
+ eq = 1;
+ else
+ /* No luck. */
+ eq = 0;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ",r=");
+ fprint_frame_id (gdb_stdlog, r);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", eq);
+ }
+ return eq;
+}
+
+int
+frame_id_inner (struct frame_id l, struct frame_id r)
+{
+ int inner;
+ if (l.stack_addr == 0 || r.stack_addr == 0)
+ /* Like NaN, any operation involving an invalid ID always fails. */
+ inner = 0;
+ else
+ /* Only return non-zero when strictly inner than. Note that, per
+ comment in "frame.h", there is some fuzz here. Frameless
+ functions are not strictly inner than (same .stack but
+ different .code and/or .special address). */
+ inner = INNER_THAN (l.stack_addr, r.stack_addr);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ",r=");
+ fprint_frame_id (gdb_stdlog, r);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", inner);
+ }
+ return inner;
+}
+
+struct frame_info *
+frame_find_by_id (struct frame_id id)
+{
+ struct frame_info *frame;
+
+ /* ZERO denotes the null frame, let the caller decide what to do
+ about it. Should it instead return get_current_frame()? */
+ if (!frame_id_p (id))
+ return NULL;
+
+ for (frame = get_current_frame ();
+ frame != NULL;
+ frame = get_prev_frame (frame))
+ {
+ struct frame_id this = get_frame_id (frame);
+ if (frame_id_eq (id, this))
+ /* An exact match. */
+ return frame;
+ if (frame_id_inner (id, this))
+ /* Gone to far. */
+ return NULL;
+ /* Either, we're not yet gone far enough out along the frame
+ chain (inner(this,id), or we're comparing frameless functions
+ (same .base, different .func, no test available). Struggle
+ on until we've definitly gone to far. */
+ }
+ return NULL;
+}
+
+CORE_ADDR
+frame_pc_unwind (struct frame_info *this_frame)
+{
+ if (!this_frame->prev_pc.p)
+ {
+ CORE_ADDR pc;
+ if (gdbarch_unwind_pc_p (current_gdbarch))
+ {
+ /* The right way. The `pure' way. The one true way. This
+ method depends solely on the register-unwind code to
+ determine the value of registers in THIS frame, and hence
+ the value of this frame's PC (resume address). A typical
+ implementation is no more than:
+
+ frame_unwind_register (this_frame, ISA_PC_REGNUM, buf);
+ return extract_unsigned_integer (buf, size of ISA_PC_REGNUM);
+
+ Note: this method is very heavily dependent on a correct
+ register-unwind implementation, it pays to fix that
+ method first; this method is frame type agnostic, since
+ it only deals with register values, it works with any
+ frame. This is all in stark contrast to the old
+ FRAME_SAVED_PC which would try to directly handle all the
+ different ways that a PC could be unwound. */
+ pc = gdbarch_unwind_pc (current_gdbarch, this_frame);
+ }
+ else if (this_frame->level < 0)
+ {
+ /* FIXME: cagney/2003-03-06: Old code and and a sentinel
+ frame. Do like was always done. Fetch the PC's value
+ direct from the global registers array (via read_pc).
+ This assumes that this frame belongs to the current
+ global register cache. The assumption is dangerous. */
+ pc = read_pc ();
+ }
+ else if (DEPRECATED_FRAME_SAVED_PC_P ())
+ {
+ /* FIXME: cagney/2003-03-06: Old code, but not a sentinel
+ frame. Do like was always done. Note that this method,
+ unlike unwind_pc(), tries to handle all the different
+ frame cases directly. It fails. */
+ pc = DEPRECATED_FRAME_SAVED_PC (this_frame);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "No gdbarch_unwind_pc method");
+ this_frame->prev_pc.value = pc;
+ this_frame->prev_pc.p = 1;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_pc_unwind (this_frame=%d) -> 0x%s }\n",
+ this_frame->level,
+ paddr_nz (this_frame->prev_pc.value));
+ }
+ return this_frame->prev_pc.value;
+}
+
+CORE_ADDR
+frame_func_unwind (struct frame_info *fi)
+{
+ if (!fi->prev_func.p)
+ {
+ /* Make certain that this, and not the adjacent, function is
+ found. */
+ CORE_ADDR addr_in_block = frame_unwind_address_in_block (fi);
+ fi->prev_func.p = 1;
+ fi->prev_func.addr = get_pc_function_start (addr_in_block);
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_func_unwind (fi=%d) -> 0x%s }\n",
+ fi->level, paddr_nz (fi->prev_func.addr));
+ }
+ return fi->prev_func.addr;
+}
+
+CORE_ADDR
+get_frame_func (struct frame_info *fi)
+{
+ return frame_func_unwind (fi->next);
+}
+
+static int
+do_frame_unwind_register (void *src, int regnum, void *buf)
+{
+ frame_unwind_register (src, regnum, buf);
+ return 1;
+}
+
+void
+frame_pop (struct frame_info *this_frame)
+{
+ struct regcache *scratch_regcache;
+ struct cleanup *cleanups;
+
+ if (DEPRECATED_POP_FRAME_P ())
+ {
+ /* A legacy architecture that has implemented a custom pop
+ function. All new architectures should instead be using the
+ generic code below. */
+ DEPRECATED_POP_FRAME;
+ }
+ else
+ {
+ /* Make a copy of all the register values unwound from this
+ frame. Save them in a scratch buffer so that there isn't a
+ race betweening trying to extract the old values from the
+ current_regcache while, at the same time writing new values
+ into that same cache. */
+ struct regcache *scratch = regcache_xmalloc (current_gdbarch);
+ struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
+ regcache_save (scratch, do_frame_unwind_register, this_frame);
+ /* FIXME: cagney/2003-03-16: It should be possible to tell the
+ target's register cache that it is about to be hit with a
+ burst register transfer and that the sequence of register
+ writes should be batched. The pair target_prepare_to_store()
+ and target_store_registers() kind of suggest this
+ functionality. Unfortunately, they don't implement it. Their
+ lack of a formal definition can lead to targets writing back
+ bogus values (arguably a bug in the target code mind). */
+ /* Now copy those saved registers into the current regcache.
+ Here, regcache_cpy() calls regcache_restore(). */
+ regcache_cpy (current_regcache, scratch);
+ do_cleanups (cleanups);
+ }
+ /* We've made right mess of GDB's local state, just discard
+ everything. */
+ flush_cached_frames ();
+}
+
+void
+frame_register_unwind (struct frame_info *frame, int regnum,
+ int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump, void *bufferp)
+{
+ struct frame_unwind_cache *cache;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "\
+{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ",
+ frame->level, regnum,
+ frame_map_regnum_to_name (frame, regnum));
+ }
+
+ /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
+ that the value proper does not need to be fetched. */
+ gdb_assert (optimizedp != NULL);
+ gdb_assert (lvalp != NULL);
+ gdb_assert (addrp != NULL);
+ gdb_assert (realnump != NULL);
+ /* gdb_assert (bufferp != NULL); */
+
+ /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
+ is broken. There is always a frame. If there, for some reason,
+ isn't, there is some pretty busted code as it should have
+ detected the problem before calling here. */
+ gdb_assert (frame != NULL);
+
+ /* Find the unwinder. */
+ if (frame->unwind == NULL)
+ {
+ frame->unwind = frame_unwind_find_by_frame (frame->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type using
+ the method deprecated_set_frame_type(). */
+ frame->type = frame->unwind->type;
+ }
+
+ /* Ask this frame to unwind its register. See comment in
+ "frame-unwind.h" for why NEXT frame and this unwind cace are
+ passed in. */
+ frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "->");
+ fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp));
+ fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp));
+ fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp)));
+ fprintf_unfiltered (gdb_stdlog, " *bufferp=");
+ if (bufferp == NULL)
+ fprintf_unfiltered (gdb_stdlog, "<NULL>");
+ else
+ {
+ int i;
+ const unsigned char *buf = bufferp;
+ fprintf_unfiltered (gdb_stdlog, "[");
+ for (i = 0; i < register_size (current_gdbarch, regnum); i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ fprintf_unfiltered (gdb_stdlog, "]");
+ }
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+}
+
+void
+frame_register (struct frame_info *frame, int regnum,
+ int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump, void *bufferp)
+{
+ /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
+ that the value proper does not need to be fetched. */
+ gdb_assert (optimizedp != NULL);
+ gdb_assert (lvalp != NULL);
+ gdb_assert (addrp != NULL);
+ gdb_assert (realnump != NULL);
+ /* gdb_assert (bufferp != NULL); */
+
+ /* Ulgh! Old code that, for lval_register, sets ADDRP to the offset
+ of the register in the register cache. It should instead return
+ the REGNUM corresponding to that register. Translate the . */
+ if (DEPRECATED_GET_SAVED_REGISTER_P ())
+ {
+ DEPRECATED_GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame,
+ regnum, lvalp);
+ /* Compute the REALNUM if the caller wants it. */
+ if (*lvalp == lval_register)
+ {
+ int regnum;
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ if (*addrp == register_offset_hack (current_gdbarch, regnum))
+ {
+ *realnump = regnum;
+ return;
+ }
+ }
+ internal_error (__FILE__, __LINE__,
+ "Failed to compute the register number corresponding"
+ " to 0x%s", paddr_d (*addrp));
+ }
+ *realnump = -1;
+ return;
+ }
+
+ /* Obtain the register value by unwinding the register from the next
+ (more inner frame). */
+ gdb_assert (frame != NULL && frame->next != NULL);
+ frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+}
+
+void
+frame_unwind_register (struct frame_info *frame, int regnum, void *buf)
+{
+ int optimized;
+ CORE_ADDR addr;
+ int realnum;
+ enum lval_type lval;
+ frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
+ &realnum, buf);
+}
+
+void
+get_frame_register (struct frame_info *frame,
+ int regnum, void *buf)
+{
+ frame_unwind_register (frame->next, regnum, buf);
+}
+
+LONGEST
+frame_unwind_register_signed (struct frame_info *frame, int regnum)
+{
+ char buf[MAX_REGISTER_SIZE];
+ frame_unwind_register (frame, regnum, buf);
+ return extract_signed_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+}
+
+LONGEST
+get_frame_register_signed (struct frame_info *frame, int regnum)
+{
+ return frame_unwind_register_signed (frame->next, regnum);
+}
+
+ULONGEST
+frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
+{
+ char buf[MAX_REGISTER_SIZE];
+ frame_unwind_register (frame, regnum, buf);
+ return extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+}
+
+ULONGEST
+get_frame_register_unsigned (struct frame_info *frame, int regnum)
+{
+ return frame_unwind_register_unsigned (frame->next, regnum);
+}
+
+void
+frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
+ ULONGEST *val)
+{
+ char buf[MAX_REGISTER_SIZE];
+ frame_unwind_register (frame, regnum, buf);
+ (*val) = extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+}
+
+void
+put_frame_register (struct frame_info *frame, int regnum, const void *buf)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ int realnum;
+ int optim;
+ enum lval_type lval;
+ CORE_ADDR addr;
+ frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
+ if (optim)
+ error ("Attempt to assign to a value that was optimized out.");
+ switch (lval)
+ {
+ case lval_memory:
+ {
+ /* FIXME: write_memory doesn't yet take constant buffers.
+ Arrrg! */
+ char tmp[MAX_REGISTER_SIZE];
+ memcpy (tmp, buf, register_size (gdbarch, regnum));
+ write_memory (addr, tmp, register_size (gdbarch, regnum));
+ break;
+ }
+ case lval_register:
+ regcache_cooked_write (current_regcache, realnum, buf);
+ break;
+ default:
+ error ("Attempt to assign to an unmodifiable value.");
+ }
+}
+
+/* frame_register_read ()
+
+ Find and return the value of REGNUM for the specified stack frame.
+ The number of bytes copied is DEPRECATED_REGISTER_RAW_SIZE
+ (REGNUM).
+
+ Returns 0 if the register value could not be found. */
+
+int
+frame_register_read (struct frame_info *frame, int regnum, void *myaddr)
+{
+ int optimized;
+ enum lval_type lval;
+ CORE_ADDR addr;
+ int realnum;
+ frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr);
+
+ /* FIXME: cagney/2002-05-15: This test, is just bogus.
+
+ It indicates that the target failed to supply a value for a
+ register because it was "not available" at this time. Problem
+ is, the target still has the register and so get saved_register()
+ may be returning a value saved on the stack. */
+
+ if (register_cached (regnum) < 0)
+ return 0; /* register value not available */
+
+ return !optimized;
+}
+
+
+/* Map between a frame register number and its name. A frame register
+ space is a superset of the cooked register space --- it also
+ includes builtin registers. */
+
+int
+frame_map_name_to_regnum (struct frame_info *frame, const char *name, int len)
+{
+ return user_reg_map_name_to_regnum (get_frame_arch (frame), name, len);
+}
+
+const char *
+frame_map_regnum_to_name (struct frame_info *frame, int regnum)
+{
+ return user_reg_map_regnum_to_name (get_frame_arch (frame), regnum);
+}
+
+/* Create a sentinel frame. */
+
+static struct frame_info *
+create_sentinel_frame (struct regcache *regcache)
+{
+ struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ frame->type = NORMAL_FRAME;
+ frame->level = -1;
+ /* Explicitly initialize the sentinel frame's cache. Provide it
+ with the underlying regcache. In the future additional
+ information, such as the frame's thread will be added. */
+ frame->prologue_cache = sentinel_frame_cache (regcache);
+ /* For the moment there is only one sentinel frame implementation. */
+ frame->unwind = sentinel_frame_unwind;
+ /* Link this frame back to itself. The frame is self referential
+ (the unwound PC is the same as the pc), so make it so. */
+ frame->next = frame;
+ /* Make the sentinel frame's ID valid, but invalid. That way all
+ comparisons with it should fail. */
+ frame->this_id.p = 1;
+ frame->this_id.value = null_frame_id;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ create_sentinel_frame (...) -> ");
+ fprint_frame (gdb_stdlog, frame);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+ return frame;
+}
+
+/* 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. */
+
+static struct obstack frame_cache_obstack;
+
+void *
+frame_obstack_zalloc (unsigned long size)
+{
+ void *data = obstack_alloc (&frame_cache_obstack, size);
+ memset (data, 0, size);
+ return data;
+}
+
+CORE_ADDR *
+frame_saved_regs_zalloc (struct frame_info *fi)
+{
+ fi->saved_regs = (CORE_ADDR *)
+ frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
+ return fi->saved_regs;
+}
+
+CORE_ADDR *
+deprecated_get_frame_saved_regs (struct frame_info *fi)
+{
+ return fi->saved_regs;
+}
+
+/* Return the innermost (currently executing) stack frame. This is
+ split into two functions. The function unwind_to_current_frame()
+ is wrapped in catch exceptions so that, even when the unwind of the
+ sentinel frame fails, the function still returns a stack frame. */
+
+static int
+unwind_to_current_frame (struct ui_out *ui_out, void *args)
+{
+ struct frame_info *frame = get_prev_frame (args);
+ /* A sentinel frame can fail to unwind, eg, because it's PC value
+ lands in somewhere like start. */
+ if (frame == NULL)
+ return 1;
+ current_frame = frame;
+ return 0;
+}
+
+struct frame_info *
+get_current_frame (void)
+{
+ /* First check, and report, the lack of registers. Having GDB
+ report "No stack!" or "No memory" when the target doesn't even
+ have registers is very confusing. Besides, "printcmd.exp"
+ explicitly checks that ``print $pc'' with no registers prints "No
+ registers". */
+ if (!target_has_registers)
+ error ("No registers.");
+ if (!target_has_stack)
+ error ("No stack.");
+ if (!target_has_memory)
+ error ("No memory.");
+ if (current_frame == NULL)
+ {
+ struct frame_info *sentinel_frame =
+ create_sentinel_frame (current_regcache);
+ if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
+ NULL, RETURN_MASK_ERROR) != 0)
+ {
+ /* Oops! Fake a current frame? Is this useful? It has a PC
+ of zero, for instance. */
+ current_frame = sentinel_frame;
+ }
+ }
+ return current_frame;
+}
+
+/* The "selected" stack frame is used by default for local and arg
+ access. May be zero, for no selected frame. */
+
+struct frame_info *deprecated_selected_frame;
+
+/* Return the selected frame. Always non-null (unless there isn't an
+ inferior sufficient for creating a frame) in which case an error is
+ thrown. */
+
+struct frame_info *
+get_selected_frame (void)
+{
+ if (deprecated_selected_frame == NULL)
+ /* Hey! Don't trust this. It should really be re-finding the
+ last selected frame of the currently selected thread. This,
+ though, is better than nothing. */
+ select_frame (get_current_frame ());
+ /* There is always a frame. */
+ gdb_assert (deprecated_selected_frame != NULL);
+ return deprecated_selected_frame;
+}
+
+/* This is a variant of get_selected_frame which can be called when
+ the inferior does not have a frame; in that case it will return
+ NULL instead of calling error (). */
+
+struct frame_info *
+deprecated_safe_get_selected_frame (void)
+{
+ if (!target_has_registers || !target_has_stack || !target_has_memory)
+ return NULL;
+ return get_selected_frame ();
+}
+
+/* Select frame FI (or NULL - to invalidate the current frame). */
+
+void
+select_frame (struct frame_info *fi)
+{
+ struct symtab *s;
+
+ deprecated_selected_frame = fi;
+ /* NOTE: cagney/2002-05-04: FI can be NULL. This occures when the
+ frame is being invalidated. */
+ if (selected_frame_level_changed_hook)
+ selected_frame_level_changed_hook (frame_relative_level (fi));
+
+ /* FIXME: kseitz/2002-08-28: It would be nice to call
+ selected_frame_level_changed_event right here, but due to limitations
+ in the current interfaces, we would end up flooding UIs with events
+ because select_frame is used extensively internally.
+
+ Once we have frame-parameterized frame (and frame-related) commands,
+ the event notification can be moved here, since this function will only
+ be called when the users selected frame is being changed. */
+
+ /* 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)
+ {
+ /* We retrieve the frame's symtab by using the frame PC. However
+ we cannot use the frame pc as is, because it usually points to
+ the instruction following the "call", which is sometimes the
+ first instruction of another function. So we rely on
+ get_frame_address_in_block() which provides us with a PC which
+ is guaranteed to be inside the frame's code block. */
+ s = find_pc_symtab (get_frame_address_in_block (fi));
+ if (s
+ && s->language != current_language->la_language
+ && s->language != language_unknown
+ && language_mode == language_mode_auto)
+ {
+ set_language (s->language);
+ }
+ }
+}
+
+/* Return the register saved in the simplistic ``saved_regs'' cache.
+ If the value isn't here AND a value is needed, try the next inner
+ most frame. */
+
+static void
+legacy_saved_regs_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ /* HACK: New code is passed the next frame and this cache.
+ Unfortunately, old code expects this frame. Since this is a
+ backward compatibility hack, cheat by walking one level along the
+ prologue chain to the frame the old code expects.
+
+ Do not try this at home. Professional driver, closed course. */
+ struct frame_info *frame = next_frame->prev;
+ gdb_assert (frame != NULL);
+
+ if (deprecated_get_frame_saved_regs (frame) == NULL)
+ {
+ /* If nothing's initialized the saved regs, do it now. */
+ gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
+ DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
+ gdb_assert (deprecated_get_frame_saved_regs (frame) != NULL);
+ }
+
+ if (deprecated_get_frame_saved_regs (frame) != NULL
+ && deprecated_get_frame_saved_regs (frame)[regnum] != 0)
+ {
+ if (regnum == SP_REGNUM)
+ {
+ /* SP register treated specially. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (bufferp != NULL)
+ /* NOTE: cagney/2003-05-09: In-lined store_address with
+ it's body - store_unsigned_integer. */
+ store_unsigned_integer (bufferp, DEPRECATED_REGISTER_RAW_SIZE (regnum),
+ deprecated_get_frame_saved_regs (frame)[regnum]);
+ }
+ else
+ {
+ /* Any other register is saved in memory, fetch it but cache
+ a local copy of its value. */
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = deprecated_get_frame_saved_regs (frame)[regnum];
+ *realnump = -1;
+ if (bufferp != NULL)
+ {
+#if 1
+ /* Save each register value, as it is read in, in a
+ frame based cache. */
+ void **regs = (*this_prologue_cache);
+ if (regs == NULL)
+ {
+ int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
+ * sizeof (void *));
+ regs = frame_obstack_zalloc (sizeof_cache);
+ (*this_prologue_cache) = regs;
+ }
+ if (regs[regnum] == NULL)
+ {
+ regs[regnum]
+ = frame_obstack_zalloc (DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ read_memory (deprecated_get_frame_saved_regs (frame)[regnum], regs[regnum],
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ }
+ memcpy (bufferp, regs[regnum], DEPRECATED_REGISTER_RAW_SIZE (regnum));
+#else
+ /* Read the value in from memory. */
+ read_memory (deprecated_get_frame_saved_regs (frame)[regnum], bufferp,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
+#endif
+ }
+ }
+ return;
+ }
+
+ /* No luck. Assume this and the next frame have the same register
+ value. Pass the unwind request down the frame chain to the next
+ frame. Hopefully that frame will find the register's location. */
+ frame_register_unwind (next_frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+}
+
+static void
+legacy_saved_regs_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *id)
+{
+ /* A developer is trying to bring up a new architecture, help them
+ by providing a default unwinder that refuses to unwind anything
+ (the ID is always NULL). In the case of legacy code,
+ legacy_get_prev_frame() will have previously set ->this_id.p, so
+ this code won't be called. */
+ (*id) = null_frame_id;
+}
+
+const struct frame_unwind legacy_saved_regs_unwinder = {
+ /* Not really. It gets overridden by legacy_get_prev_frame. */
+ UNKNOWN_FRAME,
+ legacy_saved_regs_this_id,
+ legacy_saved_regs_prev_register
+};
+const struct frame_unwind *legacy_saved_regs_unwind = &legacy_saved_regs_unwinder;
+
+
+/* Function: deprecated_generic_get_saved_register
+ 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). Note that this is never set to anything other than zero
+ in this implementation.
+
+ 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). We will use not_lval for values
+ fetched from generic dummy frames.
+
+ Set *ADDRP to the address, either in memory or as a
+ DEPRECATED_REGISTER_BYTE offset into the registers array. If the
+ value is stored in a dummy frame, set *ADDRP to zero.
+
+ The argument RAW_BUFFER must point to aligned memory. */
+
+void
+deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
+ CORE_ADDR *addrp,
+ struct frame_info *frame, int regnum,
+ enum lval_type *lval)
+{
+ if (!target_has_registers)
+ error ("No registers.");
+
+ /* Normal systems don't optimize out things with register numbers. */
+ if (optimized != NULL)
+ *optimized = 0;
+
+ if (addrp) /* default assumption: not found in memory */
+ *addrp = 0;
+
+ /* Note: since the current frame's registers could only have been
+ saved by frames INTERIOR TO the current frame, we skip examining
+ the current frame itself: otherwise, we would be getting the
+ previous frame's registers which were saved by the current frame. */
+
+ if (frame != NULL)
+ {
+ for (frame = get_next_frame (frame);
+ frame_relative_level (frame) >= 0;
+ frame = get_next_frame (frame))
+ {
+ if (get_frame_type (frame) == DUMMY_FRAME)
+ {
+ if (lval) /* found it in a CALL_DUMMY frame */
+ *lval = not_lval;
+ if (raw_buffer)
+ /* FIXME: cagney/2002-06-26: This should be via the
+ gdbarch_register_read() method so that it, on the
+ fly, constructs either a raw or pseudo register
+ from the raw register cache. */
+ regcache_raw_read
+ (deprecated_find_dummy_frame_regcache (get_frame_pc (frame),
+ get_frame_base (frame)),
+ regnum, raw_buffer);
+ return;
+ }
+
+ DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
+ if (deprecated_get_frame_saved_regs (frame) != NULL
+ && deprecated_get_frame_saved_regs (frame)[regnum] != 0)
+ {
+ if (lval) /* found it saved on the stack */
+ *lval = lval_memory;
+ if (regnum == SP_REGNUM)
+ {
+ if (raw_buffer) /* SP register treated specially */
+ /* NOTE: cagney/2003-05-09: In-line store_address
+ with it's body - store_unsigned_integer. */
+ store_unsigned_integer (raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum),
+ deprecated_get_frame_saved_regs (frame)[regnum]);
+ }
+ else
+ {
+ if (addrp) /* any other register */
+ *addrp = deprecated_get_frame_saved_regs (frame)[regnum];
+ if (raw_buffer)
+ read_memory (deprecated_get_frame_saved_regs (frame)[regnum], raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ }
+ return;
+ }
+ }
+ }
+
+ /* If we get thru the loop to this point, it means the register was
+ not saved in any frame. Return the actual live-register value. */
+
+ if (lval) /* found it in a live register */
+ *lval = lval_register;
+ if (addrp)
+ *addrp = DEPRECATED_REGISTER_BYTE (regnum);
+ if (raw_buffer)
+ deprecated_read_register_gen (regnum, raw_buffer);
+}
+
+/* Determine the frame's type based on its PC. */
+
+static enum frame_type
+frame_type_from_pc (CORE_ADDR pc)
+{
+ /* FIXME: cagney/2002-11-24: Can't yet directly call
+ pc_in_dummy_frame() as some architectures don't set
+ PC_IN_CALL_DUMMY() to generic_pc_in_call_dummy() (remember the
+ latter is implemented by simply calling pc_in_dummy_frame). */
+ if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+ && DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+ return DUMMY_FRAME;
+ else
+ {
+ char *name;
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (PC_IN_SIGTRAMP (pc, name))
+ return SIGTRAMP_FRAME;
+ else
+ return NORMAL_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 (CORE_ADDR addr, CORE_ADDR pc)
+{
+ struct frame_info *fi;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "{ create_new_frame (addr=0x%s, pc=0x%s) ",
+ paddr_nz (addr), paddr_nz (pc));
+ }
+
+ fi = frame_obstack_zalloc (sizeof (struct frame_info));
+
+ fi->next = create_sentinel_frame (current_regcache);
+
+ /* Select/initialize both the unwind function and the frame's type
+ based on the PC. */
+ fi->unwind = frame_unwind_find_by_frame (fi->next);
+ if (fi->unwind->type != UNKNOWN_FRAME)
+ fi->type = fi->unwind->type;
+ else
+ fi->type = frame_type_from_pc (pc);
+
+ fi->this_id.p = 1;
+ deprecated_update_frame_base_hack (fi, addr);
+ deprecated_update_frame_pc_hack (fi, pc);
+
+ if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+ DEPRECATED_INIT_EXTRA_FRAME_INFO (0, fi);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, fi);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+
+ return fi;
+}
+
+/* Return the frame that THIS_FRAME calls (NULL if THIS_FRAME is the
+ innermost frame). Be careful to not fall off the bottom of the
+ frame chain and onto the sentinel frame. */
+
+struct frame_info *
+get_next_frame (struct frame_info *this_frame)
+{
+ if (this_frame->level > 0)
+ return this_frame->next;
+ else
+ return NULL;
+}
+
+/* Flush the entire frame cache. */
+
+void
+flush_cached_frames (void)
+{
+ /* 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);
+ annotate_frames_invalid ();
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ flush_cached_frames () }\n");
+}
+
+/* Flush the frame cache, and start a new one if necessary. */
+
+void
+reinit_frame_cache (void)
+{
+ flush_cached_frames ();
+
+ /* FIXME: The inferior_ptid test is wrong if there is a corefile. */
+ if (PIDGET (inferior_ptid) != 0)
+ {
+ select_frame (get_current_frame ());
+ }
+}
+
+/* Create the previous frame using the deprecated methods
+ INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST. */
+
+static struct frame_info *
+legacy_get_prev_frame (struct frame_info *this_frame)
+{
+ CORE_ADDR address = 0;
+ struct frame_info *prev;
+ int fromleaf;
+
+ /* Don't frame_debug print legacy_get_prev_frame() here, just
+ confuses the output. */
+
+ /* Allocate the new frame.
+
+ There is no reason to worry about memory leaks, should the
+ remainder of the function fail. The allocated memory will be
+ quickly reclaimed when the frame cache is flushed, and the `we've
+ been here before' check, in get_prev_frame will stop repeated
+ memory allocation calls. */
+ prev = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ prev->level = this_frame->level + 1;
+
+ /* Do not completely wire it in to the frame chain. Some (bad) code
+ in INIT_FRAME_EXTRA_INFO tries to look along frame->prev to pull
+ some fancy tricks (of course such code is, by definition,
+ recursive).
+
+ On the other hand, methods, such as get_frame_pc() and
+ get_frame_base() rely on being able to walk along the frame
+ chain. Make certain that at least they work by providing that
+ link. Of course things manipulating prev can't go back. */
+ prev->next = this_frame;
+
+ /* NOTE: cagney/2002-11-18: Should have been correctly setting the
+ frame's type here, before anything else, and not last, at the
+ bottom of this function. The various
+ DEPRECATED_INIT_EXTRA_FRAME_INFO, DEPRECATED_INIT_FRAME_PC,
+ DEPRECATED_INIT_FRAME_PC_FIRST and
+ DEPRECATED_FRAME_INIT_SAVED_REGS methods are full of work-arounds
+ that handle the frame not being correctly set from the start.
+ Unfortunately those same work-arounds rely on the type defaulting
+ to NORMAL_FRAME. Ulgh! The new frame code does not have this
+ problem. */
+ prev->type = UNKNOWN_FRAME;
+
+ /* A legacy frame's ID is always computed here. Mark it as valid. */
+ prev->this_id.p = 1;
+
+ /* Handle sentinel frame unwind as a special case. */
+ if (this_frame->level < 0)
+ {
+ /* Try to unwind the PC. If that doesn't work, assume we've reached
+ the oldest frame and simply return. Is there a better sentinal
+ value? The unwound PC value is then used to initialize the new
+ previous frame's type.
+
+ Note that the pc-unwind is intentionally performed before the
+ frame chain. This is ok since, for old targets, both
+ frame_pc_unwind (nee, DEPRECATED_FRAME_SAVED_PC) and
+ DEPRECATED_FRAME_CHAIN()) assume THIS_FRAME's data structures
+ have already been initialized (using
+ DEPRECATED_INIT_EXTRA_FRAME_INFO) and hence the call order
+ doesn't matter.
+
+ By unwinding the PC first, it becomes possible to, in the case of
+ a dummy frame, avoid also unwinding the frame ID. This is
+ because (well ignoring the PPC) a dummy frame can be located
+ using THIS_FRAME's frame ID. */
+
+ deprecated_update_frame_pc_hack (prev, frame_pc_unwind (this_frame));
+ if (get_frame_pc (prev) == 0)
+ {
+ /* The allocated PREV_FRAME will be reclaimed when the frame
+ obstack is next purged. */
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // unwound legacy PC zero }\n");
+ }
+ return NULL;
+ }
+
+ /* Set the unwind functions based on that identified PC. Ditto
+ for the "type" but strongly prefer the unwinder's frame type. */
+ prev->unwind = frame_unwind_find_by_frame (prev->next);
+ if (prev->unwind->type == UNKNOWN_FRAME)
+ prev->type = frame_type_from_pc (get_frame_pc (prev));
+ else
+ prev->type = prev->unwind->type;
+
+ /* Find the prev's frame's ID. */
+ if (prev->type == DUMMY_FRAME
+ && gdbarch_unwind_dummy_id_p (current_gdbarch))
+ {
+ /* When unwinding a normal frame, the stack structure is
+ determined by analyzing the frame's function's code (be
+ it using brute force prologue analysis, or the dwarf2
+ CFI). In the case of a dummy frame, that simply isn't
+ possible. The The PC is either the program entry point,
+ or some random address on the stack. Trying to use that
+ PC to apply standard frame ID unwind techniques is just
+ asking for trouble. */
+ /* Use an architecture specific method to extract the prev's
+ dummy ID from the next frame. Note that this method uses
+ frame_register_unwind to obtain the register values
+ needed to determine the dummy frame's ID. */
+ prev->this_id.value = gdbarch_unwind_dummy_id (current_gdbarch,
+ this_frame);
+ }
+ else
+ {
+ /* We're unwinding a sentinel frame, the PC of which is
+ pointing at a stack dummy. Fake up the dummy frame's ID
+ using the same sequence as is found a traditional
+ unwinder. Once all architectures supply the
+ unwind_dummy_id method, this code can go away. */
+ prev->this_id.value = frame_id_build (deprecated_read_fp (),
+ read_pc ());
+ }
+
+ /* Check that the unwound ID is valid. */
+ if (!frame_id_p (prev->this_id.value))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // unwound legacy ID invalid }\n");
+ }
+ return NULL;
+ }
+
+ /* Check that the new frame isn't inner to (younger, below,
+ next) the old frame. If that happens the frame unwind is
+ going backwards. */
+ /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since
+ that doesn't have a valid frame ID. Should instead set the
+ sentinel frame's frame ID to a `sentinel'. Leave it until
+ after the switch to storing the frame ID, instead of the
+ frame base, in the frame object. */
+
+ /* Link it in. */
+ this_frame->prev = prev;
+
+ /* FIXME: cagney/2002-01-19: This call will go away. Instead of
+ initializing extra info, all frames will use the frame_cache
+ (passed to the unwind functions) to store additional frame
+ info. Unfortunately legacy targets can't use
+ legacy_get_prev_frame() to unwind the sentinel frame and,
+ consequently, are forced to take this code path and rely on
+ the below call to DEPRECATED_INIT_EXTRA_FRAME_INFO to
+ initialize the inner-most frame. */
+ if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+ {
+ DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev);
+ }
+
+ if (prev->type == NORMAL_FRAME)
+ prev->this_id.value.code_addr
+ = get_pc_function_start (prev->this_id.value.code_addr);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev);
+ fprintf_unfiltered (gdb_stdlog, " } // legacy innermost frame\n");
+ }
+ return prev;
+ }
+
+ /* This code only works on normal frames. A sentinel frame, where
+ the level is -1, should never reach this code. */
+ gdb_assert (this_frame->level >= 0);
+
+ /* 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. */
+
+ /* Still don't want to worry about this except on the innermost
+ frame. This macro will set FROMLEAF if THIS_FRAME is a frameless
+ function invocation. */
+ if (this_frame->level == 0)
+ /* FIXME: 2002-11-09: Frameless functions can occure anywhere in
+ the frame chain, not just the inner most frame! The generic,
+ per-architecture, frame code should handle this and the below
+ should simply be removed. */
+ fromleaf = (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ()
+ && DEPRECATED_FRAMELESS_FUNCTION_INVOCATION (this_frame));
+ else
+ fromleaf = 0;
+
+ if (fromleaf)
+ /* A frameless inner-most frame. The `FP' (which isn't an
+ architecture frame-pointer register!) of the caller is the same
+ as the callee. */
+ /* FIXME: 2002-11-09: There isn't any reason to special case this
+ edge condition. Instead the per-architecture code should hande
+ it locally. */
+ /* FIXME: cagney/2003-06-16: This returns the inner most stack
+ address for the previous frame, that, however, is wrong. It
+ should be the inner most stack address for the previous to
+ previous frame. This is because it is the previous to previous
+ frame's innermost stack address that is constant through out
+ the lifetime of the previous frame (trust me :-). */
+ address = get_frame_base (this_frame);
+ else
+ {
+ /* 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. */
+ if (DEPRECATED_FRAME_CHAIN_P ())
+ address = DEPRECATED_FRAME_CHAIN (this_frame);
+ else
+ {
+ /* Someone is part way through coverting an old architecture
+ to the new frame code. Implement FRAME_CHAIN the way the
+ new frame will. */
+ /* Find PREV frame's unwinder. */
+ prev->unwind = frame_unwind_find_by_frame (this_frame->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type
+ using the method deprecated_set_frame_type(). */
+ prev->type = prev->unwind->type;
+ /* Find PREV frame's ID. */
+ prev->unwind->this_id (this_frame,
+ &prev->prologue_cache,
+ &prev->this_id.value);
+ prev->this_id.p = 1;
+ address = prev->this_id.value.stack_addr;
+ }
+
+ if (!legacy_frame_chain_valid (address, this_frame))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // legacy frame chain invalid }\n");
+ }
+ return NULL;
+ }
+ }
+ if (address == 0)
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // legacy frame chain NULL }\n");
+ }
+ return NULL;
+ }
+
+ /* Link in the already allocated prev frame. */
+ this_frame->prev = prev;
+ deprecated_update_frame_base_hack (prev, address);
+
+ /* This change should not be needed, FIXME! We should determine
+ whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen
+ after DEPRECATED_INIT_EXTRA_FRAME_INFO and come up with a simple
+ way to express what goes on here.
+
+ DEPRECATED_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). DEPRECATED_INIT_FRAME_PC is only called from here,
+ always after DEPRECATED_INIT_EXTRA_FRAME_INFO.
+
+ The catch is the MIPS, where DEPRECATED_INIT_EXTRA_FRAME_INFO
+ requires the PC value (which hasn't been set yet). Some other
+ machines appear to require DEPRECATED_INIT_EXTRA_FRAME_INFO
+ before they can do DEPRECATED_INIT_FRAME_PC. Phoo.
+
+ We shouldn't need DEPRECATED_INIT_FRAME_PC_FIRST to add more
+ complication to an already overcomplicated part of GDB.
+ gnu@cygnus.com, 15Sep92.
+
+ Assuming that some machines need DEPRECATED_INIT_FRAME_PC after
+ DEPRECATED_INIT_EXTRA_FRAME_INFO, one possible scheme:
+
+ SETUP_INNERMOST_FRAME(): Default version is just create_new_frame
+ (deprecated_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
+ DEPRECATED_INIT_EXTRA_FRAME_INFO and DEPRECATED_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 DEPRECATED_FRAME_CHAIN_VALID
+ called BEFORE DEPRECATED_INIT_EXTRA_FRAME_INFO (there is no good
+ way to get information deduced in DEPRECATED_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 DEPRECATED_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. */
+
+ /* NOTE: cagney/2002-11-09: Just ignore the above! There is no
+ reason for things to be this complicated.
+
+ The trick is to assume that there is always a frame. Instead of
+ special casing the inner-most frame, create fake frame
+ (containing the hardware registers) that is inner to the
+ user-visible inner-most frame (...) and then unwind from that.
+ That way architecture code can use use the standard
+ frame_XX_unwind() functions and not differentiate between the
+ inner most and any other case.
+
+ Since there is always a frame to unwind from, there is always
+ somewhere (THIS_FRAME) to store all the info needed to construct
+ a new (previous) frame without having to first create it. This
+ means that the convolution below - needing to carefully order a
+ frame's initialization - isn't needed.
+
+ The irony here though, is that DEPRECATED_FRAME_CHAIN(), at least
+ for a more up-to-date architecture, always calls
+ FRAME_SAVED_PC(), and FRAME_SAVED_PC() computes the PC but
+ without first needing the frame! Instead of the convolution
+ below, we could have simply called FRAME_SAVED_PC() and been done
+ with it! Note that FRAME_SAVED_PC() is being superseed by
+ frame_pc_unwind() and that function does have somewhere to cache
+ that PC value. */
+
+ if (DEPRECATED_INIT_FRAME_PC_FIRST_P ())
+ deprecated_update_frame_pc_hack (prev,
+ DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf,
+ prev));
+
+ if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+ DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, prev);
+
+ /* 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. */
+ if (DEPRECATED_INIT_FRAME_PC_P ())
+ deprecated_update_frame_pc_hack (prev,
+ DEPRECATED_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 DEPRECATED_FRAME_CHAIN or thereabouts, but it seems
+ like there is no reason this can't be an architecture-independent
+ check. */
+ if (get_frame_base (prev) == get_frame_base (this_frame)
+ && get_frame_pc (prev) == get_frame_pc (this_frame))
+ {
+ this_frame->prev = NULL;
+ obstack_free (&frame_cache_obstack, prev);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // legacy this.id == prev.id }\n");
+ }
+ return NULL;
+ }
+
+ /* Initialize the code used to unwind the frame PREV based on the PC
+ (and probably other architectural information). The PC lets you
+ check things like the debug info at that point (dwarf2cfi?) and
+ use that to decide how the frame should be unwound.
+
+ If there isn't a FRAME_CHAIN, the code above will have already
+ done this. */
+ if (prev->unwind == NULL)
+ prev->unwind = frame_unwind_find_by_frame (prev->next);
+
+ /* If the unwinder provides a frame type, use it. Otherwize
+ continue on to that heuristic mess. */
+ if (prev->unwind->type != UNKNOWN_FRAME)
+ {
+ prev->type = prev->unwind->type;
+ if (prev->type == NORMAL_FRAME)
+ /* FIXME: cagney/2003-06-16: would get_frame_pc() be better? */
+ prev->this_id.value.code_addr
+ = get_pc_function_start (prev->this_id.value.code_addr);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev);
+ fprintf_unfiltered (gdb_stdlog, " } // legacy with unwound type\n");
+ }
+ return prev;
+ }
+
+ /* NOTE: cagney/2002-11-18: The code segments, found in
+ create_new_frame and get_prev_frame(), that initializes the
+ frames type is subtly different. The latter only updates ->type
+ when it encounters a SIGTRAMP_FRAME or DUMMY_FRAME. This stops
+ get_prev_frame() overriding the frame's type when the INIT code
+ has previously set it. This is really somewhat bogus. The
+ initialization, as seen in create_new_frame(), should occur
+ before the INIT function has been called. */
+ if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+ && (DEPRECATED_PC_IN_CALL_DUMMY_P ()
+ ? DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (prev), 0, 0)
+ : pc_in_dummy_frame (get_frame_pc (prev))))
+ prev->type = DUMMY_FRAME;
+ else
+ {
+ /* FIXME: cagney/2002-11-10: This should be moved to before the
+ INIT code above so that the INIT code knows what the frame's
+ type is (in fact, for a [generic] dummy-frame, the type can
+ be set and then the entire initialization can be skipped.
+ Unforunatly, its the INIT code that sets the PC (Hmm, catch
+ 22). */
+ char *name;
+ find_pc_partial_function (get_frame_pc (prev), &name, NULL, NULL);
+ if (PC_IN_SIGTRAMP (get_frame_pc (prev), name))
+ prev->type = SIGTRAMP_FRAME;
+ /* FIXME: cagney/2002-11-11: Leave prev->type alone. Some
+ architectures are forcing the frame's type in INIT so we
+ don't want to override it here. Remember, NORMAL_FRAME == 0,
+ so it all works (just :-/). Once this initialization is
+ moved to the start of this function, all this nastness will
+ go away. */
+ }
+
+ if (prev->type == NORMAL_FRAME)
+ prev->this_id.value.code_addr
+ = get_pc_function_start (prev->this_id.value.code_addr);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev);
+ fprintf_unfiltered (gdb_stdlog, " } // legacy with confused type\n");
+ }
+
+ return prev;
+}
+
+/* Return a structure containing various interesting information
+ about the frame that called THIS_FRAME. Returns NULL
+ if there is no such frame.
+
+ This function tests some target-independent conditions that should
+ terminate the frame chain, such as unwinding past main(). It
+ should not contain any target-dependent tests, such as checking
+ whether the program-counter is zero. */
+
+struct frame_info *
+get_prev_frame (struct frame_info *this_frame)
+{
+ struct frame_info *prev_frame;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame=");
+ if (this_frame != NULL)
+ fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
+ else
+ fprintf_unfiltered (gdb_stdlog, "<NULL>");
+ fprintf_unfiltered (gdb_stdlog, ") ");
+ }
+
+ /* Return the inner-most frame, when the caller passes in NULL. */
+ /* NOTE: cagney/2002-11-09: Not sure how this would happen. The
+ caller should have previously obtained a valid frame using
+ get_selected_frame() and then called this code - only possibility
+ I can think of is code behaving badly.
+
+ NOTE: cagney/2003-01-10: Talk about code behaving badly. Check
+ block_innermost_frame(). It does the sequence: frame = NULL;
+ while (1) { frame = get_prev_frame (frame); .... }. Ulgh! Why
+ it couldn't be written better, I don't know.
+
+ NOTE: cagney/2003-01-11: I suspect what is happening is
+ block_innermost_frame() is, when the target has no state
+ (registers, memory, ...), still calling this function. The
+ assumption being that this function will return NULL indicating
+ that a frame isn't possible, rather than checking that the target
+ has state and then calling get_current_frame() and
+ get_prev_frame(). This is a guess mind. */
+ if (this_frame == NULL)
+ {
+ /* NOTE: cagney/2002-11-09: There was a code segment here that
+ would error out when CURRENT_FRAME was NULL. The comment
+ that went with it made the claim ...
+
+ ``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.''
+
+ Per the above, this code shouldn't even be called with a NULL
+ THIS_FRAME. */
+ return current_frame;
+ }
+
+ /* There is always a frame. If this assertion fails, suspect that
+ something should be calling get_selected_frame() or
+ get_current_frame(). */
+ gdb_assert (this_frame != NULL);
+
+ /* Make sure we pass an address within THIS_FRAME's code block to
+ inside_main_func. Otherwise, we might stop unwinding at a
+ function which has a call instruction as its last instruction if
+ that function immediately precedes main(). */
+ if (this_frame->level >= 0
+ && !backtrace_past_main
+ && inside_main_func (get_frame_address_in_block (this_frame)))
+ /* Don't unwind past main(), bug always unwind the sentinel frame.
+ Note, this is done _before_ the frame has been marked as
+ previously unwound. That way if the user later decides to
+ allow unwinds past main(), that just happens. */
+ {
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "-> NULL // inside main func }\n");
+ return NULL;
+ }
+
+ if (this_frame->level > backtrace_limit)
+ {
+ error ("Backtrace limit of %d exceeded", backtrace_limit);
+ }
+
+ /* If we're already inside the entry function for the main objfile,
+ then it isn't valid. Don't apply this test to a dummy frame -
+ dummy frame PC's typically land in the entry func. Don't apply
+ this test to the sentinel frame. Sentinel frames should always
+ be allowed to unwind. */
+ /* NOTE: cagney/2003-02-25: Don't enable until someone has found
+ hard evidence that this is needed. */
+ /* NOTE: cagney/2003-07-07: Fixed a bug in inside_main_func - wasn't
+ checking for "main" in the minimal symbols. With that fixed
+ asm-source tests now stop in "main" instead of halting the
+ backtrace in wierd and wonderful ways somewhere inside the entry
+ file. Suspect that deprecated_inside_entry_file and
+ inside_entry_func tests were added to work around that (now
+ fixed) case. */
+ /* NOTE: cagney/2003-07-15: danielj (if I'm reading it right)
+ suggested having the inside_entry_func test use the
+ inside_main_func msymbol trick (along with entry_point_address I
+ guess) to determine the address range of the start function.
+ That should provide a far better stopper than the current
+ heuristics. */
+ /* NOTE: cagney/2003-07-15: Need to add a "set backtrace
+ beyond-entry-func" command so that this can be selectively
+ disabled. */
+ if (0
+#if 0
+ && backtrace_beyond_entry_func
+#endif
+ && this_frame->type != DUMMY_FRAME && this_frame->level >= 0
+ && inside_entry_func (this_frame))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, "// inside entry func }\n");
+ }
+ return NULL;
+ }
+
+ /* Only try to do the unwind once. */
+ if (this_frame->prev_p)
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, this_frame->prev);
+ fprintf_unfiltered (gdb_stdlog, " // cached \n");
+ }
+ return this_frame->prev;
+ }
+ this_frame->prev_p = 1;
+
+ /* If we're inside the entry file, it isn't valid. Don't apply this
+ test to a dummy frame - dummy frame PC's typically land in the
+ entry file. Don't apply this test to the sentinel frame.
+ Sentinel frames should always be allowed to unwind. */
+ /* NOTE: drow/2002-12-25: should there be a way to disable this
+ check? It assumes a single small entry file, and the way some
+ debug readers (e.g. dbxread) figure out which object is the
+ entry file is somewhat hokey. */
+ /* NOTE: cagney/2003-01-10: If there is a way of disabling this test
+ then it should probably be moved to before the ->prev_p test,
+ above. */
+ /* NOTE: vinschen/2003-04-01: Disabled. It turns out that the call
+ to deprecated_inside_entry_file destroys a meaningful backtrace
+ under some conditions. E. g. the backtrace tests in the
+ asm-source testcase are broken for some targets. In this test
+ the functions are all implemented as part of one file and the
+ testcase is not necessarily linked with a start file (depending
+ on the target). What happens is, that the first frame is printed
+ normaly and following frames are treated as being inside the
+ enttry file then. This way, only the #0 frame is printed in the
+ backtrace output. */
+ if (0
+ && this_frame->type != DUMMY_FRAME && this_frame->level >= 0
+ && deprecated_inside_entry_file (get_frame_pc (this_frame)))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // inside entry file }\n");
+ }
+ return NULL;
+ }
+
+ /* If any of the old frame initialization methods are around, use
+ the legacy get_prev_frame method. */
+ if (legacy_frame_p (current_gdbarch))
+ {
+ prev_frame = legacy_get_prev_frame (this_frame);
+ return prev_frame;
+ }
+
+ /* Check that this frame's ID was valid. If it wasn't, don't try to
+ unwind to the prev frame. Be careful to not apply this test to
+ the sentinel frame. */
+ if (this_frame->level >= 0 && !frame_id_p (get_frame_id (this_frame)))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
+ }
+ return NULL;
+ }
+
+ /* Check that this frame's ID isn't inner to (younger, below, next)
+ the next frame. This happens when a frame unwind goes backwards.
+ Since the sentinel frame doesn't really exist, don't compare the
+ inner-most against that sentinel. */
+ if (this_frame->level > 0
+ && frame_id_inner (get_frame_id (this_frame),
+ get_frame_id (this_frame->next)))
+ error ("Previous frame inner to this frame (corrupt stack?)");
+
+ /* Check that this and the next frame are not identical. If they
+ are, there is most likely a stack cycle. As with the inner-than
+ test above, avoid comparing the inner-most and sentinel frames. */
+ if (this_frame->level > 0
+ && frame_id_eq (get_frame_id (this_frame),
+ get_frame_id (this_frame->next)))
+ error ("Previous frame identical to this frame (corrupt stack?)");
+
+ /* Allocate the new frame but do not wire it in to the frame chain.
+ Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
+ frame->next to pull some fancy tricks (of course such code is, by
+ definition, recursive). Try to prevent it.
+
+ There is no reason to worry about memory leaks, should the
+ remainder of the function fail. The allocated memory will be
+ quickly reclaimed when the frame cache is flushed, and the `we've
+ been here before' check above will stop repeated memory
+ allocation calls. */
+ prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ prev_frame->level = this_frame->level + 1;
+
+ /* Don't yet compute ->unwind (and hence ->type). It is computed
+ on-demand in get_frame_type, frame_register_unwind, and
+ get_frame_id. */
+
+ /* Don't yet compute the frame's ID. It is computed on-demand by
+ get_frame_id(). */
+
+ /* The unwound frame ID is validate at the start of this function,
+ as part of the logic to decide if that frame should be further
+ unwound, and not here while the prev frame is being created.
+ Doing this makes it possible for the user to examine a frame that
+ has an invalid frame ID.
+
+ Some very old VAX code noted: [...] For the sake of argument,
+ suppose that the stack is somewhat trashed (which is one reason
+ that "info frame" exists). So, return 0 (indicating we don't
+ know the address of the arglist) if we don't know what frame this
+ frame calls. */
+
+ /* Link it in. */
+ this_frame->prev = prev_frame;
+ prev_frame->next = this_frame;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev_frame);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+
+ return prev_frame;
+}
+
+CORE_ADDR
+get_frame_pc (struct frame_info *frame)
+{
+ gdb_assert (frame->next != NULL);
+ return frame_pc_unwind (frame->next);
+}
+
+/* Return an address of that falls within the frame's code block. */
+
+CORE_ADDR
+frame_unwind_address_in_block (struct frame_info *next_frame)
+{
+ /* A draft address. */
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+ /* If THIS frame is not inner most (i.e., NEXT isn't the sentinel),
+ and NEXT is `normal' (i.e., not a sigtramp, dummy, ....) THIS
+ frame's PC ends up pointing at the instruction fallowing the
+ "call". Adjust that PC value so that it falls on the call
+ instruction (which, hopefully, falls within THIS frame's code
+ block. So far it's proved to be a very good approximation. See
+ get_frame_type for why ->type can't be used. */
+ if (next_frame->level >= 0
+ && get_frame_type (next_frame) == NORMAL_FRAME)
+ --pc;
+ return pc;
+}
+
+CORE_ADDR
+get_frame_address_in_block (struct frame_info *this_frame)
+{
+ return frame_unwind_address_in_block (this_frame->next);
+}
+
+static int
+pc_notcurrent (struct frame_info *frame)
+{
+ /* If FRAME is not the innermost frame, that normally means that
+ FRAME->pc points at the return instruction (which is *after* the
+ call instruction), and we want to get the line containing the
+ call (because the call is where the user thinks the program is).
+ However, if the next frame is either a SIGTRAMP_FRAME or a
+ DUMMY_FRAME, then the next frame will contain a saved interrupt
+ PC and such a PC indicates the current (rather than next)
+ instruction/line, consequently, for such cases, want to get the
+ line containing fi->pc. */
+ struct frame_info *next = get_next_frame (frame);
+ int notcurrent = (next != NULL && get_frame_type (next) == NORMAL_FRAME);
+ return notcurrent;
+}
+
+void
+find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
+{
+ (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
+}
+
+/* Per "frame.h", return the ``address'' of the frame. Code should
+ really be using get_frame_id(). */
+CORE_ADDR
+get_frame_base (struct frame_info *fi)
+{
+ return get_frame_id (fi).stack_addr;
+}
+
+/* High-level offsets into the frame. Used by the debug info. */
+
+CORE_ADDR
+get_frame_base_address (struct frame_info *fi)
+{
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ return 0;
+ if (fi->base == NULL)
+ fi->base = frame_base_find_by_frame (fi->next);
+ /* Sneaky: If the low-level unwind and high-level base code share a
+ common unwinder, let them share the prologue cache. */
+ if (fi->base->unwind == fi->unwind)
+ return fi->base->this_base (fi->next, &fi->prologue_cache);
+ return fi->base->this_base (fi->next, &fi->base_cache);
+}
+
+CORE_ADDR
+get_frame_locals_address (struct frame_info *fi)
+{
+ void **cache;
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ return 0;
+ /* If there isn't a frame address method, find it. */
+ if (fi->base == NULL)
+ fi->base = frame_base_find_by_frame (fi->next);
+ /* Sneaky: If the low-level unwind and high-level base code share a
+ common unwinder, let them share the prologue cache. */
+ if (fi->base->unwind == fi->unwind)
+ cache = &fi->prologue_cache;
+ else
+ cache = &fi->base_cache;
+ return fi->base->this_locals (fi->next, cache);
+}
+
+CORE_ADDR
+get_frame_args_address (struct frame_info *fi)
+{
+ void **cache;
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ return 0;
+ /* If there isn't a frame address method, find it. */
+ if (fi->base == NULL)
+ fi->base = frame_base_find_by_frame (fi->next);
+ /* Sneaky: If the low-level unwind and high-level base code share a
+ common unwinder, let them share the prologue cache. */
+ if (fi->base->unwind == fi->unwind)
+ cache = &fi->prologue_cache;
+ else
+ cache = &fi->base_cache;
+ return fi->base->this_args (fi->next, cache);
+}
+
+/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
+ or -1 for a NULL frame. */
+
+int
+frame_relative_level (struct frame_info *fi)
+{
+ if (fi == NULL)
+ return -1;
+ else
+ return fi->level;
+}
+
+enum frame_type
+get_frame_type (struct frame_info *frame)
+{
+ /* Some targets still don't use [generic] dummy frames. Catch them
+ here. */
+ if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+ && deprecated_frame_in_dummy (frame))
+ return DUMMY_FRAME;
+
+ /* Some legacy code, e.g, mips_init_extra_frame_info() wants
+ to determine the frame's type prior to it being completely
+ initialized. Don't attempt to lazily initialize ->unwind for
+ legacy code. It will be initialized in legacy_get_prev_frame(). */
+ if (frame->unwind == NULL && !legacy_frame_p (current_gdbarch))
+ {
+ /* Initialize the frame's unwinder because it is that which
+ provides the frame's type. */
+ frame->unwind = frame_unwind_find_by_frame (frame->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type using
+ the method deprecated_set_frame_type(). */
+ frame->type = frame->unwind->type;
+ }
+ if (frame->type == UNKNOWN_FRAME)
+ return NORMAL_FRAME;
+ else
+ return frame->type;
+}
+
+void
+deprecated_set_frame_type (struct frame_info *frame, enum frame_type type)
+{
+ /* Arrrg! See comment in "frame.h". */
+ frame->type = type;
+}
+
+struct frame_extra_info *
+get_frame_extra_info (struct frame_info *fi)
+{
+ return fi->extra_info;
+}
+
+struct frame_extra_info *
+frame_extra_info_zalloc (struct frame_info *fi, long size)
+{
+ fi->extra_info = frame_obstack_zalloc (size);
+ return fi->extra_info;
+}
+
+void
+deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
+{
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ deprecated_update_frame_pc_hack (frame=%d,pc=0x%s) }\n",
+ frame->level, paddr_nz (pc));
+ /* NOTE: cagney/2003-03-11: Some architectures (e.g., Arm) are
+ maintaining a locally allocated frame object. Since such frame's
+ are not in the frame chain, it isn't possible to assume that the
+ frame has a next. Sigh. */
+ if (frame->next != NULL)
+ {
+ /* While we're at it, update this frame's cached PC value, found
+ in the next frame. Oh for the day when "struct frame_info"
+ is opaque and this hack on hack can just go away. */
+ frame->next->prev_pc.value = pc;
+ frame->next->prev_pc.p = 1;
+ }
+}
+
+void
+deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
+{
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ deprecated_update_frame_base_hack (frame=%d,base=0x%s) }\n",
+ frame->level, paddr_nz (base));
+ /* See comment in "frame.h". */
+ frame->this_id.value.stack_addr = base;
+}
+
+struct frame_info *
+deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
+ long sizeof_extra_info)
+{
+ struct frame_info *frame = XMALLOC (struct frame_info);
+ memset (frame, 0, sizeof (*frame));
+ frame->this_id.p = 1;
+ make_cleanup (xfree, frame);
+ if (sizeof_saved_regs > 0)
+ {
+ frame->saved_regs = xcalloc (1, sizeof_saved_regs);
+ make_cleanup (xfree, frame->saved_regs);
+ }
+ if (sizeof_extra_info > 0)
+ {
+ frame->extra_info = xcalloc (1, sizeof_extra_info);
+ make_cleanup (xfree, frame->extra_info);
+ }
+ return frame;
+}
+
+/* Memory access methods. */
+
+void
+get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr, void *buf,
+ int len)
+{
+ read_memory (addr, buf, len);
+}
+
+LONGEST
+get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr,
+ int len)
+{
+ return read_memory_integer (addr, len);
+}
+
+ULONGEST
+get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
+ int len)
+{
+ return read_memory_unsigned_integer (addr, len);
+}
+
+/* Architecture method. */
+
+struct gdbarch *
+get_frame_arch (struct frame_info *this_frame)
+{
+ return current_gdbarch;
+}
+
+/* Stack pointer methods. */
+
+CORE_ADDR
+get_frame_sp (struct frame_info *this_frame)
+{
+ return frame_sp_unwind (this_frame->next);
+}
+
+CORE_ADDR
+frame_sp_unwind (struct frame_info *next_frame)
+{
+ /* Normality, an architecture that provides a way of obtaining any
+ frame inner-most address. */
+ if (gdbarch_unwind_sp_p (current_gdbarch))
+ return gdbarch_unwind_sp (current_gdbarch, next_frame);
+ /* Things are looking grim. If it's the inner-most frame and there
+ is a TARGET_READ_SP then that can be used. */
+ if (next_frame->level < 0 && TARGET_READ_SP_P ())
+ return TARGET_READ_SP ();
+ /* Now things are really are grim. Hope that the value returned by
+ the SP_REGNUM register is meaningful. */
+ if (SP_REGNUM >= 0)
+ {
+ ULONGEST sp;
+ frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
+ return sp;
+ }
+ internal_error (__FILE__, __LINE__, "Missing unwind SP method");
+}
+
+
+int
+legacy_frame_p (struct gdbarch *current_gdbarch)
+{
+ if (DEPRECATED_INIT_FRAME_PC_P ()
+ || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
+ || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
+ || DEPRECATED_FRAME_CHAIN_P ())
+ /* No question, it's a legacy frame. */
+ return 1;
+ if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+ /* No question, it's not a legacy frame (provided none of the
+ deprecated methods checked above are present that is). */
+ return 0;
+ if (DEPRECATED_TARGET_READ_FP_P ()
+ || DEPRECATED_FP_REGNUM >= 0)
+ /* Assume it's legacy. If you're trying to convert a legacy frame
+ target to the new mechanism, get rid of these. legacy
+ get_prev_frame requires these when unwind_frame_id isn't
+ available. */
+ return 1;
+ /* Default to assuming that it's brand new code, and hence not
+ legacy. Force it down the non-legacy path so that the new code
+ uses the new frame mechanism from day one. Dummy frame's won't
+ work very well but we can live with that. */
+ return 0;
+}
+
+extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
+
+static struct cmd_list_element *set_backtrace_cmdlist;
+static struct cmd_list_element *show_backtrace_cmdlist;
+
+static void
+set_backtrace_cmd (char *args, int from_tty)
+{
+ help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout);
+}
+
+static void
+show_backtrace_cmd (char *args, int from_tty)
+{
+ cmd_show_list (show_backtrace_cmdlist, from_tty, "");
+}
+
+void
+_initialize_frame (void)
+{
+ obstack_init (&frame_cache_obstack);
+
+ add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, "\
+Set backtrace specific variables.\n\
+Configure backtrace variables such as the backtrace limit",
+ &set_backtrace_cmdlist, "set backtrace ",
+ 0/*allow-unknown*/, &setlist);
+ add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, "\
+Show backtrace specific variables\n\
+Show backtrace variables such as the backtrace limit",
+ &show_backtrace_cmdlist, "show backtrace ",
+ 0/*allow-unknown*/, &showlist);
+
+ add_setshow_boolean_cmd ("past-main", class_obscure,
+ &backtrace_past_main, "\
+Set whether backtraces should continue past \"main\".\n\
+Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
+the backtrace at \"main\". Set this variable if you need to see the rest\n\
+of the stack trace.", "\
+Show whether backtraces should continue past \"main\".\n\
+Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
+the backtrace at \"main\". Set this variable if you need to see the rest\n\
+of the stack trace.",
+ NULL, NULL, &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
+
+ add_setshow_uinteger_cmd ("limit", class_obscure,
+ &backtrace_limit, "\
+Set an upper bound on the number of backtrace levels.\n\
+No more than the specified number of frames can be displayed or examined.\n\
+Zero is unlimited.", "\
+Show the upper bound on the number of backtrace levels.",
+ NULL, NULL, &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
+
+ /* Debug this files internals. */
+ add_show_from_set (add_set_cmd ("frame", class_maintenance, var_zinteger,
+ &frame_debug, "Set frame debugging.\n\
+When non-zero, frame specific internal debugging is enabled.", &setdebuglist),
+ &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/frame.h b/contrib/gdb/gdb/frame.h
new file mode 100644
index 0000000..0cdae6d
--- /dev/null
+++ b/contrib/gdb/gdb/frame.h
@@ -0,0 +1,705 @@
+/* Definitions for dealing with stack frames, for GDB, the GNU debugger.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+/* The following is the intended naming schema for frame functions.
+ It isn't 100% consistent, but it is aproaching that. Frame naming
+ schema:
+
+ Prefixes:
+
+ get_frame_WHAT...(): Get WHAT from the THIS frame (functionaly
+ equivalent to THIS->next->unwind->what)
+
+ frame_unwind_WHAT...(): Unwind THIS frame's WHAT from the NEXT
+ frame.
+
+ put_frame_WHAT...(): Put a value into this frame (unsafe, need to
+ invalidate the frame / regcache afterwards) (better name more
+ strongly hinting at its unsafeness)
+
+ safe_....(): Safer version of various functions, doesn't throw an
+ error (leave this for later?). Returns non-zero if the fetch
+ succeeds. Return a freshly allocated error message?
+
+ Suffixes:
+
+ void /frame/_WHAT(): Read WHAT's value into the buffer parameter.
+
+ ULONGEST /frame/_WHAT_unsigned(): Return an unsigned value (the
+ alternative is *frame_unsigned_WHAT).
+
+ LONGEST /frame/_WHAT_signed(): Return WHAT signed value.
+
+ What:
+
+ /frame/_memory* (frame, coreaddr, len [, buf]): Extract/return
+ *memory.
+
+ /frame/_register* (frame, regnum [, buf]): extract/return register.
+
+ CORE_ADDR /frame/_{pc,sp,...} (frame): Resume address, innner most
+ stack *address, ...
+
+ */
+
+struct symtab_and_line;
+struct frame_unwind;
+struct frame_base;
+struct block;
+struct gdbarch;
+struct ui_file;
+
+/* A legacy unwinder to prop up architectures using the old style
+ saved regs array. */
+extern const struct frame_unwind *legacy_saved_regs_unwind;
+
+/* The frame object. */
+
+struct frame_info;
+
+/* The frame object's ID. This provides a per-frame unique identifier
+ that can be used to relocate a `struct frame_info' after a target
+ resume or a frame cache destruct. It of course assumes that the
+ inferior hasn't unwound the stack past that frame. */
+
+struct frame_id
+{
+ /* The frame's stack address. This shall be constant through out
+ the lifetime of a frame. Note that this requirement applies to
+ not just the function body, but also the prologue and (in theory
+ at least) the epilogue. Since that value needs to fall either on
+ the boundary, or within the frame's address range, the frame's
+ outer-most address (the inner-most address of the previous frame)
+ is used. Watch out for all the legacy targets that still use the
+ function pointer register or stack pointer register. They are
+ wrong. */
+ CORE_ADDR stack_addr;
+ /* The frame's code address. This shall be constant through out the
+ lifetime of the frame. While the PC (a.k.a. resume address)
+ changes as the function is executed, this code address cannot.
+ Typically, it is set to the address of the entry point of the
+ frame's function (as returned by frame_func_unwind(). */
+ CORE_ADDR code_addr;
+ /* The frame's special address. This shall be constant through out the
+ lifetime of the frame. This is used for architectures that may have
+ frames that do not change the stack but are still distinct and have
+ some form of distinct identifier (e.g. the ia64 which uses a 2nd
+ stack for registers). This field is treated as unordered - i.e. will
+ not be used in frame ordering comparisons such as frame_id_inner().
+ A zero in this field will be treated as a wild-card when comparing
+ frames for equality. */
+ CORE_ADDR special_addr;
+};
+
+/* Methods for constructing and comparing Frame IDs.
+
+ NOTE: Given stackless functions A and B, where A calls B (and hence
+ B is inner-to A). The relationships: !eq(A,B); !eq(B,A);
+ !inner(A,B); !inner(B,A); all hold.
+
+ This is because, while B is inner-to A, B is not strictly inner-to A.
+ Being stackless, they have an identical .stack_addr value, and differ
+ only by their unordered .code_addr and/or .special_addr values.
+
+ Because frame_id_inner is only used as a safety net (e.g.,
+ detect a corrupt stack) the lack of strictness is not a problem.
+ Code needing to determine an exact relationship between two frames
+ must instead use frame_id_eq and frame_id_unwind. For instance,
+ in the above, to determine that A stepped-into B, the equation
+ "A.id != B.id && A.id == id_unwind (B)" can be used. */
+
+/* For convenience. All fields are zero. */
+extern const struct frame_id null_frame_id;
+
+/* Construct a frame ID. The first parameter is the frame's constant
+ stack address (typically the outer-bound), and the second the
+ frame's constant code address (typically the entry point) (or zero,
+ to indicate a wild card). The special identifier address is
+ defaulted to zero. */
+extern struct frame_id frame_id_build (CORE_ADDR stack_addr,
+ CORE_ADDR code_addr);
+
+/* Construct a special frame ID. The first parameter is the frame's constant
+ stack address (typically the outer-bound), the second is the
+ frame's constant code address (typically the entry point) (or zero,
+ to indicate a wild card), and the third parameter is the frame's
+ special identifier address (or zero to indicate a wild card or
+ unused default). */
+extern struct frame_id frame_id_build_special (CORE_ADDR stack_addr,
+ CORE_ADDR code_addr,
+ CORE_ADDR special_addr);
+
+/* Returns non-zero when L is a valid frame (a valid frame has a
+ non-zero .base). */
+extern int frame_id_p (struct frame_id l);
+
+/* Returns non-zero when L and R identify the same frame, or, if
+ either L or R have a zero .func, then the same frame base. */
+extern int frame_id_eq (struct frame_id l, struct frame_id r);
+
+/* Returns non-zero when L is strictly inner-than R (they have
+ different frame .bases). Neither L, nor R can be `null'. See note
+ above about frameless functions. */
+extern int frame_id_inner (struct frame_id l, struct frame_id r);
+
+/* Write the internal representation of a frame ID on the specified
+ stream. */
+extern void fprint_frame_id (struct ui_file *file, struct frame_id id);
+
+
+/* For every stopped thread, GDB tracks two frames: current and
+ selected. Current frame is the inner most frame of the selected
+ thread. Selected frame is the one being examined by the the GDB
+ CLI (selected using `up', `down', ...). The frames are created
+ on-demand (via get_prev_frame()) and then held in a frame cache. */
+/* FIXME: cagney/2002-11-28: Er, there is a lie here. If you do the
+ sequence: `thread 1; up; thread 2; thread 1' you loose thread 1's
+ selected frame. At present GDB only tracks the selected frame of
+ the current thread. But be warned, that might change. */
+/* FIXME: cagney/2002-11-14: At any time, only one thread's selected
+ and current frame can be active. Switching threads causes gdb to
+ discard all that cached frame information. Ulgh! Instead, current
+ and selected frame should be bound to a thread. */
+
+/* On demand, create the inner most frame using information found in
+ the inferior. If the inner most frame can't be created, throw an
+ error. */
+extern struct frame_info *get_current_frame (void);
+
+/* Invalidates the frame cache (this function should have been called
+ invalidate_cached_frames).
+
+ FIXME: cagney/2002-11-28: The only difference between
+ flush_cached_frames() and reinit_frame_cache() is that the latter
+ explicitly sets the selected frame back to the current frame there
+ isn't any real difference (except that one delays the selection of
+ a new frame). Code can instead simply rely on get_selected_frame()
+ to reinit's the selected frame as needed. As for invalidating the
+ cache, there should be two methods one that reverts the thread's
+ selected frame back to current frame (for when the inferior
+ resumes) and one that does not (for when the user modifies the
+ target invalidating the frame cache). */
+extern void flush_cached_frames (void);
+extern void reinit_frame_cache (void);
+
+/* On demand, create the selected frame and then return it. If the
+ selected frame can not be created, this function throws an error. */
+/* FIXME: cagney/2002-11-28: At present, when there is no selected
+ frame, this function always returns the current (inner most) frame.
+ It should instead, when a thread has previously had its frame
+ selected (but not resumed) and the frame cache invalidated, find
+ and then return that thread's previously selected frame. */
+extern struct frame_info *get_selected_frame (void);
+
+/* Select a specific frame. NULL, apparently implies re-select the
+ inner most frame. */
+extern void select_frame (struct frame_info *);
+
+/* Given a FRAME, return the next (more inner, younger) or previous
+ (more outer, older) frame. */
+extern struct frame_info *get_prev_frame (struct frame_info *);
+extern struct frame_info *get_next_frame (struct frame_info *);
+
+/* Given a frame's ID, relocate the frame. Returns NULL if the frame
+ is not found. */
+extern struct frame_info *frame_find_by_id (struct frame_id id);
+
+/* Base attributes of a frame: */
+
+/* The frame's `resume' address. Where the program will resume in
+ this frame.
+
+ This replaced: frame->pc; */
+extern CORE_ADDR get_frame_pc (struct frame_info *);
+
+/* An address (not necessarily alligned to an instruction boundary)
+ that falls within THIS frame's code block.
+
+ When a function call is the last statement in a block, the return
+ address for the call may land at the start of the next block.
+ Similarly, if a no-return function call is the last statement in
+ the function, the return address may end up pointing beyond the
+ function, and possibly at the start of the next function.
+
+ These methods make an allowance for this. For call frames, this
+ function returns the frame's PC-1 which "should" be an address in
+ the frame's block. */
+
+extern CORE_ADDR get_frame_address_in_block (struct frame_info *this_frame);
+extern CORE_ADDR frame_unwind_address_in_block (struct frame_info *next_frame);
+
+/* The frame's inner-most bound. AKA the stack-pointer. Confusingly
+ known as top-of-stack. */
+
+extern CORE_ADDR get_frame_sp (struct frame_info *);
+extern CORE_ADDR frame_sp_unwind (struct frame_info *);
+
+
+/* Following on from the `resume' address. Return the entry point
+ address of the function containing that resume address, or zero if
+ that function isn't known. */
+extern CORE_ADDR frame_func_unwind (struct frame_info *fi);
+extern CORE_ADDR get_frame_func (struct frame_info *fi);
+
+/* Closely related to the resume address, various symbol table
+ attributes that are determined by the PC. Note that for a normal
+ frame, the PC refers to the resume address after the return, and
+ not the call instruction. In such a case, the address is adjusted
+ so that it (approximatly) identifies the call site (and not return
+ site).
+
+ NOTE: cagney/2002-11-28: The frame cache could be used to cache the
+ computed value. Working on the assumption that the bottle-neck is
+ in the single step code, and that code causes the frame cache to be
+ constantly flushed, caching things in a frame is probably of little
+ benefit. As they say `show us the numbers'.
+
+ NOTE: cagney/2002-11-28: Plenty more where this one came from:
+ find_frame_block(), find_frame_partial_function(),
+ find_frame_symtab(), find_frame_function(). Each will need to be
+ carefully considered to determine if the real intent was for it to
+ apply to the PC or the adjusted PC. */
+extern void find_frame_sal (struct frame_info *frame,
+ struct symtab_and_line *sal);
+
+/* Return the frame base (what ever that is) (DEPRECATED).
+
+ Old code was trying to use this single method for two conflicting
+ purposes. Such code needs to be updated to use either of:
+
+ get_frame_id: A low level frame unique identifier, that consists of
+ both a stack and a function address, that can be used to uniquely
+ identify a frame. This value is determined by the frame's
+ low-level unwinder, the stack part [typically] being the
+ top-of-stack of the previous frame, and the function part being the
+ function's start address. Since the correct identification of a
+ frameless function requires both the a stack and function address,
+ the old get_frame_base method was not sufficient.
+
+ get_frame_base_address: get_frame_locals_address:
+ get_frame_args_address: A set of high-level debug-info dependant
+ addresses that fall within the frame. These addresses almost
+ certainly will not match the stack address part of a frame ID (as
+ returned by get_frame_base).
+
+ This replaced: frame->frame; */
+
+extern CORE_ADDR get_frame_base (struct frame_info *);
+
+/* Return the per-frame unique identifer. Can be used to relocate a
+ frame after a frame cache flush (and other similar operations). If
+ FI is NULL, return the null_frame_id. */
+extern struct frame_id get_frame_id (struct frame_info *fi);
+
+/* Assuming that a frame is `normal', return its base-address, or 0 if
+ the information isn't available. NOTE: This address is really only
+ meaningful to the frame's high-level debug info. */
+extern CORE_ADDR get_frame_base_address (struct frame_info *);
+
+/* Assuming that a frame is `normal', return the base-address of the
+ local variables, or 0 if the information isn't available. NOTE:
+ This address is really only meaningful to the frame's high-level
+ debug info. Typically, the argument and locals share a single
+ base-address. */
+extern CORE_ADDR get_frame_locals_address (struct frame_info *);
+
+/* Assuming that a frame is `normal', return the base-address of the
+ parameter list, or 0 if that information isn't available. NOTE:
+ This address is really only meaningful to the frame's high-level
+ debug info. Typically, the argument and locals share a single
+ base-address. */
+extern CORE_ADDR get_frame_args_address (struct frame_info *);
+
+/* The frame's level: 0 for innermost, 1 for its caller, ...; or -1
+ for an invalid frame). */
+extern int frame_relative_level (struct frame_info *fi);
+
+/* Return the frame's type. Some are real, some are signal
+ trampolines, and some are completely artificial (dummy). */
+
+enum frame_type
+{
+ /* The frame's type hasn't yet been defined. This is a catch-all
+ for legacy code that uses really strange technicques, such as
+ deprecated_set_frame_type, to set the frame's type. New code
+ should not use this value. */
+ UNKNOWN_FRAME,
+ /* A true stack frame, created by the target program during normal
+ execution. */
+ NORMAL_FRAME,
+ /* A fake frame, created by GDB when performing an inferior function
+ call. */
+ DUMMY_FRAME,
+ /* In a signal handler, various OSs handle this in various ways.
+ The main thing is that the frame may be far from normal. */
+ SIGTRAMP_FRAME
+};
+extern enum frame_type get_frame_type (struct frame_info *);
+
+/* FIXME: cagney/2002-11-10: Some targets want to directly mark a
+ frame as being of a specific type. This shouldn't be necessary.
+ PC_IN_SIGTRAMP() indicates a SIGTRAMP_FRAME and
+ DEPRECATED_PC_IN_CALL_DUMMY() indicates a DUMMY_FRAME. I suspect
+ the real problem here is that get_prev_frame() only sets
+ initialized after DEPRECATED_INIT_EXTRA_FRAME_INFO as been called.
+ Consequently, some targets found that the frame's type was wrong
+ and tried to fix it. The correct fix is to modify get_prev_frame()
+ so that it initializes the frame's type before calling any other
+ functions. */
+extern void deprecated_set_frame_type (struct frame_info *,
+ enum frame_type type);
+
+/* Unwind the stack frame so that the value of REGNUM, in the previous
+ (up, older) frame is returned. If VALUEP is NULL, don't
+ fetch/compute the value. Instead just return the location of the
+ value. */
+extern void frame_register_unwind (struct frame_info *frame, int regnum,
+ int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump,
+ void *valuep);
+
+/* Fetch a register from this, or unwind a register from the next
+ frame. Note that the get_frame methods are wrappers to
+ frame->next->unwind. They all [potentially] throw an error if the
+ fetch fails. */
+
+extern void frame_unwind_register (struct frame_info *frame,
+ int regnum, void *buf);
+extern void get_frame_register (struct frame_info *frame,
+ int regnum, void *buf);
+
+extern LONGEST frame_unwind_register_signed (struct frame_info *frame,
+ int regnum);
+extern LONGEST get_frame_register_signed (struct frame_info *frame,
+ int regnum);
+extern ULONGEST frame_unwind_register_unsigned (struct frame_info *frame,
+ int regnum);
+extern ULONGEST get_frame_register_unsigned (struct frame_info *frame,
+ int regnum);
+
+
+/* Use frame_unwind_register_signed. */
+extern void frame_unwind_unsigned_register (struct frame_info *frame,
+ int regnum, ULONGEST *val);
+
+/* Get the value of the register that belongs to this FRAME. This
+ function is a wrapper to the call sequence ``frame_unwind_register
+ (get_next_frame (FRAME))''. As per frame_register_unwind(), if
+ VALUEP is NULL, the registers value is not fetched/computed. */
+
+extern void frame_register (struct frame_info *frame, int regnum,
+ int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump,
+ void *valuep);
+
+/* The reverse. Store a register value relative to the specified
+ frame. Note: this call makes the frame's state undefined. The
+ register and frame caches must be flushed. */
+extern void put_frame_register (struct frame_info *frame, int regnum,
+ const void *buf);
+
+/* Map between a frame register number and its name. A frame register
+ space is a superset of the cooked register space --- it also
+ includes builtin registers. If NAMELEN is negative, use the NAME's
+ length when doing the comparison. */
+
+extern int frame_map_name_to_regnum (struct frame_info *frame,
+ const char *name, int namelen);
+extern const char *frame_map_regnum_to_name (struct frame_info *frame,
+ int regnum);
+
+/* Unwind the PC. Strictly speaking return the resume address of the
+ calling frame. For GDB, `pc' is the resume address and not a
+ specific register. */
+
+extern CORE_ADDR frame_pc_unwind (struct frame_info *frame);
+
+/* Discard the specified frame. Restoring the registers to the state
+ of the caller. */
+extern void frame_pop (struct frame_info *frame);
+
+/* Return memory from the specified frame. A frame knows its thread /
+ LWP and hence can find its way down to a target. The assumption
+ here is that the current and previous frame share a common address
+ space.
+
+ If the memory read fails, these methods throw an error.
+
+ NOTE: cagney/2003-06-03: Should there be unwind versions of these
+ methods? That isn't clear. Can code, for instance, assume that
+ this and the previous frame's memory or architecture are identical?
+ If architecture / memory changes are always separated by special
+ adaptor frames this should be ok. */
+
+extern void get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr,
+ void *buf, int len);
+extern LONGEST get_frame_memory_signed (struct frame_info *this_frame,
+ CORE_ADDR memaddr, int len);
+extern ULONGEST get_frame_memory_unsigned (struct frame_info *this_frame,
+ CORE_ADDR memaddr, int len);
+
+/* Return this frame's architecture. */
+
+extern struct gdbarch *get_frame_arch (struct frame_info *this_frame);
+
+
+/* Values for the source flag to be used in print_frame_info_base(). */
+enum print_what
+ {
+ /* Print only the source line, like in stepi. */
+ SRC_LINE = -1,
+ /* Print only the location, i.e. level, address (sometimes)
+ function, args, file, line, line num. */
+ LOCATION,
+ /* Print both of the above. */
+ SRC_AND_LOC,
+ /* Print location only, but always include the address. */
+ LOC_AND_ADDRESS
+ };
+
+/* Allocate additional space for appendices to a struct frame_info.
+ NOTE: Much of GDB's code works on the assumption that the allocated
+ saved_regs[] array is the size specified below. If you try to make
+ that array smaller, GDB will happily walk off its end. */
+
+#ifdef SIZEOF_FRAME_SAVED_REGS
+#error "SIZEOF_FRAME_SAVED_REGS can not be re-defined"
+#endif
+#define SIZEOF_FRAME_SAVED_REGS \
+ (sizeof (CORE_ADDR) * (NUM_REGS+NUM_PSEUDO_REGS))
+
+/* Allocate zero initialized memory from the frame cache obstack.
+ Appendices to the frame info (such as the unwind cache) should
+ allocate memory using this method. */
+
+extern void *frame_obstack_zalloc (unsigned long size);
+#define FRAME_OBSTACK_ZALLOC(TYPE) ((TYPE *) frame_obstack_zalloc (sizeof (TYPE)))
+#define FRAME_OBSTACK_CALLOC(NUMBER,TYPE) ((TYPE *) frame_obstack_zalloc ((NUMBER) * sizeof (TYPE)))
+
+/* If legacy_frame_chain_valid() returns zero it means that the given
+ frame is the outermost one and has no caller.
+
+ This method has been superseeded by the per-architecture
+ frame_unwind_pc() (returns 0 to indicate an invalid return address)
+ and per-frame this_id() (returns a NULL frame ID to indicate an
+ invalid frame). */
+extern int legacy_frame_chain_valid (CORE_ADDR, struct frame_info *);
+
+extern void generic_save_dummy_frame_tos (CORE_ADDR sp);
+
+extern struct block *get_frame_block (struct frame_info *,
+ CORE_ADDR *addr_in_block);
+
+/* Return the `struct block' that belongs to the selected thread's
+ selected frame. If the inferior has no state, return NULL.
+
+ NOTE: cagney/2002-11-29:
+
+ No state? Does the inferior have any execution state (a core file
+ does, an executable does not). At present the code tests
+ `target_has_stack' but I'm left wondering if it should test
+ `target_has_registers' or, even, a merged target_has_state.
+
+ Should it look at the most recently specified SAL? If the target
+ has no state, should this function try to extract a block from the
+ most recently selected SAL? That way `list foo' would give it some
+ sort of reference point. Then again, perhaphs that would confuse
+ things.
+
+ Calls to this function can be broken down into two categories: Code
+ that uses the selected block as an additional, but optional, data
+ point; Code that uses the selected block as a prop, when it should
+ have the relevant frame/block/pc explicitly passed in.
+
+ The latter can be eliminated by correctly parameterizing the code,
+ the former though is more interesting. Per the "address" command,
+ it occures in the CLI code and makes it possible for commands to
+ work, even when the inferior has no state. */
+
+extern struct block *get_selected_block (CORE_ADDR *addr_in_block);
+
+extern struct symbol *get_frame_function (struct frame_info *);
+
+extern CORE_ADDR get_pc_function_start (CORE_ADDR);
+
+extern int legacy_frameless_look_for_prologue (struct frame_info *);
+
+extern struct frame_info *find_relative_frame (struct frame_info *, int *);
+
+extern void show_and_print_stack_frame (struct frame_info *fi, int level,
+ int source);
+
+extern void print_stack_frame (struct frame_info *, int, int);
+
+extern void show_stack_frame (struct frame_info *);
+
+extern void print_frame_info (struct frame_info *, int, int, int);
+
+extern void show_frame_info (struct frame_info *, int, int, int);
+
+extern struct frame_info *block_innermost_frame (struct block *);
+
+/* NOTE: cagney/2002-09-13: There is no need for this function. */
+extern CORE_ADDR deprecated_read_register_dummy (CORE_ADDR pc,
+ CORE_ADDR fp, int);
+extern void generic_push_dummy_frame (void);
+extern void generic_pop_current_frame (void (*)(struct frame_info *));
+extern void generic_pop_dummy_frame (void);
+
+extern int generic_pc_in_call_dummy (CORE_ADDR pc,
+ CORE_ADDR sp, CORE_ADDR fp);
+
+/* NOTE: cagney/2002-06-26: Targets should no longer use this
+ function. Instead, the contents of a dummy frames registers can be
+ obtained by applying: frame_register_unwind to the dummy frame; or
+ frame_register_unwind() to the next outer frame. */
+
+extern char *deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp);
+
+
+/* The DEPRECATED_GET_SAVED_REGISTER architecture interface is
+ entirely redundant. New architectures should implement per-frame
+ unwinders (ref "frame-unwind.h"). */
+extern void deprecated_generic_get_saved_register (char *, int *, CORE_ADDR *,
+ struct frame_info *, int,
+ enum lval_type *);
+
+extern void generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi);
+
+/* FIXME: cagney/2003-02-02: Should be deprecated or replaced with a
+ function called get_frame_register_p(). This slightly weird (and
+ older) variant of get_frame_register() returns zero (indicating the
+ register is unavailable) if either: the register isn't cached; or
+ the register has been optimized out. Problem is, neither check is
+ exactly correct. A register can't be optimized out (it may not
+ have been saved as part of a function call); The fact that a
+ register isn't in the register cache doesn't mean that the register
+ isn't available (it could have been fetched from memory). */
+
+extern int frame_register_read (struct frame_info *frame, int regnum,
+ void *buf);
+
+/* From stack.c. */
+extern void args_info (char *, int);
+
+extern void locals_info (char *, int);
+
+extern void (*selected_frame_level_changed_hook) (int);
+
+extern void return_command (char *, int);
+
+
+/* NOTE: cagney/2002-11-27:
+
+ You might think that the below global can simply be replaced by a
+ call to either get_selected_frame() or select_frame().
+
+ Unfortunately, it isn't that easy.
+
+ The relevant code needs to be audited to determine if it is
+ possible (or pratical) to instead pass the applicable frame in as a
+ parameter. For instance, DEPRECATED_DO_REGISTERS_INFO() relied on
+ the deprecated_selected_frame global, while its replacement,
+ PRINT_REGISTERS_INFO(), is parameterized with the selected frame.
+ The only real exceptions occure at the edge (in the CLI code) where
+ user commands need to pick up the selected frame before proceeding.
+
+ This is important. GDB is trying to stamp out the hack:
+
+ saved_frame = deprecated_selected_frame;
+ deprecated_selected_frame = ...;
+ hack_using_global_selected_frame ();
+ deprecated_selected_frame = saved_frame;
+
+ Take care! */
+
+extern struct frame_info *deprecated_selected_frame;
+
+/* NOTE: drow/2003-09-06:
+
+ This function is "a step sideways" for uses of deprecated_selected_frame.
+ They should be fixed as above, but meanwhile, we needed a solution for
+ cases where functions are called with a NULL frame meaning either "the
+ program is not running" or "use the selected frame". Lazy building of
+ deprecated_selected_frame confuses the situation, because now
+ deprecated_selected_frame can be NULL even when the inferior is running.
+
+ This function calls get_selected_frame if the inferior should have a
+ frame, or returns NULL otherwise. */
+
+extern struct frame_info *deprecated_safe_get_selected_frame (void);
+
+/* Create a frame using the specified BASE and PC. */
+
+extern struct frame_info *create_new_frame (CORE_ADDR base, CORE_ADDR pc);
+
+
+/* Create/access the frame's `extra info'. The extra info is used by
+ older code to store information such as the analyzed prologue. The
+ zalloc() should only be called by the INIT_EXTRA_INFO method. */
+
+extern struct frame_extra_info *frame_extra_info_zalloc (struct frame_info *fi,
+ long size);
+extern struct frame_extra_info *get_frame_extra_info (struct frame_info *fi);
+
+/* Create/access the frame's `saved_regs'. The saved regs are used by
+ older code to store the address of each register (except for
+ SP_REGNUM where the value of the register in the previous frame is
+ stored). */
+extern CORE_ADDR *frame_saved_regs_zalloc (struct frame_info *);
+extern CORE_ADDR *deprecated_get_frame_saved_regs (struct frame_info *);
+
+/* FIXME: cagney/2002-12-06: Has the PC in the current frame changed?
+ "infrun.c", Thanks to DECR_PC_AFTER_BREAK, can change the PC after
+ the initial frame create. This puts things back in sync.
+
+ This replaced: frame->pc = ....; */
+extern void deprecated_update_frame_pc_hack (struct frame_info *frame,
+ CORE_ADDR pc);
+
+/* FIXME: cagney/2002-12-18: Has the frame's base changed? Or to be
+ more exact, was that initial guess at the frame's base as returned
+ by deprecated_read_fp() wrong? If it was, fix it. This shouldn't
+ be necessary since the code should be getting the frame's base
+ correct from the outset.
+
+ This replaced: frame->frame = ....; */
+extern void deprecated_update_frame_base_hack (struct frame_info *frame,
+ CORE_ADDR base);
+
+/* FIXME: cagney/2003-01-05: Allocate a frame, along with the
+ saved_regs and extra_info. Set up cleanups for all three. Same as
+ for deprecated_frame_xmalloc, targets are calling this when
+ creating a scratch `struct frame_info'. The frame overhaul makes
+ this unnecessary since all frame queries are parameterized with a
+ common cache parameter and a frame. */
+extern struct frame_info *deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
+ long sizeof_extra_info);
+
+/* Return non-zero if the architecture is relying on legacy frame
+ code. */
+extern int legacy_frame_p (struct gdbarch *gdbarch);
+
+#endif /* !defined (FRAME_H) */
diff --git a/contrib/gdb/gdb/gcore.c b/contrib/gdb/gdb/gcore.c
new file mode 100644
index 0000000..b551372
--- /dev/null
+++ b/contrib/gdb/gdb/gcore.c
@@ -0,0 +1,501 @@
+/* Generate a core file for the inferior process.
+
+ Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "elf-bfd.h"
+#include "infcall.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "objfiles.h"
+#include "symfile.h"
+
+#include "cli/cli-decode.h"
+
+#include "gdb_assert.h"
+
+static char *default_gcore_target (void);
+static enum bfd_architecture default_gcore_arch (void);
+static unsigned long default_gcore_mach (void);
+static int gcore_memory_sections (bfd *);
+
+/* Generate a core file from the inferior process. */
+
+static void
+gcore_command (char *args, int from_tty)
+{
+ struct cleanup *old_chain;
+ char *corefilename, corefilename_buffer[40];
+ asection *note_sec = NULL;
+ bfd *obfd;
+ void *note_data = NULL;
+ int note_size = 0;
+
+ /* No use generating a corefile without a target process. */
+ if (!target_has_execution)
+ noprocess ();
+
+ if (args && *args)
+ corefilename = args;
+ else
+ {
+ /* Default corefile name is "core.PID". */
+ sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
+ corefilename = corefilename_buffer;
+ }
+
+ if (info_verbose)
+ fprintf_filtered (gdb_stdout,
+ "Opening corefile '%s' for output.\n", corefilename);
+
+ /* Open the output file. */
+ obfd = bfd_openw (corefilename, default_gcore_target ());
+ if (!obfd)
+ error ("Failed to open '%s' for output.", corefilename);
+
+ /* Need a cleanup that will close the file (FIXME: delete it?). */
+ old_chain = make_cleanup_bfd_close (obfd);
+
+ bfd_set_format (obfd, bfd_core);
+ bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());
+
+ /* An external target method must build the notes section. */
+ note_data = target_make_corefile_notes (obfd, &note_size);
+
+ /* Create the note section. */
+ if (note_data != NULL && note_size != 0)
+ {
+ note_sec = bfd_make_section_anyway (obfd, "note0");
+ if (note_sec == NULL)
+ error ("Failed to create 'note' section for corefile: %s",
+ bfd_errmsg (bfd_get_error ()));
+
+ bfd_set_section_vma (obfd, note_sec, 0);
+ bfd_set_section_flags (obfd, note_sec,
+ SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC);
+ bfd_set_section_alignment (obfd, note_sec, 0);
+ bfd_set_section_size (obfd, note_sec, note_size);
+ }
+
+ /* Now create the memory/load sections. */
+ if (gcore_memory_sections (obfd) == 0)
+ error ("gcore: failed to get corefile memory sections from target.");
+
+ /* Write out the contents of the note section. */
+ if (note_data != NULL && note_size != 0)
+ {
+ if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
+ warning ("writing note section (%s)", bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* Succeeded. */
+ fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename);
+
+ /* Clean-ups will close the output file and free malloc memory. */
+ do_cleanups (old_chain);
+ return;
+}
+
+static unsigned long
+default_gcore_mach (void)
+{
+#if 1 /* See if this even matters... */
+ return 0;
+#else
+#ifdef TARGET_ARCHITECTURE
+ const struct bfd_arch_info *bfdarch = TARGET_ARCHITECTURE;
+
+ if (bfdarch != NULL)
+ return bfdarch->mach;
+#endif /* TARGET_ARCHITECTURE */
+ if (exec_bfd == NULL)
+ error ("Can't find default bfd machine type (need execfile).");
+
+ return bfd_get_mach (exec_bfd);
+#endif /* 1 */
+}
+
+static enum bfd_architecture
+default_gcore_arch (void)
+{
+#ifdef TARGET_ARCHITECTURE
+ const struct bfd_arch_info * bfdarch = TARGET_ARCHITECTURE;
+
+ if (bfdarch != NULL)
+ return bfdarch->arch;
+#endif
+ if (exec_bfd == NULL)
+ error ("Can't find bfd architecture for corefile (need execfile).");
+
+ return bfd_get_arch (exec_bfd);
+}
+
+static char *
+default_gcore_target (void)
+{
+ /* FIXME: This may only work for ELF targets. */
+ if (exec_bfd == NULL)
+ return NULL;
+ else
+ return bfd_get_target (exec_bfd);
+}
+
+/* Derive a reasonable stack segment by unwinding the target stack,
+ and store its limits in *BOTTOM and *TOP. Return non-zero if
+ successful. */
+
+static int
+derive_stack_segment (bfd_vma *bottom, bfd_vma *top)
+{
+ struct frame_info *fi, *tmp_fi;
+
+ gdb_assert (bottom);
+ gdb_assert (top);
+
+ /* Can't succeed without stack and registers. */
+ if (!target_has_stack || !target_has_registers)
+ return 0;
+
+ /* Can't succeed without current frame. */
+ fi = get_current_frame ();
+ if (fi == NULL)
+ return 0;
+
+ /* Save frame pointer of TOS frame. */
+ *top = get_frame_base (fi);
+ /* If current stack pointer is more "inner", use that instead. */
+ if (INNER_THAN (read_sp (), *top))
+ *top = read_sp ();
+
+ /* Find prev-most frame. */
+ while ((tmp_fi = get_prev_frame (fi)) != NULL)
+ fi = tmp_fi;
+
+ /* Save frame pointer of prev-most frame. */
+ *bottom = get_frame_base (fi);
+
+ /* Now canonicalize their order, so that BOTTOM is a lower address
+ (as opposed to a lower stack frame). */
+ if (*bottom > *top)
+ {
+ bfd_vma tmp_vma;
+
+ tmp_vma = *top;
+ *top = *bottom;
+ *bottom = tmp_vma;
+ }
+
+ return 1;
+}
+
+/* Derive a reasonable heap segment for ABFD by looking at sbrk and
+ the static data sections. Store its limits in *BOTTOM and *TOP.
+ Return non-zero if successful. */
+
+static int
+derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
+{
+ bfd_vma top_of_data_memory = 0;
+ bfd_vma top_of_heap = 0;
+ bfd_size_type sec_size;
+ struct value *zero, *sbrk;
+ bfd_vma sec_vaddr;
+ asection *sec;
+
+ gdb_assert (bottom);
+ gdb_assert (top);
+
+ /* This function depends on being able to call a function in the
+ inferior. */
+ if (!target_has_execution)
+ return 0;
+
+ /* The following code assumes that the link map is arranged as
+ follows (low to high addresses):
+
+ ---------------------------------
+ | text sections |
+ ---------------------------------
+ | data sections (including bss) |
+ ---------------------------------
+ | heap |
+ --------------------------------- */
+
+ for (sec = abfd->sections; sec; sec = sec->next)
+ {
+ if (bfd_get_section_flags (abfd, sec) & SEC_DATA
+ || strcmp (".bss", bfd_section_name (abfd, sec)) == 0)
+ {
+ sec_vaddr = bfd_get_section_vma (abfd, sec);
+ sec_size = bfd_get_section_size_before_reloc (sec);
+ if (sec_vaddr + sec_size > top_of_data_memory)
+ top_of_data_memory = sec_vaddr + sec_size;
+ }
+ }
+
+ /* Now get the top-of-heap by calling sbrk in the inferior. */
+ if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL)
+ {
+ sbrk = find_function_in_inferior ("sbrk");
+ if (sbrk == NULL)
+ return 0;
+ }
+ else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL)
+ {
+ sbrk = find_function_in_inferior ("_sbrk");
+ if (sbrk == NULL)
+ return 0;
+ }
+ else
+ return 0;
+
+ zero = value_from_longest (builtin_type_int, 0);
+ gdb_assert (zero);
+ sbrk = call_function_by_hand (sbrk, 1, &zero);
+ if (sbrk == NULL)
+ return 0;
+ top_of_heap = value_as_long (sbrk);
+
+ /* Return results. */
+ if (top_of_heap > top_of_data_memory)
+ {
+ *bottom = top_of_data_memory;
+ *top = top_of_heap;
+ return 1;
+ }
+
+ /* No additional heap space needs to be saved. */
+ return 0;
+}
+
+static void
+make_output_phdrs (bfd *obfd, asection *osec, void *ignored)
+{
+ int p_flags = 0;
+ int p_type;
+
+ /* FIXME: these constants may only be applicable for ELF. */
+ if (strncmp (bfd_section_name (obfd, osec), "load", 4) == 0)
+ p_type = PT_LOAD;
+ else
+ p_type = PT_NOTE;
+
+ p_flags |= PF_R; /* Segment is readable. */
+ if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY))
+ p_flags |= PF_W; /* Segment is writable. */
+ if (bfd_get_section_flags (obfd, osec) & SEC_CODE)
+ p_flags |= PF_X; /* Segment is executable. */
+
+ bfd_record_phdr (obfd, p_type, 1, p_flags, 0, 0, 0, 0, 1, &osec);
+}
+
+static int
+gcore_create_callback (CORE_ADDR vaddr, unsigned long size,
+ int read, int write, int exec, void *data)
+{
+ bfd *obfd = data;
+ asection *osec;
+ flagword flags = SEC_ALLOC | SEC_HAS_CONTENTS | SEC_LOAD;
+
+ /* If the memory segment has no permissions set, ignore it, otherwise
+ when we later try to access it for read/write, we'll get an error
+ or jam the kernel. */
+ if (read == 0 && write == 0 && exec == 0)
+ {
+ if (info_verbose)
+ {
+ fprintf_filtered (gdb_stdout, "Ignore segment, %s bytes at 0x%s\n",
+ paddr_d (size), paddr_nz (vaddr));
+ }
+
+ return 0;
+ }
+
+ if (write == 0)
+ {
+ /* See if this region of memory lies inside a known file on disk.
+ If so, we can avoid copying its contents by clearing SEC_LOAD. */
+ struct objfile *objfile;
+ struct obj_section *objsec;
+
+ ALL_OBJSECTIONS (objfile, objsec)
+ {
+ bfd *abfd = objfile->obfd;
+ asection *asec = objsec->the_bfd_section;
+ bfd_vma align = (bfd_vma) 1 << bfd_get_section_alignment (abfd,
+ asec);
+ bfd_vma start = objsec->addr & -align;
+ bfd_vma end = (objsec->endaddr + align - 1) & -align;
+ /* Match if either the entire memory region lies inside the
+ section (i.e. a mapping covering some pages of a large
+ segment) or the entire section lies inside the memory region
+ (i.e. a mapping covering multiple small sections).
+
+ This BFD was synthesized from reading target memory,
+ we don't want to omit that. */
+ if (((vaddr >= start && vaddr + size <= end)
+ || (start >= vaddr && end <= vaddr + size))
+ && !(bfd_get_file_flags (abfd) & BFD_IN_MEMORY))
+ {
+ flags &= ~SEC_LOAD;
+ goto keep; /* break out of two nested for loops */
+ }
+ }
+
+ keep:
+ flags |= SEC_READONLY;
+ }
+
+ if (exec)
+ flags |= SEC_CODE;
+ else
+ flags |= SEC_DATA;
+
+ osec = bfd_make_section_anyway (obfd, "load");
+ if (osec == NULL)
+ {
+ warning ("Couldn't make gcore segment: %s",
+ bfd_errmsg (bfd_get_error ()));
+ return 1;
+ }
+
+ if (info_verbose)
+ {
+ fprintf_filtered (gdb_stdout, "Save segment, %s bytes at 0x%s\n",
+ paddr_d (size), paddr_nz (vaddr));
+ }
+
+ bfd_set_section_size (obfd, osec, size);
+ bfd_set_section_vma (obfd, osec, vaddr);
+ bfd_section_lma (obfd, osec) = 0; /* ??? bfd_set_section_lma? */
+ bfd_set_section_flags (obfd, osec, flags);
+ return 0;
+}
+
+static int
+objfile_find_memory_regions (int (*func) (CORE_ADDR, unsigned long,
+ int, int, int, void *),
+ void *obfd)
+{
+ /* Use objfile data to create memory sections. */
+ struct objfile *objfile;
+ struct obj_section *objsec;
+ bfd_vma temp_bottom, temp_top;
+
+ /* Call callback function for each objfile section. */
+ ALL_OBJSECTIONS (objfile, objsec)
+ {
+ bfd *ibfd = objfile->obfd;
+ asection *isec = objsec->the_bfd_section;
+ flagword flags = bfd_get_section_flags (ibfd, isec);
+ int ret;
+
+ if ((flags & SEC_ALLOC) || (flags & SEC_LOAD))
+ {
+ int size = bfd_section_size (ibfd, isec);
+ int ret;
+
+ ret = (*func) (objsec->addr, bfd_section_size (ibfd, isec),
+ 1, /* All sections will be readable. */
+ (flags & SEC_READONLY) == 0, /* Writable. */
+ (flags & SEC_CODE) != 0, /* Executable. */
+ obfd);
+ if (ret != 0)
+ return ret;
+ }
+ }
+
+ /* Make a stack segment. */
+ if (derive_stack_segment (&temp_bottom, &temp_top))
+ (*func) (temp_bottom, temp_top - temp_bottom,
+ 1, /* Stack section will be readable. */
+ 1, /* Stack section will be writable. */
+ 0, /* Stack section will not be executable. */
+ obfd);
+
+ /* Make a heap segment. */
+ if (derive_heap_segment (exec_bfd, &temp_bottom, &temp_top))
+ (*func) (temp_bottom, temp_top - temp_bottom,
+ 1, /* Heap section will be readable. */
+ 1, /* Heap section will be writable. */
+ 0, /* Heap section will not be executable. */
+ obfd);
+
+ return 0;
+}
+
+static void
+gcore_copy_callback (bfd *obfd, asection *osec, void *ignored)
+{
+ bfd_size_type size = bfd_section_size (obfd, osec);
+ struct cleanup *old_chain = NULL;
+ void *memhunk;
+
+ /* Read-only sections are marked; we don't have to copy their contents. */
+ if ((bfd_get_section_flags (obfd, osec) & SEC_LOAD) == 0)
+ return;
+
+ /* Only interested in "load" sections. */
+ if (strncmp ("load", bfd_section_name (obfd, osec), 4) != 0)
+ return;
+
+ memhunk = xmalloc (size);
+ /* ??? This is crap since xmalloc should never return NULL. */
+ if (memhunk == NULL)
+ error ("Not enough memory to create corefile.");
+ old_chain = make_cleanup (xfree, memhunk);
+
+ if (target_read_memory (bfd_section_vma (obfd, osec),
+ memhunk, size) != 0)
+ warning ("Memory read failed for corefile section, %s bytes at 0x%s\n",
+ paddr_d (size), paddr (bfd_section_vma (obfd, osec)));
+ if (!bfd_set_section_contents (obfd, osec, memhunk, 0, size))
+ warning ("Failed to write corefile contents (%s).",
+ bfd_errmsg (bfd_get_error ()));
+
+ do_cleanups (old_chain); /* Frees MEMHUNK. */
+}
+
+static int
+gcore_memory_sections (bfd *obfd)
+{
+ if (target_find_memory_regions (gcore_create_callback, obfd) != 0)
+ return 0; /* FIXME: error return/msg? */
+
+ /* Record phdrs for section-to-segment mapping. */
+ bfd_map_over_sections (obfd, make_output_phdrs, NULL);
+
+ /* Copy memory region contents. */
+ bfd_map_over_sections (obfd, gcore_copy_callback, NULL);
+
+ return 1;
+}
+
+void
+_initialize_gcore (void)
+{
+ add_com ("generate-core-file", class_files, gcore_command,
+ "\
+Save a core file with the current state of the debugged process.\n\
+Argument is optional filename. Default filename is 'core.<process_id>'.");
+
+ add_com_alias ("gcore", "generate-core-file", class_files, 1);
+ exec_set_find_memory_regions (objfile_find_memory_regions);
+}
diff --git a/contrib/gdb/gdb/gdb-events.c b/contrib/gdb/gdb/gdb-events.c
new file mode 100644
index 0000000..63ee3bc
--- /dev/null
+++ b/contrib/gdb/gdb/gdb-events.c
@@ -0,0 +1,444 @@
+/* User Interface Events.
+
+ Copyright 1999, 2001, 2002 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Work in progress */
+
+/* This file was created with the aid of ``gdb-events.sh''.
+
+ The bourn shell script ``gdb-events.sh'' creates the files
+ ``new-gdb-events.c'' and ``new-gdb-events.h and then compares
+ them against the existing ``gdb-events.[hc]''. Any differences
+ found being reported.
+
+ If editing this file, please also run gdb-events.sh and merge any
+ changes into that script. Conversely, when making sweeping changes
+ to this file, modifying gdb-events.sh and using its output may
+ prove easier. */
+
+
+#include "defs.h"
+#include "gdb-events.h"
+#include "gdbcmd.h"
+
+#if WITH_GDB_EVENTS
+static struct gdb_events null_event_hooks;
+static struct gdb_events queue_event_hooks;
+static struct gdb_events *current_event_hooks = &null_event_hooks;
+#endif
+
+int gdb_events_debug;
+
+#if WITH_GDB_EVENTS
+
+void
+breakpoint_create_event (int b)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "breakpoint_create_event\n");
+ if (!current_event_hooks->breakpoint_create)
+ return;
+ current_event_hooks->breakpoint_create (b);
+}
+
+void
+breakpoint_delete_event (int b)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "breakpoint_delete_event\n");
+ if (!current_event_hooks->breakpoint_delete)
+ return;
+ current_event_hooks->breakpoint_delete (b);
+}
+
+void
+breakpoint_modify_event (int b)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "breakpoint_modify_event\n");
+ if (!current_event_hooks->breakpoint_modify)
+ return;
+ current_event_hooks->breakpoint_modify (b);
+}
+
+void
+tracepoint_create_event (int number)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "tracepoint_create_event\n");
+ if (!current_event_hooks->tracepoint_create)
+ return;
+ current_event_hooks->tracepoint_create (number);
+}
+
+void
+tracepoint_delete_event (int number)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "tracepoint_delete_event\n");
+ if (!current_event_hooks->tracepoint_delete)
+ return;
+ current_event_hooks->tracepoint_delete (number);
+}
+
+void
+tracepoint_modify_event (int number)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "tracepoint_modify_event\n");
+ if (!current_event_hooks->tracepoint_modify)
+ return;
+ current_event_hooks->tracepoint_modify (number);
+}
+
+void
+architecture_changed_event (void)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "architecture_changed_event\n");
+ if (!current_event_hooks->architecture_changed)
+ return;
+ current_event_hooks->architecture_changed ();
+}
+
+void
+target_changed_event (void)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "target_changed_event\n");
+ if (!current_event_hooks->target_changed)
+ return;
+ current_event_hooks->target_changed ();
+}
+
+void
+selected_frame_level_changed_event (int level)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "selected_frame_level_changed_event\n");
+ if (!current_event_hooks->selected_frame_level_changed)
+ return;
+ current_event_hooks->selected_frame_level_changed (level);
+}
+
+void
+selected_thread_changed_event (int thread_num)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "selected_thread_changed_event\n");
+ if (!current_event_hooks->selected_thread_changed)
+ return;
+ current_event_hooks->selected_thread_changed (thread_num);
+}
+
+#endif
+
+#if WITH_GDB_EVENTS
+struct gdb_events *
+set_gdb_event_hooks (struct gdb_events *vector)
+{
+ struct gdb_events *old_events = current_event_hooks;
+ if (vector == NULL)
+ current_event_hooks = &queue_event_hooks;
+ else
+ current_event_hooks = vector;
+ return old_events;
+}
+#endif
+
+#if WITH_GDB_EVENTS
+void
+clear_gdb_event_hooks (void)
+{
+ set_gdb_event_hooks (&null_event_hooks);
+}
+#endif
+
+enum gdb_event
+{
+ breakpoint_create,
+ breakpoint_delete,
+ breakpoint_modify,
+ tracepoint_create,
+ tracepoint_delete,
+ tracepoint_modify,
+ architecture_changed,
+ target_changed,
+ selected_frame_level_changed,
+ selected_thread_changed,
+ nr_gdb_events
+};
+
+struct breakpoint_create
+ {
+ int b;
+ };
+
+struct breakpoint_delete
+ {
+ int b;
+ };
+
+struct breakpoint_modify
+ {
+ int b;
+ };
+
+struct tracepoint_create
+ {
+ int number;
+ };
+
+struct tracepoint_delete
+ {
+ int number;
+ };
+
+struct tracepoint_modify
+ {
+ int number;
+ };
+
+struct selected_frame_level_changed
+ {
+ int level;
+ };
+
+struct selected_thread_changed
+ {
+ int thread_num;
+ };
+
+struct event
+ {
+ enum gdb_event type;
+ struct event *next;
+ union
+ {
+ struct breakpoint_create breakpoint_create;
+ struct breakpoint_delete breakpoint_delete;
+ struct breakpoint_modify breakpoint_modify;
+ struct tracepoint_create tracepoint_create;
+ struct tracepoint_delete tracepoint_delete;
+ struct tracepoint_modify tracepoint_modify;
+ struct selected_frame_level_changed selected_frame_level_changed;
+ struct selected_thread_changed selected_thread_changed;
+ }
+ data;
+ };
+struct event *pending_events;
+struct event *delivering_events;
+
+static void
+append (struct event *new_event)
+{
+ struct event **event = &pending_events;
+ while ((*event) != NULL)
+ event = &((*event)->next);
+ (*event) = new_event;
+ (*event)->next = NULL;
+}
+
+static void
+queue_breakpoint_create (int b)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = breakpoint_create;
+ event->data.breakpoint_create.b = b;
+ append (event);
+}
+
+static void
+queue_breakpoint_delete (int b)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = breakpoint_delete;
+ event->data.breakpoint_delete.b = b;
+ append (event);
+}
+
+static void
+queue_breakpoint_modify (int b)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = breakpoint_modify;
+ event->data.breakpoint_modify.b = b;
+ append (event);
+}
+
+static void
+queue_tracepoint_create (int number)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = tracepoint_create;
+ event->data.tracepoint_create.number = number;
+ append (event);
+}
+
+static void
+queue_tracepoint_delete (int number)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = tracepoint_delete;
+ event->data.tracepoint_delete.number = number;
+ append (event);
+}
+
+static void
+queue_tracepoint_modify (int number)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = tracepoint_modify;
+ event->data.tracepoint_modify.number = number;
+ append (event);
+}
+
+static void
+queue_architecture_changed (void)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = architecture_changed;
+ append (event);
+}
+
+static void
+queue_target_changed (void)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = target_changed;
+ append (event);
+}
+
+static void
+queue_selected_frame_level_changed (int level)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = selected_frame_level_changed;
+ event->data.selected_frame_level_changed.level = level;
+ append (event);
+}
+
+static void
+queue_selected_thread_changed (int thread_num)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = selected_thread_changed;
+ event->data.selected_thread_changed.thread_num = thread_num;
+ append (event);
+}
+
+void
+gdb_events_deliver (struct gdb_events *vector)
+{
+ /* Just zap any events left around from last time. */
+ while (delivering_events != NULL)
+ {
+ struct event *event = delivering_events;
+ delivering_events = event->next;
+ xfree (event);
+ }
+ /* Process any pending events. Because one of the deliveries could
+ bail out we move everything off of the pending queue onto an
+ in-progress queue where it can, later, be cleaned up if
+ necessary. */
+ delivering_events = pending_events;
+ pending_events = NULL;
+ while (delivering_events != NULL)
+ {
+ struct event *event = delivering_events;
+ switch (event->type)
+ {
+ case breakpoint_create:
+ vector->breakpoint_create
+ (event->data.breakpoint_create.b);
+ break;
+ case breakpoint_delete:
+ vector->breakpoint_delete
+ (event->data.breakpoint_delete.b);
+ break;
+ case breakpoint_modify:
+ vector->breakpoint_modify
+ (event->data.breakpoint_modify.b);
+ break;
+ case tracepoint_create:
+ vector->tracepoint_create
+ (event->data.tracepoint_create.number);
+ break;
+ case tracepoint_delete:
+ vector->tracepoint_delete
+ (event->data.tracepoint_delete.number);
+ break;
+ case tracepoint_modify:
+ vector->tracepoint_modify
+ (event->data.tracepoint_modify.number);
+ break;
+ case architecture_changed:
+ vector->architecture_changed ();
+ break;
+ case target_changed:
+ vector->target_changed ();
+ break;
+ case selected_frame_level_changed:
+ vector->selected_frame_level_changed
+ (event->data.selected_frame_level_changed.level);
+ break;
+ case selected_thread_changed:
+ vector->selected_thread_changed
+ (event->data.selected_thread_changed.thread_num);
+ break;
+ }
+ delivering_events = event->next;
+ xfree (event);
+ }
+}
+
+void _initialize_gdb_events (void);
+void
+_initialize_gdb_events (void)
+{
+ struct cmd_list_element *c;
+#if WITH_GDB_EVENTS
+ queue_event_hooks.breakpoint_create = queue_breakpoint_create;
+ queue_event_hooks.breakpoint_delete = queue_breakpoint_delete;
+ queue_event_hooks.breakpoint_modify = queue_breakpoint_modify;
+ queue_event_hooks.tracepoint_create = queue_tracepoint_create;
+ queue_event_hooks.tracepoint_delete = queue_tracepoint_delete;
+ queue_event_hooks.tracepoint_modify = queue_tracepoint_modify;
+ queue_event_hooks.architecture_changed = queue_architecture_changed;
+ queue_event_hooks.target_changed = queue_target_changed;
+ queue_event_hooks.selected_frame_level_changed = queue_selected_frame_level_changed;
+ queue_event_hooks.selected_thread_changed = queue_selected_thread_changed;
+#endif
+
+ c = add_set_cmd ("eventdebug", class_maintenance, var_zinteger,
+ (char *) (&gdb_events_debug), "Set event debugging.\n\
+When non-zero, event/notify debugging is enabled.", &setlist);
+ deprecate_cmd (c, "set debug event");
+ deprecate_cmd (add_show_from_set (c, &showlist), "show debug event");
+
+ add_show_from_set (add_set_cmd ("event",
+ class_maintenance,
+ var_zinteger,
+ (char *) (&gdb_events_debug),
+ "Set event debugging.\n\
+When non-zero, event/notify debugging is enabled.", &setdebuglist),
+ &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/gdb-events.h b/contrib/gdb/gdb/gdb-events.h
new file mode 100644
index 0000000..2ce193f
--- /dev/null
+++ b/contrib/gdb/gdb/gdb-events.h
@@ -0,0 +1,129 @@
+/* User Interface Events.
+
+ Copyright 1999, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Work in progress */
+
+/* This file was created with the aid of ``gdb-events.sh''.
+
+ The bourn shell script ``gdb-events.sh'' creates the files
+ ``new-gdb-events.c'' and ``new-gdb-events.h and then compares
+ them against the existing ``gdb-events.[hc]''. Any differences
+ found being reported.
+
+ If editing this file, please also run gdb-events.sh and merge any
+ changes into that script. Conversely, when making sweeping changes
+ to this file, modifying gdb-events.sh and using its output may
+ prove easier. */
+
+
+#ifndef GDB_EVENTS_H
+#define GDB_EVENTS_H
+
+#ifndef WITH_GDB_EVENTS
+#define WITH_GDB_EVENTS 1
+#endif
+
+
+/* COMPAT: pointer variables for old, unconverted events.
+ A call to set_gdb_events() will automatically update these. */
+
+
+
+/* Type definition of all hook functions.
+ Recommended pratice is to first declare each hook function using
+ the below ftype and then define it. */
+
+typedef void (gdb_events_breakpoint_create_ftype) (int b);
+typedef void (gdb_events_breakpoint_delete_ftype) (int b);
+typedef void (gdb_events_breakpoint_modify_ftype) (int b);
+typedef void (gdb_events_tracepoint_create_ftype) (int number);
+typedef void (gdb_events_tracepoint_delete_ftype) (int number);
+typedef void (gdb_events_tracepoint_modify_ftype) (int number);
+typedef void (gdb_events_architecture_changed_ftype) (void);
+typedef void (gdb_events_target_changed_ftype) (void);
+typedef void (gdb_events_selected_frame_level_changed_ftype) (int level);
+typedef void (gdb_events_selected_thread_changed_ftype) (int thread_num);
+
+
+/* gdb-events: object. */
+
+struct gdb_events
+ {
+ gdb_events_breakpoint_create_ftype *breakpoint_create;
+ gdb_events_breakpoint_delete_ftype *breakpoint_delete;
+ gdb_events_breakpoint_modify_ftype *breakpoint_modify;
+ gdb_events_tracepoint_create_ftype *tracepoint_create;
+ gdb_events_tracepoint_delete_ftype *tracepoint_delete;
+ gdb_events_tracepoint_modify_ftype *tracepoint_modify;
+ gdb_events_architecture_changed_ftype *architecture_changed;
+ gdb_events_target_changed_ftype *target_changed;
+ gdb_events_selected_frame_level_changed_ftype *selected_frame_level_changed;
+ gdb_events_selected_thread_changed_ftype *selected_thread_changed;
+ };
+
+
+/* Interface into events functions.
+ Where a *_p() predicate is present, it must be called before
+ calling the hook proper. */
+extern void breakpoint_create_event (int b);
+extern void breakpoint_delete_event (int b);
+extern void breakpoint_modify_event (int b);
+extern void tracepoint_create_event (int number);
+extern void tracepoint_delete_event (int number);
+extern void tracepoint_modify_event (int number);
+extern void architecture_changed_event (void);
+extern void target_changed_event (void);
+extern void selected_frame_level_changed_event (int level);
+extern void selected_thread_changed_event (int thread_num);
+
+
+/* When GDB_EVENTS are not being used, completely disable them. */
+
+#if !WITH_GDB_EVENTS
+#define breakpoint_create_event(b) 0
+#define breakpoint_delete_event(b) 0
+#define breakpoint_modify_event(b) 0
+#define tracepoint_create_event(number) 0
+#define tracepoint_delete_event(number) 0
+#define tracepoint_modify_event(number) 0
+#define architecture_changed_event() 0
+#define target_changed_event() 0
+#define selected_frame_level_changed_event(level) 0
+#define selected_thread_changed_event(thread_num) 0
+#endif
+
+/* Install custom gdb-events hooks. */
+extern struct gdb_events *set_gdb_event_hooks (struct gdb_events *vector);
+
+/* Deliver any pending events. */
+extern void gdb_events_deliver (struct gdb_events *vector);
+
+/* Clear event handlers */
+extern void clear_gdb_event_hooks (void);
+
+#if !WITH_GDB_EVENTS
+#define set_gdb_events(x) 0
+#define set_gdb_event_hooks(x) 0
+#define gdb_events_deliver(x) 0
+#endif
+
+#endif
diff --git a/contrib/gdb/gdb/gdb-events.sh b/contrib/gdb/gdb/gdb-events.sh
new file mode 100755
index 0000000..bd07794
--- /dev/null
+++ b/contrib/gdb/gdb/gdb-events.sh
@@ -0,0 +1,620 @@
+#!/bin/sh
+
+# User Interface Events.
+# Copyright 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+#
+# Contributed by Cygnus Solutions.
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#
+# What happens next:
+#
+
+# The gdb-events.h/gdb-events.c files this script generates are commited
+# and published.
+
+# Any UI module that is installing events is changed so that the
+# events are installed using the ``set_gdb_events()'' and
+# ``gdb_event_hooks()'' interfaces. There could prove to be an issue
+# here with respect to annotate. We might need to accomodate a hook
+# stack that allows several ui blocks to install their own events.
+
+# Each of the variable events (as currently generated) is converted
+# to either a straight function call or a function call with a
+# predicate.
+
+
+IFS=:
+
+read="class returntype function formal actual attrib"
+
+function_list ()
+{
+ # category:
+ # # -> disable
+ # * -> compatibility - pointer variable that is initialized
+ # by set_gdb_events().
+ # ? -> Predicate and function proper.
+ # f -> always call (must have a void returntype)
+ # return-type
+ # name
+ # formal argument list
+ # actual argument list
+ # attributes
+ # description
+ cat <<EOF |
+f:void:breakpoint_create:int b:b
+f:void:breakpoint_delete:int b:b
+f:void:breakpoint_modify:int b:b
+f:void:tracepoint_create:int number:number
+f:void:tracepoint_delete:int number:number
+f:void:tracepoint_modify:int number:number
+f:void:architecture_changed:void
+f:void:target_changed:void
+f:void:selected_frame_level_changed:int level:level
+f:void:selected_thread_changed:int thread_num:thread_num
+#*:void:annotate_starting_hook:void
+#*:void:annotate_stopped_hook:void
+#*:void:annotate_signalled_hook:void
+#*:void:annotate_signal_hook:void
+#*:void:annotate_exited_hook:void
+##*:void:print_register_hook:int
+##*:CORE_ADDR:find_toc_address_hook:CORE_ADDR
+##*:void:sparc_print_register_hook:int regno:regno
+#*:void:target_resume_hook:void
+#*:void:target_wait_loop_hook:void
+#*:void:init_gdb_hook:char *argv0:argv0
+#*:void:command_loop_hook:void
+#*:void:fputs_unfiltered_hook:const char *linebuff,struct ui_file *stream:linebuff, stream
+#*:void:print_frame_info_listing_hook:struct symtab *s, int line, int stopline, int noerror:s, line, stopline, noerror
+#*:int:query_hook:const char *query, va_list args:query, args
+#*:void:warning_hook:const char *string, va_list args:string, args
+#*:void:target_output_hook:char *b:b
+#*:void:interactive_hook:void
+#*:void:registers_changed_hook:void
+#*:void:readline_begin_hook:char *format, ...:format
+#*:char *:readline_hook:char *prompt:prompt
+#*:void:readline_end_hook:void
+#*:int:target_wait_hook:int pid, struct target_waitstatus *status:pid, status
+#*:void:call_command_hook:struct cmd_list_element *c, char *cmd, int from_tty:c, cmd, from_tty
+#*:NORETURN void:error_hook:void:: ATTR_NORETURN
+#*:void:error_begin_hook:void
+##*:int:target_architecture_hook:const struct bfd_arch_info *
+#*:void:exec_file_display_hook:char *filename:filename
+#*:void:file_changed_hook:char *filename:filename
+##*:void:specify_exec_file_hook:
+#*:int:gdb_load_progress_hook:char *section, unsigned long num:section, num
+#*:void:pre_add_symbol_hook:char *name:name
+#*:void:post_add_symbol_hook:void
+#*:void:selected_frame_level_changed_hook:int level:level
+#*:int:gdb_loop_hook:int signo:signo
+##*:void:solib_create_inferior_hook:void
+##*:void:xcoff_relocate_symtab_hook:unsigned int
+EOF
+ grep -v '^#'
+}
+
+copyright ()
+{
+ cat <<EOF
+/* User Interface Events.
+
+ Copyright 1999, 2001, 2002 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Work in progress */
+
+/* This file was created with the aid of \`\`gdb-events.sh''.
+
+ The bourn shell script \`\`gdb-events.sh'' creates the files
+ \`\`new-gdb-events.c'' and \`\`new-gdb-events.h and then compares
+ them against the existing \`\`gdb-events.[hc]''. Any differences
+ found being reported.
+
+ If editing this file, please also run gdb-events.sh and merge any
+ changes into that script. Conversely, when making sweeping changes
+ to this file, modifying gdb-events.sh and using its output may
+ prove easier. */
+
+EOF
+}
+
+#
+# The .h file
+#
+
+exec > new-gdb-events.h
+copyright
+cat <<EOF
+
+#ifndef GDB_EVENTS_H
+#define GDB_EVENTS_H
+
+#ifndef WITH_GDB_EVENTS
+#define WITH_GDB_EVENTS 1
+#endif
+EOF
+
+# pointer declarations
+echo ""
+echo ""
+cat <<EOF
+/* COMPAT: pointer variables for old, unconverted events.
+ A call to set_gdb_events() will automatically update these. */
+EOF
+echo ""
+function_list | while eval read $read
+do
+ case "${class}" in
+ "*" )
+ echo "extern ${returntype} (*${function}_event) (${formal})${attrib};"
+ ;;
+ esac
+done
+
+# function typedef's
+echo ""
+echo ""
+cat <<EOF
+/* Type definition of all hook functions.
+ Recommended pratice is to first declare each hook function using
+ the below ftype and then define it. */
+EOF
+echo ""
+function_list | while eval read $read
+do
+ echo "typedef ${returntype} (gdb_events_${function}_ftype) (${formal});"
+done
+
+# gdb_events object
+echo ""
+echo ""
+cat <<EOF
+/* gdb-events: object. */
+EOF
+echo ""
+echo "struct gdb_events"
+echo " {"
+function_list | while eval read $read
+do
+ echo " gdb_events_${function}_ftype *${function}${attrib};"
+done
+echo " };"
+
+# function declarations
+echo ""
+echo ""
+cat <<EOF
+/* Interface into events functions.
+ Where a *_p() predicate is present, it must be called before
+ calling the hook proper. */
+EOF
+function_list | while eval read $read
+do
+ case "${class}" in
+ "*" ) continue ;;
+ "?" )
+ echo "extern int ${function}_p (void);"
+ echo "extern ${returntype} ${function}_event (${formal})${attrib};"
+ ;;
+ "f" )
+ echo "extern ${returntype} ${function}_event (${formal})${attrib};"
+ ;;
+ esac
+done
+
+# function macros
+echo ""
+echo ""
+cat <<EOF
+/* When GDB_EVENTS are not being used, completely disable them. */
+EOF
+echo ""
+echo "#if !WITH_GDB_EVENTS"
+function_list | while eval read $read
+do
+ case "${class}" in
+ "*" ) continue ;;
+ "?" )
+ echo "#define ${function}_event_p() 0"
+ echo "#define ${function}_event(${actual}) 0"
+ ;;
+ "f" )
+ echo "#define ${function}_event(${actual}) 0"
+ ;;
+ esac
+done
+echo "#endif"
+
+# our set function
+cat <<EOF
+
+/* Install custom gdb-events hooks. */
+extern struct gdb_events *set_gdb_event_hooks (struct gdb_events *vector);
+
+/* Deliver any pending events. */
+extern void gdb_events_deliver (struct gdb_events *vector);
+
+/* Clear event handlers */
+extern void clear_gdb_event_hooks (void);
+
+#if !WITH_GDB_EVENTS
+#define set_gdb_events(x) 0
+#define set_gdb_event_hooks(x) 0
+#define gdb_events_deliver(x) 0
+#endif
+EOF
+
+# close it off
+echo ""
+echo "#endif"
+exec 1>&2
+#../move-if-change new-gdb-events.h gdb-events.h
+if test -r gdb-events.h
+then
+ diff -c gdb-events.h new-gdb-events.h
+ if [ $? = 1 ]
+ then
+ echo "gdb-events.h changed? cp new-gdb-events.h gdb-events.h" 1>&2
+ fi
+else
+ echo "File missing? mv new-gdb-events.h gdb-events.h" 1>&2
+fi
+
+
+
+#
+# C file
+#
+
+exec > new-gdb-events.c
+copyright
+cat <<EOF
+
+#include "defs.h"
+#include "gdb-events.h"
+#include "gdbcmd.h"
+
+#if WITH_GDB_EVENTS
+static struct gdb_events null_event_hooks;
+static struct gdb_events queue_event_hooks;
+static struct gdb_events *current_event_hooks = &null_event_hooks;
+#endif
+
+int gdb_events_debug;
+EOF
+
+# global pointer variables - always have this
+#echo ""
+#function_list | while eval read $read
+#do
+# case "${class}" in
+# "*" )
+# echo "${returntype} (*${function}_event) (${formal})${attrib} = 0;"
+# ;;
+# esac
+#done
+
+# function bodies
+echo ""
+echo "#if WITH_GDB_EVENTS"
+function_list | while eval read $read
+do
+ case "${class}" in
+ "*" ) continue ;;
+ "?" )
+cat <<EOF
+
+int
+${function}_event_p (${formal})
+{
+ return current_event_hooks->${function};
+}
+
+${returntype}
+${function}_event (${formal})
+{
+ return current_events->${function} (${actual});
+}
+EOF
+ ;;
+ "f" )
+cat <<EOF
+
+void
+${function}_event (${formal})
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "${function}_event\n");
+ if (!current_event_hooks->${function})
+ return;
+ current_event_hooks->${function} (${actual});
+}
+EOF
+ ;;
+ esac
+done
+echo ""
+echo "#endif"
+
+# Set hooks function
+echo ""
+cat <<EOF
+#if WITH_GDB_EVENTS
+struct gdb_events *
+set_gdb_event_hooks (struct gdb_events *vector)
+{
+ struct gdb_events *old_events = current_event_hooks;
+ if (vector == NULL)
+ current_event_hooks = &queue_event_hooks;
+ else
+ current_event_hooks = vector;
+ return old_events;
+EOF
+function_list | while eval read $read
+do
+ case "${class}" in
+ "*" )
+ echo " ${function}_event = hooks->${function};"
+ ;;
+ esac
+done
+cat <<EOF
+}
+#endif
+EOF
+
+# Clear hooks function
+echo ""
+cat <<EOF
+#if WITH_GDB_EVENTS
+void
+clear_gdb_event_hooks (void)
+{
+ set_gdb_event_hooks (&null_event_hooks);
+}
+#endif
+EOF
+
+# event type
+echo ""
+cat <<EOF
+enum gdb_event
+{
+EOF
+function_list | while eval read $read
+do
+ case "${class}" in
+ "f" )
+ echo " ${function},"
+ ;;
+ esac
+done
+cat <<EOF
+ nr_gdb_events
+};
+EOF
+
+# event data
+echo ""
+function_list | while eval read $read
+do
+ case "${class}" in
+ "f" )
+ if test ${actual}
+ then
+ echo "struct ${function}"
+ echo " {"
+ echo " `echo ${formal} | tr '[,]' '[;]'`;"
+ echo " };"
+ echo ""
+ fi
+ ;;
+ esac
+done
+
+# event queue
+cat <<EOF
+struct event
+ {
+ enum gdb_event type;
+ struct event *next;
+ union
+ {
+EOF
+function_list | while eval read $read
+do
+ case "${class}" in
+ "f" )
+ if test ${actual}
+ then
+ echo " struct ${function} ${function};"
+ fi
+ ;;
+ esac
+done
+cat <<EOF
+ }
+ data;
+ };
+struct event *pending_events;
+struct event *delivering_events;
+EOF
+
+# append
+echo ""
+cat <<EOF
+static void
+append (struct event *new_event)
+{
+ struct event **event = &pending_events;
+ while ((*event) != NULL)
+ event = &((*event)->next);
+ (*event) = new_event;
+ (*event)->next = NULL;
+}
+EOF
+
+# schedule a given event
+function_list | while eval read $read
+do
+ case "${class}" in
+ "f" )
+ echo ""
+ echo "static void"
+ echo "queue_${function} (${formal})"
+ echo "{"
+ echo " struct event *event = XMALLOC (struct event);"
+ echo " event->type = ${function};"
+ for arg in `echo ${actual} | tr '[,]' '[:]' | tr -d '[ ]'`; do
+ echo " event->data.${function}.${arg} = ${arg};"
+ done
+ echo " append (event);"
+ echo "}"
+ ;;
+ esac
+done
+
+# deliver
+echo ""
+cat <<EOF
+void
+gdb_events_deliver (struct gdb_events *vector)
+{
+ /* Just zap any events left around from last time. */
+ while (delivering_events != NULL)
+ {
+ struct event *event = delivering_events;
+ delivering_events = event->next;
+ xfree (event);
+ }
+ /* Process any pending events. Because one of the deliveries could
+ bail out we move everything off of the pending queue onto an
+ in-progress queue where it can, later, be cleaned up if
+ necessary. */
+ delivering_events = pending_events;
+ pending_events = NULL;
+ while (delivering_events != NULL)
+ {
+ struct event *event = delivering_events;
+ switch (event->type)
+ {
+EOF
+function_list | while eval read $read
+do
+ case "${class}" in
+ "f" )
+ echo " case ${function}:"
+ if test ${actual}
+ then
+ echo " vector->${function}"
+ sep=" ("
+ ass=""
+ for arg in `echo ${actual} | tr '[,]' '[:]' | tr -d '[ ]'`; do
+ ass="${ass}${sep}event->data.${function}.${arg}"
+ sep=",
+ "
+ done
+ echo "${ass});"
+ else
+ echo " vector->${function} ();"
+ fi
+ echo " break;"
+ ;;
+ esac
+done
+cat <<EOF
+ }
+ delivering_events = event->next;
+ xfree (event);
+ }
+}
+EOF
+
+# Finally the initialization
+echo ""
+cat <<EOF
+void _initialize_gdb_events (void);
+void
+_initialize_gdb_events (void)
+{
+ struct cmd_list_element *c;
+#if WITH_GDB_EVENTS
+EOF
+function_list | while eval read $read
+do
+ case "${class}" in
+ "f" )
+ echo " queue_event_hooks.${function} = queue_${function};"
+ ;;
+ esac
+done
+cat <<EOF
+#endif
+
+ c = add_set_cmd ("eventdebug", class_maintenance, var_zinteger,
+ (char *) (&gdb_events_debug), "Set event debugging.\n\\
+When non-zero, event/notify debugging is enabled.", &setlist);
+ deprecate_cmd (c, "set debug event");
+ deprecate_cmd (add_show_from_set (c, &showlist), "show debug event");
+
+ add_show_from_set (add_set_cmd ("event",
+ class_maintenance,
+ var_zinteger,
+ (char *) (&gdb_events_debug),
+ "Set event debugging.\n\\
+When non-zero, event/notify debugging is enabled.", &setdebuglist),
+ &showdebuglist);
+}
+EOF
+
+# close things off
+exec 1>&2
+#../move-if-change new-gdb-events.c gdb-events.c
+# Replace any leading spaces with tabs
+sed < new-gdb-events.c > tmp-gdb-events.c \
+ -e 's/\( \)* /\1 /g'
+mv tmp-gdb-events.c new-gdb-events.c
+# Move if changed?
+if test -r gdb-events.c
+then
+ diff -c gdb-events.c new-gdb-events.c
+ if [ $? = 1 ]
+ then
+ echo "gdb-events.c changed? cp new-gdb-events.c gdb-events.c" 1>&2
+ fi
+else
+ echo "File missing? mv new-gdb-events.c gdb-events.c" 1>&2
+fi
diff --git a/contrib/gdb/gdb/gdb-stabs.h b/contrib/gdb/gdb/gdb-stabs.h
new file mode 100644
index 0000000..097f9d9
--- /dev/null
+++ b/contrib/gdb/gdb/gdb-stabs.h
@@ -0,0 +1,90 @@
+/* Definitions for symbol-reading containing "stabs", for GDB.
+ Copyright 1992, 1993, 1995, 1996, 1997, 1999, 2000
+ 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
+
+/* 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;
+ struct stab_section_info *next;
+ int found; /* Count of times it's found in searching */
+ size_t num_sections;
+ CORE_ADDR sections[1];
+ };
+
+/* 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. */
+
+ /* See stabsread.h for the use of the following. */
+ struct header_file *header_files;
+ int n_header_files;
+ int n_allocated_header_files;
+
+ /* Pointers to BFD sections. These are used to speed up the building of
+ minimal symbols. */
+ asection *text_section;
+ asection *data_section;
+ asection *bss_section;
+
+ /* Pointer to the separate ".stab" section, if there is one. */
+ asection *stab_section;
+ };
+
+#define DBX_SYMFILE_INFO(o) ((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)
+#define DBX_TEXT_SECTION(o) (DBX_SYMFILE_INFO(o)->text_section)
+#define DBX_DATA_SECTION(o) (DBX_SYMFILE_INFO(o)->data_section)
+#define DBX_BSS_SECTION(o) (DBX_SYMFILE_INFO(o)->bss_section)
+#define DBX_STAB_SECTION(o) (DBX_SYMFILE_INFO(o)->stab_section)
+
+#endif /* GDBSTABS_H */
diff --git a/contrib/gdb/gdb/gdb.1 b/contrib/gdb/gdb/gdb.1
new file mode 100644
index 0000000..dbe3178
--- /dev/null
+++ b/contrib/gdb/gdb/gdb.1
@@ -0,0 +1,381 @@
+.\" Copyright 1991, 1999 Free Software Foundation, Inc.
+.\" See section COPYING for conditions for redistribution
+.\" $Id: gdb.1,v 1.4 1999/01/05 00:50:50 jsm Exp $
+.TH gdb 1 "22may2002" "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 edit \fR[\|\fIfile\fB:\fR\|]\fIfunction
+look at the program line where it is presently stopped.
+.TP
+.B list \fR[\|\fIfile\fB:\fR\|]\fIfunction
+type the text of the program in the vicinity of where it is presently stopped.
+.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
+.B \-write
+Enable writing into executable and core files.
+
+.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.c b/contrib/gdb/gdb/gdb.c
new file mode 100644
index 0000000..b6eae2b
--- /dev/null
+++ b/contrib/gdb/gdb/gdb.c
@@ -0,0 +1,36 @@
+/* Main function for CLI gdb.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "main.h"
+#include "gdb_string.h"
+#include "interps.h"
+
+int
+main (int argc, char **argv)
+{
+ struct captured_main_args args;
+ memset (&args, 0, sizeof args);
+ args.argc = argc;
+ args.argv = argv;
+ args.use_windows = 0;
+ args.interpreter_p = INTERP_CONSOLE;
+ return gdb_main (&args);
+}
diff --git a/contrib/gdb/gdb/gdb.gdb b/contrib/gdb/gdb/gdb.gdb
new file mode 100644
index 0000000..4377841
--- /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.h b/contrib/gdb/gdb/gdb.h
new file mode 100644
index 0000000..6a2eaa0
--- /dev/null
+++ b/contrib/gdb/gdb/gdb.h
@@ -0,0 +1,62 @@
+/* Library interface into GDB.
+ Copyright 1999, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_H
+#define GDB_H
+
+struct ui_out;
+
+/* Return-code (RC) from a gdb library call. (The abreviation RC is
+ taken from the sim/common directory.) */
+
+enum gdb_rc {
+ /* The operation failed. The failure message can be fetched by
+ calling ``char *error_last_message(void)''. The value is
+ determined by the catch_errors() interface. */
+ /* NOTE: Since ``defs.h:catch_errors()'' does not return an error /
+ internal / quit indication it is not possible to return that
+ here. */
+ GDB_RC_FAIL = 0,
+ /* No error occured but nothing happened. Due to the catch_errors()
+ interface, this must be non-zero. */
+ GDB_RC_NONE = 1,
+ /* The operation was successful. Due to the catch_errors()
+ interface, this must be non-zero. */
+ GDB_RC_OK = 2
+};
+
+
+/* Print the specified breakpoint on GDB_STDOUT. (Eventually this
+ function will ``print'' the object on ``output''). */
+enum gdb_rc gdb_breakpoint_query (struct ui_out *uiout, int bnum);
+
+/* Create a breakpoint at ADDRESS (a GDB source and line). */
+enum gdb_rc gdb_breakpoint (char *address, char *condition,
+ int hardwareflag, int tempflag,
+ int thread, int ignore_count);
+
+/* Switch thread and print notification. */
+enum gdb_rc gdb_thread_select (struct ui_out *uiout, char *tidstr);
+
+/* Print a list of known thread ids. */
+enum gdb_rc gdb_list_thread_ids (struct ui_out *uiout);
+
+#endif
diff --git a/contrib/gdb/gdb/gdb_assert.h b/contrib/gdb/gdb/gdb_assert.h
new file mode 100644
index 0000000..9cad74c
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_assert.h
@@ -0,0 +1,58 @@
+/* GDB-friendly replacement for <assert.h>.
+ Copyright 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_ASSERT_H
+#define GDB_ASSERT_H
+
+/* PRAGMATICS: "gdb_assert.h":gdb_assert() is a lower case (rather
+ than upper case) macro since that provides the closest fit to the
+ existing lower case macro <assert.h>:assert() that it is
+ replacing. */
+
+#define gdb_assert(expr) \
+ ((void) ((expr) ? 0 : \
+ (gdb_assert_fail (#expr, __FILE__, __LINE__, ASSERT_FUNCTION), 0)))
+
+/* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__'
+ which contains the name of the function currently being defined.
+ This is broken in G++ before version 2.6.
+ C9x has a similar variable called __func__, but prefer the GCC one since
+ it demangles C++ function names. */
+#if (GCC_VERSION >= 2004)
+#define ASSERT_FUNCTION __PRETTY_FUNCTION__
+#else
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#define ASSERT_FUNCTION __func__
+#endif
+#endif
+
+/* This prints an "Assertion failed" message, aksing the user if they
+ want to continue, dump core, or just exit. */
+#if defined (ASSERT_FUNCTION)
+#define gdb_assert_fail(assertion, file, line, function) \
+ internal_error (file, line, "%s: Assertion `%s' failed.", \
+ function, assertion)
+#else
+#define gdb_assert_fail(assertion, file, line, function) \
+ internal_error (file, line, "Assertion `%s' failed.", \
+ assertion)
+#endif
+
+#endif /* gdb_assert.h */
diff --git a/contrib/gdb/gdb/gdb_curses.h b/contrib/gdb/gdb/gdb_curses.h
new file mode 100644
index 0000000..074313e
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_curses.h
@@ -0,0 +1,31 @@
+/* Portable <curses.h>.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_CURSES_H
+#define GDB_CURSES_H 1
+
+#if defined (HAVE_NCURSES_H)
+#include <ncurses.h>
+#elif defined (HAVE_CURSES_H)
+#include <curses.h>
+#endif
+
+#endif
diff --git a/contrib/gdb/gdb/gdb_dirent.h b/contrib/gdb/gdb/gdb_dirent.h
new file mode 100644
index 0000000..ba28ca5
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_dirent.h
@@ -0,0 +1,42 @@
+/* Portable <dirent.h>.
+ Copyright 2000, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_DIRENT_H
+#define GDB_DIRENT_H 1
+
+/* See description of `AC_HEADER_DIRENT' in the Autoconf manual. */
+#ifdef HAVE_DIRENT_H
+# include <dirent.h> /* OK: dirent.h */
+# define NAMELEN(dirent) strlen ((dirent)->d_name) /* OK: strlen d_name */
+#else
+# define dirent direct
+# define NAMELEN(dirent) (dirent)->d_namelen /* OK: d_namelen */
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#endif /* not GDB_DIRENT_H */
diff --git a/contrib/gdb/gdb/gdb_gcore.sh b/contrib/gdb/gdb/gdb_gcore.sh
new file mode 100755
index 0000000..9b42808
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_gcore.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+# Copyright 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+#
+# gcore.sh
+# Script to generate a core file of a running program.
+# It starts up gdb, attaches to the given PID and invokes the gcore command.
+#
+
+if [ "$#" -eq "0" ]
+then
+ echo "usage: gcore [-o filename] pid"
+ exit 2
+fi
+
+# Need to check for -o option, but set default basename to "core".
+name=core
+
+if [ "$1" = "-o" ]
+then
+ if [ "$#" -lt "3" ]
+ then
+ # Not enough arguments.
+ echo "usage: gcore [-o filename] pid"
+ exit 2
+ fi
+ name=$2
+
+ # Shift over to start of pid list
+ shift; shift
+fi
+
+# Initialise return code.
+rc=0
+
+# Loop through pids
+for pid in $*
+do
+ # Write gdb script for pid $pid.
+
+ # Avoid need for temporary files by using funky "here
+ # document" feature of sh.
+
+ /usr/bin/gdb > /dev/null << EOF
+ attach $pid
+ gcore $name.$pid
+ detach
+ quit
+EOF
+
+ if [ -r $name.$pid ] ; then
+ rc=0
+ else
+ echo gcore: failed to create $name.$pid
+ rc=1
+ break
+ fi
+
+
+done
+
+exit $rc
+
diff --git a/contrib/gdb/gdb/gdb_indent.sh b/contrib/gdb/gdb/gdb_indent.sh
new file mode 100755
index 0000000..b210161
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_indent.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+# Try to find a GNU indent. There could be a BSD indent in front of a
+# GNU gindent so when indent is found, keep looking.
+
+gindent=
+indent=
+paths=`echo $PATH | sed \
+ -e 's/::/:.:/g' \
+ -e 's/^:/.:/' \
+ -e 's/:$/:./' \
+ -e 's/:/ /g'`
+for path in $paths
+do
+ if test ! -n "${gindent}" -a -x ${path}/gindent
+ then
+ gindent=${path}/gindent
+ break
+ elif test ! -n "${indent}" -a -x ${path}/indent
+ then
+ indent=${path}/indent
+ fi
+done
+
+if test -n "${gindent}"
+then
+ indent=${gindent}
+elif test -n "${indent}"
+then
+ :
+else
+ echo "Indent not found" 1>&2
+fi
+
+
+# Check that the indent found is both GNU and a reasonable version.
+# Different indent versions give different indentation.
+
+m1=2
+m2=2
+m3=9
+
+version=`${indent} --version 2>/dev/null < /dev/null`
+case "${version}" in
+ *GNU* ) ;;
+ * ) echo "error: GNU indent $m1.$m2.$m3 expected" 1>&2 ; exit 1;;
+esac
+v1=`echo "${version}" | sed 's/^.* \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$/\1/'`
+v2=`echo "${version}" | sed 's/^.* \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$/\2/'`
+v3=`echo "${version}" | sed 's/^.* \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$/\3/'`
+
+if test $m1 -ne $v1 -o $m2 -ne $v2 -o $m3 -gt $v3
+then
+ echo "error: Must be GNU indent version $m1.$m2.$m3 or later" 1>&2
+ exit 1
+fi
+
+if test $m3 -ne $v3
+then
+ echo "warning: GNU indent version $m1.$m2.$m3 recommended" 1>&2
+fi
+
+# Check that we're in the GDB source directory
+
+case `pwd` in
+ */gdb ) ;;
+ */sim/* ) ;;
+ * ) echo "Not in GDB directory" 1>&2 ; exit 1 ;;
+esac
+
+
+# Run indent per GDB specs
+
+types="\
+-T FILE \
+-T bfd -T asection -T pid_t \
+-T prgregset_t -T fpregset_t -T gregset_t -T sigset_t \
+-T td_thrhandle_t -T td_event_msg_t -T td_thr_events_t \
+-T td_notify_t -T td_thr_iter_f -T td_thrinfo_t \
+`cat *.h | sed -n \
+ -e 's/^.*[^a-z0-9_]\([a-z0-9_]*_ftype\).*$/-T \1/p' \
+ -e 's/^.*[^a-z0-9_]\([a-z0-9_]*_func\).*$/-T \1/p' \
+ -e 's/^typedef.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*[a-zA-Z0-9_]\);$/-T \1/p' \
+ | sort -u`"
+
+${indent} ${types} "$@"
diff --git a/contrib/gdb/gdb/gdb_locale.h b/contrib/gdb/gdb/gdb_locale.h
new file mode 100644
index 0000000..0d89092
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_locale.h
@@ -0,0 +1,46 @@
+/* GDB-friendly replacement for <locale.h>.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_LOCALE_H
+#define GDB_LOCALE_H
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(String) gettext (String)
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define textdomain(Domainname) while (0) /* nothing */
+# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */
+# define _(String) (String)
+# define N_(String) (String)
+#endif
+
+#endif /* GDB_LOCALE_H */
diff --git a/contrib/gdb/gdb/gdb_mbuild.sh b/contrib/gdb/gdb/gdb_mbuild.sh
new file mode 100755
index 0000000..fc17219
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_mbuild.sh
@@ -0,0 +1,333 @@
+#!/bin/sh
+
+# Multi-build script for testing compilation of all maintained
+# configs of GDB.
+
+# Copyright 2002, 2003 Free Software Foundation, Inc.
+
+# Contributed by Richard Earnshaw (rearnsha@arm.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
+
+usage()
+{
+ cat <<EOF
+Usage: gdb_mbuild.sh [ <options> ... ] <srcdir> <builddir>
+ Options:
+ -j <makejobs> Run <makejobs> in parallel. Passed to make.
+ On a single cpu machine, 2 is recommended.
+ -k Keep going. Do not stop after the first build fails.
+ --keep Keep builds. Do not remove each build when finished.
+ -e <regexp> Regular expression for selecting the targets to build.
+ -f Force rebuild. Even rebuild previously built directories.
+ -v Be more (and more, and more) verbose.
+ Arguments:
+ <srcdir> Source code directory.
+ <builddir> Build directory.
+ Environment variables examined (with default if not defined):
+ MAKE (make)"
+EOF
+ exit 1;
+cat <<NOTYET
+ -b <maxbuilds> Run <maxbuild> builds in parallel.
+ On a single cpu machine, 1 is recommended.
+NOTYET
+}
+
+### COMMAND LINE OPTIONS
+
+makejobs=
+maxbuilds=1
+keepgoing=
+force=false
+targexp=""
+verbose=0
+keep=false
+while test $# -gt 0
+do
+ case "$1" in
+ -j )
+ # Number of parallel make jobs.
+ shift
+ test $# -ge 1 || usage
+ makejobs="-j $1"
+ ;;
+ -b | -c )
+ # Number of builds to fire off in parallel.
+ shift
+ test $# -ge 1 || usage
+ maxbuilds=$1
+ ;;
+ -k )
+ # Should we soldier on after the first build fails?
+ keepgoing=-k
+ ;;
+ --keep )
+ keep=true
+ ;;
+ -e )
+ # A regular expression for selecting targets
+ shift
+ test $# -ge 1 || usage
+ targexp="${targexp} -e ${1}"
+ ;;
+ -f )
+ # Force a rebuild
+ force=true ;
+ ;;
+ -v )
+ # Be more, and more, and more, verbose
+ verbose=`expr ${verbose} + 1`
+ ;;
+ -* ) usage ;;
+ *) break ;;
+ esac
+ shift
+done
+
+
+### COMMAND LINE PARAMETERS
+
+if test $# -ne 2
+then
+ usage
+fi
+
+# Convert these to absolute directory paths.
+
+# Where the sources live
+srcdir=`cd $1 && /bin/pwd` || exit 1
+
+# Where the builds occur
+builddir=`cd $2 && /bin/pwd` || exit 1
+
+### ENVIRONMENT PARAMETERS
+
+# Version of make to use
+make=${MAKE:-make}
+MAKE=${make}
+export MAKE
+
+
+# Where to look for the list of targets to test
+maintainers=${srcdir}/gdb/MAINTAINERS
+if [ ! -r ${maintainers} ]
+then
+ echo Maintainers file ${maintainers} not found
+ exit 1
+fi
+
+# Get the list of targets and the build options
+alltarg=`cat ${maintainers} | tr -s '[\t]' '[ ]' | sed -n '
+/^[ ]*[-a-z0-9\.]*[ ]*[(]*--target=.*/ !d
+s/^.*--target=//
+s/).*$//
+h
+:loop
+ g
+ /^[^ ]*,/ !b end
+ s/,[^ ]*//
+ p
+ g
+ s/^[^,]*,//
+ h
+b loop
+:end
+p
+' | if test "${targexp}" = ""
+then
+ grep -v -e broken -e OBSOLETE
+else
+ grep ${targexp}
+fi`
+
+
+# Usage: fail <message> <test-that-should-succeed>. Should the build
+# fail? If the test is true, and we don't want to keep going, print
+# the message and shoot everything in sight and abort the build.
+
+fail ()
+{
+ msg="$1" ; shift
+ if test "$@"
+ then
+ echo "${target}: ${msg}"
+ if test "${keepgoing}" != ""
+ then
+ #exit 1
+ continue
+ else
+ kill $$
+ exit 1
+ fi
+ fi
+}
+
+
+# Usage: log <level> <logfile>. Write standard input to <logfile> and
+# stdout (if verbose >= level).
+
+log ()
+{
+ if test ${verbose} -ge $1
+ then
+ tee $2
+ else
+ cat > $2
+ fi
+}
+
+
+
+# Warn the user of what is comming, print the list of targets
+
+echo "$alltarg"
+echo ""
+
+
+# For each target, configure, build and test it.
+
+echo "$alltarg" | while read target gdbopts simopts
+do
+
+ trap "exit 1" 1 2 15
+ dir=${builddir}/${target}
+
+ # Should a scratch rebuild be forced, for perhaphs the entire
+ # build be skipped?
+
+ if ${force}
+ then
+ echo forcing ${target} ...
+ rm -rf ${dir}
+ elif test -f ${dir}
+ then
+ echo "${target}"
+ continue
+ else
+ echo ${target} ...
+ fi
+
+ # Did the previous configure attempt fail? If it did
+ # restart from scratch.
+
+ if test -d ${dir} -a ! -r ${dir}/Makefile
+ then
+ echo ... removing partially configured ${target}
+ rm -rf ${dir}
+ if test -d ${dir}
+ then
+ echo "${target}: unable to remove directory ${dir}"
+ exit 1
+ fi
+ fi
+
+ # From now on, we're in this target's build directory
+
+ mkdir -p ${dir}
+ cd ${dir} || exit 1
+
+ # Configure, if not already. Should this go back to being
+ # separate and done in parallel?
+
+ if test ! -r Makefile
+ then
+ # Default SIMOPTS to GDBOPTS.
+ test -z "${simopts}" && simopts="${gdbopts}"
+ # The config options
+ __target="--target=${target}"
+ __enable_gdb_build_warnings=`test -z "${gdbopts}" \
+ || echo "--enable-gdb-build-warnings=${gdbopts}"`
+ __enable_sim_build_warnings=`test -z "${simopts}" \
+ || echo "--enable-sim-build-warnings=${simopts}"`
+ __configure="${srcdir}/configure \
+ ${__target} \
+ ${__enable_gdb_build_warnings} \
+ ${__enable_sim_build_warnings}"
+ echo ... ${__configure}
+ trap "echo Removing partially configured ${dir} directory ...; rm -rf ${dir}; exit 1" 1 2 15
+ ${__configure} 2>&1 | log 2 Config.log
+ trap "exit 1" 1 2 15
+ fi
+ fail "configure failed" ! -r Makefile
+
+ # Build, if not built.
+
+ if test ! -x gdb/gdb -a ! -x gdb/gdb.exe
+ then
+ # Iff the build fails remove the final build target so that
+ # the follow-on code knows things failed. Stops the follow-on
+ # code thinking that a failed rebuild succedded (executable
+ # left around from previous build).
+ echo ... ${make} ${keepgoing} ${makejobs} ${target}
+ ( ${make} ${keepgoing} ${makejobs} all-gdb || rm -f gdb/gdb gdb/gdb.exe
+ ) 2>&1 | log 1 Build.log
+ fi
+ fail "compile failed" ! -x gdb/gdb -a ! -x gdb/gdb.exe
+
+ # Check that the built GDB can at least print it's architecture.
+
+ echo ... run ${target}
+ rm -f core gdb.core ${dir}/gdb/x
+ cat <<EOF > x
+maint print architecture
+quit
+EOF
+ ./gdb/gdb -batch -nx -x x 2>&1 | log 1 Gdb.log
+ fail "gdb dumped core" -r core -o -r gdb.core
+ fail "gdb printed no output" ! -s Gdb.log
+ grep -e internal-error Gdb.log && fail "gdb panic" 1
+
+ echo ... cleanup ${target}
+
+ # Create a sed script that cleans up the output from GDB.
+ rm -f mbuild.sed
+ touch mbuild.sed || exit 1
+ # Rules to replace <0xNNNN> with the corresponding function's
+ # name.
+ sed -n -e '/<0x0*>/d' -e 's/^.*<0x\([0-9a-f]*\)>.*$/0x\1/p' Gdb.log \
+ | sort -u \
+ | while read addr
+ do
+ func="`addr2line -f -e ./gdb/gdb -s ${addr} | sed -n -e 1p`"
+ test ${verbose} -gt 0 && echo "${addr} ${func}" 1>&2
+ echo "s/<${addr}>/<${func}>/g"
+ done >> mbuild.sed
+ # Rules to strip the leading paths off of file names.
+ echo 's/"\/.*\/gdb\//"gdb\//g' >> mbuild.sed
+ # Run the script
+ sed -f mbuild.sed Gdb.log > Mbuild.log
+
+ # Replace the build directory with a file as semaphore that stops
+ # a rebuild. (should the logs be saved?)
+
+ cd ${builddir}
+
+ if ${keep}
+ then
+ :
+ else
+ rm -f ${target}.tmp
+ mv ${target}/Mbuild.log ${target}.tmp
+ rm -rf ${target}
+ mv ${target}.tmp ${target}
+ fi
+
+ # Success!
+ echo ... ${target} built
+
+done
+
+exit 0
diff --git a/contrib/gdb/gdb/gdb_obstack.h b/contrib/gdb/gdb/gdb_obstack.h
new file mode 100644
index 0000000..0dcfc4f
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_obstack.h
@@ -0,0 +1,39 @@
+/* Obstack wrapper for GDB.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_OBSTACK_H)
+#define GDB_OBSTACK_H 1
+
+#include "obstack.h"
+
+/* Unless explicitly specified, GDB obstacks always use xmalloc() and
+ xfree(). */
+/* Note: ezannoni 2004-02-09: One could also specify the allocation
+ functions using a special init function for each obstack,
+ obstack_specify_allocation. However we just use obstack_init and
+ let these defines here do the job. While one could argue the
+ superiority of one approach over the other, we just chose one
+ throughout. */
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free xfree
+
+#endif
diff --git a/contrib/gdb/gdb/gdb_proc_service.h b/contrib/gdb/gdb/gdb_proc_service.h
new file mode 100644
index 0000000..e77cdf6
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_proc_service.h
@@ -0,0 +1,86 @@
+/* <proc_service.h> replacement for systems that don't have it.
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_PROC_SERVICE_H
+#define GDB_PROC_SERVICE_H
+
+#include <sys/types.h>
+
+#ifdef HAVE_PROC_SERVICE_H
+#include <proc_service.h>
+#else
+
+#ifdef HAVE_SYS_PROCFS_H
+#include <sys/procfs.h>
+#endif
+
+#include "gregset.h"
+
+typedef enum
+{
+ PS_OK, /* Success. */
+ PS_ERR, /* Generic error. */
+ PS_BADPID, /* Bad process handle. */
+ PS_BADLID, /* Bad LWP id. */
+ PS_BADADDR, /* Bad address. */
+ PS_NOSYM, /* Symbol not found. */
+ PS_NOFREGS /* FPU register set not available. */
+} ps_err_e;
+
+#ifndef HAVE_LWPID_T
+typedef unsigned int lwpid_t;
+#endif
+
+typedef unsigned long paddr_t;
+
+#ifndef HAVE_PSADDR_T
+typedef unsigned long psaddr_t;
+#endif
+
+#ifndef HAVE_PRGREGSET_T
+typedef gdb_gregset_t prgregset_t;
+#endif
+
+#ifndef HAVE_PRFPREGSET_T
+typedef gdb_fpregset_t prfpregset_t;
+#endif
+
+#endif /* HAVE_PROC_SERVICE_H */
+
+/* Fix-up some broken systems. */
+
+/* Unfortunately glibc 2.1.3 was released with a broken prfpregset_t
+ type. We let configure check for this lossage, and make
+ appropriate typedefs here. */
+
+#ifdef PRFPREGSET_T_BROKEN
+typedef gdb_fpregset_t gdb_prfpregset_t;
+#else
+typedef prfpregset_t gdb_prfpregset_t;
+#endif
+
+/* Structure that identifies the target process. */
+struct ps_prochandle
+{
+ /* The process id is all we need. */
+ pid_t pid;
+};
+
+#endif /* gdb_proc_service.h */
diff --git a/contrib/gdb/gdb/gdb_regex.h b/contrib/gdb/gdb/gdb_regex.h
new file mode 100644
index 0000000..7e270f4
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_regex.h
@@ -0,0 +1,32 @@
+/* Portable <regex.h>.
+ Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_REGEX_H
+#define GDB_REGEX_H 1
+
+#ifdef USE_INCLUDED_REGEX
+# include "xregex.h"
+#else
+/* Request 4.2 BSD regex functions. */
+# define _REGEX_RE_COMP
+# include <regex.h>
+#endif
+
+#endif /* not GDB_REGEX_H */
diff --git a/contrib/gdb/gdb/gdb_stat.h b/contrib/gdb/gdb/gdb_stat.h
new file mode 100644
index 0000000..f3577f2
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_stat.h
@@ -0,0 +1,74 @@
+/* Portable <sys/stat.h>
+ 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 <sys/types.h>
+#include <sys/stat.h>
+
+#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
+
+/* Microsoft C's stat.h doesn't define all the POSIX file modes. */
+#ifndef S_IROTH
+#define S_IROTH S_IREAD
+#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 0000000..f54af80
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_string.h
@@ -0,0 +1,67 @@
+/* Portable <string.h>
+ Copyright 1995, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <string.h>
+#else
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifndef strchr
+extern char *strchr (const char *, int); /* X3.159-1989 4.11.5.2 */
+#endif
+
+#ifndef strrchr
+extern char *strrchr (const char *, int); /* X3.159-1989 4.11.5.5 */
+#endif
+
+#ifndef strtok
+extern char *strtok (char *, const char *); /* X3.159-1989 4.11.5.8 */
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#else
+extern void *memset ();
+extern void *memcpy ();
+extern void *memmove ();
+extern int memcmp ();
+#endif
+#endif /* STDC_HEADERS */
+
+#ifdef NEED_DECLARATION_STRERROR
+#ifndef strerror
+extern char *strerror (int); /* X3.159-1989 4.11.6.2 */
+#endif
+#endif
+
+#ifdef NEED_DECLARATION_STRSTR
+#ifndef strstr
+extern char *strstr (const char *, const char *); /* X3.159-1989 4.11.5.7 */
+#endif
+#endif
+
+#endif /* !defined(GDB_STRING_H) */
diff --git a/contrib/gdb/gdb/gdb_thread_db.h b/contrib/gdb/gdb/gdb_thread_db.h
new file mode 100644
index 0000000..81dd0a0
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_thread_db.h
@@ -0,0 +1,461 @@
+#ifdef HAVE_THREAD_DB_H
+#include <thread_db.h>
+#else
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+typedef uint32_t gdb_uint32_t;
+#define GDB_UINT32_C(c) UINT32_C(c)
+#else
+typedef unsigned int gdb_uint32_t;
+#define GDB_UINT32_C(c) c ## U
+#endif
+
+/* Copyright 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _THREAD_DB_H
+#define _THREAD_DB_H 1
+
+/* This is the debugger interface for the LinuxThreads library. It is
+ modelled closely after the interface with same names in Solaris with
+ the goal to share the same code in the debugger. */
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+
+
+/* Error codes of the library. */
+typedef enum
+{
+ TD_OK, /* No error. */
+ TD_ERR, /* No further specified error. */
+ TD_NOTHR, /* No matching thread found. */
+ TD_NOSV, /* No matching synchronization handle found. */
+ TD_NOLWP, /* No matching light-weighted process found. */
+ TD_BADPH, /* Invalid process handle. */
+ TD_BADTH, /* Invalid thread handle. */
+ TD_BADSH, /* Invalid synchronization handle. */
+ TD_BADTA, /* Invalid thread agent. */
+ TD_BADKEY, /* Invalid key. */
+ TD_NOMSG, /* No event available. */
+ TD_NOFPREGS, /* No floating-point register content available. */
+ TD_NOLIBTHREAD, /* Application not linked with thread library. */
+ TD_NOEVENT, /* Requested event is not supported. */
+ TD_NOCAPAB, /* Capability not available. */
+ TD_DBERR, /* Internal debug library error. */
+ TD_NOAPLIC, /* Operation is not applicable. */
+ TD_NOTSD, /* No thread-specific data available. */
+ TD_MALLOC, /* Out of memory. */
+ TD_PARTIALREG, /* Not entire register set was read or written. */
+ TD_NOXREGS, /* X register set not available for given thread. */
+ TD_NOTALLOC /* TLS memory not yet allocated. */
+} td_err_e;
+
+
+/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to
+ select threads regardless of state in td_ta_thr_iter(). */
+typedef enum
+{
+ TD_THR_ANY_STATE,
+ TD_THR_UNKNOWN,
+ TD_THR_STOPPED,
+ TD_THR_RUN,
+ TD_THR_ACTIVE,
+ TD_THR_ZOMBIE,
+ TD_THR_SLEEP,
+ TD_THR_STOPPED_ASLEEP
+} td_thr_state_e;
+
+/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used
+ to select threads regardless of type in td_ta_thr_iter(). */
+typedef enum
+{
+ TD_THR_ANY_TYPE,
+ TD_THR_USER,
+ TD_THR_SYSTEM
+} td_thr_type_e;
+
+
+/* Types of the debugging library. */
+
+/* Handle for a process. This type is opaque. */
+typedef struct td_thragent td_thragent_t;
+
+/* The actual thread handle type. This is also opaque. */
+typedef struct td_thrhandle
+{
+ td_thragent_t *th_ta_p;
+ psaddr_t th_unique;
+} td_thrhandle_t;
+
+
+/* Flags for `td_ta_thr_iter'. */
+#define TD_THR_ANY_USER_FLAGS 0xffffffff
+#define TD_THR_LOWEST_PRIORITY -20
+#define TD_SIGNO_MASK NULL
+
+
+#define TD_EVENTSIZE 2
+#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */
+#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */
+#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */
+
+/* Bitmask of enabled events. */
+typedef struct td_thr_events
+{
+ gdb_uint32_t event_bits[TD_EVENTSIZE];
+} td_thr_events_t;
+
+/* Event set manipulation macros. */
+#define __td_eventmask(n) \
+ (GDB_UINT32_C (1) << (((n) - 1) & BT_UIMASK))
+#define __td_eventword(n) \
+ ((GDB_UINT32_C ((n) - 1)) >> BT_UISHIFT)
+
+#define td_event_emptyset(setp) \
+ do { \
+ int __i; \
+ for (__i = TD_EVENTSIZE; __i > 0; --__i) \
+ (setp)->event_bits[__i - 1] = 0; \
+ } while (0)
+
+#define td_event_fillset(setp) \
+ do { \
+ int __i; \
+ for (__i = TD_EVENTSIZE; __i > 0; --__i) \
+ (setp)->event_bits[__i - 1] = GDB_UINT32_C (0xffffffff); \
+ } while (0)
+
+#define td_event_addset(setp, n) \
+ (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n))
+#define td_event_delset(setp, n) \
+ (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n))
+#define td_eventismember(setp, n) \
+ (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)]))
+#if TD_EVENTSIZE == 2
+# define td_eventisempty(setp) \
+ (!((setp)->event_bits[0]) && !((setp)->event_bits[1]))
+#else
+# error "td_eventisempty must be changed to match TD_EVENTSIZE"
+#endif
+
+/* Events reportable by the thread implementation. */
+typedef enum
+{
+ TD_ALL_EVENTS, /* Pseudo-event number. */
+ TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */
+ TD_READY, /* Is executable now. */
+ TD_SLEEP, /* Blocked in a synchronization obj. */
+ TD_SWITCHTO, /* Now assigned to a process. */
+ TD_SWITCHFROM, /* Not anymore assigned to a process. */
+ TD_LOCK_TRY, /* Trying to get an unavailable lock. */
+ TD_CATCHSIG, /* Signal posted to the thread. */
+ TD_IDLE, /* Process getting idle. */
+ TD_CREATE, /* New thread created. */
+ TD_DEATH, /* Thread terminated. */
+ TD_PREEMPT, /* Preempted. */
+ TD_PRI_INHERIT, /* Inherited elevated priority. */
+ TD_REAP, /* Reaped. */
+ TD_CONCURRENCY, /* Number of processes changing. */
+ TD_TIMEOUT, /* Conditional variable wait timed out. */
+ TD_MIN_EVENT_NUM = TD_READY,
+ TD_MAX_EVENT_NUM = TD_TIMEOUT,
+ TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */
+} td_event_e;
+
+/* Values representing the different ways events are reported. */
+typedef enum
+{
+ NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */
+ NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically
+ inserted. */
+ NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */
+} td_notify_e;
+
+/* Description how event type is reported. */
+typedef struct td_notify
+{
+ td_notify_e type; /* Way the event is reported. */
+ union
+ {
+ psaddr_t bptaddr; /* Address of breakpoint. */
+ int syscallno; /* Number of system call used. */
+ } u;
+} td_notify_t;
+
+/* Some people still have libc5 or old glibc with no uintptr_t.
+ They lose. glibc 2.1.3 was released on 2000-02-25, and it has
+ uintptr_t, so it's reasonable to force these people to upgrade. */
+
+#ifndef HAVE_UINTPTR_T
+#error No uintptr_t available; your C library is too old.
+/* Inhibit further compilation errors after this error. */
+#define uintptr_t void *
+#endif
+
+/* Structure used to report event. */
+typedef struct td_event_msg
+{
+ td_event_e event; /* Event type being reported. */
+ const td_thrhandle_t *th_p; /* Thread reporting the event. */
+ union
+ {
+#if 0
+ td_synchandle_t *sh; /* Handle of synchronization object. */
+#endif
+ uintptr_t data; /* Event specific data. */
+ } msg;
+} td_event_msg_t;
+
+/* Structure containing event data available in each thread structure. */
+typedef struct
+{
+ td_thr_events_t eventmask; /* Mask of enabled events. */
+ td_event_e eventnum; /* Number of last event. */
+ void *eventdata; /* Data associated with event. */
+} td_eventbuf_t;
+
+
+/* Gathered statistics about the process. */
+typedef struct td_ta_stats
+{
+ int nthreads; /* Total number of threads in use. */
+ int r_concurrency; /* Concurrency level requested by user. */
+ int nrunnable_num; /* Average runnable threads, numerator. */
+ int nrunnable_den; /* Average runnable threads, denominator. */
+ int a_concurrency_num; /* Achieved concurrency level, numerator. */
+ int a_concurrency_den; /* Achieved concurrency level, denominator. */
+ int nlwps_num; /* Average number of processes in use,
+ numerator. */
+ int nlwps_den; /* Average number of processes in use,
+ denominator. */
+ int nidle_num; /* Average number of idling processes,
+ numerator. */
+ int nidle_den; /* Average number of idling processes,
+ denominator. */
+} td_ta_stats_t;
+
+
+/* Since Sun's library is based on Solaris threads we have to define a few
+ types to map them to POSIX threads. */
+typedef pthread_t thread_t;
+typedef pthread_key_t thread_key_t;
+
+
+/* Callback for iteration over threads. */
+typedef int td_thr_iter_f (const td_thrhandle_t *, void *);
+
+/* Callback for iteration over thread local data. */
+typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *);
+
+
+
+/* Forward declaration. This has to be defined by the user. */
+struct ps_prochandle;
+
+
+/* Information about the thread. */
+typedef struct td_thrinfo
+{
+ td_thragent_t *ti_ta_p; /* Process handle. */
+ unsigned int ti_user_flags; /* Unused. */
+ thread_t ti_tid; /* Thread ID returned by
+ pthread_create(). */
+ char *ti_tls; /* Pointer to thread-local data. */
+ psaddr_t ti_startfunc; /* Start function passed to
+ pthread_create(). */
+ psaddr_t ti_stkbase; /* Base of thread's stack. */
+ long int ti_stksize; /* Size of thread's stack. */
+ psaddr_t ti_ro_area; /* Unused. */
+ int ti_ro_size; /* Unused. */
+ td_thr_state_e ti_state; /* Thread state. */
+ unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */
+ td_thr_type_e ti_type; /* Type of the thread (system vs
+ user thread). */
+ intptr_t ti_pc; /* Unused. */
+ intptr_t ti_sp; /* Unused. */
+ short int ti_flags; /* Unused. */
+ int ti_pri; /* Thread priority. */
+ lwpid_t ti_lid; /* Unused. */
+ sigset_t ti_sigmask; /* Signal mask. */
+ unsigned char ti_traceme; /* Nonzero if event reporting
+ enabled. */
+ unsigned char ti_preemptflag; /* Unused. */
+ unsigned char ti_pirecflag; /* Unused. */
+ sigset_t ti_pending; /* Set of pending signals. */
+ td_thr_events_t ti_events; /* Set of enabled events. */
+} td_thrinfo_t;
+
+
+
+/* Prototypes for exported library functions. */
+
+/* Initialize the thread debug support library. */
+extern td_err_e td_init (void);
+
+/* Historical relict. Should not be used anymore. */
+extern td_err_e td_log (void);
+
+/* Generate new thread debug library handle for process PS. */
+extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta);
+
+/* Free resources allocated for TA. */
+extern td_err_e td_ta_delete (td_thragent_t *__ta);
+
+/* Get number of currently running threads in process associated with TA. */
+extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np);
+
+/* Return process handle passed in `td_ta_new' for process associated with
+ TA. */
+extern td_err_e td_ta_get_ph (const td_thragent_t *__ta,
+ struct ps_prochandle **__ph);
+
+/* Map thread library handle PT to thread debug library handle for process
+ associated with TA and store result in *TH. */
+extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt,
+ td_thrhandle_t *__th);
+
+/* Map process ID LWPID to thread debug library handle for process
+ associated with TA and store result in *TH. */
+extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid,
+ td_thrhandle_t *__th);
+
+
+/* Call for each thread in a process associated with TA the callback function
+ CALLBACK. */
+extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta,
+ td_thr_iter_f *__callback, void *__cbdata_p,
+ td_thr_state_e __state, int __ti_pri,
+ sigset_t *__ti_sigmask_p,
+ unsigned int __ti_user_flags);
+
+/* Call for each defined thread local data entry the callback function KI. */
+extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki,
+ void *__p);
+
+
+/* Get event address for EVENT. */
+extern td_err_e td_ta_event_addr (const td_thragent_t *__ta,
+ td_event_e __event, td_notify_t *__ptr);
+
+/* Enable EVENT in global mask. */
+extern td_err_e td_ta_set_event (const td_thragent_t *__ta,
+ td_thr_events_t *__event);
+
+/* Disable EVENT in global mask. */
+extern td_err_e td_ta_clear_event (const td_thragent_t *__ta,
+ td_thr_events_t *__event);
+
+/* Return information about last event. */
+extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta,
+ td_event_msg_t *msg);
+
+
+/* Set suggested concurrency level for process associated with TA. */
+extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level);
+
+
+/* Enable collecting statistics for process associated with TA. */
+extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable);
+
+/* Reset statistics. */
+extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta);
+
+/* Retrieve statistics from process associated with TA. */
+extern td_err_e td_ta_get_stats (const td_thragent_t *__ta,
+ td_ta_stats_t *__statsp);
+
+
+/* Validate that TH is a thread handle. */
+extern td_err_e td_thr_validate (const td_thrhandle_t *__th);
+
+/* Return information about thread TH. */
+extern td_err_e td_thr_get_info (const td_thrhandle_t *__th,
+ td_thrinfo_t *__infop);
+
+/* Retrieve floating-point register contents of process running thread TH. */
+extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th,
+ prfpregset_t *__regset);
+
+/* Retrieve general register contents of process running thread TH. */
+extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th,
+ prgregset_t __gregs);
+
+/* Retrieve extended register contents of process running thread TH. */
+extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs);
+
+/* Get size of extended register set of process running thread TH. */
+extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep);
+
+/* Set floating-point register contents of process running thread TH. */
+extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th,
+ const prfpregset_t *__fpregs);
+
+/* Set general register contents of process running thread TH. */
+extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th,
+ prgregset_t __gregs);
+
+/* Set extended register contents of process running thread TH. */
+extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th,
+ const void *__addr);
+
+
+/* Enable reporting for EVENT for thread TH. */
+extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event);
+
+/* Enable EVENT for thread TH. */
+extern td_err_e td_thr_set_event (const td_thrhandle_t *__th,
+ td_thr_events_t *__event);
+
+/* Disable EVENT for thread TH. */
+extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th,
+ td_thr_events_t *__event);
+
+/* Get event message for thread TH. */
+extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th,
+ td_event_msg_t *__msg);
+
+
+/* Set priority of thread TH. */
+extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio);
+
+
+/* Set pending signals for thread TH. */
+extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th,
+ unsigned char __n, const sigset_t *__ss);
+
+/* Set signal mask for thread TH. */
+extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th,
+ const sigset_t *__ss);
+
+
+/* Return thread local data associated with key TK in thread TH. */
+extern td_err_e td_thr_tsd (const td_thrhandle_t *__th,
+ const thread_key_t __tk, void **__data);
+
+
+/* Suspend execution of thread TH. */
+extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th);
+
+/* Resume execution of thread TH. */
+extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th);
+
+#endif /* thread_db.h */
+
+#endif /* HAVE_THREAD_DB_H */
diff --git a/contrib/gdb/gdb/gdb_vfork.h b/contrib/gdb/gdb/gdb_vfork.h
new file mode 100644
index 0000000..b9cef96
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_vfork.h
@@ -0,0 +1,28 @@
+/* GDB-friendly replacement for <vfork.h>.
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_VFORK_H
+#define GDB_VFORK_H
+
+#if HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#endif /* GDB_VFORK_H */
diff --git a/contrib/gdb/gdb/gdb_wait.h b/contrib/gdb/gdb/gdb_wait.h
new file mode 100644
index 0000000..fec6f60
--- /dev/null
+++ b/contrib/gdb/gdb/gdb_wait.h
@@ -0,0 +1,121 @@
+/* Standard wait macros.
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_WAIT_H
+#define GDB_WAIT_H
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h> /* POSIX */
+#else
+#ifdef HAVE_WAIT_H
+#include <wait.h> /* legacy */
+#endif
+#endif
+
+/* 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
+ <sys/wait.h> defines, since our code does not use waitpid() (but
+ NOTE exception for GNU/Linux below). 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
+# ifdef W_EXITCODE
+#define WSETEXIT(w,status) ((w) = W_EXITCODE(status,0))
+# else
+#define WSETEXIT(w,status) ((w) = (0 | ((status) << 8)))
+# endif
+#endif
+
+#ifndef WSETSTOP
+# ifdef W_STOPCODE
+#define WSETSTOP(w,sig) ((w) = W_STOPCODE(sig))
+# else
+#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8)))
+# endif
+#endif
+
+/* For native GNU/Linux we may use waitpid and the __WCLONE option.
+ <GRIPE> It is of course dangerous not to use the REAL header file...
+ </GRIPE>. */
+
+/* Bits in the third argument to `waitpid'. */
+#ifndef WNOHANG
+#define WNOHANG 1 /* Don't block waiting. */
+#endif
+
+#ifndef WUNTRACED
+#define WUNTRACED 2 /* Report status of stopped children. */
+#endif
+
+#ifndef __WCLONE
+#define __WCLONE 0x80000000 /* Wait for cloned process. */
+#endif
+
+#endif
diff --git a/contrib/gdb/gdb/gdbarch.c b/contrib/gdb/gdb/gdbarch.c
new file mode 100644
index 0000000..1ee401f
--- /dev/null
+++ b/contrib/gdb/gdb/gdbarch.c
@@ -0,0 +1,5885 @@
+/* *INDENT-OFF* */ /* THIS FILE IS GENERATED */
+
+/* Dynamic architecture support for GDB, the GNU debugger.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This file was created with the aid of ``gdbarch.sh''.
+
+ The Bourne shell script ``gdbarch.sh'' creates the files
+ ``new-gdbarch.c'' and ``new-gdbarch.h and then compares them
+ against the existing ``gdbarch.[hc]''. Any differences found
+ being reported.
+
+ If editing this file, please also run gdbarch.sh and merge any
+ changes into that script. Conversely, when making sweeping changes
+ to this file, modifying gdbarch.sh and using its output may prove
+ easier. */
+
+
+#include "defs.h"
+#include "arch-utils.h"
+
+#include "gdbcmd.h"
+#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
+#include "symcat.h"
+
+#include "floatformat.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdb-events.h"
+#include "reggroups.h"
+#include "osabi.h"
+#include "gdb_obstack.h"
+
+/* Static function declarations */
+
+static void alloc_gdbarch_data (struct gdbarch *);
+
+/* Non-zero if we want to trace architecture code. */
+
+#ifndef GDBARCH_DEBUG
+#define GDBARCH_DEBUG 0
+#endif
+int gdbarch_debug = GDBARCH_DEBUG;
+
+
+/* Maintain the struct gdbarch object */
+
+struct gdbarch
+{
+ /* Has this architecture been fully initialized? */
+ int initialized_p;
+
+ /* An obstack bound to the lifetime of the architecture. */
+ struct obstack *obstack;
+
+ /* basic architectural information */
+ const struct bfd_arch_info * bfd_arch_info;
+ int byte_order;
+ enum gdb_osabi osabi;
+
+ /* target specific vector. */
+ struct gdbarch_tdep *tdep;
+ gdbarch_dump_tdep_ftype *dump_tdep;
+
+ /* per-architecture data-pointers */
+ unsigned nr_data;
+ void **data;
+
+ /* per-architecture swap-regions */
+ struct gdbarch_swap *swap;
+
+ /* Multi-arch values.
+
+ When extending this structure you must:
+
+ Add the field below.
+
+ Declare set/get functions and define the corresponding
+ macro in gdbarch.h.
+
+ gdbarch_alloc(): If zero/NULL is not a suitable default,
+ initialize the new field.
+
+ verify_gdbarch(): Confirm that the target updated the field
+ correctly.
+
+ gdbarch_dump(): Add a fprintf_unfiltered call so that the new
+ field is dumped out
+
+ ``startup_gdbarch()'': Append an initial value to the static
+ variable (base values on the host's c-type system).
+
+ get_gdbarch(): Implement the set/get functions (probably using
+ the macro's as shortcuts).
+
+ */
+
+ int short_bit;
+ int int_bit;
+ int long_bit;
+ int long_long_bit;
+ int float_bit;
+ int double_bit;
+ int long_double_bit;
+ int ptr_bit;
+ int addr_bit;
+ int bfd_vma_bit;
+ int char_signed;
+ gdbarch_read_pc_ftype *read_pc;
+ gdbarch_write_pc_ftype *write_pc;
+ gdbarch_read_sp_ftype *read_sp;
+ gdbarch_virtual_frame_pointer_ftype *virtual_frame_pointer;
+ gdbarch_pseudo_register_read_ftype *pseudo_register_read;
+ gdbarch_pseudo_register_write_ftype *pseudo_register_write;
+ int num_regs;
+ int num_pseudo_regs;
+ int sp_regnum;
+ int pc_regnum;
+ int ps_regnum;
+ int fp0_regnum;
+ gdbarch_stab_reg_to_regnum_ftype *stab_reg_to_regnum;
+ gdbarch_ecoff_reg_to_regnum_ftype *ecoff_reg_to_regnum;
+ gdbarch_dwarf_reg_to_regnum_ftype *dwarf_reg_to_regnum;
+ gdbarch_sdb_reg_to_regnum_ftype *sdb_reg_to_regnum;
+ gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum;
+ gdbarch_register_name_ftype *register_name;
+ gdbarch_register_type_ftype *register_type;
+ gdbarch_deprecated_register_virtual_type_ftype *deprecated_register_virtual_type;
+ int deprecated_register_bytes;
+ gdbarch_deprecated_register_byte_ftype *deprecated_register_byte;
+ gdbarch_deprecated_register_raw_size_ftype *deprecated_register_raw_size;
+ gdbarch_deprecated_register_virtual_size_ftype *deprecated_register_virtual_size;
+ int deprecated_max_register_raw_size;
+ int deprecated_max_register_virtual_size;
+ gdbarch_unwind_dummy_id_ftype *unwind_dummy_id;
+ gdbarch_deprecated_save_dummy_frame_tos_ftype *deprecated_save_dummy_frame_tos;
+ int deprecated_fp_regnum;
+ gdbarch_deprecated_target_read_fp_ftype *deprecated_target_read_fp;
+ gdbarch_push_dummy_call_ftype *push_dummy_call;
+ gdbarch_deprecated_push_arguments_ftype *deprecated_push_arguments;
+ int deprecated_use_generic_dummy_frames;
+ gdbarch_deprecated_push_return_address_ftype *deprecated_push_return_address;
+ gdbarch_deprecated_dummy_write_sp_ftype *deprecated_dummy_write_sp;
+ int deprecated_register_size;
+ int call_dummy_location;
+ CORE_ADDR deprecated_call_dummy_start_offset;
+ CORE_ADDR deprecated_call_dummy_breakpoint_offset;
+ int deprecated_call_dummy_length;
+ LONGEST * deprecated_call_dummy_words;
+ int deprecated_sizeof_call_dummy_words;
+ gdbarch_deprecated_fix_call_dummy_ftype *deprecated_fix_call_dummy;
+ gdbarch_push_dummy_code_ftype *push_dummy_code;
+ gdbarch_deprecated_push_dummy_frame_ftype *deprecated_push_dummy_frame;
+ gdbarch_deprecated_do_registers_info_ftype *deprecated_do_registers_info;
+ gdbarch_print_registers_info_ftype *print_registers_info;
+ gdbarch_print_float_info_ftype *print_float_info;
+ gdbarch_print_vector_info_ftype *print_vector_info;
+ gdbarch_register_sim_regno_ftype *register_sim_regno;
+ gdbarch_register_bytes_ok_ftype *register_bytes_ok;
+ gdbarch_cannot_fetch_register_ftype *cannot_fetch_register;
+ gdbarch_cannot_store_register_ftype *cannot_store_register;
+ gdbarch_get_longjmp_target_ftype *get_longjmp_target;
+ gdbarch_deprecated_pc_in_call_dummy_ftype *deprecated_pc_in_call_dummy;
+ gdbarch_deprecated_init_frame_pc_first_ftype *deprecated_init_frame_pc_first;
+ gdbarch_deprecated_init_frame_pc_ftype *deprecated_init_frame_pc;
+ int believe_pcc_promotion;
+ int believe_pcc_promotion_type;
+ gdbarch_deprecated_get_saved_register_ftype *deprecated_get_saved_register;
+ gdbarch_deprecated_register_convertible_ftype *deprecated_register_convertible;
+ gdbarch_deprecated_register_convert_to_virtual_ftype *deprecated_register_convert_to_virtual;
+ gdbarch_deprecated_register_convert_to_raw_ftype *deprecated_register_convert_to_raw;
+ gdbarch_convert_register_p_ftype *convert_register_p;
+ gdbarch_register_to_value_ftype *register_to_value;
+ gdbarch_value_to_register_ftype *value_to_register;
+ gdbarch_pointer_to_address_ftype *pointer_to_address;
+ gdbarch_address_to_pointer_ftype *address_to_pointer;
+ gdbarch_integer_to_address_ftype *integer_to_address;
+ gdbarch_deprecated_pop_frame_ftype *deprecated_pop_frame;
+ gdbarch_deprecated_store_struct_return_ftype *deprecated_store_struct_return;
+ gdbarch_return_value_ftype *return_value;
+ gdbarch_return_value_on_stack_ftype *return_value_on_stack;
+ gdbarch_extract_return_value_ftype *extract_return_value;
+ gdbarch_store_return_value_ftype *store_return_value;
+ gdbarch_deprecated_extract_return_value_ftype *deprecated_extract_return_value;
+ gdbarch_deprecated_store_return_value_ftype *deprecated_store_return_value;
+ gdbarch_use_struct_convention_ftype *use_struct_convention;
+ gdbarch_deprecated_extract_struct_value_address_ftype *deprecated_extract_struct_value_address;
+ gdbarch_deprecated_frame_init_saved_regs_ftype *deprecated_frame_init_saved_regs;
+ gdbarch_deprecated_init_extra_frame_info_ftype *deprecated_init_extra_frame_info;
+ gdbarch_skip_prologue_ftype *skip_prologue;
+ gdbarch_inner_than_ftype *inner_than;
+ gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc;
+ gdbarch_adjust_breakpoint_address_ftype *adjust_breakpoint_address;
+ gdbarch_memory_insert_breakpoint_ftype *memory_insert_breakpoint;
+ gdbarch_memory_remove_breakpoint_ftype *memory_remove_breakpoint;
+ CORE_ADDR decr_pc_after_break;
+ CORE_ADDR function_start_offset;
+ gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address;
+ CORE_ADDR frame_args_skip;
+ gdbarch_deprecated_frameless_function_invocation_ftype *deprecated_frameless_function_invocation;
+ gdbarch_deprecated_frame_chain_ftype *deprecated_frame_chain;
+ gdbarch_deprecated_frame_chain_valid_ftype *deprecated_frame_chain_valid;
+ gdbarch_deprecated_frame_saved_pc_ftype *deprecated_frame_saved_pc;
+ gdbarch_unwind_pc_ftype *unwind_pc;
+ gdbarch_unwind_sp_ftype *unwind_sp;
+ gdbarch_deprecated_frame_args_address_ftype *deprecated_frame_args_address;
+ gdbarch_deprecated_frame_locals_address_ftype *deprecated_frame_locals_address;
+ gdbarch_deprecated_saved_pc_after_call_ftype *deprecated_saved_pc_after_call;
+ gdbarch_frame_num_args_ftype *frame_num_args;
+ gdbarch_deprecated_stack_align_ftype *deprecated_stack_align;
+ gdbarch_frame_align_ftype *frame_align;
+ gdbarch_deprecated_reg_struct_has_addr_ftype *deprecated_reg_struct_has_addr;
+ gdbarch_stabs_argument_has_addr_ftype *stabs_argument_has_addr;
+ int frame_red_zone_size;
+ int parm_boundary;
+ const struct floatformat * float_format;
+ const struct floatformat * double_format;
+ const struct floatformat * long_double_format;
+ gdbarch_convert_from_func_ptr_addr_ftype *convert_from_func_ptr_addr;
+ gdbarch_addr_bits_remove_ftype *addr_bits_remove;
+ gdbarch_smash_text_address_ftype *smash_text_address;
+ gdbarch_software_single_step_ftype *software_single_step;
+ gdbarch_print_insn_ftype *print_insn;
+ gdbarch_skip_trampoline_code_ftype *skip_trampoline_code;
+ gdbarch_skip_solib_resolver_ftype *skip_solib_resolver;
+ gdbarch_in_solib_call_trampoline_ftype *in_solib_call_trampoline;
+ gdbarch_in_solib_return_trampoline_ftype *in_solib_return_trampoline;
+ gdbarch_pc_in_sigtramp_ftype *pc_in_sigtramp;
+ gdbarch_sigtramp_start_ftype *sigtramp_start;
+ gdbarch_sigtramp_end_ftype *sigtramp_end;
+ gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p;
+ gdbarch_construct_inferior_arguments_ftype *construct_inferior_arguments;
+ gdbarch_elf_make_msymbol_special_ftype *elf_make_msymbol_special;
+ gdbarch_coff_make_msymbol_special_ftype *coff_make_msymbol_special;
+ const char * name_of_malloc;
+ int cannot_step_breakpoint;
+ int have_nonsteppable_watchpoint;
+ gdbarch_address_class_type_flags_ftype *address_class_type_flags;
+ gdbarch_address_class_type_flags_to_name_ftype *address_class_type_flags_to_name;
+ gdbarch_address_class_name_to_type_flags_ftype *address_class_name_to_type_flags;
+ gdbarch_register_reggroup_p_ftype *register_reggroup_p;
+ gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
+ gdbarch_regset_from_core_section_ftype *regset_from_core_section;
+};
+
+
+/* The default architecture uses host values (for want of a better
+ choice). */
+
+extern const struct bfd_arch_info bfd_default_arch_struct;
+
+struct gdbarch startup_gdbarch =
+{
+ 1, /* Always initialized. */
+ NULL, /* The obstack. */
+ /* basic architecture information */
+ &bfd_default_arch_struct, /* bfd_arch_info */
+ BFD_ENDIAN_BIG, /* byte_order */
+ GDB_OSABI_UNKNOWN, /* osabi */
+ /* target specific vector and its dump routine */
+ NULL, NULL,
+ /*per-architecture data-pointers and swap regions */
+ 0, NULL, NULL,
+ /* Multi-arch values */
+ 8 * sizeof (short), /* short_bit */
+ 8 * sizeof (int), /* int_bit */
+ 8 * sizeof (long), /* long_bit */
+ 8 * sizeof (LONGEST), /* long_long_bit */
+ 8 * sizeof (float), /* float_bit */
+ 8 * sizeof (double), /* double_bit */
+ 8 * sizeof (long double), /* long_double_bit */
+ 8 * sizeof (void*), /* ptr_bit */
+ 8 * sizeof (void*), /* addr_bit */
+ 8 * sizeof (void*), /* bfd_vma_bit */
+ 1, /* char_signed */
+ 0, /* read_pc */
+ 0, /* write_pc */
+ 0, /* read_sp */
+ 0, /* virtual_frame_pointer */
+ 0, /* pseudo_register_read */
+ 0, /* pseudo_register_write */
+ 0, /* num_regs */
+ 0, /* num_pseudo_regs */
+ -1, /* sp_regnum */
+ -1, /* pc_regnum */
+ -1, /* ps_regnum */
+ 0, /* fp0_regnum */
+ 0, /* stab_reg_to_regnum */
+ 0, /* ecoff_reg_to_regnum */
+ 0, /* dwarf_reg_to_regnum */
+ 0, /* sdb_reg_to_regnum */
+ 0, /* dwarf2_reg_to_regnum */
+ 0, /* register_name */
+ 0, /* register_type */
+ 0, /* deprecated_register_virtual_type */
+ 0, /* deprecated_register_bytes */
+ generic_register_byte, /* deprecated_register_byte */
+ generic_register_size, /* deprecated_register_raw_size */
+ generic_register_size, /* deprecated_register_virtual_size */
+ 0, /* deprecated_max_register_raw_size */
+ 0, /* deprecated_max_register_virtual_size */
+ 0, /* unwind_dummy_id */
+ 0, /* deprecated_save_dummy_frame_tos */
+ -1, /* deprecated_fp_regnum */
+ 0, /* deprecated_target_read_fp */
+ 0, /* push_dummy_call */
+ 0, /* deprecated_push_arguments */
+ 0, /* deprecated_use_generic_dummy_frames */
+ 0, /* deprecated_push_return_address */
+ 0, /* deprecated_dummy_write_sp */
+ 0, /* deprecated_register_size */
+ 0, /* call_dummy_location */
+ 0, /* deprecated_call_dummy_start_offset */
+ 0, /* deprecated_call_dummy_breakpoint_offset */
+ 0, /* deprecated_call_dummy_length */
+ 0, /* deprecated_call_dummy_words */
+ 0, /* deprecated_sizeof_call_dummy_words */
+ 0, /* deprecated_fix_call_dummy */
+ 0, /* push_dummy_code */
+ 0, /* deprecated_push_dummy_frame */
+ 0, /* deprecated_do_registers_info */
+ default_print_registers_info, /* print_registers_info */
+ 0, /* print_float_info */
+ 0, /* print_vector_info */
+ 0, /* register_sim_regno */
+ 0, /* register_bytes_ok */
+ 0, /* cannot_fetch_register */
+ 0, /* cannot_store_register */
+ 0, /* get_longjmp_target */
+ generic_pc_in_call_dummy, /* deprecated_pc_in_call_dummy */
+ 0, /* deprecated_init_frame_pc_first */
+ 0, /* deprecated_init_frame_pc */
+ 0, /* believe_pcc_promotion */
+ 0, /* believe_pcc_promotion_type */
+ 0, /* deprecated_get_saved_register */
+ 0, /* deprecated_register_convertible */
+ 0, /* deprecated_register_convert_to_virtual */
+ 0, /* deprecated_register_convert_to_raw */
+ 0, /* convert_register_p */
+ 0, /* register_to_value */
+ 0, /* value_to_register */
+ 0, /* pointer_to_address */
+ 0, /* address_to_pointer */
+ 0, /* integer_to_address */
+ 0, /* deprecated_pop_frame */
+ 0, /* deprecated_store_struct_return */
+ 0, /* return_value */
+ 0, /* return_value_on_stack */
+ 0, /* extract_return_value */
+ 0, /* store_return_value */
+ 0, /* deprecated_extract_return_value */
+ 0, /* deprecated_store_return_value */
+ 0, /* use_struct_convention */
+ 0, /* deprecated_extract_struct_value_address */
+ 0, /* deprecated_frame_init_saved_regs */
+ 0, /* deprecated_init_extra_frame_info */
+ 0, /* skip_prologue */
+ 0, /* inner_than */
+ 0, /* breakpoint_from_pc */
+ 0, /* adjust_breakpoint_address */
+ 0, /* memory_insert_breakpoint */
+ 0, /* memory_remove_breakpoint */
+ 0, /* decr_pc_after_break */
+ 0, /* function_start_offset */
+ generic_remote_translate_xfer_address, /* remote_translate_xfer_address */
+ 0, /* frame_args_skip */
+ 0, /* deprecated_frameless_function_invocation */
+ 0, /* deprecated_frame_chain */
+ 0, /* deprecated_frame_chain_valid */
+ 0, /* deprecated_frame_saved_pc */
+ 0, /* unwind_pc */
+ 0, /* unwind_sp */
+ get_frame_base, /* deprecated_frame_args_address */
+ get_frame_base, /* deprecated_frame_locals_address */
+ 0, /* deprecated_saved_pc_after_call */
+ 0, /* frame_num_args */
+ 0, /* deprecated_stack_align */
+ 0, /* frame_align */
+ 0, /* deprecated_reg_struct_has_addr */
+ default_stabs_argument_has_addr, /* stabs_argument_has_addr */
+ 0, /* frame_red_zone_size */
+ 0, /* parm_boundary */
+ 0, /* float_format */
+ 0, /* double_format */
+ 0, /* long_double_format */
+ convert_from_func_ptr_addr_identity, /* convert_from_func_ptr_addr */
+ 0, /* addr_bits_remove */
+ 0, /* smash_text_address */
+ 0, /* software_single_step */
+ 0, /* print_insn */
+ 0, /* skip_trampoline_code */
+ generic_skip_solib_resolver, /* skip_solib_resolver */
+ 0, /* in_solib_call_trampoline */
+ 0, /* in_solib_return_trampoline */
+ 0, /* pc_in_sigtramp */
+ 0, /* sigtramp_start */
+ 0, /* sigtramp_end */
+ generic_in_function_epilogue_p, /* in_function_epilogue_p */
+ construct_inferior_arguments, /* construct_inferior_arguments */
+ 0, /* elf_make_msymbol_special */
+ 0, /* coff_make_msymbol_special */
+ "malloc", /* name_of_malloc */
+ 0, /* cannot_step_breakpoint */
+ 0, /* have_nonsteppable_watchpoint */
+ 0, /* address_class_type_flags */
+ 0, /* address_class_type_flags_to_name */
+ 0, /* address_class_name_to_type_flags */
+ default_register_reggroup_p, /* register_reggroup_p */
+ 0, /* fetch_pointer_argument */
+ 0, /* regset_from_core_section */
+ /* startup_gdbarch() */
+};
+
+struct gdbarch *current_gdbarch = &startup_gdbarch;
+
+/* Create a new ``struct gdbarch'' based on information provided by
+ ``struct gdbarch_info''. */
+
+struct gdbarch *
+gdbarch_alloc (const struct gdbarch_info *info,
+ struct gdbarch_tdep *tdep)
+{
+ /* NOTE: The new architecture variable is named ``current_gdbarch''
+ so that macros such as TARGET_DOUBLE_BIT, when expanded, refer to
+ the current local architecture and not the previous global
+ architecture. This ensures that the new architectures initial
+ values are not influenced by the previous architecture. Once
+ everything is parameterised with gdbarch, this will go away. */
+ struct gdbarch *current_gdbarch;
+
+ /* Create an obstack for allocating all the per-architecture memory,
+ then use that to allocate the architecture vector. */
+ struct obstack *obstack = XMALLOC (struct obstack);
+ obstack_init (obstack);
+ current_gdbarch = obstack_alloc (obstack, sizeof (*current_gdbarch));
+ memset (current_gdbarch, 0, sizeof (*current_gdbarch));
+ current_gdbarch->obstack = obstack;
+
+ alloc_gdbarch_data (current_gdbarch);
+
+ current_gdbarch->tdep = tdep;
+
+ current_gdbarch->bfd_arch_info = info->bfd_arch_info;
+ current_gdbarch->byte_order = info->byte_order;
+ current_gdbarch->osabi = info->osabi;
+
+ /* Force the explicit initialization of these. */
+ current_gdbarch->short_bit = 2*TARGET_CHAR_BIT;
+ current_gdbarch->int_bit = 4*TARGET_CHAR_BIT;
+ current_gdbarch->long_bit = 4*TARGET_CHAR_BIT;
+ current_gdbarch->long_long_bit = 2*TARGET_LONG_BIT;
+ current_gdbarch->float_bit = 4*TARGET_CHAR_BIT;
+ current_gdbarch->double_bit = 8*TARGET_CHAR_BIT;
+ current_gdbarch->long_double_bit = 8*TARGET_CHAR_BIT;
+ current_gdbarch->ptr_bit = TARGET_INT_BIT;
+ current_gdbarch->bfd_vma_bit = TARGET_ARCHITECTURE->bits_per_address;
+ current_gdbarch->char_signed = -1;
+ current_gdbarch->write_pc = generic_target_write_pc;
+ current_gdbarch->virtual_frame_pointer = legacy_virtual_frame_pointer;
+ current_gdbarch->num_regs = -1;
+ current_gdbarch->sp_regnum = -1;
+ current_gdbarch->pc_regnum = -1;
+ current_gdbarch->ps_regnum = -1;
+ current_gdbarch->fp0_regnum = -1;
+ current_gdbarch->stab_reg_to_regnum = no_op_reg_to_regnum;
+ current_gdbarch->ecoff_reg_to_regnum = no_op_reg_to_regnum;
+ current_gdbarch->dwarf_reg_to_regnum = no_op_reg_to_regnum;
+ current_gdbarch->sdb_reg_to_regnum = no_op_reg_to_regnum;
+ current_gdbarch->dwarf2_reg_to_regnum = no_op_reg_to_regnum;
+ current_gdbarch->deprecated_register_byte = generic_register_byte;
+ current_gdbarch->deprecated_register_raw_size = generic_register_size;
+ current_gdbarch->deprecated_register_virtual_size = generic_register_size;
+ current_gdbarch->deprecated_fp_regnum = -1;
+ current_gdbarch->deprecated_use_generic_dummy_frames = 1;
+ current_gdbarch->call_dummy_location = AT_ENTRY_POINT;
+ current_gdbarch->deprecated_call_dummy_words = legacy_call_dummy_words;
+ current_gdbarch->deprecated_sizeof_call_dummy_words = legacy_sizeof_call_dummy_words;
+ current_gdbarch->print_registers_info = default_print_registers_info;
+ current_gdbarch->register_sim_regno = legacy_register_sim_regno;
+ current_gdbarch->cannot_fetch_register = cannot_register_not;
+ current_gdbarch->cannot_store_register = cannot_register_not;
+ current_gdbarch->deprecated_pc_in_call_dummy = generic_pc_in_call_dummy;
+ current_gdbarch->convert_register_p = legacy_convert_register_p;
+ current_gdbarch->register_to_value = legacy_register_to_value;
+ current_gdbarch->value_to_register = legacy_value_to_register;
+ current_gdbarch->pointer_to_address = unsigned_pointer_to_address;
+ current_gdbarch->address_to_pointer = unsigned_address_to_pointer;
+ current_gdbarch->return_value_on_stack = generic_return_value_on_stack_not;
+ current_gdbarch->extract_return_value = legacy_extract_return_value;
+ current_gdbarch->store_return_value = legacy_store_return_value;
+ current_gdbarch->use_struct_convention = generic_use_struct_convention;
+ current_gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint;
+ current_gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint;
+ current_gdbarch->remote_translate_xfer_address = generic_remote_translate_xfer_address;
+ current_gdbarch->deprecated_frame_args_address = get_frame_base;
+ current_gdbarch->deprecated_frame_locals_address = get_frame_base;
+ current_gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
+ current_gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity;
+ current_gdbarch->addr_bits_remove = core_addr_identity;
+ current_gdbarch->smash_text_address = core_addr_identity;
+ current_gdbarch->skip_trampoline_code = generic_skip_trampoline_code;
+ current_gdbarch->skip_solib_resolver = generic_skip_solib_resolver;
+ current_gdbarch->in_solib_call_trampoline = generic_in_solib_call_trampoline;
+ current_gdbarch->in_solib_return_trampoline = generic_in_solib_return_trampoline;
+ current_gdbarch->pc_in_sigtramp = legacy_pc_in_sigtramp;
+ current_gdbarch->in_function_epilogue_p = generic_in_function_epilogue_p;
+ current_gdbarch->construct_inferior_arguments = construct_inferior_arguments;
+ current_gdbarch->elf_make_msymbol_special = default_elf_make_msymbol_special;
+ current_gdbarch->coff_make_msymbol_special = default_coff_make_msymbol_special;
+ current_gdbarch->name_of_malloc = "malloc";
+ current_gdbarch->register_reggroup_p = default_register_reggroup_p;
+ /* gdbarch_alloc() */
+
+ return current_gdbarch;
+}
+
+
+/* Allocate extra space using the per-architecture obstack. */
+
+void *
+gdbarch_obstack_zalloc (struct gdbarch *arch, long size)
+{
+ void *data = obstack_alloc (arch->obstack, size);
+ memset (data, 0, size);
+ return data;
+}
+
+
+/* Free a gdbarch struct. This should never happen in normal
+ operation --- once you've created a gdbarch, you keep it around.
+ However, if an architecture's init function encounters an error
+ building the structure, it may need to clean up a partially
+ constructed gdbarch. */
+
+void
+gdbarch_free (struct gdbarch *arch)
+{
+ struct obstack *obstack;
+ gdb_assert (arch != NULL);
+ gdb_assert (!arch->initialized_p);
+ obstack = arch->obstack;
+ obstack_free (obstack, 0); /* Includes the ARCH. */
+ xfree (obstack);
+}
+
+
+/* Ensure that all values in a GDBARCH are reasonable. */
+
+/* NOTE/WARNING: The parameter is called ``current_gdbarch'' so that it
+ just happens to match the global variable ``current_gdbarch''. That
+ way macros refering to that variable get the local and not the global
+ version - ulgh. Once everything is parameterised with gdbarch, this
+ will go away. */
+
+static void
+verify_gdbarch (struct gdbarch *current_gdbarch)
+{
+ struct ui_file *log;
+ struct cleanup *cleanups;
+ long dummy;
+ char *buf;
+ log = mem_fileopen ();
+ cleanups = make_cleanup_ui_file_delete (log);
+ /* fundamental */
+ if (current_gdbarch->byte_order == BFD_ENDIAN_UNKNOWN)
+ fprintf_unfiltered (log, "\n\tbyte-order");
+ if (current_gdbarch->bfd_arch_info == NULL)
+ fprintf_unfiltered (log, "\n\tbfd_arch_info");
+ /* Check those that need to be defined for the given multi-arch level. */
+ /* Skip verify of short_bit, invalid_p == 0 */
+ /* Skip verify of int_bit, invalid_p == 0 */
+ /* Skip verify of long_bit, invalid_p == 0 */
+ /* Skip verify of long_long_bit, invalid_p == 0 */
+ /* Skip verify of float_bit, invalid_p == 0 */
+ /* Skip verify of double_bit, invalid_p == 0 */
+ /* Skip verify of long_double_bit, invalid_p == 0 */
+ /* Skip verify of ptr_bit, invalid_p == 0 */
+ if (current_gdbarch->addr_bit == 0)
+ current_gdbarch->addr_bit = TARGET_PTR_BIT;
+ /* Skip verify of bfd_vma_bit, invalid_p == 0 */
+ if (current_gdbarch->char_signed == -1)
+ current_gdbarch->char_signed = 1;
+ /* Skip verify of read_pc, has predicate */
+ /* Skip verify of write_pc, invalid_p == 0 */
+ /* Skip verify of read_sp, has predicate */
+ /* Skip verify of virtual_frame_pointer, invalid_p == 0 */
+ /* Skip verify of pseudo_register_read, has predicate */
+ /* Skip verify of pseudo_register_write, has predicate */
+ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ && (current_gdbarch->num_regs == -1))
+ fprintf_unfiltered (log, "\n\tnum_regs");
+ /* Skip verify of num_pseudo_regs, invalid_p == 0 */
+ /* Skip verify of sp_regnum, invalid_p == 0 */
+ /* Skip verify of pc_regnum, invalid_p == 0 */
+ /* Skip verify of ps_regnum, invalid_p == 0 */
+ /* Skip verify of fp0_regnum, invalid_p == 0 */
+ /* Skip verify of stab_reg_to_regnum, invalid_p == 0 */
+ /* Skip verify of ecoff_reg_to_regnum, invalid_p == 0 */
+ /* Skip verify of dwarf_reg_to_regnum, invalid_p == 0 */
+ /* Skip verify of sdb_reg_to_regnum, invalid_p == 0 */
+ /* Skip verify of dwarf2_reg_to_regnum, invalid_p == 0 */
+ /* Skip verify of register_type, has predicate */
+ /* Skip verify of deprecated_register_virtual_type, has predicate */
+ /* Skip verify of deprecated_register_byte, has predicate */
+ /* Skip verify of deprecated_register_raw_size, has predicate */
+ /* Skip verify of deprecated_register_virtual_size, has predicate */
+ /* Skip verify of deprecated_max_register_raw_size, has predicate */
+ /* Skip verify of deprecated_max_register_virtual_size, has predicate */
+ /* Skip verify of unwind_dummy_id, has predicate */
+ /* Skip verify of deprecated_save_dummy_frame_tos, has predicate */
+ /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
+ /* Skip verify of deprecated_target_read_fp, has predicate */
+ /* Skip verify of push_dummy_call, has predicate */
+ /* Skip verify of deprecated_push_arguments, has predicate */
+ /* Skip verify of deprecated_use_generic_dummy_frames, invalid_p == 0 */
+ /* Skip verify of deprecated_push_return_address, has predicate */
+ /* Skip verify of deprecated_dummy_write_sp, has predicate */
+ /* Skip verify of call_dummy_location, invalid_p == 0 */
+ /* Skip verify of deprecated_call_dummy_words, invalid_p == 0 */
+ /* Skip verify of deprecated_sizeof_call_dummy_words, invalid_p == 0 */
+ /* Skip verify of deprecated_fix_call_dummy, has predicate */
+ /* Skip verify of push_dummy_code, has predicate */
+ /* Skip verify of deprecated_push_dummy_frame, has predicate */
+ /* Skip verify of deprecated_do_registers_info, has predicate */
+ /* Skip verify of print_registers_info, invalid_p == 0 */
+ /* Skip verify of print_float_info, has predicate */
+ /* Skip verify of print_vector_info, has predicate */
+ /* Skip verify of register_sim_regno, invalid_p == 0 */
+ /* Skip verify of register_bytes_ok, has predicate */
+ /* Skip verify of cannot_fetch_register, invalid_p == 0 */
+ /* Skip verify of cannot_store_register, invalid_p == 0 */
+ /* Skip verify of get_longjmp_target, has predicate */
+ /* Skip verify of deprecated_pc_in_call_dummy, has predicate */
+ /* Skip verify of deprecated_init_frame_pc_first, has predicate */
+ /* Skip verify of deprecated_init_frame_pc, has predicate */
+ /* Skip verify of deprecated_get_saved_register, has predicate */
+ /* Skip verify of deprecated_register_convertible, has predicate */
+ /* Skip verify of deprecated_register_convert_to_virtual, invalid_p == 0 */
+ /* Skip verify of deprecated_register_convert_to_raw, invalid_p == 0 */
+ /* Skip verify of convert_register_p, invalid_p == 0 */
+ /* Skip verify of register_to_value, invalid_p == 0 */
+ /* Skip verify of value_to_register, invalid_p == 0 */
+ /* Skip verify of pointer_to_address, invalid_p == 0 */
+ /* Skip verify of address_to_pointer, invalid_p == 0 */
+ /* Skip verify of integer_to_address, has predicate */
+ /* Skip verify of deprecated_pop_frame, has predicate */
+ /* Skip verify of deprecated_store_struct_return, has predicate */
+ /* Skip verify of return_value, has predicate */
+ /* Skip verify of return_value_on_stack, invalid_p == 0 */
+ /* Skip verify of extract_return_value, invalid_p == 0 */
+ /* Skip verify of store_return_value, invalid_p == 0 */
+ /* Skip verify of use_struct_convention, invalid_p == 0 */
+ /* Skip verify of deprecated_extract_struct_value_address, has predicate */
+ /* Skip verify of deprecated_frame_init_saved_regs, has predicate */
+ /* Skip verify of deprecated_init_extra_frame_info, has predicate */
+ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ && (current_gdbarch->skip_prologue == 0))
+ fprintf_unfiltered (log, "\n\tskip_prologue");
+ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ && (current_gdbarch->inner_than == 0))
+ fprintf_unfiltered (log, "\n\tinner_than");
+ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ && (current_gdbarch->breakpoint_from_pc == 0))
+ fprintf_unfiltered (log, "\n\tbreakpoint_from_pc");
+ /* Skip verify of adjust_breakpoint_address, has predicate */
+ /* Skip verify of memory_insert_breakpoint, invalid_p == 0 */
+ /* Skip verify of memory_remove_breakpoint, invalid_p == 0 */
+ /* Skip verify of decr_pc_after_break, invalid_p == 0 */
+ /* Skip verify of function_start_offset, invalid_p == 0 */
+ /* Skip verify of remote_translate_xfer_address, invalid_p == 0 */
+ /* Skip verify of frame_args_skip, invalid_p == 0 */
+ /* Skip verify of deprecated_frameless_function_invocation, has predicate */
+ /* Skip verify of deprecated_frame_chain, has predicate */
+ /* Skip verify of deprecated_frame_chain_valid, has predicate */
+ /* Skip verify of deprecated_frame_saved_pc, has predicate */
+ /* Skip verify of unwind_pc, has predicate */
+ /* Skip verify of unwind_sp, has predicate */
+ /* Skip verify of deprecated_frame_args_address, has predicate */
+ /* Skip verify of deprecated_frame_locals_address, has predicate */
+ /* Skip verify of deprecated_saved_pc_after_call, has predicate */
+ /* Skip verify of frame_num_args, has predicate */
+ /* Skip verify of deprecated_stack_align, has predicate */
+ /* Skip verify of frame_align, has predicate */
+ /* Skip verify of deprecated_reg_struct_has_addr, has predicate */
+ /* Skip verify of stabs_argument_has_addr, invalid_p == 0 */
+ if (current_gdbarch->float_format == 0)
+ current_gdbarch->float_format = default_float_format (current_gdbarch);
+ if (current_gdbarch->double_format == 0)
+ current_gdbarch->double_format = default_double_format (current_gdbarch);
+ if (current_gdbarch->long_double_format == 0)
+ current_gdbarch->long_double_format = default_double_format (current_gdbarch);
+ /* Skip verify of convert_from_func_ptr_addr, invalid_p == 0 */
+ /* Skip verify of addr_bits_remove, invalid_p == 0 */
+ /* Skip verify of smash_text_address, invalid_p == 0 */
+ /* Skip verify of software_single_step, has predicate */
+ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ && (current_gdbarch->print_insn == 0))
+ fprintf_unfiltered (log, "\n\tprint_insn");
+ /* Skip verify of skip_trampoline_code, invalid_p == 0 */
+ /* Skip verify of skip_solib_resolver, invalid_p == 0 */
+ /* Skip verify of in_solib_call_trampoline, invalid_p == 0 */
+ /* Skip verify of in_solib_return_trampoline, invalid_p == 0 */
+ /* Skip verify of pc_in_sigtramp, invalid_p == 0 */
+ /* Skip verify of sigtramp_start, has predicate */
+ /* Skip verify of sigtramp_end, has predicate */
+ /* Skip verify of in_function_epilogue_p, invalid_p == 0 */
+ /* Skip verify of construct_inferior_arguments, invalid_p == 0 */
+ /* Skip verify of elf_make_msymbol_special, invalid_p == 0 */
+ /* Skip verify of coff_make_msymbol_special, invalid_p == 0 */
+ /* Skip verify of name_of_malloc, invalid_p == 0 */
+ /* Skip verify of cannot_step_breakpoint, invalid_p == 0 */
+ /* Skip verify of have_nonsteppable_watchpoint, invalid_p == 0 */
+ /* Skip verify of address_class_type_flags, has predicate */
+ /* Skip verify of address_class_type_flags_to_name, has predicate */
+ /* Skip verify of address_class_name_to_type_flags, has predicate */
+ /* Skip verify of register_reggroup_p, invalid_p == 0 */
+ /* Skip verify of fetch_pointer_argument, has predicate */
+ /* Skip verify of regset_from_core_section, has predicate */
+ buf = ui_file_xstrdup (log, &dummy);
+ make_cleanup (xfree, buf);
+ if (strlen (buf) > 0)
+ internal_error (__FILE__, __LINE__,
+ "verify_gdbarch: the following are invalid ...%s",
+ buf);
+ do_cleanups (cleanups);
+}
+
+
+/* Print out the details of the current architecture. */
+
+/* NOTE/WARNING: The parameter is called ``current_gdbarch'' so that it
+ just happens to match the global variable ``current_gdbarch''. That
+ way macros refering to that variable get the local and not the global
+ version - ulgh. Once everything is parameterised with gdbarch, this
+ will go away. */
+
+void
+gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ fprintf_unfiltered (file,
+ "gdbarch_dump: GDB_MULTI_ARCH = %d\n",
+ GDB_MULTI_ARCH);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: convert_from_func_ptr_addr = 0x%08lx\n",
+ (long) current_gdbarch->convert_from_func_ptr_addr);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_frame_align_p() = %d\n",
+ gdbarch_frame_align_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: frame_align = 0x%08lx\n",
+ (long) current_gdbarch->frame_align);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_regset_from_core_section_p() = %d\n",
+ gdbarch_regset_from_core_section_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: regset_from_core_section = 0x%08lx\n",
+ (long) current_gdbarch->regset_from_core_section);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_return_value_p() = %d\n",
+ gdbarch_return_value_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: return_value = 0x%08lx\n",
+ (long) current_gdbarch->return_value);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: in_function_epilogue_p = 0x%08lx\n",
+ (long) current_gdbarch->in_function_epilogue_p);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: register_reggroup_p = 0x%08lx\n",
+ (long) current_gdbarch->register_reggroup_p);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stabs_argument_has_addr = 0x%08lx\n",
+ (long) current_gdbarch->stabs_argument_has_addr);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_pseudo_register_read_p() = %d\n",
+ gdbarch_pseudo_register_read_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: pseudo_register_read = 0x%08lx\n",
+ (long) current_gdbarch->pseudo_register_read);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_pseudo_register_write_p() = %d\n",
+ gdbarch_pseudo_register_write_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: pseudo_register_write = 0x%08lx\n",
+ (long) current_gdbarch->pseudo_register_write);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_address_class_name_to_type_flags_p() = %d\n",
+ gdbarch_address_class_name_to_type_flags_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: address_class_name_to_type_flags = 0x%08lx\n",
+ (long) current_gdbarch->address_class_name_to_type_flags);
+#ifdef ADDRESS_CLASS_TYPE_FLAGS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "ADDRESS_CLASS_TYPE_FLAGS_P()",
+ XSTRING (ADDRESS_CLASS_TYPE_FLAGS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ADDRESS_CLASS_TYPE_FLAGS_P() = %d\n",
+ ADDRESS_CLASS_TYPE_FLAGS_P ());
+#endif
+#ifdef ADDRESS_CLASS_TYPE_FLAGS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "ADDRESS_CLASS_TYPE_FLAGS(byte_size, dwarf2_addr_class)",
+ XSTRING (ADDRESS_CLASS_TYPE_FLAGS (byte_size, dwarf2_addr_class)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ADDRESS_CLASS_TYPE_FLAGS = <0x%08lx>\n",
+ (long) current_gdbarch->address_class_type_flags
+ /*ADDRESS_CLASS_TYPE_FLAGS ()*/);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_address_class_type_flags_to_name_p() = %d\n",
+ gdbarch_address_class_type_flags_to_name_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: address_class_type_flags_to_name = 0x%08lx\n",
+ (long) current_gdbarch->address_class_type_flags_to_name);
+#ifdef ADDRESS_TO_POINTER
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "ADDRESS_TO_POINTER(type, buf, addr)",
+ XSTRING (ADDRESS_TO_POINTER (type, buf, addr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ADDRESS_TO_POINTER = <0x%08lx>\n",
+ (long) current_gdbarch->address_to_pointer
+ /*ADDRESS_TO_POINTER ()*/);
+#endif
+#ifdef ADDR_BITS_REMOVE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "ADDR_BITS_REMOVE(addr)",
+ XSTRING (ADDR_BITS_REMOVE (addr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ADDR_BITS_REMOVE = <0x%08lx>\n",
+ (long) current_gdbarch->addr_bits_remove
+ /*ADDR_BITS_REMOVE ()*/);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_adjust_breakpoint_address_p() = %d\n",
+ gdbarch_adjust_breakpoint_address_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: adjust_breakpoint_address = 0x%08lx\n",
+ (long) current_gdbarch->adjust_breakpoint_address);
+#ifdef BELIEVE_PCC_PROMOTION
+ fprintf_unfiltered (file,
+ "gdbarch_dump: BELIEVE_PCC_PROMOTION # %s\n",
+ XSTRING (BELIEVE_PCC_PROMOTION));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: BELIEVE_PCC_PROMOTION = %d\n",
+ BELIEVE_PCC_PROMOTION);
+#endif
+#ifdef BELIEVE_PCC_PROMOTION_TYPE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: BELIEVE_PCC_PROMOTION_TYPE # %s\n",
+ XSTRING (BELIEVE_PCC_PROMOTION_TYPE));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: BELIEVE_PCC_PROMOTION_TYPE = %d\n",
+ BELIEVE_PCC_PROMOTION_TYPE);
+#endif
+#ifdef BREAKPOINT_FROM_PC
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "BREAKPOINT_FROM_PC(pcptr, lenptr)",
+ XSTRING (BREAKPOINT_FROM_PC (pcptr, lenptr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: BREAKPOINT_FROM_PC = <0x%08lx>\n",
+ (long) current_gdbarch->breakpoint_from_pc
+ /*BREAKPOINT_FROM_PC ()*/);
+#endif
+#ifdef CALL_DUMMY_LOCATION
+ fprintf_unfiltered (file,
+ "gdbarch_dump: CALL_DUMMY_LOCATION # %s\n",
+ XSTRING (CALL_DUMMY_LOCATION));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: CALL_DUMMY_LOCATION = %d\n",
+ CALL_DUMMY_LOCATION);
+#endif
+#ifdef CANNOT_FETCH_REGISTER
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "CANNOT_FETCH_REGISTER(regnum)",
+ XSTRING (CANNOT_FETCH_REGISTER (regnum)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: CANNOT_FETCH_REGISTER = <0x%08lx>\n",
+ (long) current_gdbarch->cannot_fetch_register
+ /*CANNOT_FETCH_REGISTER ()*/);
+#endif
+#ifdef CANNOT_STEP_BREAKPOINT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: CANNOT_STEP_BREAKPOINT # %s\n",
+ XSTRING (CANNOT_STEP_BREAKPOINT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: CANNOT_STEP_BREAKPOINT = %d\n",
+ CANNOT_STEP_BREAKPOINT);
+#endif
+#ifdef CANNOT_STORE_REGISTER
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "CANNOT_STORE_REGISTER(regnum)",
+ XSTRING (CANNOT_STORE_REGISTER (regnum)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: CANNOT_STORE_REGISTER = <0x%08lx>\n",
+ (long) current_gdbarch->cannot_store_register
+ /*CANNOT_STORE_REGISTER ()*/);
+#endif
+#ifdef COFF_MAKE_MSYMBOL_SPECIAL
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "COFF_MAKE_MSYMBOL_SPECIAL(val, msym)",
+ XSTRING (COFF_MAKE_MSYMBOL_SPECIAL (val, msym)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: COFF_MAKE_MSYMBOL_SPECIAL = <0x%08lx>\n",
+ (long) current_gdbarch->coff_make_msymbol_special
+ /*COFF_MAKE_MSYMBOL_SPECIAL ()*/);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: construct_inferior_arguments = 0x%08lx\n",
+ (long) current_gdbarch->construct_inferior_arguments);
+#ifdef CONVERT_REGISTER_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "CONVERT_REGISTER_P(regnum, type)",
+ XSTRING (CONVERT_REGISTER_P (regnum, type)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: CONVERT_REGISTER_P = <0x%08lx>\n",
+ (long) current_gdbarch->convert_register_p
+ /*CONVERT_REGISTER_P ()*/);
+#endif
+#ifdef DECR_PC_AFTER_BREAK
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DECR_PC_AFTER_BREAK # %s\n",
+ XSTRING (DECR_PC_AFTER_BREAK));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DECR_PC_AFTER_BREAK = %ld\n",
+ (long) DECR_PC_AFTER_BREAK);
+#endif
+#ifdef DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET # %s\n",
+ XSTRING (DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET = %ld\n",
+ (long) DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET);
+#endif
+#ifdef DEPRECATED_CALL_DUMMY_LENGTH
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_LENGTH # %s\n",
+ XSTRING (DEPRECATED_CALL_DUMMY_LENGTH));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_LENGTH = %d\n",
+ DEPRECATED_CALL_DUMMY_LENGTH);
+#endif
+#ifdef DEPRECATED_CALL_DUMMY_START_OFFSET
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_START_OFFSET # %s\n",
+ XSTRING (DEPRECATED_CALL_DUMMY_START_OFFSET));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_START_OFFSET = %ld\n",
+ (long) DEPRECATED_CALL_DUMMY_START_OFFSET);
+#endif
+#ifdef DEPRECATED_CALL_DUMMY_WORDS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_WORDS # %s\n",
+ XSTRING (DEPRECATED_CALL_DUMMY_WORDS));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_CALL_DUMMY_WORDS = 0x%08lx\n",
+ (long) DEPRECATED_CALL_DUMMY_WORDS);
+#endif
+#ifdef DEPRECATED_DO_REGISTERS_INFO_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_DO_REGISTERS_INFO_P()",
+ XSTRING (DEPRECATED_DO_REGISTERS_INFO_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_DO_REGISTERS_INFO_P() = %d\n",
+ DEPRECATED_DO_REGISTERS_INFO_P ());
+#endif
+#ifdef DEPRECATED_DO_REGISTERS_INFO
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_DO_REGISTERS_INFO(reg_nr, fpregs)",
+ XSTRING (DEPRECATED_DO_REGISTERS_INFO (reg_nr, fpregs)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_DO_REGISTERS_INFO = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_do_registers_info
+ /*DEPRECATED_DO_REGISTERS_INFO ()*/);
+#endif
+#ifdef DEPRECATED_DUMMY_WRITE_SP_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_DUMMY_WRITE_SP_P()",
+ XSTRING (DEPRECATED_DUMMY_WRITE_SP_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_DUMMY_WRITE_SP_P() = %d\n",
+ DEPRECATED_DUMMY_WRITE_SP_P ());
+#endif
+#ifdef DEPRECATED_DUMMY_WRITE_SP
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_DUMMY_WRITE_SP(val)",
+ XSTRING (DEPRECATED_DUMMY_WRITE_SP (val)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_DUMMY_WRITE_SP = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_dummy_write_sp
+ /*DEPRECATED_DUMMY_WRITE_SP ()*/);
+#endif
+#ifdef DEPRECATED_EXTRACT_RETURN_VALUE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_EXTRACT_RETURN_VALUE(type, regbuf, valbuf)",
+ XSTRING (DEPRECATED_EXTRACT_RETURN_VALUE (type, regbuf, valbuf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_EXTRACT_RETURN_VALUE = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_extract_return_value
+ /*DEPRECATED_EXTRACT_RETURN_VALUE ()*/);
+#endif
+#ifdef DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P()",
+ XSTRING (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P() = %d\n",
+ DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P ());
+#endif
+#ifdef DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS(regcache)",
+ XSTRING (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS (regcache)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_extract_struct_value_address
+ /*DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS ()*/);
+#endif
+#ifdef DEPRECATED_FIX_CALL_DUMMY_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FIX_CALL_DUMMY_P()",
+ XSTRING (DEPRECATED_FIX_CALL_DUMMY_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FIX_CALL_DUMMY_P() = %d\n",
+ DEPRECATED_FIX_CALL_DUMMY_P ());
+#endif
+#ifdef DEPRECATED_FIX_CALL_DUMMY
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FIX_CALL_DUMMY(dummy, pc, fun, nargs, args, type, gcc_p)",
+ XSTRING (DEPRECATED_FIX_CALL_DUMMY (dummy, pc, fun, nargs, args, type, gcc_p)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FIX_CALL_DUMMY = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_fix_call_dummy
+ /*DEPRECATED_FIX_CALL_DUMMY ()*/);
+#endif
+#ifdef DEPRECATED_FP_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FP_REGNUM # %s\n",
+ XSTRING (DEPRECATED_FP_REGNUM));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FP_REGNUM = %d\n",
+ DEPRECATED_FP_REGNUM);
+#endif
+#ifdef DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P()",
+ XSTRING (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P() = %d\n",
+ DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ());
+#endif
+#ifdef DEPRECATED_FRAMELESS_FUNCTION_INVOCATION
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAMELESS_FUNCTION_INVOCATION(fi)",
+ XSTRING (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION (fi)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAMELESS_FUNCTION_INVOCATION = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_frameless_function_invocation
+ /*DEPRECATED_FRAMELESS_FUNCTION_INVOCATION ()*/);
+#endif
+#ifdef DEPRECATED_FRAME_ARGS_ADDRESS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_ARGS_ADDRESS_P()",
+ XSTRING (DEPRECATED_FRAME_ARGS_ADDRESS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_ARGS_ADDRESS_P() = %d\n",
+ DEPRECATED_FRAME_ARGS_ADDRESS_P ());
+#endif
+#ifdef DEPRECATED_FRAME_ARGS_ADDRESS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_ARGS_ADDRESS(fi)",
+ XSTRING (DEPRECATED_FRAME_ARGS_ADDRESS (fi)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_ARGS_ADDRESS = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_frame_args_address
+ /*DEPRECATED_FRAME_ARGS_ADDRESS ()*/);
+#endif
+#ifdef DEPRECATED_FRAME_CHAIN_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_CHAIN_P()",
+ XSTRING (DEPRECATED_FRAME_CHAIN_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_CHAIN_P() = %d\n",
+ DEPRECATED_FRAME_CHAIN_P ());
+#endif
+#ifdef DEPRECATED_FRAME_CHAIN
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_CHAIN(frame)",
+ XSTRING (DEPRECATED_FRAME_CHAIN (frame)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_CHAIN = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_frame_chain
+ /*DEPRECATED_FRAME_CHAIN ()*/);
+#endif
+#ifdef DEPRECATED_FRAME_CHAIN_VALID_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_CHAIN_VALID_P()",
+ XSTRING (DEPRECATED_FRAME_CHAIN_VALID_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_CHAIN_VALID_P() = %d\n",
+ DEPRECATED_FRAME_CHAIN_VALID_P ());
+#endif
+#ifdef DEPRECATED_FRAME_CHAIN_VALID
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_CHAIN_VALID(chain, thisframe)",
+ XSTRING (DEPRECATED_FRAME_CHAIN_VALID (chain, thisframe)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_CHAIN_VALID = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_frame_chain_valid
+ /*DEPRECATED_FRAME_CHAIN_VALID ()*/);
+#endif
+#ifdef DEPRECATED_FRAME_INIT_SAVED_REGS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_INIT_SAVED_REGS_P()",
+ XSTRING (DEPRECATED_FRAME_INIT_SAVED_REGS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_INIT_SAVED_REGS_P() = %d\n",
+ DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
+#endif
+#ifdef DEPRECATED_FRAME_INIT_SAVED_REGS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_INIT_SAVED_REGS(frame)",
+ XSTRING (DEPRECATED_FRAME_INIT_SAVED_REGS (frame)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_INIT_SAVED_REGS = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_frame_init_saved_regs
+ /*DEPRECATED_FRAME_INIT_SAVED_REGS ()*/);
+#endif
+#ifdef DEPRECATED_FRAME_LOCALS_ADDRESS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_LOCALS_ADDRESS_P()",
+ XSTRING (DEPRECATED_FRAME_LOCALS_ADDRESS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_LOCALS_ADDRESS_P() = %d\n",
+ DEPRECATED_FRAME_LOCALS_ADDRESS_P ());
+#endif
+#ifdef DEPRECATED_FRAME_LOCALS_ADDRESS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_LOCALS_ADDRESS(fi)",
+ XSTRING (DEPRECATED_FRAME_LOCALS_ADDRESS (fi)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_LOCALS_ADDRESS = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_frame_locals_address
+ /*DEPRECATED_FRAME_LOCALS_ADDRESS ()*/);
+#endif
+#ifdef DEPRECATED_FRAME_SAVED_PC_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_SAVED_PC_P()",
+ XSTRING (DEPRECATED_FRAME_SAVED_PC_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_SAVED_PC_P() = %d\n",
+ DEPRECATED_FRAME_SAVED_PC_P ());
+#endif
+#ifdef DEPRECATED_FRAME_SAVED_PC
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_FRAME_SAVED_PC(fi)",
+ XSTRING (DEPRECATED_FRAME_SAVED_PC (fi)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_FRAME_SAVED_PC = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_frame_saved_pc
+ /*DEPRECATED_FRAME_SAVED_PC ()*/);
+#endif
+#ifdef DEPRECATED_GET_SAVED_REGISTER_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_GET_SAVED_REGISTER_P()",
+ XSTRING (DEPRECATED_GET_SAVED_REGISTER_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_GET_SAVED_REGISTER_P() = %d\n",
+ DEPRECATED_GET_SAVED_REGISTER_P ());
+#endif
+#ifdef DEPRECATED_GET_SAVED_REGISTER
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_GET_SAVED_REGISTER(raw_buffer, optimized, addrp, frame, regnum, lval)",
+ XSTRING (DEPRECATED_GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_GET_SAVED_REGISTER = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_get_saved_register
+ /*DEPRECATED_GET_SAVED_REGISTER ()*/);
+#endif
+#ifdef DEPRECATED_INIT_EXTRA_FRAME_INFO_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_INIT_EXTRA_FRAME_INFO_P()",
+ XSTRING (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_INIT_EXTRA_FRAME_INFO_P() = %d\n",
+ DEPRECATED_INIT_EXTRA_FRAME_INFO_P ());
+#endif
+#ifdef DEPRECATED_INIT_EXTRA_FRAME_INFO
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_INIT_EXTRA_FRAME_INFO(fromleaf, frame)",
+ XSTRING (DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, frame)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_INIT_EXTRA_FRAME_INFO = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_init_extra_frame_info
+ /*DEPRECATED_INIT_EXTRA_FRAME_INFO ()*/);
+#endif
+#ifdef DEPRECATED_INIT_FRAME_PC_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_INIT_FRAME_PC_P()",
+ XSTRING (DEPRECATED_INIT_FRAME_PC_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_INIT_FRAME_PC_P() = %d\n",
+ DEPRECATED_INIT_FRAME_PC_P ());
+#endif
+#ifdef DEPRECATED_INIT_FRAME_PC
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_INIT_FRAME_PC(fromleaf, prev)",
+ XSTRING (DEPRECATED_INIT_FRAME_PC (fromleaf, prev)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_INIT_FRAME_PC = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_init_frame_pc
+ /*DEPRECATED_INIT_FRAME_PC ()*/);
+#endif
+#ifdef DEPRECATED_INIT_FRAME_PC_FIRST_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_INIT_FRAME_PC_FIRST_P()",
+ XSTRING (DEPRECATED_INIT_FRAME_PC_FIRST_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_INIT_FRAME_PC_FIRST_P() = %d\n",
+ DEPRECATED_INIT_FRAME_PC_FIRST_P ());
+#endif
+#ifdef DEPRECATED_INIT_FRAME_PC_FIRST
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_INIT_FRAME_PC_FIRST(fromleaf, prev)",
+ XSTRING (DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf, prev)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_INIT_FRAME_PC_FIRST = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_init_frame_pc_first
+ /*DEPRECATED_INIT_FRAME_PC_FIRST ()*/);
+#endif
+#ifdef DEPRECATED_MAX_REGISTER_RAW_SIZE_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_MAX_REGISTER_RAW_SIZE_P()",
+ XSTRING (DEPRECATED_MAX_REGISTER_RAW_SIZE_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_MAX_REGISTER_RAW_SIZE_P() = %d\n",
+ DEPRECATED_MAX_REGISTER_RAW_SIZE_P ());
+#endif
+#ifdef DEPRECATED_MAX_REGISTER_RAW_SIZE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_MAX_REGISTER_RAW_SIZE # %s\n",
+ XSTRING (DEPRECATED_MAX_REGISTER_RAW_SIZE));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_MAX_REGISTER_RAW_SIZE = %d\n",
+ DEPRECATED_MAX_REGISTER_RAW_SIZE);
+#endif
+#ifdef DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P()",
+ XSTRING (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P() = %d\n",
+ DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P ());
+#endif
+#ifdef DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE # %s\n",
+ XSTRING (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE = %d\n",
+ DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE);
+#endif
+#ifdef DEPRECATED_PC_IN_CALL_DUMMY_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PC_IN_CALL_DUMMY_P()",
+ XSTRING (DEPRECATED_PC_IN_CALL_DUMMY_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PC_IN_CALL_DUMMY_P() = %d\n",
+ DEPRECATED_PC_IN_CALL_DUMMY_P ());
+#endif
+#ifdef DEPRECATED_PC_IN_CALL_DUMMY
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PC_IN_CALL_DUMMY(pc, sp, frame_address)",
+ XSTRING (DEPRECATED_PC_IN_CALL_DUMMY (pc, sp, frame_address)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PC_IN_CALL_DUMMY = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_pc_in_call_dummy
+ /*DEPRECATED_PC_IN_CALL_DUMMY ()*/);
+#endif
+#ifdef DEPRECATED_POP_FRAME_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_POP_FRAME_P()",
+ XSTRING (DEPRECATED_POP_FRAME_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_POP_FRAME_P() = %d\n",
+ DEPRECATED_POP_FRAME_P ());
+#endif
+#ifdef DEPRECATED_POP_FRAME
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_POP_FRAME(-)",
+ XSTRING (DEPRECATED_POP_FRAME (-)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_POP_FRAME = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_pop_frame
+ /*DEPRECATED_POP_FRAME ()*/);
+#endif
+#ifdef DEPRECATED_PUSH_ARGUMENTS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PUSH_ARGUMENTS_P()",
+ XSTRING (DEPRECATED_PUSH_ARGUMENTS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PUSH_ARGUMENTS_P() = %d\n",
+ DEPRECATED_PUSH_ARGUMENTS_P ());
+#endif
+#ifdef DEPRECATED_PUSH_ARGUMENTS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr)",
+ XSTRING (DEPRECATED_PUSH_ARGUMENTS (nargs, args, sp, struct_return, struct_addr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PUSH_ARGUMENTS = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_push_arguments
+ /*DEPRECATED_PUSH_ARGUMENTS ()*/);
+#endif
+#ifdef DEPRECATED_PUSH_DUMMY_FRAME_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PUSH_DUMMY_FRAME_P()",
+ XSTRING (DEPRECATED_PUSH_DUMMY_FRAME_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PUSH_DUMMY_FRAME_P() = %d\n",
+ DEPRECATED_PUSH_DUMMY_FRAME_P ());
+#endif
+#ifdef DEPRECATED_PUSH_DUMMY_FRAME
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PUSH_DUMMY_FRAME(-)",
+ XSTRING (DEPRECATED_PUSH_DUMMY_FRAME (-)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PUSH_DUMMY_FRAME = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_push_dummy_frame
+ /*DEPRECATED_PUSH_DUMMY_FRAME ()*/);
+#endif
+#ifdef DEPRECATED_PUSH_RETURN_ADDRESS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PUSH_RETURN_ADDRESS_P()",
+ XSTRING (DEPRECATED_PUSH_RETURN_ADDRESS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PUSH_RETURN_ADDRESS_P() = %d\n",
+ DEPRECATED_PUSH_RETURN_ADDRESS_P ());
+#endif
+#ifdef DEPRECATED_PUSH_RETURN_ADDRESS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_PUSH_RETURN_ADDRESS(pc, sp)",
+ XSTRING (DEPRECATED_PUSH_RETURN_ADDRESS (pc, sp)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_PUSH_RETURN_ADDRESS = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_push_return_address
+ /*DEPRECATED_PUSH_RETURN_ADDRESS ()*/);
+#endif
+#ifdef DEPRECATED_REGISTER_BYTE_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_BYTE_P()",
+ XSTRING (DEPRECATED_REGISTER_BYTE_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_BYTE_P() = %d\n",
+ DEPRECATED_REGISTER_BYTE_P ());
+#endif
+#ifdef DEPRECATED_REGISTER_BYTE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_BYTE(reg_nr)",
+ XSTRING (DEPRECATED_REGISTER_BYTE (reg_nr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_BYTE = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_register_byte
+ /*DEPRECATED_REGISTER_BYTE ()*/);
+#endif
+#ifdef DEPRECATED_REGISTER_BYTES
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_BYTES # %s\n",
+ XSTRING (DEPRECATED_REGISTER_BYTES));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_BYTES = %d\n",
+ DEPRECATED_REGISTER_BYTES);
+#endif
+#ifdef DEPRECATED_REGISTER_CONVERTIBLE_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_CONVERTIBLE_P()",
+ XSTRING (DEPRECATED_REGISTER_CONVERTIBLE_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_CONVERTIBLE_P() = %d\n",
+ DEPRECATED_REGISTER_CONVERTIBLE_P ());
+#endif
+#ifdef DEPRECATED_REGISTER_CONVERTIBLE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_CONVERTIBLE(nr)",
+ XSTRING (DEPRECATED_REGISTER_CONVERTIBLE (nr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_CONVERTIBLE = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_register_convertible
+ /*DEPRECATED_REGISTER_CONVERTIBLE ()*/);
+#endif
+#ifdef DEPRECATED_REGISTER_CONVERT_TO_RAW
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_CONVERT_TO_RAW(type, regnum, from, to)",
+ XSTRING (DEPRECATED_REGISTER_CONVERT_TO_RAW (type, regnum, from, to)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_CONVERT_TO_RAW = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_register_convert_to_raw
+ /*DEPRECATED_REGISTER_CONVERT_TO_RAW ()*/);
+#endif
+#ifdef DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL(regnum, type, from, to)",
+ XSTRING (DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (regnum, type, from, to)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_register_convert_to_virtual
+ /*DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL ()*/);
+#endif
+#ifdef DEPRECATED_REGISTER_RAW_SIZE_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_RAW_SIZE_P()",
+ XSTRING (DEPRECATED_REGISTER_RAW_SIZE_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_RAW_SIZE_P() = %d\n",
+ DEPRECATED_REGISTER_RAW_SIZE_P ());
+#endif
+#ifdef DEPRECATED_REGISTER_RAW_SIZE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_RAW_SIZE(reg_nr)",
+ XSTRING (DEPRECATED_REGISTER_RAW_SIZE (reg_nr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_RAW_SIZE = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_register_raw_size
+ /*DEPRECATED_REGISTER_RAW_SIZE ()*/);
+#endif
+#ifdef DEPRECATED_REGISTER_SIZE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_SIZE # %s\n",
+ XSTRING (DEPRECATED_REGISTER_SIZE));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_SIZE = %d\n",
+ DEPRECATED_REGISTER_SIZE);
+#endif
+#ifdef DEPRECATED_REGISTER_VIRTUAL_SIZE_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_VIRTUAL_SIZE_P()",
+ XSTRING (DEPRECATED_REGISTER_VIRTUAL_SIZE_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_VIRTUAL_SIZE_P() = %d\n",
+ DEPRECATED_REGISTER_VIRTUAL_SIZE_P ());
+#endif
+#ifdef DEPRECATED_REGISTER_VIRTUAL_SIZE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_VIRTUAL_SIZE(reg_nr)",
+ XSTRING (DEPRECATED_REGISTER_VIRTUAL_SIZE (reg_nr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_VIRTUAL_SIZE = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_register_virtual_size
+ /*DEPRECATED_REGISTER_VIRTUAL_SIZE ()*/);
+#endif
+#ifdef DEPRECATED_REGISTER_VIRTUAL_TYPE_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_VIRTUAL_TYPE_P()",
+ XSTRING (DEPRECATED_REGISTER_VIRTUAL_TYPE_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_VIRTUAL_TYPE_P() = %d\n",
+ DEPRECATED_REGISTER_VIRTUAL_TYPE_P ());
+#endif
+#ifdef DEPRECATED_REGISTER_VIRTUAL_TYPE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REGISTER_VIRTUAL_TYPE(reg_nr)",
+ XSTRING (DEPRECATED_REGISTER_VIRTUAL_TYPE (reg_nr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REGISTER_VIRTUAL_TYPE = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_register_virtual_type
+ /*DEPRECATED_REGISTER_VIRTUAL_TYPE ()*/);
+#endif
+#ifdef DEPRECATED_REG_STRUCT_HAS_ADDR_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REG_STRUCT_HAS_ADDR_P()",
+ XSTRING (DEPRECATED_REG_STRUCT_HAS_ADDR_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REG_STRUCT_HAS_ADDR_P() = %d\n",
+ DEPRECATED_REG_STRUCT_HAS_ADDR_P ());
+#endif
+#ifdef DEPRECATED_REG_STRUCT_HAS_ADDR
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_REG_STRUCT_HAS_ADDR(gcc_p, type)",
+ XSTRING (DEPRECATED_REG_STRUCT_HAS_ADDR (gcc_p, type)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_REG_STRUCT_HAS_ADDR = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_reg_struct_has_addr
+ /*DEPRECATED_REG_STRUCT_HAS_ADDR ()*/);
+#endif
+#ifdef DEPRECATED_SAVED_PC_AFTER_CALL_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_SAVED_PC_AFTER_CALL_P()",
+ XSTRING (DEPRECATED_SAVED_PC_AFTER_CALL_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_SAVED_PC_AFTER_CALL_P() = %d\n",
+ DEPRECATED_SAVED_PC_AFTER_CALL_P ());
+#endif
+#ifdef DEPRECATED_SAVED_PC_AFTER_CALL
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_SAVED_PC_AFTER_CALL(frame)",
+ XSTRING (DEPRECATED_SAVED_PC_AFTER_CALL (frame)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_SAVED_PC_AFTER_CALL = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_saved_pc_after_call
+ /*DEPRECATED_SAVED_PC_AFTER_CALL ()*/);
+#endif
+#ifdef DEPRECATED_SAVE_DUMMY_FRAME_TOS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_SAVE_DUMMY_FRAME_TOS_P()",
+ XSTRING (DEPRECATED_SAVE_DUMMY_FRAME_TOS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_SAVE_DUMMY_FRAME_TOS_P() = %d\n",
+ DEPRECATED_SAVE_DUMMY_FRAME_TOS_P ());
+#endif
+#ifdef DEPRECATED_SAVE_DUMMY_FRAME_TOS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_SAVE_DUMMY_FRAME_TOS(sp)",
+ XSTRING (DEPRECATED_SAVE_DUMMY_FRAME_TOS (sp)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_SAVE_DUMMY_FRAME_TOS = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_save_dummy_frame_tos
+ /*DEPRECATED_SAVE_DUMMY_FRAME_TOS ()*/);
+#endif
+#ifdef DEPRECATED_SIZEOF_CALL_DUMMY_WORDS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_SIZEOF_CALL_DUMMY_WORDS # %s\n",
+ XSTRING (DEPRECATED_SIZEOF_CALL_DUMMY_WORDS));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_SIZEOF_CALL_DUMMY_WORDS = %d\n",
+ DEPRECATED_SIZEOF_CALL_DUMMY_WORDS);
+#endif
+#ifdef DEPRECATED_STACK_ALIGN_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_STACK_ALIGN_P()",
+ XSTRING (DEPRECATED_STACK_ALIGN_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_STACK_ALIGN_P() = %d\n",
+ DEPRECATED_STACK_ALIGN_P ());
+#endif
+#ifdef DEPRECATED_STACK_ALIGN
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_STACK_ALIGN(sp)",
+ XSTRING (DEPRECATED_STACK_ALIGN (sp)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_STACK_ALIGN = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_stack_align
+ /*DEPRECATED_STACK_ALIGN ()*/);
+#endif
+#ifdef DEPRECATED_STORE_RETURN_VALUE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_STORE_RETURN_VALUE(type, valbuf)",
+ XSTRING (DEPRECATED_STORE_RETURN_VALUE (type, valbuf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_STORE_RETURN_VALUE = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_store_return_value
+ /*DEPRECATED_STORE_RETURN_VALUE ()*/);
+#endif
+#ifdef DEPRECATED_STORE_STRUCT_RETURN_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_STORE_STRUCT_RETURN_P()",
+ XSTRING (DEPRECATED_STORE_STRUCT_RETURN_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_STORE_STRUCT_RETURN_P() = %d\n",
+ DEPRECATED_STORE_STRUCT_RETURN_P ());
+#endif
+#ifdef DEPRECATED_STORE_STRUCT_RETURN
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_STORE_STRUCT_RETURN(addr, sp)",
+ XSTRING (DEPRECATED_STORE_STRUCT_RETURN (addr, sp)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_STORE_STRUCT_RETURN = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_store_struct_return
+ /*DEPRECATED_STORE_STRUCT_RETURN ()*/);
+#endif
+#ifdef DEPRECATED_TARGET_READ_FP_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_TARGET_READ_FP_P()",
+ XSTRING (DEPRECATED_TARGET_READ_FP_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_TARGET_READ_FP_P() = %d\n",
+ DEPRECATED_TARGET_READ_FP_P ());
+#endif
+#ifdef DEPRECATED_TARGET_READ_FP
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DEPRECATED_TARGET_READ_FP()",
+ XSTRING (DEPRECATED_TARGET_READ_FP ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_TARGET_READ_FP = <0x%08lx>\n",
+ (long) current_gdbarch->deprecated_target_read_fp
+ /*DEPRECATED_TARGET_READ_FP ()*/);
+#endif
+#ifdef DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_USE_GENERIC_DUMMY_FRAMES # %s\n",
+ XSTRING (DEPRECATED_USE_GENERIC_DUMMY_FRAMES));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DEPRECATED_USE_GENERIC_DUMMY_FRAMES = %d\n",
+ DEPRECATED_USE_GENERIC_DUMMY_FRAMES);
+#endif
+#ifdef DWARF2_REG_TO_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DWARF2_REG_TO_REGNUM(dwarf2_regnr)",
+ XSTRING (DWARF2_REG_TO_REGNUM (dwarf2_regnr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DWARF2_REG_TO_REGNUM = <0x%08lx>\n",
+ (long) current_gdbarch->dwarf2_reg_to_regnum
+ /*DWARF2_REG_TO_REGNUM ()*/);
+#endif
+#ifdef DWARF_REG_TO_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "DWARF_REG_TO_REGNUM(dwarf_regnr)",
+ XSTRING (DWARF_REG_TO_REGNUM (dwarf_regnr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: DWARF_REG_TO_REGNUM = <0x%08lx>\n",
+ (long) current_gdbarch->dwarf_reg_to_regnum
+ /*DWARF_REG_TO_REGNUM ()*/);
+#endif
+#ifdef ECOFF_REG_TO_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "ECOFF_REG_TO_REGNUM(ecoff_regnr)",
+ XSTRING (ECOFF_REG_TO_REGNUM (ecoff_regnr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ECOFF_REG_TO_REGNUM = <0x%08lx>\n",
+ (long) current_gdbarch->ecoff_reg_to_regnum
+ /*ECOFF_REG_TO_REGNUM ()*/);
+#endif
+#ifdef ELF_MAKE_MSYMBOL_SPECIAL
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "ELF_MAKE_MSYMBOL_SPECIAL(sym, msym)",
+ XSTRING (ELF_MAKE_MSYMBOL_SPECIAL (sym, msym)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ELF_MAKE_MSYMBOL_SPECIAL = <0x%08lx>\n",
+ (long) current_gdbarch->elf_make_msymbol_special
+ /*ELF_MAKE_MSYMBOL_SPECIAL ()*/);
+#endif
+#ifdef EXTRACT_RETURN_VALUE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "EXTRACT_RETURN_VALUE(type, regcache, valbuf)",
+ XSTRING (EXTRACT_RETURN_VALUE (type, regcache, valbuf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: EXTRACT_RETURN_VALUE = <0x%08lx>\n",
+ (long) current_gdbarch->extract_return_value
+ /*EXTRACT_RETURN_VALUE ()*/);
+#endif
+#ifdef FETCH_POINTER_ARGUMENT_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "FETCH_POINTER_ARGUMENT_P()",
+ XSTRING (FETCH_POINTER_ARGUMENT_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FETCH_POINTER_ARGUMENT_P() = %d\n",
+ FETCH_POINTER_ARGUMENT_P ());
+#endif
+#ifdef FETCH_POINTER_ARGUMENT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "FETCH_POINTER_ARGUMENT(frame, argi, type)",
+ XSTRING (FETCH_POINTER_ARGUMENT (frame, argi, type)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FETCH_POINTER_ARGUMENT = <0x%08lx>\n",
+ (long) current_gdbarch->fetch_pointer_argument
+ /*FETCH_POINTER_ARGUMENT ()*/);
+#endif
+#ifdef FP0_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FP0_REGNUM # %s\n",
+ XSTRING (FP0_REGNUM));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FP0_REGNUM = %d\n",
+ FP0_REGNUM);
+#endif
+#ifdef FRAME_ARGS_SKIP
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FRAME_ARGS_SKIP # %s\n",
+ XSTRING (FRAME_ARGS_SKIP));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FRAME_ARGS_SKIP = %ld\n",
+ (long) FRAME_ARGS_SKIP);
+#endif
+#ifdef FRAME_NUM_ARGS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "FRAME_NUM_ARGS_P()",
+ XSTRING (FRAME_NUM_ARGS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FRAME_NUM_ARGS_P() = %d\n",
+ FRAME_NUM_ARGS_P ());
+#endif
+#ifdef FRAME_NUM_ARGS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "FRAME_NUM_ARGS(frame)",
+ XSTRING (FRAME_NUM_ARGS (frame)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FRAME_NUM_ARGS = <0x%08lx>\n",
+ (long) current_gdbarch->frame_num_args
+ /*FRAME_NUM_ARGS ()*/);
+#endif
+#ifdef FRAME_RED_ZONE_SIZE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FRAME_RED_ZONE_SIZE # %s\n",
+ XSTRING (FRAME_RED_ZONE_SIZE));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FRAME_RED_ZONE_SIZE = %d\n",
+ FRAME_RED_ZONE_SIZE);
+#endif
+#ifdef FUNCTION_START_OFFSET
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FUNCTION_START_OFFSET # %s\n",
+ XSTRING (FUNCTION_START_OFFSET));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: FUNCTION_START_OFFSET = %ld\n",
+ (long) FUNCTION_START_OFFSET);
+#endif
+#ifdef GET_LONGJMP_TARGET_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "GET_LONGJMP_TARGET_P()",
+ XSTRING (GET_LONGJMP_TARGET_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: GET_LONGJMP_TARGET_P() = %d\n",
+ GET_LONGJMP_TARGET_P ());
+#endif
+#ifdef GET_LONGJMP_TARGET
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "GET_LONGJMP_TARGET(pc)",
+ XSTRING (GET_LONGJMP_TARGET (pc)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: GET_LONGJMP_TARGET = <0x%08lx>\n",
+ (long) current_gdbarch->get_longjmp_target
+ /*GET_LONGJMP_TARGET ()*/);
+#endif
+#ifdef HAVE_NONSTEPPABLE_WATCHPOINT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: HAVE_NONSTEPPABLE_WATCHPOINT # %s\n",
+ XSTRING (HAVE_NONSTEPPABLE_WATCHPOINT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: HAVE_NONSTEPPABLE_WATCHPOINT = %d\n",
+ HAVE_NONSTEPPABLE_WATCHPOINT);
+#endif
+#ifdef INNER_THAN
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "INNER_THAN(lhs, rhs)",
+ XSTRING (INNER_THAN (lhs, rhs)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: INNER_THAN = <0x%08lx>\n",
+ (long) current_gdbarch->inner_than
+ /*INNER_THAN ()*/);
+#endif
+#ifdef INTEGER_TO_ADDRESS_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "INTEGER_TO_ADDRESS_P()",
+ XSTRING (INTEGER_TO_ADDRESS_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: INTEGER_TO_ADDRESS_P() = %d\n",
+ INTEGER_TO_ADDRESS_P ());
+#endif
+#ifdef INTEGER_TO_ADDRESS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "INTEGER_TO_ADDRESS(type, buf)",
+ XSTRING (INTEGER_TO_ADDRESS (type, buf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: INTEGER_TO_ADDRESS = <0x%08lx>\n",
+ (long) current_gdbarch->integer_to_address
+ /*INTEGER_TO_ADDRESS ()*/);
+#endif
+#ifdef IN_SOLIB_CALL_TRAMPOLINE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "IN_SOLIB_CALL_TRAMPOLINE(pc, name)",
+ XSTRING (IN_SOLIB_CALL_TRAMPOLINE (pc, name)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: IN_SOLIB_CALL_TRAMPOLINE = <0x%08lx>\n",
+ (long) current_gdbarch->in_solib_call_trampoline
+ /*IN_SOLIB_CALL_TRAMPOLINE ()*/);
+#endif
+#ifdef IN_SOLIB_RETURN_TRAMPOLINE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "IN_SOLIB_RETURN_TRAMPOLINE(pc, name)",
+ XSTRING (IN_SOLIB_RETURN_TRAMPOLINE (pc, name)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: IN_SOLIB_RETURN_TRAMPOLINE = <0x%08lx>\n",
+ (long) current_gdbarch->in_solib_return_trampoline
+ /*IN_SOLIB_RETURN_TRAMPOLINE ()*/);
+#endif
+#ifdef MEMORY_INSERT_BREAKPOINT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "MEMORY_INSERT_BREAKPOINT(addr, contents_cache)",
+ XSTRING (MEMORY_INSERT_BREAKPOINT (addr, contents_cache)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: MEMORY_INSERT_BREAKPOINT = <0x%08lx>\n",
+ (long) current_gdbarch->memory_insert_breakpoint
+ /*MEMORY_INSERT_BREAKPOINT ()*/);
+#endif
+#ifdef MEMORY_REMOVE_BREAKPOINT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "MEMORY_REMOVE_BREAKPOINT(addr, contents_cache)",
+ XSTRING (MEMORY_REMOVE_BREAKPOINT (addr, contents_cache)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: MEMORY_REMOVE_BREAKPOINT = <0x%08lx>\n",
+ (long) current_gdbarch->memory_remove_breakpoint
+ /*MEMORY_REMOVE_BREAKPOINT ()*/);
+#endif
+#ifdef NAME_OF_MALLOC
+ fprintf_unfiltered (file,
+ "gdbarch_dump: NAME_OF_MALLOC # %s\n",
+ XSTRING (NAME_OF_MALLOC));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: NAME_OF_MALLOC = %s\n",
+ NAME_OF_MALLOC);
+#endif
+#ifdef NUM_PSEUDO_REGS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: NUM_PSEUDO_REGS # %s\n",
+ XSTRING (NUM_PSEUDO_REGS));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: NUM_PSEUDO_REGS = %d\n",
+ NUM_PSEUDO_REGS);
+#endif
+#ifdef NUM_REGS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: NUM_REGS # %s\n",
+ XSTRING (NUM_REGS));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: NUM_REGS = %d\n",
+ NUM_REGS);
+#endif
+#ifdef PARM_BOUNDARY
+ fprintf_unfiltered (file,
+ "gdbarch_dump: PARM_BOUNDARY # %s\n",
+ XSTRING (PARM_BOUNDARY));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: PARM_BOUNDARY = %d\n",
+ PARM_BOUNDARY);
+#endif
+#ifdef PC_IN_SIGTRAMP
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "PC_IN_SIGTRAMP(pc, name)",
+ XSTRING (PC_IN_SIGTRAMP (pc, name)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: PC_IN_SIGTRAMP = <0x%08lx>\n",
+ (long) current_gdbarch->pc_in_sigtramp
+ /*PC_IN_SIGTRAMP ()*/);
+#endif
+#ifdef PC_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: PC_REGNUM # %s\n",
+ XSTRING (PC_REGNUM));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: PC_REGNUM = %d\n",
+ PC_REGNUM);
+#endif
+#ifdef POINTER_TO_ADDRESS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "POINTER_TO_ADDRESS(type, buf)",
+ XSTRING (POINTER_TO_ADDRESS (type, buf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: POINTER_TO_ADDRESS = <0x%08lx>\n",
+ (long) current_gdbarch->pointer_to_address
+ /*POINTER_TO_ADDRESS ()*/);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_print_float_info_p() = %d\n",
+ gdbarch_print_float_info_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: print_float_info = 0x%08lx\n",
+ (long) current_gdbarch->print_float_info);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: print_registers_info = 0x%08lx\n",
+ (long) current_gdbarch->print_registers_info);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_print_vector_info_p() = %d\n",
+ gdbarch_print_vector_info_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: print_vector_info = 0x%08lx\n",
+ (long) current_gdbarch->print_vector_info);
+#ifdef PS_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: PS_REGNUM # %s\n",
+ XSTRING (PS_REGNUM));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: PS_REGNUM = %d\n",
+ PS_REGNUM);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_push_dummy_call_p() = %d\n",
+ gdbarch_push_dummy_call_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: push_dummy_call = 0x%08lx\n",
+ (long) current_gdbarch->push_dummy_call);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_push_dummy_code_p() = %d\n",
+ gdbarch_push_dummy_code_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: push_dummy_code = 0x%08lx\n",
+ (long) current_gdbarch->push_dummy_code);
+#ifdef REGISTER_BYTES_OK_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "REGISTER_BYTES_OK_P()",
+ XSTRING (REGISTER_BYTES_OK_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: REGISTER_BYTES_OK_P() = %d\n",
+ REGISTER_BYTES_OK_P ());
+#endif
+#ifdef REGISTER_BYTES_OK
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "REGISTER_BYTES_OK(nr_bytes)",
+ XSTRING (REGISTER_BYTES_OK (nr_bytes)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: REGISTER_BYTES_OK = <0x%08lx>\n",
+ (long) current_gdbarch->register_bytes_ok
+ /*REGISTER_BYTES_OK ()*/);
+#endif
+#ifdef REGISTER_NAME
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "REGISTER_NAME(regnr)",
+ XSTRING (REGISTER_NAME (regnr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: REGISTER_NAME = <0x%08lx>\n",
+ (long) current_gdbarch->register_name
+ /*REGISTER_NAME ()*/);
+#endif
+#ifdef REGISTER_SIM_REGNO
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "REGISTER_SIM_REGNO(reg_nr)",
+ XSTRING (REGISTER_SIM_REGNO (reg_nr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: REGISTER_SIM_REGNO = <0x%08lx>\n",
+ (long) current_gdbarch->register_sim_regno
+ /*REGISTER_SIM_REGNO ()*/);
+#endif
+#ifdef REGISTER_TO_VALUE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "REGISTER_TO_VALUE(frame, regnum, type, buf)",
+ XSTRING (REGISTER_TO_VALUE (frame, regnum, type, buf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: REGISTER_TO_VALUE = <0x%08lx>\n",
+ (long) current_gdbarch->register_to_value
+ /*REGISTER_TO_VALUE ()*/);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_register_type_p() = %d\n",
+ gdbarch_register_type_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: register_type = 0x%08lx\n",
+ (long) current_gdbarch->register_type);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: remote_translate_xfer_address = 0x%08lx\n",
+ (long) current_gdbarch->remote_translate_xfer_address);
+#ifdef RETURN_VALUE_ON_STACK
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "RETURN_VALUE_ON_STACK(type)",
+ XSTRING (RETURN_VALUE_ON_STACK (type)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: RETURN_VALUE_ON_STACK = <0x%08lx>\n",
+ (long) current_gdbarch->return_value_on_stack
+ /*RETURN_VALUE_ON_STACK ()*/);
+#endif
+#ifdef SDB_REG_TO_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SDB_REG_TO_REGNUM(sdb_regnr)",
+ XSTRING (SDB_REG_TO_REGNUM (sdb_regnr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SDB_REG_TO_REGNUM = <0x%08lx>\n",
+ (long) current_gdbarch->sdb_reg_to_regnum
+ /*SDB_REG_TO_REGNUM ()*/);
+#endif
+#ifdef SIGTRAMP_END_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SIGTRAMP_END_P()",
+ XSTRING (SIGTRAMP_END_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SIGTRAMP_END_P() = %d\n",
+ SIGTRAMP_END_P ());
+#endif
+#ifdef SIGTRAMP_END
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SIGTRAMP_END(pc)",
+ XSTRING (SIGTRAMP_END (pc)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SIGTRAMP_END = <0x%08lx>\n",
+ (long) current_gdbarch->sigtramp_end
+ /*SIGTRAMP_END ()*/);
+#endif
+#ifdef SIGTRAMP_START_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SIGTRAMP_START_P()",
+ XSTRING (SIGTRAMP_START_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SIGTRAMP_START_P() = %d\n",
+ SIGTRAMP_START_P ());
+#endif
+#ifdef SIGTRAMP_START
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SIGTRAMP_START(pc)",
+ XSTRING (SIGTRAMP_START (pc)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SIGTRAMP_START = <0x%08lx>\n",
+ (long) current_gdbarch->sigtramp_start
+ /*SIGTRAMP_START ()*/);
+#endif
+#ifdef SKIP_PROLOGUE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SKIP_PROLOGUE(ip)",
+ XSTRING (SKIP_PROLOGUE (ip)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SKIP_PROLOGUE = <0x%08lx>\n",
+ (long) current_gdbarch->skip_prologue
+ /*SKIP_PROLOGUE ()*/);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: skip_solib_resolver = 0x%08lx\n",
+ (long) current_gdbarch->skip_solib_resolver);
+#ifdef SKIP_TRAMPOLINE_CODE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SKIP_TRAMPOLINE_CODE(pc)",
+ XSTRING (SKIP_TRAMPOLINE_CODE (pc)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SKIP_TRAMPOLINE_CODE = <0x%08lx>\n",
+ (long) current_gdbarch->skip_trampoline_code
+ /*SKIP_TRAMPOLINE_CODE ()*/);
+#endif
+#ifdef SMASH_TEXT_ADDRESS
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SMASH_TEXT_ADDRESS(addr)",
+ XSTRING (SMASH_TEXT_ADDRESS (addr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SMASH_TEXT_ADDRESS = <0x%08lx>\n",
+ (long) current_gdbarch->smash_text_address
+ /*SMASH_TEXT_ADDRESS ()*/);
+#endif
+#ifdef SOFTWARE_SINGLE_STEP_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SOFTWARE_SINGLE_STEP_P()",
+ XSTRING (SOFTWARE_SINGLE_STEP_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SOFTWARE_SINGLE_STEP_P() = %d\n",
+ SOFTWARE_SINGLE_STEP_P ());
+#endif
+#ifdef SOFTWARE_SINGLE_STEP
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "SOFTWARE_SINGLE_STEP(sig, insert_breakpoints_p)",
+ XSTRING (SOFTWARE_SINGLE_STEP (sig, insert_breakpoints_p)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SOFTWARE_SINGLE_STEP = <0x%08lx>\n",
+ (long) current_gdbarch->software_single_step
+ /*SOFTWARE_SINGLE_STEP ()*/);
+#endif
+#ifdef SP_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SP_REGNUM # %s\n",
+ XSTRING (SP_REGNUM));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: SP_REGNUM = %d\n",
+ SP_REGNUM);
+#endif
+#ifdef STAB_REG_TO_REGNUM
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "STAB_REG_TO_REGNUM(stab_regnr)",
+ XSTRING (STAB_REG_TO_REGNUM (stab_regnr)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: STAB_REG_TO_REGNUM = <0x%08lx>\n",
+ (long) current_gdbarch->stab_reg_to_regnum
+ /*STAB_REG_TO_REGNUM ()*/);
+#endif
+#ifdef STORE_RETURN_VALUE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "STORE_RETURN_VALUE(type, regcache, valbuf)",
+ XSTRING (STORE_RETURN_VALUE (type, regcache, valbuf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: STORE_RETURN_VALUE = <0x%08lx>\n",
+ (long) current_gdbarch->store_return_value
+ /*STORE_RETURN_VALUE ()*/);
+#endif
+#ifdef TARGET_ADDR_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_ADDR_BIT # %s\n",
+ XSTRING (TARGET_ADDR_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_ADDR_BIT = %d\n",
+ TARGET_ADDR_BIT);
+#endif
+#ifdef TARGET_ARCHITECTURE
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_ARCHITECTURE # %s\n",
+ XSTRING (TARGET_ARCHITECTURE));
+ if (TARGET_ARCHITECTURE != NULL)
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_ARCHITECTURE = %s\n",
+ TARGET_ARCHITECTURE->printable_name);
+#endif
+#ifdef TARGET_BFD_VMA_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_BFD_VMA_BIT # %s\n",
+ XSTRING (TARGET_BFD_VMA_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_BFD_VMA_BIT = %d\n",
+ TARGET_BFD_VMA_BIT);
+#endif
+#ifdef TARGET_BYTE_ORDER
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_BYTE_ORDER # %s\n",
+ XSTRING (TARGET_BYTE_ORDER));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_BYTE_ORDER = %ld\n",
+ (long) TARGET_BYTE_ORDER);
+#endif
+#ifdef TARGET_CHAR_SIGNED
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_CHAR_SIGNED # %s\n",
+ XSTRING (TARGET_CHAR_SIGNED));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_CHAR_SIGNED = %d\n",
+ TARGET_CHAR_SIGNED);
+#endif
+#ifdef TARGET_DOUBLE_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_DOUBLE_BIT # %s\n",
+ XSTRING (TARGET_DOUBLE_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_DOUBLE_BIT = %d\n",
+ TARGET_DOUBLE_BIT);
+#endif
+#ifdef TARGET_DOUBLE_FORMAT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_DOUBLE_FORMAT # %s\n",
+ XSTRING (TARGET_DOUBLE_FORMAT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_DOUBLE_FORMAT = %s\n",
+ (TARGET_DOUBLE_FORMAT)->name);
+#endif
+#ifdef TARGET_FLOAT_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_FLOAT_BIT # %s\n",
+ XSTRING (TARGET_FLOAT_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_FLOAT_BIT = %d\n",
+ TARGET_FLOAT_BIT);
+#endif
+#ifdef TARGET_FLOAT_FORMAT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_FLOAT_FORMAT # %s\n",
+ XSTRING (TARGET_FLOAT_FORMAT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_FLOAT_FORMAT = %s\n",
+ (TARGET_FLOAT_FORMAT)->name);
+#endif
+#ifdef TARGET_INT_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_INT_BIT # %s\n",
+ XSTRING (TARGET_INT_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_INT_BIT = %d\n",
+ TARGET_INT_BIT);
+#endif
+#ifdef TARGET_LONG_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_BIT # %s\n",
+ XSTRING (TARGET_LONG_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_BIT = %d\n",
+ TARGET_LONG_BIT);
+#endif
+#ifdef TARGET_LONG_DOUBLE_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_DOUBLE_BIT # %s\n",
+ XSTRING (TARGET_LONG_DOUBLE_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_DOUBLE_BIT = %d\n",
+ TARGET_LONG_DOUBLE_BIT);
+#endif
+#ifdef TARGET_LONG_DOUBLE_FORMAT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_DOUBLE_FORMAT # %s\n",
+ XSTRING (TARGET_LONG_DOUBLE_FORMAT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_DOUBLE_FORMAT = %s\n",
+ (TARGET_LONG_DOUBLE_FORMAT)->name);
+#endif
+#ifdef TARGET_LONG_LONG_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_LONG_BIT # %s\n",
+ XSTRING (TARGET_LONG_LONG_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_LONG_LONG_BIT = %d\n",
+ TARGET_LONG_LONG_BIT);
+#endif
+#ifdef TARGET_OSABI
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_OSABI # %s\n",
+ XSTRING (TARGET_OSABI));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_OSABI = %ld\n",
+ (long) TARGET_OSABI);
+#endif
+#ifdef TARGET_PRINT_INSN
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "TARGET_PRINT_INSN(vma, info)",
+ XSTRING (TARGET_PRINT_INSN (vma, info)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_PRINT_INSN = <0x%08lx>\n",
+ (long) current_gdbarch->print_insn
+ /*TARGET_PRINT_INSN ()*/);
+#endif
+#ifdef TARGET_PTR_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_PTR_BIT # %s\n",
+ XSTRING (TARGET_PTR_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_PTR_BIT = %d\n",
+ TARGET_PTR_BIT);
+#endif
+#ifdef TARGET_READ_PC_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "TARGET_READ_PC_P()",
+ XSTRING (TARGET_READ_PC_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_READ_PC_P() = %d\n",
+ TARGET_READ_PC_P ());
+#endif
+#ifdef TARGET_READ_PC
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "TARGET_READ_PC(ptid)",
+ XSTRING (TARGET_READ_PC (ptid)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_READ_PC = <0x%08lx>\n",
+ (long) current_gdbarch->read_pc
+ /*TARGET_READ_PC ()*/);
+#endif
+#ifdef TARGET_READ_SP_P
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "TARGET_READ_SP_P()",
+ XSTRING (TARGET_READ_SP_P ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_READ_SP_P() = %d\n",
+ TARGET_READ_SP_P ());
+#endif
+#ifdef TARGET_READ_SP
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "TARGET_READ_SP()",
+ XSTRING (TARGET_READ_SP ()));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_READ_SP = <0x%08lx>\n",
+ (long) current_gdbarch->read_sp
+ /*TARGET_READ_SP ()*/);
+#endif
+#ifdef TARGET_SHORT_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_SHORT_BIT # %s\n",
+ XSTRING (TARGET_SHORT_BIT));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_SHORT_BIT = %d\n",
+ TARGET_SHORT_BIT);
+#endif
+#ifdef TARGET_VIRTUAL_FRAME_POINTER
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "TARGET_VIRTUAL_FRAME_POINTER(pc, frame_regnum, frame_offset)",
+ XSTRING (TARGET_VIRTUAL_FRAME_POINTER (pc, frame_regnum, frame_offset)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_VIRTUAL_FRAME_POINTER = <0x%08lx>\n",
+ (long) current_gdbarch->virtual_frame_pointer
+ /*TARGET_VIRTUAL_FRAME_POINTER ()*/);
+#endif
+#ifdef TARGET_WRITE_PC
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "TARGET_WRITE_PC(val, ptid)",
+ XSTRING (TARGET_WRITE_PC (val, ptid)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_WRITE_PC = <0x%08lx>\n",
+ (long) current_gdbarch->write_pc
+ /*TARGET_WRITE_PC ()*/);
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_unwind_dummy_id_p() = %d\n",
+ gdbarch_unwind_dummy_id_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: unwind_dummy_id = 0x%08lx\n",
+ (long) current_gdbarch->unwind_dummy_id);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
+ gdbarch_unwind_pc_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: unwind_pc = 0x%08lx\n",
+ (long) current_gdbarch->unwind_pc);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_unwind_sp_p() = %d\n",
+ gdbarch_unwind_sp_p (current_gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: unwind_sp = 0x%08lx\n",
+ (long) current_gdbarch->unwind_sp);
+#ifdef USE_STRUCT_CONVENTION
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "USE_STRUCT_CONVENTION(gcc_p, value_type)",
+ XSTRING (USE_STRUCT_CONVENTION (gcc_p, value_type)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: USE_STRUCT_CONVENTION = <0x%08lx>\n",
+ (long) current_gdbarch->use_struct_convention
+ /*USE_STRUCT_CONVENTION ()*/);
+#endif
+#ifdef VALUE_TO_REGISTER
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "VALUE_TO_REGISTER(frame, regnum, type, buf)",
+ XSTRING (VALUE_TO_REGISTER (frame, regnum, type, buf)));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: VALUE_TO_REGISTER = <0x%08lx>\n",
+ (long) current_gdbarch->value_to_register
+ /*VALUE_TO_REGISTER ()*/);
+#endif
+ if (current_gdbarch->dump_tdep != NULL)
+ current_gdbarch->dump_tdep (current_gdbarch, file);
+}
+
+struct gdbarch_tdep *
+gdbarch_tdep (struct gdbarch *gdbarch)
+{
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_tdep called\n");
+ return gdbarch->tdep;
+}
+
+
+const struct bfd_arch_info *
+gdbarch_bfd_arch_info (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_bfd_arch_info called\n");
+ return gdbarch->bfd_arch_info;
+}
+
+int
+gdbarch_byte_order (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_byte_order called\n");
+ return gdbarch->byte_order;
+}
+
+enum gdb_osabi
+gdbarch_osabi (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_osabi called\n");
+ return gdbarch->osabi;
+}
+
+int
+gdbarch_short_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of short_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_short_bit called\n");
+ return gdbarch->short_bit;
+}
+
+void
+set_gdbarch_short_bit (struct gdbarch *gdbarch,
+ int short_bit)
+{
+ gdbarch->short_bit = short_bit;
+}
+
+int
+gdbarch_int_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of int_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_int_bit called\n");
+ return gdbarch->int_bit;
+}
+
+void
+set_gdbarch_int_bit (struct gdbarch *gdbarch,
+ int int_bit)
+{
+ gdbarch->int_bit = int_bit;
+}
+
+int
+gdbarch_long_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of long_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_long_bit called\n");
+ return gdbarch->long_bit;
+}
+
+void
+set_gdbarch_long_bit (struct gdbarch *gdbarch,
+ int long_bit)
+{
+ gdbarch->long_bit = long_bit;
+}
+
+int
+gdbarch_long_long_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of long_long_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_long_long_bit called\n");
+ return gdbarch->long_long_bit;
+}
+
+void
+set_gdbarch_long_long_bit (struct gdbarch *gdbarch,
+ int long_long_bit)
+{
+ gdbarch->long_long_bit = long_long_bit;
+}
+
+int
+gdbarch_float_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of float_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_float_bit called\n");
+ return gdbarch->float_bit;
+}
+
+void
+set_gdbarch_float_bit (struct gdbarch *gdbarch,
+ int float_bit)
+{
+ gdbarch->float_bit = float_bit;
+}
+
+int
+gdbarch_double_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of double_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_double_bit called\n");
+ return gdbarch->double_bit;
+}
+
+void
+set_gdbarch_double_bit (struct gdbarch *gdbarch,
+ int double_bit)
+{
+ gdbarch->double_bit = double_bit;
+}
+
+int
+gdbarch_long_double_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of long_double_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_long_double_bit called\n");
+ return gdbarch->long_double_bit;
+}
+
+void
+set_gdbarch_long_double_bit (struct gdbarch *gdbarch,
+ int long_double_bit)
+{
+ gdbarch->long_double_bit = long_double_bit;
+}
+
+int
+gdbarch_ptr_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of ptr_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_ptr_bit called\n");
+ return gdbarch->ptr_bit;
+}
+
+void
+set_gdbarch_ptr_bit (struct gdbarch *gdbarch,
+ int ptr_bit)
+{
+ gdbarch->ptr_bit = ptr_bit;
+}
+
+int
+gdbarch_addr_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Check variable changed from pre-default. */
+ gdb_assert (gdbarch->addr_bit != 0);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_addr_bit called\n");
+ return gdbarch->addr_bit;
+}
+
+void
+set_gdbarch_addr_bit (struct gdbarch *gdbarch,
+ int addr_bit)
+{
+ gdbarch->addr_bit = addr_bit;
+}
+
+int
+gdbarch_bfd_vma_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of bfd_vma_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_bfd_vma_bit called\n");
+ return gdbarch->bfd_vma_bit;
+}
+
+void
+set_gdbarch_bfd_vma_bit (struct gdbarch *gdbarch,
+ int bfd_vma_bit)
+{
+ gdbarch->bfd_vma_bit = bfd_vma_bit;
+}
+
+int
+gdbarch_char_signed (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Check variable changed from pre-default. */
+ gdb_assert (gdbarch->char_signed != -1);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_char_signed called\n");
+ return gdbarch->char_signed;
+}
+
+void
+set_gdbarch_char_signed (struct gdbarch *gdbarch,
+ int char_signed)
+{
+ gdbarch->char_signed = char_signed;
+}
+
+int
+gdbarch_read_pc_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->read_pc != NULL;
+}
+
+CORE_ADDR
+gdbarch_read_pc (struct gdbarch *gdbarch, ptid_t ptid)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->read_pc != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_read_pc called\n");
+ return gdbarch->read_pc (ptid);
+}
+
+void
+set_gdbarch_read_pc (struct gdbarch *gdbarch,
+ gdbarch_read_pc_ftype read_pc)
+{
+ gdbarch->read_pc = read_pc;
+}
+
+void
+gdbarch_write_pc (struct gdbarch *gdbarch, CORE_ADDR val, ptid_t ptid)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->write_pc != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_write_pc called\n");
+ gdbarch->write_pc (val, ptid);
+}
+
+void
+set_gdbarch_write_pc (struct gdbarch *gdbarch,
+ gdbarch_write_pc_ftype write_pc)
+{
+ gdbarch->write_pc = write_pc;
+}
+
+int
+gdbarch_read_sp_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->read_sp != NULL;
+}
+
+CORE_ADDR
+gdbarch_read_sp (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->read_sp != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_read_sp called\n");
+ return gdbarch->read_sp ();
+}
+
+void
+set_gdbarch_read_sp (struct gdbarch *gdbarch,
+ gdbarch_read_sp_ftype read_sp)
+{
+ gdbarch->read_sp = read_sp;
+}
+
+void
+gdbarch_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc, int *frame_regnum, LONGEST *frame_offset)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->virtual_frame_pointer != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_virtual_frame_pointer called\n");
+ gdbarch->virtual_frame_pointer (pc, frame_regnum, frame_offset);
+}
+
+void
+set_gdbarch_virtual_frame_pointer (struct gdbarch *gdbarch,
+ gdbarch_virtual_frame_pointer_ftype virtual_frame_pointer)
+{
+ gdbarch->virtual_frame_pointer = virtual_frame_pointer;
+}
+
+int
+gdbarch_pseudo_register_read_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->pseudo_register_read != NULL;
+}
+
+void
+gdbarch_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, void *buf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->pseudo_register_read != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_pseudo_register_read called\n");
+ gdbarch->pseudo_register_read (gdbarch, regcache, cookednum, buf);
+}
+
+void
+set_gdbarch_pseudo_register_read (struct gdbarch *gdbarch,
+ gdbarch_pseudo_register_read_ftype pseudo_register_read)
+{
+ gdbarch->pseudo_register_read = pseudo_register_read;
+}
+
+int
+gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->pseudo_register_write != NULL;
+}
+
+void
+gdbarch_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const void *buf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->pseudo_register_write != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_pseudo_register_write called\n");
+ gdbarch->pseudo_register_write (gdbarch, regcache, cookednum, buf);
+}
+
+void
+set_gdbarch_pseudo_register_write (struct gdbarch *gdbarch,
+ gdbarch_pseudo_register_write_ftype pseudo_register_write)
+{
+ gdbarch->pseudo_register_write = pseudo_register_write;
+}
+
+int
+gdbarch_num_regs (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Check variable changed from pre-default. */
+ gdb_assert (gdbarch->num_regs != -1);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_num_regs called\n");
+ return gdbarch->num_regs;
+}
+
+void
+set_gdbarch_num_regs (struct gdbarch *gdbarch,
+ int num_regs)
+{
+ gdbarch->num_regs = num_regs;
+}
+
+int
+gdbarch_num_pseudo_regs (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of num_pseudo_regs, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_num_pseudo_regs called\n");
+ return gdbarch->num_pseudo_regs;
+}
+
+void
+set_gdbarch_num_pseudo_regs (struct gdbarch *gdbarch,
+ int num_pseudo_regs)
+{
+ gdbarch->num_pseudo_regs = num_pseudo_regs;
+}
+
+int
+gdbarch_sp_regnum (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of sp_regnum, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_sp_regnum called\n");
+ return gdbarch->sp_regnum;
+}
+
+void
+set_gdbarch_sp_regnum (struct gdbarch *gdbarch,
+ int sp_regnum)
+{
+ gdbarch->sp_regnum = sp_regnum;
+}
+
+int
+gdbarch_pc_regnum (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of pc_regnum, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_pc_regnum called\n");
+ return gdbarch->pc_regnum;
+}
+
+void
+set_gdbarch_pc_regnum (struct gdbarch *gdbarch,
+ int pc_regnum)
+{
+ gdbarch->pc_regnum = pc_regnum;
+}
+
+int
+gdbarch_ps_regnum (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of ps_regnum, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_ps_regnum called\n");
+ return gdbarch->ps_regnum;
+}
+
+void
+set_gdbarch_ps_regnum (struct gdbarch *gdbarch,
+ int ps_regnum)
+{
+ gdbarch->ps_regnum = ps_regnum;
+}
+
+int
+gdbarch_fp0_regnum (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of fp0_regnum, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_fp0_regnum called\n");
+ return gdbarch->fp0_regnum;
+}
+
+void
+set_gdbarch_fp0_regnum (struct gdbarch *gdbarch,
+ int fp0_regnum)
+{
+ gdbarch->fp0_regnum = fp0_regnum;
+}
+
+int
+gdbarch_stab_reg_to_regnum (struct gdbarch *gdbarch, int stab_regnr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->stab_reg_to_regnum != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stab_reg_to_regnum called\n");
+ return gdbarch->stab_reg_to_regnum (stab_regnr);
+}
+
+void
+set_gdbarch_stab_reg_to_regnum (struct gdbarch *gdbarch,
+ gdbarch_stab_reg_to_regnum_ftype stab_reg_to_regnum)
+{
+ gdbarch->stab_reg_to_regnum = stab_reg_to_regnum;
+}
+
+int
+gdbarch_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int ecoff_regnr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->ecoff_reg_to_regnum != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_ecoff_reg_to_regnum called\n");
+ return gdbarch->ecoff_reg_to_regnum (ecoff_regnr);
+}
+
+void
+set_gdbarch_ecoff_reg_to_regnum (struct gdbarch *gdbarch,
+ gdbarch_ecoff_reg_to_regnum_ftype ecoff_reg_to_regnum)
+{
+ gdbarch->ecoff_reg_to_regnum = ecoff_reg_to_regnum;
+}
+
+int
+gdbarch_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dwarf_regnr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->dwarf_reg_to_regnum != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dwarf_reg_to_regnum called\n");
+ return gdbarch->dwarf_reg_to_regnum (dwarf_regnr);
+}
+
+void
+set_gdbarch_dwarf_reg_to_regnum (struct gdbarch *gdbarch,
+ gdbarch_dwarf_reg_to_regnum_ftype dwarf_reg_to_regnum)
+{
+ gdbarch->dwarf_reg_to_regnum = dwarf_reg_to_regnum;
+}
+
+int
+gdbarch_sdb_reg_to_regnum (struct gdbarch *gdbarch, int sdb_regnr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->sdb_reg_to_regnum != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_sdb_reg_to_regnum called\n");
+ return gdbarch->sdb_reg_to_regnum (sdb_regnr);
+}
+
+void
+set_gdbarch_sdb_reg_to_regnum (struct gdbarch *gdbarch,
+ gdbarch_sdb_reg_to_regnum_ftype sdb_reg_to_regnum)
+{
+ gdbarch->sdb_reg_to_regnum = sdb_reg_to_regnum;
+}
+
+int
+gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int dwarf2_regnr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->dwarf2_reg_to_regnum != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dwarf2_reg_to_regnum called\n");
+ return gdbarch->dwarf2_reg_to_regnum (dwarf2_regnr);
+}
+
+void
+set_gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch,
+ gdbarch_dwarf2_reg_to_regnum_ftype dwarf2_reg_to_regnum)
+{
+ gdbarch->dwarf2_reg_to_regnum = dwarf2_reg_to_regnum;
+}
+
+const char *
+gdbarch_register_name (struct gdbarch *gdbarch, int regnr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_name != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_name called\n");
+ return gdbarch->register_name (regnr);
+}
+
+void
+set_gdbarch_register_name (struct gdbarch *gdbarch,
+ gdbarch_register_name_ftype register_name)
+{
+ gdbarch->register_name = register_name;
+}
+
+int
+gdbarch_register_type_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->register_type != NULL;
+}
+
+struct type *
+gdbarch_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_type != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_type called\n");
+ return gdbarch->register_type (gdbarch, reg_nr);
+}
+
+void
+set_gdbarch_register_type (struct gdbarch *gdbarch,
+ gdbarch_register_type_ftype register_type)
+{
+ gdbarch->register_type = register_type;
+}
+
+int
+gdbarch_deprecated_register_virtual_type_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_register_virtual_type != NULL;
+}
+
+struct type *
+gdbarch_deprecated_register_virtual_type (struct gdbarch *gdbarch, int reg_nr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_register_virtual_type != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_virtual_type called\n");
+ return gdbarch->deprecated_register_virtual_type (reg_nr);
+}
+
+void
+set_gdbarch_deprecated_register_virtual_type (struct gdbarch *gdbarch,
+ gdbarch_deprecated_register_virtual_type_ftype deprecated_register_virtual_type)
+{
+ gdbarch->deprecated_register_virtual_type = deprecated_register_virtual_type;
+}
+
+int
+gdbarch_deprecated_register_bytes (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_bytes called\n");
+ return gdbarch->deprecated_register_bytes;
+}
+
+void
+set_gdbarch_deprecated_register_bytes (struct gdbarch *gdbarch,
+ int deprecated_register_bytes)
+{
+ gdbarch->deprecated_register_bytes = deprecated_register_bytes;
+}
+
+int
+gdbarch_deprecated_register_byte_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_register_byte != generic_register_byte;
+}
+
+int
+gdbarch_deprecated_register_byte (struct gdbarch *gdbarch, int reg_nr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_register_byte != NULL);
+ /* Do not check predicate: gdbarch->deprecated_register_byte != generic_register_byte, allow call. */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_byte called\n");
+ return gdbarch->deprecated_register_byte (reg_nr);
+}
+
+void
+set_gdbarch_deprecated_register_byte (struct gdbarch *gdbarch,
+ gdbarch_deprecated_register_byte_ftype deprecated_register_byte)
+{
+ gdbarch->deprecated_register_byte = deprecated_register_byte;
+}
+
+int
+gdbarch_deprecated_register_raw_size_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_register_raw_size != generic_register_size;
+}
+
+int
+gdbarch_deprecated_register_raw_size (struct gdbarch *gdbarch, int reg_nr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_register_raw_size != NULL);
+ /* Do not check predicate: gdbarch->deprecated_register_raw_size != generic_register_size, allow call. */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_raw_size called\n");
+ return gdbarch->deprecated_register_raw_size (reg_nr);
+}
+
+void
+set_gdbarch_deprecated_register_raw_size (struct gdbarch *gdbarch,
+ gdbarch_deprecated_register_raw_size_ftype deprecated_register_raw_size)
+{
+ gdbarch->deprecated_register_raw_size = deprecated_register_raw_size;
+}
+
+int
+gdbarch_deprecated_register_virtual_size_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_register_virtual_size != generic_register_size;
+}
+
+int
+gdbarch_deprecated_register_virtual_size (struct gdbarch *gdbarch, int reg_nr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_register_virtual_size != NULL);
+ /* Do not check predicate: gdbarch->deprecated_register_virtual_size != generic_register_size, allow call. */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_virtual_size called\n");
+ return gdbarch->deprecated_register_virtual_size (reg_nr);
+}
+
+void
+set_gdbarch_deprecated_register_virtual_size (struct gdbarch *gdbarch,
+ gdbarch_deprecated_register_virtual_size_ftype deprecated_register_virtual_size)
+{
+ gdbarch->deprecated_register_virtual_size = deprecated_register_virtual_size;
+}
+
+int
+gdbarch_deprecated_max_register_raw_size_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_max_register_raw_size != 0;
+}
+
+int
+gdbarch_deprecated_max_register_raw_size (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_max_register_raw_size called\n");
+ return gdbarch->deprecated_max_register_raw_size;
+}
+
+void
+set_gdbarch_deprecated_max_register_raw_size (struct gdbarch *gdbarch,
+ int deprecated_max_register_raw_size)
+{
+ gdbarch->deprecated_max_register_raw_size = deprecated_max_register_raw_size;
+}
+
+int
+gdbarch_deprecated_max_register_virtual_size_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_max_register_virtual_size != 0;
+}
+
+int
+gdbarch_deprecated_max_register_virtual_size (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_max_register_virtual_size called\n");
+ return gdbarch->deprecated_max_register_virtual_size;
+}
+
+void
+set_gdbarch_deprecated_max_register_virtual_size (struct gdbarch *gdbarch,
+ int deprecated_max_register_virtual_size)
+{
+ gdbarch->deprecated_max_register_virtual_size = deprecated_max_register_virtual_size;
+}
+
+int
+gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->unwind_dummy_id != NULL;
+}
+
+struct frame_id
+gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->unwind_dummy_id != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_dummy_id called\n");
+ return gdbarch->unwind_dummy_id (gdbarch, info);
+}
+
+void
+set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch,
+ gdbarch_unwind_dummy_id_ftype unwind_dummy_id)
+{
+ gdbarch->unwind_dummy_id = unwind_dummy_id;
+}
+
+int
+gdbarch_deprecated_save_dummy_frame_tos_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_save_dummy_frame_tos != NULL;
+}
+
+void
+gdbarch_deprecated_save_dummy_frame_tos (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_save_dummy_frame_tos != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_save_dummy_frame_tos called\n");
+ gdbarch->deprecated_save_dummy_frame_tos (sp);
+}
+
+void
+set_gdbarch_deprecated_save_dummy_frame_tos (struct gdbarch *gdbarch,
+ gdbarch_deprecated_save_dummy_frame_tos_ftype deprecated_save_dummy_frame_tos)
+{
+ gdbarch->deprecated_save_dummy_frame_tos = deprecated_save_dummy_frame_tos;
+}
+
+int
+gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_fp_regnum called\n");
+ return gdbarch->deprecated_fp_regnum;
+}
+
+void
+set_gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch,
+ int deprecated_fp_regnum)
+{
+ gdbarch->deprecated_fp_regnum = deprecated_fp_regnum;
+}
+
+int
+gdbarch_deprecated_target_read_fp_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_target_read_fp != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_target_read_fp (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_target_read_fp != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_target_read_fp called\n");
+ return gdbarch->deprecated_target_read_fp ();
+}
+
+void
+set_gdbarch_deprecated_target_read_fp (struct gdbarch *gdbarch,
+ gdbarch_deprecated_target_read_fp_ftype deprecated_target_read_fp)
+{
+ gdbarch->deprecated_target_read_fp = deprecated_target_read_fp;
+}
+
+int
+gdbarch_push_dummy_call_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->push_dummy_call != NULL;
+}
+
+CORE_ADDR
+gdbarch_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->push_dummy_call != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_push_dummy_call called\n");
+ return gdbarch->push_dummy_call (gdbarch, func_addr, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr);
+}
+
+void
+set_gdbarch_push_dummy_call (struct gdbarch *gdbarch,
+ gdbarch_push_dummy_call_ftype push_dummy_call)
+{
+ gdbarch->push_dummy_call = push_dummy_call;
+}
+
+int
+gdbarch_deprecated_push_arguments_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_push_arguments != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_push_arguments (struct gdbarch *gdbarch, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_push_arguments != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_push_arguments called\n");
+ return gdbarch->deprecated_push_arguments (nargs, args, sp, struct_return, struct_addr);
+}
+
+void
+set_gdbarch_deprecated_push_arguments (struct gdbarch *gdbarch,
+ gdbarch_deprecated_push_arguments_ftype deprecated_push_arguments)
+{
+ gdbarch->deprecated_push_arguments = deprecated_push_arguments;
+}
+
+int
+gdbarch_deprecated_use_generic_dummy_frames (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of deprecated_use_generic_dummy_frames, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_use_generic_dummy_frames called\n");
+ return gdbarch->deprecated_use_generic_dummy_frames;
+}
+
+void
+set_gdbarch_deprecated_use_generic_dummy_frames (struct gdbarch *gdbarch,
+ int deprecated_use_generic_dummy_frames)
+{
+ gdbarch->deprecated_use_generic_dummy_frames = deprecated_use_generic_dummy_frames;
+}
+
+int
+gdbarch_deprecated_push_return_address_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_push_return_address != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_push_return_address (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR sp)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_push_return_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_push_return_address called\n");
+ return gdbarch->deprecated_push_return_address (pc, sp);
+}
+
+void
+set_gdbarch_deprecated_push_return_address (struct gdbarch *gdbarch,
+ gdbarch_deprecated_push_return_address_ftype deprecated_push_return_address)
+{
+ gdbarch->deprecated_push_return_address = deprecated_push_return_address;
+}
+
+int
+gdbarch_deprecated_dummy_write_sp_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_dummy_write_sp != NULL;
+}
+
+void
+gdbarch_deprecated_dummy_write_sp (struct gdbarch *gdbarch, CORE_ADDR val)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_dummy_write_sp != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_dummy_write_sp called\n");
+ gdbarch->deprecated_dummy_write_sp (val);
+}
+
+void
+set_gdbarch_deprecated_dummy_write_sp (struct gdbarch *gdbarch,
+ gdbarch_deprecated_dummy_write_sp_ftype deprecated_dummy_write_sp)
+{
+ gdbarch->deprecated_dummy_write_sp = deprecated_dummy_write_sp;
+}
+
+int
+gdbarch_deprecated_register_size (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_size called\n");
+ return gdbarch->deprecated_register_size;
+}
+
+void
+set_gdbarch_deprecated_register_size (struct gdbarch *gdbarch,
+ int deprecated_register_size)
+{
+ gdbarch->deprecated_register_size = deprecated_register_size;
+}
+
+int
+gdbarch_call_dummy_location (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of call_dummy_location, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_call_dummy_location called\n");
+ return gdbarch->call_dummy_location;
+}
+
+void
+set_gdbarch_call_dummy_location (struct gdbarch *gdbarch,
+ int call_dummy_location)
+{
+ gdbarch->call_dummy_location = call_dummy_location;
+}
+
+CORE_ADDR
+gdbarch_deprecated_call_dummy_start_offset (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_call_dummy_start_offset called\n");
+ return gdbarch->deprecated_call_dummy_start_offset;
+}
+
+void
+set_gdbarch_deprecated_call_dummy_start_offset (struct gdbarch *gdbarch,
+ CORE_ADDR deprecated_call_dummy_start_offset)
+{
+ gdbarch->deprecated_call_dummy_start_offset = deprecated_call_dummy_start_offset;
+}
+
+CORE_ADDR
+gdbarch_deprecated_call_dummy_breakpoint_offset (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_call_dummy_breakpoint_offset called\n");
+ return gdbarch->deprecated_call_dummy_breakpoint_offset;
+}
+
+void
+set_gdbarch_deprecated_call_dummy_breakpoint_offset (struct gdbarch *gdbarch,
+ CORE_ADDR deprecated_call_dummy_breakpoint_offset)
+{
+ gdbarch->deprecated_call_dummy_breakpoint_offset = deprecated_call_dummy_breakpoint_offset;
+}
+
+int
+gdbarch_deprecated_call_dummy_length (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_call_dummy_length called\n");
+ return gdbarch->deprecated_call_dummy_length;
+}
+
+void
+set_gdbarch_deprecated_call_dummy_length (struct gdbarch *gdbarch,
+ int deprecated_call_dummy_length)
+{
+ gdbarch->deprecated_call_dummy_length = deprecated_call_dummy_length;
+}
+
+LONGEST *
+gdbarch_deprecated_call_dummy_words (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of deprecated_call_dummy_words, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_call_dummy_words called\n");
+ return gdbarch->deprecated_call_dummy_words;
+}
+
+void
+set_gdbarch_deprecated_call_dummy_words (struct gdbarch *gdbarch,
+ LONGEST * deprecated_call_dummy_words)
+{
+ gdbarch->deprecated_call_dummy_words = deprecated_call_dummy_words;
+}
+
+int
+gdbarch_deprecated_sizeof_call_dummy_words (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of deprecated_sizeof_call_dummy_words, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_sizeof_call_dummy_words called\n");
+ return gdbarch->deprecated_sizeof_call_dummy_words;
+}
+
+void
+set_gdbarch_deprecated_sizeof_call_dummy_words (struct gdbarch *gdbarch,
+ int deprecated_sizeof_call_dummy_words)
+{
+ gdbarch->deprecated_sizeof_call_dummy_words = deprecated_sizeof_call_dummy_words;
+}
+
+int
+gdbarch_deprecated_fix_call_dummy_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_fix_call_dummy != NULL;
+}
+
+void
+gdbarch_deprecated_fix_call_dummy (struct gdbarch *gdbarch, char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, struct value **args, struct type *type, int gcc_p)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_fix_call_dummy != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_fix_call_dummy called\n");
+ gdbarch->deprecated_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p);
+}
+
+void
+set_gdbarch_deprecated_fix_call_dummy (struct gdbarch *gdbarch,
+ gdbarch_deprecated_fix_call_dummy_ftype deprecated_fix_call_dummy)
+{
+ gdbarch->deprecated_fix_call_dummy = deprecated_fix_call_dummy;
+}
+
+int
+gdbarch_push_dummy_code_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->push_dummy_code != NULL;
+}
+
+CORE_ADDR
+gdbarch_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc, struct value **args, int nargs, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->push_dummy_code != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_push_dummy_code called\n");
+ return gdbarch->push_dummy_code (gdbarch, sp, funaddr, using_gcc, args, nargs, value_type, real_pc, bp_addr);
+}
+
+void
+set_gdbarch_push_dummy_code (struct gdbarch *gdbarch,
+ gdbarch_push_dummy_code_ftype push_dummy_code)
+{
+ gdbarch->push_dummy_code = push_dummy_code;
+}
+
+int
+gdbarch_deprecated_push_dummy_frame_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_push_dummy_frame != NULL;
+}
+
+void
+gdbarch_deprecated_push_dummy_frame (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_push_dummy_frame != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_push_dummy_frame called\n");
+ gdbarch->deprecated_push_dummy_frame ();
+}
+
+void
+set_gdbarch_deprecated_push_dummy_frame (struct gdbarch *gdbarch,
+ gdbarch_deprecated_push_dummy_frame_ftype deprecated_push_dummy_frame)
+{
+ gdbarch->deprecated_push_dummy_frame = deprecated_push_dummy_frame;
+}
+
+int
+gdbarch_deprecated_do_registers_info_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_do_registers_info != NULL;
+}
+
+void
+gdbarch_deprecated_do_registers_info (struct gdbarch *gdbarch, int reg_nr, int fpregs)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_do_registers_info != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_do_registers_info called\n");
+ gdbarch->deprecated_do_registers_info (reg_nr, fpregs);
+}
+
+void
+set_gdbarch_deprecated_do_registers_info (struct gdbarch *gdbarch,
+ gdbarch_deprecated_do_registers_info_ftype deprecated_do_registers_info)
+{
+ gdbarch->deprecated_do_registers_info = deprecated_do_registers_info;
+}
+
+void
+gdbarch_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, int regnum, int all)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->print_registers_info != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_print_registers_info called\n");
+ gdbarch->print_registers_info (gdbarch, file, frame, regnum, all);
+}
+
+void
+set_gdbarch_print_registers_info (struct gdbarch *gdbarch,
+ gdbarch_print_registers_info_ftype print_registers_info)
+{
+ gdbarch->print_registers_info = print_registers_info;
+}
+
+int
+gdbarch_print_float_info_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->print_float_info != NULL;
+}
+
+void
+gdbarch_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->print_float_info != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_print_float_info called\n");
+ gdbarch->print_float_info (gdbarch, file, frame, args);
+}
+
+void
+set_gdbarch_print_float_info (struct gdbarch *gdbarch,
+ gdbarch_print_float_info_ftype print_float_info)
+{
+ gdbarch->print_float_info = print_float_info;
+}
+
+int
+gdbarch_print_vector_info_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->print_vector_info != NULL;
+}
+
+void
+gdbarch_print_vector_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->print_vector_info != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_print_vector_info called\n");
+ gdbarch->print_vector_info (gdbarch, file, frame, args);
+}
+
+void
+set_gdbarch_print_vector_info (struct gdbarch *gdbarch,
+ gdbarch_print_vector_info_ftype print_vector_info)
+{
+ gdbarch->print_vector_info = print_vector_info;
+}
+
+int
+gdbarch_register_sim_regno (struct gdbarch *gdbarch, int reg_nr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_sim_regno != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_sim_regno called\n");
+ return gdbarch->register_sim_regno (reg_nr);
+}
+
+void
+set_gdbarch_register_sim_regno (struct gdbarch *gdbarch,
+ gdbarch_register_sim_regno_ftype register_sim_regno)
+{
+ gdbarch->register_sim_regno = register_sim_regno;
+}
+
+int
+gdbarch_register_bytes_ok_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->register_bytes_ok != NULL;
+}
+
+int
+gdbarch_register_bytes_ok (struct gdbarch *gdbarch, long nr_bytes)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_bytes_ok != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_bytes_ok called\n");
+ return gdbarch->register_bytes_ok (nr_bytes);
+}
+
+void
+set_gdbarch_register_bytes_ok (struct gdbarch *gdbarch,
+ gdbarch_register_bytes_ok_ftype register_bytes_ok)
+{
+ gdbarch->register_bytes_ok = register_bytes_ok;
+}
+
+int
+gdbarch_cannot_fetch_register (struct gdbarch *gdbarch, int regnum)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->cannot_fetch_register != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_cannot_fetch_register called\n");
+ return gdbarch->cannot_fetch_register (regnum);
+}
+
+void
+set_gdbarch_cannot_fetch_register (struct gdbarch *gdbarch,
+ gdbarch_cannot_fetch_register_ftype cannot_fetch_register)
+{
+ gdbarch->cannot_fetch_register = cannot_fetch_register;
+}
+
+int
+gdbarch_cannot_store_register (struct gdbarch *gdbarch, int regnum)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->cannot_store_register != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_cannot_store_register called\n");
+ return gdbarch->cannot_store_register (regnum);
+}
+
+void
+set_gdbarch_cannot_store_register (struct gdbarch *gdbarch,
+ gdbarch_cannot_store_register_ftype cannot_store_register)
+{
+ gdbarch->cannot_store_register = cannot_store_register;
+}
+
+int
+gdbarch_get_longjmp_target_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_longjmp_target != NULL;
+}
+
+int
+gdbarch_get_longjmp_target (struct gdbarch *gdbarch, CORE_ADDR *pc)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_longjmp_target != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_longjmp_target called\n");
+ return gdbarch->get_longjmp_target (pc);
+}
+
+void
+set_gdbarch_get_longjmp_target (struct gdbarch *gdbarch,
+ gdbarch_get_longjmp_target_ftype get_longjmp_target)
+{
+ gdbarch->get_longjmp_target = get_longjmp_target;
+}
+
+int
+gdbarch_deprecated_pc_in_call_dummy_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_pc_in_call_dummy != generic_pc_in_call_dummy;
+}
+
+int
+gdbarch_deprecated_pc_in_call_dummy (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR frame_address)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_pc_in_call_dummy != NULL);
+ /* Do not check predicate: gdbarch->deprecated_pc_in_call_dummy != generic_pc_in_call_dummy, allow call. */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_pc_in_call_dummy called\n");
+ return gdbarch->deprecated_pc_in_call_dummy (pc, sp, frame_address);
+}
+
+void
+set_gdbarch_deprecated_pc_in_call_dummy (struct gdbarch *gdbarch,
+ gdbarch_deprecated_pc_in_call_dummy_ftype deprecated_pc_in_call_dummy)
+{
+ gdbarch->deprecated_pc_in_call_dummy = deprecated_pc_in_call_dummy;
+}
+
+int
+gdbarch_deprecated_init_frame_pc_first_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_init_frame_pc_first != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_init_frame_pc_first (struct gdbarch *gdbarch, int fromleaf, struct frame_info *prev)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_init_frame_pc_first != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_init_frame_pc_first called\n");
+ return gdbarch->deprecated_init_frame_pc_first (fromleaf, prev);
+}
+
+void
+set_gdbarch_deprecated_init_frame_pc_first (struct gdbarch *gdbarch,
+ gdbarch_deprecated_init_frame_pc_first_ftype deprecated_init_frame_pc_first)
+{
+ gdbarch->deprecated_init_frame_pc_first = deprecated_init_frame_pc_first;
+}
+
+int
+gdbarch_deprecated_init_frame_pc_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_init_frame_pc != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_init_frame_pc (struct gdbarch *gdbarch, int fromleaf, struct frame_info *prev)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_init_frame_pc != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_init_frame_pc called\n");
+ return gdbarch->deprecated_init_frame_pc (fromleaf, prev);
+}
+
+void
+set_gdbarch_deprecated_init_frame_pc (struct gdbarch *gdbarch,
+ gdbarch_deprecated_init_frame_pc_ftype deprecated_init_frame_pc)
+{
+ gdbarch->deprecated_init_frame_pc = deprecated_init_frame_pc;
+}
+
+int
+gdbarch_believe_pcc_promotion (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_believe_pcc_promotion called\n");
+ return gdbarch->believe_pcc_promotion;
+}
+
+void
+set_gdbarch_believe_pcc_promotion (struct gdbarch *gdbarch,
+ int believe_pcc_promotion)
+{
+ gdbarch->believe_pcc_promotion = believe_pcc_promotion;
+}
+
+int
+gdbarch_believe_pcc_promotion_type (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_believe_pcc_promotion_type called\n");
+ return gdbarch->believe_pcc_promotion_type;
+}
+
+void
+set_gdbarch_believe_pcc_promotion_type (struct gdbarch *gdbarch,
+ int believe_pcc_promotion_type)
+{
+ gdbarch->believe_pcc_promotion_type = believe_pcc_promotion_type;
+}
+
+int
+gdbarch_deprecated_get_saved_register_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_get_saved_register != NULL;
+}
+
+void
+gdbarch_deprecated_get_saved_register (struct gdbarch *gdbarch, char *raw_buffer, int *optimized, CORE_ADDR *addrp, struct frame_info *frame, int regnum, enum lval_type *lval)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_get_saved_register != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_get_saved_register called\n");
+ gdbarch->deprecated_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval);
+}
+
+void
+set_gdbarch_deprecated_get_saved_register (struct gdbarch *gdbarch,
+ gdbarch_deprecated_get_saved_register_ftype deprecated_get_saved_register)
+{
+ gdbarch->deprecated_get_saved_register = deprecated_get_saved_register;
+}
+
+int
+gdbarch_deprecated_register_convertible_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_register_convertible != NULL;
+}
+
+int
+gdbarch_deprecated_register_convertible (struct gdbarch *gdbarch, int nr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_register_convertible != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_convertible called\n");
+ return gdbarch->deprecated_register_convertible (nr);
+}
+
+void
+set_gdbarch_deprecated_register_convertible (struct gdbarch *gdbarch,
+ gdbarch_deprecated_register_convertible_ftype deprecated_register_convertible)
+{
+ gdbarch->deprecated_register_convertible = deprecated_register_convertible;
+}
+
+void
+gdbarch_deprecated_register_convert_to_virtual (struct gdbarch *gdbarch, int regnum, struct type *type, char *from, char *to)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_register_convert_to_virtual != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_convert_to_virtual called\n");
+ gdbarch->deprecated_register_convert_to_virtual (regnum, type, from, to);
+}
+
+void
+set_gdbarch_deprecated_register_convert_to_virtual (struct gdbarch *gdbarch,
+ gdbarch_deprecated_register_convert_to_virtual_ftype deprecated_register_convert_to_virtual)
+{
+ gdbarch->deprecated_register_convert_to_virtual = deprecated_register_convert_to_virtual;
+}
+
+void
+gdbarch_deprecated_register_convert_to_raw (struct gdbarch *gdbarch, struct type *type, int regnum, const char *from, char *to)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_register_convert_to_raw != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_register_convert_to_raw called\n");
+ gdbarch->deprecated_register_convert_to_raw (type, regnum, from, to);
+}
+
+void
+set_gdbarch_deprecated_register_convert_to_raw (struct gdbarch *gdbarch,
+ gdbarch_deprecated_register_convert_to_raw_ftype deprecated_register_convert_to_raw)
+{
+ gdbarch->deprecated_register_convert_to_raw = deprecated_register_convert_to_raw;
+}
+
+int
+gdbarch_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->convert_register_p != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_convert_register_p called\n");
+ return gdbarch->convert_register_p (regnum, type);
+}
+
+void
+set_gdbarch_convert_register_p (struct gdbarch *gdbarch,
+ gdbarch_convert_register_p_ftype convert_register_p)
+{
+ gdbarch->convert_register_p = convert_register_p;
+}
+
+void
+gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, void *buf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_to_value != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_to_value called\n");
+ gdbarch->register_to_value (frame, regnum, type, buf);
+}
+
+void
+set_gdbarch_register_to_value (struct gdbarch *gdbarch,
+ gdbarch_register_to_value_ftype register_to_value)
+{
+ gdbarch->register_to_value = register_to_value;
+}
+
+void
+gdbarch_value_to_register (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, const void *buf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->value_to_register != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_value_to_register called\n");
+ gdbarch->value_to_register (frame, regnum, type, buf);
+}
+
+void
+set_gdbarch_value_to_register (struct gdbarch *gdbarch,
+ gdbarch_value_to_register_ftype value_to_register)
+{
+ gdbarch->value_to_register = value_to_register;
+}
+
+CORE_ADDR
+gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const void *buf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->pointer_to_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_pointer_to_address called\n");
+ return gdbarch->pointer_to_address (type, buf);
+}
+
+void
+set_gdbarch_pointer_to_address (struct gdbarch *gdbarch,
+ gdbarch_pointer_to_address_ftype pointer_to_address)
+{
+ gdbarch->pointer_to_address = pointer_to_address;
+}
+
+void
+gdbarch_address_to_pointer (struct gdbarch *gdbarch, struct type *type, void *buf, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->address_to_pointer != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_address_to_pointer called\n");
+ gdbarch->address_to_pointer (type, buf, addr);
+}
+
+void
+set_gdbarch_address_to_pointer (struct gdbarch *gdbarch,
+ gdbarch_address_to_pointer_ftype address_to_pointer)
+{
+ gdbarch->address_to_pointer = address_to_pointer;
+}
+
+int
+gdbarch_integer_to_address_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->integer_to_address != NULL;
+}
+
+CORE_ADDR
+gdbarch_integer_to_address (struct gdbarch *gdbarch, struct type *type, void *buf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->integer_to_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_integer_to_address called\n");
+ return gdbarch->integer_to_address (type, buf);
+}
+
+void
+set_gdbarch_integer_to_address (struct gdbarch *gdbarch,
+ gdbarch_integer_to_address_ftype integer_to_address)
+{
+ gdbarch->integer_to_address = integer_to_address;
+}
+
+int
+gdbarch_deprecated_pop_frame_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_pop_frame != NULL;
+}
+
+void
+gdbarch_deprecated_pop_frame (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_pop_frame != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_pop_frame called\n");
+ gdbarch->deprecated_pop_frame ();
+}
+
+void
+set_gdbarch_deprecated_pop_frame (struct gdbarch *gdbarch,
+ gdbarch_deprecated_pop_frame_ftype deprecated_pop_frame)
+{
+ gdbarch->deprecated_pop_frame = deprecated_pop_frame;
+}
+
+int
+gdbarch_deprecated_store_struct_return_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_store_struct_return != NULL;
+}
+
+void
+gdbarch_deprecated_store_struct_return (struct gdbarch *gdbarch, CORE_ADDR addr, CORE_ADDR sp)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_store_struct_return != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_store_struct_return called\n");
+ gdbarch->deprecated_store_struct_return (addr, sp);
+}
+
+void
+set_gdbarch_deprecated_store_struct_return (struct gdbarch *gdbarch,
+ gdbarch_deprecated_store_struct_return_ftype deprecated_store_struct_return)
+{
+ gdbarch->deprecated_store_struct_return = deprecated_store_struct_return;
+}
+
+int
+gdbarch_return_value_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->return_value != NULL;
+}
+
+enum return_value_convention
+gdbarch_return_value (struct gdbarch *gdbarch, struct type *valtype, struct regcache *regcache, void *readbuf, const void *writebuf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->return_value != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_return_value called\n");
+ return gdbarch->return_value (gdbarch, valtype, regcache, readbuf, writebuf);
+}
+
+void
+set_gdbarch_return_value (struct gdbarch *gdbarch,
+ gdbarch_return_value_ftype return_value)
+{
+ gdbarch->return_value = return_value;
+}
+
+int
+gdbarch_return_value_on_stack (struct gdbarch *gdbarch, struct type *type)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->return_value_on_stack != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_return_value_on_stack called\n");
+ return gdbarch->return_value_on_stack (type);
+}
+
+void
+set_gdbarch_return_value_on_stack (struct gdbarch *gdbarch,
+ gdbarch_return_value_on_stack_ftype return_value_on_stack)
+{
+ gdbarch->return_value_on_stack = return_value_on_stack;
+}
+
+void
+gdbarch_extract_return_value (struct gdbarch *gdbarch, struct type *type, struct regcache *regcache, void *valbuf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->extract_return_value != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_extract_return_value called\n");
+ gdbarch->extract_return_value (type, regcache, valbuf);
+}
+
+void
+set_gdbarch_extract_return_value (struct gdbarch *gdbarch,
+ gdbarch_extract_return_value_ftype extract_return_value)
+{
+ gdbarch->extract_return_value = extract_return_value;
+}
+
+void
+gdbarch_store_return_value (struct gdbarch *gdbarch, struct type *type, struct regcache *regcache, const void *valbuf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->store_return_value != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_store_return_value called\n");
+ gdbarch->store_return_value (type, regcache, valbuf);
+}
+
+void
+set_gdbarch_store_return_value (struct gdbarch *gdbarch,
+ gdbarch_store_return_value_ftype store_return_value)
+{
+ gdbarch->store_return_value = store_return_value;
+}
+
+void
+gdbarch_deprecated_extract_return_value (struct gdbarch *gdbarch, struct type *type, char *regbuf, char *valbuf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_extract_return_value != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_extract_return_value called\n");
+ gdbarch->deprecated_extract_return_value (type, regbuf, valbuf);
+}
+
+void
+set_gdbarch_deprecated_extract_return_value (struct gdbarch *gdbarch,
+ gdbarch_deprecated_extract_return_value_ftype deprecated_extract_return_value)
+{
+ gdbarch->deprecated_extract_return_value = deprecated_extract_return_value;
+}
+
+void
+gdbarch_deprecated_store_return_value (struct gdbarch *gdbarch, struct type *type, char *valbuf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_store_return_value != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_store_return_value called\n");
+ gdbarch->deprecated_store_return_value (type, valbuf);
+}
+
+void
+set_gdbarch_deprecated_store_return_value (struct gdbarch *gdbarch,
+ gdbarch_deprecated_store_return_value_ftype deprecated_store_return_value)
+{
+ gdbarch->deprecated_store_return_value = deprecated_store_return_value;
+}
+
+int
+gdbarch_use_struct_convention (struct gdbarch *gdbarch, int gcc_p, struct type *value_type)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->use_struct_convention != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_use_struct_convention called\n");
+ return gdbarch->use_struct_convention (gcc_p, value_type);
+}
+
+void
+set_gdbarch_use_struct_convention (struct gdbarch *gdbarch,
+ gdbarch_use_struct_convention_ftype use_struct_convention)
+{
+ gdbarch->use_struct_convention = use_struct_convention;
+}
+
+int
+gdbarch_deprecated_extract_struct_value_address_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_extract_struct_value_address != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_extract_struct_value_address (struct gdbarch *gdbarch, struct regcache *regcache)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_extract_struct_value_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_extract_struct_value_address called\n");
+ return gdbarch->deprecated_extract_struct_value_address (regcache);
+}
+
+void
+set_gdbarch_deprecated_extract_struct_value_address (struct gdbarch *gdbarch,
+ gdbarch_deprecated_extract_struct_value_address_ftype deprecated_extract_struct_value_address)
+{
+ gdbarch->deprecated_extract_struct_value_address = deprecated_extract_struct_value_address;
+}
+
+int
+gdbarch_deprecated_frame_init_saved_regs_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_frame_init_saved_regs != NULL;
+}
+
+void
+gdbarch_deprecated_frame_init_saved_regs (struct gdbarch *gdbarch, struct frame_info *frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_frame_init_saved_regs != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_frame_init_saved_regs called\n");
+ gdbarch->deprecated_frame_init_saved_regs (frame);
+}
+
+void
+set_gdbarch_deprecated_frame_init_saved_regs (struct gdbarch *gdbarch,
+ gdbarch_deprecated_frame_init_saved_regs_ftype deprecated_frame_init_saved_regs)
+{
+ gdbarch->deprecated_frame_init_saved_regs = deprecated_frame_init_saved_regs;
+}
+
+int
+gdbarch_deprecated_init_extra_frame_info_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_init_extra_frame_info != NULL;
+}
+
+void
+gdbarch_deprecated_init_extra_frame_info (struct gdbarch *gdbarch, int fromleaf, struct frame_info *frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_init_extra_frame_info != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_init_extra_frame_info called\n");
+ gdbarch->deprecated_init_extra_frame_info (fromleaf, frame);
+}
+
+void
+set_gdbarch_deprecated_init_extra_frame_info (struct gdbarch *gdbarch,
+ gdbarch_deprecated_init_extra_frame_info_ftype deprecated_init_extra_frame_info)
+{
+ gdbarch->deprecated_init_extra_frame_info = deprecated_init_extra_frame_info;
+}
+
+CORE_ADDR
+gdbarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR ip)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->skip_prologue != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_prologue called\n");
+ return gdbarch->skip_prologue (ip);
+}
+
+void
+set_gdbarch_skip_prologue (struct gdbarch *gdbarch,
+ gdbarch_skip_prologue_ftype skip_prologue)
+{
+ gdbarch->skip_prologue = skip_prologue;
+}
+
+int
+gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->inner_than != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_inner_than called\n");
+ return gdbarch->inner_than (lhs, rhs);
+}
+
+void
+set_gdbarch_inner_than (struct gdbarch *gdbarch,
+ gdbarch_inner_than_ftype inner_than)
+{
+ gdbarch->inner_than = inner_than;
+}
+
+const unsigned char *
+gdbarch_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->breakpoint_from_pc != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_breakpoint_from_pc called\n");
+ return gdbarch->breakpoint_from_pc (pcptr, lenptr);
+}
+
+void
+set_gdbarch_breakpoint_from_pc (struct gdbarch *gdbarch,
+ gdbarch_breakpoint_from_pc_ftype breakpoint_from_pc)
+{
+ gdbarch->breakpoint_from_pc = breakpoint_from_pc;
+}
+
+int
+gdbarch_adjust_breakpoint_address_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->adjust_breakpoint_address != NULL;
+}
+
+CORE_ADDR
+gdbarch_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->adjust_breakpoint_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_adjust_breakpoint_address called\n");
+ return gdbarch->adjust_breakpoint_address (gdbarch, bpaddr);
+}
+
+void
+set_gdbarch_adjust_breakpoint_address (struct gdbarch *gdbarch,
+ gdbarch_adjust_breakpoint_address_ftype adjust_breakpoint_address)
+{
+ gdbarch->adjust_breakpoint_address = adjust_breakpoint_address;
+}
+
+int
+gdbarch_memory_insert_breakpoint (struct gdbarch *gdbarch, CORE_ADDR addr, char *contents_cache)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->memory_insert_breakpoint != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_memory_insert_breakpoint called\n");
+ return gdbarch->memory_insert_breakpoint (addr, contents_cache);
+}
+
+void
+set_gdbarch_memory_insert_breakpoint (struct gdbarch *gdbarch,
+ gdbarch_memory_insert_breakpoint_ftype memory_insert_breakpoint)
+{
+ gdbarch->memory_insert_breakpoint = memory_insert_breakpoint;
+}
+
+int
+gdbarch_memory_remove_breakpoint (struct gdbarch *gdbarch, CORE_ADDR addr, char *contents_cache)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->memory_remove_breakpoint != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_memory_remove_breakpoint called\n");
+ return gdbarch->memory_remove_breakpoint (addr, contents_cache);
+}
+
+void
+set_gdbarch_memory_remove_breakpoint (struct gdbarch *gdbarch,
+ gdbarch_memory_remove_breakpoint_ftype memory_remove_breakpoint)
+{
+ gdbarch->memory_remove_breakpoint = memory_remove_breakpoint;
+}
+
+CORE_ADDR
+gdbarch_decr_pc_after_break (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of decr_pc_after_break, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_decr_pc_after_break called\n");
+ return gdbarch->decr_pc_after_break;
+}
+
+void
+set_gdbarch_decr_pc_after_break (struct gdbarch *gdbarch,
+ CORE_ADDR decr_pc_after_break)
+{
+ gdbarch->decr_pc_after_break = decr_pc_after_break;
+}
+
+CORE_ADDR
+gdbarch_function_start_offset (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of function_start_offset, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_function_start_offset called\n");
+ return gdbarch->function_start_offset;
+}
+
+void
+set_gdbarch_function_start_offset (struct gdbarch *gdbarch,
+ CORE_ADDR function_start_offset)
+{
+ gdbarch->function_start_offset = function_start_offset;
+}
+
+void
+gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->remote_translate_xfer_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_remote_translate_xfer_address called\n");
+ gdbarch->remote_translate_xfer_address (gdbarch, regcache, gdb_addr, gdb_len, rem_addr, rem_len);
+}
+
+void
+set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch,
+ gdbarch_remote_translate_xfer_address_ftype remote_translate_xfer_address)
+{
+ gdbarch->remote_translate_xfer_address = remote_translate_xfer_address;
+}
+
+CORE_ADDR
+gdbarch_frame_args_skip (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of frame_args_skip, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_frame_args_skip called\n");
+ return gdbarch->frame_args_skip;
+}
+
+void
+set_gdbarch_frame_args_skip (struct gdbarch *gdbarch,
+ CORE_ADDR frame_args_skip)
+{
+ gdbarch->frame_args_skip = frame_args_skip;
+}
+
+int
+gdbarch_deprecated_frameless_function_invocation_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_frameless_function_invocation != NULL;
+}
+
+int
+gdbarch_deprecated_frameless_function_invocation (struct gdbarch *gdbarch, struct frame_info *fi)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_frameless_function_invocation != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_frameless_function_invocation called\n");
+ return gdbarch->deprecated_frameless_function_invocation (fi);
+}
+
+void
+set_gdbarch_deprecated_frameless_function_invocation (struct gdbarch *gdbarch,
+ gdbarch_deprecated_frameless_function_invocation_ftype deprecated_frameless_function_invocation)
+{
+ gdbarch->deprecated_frameless_function_invocation = deprecated_frameless_function_invocation;
+}
+
+int
+gdbarch_deprecated_frame_chain_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_frame_chain != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_frame_chain (struct gdbarch *gdbarch, struct frame_info *frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_frame_chain != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_frame_chain called\n");
+ return gdbarch->deprecated_frame_chain (frame);
+}
+
+void
+set_gdbarch_deprecated_frame_chain (struct gdbarch *gdbarch,
+ gdbarch_deprecated_frame_chain_ftype deprecated_frame_chain)
+{
+ gdbarch->deprecated_frame_chain = deprecated_frame_chain;
+}
+
+int
+gdbarch_deprecated_frame_chain_valid_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_frame_chain_valid != NULL;
+}
+
+int
+gdbarch_deprecated_frame_chain_valid (struct gdbarch *gdbarch, CORE_ADDR chain, struct frame_info *thisframe)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_frame_chain_valid != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_frame_chain_valid called\n");
+ return gdbarch->deprecated_frame_chain_valid (chain, thisframe);
+}
+
+void
+set_gdbarch_deprecated_frame_chain_valid (struct gdbarch *gdbarch,
+ gdbarch_deprecated_frame_chain_valid_ftype deprecated_frame_chain_valid)
+{
+ gdbarch->deprecated_frame_chain_valid = deprecated_frame_chain_valid;
+}
+
+int
+gdbarch_deprecated_frame_saved_pc_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_frame_saved_pc != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_frame_saved_pc (struct gdbarch *gdbarch, struct frame_info *fi)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_frame_saved_pc != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_frame_saved_pc called\n");
+ return gdbarch->deprecated_frame_saved_pc (fi);
+}
+
+void
+set_gdbarch_deprecated_frame_saved_pc (struct gdbarch *gdbarch,
+ gdbarch_deprecated_frame_saved_pc_ftype deprecated_frame_saved_pc)
+{
+ gdbarch->deprecated_frame_saved_pc = deprecated_frame_saved_pc;
+}
+
+int
+gdbarch_unwind_pc_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->unwind_pc != NULL;
+}
+
+CORE_ADDR
+gdbarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->unwind_pc != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_pc called\n");
+ return gdbarch->unwind_pc (gdbarch, next_frame);
+}
+
+void
+set_gdbarch_unwind_pc (struct gdbarch *gdbarch,
+ gdbarch_unwind_pc_ftype unwind_pc)
+{
+ gdbarch->unwind_pc = unwind_pc;
+}
+
+int
+gdbarch_unwind_sp_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->unwind_sp != NULL;
+}
+
+CORE_ADDR
+gdbarch_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->unwind_sp != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_sp called\n");
+ return gdbarch->unwind_sp (gdbarch, next_frame);
+}
+
+void
+set_gdbarch_unwind_sp (struct gdbarch *gdbarch,
+ gdbarch_unwind_sp_ftype unwind_sp)
+{
+ gdbarch->unwind_sp = unwind_sp;
+}
+
+int
+gdbarch_deprecated_frame_args_address_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_frame_args_address != get_frame_base;
+}
+
+CORE_ADDR
+gdbarch_deprecated_frame_args_address (struct gdbarch *gdbarch, struct frame_info *fi)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_frame_args_address != NULL);
+ /* Do not check predicate: gdbarch->deprecated_frame_args_address != get_frame_base, allow call. */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_frame_args_address called\n");
+ return gdbarch->deprecated_frame_args_address (fi);
+}
+
+void
+set_gdbarch_deprecated_frame_args_address (struct gdbarch *gdbarch,
+ gdbarch_deprecated_frame_args_address_ftype deprecated_frame_args_address)
+{
+ gdbarch->deprecated_frame_args_address = deprecated_frame_args_address;
+}
+
+int
+gdbarch_deprecated_frame_locals_address_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_frame_locals_address != get_frame_base;
+}
+
+CORE_ADDR
+gdbarch_deprecated_frame_locals_address (struct gdbarch *gdbarch, struct frame_info *fi)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_frame_locals_address != NULL);
+ /* Do not check predicate: gdbarch->deprecated_frame_locals_address != get_frame_base, allow call. */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_frame_locals_address called\n");
+ return gdbarch->deprecated_frame_locals_address (fi);
+}
+
+void
+set_gdbarch_deprecated_frame_locals_address (struct gdbarch *gdbarch,
+ gdbarch_deprecated_frame_locals_address_ftype deprecated_frame_locals_address)
+{
+ gdbarch->deprecated_frame_locals_address = deprecated_frame_locals_address;
+}
+
+int
+gdbarch_deprecated_saved_pc_after_call_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_saved_pc_after_call != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_saved_pc_after_call (struct gdbarch *gdbarch, struct frame_info *frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_saved_pc_after_call != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_saved_pc_after_call called\n");
+ return gdbarch->deprecated_saved_pc_after_call (frame);
+}
+
+void
+set_gdbarch_deprecated_saved_pc_after_call (struct gdbarch *gdbarch,
+ gdbarch_deprecated_saved_pc_after_call_ftype deprecated_saved_pc_after_call)
+{
+ gdbarch->deprecated_saved_pc_after_call = deprecated_saved_pc_after_call;
+}
+
+int
+gdbarch_frame_num_args_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->frame_num_args != NULL;
+}
+
+int
+gdbarch_frame_num_args (struct gdbarch *gdbarch, struct frame_info *frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->frame_num_args != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_frame_num_args called\n");
+ return gdbarch->frame_num_args (frame);
+}
+
+void
+set_gdbarch_frame_num_args (struct gdbarch *gdbarch,
+ gdbarch_frame_num_args_ftype frame_num_args)
+{
+ gdbarch->frame_num_args = frame_num_args;
+}
+
+int
+gdbarch_deprecated_stack_align_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_stack_align != NULL;
+}
+
+CORE_ADDR
+gdbarch_deprecated_stack_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_stack_align != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_stack_align called\n");
+ return gdbarch->deprecated_stack_align (sp);
+}
+
+void
+set_gdbarch_deprecated_stack_align (struct gdbarch *gdbarch,
+ gdbarch_deprecated_stack_align_ftype deprecated_stack_align)
+{
+ gdbarch->deprecated_stack_align = deprecated_stack_align;
+}
+
+int
+gdbarch_frame_align_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->frame_align != NULL;
+}
+
+CORE_ADDR
+gdbarch_frame_align (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->frame_align != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_frame_align called\n");
+ return gdbarch->frame_align (gdbarch, address);
+}
+
+void
+set_gdbarch_frame_align (struct gdbarch *gdbarch,
+ gdbarch_frame_align_ftype frame_align)
+{
+ gdbarch->frame_align = frame_align;
+}
+
+int
+gdbarch_deprecated_reg_struct_has_addr_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->deprecated_reg_struct_has_addr != NULL;
+}
+
+int
+gdbarch_deprecated_reg_struct_has_addr (struct gdbarch *gdbarch, int gcc_p, struct type *type)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->deprecated_reg_struct_has_addr != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_deprecated_reg_struct_has_addr called\n");
+ return gdbarch->deprecated_reg_struct_has_addr (gcc_p, type);
+}
+
+void
+set_gdbarch_deprecated_reg_struct_has_addr (struct gdbarch *gdbarch,
+ gdbarch_deprecated_reg_struct_has_addr_ftype deprecated_reg_struct_has_addr)
+{
+ gdbarch->deprecated_reg_struct_has_addr = deprecated_reg_struct_has_addr;
+}
+
+int
+gdbarch_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->stabs_argument_has_addr != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stabs_argument_has_addr called\n");
+ return gdbarch->stabs_argument_has_addr (gdbarch, type);
+}
+
+void
+set_gdbarch_stabs_argument_has_addr (struct gdbarch *gdbarch,
+ gdbarch_stabs_argument_has_addr_ftype stabs_argument_has_addr)
+{
+ gdbarch->stabs_argument_has_addr = stabs_argument_has_addr;
+}
+
+int
+gdbarch_frame_red_zone_size (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_frame_red_zone_size called\n");
+ return gdbarch->frame_red_zone_size;
+}
+
+void
+set_gdbarch_frame_red_zone_size (struct gdbarch *gdbarch,
+ int frame_red_zone_size)
+{
+ gdbarch->frame_red_zone_size = frame_red_zone_size;
+}
+
+int
+gdbarch_parm_boundary (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_parm_boundary called\n");
+ return gdbarch->parm_boundary;
+}
+
+void
+set_gdbarch_parm_boundary (struct gdbarch *gdbarch,
+ int parm_boundary)
+{
+ gdbarch->parm_boundary = parm_boundary;
+}
+
+const struct floatformat *
+gdbarch_float_format (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_float_format called\n");
+ return gdbarch->float_format;
+}
+
+void
+set_gdbarch_float_format (struct gdbarch *gdbarch,
+ const struct floatformat * float_format)
+{
+ gdbarch->float_format = float_format;
+}
+
+const struct floatformat *
+gdbarch_double_format (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_double_format called\n");
+ return gdbarch->double_format;
+}
+
+void
+set_gdbarch_double_format (struct gdbarch *gdbarch,
+ const struct floatformat * double_format)
+{
+ gdbarch->double_format = double_format;
+}
+
+const struct floatformat *
+gdbarch_long_double_format (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_long_double_format called\n");
+ return gdbarch->long_double_format;
+}
+
+void
+set_gdbarch_long_double_format (struct gdbarch *gdbarch,
+ const struct floatformat * long_double_format)
+{
+ gdbarch->long_double_format = long_double_format;
+}
+
+CORE_ADDR
+gdbarch_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr, struct target_ops *targ)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->convert_from_func_ptr_addr != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_convert_from_func_ptr_addr called\n");
+ return gdbarch->convert_from_func_ptr_addr (gdbarch, addr, targ);
+}
+
+void
+set_gdbarch_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ gdbarch_convert_from_func_ptr_addr_ftype convert_from_func_ptr_addr)
+{
+ gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr;
+}
+
+CORE_ADDR
+gdbarch_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->addr_bits_remove != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_addr_bits_remove called\n");
+ return gdbarch->addr_bits_remove (addr);
+}
+
+void
+set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch,
+ gdbarch_addr_bits_remove_ftype addr_bits_remove)
+{
+ gdbarch->addr_bits_remove = addr_bits_remove;
+}
+
+CORE_ADDR
+gdbarch_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->smash_text_address != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_smash_text_address called\n");
+ return gdbarch->smash_text_address (addr);
+}
+
+void
+set_gdbarch_smash_text_address (struct gdbarch *gdbarch,
+ gdbarch_smash_text_address_ftype smash_text_address)
+{
+ gdbarch->smash_text_address = smash_text_address;
+}
+
+int
+gdbarch_software_single_step_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->software_single_step != NULL;
+}
+
+void
+gdbarch_software_single_step (struct gdbarch *gdbarch, enum target_signal sig, int insert_breakpoints_p)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->software_single_step != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_software_single_step called\n");
+ gdbarch->software_single_step (sig, insert_breakpoints_p);
+}
+
+void
+set_gdbarch_software_single_step (struct gdbarch *gdbarch,
+ gdbarch_software_single_step_ftype software_single_step)
+{
+ gdbarch->software_single_step = software_single_step;
+}
+
+int
+gdbarch_print_insn (struct gdbarch *gdbarch, bfd_vma vma, struct disassemble_info *info)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->print_insn != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_print_insn called\n");
+ return gdbarch->print_insn (vma, info);
+}
+
+void
+set_gdbarch_print_insn (struct gdbarch *gdbarch,
+ gdbarch_print_insn_ftype print_insn)
+{
+ gdbarch->print_insn = print_insn;
+}
+
+CORE_ADDR
+gdbarch_skip_trampoline_code (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->skip_trampoline_code != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_trampoline_code called\n");
+ return gdbarch->skip_trampoline_code (pc);
+}
+
+void
+set_gdbarch_skip_trampoline_code (struct gdbarch *gdbarch,
+ gdbarch_skip_trampoline_code_ftype skip_trampoline_code)
+{
+ gdbarch->skip_trampoline_code = skip_trampoline_code;
+}
+
+CORE_ADDR
+gdbarch_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->skip_solib_resolver != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_solib_resolver called\n");
+ return gdbarch->skip_solib_resolver (gdbarch, pc);
+}
+
+void
+set_gdbarch_skip_solib_resolver (struct gdbarch *gdbarch,
+ gdbarch_skip_solib_resolver_ftype skip_solib_resolver)
+{
+ gdbarch->skip_solib_resolver = skip_solib_resolver;
+}
+
+int
+gdbarch_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc, char *name)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->in_solib_call_trampoline != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_in_solib_call_trampoline called\n");
+ return gdbarch->in_solib_call_trampoline (pc, name);
+}
+
+void
+set_gdbarch_in_solib_call_trampoline (struct gdbarch *gdbarch,
+ gdbarch_in_solib_call_trampoline_ftype in_solib_call_trampoline)
+{
+ gdbarch->in_solib_call_trampoline = in_solib_call_trampoline;
+}
+
+int
+gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc, char *name)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->in_solib_return_trampoline != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_in_solib_return_trampoline called\n");
+ return gdbarch->in_solib_return_trampoline (pc, name);
+}
+
+void
+set_gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch,
+ gdbarch_in_solib_return_trampoline_ftype in_solib_return_trampoline)
+{
+ gdbarch->in_solib_return_trampoline = in_solib_return_trampoline;
+}
+
+int
+gdbarch_pc_in_sigtramp (struct gdbarch *gdbarch, CORE_ADDR pc, char *name)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->pc_in_sigtramp != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_pc_in_sigtramp called\n");
+ return gdbarch->pc_in_sigtramp (pc, name);
+}
+
+void
+set_gdbarch_pc_in_sigtramp (struct gdbarch *gdbarch,
+ gdbarch_pc_in_sigtramp_ftype pc_in_sigtramp)
+{
+ gdbarch->pc_in_sigtramp = pc_in_sigtramp;
+}
+
+int
+gdbarch_sigtramp_start_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->sigtramp_start != NULL;
+}
+
+CORE_ADDR
+gdbarch_sigtramp_start (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->sigtramp_start != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_sigtramp_start called\n");
+ return gdbarch->sigtramp_start (pc);
+}
+
+void
+set_gdbarch_sigtramp_start (struct gdbarch *gdbarch,
+ gdbarch_sigtramp_start_ftype sigtramp_start)
+{
+ gdbarch->sigtramp_start = sigtramp_start;
+}
+
+int
+gdbarch_sigtramp_end_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->sigtramp_end != NULL;
+}
+
+CORE_ADDR
+gdbarch_sigtramp_end (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->sigtramp_end != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_sigtramp_end called\n");
+ return gdbarch->sigtramp_end (pc);
+}
+
+void
+set_gdbarch_sigtramp_end (struct gdbarch *gdbarch,
+ gdbarch_sigtramp_end_ftype sigtramp_end)
+{
+ gdbarch->sigtramp_end = sigtramp_end;
+}
+
+int
+gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->in_function_epilogue_p != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_in_function_epilogue_p called\n");
+ return gdbarch->in_function_epilogue_p (gdbarch, addr);
+}
+
+void
+set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch,
+ gdbarch_in_function_epilogue_p_ftype in_function_epilogue_p)
+{
+ gdbarch->in_function_epilogue_p = in_function_epilogue_p;
+}
+
+char *
+gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->construct_inferior_arguments != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_construct_inferior_arguments called\n");
+ return gdbarch->construct_inferior_arguments (gdbarch, argc, argv);
+}
+
+void
+set_gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch,
+ gdbarch_construct_inferior_arguments_ftype construct_inferior_arguments)
+{
+ gdbarch->construct_inferior_arguments = construct_inferior_arguments;
+}
+
+void
+gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, asymbol *sym, struct minimal_symbol *msym)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->elf_make_msymbol_special != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_elf_make_msymbol_special called\n");
+ gdbarch->elf_make_msymbol_special (sym, msym);
+}
+
+void
+set_gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch,
+ gdbarch_elf_make_msymbol_special_ftype elf_make_msymbol_special)
+{
+ gdbarch->elf_make_msymbol_special = elf_make_msymbol_special;
+}
+
+void
+gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, int val, struct minimal_symbol *msym)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->coff_make_msymbol_special != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_coff_make_msymbol_special called\n");
+ gdbarch->coff_make_msymbol_special (val, msym);
+}
+
+void
+set_gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch,
+ gdbarch_coff_make_msymbol_special_ftype coff_make_msymbol_special)
+{
+ gdbarch->coff_make_msymbol_special = coff_make_msymbol_special;
+}
+
+const char *
+gdbarch_name_of_malloc (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of name_of_malloc, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_name_of_malloc called\n");
+ return gdbarch->name_of_malloc;
+}
+
+void
+set_gdbarch_name_of_malloc (struct gdbarch *gdbarch,
+ const char * name_of_malloc)
+{
+ gdbarch->name_of_malloc = name_of_malloc;
+}
+
+int
+gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of cannot_step_breakpoint, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_cannot_step_breakpoint called\n");
+ return gdbarch->cannot_step_breakpoint;
+}
+
+void
+set_gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch,
+ int cannot_step_breakpoint)
+{
+ gdbarch->cannot_step_breakpoint = cannot_step_breakpoint;
+}
+
+int
+gdbarch_have_nonsteppable_watchpoint (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of have_nonsteppable_watchpoint, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_have_nonsteppable_watchpoint called\n");
+ return gdbarch->have_nonsteppable_watchpoint;
+}
+
+void
+set_gdbarch_have_nonsteppable_watchpoint (struct gdbarch *gdbarch,
+ int have_nonsteppable_watchpoint)
+{
+ gdbarch->have_nonsteppable_watchpoint = have_nonsteppable_watchpoint;
+}
+
+int
+gdbarch_address_class_type_flags_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->address_class_type_flags != NULL;
+}
+
+int
+gdbarch_address_class_type_flags (struct gdbarch *gdbarch, int byte_size, int dwarf2_addr_class)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->address_class_type_flags != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_address_class_type_flags called\n");
+ return gdbarch->address_class_type_flags (byte_size, dwarf2_addr_class);
+}
+
+void
+set_gdbarch_address_class_type_flags (struct gdbarch *gdbarch,
+ gdbarch_address_class_type_flags_ftype address_class_type_flags)
+{
+ gdbarch->address_class_type_flags = address_class_type_flags;
+}
+
+int
+gdbarch_address_class_type_flags_to_name_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->address_class_type_flags_to_name != NULL;
+}
+
+const char *
+gdbarch_address_class_type_flags_to_name (struct gdbarch *gdbarch, int type_flags)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->address_class_type_flags_to_name != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_address_class_type_flags_to_name called\n");
+ return gdbarch->address_class_type_flags_to_name (gdbarch, type_flags);
+}
+
+void
+set_gdbarch_address_class_type_flags_to_name (struct gdbarch *gdbarch,
+ gdbarch_address_class_type_flags_to_name_ftype address_class_type_flags_to_name)
+{
+ gdbarch->address_class_type_flags_to_name = address_class_type_flags_to_name;
+}
+
+int
+gdbarch_address_class_name_to_type_flags_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->address_class_name_to_type_flags != NULL;
+}
+
+int
+gdbarch_address_class_name_to_type_flags (struct gdbarch *gdbarch, const char *name, int *type_flags_ptr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->address_class_name_to_type_flags != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_address_class_name_to_type_flags called\n");
+ return gdbarch->address_class_name_to_type_flags (gdbarch, name, type_flags_ptr);
+}
+
+void
+set_gdbarch_address_class_name_to_type_flags (struct gdbarch *gdbarch,
+ gdbarch_address_class_name_to_type_flags_ftype address_class_name_to_type_flags)
+{
+ gdbarch->address_class_name_to_type_flags = address_class_name_to_type_flags;
+}
+
+int
+gdbarch_register_reggroup_p (struct gdbarch *gdbarch, int regnum, struct reggroup *reggroup)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_reggroup_p != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_reggroup_p called\n");
+ return gdbarch->register_reggroup_p (gdbarch, regnum, reggroup);
+}
+
+void
+set_gdbarch_register_reggroup_p (struct gdbarch *gdbarch,
+ gdbarch_register_reggroup_p_ftype register_reggroup_p)
+{
+ gdbarch->register_reggroup_p = register_reggroup_p;
+}
+
+int
+gdbarch_fetch_pointer_argument_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->fetch_pointer_argument != NULL;
+}
+
+CORE_ADDR
+gdbarch_fetch_pointer_argument (struct gdbarch *gdbarch, struct frame_info *frame, int argi, struct type *type)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->fetch_pointer_argument != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_fetch_pointer_argument called\n");
+ return gdbarch->fetch_pointer_argument (frame, argi, type);
+}
+
+void
+set_gdbarch_fetch_pointer_argument (struct gdbarch *gdbarch,
+ gdbarch_fetch_pointer_argument_ftype fetch_pointer_argument)
+{
+ gdbarch->fetch_pointer_argument = fetch_pointer_argument;
+}
+
+int
+gdbarch_regset_from_core_section_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->regset_from_core_section != NULL;
+}
+
+const struct regset *
+gdbarch_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->regset_from_core_section != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_regset_from_core_section called\n");
+ return gdbarch->regset_from_core_section (gdbarch, sect_name, sect_size);
+}
+
+void
+set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch,
+ gdbarch_regset_from_core_section_ftype regset_from_core_section)
+{
+ gdbarch->regset_from_core_section = regset_from_core_section;
+}
+
+
+/* Keep a registry of per-architecture data-pointers required by GDB
+ modules. */
+
+struct gdbarch_data
+{
+ unsigned index;
+ int init_p;
+ gdbarch_data_init_ftype *init;
+};
+
+struct gdbarch_data_registration
+{
+ struct gdbarch_data *data;
+ struct gdbarch_data_registration *next;
+};
+
+struct gdbarch_data_registry
+{
+ unsigned nr;
+ struct gdbarch_data_registration *registrations;
+};
+
+struct gdbarch_data_registry gdbarch_data_registry =
+{
+ 0, NULL,
+};
+
+struct gdbarch_data *
+register_gdbarch_data (gdbarch_data_init_ftype *init)
+{
+ struct gdbarch_data_registration **curr;
+ /* Append the new registraration. */
+ for (curr = &gdbarch_data_registry.registrations;
+ (*curr) != NULL;
+ curr = &(*curr)->next);
+ (*curr) = XMALLOC (struct gdbarch_data_registration);
+ (*curr)->next = NULL;
+ (*curr)->data = XMALLOC (struct gdbarch_data);
+ (*curr)->data->index = gdbarch_data_registry.nr++;
+ (*curr)->data->init = init;
+ (*curr)->data->init_p = 1;
+ return (*curr)->data;
+}
+
+
+/* Create/delete the gdbarch data vector. */
+
+static void
+alloc_gdbarch_data (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch->data == NULL);
+ gdbarch->nr_data = gdbarch_data_registry.nr;
+ gdbarch->data = GDBARCH_OBSTACK_CALLOC (gdbarch, gdbarch->nr_data, void *);
+}
+
+/* Initialize the current value of the specified per-architecture
+ data-pointer. */
+
+void
+set_gdbarch_data (struct gdbarch *gdbarch,
+ struct gdbarch_data *data,
+ void *pointer)
+{
+ gdb_assert (data->index < gdbarch->nr_data);
+ gdb_assert (gdbarch->data[data->index] == NULL);
+ gdbarch->data[data->index] = pointer;
+}
+
+/* Return the current value of the specified per-architecture
+ data-pointer. */
+
+void *
+gdbarch_data (struct gdbarch *gdbarch, struct gdbarch_data *data)
+{
+ gdb_assert (data->index < gdbarch->nr_data);
+ /* The data-pointer isn't initialized, call init() to get a value but
+ only if the architecture initializaiton has completed. Otherwise
+ punt - hope that the caller knows what they are doing. */
+ if (gdbarch->data[data->index] == NULL
+ && gdbarch->initialized_p)
+ {
+ /* Be careful to detect an initialization cycle. */
+ gdb_assert (data->init_p);
+ data->init_p = 0;
+ gdb_assert (data->init != NULL);
+ gdbarch->data[data->index] = data->init (gdbarch);
+ data->init_p = 1;
+ gdb_assert (gdbarch->data[data->index] != NULL);
+ }
+ return gdbarch->data[data->index];
+}
+
+
+
+/* Keep a registry of swapped data required by GDB modules. */
+
+struct gdbarch_swap
+{
+ void *swap;
+ struct gdbarch_swap_registration *source;
+ struct gdbarch_swap *next;
+};
+
+struct gdbarch_swap_registration
+{
+ void *data;
+ unsigned long sizeof_data;
+ gdbarch_swap_ftype *init;
+ struct gdbarch_swap_registration *next;
+};
+
+struct gdbarch_swap_registry
+{
+ int nr;
+ struct gdbarch_swap_registration *registrations;
+};
+
+struct gdbarch_swap_registry gdbarch_swap_registry =
+{
+ 0, NULL,
+};
+
+void
+deprecated_register_gdbarch_swap (void *data,
+ unsigned long sizeof_data,
+ gdbarch_swap_ftype *init)
+{
+ struct gdbarch_swap_registration **rego;
+ for (rego = &gdbarch_swap_registry.registrations;
+ (*rego) != NULL;
+ rego = &(*rego)->next);
+ (*rego) = XMALLOC (struct gdbarch_swap_registration);
+ (*rego)->next = NULL;
+ (*rego)->init = init;
+ (*rego)->data = data;
+ (*rego)->sizeof_data = sizeof_data;
+}
+
+static void
+current_gdbarch_swap_init_hack (void)
+{
+ struct gdbarch_swap_registration *rego;
+ struct gdbarch_swap **curr = &current_gdbarch->swap;
+ for (rego = gdbarch_swap_registry.registrations;
+ rego != NULL;
+ rego = rego->next)
+ {
+ if (rego->data != NULL)
+ {
+ (*curr) = GDBARCH_OBSTACK_ZALLOC (current_gdbarch,
+ struct gdbarch_swap);
+ (*curr)->source = rego;
+ (*curr)->swap = gdbarch_obstack_zalloc (current_gdbarch,
+ rego->sizeof_data);
+ (*curr)->next = NULL;
+ curr = &(*curr)->next;
+ }
+ if (rego->init != NULL)
+ rego->init ();
+ }
+}
+
+static struct gdbarch *
+current_gdbarch_swap_out_hack (void)
+{
+ struct gdbarch *old_gdbarch = current_gdbarch;
+ struct gdbarch_swap *curr;
+
+ gdb_assert (old_gdbarch != NULL);
+ for (curr = old_gdbarch->swap;
+ curr != NULL;
+ curr = curr->next)
+ {
+ memcpy (curr->swap, curr->source->data, curr->source->sizeof_data);
+ memset (curr->source->data, 0, curr->source->sizeof_data);
+ }
+ current_gdbarch = NULL;
+ return old_gdbarch;
+}
+
+static void
+current_gdbarch_swap_in_hack (struct gdbarch *new_gdbarch)
+{
+ struct gdbarch_swap *curr;
+
+ gdb_assert (current_gdbarch == NULL);
+ for (curr = new_gdbarch->swap;
+ curr != NULL;
+ curr = curr->next)
+ memcpy (curr->source->data, curr->swap, curr->source->sizeof_data);
+ current_gdbarch = new_gdbarch;
+}
+
+
+/* Keep a registry of the architectures known by GDB. */
+
+struct gdbarch_registration
+{
+ enum bfd_architecture bfd_architecture;
+ gdbarch_init_ftype *init;
+ gdbarch_dump_tdep_ftype *dump_tdep;
+ struct gdbarch_list *arches;
+ struct gdbarch_registration *next;
+};
+
+static struct gdbarch_registration *gdbarch_registry = NULL;
+
+static void
+append_name (const char ***buf, int *nr, const char *name)
+{
+ *buf = xrealloc (*buf, sizeof (char**) * (*nr + 1));
+ (*buf)[*nr] = name;
+ *nr += 1;
+}
+
+const char **
+gdbarch_printable_names (void)
+{
+ /* Accumulate a list of names based on the registed list of
+ architectures. */
+ enum bfd_architecture a;
+ int nr_arches = 0;
+ const char **arches = NULL;
+ struct gdbarch_registration *rego;
+ for (rego = gdbarch_registry;
+ rego != NULL;
+ rego = rego->next)
+ {
+ const struct bfd_arch_info *ap;
+ ap = bfd_lookup_arch (rego->bfd_architecture, 0);
+ if (ap == NULL)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch_architecture_names: multi-arch unknown");
+ do
+ {
+ append_name (&arches, &nr_arches, ap->printable_name);
+ ap = ap->next;
+ }
+ while (ap != NULL);
+ }
+ append_name (&arches, &nr_arches, NULL);
+ return arches;
+}
+
+
+void
+gdbarch_register (enum bfd_architecture bfd_architecture,
+ gdbarch_init_ftype *init,
+ gdbarch_dump_tdep_ftype *dump_tdep)
+{
+ struct gdbarch_registration **curr;
+ const struct bfd_arch_info *bfd_arch_info;
+ /* Check that BFD recognizes this architecture */
+ bfd_arch_info = bfd_lookup_arch (bfd_architecture, 0);
+ if (bfd_arch_info == NULL)
+ {
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: Attempt to register unknown architecture (%d)",
+ bfd_architecture);
+ }
+ /* Check that we haven't seen this architecture before */
+ for (curr = &gdbarch_registry;
+ (*curr) != NULL;
+ curr = &(*curr)->next)
+ {
+ if (bfd_architecture == (*curr)->bfd_architecture)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: Duplicate registraration of architecture (%s)",
+ bfd_arch_info->printable_name);
+ }
+ /* log it */
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "register_gdbarch_init (%s, 0x%08lx)\n",
+ bfd_arch_info->printable_name,
+ (long) init);
+ /* Append it */
+ (*curr) = XMALLOC (struct gdbarch_registration);
+ (*curr)->bfd_architecture = bfd_architecture;
+ (*curr)->init = init;
+ (*curr)->dump_tdep = dump_tdep;
+ (*curr)->arches = NULL;
+ (*curr)->next = NULL;
+}
+
+void
+register_gdbarch_init (enum bfd_architecture bfd_architecture,
+ gdbarch_init_ftype *init)
+{
+ gdbarch_register (bfd_architecture, init, NULL);
+}
+
+
+/* Look for an architecture using gdbarch_info. Base search on only
+ BFD_ARCH_INFO and BYTE_ORDER. */
+
+struct gdbarch_list *
+gdbarch_list_lookup_by_info (struct gdbarch_list *arches,
+ const struct gdbarch_info *info)
+{
+ for (; arches != NULL; arches = arches->next)
+ {
+ if (info->bfd_arch_info != arches->gdbarch->bfd_arch_info)
+ continue;
+ if (info->byte_order != arches->gdbarch->byte_order)
+ continue;
+ if (info->osabi != arches->gdbarch->osabi)
+ continue;
+ return arches;
+ }
+ return NULL;
+}
+
+
+/* Find an architecture that matches the specified INFO. Create a new
+ architecture if needed. Return that new architecture. Assumes
+ that there is no current architecture. */
+
+static struct gdbarch *
+find_arch_by_info (struct gdbarch *old_gdbarch, struct gdbarch_info info)
+{
+ struct gdbarch *new_gdbarch;
+ struct gdbarch_registration *rego;
+
+ /* The existing architecture has been swapped out - all this code
+ works from a clean slate. */
+ gdb_assert (current_gdbarch == NULL);
+
+ /* Fill in missing parts of the INFO struct using a number of
+ sources: "set ..."; INFOabfd supplied; and the existing
+ architecture. */
+ gdbarch_info_fill (old_gdbarch, &info);
+
+ /* Must have found some sort of architecture. */
+ gdb_assert (info.bfd_arch_info != NULL);
+
+ if (gdbarch_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.bfd_arch_info %s\n",
+ (info.bfd_arch_info != NULL
+ ? info.bfd_arch_info->printable_name
+ : "(null)"));
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.byte_order %d (%s)\n",
+ info.byte_order,
+ (info.byte_order == BFD_ENDIAN_BIG ? "big"
+ : info.byte_order == BFD_ENDIAN_LITTLE ? "little"
+ : "default"));
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.osabi %d (%s)\n",
+ info.osabi, gdbarch_osabi_name (info.osabi));
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.abfd 0x%lx\n",
+ (long) info.abfd);
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.tdep_info 0x%lx\n",
+ (long) info.tdep_info);
+ }
+
+ /* Find the tdep code that knows about this architecture. */
+ for (rego = gdbarch_registry;
+ rego != NULL;
+ rego = rego->next)
+ if (rego->bfd_architecture == info.bfd_arch_info->arch)
+ break;
+ if (rego == NULL)
+ {
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "No matching architecture\n");
+ return 0;
+ }
+
+ /* Ask the tdep code for an architecture that matches "info". */
+ new_gdbarch = rego->init (info, rego->arches);
+
+ /* Did the tdep code like it? No. Reject the change and revert to
+ the old architecture. */
+ if (new_gdbarch == NULL)
+ {
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "Target rejected architecture\n");
+ return NULL;
+ }
+
+ /* Is this a pre-existing architecture (as determined by already
+ being initialized)? Move it to the front of the architecture
+ list (keeping the list sorted Most Recently Used). */
+ if (new_gdbarch->initialized_p)
+ {
+ struct gdbarch_list **list;
+ struct gdbarch_list *this;
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "Previous architecture 0x%08lx (%s) selected\n",
+ (long) new_gdbarch,
+ new_gdbarch->bfd_arch_info->printable_name);
+ /* Find the existing arch in the list. */
+ for (list = &rego->arches;
+ (*list) != NULL && (*list)->gdbarch != new_gdbarch;
+ list = &(*list)->next);
+ /* It had better be in the list of architectures. */
+ gdb_assert ((*list) != NULL && (*list)->gdbarch == new_gdbarch);
+ /* Unlink THIS. */
+ this = (*list);
+ (*list) = this->next;
+ /* Insert THIS at the front. */
+ this->next = rego->arches;
+ rego->arches = this;
+ /* Return it. */
+ return new_gdbarch;
+ }
+
+ /* It's a new architecture. */
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "New architecture 0x%08lx (%s) selected\n",
+ (long) new_gdbarch,
+ new_gdbarch->bfd_arch_info->printable_name);
+
+ /* Insert the new architecture into the front of the architecture
+ list (keep the list sorted Most Recently Used). */
+ {
+ struct gdbarch_list *this = XMALLOC (struct gdbarch_list);
+ this->next = rego->arches;
+ this->gdbarch = new_gdbarch;
+ rego->arches = this;
+ }
+
+ /* Check that the newly installed architecture is valid. Plug in
+ any post init values. */
+ new_gdbarch->dump_tdep = rego->dump_tdep;
+ verify_gdbarch (new_gdbarch);
+ new_gdbarch->initialized_p = 1;
+
+ /* Initialize any per-architecture swap areas. This phase requires
+ a valid global CURRENT_GDBARCH. Set it momentarially, and then
+ swap the entire architecture out. */
+ current_gdbarch = new_gdbarch;
+ current_gdbarch_swap_init_hack ();
+ current_gdbarch_swap_out_hack ();
+
+ if (gdbarch_debug)
+ gdbarch_dump (new_gdbarch, gdb_stdlog);
+
+ return new_gdbarch;
+}
+
+struct gdbarch *
+gdbarch_find_by_info (struct gdbarch_info info)
+{
+ /* Save the previously selected architecture, setting the global to
+ NULL. This stops things like gdbarch->init() trying to use the
+ previous architecture's configuration. The previous architecture
+ may not even be of the same architecture family. The most recent
+ architecture of the same family is found at the head of the
+ rego->arches list. */
+ struct gdbarch *old_gdbarch = current_gdbarch_swap_out_hack ();
+
+ /* Find the specified architecture. */
+ struct gdbarch *new_gdbarch = find_arch_by_info (old_gdbarch, info);
+
+ /* Restore the existing architecture. */
+ gdb_assert (current_gdbarch == NULL);
+ current_gdbarch_swap_in_hack (old_gdbarch);
+
+ return new_gdbarch;
+}
+
+/* Make the specified architecture current, swapping the existing one
+ out. */
+
+void
+deprecated_current_gdbarch_select_hack (struct gdbarch *new_gdbarch)
+{
+ gdb_assert (new_gdbarch != NULL);
+ gdb_assert (current_gdbarch != NULL);
+ gdb_assert (new_gdbarch->initialized_p);
+ current_gdbarch_swap_out_hack ();
+ current_gdbarch_swap_in_hack (new_gdbarch);
+ architecture_changed_event ();
+}
+
+extern void _initialize_gdbarch (void);
+
+void
+_initialize_gdbarch (void)
+{
+ struct cmd_list_element *c;
+
+ add_show_from_set (add_set_cmd ("arch",
+ class_maintenance,
+ var_zinteger,
+ (char *)&gdbarch_debug,
+ "Set architecture debugging.\n\
+When non-zero, architecture debugging is enabled.", &setdebuglist),
+ &showdebuglist);
+ c = add_set_cmd ("archdebug",
+ class_maintenance,
+ var_zinteger,
+ (char *)&gdbarch_debug,
+ "Set architecture debugging.\n\
+When non-zero, architecture debugging is enabled.", &setlist);
+
+ deprecate_cmd (c, "set debug arch");
+ deprecate_cmd (add_show_from_set (c, &showlist), "show debug arch");
+}
diff --git a/contrib/gdb/gdb/gdbarch.h b/contrib/gdb/gdb/gdbarch.h
new file mode 100644
index 0000000..3f01249
--- /dev/null
+++ b/contrib/gdb/gdb/gdbarch.h
@@ -0,0 +1,2581 @@
+/* *INDENT-OFF* */ /* THIS FILE IS GENERATED */
+
+/* Dynamic architecture support for GDB, the GNU debugger.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This file was created with the aid of ``gdbarch.sh''.
+
+ The Bourne shell script ``gdbarch.sh'' creates the files
+ ``new-gdbarch.c'' and ``new-gdbarch.h and then compares them
+ against the existing ``gdbarch.[hc]''. Any differences found
+ being reported.
+
+ If editing this file, please also run gdbarch.sh and merge any
+ changes into that script. Conversely, when making sweeping changes
+ to this file, modifying gdbarch.sh and using its output may prove
+ easier. */
+
+#ifndef GDBARCH_H
+#define GDBARCH_H
+
+struct floatformat;
+struct ui_file;
+struct frame_info;
+struct value;
+struct objfile;
+struct minimal_symbol;
+struct regcache;
+struct reggroup;
+struct regset;
+struct disassemble_info;
+struct target_ops;
+
+extern struct gdbarch *current_gdbarch;
+
+
+/* If any of the following are defined, the target wasn't correctly
+ converted. */
+
+#if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PURE) && defined (GDB_TM_FILE)
+#error "GDB_TM_FILE: Pure multi-arch targets do not have a tm.h file."
+#endif
+
+
+/* The following are pre-initialized by GDBARCH. */
+
+extern const struct bfd_arch_info * gdbarch_bfd_arch_info (struct gdbarch *gdbarch);
+/* set_gdbarch_bfd_arch_info() - not applicable - pre-initialized. */
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_ARCHITECTURE)
+#error "Non multi-arch definition of TARGET_ARCHITECTURE"
+#endif
+#if !defined (TARGET_ARCHITECTURE)
+#define TARGET_ARCHITECTURE (gdbarch_bfd_arch_info (current_gdbarch))
+#endif
+
+extern int gdbarch_byte_order (struct gdbarch *gdbarch);
+/* set_gdbarch_byte_order() - not applicable - pre-initialized. */
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_BYTE_ORDER)
+#error "Non multi-arch definition of TARGET_BYTE_ORDER"
+#endif
+#if !defined (TARGET_BYTE_ORDER)
+#define TARGET_BYTE_ORDER (gdbarch_byte_order (current_gdbarch))
+#endif
+
+extern enum gdb_osabi gdbarch_osabi (struct gdbarch *gdbarch);
+/* set_gdbarch_osabi() - not applicable - pre-initialized. */
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_OSABI)
+#error "Non multi-arch definition of TARGET_OSABI"
+#endif
+#if !defined (TARGET_OSABI)
+#define TARGET_OSABI (gdbarch_osabi (current_gdbarch))
+#endif
+
+
+/* The following are initialized by the target dependent code. */
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine.
+ v:2:TARGET_CHAR_BIT:int:char_bit::::8 * sizeof (char):8::0:
+
+ Number of bits in a short or unsigned short for the target machine. */
+
+extern int gdbarch_short_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_short_bit (struct gdbarch *gdbarch, int short_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_SHORT_BIT)
+#error "Non multi-arch definition of TARGET_SHORT_BIT"
+#endif
+#if !defined (TARGET_SHORT_BIT)
+#define TARGET_SHORT_BIT (gdbarch_short_bit (current_gdbarch))
+#endif
+
+/* Number of bits in an int or unsigned int for the target machine. */
+
+extern int gdbarch_int_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_int_bit (struct gdbarch *gdbarch, int int_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_INT_BIT)
+#error "Non multi-arch definition of TARGET_INT_BIT"
+#endif
+#if !defined (TARGET_INT_BIT)
+#define TARGET_INT_BIT (gdbarch_int_bit (current_gdbarch))
+#endif
+
+/* Number of bits in a long or unsigned long for the target machine. */
+
+extern int gdbarch_long_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_long_bit (struct gdbarch *gdbarch, int long_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_LONG_BIT)
+#error "Non multi-arch definition of TARGET_LONG_BIT"
+#endif
+#if !defined (TARGET_LONG_BIT)
+#define TARGET_LONG_BIT (gdbarch_long_bit (current_gdbarch))
+#endif
+
+/* Number of bits in a long long or unsigned long long for the target
+ machine. */
+
+extern int gdbarch_long_long_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_long_long_bit (struct gdbarch *gdbarch, int long_long_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_LONG_LONG_BIT)
+#error "Non multi-arch definition of TARGET_LONG_LONG_BIT"
+#endif
+#if !defined (TARGET_LONG_LONG_BIT)
+#define TARGET_LONG_LONG_BIT (gdbarch_long_long_bit (current_gdbarch))
+#endif
+
+/* Number of bits in a float for the target machine. */
+
+extern int gdbarch_float_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_float_bit (struct gdbarch *gdbarch, int float_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_FLOAT_BIT)
+#error "Non multi-arch definition of TARGET_FLOAT_BIT"
+#endif
+#if !defined (TARGET_FLOAT_BIT)
+#define TARGET_FLOAT_BIT (gdbarch_float_bit (current_gdbarch))
+#endif
+
+/* Number of bits in a double for the target machine. */
+
+extern int gdbarch_double_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_double_bit (struct gdbarch *gdbarch, int double_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_DOUBLE_BIT)
+#error "Non multi-arch definition of TARGET_DOUBLE_BIT"
+#endif
+#if !defined (TARGET_DOUBLE_BIT)
+#define TARGET_DOUBLE_BIT (gdbarch_double_bit (current_gdbarch))
+#endif
+
+/* Number of bits in a long double for the target machine. */
+
+extern int gdbarch_long_double_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_long_double_bit (struct gdbarch *gdbarch, int long_double_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_LONG_DOUBLE_BIT)
+#error "Non multi-arch definition of TARGET_LONG_DOUBLE_BIT"
+#endif
+#if !defined (TARGET_LONG_DOUBLE_BIT)
+#define TARGET_LONG_DOUBLE_BIT (gdbarch_long_double_bit (current_gdbarch))
+#endif
+
+/* For most targets, a pointer on the target and its representation as an
+ address in GDB have the same size and "look the same". For such a
+ target, you need only set TARGET_PTR_BIT / ptr_bit and TARGET_ADDR_BIT
+ / addr_bit will be set from it.
+
+ If TARGET_PTR_BIT and TARGET_ADDR_BIT are different, you'll probably
+ also need to set POINTER_TO_ADDRESS and ADDRESS_TO_POINTER as well.
+
+ ptr_bit is the size of a pointer on the target */
+
+extern int gdbarch_ptr_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_ptr_bit (struct gdbarch *gdbarch, int ptr_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_PTR_BIT)
+#error "Non multi-arch definition of TARGET_PTR_BIT"
+#endif
+#if !defined (TARGET_PTR_BIT)
+#define TARGET_PTR_BIT (gdbarch_ptr_bit (current_gdbarch))
+#endif
+
+/* addr_bit is the size of a target address as represented in gdb */
+
+extern int gdbarch_addr_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_addr_bit (struct gdbarch *gdbarch, int addr_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_ADDR_BIT)
+#error "Non multi-arch definition of TARGET_ADDR_BIT"
+#endif
+#if !defined (TARGET_ADDR_BIT)
+#define TARGET_ADDR_BIT (gdbarch_addr_bit (current_gdbarch))
+#endif
+
+/* Number of bits in a BFD_VMA for the target object file format. */
+
+extern int gdbarch_bfd_vma_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_bfd_vma_bit (struct gdbarch *gdbarch, int bfd_vma_bit);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_BFD_VMA_BIT)
+#error "Non multi-arch definition of TARGET_BFD_VMA_BIT"
+#endif
+#if !defined (TARGET_BFD_VMA_BIT)
+#define TARGET_BFD_VMA_BIT (gdbarch_bfd_vma_bit (current_gdbarch))
+#endif
+
+/* One if `char' acts like `signed char', zero if `unsigned char'. */
+
+extern int gdbarch_char_signed (struct gdbarch *gdbarch);
+extern void set_gdbarch_char_signed (struct gdbarch *gdbarch, int char_signed);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_CHAR_SIGNED)
+#error "Non multi-arch definition of TARGET_CHAR_SIGNED"
+#endif
+#if !defined (TARGET_CHAR_SIGNED)
+#define TARGET_CHAR_SIGNED (gdbarch_char_signed (current_gdbarch))
+#endif
+
+#if defined (TARGET_READ_PC)
+/* Legacy for systems yet to multi-arch TARGET_READ_PC */
+#if !defined (TARGET_READ_PC_P)
+#define TARGET_READ_PC_P() (1)
+#endif
+#endif
+
+extern int gdbarch_read_pc_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_READ_PC_P)
+#error "Non multi-arch definition of TARGET_READ_PC"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (TARGET_READ_PC_P)
+#define TARGET_READ_PC_P() (gdbarch_read_pc_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_read_pc_ftype) (ptid_t ptid);
+extern CORE_ADDR gdbarch_read_pc (struct gdbarch *gdbarch, ptid_t ptid);
+extern void set_gdbarch_read_pc (struct gdbarch *gdbarch, gdbarch_read_pc_ftype *read_pc);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_READ_PC)
+#error "Non multi-arch definition of TARGET_READ_PC"
+#endif
+#if !defined (TARGET_READ_PC)
+#define TARGET_READ_PC(ptid) (gdbarch_read_pc (current_gdbarch, ptid))
+#endif
+
+typedef void (gdbarch_write_pc_ftype) (CORE_ADDR val, ptid_t ptid);
+extern void gdbarch_write_pc (struct gdbarch *gdbarch, CORE_ADDR val, ptid_t ptid);
+extern void set_gdbarch_write_pc (struct gdbarch *gdbarch, gdbarch_write_pc_ftype *write_pc);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_WRITE_PC)
+#error "Non multi-arch definition of TARGET_WRITE_PC"
+#endif
+#if !defined (TARGET_WRITE_PC)
+#define TARGET_WRITE_PC(val, ptid) (gdbarch_write_pc (current_gdbarch, val, ptid))
+#endif
+
+/* UNWIND_SP is a direct replacement for TARGET_READ_SP. */
+
+#if defined (TARGET_READ_SP)
+/* Legacy for systems yet to multi-arch TARGET_READ_SP */
+#if !defined (TARGET_READ_SP_P)
+#define TARGET_READ_SP_P() (1)
+#endif
+#endif
+
+extern int gdbarch_read_sp_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_READ_SP_P)
+#error "Non multi-arch definition of TARGET_READ_SP"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (TARGET_READ_SP_P)
+#define TARGET_READ_SP_P() (gdbarch_read_sp_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_read_sp_ftype) (void);
+extern CORE_ADDR gdbarch_read_sp (struct gdbarch *gdbarch);
+extern void set_gdbarch_read_sp (struct gdbarch *gdbarch, gdbarch_read_sp_ftype *read_sp);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_READ_SP)
+#error "Non multi-arch definition of TARGET_READ_SP"
+#endif
+#if !defined (TARGET_READ_SP)
+#define TARGET_READ_SP() (gdbarch_read_sp (current_gdbarch))
+#endif
+
+/* Function for getting target's idea of a frame pointer. FIXME: GDB's
+ whole scheme for dealing with "frames" and "frame pointers" needs a
+ serious shakedown. */
+
+typedef void (gdbarch_virtual_frame_pointer_ftype) (CORE_ADDR pc, int *frame_regnum, LONGEST *frame_offset);
+extern void gdbarch_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc, int *frame_regnum, LONGEST *frame_offset);
+extern void set_gdbarch_virtual_frame_pointer (struct gdbarch *gdbarch, gdbarch_virtual_frame_pointer_ftype *virtual_frame_pointer);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_VIRTUAL_FRAME_POINTER)
+#error "Non multi-arch definition of TARGET_VIRTUAL_FRAME_POINTER"
+#endif
+#if !defined (TARGET_VIRTUAL_FRAME_POINTER)
+#define TARGET_VIRTUAL_FRAME_POINTER(pc, frame_regnum, frame_offset) (gdbarch_virtual_frame_pointer (current_gdbarch, pc, frame_regnum, frame_offset))
+#endif
+
+extern int gdbarch_pseudo_register_read_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_pseudo_register_read_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, void *buf);
+extern void gdbarch_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, void *buf);
+extern void set_gdbarch_pseudo_register_read (struct gdbarch *gdbarch, gdbarch_pseudo_register_read_ftype *pseudo_register_read);
+
+extern int gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_pseudo_register_write_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const void *buf);
+extern void gdbarch_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const void *buf);
+extern void set_gdbarch_pseudo_register_write (struct gdbarch *gdbarch, gdbarch_pseudo_register_write_ftype *pseudo_register_write);
+
+extern int gdbarch_num_regs (struct gdbarch *gdbarch);
+extern void set_gdbarch_num_regs (struct gdbarch *gdbarch, int num_regs);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (NUM_REGS)
+#error "Non multi-arch definition of NUM_REGS"
+#endif
+#if !defined (NUM_REGS)
+#define NUM_REGS (gdbarch_num_regs (current_gdbarch))
+#endif
+
+/* This macro gives the number of pseudo-registers that live in the
+ register namespace but do not get fetched or stored on the target.
+ These pseudo-registers may be aliases for other registers,
+ combinations of other registers, or they may be computed by GDB. */
+
+extern int gdbarch_num_pseudo_regs (struct gdbarch *gdbarch);
+extern void set_gdbarch_num_pseudo_regs (struct gdbarch *gdbarch, int num_pseudo_regs);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (NUM_PSEUDO_REGS)
+#error "Non multi-arch definition of NUM_PSEUDO_REGS"
+#endif
+#if !defined (NUM_PSEUDO_REGS)
+#define NUM_PSEUDO_REGS (gdbarch_num_pseudo_regs (current_gdbarch))
+#endif
+
+/* GDB's standard (or well known) register numbers. These can map onto
+ a real register or a pseudo (computed) register or not be defined at
+ all (-1).
+ SP_REGNUM will hopefully be replaced by UNWIND_SP. */
+
+extern int gdbarch_sp_regnum (struct gdbarch *gdbarch);
+extern void set_gdbarch_sp_regnum (struct gdbarch *gdbarch, int sp_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SP_REGNUM)
+#error "Non multi-arch definition of SP_REGNUM"
+#endif
+#if !defined (SP_REGNUM)
+#define SP_REGNUM (gdbarch_sp_regnum (current_gdbarch))
+#endif
+
+extern int gdbarch_pc_regnum (struct gdbarch *gdbarch);
+extern void set_gdbarch_pc_regnum (struct gdbarch *gdbarch, int pc_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (PC_REGNUM)
+#error "Non multi-arch definition of PC_REGNUM"
+#endif
+#if !defined (PC_REGNUM)
+#define PC_REGNUM (gdbarch_pc_regnum (current_gdbarch))
+#endif
+
+extern int gdbarch_ps_regnum (struct gdbarch *gdbarch);
+extern void set_gdbarch_ps_regnum (struct gdbarch *gdbarch, int ps_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (PS_REGNUM)
+#error "Non multi-arch definition of PS_REGNUM"
+#endif
+#if !defined (PS_REGNUM)
+#define PS_REGNUM (gdbarch_ps_regnum (current_gdbarch))
+#endif
+
+extern int gdbarch_fp0_regnum (struct gdbarch *gdbarch);
+extern void set_gdbarch_fp0_regnum (struct gdbarch *gdbarch, int fp0_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FP0_REGNUM)
+#error "Non multi-arch definition of FP0_REGNUM"
+#endif
+#if !defined (FP0_REGNUM)
+#define FP0_REGNUM (gdbarch_fp0_regnum (current_gdbarch))
+#endif
+
+/* Convert stab register number (from `r' declaration) to a gdb REGNUM. */
+
+typedef int (gdbarch_stab_reg_to_regnum_ftype) (int stab_regnr);
+extern int gdbarch_stab_reg_to_regnum (struct gdbarch *gdbarch, int stab_regnr);
+extern void set_gdbarch_stab_reg_to_regnum (struct gdbarch *gdbarch, gdbarch_stab_reg_to_regnum_ftype *stab_reg_to_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (STAB_REG_TO_REGNUM)
+#error "Non multi-arch definition of STAB_REG_TO_REGNUM"
+#endif
+#if !defined (STAB_REG_TO_REGNUM)
+#define STAB_REG_TO_REGNUM(stab_regnr) (gdbarch_stab_reg_to_regnum (current_gdbarch, stab_regnr))
+#endif
+
+/* Provide a default mapping from a ecoff register number to a gdb REGNUM. */
+
+typedef int (gdbarch_ecoff_reg_to_regnum_ftype) (int ecoff_regnr);
+extern int gdbarch_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int ecoff_regnr);
+extern void set_gdbarch_ecoff_reg_to_regnum (struct gdbarch *gdbarch, gdbarch_ecoff_reg_to_regnum_ftype *ecoff_reg_to_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (ECOFF_REG_TO_REGNUM)
+#error "Non multi-arch definition of ECOFF_REG_TO_REGNUM"
+#endif
+#if !defined (ECOFF_REG_TO_REGNUM)
+#define ECOFF_REG_TO_REGNUM(ecoff_regnr) (gdbarch_ecoff_reg_to_regnum (current_gdbarch, ecoff_regnr))
+#endif
+
+/* Provide a default mapping from a DWARF register number to a gdb REGNUM. */
+
+typedef int (gdbarch_dwarf_reg_to_regnum_ftype) (int dwarf_regnr);
+extern int gdbarch_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dwarf_regnr);
+extern void set_gdbarch_dwarf_reg_to_regnum (struct gdbarch *gdbarch, gdbarch_dwarf_reg_to_regnum_ftype *dwarf_reg_to_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DWARF_REG_TO_REGNUM)
+#error "Non multi-arch definition of DWARF_REG_TO_REGNUM"
+#endif
+#if !defined (DWARF_REG_TO_REGNUM)
+#define DWARF_REG_TO_REGNUM(dwarf_regnr) (gdbarch_dwarf_reg_to_regnum (current_gdbarch, dwarf_regnr))
+#endif
+
+/* Convert from an sdb register number to an internal gdb register number. */
+
+typedef int (gdbarch_sdb_reg_to_regnum_ftype) (int sdb_regnr);
+extern int gdbarch_sdb_reg_to_regnum (struct gdbarch *gdbarch, int sdb_regnr);
+extern void set_gdbarch_sdb_reg_to_regnum (struct gdbarch *gdbarch, gdbarch_sdb_reg_to_regnum_ftype *sdb_reg_to_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SDB_REG_TO_REGNUM)
+#error "Non multi-arch definition of SDB_REG_TO_REGNUM"
+#endif
+#if !defined (SDB_REG_TO_REGNUM)
+#define SDB_REG_TO_REGNUM(sdb_regnr) (gdbarch_sdb_reg_to_regnum (current_gdbarch, sdb_regnr))
+#endif
+
+typedef int (gdbarch_dwarf2_reg_to_regnum_ftype) (int dwarf2_regnr);
+extern int gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int dwarf2_regnr);
+extern void set_gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DWARF2_REG_TO_REGNUM)
+#error "Non multi-arch definition of DWARF2_REG_TO_REGNUM"
+#endif
+#if !defined (DWARF2_REG_TO_REGNUM)
+#define DWARF2_REG_TO_REGNUM(dwarf2_regnr) (gdbarch_dwarf2_reg_to_regnum (current_gdbarch, dwarf2_regnr))
+#endif
+
+typedef const char * (gdbarch_register_name_ftype) (int regnr);
+extern const char * gdbarch_register_name (struct gdbarch *gdbarch, int regnr);
+extern void set_gdbarch_register_name (struct gdbarch *gdbarch, gdbarch_register_name_ftype *register_name);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (REGISTER_NAME)
+#error "Non multi-arch definition of REGISTER_NAME"
+#endif
+#if !defined (REGISTER_NAME)
+#define REGISTER_NAME(regnr) (gdbarch_register_name (current_gdbarch, regnr))
+#endif
+
+/* REGISTER_TYPE is a direct replacement for DEPRECATED_REGISTER_VIRTUAL_TYPE. */
+
+extern int gdbarch_register_type_p (struct gdbarch *gdbarch);
+
+typedef struct type * (gdbarch_register_type_ftype) (struct gdbarch *gdbarch, int reg_nr);
+extern struct type * gdbarch_register_type (struct gdbarch *gdbarch, int reg_nr);
+extern void set_gdbarch_register_type (struct gdbarch *gdbarch, gdbarch_register_type_ftype *register_type);
+
+/* REGISTER_TYPE is a direct replacement for DEPRECATED_REGISTER_VIRTUAL_TYPE. */
+
+#if defined (DEPRECATED_REGISTER_VIRTUAL_TYPE)
+/* Legacy for systems yet to multi-arch DEPRECATED_REGISTER_VIRTUAL_TYPE */
+#if !defined (DEPRECATED_REGISTER_VIRTUAL_TYPE_P)
+#define DEPRECATED_REGISTER_VIRTUAL_TYPE_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_register_virtual_type_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_VIRTUAL_TYPE_P)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_VIRTUAL_TYPE"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_REGISTER_VIRTUAL_TYPE_P)
+#define DEPRECATED_REGISTER_VIRTUAL_TYPE_P() (gdbarch_deprecated_register_virtual_type_p (current_gdbarch))
+#endif
+
+typedef struct type * (gdbarch_deprecated_register_virtual_type_ftype) (int reg_nr);
+extern struct type * gdbarch_deprecated_register_virtual_type (struct gdbarch *gdbarch, int reg_nr);
+extern void set_gdbarch_deprecated_register_virtual_type (struct gdbarch *gdbarch, gdbarch_deprecated_register_virtual_type_ftype *deprecated_register_virtual_type);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_VIRTUAL_TYPE)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_VIRTUAL_TYPE"
+#endif
+#if !defined (DEPRECATED_REGISTER_VIRTUAL_TYPE)
+#define DEPRECATED_REGISTER_VIRTUAL_TYPE(reg_nr) (gdbarch_deprecated_register_virtual_type (current_gdbarch, reg_nr))
+#endif
+
+/* DEPRECATED_REGISTER_BYTES can be deleted. The value is computed
+ from REGISTER_TYPE. */
+
+extern int gdbarch_deprecated_register_bytes (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_register_bytes (struct gdbarch *gdbarch, int deprecated_register_bytes);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_BYTES)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_BYTES"
+#endif
+#if !defined (DEPRECATED_REGISTER_BYTES)
+#define DEPRECATED_REGISTER_BYTES (gdbarch_deprecated_register_bytes (current_gdbarch))
+#endif
+
+/* If the value returned by DEPRECATED_REGISTER_BYTE agrees with the
+ register offsets computed using just REGISTER_TYPE, this can be
+ deleted. See: maint print registers. NOTE: cagney/2002-05-02: This
+ function with predicate has a valid (callable) initial value. As a
+ consequence, even when the predicate is false, the corresponding
+ function works. This simplifies the migration process - old code,
+ calling DEPRECATED_REGISTER_BYTE, doesn't need to be modified. */
+
+#if defined (DEPRECATED_REGISTER_BYTE)
+/* Legacy for systems yet to multi-arch DEPRECATED_REGISTER_BYTE */
+#if !defined (DEPRECATED_REGISTER_BYTE_P)
+#define DEPRECATED_REGISTER_BYTE_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_register_byte_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_BYTE_P)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_BYTE"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_REGISTER_BYTE_P)
+#define DEPRECATED_REGISTER_BYTE_P() (gdbarch_deprecated_register_byte_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_register_byte_ftype) (int reg_nr);
+extern int gdbarch_deprecated_register_byte (struct gdbarch *gdbarch, int reg_nr);
+extern void set_gdbarch_deprecated_register_byte (struct gdbarch *gdbarch, gdbarch_deprecated_register_byte_ftype *deprecated_register_byte);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_BYTE)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_BYTE"
+#endif
+#if !defined (DEPRECATED_REGISTER_BYTE)
+#define DEPRECATED_REGISTER_BYTE(reg_nr) (gdbarch_deprecated_register_byte (current_gdbarch, reg_nr))
+#endif
+
+/* If all registers have identical raw and virtual sizes and those
+ sizes agree with the value computed from REGISTER_TYPE,
+ DEPRECATED_REGISTER_RAW_SIZE can be deleted. See: maint print
+ registers. */
+
+#if defined (DEPRECATED_REGISTER_RAW_SIZE)
+/* Legacy for systems yet to multi-arch DEPRECATED_REGISTER_RAW_SIZE */
+#if !defined (DEPRECATED_REGISTER_RAW_SIZE_P)
+#define DEPRECATED_REGISTER_RAW_SIZE_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_register_raw_size_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_RAW_SIZE_P)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_RAW_SIZE"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_REGISTER_RAW_SIZE_P)
+#define DEPRECATED_REGISTER_RAW_SIZE_P() (gdbarch_deprecated_register_raw_size_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_register_raw_size_ftype) (int reg_nr);
+extern int gdbarch_deprecated_register_raw_size (struct gdbarch *gdbarch, int reg_nr);
+extern void set_gdbarch_deprecated_register_raw_size (struct gdbarch *gdbarch, gdbarch_deprecated_register_raw_size_ftype *deprecated_register_raw_size);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_RAW_SIZE)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_RAW_SIZE"
+#endif
+#if !defined (DEPRECATED_REGISTER_RAW_SIZE)
+#define DEPRECATED_REGISTER_RAW_SIZE(reg_nr) (gdbarch_deprecated_register_raw_size (current_gdbarch, reg_nr))
+#endif
+
+/* If all registers have identical raw and virtual sizes and those
+ sizes agree with the value computed from REGISTER_TYPE,
+ DEPRECATED_REGISTER_VIRTUAL_SIZE can be deleted. See: maint print
+ registers. */
+
+#if defined (DEPRECATED_REGISTER_VIRTUAL_SIZE)
+/* Legacy for systems yet to multi-arch DEPRECATED_REGISTER_VIRTUAL_SIZE */
+#if !defined (DEPRECATED_REGISTER_VIRTUAL_SIZE_P)
+#define DEPRECATED_REGISTER_VIRTUAL_SIZE_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_register_virtual_size_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_VIRTUAL_SIZE_P)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_VIRTUAL_SIZE"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_REGISTER_VIRTUAL_SIZE_P)
+#define DEPRECATED_REGISTER_VIRTUAL_SIZE_P() (gdbarch_deprecated_register_virtual_size_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_register_virtual_size_ftype) (int reg_nr);
+extern int gdbarch_deprecated_register_virtual_size (struct gdbarch *gdbarch, int reg_nr);
+extern void set_gdbarch_deprecated_register_virtual_size (struct gdbarch *gdbarch, gdbarch_deprecated_register_virtual_size_ftype *deprecated_register_virtual_size);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_VIRTUAL_SIZE)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_VIRTUAL_SIZE"
+#endif
+#if !defined (DEPRECATED_REGISTER_VIRTUAL_SIZE)
+#define DEPRECATED_REGISTER_VIRTUAL_SIZE(reg_nr) (gdbarch_deprecated_register_virtual_size (current_gdbarch, reg_nr))
+#endif
+
+/* DEPRECATED_MAX_REGISTER_RAW_SIZE can be deleted. It has been
+ replaced by the constant MAX_REGISTER_SIZE. */
+
+#if defined (DEPRECATED_MAX_REGISTER_RAW_SIZE)
+/* Legacy for systems yet to multi-arch DEPRECATED_MAX_REGISTER_RAW_SIZE */
+#if !defined (DEPRECATED_MAX_REGISTER_RAW_SIZE_P)
+#define DEPRECATED_MAX_REGISTER_RAW_SIZE_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_max_register_raw_size_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_MAX_REGISTER_RAW_SIZE_P)
+#error "Non multi-arch definition of DEPRECATED_MAX_REGISTER_RAW_SIZE"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_MAX_REGISTER_RAW_SIZE_P)
+#define DEPRECATED_MAX_REGISTER_RAW_SIZE_P() (gdbarch_deprecated_max_register_raw_size_p (current_gdbarch))
+#endif
+
+extern int gdbarch_deprecated_max_register_raw_size (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_max_register_raw_size (struct gdbarch *gdbarch, int deprecated_max_register_raw_size);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_MAX_REGISTER_RAW_SIZE)
+#error "Non multi-arch definition of DEPRECATED_MAX_REGISTER_RAW_SIZE"
+#endif
+#if !defined (DEPRECATED_MAX_REGISTER_RAW_SIZE)
+#define DEPRECATED_MAX_REGISTER_RAW_SIZE (gdbarch_deprecated_max_register_raw_size (current_gdbarch))
+#endif
+
+/* DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE can be deleted. It has been
+ replaced by the constant MAX_REGISTER_SIZE. */
+
+#if defined (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE)
+/* Legacy for systems yet to multi-arch DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE */
+#if !defined (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P)
+#define DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_max_register_virtual_size_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P)
+#error "Non multi-arch definition of DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P)
+#define DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE_P() (gdbarch_deprecated_max_register_virtual_size_p (current_gdbarch))
+#endif
+
+extern int gdbarch_deprecated_max_register_virtual_size (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_max_register_virtual_size (struct gdbarch *gdbarch, int deprecated_max_register_virtual_size);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE)
+#error "Non multi-arch definition of DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE"
+#endif
+#if !defined (DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE)
+#define DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE (gdbarch_deprecated_max_register_virtual_size (current_gdbarch))
+#endif
+
+/* See gdbint.texinfo, and PUSH_DUMMY_CALL. */
+
+extern int gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch);
+
+typedef struct frame_id (gdbarch_unwind_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *info);
+extern struct frame_id gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info);
+extern void set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, gdbarch_unwind_dummy_id_ftype *unwind_dummy_id);
+
+/* Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+ SAVE_DUMMY_FRAME_TOS. */
+
+#if defined (DEPRECATED_SAVE_DUMMY_FRAME_TOS)
+/* Legacy for systems yet to multi-arch DEPRECATED_SAVE_DUMMY_FRAME_TOS */
+#if !defined (DEPRECATED_SAVE_DUMMY_FRAME_TOS_P)
+#define DEPRECATED_SAVE_DUMMY_FRAME_TOS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_save_dummy_frame_tos_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_SAVE_DUMMY_FRAME_TOS_P)
+#error "Non multi-arch definition of DEPRECATED_SAVE_DUMMY_FRAME_TOS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_SAVE_DUMMY_FRAME_TOS_P)
+#define DEPRECATED_SAVE_DUMMY_FRAME_TOS_P() (gdbarch_deprecated_save_dummy_frame_tos_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_save_dummy_frame_tos_ftype) (CORE_ADDR sp);
+extern void gdbarch_deprecated_save_dummy_frame_tos (struct gdbarch *gdbarch, CORE_ADDR sp);
+extern void set_gdbarch_deprecated_save_dummy_frame_tos (struct gdbarch *gdbarch, gdbarch_deprecated_save_dummy_frame_tos_ftype *deprecated_save_dummy_frame_tos);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_SAVE_DUMMY_FRAME_TOS)
+#error "Non multi-arch definition of DEPRECATED_SAVE_DUMMY_FRAME_TOS"
+#endif
+#if !defined (DEPRECATED_SAVE_DUMMY_FRAME_TOS)
+#define DEPRECATED_SAVE_DUMMY_FRAME_TOS(sp) (gdbarch_deprecated_save_dummy_frame_tos (current_gdbarch, sp))
+#endif
+
+/* Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+ DEPRECATED_FP_REGNUM. */
+
+extern int gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch, int deprecated_fp_regnum);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FP_REGNUM)
+#error "Non multi-arch definition of DEPRECATED_FP_REGNUM"
+#endif
+#if !defined (DEPRECATED_FP_REGNUM)
+#define DEPRECATED_FP_REGNUM (gdbarch_deprecated_fp_regnum (current_gdbarch))
+#endif
+
+/* Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+ DEPRECATED_TARGET_READ_FP. */
+
+#if defined (DEPRECATED_TARGET_READ_FP)
+/* Legacy for systems yet to multi-arch DEPRECATED_TARGET_READ_FP */
+#if !defined (DEPRECATED_TARGET_READ_FP_P)
+#define DEPRECATED_TARGET_READ_FP_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_target_read_fp_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_TARGET_READ_FP_P)
+#error "Non multi-arch definition of DEPRECATED_TARGET_READ_FP"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_TARGET_READ_FP_P)
+#define DEPRECATED_TARGET_READ_FP_P() (gdbarch_deprecated_target_read_fp_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_target_read_fp_ftype) (void);
+extern CORE_ADDR gdbarch_deprecated_target_read_fp (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_target_read_fp (struct gdbarch *gdbarch, gdbarch_deprecated_target_read_fp_ftype *deprecated_target_read_fp);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_TARGET_READ_FP)
+#error "Non multi-arch definition of DEPRECATED_TARGET_READ_FP"
+#endif
+#if !defined (DEPRECATED_TARGET_READ_FP)
+#define DEPRECATED_TARGET_READ_FP() (gdbarch_deprecated_target_read_fp (current_gdbarch))
+#endif
+
+/* See gdbint.texinfo. See infcall.c. New, all singing all dancing,
+ replacement for DEPRECATED_PUSH_ARGUMENTS. */
+
+extern int gdbarch_push_dummy_call_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_push_dummy_call_ftype) (struct gdbarch *gdbarch, CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
+extern CORE_ADDR gdbarch_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
+extern void set_gdbarch_push_dummy_call (struct gdbarch *gdbarch, gdbarch_push_dummy_call_ftype *push_dummy_call);
+
+/* PUSH_DUMMY_CALL is a direct replacement for DEPRECATED_PUSH_ARGUMENTS. */
+
+#if defined (DEPRECATED_PUSH_ARGUMENTS)
+/* Legacy for systems yet to multi-arch DEPRECATED_PUSH_ARGUMENTS */
+#if !defined (DEPRECATED_PUSH_ARGUMENTS_P)
+#define DEPRECATED_PUSH_ARGUMENTS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_push_arguments_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PUSH_ARGUMENTS_P)
+#error "Non multi-arch definition of DEPRECATED_PUSH_ARGUMENTS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_PUSH_ARGUMENTS_P)
+#define DEPRECATED_PUSH_ARGUMENTS_P() (gdbarch_deprecated_push_arguments_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_push_arguments_ftype) (int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
+extern CORE_ADDR gdbarch_deprecated_push_arguments (struct gdbarch *gdbarch, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
+extern void set_gdbarch_deprecated_push_arguments (struct gdbarch *gdbarch, gdbarch_deprecated_push_arguments_ftype *deprecated_push_arguments);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PUSH_ARGUMENTS)
+#error "Non multi-arch definition of DEPRECATED_PUSH_ARGUMENTS"
+#endif
+#if !defined (DEPRECATED_PUSH_ARGUMENTS)
+#define DEPRECATED_PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) (gdbarch_deprecated_push_arguments (current_gdbarch, nargs, args, sp, struct_return, struct_addr))
+#endif
+
+/* DEPRECATED_USE_GENERIC_DUMMY_FRAMES can be deleted. Always true. */
+
+extern int gdbarch_deprecated_use_generic_dummy_frames (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_use_generic_dummy_frames (struct gdbarch *gdbarch, int deprecated_use_generic_dummy_frames);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+#error "Non multi-arch definition of DEPRECATED_USE_GENERIC_DUMMY_FRAMES"
+#endif
+#if !defined (DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+#define DEPRECATED_USE_GENERIC_DUMMY_FRAMES (gdbarch_deprecated_use_generic_dummy_frames (current_gdbarch))
+#endif
+
+/* Implement PUSH_RETURN_ADDRESS, and then merge in
+ DEPRECATED_PUSH_RETURN_ADDRESS. */
+
+#if defined (DEPRECATED_PUSH_RETURN_ADDRESS)
+/* Legacy for systems yet to multi-arch DEPRECATED_PUSH_RETURN_ADDRESS */
+#if !defined (DEPRECATED_PUSH_RETURN_ADDRESS_P)
+#define DEPRECATED_PUSH_RETURN_ADDRESS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_push_return_address_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PUSH_RETURN_ADDRESS_P)
+#error "Non multi-arch definition of DEPRECATED_PUSH_RETURN_ADDRESS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_PUSH_RETURN_ADDRESS_P)
+#define DEPRECATED_PUSH_RETURN_ADDRESS_P() (gdbarch_deprecated_push_return_address_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_push_return_address_ftype) (CORE_ADDR pc, CORE_ADDR sp);
+extern CORE_ADDR gdbarch_deprecated_push_return_address (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR sp);
+extern void set_gdbarch_deprecated_push_return_address (struct gdbarch *gdbarch, gdbarch_deprecated_push_return_address_ftype *deprecated_push_return_address);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PUSH_RETURN_ADDRESS)
+#error "Non multi-arch definition of DEPRECATED_PUSH_RETURN_ADDRESS"
+#endif
+#if !defined (DEPRECATED_PUSH_RETURN_ADDRESS)
+#define DEPRECATED_PUSH_RETURN_ADDRESS(pc, sp) (gdbarch_deprecated_push_return_address (current_gdbarch, pc, sp))
+#endif
+
+/* Implement PUSH_DUMMY_CALL, then merge in DEPRECATED_DUMMY_WRITE_SP. */
+
+#if defined (DEPRECATED_DUMMY_WRITE_SP)
+/* Legacy for systems yet to multi-arch DEPRECATED_DUMMY_WRITE_SP */
+#if !defined (DEPRECATED_DUMMY_WRITE_SP_P)
+#define DEPRECATED_DUMMY_WRITE_SP_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_dummy_write_sp_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_DUMMY_WRITE_SP_P)
+#error "Non multi-arch definition of DEPRECATED_DUMMY_WRITE_SP"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_DUMMY_WRITE_SP_P)
+#define DEPRECATED_DUMMY_WRITE_SP_P() (gdbarch_deprecated_dummy_write_sp_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_dummy_write_sp_ftype) (CORE_ADDR val);
+extern void gdbarch_deprecated_dummy_write_sp (struct gdbarch *gdbarch, CORE_ADDR val);
+extern void set_gdbarch_deprecated_dummy_write_sp (struct gdbarch *gdbarch, gdbarch_deprecated_dummy_write_sp_ftype *deprecated_dummy_write_sp);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_DUMMY_WRITE_SP)
+#error "Non multi-arch definition of DEPRECATED_DUMMY_WRITE_SP"
+#endif
+#if !defined (DEPRECATED_DUMMY_WRITE_SP)
+#define DEPRECATED_DUMMY_WRITE_SP(val) (gdbarch_deprecated_dummy_write_sp (current_gdbarch, val))
+#endif
+
+/* DEPRECATED_REGISTER_SIZE can be deleted. */
+
+extern int gdbarch_deprecated_register_size (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_register_size (struct gdbarch *gdbarch, int deprecated_register_size);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_SIZE)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_SIZE"
+#endif
+#if !defined (DEPRECATED_REGISTER_SIZE)
+#define DEPRECATED_REGISTER_SIZE (gdbarch_deprecated_register_size (current_gdbarch))
+#endif
+
+extern int gdbarch_call_dummy_location (struct gdbarch *gdbarch);
+extern void set_gdbarch_call_dummy_location (struct gdbarch *gdbarch, int call_dummy_location);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (CALL_DUMMY_LOCATION)
+#error "Non multi-arch definition of CALL_DUMMY_LOCATION"
+#endif
+#if !defined (CALL_DUMMY_LOCATION)
+#define CALL_DUMMY_LOCATION (gdbarch_call_dummy_location (current_gdbarch))
+#endif
+
+/* DEPRECATED_CALL_DUMMY_START_OFFSET can be deleted. */
+
+extern CORE_ADDR gdbarch_deprecated_call_dummy_start_offset (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_call_dummy_start_offset (struct gdbarch *gdbarch, CORE_ADDR deprecated_call_dummy_start_offset);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_CALL_DUMMY_START_OFFSET)
+#error "Non multi-arch definition of DEPRECATED_CALL_DUMMY_START_OFFSET"
+#endif
+#if !defined (DEPRECATED_CALL_DUMMY_START_OFFSET)
+#define DEPRECATED_CALL_DUMMY_START_OFFSET (gdbarch_deprecated_call_dummy_start_offset (current_gdbarch))
+#endif
+
+/* DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET can be deleted. */
+
+extern CORE_ADDR gdbarch_deprecated_call_dummy_breakpoint_offset (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_call_dummy_breakpoint_offset (struct gdbarch *gdbarch, CORE_ADDR deprecated_call_dummy_breakpoint_offset);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET)
+#error "Non multi-arch definition of DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET"
+#endif
+#if !defined (DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET)
+#define DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET (gdbarch_deprecated_call_dummy_breakpoint_offset (current_gdbarch))
+#endif
+
+/* DEPRECATED_CALL_DUMMY_LENGTH can be deleted. */
+
+extern int gdbarch_deprecated_call_dummy_length (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_call_dummy_length (struct gdbarch *gdbarch, int deprecated_call_dummy_length);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_CALL_DUMMY_LENGTH)
+#error "Non multi-arch definition of DEPRECATED_CALL_DUMMY_LENGTH"
+#endif
+#if !defined (DEPRECATED_CALL_DUMMY_LENGTH)
+#define DEPRECATED_CALL_DUMMY_LENGTH (gdbarch_deprecated_call_dummy_length (current_gdbarch))
+#endif
+
+/* DEPRECATED_CALL_DUMMY_WORDS can be deleted. */
+
+extern LONGEST * gdbarch_deprecated_call_dummy_words (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_call_dummy_words (struct gdbarch *gdbarch, LONGEST * deprecated_call_dummy_words);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_CALL_DUMMY_WORDS)
+#error "Non multi-arch definition of DEPRECATED_CALL_DUMMY_WORDS"
+#endif
+#if !defined (DEPRECATED_CALL_DUMMY_WORDS)
+#define DEPRECATED_CALL_DUMMY_WORDS (gdbarch_deprecated_call_dummy_words (current_gdbarch))
+#endif
+
+/* Implement PUSH_DUMMY_CALL, then delete DEPRECATED_SIZEOF_CALL_DUMMY_WORDS. */
+
+extern int gdbarch_deprecated_sizeof_call_dummy_words (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_sizeof_call_dummy_words (struct gdbarch *gdbarch, int deprecated_sizeof_call_dummy_words);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_SIZEOF_CALL_DUMMY_WORDS)
+#error "Non multi-arch definition of DEPRECATED_SIZEOF_CALL_DUMMY_WORDS"
+#endif
+#if !defined (DEPRECATED_SIZEOF_CALL_DUMMY_WORDS)
+#define DEPRECATED_SIZEOF_CALL_DUMMY_WORDS (gdbarch_deprecated_sizeof_call_dummy_words (current_gdbarch))
+#endif
+
+/* DEPRECATED_FIX_CALL_DUMMY can be deleted. For the SPARC, implement
+ PUSH_DUMMY_CODE and set CALL_DUMMY_LOCATION to ON_STACK. */
+
+#if defined (DEPRECATED_FIX_CALL_DUMMY)
+/* Legacy for systems yet to multi-arch DEPRECATED_FIX_CALL_DUMMY */
+#if !defined (DEPRECATED_FIX_CALL_DUMMY_P)
+#define DEPRECATED_FIX_CALL_DUMMY_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_fix_call_dummy_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FIX_CALL_DUMMY_P)
+#error "Non multi-arch definition of DEPRECATED_FIX_CALL_DUMMY"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FIX_CALL_DUMMY_P)
+#define DEPRECATED_FIX_CALL_DUMMY_P() (gdbarch_deprecated_fix_call_dummy_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_fix_call_dummy_ftype) (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, struct value **args, struct type *type, int gcc_p);
+extern void gdbarch_deprecated_fix_call_dummy (struct gdbarch *gdbarch, char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, struct value **args, struct type *type, int gcc_p);
+extern void set_gdbarch_deprecated_fix_call_dummy (struct gdbarch *gdbarch, gdbarch_deprecated_fix_call_dummy_ftype *deprecated_fix_call_dummy);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FIX_CALL_DUMMY)
+#error "Non multi-arch definition of DEPRECATED_FIX_CALL_DUMMY"
+#endif
+#if !defined (DEPRECATED_FIX_CALL_DUMMY)
+#define DEPRECATED_FIX_CALL_DUMMY(dummy, pc, fun, nargs, args, type, gcc_p) (gdbarch_deprecated_fix_call_dummy (current_gdbarch, dummy, pc, fun, nargs, args, type, gcc_p))
+#endif
+
+/* This is a replacement for DEPRECATED_FIX_CALL_DUMMY et.al. */
+
+extern int gdbarch_push_dummy_code_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_push_dummy_code_ftype) (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc, struct value **args, int nargs, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr);
+extern CORE_ADDR gdbarch_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc, struct value **args, int nargs, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr);
+extern void set_gdbarch_push_dummy_code (struct gdbarch *gdbarch, gdbarch_push_dummy_code_ftype *push_dummy_code);
+
+/* Implement PUSH_DUMMY_CALL, then delete DEPRECATED_PUSH_DUMMY_FRAME. */
+
+#if defined (DEPRECATED_PUSH_DUMMY_FRAME)
+/* Legacy for systems yet to multi-arch DEPRECATED_PUSH_DUMMY_FRAME */
+#if !defined (DEPRECATED_PUSH_DUMMY_FRAME_P)
+#define DEPRECATED_PUSH_DUMMY_FRAME_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_push_dummy_frame_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PUSH_DUMMY_FRAME_P)
+#error "Non multi-arch definition of DEPRECATED_PUSH_DUMMY_FRAME"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_PUSH_DUMMY_FRAME_P)
+#define DEPRECATED_PUSH_DUMMY_FRAME_P() (gdbarch_deprecated_push_dummy_frame_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_push_dummy_frame_ftype) (void);
+extern void gdbarch_deprecated_push_dummy_frame (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_push_dummy_frame (struct gdbarch *gdbarch, gdbarch_deprecated_push_dummy_frame_ftype *deprecated_push_dummy_frame);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PUSH_DUMMY_FRAME)
+#error "Non multi-arch definition of DEPRECATED_PUSH_DUMMY_FRAME"
+#endif
+#if !defined (DEPRECATED_PUSH_DUMMY_FRAME)
+#define DEPRECATED_PUSH_DUMMY_FRAME (gdbarch_deprecated_push_dummy_frame (current_gdbarch))
+#endif
+
+#if defined (DEPRECATED_DO_REGISTERS_INFO)
+/* Legacy for systems yet to multi-arch DEPRECATED_DO_REGISTERS_INFO */
+#if !defined (DEPRECATED_DO_REGISTERS_INFO_P)
+#define DEPRECATED_DO_REGISTERS_INFO_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_do_registers_info_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_DO_REGISTERS_INFO_P)
+#error "Non multi-arch definition of DEPRECATED_DO_REGISTERS_INFO"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_DO_REGISTERS_INFO_P)
+#define DEPRECATED_DO_REGISTERS_INFO_P() (gdbarch_deprecated_do_registers_info_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_do_registers_info_ftype) (int reg_nr, int fpregs);
+extern void gdbarch_deprecated_do_registers_info (struct gdbarch *gdbarch, int reg_nr, int fpregs);
+extern void set_gdbarch_deprecated_do_registers_info (struct gdbarch *gdbarch, gdbarch_deprecated_do_registers_info_ftype *deprecated_do_registers_info);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_DO_REGISTERS_INFO)
+#error "Non multi-arch definition of DEPRECATED_DO_REGISTERS_INFO"
+#endif
+#if !defined (DEPRECATED_DO_REGISTERS_INFO)
+#define DEPRECATED_DO_REGISTERS_INFO(reg_nr, fpregs) (gdbarch_deprecated_do_registers_info (current_gdbarch, reg_nr, fpregs))
+#endif
+
+typedef void (gdbarch_print_registers_info_ftype) (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, int regnum, int all);
+extern void gdbarch_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, int regnum, int all);
+extern void set_gdbarch_print_registers_info (struct gdbarch *gdbarch, gdbarch_print_registers_info_ftype *print_registers_info);
+
+extern int gdbarch_print_float_info_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_print_float_info_ftype) (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args);
+extern void gdbarch_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args);
+extern void set_gdbarch_print_float_info (struct gdbarch *gdbarch, gdbarch_print_float_info_ftype *print_float_info);
+
+extern int gdbarch_print_vector_info_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_print_vector_info_ftype) (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args);
+extern void gdbarch_print_vector_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args);
+extern void set_gdbarch_print_vector_info (struct gdbarch *gdbarch, gdbarch_print_vector_info_ftype *print_vector_info);
+
+/* MAP a GDB RAW register number onto a simulator register number. See
+ also include/...-sim.h. */
+
+typedef int (gdbarch_register_sim_regno_ftype) (int reg_nr);
+extern int gdbarch_register_sim_regno (struct gdbarch *gdbarch, int reg_nr);
+extern void set_gdbarch_register_sim_regno (struct gdbarch *gdbarch, gdbarch_register_sim_regno_ftype *register_sim_regno);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (REGISTER_SIM_REGNO)
+#error "Non multi-arch definition of REGISTER_SIM_REGNO"
+#endif
+#if !defined (REGISTER_SIM_REGNO)
+#define REGISTER_SIM_REGNO(reg_nr) (gdbarch_register_sim_regno (current_gdbarch, reg_nr))
+#endif
+
+#if defined (REGISTER_BYTES_OK)
+/* Legacy for systems yet to multi-arch REGISTER_BYTES_OK */
+#if !defined (REGISTER_BYTES_OK_P)
+#define REGISTER_BYTES_OK_P() (1)
+#endif
+#endif
+
+extern int gdbarch_register_bytes_ok_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (REGISTER_BYTES_OK_P)
+#error "Non multi-arch definition of REGISTER_BYTES_OK"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (REGISTER_BYTES_OK_P)
+#define REGISTER_BYTES_OK_P() (gdbarch_register_bytes_ok_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_register_bytes_ok_ftype) (long nr_bytes);
+extern int gdbarch_register_bytes_ok (struct gdbarch *gdbarch, long nr_bytes);
+extern void set_gdbarch_register_bytes_ok (struct gdbarch *gdbarch, gdbarch_register_bytes_ok_ftype *register_bytes_ok);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (REGISTER_BYTES_OK)
+#error "Non multi-arch definition of REGISTER_BYTES_OK"
+#endif
+#if !defined (REGISTER_BYTES_OK)
+#define REGISTER_BYTES_OK(nr_bytes) (gdbarch_register_bytes_ok (current_gdbarch, nr_bytes))
+#endif
+
+typedef int (gdbarch_cannot_fetch_register_ftype) (int regnum);
+extern int gdbarch_cannot_fetch_register (struct gdbarch *gdbarch, int regnum);
+extern void set_gdbarch_cannot_fetch_register (struct gdbarch *gdbarch, gdbarch_cannot_fetch_register_ftype *cannot_fetch_register);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (CANNOT_FETCH_REGISTER)
+#error "Non multi-arch definition of CANNOT_FETCH_REGISTER"
+#endif
+#if !defined (CANNOT_FETCH_REGISTER)
+#define CANNOT_FETCH_REGISTER(regnum) (gdbarch_cannot_fetch_register (current_gdbarch, regnum))
+#endif
+
+typedef int (gdbarch_cannot_store_register_ftype) (int regnum);
+extern int gdbarch_cannot_store_register (struct gdbarch *gdbarch, int regnum);
+extern void set_gdbarch_cannot_store_register (struct gdbarch *gdbarch, gdbarch_cannot_store_register_ftype *cannot_store_register);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (CANNOT_STORE_REGISTER)
+#error "Non multi-arch definition of CANNOT_STORE_REGISTER"
+#endif
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regnum) (gdbarch_cannot_store_register (current_gdbarch, regnum))
+#endif
+
+/* setjmp/longjmp support. */
+
+#if defined (GET_LONGJMP_TARGET)
+/* Legacy for systems yet to multi-arch GET_LONGJMP_TARGET */
+#if !defined (GET_LONGJMP_TARGET_P)
+#define GET_LONGJMP_TARGET_P() (1)
+#endif
+#endif
+
+extern int gdbarch_get_longjmp_target_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (GET_LONGJMP_TARGET_P)
+#error "Non multi-arch definition of GET_LONGJMP_TARGET"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (GET_LONGJMP_TARGET_P)
+#define GET_LONGJMP_TARGET_P() (gdbarch_get_longjmp_target_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_get_longjmp_target_ftype) (CORE_ADDR *pc);
+extern int gdbarch_get_longjmp_target (struct gdbarch *gdbarch, CORE_ADDR *pc);
+extern void set_gdbarch_get_longjmp_target (struct gdbarch *gdbarch, gdbarch_get_longjmp_target_ftype *get_longjmp_target);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (GET_LONGJMP_TARGET)
+#error "Non multi-arch definition of GET_LONGJMP_TARGET"
+#endif
+#if !defined (GET_LONGJMP_TARGET)
+#define GET_LONGJMP_TARGET(pc) (gdbarch_get_longjmp_target (current_gdbarch, pc))
+#endif
+
+/* NOTE: cagney/2002-11-24: This function with predicate has a valid
+ (callable) initial value. As a consequence, even when the predicate
+ is false, the corresponding function works. This simplifies the
+ migration process - old code, calling DEPRECATED_PC_IN_CALL_DUMMY(),
+ doesn't need to be modified. */
+
+#if defined (DEPRECATED_PC_IN_CALL_DUMMY)
+/* Legacy for systems yet to multi-arch DEPRECATED_PC_IN_CALL_DUMMY */
+#if !defined (DEPRECATED_PC_IN_CALL_DUMMY_P)
+#define DEPRECATED_PC_IN_CALL_DUMMY_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_pc_in_call_dummy_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PC_IN_CALL_DUMMY_P)
+#error "Non multi-arch definition of DEPRECATED_PC_IN_CALL_DUMMY"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_PC_IN_CALL_DUMMY_P)
+#define DEPRECATED_PC_IN_CALL_DUMMY_P() (gdbarch_deprecated_pc_in_call_dummy_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_pc_in_call_dummy_ftype) (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR frame_address);
+extern int gdbarch_deprecated_pc_in_call_dummy (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR frame_address);
+extern void set_gdbarch_deprecated_pc_in_call_dummy (struct gdbarch *gdbarch, gdbarch_deprecated_pc_in_call_dummy_ftype *deprecated_pc_in_call_dummy);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_PC_IN_CALL_DUMMY)
+#error "Non multi-arch definition of DEPRECATED_PC_IN_CALL_DUMMY"
+#endif
+#if !defined (DEPRECATED_PC_IN_CALL_DUMMY)
+#define DEPRECATED_PC_IN_CALL_DUMMY(pc, sp, frame_address) (gdbarch_deprecated_pc_in_call_dummy (current_gdbarch, pc, sp, frame_address))
+#endif
+
+#if defined (DEPRECATED_INIT_FRAME_PC_FIRST)
+/* Legacy for systems yet to multi-arch DEPRECATED_INIT_FRAME_PC_FIRST */
+#if !defined (DEPRECATED_INIT_FRAME_PC_FIRST_P)
+#define DEPRECATED_INIT_FRAME_PC_FIRST_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_init_frame_pc_first_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_INIT_FRAME_PC_FIRST_P)
+#error "Non multi-arch definition of DEPRECATED_INIT_FRAME_PC_FIRST"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_INIT_FRAME_PC_FIRST_P)
+#define DEPRECATED_INIT_FRAME_PC_FIRST_P() (gdbarch_deprecated_init_frame_pc_first_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_init_frame_pc_first_ftype) (int fromleaf, struct frame_info *prev);
+extern CORE_ADDR gdbarch_deprecated_init_frame_pc_first (struct gdbarch *gdbarch, int fromleaf, struct frame_info *prev);
+extern void set_gdbarch_deprecated_init_frame_pc_first (struct gdbarch *gdbarch, gdbarch_deprecated_init_frame_pc_first_ftype *deprecated_init_frame_pc_first);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_INIT_FRAME_PC_FIRST)
+#error "Non multi-arch definition of DEPRECATED_INIT_FRAME_PC_FIRST"
+#endif
+#if !defined (DEPRECATED_INIT_FRAME_PC_FIRST)
+#define DEPRECATED_INIT_FRAME_PC_FIRST(fromleaf, prev) (gdbarch_deprecated_init_frame_pc_first (current_gdbarch, fromleaf, prev))
+#endif
+
+#if defined (DEPRECATED_INIT_FRAME_PC)
+/* Legacy for systems yet to multi-arch DEPRECATED_INIT_FRAME_PC */
+#if !defined (DEPRECATED_INIT_FRAME_PC_P)
+#define DEPRECATED_INIT_FRAME_PC_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_init_frame_pc_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_INIT_FRAME_PC_P)
+#error "Non multi-arch definition of DEPRECATED_INIT_FRAME_PC"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_INIT_FRAME_PC_P)
+#define DEPRECATED_INIT_FRAME_PC_P() (gdbarch_deprecated_init_frame_pc_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_init_frame_pc_ftype) (int fromleaf, struct frame_info *prev);
+extern CORE_ADDR gdbarch_deprecated_init_frame_pc (struct gdbarch *gdbarch, int fromleaf, struct frame_info *prev);
+extern void set_gdbarch_deprecated_init_frame_pc (struct gdbarch *gdbarch, gdbarch_deprecated_init_frame_pc_ftype *deprecated_init_frame_pc);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_INIT_FRAME_PC)
+#error "Non multi-arch definition of DEPRECATED_INIT_FRAME_PC"
+#endif
+#if !defined (DEPRECATED_INIT_FRAME_PC)
+#define DEPRECATED_INIT_FRAME_PC(fromleaf, prev) (gdbarch_deprecated_init_frame_pc (current_gdbarch, fromleaf, prev))
+#endif
+
+extern int gdbarch_believe_pcc_promotion (struct gdbarch *gdbarch);
+extern void set_gdbarch_believe_pcc_promotion (struct gdbarch *gdbarch, int believe_pcc_promotion);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (BELIEVE_PCC_PROMOTION)
+#error "Non multi-arch definition of BELIEVE_PCC_PROMOTION"
+#endif
+#if !defined (BELIEVE_PCC_PROMOTION)
+#define BELIEVE_PCC_PROMOTION (gdbarch_believe_pcc_promotion (current_gdbarch))
+#endif
+
+extern int gdbarch_believe_pcc_promotion_type (struct gdbarch *gdbarch);
+extern void set_gdbarch_believe_pcc_promotion_type (struct gdbarch *gdbarch, int believe_pcc_promotion_type);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (BELIEVE_PCC_PROMOTION_TYPE)
+#error "Non multi-arch definition of BELIEVE_PCC_PROMOTION_TYPE"
+#endif
+#if !defined (BELIEVE_PCC_PROMOTION_TYPE)
+#define BELIEVE_PCC_PROMOTION_TYPE (gdbarch_believe_pcc_promotion_type (current_gdbarch))
+#endif
+
+#if defined (DEPRECATED_GET_SAVED_REGISTER)
+/* Legacy for systems yet to multi-arch DEPRECATED_GET_SAVED_REGISTER */
+#if !defined (DEPRECATED_GET_SAVED_REGISTER_P)
+#define DEPRECATED_GET_SAVED_REGISTER_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_get_saved_register_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_GET_SAVED_REGISTER_P)
+#error "Non multi-arch definition of DEPRECATED_GET_SAVED_REGISTER"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_GET_SAVED_REGISTER_P)
+#define DEPRECATED_GET_SAVED_REGISTER_P() (gdbarch_deprecated_get_saved_register_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_get_saved_register_ftype) (char *raw_buffer, int *optimized, CORE_ADDR *addrp, struct frame_info *frame, int regnum, enum lval_type *lval);
+extern void gdbarch_deprecated_get_saved_register (struct gdbarch *gdbarch, char *raw_buffer, int *optimized, CORE_ADDR *addrp, struct frame_info *frame, int regnum, enum lval_type *lval);
+extern void set_gdbarch_deprecated_get_saved_register (struct gdbarch *gdbarch, gdbarch_deprecated_get_saved_register_ftype *deprecated_get_saved_register);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_GET_SAVED_REGISTER)
+#error "Non multi-arch definition of DEPRECATED_GET_SAVED_REGISTER"
+#endif
+#if !defined (DEPRECATED_GET_SAVED_REGISTER)
+#define DEPRECATED_GET_SAVED_REGISTER(raw_buffer, optimized, addrp, frame, regnum, lval) (gdbarch_deprecated_get_saved_register (current_gdbarch, raw_buffer, optimized, addrp, frame, regnum, lval))
+#endif
+
+/* For register <-> value conversions, replaced by CONVERT_REGISTER_P et.al.
+ For raw <-> cooked register conversions, replaced by pseudo registers. */
+
+#if defined (DEPRECATED_REGISTER_CONVERTIBLE)
+/* Legacy for systems yet to multi-arch DEPRECATED_REGISTER_CONVERTIBLE */
+#if !defined (DEPRECATED_REGISTER_CONVERTIBLE_P)
+#define DEPRECATED_REGISTER_CONVERTIBLE_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_register_convertible_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_CONVERTIBLE_P)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_CONVERTIBLE"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_REGISTER_CONVERTIBLE_P)
+#define DEPRECATED_REGISTER_CONVERTIBLE_P() (gdbarch_deprecated_register_convertible_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_register_convertible_ftype) (int nr);
+extern int gdbarch_deprecated_register_convertible (struct gdbarch *gdbarch, int nr);
+extern void set_gdbarch_deprecated_register_convertible (struct gdbarch *gdbarch, gdbarch_deprecated_register_convertible_ftype *deprecated_register_convertible);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_CONVERTIBLE)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_CONVERTIBLE"
+#endif
+#if !defined (DEPRECATED_REGISTER_CONVERTIBLE)
+#define DEPRECATED_REGISTER_CONVERTIBLE(nr) (gdbarch_deprecated_register_convertible (current_gdbarch, nr))
+#endif
+
+/* For register <-> value conversions, replaced by CONVERT_REGISTER_P et.al.
+ For raw <-> cooked register conversions, replaced by pseudo registers. */
+
+typedef void (gdbarch_deprecated_register_convert_to_virtual_ftype) (int regnum, struct type *type, char *from, char *to);
+extern void gdbarch_deprecated_register_convert_to_virtual (struct gdbarch *gdbarch, int regnum, struct type *type, char *from, char *to);
+extern void set_gdbarch_deprecated_register_convert_to_virtual (struct gdbarch *gdbarch, gdbarch_deprecated_register_convert_to_virtual_ftype *deprecated_register_convert_to_virtual);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL"
+#endif
+#if !defined (DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL)
+#define DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL(regnum, type, from, to) (gdbarch_deprecated_register_convert_to_virtual (current_gdbarch, regnum, type, from, to))
+#endif
+
+/* For register <-> value conversions, replaced by CONVERT_REGISTER_P et.al.
+ For raw <-> cooked register conversions, replaced by pseudo registers. */
+
+typedef void (gdbarch_deprecated_register_convert_to_raw_ftype) (struct type *type, int regnum, const char *from, char *to);
+extern void gdbarch_deprecated_register_convert_to_raw (struct gdbarch *gdbarch, struct type *type, int regnum, const char *from, char *to);
+extern void set_gdbarch_deprecated_register_convert_to_raw (struct gdbarch *gdbarch, gdbarch_deprecated_register_convert_to_raw_ftype *deprecated_register_convert_to_raw);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REGISTER_CONVERT_TO_RAW)
+#error "Non multi-arch definition of DEPRECATED_REGISTER_CONVERT_TO_RAW"
+#endif
+#if !defined (DEPRECATED_REGISTER_CONVERT_TO_RAW)
+#define DEPRECATED_REGISTER_CONVERT_TO_RAW(type, regnum, from, to) (gdbarch_deprecated_register_convert_to_raw (current_gdbarch, type, regnum, from, to))
+#endif
+
+typedef int (gdbarch_convert_register_p_ftype) (int regnum, struct type *type);
+extern int gdbarch_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type);
+extern void set_gdbarch_convert_register_p (struct gdbarch *gdbarch, gdbarch_convert_register_p_ftype *convert_register_p);
+#if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PARTIAL) && defined (CONVERT_REGISTER_P)
+#error "Non multi-arch definition of CONVERT_REGISTER_P"
+#endif
+#if !defined (CONVERT_REGISTER_P)
+#define CONVERT_REGISTER_P(regnum, type) (gdbarch_convert_register_p (current_gdbarch, regnum, type))
+#endif
+
+typedef void (gdbarch_register_to_value_ftype) (struct frame_info *frame, int regnum, struct type *type, void *buf);
+extern void gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, void *buf);
+extern void set_gdbarch_register_to_value (struct gdbarch *gdbarch, gdbarch_register_to_value_ftype *register_to_value);
+#if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PARTIAL) && defined (REGISTER_TO_VALUE)
+#error "Non multi-arch definition of REGISTER_TO_VALUE"
+#endif
+#if !defined (REGISTER_TO_VALUE)
+#define REGISTER_TO_VALUE(frame, regnum, type, buf) (gdbarch_register_to_value (current_gdbarch, frame, regnum, type, buf))
+#endif
+
+typedef void (gdbarch_value_to_register_ftype) (struct frame_info *frame, int regnum, struct type *type, const void *buf);
+extern void gdbarch_value_to_register (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, const void *buf);
+extern void set_gdbarch_value_to_register (struct gdbarch *gdbarch, gdbarch_value_to_register_ftype *value_to_register);
+#if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PARTIAL) && defined (VALUE_TO_REGISTER)
+#error "Non multi-arch definition of VALUE_TO_REGISTER"
+#endif
+#if !defined (VALUE_TO_REGISTER)
+#define VALUE_TO_REGISTER(frame, regnum, type, buf) (gdbarch_value_to_register (current_gdbarch, frame, regnum, type, buf))
+#endif
+
+typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct type *type, const void *buf);
+extern CORE_ADDR gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const void *buf);
+extern void set_gdbarch_pointer_to_address (struct gdbarch *gdbarch, gdbarch_pointer_to_address_ftype *pointer_to_address);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (POINTER_TO_ADDRESS)
+#error "Non multi-arch definition of POINTER_TO_ADDRESS"
+#endif
+#if !defined (POINTER_TO_ADDRESS)
+#define POINTER_TO_ADDRESS(type, buf) (gdbarch_pointer_to_address (current_gdbarch, type, buf))
+#endif
+
+typedef void (gdbarch_address_to_pointer_ftype) (struct type *type, void *buf, CORE_ADDR addr);
+extern void gdbarch_address_to_pointer (struct gdbarch *gdbarch, struct type *type, void *buf, CORE_ADDR addr);
+extern void set_gdbarch_address_to_pointer (struct gdbarch *gdbarch, gdbarch_address_to_pointer_ftype *address_to_pointer);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (ADDRESS_TO_POINTER)
+#error "Non multi-arch definition of ADDRESS_TO_POINTER"
+#endif
+#if !defined (ADDRESS_TO_POINTER)
+#define ADDRESS_TO_POINTER(type, buf, addr) (gdbarch_address_to_pointer (current_gdbarch, type, buf, addr))
+#endif
+
+#if defined (INTEGER_TO_ADDRESS)
+/* Legacy for systems yet to multi-arch INTEGER_TO_ADDRESS */
+#if !defined (INTEGER_TO_ADDRESS_P)
+#define INTEGER_TO_ADDRESS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_integer_to_address_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (INTEGER_TO_ADDRESS_P)
+#error "Non multi-arch definition of INTEGER_TO_ADDRESS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (INTEGER_TO_ADDRESS_P)
+#define INTEGER_TO_ADDRESS_P() (gdbarch_integer_to_address_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_integer_to_address_ftype) (struct type *type, void *buf);
+extern CORE_ADDR gdbarch_integer_to_address (struct gdbarch *gdbarch, struct type *type, void *buf);
+extern void set_gdbarch_integer_to_address (struct gdbarch *gdbarch, gdbarch_integer_to_address_ftype *integer_to_address);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (INTEGER_TO_ADDRESS)
+#error "Non multi-arch definition of INTEGER_TO_ADDRESS"
+#endif
+#if !defined (INTEGER_TO_ADDRESS)
+#define INTEGER_TO_ADDRESS(type, buf) (gdbarch_integer_to_address (current_gdbarch, type, buf))
+#endif
+
+#if defined (DEPRECATED_POP_FRAME)
+/* Legacy for systems yet to multi-arch DEPRECATED_POP_FRAME */
+#if !defined (DEPRECATED_POP_FRAME_P)
+#define DEPRECATED_POP_FRAME_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_pop_frame_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_POP_FRAME_P)
+#error "Non multi-arch definition of DEPRECATED_POP_FRAME"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_POP_FRAME_P)
+#define DEPRECATED_POP_FRAME_P() (gdbarch_deprecated_pop_frame_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_pop_frame_ftype) (void);
+extern void gdbarch_deprecated_pop_frame (struct gdbarch *gdbarch);
+extern void set_gdbarch_deprecated_pop_frame (struct gdbarch *gdbarch, gdbarch_deprecated_pop_frame_ftype *deprecated_pop_frame);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_POP_FRAME)
+#error "Non multi-arch definition of DEPRECATED_POP_FRAME"
+#endif
+#if !defined (DEPRECATED_POP_FRAME)
+#define DEPRECATED_POP_FRAME (gdbarch_deprecated_pop_frame (current_gdbarch))
+#endif
+
+/* NOTE: cagney/2003-03-24: Replaced by PUSH_ARGUMENTS. */
+
+#if defined (DEPRECATED_STORE_STRUCT_RETURN)
+/* Legacy for systems yet to multi-arch DEPRECATED_STORE_STRUCT_RETURN */
+#if !defined (DEPRECATED_STORE_STRUCT_RETURN_P)
+#define DEPRECATED_STORE_STRUCT_RETURN_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_store_struct_return_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_STORE_STRUCT_RETURN_P)
+#error "Non multi-arch definition of DEPRECATED_STORE_STRUCT_RETURN"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_STORE_STRUCT_RETURN_P)
+#define DEPRECATED_STORE_STRUCT_RETURN_P() (gdbarch_deprecated_store_struct_return_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_store_struct_return_ftype) (CORE_ADDR addr, CORE_ADDR sp);
+extern void gdbarch_deprecated_store_struct_return (struct gdbarch *gdbarch, CORE_ADDR addr, CORE_ADDR sp);
+extern void set_gdbarch_deprecated_store_struct_return (struct gdbarch *gdbarch, gdbarch_deprecated_store_struct_return_ftype *deprecated_store_struct_return);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_STORE_STRUCT_RETURN)
+#error "Non multi-arch definition of DEPRECATED_STORE_STRUCT_RETURN"
+#endif
+#if !defined (DEPRECATED_STORE_STRUCT_RETURN)
+#define DEPRECATED_STORE_STRUCT_RETURN(addr, sp) (gdbarch_deprecated_store_struct_return (current_gdbarch, addr, sp))
+#endif
+
+/* It has been suggested that this, well actually its predecessor,
+ should take the type/value of the function to be called and not the
+ return type. This is left as an exercise for the reader. */
+
+extern int gdbarch_return_value_p (struct gdbarch *gdbarch);
+
+typedef enum return_value_convention (gdbarch_return_value_ftype) (struct gdbarch *gdbarch, struct type *valtype, struct regcache *regcache, void *readbuf, const void *writebuf);
+extern enum return_value_convention gdbarch_return_value (struct gdbarch *gdbarch, struct type *valtype, struct regcache *regcache, void *readbuf, const void *writebuf);
+extern void set_gdbarch_return_value (struct gdbarch *gdbarch, gdbarch_return_value_ftype *return_value);
+
+/* The deprecated methods RETURN_VALUE_ON_STACK, EXTRACT_RETURN_VALUE,
+ STORE_RETURN_VALUE and USE_STRUCT_CONVENTION have all been folded
+ into RETURN_VALUE. */
+
+typedef int (gdbarch_return_value_on_stack_ftype) (struct type *type);
+extern int gdbarch_return_value_on_stack (struct gdbarch *gdbarch, struct type *type);
+extern void set_gdbarch_return_value_on_stack (struct gdbarch *gdbarch, gdbarch_return_value_on_stack_ftype *return_value_on_stack);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (RETURN_VALUE_ON_STACK)
+#error "Non multi-arch definition of RETURN_VALUE_ON_STACK"
+#endif
+#if !defined (RETURN_VALUE_ON_STACK)
+#define RETURN_VALUE_ON_STACK(type) (gdbarch_return_value_on_stack (current_gdbarch, type))
+#endif
+
+typedef void (gdbarch_extract_return_value_ftype) (struct type *type, struct regcache *regcache, void *valbuf);
+extern void gdbarch_extract_return_value (struct gdbarch *gdbarch, struct type *type, struct regcache *regcache, void *valbuf);
+extern void set_gdbarch_extract_return_value (struct gdbarch *gdbarch, gdbarch_extract_return_value_ftype *extract_return_value);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (EXTRACT_RETURN_VALUE)
+#error "Non multi-arch definition of EXTRACT_RETURN_VALUE"
+#endif
+#if !defined (EXTRACT_RETURN_VALUE)
+#define EXTRACT_RETURN_VALUE(type, regcache, valbuf) (gdbarch_extract_return_value (current_gdbarch, type, regcache, valbuf))
+#endif
+
+typedef void (gdbarch_store_return_value_ftype) (struct type *type, struct regcache *regcache, const void *valbuf);
+extern void gdbarch_store_return_value (struct gdbarch *gdbarch, struct type *type, struct regcache *regcache, const void *valbuf);
+extern void set_gdbarch_store_return_value (struct gdbarch *gdbarch, gdbarch_store_return_value_ftype *store_return_value);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (STORE_RETURN_VALUE)
+#error "Non multi-arch definition of STORE_RETURN_VALUE"
+#endif
+#if !defined (STORE_RETURN_VALUE)
+#define STORE_RETURN_VALUE(type, regcache, valbuf) (gdbarch_store_return_value (current_gdbarch, type, regcache, valbuf))
+#endif
+
+typedef void (gdbarch_deprecated_extract_return_value_ftype) (struct type *type, char *regbuf, char *valbuf);
+extern void gdbarch_deprecated_extract_return_value (struct gdbarch *gdbarch, struct type *type, char *regbuf, char *valbuf);
+extern void set_gdbarch_deprecated_extract_return_value (struct gdbarch *gdbarch, gdbarch_deprecated_extract_return_value_ftype *deprecated_extract_return_value);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_EXTRACT_RETURN_VALUE)
+#error "Non multi-arch definition of DEPRECATED_EXTRACT_RETURN_VALUE"
+#endif
+#if !defined (DEPRECATED_EXTRACT_RETURN_VALUE)
+#define DEPRECATED_EXTRACT_RETURN_VALUE(type, regbuf, valbuf) (gdbarch_deprecated_extract_return_value (current_gdbarch, type, regbuf, valbuf))
+#endif
+
+typedef void (gdbarch_deprecated_store_return_value_ftype) (struct type *type, char *valbuf);
+extern void gdbarch_deprecated_store_return_value (struct gdbarch *gdbarch, struct type *type, char *valbuf);
+extern void set_gdbarch_deprecated_store_return_value (struct gdbarch *gdbarch, gdbarch_deprecated_store_return_value_ftype *deprecated_store_return_value);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_STORE_RETURN_VALUE)
+#error "Non multi-arch definition of DEPRECATED_STORE_RETURN_VALUE"
+#endif
+#if !defined (DEPRECATED_STORE_RETURN_VALUE)
+#define DEPRECATED_STORE_RETURN_VALUE(type, valbuf) (gdbarch_deprecated_store_return_value (current_gdbarch, type, valbuf))
+#endif
+
+typedef int (gdbarch_use_struct_convention_ftype) (int gcc_p, struct type *value_type);
+extern int gdbarch_use_struct_convention (struct gdbarch *gdbarch, int gcc_p, struct type *value_type);
+extern void set_gdbarch_use_struct_convention (struct gdbarch *gdbarch, gdbarch_use_struct_convention_ftype *use_struct_convention);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (USE_STRUCT_CONVENTION)
+#error "Non multi-arch definition of USE_STRUCT_CONVENTION"
+#endif
+#if !defined (USE_STRUCT_CONVENTION)
+#define USE_STRUCT_CONVENTION(gcc_p, value_type) (gdbarch_use_struct_convention (current_gdbarch, gcc_p, value_type))
+#endif
+
+/* As of 2004-01-17 only the 32-bit SPARC ABI has been identified as an
+ ABI suitable for the implementation of a robust extract
+ struct-convention return-value address method (the sparc saves the
+ address in the callers frame). All the other cases so far examined,
+ the DEPRECATED_EXTRACT_STRUCT_VALUE implementation has been
+ erreneous - the code was incorrectly assuming that the return-value
+ address, stored in a register, was preserved across the entire
+ function call.
+ For the moment retain DEPRECATED_EXTRACT_STRUCT_VALUE as a marker of
+ the ABIs that are still to be analyzed - perhaps this should simply
+ be deleted. The commented out extract_returned_value_address method
+ is provided as a starting point for the 32-bit SPARC. It, or
+ something like it, along with changes to both infcmd.c and stack.c
+ will be needed for that case to work. NB: It is passed the callers
+ frame since it is only after the callee has returned that this
+ function is used.
+ M:::CORE_ADDR:extract_returned_value_address:struct frame_info *caller_frame:caller_frame */
+
+#if defined (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS)
+/* Legacy for systems yet to multi-arch DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS */
+#if !defined (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P)
+#define DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_extract_struct_value_address_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P)
+#error "Non multi-arch definition of DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P)
+#define DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P() (gdbarch_deprecated_extract_struct_value_address_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_extract_struct_value_address_ftype) (struct regcache *regcache);
+extern CORE_ADDR gdbarch_deprecated_extract_struct_value_address (struct gdbarch *gdbarch, struct regcache *regcache);
+extern void set_gdbarch_deprecated_extract_struct_value_address (struct gdbarch *gdbarch, gdbarch_deprecated_extract_struct_value_address_ftype *deprecated_extract_struct_value_address);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS)
+#error "Non multi-arch definition of DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS"
+#endif
+#if !defined (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS)
+#define DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS(regcache) (gdbarch_deprecated_extract_struct_value_address (current_gdbarch, regcache))
+#endif
+
+#if defined (DEPRECATED_FRAME_INIT_SAVED_REGS)
+/* Legacy for systems yet to multi-arch DEPRECATED_FRAME_INIT_SAVED_REGS */
+#if !defined (DEPRECATED_FRAME_INIT_SAVED_REGS_P)
+#define DEPRECATED_FRAME_INIT_SAVED_REGS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_frame_init_saved_regs_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_INIT_SAVED_REGS_P)
+#error "Non multi-arch definition of DEPRECATED_FRAME_INIT_SAVED_REGS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FRAME_INIT_SAVED_REGS_P)
+#define DEPRECATED_FRAME_INIT_SAVED_REGS_P() (gdbarch_deprecated_frame_init_saved_regs_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_frame_init_saved_regs_ftype) (struct frame_info *frame);
+extern void gdbarch_deprecated_frame_init_saved_regs (struct gdbarch *gdbarch, struct frame_info *frame);
+extern void set_gdbarch_deprecated_frame_init_saved_regs (struct gdbarch *gdbarch, gdbarch_deprecated_frame_init_saved_regs_ftype *deprecated_frame_init_saved_regs);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_INIT_SAVED_REGS)
+#error "Non multi-arch definition of DEPRECATED_FRAME_INIT_SAVED_REGS"
+#endif
+#if !defined (DEPRECATED_FRAME_INIT_SAVED_REGS)
+#define DEPRECATED_FRAME_INIT_SAVED_REGS(frame) (gdbarch_deprecated_frame_init_saved_regs (current_gdbarch, frame))
+#endif
+
+#if defined (DEPRECATED_INIT_EXTRA_FRAME_INFO)
+/* Legacy for systems yet to multi-arch DEPRECATED_INIT_EXTRA_FRAME_INFO */
+#if !defined (DEPRECATED_INIT_EXTRA_FRAME_INFO_P)
+#define DEPRECATED_INIT_EXTRA_FRAME_INFO_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_init_extra_frame_info_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_INIT_EXTRA_FRAME_INFO_P)
+#error "Non multi-arch definition of DEPRECATED_INIT_EXTRA_FRAME_INFO"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_INIT_EXTRA_FRAME_INFO_P)
+#define DEPRECATED_INIT_EXTRA_FRAME_INFO_P() (gdbarch_deprecated_init_extra_frame_info_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_deprecated_init_extra_frame_info_ftype) (int fromleaf, struct frame_info *frame);
+extern void gdbarch_deprecated_init_extra_frame_info (struct gdbarch *gdbarch, int fromleaf, struct frame_info *frame);
+extern void set_gdbarch_deprecated_init_extra_frame_info (struct gdbarch *gdbarch, gdbarch_deprecated_init_extra_frame_info_ftype *deprecated_init_extra_frame_info);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_INIT_EXTRA_FRAME_INFO)
+#error "Non multi-arch definition of DEPRECATED_INIT_EXTRA_FRAME_INFO"
+#endif
+#if !defined (DEPRECATED_INIT_EXTRA_FRAME_INFO)
+#define DEPRECATED_INIT_EXTRA_FRAME_INFO(fromleaf, frame) (gdbarch_deprecated_init_extra_frame_info (current_gdbarch, fromleaf, frame))
+#endif
+
+typedef CORE_ADDR (gdbarch_skip_prologue_ftype) (CORE_ADDR ip);
+extern CORE_ADDR gdbarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR ip);
+extern void set_gdbarch_skip_prologue (struct gdbarch *gdbarch, gdbarch_skip_prologue_ftype *skip_prologue);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SKIP_PROLOGUE)
+#error "Non multi-arch definition of SKIP_PROLOGUE"
+#endif
+#if !defined (SKIP_PROLOGUE)
+#define SKIP_PROLOGUE(ip) (gdbarch_skip_prologue (current_gdbarch, ip))
+#endif
+
+typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs);
+extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs);
+extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (INNER_THAN)
+#error "Non multi-arch definition of INNER_THAN"
+#endif
+#if !defined (INNER_THAN)
+#define INNER_THAN(lhs, rhs) (gdbarch_inner_than (current_gdbarch, lhs, rhs))
+#endif
+
+typedef const unsigned char * (gdbarch_breakpoint_from_pc_ftype) (CORE_ADDR *pcptr, int *lenptr);
+extern const unsigned char * gdbarch_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr);
+extern void set_gdbarch_breakpoint_from_pc (struct gdbarch *gdbarch, gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (BREAKPOINT_FROM_PC)
+#error "Non multi-arch definition of BREAKPOINT_FROM_PC"
+#endif
+#if !defined (BREAKPOINT_FROM_PC)
+#define BREAKPOINT_FROM_PC(pcptr, lenptr) (gdbarch_breakpoint_from_pc (current_gdbarch, pcptr, lenptr))
+#endif
+
+extern int gdbarch_adjust_breakpoint_address_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_adjust_breakpoint_address_ftype) (struct gdbarch *gdbarch, CORE_ADDR bpaddr);
+extern CORE_ADDR gdbarch_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr);
+extern void set_gdbarch_adjust_breakpoint_address (struct gdbarch *gdbarch, gdbarch_adjust_breakpoint_address_ftype *adjust_breakpoint_address);
+
+typedef int (gdbarch_memory_insert_breakpoint_ftype) (CORE_ADDR addr, char *contents_cache);
+extern int gdbarch_memory_insert_breakpoint (struct gdbarch *gdbarch, CORE_ADDR addr, char *contents_cache);
+extern void set_gdbarch_memory_insert_breakpoint (struct gdbarch *gdbarch, gdbarch_memory_insert_breakpoint_ftype *memory_insert_breakpoint);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (MEMORY_INSERT_BREAKPOINT)
+#error "Non multi-arch definition of MEMORY_INSERT_BREAKPOINT"
+#endif
+#if !defined (MEMORY_INSERT_BREAKPOINT)
+#define MEMORY_INSERT_BREAKPOINT(addr, contents_cache) (gdbarch_memory_insert_breakpoint (current_gdbarch, addr, contents_cache))
+#endif
+
+typedef int (gdbarch_memory_remove_breakpoint_ftype) (CORE_ADDR addr, char *contents_cache);
+extern int gdbarch_memory_remove_breakpoint (struct gdbarch *gdbarch, CORE_ADDR addr, char *contents_cache);
+extern void set_gdbarch_memory_remove_breakpoint (struct gdbarch *gdbarch, gdbarch_memory_remove_breakpoint_ftype *memory_remove_breakpoint);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (MEMORY_REMOVE_BREAKPOINT)
+#error "Non multi-arch definition of MEMORY_REMOVE_BREAKPOINT"
+#endif
+#if !defined (MEMORY_REMOVE_BREAKPOINT)
+#define MEMORY_REMOVE_BREAKPOINT(addr, contents_cache) (gdbarch_memory_remove_breakpoint (current_gdbarch, addr, contents_cache))
+#endif
+
+extern CORE_ADDR gdbarch_decr_pc_after_break (struct gdbarch *gdbarch);
+extern void set_gdbarch_decr_pc_after_break (struct gdbarch *gdbarch, CORE_ADDR decr_pc_after_break);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DECR_PC_AFTER_BREAK)
+#error "Non multi-arch definition of DECR_PC_AFTER_BREAK"
+#endif
+#if !defined (DECR_PC_AFTER_BREAK)
+#define DECR_PC_AFTER_BREAK (gdbarch_decr_pc_after_break (current_gdbarch))
+#endif
+
+extern CORE_ADDR gdbarch_function_start_offset (struct gdbarch *gdbarch);
+extern void set_gdbarch_function_start_offset (struct gdbarch *gdbarch, CORE_ADDR function_start_offset);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FUNCTION_START_OFFSET)
+#error "Non multi-arch definition of FUNCTION_START_OFFSET"
+#endif
+#if !defined (FUNCTION_START_OFFSET)
+#define FUNCTION_START_OFFSET (gdbarch_function_start_offset (current_gdbarch))
+#endif
+
+typedef void (gdbarch_remote_translate_xfer_address_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len);
+extern void gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len);
+extern void set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address);
+
+extern CORE_ADDR gdbarch_frame_args_skip (struct gdbarch *gdbarch);
+extern void set_gdbarch_frame_args_skip (struct gdbarch *gdbarch, CORE_ADDR frame_args_skip);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FRAME_ARGS_SKIP)
+#error "Non multi-arch definition of FRAME_ARGS_SKIP"
+#endif
+#if !defined (FRAME_ARGS_SKIP)
+#define FRAME_ARGS_SKIP (gdbarch_frame_args_skip (current_gdbarch))
+#endif
+
+/* DEPRECATED_FRAMELESS_FUNCTION_INVOCATION is not needed. The new
+ frame code works regardless of the type of frame - frameless,
+ stackless, or normal. */
+
+#if defined (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION)
+/* Legacy for systems yet to multi-arch DEPRECATED_FRAMELESS_FUNCTION_INVOCATION */
+#if !defined (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P)
+#define DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_frameless_function_invocation_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P)
+#error "Non multi-arch definition of DEPRECATED_FRAMELESS_FUNCTION_INVOCATION"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P)
+#define DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P() (gdbarch_deprecated_frameless_function_invocation_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_frameless_function_invocation_ftype) (struct frame_info *fi);
+extern int gdbarch_deprecated_frameless_function_invocation (struct gdbarch *gdbarch, struct frame_info *fi);
+extern void set_gdbarch_deprecated_frameless_function_invocation (struct gdbarch *gdbarch, gdbarch_deprecated_frameless_function_invocation_ftype *deprecated_frameless_function_invocation);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION)
+#error "Non multi-arch definition of DEPRECATED_FRAMELESS_FUNCTION_INVOCATION"
+#endif
+#if !defined (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION)
+#define DEPRECATED_FRAMELESS_FUNCTION_INVOCATION(fi) (gdbarch_deprecated_frameless_function_invocation (current_gdbarch, fi))
+#endif
+
+#if defined (DEPRECATED_FRAME_CHAIN)
+/* Legacy for systems yet to multi-arch DEPRECATED_FRAME_CHAIN */
+#if !defined (DEPRECATED_FRAME_CHAIN_P)
+#define DEPRECATED_FRAME_CHAIN_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_frame_chain_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_CHAIN_P)
+#error "Non multi-arch definition of DEPRECATED_FRAME_CHAIN"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FRAME_CHAIN_P)
+#define DEPRECATED_FRAME_CHAIN_P() (gdbarch_deprecated_frame_chain_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_frame_chain_ftype) (struct frame_info *frame);
+extern CORE_ADDR gdbarch_deprecated_frame_chain (struct gdbarch *gdbarch, struct frame_info *frame);
+extern void set_gdbarch_deprecated_frame_chain (struct gdbarch *gdbarch, gdbarch_deprecated_frame_chain_ftype *deprecated_frame_chain);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_CHAIN)
+#error "Non multi-arch definition of DEPRECATED_FRAME_CHAIN"
+#endif
+#if !defined (DEPRECATED_FRAME_CHAIN)
+#define DEPRECATED_FRAME_CHAIN(frame) (gdbarch_deprecated_frame_chain (current_gdbarch, frame))
+#endif
+
+#if defined (DEPRECATED_FRAME_CHAIN_VALID)
+/* Legacy for systems yet to multi-arch DEPRECATED_FRAME_CHAIN_VALID */
+#if !defined (DEPRECATED_FRAME_CHAIN_VALID_P)
+#define DEPRECATED_FRAME_CHAIN_VALID_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_frame_chain_valid_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_CHAIN_VALID_P)
+#error "Non multi-arch definition of DEPRECATED_FRAME_CHAIN_VALID"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FRAME_CHAIN_VALID_P)
+#define DEPRECATED_FRAME_CHAIN_VALID_P() (gdbarch_deprecated_frame_chain_valid_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_frame_chain_valid_ftype) (CORE_ADDR chain, struct frame_info *thisframe);
+extern int gdbarch_deprecated_frame_chain_valid (struct gdbarch *gdbarch, CORE_ADDR chain, struct frame_info *thisframe);
+extern void set_gdbarch_deprecated_frame_chain_valid (struct gdbarch *gdbarch, gdbarch_deprecated_frame_chain_valid_ftype *deprecated_frame_chain_valid);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_CHAIN_VALID)
+#error "Non multi-arch definition of DEPRECATED_FRAME_CHAIN_VALID"
+#endif
+#if !defined (DEPRECATED_FRAME_CHAIN_VALID)
+#define DEPRECATED_FRAME_CHAIN_VALID(chain, thisframe) (gdbarch_deprecated_frame_chain_valid (current_gdbarch, chain, thisframe))
+#endif
+
+/* DEPRECATED_FRAME_SAVED_PC has been replaced by UNWIND_PC. Please
+ note, per UNWIND_PC's doco, that while the two have similar
+ interfaces they have very different underlying implementations. */
+
+#if defined (DEPRECATED_FRAME_SAVED_PC)
+/* Legacy for systems yet to multi-arch DEPRECATED_FRAME_SAVED_PC */
+#if !defined (DEPRECATED_FRAME_SAVED_PC_P)
+#define DEPRECATED_FRAME_SAVED_PC_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_frame_saved_pc_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_SAVED_PC_P)
+#error "Non multi-arch definition of DEPRECATED_FRAME_SAVED_PC"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FRAME_SAVED_PC_P)
+#define DEPRECATED_FRAME_SAVED_PC_P() (gdbarch_deprecated_frame_saved_pc_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_frame_saved_pc_ftype) (struct frame_info *fi);
+extern CORE_ADDR gdbarch_deprecated_frame_saved_pc (struct gdbarch *gdbarch, struct frame_info *fi);
+extern void set_gdbarch_deprecated_frame_saved_pc (struct gdbarch *gdbarch, gdbarch_deprecated_frame_saved_pc_ftype *deprecated_frame_saved_pc);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_SAVED_PC)
+#error "Non multi-arch definition of DEPRECATED_FRAME_SAVED_PC"
+#endif
+#if !defined (DEPRECATED_FRAME_SAVED_PC)
+#define DEPRECATED_FRAME_SAVED_PC(fi) (gdbarch_deprecated_frame_saved_pc (current_gdbarch, fi))
+#endif
+
+extern int gdbarch_unwind_pc_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_unwind_pc_ftype) (struct gdbarch *gdbarch, struct frame_info *next_frame);
+extern CORE_ADDR gdbarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame);
+extern void set_gdbarch_unwind_pc (struct gdbarch *gdbarch, gdbarch_unwind_pc_ftype *unwind_pc);
+
+extern int gdbarch_unwind_sp_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_unwind_sp_ftype) (struct gdbarch *gdbarch, struct frame_info *next_frame);
+extern CORE_ADDR gdbarch_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame);
+extern void set_gdbarch_unwind_sp (struct gdbarch *gdbarch, gdbarch_unwind_sp_ftype *unwind_sp);
+
+/* DEPRECATED_FRAME_ARGS_ADDRESS as been replaced by the per-frame
+ frame-base. Enable frame-base before frame-unwind. */
+
+#if defined (DEPRECATED_FRAME_ARGS_ADDRESS)
+/* Legacy for systems yet to multi-arch DEPRECATED_FRAME_ARGS_ADDRESS */
+#if !defined (DEPRECATED_FRAME_ARGS_ADDRESS_P)
+#define DEPRECATED_FRAME_ARGS_ADDRESS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_frame_args_address_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_ARGS_ADDRESS_P)
+#error "Non multi-arch definition of DEPRECATED_FRAME_ARGS_ADDRESS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FRAME_ARGS_ADDRESS_P)
+#define DEPRECATED_FRAME_ARGS_ADDRESS_P() (gdbarch_deprecated_frame_args_address_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_frame_args_address_ftype) (struct frame_info *fi);
+extern CORE_ADDR gdbarch_deprecated_frame_args_address (struct gdbarch *gdbarch, struct frame_info *fi);
+extern void set_gdbarch_deprecated_frame_args_address (struct gdbarch *gdbarch, gdbarch_deprecated_frame_args_address_ftype *deprecated_frame_args_address);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_ARGS_ADDRESS)
+#error "Non multi-arch definition of DEPRECATED_FRAME_ARGS_ADDRESS"
+#endif
+#if !defined (DEPRECATED_FRAME_ARGS_ADDRESS)
+#define DEPRECATED_FRAME_ARGS_ADDRESS(fi) (gdbarch_deprecated_frame_args_address (current_gdbarch, fi))
+#endif
+
+/* DEPRECATED_FRAME_LOCALS_ADDRESS as been replaced by the per-frame
+ frame-base. Enable frame-base before frame-unwind. */
+
+#if defined (DEPRECATED_FRAME_LOCALS_ADDRESS)
+/* Legacy for systems yet to multi-arch DEPRECATED_FRAME_LOCALS_ADDRESS */
+#if !defined (DEPRECATED_FRAME_LOCALS_ADDRESS_P)
+#define DEPRECATED_FRAME_LOCALS_ADDRESS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_frame_locals_address_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_LOCALS_ADDRESS_P)
+#error "Non multi-arch definition of DEPRECATED_FRAME_LOCALS_ADDRESS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_FRAME_LOCALS_ADDRESS_P)
+#define DEPRECATED_FRAME_LOCALS_ADDRESS_P() (gdbarch_deprecated_frame_locals_address_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_frame_locals_address_ftype) (struct frame_info *fi);
+extern CORE_ADDR gdbarch_deprecated_frame_locals_address (struct gdbarch *gdbarch, struct frame_info *fi);
+extern void set_gdbarch_deprecated_frame_locals_address (struct gdbarch *gdbarch, gdbarch_deprecated_frame_locals_address_ftype *deprecated_frame_locals_address);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_FRAME_LOCALS_ADDRESS)
+#error "Non multi-arch definition of DEPRECATED_FRAME_LOCALS_ADDRESS"
+#endif
+#if !defined (DEPRECATED_FRAME_LOCALS_ADDRESS)
+#define DEPRECATED_FRAME_LOCALS_ADDRESS(fi) (gdbarch_deprecated_frame_locals_address (current_gdbarch, fi))
+#endif
+
+#if defined (DEPRECATED_SAVED_PC_AFTER_CALL)
+/* Legacy for systems yet to multi-arch DEPRECATED_SAVED_PC_AFTER_CALL */
+#if !defined (DEPRECATED_SAVED_PC_AFTER_CALL_P)
+#define DEPRECATED_SAVED_PC_AFTER_CALL_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_saved_pc_after_call_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_SAVED_PC_AFTER_CALL_P)
+#error "Non multi-arch definition of DEPRECATED_SAVED_PC_AFTER_CALL"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_SAVED_PC_AFTER_CALL_P)
+#define DEPRECATED_SAVED_PC_AFTER_CALL_P() (gdbarch_deprecated_saved_pc_after_call_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_saved_pc_after_call_ftype) (struct frame_info *frame);
+extern CORE_ADDR gdbarch_deprecated_saved_pc_after_call (struct gdbarch *gdbarch, struct frame_info *frame);
+extern void set_gdbarch_deprecated_saved_pc_after_call (struct gdbarch *gdbarch, gdbarch_deprecated_saved_pc_after_call_ftype *deprecated_saved_pc_after_call);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_SAVED_PC_AFTER_CALL)
+#error "Non multi-arch definition of DEPRECATED_SAVED_PC_AFTER_CALL"
+#endif
+#if !defined (DEPRECATED_SAVED_PC_AFTER_CALL)
+#define DEPRECATED_SAVED_PC_AFTER_CALL(frame) (gdbarch_deprecated_saved_pc_after_call (current_gdbarch, frame))
+#endif
+
+#if defined (FRAME_NUM_ARGS)
+/* Legacy for systems yet to multi-arch FRAME_NUM_ARGS */
+#if !defined (FRAME_NUM_ARGS_P)
+#define FRAME_NUM_ARGS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_frame_num_args_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FRAME_NUM_ARGS_P)
+#error "Non multi-arch definition of FRAME_NUM_ARGS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (FRAME_NUM_ARGS_P)
+#define FRAME_NUM_ARGS_P() (gdbarch_frame_num_args_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_frame_num_args_ftype) (struct frame_info *frame);
+extern int gdbarch_frame_num_args (struct gdbarch *gdbarch, struct frame_info *frame);
+extern void set_gdbarch_frame_num_args (struct gdbarch *gdbarch, gdbarch_frame_num_args_ftype *frame_num_args);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FRAME_NUM_ARGS)
+#error "Non multi-arch definition of FRAME_NUM_ARGS"
+#endif
+#if !defined (FRAME_NUM_ARGS)
+#define FRAME_NUM_ARGS(frame) (gdbarch_frame_num_args (current_gdbarch, frame))
+#endif
+
+/* DEPRECATED_STACK_ALIGN has been replaced by an initial aligning call
+ to frame_align and the requirement that methods such as
+ push_dummy_call and frame_red_zone_size maintain correct stack/frame
+ alignment. */
+
+#if defined (DEPRECATED_STACK_ALIGN)
+/* Legacy for systems yet to multi-arch DEPRECATED_STACK_ALIGN */
+#if !defined (DEPRECATED_STACK_ALIGN_P)
+#define DEPRECATED_STACK_ALIGN_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_stack_align_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_STACK_ALIGN_P)
+#error "Non multi-arch definition of DEPRECATED_STACK_ALIGN"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_STACK_ALIGN_P)
+#define DEPRECATED_STACK_ALIGN_P() (gdbarch_deprecated_stack_align_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_deprecated_stack_align_ftype) (CORE_ADDR sp);
+extern CORE_ADDR gdbarch_deprecated_stack_align (struct gdbarch *gdbarch, CORE_ADDR sp);
+extern void set_gdbarch_deprecated_stack_align (struct gdbarch *gdbarch, gdbarch_deprecated_stack_align_ftype *deprecated_stack_align);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_STACK_ALIGN)
+#error "Non multi-arch definition of DEPRECATED_STACK_ALIGN"
+#endif
+#if !defined (DEPRECATED_STACK_ALIGN)
+#define DEPRECATED_STACK_ALIGN(sp) (gdbarch_deprecated_stack_align (current_gdbarch, sp))
+#endif
+
+extern int gdbarch_frame_align_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_frame_align_ftype) (struct gdbarch *gdbarch, CORE_ADDR address);
+extern CORE_ADDR gdbarch_frame_align (struct gdbarch *gdbarch, CORE_ADDR address);
+extern void set_gdbarch_frame_align (struct gdbarch *gdbarch, gdbarch_frame_align_ftype *frame_align);
+
+/* DEPRECATED_REG_STRUCT_HAS_ADDR has been replaced by
+ stabs_argument_has_addr. */
+
+#if defined (DEPRECATED_REG_STRUCT_HAS_ADDR)
+/* Legacy for systems yet to multi-arch DEPRECATED_REG_STRUCT_HAS_ADDR */
+#if !defined (DEPRECATED_REG_STRUCT_HAS_ADDR_P)
+#define DEPRECATED_REG_STRUCT_HAS_ADDR_P() (1)
+#endif
+#endif
+
+extern int gdbarch_deprecated_reg_struct_has_addr_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REG_STRUCT_HAS_ADDR_P)
+#error "Non multi-arch definition of DEPRECATED_REG_STRUCT_HAS_ADDR"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DEPRECATED_REG_STRUCT_HAS_ADDR_P)
+#define DEPRECATED_REG_STRUCT_HAS_ADDR_P() (gdbarch_deprecated_reg_struct_has_addr_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_deprecated_reg_struct_has_addr_ftype) (int gcc_p, struct type *type);
+extern int gdbarch_deprecated_reg_struct_has_addr (struct gdbarch *gdbarch, int gcc_p, struct type *type);
+extern void set_gdbarch_deprecated_reg_struct_has_addr (struct gdbarch *gdbarch, gdbarch_deprecated_reg_struct_has_addr_ftype *deprecated_reg_struct_has_addr);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DEPRECATED_REG_STRUCT_HAS_ADDR)
+#error "Non multi-arch definition of DEPRECATED_REG_STRUCT_HAS_ADDR"
+#endif
+#if !defined (DEPRECATED_REG_STRUCT_HAS_ADDR)
+#define DEPRECATED_REG_STRUCT_HAS_ADDR(gcc_p, type) (gdbarch_deprecated_reg_struct_has_addr (current_gdbarch, gcc_p, type))
+#endif
+
+typedef int (gdbarch_stabs_argument_has_addr_ftype) (struct gdbarch *gdbarch, struct type *type);
+extern int gdbarch_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type);
+extern void set_gdbarch_stabs_argument_has_addr (struct gdbarch *gdbarch, gdbarch_stabs_argument_has_addr_ftype *stabs_argument_has_addr);
+
+extern int gdbarch_frame_red_zone_size (struct gdbarch *gdbarch);
+extern void set_gdbarch_frame_red_zone_size (struct gdbarch *gdbarch, int frame_red_zone_size);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FRAME_RED_ZONE_SIZE)
+#error "Non multi-arch definition of FRAME_RED_ZONE_SIZE"
+#endif
+#if !defined (FRAME_RED_ZONE_SIZE)
+#define FRAME_RED_ZONE_SIZE (gdbarch_frame_red_zone_size (current_gdbarch))
+#endif
+
+extern int gdbarch_parm_boundary (struct gdbarch *gdbarch);
+extern void set_gdbarch_parm_boundary (struct gdbarch *gdbarch, int parm_boundary);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (PARM_BOUNDARY)
+#error "Non multi-arch definition of PARM_BOUNDARY"
+#endif
+#if !defined (PARM_BOUNDARY)
+#define PARM_BOUNDARY (gdbarch_parm_boundary (current_gdbarch))
+#endif
+
+extern const struct floatformat * gdbarch_float_format (struct gdbarch *gdbarch);
+extern void set_gdbarch_float_format (struct gdbarch *gdbarch, const struct floatformat * float_format);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_FLOAT_FORMAT)
+#error "Non multi-arch definition of TARGET_FLOAT_FORMAT"
+#endif
+#if !defined (TARGET_FLOAT_FORMAT)
+#define TARGET_FLOAT_FORMAT (gdbarch_float_format (current_gdbarch))
+#endif
+
+extern const struct floatformat * gdbarch_double_format (struct gdbarch *gdbarch);
+extern void set_gdbarch_double_format (struct gdbarch *gdbarch, const struct floatformat * double_format);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_DOUBLE_FORMAT)
+#error "Non multi-arch definition of TARGET_DOUBLE_FORMAT"
+#endif
+#if !defined (TARGET_DOUBLE_FORMAT)
+#define TARGET_DOUBLE_FORMAT (gdbarch_double_format (current_gdbarch))
+#endif
+
+extern const struct floatformat * gdbarch_long_double_format (struct gdbarch *gdbarch);
+extern void set_gdbarch_long_double_format (struct gdbarch *gdbarch, const struct floatformat * long_double_format);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_LONG_DOUBLE_FORMAT)
+#error "Non multi-arch definition of TARGET_LONG_DOUBLE_FORMAT"
+#endif
+#if !defined (TARGET_LONG_DOUBLE_FORMAT)
+#define TARGET_LONG_DOUBLE_FORMAT (gdbarch_long_double_format (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_convert_from_func_ptr_addr_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr, struct target_ops *targ);
+extern CORE_ADDR gdbarch_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr, struct target_ops *targ);
+extern void set_gdbarch_convert_from_func_ptr_addr (struct gdbarch *gdbarch, gdbarch_convert_from_func_ptr_addr_ftype *convert_from_func_ptr_addr);
+
+/* 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). */
+
+typedef CORE_ADDR (gdbarch_addr_bits_remove_ftype) (CORE_ADDR addr);
+extern CORE_ADDR gdbarch_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch, gdbarch_addr_bits_remove_ftype *addr_bits_remove);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (ADDR_BITS_REMOVE)
+#error "Non multi-arch definition of ADDR_BITS_REMOVE"
+#endif
+#if !defined (ADDR_BITS_REMOVE)
+#define ADDR_BITS_REMOVE(addr) (gdbarch_addr_bits_remove (current_gdbarch, addr))
+#endif
+
+/* It is not at all clear why SMASH_TEXT_ADDRESS is not folded into
+ ADDR_BITS_REMOVE. */
+
+typedef CORE_ADDR (gdbarch_smash_text_address_ftype) (CORE_ADDR addr);
+extern CORE_ADDR gdbarch_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_smash_text_address (struct gdbarch *gdbarch, gdbarch_smash_text_address_ftype *smash_text_address);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SMASH_TEXT_ADDRESS)
+#error "Non multi-arch definition of SMASH_TEXT_ADDRESS"
+#endif
+#if !defined (SMASH_TEXT_ADDRESS)
+#define SMASH_TEXT_ADDRESS(addr) (gdbarch_smash_text_address (current_gdbarch, addr))
+#endif
+
+/* FIXME/cagney/2001-01-18: This should be split in two. A target method that indicates if
+ the target needs software single step. An ISA method to implement it.
+
+ FIXME/cagney/2001-01-18: This should be replaced with something that inserts breakpoints
+ using the breakpoint system instead of blatting memory directly (as with rs6000).
+
+ FIXME/cagney/2001-01-18: The logic is backwards. It should be asking if the target can
+ single step. If not, then implement single step using breakpoints. */
+
+#if defined (SOFTWARE_SINGLE_STEP)
+/* Legacy for systems yet to multi-arch SOFTWARE_SINGLE_STEP */
+#if !defined (SOFTWARE_SINGLE_STEP_P)
+#define SOFTWARE_SINGLE_STEP_P() (1)
+#endif
+#endif
+
+extern int gdbarch_software_single_step_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SOFTWARE_SINGLE_STEP_P)
+#error "Non multi-arch definition of SOFTWARE_SINGLE_STEP"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (SOFTWARE_SINGLE_STEP_P)
+#define SOFTWARE_SINGLE_STEP_P() (gdbarch_software_single_step_p (current_gdbarch))
+#endif
+
+typedef void (gdbarch_software_single_step_ftype) (enum target_signal sig, int insert_breakpoints_p);
+extern void gdbarch_software_single_step (struct gdbarch *gdbarch, enum target_signal sig, int insert_breakpoints_p);
+extern void set_gdbarch_software_single_step (struct gdbarch *gdbarch, gdbarch_software_single_step_ftype *software_single_step);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SOFTWARE_SINGLE_STEP)
+#error "Non multi-arch definition of SOFTWARE_SINGLE_STEP"
+#endif
+#if !defined (SOFTWARE_SINGLE_STEP)
+#define SOFTWARE_SINGLE_STEP(sig, insert_breakpoints_p) (gdbarch_software_single_step (current_gdbarch, sig, insert_breakpoints_p))
+#endif
+
+/* FIXME: cagney/2003-08-28: Need to find a better way of selecting the
+ disassembler. Perhaphs objdump can handle it? */
+
+typedef int (gdbarch_print_insn_ftype) (bfd_vma vma, struct disassemble_info *info);
+extern int gdbarch_print_insn (struct gdbarch *gdbarch, bfd_vma vma, struct disassemble_info *info);
+extern void set_gdbarch_print_insn (struct gdbarch *gdbarch, gdbarch_print_insn_ftype *print_insn);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (TARGET_PRINT_INSN)
+#error "Non multi-arch definition of TARGET_PRINT_INSN"
+#endif
+#if !defined (TARGET_PRINT_INSN)
+#define TARGET_PRINT_INSN(vma, info) (gdbarch_print_insn (current_gdbarch, vma, info))
+#endif
+
+typedef CORE_ADDR (gdbarch_skip_trampoline_code_ftype) (CORE_ADDR pc);
+extern CORE_ADDR gdbarch_skip_trampoline_code (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern void set_gdbarch_skip_trampoline_code (struct gdbarch *gdbarch, gdbarch_skip_trampoline_code_ftype *skip_trampoline_code);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SKIP_TRAMPOLINE_CODE)
+#error "Non multi-arch definition of SKIP_TRAMPOLINE_CODE"
+#endif
+#if !defined (SKIP_TRAMPOLINE_CODE)
+#define SKIP_TRAMPOLINE_CODE(pc) (gdbarch_skip_trampoline_code (current_gdbarch, pc))
+#endif
+
+/* If IN_SOLIB_DYNSYM_RESOLVE_CODE returns true, and SKIP_SOLIB_RESOLVER
+ evaluates non-zero, this is the address where the debugger will place
+ a step-resume breakpoint to get us past the dynamic linker. */
+
+typedef CORE_ADDR (gdbarch_skip_solib_resolver_ftype) (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern CORE_ADDR gdbarch_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern void set_gdbarch_skip_solib_resolver (struct gdbarch *gdbarch, gdbarch_skip_solib_resolver_ftype *skip_solib_resolver);
+
+/* 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 currently stopped in one of these. */
+
+typedef int (gdbarch_in_solib_call_trampoline_ftype) (CORE_ADDR pc, char *name);
+extern int gdbarch_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc, char *name);
+extern void set_gdbarch_in_solib_call_trampoline (struct gdbarch *gdbarch, gdbarch_in_solib_call_trampoline_ftype *in_solib_call_trampoline);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (IN_SOLIB_CALL_TRAMPOLINE)
+#error "Non multi-arch definition of IN_SOLIB_CALL_TRAMPOLINE"
+#endif
+#if !defined (IN_SOLIB_CALL_TRAMPOLINE)
+#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) (gdbarch_in_solib_call_trampoline (current_gdbarch, pc, name))
+#endif
+
+/* Some systems also have trampoline code for returning from shared libs. */
+
+typedef int (gdbarch_in_solib_return_trampoline_ftype) (CORE_ADDR pc, char *name);
+extern int gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc, char *name);
+extern void set_gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch, gdbarch_in_solib_return_trampoline_ftype *in_solib_return_trampoline);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (IN_SOLIB_RETURN_TRAMPOLINE)
+#error "Non multi-arch definition of IN_SOLIB_RETURN_TRAMPOLINE"
+#endif
+#if !defined (IN_SOLIB_RETURN_TRAMPOLINE)
+#define IN_SOLIB_RETURN_TRAMPOLINE(pc, name) (gdbarch_in_solib_return_trampoline (current_gdbarch, pc, name))
+#endif
+
+/* 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).
+
+ FIXME: cagney/2002-04-21: The function find_pc_partial_function
+ calls find_pc_sect_partial_function() which calls PC_IN_SIGTRAMP.
+ This means PC_IN_SIGTRAMP function can't be implemented by doing its
+ own local NAME lookup.
+
+ FIXME: cagney/2002-04-21: PC_IN_SIGTRAMP is something of a mess.
+ Some code also depends on SIGTRAMP_START and SIGTRAMP_END but other
+ does not. */
+
+typedef int (gdbarch_pc_in_sigtramp_ftype) (CORE_ADDR pc, char *name);
+extern int gdbarch_pc_in_sigtramp (struct gdbarch *gdbarch, CORE_ADDR pc, char *name);
+extern void set_gdbarch_pc_in_sigtramp (struct gdbarch *gdbarch, gdbarch_pc_in_sigtramp_ftype *pc_in_sigtramp);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (PC_IN_SIGTRAMP)
+#error "Non multi-arch definition of PC_IN_SIGTRAMP"
+#endif
+#if !defined (PC_IN_SIGTRAMP)
+#define PC_IN_SIGTRAMP(pc, name) (gdbarch_pc_in_sigtramp (current_gdbarch, pc, name))
+#endif
+
+#if defined (SIGTRAMP_START)
+/* Legacy for systems yet to multi-arch SIGTRAMP_START */
+#if !defined (SIGTRAMP_START_P)
+#define SIGTRAMP_START_P() (1)
+#endif
+#endif
+
+extern int gdbarch_sigtramp_start_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SIGTRAMP_START_P)
+#error "Non multi-arch definition of SIGTRAMP_START"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (SIGTRAMP_START_P)
+#define SIGTRAMP_START_P() (gdbarch_sigtramp_start_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_sigtramp_start_ftype) (CORE_ADDR pc);
+extern CORE_ADDR gdbarch_sigtramp_start (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern void set_gdbarch_sigtramp_start (struct gdbarch *gdbarch, gdbarch_sigtramp_start_ftype *sigtramp_start);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SIGTRAMP_START)
+#error "Non multi-arch definition of SIGTRAMP_START"
+#endif
+#if !defined (SIGTRAMP_START)
+#define SIGTRAMP_START(pc) (gdbarch_sigtramp_start (current_gdbarch, pc))
+#endif
+
+#if defined (SIGTRAMP_END)
+/* Legacy for systems yet to multi-arch SIGTRAMP_END */
+#if !defined (SIGTRAMP_END_P)
+#define SIGTRAMP_END_P() (1)
+#endif
+#endif
+
+extern int gdbarch_sigtramp_end_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SIGTRAMP_END_P)
+#error "Non multi-arch definition of SIGTRAMP_END"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (SIGTRAMP_END_P)
+#define SIGTRAMP_END_P() (gdbarch_sigtramp_end_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_sigtramp_end_ftype) (CORE_ADDR pc);
+extern CORE_ADDR gdbarch_sigtramp_end (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern void set_gdbarch_sigtramp_end (struct gdbarch *gdbarch, gdbarch_sigtramp_end_ftype *sigtramp_end);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (SIGTRAMP_END)
+#error "Non multi-arch definition of SIGTRAMP_END"
+#endif
+#if !defined (SIGTRAMP_END)
+#define SIGTRAMP_END(pc) (gdbarch_sigtramp_end (current_gdbarch, pc))
+#endif
+
+/* A target might have problems with watchpoints as soon as the stack
+ frame of the current function has been destroyed. This mostly happens
+ as the first action in a funtion's epilogue. in_function_epilogue_p()
+ is defined to return a non-zero value if either the given addr is one
+ instruction after the stack destroying instruction up to the trailing
+ return instruction or if we can figure out that the stack frame has
+ already been invalidated regardless of the value of addr. Targets
+ which don't suffer from that problem could just let this functionality
+ untouched. */
+
+typedef int (gdbarch_in_function_epilogue_p_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern int gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p);
+
+/* Given a vector of command-line arguments, return a newly allocated
+ string which, when passed to the create_inferior function, will be
+ parsed (on Unix systems, by the shell) to yield the same vector.
+ This function should call error() if the argument vector is not
+ representable for this target or if this target does not support
+ command-line arguments.
+ ARGC is the number of elements in the vector.
+ ARGV is an array of strings, one per argument. */
+
+typedef char * (gdbarch_construct_inferior_arguments_ftype) (struct gdbarch *gdbarch, int argc, char **argv);
+extern char * gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv);
+extern void set_gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, gdbarch_construct_inferior_arguments_ftype *construct_inferior_arguments);
+
+typedef void (gdbarch_elf_make_msymbol_special_ftype) (asymbol *sym, struct minimal_symbol *msym);
+extern void gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, asymbol *sym, struct minimal_symbol *msym);
+extern void set_gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, gdbarch_elf_make_msymbol_special_ftype *elf_make_msymbol_special);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (ELF_MAKE_MSYMBOL_SPECIAL)
+#error "Non multi-arch definition of ELF_MAKE_MSYMBOL_SPECIAL"
+#endif
+#if !defined (ELF_MAKE_MSYMBOL_SPECIAL)
+#define ELF_MAKE_MSYMBOL_SPECIAL(sym, msym) (gdbarch_elf_make_msymbol_special (current_gdbarch, sym, msym))
+#endif
+
+typedef void (gdbarch_coff_make_msymbol_special_ftype) (int val, struct minimal_symbol *msym);
+extern void gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, int val, struct minimal_symbol *msym);
+extern void set_gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, gdbarch_coff_make_msymbol_special_ftype *coff_make_msymbol_special);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (COFF_MAKE_MSYMBOL_SPECIAL)
+#error "Non multi-arch definition of COFF_MAKE_MSYMBOL_SPECIAL"
+#endif
+#if !defined (COFF_MAKE_MSYMBOL_SPECIAL)
+#define COFF_MAKE_MSYMBOL_SPECIAL(val, msym) (gdbarch_coff_make_msymbol_special (current_gdbarch, val, msym))
+#endif
+
+extern const char * gdbarch_name_of_malloc (struct gdbarch *gdbarch);
+extern void set_gdbarch_name_of_malloc (struct gdbarch *gdbarch, const char * name_of_malloc);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (NAME_OF_MALLOC)
+#error "Non multi-arch definition of NAME_OF_MALLOC"
+#endif
+#if !defined (NAME_OF_MALLOC)
+#define NAME_OF_MALLOC (gdbarch_name_of_malloc (current_gdbarch))
+#endif
+
+extern int gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch);
+extern void set_gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch, int cannot_step_breakpoint);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (CANNOT_STEP_BREAKPOINT)
+#error "Non multi-arch definition of CANNOT_STEP_BREAKPOINT"
+#endif
+#if !defined (CANNOT_STEP_BREAKPOINT)
+#define CANNOT_STEP_BREAKPOINT (gdbarch_cannot_step_breakpoint (current_gdbarch))
+#endif
+
+extern int gdbarch_have_nonsteppable_watchpoint (struct gdbarch *gdbarch);
+extern void set_gdbarch_have_nonsteppable_watchpoint (struct gdbarch *gdbarch, int have_nonsteppable_watchpoint);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (HAVE_NONSTEPPABLE_WATCHPOINT)
+#error "Non multi-arch definition of HAVE_NONSTEPPABLE_WATCHPOINT"
+#endif
+#if !defined (HAVE_NONSTEPPABLE_WATCHPOINT)
+#define HAVE_NONSTEPPABLE_WATCHPOINT (gdbarch_have_nonsteppable_watchpoint (current_gdbarch))
+#endif
+
+#if defined (ADDRESS_CLASS_TYPE_FLAGS)
+/* Legacy for systems yet to multi-arch ADDRESS_CLASS_TYPE_FLAGS */
+#if !defined (ADDRESS_CLASS_TYPE_FLAGS_P)
+#define ADDRESS_CLASS_TYPE_FLAGS_P() (1)
+#endif
+#endif
+
+extern int gdbarch_address_class_type_flags_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (ADDRESS_CLASS_TYPE_FLAGS_P)
+#error "Non multi-arch definition of ADDRESS_CLASS_TYPE_FLAGS"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (ADDRESS_CLASS_TYPE_FLAGS_P)
+#define ADDRESS_CLASS_TYPE_FLAGS_P() (gdbarch_address_class_type_flags_p (current_gdbarch))
+#endif
+
+typedef int (gdbarch_address_class_type_flags_ftype) (int byte_size, int dwarf2_addr_class);
+extern int gdbarch_address_class_type_flags (struct gdbarch *gdbarch, int byte_size, int dwarf2_addr_class);
+extern void set_gdbarch_address_class_type_flags (struct gdbarch *gdbarch, gdbarch_address_class_type_flags_ftype *address_class_type_flags);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (ADDRESS_CLASS_TYPE_FLAGS)
+#error "Non multi-arch definition of ADDRESS_CLASS_TYPE_FLAGS"
+#endif
+#if !defined (ADDRESS_CLASS_TYPE_FLAGS)
+#define ADDRESS_CLASS_TYPE_FLAGS(byte_size, dwarf2_addr_class) (gdbarch_address_class_type_flags (current_gdbarch, byte_size, dwarf2_addr_class))
+#endif
+
+extern int gdbarch_address_class_type_flags_to_name_p (struct gdbarch *gdbarch);
+
+typedef const char * (gdbarch_address_class_type_flags_to_name_ftype) (struct gdbarch *gdbarch, int type_flags);
+extern const char * gdbarch_address_class_type_flags_to_name (struct gdbarch *gdbarch, int type_flags);
+extern void set_gdbarch_address_class_type_flags_to_name (struct gdbarch *gdbarch, gdbarch_address_class_type_flags_to_name_ftype *address_class_type_flags_to_name);
+
+extern int gdbarch_address_class_name_to_type_flags_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_address_class_name_to_type_flags_ftype) (struct gdbarch *gdbarch, const char *name, int *type_flags_ptr);
+extern int gdbarch_address_class_name_to_type_flags (struct gdbarch *gdbarch, const char *name, int *type_flags_ptr);
+extern void set_gdbarch_address_class_name_to_type_flags (struct gdbarch *gdbarch, gdbarch_address_class_name_to_type_flags_ftype *address_class_name_to_type_flags);
+
+/* Is a register in a group */
+
+typedef int (gdbarch_register_reggroup_p_ftype) (struct gdbarch *gdbarch, int regnum, struct reggroup *reggroup);
+extern int gdbarch_register_reggroup_p (struct gdbarch *gdbarch, int regnum, struct reggroup *reggroup);
+extern void set_gdbarch_register_reggroup_p (struct gdbarch *gdbarch, gdbarch_register_reggroup_p_ftype *register_reggroup_p);
+
+/* Fetch the pointer to the ith function argument. */
+
+#if defined (FETCH_POINTER_ARGUMENT)
+/* Legacy for systems yet to multi-arch FETCH_POINTER_ARGUMENT */
+#if !defined (FETCH_POINTER_ARGUMENT_P)
+#define FETCH_POINTER_ARGUMENT_P() (1)
+#endif
+#endif
+
+extern int gdbarch_fetch_pointer_argument_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FETCH_POINTER_ARGUMENT_P)
+#error "Non multi-arch definition of FETCH_POINTER_ARGUMENT"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (FETCH_POINTER_ARGUMENT_P)
+#define FETCH_POINTER_ARGUMENT_P() (gdbarch_fetch_pointer_argument_p (current_gdbarch))
+#endif
+
+typedef CORE_ADDR (gdbarch_fetch_pointer_argument_ftype) (struct frame_info *frame, int argi, struct type *type);
+extern CORE_ADDR gdbarch_fetch_pointer_argument (struct gdbarch *gdbarch, struct frame_info *frame, int argi, struct type *type);
+extern void set_gdbarch_fetch_pointer_argument (struct gdbarch *gdbarch, gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (FETCH_POINTER_ARGUMENT)
+#error "Non multi-arch definition of FETCH_POINTER_ARGUMENT"
+#endif
+#if !defined (FETCH_POINTER_ARGUMENT)
+#define FETCH_POINTER_ARGUMENT(frame, argi, type) (gdbarch_fetch_pointer_argument (current_gdbarch, frame, argi, type))
+#endif
+
+/* Return the appropriate register set for a core file section with
+ name SECT_NAME and size SECT_SIZE. */
+
+extern int gdbarch_regset_from_core_section_p (struct gdbarch *gdbarch);
+
+typedef const struct regset * (gdbarch_regset_from_core_section_ftype) (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size);
+extern const struct regset * gdbarch_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size);
+extern void set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, gdbarch_regset_from_core_section_ftype *regset_from_core_section);
+
+extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
+
+
+/* Mechanism for co-ordinating the selection of a specific
+ architecture.
+
+ GDB targets (*-tdep.c) can register an interest in a specific
+ architecture. Other GDB components can register a need to maintain
+ per-architecture data.
+
+ The mechanisms below ensures that there is only a loose connection
+ between the set-architecture command and the various GDB
+ components. Each component can independently register their need
+ to maintain architecture specific data with gdbarch.
+
+ Pragmatics:
+
+ Previously, a single TARGET_ARCHITECTURE_HOOK was provided. It
+ didn't scale.
+
+ The more traditional mega-struct containing architecture specific
+ data for all the various GDB components was also considered. Since
+ GDB is built from a variable number of (fairly independent)
+ components it was determined that the global aproach was not
+ applicable. */
+
+
+/* Register a new architectural family with GDB.
+
+ Register support for the specified ARCHITECTURE with GDB. When
+ gdbarch determines that the specified architecture has been
+ selected, the corresponding INIT function is called.
+
+ --
+
+ The INIT function takes two parameters: INFO which contains the
+ information available to gdbarch about the (possibly new)
+ architecture; ARCHES which is a list of the previously created
+ ``struct gdbarch'' for this architecture.
+
+ The INFO parameter is, as far as possible, be pre-initialized with
+ information obtained from INFO.ABFD or the previously selected
+ architecture.
+
+ The ARCHES parameter is a linked list (sorted most recently used)
+ of all the previously created architures for this architecture
+ family. The (possibly NULL) ARCHES->gdbarch can used to access
+ values from the previously selected architecture for this
+ architecture family. The global ``current_gdbarch'' shall not be
+ used.
+
+ The INIT function shall return any of: NULL - indicating that it
+ doesn't recognize the selected architecture; an existing ``struct
+ gdbarch'' from the ARCHES list - indicating that the new
+ architecture is just a synonym for an earlier architecture (see
+ gdbarch_list_lookup_by_info()); a newly created ``struct gdbarch''
+ - that describes the selected architecture (see gdbarch_alloc()).
+
+ The DUMP_TDEP function shall print out all target specific values.
+ Care should be taken to ensure that the function works in both the
+ multi-arch and non- multi-arch cases. */
+
+struct gdbarch_list
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_list *next;
+};
+
+struct gdbarch_info
+{
+ /* Use default: NULL (ZERO). */
+ const struct bfd_arch_info *bfd_arch_info;
+
+ /* Use default: BFD_ENDIAN_UNKNOWN (NB: is not ZERO). */
+ int byte_order;
+
+ /* Use default: NULL (ZERO). */
+ bfd *abfd;
+
+ /* Use default: NULL (ZERO). */
+ struct gdbarch_tdep_info *tdep_info;
+
+ /* Use default: GDB_OSABI_UNINITIALIZED (-1). */
+ enum gdb_osabi osabi;
+};
+
+typedef struct gdbarch *(gdbarch_init_ftype) (struct gdbarch_info info, struct gdbarch_list *arches);
+typedef void (gdbarch_dump_tdep_ftype) (struct gdbarch *gdbarch, struct ui_file *file);
+
+/* DEPRECATED - use gdbarch_register() */
+extern void register_gdbarch_init (enum bfd_architecture architecture, gdbarch_init_ftype *);
+
+extern void gdbarch_register (enum bfd_architecture architecture,
+ gdbarch_init_ftype *,
+ gdbarch_dump_tdep_ftype *);
+
+
+/* Return a freshly allocated, NULL terminated, array of the valid
+ architecture names. Since architectures are registered during the
+ _initialize phase this function only returns useful information
+ once initialization has been completed. */
+
+extern const char **gdbarch_printable_names (void);
+
+
+/* Helper function. Search the list of ARCHES for a GDBARCH that
+ matches the information provided by INFO. */
+
+extern struct gdbarch_list *gdbarch_list_lookup_by_info (struct gdbarch_list *arches, const struct gdbarch_info *info);
+
+
+/* Helper function. Create a preliminary ``struct gdbarch''. Perform
+ basic initialization using values obtained from the INFO andTDEP
+ parameters. set_gdbarch_*() functions are called to complete the
+ initialization of the object. */
+
+extern struct gdbarch *gdbarch_alloc (const struct gdbarch_info *info, struct gdbarch_tdep *tdep);
+
+
+/* Helper function. Free a partially-constructed ``struct gdbarch''.
+ It is assumed that the caller freeds the ``struct
+ gdbarch_tdep''. */
+
+extern void gdbarch_free (struct gdbarch *);
+
+
+/* Helper function. Allocate memory from the ``struct gdbarch''
+ obstack. The memory is freed when the corresponding architecture
+ is also freed. */
+
+extern void *gdbarch_obstack_zalloc (struct gdbarch *gdbarch, long size);
+#define GDBARCH_OBSTACK_CALLOC(GDBARCH, NR, TYPE) ((TYPE *) gdbarch_obstack_zalloc ((GDBARCH), (NR) * sizeof (TYPE)))
+#define GDBARCH_OBSTACK_ZALLOC(GDBARCH, TYPE) ((TYPE *) gdbarch_obstack_zalloc ((GDBARCH), sizeof (TYPE)))
+
+
+/* Helper function. Force an update of the current architecture.
+
+ The actual architecture selected is determined by INFO, ``(gdb) set
+ architecture'' et.al., the existing architecture and BFD's default
+ architecture. INFO should be initialized to zero and then selected
+ fields should be updated.
+
+ Returns non-zero if the update succeeds */
+
+extern int gdbarch_update_p (struct gdbarch_info info);
+
+
+/* Helper function. Find an architecture matching info.
+
+ INFO should be initialized using gdbarch_info_init, relevant fields
+ set, and then finished using gdbarch_info_fill.
+
+ Returns the corresponding architecture, or NULL if no matching
+ architecture was found. "current_gdbarch" is not updated. */
+
+extern struct gdbarch *gdbarch_find_by_info (struct gdbarch_info info);
+
+
+/* Helper function. Set the global "current_gdbarch" to "gdbarch".
+
+ FIXME: kettenis/20031124: Of the functions that follow, only
+ gdbarch_from_bfd is supposed to survive. The others will
+ dissappear since in the future GDB will (hopefully) be truly
+ multi-arch. However, for now we're still stuck with the concept of
+ a single active architecture. */
+
+extern void deprecated_current_gdbarch_select_hack (struct gdbarch *gdbarch);
+
+
+/* Register per-architecture data-pointer.
+
+ Reserve space for a per-architecture data-pointer. An identifier
+ for the reserved data-pointer is returned. That identifer should
+ be saved in a local static variable.
+
+ The per-architecture data-pointer is either initialized explicitly
+ (set_gdbarch_data()) or implicitly (by INIT() via a call to
+ gdbarch_data()).
+
+ Memory for the per-architecture data shall be allocated using
+ gdbarch_obstack_zalloc. That memory will be deleted when the
+ corresponding architecture object is deleted.
+
+ When a previously created architecture is re-selected, the
+ per-architecture data-pointer for that previous architecture is
+ restored. INIT() is not re-called.
+
+ Multiple registrarants for any architecture are allowed (and
+ strongly encouraged). */
+
+struct gdbarch_data;
+
+typedef void *(gdbarch_data_init_ftype) (struct gdbarch *gdbarch);
+extern struct gdbarch_data *register_gdbarch_data (gdbarch_data_init_ftype *init);
+extern void set_gdbarch_data (struct gdbarch *gdbarch,
+ struct gdbarch_data *data,
+ void *pointer);
+
+extern void *gdbarch_data (struct gdbarch *gdbarch, struct gdbarch_data *);
+
+
+
+/* Register per-architecture memory region.
+
+ Provide a memory-region swap mechanism. Per-architecture memory
+ region are created. These memory regions are swapped whenever the
+ architecture is changed. For a new architecture, the memory region
+ is initialized with zero (0) and the INIT function is called.
+
+ Memory regions are swapped / initialized in the order that they are
+ registered. NULL DATA and/or INIT values can be specified.
+
+ New code should use register_gdbarch_data(). */
+
+typedef void (gdbarch_swap_ftype) (void);
+extern void deprecated_register_gdbarch_swap (void *data, unsigned long size, gdbarch_swap_ftype *init);
+#define DEPRECATED_REGISTER_GDBARCH_SWAP(VAR) deprecated_register_gdbarch_swap (&(VAR), sizeof ((VAR)), NULL)
+
+
+
+/* Set the dynamic target-system-dependent parameters (architecture,
+ byte-order, ...) using information found in the BFD */
+
+extern void set_gdbarch_from_file (bfd *);
+
+
+/* Initialize the current architecture to the "first" one we find on
+ our list. */
+
+extern void initialize_current_architecture (void);
+
+/* gdbarch trace variable */
+extern int gdbarch_debug;
+
+extern void gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file);
+
+#endif
diff --git a/contrib/gdb/gdb/gdbarch.sh b/contrib/gdb/gdb/gdbarch.sh
new file mode 100755
index 0000000..df3b102
--- /dev/null
+++ b/contrib/gdb/gdb/gdbarch.sh
@@ -0,0 +1,2320 @@
+#!/bin/sh -u
+
+# Architecture commands for GDB, the GNU debugger.
+#
+# Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+# Foundation, Inc.
+#
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Make certain that the script is running in an internationalized
+# environment.
+LANG=c ; export LANG
+LC_ALL=c ; export LC_ALL
+
+
+compare_new ()
+{
+ file=$1
+ if test ! -r ${file}
+ then
+ echo "${file} missing? cp new-${file} ${file}" 1>&2
+ elif diff -u ${file} new-${file}
+ then
+ echo "${file} unchanged" 1>&2
+ else
+ echo "${file} has changed? cp new-${file} ${file}" 1>&2
+ fi
+}
+
+
+# Format of the input table
+read="class level macro returntype function formal actual attrib staticdefault predefault postdefault invalid_p fmt print print_p description"
+
+do_read ()
+{
+ comment=""
+ class=""
+ while read line
+ do
+ if test "${line}" = ""
+ then
+ continue
+ elif test "${line}" = "#" -a "${comment}" = ""
+ then
+ continue
+ elif expr "${line}" : "#" > /dev/null
+ then
+ comment="${comment}
+${line}"
+ else
+
+ # The semantics of IFS varies between different SH's. Some
+ # treat ``::' as three fields while some treat it as just too.
+ # Work around this by eliminating ``::'' ....
+ line="`echo "${line}" | sed -e 's/::/: :/g' -e 's/::/: :/g'`"
+
+ OFS="${IFS}" ; IFS="[:]"
+ eval read ${read} <<EOF
+${line}
+EOF
+ IFS="${OFS}"
+
+ # .... and then going back through each field and strip out those
+ # that ended up with just that space character.
+ for r in ${read}
+ do
+ if eval test \"\${${r}}\" = \"\ \"
+ then
+ eval ${r}=""
+ fi
+ done
+
+ case "${level}" in
+ 1 ) gt_level=">= GDB_MULTI_ARCH_PARTIAL" ;;
+ 2 ) gt_level="> GDB_MULTI_ARCH_PARTIAL" ;;
+ "" ) gt_level="> GDB_MULTI_ARCH_PARTIAL" ;;
+ * ) error "Error: bad level for ${function}" 1>&2 ; kill $$ ; exit 1 ;;
+ esac
+
+ case "${class}" in
+ m ) staticdefault="${predefault}" ;;
+ M ) staticdefault="0" ;;
+ * ) test "${staticdefault}" || staticdefault=0 ;;
+ esac
+
+ # come up with a format, use a few guesses for variables
+ case ":${class}:${fmt}:${print}:" in
+ :[vV]::: )
+ if [ "${returntype}" = int ]
+ then
+ fmt="%d"
+ print="${macro}"
+ elif [ "${returntype}" = long ]
+ then
+ fmt="%ld"
+ print="${macro}"
+ fi
+ ;;
+ esac
+ test "${fmt}" || fmt="%ld"
+ test "${print}" || print="(long) ${macro}"
+
+ case "${class}" in
+ F | V | M )
+ case "${invalid_p}" in
+ "" )
+ if test -n "${predefault}"
+ then
+ #invalid_p="gdbarch->${function} == ${predefault}"
+ predicate="gdbarch->${function} != ${predefault}"
+ elif class_is_variable_p
+ then
+ predicate="gdbarch->${function} != 0"
+ elif class_is_function_p
+ then
+ predicate="gdbarch->${function} != NULL"
+ fi
+ ;;
+ * )
+ echo "Predicate function ${function} with invalid_p." 1>&2
+ kill $$
+ exit 1
+ ;;
+ esac
+ esac
+
+ # PREDEFAULT is a valid fallback definition of MEMBER when
+ # multi-arch is not enabled. This ensures that the
+ # default value, when multi-arch is the same as the
+ # default value when not multi-arch. POSTDEFAULT is
+ # always a valid definition of MEMBER as this again
+ # ensures consistency.
+
+ if [ -n "${postdefault}" ]
+ then
+ fallbackdefault="${postdefault}"
+ elif [ -n "${predefault}" ]
+ then
+ fallbackdefault="${predefault}"
+ else
+ fallbackdefault="0"
+ fi
+
+ #NOT YET: See gdbarch.log for basic verification of
+ # database
+
+ break
+ fi
+ done
+ if [ -n "${class}" ]
+ then
+ true
+ else
+ false
+ fi
+}
+
+
+fallback_default_p ()
+{
+ [ -n "${postdefault}" -a "x${invalid_p}" != "x0" ] \
+ || [ -n "${predefault}" -a "x${invalid_p}" = "x0" ]
+}
+
+class_is_variable_p ()
+{
+ case "${class}" in
+ *v* | *V* ) true ;;
+ * ) false ;;
+ esac
+}
+
+class_is_function_p ()
+{
+ case "${class}" in
+ *f* | *F* | *m* | *M* ) true ;;
+ * ) false ;;
+ esac
+}
+
+class_is_multiarch_p ()
+{
+ case "${class}" in
+ *m* | *M* ) true ;;
+ * ) false ;;
+ esac
+}
+
+class_is_predicate_p ()
+{
+ case "${class}" in
+ *F* | *V* | *M* ) true ;;
+ * ) false ;;
+ esac
+}
+
+class_is_info_p ()
+{
+ case "${class}" in
+ *i* ) true ;;
+ * ) false ;;
+ esac
+}
+
+
+# dump out/verify the doco
+for field in ${read}
+do
+ case ${field} in
+
+ class ) : ;;
+
+ # # -> line disable
+ # f -> function
+ # hiding a function
+ # F -> function + predicate
+ # hiding a function + predicate to test function validity
+ # v -> variable
+ # hiding a variable
+ # V -> variable + predicate
+ # hiding a variable + predicate to test variables validity
+ # i -> set from info
+ # hiding something from the ``struct info'' object
+ # m -> multi-arch function
+ # hiding a multi-arch function (parameterised with the architecture)
+ # M -> multi-arch function + predicate
+ # hiding a multi-arch function + predicate to test function validity
+
+ level ) : ;;
+
+ # See GDB_MULTI_ARCH description. Having GDB_MULTI_ARCH >=
+ # LEVEL is a predicate on checking that a given method is
+ # initialized (using INVALID_P).
+
+ macro ) : ;;
+
+ # The name of the MACRO that this method is to be accessed by.
+
+ returntype ) : ;;
+
+ # For functions, the return type; for variables, the data type
+
+ function ) : ;;
+
+ # For functions, the member function name; for variables, the
+ # variable name. Member function names are always prefixed with
+ # ``gdbarch_'' for name-space purity.
+
+ formal ) : ;;
+
+ # The formal argument list. It is assumed that the formal
+ # argument list includes the actual name of each list element.
+ # A function with no arguments shall have ``void'' as the
+ # formal argument list.
+
+ actual ) : ;;
+
+ # The list of actual arguments. The arguments specified shall
+ # match the FORMAL list given above. Functions with out
+ # arguments leave this blank.
+
+ attrib ) : ;;
+
+ # Any GCC attributes that should be attached to the function
+ # declaration. At present this field is unused.
+
+ staticdefault ) : ;;
+
+ # To help with the GDB startup a static gdbarch object is
+ # created. STATICDEFAULT is the value to insert into that
+ # static gdbarch object. Since this a static object only
+ # simple expressions can be used.
+
+ # If STATICDEFAULT is empty, zero is used.
+
+ predefault ) : ;;
+
+ # An initial value to assign to MEMBER of the freshly
+ # malloc()ed gdbarch object. After initialization, the
+ # freshly malloc()ed object is passed to the target
+ # architecture code for further updates.
+
+ # If PREDEFAULT is empty, zero is used.
+
+ # A non-empty PREDEFAULT, an empty POSTDEFAULT and a zero
+ # INVALID_P are specified, PREDEFAULT will be used as the
+ # default for the non- multi-arch target.
+
+ # A zero PREDEFAULT function will force the fallback to call
+ # internal_error().
+
+ # Variable declarations can refer to ``gdbarch'' which will
+ # contain the current architecture. Care should be taken.
+
+ postdefault ) : ;;
+
+ # A value to assign to MEMBER of the new gdbarch object should
+ # the target architecture code fail to change the PREDEFAULT
+ # value.
+
+ # If POSTDEFAULT is empty, no post update is performed.
+
+ # If both INVALID_P and POSTDEFAULT are non-empty then
+ # INVALID_P will be used to determine if MEMBER should be
+ # changed to POSTDEFAULT.
+
+ # If a non-empty POSTDEFAULT and a zero INVALID_P are
+ # specified, POSTDEFAULT will be used as the default for the
+ # non- multi-arch target (regardless of the value of
+ # PREDEFAULT).
+
+ # You cannot specify both a zero INVALID_P and a POSTDEFAULT.
+
+ # Variable declarations can refer to ``current_gdbarch'' which
+ # will contain the current architecture. Care should be
+ # taken.
+
+ invalid_p ) : ;;
+
+ # A predicate equation that validates MEMBER. Non-zero is
+ # returned if the code creating the new architecture failed to
+ # initialize MEMBER or the initialized the member is invalid.
+ # If POSTDEFAULT is non-empty then MEMBER will be updated to
+ # that value. If POSTDEFAULT is empty then internal_error()
+ # is called.
+
+ # If INVALID_P is empty, a check that MEMBER is no longer
+ # equal to PREDEFAULT is used.
+
+ # The expression ``0'' disables the INVALID_P check making
+ # PREDEFAULT a legitimate value.
+
+ # See also PREDEFAULT and POSTDEFAULT.
+
+ fmt ) : ;;
+
+ # printf style format string that can be used to print out the
+ # MEMBER. Sometimes "%s" is useful. For functions, this is
+ # ignored and the function address is printed.
+
+ # If FMT is empty, ``%ld'' is used.
+
+ print ) : ;;
+
+ # An optional equation that casts MEMBER to a value suitable
+ # for formatting by FMT.
+
+ # If PRINT is empty, ``(long)'' is used.
+
+ print_p ) : ;;
+
+ # An optional indicator for any predicte to wrap around the
+ # print member code.
+
+ # () -> Call a custom function to do the dump.
+ # exp -> Wrap print up in ``if (${print_p}) ...
+ # ``'' -> No predicate
+
+ # If PRINT_P is empty, ``1'' is always used.
+
+ description ) : ;;
+
+ # Currently unused.
+
+ *)
+ echo "Bad field ${field}"
+ exit 1;;
+ esac
+done
+
+
+function_list ()
+{
+ # See below (DOCO) for description of each field
+ cat <<EOF
+i:2:TARGET_ARCHITECTURE:const struct bfd_arch_info *:bfd_arch_info::::&bfd_default_arch_struct::::%s:TARGET_ARCHITECTURE->printable_name:TARGET_ARCHITECTURE != NULL
+#
+i:2:TARGET_BYTE_ORDER:int:byte_order::::BFD_ENDIAN_BIG
+#
+i:2:TARGET_OSABI:enum gdb_osabi:osabi::::GDB_OSABI_UNKNOWN
+# Number of bits in a char or unsigned char for the target machine.
+# Just like CHAR_BIT in <limits.h> but describes the target machine.
+# v:2:TARGET_CHAR_BIT:int:char_bit::::8 * sizeof (char):8::0:
+#
+# Number of bits in a short or unsigned short for the target machine.
+v:2:TARGET_SHORT_BIT:int:short_bit::::8 * sizeof (short):2*TARGET_CHAR_BIT::0
+# Number of bits in an int or unsigned int for the target machine.
+v:2:TARGET_INT_BIT:int:int_bit::::8 * sizeof (int):4*TARGET_CHAR_BIT::0
+# Number of bits in a long or unsigned long for the target machine.
+v:2:TARGET_LONG_BIT:int:long_bit::::8 * sizeof (long):4*TARGET_CHAR_BIT::0
+# Number of bits in a long long or unsigned long long for the target
+# machine.
+v:2:TARGET_LONG_LONG_BIT:int:long_long_bit::::8 * sizeof (LONGEST):2*TARGET_LONG_BIT::0
+# Number of bits in a float for the target machine.
+v:2:TARGET_FLOAT_BIT:int:float_bit::::8 * sizeof (float):4*TARGET_CHAR_BIT::0
+# Number of bits in a double for the target machine.
+v:2:TARGET_DOUBLE_BIT:int:double_bit::::8 * sizeof (double):8*TARGET_CHAR_BIT::0
+# Number of bits in a long double for the target machine.
+v:2:TARGET_LONG_DOUBLE_BIT:int:long_double_bit::::8 * sizeof (long double):8*TARGET_CHAR_BIT::0
+# For most targets, a pointer on the target and its representation as an
+# address in GDB have the same size and "look the same". For such a
+# target, you need only set TARGET_PTR_BIT / ptr_bit and TARGET_ADDR_BIT
+# / addr_bit will be set from it.
+#
+# If TARGET_PTR_BIT and TARGET_ADDR_BIT are different, you'll probably
+# also need to set POINTER_TO_ADDRESS and ADDRESS_TO_POINTER as well.
+#
+# ptr_bit is the size of a pointer on the target
+v:2:TARGET_PTR_BIT:int:ptr_bit::::8 * sizeof (void*):TARGET_INT_BIT::0
+# addr_bit is the size of a target address as represented in gdb
+v:2:TARGET_ADDR_BIT:int:addr_bit::::8 * sizeof (void*):0:TARGET_PTR_BIT:
+# Number of bits in a BFD_VMA for the target object file format.
+v:2:TARGET_BFD_VMA_BIT:int:bfd_vma_bit::::8 * sizeof (void*):TARGET_ARCHITECTURE->bits_per_address::0
+#
+# One if \`char' acts like \`signed char', zero if \`unsigned char'.
+v:2:TARGET_CHAR_SIGNED:int:char_signed::::1:-1:1::::
+#
+F:2:TARGET_READ_PC:CORE_ADDR:read_pc:ptid_t ptid:ptid
+f:2:TARGET_WRITE_PC:void:write_pc:CORE_ADDR val, ptid_t ptid:val, ptid::0:generic_target_write_pc::0
+# UNWIND_SP is a direct replacement for TARGET_READ_SP.
+F:2:TARGET_READ_SP:CORE_ADDR:read_sp:void
+# Function for getting target's idea of a frame pointer. FIXME: GDB's
+# whole scheme for dealing with "frames" and "frame pointers" needs a
+# serious shakedown.
+f:2:TARGET_VIRTUAL_FRAME_POINTER:void:virtual_frame_pointer:CORE_ADDR pc, int *frame_regnum, LONGEST *frame_offset:pc, frame_regnum, frame_offset::0:legacy_virtual_frame_pointer::0
+#
+M:::void:pseudo_register_read:struct regcache *regcache, int cookednum, void *buf:regcache, cookednum, buf
+M:::void:pseudo_register_write:struct regcache *regcache, int cookednum, const void *buf:regcache, cookednum, buf
+#
+v:2:NUM_REGS:int:num_regs::::0:-1
+# This macro gives the number of pseudo-registers that live in the
+# register namespace but do not get fetched or stored on the target.
+# These pseudo-registers may be aliases for other registers,
+# combinations of other registers, or they may be computed by GDB.
+v:2:NUM_PSEUDO_REGS:int:num_pseudo_regs::::0:0::0:::
+
+# GDB's standard (or well known) register numbers. These can map onto
+# a real register or a pseudo (computed) register or not be defined at
+# all (-1).
+# SP_REGNUM will hopefully be replaced by UNWIND_SP.
+v:2:SP_REGNUM:int:sp_regnum::::-1:-1::0
+v:2:PC_REGNUM:int:pc_regnum::::-1:-1::0
+v:2:PS_REGNUM:int:ps_regnum::::-1:-1::0
+v:2:FP0_REGNUM:int:fp0_regnum::::0:-1::0
+# Convert stab register number (from \`r\' declaration) to a gdb REGNUM.
+f:2:STAB_REG_TO_REGNUM:int:stab_reg_to_regnum:int stab_regnr:stab_regnr:::no_op_reg_to_regnum::0
+# Provide a default mapping from a ecoff register number to a gdb REGNUM.
+f:2:ECOFF_REG_TO_REGNUM:int:ecoff_reg_to_regnum:int ecoff_regnr:ecoff_regnr:::no_op_reg_to_regnum::0
+# Provide a default mapping from a DWARF register number to a gdb REGNUM.
+f:2:DWARF_REG_TO_REGNUM:int:dwarf_reg_to_regnum:int dwarf_regnr:dwarf_regnr:::no_op_reg_to_regnum::0
+# Convert from an sdb register number to an internal gdb register number.
+f:2:SDB_REG_TO_REGNUM:int:sdb_reg_to_regnum:int sdb_regnr:sdb_regnr:::no_op_reg_to_regnum::0
+f:2:DWARF2_REG_TO_REGNUM:int:dwarf2_reg_to_regnum:int dwarf2_regnr:dwarf2_regnr:::no_op_reg_to_regnum::0
+f::REGISTER_NAME:const char *:register_name:int regnr:regnr
+
+# REGISTER_TYPE is a direct replacement for DEPRECATED_REGISTER_VIRTUAL_TYPE.
+M:2:REGISTER_TYPE:struct type *:register_type:int reg_nr:reg_nr
+# REGISTER_TYPE is a direct replacement for DEPRECATED_REGISTER_VIRTUAL_TYPE.
+F:2:DEPRECATED_REGISTER_VIRTUAL_TYPE:struct type *:deprecated_register_virtual_type:int reg_nr:reg_nr
+# DEPRECATED_REGISTER_BYTES can be deleted. The value is computed
+# from REGISTER_TYPE.
+v::DEPRECATED_REGISTER_BYTES:int:deprecated_register_bytes
+# If the value returned by DEPRECATED_REGISTER_BYTE agrees with the
+# register offsets computed using just REGISTER_TYPE, this can be
+# deleted. See: maint print registers. NOTE: cagney/2002-05-02: This
+# function with predicate has a valid (callable) initial value. As a
+# consequence, even when the predicate is false, the corresponding
+# function works. This simplifies the migration process - old code,
+# calling DEPRECATED_REGISTER_BYTE, doesn't need to be modified.
+F::DEPRECATED_REGISTER_BYTE:int:deprecated_register_byte:int reg_nr:reg_nr::generic_register_byte:generic_register_byte
+# If all registers have identical raw and virtual sizes and those
+# sizes agree with the value computed from REGISTER_TYPE,
+# DEPRECATED_REGISTER_RAW_SIZE can be deleted. See: maint print
+# registers.
+F:2:DEPRECATED_REGISTER_RAW_SIZE:int:deprecated_register_raw_size:int reg_nr:reg_nr::generic_register_size:generic_register_size
+# If all registers have identical raw and virtual sizes and those
+# sizes agree with the value computed from REGISTER_TYPE,
+# DEPRECATED_REGISTER_VIRTUAL_SIZE can be deleted. See: maint print
+# registers.
+F:2:DEPRECATED_REGISTER_VIRTUAL_SIZE:int:deprecated_register_virtual_size:int reg_nr:reg_nr::generic_register_size:generic_register_size
+# DEPRECATED_MAX_REGISTER_RAW_SIZE can be deleted. It has been
+# replaced by the constant MAX_REGISTER_SIZE.
+V:2:DEPRECATED_MAX_REGISTER_RAW_SIZE:int:deprecated_max_register_raw_size
+# DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE can be deleted. It has been
+# replaced by the constant MAX_REGISTER_SIZE.
+V:2:DEPRECATED_MAX_REGISTER_VIRTUAL_SIZE:int:deprecated_max_register_virtual_size
+
+# See gdbint.texinfo, and PUSH_DUMMY_CALL.
+M::UNWIND_DUMMY_ID:struct frame_id:unwind_dummy_id:struct frame_info *info:info
+# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+# SAVE_DUMMY_FRAME_TOS.
+F:2:DEPRECATED_SAVE_DUMMY_FRAME_TOS:void:deprecated_save_dummy_frame_tos:CORE_ADDR sp:sp
+# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+# DEPRECATED_FP_REGNUM.
+v:2:DEPRECATED_FP_REGNUM:int:deprecated_fp_regnum::::-1:-1::0
+# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+# DEPRECATED_TARGET_READ_FP.
+F::DEPRECATED_TARGET_READ_FP:CORE_ADDR:deprecated_target_read_fp:void
+
+# See gdbint.texinfo. See infcall.c. New, all singing all dancing,
+# replacement for DEPRECATED_PUSH_ARGUMENTS.
+M::PUSH_DUMMY_CALL:CORE_ADDR:push_dummy_call:CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr:func_addr, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr
+# PUSH_DUMMY_CALL is a direct replacement for DEPRECATED_PUSH_ARGUMENTS.
+F:2:DEPRECATED_PUSH_ARGUMENTS:CORE_ADDR:deprecated_push_arguments:int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr:nargs, args, sp, struct_return, struct_addr
+# DEPRECATED_USE_GENERIC_DUMMY_FRAMES can be deleted. Always true.
+v::DEPRECATED_USE_GENERIC_DUMMY_FRAMES:int:deprecated_use_generic_dummy_frames:::::1::0
+# Implement PUSH_RETURN_ADDRESS, and then merge in
+# DEPRECATED_PUSH_RETURN_ADDRESS.
+F:2:DEPRECATED_PUSH_RETURN_ADDRESS:CORE_ADDR:deprecated_push_return_address:CORE_ADDR pc, CORE_ADDR sp:pc, sp
+# Implement PUSH_DUMMY_CALL, then merge in DEPRECATED_DUMMY_WRITE_SP.
+F:2:DEPRECATED_DUMMY_WRITE_SP:void:deprecated_dummy_write_sp:CORE_ADDR val:val
+# DEPRECATED_REGISTER_SIZE can be deleted.
+v::DEPRECATED_REGISTER_SIZE:int:deprecated_register_size
+v::CALL_DUMMY_LOCATION:int:call_dummy_location:::::AT_ENTRY_POINT::0
+# DEPRECATED_CALL_DUMMY_START_OFFSET can be deleted.
+v::DEPRECATED_CALL_DUMMY_START_OFFSET:CORE_ADDR:deprecated_call_dummy_start_offset
+# DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET can be deleted.
+v::DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET:CORE_ADDR:deprecated_call_dummy_breakpoint_offset
+# DEPRECATED_CALL_DUMMY_LENGTH can be deleted.
+v::DEPRECATED_CALL_DUMMY_LENGTH:int:deprecated_call_dummy_length
+# DEPRECATED_CALL_DUMMY_WORDS can be deleted.
+v::DEPRECATED_CALL_DUMMY_WORDS:LONGEST *:deprecated_call_dummy_words::::0:legacy_call_dummy_words::0:0x%08lx
+# Implement PUSH_DUMMY_CALL, then delete DEPRECATED_SIZEOF_CALL_DUMMY_WORDS.
+v::DEPRECATED_SIZEOF_CALL_DUMMY_WORDS:int:deprecated_sizeof_call_dummy_words::::0:legacy_sizeof_call_dummy_words::0
+# DEPRECATED_FIX_CALL_DUMMY can be deleted. For the SPARC, implement
+# PUSH_DUMMY_CODE and set CALL_DUMMY_LOCATION to ON_STACK.
+F::DEPRECATED_FIX_CALL_DUMMY:void:deprecated_fix_call_dummy:char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, struct value **args, struct type *type, int gcc_p:dummy, pc, fun, nargs, args, type, gcc_p
+# This is a replacement for DEPRECATED_FIX_CALL_DUMMY et.al.
+M::PUSH_DUMMY_CODE:CORE_ADDR:push_dummy_code:CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc, struct value **args, int nargs, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr:sp, funaddr, using_gcc, args, nargs, value_type, real_pc, bp_addr
+# Implement PUSH_DUMMY_CALL, then delete DEPRECATED_PUSH_DUMMY_FRAME.
+F:2:DEPRECATED_PUSH_DUMMY_FRAME:void:deprecated_push_dummy_frame:void:-
+
+F:2:DEPRECATED_DO_REGISTERS_INFO:void:deprecated_do_registers_info:int reg_nr, int fpregs:reg_nr, fpregs
+m:2:PRINT_REGISTERS_INFO:void:print_registers_info:struct ui_file *file, struct frame_info *frame, int regnum, int all:file, frame, regnum, all:::default_print_registers_info::0
+M:2:PRINT_FLOAT_INFO:void:print_float_info:struct ui_file *file, struct frame_info *frame, const char *args:file, frame, args
+M:2:PRINT_VECTOR_INFO:void:print_vector_info:struct ui_file *file, struct frame_info *frame, const char *args:file, frame, args
+# MAP a GDB RAW register number onto a simulator register number. See
+# also include/...-sim.h.
+f:2:REGISTER_SIM_REGNO:int:register_sim_regno:int reg_nr:reg_nr:::legacy_register_sim_regno::0
+F:2:REGISTER_BYTES_OK:int:register_bytes_ok:long nr_bytes:nr_bytes
+f:2:CANNOT_FETCH_REGISTER:int:cannot_fetch_register:int regnum:regnum:::cannot_register_not::0
+f:2:CANNOT_STORE_REGISTER:int:cannot_store_register:int regnum:regnum:::cannot_register_not::0
+# setjmp/longjmp support.
+F:2:GET_LONGJMP_TARGET:int:get_longjmp_target:CORE_ADDR *pc:pc
+# NOTE: cagney/2002-11-24: This function with predicate has a valid
+# (callable) initial value. As a consequence, even when the predicate
+# is false, the corresponding function works. This simplifies the
+# migration process - old code, calling DEPRECATED_PC_IN_CALL_DUMMY(),
+# doesn't need to be modified.
+F::DEPRECATED_PC_IN_CALL_DUMMY:int:deprecated_pc_in_call_dummy:CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR frame_address:pc, sp, frame_address::generic_pc_in_call_dummy:generic_pc_in_call_dummy
+F:2:DEPRECATED_INIT_FRAME_PC_FIRST:CORE_ADDR:deprecated_init_frame_pc_first:int fromleaf, struct frame_info *prev:fromleaf, prev
+F:2:DEPRECATED_INIT_FRAME_PC:CORE_ADDR:deprecated_init_frame_pc:int fromleaf, struct frame_info *prev:fromleaf, prev
+#
+v:2:BELIEVE_PCC_PROMOTION:int:believe_pcc_promotion:::::::
+v::BELIEVE_PCC_PROMOTION_TYPE:int:believe_pcc_promotion_type:::::::
+F:2:DEPRECATED_GET_SAVED_REGISTER:void:deprecated_get_saved_register:char *raw_buffer, int *optimized, CORE_ADDR *addrp, struct frame_info *frame, int regnum, enum lval_type *lval:raw_buffer, optimized, addrp, frame, regnum, lval
+#
+# For register <-> value conversions, replaced by CONVERT_REGISTER_P et.al.
+# For raw <-> cooked register conversions, replaced by pseudo registers.
+F::DEPRECATED_REGISTER_CONVERTIBLE:int:deprecated_register_convertible:int nr:nr
+# For register <-> value conversions, replaced by CONVERT_REGISTER_P et.al.
+# For raw <-> cooked register conversions, replaced by pseudo registers.
+f:2:DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL:void:deprecated_register_convert_to_virtual:int regnum, struct type *type, char *from, char *to:regnum, type, from, to:::0::0
+# For register <-> value conversions, replaced by CONVERT_REGISTER_P et.al.
+# For raw <-> cooked register conversions, replaced by pseudo registers.
+f:2:DEPRECATED_REGISTER_CONVERT_TO_RAW:void:deprecated_register_convert_to_raw:struct type *type, int regnum, const char *from, char *to:type, regnum, from, to:::0::0
+#
+f:1:CONVERT_REGISTER_P:int:convert_register_p:int regnum, struct type *type:regnum, type::0:legacy_convert_register_p::0
+f:1:REGISTER_TO_VALUE:void:register_to_value:struct frame_info *frame, int regnum, struct type *type, void *buf:frame, regnum, type, buf::0:legacy_register_to_value::0
+f:1:VALUE_TO_REGISTER:void:value_to_register:struct frame_info *frame, int regnum, struct type *type, const void *buf:frame, regnum, type, buf::0:legacy_value_to_register::0
+#
+f:2:POINTER_TO_ADDRESS:CORE_ADDR:pointer_to_address:struct type *type, const void *buf:type, buf:::unsigned_pointer_to_address::0
+f:2:ADDRESS_TO_POINTER:void:address_to_pointer:struct type *type, void *buf, CORE_ADDR addr:type, buf, addr:::unsigned_address_to_pointer::0
+F:2:INTEGER_TO_ADDRESS:CORE_ADDR:integer_to_address:struct type *type, void *buf:type, buf
+#
+F:2:DEPRECATED_POP_FRAME:void:deprecated_pop_frame:void:-
+# NOTE: cagney/2003-03-24: Replaced by PUSH_ARGUMENTS.
+F:2:DEPRECATED_STORE_STRUCT_RETURN:void:deprecated_store_struct_return:CORE_ADDR addr, CORE_ADDR sp:addr, sp
+
+# It has been suggested that this, well actually its predecessor,
+# should take the type/value of the function to be called and not the
+# return type. This is left as an exercise for the reader.
+
+M:::enum return_value_convention:return_value:struct type *valtype, struct regcache *regcache, void *readbuf, const void *writebuf:valtype, regcache, readbuf, writebuf
+
+# The deprecated methods RETURN_VALUE_ON_STACK, EXTRACT_RETURN_VALUE,
+# STORE_RETURN_VALUE and USE_STRUCT_CONVENTION have all been folded
+# into RETURN_VALUE.
+
+f:2:RETURN_VALUE_ON_STACK:int:return_value_on_stack:struct type *type:type:::generic_return_value_on_stack_not::0
+f:2:EXTRACT_RETURN_VALUE:void:extract_return_value:struct type *type, struct regcache *regcache, void *valbuf:type, regcache, valbuf:::legacy_extract_return_value::0
+f:2:STORE_RETURN_VALUE:void:store_return_value:struct type *type, struct regcache *regcache, const void *valbuf:type, regcache, valbuf:::legacy_store_return_value::0
+f:2:DEPRECATED_EXTRACT_RETURN_VALUE:void:deprecated_extract_return_value:struct type *type, char *regbuf, char *valbuf:type, regbuf, valbuf
+f:2:DEPRECATED_STORE_RETURN_VALUE:void:deprecated_store_return_value:struct type *type, char *valbuf:type, valbuf
+f:2:USE_STRUCT_CONVENTION:int:use_struct_convention:int gcc_p, struct type *value_type:gcc_p, value_type:::generic_use_struct_convention::0
+
+# As of 2004-01-17 only the 32-bit SPARC ABI has been identified as an
+# ABI suitable for the implementation of a robust extract
+# struct-convention return-value address method (the sparc saves the
+# address in the callers frame). All the other cases so far examined,
+# the DEPRECATED_EXTRACT_STRUCT_VALUE implementation has been
+# erreneous - the code was incorrectly assuming that the return-value
+# address, stored in a register, was preserved across the entire
+# function call.
+
+# For the moment retain DEPRECATED_EXTRACT_STRUCT_VALUE as a marker of
+# the ABIs that are still to be analyzed - perhaps this should simply
+# be deleted. The commented out extract_returned_value_address method
+# is provided as a starting point for the 32-bit SPARC. It, or
+# something like it, along with changes to both infcmd.c and stack.c
+# will be needed for that case to work. NB: It is passed the callers
+# frame since it is only after the callee has returned that this
+# function is used.
+
+#M:::CORE_ADDR:extract_returned_value_address:struct frame_info *caller_frame:caller_frame
+F:2:DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS:CORE_ADDR:deprecated_extract_struct_value_address:struct regcache *regcache:regcache
+
+F:2:DEPRECATED_FRAME_INIT_SAVED_REGS:void:deprecated_frame_init_saved_regs:struct frame_info *frame:frame
+F:2:DEPRECATED_INIT_EXTRA_FRAME_INFO:void:deprecated_init_extra_frame_info:int fromleaf, struct frame_info *frame:fromleaf, frame
+#
+f:2:SKIP_PROLOGUE:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip::0:0
+f:2:INNER_THAN:int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs::0:0
+f::BREAKPOINT_FROM_PC:const unsigned char *:breakpoint_from_pc:CORE_ADDR *pcptr, int *lenptr:pcptr, lenptr:::0:
+M:2:ADJUST_BREAKPOINT_ADDRESS:CORE_ADDR:adjust_breakpoint_address:CORE_ADDR bpaddr:bpaddr
+f:2:MEMORY_INSERT_BREAKPOINT:int:memory_insert_breakpoint:CORE_ADDR addr, char *contents_cache:addr, contents_cache::0:default_memory_insert_breakpoint::0
+f:2:MEMORY_REMOVE_BREAKPOINT:int:memory_remove_breakpoint:CORE_ADDR addr, char *contents_cache:addr, contents_cache::0:default_memory_remove_breakpoint::0
+v:2:DECR_PC_AFTER_BREAK:CORE_ADDR:decr_pc_after_break::::0:::0
+v:2:FUNCTION_START_OFFSET:CORE_ADDR:function_start_offset::::0:::0
+#
+m::REMOTE_TRANSLATE_XFER_ADDRESS:void:remote_translate_xfer_address:struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len:regcache, gdb_addr, gdb_len, rem_addr, rem_len:::generic_remote_translate_xfer_address::0
+#
+v::FRAME_ARGS_SKIP:CORE_ADDR:frame_args_skip::::0:::0
+# DEPRECATED_FRAMELESS_FUNCTION_INVOCATION is not needed. The new
+# frame code works regardless of the type of frame - frameless,
+# stackless, or normal.
+F::DEPRECATED_FRAMELESS_FUNCTION_INVOCATION:int:deprecated_frameless_function_invocation:struct frame_info *fi:fi
+F:2:DEPRECATED_FRAME_CHAIN:CORE_ADDR:deprecated_frame_chain:struct frame_info *frame:frame
+F:2:DEPRECATED_FRAME_CHAIN_VALID:int:deprecated_frame_chain_valid:CORE_ADDR chain, struct frame_info *thisframe:chain, thisframe
+# DEPRECATED_FRAME_SAVED_PC has been replaced by UNWIND_PC. Please
+# note, per UNWIND_PC's doco, that while the two have similar
+# interfaces they have very different underlying implementations.
+F:2:DEPRECATED_FRAME_SAVED_PC:CORE_ADDR:deprecated_frame_saved_pc:struct frame_info *fi:fi
+M::UNWIND_PC:CORE_ADDR:unwind_pc:struct frame_info *next_frame:next_frame
+M::UNWIND_SP:CORE_ADDR:unwind_sp:struct frame_info *next_frame:next_frame
+# DEPRECATED_FRAME_ARGS_ADDRESS as been replaced by the per-frame
+# frame-base. Enable frame-base before frame-unwind.
+F::DEPRECATED_FRAME_ARGS_ADDRESS:CORE_ADDR:deprecated_frame_args_address:struct frame_info *fi:fi::get_frame_base:get_frame_base
+# DEPRECATED_FRAME_LOCALS_ADDRESS as been replaced by the per-frame
+# frame-base. Enable frame-base before frame-unwind.
+F::DEPRECATED_FRAME_LOCALS_ADDRESS:CORE_ADDR:deprecated_frame_locals_address:struct frame_info *fi:fi::get_frame_base:get_frame_base
+F::DEPRECATED_SAVED_PC_AFTER_CALL:CORE_ADDR:deprecated_saved_pc_after_call:struct frame_info *frame:frame
+F:2:FRAME_NUM_ARGS:int:frame_num_args:struct frame_info *frame:frame
+#
+# DEPRECATED_STACK_ALIGN has been replaced by an initial aligning call
+# to frame_align and the requirement that methods such as
+# push_dummy_call and frame_red_zone_size maintain correct stack/frame
+# alignment.
+F:2:DEPRECATED_STACK_ALIGN:CORE_ADDR:deprecated_stack_align:CORE_ADDR sp:sp
+M:::CORE_ADDR:frame_align:CORE_ADDR address:address
+# DEPRECATED_REG_STRUCT_HAS_ADDR has been replaced by
+# stabs_argument_has_addr.
+F:2:DEPRECATED_REG_STRUCT_HAS_ADDR:int:deprecated_reg_struct_has_addr:int gcc_p, struct type *type:gcc_p, type
+m:::int:stabs_argument_has_addr:struct type *type:type:::default_stabs_argument_has_addr::0
+v::FRAME_RED_ZONE_SIZE:int:frame_red_zone_size
+v:2:PARM_BOUNDARY:int:parm_boundary
+#
+v:2:TARGET_FLOAT_FORMAT:const struct floatformat *:float_format::::::default_float_format (current_gdbarch)::%s:(TARGET_FLOAT_FORMAT)->name
+v:2:TARGET_DOUBLE_FORMAT:const struct floatformat *:double_format::::::default_double_format (current_gdbarch)::%s:(TARGET_DOUBLE_FORMAT)->name
+v:2:TARGET_LONG_DOUBLE_FORMAT:const struct floatformat *:long_double_format::::::default_double_format (current_gdbarch)::%s:(TARGET_LONG_DOUBLE_FORMAT)->name
+m:::CORE_ADDR:convert_from_func_ptr_addr:CORE_ADDR addr, struct target_ops *targ:addr, targ:::convert_from_func_ptr_addr_identity::0
+# 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).
+f:2:ADDR_BITS_REMOVE:CORE_ADDR:addr_bits_remove:CORE_ADDR addr:addr:::core_addr_identity::0
+# It is not at all clear why SMASH_TEXT_ADDRESS is not folded into
+# ADDR_BITS_REMOVE.
+f:2:SMASH_TEXT_ADDRESS:CORE_ADDR:smash_text_address:CORE_ADDR addr:addr:::core_addr_identity::0
+# FIXME/cagney/2001-01-18: This should be split in two. A target method that indicates if
+# the target needs software single step. An ISA method to implement it.
+#
+# FIXME/cagney/2001-01-18: This should be replaced with something that inserts breakpoints
+# using the breakpoint system instead of blatting memory directly (as with rs6000).
+#
+# FIXME/cagney/2001-01-18: The logic is backwards. It should be asking if the target can
+# single step. If not, then implement single step using breakpoints.
+F:2:SOFTWARE_SINGLE_STEP:void:software_single_step:enum target_signal sig, int insert_breakpoints_p:sig, insert_breakpoints_p
+# FIXME: cagney/2003-08-28: Need to find a better way of selecting the
+# disassembler. Perhaphs objdump can handle it?
+f::TARGET_PRINT_INSN:int:print_insn:bfd_vma vma, struct disassemble_info *info:vma, info:::0:
+f:2:SKIP_TRAMPOLINE_CODE:CORE_ADDR:skip_trampoline_code:CORE_ADDR pc:pc:::generic_skip_trampoline_code::0
+
+
+# If IN_SOLIB_DYNSYM_RESOLVE_CODE returns true, and SKIP_SOLIB_RESOLVER
+# evaluates non-zero, this is the address where the debugger will place
+# a step-resume breakpoint to get us past the dynamic linker.
+m:2:SKIP_SOLIB_RESOLVER:CORE_ADDR:skip_solib_resolver:CORE_ADDR pc:pc:::generic_skip_solib_resolver::0
+# 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 currently stopped in one of these.
+f:2:IN_SOLIB_CALL_TRAMPOLINE:int:in_solib_call_trampoline:CORE_ADDR pc, char *name:pc, name:::generic_in_solib_call_trampoline::0
+
+# Some systems also have trampoline code for returning from shared libs.
+f:2:IN_SOLIB_RETURN_TRAMPOLINE:int:in_solib_return_trampoline:CORE_ADDR pc, char *name:pc, name:::generic_in_solib_return_trampoline::0
+
+# 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).
+#
+# FIXME: cagney/2002-04-21: The function find_pc_partial_function
+# calls find_pc_sect_partial_function() which calls PC_IN_SIGTRAMP.
+# This means PC_IN_SIGTRAMP function can't be implemented by doing its
+# own local NAME lookup.
+#
+# FIXME: cagney/2002-04-21: PC_IN_SIGTRAMP is something of a mess.
+# Some code also depends on SIGTRAMP_START and SIGTRAMP_END but other
+# does not.
+f:2:PC_IN_SIGTRAMP:int:pc_in_sigtramp:CORE_ADDR pc, char *name:pc, name:::legacy_pc_in_sigtramp::0
+F:2:SIGTRAMP_START:CORE_ADDR:sigtramp_start:CORE_ADDR pc:pc
+F:2:SIGTRAMP_END:CORE_ADDR:sigtramp_end:CORE_ADDR pc:pc
+# A target might have problems with watchpoints as soon as the stack
+# frame of the current function has been destroyed. This mostly happens
+# as the first action in a funtion's epilogue. in_function_epilogue_p()
+# is defined to return a non-zero value if either the given addr is one
+# instruction after the stack destroying instruction up to the trailing
+# return instruction or if we can figure out that the stack frame has
+# already been invalidated regardless of the value of addr. Targets
+# which don't suffer from that problem could just let this functionality
+# untouched.
+m:::int:in_function_epilogue_p:CORE_ADDR addr:addr::0:generic_in_function_epilogue_p::0
+# Given a vector of command-line arguments, return a newly allocated
+# string which, when passed to the create_inferior function, will be
+# parsed (on Unix systems, by the shell) to yield the same vector.
+# This function should call error() if the argument vector is not
+# representable for this target or if this target does not support
+# command-line arguments.
+# ARGC is the number of elements in the vector.
+# ARGV is an array of strings, one per argument.
+m::CONSTRUCT_INFERIOR_ARGUMENTS:char *:construct_inferior_arguments:int argc, char **argv:argc, argv:::construct_inferior_arguments::0
+f:2:ELF_MAKE_MSYMBOL_SPECIAL:void:elf_make_msymbol_special:asymbol *sym, struct minimal_symbol *msym:sym, msym:::default_elf_make_msymbol_special::0
+f:2:COFF_MAKE_MSYMBOL_SPECIAL:void:coff_make_msymbol_special:int val, struct minimal_symbol *msym:val, msym:::default_coff_make_msymbol_special::0
+v:2:NAME_OF_MALLOC:const char *:name_of_malloc::::"malloc":"malloc"::0:%s:NAME_OF_MALLOC
+v:2:CANNOT_STEP_BREAKPOINT:int:cannot_step_breakpoint::::0:0::0
+v:2:HAVE_NONSTEPPABLE_WATCHPOINT:int:have_nonsteppable_watchpoint::::0:0::0
+F:2:ADDRESS_CLASS_TYPE_FLAGS:int:address_class_type_flags:int byte_size, int dwarf2_addr_class:byte_size, dwarf2_addr_class
+M:2:ADDRESS_CLASS_TYPE_FLAGS_TO_NAME:const char *:address_class_type_flags_to_name:int type_flags:type_flags
+M:2:ADDRESS_CLASS_NAME_TO_TYPE_FLAGS:int:address_class_name_to_type_flags:const char *name, int *type_flags_ptr:name, type_flags_ptr
+# Is a register in a group
+m:::int:register_reggroup_p:int regnum, struct reggroup *reggroup:regnum, reggroup:::default_register_reggroup_p::0
+# Fetch the pointer to the ith function argument.
+F::FETCH_POINTER_ARGUMENT:CORE_ADDR:fetch_pointer_argument:struct frame_info *frame, int argi, struct type *type:frame, argi, type
+
+# Return the appropriate register set for a core file section with
+# name SECT_NAME and size SECT_SIZE.
+M:::const struct regset *:regset_from_core_section:const char *sect_name, size_t sect_size:sect_name, sect_size
+EOF
+}
+
+#
+# The .log file
+#
+exec > new-gdbarch.log
+function_list | while do_read
+do
+ cat <<EOF
+${class} ${macro}(${actual})
+ ${returntype} ${function} ($formal)${attrib}
+EOF
+ for r in ${read}
+ do
+ eval echo \"\ \ \ \ ${r}=\${${r}}\"
+ done
+ if class_is_predicate_p && fallback_default_p
+ then
+ echo "Error: predicate function ${macro} can not have a non- multi-arch default" 1>&2
+ kill $$
+ exit 1
+ fi
+ if [ "x${invalid_p}" = "x0" -a -n "${postdefault}" ]
+ then
+ echo "Error: postdefault is useless when invalid_p=0" 1>&2
+ kill $$
+ exit 1
+ fi
+ if class_is_multiarch_p
+ then
+ if class_is_predicate_p ; then :
+ elif test "x${predefault}" = "x"
+ then
+ echo "Error: pure multi-arch function must have a predefault" 1>&2
+ kill $$
+ exit 1
+ fi
+ fi
+ echo ""
+done
+
+exec 1>&2
+compare_new gdbarch.log
+
+
+copyright ()
+{
+cat <<EOF
+/* *INDENT-OFF* */ /* THIS FILE IS GENERATED */
+
+/* Dynamic architecture support for GDB, the GNU debugger.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This file was created with the aid of \`\`gdbarch.sh''.
+
+ The Bourne shell script \`\`gdbarch.sh'' creates the files
+ \`\`new-gdbarch.c'' and \`\`new-gdbarch.h and then compares them
+ against the existing \`\`gdbarch.[hc]''. Any differences found
+ being reported.
+
+ If editing this file, please also run gdbarch.sh and merge any
+ changes into that script. Conversely, when making sweeping changes
+ to this file, modifying gdbarch.sh and using its output may prove
+ easier. */
+
+EOF
+}
+
+#
+# The .h file
+#
+
+exec > new-gdbarch.h
+copyright
+cat <<EOF
+#ifndef GDBARCH_H
+#define GDBARCH_H
+
+struct floatformat;
+struct ui_file;
+struct frame_info;
+struct value;
+struct objfile;
+struct minimal_symbol;
+struct regcache;
+struct reggroup;
+struct regset;
+struct disassemble_info;
+struct target_ops;
+
+extern struct gdbarch *current_gdbarch;
+
+
+/* If any of the following are defined, the target wasn't correctly
+ converted. */
+
+#if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PURE) && defined (GDB_TM_FILE)
+#error "GDB_TM_FILE: Pure multi-arch targets do not have a tm.h file."
+#endif
+EOF
+
+# function typedef's
+printf "\n"
+printf "\n"
+printf "/* The following are pre-initialized by GDBARCH. */\n"
+function_list | while do_read
+do
+ if class_is_info_p
+ then
+ printf "\n"
+ printf "extern ${returntype} gdbarch_${function} (struct gdbarch *gdbarch);\n"
+ printf "/* set_gdbarch_${function}() - not applicable - pre-initialized. */\n"
+ printf "#if (GDB_MULTI_ARCH ${gt_level}) && defined (${macro})\n"
+ printf "#error \"Non multi-arch definition of ${macro}\"\n"
+ printf "#endif\n"
+ printf "#if !defined (${macro})\n"
+ printf "#define ${macro} (gdbarch_${function} (current_gdbarch))\n"
+ printf "#endif\n"
+ fi
+done
+
+# function typedef's
+printf "\n"
+printf "\n"
+printf "/* The following are initialized by the target dependent code. */\n"
+function_list | while do_read
+do
+ if [ -n "${comment}" ]
+ then
+ echo "${comment}" | sed \
+ -e '2 s,#,/*,' \
+ -e '3,$ s,#, ,' \
+ -e '$ s,$, */,'
+ fi
+ if class_is_multiarch_p
+ then
+ if class_is_predicate_p
+ then
+ printf "\n"
+ printf "extern int gdbarch_${function}_p (struct gdbarch *gdbarch);\n"
+ fi
+ else
+ if class_is_predicate_p
+ then
+ printf "\n"
+ printf "#if defined (${macro})\n"
+ printf "/* Legacy for systems yet to multi-arch ${macro} */\n"
+ #printf "#if (GDB_MULTI_ARCH <= GDB_MULTI_ARCH_PARTIAL) && defined (${macro})\n"
+ printf "#if !defined (${macro}_P)\n"
+ printf "#define ${macro}_P() (1)\n"
+ printf "#endif\n"
+ printf "#endif\n"
+ printf "\n"
+ printf "extern int gdbarch_${function}_p (struct gdbarch *gdbarch);\n"
+ printf "#if (GDB_MULTI_ARCH ${gt_level}) && defined (${macro}_P)\n"
+ printf "#error \"Non multi-arch definition of ${macro}\"\n"
+ printf "#endif\n"
+ printf "#if (GDB_MULTI_ARCH ${gt_level}) || !defined (${macro}_P)\n"
+ printf "#define ${macro}_P() (gdbarch_${function}_p (current_gdbarch))\n"
+ printf "#endif\n"
+ fi
+ fi
+ if class_is_variable_p
+ then
+ printf "\n"
+ printf "extern ${returntype} gdbarch_${function} (struct gdbarch *gdbarch);\n"
+ printf "extern void set_gdbarch_${function} (struct gdbarch *gdbarch, ${returntype} ${function});\n"
+ printf "#if (GDB_MULTI_ARCH ${gt_level}) && defined (${macro})\n"
+ printf "#error \"Non multi-arch definition of ${macro}\"\n"
+ printf "#endif\n"
+ printf "#if !defined (${macro})\n"
+ printf "#define ${macro} (gdbarch_${function} (current_gdbarch))\n"
+ printf "#endif\n"
+ fi
+ if class_is_function_p
+ then
+ printf "\n"
+ if [ "x${formal}" = "xvoid" ] && class_is_multiarch_p
+ then
+ printf "typedef ${returntype} (gdbarch_${function}_ftype) (struct gdbarch *gdbarch);\n"
+ elif class_is_multiarch_p
+ then
+ printf "typedef ${returntype} (gdbarch_${function}_ftype) (struct gdbarch *gdbarch, ${formal});\n"
+ else
+ printf "typedef ${returntype} (gdbarch_${function}_ftype) (${formal});\n"
+ fi
+ if [ "x${formal}" = "xvoid" ]
+ then
+ printf "extern ${returntype} gdbarch_${function} (struct gdbarch *gdbarch);\n"
+ else
+ printf "extern ${returntype} gdbarch_${function} (struct gdbarch *gdbarch, ${formal});\n"
+ fi
+ printf "extern void set_gdbarch_${function} (struct gdbarch *gdbarch, gdbarch_${function}_ftype *${function});\n"
+ if class_is_multiarch_p ; then :
+ else
+ printf "#if (GDB_MULTI_ARCH ${gt_level}) && defined (${macro})\n"
+ printf "#error \"Non multi-arch definition of ${macro}\"\n"
+ printf "#endif\n"
+ if [ "x${actual}" = "x" ]
+ then
+ d="#define ${macro}() (gdbarch_${function} (current_gdbarch))"
+ elif [ "x${actual}" = "x-" ]
+ then
+ d="#define ${macro} (gdbarch_${function} (current_gdbarch))"
+ else
+ d="#define ${macro}(${actual}) (gdbarch_${function} (current_gdbarch, ${actual}))"
+ fi
+ printf "#if !defined (${macro})\n"
+ if [ "x${actual}" = "x" ]
+ then
+ printf "#define ${macro}() (gdbarch_${function} (current_gdbarch))\n"
+ elif [ "x${actual}" = "x-" ]
+ then
+ printf "#define ${macro} (gdbarch_${function} (current_gdbarch))\n"
+ else
+ printf "#define ${macro}(${actual}) (gdbarch_${function} (current_gdbarch, ${actual}))\n"
+ fi
+ printf "#endif\n"
+ fi
+ fi
+done
+
+# close it off
+cat <<EOF
+
+extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
+
+
+/* Mechanism for co-ordinating the selection of a specific
+ architecture.
+
+ GDB targets (*-tdep.c) can register an interest in a specific
+ architecture. Other GDB components can register a need to maintain
+ per-architecture data.
+
+ The mechanisms below ensures that there is only a loose connection
+ between the set-architecture command and the various GDB
+ components. Each component can independently register their need
+ to maintain architecture specific data with gdbarch.
+
+ Pragmatics:
+
+ Previously, a single TARGET_ARCHITECTURE_HOOK was provided. It
+ didn't scale.
+
+ The more traditional mega-struct containing architecture specific
+ data for all the various GDB components was also considered. Since
+ GDB is built from a variable number of (fairly independent)
+ components it was determined that the global aproach was not
+ applicable. */
+
+
+/* Register a new architectural family with GDB.
+
+ Register support for the specified ARCHITECTURE with GDB. When
+ gdbarch determines that the specified architecture has been
+ selected, the corresponding INIT function is called.
+
+ --
+
+ The INIT function takes two parameters: INFO which contains the
+ information available to gdbarch about the (possibly new)
+ architecture; ARCHES which is a list of the previously created
+ \`\`struct gdbarch'' for this architecture.
+
+ The INFO parameter is, as far as possible, be pre-initialized with
+ information obtained from INFO.ABFD or the previously selected
+ architecture.
+
+ The ARCHES parameter is a linked list (sorted most recently used)
+ of all the previously created architures for this architecture
+ family. The (possibly NULL) ARCHES->gdbarch can used to access
+ values from the previously selected architecture for this
+ architecture family. The global \`\`current_gdbarch'' shall not be
+ used.
+
+ The INIT function shall return any of: NULL - indicating that it
+ doesn't recognize the selected architecture; an existing \`\`struct
+ gdbarch'' from the ARCHES list - indicating that the new
+ architecture is just a synonym for an earlier architecture (see
+ gdbarch_list_lookup_by_info()); a newly created \`\`struct gdbarch''
+ - that describes the selected architecture (see gdbarch_alloc()).
+
+ The DUMP_TDEP function shall print out all target specific values.
+ Care should be taken to ensure that the function works in both the
+ multi-arch and non- multi-arch cases. */
+
+struct gdbarch_list
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_list *next;
+};
+
+struct gdbarch_info
+{
+ /* Use default: NULL (ZERO). */
+ const struct bfd_arch_info *bfd_arch_info;
+
+ /* Use default: BFD_ENDIAN_UNKNOWN (NB: is not ZERO). */
+ int byte_order;
+
+ /* Use default: NULL (ZERO). */
+ bfd *abfd;
+
+ /* Use default: NULL (ZERO). */
+ struct gdbarch_tdep_info *tdep_info;
+
+ /* Use default: GDB_OSABI_UNINITIALIZED (-1). */
+ enum gdb_osabi osabi;
+};
+
+typedef struct gdbarch *(gdbarch_init_ftype) (struct gdbarch_info info, struct gdbarch_list *arches);
+typedef void (gdbarch_dump_tdep_ftype) (struct gdbarch *gdbarch, struct ui_file *file);
+
+/* DEPRECATED - use gdbarch_register() */
+extern void register_gdbarch_init (enum bfd_architecture architecture, gdbarch_init_ftype *);
+
+extern void gdbarch_register (enum bfd_architecture architecture,
+ gdbarch_init_ftype *,
+ gdbarch_dump_tdep_ftype *);
+
+
+/* Return a freshly allocated, NULL terminated, array of the valid
+ architecture names. Since architectures are registered during the
+ _initialize phase this function only returns useful information
+ once initialization has been completed. */
+
+extern const char **gdbarch_printable_names (void);
+
+
+/* Helper function. Search the list of ARCHES for a GDBARCH that
+ matches the information provided by INFO. */
+
+extern struct gdbarch_list *gdbarch_list_lookup_by_info (struct gdbarch_list *arches, const struct gdbarch_info *info);
+
+
+/* Helper function. Create a preliminary \`\`struct gdbarch''. Perform
+ basic initialization using values obtained from the INFO andTDEP
+ parameters. set_gdbarch_*() functions are called to complete the
+ initialization of the object. */
+
+extern struct gdbarch *gdbarch_alloc (const struct gdbarch_info *info, struct gdbarch_tdep *tdep);
+
+
+/* Helper function. Free a partially-constructed \`\`struct gdbarch''.
+ It is assumed that the caller freeds the \`\`struct
+ gdbarch_tdep''. */
+
+extern void gdbarch_free (struct gdbarch *);
+
+
+/* Helper function. Allocate memory from the \`\`struct gdbarch''
+ obstack. The memory is freed when the corresponding architecture
+ is also freed. */
+
+extern void *gdbarch_obstack_zalloc (struct gdbarch *gdbarch, long size);
+#define GDBARCH_OBSTACK_CALLOC(GDBARCH, NR, TYPE) ((TYPE *) gdbarch_obstack_zalloc ((GDBARCH), (NR) * sizeof (TYPE)))
+#define GDBARCH_OBSTACK_ZALLOC(GDBARCH, TYPE) ((TYPE *) gdbarch_obstack_zalloc ((GDBARCH), sizeof (TYPE)))
+
+
+/* Helper function. Force an update of the current architecture.
+
+ The actual architecture selected is determined by INFO, \`\`(gdb) set
+ architecture'' et.al., the existing architecture and BFD's default
+ architecture. INFO should be initialized to zero and then selected
+ fields should be updated.
+
+ Returns non-zero if the update succeeds */
+
+extern int gdbarch_update_p (struct gdbarch_info info);
+
+
+/* Helper function. Find an architecture matching info.
+
+ INFO should be initialized using gdbarch_info_init, relevant fields
+ set, and then finished using gdbarch_info_fill.
+
+ Returns the corresponding architecture, or NULL if no matching
+ architecture was found. "current_gdbarch" is not updated. */
+
+extern struct gdbarch *gdbarch_find_by_info (struct gdbarch_info info);
+
+
+/* Helper function. Set the global "current_gdbarch" to "gdbarch".
+
+ FIXME: kettenis/20031124: Of the functions that follow, only
+ gdbarch_from_bfd is supposed to survive. The others will
+ dissappear since in the future GDB will (hopefully) be truly
+ multi-arch. However, for now we're still stuck with the concept of
+ a single active architecture. */
+
+extern void deprecated_current_gdbarch_select_hack (struct gdbarch *gdbarch);
+
+
+/* Register per-architecture data-pointer.
+
+ Reserve space for a per-architecture data-pointer. An identifier
+ for the reserved data-pointer is returned. That identifer should
+ be saved in a local static variable.
+
+ The per-architecture data-pointer is either initialized explicitly
+ (set_gdbarch_data()) or implicitly (by INIT() via a call to
+ gdbarch_data()).
+
+ Memory for the per-architecture data shall be allocated using
+ gdbarch_obstack_zalloc. That memory will be deleted when the
+ corresponding architecture object is deleted.
+
+ When a previously created architecture is re-selected, the
+ per-architecture data-pointer for that previous architecture is
+ restored. INIT() is not re-called.
+
+ Multiple registrarants for any architecture are allowed (and
+ strongly encouraged). */
+
+struct gdbarch_data;
+
+typedef void *(gdbarch_data_init_ftype) (struct gdbarch *gdbarch);
+extern struct gdbarch_data *register_gdbarch_data (gdbarch_data_init_ftype *init);
+extern void set_gdbarch_data (struct gdbarch *gdbarch,
+ struct gdbarch_data *data,
+ void *pointer);
+
+extern void *gdbarch_data (struct gdbarch *gdbarch, struct gdbarch_data *);
+
+
+
+/* Register per-architecture memory region.
+
+ Provide a memory-region swap mechanism. Per-architecture memory
+ region are created. These memory regions are swapped whenever the
+ architecture is changed. For a new architecture, the memory region
+ is initialized with zero (0) and the INIT function is called.
+
+ Memory regions are swapped / initialized in the order that they are
+ registered. NULL DATA and/or INIT values can be specified.
+
+ New code should use register_gdbarch_data(). */
+
+typedef void (gdbarch_swap_ftype) (void);
+extern void deprecated_register_gdbarch_swap (void *data, unsigned long size, gdbarch_swap_ftype *init);
+#define DEPRECATED_REGISTER_GDBARCH_SWAP(VAR) deprecated_register_gdbarch_swap (&(VAR), sizeof ((VAR)), NULL)
+
+
+
+/* Set the dynamic target-system-dependent parameters (architecture,
+ byte-order, ...) using information found in the BFD */
+
+extern void set_gdbarch_from_file (bfd *);
+
+
+/* Initialize the current architecture to the "first" one we find on
+ our list. */
+
+extern void initialize_current_architecture (void);
+
+/* gdbarch trace variable */
+extern int gdbarch_debug;
+
+extern void gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file);
+
+#endif
+EOF
+exec 1>&2
+#../move-if-change new-gdbarch.h gdbarch.h
+compare_new gdbarch.h
+
+
+#
+# C file
+#
+
+exec > new-gdbarch.c
+copyright
+cat <<EOF
+
+#include "defs.h"
+#include "arch-utils.h"
+
+#include "gdbcmd.h"
+#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
+#include "symcat.h"
+
+#include "floatformat.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdb-events.h"
+#include "reggroups.h"
+#include "osabi.h"
+#include "gdb_obstack.h"
+
+/* Static function declarations */
+
+static void alloc_gdbarch_data (struct gdbarch *);
+
+/* Non-zero if we want to trace architecture code. */
+
+#ifndef GDBARCH_DEBUG
+#define GDBARCH_DEBUG 0
+#endif
+int gdbarch_debug = GDBARCH_DEBUG;
+
+EOF
+
+# gdbarch open the gdbarch object
+printf "\n"
+printf "/* Maintain the struct gdbarch object */\n"
+printf "\n"
+printf "struct gdbarch\n"
+printf "{\n"
+printf " /* Has this architecture been fully initialized? */\n"
+printf " int initialized_p;\n"
+printf "\n"
+printf " /* An obstack bound to the lifetime of the architecture. */\n"
+printf " struct obstack *obstack;\n"
+printf "\n"
+printf " /* basic architectural information */\n"
+function_list | while do_read
+do
+ if class_is_info_p
+ then
+ printf " ${returntype} ${function};\n"
+ fi
+done
+printf "\n"
+printf " /* target specific vector. */\n"
+printf " struct gdbarch_tdep *tdep;\n"
+printf " gdbarch_dump_tdep_ftype *dump_tdep;\n"
+printf "\n"
+printf " /* per-architecture data-pointers */\n"
+printf " unsigned nr_data;\n"
+printf " void **data;\n"
+printf "\n"
+printf " /* per-architecture swap-regions */\n"
+printf " struct gdbarch_swap *swap;\n"
+printf "\n"
+cat <<EOF
+ /* Multi-arch values.
+
+ When extending this structure you must:
+
+ Add the field below.
+
+ Declare set/get functions and define the corresponding
+ macro in gdbarch.h.
+
+ gdbarch_alloc(): If zero/NULL is not a suitable default,
+ initialize the new field.
+
+ verify_gdbarch(): Confirm that the target updated the field
+ correctly.
+
+ gdbarch_dump(): Add a fprintf_unfiltered call so that the new
+ field is dumped out
+
+ \`\`startup_gdbarch()'': Append an initial value to the static
+ variable (base values on the host's c-type system).
+
+ get_gdbarch(): Implement the set/get functions (probably using
+ the macro's as shortcuts).
+
+ */
+
+EOF
+function_list | while do_read
+do
+ if class_is_variable_p
+ then
+ printf " ${returntype} ${function};\n"
+ elif class_is_function_p
+ then
+ printf " gdbarch_${function}_ftype *${function}${attrib};\n"
+ fi
+done
+printf "};\n"
+
+# A pre-initialized vector
+printf "\n"
+printf "\n"
+cat <<EOF
+/* The default architecture uses host values (for want of a better
+ choice). */
+EOF
+printf "\n"
+printf "extern const struct bfd_arch_info bfd_default_arch_struct;\n"
+printf "\n"
+printf "struct gdbarch startup_gdbarch =\n"
+printf "{\n"
+printf " 1, /* Always initialized. */\n"
+printf " NULL, /* The obstack. */\n"
+printf " /* basic architecture information */\n"
+function_list | while do_read
+do
+ if class_is_info_p
+ then
+ printf " ${staticdefault}, /* ${function} */\n"
+ fi
+done
+cat <<EOF
+ /* target specific vector and its dump routine */
+ NULL, NULL,
+ /*per-architecture data-pointers and swap regions */
+ 0, NULL, NULL,
+ /* Multi-arch values */
+EOF
+function_list | while do_read
+do
+ if class_is_function_p || class_is_variable_p
+ then
+ printf " ${staticdefault}, /* ${function} */\n"
+ fi
+done
+cat <<EOF
+ /* startup_gdbarch() */
+};
+
+struct gdbarch *current_gdbarch = &startup_gdbarch;
+EOF
+
+# Create a new gdbarch struct
+cat <<EOF
+
+/* Create a new \`\`struct gdbarch'' based on information provided by
+ \`\`struct gdbarch_info''. */
+EOF
+printf "\n"
+cat <<EOF
+struct gdbarch *
+gdbarch_alloc (const struct gdbarch_info *info,
+ struct gdbarch_tdep *tdep)
+{
+ /* NOTE: The new architecture variable is named \`\`current_gdbarch''
+ so that macros such as TARGET_DOUBLE_BIT, when expanded, refer to
+ the current local architecture and not the previous global
+ architecture. This ensures that the new architectures initial
+ values are not influenced by the previous architecture. Once
+ everything is parameterised with gdbarch, this will go away. */
+ struct gdbarch *current_gdbarch;
+
+ /* Create an obstack for allocating all the per-architecture memory,
+ then use that to allocate the architecture vector. */
+ struct obstack *obstack = XMALLOC (struct obstack);
+ obstack_init (obstack);
+ current_gdbarch = obstack_alloc (obstack, sizeof (*current_gdbarch));
+ memset (current_gdbarch, 0, sizeof (*current_gdbarch));
+ current_gdbarch->obstack = obstack;
+
+ alloc_gdbarch_data (current_gdbarch);
+
+ current_gdbarch->tdep = tdep;
+EOF
+printf "\n"
+function_list | while do_read
+do
+ if class_is_info_p
+ then
+ printf " current_gdbarch->${function} = info->${function};\n"
+ fi
+done
+printf "\n"
+printf " /* Force the explicit initialization of these. */\n"
+function_list | while do_read
+do
+ if class_is_function_p || class_is_variable_p
+ then
+ if [ -n "${predefault}" -a "x${predefault}" != "x0" ]
+ then
+ printf " current_gdbarch->${function} = ${predefault};\n"
+ fi
+ fi
+done
+cat <<EOF
+ /* gdbarch_alloc() */
+
+ return current_gdbarch;
+}
+EOF
+
+# Free a gdbarch struct.
+printf "\n"
+printf "\n"
+cat <<EOF
+/* Allocate extra space using the per-architecture obstack. */
+
+void *
+gdbarch_obstack_zalloc (struct gdbarch *arch, long size)
+{
+ void *data = obstack_alloc (arch->obstack, size);
+ memset (data, 0, size);
+ return data;
+}
+
+
+/* Free a gdbarch struct. This should never happen in normal
+ operation --- once you've created a gdbarch, you keep it around.
+ However, if an architecture's init function encounters an error
+ building the structure, it may need to clean up a partially
+ constructed gdbarch. */
+
+void
+gdbarch_free (struct gdbarch *arch)
+{
+ struct obstack *obstack;
+ gdb_assert (arch != NULL);
+ gdb_assert (!arch->initialized_p);
+ obstack = arch->obstack;
+ obstack_free (obstack, 0); /* Includes the ARCH. */
+ xfree (obstack);
+}
+EOF
+
+# verify a new architecture
+cat <<EOF
+
+
+/* Ensure that all values in a GDBARCH are reasonable. */
+
+/* NOTE/WARNING: The parameter is called \`\`current_gdbarch'' so that it
+ just happens to match the global variable \`\`current_gdbarch''. That
+ way macros refering to that variable get the local and not the global
+ version - ulgh. Once everything is parameterised with gdbarch, this
+ will go away. */
+
+static void
+verify_gdbarch (struct gdbarch *current_gdbarch)
+{
+ struct ui_file *log;
+ struct cleanup *cleanups;
+ long dummy;
+ char *buf;
+ log = mem_fileopen ();
+ cleanups = make_cleanup_ui_file_delete (log);
+ /* fundamental */
+ if (current_gdbarch->byte_order == BFD_ENDIAN_UNKNOWN)
+ fprintf_unfiltered (log, "\n\tbyte-order");
+ if (current_gdbarch->bfd_arch_info == NULL)
+ fprintf_unfiltered (log, "\n\tbfd_arch_info");
+ /* Check those that need to be defined for the given multi-arch level. */
+EOF
+function_list | while do_read
+do
+ if class_is_function_p || class_is_variable_p
+ then
+ if [ "x${invalid_p}" = "x0" ]
+ then
+ printf " /* Skip verify of ${function}, invalid_p == 0 */\n"
+ elif class_is_predicate_p
+ then
+ printf " /* Skip verify of ${function}, has predicate */\n"
+ # FIXME: See do_read for potential simplification
+ elif [ -n "${invalid_p}" -a -n "${postdefault}" ]
+ then
+ printf " if (${invalid_p})\n"
+ printf " current_gdbarch->${function} = ${postdefault};\n"
+ elif [ -n "${predefault}" -a -n "${postdefault}" ]
+ then
+ printf " if (current_gdbarch->${function} == ${predefault})\n"
+ printf " current_gdbarch->${function} = ${postdefault};\n"
+ elif [ -n "${postdefault}" ]
+ then
+ printf " if (current_gdbarch->${function} == 0)\n"
+ printf " current_gdbarch->${function} = ${postdefault};\n"
+ elif [ -n "${invalid_p}" ]
+ then
+ printf " if ((GDB_MULTI_ARCH ${gt_level})\n"
+ printf " && (${invalid_p}))\n"
+ printf " fprintf_unfiltered (log, \"\\\\n\\\\t${function}\");\n"
+ elif [ -n "${predefault}" ]
+ then
+ printf " if ((GDB_MULTI_ARCH ${gt_level})\n"
+ printf " && (current_gdbarch->${function} == ${predefault}))\n"
+ printf " fprintf_unfiltered (log, \"\\\\n\\\\t${function}\");\n"
+ fi
+ fi
+done
+cat <<EOF
+ buf = ui_file_xstrdup (log, &dummy);
+ make_cleanup (xfree, buf);
+ if (strlen (buf) > 0)
+ internal_error (__FILE__, __LINE__,
+ "verify_gdbarch: the following are invalid ...%s",
+ buf);
+ do_cleanups (cleanups);
+}
+EOF
+
+# dump the structure
+printf "\n"
+printf "\n"
+cat <<EOF
+/* Print out the details of the current architecture. */
+
+/* NOTE/WARNING: The parameter is called \`\`current_gdbarch'' so that it
+ just happens to match the global variable \`\`current_gdbarch''. That
+ way macros refering to that variable get the local and not the global
+ version - ulgh. Once everything is parameterised with gdbarch, this
+ will go away. */
+
+void
+gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ fprintf_unfiltered (file,
+ "gdbarch_dump: GDB_MULTI_ARCH = %d\\n",
+ GDB_MULTI_ARCH);
+EOF
+function_list | sort -t: -k 3 | while do_read
+do
+ # First the predicate
+ if class_is_predicate_p
+ then
+ if class_is_multiarch_p
+ then
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: gdbarch_${function}_p() = %%d\\\\n\",\n"
+ printf " gdbarch_${function}_p (current_gdbarch));\n"
+ else
+ printf "#ifdef ${macro}_P\n"
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: %%s # %%s\\\\n\",\n"
+ printf " \"${macro}_P()\",\n"
+ printf " XSTRING (${macro}_P ()));\n"
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: ${macro}_P() = %%d\\\\n\",\n"
+ printf " ${macro}_P ());\n"
+ printf "#endif\n"
+ fi
+ fi
+ # multiarch functions don't have macros.
+ if class_is_multiarch_p
+ then
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: ${function} = 0x%%08lx\\\\n\",\n"
+ printf " (long) current_gdbarch->${function});\n"
+ continue
+ fi
+ # Print the macro definition.
+ printf "#ifdef ${macro}\n"
+ if class_is_function_p
+ then
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: %%s # %%s\\\\n\",\n"
+ printf " \"${macro}(${actual})\",\n"
+ printf " XSTRING (${macro} (${actual})));\n"
+ else
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: ${macro} # %%s\\\\n\",\n"
+ printf " XSTRING (${macro}));\n"
+ fi
+ if [ "x${print_p}" = "x()" ]
+ then
+ printf " gdbarch_dump_${function} (current_gdbarch);\n"
+ elif [ "x${print_p}" = "x0" ]
+ then
+ printf " /* skip print of ${macro}, print_p == 0. */\n"
+ elif [ -n "${print_p}" ]
+ then
+ printf " if (${print_p})\n"
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: ${macro} = %s\\\\n\",\n" "${fmt}"
+ printf " ${print});\n"
+ elif class_is_function_p
+ then
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: ${macro} = <0x%%08lx>\\\\n\",\n"
+ printf " (long) current_gdbarch->${function}\n"
+ printf " /*${macro} ()*/);\n"
+ else
+ printf " fprintf_unfiltered (file,\n"
+ printf " \"gdbarch_dump: ${macro} = %s\\\\n\",\n" "${fmt}"
+ printf " ${print});\n"
+ fi
+ printf "#endif\n"
+done
+cat <<EOF
+ if (current_gdbarch->dump_tdep != NULL)
+ current_gdbarch->dump_tdep (current_gdbarch, file);
+}
+EOF
+
+
+# GET/SET
+printf "\n"
+cat <<EOF
+struct gdbarch_tdep *
+gdbarch_tdep (struct gdbarch *gdbarch)
+{
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_tdep called\\n");
+ return gdbarch->tdep;
+}
+EOF
+printf "\n"
+function_list | while do_read
+do
+ if class_is_predicate_p
+ then
+ printf "\n"
+ printf "int\n"
+ printf "gdbarch_${function}_p (struct gdbarch *gdbarch)\n"
+ printf "{\n"
+ printf " gdb_assert (gdbarch != NULL);\n"
+ printf " return ${predicate};\n"
+ printf "}\n"
+ fi
+ if class_is_function_p
+ then
+ printf "\n"
+ printf "${returntype}\n"
+ if [ "x${formal}" = "xvoid" ]
+ then
+ printf "gdbarch_${function} (struct gdbarch *gdbarch)\n"
+ else
+ printf "gdbarch_${function} (struct gdbarch *gdbarch, ${formal})\n"
+ fi
+ printf "{\n"
+ printf " gdb_assert (gdbarch != NULL);\n"
+ printf " gdb_assert (gdbarch->${function} != NULL);\n"
+ if class_is_predicate_p && test -n "${predefault}"
+ then
+ # Allow a call to a function with a predicate.
+ printf " /* Do not check predicate: ${predicate}, allow call. */\n"
+ fi
+ printf " if (gdbarch_debug >= 2)\n"
+ printf " fprintf_unfiltered (gdb_stdlog, \"gdbarch_${function} called\\\\n\");\n"
+ if [ "x${actual}" = "x-" -o "x${actual}" = "x" ]
+ then
+ if class_is_multiarch_p
+ then
+ params="gdbarch"
+ else
+ params=""
+ fi
+ else
+ if class_is_multiarch_p
+ then
+ params="gdbarch, ${actual}"
+ else
+ params="${actual}"
+ fi
+ fi
+ if [ "x${returntype}" = "xvoid" ]
+ then
+ printf " gdbarch->${function} (${params});\n"
+ else
+ printf " return gdbarch->${function} (${params});\n"
+ fi
+ printf "}\n"
+ printf "\n"
+ printf "void\n"
+ printf "set_gdbarch_${function} (struct gdbarch *gdbarch,\n"
+ printf " `echo ${function} | sed -e 's/./ /g'` gdbarch_${function}_ftype ${function})\n"
+ printf "{\n"
+ printf " gdbarch->${function} = ${function};\n"
+ printf "}\n"
+ elif class_is_variable_p
+ then
+ printf "\n"
+ printf "${returntype}\n"
+ printf "gdbarch_${function} (struct gdbarch *gdbarch)\n"
+ printf "{\n"
+ printf " gdb_assert (gdbarch != NULL);\n"
+ if [ "x${invalid_p}" = "x0" ]
+ then
+ printf " /* Skip verify of ${function}, invalid_p == 0 */\n"
+ elif [ -n "${invalid_p}" ]
+ then
+ printf " /* Check variable is valid. */\n"
+ printf " gdb_assert (!(${invalid_p}));\n"
+ elif [ -n "${predefault}" ]
+ then
+ printf " /* Check variable changed from pre-default. */\n"
+ printf " gdb_assert (gdbarch->${function} != ${predefault});\n"
+ fi
+ printf " if (gdbarch_debug >= 2)\n"
+ printf " fprintf_unfiltered (gdb_stdlog, \"gdbarch_${function} called\\\\n\");\n"
+ printf " return gdbarch->${function};\n"
+ printf "}\n"
+ printf "\n"
+ printf "void\n"
+ printf "set_gdbarch_${function} (struct gdbarch *gdbarch,\n"
+ printf " `echo ${function} | sed -e 's/./ /g'` ${returntype} ${function})\n"
+ printf "{\n"
+ printf " gdbarch->${function} = ${function};\n"
+ printf "}\n"
+ elif class_is_info_p
+ then
+ printf "\n"
+ printf "${returntype}\n"
+ printf "gdbarch_${function} (struct gdbarch *gdbarch)\n"
+ printf "{\n"
+ printf " gdb_assert (gdbarch != NULL);\n"
+ printf " if (gdbarch_debug >= 2)\n"
+ printf " fprintf_unfiltered (gdb_stdlog, \"gdbarch_${function} called\\\\n\");\n"
+ printf " return gdbarch->${function};\n"
+ printf "}\n"
+ fi
+done
+
+# All the trailing guff
+cat <<EOF
+
+
+/* Keep a registry of per-architecture data-pointers required by GDB
+ modules. */
+
+struct gdbarch_data
+{
+ unsigned index;
+ int init_p;
+ gdbarch_data_init_ftype *init;
+};
+
+struct gdbarch_data_registration
+{
+ struct gdbarch_data *data;
+ struct gdbarch_data_registration *next;
+};
+
+struct gdbarch_data_registry
+{
+ unsigned nr;
+ struct gdbarch_data_registration *registrations;
+};
+
+struct gdbarch_data_registry gdbarch_data_registry =
+{
+ 0, NULL,
+};
+
+struct gdbarch_data *
+register_gdbarch_data (gdbarch_data_init_ftype *init)
+{
+ struct gdbarch_data_registration **curr;
+ /* Append the new registraration. */
+ for (curr = &gdbarch_data_registry.registrations;
+ (*curr) != NULL;
+ curr = &(*curr)->next);
+ (*curr) = XMALLOC (struct gdbarch_data_registration);
+ (*curr)->next = NULL;
+ (*curr)->data = XMALLOC (struct gdbarch_data);
+ (*curr)->data->index = gdbarch_data_registry.nr++;
+ (*curr)->data->init = init;
+ (*curr)->data->init_p = 1;
+ return (*curr)->data;
+}
+
+
+/* Create/delete the gdbarch data vector. */
+
+static void
+alloc_gdbarch_data (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch->data == NULL);
+ gdbarch->nr_data = gdbarch_data_registry.nr;
+ gdbarch->data = GDBARCH_OBSTACK_CALLOC (gdbarch, gdbarch->nr_data, void *);
+}
+
+/* Initialize the current value of the specified per-architecture
+ data-pointer. */
+
+void
+set_gdbarch_data (struct gdbarch *gdbarch,
+ struct gdbarch_data *data,
+ void *pointer)
+{
+ gdb_assert (data->index < gdbarch->nr_data);
+ gdb_assert (gdbarch->data[data->index] == NULL);
+ gdbarch->data[data->index] = pointer;
+}
+
+/* Return the current value of the specified per-architecture
+ data-pointer. */
+
+void *
+gdbarch_data (struct gdbarch *gdbarch, struct gdbarch_data *data)
+{
+ gdb_assert (data->index < gdbarch->nr_data);
+ /* The data-pointer isn't initialized, call init() to get a value but
+ only if the architecture initializaiton has completed. Otherwise
+ punt - hope that the caller knows what they are doing. */
+ if (gdbarch->data[data->index] == NULL
+ && gdbarch->initialized_p)
+ {
+ /* Be careful to detect an initialization cycle. */
+ gdb_assert (data->init_p);
+ data->init_p = 0;
+ gdb_assert (data->init != NULL);
+ gdbarch->data[data->index] = data->init (gdbarch);
+ data->init_p = 1;
+ gdb_assert (gdbarch->data[data->index] != NULL);
+ }
+ return gdbarch->data[data->index];
+}
+
+
+
+/* Keep a registry of swapped data required by GDB modules. */
+
+struct gdbarch_swap
+{
+ void *swap;
+ struct gdbarch_swap_registration *source;
+ struct gdbarch_swap *next;
+};
+
+struct gdbarch_swap_registration
+{
+ void *data;
+ unsigned long sizeof_data;
+ gdbarch_swap_ftype *init;
+ struct gdbarch_swap_registration *next;
+};
+
+struct gdbarch_swap_registry
+{
+ int nr;
+ struct gdbarch_swap_registration *registrations;
+};
+
+struct gdbarch_swap_registry gdbarch_swap_registry =
+{
+ 0, NULL,
+};
+
+void
+deprecated_register_gdbarch_swap (void *data,
+ unsigned long sizeof_data,
+ gdbarch_swap_ftype *init)
+{
+ struct gdbarch_swap_registration **rego;
+ for (rego = &gdbarch_swap_registry.registrations;
+ (*rego) != NULL;
+ rego = &(*rego)->next);
+ (*rego) = XMALLOC (struct gdbarch_swap_registration);
+ (*rego)->next = NULL;
+ (*rego)->init = init;
+ (*rego)->data = data;
+ (*rego)->sizeof_data = sizeof_data;
+}
+
+static void
+current_gdbarch_swap_init_hack (void)
+{
+ struct gdbarch_swap_registration *rego;
+ struct gdbarch_swap **curr = &current_gdbarch->swap;
+ for (rego = gdbarch_swap_registry.registrations;
+ rego != NULL;
+ rego = rego->next)
+ {
+ if (rego->data != NULL)
+ {
+ (*curr) = GDBARCH_OBSTACK_ZALLOC (current_gdbarch,
+ struct gdbarch_swap);
+ (*curr)->source = rego;
+ (*curr)->swap = gdbarch_obstack_zalloc (current_gdbarch,
+ rego->sizeof_data);
+ (*curr)->next = NULL;
+ curr = &(*curr)->next;
+ }
+ if (rego->init != NULL)
+ rego->init ();
+ }
+}
+
+static struct gdbarch *
+current_gdbarch_swap_out_hack (void)
+{
+ struct gdbarch *old_gdbarch = current_gdbarch;
+ struct gdbarch_swap *curr;
+
+ gdb_assert (old_gdbarch != NULL);
+ for (curr = old_gdbarch->swap;
+ curr != NULL;
+ curr = curr->next)
+ {
+ memcpy (curr->swap, curr->source->data, curr->source->sizeof_data);
+ memset (curr->source->data, 0, curr->source->sizeof_data);
+ }
+ current_gdbarch = NULL;
+ return old_gdbarch;
+}
+
+static void
+current_gdbarch_swap_in_hack (struct gdbarch *new_gdbarch)
+{
+ struct gdbarch_swap *curr;
+
+ gdb_assert (current_gdbarch == NULL);
+ for (curr = new_gdbarch->swap;
+ curr != NULL;
+ curr = curr->next)
+ memcpy (curr->source->data, curr->swap, curr->source->sizeof_data);
+ current_gdbarch = new_gdbarch;
+}
+
+
+/* Keep a registry of the architectures known by GDB. */
+
+struct gdbarch_registration
+{
+ enum bfd_architecture bfd_architecture;
+ gdbarch_init_ftype *init;
+ gdbarch_dump_tdep_ftype *dump_tdep;
+ struct gdbarch_list *arches;
+ struct gdbarch_registration *next;
+};
+
+static struct gdbarch_registration *gdbarch_registry = NULL;
+
+static void
+append_name (const char ***buf, int *nr, const char *name)
+{
+ *buf = xrealloc (*buf, sizeof (char**) * (*nr + 1));
+ (*buf)[*nr] = name;
+ *nr += 1;
+}
+
+const char **
+gdbarch_printable_names (void)
+{
+ /* Accumulate a list of names based on the registed list of
+ architectures. */
+ enum bfd_architecture a;
+ int nr_arches = 0;
+ const char **arches = NULL;
+ struct gdbarch_registration *rego;
+ for (rego = gdbarch_registry;
+ rego != NULL;
+ rego = rego->next)
+ {
+ const struct bfd_arch_info *ap;
+ ap = bfd_lookup_arch (rego->bfd_architecture, 0);
+ if (ap == NULL)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch_architecture_names: multi-arch unknown");
+ do
+ {
+ append_name (&arches, &nr_arches, ap->printable_name);
+ ap = ap->next;
+ }
+ while (ap != NULL);
+ }
+ append_name (&arches, &nr_arches, NULL);
+ return arches;
+}
+
+
+void
+gdbarch_register (enum bfd_architecture bfd_architecture,
+ gdbarch_init_ftype *init,
+ gdbarch_dump_tdep_ftype *dump_tdep)
+{
+ struct gdbarch_registration **curr;
+ const struct bfd_arch_info *bfd_arch_info;
+ /* Check that BFD recognizes this architecture */
+ bfd_arch_info = bfd_lookup_arch (bfd_architecture, 0);
+ if (bfd_arch_info == NULL)
+ {
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: Attempt to register unknown architecture (%d)",
+ bfd_architecture);
+ }
+ /* Check that we haven't seen this architecture before */
+ for (curr = &gdbarch_registry;
+ (*curr) != NULL;
+ curr = &(*curr)->next)
+ {
+ if (bfd_architecture == (*curr)->bfd_architecture)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: Duplicate registraration of architecture (%s)",
+ bfd_arch_info->printable_name);
+ }
+ /* log it */
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "register_gdbarch_init (%s, 0x%08lx)\n",
+ bfd_arch_info->printable_name,
+ (long) init);
+ /* Append it */
+ (*curr) = XMALLOC (struct gdbarch_registration);
+ (*curr)->bfd_architecture = bfd_architecture;
+ (*curr)->init = init;
+ (*curr)->dump_tdep = dump_tdep;
+ (*curr)->arches = NULL;
+ (*curr)->next = NULL;
+}
+
+void
+register_gdbarch_init (enum bfd_architecture bfd_architecture,
+ gdbarch_init_ftype *init)
+{
+ gdbarch_register (bfd_architecture, init, NULL);
+}
+
+
+/* Look for an architecture using gdbarch_info. Base search on only
+ BFD_ARCH_INFO and BYTE_ORDER. */
+
+struct gdbarch_list *
+gdbarch_list_lookup_by_info (struct gdbarch_list *arches,
+ const struct gdbarch_info *info)
+{
+ for (; arches != NULL; arches = arches->next)
+ {
+ if (info->bfd_arch_info != arches->gdbarch->bfd_arch_info)
+ continue;
+ if (info->byte_order != arches->gdbarch->byte_order)
+ continue;
+ if (info->osabi != arches->gdbarch->osabi)
+ continue;
+ return arches;
+ }
+ return NULL;
+}
+
+
+/* Find an architecture that matches the specified INFO. Create a new
+ architecture if needed. Return that new architecture. Assumes
+ that there is no current architecture. */
+
+static struct gdbarch *
+find_arch_by_info (struct gdbarch *old_gdbarch, struct gdbarch_info info)
+{
+ struct gdbarch *new_gdbarch;
+ struct gdbarch_registration *rego;
+
+ /* The existing architecture has been swapped out - all this code
+ works from a clean slate. */
+ gdb_assert (current_gdbarch == NULL);
+
+ /* Fill in missing parts of the INFO struct using a number of
+ sources: "set ..."; INFOabfd supplied; and the existing
+ architecture. */
+ gdbarch_info_fill (old_gdbarch, &info);
+
+ /* Must have found some sort of architecture. */
+ gdb_assert (info.bfd_arch_info != NULL);
+
+ if (gdbarch_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.bfd_arch_info %s\n",
+ (info.bfd_arch_info != NULL
+ ? info.bfd_arch_info->printable_name
+ : "(null)"));
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.byte_order %d (%s)\n",
+ info.byte_order,
+ (info.byte_order == BFD_ENDIAN_BIG ? "big"
+ : info.byte_order == BFD_ENDIAN_LITTLE ? "little"
+ : "default"));
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.osabi %d (%s)\n",
+ info.osabi, gdbarch_osabi_name (info.osabi));
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.abfd 0x%lx\n",
+ (long) info.abfd);
+ fprintf_unfiltered (gdb_stdlog,
+ "find_arch_by_info: info.tdep_info 0x%lx\n",
+ (long) info.tdep_info);
+ }
+
+ /* Find the tdep code that knows about this architecture. */
+ for (rego = gdbarch_registry;
+ rego != NULL;
+ rego = rego->next)
+ if (rego->bfd_architecture == info.bfd_arch_info->arch)
+ break;
+ if (rego == NULL)
+ {
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "No matching architecture\n");
+ return 0;
+ }
+
+ /* Ask the tdep code for an architecture that matches "info". */
+ new_gdbarch = rego->init (info, rego->arches);
+
+ /* Did the tdep code like it? No. Reject the change and revert to
+ the old architecture. */
+ if (new_gdbarch == NULL)
+ {
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "Target rejected architecture\n");
+ return NULL;
+ }
+
+ /* Is this a pre-existing architecture (as determined by already
+ being initialized)? Move it to the front of the architecture
+ list (keeping the list sorted Most Recently Used). */
+ if (new_gdbarch->initialized_p)
+ {
+ struct gdbarch_list **list;
+ struct gdbarch_list *this;
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "Previous architecture 0x%08lx (%s) selected\n",
+ (long) new_gdbarch,
+ new_gdbarch->bfd_arch_info->printable_name);
+ /* Find the existing arch in the list. */
+ for (list = &rego->arches;
+ (*list) != NULL && (*list)->gdbarch != new_gdbarch;
+ list = &(*list)->next);
+ /* It had better be in the list of architectures. */
+ gdb_assert ((*list) != NULL && (*list)->gdbarch == new_gdbarch);
+ /* Unlink THIS. */
+ this = (*list);
+ (*list) = this->next;
+ /* Insert THIS at the front. */
+ this->next = rego->arches;
+ rego->arches = this;
+ /* Return it. */
+ return new_gdbarch;
+ }
+
+ /* It's a new architecture. */
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "find_arch_by_info: "
+ "New architecture 0x%08lx (%s) selected\n",
+ (long) new_gdbarch,
+ new_gdbarch->bfd_arch_info->printable_name);
+
+ /* Insert the new architecture into the front of the architecture
+ list (keep the list sorted Most Recently Used). */
+ {
+ struct gdbarch_list *this = XMALLOC (struct gdbarch_list);
+ this->next = rego->arches;
+ this->gdbarch = new_gdbarch;
+ rego->arches = this;
+ }
+
+ /* Check that the newly installed architecture is valid. Plug in
+ any post init values. */
+ new_gdbarch->dump_tdep = rego->dump_tdep;
+ verify_gdbarch (new_gdbarch);
+ new_gdbarch->initialized_p = 1;
+
+ /* Initialize any per-architecture swap areas. This phase requires
+ a valid global CURRENT_GDBARCH. Set it momentarially, and then
+ swap the entire architecture out. */
+ current_gdbarch = new_gdbarch;
+ current_gdbarch_swap_init_hack ();
+ current_gdbarch_swap_out_hack ();
+
+ if (gdbarch_debug)
+ gdbarch_dump (new_gdbarch, gdb_stdlog);
+
+ return new_gdbarch;
+}
+
+struct gdbarch *
+gdbarch_find_by_info (struct gdbarch_info info)
+{
+ /* Save the previously selected architecture, setting the global to
+ NULL. This stops things like gdbarch->init() trying to use the
+ previous architecture's configuration. The previous architecture
+ may not even be of the same architecture family. The most recent
+ architecture of the same family is found at the head of the
+ rego->arches list. */
+ struct gdbarch *old_gdbarch = current_gdbarch_swap_out_hack ();
+
+ /* Find the specified architecture. */
+ struct gdbarch *new_gdbarch = find_arch_by_info (old_gdbarch, info);
+
+ /* Restore the existing architecture. */
+ gdb_assert (current_gdbarch == NULL);
+ current_gdbarch_swap_in_hack (old_gdbarch);
+
+ return new_gdbarch;
+}
+
+/* Make the specified architecture current, swapping the existing one
+ out. */
+
+void
+deprecated_current_gdbarch_select_hack (struct gdbarch *new_gdbarch)
+{
+ gdb_assert (new_gdbarch != NULL);
+ gdb_assert (current_gdbarch != NULL);
+ gdb_assert (new_gdbarch->initialized_p);
+ current_gdbarch_swap_out_hack ();
+ current_gdbarch_swap_in_hack (new_gdbarch);
+ architecture_changed_event ();
+}
+
+extern void _initialize_gdbarch (void);
+
+void
+_initialize_gdbarch (void)
+{
+ struct cmd_list_element *c;
+
+ add_show_from_set (add_set_cmd ("arch",
+ class_maintenance,
+ var_zinteger,
+ (char *)&gdbarch_debug,
+ "Set architecture debugging.\\n\\
+When non-zero, architecture debugging is enabled.", &setdebuglist),
+ &showdebuglist);
+ c = add_set_cmd ("archdebug",
+ class_maintenance,
+ var_zinteger,
+ (char *)&gdbarch_debug,
+ "Set architecture debugging.\\n\\
+When non-zero, architecture debugging is enabled.", &setlist);
+
+ deprecate_cmd (c, "set debug arch");
+ deprecate_cmd (add_show_from_set (c, &showlist), "show debug arch");
+}
+EOF
+
+# close things off
+exec 1>&2
+#../move-if-change new-gdbarch.c gdbarch.c
+compare_new gdbarch.c
diff --git a/contrib/gdb/gdb/gdbcmd.h b/contrib/gdb/gdb/gdbcmd.h
new file mode 100644
index 0000000..8c4490e
--- /dev/null
+++ b/contrib/gdb/gdb/gdbcmd.h
@@ -0,0 +1,122 @@
+/* ***DEPRECATED*** The gdblib files must not be calling/using things in any
+ of the possible command languages. If necessary, a hook (that may be
+ present or not) must be used and set to the appropriate routine by any
+ command language that cares about it. If you are having to include this
+ file you are possibly doing things the old way. This file will disapear.
+ fnasser@redhat.com */
+
+/* Header file for GDB-specific command-line stuff.
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999,
+ 2000, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (GDBCMD_H)
+#define GDBCMD_H 1
+
+#include "command.h"
+#include "ui-out.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 toggle subcommands. */
+
+extern struct cmd_list_element *togglelist;
+
+/* Chain containing all defined stop subcommands. */
+
+extern struct cmd_list_element *stoplist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+extern struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+extern struct cmd_list_element *setlist;
+
+/* 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 *setdebuglist;
+
+extern struct cmd_list_element *showdebuglist;
+
+extern struct cmd_list_element *setchecklist;
+
+extern struct cmd_list_element *showchecklist;
+
+extern void execute_command (char *, int);
+
+enum command_control_type execute_control_command (struct command_line *);
+
+extern void print_command_line (struct command_line *, unsigned int,
+ struct ui_file *);
+extern void print_command_lines (struct ui_out *,
+ struct command_line *, unsigned int);
+
+#endif /* !defined (GDBCMD_H) */
diff --git a/contrib/gdb/gdb/gdbcore.h b/contrib/gdb/gdb/gdbcore.h
new file mode 100644
index 0000000..e03ebf4
--- /dev/null
+++ b/contrib/gdb/gdb/gdbcore.h
@@ -0,0 +1,209 @@
+/* Machine independent variables that describe the core file under GDB.
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+struct type;
+
+#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 (int err);
+
+/* Nonzero if there is a core file. */
+
+extern int have_core_file_p (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 (CORE_ADDR memaddr, char *myaddr, unsigned len);
+
+/* Report a memory error with error(). */
+
+extern void memory_error (int status, CORE_ADDR memaddr);
+
+/* Like target_read_memory, but report an error if can't read. */
+
+extern void read_memory (CORE_ADDR memaddr, char *myaddr, int len);
+
+/* Read an integer from debugged memory, given address and number of
+ bytes. */
+
+extern LONGEST read_memory_integer (CORE_ADDR memaddr, int len);
+extern int safe_read_memory_integer (CORE_ADDR memaddr, int len, LONGEST *return_value);
+
+/* Read an unsigned integer from debugged memory, given address and
+ number of bytes. */
+
+extern ULONGEST read_memory_unsigned_integer (CORE_ADDR memaddr, int len);
+
+/* Read a null-terminated string from the debuggee's memory, given address,
+ * a buffer into which to place the string, and the maximum available space */
+
+extern void read_memory_string (CORE_ADDR, char *, int);
+
+/* Read the pointer of type TYPE at ADDR, and return the address it
+ represents. */
+
+CORE_ADDR read_memory_typed_address (CORE_ADDR addr, struct type *type);
+
+/* 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 (CORE_ADDR memaddr, char *myaddr, int len);
+
+/* Store VALUE at ADDR in the inferior as a LEN-byte unsigned integer. */
+extern void write_memory_unsigned_integer (CORE_ADDR addr, int len,
+ ULONGEST value);
+
+/* Store VALUE at ADDR in the inferior as a LEN-byte unsigned integer. */
+extern void write_memory_signed_integer (CORE_ADDR addr, int len,
+ LONGEST value);
+
+extern void generic_search (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) (char *filename);
+
+/* Hook for "file_command", which is more useful than above
+ (because it is invoked AFTER symbols are read, not before) */
+
+extern void (*file_changed_hook) (char *filename);
+
+extern void specify_exec_file_hook (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 (char *filename, int from_tty);
+
+extern void exec_open (char *filename, int from_tty);
+
+extern void exec_file_attach (char *filename, int from_tty);
+
+extern void exec_file_clear (int from_tty);
+
+extern void validate_files (void);
+
+extern CORE_ADDR register_addr (int regno, CORE_ADDR blockend);
+
+#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 (char *);
+
+/* Structure to keep track of core register reading functions for
+ various core file types. */
+
+struct core_fns
+ {
+
+ /* BFD flavour that a core file handler is prepared to read. This
+ can be used by the handler's core tasting function as a first
+ level filter to reject BFD's that don't have the right
+ flavour. */
+
+ enum bfd_flavour core_flavour;
+
+ /* Core file handler function to call to recognize corefile
+ formats that BFD rejects. Some core file format just don't fit
+ into the BFD model, or may require other resources to identify
+ them, that simply aren't available to BFD (such as symbols from
+ another file). Returns nonzero if the handler recognizes the
+ format, zero otherwise. */
+
+ int (*check_format) (bfd *);
+
+ /* Core file handler function to call to ask if it can handle a
+ given core file format or not. Returns zero if it can't,
+ nonzero otherwise. */
+
+ int (*core_sniffer) (struct core_fns *, bfd *);
+
+ /* 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 --- integer registers
+ 2 --- floating-point registers, on machines where they are
+ discontiguous
+ 3 --- extended floating-point registers, on machines where
+ these are present in yet a third area. (GNU/Linux uses
+ this to get at the SSE registers.)
+
+ 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) (char *core_reg_sect,
+ unsigned core_reg_size,
+ int which, CORE_ADDR 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 (struct core_fns *cf);
+extern int default_core_sniffer (struct core_fns *cf, bfd * abfd);
+extern int default_check_format (bfd * abfd);
+
+#endif /* !defined (GDBCORE_H) */
diff --git a/contrib/gdb/gdb/gdbinit.in b/contrib/gdb/gdb/gdbinit.in
new file mode 100644
index 0000000..1a080dc
--- /dev/null
+++ b/contrib/gdb/gdb/gdbinit.in
@@ -0,0 +1,17 @@
+echo Setting up the environment for debugging gdb.\n
+
+set complaints 1
+
+b internal_error
+
+b info_command
+commands
+ silent
+ return
+end
+
+dir @srcdir@/../libiberty
+dir @srcdir@/../bfd
+dir @srcdir@
+dir .
+set prompt (top-gdb)
diff --git a/contrib/gdb/gdb/gdbserver/README b/contrib/gdb/gdb/gdbserver/README
new file mode 100644
index 0000000..71887ca
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/README
@@ -0,0 +1,138 @@
+ 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.
+
+On some targets, gdbserver can also attach to running programs. This is
+accomplished via the --attach argument. The syntax is:
+
+ target> gdbserver COMM --attach PID
+
+PID is the process ID of a currently running process. It isn't necessary
+to point gdbserver at a binary for the running process.
+
+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 gdbserver:
+
+The supported targets as of February 2002 are:
+ arm-*-linux-gnu
+ i386-*-linux-gnu
+ ia64-*-linux-gnu
+ m68k-*-linux-gnu
+ mips-*-linux-gnu
+ powerpc-*-linux-gnu
+ sh-*-linux-gnu
+
+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)).
+
+Building gdbserver for your target is very straightforward. If you build
+GDB natively on a target which gdbserver supports, it will be built
+automatically when you build GDB. You can also build just gdbserver:
+
+ % mkdir obj
+ % cd obj
+ % path-to-gdbserver-sources/configure
+ % make
+
+If you prefer to cross-compile to your target, then you can also build
+gdbserver that way. In a Bourne shell, for example:
+
+ % export CC=your-cross-compiler
+ % path-to-gdbserver-sources/configure your-target-name
+ % make
+
+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 <filename>" 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/acinclude.m4 b/contrib/gdb/gdb/gdbserver/acinclude.m4
new file mode 100644
index 0000000..bbfa86f
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/acinclude.m4
@@ -0,0 +1,41 @@
+dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE.
+sinclude(../../bfd/acinclude.m4)
+
+AC_DEFUN([SRV_CHECK_THREAD_DB],
+[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
+ [old_LIBS="$LIBS"
+ LIBS="$LIBS -lthread_db"
+ AC_TRY_LINK(
+ [void ps_pglobal_lookup() {}
+ void ps_pdread() {}
+ void ps_pdwrite() {}
+ void ps_lgetregs() {}
+ void ps_lsetregs() {}
+ void ps_lgetfpregs() {}
+ void ps_lsetfpregs() {}
+ void ps_getpid() {}],
+ [td_ta_new();],
+ [srv_cv_thread_db="-lthread_db"],
+ [srv_cv_thread_db=no
+
+ if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
+ thread_db="/lib/libthread_db.so.1"
+ else
+ thread_db='$prefix/lib/libthread_db.so.1'
+ fi
+ LIBS="$old_LIBS `eval echo "$thread_db"`"
+ AC_TRY_LINK(
+ [void ps_pglobal_lookup() {}
+ void ps_pdread() {}
+ void ps_pdwrite() {}
+ void ps_lgetregs() {}
+ void ps_lsetregs() {}
+ void ps_lgetfpregs() {}
+ void ps_lsetfpregs() {}
+ void ps_getpid() {}],
+ [td_ta_new();],
+ [srv_cv_thread_db="$thread_db"],
+ [srv_cv_thread_db=no])
+ LIBS="$old_LIBS"
+ ]])
+)])
diff --git a/contrib/gdb/gdb/gdbserver/aclocal.m4 b/contrib/gdb/gdb/gdbserver/aclocal.m4
new file mode 100644
index 0000000..2fc6cf8
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/aclocal.m4
@@ -0,0 +1,54 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4-p4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE.
+sinclude(../../bfd/acinclude.m4)
+
+AC_DEFUN([SRV_CHECK_THREAD_DB],
+[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
+ [old_LIBS="$LIBS"
+ LIBS="$LIBS -lthread_db"
+ AC_TRY_LINK(
+ [void ps_pglobal_lookup() {}
+ void ps_pdread() {}
+ void ps_pdwrite() {}
+ void ps_lgetregs() {}
+ void ps_lsetregs() {}
+ void ps_lgetfpregs() {}
+ void ps_lsetfpregs() {}
+ void ps_getpid() {}],
+ [td_ta_new();],
+ [srv_cv_thread_db="-lthread_db"],
+ [srv_cv_thread_db=no
+
+ if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
+ thread_db="/lib/libthread_db.so.1"
+ else
+ thread_db='$prefix/lib/libthread_db.so.1'
+ fi
+ LIBS="$old_LIBS `eval echo "$thread_db"`"
+ AC_TRY_LINK(
+ [void ps_pglobal_lookup() {}
+ void ps_pdread() {}
+ void ps_pdwrite() {}
+ void ps_lgetregs() {}
+ void ps_lsetregs() {}
+ void ps_lgetfpregs() {}
+ void ps_lsetfpregs() {}
+ void ps_getpid() {}],
+ [td_ta_new();],
+ [srv_cv_thread_db="$thread_db"],
+ [srv_cv_thread_db=no])
+ LIBS="$old_LIBS"
+ ]])
+)])
+
diff --git a/contrib/gdb/gdb/gdbserver/gdbreplay.c b/contrib/gdb/gdb/gdbserver/gdbreplay.c
new file mode 100644
index 0000000..7c9064b
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/gdbreplay.c
@@ -0,0 +1,329 @@
+/* Replay a remote debug session logfile for GDB.
+ Copyright 1996, 1998, 1999, 2000, 2002, 2003 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 "config.h"
+#include <stdio.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* 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. */
+
+static void
+perror_with_name (char *string)
+{
+#ifndef STDC_HEADERS
+ extern int errno;
+#endif
+ const char *err;
+ char *combined;
+
+ err = strerror (errno);
+ if (err == NULL)
+ err = "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 (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);
+}
+
+static void
+remote_close (void)
+{
+ close (remote_desc);
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static void
+remote_open (char *name)
+{
+ 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;
+ 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");
+
+ /* 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, IPPROTO_TCP, 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 (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 (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) */
+
+static void
+expect (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). */
+
+static void
+play (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 (int argc, char *argv[])
+{
+ FILE *fp;
+ int ch;
+
+ if (argc < 3)
+ {
+ fprintf (stderr, "Usage: gdbreplay <logfile> <host:port>\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 0000000..846634b
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/gdbserver.1
@@ -0,0 +1,116 @@
+.\" Copyright 1993 Free Software Foundation, Inc.
+.\" 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... "\|]"
+.PP
+.B gdbserver
+.RB tty
+.B --attach
+.RB PID
+.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.
+
+On some targets, gdbserver can also attach to running programs.
+This is accomplished via the --attach argument. The syntax is:
+
+ target> gdbserver COMM --attach PID
+
+PID is the process ID of a currently running process. It isn't
+necessary to point gdbserver at a binary for the running process.
+
+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/i387-fp.c b/contrib/gdb/gdb/gdbserver/i387-fp.c
new file mode 100644
index 0000000..19a9929
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/i387-fp.c
@@ -0,0 +1,290 @@
+/* i387-specific utility functions, for the remote server for GDB.
+ Copyright 2000, 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "i387-fp.h"
+
+int num_xmm_registers = 8;
+
+/* Note: These functions preserve the reserved bits in control registers.
+ However, gdbserver promptly throws away that information. */
+
+/* These structs should have the proper sizes and alignment on both
+ i386 and x86-64 machines. */
+
+struct i387_fsave {
+ /* All these are only sixteen bits, plus padding, except for fop (which
+ is only eleven bits), and fooff / fioff (which are 32 bits each). */
+ unsigned int fctrl;
+ unsigned int fstat;
+ unsigned int ftag;
+ unsigned int fioff;
+ unsigned short fiseg;
+ unsigned short fop;
+ unsigned int fooff;
+ unsigned int foseg;
+
+ /* Space for eight 80-bit FP values. */
+ char st_space[80];
+};
+
+struct i387_fxsave {
+ /* All these are only sixteen bits, plus padding, except for fop (which
+ is only eleven bits), and fooff / fioff (which are 32 bits each). */
+ unsigned short fctrl;
+ unsigned short fstat;
+ unsigned short ftag;
+ unsigned short fop;
+ unsigned int fioff;
+ unsigned int fiseg;
+ unsigned int fooff;
+ unsigned int foseg;
+
+ unsigned int mxcsr;
+
+ unsigned int _pad1;
+
+ /* Space for eight 80-bit FP values in 128-bit spaces. */
+ char st_space[128];
+
+ /* Space for eight 128-bit XMM values, or 16 on x86-64. */
+ char xmm_space[256];
+};
+
+void
+i387_cache_to_fsave (void *buf)
+{
+ struct i387_fsave *fp = (struct i387_fsave *) buf;
+ int i;
+ int st0_regnum = find_regno ("st0");
+ unsigned long val, val2;
+
+ for (i = 0; i < 8; i++)
+ collect_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 10);
+
+ collect_register_by_name ("fioff", &fp->fioff);
+ collect_register_by_name ("fooff", &fp->fooff);
+
+ /* This one's 11 bits... */
+ collect_register_by_name ("fop", &val2);
+ fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
+
+ /* Some registers are 16-bit. */
+ collect_register_by_name ("fctrl", &val);
+ *(unsigned short *) &fp->fctrl = val;
+
+ collect_register_by_name ("fstat", &val);
+ val &= 0xFFFF;
+ *(unsigned short *) &fp->fstat = val;
+
+ collect_register_by_name ("ftag", &val);
+ val &= 0xFFFF;
+ *(unsigned short *) &fp->ftag = val;
+
+ collect_register_by_name ("fiseg", &val);
+ val &= 0xFFFF;
+ *(unsigned short *) &fp->fiseg = val;
+
+ collect_register_by_name ("foseg", &val);
+ val &= 0xFFFF;
+ *(unsigned short *) &fp->foseg = val;
+}
+
+void
+i387_fsave_to_cache (const void *buf)
+{
+ struct i387_fsave *fp = (struct i387_fsave *) buf;
+ int i;
+ int st0_regnum = find_regno ("st0");
+ unsigned long val;
+
+ for (i = 0; i < 8; i++)
+ supply_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 10);
+
+ supply_register_by_name ("fioff", &fp->fioff);
+ supply_register_by_name ("fooff", &fp->fooff);
+
+ /* Some registers are 16-bit. */
+ val = fp->fctrl & 0xFFFF;
+ supply_register_by_name ("fctrl", &val);
+
+ val = fp->fstat & 0xFFFF;
+ supply_register_by_name ("fstat", &val);
+
+ val = fp->ftag & 0xFFFF;
+ supply_register_by_name ("ftag", &val);
+
+ val = fp->fiseg & 0xFFFF;
+ supply_register_by_name ("fiseg", &val);
+
+ val = fp->foseg & 0xFFFF;
+ supply_register_by_name ("foseg", &val);
+
+ val = (fp->fop) & 0x7FF;
+ supply_register_by_name ("fop", &val);
+}
+
+void
+i387_cache_to_fxsave (void *buf)
+{
+ struct i387_fxsave *fp = (struct i387_fxsave *) buf;
+ int i;
+ int st0_regnum = find_regno ("st0");
+ int xmm0_regnum = find_regno ("xmm0");
+ unsigned long val, val2;
+
+ for (i = 0; i < 8; i++)
+ collect_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16);
+ for (i = 0; i < num_xmm_registers; i++)
+ collect_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16);
+
+ collect_register_by_name ("fioff", &fp->fioff);
+ collect_register_by_name ("fooff", &fp->fooff);
+ collect_register_by_name ("mxcsr", &fp->mxcsr);
+
+ /* This one's 11 bits... */
+ collect_register_by_name ("fop", &val2);
+ fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
+
+ /* Some registers are 16-bit. */
+ collect_register_by_name ("fctrl", &val);
+ *(unsigned short *) &fp->fctrl = val;
+
+ collect_register_by_name ("fstat", &val);
+ val &= 0xFFFF;
+ *(unsigned short *) &fp->fstat = val;
+
+ /* Convert to the simplifed tag form stored in fxsave data. */
+ collect_register_by_name ("ftag", &val);
+ val &= 0xFFFF;
+ for (i = 7; i >= 0; i--)
+ {
+ int tag = (val >> (i * 2)) & 3;
+
+ if (tag != 3)
+ val2 |= (1 << i);
+ }
+ *(unsigned short *) &fp->ftag = val2;
+
+ collect_register_by_name ("fiseg", &val);
+ val &= 0xFFFF;
+ *(unsigned short *) &fp->fiseg = val;
+
+ collect_register_by_name ("foseg", &val);
+ val &= 0xFFFF;
+ *(unsigned short *) &fp->foseg = val;
+}
+
+static int
+i387_ftag (struct i387_fxsave *fp, int regno)
+{
+ unsigned char *raw = &fp->st_space[regno * 16];
+ unsigned int exponent;
+ unsigned long fraction[2];
+ int integer;
+
+ integer = raw[7] & 0x80;
+ exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
+ fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
+ fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
+ | (raw[5] << 8) | raw[4]);
+
+ if (exponent == 0x7fff)
+ {
+ /* Special. */
+ return (2);
+ }
+ else if (exponent == 0x0000)
+ {
+ if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
+ {
+ /* Zero. */
+ return (1);
+ }
+ else
+ {
+ /* Special. */
+ return (2);
+ }
+ }
+ else
+ {
+ if (integer)
+ {
+ /* Valid. */
+ return (0);
+ }
+ else
+ {
+ /* Special. */
+ return (2);
+ }
+ }
+}
+
+void
+i387_fxsave_to_cache (const void *buf)
+{
+ struct i387_fxsave *fp = (struct i387_fxsave *) buf;
+ int i, top;
+ int st0_regnum = find_regno ("st0");
+ int xmm0_regnum = find_regno ("xmm0");
+ unsigned long val;
+
+ for (i = 0; i < 8; i++)
+ supply_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16);
+ for (i = 0; i < num_xmm_registers; i++)
+ supply_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16);
+
+ supply_register_by_name ("fioff", &fp->fioff);
+ supply_register_by_name ("fooff", &fp->fooff);
+ supply_register_by_name ("mxcsr", &fp->mxcsr);
+
+ /* Some registers are 16-bit. */
+ val = fp->fctrl & 0xFFFF;
+ supply_register_by_name ("fctrl", &val);
+
+ val = fp->fstat & 0xFFFF;
+ supply_register_by_name ("fstat", &val);
+
+ /* Generate the form of ftag data that GDB expects. */
+ top = (fp->fstat >> 11) & 0x7;
+ val = 0;
+ for (i = 7; i >= 0; i--)
+ {
+ int tag;
+ if (val & (1 << i))
+ tag = i387_ftag (fp, (i + 8 - top) % 8);
+ else
+ tag = 3;
+ val |= tag << (2 * i);
+ }
+ supply_register_by_name ("ftag", &val);
+
+ val = fp->fiseg & 0xFFFF;
+ supply_register_by_name ("fiseg", &val);
+
+ val = fp->foseg & 0xFFFF;
+ supply_register_by_name ("foseg", &val);
+
+ val = (fp->fop) & 0x7FF;
+ supply_register_by_name ("fop", &val);
+}
diff --git a/contrib/gdb/gdb/gdbserver/i387-fp.h b/contrib/gdb/gdb/gdbserver/i387-fp.h
new file mode 100644
index 0000000..d28c422
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/i387-fp.h
@@ -0,0 +1,33 @@
+/* i387-specific utility functions, for the remote server for GDB.
+ Copyright 2000, 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 I387_FP_H
+#define I387_FP_H
+
+void i387_cache_to_fsave (void *buf);
+void i387_fsave_to_cache (const void *buf);
+
+void i387_cache_to_fxsave (void *buf);
+void i387_fxsave_to_cache (const void *buf);
+
+extern int num_xmm_registers;
+
+#endif /* I387_FP_H */
diff --git a/contrib/gdb/gdb/gdbserver/inferiors.c b/contrib/gdb/gdb/gdbserver/inferiors.c
new file mode 100644
index 0000000..68c91c4
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/inferiors.c
@@ -0,0 +1,199 @@
+/* Inferior process information for the remote server for GDB.
+ Copyright 2002
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stdlib.h>
+
+#include "server.h"
+
+struct thread_info
+{
+ struct inferior_list_entry entry;
+ void *target_data;
+ void *regcache_data;
+};
+
+struct inferior_list all_threads;
+
+struct thread_info *current_inferior;
+
+#define get_thread(inf) ((struct thread_info *)(inf))
+
+void
+add_inferior_to_list (struct inferior_list *list,
+ struct inferior_list_entry *new_inferior)
+{
+ new_inferior->next = NULL;
+ if (list->tail != NULL)
+ list->tail->next = new_inferior;
+ else
+ list->head = new_inferior;
+ list->tail = new_inferior;
+}
+
+void
+for_each_inferior (struct inferior_list *list,
+ void (*action) (struct inferior_list_entry *))
+{
+ struct inferior_list_entry *cur = list->head, *next;
+
+ while (cur != NULL)
+ {
+ next = cur->next;
+ (*action) (cur);
+ cur = next;
+ }
+}
+
+void
+change_inferior_id (struct inferior_list *list,
+ int new_id)
+{
+ if (list->head != list->tail)
+ error ("tried to change thread ID after multiple threads are created");
+
+ list->head->id = new_id;
+}
+
+void
+remove_inferior (struct inferior_list *list,
+ struct inferior_list_entry *entry)
+{
+ struct inferior_list_entry **cur;
+
+ if (list->head == entry)
+ {
+ list->head = entry->next;
+ if (list->tail == entry)
+ list->tail = list->head;
+ return;
+ }
+
+ cur = &list->head;
+ while (*cur && (*cur)->next != entry)
+ cur = &(*cur)->next;
+
+ if (*cur == NULL)
+ return;
+
+ (*cur)->next = entry->next;
+
+ if (list->tail == entry)
+ list->tail = *cur;
+}
+
+void
+add_thread (int thread_id, void *target_data)
+{
+ struct thread_info *new_thread
+ = (struct thread_info *) malloc (sizeof (*new_thread));
+
+ memset (new_thread, 0, sizeof (*new_thread));
+
+ new_thread->entry.id = thread_id;
+
+ add_inferior_to_list (&all_threads, & new_thread->entry);
+
+ if (current_inferior == NULL)
+ current_inferior = new_thread;
+
+ new_thread->target_data = target_data;
+ set_inferior_regcache_data (new_thread, new_register_cache ());
+}
+
+static void
+free_one_thread (struct inferior_list_entry *inf)
+{
+ struct thread_info *thread = get_thread (inf);
+ free_register_cache (inferior_regcache_data (thread));
+ free (thread);
+}
+
+void
+remove_thread (struct thread_info *thread)
+{
+ remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
+ free_one_thread (&thread->entry);
+}
+
+void
+clear_inferiors (void)
+{
+ for_each_inferior (&all_threads, free_one_thread);
+
+ all_threads.head = all_threads.tail = NULL;
+}
+
+struct inferior_list_entry *
+find_inferior (struct inferior_list *list,
+ int (*func) (struct inferior_list_entry *, void *), void *arg)
+{
+ struct inferior_list_entry *inf = list->head;
+
+ while (inf != NULL)
+ {
+ if ((*func) (inf, arg))
+ return inf;
+ inf = inf->next;
+ }
+
+ return NULL;
+}
+
+struct inferior_list_entry *
+find_inferior_id (struct inferior_list *list, int id)
+{
+ struct inferior_list_entry *inf = list->head;
+
+ while (inf != NULL)
+ {
+ if (inf->id == id)
+ return inf;
+ inf = inf->next;
+ }
+
+ return NULL;
+}
+
+void *
+inferior_target_data (struct thread_info *inferior)
+{
+ return inferior->target_data;
+}
+
+void
+set_inferior_target_data (struct thread_info *inferior, void *data)
+{
+ inferior->target_data = data;
+}
+
+void *
+inferior_regcache_data (struct thread_info *inferior)
+{
+ return inferior->regcache_data;
+}
+
+void
+set_inferior_regcache_data (struct thread_info *inferior, void *data)
+{
+ inferior->regcache_data = data;
+}
diff --git a/contrib/gdb/gdb/gdbserver/mem-break.c b/contrib/gdb/gdb/gdbserver/mem-break.c
new file mode 100644
index 0000000..977b0e3
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/mem-break.c
@@ -0,0 +1,278 @@
+/* Memory breakpoint operations for the remote server for GDB.
+ Copyright 2002
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+const char *breakpoint_data;
+int breakpoint_len;
+
+#define MAX_BREAKPOINT_LEN 8
+
+struct breakpoint
+{
+ struct breakpoint *next;
+ CORE_ADDR pc;
+ unsigned char old_data[MAX_BREAKPOINT_LEN];
+
+ /* Non-zero iff we are stepping over this breakpoint. */
+ int reinserting;
+
+ /* Non-NULL iff this breakpoint was inserted to step over
+ another one. Points to the other breakpoint (which is also
+ in the *next chain somewhere). */
+ struct breakpoint *breakpoint_to_reinsert;
+
+ /* Function to call when we hit this breakpoint. */
+ void (*handler) (CORE_ADDR);
+};
+
+struct breakpoint *breakpoints;
+
+void
+set_breakpoint_at (CORE_ADDR where, void (*handler) (CORE_ADDR))
+{
+ struct breakpoint *bp;
+
+ if (breakpoint_data == NULL)
+ error ("Target does not support breakpoints.");
+
+ bp = malloc (sizeof (struct breakpoint));
+ memset (bp, 0, sizeof (struct breakpoint));
+
+ (*the_target->read_memory) (where, bp->old_data,
+ breakpoint_len);
+ (*the_target->write_memory) (where, breakpoint_data,
+ breakpoint_len);
+
+ bp->pc = where;
+ bp->handler = handler;
+
+ bp->next = breakpoints;
+ breakpoints = bp;
+}
+
+static void
+delete_breakpoint (struct breakpoint *bp)
+{
+ struct breakpoint *cur;
+
+ if (breakpoints == bp)
+ {
+ breakpoints = bp->next;
+ (*the_target->write_memory) (bp->pc, bp->old_data,
+ breakpoint_len);
+ free (bp);
+ return;
+ }
+ cur = breakpoints;
+ while (cur->next)
+ {
+ if (cur->next == bp)
+ {
+ cur->next = bp->next;
+ (*the_target->write_memory) (bp->pc, bp->old_data,
+ breakpoint_len);
+ free (bp);
+ return;
+ }
+ }
+ warning ("Could not find breakpoint in list.");
+}
+
+static struct breakpoint *
+find_breakpoint_at (CORE_ADDR where)
+{
+ struct breakpoint *bp = breakpoints;
+
+ while (bp != NULL)
+ {
+ if (bp->pc == where)
+ return bp;
+ bp = bp->next;
+ }
+
+ return NULL;
+}
+
+static void
+reinsert_breakpoint_handler (CORE_ADDR stop_pc)
+{
+ struct breakpoint *stop_bp, *orig_bp;
+
+ stop_bp = find_breakpoint_at (stop_pc);
+ if (stop_bp == NULL)
+ error ("lost the stopping breakpoint.");
+
+ orig_bp = stop_bp->breakpoint_to_reinsert;
+ if (orig_bp == NULL)
+ error ("no breakpoint to reinsert");
+
+ (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
+ breakpoint_len);
+ orig_bp->reinserting = 0;
+ delete_breakpoint (stop_bp);
+}
+
+void
+reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
+{
+ struct breakpoint *bp, *orig_bp;
+
+ set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
+
+ orig_bp = find_breakpoint_at (stop_pc);
+ if (orig_bp == NULL)
+ error ("Could not find original breakpoint in list.");
+
+ bp = find_breakpoint_at (stop_at);
+ if (bp == NULL)
+ error ("Could not find breakpoint in list (reinserting by breakpoint).");
+ bp->breakpoint_to_reinsert = orig_bp;
+
+ (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
+ breakpoint_len);
+ orig_bp->reinserting = 1;
+}
+
+void
+uninsert_breakpoint (CORE_ADDR stopped_at)
+{
+ struct breakpoint *bp;
+
+ bp = find_breakpoint_at (stopped_at);
+ if (bp == NULL)
+ error ("Could not find breakpoint in list (uninserting).");
+
+ (*the_target->write_memory) (bp->pc, bp->old_data,
+ breakpoint_len);
+ bp->reinserting = 1;
+}
+
+void
+reinsert_breakpoint (CORE_ADDR stopped_at)
+{
+ struct breakpoint *bp;
+
+ bp = find_breakpoint_at (stopped_at);
+ if (bp == NULL)
+ error ("Could not find breakpoint in list (uninserting).");
+ if (! bp->reinserting)
+ error ("Breakpoint already inserted at reinsert time.");
+
+ (*the_target->write_memory) (bp->pc, breakpoint_data,
+ breakpoint_len);
+ bp->reinserting = 0;
+}
+
+int
+check_breakpoints (CORE_ADDR stop_pc)
+{
+ struct breakpoint *bp;
+
+ bp = find_breakpoint_at (stop_pc);
+ if (bp == NULL)
+ return 0;
+ if (bp->reinserting)
+ {
+ warning ("Hit a removed breakpoint?");
+ return 0;
+ }
+
+ (*bp->handler) (bp->pc);
+ return 1;
+}
+
+void
+set_breakpoint_data (const char *bp_data, int bp_len)
+{
+ breakpoint_data = bp_data;
+ breakpoint_len = bp_len;
+}
+
+void
+check_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len)
+{
+ struct breakpoint *bp = breakpoints;
+ CORE_ADDR mem_end = mem_addr + mem_len;
+
+ for (; bp != NULL; bp = bp->next)
+ {
+ CORE_ADDR bp_end = bp->pc + breakpoint_len;
+ CORE_ADDR start, end;
+ int copy_offset, copy_len, buf_offset;
+
+ if (mem_addr >= bp_end)
+ continue;
+ if (bp->pc >= mem_end)
+ continue;
+
+ start = bp->pc;
+ if (mem_addr > start)
+ start = mem_addr;
+
+ end = bp_end;
+ if (end > mem_end)
+ end = mem_end;
+
+ copy_len = end - start;
+ copy_offset = start - bp->pc;
+ buf_offset = start - mem_addr;
+
+ memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
+ }
+}
+
+void
+check_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len)
+{
+ struct breakpoint *bp = breakpoints;
+ CORE_ADDR mem_end = mem_addr + mem_len;
+
+ for (; bp != NULL; bp = bp->next)
+ {
+ CORE_ADDR bp_end = bp->pc + breakpoint_len;
+ CORE_ADDR start, end;
+ int copy_offset, copy_len, buf_offset;
+
+ if (mem_addr >= bp_end)
+ continue;
+ if (bp->pc >= mem_end)
+ continue;
+
+ start = bp->pc;
+ if (mem_addr > start)
+ start = mem_addr;
+
+ end = bp_end;
+ if (end > mem_end)
+ end = mem_end;
+
+ copy_len = end - start;
+ copy_offset = start - bp->pc;
+ buf_offset = start - mem_addr;
+
+ memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
+ if (bp->reinserting == 0)
+ memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
+ }
+}
diff --git a/contrib/gdb/gdb/gdbserver/mem-break.h b/contrib/gdb/gdb/gdbserver/mem-break.h
new file mode 100644
index 0000000..356e763
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/mem-break.h
@@ -0,0 +1,71 @@
+/* Memory breakpoint interfaces for the remote server for GDB.
+ Copyright 2002
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MEM_BREAK_H
+#define MEM_BREAK_H
+
+/* Breakpoints are opaque. */
+
+/* Create a new breakpoint at WHERE, and call HANDLER when
+ it is hit. */
+
+void set_breakpoint_at (CORE_ADDR where,
+ void (*handler) (CORE_ADDR));
+
+/* Create a reinsertion breakpoint at STOP_AT for the breakpoint
+ currently at STOP_PC (and temporarily remove the breakpoint at
+ STOP_PC). */
+
+void reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at);
+
+/* Change the status of the breakpoint at WHERE to inserted. */
+
+void reinsert_breakpoint (CORE_ADDR where);
+
+/* Change the status of the breakpoint at WHERE to uninserted. */
+
+void uninsert_breakpoint (CORE_ADDR where);
+
+/* See if any breakpoint claims ownership of STOP_PC. Call the handler for
+ the breakpoint, if found. */
+
+int check_breakpoints (CORE_ADDR stop_pc);
+
+/* See if any breakpoints shadow the target memory area from MEM_ADDR
+ to MEM_ADDR + MEM_LEN. Update the data already read from the target
+ (in BUF) if necessary. */
+
+void check_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len);
+
+/* See if any breakpoints shadow the target memory area from MEM_ADDR
+ to MEM_ADDR + MEM_LEN. Update the data to be written to the target
+ (in BUF) if necessary, as well as the original data for any breakpoints. */
+
+void check_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len);
+
+/* Set the byte pattern to insert for memory breakpoints. This function
+ must be called before any breakpoints are set. */
+
+void set_breakpoint_data (const char *bp_data, int bp_len);
+
+#endif /* MEM_BREAK_H */
diff --git a/contrib/gdb/gdb/gdbserver/proc-service.c b/contrib/gdb/gdb/gdbserver/proc-service.c
new file mode 100644
index 0000000..becf565
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/proc-service.c
@@ -0,0 +1,256 @@
+/* libthread_db helper functions for the remote server for GDB.
+ Copyright 2002
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+/* This file is currently tied to GNU/Linux. It should scale well to
+ another libthread_db implementation, with the approriate gdbserver
+ hooks, but for now this means we can use GNU/Linux's target data. */
+
+#include "linux-low.h"
+
+/* Correct for all GNU/Linux targets (for quite some time). */
+#define GDB_GREGSET_T elf_gregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
+
+#ifndef HAVE_ELF_FPREGSET_T
+/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
+ via <sys/procfs.h>. */
+#ifdef HAVE_LINUX_ELF_H
+#include <linux/elf.h>
+#endif
+#endif
+
+#include "../gdb_proc_service.h"
+
+typedef struct ps_prochandle *gdb_ps_prochandle_t;
+typedef void *gdb_ps_read_buf_t;
+typedef const void *gdb_ps_write_buf_t;
+typedef size_t gdb_ps_size_t;
+
+/* FIXME redo this right */
+#if 0
+#ifndef HAVE_LINUX_REGSETS
+#error HAVE_LINUX_REGSETS required!
+#else
+static struct regset_info *
+gregset_info(void)
+{
+ int i = 0;
+
+ while (target_regsets[i].size != -1)
+ {
+ if (target_regsets[i].type == GENERAL_REGS)
+ break;
+ i++;
+ }
+
+ return &target_regsets[i];
+}
+
+static struct regset_info *
+fpregset_info(void)
+{
+ int i = 0;
+
+ while (target_regsets[i].size != -1)
+ {
+ if (target_regsets[i].type == FP_REGS)
+ break;
+ i++;
+ }
+
+ return &target_regsets[i];
+}
+#endif
+#endif
+
+/* Search for the symbol named NAME within the object named OBJ within
+ the target process PH. If the symbol is found the address of the
+ symbol is stored in SYM_ADDR. */
+
+ps_err_e
+ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
+ const char *name, paddr_t *sym_addr)
+{
+ CORE_ADDR addr;
+
+ if (look_up_one_symbol (name, &addr) == 0)
+ return PS_NOSYM;
+
+ *sym_addr = (paddr_t) (unsigned long) addr;
+ return PS_OK;
+}
+
+/* Read SIZE bytes from the target process PH at address ADDR and copy
+ them into BUF. */
+
+ps_err_e
+ps_pdread (gdb_ps_prochandle_t ph, paddr_t addr,
+ gdb_ps_read_buf_t buf, gdb_ps_size_t size)
+{
+ read_inferior_memory (addr, buf, size);
+ return PS_OK;
+}
+
+/* Write SIZE bytes from BUF into the target process PH at address ADDR. */
+
+ps_err_e
+ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr,
+ gdb_ps_write_buf_t buf, gdb_ps_size_t size)
+{
+ return write_inferior_memory (addr, buf, size);
+}
+
+/* Get the general registers of LWP LWPID within the target process PH
+ and store them in GREGSET. */
+
+ps_err_e
+ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
+{
+#if 0
+ struct thread_info *reg_inferior, *save_inferior;
+ void *regcache;
+
+ reg_inferior = (struct thread_info *) find_inferior_id (&all_threads,
+ lwpid);
+ if (reg_inferior == NULL)
+ return PS_ERR;
+
+ save_inferior = current_inferior;
+ current_inferior = reg_inferior;
+
+ regcache = new_register_cache ();
+ the_target->fetch_registers (0, regcache);
+ gregset_info()->fill_function (gregset, regcache);
+ free_register_cache (regcache);
+
+ current_inferior = save_inferior;
+ return PS_OK;
+#endif
+ /* FIXME */
+ return PS_ERR;
+}
+
+/* Set the general registers of LWP LWPID within the target process PH
+ from GREGSET. */
+
+ps_err_e
+ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset)
+{
+#if 0
+ struct thread_info *reg_inferior, *save_inferior;
+ void *regcache;
+
+ reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+ if (reg_inferior == NULL)
+ return PS_ERR;
+
+ save_inferior = current_inferior;
+ current_inferior = reg_inferior;
+
+ regcache = new_register_cache ();
+ gregset_info()->store_function (gregset, regcache);
+ the_target->store_registers (0, regcache);
+ free_register_cache (regcache);
+
+ current_inferior = save_inferior;
+
+ return PS_OK;
+#endif
+ /* FIXME */
+ return PS_ERR;
+}
+
+/* Get the floating-point registers of LWP LWPID within the target
+ process PH and store them in FPREGSET. */
+
+ps_err_e
+ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ gdb_prfpregset_t *fpregset)
+{
+#if 0
+ struct thread_info *reg_inferior, *save_inferior;
+ void *regcache;
+
+ reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+ if (reg_inferior == NULL)
+ return PS_ERR;
+
+ save_inferior = current_inferior;
+ current_inferior = reg_inferior;
+
+ regcache = new_register_cache ();
+ the_target->fetch_registers (0, regcache);
+ fpregset_info()->fill_function (fpregset, regcache);
+ free_register_cache (regcache);
+
+ current_inferior = save_inferior;
+
+ return PS_OK;
+#endif
+ /* FIXME */
+ return PS_ERR;
+}
+
+/* Set the floating-point registers of LWP LWPID within the target
+ process PH from FPREGSET. */
+
+ps_err_e
+ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ const gdb_prfpregset_t *fpregset)
+{
+#if 0
+ struct thread_info *reg_inferior, *save_inferior;
+ void *regcache;
+
+ reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+ if (reg_inferior == NULL)
+ return PS_ERR;
+
+ save_inferior = current_inferior;
+ current_inferior = reg_inferior;
+
+ regcache = new_register_cache ();
+ fpregset_info()->store_function (fpregset, regcache);
+ the_target->store_registers (0, regcache);
+ free_register_cache (regcache);
+
+ current_inferior = save_inferior;
+
+ return PS_OK;
+#endif
+ /* FIXME */
+ return PS_ERR;
+}
+
+/* Return overall process id of the target PH. Special for GNU/Linux
+ -- not used on Solaris. */
+
+pid_t
+ps_getpid (gdb_ps_prochandle_t ph)
+{
+ return ph->pid;
+}
+
+
diff --git a/contrib/gdb/gdb/gdbserver/regcache.c b/contrib/gdb/gdb/gdbserver/regcache.c
new file mode 100644
index 0000000..bc64ebc
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/regcache.c
@@ -0,0 +1,239 @@
+/* Register support routines for the remote server for GDB.
+ Copyright 2001, 2002, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regdef.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* The private data for the register cache. Note that we have one
+ per inferior; this is primarily for simplicity, as the performance
+ benefit is minimal. */
+
+struct inferior_regcache_data
+{
+ int registers_valid;
+ char *registers;
+};
+
+static int register_bytes;
+
+static struct reg *reg_defs;
+static int num_registers;
+
+const char **gdbserver_expedite_regs;
+
+static struct inferior_regcache_data *
+get_regcache (struct thread_info *inf, int fetch)
+{
+ struct inferior_regcache_data *regcache;
+
+ regcache = (struct inferior_regcache_data *) inferior_regcache_data (inf);
+
+ if (regcache == NULL)
+ fatal ("no register cache");
+
+ /* FIXME - fetch registers for INF */
+ if (fetch && regcache->registers_valid == 0)
+ {
+ fetch_inferior_registers (0);
+ regcache->registers_valid = 1;
+ }
+
+ return regcache;
+}
+
+void
+regcache_invalidate_one (struct inferior_list_entry *entry)
+{
+ struct thread_info *thread = (struct thread_info *) entry;
+ struct inferior_regcache_data *regcache;
+
+ regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
+
+ if (regcache->registers_valid)
+ {
+ struct thread_info *saved_inferior = current_inferior;
+
+ current_inferior = thread;
+ store_inferior_registers (-1);
+ current_inferior = saved_inferior;
+ }
+
+ regcache->registers_valid = 0;
+}
+
+void
+regcache_invalidate ()
+{
+ for_each_inferior (&all_threads, regcache_invalidate_one);
+}
+
+int
+registers_length (void)
+{
+ return 2 * register_bytes;
+}
+
+void *
+new_register_cache (void)
+{
+ struct inferior_regcache_data *regcache;
+
+ regcache = malloc (sizeof (*regcache));
+
+ /* Make sure to zero-initialize the register cache when it is created,
+ in case there are registers the target never fetches. This way they'll
+ read as zero instead of garbage. */
+ regcache->registers = calloc (1, register_bytes);
+ if (regcache->registers == NULL)
+ fatal ("Could not allocate register cache.");
+
+ regcache->registers_valid = 0;
+
+ return regcache;
+}
+
+void
+free_register_cache (void *regcache_p)
+{
+ struct inferior_regcache_data *regcache
+ = (struct inferior_regcache_data *) regcache_p;
+
+ free (regcache->registers);
+ free (regcache);
+}
+
+void
+set_register_cache (struct reg *regs, int n)
+{
+ int offset, i;
+
+ reg_defs = regs;
+ num_registers = n;
+
+ offset = 0;
+ for (i = 0; i < n; i++)
+ {
+ regs[i].offset = offset;
+ offset += regs[i].size;
+ }
+
+ register_bytes = offset / 8;
+}
+
+void
+registers_to_string (char *buf)
+{
+ char *registers = get_regcache (current_inferior, 1)->registers;
+
+ convert_int_to_ascii (registers, buf, register_bytes);
+}
+
+void
+registers_from_string (char *buf)
+{
+ int len = strlen (buf);
+ char *registers = get_regcache (current_inferior, 1)->registers;
+
+ if (len != register_bytes * 2)
+ {
+ warning ("Wrong sized register packet (expected %d bytes, got %d)", 2*register_bytes, len);
+ if (len > register_bytes * 2)
+ len = register_bytes * 2;
+ }
+ convert_ascii_to_int (buf, registers, len / 2);
+}
+
+struct reg *
+find_register_by_name (const char *name)
+{
+ int i;
+
+ for (i = 0; i < num_registers; i++)
+ if (!strcmp (name, reg_defs[i].name))
+ return &reg_defs[i];
+ fatal ("Unknown register %s requested", name);
+ return 0;
+}
+
+int
+find_regno (const char *name)
+{
+ int i;
+
+ for (i = 0; i < num_registers; i++)
+ if (!strcmp (name, reg_defs[i].name))
+ return i;
+ fatal ("Unknown register %s requested", name);
+ return -1;
+}
+
+struct reg *
+find_register_by_number (int n)
+{
+ return &reg_defs[n];
+}
+
+int
+register_size (int n)
+{
+ return reg_defs[n].size / 8;
+}
+
+static char *
+register_data (int n, int fetch)
+{
+ char *registers = get_regcache (current_inferior, fetch)->registers;
+
+ return registers + (reg_defs[n].offset / 8);
+}
+
+void
+supply_register (int n, const void *buf)
+{
+ memcpy (register_data (n, 0), buf, register_size (n));
+}
+
+void
+supply_register_by_name (const char *name, const void *buf)
+{
+ supply_register (find_regno (name), buf);
+}
+
+void
+collect_register (int n, void *buf)
+{
+ memcpy (buf, register_data (n, 1), register_size (n));
+}
+
+void
+collect_register_as_string (int n, char *buf)
+{
+ convert_int_to_ascii (register_data (n, 1), buf, register_size (n));
+}
+
+void
+collect_register_by_name (const char *name, void *buf)
+{
+ collect_register (find_regno (name), buf);
+}
diff --git a/contrib/gdb/gdb/gdbserver/regcache.h b/contrib/gdb/gdb/gdbserver/regcache.h
new file mode 100644
index 0000000..930bd9c
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/regcache.h
@@ -0,0 +1,72 @@
+/* Register support routines for the remote server for GDB.
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 REGCACHE_H
+#define REGCACHE_H
+
+struct inferior_list_entry;
+
+/* Create a new register cache for INFERIOR. */
+
+void *new_register_cache (void);
+
+/* Release all memory associated with the register cache for INFERIOR. */
+
+void free_register_cache (void *regcache);
+
+/* Invalidate cached registers for one or all threads. */
+
+void regcache_invalidate_one (struct inferior_list_entry *);
+void regcache_invalidate (void);
+
+/* Convert all registers to a string in the currently specified remote
+ format. */
+
+void registers_to_string (char *buf);
+
+/* Convert a string to register values and fill our register cache. */
+
+void registers_from_string (char *buf);
+
+/* Return the size in bytes of a string-encoded register packet. */
+
+int registers_length (void);
+
+/* Return a pointer to the description of register ``n''. */
+
+struct reg *find_register_by_number (int n);
+
+int register_size (int n);
+
+int find_regno (const char *name);
+
+extern const char **gdbserver_expedite_regs;
+
+void supply_register (int n, const void *buf);
+
+void supply_register_by_name (const char *name, const void *buf);
+
+void collect_register (int n, void *buf);
+
+void collect_register_as_string (int n, char *buf);
+
+void collect_register_by_name (const char *name, void *buf);
+
+#endif /* REGCACHE_H */
diff --git a/contrib/gdb/gdb/gdbserver/remote-utils.c b/contrib/gdb/gdb/gdbserver/remote-utils.c
new file mode 100644
index 0000000..26b267a
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/remote-utils.c
@@ -0,0 +1,736 @@
+/* Remote utility routines for the remote server for GDB.
+ Copyright 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "terminal.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+int remote_debug = 0;
+struct ui_file *gdb_stdlog;
+
+static int remote_desc;
+
+/* FIXME headerize? */
+extern int using_threads;
+extern int debug_threads;
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+void
+remote_open (char *name)
+{
+ int save_fcntl_flags;
+
+ if (!strchr (name, ':'))
+ {
+ remote_desc = open (name, O_RDWR);
+ if (remote_desc < 0)
+ perror_with_name ("Could not open remote device");
+
+#ifdef HAVE_TERMIOS
+ {
+ struct termios termios;
+ tcgetattr (remote_desc, &termios);
+
+ termios.c_iflag = 0;
+ termios.c_oflag = 0;
+ termios.c_lflag = 0;
+ termios.c_cflag &= ~(CSIZE | PARENB);
+ termios.c_cflag |= CLOCAL | CS8;
+ termios.c_cc[VMIN] = 1;
+ termios.c_cc[VTIME] = 0;
+
+ tcsetattr (remote_desc, TCSANOW, &termios);
+ }
+#endif
+
+#ifdef HAVE_TERMIO
+ {
+ struct termio termio;
+ ioctl (remote_desc, TCGETA, &termio);
+
+ termio.c_iflag = 0;
+ termio.c_oflag = 0;
+ termio.c_lflag = 0;
+ termio.c_cflag &= ~(CSIZE | PARENB);
+ termio.c_cflag |= CLOCAL | CS8;
+ termio.c_cc[VMIN] = 1;
+ termio.c_cc[VTIME] = 0;
+
+ ioctl (remote_desc, TCSETA, &termio);
+ }
+#endif
+
+#ifdef HAVE_SGTTY
+ {
+ struct sgttyb sg;
+
+ ioctl (remote_desc, TIOCGETP, &sg);
+ sg.sg_flags = RAW;
+ ioctl (remote_desc, TIOCSETP, &sg);
+ }
+#endif
+
+ fprintf (stderr, "Remote debugging using %s\n", name);
+ }
+ else
+ {
+ char *port_str;
+ int port;
+ struct sockaddr_in sockaddr;
+ int tmp;
+ 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");
+
+ fprintf (stderr, "Listening on port %d\n", port);
+
+ tmp = sizeof (sockaddr);
+ remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
+ if (remote_desc == -1)
+ perror_with_name ("Accept failed");
+
+ /* 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, IPPROTO_TCP, 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. */
+
+ /* Convert IP address to string. */
+ fprintf (stderr, "Remote debugging from host %s\n",
+ inet_ntoa (sockaddr.sin_addr));
+ }
+
+#if defined(F_SETFL) && defined (FASYNC)
+ save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0);
+ fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC);
+#if defined (F_SETOWN)
+ fcntl (remote_desc, F_SETOWN, getpid ());
+#endif
+#endif
+ disable_async_io ();
+}
+
+void
+remote_close (void)
+{
+ close (remote_desc);
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (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");
+ return 0;
+}
+
+int
+unhexify (char *bin, const char *hex, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ if (hex[0] == 0 || hex[1] == 0)
+ {
+ /* Hex string is short, or of uneven length.
+ Return the count that has been converted so far. */
+ return i;
+ }
+ *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
+ hex += 2;
+ }
+ return i;
+}
+
+static void
+decode_address (CORE_ADDR *addrp, const char *start, int len)
+{
+ CORE_ADDR addr;
+ char ch;
+ int i;
+
+ addr = 0;
+ for (i = 0; i < len; i++)
+ {
+ ch = start[i];
+ addr = addr << 4;
+ addr = addr | (fromhex (ch) & 0x0f);
+ }
+ *addrp = addr;
+}
+
+/* Convert number NIB to a hex digit. */
+
+static int
+tohex (int nib)
+{
+ if (nib < 10)
+ return '0' + nib;
+ else
+ return 'a' + nib - 10;
+}
+
+int
+hexify (char *hex, const char *bin, int count)
+{
+ int i;
+
+ /* May use a length, or a nul-terminated string as input. */
+ if (count == 0)
+ count = strlen (bin);
+
+ for (i = 0; i < count; i++)
+ {
+ *hex++ = tohex ((*bin >> 4) & 0xf);
+ *hex++ = tohex (*bin++ & 0xf);
+ }
+ *hex = 0;
+ return i;
+}
+
+/* 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 (char *buf)
+{
+ int i;
+ unsigned char csum = 0;
+ char *buf2;
+ char buf3[1];
+ int cnt = strlen (buf);
+ char *p;
+
+ buf2 = malloc (PBUFSIZ);
+
+ /* 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);
+
+ *p = '\0';
+
+ /* 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;
+ }
+
+ if (remote_debug)
+ {
+ fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
+ fflush (stderr);
+ }
+ cc = read (remote_desc, buf3, 1);
+ if (remote_debug)
+ {
+ fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
+ fflush (stderr);
+ }
+
+ if (cc <= 0)
+ {
+ if (cc == 0)
+ fprintf (stderr, "putpkt(read): Got EOF\n");
+ else
+ perror ("putpkt(read)");
+
+ free (buf2);
+ return -1;
+ }
+
+ /* Check for an input interrupt while we're here. */
+ if (buf3[0] == '\003')
+ (*the_target->send_signal) (SIGINT);
+ }
+ while (buf3[0] != '+');
+
+ free (buf2);
+ 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 unused)
+{
+ fd_set readset;
+ struct timeval immediate = { 0, 0 };
+
+ /* Protect against spurious interrupts. This has been observed to
+ be a problem under NetBSD 1.4 and 1.5. */
+
+ FD_ZERO (&readset);
+ FD_SET (remote_desc, &readset);
+ if (select (remote_desc + 1, &readset, 0, 0, &immediate) > 0)
+ {
+ 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;
+ }
+
+ (*the_target->send_signal) (SIGINT);
+ }
+}
+
+void
+block_async_io (void)
+{
+ sigset_t sigio_set;
+ sigemptyset (&sigio_set);
+ sigaddset (&sigio_set, SIGIO);
+ sigprocmask (SIG_BLOCK, &sigio_set, NULL);
+}
+
+void
+unblock_async_io (void)
+{
+ sigset_t sigio_set;
+ sigemptyset (&sigio_set);
+ sigaddset (&sigio_set, SIGIO);
+ sigprocmask (SIG_UNBLOCK, &sigio_set, NULL);
+}
+
+void
+enable_async_io (void)
+{
+ signal (SIGIO, input_interrupt);
+}
+
+void
+disable_async_io (void)
+{
+ signal (SIGIO, SIG_IGN);
+}
+
+/* Returns next char from remote GDB. -1 if error. */
+
+static int
+readchar (void)
+{
+ 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 (char *buf)
+{
+ char *bp;
+ unsigned char csum, c1, c2;
+ int c;
+
+ while (1)
+ {
+ csum = 0;
+
+ while (1)
+ {
+ c = readchar ();
+ if (c == '$')
+ break;
+ if (remote_debug)
+ {
+ fprintf (stderr, "[getpkt: discarding char '%c']\n", c);
+ fflush (stderr);
+ }
+
+ 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);
+ }
+
+ if (remote_debug)
+ {
+ fprintf (stderr, "getpkt (\"%s\"); [sending ack] \n", buf);
+ fflush (stderr);
+ }
+
+ write (remote_desc, "+", 1);
+
+ if (remote_debug)
+ {
+ fprintf (stderr, "[sent ack]\n");
+ fflush (stderr);
+ }
+
+ return bp - buf;
+}
+
+void
+write_ok (char *buf)
+{
+ buf[0] = 'O';
+ buf[1] = 'K';
+ buf[2] = '\0';
+}
+
+void
+write_enn (char *buf)
+{
+ /* Some day, we should define the meanings of the error codes... */
+ buf[0] = 'E';
+ buf[1] = '0';
+ buf[2] = '1';
+ buf[3] = '\0';
+}
+
+void
+convert_int_to_ascii (char *from, char *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 (char *from, char *to, int n)
+{
+ int nib1, nib2;
+ while (n--)
+ {
+ nib1 = fromhex (*from++);
+ nib2 = fromhex (*from++);
+ *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f);
+ }
+}
+
+static char *
+outreg (int regno, char *buf)
+{
+ if ((regno >> 12) != 0)
+ *buf++ = tohex ((regno >> 12) & 0xf);
+ if ((regno >> 8) != 0)
+ *buf++ = tohex ((regno >> 8) & 0xf);
+ *buf++ = tohex ((regno >> 4) & 0xf);
+ *buf++ = tohex (regno & 0xf);
+ *buf++ = ':';
+ collect_register_as_string (regno, buf);
+ buf += 2 * register_size (regno);
+ *buf++ = ';';
+
+ return buf;
+}
+
+void
+new_thread_notify (int id)
+{
+ char own_buf[256];
+
+ /* The `n' response is not yet part of the remote protocol. Do nothing. */
+ if (1)
+ return;
+
+ if (server_waiting == 0)
+ return;
+
+ sprintf (own_buf, "n%x", id);
+ disable_async_io ();
+ putpkt (own_buf);
+ enable_async_io ();
+}
+
+void
+dead_thread_notify (int id)
+{
+ char own_buf[256];
+
+ /* The `x' response is not yet part of the remote protocol. Do nothing. */
+ if (1)
+ return;
+
+ sprintf (own_buf, "x%x", id);
+ disable_async_io ();
+ putpkt (own_buf);
+ enable_async_io ();
+}
+
+void
+prepare_resume_reply (char *buf, char status, unsigned char signo)
+{
+ int nib, sig;
+
+ *buf++ = status;
+
+ sig = (int)target_signal_from_host (signo);
+
+ nib = ((sig & 0xf0) >> 4);
+ *buf++ = tohex (nib);
+ nib = sig & 0x0f;
+ *buf++ = tohex (nib);
+
+ if (status == 'T')
+ {
+ const char **regp = gdbserver_expedite_regs;
+ while (*regp)
+ {
+ buf = outreg (find_regno (*regp), buf);
+ regp ++;
+ }
+
+ /* Formerly, if the debugger had not used any thread features we would not
+ burden it with a thread status response. This was for the benefit of
+ GDB 4.13 and older. However, in recent GDB versions the check
+ (``if (cont_thread != 0)'') does not have the desired effect because of
+ sillyness in the way that the remote protocol handles specifying a thread.
+ Since thread support relies on qSymbol support anyway, assume GDB can handle
+ threads. */
+
+ if (using_threads)
+ {
+ /* FIXME right place to set this? */
+ thread_from_wait = ((struct inferior_list_entry *)current_inferior)->id;
+ if (debug_threads)
+ fprintf (stderr, "Writing resume reply for %d\n\n", thread_from_wait);
+ /* This if (1) ought to be unnecessary. But remote_wait in GDB
+ will claim this event belongs to inferior_ptid if we do not
+ specify a thread, and there's no way for gdbserver to know
+ what inferior_ptid is. */
+ if (1 || old_thread_from_wait != thread_from_wait)
+ {
+ general_thread = 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 (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *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 (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
+ char *to)
+{
+ int i = 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);
+}
+
+int
+look_up_one_symbol (const char *name, CORE_ADDR *addrp)
+{
+ char own_buf[266], *p, *q;
+ int len;
+
+ /* Send the request. */
+ strcpy (own_buf, "qSymbol:");
+ hexify (own_buf + strlen ("qSymbol:"), name, strlen (name));
+ if (putpkt (own_buf) < 0)
+ return -1;
+
+ /* FIXME: Eventually add buffer overflow checking (to getpkt?) */
+ len = getpkt (own_buf);
+ if (len < 0)
+ return -1;
+
+ if (strncmp (own_buf, "qSymbol:", strlen ("qSymbol:")) != 0)
+ {
+ /* Malformed response. */
+ if (remote_debug)
+ {
+ fprintf (stderr, "Malformed response to qSymbol, ignoring.\n");
+ fflush (stderr);
+ }
+
+ return -1;
+ }
+
+ p = own_buf + strlen ("qSymbol:");
+ q = p;
+ while (*q && *q != ':')
+ q++;
+
+ /* Make sure we found a value for the symbol. */
+ if (p == q || *q == '\0')
+ return 0;
+
+ decode_address (addrp, p, q - p);
+ return 1;
+}
+
diff --git a/contrib/gdb/gdb/gdbserver/server.c b/contrib/gdb/gdb/gdbserver/server.c
new file mode 100644
index 0000000..93e3ea4
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/server.c
@@ -0,0 +1,621 @@
+/* Main code for remote server for GDB.
+ Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+int cont_thread;
+int general_thread;
+int step_thread;
+int thread_from_wait;
+int old_thread_from_wait;
+int extended_protocol;
+int server_waiting;
+
+jmp_buf toplevel;
+
+/* The PID of the originally created or attached inferior. Used to
+ send signals to the process when GDB sends us an asynchronous interrupt
+ (user hitting Control-C in the client), and to wait for the child to exit
+ when no longer debugging it. */
+
+int signal_pid;
+
+static unsigned char
+start_inferior (char *argv[], char *statusptr)
+{
+ signal (SIGTTOU, SIG_DFL);
+ signal (SIGTTIN, SIG_DFL);
+
+ signal_pid = create_inferior (argv[0], argv);
+
+ fprintf (stderr, "Process %s created; pid = %d\n", argv[0],
+ signal_pid);
+
+ signal (SIGTTOU, SIG_IGN);
+ signal (SIGTTIN, SIG_IGN);
+ tcsetpgrp (fileno (stderr), signal_pid);
+
+ /* Wait till we are at 1st instruction in program, return signal number. */
+ return mywait (statusptr, 0);
+}
+
+static int
+attach_inferior (int pid, char *statusptr, unsigned char *sigptr)
+{
+ /* myattach should return -1 if attaching is unsupported,
+ 0 if it succeeded, and call error() otherwise. */
+
+ if (myattach (pid) != 0)
+ return -1;
+
+ fprintf (stderr, "Attached; pid = %d\n", pid);
+
+ /* FIXME - It may be that we should get the SIGNAL_PID from the
+ attach function, so that it can be the main thread instead of
+ whichever we were told to attach to. */
+ signal_pid = pid;
+
+ *sigptr = mywait (statusptr, 0);
+
+ return 0;
+}
+
+extern int remote_debug;
+
+/* Handle all of the extended 'q' packets. */
+void
+handle_query (char *own_buf)
+{
+ static struct inferior_list_entry *thread_ptr;
+
+ if (strcmp ("qSymbol::", own_buf) == 0)
+ {
+ if (the_target->look_up_symbols != NULL)
+ (*the_target->look_up_symbols) ();
+
+ strcpy (own_buf, "OK");
+ return;
+ }
+
+ if (strcmp ("qfThreadInfo", own_buf) == 0)
+ {
+ thread_ptr = all_threads.head;
+ sprintf (own_buf, "m%x", thread_ptr->id);
+ thread_ptr = thread_ptr->next;
+ return;
+ }
+
+ if (strcmp ("qsThreadInfo", own_buf) == 0)
+ {
+ if (thread_ptr != NULL)
+ {
+ sprintf (own_buf, "m%x", thread_ptr->id);
+ thread_ptr = thread_ptr->next;
+ return;
+ }
+ else
+ {
+ sprintf (own_buf, "l");
+ return;
+ }
+ }
+
+ if (the_target->read_auxv != NULL
+ && strncmp ("qPart:auxv:read::", own_buf, 17) == 0)
+ {
+ char data[(PBUFSIZ - 1) / 2];
+ CORE_ADDR ofs;
+ unsigned int len;
+ int n;
+ decode_m_packet (&own_buf[17], &ofs, &len); /* "OFS,LEN" */
+ if (len > sizeof data)
+ len = sizeof data;
+ n = (*the_target->read_auxv) (ofs, data, len);
+ if (n == 0)
+ write_ok (own_buf);
+ else if (n < 0)
+ write_enn (own_buf);
+ else
+ convert_int_to_ascii (data, own_buf, n);
+ return;
+ }
+
+ /* Otherwise we didn't know what packet it was. Say we didn't
+ understand it. */
+ own_buf[0] = 0;
+}
+
+/* Parse vCont packets. */
+void
+handle_v_cont (char *own_buf, char *status, unsigned char *signal)
+{
+ char *p, *q;
+ int n = 0, i = 0;
+ struct thread_resume *resume_info, default_action;
+
+ /* Count the number of semicolons in the packet. There should be one
+ for every action. */
+ p = &own_buf[5];
+ while (p)
+ {
+ n++;
+ p++;
+ p = strchr (p, ';');
+ }
+ /* Allocate room for one extra action, for the default remain-stopped
+ behavior; if no default action is in the list, we'll need the extra
+ slot. */
+ resume_info = malloc ((n + 1) * sizeof (resume_info[0]));
+
+ default_action.thread = -1;
+ default_action.leave_stopped = 1;
+ default_action.step = 0;
+ default_action.sig = 0;
+
+ p = &own_buf[5];
+ i = 0;
+ while (*p)
+ {
+ p++;
+
+ resume_info[i].leave_stopped = 0;
+
+ if (p[0] == 's' || p[0] == 'S')
+ resume_info[i].step = 1;
+ else if (p[0] == 'c' || p[0] == 'C')
+ resume_info[i].step = 0;
+ else
+ goto err;
+
+ if (p[0] == 'S' || p[0] == 'C')
+ {
+ int sig;
+ sig = strtol (p + 1, &q, 16);
+ if (p == q)
+ goto err;
+ p = q;
+
+ if (!target_signal_to_host_p (sig))
+ goto err;
+ resume_info[i].sig = target_signal_to_host (sig);
+ }
+ else
+ {
+ resume_info[i].sig = 0;
+ p = p + 1;
+ }
+
+ if (p[0] == 0)
+ {
+ resume_info[i].thread = -1;
+ default_action = resume_info[i];
+
+ /* Note: we don't increment i here, we'll overwrite this entry
+ the next time through. */
+ }
+ else if (p[0] == ':')
+ {
+ resume_info[i].thread = strtol (p + 1, &q, 16);
+ if (p == q)
+ goto err;
+ p = q;
+ if (p[0] != ';' && p[0] != 0)
+ goto err;
+
+ i++;
+ }
+ }
+
+ resume_info[i] = default_action;
+
+ /* Still used in occasional places in the backend. */
+ if (n == 1 && resume_info[0].thread != -1)
+ cont_thread = resume_info[0].thread;
+ else
+ cont_thread = -1;
+ set_desired_inferior (0);
+
+ (*the_target->resume) (resume_info);
+
+ free (resume_info);
+
+ *signal = mywait (status, 1);
+ prepare_resume_reply (own_buf, *status, *signal);
+ return;
+
+err:
+ /* No other way to report an error... */
+ strcpy (own_buf, "");
+ free (resume_info);
+ return;
+}
+
+/* Handle all of the extended 'v' packets. */
+void
+handle_v_requests (char *own_buf, char *status, unsigned char *signal)
+{
+ if (strncmp (own_buf, "vCont;", 6) == 0)
+ {
+ handle_v_cont (own_buf, status, signal);
+ return;
+ }
+
+ if (strncmp (own_buf, "vCont?", 6) == 0)
+ {
+ strcpy (own_buf, "vCont;c;C;s;S");
+ return;
+ }
+
+ /* Otherwise we didn't know what packet it was. Say we didn't
+ understand it. */
+ own_buf[0] = 0;
+ return;
+}
+
+void
+myresume (int step, int sig)
+{
+ struct thread_resume resume_info[2];
+ int n = 0;
+
+ if (step || sig || cont_thread > 0)
+ {
+ resume_info[0].thread
+ = ((struct inferior_list_entry *) current_inferior)->id;
+ resume_info[0].step = step;
+ resume_info[0].sig = sig;
+ resume_info[0].leave_stopped = 0;
+ n++;
+ }
+ resume_info[n].thread = -1;
+ resume_info[n].step = 0;
+ resume_info[n].sig = 0;
+ resume_info[n].leave_stopped = (cont_thread > 0);
+
+ (*the_target->resume) (resume_info);
+}
+
+static int attached;
+
+static void
+gdbserver_usage (void)
+{
+ error ("Usage:\tgdbserver COMM PROG [ARGS ...]\n"
+ "\tgdbserver COMM --attach PID\n"
+ "\n"
+ "COMM may either be a tty device (for serial debugging), or \n"
+ "HOST:PORT to listen for a TCP connection.\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+ char ch, status, *own_buf, mem_buf[2000];
+ int i = 0;
+ unsigned char signal;
+ unsigned int len;
+ CORE_ADDR mem_addr;
+ int bad_attach;
+ int pid;
+ char *arg_end;
+
+ if (setjmp (toplevel))
+ {
+ fprintf (stderr, "Exiting\n");
+ exit (1);
+ }
+
+ bad_attach = 0;
+ pid = 0;
+ attached = 0;
+ if (argc >= 3 && strcmp (argv[2], "--attach") == 0)
+ {
+ if (argc == 4
+ && argv[3] != '\0'
+ && (pid = strtoul (argv[3], &arg_end, 10)) != 0
+ && *arg_end == '\0')
+ {
+ ;
+ }
+ else
+ bad_attach = 1;
+ }
+
+ if (argc < 3 || bad_attach)
+ gdbserver_usage();
+
+ initialize_low ();
+
+ own_buf = malloc (PBUFSIZ);
+
+ if (pid == 0)
+ {
+ /* Wait till we are at first instruction in program. */
+ signal = start_inferior (&argv[2], &status);
+
+ /* We are now stopped at the first instruction of the target process */
+ }
+ else
+ {
+ switch (attach_inferior (pid, &status, &signal))
+ {
+ case -1:
+ error ("Attaching not supported on this target");
+ break;
+ default:
+ attached = 1;
+ break;
+ }
+ }
+
+ 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 'q':
+ handle_query (own_buf);
+ break;
+ case 'd':
+ remote_debug = !remote_debug;
+ break;
+ case 'D':
+ fprintf (stderr, "Detaching from inferior\n");
+ detach_inferior ();
+ write_ok (own_buf);
+ putpkt (own_buf);
+ remote_close ();
+
+ /* If we are attached, then we can exit. Otherwise, we need to
+ hang around doing nothing, until the child is gone. */
+ if (!attached)
+ {
+ int status, ret;
+
+ do {
+ ret = waitpid (signal_pid, &status, 0);
+ if (WIFEXITED (status) || WIFSIGNALED (status))
+ break;
+ } while (ret != -1 || errno != ECHILD);
+ }
+
+ exit (0);
+
+ case '!':
+ if (attached == 0)
+ {
+ extended_protocol = 1;
+ prepare_resume_reply (own_buf, status, signal);
+ }
+ else
+ {
+ /* We can not use the extended protocol if we are
+ attached, because we can not restart the running
+ program. So return unrecognized. */
+ own_buf[0] = '\0';
+ }
+ 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);
+ set_desired_inferior (1);
+ break;
+ case 'c':
+ cont_thread = strtol (&own_buf[2], NULL, 16);
+ write_ok (own_buf);
+ break;
+ case 's':
+ step_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':
+ set_desired_inferior (1);
+ registers_to_string (own_buf);
+ break;
+ case 'G':
+ set_desired_inferior (1);
+ registers_from_string (&own_buf[1]);
+ write_ok (own_buf);
+ break;
+ case 'm':
+ decode_m_packet (&own_buf[1], &mem_addr, &len);
+ if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
+ convert_int_to_ascii (mem_buf, own_buf, len);
+ else
+ write_enn (own_buf);
+ 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);
+ if (target_signal_to_host_p (sig))
+ signal = target_signal_to_host (sig);
+ else
+ signal = 0;
+ set_desired_inferior (0);
+ myresume (0, signal);
+ signal = mywait (&status, 1);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'S':
+ convert_ascii_to_int (own_buf + 1, &sig, 1);
+ if (target_signal_to_host_p (sig))
+ signal = target_signal_to_host (sig);
+ else
+ signal = 0;
+ set_desired_inferior (0);
+ myresume (1, signal);
+ signal = mywait (&status, 1);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'c':
+ set_desired_inferior (0);
+ myresume (0, 0);
+ signal = mywait (&status, 1);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 's':
+ set_desired_inferior (0);
+ myresume (1, 0);
+ signal = mywait (&status, 1);
+ 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");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &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");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &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;
+ }
+ case 'v':
+ /* Extended (long) request. */
+ handle_v_requests (own_buf, &status, &signal);
+ 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", signal);
+ if (status == 'X')
+ fprintf (stderr, "\nChild terminated with signal = 0x%x\n",
+ signal);
+ if (status == 'W' || status == 'X')
+ {
+ if (extended_protocol)
+ {
+ fprintf (stderr, "Killing inferior\n");
+ kill_inferior ();
+ write_ok (own_buf);
+ fprintf (stderr, "GDBserver restarting\n");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &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 0000000..59dbcf9
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/server.h
@@ -0,0 +1,181 @@
+/* Common definitions for remote server for GDB.
+ Copyright 1993, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SERVER_H
+#define SERVER_H
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef NEED_DECLARATION_STRERROR
+#ifndef strerror
+extern char *strerror (int); /* X3.159-1989 4.11.6.2 */
+#endif
+#endif
+
+#ifndef ATTR_NORETURN
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__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__ == 2 && __GNUC_MINOR__ >= 4))
+#define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y)))
+#else
+#define ATTR_FORMAT(type, x, y) /* nothing */
+#endif
+#endif
+
+/* FIXME: This should probably be autoconf'd for. It's an integer type at
+ least the size of a (void *). */
+typedef long long CORE_ADDR;
+
+/* Generic information for tracking a list of ``inferiors'' - threads,
+ processes, etc. */
+struct inferior_list
+{
+ struct inferior_list_entry *head;
+ struct inferior_list_entry *tail;
+};
+struct inferior_list_entry
+{
+ int id;
+ struct inferior_list_entry *next;
+};
+
+/* Opaque type for user-visible threads. */
+struct thread_info;
+
+#include "regcache.h"
+#include "gdb/signals.h"
+
+#include "target.h"
+#include "mem-break.h"
+
+/* Target-specific functions */
+
+void initialize_low ();
+
+/* From inferiors.c. */
+
+extern struct inferior_list all_threads;
+void add_inferior_to_list (struct inferior_list *list,
+ struct inferior_list_entry *new_inferior);
+void for_each_inferior (struct inferior_list *list,
+ void (*action) (struct inferior_list_entry *));
+extern struct thread_info *current_inferior;
+void remove_inferior (struct inferior_list *list,
+ struct inferior_list_entry *entry);
+void remove_thread (struct thread_info *thread);
+void add_thread (int thread_id, void *target_data);
+void clear_inferiors (void);
+struct inferior_list_entry *find_inferior
+ (struct inferior_list *,
+ int (*func) (struct inferior_list_entry *,
+ void *),
+ void *arg);
+struct inferior_list_entry *find_inferior_id (struct inferior_list *list,
+ int id);
+void *inferior_target_data (struct thread_info *);
+void set_inferior_target_data (struct thread_info *, void *);
+void *inferior_regcache_data (struct thread_info *);
+void set_inferior_regcache_data (struct thread_info *, void *);
+void change_inferior_id (struct inferior_list *list,
+ int new_id);
+
+/* Public variables in server.c */
+
+extern int cont_thread;
+extern int general_thread;
+extern int step_thread;
+extern int thread_from_wait;
+extern int old_thread_from_wait;
+extern int server_waiting;
+
+extern jmp_buf toplevel;
+
+/* Functions from remote-utils.c */
+
+int putpkt (char *buf);
+int getpkt (char *buf);
+void remote_open (char *name);
+void remote_close (void);
+void write_ok (char *buf);
+void write_enn (char *buf);
+void enable_async_io (void);
+void disable_async_io (void);
+void unblock_async_io (void);
+void block_async_io (void);
+void convert_ascii_to_int (char *from, char *to, int n);
+void convert_int_to_ascii (char *from, char *to, int n);
+void new_thread_notify (int id);
+void dead_thread_notify (int id);
+void prepare_resume_reply (char *buf, char status, unsigned char sig);
+
+void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr,
+ unsigned int *len_ptr);
+void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr,
+ unsigned int *len_ptr, char *to);
+
+int unhexify (char *bin, const char *hex, int count);
+int hexify (char *hex, const char *bin, int count);
+
+int look_up_one_symbol (const char *name, CORE_ADDR *addrp);
+
+/* Functions from ``signals.c''. */
+enum target_signal target_signal_from_host (int hostsig);
+int target_signal_to_host_p (enum target_signal oursig);
+int target_signal_to_host (enum target_signal oursig);
+
+/* Functions from utils.c */
+
+void perror_with_name (char *string);
+void error (const char *string,...) ATTR_NORETURN;
+void fatal (const char *string,...) ATTR_NORETURN;
+void warning (const char *string,...);
+
+/* Functions from the register cache definition. */
+
+void init_registers (void);
+
+/* 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(N) (((N)-32)/2)
+
+/* Buffer sizes for transferring memory, registers, etc. Round up PBUFSIZ to
+ hold all the registers, at least. */
+#define PBUFSIZ ((registers_length () + 32 > 2000) \
+ ? (registers_length () + 32) \
+ : 2000)
+
+#endif /* SERVER_H */
diff --git a/contrib/gdb/gdb/gdbserver/target.c b/contrib/gdb/gdb/gdbserver/target.c
new file mode 100644
index 0000000..2c60e17
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/target.c
@@ -0,0 +1,112 @@
+/* Target operations for the remote server for GDB.
+ Copyright 2002, 2004
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+struct target_ops *the_target;
+
+void
+set_desired_inferior (int use_general)
+{
+ struct thread_info *found;
+
+ if (use_general == 1)
+ {
+ found = (struct thread_info *) find_inferior_id (&all_threads,
+ general_thread);
+ }
+ else
+ {
+ found = NULL;
+
+ /* If we are continuing any (all) thread(s), use step_thread
+ to decide which thread to step and/or send the specified
+ signal to. */
+ if (step_thread > 0 && (cont_thread == 0 || cont_thread == -1))
+ found = (struct thread_info *) find_inferior_id (&all_threads,
+ step_thread);
+
+ if (found == NULL)
+ found = (struct thread_info *) find_inferior_id (&all_threads,
+ cont_thread);
+ }
+
+ if (found == NULL)
+ current_inferior = (struct thread_info *) all_threads.head;
+ else
+ current_inferior = found;
+}
+
+int
+read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int res;
+ res = (*the_target->read_memory) (memaddr, myaddr, len);
+ check_mem_read (memaddr, myaddr, len);
+ return res;
+}
+
+int
+write_inferior_memory (CORE_ADDR memaddr, const char *myaddr, int len)
+{
+ /* Lacking cleanups, there is some potential for a memory leak if the
+ write fails and we go through error(). Make sure that no more than
+ one buffer is ever pending by making BUFFER static. */
+ static char *buffer = 0;
+ int res;
+
+ if (buffer != NULL)
+ free (buffer);
+
+ buffer = malloc (len);
+ memcpy (buffer, myaddr, len);
+ check_mem_write (memaddr, buffer, len);
+ res = (*the_target->write_memory) (memaddr, buffer, len);
+ free (buffer);
+ buffer = NULL;
+
+ return res;
+}
+
+unsigned char
+mywait (char *statusp, int connected_wait)
+{
+ unsigned char ret;
+
+ if (connected_wait)
+ server_waiting = 1;
+
+ ret = (*the_target->wait) (statusp);
+
+ if (connected_wait)
+ server_waiting = 0;
+
+ return ret;
+}
+
+void
+set_target_ops (struct target_ops *target)
+{
+ the_target = (struct target_ops *) malloc (sizeof (*the_target));
+ memcpy (the_target, target, sizeof (*the_target));
+}
diff --git a/contrib/gdb/gdb/gdbserver/target.h b/contrib/gdb/gdb/gdbserver/target.h
new file mode 100644
index 0000000..770ffcb
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/target.h
@@ -0,0 +1,171 @@
+/* Target operations for the remote server for GDB.
+ Copyright 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TARGET_H
+#define TARGET_H
+
+/* This structure describes how to resume a particular thread (or
+ all threads) based on the client's request. If thread is -1, then
+ this entry applies to all threads. These are generally passed around
+ as an array, and terminated by a thread == -1 entry. */
+
+struct thread_resume
+{
+ int thread;
+
+ /* If non-zero, leave this thread stopped. */
+ int leave_stopped;
+
+ /* If non-zero, we want to single-step. */
+ int step;
+
+ /* If non-zero, send this signal when we resume. */
+ int sig;
+};
+
+struct target_ops
+{
+ /* Start a new process.
+
+ PROGRAM is a path to the program to execute.
+ ARGS is a standard NULL-terminated array of arguments,
+ to be passed to the inferior as ``argv''.
+
+ Returns the new PID on success, -1 on failure. Registers the new
+ process with the process list. */
+
+ int (*create_inferior) (char *program, char **args);
+
+ /* Attach to a running process.
+
+ PID is the process ID to attach to, specified by the user
+ or a higher layer. */
+
+ int (*attach) (int pid);
+
+ /* Kill all inferiors. */
+
+ void (*kill) (void);
+
+ /* Detach from all inferiors. */
+
+ void (*detach) (void);
+
+ /* Return 1 iff the thread with process ID PID is alive. */
+
+ int (*thread_alive) (int pid);
+
+ /* Resume the inferior process. */
+
+ void (*resume) (struct thread_resume *resume_info);
+
+ /* Wait for the inferior process to change state.
+
+ STATUSP will be filled in with a response code to send to GDB.
+
+ Returns the signal which caused the process to stop. */
+
+ unsigned char (*wait) (char *status);
+
+ /* Fetch registers from the inferior process.
+
+ If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
+
+ void (*fetch_registers) (int regno);
+
+ /* Store registers to the inferior process.
+
+ If REGNO is -1, store all registers; otherwise, store at least REGNO. */
+
+ void (*store_registers) (int regno);
+
+ /* Read memory from the inferior process. This should generally be
+ called through read_inferior_memory, which handles breakpoint shadowing.
+
+ Read LEN bytes at MEMADDR into a buffer at MYADDR.
+
+ Returns 0 on success and errno on failure. */
+
+ int (*read_memory) (CORE_ADDR memaddr, char *myaddr, int len);
+
+ /* Write memory to the inferior process. This should generally be
+ called through write_inferior_memory, which handles breakpoint shadowing.
+
+ Write LEN bytes from the buffer at MYADDR to MEMADDR.
+
+ Returns 0 on success and errno on failure. */
+
+ int (*write_memory) (CORE_ADDR memaddr, const char *myaddr, int len);
+
+ /* Query GDB for the values of any symbols we're interested in.
+ This function is called whenever we receive a "qSymbols::"
+ query, which corresponds to every time more symbols (might)
+ become available. NULL if we aren't interested in any
+ symbols. */
+
+ void (*look_up_symbols) (void);
+
+ /* Send a signal to the inferior process, however is appropriate. */
+ void (*send_signal) (int);
+
+ /* Read auxiliary vector data from the inferior process.
+
+ Read LEN bytes at OFFSET into a buffer at MYADDR. */
+
+ int (*read_auxv) (CORE_ADDR offset, char *myaddr, unsigned int len);
+};
+
+extern struct target_ops *the_target;
+
+void set_target_ops (struct target_ops *);
+
+#define create_inferior(program, args) \
+ (*the_target->create_inferior) (program, args)
+
+#define myattach(pid) \
+ (*the_target->attach) (pid)
+
+#define kill_inferior() \
+ (*the_target->kill) ()
+
+#define detach_inferior() \
+ (*the_target->detach) ()
+
+#define mythread_alive(pid) \
+ (*the_target->thread_alive) (pid)
+
+#define fetch_inferior_registers(regno) \
+ (*the_target->fetch_registers) (regno)
+
+#define store_inferior_registers(regno) \
+ (*the_target->store_registers) (regno)
+
+unsigned char mywait (char *statusp, int connected_wait);
+
+int read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
+
+int write_inferior_memory (CORE_ADDR memaddr, const char *myaddr, int len);
+
+void set_desired_inferior (int id);
+
+#endif /* TARGET_H */
diff --git a/contrib/gdb/gdb/gdbserver/terminal.h b/contrib/gdb/gdb/gdbserver/terminal.h
new file mode 100644
index 0000000..69b6692
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/terminal.h
@@ -0,0 +1,51 @@
+/* Terminal interface definitions for the GDB remote server.
+ Copyright 2002, Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+/* Autoconf will have defined HAVE_TERMIOS_H, HAVE_TERMIO_H,
+ and HAVE_SGTTY_H for us as appropriate. */
+
+#if defined(HAVE_TERMIOS_H)
+#define HAVE_TERMIOS
+#include <termios.h>
+#else /* ! HAVE_TERMIOS_H */
+#if defined(HAVE_TERMIO_H)
+#define HAVE_TERMIO
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+#else /* ! HAVE_TERMIO_H; default to SGTTY. */
+#define HAVE_SGTTY
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+#endif
+#endif
+
+#endif /* !defined (TERMINAL_H) */
diff --git a/contrib/gdb/gdb/gdbserver/thread-db.c b/contrib/gdb/gdb/gdbserver/thread-db.c
new file mode 100644
index 0000000..f3d57a5
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/thread-db.c
@@ -0,0 +1,342 @@
+/* Thread management interface, for the remote server for GDB.
+ Copyright 2002
+ Free Software Foundation, Inc.
+
+ Contributed by MontaVista Software.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "linux-low.h"
+
+extern int debug_threads;
+
+#ifdef HAVE_THREAD_DB_H
+#include <thread_db.h>
+#endif
+
+/* Correct for all GNU/Linux targets (for quite some time). */
+#define GDB_GREGSET_T elf_gregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
+
+#ifndef HAVE_ELF_FPREGSET_T
+/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
+ via <sys/procfs.h>. */
+#ifdef HAVE_LINUX_ELF_H
+#include <linux/elf.h>
+#endif
+#endif
+
+#include "../gdb_proc_service.h"
+
+/* Structure that identifies the child process for the
+ <proc_service.h> interface. */
+static struct ps_prochandle proc_handle;
+
+/* Connection to the libthread_db library. */
+static td_thragent_t *thread_agent;
+
+static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
+
+static char *
+thread_db_err_str (td_err_e err)
+{
+ static char buf[64];
+
+ switch (err)
+ {
+ case TD_OK:
+ return "generic 'call succeeded'";
+ case TD_ERR:
+ return "generic error";
+ case TD_NOTHR:
+ return "no thread to satisfy query";
+ case TD_NOSV:
+ return "no sync handle to satisfy query";
+ case TD_NOLWP:
+ return "no LWP to satisfy query";
+ case TD_BADPH:
+ return "invalid process handle";
+ case TD_BADTH:
+ return "invalid thread handle";
+ case TD_BADSH:
+ return "invalid synchronization handle";
+ case TD_BADTA:
+ return "invalid thread agent";
+ case TD_BADKEY:
+ return "invalid key";
+ case TD_NOMSG:
+ return "no event message for getmsg";
+ case TD_NOFPREGS:
+ return "FPU register set not available";
+ case TD_NOLIBTHREAD:
+ return "application not linked with libthread";
+ case TD_NOEVENT:
+ return "requested event is not supported";
+ case TD_NOCAPAB:
+ return "capability not available";
+ case TD_DBERR:
+ return "debugger service failed";
+ case TD_NOAPLIC:
+ return "operation not applicable to";
+ case TD_NOTSD:
+ return "no thread-specific data for this thread";
+ case TD_MALLOC:
+ return "malloc failed";
+ case TD_PARTIALREG:
+ return "only part of register set was written/read";
+ case TD_NOXREGS:
+ return "X register set not available for this thread";
+ default:
+ snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
+ return buf;
+ }
+}
+
+#if 0
+static char *
+thread_db_state_str (td_thr_state_e state)
+{
+ static char buf[64];
+
+ switch (state)
+ {
+ case TD_THR_STOPPED:
+ return "stopped by debugger";
+ case TD_THR_RUN:
+ return "runnable";
+ case TD_THR_ACTIVE:
+ return "active";
+ case TD_THR_ZOMBIE:
+ return "zombie";
+ case TD_THR_SLEEP:
+ return "sleeping";
+ case TD_THR_STOPPED_ASLEEP:
+ return "stopped by debugger AND blocked";
+ default:
+ snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
+ return buf;
+ }
+}
+#endif
+
+static void
+thread_db_create_event (CORE_ADDR where)
+{
+ td_event_msg_t msg;
+ td_err_e err;
+ struct inferior_linux_data *tdata;
+
+ if (debug_threads)
+ fprintf (stderr, "Thread creation event.\n");
+
+ tdata = inferior_target_data (current_inferior);
+
+ /* FIXME: This assumes we don't get another event.
+ In the LinuxThreads implementation, this is safe,
+ because all events come from the manager thread
+ (except for its own creation, of course). */
+ err = td_ta_event_getmsg (thread_agent, &msg);
+ if (err != TD_OK)
+ fprintf (stderr, "thread getmsg err: %s\n",
+ thread_db_err_str (err));
+
+ /* msg.event == TD_EVENT_CREATE */
+
+ find_new_threads_callback (msg.th_p, NULL);
+}
+
+#if 0
+static void
+thread_db_death_event (CORE_ADDR where)
+{
+ if (debug_threads)
+ fprintf (stderr, "Thread death event.\n");
+}
+#endif
+
+static int
+thread_db_enable_reporting ()
+{
+ td_thr_events_t events;
+ td_notify_t notify;
+ td_err_e err;
+
+ /* Set the process wide mask saying which events we're interested in. */
+ td_event_emptyset (&events);
+ td_event_addset (&events, TD_CREATE);
+
+#if 0
+ /* This is reported to be broken in glibc 2.1.3. A different approach
+ will be necessary to support that. */
+ td_event_addset (&events, TD_DEATH);
+#endif
+
+ err = td_ta_set_event (thread_agent, &events);
+ if (err != TD_OK)
+ {
+ warning ("Unable to set global thread event mask: %s",
+ thread_db_err_str (err));
+ return 0;
+ }
+
+ /* Get address for thread creation breakpoint. */
+ err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
+ if (err != TD_OK)
+ {
+ warning ("Unable to get location for thread creation breakpoint: %s",
+ thread_db_err_str (err));
+ return 0;
+ }
+ set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
+ thread_db_create_event);
+
+#if 0
+ /* Don't concern ourselves with reported thread deaths, only
+ with actual thread deaths (via wait). */
+
+ /* Get address for thread death breakpoint. */
+ err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
+ if (err != TD_OK)
+ {
+ warning ("Unable to get location for thread death breakpoint: %s",
+ thread_db_err_str (err));
+ return;
+ }
+ set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
+ thread_db_death_event);
+#endif
+
+ return 1;
+}
+
+static void
+maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
+{
+ td_err_e err;
+ struct thread_info *inferior;
+ struct process_info *process;
+
+ /* If we are attaching to our first thread, things are a little
+ different. */
+ if (all_threads.head == all_threads.tail)
+ {
+ inferior = (struct thread_info *) all_threads.head;
+ process = get_thread_process (inferior);
+ if (process->thread_known == 0)
+ {
+ /* Switch to indexing the threads list by TID. */
+ change_inferior_id (&all_threads, ti_p->ti_tid);
+ goto found;
+ }
+ }
+
+ inferior = (struct thread_info *) find_inferior_id (&all_threads,
+ ti_p->ti_tid);
+ if (inferior != NULL)
+ return;
+
+ if (debug_threads)
+ fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
+ ti_p->ti_tid, ti_p->ti_lid);
+ linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
+ inferior = (struct thread_info *) find_inferior_id (&all_threads,
+ ti_p->ti_tid);
+ if (inferior == NULL)
+ {
+ warning ("Could not attach to thread %ld (LWP %d)\n",
+ ti_p->ti_tid, ti_p->ti_lid);
+ return;
+ }
+
+ process = inferior_target_data (inferior);
+
+found:
+ new_thread_notify (ti_p->ti_tid);
+
+ process->tid = ti_p->ti_tid;
+ process->lwpid = ti_p->ti_lid;
+
+ process->thread_known = 1;
+ err = td_thr_event_enable (th_p, 1);
+ if (err != TD_OK)
+ error ("Cannot enable thread event reporting for %d: %s",
+ ti_p->ti_lid, thread_db_err_str (err));
+}
+
+static int
+find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
+{
+ td_thrinfo_t ti;
+ td_err_e err;
+
+ err = td_thr_get_info (th_p, &ti);
+ if (err != TD_OK)
+ error ("Cannot get thread info: %s", thread_db_err_str (err));
+
+ /* Check for zombies. */
+ if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
+ return 0;
+
+ maybe_attach_thread (th_p, &ti);
+
+ return 0;
+}
+
+static void
+thread_db_find_new_threads (void)
+{
+ td_err_e err;
+
+ /* Iterate over all user-space threads to discover new threads. */
+ err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
+ TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+ TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+ if (err != TD_OK)
+ error ("Cannot find new threads: %s", thread_db_err_str (err));
+}
+
+int
+thread_db_init ()
+{
+ int err;
+
+ proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
+
+ err = td_ta_new (&proc_handle, &thread_agent);
+ switch (err)
+ {
+ case TD_NOLIBTHREAD:
+ /* No thread library was detected. */
+ return 0;
+
+ case TD_OK:
+ /* The thread library was detected. */
+
+ if (thread_db_enable_reporting () == 0)
+ return 0;
+ thread_db_find_new_threads ();
+ return 1;
+
+ default:
+ warning ("error initializing thread_db library.");
+ }
+
+ return 0;
+}
diff --git a/contrib/gdb/gdb/gdbserver/utils.c b/contrib/gdb/gdb/gdbserver/utils.c
new file mode 100644
index 0000000..44bdccf
--- /dev/null
+++ b/contrib/gdb/gdb/gdbserver/utils.c
@@ -0,0 +1,96 @@
+/* General utility routines for the remote server for GDB.
+ Copyright 1986, 1989, 1993, 1995, 1996, 1997, 1999, 2000, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stdio.h>
+#include <string.h>
+
+/* 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 (char *string)
+{
+#ifndef STDC_HEADERS
+ extern int errno;
+#endif
+ const char *err;
+ char *combined;
+
+ err = strerror (errno);
+ if (err == NULL)
+ 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. */
+
+void
+error (const char *string,...)
+{
+ extern jmp_buf toplevel;
+ va_list args;
+ va_start (args, string);
+ fflush (stdout);
+ vfprintf (stderr, string, args);
+ 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 */
+void
+fatal (const char *string,...)
+{
+ va_list args;
+ va_start (args, string);
+ fprintf (stderr, "gdb: ");
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+ exit (1);
+}
+
+/* VARARGS */
+void
+warning (const char *string,...)
+{
+ va_list args;
+ va_start (args, string);
+ fprintf (stderr, "gdb: ");
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
diff --git a/contrib/gdb/gdb/gdbthread.h b/contrib/gdb/gdb/gdbthread.h
new file mode 100644
index 0000000..09dea26
--- /dev/null
+++ b/contrib/gdb/gdb/gdbthread.h
@@ -0,0 +1,156 @@
+/* Multi-process/thread control defs for GDB, the GNU debugger.
+ Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1997, 1998, 1999,
+ 2000
+ Free Software Foundation, Inc.
+ Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
+
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDBTHREAD_H
+#define GDBTHREAD_H
+
+struct breakpoint;
+struct frame_id;
+struct symtab;
+
+/* For bpstat */
+#include "breakpoint.h"
+
+/* For struct frame_id. */
+#include "frame.h"
+
+struct thread_info
+{
+ struct thread_info *next;
+ ptid_t ptid; /* "Actual process id";
+ In fact, this may be overloaded with
+ kernel thread id, etc. */
+ int num; /* Convenient handle (GDB thread id) */
+ /* State from wait_for_inferior */
+ CORE_ADDR prev_pc;
+ struct breakpoint *step_resume_breakpoint;
+ struct breakpoint *through_sigtramp_breakpoint;
+ CORE_ADDR step_range_start;
+ CORE_ADDR step_range_end;
+ struct frame_id step_frame_id;
+ CORE_ADDR step_sp;
+ int current_line;
+ struct symtab *current_symtab;
+ int trap_expected;
+ int handling_longjmp;
+ int another_trap;
+
+ /* This is set TRUE when a catchpoint of a shared library event
+ triggers. Since we don't wish to leave the inferior in the
+ solib hook when we report the event, we step the inferior
+ back to user code before stopping and reporting the event. */
+ int stepping_through_solib_after_catch;
+
+ /* When stepping_through_solib_after_catch is TRUE, this is a
+ list of the catchpoints that should be reported as triggering
+ when we finally do stop stepping. */
+ bpstat stepping_through_solib_catchpoints;
+
+ /* This is set to TRUE when this thread is in a signal handler
+ trampoline and we're single-stepping through it. */
+ int stepping_through_sigtramp;
+
+ /* Private data used by the target vector implementation. */
+ struct private_thread_info *private;
+};
+
+/* Create an empty thread list, or empty the existing one. */
+extern void init_thread_list (void);
+
+/* Add a thread to the thread list.
+ Note that add_thread now returns the handle of the new thread,
+ so that the caller may initialize the private thread data. */
+extern struct thread_info *add_thread (ptid_t ptid);
+
+/* Delete an existing thread list entry. */
+extern void delete_thread (ptid_t);
+
+/* Delete a step_resume_breakpoint from the thread database. */
+extern void delete_step_resume_breakpoint (void *);
+
+/* Translate the integer thread id (GDB's homegrown id, not the system's)
+ into a "pid" (which may be overloaded with extra thread information). */
+extern ptid_t thread_id_to_pid (int);
+
+/* Translate a 'pid' (which may be overloaded with extra thread information)
+ into the integer thread id (GDB's homegrown id, not the system's). */
+extern int pid_to_thread_id (ptid_t ptid);
+
+/* Boolean test for an already-known pid (which may be overloaded with
+ extra thread information). */
+extern int in_thread_list (ptid_t ptid);
+
+/* Boolean test for an already-known thread id (GDB's homegrown id,
+ not the system's). */
+extern int valid_thread_id (int thread);
+
+/* Search function to lookup a thread by 'pid'. */
+extern struct thread_info *find_thread_pid (ptid_t ptid);
+
+/* Iterator function to call a user-provided callback function
+ once for each known thread. */
+typedef int (*thread_callback_func) (struct thread_info *, void *);
+extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
+
+/* infrun context switch: save the debugger state for the given thread. */
+extern void save_infrun_state (ptid_t ptid,
+ CORE_ADDR prev_pc,
+ int trap_expected,
+ struct breakpoint *step_resume_breakpoint,
+ struct breakpoint *through_sigtramp_breakpoint,
+ CORE_ADDR step_range_start,
+ CORE_ADDR step_range_end,
+ const struct frame_id *step_frame_id,
+ int handling_longjmp,
+ int another_trap,
+ int stepping_through_solib_after_catch,
+ bpstat stepping_through_solib_catchpoints,
+ int stepping_through_sigtramp,
+ int current_line,
+ struct symtab *current_symtab,
+ CORE_ADDR step_sp);
+
+/* infrun context switch: load the debugger state previously saved
+ for the given thread. */
+extern void load_infrun_state (ptid_t ptid,
+ CORE_ADDR *prev_pc,
+ int *trap_expected,
+ struct breakpoint **step_resume_breakpoint,
+ struct breakpoint **through_sigtramp_breakpoint,
+ CORE_ADDR *step_range_start,
+ CORE_ADDR *step_range_end,
+ struct frame_id *step_frame_id,
+ int *handling_longjmp,
+ int *another_trap,
+ int *stepping_through_solib_affter_catch,
+ bpstat *stepping_through_solib_catchpoints,
+ int *stepping_through_sigtramp,
+ int *current_line,
+ struct symtab **current_symtab,
+ CORE_ADDR *step_sp);
+
+/* Commands with a prefix of `thread'. */
+extern struct cmd_list_element *thread_cmd_list;
+
+#endif /* GDBTHREAD_H */
diff --git a/contrib/gdb/gdb/gdbtypes.c b/contrib/gdb/gdb/gdbtypes.c
new file mode 100644
index 0000000..1349ffb
--- /dev/null
+++ b/contrib/gdb/gdb/gdbtypes.c
@@ -0,0 +1,3499 @@
+/* Support routines for manipulating internal types for GDB.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004 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"
+#include "gdbcmd.h"
+#include "wrapper.h"
+#include "cp-abi.h"
+#include "gdb_assert.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_true_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;
+struct type *builtin_type_int0;
+struct type *builtin_type_int8;
+struct type *builtin_type_uint8;
+struct type *builtin_type_int16;
+struct type *builtin_type_uint16;
+struct type *builtin_type_int32;
+struct type *builtin_type_uint32;
+struct type *builtin_type_int64;
+struct type *builtin_type_uint64;
+struct type *builtin_type_int128;
+struct type *builtin_type_uint128;
+struct type *builtin_type_bool;
+
+/* 128 bit long vector types */
+struct type *builtin_type_v2_double;
+struct type *builtin_type_v4_float;
+struct type *builtin_type_v2_int64;
+struct type *builtin_type_v4_int32;
+struct type *builtin_type_v8_int16;
+struct type *builtin_type_v16_int8;
+/* 64 bit long vector types */
+struct type *builtin_type_v2_float;
+struct type *builtin_type_v2_int32;
+struct type *builtin_type_v4_int16;
+struct type *builtin_type_v8_int8;
+
+struct type *builtin_type_v4sf;
+struct type *builtin_type_v4si;
+struct type *builtin_type_v16qi;
+struct type *builtin_type_v8qi;
+struct type *builtin_type_v8hi;
+struct type *builtin_type_v4hi;
+struct type *builtin_type_v2si;
+struct type *builtin_type_vec64;
+struct type *builtin_type_vec64i;
+struct type *builtin_type_vec128;
+struct type *builtin_type_vec128i;
+struct type *builtin_type_ieee_single_big;
+struct type *builtin_type_ieee_single_little;
+struct type *builtin_type_ieee_double_big;
+struct type *builtin_type_ieee_double_little;
+struct type *builtin_type_ieee_double_littlebyte_bigword;
+struct type *builtin_type_i387_ext;
+struct type *builtin_type_m68881_ext;
+struct type *builtin_type_i960_ext;
+struct type *builtin_type_m88110_ext;
+struct type *builtin_type_m88110_harris_ext;
+struct type *builtin_type_arm_ext_big;
+struct type *builtin_type_arm_ext_littlebyte_bigword;
+struct type *builtin_type_ia64_spill_big;
+struct type *builtin_type_ia64_spill_little;
+struct type *builtin_type_ia64_quad_big;
+struct type *builtin_type_ia64_quad_little;
+struct type *builtin_type_void_data_ptr;
+struct type *builtin_type_void_func_ptr;
+struct type *builtin_type_CORE_ADDR;
+struct type *builtin_type_bfd_vma;
+
+int opaque_type_resolution = 1;
+int overload_debug = 0;
+
+struct extra
+ {
+ char str[128];
+ int len;
+ }; /* maximum extension is 128! FIXME */
+
+static void print_bit_vector (B_TYPE *, int);
+static void print_arg_types (struct field *, int, int);
+static void dump_fn_fieldlists (struct type *, int);
+static void print_cplus_stuff (struct type *, int);
+static void virtual_base_list_aux (struct type *dclass);
+
+
+/* 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 objfile_obstack. Otherwise allocate the new type structure
+ by xmalloc () (for permanent types). */
+
+struct type *
+alloc_type (struct objfile *objfile)
+{
+ struct type *type;
+
+ /* Alloc the structure and start off with all fields zeroed. */
+
+ if (objfile == NULL)
+ {
+ type = xmalloc (sizeof (struct type));
+ memset (type, 0, sizeof (struct type));
+ TYPE_MAIN_TYPE (type) = xmalloc (sizeof (struct main_type));
+ }
+ else
+ {
+ type = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct type));
+ memset (type, 0, sizeof (struct type));
+ TYPE_MAIN_TYPE (type) = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct main_type));
+ OBJSTAT (objfile, n_types++);
+ }
+ memset (TYPE_MAIN_TYPE (type), 0, sizeof (struct main_type));
+
+ /* Initialize the fields that might not be zero. */
+
+ TYPE_CODE (type) = TYPE_CODE_UNDEF;
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_VPTR_FIELDNO (type) = -1;
+ TYPE_CHAIN (type) = type; /* Chain back to itself. */
+
+ return (type);
+}
+
+/* Alloc a new type instance structure, fill it with some defaults,
+ and point it at OLDTYPE. Allocate the new type instance from the
+ same place as OLDTYPE. */
+
+static struct type *
+alloc_type_instance (struct type *oldtype)
+{
+ struct type *type;
+
+ /* Allocate the structure. */
+
+ if (TYPE_OBJFILE (oldtype) == NULL)
+ {
+ type = xmalloc (sizeof (struct type));
+ memset (type, 0, sizeof (struct type));
+ }
+ else
+ {
+ type = obstack_alloc (&TYPE_OBJFILE (oldtype)->objfile_obstack,
+ sizeof (struct type));
+ memset (type, 0, sizeof (struct type));
+ }
+ TYPE_MAIN_TYPE (type) = TYPE_MAIN_TYPE (oldtype);
+
+ TYPE_CHAIN (type) = type; /* Chain back to itself for now. */
+
+ return (type);
+}
+
+/* Clear all remnants of the previous type at TYPE, in preparation for
+ replacing it with something else. */
+static void
+smash_type (struct type *type)
+{
+ memset (TYPE_MAIN_TYPE (type), 0, sizeof (struct main_type));
+
+ /* For now, delete the rings. */
+ TYPE_CHAIN (type) = type;
+
+ /* For now, leave the pointer/reference types alone. */
+}
+
+/* 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 (struct type *type, struct type **typeptr)
+{
+ 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);
+ smash_type (ntype);
+ 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;
+
+ /* Mark pointers as unsigned. The target converts between pointers
+ and addresses (CORE_ADDRs) using POINTER_TO_ADDRESS() and
+ ADDRESS_TO_POINTER(). */
+ 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 (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 (struct type *type, struct type **typeptr)
+{
+ 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);
+ smash_type (ntype);
+ 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 (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 (struct type *type, struct type **typeptr)
+{
+ 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);
+ smash_type (ntype);
+ 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 (struct type *type)
+{
+ return make_function_type (type, (struct type **) 0);
+}
+
+/* Identify address space identifier by name --
+ return the integer flag defined in gdbtypes.h. */
+extern int
+address_space_name_to_int (char *space_identifier)
+{
+ struct gdbarch *gdbarch = current_gdbarch;
+ int type_flags;
+ /* Check for known address space delimiters. */
+ if (!strcmp (space_identifier, "code"))
+ return TYPE_FLAG_CODE_SPACE;
+ else if (!strcmp (space_identifier, "data"))
+ return TYPE_FLAG_DATA_SPACE;
+ else if (gdbarch_address_class_name_to_type_flags_p (gdbarch)
+ && gdbarch_address_class_name_to_type_flags (gdbarch,
+ space_identifier,
+ &type_flags))
+ return type_flags;
+ else
+ error ("Unknown address space specifier: \"%s\"", space_identifier);
+}
+
+/* Identify address space identifier by integer flag as defined in
+ gdbtypes.h -- return the string version of the adress space name. */
+
+const char *
+address_space_int_to_name (int space_flag)
+{
+ struct gdbarch *gdbarch = current_gdbarch;
+ if (space_flag & TYPE_FLAG_CODE_SPACE)
+ return "code";
+ else if (space_flag & TYPE_FLAG_DATA_SPACE)
+ return "data";
+ else if ((space_flag & TYPE_FLAG_ADDRESS_CLASS_ALL)
+ && gdbarch_address_class_type_flags_to_name_p (gdbarch))
+ return gdbarch_address_class_type_flags_to_name (gdbarch, space_flag);
+ else
+ return NULL;
+}
+
+/* Create a new type with instance flags NEW_FLAGS, based on TYPE.
+ If STORAGE is non-NULL, create the new type instance there. */
+
+static struct type *
+make_qualified_type (struct type *type, int new_flags,
+ struct type *storage)
+{
+ struct type *ntype;
+
+ ntype = type;
+ do {
+ if (TYPE_INSTANCE_FLAGS (ntype) == new_flags)
+ return ntype;
+ ntype = TYPE_CHAIN (ntype);
+ } while (ntype != type);
+
+ /* Create a new type instance. */
+ if (storage == NULL)
+ ntype = alloc_type_instance (type);
+ else
+ {
+ ntype = storage;
+ TYPE_MAIN_TYPE (ntype) = TYPE_MAIN_TYPE (type);
+ TYPE_CHAIN (ntype) = ntype;
+ }
+
+ /* Pointers or references to the original type are not relevant to
+ the new type. */
+ TYPE_POINTER_TYPE (ntype) = (struct type *) 0;
+ TYPE_REFERENCE_TYPE (ntype) = (struct type *) 0;
+
+ /* Chain the new qualified type to the old type. */
+ TYPE_CHAIN (ntype) = TYPE_CHAIN (type);
+ TYPE_CHAIN (type) = ntype;
+
+ /* Now set the instance flags and return the new type. */
+ TYPE_INSTANCE_FLAGS (ntype) = new_flags;
+
+ /* Set length of new type to that of the original type. */
+ TYPE_LENGTH (ntype) = TYPE_LENGTH (type);
+
+ return ntype;
+}
+
+/* Make an address-space-delimited variant of a type -- a type that
+ is identical to the one supplied except that it has an address
+ space attribute attached to it (such as "code" or "data").
+
+ The space attributes "code" and "data" are for Harvard architectures.
+ The address space attributes are for architectures which have
+ alternately sized pointers or pointers with alternate representations. */
+
+struct type *
+make_type_with_address_space (struct type *type, int space_flag)
+{
+ struct type *ntype;
+ int new_flags = ((TYPE_INSTANCE_FLAGS (type)
+ & ~(TYPE_FLAG_CODE_SPACE | TYPE_FLAG_DATA_SPACE
+ | TYPE_FLAG_ADDRESS_CLASS_ALL))
+ | space_flag);
+
+ return make_qualified_type (type, new_flags, NULL);
+}
+
+/* Make a "c-v" variant of a type -- a type that is identical to the
+ one supplied except that it may have const or volatile attributes
+ CNST is a flag for setting the const attribute
+ VOLTL is a flag for setting the volatile attribute
+ TYPE is the base type whose variant we are creating.
+ 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_cv_type (int cnst, int voltl, struct type *type, struct type **typeptr)
+{
+ struct type *ntype; /* New type */
+ struct type *tmp_type = type; /* tmp type */
+ struct objfile *objfile;
+
+ int new_flags = (TYPE_INSTANCE_FLAGS (type)
+ & ~(TYPE_FLAG_CONST | TYPE_FLAG_VOLATILE));
+
+ if (cnst)
+ new_flags |= TYPE_FLAG_CONST;
+
+ if (voltl)
+ new_flags |= TYPE_FLAG_VOLATILE;
+
+ if (typeptr && *typeptr != NULL)
+ {
+ /* Objfile is per-core-type. This const-qualified type had best
+ belong to the same objfile as the type it is qualifying, unless
+ we are overwriting a stub type, in which case the safest thing
+ to do is to copy the core type into the new objfile. */
+
+ gdb_assert (TYPE_OBJFILE (*typeptr) == TYPE_OBJFILE (type)
+ || TYPE_STUB (*typeptr));
+ if (TYPE_OBJFILE (*typeptr) != TYPE_OBJFILE (type))
+ {
+ TYPE_MAIN_TYPE (*typeptr)
+ = TYPE_ALLOC (*typeptr, sizeof (struct main_type));
+ *TYPE_MAIN_TYPE (*typeptr)
+ = *TYPE_MAIN_TYPE (type);
+ }
+ }
+
+ ntype = make_qualified_type (type, new_flags, typeptr ? *typeptr : NULL);
+
+ if (typeptr != NULL)
+ *typeptr = ntype;
+
+ return ntype;
+}
+
+/* Replace the contents of ntype with the type *type. This changes the
+ contents, rather than the pointer for TYPE_MAIN_TYPE (ntype); thus
+ the changes are propogated to all types in the TYPE_CHAIN.
+
+ In order to build recursive types, it's inevitable that we'll need
+ to update types in place --- but this sort of indiscriminate
+ smashing is ugly, and needs to be replaced with something more
+ controlled. TYPE_MAIN_TYPE is a step in this direction; it's not
+ clear if more steps are needed. */
+void
+replace_type (struct type *ntype, struct type *type)
+{
+ struct type *chain;
+
+ *TYPE_MAIN_TYPE (ntype) = *TYPE_MAIN_TYPE (type);
+
+ /* The type length is not a part of the main type. Update it for each
+ type on the variant chain. */
+ chain = ntype;
+ do {
+ /* Assert that this element of the chain has no address-class bits
+ set in its flags. Such type variants might have type lengths
+ which are supposed to be different from the non-address-class
+ variants. This assertion shouldn't ever be triggered because
+ symbol readers which do construct address-class variants don't
+ call replace_type(). */
+ gdb_assert (TYPE_ADDRESS_CLASS_ALL (chain) == 0);
+
+ TYPE_LENGTH (ntype) = TYPE_LENGTH (type);
+ chain = TYPE_CHAIN (chain);
+ } while (ntype != chain);
+
+ /* Assert that the two types have equivalent instance qualifiers.
+ This should be true for at least all of our debug readers. */
+ gdb_assert (TYPE_INSTANCE_FLAGS (ntype) == TYPE_INSTANCE_FLAGS (type));
+}
+
+/* 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 (struct type *type, struct type *domain)
+{
+ 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 (struct type *type)
+{
+ struct type *mtype;
+
+ mtype = init_type (TYPE_CODE_METHOD, 1, TYPE_FLAG_STUB, NULL,
+ TYPE_OBJFILE (type));
+ TYPE_TARGET_TYPE (mtype) = type;
+ /* _DOMAIN_TYPE (mtype) = unknown yet */
+ 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 (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_STUB (index_type))
+ 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 */
+
+ if (low_bound >= 0)
+ TYPE_FLAGS (result_type) |= TYPE_FLAG_UNSIGNED;
+
+ 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 (struct type *type, LONGEST *lowp, LONGEST *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);
+ }
+
+ /* Set unsigned indicator if warranted. */
+ if (*lowp >= 0)
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+ }
+ }
+ 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 (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;
+
+ /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays */
+ if (TYPE_LENGTH (result_type) == 0)
+ TYPE_FLAGS (result_type) |= TYPE_FLAG_TARGET_STUB;
+
+ 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 (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 (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_STUB (domain_type))
+ {
+ 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;
+
+ if (low_bound >= 0)
+ TYPE_FLAGS (result_type) |= TYPE_FLAG_UNSIGNED;
+
+ return (result_type);
+}
+
+/* Construct and return a type of the form:
+ struct NAME { ELT_TYPE ELT_NAME[N]; }
+ We use these types for SIMD registers. For example, the type of
+ the SSE registers on the late x86-family processors is:
+ struct __builtin_v4sf { float f[4]; }
+ built by the function call:
+ init_simd_type ("__builtin_v4sf", builtin_type_float, "f", 4)
+ The type returned is a permanent type, allocated using malloc; it
+ doesn't live in any objfile's obstack. */
+static struct type *
+init_simd_type (char *name,
+ struct type *elt_type,
+ char *elt_name,
+ int n)
+{
+ struct type *simd_type;
+ struct type *array_type;
+
+ simd_type = init_composite_type (name, TYPE_CODE_STRUCT);
+ array_type = create_array_type (0, elt_type,
+ create_range_type (0, builtin_type_int,
+ 0, n-1));
+ append_composite_type_field (simd_type, elt_name, array_type);
+ return simd_type;
+}
+
+static struct type *
+init_vector_type (struct type *elt_type, int n)
+{
+ struct type *array_type;
+
+ array_type = create_array_type (0, elt_type,
+ create_range_type (0, builtin_type_int,
+ 0, n-1));
+ TYPE_FLAGS (array_type) |= TYPE_FLAG_VECTOR;
+ return array_type;
+}
+
+static struct type *
+build_builtin_type_vec64 (void)
+{
+ /* Construct a type for the 64 bit registers. The type we're
+ building is this: */
+#if 0
+ union __gdb_builtin_type_vec64
+ {
+ int64_t uint64;
+ float v2_float[2];
+ int32_t v2_int32[2];
+ int16_t v4_int16[4];
+ int8_t v8_int8[8];
+ };
+#endif
+
+ struct type *t;
+
+ t = init_composite_type ("__gdb_builtin_type_vec64", TYPE_CODE_UNION);
+ append_composite_type_field (t, "uint64", builtin_type_int64);
+ append_composite_type_field (t, "v2_float", builtin_type_v2_float);
+ append_composite_type_field (t, "v2_int32", builtin_type_v2_int32);
+ append_composite_type_field (t, "v4_int16", builtin_type_v4_int16);
+ append_composite_type_field (t, "v8_int8", builtin_type_v8_int8);
+
+ TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (t) = "builtin_type_vec64";
+ return t;
+}
+
+static struct type *
+build_builtin_type_vec64i (void)
+{
+ /* Construct a type for the 64 bit registers. The type we're
+ building is this: */
+#if 0
+ union __gdb_builtin_type_vec64i
+ {
+ int64_t uint64;
+ int32_t v2_int32[2];
+ int16_t v4_int16[4];
+ int8_t v8_int8[8];
+ };
+#endif
+
+ struct type *t;
+
+ t = init_composite_type ("__gdb_builtin_type_vec64i", TYPE_CODE_UNION);
+ append_composite_type_field (t, "uint64", builtin_type_int64);
+ append_composite_type_field (t, "v2_int32", builtin_type_v2_int32);
+ append_composite_type_field (t, "v4_int16", builtin_type_v4_int16);
+ append_composite_type_field (t, "v8_int8", builtin_type_v8_int8);
+
+ TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (t) = "builtin_type_vec64i";
+ return t;
+}
+
+static struct type *
+build_builtin_type_vec128 (void)
+{
+ /* Construct a type for the 128 bit registers. The type we're
+ building is this: */
+#if 0
+ union __gdb_builtin_type_vec128
+ {
+ int128_t uint128;
+ float v4_float[4];
+ int32_t v4_int32[4];
+ int16_t v8_int16[8];
+ int8_t v16_int8[16];
+ };
+#endif
+
+ struct type *t;
+
+ t = init_composite_type ("__gdb_builtin_type_vec128", TYPE_CODE_UNION);
+ append_composite_type_field (t, "uint128", builtin_type_int128);
+ append_composite_type_field (t, "v4_float", builtin_type_v4_float);
+ append_composite_type_field (t, "v4_int32", builtin_type_v4_int32);
+ append_composite_type_field (t, "v8_int16", builtin_type_v8_int16);
+ append_composite_type_field (t, "v16_int8", builtin_type_v16_int8);
+
+ TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (t) = "builtin_type_vec128";
+ return t;
+}
+
+static struct type *
+build_builtin_type_vec128i (void)
+{
+ /* 128-bit Intel SIMD registers */
+ struct type *t;
+
+ t = init_composite_type ("__gdb_builtin_type_vec128i", TYPE_CODE_UNION);
+ append_composite_type_field (t, "v4_float", builtin_type_v4_float);
+ append_composite_type_field (t, "v2_double", builtin_type_v2_double);
+ append_composite_type_field (t, "v16_int8", builtin_type_v16_int8);
+ append_composite_type_field (t, "v8_int16", builtin_type_v8_int16);
+ append_composite_type_field (t, "v4_int32", builtin_type_v4_int32);
+ append_composite_type_field (t, "v2_int64", builtin_type_v2_int64);
+ append_composite_type_field (t, "uint128", builtin_type_int128);
+
+ TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (t) = "builtin_type_vec128i";
+ return t;
+}
+
+/* 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 (struct type *type, struct type *domain,
+ struct type *to_type)
+{
+ struct objfile *objfile;
+
+ objfile = TYPE_OBJFILE (type);
+
+ smash_type (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 (struct type *type, struct type *domain,
+ struct type *to_type, struct field *args,
+ int nargs, int varargs)
+{
+ struct objfile *objfile;
+
+ objfile = TYPE_OBJFILE (type);
+
+ smash_type (type);
+ TYPE_OBJFILE (type) = objfile;
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+ TYPE_FIELDS (type) = args;
+ TYPE_NFIELDS (type) = nargs;
+ if (varargs)
+ TYPE_FLAGS (type) |= TYPE_FLAG_VARARGS;
+ 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 (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 (char *name)
+{
+ struct type **const *p;
+
+ for (p = current_language->la_builtin_type_vector; *p != NULL; p++)
+ {
+ if (strcmp (TYPE_NAME (**p), name) == 0)
+ {
+ 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 (char *name, struct block *block, int noerr)
+{
+ struct symbol *sym;
+ struct type *tmp;
+
+ sym = lookup_symbol (name, block, VAR_DOMAIN, 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 (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 (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 (char *name, struct block *block)
+{
+ struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_DOMAIN, 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 (char *name, struct block *block)
+{
+ struct symbol *sym;
+ struct type *t;
+
+ sym = lookup_symbol (name, block, STRUCT_DOMAIN, 0,
+ (struct symtab **) NULL);
+
+ if (sym == NULL)
+ error ("No union type named %s.", name);
+
+ t = SYMBOL_TYPE (sym);
+
+ if (TYPE_CODE (t) == TYPE_CODE_UNION)
+ return (t);
+
+ /* C++ unions may come out with TYPE_CODE_CLASS, but we look at
+ * a further "declared_type" field to discover it is really a union.
+ */
+ if (HAVE_CPLUS_STRUCT (t))
+ if (TYPE_DECLARED_TYPE (t) == DECLARED_TYPE_UNION)
+ return (t);
+
+ /* If we get here, it's not a union */
+ error ("This context has class, struct or enum %s, not a union.", name);
+}
+
+
+/* Lookup an enum type named "enum NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_enum (char *name, struct block *block)
+{
+ struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_DOMAIN, 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<TYPE>",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_template_type (char *name, struct type *type, struct block *block)
+{
+ struct symbol *sym;
+ char *nam = (char *) alloca (strlen (name) + strlen (TYPE_NAME (type)) + 4);
+ strcpy (nam, name);
+ strcat (nam, "<");
+ strcat (nam, TYPE_NAME (type));
+ strcat (nam, " >"); /* FIXME, extra space still introduced in gcc? */
+
+ sym = lookup_symbol (nam, block, VAR_DOMAIN, 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 (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 && strcmp (typename, name) == 0)
+ 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 && (strcmp_iw (t_field_name, name) == 0))
+ {
+ 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 (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++)
+ {
+ struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
+ fill_in_vptr_fieldno (baseclass);
+ if (TYPE_VPTR_FIELDNO (baseclass) >= 0)
+ {
+ TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (baseclass);
+ TYPE_VPTR_BASETYPE (type) = TYPE_VPTR_BASETYPE (baseclass);
+ break;
+ }
+ }
+ }
+}
+
+/* Find the method and field indices for the destructor in class type T.
+ Return 1 if the destructor was found, otherwise, return 0. */
+
+int
+get_destructor_fn_field (struct type *t, int *method_indexp, int *field_indexp)
+{
+ int i;
+
+ for (i = 0; i < TYPE_NFN_FIELDS (t); i++)
+ {
+ int j;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ for (j = 0; j < TYPE_FN_FIELDLIST_LENGTH (t, i); j++)
+ {
+ if (is_destructor_name (TYPE_FN_FIELD_PHYSNAME (f, j)) != 0)
+ {
+ *method_indexp = i;
+ *field_indexp = j;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static void
+stub_noname_complaint (void)
+{
+ complaint (&symfile_complaints, "stub type has NULL name");
+}
+
+/* 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. */
+
+/* Find the real type of TYPE. This function returns the real type, after
+ removing all layers of typedefs and completing opaque or stub types.
+ Completion changes the TYPE argument, but stripping of typedefs does
+ not. */
+
+struct type *
+check_typedef (struct type *type)
+{
+ struct type *orig_type = type;
+ int is_const, is_volatile;
+
+ 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_DOMAIN and/or VAR_DOMAIN
+ as appropriate? (this code was written before TYPE_NAME and
+ TYPE_TAG_NAME were separate). */
+ if (name == NULL)
+ {
+ stub_noname_complaint ();
+ return type;
+ }
+ sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 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);
+ }
+
+ is_const = TYPE_CONST (type);
+ is_volatile = TYPE_VOLATILE (type);
+
+ /* If this is a struct/class/union with no fields, then check whether a
+ full definition exists somewhere else. This is for systems where a
+ type definition with no fields is issued for such types, instead of
+ identifying them as stub types in the first place */
+
+ if (TYPE_IS_OPAQUE (type) && opaque_type_resolution && !currently_reading_symtab)
+ {
+ char *name = type_name_no_tag (type);
+ struct type *newtype;
+ if (name == NULL)
+ {
+ stub_noname_complaint ();
+ return type;
+ }
+ newtype = lookup_transparent_type (name);
+ if (newtype)
+ make_cv_type (is_const, is_volatile, newtype, &type);
+ }
+ /* Otherwise, rely on the stub flag being set for opaque/stubbed types */
+ else if (TYPE_STUB (type) && !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_DOMAIN and/or VAR_DOMAIN
+ as appropriate? (this code was written before TYPE_NAME and
+ TYPE_TAG_NAME were separate). */
+ struct symbol *sym;
+ if (name == NULL)
+ {
+ stub_noname_complaint ();
+ return type;
+ }
+ sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0, (struct symtab **) NULL);
+ if (sym)
+ make_cv_type (is_const, is_volatile, SYMBOL_TYPE (sym), &type);
+ }
+
+ if (TYPE_TARGET_STUB (type))
+ {
+ struct type *range_type;
+ struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
+
+ if (TYPE_STUB (target_type) || TYPE_TARGET_STUB (target_type))
+ {
+ }
+ 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;
+}
+
+/* Parse a type expression in the string [P..P+LENGTH). If an error occurs,
+ silently return builtin_type_void. */
+
+static struct type *
+safe_parse_type (char *p, int length)
+{
+ struct ui_file *saved_gdb_stderr;
+ struct type *type;
+
+ /* Suppress error messages. */
+ saved_gdb_stderr = gdb_stderr;
+ gdb_stderr = ui_file_new ();
+
+ /* Call parse_and_eval_type() without fear of longjmp()s. */
+ if (!gdb_parse_and_eval_type (p, length, &type))
+ type = builtin_type_void;
+
+ /* Stop suppressing error messages. */
+ ui_file_delete (gdb_stderr);
+ gdb_stderr = saved_gdb_stderr;
+
+ 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. */
+
+static void
+check_stub_method (struct type *type, int method_id, int signature_id)
+{
+ struct fn_field *f;
+ char *mangled_name = gdb_mangle_name (type, method_id, signature_id);
+ char *demangled_name = cplus_demangle (mangled_name,
+ DMGL_PARAMS | DMGL_ANSI);
+ char *argtypetext, *p;
+ int depth = 0, argcount = 1;
+ struct field *argtypes;
+ struct type *mtype;
+
+ /* Make sure we got back a function string that we can use. */
+ if (demangled_name)
+ p = strchr (demangled_name, '(');
+ else
+ p = NULL;
+
+ 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 == '(' || *p == '<')
+ {
+ depth += 1;
+ }
+ else if (*p == ')' || *p == '>')
+ {
+ depth -= 1;
+ }
+ else if (*p == ',' && depth == 0)
+ {
+ argcount += 1;
+ }
+
+ p += 1;
+ }
+
+ /* If we read one argument and it was ``void'', don't count it. */
+ if (strncmp (argtypetext, "(void)", 6) == 0)
+ argcount -= 1;
+
+ /* We need one extra slot, for the THIS pointer. */
+
+ argtypes = (struct field *)
+ TYPE_ALLOC (type, (argcount + 1) * sizeof (struct field));
+ p = argtypetext;
+
+ /* Add THIS pointer for non-static methods. */
+ f = TYPE_FN_FIELDLIST1 (type, method_id);
+ if (TYPE_FN_FIELD_STATIC_P (f, signature_id))
+ argcount = 0;
+ else
+ {
+ argtypes[0].type = 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.
+ Also avoid ``void'' as above. */
+ if (strncmp (argtypetext, "...", p - argtypetext) != 0
+ && strncmp (argtypetext, "void", p - argtypetext) != 0)
+ {
+ argtypes[argcount].type =
+ safe_parse_type (argtypetext, p - argtypetext);
+ argcount += 1;
+ }
+ argtypetext = p + 1;
+ }
+
+ if (*p == '(' || *p == '<')
+ {
+ depth += 1;
+ }
+ else if (*p == ')' || *p == '>')
+ {
+ depth -= 1;
+ }
+
+ p += 1;
+ }
+ }
+
+ TYPE_FN_FIELD_PHYSNAME (f, signature_id) = mangled_name;
+
+ /* Now update the old "stub" type into a real type. */
+ mtype = TYPE_FN_FIELD_TYPE (f, signature_id);
+ TYPE_DOMAIN_TYPE (mtype) = type;
+ TYPE_FIELDS (mtype) = argtypes;
+ TYPE_NFIELDS (mtype) = argcount;
+ TYPE_FLAGS (mtype) &= ~TYPE_FLAG_STUB;
+ TYPE_FN_FIELD_STUB (f, signature_id) = 0;
+ if (p[-2] == '.')
+ TYPE_FLAGS (mtype) |= TYPE_FLAG_VARARGS;
+
+ xfree (demangled_name);
+}
+
+/* This is the external interface to check_stub_method, above. This function
+ unstubs all of the signatures for TYPE's METHOD_ID method name. After
+ calling this function TYPE_FN_FIELD_STUB will be cleared for each signature
+ and TYPE_FN_FIELDLIST_NAME will be correct.
+
+ This function unfortunately can not die until stabs do. */
+
+void
+check_stub_method_group (struct type *type, int method_id)
+{
+ int len = TYPE_FN_FIELDLIST_LENGTH (type, method_id);
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, method_id);
+ int j, found_stub = 0;
+
+ for (j = 0; j < len; j++)
+ if (TYPE_FN_FIELD_STUB (f, j))
+ {
+ found_stub = 1;
+ check_stub_method (type, method_id, j);
+ }
+
+ /* GNU v3 methods with incorrect names were corrected when we read in
+ type information, because it was cheaper to do it then. The only GNU v2
+ methods with incorrect method names are operators and destructors;
+ destructors were also corrected when we read in type information.
+
+ Therefore the only thing we need to handle here are v2 operator
+ names. */
+ if (found_stub && strncmp (TYPE_FN_FIELD_PHYSNAME (f, 0), "_Z", 2) != 0)
+ {
+ int ret;
+ char dem_opname[256];
+
+ ret = cplus_demangle_opname (TYPE_FN_FIELDLIST_NAME (type, method_id),
+ dem_opname, DMGL_ANSI);
+ if (!ret)
+ ret = cplus_demangle_opname (TYPE_FN_FIELDLIST_NAME (type, method_id),
+ dem_opname, 0);
+ if (ret)
+ TYPE_FN_FIELDLIST_NAME (type, method_id) = xstrdup (dem_opname);
+ }
+}
+
+const struct cplus_struct_type cplus_struct_default;
+
+void
+allocate_cplus_struct_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 objfile_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 (enum type_code code, int length, int flags, char *name,
+ struct objfile *objfile)
+{
+ 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->objfile_obstack);
+ }
+ else
+ {
+ TYPE_NAME (type) = name;
+ }
+
+ /* C++ fancies. */
+
+ if (name && strcmp (name, "char") == 0)
+ TYPE_FLAGS (type) |= TYPE_FLAG_NOSIGN;
+
+ if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION
+ || code == TYPE_CODE_NAMESPACE)
+ {
+ INIT_CPLUS_SPECIFIC (type);
+ }
+ return (type);
+}
+
+/* Helper function. Create an empty composite type. */
+
+struct type *
+init_composite_type (char *name, enum type_code code)
+{
+ struct type *t;
+ gdb_assert (code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION);
+ t = init_type (code, 0, 0, NULL, NULL);
+ TYPE_TAG_NAME (t) = name;
+ return t;
+}
+
+/* Helper function. Append a field to a composite type. */
+
+void
+append_composite_type_field (struct type *t, char *name, struct type *field)
+{
+ struct field *f;
+ TYPE_NFIELDS (t) = TYPE_NFIELDS (t) + 1;
+ TYPE_FIELDS (t) = xrealloc (TYPE_FIELDS (t),
+ sizeof (struct field) * TYPE_NFIELDS (t));
+ f = &(TYPE_FIELDS (t)[TYPE_NFIELDS (t) - 1]);
+ memset (f, 0, sizeof f[0]);
+ FIELD_TYPE (f[0]) = field;
+ FIELD_NAME (f[0]) = name;
+ if (TYPE_CODE (t) == TYPE_CODE_UNION)
+ {
+ if (TYPE_LENGTH (t) < TYPE_LENGTH (field))
+ TYPE_LENGTH (t) = TYPE_LENGTH (field);
+ }
+ else if (TYPE_CODE (t) == TYPE_CODE_STRUCT)
+ {
+ TYPE_LENGTH (t) = TYPE_LENGTH (t) + TYPE_LENGTH (field);
+ if (TYPE_NFIELDS (t) > 1)
+ {
+ FIELD_BITPOS (f[0]) = (FIELD_BITPOS (f[-1])
+ + TYPE_LENGTH (field) * TARGET_CHAR_BIT);
+ }
+ }
+}
+
+/* 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 (struct objfile *objfile, int typeid)
+{
+ struct type **typep;
+ 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->objfile_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 (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);
+}
+
+int
+is_integral_type (struct type *t)
+{
+ CHECK_TYPEDEF (t);
+ return
+ ((t != NULL)
+ && ((TYPE_CODE (t) == TYPE_CODE_INT)
+ || (TYPE_CODE (t) == TYPE_CODE_ENUM)
+ || (TYPE_CODE (t) == TYPE_CODE_CHAR)
+ || (TYPE_CODE (t) == TYPE_CODE_RANGE)
+ || (TYPE_CODE (t) == TYPE_CODE_BOOL)));
+}
+
+/* Check whether BASE is an ancestor or base class or DCLASS
+ Return 1 if so, and 0 if not.
+ Note: callers may want to check for identity of the types before
+ calling this function -- identical types are considered to satisfy
+ the ancestor relationship even if they're identical */
+
+int
+is_ancestor (struct type *base, struct type *dclass)
+{
+ int i;
+
+ CHECK_TYPEDEF (base);
+ CHECK_TYPEDEF (dclass);
+
+ if (base == dclass)
+ return 1;
+ if (TYPE_NAME (base) && TYPE_NAME (dclass) &&
+ !strcmp (TYPE_NAME (base), TYPE_NAME (dclass)))
+ return 1;
+
+ for (i = 0; i < TYPE_N_BASECLASSES (dclass); i++)
+ if (is_ancestor (base, TYPE_BASECLASS (dclass, i)))
+ return 1;
+
+ return 0;
+}
+
+
+
+/* See whether DCLASS has a virtual table. This routine is aimed at
+ the HP/Taligent ANSI C++ runtime model, and may not work with other
+ runtime models. Return 1 => Yes, 0 => No. */
+
+int
+has_vtable (struct type *dclass)
+{
+ /* In the HP ANSI C++ runtime model, a class has a vtable only if it
+ has virtual functions or virtual bases. */
+
+ int i;
+
+ if (TYPE_CODE (dclass) != TYPE_CODE_CLASS)
+ return 0;
+
+ /* First check for the presence of virtual bases */
+ if (TYPE_FIELD_VIRTUAL_BITS (dclass))
+ for (i = 0; i < TYPE_N_BASECLASSES (dclass); i++)
+ if (B_TST (TYPE_FIELD_VIRTUAL_BITS (dclass), i))
+ return 1;
+
+ /* Next check for virtual functions */
+ if (TYPE_FN_FIELDLISTS (dclass))
+ for (i = 0; i < TYPE_NFN_FIELDS (dclass); i++)
+ if (TYPE_FN_FIELD_VIRTUAL_P (TYPE_FN_FIELDLIST1 (dclass, i), 0))
+ return 1;
+
+ /* Recurse on non-virtual bases to see if any of them needs a vtable */
+ if (TYPE_FIELD_VIRTUAL_BITS (dclass))
+ for (i = 0; i < TYPE_N_BASECLASSES (dclass); i++)
+ if ((!B_TST (TYPE_FIELD_VIRTUAL_BITS (dclass), i)) &&
+ (has_vtable (TYPE_FIELD_TYPE (dclass, i))))
+ return 1;
+
+ /* Well, maybe we don't need a virtual table */
+ return 0;
+}
+
+/* Return a pointer to the "primary base class" of DCLASS.
+
+ A NULL return indicates that DCLASS has no primary base, or that it
+ couldn't be found (insufficient information).
+
+ This routine is aimed at the HP/Taligent ANSI C++ runtime model,
+ and may not work with other runtime models. */
+
+struct type *
+primary_base_class (struct type *dclass)
+{
+ /* In HP ANSI C++'s runtime model, a "primary base class" of a class
+ is the first directly inherited, non-virtual base class that
+ requires a virtual table */
+
+ int i;
+
+ if (TYPE_CODE (dclass) != TYPE_CODE_CLASS)
+ return NULL;
+
+ for (i = 0; i < TYPE_N_BASECLASSES (dclass); i++)
+ if (!TYPE_FIELD_VIRTUAL (dclass, i) &&
+ has_vtable (TYPE_FIELD_TYPE (dclass, i)))
+ return TYPE_FIELD_TYPE (dclass, i);
+
+ return NULL;
+}
+
+/* Global manipulated by virtual_base_list[_aux]() */
+
+static struct vbase *current_vbase_list = NULL;
+
+/* Return a pointer to a null-terminated list of struct vbase
+ items. The vbasetype pointer of each item in the list points to the
+ type information for a virtual base of the argument DCLASS.
+
+ Helper function for virtual_base_list().
+ Note: the list goes backward, right-to-left. virtual_base_list()
+ copies the items out in reverse order. */
+
+static void
+virtual_base_list_aux (struct type *dclass)
+{
+ struct vbase *tmp_vbase;
+ int i;
+
+ if (TYPE_CODE (dclass) != TYPE_CODE_CLASS)
+ return;
+
+ for (i = 0; i < TYPE_N_BASECLASSES (dclass); i++)
+ {
+ /* Recurse on this ancestor, first */
+ virtual_base_list_aux (TYPE_FIELD_TYPE (dclass, i));
+
+ /* If this current base is itself virtual, add it to the list */
+ if (BASETYPE_VIA_VIRTUAL (dclass, i))
+ {
+ struct type *basetype = TYPE_FIELD_TYPE (dclass, i);
+
+ /* Check if base already recorded */
+ tmp_vbase = current_vbase_list;
+ while (tmp_vbase)
+ {
+ if (tmp_vbase->vbasetype == basetype)
+ break; /* found it */
+ tmp_vbase = tmp_vbase->next;
+ }
+
+ if (!tmp_vbase) /* normal exit from loop */
+ {
+ /* Allocate new item for this virtual base */
+ tmp_vbase = (struct vbase *) xmalloc (sizeof (struct vbase));
+
+ /* Stick it on at the end of the list */
+ tmp_vbase->vbasetype = basetype;
+ tmp_vbase->next = current_vbase_list;
+ current_vbase_list = tmp_vbase;
+ }
+ } /* if virtual */
+ } /* for loop over bases */
+}
+
+
+/* Compute the list of virtual bases in the right order. Virtual
+ bases are laid out in the object's memory area in order of their
+ occurrence in a depth-first, left-to-right search through the
+ ancestors.
+
+ Argument DCLASS is the type whose virtual bases are required.
+ Return value is the address of a null-terminated array of pointers
+ to struct type items.
+
+ This routine is aimed at the HP/Taligent ANSI C++ runtime model,
+ and may not work with other runtime models.
+
+ This routine merely hands off the argument to virtual_base_list_aux()
+ and then copies the result into an array to save space. */
+
+struct type **
+virtual_base_list (struct type *dclass)
+{
+ struct vbase *tmp_vbase;
+ struct vbase *tmp_vbase_2;
+ int i;
+ int count;
+ struct type **vbase_array;
+
+ current_vbase_list = NULL;
+ virtual_base_list_aux (dclass);
+
+ for (i = 0, tmp_vbase = current_vbase_list; tmp_vbase != NULL; i++, tmp_vbase = tmp_vbase->next)
+ /* no body */ ;
+
+ count = i;
+
+ vbase_array = (struct type **) xmalloc ((count + 1) * sizeof (struct type *));
+
+ for (i = count - 1, tmp_vbase = current_vbase_list; i >= 0; i--, tmp_vbase = tmp_vbase->next)
+ vbase_array[i] = tmp_vbase->vbasetype;
+
+ /* Get rid of constructed chain */
+ tmp_vbase_2 = tmp_vbase = current_vbase_list;
+ while (tmp_vbase)
+ {
+ tmp_vbase = tmp_vbase->next;
+ xfree (tmp_vbase_2);
+ tmp_vbase_2 = tmp_vbase;
+ }
+
+ vbase_array[count] = NULL;
+ return vbase_array;
+}
+
+/* Return the length of the virtual base list of the type DCLASS. */
+
+int
+virtual_base_list_length (struct type *dclass)
+{
+ int i;
+ struct vbase *tmp_vbase;
+
+ current_vbase_list = NULL;
+ virtual_base_list_aux (dclass);
+
+ for (i = 0, tmp_vbase = current_vbase_list; tmp_vbase != NULL; i++, tmp_vbase = tmp_vbase->next)
+ /* no body */ ;
+ return i;
+}
+
+/* Return the number of elements of the virtual base list of the type
+ DCLASS, ignoring those appearing in the primary base (and its
+ primary base, recursively). */
+
+int
+virtual_base_list_length_skip_primaries (struct type *dclass)
+{
+ int i;
+ struct vbase *tmp_vbase;
+ struct type *primary;
+
+ primary = TYPE_RUNTIME_PTR (dclass) ? TYPE_PRIMARY_BASE (dclass) : NULL;
+
+ if (!primary)
+ return virtual_base_list_length (dclass);
+
+ current_vbase_list = NULL;
+ virtual_base_list_aux (dclass);
+
+ for (i = 0, tmp_vbase = current_vbase_list; tmp_vbase != NULL; tmp_vbase = tmp_vbase->next)
+ {
+ if (virtual_base_index (tmp_vbase->vbasetype, primary) >= 0)
+ continue;
+ i++;
+ }
+ return i;
+}
+
+
+/* Return the index (position) of type BASE, which is a virtual base
+ class of DCLASS, in the latter's virtual base list. A return of -1
+ indicates "not found" or a problem. */
+
+int
+virtual_base_index (struct type *base, struct type *dclass)
+{
+ struct type *vbase;
+ int i;
+
+ if ((TYPE_CODE (dclass) != TYPE_CODE_CLASS) ||
+ (TYPE_CODE (base) != TYPE_CODE_CLASS))
+ return -1;
+
+ i = 0;
+ vbase = virtual_base_list (dclass)[0];
+ while (vbase)
+ {
+ if (vbase == base)
+ break;
+ vbase = virtual_base_list (dclass)[++i];
+ }
+
+ return vbase ? i : -1;
+}
+
+
+
+/* Return the index (position) of type BASE, which is a virtual base
+ class of DCLASS, in the latter's virtual base list. Skip over all
+ bases that may appear in the virtual base list of the primary base
+ class of DCLASS (recursively). A return of -1 indicates "not
+ found" or a problem. */
+
+int
+virtual_base_index_skip_primaries (struct type *base, struct type *dclass)
+{
+ struct type *vbase;
+ int i, j;
+ struct type *primary;
+
+ if ((TYPE_CODE (dclass) != TYPE_CODE_CLASS) ||
+ (TYPE_CODE (base) != TYPE_CODE_CLASS))
+ return -1;
+
+ primary = TYPE_RUNTIME_PTR (dclass) ? TYPE_PRIMARY_BASE (dclass) : NULL;
+
+ j = -1;
+ i = 0;
+ vbase = virtual_base_list (dclass)[0];
+ while (vbase)
+ {
+ if (!primary || (virtual_base_index_skip_primaries (vbase, primary) < 0))
+ j++;
+ if (vbase == base)
+ break;
+ vbase = virtual_base_list (dclass)[++i];
+ }
+
+ return vbase ? j : -1;
+}
+
+/* Return position of a derived class DCLASS in the list of
+ * primary bases starting with the remotest ancestor.
+ * Position returned is 0-based. */
+
+int
+class_index_in_primary_list (struct type *dclass)
+{
+ struct type *pbc; /* primary base class */
+
+ /* Simply recurse on primary base */
+ pbc = TYPE_PRIMARY_BASE (dclass);
+ if (pbc)
+ return 1 + class_index_in_primary_list (pbc);
+ else
+ return 0;
+}
+
+/* Return a count of the number of virtual functions a type has.
+ * This includes all the virtual functions it inherits from its
+ * base classes too.
+ */
+
+/* pai: FIXME This doesn't do the right thing: count redefined virtual
+ * functions only once (latest redefinition)
+ */
+
+int
+count_virtual_fns (struct type *dclass)
+{
+ int fn, oi; /* function and overloaded instance indices */
+ int vfuncs; /* count to return */
+
+ /* recurse on bases that can share virtual table */
+ struct type *pbc = primary_base_class (dclass);
+ if (pbc)
+ vfuncs = count_virtual_fns (pbc);
+ else
+ vfuncs = 0;
+
+ for (fn = 0; fn < TYPE_NFN_FIELDS (dclass); fn++)
+ for (oi = 0; oi < TYPE_FN_FIELDLIST_LENGTH (dclass, fn); oi++)
+ if (TYPE_FN_FIELD_VIRTUAL_P (TYPE_FN_FIELDLIST1 (dclass, fn), oi))
+ vfuncs++;
+
+ return vfuncs;
+}
+
+
+
+/* Functions for overload resolution begin here */
+
+/* Compare two badness vectors A and B and return the result.
+ * 0 => A and B are identical
+ * 1 => A and B are incomparable
+ * 2 => A is better than B
+ * 3 => A is worse than B */
+
+int
+compare_badness (struct badness_vector *a, struct badness_vector *b)
+{
+ int i;
+ int tmp;
+ short found_pos = 0; /* any positives in c? */
+ short found_neg = 0; /* any negatives in c? */
+
+ /* differing lengths => incomparable */
+ if (a->length != b->length)
+ return 1;
+
+ /* Subtract b from a */
+ for (i = 0; i < a->length; i++)
+ {
+ tmp = a->rank[i] - b->rank[i];
+ if (tmp > 0)
+ found_pos = 1;
+ else if (tmp < 0)
+ found_neg = 1;
+ }
+
+ if (found_pos)
+ {
+ if (found_neg)
+ return 1; /* incomparable */
+ else
+ return 3; /* A > B */
+ }
+ else
+ /* no positives */
+ {
+ if (found_neg)
+ return 2; /* A < B */
+ else
+ return 0; /* A == B */
+ }
+}
+
+/* Rank a function by comparing its parameter types (PARMS, length NPARMS),
+ * to the types of an argument list (ARGS, length NARGS).
+ * Return a pointer to a badness vector. This has NARGS + 1 entries. */
+
+struct badness_vector *
+rank_function (struct type **parms, int nparms, struct type **args, int nargs)
+{
+ int i;
+ struct badness_vector *bv;
+ int min_len = nparms < nargs ? nparms : nargs;
+
+ bv = xmalloc (sizeof (struct badness_vector));
+ bv->length = nargs + 1; /* add 1 for the length-match rank */
+ bv->rank = xmalloc ((nargs + 1) * sizeof (int));
+
+ /* First compare the lengths of the supplied lists.
+ * If there is a mismatch, set it to a high value. */
+
+ /* pai/1997-06-03 FIXME: when we have debug info about default
+ * arguments and ellipsis parameter lists, we should consider those
+ * and rank the length-match more finely. */
+
+ LENGTH_MATCH (bv) = (nargs != nparms) ? LENGTH_MISMATCH_BADNESS : 0;
+
+ /* Now rank all the parameters of the candidate function */
+ for (i = 1; i <= min_len; i++)
+ bv->rank[i] = rank_one_type (parms[i-1], args[i-1]);
+
+ /* If more arguments than parameters, add dummy entries */
+ for (i = min_len + 1; i <= nargs; i++)
+ bv->rank[i] = TOO_FEW_PARAMS_BADNESS;
+
+ return bv;
+}
+
+/* Compare the names of two integer types, assuming that any sign
+ qualifiers have been checked already. We do it this way because
+ there may be an "int" in the name of one of the types. */
+
+static int
+integer_types_same_name_p (const char *first, const char *second)
+{
+ int first_p, second_p;
+
+ /* If both are shorts, return 1; if neither is a short, keep checking. */
+ first_p = (strstr (first, "short") != NULL);
+ second_p = (strstr (second, "short") != NULL);
+ if (first_p && second_p)
+ return 1;
+ if (first_p || second_p)
+ return 0;
+
+ /* Likewise for long. */
+ first_p = (strstr (first, "long") != NULL);
+ second_p = (strstr (second, "long") != NULL);
+ if (first_p && second_p)
+ return 1;
+ if (first_p || second_p)
+ return 0;
+
+ /* Likewise for char. */
+ first_p = (strstr (first, "char") != NULL);
+ second_p = (strstr (second, "char") != NULL);
+ if (first_p && second_p)
+ return 1;
+ if (first_p || second_p)
+ return 0;
+
+ /* They must both be ints. */
+ return 1;
+}
+
+/* Compare one type (PARM) for compatibility with another (ARG).
+ * PARM is intended to be the parameter type of a function; and
+ * ARG is the supplied argument's type. This function tests if
+ * the latter can be converted to the former.
+ *
+ * Return 0 if they are identical types;
+ * Otherwise, return an integer which corresponds to how compatible
+ * PARM is to ARG. The higher the return value, the worse the match.
+ * Generally the "bad" conversions are all uniformly assigned a 100 */
+
+int
+rank_one_type (struct type *parm, struct type *arg)
+{
+ /* Identical type pointers */
+ /* However, this still doesn't catch all cases of same type for arg
+ * and param. The reason is that builtin types are different from
+ * the same ones constructed from the object. */
+ if (parm == arg)
+ return 0;
+
+ /* Resolve typedefs */
+ if (TYPE_CODE (parm) == TYPE_CODE_TYPEDEF)
+ parm = check_typedef (parm);
+ if (TYPE_CODE (arg) == TYPE_CODE_TYPEDEF)
+ arg = check_typedef (arg);
+
+ /*
+ Well, damnit, if the names are exactly the same,
+ i'll say they are exactly the same. This happens when we generate
+ method stubs. The types won't point to the same address, but they
+ really are the same.
+ */
+
+ if (TYPE_NAME (parm) && TYPE_NAME (arg) &&
+ !strcmp (TYPE_NAME (parm), TYPE_NAME (arg)))
+ return 0;
+
+ /* Check if identical after resolving typedefs */
+ if (parm == arg)
+ return 0;
+
+ /* See through references, since we can almost make non-references
+ references. */
+ if (TYPE_CODE (arg) == TYPE_CODE_REF)
+ return (rank_one_type (parm, TYPE_TARGET_TYPE (arg))
+ + REFERENCE_CONVERSION_BADNESS);
+ if (TYPE_CODE (parm) == TYPE_CODE_REF)
+ return (rank_one_type (TYPE_TARGET_TYPE (parm), arg)
+ + REFERENCE_CONVERSION_BADNESS);
+ if (overload_debug)
+ /* Debugging only. */
+ fprintf_filtered (gdb_stderr,"------ Arg is %s [%d], parm is %s [%d]\n",
+ TYPE_NAME (arg), TYPE_CODE (arg), TYPE_NAME (parm), TYPE_CODE (parm));
+
+ /* x -> y means arg of type x being supplied for parameter of type y */
+
+ switch (TYPE_CODE (parm))
+ {
+ case TYPE_CODE_PTR:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_PTR:
+ if (TYPE_CODE (TYPE_TARGET_TYPE (parm)) == TYPE_CODE_VOID)
+ return VOID_PTR_CONVERSION_BADNESS;
+ else
+ return rank_one_type (TYPE_TARGET_TYPE (parm), TYPE_TARGET_TYPE (arg));
+ case TYPE_CODE_ARRAY:
+ return rank_one_type (TYPE_TARGET_TYPE (parm), TYPE_TARGET_TYPE (arg));
+ case TYPE_CODE_FUNC:
+ return rank_one_type (TYPE_TARGET_TYPE (parm), arg);
+ case TYPE_CODE_INT:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BOOL:
+ return POINTER_CONVERSION_BADNESS;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ case TYPE_CODE_ARRAY:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_ARRAY:
+ return rank_one_type (TYPE_TARGET_TYPE (parm), TYPE_TARGET_TYPE (arg));
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ case TYPE_CODE_FUNC:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_PTR: /* funcptr -> func */
+ return rank_one_type (parm, TYPE_TARGET_TYPE (arg));
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ case TYPE_CODE_INT:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_INT:
+ if (TYPE_LENGTH (arg) == TYPE_LENGTH (parm))
+ {
+ /* Deal with signed, unsigned, and plain chars and
+ signed and unsigned ints */
+ if (TYPE_NOSIGN (parm))
+ {
+ /* This case only for character types */
+ if (TYPE_NOSIGN (arg)) /* plain char -> plain char */
+ return 0;
+ else
+ return INTEGER_CONVERSION_BADNESS; /* signed/unsigned char -> plain char */
+ }
+ else if (TYPE_UNSIGNED (parm))
+ {
+ if (TYPE_UNSIGNED (arg))
+ {
+ /* unsigned int -> unsigned int, or unsigned long -> unsigned long */
+ if (integer_types_same_name_p (TYPE_NAME (parm), TYPE_NAME (arg)))
+ return 0;
+ else if (integer_types_same_name_p (TYPE_NAME (arg), "int")
+ && integer_types_same_name_p (TYPE_NAME (parm), "long"))
+ return INTEGER_PROMOTION_BADNESS; /* unsigned int -> unsigned long */
+ else
+ return INTEGER_CONVERSION_BADNESS; /* unsigned long -> unsigned int */
+ }
+ else
+ {
+ if (integer_types_same_name_p (TYPE_NAME (arg), "long")
+ && integer_types_same_name_p (TYPE_NAME (parm), "int"))
+ return INTEGER_CONVERSION_BADNESS; /* signed long -> unsigned int */
+ else
+ return INTEGER_CONVERSION_BADNESS; /* signed int/long -> unsigned int/long */
+ }
+ }
+ else if (!TYPE_NOSIGN (arg) && !TYPE_UNSIGNED (arg))
+ {
+ if (integer_types_same_name_p (TYPE_NAME (parm), TYPE_NAME (arg)))
+ return 0;
+ else if (integer_types_same_name_p (TYPE_NAME (arg), "int")
+ && integer_types_same_name_p (TYPE_NAME (parm), "long"))
+ return INTEGER_PROMOTION_BADNESS;
+ else
+ return INTEGER_CONVERSION_BADNESS;
+ }
+ else
+ return INTEGER_CONVERSION_BADNESS;
+ }
+ else if (TYPE_LENGTH (arg) < TYPE_LENGTH (parm))
+ return INTEGER_PROMOTION_BADNESS;
+ else
+ return INTEGER_CONVERSION_BADNESS;
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BOOL:
+ return INTEGER_PROMOTION_BADNESS;
+ case TYPE_CODE_FLT:
+ return INT_FLOAT_CONVERSION_BADNESS;
+ case TYPE_CODE_PTR:
+ return NS_POINTER_CONVERSION_BADNESS;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_ENUM:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_ENUM:
+ return INTEGER_CONVERSION_BADNESS;
+ case TYPE_CODE_FLT:
+ return INT_FLOAT_CONVERSION_BADNESS;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_CHAR:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_ENUM:
+ return INTEGER_CONVERSION_BADNESS;
+ case TYPE_CODE_FLT:
+ return INT_FLOAT_CONVERSION_BADNESS;
+ case TYPE_CODE_INT:
+ if (TYPE_LENGTH (arg) > TYPE_LENGTH (parm))
+ return INTEGER_CONVERSION_BADNESS;
+ else if (TYPE_LENGTH (arg) < TYPE_LENGTH (parm))
+ return INTEGER_PROMOTION_BADNESS;
+ /* >>> !! else fall through !! <<< */
+ case TYPE_CODE_CHAR:
+ /* Deal with signed, unsigned, and plain chars for C++
+ and with int cases falling through from previous case */
+ if (TYPE_NOSIGN (parm))
+ {
+ if (TYPE_NOSIGN (arg))
+ return 0;
+ else
+ return INTEGER_CONVERSION_BADNESS;
+ }
+ else if (TYPE_UNSIGNED (parm))
+ {
+ if (TYPE_UNSIGNED (arg))
+ return 0;
+ else
+ return INTEGER_PROMOTION_BADNESS;
+ }
+ else if (!TYPE_NOSIGN (arg) && !TYPE_UNSIGNED (arg))
+ return 0;
+ else
+ return INTEGER_CONVERSION_BADNESS;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_RANGE:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_ENUM:
+ return INTEGER_CONVERSION_BADNESS;
+ case TYPE_CODE_FLT:
+ return INT_FLOAT_CONVERSION_BADNESS;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_BOOL:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_PTR:
+ return BOOLEAN_CONVERSION_BADNESS;
+ case TYPE_CODE_BOOL:
+ return 0;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_FLT:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_FLT:
+ if (TYPE_LENGTH (arg) < TYPE_LENGTH (parm))
+ return FLOAT_PROMOTION_BADNESS;
+ else if (TYPE_LENGTH (arg) == TYPE_LENGTH (parm))
+ return 0;
+ else
+ return FLOAT_CONVERSION_BADNESS;
+ case TYPE_CODE_INT:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_CHAR:
+ return INT_FLOAT_CONVERSION_BADNESS;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_COMPLEX:
+ switch (TYPE_CODE (arg))
+ { /* Strictly not needed for C++, but... */
+ case TYPE_CODE_FLT:
+ return FLOAT_PROMOTION_BADNESS;
+ case TYPE_CODE_COMPLEX:
+ return 0;
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_STRUCT:
+ /* currently same as TYPE_CODE_CLASS */
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_STRUCT:
+ /* Check for derivation */
+ if (is_ancestor (parm, arg))
+ return BASE_CONVERSION_BADNESS;
+ /* else fall through */
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_UNION:
+ switch (TYPE_CODE (arg))
+ {
+ case TYPE_CODE_UNION:
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_MEMBER:
+ switch (TYPE_CODE (arg))
+ {
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_METHOD:
+ switch (TYPE_CODE (arg))
+ {
+
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_REF:
+ switch (TYPE_CODE (arg))
+ {
+
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+
+ break;
+ case TYPE_CODE_SET:
+ switch (TYPE_CODE (arg))
+ {
+ /* Not in C++ */
+ case TYPE_CODE_SET:
+ return rank_one_type (TYPE_FIELD_TYPE (parm, 0), TYPE_FIELD_TYPE (arg, 0));
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ }
+ break;
+ case TYPE_CODE_VOID:
+ default:
+ return INCOMPATIBLE_TYPE_BADNESS;
+ } /* switch (TYPE_CODE (arg)) */
+}
+
+
+/* End of functions for overload resolution */
+
+static void
+print_bit_vector (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");
+ }
+ }
+}
+
+/* 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 (struct field *args, int nargs, int spaces)
+{
+ if (args != NULL)
+ {
+ int i;
+
+ for (i = 0; i < nargs; i++)
+ recursive_dump_type (args[i].type, spaces + 2);
+ }
+}
+
+static void
+dump_fn_fieldlists (struct type *type, int spaces)
+{
+ int method_idx;
+ int overload_idx;
+ struct fn_field *f;
+
+ printfi_filtered (spaces, "fn_fieldlists ");
+ gdb_print_host_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_host_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_host_address (TYPE_FN_FIELD_PHYSNAME (f, overload_idx),
+ gdb_stdout);
+ printf_filtered (")\n");
+ printfi_filtered (spaces + 8, "type ");
+ gdb_print_host_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_host_address (TYPE_FN_FIELD_ARGS (f, overload_idx), gdb_stdout);
+ printf_filtered ("\n");
+
+ print_arg_types (TYPE_FN_FIELD_ARGS (f, overload_idx),
+ TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (f, overload_idx)),
+ spaces);
+ printfi_filtered (spaces + 8, "fcontext ");
+ gdb_print_host_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 (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_host_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_host_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_host_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 void
+print_bound_type (int bt)
+{
+ switch (bt)
+ {
+ case BOUND_CANNOT_BE_DETERMINED:
+ printf_filtered ("(BOUND_CANNOT_BE_DETERMINED)");
+ break;
+ case BOUND_BY_REF_ON_STACK:
+ printf_filtered ("(BOUND_BY_REF_ON_STACK)");
+ break;
+ case BOUND_BY_VALUE_ON_STACK:
+ printf_filtered ("(BOUND_BY_VALUE_ON_STACK)");
+ break;
+ case BOUND_BY_REF_IN_REG:
+ printf_filtered ("(BOUND_BY_REF_IN_REG)");
+ break;
+ case BOUND_BY_VALUE_IN_REG:
+ printf_filtered ("(BOUND_BY_VALUE_IN_REG)");
+ break;
+ case BOUND_SIMPLE:
+ printf_filtered ("(BOUND_SIMPLE)");
+ break;
+ default:
+ printf_filtered ("(unknown bound type)");
+ break;
+ }
+}
+
+static struct obstack dont_print_type_obstack;
+
+void
+recursive_dump_type (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_host_address (type, gdb_stdout);
+ printf_filtered (" <same as already seen type>\n");
+ return;
+ }
+ }
+
+ obstack_ptr_grow (&dont_print_type_obstack, type);
+ }
+
+ printfi_filtered (spaces, "type node ");
+ gdb_print_host_address (type, gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "name '%s' (",
+ TYPE_NAME (type) ? TYPE_NAME (type) : "<NULL>");
+ gdb_print_host_address (TYPE_NAME (type), gdb_stdout);
+ printf_filtered (")\n");
+ printfi_filtered (spaces, "tagname '%s' (",
+ TYPE_TAG_NAME (type) ? TYPE_TAG_NAME (type) : "<NULL>");
+ gdb_print_host_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_BITSTRING:
+ printf_filtered ("(TYPE_CODE_BITSTRING)");
+ 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_COMPLEX:
+ printf_filtered ("(TYPE_CODE_COMPLEX)");
+ break;
+ case TYPE_CODE_TYPEDEF:
+ printf_filtered ("(TYPE_CODE_TYPEDEF)");
+ break;
+ case TYPE_CODE_TEMPLATE:
+ printf_filtered ("(TYPE_CODE_TEMPLATE)");
+ break;
+ case TYPE_CODE_TEMPLATE_ARG:
+ printf_filtered ("(TYPE_CODE_TEMPLATE_ARG)");
+ break;
+ case TYPE_CODE_NAMESPACE:
+ printf_filtered ("(TYPE_CODE_NAMESPACE)");
+ break;
+ default:
+ printf_filtered ("(UNKNOWN TYPE CODE)");
+ break;
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "length %d\n", TYPE_LENGTH (type));
+ printfi_filtered (spaces, "upper_bound_type 0x%x ",
+ TYPE_ARRAY_UPPER_BOUND_TYPE (type));
+ print_bound_type (TYPE_ARRAY_UPPER_BOUND_TYPE (type));
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "lower_bound_type 0x%x ",
+ TYPE_ARRAY_LOWER_BOUND_TYPE (type));
+ print_bound_type (TYPE_ARRAY_LOWER_BOUND_TYPE (type));
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "objfile ");
+ gdb_print_host_address (TYPE_OBJFILE (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "target_type ");
+ gdb_print_host_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_host_address (TYPE_POINTER_TYPE (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "reference_type ");
+ gdb_print_host_address (TYPE_REFERENCE_TYPE (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "type_chain ");
+ gdb_print_host_address (TYPE_CHAIN (type), gdb_stdout);
+ printf_filtered ("\n");
+ printfi_filtered (spaces, "instance_flags 0x%x", TYPE_INSTANCE_FLAGS (type));
+ if (TYPE_CONST (type))
+ {
+ puts_filtered (" TYPE_FLAG_CONST");
+ }
+ if (TYPE_VOLATILE (type))
+ {
+ puts_filtered (" TYPE_FLAG_VOLATILE");
+ }
+ if (TYPE_CODE_SPACE (type))
+ {
+ puts_filtered (" TYPE_FLAG_CODE_SPACE");
+ }
+ if (TYPE_DATA_SPACE (type))
+ {
+ puts_filtered (" TYPE_FLAG_DATA_SPACE");
+ }
+ if (TYPE_ADDRESS_CLASS_1 (type))
+ {
+ puts_filtered (" TYPE_FLAG_ADDRESS_CLASS_1");
+ }
+ if (TYPE_ADDRESS_CLASS_2 (type))
+ {
+ puts_filtered (" TYPE_FLAG_ADDRESS_CLASS_2");
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "flags 0x%x", TYPE_FLAGS (type));
+ if (TYPE_UNSIGNED (type))
+ {
+ puts_filtered (" TYPE_FLAG_UNSIGNED");
+ }
+ if (TYPE_NOSIGN (type))
+ {
+ puts_filtered (" TYPE_FLAG_NOSIGN");
+ }
+ if (TYPE_STUB (type))
+ {
+ puts_filtered (" TYPE_FLAG_STUB");
+ }
+ if (TYPE_TARGET_STUB (type))
+ {
+ puts_filtered (" TYPE_FLAG_TARGET_STUB");
+ }
+ if (TYPE_STATIC (type))
+ {
+ puts_filtered (" TYPE_FLAG_STATIC");
+ }
+ if (TYPE_PROTOTYPED (type))
+ {
+ puts_filtered (" TYPE_FLAG_PROTOTYPED");
+ }
+ if (TYPE_INCOMPLETE (type))
+ {
+ puts_filtered (" TYPE_FLAG_INCOMPLETE");
+ }
+ if (TYPE_VARARGS (type))
+ {
+ puts_filtered (" TYPE_FLAG_VARARGS");
+ }
+ /* This is used for things like AltiVec registers on ppc. Gcc emits
+ an attribute for the array type, which tells whether or not we
+ have a vector, instead of a regular array. */
+ if (TYPE_VECTOR (type))
+ {
+ puts_filtered (" TYPE_FLAG_VECTOR");
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "nfields %d ", TYPE_NFIELDS (type));
+ gdb_print_host_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_host_address (TYPE_FIELD_TYPE (type, idx), gdb_stdout);
+ printf_filtered (" name '%s' (",
+ TYPE_FIELD_NAME (type, idx) != NULL
+ ? TYPE_FIELD_NAME (type, idx)
+ : "<NULL>");
+ gdb_print_host_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_host_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_STRUCT:
+ printfi_filtered (spaces, "cplus_stuff ");
+ gdb_print_host_address (TYPE_CPLUS_SPECIFIC (type), gdb_stdout);
+ puts_filtered ("\n");
+ print_cplus_stuff (type, spaces);
+ break;
+
+ case TYPE_CODE_FLT:
+ printfi_filtered (spaces, "floatformat ");
+ if (TYPE_FLOATFORMAT (type) == NULL
+ || TYPE_FLOATFORMAT (type)->name == NULL)
+ puts_filtered ("(null)");
+ else
+ puts_filtered (TYPE_FLOATFORMAT (type)->name);
+ puts_filtered ("\n");
+ 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_host_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);
+}
+
+static void build_gdbtypes (void);
+static void
+build_gdbtypes (void)
+{
+ 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,
+ (TYPE_FLAG_NOSIGN
+ | (TARGET_CHAR_SIGNED ? 0 : TYPE_FLAG_UNSIGNED)),
+ "char", (struct objfile *) NULL);
+ builtin_type_true_char =
+ init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0,
+ "true character", (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);
+/* vinschen@redhat.com 2002-02-08:
+ The below lines are disabled since they are doing the wrong
+ thing for non-multiarch targets. They are setting the correct
+ type of floats for the target but while on multiarch targets
+ this is done everytime the architecture changes, it's done on
+ non-multiarch targets only on startup, leaving the wrong values
+ in even if the architecture changes (eg. from big-endian to
+ little-endian). */
+#if 0
+ TYPE_FLOATFORMAT (builtin_type_float) = TARGET_FLOAT_FORMAT;
+#endif
+ builtin_type_double =
+ init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "double", (struct objfile *) NULL);
+#if 0
+ TYPE_FLOATFORMAT (builtin_type_double) = TARGET_DOUBLE_FORMAT;
+#endif
+ builtin_type_long_double =
+ init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0,
+ "long double", (struct objfile *) NULL);
+#if 0
+ TYPE_FLOATFORMAT (builtin_type_long_double) = TARGET_LONG_DOUBLE_FORMAT;
+#endif
+ 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);
+ builtin_type_int0 =
+ init_type (TYPE_CODE_INT, 0 / 8,
+ 0,
+ "int0_t", (struct objfile *) NULL);
+ builtin_type_int8 =
+ init_type (TYPE_CODE_INT, 8 / 8,
+ 0,
+ "int8_t", (struct objfile *) NULL);
+ builtin_type_uint8 =
+ init_type (TYPE_CODE_INT, 8 / 8,
+ TYPE_FLAG_UNSIGNED,
+ "uint8_t", (struct objfile *) NULL);
+ builtin_type_int16 =
+ init_type (TYPE_CODE_INT, 16 / 8,
+ 0,
+ "int16_t", (struct objfile *) NULL);
+ builtin_type_uint16 =
+ init_type (TYPE_CODE_INT, 16 / 8,
+ TYPE_FLAG_UNSIGNED,
+ "uint16_t", (struct objfile *) NULL);
+ builtin_type_int32 =
+ init_type (TYPE_CODE_INT, 32 / 8,
+ 0,
+ "int32_t", (struct objfile *) NULL);
+ builtin_type_uint32 =
+ init_type (TYPE_CODE_INT, 32 / 8,
+ TYPE_FLAG_UNSIGNED,
+ "uint32_t", (struct objfile *) NULL);
+ builtin_type_int64 =
+ init_type (TYPE_CODE_INT, 64 / 8,
+ 0,
+ "int64_t", (struct objfile *) NULL);
+ builtin_type_uint64 =
+ init_type (TYPE_CODE_INT, 64 / 8,
+ TYPE_FLAG_UNSIGNED,
+ "uint64_t", (struct objfile *) NULL);
+ builtin_type_int128 =
+ init_type (TYPE_CODE_INT, 128 / 8,
+ 0,
+ "int128_t", (struct objfile *) NULL);
+ builtin_type_uint128 =
+ init_type (TYPE_CODE_INT, 128 / 8,
+ TYPE_FLAG_UNSIGNED,
+ "uint128_t", (struct objfile *) NULL);
+ builtin_type_bool =
+ init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0,
+ "bool", (struct objfile *) NULL);
+
+ /* Add user knob for controlling resolution of opaque types */
+ add_show_from_set
+ (add_set_cmd ("opaque-type-resolution", class_support, var_boolean, (char *) &opaque_type_resolution,
+ "Set resolution of opaque struct/class/union types (if set before loading symbols).",
+ &setlist),
+ &showlist);
+ opaque_type_resolution = 1;
+
+ /* Build SIMD types. */
+ builtin_type_v4sf
+ = init_simd_type ("__builtin_v4sf", builtin_type_float, "f", 4);
+ builtin_type_v4si
+ = init_simd_type ("__builtin_v4si", builtin_type_int32, "f", 4);
+ builtin_type_v16qi
+ = init_simd_type ("__builtin_v16qi", builtin_type_int8, "f", 16);
+ builtin_type_v8qi
+ = init_simd_type ("__builtin_v8qi", builtin_type_int8, "f", 8);
+ builtin_type_v8hi
+ = init_simd_type ("__builtin_v8hi", builtin_type_int16, "f", 8);
+ builtin_type_v4hi
+ = init_simd_type ("__builtin_v4hi", builtin_type_int16, "f", 4);
+ builtin_type_v2si
+ = init_simd_type ("__builtin_v2si", builtin_type_int32, "f", 2);
+
+ /* 128 bit vectors. */
+ builtin_type_v2_double = init_vector_type (builtin_type_double, 2);
+ builtin_type_v4_float = init_vector_type (builtin_type_float, 4);
+ builtin_type_v2_int64 = init_vector_type (builtin_type_int64, 2);
+ builtin_type_v4_int32 = init_vector_type (builtin_type_int32, 4);
+ builtin_type_v8_int16 = init_vector_type (builtin_type_int16, 8);
+ builtin_type_v16_int8 = init_vector_type (builtin_type_int8, 16);
+ /* 64 bit vectors. */
+ builtin_type_v2_float = init_vector_type (builtin_type_float, 2);
+ builtin_type_v2_int32 = init_vector_type (builtin_type_int32, 2);
+ builtin_type_v4_int16 = init_vector_type (builtin_type_int16, 4);
+ builtin_type_v8_int8 = init_vector_type (builtin_type_int8, 8);
+
+ /* Vector types. */
+ builtin_type_vec64 = build_builtin_type_vec64 ();
+ builtin_type_vec64i = build_builtin_type_vec64i ();
+ builtin_type_vec128 = build_builtin_type_vec128 ();
+ builtin_type_vec128i = build_builtin_type_vec128i ();
+
+ /* Pointer/Address types. */
+
+ /* NOTE: on some targets, addresses and pointers are not necessarily
+ the same --- for example, on the D10V, pointers are 16 bits long,
+ but addresses are 32 bits long. See doc/gdbint.texinfo,
+ ``Pointers Are Not Always Addresses''.
+
+ The upshot is:
+ - gdb's `struct type' always describes the target's
+ representation.
+ - gdb's `struct value' objects should always hold values in
+ target form.
+ - gdb's CORE_ADDR values are addresses in the unified virtual
+ address space that the assembler and linker work with. Thus,
+ since target_read_memory takes a CORE_ADDR as an argument, it
+ can access any memory on the target, even if the processor has
+ separate code and data address spaces.
+
+ So, for example:
+ - If v is a value holding a D10V code pointer, its contents are
+ in target form: a big-endian address left-shifted two bits.
+ - If p is a D10V pointer type, TYPE_LENGTH (p) == 2, just as
+ sizeof (void *) == 2 on the target.
+
+ In this context, builtin_type_CORE_ADDR is a bit odd: it's a
+ target type for a value the target will never see. It's only
+ used to hold the values of (typeless) linker symbols, which are
+ indeed in the unified virtual address space. */
+ builtin_type_void_data_ptr = make_pointer_type (builtin_type_void, NULL);
+ builtin_type_void_func_ptr
+ = lookup_pointer_type (lookup_function_type (builtin_type_void));
+ builtin_type_CORE_ADDR =
+ init_type (TYPE_CODE_INT, TARGET_ADDR_BIT / 8,
+ TYPE_FLAG_UNSIGNED,
+ "__CORE_ADDR", (struct objfile *) NULL);
+ builtin_type_bfd_vma =
+ init_type (TYPE_CODE_INT, TARGET_BFD_VMA_BIT / 8,
+ TYPE_FLAG_UNSIGNED,
+ "__bfd_vma", (struct objfile *) NULL);
+}
+
+extern void _initialize_gdbtypes (void);
+void
+_initialize_gdbtypes (void)
+{
+ struct cmd_list_element *c;
+ build_gdbtypes ();
+
+ /* FIXME - For the moment, handle types by swapping them in and out.
+ Should be using the per-architecture data-pointer and a large
+ struct. */
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_void);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_char);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_short);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_int);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_long);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_long_long);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_signed_char);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_unsigned_char);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_unsigned_short);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_unsigned_int);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_unsigned_long);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_unsigned_long_long);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_float);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_double);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_long_double);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_complex);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_double_complex);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_string);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_int8);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_uint8);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_int16);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_uint16);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_int32);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_uint32);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_int64);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_uint64);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_int128);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_uint128);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v4sf);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v4si);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v16qi);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v8qi);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v8hi);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v4hi);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v2si);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v2_double);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v4_float);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v2_int64);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v4_int32);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v8_int16);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v16_int8);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v2_float);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v2_int32);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v8_int8);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_v4_int16);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_vec128);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_vec128i);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_void_data_ptr);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_void_func_ptr);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_CORE_ADDR);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_bfd_vma);
+ deprecated_register_gdbarch_swap (NULL, 0, build_gdbtypes);
+
+ /* Note: These types do not need to be swapped - they are target
+ neutral. */
+ builtin_type_ieee_single_big =
+ init_type (TYPE_CODE_FLT, floatformat_ieee_single_big.totalsize / 8,
+ 0, "builtin_type_ieee_single_big", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ieee_single_big) = &floatformat_ieee_single_big;
+ builtin_type_ieee_single_little =
+ init_type (TYPE_CODE_FLT, floatformat_ieee_single_little.totalsize / 8,
+ 0, "builtin_type_ieee_single_little", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ieee_single_little) = &floatformat_ieee_single_little;
+ builtin_type_ieee_double_big =
+ init_type (TYPE_CODE_FLT, floatformat_ieee_double_big.totalsize / 8,
+ 0, "builtin_type_ieee_double_big", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ieee_double_big) = &floatformat_ieee_double_big;
+ builtin_type_ieee_double_little =
+ init_type (TYPE_CODE_FLT, floatformat_ieee_double_little.totalsize / 8,
+ 0, "builtin_type_ieee_double_little", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ieee_double_little) = &floatformat_ieee_double_little;
+ builtin_type_ieee_double_littlebyte_bigword =
+ init_type (TYPE_CODE_FLT, floatformat_ieee_double_littlebyte_bigword.totalsize / 8,
+ 0, "builtin_type_ieee_double_littlebyte_bigword", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ieee_double_littlebyte_bigword) = &floatformat_ieee_double_littlebyte_bigword;
+ builtin_type_i387_ext =
+ init_type (TYPE_CODE_FLT, floatformat_i387_ext.totalsize / 8,
+ 0, "builtin_type_i387_ext", NULL);
+ TYPE_FLOATFORMAT (builtin_type_i387_ext) = &floatformat_i387_ext;
+ builtin_type_m68881_ext =
+ init_type (TYPE_CODE_FLT, floatformat_m68881_ext.totalsize / 8,
+ 0, "builtin_type_m68881_ext", NULL);
+ TYPE_FLOATFORMAT (builtin_type_m68881_ext) = &floatformat_m68881_ext;
+ builtin_type_i960_ext =
+ init_type (TYPE_CODE_FLT, floatformat_i960_ext.totalsize / 8,
+ 0, "builtin_type_i960_ext", NULL);
+ TYPE_FLOATFORMAT (builtin_type_i960_ext) = &floatformat_i960_ext;
+ builtin_type_m88110_ext =
+ init_type (TYPE_CODE_FLT, floatformat_m88110_ext.totalsize / 8,
+ 0, "builtin_type_m88110_ext", NULL);
+ TYPE_FLOATFORMAT (builtin_type_m88110_ext) = &floatformat_m88110_ext;
+ builtin_type_m88110_harris_ext =
+ init_type (TYPE_CODE_FLT, floatformat_m88110_harris_ext.totalsize / 8,
+ 0, "builtin_type_m88110_harris_ext", NULL);
+ TYPE_FLOATFORMAT (builtin_type_m88110_harris_ext) = &floatformat_m88110_harris_ext;
+ builtin_type_arm_ext_big =
+ init_type (TYPE_CODE_FLT, floatformat_arm_ext_big.totalsize / 8,
+ 0, "builtin_type_arm_ext_big", NULL);
+ TYPE_FLOATFORMAT (builtin_type_arm_ext_big) = &floatformat_arm_ext_big;
+ builtin_type_arm_ext_littlebyte_bigword =
+ init_type (TYPE_CODE_FLT, floatformat_arm_ext_littlebyte_bigword.totalsize / 8,
+ 0, "builtin_type_arm_ext_littlebyte_bigword", NULL);
+ TYPE_FLOATFORMAT (builtin_type_arm_ext_littlebyte_bigword) = &floatformat_arm_ext_littlebyte_bigword;
+ builtin_type_ia64_spill_big =
+ init_type (TYPE_CODE_FLT, floatformat_ia64_spill_big.totalsize / 8,
+ 0, "builtin_type_ia64_spill_big", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ia64_spill_big) = &floatformat_ia64_spill_big;
+ builtin_type_ia64_spill_little =
+ init_type (TYPE_CODE_FLT, floatformat_ia64_spill_little.totalsize / 8,
+ 0, "builtin_type_ia64_spill_little", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ia64_spill_little) = &floatformat_ia64_spill_little;
+ builtin_type_ia64_quad_big =
+ init_type (TYPE_CODE_FLT, floatformat_ia64_quad_big.totalsize / 8,
+ 0, "builtin_type_ia64_quad_big", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ia64_quad_big) = &floatformat_ia64_quad_big;
+ builtin_type_ia64_quad_little =
+ init_type (TYPE_CODE_FLT, floatformat_ia64_quad_little.totalsize / 8,
+ 0, "builtin_type_ia64_quad_little", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ia64_quad_little) = &floatformat_ia64_quad_little;
+
+ add_show_from_set (
+ add_set_cmd ("overload", no_class, var_zinteger, (char *) &overload_debug,
+ "Set debugging of C++ overloading.\n\
+ When enabled, ranking of the functions\n\
+ is displayed.", &setdebuglist),
+ &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/gdbtypes.h b/contrib/gdb/gdb/gdbtypes.h
new file mode 100644
index 0000000..c0696ad
--- /dev/null
+++ b/contrib/gdb/gdb/gdbtypes.h
@@ -0,0 +1,1276 @@
+/* Internal type definitions for GDB.
+
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004 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
+
+/* Forward declarations for prototypes. */
+struct field;
+struct block;
+
+/* 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 /* we use this for not-unsigned C/C++ chars */
+#define FT_SIGNED_CHAR 3 /* we use this for C++ signed chars */
+#define FT_UNSIGNED_CHAR 4 /* we use this for C/C++ unsigned chars */
+#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_TEMPLATE_ARG 28
+
+#define FT_NUM_MEMBERS 29 /* 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 (the deleted) 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 (the deleted) 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,
+ TYPE_CODE_TEMPLATE, /* C++ template */
+ TYPE_CODE_TEMPLATE_ARG, /* C++ template arg */
+
+ TYPE_CODE_NAMESPACE /* C++ namespace. */
+ };
+
+/* 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, and macros to test them. */
+
+/* Unsigned integer type. If this is not set for a TYPE_CODE_INT, the
+ type is signed (unless TYPE_FLAG_NOSIGN (below) is set). */
+
+#define TYPE_FLAG_UNSIGNED (1 << 0)
+#define TYPE_UNSIGNED(t) (TYPE_FLAGS (t) & TYPE_FLAG_UNSIGNED)
+
+/* No sign for this type. In C++, "char", "signed char", and "unsigned
+ char" are distinct types; so we need an extra flag to indicate the
+ absence of a sign! */
+
+#define TYPE_FLAG_NOSIGN (1 << 1)
+#define TYPE_NOSIGN(t) (TYPE_FLAGS (t) & TYPE_FLAG_NOSIGN)
+
+/* 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)
+#define TYPE_STUB(t) (TYPE_FLAGS (t) & TYPE_FLAG_STUB)
+
+/* 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)
+#define TYPE_TARGET_STUB(t) (TYPE_FLAGS (t) & TYPE_FLAG_TARGET_STUB)
+
+/* Static type. If this is set, the corresponding type had
+ * a static modifier.
+ * Note: This may be unnecessary, since static data members
+ * are indicated by other means (bitpos == -1)
+ */
+
+#define TYPE_FLAG_STATIC (1 << 4)
+#define TYPE_STATIC(t) (TYPE_FLAGS (t) & TYPE_FLAG_STATIC)
+
+/* Constant type. If this is set, the corresponding type has a
+ * const modifier.
+ */
+
+#define TYPE_FLAG_CONST (1 << 5)
+#define TYPE_CONST(t) (TYPE_INSTANCE_FLAGS (t) & TYPE_FLAG_CONST)
+
+/* Volatile type. If this is set, the corresponding type has a
+ * volatile modifier.
+ */
+
+#define TYPE_FLAG_VOLATILE (1 << 6)
+#define TYPE_VOLATILE(t) (TYPE_INSTANCE_FLAGS (t) & TYPE_FLAG_VOLATILE)
+
+
+/* This is a function type which appears to have a prototype. We need this
+ for function calls in order to tell us if it's necessary to coerce the args,
+ or to just do the standard conversions. This is used with a short field. */
+
+#define TYPE_FLAG_PROTOTYPED (1 << 7)
+#define TYPE_PROTOTYPED(t) (TYPE_FLAGS (t) & TYPE_FLAG_PROTOTYPED)
+
+/* This flag is used to indicate that processing for this type
+ is incomplete.
+
+ (Mostly intended for HP platforms, where class methods, for
+ instance, can be encountered before their classes in the debug
+ info; the incomplete type has to be marked so that the class and
+ the method can be assigned correct types.) */
+
+#define TYPE_FLAG_INCOMPLETE (1 << 8)
+#define TYPE_INCOMPLETE(t) (TYPE_FLAGS (t) & TYPE_FLAG_INCOMPLETE)
+
+/* Instruction-space delimited type. This is for Harvard architectures
+ which have separate instruction and data address spaces (and perhaps
+ others).
+
+ GDB usually defines a flat address space that is a superset of the
+ architecture's two (or more) address spaces, but this is an extension
+ of the architecture's model.
+
+ If TYPE_FLAG_INST is set, an object of the corresponding type
+ resides in instruction memory, even if its address (in the extended
+ flat address space) does not reflect this.
+
+ Similarly, if TYPE_FLAG_DATA is set, then an object of the
+ corresponding type resides in the data memory space, even if
+ this is not indicated by its (flat address space) address.
+
+ If neither flag is set, the default space for functions / methods
+ is instruction space, and for data objects is data memory. */
+
+#define TYPE_FLAG_CODE_SPACE (1 << 9)
+#define TYPE_CODE_SPACE(t) (TYPE_INSTANCE_FLAGS (t) & TYPE_FLAG_CODE_SPACE)
+
+#define TYPE_FLAG_DATA_SPACE (1 << 10)
+#define TYPE_DATA_SPACE(t) (TYPE_INSTANCE_FLAGS (t) & TYPE_FLAG_DATA_SPACE)
+
+/* FIXME drow/2002-06-03: Only used for methods, but applies as well
+ to functions. */
+
+#define TYPE_FLAG_VARARGS (1 << 11)
+#define TYPE_VARARGS(t) (TYPE_FLAGS (t) & TYPE_FLAG_VARARGS)
+
+/* Identify a vector type. Gcc is handling this by adding an extra
+ attribute to the array type. We slurp that in as a new flag of a
+ type. This is used only in dwarf2read.c. */
+#define TYPE_FLAG_VECTOR (1 << 12)
+#define TYPE_VECTOR(t) (TYPE_FLAGS (t) & TYPE_FLAG_VECTOR)
+
+/* Address class flags. Some environments provide for pointers whose
+ size is different from that of a normal pointer or address types
+ where the bits are interpreted differently than normal addresses. The
+ TYPE_FLAG_ADDRESS_CLASS_n flags may be used in target specific
+ ways to represent these different types of address classes. */
+#define TYPE_FLAG_ADDRESS_CLASS_1 (1 << 13)
+#define TYPE_ADDRESS_CLASS_1(t) (TYPE_INSTANCE_FLAGS(t) \
+ & TYPE_FLAG_ADDRESS_CLASS_1)
+#define TYPE_FLAG_ADDRESS_CLASS_2 (1 << 14)
+#define TYPE_ADDRESS_CLASS_2(t) (TYPE_INSTANCE_FLAGS(t) \
+ & TYPE_FLAG_ADDRESS_CLASS_2)
+#define TYPE_FLAG_ADDRESS_CLASS_ALL (TYPE_FLAG_ADDRESS_CLASS_1 \
+ | TYPE_FLAG_ADDRESS_CLASS_2)
+#define TYPE_ADDRESS_CLASS_ALL(t) (TYPE_INSTANCE_FLAGS(t) \
+ & TYPE_FLAG_ADDRESS_CLASS_ALL)
+
+/* Array bound type. */
+enum array_bound_type
+{
+ BOUND_SIMPLE = 0,
+ BOUND_BY_VALUE_IN_REG,
+ BOUND_BY_REF_IN_REG,
+ BOUND_BY_VALUE_ON_STACK,
+ BOUND_BY_REF_ON_STACK,
+ BOUND_CANNOT_BE_DETERMINED
+};
+
+/* This structure is space-critical.
+ Its layout has been tweaked to reduce the space used. */
+
+struct main_type
+{
+ /* Code for kind of type */
+
+ ENUM_BITFIELD(type_code) code : 8;
+
+ /* Array bounds. These fields appear at this location because
+ they pack nicely here. */
+
+ ENUM_BITFIELD(array_bound_type) upper_bound_type : 4;
+ ENUM_BITFIELD(array_bound_type) lower_bound_type : 4;
+
+ /* 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_DOMAIN. */
+
+ 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_DOMAIN.
+ 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;
+
+ /* Every type is now associated with a particular objfile, and the
+ type is allocated on the objfile_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;
+
+ /* Flags about this type. */
+
+ int flags;
+
+ /* Number of fields described for this type */
+
+ short nfields;
+
+ /* 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. */
+
+ short vptr_fieldno;
+
+ /* 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 or method type, a "field" for each parameter.
+ 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
+ {
+ union field_location
+ {
+ /* Position of this field, counting in bits from start of
+ containing structure.
+ 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.
+ For a range bound or enum value, this is the value itself. */
+
+ int bitpos;
+
+ /* For a static field, if TYPE_FIELD_STATIC_HAS_ADDR then physaddr
+ is the location (in the target) of the static field.
+ Otherwise, physname is the mangled label of the static field. */
+
+ CORE_ADDR physaddr;
+ char *physname;
+ }
+ loc;
+
+ /* For a function or member type, this is 1 if the argument is marked
+ artificial. Artificial arguments should not be shown to the
+ user. */
+ unsigned int artificial : 1;
+
+ /* This flag is zero for non-static fields, 1 for fields whose location
+ is specified by the label loc.physname, and 2 for fields whose location
+ is specified by loc.physaddr. */
+
+ unsigned int static_kind : 2;
+
+ /* 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. */
+
+ unsigned int bitsize : 29;
+
+ /* In a struct or union type, type of this field.
+ In a function or member 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, array domains, and member function
+ arguments. */
+
+ char *name;
+
+ } *fields;
+
+ /* For types with virtual functions (TYPE_CODE_STRUCT), VPTR_BASETYPE
+ is the base class which defined the virtual function table pointer.
+
+ For types that are pointer to member types (TYPE_CODE_MEMBER),
+ VPTR_BASETYPE is the type that this pointer is a member of.
+
+ For method types (TYPE_CODE_METHOD), VPTR_BASETYPE is the aggregate
+ type that contains the method.
+
+ Unused otherwise. */
+
+ struct type *vptr_basetype;
+
+ /* Slot to point to additional language-specific fields of this type. */
+
+ union type_specific
+ {
+ /* 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;
+
+ /* FLOATFORMAT is for TYPE_CODE_FLT. It is a pointer to the
+ floatformat object that describes the floating-point value
+ that resides within the type. */
+
+ const struct floatformat *floatformat;
+ } type_specific;
+};
+
+/* A ``struct type'' describes a particular instance of a type, with
+ some particular qualification. */
+struct 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;
+
+ /* Variant chain. This points to a type that differs from this one only
+ in qualifiers and length. Currently, the possible qualifiers are
+ const, volatile, code-space, data-space, and address class. The
+ length may differ only when one of the address class flags are set.
+ The variants are linked in a circular ring and share MAIN_TYPE. */
+ struct type *chain;
+
+ /* Flags specific to this instance of the type, indicating where
+ on the ring we are. */
+ int instance_flags;
+
+ /* Length of storage for a value of this type. This is what
+ sizeof(type) would return; use it for address arithmetic,
+ memory reads and writes, etc. This size includes padding. For
+ example, an i386 extended-precision floating point value really
+ only occupies ten bytes, but most ABI's declare its size to be
+ 12 bytes, to preserve alignment. A `struct type' representing
+ such a floating-point type would have a `length' value of 12,
+ even though the last two bytes are unused.
+
+ There's a bit of a host/target mess here, if you're concerned
+ about machines whose bytes aren't eight bits long, or who don't
+ have byte-addressed memory. Various places pass this to memcpy
+ and such, meaning it must be in units of host bytes. Various
+ other places expect they can calculate addresses by adding it
+ and such, meaning it must be in units of target bytes. 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. However, this would still fail to address
+ machines based on a ternary or decimal representation. */
+
+ unsigned length;
+
+ /* Core type, shared by a group of qualified types. */
+ struct main_type *main_type;
+};
+
+#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. */
+
+ short nfn_fields_total;
+
+ /* The "declared_type" field contains a code saying how the
+ user really declared this type, e.g., "class s", "union s",
+ "struct s".
+ The 3 above things come out from the C++ compiler looking like classes,
+ but we keep track of the real declaration so we can give
+ the correct information on "ptype". (Note: TEMPLATE may not
+ belong in this list...) */
+
+#define DECLARED_TYPE_CLASS 0
+#define DECLARED_TYPE_UNION 1
+#define DECLARED_TYPE_STRUCT 2
+#define DECLARED_TYPE_TEMPLATE 3
+ short declared_type; /* One of the above codes */
+
+ /* 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 function type for the method.
+ (This comment used to say "The return value of the method",
+ but that's wrong. The function type
+ is expected here, i.e. something with TYPE_CODE_FUNC,
+ and *not* the return-value type). */
+
+ struct type *type;
+
+ /* 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;
+ unsigned int is_public:1;
+ unsigned int is_abstract:1;
+ unsigned int is_static:1;
+ unsigned int is_final:1;
+ unsigned int is_synchronized:1;
+ unsigned int is_native:1;
+ unsigned int is_artificial: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;
+
+ /* C++ method that is inlined */
+ unsigned int is_inlined: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:16;
+
+#define VOFFSET_STATIC 1
+
+ }
+ *fn_fields;
+
+ }
+ *fn_fieldlists;
+
+ /* If this "struct type" describes a template, then it
+ * has arguments. "template_args" points to an array of
+ * template arg descriptors, of length "ntemplate_args".
+ * The only real information in each of these template arg descriptors
+ * is a name. "type" will typically just point to a "struct type" with
+ * the placeholder TYPE_CODE_TEMPLATE_ARG type.
+ */
+ short ntemplate_args;
+ struct template_arg
+ {
+ char *name;
+ struct type *type;
+ }
+ *template_args;
+
+ /* If this "struct type" describes a template, it has a list
+ * of instantiations. "instantiations" is a pointer to an array
+ * of type's, one representing each instantiation. There
+ * are "ninstantiations" elements in this array.
+ */
+ short ninstantiations;
+ struct type **instantiations;
+
+ /* The following points to information relevant to the runtime model
+ * of the compiler.
+ * Currently being used only for HP's ANSI C++ compiler.
+ * (This type may have to be changed/enhanced for other compilers.)
+ *
+ * RUNTIME_PTR is NULL if there is no runtime information (currently
+ * this means the type was not compiled by HP aCC).
+ *
+ * Fields in structure pointed to:
+ * ->HAS_VTABLE : 0 => no virtual table, 1 => vtable present
+ *
+ * ->PRIMARY_BASE points to the first non-virtual base class that has
+ * a virtual table.
+ *
+ * ->VIRTUAL_BASE_LIST points to a list of struct type * pointers that
+ * point to the type information for all virtual bases among this type's
+ * ancestors.
+ */
+ struct runtime_info
+ {
+ short has_vtable;
+ struct type *primary_base;
+ struct type **virtual_base_list;
+ }
+ *runtime_ptr;
+
+ /* Pointer to information about enclosing scope, if this is a
+ * local type. If it is not a local type, this is NULL
+ */
+ struct local_type_info
+ {
+ char *file;
+ int line;
+ }
+ *localtype_ptr;
+ };
+
+/* Struct used in computing virtual base list */
+struct vbase
+ {
+ struct type *vbasetype; /* pointer to virtual base */
+ struct vbase *next; /* next in chain */
+ };
+
+/* Struct used for ranking a function for overload resolution */
+struct badness_vector
+ {
+ int length;
+ int *rank;
+ };
+
+/* 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 (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_INSTANCE_FLAGS(thistype) (thistype)->instance_flags
+#define TYPE_MAIN_TYPE(thistype) (thistype)->main_type
+#define TYPE_NAME(thistype) TYPE_MAIN_TYPE(thistype)->name
+#define TYPE_TAG_NAME(type) TYPE_MAIN_TYPE(type)->tag_name
+#define TYPE_TARGET_TYPE(thistype) TYPE_MAIN_TYPE(thistype)->target_type
+#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
+#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
+#define TYPE_CHAIN(thistype) (thistype)->chain
+/* Note that if thistype is a TYPEDEF type, you have to call check_typedef.
+ But check_typedef does set the TYPE_LENGTH of the TYPEDEF type,
+ so you only have to call check_typedef once. Since allocate_value
+ calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */
+#define TYPE_LENGTH(thistype) (thistype)->length
+#define TYPE_OBJFILE(thistype) TYPE_MAIN_TYPE(thistype)->objfile
+#define TYPE_FLAGS(thistype) TYPE_MAIN_TYPE(thistype)->flags
+/* Note that TYPE_CODE can be TYPE_CODE_TYPEDEF, so if you want the real
+ type, you need to do TYPE_CODE (check_type (this_type)). */
+#define TYPE_CODE(thistype) TYPE_MAIN_TYPE(thistype)->code
+#define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields
+#define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->fields
+#define TYPE_TEMPLATE_ARGS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->template_args
+#define TYPE_INSTANTIATIONS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->instantiations
+
+#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) \
+ TYPE_MAIN_TYPE(thistype)->upper_bound_type
+#define TYPE_ARRAY_LOWER_BOUND_TYPE(thistype) \
+ TYPE_MAIN_TYPE(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) TYPE_MAIN_TYPE(thistype)->vptr_basetype
+#define TYPE_DOMAIN_TYPE(thistype) TYPE_MAIN_TYPE(thistype)->vptr_basetype
+#define TYPE_VPTR_FIELDNO(thistype) TYPE_MAIN_TYPE(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_NTEMPLATE_ARGS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->ntemplate_args
+#define TYPE_NINSTANTIATIONS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->ninstantiations
+#define TYPE_DECLARED_TYPE(thistype) TYPE_CPLUS_SPECIFIC(thistype)->declared_type
+#define TYPE_TYPE_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific
+#define TYPE_CPLUS_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.cplus_stuff
+#define TYPE_FLOATFORMAT(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.floatformat
+#define TYPE_BASECLASS(thistype,index) TYPE_MAIN_TYPE(thistype)->fields[index].type
+#define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses
+#define TYPE_BASECLASS_NAME(thistype,index) TYPE_MAIN_TYPE(thistype)->fields[index].name
+#define TYPE_BASECLASS_BITPOS(thistype,index) TYPE_FIELD_BITPOS(thistype,index)
+#define BASETYPE_VIA_PUBLIC(thistype, index) \
+ ((!TYPE_FIELD_PRIVATE(thistype, index)) && (!TYPE_FIELD_PROTECTED(thistype, index)))
+
+#define BASETYPE_VIA_VIRTUAL(thistype, index) \
+ (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
+ : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
+
+#define FIELD_TYPE(thisfld) ((thisfld).type)
+#define FIELD_NAME(thisfld) ((thisfld).name)
+#define FIELD_BITPOS(thisfld) ((thisfld).loc.bitpos)
+#define FIELD_ARTIFICIAL(thisfld) ((thisfld).artificial)
+#define FIELD_BITSIZE(thisfld) ((thisfld).bitsize)
+#define FIELD_STATIC_KIND(thisfld) ((thisfld).static_kind)
+#define FIELD_PHYSNAME(thisfld) ((thisfld).loc.physname)
+#define FIELD_PHYSADDR(thisfld) ((thisfld).loc.physaddr)
+#define SET_FIELD_PHYSNAME(thisfld, name) \
+ ((thisfld).static_kind = 1, FIELD_PHYSNAME(thisfld) = (name))
+#define SET_FIELD_PHYSADDR(thisfld, name) \
+ ((thisfld).static_kind = 2, FIELD_PHYSADDR(thisfld) = (name))
+#define TYPE_FIELD(thistype, n) TYPE_MAIN_TYPE(thistype)->fields[n]
+#define TYPE_FIELD_TYPE(thistype, n) FIELD_TYPE(TYPE_FIELD(thistype, n))
+#define TYPE_FIELD_NAME(thistype, n) FIELD_NAME(TYPE_FIELD(thistype, n))
+#define TYPE_FIELD_BITPOS(thistype, n) FIELD_BITPOS(TYPE_FIELD(thistype,n))
+#define TYPE_FIELD_ARTIFICIAL(thistype, n) FIELD_ARTIFICIAL(TYPE_FIELD(thistype,n))
+#define TYPE_FIELD_BITSIZE(thistype, n) FIELD_BITSIZE(TYPE_FIELD(thistype,n))
+#define TYPE_FIELD_PACKED(thistype, n) (FIELD_BITSIZE(TYPE_FIELD(thistype,n))!=0)
+#define TYPE_TEMPLATE_ARG(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->template_args[n]
+#define TYPE_INSTANTIATION(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->instantiations[n]
+
+#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) \
+ (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
+ : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n)))
+
+#define TYPE_FIELD_STATIC(thistype, n) (TYPE_MAIN_TYPE (thistype)->fields[n].static_kind != 0)
+#define TYPE_FIELD_STATIC_KIND(thistype, n) TYPE_MAIN_TYPE (thistype)->fields[n].static_kind
+#define TYPE_FIELD_STATIC_HAS_ADDR(thistype, n) (TYPE_MAIN_TYPE (thistype)->fields[n].static_kind == 2)
+#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) FIELD_PHYSNAME(TYPE_FIELD(thistype, n))
+#define TYPE_FIELD_STATIC_PHYSADDR(thistype, n) FIELD_PHYSADDR(TYPE_FIELD(thistype, n))
+
+#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_FIELDS ((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_PUBLIC(thisfn, n) ((thisfn)[n].is_public)
+#define TYPE_FN_FIELD_STATIC(thisfn, n) ((thisfn)[n].is_static)
+#define TYPE_FN_FIELD_FINAL(thisfn, n) ((thisfn)[n].is_final)
+#define TYPE_FN_FIELD_SYNCHRONIZED(thisfn, n) ((thisfn)[n].is_synchronized)
+#define TYPE_FN_FIELD_NATIVE(thisfn, n) ((thisfn)[n].is_native)
+#define TYPE_FN_FIELD_ARTIFICIAL(thisfn, n) ((thisfn)[n].is_artificial)
+#define TYPE_FN_FIELD_ABSTRACT(thisfn, n) ((thisfn)[n].is_abstract)
+#define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub)
+#define TYPE_FN_FIELD_INLINED(thisfn, n) ((thisfn)[n].is_inlined)
+#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)
+
+#define TYPE_RUNTIME_PTR(thistype) (TYPE_CPLUS_SPECIFIC(thistype)->runtime_ptr)
+#define TYPE_VTABLE(thistype) (TYPE_RUNTIME_PTR(thistype)->has_vtable)
+#define TYPE_HAS_VTABLE(thistype) (TYPE_RUNTIME_PTR(thistype) && TYPE_VTABLE(thistype))
+#define TYPE_PRIMARY_BASE(thistype) (TYPE_RUNTIME_PTR(thistype)->primary_base)
+#define TYPE_VIRTUAL_BASE_LIST(thistype) (TYPE_RUNTIME_PTR(thistype)->virtual_base_list)
+
+#define TYPE_LOCALTYPE_PTR(thistype) (TYPE_CPLUS_SPECIFIC(thistype)->localtype_ptr)
+#define TYPE_LOCALTYPE_FILE(thistype) (TYPE_CPLUS_SPECIFIC(thistype)->localtype_ptr->file)
+#define TYPE_LOCALTYPE_LINE(thistype) (TYPE_CPLUS_SPECIFIC(thistype)->localtype_ptr->line)
+
+#define TYPE_IS_OPAQUE(thistype) (((TYPE_CODE (thistype) == TYPE_CODE_STRUCT) || \
+ (TYPE_CODE (thistype) == TYPE_CODE_UNION)) && \
+ (TYPE_NFIELDS (thistype) == 0) && \
+ (TYPE_CPLUS_SPECIFIC (thistype) && (TYPE_NFN_FIELDS (thistype) == 0)))
+
+
+
+/* Implicit sizes */
+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;
+extern struct type *builtin_type_bool;
+
+/* Address/pointer types: */
+/* (C) Language `pointer to data' type. Some target platforms use an
+ implicitly {sign,zero} -extended 32 bit C language pointer on a 64
+ bit ISA. */
+extern struct type *builtin_type_void_data_ptr;
+
+/* (C) Language `pointer to function returning void' type. Since
+ ANSI, C standards have explicitly said that pointers to functions
+ and pointers to data are not interconvertible --- that is, you
+ can't cast a function pointer to void * and back, and expect to get
+ the same value. However, all function pointer types are
+ interconvertible, so void (*) () can server as a generic function
+ pointer. */
+extern struct type *builtin_type_void_func_ptr;
+
+/* The target CPU's address type. This is the ISA address size. */
+extern struct type *builtin_type_CORE_ADDR;
+/* The symbol table address type. Some object file formats have a 32
+ bit address type even though the TARGET has a 64 bit pointer type
+ (cf MIPS). */
+extern struct type *builtin_type_bfd_vma;
+
+/* Explicit sizes - see C9X <intypes.h> for naming scheme. The "int0"
+ is for when an architecture needs to describe a register that has
+ no size. */
+extern struct type *builtin_type_int0;
+extern struct type *builtin_type_int8;
+extern struct type *builtin_type_uint8;
+extern struct type *builtin_type_int16;
+extern struct type *builtin_type_uint16;
+extern struct type *builtin_type_int32;
+extern struct type *builtin_type_uint32;
+extern struct type *builtin_type_int64;
+extern struct type *builtin_type_uint64;
+extern struct type *builtin_type_int128;
+extern struct type *builtin_type_uint128;
+
+/* SIMD types. We inherit these names from GCC. */
+extern struct type *builtin_type_v4sf;
+extern struct type *builtin_type_v4si;
+extern struct type *builtin_type_v16qi;
+extern struct type *builtin_type_v8qi;
+extern struct type *builtin_type_v8hi;
+extern struct type *builtin_type_v4hi;
+extern struct type *builtin_type_v2si;
+
+/* Type for 64 bit vectors. */
+extern struct type *builtin_type_vec64;
+extern struct type *builtin_type_vec64i;
+
+/* Type for 128 bit vectors. */
+extern struct type *builtin_type_vec128;
+extern struct type *builtin_type_vec128i;
+
+/* Explicit floating-point formats. See "floatformat.h". */
+extern struct type *builtin_type_ieee_single_big;
+extern struct type *builtin_type_ieee_single_little;
+extern struct type *builtin_type_ieee_double_big;
+extern struct type *builtin_type_ieee_double_little;
+extern struct type *builtin_type_ieee_double_littlebyte_bigword;
+extern struct type *builtin_type_i387_ext;
+extern struct type *builtin_type_m68881_ext;
+extern struct type *builtin_type_i960_ext;
+extern struct type *builtin_type_m88110_ext;
+extern struct type *builtin_type_m88110_harris_ext;
+extern struct type *builtin_type_arm_ext_big;
+extern struct type *builtin_type_arm_ext_littlebyte_bigword;
+extern struct type *builtin_type_ia64_spill_big;
+extern struct type *builtin_type_ia64_spill_little;
+extern struct type *builtin_type_ia64_quad_big;
+extern struct type *builtin_type_ia64_quad_little;
+
+/* We use this for the '/c' print format, because builtin_type_char is
+ just a one-byte integral type, which languages less laid back than
+ C will print as ... well, a one-byte integral type. */
+extern struct type *builtin_type_true_char;
+
+/* 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;
+
+/* Fortran (F77) types */
+
+extern struct type *builtin_type_f_character;
+extern struct type *builtin_type_f_integer;
+extern struct type *builtin_type_f_integer_s2;
+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_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;
+
+/* RTTI for C++ */
+/* extern struct type *builtin_type_cxx_typeinfo; */
+
+/* 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 objfile_obstack, then the space for data
+ associated with that type will also be allocated on the objfile_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) -> objfile_obstack, size) \
+ : xmalloc (size))
+
+extern struct type *alloc_type (struct objfile *);
+
+extern struct type *init_type (enum type_code, int, int, char *,
+ struct objfile *);
+
+/* Helper functions to construct a struct or record type. An
+ initially empty type is created using init_composite_type().
+ Fields are then added using append_struct_type_field(). A union
+ type has its size set to the largest field. A struct type has each
+ field packed against the previous. */
+
+extern struct type *init_composite_type (char *name, enum type_code code);
+extern void append_composite_type_field (struct type *t, char *name,
+ struct type *field);
+
+extern struct type *lookup_reference_type (struct type *);
+
+extern struct type *make_reference_type (struct type *, struct type **);
+
+extern struct type *make_cv_type (int, int, struct type *, struct type **);
+
+extern void replace_type (struct type *, struct type *);
+
+extern int address_space_name_to_int (char *);
+
+extern const char *address_space_int_to_name (int);
+
+extern struct type *make_type_with_address_space (struct type *type,
+ int space_identifier);
+
+extern struct type *lookup_member_type (struct type *, struct type *);
+
+extern void
+smash_to_method_type (struct type *type, struct type *domain,
+ struct type *to_type, struct field *args,
+ int nargs, int varargs);
+
+extern void smash_to_member_type (struct type *, struct type *, struct type *);
+
+extern struct type *allocate_stub_method (struct type *);
+
+extern char *type_name_no_tag (const struct type *);
+
+extern struct type *lookup_struct_elt_type (struct type *, char *, int);
+
+extern struct type *make_pointer_type (struct type *, struct type **);
+
+extern struct type *lookup_pointer_type (struct type *);
+
+extern struct type *make_function_type (struct type *, struct type **);
+
+extern struct type *lookup_function_type (struct type *);
+
+extern struct type *create_range_type (struct type *, struct type *, int,
+ int);
+
+extern struct type *create_array_type (struct type *, struct type *,
+ struct type *);
+
+extern struct type *create_string_type (struct type *, struct type *);
+
+extern struct type *create_set_type (struct type *, struct type *);
+
+extern struct type *lookup_unsigned_typename (char *);
+
+extern struct type *lookup_signed_typename (char *);
+
+extern struct type *check_typedef (struct type *);
+
+#define CHECK_TYPEDEF(TYPE) (TYPE) = check_typedef (TYPE)
+
+extern void check_stub_method_group (struct type *, int);
+
+extern struct type *lookup_primitive_typename (char *);
+
+extern char *gdb_mangle_name (struct type *, int, int);
+
+extern struct type *builtin_type (char **);
+
+extern struct type *lookup_typename (char *, struct block *, int);
+
+extern struct type *lookup_template_type (char *, struct type *,
+ struct block *);
+
+extern struct type *lookup_fundamental_type (struct objfile *, int);
+
+extern void fill_in_vptr_fieldno (struct type *);
+
+extern int get_destructor_fn_field (struct type *, int *, int *);
+
+extern int get_discrete_bounds (struct type *, LONGEST *, LONGEST *);
+
+extern int is_ancestor (struct type *, struct type *);
+
+extern int has_vtable (struct type *);
+
+extern struct type *primary_base_class (struct type *);
+
+extern struct type **virtual_base_list (struct type *);
+
+extern int virtual_base_list_length (struct type *);
+extern int virtual_base_list_length_skip_primaries (struct type *);
+
+extern int virtual_base_index (struct type *, struct type *);
+extern int virtual_base_index_skip_primaries (struct type *, struct type *);
+
+
+extern int class_index_in_primary_list (struct type *);
+
+extern int count_virtual_fns (struct type *);
+
+/* Constants for HP/Taligent ANSI C++ runtime model */
+
+/* Where virtual function entries begin in the
+ * virtual table, in the non-RRBC vtable format.
+ * First 4 are the metavtable pointer, top offset,
+ * typeinfo pointer, and dup base info pointer */
+#define HP_ACC_VFUNC_START 4
+
+/* (Negative) Offset where virtual base offset entries begin
+ * in the virtual table. Skips over metavtable pointer and
+ * the self-offset entry.
+ * NOTE: NEGATE THIS BEFORE USING! The virtual base offsets
+ * appear before the address point of the vtable (the slot
+ * pointed to by the object's vtable pointer), i.e. at lower
+ * addresses than the vtable pointer. */
+#define HP_ACC_VBASE_START 2
+
+/* (Positive) Offset where the pointer to the typeinfo
+ * object is present in the virtual table */
+#define HP_ACC_TYPEINFO_OFFSET 2
+
+/* (Positive) Offset where the ``top offset'' entry of
+ * the virtual table is */
+#define HP_ACC_TOP_OFFSET_OFFSET 1
+
+/* Overload resolution */
+
+#define LENGTH_MATCH(bv) ((bv)->rank[0])
+
+/* Badness if parameter list length doesn't match arg list length */
+#define LENGTH_MISMATCH_BADNESS 100
+/* Dummy badness value for nonexistent parameter positions */
+#define TOO_FEW_PARAMS_BADNESS 100
+/* Badness if no conversion among types */
+#define INCOMPATIBLE_TYPE_BADNESS 100
+
+/* Badness of integral promotion */
+#define INTEGER_PROMOTION_BADNESS 1
+/* Badness of floating promotion */
+#define FLOAT_PROMOTION_BADNESS 1
+/* Badness of integral conversion */
+#define INTEGER_CONVERSION_BADNESS 2
+/* Badness of floating conversion */
+#define FLOAT_CONVERSION_BADNESS 2
+/* Badness of integer<->floating conversions */
+#define INT_FLOAT_CONVERSION_BADNESS 2
+/* Badness of converting to a boolean */
+#define BOOLEAN_CONVERSION_BADNESS 2
+/* Badness of pointer conversion */
+#define POINTER_CONVERSION_BADNESS 2
+/* Badness of conversion of pointer to void pointer */
+#define VOID_PTR_CONVERSION_BADNESS 2
+/* Badness of converting derived to base class */
+#define BASE_CONVERSION_BADNESS 2
+/* Badness of converting from non-reference to reference */
+#define REFERENCE_CONVERSION_BADNESS 2
+
+/* Non-standard conversions allowed by the debugger */
+/* Converting a pointer to an int is usually OK */
+#define NS_POINTER_CONVERSION_BADNESS 10
+
+
+extern int compare_badness (struct badness_vector *, struct badness_vector *);
+
+extern struct badness_vector *rank_function (struct type **, int,
+ struct type **, int);
+
+extern int rank_one_type (struct type *, struct type *);
+
+extern void recursive_dump_type (struct type *, int);
+
+/* printcmd.c */
+
+extern void print_scalar_formatted (void *, struct type *, int, int,
+ struct ui_file *);
+
+extern int can_dereference (struct type *);
+
+extern int is_integral_type (struct type *);
+
+extern void maintenance_print_type (char *, int);
+
+#endif /* GDBTYPES_H */
diff --git a/contrib/gdb/gdb/glibc-tdep.c b/contrib/gdb/gdb/glibc-tdep.c
new file mode 100644
index 0000000..04bb683
--- /dev/null
+++ b/contrib/gdb/gdb/glibc-tdep.c
@@ -0,0 +1,101 @@
+/* Target-dependent code for the GNU C Library (glibc).
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "symfile.h"
+#include "objfiles.h"
+
+#include "glibc-tdep.h"
+
+/* Calling functions in shared libraries. */
+
+/* Find the minimal symbol named NAME, and return both the minsym
+ struct and its objfile. This probably ought to be in minsym.c, but
+ everything there is trying to deal with things like C++ and
+ SOFUN_ADDRESS_MAYBE_TURQUOISE, ... Since this is so simple, it may
+ be considered too special-purpose for general consumption. */
+
+static struct minimal_symbol *
+find_minsym_and_objfile (char *name, struct objfile **objfile_p)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct minimal_symbol *msym;
+
+ ALL_OBJFILE_MSYMBOLS (objfile, msym)
+ {
+ if (SYMBOL_LINKAGE_NAME (msym)
+ && strcmp (SYMBOL_LINKAGE_NAME (msym), name) == 0)
+ {
+ *objfile_p = objfile;
+ return msym;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c.
+ This function:
+ 1) decides whether a PLT has sent us into the linker to resolve
+ a function reference, and
+ 2) if so, tells us where to set a temporary breakpoint that will
+ trigger when the dynamic linker is done. */
+
+CORE_ADDR
+glibc_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ /* The GNU dynamic linker is part of the GNU C library, and is used
+ by all GNU systems (GNU/Hurd, GNU/Linux). An unresolved PLT
+ entry points to "_dl_runtime_resolve", which calls "fixup" to
+ patch the PLT, and then passes control to the function.
+
+ We look for the symbol `_dl_runtime_resolve', and find `fixup' in
+ the same objfile. If we are at the entry point of `fixup', then
+ we set a breakpoint at the return address (at the top of the
+ stack), and continue.
+
+ It's kind of gross to do all these checks every time we're
+ called, since they don't change once the executable has gotten
+ started. But this is only a temporary hack --- upcoming versions
+ of GNU/Linux will provide a portable, efficient interface for
+ debugging programs that use shared libraries. */
+
+ struct objfile *objfile;
+ struct minimal_symbol *resolver
+ = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile);
+
+ if (resolver)
+ {
+ struct minimal_symbol *fixup
+ = lookup_minimal_symbol ("fixup", NULL, objfile);
+
+ if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
+ return frame_pc_unwind (get_current_frame ());
+ }
+
+ return 0;
+}
diff --git a/contrib/gdb/gdb/glibc-tdep.h b/contrib/gdb/gdb/glibc-tdep.h
new file mode 100644
index 0000000..75598d5
--- /dev/null
+++ b/contrib/gdb/gdb/glibc-tdep.h
@@ -0,0 +1,30 @@
+/* Target-dependent code for the GNU C Library (glibc).
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GLIBC_TDEP_H
+#define GLIBC_TDEP_H
+
+struct gdbarch;
+
+extern CORE_ADDR glibc_skip_solib_resolver (struct gdbarch *gdbarch,
+ CORE_ADDR);
+
+#endif /* glibc-tdep.h */
diff --git a/contrib/gdb/gdb/gnu-nat.c b/contrib/gdb/gdb/gnu-nat.c
new file mode 100644
index 0000000..a61d577
--- /dev/null
+++ b/contrib/gdb/gdb/gnu-nat.c
@@ -0,0 +1,3409 @@
+/* Interface GDB to the GNU Hurd.
+ Copyright 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Some code and ideas from m3-nat.c by Jukka Virtanen <jtv@hut.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include "gdb_string.h"
+#include <sys/ptrace.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/exception.h>
+#include <mach/message.h>
+#include <mach/notify.h>
+#include <mach/vm_attributes.h>
+
+#include <hurd.h>
+#include <hurd/interrupt.h>
+#include <hurd/msg.h>
+#include <hurd/msg_request.h>
+#include <hurd/process.h>
+#include <hurd/process_request.h>
+#include <hurd/signal.h>
+#include <hurd/sigpreempt.h>
+
+#include <portinfo.h>
+
+#include "defs.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "language.h"
+#include "target.h"
+#include "gdb_wait.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdbthread.h"
+#include "gdb_assert.h"
+#include "gdb_obstack.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);
+int inf_update_suspends (struct inf *inf);
+void inf_set_pid (struct inf *inf, pid_t pid);
+void inf_validate_procs (struct inf *inf);
+void inf_steal_exc_ports (struct inf *inf);
+void inf_restore_exc_ports (struct inf *inf);
+struct proc *inf_tid_to_proc (struct inf *inf, int tid);
+void inf_set_threads_resume_sc (struct inf *inf,
+ struct proc *run_thread,
+ int run_others);
+int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf);
+void inf_suspend (struct inf *inf);
+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);
+void inf_continue (struct inf *inf);
+
+#define inf_debug(_inf, msg, args...) \
+ do { struct inf *__inf = (_inf); \
+ debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0)
+
+void proc_abort (struct proc *proc, int force);
+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);
+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);
+
+/* 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)
+
+
+/* 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. */
+ unsigned 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... */
+ unsigned int stopped:1;
+
+ /* True if the inferior has no message port. */
+ unsigned int nomsg:1;
+
+ /* True if the inferior is traced. */
+ unsigned int traced:1;
+
+ /* True if we shouldn't try waiting for the inferior, usually because we
+ can't for some reason. */
+ unsigned 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 task suspend count left when detaching from a task. */
+ int detach_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;
+ int default_thread_detach_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. */
+ {
+ gdb_assert (proc_is_thread (proc));
+ proc_debug (proc, "storing back changed thread state");
+ err = thread_set_state (proc->port, THREAD_STATE_FLAVOR,
+ (thread_state_t) &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", safe_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)
+{
+ gdb_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,
+ (thread_state_t) &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 (thread_state_t) &proc->state;
+ }
+ else
+ return 0;
+}
+
+
+/* Set PORT to PROC's exception port. */
+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);
+}
+
+/* Set PROC's exception port to 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 = 0;
+
+ 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), safe_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 been
+ 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), safe_strerror (err));
+ }
+}
+
+
+/* Turns hardware tracing in PROC on or off when SET is true or false,
+ 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 = xmalloc (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;
+
+ /* Note that these are all the values for threads; the task simply uses the
+ corresponding field in INF directly. */
+ proc->run_sc = inf->default_thread_run_sc;
+ proc->pause_sc = inf->default_thread_pause_sc;
+ proc->detach_sc = inf->default_thread_detach_sc;
+ proc->resume_sc = proc->run_sc;
+
+ proc->aborted = 0;
+ proc->dead = 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, safe_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);
+ }
+
+ xfree (proc);
+ return next;
+}
+
+
+struct inf *
+make_inf (void)
+{
+ struct inf *inf = xmalloc (sizeof (struct inf));
+
+ 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->running = 0;
+ inf->stopped = 0;
+ inf->nomsg = 1;
+ inf->traced = 0;
+ inf->no_wait = 0;
+ inf->pending_execs = 0;
+ inf->pause_sc = 1;
+ inf->detach_sc = 0;
+ inf->default_thread_run_sc = 0;
+ inf->default_thread_pause_sc = 0;
+ inf->default_thread_detach_sc = 0;
+ inf->want_signals = 1; /* By default */
+ inf->want_exceptions = 1; /* By default */
+
+ return inf;
+}
+
+/* Clear INF's target wait status. */
+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_pid (inf, -1);
+ inf->pid = 0;
+ inf->running = 0;
+ inf->stopped = 0;
+ inf->nomsg = 1;
+ inf->traced = 0;
+ inf->no_wait = 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)
+{
+ error_t err;
+
+ inf_debug (inf, "startup: pid = %d", pid);
+
+ 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", safe_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);
+ inf_set_pid (inf, pid);
+}
+
+
+/* Close current process, if any, and attach INF to process PORT. */
+void
+inf_set_pid (struct inf *inf, pid_t pid)
+{
+ task_t task_port;
+ struct proc *task = inf->task;
+
+ inf_debug (inf, "setting pid: %d", pid);
+
+ if (pid < 0)
+ task_port = MACH_PORT_NULL;
+ else
+ {
+ error_t err = proc_pid2task (proc_server, pid, &task_port);
+ if (err)
+ error ("Error getting task for pid %d: %s", pid, safe_strerror (err));
+ }
+
+ inf_debug (inf, "setting task: %d", task_port);
+
+ if (inf->pause_sc)
+ task_suspend (task_port);
+
+ if (task && task->port != task_port)
+ {
+ inf->task = 0;
+ inf_validate_procs (inf); /* Trash all the threads. */
+ _proc_free (task); /* And the task. */
+ }
+
+ if (task_port != MACH_PORT_NULL)
+ {
+ inf->task = make_proc (inf, task_port, PROC_TID_TASK);
+ inf->threads_up_to_date = 0;
+ }
+
+ if (inf->task)
+ {
+ inf->pid = pid;
+ if (inf->pause_sc)
+ /* Reflect task_suspend above. */
+ inf->task->sc = inf->task->cur_sc = 1;
+ }
+ else
+ inf->pid = -1;
+}
+
+
+/* Validates INF's stopped, nomsg and traced field from the actual
+ proc server state. Note that the traced field is only updated from
+ the proc server state if we do not have a message port. If we do
+ have a message port we'd better look at the tracemask itself. */
+static void
+inf_validate_procinfo (struct inf *inf)
+{
+ char *noise;
+ mach_msg_type_number_t noise_len = 0;
+ struct procinfo *pi;
+ mach_msg_type_number_t pi_len = 0;
+ int info_flags = 0;
+ error_t err =
+ proc_getprocinfo (proc_server, inf->pid, &info_flags,
+ (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
+
+ if (!err)
+ {
+ inf->stopped = !!(pi->state & PI_STOPPED);
+ inf->nomsg = !!(pi->state & PI_NOMSG);
+ if (inf->nomsg)
+ inf->traced = !!(pi->state & PI_TRACED);
+ 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. If it's higher than we expect,
+ verify with the user before `stealing' the extra count. */
+static void
+inf_validate_task_sc (struct inf *inf)
+{
+ char *noise;
+ mach_msg_type_number_t noise_len = 0;
+ struct procinfo *pi;
+ mach_msg_type_number_t pi_len = 0;
+ int info_flags = PI_FETCH_TASKINFO;
+ int suspend_count = -1;
+ error_t err;
+
+ retry:
+ err = proc_getprocinfo (proc_server, inf->pid, &info_flags,
+ (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
+ if (err)
+ {
+ inf->task->dead = 1; /* oh well */
+ return;
+ }
+
+ if (inf->task->cur_sc < pi->taskinfo.suspend_count && suspend_count == -1)
+ {
+ /* The proc server might have suspended the task while stopping
+ it. This happens when the task is handling a traced signal.
+ Refetch the suspend count. The proc server should be
+ finished stopping the task by now. */
+ suspend_count = pi->taskinfo.suspend_count;
+ goto retry;
+ }
+
+ suspend_count = pi->taskinfo.suspend_count;
+
+ vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+ if (noise_len > 0)
+ vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+
+ if (inf->task->cur_sc < suspend_count)
+ {
+ int abort;
+
+ target_terminal_ours (); /* Allow I/O. */
+ abort = !query ("Pid %d has an additional task suspend count of %d;"
+ " clear it? ", inf->pid,
+ suspend_count - inf->task->cur_sc);
+ target_terminal_inferior (); /* Give it back to the child. */
+
+ if (abort)
+ error ("Additional task suspend count left untouched.");
+
+ inf->task->cur_sc = 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)
+ return;
+
+ if (inf->task && !inf->task->dead)
+ /* Make it take effect immediately. */
+ {
+ sigset_t mask = on ? ~(sigset_t) 0 : 0;
+ error_t err =
+ INF_RESUME_MSGPORT_RPC (inf, msg_set_init_int (msgport, refport,
+ INIT_TRACEMASK, mask));
+ if (err == EIEIO)
+ {
+ if (on)
+ warning ("Can't modify tracing state for pid %d: %s",
+ inf->pid, "No signal thread");
+ inf->traced = on;
+ }
+ else if (err)
+ warning ("Can't modify tracing state for pid %d: %s",
+ inf->pid, safe_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)
+{
+ thread_array_t threads;
+ mach_msg_type_number_t num_threads, i;
+ struct proc *task = inf->task;
+
+ /* If no threads are currently running, this function will guarantee that
+ things are up to date. The exception is if there are zero threads --
+ then it is almost certainly in an odd state, and probably some outside
+ agent will create threads. */
+ inf->threads_up_to_date = inf->threads ? !inf->running : 0;
+
+ if (task)
+ {
+ error_t err = task_threads (task->port, &threads, &num_threads);
+ inf_debug (inf, "fetching threads");
+ if (err)
+ /* TASK must be dead. */
+ {
+ task->dead = 1;
+ task = 0;
+ }
+ }
+
+ if (!task)
+ {
+ num_threads = 0;
+ inf_debug (inf, "no task");
+ }
+
+ {
+ /* Make things normally linear. */
+ mach_msg_type_number_t search_start = 0;
+ /* 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;
+
+ memset (matched, 0, sizeof (matched));
+
+ while (thread)
+ {
+ mach_msg_type_number_t 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 (pid_to_ptid (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. */
+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. */
+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). */
+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)
+ {
+ if (!inf->pending_execs)
+ /* Try to make sure our task count is correct -- in the case where
+ we're waiting for an exec though, things are too volatile, so just
+ assume things will be reasonable (which they usually will be). */
+ inf_validate_task_sc (inf);
+ inf->task->sc = 0;
+ }
+
+ inf_update_suspends (inf);
+}
+
+/* Cause INF to stop execution immediately; individual threads may still
+ be running. */
+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
+ function changes it to be PROC, changing any old step_thread to be
+ a normal one. A PROC of 0 clears any existing value. */
+void
+inf_set_step_thread (struct inf *inf, struct proc *thread)
+{
+ gdb_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. */
+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_validate_procinfo (inf);
+
+ inf_set_traced (inf, 0);
+ if (inf->stopped)
+ {
+ if (inf->nomsg)
+ inf_continue (inf);
+ else
+ inf_signal (inf, TARGET_SIGNAL_0);
+ }
+
+ proc_restore_exc_port (task);
+ task->sc = inf->detach_sc;
+
+ for (thread = inf->threads; thread; thread = thread->next)
+ {
+ proc_restore_exc_port (thread);
+ thread->sc = thread->detach_sc;
+ }
+
+ 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)
+{
+ inf_debug (inf, "attaching: %d", pid);
+
+ if (inf->pid)
+ inf_detach (inf);
+
+ inf_startup (inf, pid);
+}
+
+
+/* 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
+ error ("Can't forward spontaneous exception (%s).", NAME);
+ }
+ else
+ /* A Unix signal. */
+ if (inf->stopped)
+ /* The process is stopped and 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, 0,
+ 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,
+ 0, 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, safe_strerror (err));
+
+#undef NAME
+}
+
+
+/* Continue INF without delivering a signal. This is meant to be used
+ when INF does not have a message port. */
+void
+inf_continue (struct inf *inf)
+{
+ process_t proc;
+ error_t err = proc_pid2proc (proc_server, inf->pid, &proc);
+
+ if (!err)
+ {
+ inf_debug (inf, "continuing process");
+
+ err = proc_mark_cont (proc);
+ if (!err)
+ {
+ struct proc *thread;
+
+ for (thread = inf->threads; thread; thread = thread->next)
+ thread_resume (thread->port);
+
+ inf->stopped = 0;
+ }
+ }
+
+ if (err)
+ warning ("Can't continue process: %s", safe_strerror (err));
+}
+
+
+/* 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 ptid_t
+gnu_wait (ptid_t 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;
+
+ extern int exc_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int msg_reply_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int process_reply_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ gdb_assert (inf->task);
+
+ if (!inf->threads && !inf->pending_execs)
+ /* No threads! Assume that maybe some outside agency is frobbing our
+ task, and really look for new threads. If we can't find any, just tell
+ the user to try again later. */
+ {
+ inf_validate_procs (inf);
+ if (!inf->threads && !inf->task->dead)
+ error ("There are no threads; try again later.");
+ }
+
+ waiting_inf = inf;
+
+ inf_debug (inf, "waiting for: %d", PIDGET (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, 0);
+ }
+
+ err =
+ proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED);
+ if (err)
+ warning ("wait request failed: %s", safe_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 = mach_msg (&msg.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT,
+ 0, sizeof (struct msg), inf->event_port,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+ /* Re-suspend the task. */
+ inf_suspend (inf);
+
+ if (!inf->task && inf->pending_execs)
+ /* When doing an exec, it's possible that the old task wasn't reused
+ (e.g., setuid execs). So if the task seems to have disappeared,
+ attempt to refetch it, as the pid should still be the same. */
+ inf_set_pid (inf, inf->pid);
+
+ if (err == EMACH_RCV_INTERRUPTED)
+ inf_debug (inf, "interrupted");
+ else if (err)
+ error ("Couldn't wait for an event: %s", safe_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, safe_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;
+ inf_debug (inf, "pending_execs = %d, ignoring minor event",
+ inf->pending_execs);
+ }
+ 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! */
+ {
+#if 0 /* do we need this? */
+ prune_threads (1); /* Get rid of the old shell threads */
+ renumber_threads (0); /* Give our threads reasonable names. */
+#endif
+ }
+ inf_debug (inf, "pending exec completed, pending_execs => %d",
+ inf->pending_execs);
+ }
+ else if (kind == TARGET_WAITKIND_STOPPED)
+ /* It's possible that this signal is because of a crashed process
+ being handled by the hurd crash server; in this case, the process
+ will have an extra task suspend, which we need to know about.
+ Since the code in inf_resume that normally checks for this is
+ disabled while INF->pending_execs, we do the check here instead. */
+ inf_validate_task_sc (inf);
+ }
+
+ 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 = pid_to_ptid (thread->tid);
+ else
+ thread = inf_tid_to_thread (inf, PIDGET (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 = pid_to_ptid (inf->threads->tid); /* The first available thread. */
+ else
+ tid = inferior_ptid; /* let wait_for_inferior handle exit case */
+ }
+
+ if (thread && PIDGET (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)", PIDGET (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, subcode);
+
+ 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_debug (waiting_inf, "Handler is thread exception port <%d>",
+ thread->saved_exc_port);
+ inf->wait.exc.handler = thread->saved_exc_port;
+ }
+ else
+ {
+ inf_debug (waiting_inf, "Handler is task exception port <%d>",
+ inf->task->saved_exc_port);
+ inf->wait.exc.handler = inf->task->saved_exc_port;
+ gdb_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;
+ }
+
+ if (inf->task->dead)
+ /* Since the task is dead, its threads are dying with it. */
+ inf->wait.suppress = 1;
+ }
+
+ 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 ("do_mach_notify_no_senders");
+}
+
+error_t
+do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name)
+{
+ return ill_rpc ("do_mach_notify_port_deleted");
+}
+
+error_t
+do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name)
+{
+ return ill_rpc ("do_mach_notify_msg_accepted");
+}
+
+error_t
+do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name)
+{
+ return ill_rpc ("do_mach_notify_port_destroyed");
+}
+
+error_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return ill_rpc ("do_mach_notify_send_once");
+}
+
+
+/* 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, int sigcode, rusage_t rusage, pid_t pid)
+{
+ struct inf *inf = waiting_inf;
+
+ inf_debug (inf, "err = %s, pid = %d, status = 0x%x, sigcode = %d",
+ err ? safe_strerror (err) : "0", pid, status, sigcode);
+
+ 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, safe_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;
+ }
+ }
+ 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 ("S_proc_setmsgport_reply");
+}
+
+error_t
+S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port)
+{
+ return ill_rpc ("S_proc_getmsgport_reply");
+}
+
+
+/* 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", safe_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 ("S_msg_sig_post_reply");
+}
+
+
+/* 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 (ptid_t 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", PIDGET (tid), step, sig);
+
+ inf_validate_procinfo (inf);
+
+ if (sig != TARGET_SIGNAL_0 || inf->stopped)
+ {
+ if (sig == TARGET_SIGNAL_0 && inf->nomsg)
+ inf_continue (inf);
+ else
+ 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;
+
+ inf_update_procs (inf);
+
+ if (PIDGET (tid) < 0)
+ /* Allow all threads to run, except perhaps single-stepping one. */
+ {
+ inf_debug (inf, "running all threads; tid = %d", PIDGET (inferior_ptid));
+ tid = inferior_ptid; /* 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, PIDGET (tid));
+ if (!thread)
+ error ("Can't run single thread id %d: no such 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, PIDGET (tid));
+ if (!step_thread)
+ warning ("Can't step thread id %d: no such thread.", PIDGET (tid));
+ else
+ 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 (void)
+{
+ struct proc *task = current_inferior->task;
+ if (task)
+ {
+ proc_debug (task, "terminating...");
+ task_terminate (task->port);
+ inf_set_pid (current_inferior, -1);
+ }
+ target_mourn_inferior ();
+}
+
+/* Clean up after the inferior dies. */
+static void
+gnu_mourn_inferior (void)
+{
+ 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 int
+inf_pick_first_thread (void)
+{
+ if (current_inferior->task && current_inferior->threads)
+ /* The first thread. */
+ return current_inferior->threads->tid;
+ else
+ /* What may be the next thread. */
+ return next_thread_id;
+}
+
+static struct inf *
+cur_inf (void)
+{
+ if (!current_inferior)
+ current_inferior = make_inf ();
+ return current_inferior;
+}
+
+static void
+gnu_create_inferior (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");
+ if (ptrace (PTRACE_TRACEME) != 0)
+ error ("ptrace (PTRACE_TRACEME) failed!");
+ }
+ 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);
+
+ attach_flag = 0;
+ push_target (&gnu_ops);
+
+ inf->pending_execs = 2;
+ inf->nomsg = 1;
+ inf->traced = 1;
+
+ /* Now let the child run again, knowing that it will stop immediately
+ because of the ptrace. */
+ inf_resume (inf);
+ inferior_ptid = pid_to_ptid (inf_pick_first_thread ());
+
+ startup_inferior (inf->pending_execs);
+ }
+
+ inf_debug (inf, "creating inferior");
+
+ fork_inferior (exec_file, allargs, env, trace_me, attach_to_child,
+ NULL, NULL);
+
+ inf_validate_procinfo (inf);
+ 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 (void)
+{
+ 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 (char *args, int from_tty)
+{
+ int pid;
+ char *exec_file;
+ struct inf *inf = cur_inf ();
+
+ 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', 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);
+
+ inferior_ptid = pid_to_ptid (inf_pick_first_thread ());
+
+ attach_flag = 1;
+ push_target (&gnu_ops);
+
+ /* We have to initialize the terminal settings now, since the code
+ below might try to restore them. */
+ target_terminal_init ();
+
+ /* If the process was stopped before we attached, make it continue the next
+ time the user does a continue. */
+ inf_validate_procinfo (inf);
+
+ inf_update_signal_thread (inf);
+ inf_set_traced (inf, inf->want_signals);
+
+#if 0 /* Do we need this? */
+ renumber_threads (0); /* Give our threads reasonable names. */
+#endif
+}
+
+
+/* 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 (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_ptid = null_ptid;
+
+ unpush_target (&gnu_ops); /* Pop out of handling an inferior */
+}
+#endif /* ATTACH_DETACH */
+
+
+static void
+gnu_terminal_init_inferior (void)
+{
+ gdb_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 (void)
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+static void
+gnu_open (char *arg, int from_tty)
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
+
+static void
+gnu_stop (void)
+{
+ error ("to_stop target function not implemented");
+}
+
+static char *
+gnu_pid_to_exec_file (int pid)
+{
+ error ("to_pid_to_exec_file target function not implemented");
+ return NULL;
+}
+
+
+static int
+gnu_thread_alive (ptid_t tid)
+{
+ inf_update_procs (current_inferior);
+ return !!inf_tid_to_thread (current_inferior, PIDGET (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_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, &copy_count);
+ if (err)
+ return 0;
+
+ err = hurd_safe_copyin (myaddr, (void *) addr - low_address + copied, length);
+ if (err)
+ {
+ warning ("Read from inferior faulted: %s", safe_strerror (err));
+ length = 0;
+ }
+
+ err = vm_deallocate (mach_task_self (), copied, copy_count);
+ if (err)
+ warning ("gnu_read_inferior vm_deallocate failed: %s", safe_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 gdb's LEN bytes from MYADDR and copy it to ADDR in inferior
+ task's address space. */
+int
+gnu_write_inferior (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,
+ &copy_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 (&region_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,
+ &region_address,
+ &region_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 (&region_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)
+ {
+ 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)
+ {
+ 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 (&region_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. TARGET
+ is ignored. */
+static int
+gnu_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ 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", (void *) memaddr, len,
+ write ? "<--" : "-->", myaddr);
+ if (write)
+ return gnu_write_inferior (task, memaddr, myaddr, len);
+ else
+ return gnu_read_inferior (task, memaddr, myaddr, len);
+ }
+}
+
+/* Call FUNC on each memory region in the task. */
+static int
+gnu_find_memory_regions (int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ error_t err;
+ task_t task;
+ vm_address_t region_address, last_region_address, last_region_end;
+ vm_prot_t last_protection;
+
+ if (current_inferior == 0 || current_inferior->task == 0)
+ return 0;
+ task = current_inferior->task->port;
+ if (task == MACH_PORT_NULL)
+ return 0;
+
+ region_address = last_region_address = last_region_end = VM_MIN_ADDRESS;
+ last_protection = VM_PROT_NONE;
+ while (region_address < VM_MAX_ADDRESS)
+ {
+ 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 = VM_MAX_ADDRESS - region_address;
+ vm_address_t old_address = region_address;
+
+ err = vm_region (task,
+ &region_address,
+ &region_length,
+ &protection,
+ &max_protection,
+ &inheritance,
+ &shared,
+ &object_name,
+ &offset);
+ if (err == KERN_NO_SPACE)
+ break;
+ if (err != KERN_SUCCESS)
+ {
+ warning ("vm_region failed: %s", mach_error_string (err));
+ return -1;
+ }
+
+ if (protection == last_protection && region_address == last_region_end)
+ /* This region is contiguous with and indistinguishable from
+ the previous one, so we just extend that one. */
+ last_region_end = region_address += region_length;
+ else
+ {
+ /* This region is distinct from the last one we saw, so report
+ that previous one. */
+ if (last_protection != VM_PROT_NONE)
+ (*func) (last_region_address,
+ last_region_end - last_region_address,
+ last_protection & VM_PROT_READ,
+ last_protection & VM_PROT_WRITE,
+ last_protection & VM_PROT_EXECUTE,
+ data);
+ last_region_address = region_address;
+ last_region_end = region_address += region_length;
+ last_protection = protection;
+ }
+ }
+
+ /* Report the final region. */
+ if (last_region_end > last_region_address && last_protection != VM_PROT_NONE)
+ (*func) (last_region_address, last_region_end - last_region_address,
+ last_protection & VM_PROT_READ,
+ last_protection & VM_PROT_WRITE,
+ last_protection & VM_PROT_EXECUTE,
+ data);
+
+ return 0;
+}
+
+
+/* Return printable description of proc. */
+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 (MERGEPID (proc->tid, 0)));
+ return tid_str;
+}
+
+static char *
+gnu_pid_to_str (ptid_t ptid)
+{
+ struct inf *inf = current_inferior;
+ int tid = PIDGET (ptid);
+ 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;
+ }
+}
+
+
+extern void gnu_store_registers (int regno);
+extern void gnu_fetch_registers (int regno);
+
+struct target_ops gnu_ops;
+
+static void
+init_gnu_ops (void)
+{
+ gnu_ops.to_shortname = "GNU"; /* to_shortname */
+ gnu_ops.to_longname = "GNU Hurd process"; /* to_longname */
+ gnu_ops.to_doc = "GNU Hurd process"; /* to_doc */
+ gnu_ops.to_open = gnu_open; /* to_open */
+ gnu_ops.to_attach = gnu_attach; /* to_attach */
+ gnu_ops.to_detach = gnu_detach; /* to_detach */
+ gnu_ops.to_resume = gnu_resume; /* to_resume */
+ gnu_ops.to_wait = gnu_wait; /* to_wait */
+ gnu_ops.to_fetch_registers = gnu_fetch_registers; /* to_fetch_registers */
+ gnu_ops.to_store_registers = gnu_store_registers; /* to_store_registers */
+ gnu_ops.to_prepare_to_store = gnu_prepare_to_store; /* to_prepare_to_store */
+ gnu_ops.to_xfer_memory = gnu_xfer_memory; /* to_xfer_memory */
+ gnu_ops.to_find_memory_regions = gnu_find_memory_regions;
+ gnu_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ gnu_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ gnu_ops.to_terminal_init = gnu_terminal_init_inferior;
+ gnu_ops.to_terminal_inferior = terminal_inferior;
+ gnu_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ gnu_ops.to_terminal_save_ours = terminal_save_ours;
+ gnu_ops.to_terminal_ours = terminal_ours;
+ gnu_ops.to_terminal_info = child_terminal_info;
+ gnu_ops.to_kill = gnu_kill_inferior; /* to_kill */
+ gnu_ops.to_create_inferior = gnu_create_inferior; /* to_create_inferior */
+ gnu_ops.to_mourn_inferior = gnu_mourn_inferior; /* to_mourn_inferior */
+ gnu_ops.to_can_run = gnu_can_run; /* to_can_run */
+ gnu_ops.to_thread_alive = gnu_thread_alive; /* to_thread_alive */
+ gnu_ops.to_pid_to_str = gnu_pid_to_str; /* to_pid_to_str */
+ gnu_ops.to_stop = gnu_stop; /* to_stop */
+ gnu_ops.to_pid_to_exec_file = gnu_pid_to_exec_file; /* to_pid_to_exec_file */
+ gnu_ops.to_stratum = process_stratum; /* to_stratum */
+ gnu_ops.to_has_all_memory = 1; /* to_has_all_memory */
+ gnu_ops.to_has_memory = 1; /* to_has_memory */
+ gnu_ops.to_has_stack = 1; /* to_has_stack */
+ gnu_ops.to_has_registers = 1; /* to_has_registers */
+ gnu_ops.to_has_execution = 1; /* to_has_execution */
+ gnu_ops.to_magic = OPS_MAGIC; /* to_magic */
+} /* init_gnu_ops */
+
+
+/* User task commands. */
+
+struct cmd_list_element *set_task_cmd_list = 0;
+struct cmd_list_element *show_task_cmd_list = 0;
+/* User thread commands. */
+
+/* Commands with a prefix of `set/show thread'. */
+extern struct cmd_list_element *thread_cmd_list;
+struct cmd_list_element *set_thread_cmd_list = NULL;
+struct cmd_list_element *show_thread_cmd_list = NULL;
+
+/* Commands with a prefix of `set/show thread default'. */
+struct cmd_list_element *set_thread_default_cmd_list = NULL;
+struct cmd_list_element *show_thread_default_cmd_list = NULL;
+
+static void
+set_thread_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set thread\" must be followed by the name of a thread property, or \"default\".\n");
+}
+
+static void
+show_thread_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"show thread\" must be followed by the name of a thread property, or \"default\".\n");
+}
+
+static void
+set_thread_default_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set thread default\" must be followed by the name of a thread property.\n");
+}
+
+static void
+show_thread_default_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"show thread default\" must be followed by the name of a thread property.\n");
+}
+
+static int
+parse_int_arg (char *args, char *cmd_prefix)
+{
+ if (args)
+ {
+ char *arg_end;
+ int val = strtoul (args, &arg_end, 10);
+ if (*args && *arg_end == '\0')
+ return val;
+ }
+ error ("Illegal argument for \"%s\" command, should be an integer.", cmd_prefix);
+}
+
+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 (void)
+{
+ struct inf *inf = cur_inf ();
+ struct proc *thread = inf_tid_to_thread (inf, PIDGET (inferior_ptid));
+ if (!thread)
+ error ("No current thread.");
+ return thread;
+}
+
+/* Returns the current inferior, but signals an error if it has no task. */
+static struct inf *
+active_inf (void)
+{
+ struct inf *inf = cur_inf ();
+ if (!inf->task)
+ error ("No current process.");
+ return inf;
+}
+
+
+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_task_detach_sc_cmd (char *args, int from_tty)
+{
+ cur_inf ()->detach_sc = parse_int_arg (args, "set task detach-suspend-count");
+}
+
+static void
+show_task_detach_sc_cmd (char *args, int from_tty)
+{
+ check_empty (args, "show task detach-suspend-count");
+ printf_unfiltered ("The inferior task will be left with a suspend count of %d when detaching.\n",
+ cur_inf ()->detach_sc);
+}
+
+
+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");
+}
+
+static void
+set_thread_default_detach_sc_cmd (char *args, int from_tty)
+{
+ cur_inf ()->default_thread_detach_sc =
+ parse_int_arg (args, "set thread default detach-suspend-count");
+}
+
+static void
+show_thread_default_detach_sc_cmd (char *args, int from_tty)
+{
+ check_empty (args, "show thread default detach-suspend-count");
+ printf_unfiltered ("New threads will get a detach-suspend-count of %d.\n",
+ cur_inf ()->default_thread_detach_sc);
+}
+
+
+/* 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, safe_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), safe_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_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 = active_inf ();
+ check_empty (args, "show stopped");
+ printf_unfiltered ("The inferior process %s stopped.\n",
+ inf->stopped ? "is" : "isn't");
+}
+
+static void
+set_sig_thread_cmd (char *args, int from_tty)
+{
+ 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 = PIDGET (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 = active_inf ();
+ check_empty (args, "show signal-thread");
+ 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_signals_cmd (char *args, int from_tty)
+{
+ 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_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);
+ }
+
+ if (inf->detach_sc != 0)
+ show_task_detach_sc_cmd (0, from_tty);
+ if (inf->default_thread_detach_sc != 0)
+ show_thread_default_detach_sc_cmd (0, from_tty);
+}
+
+
+static void
+set_noninvasive_cmd (char *args, int from_tty)
+{
+ /* Invert the sense of the arg for each component. */
+ char *inv_args = parse_bool_arg (args, "set noninvasive") ? "off" : "on";
+
+ set_task_pause_cmd (inv_args, from_tty);
+ set_signals_cmd (inv_args, from_tty);
+ set_exceptions_cmd (inv_args, from_tty);
+}
+
+
+static void
+info_port_rights (char *args, mach_port_type_t only)
+{
+ struct inf *inf = active_inf ();
+ struct value *vmark = value_mark ();
+
+ if (args)
+ /* Explicit list of port rights. */
+ {
+ while (*args)
+ {
+ struct value *val = parse_to_comma_and_eval (&args);
+ long right = value_as_long (val);
+ error_t err =
+ print_port_info (right, 0, inf->task->port, PORTINFO_DETAILS,
+ stdout);
+ if (err)
+ error ("%ld: %s.", right, safe_strerror (err));
+ }
+ }
+ else
+ /* Print all of them. */
+ {
+ error_t err =
+ print_task_ports_info (inf->task->port, only, PORTINFO_DETAILS,
+ stdout);
+ if (err)
+ error ("%s.", safe_strerror (err));
+ }
+
+ value_free_to_mark (vmark);
+}
+
+static void
+info_send_rights_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_SEND);
+}
+
+static void
+info_recv_rights_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_RECEIVE);
+}
+
+static void
+info_port_sets_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_PORT_SET);
+}
+
+static void
+info_dead_names_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_DEAD_NAME);
+}
+
+static void
+info_port_rights_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, ~0);
+}
+
+
+static void
+add_task_commands (void)
+{
+ 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 ("detach-suspend-count", class_run, set_thread_default_detach_sc_cmd,
+ "Set the default detach-suspend-count value for new threads.",
+ &set_thread_default_cmd_list);
+ add_cmd ("detach-suspend-count", no_class, show_thread_default_detach_sc_cmd,
+ "Show the default detach-suspend-count value for new threads.",
+ &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 happens\n\
+until the next time the program is continued.\n\
+When setting this to \"off\", \"set thread default pause on\" can be\n\
+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 ("detach-suspend-count", class_run, set_task_detach_sc_cmd,
+ "Set the suspend count will leave on the thread when detaching.",
+ &set_task_cmd_list);
+ add_cmd ("detach-suspend-count", no_class, show_task_detach_sc_cmd,
+ "Show the suspend count will leave on the thread when detaching.",
+ &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);
+
+ /* A convenient way of turning on all options require to noninvasively
+ debug running tasks. */
+ add_cmd ("noninvasive", no_class, set_noninvasive_cmd,
+ "Set task options so that we interfere as little as possible.\n\
+This is the same as setting `task pause', `exceptions', and\n\
+`signals' to the opposite value.",
+ &setlist);
+
+ /* Commands to show information about the task's ports. */
+ add_cmd ("send-rights", class_info, info_send_rights_cmd,
+ "Show information about the task's send rights",
+ &infolist);
+ add_cmd ("receive-rights", class_info, info_recv_rights_cmd,
+ "Show information about the task's receive rights",
+ &infolist);
+ add_cmd ("port-rights", class_info, info_port_rights_cmd,
+ "Show information about the task's port rights",
+ &infolist);
+ add_cmd ("port-sets", class_info, info_port_sets_cmd,
+ "Show information about the task's port sets",
+ &infolist);
+ add_cmd ("dead-names", class_info, info_dead_names_cmd,
+ "Show information about the task's dead names",
+ &infolist);
+ add_info_alias ("ports", "port-rights", 1);
+ add_info_alias ("port", "port-rights", 1);
+ add_info_alias ("psets", "port-sets", 1);
+}
+
+
+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 %s allowed to run.",
+ proc_string (thread),
+ thread->run_sc == 0 ? "is" : "isn't");
+}
+
+static void
+set_thread_detach_sc_cmd (char *args, int from_tty)
+{
+ cur_thread ()->detach_sc = parse_int_arg (args,
+ "set thread detach-suspend-count");
+}
+
+static void
+show_thread_detach_sc_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ check_empty (args, "show thread detach-suspend-count");
+ printf_unfiltered ("Thread %s will be left with a suspend count"
+ " of %d when detaching.\n",
+ proc_string (thread),
+ thread->detach_sc);
+}
+
+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));
+}
+
+#if 0
+static void
+show_thread_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ check_empty (args, "show thread");
+ show_thread_run_cmd (0, from_tty);
+ show_thread_pause_cmd (0, from_tty);
+ if (thread->detach_sc != 0)
+ show_thread_detach_sc_cmd (0, from_tty);
+}
+#endif
+
+static void
+thread_takeover_sc_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ thread_basic_info_data_t _info;
+ thread_basic_info_t info = &_info;
+ mach_msg_type_number_t info_len = THREAD_BASIC_INFO_COUNT;
+ error_t err =
+ thread_info (thread->port, THREAD_BASIC_INFO, (int *) &info, &info_len);
+ if (err)
+ error ("%s.", safe_strerror (err));
+ thread->sc = info->suspend_count;
+ if (from_tty)
+ printf_unfiltered ("Suspend count was %d.\n", thread->sc);
+ if (info != &_info)
+ vm_deallocate (mach_task_self (), (vm_address_t) info,
+ info_len * sizeof (int));
+}
+
+
+static void
+add_thread_commands (void)
+{
+ add_prefix_cmd ("thread", no_class, set_thread_cmd,
+ "Command prefix for setting thread properties.",
+ &set_thread_cmd_list, "set thread ", 0, &setlist);
+ add_prefix_cmd ("default", no_class, show_thread_cmd,
+ "Command prefix for setting default thread properties.",
+ &set_thread_default_cmd_list, "set thread default ", 0,
+ &set_thread_cmd_list);
+ add_prefix_cmd ("thread", no_class, set_thread_default_cmd,
+ "Command prefix for showing thread properties.",
+ &show_thread_cmd_list, "show thread ", 0, &showlist);
+ add_prefix_cmd ("default", no_class, show_thread_default_cmd,
+ "Command prefix for showing default thread properties.",
+ &show_thread_default_cmd_list, "show thread default ", 0,
+ &show_thread_cmd_list);
+
+ 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 happens\n\
+until the next time the program is continued. This property normally\n\
+has no effect because the whole task is suspended, however, that may\n\
+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 ("detach-suspend-count", class_run, set_thread_detach_sc_cmd,
+ "Set the suspend count will leave on the thread when detaching.\n\
+Note that this is relative to suspend count when gdb noticed the thread;\n\
+use the `thread takeover-suspend-count' to force it to an absolute value.",
+ &set_thread_cmd_list);
+ add_cmd ("detach-suspend-count", no_class, show_thread_detach_sc_cmd,
+ "Show the suspend count will leave on the thread when detaching.\n\
+Note that this is relative to suspend count when gdb noticed the thread;\n\
+use the `thread takeover-suspend-count' to force it to an absolute value.",
+ &show_thread_cmd_list);
+
+ add_cmd ("exception-port", no_class, set_thread_exc_port_cmd,
+ "Set the thread exception port to which we forward exceptions.\n\
+This overrides 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);
+
+ add_cmd ("takeover-suspend-count", no_class, thread_takeover_sc_cmd,
+ "Force the threads absolute suspend-count to be gdb's.\n\
+Prior to giving this command, gdb's thread suspend-counts are relative\n\
+to the thread's initial suspend-count when gdb notices the threads.",
+ &thread_cmd_list);
+}
+
+
+void
+_initialize_gnu_nat (void)
+{
+ proc_server = getproc ();
+
+ init_gnu_ops ();
+ add_target (&gnu_ops);
+
+ add_task_commands ();
+ add_thread_commands ();
+ add_set_cmd ("gnu-debug", class_maintenance,
+ var_boolean, (char *) &gnu_debug_flag,
+ "Set debugging output for the gnu backend.", &maintenancelist);
+}
+
+#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 (CORE_ADDR pc, int amount)
+{
+ 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", safe_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 0000000..bcdfe6e
--- /dev/null
+++ b/contrib/gdb/gdb/gnu-nat.h
@@ -0,0 +1,101 @@
+/* Common things used by the various *gnu-nat.c files
+ Copyright 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef __GNU_NAT_H__
+#define __GNU_NAT_H__
+
+#include <unistd.h>
+#include <mach.h>
+
+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);
+
+/* Makes sure that INF's thread list is synced with the actual process. */
+int inf_update_procs (struct inf *inf);
+
+/* 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 from the last resume. */
+ int detach_sc; /* SC to leave around when detaching
+ from program. */
+
+ 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. */
+ int dead:1; /* We happen to know it's actually dead. */
+
+ /* 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);
+
+/* 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. */
+extern thread_state_t proc_get_state (struct proc *proc, int will_modify);
+
+/* Return printable description of proc. */
+extern char *proc_string (struct proc *proc);
+
+#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)
+
+extern int gnu_debug_flag;
+
+#define debug(msg, args...) \
+ do { if (gnu_debug_flag) \
+ fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", __FILE__ , __LINE__ , ##args); } while (0)
+
+#endif /* __GNU_NAT_H__ */
diff --git a/contrib/gdb/gdb/gnu-v2-abi.c b/contrib/gdb/gdb/gnu-v2-abi.c
new file mode 100644
index 0000000..8cb2a7e
--- /dev/null
+++ b/contrib/gdb/gdb/gnu-v2-abi.c
@@ -0,0 +1,413 @@
+/* Abstraction of GNU v2 abi.
+
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Daniel Berlin <dberlin@redhat.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 "value.h"
+#include "demangle.h"
+#include "cp-abi.h"
+#include "cp-support.h"
+
+#include <ctype.h>
+
+struct cp_abi_ops gnu_v2_abi_ops;
+
+static int vb_match (struct type *, int, struct type *);
+int gnuv2_baseclass_offset (struct type *type, int index, char *valaddr,
+ CORE_ADDR address);
+
+static enum dtor_kinds
+gnuv2_is_destructor_name (const char *name)
+{
+ if ((name[0] == '_' && is_cplus_marker (name[1]) && name[2] == '_')
+ || strncmp (name, "__dt__", 6) == 0)
+ return complete_object_dtor;
+ else
+ return 0;
+}
+
+static enum ctor_kinds
+gnuv2_is_constructor_name (const char *name)
+{
+ if ((name[0] == '_' && name[1] == '_'
+ && (isdigit (name[2]) || strchr ("Qt", name[2])))
+ || strncmp (name, "__ct__", 6) == 0)
+ return complete_object_ctor;
+ else
+ return 0;
+}
+
+static int
+gnuv2_is_vtable_name (const char *name)
+{
+ return (((name)[0] == '_'
+ && (((name)[1] == 'V' && (name)[2] == 'T')
+ || ((name)[1] == 'v' && (name)[2] == 't'))
+ && is_cplus_marker ((name)[3])) ||
+ ((name)[0] == '_' && (name)[1] == '_'
+ && (name)[2] == 'v' && (name)[3] == 't' && (name)[4] == '_'));
+}
+
+static int
+gnuv2_is_operator_name (const char *name)
+{
+ return strncmp (name, "operator", 8) == 0;
+}
+
+
+/* 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. */
+static struct value *
+gnuv2_virtual_fn_field (struct value **arg1p, struct fn_field * f, int j,
+ struct type * type, int offset)
+{
+ struct value *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. */
+ struct value *entry;
+ struct value *vfn;
+ struct value *vtbl;
+ struct value *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)
+ {
+ struct value *tmp = value_cast (context, value_addr (arg1));
+ arg1 = value_ind (tmp);
+ 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_primitive_field (arg1, 0, TYPE_VPTR_FIELDNO (context),
+ TYPE_VPTR_BASETYPE (context));
+
+ /* With older versions of g++, the vtbl field pointed to an array
+ of structures. Nowadays it points directly to the structure. */
+ if (TYPE_CODE (VALUE_TYPE (vtbl)) == TYPE_CODE_PTR
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (vtbl))) == TYPE_CODE_ARRAY)
+ {
+ /* Handle the case where the vtbl field points to an
+ array of structures. */
+ vtbl = value_ind (vtbl);
+
+ /* 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);
+ }
+ else
+ {
+ /* Handle the case where the vtbl field points directly to a structure. */
+ vtbl = value_add (vtbl, vi);
+ entry = value_ind (vtbl);
+ }
+
+ 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;
+}
+
+
+static struct type *
+gnuv2_value_rtti_type (struct value *v, int *full, int *top, int *using_enc)
+{
+ struct type *known_type;
+ struct type *rtti_type;
+ CORE_ADDR coreptr;
+ struct value *vp;
+ long top_offset = 0;
+ char rtti_type_name[256];
+ CORE_ADDR vtbl;
+ struct minimal_symbol *minsym;
+ struct symbol *sym;
+ char *demangled_name;
+ struct type *btype;
+
+ if (full)
+ *full = 0;
+ if (top)
+ *top = -1;
+ if (using_enc)
+ *using_enc = 0;
+
+ /* Get declared type */
+ known_type = VALUE_TYPE (v);
+ CHECK_TYPEDEF (known_type);
+ /* RTTI works only or class objects */
+ if (TYPE_CODE (known_type) != TYPE_CODE_CLASS)
+ return NULL;
+
+ /* Plan on this changing in the future as i get around to setting
+ the vtables properly for G++ compiled stuff. Also, I'll be using
+ the type info functions, which are always right. Deal with it
+ until then. */
+
+ /* If the type has no vptr fieldno, try to get it filled in */
+ if (TYPE_VPTR_FIELDNO(known_type) < 0)
+ fill_in_vptr_fieldno(known_type);
+
+ /* If we still can't find one, give up */
+ if (TYPE_VPTR_FIELDNO(known_type) < 0)
+ return NULL;
+
+ /* Make sure our basetype and known type match, otherwise, cast
+ so we can get at the vtable properly.
+ */
+ btype = TYPE_VPTR_BASETYPE (known_type);
+ CHECK_TYPEDEF (btype);
+ if (btype != known_type )
+ {
+ v = value_cast (btype, v);
+ if (using_enc)
+ *using_enc=1;
+ }
+ /*
+ We can't use value_ind here, because it would want to use RTTI, and
+ we'd waste a bunch of time figuring out we already know the type.
+ Besides, we don't care about the type, just the actual pointer
+ */
+ if (VALUE_ADDRESS (value_field (v, TYPE_VPTR_FIELDNO (known_type))) == 0)
+ return NULL;
+
+ vtbl=value_as_address(value_field(v,TYPE_VPTR_FIELDNO(known_type)));
+
+ /* Try to find a symbol that is the vtable */
+ minsym=lookup_minimal_symbol_by_pc(vtbl);
+ if (minsym==NULL
+ || (demangled_name=DEPRECATED_SYMBOL_NAME (minsym))==NULL
+ || !is_vtable_name (demangled_name))
+ return NULL;
+
+ /* If we just skip the prefix, we get screwed by namespaces */
+ demangled_name=cplus_demangle(demangled_name,DMGL_PARAMS|DMGL_ANSI);
+ *(strchr(demangled_name,' '))=0;
+
+ /* Lookup the type for the name */
+ /* FIXME: chastain/2003-11-26: block=NULL is bogus. See pr gdb/1465. */
+ rtti_type = cp_lookup_rtti_type (demangled_name, NULL);
+ if (rtti_type == NULL)
+ return NULL;
+
+ if (TYPE_N_BASECLASSES(rtti_type) > 1 && full && (*full) != 1)
+ {
+ if (top)
+ *top=TYPE_BASECLASS_BITPOS(rtti_type,TYPE_VPTR_FIELDNO(rtti_type))/8;
+ if (top && ((*top) >0))
+ {
+ if (TYPE_LENGTH(rtti_type) > TYPE_LENGTH(known_type))
+ {
+ if (full)
+ *full=0;
+ }
+ else
+ {
+ if (full)
+ *full=1;
+ }
+ }
+ }
+ else
+ {
+ if (full)
+ *full=1;
+ }
+
+ return rtti_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 (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
+ && strcmp (TYPE_NAME (basetype),
+ TYPE_NAME (TYPE_TARGET_TYPE (fieldtype))) == 0)
+ 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
+gnuv2_baseclass_offset (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. */
+ int i, len = TYPE_NFIELDS (type);
+ 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;
+}
+
+static void
+init_gnuv2_ops (void)
+{
+ gnu_v2_abi_ops.shortname = "gnu-v2";
+ gnu_v2_abi_ops.longname = "GNU G++ Version 2 ABI";
+ gnu_v2_abi_ops.doc = "G++ Version 2 ABI";
+ gnu_v2_abi_ops.is_destructor_name = gnuv2_is_destructor_name;
+ gnu_v2_abi_ops.is_constructor_name = gnuv2_is_constructor_name;
+ gnu_v2_abi_ops.is_vtable_name = gnuv2_is_vtable_name;
+ gnu_v2_abi_ops.is_operator_name = gnuv2_is_operator_name;
+ gnu_v2_abi_ops.virtual_fn_field = gnuv2_virtual_fn_field;
+ gnu_v2_abi_ops.rtti_type = gnuv2_value_rtti_type;
+ gnu_v2_abi_ops.baseclass_offset = gnuv2_baseclass_offset;
+}
+
+extern initialize_file_ftype _initialize_gnu_v2_abi; /* -Wmissing-prototypes */
+
+void
+_initialize_gnu_v2_abi (void)
+{
+ init_gnuv2_ops ();
+ register_cp_abi (&gnu_v2_abi_ops);
+ set_cp_abi_as_auto_default (gnu_v2_abi_ops.shortname);
+}
diff --git a/contrib/gdb/gdb/gnu-v3-abi.c b/contrib/gdb/gdb/gnu-v3-abi.c
new file mode 100644
index 0000000..0fbdd6e
--- /dev/null
+++ b/contrib/gdb/gdb/gnu-v3-abi.c
@@ -0,0 +1,447 @@
+/* Abstraction of GNU v3 abi.
+ Contributed by Jim Blandy <jimb@redhat.com>
+
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "cp-abi.h"
+#include "cp-support.h"
+#include "demangle.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+static struct cp_abi_ops gnu_v3_abi_ops;
+
+static int
+gnuv3_is_vtable_name (const char *name)
+{
+ return strncmp (name, "_ZTV", 4) == 0;
+}
+
+static int
+gnuv3_is_operator_name (const char *name)
+{
+ return strncmp (name, "operator", 8) == 0;
+}
+
+
+/* To help us find the components of a vtable, we build ourselves a
+ GDB type object representing the vtable structure. Following the
+ V3 ABI, it goes something like this:
+
+ struct gdb_gnu_v3_abi_vtable {
+
+ / * An array of virtual call and virtual base offsets. The real
+ length of this array depends on the class hierarchy; we use
+ negative subscripts to access the elements. Yucky, but
+ better than the alternatives. * /
+ ptrdiff_t vcall_and_vbase_offsets[0];
+
+ / * The offset from a virtual pointer referring to this table
+ to the top of the complete object. * /
+ ptrdiff_t offset_to_top;
+
+ / * The type_info pointer for this class. This is really a
+ std::type_info *, but GDB doesn't really look at the
+ type_info object itself, so we don't bother to get the type
+ exactly right. * /
+ void *type_info;
+
+ / * Virtual table pointers in objects point here. * /
+
+ / * Virtual function pointers. Like the vcall/vbase array, the
+ real length of this table depends on the class hierarchy. * /
+ void (*virtual_functions[0]) ();
+
+ };
+
+ The catch, of course, is that the exact layout of this table
+ depends on the ABI --- word size, endianness, alignment, etc. So
+ the GDB type object is actually a per-architecture kind of thing.
+
+ vtable_type_gdbarch_data is a gdbarch per-architecture data pointer
+ which refers to the struct type * for this structure, laid out
+ appropriately for the architecture. */
+static struct gdbarch_data *vtable_type_gdbarch_data;
+
+
+/* Human-readable names for the numbers of the fields above. */
+enum {
+ vtable_field_vcall_and_vbase_offsets,
+ vtable_field_offset_to_top,
+ vtable_field_type_info,
+ vtable_field_virtual_functions
+};
+
+
+/* Return a GDB type representing `struct gdb_gnu_v3_abi_vtable',
+ described above, laid out appropriately for ARCH.
+
+ We use this function as the gdbarch per-architecture data
+ initialization function. We assume that the gdbarch framework
+ calls the per-architecture data initialization functions after it
+ sets current_gdbarch to the new architecture. */
+static void *
+build_gdb_vtable_type (struct gdbarch *arch)
+{
+ struct type *t;
+ struct field *field_list, *field;
+ int offset;
+
+ struct type *void_ptr_type
+ = lookup_pointer_type (builtin_type_void);
+ struct type *ptr_to_void_fn_type
+ = lookup_pointer_type (lookup_function_type (builtin_type_void));
+
+ /* ARCH can't give us the true ptrdiff_t type, so we guess. */
+ struct type *ptrdiff_type
+ = init_type (TYPE_CODE_INT, TARGET_PTR_BIT / TARGET_CHAR_BIT, 0,
+ "ptrdiff_t", 0);
+
+ /* We assume no padding is necessary, since GDB doesn't know
+ anything about alignment at the moment. If this assumption bites
+ us, we should add a gdbarch method which, given a type, returns
+ the alignment that type requires, and then use that here. */
+
+ /* Build the field list. */
+ field_list = xmalloc (sizeof (struct field [4]));
+ memset (field_list, 0, sizeof (struct field [4]));
+ field = &field_list[0];
+ offset = 0;
+
+ /* ptrdiff_t vcall_and_vbase_offsets[0]; */
+ FIELD_NAME (*field) = "vcall_and_vbase_offsets";
+ FIELD_TYPE (*field)
+ = create_array_type (0, ptrdiff_type,
+ create_range_type (0, builtin_type_int, 0, -1));
+ FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+ offset += TYPE_LENGTH (FIELD_TYPE (*field));
+ field++;
+
+ /* ptrdiff_t offset_to_top; */
+ FIELD_NAME (*field) = "offset_to_top";
+ FIELD_TYPE (*field) = ptrdiff_type;
+ FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+ offset += TYPE_LENGTH (FIELD_TYPE (*field));
+ field++;
+
+ /* void *type_info; */
+ FIELD_NAME (*field) = "type_info";
+ FIELD_TYPE (*field) = void_ptr_type;
+ FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+ offset += TYPE_LENGTH (FIELD_TYPE (*field));
+ field++;
+
+ /* void (*virtual_functions[0]) (); */
+ FIELD_NAME (*field) = "virtual_functions";
+ FIELD_TYPE (*field)
+ = create_array_type (0, ptr_to_void_fn_type,
+ create_range_type (0, builtin_type_int, 0, -1));
+ FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+ offset += TYPE_LENGTH (FIELD_TYPE (*field));
+ field++;
+
+ /* We assumed in the allocation above that there were four fields. */
+ gdb_assert (field == (field_list + 4));
+
+ t = init_type (TYPE_CODE_STRUCT, offset, 0, 0, 0);
+ TYPE_NFIELDS (t) = field - field_list;
+ TYPE_FIELDS (t) = field_list;
+ TYPE_TAG_NAME (t) = "gdb_gnu_v3_abi_vtable";
+
+ return t;
+}
+
+
+/* Return the offset from the start of the imaginary `struct
+ gdb_gnu_v3_abi_vtable' object to the vtable's "address point"
+ (i.e., where objects' virtual table pointers point). */
+static int
+vtable_address_point_offset (void)
+{
+ struct type *vtable_type = gdbarch_data (current_gdbarch,
+ vtable_type_gdbarch_data);
+
+ return (TYPE_FIELD_BITPOS (vtable_type, vtable_field_virtual_functions)
+ / TARGET_CHAR_BIT);
+}
+
+
+static struct type *
+gnuv3_rtti_type (struct value *value,
+ int *full_p, int *top_p, int *using_enc_p)
+{
+ struct type *vtable_type = gdbarch_data (current_gdbarch,
+ vtable_type_gdbarch_data);
+ struct type *value_type = check_typedef (VALUE_TYPE (value));
+ CORE_ADDR vtable_address;
+ struct value *vtable;
+ struct minimal_symbol *vtable_symbol;
+ const char *vtable_symbol_name;
+ const char *class_name;
+ struct type *run_time_type;
+ struct type *base_type;
+ LONGEST offset_to_top;
+
+ /* We only have RTTI for class objects. */
+ if (TYPE_CODE (value_type) != TYPE_CODE_CLASS)
+ return NULL;
+
+ /* If we can't find the virtual table pointer for value_type, we
+ can't find the RTTI. */
+ fill_in_vptr_fieldno (value_type);
+ if (TYPE_VPTR_FIELDNO (value_type) == -1)
+ return NULL;
+
+ if (using_enc_p)
+ *using_enc_p = 0;
+
+ /* Fetch VALUE's virtual table pointer, and tweak it to point at
+ an instance of our imaginary gdb_gnu_v3_abi_vtable structure. */
+ base_type = check_typedef (TYPE_VPTR_BASETYPE (value_type));
+ if (value_type != base_type)
+ {
+ value = value_cast (base_type, value);
+ if (using_enc_p)
+ *using_enc_p = 1;
+ }
+ vtable_address
+ = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (value_type)));
+ vtable = value_at_lazy (vtable_type,
+ vtable_address - vtable_address_point_offset (),
+ VALUE_BFD_SECTION (value));
+
+ /* Find the linker symbol for this vtable. */
+ vtable_symbol
+ = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtable)
+ + VALUE_OFFSET (vtable)
+ + VALUE_EMBEDDED_OFFSET (vtable));
+ if (! vtable_symbol)
+ return NULL;
+
+ /* The symbol's demangled name should be something like "vtable for
+ CLASS", where CLASS is the name of the run-time type of VALUE.
+ If we didn't like this approach, we could instead look in the
+ type_info object itself to get the class name. But this way
+ should work just as well, and doesn't read target memory. */
+ vtable_symbol_name = SYMBOL_DEMANGLED_NAME (vtable_symbol);
+ if (vtable_symbol_name == NULL
+ || strncmp (vtable_symbol_name, "vtable for ", 11))
+ {
+ warning ("can't find linker symbol for virtual table for `%s' value",
+ TYPE_NAME (value_type));
+ if (vtable_symbol_name)
+ warning (" found `%s' instead", vtable_symbol_name);
+ return NULL;
+ }
+ class_name = vtable_symbol_name + 11;
+
+ /* Try to look up the class name as a type name. */
+ /* FIXME: chastain/2003-11-26: block=NULL is bogus. See pr gdb/1465. */
+ run_time_type = cp_lookup_rtti_type (class_name, NULL);
+ if (run_time_type == NULL)
+ return NULL;
+
+ /* Get the offset from VALUE to the top of the complete object.
+ NOTE: this is the reverse of the meaning of *TOP_P. */
+ offset_to_top
+ = value_as_long (value_field (vtable, vtable_field_offset_to_top));
+
+ if (full_p)
+ *full_p = (- offset_to_top == VALUE_EMBEDDED_OFFSET (value)
+ && (TYPE_LENGTH (VALUE_ENCLOSING_TYPE (value))
+ >= TYPE_LENGTH (run_time_type)));
+ if (top_p)
+ *top_p = - offset_to_top;
+
+ return run_time_type;
+}
+
+
+static struct value *
+gnuv3_virtual_fn_field (struct value **value_p,
+ struct fn_field *f, int j,
+ struct type *type, int offset)
+{
+ struct type *vtable_type = gdbarch_data (current_gdbarch,
+ vtable_type_gdbarch_data);
+ struct value *value = *value_p;
+ struct type *value_type = check_typedef (VALUE_TYPE (value));
+ struct type *vfn_base;
+ CORE_ADDR vtable_address;
+ struct value *vtable;
+ struct value *vfn;
+
+ /* Some simple sanity checks. */
+ if (TYPE_CODE (value_type) != TYPE_CODE_CLASS)
+ error ("Only classes can have virtual functions.");
+
+ /* Find the base class that defines this virtual function. */
+ vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j);
+ if (! vfn_base)
+ /* In programs compiled with G++ version 1, the debug info doesn't
+ say which base class defined the virtual function. We'll guess
+ it's the same base class that has our vtable; this is wrong for
+ multiple inheritance, but it's better than nothing. */
+ vfn_base = TYPE_VPTR_BASETYPE (type);
+
+ /* 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 (vfn_base) < 0)
+ fill_in_vptr_fieldno (vfn_base);
+ if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
+ error ("Could not find virtual table pointer for class \"%s\".",
+ TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : "<unknown>");
+
+ /* Now that we know which base class is defining our virtual
+ function, cast our value to that baseclass. This takes care of
+ any necessary `this' adjustments. */
+ if (vfn_base != value_type)
+ value = value_cast (vfn_base, value);
+
+ /* Now value is an object of the appropriate base type. Fetch its
+ virtual table. */
+ /* It might be possible to do this cast at the same time as the above.
+ Does multiple inheritance affect this?
+ Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent?
+ */
+ if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
+ value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
+ vtable_address
+ = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
+
+ vtable = value_at_lazy (vtable_type,
+ vtable_address - vtable_address_point_offset (),
+ VALUE_BFD_SECTION (value));
+
+ /* Fetch the appropriate function pointer from the vtable. */
+ vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
+ value_from_longest (builtin_type_int,
+ TYPE_FN_FIELD_VOFFSET (f, j)));
+
+ /* Cast the function pointer to the appropriate type. */
+ vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)),
+ vfn);
+
+ /* Is (type)value always numerically the same as (vfn_base)value?
+ If so we can spare this cast and use one of the ones above. */
+ *value_p = value_addr (value_cast (type, *value_p));
+
+ return vfn;
+}
+
+/* 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. */
+static int
+gnuv3_baseclass_offset (struct type *type, int index, char *valaddr,
+ CORE_ADDR address)
+{
+ struct type *vtable_type = gdbarch_data (current_gdbarch,
+ vtable_type_gdbarch_data);
+ struct value *vtable;
+ struct type *vbasetype;
+ struct value *offset_val, *vbase_array;
+ CORE_ADDR vtable_address;
+ long int cur_base_offset, base_offset;
+
+ /* If it isn't a virtual base, this is easy. The offset is in the
+ type definition. */
+ if (!BASETYPE_VIA_VIRTUAL (type, index))
+ return TYPE_BASECLASS_BITPOS (type, index) / 8;
+
+ /* To access a virtual base, we need to use the vbase offset stored in
+ our vtable. Recent GCC versions provide this information. If it isn't
+ available, we could get what we needed from RTTI, or from drawing the
+ complete inheritance graph based on the debug info. Neither is
+ worthwhile. */
+ cur_base_offset = TYPE_BASECLASS_BITPOS (type, index) / 8;
+ if (cur_base_offset >= - vtable_address_point_offset ())
+ error ("Expected a negative vbase offset (old compiler?)");
+
+ cur_base_offset = cur_base_offset + vtable_address_point_offset ();
+ if ((- cur_base_offset) % TYPE_LENGTH (builtin_type_void_data_ptr) != 0)
+ error ("Misaligned vbase offset.");
+ cur_base_offset = cur_base_offset
+ / ((int) TYPE_LENGTH (builtin_type_void_data_ptr));
+
+ /* We're now looking for the cur_base_offset'th entry (negative index)
+ in the vcall_and_vbase_offsets array. We used to cast the object to
+ its TYPE_VPTR_BASETYPE, and reference the vtable as TYPE_VPTR_FIELDNO;
+ however, that cast can not be done without calling baseclass_offset again
+ if the TYPE_VPTR_BASETYPE is a virtual base class, as described in the
+ v3 C++ ABI Section 2.4.I.2.b. Fortunately the ABI guarantees that the
+ vtable pointer will be located at the beginning of the object, so we can
+ bypass the casting. Verify that the TYPE_VPTR_FIELDNO is in fact at the
+ start of whichever baseclass it resides in, as a sanity measure - iff
+ we have debugging information for that baseclass. */
+
+ vbasetype = TYPE_VPTR_BASETYPE (type);
+ if (TYPE_VPTR_FIELDNO (vbasetype) < 0)
+ fill_in_vptr_fieldno (vbasetype);
+
+ if (TYPE_VPTR_FIELDNO (vbasetype) >= 0
+ && TYPE_FIELD_BITPOS (vbasetype, TYPE_VPTR_FIELDNO (vbasetype)) != 0)
+ error ("Illegal vptr offset in class %s",
+ TYPE_NAME (vbasetype) ? TYPE_NAME (vbasetype) : "<unknown>");
+
+ vtable_address = value_as_address (value_at_lazy (builtin_type_void_data_ptr,
+ address, NULL));
+ vtable = value_at_lazy (vtable_type,
+ vtable_address - vtable_address_point_offset (),
+ NULL);
+ offset_val = value_from_longest(builtin_type_int, cur_base_offset);
+ vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets);
+ base_offset = value_as_long (value_subscript (vbase_array, offset_val));
+ return base_offset;
+}
+
+static void
+init_gnuv3_ops (void)
+{
+ vtable_type_gdbarch_data = register_gdbarch_data (build_gdb_vtable_type);
+
+ gnu_v3_abi_ops.shortname = "gnu-v3";
+ gnu_v3_abi_ops.longname = "GNU G++ Version 3 ABI";
+ gnu_v3_abi_ops.doc = "G++ Version 3 ABI";
+ gnu_v3_abi_ops.is_destructor_name = is_gnu_v3_mangled_dtor;
+ gnu_v3_abi_ops.is_constructor_name = is_gnu_v3_mangled_ctor;
+ gnu_v3_abi_ops.is_vtable_name = gnuv3_is_vtable_name;
+ gnu_v3_abi_ops.is_operator_name = gnuv3_is_operator_name;
+ gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type;
+ gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field;
+ gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset;
+}
+
+extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */
+
+void
+_initialize_gnu_v3_abi (void)
+{
+ init_gnuv3_ops ();
+
+ register_cp_abi (&gnu_v3_abi_ops);
+}
diff --git a/contrib/gdb/gdb/go32-nat.c b/contrib/gdb/gdb/go32-nat.c
new file mode 100644
index 0000000..0932ddb
--- /dev/null
+++ b/contrib/gdb/gdb/go32-nat.c
@@ -0,0 +1,1963 @@
+/* Native debugging support for Intel x86 running DJGPP.
+ Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Written by Robert Hoehne.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <fcntl.h>
+
+#include "defs.h"
+#include "inferior.h"
+#include "gdb_wait.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "floatformat.h"
+#include "buildsym.h"
+#include "i387-tdep.h"
+#include "i386-tdep.h"
+#include "value.h"
+#include "regcache.h"
+#include "gdb_string.h"
+
+#include <stdio.h> /* might be required for __DJGPP_MINOR__ */
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <io.h>
+#include <dos.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <sys/farptr.h>
+#include <debug/v2load.h>
+#include <debug/dbgcom.h>
+#if __DJGPP_MINOR__ > 2
+#include <debug/redir.h>
+#endif
+
+#if __DJGPP_MINOR__ < 3
+/* This code will be provided from DJGPP 2.03 on. Until then I code it
+ here */
+typedef struct
+ {
+ unsigned short sig0;
+ unsigned short sig1;
+ unsigned short sig2;
+ unsigned short sig3;
+ unsigned short exponent:15;
+ unsigned short sign:1;
+ }
+NPXREG;
+
+typedef struct
+ {
+ unsigned int control;
+ unsigned int status;
+ unsigned int tag;
+ unsigned int eip;
+ unsigned int cs;
+ unsigned int dataptr;
+ unsigned int datasel;
+ NPXREG reg[8];
+ }
+NPX;
+
+static NPX npx;
+
+static void save_npx (void); /* Save the FPU of the debugged program */
+static void load_npx (void); /* Restore the FPU of the debugged program */
+
+/* ------------------------------------------------------------------------- */
+/* Store the contents of the NPX in the global variable `npx'. */
+/* *INDENT-OFF* */
+
+static void
+save_npx (void)
+{
+ asm ("inb $0xa0, %%al \n\
+ testb $0x20, %%al \n\
+ jz 1f \n\
+ xorb %%al, %%al \n\
+ outb %%al, $0xf0 \n\
+ movb $0x20, %%al \n\
+ outb %%al, $0xa0 \n\
+ outb %%al, $0x20 \n\
+1: \n\
+ fnsave %0 \n\
+ fwait "
+: "=m" (npx)
+: /* No input */
+: "%eax");
+}
+
+/* *INDENT-ON* */
+
+
+/* ------------------------------------------------------------------------- */
+/* Reload the contents of the NPX from the global variable `npx'. */
+
+static void
+load_npx (void)
+{
+ asm ("frstor %0":"=m" (npx));
+}
+/* ------------------------------------------------------------------------- */
+/* Stubs for the missing redirection functions. */
+typedef struct {
+ char *command;
+ int redirected;
+} cmdline_t;
+
+void
+redir_cmdline_delete (cmdline_t *ptr)
+{
+ ptr->redirected = 0;
+}
+
+int
+redir_cmdline_parse (const char *args, cmdline_t *ptr)
+{
+ return -1;
+}
+
+int
+redir_to_child (cmdline_t *ptr)
+{
+ return 1;
+}
+
+int
+redir_to_debugger (cmdline_t *ptr)
+{
+ return 1;
+}
+
+int
+redir_debug_init (cmdline_t *ptr)
+{
+ return 0;
+}
+#endif /* __DJGPP_MINOR < 3 */
+
+typedef enum { wp_insert, wp_remove, wp_count } wp_op;
+
+/* This holds the current reference counts for each debug register. */
+static int dr_ref_count[4];
+
+#define SOME_PID 42
+
+static int prog_has_started = 0;
+static void go32_open (char *name, int from_tty);
+static void go32_close (int quitting);
+static void go32_attach (char *args, int from_tty);
+static void go32_detach (char *args, int from_tty);
+static void go32_resume (ptid_t ptid, int step,
+ enum target_signal siggnal);
+static ptid_t go32_wait (ptid_t ptid,
+ struct target_waitstatus *status);
+static void go32_fetch_registers (int regno);
+static void store_register (int regno);
+static void go32_store_registers (int regno);
+static void go32_prepare_to_store (void);
+static int go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+static void go32_files_info (struct target_ops *target);
+static void go32_stop (void);
+static void go32_kill_inferior (void);
+static void go32_create_inferior (char *exec_file, char *args, char **env);
+static void go32_mourn_inferior (void);
+static int go32_can_run (void);
+
+static struct target_ops go32_ops;
+static void go32_terminal_init (void);
+static void go32_terminal_inferior (void);
+static void go32_terminal_ours (void);
+
+#define r_ofs(x) (offsetof(TSS,x))
+
+static struct
+{
+ size_t tss_ofs;
+ size_t size;
+}
+regno_mapping[] =
+{
+ {r_ofs (tss_eax), 4}, /* normal registers, from a_tss */
+ {r_ofs (tss_ecx), 4},
+ {r_ofs (tss_edx), 4},
+ {r_ofs (tss_ebx), 4},
+ {r_ofs (tss_esp), 4},
+ {r_ofs (tss_ebp), 4},
+ {r_ofs (tss_esi), 4},
+ {r_ofs (tss_edi), 4},
+ {r_ofs (tss_eip), 4},
+ {r_ofs (tss_eflags), 4},
+ {r_ofs (tss_cs), 2},
+ {r_ofs (tss_ss), 2},
+ {r_ofs (tss_ds), 2},
+ {r_ofs (tss_es), 2},
+ {r_ofs (tss_fs), 2},
+ {r_ofs (tss_gs), 2},
+ {0, 10}, /* 8 FP registers, from npx.reg[] */
+ {1, 10},
+ {2, 10},
+ {3, 10},
+ {4, 10},
+ {5, 10},
+ {6, 10},
+ {7, 10},
+ /* The order of the next 7 registers must be consistent
+ with their numbering in config/i386/tm-i386.h, which see. */
+ {0, 2}, /* control word, from npx */
+ {4, 2}, /* status word, from npx */
+ {8, 2}, /* tag word, from npx */
+ {16, 2}, /* last FP exception CS from npx */
+ {12, 4}, /* last FP exception EIP from npx */
+ {24, 2}, /* last FP exception operand selector from npx */
+ {20, 4}, /* last FP exception operand offset from npx */
+ {18, 2} /* last FP opcode from npx */
+};
+
+static struct
+ {
+ int go32_sig;
+ enum target_signal gdb_sig;
+ }
+sig_map[] =
+{
+ {0, TARGET_SIGNAL_FPE},
+ {1, TARGET_SIGNAL_TRAP},
+ /* Exception 2 is triggered by the NMI. DJGPP handles it as SIGILL,
+ but I think SIGBUS is better, since the NMI is usually activated
+ as a result of a memory parity check failure. */
+ {2, TARGET_SIGNAL_BUS},
+ {3, TARGET_SIGNAL_TRAP},
+ {4, TARGET_SIGNAL_FPE},
+ {5, TARGET_SIGNAL_SEGV},
+ {6, TARGET_SIGNAL_ILL},
+ {7, TARGET_SIGNAL_EMT}, /* no-coprocessor exception */
+ {8, TARGET_SIGNAL_SEGV},
+ {9, TARGET_SIGNAL_SEGV},
+ {10, TARGET_SIGNAL_BUS},
+ {11, TARGET_SIGNAL_SEGV},
+ {12, TARGET_SIGNAL_SEGV},
+ {13, TARGET_SIGNAL_SEGV},
+ {14, TARGET_SIGNAL_SEGV},
+ {16, TARGET_SIGNAL_FPE},
+ {17, TARGET_SIGNAL_BUS},
+ {31, TARGET_SIGNAL_ILL},
+ {0x1b, TARGET_SIGNAL_INT},
+ {0x75, TARGET_SIGNAL_FPE},
+ {0x78, TARGET_SIGNAL_ALRM},
+ {0x79, TARGET_SIGNAL_INT},
+ {0x7a, TARGET_SIGNAL_QUIT},
+ {-1, TARGET_SIGNAL_LAST}
+};
+
+static struct {
+ enum target_signal gdb_sig;
+ int djgpp_excepno;
+} excepn_map[] = {
+ {TARGET_SIGNAL_0, -1},
+ {TARGET_SIGNAL_ILL, 6}, /* Invalid Opcode */
+ {TARGET_SIGNAL_EMT, 7}, /* triggers SIGNOFP */
+ {TARGET_SIGNAL_SEGV, 13}, /* GPF */
+ {TARGET_SIGNAL_BUS, 17}, /* Alignment Check */
+ /* The rest are fake exceptions, see dpmiexcp.c in djlsr*.zip for
+ details. */
+ {TARGET_SIGNAL_TERM, 0x1b}, /* triggers Ctrl-Break type of SIGINT */
+ {TARGET_SIGNAL_FPE, 0x75},
+ {TARGET_SIGNAL_INT, 0x79},
+ {TARGET_SIGNAL_QUIT, 0x7a},
+ {TARGET_SIGNAL_ALRM, 0x78}, /* triggers SIGTIMR */
+ {TARGET_SIGNAL_PROF, 0x78},
+ {TARGET_SIGNAL_LAST, -1}
+};
+
+static void
+go32_open (char *name, int from_tty)
+{
+ printf_unfiltered ("Done. Use the \"run\" command to run the program.\n");
+}
+
+static void
+go32_close (int quitting)
+{
+}
+
+static void
+go32_attach (char *args, int from_tty)
+{
+ error ("\
+You cannot attach to a running program on this platform.\n\
+Use the `run' command to run DJGPP programs.");
+}
+
+static void
+go32_detach (char *args, int from_tty)
+{
+}
+
+static int resume_is_step;
+static int resume_signal = -1;
+
+static void
+go32_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ int i;
+
+ resume_is_step = step;
+
+ if (siggnal != TARGET_SIGNAL_0 && siggnal != TARGET_SIGNAL_TRAP)
+ {
+ for (i = 0, resume_signal = -1;
+ excepn_map[i].gdb_sig != TARGET_SIGNAL_LAST; i++)
+ if (excepn_map[i].gdb_sig == siggnal)
+ {
+ resume_signal = excepn_map[i].djgpp_excepno;
+ break;
+ }
+ if (resume_signal == -1)
+ printf_unfiltered ("Cannot deliver signal %s on this platform.\n",
+ target_signal_to_name (siggnal));
+ }
+}
+
+static char child_cwd[FILENAME_MAX];
+
+static ptid_t
+go32_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ int i;
+ unsigned char saved_opcode;
+ unsigned long INT3_addr = 0;
+ int stepping_over_INT = 0;
+
+ a_tss.tss_eflags &= 0xfeff; /* reset the single-step flag (TF) */
+ if (resume_is_step)
+ {
+ /* If the next instruction is INT xx or INTO, we need to handle
+ them specially. Intel manuals say that these instructions
+ reset the single-step flag (a.k.a. TF). However, it seems
+ that, at least in the DPMI environment, and at least when
+ stepping over the DPMI interrupt 31h, the problem is having
+ TF set at all when INT 31h is executed: the debuggee either
+ crashes (and takes the system with it) or is killed by a
+ SIGTRAP.
+
+ So we need to emulate single-step mode: we put an INT3 opcode
+ right after the INT xx instruction, let the debuggee run
+ until it hits INT3 and stops, then restore the original
+ instruction which we overwrote with the INT3 opcode, and back
+ up the debuggee's EIP to that instruction. */
+ read_child (a_tss.tss_eip, &saved_opcode, 1);
+ if (saved_opcode == 0xCD || saved_opcode == 0xCE)
+ {
+ unsigned char INT3_opcode = 0xCC;
+
+ INT3_addr
+ = saved_opcode == 0xCD ? a_tss.tss_eip + 2 : a_tss.tss_eip + 1;
+ stepping_over_INT = 1;
+ read_child (INT3_addr, &saved_opcode, 1);
+ write_child (INT3_addr, &INT3_opcode, 1);
+ }
+ else
+ a_tss.tss_eflags |= 0x0100; /* normal instruction: set TF */
+ }
+
+ /* The special value FFFFh in tss_trap indicates to run_child that
+ tss_irqn holds a signal to be delivered to the debuggee. */
+ if (resume_signal <= -1)
+ {
+ a_tss.tss_trap = 0;
+ a_tss.tss_irqn = 0xff;
+ }
+ else
+ {
+ a_tss.tss_trap = 0xffff; /* run_child looks for this */
+ a_tss.tss_irqn = resume_signal;
+ }
+
+ /* The child might change working directory behind our back. The
+ GDB users won't like the side effects of that when they work with
+ relative file names, and GDB might be confused by its current
+ directory not being in sync with the truth. So we always make a
+ point of changing back to where GDB thinks is its cwd, when we
+ return control to the debugger, but restore child's cwd before we
+ run it. */
+ /* Initialize child_cwd, before the first call to run_child and not
+ in the initialization, so the child get also the changed directory
+ set with the gdb-command "cd ..." */
+ if (!*child_cwd)
+ /* Initialize child's cwd with the current one. */
+ getcwd (child_cwd, sizeof (child_cwd));
+
+ chdir (child_cwd);
+
+#if __DJGPP_MINOR__ < 3
+ load_npx ();
+#endif
+ run_child ();
+#if __DJGPP_MINOR__ < 3
+ save_npx ();
+#endif
+
+ /* Did we step over an INT xx instruction? */
+ if (stepping_over_INT && a_tss.tss_eip == INT3_addr + 1)
+ {
+ /* Restore the original opcode. */
+ a_tss.tss_eip--; /* EIP points *after* the INT3 instruction */
+ write_child (a_tss.tss_eip, &saved_opcode, 1);
+ /* Simulate a TRAP exception. */
+ a_tss.tss_irqn = 1;
+ a_tss.tss_eflags |= 0x0100;
+ }
+
+ getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
+ chdir (current_directory);
+
+ if (a_tss.tss_irqn == 0x21)
+ {
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = a_tss.tss_eax & 0xff;
+ }
+ else
+ {
+ status->value.sig = TARGET_SIGNAL_UNKNOWN;
+ status->kind = TARGET_WAITKIND_STOPPED;
+ for (i = 0; sig_map[i].go32_sig != -1; i++)
+ {
+ if (a_tss.tss_irqn == sig_map[i].go32_sig)
+ {
+#if __DJGPP_MINOR__ < 3
+ if ((status->value.sig = sig_map[i].gdb_sig) !=
+ TARGET_SIGNAL_TRAP)
+ status->kind = TARGET_WAITKIND_SIGNALLED;
+#else
+ status->value.sig = sig_map[i].gdb_sig;
+#endif
+ break;
+ }
+ }
+ }
+ return pid_to_ptid (SOME_PID);
+}
+
+static void
+fetch_register (int regno)
+{
+ if (regno < FP0_REGNUM)
+ supply_register (regno, (char *) &a_tss + regno_mapping[regno].tss_ofs);
+ else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
+ i387_supply_fsave (current_regcache, regno, &npx);
+ else
+ internal_error (__FILE__, __LINE__,
+ "Invalid register no. %d in fetch_register.", regno);
+}
+
+static void
+go32_fetch_registers (int regno)
+{
+ if (regno >= 0)
+ fetch_register (regno);
+ else
+ {
+ for (regno = 0; regno < FP0_REGNUM; regno++)
+ fetch_register (regno);
+ i387_supply_fsave (current_regcache, -1, &npx);
+ }
+}
+
+static void
+store_register (int regno)
+{
+ if (regno < FP0_REGNUM)
+ regcache_collect (regno, (char *) &a_tss + regno_mapping[regno].tss_ofs);
+ else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
+ i387_fill_fsave ((char *) &npx, regno);
+ else
+ internal_error (__FILE__, __LINE__,
+ "Invalid register no. %d in store_register.", regno);
+}
+
+static void
+go32_store_registers (int regno)
+{
+ unsigned r;
+
+ if (regno >= 0)
+ store_register (regno);
+ else
+ {
+ for (r = 0; r < FP0_REGNUM; r++)
+ store_register (r);
+ i387_fill_fsave ((char *) &npx, -1);
+ }
+}
+
+static void
+go32_prepare_to_store (void)
+{
+}
+
+static int
+go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ if (write)
+ {
+ if (write_child (memaddr, myaddr, len))
+ {
+ return 0;
+ }
+ else
+ {
+ return len;
+ }
+ }
+ else
+ {
+ if (read_child (memaddr, myaddr, len))
+ {
+ return 0;
+ }
+ else
+ {
+ return len;
+ }
+ }
+}
+
+static cmdline_t child_cmd; /* parsed child's command line kept here */
+
+static void
+go32_files_info (struct target_ops *target)
+{
+ printf_unfiltered ("You are running a DJGPP V2 program.\n");
+}
+
+static void
+go32_stop (void)
+{
+ normal_stop ();
+ cleanup_client ();
+ inferior_ptid = null_ptid;
+ prog_has_started = 0;
+}
+
+static void
+go32_kill_inferior (void)
+{
+ redir_cmdline_delete (&child_cmd);
+ resume_signal = -1;
+ resume_is_step = 0;
+ unpush_target (&go32_ops);
+}
+
+static void
+go32_create_inferior (char *exec_file, char *args, char **env)
+{
+ extern char **environ;
+ jmp_buf start_state;
+ char *cmdline;
+ char **env_save = environ;
+ size_t cmdlen;
+
+ /* 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);
+
+ if (prog_has_started)
+ {
+ go32_stop ();
+ go32_kill_inferior ();
+ }
+ resume_signal = -1;
+ resume_is_step = 0;
+
+ /* Initialize child's cwd as empty to be initialized when starting
+ the child. */
+ *child_cwd = 0;
+
+ /* Init command line storage. */
+ if (redir_debug_init (&child_cmd) == -1)
+ internal_error (__FILE__, __LINE__,
+ "Cannot allocate redirection storage: not enough memory.\n");
+
+ /* Parse the command line and create redirections. */
+ if (strpbrk (args, "<>"))
+ {
+ if (redir_cmdline_parse (args, &child_cmd) == 0)
+ args = child_cmd.command;
+ else
+ error ("Syntax error in command line.");
+ }
+ else
+ child_cmd.command = xstrdup (args);
+
+ cmdlen = strlen (args);
+ /* v2loadimage passes command lines via DOS memory, so it cannot
+ possibly handle commands longer than 1MB. */
+ if (cmdlen > 1024*1024)
+ error ("Command line too long.");
+
+ cmdline = xmalloc (cmdlen + 4);
+ strcpy (cmdline + 1, args);
+ /* If the command-line length fits into DOS 126-char limits, use the
+ DOS command tail format; otherwise, tell v2loadimage to pass it
+ through a buffer in conventional memory. */
+ if (cmdlen < 127)
+ {
+ cmdline[0] = strlen (args);
+ cmdline[cmdlen + 1] = 13;
+ }
+ else
+ cmdline[0] = 0xff; /* signal v2loadimage it's a long command */
+
+ environ = env;
+
+ if (v2loadimage (exec_file, cmdline, start_state))
+ {
+ environ = env_save;
+ printf_unfiltered ("Load failed for image %s\n", exec_file);
+ exit (1);
+ }
+ environ = env_save;
+ xfree (cmdline);
+
+ edi_init (start_state);
+#if __DJGPP_MINOR__ < 3
+ save_npx ();
+#endif
+
+ inferior_ptid = pid_to_ptid (SOME_PID);
+ push_target (&go32_ops);
+ clear_proceed_status ();
+ insert_breakpoints ();
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+ prog_has_started = 1;
+}
+
+static void
+go32_mourn_inferior (void)
+{
+ /* We need to make sure all the breakpoint enable bits in the DR7
+ register are reset when the inferior exits. Otherwise, if they
+ rerun the inferior, the uncleared bits may cause random SIGTRAPs,
+ failure to set more watchpoints, and other calamities. It would
+ be nice if GDB itself would take care to remove all breakpoints
+ at all times, but it doesn't, probably under an assumption that
+ the OS cleans up when the debuggee exits. */
+ i386_cleanup_dregs ();
+ go32_kill_inferior ();
+ generic_mourn_inferior ();
+}
+
+static int
+go32_can_run (void)
+{
+ return 1;
+}
+
+/* Hardware watchpoint support. */
+
+#define D_REGS edi.dr
+#define CONTROL D_REGS[7]
+#define STATUS D_REGS[6]
+
+/* Pass the address ADDR to the inferior in the I'th debug register.
+ Here we just store the address in D_REGS, the watchpoint will be
+ actually set up when go32_wait runs the debuggee. */
+void
+go32_set_dr (int i, CORE_ADDR addr)
+{
+ if (i < 0 || i > 3)
+ internal_error (__FILE__, __LINE__,
+ "Invalid register %d in go32_set_dr.\n", i);
+ D_REGS[i] = addr;
+}
+
+/* Pass the value VAL to the inferior in the DR7 debug control
+ register. Here we just store the address in D_REGS, the watchpoint
+ will be actually set up when go32_wait runs the debuggee. */
+void
+go32_set_dr7 (unsigned val)
+{
+ CONTROL = val;
+}
+
+/* Get the value of the DR6 debug status register from the inferior.
+ Here we just return the value stored in D_REGS, as we've got it
+ from the last go32_wait call. */
+unsigned
+go32_get_dr6 (void)
+{
+ return STATUS;
+}
+
+/* Put the device open on handle FD into either raw or cooked
+ mode, return 1 if it was in raw mode, zero otherwise. */
+
+static int
+device_mode (int fd, int raw_p)
+{
+ int oldmode, newmode;
+ __dpmi_regs regs;
+
+ regs.x.ax = 0x4400;
+ regs.x.bx = fd;
+ __dpmi_int (0x21, &regs);
+ if (regs.x.flags & 1)
+ return -1;
+ newmode = oldmode = regs.x.dx;
+
+ if (raw_p)
+ newmode |= 0x20;
+ else
+ newmode &= ~0x20;
+
+ if (oldmode & 0x80) /* Only for character dev */
+ {
+ regs.x.ax = 0x4401;
+ regs.x.bx = fd;
+ regs.x.dx = newmode & 0xff; /* Force upper byte zero, else it fails */
+ __dpmi_int (0x21, &regs);
+ if (regs.x.flags & 1)
+ return -1;
+ }
+ return (oldmode & 0x20) == 0x20;
+}
+
+
+static int inf_mode_valid = 0;
+static int inf_terminal_mode;
+
+/* This semaphore is needed because, amazingly enough, GDB calls
+ target.to_terminal_ours more than once after the inferior stops.
+ But we need the information from the first call only, since the
+ second call will always see GDB's own cooked terminal. */
+static int terminal_is_ours = 1;
+
+static void
+go32_terminal_init (void)
+{
+ inf_mode_valid = 0; /* reinitialize, in case they are restarting child */
+ terminal_is_ours = 1;
+}
+
+static void
+go32_terminal_info (char *args, int from_tty)
+{
+ printf_unfiltered ("Inferior's terminal is in %s mode.\n",
+ !inf_mode_valid
+ ? "default" : inf_terminal_mode ? "raw" : "cooked");
+
+#if __DJGPP_MINOR__ > 2
+ if (child_cmd.redirection)
+ {
+ int i;
+
+ for (i = 0; i < DBG_HANDLES; i++)
+ {
+ if (child_cmd.redirection[i]->file_name)
+ printf_unfiltered ("\tFile handle %d is redirected to `%s'.\n",
+ i, child_cmd.redirection[i]->file_name);
+ else if (_get_dev_info (child_cmd.redirection[i]->inf_handle) == -1)
+ printf_unfiltered
+ ("\tFile handle %d appears to be closed by inferior.\n", i);
+ /* Mask off the raw/cooked bit when comparing device info words. */
+ else if ((_get_dev_info (child_cmd.redirection[i]->inf_handle) & 0xdf)
+ != (_get_dev_info (i) & 0xdf))
+ printf_unfiltered
+ ("\tFile handle %d appears to be redirected by inferior.\n", i);
+ }
+ }
+#endif
+}
+
+static void
+go32_terminal_inferior (void)
+{
+ /* Redirect standard handles as child wants them. */
+ errno = 0;
+ if (redir_to_child (&child_cmd) == -1)
+ {
+ redir_to_debugger (&child_cmd);
+ error ("Cannot redirect standard handles for program: %s.",
+ safe_strerror (errno));
+ }
+ /* set the console device of the inferior to whatever mode
+ (raw or cooked) we found it last time */
+ if (terminal_is_ours)
+ {
+ if (inf_mode_valid)
+ device_mode (0, inf_terminal_mode);
+ terminal_is_ours = 0;
+ }
+}
+
+static void
+go32_terminal_ours (void)
+{
+ /* Switch to cooked mode on the gdb terminal and save the inferior
+ terminal mode to be restored when it is resumed */
+ if (!terminal_is_ours)
+ {
+ inf_terminal_mode = device_mode (0, 0);
+ if (inf_terminal_mode != -1)
+ inf_mode_valid = 1;
+ else
+ /* If device_mode returned -1, we don't know what happens with
+ handle 0 anymore, so make the info invalid. */
+ inf_mode_valid = 0;
+ terminal_is_ours = 1;
+
+ /* Restore debugger's standard handles. */
+ errno = 0;
+ if (redir_to_debugger (&child_cmd) == -1)
+ {
+ redir_to_child (&child_cmd);
+ error ("Cannot redirect standard handles for debugger: %s.",
+ safe_strerror (errno));
+ }
+ }
+}
+
+static void
+init_go32_ops (void)
+{
+ go32_ops.to_shortname = "djgpp";
+ go32_ops.to_longname = "djgpp target process";
+ go32_ops.to_doc =
+ "Program loaded by djgpp, when gdb is used as an external debugger";
+ go32_ops.to_open = go32_open;
+ go32_ops.to_close = go32_close;
+ go32_ops.to_attach = go32_attach;
+ go32_ops.to_detach = go32_detach;
+ go32_ops.to_resume = go32_resume;
+ go32_ops.to_wait = go32_wait;
+ go32_ops.to_fetch_registers = go32_fetch_registers;
+ go32_ops.to_store_registers = go32_store_registers;
+ go32_ops.to_prepare_to_store = go32_prepare_to_store;
+ go32_ops.to_xfer_memory = go32_xfer_memory;
+ go32_ops.to_files_info = go32_files_info;
+ go32_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ go32_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ go32_ops.to_terminal_init = go32_terminal_init;
+ go32_ops.to_terminal_inferior = go32_terminal_inferior;
+ go32_ops.to_terminal_ours_for_output = go32_terminal_ours;
+ go32_ops.to_terminal_ours = go32_terminal_ours;
+ go32_ops.to_terminal_info = go32_terminal_info;
+ go32_ops.to_kill = go32_kill_inferior;
+ go32_ops.to_create_inferior = go32_create_inferior;
+ go32_ops.to_mourn_inferior = go32_mourn_inferior;
+ go32_ops.to_can_run = go32_can_run;
+ go32_ops.to_stop = go32_stop;
+ go32_ops.to_stratum = process_stratum;
+ go32_ops.to_has_all_memory = 1;
+ go32_ops.to_has_memory = 1;
+ go32_ops.to_has_stack = 1;
+ go32_ops.to_has_registers = 1;
+ go32_ops.to_has_execution = 1;
+ go32_ops.to_magic = OPS_MAGIC;
+
+ /* Initialize child's cwd as empty to be initialized when starting
+ the child. */
+ *child_cwd = 0;
+
+ /* Initialize child's command line storage. */
+ if (redir_debug_init (&child_cmd) == -1)
+ internal_error (__FILE__, __LINE__,
+ "Cannot allocate redirection storage: not enough memory.\n");
+
+ /* We are always processing GCC-compiled programs. */
+ processing_gcc_compilation = 2;
+}
+
+unsigned short windows_major, windows_minor;
+
+/* Compute the version Windows reports via Int 2Fh/AX=1600h. */
+static void
+go32_get_windows_version(void)
+{
+ __dpmi_regs r;
+
+ r.x.ax = 0x1600;
+ __dpmi_int(0x2f, &r);
+ if (r.h.al > 2 && r.h.al != 0x80 && r.h.al != 0xff
+ && (r.h.al > 3 || r.h.ah > 0))
+ {
+ windows_major = r.h.al;
+ windows_minor = r.h.ah;
+ }
+ else
+ windows_major = 0xff; /* meaning no Windows */
+}
+
+/* A subroutine of go32_sysinfo to display memory info. */
+static void
+print_mem (unsigned long datum, const char *header, int in_pages_p)
+{
+ if (datum != 0xffffffffUL)
+ {
+ if (in_pages_p)
+ datum <<= 12;
+ puts_filtered (header);
+ if (datum > 1024)
+ {
+ printf_filtered ("%lu KB", datum >> 10);
+ if (datum > 1024 * 1024)
+ printf_filtered (" (%lu MB)", datum >> 20);
+ }
+ else
+ printf_filtered ("%lu Bytes", datum);
+ puts_filtered ("\n");
+ }
+}
+
+/* Display assorted information about the underlying OS. */
+static void
+go32_sysinfo (char *arg, int from_tty)
+{
+ struct utsname u;
+ char cpuid_vendor[13];
+ unsigned cpuid_max = 0, cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
+ unsigned true_dos_version = _get_dos_version (1);
+ unsigned advertized_dos_version = ((unsigned int)_osmajor << 8) | _osminor;
+ int dpmi_flags;
+ char dpmi_vendor_info[129];
+ int dpmi_vendor_available =
+ __dpmi_get_capabilities (&dpmi_flags, dpmi_vendor_info);
+ __dpmi_version_ret dpmi_version_data;
+ long eflags;
+ __dpmi_free_mem_info mem_info;
+ __dpmi_regs regs;
+
+ cpuid_vendor[0] = '\0';
+ if (uname (&u))
+ strcpy (u.machine, "Unknown x86");
+ else if (u.machine[0] == 'i' && u.machine[1] > 4)
+ {
+ /* CPUID with EAX = 0 returns the Vendor ID. */
+ __asm__ __volatile__ ("xorl %%ebx, %%ebx;"
+ "xorl %%ecx, %%ecx;"
+ "xorl %%edx, %%edx;"
+ "movl $0, %%eax;"
+ "cpuid;"
+ "movl %%ebx, %0;"
+ "movl %%edx, %1;"
+ "movl %%ecx, %2;"
+ "movl %%eax, %3;"
+ : "=m" (cpuid_vendor[0]),
+ "=m" (cpuid_vendor[4]),
+ "=m" (cpuid_vendor[8]),
+ "=m" (cpuid_max)
+ :
+ : "%eax", "%ebx", "%ecx", "%edx");
+ cpuid_vendor[12] = '\0';
+ }
+
+ printf_filtered ("CPU Type.......................%s", u.machine);
+ if (cpuid_vendor[0])
+ printf_filtered (" (%s)", cpuid_vendor);
+ puts_filtered ("\n");
+
+ /* CPUID with EAX = 1 returns processor signature and features. */
+ if (cpuid_max >= 1)
+ {
+ static char *brand_name[] = {
+ "",
+ " Celeron",
+ " III",
+ " III Xeon",
+ "", "", "", "",
+ " 4"
+ };
+ char cpu_string[80];
+ char cpu_brand[20];
+ unsigned brand_idx;
+ int intel_p = strcmp (cpuid_vendor, "GenuineIntel") == 0;
+ int amd_p = strcmp (cpuid_vendor, "AuthenticAMD") == 0;
+ unsigned cpu_family, cpu_model;
+
+ __asm__ __volatile__ ("movl $1, %%eax;"
+ "cpuid;"
+ : "=a" (cpuid_eax),
+ "=b" (cpuid_ebx),
+ "=d" (cpuid_edx)
+ :
+ : "%ecx");
+ brand_idx = cpuid_ebx & 0xff;
+ cpu_family = (cpuid_eax >> 8) & 0xf;
+ cpu_model = (cpuid_eax >> 4) & 0xf;
+ cpu_brand[0] = '\0';
+ if (intel_p)
+ {
+ if (brand_idx > 0
+ && brand_idx < sizeof(brand_name)/sizeof(brand_name[0])
+ && *brand_name[brand_idx])
+ strcpy (cpu_brand, brand_name[brand_idx]);
+ else if (cpu_family == 5)
+ {
+ if (((cpuid_eax >> 12) & 3) == 0 && cpu_model == 4)
+ strcpy (cpu_brand, " MMX");
+ else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 1)
+ strcpy (cpu_brand, " OverDrive");
+ else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 2)
+ strcpy (cpu_brand, " Dual");
+ }
+ else if (cpu_family == 6 && cpu_model < 8)
+ {
+ switch (cpu_model)
+ {
+ case 1:
+ strcpy (cpu_brand, " Pro");
+ break;
+ case 3:
+ strcpy (cpu_brand, " II");
+ break;
+ case 5:
+ strcpy (cpu_brand, " II Xeon");
+ break;
+ case 6:
+ strcpy (cpu_brand, " Celeron");
+ break;
+ case 7:
+ strcpy (cpu_brand, " III");
+ break;
+ }
+ }
+ }
+ else if (amd_p)
+ {
+ switch (cpu_family)
+ {
+ case 4:
+ strcpy (cpu_brand, "486/5x86");
+ break;
+ case 5:
+ switch (cpu_model)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ strcpy (cpu_brand, "-K5");
+ break;
+ case 6:
+ case 7:
+ strcpy (cpu_brand, "-K6");
+ break;
+ case 8:
+ strcpy (cpu_brand, "-K6-2");
+ break;
+ case 9:
+ strcpy (cpu_brand, "-K6-III");
+ break;
+ }
+ break;
+ case 6:
+ switch (cpu_model)
+ {
+ case 1:
+ case 2:
+ case 4:
+ strcpy (cpu_brand, " Athlon");
+ break;
+ case 3:
+ strcpy (cpu_brand, " Duron");
+ break;
+ }
+ break;
+ }
+ }
+ sprintf (cpu_string, "%s%s Model %d Stepping %d",
+ intel_p ? "Pentium" : (amd_p ? "AMD" : "ix86"),
+ cpu_brand, cpu_model, cpuid_eax & 0xf);
+ printfi_filtered (31, "%s\n", cpu_string);
+ if (((cpuid_edx & (6 | (0x0d << 23))) != 0)
+ || ((cpuid_edx & 1) == 0)
+ || (amd_p && (cpuid_edx & (3 << 30)) != 0))
+ {
+ puts_filtered ("CPU Features...................");
+ /* We only list features which might be useful in the DPMI
+ environment. */
+ if ((cpuid_edx & 1) == 0)
+ puts_filtered ("No FPU "); /* it's unusual to not have an FPU */
+ if ((cpuid_edx & (1 << 1)) != 0)
+ puts_filtered ("VME ");
+ if ((cpuid_edx & (1 << 2)) != 0)
+ puts_filtered ("DE ");
+ if ((cpuid_edx & (1 << 4)) != 0)
+ puts_filtered ("TSC ");
+ if ((cpuid_edx & (1 << 23)) != 0)
+ puts_filtered ("MMX ");
+ if ((cpuid_edx & (1 << 25)) != 0)
+ puts_filtered ("SSE ");
+ if ((cpuid_edx & (1 << 26)) != 0)
+ puts_filtered ("SSE2 ");
+ if (amd_p)
+ {
+ if ((cpuid_edx & (1 << 31)) != 0)
+ puts_filtered ("3DNow! ");
+ if ((cpuid_edx & (1 << 30)) != 0)
+ puts_filtered ("3DNow!Ext");
+ }
+ puts_filtered ("\n");
+ }
+ }
+ puts_filtered ("\n");
+ printf_filtered ("DOS Version....................%s %s.%s",
+ _os_flavor, u.release, u.version);
+ if (true_dos_version != advertized_dos_version)
+ printf_filtered (" (disguised as v%d.%d)", _osmajor, _osminor);
+ puts_filtered ("\n");
+ if (!windows_major)
+ go32_get_windows_version ();
+ if (windows_major != 0xff)
+ {
+ const char *windows_flavor;
+
+ printf_filtered ("Windows Version................%d.%02d (Windows ",
+ windows_major, windows_minor);
+ switch (windows_major)
+ {
+ case 3:
+ windows_flavor = "3.X";
+ break;
+ case 4:
+ switch (windows_minor)
+ {
+ case 0:
+ windows_flavor = "95, 95A, or 95B";
+ break;
+ case 3:
+ windows_flavor = "95B OSR2.1 or 95C OSR2.5";
+ break;
+ case 10:
+ windows_flavor = "98 or 98 SE";
+ break;
+ case 90:
+ windows_flavor = "ME";
+ break;
+ default:
+ windows_flavor = "9X";
+ break;
+ }
+ break;
+ default:
+ windows_flavor = "??";
+ break;
+ }
+ printf_filtered ("%s)\n", windows_flavor);
+ }
+ else if (true_dos_version == 0x532 && advertized_dos_version == 0x500)
+ printf_filtered ("Windows Version................Windows NT or Windows 2000\n");
+ puts_filtered ("\n");
+ if (dpmi_vendor_available == 0)
+ {
+ /* The DPMI spec says the vendor string should be ASCIIZ, but
+ I don't trust the vendors to follow that... */
+ if (!memchr (&dpmi_vendor_info[2], 0, 126))
+ dpmi_vendor_info[128] = '\0';
+ printf_filtered ("DPMI Host......................%s v%d.%d (capabilities: %#x)\n",
+ &dpmi_vendor_info[2],
+ (unsigned)dpmi_vendor_info[0],
+ (unsigned)dpmi_vendor_info[1],
+ ((unsigned)dpmi_flags & 0x7f));
+ }
+ __dpmi_get_version (&dpmi_version_data);
+ printf_filtered ("DPMI Version...................%d.%02d\n",
+ dpmi_version_data.major, dpmi_version_data.minor);
+ printf_filtered ("DPMI Info......................%s-bit DPMI, with%s Virtual Memory support\n",
+ (dpmi_version_data.flags & 1) ? "32" : "16",
+ (dpmi_version_data.flags & 4) ? "" : "out");
+ printfi_filtered (31, "Interrupts reflected to %s mode\n",
+ (dpmi_version_data.flags & 2) ? "V86" : "Real");
+ printfi_filtered (31, "Processor type: i%d86\n",
+ dpmi_version_data.cpu);
+ printfi_filtered (31, "PIC base interrupt: Master: %#x Slave: %#x\n",
+ dpmi_version_data.master_pic, dpmi_version_data.slave_pic);
+
+ /* a_tss is only initialized when the debuggee is first run. */
+ if (prog_has_started)
+ {
+ __asm__ __volatile__ ("pushfl ; popl %0" : "=g" (eflags));
+ printf_filtered ("Protection.....................Ring %d (in %s), with%s I/O protection\n",
+ a_tss.tss_cs & 3, (a_tss.tss_cs & 4) ? "LDT" : "GDT",
+ (a_tss.tss_cs & 3) > ((eflags >> 12) & 3) ? "" : "out");
+ }
+ puts_filtered ("\n");
+ __dpmi_get_free_memory_information (&mem_info);
+ print_mem (mem_info.total_number_of_physical_pages,
+ "DPMI Total Physical Memory.....", 1);
+ print_mem (mem_info.total_number_of_free_pages,
+ "DPMI Free Physical Memory......", 1);
+ print_mem (mem_info.size_of_paging_file_partition_in_pages,
+ "DPMI Swap Space................", 1);
+ print_mem (mem_info.linear_address_space_size_in_pages,
+ "DPMI Total Linear Address Size.", 1);
+ print_mem (mem_info.free_linear_address_space_in_pages,
+ "DPMI Free Linear Address Size..", 1);
+ print_mem (mem_info.largest_available_free_block_in_bytes,
+ "DPMI Largest Free Memory Block.", 0);
+
+ regs.h.ah = 0x48;
+ regs.x.bx = 0xffff;
+ __dpmi_int (0x21, &regs);
+ print_mem (regs.x.bx << 4, "Free DOS Memory................", 0);
+ regs.x.ax = 0x5800;
+ __dpmi_int (0x21, &regs);
+ if ((regs.x.flags & 1) == 0)
+ {
+ static const char *dos_hilo[] = {
+ "Low", "", "", "", "High", "", "", "", "High, then Low"
+ };
+ static const char *dos_fit[] = {
+ "First", "Best", "Last"
+ };
+ int hilo_idx = (regs.x.ax >> 4) & 0x0f;
+ int fit_idx = regs.x.ax & 0x0f;
+
+ if (hilo_idx > 8)
+ hilo_idx = 0;
+ if (fit_idx > 2)
+ fit_idx = 0;
+ printf_filtered ("DOS Memory Allocation..........%s memory, %s fit\n",
+ dos_hilo[hilo_idx], dos_fit[fit_idx]);
+ regs.x.ax = 0x5802;
+ __dpmi_int (0x21, &regs);
+ if ((regs.x.flags & 1) != 0)
+ regs.h.al = 0;
+ printfi_filtered (31, "UMBs %sin DOS memory chain\n",
+ regs.h.al == 0 ? "not " : "");
+ }
+}
+
+struct seg_descr {
+ unsigned short limit0 __attribute__((packed));
+ unsigned short base0 __attribute__((packed));
+ unsigned char base1 __attribute__((packed));
+ unsigned stype:5 __attribute__((packed));
+ unsigned dpl:2 __attribute__((packed));
+ unsigned present:1 __attribute__((packed));
+ unsigned limit1:4 __attribute__((packed));
+ unsigned available:1 __attribute__((packed));
+ unsigned dummy:1 __attribute__((packed));
+ unsigned bit32:1 __attribute__((packed));
+ unsigned page_granular:1 __attribute__((packed));
+ unsigned char base2 __attribute__((packed));
+};
+
+struct gate_descr {
+ unsigned short offset0 __attribute__((packed));
+ unsigned short selector __attribute__((packed));
+ unsigned param_count:5 __attribute__((packed));
+ unsigned dummy:3 __attribute__((packed));
+ unsigned stype:5 __attribute__((packed));
+ unsigned dpl:2 __attribute__((packed));
+ unsigned present:1 __attribute__((packed));
+ unsigned short offset1 __attribute__((packed));
+};
+
+/* Read LEN bytes starting at logical address ADDR, and put the result
+ into DEST. Return 1 if success, zero if not. */
+static int
+read_memory_region (unsigned long addr, void *dest, size_t len)
+{
+ unsigned long dos_ds_limit = __dpmi_get_segment_limit (_dos_ds);
+ int retval = 1;
+
+ /* For the low memory, we can simply use _dos_ds. */
+ if (addr <= dos_ds_limit - len)
+ dosmemget (addr, len, dest);
+ else
+ {
+ /* For memory above 1MB we need to set up a special segment to
+ be able to access that memory. */
+ int sel = __dpmi_allocate_ldt_descriptors (1);
+
+ if (sel <= 0)
+ retval = 0;
+ else
+ {
+ int access_rights = __dpmi_get_descriptor_access_rights (sel);
+ size_t segment_limit = len - 1;
+
+ /* Make sure the crucial bits in the descriptor access
+ rights are set correctly. Some DPMI providers might barf
+ if we set the segment limit to something that is not an
+ integral multiple of 4KB pages if the granularity bit is
+ not set to byte-granular, even though the DPMI spec says
+ it's the host's responsibility to set that bit correctly. */
+ if (len > 1024 * 1024)
+ {
+ access_rights |= 0x8000;
+ /* Page-granular segments should have the low 12 bits of
+ the limit set. */
+ segment_limit |= 0xfff;
+ }
+ else
+ access_rights &= ~0x8000;
+
+ if (__dpmi_set_segment_base_address (sel, addr) != -1
+ && __dpmi_set_descriptor_access_rights (sel, access_rights) != -1
+ && __dpmi_set_segment_limit (sel, segment_limit) != -1
+ /* W2K silently fails to set the segment limit, leaving
+ it at zero; this test avoids the resulting crash. */
+ && __dpmi_get_segment_limit (sel) >= segment_limit)
+ movedata (sel, 0, _my_ds (), (unsigned)dest, len);
+ else
+ retval = 0;
+
+ __dpmi_free_ldt_descriptor (sel);
+ }
+ }
+ return retval;
+}
+
+/* Get a segment descriptor stored at index IDX in the descriptor
+ table whose base address is TABLE_BASE. Return the descriptor
+ type, or -1 if failure. */
+static int
+get_descriptor (unsigned long table_base, int idx, void *descr)
+{
+ unsigned long addr = table_base + idx * 8; /* 8 bytes per entry */
+
+ if (read_memory_region (addr, descr, 8))
+ return (int)((struct seg_descr *)descr)->stype;
+ return -1;
+}
+
+struct dtr_reg {
+ unsigned short limit __attribute__((packed));
+ unsigned long base __attribute__((packed));
+};
+
+/* Display a segment descriptor stored at index IDX in a descriptor
+ table whose type is TYPE and whose base address is BASE_ADDR. If
+ FORCE is non-zero, display even invalid descriptors. */
+static void
+display_descriptor (unsigned type, unsigned long base_addr, int idx, int force)
+{
+ struct seg_descr descr;
+ struct gate_descr gate;
+
+ /* Get the descriptor from the table. */
+ if (idx == 0 && type == 0)
+ puts_filtered ("0x000: null descriptor\n");
+ else if (get_descriptor (base_addr, idx, &descr) != -1)
+ {
+ /* For each type of descriptor table, this has a bit set if the
+ corresponding type of selectors is valid in that table. */
+ static unsigned allowed_descriptors[] = {
+ 0xffffdafeL, /* GDT */
+ 0x0000c0e0L, /* IDT */
+ 0xffffdafaL /* LDT */
+ };
+
+ /* If the program hasn't started yet, assume the debuggee will
+ have the same CPL as the debugger. */
+ int cpl = prog_has_started ? (a_tss.tss_cs & 3) : _my_cs () & 3;
+ unsigned long limit = (descr.limit1 << 16) | descr.limit0;
+
+ if (descr.present
+ && (allowed_descriptors[type] & (1 << descr.stype)) != 0)
+ {
+ printf_filtered ("0x%03x: ",
+ type == 1
+ ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
+ if (descr.page_granular)
+ limit = (limit << 12) | 0xfff; /* big segment: low 12 bit set */
+ if (descr.stype == 1 || descr.stype == 2 || descr.stype == 3
+ || descr.stype == 9 || descr.stype == 11
+ || (descr.stype >= 16 && descr.stype < 32))
+ printf_filtered ("base=0x%02x%02x%04x limit=0x%08lx",
+ descr.base2, descr.base1, descr.base0, limit);
+
+ switch (descr.stype)
+ {
+ case 1:
+ case 3:
+ printf_filtered (" 16-bit TSS (task %sactive)",
+ descr.stype == 3 ? "" : "in");
+ break;
+ case 2:
+ puts_filtered (" LDT");
+ break;
+ case 4:
+ memcpy (&gate, &descr, sizeof gate);
+ printf_filtered ("selector=0x%04x offs=0x%04x%04x",
+ gate.selector, gate.offset1, gate.offset0);
+ printf_filtered (" 16-bit Call Gate (params=%d)",
+ gate.param_count);
+ break;
+ case 5:
+ printf_filtered ("TSS selector=0x%04x", descr.base0);
+ printfi_filtered (16, "Task Gate");
+ break;
+ case 6:
+ case 7:
+ memcpy (&gate, &descr, sizeof gate);
+ printf_filtered ("selector=0x%04x offs=0x%04x%04x",
+ gate.selector, gate.offset1, gate.offset0);
+ printf_filtered (" 16-bit %s Gate",
+ descr.stype == 6 ? "Interrupt" : "Trap");
+ break;
+ case 9:
+ case 11:
+ printf_filtered (" 32-bit TSS (task %sactive)",
+ descr.stype == 3 ? "" : "in");
+ break;
+ case 12:
+ memcpy (&gate, &descr, sizeof gate);
+ printf_filtered ("selector=0x%04x offs=0x%04x%04x",
+ gate.selector, gate.offset1, gate.offset0);
+ printf_filtered (" 32-bit Call Gate (params=%d)",
+ gate.param_count);
+ break;
+ case 14:
+ case 15:
+ memcpy (&gate, &descr, sizeof gate);
+ printf_filtered ("selector=0x%04x offs=0x%04x%04x",
+ gate.selector, gate.offset1, gate.offset0);
+ printf_filtered (" 32-bit %s Gate",
+ descr.stype == 14 ? "Interrupt" : "Trap");
+ break;
+ case 16: /* data segments */
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ printf_filtered (" %s-bit Data (%s Exp-%s%s)",
+ descr.bit32 ? "32" : "16",
+ descr.stype & 2 ? "Read/Write," : "Read-Only, ",
+ descr.stype & 4 ? "down" : "up",
+ descr.stype & 1 ? "" : ", N.Acc");
+ break;
+ case 24: /* code segments */
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ printf_filtered (" %s-bit Code (%s, %sConf%s)",
+ descr.bit32 ? "32" : "16",
+ descr.stype & 2 ? "Exec/Read" : "Exec-Only",
+ descr.stype & 4 ? "" : "N.",
+ descr.stype & 1 ? "" : ", N.Acc");
+ break;
+ default:
+ printf_filtered ("Unknown type 0x%02x", descr.stype);
+ break;
+ }
+ puts_filtered ("\n");
+ }
+ else if (force)
+ {
+ printf_filtered ("0x%03x: ",
+ type == 1
+ ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
+ if (!descr.present)
+ puts_filtered ("Segment not present\n");
+ else
+ printf_filtered ("Segment type 0x%02x is invalid in this table\n",
+ descr.stype);
+ }
+ }
+ else if (force)
+ printf_filtered ("0x%03x: Cannot read this descriptor\n", idx);
+}
+
+static void
+go32_sldt (char *arg, int from_tty)
+{
+ struct dtr_reg gdtr;
+ unsigned short ldtr = 0;
+ int ldt_idx;
+ struct seg_descr ldt_descr;
+ long ldt_entry = -1L;
+ int cpl = (prog_has_started ? a_tss.tss_cs : _my_cs ()) & 3;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ {
+ ldt_entry = parse_and_eval_long (arg);
+ if (ldt_entry < 0
+ || (ldt_entry & 4) == 0
+ || (ldt_entry & 3) != (cpl & 3))
+ error ("Invalid LDT entry 0x%03lx.", (unsigned long)ldt_entry);
+ }
+ }
+
+ __asm__ __volatile__ ("sgdt %0" : "=m" (gdtr) : /* no inputs */ );
+ __asm__ __volatile__ ("sldt %0" : "=m" (ldtr) : /* no inputs */ );
+ ldt_idx = ldtr / 8;
+ if (ldt_idx == 0)
+ puts_filtered ("There is no LDT.\n");
+ /* LDT's entry in the GDT must have the type LDT, which is 2. */
+ else if (get_descriptor (gdtr.base, ldt_idx, &ldt_descr) != 2)
+ printf_filtered ("LDT is present (at %#x), but unreadable by GDB.\n",
+ ldt_descr.base0
+ | (ldt_descr.base1 << 16)
+ | (ldt_descr.base2 << 24));
+ else
+ {
+ unsigned base =
+ ldt_descr.base0
+ | (ldt_descr.base1 << 16)
+ | (ldt_descr.base2 << 24);
+ unsigned limit = ldt_descr.limit0 | (ldt_descr.limit1 << 16);
+ int max_entry;
+
+ if (ldt_descr.page_granular)
+ /* Page-granular segments must have the low 12 bits of their
+ limit set. */
+ limit = (limit << 12) | 0xfff;
+ /* LDT cannot have more than 8K 8-byte entries, i.e. more than
+ 64KB. */
+ if (limit > 0xffff)
+ limit = 0xffff;
+
+ max_entry = (limit + 1) / 8;
+
+ if (ldt_entry >= 0)
+ {
+ if (ldt_entry > limit)
+ error ("Invalid LDT entry %#lx: outside valid limits [0..%#x]",
+ (unsigned long)ldt_entry, limit);
+
+ display_descriptor (ldt_descr.stype, base, ldt_entry / 8, 1);
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < max_entry; i++)
+ display_descriptor (ldt_descr.stype, base, i, 0);
+ }
+ }
+}
+
+static void
+go32_sgdt (char *arg, int from_tty)
+{
+ struct dtr_reg gdtr;
+ long gdt_entry = -1L;
+ int max_entry;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ {
+ gdt_entry = parse_and_eval_long (arg);
+ if (gdt_entry < 0 || (gdt_entry & 7) != 0)
+ error ("Invalid GDT entry 0x%03lx: not an integral multiple of 8.",
+ (unsigned long)gdt_entry);
+ }
+ }
+
+ __asm__ __volatile__ ("sgdt %0" : "=m" (gdtr) : /* no inputs */ );
+ max_entry = (gdtr.limit + 1) / 8;
+
+ if (gdt_entry >= 0)
+ {
+ if (gdt_entry > gdtr.limit)
+ error ("Invalid GDT entry %#lx: outside valid limits [0..%#x]",
+ (unsigned long)gdt_entry, gdtr.limit);
+
+ display_descriptor (0, gdtr.base, gdt_entry / 8, 1);
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < max_entry; i++)
+ display_descriptor (0, gdtr.base, i, 0);
+ }
+}
+
+static void
+go32_sidt (char *arg, int from_tty)
+{
+ struct dtr_reg idtr;
+ long idt_entry = -1L;
+ int max_entry;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ {
+ idt_entry = parse_and_eval_long (arg);
+ if (idt_entry < 0)
+ error ("Invalid (negative) IDT entry %ld.", idt_entry);
+ }
+ }
+
+ __asm__ __volatile__ ("sidt %0" : "=m" (idtr) : /* no inputs */ );
+ max_entry = (idtr.limit + 1) / 8;
+ if (max_entry > 0x100) /* no more than 256 entries */
+ max_entry = 0x100;
+
+ if (idt_entry >= 0)
+ {
+ if (idt_entry > idtr.limit)
+ error ("Invalid IDT entry %#lx: outside valid limits [0..%#x]",
+ (unsigned long)idt_entry, idtr.limit);
+
+ display_descriptor (1, idtr.base, idt_entry, 1);
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < max_entry; i++)
+ display_descriptor (1, idtr.base, i, 0);
+ }
+}
+
+/* Cached linear address of the base of the page directory. For
+ now, available only under CWSDPMI. Code based on ideas and
+ suggestions from Charles Sandmann <sandmann@clio.rice.edu>. */
+static unsigned long pdbr;
+
+static unsigned long
+get_cr3 (void)
+{
+ unsigned offset;
+ unsigned taskreg;
+ unsigned long taskbase, cr3;
+ struct dtr_reg gdtr;
+
+ if (pdbr > 0 && pdbr <= 0xfffff)
+ return pdbr;
+
+ /* Get the linear address of GDT and the Task Register. */
+ __asm__ __volatile__ ("sgdt %0" : "=m" (gdtr) : /* no inputs */ );
+ __asm__ __volatile__ ("str %0" : "=m" (taskreg) : /* no inputs */ );
+
+ /* Task Register is a segment selector for the TSS of the current
+ task. Therefore, it can be used as an index into the GDT to get
+ at the segment descriptor for the TSS. To get the index, reset
+ the low 3 bits of the selector (which give the CPL). Add 2 to the
+ offset to point to the 3 low bytes of the base address. */
+ offset = gdtr.base + (taskreg & 0xfff8) + 2;
+
+
+ /* CWSDPMI's task base is always under the 1MB mark. */
+ if (offset > 0xfffff)
+ return 0;
+
+ _farsetsel (_dos_ds);
+ taskbase = _farnspeekl (offset) & 0xffffffU;
+ taskbase += _farnspeekl (offset + 2) & 0xff000000U;
+ if (taskbase > 0xfffff)
+ return 0;
+
+ /* CR3 (a.k.a. PDBR, the Page Directory Base Register) is stored at
+ offset 1Ch in the TSS. */
+ cr3 = _farnspeekl (taskbase + 0x1c) & ~0xfff;
+ if (cr3 > 0xfffff)
+ {
+#if 0 /* not fullly supported yet */
+ /* The Page Directory is in UMBs. In that case, CWSDPMI puts
+ the first Page Table right below the Page Directory. Thus,
+ the first Page Table's entry for its own address and the Page
+ Directory entry for that Page Table will hold the same
+ physical address. The loop below searches the entire UMB
+ range of addresses for such an occurence. */
+ unsigned long addr, pte_idx;
+
+ for (addr = 0xb0000, pte_idx = 0xb0;
+ pte_idx < 0xff;
+ addr += 0x1000, pte_idx++)
+ {
+ if (((_farnspeekl (addr + 4 * pte_idx) & 0xfffff027) ==
+ (_farnspeekl (addr + 0x1000) & 0xfffff027))
+ && ((_farnspeekl (addr + 4 * pte_idx + 4) & 0xfffff000) == cr3))
+ {
+ cr3 = addr + 0x1000;
+ break;
+ }
+ }
+#endif
+
+ if (cr3 > 0xfffff)
+ cr3 = 0;
+ }
+
+ return cr3;
+}
+
+/* Return the N'th Page Directory entry. */
+static unsigned long
+get_pde (int n)
+{
+ unsigned long pde = 0;
+
+ if (pdbr && n >= 0 && n < 1024)
+ {
+ pde = _farpeekl (_dos_ds, pdbr + 4*n);
+ }
+ return pde;
+}
+
+/* Return the N'th entry of the Page Table whose Page Directory entry
+ is PDE. */
+static unsigned long
+get_pte (unsigned long pde, int n)
+{
+ unsigned long pte = 0;
+
+ /* pde & 0x80 tests the 4MB page bit. We don't support 4MB
+ page tables, for now. */
+ if ((pde & 1) && !(pde & 0x80) && n >= 0 && n < 1024)
+ {
+ pde &= ~0xfff; /* clear non-address bits */
+ pte = _farpeekl (_dos_ds, pde + 4*n);
+ }
+ return pte;
+}
+
+/* Display a Page Directory or Page Table entry. IS_DIR, if non-zero,
+ says this is a Page Directory entry. If FORCE is non-zero, display
+ the entry even if its Present flag is off. OFF is the offset of the
+ address from the page's base address. */
+static void
+display_ptable_entry (unsigned long entry, int is_dir, int force, unsigned off)
+{
+ if ((entry & 1) != 0)
+ {
+ printf_filtered ("Base=0x%05lx000", entry >> 12);
+ if ((entry & 0x100) && !is_dir)
+ puts_filtered (" Global");
+ if ((entry & 0x40) && !is_dir)
+ puts_filtered (" Dirty");
+ printf_filtered (" %sAcc.", (entry & 0x20) ? "" : "Not-");
+ printf_filtered (" %sCached", (entry & 0x10) ? "" : "Not-");
+ printf_filtered (" Write-%s", (entry & 8) ? "Thru" : "Back");
+ printf_filtered (" %s", (entry & 4) ? "Usr" : "Sup");
+ printf_filtered (" Read-%s", (entry & 2) ? "Write" : "Only");
+ if (off)
+ printf_filtered (" +0x%x", off);
+ puts_filtered ("\n");
+ }
+ else if (force)
+ printf_filtered ("Page%s not present or not supported; value=0x%lx.\n",
+ is_dir ? " Table" : "", entry >> 1);
+}
+
+static void
+go32_pde (char *arg, int from_tty)
+{
+ long pde_idx = -1, i;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ {
+ pde_idx = parse_and_eval_long (arg);
+ if (pde_idx < 0 || pde_idx >= 1024)
+ error ("Entry %ld is outside valid limits [0..1023].", pde_idx);
+ }
+ }
+
+ pdbr = get_cr3 ();
+ if (!pdbr)
+ puts_filtered ("Access to Page Directories is not supported on this system.\n");
+ else if (pde_idx >= 0)
+ display_ptable_entry (get_pde (pde_idx), 1, 1, 0);
+ else
+ for (i = 0; i < 1024; i++)
+ display_ptable_entry (get_pde (i), 1, 0, 0);
+}
+
+/* A helper function to display entries in a Page Table pointed to by
+ the N'th entry in the Page Directory. If FORCE is non-zero, say
+ something even if the Page Table is not accessible. */
+static void
+display_page_table (long n, int force)
+{
+ unsigned long pde = get_pde (n);
+
+ if ((pde & 1) != 0)
+ {
+ int i;
+
+ printf_filtered ("Page Table pointed to by Page Directory entry 0x%lx:\n", n);
+ for (i = 0; i < 1024; i++)
+ display_ptable_entry (get_pte (pde, i), 0, 0, 0);
+ puts_filtered ("\n");
+ }
+ else if (force)
+ printf_filtered ("Page Table not present; value=0x%lx.\n", pde >> 1);
+}
+
+static void
+go32_pte (char *arg, int from_tty)
+{
+ long pde_idx = -1L, i;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ {
+ pde_idx = parse_and_eval_long (arg);
+ if (pde_idx < 0 || pde_idx >= 1024)
+ error ("Entry %ld is outside valid limits [0..1023].", pde_idx);
+ }
+ }
+
+ pdbr = get_cr3 ();
+ if (!pdbr)
+ puts_filtered ("Access to Page Tables is not supported on this system.\n");
+ else if (pde_idx >= 0)
+ display_page_table (pde_idx, 1);
+ else
+ for (i = 0; i < 1024; i++)
+ display_page_table (i, 0);
+}
+
+static void
+go32_pte_for_address (char *arg, int from_tty)
+{
+ CORE_ADDR addr = 0, i;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ addr = parse_and_eval_address (arg);
+ }
+ if (!addr)
+ error_no_arg ("linear address");
+
+ pdbr = get_cr3 ();
+ if (!pdbr)
+ puts_filtered ("Access to Page Tables is not supported on this system.\n");
+ else
+ {
+ int pde_idx = (addr >> 22) & 0x3ff;
+ int pte_idx = (addr >> 12) & 0x3ff;
+ unsigned offs = addr & 0xfff;
+
+ printf_filtered ("Page Table entry for address 0x%llx:\n",
+ (unsigned long long)addr);
+ display_ptable_entry (get_pte (get_pde (pde_idx), pte_idx), 0, 1, offs);
+ }
+}
+
+static struct cmd_list_element *info_dos_cmdlist = NULL;
+
+static void
+go32_info_dos_command (char *args, int from_tty)
+{
+ help_list (info_dos_cmdlist, "info dos ", class_info, gdb_stdout);
+}
+
+void
+_initialize_go32_nat (void)
+{
+ init_go32_ops ();
+ add_target (&go32_ops);
+
+ add_prefix_cmd ("dos", class_info, go32_info_dos_command,
+ "Print information specific to DJGPP (aka MS-DOS) debugging.",
+ &info_dos_cmdlist, "info dos ", 0, &infolist);
+
+ add_cmd ("sysinfo", class_info, go32_sysinfo,
+ "Display information about the target system, including CPU, OS, DPMI, etc.",
+ &info_dos_cmdlist);
+ add_cmd ("ldt", class_info, go32_sldt,
+ "Display entries in the LDT (Local Descriptor Table).\n"
+ "Entry number (an expression) as an argument means display only that entry.",
+ &info_dos_cmdlist);
+ add_cmd ("gdt", class_info, go32_sgdt,
+ "Display entries in the GDT (Global Descriptor Table).\n"
+ "Entry number (an expression) as an argument means display only that entry.",
+ &info_dos_cmdlist);
+ add_cmd ("idt", class_info, go32_sidt,
+ "Display entries in the IDT (Interrupt Descriptor Table).\n"
+ "Entry number (an expression) as an argument means display only that entry.",
+ &info_dos_cmdlist);
+ add_cmd ("pde", class_info, go32_pde,
+ "Display entries in the Page Directory.\n"
+ "Entry number (an expression) as an argument means display only that entry.",
+ &info_dos_cmdlist);
+ add_cmd ("pte", class_info, go32_pte,
+ "Display entries in Page Tables.\n"
+ "Entry number (an expression) as an argument means display only entries\n"
+ "from the Page Table pointed to by the specified Page Directory entry.",
+ &info_dos_cmdlist);
+ add_cmd ("address-pte", class_info, go32_pte_for_address,
+ "Display a Page Table entry for a linear address.\n"
+ "The address argument must be a linear address, after adding to\n"
+ "it the base address of the appropriate segment.\n"
+ "The base address of variables and functions in the debuggee's data\n"
+ "or code segment is stored in the variable __djgpp_base_address,\n"
+ "so use `__djgpp_base_address + (char *)&var' as the argument.\n"
+ "For other segments, look up their base address in the output of\n"
+ "the `info dos ldt' command.",
+ &info_dos_cmdlist);
+}
+
+pid_t
+tcgetpgrp (int fd)
+{
+ if (isatty (fd))
+ return SOME_PID;
+ errno = ENOTTY;
+ return -1;
+}
+
+int
+tcsetpgrp (int fd, pid_t pgid)
+{
+ if (isatty (fd) && pgid == SOME_PID)
+ return 0;
+ errno = pgid == SOME_PID ? ENOTTY : ENOSYS;
+ return -1;
+}
diff --git a/contrib/gdb/gdb/gregset.h b/contrib/gdb/gdb/gregset.h
new file mode 100644
index 0000000..0ec80a1
--- /dev/null
+++ b/contrib/gdb/gdb/gregset.h
@@ -0,0 +1,69 @@
+/* Interface for functions using gregset and fpregset types.
+ Copyright 2000, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GREGSET_H
+#define GREGSET_H
+
+#ifndef GDB_GREGSET_T
+#define GDB_GREGSET_T gregset_t
+#endif
+
+#ifndef GDB_FPREGSET_T
+#define GDB_FPREGSET_T fpregset_t
+#endif
+
+typedef GDB_GREGSET_T gdb_gregset_t;
+typedef GDB_FPREGSET_T gdb_fpregset_t;
+
+/* A gregset is a data structure supplied by the native OS containing
+ the general register values of the debugged process. Usually this
+ includes integer registers and control registers. An fpregset is a
+ data structure containing the floating point registers. These data
+ structures were originally a part of the /proc interface, but have
+ been borrowed or copied by other GDB targets, eg. GNU/Linux. */
+
+/* Copy register values from the native target gregset/fpregset
+ into GDB's internal register cache. */
+
+extern void supply_gregset (gdb_gregset_t *gregs);
+extern void supply_fpregset (gdb_fpregset_t *fpregs);
+
+/* Copy register values from GDB's register cache into
+ the native target gregset/fpregset. If regno is -1,
+ copy all the registers. */
+
+extern void fill_gregset (gdb_gregset_t *gregs, int regno);
+extern void fill_fpregset (gdb_fpregset_t *fpregs, int regno);
+
+#ifdef FILL_FPXREGSET
+/* GNU/Linux i386: Copy register values between GDB's internal register cache
+ and the i386 extended floating point registers. */
+
+#ifndef GDB_FPXREGSET_T
+#define GDB_FPXREGSET_T elf_fpxregset_t
+#endif
+
+typedef GDB_FPXREGSET_T gdb_fpxregset_t;
+
+extern void supply_fpxregset (gdb_fpxregset_t *fpxregs);
+extern void fill_fpxregset (gdb_fpxregset_t *fpxregs, int regno);
+#endif
+
+#endif
diff --git a/contrib/gdb/gdb/hpacc-abi.c b/contrib/gdb/gdb/hpacc-abi.c
new file mode 100644
index 0000000..0fb3adc
--- /dev/null
+++ b/contrib/gdb/gdb/hpacc-abi.c
@@ -0,0 +1,329 @@
+/* Abstraction of HP aCC ABI.
+ Contributed by Daniel Berlin <dberlin@redhat.com>
+ Most of the real code is from HP, i've just fiddled it to fit in
+ the C++ ABI abstraction framework.
+
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or
+ modify
+ it under the terms of the GNU General Public License as published
+ by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_regex.h"
+#include "gdb_string.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "cp-abi.h"
+
+struct cp_abi_ops hpacc_abi_ops;
+
+/* It appears the is_*_name stuff is never used when we try the hpACC
+ * ABI. As such, I have no clue what the real answers are. Shouldn't
+ * have any more effect than it does now. */
+static regex_t constructor_pattern;
+static regex_t destructor_pattern;
+static regex_t operator_pattern;
+
+static enum dtor_kinds
+hpacc_is_destructor_name (const char *name)
+{
+ if (regexec (&destructor_pattern, name, 0, 0, 0) == 0)
+ return complete_object_dtor;
+ else
+ return 0;
+}
+
+static enum ctor_kinds
+hpacc_is_constructor_name (const char *name)
+{
+ if (regexec (&constructor_pattern, name, 0, 0, 0) == 0)
+ return complete_object_ctor;
+ else
+ return 0;
+}
+
+static int
+hpacc_is_operator_name (const char *name)
+{
+ return regexec (&operator_pattern, name, 0, 0, 0) == 0;
+}
+
+static int
+hpacc_is_vtable_name (const char *name)
+{
+ return strcmp (name,
+ "This will never match anything, please fill it in") == 0;
+}
+
+/* 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. */
+static struct value *
+hpacc_virtual_fn_field (struct value **arg1p, struct fn_field * f, int j,
+ struct type * type, int offset)
+{
+ struct value *arg1 = *arg1p;
+ struct type *type1 = check_typedef (VALUE_TYPE (arg1));
+
+ /* Deal with HP/Taligent runtime model for virtual functions */
+ struct value *vp;
+ struct value *argp; /* arg1 cast to base */
+ CORE_ADDR coreptr; /* pointer to target address */
+ int class_index; /* which class segment pointer to use */
+ struct type *ftype = TYPE_FN_FIELD_TYPE (f, j); /* method type */
+
+ argp = value_cast (type, *arg1p);
+
+ if (VALUE_ADDRESS (argp) == 0)
+ error ("Address of object is null; object may not have been created.");
+
+ /* pai: FIXME -- 32x64 possible problem? */
+ /* First word (4 bytes) in object layout is the vtable pointer */
+ coreptr = *(CORE_ADDR *) (VALUE_CONTENTS (argp)); /* pai: (temp) */
+ /* + offset + VALUE_EMBEDDED_OFFSET (argp)); */
+
+ if (!coreptr)
+ error
+ ("Virtual table pointer is null for object; object may not have been created.");
+
+ /* pai/1997-05-09
+ * FIXME: The code here currently handles only
+ * the non-RRBC case of the Taligent/HP runtime spec; when RRBC
+ * is introduced, the condition for the "if" below will have to
+ * be changed to be a test for the RRBC case. */
+
+ if (1)
+ {
+ /* Non-RRBC case; the virtual function pointers are stored at fixed
+ * offsets in the virtual table. */
+
+ /* Retrieve the offset in the virtual table from the debug
+ * info. The offset of the vfunc's entry is in words from
+ * the beginning of the vtable; but first we have to adjust
+ * by HP_ACC_VFUNC_START to account for other entries */
+
+ /* pai: FIXME: 32x64 problem here, a word may be 8 bytes in
+ * which case the multiplier should be 8 and values should be long */
+ vp = value_at (builtin_type_int,
+ coreptr + 4 * (TYPE_FN_FIELD_VOFFSET (f, j) +
+ HP_ACC_VFUNC_START), NULL);
+
+ coreptr = *(CORE_ADDR *) (VALUE_CONTENTS (vp));
+ /* coreptr now contains the address of the virtual function */
+ /* (Actually, it contains the pointer to the plabel for the function. */
+ }
+ else
+ {
+ /* RRBC case; the virtual function pointers are found by double
+ * indirection through the class segment tables. */
+
+ /* Choose class segment depending on type we were passed */
+ class_index = class_index_in_primary_list (type);
+
+ /* Find class segment pointer. These are in the vtable slots after
+ * some other entries, so adjust by HP_ACC_VFUNC_START for that. */
+ /* pai: FIXME 32x64 problem here, if words are 8 bytes long
+ * the multiplier below has to be 8 and value should be long. */
+ vp = value_at (builtin_type_int,
+ coreptr + 4 * (HP_ACC_VFUNC_START + class_index), NULL);
+ /* Indirect once more, offset by function index */
+ /* pai: FIXME 32x64 problem here, again multiplier could be 8 and value long */
+ coreptr =
+ *(CORE_ADDR *) (VALUE_CONTENTS (vp) +
+ 4 * TYPE_FN_FIELD_VOFFSET (f, j));
+ vp = value_at (builtin_type_int, coreptr, NULL);
+ coreptr = *(CORE_ADDR *) (VALUE_CONTENTS (vp));
+
+ /* coreptr now contains the address of the virtual function */
+ /* (Actually, it contains the pointer to the plabel for the function.) */
+
+ }
+
+ if (!coreptr)
+ error ("Address of virtual function is null; error in virtual table?");
+
+ /* Wrap this addr in a value and return pointer */
+ vp = allocate_value (ftype);
+ VALUE_TYPE (vp) = ftype;
+ VALUE_ADDRESS (vp) = coreptr;
+
+ /* pai: (temp) do we need the value_ind stuff in value_fn_field? */
+ return vp;
+}
+
+
+static struct type *
+hpacc_value_rtti_type (struct value *v, int *full, int *top, int *using_enc)
+{
+ struct type *known_type;
+ struct type *rtti_type;
+ CORE_ADDR coreptr;
+ struct value *vp;
+ int using_enclosing = 0;
+ long top_offset = 0;
+ char rtti_type_name[256];
+
+ if (full)
+ *full = 0;
+ if (top)
+ *top = -1;
+ if (using_enc)
+ *using_enc = 0;
+
+ /* Get declared type */
+ known_type = VALUE_TYPE (v);
+ CHECK_TYPEDEF (known_type);
+ /* RTTI works only or class objects */
+ if (TYPE_CODE (known_type) != TYPE_CODE_CLASS)
+ return NULL;
+
+ /* If neither the declared type nor the enclosing type of the
+ * value structure has a HP ANSI C++ style virtual table,
+ * we can't do anything. */
+ if (!TYPE_HAS_VTABLE (known_type))
+ {
+ known_type = VALUE_ENCLOSING_TYPE (v);
+ CHECK_TYPEDEF (known_type);
+ if ((TYPE_CODE (known_type) != TYPE_CODE_CLASS) ||
+ !TYPE_HAS_VTABLE (known_type))
+ return NULL; /* No RTTI, or not HP-compiled types */
+ CHECK_TYPEDEF (known_type);
+ using_enclosing = 1;
+ }
+
+ if (using_enclosing && using_enc)
+ *using_enc = 1;
+
+ /* First get the virtual table address */
+ coreptr = *(CORE_ADDR *) ((VALUE_CONTENTS_ALL (v))
+ + VALUE_OFFSET (v)
+ + (using_enclosing
+ ? 0
+ : VALUE_EMBEDDED_OFFSET (v)));
+ if (coreptr == 0)
+ /* return silently -- maybe called on gdb-generated value */
+ return NULL;
+
+ /* Fetch the top offset of the object */
+ /* FIXME possible 32x64 problem with pointer size & arithmetic */
+ vp = value_at (builtin_type_int,
+ coreptr + 4 * HP_ACC_TOP_OFFSET_OFFSET,
+ VALUE_BFD_SECTION (v));
+ top_offset = value_as_long (vp);
+ if (top)
+ *top = top_offset;
+
+ /* Fetch the typeinfo pointer */
+ /* FIXME possible 32x64 problem with pointer size & arithmetic */
+ vp = value_at (builtin_type_int, coreptr + 4 * HP_ACC_TYPEINFO_OFFSET,
+ VALUE_BFD_SECTION (v));
+ /* Indirect through the typeinfo pointer and retrieve the pointer
+ * to the string name */
+ coreptr = *(CORE_ADDR *) (VALUE_CONTENTS (vp));
+ if (!coreptr)
+ error ("Retrieved null typeinfo pointer in trying to determine "
+ "run-time type");
+ /* 4 -> offset of name field */
+ vp = value_at (builtin_type_int, coreptr + 4, VALUE_BFD_SECTION (v));
+ /* FIXME possible 32x64 problem */
+
+ coreptr = *(CORE_ADDR *) (VALUE_CONTENTS (vp));
+
+ read_memory_string (coreptr, rtti_type_name, 256);
+
+ if (strlen (rtti_type_name) == 0)
+ error ("Retrieved null type name from typeinfo");
+
+ /* search for type */
+ rtti_type = lookup_typename (rtti_type_name, (struct block *) 0, 1);
+
+ if (!rtti_type)
+ error ("Could not find run-time type: invalid type name %s in typeinfo??",
+ rtti_type_name);
+ CHECK_TYPEDEF (rtti_type);
+#if 0
+ printf ("RTTI type name %s, tag %s, full? %d\n", TYPE_NAME (rtti_type),
+ TYPE_TAG_NAME (rtti_type), full ? *full : -1);
+#endif
+ /* Check whether we have the entire object */
+ if (full /* Non-null pointer passed */
+ &&
+ /* Either we checked on the whole object in hand and found the
+ top offset to be zero */
+ (((top_offset == 0) &&
+ using_enclosing &&
+ TYPE_LENGTH (known_type) == TYPE_LENGTH (rtti_type))
+ ||
+ /* Or we checked on the embedded object and top offset was the
+ same as the embedded offset */
+ ((top_offset == VALUE_EMBEDDED_OFFSET (v)) &&
+ !using_enclosing &&
+ TYPE_LENGTH (VALUE_ENCLOSING_TYPE (v)) == TYPE_LENGTH (rtti_type))))
+
+ *full = 1;
+
+ return rtti_type;
+}
+
+extern int gnuv2_baseclass_offset (struct type *type, int index,
+ char *valaddr, CORE_ADDR address);
+
+static void
+init_hpacc_ops (void)
+{
+ hpacc_abi_ops.shortname = "hpaCC";
+ hpacc_abi_ops.longname = "HP aCC ABI";
+ hpacc_abi_ops.doc = "HP aCC ABI";
+ hpacc_abi_ops.is_destructor_name = hpacc_is_destructor_name;
+ hpacc_abi_ops.is_constructor_name = hpacc_is_constructor_name;
+ hpacc_abi_ops.is_vtable_name = hpacc_is_vtable_name;
+ hpacc_abi_ops.is_operator_name = hpacc_is_operator_name;
+ hpacc_abi_ops.virtual_fn_field = hpacc_virtual_fn_field;
+ hpacc_abi_ops.rtti_type = hpacc_value_rtti_type;
+ /* It seems that this function is specific to GNU G++ < 3.0.
+ However, it is called for data members even in the HP
+ case (although not for member functions).
+ FIXME: Is that correct? */
+ hpacc_abi_ops.baseclass_offset = gnuv2_baseclass_offset;
+}
+
+extern initialize_file_ftype _initialize_hpacc_abi; /* -Wmissing-prototypes */
+
+void
+_initialize_hpacc_abi (void)
+{
+ init_hpacc_ops ();
+
+ regcomp (&constructor_pattern,
+ "^This will never match anything, please fill it in$", REG_NOSUB);
+
+ regcomp (&destructor_pattern,
+ "^This will never match anything, please fill it in$", REG_NOSUB);
+
+ regcomp (&operator_pattern,
+ "^This will never match anything, please fill it in$", REG_NOSUB);
+
+ register_cp_abi (&hpacc_abi_ops);
+}
diff --git a/contrib/gdb/gdb/hpread.c b/contrib/gdb/gdb/hpread.c
new file mode 100644
index 0000000..d345a04
--- /dev/null
+++ b/contrib/gdb/gdb/hpread.c
@@ -0,0 +1,6327 @@
+/* Read hp debug symbols and convert to internal format, for GDB.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "gdb_string.h"
+#include "hp-symtab.h"
+#include "syms.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "complaints.h"
+#include "gdb-stabs.h"
+#include "gdbtypes.h"
+#include "demangle.h"
+#include "somsolib.h"
+#include "gdb_assert.h"
+
+/* Private information attached to an objfile which we use to find
+ and internalize the HP C debug symbols within that objfile. */
+
+struct hpread_symfile_info
+ {
+ /* The contents of each of the debug sections (there are 4 of them). */
+ char *gntt;
+ char *lntt;
+ char *slt;
+ char *vt;
+
+ /* We keep the size of the $VT$ section for range checking. */
+ unsigned int vt_size;
+
+ /* Some routines still need to know the number of symbols in the
+ main debug sections ($LNTT$ and $GNTT$). */
+ unsigned int lntt_symcount;
+ unsigned int gntt_symcount;
+
+ /* To keep track of all the types we've processed. */
+ struct type **dntt_type_vector;
+ int dntt_type_vector_length;
+
+ /* Keeps track of the beginning of a range of source lines. */
+ sltpointer sl_index;
+
+ /* Some state variables we'll need. */
+ int within_function;
+
+ /* Keep track of the current function's address. We may need to look
+ up something based on this address. */
+ unsigned int current_function_value;
+ };
+
+/* Accessor macros to get at the fields. */
+#define HPUX_SYMFILE_INFO(o) \
+ ((struct hpread_symfile_info *)((o)->sym_private))
+#define GNTT(o) (HPUX_SYMFILE_INFO(o)->gntt)
+#define LNTT(o) (HPUX_SYMFILE_INFO(o)->lntt)
+#define SLT(o) (HPUX_SYMFILE_INFO(o)->slt)
+#define VT(o) (HPUX_SYMFILE_INFO(o)->vt)
+#define VT_SIZE(o) (HPUX_SYMFILE_INFO(o)->vt_size)
+#define LNTT_SYMCOUNT(o) (HPUX_SYMFILE_INFO(o)->lntt_symcount)
+#define GNTT_SYMCOUNT(o) (HPUX_SYMFILE_INFO(o)->gntt_symcount)
+#define DNTT_TYPE_VECTOR(o) (HPUX_SYMFILE_INFO(o)->dntt_type_vector)
+#define DNTT_TYPE_VECTOR_LENGTH(o) \
+ (HPUX_SYMFILE_INFO(o)->dntt_type_vector_length)
+#define SL_INDEX(o) (HPUX_SYMFILE_INFO(o)->sl_index)
+#define WITHIN_FUNCTION(o) (HPUX_SYMFILE_INFO(o)->within_function)
+#define CURRENT_FUNCTION_VALUE(o) (HPUX_SYMFILE_INFO(o)->current_function_value)
+
+
+/* We put a pointer to this structure in the read_symtab_private field
+ of the psymtab. */
+
+struct symloc
+ {
+ /* The 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;
+ };
+
+#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))
+
+/* Complaints about the symbols we have encountered. */
+static void
+lbrac_unmatched_complaint (int arg1)
+{
+ complaint (&symfile_complaints, "unmatched N_LBRAC before symtab pos %d",
+ arg1);
+}
+
+static void
+lbrac_mismatch_complaint (int arg1)
+{
+ complaint (&symfile_complaints,
+ "N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", arg1);
+}
+
+/* To generate dumping code, uncomment this define. The dumping
+ itself is controlled by routine-local statics called "dumping". */
+/* #define DUMPING 1 */
+
+/* To use the quick look-up tables, uncomment this define. */
+#define QUICK_LOOK_UP 1
+
+/* To call PXDB to process un-processed files, uncomment this define. */
+#define USE_PXDB 1
+
+/* Forward procedure declarations */
+
+/* Used in somread.c. */
+void hpread_symfile_init (struct objfile *);
+
+void do_pxdb (bfd *);
+
+void hpread_build_psymtabs (struct objfile *, int);
+
+void hpread_symfile_finish (struct objfile *);
+
+static void set_namestring (union dnttentry *sym, char **namep,
+ struct objfile *objfile);
+
+static union dnttentry *hpread_get_gntt (int, struct objfile *);
+
+static union dnttentry *hpread_get_lntt (int index, struct objfile *objfile);
+
+
+static unsigned long hpread_get_textlow (int, int, struct objfile *, int);
+
+static struct partial_symtab *hpread_start_psymtab
+ (struct objfile *, char *, CORE_ADDR, int,
+ struct partial_symbol **, struct partial_symbol **);
+
+static struct partial_symtab *hpread_end_psymtab
+ (struct partial_symtab *, char **, int, int, CORE_ADDR,
+ struct partial_symtab **, int);
+
+static unsigned long hpread_get_scope_start (sltpointer, struct objfile *);
+
+static unsigned long hpread_get_line (sltpointer, struct objfile *);
+
+static CORE_ADDR hpread_get_location (sltpointer, struct objfile *);
+
+static int hpread_has_name (enum dntt_entry_type kind);
+
+static void hpread_psymtab_to_symtab_1 (struct partial_symtab *);
+
+static void hpread_psymtab_to_symtab (struct partial_symtab *);
+
+static struct symtab *hpread_expand_symtab
+ (struct objfile *, int, int, CORE_ADDR, int,
+ struct section_offsets *, char *);
+
+static int hpread_type_translate (dnttpointer);
+
+static struct type **hpread_lookup_type (dnttpointer, struct objfile *);
+
+static struct type *hpread_alloc_type (dnttpointer, struct objfile *);
+
+static struct type *hpread_read_enum_type
+ (dnttpointer, union dnttentry *, struct objfile *);
+
+static struct type *hpread_read_function_type
+ (dnttpointer, union dnttentry *, struct objfile *, int);
+
+static struct type *hpread_read_doc_function_type
+ (dnttpointer, union dnttentry *, struct objfile *, int);
+
+static struct type *hpread_read_struct_type
+ (dnttpointer, union dnttentry *, struct objfile *);
+
+static struct type *hpread_get_nth_template_arg (struct objfile *, int);
+
+static struct type *hpread_read_templ_arg_type
+ (dnttpointer, union dnttentry *, struct objfile *, char *);
+
+static struct type *hpread_read_set_type
+ (dnttpointer, union dnttentry *, struct objfile *);
+
+static struct type *hpread_read_array_type
+ (dnttpointer, union dnttentry *dn_bufp, struct objfile *objfile);
+
+static struct type *hpread_read_subrange_type
+ (dnttpointer, union dnttentry *, struct objfile *);
+
+static struct type *hpread_type_lookup (dnttpointer, struct objfile *);
+
+static sltpointer hpread_record_lines
+ (struct subfile *, sltpointer, sltpointer, struct objfile *, CORE_ADDR);
+
+static void hpread_process_one_debug_symbol
+ (union dnttentry *, char *, struct section_offsets *,
+ struct objfile *, CORE_ADDR, int, char *, int, int *);
+
+static int hpread_get_scope_depth (union dnttentry *, struct objfile *, int);
+
+static void fix_static_member_physnames
+ (struct type *, char *, struct objfile *);
+
+static void fixup_class_method_type
+ (struct type *, struct type *, struct objfile *);
+
+static void hpread_adjust_bitoffsets (struct type *, int);
+
+static dnttpointer hpread_get_next_skip_over_anon_unions
+ (int, dnttpointer, union dnttentry **, struct objfile *);
+
+
+/* Global to indicate presence of HP-compiled objects,
+ in particular, SOM executable file with SOM debug info
+ Defined in symtab.c, used in hppa-tdep.c. */
+extern int hp_som_som_object_present;
+
+/* Static used to indicate a class type that requires a
+ fix-up of one of its method types */
+static struct type *fixup_class = NULL;
+
+/* Static used to indicate the method type that is to be
+ used to fix-up the type for fixup_class */
+static struct type *fixup_method = NULL;
+
+#ifdef USE_PXDB
+
+/* NOTE use of system files! May not be portable. */
+
+#define PXDB_SVR4 "/opt/langtools/bin/pxdb"
+#define PXDB_BSD "/usr/bin/pxdb"
+
+#include <stdlib.h>
+#include "gdb_string.h"
+
+/* check for the existence of a file, given its full pathname */
+static int
+file_exists (char *filename)
+{
+ if (filename)
+ return (access (filename, F_OK) == 0);
+ return 0;
+}
+
+
+/* Translate from the "hp_language" enumeration in hp-symtab.h
+ used in the debug info to gdb's generic enumeration in defs.h. */
+static enum language
+trans_lang (enum hp_language in_lang)
+{
+ if (in_lang == HP_LANGUAGE_C)
+ return language_c;
+
+ else if (in_lang == HP_LANGUAGE_CPLUSPLUS)
+ return language_cplus;
+
+ else if (in_lang == HP_LANGUAGE_FORTRAN)
+ return language_fortran;
+
+ else
+ return language_unknown;
+}
+
+static char main_string[] = "main";
+
+
+/* Given the native debug symbol SYM, set NAMEP to the name associated
+ with the debug symbol. Note we may be called with a debug symbol which
+ has no associated name, in that case we return an empty string. */
+
+static void
+set_namestring (union dnttentry *sym, char **namep, struct objfile *objfile)
+{
+ /* Note that we "know" that the name for any symbol is always in the same
+ place. Hence we don't have to conditionalize on the symbol type. */
+ if (! hpread_has_name (sym->dblock.kind))
+ *namep = "";
+ else if ((unsigned) sym->dsfile.name >= VT_SIZE (objfile))
+ {
+ complaint (&symfile_complaints, "bad string table offset in symbol %d",
+ symnum);
+ *namep = "";
+ }
+ else
+ *namep = sym->dsfile.name + VT (objfile);
+}
+
+/* Call PXDB to process our file.
+
+ Approach copied from DDE's "dbgk_run_pxdb". Note: we
+ don't check for BSD location of pxdb, nor for existence
+ of pxdb itself, etc.
+
+ NOTE: uses system function and string functions directly.
+
+ Return value: 1 if ok, 0 if not */
+static int
+hpread_call_pxdb (const char *file_name)
+{
+ char *p;
+ int status;
+ int retval;
+
+ if (file_exists (PXDB_SVR4))
+ {
+ p = xmalloc (strlen (PXDB_SVR4) + strlen (file_name) + 2);
+ strcpy (p, PXDB_SVR4);
+ strcat (p, " ");
+ strcat (p, file_name);
+
+ warning ("File not processed by pxdb--about to process now.\n");
+ status = system (p);
+
+ retval = (status == 0);
+ }
+ else
+ {
+ warning ("pxdb not found at standard location: /opt/langtools/bin\ngdb will not be able to debug %s.\nPlease install pxdb at the above location and then restart gdb.\nYou can also run pxdb on %s with the command\n\"pxdb %s\" and then restart gdb.", file_name, file_name, file_name);
+
+ retval = 0;
+ }
+ return retval;
+} /* hpread_call_pxdb */
+
+
+/* Return 1 if the file turns out to need pre-processing
+ by PXDB, and we have thus called PXDB to do this processing
+ and the file therefore needs to be re-loaded. Otherwise
+ return 0. */
+static int
+hpread_pxdb_needed (bfd *sym_bfd)
+{
+ asection *pinfo_section, *debug_section, *header_section;
+ unsigned int do_pxdb;
+ char *buf;
+ bfd_size_type header_section_size;
+
+ unsigned long tmp;
+ unsigned int pxdbed;
+
+ header_section = bfd_get_section_by_name (sym_bfd, "$HEADER$");
+ if (!header_section)
+ {
+ return 0; /* No header at all, can't recover... */
+ }
+
+ debug_section = bfd_get_section_by_name (sym_bfd, "$DEBUG$");
+ pinfo_section = bfd_get_section_by_name (sym_bfd, "$PINFO$");
+
+ if (pinfo_section && !debug_section)
+ {
+ /* Debug info with DOC, has different header format.
+ this only happens if the file was pxdbed and compiled optimized
+ otherwise the PINFO section is not there. */
+ header_section_size = bfd_section_size (objfile->obfd, header_section);
+
+ if (header_section_size == (bfd_size_type) sizeof (DOC_info_PXDB_header))
+ {
+ buf = alloca (sizeof (DOC_info_PXDB_header));
+ memset (buf, 0, sizeof (DOC_info_PXDB_header));
+
+ if (!bfd_get_section_contents (sym_bfd,
+ header_section,
+ buf, 0,
+ header_section_size))
+ error ("bfd_get_section_contents\n");
+
+ tmp = bfd_get_32 (sym_bfd, (bfd_byte *) (buf + sizeof (int) * 4));
+ pxdbed = (tmp >> 31) & 0x1;
+
+ if (!pxdbed)
+ error ("file debug header info invalid\n");
+ do_pxdb = 0;
+ }
+
+ else
+ error ("invalid $HEADER$ size in executable \n");
+ }
+
+ else
+ {
+
+ /* this can be three different cases:
+ 1. pxdbed and not doc
+ - DEBUG and HEADER sections are there
+ - header is PXDB_header type
+ - pxdbed flag is set to 1
+
+ 2. not pxdbed and doc
+ - DEBUG and HEADER sections are there
+ - header is DOC_info_header type
+ - pxdbed flag is set to 0
+
+ 3. not pxdbed and not doc
+ - DEBUG and HEADER sections are there
+ - header is XDB_header type
+ - pxdbed flag is set to 0
+
+ NOTE: the pxdbed flag is meaningful also in the not
+ already pxdb processed version of the header,
+ because in case on non-already processed by pxdb files
+ that same bit in the header would be always zero.
+ Why? Because the bit is the leftmost bit of a word
+ which contains a 'length' which is always a positive value
+ so that bit is never set to 1 (otherwise it would be negative)
+
+ Given the above, we have two choices : either we ignore the
+ size of the header itself and just look at the pxdbed field,
+ or we check the size and then we (for safety and paranoia related
+ issues) check the bit.
+ The first solution is used by DDE, the second by PXDB itself.
+ I am using the second one here, because I already wrote it,
+ and it is the end of a long day.
+ Also, using the first approach would still involve size issues
+ because we need to read in the contents of the header section, and
+ give the correct amount of stuff we want to read to the
+ get_bfd_section_contents function. */
+
+ /* decide which case depending on the size of the header section.
+ The size is as defined in hp-symtab.h */
+
+ header_section_size = bfd_section_size (objfile->obfd, header_section);
+
+ if (header_section_size == (bfd_size_type) sizeof (PXDB_header)) /* pxdb and not doc */
+ {
+
+ buf = alloca (sizeof (PXDB_header));
+ memset (buf, 0, sizeof (PXDB_header));
+ if (!bfd_get_section_contents (sym_bfd,
+ header_section,
+ buf, 0,
+ header_section_size))
+ error ("bfd_get_section_contents\n");
+
+ tmp = bfd_get_32 (sym_bfd, (bfd_byte *) (buf + sizeof (int) * 3));
+ pxdbed = (tmp >> 31) & 0x1;
+
+ if (pxdbed)
+ do_pxdb = 0;
+ else
+ error ("file debug header invalid\n");
+ }
+ else /*not pxdbed and doc OR not pxdbed and non doc */
+ do_pxdb = 1;
+ }
+
+ if (do_pxdb)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+} /* hpread_pxdb_needed */
+
+#endif
+
+/* Check whether the file needs to be preprocessed by pxdb.
+ If so, call pxdb. */
+
+void
+do_pxdb (bfd *sym_bfd)
+{
+ /* The following code is HP-specific. The "right" way of
+ doing this is unknown, but we bet would involve a target-
+ specific pre-file-load check using a generic mechanism. */
+
+ /* This code will not be executed if the file is not in SOM
+ format (i.e. if compiled with gcc) */
+ if (hpread_pxdb_needed (sym_bfd))
+ {
+ /*This file has not been pre-processed. Preprocess now */
+
+ if (hpread_call_pxdb (sym_bfd->filename))
+ {
+ /* The call above has changed the on-disk file,
+ we can close the file anyway, because the
+ symbols will be reread in when the target is run */
+ bfd_close (sym_bfd);
+ }
+ }
+}
+
+
+
+#ifdef QUICK_LOOK_UP
+
+/* Code to handle quick lookup-tables follows. */
+
+
+/* Some useful macros */
+#define VALID_FILE(i) ((i) < pxdb_header_p->fd_entries)
+#define VALID_MODULE(i) ((i) < pxdb_header_p->md_entries)
+#define VALID_PROC(i) ((i) < pxdb_header_p->pd_entries)
+#define VALID_CLASS(i) ((i) < pxdb_header_p->cd_entries)
+
+#define FILE_START(i) (qFD[i].adrStart)
+#define MODULE_START(i) (qMD[i].adrStart)
+#define PROC_START(i) (qPD[i].adrStart)
+
+#define FILE_END(i) (qFD[i].adrEnd)
+#define MODULE_END(i) (qMD[i].adrEnd)
+#define PROC_END(i) (qPD[i].adrEnd)
+
+#define FILE_ISYM(i) (qFD[i].isym)
+#define MODULE_ISYM(i) (qMD[i].isym)
+#define PROC_ISYM(i) (qPD[i].isym)
+
+#define VALID_CURR_FILE (curr_fd < pxdb_header_p->fd_entries)
+#define VALID_CURR_MODULE (curr_md < pxdb_header_p->md_entries)
+#define VALID_CURR_PROC (curr_pd < pxdb_header_p->pd_entries)
+#define VALID_CURR_CLASS (curr_cd < pxdb_header_p->cd_entries)
+
+#define CURR_FILE_START (qFD[curr_fd].adrStart)
+#define CURR_MODULE_START (qMD[curr_md].adrStart)
+#define CURR_PROC_START (qPD[curr_pd].adrStart)
+
+#define CURR_FILE_END (qFD[curr_fd].adrEnd)
+#define CURR_MODULE_END (qMD[curr_md].adrEnd)
+#define CURR_PROC_END (qPD[curr_pd].adrEnd)
+
+#define CURR_FILE_ISYM (qFD[curr_fd].isym)
+#define CURR_MODULE_ISYM (qMD[curr_md].isym)
+#define CURR_PROC_ISYM (qPD[curr_pd].isym)
+
+#define TELL_OBJFILE \
+ do { \
+ if( !told_objfile ) { \
+ told_objfile = 1; \
+ warning ("\nIn object file \"%s\":\n", \
+ objfile->name); \
+ } \
+ } while (0)
+
+
+
+/* Keeping track of the start/end symbol table (LNTT) indices of
+ psymtabs created so far */
+
+typedef struct
+{
+ int start;
+ int end;
+}
+pst_syms_struct;
+
+static pst_syms_struct *pst_syms_array = 0;
+
+static int pst_syms_count = 0;
+static int pst_syms_size = 0;
+
+/* used by the TELL_OBJFILE macro */
+static int told_objfile = 0;
+
+/* Set up psymtab symbol index stuff */
+static void
+init_pst_syms (void)
+{
+ pst_syms_count = 0;
+ pst_syms_size = 20;
+ pst_syms_array = (pst_syms_struct *) xmalloc (20 * sizeof (pst_syms_struct));
+}
+
+/* Clean up psymtab symbol index stuff */
+static void
+clear_pst_syms (void)
+{
+ pst_syms_count = 0;
+ pst_syms_size = 0;
+ xfree (pst_syms_array);
+ pst_syms_array = 0;
+}
+
+/* Add information about latest psymtab to symbol index table */
+static void
+record_pst_syms (int start_sym, int end_sym)
+{
+ if (++pst_syms_count > pst_syms_size)
+ {
+ pst_syms_array = (pst_syms_struct *) xrealloc (pst_syms_array,
+ 2 * pst_syms_size * sizeof (pst_syms_struct));
+ pst_syms_size *= 2;
+ }
+ pst_syms_array[pst_syms_count - 1].start = start_sym;
+ pst_syms_array[pst_syms_count - 1].end = end_sym;
+}
+
+/* Find a suitable symbol table index which can serve as the upper
+ bound of a psymtab that starts at INDEX
+
+ This scans backwards in the psymtab symbol index table to find a
+ "hole" in which the given index can fit. This is a heuristic!!
+ We don't search the entire table to check for multiple holes,
+ we don't care about overlaps, etc.
+
+ Return 0 => not found */
+static int
+find_next_pst_start (int index)
+{
+ int i;
+
+ for (i = pst_syms_count - 1; i >= 0; i--)
+ if (pst_syms_array[i].end <= index)
+ return (i == pst_syms_count - 1) ? 0 : pst_syms_array[i + 1].start - 1;
+
+ if (pst_syms_array[0].start > index)
+ return pst_syms_array[0].start - 1;
+
+ return 0;
+}
+
+
+
+/* Utility functions to find the ending symbol index for a psymtab */
+
+/* Find the next file entry that begins beyond INDEX, and return
+ its starting symbol index - 1.
+ QFD is the file table, CURR_FD is the file entry from where to start,
+ PXDB_HEADER_P as in hpread_quick_traverse (to allow macros to work).
+
+ Return 0 => not found */
+static int
+find_next_file_isym (int index, quick_file_entry *qFD, int curr_fd,
+ PXDB_header_ptr pxdb_header_p)
+{
+ while (VALID_CURR_FILE)
+ {
+ if (CURR_FILE_ISYM >= index)
+ return CURR_FILE_ISYM - 1;
+ curr_fd++;
+ }
+ return 0;
+}
+
+/* Find the next procedure entry that begins beyond INDEX, and return
+ its starting symbol index - 1.
+ QPD is the procedure table, CURR_PD is the proc entry from where to start,
+ PXDB_HEADER_P as in hpread_quick_traverse (to allow macros to work).
+
+ Return 0 => not found */
+static int
+find_next_proc_isym (int index, quick_procedure_entry *qPD, int curr_pd,
+ PXDB_header_ptr pxdb_header_p)
+{
+ while (VALID_CURR_PROC)
+ {
+ if (CURR_PROC_ISYM >= index)
+ return CURR_PROC_ISYM - 1;
+ curr_pd++;
+ }
+ return 0;
+}
+
+/* Find the next module entry that begins beyond INDEX, and return
+ its starting symbol index - 1.
+ QMD is the module table, CURR_MD is the modue entry from where to start,
+ PXDB_HEADER_P as in hpread_quick_traverse (to allow macros to work).
+
+ Return 0 => not found */
+static int
+find_next_module_isym (int index, quick_module_entry *qMD, int curr_md,
+ PXDB_header_ptr pxdb_header_p)
+{
+ while (VALID_CURR_MODULE)
+ {
+ if (CURR_MODULE_ISYM >= index)
+ return CURR_MODULE_ISYM - 1;
+ curr_md++;
+ }
+ return 0;
+}
+
+/* Scan and record partial symbols for all functions starting from index
+ pointed to by CURR_PD_P, and between code addresses START_ADR and END_ADR.
+ Other parameters are explained in comments below. */
+
+/* This used to be inline in hpread_quick_traverse, but now that we do
+ essentially the same thing for two different cases (modules and
+ module-less files), it's better organized in a separate routine,
+ although it does take lots of arguments. pai/1997-10-08
+
+ CURR_PD_P is the pointer to the current proc index. QPD is the
+ procedure quick lookup table. MAX_PROCS is the number of entries
+ in the proc. table. START_ADR is the beginning of the code range
+ for the current psymtab. end_adr is the end of the code range for
+ the current psymtab. PST is the current psymtab. VT_bits is
+ a pointer to the strings table of SOM debug space. OBJFILE is
+ the current object file. */
+
+static int
+scan_procs (int *curr_pd_p, quick_procedure_entry *qPD, int max_procs,
+ CORE_ADDR start_adr, CORE_ADDR end_adr, struct partial_symtab *pst,
+ char *vt_bits, struct objfile *objfile)
+{
+ union dnttentry *dn_bufp;
+ int symbol_count = 0; /* Total number of symbols in this psymtab */
+ int curr_pd = *curr_pd_p; /* Convenience variable -- avoid dereferencing pointer all the time */
+
+#ifdef DUMPING
+ /* Turn this on for lots of debugging information in this routine */
+ static int dumping = 0;
+#endif
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("Scan_procs called, addresses %x to %x, proc %x\n", start_adr, end_adr, curr_pd);
+ }
+#endif
+
+ while ((CURR_PROC_START <= end_adr) && (curr_pd < max_procs))
+ {
+
+ char *rtn_name; /* mangled name */
+ char *rtn_dem_name; /* qualified demangled name */
+ char *class_name;
+ int class;
+
+ if ((trans_lang ((enum hp_language) qPD[curr_pd].language) == language_cplus) &&
+ vt_bits[(long) qPD[curr_pd].sbAlias]) /* not a null string */
+ {
+ /* Get mangled name for the procedure, and demangle it */
+ rtn_name = &vt_bits[(long) qPD[curr_pd].sbAlias];
+ rtn_dem_name = cplus_demangle (rtn_name, DMGL_ANSI | DMGL_PARAMS);
+ }
+ else
+ {
+ rtn_name = &vt_bits[(long) qPD[curr_pd].sbProc];
+ rtn_dem_name = NULL;
+ }
+
+ /* Hack to get around HP C/C++ compilers' insistence on providing
+ "_MAIN_" as an alternate name for "main" */
+ if ((strcmp (rtn_name, "_MAIN_") == 0) &&
+ (strcmp (&vt_bits[(long) qPD[curr_pd].sbProc], "main") == 0))
+ rtn_dem_name = rtn_name = main_string;
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("..add %s (demangled %s), index %x to this psymtab\n", rtn_name, rtn_dem_name, curr_pd);
+ }
+#endif
+
+ /* Check for module-spanning routines. */
+ if (CURR_PROC_END > end_adr)
+ {
+ TELL_OBJFILE;
+ warning ("Procedure \"%s\" [0x%x] spans file or module boundaries.", rtn_name, curr_pd);
+ }
+
+ /* Add this routine symbol to the list in the objfile.
+ Unfortunately we have to go to the LNTT to determine the
+ correct list to put it on. An alternative (which the
+ code used to do) would be to not check and always throw
+ it on the "static" list. But if we go that route, then
+ symbol_lookup() needs to be tweaked a bit to account
+ for the fact that the function might not be found on
+ the correct list in the psymtab. - RT */
+ dn_bufp = hpread_get_lntt (qPD[curr_pd].isym, objfile);
+ if (dn_bufp->dfunc.global)
+ add_psymbol_with_dem_name_to_list (rtn_name,
+ strlen (rtn_name),
+ rtn_dem_name,
+ strlen (rtn_dem_name),
+ VAR_DOMAIN,
+ LOC_BLOCK, /* "I am a routine" */
+ &objfile->global_psymbols,
+ (qPD[curr_pd].adrStart + /* Starting address of rtn */
+ ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile))),
+ 0, /* core addr?? */
+ trans_lang ((enum hp_language) qPD[curr_pd].language),
+ objfile);
+ else
+ add_psymbol_with_dem_name_to_list (rtn_name,
+ strlen (rtn_name),
+ rtn_dem_name,
+ strlen (rtn_dem_name),
+ VAR_DOMAIN,
+ LOC_BLOCK, /* "I am a routine" */
+ &objfile->static_psymbols,
+ (qPD[curr_pd].adrStart + /* Starting address of rtn */
+ ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile))),
+ 0, /* core addr?? */
+ trans_lang ((enum hp_language) qPD[curr_pd].language),
+ objfile);
+
+ symbol_count++;
+ *curr_pd_p = ++curr_pd; /* bump up count & reflect in caller */
+ } /* loop over procedures */
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ if (symbol_count == 0)
+ printf ("Scan_procs: no symbols found!\n");
+ }
+#endif
+
+ return symbol_count;
+}
+
+
+/* Traverse the quick look-up tables, building a set of psymtabs.
+
+ This constructs a psymtab for modules and files in the quick lookup
+ tables.
+
+ Mostly, modules correspond to compilation units, so we try to
+ create psymtabs that correspond to modules; however, in some cases
+ a file can result in a compiled object which does not have a module
+ entry for it, so in such cases we create a psymtab for the file. */
+
+static int
+hpread_quick_traverse (struct objfile *objfile, char *gntt_bits,
+ char *vt_bits, PXDB_header_ptr pxdb_header_p)
+{
+ struct partial_symtab *pst;
+
+ char *addr;
+
+ quick_procedure_entry *qPD;
+ quick_file_entry *qFD;
+ quick_module_entry *qMD;
+ quick_class_entry *qCD;
+
+ int idx;
+ int i;
+ CORE_ADDR start_adr; /* current psymtab's starting code addr */
+ CORE_ADDR end_adr; /* current psymtab's ending code addr */
+ CORE_ADDR next_mod_adr; /* next module's starting code addr */
+ int curr_pd; /* current procedure */
+ int curr_fd; /* current file */
+ int curr_md; /* current module */
+ int start_sym; /* current psymtab's starting symbol index */
+ int end_sym; /* current psymtab's ending symbol index */
+ int max_LNTT_sym_index;
+ int syms_in_pst;
+ B_TYPE *class_entered;
+
+ struct partial_symbol **global_syms; /* We'll be filling in the "global" */
+ struct partial_symbol **static_syms; /* and "static" tables in the objfile
+ as we go, so we need a pair of
+ current pointers. */
+
+#ifdef DUMPING
+ /* Turn this on for lots of debugging information in this routine.
+ You get a blow-by-blow account of quick lookup table reading */
+ static int dumping = 0;
+#endif
+
+ pst = (struct partial_symtab *) 0;
+
+ /* Clear out some globals */
+ init_pst_syms ();
+ told_objfile = 0;
+
+ /* Demangling style -- if EDG style already set, don't change it,
+ as HP style causes some problems with the KAI EDG compiler */
+ if (current_demangling_style != edg_demangling)
+ {
+ /* Otherwise, ensure that we are using HP style demangling */
+ set_demangling_style (HP_DEMANGLING_STYLE_STRING);
+ }
+
+ /* First we need to find the starting points of the quick
+ look-up tables in the GNTT. */
+
+ addr = gntt_bits;
+
+ qPD = (quick_procedure_entry_ptr) addr;
+ addr += pxdb_header_p->pd_entries * sizeof (quick_procedure_entry);
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("\n Printing routines as we see them\n");
+ for (i = 0; VALID_PROC (i); i++)
+ {
+ idx = (long) qPD[i].sbProc;
+ printf ("%s %x..%x\n", &vt_bits[idx],
+ (int) PROC_START (i),
+ (int) PROC_END (i));
+ }
+ }
+#endif
+
+ qFD = (quick_file_entry_ptr) addr;
+ addr += pxdb_header_p->fd_entries * sizeof (quick_file_entry);
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("\n Printing files as we see them\n");
+ for (i = 0; VALID_FILE (i); i++)
+ {
+ idx = (long) qFD[i].sbFile;
+ printf ("%s %x..%x\n", &vt_bits[idx],
+ (int) FILE_START (i),
+ (int) FILE_END (i));
+ }
+ }
+#endif
+
+ qMD = (quick_module_entry_ptr) addr;
+ addr += pxdb_header_p->md_entries * sizeof (quick_module_entry);
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("\n Printing modules as we see them\n");
+ for (i = 0; i < pxdb_header_p->md_entries; i++)
+ {
+ idx = (long) qMD[i].sbMod;
+ printf ("%s\n", &vt_bits[idx]);
+ }
+ }
+#endif
+
+ qCD = (quick_class_entry_ptr) addr;
+ addr += pxdb_header_p->cd_entries * sizeof (quick_class_entry);
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("\n Printing classes as we see them\n");
+ for (i = 0; VALID_CLASS (i); i++)
+ {
+ idx = (long) qCD[i].sbClass;
+ printf ("%s\n", &vt_bits[idx]);
+ }
+
+ printf ("\n Done with dump, on to build!\n");
+ }
+#endif
+
+ /* We need this index only while hp-symtab-read.c expects
+ a byte offset to the end of the LNTT entries for a given
+ psymtab. Thus the need for it should go away someday.
+
+ When it goes away, then we won't have any need to load the
+ LNTT from the objfile at psymtab-time, and start-up will be
+ faster. To make that work, we'll need some way to create
+ a null pst for the "globals" pseudo-module. */
+ max_LNTT_sym_index = LNTT_SYMCOUNT (objfile);
+
+ /* Scan the module descriptors and make a psymtab for each.
+
+ We know the MDs, FDs and the PDs are in order by starting
+ address. We use that fact to traverse all three arrays in
+ parallel, knowing when the next PD is in a new file
+ and we need to create a new psymtab. */
+ curr_pd = 0; /* Current procedure entry */
+ curr_fd = 0; /* Current file entry */
+ curr_md = 0; /* Current module entry */
+
+ start_adr = 0; /* Current psymtab code range */
+ end_adr = 0;
+
+ start_sym = 0; /* Current psymtab symbol range */
+ end_sym = 0;
+
+ syms_in_pst = 0; /* Symbol count for psymtab */
+
+ /* Psts actually just have pointers into the objfile's
+ symbol table, not their own symbol tables. */
+ global_syms = objfile->global_psymbols.list;
+ static_syms = objfile->static_psymbols.list;
+
+
+ /* First skip over pseudo-entries with address 0. These represent inlined
+ routines and abstract (uninstantiated) template routines.
+ FIXME: These should be read in and available -- even if we can't set
+ breakpoints, etc., there's some information that can be presented
+ to the user. pai/1997-10-08 */
+
+ while (VALID_CURR_PROC && (CURR_PROC_START == 0))
+ curr_pd++;
+
+ /* Loop over files, modules, and procedures in code address order. Each
+ time we enter an iteration of this loop, curr_pd points to the first
+ unprocessed procedure, curr_fd points to the first unprocessed file, and
+ curr_md to the first unprocessed module. Each iteration of this loop
+ updates these as required -- any or all of them may be bumpd up
+ each time around. When we exit this loop, we are done with all files
+ and modules in the tables -- there may still be some procedures, however.
+
+ Note: This code used to loop only over module entries, under the assumption
+ that files can occur via inclusions and are thus unreliable, while a
+ compiled object always corresponds to a module. With CTTI in the HP aCC
+ compiler, it turns out that compiled objects may have only files and no
+ modules; so we have to loop over files and modules, creating psymtabs for
+ either as appropriate. Unfortunately there are some problems (notably:
+ 1. the lack of "SRC_FILE_END" entries in the LNTT, 2. the lack of pointers
+ to the ending symbol indices of a module or a file) which make it quite hard
+ to do this correctly. Currently it uses a bunch of heuristics to start and
+ end psymtabs; they seem to work well with most objects generated by aCC, but
+ who knows when that will change... */
+
+ while (VALID_CURR_FILE || VALID_CURR_MODULE)
+ {
+
+ char *mod_name_string = NULL;
+ char *full_name_string;
+
+ /* First check for modules like "version.c", which have no code
+ in them but still have qMD entries. They also have no qFD or
+ qPD entries. Their start address is -1 and their end address
+ is 0. */
+ if (VALID_CURR_MODULE && (CURR_MODULE_START == -1) && (CURR_MODULE_END == 0))
+ {
+
+ mod_name_string = &vt_bits[(long) qMD[curr_md].sbMod];
+
+#ifdef DUMPING
+ if (dumping)
+ printf ("Module with data only %s\n", mod_name_string);
+#endif
+
+ /* We'll skip the rest (it makes error-checking easier), and
+ just make an empty pst. Right now empty psts are not put
+ in the pst chain, so all this is for naught, but later it
+ might help. */
+
+ pst = hpread_start_psymtab (objfile,
+ mod_name_string,
+ CURR_MODULE_START, /* Low text address: bogus! */
+ (CURR_MODULE_ISYM * sizeof (struct dntt_type_block)),
+ /* ldsymoff */
+ global_syms,
+ static_syms);
+
+ pst = hpread_end_psymtab (pst,
+ NULL, /* psymtab_include_list */
+ 0, /* includes_used */
+ end_sym * sizeof (struct dntt_type_block),
+ /* byte index in LNTT of end
+ = capping symbol offset
+ = LDSYMOFF of nextfile */
+ 0, /* text high */
+ NULL, /* dependency_list */
+ 0); /* dependencies_used */
+
+ global_syms = objfile->global_psymbols.next;
+ static_syms = objfile->static_psymbols.next;
+
+ curr_md++;
+ }
+ else if (VALID_CURR_MODULE &&
+ ((CURR_MODULE_START == 0) || (CURR_MODULE_START == -1) ||
+ (CURR_MODULE_END == 0) || (CURR_MODULE_END == -1)))
+ {
+ TELL_OBJFILE;
+ warning ("Module \"%s\" [0x%s] has non-standard addresses. It starts at 0x%s, ends at 0x%s, and will be skipped.",
+ mod_name_string, paddr_nz (curr_md), paddr_nz (start_adr), paddr_nz (end_adr));
+ /* On to next module */
+ curr_md++;
+ }
+ else
+ {
+ /* First check if we are looking at a file with code in it
+ that does not overlap the current module's code range */
+
+ if (VALID_CURR_FILE ? (VALID_CURR_MODULE ? (CURR_FILE_END < CURR_MODULE_START) : 1) : 0)
+ {
+
+ /* Looking at file not corresponding to any module,
+ create a psymtab for it */
+ full_name_string = &vt_bits[(long) qFD[curr_fd].sbFile];
+ start_adr = CURR_FILE_START;
+ end_adr = CURR_FILE_END;
+ start_sym = CURR_FILE_ISYM;
+
+ /* Check if there are any procedures not handled until now, that
+ begin before the start address of this file, and if so, adjust
+ this module's start address to include them. This handles routines that
+ are in between file or module ranges for some reason (probably
+ indicates a compiler bug */
+
+ if (CURR_PROC_START < start_adr)
+ {
+ TELL_OBJFILE;
+ warning ("Found procedure \"%s\" [0x%x] that is not in any file or module.",
+ &vt_bits[(long) qPD[curr_pd].sbProc], curr_pd);
+ start_adr = CURR_PROC_START;
+ if (CURR_PROC_ISYM < start_sym)
+ start_sym = CURR_PROC_ISYM;
+ }
+
+ /* Sometimes (compiler bug -- COBOL) the module end address is higher
+ than the start address of the next module, so check for that and
+ adjust accordingly */
+
+ if (VALID_FILE (curr_fd + 1) && (FILE_START (curr_fd + 1) <= end_adr))
+ {
+ TELL_OBJFILE;
+ warning ("File \"%s\" [0x%x] has ending address after starting address of next file; adjusting ending address down.",
+ full_name_string, curr_fd);
+ end_adr = FILE_START (curr_fd + 1) - 1; /* Is -4 (or -8 for 64-bit) better? */
+ }
+ if (VALID_MODULE (curr_md) && (CURR_MODULE_START <= end_adr))
+ {
+ TELL_OBJFILE;
+ warning ("File \"%s\" [0x%x] has ending address after starting address of next module; adjusting ending address down.",
+ full_name_string, curr_fd);
+ end_adr = CURR_MODULE_START - 1; /* Is -4 (or -8 for 64-bit) better? */
+ }
+
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("Make new psymtab for file %s (%x to %x).\n",
+ full_name_string, start_adr, end_adr);
+ }
+#endif
+ /* Create the basic psymtab, connecting it in the list
+ for this objfile and pointing its symbol entries
+ to the current end of the symbol areas in the objfile.
+
+ The "ldsymoff" parameter is the byte offset in the LNTT
+ of the first symbol in this file. Some day we should
+ turn this into an index (fix in hp-symtab-read.c as well).
+ And it's not even the right byte offset, as we're using
+ the size of a union! FIXME! */
+ pst = hpread_start_psymtab (objfile,
+ full_name_string,
+ start_adr, /* Low text address */
+ (start_sym * sizeof (struct dntt_type_block)),
+ /* ldsymoff */
+ global_syms,
+ static_syms);
+
+ /* Set up to only enter each class referenced in this module once. */
+ class_entered = xmalloc (B_BYTES (pxdb_header_p->cd_entries));
+ B_CLRALL (class_entered, pxdb_header_p->cd_entries);
+
+ /* Scan the procedure descriptors for procedures in the current
+ file, based on the starting addresses. */
+
+ syms_in_pst = scan_procs (&curr_pd, qPD, pxdb_header_p->pd_entries,
+ start_adr, end_adr, pst, vt_bits, objfile);
+
+ /* Get ending symbol offset */
+
+ end_sym = 0;
+ /* First check for starting index before previous psymtab */
+ if (pst_syms_count && start_sym < pst_syms_array[pst_syms_count - 1].end)
+ {
+ end_sym = find_next_pst_start (start_sym);
+ }
+ /* Look for next start index of a file or module, or procedure */
+ if (!end_sym)
+ {
+ int next_file_isym = find_next_file_isym (start_sym, qFD, curr_fd + 1, pxdb_header_p);
+ int next_module_isym = find_next_module_isym (start_sym, qMD, curr_md, pxdb_header_p);
+ int next_proc_isym = find_next_proc_isym (start_sym, qPD, curr_pd, pxdb_header_p);
+
+ if (next_file_isym && next_module_isym)
+ {
+ /* pick lower of next file or module start index */
+ end_sym = min (next_file_isym, next_module_isym);
+ }
+ else
+ {
+ /* one of them is zero, pick the other */
+ end_sym = max (next_file_isym, next_module_isym);
+ }
+
+ /* As a precaution, check next procedure index too */
+ if (!end_sym)
+ end_sym = next_proc_isym;
+ else
+ end_sym = min (end_sym, next_proc_isym);
+ }
+
+ /* Couldn't find procedure, file, or module, use globals as default */
+ if (!end_sym)
+ end_sym = pxdb_header_p->globals;
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("File psymtab indices: %x to %x\n", start_sym, end_sym);
+ }
+#endif
+
+ pst = hpread_end_psymtab (pst,
+ NULL, /* psymtab_include_list */
+ 0, /* includes_used */
+ end_sym * sizeof (struct dntt_type_block),
+ /* byte index in LNTT of end
+ = capping symbol offset
+ = LDSYMOFF of nextfile */
+ end_adr, /* text high */
+ NULL, /* dependency_list */
+ 0); /* dependencies_used */
+
+ record_pst_syms (start_sym, end_sym);
+
+ if (NULL == pst)
+ warning ("No symbols in psymtab for file \"%s\" [0x%x].", full_name_string, curr_fd);
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("Made new psymtab for file %s (%x to %x), sym %x to %x.\n",
+ full_name_string, start_adr, end_adr, CURR_FILE_ISYM, end_sym);
+ }
+#endif
+ /* Prepare for the next psymtab. */
+ global_syms = objfile->global_psymbols.next;
+ static_syms = objfile->static_psymbols.next;
+ xfree (class_entered);
+
+ curr_fd++;
+ } /* Psymtab for file */
+ else
+ {
+ /* We have a module for which we create a psymtab */
+
+ mod_name_string = &vt_bits[(long) qMD[curr_md].sbMod];
+
+ /* We will include the code ranges of any files that happen to
+ overlap with this module */
+
+ /* So, first pick the lower of the file's and module's start addresses */
+ start_adr = CURR_MODULE_START;
+ if (VALID_CURR_FILE)
+ {
+ if (CURR_FILE_START < CURR_MODULE_START)
+ {
+ TELL_OBJFILE;
+ warning ("File \"%s\" [0x%x] crosses beginning of module \"%s\".",
+ &vt_bits[(long) qFD[curr_fd].sbFile],
+ curr_fd, mod_name_string);
+
+ start_adr = CURR_FILE_START;
+ }
+ }
+
+ /* Also pick the lower of the file's and the module's start symbol indices */
+ start_sym = CURR_MODULE_ISYM;
+ if (VALID_CURR_FILE && (CURR_FILE_ISYM < CURR_MODULE_ISYM))
+ start_sym = CURR_FILE_ISYM;
+
+ /* For the end address, we scan through the files till we find one
+ that overlaps the current module but ends beyond it; if no such file exists we
+ simply use the module's start address.
+ (Note, if file entries themselves overlap
+ we take the longest overlapping extension beyond the end of the module...)
+ We assume that modules never overlap. */
+
+ end_adr = CURR_MODULE_END;
+
+ if (VALID_CURR_FILE)
+ {
+ while (VALID_CURR_FILE && (CURR_FILE_START < end_adr))
+ {
+
+#ifdef DUMPING
+ if (dumping)
+ printf ("Maybe skipping file %s which overlaps with module %s\n",
+ &vt_bits[(long) qFD[curr_fd].sbFile], mod_name_string);
+#endif
+ if (CURR_FILE_END > end_adr)
+ {
+ TELL_OBJFILE;
+ warning ("File \"%s\" [0x%x] crosses end of module \"%s\".",
+ &vt_bits[(long) qFD[curr_fd].sbFile],
+ curr_fd, mod_name_string);
+ end_adr = CURR_FILE_END;
+ }
+ curr_fd++;
+ }
+ curr_fd--; /* back up after going too far */
+ }
+
+ /* Sometimes (compiler bug -- COBOL) the module end address is higher
+ than the start address of the next module, so check for that and
+ adjust accordingly */
+
+ if (VALID_MODULE (curr_md + 1) && (MODULE_START (curr_md + 1) <= end_adr))
+ {
+ TELL_OBJFILE;
+ warning ("Module \"%s\" [0x%x] has ending address after starting address of next module; adjusting ending address down.",
+ mod_name_string, curr_md);
+ end_adr = MODULE_START (curr_md + 1) - 1; /* Is -4 (or -8 for 64-bit) better? */
+ }
+ if (VALID_FILE (curr_fd + 1) && (FILE_START (curr_fd + 1) <= end_adr))
+ {
+ TELL_OBJFILE;
+ warning ("Module \"%s\" [0x%x] has ending address after starting address of next file; adjusting ending address down.",
+ mod_name_string, curr_md);
+ end_adr = FILE_START (curr_fd + 1) - 1; /* Is -4 (or -8 for 64-bit) better? */
+ }
+
+ /* Use one file to get the full name for the module. This
+ situation can arise if there is executable code in a #include
+ file. Each file with code in it gets a qFD. Files which don't
+ contribute code don't get a qFD, even if they include files
+ which do, e.g.:
+
+ body.c: rtn.h:
+ int x; int main() {
+ #include "rtn.h" return x;
+ }
+
+ There will a qFD for "rtn.h",and a qMD for "body.c",
+ but no qMD for "rtn.h" or qFD for "body.c"!
+
+ We pick the name of the last file to overlap with this
+ module. C convention is to put include files first. In a
+ perfect world, we could check names and use the file whose full
+ path name ends with the module name. */
+
+ if (VALID_CURR_FILE)
+ full_name_string = &vt_bits[(long) qFD[curr_fd].sbFile];
+ else
+ full_name_string = mod_name_string;
+
+ /* Check if there are any procedures not handled until now, that
+ begin before the start address we have now, and if so, adjust
+ this psymtab's start address to include them. This handles routines that
+ are in between file or module ranges for some reason (probably
+ indicates a compiler bug */
+
+ if (CURR_PROC_START < start_adr)
+ {
+ TELL_OBJFILE;
+ warning ("Found procedure \"%s\" [0x%x] that is not in any file or module.",
+ &vt_bits[(long) qPD[curr_pd].sbProc], curr_pd);
+ start_adr = CURR_PROC_START;
+ if (CURR_PROC_ISYM < start_sym)
+ start_sym = CURR_PROC_ISYM;
+ }
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("Make new psymtab for module %s (%x to %x), using file %s\n",
+ mod_name_string, start_adr, end_adr, full_name_string);
+ }
+#endif
+ /* Create the basic psymtab, connecting it in the list
+ for this objfile and pointing its symbol entries
+ to the current end of the symbol areas in the objfile.
+
+ The "ldsymoff" parameter is the byte offset in the LNTT
+ of the first symbol in this file. Some day we should
+ turn this into an index (fix in hp-symtab-read.c as well).
+ And it's not even the right byte offset, as we're using
+ the size of a union! FIXME! */
+ pst = hpread_start_psymtab (objfile,
+ full_name_string,
+ start_adr, /* Low text address */
+ (start_sym * sizeof (struct dntt_type_block)),
+ /* ldsymoff */
+ global_syms,
+ static_syms);
+
+ /* Set up to only enter each class referenced in this module once. */
+ class_entered = xmalloc (B_BYTES (pxdb_header_p->cd_entries));
+ B_CLRALL (class_entered, pxdb_header_p->cd_entries);
+
+ /* Scan the procedure descriptors for procedures in the current
+ module, based on the starting addresses. */
+
+ syms_in_pst = scan_procs (&curr_pd, qPD, pxdb_header_p->pd_entries,
+ start_adr, end_adr, pst, vt_bits, objfile);
+
+ /* Get ending symbol offset */
+
+ end_sym = 0;
+ /* First check for starting index before previous psymtab */
+ if (pst_syms_count && start_sym < pst_syms_array[pst_syms_count - 1].end)
+ {
+ end_sym = find_next_pst_start (start_sym);
+ }
+ /* Look for next start index of a file or module, or procedure */
+ if (!end_sym)
+ {
+ int next_file_isym = find_next_file_isym (start_sym, qFD, curr_fd + 1, pxdb_header_p);
+ int next_module_isym = find_next_module_isym (start_sym, qMD, curr_md + 1, pxdb_header_p);
+ int next_proc_isym = find_next_proc_isym (start_sym, qPD, curr_pd, pxdb_header_p);
+
+ if (next_file_isym && next_module_isym)
+ {
+ /* pick lower of next file or module start index */
+ end_sym = min (next_file_isym, next_module_isym);
+ }
+ else
+ {
+ /* one of them is zero, pick the other */
+ end_sym = max (next_file_isym, next_module_isym);
+ }
+
+ /* As a precaution, check next procedure index too */
+ if (!end_sym)
+ end_sym = next_proc_isym;
+ else
+ end_sym = min (end_sym, next_proc_isym);
+ }
+
+ /* Couldn't find procedure, file, or module, use globals as default */
+ if (!end_sym)
+ end_sym = pxdb_header_p->globals;
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("Module psymtab indices: %x to %x\n", start_sym, end_sym);
+ }
+#endif
+
+ pst = hpread_end_psymtab (pst,
+ NULL, /* psymtab_include_list */
+ 0, /* includes_used */
+ end_sym * sizeof (struct dntt_type_block),
+ /* byte index in LNTT of end
+ = capping symbol offset
+ = LDSYMOFF of nextfile */
+ end_adr, /* text high */
+ NULL, /* dependency_list */
+ 0); /* dependencies_used */
+
+ record_pst_syms (start_sym, end_sym);
+
+ if (NULL == pst)
+ warning ("No symbols in psymtab for module \"%s\" [0x%x].", mod_name_string, curr_md);
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("Made new psymtab for module %s (%x to %x), sym %x to %x.\n",
+ mod_name_string, start_adr, end_adr, CURR_MODULE_ISYM, end_sym);
+ }
+#endif
+
+ /* Prepare for the next psymtab. */
+ global_syms = objfile->global_psymbols.next;
+ static_syms = objfile->static_psymbols.next;
+ xfree (class_entered);
+
+ curr_md++;
+ curr_fd++;
+ } /* psymtab for module */
+ } /* psymtab for non-bogus file or module */
+ } /* End of while loop over all files & modules */
+
+ /* There may be some routines after all files and modules -- these will get
+ inserted in a separate new module of their own */
+ if (VALID_CURR_PROC)
+ {
+ start_adr = CURR_PROC_START;
+ end_adr = qPD[pxdb_header_p->pd_entries - 1].adrEnd;
+ TELL_OBJFILE;
+ warning ("Found functions beyond end of all files and modules [0x%x].", curr_pd);
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("Orphan functions at end, PD %d and beyond (%x to %x)\n",
+ curr_pd, start_adr, end_adr);
+ }
+#endif
+ pst = hpread_start_psymtab (objfile,
+ "orphans",
+ start_adr, /* Low text address */
+ (CURR_PROC_ISYM * sizeof (struct dntt_type_block)),
+ /* ldsymoff */
+ global_syms,
+ static_syms);
+
+ scan_procs (&curr_pd, qPD, pxdb_header_p->pd_entries,
+ start_adr, end_adr, pst, vt_bits, objfile);
+
+ pst = hpread_end_psymtab (pst,
+ NULL, /* psymtab_include_list */
+ 0, /* includes_used */
+ pxdb_header_p->globals * sizeof (struct dntt_type_block),
+ /* byte index in LNTT of end
+ = capping symbol offset
+ = LDSYMOFF of nextfile */
+ end_adr, /* text high */
+ NULL, /* dependency_list */
+ 0); /* dependencies_used */
+ }
+
+
+#ifdef NEVER_NEVER
+ /* Now build psts for non-module things (in the tail of
+ the LNTT, after the last END MODULE entry).
+
+ If null psts were kept on the chain, this would be
+ a solution. FIXME */
+ pst = hpread_start_psymtab (objfile,
+ "globals",
+ 0,
+ (pxdb_header_p->globals
+ * sizeof (struct dntt_type_block)),
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ hpread_end_psymtab (pst,
+ NULL, 0,
+ (max_LNTT_sym_index * sizeof (struct dntt_type_block)),
+ 0,
+ NULL, 0);
+#endif
+
+ clear_pst_syms ();
+
+ return 1;
+
+} /* End of hpread_quick_traverse. */
+
+
+/* Get appropriate header, based on pxdb type.
+ Return value: 1 if ok, 0 if not */
+static int
+hpread_get_header (struct objfile *objfile, PXDB_header_ptr pxdb_header_p)
+{
+ asection *pinfo_section, *debug_section, *header_section;
+
+#ifdef DUMPING
+ /* Turn on for debugging information */
+ static int dumping = 0;
+#endif
+
+ header_section = bfd_get_section_by_name (objfile->obfd, "$HEADER$");
+ if (!header_section)
+ {
+ /* We don't have either PINFO or DEBUG sections. But
+ stuff like "libc.sl" has no debug info. There's no
+ need to warn the user of this, as it may be ok. The
+ caller will figure it out and issue any needed
+ messages. */
+#ifdef DUMPING
+ if (dumping)
+ printf ("==No debug info at all for %s.\n", objfile->name);
+#endif
+
+ return 0;
+ }
+
+ /* We would like either a $DEBUG$ or $PINFO$ section.
+ Once we know which, we can understand the header
+ data (which we have defined to suit the more common
+ $DEBUG$ case). */
+ debug_section = bfd_get_section_by_name (objfile->obfd, "$DEBUG$");
+ pinfo_section = bfd_get_section_by_name (objfile->obfd, "$PINFO$");
+ if (debug_section)
+ {
+ /* The expected case: normal pxdb header. */
+ bfd_get_section_contents (objfile->obfd, header_section,
+ pxdb_header_p, 0, sizeof (PXDB_header));
+
+ if (!pxdb_header_p->pxdbed)
+ {
+ /* This shouldn't happen if we check in "symfile.c". */
+ return 0;
+ } /* DEBUG section */
+ }
+
+ else if (pinfo_section)
+ {
+ /* The DOC case; we need to translate this into a
+ regular header. */
+ DOC_info_PXDB_header doc_header;
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("==OOps, PINFO, let's try to handle this, %s.\n", objfile->name);
+ }
+#endif
+
+ bfd_get_section_contents (objfile->obfd,
+ header_section,
+ &doc_header, 0,
+ sizeof (DOC_info_PXDB_header));
+
+ if (!doc_header.pxdbed)
+ {
+ /* This shouldn't happen if we check in "symfile.c". */
+ warning ("File \"%s\" not processed by pxdb!", objfile->name);
+ return 0;
+ }
+
+ /* Copy relevent fields to standard header passed in. */
+ pxdb_header_p->pd_entries = doc_header.pd_entries;
+ pxdb_header_p->fd_entries = doc_header.fd_entries;
+ pxdb_header_p->md_entries = doc_header.md_entries;
+ pxdb_header_p->pxdbed = doc_header.pxdbed;
+ pxdb_header_p->bighdr = doc_header.bighdr;
+ pxdb_header_p->sa_header = doc_header.sa_header;
+ pxdb_header_p->inlined = doc_header.inlined;
+ pxdb_header_p->globals = doc_header.globals;
+ pxdb_header_p->time = doc_header.time;
+ pxdb_header_p->pg_entries = doc_header.pg_entries;
+ pxdb_header_p->functions = doc_header.functions;
+ pxdb_header_p->files = doc_header.files;
+ pxdb_header_p->cd_entries = doc_header.cd_entries;
+ pxdb_header_p->aa_entries = doc_header.aa_entries;
+ pxdb_header_p->oi_entries = doc_header.oi_entries;
+ pxdb_header_p->version = doc_header.version;
+ } /* PINFO section */
+
+ else
+ {
+#ifdef DUMPING
+ if (dumping)
+ printf ("==No debug info at all for %s.\n", objfile->name);
+#endif
+
+ return 0;
+
+ }
+
+ return 1;
+} /* End of hpread_get_header */
+#endif /* QUICK_LOOK_UP */
+
+
+/* Initialization for reading native HP C debug symbols from OBJFILE.
+
+ Its only purpose in life is to set up the symbol reader's private
+ per-objfile data structures, and read in the raw contents of the debug
+ sections (attaching pointers to the debug info into the private data
+ structures).
+
+ 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. Note we may
+ be called on a file without native HP C debugging symbols.
+
+ FIXME, there should be a cleaner peephole into the BFD environment
+ here. */
+void
+hpread_symfile_init (struct objfile *objfile)
+{
+ asection *vt_section, *slt_section, *lntt_section, *gntt_section;
+
+ /* Allocate struct to keep track of the symfile */
+ objfile->sym_private =
+ xmmalloc (objfile->md, sizeof (struct hpread_symfile_info));
+ memset (objfile->sym_private, 0, sizeof (struct hpread_symfile_info));
+
+ /* We haven't read in any types yet. */
+ DNTT_TYPE_VECTOR (objfile) = 0;
+
+ /* Read in data from the $GNTT$ subspace. */
+ gntt_section = bfd_get_section_by_name (objfile->obfd, "$GNTT$");
+ if (!gntt_section)
+ return;
+
+ GNTT (objfile)
+ = obstack_alloc (&objfile->objfile_obstack,
+ bfd_section_size (objfile->obfd, gntt_section));
+
+ bfd_get_section_contents (objfile->obfd, gntt_section, GNTT (objfile),
+ 0, bfd_section_size (objfile->obfd, gntt_section));
+
+ GNTT_SYMCOUNT (objfile)
+ = bfd_section_size (objfile->obfd, gntt_section)
+ / sizeof (struct dntt_type_block);
+
+ /* Read in data from the $LNTT$ subspace. Also keep track of the number
+ of LNTT symbols.
+
+ FIXME: this could be moved into the psymtab-to-symtab expansion
+ code, and save startup time. At the moment this data is
+ still used, though. We'd need a way to tell hp-symtab-read.c
+ whether or not to load the LNTT. */
+ lntt_section = bfd_get_section_by_name (objfile->obfd, "$LNTT$");
+ if (!lntt_section)
+ return;
+
+ LNTT (objfile)
+ = obstack_alloc (&objfile->objfile_obstack,
+ bfd_section_size (objfile->obfd, lntt_section));
+
+ bfd_get_section_contents (objfile->obfd, lntt_section, LNTT (objfile),
+ 0, bfd_section_size (objfile->obfd, lntt_section));
+
+ LNTT_SYMCOUNT (objfile)
+ = bfd_section_size (objfile->obfd, lntt_section)
+ / sizeof (struct dntt_type_block);
+
+ /* Read in data from the $SLT$ subspace. $SLT$ contains information
+ on source line numbers. */
+ slt_section = bfd_get_section_by_name (objfile->obfd, "$SLT$");
+ if (!slt_section)
+ return;
+
+ SLT (objfile) =
+ obstack_alloc (&objfile->objfile_obstack,
+ bfd_section_size (objfile->obfd, slt_section));
+
+ bfd_get_section_contents (objfile->obfd, slt_section, SLT (objfile),
+ 0, bfd_section_size (objfile->obfd, slt_section));
+
+ /* Read in data from the $VT$ subspace. $VT$ contains things like
+ names and constants. Keep track of the number of symbols in the VT. */
+ vt_section = bfd_get_section_by_name (objfile->obfd, "$VT$");
+ if (!vt_section)
+ return;
+
+ VT_SIZE (objfile) = bfd_section_size (objfile->obfd, vt_section);
+
+ VT (objfile) =
+ (char *) obstack_alloc (&objfile->objfile_obstack,
+ VT_SIZE (objfile));
+
+ bfd_get_section_contents (objfile->obfd, vt_section, VT (objfile),
+ 0, VT_SIZE (objfile));
+}
+
+/* Scan and build partial symbols for a symbol file.
+
+ The minimal symbol table (either SOM or HP a.out) has already been
+ read in; all we need to do is setup partial symbols based on the
+ native debugging information.
+
+ Note that the minimal table is produced by the linker, and has
+ only global routines in it; the psymtab is based on compiler-
+ generated debug information and has non-global
+ routines in it as well as files and class information.
+
+ We assume hpread_symfile_init has been called to initialize the
+ symbol reader's private data structures.
+
+ MAINLINE is true if we are reading the main symbol table (as
+ opposed to a shared lib or dynamically loaded file). */
+
+void
+hpread_build_psymtabs (struct objfile *objfile, int mainline)
+{
+
+#ifdef DUMPING
+ /* Turn this on to get debugging output. */
+ static int dumping = 0;
+#endif
+
+ char *namestring;
+ int past_first_source_file = 0;
+ struct cleanup *old_chain;
+
+ int hp_symnum, symcount, i;
+ int scan_start = 0;
+
+ union dnttentry *dn_bufp;
+ unsigned long valu;
+ char *p;
+ int texthigh = 0;
+ int have_name = 0;
+
+ /* 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;
+
+ /* Just in case the stabs reader left turds lying around. */
+ free_pending_blocks ();
+ make_cleanup (really_free_pendings, 0);
+
+ pst = (struct partial_symtab *) 0;
+
+ /* We shouldn't use alloca, instead use malloc/free. Doing so avoids
+ a number of problems with cross compilation and creating useless holes
+ in the stack when we have to allocate new entries. FIXME. */
+
+ 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 *));
+
+ old_chain = make_cleanup_free_objfile (objfile);
+
+ last_source_file = 0;
+
+#ifdef QUICK_LOOK_UP
+ {
+ /* Begin code for new-style loading of quick look-up tables. */
+
+ /* elz: this checks whether the file has beeen processed by pxdb.
+ If not we would like to try to read the psymbols in
+ anyway, but it turns out to be not so easy. So this could
+ actually be commented out, but I leave it in, just in case
+ we decide to add support for non-pxdb-ed stuff in the future. */
+ PXDB_header pxdb_header;
+ int found_modules_in_program;
+
+ if (hpread_get_header (objfile, &pxdb_header))
+ {
+ /* Build a minimal table. No types, no global variables,
+ no include files.... */
+#ifdef DUMPING
+ if (dumping)
+ printf ("\nNew method for %s\n", objfile->name);
+#endif
+
+ /* elz: quick_traverse returns true if it found
+ some modules in the main source file, other
+ than those in end.c
+ In C and C++, all the files have MODULES entries
+ in the LNTT, and the quick table traverse is all
+ based on finding these MODULES entries. Without
+ those it cannot work.
+ It happens that F77 programs don't have MODULES
+ so the quick traverse gets confused. F90 programs
+ have modules, and the quick method still works.
+ So, if modules (other than those in end.c) are
+ not found we give up on the quick table stuff,
+ and fall back on the slower method */
+ found_modules_in_program = hpread_quick_traverse (objfile,
+ GNTT (objfile),
+ VT (objfile),
+ &pxdb_header);
+
+ discard_cleanups (old_chain);
+
+ /* Set up to scan the global section of the LNTT.
+
+ This field is not always correct: if there are
+ no globals, it will point to the last record in
+ the regular LNTT, which is usually an END MODULE.
+
+ Since it might happen that there could be a file
+ with just one global record, there's no way to
+ tell other than by looking at the record, so that's
+ done below. */
+ if (found_modules_in_program)
+ scan_start = pxdb_header.globals;
+ }
+#ifdef DUMPING
+ else
+ {
+ if (dumping)
+ printf ("\nGoing on to old method for %s\n", objfile->name);
+ }
+#endif
+ }
+#endif /* QUICK_LOOK_UP */
+
+ /* Make two passes, one over the GNTT symbols, the other for the
+ LNTT symbols.
+
+ JB comment: above isn't true--they only make one pass, over
+ the LNTT. */
+ for (i = 0; i < 1; i++)
+ {
+ int within_function = 0;
+
+ if (i)
+ symcount = GNTT_SYMCOUNT (objfile);
+ else
+ symcount = LNTT_SYMCOUNT (objfile);
+
+
+ for (hp_symnum = scan_start; hp_symnum < symcount; hp_symnum++)
+ {
+ QUIT;
+ if (i)
+ dn_bufp = hpread_get_gntt (hp_symnum, objfile);
+ else
+ dn_bufp = hpread_get_lntt (hp_symnum, objfile);
+
+ if (dn_bufp->dblock.extension)
+ continue;
+
+ /* Only handle things which are necessary for minimal symbols.
+ everything else is ignored. */
+ switch (dn_bufp->dblock.kind)
+ {
+ case DNTT_TYPE_SRCFILE:
+ {
+#ifdef QUICK_LOOK_UP
+ if (scan_start == hp_symnum
+ && symcount == hp_symnum + 1)
+ {
+ /* If there are NO globals in an executable,
+ PXDB's index to the globals will point to
+ the last record in the file, which
+ could be this record. (this happened for F77 libraries)
+ ignore it and be done! */
+ continue;
+ }
+#endif /* QUICK_LOOK_UP */
+
+ /* A source file of some kind. Note this may simply
+ be an included file. */
+ set_namestring (dn_bufp, &namestring, objfile);
+
+ /* Check if this is the source file we are already working
+ with. */
+ if (pst && !strcmp (namestring, pst->filename))
+ continue;
+
+ /* Check if this is an include file, if so check if we have
+ already seen it. Add it to the include list */
+ p = strrchr (namestring, '.');
+ if (!strcmp (p, ".h"))
+ {
+ int j, found;
+
+ found = 0;
+ for (j = 0; j < includes_used; j++)
+ if (!strcmp (namestring, psymtab_include_list[j]))
+ {
+ found = 1;
+ break;
+ }
+ if (found)
+ continue;
+
+ /* Add it to the list of includes seen so far and
+ allocate more include space if necessary. */
+ 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 (psymtab_include_list, orig,
+ includes_used * sizeof (char *));
+ }
+ continue;
+ }
+
+ if (pst)
+ {
+ if (!have_name)
+ {
+ pst->filename = (char *)
+ obstack_alloc (&pst->objfile->objfile_obstack,
+ strlen (namestring) + 1);
+ strcpy (pst->filename, namestring);
+ have_name = 1;
+ continue;
+ }
+ continue;
+ }
+
+ /* This is a bonafide new source file.
+ End the current partial symtab and start a new one. */
+
+ if (pst && past_first_source_file)
+ {
+ hpread_end_psymtab (pst, psymtab_include_list,
+ includes_used,
+ (hp_symnum
+ * sizeof (struct dntt_type_block)),
+ texthigh,
+ dependency_list, dependencies_used);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+
+ valu = hpread_get_textlow (i, hp_symnum, objfile, symcount);
+ valu += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ pst = hpread_start_psymtab (objfile,
+ namestring, valu,
+ (hp_symnum
+ * sizeof (struct dntt_type_block)),
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ texthigh = valu;
+ have_name = 1;
+ continue;
+ }
+
+ case DNTT_TYPE_MODULE:
+ /* A source file. It's still unclear to me what the
+ real difference between a DNTT_TYPE_SRCFILE and DNTT_TYPE_MODULE
+ is supposed to be. */
+
+ /* First end the previous psymtab */
+ if (pst)
+ {
+ hpread_end_psymtab (pst, psymtab_include_list, includes_used,
+ ((hp_symnum - 1)
+ * sizeof (struct dntt_type_block)),
+ texthigh,
+ dependency_list, dependencies_used);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ have_name = 0;
+ }
+
+ /* Now begin a new module and a new psymtab for it */
+ set_namestring (dn_bufp, &namestring, objfile);
+ valu = hpread_get_textlow (i, hp_symnum, objfile, symcount);
+ valu += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ if (!pst)
+ {
+ pst = hpread_start_psymtab (objfile,
+ namestring, valu,
+ (hp_symnum
+ * sizeof (struct dntt_type_block)),
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ texthigh = valu;
+ have_name = 0;
+ }
+ continue;
+
+ case DNTT_TYPE_FUNCTION:
+ case DNTT_TYPE_ENTRY:
+ /* The beginning of a function. DNTT_TYPE_ENTRY may also denote
+ a secondary entry point. */
+ valu = dn_bufp->dfunc.hiaddr + ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile));
+ if (valu > texthigh)
+ texthigh = valu;
+ valu = dn_bufp->dfunc.lowaddr +
+ ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ set_namestring (dn_bufp, &namestring, objfile);
+ if (dn_bufp->dfunc.global)
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols, valu,
+ 0, language_unknown, objfile);
+ else
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols, valu,
+ 0, language_unknown, objfile);
+ within_function = 1;
+ continue;
+
+ case DNTT_TYPE_DOC_FUNCTION:
+ valu = dn_bufp->ddocfunc.hiaddr + ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile));
+ if (valu > texthigh)
+ texthigh = valu;
+ valu = dn_bufp->ddocfunc.lowaddr +
+ ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ set_namestring (dn_bufp, &namestring, objfile);
+ if (dn_bufp->ddocfunc.global)
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols, valu,
+ 0, language_unknown, objfile);
+ else
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols, valu,
+ 0, language_unknown, objfile);
+ within_function = 1;
+ continue;
+
+ case DNTT_TYPE_BEGIN:
+ case DNTT_TYPE_END:
+ /* We don't check MODULE end here, because there can be
+ symbols beyond the module end which properly belong to the
+ current psymtab -- so we wait till the next MODULE start */
+
+
+#ifdef QUICK_LOOK_UP
+ if (scan_start == hp_symnum
+ && symcount == hp_symnum + 1)
+ {
+ /* If there are NO globals in an executable,
+ PXDB's index to the globals will point to
+ the last record in the file, which is
+ probably an END MODULE, i.e. this record.
+ ignore it and be done! */
+ continue;
+ }
+#endif /* QUICK_LOOK_UP */
+
+ /* Scope block begin/end. We only care about function
+ and file blocks right now. */
+
+ if ((dn_bufp->dend.endkind == DNTT_TYPE_FUNCTION) ||
+ (dn_bufp->dend.endkind == DNTT_TYPE_DOC_FUNCTION))
+ within_function = 0;
+ continue;
+
+ case DNTT_TYPE_SVAR:
+ case DNTT_TYPE_DVAR:
+ case DNTT_TYPE_TYPEDEF:
+ case DNTT_TYPE_TAGDEF:
+ {
+ /* Variables, typedefs an the like. */
+ enum address_class storage;
+ domain_enum domain;
+
+ /* Don't add locals to the partial symbol table. */
+ if (within_function
+ && (dn_bufp->dblock.kind == DNTT_TYPE_SVAR
+ || dn_bufp->dblock.kind == DNTT_TYPE_DVAR))
+ continue;
+
+ /* TAGDEFs go into the structure domain. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_TAGDEF)
+ domain = STRUCT_DOMAIN;
+ else
+ domain = VAR_DOMAIN;
+
+ /* What kind of "storage" does this use? */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_SVAR)
+ storage = LOC_STATIC;
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_DVAR
+ && dn_bufp->ddvar.regvar)
+ storage = LOC_REGISTER;
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_DVAR)
+ storage = LOC_LOCAL;
+ else
+ storage = LOC_UNDEF;
+
+ set_namestring (dn_bufp, &namestring, objfile);
+ if (!pst)
+ {
+ pst = hpread_start_psymtab (objfile,
+ "globals", 0,
+ (hp_symnum
+ * sizeof (struct dntt_type_block)),
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ }
+
+ /* Compute address of the data symbol */
+ valu = dn_bufp->dsvar.location;
+ /* Relocate in case it's in a shared library */
+ if (storage == LOC_STATIC)
+ valu += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+
+ /* Luckily, dvar, svar, typedef, and tagdef all
+ have their "global" bit in the same place, so it works
+ (though it's bad programming practice) to reference
+ "dsvar.global" even though we may be looking at
+ any of the above four types. */
+ if (dn_bufp->dsvar.global)
+ {
+ add_psymbol_to_list (namestring, strlen (namestring),
+ domain, storage,
+ &objfile->global_psymbols,
+ valu,
+ 0, language_unknown, objfile);
+ }
+ else
+ {
+ add_psymbol_to_list (namestring, strlen (namestring),
+ domain, storage,
+ &objfile->static_psymbols,
+ valu,
+ 0, language_unknown, objfile);
+ }
+
+ /* For TAGDEF's, the above code added the tagname to the
+ struct domain. This will cause tag "t" to be found
+ on a reference of the form "(struct t) x". But for
+ C++ classes, "t" will also be a typename, which we
+ want to find on a reference of the form "ptype t".
+ Therefore, we also add "t" to the var domain.
+ Do the same for enum's due to the way aCC generates
+ debug info for these (see more extended comment
+ in hp-symtab-read.c).
+ We do the same for templates, so that "ptype t"
+ where "t" is a template also works. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_TAGDEF &&
+ dn_bufp->dtype.type.dnttp.index < LNTT_SYMCOUNT (objfile))
+ {
+ int global = dn_bufp->dtag.global;
+ /* Look ahead to see if it's a C++ class */
+ dn_bufp = hpread_get_lntt (dn_bufp->dtype.type.dnttp.index, objfile);
+ if (dn_bufp->dblock.kind == DNTT_TYPE_CLASS ||
+ dn_bufp->dblock.kind == DNTT_TYPE_ENUM ||
+ dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
+ {
+ if (global)
+ {
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, storage,
+ &objfile->global_psymbols,
+ dn_bufp->dsvar.location,
+ 0, language_unknown, objfile);
+ }
+ else
+ {
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, storage,
+ &objfile->static_psymbols,
+ dn_bufp->dsvar.location,
+ 0, language_unknown, objfile);
+ }
+ }
+ }
+ }
+ continue;
+
+ case DNTT_TYPE_MEMENUM:
+ case DNTT_TYPE_CONST:
+ /* Constants and members of enumerated types. */
+ set_namestring (dn_bufp, &namestring, objfile);
+ if (!pst)
+ {
+ pst = hpread_start_psymtab (objfile,
+ "globals", 0,
+ (hp_symnum
+ * sizeof (struct dntt_type_block)),
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ }
+ if (dn_bufp->dconst.global)
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, LOC_CONST,
+ &objfile->global_psymbols, 0,
+ 0, language_unknown, objfile);
+ else
+ add_psymbol_to_list (namestring, strlen (namestring),
+ VAR_DOMAIN, LOC_CONST,
+ &objfile->static_psymbols, 0,
+ 0, language_unknown, objfile);
+ continue;
+ default:
+ continue;
+ }
+ }
+ }
+
+ /* End any pending partial symbol table. */
+ if (pst)
+ {
+ hpread_end_psymtab (pst, psymtab_include_list, includes_used,
+ hp_symnum * sizeof (struct dntt_type_block),
+ 0, dependency_list, dependencies_used);
+ }
+
+ discard_cleanups (old_chain);
+}
+
+/* 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. */
+
+void
+hpread_symfile_finish (struct objfile *objfile)
+{
+ if (objfile->sym_private != NULL)
+ {
+ xmfree (objfile->md, objfile->sym_private);
+ }
+}
+
+
+/* The remaining functions are all for internal use only. */
+
+/* Various small functions to get entries in the debug symbol sections. */
+
+static union dnttentry *
+hpread_get_lntt (int index, struct objfile *objfile)
+{
+ return (union dnttentry *)
+ &(LNTT (objfile)[(index * sizeof (struct dntt_type_block))]);
+}
+
+static union dnttentry *
+hpread_get_gntt (int index, struct objfile *objfile)
+{
+ return (union dnttentry *)
+ &(GNTT (objfile)[(index * sizeof (struct dntt_type_block))]);
+}
+
+static union sltentry *
+hpread_get_slt (int index, struct objfile *objfile)
+{
+ return (union sltentry *) &(SLT (objfile)[index * sizeof (union sltentry)]);
+}
+
+/* Get the low address associated with some symbol (typically the start
+ of a particular source file or module). Since that information is not
+ stored as part of the DNTT_TYPE_MODULE or DNTT_TYPE_SRCFILE symbol we
+ must infer it from the existence of DNTT_TYPE_FUNCTION symbols. */
+
+static unsigned long
+hpread_get_textlow (int global, int index, struct objfile *objfile,
+ int symcount)
+{
+ union dnttentry *dn_bufp = NULL;
+ struct minimal_symbol *msymbol;
+
+ /* Look for a DNTT_TYPE_FUNCTION symbol. */
+ if (index < symcount) /* symcount is the number of symbols in */
+ { /* the dbinfo, LNTT table */
+ do
+ {
+ if (global)
+ dn_bufp = hpread_get_gntt (index++, objfile);
+ else
+ dn_bufp = hpread_get_lntt (index++, objfile);
+ }
+ while (dn_bufp->dblock.kind != DNTT_TYPE_FUNCTION
+ && dn_bufp->dblock.kind != DNTT_TYPE_DOC_FUNCTION
+ && dn_bufp->dblock.kind != DNTT_TYPE_END
+ && index < symcount);
+ }
+
+ /* NOTE: cagney/2003-03-29: If !(index < symcount), dn_bufp is left
+ undefined and that means that the test below is using a garbage
+ pointer from the stack. */
+ gdb_assert (dn_bufp != NULL);
+
+ /* Avoid going past a DNTT_TYPE_END when looking for a DNTT_TYPE_FUNCTION. This
+ might happen when a sourcefile has no functions. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_END)
+ return 0;
+
+ /* Avoid going past the end of the LNTT file */
+ if (index == symcount)
+ return 0;
+
+ /* The minimal symbols are typically more accurate for some reason. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_FUNCTION)
+ msymbol = lookup_minimal_symbol (dn_bufp->dfunc.name + VT (objfile), NULL,
+ objfile);
+ else /* must be a DNTT_TYPE_DOC_FUNCTION */
+ msymbol = lookup_minimal_symbol (dn_bufp->ddocfunc.name + VT (objfile), NULL,
+ objfile);
+
+ if (msymbol)
+ return SYMBOL_VALUE_ADDRESS (msymbol);
+ else
+ return dn_bufp->dfunc.lowaddr;
+}
+
+/* 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 *
+hpread_start_psymtab (struct objfile *objfile, char *filename,
+ CORE_ADDR textlow, int ldsymoff,
+ struct partial_symbol **global_syms,
+ struct partial_symbol **static_syms)
+{
+ int offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ extern void hpread_psymtab_to_symtab ();
+ struct partial_symtab *result =
+ start_psymtab_common (objfile, objfile->section_offsets,
+ filename, textlow, global_syms, static_syms);
+
+ result->textlow += offset;
+ result->read_symtab_private = (char *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct symloc));
+ LDSYMOFF (result) = ldsymoff;
+ result->read_symtab = hpread_psymtab_to_symtab;
+
+ return result;
+}
+
+
+/* Close off the current usage of PST.
+ Returns PST or NULL if the partial symtab was empty and thrown away.
+
+ capping_symbol_offset --Byte index in LNTT or GNTT of the
+ last symbol processed during the build
+ of the previous pst.
+
+ FIXME: List variables and peculiarities of same. */
+
+static struct partial_symtab *
+hpread_end_psymtab (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;
+ int offset = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
+
+#ifdef DUMPING
+ /* Turn on to see what kind of a psymtab we've built. */
+ static int dumping = 0;
+#endif
+
+ if (capping_symbol_offset != -1)
+ LDSYMLEN (pst) = capping_symbol_offset - LDSYMOFF (pst);
+ else
+ LDSYMLEN (pst) = 0;
+ pst->texthigh = capping_text + offset;
+
+ 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);
+
+#ifdef DUMPING
+ if (dumping)
+ {
+ printf ("\nPst %s, LDSYMOFF %x (%x), LDSYMLEN %x (%x), globals %d, statics %d\n",
+ pst->filename,
+ LDSYMOFF (pst),
+ LDSYMOFF (pst) / sizeof (struct dntt_type_block),
+ LDSYMLEN (pst),
+ LDSYMLEN (pst) / sizeof (struct dntt_type_block),
+ pst->n_global_syms, pst->n_static_syms);
+ }
+#endif
+
+ pst->number_of_dependencies = number_dependencies;
+ if (number_dependencies)
+ {
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->objfile_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->objfile_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->objfile_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.
+ It's also wrong if we're using the quick look-up tables, as
+ we can get empty psymtabs from modules with no routines in
+ them. */
+
+ discard_psymtab (pst);
+
+ /* Indicate that psymtab was thrown away. */
+ pst = (struct partial_symtab *) NULL;
+
+ }
+ return pst;
+}
+
+
+/* Get the nesting depth for the source line identified by INDEX. */
+
+static unsigned long
+hpread_get_scope_start (sltpointer index, struct objfile *objfile)
+{
+ union sltentry *sl_bufp;
+
+ sl_bufp = hpread_get_slt (index, objfile);
+ return sl_bufp->sspec.backptr.dnttp.index;
+}
+
+/* Get the source line number the the line identified by INDEX. */
+
+static unsigned long
+hpread_get_line (sltpointer index, struct objfile *objfile)
+{
+ union sltentry *sl_bufp;
+
+ sl_bufp = hpread_get_slt (index, objfile);
+ return sl_bufp->snorm.line;
+}
+
+/* Find the code address associated with a given sltpointer */
+
+static CORE_ADDR
+hpread_get_location (sltpointer index, struct objfile *objfile)
+{
+ union sltentry *sl_bufp;
+ int i;
+
+ /* code location of special sltentrys is determined from context */
+ sl_bufp = hpread_get_slt (index, objfile);
+
+ if (sl_bufp->snorm.sltdesc == SLT_END)
+ {
+ /* find previous normal sltentry and get address */
+ for (i = 0; ((sl_bufp->snorm.sltdesc != SLT_NORMAL) &&
+ (sl_bufp->snorm.sltdesc != SLT_NORMAL_OFFSET) &&
+ (sl_bufp->snorm.sltdesc != SLT_EXIT)); i++)
+ sl_bufp = hpread_get_slt (index - i, objfile);
+ if (sl_bufp->snorm.sltdesc == SLT_NORMAL_OFFSET)
+ return sl_bufp->snormoff.address;
+ else
+ return sl_bufp->snorm.address;
+ }
+
+ /* find next normal sltentry and get address */
+ for (i = 0; ((sl_bufp->snorm.sltdesc != SLT_NORMAL) &&
+ (sl_bufp->snorm.sltdesc != SLT_NORMAL_OFFSET) &&
+ (sl_bufp->snorm.sltdesc != SLT_EXIT)); i++)
+ sl_bufp = hpread_get_slt (index + i, objfile);
+ if (sl_bufp->snorm.sltdesc == SLT_NORMAL_OFFSET)
+ return sl_bufp->snormoff.address;
+ else
+ return sl_bufp->snorm.address;
+}
+
+
+/* Return 1 if an HP debug symbol of type KIND has a name associated with
+ * it, else return 0. (This function is not currently used, but I'll
+ * leave it here in case it proves useful later on. - RT).
+ */
+
+static int
+hpread_has_name (enum dntt_entry_type kind)
+{
+ switch (kind)
+ {
+ case DNTT_TYPE_SRCFILE:
+ case DNTT_TYPE_MODULE:
+ case DNTT_TYPE_FUNCTION:
+ case DNTT_TYPE_DOC_FUNCTION:
+ case DNTT_TYPE_ENTRY:
+ case DNTT_TYPE_IMPORT:
+ case DNTT_TYPE_LABEL:
+ case DNTT_TYPE_FPARAM:
+ case DNTT_TYPE_SVAR:
+ case DNTT_TYPE_DVAR:
+ case DNTT_TYPE_CONST:
+ case DNTT_TYPE_TYPEDEF:
+ case DNTT_TYPE_TAGDEF:
+ case DNTT_TYPE_MEMENUM:
+ case DNTT_TYPE_FIELD:
+ case DNTT_TYPE_SA:
+ case DNTT_TYPE_BLOCKDATA:
+ case DNTT_TYPE_MEMFUNC:
+ case DNTT_TYPE_DOC_MEMFUNC:
+ return 1;
+
+ case DNTT_TYPE_BEGIN:
+ case DNTT_TYPE_END:
+ case DNTT_TYPE_POINTER:
+ case DNTT_TYPE_ENUM:
+ case DNTT_TYPE_SET:
+ case DNTT_TYPE_ARRAY:
+ case DNTT_TYPE_STRUCT:
+ case DNTT_TYPE_UNION:
+ case DNTT_TYPE_VARIANT:
+ case DNTT_TYPE_FILE:
+ case DNTT_TYPE_FUNCTYPE:
+ case DNTT_TYPE_SUBRANGE:
+ case DNTT_TYPE_WITH:
+ case DNTT_TYPE_COMMON:
+ case DNTT_TYPE_COBSTRUCT:
+ case DNTT_TYPE_XREF:
+ case DNTT_TYPE_MACRO:
+ case DNTT_TYPE_CLASS_SCOPE:
+ case DNTT_TYPE_REFERENCE:
+ case DNTT_TYPE_PTRMEM:
+ case DNTT_TYPE_PTRMEMFUNC:
+ case DNTT_TYPE_CLASS:
+ case DNTT_TYPE_GENFIELD:
+ case DNTT_TYPE_VFUNC:
+ case DNTT_TYPE_MEMACCESS:
+ case DNTT_TYPE_INHERITANCE:
+ case DNTT_TYPE_FRIEND_CLASS:
+ case DNTT_TYPE_FRIEND_FUNC:
+ case DNTT_TYPE_MODIFIER:
+ case DNTT_TYPE_OBJECT_ID:
+ case DNTT_TYPE_TEMPLATE:
+ case DNTT_TYPE_TEMPLATE_ARG:
+ case DNTT_TYPE_FUNC_TEMPLATE:
+ case DNTT_TYPE_LINK:
+ /* DNTT_TYPE_DYN_ARRAY_DESC ? */
+ /* DNTT_TYPE_DESC_SUBRANGE ? */
+ /* DNTT_TYPE_BEGIN_EXT ? */
+ /* DNTT_TYPE_INLN ? */
+ /* DNTT_TYPE_INLN_LIST ? */
+ /* DNTT_TYPE_ALIAS ? */
+ default:
+ return 0;
+ }
+}
+
+/* Do the dirty work of reading in the full symbol from a partial symbol
+ table. */
+
+static void
+hpread_psymtab_to_symtab_1 (struct partial_symtab *pst)
+{
+ struct cleanup *old_chain;
+ int i;
+
+ /* Get out quick if passed junk. */
+ if (!pst)
+ return;
+
+ /* Complain if we've already read in this symbol table. */
+ 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);
+ }
+ hpread_psymtab_to_symtab_1 (pst->dependencies[i]);
+ }
+
+ /* If it's real... */
+ if (LDSYMLEN (pst))
+ {
+ /* Init stuff necessary for reading in symbols */
+ buildsym_init ();
+ old_chain = make_cleanup (really_free_pendings, 0);
+
+ pst->symtab =
+ hpread_expand_symtab (pst->objfile, LDSYMOFF (pst), LDSYMLEN (pst),
+ pst->textlow, pst->texthigh - pst->textlow,
+ pst->section_offsets, pst->filename);
+
+ 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
+hpread_psymtab_to_symtab (struct partial_symtab *pst)
+{
+ /* Get out quick if given junk. */
+ if (!pst)
+ return;
+
+ /* Sanity check. */
+ if (pst->readin)
+ {
+ fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in."
+ " Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ /* elz: setting the flag to indicate that the code of the target
+ was compiled using an HP compiler (aCC, cc)
+ the processing_acc_compilation variable is declared in the
+ file buildsym.h, the HP_COMPILED_TARGET is defined to be equal
+ to 3 in the file tm_hppa.h */
+
+ processing_gcc_compilation = 0;
+
+ 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);
+ }
+
+ hpread_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.
+
+ DESC is the file descriptor for the file, positioned at the
+ beginning of the symtab
+ SYM_OFFSET is the offset within the file of
+ the beginning of the symbols we want to read
+ SYM_SIZE is the size of the symbol info to read in.
+ TEXT_OFFSET is the beginning of the text segment we are reading symbols for
+ TEXT_SIZE is the size of the text segment read in.
+ SECTION_OFFSETS are the relocation offsets which get added to each symbol. */
+
+static struct symtab *
+hpread_expand_symtab (struct objfile *objfile, int sym_offset, int sym_size,
+ CORE_ADDR text_offset, int text_size,
+ struct section_offsets *section_offsets, char *filename)
+{
+ char *namestring;
+ union dnttentry *dn_bufp;
+ unsigned max_symnum;
+ int at_module_boundary = 0;
+ /* 1 => at end, -1 => at beginning */
+
+ int sym_index = sym_offset / sizeof (struct dntt_type_block);
+
+ current_objfile = objfile;
+ subfile_stack = 0;
+
+ last_source_file = 0;
+
+ /* Demangling style -- if EDG style already set, don't change it,
+ as HP style causes some problems with the KAI EDG compiler */
+ if (current_demangling_style != edg_demangling)
+ {
+ /* Otherwise, ensure that we are using HP style demangling */
+ set_demangling_style (HP_DEMANGLING_STYLE_STRING);
+ }
+
+ dn_bufp = hpread_get_lntt (sym_index, objfile);
+ if (!((dn_bufp->dblock.kind == (unsigned char) DNTT_TYPE_SRCFILE) ||
+ (dn_bufp->dblock.kind == (unsigned char) DNTT_TYPE_MODULE)))
+ {
+ start_symtab ("globals", NULL, 0);
+ record_debugformat ("HP");
+ }
+
+ /* The psymtab builder (hp-psymtab-read.c) is the one that
+ * determined the "sym_size" argument (i.e. how many DNTT symbols
+ * are in this symtab), which we use to compute "max_symnum"
+ * (point in DNTT to which we read).
+ *
+ * Perhaps this should be changed so that
+ * process_one_debug_symbol() "knows" when
+ * to stop reading (based on reading from the MODULE to the matching
+ * END), and take out this reliance on a #-syms being passed in...
+ * (I'm worried about the reliability of this number). But I'll
+ * leave it as-is, for now. - RT
+ *
+ * The change above has been made. I've left the "for" loop control
+ * in to prepare for backing this out again. -JB
+ */
+ max_symnum = sym_size / sizeof (struct dntt_type_block);
+ /* No reason to multiply on pst side and divide on sym side... FIXME */
+
+ /* Read in and process each debug symbol within the specified range.
+ */
+ for (symnum = 0;
+ symnum < max_symnum;
+ symnum++)
+ {
+ QUIT; /* Allow this to be interruptable */
+ dn_bufp = hpread_get_lntt (sym_index + symnum, objfile);
+
+ if (dn_bufp->dblock.extension)
+ continue;
+
+ /* Yow! We call set_namestring on things without names! */
+ set_namestring (dn_bufp, &namestring, objfile);
+
+ hpread_process_one_debug_symbol (dn_bufp, namestring, section_offsets,
+ objfile, text_offset, text_size,
+ filename, symnum + sym_index,
+ &at_module_boundary
+ );
+
+ /* OLD COMMENTS: This routine is only called for psts. All psts
+ * correspond to MODULES. If we ever do lazy-reading of globals
+ * from the LNTT, then there will be a pst which ends when the
+ * LNTT ends, and not at an END MODULE entry. Then we'll have
+ * to re-visit this break.
+
+ if( at_end_of_module )
+ break;
+
+ */
+
+ /* We no longer break out of the loop when we reach the end of a
+ module. The reason is that with CTTI, the compiler can generate
+ function symbols (for template function instantiations) which are not
+ in any module; typically they show up beyond a module's end, and
+ before the next module's start. We include them in the current
+ module. However, we still don't trust the MAX_SYMNUM value from
+ the psymtab, so we break out if we enter a new module. */
+
+ if (at_module_boundary == -1)
+ break;
+ }
+
+ current_objfile = NULL;
+ hp_som_som_object_present = 1; /* Indicate we've processed an HP SOM SOM file */
+
+ return end_symtab (text_offset + text_size, objfile, SECT_OFF_TEXT (objfile));
+}
+
+
+
+
+/* Convert basic types from HP debug format into GDB internal format. */
+
+static int
+hpread_type_translate (dnttpointer typep)
+{
+ if (!typep.dntti.immediate)
+ {
+ error ("error in hpread_type_translate\n.");
+ return FT_VOID;
+ }
+
+ switch (typep.dntti.type)
+ {
+ case HP_TYPE_BOOLEAN:
+ case HP_TYPE_BOOLEAN_S300_COMPAT:
+ case HP_TYPE_BOOLEAN_VAX_COMPAT:
+ return FT_BOOLEAN;
+ case HP_TYPE_CHAR: /* C signed char, C++ plain char */
+
+ case HP_TYPE_WIDE_CHAR:
+ return FT_CHAR;
+ case HP_TYPE_INT:
+ if (typep.dntti.bitlength <= 8)
+ return FT_SIGNED_CHAR; /* C++ signed char */
+ if (typep.dntti.bitlength <= 16)
+ return FT_SHORT;
+ if (typep.dntti.bitlength <= 32)
+ return FT_INTEGER;
+ return FT_LONG_LONG;
+ case HP_TYPE_LONG:
+ if (typep.dntti.bitlength <= 8)
+ return FT_SIGNED_CHAR; /* C++ signed char. */
+ return FT_LONG;
+ case HP_TYPE_UNSIGNED_LONG:
+ if (typep.dntti.bitlength <= 8)
+ return FT_UNSIGNED_CHAR; /* C/C++ unsigned char */
+ if (typep.dntti.bitlength <= 16)
+ return FT_UNSIGNED_SHORT;
+ if (typep.dntti.bitlength <= 32)
+ return FT_UNSIGNED_LONG;
+ return FT_UNSIGNED_LONG_LONG;
+ case HP_TYPE_UNSIGNED_INT:
+ if (typep.dntti.bitlength <= 8)
+ return FT_UNSIGNED_CHAR;
+ if (typep.dntti.bitlength <= 16)
+ return FT_UNSIGNED_SHORT;
+ if (typep.dntti.bitlength <= 32)
+ return FT_UNSIGNED_INTEGER;
+ return FT_UNSIGNED_LONG_LONG;
+ case HP_TYPE_REAL:
+ case HP_TYPE_REAL_3000:
+ case HP_TYPE_DOUBLE:
+ if (typep.dntti.bitlength == 64)
+ return FT_DBL_PREC_FLOAT;
+ if (typep.dntti.bitlength == 128)
+ return FT_EXT_PREC_FLOAT;
+ return FT_FLOAT;
+ case HP_TYPE_COMPLEX:
+ case HP_TYPE_COMPLEXS3000:
+ if (typep.dntti.bitlength == 128)
+ return FT_DBL_PREC_COMPLEX;
+ if (typep.dntti.bitlength == 192)
+ return FT_EXT_PREC_COMPLEX;
+ return FT_COMPLEX;
+ case HP_TYPE_VOID:
+ return FT_VOID;
+ case HP_TYPE_STRING200:
+ case HP_TYPE_LONGSTRING200:
+ case HP_TYPE_FTN_STRING_SPEC:
+ case HP_TYPE_MOD_STRING_SPEC:
+ case HP_TYPE_MOD_STRING_3000:
+ case HP_TYPE_FTN_STRING_S300_COMPAT:
+ case HP_TYPE_FTN_STRING_VAX_COMPAT:
+ return FT_STRING;
+ case HP_TYPE_TEMPLATE_ARG:
+ return FT_TEMPLATE_ARG;
+ case HP_TYPE_TEXT:
+ case HP_TYPE_FLABEL:
+ case HP_TYPE_PACKED_DECIMAL:
+ case HP_TYPE_ANYPOINTER:
+ case HP_TYPE_GLOBAL_ANYPOINTER:
+ case HP_TYPE_LOCAL_ANYPOINTER:
+ default:
+ warning ("hpread_type_translate: unhandled type code.\n");
+ return FT_VOID;
+ }
+}
+
+/* Given a position in the DNTT, return a pointer to the
+ * already-built "struct type" (if any), for the type defined
+ * at that position.
+ */
+
+static struct type **
+hpread_lookup_type (dnttpointer hp_type, struct objfile *objfile)
+{
+ unsigned old_len;
+ int index = hp_type.dnttp.index;
+ int size_changed = 0;
+
+ /* The immediate flag indicates this doesn't actually point to
+ * a type DNTT.
+ */
+ if (hp_type.dntti.immediate)
+ return NULL;
+
+ /* For each objfile, we maintain a "type vector".
+ * This an array of "struct type *"'s with one pointer per DNTT index.
+ * Given a DNTT index, we look in this array to see if we have
+ * already processed this DNTT and if it is a type definition.
+ * If so, then we can locate a pointer to the already-built
+ * "struct type", and not build it again.
+ *
+ * The need for this arises because our DNTT-walking code wanders
+ * around. In particular, it will encounter the same type multiple
+ * times (once for each object of that type). We don't want to
+ * built multiple "struct type"'s for the same thing.
+ *
+ * Having said this, I should point out that this type-vector is
+ * an expensive way to keep track of this. If most DNTT entries are
+ * 3 words, the type-vector will be 1/3 the size of the DNTT itself.
+ * Alternative solutions:
+ * - Keep a compressed or hashed table. Less memory, but more expensive
+ * to search and update.
+ * - (Suggested by JB): Overwrite the DNTT entry itself
+ * with the info. Create a new type code "ALREADY_BUILT", and modify
+ * the DNTT to have that type code and point to the already-built entry.
+ * -RT
+ */
+
+ if (index < LNTT_SYMCOUNT (objfile))
+ {
+ if (index >= DNTT_TYPE_VECTOR_LENGTH (objfile))
+ {
+ old_len = DNTT_TYPE_VECTOR_LENGTH (objfile);
+
+ /* See if we need to allocate a type-vector. */
+ if (old_len == 0)
+ {
+ DNTT_TYPE_VECTOR_LENGTH (objfile) = LNTT_SYMCOUNT (objfile) + GNTT_SYMCOUNT (objfile);
+ DNTT_TYPE_VECTOR (objfile) = (struct type **)
+ xmmalloc (objfile->md, DNTT_TYPE_VECTOR_LENGTH (objfile) * sizeof (struct type *));
+ memset (&DNTT_TYPE_VECTOR (objfile)[old_len], 0,
+ (DNTT_TYPE_VECTOR_LENGTH (objfile) - old_len) *
+ sizeof (struct type *));
+ }
+
+ /* See if we need to resize type-vector. With my change to
+ * initially allocate a correct-size type-vector, this code
+ * should no longer trigger.
+ */
+ while (index >= DNTT_TYPE_VECTOR_LENGTH (objfile))
+ {
+ DNTT_TYPE_VECTOR_LENGTH (objfile) *= 2;
+ size_changed = 1;
+ }
+ if (size_changed)
+ {
+ DNTT_TYPE_VECTOR (objfile) = (struct type **)
+ xmrealloc (objfile->md,
+ (char *) DNTT_TYPE_VECTOR (objfile),
+ (DNTT_TYPE_VECTOR_LENGTH (objfile) * sizeof (struct type *)));
+
+ memset (&DNTT_TYPE_VECTOR (objfile)[old_len], 0,
+ (DNTT_TYPE_VECTOR_LENGTH (objfile) - old_len) *
+ sizeof (struct type *));
+ }
+
+ }
+ return &DNTT_TYPE_VECTOR (objfile)[index];
+ }
+ else
+ return NULL;
+}
+
+/* Possibly allocate a GDB internal type so we can internalize HP_TYPE.
+ Note we'll just return the address of a GDB internal type if we already
+ have it lying around. */
+
+static struct type *
+hpread_alloc_type (dnttpointer hp_type, struct objfile *objfile)
+{
+ struct type **type_addr;
+
+ type_addr = hpread_lookup_type (hp_type, objfile);
+ if (*type_addr == 0)
+ {
+ *type_addr = alloc_type (objfile);
+
+ /* A hack - if we really are a C++ class symbol, then this default
+ * will get overriden later on.
+ */
+ TYPE_CPLUS_SPECIFIC (*type_addr)
+ = (struct cplus_struct_type *) &cplus_struct_default;
+ }
+
+ return *type_addr;
+}
+
+/* Read a native enumerated type and return it in GDB internal form. */
+
+static struct type *
+hpread_read_enum_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile)
+{
+ struct type *type;
+ struct pending **symlist, *osyms, *syms;
+ struct pending *local_list = NULL;
+ int o_nsyms, nsyms = 0;
+ dnttpointer mem;
+ union dnttentry *memp;
+ char *name;
+ long n;
+ struct symbol *sym;
+
+ /* Allocate a GDB type. If we've already read in this enum type,
+ * it'll return the already built GDB type, so stop here.
+ * (Note: I added this check, to conform with what's done for
+ * struct, union, class.
+ * I assume this is OK. - RT)
+ */
+ type = hpread_alloc_type (hp_type, objfile);
+ if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+ return type;
+
+ /* HP C supports "sized enums", where a specifier such as "short" or
+ "char" can be used to get enums of different sizes. So don't assume
+ an enum is always 4 bytes long. pai/1997-08-21 */
+ TYPE_LENGTH (type) = dn_bufp->denum.bitlength / 8;
+
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ /* Get a name for each member and add it to our list of members.
+ * The list of "mem" SOM records we are walking should all be
+ * SOM type DNTT_TYPE_MEMENUM (not checked).
+ */
+ mem = dn_bufp->denum.firstmem;
+ while (mem.word && mem.word != DNTTNIL)
+ {
+ memp = hpread_get_lntt (mem.dnttp.index, objfile);
+
+ name = VT (objfile) + memp->dmember.name;
+ sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (sym) = obsavestring (name, strlen (name),
+ &objfile->objfile_obstack);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ SYMBOL_VALUE (sym) = memp->dmember.value;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ mem = memp->dmember.nextmem;
+ }
+
+ /* Now that we know more about the enum, fill in more info. */
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the members 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) = DEPRECATED_SYMBOL_NAME (xsym);
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ TYPE_FIELD_STATIC_KIND (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ return type;
+}
+
+/* Read and internalize a native function debug symbol. */
+
+static struct type *
+hpread_read_function_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile, int newblock)
+{
+ struct type *type, *type1;
+ struct pending *syms;
+ struct pending *local_list = NULL;
+ int nsyms = 0;
+ dnttpointer param;
+ union dnttentry *paramp;
+ char *name;
+ long n;
+ struct symbol *sym;
+ int record_args = 1;
+
+ /* See if we've already read in this type. */
+ type = hpread_alloc_type (hp_type, objfile);
+ if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+ {
+ record_args = 0; /* already read in, don't modify type */
+ }
+ else
+ {
+ /* Nope, so read it in and store it away. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_FUNCTION ||
+ dn_bufp->dblock.kind == DNTT_TYPE_MEMFUNC)
+ type1 = lookup_function_type (hpread_type_lookup (dn_bufp->dfunc.retval,
+ objfile));
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_FUNCTYPE)
+ type1 = lookup_function_type (hpread_type_lookup (dn_bufp->dfunctype.retval,
+ objfile));
+ else /* expect DNTT_TYPE_FUNC_TEMPLATE */
+ type1 = lookup_function_type (hpread_type_lookup (dn_bufp->dfunc_template.retval,
+ objfile));
+ replace_type (type, type1);
+
+ /* Mark it -- in the middle of processing */
+ TYPE_FLAGS (type) |= TYPE_FLAG_INCOMPLETE;
+ }
+
+ /* Now examine each parameter noting its type, location, and a
+ wealth of other information. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_FUNCTION ||
+ dn_bufp->dblock.kind == DNTT_TYPE_MEMFUNC)
+ param = dn_bufp->dfunc.firstparam;
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_FUNCTYPE)
+ param = dn_bufp->dfunctype.firstparam;
+ else /* expect DNTT_TYPE_FUNC_TEMPLATE */
+ param = dn_bufp->dfunc_template.firstparam;
+ while (param.word && param.word != DNTTNIL)
+ {
+ paramp = hpread_get_lntt (param.dnttp.index, objfile);
+ nsyms++;
+ param = paramp->dfparam.nextparam;
+
+ /* Get the name. */
+ name = VT (objfile) + paramp->dfparam.name;
+ sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ (void) memset (sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (sym) = obsavestring (name, strlen (name),
+ &objfile->objfile_obstack);
+
+ /* Figure out where it lives. */
+ if (paramp->dfparam.regparam)
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ else if (paramp->dfparam.indirect)
+ SYMBOL_CLASS (sym) = LOC_REF_ARG;
+ else
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ if (paramp->dfparam.copyparam)
+ {
+ SYMBOL_VALUE (sym) = paramp->dfparam.location;
+#ifdef HPREAD_ADJUST_STACK_ADDRESS
+ SYMBOL_VALUE (sym)
+ += HPREAD_ADJUST_STACK_ADDRESS (CURRENT_FUNCTION_VALUE (objfile));
+#endif
+ /* This is likely a pass-by-invisible reference parameter,
+ Hack on the symbol class to make GDB happy. */
+ /* ??rehrauer: This appears to be broken w/r/t to passing
+ C values of type float and struct. Perhaps this ought
+ to be highighted as a special case, but for now, just
+ allowing these to be LOC_ARGs seems to work fine.
+ */
+#if 0
+ SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR;
+#endif
+ }
+ else
+ SYMBOL_VALUE (sym) = paramp->dfparam.location;
+
+ /* Get its type. */
+ SYMBOL_TYPE (sym) = hpread_type_lookup (paramp->dfparam.type, objfile);
+ /* Add it to the symbol list. */
+ /* Note 1 (RT) At the moment, add_symbol_to_list() is also being
+ * called on FPARAM symbols from the process_one_debug_symbol()
+ * level... so parameters are getting added twice! (this shows
+ * up in the symbol dump you get from "maint print symbols ...").
+ * Note 2 (RT) I took out the processing of FPARAM from the
+ * process_one_debug_symbol() level, so at the moment parameters are only
+ * being processed here. This seems to have no ill effect.
+ */
+ /* Note 3 (pai/1997-08-11) I removed the add_symbol_to_list() which put
+ each fparam on the local_symbols list from here. Now we use the
+ local_list to which fparams are added below, and set the param_symbols
+ global to point to that at the end of this routine. */
+ /* elz: I added this new list of symbols which is local to the function.
+ this list is the one which is actually used to build the type for the
+ function rather than the gloabal list pointed to by symlist.
+ Using a global list to keep track of the parameters is wrong, because
+ this function is called recursively if one parameter happend to be
+ a function itself with more parameters in it. Adding parameters to the
+ same global symbol list would not work!
+ Actually it did work in case of cc compiled programs where you do
+ not check the parameter lists of the arguments. */
+ add_symbol_to_list (sym, &local_list);
+
+ }
+
+ /* If type was read in earlier, don't bother with modifying
+ the type struct */
+ if (!record_args)
+ goto finish;
+
+ /* Note how many parameters we found. */
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the parameters and
+ use them to fill parameter-type information into the function-type.
+ The parameter symbols can be found in the local_list that we just put them on. */
+ /* Note that we preserve the order of the parameters, so
+ that in something like "enum {FOO, LAST_THING=FOO}" we print
+ FOO, not LAST_THING. */
+
+ /* get the parameters types from the local list not the global list
+ so that the type can be correctly constructed for functions which
+ have function as parameters */
+ for (syms = local_list, n = 0; syms; syms = syms->next)
+ {
+ int j = 0;
+ for (j = 0; j < syms->nsyms; j++, n++)
+ {
+ struct symbol *xsym = syms->symbol[j];
+ TYPE_FIELD_NAME (type, n) = DEPRECATED_SYMBOL_NAME (xsym);
+ TYPE_FIELD_TYPE (type, n) = SYMBOL_TYPE (xsym);
+ TYPE_FIELD_ARTIFICIAL (type, n) = 0;
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ TYPE_FIELD_STATIC_KIND (type, n) = 0;
+ }
+ }
+ /* Mark it as having been processed */
+ TYPE_FLAGS (type) &= ~(TYPE_FLAG_INCOMPLETE);
+
+ /* Check whether we need to fix-up a class type with this function's type */
+ if (fixup_class && (fixup_method == type))
+ {
+ fixup_class_method_type (fixup_class, fixup_method, objfile);
+ fixup_class = NULL;
+ fixup_method = NULL;
+ }
+
+ /* Set the param list of this level of the context stack
+ to our local list. Do this only if this function was
+ called for creating a new block, and not if it was called
+ simply to get the function type. This prevents recursive
+ invocations from trashing param_symbols. */
+finish:
+ if (newblock)
+ param_symbols = local_list;
+
+ return type;
+}
+
+
+/* Read and internalize a native DOC function debug symbol. */
+/* This is almost identical to hpread_read_function_type(), except
+ * for references to dn_bufp->ddocfunc instead of db_bufp->dfunc.
+ * Since debug information for DOC functions is more likely to be
+ * volatile, please leave it this way.
+ */
+static struct type *
+hpread_read_doc_function_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile, int newblock)
+{
+ struct pending *syms;
+ struct pending *local_list = NULL;
+ int nsyms = 0;
+ struct type *type;
+ dnttpointer param;
+ union dnttentry *paramp;
+ char *name;
+ long n;
+ struct symbol *sym;
+ int record_args = 1;
+
+ /* See if we've already read in this type. */
+ type = hpread_alloc_type (hp_type, objfile);
+ if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+ {
+ record_args = 0; /* already read in, don't modify type */
+ }
+ else
+ {
+ struct type *type1 = NULL;
+ /* Nope, so read it in and store it away. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_DOC_FUNCTION ||
+ dn_bufp->dblock.kind == DNTT_TYPE_DOC_MEMFUNC)
+ type1 = lookup_function_type (hpread_type_lookup (dn_bufp->ddocfunc.retval,
+ objfile));
+ /* NOTE: cagney/2003-03-29: Oh, no not again. TYPE1 is
+ potentially left undefined here. Assert it isn't and hope
+ the assert never fails ... */
+ gdb_assert (type1 != NULL);
+
+ replace_type (type, type1);
+
+ /* Mark it -- in the middle of processing */
+ TYPE_FLAGS (type) |= TYPE_FLAG_INCOMPLETE;
+ }
+
+ /* Now examine each parameter noting its type, location, and a
+ wealth of other information. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_DOC_FUNCTION ||
+ dn_bufp->dblock.kind == DNTT_TYPE_DOC_MEMFUNC)
+ param = dn_bufp->ddocfunc.firstparam;
+ while (param.word && param.word != DNTTNIL)
+ {
+ paramp = hpread_get_lntt (param.dnttp.index, objfile);
+ nsyms++;
+ param = paramp->dfparam.nextparam;
+
+ /* Get the name. */
+ name = VT (objfile) + paramp->dfparam.name;
+ sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ (void) memset (sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (sym) = name;
+
+ /* Figure out where it lives. */
+ if (paramp->dfparam.regparam)
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ else if (paramp->dfparam.indirect)
+ SYMBOL_CLASS (sym) = LOC_REF_ARG;
+ else
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ if (paramp->dfparam.copyparam)
+ {
+ SYMBOL_VALUE (sym) = paramp->dfparam.location;
+#ifdef HPREAD_ADJUST_STACK_ADDRESS
+ SYMBOL_VALUE (sym)
+ += HPREAD_ADJUST_STACK_ADDRESS (CURRENT_FUNCTION_VALUE (objfile));
+#endif
+ /* This is likely a pass-by-invisible reference parameter,
+ Hack on the symbol class to make GDB happy. */
+ /* ??rehrauer: This appears to be broken w/r/t to passing
+ C values of type float and struct. Perhaps this ought
+ to be highighted as a special case, but for now, just
+ allowing these to be LOC_ARGs seems to work fine.
+ */
+#if 0
+ SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR;
+#endif
+ }
+ else
+ SYMBOL_VALUE (sym) = paramp->dfparam.location;
+
+ /* Get its type. */
+ SYMBOL_TYPE (sym) = hpread_type_lookup (paramp->dfparam.type, objfile);
+ /* Add it to the symbol list. */
+ /* Note 1 (RT) At the moment, add_symbol_to_list() is also being
+ * called on FPARAM symbols from the process_one_debug_symbol()
+ * level... so parameters are getting added twice! (this shows
+ * up in the symbol dump you get from "maint print symbols ...").
+ * Note 2 (RT) I took out the processing of FPARAM from the
+ * process_one_debug_symbol() level, so at the moment parameters are only
+ * being processed here. This seems to have no ill effect.
+ */
+ /* Note 3 (pai/1997-08-11) I removed the add_symbol_to_list() which put
+ each fparam on the local_symbols list from here. Now we use the
+ local_list to which fparams are added below, and set the param_symbols
+ global to point to that at the end of this routine. */
+
+ /* elz: I added this new list of symbols which is local to the function.
+ this list is the one which is actually used to build the type for the
+ function rather than the gloabal list pointed to by symlist.
+ Using a global list to keep track of the parameters is wrong, because
+ this function is called recursively if one parameter happend to be
+ a function itself with more parameters in it. Adding parameters to the
+ same global symbol list would not work!
+ Actually it did work in case of cc compiled programs where you do not check the
+ parameter lists of the arguments. */
+ add_symbol_to_list (sym, &local_list);
+ }
+
+ /* If type was read in earlier, don't bother with modifying
+ the type struct */
+ if (!record_args)
+ goto finish;
+
+ /* Note how many parameters we found. */
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the parameters and
+ use them to fill parameter-type information into the function-type.
+ The parameter symbols can be found in the local_list that we just put them on. */
+ /* Note that we preserve the order of the parameters, so
+ that in something like "enum {FOO, LAST_THING=FOO}" we print
+ FOO, not LAST_THING. */
+
+ /* get the parameters types from the local list not the global list
+ so that the type can be correctly constructed for functions which
+ have function as parameters
+ */
+ for (syms = local_list, n = 0; syms; syms = syms->next)
+ {
+ int j = 0;
+ for (j = 0; j < syms->nsyms; j++, n++)
+ {
+ struct symbol *xsym = syms->symbol[j];
+ TYPE_FIELD_NAME (type, n) = DEPRECATED_SYMBOL_NAME (xsym);
+ TYPE_FIELD_TYPE (type, n) = SYMBOL_TYPE (xsym);
+ TYPE_FIELD_ARTIFICIAL (type, n) = 0;
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ TYPE_FIELD_STATIC_KIND (type, n) = 0;
+ }
+ }
+
+ /* Mark it as having been processed */
+ TYPE_FLAGS (type) &= ~(TYPE_FLAG_INCOMPLETE);
+
+ /* Check whether we need to fix-up a class type with this function's type */
+ if (fixup_class && (fixup_method == type))
+ {
+ fixup_class_method_type (fixup_class, fixup_method, objfile);
+ fixup_class = NULL;
+ fixup_method = NULL;
+ }
+
+ /* Set the param list of this level of the context stack
+ to our local list. Do this only if this function was
+ called for creating a new block, and not if it was called
+ simply to get the function type. This prevents recursive
+ invocations from trashing param_symbols. */
+finish:
+ if (newblock)
+ param_symbols = local_list;
+
+ return type;
+}
+
+
+
+/* A file-level variable which keeps track of the current-template
+ * being processed. Set in hpread_read_struct_type() while processing
+ * a template type. Referred to in hpread_get_nth_templ_arg().
+ * Yes, this is a kludge, but it arises from the kludge that already
+ * exists in symtab.h, namely the fact that they encode
+ * "template argument n" with fundamental type FT_TEMPLATE_ARG and
+ * bitlength n. This means that deep in processing fundamental types
+ * I need to ask the question "what template am I in the middle of?".
+ * The alternative to stuffing a global would be to pass an argument
+ * down the chain of calls just for this purpose.
+ *
+ * There may be problems handling nested templates... tough.
+ */
+static struct type *current_template = NULL;
+
+/* Read in and internalize a structure definition.
+ * This same routine is called for struct, union, and class types.
+ * Also called for templates, since they build a very similar
+ * type entry as for class types.
+ */
+
+static struct type *
+hpread_read_struct_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile)
+{
+ /* The data members get linked together into a list of struct nextfield's */
+ struct nextfield
+ {
+ struct nextfield *next;
+ struct field field;
+ unsigned char attributes; /* store visibility and virtuality info */
+#define ATTR_VIRTUAL 1
+#define ATTR_PRIVATE 2
+#define ATTR_PROTECT 3
+ };
+
+
+ /* The methods get linked together into a list of struct next_fn_field's */
+ struct next_fn_field
+ {
+ struct next_fn_field *next;
+ struct fn_fieldlist field;
+ struct fn_field fn_field;
+ int num_fn_fields;
+ };
+
+ /* The template args get linked together into a list of struct next_template's */
+ struct next_template
+ {
+ struct next_template *next;
+ struct template_arg arg;
+ };
+
+ /* The template instantiations get linked together into a list of these... */
+ struct next_instantiation
+ {
+ struct next_instantiation *next;
+ struct type *t;
+ };
+
+ struct type *type;
+ struct type *baseclass;
+ struct type *memtype;
+ struct nextfield *list = 0, *tmp_list = 0;
+ struct next_fn_field *fn_list = 0;
+ struct next_fn_field *fn_p;
+ struct next_template *t_new, *t_list = 0;
+ struct nextfield *new;
+ struct next_fn_field *fn_new;
+ struct next_instantiation *i_new, *i_list = 0;
+ int n, nfields = 0, n_fn_fields = 0, n_fn_fields_total = 0;
+ int n_base_classes = 0, n_templ_args = 0;
+ int ninstantiations = 0;
+ dnttpointer field, fn_field, parent;
+ union dnttentry *fieldp, *fn_fieldp, *parentp;
+ int i;
+ int static_member = 0;
+ int const_member = 0;
+ int volatile_member = 0;
+ unsigned long vtbl_offset;
+ int need_bitvectors = 0;
+ char *method_name = NULL;
+ char *method_alias = NULL;
+
+
+ /* Is it something we've already dealt with? */
+ type = hpread_alloc_type (hp_type, objfile);
+ if ((TYPE_CODE (type) == TYPE_CODE_STRUCT) ||
+ (TYPE_CODE (type) == TYPE_CODE_UNION) ||
+ (TYPE_CODE (type) == TYPE_CODE_CLASS) ||
+ (TYPE_CODE (type) == TYPE_CODE_TEMPLATE))
+ return type;
+
+ /* Get the basic type correct. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_STRUCT)
+ {
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ TYPE_LENGTH (type) = dn_bufp->dstruct.bitlength / 8;
+ }
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_UNION)
+ {
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ TYPE_LENGTH (type) = dn_bufp->dunion.bitlength / 8;
+ }
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_CLASS)
+ {
+ TYPE_CODE (type) = TYPE_CODE_CLASS;
+ TYPE_LENGTH (type) = dn_bufp->dclass.bitlength / 8;
+
+ /* Overrides the TYPE_CPLUS_SPECIFIC(type) with allocated memory
+ * rather than &cplus_struct_default.
+ */
+ allocate_cplus_struct_type (type);
+
+ /* Fill in declared-type.
+ * (The C++ compiler will emit TYPE_CODE_CLASS
+ * for all 3 of "class", "struct"
+ * "union", and we have to look at the "class_decl" field if we
+ * want to know how it was really declared)
+ */
+ /* (0==class, 1==union, 2==struct) */
+ TYPE_DECLARED_TYPE (type) = dn_bufp->dclass.class_decl;
+ }
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
+ {
+ /* Get the basic type correct. */
+ TYPE_CODE (type) = TYPE_CODE_TEMPLATE;
+ allocate_cplus_struct_type (type);
+ TYPE_DECLARED_TYPE (type) = DECLARED_TYPE_TEMPLATE;
+ }
+ else
+ return type;
+
+
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+
+ /* For classes, read the parent list.
+ * Question (RT): Do we need to do this for templates also?
+ */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_CLASS)
+ {
+
+ /* First read the parent-list (classes from which we derive fields) */
+ parent = dn_bufp->dclass.parentlist;
+ while (parent.word && parent.word != DNTTNIL)
+ {
+ parentp = hpread_get_lntt (parent.dnttp.index, objfile);
+
+ /* "parentp" should point to a DNTT_TYPE_INHERITANCE record */
+
+ /* Get space to record the next field/data-member. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ memset (new, 0, sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ FIELD_BITSIZE (list->field) = 0;
+ FIELD_STATIC_KIND (list->field) = 0;
+
+ /* The "classname" field is actually a DNTT pointer to the base class */
+ baseclass = hpread_type_lookup (parentp->dinheritance.classname,
+ objfile);
+ FIELD_TYPE (list->field) = baseclass;
+
+ list->field.name = type_name_no_tag (FIELD_TYPE (list->field));
+
+ list->attributes = 0;
+
+ /* Check for virtuality of base, and set the
+ * offset of the base subobject within the object.
+ * (Offset set to -1 for virtual bases (for now).)
+ */
+ if (parentp->dinheritance.Virtual)
+ {
+ B_SET (&(list->attributes), ATTR_VIRTUAL);
+ parentp->dinheritance.offset = -1;
+ }
+ else
+ FIELD_BITPOS (list->field) = parentp->dinheritance.offset;
+
+ /* Check visibility */
+ switch (parentp->dinheritance.visibility)
+ {
+ case 1:
+ B_SET (&(list->attributes), ATTR_PROTECT);
+ break;
+ case 2:
+ B_SET (&(list->attributes), ATTR_PRIVATE);
+ break;
+ }
+
+ n_base_classes++;
+ nfields++;
+
+ parent = parentp->dinheritance.next;
+ }
+ }
+
+ /* For templates, read the template argument list.
+ * This must be done before processing the member list, because
+ * the member list may refer back to this. E.g.:
+ * template <class T1, class T2> class q2 {
+ * public:
+ * T1 a;
+ * T2 b;
+ * };
+ * We need to read the argument list "T1", "T2" first.
+ */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
+ {
+ /* Kludge alert: This stuffs a global "current_template" which
+ * is referred to by hpread_get_nth_templ_arg(). The global
+ * is cleared at the end of this routine.
+ */
+ current_template = type;
+
+ /* Read in the argument list */
+ field = dn_bufp->dtemplate.arglist;
+ while (field.word && field.word != DNTTNIL)
+ {
+ /* Get this template argument */
+ fieldp = hpread_get_lntt (field.dnttp.index, objfile);
+ if (fieldp->dblock.kind != DNTT_TYPE_TEMPLATE_ARG)
+ {
+ warning ("Invalid debug info: Template argument entry is of wrong kind");
+ break;
+ }
+ /* Bump the count */
+ n_templ_args++;
+ /* Allocate and fill in a struct next_template */
+ t_new = (struct next_template *) alloca (sizeof (struct next_template));
+ memset (t_new, 0, sizeof (struct next_template));
+ t_new->next = t_list;
+ t_list = t_new;
+ t_list->arg.name = VT (objfile) + fieldp->dtempl_arg.name;
+ t_list->arg.type = hpread_read_templ_arg_type (field, fieldp,
+ objfile, t_list->arg.name);
+ /* Walk to the next template argument */
+ field = fieldp->dtempl_arg.nextarg;
+ }
+ }
+
+ TYPE_NTEMPLATE_ARGS (type) = n_templ_args;
+
+ if (n_templ_args > 0)
+ TYPE_TEMPLATE_ARGS (type) = (struct template_arg *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct template_arg) * n_templ_args);
+ for (n = n_templ_args; t_list; t_list = t_list->next)
+ {
+ n -= 1;
+ TYPE_TEMPLATE_ARG (type, n) = t_list->arg;
+ }
+
+ /* Next read in and internalize all the fields/members. */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_STRUCT)
+ field = dn_bufp->dstruct.firstfield;
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_UNION)
+ field = dn_bufp->dunion.firstfield;
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_CLASS)
+ field = dn_bufp->dclass.memberlist;
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
+ field = dn_bufp->dtemplate.memberlist;
+ else
+ field.word = DNTTNIL;
+
+ while (field.word && field.word != DNTTNIL)
+ {
+ fieldp = hpread_get_lntt (field.dnttp.index, objfile);
+
+ /* At this point "fieldp" may point to either a DNTT_TYPE_FIELD
+ * or a DNTT_TYPE_GENFIELD record.
+ */
+ vtbl_offset = 0;
+ static_member = 0;
+ const_member = 0;
+ volatile_member = 0;
+
+ if (fieldp->dblock.kind == DNTT_TYPE_GENFIELD)
+ {
+
+ /* The type will be GENFIELD if the field is a method or
+ * a static member (or some other cases -- see below)
+ */
+
+ /* Follow a link to get to the record for the field. */
+ fn_field = fieldp->dgenfield.field;
+ fn_fieldp = hpread_get_lntt (fn_field.dnttp.index, objfile);
+
+ /* Virtual funcs are indicated by a VFUNC which points to the
+ * real entry
+ */
+ if (fn_fieldp->dblock.kind == DNTT_TYPE_VFUNC)
+ {
+ vtbl_offset = fn_fieldp->dvfunc.vtbl_offset;
+ fn_field = fn_fieldp->dvfunc.funcptr;
+ fn_fieldp = hpread_get_lntt (fn_field.dnttp.index, objfile);
+ }
+
+ /* A function's entry may be preceded by a modifier which
+ * labels it static/constant/volatile.
+ */
+ if (fn_fieldp->dblock.kind == DNTT_TYPE_MODIFIER)
+ {
+ static_member = fn_fieldp->dmodifier.m_static;
+ const_member = fn_fieldp->dmodifier.m_const;
+ volatile_member = fn_fieldp->dmodifier.m_volatile;
+ fn_field = fn_fieldp->dmodifier.type;
+ fn_fieldp = hpread_get_lntt (fn_field.dnttp.index, objfile);
+ }
+
+ /* Check whether we have a method */
+ if ((fn_fieldp->dblock.kind == DNTT_TYPE_MEMFUNC) ||
+ (fn_fieldp->dblock.kind == DNTT_TYPE_FUNCTION) ||
+ (fn_fieldp->dblock.kind == DNTT_TYPE_DOC_MEMFUNC) ||
+ (fn_fieldp->dblock.kind == DNTT_TYPE_DOC_FUNCTION))
+ {
+ /* Method found */
+
+ short ix = 0;
+
+ /* Look up function type of method */
+ memtype = hpread_type_lookup (fn_field, objfile);
+
+ /* Methods can be seen before classes in the SOM records.
+ If we are processing this class because it's a parameter of a
+ method, at this point the method's type is actually incomplete;
+ we'll have to fix it up later; mark the class for this. */
+
+ if (TYPE_INCOMPLETE (memtype))
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_INCOMPLETE;
+ if (fixup_class)
+ warning ("Two classes to fix up for method?? Type information may be incorrect for some classes.");
+ if (fixup_method)
+ warning ("Two methods to be fixed up at once?? Type information may be incorrect for some classes.");
+ fixup_class = type; /* remember this class has to be fixed up */
+ fixup_method = memtype; /* remember the method type to be used in fixup */
+ }
+
+ /* HP aCC generates operator names without the "operator" keyword, and
+ generates null strings as names for operators that are
+ user-defined type conversions to basic types (e.g. operator int ()).
+ So try to reconstruct name as best as possible. */
+
+ method_name = (char *) (VT (objfile) + fn_fieldp->dfunc.name);
+ method_alias = (char *) (VT (objfile) + fn_fieldp->dfunc.alias);
+
+ if (!method_name || /* no name */
+ !*method_name || /* or null name */
+ cplus_mangle_opname (method_name, DMGL_ANSI)) /* or name is an operator like "<" */
+ {
+ char *tmp_name = cplus_demangle (method_alias, DMGL_ANSI);
+ char *op_string = strstr (tmp_name, "operator");
+ method_name = xmalloc (strlen (op_string) + 1); /* don't overwrite VT! */
+ strcpy (method_name, op_string);
+ }
+
+ /* First check if a method of the same name has already been seen. */
+ fn_p = fn_list;
+ while (fn_p)
+ {
+ if (DEPRECATED_STREQ (fn_p->field.name, method_name))
+ break;
+ fn_p = fn_p->next;
+ }
+
+ /* If no such method was found, allocate a new entry in the list */
+ if (!fn_p)
+ {
+ /* Get space to record this member function */
+ /* Note: alloca used; this will disappear on routine exit */
+ fn_new = (struct next_fn_field *) alloca (sizeof (struct next_fn_field));
+ memset (fn_new, 0, sizeof (struct next_fn_field));
+ fn_new->next = fn_list;
+ fn_list = fn_new;
+
+ /* Fill in the fields of the struct nextfield */
+
+ /* Record the (unmangled) method name */
+ fn_list->field.name = method_name;
+ /* Initial space for overloaded methods */
+ /* Note: xmalloc is used; this will persist after this routine exits */
+ fn_list->field.fn_fields = (struct fn_field *) xmalloc (5 * (sizeof (struct fn_field)));
+ fn_list->field.length = 1; /* Init # of overloaded instances */
+ fn_list->num_fn_fields = 5; /* # of entries for which space allocated */
+ fn_p = fn_list;
+ ix = 0; /* array index for fn_field */
+ /* Bump the total count of the distinctly named methods */
+ n_fn_fields++;
+ }
+ else
+ /* Another overloaded instance of an already seen method name */
+ {
+ if (++(fn_p->field.length) > fn_p->num_fn_fields)
+ {
+ /* Increase space allocated for overloaded instances */
+ fn_p->field.fn_fields
+ = (struct fn_field *) xrealloc (fn_p->field.fn_fields,
+ (fn_p->num_fn_fields + 5) * sizeof (struct fn_field));
+ fn_p->num_fn_fields += 5;
+ }
+ ix = fn_p->field.length - 1; /* array index for fn_field */
+ }
+
+ /* "physname" is intended to be the name of this overloaded instance. */
+ if ((fn_fieldp->dfunc.language == HP_LANGUAGE_CPLUSPLUS) &&
+ method_alias &&
+ *method_alias) /* not a null string */
+ fn_p->field.fn_fields[ix].physname = method_alias;
+ else
+ fn_p->field.fn_fields[ix].physname = method_name;
+ /* What's expected here is the function type */
+ /* But mark it as NULL if the method was incompletely processed
+ We'll fix this up later when the method is fully processed */
+ if (TYPE_INCOMPLETE (memtype))
+ fn_p->field.fn_fields[ix].type = NULL;
+ else
+ fn_p->field.fn_fields[ix].type = memtype;
+
+ /* For virtual functions, fill in the voffset field with the
+ * virtual table offset. (This is just copied over from the
+ * SOM record; not sure if it is what GDB expects here...).
+ * But if the function is a static method, set it to 1.
+ *
+ * Note that we have to add 1 because 1 indicates a static
+ * method, and 0 indicates a non-static, non-virtual method */
+
+ if (static_member)
+ fn_p->field.fn_fields[ix].voffset = VOFFSET_STATIC;
+ else
+ fn_p->field.fn_fields[ix].voffset = vtbl_offset ? vtbl_offset + 1 : 0;
+
+ /* Also fill in the fcontext field with the current
+ * class. (The latter isn't quite right: should be the baseclass
+ * that defines the virtual function... Note we do have
+ * a variable "baseclass" that we could stuff into the fcontext
+ * field, but "baseclass" isn't necessarily right either,
+ * since the virtual function could have been defined more
+ * than one level up).
+ */
+
+ if (vtbl_offset != 0)
+ fn_p->field.fn_fields[ix].fcontext = type;
+ else
+ fn_p->field.fn_fields[ix].fcontext = NULL;
+
+ /* Other random fields pertaining to this method */
+ fn_p->field.fn_fields[ix].is_const = const_member;
+ fn_p->field.fn_fields[ix].is_volatile = volatile_member; /* ?? */
+ switch (fieldp->dgenfield.visibility)
+ {
+ case 1:
+ fn_p->field.fn_fields[ix].is_protected = 1;
+ fn_p->field.fn_fields[ix].is_private = 0;
+ break;
+ case 2:
+ fn_p->field.fn_fields[ix].is_protected = 0;
+ fn_p->field.fn_fields[ix].is_private = 1;
+ break;
+ default: /* public */
+ fn_p->field.fn_fields[ix].is_protected = 0;
+ fn_p->field.fn_fields[ix].is_private = 0;
+ }
+ fn_p->field.fn_fields[ix].is_stub = 0;
+
+ /* HP aCC emits both MEMFUNC and FUNCTION entries for a method;
+ if the class points to the FUNCTION, there is usually separate
+ code for the method; but if we have a MEMFUNC, the method has
+ been inlined (and there is usually no FUNCTION entry)
+ FIXME Not sure if this test is accurate. pai/1997-08-22 */
+ if ((fn_fieldp->dblock.kind == DNTT_TYPE_MEMFUNC) ||
+ (fn_fieldp->dblock.kind == DNTT_TYPE_DOC_MEMFUNC))
+ fn_p->field.fn_fields[ix].is_inlined = 1;
+ else
+ fn_p->field.fn_fields[ix].is_inlined = 0;
+
+ fn_p->field.fn_fields[ix].dummy = 0;
+
+ /* Bump the total count of the member functions */
+ n_fn_fields_total++;
+
+ }
+ else if (fn_fieldp->dblock.kind == DNTT_TYPE_SVAR)
+ {
+ /* This case is for static data members of classes */
+
+ /* pai:: FIXME -- check that "staticmem" bit is set */
+
+ /* Get space to record this static member */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ memset (new, 0, sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ list->field.name = VT (objfile) + fn_fieldp->dsvar.name;
+ SET_FIELD_PHYSNAME (list->field, 0); /* initialize to empty */
+ memtype = hpread_type_lookup (fn_fieldp->dsvar.type, objfile);
+
+ FIELD_TYPE (list->field) = memtype;
+ list->attributes = 0;
+ switch (fieldp->dgenfield.visibility)
+ {
+ case 1:
+ B_SET (&(list->attributes), ATTR_PROTECT);
+ break;
+ case 2:
+ B_SET (&(list->attributes), ATTR_PRIVATE);
+ break;
+ }
+ nfields++;
+ }
+
+ else if (fn_fieldp->dblock.kind == DNTT_TYPE_FIELD)
+ {
+ /* FIELDs follow GENFIELDs for fields of anonymous unions.
+ Code below is replicated from the case for FIELDs further
+ below, except that fieldp is replaced by fn_fieldp */
+ if (!fn_fieldp->dfield.a_union)
+ warning ("Debug info inconsistent: FIELD of anonymous union doesn't have a_union bit set");
+ /* Get space to record the next field/data-member. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ memset (new, 0, sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ list->field.name = VT (objfile) + fn_fieldp->dfield.name;
+ FIELD_BITPOS (list->field) = fn_fieldp->dfield.bitoffset;
+ if (fn_fieldp->dfield.bitlength % 8)
+ list->field.bitsize = fn_fieldp->dfield.bitlength;
+ else
+ list->field.bitsize = 0;
+
+ memtype = hpread_type_lookup (fn_fieldp->dfield.type, objfile);
+ list->field.type = memtype;
+ list->attributes = 0;
+ switch (fn_fieldp->dfield.visibility)
+ {
+ case 1:
+ B_SET (&(list->attributes), ATTR_PROTECT);
+ break;
+ case 2:
+ B_SET (&(list->attributes), ATTR_PRIVATE);
+ break;
+ }
+ nfields++;
+ }
+ else if (fn_fieldp->dblock.kind == DNTT_TYPE_SVAR)
+ {
+ /* Field of anonymous union; union is not inside a class */
+ if (!fn_fieldp->dsvar.a_union)
+ warning ("Debug info inconsistent: SVAR field in anonymous union doesn't have a_union bit set");
+ /* Get space to record the next field/data-member. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ memset (new, 0, sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ list->field.name = VT (objfile) + fn_fieldp->dsvar.name;
+ FIELD_BITPOS (list->field) = 0; /* FIXME is this always true? */
+ FIELD_BITSIZE (list->field) = 0; /* use length from type */
+ FIELD_STATIC_KIND (list->field) = 0;
+ memtype = hpread_type_lookup (fn_fieldp->dsvar.type, objfile);
+ list->field.type = memtype;
+ list->attributes = 0;
+ /* No info to set visibility -- always public */
+ nfields++;
+ }
+ else if (fn_fieldp->dblock.kind == DNTT_TYPE_DVAR)
+ {
+ /* Field of anonymous union; union is not inside a class */
+ if (!fn_fieldp->ddvar.a_union)
+ warning ("Debug info inconsistent: DVAR field in anonymous union doesn't have a_union bit set");
+ /* Get space to record the next field/data-member. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ memset (new, 0, sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ list->field.name = VT (objfile) + fn_fieldp->ddvar.name;
+ FIELD_BITPOS (list->field) = 0; /* FIXME is this always true? */
+ FIELD_BITSIZE (list->field) = 0; /* use length from type */
+ FIELD_STATIC_KIND (list->field) = 0;
+ memtype = hpread_type_lookup (fn_fieldp->ddvar.type, objfile);
+ list->field.type = memtype;
+ list->attributes = 0;
+ /* No info to set visibility -- always public */
+ nfields++;
+ }
+ else
+ { /* Not a method, nor a static data member, nor an anon union field */
+
+ /* This case is for miscellaneous type entries (local enums,
+ local function templates, etc.) that can be present
+ inside a class. */
+
+ /* Enums -- will be handled by other code that takes care
+ of DNTT_TYPE_ENUM; here we see only DNTT_TYPE_MEMENUM so
+ it's not clear we could have handled them here at all. */
+ /* FUNC_TEMPLATE: is handled by other code (?). */
+ /* MEMACCESS: modified access for inherited member. Not
+ sure what to do with this, ignoriing it at present. */
+
+ /* What other entries can appear following a GENFIELD which
+ we do not handle above? (MODIFIER, VFUNC handled above.) */
+
+ if ((fn_fieldp->dblock.kind != DNTT_TYPE_MEMACCESS) &&
+ (fn_fieldp->dblock.kind != DNTT_TYPE_MEMENUM) &&
+ (fn_fieldp->dblock.kind != DNTT_TYPE_FUNC_TEMPLATE))
+ warning ("Internal error: Unexpected debug record kind %d found following DNTT_GENFIELD",
+ fn_fieldp->dblock.kind);
+ }
+ /* walk to the next FIELD or GENFIELD */
+ field = fieldp->dgenfield.nextfield;
+
+ }
+ else if (fieldp->dblock.kind == DNTT_TYPE_FIELD)
+ {
+
+ /* Ordinary structure/union/class field */
+ struct type *anon_union_type;
+
+ /* Get space to record the next field/data-member. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ memset (new, 0, sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ list->field.name = VT (objfile) + fieldp->dfield.name;
+
+
+ /* A FIELD by itself (without a GENFIELD) can also be a static
+ member. Mark it as static with a physname of NULL.
+ fix_static_member_physnames will assign the physname later. */
+ if (fieldp->dfield.staticmem)
+ {
+ SET_FIELD_PHYSNAME (list->field, NULL);
+ FIELD_BITPOS (list->field) = 0;
+ FIELD_BITSIZE (list->field) = 0;
+ }
+ else
+ /* Non-static data member */
+ {
+ FIELD_STATIC_KIND (list->field) = 0;
+ FIELD_BITPOS (list->field) = fieldp->dfield.bitoffset;
+ if (fieldp->dfield.bitlength % 8)
+ FIELD_BITSIZE (list->field) = fieldp->dfield.bitlength;
+ else
+ FIELD_BITSIZE (list->field) = 0;
+ }
+
+ memtype = hpread_type_lookup (fieldp->dfield.type, objfile);
+ FIELD_TYPE (list->field) = memtype;
+ list->attributes = 0;
+ switch (fieldp->dfield.visibility)
+ {
+ case 1:
+ B_SET (&(list->attributes), ATTR_PROTECT);
+ break;
+ case 2:
+ B_SET (&(list->attributes), ATTR_PRIVATE);
+ break;
+ }
+ nfields++;
+
+
+ /* Note 1: First, we have to check if the current field is an anonymous
+ union. If it is, then *its* fields are threaded along in the
+ nextfield chain. :-( This was supposed to help debuggers, but is
+ really just a nuisance since we deal with anonymous unions anyway by
+ checking that the name is null. So anyway, we skip over the fields
+ of the anonymous union. pai/1997-08-22 */
+ /* Note 2: In addition, the bitoffsets for the fields of the anon union
+ are relative to the enclosing struct, *NOT* relative to the anon
+ union! This is an even bigger nuisance -- we have to go in and munge
+ the anon union's type information appropriately. pai/1997-08-22 */
+
+ /* Both tasks noted above are done by a separate function. This takes us
+ to the next FIELD or GENFIELD, skipping anon unions, and recursively
+ processing intermediate types. */
+ field = hpread_get_next_skip_over_anon_unions (1, field, &fieldp, objfile);
+
+ }
+ else
+ {
+ /* neither field nor genfield ?? is this possible?? */
+ /* pai:: FIXME walk to the next -- how? */
+ warning ("Internal error: unexpected DNTT kind %d encountered as field of struct",
+ fieldp->dblock.kind);
+ warning ("Skipping remaining fields of struct");
+ break; /* get out of loop of fields */
+ }
+ }
+
+ /* If it's a template, read in the instantiation list */
+ if (dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
+ {
+ ninstantiations = 0;
+ field = dn_bufp->dtemplate.expansions;
+ while (field.word && field.word != DNTTNIL)
+ {
+ fieldp = hpread_get_lntt (field.dnttp.index, objfile);
+
+ /* The expansions or nextexp should point to a tagdef */
+ if (fieldp->dblock.kind != DNTT_TYPE_TAGDEF)
+ break;
+
+ i_new = (struct next_instantiation *) alloca (sizeof (struct next_instantiation));
+ memset (i_new, 0, sizeof (struct next_instantiation));
+ i_new->next = i_list;
+ i_list = i_new;
+ i_list->t = hpread_type_lookup (field, objfile);
+ ninstantiations++;
+
+ /* And the "type" field of that should point to a class */
+ field = fieldp->dtag.type;
+ fieldp = hpread_get_lntt (field.dnttp.index, objfile);
+ if (fieldp->dblock.kind != DNTT_TYPE_CLASS)
+ break;
+
+ /* Get the next expansion */
+ field = fieldp->dclass.nextexp;
+ }
+ }
+ TYPE_NINSTANTIATIONS (type) = ninstantiations;
+ if (ninstantiations > 0)
+ TYPE_INSTANTIATIONS (type) = (struct type **)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct type *) * ninstantiations);
+ for (n = ninstantiations; i_list; i_list = i_list->next)
+ {
+ n -= 1;
+ TYPE_INSTANTIATION (type, n) = i_list->t;
+ }
+
+
+ /* Copy the field-list to GDB's symbol table */
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_N_BASECLASSES (type) = n_base_classes;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct field) * nfields);
+ /* Copy the saved-up fields into the field vector. */
+ for (n = nfields, tmp_list = list; tmp_list; tmp_list = tmp_list->next)
+ {
+ n -= 1;
+ TYPE_FIELD (type, n) = tmp_list->field;
+ }
+
+ /* Copy the "function-field-list" (i.e., the list of member
+ * functions in the class) to GDB's symbol table
+ */
+ TYPE_NFN_FIELDS (type) = n_fn_fields;
+ TYPE_NFN_FIELDS_TOTAL (type) = n_fn_fields_total;
+ TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct fn_fieldlist) * n_fn_fields);
+ for (n = n_fn_fields; fn_list; fn_list = fn_list->next)
+ {
+ n -= 1;
+ TYPE_FN_FIELDLIST (type, n) = fn_list->field;
+ }
+
+ /* pai:: FIXME -- perhaps each bitvector should be created individually */
+ for (n = nfields, tmp_list = list; tmp_list; tmp_list = tmp_list->next)
+ {
+ n -= 1;
+ if (tmp_list->attributes)
+ {
+ need_bitvectors = 1;
+ break;
+ }
+ }
+
+ if (need_bitvectors)
+ {
+ /* pai:: this step probably redundant */
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+
+ TYPE_FIELD_VIRTUAL_BITS (type) =
+ (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+ B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), nfields);
+
+ 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);
+
+ /* this field vector isn't actually used with HP aCC */
+ TYPE_FIELD_IGNORE_BITS (type) =
+ (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+ B_CLRALL (TYPE_FIELD_IGNORE_BITS (type), nfields);
+
+ while (nfields-- > 0)
+ {
+ if (B_TST (&(list->attributes), ATTR_VIRTUAL))
+ SET_TYPE_FIELD_VIRTUAL (type, nfields);
+ if (B_TST (&(list->attributes), ATTR_PRIVATE))
+ SET_TYPE_FIELD_PRIVATE (type, nfields);
+ if (B_TST (&(list->attributes), ATTR_PROTECT))
+ SET_TYPE_FIELD_PROTECTED (type, nfields);
+
+ list = list->next;
+ }
+ }
+ else
+ {
+ TYPE_FIELD_VIRTUAL_BITS (type) = NULL;
+ TYPE_FIELD_PROTECTED_BITS (type) = NULL;
+ TYPE_FIELD_PRIVATE_BITS (type) = NULL;
+ }
+
+ if (has_vtable (type))
+ {
+ /* Allocate space for class runtime information */
+ TYPE_RUNTIME_PTR (type) = (struct runtime_info *) xmalloc (sizeof (struct runtime_info));
+ /* Set flag for vtable */
+ TYPE_VTABLE (type) = 1;
+ /* The first non-virtual base class with a vtable. */
+ TYPE_PRIMARY_BASE (type) = primary_base_class (type);
+ /* The virtual base list. */
+ TYPE_VIRTUAL_BASE_LIST (type) = virtual_base_list (type);
+ }
+ else
+ TYPE_RUNTIME_PTR (type) = NULL;
+
+ /* If this is a local type (C++ - declared inside a function), record file name & line # */
+ if (hpread_get_scope_depth (dn_bufp, objfile, 1 /* no need for real depth */ ))
+ {
+ TYPE_LOCALTYPE_PTR (type) = (struct local_type_info *) xmalloc (sizeof (struct local_type_info));
+ TYPE_LOCALTYPE_FILE (type) = (char *) xmalloc (strlen (current_subfile->name) + 1);
+ strcpy (TYPE_LOCALTYPE_FILE (type), current_subfile->name);
+ if (current_subfile->line_vector && (current_subfile->line_vector->nitems > 0))
+ TYPE_LOCALTYPE_LINE (type) = current_subfile->line_vector->item[current_subfile->line_vector->nitems - 1].line;
+ else
+ TYPE_LOCALTYPE_LINE (type) = 0;
+ }
+ else
+ TYPE_LOCALTYPE_PTR (type) = NULL;
+
+ /* Clear the global saying what template we are in the middle of processing */
+ current_template = NULL;
+
+ return type;
+}
+
+/* Adjust the physnames for each static member of a struct
+ or class type to be something like "A::x"; then various
+ other pieces of code that do a lookup_symbol on the phyname
+ work correctly.
+ TYPE is a pointer to the struct/class type
+ NAME is a char * (string) which is the class/struct name
+ Void return */
+
+static void
+fix_static_member_physnames (struct type *type, char *class_name,
+ struct objfile *objfile)
+{
+ int i;
+
+ /* We fix the member names only for classes or structs */
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
+ return;
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ if (TYPE_FIELD_STATIC_PHYSNAME (type, i))
+ return; /* physnames are already set */
+
+ SET_FIELD_PHYSNAME (TYPE_FIELDS (type)[i],
+ obstack_alloc (&objfile->objfile_obstack,
+ strlen (class_name) + strlen (TYPE_FIELD_NAME (type, i)) + 3));
+ strcpy (TYPE_FIELD_STATIC_PHYSNAME (type, i), class_name);
+ strcat (TYPE_FIELD_STATIC_PHYSNAME (type, i), "::");
+ strcat (TYPE_FIELD_STATIC_PHYSNAME (type, i), TYPE_FIELD_NAME (type, i));
+ }
+}
+
+/* Fix-up the type structure for a CLASS so that the type entry
+ * for a method (previously marked with a null type in hpread_read_struct_type()
+ * is set correctly to METHOD.
+ * OBJFILE is as for other such functions.
+ * Void return. */
+
+static void
+fixup_class_method_type (struct type *class, struct type *method,
+ struct objfile *objfile)
+{
+ int i, j, k;
+
+ if (!class || !method || !objfile)
+ return;
+
+ /* Only for types that have methods */
+ if ((TYPE_CODE (class) != TYPE_CODE_CLASS) &&
+ (TYPE_CODE (class) != TYPE_CODE_UNION))
+ return;
+
+ /* Loop over all methods and find the one marked with a NULL type */
+ for (i = 0; i < TYPE_NFN_FIELDS (class); i++)
+ for (j = 0; j < TYPE_FN_FIELDLIST_LENGTH (class, i); j++)
+ if (TYPE_FN_FIELD_TYPE (TYPE_FN_FIELDLIST1 (class, i), j) == NULL)
+ {
+ /* Set the method type */
+ TYPE_FN_FIELD_TYPE (TYPE_FN_FIELDLIST1 (class, i), j) = method;
+
+ /* Break out of both loops -- only one method to fix up in a class */
+ goto finish;
+ }
+
+finish:
+ TYPE_FLAGS (class) &= ~TYPE_FLAG_INCOMPLETE;
+}
+
+
+/* If we're in the middle of processing a template, get a pointer
+ * to the Nth template argument.
+ * An example may make this clearer:
+ * template <class T1, class T2> class q2 {
+ * public:
+ * T1 a;
+ * T2 b;
+ * };
+ * The type for "a" will be "first template arg" and
+ * the type for "b" will be "second template arg".
+ * We need to look these up in order to fill in "a" and "b"'s type.
+ * This is called from hpread_type_lookup().
+ */
+static struct type *
+hpread_get_nth_template_arg (struct objfile *objfile, int n)
+{
+ if (current_template != NULL)
+ return TYPE_TEMPLATE_ARG (current_template, n).type;
+ else
+ return lookup_fundamental_type (objfile, FT_TEMPLATE_ARG);
+}
+
+/* Read in and internalize a TEMPL_ARG (template arg) symbol. */
+
+static struct type *
+hpread_read_templ_arg_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile, char *name)
+{
+ struct type *type;
+
+ /* See if it's something we've already deal with. */
+ type = hpread_alloc_type (hp_type, objfile);
+ if (TYPE_CODE (type) == TYPE_CODE_TEMPLATE_ARG)
+ return type;
+
+ /* Nope. Fill in the appropriate fields. */
+ TYPE_CODE (type) = TYPE_CODE_TEMPLATE_ARG;
+ TYPE_LENGTH (type) = 0;
+ TYPE_NFIELDS (type) = 0;
+ TYPE_NAME (type) = name;
+ return type;
+}
+
+/* Read in and internalize a set debug symbol. */
+
+static struct type *
+hpread_read_set_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile)
+{
+ struct type *type;
+
+ /* See if it's something we've already deal with. */
+ type = hpread_alloc_type (hp_type, objfile);
+ if (TYPE_CODE (type) == TYPE_CODE_SET)
+ return type;
+
+ /* Nope. Fill in the appropriate fields. */
+ TYPE_CODE (type) = TYPE_CODE_SET;
+ TYPE_LENGTH (type) = dn_bufp->dset.bitlength / 8;
+ TYPE_NFIELDS (type) = 0;
+ TYPE_TARGET_TYPE (type) = hpread_type_lookup (dn_bufp->dset.subtype,
+ objfile);
+ return type;
+}
+
+/* Read in and internalize an array debug symbol. */
+
+static struct type *
+hpread_read_array_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile)
+{
+ struct type *type;
+
+ /* Allocate an array type symbol.
+ * Why no check for already-read here, like in the other
+ * hpread_read_xxx_type routines? Because it kept us
+ * from properly determining the size of the array!
+ */
+ type = hpread_alloc_type (hp_type, objfile);
+
+ TYPE_CODE (type) = TYPE_CODE_ARRAY;
+
+ /* Although the hp-symtab.h does not *require* this to be the case,
+ * GDB is assuming that "arrayisbytes" and "elemisbytes" be consistent.
+ * I.e., express both array-length and element-length in bits,
+ * or express both array-length and element-length in bytes.
+ */
+ if (!((dn_bufp->darray.arrayisbytes && dn_bufp->darray.elemisbytes) ||
+ (!dn_bufp->darray.arrayisbytes && !dn_bufp->darray.elemisbytes)))
+ {
+ warning ("error in hpread_array_type.\n");
+ return NULL;
+ }
+ else if (dn_bufp->darray.arraylength == 0x7fffffff)
+ {
+ /* The HP debug format represents char foo[]; as an array with
+ * length 0x7fffffff. Internally GDB wants to represent this
+ * as an array of length zero.
+ */
+ TYPE_LENGTH (type) = 0;
+ }
+ else if (dn_bufp->darray.arrayisbytes)
+ TYPE_LENGTH (type) = dn_bufp->darray.arraylength;
+ else /* arraylength is in bits */
+ TYPE_LENGTH (type) = dn_bufp->darray.arraylength / 8;
+
+ TYPE_TARGET_TYPE (type) = hpread_type_lookup (dn_bufp->darray.elemtype,
+ objfile);
+
+ /* The one "field" is used to store the subscript type */
+ /* Since C and C++ multi-dimensional arrays are simply represented
+ * as: array of array of ..., we only need one subscript-type
+ * per array. This subscript type is typically a subrange of integer.
+ * If this gets extended to support languages like Pascal, then
+ * we need to fix this to represent multi-dimensional arrays properly.
+ */
+ TYPE_NFIELDS (type) = 1;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct field));
+ TYPE_FIELD_TYPE (type, 0) = hpread_type_lookup (dn_bufp->darray.indextype,
+ objfile);
+ return type;
+}
+
+/* Read in and internalize a subrange debug symbol. */
+static struct type *
+hpread_read_subrange_type (dnttpointer hp_type, union dnttentry *dn_bufp,
+ struct objfile *objfile)
+{
+ struct type *type;
+
+ /* Is it something we've already dealt with. */
+ type = hpread_alloc_type (hp_type, objfile);
+ if (TYPE_CODE (type) == TYPE_CODE_RANGE)
+ return type;
+
+ /* Nope, internalize it. */
+ TYPE_CODE (type) = TYPE_CODE_RANGE;
+ TYPE_LENGTH (type) = dn_bufp->dsubr.bitlength / 8;
+ TYPE_NFIELDS (type) = 2;
+ TYPE_FIELDS (type)
+ = (struct field *) obstack_alloc (&objfile->objfile_obstack,
+ 2 * sizeof (struct field));
+
+ if (dn_bufp->dsubr.dyn_low)
+ TYPE_FIELD_BITPOS (type, 0) = 0;
+ else
+ TYPE_FIELD_BITPOS (type, 0) = dn_bufp->dsubr.lowbound;
+
+ if (dn_bufp->dsubr.dyn_high)
+ TYPE_FIELD_BITPOS (type, 1) = -1;
+ else
+ TYPE_FIELD_BITPOS (type, 1) = dn_bufp->dsubr.highbound;
+ TYPE_TARGET_TYPE (type) = hpread_type_lookup (dn_bufp->dsubr.subtype,
+ objfile);
+ return type;
+}
+
+/* struct type * hpread_type_lookup(hp_type, objfile)
+ * Arguments:
+ * hp_type: A pointer into the DNTT specifying what type we
+ * are about to "look up"., or else [for fundamental types
+ * like int, float, ...] an "immediate" structure describing
+ * the type.
+ * objfile: ?
+ * Return value: A pointer to a "struct type" (representation of a
+ * type in GDB's internal symbol table - see gdbtypes.h)
+ * Routine description:
+ * There are a variety of places when scanning the DNTT when we
+ * need to interpret a "type" field. The simplest and most basic
+ * example is when we're processing the symbol table record
+ * for a data symbol (a SVAR or DVAR record). That has
+ * a "type" field specifying the type of the data symbol. That
+ * "type" field is either an "immediate" type specification (for the
+ * fundamental types) or a DNTT pointer (for more complicated types).
+ * For the more complicated types, we may or may not have already
+ * processed the pointed-to type. (Multiple data symbols can of course
+ * share the same type).
+ * The job of hpread_type_lookup() is to process this "type" field.
+ * Most of the real work is done in subroutines. Here we interpret
+ * the immediate flag. If not immediate, chase the DNTT pointer to
+ * find our way to the SOM record describing the type, switch on
+ * the SOM kind, and then call an appropriate subroutine depending
+ * on what kind of type we are constructing. (e.g., an array type,
+ * a struct/class type, etc).
+ */
+static struct type *
+hpread_type_lookup (dnttpointer hp_type, struct objfile *objfile)
+{
+ union dnttentry *dn_bufp;
+ struct type *tmp_type;
+
+ /* First see if it's a simple builtin type. */
+ if (hp_type.dntti.immediate)
+ {
+ /* If this is a template argument, the argument number is
+ * encoded in the bitlength. All other cases, just return
+ * GDB's representation of this fundamental type.
+ */
+ if (hp_type.dntti.type == HP_TYPE_TEMPLATE_ARG)
+ return hpread_get_nth_template_arg (objfile, hp_type.dntti.bitlength);
+ else
+ return lookup_fundamental_type (objfile,
+ hpread_type_translate (hp_type));
+ }
+
+ /* Not a builtin type. We'll have to read it in. */
+ if (hp_type.dnttp.index < LNTT_SYMCOUNT (objfile))
+ dn_bufp = hpread_get_lntt (hp_type.dnttp.index, objfile);
+ else
+ /* This is a fancy way of returning NULL */
+ return lookup_fundamental_type (objfile, FT_VOID);
+
+ switch (dn_bufp->dblock.kind)
+ {
+ case DNTT_TYPE_SRCFILE:
+ case DNTT_TYPE_MODULE:
+ case DNTT_TYPE_ENTRY:
+ case DNTT_TYPE_BEGIN:
+ case DNTT_TYPE_END:
+ case DNTT_TYPE_IMPORT:
+ case DNTT_TYPE_LABEL:
+ case DNTT_TYPE_FPARAM:
+ case DNTT_TYPE_SVAR:
+ case DNTT_TYPE_DVAR:
+ case DNTT_TYPE_CONST:
+ case DNTT_TYPE_MEMENUM:
+ case DNTT_TYPE_VARIANT:
+ case DNTT_TYPE_FILE:
+ case DNTT_TYPE_WITH:
+ case DNTT_TYPE_COMMON:
+ case DNTT_TYPE_COBSTRUCT:
+ case DNTT_TYPE_XREF:
+ case DNTT_TYPE_SA:
+ case DNTT_TYPE_MACRO:
+ case DNTT_TYPE_BLOCKDATA:
+ case DNTT_TYPE_CLASS_SCOPE:
+ case DNTT_TYPE_MEMACCESS:
+ case DNTT_TYPE_INHERITANCE:
+ case DNTT_TYPE_OBJECT_ID:
+ case DNTT_TYPE_FRIEND_CLASS:
+ case DNTT_TYPE_FRIEND_FUNC:
+ /* These are not types - something went wrong. */
+ /* This is a fancy way of returning NULL */
+ return lookup_fundamental_type (objfile, FT_VOID);
+
+ case DNTT_TYPE_FUNCTION:
+ /* We wind up here when dealing with class member functions
+ * (called from hpread_read_struct_type(), i.e. when processing
+ * the class definition itself).
+ */
+ return hpread_read_function_type (hp_type, dn_bufp, objfile, 0);
+
+ case DNTT_TYPE_DOC_FUNCTION:
+ return hpread_read_doc_function_type (hp_type, dn_bufp, objfile, 0);
+
+ case DNTT_TYPE_TYPEDEF:
+ {
+ /* A typedef - chase it down by making a recursive call */
+ struct type *structtype = hpread_type_lookup (dn_bufp->dtype.type,
+ objfile);
+
+ /* The following came from the base hpread.c that we inherited.
+ * It is WRONG so I have commented it out. - RT
+ *...
+
+ char *suffix;
+ suffix = VT (objfile) + dn_bufp->dtype.name;
+ TYPE_NAME (structtype) = suffix;
+
+ * ... further explanation ....
+ *
+ * What we have here is a typedef pointing to a typedef.
+ * E.g.,
+ * typedef int foo;
+ * typedef foo fum;
+ *
+ * What we desire to build is (these are pictures
+ * of "struct type"'s):
+ *
+ * +---------+ +----------+ +------------+
+ * | typedef | | typedef | | fund. type |
+ * | type| -> | type| -> | |
+ * | "fum" | | "foo" | | "int" |
+ * +---------+ +----------+ +------------+
+ *
+ * What this commented-out code is doing is smashing the
+ * name of pointed-to-type to be the same as the pointed-from
+ * type. So we wind up with something like:
+ *
+ * +---------+ +----------+ +------------+
+ * | typedef | | typedef | | fund. type |
+ * | type| -> | type| -> | |
+ * | "fum" | | "fum" | | "fum" |
+ * +---------+ +----------+ +------------+
+ *
+ */
+
+ return structtype;
+ }
+
+ case DNTT_TYPE_TAGDEF:
+ {
+ /* Just a little different from above. We have to tack on
+ * an identifier of some kind (struct, union, enum, class, etc).
+ */
+ struct type *structtype = hpread_type_lookup (dn_bufp->dtype.type,
+ objfile);
+ char *prefix, *suffix;
+ suffix = VT (objfile) + dn_bufp->dtype.name;
+
+ /* Lookup the next type in the list. It should be a structure,
+ * union, class, enum, or template type.
+ * We will need to attach that to our name.
+ */
+ if (dn_bufp->dtype.type.dnttp.index < LNTT_SYMCOUNT (objfile))
+ dn_bufp = hpread_get_lntt (dn_bufp->dtype.type.dnttp.index, objfile);
+ else
+ {
+ complaint (&symfile_complaints, "error in hpread_type_lookup().");
+ return NULL;
+ }
+
+ if (dn_bufp->dblock.kind == DNTT_TYPE_STRUCT)
+ {
+ prefix = "struct ";
+ }
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_UNION)
+ {
+ prefix = "union ";
+ }
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_CLASS)
+ {
+ /* Further field for CLASS saying how it was really declared */
+ /* 0==class, 1==union, 2==struct */
+ if (dn_bufp->dclass.class_decl == 0)
+ prefix = "class ";
+ else if (dn_bufp->dclass.class_decl == 1)
+ prefix = "union ";
+ else if (dn_bufp->dclass.class_decl == 2)
+ prefix = "struct ";
+ else
+ prefix = "";
+ }
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_ENUM)
+ {
+ prefix = "enum ";
+ }
+ else if (dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
+ {
+ prefix = "template ";
+ }
+ else
+ {
+ prefix = "";
+ }
+
+ /* Build the correct name. */
+ TYPE_NAME (structtype)
+ = (char *) obstack_alloc (&objfile->objfile_obstack,
+ strlen (prefix) + strlen (suffix) + 1);
+ TYPE_NAME (structtype) = strcpy (TYPE_NAME (structtype), prefix);
+ TYPE_NAME (structtype) = strcat (TYPE_NAME (structtype), suffix);
+ TYPE_TAG_NAME (structtype) = suffix;
+
+ /* For classes/structs, we have to set the static member "physnames"
+ to point to strings like "Class::Member" */
+ if (TYPE_CODE (structtype) == TYPE_CODE_STRUCT)
+ fix_static_member_physnames (structtype, suffix, objfile);
+
+ return structtype;
+ }
+
+ case DNTT_TYPE_POINTER:
+ /* Pointer type - call a routine in gdbtypes.c that constructs
+ * the appropriate GDB type.
+ */
+ return make_pointer_type (
+ hpread_type_lookup (dn_bufp->dptr.pointsto,
+ objfile),
+ NULL);
+
+ case DNTT_TYPE_REFERENCE:
+ /* C++ reference type - call a routine in gdbtypes.c that constructs
+ * the appropriate GDB type.
+ */
+ return make_reference_type (
+ hpread_type_lookup (dn_bufp->dreference.pointsto,
+ objfile),
+ NULL);
+
+ case DNTT_TYPE_ENUM:
+ return hpread_read_enum_type (hp_type, dn_bufp, objfile);
+ case DNTT_TYPE_SET:
+ return hpread_read_set_type (hp_type, dn_bufp, objfile);
+ case DNTT_TYPE_SUBRANGE:
+ return hpread_read_subrange_type (hp_type, dn_bufp, objfile);
+ case DNTT_TYPE_ARRAY:
+ return hpread_read_array_type (hp_type, dn_bufp, objfile);
+ case DNTT_TYPE_STRUCT:
+ case DNTT_TYPE_UNION:
+ return hpread_read_struct_type (hp_type, dn_bufp, objfile);
+ case DNTT_TYPE_FIELD:
+ return hpread_type_lookup (dn_bufp->dfield.type, objfile);
+
+ case DNTT_TYPE_FUNCTYPE:
+ /* Here we want to read the function SOMs and return a
+ * type for it. We get here, for instance, when processing
+ * pointer-to-function type.
+ */
+ return hpread_read_function_type (hp_type, dn_bufp, objfile, 0);
+
+ case DNTT_TYPE_PTRMEM:
+ /* Declares a C++ pointer-to-data-member type.
+ * The "pointsto" field defines the class,
+ * while the "memtype" field defines the pointed-to-type.
+ */
+ {
+ struct type *ptrmemtype;
+ struct type *class_type;
+ struct type *memtype;
+ memtype = hpread_type_lookup (dn_bufp->dptrmem.memtype,
+ objfile),
+ class_type = hpread_type_lookup (dn_bufp->dptrmem.pointsto,
+ objfile),
+ ptrmemtype = alloc_type (objfile);
+ smash_to_member_type (ptrmemtype, class_type, memtype);
+ return make_pointer_type (ptrmemtype, NULL);
+ }
+ break;
+
+ case DNTT_TYPE_PTRMEMFUNC:
+ /* Defines a C++ pointer-to-function-member type.
+ * The "pointsto" field defines the class,
+ * while the "memtype" field defines the pointed-to-type.
+ */
+ {
+ struct type *ptrmemtype;
+ struct type *class_type;
+ struct type *functype;
+ struct type *retvaltype;
+ int nargs;
+ int i;
+ class_type = hpread_type_lookup (dn_bufp->dptrmem.pointsto,
+ objfile);
+ functype = hpread_type_lookup (dn_bufp->dptrmem.memtype,
+ objfile);
+ retvaltype = TYPE_TARGET_TYPE (functype);
+ nargs = TYPE_NFIELDS (functype);
+ ptrmemtype = alloc_type (objfile);
+
+ smash_to_method_type (ptrmemtype, class_type, retvaltype,
+ TYPE_FIELDS (functype),
+ TYPE_NFIELDS (functype),
+ 0);
+ return make_pointer_type (ptrmemtype, NULL);
+ }
+ break;
+
+ case DNTT_TYPE_CLASS:
+ return hpread_read_struct_type (hp_type, dn_bufp, objfile);
+
+ case DNTT_TYPE_GENFIELD:
+ /* Chase pointer from GENFIELD to FIELD, and make recursive
+ * call on that.
+ */
+ return hpread_type_lookup (dn_bufp->dgenfield.field, objfile);
+
+ case DNTT_TYPE_VFUNC:
+ /* C++ virtual function.
+ * We get here in the course of processing a class type which
+ * contains virtual functions. Just go through another level
+ * of indirection to get to the pointed-to function SOM.
+ */
+ return hpread_type_lookup (dn_bufp->dvfunc.funcptr, objfile);
+
+ case DNTT_TYPE_MODIFIER:
+ /* Check the modifiers and then just make a recursive call on
+ * the "type" pointed to by the modifier DNTT.
+ *
+ * pai:: FIXME -- do we ever want to handle "m_duplicate" and
+ * "m_void" modifiers? Is static_flag really needed here?
+ * (m_static used for methods of classes, elsewhere).
+ */
+ tmp_type = make_cv_type (dn_bufp->dmodifier.m_const,
+ dn_bufp->dmodifier.m_volatile,
+ hpread_type_lookup (dn_bufp->dmodifier.type, objfile),
+ 0);
+ return tmp_type;
+
+
+ case DNTT_TYPE_MEMFUNC:
+ /* Member function. Treat like a function.
+ * I think we get here in the course of processing a
+ * pointer-to-member-function type...
+ */
+ return hpread_read_function_type (hp_type, dn_bufp, objfile, 0);
+
+ case DNTT_TYPE_DOC_MEMFUNC:
+ return hpread_read_doc_function_type (hp_type, dn_bufp, objfile, 0);
+
+ case DNTT_TYPE_TEMPLATE:
+ /* Template - sort of the header for a template definition,
+ * which like a class, points to a member list and also points
+ * to a TEMPLATE_ARG list of type-arguments.
+ */
+ return hpread_read_struct_type (hp_type, dn_bufp, objfile);
+
+ case DNTT_TYPE_TEMPLATE_ARG:
+ {
+ char *name;
+ /* The TEMPLATE record points to an argument list of
+ * TEMPLATE_ARG records, each of which describes one
+ * of the type-arguments.
+ */
+ name = VT (objfile) + dn_bufp->dtempl_arg.name;
+ return hpread_read_templ_arg_type (hp_type, dn_bufp, objfile, name);
+ }
+
+ case DNTT_TYPE_FUNC_TEMPLATE:
+ /* We wind up here when processing a TEMPLATE type,
+ * if the template has member function(s).
+ * Treat it like a FUNCTION.
+ */
+ return hpread_read_function_type (hp_type, dn_bufp, objfile, 0);
+
+ case DNTT_TYPE_LINK:
+ /* The LINK record is used to link up templates with instantiations.
+ * There is no type associated with the LINK record per se.
+ */
+ return lookup_fundamental_type (objfile, FT_VOID);
+
+ /* Also not yet handled... */
+ /* case DNTT_TYPE_DYN_ARRAY_DESC: */
+ /* case DNTT_TYPE_DESC_SUBRANGE: */
+ /* case DNTT_TYPE_BEGIN_EXT: */
+ /* case DNTT_TYPE_INLN: */
+ /* case DNTT_TYPE_INLN_LIST: */
+ /* case DNTT_TYPE_ALIAS: */
+ default:
+ /* A fancy way of returning NULL */
+ return lookup_fundamental_type (objfile, FT_VOID);
+ }
+}
+
+static sltpointer
+hpread_record_lines (struct subfile *subfile, sltpointer s_idx,
+ sltpointer e_idx, struct objfile *objfile,
+ CORE_ADDR offset)
+{
+ union sltentry *sl_bufp;
+
+ while (s_idx <= e_idx)
+ {
+ sl_bufp = hpread_get_slt (s_idx, objfile);
+ /* Only record "normal" entries in the SLT. */
+ if (sl_bufp->snorm.sltdesc == SLT_NORMAL
+ || sl_bufp->snorm.sltdesc == SLT_EXIT)
+ record_line (subfile, sl_bufp->snorm.line,
+ sl_bufp->snorm.address + offset);
+ else if (sl_bufp->snorm.sltdesc == SLT_NORMAL_OFFSET)
+ record_line (subfile, sl_bufp->snormoff.line,
+ sl_bufp->snormoff.address + offset);
+ s_idx++;
+ }
+ return e_idx;
+}
+
+/* Given a function "f" which is a member of a class, find
+ * the classname that it is a member of. Used to construct
+ * the name (e.g., "c::f") which GDB will put in the
+ * "demangled name" field of the function's symbol.
+ * Called from hpread_process_one_debug_symbol()
+ * If "f" is not a member function, return NULL.
+ */
+static char *
+class_of (struct type *functype)
+{
+ struct type *first_param_type;
+ char *first_param_name;
+ struct type *pointed_to_type;
+ char *class_name;
+
+ /* Check that the function has a first argument "this",
+ * and that "this" is a pointer to a class. If not,
+ * functype is not a member function, so return NULL.
+ */
+ if (TYPE_NFIELDS (functype) == 0)
+ return NULL;
+ first_param_name = TYPE_FIELD_NAME (functype, 0);
+ if (first_param_name == NULL)
+ return NULL; /* paranoia */
+ if (strcmp (first_param_name, "this"))
+ return NULL;
+ first_param_type = TYPE_FIELD_TYPE (functype, 0);
+ if (first_param_type == NULL)
+ return NULL; /* paranoia */
+ if (TYPE_CODE (first_param_type) != TYPE_CODE_PTR)
+ return NULL;
+
+ /* Get the thing that "this" points to, check that
+ * it's a class, and get its class name.
+ */
+ pointed_to_type = TYPE_TARGET_TYPE (first_param_type);
+ if (pointed_to_type == NULL)
+ return NULL; /* paranoia */
+ if (TYPE_CODE (pointed_to_type) != TYPE_CODE_CLASS)
+ return NULL;
+ class_name = TYPE_NAME (pointed_to_type);
+ if (class_name == NULL)
+ return NULL; /* paranoia */
+
+ /* The class name may be of the form "class c", in which case
+ * we want to strip off the leading "class ".
+ */
+ if (strncmp (class_name, "class ", 6) == 0)
+ class_name += 6;
+
+ return class_name;
+}
+
+/* Internalize one native debug symbol.
+ * Called in a loop from hpread_expand_symtab().
+ * Arguments:
+ * dn_bufp:
+ * name:
+ * section_offsets:
+ * objfile:
+ * text_offset:
+ * text_size:
+ * filename:
+ * index: Index of this symbol
+ * at_module_boundary_p Pointer to boolean flag to control caller's loop.
+ */
+
+static void
+hpread_process_one_debug_symbol (union dnttentry *dn_bufp, char *name,
+ struct section_offsets *section_offsets,
+ struct objfile *objfile, CORE_ADDR text_offset,
+ int text_size, char *filename, int index,
+ int *at_module_boundary_p)
+{
+ unsigned long desc;
+ int type;
+ CORE_ADDR valu;
+ int offset = ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile));
+ int data_offset = ANOFFSET (section_offsets, SECT_OFF_DATA (objfile));
+ union dnttentry *dn_temp;
+ dnttpointer hp_type;
+ struct symbol *sym;
+ struct context_stack *new;
+ char *class_scope_name;
+
+ /* Allocate one GDB debug symbol and fill in some default values. */
+ sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (sym) = obsavestring (name, strlen (name), &objfile->objfile_obstack);
+ SYMBOL_LANGUAGE (sym) = language_auto;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ SYMBOL_LINE (sym) = 0;
+ SYMBOL_VALUE (sym) = 0;
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+
+ /* Just a trick in case the SOM debug symbol is a type definition.
+ * There are routines that are set up to build a GDB type symbol, given
+ * a SOM dnttpointer. So we set up a dummy SOM dnttpointer "hp_type".
+ * This allows us to call those same routines.
+ */
+ hp_type.dnttp.extension = 1;
+ hp_type.dnttp.immediate = 0;
+ hp_type.dnttp.global = 0;
+ hp_type.dnttp.index = index;
+
+ /* This "type" is the type of SOM record.
+ * Switch on SOM type.
+ */
+ type = dn_bufp->dblock.kind;
+ switch (type)
+ {
+ case DNTT_TYPE_SRCFILE:
+ /* This type of symbol indicates from which source file or
+ * include file any following data comes. It may indicate:
+ *
+ * o The start of an entirely new source file (and thus
+ * a new module)
+ *
+ * o The start of a different source file due to #include
+ *
+ * o The end of an include file and the return to the original
+ * file. Thus if "foo.c" includes "bar.h", we see first
+ * a SRCFILE for foo.c, then one for bar.h, and then one for
+ * foo.c again.
+ *
+ * If it indicates the start of a new module then we must
+ * finish the symbol table of the previous module
+ * (if any) and start accumulating a new symbol table.
+ */
+
+ valu = text_offset;
+ if (!last_source_file)
+ {
+ /*
+ * A note on "last_source_file": this is a char* pointing
+ * to the actual file name. "start_symtab" sets it,
+ * "end_symtab" clears it.
+ *
+ * So if "last_source_file" is NULL, then either this is
+ * the first record we are looking at, or a previous call
+ * to "end_symtab()" was made to close out the previous
+ * module. Since we're now quitting the scan loop when we
+ * see a MODULE END record, we should never get here, except
+ * in the case that we're not using the quick look-up tables
+ * and have to use the old system as a fall-back.
+ */
+ start_symtab (name, NULL, valu);
+ record_debugformat ("HP");
+ SL_INDEX (objfile) = dn_bufp->dsfile.address;
+ }
+
+ else
+ {
+ /* Either a new include file, or a SRCFILE record
+ * saying we are back in the main source (or out of
+ * a nested include file) again.
+ */
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->dsfile.address,
+ objfile, offset);
+ }
+
+ /* A note on "start_subfile". This routine will check
+ * the name we pass it and look for an existing subfile
+ * of that name. There's thus only one sub-file for the
+ * actual source (e.g. for "foo.c" in foo.c), despite the
+ * fact that we'll see lots of SRCFILE entries for foo.c
+ * inside foo.c.
+ */
+ start_subfile (name, NULL);
+ break;
+
+ case DNTT_TYPE_MODULE:
+ /*
+ * We no longer ignore DNTT_TYPE_MODULE symbols. The module
+ * represents the meaningful semantic structure of a compilation
+ * unit. We expect to start the psymtab-to-symtab expansion
+ * looking at a MODULE entry, and to end it at the corresponding
+ * END MODULE entry.
+ *
+ *--Begin outdated comments
+ *
+ * This record signifies the start of a new source module
+ * In C/C++ there is no explicit "module" construct in the language,
+ * but each compilation unit is implicitly a module and they
+ * do emit the DNTT_TYPE_MODULE records.
+ * The end of the module is marked by a matching DNTT_TYPE_END record.
+ *
+ * The reason GDB gets away with ignoring the DNTT_TYPE_MODULE record
+ * is it notices the DNTT_TYPE_END record for the previous
+ * module (see comments under DNTT_TYPE_END case), and then treats
+ * the next DNTT_TYPE_SRCFILE record as if it were the module-start record.
+ * (i.e., it makes a start_symtab() call).
+ * This scheme seems a little convoluted, but I'll leave it
+ * alone on the principle "if it ain't broke don't fix
+ * it". (RT).
+ *
+ *-- End outdated comments
+ */
+
+ valu = text_offset;
+ if (!last_source_file)
+ {
+ /* Start of a new module. We know this because "last_source_file"
+ * is NULL, which can only happen the first time or if we just
+ * made a call to end_symtab() to close out the previous module.
+ */
+ start_symtab (name, NULL, valu);
+ SL_INDEX (objfile) = dn_bufp->dmodule.address;
+ }
+ else
+ {
+ /* This really shouldn't happen if we're using the quick
+ * look-up tables, as it would mean we'd scanned past an
+ * END MODULE entry. But if we're not using the tables,
+ * we started the module on the SRCFILE entry, so it's ok.
+ * For now, accept this.
+ */
+ /* warning( "Error expanding psymtab, missed module end, found entry for %s",
+ * name );
+ */
+ *at_module_boundary_p = -1;
+ }
+
+ start_subfile (name, NULL);
+ break;
+
+ case DNTT_TYPE_FUNCTION:
+ case DNTT_TYPE_ENTRY:
+ /* A function or secondary entry point. */
+ valu = dn_bufp->dfunc.lowaddr + offset;
+
+ /* Record lines up to this point. */
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->dfunc.address,
+ objfile, offset);
+
+ WITHIN_FUNCTION (objfile) = 1;
+ CURRENT_FUNCTION_VALUE (objfile) = valu;
+
+ /* Stack must be empty now. */
+ if (context_stack_depth != 0)
+ lbrac_unmatched_complaint (symnum);
+ new = push_context (0, valu);
+
+ /* Built a type for the function. This includes processing
+ * the symbol records for the function parameters.
+ */
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_TYPE (sym) = hpread_read_function_type (hp_type, dn_bufp, objfile, 1);
+
+ /* All functions in C++ have prototypes. For C we don't have enough
+ information in the debug info. */
+ if (SYMBOL_LANGUAGE (sym) == language_cplus)
+ TYPE_FLAGS (SYMBOL_TYPE (sym)) |= TYPE_FLAG_PROTOTYPED;
+
+ /* The "DEPRECATED_SYMBOL_NAME" field is expected to be the mangled name
+ * (if any), which we get from the "alias" field of the SOM record
+ * if that exists.
+ */
+ if ((dn_bufp->dfunc.language == HP_LANGUAGE_CPLUSPLUS) &&
+ dn_bufp->dfunc.alias && /* has an alias */
+ *(char *) (VT (objfile) + dn_bufp->dfunc.alias)) /* not a null string */
+ DEPRECATED_SYMBOL_NAME (sym) = VT (objfile) + dn_bufp->dfunc.alias;
+ else
+ DEPRECATED_SYMBOL_NAME (sym) = VT (objfile) + dn_bufp->dfunc.name;
+
+ /* Special hack to get around HP compilers' insistence on
+ * reporting "main" as "_MAIN_" for C/C++ */
+ if ((strcmp (DEPRECATED_SYMBOL_NAME (sym), "_MAIN_") == 0) &&
+ (strcmp (VT (objfile) + dn_bufp->dfunc.name, "main") == 0))
+ DEPRECATED_SYMBOL_NAME (sym) = VT (objfile) + dn_bufp->dfunc.name;
+
+ /* The SYMBOL_CPLUS_DEMANGLED_NAME field is expected to
+ * be the demangled name.
+ */
+ if (dn_bufp->dfunc.language == HP_LANGUAGE_CPLUSPLUS)
+ {
+ /* SYMBOL_INIT_DEMANGLED_NAME is a macro which winds up
+ * calling the demangler in libiberty (cplus_demangle()) to
+ * do the job. This generally does the job, even though
+ * it's intended for the GNU compiler and not the aCC compiler
+ * Note that SYMBOL_INIT_DEMANGLED_NAME calls the
+ * demangler with arguments DMGL_PARAMS | DMGL_ANSI.
+ * Generally, we don't want params when we display
+ * a demangled name, but when I took out the DMGL_PARAMS,
+ * some things broke, so I'm leaving it in here, and
+ * working around the issue in stack.c. - RT
+ */
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->objfile_obstack);
+ if ((DEPRECATED_SYMBOL_NAME (sym) == VT (objfile) + dn_bufp->dfunc.alias) &&
+ (!SYMBOL_CPLUS_DEMANGLED_NAME (sym)))
+ {
+
+ /* Well, the symbol name is mangled, but the
+ * demangler in libiberty failed so the demangled
+ * field is still NULL. Try to
+ * do the job ourselves based on the "name" field
+ * in the SOM record. A complication here is that
+ * the name field contains only the function name
+ * (like "f"), whereas we want the class qualification
+ * (as in "c::f"). Try to reconstruct that.
+ */
+ char *basename;
+ char *classname;
+ char *dem_name;
+ basename = VT (objfile) + dn_bufp->dfunc.name;
+ classname = class_of (SYMBOL_TYPE (sym));
+ if (classname)
+ {
+ dem_name = xmalloc (strlen (basename) + strlen (classname) + 3);
+ strcpy (dem_name, classname);
+ strcat (dem_name, "::");
+ strcat (dem_name, basename);
+ SYMBOL_CPLUS_DEMANGLED_NAME (sym) = dem_name;
+ SYMBOL_LANGUAGE (sym) = language_cplus;
+ }
+ }
+ }
+
+ /* Add the function symbol to the list of symbols in this blockvector */
+ if (dn_bufp->dfunc.global)
+ add_symbol_to_list (sym, &global_symbols);
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ new->name = sym;
+
+ /* Search forward to the next BEGIN and also read
+ * in the line info up to that point.
+ * Not sure why this is needed.
+ * In HP FORTRAN this code is harmful since there
+ * may not be a BEGIN after the FUNCTION.
+ * So I made it C/C++ specific. - RT
+ */
+ if (dn_bufp->dfunc.language == HP_LANGUAGE_C ||
+ dn_bufp->dfunc.language == HP_LANGUAGE_CPLUSPLUS)
+ {
+ while (dn_bufp->dblock.kind != DNTT_TYPE_BEGIN)
+ {
+ dn_bufp = hpread_get_lntt (++index, objfile);
+ if (dn_bufp->dblock.extension)
+ continue;
+ }
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->dbegin.address,
+ objfile, offset);
+ SYMBOL_LINE (sym) = hpread_get_line (dn_bufp->dbegin.address, objfile);
+ }
+ record_line (current_subfile, SYMBOL_LINE (sym), valu);
+ break;
+
+ case DNTT_TYPE_DOC_FUNCTION:
+ valu = dn_bufp->ddocfunc.lowaddr + offset;
+
+ /* Record lines up to this point. */
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->ddocfunc.address,
+ objfile, offset);
+
+ WITHIN_FUNCTION (objfile) = 1;
+ CURRENT_FUNCTION_VALUE (objfile) = valu;
+ /* Stack must be empty now. */
+ if (context_stack_depth != 0)
+ lbrac_unmatched_complaint (symnum);
+ new = push_context (0, valu);
+
+ /* Built a type for the function. This includes processing
+ * the symbol records for the function parameters.
+ */
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_TYPE (sym) = hpread_read_doc_function_type (hp_type, dn_bufp, objfile, 1);
+
+ /* The "DEPRECATED_SYMBOL_NAME" field is expected to be the mangled name
+ * (if any), which we get from the "alias" field of the SOM record
+ * if that exists.
+ */
+ if ((dn_bufp->ddocfunc.language == HP_LANGUAGE_CPLUSPLUS) &&
+ dn_bufp->ddocfunc.alias && /* has an alias */
+ *(char *) (VT (objfile) + dn_bufp->ddocfunc.alias)) /* not a null string */
+ DEPRECATED_SYMBOL_NAME (sym) = VT (objfile) + dn_bufp->ddocfunc.alias;
+ else
+ DEPRECATED_SYMBOL_NAME (sym) = VT (objfile) + dn_bufp->ddocfunc.name;
+
+ /* Special hack to get around HP compilers' insistence on
+ * reporting "main" as "_MAIN_" for C/C++ */
+ if ((strcmp (DEPRECATED_SYMBOL_NAME (sym), "_MAIN_") == 0) &&
+ (strcmp (VT (objfile) + dn_bufp->ddocfunc.name, "main") == 0))
+ DEPRECATED_SYMBOL_NAME (sym) = VT (objfile) + dn_bufp->ddocfunc.name;
+
+ if (dn_bufp->ddocfunc.language == HP_LANGUAGE_CPLUSPLUS)
+ {
+
+ /* SYMBOL_INIT_DEMANGLED_NAME is a macro which winds up
+ * calling the demangler in libiberty (cplus_demangle()) to
+ * do the job. This generally does the job, even though
+ * it's intended for the GNU compiler and not the aCC compiler
+ * Note that SYMBOL_INIT_DEMANGLED_NAME calls the
+ * demangler with arguments DMGL_PARAMS | DMGL_ANSI.
+ * Generally, we don't want params when we display
+ * a demangled name, but when I took out the DMGL_PARAMS,
+ * some things broke, so I'm leaving it in here, and
+ * working around the issue in stack.c. - RT
+ */
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->objfile_obstack);
+
+ if ((DEPRECATED_SYMBOL_NAME (sym) == VT (objfile) + dn_bufp->ddocfunc.alias) &&
+ (!SYMBOL_CPLUS_DEMANGLED_NAME (sym)))
+ {
+
+ /* Well, the symbol name is mangled, but the
+ * demangler in libiberty failed so the demangled
+ * field is still NULL. Try to
+ * do the job ourselves based on the "name" field
+ * in the SOM record. A complication here is that
+ * the name field contains only the function name
+ * (like "f"), whereas we want the class qualification
+ * (as in "c::f"). Try to reconstruct that.
+ */
+ char *basename;
+ char *classname;
+ char *dem_name;
+ basename = VT (objfile) + dn_bufp->ddocfunc.name;
+ classname = class_of (SYMBOL_TYPE (sym));
+ if (classname)
+ {
+ dem_name = xmalloc (strlen (basename) + strlen (classname) + 3);
+ strcpy (dem_name, classname);
+ strcat (dem_name, "::");
+ strcat (dem_name, basename);
+ SYMBOL_CPLUS_DEMANGLED_NAME (sym) = dem_name;
+ SYMBOL_LANGUAGE (sym) = language_cplus;
+ }
+ }
+ }
+
+ /* Add the function symbol to the list of symbols in this blockvector */
+ if (dn_bufp->ddocfunc.global)
+ add_symbol_to_list (sym, &global_symbols);
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ new->name = sym;
+
+ /* Search forward to the next BEGIN and also read
+ * in the line info up to that point.
+ * Not sure why this is needed.
+ * In HP FORTRAN this code is harmful since there
+ * may not be a BEGIN after the FUNCTION.
+ * So I made it C/C++ specific. - RT
+ */
+ if (dn_bufp->ddocfunc.language == HP_LANGUAGE_C ||
+ dn_bufp->ddocfunc.language == HP_LANGUAGE_CPLUSPLUS)
+ {
+ while (dn_bufp->dblock.kind != DNTT_TYPE_BEGIN)
+ {
+ dn_bufp = hpread_get_lntt (++index, objfile);
+ if (dn_bufp->dblock.extension)
+ continue;
+ }
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->dbegin.address,
+ objfile, offset);
+ SYMBOL_LINE (sym) = hpread_get_line (dn_bufp->dbegin.address, objfile);
+ }
+ record_line (current_subfile, SYMBOL_LINE (sym), valu);
+ break;
+
+ case DNTT_TYPE_BEGIN:
+ /* Begin a new scope. */
+ if (context_stack_depth == 1 /* this means we're at function level */ &&
+ context_stack[0].name != NULL /* this means it's a function */ &&
+ context_stack[0].depth == 0 /* this means it's the first BEGIN
+ we've seen after the FUNCTION */
+ )
+ {
+ /* This is the first BEGIN after a FUNCTION.
+ * We ignore this one, since HP compilers always insert
+ * at least one BEGIN, i.e. it's:
+ *
+ * FUNCTION
+ * argument symbols
+ * BEGIN
+ * local symbols
+ * (possibly nested BEGIN ... END's if there are inner { } blocks)
+ * END
+ * END
+ *
+ * By ignoring this first BEGIN, the local symbols get treated
+ * as belonging to the function scope, and "print func::local_sym"
+ * works (which is what we want).
+ */
+
+ /* All we do here is increase the depth count associated with
+ * the FUNCTION entry in the context stack. This ensures that
+ * the next BEGIN we see (if any), representing a real nested { }
+ * block, will get processed.
+ */
+
+ context_stack[0].depth++;
+
+ }
+ else
+ {
+
+ /* Record lines up to this SLT pointer. */
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->dbegin.address,
+ objfile, offset);
+ /* Calculate start address of new scope */
+ valu = hpread_get_location (dn_bufp->dbegin.address, objfile);
+ valu += offset; /* Relocate for dynamic loading */
+ /* We use the scope start DNTT index as nesting depth identifier! */
+ desc = hpread_get_scope_start (dn_bufp->dbegin.address, objfile);
+ new = push_context (desc, valu);
+ }
+ break;
+
+ case DNTT_TYPE_END:
+ /* End a scope. */
+
+ /* Valid end kinds are:
+ * MODULE
+ * FUNCTION
+ * WITH
+ * COMMON
+ * BEGIN
+ * CLASS_SCOPE
+ */
+
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->dend.address,
+ objfile, offset);
+ switch (dn_bufp->dend.endkind)
+ {
+ case DNTT_TYPE_MODULE:
+ /* Ending a module ends the symbol table for that module.
+ * Calling end_symtab() has the side effect of clearing the
+ * last_source_file pointer, which in turn signals
+ * process_one_debug_symbol() to treat the next DNTT_TYPE_SRCFILE
+ * record as a module-begin.
+ */
+ valu = text_offset + text_size + offset;
+
+ /* Tell our caller that we're done with expanding the
+ * debug information for a module.
+ */
+ *at_module_boundary_p = 1;
+
+ /* Don't do this, as our caller will do it!
+
+ * (void) end_symtab (valu, objfile, 0);
+ */
+ break;
+
+ case DNTT_TYPE_FUNCTION:
+ /* Ending a function, well, ends the function's scope. */
+ dn_temp = hpread_get_lntt (dn_bufp->dend.beginscope.dnttp.index,
+ objfile);
+ valu = dn_temp->dfunc.hiaddr + offset;
+ /* Insert func params into local list */
+ merge_symbol_lists (&param_symbols, &local_symbols);
+ 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);
+ WITHIN_FUNCTION (objfile) = 0; /* This may have to change for Pascal */
+ local_symbols = new->locals;
+ param_symbols = new->params;
+ break;
+
+ case DNTT_TYPE_BEGIN:
+ if (context_stack_depth == 1 &&
+ context_stack[0].name != NULL &&
+ context_stack[0].depth == 1)
+ {
+ /* This is the END corresponding to the
+ * BEGIN which we ignored - see DNTT_TYPE_BEGIN case above.
+ */
+ context_stack[0].depth--;
+ }
+ else
+ {
+ /* Ending a local scope. */
+ valu = hpread_get_location (dn_bufp->dend.address, objfile);
+ /* Why in the hell is this needed? */
+ valu += offset + 9; /* Relocate for dynamic loading */
+ new = pop_context ();
+ desc = dn_bufp->dend.beginscope.dnttp.index;
+ if (desc != new->depth)
+ lbrac_mismatch_complaint (symnum);
+
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ local_symbols = new->locals;
+ param_symbols = new->params;
+ }
+ break;
+
+ case DNTT_TYPE_WITH:
+ /* Since we ignore the DNTT_TYPE_WITH that starts the scope,
+ * we can ignore the DNTT_TYPE_END that ends it.
+ */
+ break;
+
+ case DNTT_TYPE_COMMON:
+ /* End a FORTRAN common block. We don't currently handle these */
+ complaint (&symfile_complaints,
+ "unhandled symbol in hp-symtab-read.c: DNTT_TYPE_COMMON/DNTT_TYPE_END.\n");
+ break;
+
+ case DNTT_TYPE_CLASS_SCOPE:
+
+ /* pai: FIXME Not handling nested classes for now -- must
+ * maintain a stack */
+ class_scope_name = NULL;
+
+#if 0
+ /* End a class scope */
+ valu = hpread_get_location (dn_bufp->dend.address, objfile);
+ /* Why in the hell is this needed? */
+ valu += offset + 9; /* Relocate for dynamic loading */
+ new = pop_context ();
+ desc = dn_bufp->dend.beginscope.dnttp.index;
+ if (desc != new->depth)
+ lbrac_mismatch_complaint ((char *) symnum);
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ local_symbols = new->locals;
+ param_symbols = new->params;
+#endif
+ break;
+
+ default:
+ complaint (&symfile_complaints,
+ "internal error in hp-symtab-read.c: Unexpected DNTT_TYPE_END kind.");
+ break;
+ }
+ break;
+
+ /* DNTT_TYPE_IMPORT is not handled */
+
+ case DNTT_TYPE_LABEL:
+ SYMBOL_DOMAIN (sym) = LABEL_DOMAIN;
+ break;
+
+ case DNTT_TYPE_FPARAM:
+ /* Function parameters. */
+ /* Note 1: This code was present in the 4.16 sources, and then
+ removed, because fparams are handled in
+ hpread_read_function_type(). However, while fparam symbols
+ are indeed handled twice, this code here cannot be removed
+ because then they don't get added to the local symbol list of
+ the function's code block, which leads to a failure to look
+ up locals, "this"-relative member names, etc. So I've put
+ this code back in. pai/1997-07-21 */
+ /* Note 2: To fix a defect, we stopped adding FPARAMS to local_symbols
+ in hpread_read_function_type(), so FPARAMS had to be handled
+ here. I changed the location to be the appropriate argument
+ kinds rather than LOC_LOCAL. pai/1997-08-08 */
+ /* Note 3: Well, the fix in Note 2 above broke argument printing
+ in traceback frames, and further it makes assumptions about the
+ order of the FPARAM entries from HP compilers (cc and aCC in particular
+ generate them in reverse orders -- fixing one breaks for the other).
+ So I've added code in hpread_read_function_type() to add fparams
+ to a param_symbols list for the current context level. These are
+ then merged into local_symbols when a function end is reached.
+ pai/1997-08-11 */
+
+ break; /* do nothing; handled in hpread_read_function_type() */
+
+#if 0 /* Old code */
+ if (dn_bufp->dfparam.regparam)
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ else if (dn_bufp->dfparam.indirect)
+ SYMBOL_CLASS (sym) = LOC_REF_ARG;
+ else
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ if (dn_bufp->dfparam.copyparam)
+ {
+ SYMBOL_VALUE (sym) = dn_bufp->dfparam.location;
+#ifdef HPREAD_ADJUST_STACK_ADDRESS
+ SYMBOL_VALUE (sym)
+ += HPREAD_ADJUST_STACK_ADDRESS (CURRENT_FUNCTION_VALUE (objfile));
+#endif
+ }
+ else
+ SYMBOL_VALUE (sym) = dn_bufp->dfparam.location;
+ SYMBOL_TYPE (sym) = hpread_type_lookup (dn_bufp->dfparam.type, objfile);
+ add_symbol_to_list (sym, &fparam_symbols);
+ break;
+#endif
+
+ case DNTT_TYPE_SVAR:
+ /* Static variables. */
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+
+ /* Note: There is a case that arises with globals in shared
+ * libraries where we need to set the address to LOC_INDIRECT.
+ * This case is if you have a global "g" in one library, and
+ * it is referenced "extern <type> g;" in another library.
+ * If we're processing the symbols for the referencing library,
+ * we'll see a global "g", but in this case the address given
+ * in the symbol table contains a pointer to the real "g".
+ * We use the storage class LOC_INDIRECT to indicate this. RT
+ */
+ if (is_in_import_list (DEPRECATED_SYMBOL_NAME (sym), objfile))
+ SYMBOL_CLASS (sym) = LOC_INDIRECT;
+
+ SYMBOL_VALUE_ADDRESS (sym) = dn_bufp->dsvar.location + data_offset;
+ SYMBOL_TYPE (sym) = hpread_type_lookup (dn_bufp->dsvar.type, objfile);
+
+ if (dn_bufp->dsvar.global)
+ add_symbol_to_list (sym, &global_symbols);
+
+ else if (WITHIN_FUNCTION (objfile))
+ add_symbol_to_list (sym, &local_symbols);
+
+ else
+ add_symbol_to_list (sym, &file_symbols);
+
+ if (dn_bufp->dsvar.thread_specific)
+ {
+ /* Thread-local variable.
+ */
+ SYMBOL_CLASS (sym) = LOC_HP_THREAD_LOCAL_STATIC;
+ SYMBOL_BASEREG (sym) = CR27_REGNUM;
+
+ if (objfile->flags & OBJF_SHARED)
+ {
+ /*
+ * This variable is not only thread local but
+ * in a shared library.
+ *
+ * Alas, the shared lib structures are private
+ * to "somsolib.c". But C lets us point to one.
+ */
+ struct so_list *so;
+
+ if (objfile->obj_private == NULL)
+ error ("Internal error in reading shared library information.");
+
+ so = ((obj_private_data_t *) (objfile->obj_private))->so_info;
+ if (so == NULL)
+ error ("Internal error in reading shared library information.");
+
+ /* Thread-locals in shared libraries do NOT have the
+ * standard offset ("data_offset"), so we re-calculate
+ * where to look for this variable, using a call-back
+ * to interpret the private shared-library data.
+ */
+ SYMBOL_VALUE_ADDRESS (sym) = dn_bufp->dsvar.location +
+ so_lib_thread_start_addr (so);
+ }
+ }
+ break;
+
+ case DNTT_TYPE_DVAR:
+ /* Dynamic variables. */
+ if (dn_bufp->ddvar.regvar)
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ else
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+
+ SYMBOL_VALUE (sym) = dn_bufp->ddvar.location;
+#ifdef HPREAD_ADJUST_STACK_ADDRESS
+ SYMBOL_VALUE (sym)
+ += HPREAD_ADJUST_STACK_ADDRESS (CURRENT_FUNCTION_VALUE (objfile));
+#endif
+ SYMBOL_TYPE (sym) = hpread_type_lookup (dn_bufp->ddvar.type, objfile);
+ if (dn_bufp->ddvar.global)
+ add_symbol_to_list (sym, &global_symbols);
+ else if (WITHIN_FUNCTION (objfile))
+ add_symbol_to_list (sym, &local_symbols);
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case DNTT_TYPE_CONST:
+ /* A constant (pascal?). */
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_VALUE (sym) = dn_bufp->dconst.location;
+ SYMBOL_TYPE (sym) = hpread_type_lookup (dn_bufp->dconst.type, objfile);
+ if (dn_bufp->dconst.global)
+ add_symbol_to_list (sym, &global_symbols);
+ else if (WITHIN_FUNCTION (objfile))
+ add_symbol_to_list (sym, &local_symbols);
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case DNTT_TYPE_TYPEDEF:
+ /* A typedef. We do want to process these, since a name is
+ * added to the domain for the typedef'ed name.
+ */
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ SYMBOL_TYPE (sym) = hpread_type_lookup (dn_bufp->dtype.type, objfile);
+ if (dn_bufp->dtype.global)
+ add_symbol_to_list (sym, &global_symbols);
+ else if (WITHIN_FUNCTION (objfile))
+ add_symbol_to_list (sym, &local_symbols);
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case DNTT_TYPE_TAGDEF:
+ {
+ int global = dn_bufp->dtag.global;
+ /* Structure, union, enum, template, or class tag definition */
+ /* We do want to process these, since a name is
+ * added to the domain for the tag name (and if C++ class,
+ * for the typename also).
+ */
+ SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN;
+
+ /* The tag contains in its "type" field a pointer to the
+ * DNTT_TYPE_STRUCT, DNTT_TYPE_UNION, DNTT_TYPE_ENUM,
+ * DNTT_TYPE_CLASS or DNTT_TYPE_TEMPLATE
+ * record that actually defines the type.
+ */
+ SYMBOL_TYPE (sym) = hpread_type_lookup (dn_bufp->dtype.type, objfile);
+ TYPE_NAME (sym->type) = DEPRECATED_SYMBOL_NAME (sym);
+ TYPE_TAG_NAME (sym->type) = DEPRECATED_SYMBOL_NAME (sym);
+ if (dn_bufp->dtag.global)
+ add_symbol_to_list (sym, &global_symbols);
+ else if (WITHIN_FUNCTION (objfile))
+ add_symbol_to_list (sym, &local_symbols);
+ else
+ add_symbol_to_list (sym, &file_symbols);
+
+ /* If this is a C++ class, then we additionally
+ * need to define a typedef for the
+ * class type. E.g., so that the name "c" becomes visible as
+ * a type name when the user says "class c { ... }".
+ * In order to figure this out, we need to chase down the "type"
+ * field to get to the DNTT_TYPE_CLASS record.
+ *
+ * We also add the typename for ENUM. Though this isn't
+ * strictly correct, it is necessary because of the debug info
+ * generated by the aCC compiler, in which we cannot
+ * distinguish between:
+ * enum e { ... };
+ * and
+ * typedef enum { ... } e;
+ * I.e., the compiler emits the same debug info for the above
+ * two cases, in both cases "e" appearing as a tagdef.
+ * Therefore go ahead and generate the typename so that
+ * "ptype e" will work in the above cases.
+ *
+ * We also add the typename for TEMPLATE, so as to allow "ptype t"
+ * when "t" is a template name.
+ */
+ if (dn_bufp->dtype.type.dnttp.index < LNTT_SYMCOUNT (objfile))
+ dn_bufp = hpread_get_lntt (dn_bufp->dtag.type.dnttp.index, objfile);
+ else
+ {
+ complaint (&symfile_complaints, "error processing class tagdef");
+ return;
+ }
+ if (dn_bufp->dblock.kind == DNTT_TYPE_CLASS ||
+ dn_bufp->dblock.kind == DNTT_TYPE_ENUM ||
+ dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
+ {
+ struct symbol *newsym;
+
+ newsym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+ memset (newsym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (newsym) = name;
+ SYMBOL_LANGUAGE (newsym) = language_auto;
+ SYMBOL_DOMAIN (newsym) = VAR_DOMAIN;
+ SYMBOL_LINE (newsym) = 0;
+ SYMBOL_VALUE (newsym) = 0;
+ SYMBOL_CLASS (newsym) = LOC_TYPEDEF;
+ SYMBOL_TYPE (newsym) = sym->type;
+ if (global)
+ add_symbol_to_list (newsym, &global_symbols);
+ else if (WITHIN_FUNCTION (objfile))
+ add_symbol_to_list (newsym, &local_symbols);
+ else
+ add_symbol_to_list (newsym, &file_symbols);
+ }
+ }
+ break;
+
+ case DNTT_TYPE_POINTER:
+ /* Declares a pointer type. Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_ENUM:
+ /* Declares an enum type. Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_MEMENUM:
+ /* Member of enum */
+ /* Ignored at this level, but hpread_read_enum_type() will take
+ * care of walking the list of enumeration members.
+ */
+ break;
+
+ case DNTT_TYPE_SET:
+ /* Declares a set type. Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_SUBRANGE:
+ /* Declares a subrange type. Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_ARRAY:
+ /* Declares an array type. Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_STRUCT:
+ case DNTT_TYPE_UNION:
+ /* Declares an struct/union type.
+ * Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_FIELD:
+ /* Structure/union/class field */
+ /* Ignored at this level, but hpread_read_struct_type() will take
+ * care of walking the list of structure/union/class members.
+ */
+ break;
+
+ /* DNTT_TYPE_VARIANT is not handled by GDB */
+
+ /* DNTT_TYPE_FILE is not handled by GDB */
+
+ case DNTT_TYPE_FUNCTYPE:
+ /* Function type */
+ /* Ignored at this level, handled within hpread_type_lookup() */
+ break;
+
+ case DNTT_TYPE_WITH:
+ /* This is emitted within methods to indicate "with <class>"
+ * scoping rules (i.e., indicate that the class data members
+ * are directly visible).
+ * However, since GDB already infers this by looking at the
+ * "this" argument, interpreting the DNTT_TYPE_WITH
+ * symbol record is unnecessary.
+ */
+ break;
+
+ case DNTT_TYPE_COMMON:
+ /* FORTRAN common. Not yet handled. */
+ complaint (&symfile_complaints,
+ "unhandled symbol in hp-symtab-read.c: DNTT_TYPE_COMMON.");
+ break;
+
+ /* DNTT_TYPE_COBSTRUCT is not handled by GDB. */
+ /* DNTT_TYPE_XREF is not handled by GDB. */
+ /* DNTT_TYPE_SA is not handled by GDB. */
+ /* DNTT_TYPE_MACRO is not handled by GDB */
+
+ case DNTT_TYPE_BLOCKDATA:
+ /* Not sure what this is - part of FORTRAN support maybe?
+ * Anyway, not yet handled.
+ */
+ complaint (&symfile_complaints,
+ "unhandled symbol in hp-symtab-read.c: DNTT_TYPE_BLOCKDATA.");
+ break;
+
+ case DNTT_TYPE_CLASS_SCOPE:
+
+
+
+ /* The compiler brackets member functions with a CLASS_SCOPE/END
+ * pair of records, presumably to put them in a different scope
+ * from the module scope where they are normally defined.
+ * E.g., in the situation:
+ * void f() { ... }
+ * void c::f() { ...}
+ * The member function "c::f" will be bracketed by a CLASS_SCOPE/END.
+ * This causes "break f" at the module level to pick the
+ * the file-level function f(), not the member function
+ * (which needs to be referenced via "break c::f").
+ *
+ * Here we record the class name to generate the demangled names of
+ * member functions later.
+ *
+ * FIXME Not being used now for anything -- cplus_demangle seems
+ * enough for getting the class-qualified names of functions. We
+ * may need this for handling nested classes and types. */
+
+ /* pai: FIXME Not handling nested classes for now -- need to
+ * maintain a stack */
+
+ dn_temp = hpread_get_lntt (dn_bufp->dclass_scope.type.dnttp.index, objfile);
+ if (dn_temp->dblock.kind == DNTT_TYPE_TAGDEF)
+ class_scope_name = VT (objfile) + dn_temp->dtag.name;
+ else
+ class_scope_name = NULL;
+
+#if 0
+
+ /* Begin a new scope. */
+ SL_INDEX (objfile) = hpread_record_lines (current_subfile,
+ SL_INDEX (objfile),
+ dn_bufp->dclass_scope.address,
+ objfile, offset);
+ valu = hpread_get_location (dn_bufp->dclass_scope.address, objfile);
+ valu += offset; /* Relocate for dynamic loading */
+ desc = hpread_get_scope_start (dn_bufp->dclass_scope.address, objfile);
+ /* We use the scope start DNTT index as the nesting depth identifier! */
+ new = push_context (desc, valu);
+#endif
+ break;
+
+ case DNTT_TYPE_REFERENCE:
+ /* Declares a C++ reference type. Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_PTRMEM:
+ /* Declares a C++ pointer-to-data-member type. This does not
+ * need to be handled at this level; being a type description it
+ * is instead handled at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_PTRMEMFUNC:
+ /* Declares a C++ pointer-to-function-member type. This does not
+ * need to be handled at this level; being a type description it
+ * is instead handled at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_CLASS:
+ /* Declares a class type.
+ * Should not be necessary to do anything
+ * with the type at this level; these are processed
+ * at the hpread_type_lookup() level.
+ */
+ break;
+
+ case DNTT_TYPE_GENFIELD:
+ /* I believe this is used for class member functions */
+ /* Ignored at this level, but hpread_read_struct_type() will take
+ * care of walking the list of class members.
+ */
+ break;
+
+ case DNTT_TYPE_VFUNC:
+ /* Virtual function */
+ /* This does not have to be handled at this level; handled in
+ * the course of processing class symbols.
+ */
+ break;
+
+ case DNTT_TYPE_MEMACCESS:
+ /* DDE ignores this symbol table record.
+ * It has something to do with "modified access" to class members.
+ * I'll assume we can safely ignore it too.
+ */
+ break;
+
+ case DNTT_TYPE_INHERITANCE:
+ /* These don't have to be handled here, since they are handled
+ * within hpread_read_struct_type() in the process of constructing
+ * a class type.
+ */
+ break;
+
+ case DNTT_TYPE_FRIEND_CLASS:
+ case DNTT_TYPE_FRIEND_FUNC:
+ /* These can safely be ignored, as GDB doesn't need this
+ * info. DDE only uses it in "describe". We may later want
+ * to extend GDB's "ptype" to give this info, but for now
+ * it seems safe enough to ignore it.
+ */
+ break;
+
+ case DNTT_TYPE_MODIFIER:
+ /* Intended to supply "modified access" to a type */
+ /* From the way DDE handles this, it looks like it always
+ * modifies a type. Therefore it is safe to ignore it at this
+ * level, and handle it in hpread_type_lookup().
+ */
+ break;
+
+ case DNTT_TYPE_OBJECT_ID:
+ /* Just ignore this - that's all DDE does */
+ break;
+
+ case DNTT_TYPE_MEMFUNC:
+ /* Member function */
+ /* This does not have to be handled at this level; handled in
+ * the course of processing class symbols.
+ */
+ break;
+
+ case DNTT_TYPE_DOC_MEMFUNC:
+ /* Member function */
+ /* This does not have to be handled at this level; handled in
+ * the course of processing class symbols.
+ */
+ break;
+
+ case DNTT_TYPE_TEMPLATE:
+ /* Template - sort of the header for a template definition,
+ * which like a class, points to a member list and also points
+ * to a TEMPLATE_ARG list of type-arguments.
+ * We do not need to process TEMPLATE records at this level though.
+ */
+ break;
+
+ case DNTT_TYPE_TEMPLATE_ARG:
+ /* The TEMPLATE record points to an argument list of
+ * TEMPLATE_ARG records, each of which describes one
+ * of the type-arguments.
+ * We do not need to process TEMPLATE_ARG records at this level though.
+ */
+ break;
+
+ case DNTT_TYPE_FUNC_TEMPLATE:
+ /* This will get emitted for member functions of templates.
+ * But we don't need to process this record at this level though,
+ * we will process it in the course of processing a TEMPLATE
+ * record.
+ */
+ break;
+
+ case DNTT_TYPE_LINK:
+ /* The LINK record is used to link up templates with instantiations. */
+ /* It is not clear why this is needed, and furthermore aCC does
+ * not appear to generate this, so I think we can safely ignore it. - RT
+ */
+ break;
+
+ /* DNTT_TYPE_DYN_ARRAY_DESC is not handled by GDB */
+ /* DNTT_TYPE_DESC_SUBRANGE is not handled by GDB */
+ /* DNTT_TYPE_BEGIN_EXT is not handled by GDB */
+ /* DNTT_TYPE_INLN is not handled by GDB */
+ /* DNTT_TYPE_INLN_LIST is not handled by GDB */
+ /* DNTT_TYPE_ALIAS is not handled by GDB */
+
+ default:
+ break;
+ }
+}
+
+/* Get nesting depth for a DNTT entry.
+ * DN_BUFP points to a DNTT entry.
+ * OBJFILE is the object file.
+ * REPORT_NESTED is a flag; if 0, real nesting depth is
+ * reported, if it is 1, the function simply returns a
+ * non-zero value if the nesting depth is anything > 0.
+ *
+ * Return value is an integer. 0 => not a local type / name
+ * positive return => type or name is local to some
+ * block or function.
+ */
+
+
+/* elz: ATTENTION: FIXME: NOTE: WARNING!!!!
+ this function now returns 0 right away. It was taking too much time
+ at start up. Now, though, the local types are not handled correctly.
+ */
+
+
+static int
+hpread_get_scope_depth (union dnttentry *dn_bufp, struct objfile *objfile,
+ int report_nested)
+{
+ int index;
+ union dnttentry *dn_tmp;
+ short depth = 0;
+/****************************/
+ return 0;
+/****************************/
+
+ index = (((char *) dn_bufp) - LNTT (objfile)) / (sizeof (struct dntt_type_block));
+
+ while (--index >= 0)
+ {
+ dn_tmp = hpread_get_lntt (index, objfile);
+ switch (dn_tmp->dblock.kind)
+ {
+ case DNTT_TYPE_MODULE:
+ return depth;
+ case DNTT_TYPE_END:
+ /* index is signed int; dnttp.index is 29-bit unsigned int! */
+ index = (int) dn_tmp->dend.beginscope.dnttp.index;
+ break;
+ case DNTT_TYPE_BEGIN:
+ case DNTT_TYPE_FUNCTION:
+ case DNTT_TYPE_DOC_FUNCTION:
+ case DNTT_TYPE_WITH:
+ case DNTT_TYPE_COMMON:
+ case DNTT_TYPE_CLASS_SCOPE:
+ depth++;
+ if (report_nested)
+ return 1;
+ break;
+ default:
+ break;
+ }
+ }
+ return depth;
+}
+
+/* Adjust the bitoffsets for all fields of an anonymous union of
+ type TYPE by negative BITS. This handles HP aCC's hideous habit
+ of giving members of anonymous unions bit offsets relative to the
+ enclosing structure instead of relative to the union itself. */
+
+static void
+hpread_adjust_bitoffsets (struct type *type, int bits)
+{
+ int i;
+
+ /* This is done only for unions; caller had better check that
+ it is an anonymous one. */
+ if (TYPE_CODE (type) != TYPE_CODE_UNION)
+ return;
+
+ /* Adjust each field; since this is a union, there are no base
+ classes. Also no static membes. Also, no need for recursion as
+ the members of this union if themeselves structs or unions, have
+ the correct bitoffsets; if an anonymous union is a member of this
+ anonymous union, the code in hpread_read_struct_type() will
+ adjust for that. */
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ TYPE_FIELD_BITPOS (type, i) -= bits;
+}
+
+/* Because of quirks in HP compilers' treatment of anonymous unions inside
+ classes, we have to chase through a chain of threaded FIELD entries.
+ If we encounter an anonymous union in the chain, we must recursively skip over
+ that too.
+
+ This function does a "next" in the chain of FIELD entries, but transparently
+ skips over anonymous unions' fields (recursively).
+
+ Inputs are the number of times to do "next" at the top level, the dnttpointer
+ (FIELD) and entry pointer (FIELDP) for the dntt record corresponding to it,
+ and the ubiquitous objfile parameter. (Note: FIELDP is a **.) Return value
+ is a dnttpointer for the new field after all the skipped ones */
+
+static dnttpointer
+hpread_get_next_skip_over_anon_unions (int skip_fields, dnttpointer field,
+ union dnttentry **fieldp,
+ struct objfile *objfile)
+{
+ struct type *anon_type;
+ int i;
+ int bitoffset;
+ char *name;
+
+ for (i = 0; i < skip_fields; i++)
+ {
+ /* Get type of item we're looking at now; recursively processes the types
+ of these intermediate items we skip over, so they aren't lost. */
+ anon_type = hpread_type_lookup ((*fieldp)->dfield.type, objfile);
+ anon_type = CHECK_TYPEDEF (anon_type);
+ bitoffset = (*fieldp)->dfield.bitoffset;
+ name = VT (objfile) + (*fieldp)->dfield.name;
+ /* First skip over one item to avoid stack death on recursion */
+ field = (*fieldp)->dfield.nextfield;
+ *fieldp = hpread_get_lntt (field.dnttp.index, objfile);
+ /* Do we have another anonymous union? If so, adjust the bitoffsets
+ of its members and skip over its members. */
+ if ((TYPE_CODE (anon_type) == TYPE_CODE_UNION) &&
+ (!name || DEPRECATED_STREQ (name, "")))
+ {
+ hpread_adjust_bitoffsets (anon_type, bitoffset);
+ field = hpread_get_next_skip_over_anon_unions (TYPE_NFIELDS (anon_type), field, fieldp, objfile);
+ }
+ }
+ return field;
+}
diff --git a/contrib/gdb/gdb/i386-nat.c b/contrib/gdb/gdb/i386-nat.c
new file mode 100644
index 0000000..a20e9b0
--- /dev/null
+++ b/contrib/gdb/gdb/i386-nat.c
@@ -0,0 +1,670 @@
+/* Native-dependent code for the i386.
+
+ Copyright 2001, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "breakpoint.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+/* Support for hardware watchpoints and breakpoints using the i386
+ debug registers.
+
+ This provides several functions for inserting and removing
+ hardware-assisted breakpoints and watchpoints, testing if one or
+ more of the watchpoints triggered and at what address, checking
+ whether a given region can be watched, etc.
+
+ A target which wants to use these functions should define several
+ macros, such as `target_insert_watchpoint' and
+ `target_stopped_data_address', listed in target.h, to call the
+ appropriate functions below. It should also define
+ I386_USE_GENERIC_WATCHPOINTS in its tm.h file.
+
+ In addition, each target should provide several low-level macros
+ that will be called to insert watchpoints and hardware breakpoints
+ into the inferior, remove them, and check their status. These
+ macros are:
+
+ I386_DR_LOW_SET_CONTROL -- set the debug control (DR7)
+ register to a given value
+
+ I386_DR_LOW_SET_ADDR -- put an address into one debug
+ register
+
+ I386_DR_LOW_RESET_ADDR -- reset the address stored in
+ one debug register
+
+ I386_DR_LOW_GET_STATUS -- return the value of the debug
+ status (DR6) register.
+
+ The functions below implement debug registers sharing by reference
+ counts, and allow to watch regions up to 16 bytes long. */
+
+#ifdef I386_USE_GENERIC_WATCHPOINTS
+
+/* Support for 8-byte wide hw watchpoints. */
+#ifndef TARGET_HAS_DR_LEN_8
+#define TARGET_HAS_DR_LEN_8 0
+#endif
+
+/* Debug registers' indices. */
+#define DR_NADDR 4 /* The number of debug address registers. */
+#define DR_STATUS 6 /* Index of debug status register (DR6). */
+#define DR_CONTROL 7 /* Index of debug control register (DR7). */
+
+/* DR7 Debug Control register fields. */
+
+/* How many bits to skip in DR7 to get to R/W and LEN fields. */
+#define DR_CONTROL_SHIFT 16
+/* How many bits in DR7 per R/W and LEN field for each watchpoint. */
+#define DR_CONTROL_SIZE 4
+
+/* Watchpoint/breakpoint read/write fields in DR7. */
+#define DR_RW_EXECUTE (0x0) /* Break on instruction execution. */
+#define DR_RW_WRITE (0x1) /* Break on data writes. */
+#define DR_RW_READ (0x3) /* Break on data reads or writes. */
+
+/* This is here for completeness. No platform supports this
+ functionality yet (as of March 2001). Note that the DE flag in the
+ CR4 register needs to be set to support this. */
+#ifndef DR_RW_IORW
+#define DR_RW_IORW (0x2) /* Break on I/O reads or writes. */
+#endif
+
+/* Watchpoint/breakpoint length fields in DR7. The 2-bit left shift
+ is so we could OR this with the read/write field defined above. */
+#define DR_LEN_1 (0x0 << 2) /* 1-byte region watch or breakpoint. */
+#define DR_LEN_2 (0x1 << 2) /* 2-byte region watch. */
+#define DR_LEN_4 (0x3 << 2) /* 4-byte region watch. */
+#define DR_LEN_8 (0x2 << 2) /* 8-byte region watch (AMD64). */
+
+/* Local and Global Enable flags in DR7.
+
+ When the Local Enable flag is set, the breakpoint/watchpoint is
+ enabled only for the current task; the processor automatically
+ clears this flag on every task switch. When the Global Enable flag
+ is set, the breakpoint/watchpoint is enabled for all tasks; the
+ processor never clears this flag.
+
+ Currently, all watchpoint are locally enabled. If you need to
+ enable them globally, read the comment which pertains to this in
+ i386_insert_aligned_watchpoint below. */
+#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */
+#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */
+#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */
+
+/* Local and global exact breakpoint enable flags (a.k.a. slowdown
+ flags). These are only required on i386, to allow detection of the
+ exact instruction which caused a watchpoint to break; i486 and
+ later processors do that automatically. We set these flags for
+ backwards compatibility. */
+#define DR_LOCAL_SLOWDOWN (0x100)
+#define DR_GLOBAL_SLOWDOWN (0x200)
+
+/* Fields reserved by Intel. This includes the GD (General Detect
+ Enable) flag, which causes a debug exception to be generated when a
+ MOV instruction accesses one of the debug registers.
+
+ FIXME: My Intel manual says we should use 0xF800, not 0xFC00. */
+#define DR_CONTROL_RESERVED (0xFC00)
+
+/* Auxiliary helper macros. */
+
+/* A value that masks all fields in DR7 that are reserved by Intel. */
+#define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED)
+
+/* The I'th debug register is vacant if its Local and Global Enable
+ bits are reset in the Debug Control register. */
+#define I386_DR_VACANT(i) \
+ ((dr_control_mirror & (3 << (DR_ENABLE_SIZE * (i)))) == 0)
+
+/* Locally enable the break/watchpoint in the I'th debug register. */
+#define I386_DR_LOCAL_ENABLE(i) \
+ dr_control_mirror |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
+
+/* Globally enable the break/watchpoint in the I'th debug register. */
+#define I386_DR_GLOBAL_ENABLE(i) \
+ dr_control_mirror |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
+
+/* Disable the break/watchpoint in the I'th debug register. */
+#define I386_DR_DISABLE(i) \
+ dr_control_mirror &= ~(3 << (DR_ENABLE_SIZE * (i)))
+
+/* Set in DR7 the RW and LEN fields for the I'th debug register. */
+#define I386_DR_SET_RW_LEN(i,rwlen) \
+ do { \
+ dr_control_mirror &= ~(0x0f << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \
+ dr_control_mirror |= ((rwlen) << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \
+ } while (0)
+
+/* Get from DR7 the RW and LEN fields for the I'th debug register. */
+#define I386_DR_GET_RW_LEN(i) \
+ ((dr_control_mirror >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f)
+
+/* Did the watchpoint whose address is in the I'th register break? */
+#define I386_DR_WATCH_HIT(i) (dr_status_mirror & (1 << (i)))
+
+/* A macro to loop over all debug registers. */
+#define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++)
+
+/* Mirror the inferior's DRi registers. We keep the status and
+ control registers separated because they don't hold addresses. */
+static CORE_ADDR dr_mirror[DR_NADDR];
+static unsigned dr_status_mirror, dr_control_mirror;
+
+/* Reference counts for each debug register. */
+static int dr_ref_count[DR_NADDR];
+
+/* Whether or not to print the mirrored debug registers. */
+static int maint_show_dr;
+
+/* Types of operations supported by i386_handle_nonaligned_watchpoint. */
+typedef enum { WP_INSERT, WP_REMOVE, WP_COUNT } i386_wp_op_t;
+
+/* Internal functions. */
+
+/* Return the value of a 4-bit field for DR7 suitable for watching a
+ region of LEN bytes for accesses of type TYPE. LEN is assumed to
+ have the value of 1, 2, or 4. */
+static unsigned i386_length_and_rw_bits (int len, enum target_hw_bp_type type);
+
+/* Insert a watchpoint at address ADDR, which is assumed to be aligned
+ according to the length of the region to watch. LEN_RW_BITS is the
+ value of the bit-field from DR7 which describes the length and
+ access type of the region to be watched by this watchpoint. Return
+ 0 on success, -1 on failure. */
+static int i386_insert_aligned_watchpoint (CORE_ADDR addr,
+ unsigned len_rw_bits);
+
+/* Remove a watchpoint at address ADDR, which is assumed to be aligned
+ according to the length of the region to watch. LEN_RW_BITS is the
+ value of the bits from DR7 which describes the length and access
+ type of the region watched by this watchpoint. Return 0 on
+ success, -1 on failure. */
+static int i386_remove_aligned_watchpoint (CORE_ADDR addr,
+ unsigned len_rw_bits);
+
+/* Insert or remove a (possibly non-aligned) watchpoint, or count the
+ number of debug registers required to watch a region at address
+ ADDR whose length is LEN for accesses of type TYPE. Return 0 on
+ successful insertion or removal, a positive number when queried
+ about the number of registers, or -1 on failure. If WHAT is not a
+ valid value, bombs through internal_error. */
+static int i386_handle_nonaligned_watchpoint (i386_wp_op_t what,
+ CORE_ADDR addr, int len,
+ enum target_hw_bp_type type);
+
+/* Implementation. */
+
+/* Clear the reference counts and forget everything we knew about the
+ debug registers. */
+
+void
+i386_cleanup_dregs (void)
+{
+ int i;
+
+ ALL_DEBUG_REGISTERS(i)
+ {
+ dr_mirror[i] = 0;
+ dr_ref_count[i] = 0;
+ }
+ dr_control_mirror = 0;
+ dr_status_mirror = 0;
+}
+
+#ifndef LINUX_CHILD_POST_STARTUP_INFERIOR
+
+/* Reset all debug registers at each new startup to avoid missing
+ watchpoints after restart. */
+
+void
+child_post_startup_inferior (ptid_t ptid)
+{
+ i386_cleanup_dregs ();
+}
+
+#endif /* LINUX_CHILD_POST_STARTUP_INFERIOR */
+
+/* Print the values of the mirrored debug registers. This is called
+ when maint_show_dr is non-zero. To set that up, type "maint
+ show-debug-regs" at GDB's prompt. */
+
+static void
+i386_show_dr (const char *func, CORE_ADDR addr,
+ int len, enum target_hw_bp_type type)
+{
+ int i;
+
+ puts_unfiltered (func);
+ if (addr || len)
+ printf_unfiltered (" (addr=%lx, len=%d, type=%s)",
+ /* This code is for ia32, so casting CORE_ADDR
+ to unsigned long should be okay. */
+ (unsigned long)addr, len,
+ type == hw_write ? "data-write"
+ : (type == hw_read ? "data-read"
+ : (type == hw_access ? "data-read/write"
+ : (type == hw_execute ? "instruction-execute"
+ /* FIXME: if/when I/O read/write
+ watchpoints are supported, add them
+ here. */
+ : "??unknown??"))));
+ puts_unfiltered (":\n");
+ printf_unfiltered ("\tCONTROL (DR7): %08x STATUS (DR6): %08x\n",
+ dr_control_mirror, dr_status_mirror);
+ ALL_DEBUG_REGISTERS(i)
+ {
+ printf_unfiltered ("\
+\tDR%d: addr=0x%s, ref.count=%d DR%d: addr=0x%s, ref.count=%d\n",
+ i, paddr(dr_mirror[i]), dr_ref_count[i],
+ i+1, paddr(dr_mirror[i+1]), dr_ref_count[i+1]);
+ i++;
+ }
+}
+
+/* Return the value of a 4-bit field for DR7 suitable for watching a
+ region of LEN bytes for accesses of type TYPE. LEN is assumed to
+ have the value of 1, 2, or 4. */
+
+static unsigned
+i386_length_and_rw_bits (int len, enum target_hw_bp_type type)
+{
+ unsigned rw;
+
+ switch (type)
+ {
+ case hw_execute:
+ rw = DR_RW_EXECUTE;
+ break;
+ case hw_write:
+ rw = DR_RW_WRITE;
+ break;
+ case hw_read:
+ /* The i386 doesn't support data-read watchpoints. */
+ case hw_access:
+ rw = DR_RW_READ;
+ break;
+#if 0
+ /* Not yet supported. */
+ case hw_io_access:
+ rw = DR_RW_IORW;
+ break;
+#endif
+ default:
+ internal_error (__FILE__, __LINE__, "\
+Invalid hardware breakpoint type %d in i386_length_and_rw_bits.\n",
+ (int) type);
+ }
+
+ switch (len)
+ {
+ case 1:
+ return (DR_LEN_1 | rw);
+ case 2:
+ return (DR_LEN_2 | rw);
+ case 4:
+ return (DR_LEN_4 | rw);
+ case 8:
+ if (TARGET_HAS_DR_LEN_8)
+ return (DR_LEN_8 | rw);
+ default:
+ internal_error (__FILE__, __LINE__, "\
+Invalid hardware breakpoint length %d in i386_length_and_rw_bits.\n", len);
+ }
+}
+
+/* Insert a watchpoint at address ADDR, which is assumed to be aligned
+ according to the length of the region to watch. LEN_RW_BITS is the
+ value of the bits from DR7 which describes the length and access
+ type of the region to be watched by this watchpoint. Return 0 on
+ success, -1 on failure. */
+
+static int
+i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
+{
+ int i;
+
+ /* First, look for an occupied debug register with the same address
+ and the same RW and LEN definitions. If we find one, we can
+ reuse it for this watchpoint as well (and save a register). */
+ ALL_DEBUG_REGISTERS(i)
+ {
+ if (!I386_DR_VACANT (i)
+ && dr_mirror[i] == addr
+ && I386_DR_GET_RW_LEN (i) == len_rw_bits)
+ {
+ dr_ref_count[i]++;
+ return 0;
+ }
+ }
+
+ /* Next, look for a vacant debug register. */
+ ALL_DEBUG_REGISTERS(i)
+ {
+ if (I386_DR_VACANT (i))
+ break;
+ }
+
+ /* No more debug registers! */
+ if (i >= DR_NADDR)
+ return -1;
+
+ /* Now set up the register I to watch our region. */
+
+ /* Record the info in our local mirrored array. */
+ dr_mirror[i] = addr;
+ dr_ref_count[i] = 1;
+ I386_DR_SET_RW_LEN (i, len_rw_bits);
+ /* Note: we only enable the watchpoint locally, i.e. in the current
+ task. Currently, no i386 target allows or supports global
+ watchpoints; however, if any target would want that in the
+ future, GDB should probably provide a command to control whether
+ to enable watchpoints globally or locally, and the code below
+ should use global or local enable and slow-down flags as
+ appropriate. */
+ I386_DR_LOCAL_ENABLE (i);
+ dr_control_mirror |= DR_LOCAL_SLOWDOWN;
+ dr_control_mirror &= I386_DR_CONTROL_MASK;
+
+ /* Finally, actually pass the info to the inferior. */
+ I386_DR_LOW_SET_ADDR (i, addr);
+ I386_DR_LOW_SET_CONTROL (dr_control_mirror);
+
+ return 0;
+}
+
+/* Remove a watchpoint at address ADDR, which is assumed to be aligned
+ according to the length of the region to watch. LEN_RW_BITS is the
+ value of the bits from DR7 which describes the length and access
+ type of the region watched by this watchpoint. Return 0 on
+ success, -1 on failure. */
+
+static int
+i386_remove_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
+{
+ int i, retval = -1;
+
+ ALL_DEBUG_REGISTERS(i)
+ {
+ if (!I386_DR_VACANT (i)
+ && dr_mirror[i] == addr
+ && I386_DR_GET_RW_LEN (i) == len_rw_bits)
+ {
+ if (--dr_ref_count[i] == 0) /* no longer in use? */
+ {
+ /* Reset our mirror. */
+ dr_mirror[i] = 0;
+ I386_DR_DISABLE (i);
+ /* Reset it in the inferior. */
+ I386_DR_LOW_SET_CONTROL (dr_control_mirror);
+ I386_DR_LOW_RESET_ADDR (i);
+ }
+ retval = 0;
+ }
+ }
+
+ return retval;
+}
+
+/* Insert or remove a (possibly non-aligned) watchpoint, or count the
+ number of debug registers required to watch a region at address
+ ADDR whose length is LEN for accesses of type TYPE. Return 0 on
+ successful insertion or removal, a positive number when queried
+ about the number of registers, or -1 on failure. If WHAT is not a
+ valid value, bombs through internal_error. */
+
+static int
+i386_handle_nonaligned_watchpoint (i386_wp_op_t what, CORE_ADDR addr, int len,
+ enum target_hw_bp_type type)
+{
+ int retval = 0, status = 0;
+ int max_wp_len = TARGET_HAS_DR_LEN_8 ? 8 : 4;
+
+ static int size_try_array[8][8] =
+ {
+ {1, 1, 1, 1, 1, 1, 1, 1}, /* Trying size one. */
+ {2, 1, 2, 1, 2, 1, 2, 1}, /* Trying size two. */
+ {2, 1, 2, 1, 2, 1, 2, 1}, /* Trying size three. */
+ {4, 1, 2, 1, 4, 1, 2, 1}, /* Trying size four. */
+ {4, 1, 2, 1, 4, 1, 2, 1}, /* Trying size five. */
+ {4, 1, 2, 1, 4, 1, 2, 1}, /* Trying size six. */
+ {4, 1, 2, 1, 4, 1, 2, 1}, /* Trying size seven. */
+ {8, 1, 2, 1, 4, 1, 2, 1}, /* Trying size eight. */
+ };
+
+ while (len > 0)
+ {
+ int align = addr % max_wp_len;
+ /* Four (eigth on AMD64) is the maximum length a debug register
+ can watch. */
+ int try = (len > max_wp_len ? (max_wp_len - 1) : len - 1);
+ int size = size_try_array[try][align];
+
+ if (what == WP_COUNT)
+ {
+ /* size_try_array[] is defined such that each iteration
+ through the loop is guaranteed to produce an address and a
+ size that can be watched with a single debug register.
+ Thus, for counting the registers required to watch a
+ region, we simply need to increment the count on each
+ iteration. */
+ retval++;
+ }
+ else
+ {
+ unsigned len_rw = i386_length_and_rw_bits (size, type);
+
+ if (what == WP_INSERT)
+ status = i386_insert_aligned_watchpoint (addr, len_rw);
+ else if (what == WP_REMOVE)
+ status = i386_remove_aligned_watchpoint (addr, len_rw);
+ else
+ internal_error (__FILE__, __LINE__, "\
+Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n",
+ (int)what);
+ /* We keep the loop going even after a failure, because some
+ of the other aligned watchpoints might still succeed
+ (e.g. if they watch addresses that are already watched,
+ in which case we just increment the reference counts of
+ occupied debug registers). If we break out of the loop
+ too early, we could cause those addresses watched by
+ other watchpoints to be disabled when breakpoint.c reacts
+ to our failure to insert this watchpoint and tries to
+ remove it. */
+ if (status)
+ retval = status;
+ }
+
+ addr += size;
+ len -= size;
+ }
+
+ return retval;
+}
+
+/* Insert a watchpoint to watch a memory region which starts at
+ address ADDR and whose length is LEN bytes. Watch memory accesses
+ of the type TYPE. Return 0 on success, -1 on failure. */
+
+int
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ int retval;
+
+ if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8))
+ || addr % len != 0)
+ retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
+ else
+ {
+ unsigned len_rw = i386_length_and_rw_bits (len, type);
+
+ retval = i386_insert_aligned_watchpoint (addr, len_rw);
+ }
+
+ if (maint_show_dr)
+ i386_show_dr ("insert_watchpoint", addr, len, type);
+
+ return retval;
+}
+
+/* Remove a watchpoint that watched the memory region which starts at
+ address ADDR, whose length is LEN bytes, and for accesses of the
+ type TYPE. Return 0 on success, -1 on failure. */
+int
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ int retval;
+
+ if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8))
+ || addr % len != 0)
+ retval = i386_handle_nonaligned_watchpoint (WP_REMOVE, addr, len, type);
+ else
+ {
+ unsigned len_rw = i386_length_and_rw_bits (len, type);
+
+ retval = i386_remove_aligned_watchpoint (addr, len_rw);
+ }
+
+ if (maint_show_dr)
+ i386_show_dr ("remove_watchpoint", addr, len, type);
+
+ return retval;
+}
+
+/* Return non-zero if we can watch a memory region that starts at
+ address ADDR and whose length is LEN bytes. */
+
+int
+i386_region_ok_for_watchpoint (CORE_ADDR addr, int len)
+{
+ int nregs;
+
+ /* Compute how many aligned watchpoints we would need to cover this
+ region. */
+ nregs = i386_handle_nonaligned_watchpoint (WP_COUNT, addr, len, hw_write);
+ return nregs <= DR_NADDR ? 1 : 0;
+}
+
+/* If the inferior has some watchpoint that triggered, return the
+ address associated with that watchpoint. Otherwise, return zero. */
+
+CORE_ADDR
+i386_stopped_data_address (void)
+{
+ CORE_ADDR addr = 0;
+ int i;
+
+ dr_status_mirror = I386_DR_LOW_GET_STATUS ();
+
+ ALL_DEBUG_REGISTERS(i)
+ {
+ if (I386_DR_WATCH_HIT (i)
+ /* This second condition makes sure DRi is set up for a data
+ watchpoint, not a hardware breakpoint. The reason is
+ that GDB doesn't call the target_stopped_data_address
+ method except for data watchpoints. In other words, I'm
+ being paranoid. */
+ && I386_DR_GET_RW_LEN (i) != 0)
+ {
+ addr = dr_mirror[i];
+ if (maint_show_dr)
+ i386_show_dr ("watchpoint_hit", addr, -1, hw_write);
+ }
+ }
+ if (maint_show_dr && addr == 0)
+ i386_show_dr ("stopped_data_addr", 0, 0, hw_write);
+
+ return addr;
+}
+
+/* Return non-zero if the inferior has some break/watchpoint that
+ triggered. */
+
+int
+i386_stopped_by_hwbp (void)
+{
+ int i;
+
+ dr_status_mirror = I386_DR_LOW_GET_STATUS ();
+ if (maint_show_dr)
+ i386_show_dr ("stopped_by_hwbp", 0, 0, hw_execute);
+
+ ALL_DEBUG_REGISTERS(i)
+ {
+ if (I386_DR_WATCH_HIT (i))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Insert a hardware-assisted breakpoint at address ADDR. SHADOW is
+ unused. Return 0 on success, EBUSY on failure. */
+int
+i386_insert_hw_breakpoint (CORE_ADDR addr, void *shadow)
+{
+ unsigned len_rw = i386_length_and_rw_bits (1, hw_execute);
+ int retval = i386_insert_aligned_watchpoint (addr, len_rw) ? EBUSY : 0;
+
+ if (maint_show_dr)
+ i386_show_dr ("insert_hwbp", addr, 1, hw_execute);
+
+ return retval;
+}
+
+/* Remove a hardware-assisted breakpoint at address ADDR. SHADOW is
+ unused. Return 0 on success, -1 on failure. */
+
+int
+i386_remove_hw_breakpoint (CORE_ADDR addr, void *shadow)
+{
+ unsigned len_rw = i386_length_and_rw_bits (1, hw_execute);
+ int retval = i386_remove_aligned_watchpoint (addr, len_rw);
+
+ if (maint_show_dr)
+ i386_show_dr ("remove_hwbp", addr, 1, hw_execute);
+
+ return retval;
+}
+
+#endif /* I386_USE_GENERIC_WATCHPOINTS */
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386_nat (void);
+
+void
+_initialize_i386_nat (void)
+{
+#ifdef I386_USE_GENERIC_WATCHPOINTS
+ /* A maintenance command to enable printing the internal DRi mirror
+ variables. */
+ add_set_cmd ("show-debug-regs", class_maintenance,
+ var_boolean, (char *) &maint_show_dr,
+ "\
+Set whether to show variables that mirror the x86 debug registers.\n\
+Use \"on\" to enable, \"off\" to disable.\n\
+If enabled, the debug registers values are shown when GDB inserts\n\
+or removes a hardware breakpoint or watchpoint, and when the inferior\n\
+triggers a breakpoint or watchpoint.", &maintenancelist);
+#endif
+}
diff --git a/contrib/gdb/gdb/i386-nto-tdep.c b/contrib/gdb/gdb/i386-nto-tdep.c
new file mode 100755
index 0000000..6d2f492
--- /dev/null
+++ b/contrib/gdb/gdb/i386-nto-tdep.c
@@ -0,0 +1,306 @@
+/* i386-nto-tdep.c - i386 specific functionality for QNX Neutrino.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by QNX Software Systems Ltd.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_string.h"
+#include "gdb_assert.h"
+#include "defs.h"
+#include "frame.h"
+#include "target.h"
+#include "regcache.h"
+#include "solib-svr4.h"
+#include "i386-tdep.h"
+#include "nto-tdep.h"
+#include "osabi.h"
+#include "i387-tdep.h"
+
+#ifndef X86_CPU_FXSR
+#define X86_CPU_FXSR (1L << 12)
+#endif
+
+/* Why 13? Look in our /usr/include/x86/context.h header at the
+ x86_cpu_registers structure and you'll see an 'exx' junk register
+ that is just filler. Don't ask me, ask the kernel guys. */
+#define NUM_GPREGS 13
+
+/* Map a GDB register number to an offset in the reg structure. */
+static int regmap[] = {
+ (7 * 4), /* eax */
+ (6 * 4), /* ecx */
+ (5 * 4), /* edx */
+ (4 * 4), /* ebx */
+ (11 * 4), /* esp */
+ (2 * 4), /* epb */
+ (1 * 4), /* esi */
+ (0 * 4), /* edi */
+ (8 * 4), /* eip */
+ (10 * 4), /* eflags */
+ (9 * 4), /* cs */
+ (12 * 4), /* ss */
+ (-1 * 4) /* filler */
+};
+
+/* Given a gdb regno, return the offset into Neutrino's register structure
+ or -1 if register is unknown. */
+static int
+nto_reg_offset (int regno)
+{
+ return (regno >= 0 && regno < NUM_GPREGS) ? regmap[regno] : -1;
+}
+
+static void
+i386nto_supply_gregset (char *gpregs)
+{
+ unsigned regno;
+ int empty = 0;
+
+ for (regno = 0; regno < FP0_REGNUM; regno++)
+ {
+ int offset = nto_reg_offset (regno);
+ if (offset == -1)
+ supply_register (regno, (char *) &empty);
+ else
+ supply_register (regno, gpregs + offset);
+ }
+}
+
+static void
+i386nto_supply_fpregset (char *fpregs)
+{
+ if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
+ i387_supply_fxsave (current_regcache, -1, fpregs);
+ else
+ i387_supply_fsave (current_regcache, -1, fpregs);
+}
+
+static void
+i386nto_supply_regset (int regset, char *data)
+{
+ switch (regset)
+ {
+ case NTO_REG_GENERAL: /* QNX has different ordering of GP regs than GDB. */
+ i386nto_supply_gregset (data);
+ break;
+ case NTO_REG_FLOAT:
+ i386nto_supply_fpregset (data);
+ break;
+ }
+}
+
+static int
+i386nto_regset_id (int regno)
+{
+ if (regno == -1)
+ return NTO_REG_END;
+ else if (regno < FP0_REGNUM)
+ return NTO_REG_GENERAL;
+ else if (regno < FPC_REGNUM)
+ return NTO_REG_FLOAT;
+
+ return -1; /* Error. */
+}
+
+static int
+i386nto_register_area (int regno, int regset, unsigned *off)
+{
+ int len;
+
+ *off = 0;
+ if (regset == NTO_REG_GENERAL)
+ {
+ if (regno == -1)
+ return NUM_GPREGS * 4;
+
+ *off = nto_reg_offset (regno);
+ if (*off == -1)
+ return 0;
+ return 4;
+ }
+ else if (regset == NTO_REG_FLOAT)
+ {
+ unsigned off_adjust, regsize, regset_size;
+
+ if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
+ {
+ off_adjust = 32;
+ regsize = 16;
+ regset_size = 512;
+ }
+ else
+ {
+ off_adjust = 28;
+ regsize = 10;
+ regset_size = 128;
+ }
+
+ if (regno == -1)
+ return regset_size;
+
+ *off = (regno - FP0_REGNUM) * regsize + off_adjust;
+ return 10;
+ /* Why 10 instead of regsize? GDB only stores 10 bytes per FP
+ register so if we're sending a register back to the target,
+ we only want pdebug to write 10 bytes so as not to clobber
+ the reserved 6 bytes in the fxsave structure. */
+ }
+ return -1;
+}
+
+static int
+i386nto_regset_fill (int regset, char *data)
+{
+ if (regset == NTO_REG_GENERAL)
+ {
+ int regno;
+
+ for (regno = 0; regno < NUM_GPREGS; regno++)
+ {
+ int offset = nto_reg_offset (regno);
+ if (offset != -1)
+ regcache_collect (regno, data + offset);
+ }
+ }
+ else if (regset == NTO_REG_FLOAT)
+ {
+ if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
+ i387_fill_fxsave (data, -1);
+ else
+ i387_fill_fsave (data, -1);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+static struct link_map_offsets *
+i386nto_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 8; /* The actual size is 20 bytes, but
+ only 8 bytes are used. */
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 20; /* The actual size is 552 bytes, but
+ only 20 bytes are used. */
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+static int
+i386nto_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ return name && strcmp ("__signalstub", name) == 0;
+}
+
+#define I386_NTO_SIGCONTEXT_OFFSET 136
+
+/* Assuming NEXT_FRAME is a frame following a QNX Neutrino sigtramp
+ routine, return the address of the associated sigcontext structure. */
+
+static CORE_ADDR
+i386nto_sigcontext_addr (struct frame_info *next_frame)
+{
+ char buf[4];
+ CORE_ADDR sp;
+
+ frame_unwind_register (next_frame, SP_REGNUM, buf);
+ sp = extract_unsigned_integer (buf, 4);
+
+ return sp + I386_NTO_SIGCONTEXT_OFFSET;
+}
+
+static void
+init_i386nto_ops (void)
+{
+ current_nto_target.nto_regset_id = i386nto_regset_id;
+ current_nto_target.nto_supply_gregset = i386nto_supply_gregset;
+ current_nto_target.nto_supply_fpregset = i386nto_supply_fpregset;
+ current_nto_target.nto_supply_altregset = nto_dummy_supply_regset;
+ current_nto_target.nto_supply_regset = i386nto_supply_regset;
+ current_nto_target.nto_register_area = i386nto_register_area;
+ current_nto_target.nto_regset_fill = i386nto_regset_fill;
+ current_nto_target.nto_fetch_link_map_offsets =
+ i386nto_svr4_fetch_link_map_offsets;
+}
+
+static void
+i386nto_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* NTO uses ELF. */
+ i386_elf_init_abi (info, gdbarch);
+
+ /* Neutrino rewinds to look more normal. Need to override the i386
+ default which is [unfortunately] to decrement the PC. */
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+
+ /* NTO has shared libraries. */
+ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386nto_pc_in_sigtramp);
+ tdep->sigcontext_addr = i386nto_sigcontext_addr;
+ tdep->sc_pc_offset = 56;
+ tdep->sc_sp_offset = 68;
+
+ /* Setjmp()'s return PC saved in EDX (5). */
+ tdep->jb_pc_offset = 20; /* 5x32 bit ints in. */
+
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ i386nto_svr4_fetch_link_map_offsets);
+
+ /* Our loader handles solib relocations slightly differently than svr4. */
+ TARGET_SO_RELOCATE_SECTION_ADDRESSES = nto_relocate_section_addresses;
+
+ /* Supply a nice function to find our solibs. */
+ TARGET_SO_FIND_AND_OPEN_SOLIB = nto_find_and_open_solib;
+
+ init_i386nto_ops ();
+}
+
+void
+_initialize_i386nto_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_QNXNTO,
+ i386nto_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386-sol2-tdep.c b/contrib/gdb/gdb/i386-sol2-tdep.c
new file mode 100644
index 0000000..0da32d5
--- /dev/null
+++ b/contrib/gdb/gdb/i386-sol2-tdep.c
@@ -0,0 +1,120 @@
+/* Target-dependent code for Solaris x86.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "osabi.h"
+
+#include "i386-tdep.h"
+
+/* From <ia32/sys/reg.h>. */
+static int i386_sol2_gregset_reg_offset[] =
+{
+ 11 * 4, /* %eax */
+ 10 * 4, /* %ecx */
+ 9 * 4, /* %edx */
+ 8 * 4, /* %ebx */
+ 17 * 4, /* %esp */
+ 6 * 4, /* %ebp */
+ 5 * 4, /* %esi */
+ 4 * 4, /* %edi */
+ 14 * 4, /* %eip */
+ 16 * 4, /* %eflags */
+ 15 * 4, /* %cs */
+ 18 * 4, /* %ss */
+ 3 * 4, /* %ds */
+ 2 * 4, /* %es */
+ 1 * 4, /* %fs */
+ 0 * 4 /* %gs */
+};
+
+static int
+i386_sol2_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ /* Signal handler frames under Solaris 2 are recognized by a return
+ address of 0xffffffff. */
+ return (pc == 0xffffffff);
+}
+
+/* Solaris doesn't have a `struct sigcontext', but it does have a
+ `mcontext_t' that contains the saved set of machine registers. */
+
+static CORE_ADDR
+i386_sol2_mcontext_addr (struct frame_info *next_frame)
+{
+ CORE_ADDR sp, ucontext_addr;
+
+ sp = frame_unwind_register_unsigned (next_frame, I386_ESP_REGNUM);
+ ucontext_addr = get_frame_memory_unsigned (next_frame, sp + 8, 4);
+
+ return ucontext_addr + 36;
+}
+
+/* Solaris 2. */
+
+static void
+i386_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Solaris is SVR4-based. */
+ i386_svr4_init_abi (info, gdbarch);
+
+ /* Solaris reserves space for its FPU emulator in `fpregset_t'.
+ There is also some space reserved for the registers of a Weitek
+ math coprocessor. */
+ tdep->gregset_reg_offset = i386_sol2_gregset_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (i386_sol2_gregset_reg_offset);
+ tdep->sizeof_gregset = 19 * 4;
+ tdep->sizeof_fpregset = 380;
+
+ tdep->sigcontext_addr = i386_sol2_mcontext_addr;
+ tdep->sc_reg_offset = tdep->gregset_reg_offset;
+ tdep->sc_num_regs = tdep->gregset_num_regs;
+
+ /* Signal trampolines are slightly different from SVR4. */
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386_sol2_pc_in_sigtramp);
+}
+
+
+static enum gdb_osabi
+i386_sol2_osabi_sniffer (bfd *abfd)
+{
+ /* If we have a section named .SUNW_version, then it is almost
+ certainly Solaris 2. */
+ if (bfd_get_section_by_name (abfd, ".SUNW_version"))
+ return GDB_OSABI_SOLARIS;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386_sol2_tdep (void);
+
+void
+_initialize_i386_sol2_tdep (void)
+{
+ /* Register an ELF OS ABI sniffer for Solaris 2 binaries. */
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+ i386_sol2_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_SOLARIS,
+ i386_sol2_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386-stub.c b/contrib/gdb/gdb/i386-stub.c
new file mode 100644
index 0000000..1251567
--- /dev/null
+++ b/contrib/gdb/gdb/i386-stub.c
@@ -0,0 +1,952 @@
+/****************************************************************************
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ HP offers the following for use in the public domain. HP makes no
+ warranty with regard to the software or it's performance and the
+ user accepts the software "AS IS" with all faults.
+
+ HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+ TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ * Module name: remcom.c $
+ * Revision: 1.34 $
+ * Date: 91/03/09 12:29:49 $
+ * Contributor: Lake Stevens Instrument Division$
+ *
+ * Description: low level support for gdb debugger. $
+ *
+ * Considerations: only works on target hardware $
+ *
+ * Written by: Glenn Engel $
+ * ModuleState: Experimental $
+ *
+ * NOTES: See Below $
+ *
+ * Modified for 386 by Jim Kingdon, Cygnus Support.
+ *
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a trap #1.
+ *
+ * The external function exceptionHandler() is
+ * used to attach a specific handler to a specific 386 vector number.
+ * It should use the same privilege level it runs at. It should
+ * install it as an interrupt gate so that interrupts are masked
+ * while the handler runs.
+ *
+ * Because gdb will sometimes write to the stack area to execute function
+ * calls, this program cannot rely on using the supervisor stack so it
+ * uses it's own stack area reserved in the int array remcomStack.
+ *
+ *************
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+
+extern void putDebugChar(); /* write a single character */
+extern int getDebugChar(); /* read and return a single char */
+extern void exceptionHandler(); /* assign an exception handler */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+#define BUFMAX 400
+
+static char initialized; /* boolean flag. != 0 means we've been initialized */
+
+int remote_debug;
+/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Number of registers. */
+#define NUMREGS 16
+
+/* Number of bytes of registers. */
+#define NUMREGBYTES (NUMREGS * 4)
+
+enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
+ PC /* also known as eip */,
+ PS /* also known as eflags */,
+ CS, SS, DS, ES, FS, GS};
+
+/*
+ * these should not be static cuz they can be used outside this module
+ */
+int registers[NUMREGS];
+
+#define STACKSIZE 10000
+int remcomStack[STACKSIZE/sizeof(int)];
+static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
+
+/*************************** ASSEMBLY CODE MACROS *************************/
+/* */
+
+extern void
+return_to_prog ();
+
+/* Restore the program's registers (including the stack pointer, which
+ means we get the right stack and don't have to worry about popping our
+ return address and any stack frames and so on) and return. */
+asm(".text");
+asm(".globl _return_to_prog");
+asm("_return_to_prog:");
+asm(" movw _registers+44, %ss");
+asm(" movl _registers+16, %esp");
+asm(" movl _registers+4, %ecx");
+asm(" movl _registers+8, %edx");
+asm(" movl _registers+12, %ebx");
+asm(" movl _registers+20, %ebp");
+asm(" movl _registers+24, %esi");
+asm(" movl _registers+28, %edi");
+asm(" movw _registers+48, %ds");
+asm(" movw _registers+52, %es");
+asm(" movw _registers+56, %fs");
+asm(" movw _registers+60, %gs");
+asm(" movl _registers+36, %eax");
+asm(" pushl %eax"); /* saved eflags */
+asm(" movl _registers+40, %eax");
+asm(" pushl %eax"); /* saved cs */
+asm(" movl _registers+32, %eax");
+asm(" pushl %eax"); /* saved eip */
+asm(" movl _registers, %eax");
+/* use iret to restore pc and flags together so
+ that trace flag works right. */
+asm(" iret");
+
+#define BREAKPOINT() asm(" int $3");
+
+/* Put the error code here just in case the user cares. */
+int gdb_i386errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+ number through the usual means, and that's not very specific). */
+int gdb_i386vector = -1;
+
+/* GDB stores segment registers in 32-bit words (that's just the way
+ m-i386v.h is written). So zero the appropriate areas in registers. */
+#define SAVE_REGISTERS1() \
+ asm ("movl %eax, _registers"); \
+ asm ("movl %ecx, _registers+4"); \
+ asm ("movl %edx, _registers+8"); \
+ asm ("movl %ebx, _registers+12"); \
+ asm ("movl %ebp, _registers+20"); \
+ asm ("movl %esi, _registers+24"); \
+ asm ("movl %edi, _registers+28"); \
+ asm ("movw $0, %ax"); \
+ asm ("movw %ds, _registers+48"); \
+ asm ("movw %ax, _registers+50"); \
+ asm ("movw %es, _registers+52"); \
+ asm ("movw %ax, _registers+54"); \
+ asm ("movw %fs, _registers+56"); \
+ asm ("movw %ax, _registers+58"); \
+ asm ("movw %gs, _registers+60"); \
+ asm ("movw %ax, _registers+62");
+#define SAVE_ERRCODE() \
+ asm ("popl %ebx"); \
+ asm ("movl %ebx, _gdb_i386errcode");
+#define SAVE_REGISTERS2() \
+ asm ("popl %ebx"); /* old eip */ \
+ asm ("movl %ebx, _registers+32"); \
+ asm ("popl %ebx"); /* old cs */ \
+ asm ("movl %ebx, _registers+40"); \
+ asm ("movw %ax, _registers+42"); \
+ asm ("popl %ebx"); /* old eflags */ \
+ asm ("movl %ebx, _registers+36"); \
+ /* Now that we've done the pops, we can save the stack pointer."); */ \
+ asm ("movw %ss, _registers+44"); \
+ asm ("movw %ax, _registers+46"); \
+ asm ("movl %esp, _registers+16");
+
+/* See if mem_fault_routine is set, if so just IRET to that address. */
+#define CHECK_FAULT() \
+ asm ("cmpl $0, _mem_fault_routine"); \
+ asm ("jne mem_fault");
+
+asm (".text");
+asm ("mem_fault:");
+/* OK to clobber temp registers; we're just going to end up in set_mem_err. */
+/* Pop error code from the stack and save it. */
+asm (" popl %eax");
+asm (" movl %eax, _gdb_i386errcode");
+
+asm (" popl %eax"); /* eip */
+/* We don't want to return there, we want to return to the function
+ pointed to by mem_fault_routine instead. */
+asm (" movl _mem_fault_routine, %eax");
+asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */
+asm (" popl %edx"); /* eflags */
+
+/* Remove this stack frame; when we do the iret, we will be going to
+ the start of a function, so we want the stack to look just like it
+ would after a "call" instruction. */
+asm (" leave");
+
+/* Push the stuff that iret wants. */
+asm (" pushl %edx"); /* eflags */
+asm (" pushl %ecx"); /* cs */
+asm (" pushl %eax"); /* eip */
+
+/* Zero mem_fault_routine. */
+asm (" movl $0, %eax");
+asm (" movl %eax, _mem_fault_routine");
+
+asm ("iret");
+
+#define CALL_HOOK() asm("call _remcomHandler");
+
+/* This function is called when a i386 exception occurs. It saves
+ * all the cpu regs in the _registers array, munges the stack a bit,
+ * and invokes an exception handler (remcom_handler).
+ *
+ * stack on entry: stack on exit:
+ * old eflags vector number
+ * old cs (zero-filled to 32 bits)
+ * old eip
+ *
+ */
+extern void _catchException3();
+asm(".text");
+asm(".globl __catchException3");
+asm("__catchException3:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $3");
+CALL_HOOK();
+
+/* Same thing for exception 1. */
+extern void _catchException1();
+asm(".text");
+asm(".globl __catchException1");
+asm("__catchException1:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $1");
+CALL_HOOK();
+
+/* Same thing for exception 0. */
+extern void _catchException0();
+asm(".text");
+asm(".globl __catchException0");
+asm("__catchException0:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $0");
+CALL_HOOK();
+
+/* Same thing for exception 4. */
+extern void _catchException4();
+asm(".text");
+asm(".globl __catchException4");
+asm("__catchException4:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $4");
+CALL_HOOK();
+
+/* Same thing for exception 5. */
+extern void _catchException5();
+asm(".text");
+asm(".globl __catchException5");
+asm("__catchException5:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $5");
+CALL_HOOK();
+
+/* Same thing for exception 6. */
+extern void _catchException6();
+asm(".text");
+asm(".globl __catchException6");
+asm("__catchException6:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $6");
+CALL_HOOK();
+
+/* Same thing for exception 7. */
+extern void _catchException7();
+asm(".text");
+asm(".globl __catchException7");
+asm("__catchException7:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $7");
+CALL_HOOK();
+
+/* Same thing for exception 8. */
+extern void _catchException8();
+asm(".text");
+asm(".globl __catchException8");
+asm("__catchException8:");
+SAVE_REGISTERS1();
+SAVE_ERRCODE();
+SAVE_REGISTERS2();
+asm ("pushl $8");
+CALL_HOOK();
+
+/* Same thing for exception 9. */
+extern void _catchException9();
+asm(".text");
+asm(".globl __catchException9");
+asm("__catchException9:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $9");
+CALL_HOOK();
+
+/* Same thing for exception 10. */
+extern void _catchException10();
+asm(".text");
+asm(".globl __catchException10");
+asm("__catchException10:");
+SAVE_REGISTERS1();
+SAVE_ERRCODE();
+SAVE_REGISTERS2();
+asm ("pushl $10");
+CALL_HOOK();
+
+/* Same thing for exception 12. */
+extern void _catchException12();
+asm(".text");
+asm(".globl __catchException12");
+asm("__catchException12:");
+SAVE_REGISTERS1();
+SAVE_ERRCODE();
+SAVE_REGISTERS2();
+asm ("pushl $12");
+CALL_HOOK();
+
+/* Same thing for exception 16. */
+extern void _catchException16();
+asm(".text");
+asm(".globl __catchException16");
+asm("__catchException16:");
+SAVE_REGISTERS1();
+SAVE_REGISTERS2();
+asm ("pushl $16");
+CALL_HOOK();
+
+/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
+
+/* Same thing for exception 13. */
+extern void _catchException13 ();
+asm (".text");
+asm (".globl __catchException13");
+asm ("__catchException13:");
+CHECK_FAULT();
+SAVE_REGISTERS1();
+SAVE_ERRCODE();
+SAVE_REGISTERS2();
+asm ("pushl $13");
+CALL_HOOK();
+
+/* Same thing for exception 11. */
+extern void _catchException11 ();
+asm (".text");
+asm (".globl __catchException11");
+asm ("__catchException11:");
+CHECK_FAULT();
+SAVE_REGISTERS1();
+SAVE_ERRCODE();
+SAVE_REGISTERS2();
+asm ("pushl $11");
+CALL_HOOK();
+
+/* Same thing for exception 14. */
+extern void _catchException14 ();
+asm (".text");
+asm (".globl __catchException14");
+asm ("__catchException14:");
+CHECK_FAULT();
+SAVE_REGISTERS1();
+SAVE_ERRCODE();
+SAVE_REGISTERS2();
+asm ("pushl $14");
+CALL_HOOK();
+
+/*
+ * remcomHandler is a front end for handle_exception. It moves the
+ * stack pointer into an area reserved for debugger use.
+ */
+asm("_remcomHandler:");
+asm(" popl %eax"); /* pop off return address */
+asm(" popl %eax"); /* get the exception number */
+asm(" movl _stackPtr, %esp"); /* move to remcom stack area */
+asm(" pushl %eax"); /* push exception onto stack */
+asm(" call _handle_exception"); /* this never returns */
+
+void
+_returnFromException ()
+{
+ return_to_prog ();
+}
+
+int
+hex (ch)
+ char ch;
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ return (ch - 'a' + 10);
+ if ((ch >= '0') && (ch <= '9'))
+ return (ch - '0');
+ if ((ch >= 'A') && (ch <= 'F'))
+ return (ch - 'A' + 10);
+ return (-1);
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+/* scan for the sequence $<data>#<checksum> */
+
+unsigned char *
+getpacket (void)
+{
+ unsigned char *buffer = &remcomInBuffer[0];
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int count;
+ char ch;
+
+ while (1)
+ {
+ /* wait around for the start character, ignore all other characters */
+ while ((ch = getDebugChar ()) != '$')
+ ;
+
+ retry:
+ checksum = 0;
+ xmitcsum = -1;
+ count = 0;
+
+ /* now, read until a # or end of buffer is found */
+ while (count < BUFMAX)
+ {
+ ch = getDebugChar ();
+ if (ch == '$')
+ goto retry;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+ buffer[count] = 0;
+
+ if (ch == '#')
+ {
+ ch = getDebugChar ();
+ xmitcsum = hex (ch) << 4;
+ ch = getDebugChar ();
+ xmitcsum += hex (ch);
+
+ if (checksum != xmitcsum)
+ {
+ if (remote_debug)
+ {
+ fprintf (stderr,
+ "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
+ checksum, xmitcsum, buffer);
+ }
+ putDebugChar ('-'); /* failed checksum */
+ }
+ else
+ {
+ putDebugChar ('+'); /* successful transfer */
+
+ /* if a sequence char is present, reply the sequence ID */
+ if (buffer[2] == ':')
+ {
+ putDebugChar (buffer[0]);
+ putDebugChar (buffer[1]);
+
+ return &buffer[3];
+ }
+
+ return &buffer[0];
+ }
+ }
+ }
+}
+
+/* send the packet in buffer. */
+
+void
+putpacket (unsigned char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ char ch;
+
+ /* $<packet info>#<checksum>. */
+ do
+ {
+ putDebugChar ('$');
+ checksum = 0;
+ count = 0;
+
+ while (ch = buffer[count])
+ {
+ putDebugChar (ch);
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar ('#');
+ putDebugChar (hexchars[checksum >> 4]);
+ putDebugChar (hexchars[checksum % 16]);
+
+ }
+ while (getDebugChar () != '+');
+}
+
+void
+debug_error (format, parm)
+ char *format;
+ char *parm;
+{
+ if (remote_debug)
+ fprintf (stderr, format, parm);
+}
+
+/* Address of a routine to RTE to if we get a memory fault. */
+static void (*volatile mem_fault_routine) () = NULL;
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+ error. */
+static volatile int mem_err = 0;
+
+void
+set_mem_err (void)
+{
+ mem_err = 1;
+}
+
+/* These are separate functions so that they are so short and sweet
+ that the compiler won't save any registers (if there is a fault
+ to mem_fault, they won't get restored, so there better not be any
+ saved). */
+int
+get_char (char *addr)
+{
+ return *addr;
+}
+
+void
+set_char (char *addr, int val)
+{
+ *addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+ a fault; if zero treat a fault like any other fault in the stub. */
+char *
+mem2hex (mem, buf, count, may_fault)
+ char *mem;
+ char *buf;
+ int count;
+ int may_fault;
+{
+ int i;
+ unsigned char ch;
+
+ if (may_fault)
+ mem_fault_routine = set_mem_err;
+ for (i = 0; i < count; i++)
+ {
+ ch = get_char (mem++);
+ if (may_fault && mem_err)
+ return (buf);
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch % 16];
+ }
+ *buf = 0;
+ if (may_fault)
+ mem_fault_routine = NULL;
+ return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+char *
+hex2mem (buf, mem, count, may_fault)
+ char *buf;
+ char *mem;
+ int count;
+ int may_fault;
+{
+ int i;
+ unsigned char ch;
+
+ if (may_fault)
+ mem_fault_routine = set_mem_err;
+ for (i = 0; i < count; i++)
+ {
+ ch = hex (*buf++) << 4;
+ ch = ch + hex (*buf++);
+ set_char (mem++, ch);
+ if (may_fault && mem_err)
+ return (mem);
+ }
+ if (may_fault)
+ mem_fault_routine = NULL;
+ return (mem);
+}
+
+/* this function takes the 386 exception vector and attempts to
+ translate this number into a unix compatible signal value */
+int
+computeSignal (int exceptionVector)
+{
+ int sigval;
+ switch (exceptionVector)
+ {
+ case 0:
+ sigval = 8;
+ break; /* divide by zero */
+ case 1:
+ sigval = 5;
+ break; /* debug exception */
+ case 3:
+ sigval = 5;
+ break; /* breakpoint */
+ case 4:
+ sigval = 16;
+ break; /* into instruction (overflow) */
+ case 5:
+ sigval = 16;
+ break; /* bound instruction */
+ case 6:
+ sigval = 4;
+ break; /* Invalid opcode */
+ case 7:
+ sigval = 8;
+ break; /* coprocessor not available */
+ case 8:
+ sigval = 7;
+ break; /* double fault */
+ case 9:
+ sigval = 11;
+ break; /* coprocessor segment overrun */
+ case 10:
+ sigval = 11;
+ break; /* Invalid TSS */
+ case 11:
+ sigval = 11;
+ break; /* Segment not present */
+ case 12:
+ sigval = 11;
+ break; /* stack exception */
+ case 13:
+ sigval = 11;
+ break; /* general protection */
+ case 14:
+ sigval = 11;
+ break; /* page fault */
+ case 16:
+ sigval = 7;
+ break; /* coprocessor error */
+ default:
+ sigval = 7; /* "software generated" */
+ }
+ return (sigval);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED */
+/**********************************************/
+int
+hexToInt (char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ while (**ptr)
+ {
+ hexValue = hex (**ptr);
+ if (hexValue >= 0)
+ {
+ *intValue = (*intValue << 4) | hexValue;
+ numChars++;
+ }
+ else
+ break;
+
+ (*ptr)++;
+ }
+
+ return (numChars);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ */
+void
+handle_exception (int exceptionVector)
+{
+ int sigval, stepping;
+ int addr, length;
+ char *ptr;
+ int newPC;
+
+ gdb_i386vector = exceptionVector;
+
+ if (remote_debug)
+ {
+ printf ("vector=%d, sr=0x%x, pc=0x%x\n",
+ exceptionVector, registers[PS], registers[PC]);
+ }
+
+ /* reply to host that an exception has occurred */
+ sigval = computeSignal (exceptionVector);
+
+ ptr = remcomOutBuffer;
+
+ *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
+ *ptr++ = hexchars[sigval >> 4];
+ *ptr++ = hexchars[sigval & 0xf];
+
+ *ptr++ = hexchars[ESP];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[ESP], ptr, 4, 0); /* SP */
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[EBP];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[EBP], ptr, 4, 0); /* FP */
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[PC];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[PC], ptr, 4, 0); /* PC */
+ *ptr++ = ';';
+
+ *ptr = '\0'
+
+ putpacket (remcomOutBuffer);
+
+ stepping = 0;
+
+ while (1 == 1)
+ {
+ remcomOutBuffer[0] = 0;
+ ptr = getpacket ();
+
+ switch (*ptr++)
+ {
+ case '?':
+ remcomOutBuffer[0] = 'S';
+ remcomOutBuffer[1] = hexchars[sigval >> 4];
+ remcomOutBuffer[2] = hexchars[sigval % 16];
+ remcomOutBuffer[3] = 0;
+ break;
+ case 'd':
+ remote_debug = !(remote_debug); /* toggle debug flag */
+ break;
+ case 'g': /* return the value of the CPU registers */
+ mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0);
+ break;
+ case 'G': /* set the value of the CPU registers - return OK */
+ hex2mem (ptr, (char *) registers, NUMREGBYTES, 0);
+ strcpy (remcomOutBuffer, "OK");
+ break;
+ case 'P': /* set the value of a single CPU register - return OK */
+ {
+ int regno;
+
+ if (hexToInt (&ptr, &regno) && *ptr++ == '=')
+ if (regno >= 0 && regno < NUMREGS)
+ {
+ hex2mem (ptr, (char *) &registers[regno], 4, 0);
+ strcpy (remcomOutBuffer, "OK");
+ break;
+ }
+
+ strcpy (remcomOutBuffer, "E01");
+ break;
+ }
+
+ /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
+ case 'm':
+ /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
+ if (hexToInt (&ptr, &addr))
+ if (*(ptr++) == ',')
+ if (hexToInt (&ptr, &length))
+ {
+ ptr = 0;
+ mem_err = 0;
+ mem2hex ((char *) addr, remcomOutBuffer, length, 1);
+ if (mem_err)
+ {
+ strcpy (remcomOutBuffer, "E03");
+ debug_error ("memory fault");
+ }
+ }
+
+ if (ptr)
+ {
+ strcpy (remcomOutBuffer, "E01");
+ }
+ break;
+
+ /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+ case 'M':
+ /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
+ if (hexToInt (&ptr, &addr))
+ if (*(ptr++) == ',')
+ if (hexToInt (&ptr, &length))
+ if (*(ptr++) == ':')
+ {
+ mem_err = 0;
+ hex2mem (ptr, (char *) addr, length, 1);
+
+ if (mem_err)
+ {
+ strcpy (remcomOutBuffer, "E03");
+ debug_error ("memory fault");
+ }
+ else
+ {
+ strcpy (remcomOutBuffer, "OK");
+ }
+
+ ptr = 0;
+ }
+ if (ptr)
+ {
+ strcpy (remcomOutBuffer, "E02");
+ }
+ break;
+
+ /* cAA..AA Continue at address AA..AA(optional) */
+ /* sAA..AA Step one instruction from AA..AA(optional) */
+ case 's':
+ stepping = 1;
+ case 'c':
+ /* try to read optional parameter, pc unchanged if no parm */
+ if (hexToInt (&ptr, &addr))
+ registers[PC] = addr;
+
+ newPC = registers[PC];
+
+ /* clear the trace bit */
+ registers[PS] &= 0xfffffeff;
+
+ /* set the trace bit if we're stepping */
+ if (stepping)
+ registers[PS] |= 0x100;
+
+ _returnFromException (); /* this is a jump */
+ break;
+
+ /* kill the program */
+ case 'k': /* do nothing */
+#if 0
+ /* Huh? This doesn't look like "nothing".
+ m68k-stub.c and sparc-stub.c don't have it. */
+ BREAKPOINT ();
+#endif
+ break;
+ } /* switch */
+
+ /* reply to the request */
+ putpacket (remcomOutBuffer);
+ }
+}
+
+/* this function is used to set up exception handlers for tracing and
+ breakpoints */
+void
+set_debug_traps (void)
+{
+ stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
+
+ exceptionHandler (0, _catchException0);
+ exceptionHandler (1, _catchException1);
+ exceptionHandler (3, _catchException3);
+ exceptionHandler (4, _catchException4);
+ exceptionHandler (5, _catchException5);
+ exceptionHandler (6, _catchException6);
+ exceptionHandler (7, _catchException7);
+ exceptionHandler (8, _catchException8);
+ exceptionHandler (9, _catchException9);
+ exceptionHandler (10, _catchException10);
+ exceptionHandler (11, _catchException11);
+ exceptionHandler (12, _catchException12);
+ exceptionHandler (13, _catchException13);
+ exceptionHandler (14, _catchException14);
+ exceptionHandler (16, _catchException16);
+
+ initialized = 1;
+}
+
+/* This function will generate a breakpoint exception. It is used at the
+ beginning of a program to sync up with a debugger and can be used
+ otherwise as a quick means to stop program execution and "break" into
+ the debugger. */
+
+void
+breakpoint (void)
+{
+ if (initialized)
+ BREAKPOINT ();
+}
diff --git a/contrib/gdb/gdb/i386-tdep.c b/contrib/gdb/gdb/i386-tdep.c
new file mode 100644
index 0000000..e1ce81f
--- /dev/null
+++ b/contrib/gdb/gdb/i386-tdep.c
@@ -0,0 +1,2109 @@
+/* Intel 386 target-dependent stuff.
+
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "command.h"
+#include "dummy-frame.h"
+#include "dwarf2-frame.h"
+#include "doublest.h"
+#include "floatformat.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "inferior.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "reggroups.h"
+#include "regset.h"
+#include "symfile.h"
+#include "symtab.h"
+#include "target.h"
+#include "value.h"
+#include "dis-asm.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+
+/* Names of the registers. The first 10 registers match the register
+ numbering scheme used by GCC for stabs and DWARF. */
+
+static char *i386_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",
+ "fctrl", "fstat", "ftag", "fiseg",
+ "fioff", "foseg", "fooff", "fop",
+ "xmm0", "xmm1", "xmm2", "xmm3",
+ "xmm4", "xmm5", "xmm6", "xmm7",
+ "mxcsr"
+};
+
+static const int i386_num_register_names = ARRAY_SIZE (i386_register_names);
+
+/* MMX registers. */
+
+static char *i386_mmx_names[] =
+{
+ "mm0", "mm1", "mm2", "mm3",
+ "mm4", "mm5", "mm6", "mm7"
+};
+
+static const int i386_num_mmx_regs = ARRAY_SIZE (i386_mmx_names);
+
+static int
+i386_mmx_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ int mm0_regnum = gdbarch_tdep (gdbarch)->mm0_regnum;
+
+ if (mm0_regnum < 0)
+ return 0;
+
+ return (regnum >= mm0_regnum && regnum < mm0_regnum + i386_num_mmx_regs);
+}
+
+/* SSE register? */
+
+static int
+i386_sse_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ if (I387_NUM_XMM_REGS == 0)
+ return 0;
+
+ return (I387_XMM0_REGNUM <= regnum && regnum < I387_MXCSR_REGNUM);
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
+}
+
+static int
+i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ if (I387_NUM_XMM_REGS == 0)
+ return 0;
+
+ return (regnum == I387_MXCSR_REGNUM);
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
+}
+
+#define I387_ST0_REGNUM (gdbarch_tdep (current_gdbarch)->st0_regnum)
+#define I387_MM0_REGNUM (gdbarch_tdep (current_gdbarch)->mm0_regnum)
+#define I387_NUM_XMM_REGS (gdbarch_tdep (current_gdbarch)->num_xmm_regs)
+
+/* FP register? */
+
+int
+i386_fp_regnum_p (int regnum)
+{
+ if (I387_ST0_REGNUM < 0)
+ return 0;
+
+ return (I387_ST0_REGNUM <= regnum && regnum < I387_FCTRL_REGNUM);
+}
+
+int
+i386_fpc_regnum_p (int regnum)
+{
+ if (I387_ST0_REGNUM < 0)
+ return 0;
+
+ return (I387_FCTRL_REGNUM <= regnum && regnum < I387_XMM0_REGNUM);
+}
+
+/* Return the name of register REG. */
+
+const char *
+i386_register_name (int reg)
+{
+ if (i386_mmx_regnum_p (current_gdbarch, reg))
+ return i386_mmx_names[reg - I387_MM0_REGNUM];
+
+ if (reg >= 0 && reg < i386_num_register_names)
+ return i386_register_names[reg];
+
+ return NULL;
+}
+
+/* Convert stabs register number REG to the appropriate register
+ number used by GDB. */
+
+static int
+i386_stab_reg_to_regnum (int reg)
+{
+ /* This implements what GCC calls the "default" register map. */
+ if (reg >= 0 && reg <= 7)
+ {
+ /* General-purpose registers. */
+ return reg;
+ }
+ else if (reg >= 12 && reg <= 19)
+ {
+ /* Floating-point registers. */
+ return reg - 12 + I387_ST0_REGNUM;
+ }
+ else if (reg >= 21 && reg <= 28)
+ {
+ /* SSE registers. */
+ return reg - 21 + I387_XMM0_REGNUM;
+ }
+ else if (reg >= 29 && reg <= 36)
+ {
+ /* MMX registers. */
+ return reg - 29 + I387_MM0_REGNUM;
+ }
+
+ /* This will hopefully provoke a warning. */
+ return NUM_REGS + NUM_PSEUDO_REGS;
+}
+
+/* Convert DWARF register number REG to the appropriate register
+ number used by GDB. */
+
+static int
+i386_dwarf_reg_to_regnum (int reg)
+{
+ /* The DWARF register numbering includes %eip and %eflags, and
+ numbers the floating point registers differently. */
+ if (reg >= 0 && reg <= 9)
+ {
+ /* General-purpose registers. */
+ return reg;
+ }
+ else if (reg >= 11 && reg <= 18)
+ {
+ /* Floating-point registers. */
+ return reg - 11 + I387_ST0_REGNUM;
+ }
+ else if (reg >= 21)
+ {
+ /* The SSE and MMX registers have identical numbers as in stabs. */
+ return i386_stab_reg_to_regnum (reg);
+ }
+
+ /* This will hopefully provoke a warning. */
+ return NUM_REGS + NUM_PSEUDO_REGS;
+}
+
+#undef I387_ST0_REGNUM
+#undef I387_MM0_REGNUM
+#undef I387_NUM_XMM_REGS
+
+
+/* This is the variable that is set with "set disassembly-flavor", and
+ its legitimate values. */
+static const char att_flavor[] = "att";
+static const char intel_flavor[] = "intel";
+static const char *valid_flavors[] =
+{
+ att_flavor,
+ intel_flavor,
+ NULL
+};
+static const char *disassembly_flavor = att_flavor;
+
+
+/* Use the program counter to determine the contents and size of a
+ breakpoint instruction. Return a pointer to a string of bytes that
+ encode a breakpoint instruction, store the length of the string in
+ *LEN and optionally adjust *PC to point to the correct memory
+ location for inserting the breakpoint.
+
+ On the i386 we have a single breakpoint that fits in a single byte
+ and can be inserted anywhere.
+
+ This function is 64-bit safe. */
+
+static const unsigned char *
+i386_breakpoint_from_pc (CORE_ADDR *pc, int *len)
+{
+ static unsigned char break_insn[] = { 0xcc }; /* int 3 */
+
+ *len = sizeof (break_insn);
+ return break_insn;
+}
+
+#ifdef I386_REGNO_TO_SYMMETRY
+#error "The Sequent Symmetry is no longer supported."
+#endif
+
+/* According to the System V ABI, the registers %ebp, %ebx, %edi, %esi
+ and %esp "belong" to the calling function. Therefore these
+ registers should be saved if they're going to be modified. */
+
+/* The maximum number of saved registers. This should include all
+ registers mentioned above, and %eip. */
+#define I386_NUM_SAVED_REGS I386_NUM_GREGS
+
+struct i386_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR sp_offset;
+ CORE_ADDR pc;
+
+ /* Saved registers. */
+ CORE_ADDR saved_regs[I386_NUM_SAVED_REGS];
+ CORE_ADDR saved_sp;
+ int pc_in_eax;
+
+ /* Stack space reserved for local variables. */
+ long locals;
+};
+
+/* Allocate and initialize a frame cache. */
+
+static struct i386_frame_cache *
+i386_alloc_frame_cache (void)
+{
+ struct i386_frame_cache *cache;
+ int i;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);
+
+ /* Base address. */
+ cache->base = 0;
+ cache->sp_offset = -4;
+ cache->pc = 0;
+
+ /* Saved registers. We initialize these to -1 since zero is a valid
+ offset (that's where %ebp is supposed to be stored). */
+ for (i = 0; i < I386_NUM_SAVED_REGS; i++)
+ cache->saved_regs[i] = -1;
+ cache->saved_sp = 0;
+ cache->pc_in_eax = 0;
+
+ /* Frameless until proven otherwise. */
+ cache->locals = -1;
+
+ return cache;
+}
+
+/* If the instruction at PC is a jump, return the address of its
+ target. Otherwise, return PC. */
+
+static CORE_ADDR
+i386_follow_jump (CORE_ADDR pc)
+{
+ unsigned char op;
+ long delta = 0;
+ int data16 = 0;
+
+ op = read_memory_unsigned_integer (pc, 1);
+ if (op == 0x66)
+ {
+ data16 = 1;
+ op = read_memory_unsigned_integer (pc + 1, 1);
+ }
+
+ switch (op)
+ {
+ case 0xe9:
+ /* Relative jump: if data16 == 0, disp32, else disp16. */
+ if (data16)
+ {
+ delta = read_memory_integer (pc + 2, 2);
+
+ /* Include the size of the jmp instruction (including the
+ 0x66 prefix). */
+ delta += 4;
+ }
+ else
+ {
+ delta = read_memory_integer (pc + 1, 4);
+
+ /* Include the size of the jmp instruction. */
+ delta += 5;
+ }
+ break;
+ case 0xeb:
+ /* Relative jump, disp8 (ignore data16). */
+ delta = read_memory_integer (pc + data16 + 1, 1);
+
+ delta += data16 + 2;
+ break;
+ }
+
+ return pc + delta;
+}
+
+/* Check whether PC points at a prologue for a function returning a
+ structure or union. If so, it updates CACHE and returns the
+ address of the first instruction after the code sequence that
+ removes the "hidden" argument from the stack or CURRENT_PC,
+ whichever is smaller. Otherwise, return PC. */
+
+static CORE_ADDR
+i386_analyze_struct_return (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct i386_frame_cache *cache)
+{
+ /* Functions that return a structure or union start with:
+
+ popl %eax 0x58
+ xchgl %eax, (%esp) 0x87 0x04 0x24
+ or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
+
+ (the System V compiler puts out the second `xchg' instruction,
+ 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. */
+ static unsigned char proto1[3] = { 0x87, 0x04, 0x24 };
+ static unsigned char proto2[4] = { 0x87, 0x44, 0x24, 0x00 };
+ unsigned char buf[4];
+ unsigned char op;
+
+ if (current_pc <= pc)
+ return pc;
+
+ op = read_memory_unsigned_integer (pc, 1);
+
+ if (op != 0x58) /* popl %eax */
+ return pc;
+
+ read_memory (pc + 1, buf, 4);
+ if (memcmp (buf, proto1, 3) != 0 && memcmp (buf, proto2, 4) != 0)
+ return pc;
+
+ if (current_pc == pc)
+ {
+ cache->sp_offset += 4;
+ return current_pc;
+ }
+
+ if (current_pc == pc + 1)
+ {
+ cache->pc_in_eax = 1;
+ return current_pc;
+ }
+
+ if (buf[1] == proto1[1])
+ return pc + 4;
+ else
+ return pc + 5;
+}
+
+static CORE_ADDR
+i386_skip_probe (CORE_ADDR pc)
+{
+ /* A function may start with
+
+ pushl constant
+ call _probe
+ addl $4, %esp
+
+ followed by
+
+ pushl %ebp
+
+ etc. */
+ unsigned char buf[8];
+ unsigned char op;
+
+ op = read_memory_unsigned_integer (pc, 1);
+
+ if (op == 0x68 || op == 0x6a)
+ {
+ int delta;
+
+ /* Skip past the `pushl' instruction; it has either a one-byte or a
+ four-byte operand, depending on the opcode. */
+ if (op == 0x68)
+ delta = 5;
+ else
+ delta = 2;
+
+ /* Read the following 8 bytes, which should be `call _probe' (6
+ bytes) followed by `addl $4,%esp' (2 bytes). */
+ read_memory (pc + delta, buf, sizeof (buf));
+ if (buf[0] == 0xe8 && buf[6] == 0xc4 && buf[7] == 0x4)
+ pc += delta + sizeof (buf);
+ }
+
+ return pc;
+}
+
+/* Check whether PC points at a code that sets up a new stack frame.
+ If so, it updates CACHE and returns the address of the first
+ instruction after the sequence that sets removes the "hidden"
+ argument from the stack or CURRENT_PC, whichever is smaller.
+ Otherwise, return PC. */
+
+static CORE_ADDR
+i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct i386_frame_cache *cache)
+{
+ unsigned char op;
+ int skip = 0;
+
+ if (current_pc <= pc)
+ return current_pc;
+
+ op = read_memory_unsigned_integer (pc, 1);
+
+ if (op == 0x55) /* pushl %ebp */
+ {
+ /* Take into account that we've executed the `pushl %ebp' that
+ starts this instruction sequence. */
+ cache->saved_regs[I386_EBP_REGNUM] = 0;
+ cache->sp_offset += 4;
+
+ /* If that's all, return now. */
+ if (current_pc <= pc + 1)
+ return current_pc;
+
+ op = read_memory_unsigned_integer (pc + 1, 1);
+
+ /* Check for some special instructions that might be migrated
+ by GCC into the prologue. We check for
+
+ xorl %ebx, %ebx
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+ xorl %eax, %eax
+
+ and the equivalent
+
+ subl %ebx, %ebx
+ subl %ecx, %ecx
+ subl %edx, %edx
+ subl %eax, %eax
+
+ Because of the symmetry, there are actually two ways to
+ encode these instructions; with opcode bytes 0x29 and 0x2b
+ for `subl' and opcode bytes 0x31 and 0x33 for `xorl'.
+
+ Make sure we only skip these instructions if we later see the
+ `movl %esp, %ebp' that actually sets up the frame. */
+ while (op == 0x29 || op == 0x2b || op == 0x31 || op == 0x33)
+ {
+ op = read_memory_unsigned_integer (pc + skip + 2, 1);
+ switch (op)
+ {
+ case 0xdb: /* %ebx */
+ case 0xc9: /* %ecx */
+ case 0xd2: /* %edx */
+ case 0xc0: /* %eax */
+ skip += 2;
+ break;
+ default:
+ return pc + 1;
+ }
+
+ op = read_memory_unsigned_integer (pc + skip + 1, 1);
+ }
+
+ /* Check for `movl %esp, %ebp' -- can be written in two ways. */
+ switch (op)
+ {
+ case 0x8b:
+ if (read_memory_unsigned_integer (pc + skip + 2, 1) != 0xec)
+ return pc + 1;
+ break;
+ case 0x89:
+ if (read_memory_unsigned_integer (pc + skip + 2, 1) != 0xe5)
+ return pc + 1;
+ break;
+ default:
+ return pc + 1;
+ }
+
+ /* OK, we actually have a frame. We just don't know how large
+ it is yet. Set its size to zero. We'll adjust it if
+ necessary. We also now commit to skipping the special
+ instructions mentioned before. */
+ cache->locals = 0;
+ pc += skip;
+
+ /* If that's all, return now. */
+ if (current_pc <= pc + 3)
+ return current_pc;
+
+ /* 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 = read_memory_unsigned_integer (pc + 3, 1);
+ if (op == 0x83)
+ {
+ /* `subl' with 8 bit immediate. */
+ if (read_memory_unsigned_integer (pc + 4, 1) != 0xec)
+ /* Some instruction starting with 0x83 other than `subl'. */
+ return pc + 3;
+
+ /* `subl' with signed byte immediate (though it wouldn't make
+ sense to be negative). */
+ cache->locals = read_memory_integer (pc + 5, 1);
+ return pc + 6;
+ }
+ else if (op == 0x81)
+ {
+ /* Maybe it is `subl' with a 32 bit immedediate. */
+ if (read_memory_unsigned_integer (pc + 4, 1) != 0xec)
+ /* Some instruction starting with 0x81 other than `subl'. */
+ return pc + 3;
+
+ /* It is `subl' with a 32 bit immediate. */
+ cache->locals = read_memory_integer (pc + 5, 4);
+ return pc + 9;
+ }
+ else
+ {
+ /* Some instruction other than `subl'. */
+ return pc + 3;
+ }
+ }
+ else if (op == 0xc8) /* enter $XXX */
+ {
+ cache->locals = read_memory_unsigned_integer (pc + 1, 2);
+ return pc + 4;
+ }
+
+ return pc;
+}
+
+/* Check whether PC points at code that saves registers on the stack.
+ If so, it updates CACHE and returns the address of the first
+ instruction after the register saves or CURRENT_PC, whichever is
+ smaller. Otherwise, return PC. */
+
+static CORE_ADDR
+i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct i386_frame_cache *cache)
+{
+ CORE_ADDR offset = 0;
+ unsigned char op;
+ int i;
+
+ if (cache->locals > 0)
+ offset -= cache->locals;
+ for (i = 0; i < 8 && pc < current_pc; i++)
+ {
+ op = read_memory_unsigned_integer (pc, 1);
+ if (op < 0x50 || op > 0x57)
+ break;
+
+ offset -= 4;
+ cache->saved_regs[op - 0x50] = offset;
+ cache->sp_offset += 4;
+ pc++;
+ }
+
+ return pc;
+}
+
+/* Do a full analysis of the prologue at PC and update CACHE
+ accordingly. Bail out early if CURRENT_PC is reached. Return the
+ address where the analysis stopped.
+
+ 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 System V compiler).
+
+ Local space is allocated just below the saved %ebp by either the
+ 'enter' instruction, or by "subl $<size>, %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. With the
+ System V 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. */
+
+static CORE_ADDR
+i386_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct i386_frame_cache *cache)
+{
+ pc = i386_follow_jump (pc);
+ pc = i386_analyze_struct_return (pc, current_pc, cache);
+ pc = i386_skip_probe (pc);
+ pc = i386_analyze_frame_setup (pc, current_pc, cache);
+ return i386_analyze_register_saves (pc, current_pc, cache);
+}
+
+/* Return PC of first real instruction. */
+
+static CORE_ADDR
+i386_skip_prologue (CORE_ADDR start_pc)
+{
+ static unsigned char pic_pat[6] =
+ {
+ 0xe8, 0, 0, 0, 0, /* call 0x0 */
+ 0x5b, /* popl %ebx */
+ };
+ struct i386_frame_cache cache;
+ CORE_ADDR pc;
+ unsigned char op;
+ int i;
+
+ cache.locals = -1;
+ pc = i386_analyze_prologue (start_pc, 0xffffffff, &cache);
+ if (cache.locals < 0)
+ return start_pc;
+
+ /* Found valid frame setup. */
+
+ /* 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. */
+
+ for (i = 0; i < 6; i++)
+ {
+ op = read_memory_unsigned_integer (pc + i, 1);
+ if (pic_pat[i] != op)
+ break;
+ }
+ if (i == 6)
+ {
+ int delta = 6;
+
+ op = read_memory_unsigned_integer (pc + delta, 1);
+
+ if (op == 0x89) /* movl %ebx, x(%ebp) */
+ {
+ op = read_memory_unsigned_integer (pc + delta + 1, 1);
+
+ if (op == 0x5d) /* One byte offset from %ebp. */
+ delta += 3;
+ else if (op == 0x9d) /* Four byte offset from %ebp. */
+ delta += 6;
+ else /* Unexpected instruction. */
+ delta = 0;
+
+ op = read_memory_unsigned_integer (pc + delta, 1);
+ }
+
+ /* addl y,%ebx */
+ if (delta > 0 && op == 0x81
+ && read_memory_unsigned_integer (pc + delta + 1, 1) == 0xc3);
+ {
+ pc += delta + 6;
+ }
+ }
+
+ return i386_follow_jump (pc);
+}
+
+/* This function is 64-bit safe. */
+
+static CORE_ADDR
+i386_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ char buf[8];
+
+ frame_unwind_register (next_frame, PC_REGNUM, buf);
+ return extract_typed_address (buf, builtin_type_void_func_ptr);
+}
+
+
+/* Normal frames. */
+
+static struct i386_frame_cache *
+i386_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct i386_frame_cache *cache;
+ char buf[4];
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = i386_alloc_frame_cache ();
+ *this_cache = cache;
+
+ /* In principle, for normal frames, %ebp holds the frame pointer,
+ which holds the base address for the current stack frame.
+ However, for functions that don't need it, the frame pointer is
+ optional. For these "frameless" functions the frame pointer is
+ actually the frame pointer of the calling frame. Signal
+ trampolines are just a special case of a "frameless" function.
+ They (usually) share their frame pointer with the frame that was
+ in progress when the signal occurred. */
+
+ frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 4);
+ if (cache->base == 0)
+ return cache;
+
+ /* For normal frames, %eip is stored at 4(%ebp). */
+ cache->saved_regs[I386_EIP_REGNUM] = 4;
+
+ cache->pc = frame_func_unwind (next_frame);
+ if (cache->pc != 0)
+ i386_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
+
+ if (cache->locals < 0)
+ {
+ /* We didn't find a valid frame, which means that CACHE->base
+ currently holds the frame pointer for our calling frame. If
+ we're at the start of a function, or somewhere half-way its
+ prologue, the function's frame probably hasn't been fully
+ setup yet. Try to reconstruct the base address for the stack
+ frame by looking at the stack pointer. For truly "frameless"
+ functions this might work too. */
+
+ frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
+ }
+
+ /* Now that we have the base address for the stack frame we can
+ calculate the value of %esp in the calling frame. */
+ cache->saved_sp = cache->base + 8;
+
+ /* Adjust all the saved registers such that they contain addresses
+ instead of offsets. */
+ for (i = 0; i < I386_NUM_SAVED_REGS; i++)
+ if (cache->saved_regs[i] != -1)
+ cache->saved_regs[i] += cache->base;
+
+ return cache;
+}
+
+static void
+i386_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ /* See the end of i386_push_dummy_call. */
+ (*this_id) = frame_id_build (cache->base + 8, cache->pc);
+}
+
+static void
+i386_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
+
+ gdb_assert (regnum >= 0);
+
+ /* The System V ABI says that:
+
+ "The flags register contains the system flags, such as the
+ direction flag and the carry flag. The direction flag must be
+ set to the forward (that is, zero) direction before entry and
+ upon exit from a function. Other user flags have no specified
+ role in the standard calling sequence and are not preserved."
+
+ To guarantee the "upon exit" part of that statement we fake a
+ saved flags register that has its direction flag cleared.
+
+ Note that GCC doesn't seem to rely on the fact that the direction
+ flag is cleared after a function return; it always explicitly
+ clears the flag before operations where it matters.
+
+ FIXME: kettenis/20030316: I'm not quite sure whether this is the
+ right thing to do. The way we fake the flags register here makes
+ it impossible to change it. */
+
+ if (regnum == I386_EFLAGS_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ ULONGEST val;
+
+ /* Clear the direction flag. */
+ val = frame_unwind_register_unsigned (next_frame,
+ I386_EFLAGS_REGNUM);
+ val &= ~(1 << 10);
+ store_unsigned_integer (valuep, 4, val);
+ }
+
+ return;
+ }
+
+ if (regnum == I386_EIP_REGNUM && cache->pc_in_eax)
+ {
+ frame_register_unwind (next_frame, I386_EAX_REGNUM,
+ optimizedp, lvalp, addrp, realnump, valuep);
+ return;
+ }
+
+ if (regnum == I386_ESP_REGNUM && cache->saved_sp)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Store the value. */
+ store_unsigned_integer (valuep, 4, cache->saved_sp);
+ }
+ return;
+ }
+
+ if (regnum < I386_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = cache->saved_regs[regnum];
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Read the value in from memory. */
+ read_memory (*addrp, valuep,
+ register_size (current_gdbarch, regnum));
+ }
+ return;
+ }
+
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind i386_frame_unwind =
+{
+ NORMAL_FRAME,
+ i386_frame_this_id,
+ i386_frame_prev_register
+};
+
+static const struct frame_unwind *
+i386_frame_sniffer (struct frame_info *next_frame)
+{
+ return &i386_frame_unwind;
+}
+
+
+/* Signal trampolines. */
+
+static struct i386_frame_cache *
+i386_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct i386_frame_cache *cache;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ CORE_ADDR addr;
+ char buf[4];
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = i386_alloc_frame_cache ();
+
+ frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 4) - 4;
+
+ addr = tdep->sigcontext_addr (next_frame);
+ if (tdep->sc_reg_offset)
+ {
+ int i;
+
+ gdb_assert (tdep->sc_num_regs <= I386_NUM_SAVED_REGS);
+
+ for (i = 0; i < tdep->sc_num_regs; i++)
+ if (tdep->sc_reg_offset[i] != -1)
+ cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+ }
+ else
+ {
+ cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
+ cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
+ }
+
+ *this_cache = cache;
+ return cache;
+}
+
+static void
+i386_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct i386_frame_cache *cache =
+ i386_sigtramp_frame_cache (next_frame, this_cache);
+
+ /* See the end of i386_push_dummy_call. */
+ (*this_id) = frame_id_build (cache->base + 8, frame_pc_unwind (next_frame));
+}
+
+static void
+i386_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ /* Make sure we've initialized the cache. */
+ i386_sigtramp_frame_cache (next_frame, this_cache);
+
+ i386_frame_prev_register (next_frame, this_cache, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind i386_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ i386_sigtramp_frame_this_id,
+ i386_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+i386_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ /* We shouldn't even bother to try if the OSABI didn't register
+ a sigcontext_addr handler. */
+ if (!gdbarch_tdep (current_gdbarch)->sigcontext_addr)
+ return NULL;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (PC_IN_SIGTRAMP (pc, name))
+ return &i386_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+
+static CORE_ADDR
+i386_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_base i386_frame_base =
+{
+ &i386_frame_unwind,
+ i386_frame_base_address,
+ i386_frame_base_address,
+ i386_frame_base_address
+};
+
+static struct frame_id
+i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ char buf[4];
+ CORE_ADDR fp;
+
+ frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
+ fp = extract_unsigned_integer (buf, 4);
+
+ /* See the end of i386_push_dummy_call. */
+ return frame_id_build (fp + 8, frame_pc_unwind (next_frame));
+}
+
+
+/* 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 address that we will land at.
+ This address is copied into PC. This routine returns non-zero on
+ success.
+
+ This function is 64-bit safe. */
+
+static int
+i386_get_longjmp_target (CORE_ADDR *pc)
+{
+ char buf[8];
+ CORE_ADDR sp, jb_addr;
+ int jb_pc_offset = gdbarch_tdep (current_gdbarch)->jb_pc_offset;
+ int len = TYPE_LENGTH (builtin_type_void_func_ptr);
+
+ /* If JB_PC_OFFSET is -1, we have no way to find out where the
+ longjmp will land. */
+ if (jb_pc_offset == -1)
+ return 0;
+
+ /* Don't use I386_ESP_REGNUM here, since this function is also used
+ for AMD64. */
+ regcache_cooked_read (current_regcache, SP_REGNUM, buf);
+ sp = extract_typed_address (buf, builtin_type_void_data_ptr);
+ if (target_read_memory (sp + len, buf, len))
+ return 0;
+
+ jb_addr = extract_typed_address (buf, builtin_type_void_data_ptr);
+ if (target_read_memory (jb_addr + jb_pc_offset, buf, len))
+ return 0;
+
+ *pc = extract_typed_address (buf, builtin_type_void_func_ptr);
+ return 1;
+}
+
+
+static CORE_ADDR
+i386_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp, int struct_return,
+ CORE_ADDR struct_addr)
+{
+ char buf[4];
+ int i;
+
+ /* Push arguments in reverse order. */
+ for (i = nargs - 1; i >= 0; i--)
+ {
+ int len = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (args[i]));
+
+ /* The System V ABI says that:
+
+ "An argument's size is increased, if necessary, to make it a
+ multiple of [32-bit] words. This may require tail padding,
+ depending on the size of the argument."
+
+ This makes sure the stack says word-aligned. */
+ sp -= (len + 3) & ~3;
+ write_memory (sp, VALUE_CONTENTS_ALL (args[i]), len);
+ }
+
+ /* Push value address. */
+ if (struct_return)
+ {
+ sp -= 4;
+ store_unsigned_integer (buf, 4, struct_addr);
+ write_memory (sp, buf, 4);
+ }
+
+ /* Store return address. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, bp_addr);
+ write_memory (sp, buf, 4);
+
+ /* Finally, update the stack pointer... */
+ store_unsigned_integer (buf, 4, sp);
+ regcache_cooked_write (regcache, I386_ESP_REGNUM, buf);
+
+ /* ...and fake a frame pointer. */
+ regcache_cooked_write (regcache, I386_EBP_REGNUM, buf);
+
+ /* MarkK wrote: This "+ 8" is all over the place:
+ (i386_frame_this_id, i386_sigtramp_frame_this_id,
+ i386_unwind_dummy_id). It's there, since all frame unwinders for
+ a given target have to agree (within a certain margin) on the
+ defenition of the stack address of a frame. Otherwise
+ frame_id_inner() won't work correctly. Since DWARF2/GCC uses the
+ stack address *before* the function call as a frame's CFA. On
+ the i386, when %ebp is used as a frame pointer, the offset
+ between the contents %ebp and the CFA as defined by GCC. */
+ return sp + 8;
+}
+
+/* These registers are used for returning integers (and on some
+ targets also for returning `struct' and `union' values when their
+ size and alignment match an integer type). */
+#define LOW_RETURN_REGNUM I386_EAX_REGNUM /* %eax */
+#define HIGH_RETURN_REGNUM I386_EDX_REGNUM /* %edx */
+
+/* Read, for architecture GDBARCH, a function return value of TYPE
+ from REGCACHE, and copy that into VALBUF. */
+
+static void
+i386_extract_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, void *valbuf)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int len = TYPE_LENGTH (type);
+ char buf[I386_MAX_REGISTER_SIZE];
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ if (tdep->st0_regnum < 0)
+ {
+ warning ("Cannot find floating-point return value.");
+ memset (valbuf, 0, len);
+ return;
+ }
+
+ /* Floating-point return values can be found in %st(0). Convert
+ its contents to the desired type. This is probably not
+ exactly how it would happen on the target itself, but it is
+ the best we can do. */
+ regcache_raw_read (regcache, I386_ST0_REGNUM, buf);
+ convert_typed_floating (buf, builtin_type_i387_ext, valbuf, type);
+ }
+ else
+ {
+ int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
+ int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
+
+ if (len <= low_size)
+ {
+ regcache_raw_read (regcache, LOW_RETURN_REGNUM, buf);
+ memcpy (valbuf, buf, len);
+ }
+ else if (len <= (low_size + high_size))
+ {
+ regcache_raw_read (regcache, LOW_RETURN_REGNUM, buf);
+ memcpy (valbuf, buf, low_size);
+ regcache_raw_read (regcache, HIGH_RETURN_REGNUM, buf);
+ memcpy ((char *) valbuf + low_size, buf, len - low_size);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ "Cannot extract return value of %d bytes long.", len);
+ }
+}
+
+/* Write, for architecture GDBARCH, a function return value of TYPE
+ from VALBUF into REGCACHE. */
+
+static void
+i386_store_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, const void *valbuf)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int len = TYPE_LENGTH (type);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for the architecture. */
+#define I387_ST0_REGNUM I386_ST0_REGNUM
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ ULONGEST fstat;
+ char buf[I386_MAX_REGISTER_SIZE];
+
+ if (tdep->st0_regnum < 0)
+ {
+ warning ("Cannot set floating-point return value.");
+ return;
+ }
+
+ /* Returning floating-point values is a bit tricky. Apart from
+ storing the return value in %st(0), we have to simulate the
+ state of the FPU at function return point. */
+
+ /* Convert the value found in VALBUF to the extended
+ floating-point format used by the FPU. This is probably
+ not exactly how it would happen on the target itself, but
+ it is the best we can do. */
+ convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext);
+ regcache_raw_write (regcache, I386_ST0_REGNUM, buf);
+
+ /* Set the top of the floating-point register stack to 7. The
+ actual value doesn't really matter, but 7 is what a normal
+ function return would end up with if the program started out
+ with a freshly initialized FPU. */
+ regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
+ fstat |= (7 << 11);
+ regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
+
+ /* Mark %st(1) through %st(7) as empty. Since we set the top of
+ the floating-point register stack to 7, the appropriate value
+ for the tag word is 0x3fff. */
+ regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
+ }
+ else
+ {
+ int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
+ int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
+
+ if (len <= low_size)
+ regcache_raw_write_part (regcache, LOW_RETURN_REGNUM, 0, len, valbuf);
+ else if (len <= (low_size + high_size))
+ {
+ regcache_raw_write (regcache, LOW_RETURN_REGNUM, valbuf);
+ regcache_raw_write_part (regcache, HIGH_RETURN_REGNUM, 0,
+ len - low_size, (char *) valbuf + low_size);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ "Cannot store return value of %d bytes long.", len);
+ }
+
+#undef I387_ST0_REGNUM
+}
+
+
+/* This is the variable that is set with "set struct-convention", and
+ its legitimate values. */
+static const char default_struct_convention[] = "default";
+static const char pcc_struct_convention[] = "pcc";
+static const char reg_struct_convention[] = "reg";
+static const char *valid_conventions[] =
+{
+ default_struct_convention,
+ pcc_struct_convention,
+ reg_struct_convention,
+ NULL
+};
+static const char *struct_convention = default_struct_convention;
+
+/* Return non-zero if TYPE, which is assumed to be a structure or
+ union type, should be returned in registers for architecture
+ GDBARCH. */
+
+static int
+i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum type_code code = TYPE_CODE (type);
+ int len = TYPE_LENGTH (type);
+
+ gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION);
+
+ if (struct_convention == pcc_struct_convention
+ || (struct_convention == default_struct_convention
+ && tdep->struct_return == pcc_struct_return))
+ return 0;
+
+ return (len == 1 || len == 2 || len == 4 || len == 8);
+}
+
+/* Determine, for architecture GDBARCH, how a return value of TYPE
+ should be returned. If it is supposed to be returned in registers,
+ and READBUF is non-zero, read the appropriate value from REGCACHE,
+ and copy it into READBUF. If WRITEBUF is non-zero, write the value
+ from WRITEBUF into REGCACHE. */
+
+static enum return_value_convention
+i386_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
+ && !i386_reg_struct_return_p (gdbarch, type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ /* This special case is for structures consisting of a single
+ `float' or `double' member. These structures are returned in
+ %st(0). For these structures, we call ourselves recursively,
+ changing TYPE into the type of the first member of the structure.
+ Since that should work for all structures that have only one
+ member, we don't bother to check the member's type here. */
+ if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
+ {
+ type = check_typedef (TYPE_FIELD_TYPE (type, 0));
+ return i386_return_value (gdbarch, type, regcache, readbuf, writebuf);
+ }
+
+ if (readbuf)
+ i386_extract_return_value (gdbarch, type, regcache, readbuf);
+ if (writebuf)
+ i386_store_return_value (gdbarch, type, regcache, writebuf);
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. Perhaps %esi and %edi should go here, but
+ potentially they could be used for things other than address. */
+
+static struct type *
+i386_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == I386_EIP_REGNUM
+ || regnum == I386_EBP_REGNUM || regnum == I386_ESP_REGNUM)
+ return lookup_pointer_type (builtin_type_void);
+
+ if (i386_fp_regnum_p (regnum))
+ return builtin_type_i387_ext;
+
+ if (i386_sse_regnum_p (gdbarch, regnum))
+ return builtin_type_vec128i;
+
+ if (i386_mmx_regnum_p (gdbarch, regnum))
+ return builtin_type_vec64i;
+
+ return builtin_type_int;
+}
+
+/* Map a cooked register onto a raw register or memory. For the i386,
+ the MMX registers need to be mapped onto floating point registers. */
+
+static int
+i386_mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ int mmxreg, fpreg;
+ ULONGEST fstat;
+ int tos;
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ mmxreg = regnum - tdep->mm0_regnum;
+ regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
+ tos = (fstat >> 11) & 0x7;
+ fpreg = (mmxreg + tos) % 8;
+
+ return (I387_ST0_REGNUM + fpreg);
+
+#undef I387_ST0_REGNUM
+}
+
+static void
+i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, void *buf)
+{
+ if (i386_mmx_regnum_p (gdbarch, regnum))
+ {
+ char mmx_buf[MAX_REGISTER_SIZE];
+ int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
+
+ /* Extract (always little endian). */
+ regcache_raw_read (regcache, fpnum, mmx_buf);
+ memcpy (buf, mmx_buf, register_size (gdbarch, regnum));
+ }
+ else
+ regcache_raw_read (regcache, regnum, buf);
+}
+
+static void
+i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, const void *buf)
+{
+ if (i386_mmx_regnum_p (gdbarch, regnum))
+ {
+ char mmx_buf[MAX_REGISTER_SIZE];
+ int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
+
+ /* Read ... */
+ regcache_raw_read (regcache, fpnum, mmx_buf);
+ /* ... Modify ... (always little endian). */
+ memcpy (mmx_buf, buf, register_size (gdbarch, regnum));
+ /* ... Write. */
+ regcache_raw_write (regcache, fpnum, mmx_buf);
+ }
+ else
+ regcache_raw_write (regcache, regnum, buf);
+}
+
+
+/* Return the register number of the register allocated by GCC after
+ REGNUM, or -1 if there is no such register. */
+
+static int
+i386_next_regnum (int regnum)
+{
+ /* GCC allocates the registers in the order:
+
+ %eax, %edx, %ecx, %ebx, %esi, %edi, %ebp, %esp, ...
+
+ Since storing a variable in %esp doesn't make any sense we return
+ -1 for %ebp and for %esp itself. */
+ static int next_regnum[] =
+ {
+ I386_EDX_REGNUM, /* Slot for %eax. */
+ I386_EBX_REGNUM, /* Slot for %ecx. */
+ I386_ECX_REGNUM, /* Slot for %edx. */
+ I386_ESI_REGNUM, /* Slot for %ebx. */
+ -1, -1, /* Slots for %esp and %ebp. */
+ I386_EDI_REGNUM, /* Slot for %esi. */
+ I386_EBP_REGNUM /* Slot for %edi. */
+ };
+
+ if (regnum >= 0 && regnum < sizeof (next_regnum) / sizeof (next_regnum[0]))
+ return next_regnum[regnum];
+
+ return -1;
+}
+
+/* Return nonzero if a value of type TYPE stored in register REGNUM
+ needs any special handling. */
+
+static int
+i386_convert_register_p (int regnum, struct type *type)
+{
+ int len = TYPE_LENGTH (type);
+
+ /* Values may be spread across multiple registers. Most debugging
+ formats aren't expressive enough to specify the locations, so
+ some heuristics is involved. Right now we only handle types that
+ have a length that is a multiple of the word size, since GCC
+ doesn't seem to put any other types into registers. */
+ if (len > 4 && len % 4 == 0)
+ {
+ int last_regnum = regnum;
+
+ while (len > 4)
+ {
+ last_regnum = i386_next_regnum (last_regnum);
+ len -= 4;
+ }
+
+ if (last_regnum != -1)
+ return 1;
+ }
+
+ return i386_fp_regnum_p (regnum);
+}
+
+/* Read a value of type TYPE from register REGNUM in frame FRAME, and
+ return its contents in TO. */
+
+static void
+i386_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, void *to)
+{
+ int len = TYPE_LENGTH (type);
+ char *buf = to;
+
+ /* FIXME: kettenis/20030609: What should we do if REGNUM isn't
+ available in FRAME (i.e. if it wasn't saved)? */
+
+ if (i386_fp_regnum_p (regnum))
+ {
+ i387_register_to_value (frame, regnum, type, to);
+ return;
+ }
+
+ /* Read a value spread accross multiple registers. */
+
+ gdb_assert (len > 4 && len % 4 == 0);
+
+ while (len > 0)
+ {
+ gdb_assert (regnum != -1);
+ gdb_assert (register_size (current_gdbarch, regnum) == 4);
+
+ get_frame_register (frame, regnum, buf);
+ regnum = i386_next_regnum (regnum);
+ len -= 4;
+ buf += 4;
+ }
+}
+
+/* Write the contents FROM of a value of type TYPE into register
+ REGNUM in frame FRAME. */
+
+static void
+i386_value_to_register (struct frame_info *frame, int regnum,
+ struct type *type, const void *from)
+{
+ int len = TYPE_LENGTH (type);
+ const char *buf = from;
+
+ if (i386_fp_regnum_p (regnum))
+ {
+ i387_value_to_register (frame, regnum, type, from);
+ return;
+ }
+
+ /* Write a value spread accross multiple registers. */
+
+ gdb_assert (len > 4 && len % 4 == 0);
+
+ while (len > 0)
+ {
+ gdb_assert (regnum != -1);
+ gdb_assert (register_size (current_gdbarch, regnum) == 4);
+
+ put_frame_register (frame, regnum, buf);
+ regnum = i386_next_regnum (regnum);
+ len -= 4;
+ buf += 4;
+ }
+}
+
+/* Supply register REGNUM from the general-purpose register set REGSET
+ to register cache REGCACHE. If REGNUM is -1, do this for all
+ registers in REGSET. */
+
+void
+i386_supply_gregset (const struct regset *regset, struct regcache *regcache,
+ int regnum, const void *gregs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = regset->descr;
+ const char *regs = gregs;
+ int i;
+
+ gdb_assert (len == tdep->sizeof_gregset);
+
+ for (i = 0; i < tdep->gregset_num_regs; i++)
+ {
+ if ((regnum == i || regnum == -1)
+ && tdep->gregset_reg_offset[i] != -1)
+ regcache_raw_supply (regcache, i, regs + tdep->gregset_reg_offset[i]);
+ }
+}
+
+/* Supply register REGNUM from the floating-point register set REGSET
+ to register cache REGCACHE. If REGNUM is -1, do this for all
+ registers in REGSET. */
+
+static void
+i386_supply_fpregset (const struct regset *regset, struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = regset->descr;
+
+ if (len == I387_SIZEOF_FXSAVE)
+ {
+ i387_supply_fxsave (regcache, regnum, fpregs);
+ return;
+ }
+
+ gdb_assert (len == tdep->sizeof_fpregset);
+ i387_supply_fsave (regcache, regnum, fpregs);
+}
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+
+const struct regset *
+i386_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (strcmp (sect_name, ".reg") == 0 && sect_size == tdep->sizeof_gregset)
+ {
+ if (tdep->gregset == NULL)
+ {
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = tdep;
+ tdep->gregset->supply_regset = i386_supply_gregset;
+ }
+ return tdep->gregset;
+ }
+
+ if ((strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
+ || (strcmp (sect_name, ".reg-xfp") == 0
+ && sect_size == I387_SIZEOF_FXSAVE))
+ {
+ if (tdep->fpregset == NULL)
+ {
+ tdep->fpregset = XMALLOC (struct regset);
+ tdep->fpregset->descr = tdep;
+ tdep->fpregset->supply_regset = i386_supply_fpregset;
+ }
+ return tdep->fpregset;
+ }
+
+ return NULL;
+}
+
+
+#ifdef STATIC_TRANSFORM_NAME
+/* SunPRO encodes the static variables. This is not related to C++
+ mangling, it is done for C too. */
+
+char *
+sunpro_static_transform_name (char *name)
+{
+ char *p;
+ if (IS_STATIC_TRANSFORM_NAME (name))
+ {
+ /* For file-local statics there will be a period, a bunch of
+ junk (the contents of which match a string given in the
+ N_OPT), a period and the name. For function-local statics
+ there will be a bunch of junk (which seems to change the
+ second character from 'A' to 'B'), a period, the name of the
+ function, and the name. So just skip everything before the
+ last period. */
+ p = strrchr (name, '.');
+ if (p != NULL)
+ name = p + 1;
+ }
+ return name;
+}
+#endif /* STATIC_TRANSFORM_NAME */
+
+
+/* Stuff for WIN32 PE style DLL's but is pretty generic really. */
+
+CORE_ADDR
+i386_pe_skip_trampoline_code (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_LINKAGE_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. */
+}
+
+
+/* Return non-zero if PC and NAME show that we are in a signal
+ trampoline. */
+
+static int
+i386_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ return (name && strcmp ("_sigtramp", name) == 0);
+}
+
+
+/* We have two flavours of disassembly. The machinery on this page
+ deals with switching between those. */
+
+static int
+i386_print_insn (bfd_vma pc, struct disassemble_info *info)
+{
+ gdb_assert (disassembly_flavor == att_flavor
+ || disassembly_flavor == intel_flavor);
+
+ /* FIXME: kettenis/20020915: Until disassembler_options is properly
+ constified, cast to prevent a compiler warning. */
+ info->disassembler_options = (char *) disassembly_flavor;
+ info->mach = gdbarch_bfd_arch_info (current_gdbarch)->mach;
+
+ return print_insn_i386 (pc, info);
+}
+
+
+/* There are a few i386 architecture variants that differ only
+ slightly from the generic i386 target. For now, we don't give them
+ their own source file, but include them here. As a consequence,
+ they'll always be included. */
+
+/* System V Release 4 (SVR4). */
+
+static int
+i386_svr4_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ /* UnixWare uses _sigacthandler. The origin of the other symbols is
+ currently unknown. */
+ return (name && (strcmp ("_sigreturn", name) == 0
+ || strcmp ("_sigacthandler", name) == 0
+ || strcmp ("sigvechandler", name) == 0));
+}
+
+/* Assuming NEXT_FRAME is for a frame following a SVR4 sigtramp
+ routine, return the address of the associated sigcontext (ucontext)
+ structure. */
+
+static CORE_ADDR
+i386_svr4_sigcontext_addr (struct frame_info *next_frame)
+{
+ char buf[4];
+ CORE_ADDR sp;
+
+ frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+ sp = extract_unsigned_integer (buf, 4);
+
+ return read_memory_unsigned_integer (sp + 8, 4);
+}
+
+
+/* DJGPP. */
+
+static int
+i386_go32_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ /* DJGPP doesn't have any special frames for signal handlers. */
+ return 0;
+}
+
+
+/* Generic ELF. */
+
+void
+i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ /* We typically use stabs-in-ELF with the DWARF register numbering. */
+ set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dwarf_reg_to_regnum);
+}
+
+/* System V Release 4 (SVR4). */
+
+void
+i386_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* System V Release 4 uses ELF. */
+ i386_elf_init_abi (info, gdbarch);
+
+ /* System V Release 4 has shared libraries. */
+ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386_svr4_pc_in_sigtramp);
+ tdep->sigcontext_addr = i386_svr4_sigcontext_addr;
+ tdep->sc_pc_offset = 36 + 14 * 4;
+ tdep->sc_sp_offset = 36 + 17 * 4;
+
+ tdep->jb_pc_offset = 20;
+}
+
+/* DJGPP. */
+
+static void
+i386_go32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386_go32_pc_in_sigtramp);
+
+ tdep->jb_pc_offset = 36;
+}
+
+/* NetWare. */
+
+static void
+i386_nw_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->jb_pc_offset = 24;
+}
+
+
+/* i386 register groups. In addition to the normal groups, add "mmx"
+ and "sse". */
+
+static struct reggroup *i386_sse_reggroup;
+static struct reggroup *i386_mmx_reggroup;
+
+static void
+i386_init_reggroups (void)
+{
+ i386_sse_reggroup = reggroup_new ("sse", USER_REGGROUP);
+ i386_mmx_reggroup = reggroup_new ("mmx", USER_REGGROUP);
+}
+
+static void
+i386_add_reggroups (struct gdbarch *gdbarch)
+{
+ reggroup_add (gdbarch, i386_sse_reggroup);
+ reggroup_add (gdbarch, i386_mmx_reggroup);
+ reggroup_add (gdbarch, general_reggroup);
+ reggroup_add (gdbarch, float_reggroup);
+ reggroup_add (gdbarch, all_reggroup);
+ reggroup_add (gdbarch, save_reggroup);
+ reggroup_add (gdbarch, restore_reggroup);
+ reggroup_add (gdbarch, vector_reggroup);
+ reggroup_add (gdbarch, system_reggroup);
+}
+
+int
+i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ int sse_regnum_p = (i386_sse_regnum_p (gdbarch, regnum)
+ || i386_mxcsr_regnum_p (gdbarch, regnum));
+ int fp_regnum_p = (i386_fp_regnum_p (regnum)
+ || i386_fpc_regnum_p (regnum));
+ int mmx_regnum_p = (i386_mmx_regnum_p (gdbarch, regnum));
+
+ if (group == i386_mmx_reggroup)
+ return mmx_regnum_p;
+ if (group == i386_sse_reggroup)
+ return sse_regnum_p;
+ if (group == vector_reggroup)
+ return (mmx_regnum_p || sse_regnum_p);
+ if (group == float_reggroup)
+ return fp_regnum_p;
+ if (group == general_reggroup)
+ return (!fp_regnum_p && !mmx_regnum_p && !sse_regnum_p);
+
+ return default_register_reggroup_p (gdbarch, regnum, group);
+}
+
+
+/* Get the ARGIth function argument for the current function. */
+
+static CORE_ADDR
+i386_fetch_pointer_argument (struct frame_info *frame, int argi,
+ struct type *type)
+{
+ CORE_ADDR sp = get_frame_register_unsigned (frame, I386_ESP_REGNUM);
+ return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
+}
+
+
+static struct gdbarch *
+i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ /* Allocate space for the new architecture. */
+ tdep = XMALLOC (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* General-purpose registers. */
+ tdep->gregset = NULL;
+ tdep->gregset_reg_offset = NULL;
+ tdep->gregset_num_regs = I386_NUM_GREGS;
+ tdep->sizeof_gregset = 0;
+
+ /* Floating-point registers. */
+ tdep->fpregset = NULL;
+ tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+
+ /* The default settings include the FPU registers, the MMX registers
+ and the SSE registers. This can be overidden for a specific ABI
+ by adjusting the members `st0_regnum', `mm0_regnum' and
+ `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
+ will show up in the output of "info all-registers". Ideally we
+ should try to autodetect whether they are available, such that we
+ can prevent "info all-registers" from displaying registers that
+ aren't available.
+
+ NOTE: kevinb/2003-07-13: ... if it's a choice between printing
+ [the SSE registers] always (even when they don't exist) or never
+ showing them to the user (even when they do exist), I prefer the
+ former over the latter. */
+
+ tdep->st0_regnum = I386_ST0_REGNUM;
+
+ /* The MMX registers are implemented as pseudo-registers. Put off
+ caclulating the register number for %mm0 until we know the number
+ of raw registers. */
+ tdep->mm0_regnum = 0;
+
+ /* I386_NUM_XREGS includes %mxcsr, so substract one. */
+ tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+
+ tdep->jb_pc_offset = -1;
+ tdep->struct_return = pcc_struct_return;
+ tdep->sigtramp_start = 0;
+ tdep->sigtramp_end = 0;
+ tdep->sigcontext_addr = NULL;
+ tdep->sc_reg_offset = NULL;
+ tdep->sc_pc_offset = -1;
+ tdep->sc_sp_offset = -1;
+
+ /* The format used for `long double' on almost all i386 targets is
+ the i387 extended floating-point format. In fact, of all targets
+ in the GCC 2.95 tree, only OSF/1 does it different, and insists
+ on having a `long double' that's not `long' at all. */
+ set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
+
+ /* Although the i387 extended floating-point has only 80 significant
+ bits, a `long double' actually takes up 96, probably to enforce
+ alignment. */
+ set_gdbarch_long_double_bit (gdbarch, 96);
+
+ /* The default ABI includes general-purpose registers,
+ floating-point registers, and the SSE registers. */
+ set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
+ set_gdbarch_register_name (gdbarch, i386_register_name);
+ set_gdbarch_register_type (gdbarch, i386_register_type);
+
+ /* Register numbers of various important registers. */
+ set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
+ set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
+ set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
+ set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+
+ /* Use the "default" register numbering scheme for stabs and COFF. */
+ set_gdbarch_stab_reg_to_regnum (gdbarch, i386_stab_reg_to_regnum);
+ set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_stab_reg_to_regnum);
+
+ /* Use the DWARF register numbering scheme for DWARF and DWARF 2. */
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_dwarf_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_dwarf_reg_to_regnum);
+
+ /* We don't define ECOFF_REG_TO_REGNUM, since ECOFF doesn't seem to
+ be in use on any of the supported i386 targets. */
+
+ set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
+
+ set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+
+ /* Call dummy code. */
+ set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+
+ set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, i386_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
+
+ set_gdbarch_return_value (gdbarch, i386_return_value);
+
+ set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+
+ /* Stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
+ set_gdbarch_decr_pc_after_break (gdbarch, 1);
+
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386_pc_in_sigtramp);
+
+ /* Wire in the MMX registers. */
+ set_gdbarch_num_pseudo_regs (gdbarch, i386_num_mmx_regs);
+ set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
+
+ set_gdbarch_print_insn (gdbarch, i386_print_insn);
+
+ set_gdbarch_unwind_dummy_id (gdbarch, i386_unwind_dummy_id);
+
+ set_gdbarch_unwind_pc (gdbarch, i386_unwind_pc);
+
+ /* Add the i386 register groups. */
+ i386_add_reggroups (gdbarch);
+ set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p);
+
+ /* Helper for function argument information. */
+ set_gdbarch_fetch_pointer_argument (gdbarch, i386_fetch_pointer_argument);
+
+ /* Hook in the DWARF CFI frame unwinder. */
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+
+ frame_base_set_default (gdbarch, &i386_frame_base);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ frame_unwind_append_sniffer (gdbarch, i386_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, i386_frame_sniffer);
+
+ /* If we have a register mapping, enable the generic core file
+ support, unless it has already been enabled. */
+ if (tdep->gregset_reg_offset
+ && !gdbarch_regset_from_core_section_p (gdbarch))
+ set_gdbarch_regset_from_core_section (gdbarch,
+ i386_regset_from_core_section);
+
+ /* Unless support for MMX has been disabled, make %mm0 the first
+ pseudo-register. */
+ if (tdep->mm0_regnum == 0)
+ tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
+
+ return gdbarch;
+}
+
+static enum gdb_osabi
+i386_coff_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "coff-go32-exe") == 0
+ || strcmp (bfd_get_target (abfd), "coff-go32") == 0)
+ return GDB_OSABI_GO32;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+static enum gdb_osabi
+i386_nlm_osabi_sniffer (bfd *abfd)
+{
+ return GDB_OSABI_NETWARE;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386_tdep (void);
+
+void
+_initialize_i386_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init);
+
+ /* Add the variable that controls the disassembly flavor. */
+ {
+ struct cmd_list_element *new_cmd;
+
+ new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class,
+ valid_flavors,
+ &disassembly_flavor,
+ "\
+Set the disassembly flavor, the valid values are \"att\" and \"intel\", \
+and the default value is \"att\".",
+ &setlist);
+ add_show_from_set (new_cmd, &showlist);
+ }
+
+ /* Add the variable that controls the convention for returning
+ structs. */
+ {
+ struct cmd_list_element *new_cmd;
+
+ new_cmd = add_set_enum_cmd ("struct-convention", no_class,
+ valid_conventions,
+ &struct_convention, "\
+Set the convention for returning small structs, valid values \
+are \"default\", \"pcc\" and \"reg\", and the default value is \"default\".",
+ &setlist);
+ add_show_from_set (new_cmd, &showlist);
+ }
+
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
+ i386_coff_osabi_sniffer);
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_nlm_flavour,
+ i386_nlm_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_SVR4,
+ i386_svr4_init_abi);
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_GO32,
+ i386_go32_init_abi);
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETWARE,
+ i386_nw_init_abi);
+
+ /* Initialize the i386 specific register groups. */
+ i386_init_reggroups ();
+}
diff --git a/contrib/gdb/gdb/i386-tdep.h b/contrib/gdb/gdb/i386-tdep.h
new file mode 100644
index 0000000..9cb8765
--- /dev/null
+++ b/contrib/gdb/gdb/i386-tdep.h
@@ -0,0 +1,233 @@
+/* Target-dependent code for the i386.
+
+ Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 I386_TDEP_H
+#define I386_TDEP_H
+
+struct frame_info;
+struct gdbarch;
+struct reggroup;
+struct regset;
+struct regcache;
+
+/* GDB's i386 target supports both the 32-bit Intel Architecture
+ (IA-32) and the 64-bit AMD x86-64 architecture. Internally it uses
+ a similar register layout for both.
+
+ - General purpose registers
+ - FPU data registers
+ - FPU control registers
+ - SSE data registers
+ - SSE control register
+
+ The general purpose registers for the x86-64 architecture are quite
+ different from IA-32. Therefore, the FP0_REGNUM target macro
+ determines the register number at which the FPU data registers
+ start. The number of FPU data and control registers is the same
+ for both architectures. The number of SSE registers however,
+ differs and is determined by the num_xmm_regs member of `struct
+ gdbarch_tdep'. */
+
+/* Convention for returning structures. */
+
+enum struct_return
+{
+ pcc_struct_return, /* Return "short" structures in memory. */
+ reg_struct_return /* Return "short" structures in registers. */
+};
+
+/* i386 architecture specific information. */
+struct gdbarch_tdep
+{
+ /* General-purpose registers. */
+ struct regset *gregset;
+ int *gregset_reg_offset;
+ int gregset_num_regs;
+ size_t sizeof_gregset;
+
+ /* Floating-point registers. */
+ struct regset *fpregset;
+ size_t sizeof_fpregset;
+
+ /* Register number for %st(0). The register numbers for the other
+ registers follow from this one. Set this to -1 to indicate the
+ absence of an FPU. */
+ int st0_regnum;
+
+ /* Register number for %mm0. Set this to -1 to indicate the absence
+ of MMX support. */
+ int mm0_regnum;
+
+ /* Number of SSE registers. */
+ int num_xmm_regs;
+
+ /* Offset of saved PC in jmp_buf. */
+ int jb_pc_offset;
+
+ /* Convention for returning structures. */
+ enum struct_return struct_return;
+
+ /* Address range where sigtramp lives. */
+ CORE_ADDR sigtramp_start;
+ CORE_ADDR sigtramp_end;
+
+ /* Get address of sigcontext for sigtramp. */
+ CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+ /* Offset of registers in `struct sigcontext'. */
+ int *sc_reg_offset;
+ int sc_num_regs;
+
+ /* Offset of saved PC and SP in `struct sigcontext'. Usage of these
+ is deprecated, please use `sc_reg_offset' instead. */
+ int sc_pc_offset;
+ int sc_sp_offset;
+};
+
+/* Floating-point registers. */
+
+/* All FPU control regusters (except for FIOFF and FOOFF) are 16-bit
+ (at most) in the FPU, but are zero-extended to 32 bits in GDB's
+ register cache. */
+
+/* "Generic" floating point control register. */
+#define FPC_REGNUM (FP0_REGNUM + 8)
+
+/* FPU control word. */
+#define FCTRL_REGNUM FPC_REGNUM
+
+/* FPU status word. */
+#define FSTAT_REGNUM (FPC_REGNUM + 1)
+
+/* FPU register tag word. */
+#define FTAG_REGNUM (FPC_REGNUM + 2)
+
+/* FPU instruction's code segment selector, called "FPU Instruction
+ Pointer Selector" in the IA-32 manuals. */
+#define FISEG_REGNUM (FPC_REGNUM + 3)
+
+/* FPU instruction's offset within segment. */
+#define FIOFF_REGNUM (FPC_REGNUM + 4)
+
+/* FPU operand's data segment. */
+#define FOSEG_REGNUM (FPC_REGNUM + 5)
+
+/* FPU operand's offset within segment */
+#define FOOFF_REGNUM (FPC_REGNUM + 6)
+
+/* FPU opcode, bottom eleven bits. */
+#define FOP_REGNUM (FPC_REGNUM + 7)
+
+/* Return non-zero if REGNUM matches the FP register and the FP
+ register set is active. */
+extern int i386_fp_regnum_p (int regnum);
+extern int i386_fpc_regnum_p (int regnum);
+
+/* SSE registers. */
+
+/* First SSE data register. */
+#define XMM0_REGNUM (FPC_REGNUM + 8)
+
+/* SSE control/status register. */
+#define MXCSR_REGNUM \
+ (XMM0_REGNUM + gdbarch_tdep (current_gdbarch)->num_xmm_regs)
+
+/* Register numbers of various important registers. */
+
+enum i386_regnum
+{
+ I386_EAX_REGNUM, /* %eax */
+ I386_ECX_REGNUM, /* %ecx */
+ I386_EDX_REGNUM, /* %edx */
+ I386_EBX_REGNUM, /* %ebx */
+ I386_ESP_REGNUM, /* %esp */
+ I386_EBP_REGNUM, /* %ebp */
+ I386_ESI_REGNUM, /* %esi */
+ I386_EDI_REGNUM, /* %edi */
+ I386_EIP_REGNUM, /* %eip */
+ I386_EFLAGS_REGNUM, /* %eflags */
+ I386_CS_REGNUM, /* %cs */
+ I386_SS_REGNUM, /* %ss */
+ I386_DS_REGNUM, /* %ds */
+ I386_ES_REGNUM, /* %es */
+ I386_FS_REGNUM, /* %fs */
+ I386_GS_REGNUM, /* %gs */
+ I386_ST0_REGNUM /* %st(0) */
+};
+
+#define I386_NUM_GREGS 16
+#define I386_NUM_FREGS 16
+#define I386_NUM_XREGS 9
+
+#define I386_SSE_NUM_REGS (I386_NUM_GREGS + I386_NUM_FREGS \
+ + I386_NUM_XREGS)
+
+/* Size of the largest register. */
+#define I386_MAX_REGISTER_SIZE 16
+
+/* Functions exported from i386-tdep.c. */
+extern CORE_ADDR i386_pe_skip_trampoline_code (CORE_ADDR pc, char *name);
+extern int i386_frameless_signal_p (struct frame_info *frame);
+
+/* Return the name of register REG. */
+extern char const *i386_register_name (int reg);
+
+/* Return non-zero if REGNUM is a member of the specified group. */
+extern int i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group);
+
+/* Supply register REGNUM from the general-purpose register set REGSET
+ to register cache REGCACHE. If REGNUM is -1, do this for all
+ registers in REGSET. */
+extern void i386_supply_gregset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *gregs, size_t len);
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+extern const struct regset *
+ i386_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size);
+
+/* Initialize a basic ELF architecture variant. */
+extern void i386_elf_init_abi (struct gdbarch_info, struct gdbarch *);
+
+/* Initialize a SVR4 architecture variant. */
+extern void i386_svr4_init_abi (struct gdbarch_info, struct gdbarch *);
+
+
+/* Functions and variables exported from i386bsd-tdep.c. */
+
+extern void i386bsd_init_abi (struct gdbarch_info, struct gdbarch *);
+extern int i386bsd_pc_in_sigtramp (CORE_ADDR pc, char *name);
+extern CORE_ADDR i386bsd_sigtramp_start (CORE_ADDR pc);
+extern CORE_ADDR i386bsd_sigtramp_end (CORE_ADDR pc);
+extern CORE_ADDR i386fbsd_sigtramp_start_addr;
+extern CORE_ADDR i386fbsd_sigtramp_end_addr;
+extern CORE_ADDR i386obsd_sigtramp_start_addr;
+extern CORE_ADDR i386obsd_sigtramp_end_addr;
+extern int i386fbsd4_sc_reg_offset[];
+extern int i386fbsd_sc_reg_offset[];
+extern int i386nbsd_sc_reg_offset[];
+extern int i386obsd_sc_reg_offset[];
+extern int i386bsd_sc_reg_offset[];
+
+#endif /* i386-tdep.h */
diff --git a/contrib/gdb/gdb/i386bsd-nat.c b/contrib/gdb/gdb/i386bsd-nat.c
new file mode 100644
index 0000000..9383a1d
--- /dev/null
+++ b/contrib/gdb/gdb/i386bsd-nat.c
@@ -0,0 +1,456 @@
+/* Native-dependent code for modern i386 BSD's.
+ Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include "gdb_assert.h"
+#include <signal.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+
+#ifdef HAVE_SYS_PROCFS_H
+#include <sys/procfs.h>
+#endif
+
+#ifndef HAVE_GREGSET_T
+typedef struct reg gregset_t;
+#endif
+
+#ifndef HAVE_FPREGSET_T
+typedef struct fpreg fpregset_t;
+#endif
+
+#include "gregset.h"
+#include "i386-tdep.h"
+
+
+/* In older BSD versions we cannot get at some of the segment
+ registers. FreeBSD for example didn't support the %fs and %gs
+ registers until the 3.0 release. We have autoconf checks for their
+ presence, and deal gracefully with their absence. */
+
+/* Registers we shouldn't try to fetch. */
+#if !defined (CANNOT_FETCH_REGISTER)
+#define CANNOT_FETCH_REGISTER(regno) cannot_fetch_register (regno)
+#endif
+
+/* Registers we shouldn't try to store. */
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regno) cannot_fetch_register (regno)
+#endif
+
+/* Offset to the gregset_t location where REG is stored. */
+#define REG_OFFSET(reg) offsetof (gregset_t, reg)
+
+/* At reg_offset[REGNO] you'll find the offset to the gregset_t
+ location where the GDB register REGNO is stored. Unsupported
+ registers are marked with `-1'. */
+static int reg_offset[] =
+{
+ REG_OFFSET (r_eax),
+ REG_OFFSET (r_ecx),
+ REG_OFFSET (r_edx),
+ REG_OFFSET (r_ebx),
+ REG_OFFSET (r_esp),
+ REG_OFFSET (r_ebp),
+ REG_OFFSET (r_esi),
+ REG_OFFSET (r_edi),
+ REG_OFFSET (r_eip),
+ REG_OFFSET (r_eflags),
+ REG_OFFSET (r_cs),
+ REG_OFFSET (r_ss),
+ REG_OFFSET (r_ds),
+ REG_OFFSET (r_es),
+#ifdef HAVE_STRUCT_REG_R_FS
+ REG_OFFSET (r_fs),
+#else
+ -1,
+#endif
+#ifdef HAVE_STRUCT_REG_R_GS
+ REG_OFFSET (r_gs)
+#else
+ -1
+#endif
+};
+
+#define REG_ADDR(regset, regno) ((char *) (regset) + reg_offset[regno])
+
+/* Macro to determine if a register is fetched with PT_GETREGS. */
+#define GETREGS_SUPPLIES(regno) \
+ ((0 <= (regno) && (regno) <= 15))
+
+#ifdef HAVE_PT_GETXMMREGS
+/* Set to 1 if the kernel supports PT_GETXMMREGS. Initialized to -1
+ so that we try PT_GETXMMREGS the first time around. */
+static int have_ptrace_xmmregs = -1;
+#endif
+
+/* Return nonzero if we shouldn't try to fetch register REGNO. */
+
+static int
+cannot_fetch_register (int regno)
+{
+ return (reg_offset[regno] == -1);
+}
+
+
+/* Transfering the registers between GDB, inferiors and core files. */
+
+/* Fill GDB's register array with the general-purpose register values
+ in *GREGSETP. */
+
+void
+supply_gregset (gregset_t *gregsetp)
+{
+ int i;
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ {
+ if (CANNOT_FETCH_REGISTER (i))
+ supply_register (i, NULL);
+ else
+ supply_register (i, REG_ADDR (gregsetp, i));
+ }
+}
+
+/* Fill register REGNO (if it is a general-purpose register) in
+ *GREGSETPS with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_gregset (gregset_t *gregsetp, int regno)
+{
+ int i;
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ if ((regno == -1 || regno == i) && ! CANNOT_STORE_REGISTER (i))
+ regcache_collect (i, REG_ADDR (gregsetp, i));
+}
+
+#include "i387-tdep.h"
+
+/* Fill GDB's register array with the floating-point register values
+ in *FPREGSETP. */
+
+void
+supply_fpregset (fpregset_t *fpregsetp)
+{
+ i387_supply_fsave (current_regcache, -1, fpregsetp);
+}
+
+/* Fill register REGNO (if it is a floating-point register) in
+ *FPREGSETP with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_fpregset (fpregset_t *fpregsetp, int regno)
+{
+ i387_fill_fsave ((char *) fpregsetp, regno);
+}
+
+/* Fetch register REGNO from the inferior. If REGNO is -1, do this
+ for all registers (including the floating point registers). */
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || GETREGS_SUPPLIES (regno))
+ {
+ gregset_t gregs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &gregs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ supply_gregset (&gregs);
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ fpregset_t fpregs;
+#ifdef HAVE_PT_GETXMMREGS
+ char xmmregs[512];
+
+ if (have_ptrace_xmmregs != 0
+ && ptrace(PT_GETXMMREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) xmmregs, 0) == 0)
+ {
+ have_ptrace_xmmregs = 1;
+ i387_supply_fxsave (current_regcache, -1, xmmregs);
+ }
+ else
+ {
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ i387_supply_fsave (current_regcache, -1, &fpregs);
+ }
+#else
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ i387_supply_fsave (current_regcache, -1, &fpregs);
+#endif
+ }
+}
+
+/* Store register REGNO back into the inferior. If REGNO is -1, do
+ this for all registers (including the floating point registers). */
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno == -1 || GETREGS_SUPPLIES (regno))
+ {
+ gregset_t gregs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &gregs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ fill_gregset (&gregs, regno);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &gregs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ fpregset_t fpregs;
+#ifdef HAVE_PT_GETXMMREGS
+ char xmmregs[512];
+
+ if (have_ptrace_xmmregs != 0
+ && ptrace(PT_GETXMMREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) xmmregs, 0) == 0)
+ {
+ have_ptrace_xmmregs = 1;
+
+ i387_fill_fxsave (xmmregs, regno);
+
+ if (ptrace (PT_SETXMMREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) xmmregs, 0) == -1)
+ perror_with_name ("Couldn't write XMM registers");
+ }
+ else
+ {
+ have_ptrace_xmmregs = 0;
+#endif
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ i387_fill_fsave ((char *) &fpregs, regno);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't write floating point status");
+#ifdef HAVE_PT_GETXMMREGS
+ }
+#endif
+ }
+}
+
+
+/* Support for debug registers. */
+
+#ifdef HAVE_PT_GETDBREGS
+
+/* Not all versions of FreeBSD/i386 that support the debug registers
+ have this macro. */
+#ifndef DBREG_DRX
+#define DBREG_DRX(d, x) ((&d->dr0)[x])
+#endif
+
+static void
+i386bsd_dr_set (int regnum, unsigned int value)
+{
+ struct dbreg dbregs;
+
+ if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &dbregs, 0) == -1)
+ perror_with_name ("Couldn't get debug registers");
+
+ /* For some mysterious reason, some of the reserved bits in the
+ debug control register get set. Mask these off, otherwise the
+ ptrace call below will fail. */
+ DBREG_DRX ((&dbregs), 7) &= ~(0x0000fc00);
+
+ DBREG_DRX ((&dbregs), regnum) = value;
+
+ if (ptrace (PT_SETDBREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &dbregs, 0) == -1)
+ perror_with_name ("Couldn't write debug registers");
+}
+
+void
+i386bsd_dr_set_control (unsigned long control)
+{
+ i386bsd_dr_set (7, control);
+}
+
+void
+i386bsd_dr_set_addr (int regnum, CORE_ADDR addr)
+{
+ gdb_assert (regnum >= 0 && regnum <= 4);
+
+ i386bsd_dr_set (regnum, addr);
+}
+
+void
+i386bsd_dr_reset_addr (int regnum)
+{
+ gdb_assert (regnum >= 0 && regnum <= 4);
+
+ i386bsd_dr_set (regnum, 0);
+}
+
+unsigned long
+i386bsd_dr_get_status (void)
+{
+ struct dbreg dbregs;
+
+ /* FIXME: kettenis/2001-03-31: Calling perror_with_name if the
+ ptrace call fails breaks debugging remote targets. The correct
+ way to fix this is to add the hardware breakpoint and watchpoint
+ stuff to the target vector. For now, just return zero if the
+ ptrace call fails. */
+ if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) & dbregs, 0) == -1)
+#if 0
+ perror_with_name ("Couldn't read debug registers");
+#else
+ return 0;
+#endif
+
+ return DBREG_DRX ((&dbregs), 6);
+}
+
+#endif /* PT_GETDBREGS */
+
+
+/* Support for the user struct. */
+
+/* Return the address register REGNO. BLOCKEND is the value of
+ u.u_ar0, which should point to the registers. */
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regno)
+{
+ return (CORE_ADDR) REG_ADDR (blockend, regno);
+}
+
+#include <sys/param.h>
+#include <sys/user.h>
+
+/* Return the size of the user struct. */
+
+int
+kernel_u_size (void)
+{
+ return (sizeof (struct user));
+}
+
+void
+_initialize_i386bsd_nat (void)
+{
+ int offset;
+
+ /* To support the recognition of signal handlers, i386bsd-tdep.c
+ hardcodes some constants. Inclusion of this file means that we
+ are compiling a native debugger, which means that we can use the
+ system header files and sysctl(3) to get at the relevant
+ information. */
+
+#if defined (__FreeBSD_version) && __FreeBSD_version >= 400011
+#define SC_REG_OFFSET i386fbsd4_sc_reg_offset
+#elif defined (__FreeBSD_version) && __FreeBSD_version >= 300005
+#define SC_REG_OFFSET i386fbsd_sc_reg_offset
+#elif defined (NetBSD) || defined (__NetBSD_Version__)
+#define SC_REG_OFFSET i386nbsd_sc_reg_offset
+#elif defined (OpenBSD)
+#define SC_REG_OFFSET i386obsd_sc_reg_offset
+#else
+#define SC_REG_OFFSET i386bsd_sc_reg_offset
+#endif
+
+ /* We only check the program counter, stack pointer and frame
+ pointer since these members of `struct sigcontext' are essential
+ for providing backtraces. More checks could be added, but would
+ involve adding configure checks for the appropriate structure
+ members, since older BSD's don't provide all of them. */
+
+#define SC_PC_OFFSET SC_REG_OFFSET[I386_EIP_REGNUM]
+#define SC_SP_OFFSET SC_REG_OFFSET[I386_ESP_REGNUM]
+#define SC_FP_OFFSET SC_REG_OFFSET[I386_EBP_REGNUM]
+
+ /* Override the default value for the offset of the program counter
+ in the sigcontext structure. */
+ offset = offsetof (struct sigcontext, sc_pc);
+
+ if (SC_PC_OFFSET != offset)
+ {
+ warning ("\
+offsetof (struct sigcontext, sc_pc) yields %d instead of %d.\n\
+Please report this to <bug-gdb@gnu.org>.",
+ offset, SC_PC_OFFSET);
+ }
+
+ SC_PC_OFFSET = offset;
+
+ /* Likewise for the stack pointer. */
+ offset = offsetof (struct sigcontext, sc_sp);
+
+ if (SC_SP_OFFSET != offset)
+ {
+ warning ("\
+offsetof (struct sigcontext, sc_sp) yields %d instead of %d.\n\
+Please report this to <bug-gdb@gnu.org>.",
+ offset, SC_SP_OFFSET);
+ }
+
+ SC_SP_OFFSET = offset;
+
+ /* And the frame pointer. */
+ offset = offsetof (struct sigcontext, sc_fp);
+
+ if (SC_FP_OFFSET != offset)
+ {
+ warning ("\
+offsetof (struct sigcontext, sc_fp) yields %d instead of %d.\n\
+Please report this to <bug-gdb@gnu.org>.",
+ offset, SC_FP_OFFSET);
+ }
+
+ SC_FP_OFFSET = offset;
+}
diff --git a/contrib/gdb/gdb/i386bsd-tdep.c b/contrib/gdb/gdb/i386bsd-tdep.c
new file mode 100644
index 0000000..9276c32
--- /dev/null
+++ b/contrib/gdb/gdb/i386bsd-tdep.c
@@ -0,0 +1,170 @@
+/* Target-dependent code for i386 BSD's.
+
+ Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "osabi.h"
+
+#include "gdb_string.h"
+
+#include "i386-tdep.h"
+
+/* Support for signal handlers. */
+
+/* Return whether PC is in a BSD sigtramp routine. */
+
+int
+i386bsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ return (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end);
+}
+
+/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
+ routine, return the address of the associated sigcontext structure. */
+
+static CORE_ADDR
+i386bsd_sigcontext_addr (struct frame_info *next_frame)
+{
+ char buf[4];
+ CORE_ADDR sp;
+
+ frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+ sp = extract_unsigned_integer (buf, 4);
+
+ return read_memory_unsigned_integer (sp + 8, 4);
+}
+
+/* Return the start address of the sigtramp routine. */
+
+CORE_ADDR
+i386bsd_sigtramp_start (CORE_ADDR pc)
+{
+ return gdbarch_tdep (current_gdbarch)->sigtramp_start;
+}
+
+/* Return the end address of the sigtramp routine. */
+
+CORE_ADDR
+i386bsd_sigtramp_end (CORE_ADDR pc)
+{
+ return gdbarch_tdep (current_gdbarch)->sigtramp_end;
+}
+
+
+/* Support for shared libraries. */
+
+/* Return non-zero if we are in a shared library trampoline code stub. */
+
+int
+i386bsd_aout_in_solib_call_trampoline (CORE_ADDR pc, char *name)
+{
+ return (name && !strcmp (name, "_DYNAMIC"));
+}
+
+/* Traditional BSD (4.3 BSD, still used for BSDI and 386BSD). */
+
+/* From <machine/signal.h>. */
+int i386bsd_sc_reg_offset[] =
+{
+ -1, /* %eax */
+ -1, /* %ecx */
+ -1, /* %edx */
+ -1, /* %ebx */
+ 8 + 0 * 4, /* %esp */
+ 8 + 1 * 4, /* %ebp */
+ -1, /* %esi */
+ -1, /* %edi */
+ 8 + 3 * 4, /* %eip */
+ 8 + 4 * 4, /* %eflags */
+ -1, /* %cs */
+ -1, /* %ss */
+ -1, /* %ds */
+ -1, /* %es */
+ -1, /* %fs */
+ -1 /* %gs */
+};
+
+void
+i386bsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386bsd_pc_in_sigtramp);
+
+ /* Allow the recognition of sigtramps as a function named <sigtramp>. */
+ set_gdbarch_sigtramp_start (gdbarch, i386bsd_sigtramp_start);
+ set_gdbarch_sigtramp_end (gdbarch, i386bsd_sigtramp_end);
+
+ /* Assume SunOS-style shared libraries. */
+ set_gdbarch_in_solib_call_trampoline (gdbarch,
+ i386bsd_aout_in_solib_call_trampoline);
+
+ tdep->jb_pc_offset = 0;
+
+ tdep->sigtramp_start = 0xfdbfdfc0;
+ tdep->sigtramp_end = 0xfdbfe000;
+ tdep->sigcontext_addr = i386bsd_sigcontext_addr;
+ tdep->sc_reg_offset = i386bsd_sc_reg_offset;
+ tdep->sc_num_regs = ARRAY_SIZE (i386bsd_sc_reg_offset);
+}
+
+
+static enum gdb_osabi
+i386bsd_aout_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "a.out-i386-netbsd") == 0)
+ return GDB_OSABI_NETBSD_AOUT;
+
+ if (strcmp (bfd_get_target (abfd), "a.out-i386-freebsd") == 0)
+ return GDB_OSABI_FREEBSD_AOUT;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+static enum gdb_osabi
+i386bsd_core_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
+ return GDB_OSABI_NETBSD_AOUT;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386bsd_tdep (void);
+
+void
+_initialize_i386bsd_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_aout_flavour,
+ i386bsd_aout_osabi_sniffer);
+
+ /* BFD doesn't set the architecture for NetBSD style a.out core
+ files. */
+ gdbarch_register_osabi_sniffer (bfd_arch_unknown, bfd_target_unknown_flavour,
+ i386bsd_core_osabi_sniffer);
+}
diff --git a/contrib/gdb/gdb/i386fbsd-nat.c b/contrib/gdb/gdb/i386fbsd-nat.c
new file mode 100644
index 0000000..c479986
--- /dev/null
+++ b/contrib/gdb/gdb/i386fbsd-nat.c
@@ -0,0 +1,107 @@
+/* Native-dependent code for FreeBSD/i386.
+
+ Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+
+#include "i386-tdep.h"
+
+/* Prevent warning from -Wmissing-prototypes. */
+void _initialize_i386fbsd_nat (void);
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+child_resume (ptid_t ptid, int step, enum target_signal signal)
+{
+ pid_t pid = ptid_get_pid (ptid);
+ int request = PT_STEP;
+
+ if (pid == -1)
+ /* Resume all threads. This only gets used in the non-threaded
+ case, where "resume all threads" and "resume inferior_ptid" are
+ the same. */
+ pid = ptid_get_pid (inferior_ptid);
+
+ if (!step)
+ {
+ ULONGEST eflags;
+
+ /* Workaround for a bug in FreeBSD. Make sure that the trace
+ flag is off when doing a continue. There is a code path
+ through the kernel which leaves the flag set when it should
+ have been cleared. If a process has a signal pending (such
+ as SIGALRM) and we do a PT_STEP, the process never really has
+ a chance to run because the kernel needs to notify the
+ debugger that a signal is being sent. Therefore, the process
+ never goes through the kernel's trap() function which would
+ normally clear it. */
+
+ regcache_cooked_read_unsigned (current_regcache, I386_EFLAGS_REGNUM,
+ &eflags);
+ if (eflags & 0x0100)
+ regcache_cooked_write_unsigned (current_regcache, I386_EFLAGS_REGNUM,
+ eflags & ~0x0100);
+
+ request = PT_CONTINUE;
+ }
+
+ /* An addres of (caddr_t) 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 (ptrace (request, pid, (caddr_t) 1,
+ target_signal_to_host (signal)) == -1)
+ perror_with_name ("ptrace");
+}
+
+void
+_initialize_i386fbsd_nat (void)
+{
+ /* FreeBSD provides a kern.ps_strings sysctl that we can use to
+ locate the sigtramp. That way we can still recognize a sigtramp
+ if its location is changed in a new kernel. Of course this is
+ still based on the assumption that the sigtramp is placed
+ directly under the location where the program arguments and
+ environment can be found. */
+#ifdef KERN_PS_STRINGS
+ {
+ int mib[2];
+ u_long ps_strings;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PS_STRINGS;
+ len = sizeof (ps_strings);
+ if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0)
+ {
+ i386fbsd_sigtramp_start_addr = ps_strings - 128;
+ i386fbsd_sigtramp_end_addr = ps_strings;
+ }
+ }
+#endif
+}
diff --git a/contrib/gdb/gdb/i386fbsd-tdep.c b/contrib/gdb/gdb/i386fbsd-tdep.c
new file mode 100644
index 0000000..db14a67
--- /dev/null
+++ b/contrib/gdb/gdb/i386fbsd-tdep.c
@@ -0,0 +1,175 @@
+/* Target-dependent code for FreeBSD/i386.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "osabi.h"
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+#include "solib-svr4.h"
+
+/* FreeBSD 3.0-RELEASE or later. */
+
+/* From <machine/reg.h>. */
+static int i386fbsd_r_reg_offset[] =
+{
+ 9 * 4, 8 * 4, 7 * 4, 6 * 4, /* %eax, %ecx, %edx, %ebx */
+ 15 * 4, 4 * 4, /* %esp, %ebp */
+ 3 * 4, 2 * 4, /* %esi, %edi */
+ 12 * 4, 14 * 4, /* %eip, %eflags */
+ 13 * 4, 16 * 4, /* %cs, %ss */
+ 1 * 4, 0 * 4, -1, -1 /* %ds, %es, %fs, %gs */
+};
+
+/* Sigtramp routine location. */
+CORE_ADDR i386fbsd_sigtramp_start_addr = 0xbfbfdf20;
+CORE_ADDR i386fbsd_sigtramp_end_addr = 0xbfbfdff0;
+
+/* From <machine/signal.h>. */
+static int i386fbsd_sc_reg_offset[] =
+{
+ 8 + 14 * 4, /* %eax */
+ 8 + 13 * 4, /* %ecx */
+ 8 + 12 * 4, /* %edx */
+ 8 + 11 * 4, /* %ebx */
+ 8 + 0 * 4, /* %esp */
+ 8 + 1 * 4, /* %ebp */
+ 8 + 10 * 4, /* %esi */
+ 8 + 9 * 4, /* %edi */
+ 8 + 3 * 4, /* %eip */
+ 8 + 4 * 4, /* %eflags */
+ 8 + 7 * 4, /* %cs */
+ 8 + 8 * 4, /* %ss */
+ 8 + 6 * 4, /* %ds */
+ 8 + 5 * 4, /* %es */
+ 8 + 15 * 4, /* %fs */
+ 8 + 16 * 4 /* %gs */
+};
+
+static void
+i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Obviously FreeBSD is BSD-based. */
+ i386bsd_init_abi (info, gdbarch);
+
+ /* FreeBSD has a different `struct reg', and reserves some space for
+ its FPU emulator in `struct fpreg'. */
+ tdep->gregset_reg_offset = i386fbsd_r_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd_r_reg_offset);
+ tdep->sizeof_gregset = 18 * 4;
+ tdep->sizeof_fpregset = 176;
+
+ /* FreeBSD uses -freg-struct-return by default. */
+ tdep->struct_return = reg_struct_return;
+
+ /* FreeBSD uses a different memory layout. */
+ tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
+ tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
+
+ /* FreeBSD has a more complete `struct sigcontext'. */
+ tdep->sc_reg_offset = i386fbsd_sc_reg_offset;
+ tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
+}
+
+static void
+i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ /* It's almost identical to FreeBSD a.out. */
+ i386fbsdaout_init_abi (info, gdbarch);
+
+ /* Except that it uses ELF. */
+ i386_elf_init_abi (info, gdbarch);
+
+ /* FreeBSD ELF uses SVR4-style shared libraries. */
+ set_gdbarch_in_solib_call_trampoline
+ (gdbarch, generic_in_solib_call_trampoline);
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+}
+
+/* FreeBSD 4.0-RELEASE or later. */
+
+/* From <machine/reg.h>. */
+static int i386fbsd4_r_reg_offset[] =
+{
+ 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
+ 16 * 4, 5 * 4, /* %esp, %ebp */
+ 4 * 4, 3 * 4, /* %esi, %edi */
+ 13 * 4, 15 * 4, /* %eip, %eflags */
+ 14 * 4, 17 * 4, /* %cs, %ss */
+ 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
+};
+
+/* From <machine/signal.h>. */
+int i386fbsd4_sc_reg_offset[] =
+{
+ 20 + 11 * 4, /* %eax */
+ 20 + 10 * 4, /* %ecx */
+ 20 + 9 * 4, /* %edx */
+ 20 + 8 * 4, /* %ebx */
+ 20 + 17 * 4, /* %esp */
+ 20 + 6 * 4, /* %ebp */
+ 20 + 5 * 4, /* %esi */
+ 20 + 4 * 4, /* %edi */
+ 20 + 14 * 4, /* %eip */
+ 20 + 16 * 4, /* %eflags */
+ 20 + 15 * 4, /* %cs */
+ 20 + 18 * 4, /* %ss */
+ 20 + 3 * 4, /* %ds */
+ 20 + 2 * 4, /* %es */
+ 20 + 1 * 4, /* %fs */
+ 20 + 0 * 4 /* %gs */
+};
+
+static void
+i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Inherit stuff from older releases. We assume that FreeBSD
+ 4.0-RELEASE always uses ELF. */
+ i386fbsd_init_abi (info, gdbarch);
+
+ /* FreeBSD 4.0 introduced a new `struct reg'. */
+ tdep->gregset_reg_offset = i386fbsd4_r_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd4_r_reg_offset);
+ tdep->sizeof_gregset = 19 * 4;
+
+ /* FreeBSD 4.0 introduced a new `struct sigcontext'. */
+ tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
+ tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386fbsd_tdep (void);
+
+void
+_initialize_i386fbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_AOUT,
+ i386fbsdaout_init_abi);
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_ELF,
+ i386fbsd4_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386gnu-nat.c b/contrib/gdb/gdb/i386gnu-nat.c
new file mode 100644
index 0000000..7533f09
--- /dev/null
+++ b/contrib/gdb/gdb/i386gnu-nat.c
@@ -0,0 +1,293 @@
+/* Low level interface to i386 running the GNU Hurd.
+ Copyright 1992, 1995, 1996, 1998, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include "gdb_assert.h"
+#include <errno.h>
+#include <stdio.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/message.h>
+#include <mach/exception.h>
+
+#include "i386-tdep.h"
+
+#include "gnu-nat.h"
+#include "i387-tdep.h"
+
+#ifdef HAVE_SYS_PROCFS_H
+# include <sys/procfs.h>
+# include "gregset.h"
+#endif
+
+/* Offset to the thread_state_t location where REG is stored. */
+#define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)
+
+/* At REG_OFFSET[N] is the offset to the thread_state_t location where
+ the GDB register N 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])
+
+
+/* Get the whole floating-point state of THREAD and record the
+ values of the corresponding (pseudo) registers. */
+static void
+fetch_fpregs (struct proc *thread)
+{
+ mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+ struct i386_float_state state;
+ error_t err;
+
+ err = thread_get_state (thread->port, i386_FLOAT_STATE,
+ (thread_state_t) &state, &count);
+ if (err)
+ {
+ warning ("Couldn't fetch floating-point state from %s",
+ proc_string (thread));
+ return;
+ }
+
+ if (!state.initialized)
+ /* The floating-point state isn't initialized. */
+ {
+ int i;
+
+ for (i = FP0_REGNUM; i <= FOP_REGNUM; i++)
+ supply_register (i, NULL);
+
+ return;
+ }
+
+ /* Supply the floating-point registers. */
+ i387_supply_fsave (current_regcache, -1, state.hw_state);
+}
+
+#ifdef HAVE_SYS_PROCFS_H
+/* These two calls are used by the core-regset.c code for
+ reading ELF core files. */
+void
+supply_gregset (gdb_gregset_t *gregs)
+{
+ int i;
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ supply_register (i, REG_ADDR (gregs, i));
+}
+
+void
+supply_fpregset (gdb_fpregset_t *fpregs)
+{
+ i387_supply_fsave (current_regcache, -1, fpregs);
+}
+#endif
+
+/* Fetch register REGNO, or all regs if REGNO is -1. */
+void
+gnu_fetch_registers (int regno)
+{
+ struct proc *thread;
+
+ /* Make sure we know about new threads. */
+ inf_update_procs (current_inferior);
+
+ thread = inf_tid_to_thread (current_inferior, PIDGET (inferior_ptid));
+ if (!thread)
+ error ("Can't fetch registers from thread %d: No such thread",
+ PIDGET (inferior_ptid));
+
+ if (regno < I386_NUM_GREGS || regno == -1)
+ {
+ thread_state_t state;
+
+ /* This does the dirty work for us. */
+ state = proc_get_state (thread, 0);
+ if (!state)
+ {
+ warning ("Couldn't fetch registers from %s",
+ proc_string (thread));
+ return;
+ }
+
+ if (regno == -1)
+ {
+ int i;
+
+ proc_debug (thread, "fetching all register");
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ supply_register (i, REG_ADDR (state, i));
+ thread->fetched_regs = ~0;
+ }
+ else
+ {
+ proc_debug (thread, "fetching register %s", REGISTER_NAME (regno));
+
+ supply_register (regno, REG_ADDR (state, regno));
+ thread->fetched_regs |= (1 << regno);
+ }
+ }
+
+ if (regno >= I386_NUM_GREGS || regno == -1)
+ {
+ proc_debug (thread, "fetching floating-point registers");
+
+ fetch_fpregs (thread);
+ }
+}
+
+
+/* Store the whole floating-point state into THREAD using information
+ from the corresponding (pseudo) registers. */
+static void
+store_fpregs (struct proc *thread, int regno)
+{
+ mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+ struct i386_float_state state;
+ error_t err;
+
+ err = thread_get_state (thread->port, i386_FLOAT_STATE,
+ (thread_state_t) &state, &count);
+ if (err)
+ {
+ warning ("Couldn't fetch floating-point state from %s",
+ proc_string (thread));
+ return;
+ }
+
+ /* FIXME: kettenis/2001-07-15: Is this right? Should we somehow
+ take into account DEPRECATED_REGISTER_VALID like the old code did? */
+ i387_fill_fsave (state.hw_state, regno);
+
+ err = thread_set_state (thread->port, i386_FLOAT_STATE,
+ (thread_state_t) &state, i386_FLOAT_STATE_COUNT);
+ if (err)
+ {
+ warning ("Couldn't store floating-point state into %s",
+ proc_string (thread));
+ return;
+ }
+}
+
+/* Store at least register REGNO, or all regs if REGNO == -1. */
+void
+gnu_store_registers (int regno)
+{
+ struct proc *thread;
+
+ /* Make sure we know about new threads. */
+ inf_update_procs (current_inferior);
+
+ thread = inf_tid_to_thread (current_inferior, PIDGET (inferior_ptid));
+ if (!thread)
+ error ("Couldn't store registers into thread %d: No such thread",
+ PIDGET (inferior_ptid));
+
+ if (regno < I386_NUM_GREGS || regno == -1)
+ {
+ thread_state_t state;
+ thread_state_data_t old_state;
+ int was_aborted = thread->aborted;
+ int was_valid = thread->state_valid;
+ int trace;
+
+ if (!was_aborted && was_valid)
+ memcpy (&old_state, &thread->state, sizeof (old_state));
+
+ state = proc_get_state (thread, 1);
+ if (!state)
+ {
+ warning ("Couldn't store registers into %s", proc_string (thread));
+ return;
+ }
+
+ /* Save the T bit. We might try to restore the %eflags register
+ below, but changing the T bit would seriously confuse GDB. */
+ trace = ((struct i386_thread_state *)state)->efl & 0x100;
+
+ if (!was_aborted && was_valid)
+ /* See which registers have changed after aborting the thread. */
+ {
+ int check_regno;
+
+ for (check_regno = 0; check_regno < I386_NUM_GREGS; check_regno++)
+ if ((thread->fetched_regs & (1 << check_regno))
+ && memcpy (REG_ADDR (&old_state, check_regno),
+ REG_ADDR (state, check_regno),
+ DEPRECATED_REGISTER_RAW_SIZE (check_regno)))
+ /* Register CHECK_REGNO has changed! Ack! */
+ {
+ warning ("Register %s changed after the thread was aborted",
+ REGISTER_NAME (check_regno));
+ if (regno >= 0 && regno != check_regno)
+ /* Update GDB's copy of the register. */
+ supply_register (check_regno, REG_ADDR (state, check_regno));
+ else
+ warning ("... also writing this register! Suspicious...");
+ }
+ }
+
+#define fill(state, regno) \
+ memcpy (REG_ADDR(state, regno), &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)], \
+ DEPRECATED_REGISTER_RAW_SIZE (regno))
+
+ if (regno == -1)
+ {
+ int i;
+
+ proc_debug (thread, "storing all registers");
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ if (deprecated_register_valid[i])
+ fill (state, i);
+ }
+ else
+ {
+ proc_debug (thread, "storing register %s", REGISTER_NAME (regno));
+
+ gdb_assert (deprecated_register_valid[regno]);
+ fill (state, regno);
+ }
+
+ /* Restore the T bit. */
+ ((struct i386_thread_state *)state)->efl &= ~0x100;
+ ((struct i386_thread_state *)state)->efl |= trace;
+ }
+
+#undef fill
+
+ if (regno >= I386_NUM_GREGS || regno == -1)
+ {
+ proc_debug (thread, "storing floating-point registers");
+
+ store_fpregs (thread, regno);
+ }
+}
diff --git a/contrib/gdb/gdb/i386gnu-tdep.c b/contrib/gdb/gdb/i386gnu-tdep.c
new file mode 100644
index 0000000..297d566
--- /dev/null
+++ b/contrib/gdb/gdb/i386gnu-tdep.c
@@ -0,0 +1,44 @@
+/* Target-dependent code for the GNU Hurd.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "osabi.h"
+
+#include "i386-tdep.h"
+
+static void
+i386gnu_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* GNU uses ELF. */
+ i386_elf_init_abi (info, gdbarch);
+
+ tdep->jb_pc_offset = 20; /* From <bits/setjmp.h>. */
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern void _initialize_i386gnu_tdep (void);
+
+void
+_initialize_i386gnu_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_HURD, i386gnu_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386ly-tdep.c b/contrib/gdb/gdb/i386ly-tdep.c
new file mode 100644
index 0000000..2374b71
--- /dev/null
+++ b/contrib/gdb/gdb/i386ly-tdep.c
@@ -0,0 +1,81 @@
+/* Target-dependent code for Intel 386 running LynxOS.
+ Copyright 1993, 1996, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "inferior.h"
+#include "regcache.h"
+#include "target.h"
+#include "osabi.h"
+
+#include "i386-tdep.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. */
+
+static CORE_ADDR
+i386lynx_saved_pc_after_call (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_nobpt (frame->pc - 7, opcode, 7);
+ if (memcmp (opcode, call_inst, 7) == 0)
+ return read_memory_unsigned_integer (read_register (SP_REGNUM) + 4, 4);
+
+ return read_memory_unsigned_integer (read_register (SP_REGNUM), 4);
+}
+
+
+/* LynxOS. */
+static void
+i386lynx_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ set_gdbarch_deprecated_saved_pc_after_call (gdbarch, i386lynx_saved_pc_after_call);
+}
+
+
+static enum gdb_osabi
+i386lynx_coff_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "coff-i386-lynx") == 0)
+ return GDB_OSABI_LYNXOS;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386lynx_tdep (void);
+
+void
+_initialize_i386lynx_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
+ i386lynx_coff_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LYNXOS,
+ i386lynx_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386nbsd-tdep.c b/contrib/gdb/gdb/i386nbsd-tdep.c
new file mode 100644
index 0000000..82013b5
--- /dev/null
+++ b/contrib/gdb/gdb/i386nbsd-tdep.c
@@ -0,0 +1,286 @@
+/* Target-dependent code for NetBSD/i386.
+
+ Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
+ 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "regset.h"
+#include "osabi.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+#include "nbsd-tdep.h"
+#include "solib-svr4.h"
+
+/* From <machine/reg.h>. */
+static int i386nbsd_r_reg_offset[] =
+{
+ 0 * 4, /* %eax */
+ 1 * 4, /* %ecx */
+ 2 * 4, /* %edx */
+ 3 * 4, /* %ebx */
+ 4 * 4, /* %esp */
+ 5 * 4, /* %ebp */
+ 6 * 4, /* %esi */
+ 7 * 4, /* %edi */
+ 8 * 4, /* %eip */
+ 9 * 4, /* %eflags */
+ 10 * 4, /* %cs */
+ 11 * 4, /* %ss */
+ 12 * 4, /* %ds */
+ 13 * 4, /* %es */
+ 14 * 4, /* %fs */
+ 15 * 4 /* %gs */
+};
+
+static void
+i386nbsd_aout_supply_regset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *regs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = regset->descr;
+
+ gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
+
+ i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
+ i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
+}
+
+static const struct regset *
+i386nbsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* NetBSD a.out core dumps don't use seperate register sets for the
+ general-purpose and floating-point registers. */
+
+ if (strcmp (sect_name, ".reg") == 0
+ && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
+ {
+ if (tdep->gregset == NULL)
+ {
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = tdep;
+ tdep->gregset->supply_regset = i386nbsd_aout_supply_regset;
+ }
+ return tdep->gregset;
+ }
+
+ return NULL;
+}
+
+/* Under NetBSD/i386, signal handler invocations can be identified by the
+ designated code sequence that is used to return from a signal handler.
+ In particular, the return address of a signal handler points to the
+ following code sequence:
+
+ leal 0x10(%esp), %eax
+ pushl %eax
+ pushl %eax
+ movl $0x127, %eax # __sigreturn14
+ int $0x80
+
+ Each instruction has a unique encoding, so we simply attempt to match
+ the instruction the PC is pointing to with any of the above instructions.
+ If there is a hit, we know the offset to the start of the designated
+ sequence and can then check whether we really are executing in the
+ signal trampoline. If not, -1 is returned, otherwise the offset from the
+ start of the return sequence is returned. */
+#define RETCODE_INSN1 0x8d
+#define RETCODE_INSN2 0x50
+#define RETCODE_INSN3 0x50
+#define RETCODE_INSN4 0xb8
+#define RETCODE_INSN5 0xcd
+
+#define RETCODE_INSN2_OFF 4
+#define RETCODE_INSN3_OFF 5
+#define RETCODE_INSN4_OFF 6
+#define RETCODE_INSN5_OFF 11
+
+static const unsigned char sigtramp_retcode[] =
+{
+ RETCODE_INSN1, 0x44, 0x24, 0x10,
+ RETCODE_INSN2,
+ RETCODE_INSN3,
+ RETCODE_INSN4, 0x27, 0x01, 0x00, 0x00,
+ RETCODE_INSN5, 0x80,
+};
+
+static LONGEST
+i386nbsd_sigtramp_offset (CORE_ADDR pc)
+{
+ unsigned char ret[sizeof(sigtramp_retcode)], insn;
+ LONGEST off;
+ int i;
+
+ if (read_memory_nobpt (pc, &insn, 1) != 0)
+ return -1;
+
+ switch (insn)
+ {
+ case RETCODE_INSN1:
+ off = 0;
+ break;
+
+ case RETCODE_INSN2:
+ /* INSN2 and INSN3 are the same. Read at the location of PC+1
+ to determine if we're actually looking at INSN2 or INSN3. */
+ if (read_memory_nobpt (pc + 1, &insn, 1) != 0)
+ return -1;
+
+ if (insn == RETCODE_INSN3)
+ off = RETCODE_INSN2_OFF;
+ else
+ off = RETCODE_INSN3_OFF;
+ break;
+
+ case RETCODE_INSN4:
+ off = RETCODE_INSN4_OFF;
+ break;
+
+ case RETCODE_INSN5:
+ off = RETCODE_INSN5_OFF;
+ break;
+
+ default:
+ return -1;
+ }
+
+ pc -= off;
+
+ if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
+ return -1;
+
+ if (memcmp (ret, sigtramp_retcode, sizeof (ret)) == 0)
+ return off;
+
+ return -1;
+}
+
+static int
+i386nbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ return (nbsd_pc_in_sigtramp (pc, name)
+ || i386nbsd_sigtramp_offset (pc) >= 0);
+}
+
+/* From <machine/signal.h>. */
+int i386nbsd_sc_reg_offset[] =
+{
+ 10 * 4, /* %eax */
+ 9 * 4, /* %ecx */
+ 8 * 4, /* %edx */
+ 7 * 4, /* %ebx */
+ 14 * 4, /* %esp */
+ 6 * 4, /* %ebp */
+ 5 * 4, /* %esi */
+ 4 * 4, /* %edi */
+ 11 * 4, /* %eip */
+ 13 * 4, /* %eflags */
+ 12 * 4, /* %cs */
+ 15 * 4, /* %ss */
+ 3 * 4, /* %ds */
+ 2 * 4, /* %es */
+ 1 * 4, /* %fs */
+ 0 * 4 /* %gs */
+};
+
+static void
+i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Obviously NetBSD is BSD-based. */
+ i386bsd_init_abi (info, gdbarch);
+
+ /* NetBSD has a different `struct reg'. */
+ tdep->gregset_reg_offset = i386nbsd_r_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset);
+ tdep->sizeof_gregset = 16 * 4;
+
+ /* NetBSD has different signal trampoline conventions. */
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386nbsd_pc_in_sigtramp);
+ /* FIXME: kettenis/20020906: We should probably provide
+ NetBSD-specific versions of these functions if we want to
+ recognize signal trampolines that live on the stack. */
+ set_gdbarch_sigtramp_start (gdbarch, NULL);
+ set_gdbarch_sigtramp_end (gdbarch, NULL);
+
+ /* NetBSD uses -freg-struct-return by default. */
+ tdep->struct_return = reg_struct_return;
+
+ /* NetBSD has a `struct sigcontext' that's different from the
+ origional 4.3 BSD. */
+ tdep->sc_reg_offset = i386nbsd_sc_reg_offset;
+ tdep->sc_num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset);
+}
+
+/* NetBSD a.out. */
+
+static void
+i386nbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ i386nbsd_init_abi (info, gdbarch);
+
+ /* NetBSD a.out has a single register set. */
+ set_gdbarch_regset_from_core_section
+ (gdbarch, i386nbsd_aout_regset_from_core_section);
+}
+
+/* NetBSD ELF. */
+
+static void
+i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* It's still NetBSD. */
+ i386nbsd_init_abi (info, gdbarch);
+
+ /* But ELF-based. */
+ i386_elf_init_abi (info, gdbarch);
+
+ /* NetBSD ELF uses SVR4-style shared libraries. */
+ set_gdbarch_in_solib_call_trampoline
+ (gdbarch, generic_in_solib_call_trampoline);
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+
+ /* NetBSD ELF uses -fpcc-struct-return by default. */
+ tdep->struct_return = pcc_struct_return;
+}
+
+void
+_initialize_i386nbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_AOUT,
+ i386nbsdaout_init_abi);
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_ELF,
+ i386nbsdelf_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386obsd-nat.c b/contrib/gdb/gdb/i386obsd-nat.c
new file mode 100644
index 0000000..68cc790
--- /dev/null
+++ b/contrib/gdb/gdb/i386obsd-nat.c
@@ -0,0 +1,60 @@
+/* Native-dependent code for OpenBSD/i386.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <sys/param.h>
+#include <sys/sysctl.h>
+
+#include "i386-tdep.h"
+
+/* Prevent warning from -Wmissing-prototypes. */
+void _initialize_i386obsd_nat (void);
+
+void
+_initialize_i386obsd_nat (void)
+{
+ /* OpenBSD provides a vm.psstrings sysctl that we can use to locate
+ the sigtramp. That way we can still recognize a sigtramp if its
+ location is changed in a new kernel. This is especially
+ important for OpenBSD, since it uses a different memory layout
+ than NetBSD, yet we cannot distinguish between the two.
+
+ Of course this is still based on the assumption that the sigtramp
+ is placed directly under the location where the program arguments
+ and environment can be found. */
+#ifdef VM_PSSTRINGS
+ {
+ struct _ps_strings _ps;
+ int mib[2];
+ size_t len;
+
+ mib[0] = CTL_VM;
+ mib[1] = VM_PSSTRINGS;
+ len = sizeof (_ps);
+ if (sysctl (mib, 2, &_ps, &len, NULL, 0) == 0)
+ {
+ i386obsd_sigtramp_start_addr = (CORE_ADDR)_ps.val - 128;
+ i386obsd_sigtramp_end_addr = (CORE_ADDR)_ps.val;
+ }
+ }
+#endif
+}
diff --git a/contrib/gdb/gdb/i386obsd-tdep.c b/contrib/gdb/gdb/i386obsd-tdep.c
new file mode 100644
index 0000000..d8556ea
--- /dev/null
+++ b/contrib/gdb/gdb/i386obsd-tdep.c
@@ -0,0 +1,277 @@
+/* Target-dependent code for OpenBSD/i386.
+
+ Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
+ 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "regset.h"
+#include "osabi.h"
+#include "target.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+#include "solib-svr4.h"
+
+/* Support for signal handlers. */
+
+/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
+ in virtual memory. The randomness makes it somewhat tricky to
+ detect it, but fortunately we can rely on the fact that the start
+ of the sigtramp routine is page-aligned. By the way, the mapping
+ is read-only, so you cannot place a breakpoint in the signal
+ trampoline. */
+
+/* Default page size. */
+static const int i386obsd_page_size = 4096;
+
+/* Return whether PC is in an OpenBSD sigtramp routine. */
+
+static int
+i386obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
+ const char sigreturn[] =
+ {
+ 0xb8,
+ 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */
+ 0xcd, 0x80 /* int $0x80 */
+ };
+ char *buf;
+
+ /* Avoid reading memory from the target if possible. If we're in a
+ named function, we're certainly not in a sigtramp routine
+ provided by the kernel. Take synthetic function names into
+ account though. */
+ if (name && name[0] != '<')
+ return 0;
+
+ /* If we can't read the instructions at START_PC, return zero. */
+ buf = alloca (sizeof sigreturn);
+ if (target_read_memory (start_pc + 0x14, buf, sizeof sigreturn))
+ return 0;
+
+ /* Check for sigreturn(2). */
+ if (memcmp (buf, sigreturn, sizeof sigreturn) == 0)
+ return 1;
+
+ /* Check for a traditional BSD sigtramp routine. */
+ return i386bsd_pc_in_sigtramp (pc, name);
+}
+
+/* Return the start address of the sigtramp routine. */
+
+static CORE_ADDR
+i386obsd_sigtramp_start (CORE_ADDR pc)
+{
+ CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
+
+ if (i386bsd_pc_in_sigtramp (pc, NULL))
+ return i386bsd_sigtramp_start (pc);
+
+ return start_pc;
+}
+
+/* Return the end address of the sigtramp routine. */
+
+static CORE_ADDR
+i386obsd_sigtramp_end (CORE_ADDR pc)
+{
+ CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
+
+ if (i386bsd_pc_in_sigtramp (pc, NULL))
+ return i386bsd_sigtramp_end (pc);
+
+ return start_pc + 0x22;
+}
+
+/* Mapping between the general-purpose registers in `struct reg'
+ format and GDB's register cache layout. */
+
+/* From <machine/reg.h>. */
+static int i386obsd_r_reg_offset[] =
+{
+ 0 * 4, /* %eax */
+ 1 * 4, /* %ecx */
+ 2 * 4, /* %edx */
+ 3 * 4, /* %ebx */
+ 4 * 4, /* %esp */
+ 5 * 4, /* %ebp */
+ 6 * 4, /* %esi */
+ 7 * 4, /* %edi */
+ 8 * 4, /* %eip */
+ 9 * 4, /* %eflags */
+ 10 * 4, /* %cs */
+ 11 * 4, /* %ss */
+ 12 * 4, /* %ds */
+ 13 * 4, /* %es */
+ 14 * 4, /* %fs */
+ 15 * 4 /* %gs */
+};
+
+static void
+i386obsd_aout_supply_regset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *regs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = regset->descr;
+
+ gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
+
+ i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
+ i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
+}
+
+static const struct regset *
+i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* OpenBSD a.out core dumps don't use seperate register sets for the
+ general-purpose and floating-point registers. */
+
+ if (strcmp (sect_name, ".reg") == 0
+ && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
+ {
+ if (tdep->gregset == NULL)
+ {
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = tdep;
+ tdep->gregset->supply_regset = i386obsd_aout_supply_regset;
+ }
+ return tdep->gregset;
+ }
+
+ return NULL;
+}
+
+
+/* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
+CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
+CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
+
+/* From <machine/signal.h>. */
+int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
+{
+ 10 * 4, /* %eax */
+ 9 * 4, /* %ecx */
+ 8 * 4, /* %edx */
+ 7 * 4, /* %ebx */
+ 14 * 4, /* %esp */
+ 6 * 4, /* %ebp */
+ 5 * 4, /* %esi */
+ 4 * 4, /* %edi */
+ 11 * 4, /* %eip */
+ 13 * 4, /* %eflags */
+ 12 * 4, /* %cs */
+ 15 * 4, /* %ss */
+ 3 * 4, /* %ds */
+ 2 * 4, /* %es */
+ 1 * 4, /* %fs */
+ 0 * 4 /* %gs */
+};
+
+static void
+i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Obviously OpenBSD is BSD-based. */
+ i386bsd_init_abi (info, gdbarch);
+
+ /* OpenBSD has a different `struct reg'. */
+ tdep->gregset_reg_offset = i386obsd_r_reg_offset;
+ tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
+ tdep->sizeof_gregset = 16 * 4;
+
+ /* OpenBSD uses -freg-struct-return by default. */
+ tdep->struct_return = reg_struct_return;
+
+ /* OpenBSD uses a different memory layout. */
+ tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
+ tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386obsd_pc_in_sigtramp);
+ set_gdbarch_sigtramp_start (gdbarch, i386obsd_sigtramp_start);
+ set_gdbarch_sigtramp_end (gdbarch, i386obsd_sigtramp_end);
+
+ /* OpenBSD has a `struct sigcontext' that's different from the
+ origional 4.3 BSD. */
+ tdep->sc_reg_offset = i386obsd_sc_reg_offset;
+ tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
+}
+
+/* OpenBSD a.out. */
+
+static void
+i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ i386obsd_init_abi (info, gdbarch);
+
+ /* OpenBSD a.out has a single register set. */
+ set_gdbarch_regset_from_core_section
+ (gdbarch, i386obsd_aout_regset_from_core_section);
+}
+
+/* OpenBSD ELF. */
+
+static void
+i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* It's still OpenBSD. */
+ i386obsd_init_abi (info, gdbarch);
+
+ /* But ELF-based. */
+ i386_elf_init_abi (info, gdbarch);
+
+ /* OpenBSD ELF uses SVR4-style shared libraries. */
+ set_gdbarch_in_solib_call_trampoline
+ (gdbarch, generic_in_solib_call_trampoline);
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386obsd_tdep (void);
+
+void
+_initialize_i386obsd_tdep (void)
+{
+ /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
+ indistingushable from NetBSD/i386 a.out binaries, building a GDB
+ that should support both these targets will probably not work as
+ expected. */
+#define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
+
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
+ i386obsd_aout_init_abi);
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
+ i386obsd_elf_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386v-nat.c b/contrib/gdb/gdb/i386v-nat.c
new file mode 100644
index 0000000..678eabc
--- /dev/null
+++ b/contrib/gdb/gdb/i386v-nat.c
@@ -0,0 +1,277 @@
+/* Intel 386 native support for System V systems (pre-SVR4).
+
+ Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_PTRACE_H
+#include <ptrace.h>
+#else
+#ifdef HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+#endif
+
+#include "frame.h"
+#include "inferior.h"
+#include "language.h"
+#include "gdbcore.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
+#include <sys/debugreg.h>
+#endif
+
+#include <sys/file.h>
+#include "gdb_stat.h"
+
+#ifdef HAVE_SYS_REG_H
+#include <sys/reg.h>
+#endif
+
+#include "floatformat.h"
+
+#include "target.h"
+
+#include "i386-tdep.h"
+
+
+/* Mapping between the general-purpose registers in `struct user'
+ format and GDB's register array layout. */
+static int regmap[] =
+{
+ EAX, ECX, EDX, EBX,
+ UESP, EBP, ESI, EDI,
+ EIP, EFL, CS, SS,
+ DS, ES, FS, GS,
+};
+
+/* Support for the user struct. */
+
+/* Return the address of register REGNUM. BLOCKEND is the value of
+ u.u_ar0, and points to the place where GS is stored. */
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regnum)
+{
+ struct user u;
+ CORE_ADDR fpstate;
+
+ if (i386_fp_regnum_p (regnum))
+ {
+#ifdef KSTKSZ /* SCO, and others? */
+ blockend += 4 * (SS + 1) - KSTKSZ;
+ fpstate = blockend + ((char *) &u.u_fps.u_fpstate - (char *) &u);
+ return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
+#else
+ fpstate = blockend + ((char *) &u.i387.st_space - (char *) &u);
+ return (fpstate + 10 * (regnum - FP0_REGNUM));
+#endif
+ }
+
+ return (blockend + 4 * regmap[regnum]);
+}
+
+/* Return the size of the user struct. */
+
+int
+kernel_u_size (void)
+{
+ 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 (int, CORE_ADDR, CORE_ADDR, int,
+ int);
+
+static int i386_insert_nonaligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
+ int);
+
+/* Insert a watchpoint. */
+
+int
+i386_insert_watchpoint (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 (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 : DR_RW_WRITE;
+
+ 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 (int pid, CORE_ADDR waddr, CORE_ADDR addr,
+ int len, int rw)
+{
+ int align;
+ int size;
+ int rv;
+
+ static int size_try_array[4][4] =
+ {
+ { 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 = size_try_array[len > 4 ? 3 : len - 1][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 (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 (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 */
diff --git a/contrib/gdb/gdb/i386v4-nat.c b/contrib/gdb/gdb/i386v4-nat.c
new file mode 100644
index 0000000..188f01b
--- /dev/null
+++ b/contrib/gdb/gdb/i386v4-nat.c
@@ -0,0 +1,160 @@
+/* Native-dependent code for SVR4 Unix running on i386's.
+ Copyright 1988, 1989, 1991, 1992, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "inferior.h"
+#include "regcache.h"
+
+#ifdef HAVE_SYS_REG_H
+#include <sys/reg.h>
+#endif
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+
+#ifdef HAVE_SYS_PROCFS_H
+
+#include <sys/procfs.h>
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* The `/proc' interface divides the target machine's register set up
+ into two different sets, the general purpose 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-purpose
+ register set is typically defined by:
+
+ typedef int gregset_t[19]; (in <sys/regset.h>)
+
+ #define GS 0 (in <sys/reg.h>)
+ #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;
+
+ Incidentally fpchip_state contains the FPU state in the same format
+ as used by the "fsave" instruction, and that's the only thing we
+ support here. I don't know how the emulator stores it state. The
+ Weitek stuff definitely isn't supported.
+
+ The routines defined here, provide the packing and unpacking of
+ gregset_t and fpregset_t formatted data. */
+
+#ifdef HAVE_GREGSET_T
+
+/* Mapping between the general-purpose registers in `/proc'
+ format and GDB's register array layout. */
+static int regmap[] =
+{
+ EAX, ECX, EDX, EBX,
+ UESP, EBP, ESI, EDI,
+ EIP, EFL, CS, SS,
+ DS, ES, FS, GS,
+};
+
+/* Fill GDB's register array with the general-purpose register values
+ in *GREGSETP. */
+
+void
+supply_gregset (gregset_t *gregsetp)
+{
+ greg_t *regp = (greg_t *) gregsetp;
+ int i;
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ supply_register (i, (char *) (regp + regmap[i]));
+}
+
+/* Fill register REGNO (if it is a general-purpose register) in
+ *GREGSETPS with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_gregset (gregset_t *gregsetp, int regno)
+{
+ greg_t *regp = (greg_t *) gregsetp;
+ int i;
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ if (regno == -1 || regno == i)
+ regcache_collect (i, regp + regmap[i]);
+}
+
+#endif /* HAVE_GREGSET_T */
+
+#ifdef HAVE_FPREGSET_T
+
+/* Fill GDB's register array with the floating-point register values in
+ *FPREGSETP. */
+
+void
+supply_fpregset (fpregset_t *fpregsetp)
+{
+ if (FP0_REGNUM == 0)
+ return;
+
+ i387_supply_fsave (current_regcache, -1, fpregsetp);
+}
+
+/* Fill register REGNO (if it is a floating-point register) in
+ *FPREGSETP with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_fpregset (fpregset_t *fpregsetp, int regno)
+{
+ if (FP0_REGNUM == 0)
+ return;
+
+ i387_fill_fsave ((char *) fpregsetp, regno);
+}
+
+#endif /* 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 0000000..21386fb
--- /dev/null
+++ b/contrib/gdb/gdb/i387-tdep.c
@@ -0,0 +1,774 @@
+/* Intel 387 floating point stuff.
+
+ Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "doublest.h"
+#include "floatformat.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "language.h"
+#include "regcache.h"
+#include "value.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+
+/* Implement the `info float' layout based on the register definitions
+ in `tm-i386.h'. */
+
+/* Print the floating point number specified by RAW. */
+
+static void
+print_i387_value (char *raw, struct ui_file *file)
+{
+ DOUBLEST value;
+
+ /* Using extract_typed_floating here might affect the representation
+ of certain numbers such as NaNs, even if GDB is running natively.
+ This is fine since our caller already detects such special
+ numbers and we print the hexadecimal representation anyway. */
+ value = extract_typed_floating (raw, builtin_type_i387_ext);
+
+ /* We try to print 19 digits. The last digit may or may not contain
+ garbage, but we'd better print one too many. We need enough room
+ to print the value, 1 position for the sign, 1 for the decimal
+ point, 19 for the digits and 6 for the exponent adds up to 27. */
+#ifdef PRINTF_HAS_LONG_DOUBLE
+ fprintf_filtered (file, " %-+27.19Lg", (long double) value);
+#else
+ fprintf_filtered (file, " %-+27.19g", (double) value);
+#endif
+}
+
+/* Print the classification for the register contents RAW. */
+
+static void
+print_i387_ext (unsigned char *raw, struct ui_file *file)
+{
+ int sign;
+ int integer;
+ unsigned int exponent;
+ unsigned long fraction[2];
+
+ sign = raw[9] & 0x80;
+ integer = raw[7] & 0x80;
+ exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
+ fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
+ fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
+ | (raw[5] << 8) | raw[4]);
+
+ if (exponent == 0x7fff && integer)
+ {
+ if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
+ /* Infinity. */
+ fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
+ else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
+ /* Real Indefinite (QNaN). */
+ fputs_unfiltered (" Real Indefinite (QNaN)", file);
+ else if (fraction[1] & 0x40000000)
+ /* QNaN. */
+ fputs_filtered (" QNaN", file);
+ else
+ /* SNaN. */
+ fputs_filtered (" SNaN", file);
+ }
+ else if (exponent < 0x7fff && exponent > 0x0000 && integer)
+ /* Normal. */
+ print_i387_value (raw, file);
+ else if (exponent == 0x0000)
+ {
+ /* Denormal or zero. */
+ print_i387_value (raw, file);
+
+ if (integer)
+ /* Pseudo-denormal. */
+ fputs_filtered (" Pseudo-denormal", file);
+ else if (fraction[0] || fraction[1])
+ /* Denormal. */
+ fputs_filtered (" Denormal", file);
+ }
+ else
+ /* Unsupported. */
+ fputs_filtered (" Unsupported", file);
+}
+
+/* Print the status word STATUS. */
+
+static void
+print_i387_status_word (unsigned int status, struct ui_file *file)
+{
+ fprintf_filtered (file, "Status Word: %s",
+ local_hex_string_custom (status, "04"));
+ fputs_filtered (" ", file);
+ fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : " ");
+ fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : " ");
+ fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : " ");
+ fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : " ");
+ fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : " ");
+ fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : " ");
+ fputs_filtered (" ", file);
+ fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : " ");
+ fputs_filtered (" ", file);
+ fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : " ");
+ fputs_filtered (" ", file);
+ fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : " ");
+ fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : " ");
+ fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : " ");
+ fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : " ");
+
+ fputs_filtered ("\n", file);
+
+ fprintf_filtered (file,
+ " TOP: %d\n", ((status >> 11) & 7));
+}
+
+/* Print the control word CONTROL. */
+
+static void
+print_i387_control_word (unsigned int control, struct ui_file *file)
+{
+ fprintf_filtered (file, "Control Word: %s",
+ local_hex_string_custom (control, "04"));
+ fputs_filtered (" ", file);
+ fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : " ");
+ fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : " ");
+ fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : " ");
+ fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : " ");
+ fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : " ");
+ fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : " ");
+
+ fputs_filtered ("\n", file);
+
+ fputs_filtered (" PC: ", file);
+ switch ((control >> 8) & 3)
+ {
+ case 0:
+ fputs_filtered ("Single Precision (24-bits)\n", file);
+ break;
+ case 1:
+ fputs_filtered ("Reserved\n", file);
+ break;
+ case 2:
+ fputs_filtered ("Double Precision (53-bits)\n", file);
+ break;
+ case 3:
+ fputs_filtered ("Extended Precision (64-bits)\n", file);
+ break;
+ }
+
+ fputs_filtered (" RC: ", file);
+ switch ((control >> 10) & 3)
+ {
+ case 0:
+ fputs_filtered ("Round to nearest\n", file);
+ break;
+ case 1:
+ fputs_filtered ("Round down\n", file);
+ break;
+ case 2:
+ fputs_filtered ("Round up\n", file);
+ break;
+ case 3:
+ fputs_filtered ("Round toward zero\n", file);
+ break;
+ }
+}
+
+/* Print out the i387 floating point state. Note that we ignore FRAME
+ in the code below. That's OK since floating-point registers are
+ never saved on the stack. */
+
+void
+i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, const char *args)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
+ char buf[4];
+ ULONGEST fctrl;
+ ULONGEST fstat;
+ ULONGEST ftag;
+ ULONGEST fiseg;
+ ULONGEST fioff;
+ ULONGEST foseg;
+ ULONGEST fooff;
+ ULONGEST fop;
+ int fpreg;
+ int top;
+
+ gdb_assert (gdbarch == get_frame_arch (frame));
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for FRAME's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ fctrl = get_frame_register_unsigned (frame, I387_FCTRL_REGNUM);
+ fstat = get_frame_register_unsigned (frame, I387_FSTAT_REGNUM);
+ ftag = get_frame_register_unsigned (frame, I387_FTAG_REGNUM);
+ fiseg = get_frame_register_unsigned (frame, I387_FISEG_REGNUM);
+ fioff = get_frame_register_unsigned (frame, I387_FIOFF_REGNUM);
+ foseg = get_frame_register_unsigned (frame, I387_FOSEG_REGNUM);
+ fooff = get_frame_register_unsigned (frame, I387_FOOFF_REGNUM);
+ fop = get_frame_register_unsigned (frame, I387_FOP_REGNUM);
+
+ top = ((fstat >> 11) & 7);
+
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ unsigned char raw[I386_MAX_REGISTER_SIZE];
+ int tag = (ftag >> (fpreg * 2)) & 3;
+ int i;
+
+ fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : " ", fpreg);
+
+ switch (tag)
+ {
+ case 0:
+ fputs_filtered ("Valid ", file);
+ break;
+ case 1:
+ fputs_filtered ("Zero ", file);
+ break;
+ case 2:
+ fputs_filtered ("Special ", file);
+ break;
+ case 3:
+ fputs_filtered ("Empty ", file);
+ break;
+ }
+
+ get_frame_register (frame, (fpreg + 8 - top) % 8 + I387_ST0_REGNUM, raw);
+
+ fputs_filtered ("0x", file);
+ for (i = 9; i >= 0; i--)
+ fprintf_filtered (file, "%02x", raw[i]);
+
+ if (tag != 3)
+ print_i387_ext (raw, file);
+
+ fputs_filtered ("\n", file);
+ }
+
+ fputs_filtered ("\n", file);
+
+ print_i387_status_word (fstat, file);
+ print_i387_control_word (fctrl, file);
+ fprintf_filtered (file, "Tag Word: %s\n",
+ local_hex_string_custom (ftag, "04"));
+ fprintf_filtered (file, "Instruction Pointer: %s:",
+ local_hex_string_custom (fiseg, "02"));
+ fprintf_filtered (file, "%s\n", local_hex_string_custom (fioff, "08"));
+ fprintf_filtered (file, "Operand Pointer: %s:",
+ local_hex_string_custom (foseg, "02"));
+ fprintf_filtered (file, "%s\n", local_hex_string_custom (fooff, "08"));
+ fprintf_filtered (file, "Opcode: %s\n",
+ local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04"));
+
+#undef I387_ST0_REGNUM
+}
+
+
+/* Read a value of type TYPE from register REGNUM in frame FRAME, and
+ return its contents in TO. */
+
+void
+i387_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, void *to)
+{
+ char from[I386_MAX_REGISTER_SIZE];
+
+ gdb_assert (i386_fp_regnum_p (regnum));
+
+ /* We only support floating-point values. */
+ if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ {
+ warning ("Cannot convert floating-point register value "
+ "to non-floating-point type.");
+ return;
+ }
+
+ /* Convert to TYPE. This should be a no-op if TYPE is equivalent to
+ the extended floating-point format used by the FPU. */
+ get_frame_register (frame, regnum, from);
+ convert_typed_floating (from, builtin_type_i387_ext, to, type);
+}
+
+/* Write the contents FROM of a value of type TYPE into register
+ REGNUM in frame FRAME. */
+
+void
+i387_value_to_register (struct frame_info *frame, int regnum,
+ struct type *type, const void *from)
+{
+ char to[I386_MAX_REGISTER_SIZE];
+
+ gdb_assert (i386_fp_regnum_p (regnum));
+
+ /* We only support floating-point values. */
+ if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ {
+ warning ("Cannot convert non-floating-point type "
+ "to floating-point register value.");
+ return;
+ }
+
+ /* Convert from TYPE. This should be a no-op if TYPE is equivalent
+ to the extended floating-point format used by the FPU. */
+ convert_typed_floating (from, type, to, builtin_type_i387_ext);
+ put_frame_register (frame, regnum, to);
+}
+
+
+
+/* Handle FSAVE and FXSAVE formats. */
+
+/* FIXME: kettenis/20030927: The functions below should accept a
+ `regcache' argument, but I don't want to change the function
+ signature just yet. There's some band-aid in the functions below
+ in the form of the `regcache' local variables. This will ease the
+ transition later on. */
+
+/* At fsave_offset[REGNUM] you'll find the offset to the location in
+ the data structure used by the "fsave" instruction where GDB
+ register REGNUM is stored. */
+
+static int fsave_offset[] =
+{
+ 28 + 0 * 10, /* %st(0) ... */
+ 28 + 1 * 10,
+ 28 + 2 * 10,
+ 28 + 3 * 10,
+ 28 + 4 * 10,
+ 28 + 5 * 10,
+ 28 + 6 * 10,
+ 28 + 7 * 10, /* ... %st(7). */
+ 0, /* `fctrl' (16 bits). */
+ 4, /* `fstat' (16 bits). */
+ 8, /* `ftag' (16 bits). */
+ 16, /* `fiseg' (16 bits). */
+ 12, /* `fioff'. */
+ 24, /* `foseg' (16 bits). */
+ 20, /* `fooff'. */
+ 18 /* `fop' (bottom 11 bits). */
+};
+
+#define FSAVE_ADDR(fsave, regnum) \
+ (fsave + fsave_offset[regnum - I387_ST0_REGNUM])
+
+
+/* Fill register REGNUM in REGCACHE with the appropriate value from
+ *FSAVE. This function masks off any of the reserved bits in
+ *FSAVE. */
+
+void
+i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ const char *regs = fsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
+ if (regnum == -1 || regnum == i)
+ {
+ if (fsave == NULL)
+ {
+ regcache_raw_supply (regcache, i, NULL);
+ continue;
+ }
+
+ /* Most of the FPU control registers occupy only 16 bits in the
+ fsave area. Give those a special treatment. */
+ if (i >= I387_FCTRL_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
+ {
+ unsigned char val[4];
+
+ memcpy (val, FSAVE_ADDR (regs, i), 2);
+ val[2] = val[3] = 0;
+ if (i == I387_FOP_REGNUM)
+ val[1] &= ((1 << 3) - 1);
+ regcache_raw_supply (regcache, i, val);
+ }
+ else
+ regcache_raw_supply (regcache, i, FSAVE_ADDR (regs, i));
+ }
+#undef I387_ST0_REGNUM
+}
+
+/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
+ with the value in GDB's register cache. If REGNUM is -1, do this
+ for all registers. This function doesn't touch any of the reserved
+ bits in *FSAVE. */
+
+void
+i387_fill_fsave (void *fsave, int regnum)
+{
+ struct regcache *regcache = current_regcache;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ char *regs = fsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
+ if (regnum == -1 || regnum == i)
+ {
+ /* Most of the FPU control registers occupy only 16 bits in
+ the fsave area. Give those a special treatment. */
+ if (i >= I387_FCTRL_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
+ {
+ unsigned char buf[4];
+
+ regcache_raw_collect (regcache, i, buf);
+
+ if (i == I387_FOP_REGNUM)
+ {
+ /* The opcode occupies only 11 bits. Make sure we
+ don't touch the other bits. */
+ buf[1] &= ((1 << 3) - 1);
+ buf[1] |= ((FSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
+ }
+ memcpy (FSAVE_ADDR (regs, i), buf, 2);
+ }
+ else
+ regcache_raw_collect (regcache, i, FSAVE_ADDR (regs, i));
+ }
+#undef I387_ST0_REGNUM
+}
+
+
+/* At fxsave_offset[REGNUM] you'll find the offset to the location in
+ the data structure used by the "fxsave" instruction where GDB
+ register REGNUM is stored. */
+
+static int fxsave_offset[] =
+{
+ 32, /* %st(0) through ... */
+ 48,
+ 64,
+ 80,
+ 96,
+ 112,
+ 128,
+ 144, /* ... %st(7) (80 bits each). */
+ 0, /* `fctrl' (16 bits). */
+ 2, /* `fstat' (16 bits). */
+ 4, /* `ftag' (16 bits). */
+ 12, /* `fiseg' (16 bits). */
+ 8, /* `fioff'. */
+ 20, /* `foseg' (16 bits). */
+ 16, /* `fooff'. */
+ 6, /* `fop' (bottom 11 bits). */
+ 160 + 0 * 16, /* %xmm0 through ... */
+ 160 + 1 * 16,
+ 160 + 2 * 16,
+ 160 + 3 * 16,
+ 160 + 4 * 16,
+ 160 + 5 * 16,
+ 160 + 6 * 16,
+ 160 + 7 * 16,
+ 160 + 8 * 16,
+ 160 + 9 * 16,
+ 160 + 10 * 16,
+ 160 + 11 * 16,
+ 160 + 12 * 16,
+ 160 + 13 * 16,
+ 160 + 14 * 16,
+ 160 + 15 * 16, /* ... %xmm15 (128 bits each). */
+};
+
+#define FXSAVE_ADDR(fxsave, regnum) \
+ (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM])
+
+/* We made an unfortunate choice in putting %mxcsr after the SSE
+ registers %xmm0-%xmm7 instead of before, since it makes supporting
+ the registers %xmm8-%xmm15 on AMD64 a bit involved. Therefore we
+ don't include the offset for %mxcsr here above. */
+
+#define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24)
+
+static int i387_tag (const unsigned char *raw);
+
+
+/* Fill register REGNUM in REGCACHE with the appropriate
+ floating-point or SSE register value from *FXSAVE. This function
+ masks off any of the reserved bits in *FXSAVE. */
+
+void
+i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ const char *regs = fxsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+ gdb_assert (tdep->num_xmm_regs > 0);
+
+ /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
+ proper definitions for REGCACHE's architecture. */
+
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
+ if (regnum == -1 || regnum == i)
+ {
+ if (regs == NULL)
+ {
+ regcache_raw_supply (regcache, i, NULL);
+ continue;
+ }
+
+ /* Most of the FPU control registers occupy only 16 bits in
+ the fxsave area. Give those a special treatment. */
+ if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
+ {
+ unsigned char val[4];
+
+ memcpy (val, FXSAVE_ADDR (regs, i), 2);
+ val[2] = val[3] = 0;
+ if (i == I387_FOP_REGNUM)
+ val[1] &= ((1 << 3) - 1);
+ else if (i== I387_FTAG_REGNUM)
+ {
+ /* The fxsave area contains a simplified version of
+ the tag word. We have to look at the actual 80-bit
+ FP data to recreate the traditional i387 tag word. */
+
+ unsigned long ftag = 0;
+ int fpreg;
+ int top;
+
+ top = ((FXSAVE_ADDR (regs, I387_FSTAT_REGNUM))[1] >> 3);
+ top &= 0x7;
+
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int tag;
+
+ if (val[0] & (1 << fpreg))
+ {
+ int regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM;
+ tag = i387_tag (FXSAVE_ADDR (regs, regnum));
+ }
+ else
+ tag = 3; /* Empty */
+
+ ftag |= tag << (2 * fpreg);
+ }
+ val[0] = ftag & 0xff;
+ val[1] = (ftag >> 8) & 0xff;
+ }
+ regcache_raw_supply (regcache, i, val);
+ }
+ else
+ regcache_raw_supply (regcache, i, FXSAVE_ADDR (regs, i));
+ }
+
+ if (regnum == I387_MXCSR_REGNUM || regnum == -1)
+ {
+ if (regs == NULL)
+ regcache_raw_supply (regcache, I387_MXCSR_REGNUM, NULL);
+ else
+ regcache_raw_supply (regcache, I387_MXCSR_REGNUM,
+ FXSAVE_MXCSR_ADDR (regs));
+ }
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
+ all registers. This function doesn't touch any of the reserved
+ bits in *FXSAVE. */
+
+void
+i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ char *regs = fxsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+ gdb_assert (tdep->num_xmm_regs > 0);
+
+ /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
+ proper definitions for REGCACHE's architecture. */
+
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
+ if (regnum == -1 || regnum == i)
+ {
+ /* Most of the FPU control registers occupy only 16 bits in
+ the fxsave area. Give those a special treatment. */
+ if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
+ {
+ unsigned char buf[4];
+
+ regcache_raw_collect (regcache, i, buf);
+
+ if (i == I387_FOP_REGNUM)
+ {
+ /* The opcode occupies only 11 bits. Make sure we
+ don't touch the other bits. */
+ buf[1] &= ((1 << 3) - 1);
+ buf[1] |= ((FXSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
+ }
+ else if (i == I387_FTAG_REGNUM)
+ {
+ /* Converting back is much easier. */
+
+ unsigned short ftag;
+ int fpreg;
+
+ ftag = (buf[1] << 8) | buf[0];
+ buf[0] = 0;
+ buf[1] = 0;
+
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int tag = (ftag >> (fpreg * 2)) & 3;
+
+ if (tag != 3)
+ buf[0] |= (1 << fpreg);
+ }
+ }
+ memcpy (FXSAVE_ADDR (regs, i), buf, 2);
+ }
+ else
+ regcache_raw_collect (regcache, i, FXSAVE_ADDR (regs, i));
+ }
+
+ if (regnum == I387_MXCSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, I387_MXCSR_REGNUM,
+ FXSAVE_MXCSR_ADDR (regs));
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
+ this for all registers. This function doesn't touch any of the
+ reserved bits in *FXSAVE. */
+
+void
+i387_fill_fxsave (void *fxsave, int regnum)
+{
+ i387_collect_fxsave (current_regcache, regnum, fxsave);
+}
+
+/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
+ *RAW. */
+
+static int
+i387_tag (const unsigned char *raw)
+{
+ int integer;
+ unsigned int exponent;
+ unsigned long fraction[2];
+
+ integer = raw[7] & 0x80;
+ exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
+ fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
+ fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
+ | (raw[5] << 8) | raw[4]);
+
+ if (exponent == 0x7fff)
+ {
+ /* Special. */
+ return (2);
+ }
+ else if (exponent == 0x0000)
+ {
+ if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
+ {
+ /* Zero. */
+ return (1);
+ }
+ else
+ {
+ /* Special. */
+ return (2);
+ }
+ }
+ else
+ {
+ if (integer)
+ {
+ /* Valid. */
+ return (0);
+ }
+ else
+ {
+ /* Special. */
+ return (2);
+ }
+ }
+}
+
+/* Prepare the FPU stack in REGCACHE for a function return. */
+
+void
+i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ULONGEST fstat;
+
+ /* Define I387_ST0_REGNUM such that we use the proper
+ definitions for the architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ /* Set the top of the floating-point register stack to 7. The
+ actual value doesn't really matter, but 7 is what a normal
+ function return would end up with if the program started out with
+ a freshly initialized FPU. */
+ regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
+ fstat |= (7 << 11);
+ regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
+
+ /* Mark %st(1) through %st(7) as empty. Since we set the top of the
+ floating-point register stack to 7, the appropriate value for the
+ tag word is 0x3fff. */
+ regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
+
+#undef I387_ST0_REGNUM
+}
diff --git a/contrib/gdb/gdb/i387-tdep.h b/contrib/gdb/gdb/i387-tdep.h
new file mode 100644
index 0000000..978fdf9
--- /dev/null
+++ b/contrib/gdb/gdb/i387-tdep.h
@@ -0,0 +1,118 @@
+/* Target-dependent code for the i387.
+
+ Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 I387_TDEP_H
+#define I387_TDEP_H
+
+struct gdbarch;
+struct frame_info;
+struct regcache;
+struct type;
+struct ui_file;
+
+/* Because the number of general-purpose registers is different for
+ AMD64, the floating-point registers and SSE registers get shifted.
+ The following definitions are intended to help writing code that
+ needs the register numbers of floating-point registers and SSE
+ registers. In order to use these, one should provide a definition
+ for I387_ST0_REGNUM, and possibly I387_NUM_XMM_REGS, preferably by
+ using a local "#define" in the body of the function that uses this.
+ Please "#undef" them before the end of the function. */
+
+#define I387_FCTRL_REGNUM (I387_ST0_REGNUM + 8)
+#define I387_FSTAT_REGNUM (I387_FCTRL_REGNUM + 1)
+#define I387_FTAG_REGNUM (I387_FCTRL_REGNUM + 2)
+#define I387_FISEG_REGNUM (I387_FCTRL_REGNUM + 3)
+#define I387_FIOFF_REGNUM (I387_FCTRL_REGNUM + 4)
+#define I387_FOSEG_REGNUM (I387_FCTRL_REGNUM + 5)
+#define I387_FOOFF_REGNUM (I387_FCTRL_REGNUM + 6)
+#define I387_FOP_REGNUM (I387_FCTRL_REGNUM + 7)
+#define I387_XMM0_REGNUM (I387_ST0_REGNUM + 16)
+#define I387_MXCSR_REGNUM (I387_XMM0_REGNUM + I387_NUM_XMM_REGS)
+
+
+/* Print out the i387 floating point state. */
+
+extern void i387_print_float_info (struct gdbarch *gdbarch,
+ struct ui_file *file,
+ struct frame_info *frame,
+ const char *args);
+
+/* Read a value of type TYPE from register REGNUM in frame FRAME, and
+ return its contents in TO. */
+
+extern void i387_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, void *to);
+
+/* Write the contents FROM of a value of type TYPE into register
+ REGNUM in frame FRAME. */
+
+extern void i387_value_to_register (struct frame_info *frame, int regnum,
+ struct type *type, const void *from);
+
+
+/* Size of the memory area use by the 'fsave' and 'fxsave'
+ instructions. */
+#define I387_SIZEOF_FSAVE 108
+#define I387_SIZEOF_FXSAVE 512
+
+/* Fill register REGNUM in REGCACHE with the appropriate value from
+ *FSAVE. This function masks off any of the reserved bits in
+ *FSAVE. */
+
+extern void i387_supply_fsave (struct regcache *regcache, int regnum,
+ const void *fsave);
+
+/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
+ with the value in GDB's register cache. If REGNUM is -1, do this
+ for all registers. This function doesn't touch any of the reserved
+ bits in *FSAVE. */
+
+extern void i387_fill_fsave (void *fsave, int regnum);
+
+/* Fill register REGNUM in REGCACHE with the appropriate
+ floating-point or SSE register value from *FXSAVE. This function
+ masks off any of the reserved bits in *FXSAVE. */
+
+extern void i387_supply_fxsave (struct regcache *regcache, int regnum,
+ const void *fxsave);
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
+ all registers. This function doesn't touch any of the reserved
+ bits in *FXSAVE. */
+
+extern void i387_collect_fxsave (const struct regcache *regcache, int regnum,
+ void *fxsave);
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+ *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
+ this for all registers. This function doesn't touch any of the
+ reserved bits in *FXSAVE. */
+
+extern void i387_fill_fxsave (void *fxsave, int regnum);
+
+/* Prepare the FPU stack in REGCACHE for a function return. */
+
+extern void i387_return_value (struct gdbarch *gdbarch,
+ struct regcache *regcache);
+
+#endif /* i387-tdep.h */
diff --git a/contrib/gdb/gdb/ia64-fbsd-nat.c b/contrib/gdb/gdb/ia64-fbsd-nat.c
new file mode 100644
index 0000000..c201864
--- /dev/null
+++ b/contrib/gdb/gdb/ia64-fbsd-nat.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "defs.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#ifdef HAVE_SYS_PROCFS_H
+#include <sys/procfs.h>
+#endif
+
+#ifndef HAVE_GREGSET_T
+typedef struct reg gregset_t;
+#endif
+
+#ifndef HAVE_FPREGSET_T
+typedef struct fpreg fpregset_t;
+#endif
+
+#include "gregset.h"
+
+#define FPREG_SUPPLIES(r) ((r) >= IA64_FR0_REGNUM && (r) <= IA64_FR127_REGNUM)
+#define GREG_SUPPLIES(r) (!FPREG_SUPPLIES(r))
+
+void
+fetch_inferior_registers (int regno)
+{
+ union {
+ fpregset_t fpr;
+ gregset_t r;
+ } regs;
+
+ if (regno == -1 || GREG_SUPPLIES(regno))
+ {
+ if (ptrace (PT_GETREGS, PIDGET(inferior_ptid),
+ (PTRACE_ARG3_TYPE)&regs.r, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+ supply_gregset (&regs.r);
+ }
+
+ if (regno == -1 || FPREG_SUPPLIES(regno))
+ {
+ if (ptrace (PT_GETFPREGS, PIDGET(inferior_ptid),
+ (PTRACE_ARG3_TYPE)&regs.fpr, 0) == -1)
+ perror_with_name ("Couldn't get FP registers");
+ supply_fpregset (&regs.fpr);
+ }
+}
+
+void
+store_inferior_registers (int regno)
+{
+ union {
+ fpregset_t fpr;
+ gregset_t r;
+ } regs;
+
+ if (regno == -1 || GREG_SUPPLIES(regno))
+ {
+ if (ptrace (PT_GETREGS, PIDGET(inferior_ptid),
+ (PTRACE_ARG3_TYPE)&regs.r, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+ fill_gregset (&regs.r, regno);
+ if (ptrace (PT_SETREGS, PIDGET(inferior_ptid),
+ (PTRACE_ARG3_TYPE)&regs.r, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || FPREG_SUPPLIES(regno))
+ {
+ if (ptrace (PT_GETFPREGS, PIDGET(inferior_ptid),
+ (PTRACE_ARG3_TYPE)&regs.fpr, 0) == -1)
+ perror_with_name ("Couldn't get FP registers");
+ fill_fpregset (&regs.fpr, regno);
+ if (ptrace (PT_SETFPREGS, PIDGET(inferior_ptid),
+ (PTRACE_ARG3_TYPE)&regs.fpr, 0) == -1)
+ perror_with_name ("Couldn't get FP registers");
+ if (regno != -1)
+ return;
+ }
+}
+
+LONGEST ia64_fbsd_xfer_dirty (struct target_ops *ops, enum target_object obj,
+ const char *annex, void *rbuf, const void *wbuf,
+ ULONGEST ofs, LONGEST len)
+{
+ if (len != 8)
+ return (-1);
+ if (rbuf != NULL) {
+ if (ptrace (PT_GETKSTACK, PIDGET(inferior_ptid), (PTRACE_ARG3_TYPE)rbuf,
+ ofs >> 3) == -1) {
+ perror_with_name ("Couldn't read dirty register");
+ return (-1);
+ }
+ } else {
+ if (ptrace (PT_SETKSTACK, PIDGET(inferior_ptid), (PTRACE_ARG3_TYPE)wbuf,
+ ofs >> 3) == -1) {
+ perror_with_name ("Couldn't write dirty register");
+ return (-1);
+ }
+ }
+ return (len);
+}
+
+void
+_initialize_ia64_fbsd_nat (void)
+{
+}
diff --git a/contrib/gdb/gdb/ia64-fbsd-tdep.c b/contrib/gdb/gdb/ia64-fbsd-tdep.c
new file mode 100644
index 0000000..4bf8918
--- /dev/null
+++ b/contrib/gdb/gdb/ia64-fbsd-tdep.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "defs.h"
+#include "gdb_string.h"
+#include "regcache.h"
+#include "regset.h"
+#include "solib-svr4.h"
+#include "value.h"
+
+#include "ia64-tdep.h"
+
+#define FPREG_SUPPLIES(r) ((r) >= IA64_FR0_REGNUM && (r) <= IA64_FR127_REGNUM)
+#define GREG_SUPPLIES(r) (!FPREG_SUPPLIES(r))
+
+static int reg_offset[462] = {
+ -1, 96, 248, 256, 152, 160, 168, 176, /* Regs 0-7. */
+ 264, 272, 280, 288, 0, 64, 296, 304, /* Regs 8-15. */
+ 312, 320, 328, 336, 344, 352, 360, 368, /* Regs 16-23. */
+ 376, 384, 392, 400, 408, 416, 424, 432, /* Regs 24-31. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 32-39. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 40-47. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 48-55. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 56-63. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 64-71. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 72-79. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 80-87. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 88-95. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 96-103. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 104-111. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 112-119. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 120-127. */
+ -1, -1, 0, 16, 32, 48, 320, 336, /* Regs 128-135. */
+ 352, 368, 384, 400, 416, 432, 448, 464, /* Regs 136-143. */
+ 64, 80, 96, 112, 128, 144, 160, 176, /* Regs 144-151. */
+ 192, 208, 224, 240, 256, 272, 288, 304, /* Regs 152-159. */
+ 480, 496, 512, 528, 544, 560, 576, 592, /* Regs 160-167. */
+ 608, 624, 640, 656, 672, 688, 704, 720, /* Regs 168-175. */
+ 736, 752, 768, 784, 800, 816, 832, 848, /* Regs 176-183. */
+ 864, 880, 896, 912, 928, 944, 960, 976, /* Regs 184-191. */
+ 992, 1008, 1024, 1040, 1056, 1072, 1088, 1104, /* Regs 192-199. */
+ 1120, 1136, 1152, 1168, 1184, 1200, 1216, 1232, /* Regs 200-207. */
+ 1248, 1264, 1280, 1296, 1312, 1328, 1344, 1360, /* Regs 208-215. */
+ 1376, 1392, 1408, 1424, 1440, 1456, 1472, 1488, /* Regs 216-223. */
+ 1504, 1520, 1536, 1552, 1568, 1584, 1600, 1616, /* Regs 224-231. */
+ 1632, 1648, 1664, 1680, 1696, 1712, 1728, 1744, /* Regs 232-239. */
+ 1760, 1776, 1792, 1808, 1824, 1840, 1856, 1872, /* Regs 240-247. */
+ 1888, 1904, 1920, 1936, 1952, 1968, 1984, 2000, /* Regs 248-255. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 256-263. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 264-271. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 272-279. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 280-287. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 288-295. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 296-303. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 304-311. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 312-319. */
+ 16, 184, 192, 200, 208, 216, 440, 448, /* Regs 320-327. */
+ -1, -1, 24, 120, 88, 112, -1, -1, /* Regs 328-335. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 336-343. */
+ -1, -1, -1, -1, -1, -1, 72, 104, /* Regs 344-351. */
+ 40, 48, -1, -1, -1, -1, -1, 464, /* Regs 352-359. */
+ 472, -1, -1, -1, -1, -1, 456, -1, /* Regs 360-367. */
+ -1, -1, 8, -1, -1, -1, 80, -1, /* Regs 368-375. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 376-383. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 384-391. */
+ -1, -1, -1, -1, -1, -1, 32, 224, /* Regs 392-399. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 400-407. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 408-415. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 416-423. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 424-431. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 432-439. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 440-447. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* Regs 448-455. */
+ -1, -1, -1, -1, -1, -1
+};
+
+static void
+ia64_fbsd_regcache_collect (struct regcache *regcache, int regno,
+ void *regs)
+{
+ int ofs;
+
+ if (regno < 0 || regno >= NUM_REGS)
+ return;
+
+ ofs = reg_offset[regno];
+ if (regno == IA64_BSP_REGNUM)
+ {
+ uint64_t bsp, bspstore;
+ regcache_raw_collect (regcache, regno, &bsp);
+ regcache_raw_collect (regcache, IA64_BSPSTORE_REGNUM, &bspstore);
+ *(uint64_t *)((char *)regs + ofs) = bsp - bspstore;
+ }
+ else
+ {
+ if (ofs >= 0)
+ regcache_raw_collect (regcache, regno, (char*)regs + ofs);
+ }
+}
+
+static void
+ia64_fbsd_regcache_supply (struct regcache *regcache, int regno,
+ const void *regs)
+{
+ int ofs;
+
+ if (regno < 0 || regno >= NUM_REGS)
+ return;
+
+ ofs = reg_offset[regno];
+ if (regno == IA64_BSP_REGNUM)
+ {
+ /* BSP is synthesized. It's not actually present in struct reg,
+ but can be derived from bspstore and ndirty. The offset of
+ IA64_BSP_REGNUM in the reg_offset array above is that of the
+ ndirty field in struct reg. */
+ uint64_t bsp;
+ bsp = *((uint64_t*)((char *)regs + ofs)); /* ndirty */
+ bsp += *((uint64_t*)((char *)regs + reg_offset[IA64_BSPSTORE_REGNUM]));
+ regcache_raw_supply (regcache, regno, &bsp);
+ }
+ else
+ {
+ if (ofs < 0)
+ regcache_raw_supply (regcache, regno, NULL);
+ else
+ regcache_raw_supply (regcache, regno, (char *)regs + ofs);
+ }
+}
+
+void
+fill_fpregset (void *fpregs, int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ if (FPREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_collect (current_regcache, regno, fpregs);
+ }
+ }
+ else
+ {
+ if (FPREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_collect (current_regcache, regno, fpregs);
+ }
+}
+
+void
+fill_gregset (void *gregs, int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ if (GREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_collect (current_regcache, regno, gregs);
+ }
+ }
+ else
+ {
+ if (GREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_collect (current_regcache, regno, gregs);
+ }
+}
+
+void
+supply_fpregset (const void *fpregs)
+{
+ int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ if (FPREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_supply (current_regcache, regno, fpregs);
+ }
+}
+
+void
+supply_gregset (const void *gregs)
+{
+ int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ if (GREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_supply (current_regcache, regno, gregs);
+ }
+}
+
+static void
+ia64_fbsd_supply_gregset (const struct regset *regset,
+ struct regcache *regcache, int regno,
+ const void *gregs, size_t len)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ if (GREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_supply (regcache, regno, gregs);
+ }
+ }
+ else
+ if (GREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_supply (regcache, regno, gregs);
+}
+
+static void
+ia64_fbsd_supply_fpregset (const struct regset *regset,
+ struct regcache *regcache, int regno,
+ const void *fpregs, size_t len)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ if (FPREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_supply (regcache, regno, fpregs);
+ }
+ }
+ else
+ if (FPREG_SUPPLIES(regno))
+ ia64_fbsd_regcache_supply (regcache, regno, fpregs);
+}
+
+static struct regset gregset = { NULL, ia64_fbsd_supply_gregset };
+static struct regset fpregset = { NULL, ia64_fbsd_supply_fpregset };
+
+static const struct regset *
+ia64_fbsd_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
+{
+ if (strcmp (sect_name, ".reg") == 0)
+ return (&gregset);
+ if (strcmp (sect_name, ".reg2") == 0)
+ return (&fpregset);
+ return (NULL);
+}
+
+static int
+ia64_fbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ uint64_t gwpage = 5ULL << 61;
+ return (pc >= gwpage && pc < (gwpage + 8192)) ? 1 : 0;
+}
+
+static void
+ia64_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, ia64_fbsd_pc_in_sigtramp);
+ set_gdbarch_regset_from_core_section (gdbarch,
+ ia64_fbsd_regset_from_core_section);
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+ tdep->find_global_pointer = ia64_generic_find_global_pointer;
+}
+
+void
+_initialize_ia64_fbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_ia64, 0ul, GDB_OSABI_FREEBSD_ELF,
+ ia64_fbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/ia64-tdep.c b/contrib/gdb/gdb/ia64-tdep.c
new file mode 100644
index 0000000..9ac1e5d
--- /dev/null
+++ b/contrib/gdb/gdb/ia64-tdep.c
@@ -0,0 +1,3382 @@
+/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
+
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "reggroups.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "doublest.h"
+#include "value.h"
+#include "gdb_assert.h"
+#include "objfiles.h"
+#include "elf/common.h" /* for DT_PLTGOT value */
+#include "elf-bfd.h"
+#include "elf.h" /* for PT_IA64_UNWIND value */
+#include "dis-asm.h"
+#include "ia64-tdep.h"
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-frame.h"
+#include "libunwind-ia64.h"
+#endif
+
+/* An enumeration of the different IA-64 instruction types. */
+
+typedef enum instruction_type
+{
+ A, /* Integer ALU ; I-unit or M-unit */
+ I, /* Non-ALU integer; I-unit */
+ M, /* Memory ; M-unit */
+ F, /* Floating-point ; F-unit */
+ B, /* Branch ; B-unit */
+ L, /* Extended (L+X) ; I-unit */
+ X, /* Extended (L+X) ; I-unit */
+ undefined /* undefined or reserved */
+} instruction_type;
+
+/* We represent IA-64 PC addresses as the value of the instruction
+ pointer or'd with some bit combination in the low nibble which
+ represents the slot number in the bundle addressed by the
+ instruction pointer. The problem is that the Linux kernel
+ multiplies its slot numbers (for exceptions) by one while the
+ disassembler multiplies its slot numbers by 6. In addition, I've
+ heard it said that the simulator uses 1 as the multiplier.
+
+ I've fixed the disassembler so that the bytes_per_line field will
+ be the slot multiplier. If bytes_per_line comes in as zero, it
+ is set to six (which is how it was set up initially). -- objdump
+ displays pretty disassembly dumps with this value. For our purposes,
+ we'll set bytes_per_line to SLOT_MULTIPLIER. This is okay since we
+ never want to also display the raw bytes the way objdump does. */
+
+#define SLOT_MULTIPLIER 1
+
+/* Length in bytes of an instruction bundle */
+
+#define BUNDLE_LEN 16
+
+static gdbarch_init_ftype ia64_gdbarch_init;
+
+static gdbarch_register_name_ftype ia64_register_name;
+static gdbarch_register_type_ftype ia64_register_type;
+static gdbarch_breakpoint_from_pc_ftype ia64_breakpoint_from_pc;
+static gdbarch_skip_prologue_ftype ia64_skip_prologue;
+static gdbarch_extract_return_value_ftype ia64_extract_return_value;
+static gdbarch_use_struct_convention_ftype ia64_use_struct_convention;
+static struct type *is_float_or_hfa_type (struct type *t);
+
+static struct type *builtin_type_ia64_ext;
+
+#define NUM_IA64_RAW_REGS 462
+
+static int sp_regnum = IA64_GR12_REGNUM;
+static int fp_regnum = IA64_VFP_REGNUM;
+static int lr_regnum = IA64_VRAP_REGNUM;
+
+/* NOTE: we treat the register stack registers r32-r127 as pseudo-registers because
+ they may not be accessible via the ptrace register get/set interfaces. */
+enum pseudo_regs { FIRST_PSEUDO_REGNUM = NUM_IA64_RAW_REGS, VBOF_REGNUM = IA64_NAT127_REGNUM + 1, V32_REGNUM,
+ V127_REGNUM = V32_REGNUM + 95,
+ VP0_REGNUM, VP16_REGNUM = VP0_REGNUM + 16, VP63_REGNUM = VP0_REGNUM + 63, LAST_PSEUDO_REGNUM };
+
+/* Array of register names; There should be ia64_num_regs strings in
+ the initializer. */
+
+static char *ia64_register_names[] =
+{ "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",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
+ "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
+ "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
+ "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
+ "f64", "f65", "f66", "f67", "f68", "f69", "f70", "f71",
+ "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
+ "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87",
+ "f88", "f89", "f90", "f91", "f92", "f93", "f94", "f95",
+ "f96", "f97", "f98", "f99", "f100", "f101", "f102", "f103",
+ "f104", "f105", "f106", "f107", "f108", "f109", "f110", "f111",
+ "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
+ "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127",
+
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+
+ "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
+
+ "vfp", "vrap",
+
+ "pr", "ip", "psr", "cfm",
+
+ "kr0", "kr1", "kr2", "kr3", "kr4", "kr5", "kr6", "kr7",
+ "", "", "", "", "", "", "", "",
+ "rsc", "bsp", "bspstore", "rnat",
+ "", "fcr", "", "",
+ "eflag", "csd", "ssd", "cflg", "fsr", "fir", "fdr", "",
+ "ccv", "", "", "", "unat", "", "", "",
+ "fpsr", "", "", "", "itc",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "",
+ "pfs", "lc", "ec",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "",
+ "nat0", "nat1", "nat2", "nat3", "nat4", "nat5", "nat6", "nat7",
+ "nat8", "nat9", "nat10", "nat11", "nat12", "nat13", "nat14", "nat15",
+ "nat16", "nat17", "nat18", "nat19", "nat20", "nat21", "nat22", "nat23",
+ "nat24", "nat25", "nat26", "nat27", "nat28", "nat29", "nat30", "nat31",
+ "nat32", "nat33", "nat34", "nat35", "nat36", "nat37", "nat38", "nat39",
+ "nat40", "nat41", "nat42", "nat43", "nat44", "nat45", "nat46", "nat47",
+ "nat48", "nat49", "nat50", "nat51", "nat52", "nat53", "nat54", "nat55",
+ "nat56", "nat57", "nat58", "nat59", "nat60", "nat61", "nat62", "nat63",
+ "nat64", "nat65", "nat66", "nat67", "nat68", "nat69", "nat70", "nat71",
+ "nat72", "nat73", "nat74", "nat75", "nat76", "nat77", "nat78", "nat79",
+ "nat80", "nat81", "nat82", "nat83", "nat84", "nat85", "nat86", "nat87",
+ "nat88", "nat89", "nat90", "nat91", "nat92", "nat93", "nat94", "nat95",
+ "nat96", "nat97", "nat98", "nat99", "nat100","nat101","nat102","nat103",
+ "nat104","nat105","nat106","nat107","nat108","nat109","nat110","nat111",
+ "nat112","nat113","nat114","nat115","nat116","nat117","nat118","nat119",
+ "nat120","nat121","nat122","nat123","nat124","nat125","nat126","nat127",
+
+ "bof",
+
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
+ "r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63",
+ "r64", "r65", "r66", "r67", "r68", "r69", "r70", "r71",
+ "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
+ "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87",
+ "r88", "r89", "r90", "r91", "r92", "r93", "r94", "r95",
+ "r96", "r97", "r98", "r99", "r100", "r101", "r102", "r103",
+ "r104", "r105", "r106", "r107", "r108", "r109", "r110", "r111",
+ "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
+ "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127",
+
+ "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7",
+ "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",
+ "p16", "p17", "p18", "p19", "p20", "p21", "p22", "p23",
+ "p24", "p25", "p26", "p27", "p28", "p29", "p30", "p31",
+ "p32", "p33", "p34", "p35", "p36", "p37", "p38", "p39",
+ "p40", "p41", "p42", "p43", "p44", "p45", "p46", "p47",
+ "p48", "p49", "p50", "p51", "p52", "p53", "p54", "p55",
+ "p56", "p57", "p58", "p59", "p60", "p61", "p62", "p63",
+};
+
+struct ia64_frame_cache
+{
+ CORE_ADDR base; /* frame pointer base for frame */
+ CORE_ADDR pc; /* function start pc for frame */
+ CORE_ADDR saved_sp; /* stack pointer for frame */
+ CORE_ADDR bsp; /* points at r32 for the current frame */
+ CORE_ADDR cfm; /* cfm value for current frame */
+ CORE_ADDR prev_cfm; /* cfm value for previous frame */
+ int frameless;
+ int sof; /* Size of frame (decoded from cfm value) */
+ int sol; /* Size of locals (decoded from cfm value) */
+ int sor; /* Number of rotating registers. (decoded from cfm value) */
+ CORE_ADDR after_prologue;
+ /* Address of first instruction after the last
+ prologue instruction; Note that there may
+ be instructions from the function's body
+ intermingled with the prologue. */
+ int mem_stack_frame_size;
+ /* Size of the memory stack frame (may be zero),
+ or -1 if it has not been determined yet. */
+ int fp_reg; /* Register number (if any) used a frame pointer
+ for this frame. 0 if no register is being used
+ as the frame pointer. */
+
+ /* Saved registers. */
+ CORE_ADDR saved_regs[NUM_IA64_RAW_REGS];
+
+};
+
+int
+ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ int vector_p;
+ int float_p;
+ int raw_p;
+ if (group == all_reggroup)
+ return 1;
+ vector_p = TYPE_VECTOR (register_type (gdbarch, regnum));
+ float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT;
+ raw_p = regnum < NUM_IA64_RAW_REGS;
+ if (group == float_reggroup)
+ return float_p;
+ if (group == vector_reggroup)
+ return vector_p;
+ if (group == general_reggroup)
+ return (!vector_p && !float_p);
+ if (group == save_reggroup || group == restore_reggroup)
+ return raw_p;
+ return 0;
+}
+
+static const char *
+ia64_register_name (int reg)
+{
+ return ia64_register_names[reg];
+}
+
+struct type *
+ia64_register_type (struct gdbarch *arch, int reg)
+{
+ if (reg >= IA64_FR0_REGNUM && reg <= IA64_FR127_REGNUM)
+ return builtin_type_ia64_ext;
+ else
+ return builtin_type_long;
+}
+
+static int
+ia64_dwarf_reg_to_regnum (int reg)
+{
+ if (reg >= IA64_GR32_REGNUM && reg <= IA64_GR127_REGNUM)
+ return V32_REGNUM + (reg - IA64_GR32_REGNUM);
+ return reg;
+}
+
+static int
+floatformat_valid (const struct floatformat *fmt, const char *from)
+{
+ return 1;
+}
+
+const struct floatformat floatformat_ia64_ext =
+{
+ floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
+ floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid
+};
+
+
+/* Extract ``len'' bits from an instruction bundle starting at
+ bit ``from''. */
+
+static long long
+extract_bit_field (char *bundle, int from, int len)
+{
+ long long result = 0LL;
+ int to = from + len;
+ int from_byte = from / 8;
+ int to_byte = to / 8;
+ unsigned char *b = (unsigned char *) bundle;
+ unsigned char c;
+ int lshift;
+ int i;
+
+ c = b[from_byte];
+ if (from_byte == to_byte)
+ c = ((unsigned char) (c << (8 - to % 8))) >> (8 - to % 8);
+ result = c >> (from % 8);
+ lshift = 8 - (from % 8);
+
+ for (i = from_byte+1; i < to_byte; i++)
+ {
+ result |= ((long long) b[i]) << lshift;
+ lshift += 8;
+ }
+
+ if (from_byte < to_byte && (to % 8 != 0))
+ {
+ c = b[to_byte];
+ c = ((unsigned char) (c << (8 - to % 8))) >> (8 - to % 8);
+ result |= ((long long) c) << lshift;
+ }
+
+ return result;
+}
+
+/* Replace the specified bits in an instruction bundle */
+
+static void
+replace_bit_field (char *bundle, long long val, int from, int len)
+{
+ int to = from + len;
+ int from_byte = from / 8;
+ int to_byte = to / 8;
+ unsigned char *b = (unsigned char *) bundle;
+ unsigned char c;
+
+ if (from_byte == to_byte)
+ {
+ unsigned char left, right;
+ c = b[from_byte];
+ left = (c >> (to % 8)) << (to % 8);
+ right = ((unsigned char) (c << (8 - from % 8))) >> (8 - from % 8);
+ c = (unsigned char) (val & 0xff);
+ c = (unsigned char) (c << (from % 8 + 8 - to % 8)) >> (8 - to % 8);
+ c |= right | left;
+ b[from_byte] = c;
+ }
+ else
+ {
+ int i;
+ c = b[from_byte];
+ c = ((unsigned char) (c << (8 - from % 8))) >> (8 - from % 8);
+ c = c | (val << (from % 8));
+ b[from_byte] = c;
+ val >>= 8 - from % 8;
+
+ for (i = from_byte+1; i < to_byte; i++)
+ {
+ c = val & 0xff;
+ val >>= 8;
+ b[i] = c;
+ }
+
+ if (to % 8 != 0)
+ {
+ unsigned char cv = (unsigned char) val;
+ c = b[to_byte];
+ c = c >> (to % 8) << (to % 8);
+ c |= ((unsigned char) (cv << (8 - to % 8))) >> (8 - to % 8);
+ b[to_byte] = c;
+ }
+ }
+}
+
+/* Return the contents of slot N (for N = 0, 1, or 2) in
+ and instruction bundle */
+
+static long long
+slotN_contents (char *bundle, int slotnum)
+{
+ return extract_bit_field (bundle, 5+41*slotnum, 41);
+}
+
+/* Store an instruction in an instruction bundle */
+
+static void
+replace_slotN_contents (char *bundle, long long instr, int slotnum)
+{
+ replace_bit_field (bundle, instr, 5+41*slotnum, 41);
+}
+
+static enum instruction_type template_encoding_table[32][3] =
+{
+ { M, I, I }, /* 00 */
+ { M, I, I }, /* 01 */
+ { M, I, I }, /* 02 */
+ { M, I, I }, /* 03 */
+ { M, L, X }, /* 04 */
+ { M, L, X }, /* 05 */
+ { undefined, undefined, undefined }, /* 06 */
+ { undefined, undefined, undefined }, /* 07 */
+ { M, M, I }, /* 08 */
+ { M, M, I }, /* 09 */
+ { M, M, I }, /* 0A */
+ { M, M, I }, /* 0B */
+ { M, F, I }, /* 0C */
+ { M, F, I }, /* 0D */
+ { M, M, F }, /* 0E */
+ { M, M, F }, /* 0F */
+ { M, I, B }, /* 10 */
+ { M, I, B }, /* 11 */
+ { M, B, B }, /* 12 */
+ { M, B, B }, /* 13 */
+ { undefined, undefined, undefined }, /* 14 */
+ { undefined, undefined, undefined }, /* 15 */
+ { B, B, B }, /* 16 */
+ { B, B, B }, /* 17 */
+ { M, M, B }, /* 18 */
+ { M, M, B }, /* 19 */
+ { undefined, undefined, undefined }, /* 1A */
+ { undefined, undefined, undefined }, /* 1B */
+ { M, F, B }, /* 1C */
+ { M, F, B }, /* 1D */
+ { undefined, undefined, undefined }, /* 1E */
+ { undefined, undefined, undefined }, /* 1F */
+};
+
+/* Fetch and (partially) decode an instruction at ADDR and return the
+ address of the next instruction to fetch. */
+
+static CORE_ADDR
+fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr)
+{
+ char bundle[BUNDLE_LEN];
+ int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
+ long long template;
+ int val;
+
+ /* Warn about slot numbers greater than 2. We used to generate
+ an error here on the assumption that the user entered an invalid
+ address. But, sometimes GDB itself requests an invalid address.
+ This can (easily) happen when execution stops in a function for
+ which there are no symbols. The prologue scanner will attempt to
+ find the beginning of the function - if the nearest symbol
+ happens to not be aligned on a bundle boundary (16 bytes), the
+ resulting starting address will cause GDB to think that the slot
+ number is too large.
+
+ So we warn about it and set the slot number to zero. It is
+ not necessarily a fatal condition, particularly if debugging
+ at the assembly language level. */
+ if (slotnum > 2)
+ {
+ warning ("Can't fetch instructions for slot numbers greater than 2.\n"
+ "Using slot 0 instead");
+ slotnum = 0;
+ }
+
+ addr &= ~0x0f;
+
+ val = target_read_memory (addr, bundle, BUNDLE_LEN);
+
+ if (val != 0)
+ return 0;
+
+ *instr = slotN_contents (bundle, slotnum);
+ template = extract_bit_field (bundle, 0, 5);
+ *it = template_encoding_table[(int)template][slotnum];
+
+ if (slotnum == 2 || (slotnum == 1 && *it == L))
+ addr += 16;
+ else
+ addr += (slotnum + 1) * SLOT_MULTIPLIER;
+
+ return addr;
+}
+
+/* There are 5 different break instructions (break.i, break.b,
+ break.m, break.f, and break.x), but they all have the same
+ encoding. (The five bit template in the low five bits of the
+ instruction bundle distinguishes one from another.)
+
+ The runtime architecture manual specifies that break instructions
+ used for debugging purposes must have the upper two bits of the 21
+ bit immediate set to a 0 and a 1 respectively. A breakpoint
+ instruction encodes the most significant bit of its 21 bit
+ immediate at bit 36 of the 41 bit instruction. The penultimate msb
+ is at bit 25 which leads to the pattern below.
+
+ Originally, I had this set up to do, e.g, a "break.i 0x80000" But
+ it turns out that 0x80000 was used as the syscall break in the early
+ simulators. So I changed the pattern slightly to do "break.i 0x080001"
+ instead. But that didn't work either (I later found out that this
+ pattern was used by the simulator that I was using.) So I ended up
+ using the pattern seen below. */
+
+#if 0
+#define IA64_BREAKPOINT 0x00002000040LL
+#endif
+#define IA64_BREAKPOINT 0x00003333300LL
+
+static int
+ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ char bundle[BUNDLE_LEN];
+ int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
+ long long instr;
+ int val;
+ int template;
+
+ if (slotnum > 2)
+ error("Can't insert breakpoint for slot numbers greater than 2.");
+
+ addr &= ~0x0f;
+
+ val = target_read_memory (addr, bundle, BUNDLE_LEN);
+
+ /* Check for L type instruction in 2nd slot, if present then
+ bump up the slot number to the 3rd slot */
+ template = extract_bit_field (bundle, 0, 5);
+ if (slotnum == 1 && template_encoding_table[template][1] == L)
+ {
+ slotnum = 2;
+ }
+
+ instr = slotN_contents (bundle, slotnum);
+ memcpy(contents_cache, &instr, sizeof(instr));
+ replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum);
+ if (val == 0)
+ target_write_memory (addr, bundle, BUNDLE_LEN);
+
+ return val;
+}
+
+static int
+ia64_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ char bundle[BUNDLE_LEN];
+ int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER;
+ long long instr;
+ int val;
+ int template;
+
+ addr &= ~0x0f;
+
+ val = target_read_memory (addr, bundle, BUNDLE_LEN);
+
+ /* Check for L type instruction in 2nd slot, if present then
+ bump up the slot number to the 3rd slot */
+ template = extract_bit_field (bundle, 0, 5);
+ if (slotnum == 1 && template_encoding_table[template][1] == L)
+ {
+ slotnum = 2;
+ }
+
+ memcpy (&instr, contents_cache, sizeof instr);
+ replace_slotN_contents (bundle, instr, slotnum);
+ if (val == 0)
+ target_write_memory (addr, bundle, BUNDLE_LEN);
+
+ return val;
+}
+
+/* We don't really want to use this, but remote.c needs to call it in order
+ to figure out if Z-packets are supported or not. Oh, well. */
+const unsigned char *
+ia64_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ static unsigned char breakpoint[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ *lenptr = sizeof (breakpoint);
+#if 0
+ *pcptr &= ~0x0f;
+#endif
+ return breakpoint;
+}
+
+static CORE_ADDR
+ia64_read_pc (ptid_t ptid)
+{
+ CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
+ CORE_ADDR pc_value = read_register_pid (IA64_IP_REGNUM, ptid);
+ int slot_num = (psr_value >> 41) & 3;
+
+ return pc_value | (slot_num * SLOT_MULTIPLIER);
+}
+
+void
+ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid)
+{
+ int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER;
+ CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
+ psr_value &= ~(3LL << 41);
+ psr_value |= (CORE_ADDR)(slot_num & 0x3) << 41;
+
+ new_pc &= ~0xfLL;
+
+ write_register_pid (IA64_PSR_REGNUM, psr_value, ptid);
+ write_register_pid (IA64_IP_REGNUM, new_pc, ptid);
+}
+
+#define IS_NaT_COLLECTION_ADDR(addr) ((((addr) >> 3) & 0x3f) == 0x3f)
+
+/* Returns the address of the slot that's NSLOTS slots away from
+ the address ADDR. NSLOTS may be positive or negative. */
+static CORE_ADDR
+rse_address_add(CORE_ADDR addr, int nslots)
+{
+ CORE_ADDR new_addr;
+ int mandatory_nat_slots = nslots / 63;
+ int direction = nslots < 0 ? -1 : 1;
+
+ new_addr = addr + 8 * (nslots + mandatory_nat_slots);
+
+ if ((new_addr >> 9) != ((addr + 8 * 64 * mandatory_nat_slots) >> 9))
+ new_addr += 8 * direction;
+
+ if (IS_NaT_COLLECTION_ADDR(new_addr))
+ new_addr += 8 * direction;
+
+ return new_addr;
+}
+
+static void
+ia64_read_reg (CORE_ADDR addr, void *buf, int len)
+{
+ ULONGEST bspstore;
+ regcache_cooked_read_unsigned (current_regcache, IA64_BSPSTORE_REGNUM,
+ &bspstore);
+ if (addr >= bspstore)
+ {
+ ULONGEST bsp;
+ regcache_cooked_read_unsigned (current_regcache, IA64_BSP_REGNUM,
+ &bsp);
+ if (addr < bsp)
+ {
+ target_read_partial (&current_target, TARGET_OBJECT_DIRTY,
+ (void*)&bspstore, buf, addr - bspstore, len);
+ return;
+ }
+ }
+ read_memory (addr, buf, len);
+}
+
+static void
+ia64_write_reg (CORE_ADDR addr, void *buf, int len)
+{
+ ULONGEST bspstore;
+ regcache_cooked_read_unsigned (current_regcache, IA64_BSPSTORE_REGNUM,
+ &bspstore);
+ if (addr >= bspstore)
+ {
+ ULONGEST bsp;
+ regcache_cooked_read_unsigned (current_regcache, IA64_BSP_REGNUM,
+ &bsp);
+ if (addr < bsp)
+ {
+ target_write_partial (&current_target, TARGET_OBJECT_DIRTY,
+ (void*)&bspstore, buf, addr - bspstore, len);
+ return;
+ }
+ }
+ write_memory (addr, buf, len);
+}
+
+static void
+ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, void *buf)
+{
+ if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
+ {
+ ULONGEST bsp;
+ ULONGEST cfm;
+ CORE_ADDR reg;
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ /* The bsp points at the end of the register frame so we
+ subtract the size of frame from it to get start of register frame. */
+ bsp = rse_address_add (bsp, -(cfm & 0x7f));
+
+ if ((cfm & 0x7f) > regnum - V32_REGNUM)
+ {
+ ULONGEST addr = rse_address_add (bsp, (regnum - V32_REGNUM));
+ ia64_read_reg (addr, buf, register_size (current_gdbarch, regnum));
+ }
+ else
+ store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
+ {
+ ULONGEST unatN_val;
+ ULONGEST unat;
+ regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
+ unatN_val = (unat & (1LL << (regnum - IA64_NAT0_REGNUM))) != 0;
+ store_unsigned_integer (buf, register_size (current_gdbarch, regnum), unatN_val);
+ }
+ else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ ULONGEST natN_val = 0;
+ ULONGEST bsp;
+ ULONGEST cfm;
+ CORE_ADDR gr_addr = 0;
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ /* The bsp points at the end of the register frame so we
+ subtract the size of frame from it to get start of register frame. */
+ bsp = rse_address_add (bsp, -(cfm & 0x7f));
+
+ if ((cfm & 0x7f) > regnum - V32_REGNUM)
+ gr_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
+
+ if (gr_addr != 0)
+ {
+ /* Compute address of nat collection bits. */
+ CORE_ADDR nat_addr = gr_addr | 0x1f8;
+ CORE_ADDR nat_collection;
+ int nat_bit;
+ /* If our nat collection address is bigger than bsp, we have to get
+ the nat collection from rnat. Otherwise, we fetch the nat
+ collection from the computed address. */
+ if (nat_addr >= bsp)
+ regcache_cooked_read_unsigned (regcache, IA64_RNAT_REGNUM, &nat_collection);
+ else
+ {
+ uint64_t tmp;
+ ia64_read_reg (nat_addr, &tmp, sizeof(tmp));
+ nat_collection = tmp;
+ }
+ nat_bit = (gr_addr >> 3) & 0x3f;
+ natN_val = (nat_collection >> nat_bit) & 1;
+ }
+
+ store_unsigned_integer (buf, register_size (current_gdbarch, regnum), natN_val);
+ }
+ else if (regnum == VBOF_REGNUM)
+ {
+ /* A virtual register frame start is provided for user convenience.
+ It can be calculated as the bsp - sof (sizeof frame). */
+ ULONGEST bsp, vbsp;
+ ULONGEST cfm;
+ CORE_ADDR reg;
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ /* The bsp points at the end of the register frame so we
+ subtract the size of frame from it to get beginning of frame. */
+ vbsp = rse_address_add (bsp, -(cfm & 0x7f));
+ store_unsigned_integer (buf, register_size (current_gdbarch, regnum), vbsp);
+ }
+ else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ ULONGEST pr;
+ ULONGEST cfm;
+ ULONGEST prN_val;
+ CORE_ADDR reg;
+ regcache_cooked_read_unsigned (regcache, IA64_PR_REGNUM, &pr);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ int rrb_pr = (cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = VP16_REGNUM
+ + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+ }
+ prN_val = (pr & (1LL << (regnum - VP0_REGNUM))) != 0;
+ store_unsigned_integer (buf, register_size (current_gdbarch, regnum), prN_val);
+ }
+ else
+ memset (buf, 0, register_size (current_gdbarch, regnum));
+}
+
+static void
+ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, const void *buf)
+{
+ if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
+ {
+ ULONGEST bsp;
+ ULONGEST cfm;
+ CORE_ADDR reg;
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ bsp = rse_address_add (bsp, -(cfm & 0x7f));
+
+ if ((cfm & 0x7f) > regnum - V32_REGNUM)
+ {
+ ULONGEST addr = rse_address_add (bsp, (regnum - V32_REGNUM));
+ ia64_write_reg (addr, (void *)buf, 8);
+ }
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
+ {
+ ULONGEST unatN_val, unat, unatN_mask;
+ regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
+ unatN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum));
+ unatN_mask = (1LL << (regnum - IA64_NAT0_REGNUM));
+ if (unatN_val == 0)
+ unat &= ~unatN_mask;
+ else if (unatN_val == 1)
+ unat |= unatN_mask;
+ regcache_cooked_write_unsigned (regcache, IA64_UNAT_REGNUM, unat);
+ }
+ else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ ULONGEST natN_val;
+ ULONGEST bsp;
+ ULONGEST cfm;
+ CORE_ADDR gr_addr = 0;
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ /* The bsp points at the end of the register frame so we
+ subtract the size of frame from it to get start of register frame. */
+ bsp = rse_address_add (bsp, -(cfm & 0x7f));
+
+ if ((cfm & 0x7f) > regnum - V32_REGNUM)
+ gr_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
+
+ natN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum));
+
+ if (gr_addr != 0 && (natN_val == 0 || natN_val == 1))
+ {
+ /* Compute address of nat collection bits. */
+ CORE_ADDR nat_addr = gr_addr | 0x1f8;
+ CORE_ADDR nat_collection;
+ int natN_bit = (gr_addr >> 3) & 0x3f;
+ ULONGEST natN_mask = (1LL << natN_bit);
+ /* If our nat collection address is bigger than bsp, we have to get
+ the nat collection from rnat. Otherwise, we fetch the nat
+ collection from the computed address. */
+ if (nat_addr >= bsp)
+ {
+ regcache_cooked_read_unsigned (regcache, IA64_RNAT_REGNUM, &nat_collection);
+ if (natN_val)
+ nat_collection |= natN_mask;
+ else
+ nat_collection &= ~natN_mask;
+ regcache_cooked_write_unsigned (regcache, IA64_RNAT_REGNUM, nat_collection);
+ }
+ else
+ {
+ uint64_t tmp;
+ ia64_read_reg (nat_addr, &tmp, sizeof(tmp));
+ nat_collection = tmp;
+ if (natN_val)
+ nat_collection |= natN_mask;
+ else
+ nat_collection &= ~natN_mask;
+ tmp = nat_collection;
+ ia64_write_reg (nat_addr, &tmp, sizeof(tmp));
+ }
+ }
+ }
+ else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ ULONGEST pr;
+ ULONGEST cfm;
+ ULONGEST prN_val;
+ ULONGEST prN_mask;
+
+ regcache_cooked_read_unsigned (regcache, IA64_PR_REGNUM, &pr);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ int rrb_pr = (cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = VP16_REGNUM
+ + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+ }
+ prN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum));
+ prN_mask = (1LL << (regnum - VP0_REGNUM));
+ if (prN_val == 0)
+ pr &= ~prN_mask;
+ else if (prN_val == 1)
+ pr |= prN_mask;
+ regcache_cooked_write_unsigned (regcache, IA64_PR_REGNUM, pr);
+ }
+}
+
+/* The ia64 needs to convert between various ieee floating-point formats
+ and the special ia64 floating point register format. */
+
+static int
+ia64_convert_register_p (int regno, struct type *type)
+{
+ return (regno >= IA64_FR0_REGNUM && regno <= IA64_FR127_REGNUM);
+}
+
+static void
+ia64_register_to_value (struct frame_info *frame, int regnum,
+ struct type *valtype, void *out)
+{
+ char in[MAX_REGISTER_SIZE];
+ frame_register_read (frame, regnum, in);
+ convert_typed_floating (in, builtin_type_ia64_ext, out, valtype);
+}
+
+static void
+ia64_value_to_register (struct frame_info *frame, int regnum,
+ struct type *valtype, const void *in)
+{
+ char out[MAX_REGISTER_SIZE];
+ convert_typed_floating (in, valtype, out, builtin_type_ia64_ext);
+ put_frame_register (frame, regnum, out);
+}
+
+
+/* Limit the number of skipped non-prologue instructions since examining
+ of the prologue is expensive. */
+static int max_skip_non_prologue_insns = 40;
+
+/* Given PC representing the starting address of a function, and
+ LIM_PC which is the (sloppy) limit to which to scan when looking
+ for a prologue, attempt to further refine this limit by using
+ the line data in the symbol table. If successful, a better guess
+ on where the prologue ends is returned, otherwise the previous
+ value of lim_pc is returned. TRUST_LIMIT is a pointer to a flag
+ which will be set to indicate whether the returned limit may be
+ used with no further scanning in the event that the function is
+ frameless. */
+
+/* FIXME: cagney/2004-02-14: This function and logic have largely been
+ superseded by skip_prologue_using_sal. */
+
+static CORE_ADDR
+refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int *trust_limit)
+{
+ struct symtab_and_line prologue_sal;
+ CORE_ADDR start_pc = pc;
+
+ /* Start off not trusting the limit. */
+ *trust_limit = 0;
+
+ prologue_sal = find_pc_line (pc, 0);
+ if (prologue_sal.line != 0)
+ {
+ int i;
+ CORE_ADDR addr = prologue_sal.end;
+
+ /* Handle the case in which compiler's optimizer/scheduler
+ has moved instructions into the prologue. We scan ahead
+ in the function looking for address ranges whose corresponding
+ line number is less than or equal to the first one that we
+ found for the function. (It can be less than when the
+ scheduler puts a body instruction before the first prologue
+ instruction.) */
+ for (i = 2 * max_skip_non_prologue_insns;
+ i > 0 && (lim_pc == 0 || addr < lim_pc);
+ i--)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (addr, 0);
+ if (sal.line == 0)
+ break;
+ if (sal.line <= prologue_sal.line
+ && sal.symtab == prologue_sal.symtab)
+ {
+ prologue_sal = sal;
+ }
+ addr = sal.end;
+ }
+
+ if (lim_pc == 0 || prologue_sal.end < lim_pc)
+ {
+ lim_pc = prologue_sal.end;
+ if (start_pc == get_pc_function_start (lim_pc))
+ *trust_limit = 1;
+ }
+ }
+ return lim_pc;
+}
+
+#define isScratch(_regnum_) ((_regnum_) == 2 || (_regnum_) == 3 \
+ || (8 <= (_regnum_) && (_regnum_) <= 11) \
+ || (14 <= (_regnum_) && (_regnum_) <= 31))
+#define imm9(_instr_) \
+ ( ((((_instr_) & 0x01000000000LL) ? -1 : 0) << 8) \
+ | (((_instr_) & 0x00008000000LL) >> 20) \
+ | (((_instr_) & 0x00000001fc0LL) >> 6))
+
+/* Allocate and initialize a frame cache. */
+
+static struct ia64_frame_cache *
+ia64_alloc_frame_cache (void)
+{
+ struct ia64_frame_cache *cache;
+ int i;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct ia64_frame_cache);
+
+ /* Base address. */
+ cache->base = 0;
+ cache->pc = 0;
+ cache->cfm = 0;
+ cache->prev_cfm = 0;
+ cache->sof = 0;
+ cache->sol = 0;
+ cache->sor = 0;
+ cache->bsp = 0;
+ cache->fp_reg = 0;
+ cache->frameless = 1;
+
+ for (i = 0; i < NUM_IA64_RAW_REGS; i++)
+ cache->saved_regs[i] = 0;
+
+ return cache;
+}
+
+static CORE_ADDR
+examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, struct ia64_frame_cache *cache)
+{
+ CORE_ADDR next_pc;
+ CORE_ADDR last_prologue_pc = pc;
+ instruction_type it;
+ long long instr;
+ int cfm_reg = 0;
+ int ret_reg = 0;
+ int fp_reg = 0;
+ int unat_save_reg = 0;
+ int pr_save_reg = 0;
+ int mem_stack_frame_size = 0;
+ int spill_reg = 0;
+ CORE_ADDR spill_addr = 0;
+ char instores[8];
+ char infpstores[8];
+ char reg_contents[256];
+ int trust_limit;
+ int frameless = 1;
+ int i;
+ CORE_ADDR addr;
+ char buf[8];
+ CORE_ADDR bof, sor, sol, sof, cfm, rrb_gr;
+
+ memset (instores, 0, sizeof instores);
+ memset (infpstores, 0, sizeof infpstores);
+ memset (reg_contents, 0, sizeof reg_contents);
+
+ if (cache->after_prologue != 0
+ && cache->after_prologue <= lim_pc)
+ return cache->after_prologue;
+
+ lim_pc = refine_prologue_limit (pc, lim_pc, &trust_limit);
+ next_pc = fetch_instruction (pc, &it, &instr);
+
+ /* We want to check if we have a recognizable function start before we
+ look ahead for a prologue. */
+ if (pc < lim_pc && next_pc
+ && it == M && ((instr & 0x1ee0000003fLL) == 0x02c00000000LL))
+ {
+ /* alloc - start of a regular function. */
+ int sor = (int) ((instr & 0x00078000000LL) >> 27);
+ int sol = (int) ((instr & 0x00007f00000LL) >> 20);
+ int sof = (int) ((instr & 0x000000fe000LL) >> 13);
+ int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
+
+ /* Verify that the current cfm matches what we think is the
+ function start. If we have somehow jumped within a function,
+ we do not want to interpret the prologue and calculate the
+ addresses of various registers such as the return address.
+ We will instead treat the frame as frameless. */
+ if (!next_frame ||
+ (sof == (cache->cfm & 0x7f) &&
+ sol == ((cache->cfm >> 7) & 0x7f)))
+ frameless = 0;
+
+ cfm_reg = rN;
+ last_prologue_pc = next_pc;
+ pc = next_pc;
+ }
+ else
+ {
+ /* Look for a leaf routine. */
+ if (pc < lim_pc && next_pc
+ && (it == I || it == M)
+ && ((instr & 0x1ee00000000LL) == 0x10800000000LL))
+ {
+ /* adds rN = imm14, rM (or mov rN, rM when imm14 is 0) */
+ int imm = (int) ((((instr & 0x01000000000LL) ? -1 : 0) << 13)
+ | ((instr & 0x001f8000000LL) >> 20)
+ | ((instr & 0x000000fe000LL) >> 13));
+ int rM = (int) ((instr & 0x00007f00000LL) >> 20);
+ int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && rN == 2 && imm == 0 && rM == 12 && fp_reg == 0)
+ {
+ /* mov r2, r12 - beginning of leaf routine */
+ fp_reg = rN;
+ last_prologue_pc = next_pc;
+ }
+ }
+
+ /* If we don't recognize a regular function or leaf routine, we are
+ done. */
+ if (!fp_reg)
+ {
+ pc = lim_pc;
+ if (trust_limit)
+ last_prologue_pc = lim_pc;
+ }
+ }
+
+ /* Loop, looking for prologue instructions, keeping track of
+ where preserved registers were spilled. */
+ while (pc < lim_pc)
+ {
+ next_pc = fetch_instruction (pc, &it, &instr);
+ if (next_pc == 0)
+ break;
+
+ if (it == B && ((instr & 0x1e1f800003f) != 0x04000000000))
+ {
+ /* Exit loop upon hitting a non-nop branch instruction. */
+ if (trust_limit)
+ lim_pc = pc;
+ break;
+ }
+ else if (((instr & 0x3fLL) != 0LL) &&
+ (frameless || ret_reg != 0))
+ {
+ /* Exit loop upon hitting a predicated instruction if
+ we already have the return register or if we are frameless. */
+ if (trust_limit)
+ lim_pc = pc;
+ break;
+ }
+ else if (it == I && ((instr & 0x1eff8000000LL) == 0x00188000000LL))
+ {
+ /* Move from BR */
+ int b2 = (int) ((instr & 0x0000000e000LL) >> 13);
+ int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
+ int qp = (int) (instr & 0x0000000003f);
+
+ if (qp == 0 && b2 == 0 && rN >= 32 && ret_reg == 0)
+ {
+ ret_reg = rN;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if ((it == I || it == M)
+ && ((instr & 0x1ee00000000LL) == 0x10800000000LL))
+ {
+ /* adds rN = imm14, rM (or mov rN, rM when imm14 is 0) */
+ int imm = (int) ((((instr & 0x01000000000LL) ? -1 : 0) << 13)
+ | ((instr & 0x001f8000000LL) >> 20)
+ | ((instr & 0x000000fe000LL) >> 13));
+ int rM = (int) ((instr & 0x00007f00000LL) >> 20);
+ int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
+ int qp = (int) (instr & 0x0000000003fLL);
+
+ if (qp == 0 && rN >= 32 && imm == 0 && rM == 12 && fp_reg == 0)
+ {
+ /* mov rN, r12 */
+ fp_reg = rN;
+ last_prologue_pc = next_pc;
+ }
+ else if (qp == 0 && rN == 12 && rM == 12)
+ {
+ /* adds r12, -mem_stack_frame_size, r12 */
+ mem_stack_frame_size -= imm;
+ last_prologue_pc = next_pc;
+ }
+ else if (qp == 0 && rN == 2
+ && ((rM == fp_reg && fp_reg != 0) || rM == 12))
+ {
+ char buf[MAX_REGISTER_SIZE];
+ CORE_ADDR saved_sp = 0;
+ /* adds r2, spilloffset, rFramePointer
+ or
+ adds r2, spilloffset, r12
+
+ Get ready for stf.spill or st8.spill instructions.
+ The address to start spilling at is loaded into r2.
+ FIXME: Why r2? That's what gcc currently uses; it
+ could well be different for other compilers. */
+
+ /* Hmm... whether or not this will work will depend on
+ where the pc is. If it's still early in the prologue
+ this'll be wrong. FIXME */
+ if (next_frame)
+ {
+ frame_unwind_register (next_frame, sp_regnum, buf);
+ saved_sp = extract_unsigned_integer (buf, 8);
+ }
+ spill_addr = saved_sp
+ + (rM == 12 ? 0 : mem_stack_frame_size)
+ + imm;
+ spill_reg = rN;
+ last_prologue_pc = next_pc;
+ }
+ else if (qp == 0 && rM >= 32 && rM < 40 && !instores[rM] &&
+ rN < 256 && imm == 0)
+ {
+ /* mov rN, rM where rM is an input register */
+ reg_contents[rN] = rM;
+ last_prologue_pc = next_pc;
+ }
+ else if (frameless && qp == 0 && rN == fp_reg && imm == 0 &&
+ rM == 2)
+ {
+ /* mov r12, r2 */
+ last_prologue_pc = next_pc;
+ break;
+ }
+ }
+ else if (it == M
+ && ( ((instr & 0x1efc0000000LL) == 0x0eec0000000LL)
+ || ((instr & 0x1ffc8000000LL) == 0x0cec0000000LL) ))
+ {
+ /* stf.spill [rN] = fM, imm9
+ or
+ stf.spill [rN] = fM */
+
+ int imm = imm9(instr);
+ int rN = (int) ((instr & 0x00007f00000LL) >> 20);
+ int fM = (int) ((instr & 0x000000fe000LL) >> 13);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && rN == spill_reg && spill_addr != 0
+ && ((2 <= fM && fM <= 5) || (16 <= fM && fM <= 31)))
+ {
+ cache->saved_regs[IA64_FR0_REGNUM + fM] = spill_addr;
+
+ if ((instr & 0x1efc0000000) == 0x0eec0000000)
+ spill_addr += imm;
+ else
+ spill_addr = 0; /* last one; must be done */
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if ((it == M && ((instr & 0x1eff8000000LL) == 0x02110000000LL))
+ || (it == I && ((instr & 0x1eff8000000LL) == 0x00050000000LL)) )
+ {
+ /* mov.m rN = arM
+ or
+ mov.i rN = arM */
+
+ int arM = (int) ((instr & 0x00007f00000LL) >> 20);
+ int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && isScratch (rN) && arM == 36 /* ar.unat */)
+ {
+ /* We have something like "mov.m r3 = ar.unat". Remember the
+ r3 (or whatever) and watch for a store of this register... */
+ unat_save_reg = rN;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if (it == I && ((instr & 0x1eff8000000LL) == 0x00198000000LL))
+ {
+ /* mov rN = pr */
+ int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && isScratch (rN))
+ {
+ pr_save_reg = rN;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if (it == M
+ && ( ((instr & 0x1ffc8000000LL) == 0x08cc0000000LL)
+ || ((instr & 0x1efc0000000LL) == 0x0acc0000000LL)))
+ {
+ /* st8 [rN] = rM
+ or
+ st8 [rN] = rM, imm9 */
+ int rN = (int) ((instr & 0x00007f00000LL) >> 20);
+ int rM = (int) ((instr & 0x000000fe000LL) >> 13);
+ int qp = (int) (instr & 0x0000000003fLL);
+ int indirect = rM < 256 ? reg_contents[rM] : 0;
+ if (qp == 0 && rN == spill_reg && spill_addr != 0
+ && (rM == unat_save_reg || rM == pr_save_reg))
+ {
+ /* We've found a spill of either the UNAT register or the PR
+ register. (Well, not exactly; what we've actually found is
+ a spill of the register that UNAT or PR was moved to).
+ Record that fact and move on... */
+ if (rM == unat_save_reg)
+ {
+ /* Track UNAT register */
+ cache->saved_regs[IA64_UNAT_REGNUM] = spill_addr;
+ unat_save_reg = 0;
+ }
+ else
+ {
+ /* Track PR register */
+ cache->saved_regs[IA64_PR_REGNUM] = spill_addr;
+ pr_save_reg = 0;
+ }
+ if ((instr & 0x1efc0000000LL) == 0x0acc0000000LL)
+ /* st8 [rN] = rM, imm9 */
+ spill_addr += imm9(instr);
+ else
+ spill_addr = 0; /* must be done spilling */
+ last_prologue_pc = next_pc;
+ }
+ else if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
+ {
+ /* Allow up to one store of each input register. */
+ instores[rM-32] = 1;
+ last_prologue_pc = next_pc;
+ }
+ else if (qp == 0 && 32 <= indirect && indirect < 40 &&
+ !instores[indirect-32])
+ {
+ /* Allow an indirect store of an input register. */
+ instores[indirect-32] = 1;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if (it == M && ((instr & 0x1ff08000000LL) == 0x08c00000000LL))
+ {
+ /* One of
+ st1 [rN] = rM
+ st2 [rN] = rM
+ st4 [rN] = rM
+ st8 [rN] = rM
+ Note that the st8 case is handled in the clause above.
+
+ Advance over stores of input registers. One store per input
+ register is permitted. */
+ int rM = (int) ((instr & 0x000000fe000LL) >> 13);
+ int qp = (int) (instr & 0x0000000003fLL);
+ int indirect = rM < 256 ? reg_contents[rM] : 0;
+ if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
+ {
+ instores[rM-32] = 1;
+ last_prologue_pc = next_pc;
+ }
+ else if (qp == 0 && 32 <= indirect && indirect < 40 &&
+ !instores[indirect-32])
+ {
+ /* Allow an indirect store of an input register. */
+ instores[indirect-32] = 1;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if (it == M && ((instr & 0x1ff88000000LL) == 0x0cc80000000LL))
+ {
+ /* Either
+ stfs [rN] = fM
+ or
+ stfd [rN] = fM
+
+ Advance over stores of floating point input registers. Again
+ one store per register is permitted */
+ int fM = (int) ((instr & 0x000000fe000LL) >> 13);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && 8 <= fM && fM < 16 && !infpstores[fM - 8])
+ {
+ infpstores[fM-8] = 1;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if (it == M
+ && ( ((instr & 0x1ffc8000000LL) == 0x08ec0000000LL)
+ || ((instr & 0x1efc0000000LL) == 0x0aec0000000LL)))
+ {
+ /* st8.spill [rN] = rM
+ or
+ st8.spill [rN] = rM, imm9 */
+ int rN = (int) ((instr & 0x00007f00000LL) >> 20);
+ int rM = (int) ((instr & 0x000000fe000LL) >> 13);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && rN == spill_reg && 4 <= rM && rM <= 7)
+ {
+ /* We've found a spill of one of the preserved general purpose
+ regs. Record the spill address and advance the spill
+ register if appropriate. */
+ cache->saved_regs[IA64_GR0_REGNUM + rM] = spill_addr;
+ if ((instr & 0x1efc0000000LL) == 0x0aec0000000LL)
+ /* st8.spill [rN] = rM, imm9 */
+ spill_addr += imm9(instr);
+ else
+ spill_addr = 0; /* Done spilling */
+ last_prologue_pc = next_pc;
+ }
+ }
+
+ pc = next_pc;
+ }
+
+ /* If not frameless and we aren't called by skip_prologue, then we need to calculate
+ registers for the previous frame which will be needed later. */
+
+ if (!frameless && next_frame)
+ {
+ /* Extract the size of the rotating portion of the stack
+ frame and the register rename base from the current
+ frame marker. */
+ cfm = cache->cfm;
+ sor = cache->sor;
+ sof = cache->sof;
+ sol = cache->sol;
+ rrb_gr = (cfm >> 18) & 0x7f;
+
+ /* Find the bof (beginning of frame). */
+ bof = rse_address_add (cache->bsp, -sof);
+
+ for (i = 0, addr = bof;
+ i < sof;
+ i++, addr += 8)
+ {
+ if (IS_NaT_COLLECTION_ADDR (addr))
+ {
+ addr += 8;
+ }
+ if (i+32 == cfm_reg)
+ cache->saved_regs[IA64_CFM_REGNUM] = addr;
+ if (i+32 == ret_reg)
+ cache->saved_regs[IA64_VRAP_REGNUM] = addr;
+ if (i+32 == fp_reg)
+ cache->saved_regs[IA64_VFP_REGNUM] = addr;
+ }
+
+ /* For the previous argument registers we require the previous bof.
+ If we can't find the previous cfm, then we can do nothing. */
+ cfm = 0;
+ if (cache->saved_regs[IA64_CFM_REGNUM] != 0)
+ {
+ uint64_t tmp;
+ ia64_read_reg (cache->saved_regs[IA64_CFM_REGNUM], &tmp, sizeof(tmp));
+ cfm = tmp;
+ }
+ else if (cfm_reg != 0)
+ {
+ frame_unwind_register (next_frame, cfm_reg, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ }
+ cache->prev_cfm = cfm;
+
+ if (cfm != 0)
+ {
+ sor = ((cfm >> 14) & 0xf) * 8;
+ sof = (cfm & 0x7f);
+ sol = (cfm >> 7) & 0x7f;
+ rrb_gr = (cfm >> 18) & 0x7f;
+
+ /* The previous bof only requires subtraction of the sol (size of locals)
+ due to the overlap between output and input of subsequent frames. */
+ bof = rse_address_add (bof, -sol);
+
+ for (i = 0, addr = bof;
+ i < sof;
+ i++, addr += 8)
+ {
+ if (IS_NaT_COLLECTION_ADDR (addr))
+ {
+ addr += 8;
+ }
+ if (i < sor)
+ cache->saved_regs[IA64_GR32_REGNUM + ((i + (sor - rrb_gr)) % sor)]
+ = addr;
+ else
+ cache->saved_regs[IA64_GR32_REGNUM + i] = addr;
+ }
+
+ }
+ }
+
+ /* Try and trust the lim_pc value whenever possible. */
+ if (trust_limit && lim_pc >= last_prologue_pc)
+ last_prologue_pc = lim_pc;
+
+ cache->frameless = frameless;
+ cache->after_prologue = last_prologue_pc;
+ cache->mem_stack_frame_size = mem_stack_frame_size;
+ cache->fp_reg = fp_reg;
+
+ return last_prologue_pc;
+}
+
+CORE_ADDR
+ia64_skip_prologue (CORE_ADDR pc)
+{
+ struct ia64_frame_cache cache;
+ cache.base = 0;
+ cache.after_prologue = 0;
+ cache.cfm = 0;
+ cache.bsp = 0;
+
+ /* Call examine_prologue with - as third argument since we don't have a next frame pointer to send. */
+ return examine_prologue (pc, pc+1024, 0, &cache);
+}
+
+
+/* Normal frames. */
+
+static struct ia64_frame_cache *
+ia64_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct ia64_frame_cache *cache;
+ char buf[8];
+ CORE_ADDR cfm, sof, sol, bsp, psr;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = ia64_alloc_frame_cache ();
+ *this_cache = cache;
+
+ frame_unwind_register (next_frame, sp_regnum, buf);
+ cache->saved_sp = extract_unsigned_integer (buf, 8);
+
+ /* We always want the bsp to point to the end of frame.
+ This way, we can always get the beginning of frame (bof)
+ by subtracting frame size. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ cache->bsp = extract_unsigned_integer (buf, 8);
+
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+
+ cache->sof = (cfm & 0x7f);
+ cache->sol = (cfm >> 7) & 0x7f;
+ cache->sor = ((cfm >> 14) & 0xf) * 8;
+
+ cache->cfm = cfm;
+
+ cache->pc = frame_func_unwind (next_frame);
+
+ if (cache->pc != 0)
+ examine_prologue (cache->pc, frame_pc_unwind (next_frame), next_frame, cache);
+
+ cache->base = cache->saved_sp + cache->mem_stack_frame_size;
+
+ return cache;
+}
+
+static void
+ia64_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct ia64_frame_cache *cache =
+ ia64_frame_cache (next_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp);
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "regular frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
+ paddr_nz (this_id->code_addr),
+ paddr_nz (this_id->stack_addr),
+ paddr_nz (cache->bsp), next_frame);
+}
+
+static void
+ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct ia64_frame_cache *cache =
+ ia64_frame_cache (next_frame, this_cache);
+ char dummy_valp[MAX_REGISTER_SIZE];
+ char buf[8];
+
+ gdb_assert (regnum >= 0);
+
+ if (!target_has_registers)
+ error ("No registers.");
+
+ *optimizedp = 0;
+ *addrp = 0;
+ *lvalp = not_lval;
+ *realnump = -1;
+
+ /* Rather than check each time if valuep is non-null, supply a dummy buffer
+ when valuep is not supplied. */
+ if (!valuep)
+ valuep = dummy_valp;
+
+ memset (valuep, 0, register_size (current_gdbarch, regnum));
+
+ if (regnum == SP_REGNUM)
+ {
+ /* Handle SP values for all frames but the topmost. */
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ cache->base);
+ }
+ else if (regnum == IA64_BSP_REGNUM)
+ {
+ char cfm_valuep[MAX_REGISTER_SIZE];
+ int cfm_optim;
+ int cfm_realnum;
+ enum lval_type cfm_lval;
+ CORE_ADDR cfm_addr;
+ CORE_ADDR bsp, prev_cfm, prev_bsp;
+
+ /* We want to calculate the previous bsp as the end of the previous register stack frame.
+ This corresponds to what the hardware bsp register will be if we pop the frame
+ back which is why we might have been called. We know the beginning of the current
+ frame is cache->bsp - cache->sof. This value in the previous frame points to
+ the start of the output registers. We can calculate the end of that frame by adding
+ the size of output (sof (size of frame) - sol (size of locals)). */
+ ia64_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
+ &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep);
+ prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
+
+ bsp = rse_address_add (cache->bsp, -(cache->sof));
+ prev_bsp = rse_address_add (bsp, (prev_cfm & 0x7f) - ((prev_cfm >> 7) & 0x7f));
+
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ prev_bsp);
+ }
+ else if (regnum == IA64_CFM_REGNUM)
+ {
+ CORE_ADDR addr = cache->saved_regs[IA64_CFM_REGNUM];
+
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, valuep, register_size (current_gdbarch, regnum));
+ }
+ else if (cache->prev_cfm)
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), cache->prev_cfm);
+ else if (cache->frameless)
+ {
+ CORE_ADDR cfm = 0;
+ frame_unwind_register (next_frame, IA64_PFS_REGNUM, valuep);
+ }
+ }
+ else if (regnum == IA64_VFP_REGNUM)
+ {
+ /* If the function in question uses an automatic register (r32-r127)
+ for the frame pointer, it'll be found by ia64_find_saved_register()
+ above. If the function lacks one of these frame pointers, we can
+ still provide a value since we know the size of the frame. */
+ CORE_ADDR vfp = cache->base;
+ store_unsigned_integer (valuep, register_size (current_gdbarch, IA64_VFP_REGNUM), vfp);
+ }
+ else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ char pr_valuep[MAX_REGISTER_SIZE];
+ int pr_optim;
+ int pr_realnum;
+ enum lval_type pr_lval;
+ CORE_ADDR pr_addr;
+ ULONGEST prN_val;
+ ia64_frame_prev_register (next_frame, this_cache, IA64_PR_REGNUM,
+ &pr_optim, &pr_lval, &pr_addr, &pr_realnum, pr_valuep);
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ int rrb_pr = (cache->cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = VP16_REGNUM
+ + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+ }
+ prN_val = extract_bit_field ((unsigned char *) pr_valuep,
+ regnum - VP0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
+ {
+ char unat_valuep[MAX_REGISTER_SIZE];
+ int unat_optim;
+ int unat_realnum;
+ enum lval_type unat_lval;
+ CORE_ADDR unat_addr;
+ ULONGEST unatN_val;
+ ia64_frame_prev_register (next_frame, this_cache, IA64_UNAT_REGNUM,
+ &unat_optim, &unat_lval, &unat_addr, &unat_realnum, unat_valuep);
+ unatN_val = extract_bit_field ((unsigned char *) unat_valuep,
+ regnum - IA64_NAT0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ unatN_val);
+ }
+ else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ int natval = 0;
+ /* Find address of general register corresponding to nat bit we're
+ interested in. */
+ CORE_ADDR gr_addr;
+
+ gr_addr = cache->saved_regs[regnum - IA64_NAT0_REGNUM
+ + IA64_GR0_REGNUM];
+ if (gr_addr != 0)
+ {
+ /* Compute address of nat collection bits. */
+ CORE_ADDR nat_addr = gr_addr | 0x1f8;
+ CORE_ADDR bsp;
+ CORE_ADDR nat_collection;
+ int nat_bit;
+ /* If our nat collection address is bigger than bsp, we have to get
+ the nat collection from rnat. Otherwise, we fetch the nat
+ collection from the computed address. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+ if (nat_addr >= bsp)
+ {
+ frame_unwind_register (next_frame, IA64_RNAT_REGNUM, buf);
+ nat_collection = extract_unsigned_integer (buf, 8);
+ }
+ else
+ {
+ uint64_t tmp;
+ ia64_read_reg (nat_addr, &tmp, sizeof(tmp));
+ nat_collection = tmp;
+ }
+ nat_bit = (gr_addr >> 3) & 0x3f;
+ natval = (nat_collection >> nat_bit) & 1;
+ }
+
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), natval);
+ }
+ else if (regnum == IA64_IP_REGNUM)
+ {
+ CORE_ADDR pc = 0;
+ CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
+
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
+ pc = extract_unsigned_integer (buf, 8);
+ }
+ else if (cache->frameless)
+ {
+ frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf);
+ pc = extract_unsigned_integer (buf, 8);
+ }
+ pc &= ~0xf;
+ store_unsigned_integer (valuep, 8, pc);
+ }
+ else if (regnum == IA64_PSR_REGNUM)
+ {
+ /* We don't know how to get the complete previous PSR, but we need it for
+ the slot information when we unwind the pc (pc is formed of IP register
+ plus slot information from PSR). To get the previous slot information,
+ we mask it off the return address. */
+ ULONGEST slot_num = 0;
+ CORE_ADDR pc= 0;
+ CORE_ADDR psr = 0;
+ CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
+
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
+ pc = extract_unsigned_integer (buf, 8);
+ }
+ else if (cache->frameless)
+ {
+ CORE_ADDR pc;
+ frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf);
+ pc = extract_unsigned_integer (buf, 8);
+ }
+ psr &= ~(3LL << 41);
+ slot_num = pc & 0x3LL;
+ psr |= (CORE_ADDR)slot_num << 41;
+ store_unsigned_integer (valuep, 8, psr);
+ }
+ else if (regnum == IA64_BR0_REGNUM)
+ {
+ CORE_ADDR br0 = 0;
+ CORE_ADDR addr = cache->saved_regs[IA64_BR0_REGNUM];
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, buf, register_size (current_gdbarch, IA64_BR0_REGNUM));
+ br0 = extract_unsigned_integer (buf, 8);
+ }
+ store_unsigned_integer (valuep, 8, br0);
+ }
+ else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) ||
+ (regnum >= V32_REGNUM && regnum <= V127_REGNUM))
+ {
+ CORE_ADDR addr = 0;
+ if (regnum >= V32_REGNUM)
+ regnum = IA64_GR32_REGNUM + (regnum - V32_REGNUM);
+ addr = cache->saved_regs[regnum];
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, valuep, register_size (current_gdbarch, regnum));
+ }
+ else if (cache->frameless)
+ {
+ char r_valuep[MAX_REGISTER_SIZE];
+ int r_optim;
+ int r_realnum;
+ enum lval_type r_lval;
+ CORE_ADDR r_addr;
+ CORE_ADDR prev_cfm, prev_bsp, prev_bof;
+ CORE_ADDR addr = 0;
+
+ if (regnum >= V32_REGNUM)
+ regnum = IA64_GR32_REGNUM + (regnum - V32_REGNUM);
+ ia64_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
+ &r_optim, &r_lval, &r_addr, &r_realnum, r_valuep);
+ prev_cfm = extract_unsigned_integer (r_valuep, 8);
+ ia64_frame_prev_register (next_frame, this_cache, IA64_BSP_REGNUM,
+ &r_optim, &r_lval, &r_addr, &r_realnum, r_valuep);
+ prev_bsp = extract_unsigned_integer (r_valuep, 8);
+ prev_bof = rse_address_add (prev_bsp, -(prev_cfm & 0x7f));
+
+ addr = rse_address_add (prev_bof, (regnum - IA64_GR32_REGNUM));
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, valuep, register_size (current_gdbarch, regnum));
+ }
+ }
+ else
+ {
+ CORE_ADDR addr = 0;
+ if (IA64_FR32_REGNUM <= regnum && regnum <= IA64_FR127_REGNUM)
+ {
+ /* Fetch floating point register rename base from current
+ frame marker for this frame. */
+ int rrb_fr = (cache->cfm >> 25) & 0x7f;
+
+ /* Adjust the floating point register number to account for
+ register rotation. */
+ regnum = IA64_FR32_REGNUM
+ + ((regnum - IA64_FR32_REGNUM) + rrb_fr) % 96;
+ }
+
+ /* If we have stored a memory address, access the register. */
+ addr = cache->saved_regs[regnum];
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, valuep, register_size (current_gdbarch, regnum));
+ }
+ /* Otherwise, punt and get the current value of the register. */
+ else
+ frame_unwind_register (next_frame, regnum, valuep);
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "regular prev register <%d> <%s> is 0x%s\n", regnum,
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"),
+ paddr_nz (extract_unsigned_integer (valuep, 8)));
+}
+
+static const struct frame_unwind ia64_frame_unwind =
+{
+ NORMAL_FRAME,
+ &ia64_frame_this_id,
+ &ia64_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_frame_sniffer (struct frame_info *next_frame)
+{
+ return &ia64_frame_unwind;
+}
+
+/* Signal trampolines. */
+
+static void
+ia64_sigtramp_frame_init_saved_regs (struct ia64_frame_cache *cache)
+{
+ if (SIGCONTEXT_REGISTER_ADDRESS)
+ {
+ int regno;
+
+ cache->saved_regs[IA64_VRAP_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_IP_REGNUM);
+ cache->saved_regs[IA64_CFM_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_CFM_REGNUM);
+ cache->saved_regs[IA64_PSR_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_PSR_REGNUM);
+ cache->saved_regs[IA64_BSP_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_BSP_REGNUM);
+ cache->saved_regs[IA64_RNAT_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_RNAT_REGNUM);
+ cache->saved_regs[IA64_CCV_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_CCV_REGNUM);
+ cache->saved_regs[IA64_UNAT_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_UNAT_REGNUM);
+ cache->saved_regs[IA64_FPSR_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_FPSR_REGNUM);
+ cache->saved_regs[IA64_PFS_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_PFS_REGNUM);
+ cache->saved_regs[IA64_LC_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_LC_REGNUM);
+ for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++)
+ cache->saved_regs[regno] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
+ for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
+ cache->saved_regs[regno] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
+ for (regno = IA64_FR2_REGNUM; regno <= IA64_FR31_REGNUM; regno++)
+ cache->saved_regs[regno] =
+ SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
+ }
+}
+
+static struct ia64_frame_cache *
+ia64_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct ia64_frame_cache *cache;
+ CORE_ADDR addr;
+ char buf[8];
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = ia64_alloc_frame_cache ();
+
+ frame_unwind_register (next_frame, sp_regnum, buf);
+ /* Note that frame size is hard-coded below. We cannot calculate it
+ via prologue examination. */
+ cache->base = extract_unsigned_integer (buf, 8) + 16;
+
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ cache->bsp = extract_unsigned_integer (buf, 8);
+
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cache->cfm = extract_unsigned_integer (buf, 8);
+ cache->sof = cache->cfm & 0x7f;
+
+ ia64_sigtramp_frame_init_saved_regs (cache);
+
+ *this_cache = cache;
+ return cache;
+}
+
+static void
+ia64_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct ia64_frame_cache *cache =
+ ia64_sigtramp_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build_special (cache->base, frame_pc_unwind (next_frame), cache->bsp);
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "sigtramp frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
+ paddr_nz (this_id->code_addr),
+ paddr_nz (this_id->stack_addr),
+ paddr_nz (cache->bsp), next_frame);
+}
+
+static void
+ia64_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ char dummy_valp[MAX_REGISTER_SIZE];
+ char buf[MAX_REGISTER_SIZE];
+
+ struct ia64_frame_cache *cache =
+ ia64_sigtramp_frame_cache (next_frame, this_cache);
+
+ gdb_assert (regnum >= 0);
+
+ if (!target_has_registers)
+ error ("No registers.");
+
+ *optimizedp = 0;
+ *addrp = 0;
+ *lvalp = not_lval;
+ *realnump = -1;
+
+ /* Rather than check each time if valuep is non-null, supply a dummy buffer
+ when valuep is not supplied. */
+ if (!valuep)
+ valuep = dummy_valp;
+
+ memset (valuep, 0, register_size (current_gdbarch, regnum));
+
+ if (regnum == IA64_IP_REGNUM)
+ {
+ CORE_ADDR pc = 0;
+ CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
+
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
+ pc = extract_unsigned_integer (buf, 8);
+ }
+ pc &= ~0xf;
+ store_unsigned_integer (valuep, 8, pc);
+ }
+ else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) ||
+ (regnum >= V32_REGNUM && regnum <= V127_REGNUM))
+ {
+ CORE_ADDR addr = 0;
+ if (regnum >= V32_REGNUM)
+ regnum = IA64_GR32_REGNUM + (regnum - V32_REGNUM);
+ addr = cache->saved_regs[regnum];
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, valuep, register_size (current_gdbarch, regnum));
+ }
+ }
+ else
+ {
+ /* All other registers not listed above. */
+ CORE_ADDR addr = cache->saved_regs[regnum];
+ if (addr != 0)
+ {
+ *lvalp = lval_memory;
+ *addrp = addr;
+ ia64_read_reg (addr, valuep, register_size (current_gdbarch, regnum));
+ }
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "sigtramp prev register <%s> is 0x%s\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"),
+ paddr_nz (extract_unsigned_integer (valuep, 8)));
+}
+
+static const struct frame_unwind ia64_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ ia64_sigtramp_frame_this_id,
+ ia64_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ char *name;
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (PC_IN_SIGTRAMP (pc, name))
+ return &ia64_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+
+static CORE_ADDR
+ia64_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct ia64_frame_cache *cache =
+ ia64_frame_cache (next_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_base ia64_frame_base =
+{
+ &ia64_frame_unwind,
+ ia64_frame_base_address,
+ ia64_frame_base_address,
+ ia64_frame_base_address
+};
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+struct ia64_unwind_table_entry
+ {
+ unw_word_t start_offset;
+ unw_word_t end_offset;
+ unw_word_t info_offset;
+ };
+
+static __inline__ uint64_t
+ia64_rse_slot_num (uint64_t addr)
+{
+ return (addr >> 3) & 0x3f;
+}
+
+/* Skip over a designated number of registers in the backing
+ store, remembering every 64th position is for NAT. */
+static __inline__ uint64_t
+ia64_rse_skip_regs (uint64_t addr, long num_regs)
+{
+ long delta = ia64_rse_slot_num(addr) + num_regs;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ return addr + ((num_regs + delta/0x3f) << 3);
+}
+
+/* Gdb libunwind-frame callback function to convert from an ia64 gdb register
+ number to a libunwind register number. */
+static int
+ia64_gdb2uw_regnum (int regnum)
+{
+ if (regnum == sp_regnum)
+ return UNW_IA64_SP;
+ else if (regnum == IA64_BSP_REGNUM)
+ return UNW_IA64_BSP;
+ else if ((unsigned) (regnum - IA64_GR0_REGNUM) < 128)
+ return UNW_IA64_GR + (regnum - IA64_GR0_REGNUM);
+ else if ((unsigned) (regnum - V32_REGNUM) < 95)
+ return UNW_IA64_GR + 32 + (regnum - V32_REGNUM);
+ else if ((unsigned) (regnum - IA64_FR0_REGNUM) < 128)
+ return UNW_IA64_FR + (regnum - IA64_FR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_PR0_REGNUM) < 64)
+ return -1;
+ else if ((unsigned) (regnum - IA64_BR0_REGNUM) < 8)
+ return UNW_IA64_BR + (regnum - IA64_BR0_REGNUM);
+ else if (regnum == IA64_PR_REGNUM)
+ return UNW_IA64_PR;
+ else if (regnum == IA64_IP_REGNUM)
+ return UNW_REG_IP;
+ else if (regnum == IA64_CFM_REGNUM)
+ return UNW_IA64_CFM;
+ else if ((unsigned) (regnum - IA64_AR0_REGNUM) < 128)
+ return UNW_IA64_AR + (regnum - IA64_AR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_NAT0_REGNUM) < 128)
+ return UNW_IA64_NAT + (regnum - IA64_NAT0_REGNUM);
+ else
+ return -1;
+}
+
+/* Gdb libunwind-frame callback function to convert from a libunwind register
+ number to a ia64 gdb register number. */
+static int
+ia64_uw2gdb_regnum (int uw_regnum)
+{
+ if (uw_regnum == UNW_IA64_SP)
+ return sp_regnum;
+ else if (uw_regnum == UNW_IA64_BSP)
+ return IA64_BSP_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 32)
+ return IA64_GR0_REGNUM + (uw_regnum - UNW_IA64_GR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 128)
+ return V32_REGNUM + (uw_regnum - (IA64_GR0_REGNUM + 32));
+ else if ((unsigned) (uw_regnum - UNW_IA64_FR) < 128)
+ return IA64_FR0_REGNUM + (uw_regnum - UNW_IA64_FR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_BR) < 8)
+ return IA64_BR0_REGNUM + (uw_regnum - UNW_IA64_BR);
+ else if (uw_regnum == UNW_IA64_PR)
+ return IA64_PR_REGNUM;
+ else if (uw_regnum == UNW_REG_IP)
+ return IA64_IP_REGNUM;
+ else if (uw_regnum == UNW_IA64_CFM)
+ return IA64_CFM_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_AR) < 128)
+ return IA64_AR0_REGNUM + (uw_regnum - UNW_IA64_AR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_NAT) < 128)
+ return IA64_NAT0_REGNUM + (uw_regnum - UNW_IA64_NAT);
+ else
+ return -1;
+}
+
+/* Gdb libunwind-frame callback function to reveal if register is a float
+ register or not. */
+static int
+ia64_is_fpreg (int uw_regnum)
+{
+ return unw_is_fpreg (uw_regnum);
+}
+
+/* Libunwind callback accessor function for general registers. */
+static int
+ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+ unw_word_t bsp, sof, sol, cfm, psr, ip;
+ struct frame_info *next_frame = arg;
+ long new_sof, old_sof;
+ char buf[MAX_REGISTER_SIZE];
+
+ if (write)
+ {
+ if (regnum < 0)
+ /* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI. */
+ return 0;
+
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ ia64_write_pc (*val, inferior_ptid);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ write_register (IA64_BSP_REGNUM, *val);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ case UNW_IA64_BSP:
+ /* Account for the fact that ptrace() expects bsp to point
+ after the current register frame. */
+ cfm = read_register (IA64_CFM_REGNUM);
+ sof = (cfm & 0x7f);
+ bsp = ia64_rse_skip_regs (*val, sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ break;
+
+ case UNW_IA64_CFM:
+ /* If we change CFM, we need to adjust ptrace's notion of
+ bsp accordingly, so that the real bsp remains
+ unchanged. */
+ bsp = read_register (IA64_BSP_REGNUM);
+ cfm = read_register (IA64_CFM_REGNUM);
+ old_sof = (cfm & 0x7f);
+ new_sof = (*val & 0x7f);
+ if (old_sof != new_sof)
+ {
+ bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ }
+ write_register (IA64_CFM_REGNUM, *val);
+ break;
+
+ default:
+ write_register (regnum, *val);
+ break;
+ }
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: to cache: %4s=0x%s\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"),
+ paddr_nz (*val));
+ }
+ else
+ {
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ /* Libunwind expects to see the pc value which means the slot number
+ from the psr must be merged with the ip word address. */
+ frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
+ ip = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+ *val = ip | ((psr >> 41) & 0x3);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ /* Libunwind expects to see the beginning of the current register
+ frame so we must account for the fact that ptrace() will return a value
+ for bsp that points *after* the current register frame. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ sof = (cfm & 0x7f);
+ *val = ia64_rse_skip_regs (bsp, -sof);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ /* Libunwind wants bspstore to be after the current register frame.
+ This is what ptrace() and gdb treats as the regular bsp value. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+
+ default:
+ /* For all other registers, just unwind the value directly. */
+ frame_unwind_register (next_frame, regnum, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: from cache: %4s=0x%s\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"),
+ paddr_nz (*val));
+ }
+ return 0;
+}
+
+/* Libunwind callback accessor function for floating-point registers. */
+static int
+ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+
+ if (write)
+ regcache_cooked_write (current_regcache, regnum, (char *) val);
+ else
+ regcache_cooked_read (current_regcache, regnum, (char *) val);
+ return 0;
+}
+
+/* Libunwind callback accessor function for accessing memory. */
+static int
+ia64_access_mem (unw_addr_space_t as,
+ unw_word_t addr, unw_word_t *val,
+ int write, void *arg)
+{
+ /* XXX do we need to normalize byte-order here? */
+ if (write)
+ return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
+ else
+ return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
+}
+
+/* Call low-level function to access the kernel unwind table. */
+static int
+getunwind_table (void *buf, size_t len)
+{
+ LONGEST x;
+ x = target_read_partial (&current_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
+ buf, 0, len);
+
+ return (int)x;
+}
+
+/* Get the kernel unwind table. */
+static int
+get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
+{
+ size_t size;
+ struct ia64_table_entry
+ {
+ uint64_t start_offset;
+ uint64_t end_offset;
+ uint64_t info_offset;
+ };
+ static struct ia64_table_entry *ktab = NULL, *etab;
+
+ if (!ktab)
+ {
+ size = getunwind_table (NULL, 0);
+ if ((int)size < 0)
+ return -UNW_ENOINFO;
+ ktab = xmalloc (size);
+ getunwind_table (ktab, size);
+
+ /* Determine length of kernel's unwind table and relocate
+ it's entries. */
+ for (etab = ktab; etab->start_offset; ++etab)
+ etab->info_offset += (uint64_t) ktab;
+ }
+
+ if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
+ return -UNW_ENOINFO;
+
+ di->format = UNW_INFO_FORMAT_TABLE;
+ di->gp = 0;
+ di->start_ip = ktab[0].start_offset;
+ di->end_ip = etab[-1].end_offset;
+ di->u.ti.name_ptr = (unw_word_t) "<kernel>";
+ di->u.ti.segbase = 0;
+ di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
+ di->u.ti.table_data = (unw_word_t *) ktab;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
+ "segbase=0x%s, length=%s, gp=0x%s\n",
+ (char *) di->u.ti.name_ptr,
+ paddr_nz (di->u.ti.segbase),
+ paddr_u (di->u.ti.table_len),
+ paddr_nz (di->gp));
+ return 0;
+}
+
+/* Find the unwind table entry for a specified address. */
+static int
+ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
+ unw_dyn_info_t *dip, void **buf)
+{
+ Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
+ Elf_Internal_Ehdr *ehdr;
+ unw_word_t segbase = 0;
+ CORE_ADDR load_base;
+ bfd *bfd;
+ int i;
+
+ bfd = objfile->obfd;
+
+ ehdr = elf_tdata (bfd)->elf_header;
+ phdr = elf_tdata (bfd)->phdr;
+
+ load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ {
+ switch (phdr[i].p_type)
+ {
+ case PT_LOAD:
+ if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
+ < phdr[i].p_memsz)
+ p_text = phdr + i;
+ break;
+
+ case PT_IA_64_UNWIND:
+ p_unwind = phdr + i;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!p_text || !p_unwind
+ /* Verify that the segment that contains the IP also contains
+ the static unwind table. If not, we are dealing with
+ runtime-generated code, for which we have no info here. */
+ || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
+ return -UNW_ENOINFO;
+
+ segbase = p_text->p_vaddr + load_base;
+
+ dip->start_ip = segbase;
+ dip->end_ip = dip->start_ip + p_text->p_memsz;
+ dip->gp = FIND_GLOBAL_POINTER (ip);
+ dip->format = UNW_INFO_FORMAT_REMOTE_TABLE;
+ dip->u.rti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+ dip->u.rti.segbase = segbase;
+ dip->u.rti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+ dip->u.rti.table_data = p_unwind->p_vaddr + load_base;
+
+ return 0;
+}
+
+/* Libunwind callback accessor function to acquire procedure unwind-info. */
+static int
+ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ struct obj_section *sec = find_pc_section (ip);
+ unw_dyn_info_t di;
+ int ret;
+ void *buf = NULL;
+
+ if (!sec)
+ {
+ /* XXX This only works if the host and the target architecture are
+ both ia64 and if the have (more or less) the same kernel
+ version. */
+ if (get_kernel_table (ip, &di) < 0)
+ return -UNW_ENOINFO;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: 0x%s -> "
+ "(name=`%s',segbase=0x%s,start=0x%s,end=0x%s,gp=0x%s,"
+ "length=%s,data=0x%s)\n",
+ paddr_nz (ip), (char *)di.u.ti.name_ptr,
+ paddr_nz (di.u.ti.segbase),
+ paddr_nz (di.start_ip), paddr_nz (di.end_ip),
+ paddr_nz (di.gp),
+ paddr_u (di.u.ti.table_len),
+ paddr_nz ((CORE_ADDR)di.u.ti.table_data));
+ }
+ else
+ {
+ ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
+ if (ret < 0)
+ return ret;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: 0x%s -> "
+ "(name=`%s',segbase=0x%s,start=0x%s,end=0x%s,gp=0x%s,"
+ "length=%s,data=0x%s)\n",
+ paddr_nz (ip), (char *)di.u.rti.name_ptr,
+ paddr_nz (di.u.rti.segbase),
+ paddr_nz (di.start_ip), paddr_nz (di.end_ip),
+ paddr_nz (di.gp),
+ paddr_u (di.u.rti.table_len),
+ paddr_nz (di.u.rti.table_data));
+ }
+
+ ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info,
+ arg);
+
+ /* We no longer need the dyn info storage so free it. */
+ xfree (buf);
+
+ return ret;
+}
+
+/* Libunwind callback accessor function for cleanup. */
+static void
+ia64_put_unwind_info (unw_addr_space_t as,
+ unw_proc_info_t *pip, void *arg)
+{
+ /* Nothing required for now. */
+}
+
+/* Libunwind callback accessor function to get head of the dynamic
+ unwind-info registration list. */
+static int
+ia64_get_dyn_info_list (unw_addr_space_t as,
+ unw_word_t *dilap, void *arg)
+{
+ struct obj_section *text_sec;
+ struct objfile *objfile;
+ unw_word_t ip, addr;
+ unw_dyn_info_t di;
+ int ret;
+
+ if (!libunwind_is_initialized ())
+ return -UNW_ENOINFO;
+
+ for (objfile = object_files; objfile; objfile = objfile->next)
+ {
+ void *buf = NULL;
+
+ text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
+ ip = text_sec->addr;
+ ret = ia64_find_unwind_table (objfile, ip, &di, &buf);
+ if (ret >= 0)
+ {
+ addr = libunwind_find_dyn_list (as, &di, arg);
+ /* We no longer need the dyn info storage so free it. */
+ xfree (buf);
+
+ if (addr)
+ {
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "dynamic unwind table in objfile %s "
+ "at 0x%s (gp=0x%s)\n",
+ bfd_get_filename (objfile->obfd),
+ paddr_nz (addr), paddr_nz (di.gp));
+ *dilap = addr;
+ return 0;
+ }
+ }
+ }
+ return -UNW_ENOINFO;
+}
+
+
+/* Frame interface functions for libunwind. */
+
+static void
+ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ char buf[8];
+ CORE_ADDR bsp;
+ struct frame_id id;
+
+ libunwind_frame_this_id (next_frame, this_cache, &id);
+
+ /* We must add the bsp as the special address for frame comparison purposes. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+
+ (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
+ paddr_nz (id.code_addr), paddr_nz (id.stack_addr),
+ paddr_nz (bsp), next_frame);
+}
+
+static void
+ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ int reg = regnum;
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ reg = IA64_PR_REGNUM;
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ reg = IA64_UNAT_REGNUM;
+
+ /* Let libunwind do most of the work. */
+ libunwind_frame_prev_register (next_frame, this_cache, reg,
+ optimizedp, lvalp, addrp, realnump, valuep);
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ ULONGEST prN_val;
+
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ int rrb_pr = 0;
+ ULONGEST cfm;
+ unsigned char buf[MAX_REGISTER_SIZE];
+
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ rrb_pr = (cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = VP16_REGNUM
+ + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+ }
+ prN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - VP0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ ULONGEST unatN_val;
+
+ unatN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - IA64_NAT0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ unatN_val);
+ }
+ else if (regnum == IA64_BSP_REGNUM)
+ {
+ char cfm_valuep[MAX_REGISTER_SIZE];
+ int cfm_optim;
+ int cfm_realnum;
+ enum lval_type cfm_lval;
+ CORE_ADDR cfm_addr;
+ CORE_ADDR bsp, prev_cfm, prev_bsp;
+
+ /* We want to calculate the previous bsp as the end of the previous register stack frame.
+ This corresponds to what the hardware bsp register will be if we pop the frame
+ back which is why we might have been called. We know that libunwind will pass us back
+ the beginning of the current frame so we should just add sof to it. */
+ prev_bsp = extract_unsigned_integer (valuep, 8);
+ libunwind_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
+ &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep);
+ prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
+ prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
+
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ prev_bsp);
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind prev register <%s> is 0x%s\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"),
+ paddr_nz (extract_unsigned_integer (valuep, 8)));
+}
+
+static const struct frame_unwind ia64_libunwind_frame_unwind =
+{
+ NORMAL_FRAME,
+ ia64_libunwind_frame_this_id,
+ ia64_libunwind_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
+{
+ if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame))
+ return &ia64_libunwind_frame_unwind;
+
+ return NULL;
+}
+
+/* Set of libunwind callback acccessor functions. */
+static unw_accessors_t ia64_unw_accessors =
+{
+ ia64_find_proc_info_x,
+ ia64_put_unwind_info,
+ ia64_get_dyn_info_list,
+ ia64_access_mem,
+ ia64_access_reg,
+ ia64_access_fpreg,
+ /* resume */
+ /* get_proc_name */
+};
+
+/* Set of ia64 gdb libunwind-frame callbacks and data for generic libunwind-frame code to use. */
+static struct libunwind_descr ia64_libunwind_descr =
+{
+ ia64_gdb2uw_regnum,
+ ia64_uw2gdb_regnum,
+ ia64_is_fpreg,
+ &ia64_unw_accessors,
+};
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
+/* Should we use DEPRECATED_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). */
+int
+ia64_use_struct_convention (int gcc_p, struct type *type)
+{
+ struct type *float_elt_type;
+
+ /* HFAs are structures (or arrays) consisting entirely of floating
+ point values of the same length. Up to 8 of these are returned
+ in registers. Don't use the struct convention when this is the
+ case. */
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL
+ && TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type) <= 8)
+ return 0;
+
+ /* Other structs of length 32 or less are returned in r8-r11.
+ Don't use the struct convention for those either. */
+ return TYPE_LENGTH (type) > 32;
+}
+
+void
+ia64_extract_return_value (struct type *type, struct regcache *regcache, void *valbuf)
+{
+ struct type *float_elt_type;
+
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL)
+ {
+ char from[MAX_REGISTER_SIZE];
+ int offset = 0;
+ int regnum = IA64_FR8_REGNUM;
+ int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type);
+
+ while (n-- > 0)
+ {
+ regcache_cooked_read (regcache, regnum, from);
+ convert_typed_floating (from, builtin_type_ia64_ext,
+ (char *)valbuf + offset, float_elt_type);
+ offset += TYPE_LENGTH (float_elt_type);
+ regnum++;
+ }
+ }
+ else
+ {
+ ULONGEST val;
+ int offset = 0;
+ int regnum = IA64_GR8_REGNUM;
+ int reglen = TYPE_LENGTH (ia64_register_type (NULL, IA64_GR8_REGNUM));
+ int n = TYPE_LENGTH (type) / reglen;
+ int m = TYPE_LENGTH (type) % reglen;
+
+ while (n-- > 0)
+ {
+ ULONGEST val;
+ regcache_cooked_read_unsigned (regcache, regnum, &val);
+ memcpy ((char *)valbuf + offset, &val, reglen);
+ offset += reglen;
+ regnum++;
+ }
+
+ if (m)
+ {
+ regcache_cooked_read_unsigned (regcache, regnum, &val);
+ memcpy ((char *)valbuf + offset, &val, m);
+ }
+ }
+}
+
+CORE_ADDR
+ia64_extract_struct_value_address (struct regcache *regcache)
+{
+ error ("ia64_extract_struct_value_address called and cannot get struct value address");
+ return 0;
+}
+
+
+static int
+is_float_or_hfa_type_recurse (struct type *t, struct type **etp)
+{
+ switch (TYPE_CODE (t))
+ {
+ case TYPE_CODE_FLT:
+ if (*etp)
+ return TYPE_LENGTH (*etp) == TYPE_LENGTH (t);
+ else
+ {
+ *etp = t;
+ return 1;
+ }
+ break;
+ case TYPE_CODE_ARRAY:
+ return
+ is_float_or_hfa_type_recurse (check_typedef (TYPE_TARGET_TYPE (t)),
+ etp);
+ break;
+ case TYPE_CODE_STRUCT:
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (t); i++)
+ if (!is_float_or_hfa_type_recurse
+ (check_typedef (TYPE_FIELD_TYPE (t, i)), etp))
+ return 0;
+ return 1;
+ }
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+/* Determine if the given type is one of the floating point types or
+ and HFA (which is a struct, array, or combination thereof whose
+ bottom-most elements are all of the same floating point type). */
+
+static struct type *
+is_float_or_hfa_type (struct type *t)
+{
+ struct type *et = 0;
+
+ return is_float_or_hfa_type_recurse (t, &et) ? et : 0;
+}
+
+
+/* Return 1 if the alignment of T is such that the next even slot
+ should be used. Return 0, if the next available slot should
+ be used. (See section 8.5.1 of the IA-64 Software Conventions
+ and Runtime manual). */
+
+static int
+slot_alignment_is_next_even (struct type *t)
+{
+ switch (TYPE_CODE (t))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ if (TYPE_LENGTH (t) > 8)
+ return 1;
+ else
+ return 0;
+ case TYPE_CODE_ARRAY:
+ return
+ slot_alignment_is_next_even (check_typedef (TYPE_TARGET_TYPE (t)));
+ case TYPE_CODE_STRUCT:
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (t); i++)
+ if (slot_alignment_is_next_even
+ (check_typedef (TYPE_FIELD_TYPE (t, i))))
+ return 1;
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+/* Attempt to find (and return) the global pointer for the given
+ function.
+
+ This is a rather nasty bit of code searchs for the .dynamic section
+ in the objfile corresponding to the pc of the function we're trying
+ to call. Once it finds the addresses at which the .dynamic section
+ lives in the child process, it scans the Elf64_Dyn entries for a
+ DT_PLTGOT tag. If it finds one of these, the corresponding
+ d_un.d_ptr value is the global pointer. */
+
+CORE_ADDR
+ia64_generic_find_global_pointer (CORE_ADDR faddr)
+{
+ struct obj_section *faddr_sect;
+
+ faddr_sect = find_pc_section (faddr);
+ if (faddr_sect != NULL)
+ {
+ struct obj_section *osect;
+
+ ALL_OBJFILE_OSECTIONS (faddr_sect->objfile, osect)
+ {
+ if (strcmp (osect->the_bfd_section->name, ".dynamic") == 0)
+ break;
+ }
+
+ if (osect < faddr_sect->objfile->sections_end)
+ {
+ CORE_ADDR addr;
+
+ addr = osect->addr;
+ while (addr < osect->endaddr)
+ {
+ int status;
+ LONGEST tag;
+ char buf[8];
+
+ status = target_read_memory (addr, buf, sizeof (buf));
+ if (status != 0)
+ break;
+ tag = extract_signed_integer (buf, sizeof (buf));
+
+ if (tag == DT_PLTGOT)
+ {
+ CORE_ADDR global_pointer;
+
+ status = target_read_memory (addr + 8, buf, sizeof (buf));
+ if (status != 0)
+ break;
+ global_pointer = extract_unsigned_integer (buf, sizeof (buf));
+
+ /* The payoff... */
+ return global_pointer;
+ }
+
+ if (tag == DT_NULL)
+ break;
+
+ addr += 16;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Given a function's address, attempt to find (and return) the
+ corresponding (canonical) function descriptor. Return 0 if
+ not found. */
+static CORE_ADDR
+find_extant_func_descr (CORE_ADDR faddr)
+{
+ struct obj_section *faddr_sect;
+
+ /* Return early if faddr is already a function descriptor. */
+ faddr_sect = find_pc_section (faddr);
+ if (faddr_sect && strcmp (faddr_sect->the_bfd_section->name, ".opd") == 0)
+ return faddr;
+
+ if (faddr_sect != NULL)
+ {
+ struct obj_section *osect;
+ ALL_OBJFILE_OSECTIONS (faddr_sect->objfile, osect)
+ {
+ if (strcmp (osect->the_bfd_section->name, ".opd") == 0)
+ break;
+ }
+
+ if (osect < faddr_sect->objfile->sections_end)
+ {
+ CORE_ADDR addr;
+
+ addr = osect->addr;
+ while (addr < osect->endaddr)
+ {
+ int status;
+ LONGEST faddr2;
+ char buf[8];
+
+ status = target_read_memory (addr, buf, sizeof (buf));
+ if (status != 0)
+ break;
+ faddr2 = extract_signed_integer (buf, sizeof (buf));
+
+ if (faddr == faddr2)
+ return addr;
+
+ addr += 16;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Attempt to find a function descriptor corresponding to the
+ given address. If none is found, construct one on the
+ stack using the address at fdaptr. */
+
+static CORE_ADDR
+find_func_descr (CORE_ADDR faddr, CORE_ADDR *fdaptr)
+{
+ CORE_ADDR fdesc;
+
+ fdesc = find_extant_func_descr (faddr);
+
+ if (fdesc == 0)
+ {
+ CORE_ADDR global_pointer;
+ char buf[16];
+
+ fdesc = *fdaptr;
+ *fdaptr += 16;
+
+ global_pointer = FIND_GLOBAL_POINTER (faddr);
+
+ if (global_pointer == 0)
+ global_pointer = read_register (IA64_GR1_REGNUM);
+
+ store_unsigned_integer (buf, 8, faddr);
+ store_unsigned_integer (buf + 8, 8, global_pointer);
+
+ write_memory (fdesc, buf, 16);
+ }
+
+ return fdesc;
+}
+
+/* Use the following routine when printing out function pointers
+ so the user can see the function address rather than just the
+ function descriptor. */
+static CORE_ADDR
+ia64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ struct obj_section *s;
+
+ s = find_pc_section (addr);
+
+ /* check if ADDR points to a function descriptor. */
+ if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
+ return read_memory_unsigned_integer (addr, 8);
+
+ return addr;
+}
+
+static CORE_ADDR
+ia64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+ return sp & ~0xfLL;
+}
+
+static CORE_ADDR
+ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int argno;
+ struct value *arg;
+ struct type *type;
+ int len, argoffset;
+ int nslots, rseslots, memslots, slotnum, nfuncargs;
+ int floatreg;
+ CORE_ADDR bsp, cfm, pfs, new_bsp, funcdescaddr, pc, global_pointer;
+
+ nslots = 0;
+ nfuncargs = 0;
+ /* Count the number of slots needed for the arguments. */
+ for (argno = 0; argno < nargs; argno++)
+ {
+ arg = args[argno];
+ type = check_typedef (VALUE_TYPE (arg));
+ len = TYPE_LENGTH (type);
+
+ if ((nslots & 1) && slot_alignment_is_next_even (type))
+ nslots++;
+
+ if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+ nfuncargs++;
+
+ nslots += (len + 7) / 8;
+ }
+
+ /* Divvy up the slots between the RSE and the memory stack. */
+ rseslots = (nslots > 8) ? 8 : nslots;
+ memslots = nslots - rseslots;
+
+ /* Allocate a new RSE frame. */
+ cfm = read_register (IA64_CFM_REGNUM);
+
+ bsp = read_register (IA64_BSP_REGNUM);
+ new_bsp = rse_address_add (bsp, rseslots);
+ write_register (IA64_BSP_REGNUM, new_bsp);
+
+ pfs = read_register (IA64_PFS_REGNUM);
+ pfs &= 0xc000000000000000LL;
+ pfs |= (cfm & 0xffffffffffffLL);
+ write_register (IA64_PFS_REGNUM, pfs);
+
+ cfm &= 0xc000000000000000LL;
+ cfm |= rseslots;
+ write_register (IA64_CFM_REGNUM, cfm);
+
+ /* We will attempt to find function descriptors in the .opd segment,
+ but if we can't we'll construct them ourselves. That being the
+ case, we'll need to reserve space on the stack for them. */
+ funcdescaddr = sp - nfuncargs * 16;
+ funcdescaddr &= ~0xfLL;
+
+ /* Adjust the stack pointer to it's new value. The calling conventions
+ require us to have 16 bytes of scratch, plus whatever space is
+ necessary for the memory slots and our function descriptors. */
+ sp = sp - 16 - (memslots + nfuncargs) * 8;
+ sp &= ~0xfLL; /* Maintain 16 byte alignment. */
+
+ /* Place the arguments where they belong. The arguments will be
+ either placed in the RSE backing store or on the memory stack.
+ In addition, floating point arguments or HFAs are placed in
+ floating point registers. */
+ slotnum = 0;
+ floatreg = IA64_FR8_REGNUM;
+ for (argno = 0; argno < nargs; argno++)
+ {
+ struct type *float_elt_type;
+
+ arg = args[argno];
+ type = check_typedef (VALUE_TYPE (arg));
+ len = TYPE_LENGTH (type);
+
+ /* Special handling for function parameters. */
+ if (len == 8
+ && TYPE_CODE (type) == TYPE_CODE_PTR
+ && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
+ {
+ char val_buf[8];
+
+ store_unsigned_integer (val_buf, 8,
+ find_func_descr (extract_unsigned_integer (VALUE_CONTENTS (arg), 8),
+ &funcdescaddr));
+ if (slotnum < rseslots)
+ write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+ else
+ write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
+ slotnum++;
+ continue;
+ }
+
+ /* Normal slots. */
+
+ /* Skip odd slot if necessary... */
+ if ((slotnum & 1) && slot_alignment_is_next_even (type))
+ slotnum++;
+
+ argoffset = 0;
+ while (len > 0)
+ {
+ char val_buf[8];
+
+ memset (val_buf, 0, 8);
+ memcpy (val_buf, VALUE_CONTENTS (arg) + argoffset, (len > 8) ? 8 : len);
+
+ if (slotnum < rseslots)
+ write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+ else
+ write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
+
+ argoffset += 8;
+ len -= 8;
+ slotnum++;
+ }
+
+ /* Handle floating point types (including HFAs). */
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL)
+ {
+ argoffset = 0;
+ len = TYPE_LENGTH (type);
+ while (len > 0 && floatreg < IA64_FR16_REGNUM)
+ {
+ char to[MAX_REGISTER_SIZE];
+ convert_typed_floating (VALUE_CONTENTS (arg) + argoffset, float_elt_type,
+ to, builtin_type_ia64_ext);
+ regcache_cooked_write (regcache, floatreg, (void *)to);
+ floatreg++;
+ argoffset += TYPE_LENGTH (float_elt_type);
+ len -= TYPE_LENGTH (float_elt_type);
+ }
+ }
+ }
+
+ /* Store the struct return value in r8 if necessary. */
+ if (struct_return)
+ {
+ regcache_cooked_write_unsigned (regcache, IA64_GR8_REGNUM, (ULONGEST)struct_addr);
+ }
+
+ global_pointer = FIND_GLOBAL_POINTER (func_addr);
+
+ if (global_pointer != 0)
+ write_register (IA64_GR1_REGNUM, global_pointer);
+
+ write_register (IA64_BR0_REGNUM, bp_addr);
+
+ write_register (sp_regnum, sp);
+
+ return sp;
+}
+
+static struct frame_id
+ia64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ char buf[8];
+ CORE_ADDR sp, bsp;
+
+ frame_unwind_register (next_frame, sp_regnum, buf);
+ sp = extract_unsigned_integer (buf, 8);
+
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "dummy frame id: code 0x%s, stack 0x%s, special 0x%s\n",
+ paddr_nz (frame_pc_unwind (next_frame)),
+ paddr_nz (sp), paddr_nz (bsp));
+
+ return frame_id_build_special (sp, frame_pc_unwind (next_frame), bsp);
+}
+
+static CORE_ADDR
+ia64_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ char buf[8];
+ CORE_ADDR ip, psr, pc;
+
+ frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
+ ip = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+
+ pc = (ip & ~0xf) | ((psr >> 41) & 3);
+ return pc;
+}
+
+static void
+ia64_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf)
+{
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ char to[MAX_REGISTER_SIZE];
+ convert_typed_floating (valbuf, type, to, builtin_type_ia64_ext);
+ regcache_cooked_write (regcache, IA64_FR8_REGNUM, (void *)to);
+ target_store_registers (IA64_FR8_REGNUM);
+ }
+ else
+ regcache_cooked_write (regcache, IA64_GR8_REGNUM, valbuf);
+}
+
+static void
+ia64_remote_translate_xfer_address (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR memaddr, int nr_bytes,
+ CORE_ADDR *targ_addr, int *targ_len)
+{
+ *targ_addr = memaddr;
+ *targ_len = nr_bytes;
+}
+
+static int
+ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info)
+{
+ info->bytes_per_line = SLOT_MULTIPLIER;
+ return print_insn_ia64 (memaddr, info);
+}
+
+static struct gdbarch *
+ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->osabi = info.osabi;
+ tdep->sigcontext_register_address = NULL;
+ tdep->find_global_pointer = ia64_generic_find_global_pointer;
+
+ /* Define the ia64 floating-point format to gdb. */
+ builtin_type_ia64_ext =
+ init_type (TYPE_CODE_FLT, 128 / 8,
+ 0, "builtin_type_ia64_ext", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ia64_ext) = &floatformat_ia64_ext;
+
+ /* According to the ia64 specs, instructions that store long double
+ floats in memory use a long-double format different than that
+ used in the floating registers. The memory format matches the
+ x86 extended float format which is 80 bits. An OS may choose to
+ use this format (e.g. GNU/Linux) or choose to use a different
+ format for storing long doubles (e.g. HPUX). In the latter case,
+ the setting of the format may be moved/overridden in an
+ OS-specific tdep file. */
+ set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
+
+ set_gdbarch_short_bit (gdbarch, 16);
+ set_gdbarch_int_bit (gdbarch, 32);
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_float_bit (gdbarch, 32);
+ set_gdbarch_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_bit (gdbarch, 128);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+
+ set_gdbarch_num_regs (gdbarch, NUM_IA64_RAW_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, LAST_PSEUDO_REGNUM - FIRST_PSEUDO_REGNUM);
+ set_gdbarch_sp_regnum (gdbarch, sp_regnum);
+ set_gdbarch_fp0_regnum (gdbarch, IA64_FR0_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, ia64_register_name);
+ /* FIXME: Following interface should not be needed, however, without it recurse.exp
+ gets a number of extra failures. */
+ set_gdbarch_deprecated_register_size (gdbarch, 8);
+ set_gdbarch_register_type (gdbarch, ia64_register_type);
+
+ set_gdbarch_pseudo_register_read (gdbarch, ia64_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, ia64_pseudo_register_write);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, ia64_dwarf_reg_to_regnum);
+ set_gdbarch_register_reggroup_p (gdbarch, ia64_register_reggroup_p);
+ set_gdbarch_convert_register_p (gdbarch, ia64_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, ia64_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, ia64_value_to_register);
+
+ set_gdbarch_skip_prologue (gdbarch, ia64_skip_prologue);
+
+ set_gdbarch_use_struct_convention (gdbarch, ia64_use_struct_convention);
+ set_gdbarch_extract_return_value (gdbarch, ia64_extract_return_value);
+
+ set_gdbarch_store_return_value (gdbarch, ia64_store_return_value);
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address);
+
+ set_gdbarch_memory_insert_breakpoint (gdbarch, ia64_memory_insert_breakpoint);
+ set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint);
+ set_gdbarch_breakpoint_from_pc (gdbarch, ia64_breakpoint_from_pc);
+ set_gdbarch_read_pc (gdbarch, ia64_read_pc);
+ set_gdbarch_write_pc (gdbarch, ia64_write_pc);
+
+ /* Settings for calling functions in the inferior. */
+ set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call);
+ set_gdbarch_frame_align (gdbarch, ia64_frame_align);
+ set_gdbarch_unwind_dummy_id (gdbarch, ia64_unwind_dummy_id);
+
+ set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
+ frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
+#ifdef HAVE_LIBUNWIND_IA64_H
+ frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
+ libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
+#endif
+ frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
+ frame_base_set_default (gdbarch, &ia64_frame_base);
+
+ /* Settings that should be unnecessary. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ set_gdbarch_remote_translate_xfer_address (
+ gdbarch, ia64_remote_translate_xfer_address);
+
+ set_gdbarch_print_insn (gdbarch, ia64_print_insn);
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch, ia64_convert_from_func_ptr_addr);
+
+ gdbarch_init_osabi (info, gdbarch);
+
+ return gdbarch;
+}
+
+extern initialize_file_ftype _initialize_ia64_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_ia64_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_ia64, ia64_gdbarch_init);
+}
diff --git a/contrib/gdb/gdb/ia64-tdep.h b/contrib/gdb/gdb/ia64-tdep.h
new file mode 100644
index 0000000..599f644
--- /dev/null
+++ b/contrib/gdb/gdb/ia64-tdep.h
@@ -0,0 +1,46 @@
+/* Target-dependent code for the ia64.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 IA64_TDEP_H
+#define IA64_TDEP_H
+
+#include "osabi.h"
+
+/* Target-dependent structure in gdbarch. */
+struct gdbarch_tdep
+{
+ enum gdb_osabi osabi; /* OS/ABI of inferior. */
+
+ CORE_ADDR (*sigcontext_register_address) (CORE_ADDR, int);
+ /* OS specific function which, given a frame address
+ and register number, returns the offset to the
+ given register from the start of the frame. */
+ CORE_ADDR (*find_global_pointer) (CORE_ADDR);
+};
+
+#define SIGCONTEXT_REGISTER_ADDRESS \
+ (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
+#define FIND_GLOBAL_POINTER \
+ (gdbarch_tdep (current_gdbarch)->find_global_pointer)
+
+extern CORE_ADDR ia64_generic_find_global_pointer (CORE_ADDR);
+
+#endif /* IA64_TDEP_H */
diff --git a/contrib/gdb/gdb/inf-loop.c b/contrib/gdb/gdb/inf-loop.c
new file mode 100644
index 0000000..ed60cc3
--- /dev/null
+++ b/contrib/gdb/gdb/inf-loop.c
@@ -0,0 +1,132 @@
+/* Handling of inferior events for the event loop for GDB, the GNU debugger.
+ Copyright 1999 Free Software Foundation, Inc.
+ Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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" /* For fetch_inferior_event. */
+#include "target.h" /* For enum inferior_event_type. */
+#include "event-loop.h"
+#include "event-top.h"
+#include "inf-loop.h"
+#include "remote.h"
+
+static int fetch_inferior_event_wrapper (gdb_client_data client_data);
+static void complete_execution (void);
+
+void
+inferior_event_handler_wrapper (gdb_client_data client_data)
+{
+ inferior_event_handler (INF_QUIT_REQ, client_data);
+}
+
+/* General function to handle events in the inferior. So far it just
+ takes care of detecting errors reported by select() or poll(),
+ otherwise it assumes that all is OK, and goes on reading data from
+ the fd. This however may not always be what we want to do. */
+void
+inferior_event_handler (enum inferior_event_type event_type,
+ gdb_client_data client_data)
+{
+ switch (event_type)
+ {
+ case INF_ERROR:
+ printf_unfiltered ("error detected from target.\n");
+ target_async (NULL, 0);
+ pop_target ();
+ discard_all_continuations ();
+ do_exec_error_cleanups (ALL_CLEANUPS);
+ break;
+
+ case INF_REG_EVENT:
+ /* Use catch errors for now, until the inner layers of
+ fetch_inferior_event (i.e. readchar) can return meaningful
+ error status. If an error occurs while getting an event from
+ the target, just get rid of the target. */
+ if (!catch_errors (fetch_inferior_event_wrapper,
+ client_data, "", RETURN_MASK_ALL))
+ {
+ target_async (NULL, 0);
+ pop_target ();
+ discard_all_continuations ();
+ do_exec_error_cleanups (ALL_CLEANUPS);
+ display_gdb_prompt (0);
+ }
+ break;
+
+ case INF_EXEC_COMPLETE:
+ /* Is there anything left to do for the command issued to
+ complete? */
+ do_all_continuations ();
+ /* Reset things after target has stopped for the async commands. */
+ complete_execution ();
+ break;
+
+ case INF_EXEC_CONTINUE:
+ /* Is there anything left to do for the command issued to
+ complete? */
+ do_all_intermediate_continuations ();
+ break;
+
+ case INF_QUIT_REQ:
+ /* FIXME: ezannoni 1999-10-04. This call should really be a
+ target vector entry, so that it can be used for any kind of
+ targets. */
+ async_remote_interrupt_twice (NULL);
+ break;
+
+ case INF_TIMER:
+ default:
+ printf_unfiltered ("Event type not recognized.\n");
+ break;
+ }
+}
+
+static int
+fetch_inferior_event_wrapper (gdb_client_data client_data)
+{
+ fetch_inferior_event (client_data);
+ return 1;
+}
+
+/* Reset proper settings after an asynchronous command has finished.
+ If the execution command was in synchronous mode, register stdin
+ with the event loop, and reset the prompt. */
+
+static void
+complete_execution (void)
+{
+ target_executing = 0;
+
+ /* Unregister the inferior from the event loop. This is done so that
+ when the inferior is not running we don't get distracted by
+ spurious inferior output. */
+ target_async (NULL, 0);
+
+ if (sync_execution)
+ {
+ do_exec_error_cleanups (ALL_CLEANUPS);
+ display_gdb_prompt (0);
+ }
+ else
+ {
+ if (exec_done_display_p)
+ printf_unfiltered ("completed.\n");
+ }
+}
diff --git a/contrib/gdb/gdb/inf-loop.h b/contrib/gdb/gdb/inf-loop.h
new file mode 100644
index 0000000..9f1713c
--- /dev/null
+++ b/contrib/gdb/gdb/inf-loop.h
@@ -0,0 +1,29 @@
+/* Interface to the inferior event handling code for GDB, the GNU debugger.
+ Copyright 1999 Free Software Foundation, Inc.
+ Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 INF_LOOP_H
+#define INF_LOOP_H
+
+extern void inferior_event_handler (enum inferior_event_type event_type,
+ void* client_data);
+extern void inferior_event_handler_wrapper (void *client_data);
+
+#endif /* #ifndef INF_LOOP_H */
diff --git a/contrib/gdb/gdb/infcall.c b/contrib/gdb/gdb/infcall.c
new file mode 100644
index 0000000..11ce018
--- /dev/null
+++ b/contrib/gdb/gdb/infcall.c
@@ -0,0 +1,1103 @@
+/* Perform an inferior function call, for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "breakpoint.h"
+#include "target.h"
+#include "regcache.h"
+#include "inferior.h"
+#include "gdb_assert.h"
+#include "block.h"
+#include "gdbcore.h"
+#include "language.h"
+#include "objfiles.h"
+#include "gdbcmd.h"
+#include "command.h"
+#include "gdb_string.h"
+#include "infcall.h"
+
+/* NOTE: cagney/2003-04-16: What's the future of this code?
+
+ GDB needs an asynchronous expression evaluator, that means an
+ asynchronous inferior function call implementation, and that in
+ turn means restructuring the code so that it is event driven. */
+
+/* How you should pass arguments to a function depends on whether it
+ was defined in K&R style or prototype style. If you define a
+ function using the K&R syntax that takes a `float' argument, then
+ callers must pass that argument as a `double'. If you define the
+ function using the prototype syntax, then you must pass the
+ argument as a `float', with no promotion.
+
+ Unfortunately, on certain older platforms, the debug info doesn't
+ indicate reliably how each function was defined. A function type's
+ TYPE_FLAG_PROTOTYPED flag may be clear, even if the function was
+ defined in prototype style. When calling a function whose
+ TYPE_FLAG_PROTOTYPED flag is clear, GDB consults this flag to
+ decide what to do.
+
+ For modern targets, it is proper to assume that, if the prototype
+ flag is clear, that can be trusted: `float' arguments should be
+ promoted to `double'. For some older targets, if the prototype
+ flag is clear, that doesn't tell us anything. The default is to
+ trust the debug information; the user can override this behavior
+ with "set coerce-float-to-double 0". */
+
+static int coerce_float_to_double_p = 1;
+
+/* This boolean tells what gdb should do if a signal is received while
+ in a function called from gdb (call dummy). If set, gdb unwinds
+ the stack and restore the context to what as it was before the
+ call.
+
+ The default is to stop in the frame where the signal was received. */
+
+int unwind_on_signal_p = 0;
+
+/* 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.
+ IS_PROTOTYPED is non-zero if the function declaration is prototyped. */
+
+static struct value *
+value_arg_coerce (struct value *arg, struct type *param_type,
+ int is_prototyped)
+{
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ 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
+ && TYPE_CODE (arg_type) != TYPE_CODE_PTR)
+ {
+ 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 we don't have a prototype, coerce to integer type if necessary. */
+ if (!is_prototyped)
+ {
+ if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+ type = builtin_type_int;
+ }
+ /* Currently all target ABIs require at least the width of an integer
+ type for an argument. We may have to conditionalize the following
+ type coercion for future targets. */
+ if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+ type = builtin_type_int;
+ break;
+ case TYPE_CODE_FLT:
+ if (!is_prototyped && coerce_float_to_double_p)
+ {
+ 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:
+ /* Arrays are coerced to pointers to their first element, unless
+ they are vectors, in which case we want to leave them alone,
+ because they are passed by value. */
+ if (current_language->c_style_arrays)
+ if (!TYPE_VECTOR (type))
+ 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. */
+
+CORE_ADDR
+find_function_addr (struct value *function, struct type **retval_type)
+{
+ struct type *ftype = check_typedef (VALUE_TYPE (function));
+ 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_address (function);
+ ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+ if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+ || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ {
+ funaddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ funaddr,
+ &current_target);
+ 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_address (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;
+}
+
+/* Call breakpoint_auto_delete on the current contents of the bpstat
+ pointed to by arg (which is really a bpstat *). */
+
+static void
+breakpoint_auto_delete_contents (void *arg)
+{
+ breakpoint_auto_delete (*(bpstat *) arg);
+}
+
+static CORE_ADDR
+legacy_push_dummy_code (struct gdbarch *gdbarch,
+ CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
+ struct value **args, int nargs,
+ struct type *value_type,
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+{
+ /* CALL_DUMMY is an array of words (DEPRECATED_REGISTER_SIZE), but
+ each word is in host byte order. Before calling
+ DEPRECATED_FIX_CALL_DUMMY, we byteswap it and remove any extra
+ bytes which might exist because ULONGEST is bigger than
+ DEPRECATED_REGISTER_SIZE. */
+ /* NOTE: This is pretty wierd, as the call dummy is actually a
+ sequence of instructions. But CISC machines will have to pack
+ the instructions into DEPRECATED_REGISTER_SIZE units (and so will
+ RISC machines for which INSTRUCTION_SIZE is not
+ DEPRECATED_REGISTER_SIZE). */
+ /* NOTE: This is pretty stupid. CALL_DUMMY should be in strict
+ target byte order. */
+ CORE_ADDR start_sp;
+ ULONGEST *dummy = alloca (DEPRECATED_SIZEOF_CALL_DUMMY_WORDS);
+ int sizeof_dummy1 = (DEPRECATED_REGISTER_SIZE
+ * DEPRECATED_SIZEOF_CALL_DUMMY_WORDS
+ / sizeof (ULONGEST));
+ char *dummy1 = alloca (sizeof_dummy1);
+ memcpy (dummy, DEPRECATED_CALL_DUMMY_WORDS,
+ DEPRECATED_SIZEOF_CALL_DUMMY_WORDS);
+ if (INNER_THAN (1, 2))
+ {
+ /* Stack grows down */
+ sp -= sizeof_dummy1;
+ start_sp = sp;
+ }
+ else
+ {
+ /* Stack grows up */
+ start_sp = sp;
+ sp += sizeof_dummy1;
+ }
+ /* NOTE: cagney/2002-09-10: Don't bother re-adjusting the stack
+ after allocating space for the call dummy. A target can specify
+ a SIZEOF_DUMMY1 (via DEPRECATED_SIZEOF_CALL_DUMMY_WORDS) such
+ that all local alignment requirements are met. */
+ /* Create a call sequence customized for this function and the
+ number of arguments for it. */
+ {
+ int i;
+ for (i = 0; i < (int) (DEPRECATED_SIZEOF_CALL_DUMMY_WORDS / sizeof (dummy[0]));
+ i++)
+ store_unsigned_integer (&dummy1[i * DEPRECATED_REGISTER_SIZE],
+ DEPRECATED_REGISTER_SIZE,
+ (ULONGEST) dummy[i]);
+ }
+ /* NOTE: cagney/2003-04-22: This computation of REAL_PC, BP_ADDR and
+ DUMMY_ADDR is pretty messed up. It comes from constant tinkering
+ with the values. Instead a DEPRECATED_FIX_CALL_DUMMY replacement
+ (PUSH_DUMMY_BREAKPOINT?) should just do everything. */
+ if (!gdbarch_push_dummy_call_p (current_gdbarch))
+ {
+#ifdef GDB_TARGET_IS_HPPA
+ (*real_pc) = DEPRECATED_FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs,
+ args, value_type, using_gcc);
+#else
+ if (DEPRECATED_FIX_CALL_DUMMY_P ())
+ {
+ /* gdb_assert (CALL_DUMMY_LOCATION == ON_STACK) true? */
+ DEPRECATED_FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+ value_type, using_gcc);
+ }
+ (*real_pc) = start_sp;
+#endif
+ }
+ /* Yes, the offset is applied to the real_pc and not the dummy addr.
+ Ulgh! Blame the HP/UX target. */
+ (*bp_addr) = (*real_pc) + DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET;
+ /* Yes, the offset is applied to the real_pc and not the
+ dummy_addr. Ulgh! Blame the HP/UX target. */
+ (*real_pc) += DEPRECATED_CALL_DUMMY_START_OFFSET;
+ write_memory (start_sp, (char *) dummy1, sizeof_dummy1);
+ if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+ generic_save_call_dummy_addr (start_sp, start_sp + sizeof_dummy1);
+ return sp;
+}
+
+static CORE_ADDR
+generic_push_dummy_code (struct gdbarch *gdbarch,
+ CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
+ struct value **args, int nargs,
+ struct type *value_type,
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+{
+ /* Something here to findout the size of a breakpoint and then
+ allocate space for it on the stack. */
+ int bplen;
+ /* This code assumes frame align. */
+ gdb_assert (gdbarch_frame_align_p (gdbarch));
+ /* Force the stack's alignment. The intent is to ensure that the SP
+ is aligned to at least a breakpoint instruction's boundary. */
+ sp = gdbarch_frame_align (gdbarch, sp);
+ /* Allocate space for, and then position the breakpoint on the
+ stack. */
+ if (gdbarch_inner_than (gdbarch, 1, 2))
+ {
+ CORE_ADDR bppc = sp;
+ gdbarch_breakpoint_from_pc (gdbarch, &bppc, &bplen);
+ sp = gdbarch_frame_align (gdbarch, sp - bplen);
+ (*bp_addr) = sp;
+ /* Should the breakpoint size/location be re-computed here? */
+ }
+ else
+ {
+ (*bp_addr) = sp;
+ gdbarch_breakpoint_from_pc (gdbarch, bp_addr, &bplen);
+ sp = gdbarch_frame_align (gdbarch, sp + bplen);
+ }
+ /* Inferior resumes at the function entry point. */
+ (*real_pc) = funaddr;
+ return sp;
+}
+
+/* Provide backward compatibility. Once DEPRECATED_FIX_CALL_DUMMY is
+ eliminated, this can be simplified. */
+
+static CORE_ADDR
+push_dummy_code (struct gdbarch *gdbarch,
+ CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
+ struct value **args, int nargs,
+ struct type *value_type,
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+{
+ if (gdbarch_push_dummy_code_p (gdbarch))
+ return gdbarch_push_dummy_code (gdbarch, sp, funaddr, using_gcc,
+ args, nargs, value_type, real_pc, bp_addr);
+ else if (DEPRECATED_FIX_CALL_DUMMY_P ()
+ && !gdbarch_push_dummy_call_p (gdbarch))
+ return legacy_push_dummy_code (gdbarch, sp, funaddr, using_gcc,
+ args, nargs, value_type, real_pc, bp_addr);
+ else
+ return generic_push_dummy_code (gdbarch, sp, funaddr, using_gcc,
+ args, nargs, value_type, real_pc, bp_addr);
+}
+
+/* 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. */
+
+struct value *
+call_function_by_hand (struct value *function, int nargs, struct value **args)
+{
+ CORE_ADDR sp;
+ CORE_ADDR dummy_addr;
+ struct type *value_type;
+ unsigned char struct_return;
+ CORE_ADDR struct_addr = 0;
+ struct regcache *retbuf;
+ struct cleanup *retbuf_cleanup;
+ struct inferior_status *inf_status;
+ struct cleanup *inf_status_cleanup;
+ CORE_ADDR funaddr;
+ int using_gcc; /* Set to version of gcc in use, or zero if not gcc */
+ CORE_ADDR real_pc;
+ struct type *ftype = check_typedef (SYMBOL_TYPE (function));
+ CORE_ADDR bp_addr;
+
+ if (!target_has_execution)
+ noprocess ();
+
+ /* Create a cleanup chain that contains the retbuf (buffer
+ containing the register values). This chain is create BEFORE the
+ inf_status chain so that the inferior status can cleaned up
+ (restored or discarded) without having the retbuf freed. */
+ retbuf = regcache_xmalloc (current_gdbarch);
+ retbuf_cleanup = make_cleanup_regcache_xfree (retbuf);
+
+ /* A cleanup for the inferior status. Create this AFTER the retbuf
+ so that this can be discarded or applied without interfering with
+ the regbuf. */
+ inf_status = save_inferior_status (1);
+ inf_status_cleanup = make_cleanup_restore_inferior_status (inf_status);
+
+ if (DEPRECATED_PUSH_DUMMY_FRAME_P ())
+ {
+ /* DEPRECATED_PUSH_DUMMY_FRAME is responsible for saving the
+ inferior registers (and frame_pop() for restoring them). (At
+ least on most machines) they are saved on the stack in the
+ inferior. */
+ DEPRECATED_PUSH_DUMMY_FRAME;
+ }
+ else
+ {
+ /* FIXME: cagney/2003-02-26: Step zero of this little tinker is
+ to extract the generic dummy frame code from the architecture
+ vector. Hence this direct call.
+
+ A follow-on change is to modify this interface so that it takes
+ thread OR frame OR ptid as a parameter, and returns a dummy
+ frame handle. The handle can then be used further down as a
+ parameter to generic_save_dummy_frame_tos(). Hmm, thinking
+ about it, since everything is ment to be using generic dummy
+ frames, why not even use some of the dummy frame code to here -
+ do a regcache dup and then pass the duped regcache, along with
+ all the other stuff, at one single point.
+
+ In fact, you can even save the structure's return address in the
+ dummy frame and fix one of those nasty lost struct return edge
+ conditions. */
+ generic_push_dummy_frame ();
+ }
+
+ /* Ensure that the initial SP is correctly aligned. */
+ {
+ CORE_ADDR old_sp = read_sp ();
+ if (gdbarch_frame_align_p (current_gdbarch))
+ {
+ sp = gdbarch_frame_align (current_gdbarch, old_sp);
+ /* NOTE: cagney/2003-08-13: Skip the "red zone". For some
+ ABIs, a function can use memory beyond the inner most stack
+ address. AMD64 called that region the "red zone". Skip at
+ least the "red zone" size before allocating any space on
+ the stack. */
+ if (INNER_THAN (1, 2))
+ sp -= gdbarch_frame_red_zone_size (current_gdbarch);
+ else
+ sp += gdbarch_frame_red_zone_size (current_gdbarch);
+ /* Still aligned? */
+ gdb_assert (sp == gdbarch_frame_align (current_gdbarch, sp));
+ /* NOTE: cagney/2002-09-18:
+
+ On a RISC architecture, a void parameterless generic dummy
+ frame (i.e., no parameters, no result) typically does not
+ need to push anything the stack and hence can leave SP and
+ FP. Similarly, a frameless (possibly leaf) function does
+ not push anything on the stack and, hence, that too can
+ leave FP and SP unchanged. As a consequence, a sequence of
+ void parameterless generic dummy frame calls to frameless
+ functions will create a sequence of effectively identical
+ frames (SP, FP and TOS and PC the same). This, not
+ suprisingly, results in what appears to be a stack in an
+ infinite loop --- when GDB tries to find a generic dummy
+ frame on the internal dummy frame stack, it will always
+ find the first one.
+
+ To avoid this problem, the code below always grows the
+ stack. That way, two dummy frames can never be identical.
+ It does burn a few bytes of stack but that is a small price
+ to pay :-). */
+ if (sp == old_sp)
+ {
+ if (INNER_THAN (1, 2))
+ /* Stack grows down. */
+ sp = gdbarch_frame_align (current_gdbarch, old_sp - 1);
+ else
+ /* Stack grows up. */
+ sp = gdbarch_frame_align (current_gdbarch, old_sp + 1);
+ }
+ gdb_assert ((INNER_THAN (1, 2) && sp <= old_sp)
+ || (INNER_THAN (2, 1) && sp >= old_sp));
+ }
+ else
+ /* FIXME: cagney/2002-09-18: Hey, you loose!
+
+ Who knows how badly aligned the SP is!
+
+ If the generic dummy frame ends up empty (because nothing is
+ pushed) GDB won't be able to correctly perform back traces.
+ If a target is having trouble with backtraces, first thing to
+ do is add FRAME_ALIGN() to the architecture vector. If that
+ fails, try unwind_dummy_id().
+
+ If the ABI specifies a "Red Zone" (see the doco) the code
+ below will quietly trash it. */
+ sp = old_sp;
+ }
+
+ funaddr = find_function_addr (function, &value_type);
+ CHECK_TYPEDEF (value_type);
+
+ {
+ struct block *b = block_for_pc (funaddr);
+ /* If compiled without -g, assume GCC 2. */
+ using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
+ }
+
+ /* Are we returning a value using a structure return or a normal
+ value return? */
+
+ struct_return = using_struct_return (value_type, using_gcc);
+
+ /* Determine the location of the breakpoint (and possibly other
+ stuff) that the called function will return to. The SPARC, for a
+ function returning a structure or union, needs to make space for
+ not just the breakpoint but also an extra word containing the
+ size (?) of the structure being passed. */
+
+ /* The actual breakpoint (at BP_ADDR) is inserted separatly so there
+ is no need to write that out. */
+
+ switch (CALL_DUMMY_LOCATION)
+ {
+ case ON_STACK:
+ /* "dummy_addr" is here just to keep old targets happy. New
+ targets return that same information via "sp" and "bp_addr". */
+ if (INNER_THAN (1, 2))
+ {
+ sp = push_dummy_code (current_gdbarch, sp, funaddr,
+ using_gcc, args, nargs, value_type,
+ &real_pc, &bp_addr);
+ dummy_addr = sp;
+ }
+ else
+ {
+ dummy_addr = sp;
+ sp = push_dummy_code (current_gdbarch, sp, funaddr,
+ using_gcc, args, nargs, value_type,
+ &real_pc, &bp_addr);
+ }
+ break;
+ case AT_ENTRY_POINT:
+ if (DEPRECATED_FIX_CALL_DUMMY_P ()
+ && !gdbarch_push_dummy_call_p (current_gdbarch))
+ {
+ /* Sigh. Some targets use DEPRECATED_FIX_CALL_DUMMY to
+ shove extra stuff onto the stack or into registers. That
+ code should be in PUSH_DUMMY_CALL, however, in the mean
+ time ... */
+ /* If the target is manipulating DUMMY1, it looses big time. */
+ void *dummy1 = NULL;
+ DEPRECATED_FIX_CALL_DUMMY (dummy1, sp, funaddr, nargs, args,
+ value_type, using_gcc);
+ }
+ real_pc = funaddr;
+ dummy_addr = entry_point_address ();
+ /* Make certain that the address points at real code, and not a
+ function descriptor. */
+ dummy_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ dummy_addr,
+ &current_target);
+ /* A call dummy always consists of just a single breakpoint, so
+ it's address is the same as the address of the dummy. */
+ bp_addr = dummy_addr;
+ break;
+ case AT_SYMBOL:
+ /* Some executables define a symbol __CALL_DUMMY_ADDRESS whose
+ address is the location where the breakpoint should be
+ placed. Once all targets are using the overhauled frame code
+ this can be deleted - ON_STACK is a better option. */
+ {
+ struct minimal_symbol *sym;
+
+ sym = lookup_minimal_symbol ("__CALL_DUMMY_ADDRESS", NULL, NULL);
+ real_pc = funaddr;
+ if (sym)
+ dummy_addr = SYMBOL_VALUE_ADDRESS (sym);
+ else
+ dummy_addr = entry_point_address ();
+ /* Make certain that the address points at real code, and not
+ a function descriptor. */
+ dummy_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ dummy_addr,
+ &current_target);
+ /* A call dummy always consists of just a single breakpoint,
+ so it's address is the same as the address of the dummy. */
+ bp_addr = dummy_addr;
+ break;
+ }
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+ /* Save where the breakpoint is going to be inserted so that the
+ dummy-frame code is later able to re-identify it. */
+ generic_save_call_dummy_addr (bp_addr, bp_addr + 1);
+
+ if (nargs < TYPE_NFIELDS (ftype))
+ error ("too few arguments in function call");
+
+ {
+ int i;
+ for (i = nargs - 1; i >= 0; i--)
+ {
+ int prototyped;
+ struct type *param_type;
+
+ /* FIXME drow/2002-05-31: Should just always mark methods as
+ prototyped. Can we respect TYPE_VARARGS? Probably not. */
+ if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ prototyped = 1;
+ else if (i < TYPE_NFIELDS (ftype))
+ prototyped = TYPE_PROTOTYPED (ftype);
+ else
+ prototyped = 0;
+
+ if (i < TYPE_NFIELDS (ftype))
+ param_type = TYPE_FIELD_TYPE (ftype, i);
+ else
+ param_type = NULL;
+
+ args[i] = value_arg_coerce (args[i], param_type, prototyped);
+
+ /* elz: this code is to handle the case in which the function
+ to be called has a pointer to function as parameter and the
+ corresponding actual argument is the address of a function
+ and not a pointer to function variable. In aCC compiled
+ code, the calls through pointers to functions (in the body
+ of the function called by hand) are made via
+ $$dyncall_external which requires some registers setting,
+ this is taken care of if we call via a function pointer
+ variable, but not via a function address. In cc this is
+ not a problem. */
+
+ if (using_gcc == 0)
+ {
+ if (param_type != NULL && TYPE_CODE (ftype) != TYPE_CODE_METHOD)
+ {
+ /* if this parameter is a pointer to function. */
+ if (TYPE_CODE (param_type) == TYPE_CODE_PTR)
+ if (TYPE_CODE (TYPE_TARGET_TYPE (param_type)) == TYPE_CODE_FUNC)
+ /* elz: FIXME here should go the test about the
+ compiler used to compile the target. We want to
+ issue the error message only if the compiler
+ used was HP's aCC. If we used HP's cc, then
+ there is no problem and no need to return at
+ this point. */
+ /* Go see if the actual parameter is a variable of
+ type pointer to function or just a function. */
+ if (args[i]->lval == not_lval)
+ {
+ char *arg_name;
+ if (find_pc_partial_function ((CORE_ADDR) args[i]->aligner.contents[0], &arg_name, NULL, NULL))
+ error ("\
+You cannot use function <%s> as argument. \n\
+You must use a pointer to function type variable. Command ignored.", arg_name);
+ }
+ }
+ }
+ }
+ }
+
+ if (DEPRECATED_REG_STRUCT_HAS_ADDR_P ())
+ {
+ int i;
+ /* 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)
+ )
+ && DEPRECATED_REG_STRUCT_HAS_ADDR (using_gcc, arg_type))
+ {
+ CORE_ADDR addr;
+ int len; /* = TYPE_LENGTH (arg_type); */
+ int aligned_len;
+ arg_type = check_typedef (VALUE_ENCLOSING_TYPE (args[i]));
+ len = TYPE_LENGTH (arg_type);
+
+ if (DEPRECATED_STACK_ALIGN_P ())
+ /* MVS 11/22/96: I think at least some of this
+ stack_align code is really broken. Better to let
+ PUSH_ARGUMENTS adjust the stack in a target-defined
+ manner. */
+ aligned_len = DEPRECATED_STACK_ALIGN (len);
+ else
+ aligned_len = len;
+ if (INNER_THAN (1, 2))
+ {
+ /* stack grows downward */
+ sp -= aligned_len;
+ /* ... so the address of the thing we push is the
+ stack pointer after we push it. */
+ addr = sp;
+ }
+ else
+ {
+ /* The stack grows up, so the address of the thing
+ we push is the stack pointer before we push it. */
+ addr = sp;
+ sp += aligned_len;
+ }
+ /* Push the structure. */
+ write_memory (addr, VALUE_CONTENTS_ALL (args[i]), len);
+ /* 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); */
+ args[i] = value_from_pointer (lookup_pointer_type (arg_type),
+ addr);
+ }
+ }
+ }
+
+
+ /* Reserve space for the return structure to be written on the
+ stack, if necessary. Make certain that the value is correctly
+ aligned. */
+
+ if (struct_return)
+ {
+ int len = TYPE_LENGTH (value_type);
+ if (DEPRECATED_STACK_ALIGN_P ())
+ /* NOTE: cagney/2003-03-22: Should rely on frame align, rather
+ than stack align to force the alignment of the stack. */
+ len = DEPRECATED_STACK_ALIGN (len);
+ if (INNER_THAN (1, 2))
+ {
+ /* Stack grows downward. Align STRUCT_ADDR and SP after
+ making space for the return value. */
+ sp -= len;
+ if (gdbarch_frame_align_p (current_gdbarch))
+ sp = gdbarch_frame_align (current_gdbarch, sp);
+ struct_addr = sp;
+ }
+ else
+ {
+ /* Stack grows upward. Align the frame, allocate space, and
+ then again, re-align the frame??? */
+ if (gdbarch_frame_align_p (current_gdbarch))
+ sp = gdbarch_frame_align (current_gdbarch, sp);
+ struct_addr = sp;
+ sp += len;
+ if (gdbarch_frame_align_p (current_gdbarch))
+ sp = gdbarch_frame_align (current_gdbarch, sp);
+ }
+ }
+
+ /* Create the dummy stack frame. Pass in the call dummy address as,
+ presumably, the ABI code knows where, in the call dummy, the
+ return address should be pointed. */
+ if (gdbarch_push_dummy_call_p (current_gdbarch))
+ /* When there is no push_dummy_call method, should this code
+ simply error out. That would the implementation of this method
+ for all ABIs (which is probably a good thing). */
+ sp = gdbarch_push_dummy_call (current_gdbarch, funaddr, current_regcache,
+ bp_addr, nargs, args, sp, struct_return,
+ struct_addr);
+ else if (DEPRECATED_PUSH_ARGUMENTS_P ())
+ /* Keep old targets working. */
+ sp = DEPRECATED_PUSH_ARGUMENTS (nargs, args, sp, struct_return,
+ struct_addr);
+ else
+ sp = legacy_push_arguments (nargs, args, sp, struct_return, struct_addr);
+
+ if (DEPRECATED_PUSH_RETURN_ADDRESS_P ())
+ /* for targets that use no CALL_DUMMY */
+ /* There are a number of targets now which actually don't write
+ any CALL_DUMMY instructions into the target, but instead just
+ save the machine state, push the arguments, and jump directly
+ to the callee function. Since this doesn't actually involve
+ executing a JSR/BSR instruction, the return address must be set
+ up by hand, either by pushing onto the stack or copying into a
+ return-address register as appropriate. Formerly this has been
+ done in PUSH_ARGUMENTS, but that's overloading its
+ functionality a bit, so I'm making it explicit to do it here. */
+ /* NOTE: cagney/2003-04-22: The first parameter ("real_pc") has
+ been replaced with zero, it turns out that no implementation
+ used that parameter. This occured because the value being
+ supplied - the address of the called function's entry point
+ instead of the address of the breakpoint that the called
+ function should return to - wasn't useful. */
+ sp = DEPRECATED_PUSH_RETURN_ADDRESS (0, sp);
+
+ /* NOTE: cagney/2003-03-23: Diable this code when there is a
+ push_dummy_call() method. Since that method will have already
+ handled any alignment issues, the code below is entirely
+ redundant. */
+ if (!gdbarch_push_dummy_call_p (current_gdbarch)
+ && DEPRECATED_STACK_ALIGN_P () && !INNER_THAN (1, 2))
+ {
+ /* If stack grows up, we must leave a hole at the bottom, note
+ that sp already has been advanced for the arguments! */
+ sp = DEPRECATED_STACK_ALIGN (sp);
+ }
+
+ /* Store the address at which the structure is supposed to be
+ written. */
+ /* NOTE: 2003-03-24: Since PUSH_ARGUMENTS can (and typically does)
+ store the struct return address, this call is entirely redundant. */
+ if (struct_return && DEPRECATED_STORE_STRUCT_RETURN_P ())
+ DEPRECATED_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). */
+ /* NOTE: cagney/2003-03-23: Since the architecture method
+ push_dummy_call() should have already stored the stack pointer
+ (as part of creating the fake call frame), and none of the code
+ following that call adjusts the stack-pointer value, the below
+ call is entirely redundant. */
+ if (DEPRECATED_DUMMY_WRITE_SP_P ())
+ DEPRECATED_DUMMY_WRITE_SP (sp);
+
+ if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+ {
+ /* Sanity. The exact same SP value is returned by
+ PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by
+ unwind_dummy_id to form the frame ID's stack address. */
+ gdb_assert (DEPRECATED_USE_GENERIC_DUMMY_FRAMES);
+ generic_save_dummy_frame_tos (sp);
+ }
+ else if (DEPRECATED_SAVE_DUMMY_FRAME_TOS_P ())
+ DEPRECATED_SAVE_DUMMY_FRAME_TOS (sp);
+
+ /* Now proceed, having reached the desired place. */
+ clear_proceed_status ();
+
+ /* Create a momentary breakpoint at the return address of the
+ inferior. That way it breaks when it returns. */
+
+ {
+ struct breakpoint *bpt;
+ struct symtab_and_line sal;
+ struct frame_id frame;
+ init_sal (&sal); /* initialize to zeroes */
+ sal.pc = bp_addr;
+ sal.section = find_pc_overlay (sal.pc);
+ /* Set up a frame ID for the dummy frame so we can pass it to
+ set_momentary_breakpoint. We need to give the breakpoint a
+ frame ID so that the breakpoint code can correctly re-identify
+ the dummy breakpoint. */
+ if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+ {
+ /* Sanity. The exact same SP value is returned by
+ PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by
+ unwind_dummy_id to form the frame ID's stack address. */
+ gdb_assert (DEPRECATED_USE_GENERIC_DUMMY_FRAMES);
+ frame = frame_id_build (sp, sal.pc);
+ }
+ else
+ {
+ /* The assumption here is that push_dummy_call() returned the
+ stack part of the frame ID. Unfortunately, many older
+ architectures were, via a convoluted mess, relying on the
+ poorly defined and greatly overloaded
+ DEPRECATED_TARGET_READ_FP or DEPRECATED_FP_REGNUM to supply
+ the value. */
+ if (DEPRECATED_TARGET_READ_FP_P ())
+ frame = frame_id_build (DEPRECATED_TARGET_READ_FP (), sal.pc);
+ else if (DEPRECATED_FP_REGNUM >= 0)
+ frame = frame_id_build (read_register (DEPRECATED_FP_REGNUM), sal.pc);
+ else
+ frame = frame_id_build (sp, sal.pc);
+ }
+ bpt = set_momentary_breakpoint (sal, frame, bp_call_dummy);
+ bpt->disposition = disp_del;
+ }
+
+ /* Execute a "stack dummy", a piece of code stored in the stack by
+ the debugger to be executed in the inferior.
+
+ The dummy's frame is automatically popped whenever that break is
+ hit. If that is the first time the program stops,
+ call_function_by_hand returns to its caller with that frame
+ already gone and sets RC to 0.
+
+ Otherwise, set RC to a non-zero value. If the called function
+ receives a random signal, we do not allow the user to continue
+ executing it as this may not work. The dummy frame is poped and
+ we return 1. If we hit a breakpoint, we leave the frame in place
+ and return 2 (the frame will eventually be popped when we do hit
+ the dummy end breakpoint). */
+
+ {
+ struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
+ int saved_async = 0;
+
+ /* 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);
+
+ disable_watchpoints_before_interactive_call_start ();
+ proceed_to_finish = 1; /* We want stop_registers, please... */
+
+ if (target_can_async_p ())
+ saved_async = target_async_mask (0);
+
+ proceed (real_pc, TARGET_SIGNAL_0, 0);
+
+ if (saved_async)
+ target_async_mask (saved_async);
+
+ enable_watchpoints_after_interactive_call_stop ();
+
+ discard_cleanups (old_cleanups);
+ }
+
+ if (stopped_by_random_signal || !stop_stack_dummy)
+ {
+ /* Find the name of the function we're about to complain about. */
+ const char *name = NULL;
+ {
+ struct symbol *symbol = find_pc_function (funaddr);
+ if (symbol)
+ name = SYMBOL_PRINT_NAME (symbol);
+ else
+ {
+ /* Try the minimal symbols. */
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr);
+ if (msymbol)
+ name = SYMBOL_PRINT_NAME (msymbol);
+ }
+ if (name == NULL)
+ {
+ /* Can't use a cleanup here. It is discarded, instead use
+ an alloca. */
+ char *tmp = xstrprintf ("at %s", local_hex_string (funaddr));
+ char *a = alloca (strlen (tmp) + 1);
+ strcpy (a, tmp);
+ xfree (tmp);
+ name = a;
+ }
+ }
+ if (stopped_by_random_signal)
+ {
+ /* We stopped inside the FUNCTION because of a random
+ signal. Further execution of the FUNCTION is not
+ allowed. */
+
+ if (unwind_on_signal_p)
+ {
+ /* The user wants the context restored. */
+
+ /* We must get back to the frame we were before the
+ dummy call. */
+ frame_pop (get_current_frame ());
+
+ /* 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 was signaled while in a function called from GDB.\n\
+GDB has restored the context to what it was before the call.\n\
+To change this behavior use \"set unwindonsignal off\"\n\
+Evaluation of the expression containing the function (%s) will be abandoned.",
+ name);
+ }
+ else
+ {
+ /* The user wants to stay in the frame where we stopped
+ (default).*/
+ /* If we restored the inferior status (via the cleanup),
+ 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. */
+ discard_cleanups (inf_status_cleanup);
+ discard_inferior_status (inf_status);
+ /* FIXME: Insert a bunch of wrap_here; name can be very
+ long if it's a C++ name with arguments and stuff. */
+ error ("\
+The program being debugged was signaled while in a function called from GDB.\n\
+GDB remains in the frame where the signal was received.\n\
+To change this behavior use \"set unwindonsignal on\"\n\
+Evaluation of the expression containing the function (%s) will be abandoned.",
+ name);
+ }
+ }
+
+ if (!stop_stack_dummy)
+ {
+ /* We hit a breakpoint inside the FUNCTION. */
+ /* If we restored the inferior status (via the cleanup), 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. */
+ discard_cleanups (inf_status_cleanup);
+ discard_inferior_status (inf_status);
+ /* 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);
+ }
+
+ /* The above code errors out, so ... */
+ internal_error (__FILE__, __LINE__, "... should not be here");
+ }
+
+ /* If we get here the called FUNCTION run to completion. */
+
+ /* On normal return, the stack dummy has been popped already. */
+ regcache_cpy_no_passthrough (retbuf, stop_registers);
+
+ /* Restore the inferior status, via its cleanup. At this stage,
+ leave the RETBUF alone. */
+ do_cleanups (inf_status_cleanup);
+
+ /* Figure out the value returned by the function. */
+ if (struct_return)
+ {
+ /* NOTE: cagney/2003-09-27: This assumes that PUSH_DUMMY_CALL
+ has correctly stored STRUCT_ADDR in the target. In the past
+ that hasn't been the case, the old MIPS PUSH_ARGUMENTS
+ (PUSH_DUMMY_CALL precursor) would silently move the location
+ of the struct return value making STRUCT_ADDR bogus. If
+ you're seeing problems with values being returned using the
+ "struct return convention", check that PUSH_DUMMY_CALL isn't
+ playing tricks. */
+ struct value *retval = value_at (value_type, struct_addr, NULL);
+ do_cleanups (retbuf_cleanup);
+ return retval;
+ }
+ else
+ {
+ /* The non-register case was handled above. */
+ struct value *retval = register_value_being_returned (value_type,
+ retbuf);
+ do_cleanups (retbuf_cleanup);
+ return retval;
+ }
+}
+
+void _initialize_infcall (void);
+
+void
+_initialize_infcall (void)
+{
+ add_setshow_boolean_cmd ("coerce-float-to-double", class_obscure,
+ &coerce_float_to_double_p, "\
+Set coercion of floats to doubles when calling functions\n\
+Variables of type float should generally be converted to doubles before\n\
+calling an unprototyped function, and left alone when calling a prototyped\n\
+function. However, some older debug info formats do not provide enough\n\
+information to determine that a function is prototyped. If this flag is\n\
+set, GDB will perform the conversion for a function it considers\n\
+unprototyped.\n\
+The default is to perform the conversion.\n", "\
+Show coercion of floats to doubles when calling functions\n\
+Variables of type float should generally be converted to doubles before\n\
+calling an unprototyped function, and left alone when calling a prototyped\n\
+function. However, some older debug info formats do not provide enough\n\
+information to determine that a function is prototyped. If this flag is\n\
+set, GDB will perform the conversion for a function it considers\n\
+unprototyped.\n\
+The default is to perform the conversion.\n",
+ NULL, NULL, &setlist, &showlist);
+
+ add_setshow_boolean_cmd ("unwindonsignal", no_class,
+ &unwind_on_signal_p, "\
+Set unwinding of stack if a signal is received while in a call dummy.\n\
+The unwindonsignal lets the user determine what gdb should do if a signal\n\
+is received while in a function called from gdb (call dummy). If set, gdb\n\
+unwinds the stack and restore the context to what as it was before the call.\n\
+The default is to stop in the frame where the signal was received.", "\
+Set unwinding of stack if a signal is received while in a call dummy.\n\
+The unwindonsignal lets the user determine what gdb should do if a signal\n\
+is received while in a function called from gdb (call dummy). If set, gdb\n\
+unwinds the stack and restore the context to what as it was before the call.\n\
+The default is to stop in the frame where the signal was received.",
+ NULL, NULL, &setlist, &showlist);
+}
diff --git a/contrib/gdb/gdb/infcall.h b/contrib/gdb/gdb/infcall.h
new file mode 100644
index 0000000..05d06e0
--- /dev/null
+++ b/contrib/gdb/gdb/infcall.h
@@ -0,0 +1,43 @@
+/* Perform an inferior function call, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 INFCALL_H
+#define INFCALL_H
+
+struct value;
+struct type;
+
+extern CORE_ADDR find_function_addr (struct value *function,
+ struct type **retval_type);
+
+/* 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. */
+
+extern struct value *call_function_by_hand (struct value *function, int nargs,
+ struct value **args);
+
+#endif
diff --git a/contrib/gdb/gdb/infcmd.c b/contrib/gdb/gdb/infcmd.c
new file mode 100644
index 0000000..6e74f4e
--- /dev/null
+++ b/contrib/gdb/gdb/infcmd.c
@@ -0,0 +1,2159 @@
+/* Memory-access and commands for "inferior" process, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <signal.h>
+#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 "symfile.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "language.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "completer.h"
+#include "ui-out.h"
+#include "event-top.h"
+#include "parser-defs.h"
+#include "regcache.h"
+#include "reggroups.h"
+#include "block.h"
+#include <ctype.h>
+#include "gdb_assert.h"
+
+/* Functions exported for general use, in inferior.h: */
+
+void all_registers_info (char *, int);
+
+void registers_info (char *, int);
+
+void nexti_command (char *, int);
+
+void stepi_command (char *, int);
+
+void continue_command (char *, int);
+
+void interrupt_target_command (char *args, int from_tty);
+
+/* Local functions: */
+
+static void nofp_registers_info (char *, int);
+
+static void print_return_value (int struct_return, struct type *value_type);
+
+static void finish_command_continuation (struct continuation_arg *);
+
+static void until_next_command (int);
+
+static void until_command (char *, int);
+
+static void path_info (char *, int);
+
+static void path_command (char *, int);
+
+static void unset_command (char *, int);
+
+static void float_info (char *, int);
+
+static void detach_command (char *, int);
+
+static void disconnect_command (char *, int);
+
+static void unset_environment_command (char *, int);
+
+static void set_environment_command (char *, int);
+
+static void environment_info (char *, int);
+
+static void program_info (char *, int);
+
+static void finish_command (char *, int);
+
+static void signal_command (char *, int);
+
+static void jump_command (char *, int);
+
+static void step_1 (int, int, char *);
+static void step_once (int skip_subroutines, int single_inst, int count);
+static void step_1_continuation (struct continuation_arg *arg);
+
+static void next_command (char *, int);
+
+static void step_command (char *, int);
+
+static void run_command (char *, int);
+
+static void run_no_args_command (char *args, int from_tty);
+
+static void go_command (char *line_no, int from_tty);
+
+static int strip_bg_char (char **);
+
+void _initialize_infcmd (void);
+
+#define GO_USAGE "Usage: go <location>\n"
+
+#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;
+
+/* The inferior arguments as a vector. If INFERIOR_ARGC is nonzero,
+ then we must compute INFERIOR_ARGS from this (via the target). */
+
+static int inferior_argc;
+static char **inferior_argv;
+
+/* 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. */
+
+ptid_t inferior_ptid;
+
+/* 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. */
+
+struct frame_id step_frame_id;
+
+/* Our notion of the current stack pointer. */
+
+CORE_ADDR step_sp;
+
+enum step_over_calls_kind 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;
+
+/* Accessor routines. */
+
+char *
+get_inferior_args (void)
+{
+ if (inferior_argc != 0)
+ {
+ char *n, *old;
+
+ n = gdbarch_construct_inferior_arguments (current_gdbarch,
+ inferior_argc, inferior_argv);
+ old = set_inferior_args (n);
+ xfree (old);
+ }
+
+ if (inferior_args == NULL)
+ inferior_args = xstrdup ("");
+
+ return inferior_args;
+}
+
+char *
+set_inferior_args (char *newargs)
+{
+ char *saved_args = inferior_args;
+
+ inferior_args = newargs;
+ inferior_argc = 0;
+ inferior_argv = 0;
+
+ return saved_args;
+}
+
+void
+set_inferior_args_vector (int argc, char **argv)
+{
+ inferior_argc = argc;
+ inferior_argv = argv;
+}
+
+/* Notice when `set args' is run. */
+static void
+notice_args_set (char *args, int from_tty, struct cmd_list_element *c)
+{
+ inferior_argc = 0;
+ inferior_argv = 0;
+}
+
+/* Notice when `show args' is run. */
+static void
+notice_args_read (char *args, int from_tty, struct cmd_list_element *c)
+{
+ /* Might compute the value. */
+ get_inferior_args ();
+}
+
+
+/* Compute command-line string given argument vector. This does the
+ same shell processing as fork_inferior. */
+char *
+construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv)
+{
+ char *result;
+
+ if (STARTUP_WITH_SHELL)
+ {
+ /* This holds all the characters considered special to the
+ typical Unix shells. We include `^' because the SunOS
+ /bin/sh treats it as a synonym for `|'. */
+ char *special = "\"!#$&*()\\|[]{}<>?'\"`~^; \t\n";
+ int i;
+ int length = 0;
+ char *out, *cp;
+
+ /* We over-compute the size. It shouldn't matter. */
+ for (i = 0; i < argc; ++i)
+ length += 2 * strlen (argv[i]) + 1 + 2 * (argv[i][0] == '\0');
+
+ result = (char *) xmalloc (length);
+ out = result;
+
+ for (i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ *out++ = ' ';
+
+ /* Need to handle empty arguments specially. */
+ if (argv[i][0] == '\0')
+ {
+ *out++ = '\'';
+ *out++ = '\'';
+ }
+ else
+ {
+ for (cp = argv[i]; *cp; ++cp)
+ {
+ if (strchr (special, *cp) != NULL)
+ *out++ = '\\';
+ *out++ = *cp;
+ }
+ }
+ }
+ *out = '\0';
+ }
+ else
+ {
+ /* In this case we can't handle arguments that contain spaces,
+ tabs, or newlines -- see breakup_args(). */
+ int i;
+ int length = 0;
+
+ for (i = 0; i < argc; ++i)
+ {
+ char *cp = strchr (argv[i], ' ');
+ if (cp == NULL)
+ cp = strchr (argv[i], '\t');
+ if (cp == NULL)
+ cp = strchr (argv[i], '\n');
+ if (cp != NULL)
+ error ("can't handle command-line argument containing whitespace");
+ length += strlen (argv[i]) + 1;
+ }
+
+ result = (char *) xmalloc (length);
+ result[0] = '\0';
+ for (i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ strcat (result, " ");
+ strcat (result, argv[i]);
+ }
+ }
+
+ return result;
+}
+
+
+/* This function detects whether or not a '&' character (indicating
+ background execution) has been added as *the last* of the arguments ARGS
+ of a command. If it has, it removes it and returns 1. Otherwise it
+ does nothing and returns 0. */
+static int
+strip_bg_char (char **args)
+{
+ char *p = NULL;
+
+ p = strchr (*args, '&');
+
+ if (p)
+ {
+ if (p == (*args + strlen (*args) - 1))
+ {
+ if (strlen (*args) > 1)
+ {
+ do
+ p--;
+ while (*p == ' ' || *p == '\t');
+ *(p + 1) = '\0';
+ }
+ else
+ *args = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+tty_command (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 (char *args, int from_tty)
+{
+ char *exec_file;
+
+ dont_repeat ();
+
+ if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
+ {
+ if (from_tty
+ && !query ("The program being debugged has been started already.\n\
+Start it from the beginning? "))
+ error ("Program not restarted.");
+ target_kill ();
+#if defined(SOLIB_RESTART)
+ SOLIB_RESTART ();
+#endif
+ init_wait_for_inferior ();
+ }
+
+ clear_breakpoint_hit_counts ();
+
+ /* Purge old solib objfiles. */
+ objfile_purge_solibs ();
+
+ do_run_cleanups (NULL);
+
+ /* The comment here used to read, "The exec file is re-read every
+ time we do a generic_mourn_inferior, so we just have to worry
+ about the symbol file." The `generic_mourn_inferior' function
+ gets called whenever the program exits. However, suppose the
+ program exits, and *then* the executable file changes? We need
+ to check again here. Since reopen_exec_file doesn't do anything
+ if the timestamp hasn't changed, I don't see the harm. */
+ reopen_exec_file ();
+ reread_symbols ();
+
+ exec_file = (char *) get_exec_file (0);
+
+ /* 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)
+ {
+ if (event_loop_p && target_can_async_p ())
+ async_disable_stdin ();
+ }
+ else
+ {
+ int async_exec = strip_bg_char (&args);
+
+ /* If we get a request for running in the bg but the target
+ doesn't support it, error out. */
+ if (event_loop_p && async_exec && !target_can_async_p ())
+ error ("Asynchronous execution not supported on this target.");
+
+ /* If we don't get a request of running in the bg, then we need
+ to simulate synchronous (fg) execution. */
+ if (event_loop_p && !async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution */
+ async_disable_stdin ();
+ }
+
+ /* If there were other args, beside '&', process them. */
+ if (args)
+ {
+ char *old_args = set_inferior_args (xstrdup (args));
+ xfree (old_args);
+ }
+ }
+
+ if (from_tty)
+ {
+ ui_out_field_string (uiout, NULL, "Starting program");
+ ui_out_text (uiout, ": ");
+ if (exec_file)
+ ui_out_field_string (uiout, "execfile", exec_file);
+ ui_out_spaces (uiout, 1);
+ /* We call get_inferior_args() because we might need to compute
+ the value now. */
+ ui_out_field_string (uiout, "infargs", get_inferior_args ());
+ ui_out_text (uiout, "\n");
+ ui_out_flush (uiout);
+ }
+
+ /* We call get_inferior_args() because we might need to compute
+ the value now. */
+ target_create_inferior (exec_file, get_inferior_args (),
+ environ_vector (inferior_environ));
+}
+
+
+static void
+run_no_args_command (char *args, int from_tty)
+{
+ char *old_args = set_inferior_args (xstrdup (""));
+ xfree (old_args);
+}
+
+
+void
+continue_command (char *proc_count_exp, int from_tty)
+{
+ int async_exec = 0;
+ ERROR_NO_INFERIOR;
+
+ /* Find out whether we must run in the background. */
+ if (proc_count_exp != NULL)
+ async_exec = strip_bg_char (&proc_count_exp);
+
+ /* If we must run in the background, but the target can't do it,
+ error out. */
+ if (event_loop_p && async_exec && !target_can_async_p ())
+ error ("Asynchronous execution not supported on this target.");
+
+ /* If we are not asked to run in the bg, then prepare to run in the
+ foreground, synchronously. */
+ if (event_loop_p && !async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution */
+ async_disable_stdin ();
+ }
+
+ /* If have argument (besides '&'), 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_long (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. */
+
+static void
+step_command (char *count_string, int from_tty)
+{
+ step_1 (0, 0, count_string);
+}
+
+/* Likewise, but skip over subroutine calls as if single instructions. */
+
+static void
+next_command (char *count_string, int from_tty)
+{
+ step_1 (1, 0, count_string);
+}
+
+/* Likewise, but step only one instruction. */
+
+void
+stepi_command (char *count_string, int from_tty)
+{
+ step_1 (0, 1, count_string);
+}
+
+void
+nexti_command (char *count_string, int from_tty)
+{
+ step_1 (1, 1, count_string);
+}
+
+static void
+disable_longjmp_breakpoint_cleanup (void *ignore)
+{
+ disable_longjmp_breakpoint ();
+}
+
+static void
+step_1 (int skip_subroutines, int single_inst, char *count_string)
+{
+ int count = 1;
+ struct frame_info *frame;
+ struct cleanup *cleanups = 0;
+ int async_exec = 0;
+
+ ERROR_NO_INFERIOR;
+
+ if (count_string)
+ async_exec = strip_bg_char (&count_string);
+
+ /* If we get a request for running in the bg but the target
+ doesn't support it, error out. */
+ if (event_loop_p && async_exec && !target_can_async_p ())
+ error ("Asynchronous execution not supported on this target.");
+
+ /* If we don't get a request of running in the bg, then we need
+ to simulate synchronous (fg) execution. */
+ if (event_loop_p && !async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution */
+ async_disable_stdin ();
+ }
+
+ count = count_string ? parse_and_eval_long (count_string) : 1;
+
+ if (!single_inst || skip_subroutines) /* leave si command alone */
+ {
+ enable_longjmp_breakpoint ();
+ if (!event_loop_p || !target_can_async_p ())
+ cleanups = make_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/);
+ else
+ make_exec_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/);
+ }
+
+ /* In synchronous case, all is well, just use the regular for loop. */
+ if (!event_loop_p || !target_can_async_p ())
+ {
+ for (; count > 0; count--)
+ {
+ clear_proceed_status ();
+
+ frame = get_current_frame ();
+ if (!frame) /* Avoid coredump here. Why tho? */
+ error ("No current frame");
+ step_frame_id = get_frame_id (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 = STEP_OVER_NONE;
+ }
+
+ if (skip_subroutines)
+ step_over_calls = STEP_OVER_ALL;
+
+ step_multi = (count > 1);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+
+ if (!stop_step)
+ break;
+ }
+
+ if (!single_inst || skip_subroutines)
+ do_cleanups (cleanups);
+ return;
+ }
+ /* In case of asynchronous target things get complicated, do only
+ one step for now, before returning control to the event loop. Let
+ the continuation figure out how many other steps we need to do,
+ and handle them one at the time, through step_once(). */
+ else
+ {
+ if (event_loop_p && target_can_async_p ())
+ step_once (skip_subroutines, single_inst, count);
+ }
+}
+
+/* Called after we are done with one step operation, to check whether
+ we need to step again, before we print the prompt and return control
+ to the user. If count is > 1, we will need to do one more call to
+ proceed(), via step_once(). Basically it is like step_once and
+ step_1_continuation are co-recursive. */
+static void
+step_1_continuation (struct continuation_arg *arg)
+{
+ int count;
+ int skip_subroutines;
+ int single_inst;
+
+ skip_subroutines = arg->data.integer;
+ single_inst = arg->next->data.integer;
+ count = arg->next->next->data.integer;
+
+ if (stop_step)
+ step_once (skip_subroutines, single_inst, count - 1);
+ else
+ if (!single_inst || skip_subroutines)
+ do_exec_cleanups (ALL_CLEANUPS);
+}
+
+/* Do just one step operation. If count >1 we will have to set up a
+ continuation to be done after the target stops (after this one
+ step). This is useful to implement the 'step n' kind of commands, in
+ case of asynchronous targets. We had to split step_1 into two parts,
+ one to be done before proceed() and one afterwards. This function is
+ called in case of step n with n>1, after the first step operation has
+ been completed.*/
+static void
+step_once (int skip_subroutines, int single_inst, int count)
+{
+ struct continuation_arg *arg1;
+ struct continuation_arg *arg2;
+ struct continuation_arg *arg3;
+ struct frame_info *frame;
+
+ if (count > 0)
+ {
+ clear_proceed_status ();
+
+ frame = get_current_frame ();
+ if (!frame) /* Avoid coredump here. Why tho? */
+ error ("No current frame");
+ step_frame_id = get_frame_id (frame);
+ step_sp = read_sp ();
+
+ if (!single_inst)
+ {
+ find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
+
+ /* If we have no line info, switch to stepi mode. */
+ if (step_range_end == 0 && step_stop_if_no_debug)
+ {
+ step_range_start = step_range_end = 1;
+ }
+ else 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 = STEP_OVER_NONE;
+ }
+
+ if (skip_subroutines)
+ step_over_calls = STEP_OVER_ALL;
+
+ step_multi = (count > 1);
+ arg1 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg2 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg3 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg1->next = arg2;
+ arg1->data.integer = skip_subroutines;
+ arg2->next = arg3;
+ arg2->data.integer = single_inst;
+ arg3->next = NULL;
+ arg3->data.integer = count;
+ add_intermediate_continuation (step_1_continuation, arg1);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+ }
+}
+
+
+/* Continue program at specified address. */
+
+static void
+jump_command (char *arg, int from_tty)
+{
+ CORE_ADDR addr;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct symbol *fn;
+ struct symbol *sfn;
+ int async_exec = 0;
+
+ ERROR_NO_INFERIOR;
+
+ /* Find out whether we must run in the background. */
+ if (arg != NULL)
+ async_exec = strip_bg_char (&arg);
+
+ /* If we must run in the background, but the target can't do it,
+ error out. */
+ if (event_loop_p && async_exec && !target_can_async_p ())
+ error ("Asynchronous execution not supported on this target.");
+
+ /* If we are not asked to run in the bg, then prepare to run in the
+ foreground, synchronously. */
+ if (event_loop_p && !async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution */
+ async_disable_stdin ();
+ }
+
+ 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];
+ xfree (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_PRINT_NAME (fn)))
+ {
+ error ("Not confirmed.");
+ /* NOTREACHED */
+ }
+ }
+
+ if (sfn != NULL)
+ {
+ fixup_symbol_section (sfn, 0);
+ if (section_is_overlay (SYMBOL_BFD_SECTION (sfn)) &&
+ !section_is_mapped (SYMBOL_BFD_SECTION (sfn)))
+ {
+ if (!query ("WARNING!!! Destination is in unmapped overlay! Jump anyway? "))
+ {
+ 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);
+}
+
+
+/* Go to line or address in current procedure */
+static void
+go_command (char *line_no, int from_tty)
+{
+ if (line_no == (char *) NULL || !*line_no)
+ printf_filtered (GO_USAGE);
+ else
+ {
+ tbreak_command (line_no, from_tty);
+ jump_command (line_no, from_tty);
+ }
+}
+
+
+/* Continue program giving it specified signal. */
+
+static void
+signal_command (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_long (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);
+}
+
+/* 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. */
+
+static void
+until_next_command (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 = STEP_OVER_ALL;
+ step_frame_id = get_frame_id (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 (char *arg, int from_tty)
+{
+ int async_exec = 0;
+
+ if (!target_has_execution)
+ error ("The program is not running.");
+
+ /* Find out whether we must run in the background. */
+ if (arg != NULL)
+ async_exec = strip_bg_char (&arg);
+
+ /* If we must run in the background, but the target can't do it,
+ error out. */
+ if (event_loop_p && async_exec && !target_can_async_p ())
+ error ("Asynchronous execution not supported on this target.");
+
+ /* If we are not asked to run in the bg, then prepare to run in the
+ foreground, synchronously. */
+ if (event_loop_p && !async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution */
+ async_disable_stdin ();
+ }
+
+ if (arg)
+ until_break_command (arg, from_tty, 0);
+ else
+ until_next_command (from_tty);
+}
+
+static void
+advance_command (char *arg, int from_tty)
+{
+ int async_exec = 0;
+
+ if (!target_has_execution)
+ error ("The program is not running.");
+
+ if (arg == NULL)
+ error_no_arg ("a location");
+
+ /* Find out whether we must run in the background. */
+ if (arg != NULL)
+ async_exec = strip_bg_char (&arg);
+
+ /* If we must run in the background, but the target can't do it,
+ error out. */
+ if (event_loop_p && async_exec && !target_can_async_p ())
+ error ("Asynchronous execution not supported on this target.");
+
+ /* If we are not asked to run in the bg, then prepare to run in the
+ foreground, synchronously. */
+ if (event_loop_p && !async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution. */
+ async_disable_stdin ();
+ }
+
+ until_break_command (arg, from_tty, 1);
+}
+
+
+/* Print the result of a function at the end of a 'finish' command. */
+
+static void
+print_return_value (int struct_return, struct type *value_type)
+{
+ struct cleanup *old_chain;
+ struct ui_stream *stb;
+ struct value *value;
+
+ if (!struct_return)
+ {
+ /* The return value can be found in the inferior's registers. */
+ value = register_value_being_returned (value_type, stop_registers);
+ }
+ /* FIXME: cagney/2004-01-17: When both return_value and
+ extract_returned_value_address are available, should use that to
+ find the address of and then extract the returned value. */
+ /* FIXME: 2003-09-27: When returning from a nested inferior function
+ call, it's possible (with no help from the architecture vector)
+ to locate and return/print a "struct return" value. This is just
+ a more complicated case of what is already being done in in the
+ inferior function call code. In fact, when inferior function
+ calls are made async, this will likely be made the norm. */
+ else if (gdbarch_return_value_p (current_gdbarch))
+ /* We cannot determine the contents of the structure because it is
+ on the stack, and we don't know where, since we did not
+ initiate the call, as opposed to the call_function_by_hand
+ case. */
+ {
+ gdb_assert (gdbarch_return_value (current_gdbarch, value_type,
+ NULL, NULL, NULL)
+ == RETURN_VALUE_STRUCT_CONVENTION);
+ ui_out_text (uiout, "Value returned has type: ");
+ ui_out_field_string (uiout, "return-type", TYPE_NAME (value_type));
+ ui_out_text (uiout, ".");
+ ui_out_text (uiout, " Cannot determine contents\n");
+ return;
+ }
+ else
+ {
+ if (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P ())
+ {
+ CORE_ADDR addr = DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS (stop_registers);
+ if (!addr)
+ error ("Function return value unknown.");
+ value = value_at (value_type, addr, NULL);
+ }
+ else
+ {
+ /* It is "struct return" yet the value is being extracted,
+ presumably from registers, using EXTRACT_RETURN_VALUE.
+ This doesn't make sense. Unfortunately, the legacy
+ interfaces allowed this behavior. Sigh! */
+ value = allocate_value (value_type);
+ CHECK_TYPEDEF (value_type);
+ /* If the function returns void, don't bother fetching the
+ return value. */
+ EXTRACT_RETURN_VALUE (value_type, stop_registers,
+ VALUE_CONTENTS_RAW (value));
+ }
+ }
+
+ /* Print it. */
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+ ui_out_text (uiout, "Value returned is ");
+ ui_out_field_fmt (uiout, "gdb-result-var", "$%d",
+ record_latest_value (value));
+ ui_out_text (uiout, " = ");
+ value_print (value, stb->stream, 0, Val_no_prettyprint);
+ ui_out_field_stream (uiout, "return-value", stb);
+ ui_out_text (uiout, "\n");
+ do_cleanups (old_chain);
+}
+
+/* Stuff that needs to be done by the finish command after the target
+ has stopped. In asynchronous mode, we wait for the target to stop
+ in the call to poll or select in the event loop, so it is
+ impossible to do all the stuff as part of the finish_command
+ function itself. The only chance we have to complete this command
+ is in fetch_inferior_event, which is called by the event loop as
+ soon as it detects that the target has stopped. This function is
+ called via the cmd_continuation pointer. */
+
+static void
+finish_command_continuation (struct continuation_arg *arg)
+{
+ struct symbol *function;
+ struct breakpoint *breakpoint;
+ struct cleanup *cleanups;
+
+ breakpoint = (struct breakpoint *) arg->data.pointer;
+ function = (struct symbol *) arg->next->data.pointer;
+ cleanups = (struct cleanup *) arg->next->next->data.pointer;
+
+ if (bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL
+ && function != NULL)
+ {
+ struct type *value_type;
+ int struct_return;
+ int gcc_compiled;
+
+ value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
+ if (!value_type)
+ internal_error (__FILE__, __LINE__,
+ "finish_command: function has no target type");
+
+ if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
+ {
+ do_exec_cleanups (cleanups);
+ return;
+ }
+
+ CHECK_TYPEDEF (value_type);
+ gcc_compiled = BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function));
+ struct_return = using_struct_return (value_type, gcc_compiled);
+
+ print_return_value (struct_return, value_type);
+ }
+
+ do_exec_cleanups (cleanups);
+}
+
+/* "finish": Set a temporary breakpoint at the place the selected
+ frame will return to, then continue. */
+
+static void
+finish_command (char *arg, int from_tty)
+{
+ struct symtab_and_line sal;
+ struct frame_info *frame;
+ struct symbol *function;
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+ struct continuation_arg *arg1, *arg2, *arg3;
+
+ int async_exec = 0;
+
+ /* Find out whether we must run in the background. */
+ if (arg != NULL)
+ async_exec = strip_bg_char (&arg);
+
+ /* If we must run in the background, but the target can't do it,
+ error out. */
+ if (event_loop_p && async_exec && !target_can_async_p ())
+ error ("Asynchronous execution not supported on this target.");
+
+ /* If we are not asked to run in the bg, then prepare to run in the
+ foreground, synchronously. */
+ if (event_loop_p && !async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution. */
+ async_disable_stdin ();
+ }
+
+ if (arg)
+ error ("The \"finish\" command does not take any arguments.");
+ if (!target_has_execution)
+ error ("The program is not running.");
+ if (deprecated_selected_frame == NULL)
+ error ("No selected frame.");
+
+ frame = get_prev_frame (deprecated_selected_frame);
+ if (frame == 0)
+ error ("\"finish\" not meaningful in the outermost frame.");
+
+ clear_proceed_status ();
+
+ sal = find_pc_line (get_frame_pc (frame), 0);
+ sal.pc = get_frame_pc (frame);
+
+ breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish);
+
+ if (!event_loop_p || !target_can_async_p ())
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ else
+ old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
+
+ /* Find the function we will return from. */
+
+ function = find_pc_function (get_frame_pc (deprecated_selected_frame));
+
+ /* Print info on the selected frame, including level number but not
+ source. */
+ if (from_tty)
+ {
+ printf_filtered ("Run till exit from ");
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 0);
+ }
+
+ /* If running asynchronously and the target support asynchronous
+ execution, set things up for the rest of the finish command to be
+ completed later on, when gdb has detected that the target has
+ stopped, in fetch_inferior_event. */
+ if (event_loop_p && target_can_async_p ())
+ {
+ arg1 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg2 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg3 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg1->next = arg2;
+ arg2->next = arg3;
+ arg3->next = NULL;
+ arg1->data.pointer = breakpoint;
+ arg2->data.pointer = function;
+ arg3->data.pointer = old_chain;
+ add_continuation (finish_command_continuation, arg1);
+ }
+
+ proceed_to_finish = 1; /* We want stop_registers, please... */
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+
+ /* Do this only if not running asynchronously or if the target
+ cannot do async execution. Otherwise, complete this command when
+ the target actually stops, in fetch_inferior_event. */
+ if (!event_loop_p || !target_can_async_p ())
+ {
+ /* Did we stop at our breakpoint? */
+ if (bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL
+ && function != NULL)
+ {
+ struct type *value_type;
+ int struct_return;
+ int gcc_compiled;
+
+ value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
+ if (!value_type)
+ internal_error (__FILE__, __LINE__,
+ "finish_command: function has no target type");
+
+ /* FIXME: Shouldn't we do the cleanups before returning? */
+ if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
+ return;
+
+ CHECK_TYPEDEF (value_type);
+ gcc_compiled = BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function));
+ struct_return = using_struct_return (value_type, gcc_compiled);
+
+ print_return_value (struct_return, value_type);
+ }
+
+ do_cleanups (old_chain);
+ }
+}
+
+
+static void
+program_info (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 ");
+ printf_filtered ("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\" ");
+ printf_filtered ("for more information.\n");
+ }
+}
+
+static void
+environment_info (char *var, int from_tty)
+{
+ if (var)
+ {
+ 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
+ {
+ char **vector = environ_vector (inferior_environ);
+ while (*vector)
+ {
+ puts_filtered (*vector++);
+ puts_filtered ("\n");
+ }
+ }
+}
+
+static void
+set_environment_command (char *arg, int from_tty)
+{
+ 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 ");
+ printf_filtered ("\"%s\" to null value.\n", var);
+ set_in_environ (inferior_environ, var, "");
+ }
+ else
+ set_in_environ (inferior_environ, var, val);
+ xfree (var);
+}
+
+static void
+unset_environment_command (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";
+
+static void
+path_info (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 (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 = xstrdup (env);
+ mod_path (dirname, &exec_path);
+ set_in_environ (inferior_environ, path_var_name, exec_path);
+ xfree (exec_path);
+ if (from_tty)
+ path_info ((char *) NULL, from_tty);
+}
+
+
+/* Print out the machine register regnum. If regnum is -1, print all
+ registers (print_all == 1) or all non-float and non-vector
+ registers (print_all == 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 architecture method PRINT_REGISTERS_INFO to
+ provide that format. */
+
+void
+default_print_registers_info (struct gdbarch *gdbarch,
+ struct ui_file *file,
+ struct frame_info *frame,
+ int regnum, int print_all)
+{
+ int i;
+ const int numregs = NUM_REGS + NUM_PSEUDO_REGS;
+ char raw_buffer[MAX_REGISTER_SIZE];
+ char virtual_buffer[MAX_REGISTER_SIZE];
+
+ if (DEPRECATED_DO_REGISTERS_INFO_P ())
+ {
+ DEPRECATED_DO_REGISTERS_INFO (regnum, print_all);
+ return;
+ }
+
+ for (i = 0; i < numregs; i++)
+ {
+ /* Decide between printing all regs, non-float / vector regs, or
+ specific reg. */
+ if (regnum == -1)
+ {
+ if (print_all)
+ {
+ if (!gdbarch_register_reggroup_p (gdbarch, i, all_reggroup))
+ continue;
+ }
+ else
+ {
+ if (!gdbarch_register_reggroup_p (gdbarch, i, general_reggroup))
+ continue;
+ }
+ }
+ else
+ {
+ if (i != regnum)
+ continue;
+ }
+
+ /* If the register name is empty, it is undefined for this
+ processor, so don't display anything. */
+ if (REGISTER_NAME (i) == NULL || *(REGISTER_NAME (i)) == '\0')
+ continue;
+
+ fputs_filtered (REGISTER_NAME (i), file);
+ print_spaces_filtered (15 - strlen (REGISTER_NAME (i)), file);
+
+ /* Get the data in raw format. */
+ if (! frame_register_read (frame, i, raw_buffer))
+ {
+ fprintf_filtered (file, "*value not available*\n");
+ continue;
+ }
+
+ /* FIXME: cagney/2002-08-03: This code shouldn't be necessary.
+ The function frame_register_read() should have returned the
+ pre-cooked register so no conversion is necessary. */
+ /* Convert raw data to virtual format if necessary. */
+ if (DEPRECATED_REGISTER_CONVERTIBLE_P ()
+ && DEPRECATED_REGISTER_CONVERTIBLE (i))
+ {
+ DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (i, register_type (current_gdbarch, i),
+ raw_buffer, virtual_buffer);
+ }
+ else
+ {
+ memcpy (virtual_buffer, raw_buffer,
+ DEPRECATED_REGISTER_VIRTUAL_SIZE (i));
+ }
+
+ /* If virtual format is floating, print it that way, and in raw
+ hex. */
+ if (TYPE_CODE (register_type (current_gdbarch, i)) == TYPE_CODE_FLT)
+ {
+ int j;
+
+ val_print (register_type (current_gdbarch, i), virtual_buffer, 0, 0,
+ file, 0, 1, 0, Val_pretty_default);
+
+ fprintf_filtered (file, "\t(raw 0x");
+ for (j = 0; j < DEPRECATED_REGISTER_RAW_SIZE (i); j++)
+ {
+ int idx;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ idx = j;
+ else
+ idx = DEPRECATED_REGISTER_RAW_SIZE (i) - 1 - j;
+ fprintf_filtered (file, "%02x", (unsigned char) raw_buffer[idx]);
+ }
+ fprintf_filtered (file, ")");
+ }
+ else
+ {
+ /* Print the register in hex. */
+ val_print (register_type (current_gdbarch, i), virtual_buffer, 0, 0,
+ file, 'x', 1, 0, Val_pretty_default);
+ /* If not a vector register, print it also according to its
+ natural format. */
+ if (TYPE_VECTOR (register_type (current_gdbarch, i)) == 0)
+ {
+ fprintf_filtered (file, "\t");
+ val_print (register_type (current_gdbarch, i), virtual_buffer, 0, 0,
+ file, 0, 1, 0, Val_pretty_default);
+ }
+ }
+
+ fprintf_filtered (file, "\n");
+ }
+}
+
+void
+registers_info (char *addr_exp, int fpregs)
+{
+ int regnum, numregs;
+ char *end;
+
+ if (!target_has_registers)
+ error ("The program has no registers now.");
+ if (deprecated_selected_frame == NULL)
+ error ("No selected frame.");
+
+ if (!addr_exp)
+ {
+ gdbarch_print_registers_info (current_gdbarch, gdb_stdout,
+ deprecated_selected_frame, -1, fpregs);
+ return;
+ }
+
+ while (*addr_exp != '\0')
+ {
+ char *start;
+ const char *end;
+
+ /* Keep skipping leading white space. */
+ if (isspace ((*addr_exp)))
+ {
+ addr_exp++;
+ continue;
+ }
+
+ /* Discard any leading ``$''. Check that there is something
+ resembling a register following it. */
+ if (addr_exp[0] == '$')
+ addr_exp++;
+ if (isspace ((*addr_exp)) || (*addr_exp) == '\0')
+ error ("Missing register name");
+
+ /* Find the start/end of this register name/num/group. */
+ start = addr_exp;
+ while ((*addr_exp) != '\0' && !isspace ((*addr_exp)))
+ addr_exp++;
+ end = addr_exp;
+
+ /* Figure out what we've found and display it. */
+
+ /* A register name? */
+ {
+ int regnum = frame_map_name_to_regnum (deprecated_selected_frame,
+ start, end - start);
+ if (regnum >= 0)
+ {
+ gdbarch_print_registers_info (current_gdbarch, gdb_stdout,
+ deprecated_selected_frame, regnum, fpregs);
+ continue;
+ }
+ }
+
+ /* A register number? (how portable is this one?). */
+ {
+ char *endptr;
+ int regnum = strtol (start, &endptr, 0);
+ if (endptr == end
+ && regnum >= 0
+ && regnum < NUM_REGS + NUM_PSEUDO_REGS)
+ {
+ gdbarch_print_registers_info (current_gdbarch, gdb_stdout,
+ deprecated_selected_frame, regnum, fpregs);
+ continue;
+ }
+ }
+
+ /* A register group? */
+ {
+ struct reggroup *group;
+ for (group = reggroup_next (current_gdbarch, NULL);
+ group != NULL;
+ group = reggroup_next (current_gdbarch, group))
+ {
+ /* Don't bother with a length check. Should the user
+ enter a short register group name, go with the first
+ group that matches. */
+ if (strncmp (start, reggroup_name (group), end - start) == 0)
+ break;
+ }
+ if (group != NULL)
+ {
+ int regnum;
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ if (gdbarch_register_reggroup_p (current_gdbarch, regnum,
+ group))
+ gdbarch_print_registers_info (current_gdbarch,
+ gdb_stdout, deprecated_selected_frame,
+ regnum, fpregs);
+ }
+ continue;
+ }
+ }
+
+ /* Nothing matched. */
+ error ("Invalid register `%.*s'", (int) (end - start), start);
+ }
+}
+
+void
+all_registers_info (char *addr_exp, int from_tty)
+{
+ registers_info (addr_exp, 1);
+}
+
+static void
+nofp_registers_info (char *addr_exp, int from_tty)
+{
+ registers_info (addr_exp, 0);
+}
+
+static void
+print_vector_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, const char *args)
+{
+ if (!target_has_registers)
+ error ("The program has no registers now.");
+ if (deprecated_selected_frame == NULL)
+ error ("No selected frame.");
+
+ if (gdbarch_print_vector_info_p (gdbarch))
+ gdbarch_print_vector_info (gdbarch, file, frame, args);
+ else
+ {
+ int regnum;
+ int printed_something = 0;
+
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, vector_reggroup))
+ {
+ printed_something = 1;
+ gdbarch_print_registers_info (gdbarch, file, frame, regnum, 1);
+ }
+ }
+ if (!printed_something)
+ fprintf_filtered (file, "No vector information\n");
+ }
+}
+
+static void
+vector_info (char *args, int from_tty)
+{
+ print_vector_info (current_gdbarch, gdb_stdout, deprecated_selected_frame, args);
+}
+
+
+/*
+ * 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 (char *args, int from_tty)
+{
+ char *exec_file;
+ char *full_exec_path = NULL;
+
+ 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 ();
+
+ /* No traps are generated when attaching to inferior under Mach 3
+ or GNU hurd. */
+#ifndef ATTACH_NO_WAIT
+ /* Careful here. See comments in inferior.h. Basically some OSes
+ don't ignore SIGSTOPs on continue requests anymore. We need a
+ way for handle_inferior_event to reset the stop_signal variable
+ after an attach, and this is what STOP_QUIETLY_NO_SIGSTOP is for. */
+ stop_soon = STOP_QUIETLY_NO_SIGSTOP;
+ wait_for_inferior ();
+ stop_soon = NO_STOP_QUIETLY;
+#endif
+
+ /*
+ * If no exec file is yet known, try to determine it from the
+ * process itself.
+ */
+ exec_file = (char *) get_exec_file (0);
+ if (!exec_file)
+ {
+ exec_file = target_pid_to_exec_file (PIDGET (inferior_ptid));
+ if (exec_file)
+ {
+ /* It's possible we don't have a full path, but rather just a
+ filename. Some targets, such as HP-UX, don't provide the
+ full path, sigh.
+
+ Attempt to qualify the filename against the source path.
+ (If that fails, we'll just fall back on the original
+ filename. Not much more we can do...)
+ */
+ if (!source_full_path_of (exec_file, &full_exec_path))
+ full_exec_path = savestring (exec_file, strlen (exec_file));
+
+ exec_file_attach (full_exec_path, from_tty);
+ symbol_file_add_main (full_exec_path, from_tty);
+ }
+ }
+
+#ifdef SOLIB_ADD
+ /* Add shared library symbols from the newly attached process, if any. */
+ SOLIB_ADD ((char *) 0, from_tty, &current_target, auto_solib_add);
+ re_enable_breakpoints_in_shlibs ();
+#endif
+
+ /* Take any necessary post-attaching actions for this platform.
+ */
+ target_post_attach (PIDGET (inferior_ptid));
+
+ normal_stop ();
+
+ if (attach_hook)
+ attach_hook ();
+}
+
+/*
+ * 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 (char *args, int from_tty)
+{
+ dont_repeat (); /* Not for the faint of heart */
+ target_detach (args, from_tty);
+#if defined(SOLIB_RESTART)
+ SOLIB_RESTART ();
+#endif
+ if (detach_hook)
+ detach_hook ();
+}
+
+/* Disconnect from the current target without resuming it (leaving it
+ waiting for a debugger).
+
+ We'd better not have left any breakpoints in the program or the
+ next debugger will get confused. Currently only supported for some
+ remote targets, since the normal attach mechanisms don't work on
+ stopped processes on some native platforms (e.g. GNU/Linux). */
+
+static void
+disconnect_command (char *args, int from_tty)
+{
+ dont_repeat (); /* Not for the faint of heart */
+ target_disconnect (args, from_tty);
+#if defined(SOLIB_RESTART)
+ SOLIB_RESTART ();
+#endif
+ if (detach_hook)
+ detach_hook ();
+}
+
+/* Stop the execution of the target while running in async mode, in
+ the backgound. */
+void
+interrupt_target_command (char *args, int from_tty)
+{
+ if (event_loop_p && target_can_async_p ())
+ {
+ dont_repeat (); /* Not for the faint of heart */
+ target_stop ();
+ }
+}
+
+static void
+print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, const char *args)
+{
+ if (!target_has_registers)
+ error ("The program has no registers now.");
+ if (deprecated_selected_frame == NULL)
+ error ("No selected frame.");
+
+ if (gdbarch_print_float_info_p (gdbarch))
+ gdbarch_print_float_info (gdbarch, file, frame, args);
+ else
+ {
+ int regnum;
+ int printed_something = 0;
+
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, float_reggroup))
+ {
+ printed_something = 1;
+ gdbarch_print_registers_info (gdbarch, file, frame, regnum, 1);
+ }
+ }
+ if (!printed_something)
+ fprintf_filtered (file, "\
+No floating-point info available for this processor.\n");
+ }
+}
+
+static void
+float_info (char *args, int from_tty)
+{
+ print_float_info (current_gdbarch, gdb_stdout, deprecated_selected_frame, args);
+}
+
+static void
+unset_command (char *args, int from_tty)
+{
+ printf_filtered ("\"unset\" must be followed by the name of ");
+ printf_filtered ("an unset subcommand.\n");
+ help_list (unsetlist, "unset ", -1, gdb_stdout);
+}
+
+void
+_initialize_infcmd (void)
+{
+ struct cmd_list_element *c;
+
+ c = add_com ("tty", class_run, tty_command,
+ "Set terminal for future runs of program being debugged.");
+ set_cmd_completer (c, filename_completer);
+
+ c = add_set_cmd ("args", class_run, var_string_noescape,
+ (char *) &inferior_args,
+ "Set argument list 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);
+ set_cmd_completer (c, filename_completer);
+ set_cmd_sfunc (c, notice_args_set);
+ c = add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, notice_args_read);
+
+ 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);
+ set_cmd_completer (c, 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);
+ set_cmd_completer (c, 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);
+ set_cmd_completer (c, noop_completer);
+
+ c = 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.");
+ set_cmd_completer (c, filename_completer);
+
+ 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);
+ set_cmd_completer (c, 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\" with a process id, the debugger finds the\n\
+program running in the process, looking first in the current working\n\
+directory, or (if not found there) using the source file search path\n\
+(see the \"directory\" command). You can also use the \"file\" command\n\
+to specify the program, 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\n\
+you were debugging a file, the file is closed and gdb no longer accesses it.");
+
+ add_com ("disconnect", class_run, disconnect_command,
+ "Disconnect from a target.\n\
+The target will wait for another debugger to connect. Not available for\n\
+all targets.");
+
+ 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);
+ if (xdb_commands)
+ add_com_alias ("S", "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);
+
+ c = add_com ("until", class_run, until_command,
+ "Execute until the program reaches a source line greater than the current\n\
+or a specified location (same args as break command) within the current frame.");
+ set_cmd_completer (c, location_completer);
+ add_com_alias ("u", "until", class_run, 1);
+
+ c = add_com ("advance", class_run, advance_command,
+ "Continue the program up to the given location (same form as args for break command).\n\
+Execution will also stop upon exit from the current stack frame.");
+ set_cmd_completer (c, location_completer);
+
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ if (xdb_commands)
+ {
+ c = add_com ("go", class_run, go_command,
+ "Usage: go <location>\n\
+Continue program being debugged, stopping at specified line or \n\
+address.\n\
+Give as argument either LINENUM or *ADDR, where ADDR is an \n\
+expression for an address to start at.\n\
+This command is a combination of tbreak and jump.");
+ set_cmd_completer (c, location_completer);
+ }
+
+ if (xdb_commands)
+ add_com_alias ("g", "go", class_run, 1);
+
+ 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);
+
+ c = 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.");
+ set_cmd_completer (c, filename_completer);
+ add_com_alias ("r", "run", class_run, 1);
+ if (xdb_commands)
+ add_com ("R", class_run, run_no_args_command,
+ "Start debugged program with no arguments.");
+
+ add_com ("interrupt", class_run, interrupt_target_command,
+ "Interrupt the execution of the debugged program.");
+
+ 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_alias ("r", "registers", 1);
+
+ if (xdb_commands)
+ add_com ("lr", class_info, 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");
+
+ add_info ("vector", vector_info,
+ "Print the status of the vector unit\n");
+
+ 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 0000000..b36dcd4
--- /dev/null
+++ b/contrib/gdb/gdb/inferior.h
@@ -0,0 +1,495 @@
+/* Variables that describe the inferior process running under GDB:
+ Where it is, why it stopped, and how to step it.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+struct target_waitstatus;
+struct frame_info;
+struct ui_file;
+struct type;
+struct gdbarch;
+struct regcache;
+
+/* For bpstat. */
+#include "breakpoint.h"
+
+/* For enum target_signal. */
+#include "target.h"
+
+/* For struct frame_id. */
+#include "frame.h"
+
+/* Structure in which to save the status of the inferior. Create/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;
+
+extern struct inferior_status *save_inferior_status (int);
+
+extern void restore_inferior_status (struct inferior_status *);
+
+extern struct cleanup *make_cleanup_restore_inferior_status (struct inferior_status *);
+
+extern void discard_inferior_status (struct inferior_status *);
+
+extern void write_inferior_status_register (struct inferior_status
+ *inf_status, int regno,
+ LONGEST val);
+
+/* The -1 ptid, often used to indicate either an error condition
+ or a "don't care" condition, i.e, "run all threads." */
+extern ptid_t minus_one_ptid;
+
+/* The null or zero ptid, often used to indicate no process. */
+extern ptid_t null_ptid;
+
+/* Attempt to find and return an existing ptid with the given PID, LWP,
+ and TID components. If none exists, create a new one and return
+ that. */
+ptid_t ptid_build (int pid, long lwp, long tid);
+
+/* Find/Create a ptid from just a pid. */
+ptid_t pid_to_ptid (int pid);
+
+/* Fetch the pid (process id) component from a ptid. */
+int ptid_get_pid (ptid_t ptid);
+
+/* Fetch the lwp (lightweight process) component from a ptid. */
+long ptid_get_lwp (ptid_t ptid);
+
+/* Fetch the tid (thread id) component from a ptid. */
+long ptid_get_tid (ptid_t ptid);
+
+/* Compare two ptids to see if they are equal */
+extern int ptid_equal (ptid_t p1, ptid_t p2);
+
+/* Save value of inferior_ptid so that it may be restored by
+ a later call to do_cleanups(). Returns the struct cleanup
+ pointer needed for later doing the cleanup. */
+extern struct cleanup * save_inferior_ptid (void);
+
+extern void set_sigint_trap (void);
+
+extern void clear_sigint_trap (void);
+
+extern void set_sigio_trap (void);
+
+extern void clear_sigio_trap (void);
+
+/* File name for default use for standard in/out in the inferior. */
+
+extern char *inferior_io_terminal;
+
+/* Collected pid, tid, etc. of the debugged inferior. When there's
+ no inferior, PIDGET (inferior_ptid) will be 0. */
+
+extern ptid_t inferior_ptid;
+
+/* Is the inferior running right now, as a result of a 'run&',
+ 'continue&' etc command? This is used in asycn gdb to determine
+ whether a command that the user enters while the target is running
+ is allowed or not. */
+extern int target_executing;
+
+/* Are we simulating synchronous execution? This is used in async gdb
+ to implement the 'run', 'continue' etc commands, which will not
+ redisplay the prompt until the execution is actually over. */
+extern int sync_execution;
+
+/* This is only valid when inferior_ptid is non-zero.
+
+ If this is 0, then exec events should be noticed and responded to
+ by the debugger (i.e., be reported to the user).
+
+ If this is > 0, then that many subsequent exec events should be
+ ignored (i.e., not be reported to the user).
+ */
+extern int inferior_ignoring_startup_exec_events;
+
+/* This is only valid when inferior_ignoring_startup_exec_events is
+ zero.
+
+ Some targets (stupidly) report more than one exec event per actual
+ call to an event() system call. If only the last such exec event
+ need actually be noticed and responded to by the debugger (i.e.,
+ be reported to the user), then this is the number of "leading"
+ exec events which should be ignored.
+ */
+extern int inferior_ignoring_leading_exec_events;
+
+/* Inferior environment. */
+
+extern struct environ *inferior_environ;
+
+extern void clear_proceed_status (void);
+
+extern void proceed (CORE_ADDR, enum target_signal, int);
+
+/* When set, stop the 'step' command if we enter a function which has
+ no line number information. The normal behavior is that we step
+ over such function. */
+extern int step_stop_if_no_debug;
+
+extern void kill_inferior (void);
+
+extern void generic_mourn_inferior (void);
+
+extern void terminal_save_ours (void);
+
+extern void terminal_ours (void);
+
+extern CORE_ADDR read_pc (void);
+
+extern CORE_ADDR read_pc_pid (ptid_t);
+
+extern void write_pc (CORE_ADDR);
+
+extern void write_pc_pid (CORE_ADDR, ptid_t);
+
+extern void generic_target_write_pc (CORE_ADDR, ptid_t);
+
+extern CORE_ADDR read_sp (void);
+
+extern void deprecated_write_sp (CORE_ADDR);
+
+extern CORE_ADDR deprecated_read_fp (void);
+
+extern CORE_ADDR unsigned_pointer_to_address (struct type *type, const void *buf);
+
+extern void unsigned_address_to_pointer (struct type *type, void *buf,
+ CORE_ADDR addr);
+extern CORE_ADDR signed_pointer_to_address (struct type *type,
+ const void *buf);
+extern void address_to_signed_pointer (struct type *type, void *buf,
+ CORE_ADDR addr);
+
+extern void wait_for_inferior (void);
+
+extern void fetch_inferior_event (void *);
+
+extern void init_wait_for_inferior (void);
+
+extern void close_exec_file (void);
+
+extern void reopen_exec_file (void);
+
+/* The `resume' routine should only be called in special circumstances.
+ Normally, use `proceed', which handles a lot of bookkeeping. */
+
+extern void resume (int, enum target_signal);
+
+/* From misc files */
+
+extern void default_print_registers_info (struct gdbarch *gdbarch,
+ struct ui_file *file,
+ struct frame_info *frame,
+ int regnum, int all);
+
+extern void store_inferior_registers (int);
+
+extern void fetch_inferior_registers (int);
+
+extern void solib_create_inferior_hook (void);
+
+extern void child_terminal_info (char *, int);
+
+extern void term_info (char *, int);
+
+extern void terminal_ours_for_output (void);
+
+extern void terminal_inferior (void);
+
+extern void terminal_init_inferior (void);
+
+extern void terminal_init_inferior_with_pgrp (int pgrp);
+
+/* From infptrace.c or infttrace.c */
+
+extern int attach (int);
+
+extern void detach (int);
+
+/* PTRACE method of waiting for inferior process. */
+int ptrace_wait (ptid_t, int *);
+
+extern void child_resume (ptid_t, int, enum target_signal);
+
+#ifndef PTRACE_ARG3_TYPE
+#define PTRACE_ARG3_TYPE int /* Correct definition for most systems. */
+#endif
+
+extern int call_ptrace (int, int, PTRACE_ARG3_TYPE, int);
+
+extern void pre_fork_inferior (void);
+
+/* From procfs.c */
+
+extern int proc_iterate_over_mappings (int (*)(int, CORE_ADDR));
+
+extern ptid_t procfs_first_available (void);
+
+/* From fork-child.c */
+
+extern void fork_inferior (char *, char *, char **,
+ void (*)(void),
+ void (*)(int), void (*)(void), char *);
+
+
+extern void startup_inferior (int);
+
+extern char *construct_inferior_arguments (struct gdbarch *, int, char **);
+
+/* From inflow.c */
+
+extern void new_tty_prefork (char *);
+
+extern int gdb_has_a_terminal (void);
+
+/* From infrun.c */
+
+extern void start_remote (void);
+
+extern void normal_stop (void);
+
+extern int signal_stop_state (int);
+
+extern int signal_print_state (int);
+
+extern int signal_pass_state (int);
+
+extern int signal_stop_update (int, int);
+
+extern int signal_print_update (int, int);
+
+extern int signal_pass_update (int, int);
+
+extern void get_last_target_status(ptid_t *ptid,
+ struct target_waitstatus *status);
+
+extern void follow_inferior_reset_breakpoints (void);
+
+/* From infcmd.c */
+
+extern void tty_command (char *, int);
+
+extern void attach_command (char *, int);
+
+extern char *get_inferior_args (void);
+
+extern char *set_inferior_args (char *);
+
+extern void set_inferior_args_vector (int, char **);
+
+extern void registers_info (char *, int);
+
+extern void nexti_command (char *, int);
+
+extern void stepi_command (char *, int);
+
+extern void continue_command (char *, int);
+
+extern void interrupt_target_command (char *args, int from_tty);
+
+/* 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 struct frame_id step_frame_id;
+
+/* 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. */
+
+enum step_over_calls_kind
+ {
+ STEP_OVER_NONE,
+ STEP_OVER_ALL,
+ STEP_OVER_UNDEBUGGABLE
+ };
+
+extern enum step_over_calls_kind 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 when running in the shell before the child
+ program has been exec'd; and when running some kinds of remote
+ stuff (FIXME?). */
+
+/* It is also used after attach, due to attaching to a process. This
+ is a bit trickier. When doing an attach, the kernel stops the
+ debuggee with a SIGSTOP. On newer GNU/Linux kernels (>= 2.5.61)
+ the handling of SIGSTOP for a ptraced process has changed. Earlier
+ versions of the kernel would ignore these SIGSTOPs, while now
+ SIGSTOP is treated like any other signal, i.e. it is not muffled.
+
+ If the gdb user does a 'continue' after the 'attach', gdb passes
+ the global variable stop_signal (which stores the signal from the
+ attach, SIGSTOP) to the ptrace(PTRACE_CONT,...) call. This is
+ problematic, because the kernel doesn't ignore such SIGSTOP
+ now. I.e. it is reported back to gdb, which in turn presents it
+ back to the user.
+
+ To avoid the problem, we use STOP_QUIETLY_NO_SIGSTOP, which allows
+ gdb to clear the value of stop_signal after the attach, so that it
+ is not passed back down to the kernel. */
+
+enum stop_kind
+ {
+ NO_STOP_QUIETLY = 0,
+ STOP_QUIETLY,
+ STOP_QUIETLY_NO_SIGSTOP
+ };
+
+extern enum stop_kind stop_soon;
+
+/* 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 struct regcache *stop_registers;
+
+/* Nonzero if the child process in inferior_ptid was attached rather
+ than forked. */
+
+extern int attach_flag;
+
+/* Possible values for CALL_DUMMY_LOCATION. */
+#define ON_STACK 1
+#define AT_ENTRY_POINT 4
+#define AT_SYMBOL 5
+
+/* FIXME: cagney/2000-04-17: gdbarch should manage this. The default
+ shouldn't be necessary. */
+
+#if !defined PUSH_DUMMY_FRAME
+#define PUSH_DUMMY_FRAME (internal_error (__FILE__, __LINE__, "PUSH_DUMMY_FRAME"), 0)
+#endif
+
+#if !defined STORE_STRUCT_RETURN
+#define STORE_STRUCT_RETURN(a1,a2) (internal_error (__FILE__, __LINE__, "STORE_STRUCT_RETURN"), 0)
+#endif
+
+
+/* Are we in a call dummy? */
+
+/* NOTE: cagney/2002-11-24: Targets need to both switch to generic
+ dummy frames, and use generic_pc_in_call_dummy(). The generic
+ version should be able to handle all cases since that code works by
+ saving the address of the dummy's breakpoint (where ever it is). */
+
+extern int deprecated_pc_in_call_dummy_on_stack (CORE_ADDR pc,
+ CORE_ADDR sp,
+ CORE_ADDR frame_address);
+
+/* NOTE: cagney/2002-11-24: Targets need to both switch to generic
+ dummy frames, and use generic_pc_in_call_dummy(). The generic
+ version should be able to handle all cases since that code works by
+ saving the address of the dummy's breakpoint (where ever it is). */
+
+extern int deprecated_pc_in_call_dummy_at_entry_point (CORE_ADDR pc,
+ CORE_ADDR sp,
+ CORE_ADDR frame_address);
+
+/* If STARTUP_WITH_SHELL is set, GDB's "run"
+ will attempts to start up the debugee under a shell.
+ This is in order for argument-expansion to occur. E.g.,
+ (gdb) run *
+ The "*" gets expanded by the shell into a list of files.
+ While this is a nice feature, it turns out to interact badly
+ with some of the catch-fork/catch-exec features we have added.
+ In particular, if the shell does any fork/exec's before
+ the exec of the target program, that can confuse GDB.
+ To disable this feature, set STARTUP_WITH_SHELL to 0.
+ To enable this feature, set STARTUP_WITH_SHELL to 1.
+ The catch-exec traps expected during start-up will
+ be 1 if target is not started up with a shell, 2 if it is.
+ - RT
+ If you disable this, you need to decrement
+ START_INFERIOR_TRAPS_EXPECTED in tm.h. */
+#define STARTUP_WITH_SHELL 1
+#if !defined(START_INFERIOR_TRAPS_EXPECTED)
+#define START_INFERIOR_TRAPS_EXPECTED 2
+#endif
+#endif /* !defined (INFERIOR_H) */
diff --git a/contrib/gdb/gdb/inflow.c b/contrib/gdb/gdb/inflow.c
new file mode 100644
index 0000000..35cd799
--- /dev/null
+++ b/contrib/gdb/gdb/inflow.c
@@ -0,0 +1,771 @@
+/* Low level interface to ptrace, for GDB when running under Unix.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "serial.h"
+#include "terminal.h"
+#include "target.h"
+#include "gdbthread.h"
+
+#include "gdb_string.h"
+#include <signal.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include "inflow.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if defined (SIGIO) && defined (FASYNC) && defined (FD_SET) && defined (F_SETOWN)
+static void handle_sigio (int);
+#endif
+
+extern void _initialize_inflow (void);
+
+static void pass_signal (int);
+
+static void kill_command (char *, int);
+
+static void terminal_ours_1 (int);
+
+/* Record terminal status separately for debugger and inferior. */
+
+static struct serial *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
+ (). */
+
+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 (void)
+{
+ 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_TERMIO
+ our_process_group = getpgrp ();
+#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, safe_strerror (errno))
+
+static void terminal_ours_1 (int);
+
+/* Initialize the terminal settings we record for the inferior,
+ before we actually run the inferior. */
+
+void
+terminal_init_inferior_with_pgrp (int pgrp)
+{
+ 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)
+ xfree (inferior_ttystate);
+ inferior_ttystate = serial_get_tty_state (stdin_serial);
+
+#ifdef PROCESS_GROUP_TYPE
+ inferior_process_group = pgrp;
+#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;
+ }
+}
+
+/* Save the terminal settings again. This is necessary for the TUI
+ when it switches to TUI or non-TUI mode; curses changes the terminal
+ and gdb must be able to restore it correctly. */
+
+void
+terminal_save_ours (void)
+{
+ 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 (our_ttystate)
+ xfree (our_ttystate);
+ our_ttystate = serial_get_tty_state (stdin_serial);
+ }
+}
+
+void
+terminal_init_inferior (void)
+{
+#ifdef PROCESS_GROUP_TYPE
+ /* 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_ptid to the same routine). */
+ /* We assume INFERIOR_PID is also the child's process group. */
+ terminal_init_inferior_with_pgrp (PIDGET (inferior_ptid));
+#endif /* PROCESS_GROUP_TYPE */
+}
+
+/* Put the inferior's terminal settings into effect.
+ This is preparation for starting or resuming the inferior. */
+
+void
+terminal_inferior (void)
+{
+ if (gdb_has_a_terminal () && terminal_is_ours
+ && inferior_ttystate != NULL
+ && 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);
+#ifdef SIGQUIT
+ sigquit_ours = (void (*)()) signal (SIGQUIT, SIG_IGN);
+#endif
+ }
+
+ /* 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 (void)
+{
+ 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 (void)
+{
+ 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 (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)
+ {
+#ifdef SIGTTOU
+ /* Ignore this signal since it will happen when we try to set the
+ pgrp. */
+ void (*osigttou) () = NULL;
+#endif
+ int result;
+
+ terminal_is_ours = 1;
+
+#ifdef SIGTTOU
+ if (job_control)
+ osigttou = (void (*)()) signal (SIGTTOU, SIG_IGN);
+#endif
+
+ if (inferior_ttystate)
+ xfree (inferior_ttystate);
+ inferior_ttystate = serial_get_tty_state (stdin_serial);
+#ifdef HAVE_TERMIOS
+ inferior_process_group = tcgetpgrp (0);
+#endif
+#ifdef HAVE_TERMIO
+ inferior_process_group = getpgrp ();
+#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",
+ safe_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);
+#ifdef SIGQUIT
+ signal (SIGQUIT, sigquit_ours);
+#endif
+ }
+
+#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 */
+ }
+}
+
+void
+term_info (char *arg, int from_tty)
+{
+ target_terminal_info (arg, from_tty);
+}
+
+void
+child_terminal_info (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",
+ (int) inferior_process_group);
+#endif
+
+ serial_print_tty_state (stdin_serial, inferior_ttystate, gdb_stdout);
+}
+
+/* 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 (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 (void)
+{
+ 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. */
+
+static void
+kill_command (char *arg, int from_tty)
+{
+ /* FIXME: This should not really be inferior_ptid (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 (ptid_equal (inferior_ptid, null_ptid))
+ 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 (deprecated_selected_frame == NULL)
+ fputs_filtered ("No selected stack frame.\n", gdb_stdout);
+ else
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 1);
+ }
+}
+
+/* Call set_sigint_trap when you need to pass a signal on to an attached
+ process when handling SIGINT */
+
+static void
+pass_signal (int signo)
+{
+#ifndef _WIN32
+ kill (PIDGET (inferior_ptid), SIGINT);
+#endif
+}
+
+static void (*osig) ();
+
+void
+set_sigint_trap (void)
+{
+ if (attach_flag || inferior_thisrun_terminal)
+ {
+ osig = (void (*)()) signal (SIGINT, pass_signal);
+ }
+}
+
+void
+clear_sigint_trap (void)
+{
+ 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 (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))
+ {
+#ifndef _WIN32
+ if ((*target_activity_function) ())
+ kill (PIDGET (inferior_ptid), SIGINT);
+#endif
+ }
+}
+
+static int old_fcntl_flags;
+
+void
+set_sigio_trap (void)
+{
+ 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 (void)
+{
+ if (target_activity_function)
+ {
+ signal (SIGIO, old_sigio);
+ fcntl (target_activity_fd, F_SETFL, old_fcntl_flags);
+ }
+}
+#else /* No SIGIO. */
+void
+set_sigio_trap (void)
+{
+ if (target_activity_function)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+}
+
+void
+clear_sigio_trap (void)
+{
+ if (target_activity_function)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+}
+#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 (void)
+{
+ int retval = 0;
+
+ if (job_control)
+ {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+ /* The call 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
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+ retval = setpgrp ();
+#else
+ retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+ }
+
+ return retval;
+}
+
+void
+_initialize_inflow (void)
+{
+ 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_ptid = null_ptid;
+
+ 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/inflow.h b/contrib/gdb/gdb/inflow.h
new file mode 100644
index 0000000..1cbfa71
--- /dev/null
+++ b/contrib/gdb/gdb/inflow.h
@@ -0,0 +1,51 @@
+/* Low level interface to ptrace, for GDB when running under Unix.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 INFLOW_H
+#define INFLOW_H
+
+#include "terminal.h" /* For HAVE_TERMIOS et.al. */
+
+#ifdef HAVE_TERMIOS
+#define PROCESS_GROUP_TYPE pid_t
+#endif
+
+#ifdef HAVE_TERMIO
+#define PROCESS_GROUP_TYPE int
+#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 */
+
+#ifdef PROCESS_GROUP_TYPE
+/* Process group for us and the inferior. Saved and restored just like
+ {our,inferior}_ttystate. */
+extern PROCESS_GROUP_TYPE our_process_group;
+extern PROCESS_GROUP_TYPE inferior_process_group;
+#endif
+
+#endif
diff --git a/contrib/gdb/gdb/infptrace.c b/contrib/gdb/gdb/infptrace.c
new file mode 100644
index 0000000..ef86f90
--- /dev/null
+++ b/contrib/gdb/gdb/infptrace.c
@@ -0,0 +1,688 @@
+/* Low level Unix child interface to ptrace, for GDB when running under Unix.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include "gdb_wait.h"
+
+#include "command.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include "gdb_dirent.h"
+#include <signal.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_PTRACE_H
+#include <ptrace.h>
+#else
+#ifdef HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+#endif
+
+#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 <sys/file.h>
+#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 <sys/user.h> /* Probably need to poke the user structure */
+#if defined (KERNEL_U_ADDR_BSD)
+#include <a.out.h> /* For struct nlist */
+#endif /* KERNEL_U_ADDR_BSD. */
+#endif /* !FETCH_INFERIOR_REGISTERS */
+
+#if !defined (CHILD_XFER_MEMORY)
+static void udot_info (char *, int);
+#endif
+
+#if !defined (FETCH_INFERIOR_REGISTERS)
+static void fetch_register (int);
+static void store_register (int);
+#endif
+
+void _initialize_kernel_u_addr (void);
+void _initialize_infptrace (void);
+
+
+/* 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 (int request, int pid, PTRACE_ARG3_TYPE addr, int data)
+{
+ int pt_status = 0;
+
+#if 0
+ int saved_errno;
+
+ printf ("call_ptrace(request=%d, pid=%d, addr=0x%x, data=0x%x)",
+ request, pid, addr, data);
+#endif
+#if defined(PT_SETTRC)
+ /* If the parent can be told to attach to us, try to do it. */
+ if (request == PT_SETTRC)
+ {
+ errno = 0;
+#if !defined (FIVE_ARG_PTRACE)
+ pt_status = ptrace (PT_SETTRC, pid, addr, data);
+#else
+ /* Deal with HPUX 8.0 braindamage. We never use the
+ calls which require the fifth argument. */
+ pt_status = ptrace (PT_SETTRC, pid, addr, data, 0);
+#endif
+ if (errno)
+ perror_with_name ("ptrace");
+#if 0
+ printf (" = %d\n", pt_status);
+#endif
+ if (pt_status < 0)
+ return pt_status;
+ else
+ return parent_attach_all (pid, addr, data);
+ }
+#endif
+
+#if defined(PT_CONTIN1)
+ /* On HPUX, PT_CONTIN1 is a form of continue that preserves pending
+ signals. If it's available, use it. */
+ if (request == PT_CONTINUE)
+ request = PT_CONTIN1;
+#endif
+
+#if defined(PT_SINGLE1)
+ /* On HPUX, PT_SINGLE1 is a form of step that preserves pending
+ signals. If it's available, use it. */
+ if (request == PT_STEP)
+ request = PT_SINGLE1;
+#endif
+
+#if 0
+ saved_errno = errno;
+ errno = 0;
+#endif
+#if !defined (FIVE_ARG_PTRACE)
+ pt_status = ptrace (request, pid, addr, data);
+#else
+ /* Deal with HPUX 8.0 braindamage. We never use the
+ calls which require the fifth argument. */
+ pt_status = ptrace (request, pid, addr, data, 0);
+#endif
+
+#if 0
+ if (errno)
+ printf (" [errno = %d]", errno);
+
+ errno = saved_errno;
+ printf (" = 0x%x\n", pt_status);
+#endif
+ return pt_status;
+}
+
+
+#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
+
+/* Wait for a process to finish, possibly running a target-specific
+ hook before returning. */
+
+int
+ptrace_wait (ptid_t ptid, int *status)
+{
+ int wstate;
+
+ wstate = wait (status);
+ target_post_wait (pid_to_ptid (wstate), *status);
+ return wstate;
+}
+
+#ifndef KILL_INFERIOR
+void
+kill_inferior (void)
+{
+ int status;
+ int pid = PIDGET (inferior_ptid);
+
+ if (pid == 0)
+ return;
+
+ /* This once used to call "kill" to kill the inferior just in case
+ the inferior was still running. As others have noted in the past
+ (kingdon) there shouldn't be any way to get here if the inferior
+ is still running -- else there's a major problem elsewere in gdb
+ and it needs to be fixed.
+
+ The kill call causes problems under hpux10, so it's been removed;
+ if this causes problems we'll deal with them as they arise. */
+ ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0);
+ ptrace_wait (null_ptid, &status);
+ target_mourn_inferior ();
+}
+#endif /* KILL_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 (ptid_t ptid, int step, enum target_signal signal)
+{
+ int pid = PIDGET (ptid);
+
+ 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_ptid" are the same. */
+ pid = PIDGET (inferior_ptid);
+
+ /* 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)
+ {
+ if (SOFTWARE_SINGLE_STEP_P ())
+ internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* Make sure this doesn't happen. */
+ else
+ 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 (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 (int signal)
+{
+ errno = 0;
+ ptrace (PT_DETACH, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) 1,
+ signal);
+ if (errno)
+ print_sys_errmsg ("ptrace", 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
+
+/* 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 (void)
+{
+#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
+ internal_error (__FILE__, __LINE__,
+ "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, PIDGET (inferior_ptid), \
+ (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
+ - KERNEL_U_ADDR
+#endif
+
+/* Fetch one register. */
+
+static void
+fetch_register (int regno)
+{
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr;
+ char mess[128]; /* For messages */
+ int i;
+ unsigned int offset; /* Offset of registers within the u area. */
+ char buf[MAX_REGISTER_SIZE];
+ int tid;
+
+ if (CANNOT_FETCH_REGISTER (regno))
+ {
+ memset (buf, '\0', DEPRECATED_REGISTER_RAW_SIZE (regno)); /* Supply zeroes */
+ supply_register (regno, buf);
+ return;
+ }
+
+ /* Overload thread id onto process id */
+ if ((tid = TIDGET (inferior_ptid)) == 0)
+ tid = PIDGET (inferior_ptid); /* no thread id, just use process id */
+
+ offset = U_REGS_OFFSET;
+
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
+ (PTRACE_ARG3_TYPE) regaddr, 0);
+ regaddr += sizeof (PTRACE_XFER_TYPE);
+ if (errno != 0)
+ {
+ sprintf (mess, "reading register %s (#%d)",
+ REGISTER_NAME (regno), regno);
+ perror_with_name (mess);
+ }
+ }
+ supply_register (regno, buf);
+}
+
+
+/* Fetch register values from the inferior.
+ If REGNO is negative, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno >= 0)
+ {
+ fetch_register (regno);
+ }
+ else
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ fetch_register (regno);
+ }
+ }
+}
+
+/* Store one register. */
+
+static void
+store_register (int regno)
+{
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr;
+ char mess[128]; /* For messages */
+ int i;
+ unsigned int offset; /* Offset of registers within the u area. */
+ int tid;
+ char buf[MAX_REGISTER_SIZE];
+
+ if (CANNOT_STORE_REGISTER (regno))
+ {
+ return;
+ }
+
+ /* Overload thread id onto process id */
+ if ((tid = TIDGET (inferior_ptid)) == 0)
+ tid = PIDGET (inferior_ptid); /* no thread id, just use process id */
+
+ offset = U_REGS_OFFSET;
+
+ regaddr = register_addr (regno, offset);
+
+ /* Put the contents of regno into a local buffer */
+ regcache_collect (regno, buf);
+
+ /* Store the local buffer into the inferior a chunk at the time. */
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) (buf + i));
+ regaddr += sizeof (PTRACE_XFER_TYPE);
+ if (errno != 0)
+ {
+ sprintf (mess, "writing register %s (#%d)",
+ REGISTER_NAME (regno), regno);
+ perror_with_name (mess);
+ }
+ }
+}
+
+/* Store our register values back into the inferior.
+ If REGNO is negative, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno >= 0)
+ {
+ store_register (regno);
+ }
+ else
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ store_register (regno);
+ }
+ }
+}
+#endif /* !defined (FETCH_INFERIOR_REGISTERS). */
+
+
+/* Set an upper limit on alloca. */
+#ifndef GDB_MAX_ALLOCA
+#define GDB_MAX_ALLOCA 0x1000
+#endif
+
+#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. TARGET is ignored.
+
+ 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 (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int i;
+ /* Round starting address down to longword boundary. */
+ CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
+ /* Round ending address up; get number of longwords that makes. */
+ int count = ((((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+ / sizeof (PTRACE_XFER_TYPE));
+ int alloc = count * sizeof (PTRACE_XFER_TYPE);
+ PTRACE_XFER_TYPE *buffer;
+ struct cleanup *old_chain = NULL;
+
+#ifdef PT_IO
+ /* OpenBSD 3.1, NetBSD 1.6 and FreeBSD 5.0 have a new PT_IO request
+ that promises to be much more efficient in reading and writing
+ data in the traced process's address space. */
+
+ {
+ struct ptrace_io_desc piod;
+
+ /* NOTE: We assume that there are no distinct address spaces for
+ instruction and data. */
+ piod.piod_op = write ? PIOD_WRITE_D : PIOD_READ_D;
+ piod.piod_offs = (void *) memaddr;
+ piod.piod_addr = myaddr;
+ piod.piod_len = len;
+
+ if (ptrace (PT_IO, PIDGET (inferior_ptid), (caddr_t) &piod, 0) == -1)
+ {
+ /* If the PT_IO request is somehow not supported, fallback on
+ using PT_WRITE_D/PT_READ_D. Otherwise we will return zero
+ to indicate failure. */
+ if (errno != EINVAL)
+ return 0;
+ }
+ else
+ {
+ /* Return the actual number of bytes read or written. */
+ return piod.piod_len;
+ }
+ }
+#endif
+
+ /* Allocate buffer of that many longwords. */
+ if (len < GDB_MAX_ALLOCA)
+ {
+ buffer = (PTRACE_XFER_TYPE *) alloca (alloc);
+ }
+ else
+ {
+ buffer = (PTRACE_XFER_TYPE *) xmalloc (alloc);
+ old_chain = make_cleanup (xfree, buffer);
+ }
+
+ 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, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) addr, 0);
+ }
+
+ if (count > 1) /* FIXME, avoid if even boundary. */
+ {
+ buffer[count - 1] =
+ ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ ((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, PIDGET (inferior_ptid),
+ (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, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ }
+ if (errno)
+ return 0;
+ }
+#ifdef CLEAR_INSN_CACHE
+ CLEAR_INSN_CACHE ();
+#endif
+ }
+ else
+ {
+ /* Read all the longwords. */
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ buffer[i] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ (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);
+ }
+
+ if (old_chain != NULL)
+ do_cleanups (old_chain);
+ return len;
+}
+
+
+static void
+udot_info (char *dummy1, int dummy2)
+{
+#if defined (KERNEL_U_SIZE)
+ long udot_off; /* Offset into user struct */
+ int udot_val; /* Value from user struct at udot_off */
+ char mess[128]; /* For messages */
+#endif
+
+ 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 ("%s:", paddr (udot_off));
+ }
+ udot_val = ptrace (PT_READ_U, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) udot_off, 0);
+ if (errno != 0)
+ {
+ sprintf (mess, "\nreading user struct at offset 0x%s",
+ paddr_nz (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 (void)
+{
+#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 0000000..e84a4c7
--- /dev/null
+++ b/contrib/gdb/gdb/infrun.c
@@ -0,0 +1,4220 @@
+/* Target-struct-independent code to start (run) and stop an inferior
+ process.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "breakpoint.h"
+#include "gdb_wait.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "cli/cli-script.h"
+#include "target.h"
+#include "gdbthread.h"
+#include "annotate.h"
+#include "symfile.h"
+#include "top.h"
+#include <signal.h>
+#include "inf-loop.h"
+#include "regcache.h"
+#include "value.h"
+#include "observer.h"
+#include "language.h"
+#include "gdb_assert.h"
+
+/* Prototypes for local functions */
+
+static void signals_info (char *, int);
+
+static void handle_command (char *, int);
+
+static void sig_print_info (enum target_signal);
+
+static void sig_print_header (void);
+
+static void resume_cleanups (void *);
+
+static int hook_stop_stub (void *);
+
+static void delete_breakpoint_current_contents (void *);
+
+static int restore_selected_frame (void *);
+
+static void build_infrun (void);
+
+static int follow_fork (void);
+
+static void set_schedlock_func (char *args, int from_tty,
+ struct cmd_list_element *c);
+
+struct execution_control_state;
+
+static int currently_stepping (struct execution_control_state *ecs);
+
+static void xdb_handle_command (char *args, int from_tty);
+
+static int prepare_to_proceed (void);
+
+void _initialize_infrun (void);
+
+int inferior_ignoring_startup_exec_events = 0;
+int inferior_ignoring_leading_exec_events = 0;
+
+/* When set, stop the 'step' command if we enter a function which has
+ no line number information. The normal behavior is that we step
+ over such function. */
+int step_stop_if_no_debug = 0;
+
+/* In asynchronous mode, but simulating synchronous execution. */
+
+int sync_execution = 0;
+
+/* wait_for_inferior and normal_stop use this to notify the user
+ when the inferior stopped in a different thread than it had been
+ running in. */
+
+static ptid_t previous_inferior_ptid;
+
+/* This is true for configurations that may follow through execl() and
+ similar functions. At present this is only true for HP-UX native. */
+
+#ifndef MAY_FOLLOW_EXEC
+#define MAY_FOLLOW_EXEC (0)
+#endif
+
+static int may_follow_exec = MAY_FOLLOW_EXEC;
+
+/* If the program uses ELF-style shared libraries, then calls to
+ functions in shared libraries go through stubs, which live in a
+ table called the PLT (Procedure Linkage Table). The first time the
+ function is called, the stub sends control to the dynamic linker,
+ which looks up the function's real address, patches the stub so
+ that future calls will go directly to the function, and then passes
+ control to the function.
+
+ If we are stepping at the source level, we don't want to see any of
+ this --- we just want to skip over the stub and the dynamic linker.
+ The simple approach is to single-step until control leaves the
+ dynamic linker.
+
+ However, on some systems (e.g., Red Hat's 5.2 distribution) the
+ dynamic linker calls functions in the shared C library, so you
+ can't tell from the PC alone whether the dynamic linker is still
+ running. In this case, we use a step-resume breakpoint to get us
+ past the dynamic linker, as if we were using "next" to step over a
+ function call.
+
+ IN_SOLIB_DYNSYM_RESOLVE_CODE says whether we're in the dynamic
+ linker code or not. Normally, this means we single-step. However,
+ if SKIP_SOLIB_RESOLVER then returns non-zero, then its value is an
+ address where we can place a step-resume breakpoint to get past the
+ linker's symbol resolution function.
+
+ IN_SOLIB_DYNSYM_RESOLVE_CODE can generally be implemented in a
+ pretty portable way, by comparing the PC against the address ranges
+ of the dynamic linker's sections.
+
+ SKIP_SOLIB_RESOLVER is generally going to be system-specific, since
+ it depends on internal details of the dynamic linker. It's usually
+ not too hard to figure out where to put a breakpoint, but it
+ certainly isn't portable. SKIP_SOLIB_RESOLVER should do plenty of
+ sanity checking. If it can't figure things out, returning zero and
+ getting the (possibly confusing) stepping behavior is better than
+ signalling an error, which will obscure the change in the
+ inferior's state. */
+
+#ifndef IN_SOLIB_DYNSYM_RESOLVE_CODE
+#define IN_SOLIB_DYNSYM_RESOLVE_CODE(pc) 0
+#endif
+
+/* This function returns TRUE if pc is the address of an instruction
+ that lies within the dynamic linker (such as the event hook, or the
+ dld itself).
+
+ This function must be used only when a dynamic linker event has
+ been caught, and the inferior is being stepped out of the hook, or
+ undefined results are guaranteed. */
+
+#ifndef SOLIB_IN_DYNAMIC_LINKER
+#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) 0
+#endif
+
+/* On MIPS16, a function that returns a floating point value may call
+ a library helper function to copy the return value to a floating point
+ register. The IGNORE_HELPER_CALL macro returns non-zero if we
+ should ignore (i.e. step over) this function call. */
+#ifndef IGNORE_HELPER_CALL
+#define IGNORE_HELPER_CALL(pc) 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
+
+/* We can't step off a permanent breakpoint in the ordinary way, because we
+ can't remove it. Instead, we have to advance the PC to the next
+ instruction. This macro should expand to a pointer to a function that
+ does that, or zero if we have no such function. If we don't have a
+ definition for it, we have to report an error. */
+#ifndef SKIP_PERMANENT_BREAKPOINT
+#define SKIP_PERMANENT_BREAKPOINT (default_skip_permanent_breakpoint)
+static void
+default_skip_permanent_breakpoint (void)
+{
+ error ("\
+The program is stopped at a permanent breakpoint, but GDB does not know\n\
+how to step past a permanent breakpoint on this architecture. Try using\n\
+a command like `return' or `jump' to continue execution.");
+}
+#endif
+
+
+/* Convert the #defines into values. This is temporary until wfi control
+ flow is completely sorted out. */
+
+#ifndef HAVE_STEPPABLE_WATCHPOINT
+#define HAVE_STEPPABLE_WATCHPOINT 0
+#else
+#undef HAVE_STEPPABLE_WATCHPOINT
+#define HAVE_STEPPABLE_WATCHPOINT 1
+#endif
+
+#ifndef CANNOT_STEP_HW_WATCHPOINTS
+#define CANNOT_STEP_HW_WATCHPOINTS 0
+#else
+#undef CANNOT_STEP_HW_WATCHPOINTS
+#define CANNOT_STEP_HW_WATCHPOINTS 1
+#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)
+
+/* Value to pass to target_resume() to cause all threads to resume */
+
+#define RESUME_ALL (pid_to_ptid (-1))
+
+/* 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;
+
+#ifdef SOLIB_ADD
+/* 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;
+#endif
+
+#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?). */
+
+enum stop_kind stop_soon;
+
+/* 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). */
+
+struct regcache *stop_registers;
+
+/* 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;
+
+static struct breakpoint *step_resume_breakpoint = NULL;
+static struct breakpoint *through_sigtramp_breakpoint = NULL;
+
+/* On some platforms (e.g., HP-UX), hardware watchpoints have bad
+ interactions with an inferior that is running a kernel function
+ (aka, a system call or "syscall"). wait_for_inferior therefore
+ may have a need to know when the inferior is in a syscall. This
+ is a count of the number of inferior threads which are known to
+ currently be running in a syscall. */
+static int number_of_threads_in_syscalls;
+
+/* This is a cached copy of the pid/waitstatus of the last event
+ returned by target_wait()/target_wait_hook(). This information is
+ returned by get_last_target_status(). */
+static ptid_t target_last_wait_ptid;
+static struct target_waitstatus target_last_waitstatus;
+
+/* This is used to remember when a fork, vfork or exec event
+ was caught by a catchpoint, and thus the event is to be
+ followed at the next resume of the inferior, and not
+ immediately. */
+static struct
+{
+ enum target_waitkind kind;
+ struct
+ {
+ int parent_pid;
+ int child_pid;
+ }
+ fork_event;
+ char *execd_pathname;
+}
+pending_follow;
+
+static const char follow_fork_mode_child[] = "child";
+static const char follow_fork_mode_parent[] = "parent";
+
+static const char *follow_fork_mode_kind_names[] = {
+ follow_fork_mode_child,
+ follow_fork_mode_parent,
+ NULL
+};
+
+static const char *follow_fork_mode_string = follow_fork_mode_parent;
+
+
+static int
+follow_fork (void)
+{
+ int follow_child = (follow_fork_mode_string == follow_fork_mode_child);
+
+ return target_follow_fork (follow_child);
+}
+
+void
+follow_inferior_reset_breakpoints (void)
+{
+ /* Was there a step_resume breakpoint? (There was if the user
+ did a "next" at the fork() call.) If so, explicitly reset its
+ thread number.
+
+ step_resumes are a form of bp that are made to be per-thread.
+ Since we created the step_resume bp when the parent process
+ was being debugged, and now are switching to the child process,
+ from the breakpoint package's viewpoint, that's a switch of
+ "threads". We must update the bp's notion of which thread
+ it is for, or it'll be ignored when it triggers. */
+
+ if (step_resume_breakpoint)
+ breakpoint_re_set_thread (step_resume_breakpoint);
+
+ /* Reinsert all breakpoints in the child. The user may have set
+ breakpoints after catching the fork, in which case those
+ were never set in the child, but only in the parent. This makes
+ sure the inserted breakpoints match the breakpoint list. */
+
+ breakpoint_re_set ();
+ insert_breakpoints ();
+}
+
+/* EXECD_PATHNAME is assumed to be non-NULL. */
+
+static void
+follow_exec (int pid, char *execd_pathname)
+{
+ int saved_pid = pid;
+ struct target_ops *tgt;
+
+ if (!may_follow_exec)
+ return;
+
+ /* This is an exec event that we actually wish to pay attention to.
+ Refresh our symbol table to the newly exec'd program, remove any
+ momentary bp's, etc.
+
+ If there are breakpoints, they aren't really inserted now,
+ since the exec() transformed our inferior into a fresh set
+ of instructions.
+
+ We want to preserve symbolic breakpoints on the list, since
+ we have hopes that they can be reset after the new a.out's
+ symbol table is read.
+
+ However, any "raw" breakpoints must be removed from the list
+ (e.g., the solib bp's), since their address is probably invalid
+ now.
+
+ And, we DON'T want to call delete_breakpoints() here, since
+ that may write the bp's "shadow contents" (the instruction
+ value that was overwritten witha TRAP instruction). Since
+ we now have a new a.out, those shadow contents aren't valid. */
+ update_breakpoints_after_exec ();
+
+ /* If there was one, it's gone now. We cannot truly step-to-next
+ statement through an exec(). */
+ step_resume_breakpoint = NULL;
+ step_range_start = 0;
+ step_range_end = 0;
+
+ /* If there was one, it's gone now. */
+ through_sigtramp_breakpoint = NULL;
+
+ /* What is this a.out's name? */
+ printf_unfiltered ("Executing new program: %s\n", execd_pathname);
+
+ /* We've followed the inferior through an exec. Therefore, the
+ inferior has essentially been killed & reborn. */
+
+ /* First collect the run target in effect. */
+ tgt = find_run_target ();
+ /* If we can't find one, things are in a very strange state... */
+ if (tgt == NULL)
+ error ("Could find run target to save before following exec");
+
+ gdb_flush (gdb_stdout);
+ target_mourn_inferior ();
+ inferior_ptid = pid_to_ptid (saved_pid);
+ /* Because mourn_inferior resets inferior_ptid. */
+ push_target (tgt);
+
+ /* That a.out is now the one to use. */
+ exec_file_attach (execd_pathname, 0);
+
+ /* And also is where symbols can be found. */
+ symbol_file_add_main (execd_pathname, 0);
+
+ /* Reset the shared library package. This ensures that we get
+ a shlib event when the child reaches "_start", at which point
+ the dld will have had a chance to initialize the child. */
+#if defined(SOLIB_RESTART)
+ SOLIB_RESTART ();
+#endif
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
+#endif
+
+ /* Reinsert all breakpoints. (Those which were symbolic have
+ been reset to the proper address in the new a.out, thanks
+ to symbol_file_command...) */
+ insert_breakpoints ();
+
+ /* The next resume of this inferior should bring it to the shlib
+ startup breakpoints. (If the user had also set bp's on
+ "main" from the old (parent) process, then they'll auto-
+ matically get reset there in the new process.) */
+}
+
+/* Non-zero if we just simulating a single-step. This is needed
+ because we cannot remove the breakpoints in the inferior process
+ until after the `wait' in `wait_for_inferior'. */
+static int singlestep_breakpoints_inserted_p = 0;
+
+/* The thread we inserted single-step breakpoints for. */
+static ptid_t singlestep_ptid;
+
+/* If another thread hit the singlestep breakpoint, we save the original
+ thread here so that we can resume single-stepping it later. */
+static ptid_t saved_singlestep_ptid;
+static int stepping_past_singlestep_breakpoint;
+
+
+/* Things to clean up if we QUIT out of resume (). */
+static void
+resume_cleanups (void *ignore)
+{
+ normal_stop ();
+}
+
+static const char schedlock_off[] = "off";
+static const char schedlock_on[] = "on";
+static const char schedlock_step[] = "step";
+static const char *scheduler_mode = schedlock_off;
+static const char *scheduler_enums[] = {
+ schedlock_off,
+ schedlock_on,
+ schedlock_step,
+ NULL
+};
+
+static void
+set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c)
+{
+ /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+ the set command passed as a parameter. The clone operation will
+ include (BUG?) any ``set'' command callback, if present.
+ Commands like ``info set'' call all the ``show'' command
+ callbacks. Unfortunately, for ``show'' commands cloned from
+ ``set'', this includes callbacks belonging to ``set'' commands.
+ Making this worse, this only occures if add_show_from_set() is
+ called after add_cmd_sfunc() (BUG?). */
+ if (cmd_type (c) == set_cmd)
+ if (!target_can_lock_scheduler)
+ {
+ scheduler_mode = schedlock_off;
+ error ("Target '%s' cannot support this command.", target_shortname);
+ }
+}
+
+
+/* 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 (int step, enum target_signal sig)
+{
+ int should_resume = 1;
+ struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
+ QUIT;
+
+ /* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
+
+
+ /* Some targets (e.g. Solaris x86) have a kernel bug when stepping
+ over an instruction that causes a page fault without triggering
+ a hardware watchpoint. The kernel properly notices that it shouldn't
+ stop, because the hardware watchpoint is not triggered, but it forgets
+ the step request and continues the program normally.
+ Work around the problem by removing hardware watchpoints if a step is
+ requested, GDB will check for a hardware watchpoint trigger after the
+ step anyway. */
+ if (CANNOT_STEP_HW_WATCHPOINTS && step && breakpoints_inserted)
+ remove_hw_watchpoints ();
+
+
+ /* Normally, by the time we reach `resume', the breakpoints are either
+ removed or inserted, as appropriate. The exception is if we're sitting
+ at a permanent breakpoint; we need to step over it, but permanent
+ breakpoints can't be removed. So we have to test for it here. */
+ if (breakpoint_here_p (read_pc ()) == permanent_breakpoint_here)
+ SKIP_PERMANENT_BREAKPOINT ();
+
+ if (SOFTWARE_SINGLE_STEP_P () && step)
+ {
+ /* Do it the hard way, w/temp breakpoints */
+ SOFTWARE_SINGLE_STEP (sig, 1 /*insert-breakpoints */ );
+ /* ...and don't ask hardware to do it. */
+ step = 0;
+ /* and do not pull these breakpoints until after a `wait' in
+ `wait_for_inferior' */
+ singlestep_breakpoints_inserted_p = 1;
+ singlestep_ptid = inferior_ptid;
+ }
+
+ /* Handle any optimized stores to the inferior NOW... */
+#ifdef DO_DEFERRED_STORES
+ DO_DEFERRED_STORES;
+#endif
+
+ /* If there were any forks/vforks/execs that were caught and are
+ now to be followed, then do so. */
+ switch (pending_follow.kind)
+ {
+ case TARGET_WAITKIND_FORKED:
+ case TARGET_WAITKIND_VFORKED:
+ pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+ if (follow_fork ())
+ should_resume = 0;
+ break;
+
+ case TARGET_WAITKIND_EXECD:
+ /* follow_exec is called as soon as the exec event is seen. */
+ pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ if (should_resume)
+ {
+ ptid_t resume_ptid;
+
+ resume_ptid = RESUME_ALL; /* Default */
+
+ if ((step || singlestep_breakpoints_inserted_p) &&
+ (stepping_past_singlestep_breakpoint
+ || (!breakpoints_inserted && breakpoint_here_p (read_pc ()))))
+ {
+ /* Stepping past a breakpoint without inserting breakpoints.
+ Make sure only the current thread gets to step, so that
+ other threads don't sneak past breakpoints while they are
+ not inserted. */
+
+ resume_ptid = inferior_ptid;
+ }
+
+ if ((scheduler_mode == schedlock_on) ||
+ (scheduler_mode == schedlock_step &&
+ (step || singlestep_breakpoints_inserted_p)))
+ {
+ /* User-settable 'scheduler' mode requires solo thread resume. */
+ resume_ptid = inferior_ptid;
+ }
+
+ if (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;
+ }
+ target_resume (resume_ptid, 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 (void)
+{
+ trap_expected = 0;
+ step_range_start = 0;
+ step_range_end = 0;
+ step_frame_id = null_frame_id;
+ step_over_calls = STEP_OVER_UNDEBUGGABLE;
+ stop_after_trap = 0;
+ stop_soon = NO_STOP_QUIETLY;
+ 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);
+}
+
+/* This should be suitable for any targets that support threads. */
+
+static int
+prepare_to_proceed (void)
+{
+ ptid_t wait_ptid;
+ struct target_waitstatus wait_status;
+
+ /* Get the last target status returned by target_wait(). */
+ get_last_target_status (&wait_ptid, &wait_status);
+
+ /* Make sure we were stopped either at a breakpoint, or because
+ of a Ctrl-C. */
+ if (wait_status.kind != TARGET_WAITKIND_STOPPED
+ || (wait_status.value.sig != TARGET_SIGNAL_TRAP &&
+ wait_status.value.sig != TARGET_SIGNAL_INT))
+ {
+ return 0;
+ }
+
+ if (!ptid_equal (wait_ptid, minus_one_ptid)
+ && !ptid_equal (inferior_ptid, wait_ptid))
+ {
+ /* Switched over from WAIT_PID. */
+ CORE_ADDR wait_pc = read_pc_pid (wait_ptid);
+
+ if (wait_pc != read_pc ())
+ {
+ /* Switch back to WAIT_PID thread. */
+ inferior_ptid = wait_ptid;
+
+ /* FIXME: This stuff came from switch_to_thread() in
+ thread.c (which should probably be a public function). */
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = wait_pc;
+ select_frame (get_current_frame ());
+ }
+
+ /* We return 1 to indicate that there is a breakpoint here,
+ so we need to step over it before continuing to avoid
+ hitting it straight away. */
+ if (breakpoint_here_p (wait_pc))
+ return 1;
+ }
+
+ return 0;
+
+}
+
+/* Record the pc of the program the last time it stopped. This is
+ 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;
+
+/* 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 (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 (and report a second
+ hit at this breakpoint). */
+
+ if (read_pc () == stop_pc && breakpoint_here_p (read_pc ()))
+ oneproc = 1;
+
+#ifndef STEP_SKIPS_DELAY
+#define STEP_SKIPS_DELAY(pc) (0)
+#define STEP_SKIPS_DELAY_P (0)
+#endif
+ /* 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 (STEP_SKIPS_DELAY_P
+ && breakpoint_here_p (read_pc () + 4)
+ && STEP_SKIPS_DELAY (read_pc ()))
+ oneproc = 1;
+ }
+ else
+ {
+ write_pc (addr);
+ }
+
+ /* In a multi-threaded task we may select another thread
+ and then continue or step.
+
+ But if the old thread was stopped at a breakpoint, it
+ will immediately cause another breakpoint stop without
+ any execution (i.e. it will report a breakpoint hit
+ incorrectly). So we must step over it first.
+
+ prepare_to_proceed checks the current thread against the thread
+ that reported the most recent event. If a step-over is required
+ it returns TRUE and sets the current thread to the old thread. */
+ if (prepare_to_proceed () && breakpoint_here_p (read_pc ()))
+ oneproc = 1;
+
+#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
+ {
+ insert_breakpoints ();
+ /* If we get here there was no call to error() in
+ insert breakpoints -- so they were inserted. */
+ 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);
+
+ /* Refresh prev_pc value just prior to resuming. This used to be
+ done in stop_stepping, however, setting prev_pc there did not handle
+ scenarios such as inferior function calls or returning from
+ a function via the return command. In those cases, the prev_pc
+ value was not set properly for subsequent commands. The prev_pc value
+ is used to initialize the starting line number in the ecs. With an
+ invalid value, the gdb next command ends up stopping at the position
+ represented by the next line table entry past our start position.
+ On platforms that generate one line table entry per line, this
+ is not a problem. However, on the ia64, the compiler generates
+ extraneous line table entries that do not increase the line number.
+ When we issue the gdb next command on the ia64 after an inferior call
+ or a return command, we often end up a few instructions forward, still
+ within the original line we started.
+
+ An attempt was made to have init_execution_control_state () refresh
+ the prev_pc value before calculating the line number. This approach
+ did not work because on platforms that use ptrace, the pc register
+ cannot be read unless the inferior is stopped. At that point, we
+ are not guaranteed the inferior is stopped and so the read_pc ()
+ call can fail. Setting the prev_pc value here ensures the value is
+ updated correctly when the inferior is stopped. */
+ prev_pc = read_pc ();
+
+ /* 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. */
+ /* Do this only if we are not using the event loop, or if the target
+ does not support asynchronous execution. */
+ if (!event_loop_p || !target_can_async_p ())
+ {
+ wait_for_inferior ();
+ normal_stop ();
+ }
+}
+
+
+/* Start remote-debugging of a machine over a serial link. */
+
+void
+start_remote (void)
+{
+ init_thread_list ();
+ init_wait_for_inferior ();
+ stop_soon = STOP_QUIETLY;
+ trap_expected = 0;
+
+ /* Always go on waiting for the target, regardless of the mode. */
+ /* FIXME: cagney/1999-09-23: At present it isn't possible to
+ indicate to wait_for_inferior that a target should timeout if
+ nothing is returned (instead of just blocking). Because of this,
+ targets expecting an immediate response need to, internally, set
+ things up so that the target_wait() is forced to eventually
+ timeout. */
+ /* FIXME: cagney/1999-09-24: It isn't possible for target_open() to
+ differentiate to its caller what the state of the target is after
+ the initial open has been performed. Here we're assuming that
+ the target has stopped. It should be possible to eventually have
+ target_open() return to the caller an indication that the target
+ is currently running and GDB state should be set to the same as
+ for an async run. */
+ wait_for_inferior ();
+ normal_stop ();
+}
+
+/* Initialize static vars when a new inferior begins. */
+
+void
+init_wait_for_inferior (void)
+{
+ /* These are meaningless until the first time through wait_for_inferior. */
+ prev_pc = 0;
+
+#ifdef HP_OS_BUG
+ trap_expected_after_continue = 0;
+#endif
+ breakpoints_inserted = 0;
+ breakpoint_init_inferior (inf_starting);
+
+ /* Don't confuse first call to proceed(). */
+ stop_signal = TARGET_SIGNAL_0;
+
+ /* The first resume is not following a fork/vfork/exec. */
+ pending_follow.kind = TARGET_WAITKIND_SPURIOUS; /* I.e., none. */
+
+ /* See wait_for_inferior's handling of SYSCALL_ENTRY/RETURN events. */
+ number_of_threads_in_syscalls = 0;
+
+ clear_proceed_status ();
+
+ stepping_past_singlestep_breakpoint = 0;
+}
+
+static void
+delete_breakpoint_current_contents (void *arg)
+{
+ struct breakpoint **breakpointp = (struct breakpoint **) arg;
+ if (*breakpointp != NULL)
+ {
+ delete_breakpoint (*breakpointp);
+ *breakpointp = NULL;
+ }
+}
+
+/* This enum encodes possible reasons for doing a target_wait, so that
+ wfi can call target_wait in one place. (Ultimately the call will be
+ moved out of the infinite loop entirely.) */
+
+enum infwait_states
+{
+ infwait_normal_state,
+ infwait_thread_hop_state,
+ infwait_nullified_state,
+ infwait_nonstep_watch_state
+};
+
+/* Why did the inferior stop? Used to print the appropriate messages
+ to the interface from within handle_inferior_event(). */
+enum inferior_stop_reason
+{
+ /* We don't know why. */
+ STOP_UNKNOWN,
+ /* Step, next, nexti, stepi finished. */
+ END_STEPPING_RANGE,
+ /* Found breakpoint. */
+ BREAKPOINT_HIT,
+ /* Inferior terminated by signal. */
+ SIGNAL_EXITED,
+ /* Inferior exited. */
+ EXITED,
+ /* Inferior received signal, and user asked to be notified. */
+ SIGNAL_RECEIVED
+};
+
+/* This structure contains what used to be local variables in
+ wait_for_inferior. Probably many of them can return to being
+ locals in handle_inferior_event. */
+
+struct execution_control_state
+{
+ struct target_waitstatus ws;
+ struct target_waitstatus *wp;
+ int another_trap;
+ int random_signal;
+ CORE_ADDR stop_func_start;
+ CORE_ADDR stop_func_end;
+ char *stop_func_name;
+ struct symtab_and_line sal;
+ int remove_breakpoints_on_following_step;
+ int current_line;
+ struct symtab *current_symtab;
+ int handling_longjmp; /* FIXME */
+ ptid_t ptid;
+ ptid_t saved_inferior_ptid;
+ int update_step_sp;
+ int stepping_through_solib_after_catch;
+ bpstat stepping_through_solib_catchpoints;
+ int enable_hw_watchpoints_after_wait;
+ int stepping_through_sigtramp;
+ int new_thread_event;
+ struct target_waitstatus tmpstatus;
+ enum infwait_states infwait_state;
+ ptid_t waiton_ptid;
+ int wait_some_more;
+};
+
+void init_execution_control_state (struct execution_control_state *ecs);
+
+static void handle_step_into_function (struct execution_control_state *ecs);
+void handle_inferior_event (struct execution_control_state *ecs);
+
+static void check_sigtramp2 (struct execution_control_state *ecs);
+static void step_into_function (struct execution_control_state *ecs);
+static void step_over_function (struct execution_control_state *ecs);
+static void stop_stepping (struct execution_control_state *ecs);
+static void prepare_to_wait (struct execution_control_state *ecs);
+static void keep_going (struct execution_control_state *ecs);
+static void print_stop_reason (enum inferior_stop_reason stop_reason,
+ int stop_info);
+
+/* 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 (void)
+{
+ struct cleanup *old_cleanups;
+ struct execution_control_state ecss;
+ struct execution_control_state *ecs;
+
+ old_cleanups = make_cleanup (delete_step_resume_breakpoint,
+ &step_resume_breakpoint);
+ make_cleanup (delete_breakpoint_current_contents,
+ &through_sigtramp_breakpoint);
+
+ /* wfi still stays in a loop, so it's OK just to take the address of
+ a local to get the ecs pointer. */
+ ecs = &ecss;
+
+ /* Fill in with reasonable starting values. */
+ init_execution_control_state (ecs);
+
+ /* We'll update this if & when we switch to a new thread. */
+ previous_inferior_ptid = inferior_ptid;
+
+ overlay_cache_invalid = 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 ();
+
+ while (1)
+ {
+ if (target_wait_hook)
+ ecs->ptid = target_wait_hook (ecs->waiton_ptid, ecs->wp);
+ else
+ ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+
+ /* Now figure out what to do with the result of the result. */
+ handle_inferior_event (ecs);
+
+ if (!ecs->wait_some_more)
+ break;
+ }
+ do_cleanups (old_cleanups);
+}
+
+/* Asynchronous version of wait_for_inferior. It is called by the
+ event loop whenever a change of state is detected on the file
+ descriptor corresponding to the target. It can be called more than
+ once to complete a single execution command. In such cases we need
+ to keep the state in a global variable ASYNC_ECSS. If it is the
+ last time that this function is called for a single execution
+ command, then report to the user that the inferior has stopped, and
+ do the necessary cleanups. */
+
+struct execution_control_state async_ecss;
+struct execution_control_state *async_ecs;
+
+void
+fetch_inferior_event (void *client_data)
+{
+ static struct cleanup *old_cleanups;
+
+ async_ecs = &async_ecss;
+
+ if (!async_ecs->wait_some_more)
+ {
+ old_cleanups = make_exec_cleanup (delete_step_resume_breakpoint,
+ &step_resume_breakpoint);
+ make_exec_cleanup (delete_breakpoint_current_contents,
+ &through_sigtramp_breakpoint);
+
+ /* Fill in with reasonable starting values. */
+ init_execution_control_state (async_ecs);
+
+ /* We'll update this if & when we switch to a new thread. */
+ previous_inferior_ptid = inferior_ptid;
+
+ overlay_cache_invalid = 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)
+ async_ecs->ptid =
+ target_wait_hook (async_ecs->waiton_ptid, async_ecs->wp);
+ else
+ async_ecs->ptid = target_wait (async_ecs->waiton_ptid, async_ecs->wp);
+
+ /* Now figure out what to do with the result of the result. */
+ handle_inferior_event (async_ecs);
+
+ if (!async_ecs->wait_some_more)
+ {
+ /* Do only the cleanups that have been added by this
+ function. Let the continuations for the commands do the rest,
+ if there are any. */
+ do_exec_cleanups (old_cleanups);
+ normal_stop ();
+ if (step_multi && stop_step)
+ inferior_event_handler (INF_EXEC_CONTINUE, NULL);
+ else
+ inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ }
+}
+
+/* Prepare an execution control state for looping through a
+ wait_for_inferior-type loop. */
+
+void
+init_execution_control_state (struct execution_control_state *ecs)
+{
+ /* ecs->another_trap? */
+ ecs->random_signal = 0;
+ ecs->remove_breakpoints_on_following_step = 0;
+ ecs->handling_longjmp = 0; /* FIXME */
+ ecs->update_step_sp = 0;
+ ecs->stepping_through_solib_after_catch = 0;
+ ecs->stepping_through_solib_catchpoints = NULL;
+ ecs->enable_hw_watchpoints_after_wait = 0;
+ ecs->stepping_through_sigtramp = 0;
+ ecs->sal = find_pc_line (prev_pc, 0);
+ ecs->current_line = ecs->sal.line;
+ ecs->current_symtab = ecs->sal.symtab;
+ ecs->infwait_state = infwait_normal_state;
+ ecs->waiton_ptid = pid_to_ptid (-1);
+ ecs->wp = &(ecs->ws);
+}
+
+/* Call this function before setting step_resume_breakpoint, as a
+ sanity check. There should never be more than one step-resume
+ breakpoint per thread, so we should never be setting a new
+ step_resume_breakpoint when one is already active. */
+static void
+check_for_old_step_resume_breakpoint (void)
+{
+ if (step_resume_breakpoint)
+ warning
+ ("GDB bug: infrun.c (wait_for_inferior): dropping old step_resume breakpoint");
+}
+
+/* Return the cached copy of the last pid/waitstatus returned by
+ target_wait()/target_wait_hook(). The data is actually cached by
+ handle_inferior_event(), which gets called immediately after
+ target_wait()/target_wait_hook(). */
+
+void
+get_last_target_status (ptid_t *ptidp, struct target_waitstatus *status)
+{
+ *ptidp = target_last_wait_ptid;
+ *status = target_last_waitstatus;
+}
+
+/* Switch thread contexts, maintaining "infrun state". */
+
+static void
+context_switch (struct execution_control_state *ecs)
+{
+ /* Caution: it may happen that the new thread (or the old one!)
+ is not in the thread list. In this case we must not attempt
+ to "switch context", or we run the risk that our context may
+ be lost. This may happen as a result of the target module
+ mishandling thread creation. */
+
+ if (in_thread_list (inferior_ptid) && in_thread_list (ecs->ptid))
+ { /* Perform infrun state context switch: */
+ /* Save infrun state for the old thread. */
+ save_infrun_state (inferior_ptid, prev_pc,
+ trap_expected, step_resume_breakpoint,
+ through_sigtramp_breakpoint, step_range_start,
+ step_range_end, &step_frame_id,
+ ecs->handling_longjmp, ecs->another_trap,
+ ecs->stepping_through_solib_after_catch,
+ ecs->stepping_through_solib_catchpoints,
+ ecs->stepping_through_sigtramp,
+ ecs->current_line, ecs->current_symtab, step_sp);
+
+ /* Load infrun state for the new thread. */
+ load_infrun_state (ecs->ptid, &prev_pc,
+ &trap_expected, &step_resume_breakpoint,
+ &through_sigtramp_breakpoint, &step_range_start,
+ &step_range_end, &step_frame_id,
+ &ecs->handling_longjmp, &ecs->another_trap,
+ &ecs->stepping_through_solib_after_catch,
+ &ecs->stepping_through_solib_catchpoints,
+ &ecs->stepping_through_sigtramp,
+ &ecs->current_line, &ecs->current_symtab, &step_sp);
+ }
+ inferior_ptid = ecs->ptid;
+}
+
+/* Wrapper for PC_IN_SIGTRAMP that takes care of the need to find the
+ function's name.
+
+ In a classic example of "left hand VS right hand", "infrun.c" was
+ trying to improve GDB's performance by caching the result of calls
+ to calls to find_pc_partial_funtion, while at the same time
+ find_pc_partial_function was also trying to ramp up performance by
+ caching its most recent return value. The below makes the the
+ function find_pc_partial_function solely responsibile for
+ performance issues (the local cache that relied on a global
+ variable - arrrggg - deleted).
+
+ Using the testsuite and gcov, it was found that dropping the local
+ "infrun.c" cache and instead relying on find_pc_partial_function
+ increased the number of calls to 12000 (from 10000), but the number
+ of times find_pc_partial_function's cache missed (this is what
+ matters) was only increased by only 4 (to 3569). (A quick back of
+ envelope caculation suggests that the extra 2000 function calls
+ @1000 extra instructions per call make the 1 MIP VAX testsuite run
+ take two extra seconds, oops :-)
+
+ Long term, this function can be eliminated, replaced by the code:
+ get_frame_type(current_frame()) == SIGTRAMP_FRAME (for new
+ architectures this is very cheap). */
+
+static int
+pc_in_sigtramp (CORE_ADDR pc)
+{
+ char *name;
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ return PC_IN_SIGTRAMP (pc, name);
+}
+
+/* Handle the inferior event in the cases when we just stepped
+ into a function. */
+
+static void
+handle_step_into_function (struct execution_control_state *ecs)
+{
+ CORE_ADDR real_stop_pc;
+
+ if ((step_over_calls == STEP_OVER_NONE)
+ || ((step_range_end == 1)
+ && in_prologue (prev_pc, ecs->stop_func_start)))
+ {
+ /* I presume that step_over_calls is only 0 when we're
+ supposed to be stepping at the assembly language level
+ ("stepi"). Just stop. */
+ /* Also, maybe we just did a "nexti" inside a prolog,
+ so we thought it was a subroutine call but it was not.
+ Stop as well. FENN */
+ stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+
+ if (step_over_calls == STEP_OVER_ALL || IGNORE_HELPER_CALL (stop_pc))
+ {
+ /* We're doing a "next". */
+
+ if (pc_in_sigtramp (stop_pc)
+ && frame_id_inner (step_frame_id,
+ frame_id_build (read_sp (), 0)))
+ /* We stepped out of a signal handler, and into its
+ calling trampoline. This is misdetected as a
+ subroutine call, but stepping over the signal
+ trampoline isn't such a bad idea. In order to do that,
+ we have to ignore the value in step_frame_id, since
+ that doesn't represent the frame that'll reach when we
+ return from the signal trampoline. Otherwise we'll
+ probably continue to the end of the program. */
+ step_frame_id = null_frame_id;
+
+ step_over_function (ecs);
+ keep_going (ecs);
+ return;
+ }
+
+ /* 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. */
+ real_stop_pc = skip_language_trampoline (stop_pc);
+ if (real_stop_pc == 0)
+ real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc);
+ if (real_stop_pc != 0)
+ ecs->stop_func_start = real_stop_pc;
+
+ /* 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 (ecs->stop_func_start, 0);
+ if (tmp_sal.line != 0)
+ {
+ step_into_function (ecs);
+ return;
+ }
+ }
+
+ /* If we have no line number and the step-stop-if-no-debug
+ is set, we stop the step so that the user has a chance to
+ switch in assembly mode. */
+ if (step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug)
+ {
+ stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+
+ step_over_function (ecs);
+ keep_going (ecs);
+ return;
+}
+
+static void
+adjust_pc_after_break (struct execution_control_state *ecs)
+{
+ CORE_ADDR stop_pc;
+
+ /* If this target does not decrement the PC after breakpoints, then
+ we have nothing to do. */
+ if (DECR_PC_AFTER_BREAK == 0)
+ return;
+
+ /* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
+ we aren't, just return.
+
+ We assume that waitkinds other than TARGET_WAITKIND_STOPPED are not
+ affected by DECR_PC_AFTER_BREAK. Other waitkinds which are implemented
+ by software breakpoints should be handled through the normal breakpoint
+ layer.
+
+ NOTE drow/2004-01-31: On some targets, breakpoints may generate
+ different signals (SIGILL or SIGEMT for instance), but it is less
+ clear where the PC is pointing afterwards. It may not match
+ DECR_PC_AFTER_BREAK. I don't know any specific target that generates
+ these signals at breakpoints (the code has been in GDB since at least
+ 1992) so I can not guess how to handle them here.
+
+ In earlier versions of GDB, a target with HAVE_NONSTEPPABLE_WATCHPOINTS
+ would have the PC after hitting a watchpoint affected by
+ DECR_PC_AFTER_BREAK. I haven't found any target with both of these set
+ in GDB history, and it seems unlikely to be correct, so
+ HAVE_NONSTEPPABLE_WATCHPOINTS is not checked here. */
+
+ if (ecs->ws.kind != TARGET_WAITKIND_STOPPED)
+ return;
+
+ if (ecs->ws.value.sig != TARGET_SIGNAL_TRAP)
+ return;
+
+ /* Find the location where (if we've hit a breakpoint) the breakpoint would
+ be. */
+ stop_pc = read_pc_pid (ecs->ptid) - DECR_PC_AFTER_BREAK;
+
+ /* If we're software-single-stepping, then assume this is a breakpoint.
+ NOTE drow/2004-01-17: This doesn't check that the PC matches, or that
+ we're even in the right thread. The software-single-step code needs
+ some modernization.
+
+ If we're not software-single-stepping, then we first check that there
+ is an enabled software breakpoint at this address. If there is, and
+ we weren't using hardware-single-step, then we've hit the breakpoint.
+
+ If we were using hardware-single-step, we check prev_pc; if we just
+ stepped over an inserted software breakpoint, then we should decrement
+ the PC and eventually report hitting the breakpoint. The prev_pc check
+ prevents us from decrementing the PC if we just stepped over a jump
+ instruction and landed on the instruction after a breakpoint.
+
+ The last bit checks that we didn't hit a breakpoint in a signal handler
+ without an intervening stop in sigtramp, which is detected by a new
+ stack pointer value below any usual function calling stack adjustments.
+
+ NOTE drow/2004-01-17: I'm not sure that this is necessary. The check
+ predates checking for software single step at the same time. Also,
+ if we've moved into a signal handler we should have seen the
+ signal. */
+
+ if ((SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+ || (software_breakpoint_inserted_here_p (stop_pc)
+ && !(currently_stepping (ecs)
+ && prev_pc != stop_pc
+#if 1
+ && !(step_range_end))))
+#else
+ && !(step_range_end && INNER_THAN (read_sp (), (step_sp - 16))))))
+#endif
+ write_pc_pid (stop_pc, ecs->ptid);
+}
+
+/* Given an execution control state that has been freshly filled in
+ by an event from the inferior, figure out what it means and take
+ appropriate action. */
+
+void
+handle_inferior_event (struct execution_control_state *ecs)
+{
+ /* NOTE: cagney/2003-03-28: If you're looking at this code and
+ thinking that the variable stepped_after_stopped_by_watchpoint
+ isn't used, then you're wrong! The macro STOPPED_BY_WATCHPOINT,
+ defined in the file "config/pa/nm-hppah.h", accesses the variable
+ indirectly. Mutter something rude about the HP merge. */
+ int stepped_after_stopped_by_watchpoint;
+ int sw_single_step_trap_p = 0;
+
+ /* Cache the last pid/waitstatus. */
+ target_last_wait_ptid = ecs->ptid;
+ target_last_waitstatus = *ecs->wp;
+
+ adjust_pc_after_break (ecs);
+
+ switch (ecs->infwait_state)
+ {
+ case infwait_thread_hop_state:
+ /* Cancel the waiton_ptid. */
+ ecs->waiton_ptid = pid_to_ptid (-1);
+ /* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event
+ is serviced in this loop, below. */
+ if (ecs->enable_hw_watchpoints_after_wait)
+ {
+ TARGET_ENABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid));
+ ecs->enable_hw_watchpoints_after_wait = 0;
+ }
+ stepped_after_stopped_by_watchpoint = 0;
+ break;
+
+ case infwait_normal_state:
+ /* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event
+ is serviced in this loop, below. */
+ if (ecs->enable_hw_watchpoints_after_wait)
+ {
+ TARGET_ENABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid));
+ ecs->enable_hw_watchpoints_after_wait = 0;
+ }
+ stepped_after_stopped_by_watchpoint = 0;
+ break;
+
+ case infwait_nullified_state:
+ stepped_after_stopped_by_watchpoint = 0;
+ break;
+
+ case infwait_nonstep_watch_state:
+ 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? */
+ stepped_after_stopped_by_watchpoint = 1;
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ ecs->infwait_state = infwait_normal_state;
+
+ flush_cached_frames ();
+
+ /* If it's a new process, add it to the thread database */
+
+ ecs->new_thread_event = (!ptid_equal (ecs->ptid, inferior_ptid)
+ && !in_thread_list (ecs->ptid));
+
+ if (ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
+ {
+ add_thread (ecs->ptid);
+
+ ui_out_text (uiout, "[New ");
+ ui_out_text (uiout, target_pid_or_tid_to_str (ecs->ptid));
+ ui_out_text (uiout, "]\n");
+
+#if 0
+ /* NOTE: This block is ONLY meant to be invoked in case of a
+ "thread creation event"! If it is invoked for any other
+ sort of event (such as a new thread landing on a breakpoint),
+ the event will be discarded, which is almost certainly
+ a bad thing!
+
+ To avoid this, the low-level module (eg. target_wait)
+ should call in_thread_list and add_thread, so that the
+ new thread is known by the time we get here. */
+
+ /* 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 (RESUME_ALL, 0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+#endif
+ }
+
+ switch (ecs->ws.kind)
+ {
+ case TARGET_WAITKIND_LOADED:
+ /* Ignore gracefully during startup of the inferior, as it
+ might be the shell which has just loaded some objects,
+ otherwise add the symbols for the newly loaded objects. */
+#ifdef SOLIB_ADD
+ if (stop_soon == NO_STOP_QUIETLY)
+ {
+ /* Remove breakpoints, SOLIB_ADD might adjust
+ breakpoint addresses via breakpoint_re_set. */
+ if (breakpoints_inserted)
+ remove_breakpoints ();
+
+ /* Check for any newly added shared libraries if we're
+ supposed to be adding them automatically. Switch
+ terminal for any messages produced by
+ breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ /* NOTE: cagney/2003-11-25: Make certain that the target
+ stack's section table is kept up-to-date. Architectures,
+ (e.g., PPC64), use the section table to perform
+ operations such as address => section name and hence
+ require the table to contain all sections (including
+ those found in shared libraries). */
+ /* NOTE: cagney/2003-11-25: Pass current_target and not
+ exec_ops to SOLIB_ADD. This is because current GDB is
+ only tooled to propagate section_table changes out from
+ the "current_target" (see target_resize_to_sections), and
+ not up from the exec stratum. This, of course, isn't
+ right. "infrun.c" should only interact with the
+ exec/process stratum, instead relying on the target stack
+ to propagate relevant changes (stop, section table
+ changed, ...) up to other layers. */
+ SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
+ target_terminal_inferior ();
+
+ /* Reinsert breakpoints and continue. */
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+#endif
+ resume (0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+
+ case TARGET_WAITKIND_SPURIOUS:
+ resume (0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+
+ case TARGET_WAITKIND_EXITED:
+ target_terminal_ours (); /* Must do this before mourn anyway */
+ print_stop_reason (EXITED, ecs->ws.value.integer);
+
+ /* 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) ecs->ws.value.integer));
+ gdb_flush (gdb_stdout);
+ target_mourn_inferior ();
+ singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P() */
+ stop_print_frame = 0;
+ stop_stepping (ecs);
+ return;
+
+ case TARGET_WAITKIND_SIGNALLED:
+ stop_print_frame = 0;
+ stop_signal = ecs->ws.value.sig;
+ target_terminal_ours (); /* Must do this before mourn anyway */
+
+ /* Note: By definition of TARGET_WAITKIND_SIGNALLED, we shouldn't
+ reach here unless the inferior is dead. However, for years
+ target_kill() was called here, which hints that fatal signals aren't
+ really fatal on some systems. If that's true, then some changes
+ may be needed. */
+ target_mourn_inferior ();
+
+ print_stop_reason (SIGNAL_EXITED, stop_signal);
+ singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P() */
+ stop_stepping (ecs);
+ return;
+
+ /* The following are the only cases in which we keep going;
+ the above cases end in a continue or goto. */
+ case TARGET_WAITKIND_FORKED:
+ case TARGET_WAITKIND_VFORKED:
+ stop_signal = TARGET_SIGNAL_TRAP;
+ pending_follow.kind = ecs->ws.kind;
+
+ pending_follow.fork_event.parent_pid = PIDGET (ecs->ptid);
+ pending_follow.fork_event.child_pid = ecs->ws.value.related_pid;
+
+ stop_pc = read_pc ();
+
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+
+ ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
+
+ /* If no catchpoint triggered for this, then keep going. */
+ if (ecs->random_signal)
+ {
+ stop_signal = TARGET_SIGNAL_0;
+ keep_going (ecs);
+ return;
+ }
+ goto process_event_stop_test;
+
+ case TARGET_WAITKIND_EXECD:
+ stop_signal = TARGET_SIGNAL_TRAP;
+
+ /* NOTE drow/2002-12-05: This code should be pushed down into the
+ target_wait function. Until then following vfork on HP/UX 10.20
+ is probably broken by this. Of course, it's broken anyway. */
+ /* Is this a target which reports multiple exec events per actual
+ call to exec()? (HP-UX using ptrace does, for example.) If so,
+ ignore all but the last one. Just resume the exec'r, and wait
+ for the next exec event. */
+ if (inferior_ignoring_leading_exec_events)
+ {
+ inferior_ignoring_leading_exec_events--;
+ if (pending_follow.kind == TARGET_WAITKIND_VFORKED)
+ ENSURE_VFORKING_PARENT_REMAINS_STOPPED (pending_follow.fork_event.
+ parent_pid);
+ target_resume (ecs->ptid, 0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+ }
+ inferior_ignoring_leading_exec_events =
+ target_reported_exec_events_per_exec_call () - 1;
+
+ pending_follow.execd_pathname =
+ savestring (ecs->ws.value.execd_pathname,
+ strlen (ecs->ws.value.execd_pathname));
+
+ /* This causes the eventpoints and symbol table to be reset. Must
+ do this now, before trying to determine whether to stop. */
+ follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname);
+ xfree (pending_follow.execd_pathname);
+
+ stop_pc = read_pc_pid (ecs->ptid);
+ ecs->saved_inferior_ptid = inferior_ptid;
+ inferior_ptid = ecs->ptid;
+
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+
+ ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
+ inferior_ptid = ecs->saved_inferior_ptid;
+
+ /* If no catchpoint triggered for this, then keep going. */
+ if (ecs->random_signal)
+ {
+ stop_signal = TARGET_SIGNAL_0;
+ keep_going (ecs);
+ return;
+ }
+ goto process_event_stop_test;
+
+ /* These syscall events are returned on HP-UX, as part of its
+ implementation of page-protection-based "hardware" watchpoints.
+ HP-UX has unfortunate interactions between page-protections and
+ some system calls. Our solution is to disable hardware watches
+ when a system call is entered, and reenable them when the syscall
+ completes. The downside of this is that we may miss the precise
+ point at which a watched piece of memory is modified. "Oh well."
+
+ Note that we may have multiple threads running, which may each
+ enter syscalls at roughly the same time. Since we don't have a
+ good notion currently of whether a watched piece of memory is
+ thread-private, we'd best not have any page-protections active
+ when any thread is in a syscall. Thus, we only want to reenable
+ hardware watches when no threads are in a syscall.
+
+ Also, be careful not to try to gather much state about a thread
+ that's in a syscall. It's frequently a losing proposition. */
+ case TARGET_WAITKIND_SYSCALL_ENTRY:
+ number_of_threads_in_syscalls++;
+ if (number_of_threads_in_syscalls == 1)
+ {
+ TARGET_DISABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid));
+ }
+ resume (0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+
+ /* Before examining the threads further, step this thread to
+ get it entirely out of the syscall. (We get notice of the
+ event when the thread is just on the verge of exiting a
+ syscall. Stepping one instruction seems to get it back
+ into user code.)
+
+ Note that although the logical place to reenable h/w watches
+ is here, we cannot. We cannot reenable them before stepping
+ the thread (this causes the next wait on the thread to hang).
+
+ Nor can we enable them after stepping until we've done a wait.
+ Thus, we simply set the flag ecs->enable_hw_watchpoints_after_wait
+ here, which will be serviced immediately after the target
+ is waited on. */
+ case TARGET_WAITKIND_SYSCALL_RETURN:
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
+
+ if (number_of_threads_in_syscalls > 0)
+ {
+ number_of_threads_in_syscalls--;
+ ecs->enable_hw_watchpoints_after_wait =
+ (number_of_threads_in_syscalls == 0);
+ }
+ prepare_to_wait (ecs);
+ return;
+
+ case TARGET_WAITKIND_STOPPED:
+ stop_signal = ecs->ws.value.sig;
+ break;
+
+ /* We had an event in the inferior, but we are not interested
+ in handling it at this level. The lower layers have already
+ done what needs to be done, if anything.
+
+ One of the possible circumstances for this is when the
+ inferior produces output for the console. The inferior has
+ not stopped, and we are ignoring the event. Another possible
+ circumstance is any event which the lower level knows will be
+ reported multiple times without an intervening resume. */
+ case TARGET_WAITKIND_IGNORE:
+ prepare_to_wait (ecs);
+ return;
+ }
+
+ /* 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. */
+ if (ecs->new_thread_event)
+ {
+ target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+ }
+
+ stop_pc = read_pc_pid (ecs->ptid);
+
+ if (stepping_past_singlestep_breakpoint)
+ {
+ gdb_assert (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p);
+ gdb_assert (ptid_equal (singlestep_ptid, ecs->ptid));
+ gdb_assert (!ptid_equal (singlestep_ptid, saved_singlestep_ptid));
+
+ stepping_past_singlestep_breakpoint = 0;
+
+ /* We've either finished single-stepping past the single-step
+ breakpoint, or stopped for some other reason. It would be nice if
+ we could tell, but we can't reliably. */
+ if (stop_signal == TARGET_SIGNAL_TRAP)
+ {
+ /* Pull the single step breakpoints out of the target. */
+ SOFTWARE_SINGLE_STEP (0, 0);
+ singlestep_breakpoints_inserted_p = 0;
+
+ ecs->random_signal = 0;
+
+ ecs->ptid = saved_singlestep_ptid;
+ context_switch (ecs);
+ if (context_hook)
+ context_hook (pid_to_thread_id (ecs->ptid));
+
+ resume (1, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+ }
+ }
+
+ stepping_past_singlestep_breakpoint = 0;
+
+ /* 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)
+ {
+ int thread_hop_needed = 0;
+
+ /* Check if a regular breakpoint has been hit before checking
+ for a potential single step breakpoint. Otherwise, GDB will
+ not see this breakpoint hit when stepping onto breakpoints. */
+ if (breakpoints_inserted && breakpoint_here_p (stop_pc))
+ {
+ ecs->random_signal = 0;
+ if (!breakpoint_thread_match (stop_pc, ecs->ptid))
+ thread_hop_needed = 1;
+ }
+ else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+ {
+ ecs->random_signal = 0;
+ /* The call to in_thread_list is necessary because PTIDs sometimes
+ change when we go from single-threaded to multi-threaded. If
+ the singlestep_ptid is still in the list, assume that it is
+ really different from ecs->ptid. */
+ if (!ptid_equal (singlestep_ptid, ecs->ptid)
+ && in_thread_list (singlestep_ptid))
+ {
+ thread_hop_needed = 1;
+ stepping_past_singlestep_breakpoint = 1;
+ saved_singlestep_ptid = singlestep_ptid;
+ }
+ }
+
+ if (thread_hop_needed)
+ {
+ int remove_status;
+
+ /* Saw a breakpoint, but it was hit by the wrong thread.
+ Just continue. */
+
+ if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+ {
+ /* Pull the single step breakpoints out of the target. */
+ SOFTWARE_SINGLE_STEP (0, 0);
+ singlestep_breakpoints_inserted_p = 0;
+ }
+
+ remove_status = remove_breakpoints ();
+ /* Did we fail to remove breakpoints? If so, try
+ to set the PC past the bp. (There's at least
+ one situation in which we can fail to remove
+ the bp's: On HP-UX's that use ttrace, we can't
+ change the address space of a vforking child
+ process until the child exits (well, okay, not
+ then either :-) or execs. */
+ if (remove_status != 0)
+ {
+ /* FIXME! This is obviously non-portable! */
+ write_pc_pid (stop_pc + 4, ecs->ptid);
+ /* We need to restart all the threads now,
+ * unles we're running in scheduler-locked mode.
+ * Use currently_stepping to determine whether to
+ * step or continue.
+ */
+ /* FIXME MVS: is there any reason not to call resume()? */
+ if (scheduler_mode == schedlock_on)
+ target_resume (ecs->ptid,
+ currently_stepping (ecs), TARGET_SIGNAL_0);
+ else
+ target_resume (RESUME_ALL,
+ currently_stepping (ecs), TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+ }
+ else
+ { /* Single step */
+ breakpoints_inserted = 0;
+ if (!ptid_equal (inferior_ptid, ecs->ptid))
+ context_switch (ecs);
+ ecs->waiton_ptid = ecs->ptid;
+ ecs->wp = &(ecs->ws);
+ ecs->another_trap = 1;
+
+ ecs->infwait_state = infwait_thread_hop_state;
+ keep_going (ecs);
+ registers_changed ();
+ return;
+ }
+ }
+ else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+ {
+ sw_single_step_trap_p = 1;
+ ecs->random_signal = 0;
+ }
+ }
+ else
+ ecs->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.
+
+ Note that if there's any kind of pending follow (i.e., of a fork,
+ vfork or exec), we don't want to do this now. Rather, we'll let
+ the next resume handle it. */
+ if (!ptid_equal (ecs->ptid, inferior_ptid) &&
+ (pending_follow.kind == TARGET_WAITKIND_SPURIOUS))
+ {
+ int printed = 0;
+
+ /* If it's a random signal for a non-current thread, notify user
+ if he's expressed an interest. */
+ if (ecs->random_signal && signal_print[stop_signal])
+ {
+/* ??rehrauer: I don't understand the rationale for this code. If the
+ inferior will stop as a result of this signal, then the act of handling
+ the stop ought to print a message that's couches the stoppage in user
+ terms, e.g., "Stopped for breakpoint/watchpoint". If the inferior
+ won't stop as a result of the signal -- i.e., if the signal is merely
+ a side-effect of something GDB's doing "under the covers" for the
+ user, such as stepping threads over a breakpoint they shouldn't stop
+ for -- then the message seems to be a serious annoyance at best.
+
+ For now, remove the message altogether. */
+#if 0
+ 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);
+#endif
+ }
+
+ /* 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 (ecs->ptid, 0, stop_signal);
+ prepare_to_wait (ecs);
+ return;
+ }
+
+ /* It's a SIGTRAP or a signal we're interested in. Switch threads,
+ and fall into the rest of wait_for_inferior(). */
+
+ context_switch (ecs);
+
+ if (context_hook)
+ context_hook (pid_to_thread_id (ecs->ptid));
+
+ flush_cached_frames ();
+ }
+
+ if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+ {
+ /* Pull the single step breakpoints out of the target. */
+ SOFTWARE_SINGLE_STEP (0, 0);
+ singlestep_breakpoints_inserted_p = 0;
+ }
+
+ /* 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 && currently_stepping (ecs)) */
+ if (INSTRUCTION_NULLIFIED)
+ {
+ registers_changed ();
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
+
+ /* We may have received a signal that we want to pass to
+ the inferior; therefore, we must not clobber the waitstatus
+ in WS. */
+
+ ecs->infwait_state = infwait_nullified_state;
+ ecs->waiton_ptid = ecs->ptid;
+ ecs->wp = &(ecs->tmpstatus);
+ prepare_to_wait (ecs);
+ return;
+ }
+
+ /* 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 (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
+ {
+ resume (1, 0);
+ prepare_to_wait (ecs);
+ return;
+ }
+
+ /* 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 (HAVE_NONSTEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
+ {
+ /* 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. */
+
+ remove_breakpoints ();
+ registers_changed ();
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */
+
+ ecs->waiton_ptid = ecs->ptid;
+ ecs->wp = &(ecs->ws);
+ ecs->infwait_state = infwait_nonstep_watch_state;
+ prepare_to_wait (ecs);
+ return;
+ }
+
+ /* It may be possible to simply continue after a watchpoint. */
+ if (HAVE_CONTINUABLE_WATCHPOINT)
+ STOPPED_BY_WATCHPOINT (ecs->ws);
+
+ ecs->stop_func_start = 0;
+ ecs->stop_func_end = 0;
+ ecs->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, &ecs->stop_func_name,
+ &ecs->stop_func_start, &ecs->stop_func_end);
+ ecs->stop_func_start += FUNCTION_START_OFFSET;
+ ecs->another_trap = 0;
+ bpstat_clear (&stop_bpstat);
+ stop_step = 0;
+ stop_stack_dummy = 0;
+ stop_print_frame = 1;
+ ecs->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 ecs->another_trap to 1 to single step once)
+ 3) set ecs->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. We do
+ something similar for SIGSEGV, since a SIGSEGV will be generated
+ when we're trying to execute a breakpoint instruction on a
+ non-executable stack. This happens for call dummy breakpoints
+ for architectures like SPARC that place call dummies on the
+ stack. */
+
+ if (stop_signal == TARGET_SIGNAL_TRAP
+ || (breakpoints_inserted &&
+ (stop_signal == TARGET_SIGNAL_ILL
+ || stop_signal == TARGET_SIGNAL_SEGV
+ || stop_signal == TARGET_SIGNAL_EMT))
+ || stop_soon == STOP_QUIETLY
+ || stop_soon == STOP_QUIETLY_NO_SIGSTOP)
+ {
+ if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
+ {
+ stop_print_frame = 0;
+ stop_stepping (ecs);
+ return;
+ }
+
+ /* This is originated from start_remote(), start_inferior() and
+ shared libraries hook functions. */
+ if (stop_soon == STOP_QUIETLY)
+ {
+ stop_stepping (ecs);
+ return;
+ }
+
+ /* This originates from attach_command(). We need to overwrite
+ the stop_signal here, because some kernels don't ignore a
+ SIGSTOP in a subsequent ptrace(PTRACE_SONT,SOGSTOP) call.
+ See more comments in inferior.h. */
+ if (stop_soon == STOP_QUIETLY_NO_SIGSTOP)
+ {
+ stop_stepping (ecs);
+ if (stop_signal == TARGET_SIGNAL_STOP)
+ stop_signal = TARGET_SIGNAL_0;
+ return;
+ }
+
+ /* 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, ecs->ptid);
+
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
+ }
+
+ /* NOTE: cagney/2003-03-29: These two checks for a random signal
+ at one stage in the past included checks for an inferior
+ function call's call dummy's return breakpoint. The original
+ comment, that went with the test, read:
+
+ ``End of a stack dummy. Some systems (e.g. Sony news) give
+ another signal besides SIGTRAP, so check here as well as
+ above.''
+
+ If someone ever tries to get get call dummys on a
+ non-executable stack to work (where the target would stop
+ with something like a SIGSEGV), then those tests might need
+ to be re-instated. Given, however, that the tests were only
+ enabled when momentary breakpoints were not being used, I
+ suspect that it won't be the case.
+
+ NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
+ be necessary for call dummies on a non-executable stack on
+ SPARC. */
+
+ if (stop_signal == TARGET_SIGNAL_TRAP)
+ ecs->random_signal
+ = !(bpstat_explains_signal (stop_bpstat)
+ || trap_expected
+ || (step_range_end && step_resume_breakpoint == NULL));
+ else
+ {
+ ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
+ if (!ecs->random_signal)
+ stop_signal = TARGET_SIGNAL_TRAP;
+ }
+ }
+
+ /* When we reach this point, we've pretty much decided
+ that the reason for stopping must've been a random
+ (unexpected) signal. */
+
+ else
+ ecs->random_signal = 1;
+
+process_event_stop_test:
+ /* For the program's own signals, act according to
+ the signal handling tables. */
+
+ if (ecs->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 ();
+ print_stop_reason (SIGNAL_RECEIVED, stop_signal);
+ }
+ if (signal_stop[stop_signal])
+ {
+ stop_stepping (ecs);
+ return;
+ }
+ /* 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.
+
+ This used to jump to step_over_function if we are stepping,
+ which is wrong.
+
+ Suppose the user does a `next' over a function call, and while
+ that call is in progress, the inferior receives a signal for
+ which GDB does not stop (i.e., signal_stop[SIG] is false). In
+ that case, when we reach this point, there is already a
+ step-resume breakpoint established, right where it should be:
+ immediately after the function call the user is "next"-ing
+ over. If we call step_over_function now, two bad things
+ happen:
+
+ - we'll create a new breakpoint, at wherever the current
+ frame's return address happens to be. That could be
+ anywhere, depending on what function call happens to be on
+ the top of the stack at that point. Point is, it's probably
+ not where we need it.
+
+ - the existing step-resume breakpoint (which is at the correct
+ address) will get orphaned: step_resume_breakpoint will point
+ to the new breakpoint, and the old step-resume breakpoint
+ will never be cleaned up.
+
+ The old behavior was meant to help HP-UX single-step out of
+ sigtramps. It would place the new breakpoint at prev_pc, which
+ was certainly wrong. I don't know the details there, so fixing
+ this probably breaks that. As with anything else, it's up to
+ the HP-UX maintainer to furnish a fix that doesn't break other
+ platforms. --JimB, 20 May 1999 */
+ check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
+ }
+
+ /* 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_P () || !GET_LONGJMP_TARGET (&jmp_buf_pc))
+ {
+ keep_going (ecs);
+ return;
+ }
+
+ /* Need to blow away step-resume breakpoint, as it
+ interferes with us */
+ if (step_resume_breakpoint != NULL)
+ {
+ delete_step_resume_breakpoint (&step_resume_breakpoint);
+ }
+ /* 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_frame_id);
+ ecs->handling_longjmp = 1; /* FIXME */
+ keep_going (ecs);
+ return;
+
+ 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_id_inner (get_frame_id (get_current_frame ()),
+ step_frame_id)))
+ {
+ ecs->another_trap = 1;
+ keep_going (ecs);
+ return;
+ }
+#endif /* 0 */
+ disable_longjmp_breakpoint ();
+ ecs->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;
+ ecs->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. */
+
+ stop_stepping (ecs);
+ return;
+
+ 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. */
+
+ stop_stepping (ecs);
+ return;
+
+ case BPSTAT_WHAT_STEP_RESUME:
+ /* This proably demands a more elegant solution, but, yeah
+ right...
+
+ This function's use of the simple variable
+ step_resume_breakpoint doesn't seem to accomodate
+ simultaneously active step-resume bp's, although the
+ breakpoint list certainly can.
+
+ If we reach here and step_resume_breakpoint is already
+ NULL, then apparently we have multiple active
+ step-resume bp's. We'll just delete the breakpoint we
+ stopped at, and carry on.
+
+ Correction: what the code currently does is delete a
+ step-resume bp, but it makes no effort to ensure that
+ the one deleted is the one currently stopped at. MVS */
+
+ if (step_resume_breakpoint == NULL)
+ {
+ step_resume_breakpoint =
+ bpstat_find_step_resume_breakpoint (stop_bpstat);
+ }
+ delete_step_resume_breakpoint (&step_resume_breakpoint);
+ 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)
+ ecs->another_trap = 1;
+ break;
+
+ case BPSTAT_WHAT_CHECK_SHLIBS:
+ case BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK:
+#ifdef 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. Switch
+ terminal for any messages produced by
+ breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ /* NOTE: cagney/2003-11-25: Make certain that the target
+ stack's section table is kept up-to-date. Architectures,
+ (e.g., PPC64), use the section table to perform
+ operations such as address => section name and hence
+ require the table to contain all sections (including
+ those found in shared libraries). */
+ /* NOTE: cagney/2003-11-25: Pass current_target and not
+ exec_ops to SOLIB_ADD. This is because current GDB is
+ only tooled to propagate section_table changes out from
+ the "current_target" (see target_resize_to_sections), and
+ not up from the exec stratum. This, of course, isn't
+ right. "infrun.c" should only interact with the
+ exec/process stratum, instead relying on the target stack
+ to propagate relevant changes (stop, section table
+ changed, ...) up to other layers. */
+ SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
+ target_terminal_inferior ();
+
+ /* Try to reenable shared library breakpoints, additional
+ code segments in shared libraries might be mapped in now. */
+ re_enable_breakpoints_in_shlibs ();
+
+ /* 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_stack_dummy)
+ {
+ stop_stepping (ecs);
+ return;
+ }
+
+ /* If we stopped due to an explicit catchpoint, then the
+ (see above) call to SOLIB_ADD pulled in any symbols
+ from a newly-loaded library, if appropriate.
+
+ We do want the inferior to stop, but not where it is
+ now, which is in the dynamic linker callback. Rather,
+ we would like it stop in the user's program, just after
+ the call that caused this catchpoint to trigger. That
+ gives the user a more useful vantage from which to
+ examine their program's state. */
+ else if (what.main_action ==
+ BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK)
+ {
+ /* ??rehrauer: If I could figure out how to get the
+ right return PC from here, we could just set a temp
+ breakpoint and resume. I'm not sure we can without
+ cracking open the dld's shared libraries and sniffing
+ their unwind tables and text/data ranges, and that's
+ not a terribly portable notion.
+
+ Until that time, we must step the inferior out of the
+ dld callback, and also out of the dld itself (and any
+ code or stubs in libdld.sl, such as "shl_load" and
+ friends) until we reach non-dld code. At that point,
+ we can stop stepping. */
+ bpstat_get_triggered_catchpoints (stop_bpstat,
+ &ecs->
+ stepping_through_solib_catchpoints);
+ ecs->stepping_through_solib_after_catch = 1;
+
+ /* Be sure to lift all breakpoints, so the inferior does
+ actually step past this point... */
+ ecs->another_trap = 1;
+ break;
+ }
+ else
+ {
+ /* We want to step over this breakpoint, then keep going. */
+ ecs->another_trap = 1;
+ break;
+ }
+ }
+#endif
+ break;
+
+ 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. */
+
+ /* Are we stepping to get the inferior out of the dynamic
+ linker's hook (and possibly the dld itself) after catching
+ a shlib event? */
+ if (ecs->stepping_through_solib_after_catch)
+ {
+#if defined(SOLIB_ADD)
+ /* Have we reached our destination? If not, keep going. */
+ if (SOLIB_IN_DYNAMIC_LINKER (PIDGET (ecs->ptid), stop_pc))
+ {
+ ecs->another_trap = 1;
+ keep_going (ecs);
+ return;
+ }
+#endif
+ /* Else, stop and report the catchpoint(s) whose triggering
+ caused us to begin stepping. */
+ ecs->stepping_through_solib_after_catch = 0;
+ bpstat_clear (&stop_bpstat);
+ stop_bpstat = bpstat_copy (ecs->stepping_through_solib_catchpoints);
+ bpstat_clear (&ecs->stepping_through_solib_catchpoints);
+ stop_print_frame = 1;
+ stop_stepping (ecs);
+ return;
+ }
+
+ 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. */
+ check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
+ }
+
+ 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. */
+ check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
+ }
+
+ /* If stepping through a line, keep going if still within it.
+
+ Note that step_range_end is the address of the first instruction
+ beyond the step range, and NOT the address of the last instruction
+ within it! */
+ if (stop_pc >= step_range_start && stop_pc < step_range_end)
+ {
+ /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal.
+ So definately need to check for sigtramp here. */
+ check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
+ }
+
+ /* We stepped out of the stepping range. */
+
+ /* If we are stepping at the source level and entered the runtime
+ loader dynamic symbol resolution code, we keep on single stepping
+ until we exit the run time loader code and reach the callee's
+ address. */
+ if (step_over_calls == STEP_OVER_UNDEBUGGABLE
+ && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc))
+ {
+ CORE_ADDR pc_after_resolver =
+ gdbarch_skip_solib_resolver (current_gdbarch, stop_pc);
+
+ if (pc_after_resolver)
+ {
+ /* Set up a step-resume breakpoint at the address
+ indicated by SKIP_SOLIB_RESOLVER. */
+ struct symtab_and_line sr_sal;
+ init_sal (&sr_sal);
+ sr_sal.pc = pc_after_resolver;
+
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, null_frame_id, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+
+ keep_going (ecs);
+ return;
+ }
+
+ /* 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. */
+ ecs->update_step_sp = 1;
+
+ /* Did we just take a signal? */
+ if (pc_in_sigtramp (stop_pc)
+ && !pc_in_sigtramp (prev_pc)
+ && INNER_THAN (read_sp (), step_sp))
+ {
+ /* We've just taken a signal; go until we are back to
+ the point where we took it and one more. */
+
+ /* Note: The test above succeeds not only when we stepped
+ into a signal handler, but also when we step past the last
+ statement of a signal handler and end up in the return stub
+ of the signal handler trampoline. To distinguish between
+ these two cases, check that the frame is INNER_THAN the
+ previous one below. pai/1997-09-11 */
+
+
+ {
+ struct frame_id current_frame = get_frame_id (get_current_frame ());
+
+ if (frame_id_inner (current_frame, step_frame_id))
+ {
+ /* We have 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;
+
+ init_sal (&sr_sal);
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ sr_sal.pc = prev_pc;
+ /* We could probably be setting the frame to
+ step_frame_id; I don't think anyone thought to try it. */
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, null_frame_id, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+ else
+ {
+ /* We just stepped out of a signal handler and into
+ its calling trampoline.
+
+ Normally, we'd call step_over_function from
+ here, but for some reason GDB can't unwind the
+ stack correctly to find the real PC for the point
+ user code where the signal trampoline will return
+ -- FRAME_SAVED_PC fails, at least on HP-UX 10.20.
+ But signal trampolines are pretty small stubs of
+ code, anyway, so it's OK instead to just
+ single-step out. Note: assuming such trampolines
+ don't exhibit recursion on any platform... */
+ find_pc_partial_function (stop_pc, &ecs->stop_func_name,
+ &ecs->stop_func_start,
+ &ecs->stop_func_end);
+ /* Readjust stepping range */
+ step_range_start = ecs->stop_func_start;
+ step_range_end = ecs->stop_func_end;
+ ecs->stepping_through_sigtramp = 1;
+ }
+ }
+
+
+ /* 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;
+
+ ecs->remove_breakpoints_on_following_step = 1;
+ keep_going (ecs);
+ return;
+ }
+
+ if (((stop_pc == ecs->stop_func_start /* Quick test */
+ || in_prologue (stop_pc, ecs->stop_func_start))
+ && !IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name))
+ || IN_SOLIB_CALL_TRAMPOLINE (stop_pc, ecs->stop_func_name)
+ || ecs->stop_func_name == 0)
+ {
+ /* It's a subroutine call. */
+ handle_step_into_function (ecs);
+ return;
+ }
+
+ /* We've wandered out of the step range. */
+
+ ecs->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;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+
+ /* 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, ecs->stop_func_name))
+ {
+ /* Determine where this trampoline returns. */
+ CORE_ADDR real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc);
+
+ /* Only proceed through if we know where it's going. */
+ if (real_stop_pc)
+ {
+ /* And put the step-breakpoint there and go until there. */
+ struct symtab_and_line sr_sal;
+
+ init_sal (&sr_sal); /* initialize to zeroes */
+ sr_sal.pc = real_stop_pc;
+ sr_sal.section = find_pc_overlay (sr_sal.pc);
+ /* 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. */
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, null_frame_id, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ /* Restart without fiddling with the step ranges or
+ other state. */
+ keep_going (ecs);
+ return;
+ }
+ }
+
+ if (ecs->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;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+
+ if ((stop_pc == ecs->sal.pc)
+ && (ecs->current_line != ecs->sal.line
+ || ecs->current_symtab != ecs->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;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+
+ /* 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 (ecs->stop_func_end && ecs->sal.end >= ecs->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;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+ step_range_start = ecs->sal.pc;
+ step_range_end = ecs->sal.end;
+ step_frame_id = get_frame_id (get_current_frame ());
+ ecs->current_line = ecs->sal.line;
+ ecs->current_symtab = ecs->sal.symtab;
+
+ /* In the case where we just stepped out of a function into the
+ middle of a line of the caller, continue stepping, but
+ step_frame_id must be modified to current frame */
+#if 0
+ /* NOTE: cagney/2003-10-16: I think this frame ID inner test is too
+ generous. It will trigger on things like a step into a frameless
+ stackless leaf function. I think the logic should instead look
+ at the unwound frame ID has that should give a more robust
+ indication of what happened. */
+ if (step-ID == current-ID)
+ still stepping in same function;
+ else if (step-ID == unwind (current-ID))
+ stepped into a function;
+ else
+ stepped out of a function;
+ /* Of course this assumes that the frame ID unwind code is robust
+ and we're willing to introduce frame unwind logic into this
+ function. Fortunately, those days are nearly upon us. */
+#endif
+ {
+ struct frame_id current_frame = get_frame_id (get_current_frame ());
+ if (!(frame_id_inner (current_frame, step_frame_id)))
+ step_frame_id = current_frame;
+ }
+
+ keep_going (ecs);
+}
+
+/* Are we in the middle of stepping? */
+
+static int
+currently_stepping (struct execution_control_state *ecs)
+{
+ return ((through_sigtramp_breakpoint == NULL
+ && !ecs->handling_longjmp
+ && ((step_range_end && step_resume_breakpoint == NULL)
+ || trap_expected))
+ || ecs->stepping_through_solib_after_catch
+ || bpstat_should_step ());
+}
+
+static void
+check_sigtramp2 (struct execution_control_state *ecs)
+{
+ if (trap_expected
+ && pc_in_sigtramp (stop_pc)
+ && !pc_in_sigtramp (prev_pc)
+ && INNER_THAN (read_sp (), step_sp))
+ {
+ /* 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 the testsuite,
+ gdb.base/signals.exp where it says "exceedingly difficult"). */
+
+ struct symtab_and_line sr_sal;
+
+ init_sal (&sr_sal); /* initialize to zeroes */
+ sr_sal.pc = prev_pc;
+ sr_sal.section = find_pc_overlay (sr_sal.pc);
+ /* 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_frame_id, bp_through_sigtramp);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ ecs->remove_breakpoints_on_following_step = 1;
+ ecs->another_trap = 1;
+ }
+}
+
+/* Subroutine call with source code we should not step over. Do step
+ to the first line of code in it. */
+
+static void
+step_into_function (struct execution_control_state *ecs)
+{
+ struct symtab *s;
+ struct symtab_and_line sr_sal;
+
+ s = find_pc_symtab (stop_pc);
+ if (s && s->language != language_asm)
+ ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start);
+
+ ecs->sal = find_pc_line (ecs->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. */
+ if (ecs->sal.end
+ && ecs->sal.pc != ecs->stop_func_start
+ && ecs->sal.end < ecs->stop_func_end)
+ ecs->stop_func_start = ecs->sal.end;
+
+ /* Architectures which require breakpoint adjustment might not be able
+ to place a breakpoint at the computed address. If so, the test
+ ``ecs->stop_func_start == stop_pc'' will never succeed. Adjust
+ ecs->stop_func_start to an address at which a breakpoint may be
+ legitimately placed.
+
+ Note: kevinb/2004-01-19: On FR-V, if this adjustment is not
+ made, GDB will enter an infinite loop when stepping through
+ optimized code consisting of VLIW instructions which contain
+ subinstructions corresponding to different source lines. On
+ FR-V, it's not permitted to place a breakpoint on any but the
+ first subinstruction of a VLIW instruction. When a breakpoint is
+ set, GDB will adjust the breakpoint address to the beginning of
+ the VLIW instruction. Thus, we need to make the corresponding
+ adjustment here when computing the stop address. */
+
+ if (gdbarch_adjust_breakpoint_address_p (current_gdbarch))
+ {
+ ecs->stop_func_start
+ = gdbarch_adjust_breakpoint_address (current_gdbarch,
+ ecs->stop_func_start);
+ }
+
+ if (ecs->stop_func_start == stop_pc)
+ {
+ /* We are already there: stop now. */
+ stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+ else
+ {
+ /* Put the step-breakpoint there and go until there. */
+ init_sal (&sr_sal); /* initialize to zeroes */
+ sr_sal.pc = ecs->stop_func_start;
+ sr_sal.section = find_pc_overlay (ecs->stop_func_start);
+ /* 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. */
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, null_frame_id, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ /* And make sure stepping stops right away then. */
+ step_range_end = step_range_start;
+ }
+ keep_going (ecs);
+}
+
+/* We've just entered a callee, and we wish to resume until it returns
+ to the caller. Setting a step_resume breakpoint on the return
+ address will catch a return from the callee.
+
+ However, if the callee is recursing, we want to be careful not to
+ catch returns of those recursive calls, but only of THIS instance
+ of the call.
+
+ To do this, we set the step_resume bp's frame to our current
+ caller's frame (step_frame_id, which is set by the "next" or
+ "until" command, before execution begins). */
+
+static void
+step_over_function (struct execution_control_state *ecs)
+{
+ struct symtab_and_line sr_sal;
+
+ init_sal (&sr_sal); /* initialize to zeros */
+
+ /* NOTE: cagney/2003-04-06:
+
+ At this point the equality get_frame_pc() == get_frame_func()
+ should hold. This may make it possible for this code to tell the
+ frame where it's function is, instead of the reverse. This would
+ avoid the need to search for the frame's function, which can get
+ very messy when there is no debug info available (look at the
+ heuristic find pc start code found in targets like the MIPS). */
+
+ /* NOTE: cagney/2003-04-06:
+
+ The intent of DEPRECATED_SAVED_PC_AFTER_CALL was to:
+
+ - provide a very light weight equivalent to frame_unwind_pc()
+ (nee FRAME_SAVED_PC) that avoids the prologue analyzer
+
+ - avoid handling the case where the PC hasn't been saved in the
+ prologue analyzer
+
+ Unfortunately, not five lines further down, is a call to
+ get_frame_id() and that is guarenteed to trigger the prologue
+ analyzer.
+
+ The `correct fix' is for the prologe analyzer to handle the case
+ where the prologue is incomplete (PC in prologue) and,
+ consequently, the return pc has not yet been saved. It should be
+ noted that the prologue analyzer needs to handle this case
+ anyway: frameless leaf functions that don't save the return PC;
+ single stepping through a prologue.
+
+ The d10v handles all this by bailing out of the prologue analsis
+ when it reaches the current instruction. */
+
+ if (DEPRECATED_SAVED_PC_AFTER_CALL_P ())
+ sr_sal.pc = ADDR_BITS_REMOVE (DEPRECATED_SAVED_PC_AFTER_CALL (get_current_frame ()));
+ else
+ sr_sal.pc = ADDR_BITS_REMOVE (frame_pc_unwind (get_current_frame ()));
+ sr_sal.section = find_pc_overlay (sr_sal.pc);
+
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_frame_id (get_current_frame ()),
+ bp_step_resume);
+
+ if (frame_id_p (step_frame_id)
+ && !IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc))
+ step_resume_breakpoint->frame_id = step_frame_id;
+
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+}
+
+static void
+stop_stepping (struct execution_control_state *ecs)
+{
+ /* Let callers know we don't want to wait for the inferior anymore. */
+ ecs->wait_some_more = 0;
+}
+
+/* This function handles various cases where we need to continue
+ waiting for the inferior. */
+/* (Used to be the keep_going: label in the old wait_for_inferior) */
+
+static void
+keep_going (struct execution_control_state *ecs)
+{
+ /* Save the pc before execution, to compare with pc after stop. */
+ prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
+
+ if (ecs->update_step_sp)
+ step_sp = read_sp ();
+ ecs->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 (ecs), 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
+ && ecs->remove_breakpoints_on_following_step)
+ {
+ ecs->remove_breakpoints_on_following_step = 0;
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ }
+ else if (!breakpoints_inserted &&
+ (through_sigtramp_breakpoint != NULL || !ecs->another_trap))
+ {
+ breakpoints_failed = insert_breakpoints ();
+ if (breakpoints_failed)
+ {
+ stop_stepping (ecs);
+ return;
+ }
+ breakpoints_inserted = 1;
+ }
+
+ trap_expected = ecs->another_trap;
+
+ /* Do not deliver SIGNAL_TRAP (except when the user explicitly
+ specifies that such a signal should be delivered to the
+ target program).
+
+ Typically, this would occure when a user is debugging a
+ target monitor on a simulator: the target monitor sets a
+ breakpoint; the simulator encounters this break-point and
+ halts the simulation handing control to GDB; GDB, noteing
+ that the break-point isn't valid, returns control back to the
+ simulator; the simulator then delivers the hardware
+ equivalent of a SIGNAL_TRAP to the program being debugged. */
+
+ if (stop_signal == TARGET_SIGNAL_TRAP && !signal_program[stop_signal])
+ stop_signal = TARGET_SIGNAL_0;
+
+
+ resume (currently_stepping (ecs), stop_signal);
+ }
+
+ prepare_to_wait (ecs);
+}
+
+/* This function normally comes after a resume, before
+ handle_inferior_event exits. It takes care of any last bits of
+ housekeeping, and sets the all-important wait_some_more flag. */
+
+static void
+prepare_to_wait (struct execution_control_state *ecs)
+{
+ if (ecs->infwait_state == infwait_normal_state)
+ {
+ overlay_cache_invalid = 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 ();
+ ecs->waiton_ptid = pid_to_ptid (-1);
+ ecs->wp = &(ecs->ws);
+ }
+ /* This is the old end of the while loop. Let everybody know we
+ want to wait for the inferior some more and get called again
+ soon. */
+ ecs->wait_some_more = 1;
+}
+
+/* Print why the inferior has stopped. We always print something when
+ the inferior exits, or receives a signal. The rest of the cases are
+ dealt with later on in normal_stop() and print_it_typical(). Ideally
+ there should be a call to this function from handle_inferior_event()
+ each time stop_stepping() is called.*/
+static void
+print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
+{
+ switch (stop_reason)
+ {
+ case STOP_UNKNOWN:
+ /* We don't deal with these cases from handle_inferior_event()
+ yet. */
+ break;
+ case END_STEPPING_RANGE:
+ /* We are done with a step/next/si/ni command. */
+ /* For now print nothing. */
+ /* Print a message only if not in the middle of doing a "step n"
+ operation for n > 1 */
+ if (!step_multi || !stop_step)
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "end-stepping-range");
+ break;
+ case BREAKPOINT_HIT:
+ /* We found a breakpoint. */
+ /* For now print nothing. */
+ break;
+ case SIGNAL_EXITED:
+ /* The inferior was terminated by a signal. */
+ annotate_signalled ();
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "exited-signalled");
+ ui_out_text (uiout, "\nProgram terminated with signal ");
+ annotate_signal_name ();
+ ui_out_field_string (uiout, "signal-name",
+ target_signal_to_name (stop_info));
+ annotate_signal_name_end ();
+ ui_out_text (uiout, ", ");
+ annotate_signal_string ();
+ ui_out_field_string (uiout, "signal-meaning",
+ target_signal_to_string (stop_info));
+ annotate_signal_string_end ();
+ ui_out_text (uiout, ".\n");
+ ui_out_text (uiout, "The program no longer exists.\n");
+ break;
+ case EXITED:
+ /* The inferior program is finished. */
+ annotate_exited (stop_info);
+ if (stop_info)
+ {
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "exited");
+ ui_out_text (uiout, "\nProgram exited with code ");
+ ui_out_field_fmt (uiout, "exit-code", "0%o",
+ (unsigned int) stop_info);
+ ui_out_text (uiout, ".\n");
+ }
+ else
+ {
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "exited-normally");
+ ui_out_text (uiout, "\nProgram exited normally.\n");
+ }
+ break;
+ case SIGNAL_RECEIVED:
+ /* Signal received. The signal table tells us to print about
+ it. */
+ annotate_signal ();
+ ui_out_text (uiout, "\nProgram received signal ");
+ annotate_signal_name ();
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "reason", "signal-received");
+ ui_out_field_string (uiout, "signal-name",
+ target_signal_to_name (stop_info));
+ annotate_signal_name_end ();
+ ui_out_text (uiout, ", ");
+ annotate_signal_string ();
+ ui_out_field_string (uiout, "signal-meaning",
+ target_signal_to_string (stop_info));
+ annotate_signal_string_end ();
+ ui_out_text (uiout, ".\n");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "print_stop_reason: unrecognized enum value");
+ break;
+ }
+}
+
+
+/* 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 (void)
+{
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ get_last_target_status (&last_ptid, &last);
+
+ /* As with the notification of thread events, we want to delay
+ notifying the user that we've switched thread context until
+ the inferior actually stops.
+
+ There's no point in saying anything if the inferior has exited.
+ Note that SIGNALLED here means "exited with a signal", not
+ "received a signal". */
+ if (!ptid_equal (previous_inferior_ptid, inferior_ptid)
+ && target_has_execution
+ && last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED)
+ {
+ target_terminal_ours_for_output ();
+ printf_filtered ("[Switching to %s]\n",
+ target_pid_or_tid_to_str (inferior_ptid));
+ previous_inferior_ptid = inferior_ptid;
+ }
+
+ /* NOTE drow/2004-01-17: Is this still necessary? */
+ /* 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)
+ /* FIXME: cagney/2002-12-06: Has the PC changed? Thanks to
+ DECR_PC_AFTER_BREAK, the program counter can change. Ask the
+ frame code to check for this and sort out any resultant mess.
+ DECR_PC_AFTER_BREAK needs to just go away. */
+ deprecated_update_frame_pc_hack (get_current_frame (), read_pc ());
+
+ if (target_has_execution && breakpoints_inserted)
+ {
+ if (remove_breakpoints ())
+ {
+ target_terminal_ours_for_output ();
+ printf_filtered ("Cannot remove breakpoints because ");
+ printf_filtered ("program is no longer writable.\n");
+ printf_filtered ("It might be running in another process.\n");
+ printf_filtered ("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 ();
+
+ /* Don't print a message if in the middle of doing a "step n"
+ operation for n > 1 */
+ if (step_multi && stop_step)
+ goto done;
+
+ target_terminal_ours ();
+
+ /* Look up the hook_stop and run it (CLI internally handles problem
+ of stop_command's pre-hook not existing). */
+ if (stop_command)
+ catch_errors (hook_stop_stub, stop_command,
+ "Error while running hook_stop:\n", RETURN_MASK_ALL);
+
+ if (!target_has_stack)
+ {
+
+ goto done;
+ }
+
+ /* Select innermost stack frame - i.e., current frame is frame 0,
+ and current location is based on that.
+ Don't do this on return from a stack dummy routine,
+ or if the program has exited. */
+
+ if (!stop_stack_dummy)
+ {
+ select_frame (get_current_frame ());
+
+ /* Print current location without a level number, if
+ we have changed functions or hit a breakpoint.
+ Print source line if we have one.
+ bpstat_print() contains the logic deciding in detail
+ what to print, based on the event(s) that just occurred. */
+
+ if (stop_print_frame && deprecated_selected_frame)
+ {
+ int bpstat_ret;
+ int source_flag;
+ int do_frame_printing = 1;
+
+ bpstat_ret = bpstat_print (stop_bpstat);
+ switch (bpstat_ret)
+ {
+ case PRINT_UNKNOWN:
+ /* FIXME: cagney/2002-12-01: Given that a frame ID does
+ (or should) carry around the function and does (or
+ should) use that when doing a frame comparison. */
+ if (stop_step
+ && frame_id_eq (step_frame_id,
+ get_frame_id (get_current_frame ()))
+ && step_start_function == find_pc_function (stop_pc))
+ source_flag = SRC_LINE; /* finished step, just print source line */
+ else
+ source_flag = SRC_AND_LOC; /* print location and source line */
+ break;
+ case PRINT_SRC_AND_LOC:
+ source_flag = SRC_AND_LOC; /* print location and source line */
+ break;
+ case PRINT_SRC_ONLY:
+ source_flag = SRC_LINE;
+ break;
+ case PRINT_NOTHING:
+ source_flag = SRC_LINE; /* something bogus */
+ do_frame_printing = 0;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "Unknown value.");
+ }
+ /* For mi, have the same behavior every time we stop:
+ print everything but the source line. */
+ if (ui_out_is_mi_like_p (uiout))
+ source_flag = LOC_AND_ADDRESS;
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "thread-id",
+ pid_to_thread_id (inferior_ptid));
+ /* The behavior of this routine with respect to the source
+ flag is:
+ SRC_LINE: Print only source line
+ LOCATION: Print only location
+ SRC_AND_LOC: Print location and source line */
+ if (do_frame_printing)
+ print_stack_frame (deprecated_selected_frame, -1, source_flag);
+
+ /* 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)
+ /* NB: The copy goes through to the target picking up the value of
+ all the registers. */
+ regcache_cpy (stop_registers, current_regcache);
+
+ 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. */
+ frame_pop (get_current_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 ());
+ }
+
+done:
+ annotate_stopped ();
+ observer_notify_normal_stop ();
+}
+
+static int
+hook_stop_stub (void *cmd)
+{
+ execute_cmd_pre_hook ((struct cmd_list_element *) cmd);
+ return (0);
+}
+
+int
+signal_stop_state (int signo)
+{
+ return signal_stop[signo];
+}
+
+int
+signal_print_state (int signo)
+{
+ return signal_print[signo];
+}
+
+int
+signal_pass_state (int signo)
+{
+ return signal_program[signo];
+}
+
+int
+signal_stop_update (int signo, int state)
+{
+ int ret = signal_stop[signo];
+ signal_stop[signo] = state;
+ return ret;
+}
+
+int
+signal_print_update (int signo, int state)
+{
+ int ret = signal_print[signo];
+ signal_print[signo] = state;
+ return ret;
+}
+
+int
+signal_pass_update (int signo, int state)
+{
+ int ret = signal_program[signo];
+ signal_program[signo] = state;
+ return ret;
+}
+
+static void
+sig_print_header (void)
+{
+ printf_filtered ("\
+Signal Stop\tPrint\tPass to program\tDescription\n");
+}
+
+static void
+sig_print_info (enum target_signal oursig)
+{
+ char *name = target_signal_to_name (oursig);
+ int name_padding = 13 - strlen (name);
+
+ if (name_padding <= 0)
+ name_padding = 0;
+
+ printf_filtered ("%s", name);
+ printf_filtered ("%*.*s ", name_padding, name_padding, " ");
+ 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 (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 (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 <LOW>-<HIGH>. */
+
+ 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_ptid);
+
+ 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);
+}
+
+static void
+xdb_handle_command (char *args, int from_tty)
+{
+ char **argv;
+ struct cleanup *old_chain;
+
+ /* Break the command line up into args. */
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ {
+ nomem (0);
+ }
+ old_chain = make_cleanup_freeargv (argv);
+ if (argv[1] != (char *) NULL)
+ {
+ char *argBuf;
+ int bufLen;
+
+ bufLen = strlen (argv[0]) + 20;
+ argBuf = (char *) xmalloc (bufLen);
+ if (argBuf)
+ {
+ int validFlag = 1;
+ enum target_signal oursig;
+
+ oursig = target_signal_from_name (argv[0]);
+ memset (argBuf, 0, bufLen);
+ if (strcmp (argv[1], "Q") == 0)
+ sprintf (argBuf, "%s %s", argv[0], "noprint");
+ else
+ {
+ if (strcmp (argv[1], "s") == 0)
+ {
+ if (!signal_stop[oursig])
+ sprintf (argBuf, "%s %s", argv[0], "stop");
+ else
+ sprintf (argBuf, "%s %s", argv[0], "nostop");
+ }
+ else if (strcmp (argv[1], "i") == 0)
+ {
+ if (!signal_program[oursig])
+ sprintf (argBuf, "%s %s", argv[0], "pass");
+ else
+ sprintf (argBuf, "%s %s", argv[0], "nopass");
+ }
+ else if (strcmp (argv[1], "r") == 0)
+ {
+ if (!signal_print[oursig])
+ sprintf (argBuf, "%s %s", argv[0], "print");
+ else
+ sprintf (argBuf, "%s %s", argv[0], "noprint");
+ }
+ else
+ validFlag = 0;
+ }
+ if (validFlag)
+ handle_command (argBuf, from_tty);
+ else
+ printf_filtered ("Invalid signal handling flag.\n");
+ if (argBuf)
+ xfree (argBuf);
+ }
+ }
+ 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 (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_long (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");
+}
+
+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;
+ struct frame_id step_frame_id;
+ enum step_over_calls_kind step_over_calls;
+ CORE_ADDR step_resume_break_address;
+ int stop_after_trap;
+ int stop_soon;
+ struct regcache *stop_registers;
+
+ /* 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. */
+ struct regcache *registers;
+
+ /* A frame unique identifier. */
+ struct frame_id selected_frame_id;
+
+ int breakpoint_proceeded;
+ int restore_stack_info;
+ int proceed_to_finish;
+};
+
+void
+write_inferior_status_register (struct inferior_status *inf_status, int regno,
+ LONGEST val)
+{
+ int size = DEPRECATED_REGISTER_RAW_SIZE (regno);
+ void *buf = alloca (size);
+ store_signed_integer (buf, size, val);
+ regcache_raw_write (inf_status->registers, regno, buf);
+}
+
+/* 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). */
+
+struct inferior_status *
+save_inferior_status (int restore_stack_info)
+{
+ struct inferior_status *inf_status = XMALLOC (struct inferior_status);
+
+ 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_id = step_frame_id;
+ inf_status->step_over_calls = step_over_calls;
+ inf_status->stop_after_trap = stop_after_trap;
+ inf_status->stop_soon = stop_soon;
+ /* 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_inferior_status 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;
+
+ inf_status->stop_registers = regcache_dup_no_passthrough (stop_registers);
+
+ inf_status->registers = regcache_dup (current_regcache);
+
+ inf_status->selected_frame_id = get_frame_id (deprecated_selected_frame);
+ return inf_status;
+}
+
+static int
+restore_selected_frame (void *args)
+{
+ struct frame_id *fid = (struct frame_id *) args;
+ struct frame_info *frame;
+
+ frame = frame_find_by_id (*fid);
+
+ /* If inf_status->selected_frame_id is NULL, there was no previously
+ selected frame. */
+ if (frame == NULL)
+ {
+ warning ("Unable to restore previously selected frame.\n");
+ return 0;
+ }
+
+ select_frame (frame);
+
+ return (1);
+}
+
+void
+restore_inferior_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_id = inf_status->step_frame_id;
+ step_over_calls = inf_status->step_over_calls;
+ stop_after_trap = inf_status->stop_after_trap;
+ stop_soon = inf_status->stop_soon;
+ bpstat_clear (&stop_bpstat);
+ stop_bpstat = inf_status->stop_bpstat;
+ breakpoint_proceeded = inf_status->breakpoint_proceeded;
+ proceed_to_finish = inf_status->proceed_to_finish;
+
+ /* FIXME: Is the restore of stop_registers always needed. */
+ regcache_xfree (stop_registers);
+ stop_registers = inf_status->stop_registers;
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+ if (target_has_execution)
+ /* NB: The register write goes through to the target. */
+ regcache_cpy (current_regcache, inf_status->registers);
+ regcache_xfree (inf_status->registers);
+
+ /* 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)
+ {
+ /* 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, &inf_status->selected_frame_id,
+ "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 ());
+
+ }
+
+ xfree (inf_status);
+}
+
+static void
+do_restore_inferior_status_cleanup (void *sts)
+{
+ restore_inferior_status (sts);
+}
+
+struct cleanup *
+make_cleanup_restore_inferior_status (struct inferior_status *inf_status)
+{
+ return make_cleanup (do_restore_inferior_status_cleanup, inf_status);
+}
+
+void
+discard_inferior_status (struct inferior_status *inf_status)
+{
+ /* See save_inferior_status for info on stop_bpstat. */
+ bpstat_clear (&inf_status->stop_bpstat);
+ regcache_xfree (inf_status->registers);
+ regcache_xfree (inf_status->stop_registers);
+ xfree (inf_status);
+}
+
+int
+inferior_has_forked (int pid, int *child_pid)
+{
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ get_last_target_status (&last_ptid, &last);
+
+ if (last.kind != TARGET_WAITKIND_FORKED)
+ return 0;
+
+ if (ptid_get_pid (last_ptid) != pid)
+ return 0;
+
+ *child_pid = last.value.related_pid;
+ return 1;
+}
+
+int
+inferior_has_vforked (int pid, int *child_pid)
+{
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ get_last_target_status (&last_ptid, &last);
+
+ if (last.kind != TARGET_WAITKIND_VFORKED)
+ return 0;
+
+ if (ptid_get_pid (last_ptid) != pid)
+ return 0;
+
+ *child_pid = last.value.related_pid;
+ return 1;
+}
+
+int
+inferior_has_execd (int pid, char **execd_pathname)
+{
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ get_last_target_status (&last_ptid, &last);
+
+ if (last.kind != TARGET_WAITKIND_EXECD)
+ return 0;
+
+ if (ptid_get_pid (last_ptid) != pid)
+ return 0;
+
+ *execd_pathname = xstrdup (last.value.execd_pathname);
+ return 1;
+}
+
+/* Oft used ptids */
+ptid_t null_ptid;
+ptid_t minus_one_ptid;
+
+/* Create a ptid given the necessary PID, LWP, and TID components. */
+
+ptid_t
+ptid_build (int pid, long lwp, long tid)
+{
+ ptid_t ptid;
+
+ ptid.pid = pid;
+ ptid.lwp = lwp;
+ ptid.tid = tid;
+ return ptid;
+}
+
+/* Create a ptid from just a pid. */
+
+ptid_t
+pid_to_ptid (int pid)
+{
+ return ptid_build (pid, 0, 0);
+}
+
+/* Fetch the pid (process id) component from a ptid. */
+
+int
+ptid_get_pid (ptid_t ptid)
+{
+ return ptid.pid;
+}
+
+/* Fetch the lwp (lightweight process) component from a ptid. */
+
+long
+ptid_get_lwp (ptid_t ptid)
+{
+ return ptid.lwp;
+}
+
+/* Fetch the tid (thread id) component from a ptid. */
+
+long
+ptid_get_tid (ptid_t ptid)
+{
+ return ptid.tid;
+}
+
+/* ptid_equal() is used to test equality of two ptids. */
+
+int
+ptid_equal (ptid_t ptid1, ptid_t ptid2)
+{
+ return (ptid1.pid == ptid2.pid && ptid1.lwp == ptid2.lwp
+ && ptid1.tid == ptid2.tid);
+}
+
+/* restore_inferior_ptid() will be used by the cleanup machinery
+ to restore the inferior_ptid value saved in a call to
+ save_inferior_ptid(). */
+
+static void
+restore_inferior_ptid (void *arg)
+{
+ ptid_t *saved_ptid_ptr = arg;
+ inferior_ptid = *saved_ptid_ptr;
+ xfree (arg);
+}
+
+/* Save the value of inferior_ptid so that it may be restored by a
+ later call to do_cleanups(). Returns the struct cleanup pointer
+ needed for later doing the cleanup. */
+
+struct cleanup *
+save_inferior_ptid (void)
+{
+ ptid_t *saved_ptid_ptr;
+
+ saved_ptid_ptr = xmalloc (sizeof (ptid_t));
+ *saved_ptid_ptr = inferior_ptid;
+ return make_cleanup (restore_inferior_ptid, saved_ptid_ptr);
+}
+
+
+static void
+build_infrun (void)
+{
+ stop_registers = regcache_xmalloc (current_gdbarch);
+}
+
+void
+_initialize_infrun (void)
+{
+ int i;
+ int numsigs;
+ struct cmd_list_element *c;
+
+ DEPRECATED_REGISTER_GDBARCH_SWAP (stop_registers);
+ deprecated_register_gdbarch_swap (NULL, 0, build_infrun);
+
+ 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));
+ if (xdb_commands)
+ {
+ add_com ("lz", class_info, signals_info,
+ "What debugger does when program gets various signals.\n\
+Specify a signal as argument to print info on that signal only.");
+ add_com ("z", class_run, xdb_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 \"s\" (toggles between stop and nostop), \n\
+\"r\" (toggles between print and noprint), \"i\" (toggles between pass and \
+nopass), \"Q\" (noprint)\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));
+ }
+
+ if (!dbx_commands)
+ 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;
+ signal_stop[TARGET_SIGNAL_WINCH] = 0;
+ signal_print[TARGET_SIGNAL_WINCH] = 0;
+
+ /* These signals are used internally by user-level thread
+ implementations. (See signal(5) on Solaris.) Like the above
+ signals, a healthy program receives and handles them as part of
+ its normal operation. */
+ signal_stop[TARGET_SIGNAL_LWP] = 0;
+ signal_print[TARGET_SIGNAL_LWP] = 0;
+ signal_stop[TARGET_SIGNAL_WAITING] = 0;
+ signal_print[TARGET_SIGNAL_WAITING] = 0;
+ signal_stop[TARGET_SIGNAL_CANCEL] = 0;
+ signal_print[TARGET_SIGNAL_CANCEL] = 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
+
+ c = add_set_enum_cmd ("follow-fork-mode",
+ class_run,
+ follow_fork_mode_kind_names, &follow_fork_mode_string,
+ "Set debugger response to a program call of fork \
+or vfork.\n\
+A fork or vfork creates a new process. follow-fork-mode can be:\n\
+ parent - the original process is debugged after a fork\n\
+ child - the new process is debugged after a fork\n\
+The unfollowed process will continue to run.\n\
+By default, the debugger will follow the parent process.", &setlist);
+ add_show_from_set (c, &showlist);
+
+ c = add_set_enum_cmd ("scheduler-locking", class_run, scheduler_enums, /* array of string names */
+ &scheduler_mode, /* current mode */
+ "Set mode for locking scheduler during execution.\n\
+off == no locking (threads may preempt at any time)\n\
+on == full locking (no thread except the current thread may run)\n\
+step == scheduler locked during every single-step operation.\n\
+ In this mode, no other thread may run during a step command.\n\
+ Other threads may run while stepping over a function call ('next').", &setlist);
+
+ set_cmd_sfunc (c, set_schedlock_func); /* traps on target vector */
+ add_show_from_set (c, &showlist);
+
+ c = add_set_cmd ("step-mode", class_run,
+ var_boolean, (char *) &step_stop_if_no_debug,
+ "Set mode of the step operation. When set, doing a step over a\n\
+function without debug line information will stop at the first\n\
+instruction of that function. Otherwise, the function is skipped and\n\
+the step command stops at a different source line.", &setlist);
+ add_show_from_set (c, &showlist);
+
+ /* ptid initializations */
+ null_ptid = ptid_build (0, 0, 0);
+ minus_one_ptid = ptid_build (-1, 0, 0);
+ inferior_ptid = null_ptid;
+ target_last_wait_ptid = minus_one_ptid;
+}
diff --git a/contrib/gdb/gdb/inftarg.c b/contrib/gdb/gdb/inftarg.c
new file mode 100644
index 0000000..bbd7f22
--- /dev/null
+++ b/contrib/gdb/gdb/inftarg.c
@@ -0,0 +1,713 @@
+/* Target-vector operations for controlling Unix child processes, for GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
+ 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Support.
+
+ ## Contains temporary hacks..
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbcore.h"
+#include "command.h"
+#include "gdb_stat.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "gdb_wait.h"
+#include "inflow.h"
+
+extern struct symtab_and_line *child_enable_exception_callback (enum
+ exception_event_kind,
+ int);
+
+extern struct exception_event_record
+ *child_get_current_exception_event (void);
+
+extern void _initialize_inftarg (void);
+
+static void child_prepare_to_store (void);
+
+#ifndef CHILD_WAIT
+static ptid_t child_wait (ptid_t, struct target_waitstatus *);
+#endif /* CHILD_WAIT */
+
+#if !defined(CHILD_POST_WAIT)
+void child_post_wait (ptid_t, int);
+#endif
+
+static void child_open (char *, int);
+
+static void child_files_info (struct target_ops *);
+
+static void child_detach (char *, int);
+
+static void child_attach (char *, int);
+
+#if !defined(CHILD_POST_ATTACH)
+extern void child_post_attach (int);
+#endif
+
+static void ptrace_me (void);
+
+static void ptrace_him (int);
+
+static void child_create_inferior (char *, char *, char **);
+
+static void child_mourn_inferior (void);
+
+static int child_can_run (void);
+
+static void child_stop (void);
+
+#ifndef CHILD_THREAD_ALIVE
+int child_thread_alive (ptid_t);
+#endif
+
+static void init_child_ops (void);
+
+extern char **environ;
+
+struct target_ops child_ops;
+
+int child_suppress_run = 0; /* Non-zero if inftarg should pretend not to
+ be a runnable target. Used by targets
+ that can sit atop inftarg, such as HPUX
+ thread support. */
+
+#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 ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ int save_errno;
+ int status;
+ char *execd_pathname = NULL;
+ int exit_status;
+ int related_pid;
+ int syscall_id;
+ enum target_waitkind kind;
+ int pid;
+
+ do
+ {
+ set_sigint_trap (); /* Causes SIGINT to be passed on to the
+ attached process. */
+ set_sigio_trap ();
+
+ pid = ptrace_wait (inferior_ptid, &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 pid_to_ptid (-1);
+ }
+
+ /* Did it exit?
+ */
+ if (target_has_exited (pid, status, &exit_status))
+ {
+ /* ??rehrauer: For now, ignore this. */
+ continue;
+ }
+
+ if (!target_thread_alive (pid_to_ptid (pid)))
+ {
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ return pid_to_ptid (pid);
+ }
+ } while (pid != PIDGET (inferior_ptid)); /* Some other child died or stopped */
+
+ store_waitstatus (ourstatus, status);
+ return pid_to_ptid (pid);
+}
+#endif /* CHILD_WAIT */
+
+#if !defined(CHILD_POST_WAIT)
+void
+child_post_wait (ptid_t ptid, int wait_status)
+{
+ /* This version of Unix doesn't require a meaningful "post wait"
+ operation.
+ */
+}
+#endif
+
+
+#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. */
+int
+child_thread_alive (ptid_t ptid)
+{
+ pid_t pid = PIDGET (ptid);
+
+ return (kill (pid, 0) != -1);
+}
+
+#endif
+
+/* Attach to process PID, then initialize for debugging it. */
+
+static void
+child_attach (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;
+ char *dummy;
+
+ dummy = args;
+ pid = strtol (args, &dummy, 0);
+ /* Some targets don't set errno on errors, grrr! */
+ if ((pid == 0) && (args == dummy))
+ error ("Illegal process-id: %s\n", 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_to_ptid (pid)));
+ else
+ printf_unfiltered ("Attaching to %s\n",
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ gdb_flush (gdb_stdout);
+ }
+
+ attach (pid);
+
+ inferior_ptid = pid_to_ptid (pid);
+ push_target (&child_ops);
+ }
+#endif /* ATTACH_DETACH */
+}
+
+#if !defined(CHILD_POST_ATTACH)
+void
+child_post_attach (int pid)
+{
+ /* This version of Unix doesn't require a meaningful "post attach"
+ operation by a debugger. */
+}
+#endif
+
+/* 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 (char *args, int from_tty)
+{
+#ifdef ATTACH_DETACH
+ {
+ int siggnal = 0;
+ int pid = PIDGET (inferior_ptid);
+
+ 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 (pid_to_ptid (pid)));
+ gdb_flush (gdb_stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ detach (siggnal);
+
+ inferior_ptid = null_ptid;
+ 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 (void)
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+child_files_info (struct target_ops *ignore)
+{
+ printf_unfiltered ("\tUsing the running image of %s %s.\n",
+ attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
+}
+
+static void
+child_open (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 (void)
+{
+ /* "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 (int pid)
+{
+ push_target (&child_ops);
+
+ /* On some targets, there must be some explicit synchronization
+ between the parent and child processes after the debugger
+ forks, and before the child execs the debuggee program. This
+ call basically gives permission for the child to exec.
+ */
+
+ target_acknowledge_created_inferior (pid);
+
+ /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h,
+ * and will be 1 or 2 depending on whether we're starting
+ * without or with a shell.
+ */
+ startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+
+ /* On some targets, there must be some explicit actions taken after
+ the inferior has been started up.
+ */
+ target_post_startup_inferior (pid_to_ptid (pid));
+}
+
+/* Start an inferior Unix child process and sets inferior_ptid 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 (char *exec_file, char *allargs, char **env)
+{
+#ifdef HPUXHPPA
+ fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him, pre_fork_inferior, NULL);
+#else
+ fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him, NULL, NULL);
+#endif
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+}
+
+#if !defined(CHILD_POST_STARTUP_INFERIOR)
+void
+child_post_startup_inferior (ptid_t ptid)
+{
+ /* This version of Unix doesn't require a meaningful "post startup inferior"
+ operation by a debugger.
+ */
+}
+#endif
+
+#if !defined(CHILD_ACKNOWLEDGE_CREATED_INFERIOR)
+void
+child_acknowledge_created_inferior (int pid)
+{
+ /* This version of Unix doesn't require a meaningful "acknowledge created inferior"
+ operation by a debugger.
+ */
+}
+#endif
+
+
+#if !defined(CHILD_INSERT_FORK_CATCHPOINT)
+int
+child_insert_fork_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of fork events. */
+ return 0;
+}
+#endif
+
+#if !defined(CHILD_REMOVE_FORK_CATCHPOINT)
+int
+child_remove_fork_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of fork events. */
+ return 0;
+}
+#endif
+
+#if !defined(CHILD_INSERT_VFORK_CATCHPOINT)
+int
+child_insert_vfork_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of vfork events. */
+ return 0;
+}
+#endif
+
+#if !defined(CHILD_REMOVE_VFORK_CATCHPOINT)
+int
+child_remove_vfork_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of vfork events. */
+ return 0;
+}
+#endif
+
+#if !defined(CHILD_FOLLOW_FORK)
+int
+child_follow_fork (int follow_child)
+{
+ /* This version of Unix doesn't support following fork or vfork events. */
+ return 0;
+}
+#endif
+
+#if !defined(CHILD_INSERT_EXEC_CATCHPOINT)
+int
+child_insert_exec_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of exec events. */
+ return 0;
+}
+#endif
+
+#if !defined(CHILD_REMOVE_EXEC_CATCHPOINT)
+int
+child_remove_exec_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of exec events. */
+ return 0;
+}
+#endif
+
+#if !defined(CHILD_REPORTED_EXEC_EVENTS_PER_EXEC_CALL)
+int
+child_reported_exec_events_per_exec_call (void)
+{
+ /* This version of Unix doesn't support notification of exec events.
+ */
+ return 1;
+}
+#endif
+
+#if !defined(CHILD_HAS_EXITED)
+int
+child_has_exited (int pid, int wait_status, int *exit_status)
+{
+ if (WIFEXITED (wait_status))
+ {
+ *exit_status = WEXITSTATUS (wait_status);
+ return 1;
+ }
+
+ if (WIFSIGNALED (wait_status))
+ {
+ *exit_status = 0; /* ?? Don't know what else to say here. */
+ return 1;
+ }
+
+ /* ?? Do we really need to consult the event state, too? Assume the
+ wait_state alone suffices.
+ */
+ return 0;
+}
+#endif
+
+
+static void
+child_mourn_inferior (void)
+{
+ unpush_target (&child_ops);
+ generic_mourn_inferior ();
+}
+
+static int
+child_can_run (void)
+{
+ /* This variable is controlled by modules that sit atop inftarg that may layer
+ their own process structure atop that provided here. hpux-thread.c does
+ this because of the Hpux user-mode level thread model. */
+
+ return !child_suppress_run;
+}
+
+/* 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). */
+
+static void
+child_stop (void)
+{
+ kill (-inferior_process_group, SIGINT);
+}
+
+#if !defined(CHILD_ENABLE_EXCEPTION_CALLBACK)
+struct symtab_and_line *
+child_enable_exception_callback (enum exception_event_kind kind, int enable)
+{
+ return (struct symtab_and_line *) NULL;
+}
+#endif
+
+#if !defined(CHILD_GET_CURRENT_EXCEPTION_EVENT)
+struct exception_event_record *
+child_get_current_exception_event (void)
+{
+ return (struct exception_event_record *) NULL;
+}
+#endif
+
+
+#if !defined(CHILD_PID_TO_EXEC_FILE)
+char *
+child_pid_to_exec_file (int pid)
+{
+ /* This version of Unix doesn't support translation of a process ID
+ to the filename of the executable file.
+ */
+ return NULL;
+}
+#endif
+
+char *
+child_core_file_to_sym_file (char *core)
+{
+ /* The target stratum for a running executable need not support
+ this operation.
+ */
+ return NULL;
+}
+
+/* Perform a partial transfer to/from the specified object. For
+ memory transfers, fall back to the old memory xfer functions. */
+
+static LONGEST
+child_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_MEMORY:
+ if (readbuf)
+ return child_xfer_memory (offset, readbuf, len, 0/*write*/,
+ NULL, ops);
+ if (writebuf)
+ return child_xfer_memory (offset, readbuf, len, 1/*write*/,
+ NULL, ops);
+ return -1;
+
+ case TARGET_OBJECT_UNWIND_TABLE:
+#ifndef NATIVE_XFER_UNWIND_TABLE
+#define NATIVE_XFER_UNWIND_TABLE(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
+#endif
+ return NATIVE_XFER_UNWIND_TABLE (ops, object, annex, readbuf, writebuf,
+ offset, len);
+
+ case TARGET_OBJECT_AUXV:
+#ifndef NATIVE_XFER_AUXV
+#define NATIVE_XFER_AUXV(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
+#endif
+ return NATIVE_XFER_AUXV (ops, object, annex, readbuf, writebuf,
+ offset, len);
+
+ case TARGET_OBJECT_WCOOKIE:
+#ifndef NATIVE_XFER_WCOOKIE
+#define NATIVE_XFER_WCOOKIE(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
+#endif
+ return NATIVE_XFER_WCOOKIE (ops, object, annex, readbuf, writebuf,
+ offset, len);
+
+ case TARGET_OBJECT_DIRTY:
+#ifndef NATIVE_XFER_DIRTY
+#define NATIVE_XFER_DIRTY(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
+#endif
+ return NATIVE_XFER_DIRTY (ops, object, annex, readbuf, writebuf,
+ offset, len);
+
+ default:
+ return -1;
+ }
+}
+
+#if !defined(CHILD_PID_TO_STR)
+char *
+child_pid_to_str (ptid_t ptid)
+{
+ return normal_pid_to_str (ptid);
+}
+#endif
+
+static void
+init_child_ops (void)
+{
+ child_ops.to_shortname = "child";
+ child_ops.to_longname = "Unix child process";
+ child_ops.to_doc = "Unix child process (started by the \"run\" command).";
+ child_ops.to_open = child_open;
+ child_ops.to_attach = child_attach;
+ child_ops.to_post_attach = child_post_attach;
+ child_ops.to_detach = child_detach;
+ child_ops.to_resume = child_resume;
+ child_ops.to_wait = child_wait;
+ child_ops.to_post_wait = child_post_wait;
+ child_ops.to_fetch_registers = fetch_inferior_registers;
+ child_ops.to_store_registers = store_inferior_registers;
+ child_ops.to_prepare_to_store = child_prepare_to_store;
+ child_ops.to_xfer_memory = child_xfer_memory;
+ child_ops.to_xfer_partial = child_xfer_partial;
+ child_ops.to_files_info = child_files_info;
+ child_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ child_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ child_ops.to_terminal_init = terminal_init_inferior;
+ child_ops.to_terminal_inferior = terminal_inferior;
+ child_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ child_ops.to_terminal_save_ours = terminal_save_ours;
+ child_ops.to_terminal_ours = terminal_ours;
+ child_ops.to_terminal_info = child_terminal_info;
+ child_ops.to_kill = kill_inferior;
+ child_ops.to_create_inferior = child_create_inferior;
+ child_ops.to_post_startup_inferior = child_post_startup_inferior;
+ child_ops.to_acknowledge_created_inferior = child_acknowledge_created_inferior;
+ child_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint;
+ child_ops.to_remove_fork_catchpoint = child_remove_fork_catchpoint;
+ child_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
+ child_ops.to_remove_vfork_catchpoint = child_remove_vfork_catchpoint;
+ child_ops.to_follow_fork = child_follow_fork;
+ child_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint;
+ child_ops.to_remove_exec_catchpoint = child_remove_exec_catchpoint;
+ child_ops.to_reported_exec_events_per_exec_call = child_reported_exec_events_per_exec_call;
+ child_ops.to_has_exited = child_has_exited;
+ child_ops.to_mourn_inferior = child_mourn_inferior;
+ child_ops.to_can_run = child_can_run;
+ child_ops.to_thread_alive = child_thread_alive;
+ child_ops.to_pid_to_str = child_pid_to_str;
+ child_ops.to_stop = child_stop;
+ child_ops.to_enable_exception_callback = child_enable_exception_callback;
+ child_ops.to_get_current_exception_event = child_get_current_exception_event;
+ child_ops.to_pid_to_exec_file = child_pid_to_exec_file;
+ child_ops.to_stratum = process_stratum;
+ child_ops.to_has_all_memory = 1;
+ child_ops.to_has_memory = 1;
+ child_ops.to_has_stack = 1;
+ child_ops.to_has_registers = 1;
+ child_ops.to_has_execution = 1;
+ child_ops.to_magic = OPS_MAGIC;
+}
+
+/* Take over the 'find_mapped_memory' vector from inftarg.c. */
+extern void
+inftarg_set_find_memory_regions (int (*func) (int (*) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *))
+{
+ child_ops.to_find_memory_regions = func;
+}
+
+/* Take over the 'make_corefile_notes' vector from inftarg.c. */
+extern void
+inftarg_set_make_corefile_notes (char * (*func) (bfd *, int *))
+{
+ child_ops.to_make_corefile_notes = func;
+}
+
+void
+_initialize_inftarg (void)
+{
+#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 ());
+ fd = open (procname, O_RDONLY);
+ if (fd >= 0)
+ {
+ close (fd);
+ return;
+ }
+#endif
+
+ init_child_ops ();
+ add_target (&child_ops);
+}
diff --git a/contrib/gdb/gdb/infttrace.c b/contrib/gdb/gdb/infttrace.c
new file mode 100644
index 0000000..3f76edb
--- /dev/null
+++ b/contrib/gdb/gdb/infttrace.c
@@ -0,0 +1,5607 @@
+/* Low level Unix child interface to ttrace, for GDB when running under HP-UX.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2001, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_wait.h"
+#include "command.h"
+#include "gdbthread.h"
+
+/* We need pstat functionality so that we can get the exec file
+ for a process we attach to.
+
+ According to HP, we should use the 64bit interfaces, so we
+ define _PSTAT64 to achieve this. */
+#define _PSTAT64
+#include <sys/pstat.h>
+
+/* Some hackery to work around a use of the #define name NO_FLAGS
+ * in both gdb and HPUX (bfd.h and /usr/include/machine/vmparam.h).
+ */
+#ifdef NO_FLAGS
+#define INFTTRACE_TEMP_HACK NO_FLAGS
+#undef NO_FLAGS
+#endif
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+
+#include <sys/ttrace.h>
+#include <sys/mman.h>
+
+#ifndef NO_PTRACE_H
+#ifdef PTRACE_IN_WRONG_PLACE
+#include <ptrace.h>
+#else
+#include <sys/ptrace.h>
+#endif
+#endif /* NO_PTRACE_H */
+
+/* Second half of the hackery above. Non-ANSI C, so
+ * we can't use "#error", alas.
+ */
+#ifdef NO_FLAGS
+#if (NO_FLAGS != INFTTRACE_TEMP_HACK )
+ /* #error "Hackery to remove warning didn't work right" */
+#else
+ /* Ok, new def'n of NO_FLAGS is same as old one; no action needed. */
+#endif
+#else
+ /* #error "Didn't get expected re-definition of NO_FLAGS" */
+#define NO_FLAGS INFTTRACE_TEMP_HACK
+#endif
+
+#if !defined (PT_SETTRC)
+#define PT_SETTRC 0 /* Make process traceable by parent */
+#endif
+#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 <sys/file.h>
+#endif
+
+/* This semaphore is used to coordinate the child and parent processes
+ after a fork(), and before an exec() by the child. See parent_attach_all
+ for details.
+ */
+typedef struct
+ {
+ int parent_channel[2]; /* Parent "talks" to [1], child "listens" to [0] */
+ int child_channel[2]; /* Child "talks" to [1], parent "listens" to [0] */
+ }
+startup_semaphore_t;
+
+#define SEM_TALK (1)
+#define SEM_LISTEN (0)
+
+static startup_semaphore_t startup_semaphore;
+
+/* See can_touch_threads_of_process for details. */
+static int vforking_child_pid = 0;
+static int vfork_in_flight = 0;
+
+/* 1 if ok as results of a ttrace or ttrace_wait call, 0 otherwise.
+ */
+#define TT_OK( _status, _errno ) \
+ (((_status) == 1) && ((_errno) == 0))
+
+#define TTRACE_ARG_TYPE uint64_t
+
+/* When supplied as the "addr" operand, ttrace interprets this
+ to mean, "from the current address".
+ */
+#define TT_USE_CURRENT_PC ((TTRACE_ARG_TYPE) TT_NOPC)
+
+/* When supplied as the "addr", "data" or "addr2" operand for most
+ requests, ttrace interprets this to mean, "pay no heed to this
+ argument".
+ */
+#define TT_NIL ((TTRACE_ARG_TYPE) TT_NULLARG)
+
+/* This is capable of holding the value of a 32-bit register. The
+ value is always left-aligned in the buffer; i.e., [0] contains
+ the most-significant byte of the register's value, and [sizeof(reg)]
+ contains the least-significant value.
+
+ ??rehrauer: Yes, this assumes that an int is 32-bits on HP-UX, and
+ that registers are 32-bits on HP-UX. The latter assumption changes
+ with PA2.0.
+ */
+typedef int register_value_t;
+
+/********************************************************************
+
+ How this works:
+
+ 1. Thread numbers
+
+ The rest of GDB sees threads as being things with different
+ "pid" (process id) values. See "thread.c" for details. The
+ separate threads will be seen and reacted to if infttrace passes
+ back different pid values (for _events_). See wait_for_inferior
+ in inftarg.c.
+
+ So infttrace is going to use thread ids externally, pretending
+ they are process ids, and keep track internally so that it can
+ use the real process id (and thread id) when calling ttrace.
+
+ The data structure that supports this is a linked list of the
+ current threads. Since at some date infttrace will have to
+ deal with multiple processes, each list element records its
+ corresponding pid, rather than having a single global.
+
+ Note that the list is only approximately current; that's ok, as
+ it's up to date when we need it (we hope!). Also, it can contain
+ dead threads, as there's no harm if it does.
+
+ The approach taken here is to bury the translation from external
+ to internal inside "call_ttrace" and a few other places.
+
+ There are some wrinkles:
+
+ o When GDB forks itself to create the debug target process,
+ there's only a pid of 0 around in the child, so the
+ TT_PROC_SETTRC operation uses a more direct call to ttrace;
+ Similiarly, the initial setting of the event mask happens
+ early as well, and so is also special-cased, and an attach
+ uses a real pid;
+
+ o We define an unthreaded application as having a "pseudo"
+ thread;
+
+ o To keep from confusing the rest of GDB, we don't switch
+ the PID for the pseudo thread to a TID. A table will help:
+
+ Rest of GDB sees these PIDs: pid tid1 tid2 tid3 ...
+
+ Our thread list stores: pid pid pid pid ...
+ tid0 tid1 tid2 tid3
+
+ Ttrace sees these TIDS: tid0 tid1 tid2 tid3 ...
+
+ Both pid and tid0 will map to tid0, as there are infttrace.c-internal
+ calls to ttrace using tid0.
+
+ 2. Step and Continue
+
+ Since we're implementing the "stop the world" model, sub-model
+ "other threads run during step", we have some stuff to do:
+
+ o User steps require continuing all threads other than the
+ one the user is stepping;
+
+ o Internal debugger steps (such as over a breakpoint or watchpoint,
+ but not out of a library load thunk) require stepping only
+ the selected thread; this means that we have to report the
+ step finish on that thread, which can lead to complications;
+
+ o When a thread is created, it is created running, rather
+ than stopped--so we have to stop it.
+
+ The OS doesn't guarantee the stopped thread list will be stable,
+ no does it guarantee where on the stopped thread list a thread
+ that is single-stepped will wind up: it's possible that it will
+ be off the list for a while, it's possible the step will complete
+ and it will be re-posted to the end...
+
+ This means we have to scan the stopped thread list, build up
+ a work-list, and then run down the work list; we can't do the
+ step/continue during the scan.
+
+ 3. Buffering events
+
+ Then there's the issue of waiting for an event. We do this by
+ noticing how many events are reported at the end of each wait.
+ From then on, we "fake" all resumes and steps, returning instantly,
+ and don't do another wait. Once all pending events are reported,
+ we can really resume again.
+
+ To keep this hidden, all the routines which know about tids and
+ pids or real events and simulated ones are static (file-local).
+
+ This code can make lots of calls to ttrace, in particular it
+ can spin down the list of thread states more than once. If this
+ becomes a performance hit, the spin could be done once and the
+ various "tsp" blocks saved, keeping all later spins in this
+ process.
+
+ The O/S doesn't promise to keep the list straight, and so we must
+ re-scan a lot. By observation, it looks like a single-step/wait
+ puts the stepped thread at the end of the list but doesn't change
+ it otherwise.
+
+****************************************************************
+*/
+
+/* Uncomment these to turn on various debugging output */
+/* #define THREAD_DEBUG */
+/* #define WAIT_BUFFER_DEBUG */
+/* #define PARANOIA */
+
+
+#define INFTTRACE_ALL_THREADS (-1)
+#define INFTTRACE_STEP (1)
+#define INFTTRACE_CONTINUE (0)
+
+/* FIX: this is used in inftarg.c/child_wait, in a hack.
+ */
+extern int not_same_real_pid;
+
+/* This is used to count buffered events.
+ */
+static unsigned int more_events_left = 0;
+
+/* Process state.
+ */
+typedef enum process_state_enum
+ {
+ STOPPED,
+ FAKE_STEPPING,
+ FAKE_CONTINUE, /* For later use */
+ RUNNING,
+ FORKING,
+ VFORKING
+ }
+process_state_t;
+
+static process_state_t process_state = STOPPED;
+
+/* User-specified stepping modality.
+ */
+typedef enum stepping_mode_enum
+ {
+ DO_DEFAULT, /* ...which is a continue! */
+ DO_STEP,
+ DO_CONTINUE
+ }
+stepping_mode_t;
+
+/* Action to take on an attach, depends on
+ * what kind (user command, fork, vfork).
+ *
+ * At the moment, this is either:
+ *
+ * o continue with a SIGTRAP signal, or
+ *
+ * o leave stopped.
+ */
+typedef enum attach_continue_enum
+ {
+ DO_ATTACH_CONTINUE,
+ DONT_ATTACH_CONTINUE
+ }
+attach_continue_t;
+
+/* This flag is true if we are doing a step-over-bpt
+ * with buffered events. We will have to be sure to
+ * report the right thread, as otherwise the spaghetti
+ * code in "infrun.c/wait_for_inferior" will get
+ * confused.
+ */
+static int doing_fake_step = 0;
+static lwpid_t fake_step_tid = 0;
+
+
+/****************************************************
+ * Thread information structure routines and types. *
+ ****************************************************
+ */
+typedef
+struct thread_info_struct
+ {
+ int am_pseudo; /* This is a pseudo-thread for the process. */
+ int pid; /* Process ID */
+ lwpid_t tid; /* Thread ID */
+ int handled; /* 1 if a buffered event was handled. */
+ int seen; /* 1 if this thread was seen on a traverse. */
+ int terminated; /* 1 if thread has terminated. */
+ int have_signal; /* 1 if signal to be sent */
+ enum target_signal signal_value; /* Signal to send */
+ int have_start; /* 1 if alternate starting address */
+ stepping_mode_t stepping_mode; /* Whether to step or continue */
+ CORE_ADDR start; /* Where to start */
+ int have_state; /* 1 if the event state has been set */
+ ttstate_t last_stop_state; /* The most recently-waited event for this thread. */
+ struct thread_info_struct
+ *next; /* All threads are linked via this field. */
+ struct thread_info_struct
+ *next_pseudo; /* All pseudo-threads are linked via this field. */
+ }
+thread_info;
+
+typedef
+struct thread_info_header_struct
+ {
+ int count;
+ thread_info *head;
+ thread_info *head_pseudo;
+
+ }
+thread_info_header;
+
+static thread_info_header thread_head =
+{0, NULL, NULL};
+static thread_info_header deleted_threads =
+{0, NULL, NULL};
+
+static ptid_t saved_real_ptid;
+
+
+/*************************************************
+ * Debugging support functions *
+ *************************************************
+ */
+CORE_ADDR
+get_raw_pc (lwpid_t ttid)
+{
+ unsigned long pc_val;
+ int offset;
+ int res;
+
+ offset = register_addr (PC_REGNUM, U_REGS_OFFSET);
+ res = read_from_register_save_state (
+ ttid,
+ (TTRACE_ARG_TYPE) offset,
+ (char *) &pc_val,
+ sizeof (pc_val));
+ if (res <= 0)
+ {
+ return (CORE_ADDR) pc_val;
+ }
+ else
+ {
+ return (CORE_ADDR) 0;
+ }
+}
+
+static char *
+get_printable_name_of_stepping_mode (stepping_mode_t mode)
+{
+ switch (mode)
+ {
+ case DO_DEFAULT:
+ return "DO_DEFAULT";
+ case DO_STEP:
+ return "DO_STEP";
+ case DO_CONTINUE:
+ return "DO_CONTINUE";
+ default:
+ return "?unknown mode?";
+ }
+}
+
+/* This function returns a pointer to a string describing the
+ * ttrace event being reported.
+ */
+char *
+get_printable_name_of_ttrace_event (ttevents_t event)
+{
+ /* This enumeration is "gappy", so don't use a table. */
+ switch (event)
+ {
+
+ case TTEVT_NONE:
+ return "TTEVT_NONE";
+ case TTEVT_SIGNAL:
+ return "TTEVT_SIGNAL";
+ case TTEVT_FORK:
+ return "TTEVT_FORK";
+ case TTEVT_EXEC:
+ return "TTEVT_EXEC";
+ case TTEVT_EXIT:
+ return "TTEVT_EXIT";
+ case TTEVT_VFORK:
+ return "TTEVT_VFORK";
+ case TTEVT_SYSCALL_RETURN:
+ return "TTEVT_SYSCALL_RETURN";
+ case TTEVT_LWP_CREATE:
+ return "TTEVT_LWP_CREATE";
+ case TTEVT_LWP_TERMINATE:
+ return "TTEVT_LWP_TERMINATE";
+ case TTEVT_LWP_EXIT:
+ return "TTEVT_LWP_EXIT";
+ case TTEVT_LWP_ABORT_SYSCALL:
+ return "TTEVT_LWP_ABORT_SYSCALL";
+ case TTEVT_SYSCALL_ENTRY:
+ return "TTEVT_SYSCALL_ENTRY";
+ case TTEVT_SYSCALL_RESTART:
+ return "TTEVT_SYSCALL_RESTART";
+ default:
+ return "?new event?";
+ }
+}
+
+
+/* This function translates the ttrace request enumeration into
+ * a character string that is its printable (aka "human readable")
+ * name.
+ */
+char *
+get_printable_name_of_ttrace_request (ttreq_t request)
+{
+ if (!IS_TTRACE_REQ (request))
+ return "?bad req?";
+
+ /* This enumeration is "gappy", so don't use a table. */
+ switch (request)
+ {
+ case TT_PROC_SETTRC:
+ return "TT_PROC_SETTRC";
+ case TT_PROC_ATTACH:
+ return "TT_PROC_ATTACH";
+ case TT_PROC_DETACH:
+ return "TT_PROC_DETACH";
+ case TT_PROC_RDTEXT:
+ return "TT_PROC_RDTEXT";
+ case TT_PROC_WRTEXT:
+ return "TT_PROC_WRTEXT";
+ case TT_PROC_RDDATA:
+ return "TT_PROC_RDDATA";
+ case TT_PROC_WRDATA:
+ return "TT_PROC_WRDATA";
+ case TT_PROC_STOP:
+ return "TT_PROC_STOP";
+ case TT_PROC_CONTINUE:
+ return "TT_PROC_CONTINUE";
+ case TT_PROC_GET_PATHNAME:
+ return "TT_PROC_GET_PATHNAME";
+ case TT_PROC_GET_EVENT_MASK:
+ return "TT_PROC_GET_EVENT_MASK";
+ case TT_PROC_SET_EVENT_MASK:
+ return "TT_PROC_SET_EVENT_MASK";
+ case TT_PROC_GET_FIRST_LWP_STATE:
+ return "TT_PROC_GET_FIRST_LWP_STATE";
+ case TT_PROC_GET_NEXT_LWP_STATE:
+ return "TT_PROC_GET_NEXT_LWP_STATE";
+ case TT_PROC_EXIT:
+ return "TT_PROC_EXIT";
+ case TT_PROC_GET_MPROTECT:
+ return "TT_PROC_GET_MPROTECT";
+ case TT_PROC_SET_MPROTECT:
+ return "TT_PROC_SET_MPROTECT";
+ case TT_PROC_SET_SCBM:
+ return "TT_PROC_SET_SCBM";
+ case TT_LWP_STOP:
+ return "TT_LWP_STOP";
+ case TT_LWP_CONTINUE:
+ return "TT_LWP_CONTINUE";
+ case TT_LWP_SINGLE:
+ return "TT_LWP_SINGLE";
+ case TT_LWP_RUREGS:
+ return "TT_LWP_RUREGS";
+ case TT_LWP_WUREGS:
+ return "TT_LWP_WUREGS";
+ case TT_LWP_GET_EVENT_MASK:
+ return "TT_LWP_GET_EVENT_MASK";
+ case TT_LWP_SET_EVENT_MASK:
+ return "TT_LWP_SET_EVENT_MASK";
+ case TT_LWP_GET_STATE:
+ return "TT_LWP_GET_STATE";
+ default:
+ return "?new req?";
+ }
+}
+
+
+/* This function translates the process state enumeration into
+ * a character string that is its printable (aka "human readable")
+ * name.
+ */
+static char *
+get_printable_name_of_process_state (process_state_t process_state)
+{
+ switch (process_state)
+ {
+ case STOPPED:
+ return "STOPPED";
+ case FAKE_STEPPING:
+ return "FAKE_STEPPING";
+ case RUNNING:
+ return "RUNNING";
+ case FORKING:
+ return "FORKING";
+ case VFORKING:
+ return "VFORKING";
+ default:
+ return "?some unknown state?";
+ }
+}
+
+/* Set a ttrace thread state to a safe, initial state.
+ */
+static void
+clear_ttstate_t (ttstate_t *tts)
+{
+ tts->tts_pid = 0;
+ tts->tts_lwpid = 0;
+ tts->tts_user_tid = 0;
+ tts->tts_event = TTEVT_NONE;
+}
+
+/* Copy ttrace thread state TTS_FROM into TTS_TO.
+ */
+static void
+copy_ttstate_t (ttstate_t *tts_to, ttstate_t *tts_from)
+{
+ memcpy ((char *) tts_to, (char *) tts_from, sizeof (*tts_to));
+}
+
+/* Are there any live threads we know about?
+ */
+static int
+any_thread_records (void)
+{
+ return (thread_head.count > 0);
+}
+
+/* Create, fill in and link in a thread descriptor.
+ */
+static thread_info *
+create_thread_info (int pid, lwpid_t tid)
+{
+ thread_info *new_p;
+ thread_info *p;
+ int thread_count_of_pid;
+
+ new_p = xmalloc (sizeof (thread_info));
+ new_p->pid = pid;
+ new_p->tid = tid;
+ new_p->have_signal = 0;
+ new_p->have_start = 0;
+ new_p->have_state = 0;
+ clear_ttstate_t (&new_p->last_stop_state);
+ new_p->am_pseudo = 0;
+ new_p->handled = 0;
+ new_p->seen = 0;
+ new_p->terminated = 0;
+ new_p->next = NULL;
+ new_p->next_pseudo = NULL;
+ new_p->stepping_mode = DO_DEFAULT;
+
+ if (0 == thread_head.count)
+ {
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("First thread, pid %d tid %d!\n", pid, tid);
+#endif
+ saved_real_ptid = inferior_ptid;
+ }
+ else
+ {
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Subsequent thread, pid %d tid %d\n", pid, tid);
+#endif
+ }
+
+ /* Another day, another thread...
+ */
+ thread_head.count++;
+
+ /* The new thread always goes at the head of the list.
+ */
+ new_p->next = thread_head.head;
+ thread_head.head = new_p;
+
+ /* Is this the "pseudo" thread of a process? It is if there's
+ * no other thread for this process on the list. (Note that this
+ * accomodates multiple processes, such as we see even for simple
+ * cases like forking "non-threaded" programs.)
+ */
+ p = thread_head.head;
+ thread_count_of_pid = 0;
+ while (p)
+ {
+ if (p->pid == new_p->pid)
+ thread_count_of_pid++;
+ p = p->next;
+ }
+
+ /* Did we see any other threads for this pid? (Recall that we just
+ * added this thread to the list...)
+ */
+ if (thread_count_of_pid == 1)
+ {
+ new_p->am_pseudo = 1;
+ new_p->next_pseudo = thread_head.head_pseudo;
+ thread_head.head_pseudo = new_p;
+ }
+
+ return new_p;
+}
+
+/* Get rid of our thread info.
+ */
+static void
+clear_thread_info (void)
+{
+ thread_info *p;
+ thread_info *q;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Clearing all thread info\n");
+#endif
+
+ p = thread_head.head;
+ while (p)
+ {
+ q = p;
+ p = p->next;
+ xfree (q);
+ }
+
+ thread_head.head = NULL;
+ thread_head.head_pseudo = NULL;
+ thread_head.count = 0;
+
+ p = deleted_threads.head;
+ while (p)
+ {
+ q = p;
+ p = p->next;
+ xfree (q);
+ }
+
+ deleted_threads.head = NULL;
+ deleted_threads.head_pseudo = NULL;
+ deleted_threads.count = 0;
+
+ /* No threads, so can't have pending events.
+ */
+ more_events_left = 0;
+}
+
+/* Given a tid, find the thread block for it.
+ */
+static thread_info *
+find_thread_info (lwpid_t tid)
+{
+ thread_info *p;
+
+ for (p = thread_head.head; p; p = p->next)
+ {
+ if (p->tid == tid)
+ {
+ return p;
+ }
+ }
+
+ for (p = deleted_threads.head; p; p = p->next)
+ {
+ if (p->tid == tid)
+ {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+/* For any but the pseudo thread, this maps to the
+ * thread ID. For the pseudo thread, if you pass either
+ * the thread id or the PID, you get the pseudo thread ID.
+ *
+ * We have to be prepared for core gdb to ask about
+ * deleted threads. We do the map, but we don't like it.
+ */
+static lwpid_t
+map_from_gdb_tid (lwpid_t gdb_tid)
+{
+ thread_info *p;
+
+ /* First assume gdb_tid really is a tid, and try to find a
+ * matching entry on the threads list.
+ */
+ for (p = thread_head.head; p; p = p->next)
+ {
+ if (p->tid == gdb_tid)
+ return gdb_tid;
+ }
+
+ /* It doesn't appear to be a tid; perhaps it's really a pid?
+ * Try to find a "pseudo" thread entry on the threads list.
+ */
+ for (p = thread_head.head_pseudo; p != NULL; p = p->next_pseudo)
+ {
+ if (p->pid == gdb_tid)
+ return p->tid;
+ }
+
+ /* Perhaps it's the tid of a deleted thread we may still
+ * have some knowledge of?
+ */
+ for (p = deleted_threads.head; p; p = p->next)
+ {
+ if (p->tid == gdb_tid)
+ return gdb_tid;
+ }
+
+ /* Or perhaps it's the pid of a deleted process we may still
+ * have knowledge of?
+ */
+ for (p = deleted_threads.head_pseudo; p != NULL; p = p->next_pseudo)
+ {
+ if (p->pid == gdb_tid)
+ return p->tid;
+ }
+
+ return 0; /* Error? */
+}
+
+/* Map the other way: from a real tid to the
+ * "pid" known by core gdb. This tid may be
+ * for a thread that just got deleted, so we
+ * also need to consider deleted threads.
+ */
+static lwpid_t
+map_to_gdb_tid (lwpid_t real_tid)
+{
+ thread_info *p;
+
+ for (p = thread_head.head; p; p = p->next)
+ {
+ if (p->tid == real_tid)
+ {
+ if (p->am_pseudo)
+ return p->pid;
+ else
+ return real_tid;
+ }
+ }
+
+ for (p = deleted_threads.head; p; p = p->next)
+ {
+ if (p->tid == real_tid)
+ if (p->am_pseudo)
+ return p->pid; /* Error? */
+ else
+ return real_tid;
+ }
+
+ return 0; /* Error? Never heard of this thread! */
+}
+
+/* Do any threads have saved signals?
+ */
+static int
+saved_signals_exist (void)
+{
+ thread_info *p;
+
+ for (p = thread_head.head; p; p = p->next)
+ {
+ if (p->have_signal)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Is this the tid for the zero-th thread?
+ */
+static int
+is_pseudo_thread (lwpid_t tid)
+{
+ thread_info *p = find_thread_info (tid);
+ if (NULL == p || p->terminated)
+ return 0;
+ else
+ return p->am_pseudo;
+}
+
+/* Is this thread terminated?
+ */
+static int
+is_terminated (lwpid_t tid)
+{
+ thread_info *p = find_thread_info (tid);
+
+ if (NULL != p)
+ return p->terminated;
+
+ return 0;
+}
+
+/* Is this pid a real PID or a TID?
+ */
+static int
+is_process_id (int pid)
+{
+ lwpid_t tid;
+ thread_info *tinfo;
+ pid_t this_pid;
+ int this_pid_count;
+
+ /* What does PID really represent?
+ */
+ tid = map_from_gdb_tid (pid);
+ if (tid <= 0)
+ return 0; /* Actually, is probably an error... */
+
+ tinfo = find_thread_info (tid);
+
+ /* Does it appear to be a true thread?
+ */
+ if (!tinfo->am_pseudo)
+ return 0;
+
+ /* Else, it looks like it may be a process. See if there's any other
+ * threads with the same process ID, though. If there are, then TID
+ * just happens to be the first thread of several for this process.
+ */
+ this_pid = tinfo->pid;
+ this_pid_count = 0;
+ for (tinfo = thread_head.head; tinfo; tinfo = tinfo->next)
+ {
+ if (tinfo->pid == this_pid)
+ this_pid_count++;
+ }
+
+ return (this_pid_count == 1);
+}
+
+
+/* Add a thread to our info. Prevent duplicate entries.
+ */
+static thread_info *
+add_tthread (int pid, lwpid_t tid)
+{
+ thread_info *p;
+
+ p = find_thread_info (tid);
+ if (NULL == p)
+ p = create_thread_info (pid, tid);
+
+ return p;
+}
+
+/* Notice that a thread was deleted.
+ */
+static void
+del_tthread (lwpid_t tid)
+{
+ thread_info *p;
+ thread_info *chase;
+
+ if (thread_head.count <= 0)
+ {
+ error ("Internal error in thread database.");
+ return;
+ }
+
+ chase = NULL;
+ for (p = thread_head.head; p; p = p->next)
+ {
+ if (p->tid == tid)
+ {
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Delete here: %d \n", tid);
+#endif
+
+ if (p->am_pseudo)
+ {
+ /*
+ * Deleting a main thread is ok if we're doing
+ * a parent-follow on a child; this is odd but
+ * not wrong. It apparently _doesn't_ happen
+ * on the child-follow, as we don't just delete
+ * the pseudo while keeping the rest of the
+ * threads around--instead, we clear out the whole
+ * thread list at once.
+ */
+ thread_info *q;
+ thread_info *q_chase;
+
+ q_chase = NULL;
+ for (q = thread_head.head_pseudo; q; q = q->next)
+ {
+ if (q == p)
+ {
+ /* Remove from pseudo list.
+ */
+ if (q_chase == NULL)
+ thread_head.head_pseudo = p->next_pseudo;
+ else
+ q_chase->next = p->next_pseudo;
+ }
+ else
+ q_chase = q;
+ }
+ }
+
+ /* Remove from live list.
+ */
+ thread_head.count--;
+
+ if (NULL == chase)
+ thread_head.head = p->next;
+ else
+ chase->next = p->next;
+
+ /* Add to deleted thread list.
+ */
+ p->next = deleted_threads.head;
+ deleted_threads.head = p;
+ deleted_threads.count++;
+ if (p->am_pseudo)
+ {
+ p->next_pseudo = deleted_threads.head_pseudo;
+ deleted_threads.head_pseudo = p;
+ }
+ p->terminated = 1;
+
+ return;
+ }
+
+ else
+ chase = p;
+ }
+}
+
+/* Get the pid for this tid. (Has to be a real TID!).
+ */
+static int
+get_pid_for (lwpid_t tid)
+{
+ thread_info *p;
+
+ for (p = thread_head.head; p; p = p->next)
+ {
+ if (p->tid == tid)
+ {
+ return p->pid;
+ }
+ }
+
+ for (p = deleted_threads.head; p; p = p->next)
+ {
+ if (p->tid == tid)
+ {
+ return p->pid;
+ }
+ }
+
+ return 0;
+}
+
+/* Note that this thread's current event has been handled.
+ */
+static void
+set_handled (int pid, lwpid_t tid)
+{
+ thread_info *p;
+
+ p = find_thread_info (tid);
+ if (NULL == p)
+ p = add_tthread (pid, tid);
+
+ p->handled = 1;
+}
+
+/* Was this thread's current event handled?
+ */
+static int
+was_handled (lwpid_t tid)
+{
+ thread_info *p;
+
+ p = find_thread_info (tid);
+ if (NULL != p)
+ return p->handled;
+
+ return 0; /* New threads have not been handled */
+}
+
+/* Set this thread to unhandled.
+ */
+static void
+clear_handled (lwpid_t tid)
+{
+ thread_info *p;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("clear_handled %d\n", (int) tid);
+#endif
+
+ p = find_thread_info (tid);
+ if (p == NULL)
+ error ("Internal error: No thread state to clear?");
+
+ p->handled = 0;
+}
+
+/* Set all threads to unhandled.
+ */
+static void
+clear_all_handled (void)
+{
+ thread_info *p;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("clear_all_handled\n");
+#endif
+
+ for (p = thread_head.head; p; p = p->next)
+ {
+ p->handled = 0;
+ }
+
+ for (p = deleted_threads.head; p; p = p->next)
+ {
+ p->handled = 0;
+ }
+}
+
+/* Set this thread to default stepping mode.
+ */
+static void
+clear_stepping_mode (lwpid_t tid)
+{
+ thread_info *p;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("clear_stepping_mode %d\n", (int) tid);
+#endif
+
+ p = find_thread_info (tid);
+ if (p == NULL)
+ error ("Internal error: No thread state to clear?");
+
+ p->stepping_mode = DO_DEFAULT;
+}
+
+/* Set all threads to do default continue on resume.
+ */
+static void
+clear_all_stepping_mode (void)
+{
+ thread_info *p;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("clear_all_stepping_mode\n");
+#endif
+
+ for (p = thread_head.head; p; p = p->next)
+ {
+ p->stepping_mode = DO_DEFAULT;
+ }
+
+ for (p = deleted_threads.head; p; p = p->next)
+ {
+ p->stepping_mode = DO_DEFAULT;
+ }
+}
+
+/* Set all threads to unseen on this pass.
+ */
+static void
+set_all_unseen (void)
+{
+ thread_info *p;
+
+ for (p = thread_head.head; p; p = p->next)
+ {
+ p->seen = 0;
+ }
+}
+
+#if (defined( THREAD_DEBUG ) || defined( PARANOIA ))
+/* debugging routine.
+ */
+static void
+print_tthread (thread_info *p)
+{
+ printf (" Thread pid %d, tid %d", p->pid, p->tid);
+ if (p->have_state)
+ printf (", event is %s",
+ get_printable_name_of_ttrace_event (p->last_stop_state.tts_event));
+
+ if (p->am_pseudo)
+ printf (", pseudo thread");
+
+ if (p->have_signal)
+ printf (", have signal 0x%x", p->signal_value);
+
+ if (p->have_start)
+ printf (", have start at 0x%x", p->start);
+
+ printf (", step is %s", get_printable_name_of_stepping_mode (p->stepping_mode));
+
+ if (p->handled)
+ printf (", handled");
+ else
+ printf (", not handled");
+
+ if (p->seen)
+ printf (", seen");
+ else
+ printf (", not seen");
+
+ printf ("\n");
+}
+
+static void
+print_tthreads (void)
+{
+ thread_info *p;
+
+ if (thread_head.count == 0)
+ printf ("Thread list is empty\n");
+ else
+ {
+ printf ("Thread list has ");
+ if (thread_head.count == 1)
+ printf ("1 entry:\n");
+ else
+ printf ("%d entries:\n", thread_head.count);
+ for (p = thread_head.head; p; p = p->next)
+ {
+ print_tthread (p);
+ }
+ }
+
+ if (deleted_threads.count == 0)
+ printf ("Deleted thread list is empty\n");
+ else
+ {
+ printf ("Deleted thread list has ");
+ if (deleted_threads.count == 1)
+ printf ("1 entry:\n");
+ else
+ printf ("%d entries:\n", deleted_threads.count);
+
+ for (p = deleted_threads.head; p; p = p->next)
+ {
+ print_tthread (p);
+ }
+ }
+}
+#endif
+
+/* Update the thread list based on the "seen" bits.
+ */
+static void
+update_thread_list (void)
+{
+ thread_info *p;
+ thread_info *chase;
+
+ chase = NULL;
+ for (p = thread_head.head; p; p = p->next)
+ {
+ /* Is this an "unseen" thread which really happens to be a process?
+ If so, is it inferior_ptid and is a vfork in flight? If yes to
+ all, then DON'T REMOVE IT! We're in the midst of moving a vfork
+ operation, which is a multiple step thing, to the point where we
+ can touch the parent again. We've most likely stopped to examine
+ the child at a late stage in the vfork, and if we're not following
+ the child, we'd best not treat the parent as a dead "thread"...
+ */
+ if ((!p->seen) && p->am_pseudo && vfork_in_flight
+ && (p->pid != vforking_child_pid))
+ p->seen = 1;
+
+ if (!p->seen)
+ {
+ /* Remove this one
+ */
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Delete unseen thread: %d \n", p->tid);
+#endif
+ del_tthread (p->tid);
+ }
+ }
+}
+
+
+
+/************************************************
+ * O/S call wrappers *
+ ************************************************
+ */
+
+/* This function simply calls ttrace with the given arguments.
+ * It exists so that all calls to ttrace are isolated. All
+ * parameters should be as specified by "man 2 ttrace".
+ *
+ * No other "raw" calls to ttrace should exist in this module.
+ */
+static int
+call_real_ttrace (ttreq_t request, pid_t pid, lwpid_t tid, TTRACE_ARG_TYPE addr,
+ TTRACE_ARG_TYPE data, TTRACE_ARG_TYPE addr2)
+{
+ int tt_status;
+
+ errno = 0;
+ tt_status = ttrace (request, pid, tid, addr, data, addr2);
+
+#ifdef THREAD_DEBUG
+ if (errno)
+ {
+ /* Don't bother for a known benign error: if you ask for the
+ * first thread state, but there is only one thread and it's
+ * not stopped, ttrace complains.
+ *
+ * We have this inside the #ifdef because our caller will do
+ * this check for real.
+ */
+ if (request != TT_PROC_GET_FIRST_LWP_STATE
+ || errno != EPROTO)
+ {
+ if (debug_on)
+ printf ("TT fail for %s, with pid %d, tid %d, status %d \n",
+ get_printable_name_of_ttrace_request (request),
+ pid, tid, tt_status);
+ }
+ }
+#endif
+
+#if 0
+ /* ??rehrauer: It would probably be most robust to catch and report
+ * failed requests here. However, some clients of this interface
+ * seem to expect to catch & deal with them, so we'd best not.
+ */
+ if (errno)
+ {
+ strcpy (reason_for_failure, "ttrace (");
+ strcat (reason_for_failure, get_printable_name_of_ttrace_request (request));
+ strcat (reason_for_failure, ")");
+ printf ("ttrace error, errno = %d\n", errno);
+ perror_with_name (reason_for_failure);
+ }
+#endif
+
+ return tt_status;
+}
+
+
+/* This function simply calls ttrace_wait with the given arguments.
+ * It exists so that all calls to ttrace_wait are isolated.
+ *
+ * No "raw" calls to ttrace_wait should exist elsewhere.
+ */
+static int
+call_real_ttrace_wait (int pid, lwpid_t tid, ttwopt_t option, ttstate_t *tsp,
+ size_t tsp_size)
+{
+ int ttw_status;
+ thread_info *tinfo = NULL;
+
+ errno = 0;
+ ttw_status = ttrace_wait (pid, tid, option, tsp, tsp_size);
+
+ if (errno)
+ {
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("TW fail with pid %d, tid %d \n", pid, tid);
+#endif
+
+ perror_with_name ("ttrace wait");
+ }
+
+ return ttw_status;
+}
+
+
+/* A process may have one or more kernel threads, of which all or
+ none may be stopped. This function returns the ID of the first
+ kernel thread in a stopped state, or 0 if none are stopped.
+
+ This function can be used with get_process_next_stopped_thread_id
+ to iterate over the IDs of all stopped threads of this process.
+ */
+static lwpid_t
+get_process_first_stopped_thread_id (int pid, ttstate_t *thread_state)
+{
+ int tt_status;
+
+ tt_status = call_real_ttrace (TT_PROC_GET_FIRST_LWP_STATE,
+ (pid_t) pid,
+ (lwpid_t) TT_NIL,
+ (TTRACE_ARG_TYPE) thread_state,
+ (TTRACE_ARG_TYPE) sizeof (*thread_state),
+ TT_NIL);
+
+ if (errno)
+ {
+ if (errno == EPROTO)
+ {
+ /* This is an error we can handle: there isn't any stopped
+ * thread. This happens when we're re-starting the application
+ * and it has only one thread. GET_NEXT handles the case of
+ * no more stopped threads well; GET_FIRST doesn't. (A ttrace
+ * "feature".)
+ */
+ tt_status = 1;
+ errno = 0;
+ return 0;
+ }
+ else
+ perror_with_name ("ttrace");
+ }
+
+ if (tt_status < 0)
+ /* Failed somehow.
+ */
+ return 0;
+
+ return thread_state->tts_lwpid;
+}
+
+
+/* This function returns the ID of the "next" kernel thread in a
+ stopped state, or 0 if there are none. "Next" refers to the
+ thread following that of the last successful call to this
+ function or to get_process_first_stopped_thread_id, using
+ the value of thread_state returned by that call.
+
+ This function can be used with get_process_first_stopped_thread_id
+ to iterate over the IDs of all stopped threads of this process.
+ */
+static lwpid_t
+get_process_next_stopped_thread_id (int pid, ttstate_t *thread_state)
+{
+ int tt_status;
+
+ tt_status = call_real_ttrace (
+ TT_PROC_GET_NEXT_LWP_STATE,
+ (pid_t) pid,
+ (lwpid_t) TT_NIL,
+ (TTRACE_ARG_TYPE) thread_state,
+ (TTRACE_ARG_TYPE) sizeof (*thread_state),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+
+ if (tt_status < 0)
+ /* Failed
+ */
+ return 0;
+
+ else if (tt_status == 0)
+ {
+ /* End of list, no next state. Don't return the
+ * tts_lwpid, as it's a meaningless "240".
+ *
+ * This is an HPUX "feature".
+ */
+ return 0;
+ }
+
+ return thread_state->tts_lwpid;
+}
+
+/* ??rehrauer: Eventually this function perhaps should be calling
+ pid_to_thread_id. However, that function currently does nothing
+ for HP-UX. Even then, I'm not clear whether that function
+ will return a "kernel" thread ID, or a "user" thread ID. If
+ the former, we can just call it here. If the latter, we must
+ map from the "user" tid to a "kernel" tid.
+
+ NOTE: currently not called.
+ */
+static lwpid_t
+get_active_tid_of_pid (int pid)
+{
+ ttstate_t thread_state;
+
+ return get_process_first_stopped_thread_id (pid, &thread_state);
+}
+
+/* This function returns 1 if tt_request is a ttrace request that
+ * operates upon all threads of a (i.e., the entire) process.
+ */
+int
+is_process_ttrace_request (ttreq_t tt_request)
+{
+ return IS_TTRACE_PROCREQ (tt_request);
+}
+
+
+/* This function translates a thread ttrace request into
+ * the equivalent process request for a one-thread process.
+ */
+static ttreq_t
+make_process_version (ttreq_t request)
+{
+ if (!IS_TTRACE_REQ (request))
+ {
+ error ("Internal error, bad ttrace request made\n");
+ return -1;
+ }
+
+ switch (request)
+ {
+ case TT_LWP_STOP:
+ return TT_PROC_STOP;
+
+ case TT_LWP_CONTINUE:
+ return TT_PROC_CONTINUE;
+
+ case TT_LWP_GET_EVENT_MASK:
+ return TT_PROC_GET_EVENT_MASK;
+
+ case TT_LWP_SET_EVENT_MASK:
+ return TT_PROC_SET_EVENT_MASK;
+
+ case TT_LWP_SINGLE:
+ case TT_LWP_RUREGS:
+ case TT_LWP_WUREGS:
+ case TT_LWP_GET_STATE:
+ return -1; /* No equivalent */
+
+ default:
+ return request;
+ }
+}
+
+
+/* This function translates the "pid" used by the rest of
+ * gdb to a real pid and a tid. It then calls "call_real_ttrace"
+ * with the given arguments.
+ *
+ * In general, other parts of this module should call this
+ * function when they are dealing with external users, who only
+ * have tids to pass (but they call it "pid" for historical
+ * reasons).
+ */
+static int
+call_ttrace (ttreq_t request, int gdb_tid, TTRACE_ARG_TYPE addr,
+ TTRACE_ARG_TYPE data, TTRACE_ARG_TYPE addr2)
+{
+ lwpid_t real_tid;
+ int real_pid;
+ ttreq_t new_request;
+ int tt_status;
+ char reason_for_failure[100]; /* Arbitrary size, should be big enough. */
+
+#ifdef THREAD_DEBUG
+ int is_interesting = 0;
+
+ if (TT_LWP_RUREGS == request)
+ {
+ is_interesting = 1; /* Adjust code here as desired */
+ }
+
+ if (is_interesting && 0 && debug_on)
+ {
+ if (!is_process_ttrace_request (request))
+ {
+ printf ("TT: Thread request, tid is %d", gdb_tid);
+ printf ("== SINGLE at %x", addr);
+ }
+ else
+ {
+ printf ("TT: Process request, tid is %d\n", gdb_tid);
+ printf ("==! SINGLE at %x", addr);
+ }
+ }
+#endif
+
+ /* The initial SETTRC and SET_EVENT_MASK calls (and all others
+ * which happen before any threads get set up) should go
+ * directly to "call_real_ttrace", so they don't happen here.
+ *
+ * But hardware watchpoints do a SET_EVENT_MASK, so we can't
+ * rule them out....
+ */
+#ifdef THREAD_DEBUG
+ if (request == TT_PROC_SETTRC && debug_on)
+ printf ("Unexpected call for TT_PROC_SETTRC\n");
+#endif
+
+ /* Sometimes we get called with a bogus tid (e.g., if a
+ * thread has terminated, we return 0; inftarg later asks
+ * whether the thread has exited/forked/vforked).
+ */
+ if (gdb_tid == 0)
+ {
+ errno = ESRCH; /* ttrace's response would probably be "No such process". */
+ return -1;
+ }
+
+ /* All other cases should be able to expect that there are
+ * thread records.
+ */
+ if (!any_thread_records ())
+ {
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ warning ("No thread records for ttrace call");
+#endif
+ errno = ESRCH; /* ttrace's response would be "No such process". */
+ return -1;
+ }
+
+ /* OK, now the task is to translate the incoming tid into
+ * a pid/tid pair.
+ */
+ real_tid = map_from_gdb_tid (gdb_tid);
+ real_pid = get_pid_for (real_tid);
+
+ /* Now check the result. "Real_pid" is NULL if our list
+ * didn't find it. We have some tricks we can play to fix
+ * this, however.
+ */
+ if (0 == real_pid)
+ {
+ ttstate_t thread_state;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("No saved pid for tid %d\n", gdb_tid);
+#endif
+
+ if (is_process_ttrace_request (request))
+ {
+
+ /* Ok, we couldn't get a tid. Try to translate to
+ * the equivalent process operation. We expect this
+ * NOT to happen, so this is a desparation-type
+ * move. It can happen if there is an internal
+ * error and so no "wait()" call is ever done.
+ */
+ new_request = make_process_version (request);
+ if (new_request == -1)
+ {
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("...and couldn't make process version of thread operation\n");
+#endif
+
+ /* Use hacky saved pid, which won't always be correct
+ * in the multi-process future. Use tid as thread,
+ * probably dooming this to failure. FIX!
+ */
+ if (! ptid_equal (saved_real_ptid, null_ptid))
+ {
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("...using saved pid %d\n",
+ PIDGET (saved_real_ptid));
+#endif
+
+ real_pid = PIDGET (saved_real_ptid);
+ real_tid = gdb_tid;
+ }
+
+ else
+ error ("Unable to perform thread operation");
+ }
+
+ else
+ {
+ /* Sucessfully translated this to a process request,
+ * which needs no thread value.
+ */
+ real_pid = gdb_tid;
+ real_tid = 0;
+ request = new_request;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ {
+ printf ("Translated thread request to process request\n");
+ if (ptid_equal (saved_real_ptid, null_ptid))
+ printf ("...but there's no saved pid\n");
+
+ else
+ {
+ if (gdb_tid != PIDGET (saved_real_ptid))
+ printf ("...but have the wrong pid (%d rather than %d)\n",
+ gdb_tid, PIDGET (saved_real_ptid));
+ }
+ }
+#endif
+ } /* Translated to a process request */
+ } /* Is a process request */
+
+ else
+ {
+ /* We have to have a thread. Ooops.
+ */
+ error ("Thread request with no threads (%s)",
+ get_printable_name_of_ttrace_request (request));
+ }
+ }
+
+ /* Ttrace doesn't like to see tid values on process requests,
+ * even if we have the right one.
+ */
+ if (is_process_ttrace_request (request))
+ {
+ real_tid = 0;
+ }
+
+#ifdef THREAD_DEBUG
+ if (is_interesting && 0 && debug_on)
+ {
+ printf (" now tid %d, pid %d\n", real_tid, real_pid);
+ printf (" request is %s\n", get_printable_name_of_ttrace_request (request));
+ }
+#endif
+
+ /* Finally, the (almost) real call.
+ */
+ tt_status = call_real_ttrace (request, real_pid, real_tid, addr, data, addr2);
+
+#ifdef THREAD_DEBUG
+ if (is_interesting && debug_on)
+ {
+ if (!TT_OK (tt_status, errno)
+ && !(tt_status == 0 & errno == 0))
+ printf (" got error (errno==%d, status==%d)\n", errno, tt_status);
+ }
+#endif
+
+ return tt_status;
+}
+
+
+/* Stop all the threads of a process.
+
+ * NOTE: use of TT_PROC_STOP can cause a thread with a real event
+ * to get a TTEVT_NONE event, discarding the old event. Be
+ * very careful, and only call TT_PROC_STOP when you mean it!
+ */
+static void
+stop_all_threads_of_process (pid_t real_pid)
+{
+ int ttw_status;
+
+ ttw_status = call_real_ttrace (TT_PROC_STOP,
+ (pid_t) real_pid,
+ (lwpid_t) TT_NIL,
+ (TTRACE_ARG_TYPE) TT_NIL,
+ (TTRACE_ARG_TYPE) TT_NIL,
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace stop of other threads");
+}
+
+
+/* Under some circumstances, it's unsafe to attempt to stop, or even
+ query the state of, a process' threads.
+
+ In ttrace-based HP-UX, an example is a vforking child process. The
+ vforking parent and child are somewhat fragile, w/r/t what we can do
+ what we can do to them with ttrace, until after the child exits or
+ execs, or until the parent's vfork event is delivered. Until that
+ time, we must not try to stop the process' threads, or inquire how
+ many there are, or even alter its data segments, or it typically dies
+ with a SIGILL. Sigh.
+
+ This function returns 1 if this stopped process, and the event that
+ we're told was responsible for its current stopped state, cannot safely
+ have its threads examined.
+ */
+#define CHILD_VFORKED(evt,pid) \
+ (((evt) == TTEVT_VFORK) && ((pid) != PIDGET (inferior_ptid)))
+#define CHILD_URPED(evt,pid) \
+ ((((evt) == TTEVT_EXEC) || ((evt) == TTEVT_EXIT)) && ((pid) != vforking_child_pid))
+#define PARENT_VFORKED(evt,pid) \
+ (((evt) == TTEVT_VFORK) && ((pid) == PIDGET (inferior_ptid)))
+
+static int
+can_touch_threads_of_process (int pid, ttevents_t stopping_event)
+{
+ if (CHILD_VFORKED (stopping_event, pid))
+ {
+ vforking_child_pid = pid;
+ vfork_in_flight = 1;
+ }
+
+ else if (vfork_in_flight &&
+ (PARENT_VFORKED (stopping_event, pid) ||
+ CHILD_URPED (stopping_event, pid)))
+ {
+ vfork_in_flight = 0;
+ vforking_child_pid = 0;
+ }
+
+ return !vfork_in_flight;
+}
+
+
+/* If we can find an as-yet-unhandled thread state of a
+ * stopped thread of this process return 1 and set "tsp".
+ * Return 0 if we can't.
+ *
+ * If this function is used when the threads of PIS haven't
+ * been stopped, undefined behaviour is guaranteed!
+ */
+static int
+select_stopped_thread_of_process (int pid, ttstate_t *tsp)
+{
+ lwpid_t candidate_tid, tid;
+ ttstate_t candidate_tstate, tstate;
+
+ /* If we're not allowed to touch the process now, then just
+ * return the current value of *TSP.
+ *
+ * This supports "vfork". It's ok, really, to double the
+ * current event (the child EXEC, we hope!).
+ */
+ if (!can_touch_threads_of_process (pid, tsp->tts_event))
+ return 1;
+
+ /* Decide which of (possibly more than one) events to
+ * return as the first one. We scan them all so that
+ * we always return the result of a fake-step first.
+ */
+ candidate_tid = 0;
+ for (tid = get_process_first_stopped_thread_id (pid, &tstate);
+ tid != 0;
+ tid = get_process_next_stopped_thread_id (pid, &tstate))
+ {
+ /* TTEVT_NONE events are uninteresting to our clients. They're
+ * an artifact of our "stop the world" model--the thread is
+ * stopped because we stopped it.
+ */
+ if (tstate.tts_event == TTEVT_NONE)
+ {
+ set_handled (pid, tstate.tts_lwpid);
+ }
+
+ /* Did we just single-step a single thread, without letting any
+ * of the others run? Is this an event for that thread?
+ *
+ * If so, we believe our client would prefer to see this event
+ * over any others. (Typically the client wants to just push
+ * one thread a little farther forward, and then go around
+ * checking for what all threads are doing.)
+ */
+ else if (doing_fake_step && (tstate.tts_lwpid == fake_step_tid))
+ {
+#ifdef WAIT_BUFFER_DEBUG
+ /* It's possible here to see either a SIGTRAP (due to
+ * successful completion of a step) or a SYSCALL_ENTRY
+ * (due to a step completion with active hardware
+ * watchpoints).
+ */
+ if (debug_on)
+ printf ("Ending fake step with tid %d, state %s\n",
+ tstate.tts_lwpid,
+ get_printable_name_of_ttrace_event (tstate.tts_event));
+#endif
+
+ /* Remember this one, and throw away any previous
+ * candidate.
+ */
+ candidate_tid = tstate.tts_lwpid;
+ candidate_tstate = tstate;
+ }
+
+#ifdef FORGET_DELETED_BPTS
+
+ /* We can't just do this, as if we do, and then wind
+ * up the loop with no unhandled events, we need to
+ * handle that case--the appropriate reaction is to
+ * just continue, but there's no easy way to do that.
+ *
+ * Better to put this in the ttrace_wait call--if, when
+ * we fake a wait, we update our events based on the
+ * breakpoint_here_pc call and find there are no more events,
+ * then we better continue and so on.
+ *
+ * Or we could put it in the next/continue fake.
+ * But it has to go in the buffering code, not in the
+ * real go/wait code.
+ */
+ else if ((TTEVT_SIGNAL == tstate.tts_event)
+ && (5 == tstate.tts_u.tts_signal.tts_signo)
+ && (0 != get_raw_pc (tstate.tts_lwpid))
+ && !breakpoint_here_p (get_raw_pc (tstate.tts_lwpid)))
+ {
+ /*
+ * If the user deleted a breakpoint while this
+ * breakpoint-hit event was buffered, we can forget
+ * it now.
+ */
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Forgetting deleted bp hit for thread %d\n",
+ tstate.tts_lwpid);
+#endif
+
+ set_handled (pid, tstate.tts_lwpid);
+ }
+#endif
+
+ /* Else, is this the first "unhandled" event? If so,
+ * we believe our client wants to see it (if we don't
+ * see a fake-step later on in the scan).
+ */
+ else if (!was_handled (tstate.tts_lwpid) && candidate_tid == 0)
+ {
+ candidate_tid = tstate.tts_lwpid;
+ candidate_tstate = tstate;
+ }
+
+ /* This is either an event that has already been "handled",
+ * and thus we believe is uninteresting to our client, or we
+ * already have a candidate event. Ignore it...
+ */
+ }
+
+ /* What do we report?
+ */
+ if (doing_fake_step)
+ {
+ if (candidate_tid == fake_step_tid)
+ {
+ /* Fake step.
+ */
+ tstate = candidate_tstate;
+ }
+ else
+ {
+ warning ("Internal error: fake-step failed to complete.");
+ return 0;
+ }
+ }
+ else if (candidate_tid != 0)
+ {
+ /* Found a candidate unhandled event.
+ */
+ tstate = candidate_tstate;
+ }
+ else if (tid != 0)
+ {
+ warning ("Internal error in call of ttrace_wait.");
+ return 0;
+ }
+ else
+ {
+ warning ("Internal error: no unhandled thread event to select");
+ return 0;
+ }
+
+ copy_ttstate_t (tsp, &tstate);
+ return 1;
+} /* End of select_stopped_thread_of_process */
+
+#ifdef PARANOIA
+/* Check our internal thread data against the real thing.
+ */
+static void
+check_thread_consistency (pid_t real_pid)
+{
+ int tid; /* really lwpid_t */
+ ttstate_t tstate;
+ thread_info *p;
+
+ /* Spin down the O/S list of threads, checking that they
+ * match what we've got.
+ */
+ for (tid = get_process_first_stopped_thread_id (real_pid, &tstate);
+ tid != 0;
+ tid = get_process_next_stopped_thread_id (real_pid, &tstate))
+ {
+
+ p = find_thread_info (tid);
+
+ if (NULL == p)
+ {
+ warning ("No internal thread data for thread %d.", tid);
+ continue;
+ }
+
+ if (!p->seen)
+ {
+ warning ("Inconsistent internal thread data for thread %d.", tid);
+ }
+
+ if (p->terminated)
+ {
+ warning ("Thread %d is not terminated, internal error.", tid);
+ continue;
+ }
+
+
+#define TT_COMPARE( fld ) \
+ tstate.fld != p->last_stop_state.fld
+
+ if (p->have_state)
+ {
+ if (TT_COMPARE (tts_pid)
+ || TT_COMPARE (tts_lwpid)
+ || TT_COMPARE (tts_user_tid)
+ || TT_COMPARE (tts_event)
+ || TT_COMPARE (tts_flags)
+ || TT_COMPARE (tts_scno)
+ || TT_COMPARE (tts_scnargs))
+ {
+ warning ("Internal thread data for thread %d is wrong.", tid);
+ continue;
+ }
+ }
+ }
+}
+#endif /* PARANOIA */
+
+
+/* This function wraps calls to "call_real_ttrace_wait" so
+ * that a actual wait is only done when all pending events
+ * have been reported.
+ *
+ * Note that typically it is called with a pid of "0", i.e.
+ * the "don't care" value.
+ *
+ * Return value is the status of the pseudo wait.
+ */
+static int
+call_ttrace_wait (int pid, ttwopt_t option, ttstate_t *tsp, size_t tsp_size)
+{
+ /* This holds the actual, for-real, true process ID.
+ */
+ static int real_pid;
+
+ /* As an argument to ttrace_wait, zero pid
+ * means "Any process", and zero tid means
+ * "Any thread of the specified process".
+ */
+ int wait_pid = 0;
+ lwpid_t wait_tid = 0;
+ lwpid_t real_tid;
+
+ int ttw_status = 0; /* To be returned */
+
+ thread_info *tinfo = NULL;
+
+ if (pid != 0)
+ {
+ /* Unexpected case.
+ */
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("TW: Pid to wait on is %d\n", pid);
+#endif
+
+ if (!any_thread_records ())
+ error ("No thread records for ttrace call w. specific pid");
+
+ /* OK, now the task is to translate the incoming tid into
+ * a pid/tid pair.
+ */
+ real_tid = map_from_gdb_tid (pid);
+ real_pid = get_pid_for (real_tid);
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("==TW: real pid %d, real tid %d\n", real_pid, real_tid);
+#endif
+ }
+
+
+ /* Sanity checks and set-up.
+ * Process State
+ *
+ * Stopped Running Fake-step (v)Fork
+ * \________________________________________
+ * |
+ * No buffered events | error wait wait wait
+ * |
+ * Buffered events | debuffer error wait debuffer (?)
+ *
+ */
+ if (more_events_left == 0)
+ {
+
+ if (process_state == RUNNING)
+ {
+ /* OK--normal call of ttrace_wait with no buffered events.
+ */
+ ;
+ }
+ else if (process_state == FAKE_STEPPING)
+ {
+ /* Ok--call of ttrace_wait to support
+ * fake stepping with no buffered events.
+ *
+ * But we better be fake-stepping!
+ */
+ if (!doing_fake_step)
+ {
+ warning ("Inconsistent thread state.");
+ }
+ }
+ else if ((process_state == FORKING)
+ || (process_state == VFORKING))
+ {
+ /* Ok--there are two processes, so waiting
+ * for the second while the first is stopped
+ * is ok. Handled bits stay as they were.
+ */
+ ;
+ }
+ else if (process_state == STOPPED)
+ {
+ warning ("Process not running at wait call.");
+ }
+ else
+ /* No known state.
+ */
+ warning ("Inconsistent process state.");
+ }
+
+ else
+ {
+ /* More events left
+ */
+ if (process_state == STOPPED)
+ {
+ /* OK--buffered events being unbuffered.
+ */
+ ;
+ }
+ else if (process_state == RUNNING)
+ {
+ /* An error--shouldn't have buffered events
+ * when running.
+ */
+ warning ("Trying to continue with buffered events:");
+ }
+ else if (process_state == FAKE_STEPPING)
+ {
+ /*
+ * Better be fake-stepping!
+ */
+ if (!doing_fake_step)
+ {
+ warning ("Losing buffered thread events!\n");
+ }
+ }
+ else if ((process_state == FORKING)
+ || (process_state == VFORKING))
+ {
+ /* Ok--there are two processes, so waiting
+ * for the second while the first is stopped
+ * is ok. Handled bits stay as they were.
+ */
+ ;
+ }
+ else
+ warning ("Process in unknown state with buffered events.");
+ }
+
+ /* Sometimes we have to wait for a particular thread
+ * (if we're stepping over a bpt). In that case, we
+ * _know_ it's going to complete the single-step we
+ * asked for (because we're only doing the step under
+ * certain very well-understood circumstances), so it
+ * can't block.
+ */
+ if (doing_fake_step)
+ {
+ wait_tid = fake_step_tid;
+ wait_pid = get_pid_for (fake_step_tid);
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Doing a wait after a fake-step for %d, pid %d\n",
+ wait_tid, wait_pid);
+#endif
+ }
+
+ if (more_events_left == 0 /* No buffered events, need real ones. */
+ || process_state != STOPPED)
+ {
+ /* If there are no buffered events, and so we need
+ * real ones, or if we are FORKING, VFORKING,
+ * FAKE_STEPPING or RUNNING, and thus have to do
+ * a real wait, then do a real wait.
+ */
+
+#ifdef WAIT_BUFFER_DEBUG
+ /* Normal case... */
+ if (debug_on)
+ printf ("TW: do it for real; pid %d, tid %d\n", wait_pid, wait_tid);
+#endif
+
+ /* The actual wait call.
+ */
+ ttw_status = call_real_ttrace_wait (wait_pid, wait_tid, option, tsp, tsp_size);
+
+ /* Note that the routines we'll call will be using "call_real_ttrace",
+ * not "call_ttrace", and thus need the real pid rather than the pseudo-tid
+ * the rest of the world uses (which is actually the tid).
+ */
+ real_pid = tsp->tts_pid;
+
+ /* For most events: Stop the world!
+
+ * It's sometimes not safe to stop all threads of a process.
+ * Sometimes it's not even safe to ask for the thread state
+ * of a process!
+ */
+ if (can_touch_threads_of_process (real_pid, tsp->tts_event))
+ {
+ /* If we're really only stepping a single thread, then don't
+ * try to stop all the others -- we only do this single-stepping
+ * business when all others were already stopped...and the stop
+ * would mess up other threads' events.
+ *
+ * Similiarly, if there are other threads with events,
+ * don't do the stop.
+ */
+ if (!doing_fake_step)
+ {
+ if (more_events_left > 0)
+ warning ("Internal error in stopping process");
+
+ stop_all_threads_of_process (real_pid);
+
+ /* At this point, we could scan and update_thread_list(),
+ * and only use the local list for the rest of the
+ * module! We'd get rid of the scans in the various
+ * continue routines (adding one in attach). It'd
+ * be great--UPGRADE ME!
+ */
+ }
+ }
+
+#ifdef PARANOIA
+ else if (debug_on)
+ {
+ if (more_events_left > 0)
+ printf ("== Can't stop process; more events!\n");
+ else
+ printf ("== Can't stop process!\n");
+ }
+#endif
+
+ process_state = STOPPED;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Process set to STOPPED\n");
+#endif
+ }
+
+ else
+ {
+ /* Fake a call to ttrace_wait. The process must be
+ * STOPPED, as we aren't going to do any wait.
+ */
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("TW: fake it\n");
+#endif
+
+ if (process_state != STOPPED)
+ {
+ warning ("Process not stopped at wait call, in state '%s'.\n",
+ get_printable_name_of_process_state (process_state));
+ }
+
+ if (doing_fake_step)
+ error ("Internal error in stepping over breakpoint");
+
+ ttw_status = 0; /* Faking it is always successful! */
+ } /* End of fake or not? if */
+
+ /* Pick an event to pass to our caller. Be paranoid.
+ */
+ if (!select_stopped_thread_of_process (real_pid, tsp))
+ warning ("Can't find event, using previous event.");
+
+ else if (tsp->tts_event == TTEVT_NONE)
+ warning ("Internal error: no thread has a real event.");
+
+ else if (doing_fake_step)
+ {
+ if (fake_step_tid != tsp->tts_lwpid)
+ warning ("Internal error in stepping over breakpoint.");
+
+ /* This wait clears the (current) fake-step if there was one.
+ */
+ doing_fake_step = 0;
+ fake_step_tid = 0;
+ }
+
+ /* We now have a correct tsp and ttw_status for the thread
+ * which we want to report. So it's "handled"! This call
+ * will add it to our list if it's not there already.
+ */
+ set_handled (real_pid, tsp->tts_lwpid);
+
+ /* Save a copy of the ttrace state of this thread, in our local
+ thread descriptor.
+
+ This caches the state. The implementation of queries like
+ hpux_has_execd can then use this cached state, rather than
+ be forced to make an explicit ttrace call to get it.
+
+ (Guard against the condition that this is the first time we've
+ waited on, i.e., seen this thread, and so haven't yet entered
+ it into our list of threads.)
+ */
+ tinfo = find_thread_info (tsp->tts_lwpid);
+ if (tinfo != NULL)
+ {
+ copy_ttstate_t (&tinfo->last_stop_state, tsp);
+ tinfo->have_state = 1;
+ }
+
+ return ttw_status;
+} /* call_ttrace_wait */
+
+#if defined(CHILD_REPORTED_EXEC_EVENTS_PER_EXEC_CALL)
+int
+child_reported_exec_events_per_exec_call (void)
+{
+ return 1; /* ttrace reports the event once per call. */
+}
+#endif
+
+
+
+/* Our implementation of hardware watchpoints involves making memory
+ pages write-protected. We must remember a page's original permissions,
+ and we must also know when it is appropriate to restore a page's
+ permissions to its original state.
+
+ We use a "dictionary" of hardware-watched pages to do this. Each
+ hardware-watched page is recorded in the dictionary. Each page's
+ dictionary entry contains the original permissions and a reference
+ count. Pages are hashed into the dictionary by their start address.
+
+ When hardware watchpoint is set on page X for the first time, page X
+ is added to the dictionary with a reference count of 1. If other
+ hardware watchpoints are subsequently set on page X, its reference
+ count is incremented. When hardware watchpoints are removed from
+ page X, its reference count is decremented. If a page's reference
+ count drops to 0, it's permissions are restored and the page's entry
+ is thrown out of the dictionary.
+ */
+typedef struct memory_page
+{
+ CORE_ADDR page_start;
+ int reference_count;
+ int original_permissions;
+ struct memory_page *next;
+ struct memory_page *previous;
+}
+memory_page_t;
+
+#define MEMORY_PAGE_DICTIONARY_BUCKET_COUNT 128
+
+static struct
+ {
+ LONGEST page_count;
+ int page_size;
+ int page_protections_allowed;
+ /* These are just the heads of chains of actual page descriptors. */
+ memory_page_t buckets[MEMORY_PAGE_DICTIONARY_BUCKET_COUNT];
+ }
+memory_page_dictionary;
+
+
+static void
+require_memory_page_dictionary (void)
+{
+ int i;
+
+ /* Is the memory page dictionary ready for use? If so, we're done. */
+ if (memory_page_dictionary.page_count >= (LONGEST) 0)
+ return;
+
+ /* Else, initialize it. */
+ memory_page_dictionary.page_count = (LONGEST) 0;
+
+ for (i = 0; i < MEMORY_PAGE_DICTIONARY_BUCKET_COUNT; i++)
+ {
+ memory_page_dictionary.buckets[i].page_start = (CORE_ADDR) 0;
+ memory_page_dictionary.buckets[i].reference_count = 0;
+ memory_page_dictionary.buckets[i].next = NULL;
+ memory_page_dictionary.buckets[i].previous = NULL;
+ }
+}
+
+
+static void
+retire_memory_page_dictionary (void)
+{
+ memory_page_dictionary.page_count = (LONGEST) - 1;
+}
+
+
+/* Write-protect the memory page that starts at this address.
+
+ Returns the original permissions of the page.
+ */
+static int
+write_protect_page (int pid, CORE_ADDR page_start)
+{
+ int tt_status;
+ int original_permissions;
+ int new_permissions;
+
+ tt_status = call_ttrace (TT_PROC_GET_MPROTECT,
+ pid,
+ (TTRACE_ARG_TYPE) page_start,
+ TT_NIL,
+ (TTRACE_ARG_TYPE) & original_permissions);
+ if (errno || (tt_status < 0))
+ {
+ return 0; /* What else can we do? */
+ }
+
+ /* We'll also write-protect the page now, if that's allowed. */
+ if (memory_page_dictionary.page_protections_allowed)
+ {
+ new_permissions = original_permissions & ~PROT_WRITE;
+ tt_status = call_ttrace (TT_PROC_SET_MPROTECT,
+ pid,
+ (TTRACE_ARG_TYPE) page_start,
+ (TTRACE_ARG_TYPE) memory_page_dictionary.page_size,
+ (TTRACE_ARG_TYPE) new_permissions);
+ if (errno || (tt_status < 0))
+ {
+ return 0; /* What else can we do? */
+ }
+ }
+
+ return original_permissions;
+}
+
+
+/* Unwrite-protect the memory page that starts at this address, restoring
+ (what we must assume are) its original permissions.
+ */
+static void
+unwrite_protect_page (int pid, CORE_ADDR page_start, int original_permissions)
+{
+ int tt_status;
+
+ tt_status = call_ttrace (TT_PROC_SET_MPROTECT,
+ pid,
+ (TTRACE_ARG_TYPE) page_start,
+ (TTRACE_ARG_TYPE) memory_page_dictionary.page_size,
+ (TTRACE_ARG_TYPE) original_permissions);
+ if (errno || (tt_status < 0))
+ {
+ return; /* What else can we do? */
+ }
+}
+
+
+/* Memory page-protections are used to implement "hardware" watchpoints
+ on HP-UX.
+
+ For every memory page that is currently being watched (i.e., that
+ presently should be write-protected), write-protect it.
+ */
+void
+hppa_enable_page_protection_events (int pid)
+{
+ int bucket;
+
+ memory_page_dictionary.page_protections_allowed = 1;
+
+ for (bucket = 0; bucket < MEMORY_PAGE_DICTIONARY_BUCKET_COUNT; bucket++)
+ {
+ memory_page_t *page;
+
+ page = memory_page_dictionary.buckets[bucket].next;
+ while (page != NULL)
+ {
+ page->original_permissions = write_protect_page (pid, page->page_start);
+ page = page->next;
+ }
+ }
+}
+
+
+/* Memory page-protections are used to implement "hardware" watchpoints
+ on HP-UX.
+
+ For every memory page that is currently being watched (i.e., that
+ presently is or should be write-protected), un-write-protect it.
+ */
+void
+hppa_disable_page_protection_events (int pid)
+{
+ int bucket;
+
+ for (bucket = 0; bucket < MEMORY_PAGE_DICTIONARY_BUCKET_COUNT; bucket++)
+ {
+ memory_page_t *page;
+
+ page = memory_page_dictionary.buckets[bucket].next;
+ while (page != NULL)
+ {
+ unwrite_protect_page (pid, page->page_start, page->original_permissions);
+ page = page->next;
+ }
+ }
+
+ memory_page_dictionary.page_protections_allowed = 0;
+}
+
+/* Count the number of outstanding events. At this
+ * point, we have selected one thread and its event
+ * as the one to be "reported" upwards to core gdb.
+ * That thread is already marked as "handled".
+ *
+ * Note: we could just scan our own thread list. FIXME!
+ */
+static int
+count_unhandled_events (int real_pid, lwpid_t real_tid)
+{
+ ttstate_t tstate;
+ lwpid_t ttid;
+ int events_left;
+
+ /* Ok, find out how many threads have real events to report.
+ */
+ events_left = 0;
+ ttid = get_process_first_stopped_thread_id (real_pid, &tstate);
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ {
+ if (ttid == 0)
+ printf ("Process %d has no threads\n", real_pid);
+ else
+ printf ("Process %d has these threads:\n", real_pid);
+ }
+#endif
+
+ while (ttid > 0)
+ {
+ if (tstate.tts_event != TTEVT_NONE
+ && !was_handled (ttid))
+ {
+ /* TTEVT_NONE implies we just stopped it ourselves
+ * because we're the stop-the-world guys, so it's
+ * not an event from our point of view.
+ *
+ * If "was_handled" is true, this is an event we
+ * already handled, so don't count it.
+ *
+ * Note that we don't count the thread with the
+ * currently-reported event, as it's already marked
+ * as handled.
+ */
+ events_left++;
+ }
+
+#if defined( THREAD_DEBUG ) || defined( WAIT_BUFFER_DEBUG )
+ if (debug_on)
+ {
+ if (ttid == real_tid)
+ printf ("*"); /* Thread we're reporting */
+ else
+ printf (" ");
+
+ if (tstate.tts_event != TTEVT_NONE)
+ printf ("+"); /* Thread with a real event */
+ else
+ printf (" ");
+
+ if (was_handled (ttid))
+ printf ("h"); /* Thread has been handled */
+ else
+ printf (" ");
+
+ printf (" %d, with event %s", ttid,
+ get_printable_name_of_ttrace_event (tstate.tts_event));
+
+ if (tstate.tts_event == TTEVT_SIGNAL
+ && 5 == tstate.tts_u.tts_signal.tts_signo)
+ {
+ CORE_ADDR pc_val;
+
+ pc_val = get_raw_pc (ttid);
+
+ if (pc_val > 0)
+ printf (" breakpoint at 0x%x\n", pc_val);
+ else
+ printf (" bpt, can't fetch pc.\n");
+ }
+ else
+ printf ("\n");
+ }
+#endif
+
+ ttid = get_process_next_stopped_thread_id (real_pid, &tstate);
+ }
+
+#if defined( THREAD_DEBUG ) || defined( WAIT_BUFFER_DEBUG )
+ if (debug_on)
+ if (events_left > 0)
+ printf ("There are thus %d pending events\n", events_left);
+#endif
+
+ return events_left;
+}
+
+/* This function is provided as a sop to clients that are calling
+ * ptrace_wait to wait for a process to stop. (see the
+ * implementation of child_wait.) Return value is the pid for
+ * the event that ended the wait.
+ *
+ * Note: used by core gdb and so uses the pseudo-pid (really tid).
+ */
+int
+ptrace_wait (ptid_t ptid, int *status)
+{
+ ttstate_t tsp;
+ int ttwait_return;
+ int real_pid;
+ ttstate_t state;
+ lwpid_t real_tid;
+ int return_pid;
+
+ /* The ptrace implementation of this also ignores pid.
+ */
+ *status = 0;
+
+ ttwait_return = call_ttrace_wait (0, TTRACE_WAITOK, &tsp, sizeof (tsp));
+ if (ttwait_return < 0)
+ {
+ /* ??rehrauer: It appears that if our inferior exits and we
+ haven't asked for exit events, that we're not getting any
+ indication save a negative return from ttrace_wait and an
+ errno set to ESRCH?
+ */
+ if (errno == ESRCH)
+ {
+ *status = 0; /* WIFEXITED */
+ return PIDGET (inferior_ptid);
+ }
+
+ warning ("Call of ttrace_wait returned with errno %d.",
+ errno);
+ *status = ttwait_return;
+ return PIDGET (inferior_ptid);
+ }
+
+ real_pid = tsp.tts_pid;
+ real_tid = tsp.tts_lwpid;
+
+ /* One complication is that the "tts_event" structure has
+ * a set of flags, and more than one can be set. So we
+ * either have to force an order (as we do here), or handle
+ * more than one flag at a time.
+ */
+ if (tsp.tts_event & TTEVT_LWP_CREATE)
+ {
+
+ /* Unlike what you might expect, this event is reported in
+ * the _creating_ thread, and the _created_ thread (whose tid
+ * we have) is still running. So we have to stop it. This
+ * has already been done in "call_ttrace_wait", but should we
+ * ever abandon the "stop-the-world" model, here's the command
+ * to use:
+ *
+ * call_ttrace( TT_LWP_STOP, real_tid, TT_NIL, TT_NIL, TT_NIL );
+ *
+ * Note that this would depend on being called _after_ "add_tthread"
+ * below for the tid-to-pid translation to be done in "call_ttrace".
+ */
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("New thread: pid %d, tid %d, creator tid %d\n",
+ real_pid, tsp.tts_u.tts_thread.tts_target_lwpid,
+ real_tid);
+#endif
+
+ /* Now we have to return the tid of the created thread, not
+ * the creating thread, or "wait_for_inferior" won't know we
+ * have a new "process" (thread). Plus we should record it
+ * right, too.
+ */
+ real_tid = tsp.tts_u.tts_thread.tts_target_lwpid;
+
+ add_tthread (real_pid, real_tid);
+ }
+
+ else if ((tsp.tts_event & TTEVT_LWP_TERMINATE)
+ || (tsp.tts_event & TTEVT_LWP_EXIT))
+ {
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Thread dies: %d\n", real_tid);
+#endif
+
+ del_tthread (real_tid);
+ }
+
+ else if (tsp.tts_event & TTEVT_EXEC)
+ {
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Pid %d has zero'th thread %d; inferior pid is %d\n",
+ real_pid, real_tid, PIDGET (inferior_ptid));
+#endif
+
+ add_tthread (real_pid, real_tid);
+ }
+
+#ifdef THREAD_DEBUG
+ else if (debug_on)
+ {
+ printf ("Process-level event %s, using tid %d\n",
+ get_printable_name_of_ttrace_event (tsp.tts_event),
+ real_tid);
+
+ /* OK to do this, as "add_tthread" won't add
+ * duplicate entries. Also OK not to do it,
+ * as this event isn't one which can change the
+ * thread state.
+ */
+ add_tthread (real_pid, real_tid);
+ }
+#endif
+
+
+ /* How many events are left to report later?
+ * In a non-stop-the-world model, this isn't needed.
+ *
+ * Note that it's not always safe to query the thread state of a process,
+ * which is what count_unhandled_events does. (If unsafe, we're left with
+ * no other resort than to assume that no more events remain...)
+ */
+ if (can_touch_threads_of_process (real_pid, tsp.tts_event))
+ more_events_left = count_unhandled_events (real_pid, real_tid);
+
+ else
+ {
+ if (more_events_left > 0)
+ warning ("Vfork or fork causing loss of %d buffered events.",
+ more_events_left);
+
+ more_events_left = 0;
+ }
+
+ /* Attempt to translate the ttrace_wait-returned status into the
+ ptrace equivalent.
+
+ ??rehrauer: This is somewhat fragile. We really ought to rewrite
+ clients that expect to pick apart a ptrace wait status, to use
+ something a little more abstract.
+ */
+ if ((tsp.tts_event & TTEVT_EXEC)
+ || (tsp.tts_event & TTEVT_FORK)
+ || (tsp.tts_event & TTEVT_VFORK))
+ {
+ /* Forks come in pairs (parent and child), so core gdb
+ * will do two waits. Be ready to notice this.
+ */
+ if (tsp.tts_event & TTEVT_FORK)
+ {
+ process_state = FORKING;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Process set to FORKING\n");
+#endif
+ }
+ else if (tsp.tts_event & TTEVT_VFORK)
+ {
+ process_state = VFORKING;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Process set to VFORKING\n");
+#endif
+ }
+
+ /* Make an exec or fork look like a breakpoint. Definitely a hack,
+ but I don't think non HP-UX-specific clients really carefully
+ inspect the first events they get after inferior startup, so
+ it probably almost doesn't matter what we claim this is.
+ */
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("..a process 'event'\n");
+#endif
+
+ /* Also make fork and exec events look like bpts, so they can be caught.
+ */
+ *status = 0177 | (_SIGTRAP << 8);
+ }
+
+ /* Special-cases: We ask for syscall entry and exit events to implement
+ "fast" (aka "hardware") watchpoints.
+
+ When we get a syscall entry, we want to disable page-protections,
+ and resume the inferior; this isn't an event we wish for
+ wait_for_inferior to see. Note that we must resume ONLY the
+ thread that reported the syscall entry; we don't want to allow
+ other threads to run with the page protections off, as they might
+ then be able to write to watch memory without it being caught.
+
+ When we get a syscall exit, we want to reenable page-protections,
+ but we don't want to resume the inferior; this is an event we wish
+ wait_for_inferior to see. Make it look like the signal we normally
+ get for a single-step completion. This should cause wait_for_inferior
+ to evaluate whether any watchpoint triggered.
+
+ Or rather, that's what we'd LIKE to do for syscall exit; we can't,
+ due to some HP-UX "features". Some syscalls have problems with
+ write-protections on some pages, and some syscalls seem to have
+ pending writes to those pages at the time we're getting the return
+ event. So, we'll single-step the inferior to get out of the syscall,
+ and then reenable protections.
+
+ Note that we're intentionally allowing the syscall exit case to
+ fall through into the succeeding cases, as sometimes we single-
+ step out of one syscall only to immediately enter another...
+ */
+ else if ((tsp.tts_event & TTEVT_SYSCALL_ENTRY)
+ || (tsp.tts_event & TTEVT_SYSCALL_RETURN))
+ {
+ /* Make a syscall event look like a breakpoint. Same comments
+ as for exec & fork events.
+ */
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("..a syscall 'event'\n");
+#endif
+
+ /* Also make syscall events look like bpts, so they can be caught.
+ */
+ *status = 0177 | (_SIGTRAP << 8);
+ }
+
+ else if ((tsp.tts_event & TTEVT_LWP_CREATE)
+ || (tsp.tts_event & TTEVT_LWP_TERMINATE)
+ || (tsp.tts_event & TTEVT_LWP_EXIT))
+ {
+ /* Make a thread event look like a breakpoint. Same comments
+ * as for exec & fork events.
+ */
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("..a thread 'event'\n");
+#endif
+
+ /* Also make thread events look like bpts, so they can be caught.
+ */
+ *status = 0177 | (_SIGTRAP << 8);
+ }
+
+ else if ((tsp.tts_event & TTEVT_EXIT))
+ { /* WIFEXITED */
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("..an exit\n");
+#endif
+
+ /* Prevent rest of gdb from thinking this is
+ * a new thread if for some reason it's never
+ * seen the main thread before.
+ */
+ inferior_ptid = pid_to_ptid (map_to_gdb_tid (real_tid)); /* HACK, FIX */
+
+ *status = 0 | (tsp.tts_u.tts_exit.tts_exitcode);
+ }
+
+ else if (tsp.tts_event & TTEVT_SIGNAL)
+ { /* WIFSTOPPED */
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("..a signal, %d\n", tsp.tts_u.tts_signal.tts_signo);
+#endif
+
+ *status = 0177 | (tsp.tts_u.tts_signal.tts_signo << 8);
+ }
+
+ else
+ { /* !WIFSTOPPED */
+
+ /* This means the process or thread terminated. But we should've
+ caught an explicit exit/termination above. So warn (this is
+ really an internal error) and claim the process or thread
+ terminated with a SIGTRAP.
+ */
+
+ warning ("process_wait: unknown process state");
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Process-level event %s, using tid %d\n",
+ get_printable_name_of_ttrace_event (tsp.tts_event),
+ real_tid);
+#endif
+
+ *status = _SIGTRAP;
+ }
+
+ target_post_wait (pid_to_ptid (tsp.tts_pid), *status);
+
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Done waiting, pid is %d, tid %d\n", real_pid, real_tid);
+#endif
+
+ /* All code external to this module uses the tid, but calls
+ * it "pid". There's some tweaking so that the outside sees
+ * the first thread as having the same number as the starting
+ * pid.
+ */
+ return_pid = map_to_gdb_tid (real_tid);
+
+ if (real_tid == 0 || return_pid == 0)
+ {
+ warning ("Internal error: process-wait failed.");
+ }
+
+ return return_pid;
+}
+
+
+/* This function causes the caller's process to be traced by its
+ parent. This is intended to be called after GDB forks itself,
+ and before the child execs the target. Despite the name, it
+ is called by the child.
+
+ Note that HP-UX ttrace is rather funky in how this is done.
+ If the parent wants to get the initial exec event of a child,
+ it must set the ttrace event mask of the child to include execs.
+ (The child cannot do this itself.) This must be done after the
+ child is forked, but before it execs.
+
+ To coordinate the parent and child, we implement a semaphore using
+ pipes. After SETTRC'ing itself, the child tells the parent that
+ it is now traceable by the parent, and waits for the parent's
+ acknowledgement. The parent can then set the child's event mask,
+ and notify the child that it can now exec.
+
+ (The acknowledgement by parent happens as a result of a call to
+ child_acknowledge_created_inferior.)
+ */
+int
+parent_attach_all (int p1, PTRACE_ARG3_TYPE p2, int p3)
+{
+ int tt_status;
+
+ /* We need a memory home for a constant, to pass it to ttrace.
+ The value of the constant is arbitrary, so long as both
+ parent and child use the same value. Might as well use the
+ "magic" constant provided by ttrace...
+ */
+ uint64_t tc_magic_child = TT_VERSION;
+ uint64_t tc_magic_parent = 0;
+
+ tt_status = call_real_ttrace (
+ TT_PROC_SETTRC,
+ (int) TT_NIL,
+ (lwpid_t) TT_NIL,
+ TT_NIL,
+ (TTRACE_ARG_TYPE) TT_VERSION,
+ TT_NIL);
+
+ if (tt_status < 0)
+ return tt_status;
+
+ /* Notify the parent that we're potentially ready to exec(). */
+ write (startup_semaphore.child_channel[SEM_TALK],
+ &tc_magic_child,
+ sizeof (tc_magic_child));
+
+ /* Wait for acknowledgement from the parent. */
+ read (startup_semaphore.parent_channel[SEM_LISTEN],
+ &tc_magic_parent,
+ sizeof (tc_magic_parent));
+
+ if (tc_magic_child != tc_magic_parent)
+ warning ("mismatched semaphore magic");
+
+ /* Discard our copy of the semaphore. */
+ (void) close (startup_semaphore.parent_channel[SEM_LISTEN]);
+ (void) close (startup_semaphore.parent_channel[SEM_TALK]);
+ (void) close (startup_semaphore.child_channel[SEM_LISTEN]);
+ (void) close (startup_semaphore.child_channel[SEM_TALK]);
+
+ return tt_status;
+}
+
+/* Despite being file-local, this routine is dealing with
+ * actual process IDs, not thread ids. That's because it's
+ * called before the first "wait" call, and there's no map
+ * yet from tids to pids.
+ *
+ * When it is called, a forked child is running, but waiting on
+ * the semaphore. If you stop the child and re-start it,
+ * things get confused, so don't do that! An attached child is
+ * stopped.
+ *
+ * Since this is called after either attach or run, we
+ * have to be the common part of both.
+ */
+static void
+require_notification_of_events (int real_pid)
+{
+ int tt_status;
+ ttevent_t notifiable_events;
+
+ lwpid_t tid;
+ ttstate_t thread_state;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Require notif, pid is %d\n", real_pid);
+#endif
+
+ /* Temporary HACK: tell inftarg.c/child_wait to not
+ * loop until pids are the same.
+ */
+ not_same_real_pid = 0;
+
+ sigemptyset (&notifiable_events.tte_signals);
+ notifiable_events.tte_opts = TTEO_NONE;
+
+ /* This ensures that forked children inherit their parent's
+ * event mask, which we're setting here.
+ *
+ * NOTE: if you debug gdb with itself, then the ultimate
+ * debuggee gets flags set by the outermost gdb, as
+ * a child of a child will still inherit.
+ */
+ notifiable_events.tte_opts |= TTEO_PROC_INHERIT;
+
+ notifiable_events.tte_events = TTEVT_DEFAULT;
+ notifiable_events.tte_events |= TTEVT_SIGNAL;
+ notifiable_events.tte_events |= TTEVT_EXEC;
+ notifiable_events.tte_events |= TTEVT_EXIT;
+ notifiable_events.tte_events |= TTEVT_FORK;
+ notifiable_events.tte_events |= TTEVT_VFORK;
+ notifiable_events.tte_events |= TTEVT_LWP_CREATE;
+ notifiable_events.tte_events |= TTEVT_LWP_EXIT;
+ notifiable_events.tte_events |= TTEVT_LWP_TERMINATE;
+
+ tt_status = call_real_ttrace (
+ TT_PROC_SET_EVENT_MASK,
+ real_pid,
+ (lwpid_t) TT_NIL,
+ (TTRACE_ARG_TYPE) & notifiable_events,
+ (TTRACE_ARG_TYPE) sizeof (notifiable_events),
+ TT_NIL);
+}
+
+static void
+require_notification_of_exec_events (int real_pid)
+{
+ int tt_status;
+ ttevent_t notifiable_events;
+
+ lwpid_t tid;
+ ttstate_t thread_state;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Require notif, pid is %d\n", real_pid);
+#endif
+
+ /* Temporary HACK: tell inftarg.c/child_wait to not
+ * loop until pids are the same.
+ */
+ not_same_real_pid = 0;
+
+ sigemptyset (&notifiable_events.tte_signals);
+ notifiable_events.tte_opts = TTEO_NOSTRCCHLD;
+
+ /* This ensures that forked children don't inherit their parent's
+ * event mask, which we're setting here.
+ */
+ notifiable_events.tte_opts &= ~TTEO_PROC_INHERIT;
+
+ notifiable_events.tte_events = TTEVT_DEFAULT;
+ notifiable_events.tte_events |= TTEVT_EXEC;
+ notifiable_events.tte_events |= TTEVT_EXIT;
+
+ tt_status = call_real_ttrace (
+ TT_PROC_SET_EVENT_MASK,
+ real_pid,
+ (lwpid_t) TT_NIL,
+ (TTRACE_ARG_TYPE) & notifiable_events,
+ (TTRACE_ARG_TYPE) sizeof (notifiable_events),
+ TT_NIL);
+}
+
+
+/* This function is called by the parent process, with pid being the
+ * ID of the child process, after the debugger has forked.
+ */
+void
+child_acknowledge_created_inferior (int pid)
+{
+ /* We need a memory home for a constant, to pass it to ttrace.
+ The value of the constant is arbitrary, so long as both
+ parent and child use the same value. Might as well use the
+ "magic" constant provided by ttrace...
+ */
+ uint64_t tc_magic_parent = TT_VERSION;
+ uint64_t tc_magic_child = 0;
+
+ /* Wait for the child to tell us that it has forked. */
+ read (startup_semaphore.child_channel[SEM_LISTEN],
+ &tc_magic_child,
+ sizeof (tc_magic_child));
+
+ /* Clear thread info now. We'd like to do this in
+ * "require...", but that messes up attach.
+ */
+ clear_thread_info ();
+
+ /* Tell the "rest of gdb" that the initial thread exists.
+ * This isn't really a hack. Other thread-based versions
+ * of gdb (e.g. gnu-nat.c) seem to do the same thing.
+ *
+ * Q: Why don't we also add this thread to the local
+ * list via "add_tthread"?
+ *
+ * A: Because we don't know the tid, and can't stop the
+ * the process safely to ask what it is. Anyway, we'll
+ * add it when it gets the EXEC event.
+ */
+ add_thread (pid_to_ptid (pid)); /* in thread.c */
+
+ /* We can now set the child's ttrace event mask.
+ */
+ require_notification_of_exec_events (pid);
+
+ /* Tell ourselves that the process is running.
+ */
+ process_state = RUNNING;
+
+ /* Notify the child that it can exec. */
+ write (startup_semaphore.parent_channel[SEM_TALK],
+ &tc_magic_parent,
+ sizeof (tc_magic_parent));
+
+ /* Discard our copy of the semaphore. */
+ (void) close (startup_semaphore.parent_channel[SEM_LISTEN]);
+ (void) close (startup_semaphore.parent_channel[SEM_TALK]);
+ (void) close (startup_semaphore.child_channel[SEM_LISTEN]);
+ (void) close (startup_semaphore.child_channel[SEM_TALK]);
+}
+
+
+/*
+ * arrange for notification of all events by
+ * calling require_notification_of_events.
+ */
+void
+child_post_startup_inferior (ptid_t ptid)
+{
+ require_notification_of_events (PIDGET (ptid));
+}
+
+/* From here on, we should expect tids rather than pids.
+ */
+static void
+hppa_enable_catch_fork (int tid)
+{
+ int tt_status;
+ ttevent_t ttrace_events;
+
+ /* Get the set of events that are currently enabled.
+ */
+ tt_status = call_ttrace (TT_PROC_GET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+
+ /* Add forks to that set. */
+ ttrace_events.tte_events |= TTEVT_FORK;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("enable fork, tid is %d\n", tid);
+#endif
+
+ tt_status = call_ttrace (TT_PROC_SET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+}
+
+
+static void
+hppa_disable_catch_fork (int tid)
+{
+ int tt_status;
+ ttevent_t ttrace_events;
+
+ /* Get the set of events that are currently enabled.
+ */
+ tt_status = call_ttrace (TT_PROC_GET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+
+ /* Remove forks from that set. */
+ ttrace_events.tte_events &= ~TTEVT_FORK;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("disable fork, tid is %d\n", tid);
+#endif
+
+ tt_status = call_ttrace (TT_PROC_SET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+}
+
+
+#if defined(CHILD_INSERT_FORK_CATCHPOINT)
+int
+child_insert_fork_catchpoint (int tid)
+{
+ /* Enable reporting of fork events from the kernel. */
+ /* ??rehrauer: For the moment, we're always enabling these events,
+ and just ignoring them if there's no catchpoint to catch them.
+ */
+ return 0;
+}
+#endif
+
+
+#if defined(CHILD_REMOVE_FORK_CATCHPOINT)
+int
+child_remove_fork_catchpoint (int tid)
+{
+ /* Disable reporting of fork events from the kernel. */
+ /* ??rehrauer: For the moment, we're always enabling these events,
+ and just ignoring them if there's no catchpoint to catch them.
+ */
+ return 0;
+}
+#endif
+
+
+static void
+hppa_enable_catch_vfork (int tid)
+{
+ int tt_status;
+ ttevent_t ttrace_events;
+
+ /* Get the set of events that are currently enabled.
+ */
+ tt_status = call_ttrace (TT_PROC_GET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+
+ /* Add vforks to that set. */
+ ttrace_events.tte_events |= TTEVT_VFORK;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("enable vfork, tid is %d\n", tid);
+#endif
+
+ tt_status = call_ttrace (TT_PROC_SET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+}
+
+
+static void
+hppa_disable_catch_vfork (int tid)
+{
+ int tt_status;
+ ttevent_t ttrace_events;
+
+ /* Get the set of events that are currently enabled. */
+ tt_status = call_ttrace (TT_PROC_GET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+
+ /* Remove vforks from that set. */
+ ttrace_events.tte_events &= ~TTEVT_VFORK;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("disable vfork, tid is %d\n", tid);
+#endif
+ tt_status = call_ttrace (TT_PROC_SET_EVENT_MASK,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+}
+
+
+#if defined(CHILD_INSERT_VFORK_CATCHPOINT)
+int
+child_insert_vfork_catchpoint (int tid)
+{
+ /* Enable reporting of vfork events from the kernel. */
+ /* ??rehrauer: For the moment, we're always enabling these events,
+ and just ignoring them if there's no catchpoint to catch them.
+ */
+ return 0;
+}
+#endif
+
+
+#if defined(CHILD_REMOVE_VFORK_CATCHPOINT)
+int
+child_remove_vfork_catchpoint (int tid)
+{
+ /* Disable reporting of vfork events from the kernel. */
+ /* ??rehrauer: For the moment, we're always enabling these events,
+ and just ignoring them if there's no catchpoint to catch them.
+ */
+ return 0;
+}
+#endif
+
+/* Q: Do we need to map the returned process ID to a thread ID?
+
+ * A: I don't think so--here we want a _real_ pid. Any later
+ * operations will call "require_notification_of_events" and
+ * start the mapping.
+ */
+int
+hpux_has_forked (int tid, int *childpid)
+{
+ int tt_status;
+ ttstate_t ttrace_state;
+ thread_info *tinfo;
+
+ /* Do we have cached thread state that we can consult? If so, use it. */
+ tinfo = find_thread_info (map_from_gdb_tid (tid));
+ if (tinfo != NULL)
+ {
+ copy_ttstate_t (&ttrace_state, &tinfo->last_stop_state);
+ }
+
+ /* Nope, must read the thread's current state */
+ else
+ {
+ tt_status = call_ttrace (TT_LWP_GET_STATE,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_state,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_state),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+
+ if (tt_status < 0)
+ return 0;
+ }
+
+ if (ttrace_state.tts_event & TTEVT_FORK)
+ {
+ *childpid = ttrace_state.tts_u.tts_fork.tts_fpid;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* See hpux_has_forked for pid discussion.
+ */
+int
+hpux_has_vforked (int tid, int *childpid)
+{
+ int tt_status;
+ ttstate_t ttrace_state;
+ thread_info *tinfo;
+
+ /* Do we have cached thread state that we can consult? If so, use it. */
+ tinfo = find_thread_info (map_from_gdb_tid (tid));
+ if (tinfo != NULL)
+ copy_ttstate_t (&ttrace_state, &tinfo->last_stop_state);
+
+ /* Nope, must read the thread's current state */
+ else
+ {
+ tt_status = call_ttrace (TT_LWP_GET_STATE,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_state,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_state),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+
+ if (tt_status < 0)
+ return 0;
+ }
+
+ if (ttrace_state.tts_event & TTEVT_VFORK)
+ {
+ *childpid = ttrace_state.tts_u.tts_fork.tts_fpid;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+#if defined(CHILD_INSERT_EXEC_CATCHPOINT)
+int
+child_insert_exec_catchpoint (int tid)
+{
+ /* Enable reporting of exec events from the kernel. */
+ /* ??rehrauer: For the moment, we're always enabling these events,
+ and just ignoring them if there's no catchpoint to catch them.
+ */
+ return 0;
+}
+#endif
+
+
+#if defined(CHILD_REMOVE_EXEC_CATCHPOINT)
+int
+child_remove_exec_catchpoint (int tid)
+{
+ /* Disable reporting of execevents from the kernel. */
+ /* ??rehrauer: For the moment, we're always enabling these events,
+ and just ignoring them if there's no catchpoint to catch them.
+ */
+ return 0;
+}
+#endif
+
+
+int
+hpux_has_execd (int tid, char **execd_pathname)
+{
+ int tt_status;
+ ttstate_t ttrace_state;
+ thread_info *tinfo;
+
+ /* Do we have cached thread state that we can consult? If so, use it. */
+ tinfo = find_thread_info (map_from_gdb_tid (tid));
+ if (tinfo != NULL)
+ copy_ttstate_t (&ttrace_state, &tinfo->last_stop_state);
+
+ /* Nope, must read the thread's current state */
+ else
+ {
+ tt_status = call_ttrace (TT_LWP_GET_STATE,
+ tid,
+ (TTRACE_ARG_TYPE) & ttrace_state,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_state),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+
+ if (tt_status < 0)
+ return 0;
+ }
+
+ if (ttrace_state.tts_event & TTEVT_EXEC)
+ {
+ /* See child_pid_to_exec_file in this file: this is a macro.
+ */
+ char *exec_file = target_pid_to_exec_file (tid);
+
+ *execd_pathname = savestring (exec_file, strlen (exec_file));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int
+hpux_has_syscall_event (int pid, enum target_waitkind *kind, int *syscall_id)
+{
+ int tt_status;
+ ttstate_t ttrace_state;
+ thread_info *tinfo;
+
+ /* Do we have cached thread state that we can consult? If so, use it. */
+ tinfo = find_thread_info (map_from_gdb_tid (pid));
+ if (tinfo != NULL)
+ copy_ttstate_t (&ttrace_state, &tinfo->last_stop_state);
+
+ /* Nope, must read the thread's current state */
+ else
+ {
+ tt_status = call_ttrace (TT_LWP_GET_STATE,
+ pid,
+ (TTRACE_ARG_TYPE) & ttrace_state,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_state),
+ TT_NIL);
+
+ if (errno)
+ perror_with_name ("ttrace");
+
+ if (tt_status < 0)
+ return 0;
+ }
+
+ *kind = TARGET_WAITKIND_SPURIOUS; /* Until proven otherwise... */
+ *syscall_id = -1;
+
+ if (ttrace_state.tts_event & TTEVT_SYSCALL_ENTRY)
+ *kind = TARGET_WAITKIND_SYSCALL_ENTRY;
+ else if (ttrace_state.tts_event & TTEVT_SYSCALL_RETURN)
+ *kind = TARGET_WAITKIND_SYSCALL_RETURN;
+ else
+ return 0;
+
+ *syscall_id = ttrace_state.tts_scno;
+ return 1;
+}
+
+
+
+#if defined(CHILD_THREAD_ALIVE)
+
+/* Check to see if the given thread is alive.
+
+ * We'll trust the thread list, as the more correct
+ * approach of stopping the process and spinning down
+ * the OS's thread list is _very_ expensive.
+ *
+ * May need a FIXME for that reason.
+ */
+int
+child_thread_alive (ptid_t ptid)
+{
+ lwpid_t gdb_tid = PIDGET (ptid);
+ lwpid_t tid;
+
+ /* This spins down the lists twice.
+ * Possible peformance improvement here!
+ */
+ tid = map_from_gdb_tid (gdb_tid);
+ return !is_terminated (tid);
+}
+
+#endif
+
+
+
+/* This function attempts to read the specified number of bytes from the
+ save_state_t that is our view into the hardware registers, starting at
+ ss_offset, and ending at ss_offset + sizeof_buf - 1
+
+ If this function succeeds, it deposits the fetched bytes into buf,
+ and returns 0.
+
+ If it fails, it returns a negative result. The contents of buf are
+ undefined it this function fails.
+ */
+int
+read_from_register_save_state (int tid, TTRACE_ARG_TYPE ss_offset, char *buf,
+ int sizeof_buf)
+{
+ int tt_status;
+ register_value_t register_value = 0;
+
+ tt_status = call_ttrace (TT_LWP_RUREGS,
+ tid,
+ ss_offset,
+ (TTRACE_ARG_TYPE) sizeof_buf,
+ (TTRACE_ARG_TYPE) buf);
+
+ if (tt_status == 1)
+ /* Map ttrace's version of success to our version.
+ * Sometime ttrace returns 0, but that's ok here.
+ */
+ return 0;
+
+ return tt_status;
+}
+
+
+/* This function attempts to write the specified number of bytes to the
+ save_state_t that is our view into the hardware registers, starting at
+ ss_offset, and ending at ss_offset + sizeof_buf - 1
+
+ If this function succeeds, it deposits the bytes in buf, and returns 0.
+
+ If it fails, it returns a negative result. The contents of the save_state_t
+ are undefined it this function fails.
+ */
+int
+write_to_register_save_state (int tid, TTRACE_ARG_TYPE ss_offset, char *buf,
+ int sizeof_buf)
+{
+ int tt_status;
+ register_value_t register_value = 0;
+
+ tt_status = call_ttrace (TT_LWP_WUREGS,
+ tid,
+ ss_offset,
+ (TTRACE_ARG_TYPE) sizeof_buf,
+ (TTRACE_ARG_TYPE) buf);
+ return tt_status;
+}
+
+
+/* This function is a sop to the largeish number of direct calls
+ to call_ptrace that exist in other files. Rather than create
+ functions whose name abstracts away from ptrace, and change all
+ the present callers of call_ptrace, we'll do the expedient (and
+ perhaps only practical) thing.
+
+ Note HP-UX explicitly disallows a mix of ptrace & ttrace on a traced
+ process. Thus, we must translate all ptrace requests into their
+ process-specific, ttrace equivalents.
+ */
+int
+call_ptrace (int pt_request, int gdb_tid, PTRACE_ARG3_TYPE addr, int data)
+{
+ ttreq_t tt_request;
+ TTRACE_ARG_TYPE tt_addr = (TTRACE_ARG_TYPE) addr;
+ TTRACE_ARG_TYPE tt_data = (TTRACE_ARG_TYPE) data;
+ TTRACE_ARG_TYPE tt_addr2 = TT_NIL;
+ int tt_status;
+ register_value_t register_value;
+ int read_buf;
+
+ /* Perform the necessary argument translation. Note that some
+ cases are funky enough in the ttrace realm that we handle them
+ very specially.
+ */
+ switch (pt_request)
+ {
+ /* The following cases cannot conveniently be handled conveniently
+ by merely adjusting the ptrace arguments and feeding into the
+ generic call to ttrace at the bottom of this function.
+
+ Note that because all branches of this switch end in "return",
+ there's no need for any "break" statements.
+ */
+ case PT_SETTRC:
+ return parent_attach_all (0, 0, 0);
+
+ case PT_RUREGS:
+ tt_status = read_from_register_save_state (gdb_tid,
+ tt_addr,
+ &register_value,
+ sizeof (register_value));
+ if (tt_status < 0)
+ return tt_status;
+ return register_value;
+
+ case PT_WUREGS:
+ register_value = (int) tt_data;
+ tt_status = write_to_register_save_state (gdb_tid,
+ tt_addr,
+ &register_value,
+ sizeof (register_value));
+ return tt_status;
+ break;
+
+ case PT_READ_I:
+ tt_status = call_ttrace (TT_PROC_RDTEXT, /* Implicit 4-byte xfer becomes block-xfer. */
+ gdb_tid,
+ tt_addr,
+ (TTRACE_ARG_TYPE) 4,
+ (TTRACE_ARG_TYPE) & read_buf);
+ if (tt_status < 0)
+ return tt_status;
+ return read_buf;
+
+ case PT_READ_D:
+ tt_status = call_ttrace (TT_PROC_RDDATA, /* Implicit 4-byte xfer becomes block-xfer. */
+ gdb_tid,
+ tt_addr,
+ (TTRACE_ARG_TYPE) 4,
+ (TTRACE_ARG_TYPE) & read_buf);
+ if (tt_status < 0)
+ return tt_status;
+ return read_buf;
+
+ case PT_ATTACH:
+ tt_status = call_real_ttrace (TT_PROC_ATTACH,
+ map_from_gdb_tid (gdb_tid),
+ (lwpid_t) TT_NIL,
+ tt_addr,
+ (TTRACE_ARG_TYPE) TT_VERSION,
+ tt_addr2);
+ if (tt_status < 0)
+ return tt_status;
+ return tt_status;
+
+ /* The following cases are handled by merely adjusting the ptrace
+ arguments and feeding into the generic call to ttrace.
+ */
+ case PT_DETACH:
+ tt_request = TT_PROC_DETACH;
+ break;
+
+ case PT_WRITE_I:
+ tt_request = TT_PROC_WRTEXT; /* Translates 4-byte xfer to block-xfer. */
+ tt_data = 4; /* This many bytes. */
+ tt_addr2 = (TTRACE_ARG_TYPE) & data; /* Address of xfer source. */
+ break;
+
+ case PT_WRITE_D:
+ tt_request = TT_PROC_WRDATA; /* Translates 4-byte xfer to block-xfer. */
+ tt_data = 4; /* This many bytes. */
+ tt_addr2 = (TTRACE_ARG_TYPE) & data; /* Address of xfer source. */
+ break;
+
+ case PT_RDTEXT:
+ tt_request = TT_PROC_RDTEXT;
+ break;
+
+ case PT_RDDATA:
+ tt_request = TT_PROC_RDDATA;
+ break;
+
+ case PT_WRTEXT:
+ tt_request = TT_PROC_WRTEXT;
+ break;
+
+ case PT_WRDATA:
+ tt_request = TT_PROC_WRDATA;
+ break;
+
+ case PT_CONTINUE:
+ tt_request = TT_PROC_CONTINUE;
+ break;
+
+ case PT_STEP:
+ tt_request = TT_LWP_SINGLE; /* Should not be making this request? */
+ break;
+
+ case PT_KILL:
+ tt_request = TT_PROC_EXIT;
+ break;
+
+ case PT_GET_PROCESS_PATHNAME:
+ tt_request = TT_PROC_GET_PATHNAME;
+ break;
+
+ default:
+ tt_request = pt_request; /* Let ttrace be the one to complain. */
+ break;
+ }
+
+ return call_ttrace (tt_request,
+ gdb_tid,
+ tt_addr,
+ tt_data,
+ tt_addr2);
+}
+
+/* Kill that pesky process!
+ */
+void
+kill_inferior (void)
+{
+ int tid;
+ int wait_status;
+ thread_info *t;
+ thread_info **paranoia;
+ int para_count, i;
+
+ if (PIDGET (inferior_ptid) == 0)
+ return;
+
+ /* Walk the list of "threads", some of which are "pseudo threads",
+ aka "processes". For each that is NOT inferior_ptid, stop it,
+ and detach it.
+
+ You see, we may not have just a single process to kill. If we're
+ restarting or quitting or detaching just after the inferior has
+ forked, then we've actually two processes to clean up.
+
+ But we can't just call target_mourn_inferior() for each, since that
+ zaps the target vector.
+ */
+
+ paranoia = (thread_info **) xmalloc (thread_head.count *
+ sizeof (thread_info *));
+ para_count = 0;
+
+ t = thread_head.head;
+ while (t)
+ {
+
+ paranoia[para_count] = t;
+ for (i = 0; i < para_count; i++)
+ {
+ if (t->next == paranoia[i])
+ {
+ warning ("Bad data in gdb's thread data; repairing.");
+ t->next = 0;
+ }
+ }
+ para_count++;
+
+ if (t->am_pseudo && (t->pid != PIDGET (inferior_ptid)))
+ {
+ call_ttrace (TT_PROC_EXIT,
+ t->pid,
+ TT_NIL,
+ TT_NIL,
+ TT_NIL);
+ }
+ t = t->next;
+ }
+
+ xfree (paranoia);
+
+ call_ttrace (TT_PROC_EXIT,
+ PIDGET (inferior_ptid),
+ TT_NIL,
+ TT_NIL,
+ TT_NIL);
+ target_mourn_inferior ();
+ clear_thread_info ();
+}
+
+
+#ifndef CHILD_RESUME
+
+/* Sanity check a thread about to be continued.
+ */
+static void
+thread_dropping_event_check (thread_info *p)
+{
+ if (!p->handled)
+ {
+ /*
+ * This seems to happen when we "next" over a
+ * "fork()" while following the parent. If it's
+ * the FORK event, that's ok. If it's a SIGNAL
+ * in the unfollowed child, that's ok to--but
+ * how can we know that's what's going on?
+ *
+ * FIXME!
+ */
+ if (p->have_state)
+ {
+ if (p->last_stop_state.tts_event == TTEVT_FORK)
+ {
+ /* Ok */
+ ;
+ }
+ else if (p->last_stop_state.tts_event == TTEVT_SIGNAL)
+ {
+ /* Ok, close eyes and let it happen.
+ */
+ ;
+ }
+ else
+ {
+ /* This shouldn't happen--we're dropping a
+ * real event.
+ */
+ warning ("About to continue process %d, thread %d with unhandled event %s.",
+ p->pid, p->tid,
+ get_printable_name_of_ttrace_event (
+ p->last_stop_state.tts_event));
+
+#ifdef PARANOIA
+ if (debug_on)
+ print_tthread (p);
+#endif
+ }
+ }
+ else
+ {
+ /* No saved state, have to assume it failed.
+ */
+ warning ("About to continue process %d, thread %d with unhandled event.",
+ p->pid, p->tid);
+#ifdef PARANOIA
+ if (debug_on)
+ print_tthread (p);
+#endif
+ }
+ }
+
+} /* thread_dropping_event_check */
+
+/* Use a loop over the threads to continue all the threads but
+ * the one specified, which is to be stepped.
+ */
+static void
+threads_continue_all_but_one (lwpid_t gdb_tid, int signal)
+{
+ thread_info *p;
+ int thread_signal;
+ lwpid_t real_tid;
+ lwpid_t scan_tid;
+ ttstate_t state;
+ int real_pid;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Using loop over threads to step/resume with signals\n");
+#endif
+
+ /* First update the thread list.
+ */
+ set_all_unseen ();
+ real_tid = map_from_gdb_tid (gdb_tid);
+ real_pid = get_pid_for (real_tid);
+
+ scan_tid = get_process_first_stopped_thread_id (real_pid, &state);
+ while (0 != scan_tid)
+ {
+
+#ifdef THREAD_DEBUG
+ /* FIX: later should check state is stopped;
+ * state.tts_flags & TTS_STATEMASK == TTS_WASSUSPENDED
+ */
+ if (debug_on)
+ if ((state.tts_flags & TTS_STATEMASK) != TTS_WASSUSPENDED)
+ printf ("About to continue non-stopped thread %d\n", scan_tid);
+#endif
+
+ p = find_thread_info (scan_tid);
+ if (NULL == p)
+ {
+ add_tthread (real_pid, scan_tid);
+ p = find_thread_info (scan_tid);
+
+ /* This is either a newly-created thread or the
+ * result of a fork; in either case there's no
+ * actual event to worry about.
+ */
+ p->handled = 1;
+
+ if (state.tts_event != TTEVT_NONE)
+ {
+ /* Oops, do need to worry!
+ */
+ warning ("Unexpected thread with \"%s\" event.",
+ get_printable_name_of_ttrace_event (state.tts_event));
+ }
+ }
+ else if (scan_tid != p->tid)
+ error ("Bad data in thread database.");
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ if (p->terminated)
+ printf ("Why are we continuing a dead thread?\n");
+#endif
+
+ p->seen = 1;
+
+ scan_tid = get_process_next_stopped_thread_id (real_pid, &state);
+ }
+
+ /* Remove unseen threads.
+ */
+ update_thread_list ();
+
+ /* Now run down the thread list and continue or step.
+ */
+ for (p = thread_head.head; p; p = p->next)
+ {
+
+ /* Sanity check.
+ */
+ thread_dropping_event_check (p);
+
+ /* Pass the correct signals along.
+ */
+ if (p->have_signal)
+ {
+ thread_signal = p->signal_value;
+ p->have_signal = 0;
+ }
+ else
+ thread_signal = 0;
+
+ if (p->tid != real_tid)
+ {
+ /*
+ * Not the thread of interest, so continue it
+ * as the user expects.
+ */
+ if (p->stepping_mode == DO_STEP)
+ {
+ /* Just step this thread.
+ */
+ call_ttrace (
+ TT_LWP_SINGLE,
+ p->tid,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (signal),
+ TT_NIL);
+ }
+ else
+ {
+ /* Regular continue (default case).
+ */
+ call_ttrace (
+ TT_LWP_CONTINUE,
+ p->tid,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (thread_signal),
+ TT_NIL);
+ }
+ }
+ else
+ {
+ /* Step the thread of interest.
+ */
+ call_ttrace (
+ TT_LWP_SINGLE,
+ real_tid,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (signal),
+ TT_NIL);
+ }
+ } /* Loop over threads */
+} /* End threads_continue_all_but_one */
+
+/* Use a loop over the threads to continue all the threads.
+ * This is done when a signal must be sent to any of the threads.
+ */
+static void
+threads_continue_all_with_signals (lwpid_t gdb_tid, int signal)
+{
+ thread_info *p;
+ int thread_signal;
+ lwpid_t real_tid;
+ lwpid_t scan_tid;
+ ttstate_t state;
+ int real_pid;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Using loop over threads to resume with signals\n");
+#endif
+
+ /* Scan and update thread list.
+ */
+ set_all_unseen ();
+ real_tid = map_from_gdb_tid (gdb_tid);
+ real_pid = get_pid_for (real_tid);
+
+ scan_tid = get_process_first_stopped_thread_id (real_pid, &state);
+ while (0 != scan_tid)
+ {
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ if ((state.tts_flags & TTS_STATEMASK) != TTS_WASSUSPENDED)
+ warning ("About to continue non-stopped thread %d\n", scan_tid);
+#endif
+
+ p = find_thread_info (scan_tid);
+ if (NULL == p)
+ {
+ add_tthread (real_pid, scan_tid);
+ p = find_thread_info (scan_tid);
+
+ /* This is either a newly-created thread or the
+ * result of a fork; in either case there's no
+ * actual event to worry about.
+ */
+ p->handled = 1;
+
+ if (state.tts_event != TTEVT_NONE)
+ {
+ /* Oops, do need to worry!
+ */
+ warning ("Unexpected thread with \"%s\" event.",
+ get_printable_name_of_ttrace_event (state.tts_event));
+ }
+ }
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ if (p->terminated)
+ printf ("Why are we continuing a dead thread? (1)\n");
+#endif
+
+ p->seen = 1;
+
+ scan_tid = get_process_next_stopped_thread_id (real_pid, &state);
+ }
+
+ /* Remove unseen threads from our list.
+ */
+ update_thread_list ();
+
+ /* Continue the threads.
+ */
+ for (p = thread_head.head; p; p = p->next)
+ {
+
+ /* Sanity check.
+ */
+ thread_dropping_event_check (p);
+
+ /* Pass the correct signals along.
+ */
+ if (p->tid == real_tid)
+ {
+ thread_signal = signal;
+ p->have_signal = 0;
+ }
+ else if (p->have_signal)
+ {
+ thread_signal = p->signal_value;
+ p->have_signal = 0;
+ }
+ else
+ thread_signal = 0;
+
+ if (p->stepping_mode == DO_STEP)
+ {
+ call_ttrace (
+ TT_LWP_SINGLE,
+ p->tid,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (signal),
+ TT_NIL);
+ }
+ else
+ {
+ /* Continue this thread (default case).
+ */
+ call_ttrace (
+ TT_LWP_CONTINUE,
+ p->tid,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (thread_signal),
+ TT_NIL);
+ }
+ }
+} /* End threads_continue_all_with_signals */
+
+/* Step one thread only.
+ */
+static void
+thread_fake_step (lwpid_t tid, enum target_signal signal)
+{
+ thread_info *p;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ {
+ printf ("Doing a fake-step over a bpt, etc. for %d\n", tid);
+
+ if (is_terminated (tid))
+ printf ("Why are we continuing a dead thread? (4)\n");
+ }
+#endif
+
+ if (doing_fake_step)
+ warning ("Step while step already in progress.");
+
+ /* See if there's a saved signal value for this
+ * thread to be passed on, but no current signal.
+ */
+ p = find_thread_info (tid);
+ if (p != NULL)
+ {
+ if (p->have_signal && signal == TARGET_SIGNAL_0)
+ {
+ /* Pass on a saved signal.
+ */
+ signal = p->signal_value;
+ }
+
+ p->have_signal = 0;
+ }
+
+ if (!p->handled)
+ warning ("Internal error: continuing unhandled thread.");
+
+ call_ttrace (TT_LWP_SINGLE,
+ tid,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (signal),
+ TT_NIL);
+
+ /* Do bookkeeping so "call_ttrace_wait" knows it has to wait
+ * for this thread only, and clear any saved signal info.
+ */
+ doing_fake_step = 1;
+ fake_step_tid = tid;
+
+} /* End thread_fake_step */
+
+/* Continue one thread when a signal must be sent to it.
+ */
+static void
+threads_continue_one_with_signal (lwpid_t gdb_tid, int signal)
+{
+ thread_info *p;
+ lwpid_t real_tid;
+ int real_pid;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Continuing one thread with a signal\n");
+#endif
+
+ real_tid = map_from_gdb_tid (gdb_tid);
+ real_pid = get_pid_for (real_tid);
+
+ p = find_thread_info (real_tid);
+ if (NULL == p)
+ {
+ add_tthread (real_pid, real_tid);
+ }
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ if (p->terminated)
+ printf ("Why are we continuing a dead thread? (2)\n");
+#endif
+
+ if (!p->handled)
+ warning ("Internal error: continuing unhandled thread.");
+
+ p->have_signal = 0;
+
+ call_ttrace (TT_LWP_CONTINUE,
+ gdb_tid,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (signal),
+ TT_NIL);
+}
+#endif
+
+#ifndef CHILD_RESUME
+
+/* Resume execution of the inferior process.
+
+ * This routine is in charge of setting the "handled" bits.
+ *
+ * If STEP is zero, continue it.
+ * If STEP is nonzero, single-step it.
+ *
+ * If SIGNAL is nonzero, give it that signal.
+ *
+ * If TID is -1, apply to all threads.
+ * If TID is not -1, apply to specified thread.
+ *
+ * STEP
+ * \ !0 0
+ * TID \________________________________________________
+ * |
+ * -1 | Step current Continue all threads
+ * | thread and (but which gets any
+ * | continue others signal?--We look at
+ * | "inferior_ptid")
+ * |
+ * N | Step _this_ thread Continue _this_ thread
+ * | and leave others and leave others
+ * | stopped; internally stopped; used only for
+ * | used by gdb, never hardware watchpoints
+ * | a user command. and attach, never a
+ * | user command.
+ */
+void
+child_resume (ptid_t ptid, int step, enum target_signal signal)
+{
+ int resume_all_threads;
+ lwpid_t tid;
+ process_state_t new_process_state;
+ lwpid_t gdb_tid = PIDGET (ptid);
+
+ resume_all_threads =
+ (gdb_tid == INFTTRACE_ALL_THREADS) ||
+ (vfork_in_flight);
+
+ if (resume_all_threads)
+ {
+ /* Resume all threads, but first pick a tid value
+ * so we can get the pid when in call_ttrace doing
+ * the map.
+ */
+ if (vfork_in_flight)
+ tid = vforking_child_pid;
+ else
+ tid = map_from_gdb_tid (PIDGET (inferior_ptid));
+ }
+ else
+ tid = map_from_gdb_tid (gdb_tid);
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ {
+ if (more_events_left)
+ printf ("More events; ");
+
+ if (signal != 0)
+ printf ("Sending signal %d; ", signal);
+
+ if (resume_all_threads)
+ {
+ if (step == 0)
+ printf ("Continue process %d\n", tid);
+ else
+ printf ("Step/continue thread %d\n", tid);
+ }
+ else
+ {
+ if (step == 0)
+ printf ("Continue thread %d\n", tid);
+ else
+ printf ("Step just thread %d\n", tid);
+ }
+
+ if (vfork_in_flight)
+ printf ("Vfork in flight\n");
+ }
+#endif
+
+ if (process_state == RUNNING)
+ warning ("Internal error in resume logic; doing resume or step anyway.");
+
+ if (!step /* Asked to continue... */
+ && resume_all_threads /* whole process.. */
+ && signal != 0 /* with a signal... */
+ && more_events_left > 0)
+ { /* but we can't yet--save it! */
+
+ /* Continue with signal means we have to set the pending
+ * signal value for this thread.
+ */
+ thread_info *k;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Saving signal %d for thread %d\n", signal, tid);
+#endif
+
+ k = find_thread_info (tid);
+ if (k != NULL)
+ {
+ k->have_signal = 1;
+ k->signal_value = signal;
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ if (k->terminated)
+ printf ("Why are we continuing a dead thread? (3)\n");
+#endif
+
+ }
+
+#ifdef THREAD_DEBUG
+ else if (debug_on)
+ {
+ printf ("No thread info for tid %d\n", tid);
+ }
+#endif
+ }
+
+ /* Are we faking this "continue" or "step"?
+
+ * We used to do steps by continuing all the threads for
+ * which the events had been handled already. While
+ * conceptually nicer (hides it all in a lower level), this
+ * can lead to starvation and a hang (e.g. all but one thread
+ * are unhandled at a breakpoint just before a "join" operation,
+ * and one thread is in the join, and the user wants to step that
+ * thread).
+ */
+ if (resume_all_threads /* Whole process, therefore user command */
+ && more_events_left > 0)
+ { /* But we can't do this yet--fake it! */
+ thread_info *p;
+
+ if (!step)
+ {
+ /* No need to do any notes on a per-thread
+ * basis--we're done!
+ */
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Faking a process resume.\n");
+#endif
+
+ return;
+ }
+ else
+ {
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Faking a process step.\n");
+#endif
+
+ }
+
+ p = find_thread_info (tid);
+ if (p == NULL)
+ {
+ warning ("No thread information for tid %d, 'next' command ignored.\n", tid);
+ return;
+ }
+ else
+ {
+
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ if (p->terminated)
+ printf ("Why are we continuing a dead thread? (3.5)\n");
+#endif
+
+ if (p->stepping_mode != DO_DEFAULT)
+ {
+ warning ("Step or continue command applied to thread which is already stepping or continuing; command ignored.");
+
+ return;
+ }
+
+ if (step)
+ p->stepping_mode = DO_STEP;
+ else
+ p->stepping_mode = DO_CONTINUE;
+
+ return;
+ } /* Have thread info */
+ } /* Must fake step or go */
+
+ /* Execept for fake-steps, from here on we know we are
+ * going to wind up with a running process which will
+ * need a real wait.
+ */
+ new_process_state = RUNNING;
+
+ /* An address of TT_USE_CURRENT_PC tells ttrace 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)
+ {
+ if (resume_all_threads)
+ {
+ /*
+ * Regular user step: other threads get a "continue".
+ */
+ threads_continue_all_but_one (tid, signal);
+ clear_all_handled ();
+ clear_all_stepping_mode ();
+ }
+
+ else
+ {
+ /* "Fake step": gdb is stepping one thread over a
+ * breakpoint, watchpoint, or out of a library load
+ * event, etc. The rest just stay where they are.
+ *
+ * Also used when there are pending events: we really
+ * step the current thread, but leave the rest stopped.
+ * Users can't request this, but "wait_for_inferior"
+ * does--a lot!
+ */
+ thread_fake_step (tid, signal);
+
+ /* Clear the "handled" state of this thread, because
+ * we'll soon get a new event for it. Other events
+ * stay as they were.
+ */
+ clear_handled (tid);
+ clear_stepping_mode (tid);
+ new_process_state = FAKE_STEPPING;
+ }
+ }
+
+ else
+ {
+ /* TT_LWP_CONTINUE can pass signals to threads, TT_PROC_CONTINUE can't.
+ Therefore, we really can't use TT_PROC_CONTINUE here.
+
+ Consider a process which stopped due to signal which gdb decides
+ to handle and not pass on to the inferior. In that case we must
+ clear the pending signal by restarting the inferior using
+ TT_LWP_CONTINUE and pass zero as the signal number. Else the
+ pending signal will be passed to the inferior. interrupt.exp
+ in the testsuite does this precise thing and fails due to the
+ unwanted signal delivery to the inferior. */
+ /* drow/2002-12-05: However, note that we must use TT_PROC_CONTINUE
+ if we are tracing a vfork. */
+ if (vfork_in_flight)
+ {
+ call_ttrace (TT_PROC_CONTINUE, tid, TT_NIL, TT_NIL, TT_NIL);
+ clear_all_handled ();
+ clear_all_stepping_mode ();
+ }
+ else if (resume_all_threads)
+ {
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Doing a continue by loop of all threads\n");
+#endif
+
+ threads_continue_all_with_signals (tid, signal);
+
+ clear_all_handled ();
+ clear_all_stepping_mode ();
+ }
+ else
+ {
+#ifdef THREAD_DEBUG
+ printf ("Doing a continue w/signal of just thread %d\n", tid);
+#endif
+
+ threads_continue_one_with_signal (tid, signal);
+
+ /* Clear the "handled" state of this thread, because we
+ will soon get a new event for it. Other events can
+ stay as they were. */
+ clear_handled (tid);
+ clear_stepping_mode (tid);
+ }
+ }
+
+ process_state = new_process_state;
+
+#ifdef WAIT_BUFFER_DEBUG
+ if (debug_on)
+ printf ("Process set to %s\n",
+ get_printable_name_of_process_state (process_state));
+#endif
+
+}
+#endif /* CHILD_RESUME */
+
+
+#ifdef ATTACH_DETACH
+/*
+ * Like it says.
+ *
+ * One worry is that we may not be attaching to "inferior_ptid"
+ * and thus may not want to clear out our data. FIXME?
+ *
+ */
+static void
+update_thread_state_after_attach (int pid, attach_continue_t kind_of_go)
+{
+ int tt_status;
+ ttstate_t thread_state;
+ lwpid_t a_thread;
+ lwpid_t tid;
+
+ /* The process better be stopped.
+ */
+ if (process_state != STOPPED
+ && process_state != VFORKING)
+ warning ("Internal error attaching.");
+
+ /* Clear out old tthread info and start over. This has the
+ * side effect of ensuring that the TRAP is reported as being
+ * in the right thread (re-mapped from tid to pid).
+ *
+ * It's because we need to add the tthread _now_ that we
+ * need to call "clear_thread_info" _now_, and that's why
+ * "require_notification_of_events" doesn't clear the thread
+ * info (it's called later than this routine).
+ */
+ clear_thread_info ();
+ a_thread = 0;
+
+ for (tid = get_process_first_stopped_thread_id (pid, &thread_state);
+ tid != 0;
+ tid = get_process_next_stopped_thread_id (pid, &thread_state))
+ {
+ thread_info *p;
+
+ if (a_thread == 0)
+ {
+ a_thread = tid;
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("Attaching to process %d, thread %d\n",
+ pid, a_thread);
+#endif
+ }
+
+ /* Tell ourselves and the "rest of gdb" that this thread
+ * exists.
+ *
+ * This isn't really a hack. Other thread-based versions
+ * of gdb (e.g. gnu-nat.c) seem to do the same thing.
+ *
+ * We don't need to do mapping here, as we know this
+ * is the first thread and thus gets the real pid
+ * (and is "inferior_ptid").
+ *
+ * NOTE: it probably isn't the originating thread,
+ * but that doesn't matter (we hope!).
+ */
+ add_tthread (pid, tid);
+ p = find_thread_info (tid);
+ if (NULL == p) /* ?We just added it! */
+ error ("Internal error adding a thread on attach.");
+
+ copy_ttstate_t (&p->last_stop_state, &thread_state);
+ p->have_state = 1;
+
+ if (DO_ATTACH_CONTINUE == kind_of_go)
+ {
+ /*
+ * If we are going to CONTINUE afterwards,
+ * raising a SIGTRAP, don't bother trying to
+ * handle this event. But check first!
+ */
+ switch (p->last_stop_state.tts_event)
+ {
+
+ case TTEVT_NONE:
+ /* Ok to set this handled.
+ */
+ break;
+
+ default:
+ warning ("Internal error; skipping event %s on process %d, thread %d.",
+ get_printable_name_of_ttrace_event (
+ p->last_stop_state.tts_event),
+ p->pid, p->tid);
+ }
+
+ set_handled (pid, tid);
+
+ }
+ else
+ {
+ /* There will be no "continue" opertion, so the
+ * process remains stopped. Don't set any events
+ * handled except the "gimmies".
+ */
+ switch (p->last_stop_state.tts_event)
+ {
+
+ case TTEVT_NONE:
+ /* Ok to ignore this.
+ */
+ set_handled (pid, tid);
+ break;
+
+ case TTEVT_EXEC:
+ case TTEVT_FORK:
+ /* Expected "other" FORK or EXEC event from a
+ * fork or vfork.
+ */
+ break;
+
+ default:
+ printf ("Internal error: failed to handle event %s on process %d, thread %d.",
+ get_printable_name_of_ttrace_event (
+ p->last_stop_state.tts_event),
+ p->pid, p->tid);
+ }
+ }
+
+ add_thread (pid_to_ptid (pid)); /* in thread.c */
+ }
+
+#ifdef PARANOIA
+ if (debug_on)
+ print_tthreads ();
+#endif
+
+ /* One mustn't call ttrace_wait() after attaching via ttrace,
+ 'cause the process is stopped already.
+
+ However, the upper layers of gdb's execution control will
+ want to wait after attaching (but not after forks, in
+ which case they will be doing a "target_resume", anticipating
+ a later TTEVT_EXEC or TTEVT_FORK event).
+
+ To make this attach() implementation more compatible with
+ others, we'll make the attached-to process raise a SIGTRAP.
+
+ Issue: this continues only one thread. That could be
+ dangerous if the thread is blocked--the process won't run
+ and no trap will be raised. FIX! (check state.tts_flags?
+ need one that's either TTS_WASRUNNING--but we've stopped
+ it and made it TTS_WASSUSPENDED. Hum...FIXME!)
+ */
+ if (DO_ATTACH_CONTINUE == kind_of_go)
+ {
+ tt_status = call_real_ttrace (
+ TT_LWP_CONTINUE,
+ pid,
+ a_thread,
+ TT_USE_CURRENT_PC,
+ (TTRACE_ARG_TYPE) target_signal_to_host (TARGET_SIGNAL_TRAP),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+
+ clear_handled (a_thread); /* So TRAP will be reported. */
+
+ /* Now running.
+ */
+ process_state = RUNNING;
+ }
+
+ attach_flag = 1;
+}
+#endif /* ATTACH_DETACH */
+
+
+#ifdef ATTACH_DETACH
+/* Start debugging the process whose number is PID.
+ * (A _real_ pid).
+ */
+int
+attach (int pid)
+{
+ int tt_status;
+
+ tt_status = call_real_ttrace (
+ TT_PROC_ATTACH,
+ pid,
+ (lwpid_t) TT_NIL,
+ TT_NIL,
+ (TTRACE_ARG_TYPE) TT_VERSION,
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace attach");
+
+ /* If successful, the process is now stopped.
+ */
+ process_state = STOPPED;
+
+ /* Our caller ("attach_command" in "infcmd.c")
+ * expects to do a "wait_for_inferior" after
+ * the attach, so make sure the inferior is
+ * running when we're done.
+ */
+ update_thread_state_after_attach (pid, DO_ATTACH_CONTINUE);
+
+ return pid;
+}
+
+
+#if defined(CHILD_POST_ATTACH)
+void
+child_post_attach (int pid)
+{
+#ifdef THREAD_DEBUG
+ if (debug_on)
+ printf ("child-post-attach call\n");
+#endif
+
+ require_notification_of_events (pid);
+}
+#endif
+
+
+/* Stop debugging the process whose number is PID
+ and continue it with signal number SIGNAL.
+ SIGNAL = 0 means just continue it.
+ */
+void
+detach (int signal)
+{
+ errno = 0;
+ call_ttrace (TT_PROC_DETACH,
+ PIDGET (inferior_ptid),
+ TT_NIL,
+ (TTRACE_ARG_TYPE) signal,
+ TT_NIL);
+ attach_flag = 0;
+
+ clear_thread_info ();
+
+ /* Process-state? */
+}
+#endif /* ATTACH_DETACH */
+
+
+/* Default the type of the ttrace transfer to int. */
+#ifndef TTRACE_XFER_TYPE
+#define TTRACE_XFER_TYPE int
+#endif
+
+void
+_initialize_kernel_u_addr (void)
+{
+}
+
+#if !defined (CHILD_XFER_MEMORY)
+/* NOTE! I tried using TTRACE_READDATA, etc., to read and write memory
+ in the NEW_SUN_TTRACE 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. TARGET is ignored.
+
+ 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 (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ int i;
+ /* Round starting address down to longword boundary. */
+ CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (TTRACE_XFER_TYPE);
+ /* Round ending address up; get number of longwords that makes. */
+ int count
+ = (((memaddr + len) - addr) + sizeof (TTRACE_XFER_TYPE) - 1)
+ / sizeof (TTRACE_XFER_TYPE);
+ /* Allocate buffer of that many longwords. */
+ /* FIXME (alloca): This code, cloned from infptrace.c, is unsafe
+ because it uses alloca to allocate a buffer of arbitrary size.
+ For very large xfers, this could crash GDB's stack. */
+ TTRACE_XFER_TYPE *buffer
+ = (TTRACE_XFER_TYPE *) alloca (count * sizeof (TTRACE_XFER_TYPE));
+
+ if (write)
+ {
+ /* Fill start and end extra bytes of buffer with existing memory data. */
+
+ if (addr != memaddr || len < (int) sizeof (TTRACE_XFER_TYPE))
+ {
+ /* Need part of initial word -- fetch it. */
+ buffer[0] = call_ttrace (TT_LWP_RDTEXT,
+ PIDGET (inferior_ptid),
+ (TTRACE_ARG_TYPE) addr,
+ TT_NIL,
+ TT_NIL);
+ }
+
+ if (count > 1) /* FIXME, avoid if even boundary */
+ {
+ buffer[count - 1] = call_ttrace (TT_LWP_RDTEXT,
+ PIDGET (inferior_ptid),
+ ((TTRACE_ARG_TYPE)
+ (addr + (count - 1) * sizeof (TTRACE_XFER_TYPE))),
+ TT_NIL,
+ TT_NIL);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (TTRACE_XFER_TYPE) - 1)),
+ myaddr,
+ len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (TTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ call_ttrace (TT_LWP_WRDATA,
+ PIDGET (inferior_ptid),
+ (TTRACE_ARG_TYPE) addr,
+ (TTRACE_ARG_TYPE) buffer[i],
+ TT_NIL);
+ if (errno)
+ {
+ /* Using the appropriate one (I or D) is necessary for
+ Gould NP1, at least. */
+ errno = 0;
+ call_ttrace (TT_LWP_WRTEXT,
+ PIDGET (inferior_ptid),
+ (TTRACE_ARG_TYPE) addr,
+ (TTRACE_ARG_TYPE) buffer[i],
+ TT_NIL);
+ }
+ if (errno)
+ return 0;
+ }
+ }
+ else
+ {
+ /* Read all the longwords */
+ for (i = 0; i < count; i++, addr += sizeof (TTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ buffer[i] = call_ttrace (TT_LWP_RDTEXT,
+ PIDGET (inferior_ptid),
+ (TTRACE_ARG_TYPE) addr,
+ TT_NIL,
+ TT_NIL);
+ if (errno)
+ return 0;
+ QUIT;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr,
+ (char *) buffer + (memaddr & (sizeof (TTRACE_XFER_TYPE) - 1)),
+ len);
+ }
+ return len;
+}
+
+
+static void
+udot_info (void)
+{
+ 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 = call_ttrace (TT_LWP_RUREGS,
+ PIDGET (inferior_ptid),
+ (TTRACE_ARG_TYPE) udot_off,
+ TT_NIL,
+ TT_NIL);
+ 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). */
+
+
+/* TTrace version of "target_pid_to_exec_file"
+ */
+char *
+child_pid_to_exec_file (int tid)
+{
+ int tt_status;
+ static char exec_file_buffer[1024];
+ pid_t pid;
+ static struct pst_status buf;
+
+ /* On various versions of hpux11, this may fail due to a supposed
+ kernel bug. We have alternate methods to get this information
+ (ie pstat). */
+ tt_status = call_ttrace (TT_PROC_GET_PATHNAME,
+ tid,
+ (uint64_t) exec_file_buffer,
+ sizeof (exec_file_buffer) - 1,
+ 0);
+ if (tt_status >= 0)
+ return exec_file_buffer;
+
+ /* Try to get process information via pstat and extract the filename
+ from the pst_cmd field within the pst_status structure. */
+ if (pstat_getproc (&buf, sizeof (struct pst_status), 0, tid) != -1)
+ {
+ char *p = buf.pst_cmd;
+
+ while (*p && *p != ' ')
+ p++;
+ *p = 0;
+
+ return (buf.pst_cmd);
+ }
+
+ return (NULL);
+}
+
+void
+pre_fork_inferior (void)
+{
+ int status;
+
+ status = pipe (startup_semaphore.parent_channel);
+ if (status < 0)
+ {
+ warning ("error getting parent pipe for startup semaphore");
+ return;
+ }
+
+ status = pipe (startup_semaphore.child_channel);
+ if (status < 0)
+ {
+ warning ("error getting child pipe for startup semaphore");
+ return;
+ }
+}
+
+/* Called from child_follow_fork in hppah-nat.c.
+ *
+ * This seems to be intended to attach after a fork or
+ * vfork, while "attach" is used to attach to a pid
+ * given by the user. The check for an existing attach
+ * seems odd--it always fails in our test system.
+ */
+int
+hppa_require_attach (int pid)
+{
+ int tt_status;
+ CORE_ADDR pc;
+ CORE_ADDR pc_addr;
+ unsigned int regs_offset;
+ process_state_t old_process_state = process_state;
+
+ /* Are we already attached? There appears to be no explicit
+ * way to answer this via ttrace, so we try something which
+ * should be innocuous if we are attached. If that fails,
+ * then we assume we're not attached, and so attempt to make
+ * it so.
+ */
+ errno = 0;
+ tt_status = call_real_ttrace (TT_PROC_STOP,
+ pid,
+ (lwpid_t) TT_NIL,
+ (TTRACE_ARG_TYPE) TT_NIL,
+ (TTRACE_ARG_TYPE) TT_NIL,
+ TT_NIL);
+
+ if (errno)
+ {
+ /* No change to process-state!
+ */
+ errno = 0;
+ pid = attach (pid);
+ }
+ else
+ {
+ /* If successful, the process is now stopped. But if
+ * we're VFORKING, the parent is still running, so don't
+ * change the process state.
+ */
+ if (process_state != VFORKING)
+ process_state = STOPPED;
+
+ /* If we were already attached, you'd think that we
+ * would need to start going again--but you'd be wrong,
+ * as the fork-following code is actually in the middle
+ * of the "resume" routine in in "infrun.c" and so
+ * will (almost) immediately do a resume.
+ *
+ * On the other hand, if we are VFORKING, which means
+ * that the child and the parent share a process for a
+ * while, we know that "resume" won't be resuming
+ * until the child EXEC event is seen. But we still
+ * don't want to continue, as the event is already
+ * there waiting.
+ */
+ update_thread_state_after_attach (pid, DONT_ATTACH_CONTINUE);
+ } /* STOP succeeded */
+
+ return pid;
+}
+
+int
+hppa_require_detach (int pid, int signal)
+{
+ int tt_status;
+
+ /* If signal is non-zero, we must pass the signal on to the active
+ thread prior to detaching. We do this by continuing the threads
+ with the signal.
+ */
+ if (signal != 0)
+ {
+ errno = 0;
+ threads_continue_all_with_signals (pid, signal);
+ }
+
+ errno = 0;
+ tt_status = call_ttrace (TT_PROC_DETACH,
+ pid,
+ TT_NIL,
+ TT_NIL,
+ TT_NIL);
+
+ errno = 0; /* Ignore any errors. */
+
+ /* process_state? */
+
+ return pid;
+}
+
+/* Given the starting address of a memory page, hash it to a bucket in
+ the memory page dictionary.
+ */
+static int
+get_dictionary_bucket_of_page (CORE_ADDR page_start)
+{
+ int hash;
+
+ hash = (page_start / memory_page_dictionary.page_size);
+ hash = hash % MEMORY_PAGE_DICTIONARY_BUCKET_COUNT;
+
+ return hash;
+}
+
+
+/* Given a memory page's starting address, get (i.e., find an existing
+ or create a new) dictionary entry for the page. The page will be
+ write-protected when this function returns, but may have a reference
+ count of 0 (if the page was newly-added to the dictionary).
+ */
+static memory_page_t *
+get_dictionary_entry_of_page (int pid, CORE_ADDR page_start)
+{
+ int bucket;
+ memory_page_t *page = NULL;
+ memory_page_t *previous_page = NULL;
+
+ /* We're going to be using the dictionary now, than-kew. */
+ require_memory_page_dictionary ();
+
+ /* Try to find an existing dictionary entry for this page. Hash
+ on the page's starting address.
+ */
+ bucket = get_dictionary_bucket_of_page (page_start);
+ page = &memory_page_dictionary.buckets[bucket];
+ while (page != NULL)
+ {
+ if (page->page_start == page_start)
+ break;
+ previous_page = page;
+ page = page->next;
+ }
+
+ /* Did we find a dictionary entry for this page? If not, then
+ add it to the dictionary now.
+ */
+ if (page == NULL)
+ {
+ /* Create a new entry. */
+ page = (memory_page_t *) xmalloc (sizeof (memory_page_t));
+ page->page_start = page_start;
+ page->reference_count = 0;
+ page->next = NULL;
+ page->previous = NULL;
+
+ /* We'll write-protect the page now, if that's allowed. */
+ page->original_permissions = write_protect_page (pid, page_start);
+
+ /* Add the new entry to the dictionary. */
+ page->previous = previous_page;
+ previous_page->next = page;
+
+ memory_page_dictionary.page_count++;
+ }
+
+ return page;
+}
+
+
+static void
+remove_dictionary_entry_of_page (int pid, memory_page_t *page)
+{
+ /* Restore the page's original permissions. */
+ unwrite_protect_page (pid, page->page_start, page->original_permissions);
+
+ /* Kick the page out of the dictionary. */
+ if (page->previous != NULL)
+ page->previous->next = page->next;
+ if (page->next != NULL)
+ page->next->previous = page->previous;
+
+ /* Just in case someone retains a handle to this after it's freed. */
+ page->page_start = (CORE_ADDR) 0;
+
+ memory_page_dictionary.page_count--;
+
+ xfree (page);
+}
+
+
+static void
+hppa_enable_syscall_events (int pid)
+{
+ int tt_status;
+ ttevent_t ttrace_events;
+
+ /* Get the set of events that are currently enabled. */
+ tt_status = call_ttrace (TT_PROC_GET_EVENT_MASK,
+ pid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+
+ /* Add syscall events to that set. */
+ ttrace_events.tte_events |= TTEVT_SYSCALL_ENTRY;
+ ttrace_events.tte_events |= TTEVT_SYSCALL_RETURN;
+
+ tt_status = call_ttrace (TT_PROC_SET_EVENT_MASK,
+ pid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+}
+
+
+static void
+hppa_disable_syscall_events (int pid)
+{
+ int tt_status;
+ ttevent_t ttrace_events;
+
+ /* Get the set of events that are currently enabled. */
+ tt_status = call_ttrace (TT_PROC_GET_EVENT_MASK,
+ pid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+
+ /* Remove syscall events from that set. */
+ ttrace_events.tte_events &= ~TTEVT_SYSCALL_ENTRY;
+ ttrace_events.tte_events &= ~TTEVT_SYSCALL_RETURN;
+
+ tt_status = call_ttrace (TT_PROC_SET_EVENT_MASK,
+ pid,
+ (TTRACE_ARG_TYPE) & ttrace_events,
+ (TTRACE_ARG_TYPE) sizeof (ttrace_events),
+ TT_NIL);
+ if (errno)
+ perror_with_name ("ttrace");
+}
+
+
+/* The address range beginning with START and ending with START+LEN-1
+ (inclusive) is to be watched via page-protection by a new watchpoint.
+ Set protection for all pages that overlap that range.
+
+ Note that our caller sets TYPE to:
+ 0 for a bp_hardware_watchpoint,
+ 1 for a bp_read_watchpoint,
+ 2 for a bp_access_watchpoint
+
+ (Yes, this is intentionally (though lord only knows why) different
+ from the TYPE that is passed to hppa_remove_hw_watchpoint.)
+ */
+int
+hppa_insert_hw_watchpoint (int pid, CORE_ADDR start, LONGEST len, int type)
+{
+ CORE_ADDR page_start;
+ int dictionary_was_empty;
+ int page_size;
+ int page_id;
+ LONGEST range_size_in_pages;
+
+ if (type != 0)
+ error ("read or access hardware watchpoints not supported on HP-UX");
+
+ /* Examine all pages in the address range. */
+ require_memory_page_dictionary ();
+
+ dictionary_was_empty = (memory_page_dictionary.page_count == (LONGEST) 0);
+
+ page_size = memory_page_dictionary.page_size;
+ page_start = (start / page_size) * page_size;
+ range_size_in_pages = ((LONGEST) len + (LONGEST) page_size - 1) / (LONGEST) page_size;
+
+ for (page_id = 0; page_id < range_size_in_pages; page_id++, page_start += page_size)
+ {
+ memory_page_t *page;
+
+ /* This gets the page entered into the dictionary if it was
+ not already entered.
+ */
+ page = get_dictionary_entry_of_page (pid, page_start);
+ page->reference_count++;
+ }
+
+ /* Our implementation depends on seeing calls to kernel code, for the
+ following reason. Here we ask to be notified of syscalls.
+
+ When a protected page is accessed by user code, HP-UX raises a SIGBUS.
+ Fine.
+
+ But when kernel code accesses the page, it doesn't give a SIGBUS.
+ Rather, the system call that touched the page fails, with errno=EFAULT.
+ Not good for us.
+
+ We could accomodate this "feature" by asking to be notified of syscall
+ entries & exits; upon getting an entry event, disabling page-protections;
+ upon getting an exit event, reenabling page-protections and then checking
+ if any watchpoints triggered.
+
+ However, this turns out to be a real performance loser. syscalls are
+ usually a frequent occurrence. Having to unprotect-reprotect all watched
+ pages, and also to then read all watched memory locations and compare for
+ triggers, can be quite expensive.
+
+ Instead, we'll only ask to be notified of syscall exits. When we get
+ one, we'll check whether errno is set. If not, or if it's not EFAULT,
+ we can just continue the inferior.
+
+ If errno is set upon syscall exit to EFAULT, we must perform some fairly
+ hackish stuff to determine whether the failure really was due to a
+ page-protect trap on a watched location.
+ */
+ if (dictionary_was_empty)
+ hppa_enable_syscall_events (pid);
+
+ return 1;
+}
+
+
+/* The address range beginning with START and ending with START+LEN-1
+ (inclusive) was being watched via page-protection by a watchpoint
+ which has been removed. Remove protection for all pages that
+ overlap that range, which are not also being watched by other
+ watchpoints.
+ */
+int
+hppa_remove_hw_watchpoint (int pid, CORE_ADDR start, LONGEST len, int type)
+{
+ CORE_ADDR page_start;
+ int dictionary_is_empty;
+ int page_size;
+ int page_id;
+ LONGEST range_size_in_pages;
+
+ if (type != 0)
+ error ("read or access hardware watchpoints not supported on HP-UX");
+
+ /* Examine all pages in the address range. */
+ require_memory_page_dictionary ();
+
+ page_size = memory_page_dictionary.page_size;
+ page_start = (start / page_size) * page_size;
+ range_size_in_pages = ((LONGEST) len + (LONGEST) page_size - 1) / (LONGEST) page_size;
+
+ for (page_id = 0; page_id < range_size_in_pages; page_id++, page_start += page_size)
+ {
+ memory_page_t *page;
+
+ page = get_dictionary_entry_of_page (pid, page_start);
+ page->reference_count--;
+
+ /* Was this the last reference of this page? If so, then we
+ must scrub the entry from the dictionary, and also restore
+ the page's original permissions.
+ */
+ if (page->reference_count == 0)
+ remove_dictionary_entry_of_page (pid, page);
+ }
+
+ dictionary_is_empty = (memory_page_dictionary.page_count == (LONGEST) 0);
+
+ /* If write protections are currently disallowed, then that implies that
+ wait_for_inferior believes that the inferior is within a system call.
+ Since we want to see both syscall entry and return, it's clearly not
+ good to disable syscall events in this state!
+
+ ??rehrauer: Yeah, it'd be better if we had a specific flag that said,
+ "inferior is between syscall events now". Oh well.
+ */
+ if (dictionary_is_empty && memory_page_dictionary.page_protections_allowed)
+ hppa_disable_syscall_events (pid);
+
+ return 1;
+}
+
+
+/* Could we implement a watchpoint of this type via our available
+ hardware support?
+
+ This query does not consider whether a particular address range
+ could be so watched, but just whether support is generally available
+ for such things. See hppa_range_profitable_for_hw_watchpoint for a
+ query that answers whether a particular range should be watched via
+ hardware support.
+ */
+int
+hppa_can_use_hw_watchpoint (int type, int cnt, int ot)
+{
+ return (type == bp_hardware_watchpoint);
+}
+
+
+/* Assuming we could set a hardware watchpoint on this address, do
+ we think it would be profitable ("a good idea") to do so? If not,
+ we can always set a regular (aka single-step & test) watchpoint
+ on the address...
+ */
+int
+hppa_range_profitable_for_hw_watchpoint (int pid, CORE_ADDR start, LONGEST len)
+{
+ int range_is_stack_based;
+ int range_is_accessible;
+ CORE_ADDR page_start;
+ int page_size;
+ int page;
+ LONGEST range_size_in_pages;
+
+ /* ??rehrauer: For now, say that all addresses are potentially
+ profitable. Possibly later we'll want to test the address
+ for "stackness"?
+ */
+ range_is_stack_based = 0;
+
+ /* If any page in the range is inaccessible, then we cannot
+ really use hardware watchpointing, even though our client
+ thinks we can. In that case, it's actually an error to
+ attempt to use hw watchpoints, so we'll tell our client
+ that the range is "unprofitable", and hope that they listen...
+ */
+ range_is_accessible = 1; /* Until proven otherwise. */
+
+ /* Examine all pages in the address range. */
+ errno = 0;
+ page_size = sysconf (_SC_PAGE_SIZE);
+
+ /* If we can't determine page size, we're hosed. Tell our
+ client it's unprofitable to use hw watchpoints for this
+ range.
+ */
+ if (errno || (page_size <= 0))
+ {
+ errno = 0;
+ return 0;
+ }
+
+ page_start = (start / page_size) * page_size;
+ range_size_in_pages = len / (LONGEST) page_size;
+
+ for (page = 0; page < range_size_in_pages; page++, page_start += page_size)
+ {
+ int tt_status;
+ int page_permissions;
+
+ /* Is this page accessible? */
+ errno = 0;
+ tt_status = call_ttrace (TT_PROC_GET_MPROTECT,
+ pid,
+ (TTRACE_ARG_TYPE) page_start,
+ TT_NIL,
+ (TTRACE_ARG_TYPE) & page_permissions);
+ if (errno || (tt_status < 0))
+ {
+ errno = 0;
+ range_is_accessible = 0;
+ break;
+ }
+
+ /* Yes, go for another... */
+ }
+
+ return (!range_is_stack_based && range_is_accessible);
+}
+
+
+char *
+hppa_pid_or_tid_to_str (ptid_t ptid)
+{
+ static char buf[100]; /* Static because address returned. */
+ pid_t id = PIDGET (ptid);
+
+ /* Does this appear to be a process? If so, print it that way. */
+ if (is_process_id (id))
+ return child_pid_to_str (ptid);
+
+ /* Else, print both the GDB thread number and the system thread id. */
+ sprintf (buf, "thread %d (", pid_to_thread_id (ptid));
+ strcat (buf, hppa_tid_to_str (ptid));
+ strcat (buf, ")\0");
+
+ return buf;
+}
+
+
+void
+hppa_ensure_vforking_parent_remains_stopped (int pid)
+{
+ /* Nothing to do when using ttrace. Only the ptrace-based implementation
+ must do real work.
+ */
+}
+
+
+int
+hppa_resume_execd_vforking_child_to_get_parent_vfork (void)
+{
+ return 0; /* No, the parent vfork is available now. */
+}
+
+
+/* Write a register as a 64bit value. This may be necessary if the
+ native OS is too braindamaged to allow some (or all) registers to
+ be written in 32bit hunks such as hpux11 and the PC queue registers.
+
+ This is horribly gross and disgusting. */
+
+int
+ttrace_write_reg_64 (int gdb_tid, CORE_ADDR dest_addr, CORE_ADDR src_addr)
+{
+ pid_t pid;
+ lwpid_t tid;
+ int tt_status;
+
+ tid = map_from_gdb_tid (gdb_tid);
+ pid = get_pid_for (tid);
+
+ errno = 0;
+ tt_status = ttrace (TT_LWP_WUREGS,
+ pid,
+ tid,
+ (TTRACE_ARG_TYPE) dest_addr,
+ 8,
+ (TTRACE_ARG_TYPE) src_addr );
+
+#ifdef THREAD_DEBUG
+ if (errno)
+ {
+ /* Don't bother for a known benign error: if you ask for the
+ first thread state, but there is only one thread and it's
+ not stopped, ttrace complains.
+
+ We have this inside the #ifdef because our caller will do
+ this check for real. */
+ if( request != TT_PROC_GET_FIRST_LWP_STATE
+ || errno != EPROTO )
+ {
+ if( debug_on )
+ printf( "TT fail for %s, with pid %d, tid %d, status %d \n",
+ get_printable_name_of_ttrace_request (TT_LWP_WUREGS),
+ pid, tid, tt_status );
+ }
+ }
+#endif
+
+ return tt_status;
+}
+
+void
+_initialize_infttrace (void)
+{
+ /* Initialize the ttrace-based hardware watchpoint implementation. */
+ memory_page_dictionary.page_count = (LONGEST) - 1;
+ memory_page_dictionary.page_protections_allowed = 1;
+
+ errno = 0;
+ memory_page_dictionary.page_size = sysconf (_SC_PAGE_SIZE);
+
+ /* We do a lot of casts from pointers to TTRACE_ARG_TYPE; make sure
+ this is okay. */
+ if (sizeof (TTRACE_ARG_TYPE) < sizeof (void *))
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ if (errno || (memory_page_dictionary.page_size <= 0))
+ perror_with_name ("sysconf");
+}
diff --git a/contrib/gdb/gdb/infttrace.h b/contrib/gdb/gdb/infttrace.h
new file mode 100644
index 0000000..d3330e3
--- /dev/null
+++ b/contrib/gdb/gdb/infttrace.h
@@ -0,0 +1,28 @@
+/* Low level Unix child interface to ttrace, for GDB when running under HP-UX.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 INFTTRACE_H
+#define INFTTRACE_H
+
+extern int parent_attach_all (int, PTRACE_ARG3_TYPE, int);
+extern pid_t hppa_switched_threads (pid_t gdb_pid);
+
+#endif
diff --git a/contrib/gdb/gdb/interps.c b/contrib/gdb/gdb/interps.c
new file mode 100644
index 0000000..82e9af6
--- /dev/null
+++ b/contrib/gdb/gdb/interps.c
@@ -0,0 +1,486 @@
+/* Manages interpreters for GDB, the GNU debugger.
+
+ Copyright 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 just a first cut at separating out the "interpreter"
+ functions of gdb into self-contained modules. There are a couple
+ of open areas that need to be sorted out:
+
+ 1) The interpreter explicitly contains a UI_OUT, and can insert itself
+ into the event loop, but it doesn't explicitly contain hooks for readline.
+ I did this because it seems to me many interpreters won't want to use
+ the readline command interface, and it is probably simpler to just let
+ them take over the input in their resume proc. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "ui-out.h"
+#include "event-loop.h"
+#include "event-top.h"
+#include "interps.h"
+#include "completer.h"
+#include "gdb_string.h"
+#include "gdb-events.h"
+#include "gdb_assert.h"
+#include "top.h" /* For command_loop. */
+
+struct interp
+{
+ /* This is the name in "-i=" and set interpreter. */
+ const char *name;
+
+ /* Interpreters are stored in a linked list, this is the next
+ one... */
+ struct interp *next;
+
+ /* This is a cookie that an instance of the interpreter can use.
+ This is a bit confused right now as the exact initialization
+ sequence for it, and how it relates to the interpreter's uiout
+ object is a bit confused. */
+ void *data;
+
+ /* Has the init_proc been run? */
+ int inited;
+
+ /* This is the ui_out used to collect results for this interpreter.
+ It can be a formatter for stdout, as is the case for the console
+ & mi outputs, or it might be a result formatter. */
+ struct ui_out *interpreter_out;
+
+ const struct interp_procs *procs;
+ int quiet_p;
+};
+
+/* Functions local to this file. */
+static void initialize_interps (void);
+static char **interpreter_completer (char *text, char *word);
+
+/* The magic initialization routine for this module. */
+
+void _initialize_interpreter (void);
+
+/* Variables local to this file: */
+
+static struct interp *interp_list = NULL;
+static struct interp *current_interpreter = NULL;
+
+static int interpreter_initialized = 0;
+
+/* interp_new - This allocates space for a new interpreter,
+ fills the fields from the inputs, and returns a pointer to the
+ interpreter. */
+struct interp *
+interp_new (const char *name, void *data, struct ui_out *uiout,
+ const struct interp_procs *procs)
+{
+ struct interp *new_interp;
+
+ new_interp = XMALLOC (struct interp);
+
+ new_interp->name = xstrdup (name);
+ new_interp->data = data;
+ new_interp->interpreter_out = uiout;
+ new_interp->quiet_p = 0;
+ new_interp->procs = procs;
+ new_interp->inited = 0;
+
+ return new_interp;
+}
+
+/* Add interpreter INTERP to the gdb interpreter list. The
+ interpreter must not have previously been added. */
+void
+interp_add (struct interp *interp)
+{
+ if (!interpreter_initialized)
+ initialize_interps ();
+
+ gdb_assert (interp_lookup (interp->name) == NULL);
+
+ interp->next = interp_list;
+ interp_list = interp;
+}
+
+/* This sets the current interpreter to be INTERP. If INTERP has not
+ been initialized, then this will also run the init proc. If the
+ init proc is successful, return 1, if it fails, set the old
+ interpreter back in place and return 0. If we can't restore the
+ old interpreter, then raise an internal error, since we are in
+ pretty bad shape at this point. */
+int
+interp_set (struct interp *interp)
+{
+ struct interp *old_interp = current_interpreter;
+ int first_time = 0;
+
+
+ char buffer[64];
+
+ if (current_interpreter != NULL)
+ {
+ do_all_continuations ();
+ ui_out_flush (uiout);
+ if (current_interpreter->procs->suspend_proc
+ && !current_interpreter->procs->suspend_proc (current_interpreter->
+ data))
+ {
+ error ("Could not suspend interpreter \"%s\"\n",
+ current_interpreter->name);
+ }
+ }
+ else
+ {
+ first_time = 1;
+ }
+
+ current_interpreter = interp;
+
+ /* We use interpreter_p for the "set interpreter" variable, so we need
+ to make sure we have a malloc'ed copy for the set command to free. */
+ if (interpreter_p != NULL
+ && strcmp (current_interpreter->name, interpreter_p) != 0)
+ {
+ xfree (interpreter_p);
+
+ interpreter_p = xstrdup (current_interpreter->name);
+ }
+
+ uiout = interp->interpreter_out;
+
+ /* Run the init proc. If it fails, try to restore the old interp. */
+
+ if (!interp->inited)
+ {
+ if (interp->procs->init_proc != NULL)
+ {
+ interp->data = interp->procs->init_proc ();
+ }
+ interp->inited = 1;
+ }
+
+ /* Clear out any installed interpreter hooks/event handlers. */
+ clear_interpreter_hooks ();
+
+ if (interp->procs->resume_proc != NULL
+ && (!interp->procs->resume_proc (interp->data)))
+ {
+ if (old_interp == NULL || !interp_set (old_interp))
+ internal_error (__FILE__, __LINE__,
+ "Failed to initialize new interp \"%s\" %s",
+ interp->name, "and could not restore old interp!\n");
+ return 0;
+ }
+
+ /* Finally, put up the new prompt to show that we are indeed here.
+ Also, display_gdb_prompt for the console does some readline magic
+ which is needed for the console interpreter, at least... */
+
+ if (!first_time)
+ {
+ if (!interp_quiet_p (interp))
+ {
+ sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
+ interp->name);
+ ui_out_text (uiout, buffer);
+ }
+ display_gdb_prompt (NULL);
+ }
+
+ return 1;
+}
+
+/* interp_lookup - Looks up the interpreter for NAME. If no such
+ interpreter exists, return NULL, otherwise return a pointer to the
+ interpreter. */
+struct interp *
+interp_lookup (const char *name)
+{
+ struct interp *interp;
+
+ if (name == NULL || strlen (name) == 0)
+ return NULL;
+
+ for (interp = interp_list; interp != NULL; interp = interp->next)
+ {
+ if (strcmp (interp->name, name) == 0)
+ return interp;
+ }
+
+ return NULL;
+}
+
+/* Returns the current interpreter. */
+
+struct ui_out *
+interp_ui_out (struct interp *interp)
+{
+ if (interp != NULL)
+ return interp->interpreter_out;
+
+ return current_interpreter->interpreter_out;
+}
+
+/* Returns true if the current interp is the passed in name. */
+int
+current_interp_named_p (const char *interp_name)
+{
+ if (current_interpreter)
+ return (strcmp (current_interpreter->name, interp_name) == 0);
+
+ return 0;
+}
+
+/* This is called in display_gdb_prompt. If the proc returns a zero
+ value, display_gdb_prompt will return without displaying the
+ prompt. */
+int
+current_interp_display_prompt_p (void)
+{
+ if (current_interpreter == NULL
+ || current_interpreter->procs->prompt_proc_p == NULL)
+ return 0;
+ else
+ return current_interpreter->procs->prompt_proc_p (current_interpreter->
+ data);
+}
+
+/* Run the current command interpreter's main loop. */
+void
+current_interp_command_loop (void)
+{
+ /* Somewhat messy. For the moment prop up all the old ways of
+ selecting the command loop. `command_loop_hook' should be
+ deprecated. */
+ if (command_loop_hook != NULL)
+ command_loop_hook ();
+ else if (current_interpreter != NULL
+ && current_interpreter->procs->command_loop_proc != NULL)
+ current_interpreter->procs->command_loop_proc (current_interpreter->data);
+ else if (event_loop_p)
+ cli_command_loop ();
+ else
+ command_loop ();
+}
+
+int
+interp_quiet_p (struct interp *interp)
+{
+ if (interp != NULL)
+ return interp->quiet_p;
+ else
+ return current_interpreter->quiet_p;
+}
+
+static int
+interp_set_quiet (struct interp *interp, int quiet)
+{
+ int old_val = interp->quiet_p;
+ interp->quiet_p = quiet;
+ return old_val;
+}
+
+/* interp_exec - This executes COMMAND_STR in the current
+ interpreter. */
+int
+interp_exec_p (struct interp *interp)
+{
+ return interp->procs->exec_proc != NULL;
+}
+
+int
+interp_exec (struct interp *interp, const char *command_str)
+{
+ if (interp->procs->exec_proc != NULL)
+ {
+ return interp->procs->exec_proc (interp->data, command_str);
+ }
+ return 0;
+}
+
+/* A convenience routine that nulls out all the
+ common command hooks. Use it when removing your interpreter in its
+ suspend proc. */
+void
+clear_interpreter_hooks (void)
+{
+ init_ui_hook = 0;
+ print_frame_info_listing_hook = 0;
+ /*print_frame_more_info_hook = 0; */
+ query_hook = 0;
+ warning_hook = 0;
+ create_breakpoint_hook = 0;
+ delete_breakpoint_hook = 0;
+ modify_breakpoint_hook = 0;
+ interactive_hook = 0;
+ registers_changed_hook = 0;
+ readline_begin_hook = 0;
+ readline_hook = 0;
+ readline_end_hook = 0;
+ register_changed_hook = 0;
+ memory_changed_hook = 0;
+ context_hook = 0;
+ target_wait_hook = 0;
+ call_command_hook = 0;
+ error_hook = 0;
+ error_begin_hook = 0;
+ command_loop_hook = 0;
+ clear_gdb_event_hooks ();
+}
+
+/* This is a lazy init routine, called the first time
+ the interpreter module is used. I put it here just in case, but I haven't
+ thought of a use for it yet. I will probably bag it soon, since I don't
+ think it will be necessary. */
+static void
+initialize_interps (void)
+{
+ interpreter_initialized = 1;
+ /* Don't know if anything needs to be done here... */
+}
+
+static void
+interpreter_exec_cmd (char *args, int from_tty)
+{
+ struct interp *old_interp, *interp_to_use;
+ char **prules = NULL;
+ char **trule = NULL;
+ unsigned int nrules;
+ unsigned int i;
+ int old_quiet, use_quiet;
+
+ prules = buildargv (args);
+ if (prules == NULL)
+ {
+ error ("unable to parse arguments");
+ }
+
+ nrules = 0;
+ if (prules != NULL)
+ {
+ for (trule = prules; *trule != NULL; trule++)
+ {
+ nrules++;
+ }
+ }
+
+ if (nrules < 2)
+ error ("usage: interpreter-exec <interpreter> [ <command> ... ]");
+
+ old_interp = current_interpreter;
+
+ interp_to_use = interp_lookup (prules[0]);
+ if (interp_to_use == NULL)
+ error ("Could not find interpreter \"%s\".", prules[0]);
+
+ /* Temporarily set interpreters quiet */
+ old_quiet = interp_set_quiet (old_interp, 1);
+ use_quiet = interp_set_quiet (interp_to_use, 1);
+
+ if (!interp_set (interp_to_use))
+ error ("Could not switch to interpreter \"%s\".", prules[0]);
+
+ for (i = 1; i < nrules; i++)
+ {
+ if (!interp_exec (interp_to_use, prules[i]))
+ {
+ interp_set (old_interp);
+ interp_set_quiet (interp_to_use, old_quiet);
+ error ("error in command: \"%s\".", prules[i]);
+ break;
+ }
+ }
+
+ interp_set (old_interp);
+ interp_set_quiet (interp_to_use, use_quiet);
+ interp_set_quiet (old_interp, old_quiet);
+}
+
+/* List the possible interpreters which could complete the given text. */
+static char **
+interpreter_completer (char *text, char *word)
+{
+ int alloced = 0;
+ int textlen;
+ int num_matches;
+ char **matches;
+ struct interp *interp;
+
+ /* We expect only a very limited number of interpreters, so just
+ allocate room for all of them. */
+ for (interp = interp_list; interp != NULL; interp = interp->next)
+ ++alloced;
+ matches = (char **) xmalloc (alloced * sizeof (char *));
+
+ num_matches = 0;
+ textlen = strlen (text);
+ for (interp = interp_list; interp != NULL; interp = interp->next)
+ {
+ if (strncmp (interp->name, text, textlen) == 0)
+ {
+ matches[num_matches] =
+ (char *) xmalloc (strlen (word) + strlen (interp->name) + 1);
+ if (word == text)
+ strcpy (matches[num_matches], interp->name);
+ else if (word > text)
+ {
+ /* Return some portion of interp->name */
+ strcpy (matches[num_matches], interp->name + (word - text));
+ }
+ else
+ {
+ /* Return some of text plus interp->name */
+ strncpy (matches[num_matches], word, text - word);
+ matches[num_matches][text - word] = '\0';
+ strcat (matches[num_matches], interp->name);
+ }
+ ++num_matches;
+ }
+ }
+
+ if (num_matches == 0)
+ {
+ xfree (matches);
+ matches = NULL;
+ }
+ else if (num_matches < alloced)
+ {
+ matches = (char **) xrealloc ((char *) matches, ((num_matches + 1)
+ * sizeof (char *)));
+ matches[num_matches] = NULL;
+ }
+
+ return matches;
+}
+
+/* This just adds the "interpreter-exec" command. */
+void
+_initialize_interpreter (void)
+{
+ struct cmd_list_element *c;
+
+ c = add_cmd ("interpreter-exec", class_support,
+ interpreter_exec_cmd,
+ "Execute a command in an interpreter. It takes two arguments:\n\
+The first argument is the name of the interpreter to use.\n\
+The second argument is the command to execute.\n", &cmdlist);
+ set_cmd_completer (c, interpreter_completer);
+}
diff --git a/contrib/gdb/gdb/interps.h b/contrib/gdb/gdb/interps.h
new file mode 100644
index 0000000..8e3257b
--- /dev/null
+++ b/contrib/gdb/gdb/interps.h
@@ -0,0 +1,76 @@
+/* Manages interpreters for GDB, the GNU debugger.
+
+ Copyright 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 INTERPS_H
+#define INTERPS_H
+
+struct ui_out;
+struct interp;
+
+extern int interp_resume (struct interp *interp);
+extern int interp_suspend (struct interp *interp);
+extern int interp_prompt_p (struct interp *interp);
+extern int interp_exec_p (struct interp *interp);
+extern int interp_exec (struct interp *interp, const char *command);
+extern int interp_quiet_p (struct interp *interp);
+
+typedef void *(interp_init_ftype) (void);
+typedef int (interp_resume_ftype) (void *data);
+typedef int (interp_suspend_ftype) (void *data);
+typedef int (interp_prompt_p_ftype) (void *data);
+typedef int (interp_exec_ftype) (void *data, const char *command);
+typedef void (interp_command_loop_ftype) (void *data);
+
+struct interp_procs
+{
+ interp_init_ftype *init_proc;
+ interp_resume_ftype *resume_proc;
+ interp_suspend_ftype *suspend_proc;
+ interp_exec_ftype *exec_proc;
+ interp_prompt_p_ftype *prompt_proc_p;
+ interp_command_loop_ftype *command_loop_proc;
+};
+
+extern struct interp *interp_new (const char *name, void *data,
+ struct ui_out *uiout,
+ const struct interp_procs *procs);
+extern void interp_add (struct interp *interp);
+extern int interp_set (struct interp *interp);
+extern struct interp *interp_lookup (const char *name);
+extern struct ui_out *interp_ui_out (struct interp *interp);
+
+extern int current_interp_named_p (const char *name);
+extern int current_interp_display_prompt_p (void);
+extern void current_interp_command_loop (void);
+
+extern void clear_interpreter_hooks (void);
+
+/* well-known interpreters */
+#define INTERP_CONSOLE "console"
+#define INTERP_MI1 "mi1"
+#define INTERP_MI2 "mi2"
+#define INTERP_MI3 "mi3"
+#define INTERP_MI "mi"
+#define INTERP_TUI "tui"
+
+#endif
diff --git a/contrib/gdb/gdb/jv-exp.c b/contrib/gdb/gdb/jv-exp.c
new file mode 100644
index 0000000..17b792d
--- /dev/null
+++ b/contrib/gdb/gdb/jv-exp.c
@@ -0,0 +1,2842 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INTEGER_LITERAL = 258,
+ FLOATING_POINT_LITERAL = 259,
+ IDENTIFIER = 260,
+ STRING_LITERAL = 261,
+ BOOLEAN_LITERAL = 262,
+ TYPENAME = 263,
+ NAME_OR_INT = 264,
+ ERROR = 265,
+ LONG = 266,
+ SHORT = 267,
+ BYTE = 268,
+ INT = 269,
+ CHAR = 270,
+ BOOLEAN = 271,
+ DOUBLE = 272,
+ FLOAT = 273,
+ VARIABLE = 274,
+ ASSIGN_MODIFY = 275,
+ SUPER = 276,
+ NEW = 277,
+ OROR = 278,
+ ANDAND = 279,
+ NOTEQUAL = 280,
+ EQUAL = 281,
+ GEQ = 282,
+ LEQ = 283,
+ RSH = 284,
+ LSH = 285,
+ DECREMENT = 286,
+ INCREMENT = 287
+ };
+#endif
+#define INTEGER_LITERAL 258
+#define FLOATING_POINT_LITERAL 259
+#define IDENTIFIER 260
+#define STRING_LITERAL 261
+#define BOOLEAN_LITERAL 262
+#define TYPENAME 263
+#define NAME_OR_INT 264
+#define ERROR 265
+#define LONG 266
+#define SHORT 267
+#define BYTE 268
+#define INT 269
+#define CHAR 270
+#define BOOLEAN 271
+#define DOUBLE 272
+#define FLOAT 273
+#define VARIABLE 274
+#define ASSIGN_MODIFY 275
+#define SUPER 276
+#define NEW 277
+#define OROR 278
+#define ANDAND 279
+#define NOTEQUAL 280
+#define EQUAL 281
+#define GEQ 282
+#define LEQ 283
+#define RSH 284
+#define LSH 285
+#define DECREMENT 286
+#define INCREMENT 287
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 38 "jv-exp.y"
+
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "jv-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "block.h"
+
+/* 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 java_maxdepth
+#define yyparse java_parse
+#define yylex java_lex
+#define yyerror java_error
+#define yylval java_lval
+#define yychar java_char
+#define yydebug java_debug
+#define yypact java_pact
+#define yyr1 java_r1
+#define yyr2 java_r2
+#define yydef java_def
+#define yychk java_chk
+#define yypgo java_pgo
+#define yyact java_act
+#define yyexca java_exca
+#define yyerrflag java_errflag
+#define yynerrs java_nerrs
+#define yyps java_ps
+#define yypv java_pv
+#define yys java_s
+#define yy_yys java_yys
+#define yystate java_state
+#define yytmp java_tmp
+#define yyv java_v
+#define yy_yyv java_yyv
+#define yyval java_val
+#define yylloc java_lloc
+#define yyreds java_reds /* With YYDEBUG defined */
+#define yytoks java_toks /* With YYDEBUG defined */
+#define yyname java_name /* With YYDEBUG defined */
+#define yyrule java_rule /* With YYDEBUG defined */
+#define yylhs java_yylhs
+#define yylen java_yylen
+#define yydefred java_yydefred
+#define yydgoto java_yydgoto
+#define yysindex java_yysindex
+#define yyrindex java_yyrindex
+#define yygindex java_yygindex
+#define yytable java_yytable
+#define yycheck java_yycheck
+
+#ifndef YYDEBUG
+#define YYDEBUG 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static struct type *java_type_from_name (struct stoken);
+static void push_expression_name (struct stoken);
+static void push_fieldnames (struct stoken);
+
+static struct expression *copy_exp (struct expression *, int);
+static void insert_exp (int, struct expression *);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 127 "jv-exp.y"
+typedef union YYSTYPE {
+ 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;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+ int *ivec;
+ } YYSTYPE;
+/* Line 191 of yacc.c. */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+#line 148 "jv-exp.y"
+
+/* YYSTYPE gets defined by %union */
+static int parse_number (char *, int, int, YYSTYPE *);
+
+
+/* Line 214 of yacc.c. */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC xmalloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 97
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 421
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 56
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 56
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 130
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 207
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 287
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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, 54, 2, 2, 2, 43, 30, 2,
+ 48, 49, 41, 39, 23, 40, 46, 42, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 55, 2,
+ 33, 24, 34, 25, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 47, 2, 52, 29, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 50, 28, 51, 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, 26, 27,
+ 31, 32, 35, 36, 37, 38, 44, 45
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 11, 13, 15, 17,
+ 19, 21, 23, 25, 27, 29, 31, 33, 35, 37,
+ 39, 41, 43, 45, 47, 49, 51, 54, 57, 59,
+ 61, 63, 65, 67, 69, 73, 75, 79, 81, 83,
+ 85, 89, 91, 93, 95, 97, 101, 103, 105, 111,
+ 113, 117, 118, 120, 125, 130, 132, 135, 139, 142,
+ 146, 148, 149, 153, 157, 162, 169, 176, 181, 186,
+ 191, 193, 195, 197, 199, 201, 204, 207, 209, 211,
+ 214, 217, 220, 222, 225, 228, 230, 233, 236, 238,
+ 244, 249, 255, 257, 261, 265, 269, 271, 275, 279,
+ 281, 285, 289, 291, 295, 299, 303, 307, 309, 313,
+ 317, 319, 323, 325, 329, 331, 335, 337, 341, 343,
+ 347, 349, 355, 357, 359, 363, 367, 369, 371, 373,
+ 375
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 57, 0, -1, 73, -1, 58, -1, 59, -1, 62,
+ -1, 68, -1, 6, -1, 3, -1, 9, -1, 4,
+ -1, 7, -1, 60, -1, 63, -1, 16, -1, 64,
+ -1, 65, -1, 13, -1, 12, -1, 14, -1, 11,
+ -1, 15, -1, 18, -1, 17, -1, 69, -1, 66,
+ -1, 62, 84, -1, 69, 84, -1, 5, -1, 72,
+ -1, 71, -1, 72, -1, 5, -1, 9, -1, 69,
+ 46, 71, -1, 111, -1, 73, 23, 111, -1, 75,
+ -1, 81, -1, 61, -1, 48, 111, 49, -1, 78,
+ -1, 86, -1, 87, -1, 88, -1, 76, 79, 77,
+ -1, 50, -1, 51, -1, 22, 67, 48, 80, 49,
+ -1, 111, -1, 79, 23, 111, -1, -1, 79, -1,
+ 22, 62, 82, 85, -1, 22, 66, 82, 85, -1,
+ 83, -1, 82, 83, -1, 47, 111, 52, -1, 47,
+ 52, -1, 84, 47, 52, -1, 84, -1, -1, 74,
+ 46, 71, -1, 19, 46, 71, -1, 69, 48, 80,
+ 49, -1, 74, 46, 71, 48, 80, 49, -1, 21,
+ 46, 71, 48, 80, 49, -1, 69, 47, 111, 52,
+ -1, 19, 47, 111, 52, -1, 75, 47, 111, 52,
+ -1, 74, -1, 69, -1, 19, -1, 90, -1, 91,
+ -1, 89, 45, -1, 89, 44, -1, 93, -1, 94,
+ -1, 39, 92, -1, 40, 92, -1, 41, 92, -1,
+ 95, -1, 45, 92, -1, 44, 92, -1, 89, -1,
+ 53, 92, -1, 54, 92, -1, 96, -1, 48, 62,
+ 85, 49, 92, -1, 48, 111, 49, 95, -1, 48,
+ 69, 84, 49, 95, -1, 92, -1, 97, 41, 92,
+ -1, 97, 42, 92, -1, 97, 43, 92, -1, 97,
+ -1, 98, 39, 97, -1, 98, 40, 97, -1, 98,
+ -1, 99, 38, 98, -1, 99, 37, 98, -1, 99,
+ -1, 100, 33, 99, -1, 100, 34, 99, -1, 100,
+ 36, 99, -1, 100, 35, 99, -1, 100, -1, 101,
+ 32, 100, -1, 101, 31, 100, -1, 101, -1, 102,
+ 30, 101, -1, 102, -1, 103, 29, 102, -1, 103,
+ -1, 104, 28, 103, -1, 104, -1, 105, 27, 104,
+ -1, 105, -1, 106, 26, 105, -1, 106, -1, 106,
+ 25, 111, 55, 107, -1, 107, -1, 109, -1, 110,
+ 24, 107, -1, 110, 20, 107, -1, 70, -1, 19,
+ -1, 86, -1, 88, -1, 108, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 204, 204, 205, 208, 217, 218, 222, 231, 236,
+ 244, 249, 254, 265, 266, 271, 272, 276, 278, 280,
+ 282, 284, 289, 291, 303, 308, 312, 314, 319, 320,
+ 324, 325, 329, 330, 334, 357, 358, 363, 364, 368,
+ 369, 370, 371, 372, 373, 374, 382, 387, 392, 398,
+ 400, 406, 407, 411, 414, 420, 421, 425, 429, 431,
+ 436, 438, 442, 444, 450, 452, 454, 459, 476, 478,
+ 483, 484, 486, 488, 489, 493, 498, 503, 504, 505,
+ 506, 508, 510, 514, 519, 524, 525, 527, 529, 533,
+ 537, 558, 566, 567, 569, 571, 576, 577, 579, 584,
+ 585, 587, 593, 594, 596, 598, 600, 606, 607, 609,
+ 614, 615, 620, 621, 625, 626, 631, 632, 637, 638,
+ 643, 644, 649, 650, 654, 656, 663, 665, 667, 668,
+ 673
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INTEGER_LITERAL",
+ "FLOATING_POINT_LITERAL", "IDENTIFIER", "STRING_LITERAL",
+ "BOOLEAN_LITERAL", "TYPENAME", "NAME_OR_INT", "ERROR", "LONG", "SHORT",
+ "BYTE", "INT", "CHAR", "BOOLEAN", "DOUBLE", "FLOAT", "VARIABLE",
+ "ASSIGN_MODIFY", "SUPER", "NEW", "','", "'='", "'?'", "OROR", "ANDAND",
+ "'|'", "'^'", "'&'", "NOTEQUAL", "EQUAL", "'<'", "'>'", "GEQ", "LEQ",
+ "RSH", "LSH", "'+'", "'-'", "'*'", "'/'", "'%'", "DECREMENT",
+ "INCREMENT", "'.'", "'['", "'('", "')'", "'{'", "'}'", "']'", "'~'",
+ "'!'", "':'", "$accept", "start", "type_exp", "PrimitiveOrArrayType",
+ "StringLiteral", "Literal", "PrimitiveType", "NumericType",
+ "IntegralType", "FloatingPointType", "ClassOrInterfaceType",
+ "ClassType", "ArrayType", "Name", "ForcedName", "SimpleName",
+ "QualifiedName", "exp1", "Primary", "PrimaryNoNewArray", "lcurly",
+ "rcurly", "ClassInstanceCreationExpression", "ArgumentList",
+ "ArgumentList_opt", "ArrayCreationExpression", "DimExprs", "DimExpr",
+ "Dims", "Dims_opt", "FieldAccess", "MethodInvocation", "ArrayAccess",
+ "PostfixExpression", "PostIncrementExpression",
+ "PostDecrementExpression", "UnaryExpression", "PreIncrementExpression",
+ "PreDecrementExpression", "UnaryExpressionNotPlusMinus",
+ "CastExpression", "MultiplicativeExpression", "AdditiveExpression",
+ "ShiftExpression", "RelationalExpression", "EqualityExpression",
+ "AndExpression", "ExclusiveOrExpression", "InclusiveOrExpression",
+ "ConditionalAndExpression", "ConditionalOrExpression",
+ "ConditionalExpression", "AssignmentExpression", "Assignment",
+ "LeftHandSide", "Expression", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 44, 61, 63, 278, 279, 124, 94,
+ 38, 280, 281, 60, 62, 282, 283, 284, 285, 43,
+ 45, 42, 47, 37, 286, 287, 46, 91, 40, 41,
+ 123, 125, 93, 126, 33, 58
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 56, 57, 57, 58, 59, 59, 60, 61, 61,
+ 61, 61, 61, 62, 62, 63, 63, 64, 64, 64,
+ 64, 64, 65, 65, 66, 67, 68, 68, 69, 69,
+ 70, 70, 71, 71, 72, 73, 73, 74, 74, 75,
+ 75, 75, 75, 75, 75, 75, 76, 77, 78, 79,
+ 79, 80, 80, 81, 81, 82, 82, 83, 84, 84,
+ 85, 85, 86, 86, 87, 87, 87, 88, 88, 88,
+ 89, 89, 89, 89, 89, 90, 91, 92, 92, 92,
+ 92, 92, 92, 93, 94, 95, 95, 95, 95, 96,
+ 96, 96, 97, 97, 97, 97, 98, 98, 98, 99,
+ 99, 99, 100, 100, 100, 100, 100, 101, 101, 101,
+ 102, 102, 103, 103, 104, 104, 105, 105, 106, 106,
+ 107, 107, 108, 108, 109, 109, 110, 110, 110, 110,
+ 111
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
+ 1, 1, 1, 1, 3, 1, 3, 1, 1, 1,
+ 3, 1, 1, 1, 1, 3, 1, 1, 5, 1,
+ 3, 0, 1, 4, 4, 1, 2, 3, 2, 3,
+ 1, 0, 3, 3, 4, 6, 6, 4, 4, 4,
+ 1, 1, 1, 1, 1, 2, 2, 1, 1, 2,
+ 2, 2, 1, 2, 2, 1, 2, 2, 1, 5,
+ 4, 5, 1, 3, 3, 3, 1, 3, 3, 1,
+ 3, 3, 1, 3, 3, 3, 3, 1, 3, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+ 1, 5, 1, 1, 3, 3, 1, 1, 1, 1,
+ 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 0, 8, 10, 28, 7, 11, 9, 20, 18, 17,
+ 19, 21, 14, 23, 22, 72, 0, 0, 0, 0,
+ 0, 0, 0, 0, 46, 0, 0, 0, 3, 4,
+ 12, 39, 5, 13, 15, 16, 6, 71, 126, 30,
+ 29, 2, 70, 37, 0, 41, 38, 42, 43, 44,
+ 85, 73, 74, 92, 77, 78, 82, 88, 96, 99,
+ 102, 107, 110, 112, 114, 116, 118, 120, 122, 130,
+ 123, 0, 35, 0, 0, 0, 28, 0, 25, 0,
+ 24, 29, 9, 72, 71, 42, 44, 79, 80, 81,
+ 84, 83, 61, 71, 0, 86, 87, 1, 0, 26,
+ 0, 0, 51, 27, 0, 0, 0, 0, 49, 76,
+ 75, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 32, 33, 63, 0, 0, 0, 61, 55,
+ 61, 51, 0, 60, 0, 0, 40, 58, 0, 34,
+ 0, 52, 0, 36, 62, 0, 0, 47, 45, 93,
+ 94, 95, 97, 98, 101, 100, 103, 104, 106, 105,
+ 109, 108, 111, 113, 115, 117, 0, 119, 125, 124,
+ 68, 51, 0, 0, 56, 53, 54, 0, 0, 0,
+ 90, 59, 67, 64, 51, 69, 50, 0, 0, 57,
+ 48, 89, 91, 0, 121, 66, 65
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short yydefgoto[] =
+{
+ -1, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 78, 79, 36, 84, 38, 39, 81, 41, 42, 43,
+ 44, 158, 45, 151, 152, 46, 138, 139, 143, 144,
+ 85, 48, 86, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 108
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -135
+static const short yypact[] =
+{
+ 204, -135, -135, 8, -135, -135, 14, -135, -135, -135,
+ -135, -135, -135, -135, -135, -4, 5, 50, 308, 308,
+ 308, 308, 308, 204, -135, 308, 308, 40, -135, -135,
+ -135, -135, -1, -135, -135, -135, -135, 37, -135, -135,
+ 28, 36, 45, 46, 360, -135, -135, 33, -135, 49,
+ -19, -135, -135, -135, -135, -135, -135, -135, 84, 31,
+ 95, 54, 89, 75, 74, 81, 88, 110, -135, -135,
+ -135, 52, -135, 73, 360, 73, -135, 64, 64, 69,
+ 77, -135, -135, 92, 83, -135, -135, -135, -135, -135,
+ -135, -135, -1, 37, 103, -135, -135, -135, 107, 114,
+ 73, 256, 360, 114, 360, 73, 360, -6, -135, -135,
+ -135, 308, 308, 308, 308, 308, 308, 308, 308, 308,
+ 308, 308, 308, 308, 308, 308, 308, 308, 360, 308,
+ 308, 308, -135, -135, -135, 111, 116, 360, 118, -135,
+ 118, 360, 360, 114, 117, -16, 367, -135, 115, -135,
+ 120, 146, 121, -135, 125, 123, 360, -135, -135, -135,
+ -135, -135, 84, 84, 31, 31, 95, 95, 95, 95,
+ 54, 54, 89, 75, 74, 81, 122, 88, -135, -135,
+ -135, 360, 124, 256, -135, -135, -135, 129, 308, 367,
+ -135, -135, -135, -135, 360, -135, -135, 308, 130, -135,
+ -135, -135, -135, 131, -135, -135, -135
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const short yypgoto[] =
+{
+ -135, -135, -135, -135, -135, -135, 4, -135, -135, -135,
+ -135, -135, -135, 13, -135, -51, 0, -135, -135, -135,
+ -135, -135, -135, 138, -134, -135, 106, -101, -18, -59,
+ 6, -135, 12, -135, -135, -135, -17, -135, -135, -131,
+ -135, 30, 34, -21, 35, 61, 63, 60, 65, 62,
+ -135, -120, -135, -135, -135, 18
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -130
+static const short yytable[] =
+{
+ 40, 87, 88, 89, 90, 91, 47, 187, 95, 96,
+ 178, 179, 49, 37, 99, 190, -127, 156, 72, 103,
+ -127, 77, 134, 40, 136, 109, 110, 92, -32, 47,
+ 80, 148, -32, 189, -33, 49, 93, 184, -33, 184,
+ 97, 94, 73, 74, 40, 157, 98, 198, -31, 149,
+ 47, 75, -31, -128, 154, 76, 49, -128, 202, 104,
+ 203, 7, 8, 9, 10, 11, 12, 13, 14, -129,
+ 114, 115, 130, -129, 40, 145, 131, 204, 132, 185,
+ 47, 186, 133, 100, 101, 102, 49, 118, 119, 120,
+ 121, 105, 135, 106, 159, 160, 161, 166, 167, 168,
+ 169, 40, 40, 125, 40, 124, 40, 47, 47, 126,
+ 47, 137, 47, 49, 49, 127, 49, 141, 49, 150,
+ 122, 123, 153, 100, 155, 111, 112, 113, 40, 100,
+ 142, 102, 116, 117, 47, 128, 129, 40, 73, 74,
+ 49, 40, 40, 47, 162, 163, 176, 47, 47, 49,
+ 164, 165, 146, 49, 49, 182, 40, 170, 171, 147,
+ 150, 148, 47, 180, 181, 183, 188, 191, 49, 156,
+ 193, 201, 192, 194, 196, 195, 199, 197, 200, 205,
+ 206, 40, 107, 40, 140, 172, 174, 47, 173, 47,
+ 0, 177, 175, 49, 40, 49, 0, 0, 0, 0,
+ 47, 182, 0, 0, 0, 0, 49, 1, 2, 3,
+ 4, 5, 0, 6, 0, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 0, 16, 17, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 18, 19, 20, 0, 0, 21, 22,
+ 0, 0, 23, 0, 24, 0, 0, 25, 26, 1,
+ 2, 3, 4, 5, 0, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 15, 0, 16, 17, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 18, 19, 20, 0, 0,
+ 21, 22, 0, 0, 23, 0, 24, 0, 147, 25,
+ 26, 1, 2, 76, 4, 5, 0, 82, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 83, 0, 16,
+ 17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 18, 19, 20,
+ 0, 0, 21, 22, 0, 0, 23, 0, 24, 0,
+ 0, 25, 26, 1, 2, 3, 4, 5, 0, 6,
+ 1, 2, 76, 4, 5, 0, 82, 0, 0, 15,
+ 0, 16, 17, 0, 0, 0, 83, 0, 16, 17,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 18,
+ 19, 20, 0, 0, 21, 22, 0, 0, 23, 0,
+ 24, 0, 0, 25, 26, 23, 0, 24, 0, 0,
+ 25, 26
+};
+
+static const short yycheck[] =
+{
+ 0, 18, 19, 20, 21, 22, 0, 141, 25, 26,
+ 130, 131, 0, 0, 32, 146, 20, 23, 0, 37,
+ 24, 17, 73, 23, 75, 44, 45, 23, 20, 23,
+ 17, 47, 24, 49, 20, 23, 23, 138, 24, 140,
+ 0, 23, 46, 47, 44, 51, 47, 181, 20, 100,
+ 44, 46, 24, 20, 105, 5, 44, 24, 189, 23,
+ 194, 11, 12, 13, 14, 15, 16, 17, 18, 20,
+ 39, 40, 20, 24, 74, 93, 24, 197, 5, 138,
+ 74, 140, 9, 46, 47, 48, 74, 33, 34, 35,
+ 36, 46, 74, 47, 111, 112, 113, 118, 119, 120,
+ 121, 101, 102, 29, 104, 30, 106, 101, 102, 28,
+ 104, 47, 106, 101, 102, 27, 104, 48, 106, 101,
+ 31, 32, 104, 46, 106, 41, 42, 43, 128, 46,
+ 47, 48, 37, 38, 128, 25, 26, 137, 46, 47,
+ 128, 141, 142, 137, 114, 115, 128, 141, 142, 137,
+ 116, 117, 49, 141, 142, 137, 156, 122, 123, 52,
+ 142, 47, 156, 52, 48, 47, 49, 52, 156, 23,
+ 49, 188, 52, 48, 156, 52, 52, 55, 49, 49,
+ 49, 181, 44, 183, 78, 124, 126, 181, 125, 183,
+ -1, 129, 127, 181, 194, 183, -1, -1, -1, -1,
+ 194, 183, -1, -1, -1, -1, 194, 3, 4, 5,
+ 6, 7, -1, 9, -1, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, -1, 21, 22, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 39, 40, 41, -1, -1, 44, 45,
+ -1, -1, 48, -1, 50, -1, -1, 53, 54, 3,
+ 4, 5, 6, 7, -1, 9, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 19, -1, 21, 22, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 39, 40, 41, -1, -1,
+ 44, 45, -1, -1, 48, -1, 50, -1, 52, 53,
+ 54, 3, 4, 5, 6, 7, -1, 9, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 19, -1, 21,
+ 22, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 39, 40, 41,
+ -1, -1, 44, 45, -1, -1, 48, -1, 50, -1,
+ -1, 53, 54, 3, 4, 5, 6, 7, -1, 9,
+ 3, 4, 5, 6, 7, -1, 9, -1, -1, 19,
+ -1, 21, 22, -1, -1, -1, 19, -1, 21, 22,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 39,
+ 40, 41, -1, -1, 44, 45, -1, -1, 48, -1,
+ 50, -1, -1, 53, 54, 48, -1, 50, -1, -1,
+ 53, 54
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 9, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 21, 22, 39, 40,
+ 41, 44, 45, 48, 50, 53, 54, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 78, 81, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 46, 47, 46, 5, 62, 66, 67,
+ 69, 72, 9, 19, 69, 86, 88, 92, 92, 92,
+ 92, 92, 62, 69, 111, 92, 92, 0, 47, 84,
+ 46, 47, 48, 84, 23, 46, 47, 79, 111, 44,
+ 45, 41, 42, 43, 39, 40, 37, 38, 33, 34,
+ 35, 36, 31, 32, 30, 29, 28, 27, 25, 26,
+ 20, 24, 5, 9, 71, 111, 71, 47, 82, 83,
+ 82, 48, 47, 84, 85, 84, 49, 52, 47, 71,
+ 111, 79, 80, 111, 71, 111, 23, 51, 77, 92,
+ 92, 92, 97, 97, 98, 98, 99, 99, 99, 99,
+ 100, 100, 101, 102, 103, 104, 111, 105, 107, 107,
+ 52, 48, 111, 47, 83, 85, 85, 80, 49, 49,
+ 95, 52, 52, 49, 48, 52, 111, 55, 80, 52,
+ 49, 92, 95, 80, 107, 49, 49
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to xreallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to xreallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 209 "jv-exp.y"
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(yyvsp[0].tval);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+ break;
+
+ case 7:
+#line 223 "jv-exp.y"
+ {
+ write_exp_elt_opcode (OP_STRING);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_STRING);
+ }
+ break;
+
+ case 8:
+#line 232 "jv-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 9:
+#line 237 "jv-exp.y"
+ { YYSTYPE val;
+ parse_number (yyvsp[0].sval.ptr, yyvsp[0].sval.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 10:
+#line 245 "jv-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 11:
+#line 250 "jv-exp.y"
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (java_boolean_type);
+ write_exp_elt_longcst ((LONGEST)yyvsp[0].lval);
+ write_exp_elt_opcode (OP_LONG); }
+ break;
+
+ case 14:
+#line 267 "jv-exp.y"
+ { yyval.tval = java_boolean_type; }
+ break;
+
+ case 17:
+#line 277 "jv-exp.y"
+ { yyval.tval = java_byte_type; }
+ break;
+
+ case 18:
+#line 279 "jv-exp.y"
+ { yyval.tval = java_short_type; }
+ break;
+
+ case 19:
+#line 281 "jv-exp.y"
+ { yyval.tval = java_int_type; }
+ break;
+
+ case 20:
+#line 283 "jv-exp.y"
+ { yyval.tval = java_long_type; }
+ break;
+
+ case 21:
+#line 285 "jv-exp.y"
+ { yyval.tval = java_char_type; }
+ break;
+
+ case 22:
+#line 290 "jv-exp.y"
+ { yyval.tval = java_float_type; }
+ break;
+
+ case 23:
+#line 292 "jv-exp.y"
+ { yyval.tval = java_double_type; }
+ break;
+
+ case 24:
+#line 304 "jv-exp.y"
+ { yyval.tval = java_type_from_name (yyvsp[0].sval); }
+ break;
+
+ case 26:
+#line 313 "jv-exp.y"
+ { yyval.tval = java_array_type (yyvsp[-1].tval, yyvsp[0].lval); }
+ break;
+
+ case 27:
+#line 315 "jv-exp.y"
+ { yyval.tval = java_array_type (java_type_from_name (yyvsp[-1].sval), yyvsp[0].lval); }
+ break;
+
+ case 34:
+#line 335 "jv-exp.y"
+ { yyval.sval.length = yyvsp[-2].sval.length + yyvsp[0].sval.length + 1;
+ if (yyvsp[-2].sval.ptr + yyvsp[-2].sval.length + 1 == yyvsp[0].sval.ptr
+ && yyvsp[-2].sval.ptr[yyvsp[-2].sval.length] == '.')
+ yyval.sval.ptr = yyvsp[-2].sval.ptr; /* Optimization. */
+ else
+ {
+ yyval.sval.ptr = (char *) xmalloc (yyval.sval.length + 1);
+ make_cleanup (free, yyval.sval.ptr);
+ sprintf (yyval.sval.ptr, "%.*s.%.*s",
+ yyvsp[-2].sval.length, yyvsp[-2].sval.ptr, yyvsp[0].sval.length, yyvsp[0].sval.ptr);
+ } }
+ break;
+
+ case 36:
+#line 359 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ break;
+
+ case 45:
+#line 375 "jv-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 46:
+#line 383 "jv-exp.y"
+ { start_arglist (); }
+ break;
+
+ case 47:
+#line 388 "jv-exp.y"
+ { yyval.lval = end_arglist () - 1; }
+ break;
+
+ case 48:
+#line 393 "jv-exp.y"
+ { internal_error (__FILE__, __LINE__,
+ _("FIXME - ClassInstanceCreationExpression")); }
+ break;
+
+ case 49:
+#line 399 "jv-exp.y"
+ { arglist_len = 1; }
+ break;
+
+ case 50:
+#line 401 "jv-exp.y"
+ { arglist_len++; }
+ break;
+
+ case 51:
+#line 406 "jv-exp.y"
+ { arglist_len = 0; }
+ break;
+
+ case 53:
+#line 412 "jv-exp.y"
+ { internal_error (__FILE__, __LINE__,
+ _("FIXME - ArrayCreationExpression")); }
+ break;
+
+ case 54:
+#line 415 "jv-exp.y"
+ { internal_error (__FILE__, __LINE__,
+ _("FIXME - ArrayCreationExpression")); }
+ break;
+
+ case 58:
+#line 430 "jv-exp.y"
+ { yyval.lval = 1; }
+ break;
+
+ case 59:
+#line 432 "jv-exp.y"
+ { yyval.lval = yyvsp[-2].lval + 1; }
+ break;
+
+ case 61:
+#line 438 "jv-exp.y"
+ { yyval.lval = 0; }
+ break;
+
+ case 62:
+#line 443 "jv-exp.y"
+ { push_fieldnames (yyvsp[0].sval); }
+ break;
+
+ case 63:
+#line 445 "jv-exp.y"
+ { push_fieldnames (yyvsp[0].sval); }
+ break;
+
+ case 64:
+#line 451 "jv-exp.y"
+ { error (_("Method invocation not implemented")); }
+ break;
+
+ case 65:
+#line 453 "jv-exp.y"
+ { error (_("Method invocation not implemented")); }
+ break;
+
+ case 66:
+#line 455 "jv-exp.y"
+ { error (_("Method invocation not implemented")); }
+ break;
+
+ case 67:
+#line 460 "jv-exp.y"
+ {
+ /* Emit code for the Name now, then exchange it in the
+ expout array with the Expression's code. We could
+ introduce a OP_SWAP code or a reversed version of
+ BINOP_SUBSCRIPT, but that makes the rest of GDB pay
+ for our parsing kludges. */
+ struct expression *name_expr;
+
+ push_expression_name (yyvsp[-3].sval);
+ name_expr = copy_exp (expout, expout_ptr);
+ expout_ptr -= name_expr->nelts;
+ insert_exp (expout_ptr-length_of_subexp (expout, expout_ptr),
+ name_expr);
+ free (name_expr);
+ write_exp_elt_opcode (BINOP_SUBSCRIPT);
+ }
+ break;
+
+ case 68:
+#line 477 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ break;
+
+ case 69:
+#line 479 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ break;
+
+ case 71:
+#line 485 "jv-exp.y"
+ { push_expression_name (yyvsp[0].sval); }
+ break;
+
+ case 75:
+#line 494 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+ break;
+
+ case 76:
+#line 499 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+ break;
+
+ case 80:
+#line 507 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_NEG); }
+ break;
+
+ case 81:
+#line 509 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_IND); }
+ break;
+
+ case 83:
+#line 515 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ break;
+
+ case 84:
+#line 520 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ break;
+
+ case 86:
+#line 526 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+ break;
+
+ case 87:
+#line 528 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ break;
+
+ case 89:
+#line 534 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (java_array_type (yyvsp[-3].tval, yyvsp[-2].lval));
+ write_exp_elt_opcode (UNOP_CAST); }
+ break;
+
+ case 90:
+#line 538 "jv-exp.y"
+ {
+ int exp_size = expout_ptr;
+ int last_exp_size = length_of_subexp(expout, expout_ptr);
+ struct type *type;
+ int i;
+ int base = expout_ptr - last_exp_size - 3;
+ if (base < 0 || expout->elts[base+2].opcode != OP_TYPE)
+ error (_("Invalid cast expression"));
+ type = expout->elts[base+1].type;
+ /* Remove the 'Expression' and slide the
+ UnaryExpressionNotPlusMinus down to replace it. */
+ for (i = 0; i < last_exp_size; i++)
+ expout->elts[base + i] = expout->elts[base + i + 3];
+ expout_ptr -= 3;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ type = lookup_pointer_type (type);
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (type);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+ break;
+
+ case 91:
+#line 559 "jv-exp.y"
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (java_array_type (java_type_from_name (yyvsp[-3].sval), yyvsp[-2].lval));
+ write_exp_elt_opcode (UNOP_CAST); }
+ break;
+
+ case 93:
+#line 568 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_MUL); }
+ break;
+
+ case 94:
+#line 570 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_DIV); }
+ break;
+
+ case 95:
+#line 572 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_REM); }
+ break;
+
+ case 97:
+#line 578 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_ADD); }
+ break;
+
+ case 98:
+#line 580 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_SUB); }
+ break;
+
+ case 100:
+#line 586 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_LSH); }
+ break;
+
+ case 101:
+#line 588 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_RSH); }
+ break;
+
+ case 103:
+#line 595 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_LESS); }
+ break;
+
+ case 104:
+#line 597 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_GTR); }
+ break;
+
+ case 105:
+#line 599 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ break;
+
+ case 106:
+#line 601 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ break;
+
+ case 108:
+#line 608 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ break;
+
+ case 109:
+#line 610 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 111:
+#line 616 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ break;
+
+ case 113:
+#line 622 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ break;
+
+ case 115:
+#line 627 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ break;
+
+ case 117:
+#line 633 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ break;
+
+ case 119:
+#line 639 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ break;
+
+ case 121:
+#line 645 "jv-exp.y"
+ { write_exp_elt_opcode (TERNOP_COND); }
+ break;
+
+ case 124:
+#line 655 "jv-exp.y"
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ break;
+
+ case 125:
+#line 657 "jv-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 126:
+#line 664 "jv-exp.y"
+ { push_expression_name (yyvsp[0].sval); }
+ break;
+
+
+ }
+
+/* Line 991 of yacc.c. */
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ 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)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab2;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+
+ /* Suppress GCC warning that yyerrlab1 is unused when no action
+ invokes YYERROR. Doesn't work in C++ */
+#ifndef __cplusplus
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+#endif
+#endif
+
+
+ goto yyerrlab2;
+
+
+/*---------------------------------------------------------------.
+| yyerrlab2 -- pop states until the error token can be shifted. |
+`---------------------------------------------------------------*/
+yyerrlab2:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 676 "jv-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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ ULONGEST n = 0;
+ ULONGEST limit, limit_div_base;
+
+ int c;
+ int base = input_radix;
+
+ struct type *type;
+
+ if (parsed_float)
+ {
+ /* It's a float since it contains a point or an exponent. */
+ char c;
+ int num = 0; /* number of tokens scanned by scanf */
+ char saved_char = p[len];
+
+ p[len] = 0; /* null-terminate the token */
+ if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
+ num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval, &c);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval, &c);
+ else
+ {
+#ifdef SCANF_HAS_LONG_DOUBLE
+ num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval, &c);
+#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;
+ num = sscanf (p, "%lg%c", &temp, &c);
+ putithere->typed_val_float.dval = temp;
+#endif
+ }
+ p[len] = saved_char; /* restore the input stream */
+ if (num != 1) /* check scanf found ONLY a float ... */
+ return ERROR;
+ /* See if it has `f' or `d' suffix (float or double). */
+
+ c = tolower (p[len - 1]);
+
+ if (c == 'f' || c == 'F')
+ putithere->typed_val_float.type = builtin_type_float;
+ else if (isdigit (c) || c == '.' || c == 'd' || c == 'D')
+ putithere->typed_val_float.type = builtin_type_double;
+ else
+ return ERROR;
+
+ return FLOATING_POINT_LITERAL;
+ }
+
+ /* 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;
+ }
+
+ c = p[len-1];
+ /* A paranoid calculation of (1<<64)-1. */
+ limit = (ULONGEST)0xffffffff;
+ limit = ((limit << 16) << 16) | limit;
+ if (c == 'l' || c == 'L')
+ {
+ type = java_long_type;
+ len--;
+ }
+ else
+ {
+ type = java_int_type;
+ }
+ limit_div_base = limit / (ULONGEST) base;
+
+ while (--len >= 0)
+ {
+ c = *p++;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ return ERROR; /* Char not a digit */
+ if (c >= base)
+ return ERROR;
+ if (n > limit_div_base
+ || (n *= base) > limit - c)
+ error (_("Numeric constant too large"));
+ n += c;
+ }
+
+ /* If the type is bigger than a 32-bit signed integer can be, implicitly
+ promote to long. Java does not do this, so mark it as builtin_type_uint64
+ rather than java_long_type. 0x80000000 will become -0x80000000 instead
+ of 0x80000000L, because we don't know the sign at this point.
+ */
+ if (type == java_int_type && n > (ULONGEST)0x80000000)
+ type = builtin_type_uint64;
+
+ putithere->typed_val_int.val = n;
+ putithere->typed_val_int.type = type;
+
+ return INTEGER_LITERAL;
+}
+
+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},
+ {"&&", ANDAND, BINOP_END},
+ {"||", OROR, 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:
+
+ prev_lexptr = lexptr;
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
+ if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ 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 = java_char_type;
+
+ 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 INTEGER_LITERAL;
+
+ 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;
+ 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 '}':
+ 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_LITERAL);
+ }
+
+ 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 7:
+ if (DEPRECATED_STREQN (tokstart, "boolean", 7))
+ return BOOLEAN;
+ break;
+ case 6:
+ if (DEPRECATED_STREQN (tokstart, "double", 6))
+ return DOUBLE;
+ break;
+ case 5:
+ if (DEPRECATED_STREQN (tokstart, "short", 5))
+ return SHORT;
+ if (DEPRECATED_STREQN (tokstart, "false", 5))
+ {
+ yylval.lval = 0;
+ return BOOLEAN_LITERAL;
+ }
+ if (DEPRECATED_STREQN (tokstart, "super", 5))
+ return SUPER;
+ if (DEPRECATED_STREQN (tokstart, "float", 5))
+ return FLOAT;
+ break;
+ case 4:
+ if (DEPRECATED_STREQN (tokstart, "long", 4))
+ return LONG;
+ if (DEPRECATED_STREQN (tokstart, "byte", 4))
+ return BYTE;
+ if (DEPRECATED_STREQN (tokstart, "char", 4))
+ return CHAR;
+ if (DEPRECATED_STREQN (tokstart, "true", 4))
+ {
+ yylval.lval = 1;
+ return BOOLEAN_LITERAL;
+ }
+ break;
+ case 3:
+ if (strncmp (tokstart, "int", 3) == 0)
+ return INT;
+ if (strncmp (tokstart, "new", 3) == 0)
+ return NEW;
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ if (*tokstart == '$')
+ {
+ write_dollar_variable (yylval.sval);
+ return VARIABLE;
+ }
+
+ /* 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 (((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) ||
+ (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
+ {
+ YYSTYPE newlval; /* Its value is ignored. */
+ int hextype = parse_number (tokstart, namelen, 0, &newlval);
+ if (hextype == INTEGER_LITERAL)
+ return NAME_OR_INT;
+ }
+ return IDENTIFIER;
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ if (msg)
+ error (_("%s: near `%s'"), msg, lexptr);
+ else
+ error (_("error in expression, near `%s'"), lexptr);
+}
+
+static struct type *
+java_type_from_name (name)
+ struct stoken name;
+
+{
+ char *tmp = copy_name (name);
+ struct type *typ = java_lookup_class (tmp);
+ if (typ == NULL || TYPE_CODE (typ) != TYPE_CODE_STRUCT)
+ error (_("No class named `%s'"), tmp);
+ return typ;
+}
+
+/* If NAME is a valid variable name in this scope, push it and return 1.
+ Otherwise, return 0. */
+
+static int
+push_variable (struct stoken name)
+{
+ char *tmp = copy_name (name);
+ int is_a_field_of_this = 0;
+ struct symbol *sym;
+ sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN,
+ &is_a_field_of_this, (struct symtab **) NULL);
+ if (sym && SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ {
+ 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);
+ return 1;
+ }
+ if (is_a_field_of_this)
+ {
+ /* 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 (name);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ return 1;
+ }
+ return 0;
+}
+
+/* Assuming a reference expression has been pushed, emit the
+ STRUCTOP_STRUCT ops to access the field named NAME. If NAME is a
+ qualified name (has '.'), generate a field access for each part. */
+
+static void
+push_fieldnames (name)
+ struct stoken name;
+{
+ int i;
+ struct stoken token;
+ token.ptr = name.ptr;
+ for (i = 0; ; i++)
+ {
+ if (i == name.length || name.ptr[i] == '.')
+ {
+ /* token.ptr is start of current field name. */
+ token.length = &name.ptr[i] - token.ptr;
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (token);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ token.ptr += token.length + 1;
+ }
+ if (i >= name.length)
+ break;
+ }
+}
+
+/* Helper routine for push_expression_name.
+ Handle a qualified name, where DOT_INDEX is the index of the first '.' */
+
+static void
+push_qualified_expression_name (struct stoken name, int dot_index)
+{
+ struct stoken token;
+ char *tmp;
+ struct type *typ;
+
+ token.ptr = name.ptr;
+ token.length = dot_index;
+
+ if (push_variable (token))
+ {
+ token.ptr = name.ptr + dot_index + 1;
+ token.length = name.length - dot_index - 1;
+ push_fieldnames (token);
+ return;
+ }
+
+ token.ptr = name.ptr;
+ for (;;)
+ {
+ token.length = dot_index;
+ tmp = copy_name (token);
+ typ = java_lookup_class (tmp);
+ if (typ != NULL)
+ {
+ if (dot_index == name.length)
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(typ);
+ write_exp_elt_opcode(OP_TYPE);
+ return;
+ }
+ dot_index++; /* Skip '.' */
+ name.ptr += dot_index;
+ name.length -= dot_index;
+ dot_index = 0;
+ while (dot_index < name.length && name.ptr[dot_index] != '.')
+ dot_index++;
+ token.ptr = name.ptr;
+ token.length = dot_index;
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (typ);
+ write_exp_string (token);
+ write_exp_elt_opcode (OP_SCOPE);
+ if (dot_index < name.length)
+ {
+ dot_index++;
+ name.ptr += dot_index;
+ name.length -= dot_index;
+ push_fieldnames (name);
+ }
+ return;
+ }
+ else if (dot_index >= name.length)
+ break;
+ dot_index++; /* Skip '.' */
+ while (dot_index < name.length && name.ptr[dot_index] != '.')
+ dot_index++;
+ }
+ error (_("unknown type `%.*s'"), name.length, name.ptr);
+}
+
+/* Handle Name in an expression (or LHS).
+ Handle VAR, TYPE, TYPE.FIELD1....FIELDN and VAR.FIELD1....FIELDN. */
+
+static void
+push_expression_name (name)
+ struct stoken name;
+{
+ char *tmp;
+ struct type *typ;
+ char *ptr;
+ int i;
+
+ for (i = 0; i < name.length; i++)
+ {
+ if (name.ptr[i] == '.')
+ {
+ /* It's a Qualified Expression Name. */
+ push_qualified_expression_name (name, i);
+ return;
+ }
+ }
+
+ /* It's a Simple Expression Name. */
+
+ if (push_variable (name))
+ return;
+ tmp = copy_name (name);
+ typ = java_lookup_class (tmp);
+ if (typ != NULL)
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(typ);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+
+ msymbol = lookup_minimal_symbol (tmp, 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"), tmp);
+ }
+
+}
+
+
+/* The following two routines, copy_exp and insert_exp, aren't specific to
+ Java, so they could go in parse.c, but their only purpose is to support
+ the parsing kludges we use in this file, so maybe it's best to isolate
+ them here. */
+
+/* Copy the expression whose last element is at index ENDPOS - 1 in EXPR
+ into a freshly xmalloc'ed struct expression. Its language_defn is set
+ to null. */
+static struct expression *
+copy_exp (expr, endpos)
+ struct expression *expr;
+ int endpos;
+{
+ int len = length_of_subexp (expr, endpos);
+ struct expression *new
+ = (struct expression *) xmalloc (sizeof (*new) + EXP_ELEM_TO_BYTES (len));
+ new->nelts = len;
+ memcpy (new->elts, expr->elts + endpos - len, EXP_ELEM_TO_BYTES (len));
+ new->language_defn = 0;
+
+ return new;
+}
+
+/* Insert the expression NEW into the current expression (expout) at POS. */
+static void
+insert_exp (pos, new)
+ int pos;
+ struct expression *new;
+{
+ int newlen = new->nelts;
+
+ /* Grow expout if necessary. In this function's only use at present,
+ this should never be necessary. */
+ if (expout_ptr + newlen > expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + newlen + 10);
+ expout = (struct expression *)
+ xrealloc ((char *) expout, (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size)));
+ }
+
+ {
+ int i;
+
+ for (i = expout_ptr - 1; i >= pos; i--)
+ expout->elts[i + newlen] = expout->elts[i];
+ }
+
+ memcpy (expout->elts + pos, new->elts, EXP_ELEM_TO_BYTES (newlen));
+ expout_ptr += newlen;
+}
+
+
diff --git a/contrib/gdb/gdb/jv-exp.y b/contrib/gdb/gdb/jv-exp.y
new file mode 100644
index 0000000..41da7d0
--- /dev/null
+++ b/contrib/gdb/gdb/jv-exp.y
@@ -0,0 +1,1469 @@
+/* YACC parser for Java expressions, for GDB.
+ Copyright 1997, 1998, 1999, 2000
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 Java 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. Well, almost always; see ArrayAccess.
+
+ 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 (<malloc.h> and <stdlib.h> 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 <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "jv-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "block.h"
+
+/* 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 java_maxdepth
+#define yyparse java_parse
+#define yylex java_lex
+#define yyerror java_error
+#define yylval java_lval
+#define yychar java_char
+#define yydebug java_debug
+#define yypact java_pact
+#define yyr1 java_r1
+#define yyr2 java_r2
+#define yydef java_def
+#define yychk java_chk
+#define yypgo java_pgo
+#define yyact java_act
+#define yyexca java_exca
+#define yyerrflag java_errflag
+#define yynerrs java_nerrs
+#define yyps java_ps
+#define yypv java_pv
+#define yys java_s
+#define yy_yys java_yys
+#define yystate java_state
+#define yytmp java_tmp
+#define yyv java_v
+#define yy_yyv java_yyv
+#define yyval java_val
+#define yylloc java_lloc
+#define yyreds java_reds /* With YYDEBUG defined */
+#define yytoks java_toks /* With YYDEBUG defined */
+#define yyname java_name /* With YYDEBUG defined */
+#define yyrule java_rule /* With YYDEBUG defined */
+#define yylhs java_yylhs
+#define yylen java_yylen
+#define yydefred java_yydefred
+#define yydgoto java_yydgoto
+#define yysindex java_yysindex
+#define yyrindex java_yyrindex
+#define yygindex java_yygindex
+#define yytable java_yytable
+#define yycheck java_yycheck
+
+#ifndef YYDEBUG
+#define YYDEBUG 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static struct type *java_type_from_name (struct stoken);
+static void push_expression_name (struct stoken);
+static void push_fieldnames (struct stoken);
+
+static struct expression *copy_exp (struct expression *, int);
+static void insert_exp (int, struct expression *);
+
+%}
+
+/* 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;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+ int *ivec;
+ }
+
+%{
+/* YYSTYPE gets defined by %union */
+static int parse_number (char *, int, int, YYSTYPE *);
+%}
+
+%type <lval> rcurly Dims Dims_opt
+%type <tval> ClassOrInterfaceType ClassType /* ReferenceType Type ArrayType */
+%type <tval> IntegralType FloatingPointType NumericType PrimitiveType ArrayType PrimitiveOrArrayType
+
+%token <typed_val_int> INTEGER_LITERAL
+%token <typed_val_float> FLOATING_POINT_LITERAL
+
+%token <sval> IDENTIFIER
+%token <sval> STRING_LITERAL
+%token <lval> BOOLEAN_LITERAL
+%token <tsym> TYPENAME
+%type <sval> Name SimpleName QualifiedName ForcedName
+
+/* 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 <sval> NAME_OR_INT
+
+%token ERROR
+
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+%token LONG SHORT BYTE INT CHAR BOOLEAN DOUBLE FLOAT
+
+%token VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+%token SUPER NEW
+
+%left ','
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '+' '-'
+%left '*' '/' '%'
+%right INCREMENT DECREMENT
+%right '.' '[' '('
+
+
+%%
+
+start : exp1
+ | type_exp
+ ;
+
+type_exp: PrimitiveOrArrayType
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+ ;
+
+PrimitiveOrArrayType:
+ PrimitiveType
+ | ArrayType
+ ;
+
+StringLiteral:
+ STRING_LITERAL
+ {
+ write_exp_elt_opcode (OP_STRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_STRING);
+ }
+;
+
+Literal:
+ INTEGER_LITERAL
+ { 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); }
+| NAME_OR_INT
+ { YYSTYPE val;
+ parse_number ($1.ptr, $1.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);
+ }
+| FLOATING_POINT_LITERAL
+ { write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_dblcst ($1.dval);
+ write_exp_elt_opcode (OP_DOUBLE); }
+| BOOLEAN_LITERAL
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (java_boolean_type);
+ write_exp_elt_longcst ((LONGEST)$1);
+ write_exp_elt_opcode (OP_LONG); }
+| StringLiteral
+ ;
+
+/* UNUSED:
+Type:
+ PrimitiveType
+| ReferenceType
+;
+*/
+
+PrimitiveType:
+ NumericType
+| BOOLEAN
+ { $$ = java_boolean_type; }
+;
+
+NumericType:
+ IntegralType
+| FloatingPointType
+;
+
+IntegralType:
+ BYTE
+ { $$ = java_byte_type; }
+| SHORT
+ { $$ = java_short_type; }
+| INT
+ { $$ = java_int_type; }
+| LONG
+ { $$ = java_long_type; }
+| CHAR
+ { $$ = java_char_type; }
+;
+
+FloatingPointType:
+ FLOAT
+ { $$ = java_float_type; }
+| DOUBLE
+ { $$ = java_double_type; }
+;
+
+/* UNUSED:
+ReferenceType:
+ ClassOrInterfaceType
+| ArrayType
+;
+*/
+
+ClassOrInterfaceType:
+ Name
+ { $$ = java_type_from_name ($1); }
+;
+
+ClassType:
+ ClassOrInterfaceType
+;
+
+ArrayType:
+ PrimitiveType Dims
+ { $$ = java_array_type ($1, $2); }
+| Name Dims
+ { $$ = java_array_type (java_type_from_name ($1), $2); }
+;
+
+Name:
+ IDENTIFIER
+| QualifiedName
+;
+
+ForcedName:
+ SimpleName
+| QualifiedName
+;
+
+SimpleName:
+ IDENTIFIER
+| NAME_OR_INT
+;
+
+QualifiedName:
+ Name '.' SimpleName
+ { $$.length = $1.length + $3.length + 1;
+ if ($1.ptr + $1.length + 1 == $3.ptr
+ && $1.ptr[$1.length] == '.')
+ $$.ptr = $1.ptr; /* Optimization. */
+ else
+ {
+ $$.ptr = (char *) malloc ($$.length + 1);
+ make_cleanup (free, $$.ptr);
+ sprintf ($$.ptr, "%.*s.%.*s",
+ $1.length, $1.ptr, $3.length, $3.ptr);
+ } }
+;
+
+/*
+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 : Expression
+ | exp1 ',' Expression
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ ;
+
+Primary:
+ PrimaryNoNewArray
+| ArrayCreationExpression
+;
+
+PrimaryNoNewArray:
+ Literal
+| '(' Expression ')'
+| ClassInstanceCreationExpression
+| FieldAccess
+| MethodInvocation
+| ArrayAccess
+| lcurly ArgumentList rcurly
+ { write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) $3);
+ write_exp_elt_opcode (OP_ARRAY); }
+;
+
+lcurly:
+ '{'
+ { start_arglist (); }
+;
+
+rcurly:
+ '}'
+ { $$ = end_arglist () - 1; }
+;
+
+ClassInstanceCreationExpression:
+ NEW ClassType '(' ArgumentList_opt ')'
+ { internal_error (__FILE__, __LINE__,
+ _("FIXME - ClassInstanceCreationExpression")); }
+;
+
+ArgumentList:
+ Expression
+ { arglist_len = 1; }
+| ArgumentList ',' Expression
+ { arglist_len++; }
+;
+
+ArgumentList_opt:
+ /* EMPTY */
+ { arglist_len = 0; }
+| ArgumentList
+;
+
+ArrayCreationExpression:
+ NEW PrimitiveType DimExprs Dims_opt
+ { internal_error (__FILE__, __LINE__,
+ _("FIXME - ArrayCreationExpression")); }
+| NEW ClassOrInterfaceType DimExprs Dims_opt
+ { internal_error (__FILE__, __LINE__,
+ _("FIXME - ArrayCreationExpression")); }
+;
+
+DimExprs:
+ DimExpr
+| DimExprs DimExpr
+;
+
+DimExpr:
+ '[' Expression ']'
+;
+
+Dims:
+ '[' ']'
+ { $$ = 1; }
+| Dims '[' ']'
+ { $$ = $1 + 1; }
+;
+
+Dims_opt:
+ Dims
+| /* EMPTY */
+ { $$ = 0; }
+;
+
+FieldAccess:
+ Primary '.' SimpleName
+ { push_fieldnames ($3); }
+| VARIABLE '.' SimpleName
+ { push_fieldnames ($3); }
+/*| SUPER '.' SimpleName { FIXME } */
+;
+
+MethodInvocation:
+ Name '(' ArgumentList_opt ')'
+ { error (_("Method invocation not implemented")); }
+| Primary '.' SimpleName '(' ArgumentList_opt ')'
+ { error (_("Method invocation not implemented")); }
+| SUPER '.' SimpleName '(' ArgumentList_opt ')'
+ { error (_("Method invocation not implemented")); }
+;
+
+ArrayAccess:
+ Name '[' Expression ']'
+ {
+ /* Emit code for the Name now, then exchange it in the
+ expout array with the Expression's code. We could
+ introduce a OP_SWAP code or a reversed version of
+ BINOP_SUBSCRIPT, but that makes the rest of GDB pay
+ for our parsing kludges. */
+ struct expression *name_expr;
+
+ push_expression_name ($1);
+ name_expr = copy_exp (expout, expout_ptr);
+ expout_ptr -= name_expr->nelts;
+ insert_exp (expout_ptr-length_of_subexp (expout, expout_ptr),
+ name_expr);
+ free (name_expr);
+ write_exp_elt_opcode (BINOP_SUBSCRIPT);
+ }
+| VARIABLE '[' Expression ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+| PrimaryNoNewArray '[' Expression ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+;
+
+PostfixExpression:
+ Primary
+| Name
+ { push_expression_name ($1); }
+| VARIABLE
+ /* Already written by write_dollar_variable. */
+| PostIncrementExpression
+| PostDecrementExpression
+;
+
+PostIncrementExpression:
+ PostfixExpression INCREMENT
+ { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+;
+
+PostDecrementExpression:
+ PostfixExpression DECREMENT
+ { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+;
+
+UnaryExpression:
+ PreIncrementExpression
+| PreDecrementExpression
+| '+' UnaryExpression
+| '-' UnaryExpression
+ { write_exp_elt_opcode (UNOP_NEG); }
+| '*' UnaryExpression
+ { write_exp_elt_opcode (UNOP_IND); } /*FIXME not in Java */
+| UnaryExpressionNotPlusMinus
+;
+
+PreIncrementExpression:
+ INCREMENT UnaryExpression
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+;
+
+PreDecrementExpression:
+ DECREMENT UnaryExpression
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+;
+
+UnaryExpressionNotPlusMinus:
+ PostfixExpression
+| '~' UnaryExpression
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+| '!' UnaryExpression
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+| CastExpression
+ ;
+
+CastExpression:
+ '(' PrimitiveType Dims_opt ')' UnaryExpression
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (java_array_type ($2, $3));
+ write_exp_elt_opcode (UNOP_CAST); }
+| '(' Expression ')' UnaryExpressionNotPlusMinus
+ {
+ int exp_size = expout_ptr;
+ int last_exp_size = length_of_subexp(expout, expout_ptr);
+ struct type *type;
+ int i;
+ int base = expout_ptr - last_exp_size - 3;
+ if (base < 0 || expout->elts[base+2].opcode != OP_TYPE)
+ error (_("Invalid cast expression"));
+ type = expout->elts[base+1].type;
+ /* Remove the 'Expression' and slide the
+ UnaryExpressionNotPlusMinus down to replace it. */
+ for (i = 0; i < last_exp_size; i++)
+ expout->elts[base + i] = expout->elts[base + i + 3];
+ expout_ptr -= 3;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ type = lookup_pointer_type (type);
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (type);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+| '(' Name Dims ')' UnaryExpressionNotPlusMinus
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (java_array_type (java_type_from_name ($2), $3));
+ write_exp_elt_opcode (UNOP_CAST); }
+;
+
+
+MultiplicativeExpression:
+ UnaryExpression
+| MultiplicativeExpression '*' UnaryExpression
+ { write_exp_elt_opcode (BINOP_MUL); }
+| MultiplicativeExpression '/' UnaryExpression
+ { write_exp_elt_opcode (BINOP_DIV); }
+| MultiplicativeExpression '%' UnaryExpression
+ { write_exp_elt_opcode (BINOP_REM); }
+;
+
+AdditiveExpression:
+ MultiplicativeExpression
+| AdditiveExpression '+' MultiplicativeExpression
+ { write_exp_elt_opcode (BINOP_ADD); }
+| AdditiveExpression '-' MultiplicativeExpression
+ { write_exp_elt_opcode (BINOP_SUB); }
+;
+
+ShiftExpression:
+ AdditiveExpression
+| ShiftExpression LSH AdditiveExpression
+ { write_exp_elt_opcode (BINOP_LSH); }
+| ShiftExpression RSH AdditiveExpression
+ { write_exp_elt_opcode (BINOP_RSH); }
+/* | ShiftExpression >>> AdditiveExpression { FIXME } */
+;
+
+RelationalExpression:
+ ShiftExpression
+| RelationalExpression '<' ShiftExpression
+ { write_exp_elt_opcode (BINOP_LESS); }
+| RelationalExpression '>' ShiftExpression
+ { write_exp_elt_opcode (BINOP_GTR); }
+| RelationalExpression LEQ ShiftExpression
+ { write_exp_elt_opcode (BINOP_LEQ); }
+| RelationalExpression GEQ ShiftExpression
+ { write_exp_elt_opcode (BINOP_GEQ); }
+/* | RelationalExpresion INSTANCEOF ReferenceType { FIXME } */
+;
+
+EqualityExpression:
+ RelationalExpression
+| EqualityExpression EQUAL RelationalExpression
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+| EqualityExpression NOTEQUAL RelationalExpression
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+;
+
+AndExpression:
+ EqualityExpression
+| AndExpression '&' EqualityExpression
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+;
+
+ExclusiveOrExpression:
+ AndExpression
+| ExclusiveOrExpression '^' AndExpression
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+;
+InclusiveOrExpression:
+ ExclusiveOrExpression
+| InclusiveOrExpression '|' ExclusiveOrExpression
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+;
+
+ConditionalAndExpression:
+ InclusiveOrExpression
+| ConditionalAndExpression ANDAND InclusiveOrExpression
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+;
+
+ConditionalOrExpression:
+ ConditionalAndExpression
+| ConditionalOrExpression OROR ConditionalAndExpression
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+;
+
+ConditionalExpression:
+ ConditionalOrExpression
+| ConditionalOrExpression '?' Expression ':' ConditionalExpression
+ { write_exp_elt_opcode (TERNOP_COND); }
+;
+
+AssignmentExpression:
+ ConditionalExpression
+| Assignment
+;
+
+Assignment:
+ LeftHandSide '=' ConditionalExpression
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+| LeftHandSide ASSIGN_MODIFY ConditionalExpression
+ { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode ($2);
+ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
+;
+
+LeftHandSide:
+ ForcedName
+ { push_expression_name ($1); }
+| VARIABLE
+ /* Already written by write_dollar_variable. */
+| FieldAccess
+| ArrayAccess
+;
+
+
+Expression:
+ AssignmentExpression
+;
+
+%%
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/*** Needs some error checking for the float case ***/
+
+static int
+parse_number (p, len, parsed_float, putithere)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ ULONGEST n = 0;
+ ULONGEST limit, limit_div_base;
+
+ int c;
+ int base = input_radix;
+
+ struct type *type;
+
+ if (parsed_float)
+ {
+ /* It's a float since it contains a point or an exponent. */
+ char c;
+ int num = 0; /* number of tokens scanned by scanf */
+ char saved_char = p[len];
+
+ p[len] = 0; /* null-terminate the token */
+ if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
+ num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval, &c);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval, &c);
+ else
+ {
+#ifdef SCANF_HAS_LONG_DOUBLE
+ num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval, &c);
+#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;
+ num = sscanf (p, "%lg%c", &temp, &c);
+ putithere->typed_val_float.dval = temp;
+#endif
+ }
+ p[len] = saved_char; /* restore the input stream */
+ if (num != 1) /* check scanf found ONLY a float ... */
+ return ERROR;
+ /* See if it has `f' or `d' suffix (float or double). */
+
+ c = tolower (p[len - 1]);
+
+ if (c == 'f' || c == 'F')
+ putithere->typed_val_float.type = builtin_type_float;
+ else if (isdigit (c) || c == '.' || c == 'd' || c == 'D')
+ putithere->typed_val_float.type = builtin_type_double;
+ else
+ return ERROR;
+
+ return FLOATING_POINT_LITERAL;
+ }
+
+ /* 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;
+ }
+
+ c = p[len-1];
+ /* A paranoid calculation of (1<<64)-1. */
+ limit = (ULONGEST)0xffffffff;
+ limit = ((limit << 16) << 16) | limit;
+ if (c == 'l' || c == 'L')
+ {
+ type = java_long_type;
+ len--;
+ }
+ else
+ {
+ type = java_int_type;
+ }
+ limit_div_base = limit / (ULONGEST) base;
+
+ while (--len >= 0)
+ {
+ c = *p++;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ return ERROR; /* Char not a digit */
+ if (c >= base)
+ return ERROR;
+ if (n > limit_div_base
+ || (n *= base) > limit - c)
+ error (_("Numeric constant too large"));
+ n += c;
+ }
+
+ /* If the type is bigger than a 32-bit signed integer can be, implicitly
+ promote to long. Java does not do this, so mark it as builtin_type_uint64
+ rather than java_long_type. 0x80000000 will become -0x80000000 instead
+ of 0x80000000L, because we don't know the sign at this point.
+ */
+ if (type == java_int_type && n > (ULONGEST)0x80000000)
+ type = builtin_type_uint64;
+
+ putithere->typed_val_int.val = n;
+ putithere->typed_val_int.type = type;
+
+ return INTEGER_LITERAL;
+}
+
+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},
+ {"&&", ANDAND, BINOP_END},
+ {"||", OROR, 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:
+
+ prev_lexptr = lexptr;
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
+ if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ 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 = java_char_type;
+
+ 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 INTEGER_LITERAL;
+
+ 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;
+ 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 '}':
+ 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_LITERAL);
+ }
+
+ 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 7:
+ if (DEPRECATED_STREQN (tokstart, "boolean", 7))
+ return BOOLEAN;
+ break;
+ case 6:
+ if (DEPRECATED_STREQN (tokstart, "double", 6))
+ return DOUBLE;
+ break;
+ case 5:
+ if (DEPRECATED_STREQN (tokstart, "short", 5))
+ return SHORT;
+ if (DEPRECATED_STREQN (tokstart, "false", 5))
+ {
+ yylval.lval = 0;
+ return BOOLEAN_LITERAL;
+ }
+ if (DEPRECATED_STREQN (tokstart, "super", 5))
+ return SUPER;
+ if (DEPRECATED_STREQN (tokstart, "float", 5))
+ return FLOAT;
+ break;
+ case 4:
+ if (DEPRECATED_STREQN (tokstart, "long", 4))
+ return LONG;
+ if (DEPRECATED_STREQN (tokstart, "byte", 4))
+ return BYTE;
+ if (DEPRECATED_STREQN (tokstart, "char", 4))
+ return CHAR;
+ if (DEPRECATED_STREQN (tokstart, "true", 4))
+ {
+ yylval.lval = 1;
+ return BOOLEAN_LITERAL;
+ }
+ break;
+ case 3:
+ if (strncmp (tokstart, "int", 3) == 0)
+ return INT;
+ if (strncmp (tokstart, "new", 3) == 0)
+ return NEW;
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ if (*tokstart == '$')
+ {
+ write_dollar_variable (yylval.sval);
+ return VARIABLE;
+ }
+
+ /* 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 (((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) ||
+ (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
+ {
+ YYSTYPE newlval; /* Its value is ignored. */
+ int hextype = parse_number (tokstart, namelen, 0, &newlval);
+ if (hextype == INTEGER_LITERAL)
+ return NAME_OR_INT;
+ }
+ return IDENTIFIER;
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ if (msg)
+ error (_("%s: near `%s'"), msg, lexptr);
+ else
+ error (_("error in expression, near `%s'"), lexptr);
+}
+
+static struct type *
+java_type_from_name (name)
+ struct stoken name;
+
+{
+ char *tmp = copy_name (name);
+ struct type *typ = java_lookup_class (tmp);
+ if (typ == NULL || TYPE_CODE (typ) != TYPE_CODE_STRUCT)
+ error (_("No class named `%s'"), tmp);
+ return typ;
+}
+
+/* If NAME is a valid variable name in this scope, push it and return 1.
+ Otherwise, return 0. */
+
+static int
+push_variable (struct stoken name)
+{
+ char *tmp = copy_name (name);
+ int is_a_field_of_this = 0;
+ struct symbol *sym;
+ sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN,
+ &is_a_field_of_this, (struct symtab **) NULL);
+ if (sym && SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ {
+ 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);
+ return 1;
+ }
+ if (is_a_field_of_this)
+ {
+ /* 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 (name);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ return 1;
+ }
+ return 0;
+}
+
+/* Assuming a reference expression has been pushed, emit the
+ STRUCTOP_STRUCT ops to access the field named NAME. If NAME is a
+ qualified name (has '.'), generate a field access for each part. */
+
+static void
+push_fieldnames (name)
+ struct stoken name;
+{
+ int i;
+ struct stoken token;
+ token.ptr = name.ptr;
+ for (i = 0; ; i++)
+ {
+ if (i == name.length || name.ptr[i] == '.')
+ {
+ /* token.ptr is start of current field name. */
+ token.length = &name.ptr[i] - token.ptr;
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (token);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ token.ptr += token.length + 1;
+ }
+ if (i >= name.length)
+ break;
+ }
+}
+
+/* Helper routine for push_expression_name.
+ Handle a qualified name, where DOT_INDEX is the index of the first '.' */
+
+static void
+push_qualified_expression_name (struct stoken name, int dot_index)
+{
+ struct stoken token;
+ char *tmp;
+ struct type *typ;
+
+ token.ptr = name.ptr;
+ token.length = dot_index;
+
+ if (push_variable (token))
+ {
+ token.ptr = name.ptr + dot_index + 1;
+ token.length = name.length - dot_index - 1;
+ push_fieldnames (token);
+ return;
+ }
+
+ token.ptr = name.ptr;
+ for (;;)
+ {
+ token.length = dot_index;
+ tmp = copy_name (token);
+ typ = java_lookup_class (tmp);
+ if (typ != NULL)
+ {
+ if (dot_index == name.length)
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(typ);
+ write_exp_elt_opcode(OP_TYPE);
+ return;
+ }
+ dot_index++; /* Skip '.' */
+ name.ptr += dot_index;
+ name.length -= dot_index;
+ dot_index = 0;
+ while (dot_index < name.length && name.ptr[dot_index] != '.')
+ dot_index++;
+ token.ptr = name.ptr;
+ token.length = dot_index;
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (typ);
+ write_exp_string (token);
+ write_exp_elt_opcode (OP_SCOPE);
+ if (dot_index < name.length)
+ {
+ dot_index++;
+ name.ptr += dot_index;
+ name.length -= dot_index;
+ push_fieldnames (name);
+ }
+ return;
+ }
+ else if (dot_index >= name.length)
+ break;
+ dot_index++; /* Skip '.' */
+ while (dot_index < name.length && name.ptr[dot_index] != '.')
+ dot_index++;
+ }
+ error (_("unknown type `%.*s'"), name.length, name.ptr);
+}
+
+/* Handle Name in an expression (or LHS).
+ Handle VAR, TYPE, TYPE.FIELD1....FIELDN and VAR.FIELD1....FIELDN. */
+
+static void
+push_expression_name (name)
+ struct stoken name;
+{
+ char *tmp;
+ struct type *typ;
+ char *ptr;
+ int i;
+
+ for (i = 0; i < name.length; i++)
+ {
+ if (name.ptr[i] == '.')
+ {
+ /* It's a Qualified Expression Name. */
+ push_qualified_expression_name (name, i);
+ return;
+ }
+ }
+
+ /* It's a Simple Expression Name. */
+
+ if (push_variable (name))
+ return;
+ tmp = copy_name (name);
+ typ = java_lookup_class (tmp);
+ if (typ != NULL)
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(typ);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+
+ msymbol = lookup_minimal_symbol (tmp, 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"), tmp);
+ }
+
+}
+
+
+/* The following two routines, copy_exp and insert_exp, aren't specific to
+ Java, so they could go in parse.c, but their only purpose is to support
+ the parsing kludges we use in this file, so maybe it's best to isolate
+ them here. */
+
+/* Copy the expression whose last element is at index ENDPOS - 1 in EXPR
+ into a freshly malloc'ed struct expression. Its language_defn is set
+ to null. */
+static struct expression *
+copy_exp (expr, endpos)
+ struct expression *expr;
+ int endpos;
+{
+ int len = length_of_subexp (expr, endpos);
+ struct expression *new
+ = (struct expression *) malloc (sizeof (*new) + EXP_ELEM_TO_BYTES (len));
+ new->nelts = len;
+ memcpy (new->elts, expr->elts + endpos - len, EXP_ELEM_TO_BYTES (len));
+ new->language_defn = 0;
+
+ return new;
+}
+
+/* Insert the expression NEW into the current expression (expout) at POS. */
+static void
+insert_exp (pos, new)
+ int pos;
+ struct expression *new;
+{
+ int newlen = new->nelts;
+
+ /* Grow expout if necessary. In this function's only use at present,
+ this should never be necessary. */
+ if (expout_ptr + newlen > expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + newlen + 10);
+ expout = (struct expression *)
+ realloc ((char *) expout, (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size)));
+ }
+
+ {
+ int i;
+
+ for (i = expout_ptr - 1; i >= pos; i--)
+ expout->elts[i + newlen] = expout->elts[i];
+ }
+
+ memcpy (expout->elts + pos, new->elts, EXP_ELEM_TO_BYTES (newlen));
+ expout_ptr += newlen;
+}
diff --git a/contrib/gdb/gdb/jv-lang.c b/contrib/gdb/gdb/jv-lang.c
new file mode 100644
index 0000000..6db6e88
--- /dev/null
+++ b/contrib/gdb/gdb/jv-lang.c
@@ -0,0 +1,1100 @@
+/* Java language support routines for GDB, the GNU debugger.
+ Copyright 1997, 1998, 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbtypes.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h"
+#include "value.h"
+#include "c-lang.h"
+#include "jv-lang.h"
+#include "gdbcore.h"
+#include "block.h"
+#include "demangle.h"
+#include "dictionary.h"
+#include <ctype.h>
+
+struct type *java_int_type;
+struct type *java_byte_type;
+struct type *java_short_type;
+struct type *java_long_type;
+struct type *java_boolean_type;
+struct type *java_char_type;
+struct type *java_float_type;
+struct type *java_double_type;
+struct type *java_void_type;
+
+/* Local functions */
+
+extern void _initialize_java_language (void);
+
+static int java_demangled_signature_length (char *);
+static void java_demangled_signature_copy (char *, char *);
+
+static struct symtab *get_java_class_symtab (void);
+static char *get_java_utf8_name (struct obstack *obstack, struct value *name);
+static int java_class_is_primitive (struct value *clas);
+static struct value *java_value_string (char *ptr, int len);
+
+static void java_emit_char (int c, struct ui_file * stream, int quoter);
+
+/* This objfile contains symtabs that have been dynamically created
+ to record dynamically loaded Java classes and dynamically
+ compiled java methods. */
+
+static struct objfile *dynamics_objfile = NULL;
+
+static struct type *java_link_class_type (struct type *, struct value *);
+
+/* FIXME: carlton/2003-02-04: This is the main or only caller of
+ allocate_objfile with first argument NULL; as a result, this code
+ breaks every so often. Somebody should write a test case that
+ exercises GDB in various ways (e.g. something involving loading a
+ dynamic library) after this code has been called. */
+
+static struct objfile *
+get_dynamics_objfile (void)
+{
+ if (dynamics_objfile == NULL)
+ {
+ dynamics_objfile = allocate_objfile (NULL, 0);
+ }
+ return dynamics_objfile;
+}
+
+#if 1
+/* symtab contains classes read from the inferior. */
+
+static struct symtab *class_symtab = NULL;
+
+static void free_class_block (struct symtab *symtab);
+
+static struct symtab *
+get_java_class_symtab (void)
+{
+ if (class_symtab == NULL)
+ {
+ struct objfile *objfile = get_dynamics_objfile ();
+ struct blockvector *bv;
+ struct block *bl;
+ class_symtab = allocate_symtab ("<java-classes>", objfile);
+ class_symtab->language = language_java;
+ bv = (struct blockvector *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct blockvector) + sizeof (struct block *));
+ BLOCKVECTOR_NBLOCKS (bv) = 1;
+ BLOCKVECTOR (class_symtab) = bv;
+
+ /* Allocate dummy STATIC_BLOCK. */
+ bl = allocate_block (&objfile->objfile_obstack);
+ BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack,
+ NULL);
+ BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
+
+ /* Allocate GLOBAL_BLOCK. */
+ bl = allocate_block (&objfile->objfile_obstack);
+ BLOCK_DICT (bl) = dict_create_hashed_expandable ();
+ BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+ class_symtab->free_func = free_class_block;
+ }
+ return class_symtab;
+}
+
+static void
+add_class_symtab_symbol (struct symbol *sym)
+{
+ struct symtab *symtab = get_java_class_symtab ();
+ struct blockvector *bv = BLOCKVECTOR (symtab);
+ dict_add_symbol (BLOCK_DICT (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)), sym);
+}
+
+static struct symbol *add_class_symbol (struct type *type, CORE_ADDR addr);
+
+static struct symbol *
+add_class_symbol (struct type *type, CORE_ADDR addr)
+{
+ struct symbol *sym;
+ sym = (struct symbol *)
+ obstack_alloc (&dynamics_objfile->objfile_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_LANGUAGE (sym) = language_java;
+ DEPRECATED_SYMBOL_NAME (sym) = TYPE_TAG_NAME (type);
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ /* SYMBOL_VALUE (sym) = valu; */
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN;
+ SYMBOL_VALUE_ADDRESS (sym) = addr;
+ return sym;
+}
+
+/* Free the dynamic symbols block. */
+static void
+free_class_block (struct symtab *symtab)
+{
+ struct blockvector *bv = BLOCKVECTOR (symtab);
+ struct block *bl = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+
+ dict_free (BLOCK_DICT (bl));
+}
+#endif
+
+struct type *
+java_lookup_class (char *name)
+{
+ struct symbol *sym;
+ sym = lookup_symbol (name, expression_context_block, STRUCT_DOMAIN,
+ (int *) 0, (struct symtab **) NULL);
+ if (sym != NULL)
+ return SYMBOL_TYPE (sym);
+#if 0
+ CORE_ADDR addr;
+ if (called from parser)
+ {
+ call lookup_class (or similar) in inferior;
+ if not
+ found:
+ return NULL;
+ addr = found in inferior;
+ }
+ else
+ addr = 0;
+ struct type *type;
+ type = alloc_type (objfile);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ INIT_CPLUS_SPECIFIC (type);
+ TYPE_TAG_NAME (type) = obsavestring (name, strlen (name), &objfile->objfile_obstack);
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+ TYPE ? = addr;
+ return type;
+#else
+ /* FIXME - should search inferior's symbol table. */
+ return NULL;
+#endif
+}
+
+/* Return a nul-terminated string (allocated on OBSTACK) for
+ a name given by NAME (which has type Utf8Const*). */
+
+char *
+get_java_utf8_name (struct obstack *obstack, struct value *name)
+{
+ char *chrs;
+ struct value *temp = name;
+ int name_length;
+ CORE_ADDR data_addr;
+ temp = value_struct_elt (&temp, NULL, "length", NULL, "structure");
+ name_length = (int) value_as_long (temp);
+ data_addr = VALUE_ADDRESS (temp) + VALUE_OFFSET (temp)
+ + TYPE_LENGTH (VALUE_TYPE (temp));
+ chrs = obstack_alloc (obstack, name_length + 1);
+ chrs[name_length] = '\0';
+ read_memory (data_addr, chrs, name_length);
+ return chrs;
+}
+
+struct value *
+java_class_from_object (struct value *obj_val)
+{
+ /* This is all rather inefficient, since the offsets of vtable and
+ class are fixed. FIXME */
+ struct value *vtable_val;
+
+ if (TYPE_CODE (VALUE_TYPE (obj_val)) == TYPE_CODE_PTR
+ && TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (obj_val))) == 0)
+ obj_val = value_at (get_java_object_type (),
+ value_as_address (obj_val), NULL);
+
+ vtable_val = value_struct_elt (&obj_val, NULL, "vtable", NULL, "structure");
+ return value_struct_elt (&vtable_val, NULL, "class", NULL, "structure");
+}
+
+/* Check if CLASS_IS_PRIMITIVE(value of clas): */
+static int
+java_class_is_primitive (struct value *clas)
+{
+ struct value *vtable = value_struct_elt (&clas, NULL, "vtable", NULL, "struct");
+ CORE_ADDR i = value_as_address (vtable);
+ return (int) (i & 0x7fffffff) == (int) 0x7fffffff;
+}
+
+/* Read a GCJ Class object, and generated a gdb (TYPE_CODE_STRUCT) type. */
+
+struct type *
+type_from_class (struct value *clas)
+{
+ struct type *type;
+ char *name;
+ struct value *temp;
+ struct objfile *objfile;
+ struct value *utf8_name;
+ char *nptr;
+ CORE_ADDR addr;
+ struct block *bl;
+ struct dict_iterator iter;
+ int is_array = 0;
+
+ type = check_typedef (VALUE_TYPE (clas));
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ {
+ if (value_logical_not (clas))
+ return NULL;
+ clas = value_ind (clas);
+ }
+ addr = VALUE_ADDRESS (clas) + VALUE_OFFSET (clas);
+
+#if 0
+ get_java_class_symtab ();
+ bl = BLOCKVECTOR_BLOCK (BLOCKVECTOR (class_symtab), GLOBAL_BLOCK);
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ if (SYMBOL_VALUE_ADDRESS (sym) == addr)
+ return SYMBOL_TYPE (sym);
+ }
+#endif
+
+ objfile = get_dynamics_objfile ();
+ if (java_class_is_primitive (clas))
+ {
+ struct value *sig;
+ temp = clas;
+ sig = value_struct_elt (&temp, NULL, "method_count", NULL, "structure");
+ return java_primitive_type (value_as_long (sig));
+ }
+
+ /* Get Class name. */
+ /* if clasloader non-null, prepend loader address. FIXME */
+ temp = clas;
+ utf8_name = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+ name = get_java_utf8_name (&objfile->objfile_obstack, utf8_name);
+ for (nptr = name; *nptr != 0; nptr++)
+ {
+ if (*nptr == '/')
+ *nptr = '.';
+ }
+
+ type = java_lookup_class (name);
+ if (type != NULL)
+ return type;
+
+ type = alloc_type (objfile);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ INIT_CPLUS_SPECIFIC (type);
+
+ if (name[0] == '[')
+ {
+ char *signature = name;
+ int namelen = java_demangled_signature_length (signature);
+ if (namelen > strlen (name))
+ name = obstack_alloc (&objfile->objfile_obstack, namelen + 1);
+ java_demangled_signature_copy (name, signature);
+ name[namelen] = '\0';
+ is_array = 1;
+ temp = clas;
+ /* Set array element type. */
+ temp = value_struct_elt (&temp, NULL, "methods", NULL, "structure");
+ VALUE_TYPE (temp) = lookup_pointer_type (VALUE_TYPE (clas));
+ TYPE_TARGET_TYPE (type) = type_from_class (temp);
+ }
+
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_TAG_NAME (type) = name;
+
+ add_class_symtab_symbol (add_class_symbol (type, addr));
+ return java_link_class_type (type, clas);
+}
+
+/* Fill in class TYPE with data from the CLAS value. */
+
+struct type *
+java_link_class_type (struct type *type, struct value *clas)
+{
+ struct value *temp;
+ char *unqualified_name;
+ char *name = TYPE_TAG_NAME (type);
+ int ninterfaces, nfields, nmethods;
+ int type_is_object = 0;
+ struct fn_field *fn_fields;
+ struct fn_fieldlist *fn_fieldlists;
+ struct value *fields;
+ struct value *methods;
+ struct value *method = NULL;
+ struct value *field = NULL;
+ int i, j;
+ struct objfile *objfile = get_dynamics_objfile ();
+ struct type *tsuper;
+
+ unqualified_name = strrchr (name, '.');
+ if (unqualified_name == NULL)
+ unqualified_name = name;
+
+ temp = clas;
+ temp = value_struct_elt (&temp, NULL, "superclass", NULL, "structure");
+ if (name != NULL && strcmp (name, "java.lang.Object") == 0)
+ {
+ tsuper = get_java_object_type ();
+ if (tsuper && TYPE_CODE (tsuper) == TYPE_CODE_PTR)
+ tsuper = TYPE_TARGET_TYPE (tsuper);
+ type_is_object = 1;
+ }
+ else
+ tsuper = type_from_class (temp);
+
+#if 1
+ ninterfaces = 0;
+#else
+ temp = clas;
+ ninterfaces = value_as_long (value_struct_elt (&temp, NULL, "interface_len", NULL, "structure"));
+#endif
+ TYPE_N_BASECLASSES (type) = (tsuper == NULL ? 0 : 1) + ninterfaces;
+ temp = clas;
+ nfields = value_as_long (value_struct_elt (&temp, NULL, "field_count", NULL, "structure"));
+ nfields += TYPE_N_BASECLASSES (type);
+ nfields++; /* Add one for dummy "class" field. */
+ 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);
+
+ 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);
+
+ TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *)
+ TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type)));
+ B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type));
+
+ if (tsuper != NULL)
+ {
+ TYPE_BASECLASS (type, 0) = tsuper;
+ if (type_is_object)
+ SET_TYPE_FIELD_PRIVATE (type, 0);
+ }
+
+ i = strlen (name);
+ if (i > 2 && name[i - 1] == ']' && tsuper != NULL)
+ {
+ /* FIXME */
+ TYPE_LENGTH (type) = TYPE_LENGTH (tsuper) + 4; /* size with "length" */
+ }
+ else
+ {
+ temp = clas;
+ temp = value_struct_elt (&temp, NULL, "size_in_bytes", NULL, "structure");
+ TYPE_LENGTH (type) = value_as_long (temp);
+ }
+
+ fields = NULL;
+ nfields--; /* First set up dummy "class" field. */
+ SET_FIELD_PHYSADDR (TYPE_FIELD (type, nfields),
+ VALUE_ADDRESS (clas) + VALUE_OFFSET (clas));
+ TYPE_FIELD_NAME (type, nfields) = "class";
+ TYPE_FIELD_TYPE (type, nfields) = VALUE_TYPE (clas);
+ SET_TYPE_FIELD_PRIVATE (type, nfields);
+
+ for (i = TYPE_N_BASECLASSES (type); i < nfields; i++)
+ {
+ int accflags;
+ int boffset;
+ if (fields == NULL)
+ {
+ temp = clas;
+ fields = value_struct_elt (&temp, NULL, "fields", NULL, "structure");
+ field = value_ind (fields);
+ }
+ else
+ { /* Re-use field value for next field. */
+ VALUE_ADDRESS (field) += TYPE_LENGTH (VALUE_TYPE (field));
+ VALUE_LAZY (field) = 1;
+ }
+ temp = field;
+ temp = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+ TYPE_FIELD_NAME (type, i) =
+ get_java_utf8_name (&objfile->objfile_obstack, temp);
+ temp = field;
+ accflags = value_as_long (value_struct_elt (&temp, NULL, "accflags",
+ NULL, "structure"));
+ temp = field;
+ temp = value_struct_elt (&temp, NULL, "info", NULL, "structure");
+ boffset = value_as_long (value_struct_elt (&temp, NULL, "boffset",
+ NULL, "structure"));
+ if (accflags & 0x0001) /* public access */
+ {
+ /* ??? */
+ }
+ if (accflags & 0x0002) /* private access */
+ {
+ SET_TYPE_FIELD_PRIVATE (type, i);
+ }
+ if (accflags & 0x0004) /* protected access */
+ {
+ SET_TYPE_FIELD_PROTECTED (type, i);
+ }
+ if (accflags & 0x0008) /* ACC_STATIC */
+ SET_FIELD_PHYSADDR (TYPE_FIELD (type, i), boffset);
+ else
+ TYPE_FIELD_BITPOS (type, i) = 8 * boffset;
+ if (accflags & 0x8000) /* FIELD_UNRESOLVED_FLAG */
+ {
+ TYPE_FIELD_TYPE (type, i) = get_java_object_type (); /* FIXME */
+ }
+ else
+ {
+ struct type *ftype;
+ temp = field;
+ temp = value_struct_elt (&temp, NULL, "type", NULL, "structure");
+ ftype = type_from_class (temp);
+ if (TYPE_CODE (ftype) == TYPE_CODE_STRUCT)
+ ftype = lookup_pointer_type (ftype);
+ TYPE_FIELD_TYPE (type, i) = ftype;
+ }
+ }
+
+ temp = clas;
+ nmethods = value_as_long (value_struct_elt (&temp, NULL, "method_count",
+ NULL, "structure"));
+ TYPE_NFN_FIELDS_TOTAL (type) = nmethods;
+ j = nmethods * sizeof (struct fn_field);
+ fn_fields = (struct fn_field *)
+ obstack_alloc (&dynamics_objfile->objfile_obstack, j);
+ memset (fn_fields, 0, j);
+ fn_fieldlists = (struct fn_fieldlist *)
+ alloca (nmethods * sizeof (struct fn_fieldlist));
+
+ methods = NULL;
+ for (i = 0; i < nmethods; i++)
+ {
+ char *mname;
+ int k;
+ if (methods == NULL)
+ {
+ temp = clas;
+ methods = value_struct_elt (&temp, NULL, "methods", NULL, "structure");
+ method = value_ind (methods);
+ }
+ else
+ { /* Re-use method value for next method. */
+ VALUE_ADDRESS (method) += TYPE_LENGTH (VALUE_TYPE (method));
+ VALUE_LAZY (method) = 1;
+ }
+
+ /* Get method name. */
+ temp = method;
+ temp = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+ mname = get_java_utf8_name (&objfile->objfile_obstack, temp);
+ if (strcmp (mname, "<init>") == 0)
+ mname = unqualified_name;
+
+ /* Check for an existing method with the same name.
+ * This makes building the fn_fieldslists an O(nmethods**2)
+ * operation. That could be using hashing, but I doubt it
+ * is worth it. Note that we do maintain the order of methods
+ * in the inferior's Method table (as long as that is grouped
+ * by method name), which I think is desirable. --PB */
+ for (k = 0, j = TYPE_NFN_FIELDS (type);;)
+ {
+ if (--j < 0)
+ { /* No match - new method name. */
+ j = TYPE_NFN_FIELDS (type)++;
+ fn_fieldlists[j].name = mname;
+ fn_fieldlists[j].length = 1;
+ fn_fieldlists[j].fn_fields = &fn_fields[i];
+ k = i;
+ break;
+ }
+ if (strcmp (mname, fn_fieldlists[j].name) == 0)
+ { /* Found an existing method with the same name. */
+ int l;
+ if (mname != unqualified_name)
+ obstack_free (&objfile->objfile_obstack, mname);
+ mname = fn_fieldlists[j].name;
+ fn_fieldlists[j].length++;
+ k = i - k; /* Index of new slot. */
+ /* Shift intervening fn_fields (between k and i) down. */
+ for (l = i; l > k; l--)
+ fn_fields[l] = fn_fields[l - 1];
+ for (l = TYPE_NFN_FIELDS (type); --l > j;)
+ fn_fieldlists[l].fn_fields++;
+ break;
+ }
+ k += fn_fieldlists[j].length;
+ }
+ fn_fields[k].physname = "";
+ fn_fields[k].is_stub = 1;
+ fn_fields[k].type = make_function_type (java_void_type, NULL); /* FIXME */
+ TYPE_CODE (fn_fields[k].type) = TYPE_CODE_METHOD;
+ }
+
+ j = TYPE_NFN_FIELDS (type) * sizeof (struct fn_fieldlist);
+ TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+ obstack_alloc (&dynamics_objfile->objfile_obstack, j);
+ memcpy (TYPE_FN_FIELDLISTS (type), fn_fieldlists, j);
+
+ return type;
+}
+
+static struct type *java_object_type;
+
+struct type *
+get_java_object_type (void)
+{
+ if (java_object_type == NULL)
+ {
+ struct symbol *sym;
+ sym = lookup_symbol ("java.lang.Object", NULL, STRUCT_DOMAIN,
+ (int *) 0, (struct symtab **) NULL);
+ if (sym == NULL)
+ error ("cannot find java.lang.Object");
+ java_object_type = SYMBOL_TYPE (sym);
+ }
+ return java_object_type;
+}
+
+int
+get_java_object_header_size (void)
+{
+ struct type *objtype = get_java_object_type ();
+ if (objtype == NULL)
+ return (2 * TARGET_PTR_BIT / TARGET_CHAR_BIT);
+ else
+ return TYPE_LENGTH (objtype);
+}
+
+int
+is_object_type (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ {
+ struct type *ttype = check_typedef (TYPE_TARGET_TYPE (type));
+ char *name;
+ if (TYPE_CODE (ttype) != TYPE_CODE_STRUCT)
+ return 0;
+ while (TYPE_N_BASECLASSES (ttype) > 0)
+ ttype = TYPE_BASECLASS (ttype, 0);
+ name = TYPE_TAG_NAME (ttype);
+ if (name != NULL && strcmp (name, "java.lang.Object") == 0)
+ return 1;
+ name = TYPE_NFIELDS (ttype) > 0 ? TYPE_FIELD_NAME (ttype, 0) : (char *) 0;
+ if (name != NULL && strcmp (name, "vtable") == 0)
+ {
+ if (java_object_type == NULL)
+ java_object_type = type;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+struct type *
+java_primitive_type (int signature)
+{
+ switch (signature)
+ {
+ case 'B':
+ return java_byte_type;
+ case 'S':
+ return java_short_type;
+ case 'I':
+ return java_int_type;
+ case 'J':
+ return java_long_type;
+ case 'Z':
+ return java_boolean_type;
+ case 'C':
+ return java_char_type;
+ case 'F':
+ return java_float_type;
+ case 'D':
+ return java_double_type;
+ case 'V':
+ return java_void_type;
+ }
+ error ("unknown signature '%c' for primitive type", (char) signature);
+}
+
+/* If name[0 .. namelen-1] is the name of a primitive Java type,
+ return that type. Otherwise, return NULL. */
+
+struct type *
+java_primitive_type_from_name (char *name, int namelen)
+{
+ switch (name[0])
+ {
+ case 'b':
+ if (namelen == 4 && memcmp (name, "byte", 4) == 0)
+ return java_byte_type;
+ if (namelen == 7 && memcmp (name, "boolean", 7) == 0)
+ return java_boolean_type;
+ break;
+ case 'c':
+ if (namelen == 4 && memcmp (name, "char", 4) == 0)
+ return java_char_type;
+ case 'd':
+ if (namelen == 6 && memcmp (name, "double", 6) == 0)
+ return java_double_type;
+ break;
+ case 'f':
+ if (namelen == 5 && memcmp (name, "float", 5) == 0)
+ return java_float_type;
+ break;
+ case 'i':
+ if (namelen == 3 && memcmp (name, "int", 3) == 0)
+ return java_int_type;
+ break;
+ case 'l':
+ if (namelen == 4 && memcmp (name, "long", 4) == 0)
+ return java_long_type;
+ break;
+ case 's':
+ if (namelen == 5 && memcmp (name, "short", 5) == 0)
+ return java_short_type;
+ break;
+ case 'v':
+ if (namelen == 4 && memcmp (name, "void", 4) == 0)
+ return java_void_type;
+ break;
+ }
+ return NULL;
+}
+
+/* Return the length (in bytes) of demangled name of the Java type
+ signature string SIGNATURE. */
+
+static int
+java_demangled_signature_length (char *signature)
+{
+ int array = 0;
+ for (; *signature == '['; signature++)
+ array += 2; /* Two chars for "[]". */
+ switch (signature[0])
+ {
+ case 'L':
+ /* Subtract 2 for 'L' and ';'. */
+ return strlen (signature) - 2 + array;
+ default:
+ return strlen (TYPE_NAME (java_primitive_type (signature[0]))) + array;
+ }
+}
+
+/* Demangle the Java type signature SIGNATURE, leaving the result in RESULT. */
+
+static void
+java_demangled_signature_copy (char *result, char *signature)
+{
+ int array = 0;
+ char *ptr;
+ int i;
+ while (*signature == '[')
+ {
+ array++;
+ signature++;
+ }
+ switch (signature[0])
+ {
+ case 'L':
+ /* Subtract 2 for 'L' and ';', but add 1 for final nul. */
+ signature++;
+ ptr = result;
+ for (; *signature != ';' && *signature != '\0'; signature++)
+ {
+ if (*signature == '/')
+ *ptr++ = '.';
+ else
+ *ptr++ = *signature;
+ }
+ break;
+ default:
+ ptr = TYPE_NAME (java_primitive_type (signature[0]));
+ i = strlen (ptr);
+ strcpy (result, ptr);
+ ptr = result + i;
+ break;
+ }
+ while (--array >= 0)
+ {
+ *ptr++ = '[';
+ *ptr++ = ']';
+ }
+}
+
+/* Return the demangled name of the Java type signature string SIGNATURE,
+ as a freshly allocated copy. */
+
+char *
+java_demangle_type_signature (char *signature)
+{
+ int length = java_demangled_signature_length (signature);
+ char *result = xmalloc (length + 1);
+ java_demangled_signature_copy (result, signature);
+ result[length] = '\0';
+ return result;
+}
+
+/* Return the type of TYPE followed by DIMS pairs of [ ].
+ If DIMS == 0, TYPE is returned. */
+
+struct type *
+java_array_type (struct type *type, int dims)
+{
+ struct type *range_type;
+
+ while (dims-- > 0)
+ {
+ range_type = create_range_type (NULL, builtin_type_int, 0, 0);
+ /* FIXME This is bogus! Java arrays are not gdb arrays! */
+ type = create_array_type (NULL, type, range_type);
+ }
+
+ return type;
+}
+
+/* Create a Java string in the inferior from a (Utf8) literal. */
+
+static struct value *
+java_value_string (char *ptr, int len)
+{
+ error ("not implemented - java_value_string"); /* FIXME */
+}
+
+/* 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
+java_emit_char (int c, struct ui_file *stream, int quoter)
+{
+ switch (c)
+ {
+ case '\\':
+ case '\'':
+ fprintf_filtered (stream, "\\%c", c);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ default:
+ if (isprint (c))
+ fputc_filtered (c, stream);
+ else
+ fprintf_filtered (stream, "\\u%.4x", (unsigned int) c);
+ break;
+ }
+}
+
+static struct value *
+evaluate_subexp_java (struct type *expect_type, struct expression *exp,
+ int *pos, enum noside noside)
+{
+ int pc = *pos;
+ int i;
+ char *name;
+ enum exp_opcode op = exp->elts[*pos].opcode;
+ struct value *arg1;
+ struct value *arg2;
+ struct type *type;
+ switch (op)
+ {
+ case UNOP_IND:
+ if (noside == EVAL_SKIP)
+ goto standard;
+ (*pos)++;
+ arg1 = evaluate_subexp_java (NULL_TYPE, exp, pos, EVAL_NORMAL);
+ if (is_object_type (VALUE_TYPE (arg1)))
+ {
+ struct type *type;
+
+ type = type_from_class (java_class_from_object (arg1));
+ arg1 = value_cast (lookup_pointer_type (type), arg1);
+ }
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_ind (arg1);
+
+ case BINOP_SUBSCRIPT:
+ (*pos)++;
+ arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+ arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ /* If the user attempts to subscript something that is not an
+ array or pointer type (like a plain int variable for example),
+ then report this as an error. */
+
+ COERCE_REF (arg1);
+ type = check_typedef (VALUE_TYPE (arg1));
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ name = TYPE_NAME (type);
+ if (name == NULL)
+ name = TYPE_TAG_NAME (type);
+ i = name == NULL ? 0 : strlen (name);
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && i > 2 && name[i - 1] == ']')
+ {
+ CORE_ADDR address;
+ long length, index;
+ struct type *el_type;
+ char buf4[4];
+
+ struct value *clas = java_class_from_object (arg1);
+ struct value *temp = clas;
+ /* Get CLASS_ELEMENT_TYPE of the array type. */
+ temp = value_struct_elt (&temp, NULL, "methods",
+ NULL, "structure");
+ VALUE_TYPE (temp) = VALUE_TYPE (clas);
+ el_type = type_from_class (temp);
+ if (TYPE_CODE (el_type) == TYPE_CODE_STRUCT)
+ el_type = lookup_pointer_type (el_type);
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (el_type, VALUE_LVAL (arg1));
+ address = value_as_address (arg1);
+ address += JAVA_OBJECT_SIZE;
+ read_memory (address, buf4, 4);
+ length = (long) extract_signed_integer (buf4, 4);
+ index = (long) value_as_long (arg2);
+ if (index >= length || index < 0)
+ error ("array index (%ld) out of bounds (length: %ld)",
+ index, length);
+ address = (address + 4) + index * TYPE_LENGTH (el_type);
+ return value_at (el_type, address, NULL);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
+ else
+ return value_subscript (arg1, arg2);
+ }
+ if (name)
+ error ("cannot subscript something of type `%s'", name);
+ else
+ error ("cannot subscript requested type");
+
+ case OP_STRING:
+ (*pos)++;
+ i = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (i + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return java_value_string (&exp->elts[pc + 2].string, i);
+
+ case STRUCTOP_STRUCT:
+ arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside);
+ /* Convert object field (such as TYPE.class) to reference. */
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT)
+ arg1 = value_addr (arg1);
+ return arg1;
+ default:
+ break;
+ }
+standard:
+ return evaluate_subexp_standard (expect_type, exp, pos, noside);
+nosideret:
+ return value_from_longest (builtin_type_long, (LONGEST) 1);
+}
+
+static struct type *
+java_create_fundamental_type (struct objfile *objfile, int typeid)
+{
+ switch (typeid)
+ {
+ case FT_VOID:
+ return java_void_type;
+ case FT_BOOLEAN:
+ return java_boolean_type;
+ case FT_CHAR:
+ return java_char_type;
+ case FT_FLOAT:
+ return java_float_type;
+ case FT_DBL_PREC_FLOAT:
+ return java_double_type;
+ case FT_BYTE:
+ case FT_SIGNED_CHAR:
+ return java_byte_type;
+ case FT_SHORT:
+ case FT_SIGNED_SHORT:
+ return java_short_type;
+ case FT_INTEGER:
+ case FT_SIGNED_INTEGER:
+ return java_int_type;
+ case FT_LONG:
+ case FT_SIGNED_LONG:
+ return java_long_type;
+ }
+ return c_create_fundamental_type (objfile, typeid);
+}
+
+static char *java_demangle (const char *mangled, int options)
+{
+ return cplus_demangle (mangled, options | DMGL_JAVA);
+}
+
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+const struct op_print java_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},
+#if 0
+ {">>>", BINOP_ ? ? ?, PREC_SHIFT, 0},
+#endif
+ {"+", 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},
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
+ {"*", UNOP_IND, PREC_PREFIX, 0},
+#if 0
+ {"instanceof", ? ? ?, ? ? ?, 0},
+#endif
+ {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
+ {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
+ {NULL, 0, 0, 0}
+};
+
+const struct exp_descriptor exp_descriptor_java =
+{
+ print_subexp_standard,
+ operator_length_standard,
+ op_name_standard,
+ dump_subexp_body_standard,
+ evaluate_subexp_java
+};
+
+const struct language_defn java_language_defn =
+{
+ "java", /* Language name */
+ language_java,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ case_sensitive_on,
+ &exp_descriptor_java,
+ java_parse,
+ java_error,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ java_emit_char, /* Function to print a single character */
+ java_create_fundamental_type, /* Create fundamental type in this language */
+ java_print_type, /* Print a type using appropriate syntax */
+ java_val_print, /* Print a value using appropriate syntax */
+ java_value_print, /* Print a top-level value */
+ NULL, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ java_demangle, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ java_op_print_tab, /* expression operators for printing */
+ 0, /* not c-style arrays */
+ 0, /* String lower bound */
+ &builtin_type_char, /* Type of string elements */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+void
+_initialize_java_language (void)
+{
+
+ java_int_type = init_type (TYPE_CODE_INT, 4, 0, "int", NULL);
+ java_short_type = init_type (TYPE_CODE_INT, 2, 0, "short", NULL);
+ java_long_type = init_type (TYPE_CODE_INT, 8, 0, "long", NULL);
+ java_byte_type = init_type (TYPE_CODE_INT, 1, 0, "byte", NULL);
+ java_boolean_type = init_type (TYPE_CODE_BOOL, 1, 0, "boolean", NULL);
+ java_char_type = init_type (TYPE_CODE_CHAR, 2, TYPE_FLAG_UNSIGNED, "char", NULL);
+ java_float_type = init_type (TYPE_CODE_FLT, 4, 0, "float", NULL);
+ java_double_type = init_type (TYPE_CODE_FLT, 8, 0, "double", NULL);
+ java_void_type = init_type (TYPE_CODE_VOID, 1, 0, "void", NULL);
+
+ add_language (&java_language_defn);
+}
+
+/* Cleanup code that should be run on every "run".
+ We should use make_run_cleanup to have this be called.
+ But will that mess up values in value histry? FIXME */
+
+extern void java_rerun_cleanup (void);
+void
+java_rerun_cleanup (void)
+{
+ if (class_symtab != NULL)
+ {
+ free_symtab (class_symtab); /* ??? */
+ class_symtab = NULL;
+ }
+ if (dynamics_objfile != NULL)
+ {
+ free_objfile (dynamics_objfile);
+ dynamics_objfile = NULL;
+ }
+
+ java_object_type = NULL;
+}
diff --git a/contrib/gdb/gdb/jv-lang.h b/contrib/gdb/gdb/jv-lang.h
new file mode 100644
index 0000000..61fb943
--- /dev/null
+++ b/contrib/gdb/gdb/jv-lang.h
@@ -0,0 +1,73 @@
+/* Java language support definitions for GDB, the GNU debugger.
+ Copyright 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 JV_LANG_H
+#define JV_LANG_H
+
+struct value;
+
+extern int java_parse (void); /* Defined in jv-exp.y */
+
+extern void java_error (char *); /* Defined in jv-exp.y */
+
+/* sizeof (struct Object) */
+#define JAVA_OBJECT_SIZE (get_java_object_header_size ())
+
+extern struct type *java_int_type;
+extern struct type *java_byte_type;
+extern struct type *java_short_type;
+extern struct type *java_long_type;
+extern struct type *java_boolean_type;
+extern struct type *java_char_type;
+extern struct type *java_float_type;
+extern struct type *java_double_type;
+extern struct type *java_void_type;
+
+extern int java_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+extern int java_value_print (struct value *, struct ui_file *, int,
+ enum val_prettyprint);
+
+extern struct value *java_class_from_object (struct value *);
+
+extern struct type *type_from_class (struct value *);
+
+extern struct type *java_primitive_type (int signature);
+
+extern struct type *java_primitive_type_from_name (char *, int);
+
+extern struct type *java_array_type (struct type *, int);
+
+extern struct type *get_java_object_type (void);
+extern int get_java_object_header_size (void);
+
+extern struct type *java_lookup_class (char *);
+
+extern int is_object_type (struct type *);
+
+/* Defined in jv-typeprint.c */
+extern void java_print_type (struct type *, char *, struct ui_file *, int,
+ int);
+
+extern char *java_demangle_type_signature (char *);
+
+#endif
diff --git a/contrib/gdb/gdb/jv-typeprint.c b/contrib/gdb/gdb/jv-typeprint.c
new file mode 100644
index 0000000..18bfc32
--- /dev/null
+++ b/contrib/gdb/gdb/jv-typeprint.c
@@ -0,0 +1,343 @@
+/* Support for printing Java types for GDB, the GNU debugger.
+ Copyright 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "demangle.h"
+#include "jv-lang.h"
+#include "gdb_string.h"
+#include "typeprint.h"
+#include "c-lang.h"
+#include "cp-abi.h"
+
+/* Local functions */
+
+static void java_type_print_base (struct type * type,
+ struct ui_file *stream, int show,
+ int level);
+
+static void
+java_type_print_derivation_info (struct ui_file *stream, struct type *type)
+{
+ char *name;
+ int i;
+ int n_bases;
+ int prev;
+
+ n_bases = TYPE_N_BASECLASSES (type);
+
+ for (i = 0, prev = 0; i < n_bases; i++)
+ {
+ int kind;
+
+ kind = BASETYPE_VIA_VIRTUAL (type, i) ? 'I' : 'E';
+
+ fputs_filtered (kind == prev ? ", "
+ : kind == 'I' ? " implements "
+ : " extends ",
+ stream);
+ prev = kind;
+ name = type_name_no_tag (TYPE_BASECLASS (type, i));
+
+ fprintf_filtered (stream, "%s", name ? name : "(null)");
+ }
+
+ if (i > 0)
+ fputs_filtered (" ", stream);
+}
+
+/* Print the name of the type (or the ultimate pointer target,
+ function value or array element), or the description of a
+ structure or union.
+
+ 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. */
+
+static void
+java_type_print_base (struct type *type, struct ui_file *stream, int show,
+ int level)
+{
+ int i;
+ int len;
+ char *mangled_name;
+ char *demangled_name;
+ QUIT;
+
+ wrap_here (" ");
+
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", 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;
+ }
+
+ CHECK_TYPEDEF (type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ java_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ if (TYPE_TAG_NAME (type) != NULL && TYPE_TAG_NAME (type)[0] == '[')
+ { /* array type */
+ char *name = java_demangle_type_signature (TYPE_TAG_NAME (type));
+ fputs_filtered (name, stream);
+ xfree (name);
+ break;
+ }
+
+ if (show >= 0)
+ fprintf_filtered (stream, "class ");
+
+ 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)
+ {
+ java_type_print_derivation_info (stream, type);
+
+ fprintf_filtered (stream, "{\n");
+ if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+ {
+ if (TYPE_STUB (type))
+ fprintfi_filtered (level + 4, stream, "<incomplete type>\n");
+ else
+ fprintfi_filtered (level + 4, stream, "<no data fields>\n");
+ }
+
+ /* 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 (strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5) == 0
+ && is_cplus_marker ((TYPE_FIELD_NAME (type, i))[5]))
+ continue;
+
+ /* Don't print the dummy field "class". */
+ if (strncmp (TYPE_FIELD_NAME (type, i), "class", 5) == 0)
+ continue;
+
+ print_spaces_filtered (level + 4, stream);
+
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ if (TYPE_FIELD_PROTECTED (type, i))
+ fprintf_filtered (stream, "protected ");
+ else if (TYPE_FIELD_PRIVATE (type, i))
+ fprintf_filtered (stream, "private ");
+ else
+ fprintf_filtered (stream, "public ");
+ }
+
+ if (TYPE_FIELD_STATIC (type, i))
+ fprintf_filtered (stream, "static ");
+
+ java_print_type (TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 4);
+
+ fprintf_filtered (stream, ";\n");
+ }
+
+ /* If there are both fields and methods, put a space between. */
+ len = TYPE_NFN_FIELDS (type);
+ if (len)
+ fprintf_filtered (stream, "\n");
+
+ /* Print out the methods */
+
+ for (i = 0; i < len; i++)
+ {
+ struct fn_field *f;
+ int j;
+ char *method_name;
+ char *name;
+ int is_constructor;
+ int n_overloads;
+
+ f = TYPE_FN_FIELDLIST1 (type, i);
+ n_overloads = TYPE_FN_FIELDLIST_LENGTH (type, i);
+ method_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ name = type_name_no_tag (type);
+ is_constructor = name && strcmp (method_name, name) == 0;
+
+ for (j = 0; j < n_overloads; j++)
+ {
+ char *physname;
+ int is_full_physname_constructor;
+
+ physname = TYPE_FN_FIELD_PHYSNAME (f, j);
+
+ is_full_physname_constructor
+ = (is_constructor_name (physname)
+ || is_destructor_name (physname));
+
+ QUIT;
+
+ print_spaces_filtered (level + 4, stream);
+
+ if (TYPE_FN_FIELD_PROTECTED (f, j))
+ fprintf_filtered (stream, "protected ");
+ else if (TYPE_FN_FIELD_PRIVATE (f, j))
+ fprintf_filtered (stream, "private ");
+ else if (TYPE_FN_FIELD_PUBLIC (f, j))
+ fprintf_filtered (stream, "public ");
+
+ if (TYPE_FN_FIELD_ABSTRACT (f, j))
+ fprintf_filtered (stream, "abstract ");
+ if (TYPE_FN_FIELD_STATIC (f, j))
+ fprintf_filtered (stream, "static ");
+ if (TYPE_FN_FIELD_FINAL (f, j))
+ fprintf_filtered (stream, "final ");
+ if (TYPE_FN_FIELD_SYNCHRONIZED (f, j))
+ fprintf_filtered (stream, "synchronized ");
+ if (TYPE_FN_FIELD_NATIVE (f, j))
+ fprintf_filtered (stream, "native ");
+
+ if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) == 0)
+ {
+ /* Keep GDB from crashing here. */
+ fprintf_filtered (stream, "<undefined type> %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);
+ else
+ mangled_name = TYPE_FN_FIELD_PHYSNAME (f, j);
+
+ demangled_name =
+ cplus_demangle (mangled_name,
+ DMGL_ANSI | DMGL_PARAMS | DMGL_JAVA);
+
+ if (demangled_name == NULL)
+ demangled_name = xstrdup (mangled_name);
+
+ {
+ char *demangled_no_class;
+ char *ptr;
+
+ ptr = demangled_no_class = demangled_name;
+
+ while (1)
+ {
+ char c;
+
+ c = *ptr++;
+
+ if (c == 0 || c == '(')
+ break;
+ if (c == '.')
+ demangled_no_class = ptr;
+ }
+
+ fputs_filtered (demangled_no_class, stream);
+ xfree (demangled_name);
+ }
+
+ if (TYPE_FN_FIELD_STUB (f, j))
+ xfree (mangled_name);
+
+ fprintf_filtered (stream, ";\n");
+ }
+ }
+
+ fprintfi_filtered (level, stream, "}");
+ }
+ break;
+
+ default:
+ c_type_print_base (type, stream, show, level);
+ }
+}
+
+/* LEVEL is the depth to indent lines by. */
+
+extern void c_type_print_varspec_suffix (struct type *, struct ui_file *,
+ int, int, int);
+
+void
+java_print_type (struct type *type, char *varstring, struct ui_file *stream,
+ int show, int level)
+{
+ int demangled_args;
+
+ java_type_print_base (type, stream, show, level);
+
+ if (varstring != NULL && *varstring != '\0')
+ {
+ fputs_filtered (" ", stream);
+ 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);
+}
diff --git a/contrib/gdb/gdb/jv-valprint.c b/contrib/gdb/gdb/jv-valprint.c
new file mode 100644
index 0000000..8715257
--- /dev/null
+++ b/contrib/gdb/gdb/jv-valprint.c
@@ -0,0 +1,535 @@
+/* Support for printing Java values for GDB, the GNU debugger.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "expression.h"
+#include "value.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "language.h"
+#include "jv-lang.h"
+#include "c-lang.h"
+#include "annotate.h"
+#include "gdb_string.h"
+
+/* Local functions */
+
+static void java_print_value_fields (struct type * type, char *valaddr,
+ CORE_ADDR address,
+ struct ui_file *stream, int format,
+ int recurse,
+ enum val_prettyprint pretty);
+
+
+int
+java_value_print (struct value *val, struct ui_file *stream, int format,
+ enum val_prettyprint pretty)
+{
+ struct type *type;
+ CORE_ADDR address;
+ int i;
+ char *name;
+
+ type = VALUE_TYPE (val);
+ address = VALUE_ADDRESS (val) + VALUE_OFFSET (val);
+
+ if (is_object_type (type))
+ {
+ CORE_ADDR obj_addr;
+
+ /* Get the run-time type, and cast the object into that */
+
+ obj_addr = unpack_pointer (type, VALUE_CONTENTS (val));
+
+ if (obj_addr != 0)
+ {
+ type = type_from_class (java_class_from_object (val));
+ type = lookup_pointer_type (type);
+
+ val = value_at (type, address, NULL);
+ }
+ }
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR && !value_logical_not (val))
+ type_print (TYPE_TARGET_TYPE (type), "", stream, -1);
+
+ name = TYPE_TAG_NAME (type);
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT && name != NULL
+ && (i = strlen (name), name[i - 1] == ']'))
+ {
+ char buf4[4];
+ long length;
+ unsigned int things_printed = 0;
+ int reps;
+ struct type *el_type = java_primitive_type_from_name (name, i - 2);
+
+ i = 0;
+ read_memory (address + JAVA_OBJECT_SIZE, buf4, 4);
+
+ length = (long) extract_signed_integer (buf4, 4);
+ fprintf_filtered (stream, "{length: %ld", length);
+
+ if (el_type == NULL)
+ {
+ CORE_ADDR element;
+ CORE_ADDR next_element = -1; /* dummy initial value */
+
+ address += JAVA_OBJECT_SIZE + 4; /* Skip object header and length. */
+
+ while (i < length && things_printed < print_max)
+ {
+ char *buf;
+
+ buf = alloca (TARGET_PTR_BIT / HOST_CHAR_BIT);
+ fputs_filtered (", ", stream);
+ wrap_here (n_spaces (2));
+
+ if (i > 0)
+ element = next_element;
+ else
+ {
+ read_memory (address, buf, sizeof (buf));
+ address += TARGET_PTR_BIT / HOST_CHAR_BIT;
+ /* FIXME: cagney/2003-05-24: Bogus or what. It
+ pulls a host sized pointer out of the target and
+ then extracts that as an address (while assuming
+ that the address is unsigned)! */
+ element = extract_unsigned_integer (buf, sizeof (buf));
+ }
+
+ for (reps = 1; i + reps < length; reps++)
+ {
+ read_memory (address, buf, sizeof (buf));
+ address += TARGET_PTR_BIT / HOST_CHAR_BIT;
+ /* FIXME: cagney/2003-05-24: Bogus or what. It
+ pulls a host sized pointer out of the target and
+ then extracts that as an address (while assuming
+ that the address is unsigned)! */
+ next_element = extract_unsigned_integer (buf, sizeof (buf));
+ if (next_element != element)
+ break;
+ }
+
+ if (reps == 1)
+ fprintf_filtered (stream, "%d: ", i);
+ else
+ fprintf_filtered (stream, "%d..%d: ", i, i + reps - 1);
+
+ if (element == 0)
+ fprintf_filtered (stream, "null");
+ else
+ fprintf_filtered (stream, "@%s", paddr_nz (element));
+
+ things_printed++;
+ i += reps;
+ }
+ }
+ else
+ {
+ struct value *v = allocate_value (el_type);
+ struct value *next_v = allocate_value (el_type);
+
+ VALUE_ADDRESS (v) = address + JAVA_OBJECT_SIZE + 4;
+ VALUE_ADDRESS (next_v) = VALUE_ADDRESS (v);
+
+ while (i < length && things_printed < print_max)
+ {
+ fputs_filtered (", ", stream);
+ wrap_here (n_spaces (2));
+
+ if (i > 0)
+ {
+ struct value *tmp;
+
+ tmp = next_v;
+ next_v = v;
+ v = tmp;
+ }
+ else
+ {
+ VALUE_LAZY (v) = 1;
+ VALUE_OFFSET (v) = 0;
+ }
+
+ VALUE_OFFSET (next_v) = VALUE_OFFSET (v);
+
+ for (reps = 1; i + reps < length; reps++)
+ {
+ VALUE_LAZY (next_v) = 1;
+ VALUE_OFFSET (next_v) += TYPE_LENGTH (el_type);
+ if (memcmp (VALUE_CONTENTS (v), VALUE_CONTENTS (next_v),
+ TYPE_LENGTH (el_type)) != 0)
+ break;
+ }
+
+ if (reps == 1)
+ fprintf_filtered (stream, "%d: ", i);
+ else
+ fprintf_filtered (stream, "%d..%d: ", i, i + reps - 1);
+
+ val_print (VALUE_TYPE (v), VALUE_CONTENTS (v), 0, 0,
+ stream, format, 2, 1, pretty);
+
+ things_printed++;
+ i += reps;
+ }
+ }
+
+ if (i < length)
+ fprintf_filtered (stream, "...");
+
+ fprintf_filtered (stream, "}");
+
+ return 0;
+ }
+
+ /* If it's type String, print it */
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR
+ && TYPE_TARGET_TYPE (type)
+ && TYPE_TAG_NAME (TYPE_TARGET_TYPE (type))
+ && strcmp (TYPE_TAG_NAME (TYPE_TARGET_TYPE (type)),
+ "java.lang.String") == 0
+ && (format == 0 || format == 's')
+ && address != 0
+ && value_as_address (val) != 0)
+ {
+ struct value *data_val;
+ CORE_ADDR data;
+ struct value *boffset_val;
+ unsigned long boffset;
+ struct value *count_val;
+ unsigned long count;
+ struct value *mark;
+
+ mark = value_mark (); /* Remember start of new values */
+
+ data_val = value_struct_elt (&val, NULL, "data", NULL, NULL);
+ data = value_as_address (data_val);
+
+ boffset_val = value_struct_elt (&val, NULL, "boffset", NULL, NULL);
+ boffset = value_as_address (boffset_val);
+
+ count_val = value_struct_elt (&val, NULL, "count", NULL, NULL);
+ count = value_as_address (count_val);
+
+ value_free_to_mark (mark); /* Release unnecessary values */
+
+ val_print_string (data + boffset, count, 2, stream);
+
+ return 0;
+ }
+
+ return (val_print (type, VALUE_CONTENTS (val), 0, address,
+ stream, format, 1, 0, pretty));
+}
+
+/* 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. */
+
+static void
+java_print_value_fields (struct type *type, char *valaddr, CORE_ADDR address,
+ struct ui_file *stream, int format, int recurse,
+ enum val_prettyprint pretty)
+{
+ int i, len, n_baseclasses;
+
+ CHECK_TYPEDEF (type);
+
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ if (n_baseclasses > 0)
+ {
+ int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ int boffset;
+ struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
+ char *basename = TYPE_NAME (baseclass);
+ char *base_valaddr;
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ continue;
+
+ if (basename != NULL && strcmp (basename, "java.lang.Object") == 0)
+ continue;
+
+ boffset = 0;
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * (recurse + 1), 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);
+
+ base_valaddr = valaddr;
+
+ java_print_value_fields (baseclass, base_valaddr, address + boffset,
+ stream, format, recurse + 1, pretty);
+ fputs_filtered (", ", stream);
+ }
+
+ }
+
+ if (!len && n_baseclasses == 1)
+ fprintf_filtered (stream, "<No data fields>");
+ else
+ {
+ int fields_seen = 0;
+
+ for (i = n_baseclasses; i < len; i++)
+ {
+ /* If requested, skip printing of static fields. */
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ char *name = TYPE_FIELD_NAME (type, i);
+ if (!static_field_print)
+ continue;
+ if (name != NULL && strcmp (name, "class") == 0)
+ 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))
+ {
+ struct value *v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", 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,
+ 0, stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ else
+ {
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", stream);
+ }
+ else if (TYPE_FIELD_STATIC (type, i))
+ {
+ struct value *v = value_static_field (type, i);
+ if (v == NULL)
+ fputs_filtered ("<optimized out>", stream);
+ else
+ {
+ struct type *t = check_typedef (VALUE_TYPE (v));
+ if (TYPE_CODE (t) == TYPE_CODE_STRUCT)
+ v = value_addr (v);
+ val_print (VALUE_TYPE (v),
+ VALUE_CONTENTS (v), 0, VALUE_ADDRESS (v),
+ stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ else if (TYPE_FIELD_TYPE (type, i) == NULL)
+ fputs_filtered ("<unknown type>", stream);
+ else
+ {
+ val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / 8, 0,
+ address + TYPE_FIELD_BITPOS (type, i) / 8,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ annotate_field_end ();
+ }
+
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ }
+ fprintf_filtered (stream, "}");
+}
+
+/* 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
+java_val_print (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ unsigned int i = 0; /* Number of characters printed */
+ struct type *target_type;
+ CORE_ADDR addr;
+
+ CHECK_TYPEDEF (type);
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ if (format && format != 's')
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+#if 0
+ 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.) */
+ /* Extract an address, assume that it is unsigned. */
+ print_address_demangle (extract_unsigned_integer (valaddr, TYPE_LENGTH (type)),
+ stream, demangle);
+ break;
+ }
+#endif
+ addr = unpack_pointer (type, valaddr);
+ if (addr == 0)
+ {
+ fputs_filtered ("null", stream);
+ return i;
+ }
+ target_type = check_typedef (TYPE_TARGET_TYPE (type));
+
+ if (TYPE_CODE (target_type) == 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')
+ {
+ fputs_filtered ("@", stream);
+ print_longest (stream, 'x', 0, (ULONGEST) addr);
+ }
+
+ return i;
+
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_INT:
+ /* Can't just call c_val_print because that prints bytes as C
+ chars. */
+ format = format ? format : output_format;
+ if (format)
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ else if (TYPE_CODE (type) == TYPE_CODE_CHAR
+ || (TYPE_CODE (type) == TYPE_CODE_INT
+ && TYPE_LENGTH (type) == 2
+ && strcmp (TYPE_NAME (type), "char") == 0))
+ LA_PRINT_CHAR ((int) unpack_long (type, valaddr), stream);
+ else
+ val_print_type_code_int (type, valaddr, stream);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ java_print_value_fields (type, valaddr, address, stream, format,
+ recurse, pretty);
+ break;
+
+ default:
+ return c_val_print (type, valaddr, embedded_offset, address, stream,
+ format, deref_ref, recurse, pretty);
+ }
+
+ return 0;
+}
diff --git a/contrib/gdb/gdb/kod-cisco.c b/contrib/gdb/gdb/kod-cisco.c
new file mode 100644
index 0000000..de2b450
--- /dev/null
+++ b/contrib/gdb/gdb/kod-cisco.c
@@ -0,0 +1,317 @@
+/* Kernel Object Display facility for Cisco
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ Written by Tom Tromey <tromey@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 "kod.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* Define this to turn off communication with target. */
+/* #define FAKE_PACKET */
+
+/* Size of buffer used for remote communication. */
+#define PBUFSIZ 400
+
+/* Pointers to gdb callbacks. */
+static void (*gdb_kod_display) (char *);
+static void (*gdb_kod_query) (char *, char *, int *);
+
+
+
+/* Initialize and return library name and version.
+ The gdb side of KOD, kod.c, passes us two functions: one for
+ displaying output (presumably to the user) and the other for
+ querying the target. */
+char *
+cisco_kod_open (kod_display_callback_ftype *display_func,
+ kod_query_callback_ftype *query_func)
+{
+ char buffer[PBUFSIZ];
+ int bufsiz = PBUFSIZ;
+ int i, count;
+
+ gdb_kod_display = display_func;
+ gdb_kod_query = query_func;
+
+ /* Get the OS info, and check the version field. This is the stub
+ version, which we use to see whether we will understand what
+ comes back. This is lame, but the `qKoL' request doesn't
+ actually provide enough configurability.
+
+ Right now the only defined version number is `0.0.0'.
+ This stub supports qKoI and the `a' (any) object requests qKaL
+ and qKaI. Each `a' object is returned as a 4-byte integer ID.
+ An info request on an object returns a pair of 4-byte integers;
+ the first is the object pointer and the second is the thread ID. */
+
+#ifndef FAKE_PACKET
+ (*gdb_kod_query) ("oI;", buffer, &bufsiz);
+#else
+ strcpy (buffer, "Cisco IOS/Classic/13.4 0.0.0");
+#endif
+
+ count = 2;
+ for (i = 0; count && buffer[i] != '\0'; ++i)
+ {
+ if (buffer[i] == ' ')
+ --count;
+ }
+
+ if (buffer[i] == '\0')
+ error ("Remote returned malformed packet\n");
+ if (strcmp (&buffer[i], "0.0.0"))
+ error ("Remote returned unknown stub version: %s\n", &buffer[i]);
+
+ /* Return name, version, and description. I hope we have enough
+ space. */
+ return (xstrdup ("gdbkodcisco v0.0.0 - Cisco Kernel Object Display"));
+}
+
+/* Close the connection. */
+void
+cisco_kod_close (void)
+{
+}
+
+/* Print a "bad packet" message. */
+static void
+bad_packet (void)
+{
+ (*gdb_kod_display) ("Remote target returned malformed packet.\n");
+}
+
+/* Print information about currently known kernel objects.
+ We currently ignore the argument. There is only one mode of
+ querying the Cisco kernel: we ask for a dump of everything, and
+ it returns it. */
+void
+cisco_kod_request (char *arg, int from_tty)
+{
+ char buffer[PBUFSIZ], command[PBUFSIZ];
+ int done = 0, i;
+ int fail = 0;
+
+ char **sync_ids = NULL;
+ int sync_len = 0;
+ int sync_next = 0;
+ char *prev_id = NULL;
+
+ if (! arg || strcmp (arg, "any"))
+ {
+ /* "Top-level" command. This is really silly, but it also seems
+ to be how KOD is defined. */
+ /* Even sillier is the fact that this first line must start
+ with the word "List". See kod.tcl. */
+ (*gdb_kod_display) ("List of Cisco Kernel Objects\n");
+ (*gdb_kod_display) ("Object\tDescription\n");
+ (*gdb_kod_display) ("any\tAny and all objects\n");
+ return;
+ }
+
+ while (! done)
+ {
+ int off = 0; /* Where we are in the string. */
+ long count; /* Number of objects in this packet. */
+ int bufsiz = PBUFSIZ;
+ char *s_end;
+
+ strcpy (command, "aL");
+ if (prev_id)
+ {
+ strcat (command, ",");
+ strcat (command, prev_id);
+ }
+ strcat (command, ";");
+
+#ifndef FAKE_PACKET
+ /* We talk to the target by calling through the query function
+ passed to us when we were initialized. */
+ (*gdb_kod_query) (command, buffer, &bufsiz);
+#else
+ /* Fake up a multi-part packet. */
+ if (! strncmp (&command[3], "a500005a", 8))
+ strcpy (buffer, "KAL,01,1,f500005f;f500005f;");
+ else
+ strcpy (buffer, "KAL,02,0,a500005a;a500005a;de02869f;");
+#endif
+
+ /* Empty response is an error. */
+ if (strlen (buffer) == 0)
+ {
+ (*gdb_kod_display) ("Remote target did not recognize kernel object query command.\n");
+ fail = 1;
+ break;
+ }
+
+ /* If we don't get a `K' response then the buffer holds the
+ target's error message. */
+ if (buffer[0] != 'K')
+ {
+ (*gdb_kod_display) (buffer);
+ fail = 1;
+ break;
+ }
+
+ /* Make sure we get the response we expect. */
+ if (strncmp (buffer, "KAL,", 4))
+ {
+ bad_packet ();
+ fail = 1;
+ break;
+ }
+ off += 4;
+
+ /* Parse out the count. We expect to convert exactly two
+ characters followed by a comma. */
+ count = strtol (&buffer[off], &s_end, 16);
+ if (s_end - &buffer[off] != 2 || buffer[off + 2] != ',')
+ {
+ bad_packet ();
+ fail = 1;
+ break;
+ }
+ off += 3;
+
+ /* Parse out the `done' flag. */
+ if ((buffer[off] != '0' && buffer[off] != '1')
+ || buffer[off + 1] != ',')
+ {
+ bad_packet ();
+ fail = 1;
+ break;
+ }
+ done = buffer[off] == '1';
+ off += 2;
+
+ /* Id of the last item; we might this to construct the next
+ request. */
+ prev_id = &buffer[off];
+ if (strlen (prev_id) < 8 || buffer[off + 8] != ';')
+ {
+ bad_packet ();
+ fail = 1;
+ break;
+ }
+ buffer[off + 8] = '\0';
+ off += 9;
+
+ sync_len += count;
+ sync_ids = (char **) xrealloc (sync_ids, sync_len * sizeof (char *));
+
+ for (i = 0; i < count; ++i)
+ {
+ if (strlen (&buffer[off]) < 8 || buffer[off + 8] != ';')
+ {
+ bad_packet ();
+ fail = 1;
+ break;
+ }
+ buffer[off + 8] = '\0';
+ sync_ids[sync_next++] = xstrdup (&buffer[off]);
+ off += 9;
+ }
+
+ if (buffer[off] != '\0')
+ {
+ bad_packet ();
+ fail = 1;
+ break;
+ }
+ }
+
+ /* We've collected all the sync object IDs. Now query to get the
+ specific information, and arrange to print this info. */
+ if (! fail)
+ {
+ (*gdb_kod_display) ("Object ID\tObject Pointer\tThread ID\n");
+
+ for (i = 0; i < sync_next; ++i)
+ {
+ int off = 0;
+ int bufsiz = PBUFSIZ;
+
+ /* For now assume a query can be accomplished in a single
+ transaction. This is implied in the protocol document.
+ See comments above, and the KOD protocol document, to
+ understand the parsing of the return value. */
+ strcpy (command, "aI,");
+ strcat (command, sync_ids[i]);
+ strcat (command, ";");
+
+#ifndef FAKE_PACKET
+ (*gdb_kod_query) (command, buffer, &bufsiz);
+#else
+ strcpy (buffer, "KAI,");
+ strcat (buffer, sync_ids[i]);
+ strcat (buffer, ",ffef00a0,cd00123d;");
+#endif
+
+ if (strlen (buffer) == 0)
+ {
+ (*gdb_kod_display) ("Remote target did not recognize KOD command.\n");
+ break;
+ }
+
+ if (strncmp (buffer, "KAI,", 4))
+ {
+ bad_packet ();
+ break;
+ }
+ off += 4;
+
+ if (strncmp (&buffer[off], sync_ids[i], 8)
+ || buffer[off + 8] != ',')
+ {
+ bad_packet ();
+ break;
+ }
+ off += 9;
+
+ /* Extract thread id and sync object pointer. */
+ if (strlen (&buffer[off]) != 2 * 8 + 2
+ || buffer[off + 8] != ','
+ || buffer[off + 17] != ';')
+ {
+ bad_packet ();
+ break;
+ }
+
+ buffer[off + 8] = '\0';
+ buffer[off + 17] = '\0';
+
+ /* Display the result. */
+ (*gdb_kod_display) (sync_ids[i]);
+ (*gdb_kod_display) ("\t");
+ (*gdb_kod_display) (&buffer[off]);
+ (*gdb_kod_display) ("\t");
+ (*gdb_kod_display) (&buffer[off + 9]);
+ (*gdb_kod_display) ("\n");
+ }
+ }
+
+ /* Free memory. */
+ for (i = 0; i < sync_next; ++i)
+ xfree (sync_ids[i]);
+ xfree (sync_ids);
+}
diff --git a/contrib/gdb/gdb/kod.c b/contrib/gdb/gdb/kod.c
new file mode 100644
index 0000000..6cb3622
--- /dev/null
+++ b/contrib/gdb/gdb/kod.c
@@ -0,0 +1,241 @@
+/* Kernel Object Display generic routines and callbacks
+ Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ Written by Fernando Nasser <fnasser@cygnus.com> for Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "command.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "gdb_string.h"
+#include "kod.h"
+
+/* Prototypes for exported functions. */
+void _initialize_kod (void);
+
+/* Prototypes for local functions. */
+static void info_kod_command (char *, int);
+static void load_kod_library (char *);
+
+/* Prototypes for callbacks. These are passed into the KOD modules. */
+static void gdb_kod_display (char *);
+static void gdb_kod_query (char *, char *, int *);
+
+/* These functions are imported from the KOD module.
+
+ gdb_kod_open - initiates the KOD connection to the remote. The
+ first argument is the display function the module should use to
+ communicate with the user. The second argument is the query
+ function the display should use to communicate with the target.
+ This should call error() if there is an error. Otherwise it should
+ return a malloc()d string of the form:
+
+ NAME VERSION - DESCRIPTION
+
+ Neither NAME nor VERSION should contain a hyphen.
+
+
+ gdb_kod_request - This is used when the user enters an "info
+ <module>" request. The remaining arguments are passed as the first
+ argument. The second argument is the standard `from_tty'
+ argument.
+
+
+ gdb_kod_close - This is called when the KOD connection to the
+ remote should be terminated. */
+
+static char *(*gdb_kod_open) (kod_display_callback_ftype *display,
+ kod_query_callback_ftype *query);
+static void (*gdb_kod_request) (char *, int);
+static void (*gdb_kod_close) ();
+
+
+/* Name of inferior's operating system. */
+char *operating_system;
+
+/* We save a copy of the OS so that we can properly reset when
+ switching OS's. */
+static char *old_operating_system;
+
+/* Print a line of data generated by the module. */
+
+static void
+gdb_kod_display (char *arg)
+{
+ printf_filtered ("%s", arg);
+}
+
+/* Queries the target on behalf of the module. */
+
+static void
+gdb_kod_query (char *arg, char *result, int *maxsiz)
+{
+ LONGEST bufsiz = 0;
+
+ /* Check if current target has remote_query capabilities. If not,
+ it does not have kod either. */
+ bufsiz = target_read_partial (&current_target, TARGET_OBJECT_KOD,
+ NULL, NULL, 0, 0);
+ if (bufsiz < 0)
+ {
+ strcpy (result,
+ "ERR: Kernel Object Display not supported by current target\n");
+ return;
+ }
+
+ /* Just get the maximum buffer size. */
+
+ /* Check if *we* were called just for getting the buffer size. */
+ if (*maxsiz == 0)
+ {
+ *maxsiz = bufsiz;
+ strcpy (result, "OK");
+ return;
+ }
+
+ /* Check if caller can handle a buffer this large, if not, adjust. */
+ if (bufsiz > *maxsiz)
+ bufsiz = *maxsiz;
+
+ /* See if buffer can hold the query (usually it can, as the query is
+ short). */
+ if (strlen (arg) >= bufsiz)
+ error ("kod: query argument too long");
+
+ /* Send actual request. */
+ if (target_read_partial (&current_target, TARGET_OBJECT_KOD,
+ arg, result, 0, bufsiz) < 0)
+ strcpy (result, "ERR: remote query failed");
+}
+
+/* Print name of kod command after selecting the appropriate kod
+ formatting library module. As a side effect we create a new "info"
+ subcommand which is what the user actually uses to query the OS. */
+
+static void
+kod_set_os (char *arg, int from_tty, struct cmd_list_element *command)
+{
+ char *p;
+
+ /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+ the set command passed as a parameter. The clone operation will
+ include (BUG?) any ``set'' command callback, if present.
+ Commands like ``info set'' call all the ``show'' command
+ callbacks. Unfortunately, for ``show'' commands cloned from
+ ``set'', this includes callbacks belonging to ``set'' commands.
+ Making this worse, this only occures if add_show_from_set() is
+ called after add_cmd_sfunc() (BUG?). */
+
+ if (cmd_type (command) != set_cmd)
+ return;
+
+ /* If we had already had an open OS, close it. */
+ if (gdb_kod_close)
+ (*gdb_kod_close) ();
+
+ /* Also remove the old OS's command. */
+ if (old_operating_system)
+ {
+ delete_cmd (old_operating_system, &infolist);
+ xfree (old_operating_system);
+ }
+
+ if (! operating_system || ! *operating_system)
+ {
+ /* If user set operating system to empty, we want to forget we
+ had a module open. Setting these variables is just nice for
+ debugging and clarity. */
+ gdb_kod_open = NULL;
+ gdb_kod_request = NULL;
+ gdb_kod_close = NULL;
+ }
+ else
+ {
+ char *kodlib;
+
+ old_operating_system = xstrdup (operating_system);
+
+ load_kod_library (operating_system);
+
+ kodlib = (*gdb_kod_open) (gdb_kod_display, gdb_kod_query);
+
+ /* Add kod related info commands to gdb. */
+ add_info (operating_system, info_kod_command,
+ "Displays information about Kernel Objects.");
+
+ p = strrchr (kodlib, '-');
+ if (p != NULL)
+ p++;
+ else
+ p = "Unknown KOD library";
+ printf_filtered ("%s - %s\n", operating_system, p);
+
+ xfree (kodlib);
+ }
+}
+
+/* Print information about currently known kernel objects of the
+ specified type or a list of all known kernel object types if
+ argument is empty. */
+
+static void
+info_kod_command (char *arg, int from_tty)
+{
+ (*gdb_kod_request) (arg, from_tty);
+}
+
+/* Print name of kod command after selecting the appropriate kod
+ formatting library module. */
+
+static void
+load_kod_library (char *lib)
+{
+#if 0
+ /* FIXME: Don't have the eCos code here. */
+ if (! strcmp (lib, "ecos"))
+ {
+ gdb_kod_open = ecos_kod_open;
+ gdb_kod_request = ecos_kod_request;
+ gdb_kod_close = ecos_kod_close;
+ }
+ else
+#endif /* 0 */
+ if (! strcmp (lib, "cisco"))
+ {
+ gdb_kod_open = cisco_kod_open;
+ gdb_kod_request = cisco_kod_request;
+ gdb_kod_close = cisco_kod_close;
+ }
+ else
+ error ("Unknown operating system: %s\n", operating_system);
+}
+
+void
+_initialize_kod (void)
+{
+ struct cmd_list_element *c;
+
+ c = add_set_cmd ("os", no_class, var_string,
+ (char *) &operating_system,
+ "Set operating system",
+ &setlist);
+ set_cmd_sfunc (c, kod_set_os);
+ add_show_from_set (c, &showlist);
+}
diff --git a/contrib/gdb/gdb/kod.h b/contrib/gdb/gdb/kod.h
new file mode 100644
index 0000000..6c4d03a
--- /dev/null
+++ b/contrib/gdb/gdb/kod.h
@@ -0,0 +1,61 @@
+/* Kernel Object Display facility for Cisco
+ Copyright 1999 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef KOD_H
+#define KOD_H
+
+typedef void kod_display_callback_ftype (char *);
+typedef void kod_query_callback_ftype (char *, char *, int *);
+
+/* ???/???: Functions imported from the library for all supported
+ OSes. FIXME: we really should do something better, such as
+ dynamically loading the KOD modules. */
+
+/* FIXME: cagney/1999-09-20: The kod-cisco.c et.al. kernel modules
+ should register themselve with kod.c during the _initialization*()
+ phase. With that implemented the extern declarations below would
+ be replaced with the KOD register function that the various kernel
+ modules should call. An example of this mechanism can be seen in
+ gdbarch.c:register_gdbarch_init(). */
+
+#if 0
+/* Don't have ecos code yet. */
+extern char *ecos_kod_open (kod_display_callback_ftype *display_func,
+ kod_query_callback_ftype *query_func);
+extern void ecos_kod_request (char *, int);
+extern void ecos_kod_close (void);
+#endif
+
+/* Initialize and return library name and version. The gdb side of
+ KOD, kod.c, passes us two functions: one for displaying output
+ (presumably to the user) and the other for querying the target. */
+
+extern char *cisco_kod_open (kod_display_callback_ftype *display_func,
+ kod_query_callback_ftype *query_func);
+
+/* Print information about currently known kernel objects. We
+ currently ignore the argument. There is only one mode of querying
+ the Cisco kernel: we ask for a dump of everything, and it returns
+ it. */
+
+extern void cisco_kod_request (char *arg, int from_tty);
+
+extern void cisco_kod_close (void);
+
+#endif
diff --git a/contrib/gdb/gdb/language.c b/contrib/gdb/gdb/language.c
new file mode 100644
index 0000000..bc00b47
--- /dev/null
+++ b/contrib/gdb/gdb/language.c
@@ -0,0 +1,1442 @@
+/* Multiple source language support for GDB.
+
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004 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 <ctype.h>
+#include "gdb_string.h"
+
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "expression.h"
+#include "language.h"
+#include "target.h"
+#include "parser-defs.h"
+#include "jv-lang.h"
+#include "demangle.h"
+
+extern void _initialize_language (void);
+
+static void show_language_command (char *, int);
+
+static void set_language_command (char *, int);
+
+static void show_type_command (char *, int);
+
+static void set_type_command (char *, int);
+
+static void show_range_command (char *, int);
+
+static void set_range_command (char *, int);
+
+static void show_case_command (char *, int);
+
+static void set_case_command (char *, int);
+
+static void set_case_str (void);
+
+static void set_range_str (void);
+
+static void set_type_str (void);
+
+static void set_lang_str (void);
+
+static void unk_lang_error (char *);
+
+static int unk_lang_parser (void);
+
+static void show_check (char *, int);
+
+static void set_check (char *, int);
+
+static void set_type_range_case (void);
+
+static void unk_lang_emit_char (int c, struct ui_file *stream, int quoter);
+
+static void unk_lang_printchar (int c, struct ui_file *stream);
+
+static void unk_lang_printstr (struct ui_file * stream, char *string,
+ unsigned int length, int width,
+ int force_ellipses);
+
+static struct type *unk_lang_create_fundamental_type (struct objfile *, int);
+
+static void unk_lang_print_type (struct type *, char *, struct ui_file *,
+ int, int);
+
+static int unk_lang_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+static int unk_lang_value_print (struct value *, struct ui_file *, int, enum val_prettyprint);
+
+static CORE_ADDR unk_lang_trampoline (CORE_ADDR pc);
+
+/* Forward declaration */
+extern const struct language_defn unknown_language_defn;
+
+/* 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;
+enum case_mode case_mode = case_mode_auto;
+enum case_sensitivity case_sensitivity = case_sensitive_on;
+
+/* 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;
+static char *case_sensitive;
+
+/* 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 (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 (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 (strcmp (languages[i]->la_name, language) == 0)
+ {
+ /* 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_case ();
+ 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 (xfree, 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 (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 (char *ignore, int from_tty)
+{
+ if (strcmp (type, "on") == 0)
+ {
+ type_check = type_check_on;
+ type_mode = type_mode_manual;
+ }
+ else if (strcmp (type, "warn") == 0)
+ {
+ type_check = type_check_warn;
+ type_mode = type_mode_manual;
+ }
+ else if (strcmp (type, "off") == 0)
+ {
+ type_check = type_check_off;
+ type_mode = type_mode_manual;
+ }
+ else if (strcmp (type, "auto") == 0)
+ {
+ type_mode = type_mode_auto;
+ set_type_range_case ();
+ /* Avoid hitting the set_type_str call below. We
+ did it in set_type_range_case. */
+ return;
+ }
+ else
+ {
+ warning ("Unrecognized type check setting: \"%s\"", type);
+ }
+ 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 (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 (char *ignore, int from_tty)
+{
+ if (strcmp (range, "on") == 0)
+ {
+ range_check = range_check_on;
+ range_mode = range_mode_manual;
+ }
+ else if (strcmp (range, "warn") == 0)
+ {
+ range_check = range_check_warn;
+ range_mode = range_mode_manual;
+ }
+ else if (strcmp (range, "off") == 0)
+ {
+ range_check = range_check_off;
+ range_mode = range_mode_manual;
+ }
+ else if (strcmp (range, "auto") == 0)
+ {
+ range_mode = range_mode_auto;
+ set_type_range_case ();
+ /* Avoid hitting the set_range_str call below. We
+ did it in set_type_range_case. */
+ return;
+ }
+ else
+ {
+ warning ("Unrecognized range check setting: \"%s\"", range);
+ }
+ set_range_str ();
+ show_range_command ((char *) 0, from_tty);
+}
+
+/* Show command. Display a warning if the case sensitivity setting does
+ not match the current language. */
+static void
+show_case_command (char *ignore, int from_tty)
+{
+ if (case_sensitivity != current_language->la_case_sensitivity)
+ printf_unfiltered(
+"Warning: the current case sensitivity setting does not match the language.\n");
+}
+
+/* Set command. Change the setting for case sensitivity. */
+static void
+set_case_command (char *ignore, int from_tty)
+{
+ if (DEPRECATED_STREQ (case_sensitive, "on"))
+ {
+ case_sensitivity = case_sensitive_on;
+ case_mode = case_mode_manual;
+ }
+ else if (DEPRECATED_STREQ (case_sensitive, "off"))
+ {
+ case_sensitivity = case_sensitive_off;
+ case_mode = case_mode_manual;
+ }
+ else if (DEPRECATED_STREQ (case_sensitive, "auto"))
+ {
+ case_mode = case_mode_auto;
+ set_type_range_case ();
+ /* Avoid hitting the set_case_str call below. We
+ did it in set_type_range_case. */
+ return;
+ }
+ else
+ {
+ warning ("Unrecognized case-sensitive setting: \"%s\"", case_sensitive);
+ }
+ set_case_str();
+ show_case_command ((char *) NULL, from_tty);
+}
+
+/* Set the status of range and type checking and case sensitivity 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_case (void)
+{
+
+ 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;
+
+ if (case_mode == case_mode_auto)
+ case_sensitivity = current_language->la_case_sensitivity;
+
+ set_type_str ();
+ set_range_str ();
+ set_case_str ();
+}
+
+/* Set current language to (enum language) LANG. Returns previous language. */
+
+enum language
+set_language (enum language lang)
+{
+ int i;
+ enum language prev_language;
+
+ prev_language = current_language->la_language;
+
+ for (i = 0; i < languages_size; i++)
+ {
+ if (languages[i]->la_language == lang)
+ {
+ current_language = languages[i];
+ set_type_range_case ();
+ set_lang_str ();
+ break;
+ }
+ }
+
+ return prev_language;
+}
+
+/* This page contains functions that update the global vars
+ language, type and range. */
+static void
+set_lang_str (void)
+{
+ char *prefix = "";
+
+ if (language)
+ xfree (language);
+ if (language_mode == language_mode_auto)
+ prefix = "auto; currently ";
+
+ language = concat (prefix, current_language->la_name, NULL);
+}
+
+static void
+set_type_str (void)
+{
+ char *tmp = NULL, *prefix = "";
+
+ if (type)
+ xfree (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 (void)
+{
+ char *tmp, *pref = "";
+
+ 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.");
+ }
+
+ if (range)
+ xfree (range);
+ range = concat (pref, tmp, NULL);
+}
+
+static void
+set_case_str (void)
+{
+ char *tmp = NULL, *prefix = "";
+
+ if (case_mode==case_mode_auto)
+ prefix = "auto; currently ";
+
+ switch (case_sensitivity)
+ {
+ case case_sensitive_on:
+ tmp = "on";
+ break;
+ case case_sensitive_off:
+ tmp = "off";
+ break;
+ default:
+ error ("Unrecognized case-sensitive setting.");
+ }
+
+ xfree (case_sensitive);
+ case_sensitive = concat (prefix, tmp, NULL);
+}
+
+/* Print out the current language settings: language, range and
+ type checking. If QUIETLY, print only what has changed. */
+
+void
+language_info (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);
+ printf_unfiltered ("Case sensitivity: %s\n", case_sensitive);
+ show_case_command ((char *) 0, 1);
+ }
+}
+
+/* Return the result of a binary operation. */
+
+#if 0 /* Currently unused */
+
+struct type *
+binop_result_type (struct value *v1, struct value *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:
+ case language_objc:
+ 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;
+ }
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ 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 (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 LONGEST to custom hexadecimal and stores it in a static
+ string. Returns a pointer to this string. */
+char *
+local_hex_string (LONGEST num)
+{
+ return local_hex_string_custom (num, "l");
+}
+
+/* Converts a LONGEST number to custom hexadecimal and stores it in a static
+ string. Returns a pointer to this string. Note that the width parameter
+ should end with "l", e.g. "08l" as with calls to local_hex_string_custom */
+
+char *
+local_hex_string_custom (LONGEST num, char *width)
+{
+#define RESULT_BUF_LEN 50
+ static char res2[RESULT_BUF_LEN];
+ char format[RESULT_BUF_LEN];
+ int field_width;
+ int num_len;
+ int num_pad_chars;
+ char *pad_char; /* string with one character */
+ int pad_on_left;
+ char *parse_ptr;
+ char temp_nbr_buf[RESULT_BUF_LEN];
+
+ /* Use phex_nz to print the number into a string, then
+ build the result string from local_hex_format_prefix, padding and
+ the hex representation as indicated by "width". */
+ strcpy (temp_nbr_buf, phex_nz (num, sizeof (num)));
+ /* parse width */
+ parse_ptr = width;
+ pad_on_left = 1;
+ pad_char = " ";
+ if (*parse_ptr == '-')
+ {
+ parse_ptr++;
+ pad_on_left = 0;
+ }
+ if (*parse_ptr == '0')
+ {
+ parse_ptr++;
+ if (pad_on_left)
+ pad_char = "0"; /* If padding is on the right, it is blank */
+ }
+ field_width = atoi (parse_ptr);
+ num_len = strlen (temp_nbr_buf);
+ num_pad_chars = field_width - strlen (temp_nbr_buf); /* possibly negative */
+
+ if (strlen (local_hex_format_prefix ()) + num_len + num_pad_chars
+ >= RESULT_BUF_LEN) /* paranoia */
+ internal_error (__FILE__, __LINE__,
+ "local_hex_string_custom: insufficient space to store result");
+
+ strcpy (res2, local_hex_format_prefix ());
+ if (pad_on_left)
+ {
+ while (num_pad_chars > 0)
+ {
+ strcat (res2, pad_char);
+ num_pad_chars--;
+ }
+ }
+ strcat (res2, temp_nbr_buf);
+ if (!pad_on_left)
+ {
+ while (num_pad_chars > 0)
+ {
+ strcat (res2, pad_char);
+ num_pad_chars--;
+ }
+ }
+ return res2;
+
+} /* local_hex_string_custom */
+
+/* Returns the appropriate printf format for octal
+ numbers. */
+char *
+local_octal_format_custom (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 (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 (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 (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 (struct type *arg1, struct type *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 (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ switch (current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ case language_objc:
+ return (TYPE_CODE (type) != TYPE_CODE_INT) &&
+ (TYPE_CODE (type) != TYPE_CODE_ENUM) ? 0 : 1;
+ case language_m2:
+ case language_pascal:
+ return TYPE_CODE (type) != TYPE_CODE_INT ? 0 : 1;
+ default:
+ error ("Language not supported.");
+ }
+}
+
+/* Returns non-zero if the value is numeric */
+int
+numeric_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 (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ switch (current_language->la_language)
+ {
+ case language_m2:
+ case language_pascal:
+ return TYPE_CODE (type) != TYPE_CODE_CHAR ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ case language_objc:
+ 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 (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ switch (current_language->la_language)
+ {
+ case language_m2:
+ case language_pascal:
+ return TYPE_CODE (type) != TYPE_CODE_STRING ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ case language_objc:
+ /* 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 (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:
+ case language_objc:
+ /* Might be more cleanly handled by having a
+ TYPE_CODE_INT_NOT_BOOL for (the deleted) 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 (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 (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 (struct type *type)
+{
+ CHECK_TYPEDEF (type);
+ switch (current_language->la_language)
+ {
+ case language_c:
+ case language_cplus:
+ case language_objc:
+ return (TYPE_CODE (type) == TYPE_CODE_STRUCT) ||
+ (TYPE_CODE (type) == TYPE_CODE_UNION) ||
+ (TYPE_CODE (type) == TYPE_CODE_ARRAY);
+ case language_pascal:
+ return (TYPE_CODE(type) == TYPE_CODE_STRUCT) ||
+ (TYPE_CODE(type) == TYPE_CODE_UNION) ||
+ (TYPE_CODE(type) == TYPE_CODE_SET) ||
+ (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);
+ default:
+ return (0);
+ }
+}
+#endif
+
+struct type *
+lang_bool_type (void)
+{
+ struct symbol *sym;
+ struct type *type;
+ switch (current_language->la_language)
+ {
+ case language_fortran:
+ sym = lookup_symbol ("logical", NULL, VAR_DOMAIN, 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:
+ case language_pascal:
+ if (current_language->la_language==language_cplus)
+ {sym = lookup_symbol ("bool", NULL, VAR_DOMAIN, NULL, NULL);}
+ else
+ {sym = lookup_symbol ("boolean", NULL, VAR_DOMAIN, NULL, NULL);}
+ if (sym)
+ {
+ type = SYMBOL_TYPE (sym);
+ if (type && TYPE_CODE (type) == TYPE_CODE_BOOL)
+ return type;
+ }
+ return builtin_type_bool;
+ case language_java:
+ sym = lookup_symbol ("boolean", NULL, VAR_DOMAIN, NULL, NULL);
+ if (sym)
+ {
+ type = SYMBOL_TYPE (sym);
+ if (type && TYPE_CODE (type) == TYPE_CODE_BOOL)
+ return type;
+ }
+ return java_boolean_type;
+ 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 (struct value *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);
+}
+
+/* This page contains functions for the printing out of
+ error messages that occur during type- and range-
+ checking. */
+
+/* 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, an error is printed;
+ if [type|range]_check_warn, a warning; otherwise just the
+ message. */
+
+void
+type_error (const char *string,...)
+{
+ va_list args;
+ va_start (args, string);
+
+ switch (type_check)
+ {
+ case type_check_warn:
+ vwarning (string, args);
+ break;
+ case type_check_on:
+ verror (string, args);
+ break;
+ case type_check_off:
+ /* FIXME: cagney/2002-01-30: Should this function print anything
+ when type error is off? */
+ vfprintf_filtered (gdb_stderr, string, args);
+ fprintf_filtered (gdb_stderr, "\n");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ va_end (args);
+}
+
+void
+range_error (const char *string,...)
+{
+ va_list args;
+ va_start (args, string);
+
+ switch (range_check)
+ {
+ case range_check_warn:
+ vwarning (string, args);
+ break;
+ case range_check_on:
+ verror (string, args);
+ break;
+ case range_check_off:
+ /* FIXME: cagney/2002-01-30: Should this function print anything
+ when range error is off? */
+ vfprintf_filtered (gdb_stderr, string, args);
+ fprintf_filtered (gdb_stderr, "\n");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ va_end (args);
+}
+
+
+/* This page contains miscellaneous functions */
+
+/* Return the language enum for a given language string. */
+
+enum language
+language_enum (char *str)
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++)
+ if (DEPRECATED_STREQ (languages[i]->la_name, str))
+ return languages[i]->la_language;
+
+ return language_unknown;
+}
+
+/* Return the language struct for a given language enum. */
+
+const struct language_defn *
+language_def (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 (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 (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 (char *ignore, int from_tty)
+{
+ cmd_show_list (showchecklist, from_tty, "");
+}
+
+/* Add a language to the set of known languages. */
+
+void
+add_language (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);
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+
+ 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;
+}
+
+/* Iterate through all registered languages looking for and calling
+ any non-NULL struct language_defn.skip_trampoline() functions.
+ Return the result from the first that returns non-zero, or 0 if all
+ `fail'. */
+CORE_ADDR
+skip_language_trampoline (CORE_ADDR pc)
+{
+ int i;
+
+ for (i = 0; i < languages_size; i++)
+ {
+ if (languages[i]->skip_trampoline)
+ {
+ CORE_ADDR real_pc = (languages[i]->skip_trampoline) (pc);
+ if (real_pc)
+ return real_pc;
+ }
+ }
+
+ return 0;
+}
+
+/* Return demangled language symbol, or NULL.
+ FIXME: Options are only useful for certain languages and ignored
+ by others, so it would be better to remove them here and have a
+ more flexible demangler for the languages that need it.
+ FIXME: Sometimes the demangler is invoked when we don't know the
+ language, so we can't use this everywhere. */
+char *
+language_demangle (const struct language_defn *current_language,
+ const char *mangled, int options)
+{
+ if (current_language != NULL && current_language->la_demangle)
+ return current_language->la_demangle (mangled, options);
+ return NULL;
+}
+
+/* Return the default string containing the list of characters
+ delimiting words. This is a reasonable default value that
+ most languages should be able to use. */
+
+char *
+default_word_break_characters (void)
+{
+ return " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-";
+}
+
+/* Define the language that is no language. */
+
+static int
+unk_lang_parser (void)
+{
+ return 1;
+}
+
+static void
+unk_lang_error (char *msg)
+{
+ error ("Attempted to parse an expression with unknown language");
+}
+
+static void
+unk_lang_emit_char (int c, struct ui_file *stream, int quoter)
+{
+ error ("internal error - unimplemented function unk_lang_emit_char called.");
+}
+
+static void
+unk_lang_printchar (int c, struct ui_file *stream)
+{
+ error ("internal error - unimplemented function unk_lang_printchar called.");
+}
+
+static void
+unk_lang_printstr (struct ui_file *stream, char *string, unsigned int length,
+ int width, int force_ellipses)
+{
+ error ("internal error - unimplemented function unk_lang_printstr called.");
+}
+
+static struct type *
+unk_lang_create_fundamental_type (struct objfile *objfile, int typeid)
+{
+ error ("internal error - unimplemented function unk_lang_create_fundamental_type called.");
+}
+
+static void
+unk_lang_print_type (struct type *type, char *varstring, struct ui_file *stream,
+ int show, int level)
+{
+ error ("internal error - unimplemented function unk_lang_print_type called.");
+}
+
+static int
+unk_lang_val_print (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ error ("internal error - unimplemented function unk_lang_val_print called.");
+}
+
+static int
+unk_lang_value_print (struct value *val, struct ui_file *stream, int format,
+ enum val_prettyprint pretty)
+{
+ error ("internal error - unimplemented function unk_lang_value_print called.");
+}
+
+static CORE_ADDR unk_lang_trampoline (CORE_ADDR pc)
+{
+ return 0;
+}
+
+/* Unknown languages just use the cplus demangler. */
+static char *unk_lang_demangle (const char *mangled, int options)
+{
+ return cplus_demangle (mangled, options);
+}
+
+
+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,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_emit_char,
+ 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 */
+ unk_lang_trampoline, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ unk_lang_demangle, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ 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,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_emit_char,
+ 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 */
+ unk_lang_trampoline, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ unk_lang_demangle, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+const struct language_defn local_language_defn =
+{
+ "local",
+ language_auto,
+ &unknown_builtin_types[0],
+ range_check_off,
+ type_check_off,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ unk_lang_parser,
+ unk_lang_error,
+ unk_lang_printchar, /* Print character constant */
+ unk_lang_printstr,
+ unk_lang_emit_char,
+ 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 */
+ unk_lang_trampoline, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ unk_lang_demangle, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+/* Initialize the language routines */
+
+void
+_initialize_language (void)
+{
+ 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_cmd_cfunc (set, set_language_command);
+ set_cmd_cfunc (show, 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_cmd_cfunc (set, set_type_command);
+ set_cmd_cfunc (show, 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_cmd_cfunc (set, set_range_command);
+ set_cmd_cfunc (show, show_range_command);
+
+ set = add_set_cmd ("case-sensitive", class_support, var_string_noescape,
+ (char *) &case_sensitive,
+ "Set case sensitivity in name search. (on/off/auto)\n\
+For Fortran the default is off; for other languages the default is on.",
+ &setlist);
+ show = add_show_from_set (set, &showlist);
+ set_cmd_cfunc (set, set_case_command);
+ set_cmd_cfunc (show, show_case_command);
+
+ add_language (&unknown_language_defn);
+ add_language (&local_language_defn);
+ add_language (&auto_language_defn);
+
+ language = savestring ("auto", strlen ("auto"));
+ type = savestring ("auto", strlen ("auto"));
+ range = savestring ("auto", strlen ("auto"));
+ case_sensitive = savestring ("auto",strlen ("auto"));
+
+ /* Have the above take effect */
+ set_language (language_auto);
+}
diff --git a/contrib/gdb/gdb/language.h b/contrib/gdb/gdb/language.h
new file mode 100644
index 0000000..8ed9fb0
--- /dev/null
+++ b/contrib/gdb/gdb/language.h
@@ -0,0 +1,514 @@
+/* Source-language-related definitions for GDB.
+
+ Copyright 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2003,
+ 2004 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
+
+/* Forward decls for prototypes */
+struct value;
+struct objfile;
+struct expression;
+struct ui_file;
+
+/* enum exp_opcode; ANSI's `wisdom' didn't include forward enum decls. */
+
+/* This used to be included to configure GDB for one or more specific
+ languages. Now it is left out to configure for all of them. FIXME. */
+/* #include "lang_def.h" */
+#define _LANG_c
+#define _LANG_m2
+#define _LANG_fortran
+#define _LANG_pascal
+
+#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;
+
+/* case_mode ==
+ case_mode_auto: case_sensitivity set upon selection of scope
+ case_mode_manual: case_sensitivity set only by user. */
+
+extern enum case_mode
+ {
+ case_mode_auto, case_mode_manual
+ }
+case_mode;
+
+/* case_sensitivity ==
+ case_sensitive_on: Case sensitivity in name matching is used
+ case_sensitive_off: Case sensitivity in name matching is not used */
+
+extern enum case_sensitivity
+ {
+ case_sensitive_on, case_sensitive_off
+ }
+case_sensitivity;
+
+/* 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;
+
+ /* Default case sensitivity */
+ enum case_sensitivity la_case_sensitivity;
+
+ /* Definitions related to expression printing, prefixifying, and
+ dumping */
+
+ const struct exp_descriptor *la_exp_desc;
+
+ /* Parser function. */
+
+ int (*la_parser) (void);
+
+ /* Parser error function */
+
+ void (*la_error) (char *);
+
+ void (*la_printchar) (int ch, struct ui_file * stream);
+
+ void (*la_printstr) (struct ui_file * stream, char *string,
+ unsigned int length, int width,
+ int force_ellipses);
+
+ void (*la_emitchar) (int ch, struct ui_file * stream, int quoter);
+
+ struct type *(*la_fund_type) (struct objfile *, int);
+
+ /* Print a type using syntax appropriate for this language. */
+
+ void (*la_print_type) (struct type *, char *, struct ui_file *, int,
+ int);
+
+ /* Print a value using syntax appropriate for this language. */
+
+ int (*la_val_print) (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+ /* Print a top-level value using syntax appropriate for this language. */
+
+ int (*la_value_print) (struct value *, struct ui_file *,
+ int, enum val_prettyprint);
+
+ /* PC is possibly an unknown languages trampoline.
+ If that PC falls in a trampoline belonging to this language,
+ return the address of the first pc in the real function, or 0
+ if it isn't a language tramp for this language. */
+ CORE_ADDR (*skip_trampoline) (CORE_ADDR pc);
+
+ /* Now come some hooks for lookup_symbol. */
+
+ /* If this is non-NULL, lookup_symbol will do the 'field_of_this'
+ check, using this function to find the value of this. */
+
+ /* FIXME: carlton/2003-05-19: Audit all the language_defn structs
+ to make sure we're setting this appropriately: I'm sure it
+ could be NULL in more languages. */
+
+ struct value *(*la_value_of_this) (int complain);
+
+ /* This is a function that lookup_symbol will call when it gets to
+ the part of symbol lookup where C looks up static and global
+ variables. */
+
+ struct symbol *(*la_lookup_symbol_nonlocal) (const char *,
+ const char *,
+ const struct block *,
+ const domain_enum,
+ struct symtab **);
+
+ /* Find the definition of the type with the given name. */
+ struct type *(*la_lookup_transparent_type) (const char *);
+
+ /* Return demangled language symbol, or NULL. */
+ char *(*la_demangle) (const char *mangled, int options);
+
+ /* 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;
+
+ /* The list of characters forming word boundaries. */
+ char *(*la_word_break_characters) (void);
+
+ /* 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 separate 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 || \
+ current_language->la_language == language_objc)
+
+extern void language_info (int);
+
+extern enum language set_language (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,offset,addr,stream,fmt,deref,recurse,pretty) \
+ (current_language->la_val_print(type,valaddr,offset,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, width, force_ellipses) \
+ (current_language->la_printstr(stream, string, length, width, force_ellipses))
+#define LA_EMIT_CHAR(ch, stream, quoter) \
+ (current_language->la_emitchar(ch, stream, quoter))
+
+/* 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 (char *); /* language.c */
+
+extern char *local_octal_format_custom (char *); /* language.c */
+
+extern char *local_hex_format_custom (char *); /* language.c */
+
+#if 0
+/* FIXME: cagney/2000-03-04: This function does not appear to be used.
+ It can be deleted once 5.0 has been released. */
+/* Return a string that contains the hex digits of the number. No preceeding
+ "0x" */
+
+extern char *longest_raw_hex_string (LONGEST);
+#endif
+
+/* 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 "08l" or "l". */
+
+extern char *local_hex_string (LONGEST); /* language.c */
+
+extern char *local_hex_string_custom (LONGEST, char *); /* language.c */
+
+/* Type predicates */
+
+extern int simple_type (struct type *);
+
+extern int ordered_type (struct type *);
+
+extern int same_type (struct type *, struct type *);
+
+extern int integral_type (struct type *);
+
+extern int numeric_type (struct type *);
+
+extern int character_type (struct type *);
+
+extern int boolean_type (struct type *);
+
+extern int float_type (struct type *);
+
+extern int pointer_type (struct type *);
+
+extern int structured_type (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 (struct value *, struct value *, int);
+
+/* Error messages */
+
+extern void op_error (const char *lhs, enum exp_opcode,
+ const char *rhs);
+
+extern void type_error (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+
+extern void range_error (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+
+/* Data: Does this value represent "truth" to the current language? */
+
+extern int value_true (struct value *);
+
+extern struct type *lang_bool_type (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 enum language language_enum (char *str);
+
+extern const struct language_defn *language_def (enum language);
+
+extern char *language_str (enum language);
+
+/* Add a language to the set known by GDB (at initialization time). */
+
+extern void add_language (const struct language_defn *);
+
+extern enum language get_frame_language (void); /* In stack.c */
+
+/* Check for a language-specific trampoline. */
+
+extern CORE_ADDR skip_language_trampoline (CORE_ADDR pc);
+
+/* Return demangled language symbol, or NULL. */
+extern char *language_demangle (const struct language_defn *current_language,
+ const char *mangled, int options);
+
+/* Splitting strings into words. */
+extern char *default_word_break_characters (void);
+
+#endif /* defined (LANGUAGE_H) */
diff --git a/contrib/gdb/gdb/libunwind-frame.c b/contrib/gdb/gdb/libunwind-frame.c
new file mode 100644
index 0000000..bf0c36d
--- /dev/null
+++ b/contrib/gdb/gdb/libunwind-frame.c
@@ -0,0 +1,387 @@
+/* Frame unwinder for frames using the libunwind library.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Written by Jeff Johnston, contributed by Red Hat Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "gdbcore.h"
+#include "gdbtypes.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "regcache.h"
+
+#include <dlfcn.h>
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "libunwind-frame.h"
+
+#include "complaints.h"
+
+static int libunwind_initialized;
+static struct gdbarch_data *libunwind_descr_handle;
+
+#ifndef LIBUNWIND_SO
+#define LIBUNWIND_SO "libunwind.so"
+#endif
+
+/* Required function pointers from libunwind. */
+static int (*unw_get_reg_p) (unw_cursor_t *, unw_regnum_t, unw_word_t *);
+static int (*unw_get_fpreg_p) (unw_cursor_t *, unw_regnum_t, unw_fpreg_t *);
+static int (*unw_get_saveloc_p) (unw_cursor_t *, unw_regnum_t, unw_save_loc_t *);
+static int (*unw_step_p) (unw_cursor_t *);
+static int (*unw_init_remote_p) (unw_cursor_t *, unw_addr_space_t, void *);
+static unw_addr_space_t (*unw_create_addr_space_p) (unw_accessors_t *, int);
+static int (*unw_search_unwind_table_p) (unw_addr_space_t, unw_word_t, unw_dyn_info_t *,
+ unw_proc_info_t *, int, void *);
+static unw_word_t (*unw_find_dyn_list_p) (unw_addr_space_t, unw_dyn_info_t *,
+ void *);
+
+
+struct libunwind_frame_cache
+{
+ CORE_ADDR base;
+ CORE_ADDR func_addr;
+ unw_cursor_t cursor;
+};
+
+/* We need to qualify the function names with a platform-specific prefix to match
+ the names used by the libunwind library. The UNW_OBJ macro is provided by the
+ libunwind.h header file. */
+#define STRINGIFY2(name) #name
+#define STRINGIFY(name) STRINGIFY2(name)
+
+static char *get_reg_name = STRINGIFY(UNW_OBJ(get_reg));
+static char *get_fpreg_name = STRINGIFY(UNW_OBJ(get_fpreg));
+static char *get_saveloc_name = STRINGIFY(UNW_OBJ(get_save_loc));
+static char *step_name = STRINGIFY(UNW_OBJ(step));
+static char *init_remote_name = STRINGIFY(UNW_OBJ(init_remote));
+static char *create_addr_space_name = STRINGIFY(UNW_OBJ(create_addr_space));
+static char *search_unwind_table_name = STRINGIFY(UNW_OBJ(search_unwind_table));
+static char *find_dyn_list_name = STRINGIFY(UNW_OBJ(find_dyn_list));
+
+static struct libunwind_descr *
+libunwind_descr (struct gdbarch *gdbarch)
+{
+ return gdbarch_data (gdbarch, libunwind_descr_handle);
+}
+
+static void *
+libunwind_descr_init (struct gdbarch *gdbarch)
+{
+ struct libunwind_descr *descr = GDBARCH_OBSTACK_ZALLOC (gdbarch,
+ struct libunwind_descr);
+ return descr;
+}
+
+void
+libunwind_frame_set_descr (struct gdbarch *gdbarch, struct libunwind_descr *descr)
+{
+ struct libunwind_descr *arch_descr;
+
+ gdb_assert (gdbarch != NULL);
+
+ arch_descr = gdbarch_data (gdbarch, libunwind_descr_handle);
+
+ if (arch_descr == NULL)
+ {
+ /* First time here. Must initialize data area. */
+ arch_descr = libunwind_descr_init (gdbarch);
+ set_gdbarch_data (gdbarch, libunwind_descr_handle, arch_descr);
+ }
+
+ /* Copy new descriptor info into arch descriptor. */
+ arch_descr->gdb2uw = descr->gdb2uw;
+ arch_descr->uw2gdb = descr->uw2gdb;
+ arch_descr->is_fpreg = descr->is_fpreg;
+ arch_descr->accessors = descr->accessors;
+}
+
+static struct libunwind_frame_cache *
+libunwind_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ unw_accessors_t *acc;
+ unw_addr_space_t as;
+ unw_word_t fp;
+ unw_regnum_t uw_sp_regnum;
+ struct libunwind_frame_cache *cache;
+ struct libunwind_descr *descr;
+ int i, ret;
+
+ if (*this_cache)
+ return *this_cache;
+
+ /* Allocate a new cache. */
+ cache = FRAME_OBSTACK_ZALLOC (struct libunwind_frame_cache);
+
+ cache->func_addr = frame_func_unwind (next_frame);
+
+ /* Get a libunwind cursor to the previous frame. We do this by initializing
+ a cursor. Libunwind treats a new cursor as the top of stack and will get
+ the current register set via the libunwind register accessor. Now, we
+ provide the platform-specific accessors and we set up the register accessor to use
+ the frame register unwinding interfaces so that we properly get the registers for
+ the current frame rather than the top. We then use the unw_step function to
+ move the libunwind cursor back one frame. We can later use this cursor to find previous
+ registers via the unw_get_reg interface which will invoke libunwind's special logic. */
+ descr = libunwind_descr (get_frame_arch (next_frame));
+ acc = descr->accessors;
+ as = unw_create_addr_space_p (acc,
+ TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ ? __BIG_ENDIAN
+ : __LITTLE_ENDIAN);
+
+ unw_init_remote_p (&cache->cursor, as, next_frame);
+ unw_step_p (&cache->cursor);
+
+ /* To get base address, get sp from previous frame. */
+ uw_sp_regnum = descr->gdb2uw (SP_REGNUM);
+ ret = unw_get_reg_p (&cache->cursor, uw_sp_regnum, &fp);
+ if (ret < 0)
+ error ("Can't get libunwind sp register.");
+
+ cache->base = (CORE_ADDR)fp;
+
+ *this_cache = cache;
+ return cache;
+}
+
+unw_word_t
+libunwind_find_dyn_list (unw_addr_space_t as, unw_dyn_info_t *di, void *arg)
+{
+ return unw_find_dyn_list_p (as, di, arg);
+}
+
+static const struct frame_unwind libunwind_frame_unwind =
+{
+ NORMAL_FRAME,
+ libunwind_frame_this_id,
+ libunwind_frame_prev_register
+};
+
+/* Verify if there is sufficient libunwind information for the frame to use
+ libunwind frame unwinding. */
+const struct frame_unwind *
+libunwind_frame_sniffer (struct frame_info *next_frame)
+{
+ unw_cursor_t cursor;
+ unw_accessors_t *acc;
+ unw_addr_space_t as;
+ struct libunwind_descr *descr;
+ int i, ret;
+
+ /* To test for libunwind unwind support, initialize a cursor to the current frame and try to back
+ up. We use this same method when setting up the frame cache (see libunwind_frame_cache()).
+ If libunwind returns success for this operation, it means that it has found sufficient
+ libunwind unwinding information to do so. */
+
+ descr = libunwind_descr (get_frame_arch (next_frame));
+ acc = descr->accessors;
+ as = unw_create_addr_space_p (acc,
+ TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ ? __BIG_ENDIAN
+ : __LITTLE_ENDIAN);
+
+ ret = unw_init_remote_p (&cursor, as, next_frame);
+
+ if (ret >= 0)
+ ret = unw_step_p (&cursor);
+
+ if (ret < 0)
+ return NULL;
+
+ return &libunwind_frame_unwind;
+}
+
+void
+libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct libunwind_frame_cache *cache =
+ libunwind_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->func_addr);
+}
+
+void
+libunwind_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct libunwind_frame_cache *cache =
+ libunwind_frame_cache (next_frame, this_cache);
+
+ void *ptr;
+ unw_cursor_t *c;
+ unw_save_loc_t sl;
+ int i, ret;
+ unw_word_t intval;
+ unw_fpreg_t fpval;
+ unw_regnum_t uw_regnum;
+ struct libunwind_descr *descr;
+
+ /* Convert from gdb register number to libunwind register number. */
+ descr = libunwind_descr (get_frame_arch (next_frame));
+ uw_regnum = descr->gdb2uw (regnum);
+
+ gdb_assert (regnum >= 0);
+
+ if (!target_has_registers)
+ error ("No registers.");
+
+ *optimizedp = 0;
+ *addrp = 0;
+ *lvalp = not_lval;
+ *realnump = -1;
+
+ memset (valuep, 0, register_size (current_gdbarch, regnum));
+
+ if (uw_regnum < 0)
+ return;
+
+ /* To get the previous register, we use the libunwind register APIs with
+ the cursor we have already pushed back to the previous frame. */
+
+ if (descr->is_fpreg (uw_regnum))
+ {
+ ret = unw_get_fpreg_p (&cache->cursor, uw_regnum, &fpval);
+ ptr = &fpval;
+ }
+ else
+ {
+ ret = unw_get_reg_p (&cache->cursor, uw_regnum, &intval);
+ ptr = &intval;
+ }
+
+ if (ret < 0)
+ return;
+
+ memcpy (valuep, ptr, register_size (current_gdbarch, regnum));
+
+ if (unw_get_saveloc_p (&cache->cursor, uw_regnum, &sl) < 0)
+ return;
+
+ switch (sl.type)
+ {
+ case UNW_SLT_NONE:
+ *optimizedp = 1;
+ break;
+
+ case UNW_SLT_MEMORY:
+ *lvalp = lval_memory;
+ *addrp = sl.u.addr;
+ break;
+
+ case UNW_SLT_REG:
+ *lvalp = lval_register;
+ *realnump = regnum;
+ break;
+ }
+}
+
+CORE_ADDR
+libunwind_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct libunwind_frame_cache *cache =
+ libunwind_frame_cache (next_frame, this_cache);
+
+ return cache->base;
+}
+
+/* The following is a glue routine to call the libunwind unwind table
+ search function to get unwind information for a specified ip address. */
+int
+libunwind_search_unwind_table (void *as, long ip, void *di,
+ void *pi, int need_unwind_info, void *args)
+{
+ return unw_search_unwind_table_p (*(unw_addr_space_t *)as, (unw_word_t )ip,
+ di, pi, need_unwind_info, args);
+}
+
+static int
+libunwind_load (void)
+{
+ void *handle;
+
+ handle = dlopen (LIBUNWIND_SO, RTLD_NOW);
+ if (handle == NULL)
+ return 0;
+
+ /* Initialize pointers to the dynamic library functions we will use. */
+
+ unw_get_reg_p = dlsym (handle, get_reg_name);
+ if (unw_get_reg_p == NULL)
+ return 0;
+
+ unw_get_fpreg_p = dlsym (handle, get_fpreg_name);
+ if (unw_get_fpreg_p == NULL)
+ return 0;
+
+ unw_get_saveloc_p = dlsym (handle, get_saveloc_name);
+ if (unw_get_saveloc_p == NULL)
+ return 0;
+
+ unw_step_p = dlsym (handle, step_name);
+ if (unw_step_p == NULL)
+ return 0;
+
+ unw_init_remote_p = dlsym (handle, init_remote_name);
+ if (unw_init_remote_p == NULL)
+ return 0;
+
+ unw_create_addr_space_p = dlsym (handle, create_addr_space_name);
+ if (unw_create_addr_space_p == NULL)
+ return 0;
+
+ unw_search_unwind_table_p = dlsym (handle, search_unwind_table_name);
+ if (unw_search_unwind_table_p == NULL)
+ return 0;
+
+ unw_find_dyn_list_p = dlsym (handle, find_dyn_list_name);
+ if (unw_find_dyn_list_p == NULL)
+ return 0;
+
+ return 1;
+}
+
+int
+libunwind_is_initialized (void)
+{
+ return libunwind_initialized;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_libunwind_frame (void);
+
+void
+_initialize_libunwind_frame (void)
+{
+ libunwind_descr_handle = register_gdbarch_data (libunwind_descr_init);
+
+ libunwind_initialized = libunwind_load ();
+}
diff --git a/contrib/gdb/gdb/libunwind-frame.h b/contrib/gdb/gdb/libunwind-frame.h
new file mode 100644
index 0000000..e47a792
--- /dev/null
+++ b/contrib/gdb/gdb/libunwind-frame.h
@@ -0,0 +1,64 @@
+/* Frame unwinder for frames with libunwind frame information.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by Jeff Johnston.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 HAVE_LIBUNWIND_H
+
+struct frame_info;
+struct frame_id;
+
+#ifndef LIBUNWIND_FRAME_H
+#define LIBUNWIND_FRAME_H 1
+
+#include "libunwind.h"
+
+struct libunwind_descr
+{
+ int (*gdb2uw) (int);
+ int (*uw2gdb) (int);
+ int (*is_fpreg) (int);
+ void *accessors;
+};
+
+const struct frame_unwind *libunwind_frame_sniffer (struct frame_info *next_frame);
+
+void libunwind_frame_set_descr (struct gdbarch *arch, struct libunwind_descr *descr);
+
+void libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id);
+void libunwind_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep);
+CORE_ADDR libunwind_frame_base_address (struct frame_info *next_frame, void **this_cache);
+
+int libunwind_is_initialized (void);
+
+int libunwind_search_unwind_table (void *as, long ip, void *di,
+ void *pi, int need_unwind_info, void *args);
+
+unw_word_t libunwind_find_dyn_list (unw_addr_space_t, unw_dyn_info_t *,
+ void *);
+
+#endif /* libunwind-frame.h */
+
+#endif /* HAVE_LIBUNWIND_H */
diff --git a/contrib/gdb/gdb/lin-lwp.c b/contrib/gdb/gdb/lin-lwp.c
new file mode 100644
index 0000000..df91aa7
--- /dev/null
+++ b/contrib/gdb/gdb/lin-lwp.c
@@ -0,0 +1,1882 @@
+/* Multi-threaded debugging support for GNU/Linux (LWP layer).
+ Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_assert.h"
+#include "gdb_string.h"
+#include <errno.h>
+#include <signal.h>
+#ifdef HAVE_TKILL_SYSCALL
+#include <unistd.h>
+#include <sys/syscall.h>
+#endif
+#include <sys/ptrace.h>
+#include "gdb_wait.h"
+
+#include "gdbthread.h"
+#include "inferior.h"
+#include "target.h"
+#include "regcache.h"
+#include "gdbcmd.h"
+
+static int debug_lin_lwp;
+extern char *strsignal (int sig);
+
+#include "linux-nat.h"
+
+/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
+ are processes sharing the same VM space. A multi-threaded process
+ is basically a group of such processes. However, such a grouping
+ is almost entirely a user-space issue; the kernel doesn't enforce
+ such a grouping at all (this might change in the future). In
+ general, we'll rely on the threads library (i.e. the GNU/Linux
+ Threads library) to provide such a grouping.
+
+ It is perfectly well possible to write a multi-threaded application
+ without the assistance of a threads library, by using the clone
+ system call directly. This module should be able to give some
+ rudimentary support for debugging such applications if developers
+ specify the CLONE_PTRACE flag in the clone system call, and are
+ using the Linux kernel 2.4 or above.
+
+ Note that there are some peculiarities in GNU/Linux that affect
+ this code:
+
+ - In general one should specify the __WCLONE flag to waitpid in
+ order to make it report events for any of the cloned processes
+ (and leave it out for the initial process). However, if a cloned
+ process has exited the exit status is only reported if the
+ __WCLONE flag is absent. Linux kernel 2.4 has a __WALL flag, but
+ we cannot use it since GDB must work on older systems too.
+
+ - When a traced, cloned process exits and is waited for by the
+ debugger, the kernel reassigns it to the original parent and
+ keeps it around as a "zombie". Somehow, the GNU/Linux Threads
+ library doesn't notice this, which leads to the "zombie problem":
+ When debugged a multi-threaded process that spawns a lot of
+ threads will run out of processes, even if the threads exit,
+ because the "zombies" stay around. */
+
+/* List of known LWPs. */
+static struct lwp_info *lwp_list;
+
+/* Number of LWPs in the list. */
+static int num_lwps;
+
+/* Non-zero if we're running in "threaded" mode. */
+static int threaded;
+
+
+#define GET_LWP(ptid) ptid_get_lwp (ptid)
+#define GET_PID(ptid) ptid_get_pid (ptid)
+#define is_lwp(ptid) (GET_LWP (ptid) != 0)
+#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
+
+/* If the last reported event was a SIGTRAP, this variable is set to
+ the process id of the LWP/thread that got it. */
+ptid_t trap_ptid;
+
+
+/* This module's target-specific operations. */
+static struct target_ops lin_lwp_ops;
+
+/* The standard child operations. */
+extern struct target_ops child_ops;
+
+/* Since we cannot wait (in lin_lwp_wait) for the initial process and
+ any cloned processes with a single call to waitpid, we have to use
+ the WNOHANG flag and call waitpid in a loop. To optimize
+ things a bit we use `sigsuspend' to wake us up when a process has
+ something to report (it will send us a SIGCHLD if it has). To make
+ this work we have to juggle with the signal mask. We save the
+ original signal mask such that we can restore it before creating a
+ new process in order to avoid blocking certain signals in the
+ inferior. We then block SIGCHLD during the waitpid/sigsuspend
+ loop. */
+
+/* Original signal mask. */
+static sigset_t normal_mask;
+
+/* Signal mask for use with sigsuspend in lin_lwp_wait, initialized in
+ _initialize_lin_lwp. */
+static sigset_t suspend_mask;
+
+/* Signals to block to make that sigsuspend work. */
+static sigset_t blocked_mask;
+
+
+/* Prototypes for local functions. */
+static int stop_wait_callback (struct lwp_info *lp, void *data);
+static int lin_lwp_thread_alive (ptid_t ptid);
+
+/* Convert wait status STATUS to a string. Used for printing debug
+ messages only. */
+
+static char *
+status_to_str (int status)
+{
+ static char buf[64];
+
+ if (WIFSTOPPED (status))
+ snprintf (buf, sizeof (buf), "%s (stopped)",
+ strsignal (WSTOPSIG (status)));
+ else if (WIFSIGNALED (status))
+ snprintf (buf, sizeof (buf), "%s (terminated)",
+ strsignal (WSTOPSIG (status)));
+ else
+ snprintf (buf, sizeof (buf), "%d (exited)", WEXITSTATUS (status));
+
+ return buf;
+}
+
+/* Initialize the list of LWPs. Note that this module, contrary to
+ what GDB's generic threads layer does for its thread list,
+ re-initializes the LWP lists whenever we mourn or detach (which
+ doesn't involve mourning) the inferior. */
+
+static void
+init_lwp_list (void)
+{
+ struct lwp_info *lp, *lpnext;
+
+ for (lp = lwp_list; lp; lp = lpnext)
+ {
+ lpnext = lp->next;
+ xfree (lp);
+ }
+
+ lwp_list = NULL;
+ num_lwps = 0;
+ threaded = 0;
+}
+
+/* Add the LWP specified by PID to the list. If this causes the
+ number of LWPs to become larger than one, go into "threaded" mode.
+ Return a pointer to the structure describing the new LWP. */
+
+static struct lwp_info *
+add_lwp (ptid_t ptid)
+{
+ struct lwp_info *lp;
+
+ gdb_assert (is_lwp (ptid));
+
+ lp = (struct lwp_info *) xmalloc (sizeof (struct lwp_info));
+
+ memset (lp, 0, sizeof (struct lwp_info));
+
+ lp->ptid = ptid;
+
+ lp->next = lwp_list;
+ lwp_list = lp;
+ if (++num_lwps > 1)
+ threaded = 1;
+
+ return lp;
+}
+
+/* Remove the LWP specified by PID from the list. */
+
+static void
+delete_lwp (ptid_t ptid)
+{
+ struct lwp_info *lp, *lpprev;
+
+ lpprev = NULL;
+
+ for (lp = lwp_list; lp; lpprev = lp, lp = lp->next)
+ if (ptid_equal (lp->ptid, ptid))
+ break;
+
+ if (!lp)
+ return;
+
+ /* We don't go back to "non-threaded" mode if the number of threads
+ becomes less than two. */
+ num_lwps--;
+
+ if (lpprev)
+ lpprev->next = lp->next;
+ else
+ lwp_list = lp->next;
+
+ xfree (lp);
+}
+
+/* Return a pointer to the structure describing the LWP corresponding
+ to PID. If no corresponding LWP could be found, return NULL. */
+
+static struct lwp_info *
+find_lwp_pid (ptid_t ptid)
+{
+ struct lwp_info *lp;
+ int lwp;
+
+ if (is_lwp (ptid))
+ lwp = GET_LWP (ptid);
+ else
+ lwp = GET_PID (ptid);
+
+ for (lp = lwp_list; lp; lp = lp->next)
+ if (lwp == GET_LWP (lp->ptid))
+ return lp;
+
+ return NULL;
+}
+
+/* Call CALLBACK with its second argument set to DATA for every LWP in
+ the list. If CALLBACK returns 1 for a particular LWP, return a
+ pointer to the structure describing that LWP immediately.
+ Otherwise return NULL. */
+
+struct lwp_info *
+iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data)
+{
+ struct lwp_info *lp, *lpnext;
+
+ for (lp = lwp_list; lp; lp = lpnext)
+ {
+ lpnext = lp->next;
+ if ((*callback) (lp, data))
+ return lp;
+ }
+
+ return NULL;
+}
+
+
+#if 0
+static void
+lin_lwp_open (char *args, int from_tty)
+{
+ push_target (&lin_lwp_ops);
+}
+#endif
+
+/* Attach to the LWP specified by PID. If VERBOSE is non-zero, print
+ a message telling the user that a new LWP has been added to the
+ process. */
+
+void
+lin_lwp_attach_lwp (ptid_t ptid, int verbose)
+{
+ struct lwp_info *lp;
+
+ gdb_assert (is_lwp (ptid));
+
+ /* Make sure SIGCHLD is blocked. We don't want SIGCHLD events
+ to interrupt either the ptrace() or waitpid() calls below. */
+ if (!sigismember (&blocked_mask, SIGCHLD))
+ {
+ sigaddset (&blocked_mask, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
+ }
+
+ if (verbose)
+ printf_filtered ("[New %s]\n", target_pid_to_str (ptid));
+
+ lp = find_lwp_pid (ptid);
+ if (lp == NULL)
+ lp = add_lwp (ptid);
+
+ /* We assume that we're already attached to any LWP that has an
+ id equal to the overall process id. */
+ if (GET_LWP (ptid) != GET_PID (ptid))
+ {
+ pid_t pid;
+ int status;
+
+ if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
+ error ("Can't attach %s: %s", target_pid_to_str (ptid),
+ safe_strerror (errno));
+
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
+ target_pid_to_str (ptid));
+
+ pid = waitpid (GET_LWP (ptid), &status, 0);
+ if (pid == -1 && errno == ECHILD)
+ {
+ /* Try again with __WCLONE to check cloned processes. */
+ pid = waitpid (GET_LWP (ptid), &status, __WCLONE);
+ lp->cloned = 1;
+ }
+
+ gdb_assert (pid == GET_LWP (ptid)
+ && WIFSTOPPED (status) && WSTOPSIG (status));
+
+ child_post_attach (pid);
+
+ lp->stopped = 1;
+
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "LLAL: waitpid %s received %s\n",
+ target_pid_to_str (ptid),
+ status_to_str (status));
+ }
+ }
+ else
+ {
+ /* We assume that the LWP representing the original process
+ is already stopped. Mark it as stopped in the data structure
+ that the lin-lwp layer uses to keep track of threads. Note
+ that this won't have already been done since the main thread
+ will have, we assume, been stopped by an attach from a
+ different layer. */
+ lp->stopped = 1;
+ }
+}
+
+static void
+lin_lwp_attach (char *args, int from_tty)
+{
+ struct lwp_info *lp;
+ pid_t pid;
+ int status;
+
+ /* FIXME: We should probably accept a list of process id's, and
+ attach all of them. */
+ child_ops.to_attach (args, from_tty);
+
+ /* Add the initial process as the first LWP to the list. */
+ lp = add_lwp (BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)));
+
+ /* Make sure the initial process is stopped. The user-level threads
+ layer might want to poke around in the inferior, and that won't
+ work if things haven't stabilized yet. */
+ pid = waitpid (GET_PID (inferior_ptid), &status, 0);
+ if (pid == -1 && errno == ECHILD)
+ {
+ warning ("%s is a cloned process", target_pid_to_str (inferior_ptid));
+
+ /* Try again with __WCLONE to check cloned processes. */
+ pid = waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
+ lp->cloned = 1;
+ }
+
+ gdb_assert (pid == GET_PID (inferior_ptid)
+ && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
+
+ lp->stopped = 1;
+
+ /* Fake the SIGSTOP that core GDB expects. */
+ lp->status = W_STOPCODE (SIGSTOP);
+ lp->resumed = 1;
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "LLA: waitpid %ld, faking SIGSTOP\n", (long) pid);
+ }
+}
+
+static int
+detach_callback (struct lwp_info *lp, void *data)
+{
+ gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
+
+ if (debug_lin_lwp && lp->status)
+ fprintf_unfiltered (gdb_stdlog, "DC: Pending %s for %s on detach.\n",
+ strsignal (WSTOPSIG (lp->status)),
+ target_pid_to_str (lp->ptid));
+
+ while (lp->signalled && lp->stopped)
+ {
+ errno = 0;
+ if (ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0,
+ WSTOPSIG (lp->status)) < 0)
+ error ("Can't continue %s: %s", target_pid_to_str (lp->ptid),
+ safe_strerror (errno));
+
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "DC: PTRACE_CONTINUE (%s, 0, %s) (OK)\n",
+ target_pid_to_str (lp->ptid),
+ status_to_str (lp->status));
+
+ lp->stopped = 0;
+ lp->signalled = 0;
+ lp->status = 0;
+ /* FIXME drow/2003-08-26: There was a call to stop_wait_callback
+ here. But since lp->signalled was cleared above,
+ stop_wait_callback didn't do anything; the process was left
+ running. Shouldn't we be waiting for it to stop?
+ I've removed the call, since stop_wait_callback now does do
+ something when called with lp->signalled == 0. */
+
+ gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
+ }
+
+ /* We don't actually detach from the LWP that has an id equal to the
+ overall process id just yet. */
+ if (GET_LWP (lp->ptid) != GET_PID (lp->ptid))
+ {
+ errno = 0;
+ if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
+ WSTOPSIG (lp->status)) < 0)
+ error ("Can't detach %s: %s", target_pid_to_str (lp->ptid),
+ safe_strerror (errno));
+
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "PTRACE_DETACH (%s, %s, 0) (OK)\n",
+ target_pid_to_str (lp->ptid),
+ strsignal (WSTOPSIG (lp->status)));
+
+ delete_lwp (lp->ptid);
+ }
+
+ return 0;
+}
+
+static void
+lin_lwp_detach (char *args, int from_tty)
+{
+ iterate_over_lwps (detach_callback, NULL);
+
+ /* Only the initial process should be left right now. */
+ gdb_assert (num_lwps == 1);
+
+ trap_ptid = null_ptid;
+
+ /* Destroy LWP info; it's no longer valid. */
+ init_lwp_list ();
+
+ /* Restore the original signal mask. */
+ sigprocmask (SIG_SETMASK, &normal_mask, NULL);
+ sigemptyset (&blocked_mask);
+
+ inferior_ptid = pid_to_ptid (GET_PID (inferior_ptid));
+ child_ops.to_detach (args, from_tty);
+}
+
+
+/* Resume LP. */
+
+static int
+resume_callback (struct lwp_info *lp, void *data)
+{
+ if (lp->stopped && lp->status == 0)
+ {
+ struct thread_info *tp;
+
+ child_resume (pid_to_ptid (GET_LWP (lp->ptid)), 0, TARGET_SIGNAL_0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "RC: PTRACE_CONT %s, 0, 0 (resume sibling)\n",
+ target_pid_to_str (lp->ptid));
+ lp->stopped = 0;
+ lp->step = 0;
+ }
+
+ return 0;
+}
+
+static int
+resume_clear_callback (struct lwp_info *lp, void *data)
+{
+ lp->resumed = 0;
+ return 0;
+}
+
+static int
+resume_set_callback (struct lwp_info *lp, void *data)
+{
+ lp->resumed = 1;
+ return 0;
+}
+
+static void
+lin_lwp_resume (ptid_t ptid, int step, enum target_signal signo)
+{
+ struct lwp_info *lp;
+ int resume_all;
+
+ /* A specific PTID means `step only this process id'. */
+ resume_all = (PIDGET (ptid) == -1);
+
+ if (resume_all)
+ iterate_over_lwps (resume_set_callback, NULL);
+ else
+ iterate_over_lwps (resume_clear_callback, NULL);
+
+ /* If PID is -1, it's the current inferior that should be
+ handled specially. */
+ if (PIDGET (ptid) == -1)
+ ptid = inferior_ptid;
+
+ lp = find_lwp_pid (ptid);
+ if (lp)
+ {
+ ptid = pid_to_ptid (GET_LWP (lp->ptid));
+
+ /* Remember if we're stepping. */
+ lp->step = step;
+
+ /* Mark this LWP as resumed. */
+ lp->resumed = 1;
+
+ /* If we have a pending wait status for this thread, there is no
+ point in resuming the process. */
+ if (lp->status)
+ {
+ /* FIXME: What should we do if we are supposed to continue
+ this thread with a signal? */
+ gdb_assert (signo == TARGET_SIGNAL_0);
+ return;
+ }
+
+ /* Mark LWP as not stopped to prevent it from being continued by
+ resume_callback. */
+ lp->stopped = 0;
+ }
+
+ if (resume_all)
+ iterate_over_lwps (resume_callback, NULL);
+
+ child_resume (ptid, step, signo);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLR: %s %s, %s (resume event thread)\n",
+ step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+ target_pid_to_str (ptid),
+ signo ? strsignal (signo) : "0");
+}
+
+
+/* Issue kill to specified lwp. */
+
+static int tkill_failed;
+
+static int
+kill_lwp (int lwpid, int signo)
+{
+ errno = 0;
+
+/* Use tkill, if possible, in case we are using nptl threads. If tkill
+ fails, then we are not using nptl threads and we should be using kill. */
+
+#ifdef HAVE_TKILL_SYSCALL
+ if (!tkill_failed)
+ {
+ int ret = syscall (__NR_tkill, lwpid, signo);
+ if (errno != ENOSYS)
+ return ret;
+ errno = 0;
+ tkill_failed = 1;
+ }
+#endif
+
+ return kill (lwpid, signo);
+}
+
+/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
+ exited. */
+
+static int
+wait_lwp (struct lwp_info *lp)
+{
+ pid_t pid;
+ int status;
+ int thread_dead = 0;
+
+ gdb_assert (!lp->stopped);
+ gdb_assert (lp->status == 0);
+
+ pid = waitpid (GET_LWP (lp->ptid), &status, 0);
+ if (pid == -1 && errno == ECHILD)
+ {
+ pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
+ if (pid == -1 && errno == ECHILD)
+ {
+ /* The thread has previously exited. We need to delete it now
+ because in the case of NPTL threads, there won't be an
+ exit event unless it is the main thread. */
+ thread_dead = 1;
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog, "WL: %s vanished.\n",
+ target_pid_to_str (lp->ptid));
+ }
+ }
+
+ if (!thread_dead)
+ {
+ gdb_assert (pid == GET_LWP (lp->ptid));
+
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "WL: waitpid %s received %s\n",
+ target_pid_to_str (lp->ptid),
+ status_to_str (status));
+ }
+ }
+
+ /* Check if the thread has exited. */
+ if (WIFEXITED (status) || WIFSIGNALED (status))
+ {
+ thread_dead = 1;
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog, "WL: %s exited.\n",
+ target_pid_to_str (lp->ptid));
+ }
+
+ if (thread_dead)
+ {
+ if (in_thread_list (lp->ptid))
+ {
+ /* Core GDB cannot deal with us deleting the current thread. */
+ if (!ptid_equal (lp->ptid, inferior_ptid))
+ delete_thread (lp->ptid);
+ printf_unfiltered ("[%s exited]\n",
+ target_pid_to_str (lp->ptid));
+ }
+
+ delete_lwp (lp->ptid);
+ return 0;
+ }
+
+ gdb_assert (WIFSTOPPED (status));
+
+ return status;
+}
+
+/* Send a SIGSTOP to LP. */
+
+static int
+stop_callback (struct lwp_info *lp, void *data)
+{
+ if (!lp->stopped && !lp->signalled)
+ {
+ int ret;
+
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "SC: kill %s **<SIGSTOP>**\n",
+ target_pid_to_str (lp->ptid));
+ }
+ errno = 0;
+ ret = kill_lwp (GET_LWP (lp->ptid), SIGSTOP);
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "SC: lwp kill %d %s\n",
+ ret,
+ errno ? safe_strerror (errno) : "ERRNO-OK");
+ }
+
+ lp->signalled = 1;
+ gdb_assert (lp->status == 0);
+ }
+
+ return 0;
+}
+
+/* Wait until LP is stopped. If DATA is non-null it is interpreted as
+ a pointer to a set of signals to be flushed immediately. */
+
+static int
+stop_wait_callback (struct lwp_info *lp, void *data)
+{
+ sigset_t *flush_mask = data;
+
+ if (!lp->stopped)
+ {
+ int status;
+
+ status = wait_lwp (lp);
+ if (status == 0)
+ return 0;
+
+ /* Ignore any signals in FLUSH_MASK. */
+ if (flush_mask && sigismember (flush_mask, WSTOPSIG (status)))
+ {
+ if (!lp->signalled)
+ {
+ lp->stopped = 1;
+ return 0;
+ }
+
+ errno = 0;
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "PTRACE_CONT %s, 0, 0 (%s)\n",
+ target_pid_to_str (lp->ptid),
+ errno ? safe_strerror (errno) : "OK");
+
+ return stop_wait_callback (lp, flush_mask);
+ }
+
+ if (WSTOPSIG (status) != SIGSTOP)
+ {
+ if (WSTOPSIG (status) == SIGTRAP)
+ {
+ /* If a LWP other than the LWP that we're reporting an
+ event for has hit a GDB breakpoint (as opposed to
+ some random trap signal), then just arrange for it to
+ hit it again later. We don't keep the SIGTRAP status
+ and don't forward the SIGTRAP signal to the LWP. We
+ will handle the current event, eventually we will
+ resume all LWPs, and this one will get its breakpoint
+ trap again.
+
+ If we do not do this, then we run the risk that the
+ user will delete or disable the breakpoint, but the
+ thread will have already tripped on it. */
+
+ /* Now resume this LWP and get the SIGSTOP event. */
+ errno = 0;
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "PTRACE_CONT %s, 0, 0 (%s)\n",
+ target_pid_to_str (lp->ptid),
+ errno ? safe_strerror (errno) : "OK");
+
+ fprintf_unfiltered (gdb_stdlog,
+ "SWC: Candidate SIGTRAP event in %s\n",
+ target_pid_to_str (lp->ptid));
+ }
+ /* Hold the SIGTRAP for handling by lin_lwp_wait. */
+ stop_wait_callback (lp, data);
+ /* If there's another event, throw it back into the queue. */
+ if (lp->status)
+ {
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "SWC: kill %s, %s\n",
+ target_pid_to_str (lp->ptid),
+ status_to_str ((int) status));
+ }
+ kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
+ }
+ /* Save the sigtrap event. */
+ lp->status = status;
+ return 0;
+ }
+ else
+ {
+ /* The thread was stopped with a signal other than
+ SIGSTOP, and didn't accidentally trip a breakpoint. */
+
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "SWC: Pending event %s in %s\n",
+ status_to_str ((int) status),
+ target_pid_to_str (lp->ptid));
+ }
+ /* Now resume this LWP and get the SIGSTOP event. */
+ errno = 0;
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "SWC: PTRACE_CONT %s, 0, 0 (%s)\n",
+ target_pid_to_str (lp->ptid),
+ errno ? safe_strerror (errno) : "OK");
+
+ /* Hold this event/waitstatus while we check to see if
+ there are any more (we still want to get that SIGSTOP). */
+ stop_wait_callback (lp, data);
+ /* If the lp->status field is still empty, use it to hold
+ this event. If not, then this event must be returned
+ to the event queue of the LWP. */
+ if (lp->status == 0)
+ lp->status = status;
+ else
+ {
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "SWC: kill %s, %s\n",
+ target_pid_to_str (lp->ptid),
+ status_to_str ((int) status));
+ }
+ kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
+ }
+ return 0;
+ }
+ }
+ else
+ {
+ /* We caught the SIGSTOP that we intended to catch, so
+ there's no SIGSTOP pending. */
+ lp->stopped = 1;
+ lp->signalled = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Check whether PID has any pending signals in FLUSH_MASK. If so set
+ the appropriate bits in PENDING, and return 1 - otherwise return 0. */
+
+static int
+lin_lwp_has_pending (int pid, sigset_t *pending, sigset_t *flush_mask)
+{
+ sigset_t blocked, ignored;
+ int i;
+
+ linux_proc_pending_signals (pid, pending, &blocked, &ignored);
+
+ if (!flush_mask)
+ return 0;
+
+ for (i = 1; i < NSIG; i++)
+ if (sigismember (pending, i))
+ if (!sigismember (flush_mask, i)
+ || sigismember (&blocked, i)
+ || sigismember (&ignored, i))
+ sigdelset (pending, i);
+
+ if (sigisemptyset (pending))
+ return 0;
+
+ return 1;
+}
+
+/* DATA is interpreted as a mask of signals to flush. If LP has
+ signals pending, and they are all in the flush mask, then arrange
+ to flush them. LP should be stopped, as should all other threads
+ it might share a signal queue with. */
+
+static int
+flush_callback (struct lwp_info *lp, void *data)
+{
+ sigset_t *flush_mask = data;
+ sigset_t pending, intersection, blocked, ignored;
+ int pid, status;
+
+ /* Normally, when an LWP exits, it is removed from the LWP list. The
+ last LWP isn't removed till later, however. So if there is only
+ one LWP on the list, make sure it's alive. */
+ if (lwp_list == lp && lp->next == NULL)
+ if (!lin_lwp_thread_alive (lp->ptid))
+ return 0;
+
+ /* Just because the LWP is stopped doesn't mean that new signals
+ can't arrive from outside, so this function must be careful of
+ race conditions. However, because all threads are stopped, we
+ can assume that the pending mask will not shrink unless we resume
+ the LWP, and that it will then get another signal. We can't
+ control which one, however. */
+
+ if (lp->status)
+ {
+ if (debug_lin_lwp)
+ printf_unfiltered ("FC: LP has pending status %06x\n", lp->status);
+ if (WIFSTOPPED (lp->status) && sigismember (flush_mask, WSTOPSIG (lp->status)))
+ lp->status = 0;
+ }
+
+ while (lin_lwp_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
+ {
+ int ret;
+
+ errno = 0;
+ ret = ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stderr,
+ "FC: Sent PTRACE_CONT, ret %d %d\n", ret, errno);
+
+ lp->stopped = 0;
+ stop_wait_callback (lp, flush_mask);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stderr,
+ "FC: Wait finished; saved status is %d\n",
+ lp->status);
+ }
+
+ return 0;
+}
+
+/* Return non-zero if LP has a wait status pending. */
+
+static int
+status_callback (struct lwp_info *lp, void *data)
+{
+ /* Only report a pending wait status if we pretend that this has
+ indeed been resumed. */
+ return (lp->status != 0 && lp->resumed);
+}
+
+/* Return non-zero if LP isn't stopped. */
+
+static int
+running_callback (struct lwp_info *lp, void *data)
+{
+ return (lp->stopped == 0 || (lp->status != 0 && lp->resumed));
+}
+
+/* Count the LWP's that have had events. */
+
+static int
+count_events_callback (struct lwp_info *lp, void *data)
+{
+ int *count = data;
+
+ gdb_assert (count != NULL);
+
+ /* Count only LWPs that have a SIGTRAP event pending. */
+ if (lp->status != 0
+ && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP)
+ (*count)++;
+
+ return 0;
+}
+
+/* Select the LWP (if any) that is currently being single-stepped. */
+
+static int
+select_singlestep_lwp_callback (struct lwp_info *lp, void *data)
+{
+ if (lp->step && lp->status != 0)
+ return 1;
+ else
+ return 0;
+}
+
+/* Select the Nth LWP that has had a SIGTRAP event. */
+
+static int
+select_event_lwp_callback (struct lwp_info *lp, void *data)
+{
+ int *selector = data;
+
+ gdb_assert (selector != NULL);
+
+ /* Select only LWPs that have a SIGTRAP event pending. */
+ if (lp->status != 0
+ && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP)
+ if ((*selector)-- == 0)
+ return 1;
+
+ return 0;
+}
+
+static int
+cancel_breakpoints_callback (struct lwp_info *lp, void *data)
+{
+ struct lwp_info *event_lp = data;
+
+ /* Leave the LWP that has been elected to receive a SIGTRAP alone. */
+ if (lp == event_lp)
+ return 0;
+
+ /* If a LWP other than the LWP that we're reporting an event for has
+ hit a GDB breakpoint (as opposed to some random trap signal),
+ then just arrange for it to hit it again later. We don't keep
+ the SIGTRAP status and don't forward the SIGTRAP signal to the
+ LWP. We will handle the current event, eventually we will resume
+ all LWPs, and this one will get its breakpoint trap again.
+
+ If we do not do this, then we run the risk that the user will
+ delete or disable the breakpoint, but the LWP will have already
+ tripped on it. */
+
+ if (lp->status != 0
+ && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
+ && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
+ DECR_PC_AFTER_BREAK))
+ {
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "CBC: Push back breakpoint for %s\n",
+ target_pid_to_str (lp->ptid));
+
+ /* Back up the PC if necessary. */
+ if (DECR_PC_AFTER_BREAK)
+ write_pc_pid (read_pc_pid (lp->ptid) - DECR_PC_AFTER_BREAK, lp->ptid);
+
+ /* Throw away the SIGTRAP. */
+ lp->status = 0;
+ }
+
+ return 0;
+}
+
+/* Select one LWP out of those that have events pending. */
+
+static void
+select_event_lwp (struct lwp_info **orig_lp, int *status)
+{
+ int num_events = 0;
+ int random_selector;
+ struct lwp_info *event_lp;
+
+ /* Record the wait status for the origional LWP. */
+ (*orig_lp)->status = *status;
+
+ /* Give preference to any LWP that is being single-stepped. */
+ event_lp = iterate_over_lwps (select_singlestep_lwp_callback, NULL);
+ if (event_lp != NULL)
+ {
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "SEL: Select single-step %s\n",
+ target_pid_to_str (event_lp->ptid));
+ }
+ else
+ {
+ /* No single-stepping LWP. Select one at random, out of those
+ which have had SIGTRAP events. */
+
+ /* First see how many SIGTRAP events we have. */
+ iterate_over_lwps (count_events_callback, &num_events);
+
+ /* Now randomly pick a LWP out of those that have had a SIGTRAP. */
+ random_selector = (int)
+ ((num_events * (double) rand ()) / (RAND_MAX + 1.0));
+
+ if (debug_lin_lwp && num_events > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "SEL: Found %d SIGTRAP events, selecting #%d\n",
+ num_events, random_selector);
+
+ event_lp = iterate_over_lwps (select_event_lwp_callback,
+ &random_selector);
+ }
+
+ if (event_lp != NULL)
+ {
+ /* Switch the event LWP. */
+ *orig_lp = event_lp;
+ *status = event_lp->status;
+ }
+
+ /* Flush the wait status for the event LWP. */
+ (*orig_lp)->status = 0;
+}
+
+/* Return non-zero if LP has been resumed. */
+
+static int
+resumed_callback (struct lwp_info *lp, void *data)
+{
+ return lp->resumed;
+}
+
+#ifdef CHILD_WAIT
+
+/* We need to override child_wait to support attaching to cloned
+ processes, since a normal wait (as done by the default version)
+ ignores those processes. */
+
+/* Wait for child PTID to do something. Return id of the child,
+ minus_one_ptid in case of error; store status into *OURSTATUS. */
+
+ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ int save_errno;
+ int status;
+ pid_t pid;
+
+ do
+ {
+ set_sigint_trap (); /* Causes SIGINT to be passed on to the
+ attached process. */
+ set_sigio_trap ();
+
+ pid = waitpid (GET_PID (ptid), &status, 0);
+ if (pid == -1 && errno == ECHILD)
+ /* Try again with __WCLONE to check cloned processes. */
+ pid = waitpid (GET_PID (ptid), &status, __WCLONE);
+
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "CW: waitpid %ld received %s\n",
+ (long) pid, status_to_str (status));
+ }
+
+ save_errno = errno;
+
+ /* Make sure we don't report an event for the exit of the
+ original program, if we've detached from it. */
+ if (pid != -1 && !WIFSTOPPED (status) && pid != GET_PID (inferior_ptid))
+ {
+ pid = -1;
+ save_errno = EINTR;
+ }
+
+ /* Check for stop events reported by a process we didn't already
+ know about - in this case, anything other than inferior_ptid.
+
+ If we're expecting to receive stopped processes after fork,
+ vfork, and clone events, then we'll just add the new one to
+ our list and go back to waiting for the event to be reported
+ - the stopped process might be returned from waitpid before
+ or after the event is. If we want to handle debugging of
+ CLONE_PTRACE processes we need to do more here, i.e. switch
+ to multi-threaded mode. */
+ if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP
+ && pid != GET_PID (inferior_ptid))
+ {
+ linux_record_stopped_pid (pid);
+ pid = -1;
+ save_errno = EINTR;
+ }
+
+ clear_sigio_trap ();
+ clear_sigint_trap ();
+ }
+ while (pid == -1 && save_errno == EINTR);
+
+ if (pid == -1)
+ {
+ warning ("Child process unexpectedly missing: %s",
+ safe_strerror (errno));
+
+ /* Claim it exited with unknown signal. */
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ return minus_one_ptid;
+ }
+
+ /* Handle GNU/Linux's extended waitstatus for trace events. */
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+ return linux_handle_extended_wait (pid, status, ourstatus);
+
+ store_waitstatus (ourstatus, status);
+ return pid_to_ptid (pid);
+}
+
+#endif
+
+/* Stop an active thread, verify it still exists, then resume it. */
+
+static int
+stop_and_resume_callback (struct lwp_info *lp, void *data)
+{
+ struct lwp_info *ptr;
+
+ if (!lp->stopped && !lp->signalled)
+ {
+ stop_callback (lp, NULL);
+ stop_wait_callback (lp, NULL);
+ /* Resume if the lwp still exists. */
+ for (ptr = lwp_list; ptr; ptr = ptr->next)
+ if (lp == ptr)
+ {
+ resume_callback (lp, NULL);
+ resume_set_callback (lp, NULL);
+ }
+ }
+ return 0;
+}
+
+static ptid_t
+lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ struct lwp_info *lp = NULL;
+ int options = 0;
+ int status = 0;
+ pid_t pid = PIDGET (ptid);
+ sigset_t flush_mask;
+
+ sigemptyset (&flush_mask);
+
+ /* Make sure SIGCHLD is blocked. */
+ if (!sigismember (&blocked_mask, SIGCHLD))
+ {
+ sigaddset (&blocked_mask, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
+ }
+
+retry:
+
+ /* Make sure there is at least one LWP that has been resumed, at
+ least if there are any LWPs at all. */
+ gdb_assert (num_lwps == 0 || iterate_over_lwps (resumed_callback, NULL));
+
+ /* First check if there is a LWP with a wait status pending. */
+ if (pid == -1)
+ {
+ /* Any LWP that's been resumed will do. */
+ lp = iterate_over_lwps (status_callback, NULL);
+ if (lp)
+ {
+ status = lp->status;
+ lp->status = 0;
+
+ if (debug_lin_lwp && status)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Using pending wait status %s for %s.\n",
+ status_to_str (status),
+ target_pid_to_str (lp->ptid));
+ }
+
+ /* But if we don't fine one, we'll have to wait, and check both
+ cloned and uncloned processes. We start with the cloned
+ processes. */
+ options = __WCLONE | WNOHANG;
+ }
+ else if (is_lwp (ptid))
+ {
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Waiting for specific LWP %s.\n",
+ target_pid_to_str (ptid));
+
+ /* We have a specific LWP to check. */
+ lp = find_lwp_pid (ptid);
+ gdb_assert (lp);
+ status = lp->status;
+ lp->status = 0;
+
+ if (debug_lin_lwp && status)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Using pending wait status %s for %s.\n",
+ status_to_str (status),
+ target_pid_to_str (lp->ptid));
+
+ /* If we have to wait, take into account whether PID is a cloned
+ process or not. And we have to convert it to something that
+ the layer beneath us can understand. */
+ options = lp->cloned ? __WCLONE : 0;
+ pid = GET_LWP (ptid);
+ }
+
+ if (status && lp->signalled)
+ {
+ /* A pending SIGSTOP may interfere with the normal stream of
+ events. In a typical case where interference is a problem,
+ we have a SIGSTOP signal pending for LWP A while
+ single-stepping it, encounter an event in LWP B, and take the
+ pending SIGSTOP while trying to stop LWP A. After processing
+ the event in LWP B, LWP A is continued, and we'll never see
+ the SIGTRAP associated with the last time we were
+ single-stepping LWP A. */
+
+ /* Resume the thread. It should halt immediately returning the
+ pending SIGSTOP. */
+ registers_changed ();
+ child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step,
+ TARGET_SIGNAL_0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: %s %s, 0, 0 (expect SIGSTOP)\n",
+ lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+ target_pid_to_str (lp->ptid));
+ lp->stopped = 0;
+ gdb_assert (lp->resumed);
+
+ /* This should catch the pending SIGSTOP. */
+ stop_wait_callback (lp, NULL);
+ }
+
+ set_sigint_trap (); /* Causes SIGINT to be passed on to the
+ attached process. */
+ set_sigio_trap ();
+
+ while (status == 0)
+ {
+ pid_t lwpid;
+
+ lwpid = waitpid (pid, &status, options);
+ if (lwpid > 0)
+ {
+ gdb_assert (pid == -1 || lwpid == pid);
+
+ if (debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: waitpid %ld received %s\n",
+ (long) lwpid, status_to_str (status));
+ }
+
+ lp = find_lwp_pid (pid_to_ptid (lwpid));
+
+ /* Check for stop events reported by a process we didn't
+ already know about - anything not already in our LWP
+ list.
+
+ If we're expecting to receive stopped processes after
+ fork, vfork, and clone events, then we'll just add the
+ new one to our list and go back to waiting for the event
+ to be reported - the stopped process might be returned
+ from waitpid before or after the event is. */
+ if (WIFSTOPPED (status) && !lp)
+ {
+ linux_record_stopped_pid (lwpid);
+ status = 0;
+ continue;
+ }
+
+ /* Make sure we don't report an event for the exit of an LWP not in
+ our list, i.e. not part of the current process. This can happen
+ if we detach from a program we original forked and then it
+ exits. */
+ if (!WIFSTOPPED (status) && !lp)
+ {
+ status = 0;
+ continue;
+ }
+
+ /* NOTE drow/2003-06-17: This code seems to be meant for debugging
+ CLONE_PTRACE processes which do not use the thread library -
+ otherwise we wouldn't find the new LWP this way. That doesn't
+ currently work, and the following code is currently unreachable
+ due to the two blocks above. If it's fixed some day, this code
+ should be broken out into a function so that we can also pick up
+ LWPs from the new interface. */
+ if (!lp)
+ {
+ lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid)));
+ if (options & __WCLONE)
+ lp->cloned = 1;
+
+ if (threaded)
+ {
+ gdb_assert (WIFSTOPPED (status)
+ && WSTOPSIG (status) == SIGSTOP);
+ lp->signalled = 1;
+
+ if (!in_thread_list (inferior_ptid))
+ {
+ inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+ GET_PID (inferior_ptid));
+ add_thread (inferior_ptid);
+ }
+
+ add_thread (lp->ptid);
+ printf_unfiltered ("[New %s]\n",
+ target_pid_to_str (lp->ptid));
+ }
+ }
+
+ /* Check if the thread has exited. */
+ if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
+ {
+ if (in_thread_list (lp->ptid))
+ {
+ /* Core GDB cannot deal with us deleting the current
+ thread. */
+ if (!ptid_equal (lp->ptid, inferior_ptid))
+ delete_thread (lp->ptid);
+ printf_unfiltered ("[%s exited]\n",
+ target_pid_to_str (lp->ptid));
+ }
+
+ /* If this is the main thread, we must stop all threads and
+ verify if they are still alive. This is because in the nptl
+ thread model, there is no signal issued for exiting LWPs
+ other than the main thread. We only get the main thread
+ exit signal once all child threads have already exited.
+ If we stop all the threads and use the stop_wait_callback
+ to check if they have exited we can determine whether this
+ signal should be ignored or whether it means the end of the
+ debugged application, regardless of which threading model
+ is being used. */
+ if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
+ {
+ lp->stopped = 1;
+ iterate_over_lwps (stop_and_resume_callback, NULL);
+ }
+
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: %s exited.\n",
+ target_pid_to_str (lp->ptid));
+
+ delete_lwp (lp->ptid);
+
+ /* If there is at least one more LWP, then the exit signal
+ was not the end of the debugged application and should be
+ ignored. */
+ if (num_lwps > 0)
+ {
+ /* Make sure there is at least one thread running. */
+ gdb_assert (iterate_over_lwps (running_callback, NULL));
+
+ /* Discard the event. */
+ status = 0;
+ continue;
+ }
+ }
+
+ /* Check if the current LWP has previously exited. In the nptl
+ thread model, LWPs other than the main thread do not issue
+ signals when they exit so we must check whenever the thread
+ has stopped. A similar check is made in stop_wait_callback(). */
+ if (num_lwps > 1 && !lin_lwp_thread_alive (lp->ptid))
+ {
+ if (in_thread_list (lp->ptid))
+ {
+ /* Core GDB cannot deal with us deleting the current
+ thread. */
+ if (!ptid_equal (lp->ptid, inferior_ptid))
+ delete_thread (lp->ptid);
+ printf_unfiltered ("[%s exited]\n",
+ target_pid_to_str (lp->ptid));
+ }
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: %s exited.\n",
+ target_pid_to_str (lp->ptid));
+
+ delete_lwp (lp->ptid);
+
+ /* Make sure there is at least one thread running. */
+ gdb_assert (iterate_over_lwps (running_callback, NULL));
+
+ /* Discard the event. */
+ status = 0;
+ continue;
+ }
+
+ /* Make sure we don't report a SIGSTOP that we sent
+ ourselves in an attempt to stop an LWP. */
+ if (lp->signalled
+ && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
+ {
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Delayed SIGSTOP caught for %s.\n",
+ target_pid_to_str (lp->ptid));
+
+ /* This is a delayed SIGSTOP. */
+ lp->signalled = 0;
+
+ registers_changed ();
+ child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step,
+ TARGET_SIGNAL_0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
+ lp->step ?
+ "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+ target_pid_to_str (lp->ptid));
+
+ lp->stopped = 0;
+ gdb_assert (lp->resumed);
+
+ /* Discard the event. */
+ status = 0;
+ continue;
+ }
+
+ break;
+ }
+
+ if (pid == -1)
+ {
+ /* Alternate between checking cloned and uncloned processes. */
+ options ^= __WCLONE;
+
+ /* And suspend every time we have checked both. */
+ if (options & __WCLONE)
+ sigsuspend (&suspend_mask);
+ }
+
+ /* We shouldn't end up here unless we want to try again. */
+ gdb_assert (status == 0);
+ }
+
+ clear_sigio_trap ();
+ clear_sigint_trap ();
+
+ gdb_assert (lp);
+
+ /* Don't report signals that GDB isn't interested in, such as
+ signals that are neither printed nor stopped upon. Stopping all
+ threads can be a bit time-consuming so if we want decent
+ performance with heavily multi-threaded programs, especially when
+ they're using a high frequency timer, we'd better avoid it if we
+ can. */
+
+ if (WIFSTOPPED (status))
+ {
+ int signo = target_signal_from_host (WSTOPSIG (status));
+
+ if (signal_stop_state (signo) == 0
+ && signal_print_state (signo) == 0
+ && signal_pass_state (signo) == 1)
+ {
+ /* FIMXE: kettenis/2001-06-06: Should we resume all threads
+ here? It is not clear we should. GDB may not expect
+ other threads to run. On the other hand, not resuming
+ newly attached threads may cause an unwanted delay in
+ getting them running. */
+ registers_changed ();
+ child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step, signo);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: %s %s, %s (preempt 'handle')\n",
+ lp->step ?
+ "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+ target_pid_to_str (lp->ptid),
+ signo ? strsignal (signo) : "0");
+ lp->stopped = 0;
+ status = 0;
+ goto retry;
+ }
+
+ if (signo == TARGET_SIGNAL_INT && signal_pass_state (signo) == 0)
+ {
+ /* If ^C/BREAK is typed at the tty/console, SIGINT gets
+ forwarded to the entire process group, that is, all LWP's
+ will receive it. Since we only want to report it once,
+ we try to flush it from all LWPs except this one. */
+ sigaddset (&flush_mask, SIGINT);
+ }
+ }
+
+ /* This LWP is stopped now. */
+ lp->stopped = 1;
+
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog, "LLW: Candidate event %s in %s.\n",
+ status_to_str (status), target_pid_to_str (lp->ptid));
+
+ /* Now stop all other LWP's ... */
+ iterate_over_lwps (stop_callback, NULL);
+
+ /* ... and wait until all of them have reported back that they're no
+ longer running. */
+ iterate_over_lwps (stop_wait_callback, &flush_mask);
+ iterate_over_lwps (flush_callback, &flush_mask);
+
+ /* If we're not waiting for a specific LWP, choose an event LWP from
+ among those that have had events. Giving equal priority to all
+ LWPs that have had events helps prevent starvation. */
+ if (pid == -1)
+ select_event_lwp (&lp, &status);
+
+ /* Now that we've selected our final event LWP, cancel any
+ breakpoints in other LWPs that have hit a GDB breakpoint. See
+ the comment in cancel_breakpoints_callback to find out why. */
+ iterate_over_lwps (cancel_breakpoints_callback, lp);
+
+ /* If we're not running in "threaded" mode, we'll report the bare
+ process id. */
+
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+ {
+ trap_ptid = (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: trap_ptid is %s.\n",
+ target_pid_to_str (trap_ptid));
+ }
+ else
+ trap_ptid = null_ptid;
+
+ /* Handle GNU/Linux's extended waitstatus for trace events. */
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+ {
+ linux_handle_extended_wait (ptid_get_pid (trap_ptid),
+ status, ourstatus);
+ return trap_ptid;
+ }
+
+ store_waitstatus (ourstatus, status);
+ return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+}
+
+static int
+kill_callback (struct lwp_info *lp, void *data)
+{
+ errno = 0;
+ ptrace (PTRACE_KILL, GET_LWP (lp->ptid), 0, 0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "KC: PTRACE_KILL %s, 0, 0 (%s)\n",
+ target_pid_to_str (lp->ptid),
+ errno ? safe_strerror (errno) : "OK");
+
+ return 0;
+}
+
+static int
+kill_wait_callback (struct lwp_info *lp, void *data)
+{
+ pid_t pid;
+
+ /* We must make sure that there are no pending events (delayed
+ SIGSTOPs, pending SIGTRAPs, etc.) to make sure the current
+ program doesn't interfere with any following debugging session. */
+
+ /* For cloned processes we must check both with __WCLONE and
+ without, since the exit status of a cloned process isn't reported
+ with __WCLONE. */
+ if (lp->cloned)
+ {
+ do
+ {
+ pid = waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
+ if (pid != (pid_t) -1 && debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "KWC: wait %s received unknown.\n",
+ target_pid_to_str (lp->ptid));
+ }
+ }
+ while (pid == GET_LWP (lp->ptid));
+
+ gdb_assert (pid == -1 && errno == ECHILD);
+ }
+
+ do
+ {
+ pid = waitpid (GET_LWP (lp->ptid), NULL, 0);
+ if (pid != (pid_t) -1 && debug_lin_lwp)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "KWC: wait %s received unk.\n",
+ target_pid_to_str (lp->ptid));
+ }
+ }
+ while (pid == GET_LWP (lp->ptid));
+
+ gdb_assert (pid == -1 && errno == ECHILD);
+ return 0;
+}
+
+static void
+lin_lwp_kill (void)
+{
+ /* Kill all LWP's ... */
+ iterate_over_lwps (kill_callback, NULL);
+
+ /* ... and wait until we've flushed all events. */
+ iterate_over_lwps (kill_wait_callback, NULL);
+
+ target_mourn_inferior ();
+}
+
+static void
+lin_lwp_create_inferior (char *exec_file, char *allargs, char **env)
+{
+ child_ops.to_create_inferior (exec_file, allargs, env);
+}
+
+static void
+lin_lwp_mourn_inferior (void)
+{
+ trap_ptid = null_ptid;
+
+ /* Destroy LWP info; it's no longer valid. */
+ init_lwp_list ();
+
+ /* Restore the original signal mask. */
+ sigprocmask (SIG_SETMASK, &normal_mask, NULL);
+ sigemptyset (&blocked_mask);
+
+ child_ops.to_mourn_inferior ();
+}
+
+static int
+lin_lwp_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+ int xfer;
+
+ if (is_lwp (inferior_ptid))
+ inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));
+
+ xfer = linux_proc_xfer_memory (memaddr, myaddr, len, write, attrib, target);
+ if (xfer == 0)
+ xfer = child_xfer_memory (memaddr, myaddr, len, write, attrib, target);
+
+ do_cleanups (old_chain);
+ return xfer;
+}
+
+static int
+lin_lwp_thread_alive (ptid_t ptid)
+{
+ gdb_assert (is_lwp (ptid));
+
+ errno = 0;
+ ptrace (PTRACE_PEEKUSER, GET_LWP (ptid), 0, 0);
+ if (debug_lin_lwp)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLTA: PTRACE_PEEKUSER %s, 0, 0 (%s)\n",
+ target_pid_to_str (ptid),
+ errno ? safe_strerror (errno) : "OK");
+ if (errno)
+ return 0;
+
+ return 1;
+}
+
+static char *
+lin_lwp_pid_to_str (ptid_t ptid)
+{
+ static char buf[64];
+
+ if (is_lwp (ptid))
+ {
+ snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
+ return buf;
+ }
+
+ return normal_pid_to_str (ptid);
+}
+
+static void
+init_lin_lwp_ops (void)
+{
+#if 0
+ lin_lwp_ops.to_open = lin_lwp_open;
+#endif
+ lin_lwp_ops.to_shortname = "lwp-layer";
+ lin_lwp_ops.to_longname = "lwp-layer";
+ lin_lwp_ops.to_doc = "Low level threads support (LWP layer)";
+ lin_lwp_ops.to_attach = lin_lwp_attach;
+ lin_lwp_ops.to_detach = lin_lwp_detach;
+ lin_lwp_ops.to_resume = lin_lwp_resume;
+ lin_lwp_ops.to_wait = lin_lwp_wait;
+ /* fetch_inferior_registers and store_inferior_registers will
+ honor the LWP id, so we can use them directly. */
+ lin_lwp_ops.to_fetch_registers = fetch_inferior_registers;
+ lin_lwp_ops.to_store_registers = store_inferior_registers;
+ lin_lwp_ops.to_xfer_memory = lin_lwp_xfer_memory;
+ lin_lwp_ops.to_kill = lin_lwp_kill;
+ lin_lwp_ops.to_create_inferior = lin_lwp_create_inferior;
+ lin_lwp_ops.to_mourn_inferior = lin_lwp_mourn_inferior;
+ lin_lwp_ops.to_thread_alive = lin_lwp_thread_alive;
+ lin_lwp_ops.to_pid_to_str = lin_lwp_pid_to_str;
+ lin_lwp_ops.to_post_startup_inferior = child_post_startup_inferior;
+ lin_lwp_ops.to_post_attach = child_post_attach;
+ lin_lwp_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint;
+ lin_lwp_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
+ lin_lwp_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint;
+
+ lin_lwp_ops.to_stratum = thread_stratum;
+ lin_lwp_ops.to_has_thread_control = tc_schedlock;
+ lin_lwp_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+sigchld_handler (int signo)
+{
+ /* Do nothing. The only reason for this handler is that it allows
+ us to use sigsuspend in lin_lwp_wait above to wait for the
+ arrival of a SIGCHLD. */
+}
+
+void
+_initialize_lin_lwp (void)
+{
+ struct sigaction action;
+
+ extern void thread_db_init (struct target_ops *);
+
+ init_lin_lwp_ops ();
+ add_target (&lin_lwp_ops);
+ thread_db_init (&lin_lwp_ops);
+
+ /* Save the original signal mask. */
+ sigprocmask (SIG_SETMASK, NULL, &normal_mask);
+
+ action.sa_handler = sigchld_handler;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = 0;
+ sigaction (SIGCHLD, &action, NULL);
+
+ /* Make sure we don't block SIGCHLD during a sigsuspend. */
+ sigprocmask (SIG_SETMASK, NULL, &suspend_mask);
+ sigdelset (&suspend_mask, SIGCHLD);
+
+ sigemptyset (&blocked_mask);
+
+ add_show_from_set (add_set_cmd ("lin-lwp", no_class, var_zinteger,
+ (char *) &debug_lin_lwp,
+ "Set debugging of GNU/Linux lwp module.\n\
+Enables printf debugging output.\n", &setdebuglist), &showdebuglist);
+}
+
+
+/* FIXME: kettenis/2000-08-26: The stuff on this page is specific to
+ the GNU/Linux Threads library and therefore doesn't really belong
+ here. */
+
+/* Read variable NAME in the target and return its value if found.
+ Otherwise return zero. It is assumed that the type of the variable
+ is `int'. */
+
+static int
+get_signo (const char *name)
+{
+ struct minimal_symbol *ms;
+ int signo;
+
+ ms = lookup_minimal_symbol (name, NULL, NULL);
+ if (ms == NULL)
+ return 0;
+
+ if (target_read_memory (SYMBOL_VALUE_ADDRESS (ms), (char *) &signo,
+ sizeof (signo)) != 0)
+ return 0;
+
+ return signo;
+}
+
+/* Return the set of signals used by the threads library in *SET. */
+
+void
+lin_thread_get_thread_signals (sigset_t *set)
+{
+ struct sigaction action;
+ int restart, cancel;
+
+ sigemptyset (set);
+
+ restart = get_signo ("__pthread_sig_restart");
+ if (restart == 0)
+ return;
+
+ cancel = get_signo ("__pthread_sig_cancel");
+ if (cancel == 0)
+ return;
+
+ sigaddset (set, restart);
+ sigaddset (set, cancel);
+
+ /* The GNU/Linux Threads library makes terminating threads send a
+ special "cancel" signal instead of SIGCHLD. Make sure we catch
+ those (to prevent them from terminating GDB itself, which is
+ likely to be their default action) and treat them the same way as
+ SIGCHLD. */
+
+ action.sa_handler = sigchld_handler;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = 0;
+ sigaction (cancel, &action, NULL);
+
+ /* We block the "cancel" signal throughout this code ... */
+ sigaddset (&blocked_mask, cancel);
+ sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
+
+ /* ... except during a sigsuspend. */
+ sigdelset (&suspend_mask, cancel);
+}
diff --git a/contrib/gdb/gdb/linespec.c b/contrib/gdb/gdb/linespec.c
new file mode 100644
index 0000000..eedc671
--- /dev/null
+++ b/contrib/gdb/gdb/linespec.c
@@ -0,0 +1,1850 @@
+/* Parser for linespec for the GNU debugger, GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "command.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "source.h"
+#include "demangle.h"
+#include "value.h"
+#include "completer.h"
+#include "cp-abi.h"
+#include "parser-defs.h"
+#include "block.h"
+#include "objc-lang.h"
+#include "linespec.h"
+
+/* We share this one with symtab.c, but it is not exported widely. */
+
+extern char *operator_chars (char *, char **);
+
+/* Prototypes for local functions */
+
+static void initialize_defaults (struct symtab **default_symtab,
+ int *default_line);
+
+static void set_flags (char *arg, int *is_quoted, char **paren_pointer);
+
+static struct symtabs_and_lines decode_indirect (char **argptr);
+
+static char *locate_first_half (char **argptr, int *is_quote_enclosed);
+
+static struct symtabs_and_lines decode_objc (char **argptr,
+ int funfirstline,
+ struct symtab *file_symtab,
+ char ***canonical,
+ char *saved_arg);
+
+static struct symtabs_and_lines decode_compound (char **argptr,
+ int funfirstline,
+ char ***canonical,
+ char *saved_arg,
+ char *p);
+
+static struct symbol *lookup_prefix_sym (char **argptr, char *p);
+
+static struct symtabs_and_lines find_method (int funfirstline,
+ char ***canonical,
+ char *saved_arg,
+ char *copy,
+ struct type *t,
+ struct symbol *sym_class);
+
+static int collect_methods (char *copy, struct type *t,
+ struct symbol **sym_arr);
+
+static NORETURN void cplusplus_error (const char *name,
+ const char *fmt, ...)
+ ATTR_NORETURN ATTR_FORMAT (printf, 2, 3);
+
+static int total_number_of_methods (struct type *type);
+
+static int find_methods (struct type *, char *, struct symbol **);
+
+static int add_matching_methods (int method_counter, struct type *t,
+ struct symbol **sym_arr);
+
+static int add_constructors (int method_counter, struct type *t,
+ struct symbol **sym_arr);
+
+static void build_canonical_line_spec (struct symtab_and_line *,
+ char *, char ***);
+
+static char *find_toplevel_char (char *s, char c);
+
+static int is_objc_method_format (const char *s);
+
+static struct symtabs_and_lines decode_line_2 (struct symbol *[],
+ int, int, char ***);
+
+static struct symtab *symtab_from_filename (char **argptr,
+ char *p, int is_quote_enclosed,
+ int *not_found_ptr);
+
+static struct
+symtabs_and_lines decode_all_digits (char **argptr,
+ struct symtab *default_symtab,
+ int default_line,
+ char ***canonical,
+ struct symtab *file_symtab,
+ char *q);
+
+static struct symtabs_and_lines decode_dollar (char *copy,
+ int funfirstline,
+ struct symtab *default_symtab,
+ char ***canonical,
+ struct symtab *file_symtab);
+
+static struct symtabs_and_lines decode_variable (char *copy,
+ int funfirstline,
+ char ***canonical,
+ struct symtab *file_symtab,
+ int *not_found_ptr);
+
+static struct
+symtabs_and_lines symbol_found (int funfirstline,
+ char ***canonical,
+ char *copy,
+ struct symbol *sym,
+ struct symtab *file_symtab,
+ struct symtab *sym_symtab);
+
+static struct
+symtabs_and_lines minsym_found (int funfirstline,
+ struct minimal_symbol *msymbol);
+
+/* Helper functions. */
+
+/* Issue a helpful hint on using the command completion feature on
+ single quoted demangled C++ symbols as part of the completion
+ error. */
+
+static NORETURN void
+cplusplus_error (const char *name, const char *fmt, ...)
+{
+ struct ui_file *tmp_stream;
+ tmp_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_stream);
+
+ {
+ va_list args;
+ va_start (args, fmt);
+ vfprintf_unfiltered (tmp_stream, fmt, args);
+ va_end (args);
+ }
+
+ while (*name == '\'')
+ name++;
+ fprintf_unfiltered (tmp_stream,
+ ("Hint: try '%s<TAB> or '%s<ESC-?>\n"
+ "(Note leading single quote.)"),
+ name, name);
+ error_stream (tmp_stream);
+}
+
+/* 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 (struct type *type)
+{
+ int n;
+ int count;
+
+ CHECK_TYPEDEF (type);
+ if (TYPE_CPLUS_SPECIFIC (type) == NULL)
+ return 0;
+ 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. */
+
+static int
+find_methods (struct type *t, char *name, struct symbol **sym_arr)
+{
+ int i1 = 0;
+ int ibase;
+ 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
+ && (lookup_symbol (class_name, (struct block *) NULL,
+ STRUCT_DOMAIN, (int *) NULL,
+ (struct symtab **) NULL)))
+ {
+ int method_counter;
+ int name_len = strlen (name);
+
+ CHECK_TYPEDEF (t);
+
+ /* Loop over each method name. At this level, all overloads of a name
+ are counted as a single name. There is an inner loop which loops over
+ each overload. */
+
+ for (method_counter = TYPE_NFN_FIELDS (t) - 1;
+ method_counter >= 0;
+ --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 (strcmp_iw (name, method_name) == 0)
+ /* Find all the overloaded methods with that name. */
+ i1 += add_matching_methods (method_counter, t,
+ sym_arr + i1);
+ else if (strncmp (class_name, name, name_len) == 0
+ && (class_name[name_len] == '\0'
+ || class_name[name_len] == '<'))
+ i1 += add_constructors (method_counter, t,
+ sym_arr + i1);
+ }
+ }
+
+ /* 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 == 0)
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ i1 += find_methods (TYPE_BASECLASS (t, ibase), name, sym_arr + i1);
+
+ return i1;
+}
+
+/* Add the symbols associated to methods of the class whose type is T
+ and whose name matches the method indexed by METHOD_COUNTER in the
+ array SYM_ARR. Return the number of methods added. */
+
+static int
+add_matching_methods (int method_counter, struct type *t,
+ struct symbol **sym_arr)
+{
+ int field_counter;
+ int i1 = 0;
+
+ for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
+ field_counter >= 0;
+ --field_counter)
+ {
+ struct fn_field *f;
+ char *phys_name;
+
+ f = TYPE_FN_FIELDLIST1 (t, method_counter);
+
+ if (TYPE_FN_FIELD_STUB (f, field_counter))
+ {
+ char *tmp_name;
+
+ tmp_name = gdb_mangle_name (t,
+ method_counter,
+ field_counter);
+ phys_name = alloca (strlen (tmp_name) + 1);
+ strcpy (phys_name, tmp_name);
+ xfree (tmp_name);
+ }
+ else
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+
+ /* Destructor is handled by caller, don't add it to
+ the list. */
+ if (is_destructor_name (phys_name) != 0)
+ continue;
+
+ sym_arr[i1] = lookup_symbol (phys_name,
+ NULL, VAR_DOMAIN,
+ (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1])
+ i1++;
+ else
+ {
+ /* This error message gets printed, but the method
+ still seems to be found
+ 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);
+ */
+ }
+ }
+
+ return i1;
+}
+
+/* Add the symbols associated to constructors of the class whose type
+ is CLASS_TYPE and which are indexed by by METHOD_COUNTER to the
+ array SYM_ARR. Return the number of methods added. */
+
+static int
+add_constructors (int method_counter, struct type *t,
+ struct symbol **sym_arr)
+{
+ int field_counter;
+ int i1 = 0;
+
+ /* For GCC 3.x and stabs, constructors and destructors
+ have names like __base_ctor and __complete_dtor.
+ Check the physname for now if we're looking for a
+ constructor. */
+ for (field_counter
+ = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
+ field_counter >= 0;
+ --field_counter)
+ {
+ struct fn_field *f;
+ char *phys_name;
+
+ f = TYPE_FN_FIELDLIST1 (t, method_counter);
+
+ /* GCC 3.x will never produce stabs stub methods, so
+ we don't need to handle this case. */
+ if (TYPE_FN_FIELD_STUB (f, field_counter))
+ continue;
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+ if (! is_constructor_name (phys_name))
+ continue;
+
+ /* If this method is actually defined, include it in the
+ list. */
+ sym_arr[i1] = lookup_symbol (phys_name,
+ NULL, VAR_DOMAIN,
+ (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1])
+ 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 (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;
+}
+
+
+
+/* Find an instance of the character C in the string S that is outside
+ of all parenthesis pairs, single-quoted strings, and double-quoted
+ strings. Also, ignore the char within a template name, like a ','
+ within foo<int, int>. */
+
+static char *
+find_toplevel_char (char *s, char c)
+{
+ int quoted = 0; /* zero if we're not in quotes;
+ '"' if we're in a double-quoted string;
+ '\'' if we're in a single-quoted string. */
+ int depth = 0; /* Number of unclosed parens we've seen. */
+ char *scan;
+
+ for (scan = s; *scan; scan++)
+ {
+ if (quoted)
+ {
+ if (*scan == quoted)
+ quoted = 0;
+ else if (*scan == '\\' && *(scan + 1))
+ scan++;
+ }
+ else if (*scan == c && ! quoted && depth == 0)
+ return scan;
+ else if (*scan == '"' || *scan == '\'')
+ quoted = *scan;
+ else if (*scan == '(' || *scan == '<')
+ depth++;
+ else if ((*scan == ')' || *scan == '>') && depth > 0)
+ depth--;
+ }
+
+ return 0;
+}
+
+/* Determines if the gives string corresponds to an Objective-C method
+ representation, such as -[Foo bar:] or +[Foo bar]. Objective-C symbols
+ are allowed to have spaces and parentheses in them. */
+
+static int
+is_objc_method_format (const char *s)
+{
+ if (s == NULL || *s == '\0')
+ return 0;
+ /* Handle arguments with the format FILENAME:SYMBOL. */
+ if ((s[0] == ':') && (strchr ("+-", s[1]) != NULL)
+ && (s[2] == '[') && strchr(s, ']'))
+ return 1;
+ /* Handle arguments that are just SYMBOL. */
+ else if ((strchr ("+-", s[0]) != NULL) && (s[1] == '[') && strchr(s, ']'))
+ return 1;
+ return 0;
+}
+
+/* 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 (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 (xfree, return_values.sals);
+
+ if (canonical)
+ {
+ canonical_arr = (char **) xmalloc (nelts * sizeof (char *));
+ make_cleanup (xfree, canonical_arr);
+ memset (canonical_arr, 0, nelts * sizeof (char *));
+ *canonical = canonical_arr;
+ }
+
+ i = 0;
+ printf_unfiltered ("[0] cancel\n[1] all\n");
+ while (i < nelts)
+ {
+ init_sal (&return_values.sals[i]); /* Initialize to zeroes. */
+ init_sal (&values.sals[i]);
+ if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
+ {
+ values.sals[i] = find_function_start_sal (sym_arr[i], funfirstline);
+ if (values.sals[i].symtab)
+ printf_unfiltered ("[%d] %s at %s:%d\n",
+ (i + 2),
+ SYMBOL_PRINT_NAME (sym_arr[i]),
+ values.sals[i].symtab->filename,
+ values.sals[i].line);
+ else
+ printf_unfiltered ("[%d] %s at ?FILE:%d [No symtab? Probably broken debug info...]\n",
+ (i + 2),
+ SYMBOL_PRINT_NAME (sym_arr[i]),
+ values.sals[i].line);
+
+ }
+ else
+ printf_unfiltered ("?HERE\n");
+ i++;
+ }
+
+ prompt = getenv ("PS2");
+ if (prompt == NULL)
+ {
+ prompt = "> ";
+ }
+ args = command_line_input (prompt, 0, "overload-choice");
+
+ if (args == 0 || *args == 0)
+ error_no_arg ("one or more choice numbers");
+
+ i = 0;
+ while (*args)
+ {
+ int num;
+
+ arg1 = args;
+ while (*arg1 >= '0' && *arg1 <= '9')
+ arg1++;
+ if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
+ error ("Arguments must be choice numbers.");
+
+ num = atoi (args);
+
+ if (num == 0)
+ error ("canceled");
+ else if (num == 1)
+ {
+ if (canonical_arr)
+ {
+ for (i = 0; i < nelts; i++)
+ {
+ if (canonical_arr[i] == NULL)
+ {
+ symname = DEPRECATED_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 = DEPRECATED_SYMBOL_NAME (sym_arr[num]);
+ make_cleanup (xfree, symname);
+ canonical_arr[i] = savestring (symname, strlen (symname));
+ }
+ return_values.sals[i++] = values.sals[num];
+ values.sals[num].pc = 0;
+ }
+ else
+ {
+ printf_unfiltered ("duplicate request for %d ignored.\n", num);
+ }
+ }
+
+ args = arg1;
+ while (*args == ' ' || *args == '\t')
+ args++;
+ }
+ return_values.nelts = i;
+ discard_cleanups (old_chain);
+ return return_values;
+}
+
+/* The parser of linespec itself. */
+
+/* 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.
+
+ This may all be followed by an "if EXPR", which we ignore.
+
+ 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.
+
+ If NOT_FOUND_PTR is not null, store a boolean true/false value at the location, based
+ on whether or not failure occurs due to an unknown function or file. In the case
+ where failure does occur due to an unknown function or file, do not issue an error
+ message. */
+
+/* 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 (char **argptr, int funfirstline, struct symtab *default_symtab,
+ int default_line, char ***canonical, int *not_found_ptr)
+{
+ char *p;
+ char *q;
+ /* If a file name is specified, this is its symtab. */
+ struct symtab *file_symtab = NULL;
+
+ char *copy;
+ /* This is NULL if there are no parens in *ARGPTR, or a pointer to
+ the closing parenthesis if there are parens. */
+ char *paren_pointer;
+ /* This says whether or not something in *ARGPTR is quoted with
+ completer_quotes (i.e. with single quotes). */
+ int is_quoted;
+ /* Is part of *ARGPTR is enclosed in double quotes? */
+ int is_quote_enclosed;
+ int is_objc_method = 0;
+ char *saved_arg = *argptr;
+
+ if (not_found_ptr)
+ *not_found_ptr = 0;
+
+ /* Defaults have defaults. */
+
+ initialize_defaults (&default_symtab, &default_line);
+
+ /* See if arg is *PC. */
+
+ if (**argptr == '*')
+ return decode_indirect (argptr);
+
+ /* Set various flags. 'paren_pointer' is important for overload
+ checking, where we allow things like:
+ (gdb) break c::f(int)
+ */
+
+ set_flags (*argptr, &is_quoted, &paren_pointer);
+
+ /* Check to see if it's a multipart linespec (with colons or
+ periods). */
+
+ /* Locate the end of the first half of the linespec.
+ After the call, for instance, if the argptr string is "foo.c:123"
+ p will point at "123". If there is only one part, like "foo", p
+ will point to "". If this is a C++ name, like "A::B::foo", p will
+ point to "::B::foo". Argptr is not changed by this call. */
+
+ p = locate_first_half (argptr, &is_quote_enclosed);
+
+ /* Check if this is an Objective-C method (anything that starts with
+ a '+' or '-' and a '['). */
+ if (is_objc_method_format (p))
+ {
+ is_objc_method = 1;
+ paren_pointer = NULL; /* Just a category name. Ignore it. */
+ }
+
+ /* Check if the symbol could be an Objective-C selector. */
+
+ {
+ struct symtabs_and_lines values;
+ values = decode_objc (argptr, funfirstline, NULL,
+ canonical, saved_arg);
+ if (values.sals != NULL)
+ return values;
+ }
+
+ /* Does it look like there actually were two parts? */
+
+ if ((p[0] == ':' || p[0] == '.') && paren_pointer == NULL)
+ {
+ if (is_quoted)
+ *argptr = *argptr + 1;
+
+ /* Is it a C++ or Java compound data structure?
+ The check on p[1] == ':' is capturing the case of "::",
+ since p[0]==':' was checked above.
+ Note that the call to decode_compound does everything
+ for us, including the lookup on the symbol table, so we
+ can return now. */
+
+ if (p[0] == '.' || p[1] == ':')
+ return decode_compound (argptr, funfirstline, canonical,
+ saved_arg, p);
+
+ /* No, the first part is a filename; set s to be that file's
+ symtab. Also, move argptr past the filename. */
+
+ file_symtab = symtab_from_filename (argptr, p, is_quote_enclosed,
+ not_found_ptr);
+ }
+#if 0
+ /* No one really seems to know why this was added. It certainly
+ breaks the command line, though, whenever the passed
+ name is of the form ClassName::Method. This bit of code
+ singles out the class name, and if funfirstline is set (for
+ example, you are setting a breakpoint at this function),
+ you get an error. This did not occur with earlier
+ verions, so I am ifdef'ing this out. 3/29/99 */
+ else
+ {
+ /* Check if what we have till now is a symbol name */
+
+ /* We may be looking at a template instantiation such
+ as "foo<int>". Check here whether we know about it,
+ instead of falling through to the code below which
+ handles ordinary function names, because that code
+ doesn't like seeing '<' and '>' in a name -- the
+ skip_quoted call doesn't go past them. So see if we
+ can figure it out right now. */
+
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\000';
+ sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0, &sym_symtab);
+ if (sym)
+ {
+ *argptr = (*p == '\'') ? p + 1 : p;
+ return symbol_found (funfirstline, canonical, copy, sym,
+ NULL, sym_symtab);
+ }
+ /* Otherwise fall out from here and go to file/line spec
+ processing, etc. */
+ }
+#endif
+
+ /* 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. */
+ return decode_all_digits (argptr, default_symtab, default_line,
+ canonical, file_symtab, q);
+
+ /* Arg token is not digits => try it as a variable name
+ Find the next token (everything up to end or next whitespace). */
+
+ if (**argptr == '$') /* May be a convenience variable. */
+ /* One or two $ chars possible. */
+ p = skip_quoted (*argptr + (((*argptr)[1] == '$') ? 2 : 1));
+ else if (is_quoted)
+ {
+ p = skip_quoted (*argptr);
+ if (p[-1] != '\'')
+ error ("Unmatched single quote.");
+ }
+ else if (is_objc_method)
+ {
+ /* allow word separators in method names for Obj-C */
+ p = skip_quoted_chars (*argptr, NULL, "");
+ }
+ else if (paren_pointer != NULL)
+ {
+ p = paren_pointer + 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 (get_gdb_completer_quote_characters (), copy[0]) != NULL)
+ {
+ copy[p - *argptr - 1] = '\0';
+ copy++;
+ }
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ /* If it starts with $: may be a legitimate variable or routine name
+ (e.g. HP-UX millicode routines such as $$dyncall), or it may
+ be history value, or it may be a convenience variable. */
+
+ if (*copy == '$')
+ return decode_dollar (copy, funfirstline, default_symtab,
+ canonical, file_symtab);
+
+ /* Look up that token as a variable.
+ If file specified, use that file's per-file block to start with. */
+
+ return decode_variable (copy, funfirstline, canonical,
+ file_symtab, not_found_ptr);
+}
+
+
+
+/* Now, more helper functions for decode_line_1. Some conventions
+ that these functions follow:
+
+ Decode_line_1 typically passes along some of its arguments or local
+ variables to the subfunctions. It passes the variables by
+ reference if they are modified by the subfunction, and by value
+ otherwise.
+
+ Some of the functions have side effects that don't arise from
+ variables that are passed by reference. In particular, if a
+ function is passed ARGPTR as an argument, it modifies what ARGPTR
+ points to; typically, it advances *ARGPTR past whatever substring
+ it has just looked at. (If it doesn't modify *ARGPTR, then the
+ function gets passed *ARGPTR instead, which is then called ARG: see
+ set_flags, for example.) Also, functions that return a struct
+ symtabs_and_lines may modify CANONICAL, as in the description of
+ decode_line_1.
+
+ If a function returns a struct symtabs_and_lines, then that struct
+ will immediately make its way up the call chain to be returned by
+ decode_line_1. In particular, all of the functions decode_XXX
+ calculate the appropriate struct symtabs_and_lines, under the
+ assumption that their argument is of the form XXX. */
+
+/* First, some functions to initialize stuff at the beggining of the
+ function. */
+
+static void
+initialize_defaults (struct symtab **default_symtab, int *default_line)
+{
+ if (*default_symtab == 0)
+ {
+ /* Use whatever we have for the default source line. We don't use
+ get_current_or_default_symtab_and_line as it can recurse and call
+ us back! */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ *default_symtab = cursal.symtab;
+ *default_line = cursal.line;
+ }
+}
+
+static void
+set_flags (char *arg, int *is_quoted, char **paren_pointer)
+{
+ char *ii;
+ int has_if = 0;
+
+ /* 'has_if' is for the syntax:
+ (gdb) break foo if (a==b)
+ */
+ if ((ii = strstr (arg, " if ")) != NULL ||
+ (ii = strstr (arg, "\tif ")) != NULL ||
+ (ii = strstr (arg, " if\t")) != NULL ||
+ (ii = strstr (arg, "\tif\t")) != NULL ||
+ (ii = strstr (arg, " if(")) != NULL ||
+ (ii = strstr (arg, "\tif( ")) != NULL)
+ has_if = 1;
+ /* Temporarily zap out "if (condition)" to not confuse the
+ parenthesis-checking code below. This is undone below. Do not
+ change ii!! */
+ if (has_if)
+ {
+ *ii = '\0';
+ }
+
+ *is_quoted = (*arg
+ && strchr (get_gdb_completer_quote_characters (),
+ *arg) != NULL);
+
+ *paren_pointer = strchr (arg, '(');
+ if (*paren_pointer != NULL)
+ *paren_pointer = strrchr (*paren_pointer, ')');
+
+ /* Now that we're safely past the paren_pointer check, put back " if
+ (condition)" so outer layers can see it. */
+ if (has_if)
+ *ii = ' ';
+}
+
+
+
+/* Decode arg of the form *PC. */
+
+static struct symtabs_and_lines
+decode_indirect (char **argptr)
+{
+ struct symtabs_and_lines values;
+ CORE_ADDR pc;
+
+ (*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;
+ values.sals[0].section = find_pc_overlay (pc);
+
+ return values;
+}
+
+
+
+/* Locate the first half of the linespec, ending in a colon, period,
+ or whitespace. (More or less.) Also, check to see if *ARGPTR is
+ enclosed in double quotes; if so, set is_quote_enclosed, advance
+ ARGPTR past that and zero out the trailing double quote.
+ If ARGPTR is just a simple name like "main", p will point to ""
+ at the end. */
+
+static char *
+locate_first_half (char **argptr, int *is_quote_enclosed)
+{
+ char *ii;
+ char *p, *p1;
+ int has_comma;
+
+ /* Maybe we were called with a line range FILENAME:LINENUM,FILENAME:LINENUM
+ and we must isolate the first half. Outer layers will call again later
+ for the second half.
+
+ Don't count commas that appear in argument lists of overloaded
+ functions, or in quoted strings. It's stupid to go to this much
+ trouble when the rest of the function is such an obvious roach hotel. */
+ ii = find_toplevel_char (*argptr, ',');
+ has_comma = (ii != 0);
+
+ /* Temporarily zap out second half to not confuse the code below.
+ This is undone below. Do not change ii!! */
+ if (has_comma)
+ {
+ *ii = '\0';
+ }
+
+ /* Maybe arg is FILE : LINENUM or FILE : FUNCTION. May also be
+ CLASS::MEMBER, or NAMESPACE::NAME. Look for ':', but ignore
+ inside of <>. */
+
+ p = *argptr;
+ if (p[0] == '"')
+ {
+ *is_quote_enclosed = 1;
+ (*argptr)++;
+ p++;
+ }
+ else
+ *is_quote_enclosed = 0;
+ for (; *p; p++)
+ {
+ if (p[0] == '<')
+ {
+ char *temp_end = find_template_name_end (p);
+ if (!temp_end)
+ error ("malformed template specification in command");
+ p = temp_end;
+ }
+ /* Check for a colon and a plus or minus and a [ (which
+ indicates an Objective-C method) */
+ if (is_objc_method_format (p))
+ {
+ break;
+ }
+ /* Check for the end of the first half of the linespec. End of
+ line, a tab, a double colon or the last single colon, or a
+ space. But if enclosed in double quotes we do not break on
+ enclosed spaces. */
+ if (!*p
+ || p[0] == '\t'
+ || ((p[0] == ':')
+ && ((p[1] == ':') || (strchr (p + 1, ':') == NULL)))
+ || ((p[0] == ' ') && !*is_quote_enclosed))
+ break;
+ if (p[0] == '.' && strchr (p, ':') == NULL)
+ {
+ /* Java qualified method. Find the *last* '.', since the
+ others are package qualifiers. */
+ for (p1 = p; *p1; p1++)
+ {
+ if (*p1 == '.')
+ p = p1;
+ }
+ break;
+ }
+ }
+ while (p[0] == ' ' || p[0] == '\t')
+ p++;
+
+ /* If the closing double quote was left at the end, remove it. */
+ if (*is_quote_enclosed)
+ {
+ char *closing_quote = strchr (p - 1, '"');
+ if (closing_quote && closing_quote[1] == '\0')
+ *closing_quote = '\0';
+ }
+
+ /* Now that we've safely parsed the first half, put back ',' so
+ outer layers can see it. */
+ if (has_comma)
+ *ii = ',';
+
+ return p;
+}
+
+
+
+/* Here's where we recognise an Objective-C Selector. An Objective C
+ selector may be implemented by more than one class, therefore it
+ may represent more than one method/function. This gives us a
+ situation somewhat analogous to C++ overloading. If there's more
+ than one method that could represent the selector, then use some of
+ the existing C++ code to let the user choose one. */
+
+struct symtabs_and_lines
+decode_objc (char **argptr, int funfirstline, struct symtab *file_symtab,
+ char ***canonical, char *saved_arg)
+{
+ struct symtabs_and_lines values;
+ struct symbol **sym_arr = NULL;
+ struct symbol *sym = NULL;
+ char *copy = NULL;
+ struct block *block = NULL;
+ int i1 = 0;
+ int i2 = 0;
+
+ values.sals = NULL;
+ values.nelts = 0;
+
+ if (file_symtab != NULL)
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab), STATIC_BLOCK);
+ else
+ block = get_selected_block (0);
+
+ copy = find_imps (file_symtab, block, *argptr, NULL, &i1, &i2);
+
+ if (i1 > 0)
+ {
+ sym_arr = (struct symbol **) alloca ((i1 + 1) * sizeof (struct symbol *));
+ sym_arr[i1] = 0;
+
+ copy = find_imps (file_symtab, block, *argptr, sym_arr, &i1, &i2);
+ *argptr = copy;
+ }
+
+ /* i1 now represents the TOTAL number of matches found.
+ i2 represents how many HIGH-LEVEL (struct symbol) matches,
+ which will come first in the sym_arr array. Any low-level
+ (minimal_symbol) matches will follow those. */
+
+ if (i1 == 1)
+ {
+ if (i2 > 0)
+ {
+ /* Already a struct symbol. */
+ sym = sym_arr[0];
+ }
+ else
+ {
+ sym = find_pc_function (SYMBOL_VALUE_ADDRESS (sym_arr[0]));
+ if ((sym != NULL) && strcmp (SYMBOL_LINKAGE_NAME (sym_arr[0]), SYMBOL_LINKAGE_NAME (sym)) != 0)
+ {
+ warning ("debugging symbol \"%s\" does not match selector; ignoring", SYMBOL_LINKAGE_NAME (sym));
+ sym = NULL;
+ }
+ }
+
+ values.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Canonicalize this, so it remains resolved for dylib loads. */
+ values.sals[0] = find_function_start_sal (sym, funfirstline);
+ build_canonical_line_spec (values.sals, SYMBOL_NATURAL_NAME (sym), canonical);
+ }
+ else
+ {
+ /* The only match was a non-debuggable symbol. */
+ values.sals[0].symtab = 0;
+ values.sals[0].line = 0;
+ values.sals[0].end = 0;
+ values.sals[0].pc = SYMBOL_VALUE_ADDRESS (sym_arr[0]);
+ }
+ return values;
+ }
+
+ if (i1 > 1)
+ {
+ /* More than one match. The user must choose one or more. */
+ return decode_line_2 (sym_arr, i2, funfirstline, canonical);
+ }
+
+ return values;
+}
+
+/* This handles C++ and Java compound data structures. P should point
+ at the first component separator, i.e. double-colon or period. As
+ an example, on entrance to this function we could have ARGPTR
+ pointing to "AAA::inA::fun" and P pointing to "::inA::fun". */
+
+static struct symtabs_and_lines
+decode_compound (char **argptr, int funfirstline, char ***canonical,
+ char *saved_arg, char *p)
+{
+ struct symtabs_and_lines values;
+ char *p2;
+ char *saved_arg2 = *argptr;
+ char *temp_end;
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+ char *copy;
+ struct symbol *sym_class;
+ struct symbol **sym_arr;
+ struct type *t;
+
+ /* First check for "global" namespace specification, of the form
+ "::foo". If found, skip over the colons and jump to normal
+ symbol processing. I.e. the whole line specification starts with
+ "::" (note the condition that *argptr == p). */
+ if (p[0] == ':'
+ && ((*argptr == p) || (p[-1] == ' ') || (p[-1] == '\t')))
+ saved_arg2 += 2;
+
+ /* Given our example "AAA::inA::fun", we have two cases to consider:
+
+ 1) AAA::inA is the name of a class. In that case, presumably it
+ has a method called "fun"; we then look up that method using
+ find_method.
+
+ 2) AAA::inA isn't the name of a class. In that case, either the
+ user made a typo or AAA::inA is the name of a namespace.
+ Either way, we just look up AAA::inA::fun with lookup_symbol.
+
+ Thus, our first task is to find everything before the last set of
+ double-colons and figure out if it's the name of a class. So we
+ first loop through all of the double-colons. */
+
+ p2 = p; /* Save for restart. */
+
+ /* This is very messy. Following the example above we have now the
+ following pointers:
+ p -> "::inA::fun"
+ argptr -> "AAA::inA::fun
+ saved_arg -> "AAA::inA::fun
+ saved_arg2 -> "AAA::inA::fun
+ p2 -> "::inA::fun". */
+
+ /* In the loop below, with these strings, we'll make 2 passes, each
+ is marked in comments.*/
+
+ while (1)
+ {
+ /* Move pointer up to next possible class/namespace token. */
+
+ p = p2 + 1; /* Restart with old value +1. */
+
+ /* PASS1: at this point p2->"::inA::fun", so p->":inA::fun",
+ i.e. if there is a double-colon, p will now point to the
+ second colon. */
+ /* PASS2: p2->"::fun", p->":fun" */
+
+ /* Move pointer ahead to next double-colon. */
+ while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\''))
+ {
+ if (p[0] == '<')
+ {
+ temp_end = find_template_name_end (p);
+ if (!temp_end)
+ error ("malformed template specification in command");
+ p = temp_end;
+ }
+ /* Note that, since, at the start of this loop, p would be
+ pointing to the second colon in a double-colon, we only
+ satisfy the condition below if there is another
+ double-colon to the right (after). I.e. there is another
+ component that can be a class or a namespace. I.e, if at
+ the beginning of this loop (PASS1), we had
+ p->":inA::fun", we'll trigger this when p has been
+ advanced to point to "::fun". */
+ /* PASS2: we will not trigger this. */
+ else if ((p[0] == ':') && (p[1] == ':'))
+ break; /* Found double-colon. */
+ else
+ /* PASS2: We'll keep getting here, until p->"", at which point
+ we exit this loop. */
+ p++;
+ }
+
+ if (*p != ':')
+ break; /* Out of the while (1). This would happen
+ for instance if we have looked up
+ unsuccessfully all the components of the
+ string, and p->""(PASS2) */
+
+ /* We get here if p points to ' ', '\t', '\'', "::" or ""(i.e
+ string ended). */
+ /* Save restart for next time around. */
+ p2 = p;
+ /* Restore argptr as it was on entry to this function. */
+ *argptr = saved_arg2;
+ /* PASS1: at this point p->"::fun" argptr->"AAA::inA::fun",
+ p2->"::fun". */
+
+ /* All ready for next pass through the loop. */
+ } /* while (1) */
+
+
+ /* Start of lookup in the symbol tables. */
+
+ /* Lookup in the symbol table the substring between argptr and
+ p. Note, this call changes the value of argptr. */
+ /* Before the call, argptr->"AAA::inA::fun",
+ p->"", p2->"::fun". After the call: argptr->"fun", p, p2
+ unchanged. */
+ sym_class = lookup_prefix_sym (argptr, p2);
+
+ /* If sym_class has been found, and if "AAA::inA" is a class, then
+ we're in case 1 above. So we look up "fun" as a method of that
+ class. */
+ 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 (get_gdb_completer_quote_characters (),
+ **argptr) != NULL)
+ {
+ p = skip_quoted (*argptr);
+ *argptr = *argptr + 1;
+ }
+ else
+ {
+ /* At this point argptr->"fun". */
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':')
+ p++;
+ /* At this point p->"". String ended. */
+ }
+
+ /* Allocate our own copy of the substring between argptr and
+ p. */
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if (p != *argptr
+ && copy[p - *argptr - 1]
+ && strchr (get_gdb_completer_quote_characters (),
+ copy[p - *argptr - 1]) != NULL)
+ copy[p - *argptr - 1] = '\0';
+
+ /* At this point copy->"fun", p->"" */
+
+ /* No line number may be specified. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+ /* At this point arptr->"". */
+
+ /* Look for copy as a method of sym_class. */
+ /* At this point copy->"fun", sym_class is "AAA:inA",
+ saved_arg->"AAA::inA::fun". This concludes the scanning of
+ the string for possible components matches. If we find it
+ here, we return. If not, and we are at the and of the string,
+ we'll lookup the whole string in the symbol tables. */
+
+ return find_method (funfirstline, canonical, saved_arg,
+ copy, t, sym_class);
+
+ } /* End if symbol found */
+
+
+ /* We couldn't find a class, so we're in case 2 above. We check the
+ entire name as a symbol instead. */
+
+ copy = (char *) alloca (p - saved_arg2 + 1);
+ memcpy (copy, saved_arg2, p - saved_arg2);
+ /* Note: if is_quoted should be true, we snuff out quote here
+ anyway. */
+ copy[p - saved_arg2] = '\000';
+ /* Set argptr to skip over the name. */
+ *argptr = (*p == '\'') ? p + 1 : p;
+
+ /* Look up entire name */
+ sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0, &sym_symtab);
+ if (sym)
+ return symbol_found (funfirstline, canonical, copy, sym,
+ NULL, sym_symtab);
+
+ /* Couldn't find any interpretation as classes/namespaces, so give
+ up. The quotes are important if copy is empty. */
+ cplusplus_error (saved_arg,
+ "Can't find member of namespace, class, struct, or union named \"%s\"\n",
+ copy);
+}
+
+/* Next come some helper functions for decode_compound. */
+
+/* Return the symbol corresponding to the substring of *ARGPTR ending
+ at P, allowing whitespace. Also, advance *ARGPTR past the symbol
+ name in question, the compound object separator ("::" or "."), and
+ whitespace. Note that *ARGPTR is changed whether or not the
+ lookup_symbol call finds anything (i.e we return NULL). As an
+ example, say ARGPTR is "AAA::inA::fun" and P is "::inA::fun". */
+
+static struct symbol *
+lookup_prefix_sym (char **argptr, char *p)
+{
+ char *p1;
+ char *copy;
+
+ /* 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 argptr. */
+ p = p1 + (p1[0] == ':' ? 2 : 1);
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ /* At this point p1->"::inA::fun", p->"inA::fun" copy->"AAA",
+ argptr->"inA::fun" */
+
+ return lookup_symbol (copy, 0, STRUCT_DOMAIN, 0,
+ (struct symtab **) NULL);
+}
+
+/* This finds the method COPY in the class whose type is T and whose
+ symbol is SYM_CLASS. */
+
+static struct symtabs_and_lines
+find_method (int funfirstline, char ***canonical, char *saved_arg,
+ char *copy, struct type *t, struct symbol *sym_class)
+{
+ struct symtabs_and_lines values;
+ struct symbol *sym = 0;
+ int i1; /* Counter for the symbol array. */
+ struct symbol **sym_arr = alloca (total_number_of_methods (t)
+ * sizeof (struct symbol *));
+
+ /* Find all methods with a matching name, and put them in
+ sym_arr. */
+
+ i1 = collect_methods (copy, t, 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 (is_operator_name (copy))
+ {
+ tmp = (char *) alloca (strlen (copy + 3) + 9);
+ strcpy (tmp, "operator ");
+ strcat (tmp, copy + 3);
+ }
+ else
+ tmp = copy;
+ if (tmp[0] == '~')
+ cplusplus_error (saved_arg,
+ "the class `%s' does not have destructor defined\n",
+ SYMBOL_PRINT_NAME (sym_class));
+ else
+ cplusplus_error (saved_arg,
+ "the class %s does not have any method named %s\n",
+ SYMBOL_PRINT_NAME (sym_class), tmp);
+ }
+}
+
+/* Find all methods named COPY in the class whose type is T, and put
+ them in SYM_ARR. Return the number of methods found. */
+
+static int
+collect_methods (char *copy, struct type *t,
+ struct symbol **sym_arr)
+{
+ int i1 = 0; /* Counter for the symbol array. */
+
+ if (destructor_name_p (copy, t))
+ {
+ /* Destructors are a special case. */
+ int m_index, f_index;
+
+ if (get_destructor_fn_field (t, &m_index, &f_index))
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, m_index);
+
+ sym_arr[i1] =
+ lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, f_index),
+ NULL, VAR_DOMAIN, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1])
+ i1++;
+ }
+ }
+ else
+ i1 = find_methods (t, copy, sym_arr);
+
+ return i1;
+}
+
+
+
+/* Return the symtab associated to the filename given by the substring
+ of *ARGPTR ending at P, and advance ARGPTR past that filename. If
+ NOT_FOUND_PTR is not null and the source file is not found, store
+ boolean true at the location pointed to and do not issue an
+ error message. */
+
+static struct symtab *
+symtab_from_filename (char **argptr, char *p, int is_quote_enclosed,
+ int *not_found_ptr)
+{
+ char *p1;
+ char *copy;
+ struct symtab *file_symtab;
+
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ')
+ --p;
+ if ((*p == '"') && is_quote_enclosed)
+ --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ /* It may have the ending quote right after the file name. */
+ if (is_quote_enclosed && copy[p - *argptr - 1] == '"')
+ copy[p - *argptr - 1] = 0;
+ else
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ file_symtab = lookup_symtab (copy);
+ if (file_symtab == 0)
+ {
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ if (not_found_ptr)
+ {
+ *not_found_ptr = 1;
+ /* The caller has indicated that it wishes quiet notification of any
+ error where the function or file is not found. A call to
+ error_silent causes an error to occur, but it does not issue
+ the supplied message. The message can be manually output by
+ the caller, if desired. This is used, for example, when
+ attempting to set breakpoints for functions in shared libraries
+ that have not yet been loaded. */
+ error_silent ("No source file named %s.", copy);
+ }
+ error ("No source file named %s.", copy);
+ }
+
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ return file_symtab;
+}
+
+
+
+/* This decodes a line where the argument is all digits (possibly
+ preceded by a sign). Q should point to the end of those digits;
+ the other arguments are as usual. */
+
+static struct symtabs_and_lines
+decode_all_digits (char **argptr, struct symtab *default_symtab,
+ int default_line, char ***canonical,
+ struct symtab *file_symtab, char *q)
+
+{
+ struct symtabs_and_lines values;
+ struct symtab_and_line val;
+
+ enum sign
+ {
+ none, plus, minus
+ }
+ sign = none;
+
+ /* We might need a canonical line spec if no file was specified. */
+ int need_canonical = (file_symtab == 0) ? 1 : 0;
+
+ init_sal (&val);
+
+ /* 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
+ set_default_source_symtab_and_line uses
+ select_source_symtab that calls us with such an argument. */
+
+ if (file_symtab == 0 && default_symtab == 0)
+ {
+ /* Make sure we have at least a default source file. */
+ set_default_source_symtab_and_line ();
+ initialize_defaults (&default_symtab, &default_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 (file_symtab == 0)
+ val.line = default_line + val.line;
+ break;
+ case minus:
+ if (q == *argptr)
+ val.line = 15;
+ if (file_symtab == 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 (file_symtab == 0)
+ file_symtab = default_symtab;
+
+ /* It is possible that this source file has more than one symtab,
+ and that the new line number specification has moved us from the
+ default (in file_symtab) to a new one. */
+ val.symtab = find_line_symtab (file_symtab, val.line, NULL, NULL);
+ if (val.symtab == 0)
+ val.symtab = file_symtab;
+
+ 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;
+}
+
+
+
+/* Decode a linespec starting with a dollar sign. */
+
+static struct symtabs_and_lines
+decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
+ char ***canonical, struct symtab *file_symtab)
+{
+ struct value *valx;
+ int index = 0;
+ int need_canonical = 0;
+ struct symtabs_and_lines values;
+ struct symtab_and_line val;
+ char *p;
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+ struct minimal_symbol *msymbol;
+
+ p = (copy[1] == '$') ? copy + 2 : copy + 1;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ if (!*p) /* Reached end of token without hitting non-digit. */
+ {
+ /* We have a value history reference. */
+ sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index);
+ valx = access_value_history ((copy[1] == '$') ? -index : index);
+ if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT)
+ error ("History values used in line specs must have integer values.");
+ }
+ else
+ {
+ /* Not all digits -- may be user variable/function or a
+ convenience variable. */
+
+ /* Look up entire name as a symbol first. */
+ sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0, &sym_symtab);
+ file_symtab = (struct symtab *) 0;
+ need_canonical = 1;
+ /* Symbol was found --> jump to normal symbol processing. */
+ if (sym)
+ return symbol_found (funfirstline, canonical, copy, sym,
+ NULL, sym_symtab);
+
+ /* If symbol was not found, look in minimal symbol tables. */
+ msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ /* Min symbol was found --> jump to minsym processing. */
+ if (msymbol)
+ return minsym_found (funfirstline, msymbol);
+
+ /* Not a user variable or function -- must be convenience variable. */
+ need_canonical = (file_symtab == 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.");
+ }
+
+ init_sal (&val);
+
+ /* Either history value or convenience value from above, in valx. */
+ val.symtab = file_symtab ? file_symtab : 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;
+}
+
+
+
+/* Decode a linespec that's a variable. If FILE_SYMTAB is non-NULL,
+ look in that symtab's static variables first. If NOT_FOUND_PTR is not NULL and
+ the function cannot be found, store boolean true in the location pointed to
+ and do not issue an error message. */
+
+static struct symtabs_and_lines
+decode_variable (char *copy, int funfirstline, char ***canonical,
+ struct symtab *file_symtab, int *not_found_ptr)
+{
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+
+ struct minimal_symbol *msymbol;
+
+ sym = lookup_symbol (copy,
+ (file_symtab
+ ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
+ STATIC_BLOCK)
+ : get_selected_block (0)),
+ VAR_DOMAIN, 0, &sym_symtab);
+
+ if (sym != NULL)
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, sym_symtab);
+
+ msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+
+ if (msymbol != NULL)
+ return minsym_found (funfirstline, msymbol);
+
+ if (!have_full_symbols () &&
+ !have_partial_symbols () && !have_minimal_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+
+ if (not_found_ptr)
+ {
+ *not_found_ptr = 1;
+ /* The caller has indicated that it wishes quiet notification of any
+ error where the function or file is not found. A call to
+ error_silent causes an error to occur, but it does not issue
+ the supplied message. The message can be manually output by
+ the caller, if desired. This is used, for example, when
+ attempting to set breakpoints for functions in shared libraries
+ that have not yet been loaded. */
+ error_silent ("Function \"%s\" not defined.", copy);
+ }
+
+ error ("Function \"%s\" not defined.", copy);
+}
+
+
+
+
+/* Now come some functions that are called from multiple places within
+ decode_line_1. */
+
+/* We've found a symbol SYM to associate with our linespec; build a
+ corresponding struct symtabs_and_lines. */
+
+static struct symtabs_and_lines
+symbol_found (int funfirstline, char ***canonical, char *copy,
+ struct symbol *sym, struct symtab *file_symtab,
+ struct symtab *sym_symtab)
+{
+ struct symtabs_and_lines values;
+
+ 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 (file_symtab == 0)
+ {
+ struct blockvector *bv = BLOCKVECTOR (sym_symtab);
+ struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ if (lookup_block_symbol (b, copy, NULL, VAR_DOMAIN) != 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);
+ }
+}
+
+/* We've found a minimal symbol MSYMBOL to associate with our
+ linespec; build a corresponding struct symtabs_and_lines. */
+
+static struct symtabs_and_lines
+minsym_found (int funfirstline, struct minimal_symbol *msymbol)
+{
+ struct symtabs_and_lines values;
+
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
+ (struct bfd_section *) 0, 0);
+ values.sals[0].section = SYMBOL_BFD_SECTION (msymbol);
+ if (funfirstline)
+ {
+ values.sals[0].pc += FUNCTION_START_OFFSET;
+ values.sals[0].pc = SKIP_PROLOGUE (values.sals[0].pc);
+ }
+ values.nelts = 1;
+ return values;
+}
diff --git a/contrib/gdb/gdb/linespec.h b/contrib/gdb/gdb/linespec.h
new file mode 100644
index 0000000..38b0941
--- /dev/null
+++ b/contrib/gdb/gdb/linespec.h
@@ -0,0 +1,29 @@
+/* Header for GDB line completion.
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (LINESPEC_H)
+#define LINESPEC_H 1
+
+struct symtab;
+
+extern struct symtabs_and_lines
+ decode_line_1 (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line,
+ char ***canonical, int *not_found_ptr);
+
+#endif /* defined (LINESPEC_H) */
diff --git a/contrib/gdb/gdb/lynx-nat.c b/contrib/gdb/gdb/lynx-nat.c
new file mode 100644
index 0000000..7bfd40e
--- /dev/null
+++ b/contrib/gdb/gdb/lynx-nat.c
@@ -0,0 +1,624 @@
+/* Native-dependent code for LynxOS.
+
+ Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2001, 2003 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include <sys/ptrace.h>
+#Include "gdb_wait.h"
+#include <sys/fpp.h>
+
+static unsigned long registers_addr (int pid);
+static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
+
+#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 */
+
+#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 (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 (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 (PIDGET (inferior_ptid));
+
+ {
+ char buf[MAX_REGISTER_SIZE];
+ for (regno = reglo; regno <= reghi; regno++)
+ {
+ int ptrace_fun = PTRACE_PEEKTHREAD;
+
+#ifdef M68K
+ ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD;
+#endif
+
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ unsigned int reg;
+
+ errno = 0;
+ reg = ptrace (ptrace_fun, PIDGET (inferior_ptid),
+ (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). */
+
+void
+store_inferior_registers (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 (PIDGET (inferior_ptid));
+
+ 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 < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ unsigned int reg;
+
+ reg = *(unsigned int *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno) + i];
+
+ errno = 0;
+ ptrace (ptrace_fun, PIDGET (inferior_ptid),
+ (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. */
+
+ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ int save_errno;
+ int thread;
+ union wait status;
+ int pid;
+
+ 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_ptid)) /* 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_ptid) == 0 && thread != 0)
+ {
+ inferior_ptid = MERGEPID (PIDGET (inferior_ptid), thread);
+ add_thread (inferior_ptid);
+ }
+
+ ptid = BUILDPID (pid, thread);
+
+ /* We've become a single threaded process again. */
+ if (thread == 0)
+ inferior_ptid = ptid;
+
+ /* Check for thread creation. */
+ if (WIFSTOPPED (status)
+ && WSTOPSIG (status) == SIGTRAP
+ && !in_thread_list (ptid))
+ {
+ int realsig;
+
+ realsig = ptrace (PTRACE_GETTRACESIG, PIDGET (ptid),
+ (PTRACE_ARG3_TYPE) 0, 0);
+
+ if (realsig == SIGNEWTHREAD)
+ {
+ /* It's a new thread notification. We don't want to much with
+ realsig -- the code in wait_for_inferior expects SIGTRAP. */
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ ourstatus->value.sig = TARGET_SIGNAL_0;
+ return ptid;
+ }
+ else
+ error ("Signal for unknown thread was not SIGNEWTHREAD");
+ }
+
+ /* Check for thread termination. */
+ else if (WIFSTOPPED (status)
+ && WSTOPSIG (status) == SIGTRAP
+ && in_thread_list (ptid))
+ {
+ int realsig;
+
+ realsig = ptrace (PTRACE_GETTRACESIG, PIDGET (ptid),
+ (PTRACE_ARG3_TYPE) 0, 0);
+
+ if (realsig == SIGTHREADEXIT)
+ {
+ ptrace (PTRACE_CONT, PIDGET (ptid), (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 <sys/wait.h>. */
+ 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 ptid;
+ }
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+child_thread_alive (ptid_t ptid)
+{
+ int pid = PIDGET (ptid);
+
+ /* 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 (ptid_t ptid, int step, enum target_signal signal)
+{
+ int func;
+ int pid = PIDGET (ptid);
+
+ 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 = PIDGET (inferior_ptid);
+ 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 *
+child_pid_to_str (ptid_t ptid)
+{
+ static char buf[40];
+
+ sprintf (buf, "process %d thread %d", PIDGET (ptid), TIDGET (ptid));
+
+ 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 (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR 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, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_lynx (void)
+{
+ add_core_fns (&lynx_core_fns);
+}
diff --git a/contrib/gdb/gdb/m2-exp.c b/contrib/gdb/gdb/m2-exp.c
new file mode 100644
index 0000000..3923361
--- /dev/null
+++ b/contrib/gdb/gdb/m2-exp.c
@@ -0,0 +1,2600 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ HEX = 259,
+ ERROR = 260,
+ UINT = 261,
+ M2_TRUE = 262,
+ M2_FALSE = 263,
+ CHAR = 264,
+ FLOAT = 265,
+ STRING = 266,
+ NAME = 267,
+ BLOCKNAME = 268,
+ IDENT = 269,
+ VARNAME = 270,
+ TYPENAME = 271,
+ SIZE = 272,
+ CAP = 273,
+ ORD = 274,
+ HIGH = 275,
+ ABS = 276,
+ MIN_FUNC = 277,
+ MAX_FUNC = 278,
+ FLOAT_FUNC = 279,
+ VAL = 280,
+ CHR = 281,
+ ODD = 282,
+ TRUNC = 283,
+ INC = 284,
+ DEC = 285,
+ INCL = 286,
+ EXCL = 287,
+ COLONCOLON = 288,
+ INTERNAL_VAR = 289,
+ ABOVE_COMMA = 290,
+ ASSIGN = 291,
+ IN = 292,
+ NOTEQUAL = 293,
+ GEQ = 294,
+ LEQ = 295,
+ OROR = 296,
+ LOGICAL_AND = 297,
+ MOD = 298,
+ DIV = 299,
+ UNARY = 300,
+ DOT = 301,
+ NOT = 302,
+ QID = 303
+ };
+#endif
+#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 IN 292
+#define NOTEQUAL 293
+#define GEQ 294
+#define LEQ 295
+#define OROR 296
+#define LOGICAL_AND 297
+#define MOD 298
+#define DIV 299
+#define UNARY 300
+#define DOT 301
+#define NOT 302
+#define QID 303
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 41 "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 */
+#include "block.h"
+
+/* 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 yyname m2_name /* With YYDEBUG defined */
+#define yyrule m2_rule /* 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 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+#if 0
+static char *make_qualname (char *, char *);
+#endif
+
+static int parse_number (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
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 137 "m2-exp.y"
+typedef union YYSTYPE {
+ LONGEST lval;
+ ULONGEST 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;
+/* Line 191 of yacc.c. */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 214 of yacc.c. */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC xmalloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 67
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 848
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 68
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 15
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 80
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 181
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 303
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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, 41, 2, 2, 47, 2,
+ 59, 64, 52, 50, 35, 51, 2, 53, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 38, 40, 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, 58, 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, 61, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 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, 42, 43, 44, 45, 46, 48, 54, 55,
+ 56, 60, 62, 63
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 12, 13, 17, 20,
+ 23, 25, 27, 32, 37, 42, 47, 52, 57, 62,
+ 69, 74, 79, 84, 87, 92, 99, 104, 111, 115,
+ 117, 121, 128, 135, 139, 144, 145, 151, 152, 158,
+ 159, 161, 165, 167, 171, 176, 181, 185, 189, 193,
+ 197, 201, 205, 209, 213, 217, 221, 225, 229, 233,
+ 237, 241, 245, 249, 253, 255, 257, 259, 261, 263,
+ 265, 267, 272, 274, 276, 278, 282, 284, 286, 290,
+ 292
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 69, 0, -1, 71, -1, 70, -1, 82, -1, 71,
+ 57, -1, -1, 51, 72, 71, -1, 50, 71, -1,
+ 73, 71, -1, 62, -1, 61, -1, 18, 59, 71,
+ 64, -1, 19, 59, 71, 64, -1, 21, 59, 71,
+ 64, -1, 20, 59, 71, 64, -1, 22, 59, 82,
+ 64, -1, 23, 59, 82, 64, -1, 24, 59, 71,
+ 64, -1, 25, 59, 82, 35, 71, 64, -1, 26,
+ 59, 71, 64, -1, 27, 59, 71, 64, -1, 28,
+ 59, 71, 64, -1, 17, 71, -1, 29, 59, 71,
+ 64, -1, 29, 59, 71, 35, 71, 64, -1, 30,
+ 59, 71, 64, -1, 30, 59, 71, 35, 71, 64,
+ -1, 71, 60, 12, -1, 74, -1, 71, 42, 74,
+ -1, 31, 59, 71, 35, 71, 64, -1, 32, 59,
+ 71, 35, 71, 64, -1, 65, 77, 66, -1, 82,
+ 65, 77, 66, -1, -1, 71, 58, 75, 78, 67,
+ -1, -1, 71, 59, 76, 77, 64, -1, -1, 71,
+ -1, 77, 35, 71, -1, 71, -1, 78, 35, 71,
+ -1, 65, 82, 66, 71, -1, 82, 59, 71, 64,
+ -1, 59, 71, 64, -1, 71, 49, 71, -1, 71,
+ 52, 71, -1, 71, 53, 71, -1, 71, 55, 71,
+ -1, 71, 54, 71, -1, 71, 50, 71, -1, 71,
+ 51, 71, -1, 71, 40, 71, -1, 71, 43, 71,
+ -1, 71, 41, 71, -1, 71, 45, 71, -1, 71,
+ 44, 71, -1, 71, 38, 71, -1, 71, 39, 71,
+ -1, 71, 48, 71, -1, 71, 46, 71, -1, 71,
+ 37, 71, -1, 7, -1, 8, -1, 3, -1, 6,
+ -1, 9, -1, 10, -1, 81, -1, 17, 59, 82,
+ 64, -1, 11, -1, 80, -1, 13, -1, 79, 33,
+ 13, -1, 80, -1, 34, -1, 79, 33, 12, -1,
+ 12, -1, 16, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 205, 205, 206, 209, 218, 223, 222, 229, 233,
+ 237, 238, 241, 245, 249, 253, 257, 263, 269, 273,
+ 279, 283, 287, 291, 296, 300, 306, 310, 316, 322,
+ 325, 329, 333, 337, 339, 349, 345, 359, 356, 366,
+ 369, 373, 378, 383, 388, 394, 400, 408, 412, 416,
+ 420, 424, 428, 432, 436, 440, 442, 446, 450, 454,
+ 458, 462, 466, 470, 477, 483, 489, 496, 505, 513,
+ 520, 523, 530, 537, 541, 550, 562, 570, 574, 590,
+ 641
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INT", "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", "'<'", "'>'", "'='", "'#'", "IN", "NOTEQUAL", "GEQ", "LEQ",
+ "OROR", "'&'", "LOGICAL_AND", "'@'", "'+'", "'-'", "'*'", "'/'", "MOD",
+ "DIV", "UNARY", "'^'", "'['", "'('", "DOT", "'~'", "NOT", "QID", "')'",
+ "'{'", "'}'", "']'", "$accept", "start", "type_exp", "exp", "@1",
+ "not_exp", "set", "@2", "@3", "arglist", "non_empty_arglist", "block",
+ "fblock", "variable", "type", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 44, 290, 291, 60, 62,
+ 61, 35, 292, 293, 294, 295, 296, 38, 297, 64,
+ 43, 45, 42, 47, 298, 299, 300, 94, 91, 40,
+ 301, 126, 302, 303, 41, 123, 125, 93
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 68, 69, 69, 70, 71, 72, 71, 71, 71,
+ 73, 73, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 74, 74, 75, 71, 76, 71, 77,
+ 77, 77, 78, 78, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 79, 80, 80, 81, 81, 81, 81,
+ 82
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 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
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 0, 66, 67, 64, 65, 68, 69, 72, 79, 74,
+ 80, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 77, 0, 6,
+ 0, 11, 10, 39, 0, 3, 2, 0, 29, 0,
+ 76, 70, 4, 0, 23, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 8, 0, 0, 40, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 35, 37, 0,
+ 9, 0, 0, 39, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 7, 46, 0, 33, 0, 63, 59, 60, 54, 56,
+ 39, 30, 0, 55, 58, 57, 62, 61, 47, 52,
+ 53, 48, 49, 51, 50, 0, 39, 28, 78, 75,
+ 0, 0, 71, 12, 13, 15, 14, 16, 17, 18,
+ 0, 20, 21, 22, 0, 24, 0, 26, 0, 0,
+ 41, 44, 42, 0, 0, 45, 34, 0, 0, 0,
+ 0, 0, 0, 36, 38, 19, 25, 27, 31, 32,
+ 43
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short yydefgoto[] =
+{
+ -1, 34, 35, 64, 62, 37, 38, 135, 136, 65,
+ 163, 39, 40, 41, 45
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -92
+static const short yypact[] =
+{
+ 157, -92, -92, -92, -92, -92, -92, -92, -92, -92,
+ -92, 217, -53, -27, -18, -17, -8, 2, 8, 14,
+ 28, 29, 30, 31, 32, 34, 35, -92, 157, -92,
+ 157, -92, -92, 157, 44, -92, 744, 157, -92, 62,
+ 64, -92, -34, 157, 6, -34, 157, 157, 157, 157,
+ 13, 13, 157, 13, 157, 157, 157, 157, 157, 157,
+ 157, 6, 157, 79, 744, -30, -39, -92, 157, 157,
+ 157, 157, 157, -15, 157, 157, 157, 157, 157, 157,
+ 157, 157, 157, 157, 157, 157, -92, -92, -92, 86,
+ 6, -4, 157, 157, -25, 302, 330, 358, 386, 36,
+ 37, 414, 67, 442, 470, 498, 246, 274, 694, 720,
+ 6, -92, 157, -92, 157, 768, -36, -36, -36, -36,
+ 157, -92, 40, -36, -36, -36, 144, 203, 779, 788,
+ 788, 6, 6, 6, 6, 157, 157, -92, -92, -92,
+ 526, -28, -92, -92, -92, -92, -92, -92, -92, -92,
+ 157, -92, -92, -92, 157, -92, 157, -92, 157, 157,
+ 744, 6, 744, -32, -31, -92, -92, 554, 582, 610,
+ 638, 666, 157, -92, -92, -92, -92, -92, -92, -92,
+ 744
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -92, -92, -92, 0, -92, -92, 26, -92, -92, -91,
+ -92, -92, -92, -92, 53
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -74
+static const short yytable[] =
+{
+ 36, 10, 141, 172, 112, 112, 46, 112, 138, 139,
+ 77, 44, 78, 79, 80, 81, 82, 83, 84, 85,
+ 92, 86, 87, 88, 89, 92, 93, 114, 61, 10,
+ 63, 93, 47, 174, 92, 173, 113, 90, 166, 142,
+ 93, 48, 49, 63, 67, 164, 95, 96, 97, 98,
+ 120, 50, 101, 42, 103, 104, 105, 106, 107, 108,
+ 109, 51, 110, 86, 87, 88, 89, 52, 115, 116,
+ 117, 118, 119, 53, 123, 124, 125, 126, 127, 128,
+ 129, 130, 131, 132, 133, 134, 66, 54, 55, 56,
+ 57, 58, 140, 59, 60, 91, 94, -73, 137, 121,
+ 147, 148, 150, 99, 100, 93, 102, 0, 0, 0,
+ 0, 0, 160, 0, 161, 0, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 122, 78, 79, 80,
+ 81, 82, 83, 84, 85, 162, 86, 87, 88, 89,
+ 0, 0, 0, 111, 0, 0, 0, 0, 0, 0,
+ 167, 0, 0, 0, 168, 0, 169, 0, 170, 171,
+ 1, 0, 0, 2, 3, 4, 5, 6, 7, 8,
+ 9, 0, 180, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 0, 27, 78, 79, 80, 81, 82, 83, 84, 85,
+ 0, 86, 87, 88, 89, 0, 0, 28, 29, 0,
+ 0, 0, 0, 0, 0, 0, 30, 0, 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, 79, 80, 81, 82, 83, 84, 85, 0,
+ 86, 87, 88, 89, 0, 0, 0, 28, 29, 0,
+ 0, 0, 0, 0, 0, 0, 43, 0, 31, 32,
+ 0, 154, 33, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 0, 78, 79, 80, 81, 82, 83,
+ 84, 85, 0, 86, 87, 88, 89, 0, 0, 156,
+ 155, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 0, 78, 79, 80, 81, 82, 83, 84, 85,
+ 0, 86, 87, 88, 89, 0, 0, 0, 157, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 0,
+ 78, 79, 80, 81, 82, 83, 84, 85, 0, 86,
+ 87, 88, 89, 0, 0, 0, 143, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 0, 78, 79,
+ 80, 81, 82, 83, 84, 85, 0, 86, 87, 88,
+ 89, 0, 0, 0, 144, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 0, 78, 79, 80, 81,
+ 82, 83, 84, 85, 0, 86, 87, 88, 89, 0,
+ 0, 0, 145, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 0, 78, 79, 80, 81, 82, 83,
+ 84, 85, 0, 86, 87, 88, 89, 0, 0, 0,
+ 146, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 0, 78, 79, 80, 81, 82, 83, 84, 85,
+ 0, 86, 87, 88, 89, 0, 0, 0, 149, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 0,
+ 78, 79, 80, 81, 82, 83, 84, 85, 0, 86,
+ 87, 88, 89, 0, 0, 0, 151, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 0, 78, 79,
+ 80, 81, 82, 83, 84, 85, 0, 86, 87, 88,
+ 89, 0, 0, 0, 152, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 0, 78, 79, 80, 81,
+ 82, 83, 84, 85, 0, 86, 87, 88, 89, 0,
+ 0, 0, 153, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 0, 78, 79, 80, 81, 82, 83,
+ 84, 85, 0, 86, 87, 88, 89, 0, 0, 0,
+ 165, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 0, 78, 79, 80, 81, 82, 83, 84, 85,
+ 0, 86, 87, 88, 89, 0, 0, 0, 175, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 0,
+ 78, 79, 80, 81, 82, 83, 84, 85, 0, 86,
+ 87, 88, 89, 0, 0, 0, 176, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 0, 78, 79,
+ 80, 81, 82, 83, 84, 85, 0, 86, 87, 88,
+ 89, 0, 0, 0, 177, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 0, 78, 79, 80, 81,
+ 82, 83, 84, 85, 0, 86, 87, 88, 89, 0,
+ 0, 0, 178, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 0, 78, 79, 80, 81, 82, 83,
+ 84, 85, 0, 86, 87, 88, 89, 0, 0, 158,
+ 179, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 0, 78, 79, 80, 81, 82, 83, 84, 85,
+ 0, 86, 87, 88, 89, 159, 0, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 0, 78, 79,
+ 80, 81, 82, 83, 84, 85, 0, 86, 87, 88,
+ 89, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 0, 78, 79, 80, 81, 82, 83, 84, 85,
+ 0, 86, 87, 88, 89, -74, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 0, 78, 79, 80, 81,
+ 82, 83, 84, 85, 0, 86, 87, 88, 89, 80,
+ 81, 82, 83, 84, 85, 0, 86, 87, 88, 89,
+ 82, 83, 84, 85, 0, 86, 87, 88, 89
+};
+
+static const short yycheck[] =
+{
+ 0, 16, 93, 35, 35, 35, 59, 35, 12, 13,
+ 46, 11, 48, 49, 50, 51, 52, 53, 54, 55,
+ 59, 57, 58, 59, 60, 59, 65, 66, 28, 16,
+ 30, 65, 59, 64, 59, 67, 66, 37, 66, 64,
+ 65, 59, 59, 43, 0, 136, 46, 47, 48, 49,
+ 65, 59, 52, 0, 54, 55, 56, 57, 58, 59,
+ 60, 59, 62, 57, 58, 59, 60, 59, 68, 69,
+ 70, 71, 72, 59, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 33, 59, 59, 59,
+ 59, 59, 92, 59, 59, 33, 43, 33, 12, 73,
+ 64, 64, 35, 50, 51, 65, 53, -1, -1, -1,
+ -1, -1, 112, -1, 114, -1, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 73, 48, 49, 50,
+ 51, 52, 53, 54, 55, 135, 57, 58, 59, 60,
+ -1, -1, -1, 64, -1, -1, -1, -1, -1, -1,
+ 150, -1, -1, -1, 154, -1, 156, -1, 158, 159,
+ 3, -1, -1, 6, 7, 8, 9, 10, 11, 12,
+ 13, -1, 172, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ -1, 34, 48, 49, 50, 51, 52, 53, 54, 55,
+ -1, 57, 58, 59, 60, -1, -1, 50, 51, -1,
+ -1, -1, -1, -1, -1, -1, 59, -1, 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, 59, -1, 61, 62,
+ -1, 35, 65, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, -1, 48, 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, -1, 48, 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, -1,
+ 48, 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, -1, 48, 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, -1, 48, 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, -1, 48, 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, -1, 48, 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, -1,
+ 48, 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, -1, 48, 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, -1, 48, 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, -1, 48, 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, -1, 48, 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, -1,
+ 48, 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, -1, 48, 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, -1, 48, 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, -1, 48, 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, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ -1, 57, 58, 59, 60, 35, -1, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, -1, 57, 58, 59,
+ 60, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ -1, 57, 58, 59, 60, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, -1, 48, 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
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 6, 7, 8, 9, 10, 11, 12, 13,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 34, 50, 51,
+ 59, 61, 62, 65, 69, 70, 71, 73, 74, 79,
+ 80, 81, 82, 59, 71, 82, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 71, 72, 71, 71, 77, 82, 0, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 48, 49,
+ 50, 51, 52, 53, 54, 55, 57, 58, 59, 60,
+ 71, 33, 59, 65, 82, 71, 71, 71, 71, 82,
+ 82, 71, 82, 71, 71, 71, 71, 71, 71, 71,
+ 71, 64, 35, 66, 66, 71, 71, 71, 71, 71,
+ 65, 74, 82, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 75, 76, 12, 12, 13,
+ 71, 77, 64, 64, 64, 64, 64, 64, 64, 64,
+ 35, 64, 64, 64, 35, 64, 35, 64, 35, 35,
+ 71, 71, 71, 78, 77, 64, 66, 71, 71, 71,
+ 71, 71, 35, 67, 64, 64, 64, 64, 64, 64,
+ 71
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to xreallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to xreallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 210 "m2-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 219 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_IND); }
+ break;
+
+ case 6:
+#line 223 "m2-exp.y"
+ { number_sign = -1; }
+ break;
+
+ case 7:
+#line 225 "m2-exp.y"
+ { number_sign = 1;
+ write_exp_elt_opcode (UNOP_NEG); }
+ break;
+
+ case 8:
+#line 230 "m2-exp.y"
+ { write_exp_elt_opcode(UNOP_PLUS); }
+ break;
+
+ case 9:
+#line 234 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ break;
+
+ case 12:
+#line 242 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_CAP); }
+ break;
+
+ case 13:
+#line 246 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_ORD); }
+ break;
+
+ case 14:
+#line 250 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_ABS); }
+ break;
+
+ case 15:
+#line 254 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_HIGH); }
+ break;
+
+ case 16:
+#line 258 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_MIN);
+ write_exp_elt_type (yyvsp[-1].tval);
+ write_exp_elt_opcode (UNOP_MIN); }
+ break;
+
+ case 17:
+#line 264 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_MAX);
+ write_exp_elt_type (yyvsp[-1].tval);
+ write_exp_elt_opcode (UNOP_MIN); }
+ break;
+
+ case 18:
+#line 270 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_FLOAT); }
+ break;
+
+ case 19:
+#line 274 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_VAL);
+ write_exp_elt_type (yyvsp[-3].tval);
+ write_exp_elt_opcode (BINOP_VAL); }
+ break;
+
+ case 20:
+#line 280 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_CHR); }
+ break;
+
+ case 21:
+#line 284 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_ODD); }
+ break;
+
+ case 22:
+#line 288 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_TRUNC); }
+ break;
+
+ case 23:
+#line 292 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ break;
+
+ case 24:
+#line 297 "m2-exp.y"
+ { write_exp_elt_opcode(UNOP_PREINCREMENT); }
+ break;
+
+ case 25:
+#line 301 "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 26:
+#line 307 "m2-exp.y"
+ { write_exp_elt_opcode(UNOP_PREDECREMENT);}
+ break;
+
+ case 27:
+#line 311 "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 28:
+#line 317 "m2-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ break;
+
+ case 30:
+#line 326 "m2-exp.y"
+ { error("Sets are not implemented.");}
+ break;
+
+ case 31:
+#line 330 "m2-exp.y"
+ { error("Sets are not implemented.");}
+ break;
+
+ case 32:
+#line 334 "m2-exp.y"
+ { error("Sets are not implemented.");}
+ break;
+
+ case 33:
+#line 338 "m2-exp.y"
+ { error("Sets are not implemented.");}
+ break;
+
+ case 34:
+#line 340 "m2-exp.y"
+ { error("Sets are not implemented.");}
+ break;
+
+ case 35:
+#line 349 "m2-exp.y"
+ { start_arglist(); }
+ break;
+
+ case 36:
+#line 351 "m2-exp.y"
+ { write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ write_exp_elt_longcst ((LONGEST) end_arglist());
+ write_exp_elt_opcode (MULTI_SUBSCRIPT); }
+ break;
+
+ case 37:
+#line 359 "m2-exp.y"
+ { start_arglist (); }
+ break;
+
+ case 38:
+#line 361 "m2-exp.y"
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+ break;
+
+ case 40:
+#line 370 "m2-exp.y"
+ { arglist_len = 1; }
+ break;
+
+ case 41:
+#line 374 "m2-exp.y"
+ { arglist_len++; }
+ break;
+
+ case 42:
+#line 379 "m2-exp.y"
+ { arglist_len = 1; }
+ break;
+
+ case 43:
+#line 384 "m2-exp.y"
+ { arglist_len++; }
+ break;
+
+ case 44:
+#line 389 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ break;
+
+ case 45:
+#line 395 "m2-exp.y"
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-3].tval);
+ write_exp_elt_opcode (UNOP_CAST); }
+ break;
+
+ case 46:
+#line 401 "m2-exp.y"
+ { }
+ break;
+
+ case 47:
+#line 409 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ break;
+
+ case 48:
+#line 413 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_MUL); }
+ break;
+
+ case 49:
+#line 417 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_DIV); }
+ break;
+
+ case 50:
+#line 421 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_INTDIV); }
+ break;
+
+ case 51:
+#line 425 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_REM); }
+ break;
+
+ case 52:
+#line 429 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_ADD); }
+ break;
+
+ case 53:
+#line 433 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_SUB); }
+ break;
+
+ case 54:
+#line 437 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ break;
+
+ case 55:
+#line 441 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 56:
+#line 443 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 57:
+#line 447 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ break;
+
+ case 58:
+#line 451 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ break;
+
+ case 59:
+#line 455 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_LESS); }
+ break;
+
+ case 60:
+#line 459 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_GTR); }
+ break;
+
+ case 61:
+#line 463 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ break;
+
+ case 62:
+#line 467 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ break;
+
+ case 63:
+#line 471 "m2-exp.y"
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ break;
+
+ case 64:
+#line 478 "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 484 "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 66:
+#line 490 "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 67:
+#line 497 "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 68:
+#line 506 "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 69:
+#line 514 "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 71:
+#line 524 "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 72:
+#line 531 "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 73:
+#line 538 "m2-exp.y"
+ { yyval.bval = SYMBOL_BLOCK_VALUE(yyvsp[0].sym); }
+ break;
+
+ case 74:
+#line 542 "m2-exp.y"
+ { struct symbol *sym
+ = lookup_symbol (copy_name (yyvsp[0].sval), expression_context_block,
+ VAR_DOMAIN, 0, NULL);
+ yyval.sym = sym;}
+ break;
+
+ case 75:
+#line 551 "m2-exp.y"
+ { struct symbol *tem
+ = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, 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 76:
+#line 563 "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 78:
+#line 575 "m2-exp.y"
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, 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 79:
+#line 591 "m2-exp.y"
+ { struct symbol *sym;
+ int is_a_field_of_this;
+
+ sym = lookup_symbol (copy_name (yyvsp[0].sval),
+ expression_context_block,
+ VAR_DOMAIN,
+ &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;
+ 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 80:
+#line 642 "m2-exp.y"
+ { yyval.tval = lookup_typename (copy_name (yyvsp[0].sval),
+ expression_context_block, 0); }
+ break;
+
+
+ }
+
+/* Line 991 of yacc.c. */
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ 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)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab2;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+
+ /* Suppress GCC warning that yyerrlab1 is unused when no action
+ invokes YYERROR. Doesn't work in C++ */
+#ifndef __cplusplus
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+#endif
+#endif
+
+
+ goto yyerrlab2;
+
+
+/*---------------------------------------------------------------.
+| yyerrlab2 -- pop states until the error token can be shifted. |
+`---------------------------------------------------------------*/
+yyerrlab2:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 647 "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;
+{
+ char *p = lexptr;
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ int c,i,ischar=0;
+ int base = input_radix;
+ 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 ()
+{
+ int c;
+ int namelen;
+ int i;
+ char *tokstart;
+ char quote;
+
+ retry:
+
+ prev_lexptr = lexptr;
+
+ tokstart = lexptr;
+
+
+ /* See if it is a special token of length 2 */
+ for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++)
+ if(DEPRECATED_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;
+ 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) && DEPRECATED_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_DOMAIN, 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:
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ 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()");
+
+ default:
+ error ("unhandled token in m2lex()");
+ break;
+ }
+ }
+ else
+ {
+ /* Built-in BOOLEAN type. This is sort of a hack. */
+ if(DEPRECATED_STREQN(tokstart,"TRUE",4))
+ {
+ yylval.ulval = 1;
+ return M2_TRUE;
+ }
+ else if(DEPRECATED_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;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ 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 0000000..646672b
--- /dev/null
+++ b/contrib/gdb/gdb/m2-exp.y
@@ -0,0 +1,1108 @@
+/* YACC grammar for Modula-2 expressions, for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999,
+ 2000
+ 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 (<malloc.h> and <stdlib.h> 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 */
+#include "block.h"
+
+/* 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 yyname m2_name /* With YYDEBUG defined */
+#define yyrule m2_rule /* 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 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+#if 0
+static char *make_qualname (char *, char *);
+#endif
+
+static int parse_number (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;
+ ULONGEST 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 <voidval> exp type_exp start set
+%type <voidval> variable
+%type <tval> type
+%type <bval> block
+%type <sym> fblock
+
+%token <lval> INT HEX ERROR
+%token <ulval> UINT M2_TRUE M2_FALSE CHAR
+%token <dval> 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 <sval> STRING
+%token <sval> NAME BLOCKNAME IDENT VARNAME
+%token <sval> 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 <voidval> 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_DOMAIN, 0, NULL);
+ $$ = sym;}
+ ;
+
+
+/* GDB scope operator */
+fblock : block COLONCOLON BLOCKNAME
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_DOMAIN, 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_DOMAIN, 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_DOMAIN,
+ &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;
+ 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;
+{
+ char *p = lexptr;
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ int c,i,ischar=0;
+ int base = input_radix;
+ 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 ()
+{
+ int c;
+ int namelen;
+ int i;
+ char *tokstart;
+ char quote;
+
+ retry:
+
+ prev_lexptr = lexptr;
+
+ tokstart = lexptr;
+
+
+ /* See if it is a special token of length 2 */
+ for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++)
+ if(DEPRECATED_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;
+ 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) && DEPRECATED_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_DOMAIN, 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:
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ 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()");
+
+ default:
+ error ("unhandled token in m2lex()");
+ break;
+ }
+ }
+ else
+ {
+ /* Built-in BOOLEAN type. This is sort of a hack. */
+ if(DEPRECATED_STREQN(tokstart,"TRUE",4))
+ {
+ yylval.ulval = 1;
+ return M2_TRUE;
+ }
+ else if(DEPRECATED_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;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ 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 0000000..e5b6b50
--- /dev/null
+++ b/contrib/gdb/gdb/m2-lang.c
@@ -0,0 +1,473 @@
+/* Modula 2 language support routines for GDB, the GNU debugger.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "valprint.h"
+
+extern void _initialize_m2_language (void);
+static struct type *m2_create_fundamental_type (struct objfile *, int);
+static void m2_printstr (struct ui_file * stream, char *string,
+ unsigned int length, int width,
+ int force_ellipses);
+static void m2_printchar (int, struct ui_file *);
+static void m2_emit_char (int, struct ui_file *, int);
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ 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
+m2_emit_char (int c, struct ui_file *stream, int quoter)
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (c == '\\' || c == quoter)
+ {
+ fputs_filtered ("\\", stream);
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+}
+
+/* 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 (int c, struct ui_file *stream)
+{
+ fputs_filtered ("'", stream);
+ LA_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 (struct ui_file *stream, char *string, unsigned int length,
+ int width, int force_ellipses)
+{
+ unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+
+ 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, " <repeats %u times>", 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;
+ }
+ LA_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 (struct objfile *objfile, int typeid)
+{
+ 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 "<?type?>". 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, "<?type?>", 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,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ m2_parse, /* parser */
+ m2_error, /* parser error function */
+ m2_printchar, /* Print character constant */
+ m2_printstr, /* function to print string constant */
+ m2_emit_char, /* Function to print a single character */
+ 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 */
+ NULL, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+/* Initialization for Modula-2 */
+
+void
+_initialize_m2_language (void)
+{
+ /* 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 0000000..a31c5ae
--- /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, 1998, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (void); /* Defined in m2-exp.y */
+
+extern void m2_error (char *); /* Defined in m2-exp.y */
+
+/* Defined in m2-typeprint.c */
+extern void m2_print_type (struct type *, char *, struct ui_file *, int,
+ int);
+
+extern int m2_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_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 0000000..90aefae
--- /dev/null
+++ b/contrib/gdb/gdb/m2-typeprint.c
@@ -0,0 +1,41 @@
+/* Support for printing Modula 2 types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1995, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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" /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "m2-lang.h"
+#include <errno.h>
+
+void
+m2_print_type (struct type *type, char *varstring, struct ui_file *stream,
+ int show, int level)
+{
+ extern void c_print_type (struct type *, char *, struct ui_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 0000000..ec80301
--- /dev/null
+++ b/contrib/gdb/gdb/m2-valprint.c
@@ -0,0 +1,39 @@
+/* Support for printing Modula 2 values for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991, 1992, 1996, 1998, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "m2-lang.h"
+
+/* FIXME: For now, just explicitly declare c_val_print and use it instead */
+
+int
+m2_val_print (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ extern int c_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+ return (c_val_print (type, valaddr, 0, address, stream, format, deref_ref,
+ recurse, pretty));
+}
diff --git a/contrib/gdb/gdb/macrocmd.c b/contrib/gdb/gdb/macrocmd.c
new file mode 100644
index 0000000..7c2ebbe
--- /dev/null
+++ b/contrib/gdb/gdb/macrocmd.c
@@ -0,0 +1,289 @@
+/* C preprocessor macro expansion commands for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "macrotab.h"
+#include "macroexp.h"
+#include "macroscope.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+
+/* The `macro' prefix command. */
+
+static struct cmd_list_element *macrolist;
+
+static void
+macro_command (char *arg, int from_tty)
+{
+ printf_unfiltered
+ ("\"macro\" must be followed by the name of a macro command.\n");
+ help_list (macrolist, "macro ", -1, gdb_stdout);
+}
+
+
+
+/* Macro expansion commands. */
+
+
+static void
+macro_expand_command (char *exp, int from_tty)
+{
+ struct macro_scope *ms = NULL;
+ char *expanded = NULL;
+ struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+ make_cleanup (free_current_contents, &expanded);
+
+ /* You know, when the user doesn't specify any expression, it would be
+ really cool if this defaulted to the last expression evaluated.
+ Then it would be easy to ask, "Hey, what did I just evaluate?" But
+ at the moment, the `print' commands don't save the last expression
+ evaluated, just its value. */
+ if (! exp || ! *exp)
+ error ("You must follow the `macro expand' command with the"
+ " expression you\n"
+ "want to expand.");
+
+ ms = default_macro_scope ();
+ if (ms)
+ {
+ expanded = macro_expand (exp, standard_macro_lookup, ms);
+ fputs_filtered ("expands to: ", gdb_stdout);
+ fputs_filtered (expanded, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ }
+ else
+ fputs_filtered ("GDB has no preprocessor macro information for "
+ "that code.\n",
+ gdb_stdout);
+
+ do_cleanups (cleanup_chain);
+ return;
+}
+
+
+static void
+macro_expand_once_command (char *exp, int from_tty)
+{
+ struct macro_scope *ms = NULL;
+ char *expanded = NULL;
+ struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+ make_cleanup (free_current_contents, &expanded);
+
+ /* You know, when the user doesn't specify any expression, it would be
+ really cool if this defaulted to the last expression evaluated.
+ And it should set the once-expanded text as the new `last
+ expression'. That way, you could just hit return over and over and
+ see the expression expanded one level at a time. */
+ if (! exp || ! *exp)
+ error ("You must follow the `macro expand-once' command with"
+ " the expression\n"
+ "you want to expand.");
+
+ ms = default_macro_scope ();
+ if (ms)
+ {
+ expanded = macro_expand_once (exp, standard_macro_lookup, ms);
+ fputs_filtered ("expands to: ", gdb_stdout);
+ fputs_filtered (expanded, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ }
+ else
+ fputs_filtered ("GDB has no preprocessor macro information for "
+ "that code.\n",
+ gdb_stdout);
+
+ do_cleanups (cleanup_chain);
+ return;
+}
+
+
+static void
+show_pp_source_pos (struct ui_file *stream,
+ struct macro_source_file *file,
+ int line)
+{
+ fprintf_filtered (stream, "%s:%d\n", file->filename, line);
+
+ while (file->included_by)
+ {
+ fprintf_filtered (gdb_stdout, " included at %s:%d\n",
+ file->included_by->filename,
+ file->included_at_line);
+ file = file->included_by;
+ }
+}
+
+
+static void
+info_macro_command (char *name, int from_tty)
+{
+ struct macro_scope *ms = NULL;
+ struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+ struct macro_definition *d;
+
+ if (! name || ! *name)
+ error ("You must follow the `info macro' command with the name"
+ " of the macro\n"
+ "whose definition you want to see.");
+
+ ms = default_macro_scope ();
+ if (! ms)
+ error ("GDB has no preprocessor macro information for that code.");
+
+ d = macro_lookup_definition (ms->file, ms->line, name);
+ if (d)
+ {
+ int line;
+ struct macro_source_file *file
+ = macro_definition_location (ms->file, ms->line, name, &line);
+
+ fprintf_filtered (gdb_stdout, "Defined at ");
+ show_pp_source_pos (gdb_stdout, file, line);
+ fprintf_filtered (gdb_stdout, "#define %s", name);
+ if (d->kind == macro_function_like)
+ {
+ int i;
+
+ fputs_filtered ("(", gdb_stdout);
+ for (i = 0; i < d->argc; i++)
+ {
+ fputs_filtered (d->argv[i], gdb_stdout);
+ if (i + 1 < d->argc)
+ fputs_filtered (", ", gdb_stdout);
+ }
+ fputs_filtered (")", gdb_stdout);
+ }
+ fprintf_filtered (gdb_stdout, " %s\n", d->replacement);
+ }
+ else
+ {
+ fprintf_filtered (gdb_stdout,
+ "The symbol `%s' has no definition as a C/C++"
+ " preprocessor macro\n"
+ "at ", name);
+ show_pp_source_pos (gdb_stdout, ms->file, ms->line);
+ }
+
+ do_cleanups (cleanup_chain);
+}
+
+
+
+/* User-defined macros. */
+
+/* A table of user-defined macros. Unlike the macro tables used for
+ symtabs, this one uses xmalloc for all its allocation, not an
+ obstack, and it doesn't bcache anything; it just xmallocs things. So
+ it's perfectly possible to remove things from this, or redefine
+ things. */
+static struct macro_table *user_macros;
+
+static void
+macro_define_command (char *exp, int from_tty)
+{
+ error ("Command not implemented yet.");
+}
+
+
+static void
+macro_undef_command (char *exp, int from_tty)
+{
+ error ("Command not implemented yet.");
+}
+
+
+static void
+macro_list_command (char *exp, int from_tty)
+{
+ error ("Command not implemented yet.");
+}
+
+
+
+/* Initializing the `macrocmd' module. */
+
+extern initialize_file_ftype _initialize_macrocmd; /* -Wmissing-prototypes */
+
+void
+_initialize_macrocmd (void)
+{
+ struct cmd_list_element *c;
+
+ /* We introduce a new command prefix, `macro', under which we'll put
+ the various commands for working with preprocessor macros. */
+ add_prefix_cmd
+ ("macro", class_info, macro_command,
+ "Prefix for commands dealing with C preprocessor macros.",
+ &macrolist, "macro ", 0, &cmdlist);
+
+ add_cmd
+ ("expand", no_class, macro_expand_command,
+ "Fully expand any C/C++ preprocessor macro invocations in EXPRESSION.\n"
+ "Show the expanded expression.",
+ &macrolist);
+ add_alias_cmd ("exp", "expand", no_class, 1, &macrolist);
+ add_cmd
+ ("expand-once", no_class, macro_expand_once_command,
+ "Expand C/C++ preprocessor macro invocations appearing directly in"
+ " EXPRESSION.\n"
+ "Show the expanded expression.\n"
+ "\n"
+ "This command differs from `macro expand' in that it only expands macro\n"
+ "invocations that appear directly in EXPRESSION; if expanding a macro\n"
+ "introduces further macro invocations, those are left unexpanded.\n"
+ "\n"
+ "`macro expand-once' helps you see how a particular macro expands,\n"
+ "whereas `macro expand' shows you how all the macros involved in an\n"
+ "expression work together to yield a pre-processed expression.",
+ &macrolist);
+ add_alias_cmd ("exp1", "expand-once", no_class, 1, &macrolist);
+
+ add_cmd
+ ("macro", no_class, info_macro_command,
+ "Show the definition of MACRO, and its source location.",
+ &infolist);
+
+ add_cmd
+ ("define", no_class, macro_define_command,
+ "Define a new C/C++ preprocessor macro.\n"
+ "The GDB command `macro define DEFINITION' is equivalent to placing a\n"
+ "preprocessor directive of the form `#define DEFINITION' such that the\n"
+ "definition is visible in all the inferior's source files.\n"
+ "For example:\n"
+ " (gdb) macro define PI (3.1415926)\n"
+ " (gdb) macro define MIN(x,y) ((x) < (y) ? (x) : (y))",
+ &macrolist);
+
+ add_cmd
+ ("undef", no_class, macro_undef_command,
+ "Remove the definition of the C/C++ preprocessor macro with the"
+ " given name.",
+ &macrolist);
+
+ add_cmd
+ ("list", no_class, macro_list_command,
+ "List all the macros defined using the `macro define' command.",
+ &macrolist);
+
+ user_macros = new_macro_table (0, 0);
+}
diff --git a/contrib/gdb/gdb/macroexp.c b/contrib/gdb/gdb/macroexp.c
new file mode 100644
index 0000000..e39f81a
--- /dev/null
+++ b/contrib/gdb/gdb/macroexp.c
@@ -0,0 +1,1169 @@
+/* C preprocessor macro expansion for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_obstack.h"
+#include "bcache.h"
+#include "macrotab.h"
+#include "macroexp.h"
+#include "gdb_assert.h"
+
+
+
+/* A resizeable, substringable string type. */
+
+
+/* A string type that we can resize, quickly append to, and use to
+ refer to substrings of other strings. */
+struct macro_buffer
+{
+ /* An array of characters. The first LEN bytes are the real text,
+ but there are SIZE bytes allocated to the array. If SIZE is
+ zero, then this doesn't point to a malloc'ed block. If SHARED is
+ non-zero, then this buffer is actually a pointer into some larger
+ string, and we shouldn't append characters to it, etc. Because
+ of sharing, we can't assume in general that the text is
+ null-terminated. */
+ char *text;
+
+ /* The number of characters in the string. */
+ int len;
+
+ /* The number of characters allocated to the string. If SHARED is
+ non-zero, this is meaningless; in this case, we set it to zero so
+ that any "do we have room to append something?" tests will fail,
+ so we don't always have to check SHARED before using this field. */
+ int size;
+
+ /* Zero if TEXT can be safely realloc'ed (i.e., it's its own malloc
+ block). Non-zero if TEXT is actually pointing into the middle of
+ some other block, and we shouldn't reallocate it. */
+ int shared;
+
+ /* For detecting token splicing.
+
+ This is the index in TEXT of the first character of the token
+ that abuts the end of TEXT. If TEXT contains no tokens, then we
+ set this equal to LEN. If TEXT ends in whitespace, then there is
+ no token abutting the end of TEXT (it's just whitespace), and
+ again, we set this equal to LEN. We set this to -1 if we don't
+ know the nature of TEXT. */
+ int last_token;
+
+ /* If this buffer is holding the result from get_token, then this
+ is non-zero if it is an identifier token, zero otherwise. */
+ int is_identifier;
+};
+
+
+/* Set the macro buffer *B to the empty string, guessing that its
+ final contents will fit in N bytes. (It'll get resized if it
+ doesn't, so the guess doesn't have to be right.) Allocate the
+ initial storage with xmalloc. */
+static void
+init_buffer (struct macro_buffer *b, int n)
+{
+ /* Small value for initial testing. */
+ n = 1;
+
+ b->size = n;
+ if (n > 0)
+ b->text = (char *) xmalloc (n);
+ else
+ b->text = NULL;
+ b->len = 0;
+ b->shared = 0;
+ b->last_token = -1;
+}
+
+
+/* Set the macro buffer *BUF to refer to the LEN bytes at ADDR, as a
+ shared substring. */
+static void
+init_shared_buffer (struct macro_buffer *buf, char *addr, int len)
+{
+ buf->text = addr;
+ buf->len = len;
+ buf->shared = 1;
+ buf->size = 0;
+ buf->last_token = -1;
+}
+
+
+/* Free the text of the buffer B. Raise an error if B is shared. */
+static void
+free_buffer (struct macro_buffer *b)
+{
+ gdb_assert (! b->shared);
+ if (b->size)
+ xfree (b->text);
+}
+
+
+/* A cleanup function for macro buffers. */
+static void
+cleanup_macro_buffer (void *untyped_buf)
+{
+ free_buffer ((struct macro_buffer *) untyped_buf);
+}
+
+
+/* Resize the buffer B to be at least N bytes long. Raise an error if
+ B shouldn't be resized. */
+static void
+resize_buffer (struct macro_buffer *b, int n)
+{
+ /* We shouldn't be trying to resize shared strings. */
+ gdb_assert (! b->shared);
+
+ if (b->size == 0)
+ b->size = n;
+ else
+ while (b->size <= n)
+ b->size *= 2;
+
+ b->text = xrealloc (b->text, b->size);
+}
+
+
+/* Append the character C to the buffer B. */
+static void
+appendc (struct macro_buffer *b, int c)
+{
+ int new_len = b->len + 1;
+
+ if (new_len > b->size)
+ resize_buffer (b, new_len);
+
+ b->text[b->len] = c;
+ b->len = new_len;
+}
+
+
+/* Append the LEN bytes at ADDR to the buffer B. */
+static void
+appendmem (struct macro_buffer *b, char *addr, int len)
+{
+ int new_len = b->len + len;
+
+ if (new_len > b->size)
+ resize_buffer (b, new_len);
+
+ memcpy (b->text + b->len, addr, len);
+ b->len = new_len;
+}
+
+
+
+/* Recognizing preprocessor tokens. */
+
+
+static int
+is_whitespace (int c)
+{
+ return (c == ' '
+ || c == '\t'
+ || c == '\n'
+ || c == '\v'
+ || c == '\f');
+}
+
+
+static int
+is_digit (int c)
+{
+ return ('0' <= c && c <= '9');
+}
+
+
+static int
+is_identifier_nondigit (int c)
+{
+ return (c == '_'
+ || ('a' <= c && c <= 'z')
+ || ('A' <= c && c <= 'Z'));
+}
+
+
+static void
+set_token (struct macro_buffer *tok, char *start, char *end)
+{
+ init_shared_buffer (tok, start, end - start);
+ tok->last_token = 0;
+
+ /* Presumed; get_identifier may overwrite this. */
+ tok->is_identifier = 0;
+}
+
+
+static int
+get_comment (struct macro_buffer *tok, char *p, char *end)
+{
+ if (p + 2 > end)
+ return 0;
+ else if (p[0] == '/'
+ && p[1] == '*')
+ {
+ char *tok_start = p;
+
+ p += 2;
+
+ for (; p < end; p++)
+ if (p + 2 <= end
+ && p[0] == '*'
+ && p[1] == '/')
+ {
+ p += 2;
+ set_token (tok, tok_start, p);
+ return 1;
+ }
+
+ error ("Unterminated comment in macro expansion.");
+ }
+ else if (p[0] == '/'
+ && p[1] == '/')
+ {
+ char *tok_start = p;
+
+ p += 2;
+ for (; p < end; p++)
+ if (*p == '\n')
+ break;
+
+ set_token (tok, tok_start, p);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+get_identifier (struct macro_buffer *tok, char *p, char *end)
+{
+ if (p < end
+ && is_identifier_nondigit (*p))
+ {
+ char *tok_start = p;
+
+ while (p < end
+ && (is_identifier_nondigit (*p)
+ || is_digit (*p)))
+ p++;
+
+ set_token (tok, tok_start, p);
+ tok->is_identifier = 1;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+get_pp_number (struct macro_buffer *tok, char *p, char *end)
+{
+ if (p < end
+ && (is_digit (*p)
+ || *p == '.'))
+ {
+ char *tok_start = p;
+
+ while (p < end)
+ {
+ if (is_digit (*p)
+ || is_identifier_nondigit (*p)
+ || *p == '.')
+ p++;
+ else if (p + 2 <= end
+ && strchr ("eEpP.", *p)
+ && (p[1] == '+' || p[1] == '-'))
+ p += 2;
+ else
+ break;
+ }
+
+ set_token (tok, tok_start, p);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+
+/* If the text starting at P going up to (but not including) END
+ starts with a character constant, set *TOK to point to that
+ character constant, and return 1. Otherwise, return zero.
+ Signal an error if it contains a malformed or incomplete character
+ constant. */
+static int
+get_character_constant (struct macro_buffer *tok, char *p, char *end)
+{
+ /* ISO/IEC 9899:1999 (E) Section 6.4.4.4 paragraph 1
+ But of course, what really matters is that we handle it the same
+ way GDB's C/C++ lexer does. So we call parse_escape in utils.c
+ to handle escape sequences. */
+ if ((p + 1 <= end && *p == '\'')
+ || (p + 2 <= end && p[0] == 'L' && p[1] == '\''))
+ {
+ char *tok_start = p;
+ char *body_start;
+
+ if (*p == '\'')
+ p++;
+ else if (*p == 'L')
+ p += 2;
+ else
+ gdb_assert (0);
+
+ body_start = p;
+ for (;;)
+ {
+ if (p >= end)
+ error ("Unmatched single quote.");
+ else if (*p == '\'')
+ {
+ if (p == body_start)
+ error ("A character constant must contain at least one "
+ "character.");
+ p++;
+ break;
+ }
+ else if (*p == '\\')
+ {
+ p++;
+ parse_escape (&p);
+ }
+ else
+ p++;
+ }
+
+ set_token (tok, tok_start, p);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+/* If the text starting at P going up to (but not including) END
+ starts with a string literal, set *TOK to point to that string
+ literal, and return 1. Otherwise, return zero. Signal an error if
+ it contains a malformed or incomplete string literal. */
+static int
+get_string_literal (struct macro_buffer *tok, char *p, char *end)
+{
+ if ((p + 1 <= end
+ && *p == '\"')
+ || (p + 2 <= end
+ && p[0] == 'L'
+ && p[1] == '\"'))
+ {
+ char *tok_start = p;
+
+ if (*p == '\"')
+ p++;
+ else if (*p == 'L')
+ p += 2;
+ else
+ gdb_assert (0);
+
+ for (;;)
+ {
+ if (p >= end)
+ error ("Unterminated string in expression.");
+ else if (*p == '\"')
+ {
+ p++;
+ break;
+ }
+ else if (*p == '\n')
+ error ("Newline characters may not appear in string "
+ "constants.");
+ else if (*p == '\\')
+ {
+ p++;
+ parse_escape (&p);
+ }
+ else
+ p++;
+ }
+
+ set_token (tok, tok_start, p);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+get_punctuator (struct macro_buffer *tok, char *p, char *end)
+{
+ /* Here, speed is much less important than correctness and clarity. */
+
+ /* ISO/IEC 9899:1999 (E) Section 6.4.6 Paragraph 1 */
+ static const char * const punctuators[] = {
+ "[", "]", "(", ")", "{", "}", ".", "->",
+ "++", "--", "&", "*", "+", "-", "~", "!",
+ "/", "%", "<<", ">>", "<", ">", "<=", ">=", "==", "!=",
+ "^", "|", "&&", "||",
+ "?", ":", ";", "...",
+ "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=",
+ ",", "#", "##",
+ "<:", ":>", "<%", "%>", "%:", "%:%:",
+ 0
+ };
+
+ int i;
+
+ if (p + 1 <= end)
+ {
+ for (i = 0; punctuators[i]; i++)
+ {
+ const char *punctuator = punctuators[i];
+
+ if (p[0] == punctuator[0])
+ {
+ int len = strlen (punctuator);
+
+ if (p + len <= end
+ && ! memcmp (p, punctuator, len))
+ {
+ set_token (tok, p, p + len);
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* Peel the next preprocessor token off of SRC, and put it in TOK.
+ Mutate TOK to refer to the first token in SRC, and mutate SRC to
+ refer to the text after that token. SRC must be a shared buffer;
+ the resulting TOK will be shared, pointing into the same string SRC
+ does. Initialize TOK's last_token field. Return non-zero if we
+ succeed, or 0 if we didn't find any more tokens in SRC. */
+static int
+get_token (struct macro_buffer *tok,
+ struct macro_buffer *src)
+{
+ char *p = src->text;
+ char *end = p + src->len;
+
+ gdb_assert (src->shared);
+
+ /* From the ISO C standard, ISO/IEC 9899:1999 (E), section 6.4:
+
+ preprocessing-token:
+ header-name
+ identifier
+ pp-number
+ character-constant
+ string-literal
+ punctuator
+ each non-white-space character that cannot be one of the above
+
+ We don't have to deal with header-name tokens, since those can
+ only occur after a #include, which we will never see. */
+
+ while (p < end)
+ if (is_whitespace (*p))
+ p++;
+ else if (get_comment (tok, p, end))
+ p += tok->len;
+ else if (get_pp_number (tok, p, end)
+ || get_character_constant (tok, p, end)
+ || get_string_literal (tok, p, end)
+ /* Note: the grammar in the standard seems to be
+ ambiguous: L'x' can be either a wide character
+ constant, or an identifier followed by a normal
+ character constant. By trying `get_identifier' after
+ we try get_character_constant and get_string_literal,
+ we give the wide character syntax precedence. Now,
+ since GDB doesn't handle wide character constants
+ anyway, is this the right thing to do? */
+ || get_identifier (tok, p, end)
+ || get_punctuator (tok, p, end))
+ {
+ /* How many characters did we consume, including whitespace? */
+ int consumed = p - src->text + tok->len;
+ src->text += consumed;
+ src->len -= consumed;
+ return 1;
+ }
+ else
+ {
+ /* We have found a "non-whitespace character that cannot be
+ one of the above." Make a token out of it. */
+ int consumed;
+
+ set_token (tok, p, p + 1);
+ consumed = p - src->text + tok->len;
+ src->text += consumed;
+ src->len -= consumed;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+/* Appending token strings, with and without splicing */
+
+
+/* Append the macro buffer SRC to the end of DEST, and ensure that
+ doing so doesn't splice the token at the end of SRC with the token
+ at the beginning of DEST. SRC and DEST must have their last_token
+ fields set. Upon return, DEST's last_token field is set correctly.
+
+ For example:
+
+ If DEST is "(" and SRC is "y", then we can return with
+ DEST set to "(y" --- we've simply appended the two buffers.
+
+ However, if DEST is "x" and SRC is "y", then we must not return
+ with DEST set to "xy" --- that would splice the two tokens "x" and
+ "y" together to make a single token "xy". However, it would be
+ fine to return with DEST set to "x y". Similarly, "<" and "<" must
+ yield "< <", not "<<", etc. */
+static void
+append_tokens_without_splicing (struct macro_buffer *dest,
+ struct macro_buffer *src)
+{
+ int original_dest_len = dest->len;
+ struct macro_buffer dest_tail, new_token;
+
+ gdb_assert (src->last_token != -1);
+ gdb_assert (dest->last_token != -1);
+
+ /* First, just try appending the two, and call get_token to see if
+ we got a splice. */
+ appendmem (dest, src->text, src->len);
+
+ /* If DEST originally had no token abutting its end, then we can't
+ have spliced anything, so we're done. */
+ if (dest->last_token == original_dest_len)
+ {
+ dest->last_token = original_dest_len + src->last_token;
+ return;
+ }
+
+ /* Set DEST_TAIL to point to the last token in DEST, followed by
+ all the stuff we just appended. */
+ init_shared_buffer (&dest_tail,
+ dest->text + dest->last_token,
+ dest->len - dest->last_token);
+
+ /* Re-parse DEST's last token. We know that DEST used to contain
+ at least one token, so if it doesn't contain any after the
+ append, then we must have spliced "/" and "*" or "/" and "/" to
+ make a comment start. (Just for the record, I got this right
+ the first time. This is not a bug fix.) */
+ if (get_token (&new_token, &dest_tail)
+ && (new_token.text + new_token.len
+ == dest->text + original_dest_len))
+ {
+ /* No splice, so we're done. */
+ dest->last_token = original_dest_len + src->last_token;
+ return;
+ }
+
+ /* Okay, a simple append caused a splice. Let's chop dest back to
+ its original length and try again, but separate the texts with a
+ space. */
+ dest->len = original_dest_len;
+ appendc (dest, ' ');
+ appendmem (dest, src->text, src->len);
+
+ init_shared_buffer (&dest_tail,
+ dest->text + dest->last_token,
+ dest->len - dest->last_token);
+
+ /* Try to re-parse DEST's last token, as above. */
+ if (get_token (&new_token, &dest_tail)
+ && (new_token.text + new_token.len
+ == dest->text + original_dest_len))
+ {
+ /* No splice, so we're done. */
+ dest->last_token = original_dest_len + 1 + src->last_token;
+ return;
+ }
+
+ /* As far as I know, there's no case where inserting a space isn't
+ enough to prevent a splice. */
+ internal_error (__FILE__, __LINE__,
+ "unable to avoid splicing tokens during macro expansion");
+}
+
+
+
+/* Expanding macros! */
+
+
+/* A singly-linked list of the names of the macros we are currently
+ expanding --- for detecting expansion loops. */
+struct macro_name_list {
+ const char *name;
+ struct macro_name_list *next;
+};
+
+
+/* Return non-zero if we are currently expanding the macro named NAME,
+ according to LIST; otherwise, return zero.
+
+ You know, it would be possible to get rid of all the NO_LOOP
+ arguments to these functions by simply generating a new lookup
+ function and baton which refuses to find the definition for a
+ particular macro, and otherwise delegates the decision to another
+ function/baton pair. But that makes the linked list of excluded
+ macros chained through untyped baton pointers, which will make it
+ harder to debug. :( */
+static int
+currently_rescanning (struct macro_name_list *list, const char *name)
+{
+ for (; list; list = list->next)
+ if (strcmp (name, list->name) == 0)
+ return 1;
+
+ return 0;
+}
+
+
+/* Gather the arguments to a macro expansion.
+
+ NAME is the name of the macro being invoked. (It's only used for
+ printing error messages.)
+
+ Assume that SRC is the text of the macro invocation immediately
+ following the macro name. For example, if we're processing the
+ text foo(bar, baz), then NAME would be foo and SRC will be (bar,
+ baz).
+
+ If SRC doesn't start with an open paren ( token at all, return
+ zero, leave SRC unchanged, and don't set *ARGC_P to anything.
+
+ If SRC doesn't contain a properly terminated argument list, then
+ raise an error.
+
+ Otherwise, return a pointer to the first element of an array of
+ macro buffers referring to the argument texts, and set *ARGC_P to
+ the number of arguments we found --- the number of elements in the
+ array. The macro buffers share their text with SRC, and their
+ last_token fields are initialized. The array is allocated with
+ xmalloc, and the caller is responsible for freeing it.
+
+ NOTE WELL: if SRC starts with a open paren ( token followed
+ immediately by a close paren ) token (e.g., the invocation looks
+ like "foo()"), we treat that as one argument, which happens to be
+ the empty list of tokens. The caller should keep in mind that such
+ a sequence of tokens is a valid way to invoke one-parameter
+ function-like macros, but also a valid way to invoke zero-parameter
+ function-like macros. Eeew.
+
+ Consume the tokens from SRC; after this call, SRC contains the text
+ following the invocation. */
+
+static struct macro_buffer *
+gather_arguments (const char *name, struct macro_buffer *src, int *argc_p)
+{
+ struct macro_buffer tok;
+ int args_len, args_size;
+ struct macro_buffer *args = NULL;
+ struct cleanup *back_to = make_cleanup (free_current_contents, &args);
+
+ /* Does SRC start with an opening paren token? Read from a copy of
+ SRC, so SRC itself is unaffected if we don't find an opening
+ paren. */
+ {
+ struct macro_buffer temp;
+ init_shared_buffer (&temp, src->text, src->len);
+
+ if (! get_token (&tok, &temp)
+ || tok.len != 1
+ || tok.text[0] != '(')
+ {
+ discard_cleanups (back_to);
+ return 0;
+ }
+ }
+
+ /* Consume SRC's opening paren. */
+ get_token (&tok, src);
+
+ args_len = 0;
+ args_size = 1; /* small for initial testing */
+ args = (struct macro_buffer *) xmalloc (sizeof (*args) * args_size);
+
+ for (;;)
+ {
+ struct macro_buffer *arg;
+ int depth;
+
+ /* Make sure we have room for the next argument. */
+ if (args_len >= args_size)
+ {
+ args_size *= 2;
+ args = xrealloc (args, sizeof (*args) * args_size);
+ }
+
+ /* Initialize the next argument. */
+ arg = &args[args_len++];
+ set_token (arg, src->text, src->text);
+
+ /* Gather the argument's tokens. */
+ depth = 0;
+ for (;;)
+ {
+ char *start = src->text;
+
+ if (! get_token (&tok, src))
+ error ("Malformed argument list for macro `%s'.", name);
+
+ /* Is tok an opening paren? */
+ if (tok.len == 1 && tok.text[0] == '(')
+ depth++;
+
+ /* Is tok is a closing paren? */
+ else if (tok.len == 1 && tok.text[0] == ')')
+ {
+ /* If it's a closing paren at the top level, then that's
+ the end of the argument list. */
+ if (depth == 0)
+ {
+ discard_cleanups (back_to);
+ *argc_p = args_len;
+ return args;
+ }
+
+ depth--;
+ }
+
+ /* If tok is a comma at top level, then that's the end of
+ the current argument. */
+ else if (tok.len == 1 && tok.text[0] == ',' && depth == 0)
+ break;
+
+ /* Extend the current argument to enclose this token. If
+ this is the current argument's first token, leave out any
+ leading whitespace, just for aesthetics. */
+ if (arg->len == 0)
+ {
+ arg->text = tok.text;
+ arg->len = tok.len;
+ arg->last_token = 0;
+ }
+ else
+ {
+ arg->len = (tok.text + tok.len) - arg->text;
+ arg->last_token = tok.text - arg->text;
+ }
+ }
+ }
+}
+
+
+/* The `expand' and `substitute_args' functions both invoke `scan'
+ recursively, so we need a forward declaration somewhere. */
+static void scan (struct macro_buffer *dest,
+ struct macro_buffer *src,
+ struct macro_name_list *no_loop,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_baton);
+
+
+/* Given the macro definition DEF, being invoked with the actual
+ arguments given by ARGC and ARGV, substitute the arguments into the
+ replacement list, and store the result in DEST.
+
+ If it is necessary to expand macro invocations in one of the
+ arguments, use LOOKUP_FUNC and LOOKUP_BATON to find the macro
+ definitions, and don't expand invocations of the macros listed in
+ NO_LOOP. */
+static void
+substitute_args (struct macro_buffer *dest,
+ struct macro_definition *def,
+ int argc, struct macro_buffer *argv,
+ struct macro_name_list *no_loop,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_baton)
+{
+ /* A macro buffer for the macro's replacement list. */
+ struct macro_buffer replacement_list;
+
+ init_shared_buffer (&replacement_list, (char *) def->replacement,
+ strlen (def->replacement));
+
+ gdb_assert (dest->len == 0);
+ dest->last_token = 0;
+
+ for (;;)
+ {
+ struct macro_buffer tok;
+ char *original_rl_start = replacement_list.text;
+ int substituted = 0;
+
+ /* Find the next token in the replacement list. */
+ if (! get_token (&tok, &replacement_list))
+ break;
+
+ /* Just for aesthetics. If we skipped some whitespace, copy
+ that to DEST. */
+ if (tok.text > original_rl_start)
+ {
+ appendmem (dest, original_rl_start, tok.text - original_rl_start);
+ dest->last_token = dest->len;
+ }
+
+ /* Is this token the stringification operator? */
+ if (tok.len == 1
+ && tok.text[0] == '#')
+ error ("Stringification is not implemented yet.");
+
+ /* Is this token the splicing operator? */
+ if (tok.len == 2
+ && tok.text[0] == '#'
+ && tok.text[1] == '#')
+ error ("Token splicing is not implemented yet.");
+
+ /* Is this token an identifier? */
+ if (tok.is_identifier)
+ {
+ int i;
+
+ /* Is it the magic varargs parameter? */
+ if (tok.len == 11
+ && ! memcmp (tok.text, "__VA_ARGS__", 11))
+ error ("Variable-arity macros not implemented yet.");
+
+ /* Is it one of the parameters? */
+ for (i = 0; i < def->argc; i++)
+ if (tok.len == strlen (def->argv[i])
+ && ! memcmp (tok.text, def->argv[i], tok.len))
+ {
+ struct macro_buffer arg_src;
+
+ /* Expand any macro invocations in the argument text,
+ and append the result to dest. Remember that scan
+ mutates its source, so we need to scan a new buffer
+ referring to the argument's text, not the argument
+ itself. */
+ init_shared_buffer (&arg_src, argv[i].text, argv[i].len);
+ scan (dest, &arg_src, no_loop, lookup_func, lookup_baton);
+ substituted = 1;
+ break;
+ }
+ }
+
+ /* If it wasn't a parameter, then just copy it across. */
+ if (! substituted)
+ append_tokens_without_splicing (dest, &tok);
+ }
+}
+
+
+/* Expand a call to a macro named ID, whose definition is DEF. Append
+ its expansion to DEST. SRC is the input text following the ID
+ token. We are currently rescanning the expansions of the macros
+ named in NO_LOOP; don't re-expand them. Use LOOKUP_FUNC and
+ LOOKUP_BATON to find definitions for any nested macro references.
+
+ Return 1 if we decided to expand it, zero otherwise. (If it's a
+ function-like macro name that isn't followed by an argument list,
+ we don't expand it.) If we return zero, leave SRC unchanged. */
+static int
+expand (const char *id,
+ struct macro_definition *def,
+ struct macro_buffer *dest,
+ struct macro_buffer *src,
+ struct macro_name_list *no_loop,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_baton)
+{
+ struct macro_name_list new_no_loop;
+
+ /* Create a new node to be added to the front of the no-expand list.
+ This list is appropriate for re-scanning replacement lists, but
+ it is *not* appropriate for scanning macro arguments; invocations
+ of the macro whose arguments we are gathering *do* get expanded
+ there. */
+ new_no_loop.name = id;
+ new_no_loop.next = no_loop;
+
+ /* What kind of macro are we expanding? */
+ if (def->kind == macro_object_like)
+ {
+ struct macro_buffer replacement_list;
+
+ init_shared_buffer (&replacement_list, (char *) def->replacement,
+ strlen (def->replacement));
+
+ scan (dest, &replacement_list, &new_no_loop, lookup_func, lookup_baton);
+ return 1;
+ }
+ else if (def->kind == macro_function_like)
+ {
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+ int argc;
+ struct macro_buffer *argv = NULL;
+ struct macro_buffer substituted;
+ struct macro_buffer substituted_src;
+
+ if (def->argc >= 1
+ && strcmp (def->argv[def->argc - 1], "...") == 0)
+ error ("Varargs macros not implemented yet.");
+
+ make_cleanup (free_current_contents, &argv);
+ argv = gather_arguments (id, src, &argc);
+
+ /* If we couldn't find any argument list, then we don't expand
+ this macro. */
+ if (! argv)
+ {
+ do_cleanups (back_to);
+ return 0;
+ }
+
+ /* Check that we're passing an acceptable number of arguments for
+ this macro. */
+ if (argc != def->argc)
+ {
+ /* Remember that a sequence of tokens like "foo()" is a
+ valid invocation of a macro expecting either zero or one
+ arguments. */
+ if (! (argc == 1
+ && argv[0].len == 0
+ && def->argc == 0))
+ error ("Wrong number of arguments to macro `%s' "
+ "(expected %d, got %d).",
+ id, def->argc, argc);
+ }
+
+ /* Note that we don't expand macro invocations in the arguments
+ yet --- we let subst_args take care of that. Parameters that
+ appear as operands of the stringifying operator "#" or the
+ splicing operator "##" don't get macro references expanded,
+ so we can't really tell whether it's appropriate to macro-
+ expand an argument until we see how it's being used. */
+ init_buffer (&substituted, 0);
+ make_cleanup (cleanup_macro_buffer, &substituted);
+ substitute_args (&substituted, def, argc, argv, no_loop,
+ lookup_func, lookup_baton);
+
+ /* Now `substituted' is the macro's replacement list, with all
+ argument values substituted into it properly. Re-scan it for
+ macro references, but don't expand invocations of this macro.
+
+ We create a new buffer, `substituted_src', which points into
+ `substituted', and scan that. We can't scan `substituted'
+ itself, since the tokenization process moves the buffer's
+ text pointer around, and we still need to be able to find
+ `substituted's original text buffer after scanning it so we
+ can free it. */
+ init_shared_buffer (&substituted_src, substituted.text, substituted.len);
+ scan (dest, &substituted_src, &new_no_loop, lookup_func, lookup_baton);
+
+ do_cleanups (back_to);
+
+ return 1;
+ }
+ else
+ internal_error (__FILE__, __LINE__, "bad macro definition kind");
+}
+
+
+/* If the single token in SRC_FIRST followed by the tokens in SRC_REST
+ constitute a macro invokation not forbidden in NO_LOOP, append its
+ expansion to DEST and return non-zero. Otherwise, return zero, and
+ leave DEST unchanged.
+
+ SRC_FIRST and SRC_REST must be shared buffers; DEST must not be one.
+ SRC_FIRST must be a string built by get_token. */
+static int
+maybe_expand (struct macro_buffer *dest,
+ struct macro_buffer *src_first,
+ struct macro_buffer *src_rest,
+ struct macro_name_list *no_loop,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_baton)
+{
+ gdb_assert (src_first->shared);
+ gdb_assert (src_rest->shared);
+ gdb_assert (! dest->shared);
+
+ /* Is this token an identifier? */
+ if (src_first->is_identifier)
+ {
+ /* Make a null-terminated copy of it, since that's what our
+ lookup function expects. */
+ char *id = xmalloc (src_first->len + 1);
+ struct cleanup *back_to = make_cleanup (xfree, id);
+ memcpy (id, src_first->text, src_first->len);
+ id[src_first->len] = 0;
+
+ /* If we're currently re-scanning the result of expanding
+ this macro, don't expand it again. */
+ if (! currently_rescanning (no_loop, id))
+ {
+ /* Does this identifier have a macro definition in scope? */
+ struct macro_definition *def = lookup_func (id, lookup_baton);
+
+ if (def && expand (id, def, dest, src_rest, no_loop,
+ lookup_func, lookup_baton))
+ {
+ do_cleanups (back_to);
+ return 1;
+ }
+ }
+
+ do_cleanups (back_to);
+ }
+
+ return 0;
+}
+
+
+/* Expand macro references in SRC, appending the results to DEST.
+ Assume we are re-scanning the result of expanding the macros named
+ in NO_LOOP, and don't try to re-expand references to them.
+
+ SRC must be a shared buffer; DEST must not be one. */
+static void
+scan (struct macro_buffer *dest,
+ struct macro_buffer *src,
+ struct macro_name_list *no_loop,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_baton)
+{
+ gdb_assert (src->shared);
+ gdb_assert (! dest->shared);
+
+ for (;;)
+ {
+ struct macro_buffer tok;
+ char *original_src_start = src->text;
+
+ /* Find the next token in SRC. */
+ if (! get_token (&tok, src))
+ break;
+
+ /* Just for aesthetics. If we skipped some whitespace, copy
+ that to DEST. */
+ if (tok.text > original_src_start)
+ {
+ appendmem (dest, original_src_start, tok.text - original_src_start);
+ dest->last_token = dest->len;
+ }
+
+ if (! maybe_expand (dest, &tok, src, no_loop, lookup_func, lookup_baton))
+ /* We didn't end up expanding tok as a macro reference, so
+ simply append it to dest. */
+ append_tokens_without_splicing (dest, &tok);
+ }
+
+ /* Just for aesthetics. If there was any trailing whitespace in
+ src, copy it to dest. */
+ if (src->len)
+ {
+ appendmem (dest, src->text, src->len);
+ dest->last_token = dest->len;
+ }
+}
+
+
+char *
+macro_expand (const char *source,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_func_baton)
+{
+ struct macro_buffer src, dest;
+ struct cleanup *back_to;
+
+ init_shared_buffer (&src, (char *) source, strlen (source));
+
+ init_buffer (&dest, 0);
+ dest.last_token = 0;
+ back_to = make_cleanup (cleanup_macro_buffer, &dest);
+
+ scan (&dest, &src, 0, lookup_func, lookup_func_baton);
+
+ appendc (&dest, '\0');
+
+ discard_cleanups (back_to);
+ return dest.text;
+}
+
+
+char *
+macro_expand_once (const char *source,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_func_baton)
+{
+ error ("Expand-once not implemented yet.");
+}
+
+
+char *
+macro_expand_next (char **lexptr,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_baton)
+{
+ struct macro_buffer src, dest, tok;
+ struct cleanup *back_to;
+
+ /* Set up SRC to refer to the input text, pointed to by *lexptr. */
+ init_shared_buffer (&src, *lexptr, strlen (*lexptr));
+
+ /* Set up DEST to receive the expansion, if there is one. */
+ init_buffer (&dest, 0);
+ dest.last_token = 0;
+ back_to = make_cleanup (cleanup_macro_buffer, &dest);
+
+ /* Get the text's first preprocessing token. */
+ if (! get_token (&tok, &src))
+ {
+ do_cleanups (back_to);
+ return 0;
+ }
+
+ /* If it's a macro invocation, expand it. */
+ if (maybe_expand (&dest, &tok, &src, 0, lookup_func, lookup_baton))
+ {
+ /* It was a macro invocation! Package up the expansion as a
+ null-terminated string and return it. Set *lexptr to the
+ start of the next token in the input. */
+ appendc (&dest, '\0');
+ discard_cleanups (back_to);
+ *lexptr = src.text;
+ return dest.text;
+ }
+ else
+ {
+ /* It wasn't a macro invocation. */
+ do_cleanups (back_to);
+ return 0;
+ }
+}
diff --git a/contrib/gdb/gdb/macroexp.h b/contrib/gdb/gdb/macroexp.h
new file mode 100644
index 0000000..57269fa
--- /dev/null
+++ b/contrib/gdb/gdb/macroexp.h
@@ -0,0 +1,90 @@
+/* Interface to C preprocessor macro expansion for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MACROEXP_H
+#define MACROEXP_H
+
+/* A function for looking up preprocessor macro definitions. Return
+ the preprocessor definition of NAME in scope according to BATON, or
+ zero if NAME is not defined as a preprocessor macro.
+
+ The caller must not free or modify the definition returned. It is
+ probably unwise for the caller to hold pointers to it for very
+ long; it probably lives in some objfile's obstacks. */
+typedef struct macro_definition *(macro_lookup_ftype) (const char *name,
+ void *baton);
+
+
+/* Expand any preprocessor macros in SOURCE, and return the expanded
+ text. Use LOOKUP_FUNC and LOOKUP_FUNC_BATON to find identifiers'
+ preprocessor definitions. SOURCE is a null-terminated string. The
+ result is a null-terminated string, allocated using xmalloc; it is
+ the caller's responsibility to free it. */
+char *macro_expand (const char *source,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_func_baton);
+
+
+/* Expand all preprocessor macro references that appear explicitly in
+ SOURCE, but do not expand any new macro references introduced by
+ that first level of expansion. Use LOOKUP_FUNC and
+ LOOKUP_FUNC_BATON to find identifiers' preprocessor definitions.
+ SOURCE is a null-terminated string. The result is a
+ null-terminated string, allocated using xmalloc; it is the caller's
+ responsibility to free it. */
+char *macro_expand_once (const char *source,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_func_baton);
+
+
+/* If the null-terminated string pointed to by *LEXPTR begins with a
+ macro invocation, return the result of expanding that invocation as
+ a null-terminated string, and set *LEXPTR to the next character
+ after the invocation. The result is completely expanded; it
+ contains no further macro invocations.
+
+ Otherwise, if *LEXPTR does not start with a macro invocation,
+ return zero, and leave *LEXPTR unchanged.
+
+ Use LOOKUP_FUNC and LOOKUP_BATON to find macro definitions.
+
+ If this function returns a string, the caller is responsible for
+ freeing it, using xfree.
+
+ We need this expand-one-token-at-a-time interface in order to
+ accomodate GDB's C expression parser, which may not consume the
+ entire string. When the user enters a command like
+
+ (gdb) break *func+20 if x == 5
+
+ the parser is expected to consume `func+20', and then stop when it
+ sees the "if". But of course, "if" appearing in a character string
+ or as part of a larger identifier doesn't count. So you pretty
+ much have to do tokenization to find the end of the string that
+ needs to be macro-expanded. Our C/C++ tokenizer isn't really
+ designed to be called by anything but the yacc parser engine. */
+char *macro_expand_next (char **lexptr,
+ macro_lookup_ftype *lookup_func,
+ void *lookup_baton);
+
+
+#endif /* MACROEXP_H */
diff --git a/contrib/gdb/gdb/macroscope.c b/contrib/gdb/gdb/macroscope.c
new file mode 100644
index 0000000..19557d7
--- /dev/null
+++ b/contrib/gdb/gdb/macroscope.c
@@ -0,0 +1,132 @@
+/* Functions for deciding which macros are currently in scope.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "macroscope.h"
+#include "symtab.h"
+#include "source.h"
+#include "target.h"
+#include "frame.h"
+#include "inferior.h"
+#include "complaints.h"
+
+
+struct macro_scope *
+sal_macro_scope (struct symtab_and_line sal)
+{
+ struct macro_source_file *main, *inclusion;
+ struct macro_scope *ms;
+
+ if (! sal.symtab
+ || ! sal.symtab->macro_table)
+ return 0;
+
+ ms = (struct macro_scope *) xmalloc (sizeof (*ms));
+
+ main = macro_main (sal.symtab->macro_table);
+ inclusion = macro_lookup_inclusion (main, sal.symtab->filename);
+
+ if (inclusion)
+ {
+ ms->file = inclusion;
+ ms->line = sal.line;
+ }
+ else
+ {
+ /* There are, unfortunately, cases where a compilation unit can
+ have a symtab for a source file that doesn't appear in the
+ macro table. For example, at the moment, Dwarf doesn't have
+ any way in the .debug_macinfo section to describe the effect
+ of #line directives, so if you debug a YACC parser you'll get
+ a macro table which only mentions the .c files generated by
+ YACC, but symtabs that mention the .y files consumed by YACC.
+
+ In the long run, we should extend the Dwarf macro info
+ representation to handle #line directives, and get GCC to
+ emit it.
+
+ For the time being, though, we'll just treat these as
+ occurring at the end of the main source file. */
+ ms->file = main;
+ ms->line = -1;
+
+ complaint (&symfile_complaints,
+ "symtab found for `%s', but that file\n"
+ "is not covered in the compilation unit's macro information",
+ sal.symtab->filename);
+ }
+
+ return ms;
+}
+
+
+struct macro_scope *
+default_macro_scope (void)
+{
+ struct symtab_and_line sal;
+ struct macro_source_file *main;
+ struct macro_scope *ms;
+
+ /* If there's a selected frame, use its PC. */
+ if (deprecated_selected_frame)
+ sal = find_pc_line (get_frame_pc (deprecated_selected_frame), 0);
+
+ /* If the target has any registers at all, then use its PC. Why we
+ would have registers but no stack, I'm not sure. */
+ else if (target_has_registers)
+ sal = find_pc_line (read_pc (), 0);
+
+ /* If all else fails, fall back to the current listing position. */
+ else
+ {
+ /* Don't call select_source_symtab here. That can raise an
+ error if symbols aren't loaded, but GDB calls the expression
+ evaluator in all sorts of contexts.
+
+ For example, commands like `set width' call the expression
+ evaluator to evaluate their numeric arguments. If the
+ current language is C, then that may call this function to
+ choose a scope for macro expansion. If you don't have any
+ symbol files loaded, then get_current_or_default would raise an
+ error. But `set width' shouldn't raise an error just because
+ it can't decide which scope to macro-expand its argument in. */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ sal.symtab = cursal.symtab;
+ sal.line = cursal.line;
+ }
+
+ return sal_macro_scope (sal);
+}
+
+
+/* Look up the definition of the macro named NAME in scope at the source
+ location given by BATON, which must be a pointer to a `struct
+ macro_scope' structure. */
+struct macro_definition *
+standard_macro_lookup (const char *name, void *baton)
+{
+ struct macro_scope *ms = (struct macro_scope *) baton;
+
+ return macro_lookup_definition (ms->file, ms->line, name);
+}
diff --git a/contrib/gdb/gdb/macroscope.h b/contrib/gdb/gdb/macroscope.h
new file mode 100644
index 0000000..fc10b6d
--- /dev/null
+++ b/contrib/gdb/gdb/macroscope.h
@@ -0,0 +1,63 @@
+/* Interface to functions for deciding which macros are currently in scope.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MACROSCOPE_H
+#define MACROSCOPE_H
+
+#include "macrotab.h"
+#include "symtab.h"
+
+
+/* All the information we need to decide which macro definitions are
+ in scope: a source file (either a main source file or an
+ #inclusion), and a line number in that file. */
+struct macro_scope {
+ struct macro_source_file *file;
+ int line;
+};
+
+
+/* Return a `struct macro_scope' object corresponding to the symtab
+ and line given in SAL. If we have no macro information for that
+ location, or if SAL's pc is zero, return zero. */
+struct macro_scope *sal_macro_scope (struct symtab_and_line sal);
+
+
+/* Return a `struct macro_scope' object describing the scope the `macro
+ expand' and `macro expand-once' commands should use for looking up
+ macros. If we have a selected frame, this is the source location of
+ its PC; otherwise, this is the last listing position.
+
+ If we have no macro information for the current location, return zero.
+
+ The object returned is allocated using xmalloc; the caller is
+ responsible for freeing it. */
+struct macro_scope *default_macro_scope (void);
+
+
+/* Look up the definition of the macro named NAME in scope at the source
+ location given by BATON, which must be a pointer to a `struct
+ macro_scope' structure. This function is suitable for use as
+ a macro_lookup_ftype function. */
+struct macro_definition *standard_macro_lookup (const char *name, void *baton);
+
+
+#endif /* MACROSCOPE_H */
diff --git a/contrib/gdb/gdb/macrotab.c b/contrib/gdb/gdb/macrotab.c
new file mode 100644
index 0000000..56ee2a4
--- /dev/null
+++ b/contrib/gdb/gdb/macrotab.c
@@ -0,0 +1,892 @@
+/* C preprocessor macro tables for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_obstack.h"
+#include "splay-tree.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "macrotab.h"
+#include "gdb_assert.h"
+#include "bcache.h"
+#include "complaints.h"
+
+
+/* The macro table structure. */
+
+struct macro_table
+{
+ /* The obstack this table's data should be allocated in, or zero if
+ we should use xmalloc. */
+ struct obstack *obstack;
+
+ /* The bcache we should use to hold macro names, argument names, and
+ definitions, or zero if we should use xmalloc. */
+ struct bcache *bcache;
+
+ /* The main source file for this compilation unit --- the one whose
+ name was given to the compiler. This is the root of the
+ #inclusion tree; everything else is #included from here. */
+ struct macro_source_file *main_source;
+
+ /* The table of macro definitions. This is a splay tree (an ordered
+ binary tree that stays balanced, effectively), sorted by macro
+ name. Where a macro gets defined more than once (presumably with
+ an #undefinition in between), we sort the definitions by the
+ order they would appear in the preprocessor's output. That is,
+ if `a.c' #includes `m.h' and then #includes `n.h', and both
+ header files #define X (with an #undef somewhere in between),
+ then the definition from `m.h' appears in our splay tree before
+ the one from `n.h'.
+
+ The splay tree's keys are `struct macro_key' pointers;
+ the values are `struct macro_definition' pointers.
+
+ The splay tree, its nodes, and the keys and values are allocated
+ in obstack, if it's non-zero, or with xmalloc otherwise. The
+ macro names, argument names, argument name arrays, and definition
+ strings are all allocated in bcache, if non-zero, or with xmalloc
+ otherwise. */
+ splay_tree definitions;
+};
+
+
+
+/* Allocation and freeing functions. */
+
+/* Allocate SIZE bytes of memory appropriately for the macro table T.
+ This just checks whether T has an obstack, or whether its pieces
+ should be allocated with xmalloc. */
+static void *
+macro_alloc (int size, struct macro_table *t)
+{
+ if (t->obstack)
+ return obstack_alloc (t->obstack, size);
+ else
+ return xmalloc (size);
+}
+
+
+static void
+macro_free (void *object, struct macro_table *t)
+{
+ gdb_assert (! t->obstack);
+ xfree (object);
+}
+
+
+/* If the macro table T has a bcache, then cache the LEN bytes at ADDR
+ there, and return the cached copy. Otherwise, just xmalloc a copy
+ of the bytes, and return a pointer to that. */
+static const void *
+macro_bcache (struct macro_table *t, const void *addr, int len)
+{
+ if (t->bcache)
+ return bcache (addr, len, t->bcache);
+ else
+ {
+ void *copy = xmalloc (len);
+ memcpy (copy, addr, len);
+ return copy;
+ }
+}
+
+
+/* If the macro table T has a bcache, cache the null-terminated string
+ S there, and return a pointer to the cached copy. Otherwise,
+ xmalloc a copy and return that. */
+static const char *
+macro_bcache_str (struct macro_table *t, const char *s)
+{
+ return (char *) macro_bcache (t, s, strlen (s) + 1);
+}
+
+
+/* Free a possibly bcached object OBJ. That is, if the macro table T
+ has a bcache, it's an error; otherwise, xfree OBJ. */
+static void
+macro_bcache_free (struct macro_table *t, void *obj)
+{
+ gdb_assert (! t->bcache);
+ xfree (obj);
+}
+
+
+
+/* Macro tree keys, w/their comparison, allocation, and freeing functions. */
+
+/* A key in the splay tree. */
+struct macro_key
+{
+ /* The table we're in. We only need this in order to free it, since
+ the splay tree library's key and value freeing functions require
+ that the key or value contain all the information needed to free
+ themselves. */
+ struct macro_table *table;
+
+ /* The name of the macro. This is in the table's bcache, if it has
+ one. */
+ const char *name;
+
+ /* The source file and line number where the definition's scope
+ begins. This is also the line of the definition itself. */
+ struct macro_source_file *start_file;
+ int start_line;
+
+ /* The first source file and line after the definition's scope.
+ (That is, the scope does not include this endpoint.) If end_file
+ is zero, then the definition extends to the end of the
+ compilation unit. */
+ struct macro_source_file *end_file;
+ int end_line;
+};
+
+
+/* Return the #inclusion depth of the source file FILE. This is the
+ number of #inclusions it took to reach this file. For the main
+ source file, the #inclusion depth is zero; for a file it #includes
+ directly, the depth would be one; and so on. */
+static int
+inclusion_depth (struct macro_source_file *file)
+{
+ int depth;
+
+ for (depth = 0; file->included_by; depth++)
+ file = file->included_by;
+
+ return depth;
+}
+
+
+/* Compare two source locations (from the same compilation unit).
+ This is part of the comparison function for the tree of
+ definitions.
+
+ LINE1 and LINE2 are line numbers in the source files FILE1 and
+ FILE2. Return a value:
+ - less than zero if {LINE,FILE}1 comes before {LINE,FILE}2,
+ - greater than zero if {LINE,FILE}1 comes after {LINE,FILE}2, or
+ - zero if they are equal.
+
+ When the two locations are in different source files --- perhaps
+ one is in a header, while another is in the main source file --- we
+ order them by where they would appear in the fully pre-processed
+ sources, where all the #included files have been substituted into
+ their places. */
+static int
+compare_locations (struct macro_source_file *file1, int line1,
+ struct macro_source_file *file2, int line2)
+{
+ /* We want to treat positions in an #included file as coming *after*
+ the line containing the #include, but *before* the line after the
+ include. As we walk up the #inclusion tree toward the main
+ source file, we update fileX and lineX as we go; includedX
+ indicates whether the original position was from the #included
+ file. */
+ int included1 = 0;
+ int included2 = 0;
+
+ /* If a file is zero, that means "end of compilation unit." Handle
+ that specially. */
+ if (! file1)
+ {
+ if (! file2)
+ return 0;
+ else
+ return 1;
+ }
+ else if (! file2)
+ return -1;
+
+ /* If the two files are not the same, find their common ancestor in
+ the #inclusion tree. */
+ if (file1 != file2)
+ {
+ /* If one file is deeper than the other, walk up the #inclusion
+ chain until the two files are at least at the same *depth*.
+ Then, walk up both files in synchrony until they're the same
+ file. That file is the common ancestor. */
+ int depth1 = inclusion_depth (file1);
+ int depth2 = inclusion_depth (file2);
+
+ /* Only one of these while loops will ever execute in any given
+ case. */
+ while (depth1 > depth2)
+ {
+ line1 = file1->included_at_line;
+ file1 = file1->included_by;
+ included1 = 1;
+ depth1--;
+ }
+ while (depth2 > depth1)
+ {
+ line2 = file2->included_at_line;
+ file2 = file2->included_by;
+ included2 = 1;
+ depth2--;
+ }
+
+ /* Now both file1 and file2 are at the same depth. Walk toward
+ the root of the tree until we find where the branches meet. */
+ while (file1 != file2)
+ {
+ line1 = file1->included_at_line;
+ file1 = file1->included_by;
+ /* At this point, we know that the case the includedX flags
+ are trying to deal with won't come up, but we'll just
+ maintain them anyway. */
+ included1 = 1;
+
+ line2 = file2->included_at_line;
+ file2 = file2->included_by;
+ included2 = 1;
+
+ /* Sanity check. If file1 and file2 are really from the
+ same compilation unit, then they should both be part of
+ the same tree, and this shouldn't happen. */
+ gdb_assert (file1 && file2);
+ }
+ }
+
+ /* Now we've got two line numbers in the same file. */
+ if (line1 == line2)
+ {
+ /* They can't both be from #included files. Then we shouldn't
+ have walked up this far. */
+ gdb_assert (! included1 || ! included2);
+
+ /* Any #included position comes after a non-#included position
+ with the same line number in the #including file. */
+ if (included1)
+ return 1;
+ else if (included2)
+ return -1;
+ else
+ return 0;
+ }
+ else
+ return line1 - line2;
+}
+
+
+/* Compare a macro key KEY against NAME, the source file FILE, and
+ line number LINE.
+
+ Sort definitions by name; for two definitions with the same name,
+ place the one whose definition comes earlier before the one whose
+ definition comes later.
+
+ Return -1, 0, or 1 if key comes before, is identical to, or comes
+ after NAME, FILE, and LINE. */
+static int
+key_compare (struct macro_key *key,
+ const char *name, struct macro_source_file *file, int line)
+{
+ int names = strcmp (key->name, name);
+ if (names)
+ return names;
+
+ return compare_locations (key->start_file, key->start_line,
+ file, line);
+}
+
+
+/* The macro tree comparison function, typed for the splay tree
+ library's happiness. */
+static int
+macro_tree_compare (splay_tree_key untyped_key1,
+ splay_tree_key untyped_key2)
+{
+ struct macro_key *key1 = (struct macro_key *) untyped_key1;
+ struct macro_key *key2 = (struct macro_key *) untyped_key2;
+
+ return key_compare (key1, key2->name, key2->start_file, key2->start_line);
+}
+
+
+/* Construct a new macro key node for a macro in table T whose name is
+ NAME, and whose scope starts at LINE in FILE; register the name in
+ the bcache. */
+static struct macro_key *
+new_macro_key (struct macro_table *t,
+ const char *name,
+ struct macro_source_file *file,
+ int line)
+{
+ struct macro_key *k = macro_alloc (sizeof (*k), t);
+
+ memset (k, 0, sizeof (*k));
+ k->table = t;
+ k->name = macro_bcache_str (t, name);
+ k->start_file = file;
+ k->start_line = line;
+ k->end_file = 0;
+
+ return k;
+}
+
+
+static void
+macro_tree_delete_key (void *untyped_key)
+{
+ struct macro_key *key = (struct macro_key *) untyped_key;
+
+ macro_bcache_free (key->table, (char *) key->name);
+ macro_free (key, key->table);
+}
+
+
+
+/* Building and querying the tree of #included files. */
+
+
+/* Allocate and initialize a new source file structure. */
+static struct macro_source_file *
+new_source_file (struct macro_table *t,
+ const char *filename)
+{
+ /* Get space for the source file structure itself. */
+ struct macro_source_file *f = macro_alloc (sizeof (*f), t);
+
+ memset (f, 0, sizeof (*f));
+ f->table = t;
+ f->filename = macro_bcache_str (t, filename);
+ f->includes = 0;
+
+ return f;
+}
+
+
+/* Free a source file, and all the source files it #included. */
+static void
+free_macro_source_file (struct macro_source_file *src)
+{
+ struct macro_source_file *child, *next_child;
+
+ /* Free this file's children. */
+ for (child = src->includes; child; child = next_child)
+ {
+ next_child = child->next_included;
+ free_macro_source_file (child);
+ }
+
+ macro_bcache_free (src->table, (char *) src->filename);
+ macro_free (src, src->table);
+}
+
+
+struct macro_source_file *
+macro_set_main (struct macro_table *t,
+ const char *filename)
+{
+ /* You can't change a table's main source file. What would that do
+ to the tree? */
+ gdb_assert (! t->main_source);
+
+ t->main_source = new_source_file (t, filename);
+
+ return t->main_source;
+}
+
+
+struct macro_source_file *
+macro_main (struct macro_table *t)
+{
+ gdb_assert (t->main_source);
+
+ return t->main_source;
+}
+
+
+struct macro_source_file *
+macro_include (struct macro_source_file *source,
+ int line,
+ const char *included)
+{
+ struct macro_source_file *new;
+ struct macro_source_file **link;
+
+ /* Find the right position in SOURCE's `includes' list for the new
+ file. Skip inclusions at earlier lines, until we find one at the
+ same line or later --- or until the end of the list. */
+ for (link = &source->includes;
+ *link && (*link)->included_at_line < line;
+ link = &(*link)->next_included)
+ ;
+
+ /* Did we find another file already #included at the same line as
+ the new one? */
+ if (*link && line == (*link)->included_at_line)
+ {
+ /* This means the compiler is emitting bogus debug info. (GCC
+ circa March 2002 did this.) It also means that the splay
+ tree ordering function, macro_tree_compare, will abort,
+ because it can't tell which #inclusion came first. But GDB
+ should tolerate bad debug info. So:
+
+ First, squawk. */
+ complaint (&symfile_complaints,
+ "both `%s' and `%s' allegedly #included at %s:%d", included,
+ (*link)->filename, source->filename, line);
+
+ /* Now, choose a new, unoccupied line number for this
+ #inclusion, after the alleged #inclusion line. */
+ while (*link && line == (*link)->included_at_line)
+ {
+ /* This line number is taken, so try the next line. */
+ line++;
+ link = &(*link)->next_included;
+ }
+ }
+
+ /* At this point, we know that LINE is an unused line number, and
+ *LINK points to the entry an #inclusion at that line should
+ precede. */
+ new = new_source_file (source->table, included);
+ new->included_by = source;
+ new->included_at_line = line;
+ new->next_included = *link;
+ *link = new;
+
+ return new;
+}
+
+
+struct macro_source_file *
+macro_lookup_inclusion (struct macro_source_file *source, const char *name)
+{
+ /* Is SOURCE itself named NAME? */
+ if (strcmp (name, source->filename) == 0)
+ return source;
+
+ /* The filename in the source structure is probably a full path, but
+ NAME could be just the final component of the name. */
+ {
+ int name_len = strlen (name);
+ int src_name_len = strlen (source->filename);
+
+ /* We do mean < here, and not <=; if the lengths are the same,
+ then the strcmp above should have triggered, and we need to
+ check for a slash here. */
+ if (name_len < src_name_len
+ && source->filename[src_name_len - name_len - 1] == '/'
+ && strcmp (name, source->filename + src_name_len - name_len) == 0)
+ return source;
+ }
+
+ /* It's not us. Try all our children, and return the lowest. */
+ {
+ struct macro_source_file *child;
+ struct macro_source_file *best = NULL;
+ int best_depth = 0;
+
+ for (child = source->includes; child; child = child->next_included)
+ {
+ struct macro_source_file *result
+ = macro_lookup_inclusion (child, name);
+
+ if (result)
+ {
+ int result_depth = inclusion_depth (result);
+
+ if (! best || result_depth < best_depth)
+ {
+ best = result;
+ best_depth = result_depth;
+ }
+ }
+ }
+
+ return best;
+ }
+}
+
+
+
+/* Registering and looking up macro definitions. */
+
+
+/* Construct a definition for a macro in table T. Cache all strings,
+ and the macro_definition structure itself, in T's bcache. */
+static struct macro_definition *
+new_macro_definition (struct macro_table *t,
+ enum macro_kind kind,
+ int argc, const char **argv,
+ const char *replacement)
+{
+ struct macro_definition *d = macro_alloc (sizeof (*d), t);
+
+ memset (d, 0, sizeof (*d));
+ d->table = t;
+ d->kind = kind;
+ d->replacement = macro_bcache_str (t, replacement);
+
+ if (kind == macro_function_like)
+ {
+ int i;
+ const char **cached_argv;
+ int cached_argv_size = argc * sizeof (*cached_argv);
+
+ /* Bcache all the arguments. */
+ cached_argv = alloca (cached_argv_size);
+ for (i = 0; i < argc; i++)
+ cached_argv[i] = macro_bcache_str (t, argv[i]);
+
+ /* Now bcache the array of argument pointers itself. */
+ d->argv = macro_bcache (t, cached_argv, cached_argv_size);
+ d->argc = argc;
+ }
+
+ /* We don't bcache the entire definition structure because it's got
+ a pointer to the macro table in it; since each compilation unit
+ has its own macro table, you'd only get bcache hits for identical
+ definitions within a compilation unit, which seems unlikely.
+
+ "So, why do macro definitions have pointers to their macro tables
+ at all?" Well, when the splay tree library wants to free a
+ node's value, it calls the value freeing function with nothing
+ but the value itself. It makes the (apparently reasonable)
+ assumption that the value carries enough information to free
+ itself. But not all macro tables have bcaches, so not all macro
+ definitions would be bcached. There's no way to tell whether a
+ given definition is bcached without knowing which table the
+ definition belongs to. ... blah. The thing's only sixteen
+ bytes anyway, and we can still bcache the name, args, and
+ definition, so we just don't bother bcaching the definition
+ structure itself. */
+ return d;
+}
+
+
+/* Free a macro definition. */
+static void
+macro_tree_delete_value (void *untyped_definition)
+{
+ struct macro_definition *d = (struct macro_definition *) untyped_definition;
+ struct macro_table *t = d->table;
+
+ if (d->kind == macro_function_like)
+ {
+ int i;
+
+ for (i = 0; i < d->argc; i++)
+ macro_bcache_free (t, (char *) d->argv[i]);
+ macro_bcache_free (t, (char **) d->argv);
+ }
+
+ macro_bcache_free (t, (char *) d->replacement);
+ macro_free (d, t);
+}
+
+
+/* Find the splay tree node for the definition of NAME at LINE in
+ SOURCE, or zero if there is none. */
+static splay_tree_node
+find_definition (const char *name,
+ struct macro_source_file *file,
+ int line)
+{
+ struct macro_table *t = file->table;
+ splay_tree_node n;
+
+ /* Construct a macro_key object, just for the query. */
+ struct macro_key query;
+
+ query.name = name;
+ query.start_file = file;
+ query.start_line = line;
+ query.end_file = NULL;
+
+ n = splay_tree_lookup (t->definitions, (splay_tree_key) &query);
+ if (! n)
+ {
+ /* It's okay for us to do two queries like this: the real work
+ of the searching is done when we splay, and splaying the tree
+ a second time at the same key is a constant time operation.
+ If this still bugs you, you could always just extend the
+ splay tree library with a predecessor-or-equal operation, and
+ use that. */
+ splay_tree_node pred = splay_tree_predecessor (t->definitions,
+ (splay_tree_key) &query);
+
+ if (pred)
+ {
+ /* Make sure this predecessor actually has the right name.
+ We just want to search within a given name's definitions. */
+ struct macro_key *found = (struct macro_key *) pred->key;
+
+ if (strcmp (found->name, name) == 0)
+ n = pred;
+ }
+ }
+
+ if (n)
+ {
+ struct macro_key *found = (struct macro_key *) n->key;
+
+ /* Okay, so this definition has the right name, and its scope
+ begins before the given source location. But does its scope
+ end after the given source location? */
+ if (compare_locations (file, line, found->end_file, found->end_line) < 0)
+ return n;
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+
+/* If NAME already has a definition in scope at LINE in SOURCE, return
+ the key. If the old definition is different from the definition
+ given by KIND, ARGC, ARGV, and REPLACEMENT, complain, too.
+ Otherwise, return zero. (ARGC and ARGV are meaningless unless KIND
+ is `macro_function_like'.) */
+static struct macro_key *
+check_for_redefinition (struct macro_source_file *source, int line,
+ const char *name, enum macro_kind kind,
+ int argc, const char **argv,
+ const char *replacement)
+{
+ splay_tree_node n = find_definition (name, source, line);
+
+ if (n)
+ {
+ struct macro_key *found_key = (struct macro_key *) n->key;
+ struct macro_definition *found_def
+ = (struct macro_definition *) n->value;
+ int same = 1;
+
+ /* Is this definition the same as the existing one?
+ According to the standard, this comparison needs to be done
+ on lists of tokens, not byte-by-byte, as we do here. But
+ that's too hard for us at the moment, and comparing
+ byte-by-byte will only yield false negatives (i.e., extra
+ warning messages), not false positives (i.e., unnoticed
+ definition changes). */
+ if (kind != found_def->kind)
+ same = 0;
+ else if (strcmp (replacement, found_def->replacement))
+ same = 0;
+ else if (kind == macro_function_like)
+ {
+ if (argc != found_def->argc)
+ same = 0;
+ else
+ {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ if (strcmp (argv[i], found_def->argv[i]))
+ same = 0;
+ }
+ }
+
+ if (! same)
+ {
+ complaint (&symfile_complaints,
+ "macro `%s' redefined at %s:%d; original definition at %s:%d",
+ name, source->filename, line,
+ found_key->start_file->filename, found_key->start_line);
+ }
+
+ return found_key;
+ }
+ else
+ return 0;
+}
+
+
+void
+macro_define_object (struct macro_source_file *source, int line,
+ const char *name, const char *replacement)
+{
+ struct macro_table *t = source->table;
+ struct macro_key *k;
+ struct macro_definition *d;
+
+ k = check_for_redefinition (source, line,
+ name, macro_object_like,
+ 0, 0,
+ replacement);
+
+ /* If we're redefining a symbol, and the existing key would be
+ identical to our new key, then the splay_tree_insert function
+ will try to delete the old definition. When the definition is
+ living on an obstack, this isn't a happy thing.
+
+ Since this only happens in the presence of questionable debug
+ info, we just ignore all definitions after the first. The only
+ case I know of where this arises is in GCC's output for
+ predefined macros, and all the definitions are the same in that
+ case. */
+ if (k && ! key_compare (k, name, source, line))
+ return;
+
+ k = new_macro_key (t, name, source, line);
+ d = new_macro_definition (t, macro_object_like, 0, 0, replacement);
+ splay_tree_insert (t->definitions, (splay_tree_key) k, (splay_tree_value) d);
+}
+
+
+void
+macro_define_function (struct macro_source_file *source, int line,
+ const char *name, int argc, const char **argv,
+ const char *replacement)
+{
+ struct macro_table *t = source->table;
+ struct macro_key *k;
+ struct macro_definition *d;
+
+ k = check_for_redefinition (source, line,
+ name, macro_function_like,
+ argc, argv,
+ replacement);
+
+ /* See comments about duplicate keys in macro_define_object. */
+ if (k && ! key_compare (k, name, source, line))
+ return;
+
+ /* We should also check here that all the argument names in ARGV are
+ distinct. */
+
+ k = new_macro_key (t, name, source, line);
+ d = new_macro_definition (t, macro_function_like, argc, argv, replacement);
+ splay_tree_insert (t->definitions, (splay_tree_key) k, (splay_tree_value) d);
+}
+
+
+void
+macro_undef (struct macro_source_file *source, int line,
+ const char *name)
+{
+ splay_tree_node n = find_definition (name, source, line);
+
+ if (n)
+ {
+ /* This function is the only place a macro's end-of-scope
+ location gets set to anything other than "end of the
+ compilation unit" (i.e., end_file is zero). So if this macro
+ already has its end-of-scope set, then we're probably seeing
+ a second #undefinition for the same #definition. */
+ struct macro_key *key = (struct macro_key *) n->key;
+
+ if (key->end_file)
+ {
+ complaint (&symfile_complaints,
+ "macro '%s' is #undefined twice, at %s:%d and %s:%d", name,
+ source->filename, line, key->end_file->filename,
+ key->end_line);
+ }
+
+ /* Whatever the case, wipe out the old ending point, and
+ make this the ending point. */
+ key->end_file = source;
+ key->end_line = line;
+ }
+ else
+ {
+ /* According to the ISO C standard, an #undef for a symbol that
+ has no macro definition in scope is ignored. So we should
+ ignore it too. */
+#if 0
+ complaint (&symfile_complaints,
+ "no definition for macro `%s' in scope to #undef at %s:%d",
+ name, source->filename, line);
+#endif
+ }
+}
+
+
+struct macro_definition *
+macro_lookup_definition (struct macro_source_file *source,
+ int line, const char *name)
+{
+ splay_tree_node n = find_definition (name, source, line);
+
+ if (n)
+ return (struct macro_definition *) n->value;
+ else
+ return 0;
+}
+
+
+struct macro_source_file *
+macro_definition_location (struct macro_source_file *source,
+ int line,
+ const char *name,
+ int *definition_line)
+{
+ splay_tree_node n = find_definition (name, source, line);
+
+ if (n)
+ {
+ struct macro_key *key = (struct macro_key *) n->key;
+ *definition_line = key->start_line;
+ return key->start_file;
+ }
+ else
+ return 0;
+}
+
+
+
+/* Creating and freeing macro tables. */
+
+
+struct macro_table *
+new_macro_table (struct obstack *obstack,
+ struct bcache *b)
+{
+ struct macro_table *t;
+
+ /* First, get storage for the `struct macro_table' itself. */
+ if (obstack)
+ t = obstack_alloc (obstack, sizeof (*t));
+ else
+ t = xmalloc (sizeof (*t));
+
+ memset (t, 0, sizeof (*t));
+ t->obstack = obstack;
+ t->bcache = b;
+ t->main_source = NULL;
+ t->definitions = (splay_tree_new_with_allocator
+ (macro_tree_compare,
+ ((splay_tree_delete_key_fn) macro_tree_delete_key),
+ ((splay_tree_delete_value_fn) macro_tree_delete_value),
+ ((splay_tree_allocate_fn) macro_alloc),
+ ((splay_tree_deallocate_fn) macro_free),
+ t));
+
+ return t;
+}
+
+
+void
+free_macro_table (struct macro_table *table)
+{
+ /* Free the source file tree. */
+ free_macro_source_file (table->main_source);
+
+ /* Free the table of macro definitions. */
+ splay_tree_delete (table->definitions);
+}
diff --git a/contrib/gdb/gdb/macrotab.h b/contrib/gdb/gdb/macrotab.h
new file mode 100644
index 0000000..bd44e2c
--- /dev/null
+++ b/contrib/gdb/gdb/macrotab.h
@@ -0,0 +1,304 @@
+/* Interface to C preprocessor macro tables for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MACROTAB_H
+#define MACROTAB_H
+
+struct obstack;
+struct bcache;
+
+/* How do we represent a source location? I mean, how should we
+ represent them within GDB; the user wants to use all sorts of
+ ambiguous abbreviations, like "break 32" and "break foo.c:32"
+ ("foo.c" may have been #included into several compilation units),
+ but what do we disambiguate those things to?
+
+ - Answer 1: "Filename and line number." (Or column number, if
+ you're picky.) That's not quite good enough. For example, the
+ same source file can be #included into several different
+ compilation units --- which #inclusion do you mean?
+
+ - Answer 2: "Compilation unit, filename, and line number." This is
+ a pretty good answer; GDB's `struct symtab_and_line' basically
+ embodies this representation. But it's still ambiguous; what if a
+ given compilation unit #includes the same file twice --- how can I
+ set a breakpoint on line 12 of the fifth #inclusion of "foo.c"?
+
+ - Answer 3: "Compilation unit, chain of #inclusions, and line
+ number." This is analogous to the way GCC reports errors in
+ #include files:
+
+ $ gcc -c base.c
+ In file included from header2.h:8,
+ from header1.h:3,
+ from base.c:5:
+ header3.h:1: parse error before ')' token
+ $
+
+ GCC tells you exactly what path of #inclusions led you to the
+ problem. It gives you complete information, in a way that the
+ following would not:
+
+ $ gcc -c base.c
+ header3.h:1: parse error before ')' token
+ $
+
+ Converting all of GDB to use this is a big task, and I'm not really
+ suggesting it should be a priority. But this module's whole
+ purpose is to maintain structures describing the macro expansion
+ process, so I think it's appropriate for us to take a little care
+ to do that in a complete fashion.
+
+ In this interface, the first line of a file is numbered 1, not 0.
+ This is the same convention the rest of GDB uses. */
+
+
+/* A table of all the macro definitions for a given compilation unit. */
+struct macro_table;
+
+
+/* A source file that participated in a compilation unit --- either a
+ main file, or an #included file. If a file is #included more than
+ once, the presence of the `included_from' and `included_at_line'
+ members means that we need to make one instance of this structure
+ for each #inclusion. Taken as a group, these structures form a
+ tree mapping the #inclusions that contributed to the compilation
+ unit, with the main source file as its root.
+
+ Beware --- not every source file mentioned in a compilation unit's
+ symtab structures will appear in the #inclusion tree! As of Oct
+ 2002, GCC does record the effect of #line directives in the source
+ line info, but not in macro info. This means that GDB's symtabs
+ (built from the former, among other things) may mention filenames
+ that the #inclusion tree (built from the latter) doesn't have any
+ record of. See macroscope.c:sal_macro_scope for how to accomodate
+ this.
+
+ It's worth noting that libcpp has a simpler way of representing all
+ this, which we should consider switching to. It might even be
+ suitable for ordinary non-macro line number info.
+
+ Suppose you take your main source file, and after each line
+ containing an #include directive you insert the text of the
+ #included file. The result is a big file that pretty much
+ corresponds to the full text the compiler's going to see. There's
+ a one-to-one correspondence between lines in the big file and
+ per-inclusion lines in the source files. (Obviously, #include
+ directives that are #if'd out don't count. And you'll need to
+ append a newline to any file that doesn't end in one, to avoid
+ splicing the last #included line with the next line of the
+ #including file.)
+
+ Libcpp calls line numbers in this big imaginary file "logical line
+ numbers", and has a data structure called a "line map" that can map
+ logical line numbers onto actual source filenames and line numbers,
+ and also tell you the chain of #inclusions responsible for any
+ particular logical line number. Basically, this means you can pass
+ around a single line number and some kind of "compilation unit"
+ object and you get nice, unambiguous source code locations that
+ distinguish between multiple #inclusions of the same file, etc.
+
+ Pretty neat, huh? */
+
+struct macro_source_file
+{
+
+ /* The macro table for the compilation unit this source location is
+ a part of. */
+ struct macro_table *table;
+
+ /* A source file --- possibly a header file. */
+ const char *filename;
+
+ /* The location we were #included from, or zero if we are the
+ compilation unit's main source file. */
+ struct macro_source_file *included_by;
+
+ /* If `included_from' is non-zero, the line number in that source
+ file at which we were included. */
+ int included_at_line;
+
+ /* Head of a linked list of the source files #included by this file;
+ our children in the #inclusion tree. This list is sorted by its
+ elements' `included_at_line' values, which are unique. (The
+ macro splay tree's ordering function needs this property.) */
+ struct macro_source_file *includes;
+
+ /* The next file #included by our `included_from' file; our sibling
+ in the #inclusion tree. */
+ struct macro_source_file *next_included;
+};
+
+
+/* Create a new, empty macro table. Allocate it in OBSTACK, or use
+ xmalloc if OBSTACK is zero. Use BCACHE to store all macro names,
+ arguments, definitions, and anything else that might be the same
+ amongst compilation units in an executable file; if BCACHE is zero,
+ don't cache these things.
+
+ Note that, if either OBSTACK or BCACHE are non-zero, then you
+ should only ever add information the macro table --- you should
+ never remove things from it. You'll get an error if you try. At
+ the moment, since we only provide obstacks and bcaches for macro
+ tables for symtabs, this restriction makes a nice sanity check.
+ Obstacks and bcaches are pretty much grow-only structures anyway.
+ However, if we find that it's occasionally useful to delete things
+ even from the symtab's tables, and the storage leak isn't a
+ problem, this restriction could be lifted. */
+struct macro_table *new_macro_table (struct obstack *obstack,
+ struct bcache *bcache);
+
+
+/* Free TABLE, and any macro definitions, source file structures,
+ etc. it owns. This will raise an internal error if TABLE was
+ allocated on an obstack, or if it uses a bcache. */
+void free_macro_table (struct macro_table *table);
+
+
+/* Set FILENAME as the main source file of TABLE. Return a source
+ file structure describing that file; if we record the #definition
+ of macros, or the #inclusion of other files into FILENAME, we'll
+ use that source file structure to indicate the context.
+
+ The "main source file" is the one that was given to the compiler;
+ all other source files that contributed to the compilation unit are
+ #included, directly or indirectly, from this one.
+
+ The macro table makes its own copy of FILENAME; the caller is
+ responsible for freeing FILENAME when it is no longer needed. */
+struct macro_source_file *macro_set_main (struct macro_table *table,
+ const char *filename);
+
+
+/* Return the main source file of the macro table TABLE. */
+struct macro_source_file *macro_main (struct macro_table *table);
+
+
+/* Record a #inclusion.
+ Record in SOURCE's macro table that, at line number LINE in SOURCE,
+ we #included the file INCLUDED. Return a source file structure we
+ can use for symbols #defined or files #included into that. If we've
+ already created a source file structure for this #inclusion, return
+ the same structure we created last time.
+
+ The first line of the source file has a line number of 1, not 0.
+
+ The macro table makes its own copy of INCLUDED; the caller is
+ responsible for freeing INCLUDED when it is no longer needed. */
+struct macro_source_file *macro_include (struct macro_source_file *source,
+ int line,
+ const char *included);
+
+
+/* Find any source file structure for a file named NAME, either
+ included into SOURCE, or SOURCE itself. Return zero if we have
+ none. NAME is only the final portion of the filename, not the full
+ path. e.g., `stdio.h', not `/usr/include/stdio.h'. If NAME
+ appears more than once in the inclusion tree, return the
+ least-nested inclusion --- the one closest to the main source file. */
+struct macro_source_file *(macro_lookup_inclusion
+ (struct macro_source_file *source,
+ const char *name));
+
+
+/* Record an object-like #definition (i.e., one with no parameter list).
+ Record in SOURCE's macro table that, at line number LINE in SOURCE,
+ we #defined a preprocessor symbol named NAME, whose replacement
+ string is REPLACEMENT. This function makes copies of NAME and
+ REPLACEMENT; the caller is responsible for freeing them. */
+void macro_define_object (struct macro_source_file *source, int line,
+ const char *name, const char *replacement);
+
+
+/* Record an function-like #definition (i.e., one with a parameter list).
+
+ Record in SOURCE's macro table that, at line number LINE in SOURCE,
+ we #defined a preprocessor symbol named NAME, with ARGC arguments
+ whose names are given in ARGV, whose replacement string is REPLACEMENT. If
+ the macro takes a variable number of arguments, then ARGC should be
+ one greater than the number of named arguments, and ARGV[ARGC-1]
+ should be the string "...". This function makes its own copies of
+ NAME, ARGV, and REPLACEMENT; the caller is responsible for freeing
+ them. */
+void macro_define_function (struct macro_source_file *source, int line,
+ const char *name, int argc, const char **argv,
+ const char *replacement);
+
+
+/* Record an #undefinition.
+ Record in SOURCE's macro table that, at line number LINE in SOURCE,
+ we removed the definition for the preprocessor symbol named NAME. */
+void macro_undef (struct macro_source_file *source, int line,
+ const char *name);
+
+
+/* Different kinds of macro definitions. */
+enum macro_kind
+{
+ macro_object_like,
+ macro_function_like
+};
+
+
+/* A preprocessor symbol definition. */
+struct macro_definition
+{
+ /* The table this definition lives in. */
+ struct macro_table *table;
+
+ /* What kind of macro it is. */
+ enum macro_kind kind;
+
+ /* If `kind' is `macro_function_like', the number of arguments it
+ takes, and their names. The names, and the array of pointers to
+ them, are in the table's bcache, if it has one. */
+ int argc;
+ const char * const *argv;
+
+ /* The replacement string (body) of the macro. This is in the
+ table's bcache, if it has one. */
+ const char *replacement;
+};
+
+
+/* Return a pointer to the macro definition for NAME in scope at line
+ number LINE of SOURCE. If LINE is -1, return the definition in
+ effect at the end of the file. The macro table owns the structure;
+ the caller need not free it. Return zero if NAME is not #defined
+ at that point. */
+struct macro_definition *(macro_lookup_definition
+ (struct macro_source_file *source,
+ int line, const char *name));
+
+
+/* Return the source location of the definition for NAME in scope at
+ line number LINE of SOURCE. Set *DEFINITION_LINE to the line
+ number of the definition, and return a source file structure for
+ the file. Return zero if NAME has no definition in scope at that
+ point, and leave *DEFINITION_LINE unchanged. */
+struct macro_source_file *(macro_definition_location
+ (struct macro_source_file *source,
+ int line,
+ const char *name,
+ int *definition_line));
+
+
+#endif /* MACROTAB_H */
diff --git a/contrib/gdb/gdb/main.c b/contrib/gdb/gdb/main.c
new file mode 100644
index 0000000..7385cfd
--- /dev/null
+++ b/contrib/gdb/gdb/main.c
@@ -0,0 +1,890 @@
+/* Top level stuff for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "top.h"
+#include "target.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "gdbcore.h"
+
+#include "getopt.h"
+
+#include <sys/types.h>
+#include "gdb_stat.h"
+#include <ctype.h>
+
+#include "gdb_string.h"
+#include "event-loop.h"
+#include "ui-out.h"
+
+#include "interps.h"
+#include "main.h"
+
+/* 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;
+
+/* Whether this is the async version or not. The async version is
+ invoked on the command line with the -nw --async options. In this
+ version, the usual command_loop is substituted by and event loop which
+ processes UI events asynchronously. */
+int event_loop_p = 1;
+
+/* The selected interpreter. This will be used as a set command
+ variable, so it should always be malloc'ed - since
+ do_setshow_command will free it. */
+char *interpreter_p;
+
+/* Whether xdb commands will be handled */
+int xdb_commands = 0;
+
+/* Whether dbx commands will be handled */
+int dbx_commands = 0;
+
+/* System root path, used to find libraries etc. */
+char *gdb_sysroot = 0;
+
+struct ui_file *gdb_stdout;
+struct ui_file *gdb_stderr;
+struct ui_file *gdb_stdlog;
+struct ui_file *gdb_stdin;
+/* target IO streams */
+struct ui_file *gdb_stdtargin;
+struct ui_file *gdb_stdtarg;
+struct ui_file *gdb_stdtargerr;
+
+/* Whether to enable writing into executable and core files */
+extern int write_files;
+
+static void print_gdb_help (struct ui_file *);
+
+/* These two are used to set the external editor commands when gdb is farming
+ out files to be edited by another program. */
+
+extern char *external_editor_command;
+
+/* Call command_loop. If it happens to return, pass that through as a
+ non-zero return status. */
+
+static int
+captured_command_loop (void *data)
+{
+ current_interp_command_loop ();
+ /* FIXME: cagney/1999-11-05: A correct command_loop() implementaton
+ would clean things up (restoring the cleanup chain) to the state
+ they were just prior to the call. Technically, this means that
+ the do_cleanups() below is redundant. Unfortunately, many FUNCs
+ are not that well behaved. do_cleanups should either be replaced
+ with a do_cleanups call (to cover the problem) or an assertion
+ check to detect bad FUNCs code. */
+ do_cleanups (ALL_CLEANUPS);
+ /* If the command_loop returned, normally (rather than threw an
+ error) we try to quit. If the quit is aborted, catch_errors()
+ which called this catch the signal and restart the command
+ loop. */
+ quit_command (NULL, instream == stdin);
+ return 1;
+}
+
+static int
+captured_main (void *data)
+{
+ struct captured_main_args *context = data;
+ int argc = context->argc;
+ char **argv = context->argv;
+ int count;
+ static int quiet = 0;
+ static int batch = 0;
+ static int set_args = 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;
+
+ int i;
+
+ long time_at_startup = get_run_time ();
+
+#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
+ setlocale (LC_MESSAGES, "");
+#endif
+#if defined (HAVE_SETLOCALE)
+ setlocale (LC_CTYPE, "");
+#endif
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* This needs to happen before the first use of malloc. */
+ init_malloc (NULL);
+
+#ifdef HAVE_SBRK
+ lim_at_start = (char *) sbrk (0);
+#endif
+
+#if defined (ALIGN_STACK_ON_STARTUP)
+ i = (int) &count & 0x3;
+ if (i != 0)
+ alloca (4 - i);
+#endif
+
+ 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;
+
+ gdb_stdout = stdio_fileopen (stdout);
+ gdb_stderr = stdio_fileopen (stderr);
+ gdb_stdlog = gdb_stderr; /* for moment */
+ gdb_stdtarg = gdb_stderr; /* for moment */
+ gdb_stdin = stdio_fileopen (stdin);
+ gdb_stdtargerr = gdb_stderr; /* for moment */
+ gdb_stdtargin = gdb_stdin; /* for moment */
+
+ /* initialize error() */
+ error_init ();
+
+ /* Set the sysroot path. */
+#ifdef TARGET_SYSTEM_ROOT_RELOCATABLE
+ gdb_sysroot = make_relative_prefix (argv[0], BINDIR, TARGET_SYSTEM_ROOT);
+ if (gdb_sysroot)
+ {
+ struct stat s;
+ int res = 0;
+
+ if (stat (gdb_sysroot, &s) == 0)
+ if (S_ISDIR (s.st_mode))
+ res = 1;
+
+ if (res == 0)
+ {
+ xfree (gdb_sysroot);
+ gdb_sysroot = TARGET_SYSTEM_ROOT;
+ }
+ }
+ else
+ gdb_sysroot = TARGET_SYSTEM_ROOT;
+#else
+#if defined (TARGET_SYSTEM_ROOT)
+ gdb_sysroot = TARGET_SYSTEM_ROOT;
+#else
+ gdb_sysroot = "";
+#endif
+#endif
+
+ /* There will always be an interpreter. Either the one passed into
+ this captured main, or one specified by the user at start up, or
+ the console. Initialize the interpreter to the one requested by
+ the application. */
+ interpreter_p = xstrdup (context->interpreter_p);
+
+ /* Parse arguments and options. */
+ {
+ 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). */
+ enum {
+ OPT_SE = 10,
+ OPT_CD,
+ OPT_ANNOTATE,
+ OPT_STATISTICS,
+ OPT_TUI,
+ OPT_NOWINDOWS,
+ OPT_WINDOWS
+ };
+ static struct option long_options[] =
+ {
+ {"async", no_argument, &event_loop_p, 1},
+ {"noasync", no_argument, &event_loop_p, 0},
+#if defined(TUI)
+ {"tui", no_argument, 0, OPT_TUI},
+#endif
+ {"xdb", no_argument, &xdb_commands, 1},
+ {"dbx", no_argument, &dbx_commands, 1},
+ {"readnow", no_argument, &readnow_symbol_files, 1},
+ {"r", no_argument, &readnow_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, OPT_ANNOTATE},
+ {"help", no_argument, &print_help, 1},
+ {"se", required_argument, 0, OPT_SE},
+ {"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'},
+ {"pid", required_argument, 0, 'p'},
+ {"p", required_argument, 0, 'p'},
+ {"command", required_argument, 0, 'x'},
+ {"version", no_argument, &print_version, 1},
+ {"x", required_argument, 0, 'x'},
+#ifdef GDBTK
+ {"tclcommand", required_argument, 0, 'z'},
+ {"enable-external-editor", no_argument, 0, 'y'},
+ {"editor-command", required_argument, 0, 'w'},
+#endif
+ {"ui", required_argument, 0, 'i'},
+ {"interpreter", required_argument, 0, 'i'},
+ {"i", required_argument, 0, 'i'},
+ {"directory", required_argument, 0, 'd'},
+ {"d", required_argument, 0, 'd'},
+ {"cd", required_argument, 0, OPT_CD},
+ {"tty", required_argument, 0, 't'},
+ {"baud", required_argument, 0, 'b'},
+ {"b", required_argument, 0, 'b'},
+ {"nw", no_argument, NULL, OPT_NOWINDOWS},
+ {"nowindows", no_argument, NULL, OPT_NOWINDOWS},
+ {"w", no_argument, NULL, OPT_WINDOWS},
+ {"windows", no_argument, NULL, OPT_WINDOWS},
+ {"statistics", no_argument, 0, OPT_STATISTICS},
+ {"write", no_argument, &write_files, 1},
+ {"args", no_argument, &set_args, 1},
+ {0, no_argument, 0, 0}
+ };
+
+ while (1)
+ {
+ int option_index;
+
+ c = getopt_long_only (argc, argv, "",
+ long_options, &option_index);
+ if (c == EOF || set_args)
+ 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 OPT_SE:
+ symarg = optarg;
+ execarg = optarg;
+ break;
+ case OPT_CD:
+ cdarg = optarg;
+ break;
+ case OPT_ANNOTATE:
+ /* FIXME: what if the syntax is wrong (e.g. not digits)? */
+ annotation_level = atoi (optarg);
+ break;
+ case OPT_STATISTICS:
+ /* Enable the display of both time and space usage. */
+ display_time = 1;
+ display_space = 1;
+ break;
+ case OPT_TUI:
+ /* --tui is equivalent to -i=tui. */
+ xfree (interpreter_p);
+ interpreter_p = xstrdup ("tui");
+ break;
+ case OPT_WINDOWS:
+ /* FIXME: cagney/2003-03-01: Not sure if this option is
+ actually useful, and if it is, what it should do. */
+ use_windows = 1;
+ break;
+ case OPT_NOWINDOWS:
+ /* -nw is equivalent to -i=console. */
+ xfree (interpreter_p);
+ interpreter_p = xstrdup (INTERP_CONSOLE);
+ use_windows = 0;
+ 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 'p':
+ /* "corearg" is shared by "--core" and "--pid" */
+ corearg = optarg;
+ break;
+ case 'x':
+ cmdarg[ncmd++] = optarg;
+ if (ncmd >= cmdsize)
+ {
+ cmdsize *= 2;
+ cmdarg = (char **) xrealloc ((char *) cmdarg,
+ cmdsize * sizeof (*cmdarg));
+ }
+ break;
+#ifdef GDBTK
+ case 'z':
+ {
+extern int gdbtk_test (char *);
+ if (!gdbtk_test (optarg))
+ {
+ fprintf_unfiltered (gdb_stderr, _("%s: unable to load tclcommand file \"%s\""),
+ argv[0], optarg);
+ exit (1);
+ }
+ break;
+ }
+ case 'y':
+ /* Backwards compatibility only. */
+ break;
+ case 'w':
+ {
+ external_editor_command = xstrdup (optarg);
+ break;
+ }
+#endif /* GDBTK */
+ case 'i':
+ xfree (interpreter_p);
+ interpreter_p = xstrdup (optarg);
+ 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;
+ case 'l':
+ {
+ 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 timeout limit to `%s'.\n"), optarg);
+ else
+ remote_timeout = i;
+ }
+ break;
+
+ 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;
+ }
+
+ if (set_args)
+ {
+ /* The remaining options are the command-line options for the
+ inferior. The first one is the sym/exec file, and the rest
+ are arguments. */
+ if (optind >= argc)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ _("%s: `--args' specified but no program specified\n"),
+ argv[0]);
+ exit (1);
+ }
+ symarg = argv[optind];
+ execarg = argv[optind];
+ ++optind;
+ set_inferior_args_vector (argc - optind, &argv[optind]);
+ }
+ else
+ {
+ /* 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:
+ /* The documentation says this can be a "ProcID" as well.
+ We will try it as both a corefile and a pid. */
+ 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;
+ }
+
+ /* Initialize all files. Give the interpreter a chance to take
+ control of the console via the init_ui_hook()) */
+ gdb_init (argv[0]);
+
+ /* Do these (and anything which might call wrap_here or *_filtered)
+ after initialize_all_files() but before the interpreter has been
+ installed. Otherwize the help/version messages will be eaten by
+ the interpreter's output handler. */
+
+ if (print_version)
+ {
+ print_gdb_version (gdb_stdout);
+ wrap_here ("");
+ printf_filtered ("\n");
+ exit (0);
+ }
+
+ if (print_help)
+ {
+ print_gdb_help (gdb_stdout);
+ fputs_unfiltered ("\n", gdb_stdout);
+ exit (0);
+ }
+
+ /* FIXME: cagney/2003-02-03: The big hack (part 1 of 2) that lets
+ GDB retain the old MI1 interpreter startup behavior. Output the
+ copyright message before the interpreter is installed. That way
+ it isn't encapsulated in MI output. */
+ if (!quiet && strcmp (interpreter_p, INTERP_MI1) == 0)
+ {
+ /* Print all the junk at the top, with trailing "..." if we are about
+ to read a symbol file (possibly slowly). */
+ print_gdb_version (gdb_stdout);
+ if (symarg)
+ printf_filtered ("..");
+ wrap_here ("");
+ gdb_flush (gdb_stdout); /* Force to screen during slow operations */
+ }
+
+
+ /* Install the default UI. All the interpreters should have had a
+ look at things by now. Initialize the default interpreter. */
+
+ {
+ /* Find it. */
+ struct interp *interp = interp_lookup (interpreter_p);
+ if (interp == NULL)
+ error ("Interpreter `%s' unrecognized", interpreter_p);
+ /* Install it. */
+ if (!interp_set (interp))
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "Interpreter `%s' failed to initialize.\n",
+ interpreter_p);
+ exit (1);
+ }
+ }
+
+ /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets
+ GDB retain the old MI1 interpreter startup behavior. Output the
+ copyright message after the interpreter is installed when it is
+ any sane interpreter. */
+ if (!quiet && !current_interp_named_p (INTERP_MI1))
+ {
+ /* Print all the junk at the top, with trailing "..." if we are about
+ to read a symbol file (possibly slowly). */
+ 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 (homedir) +
+ strlen (gdbinit) + 10);
+ strcpy (homeinit, homedir);
+ strcat (homeinit, "/");
+ strcat (homeinit, gdbinit);
+
+ if (!inhibit_gdbinit)
+ {
+ catch_command_errors (source_command, homeinit, 0, RETURN_MASK_ALL);
+ }
+
+ /* 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)
+ {
+ catch_command_errors (cd_command, cdarg, 0, RETURN_MASK_ALL);
+ }
+
+ for (i = 0; i < ndir; i++)
+ catch_command_errors (directory_command, dirarg[i], 0, RETURN_MASK_ALL);
+ xfree (dirarg);
+
+ if (execarg != NULL
+ && symarg != NULL
+ && strcmp (execarg, symarg) == 0)
+ {
+ /* The exec file and the symbol-file are the same. If we can't
+ open it, better only print one error message.
+ catch_command_errors returns non-zero on success! */
+ if (catch_command_errors (exec_file_attach, execarg, !batch, RETURN_MASK_ALL))
+ catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL);
+ }
+ else
+ {
+ if (execarg != NULL)
+ catch_command_errors (exec_file_attach, execarg, !batch, RETURN_MASK_ALL);
+ if (symarg != NULL)
+ catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL);
+ }
+
+ /* 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)
+ {
+ /* corearg may be either a corefile or a pid.
+ If its first character is a digit, try attach first
+ and then corefile. Otherwise try corefile first. */
+
+ if (isdigit (corearg[0]))
+ {
+ if (catch_command_errors (attach_command, corearg,
+ !batch, RETURN_MASK_ALL) == 0)
+ catch_command_errors (core_file_command, corearg,
+ !batch, RETURN_MASK_ALL);
+ }
+ else /* Can't be a pid, better be a corefile. */
+ catch_command_errors (core_file_command, corearg,
+ !batch, RETURN_MASK_ALL);
+ }
+
+ if (ttyarg != NULL)
+ catch_command_errors (tty_command, ttyarg, !batch, RETURN_MASK_ALL);
+
+ /* 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)
+ {
+ catch_command_errors (source_command, gdbinit, 0, RETURN_MASK_ALL);
+ }
+
+ for (i = 0; i < ncmd; i++)
+ {
+#if 0
+ /* NOTE: cagney/1999-11-03: SET_TOP_LEVEL() was a macro that
+ expanded into a call to setjmp(). */
+ if (!SET_TOP_LEVEL ()) /* NB: This is #if 0'd out */
+ {
+ /* NOTE: I am commenting this out, because it is not clear
+ where this feature is used. It is very old and
+ undocumented. ezannoni: 1999-05-04 */
+#if 0
+ if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
+ read_command_file (stdin);
+ else
+#endif
+ source_command (cmdarg[i], !batch);
+ do_cleanups (ALL_CLEANUPS);
+ }
+#endif
+ catch_command_errors (source_command, cmdarg[i], !batch, RETURN_MASK_ALL);
+ }
+ xfree (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
+
+ /* 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
+ }
+
+#if 0
+ /* FIXME: cagney/1999-11-06: The original main loop was like: */
+ 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);
+ }
+ }
+ /* NOTE: If the command_loop() returned normally, the loop would
+ attempt to exit by calling the function quit_command(). That
+ function would either call exit() or throw an error returning
+ control to SET_TOP_LEVEL. */
+ /* NOTE: The function do_cleanups() was called once each time round
+ the loop. The usefulness of the call isn't clear. If an error
+ was thrown, everything would have already been cleaned up. If
+ command_loop() returned normally and quit_command() was called,
+ either exit() or error() (again cleaning up) would be called. */
+#endif
+ /* NOTE: cagney/1999-11-07: There is probably no reason for not
+ moving this loop and the code found in captured_command_loop()
+ into the command_loop() proper. The main thing holding back that
+ change - SET_TOP_LEVEL() - has been eliminated. */
+ while (1)
+ {
+ catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL);
+ }
+ /* No exit -- exit is through quit_command. */
+}
+
+int
+gdb_main (struct captured_main_args *args)
+{
+ use_windows = args->use_windows;
+ catch_errors (captured_main, args, "", RETURN_MASK_ALL);
+ /* The only way to end up here is by an error (normal exit is
+ handled by quit_force()), hence always return an error status. */
+ return 1;
+}
+
+
+/* Don't use *_filtered for printing help. We don't want to prompt
+ for continue no matter how small the screen or how much we're going
+ to print. */
+
+static void
+print_gdb_help (struct ui_file *stream)
+{
+ fputs_unfiltered (_("\
+This is the GNU debugger. Usage:\n\n\
+ gdb [options] [executable-file [core-file or process-id]]\n\
+ gdb [options] --args executable-file [inferior-arguments ...]\n\n\
+Options:\n\n\
+"), stream);
+ fputs_unfiltered (_("\
+ --args Arguments after executable-file are passed to inferior\n\
+"), stream);
+ fputs_unfiltered (_("\
+ --[no]async Enable (disable) asynchronous version of CLI\n\
+"), stream);
+ fputs_unfiltered (_("\
+ -b BAUDRATE Set serial port baud rate used for remote debugging.\n\
+ --batch Exit after processing options.\n\
+ --cd=DIR Change current directory to DIR.\n\
+ --command=FILE Execute GDB commands from FILE.\n\
+ --core=COREFILE Analyze the core dump COREFILE.\n\
+ --pid=PID Attach to running process PID.\n\
+"), stream);
+ fputs_unfiltered (_("\
+ --dbx DBX compatibility mode.\n\
+ --directory=DIR Search for source files in DIR.\n\
+ --epoch Output information used by epoch emacs-GDB interface.\n\
+ --exec=EXECFILE Use EXECFILE as the executable.\n\
+ --fullname Output information used by emacs-GDB interface.\n\
+ --help Print this message.\n\
+"), stream);
+ fputs_unfiltered (_("\
+ --interpreter=INTERP\n\
+ Select a specific interpreter / user interface\n\
+"), stream);
+ fputs_unfiltered (_("\
+ --mapped Use mapped symbol files if supported on this system.\n\
+ --nw Do not use a window interface.\n\
+ --nx Do not read "), stream);
+ fputs_unfiltered (gdbinit, stream);
+ fputs_unfiltered (_(" file.\n\
+ --quiet Do not print version number on startup.\n\
+ --readnow Fully read symbol files on first access.\n\
+"), stream);
+ fputs_unfiltered (_("\
+ --se=FILE Use FILE as symbol file and executable file.\n\
+ --symbols=SYMFILE Read symbols from SYMFILE.\n\
+ --tty=TTY Use TTY for input/output by the program being debugged.\n\
+"), stream);
+#if defined(TUI)
+ fputs_unfiltered (_("\
+ --tui Use a terminal user interface.\n\
+"), stream);
+#endif
+ fputs_unfiltered (_("\
+ --version Print version information and then exit.\n\
+ -w Use a window interface.\n\
+ --write Set writing into executable and core files.\n\
+ --xdb XDB compatibility mode.\n\
+"), stream);
+ 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\
+Report bugs to \"bug-gdb@gnu.org\".\
+"), stream);
+}
diff --git a/contrib/gdb/gdb/main.h b/contrib/gdb/gdb/main.h
new file mode 100644
index 0000000..1c91d07
--- /dev/null
+++ b/contrib/gdb/gdb/main.h
@@ -0,0 +1,35 @@
+/* Main interface for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MAIN_H
+#define MAIN_H
+
+struct captured_main_args
+{
+ int argc;
+ char **argv;
+ int use_windows;
+ const char *interpreter_p;
+};
+
+extern int gdb_main (struct captured_main_args *);
+
+#endif
diff --git a/contrib/gdb/gdb/maint.c b/contrib/gdb/gdb/maint.c
new file mode 100644
index 0000000..f105afa
--- /dev/null
+++ b/contrib/gdb/gdb/maint.c
@@ -0,0 +1,868 @@
+/* Support for GDB maintenance commands.
+
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
+ 2002, 2003, 2004 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 <ctype.h>
+#include <signal.h>
+#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"
+#include "value.h"
+
+#include "cli/cli-decode.h"
+
+extern void _initialize_maint_cmds (void);
+
+static void maintenance_command (char *, int);
+
+static void maintenance_dump_me (char *, int);
+
+static void maintenance_internal_error (char *args, int from_tty);
+
+static void maintenance_demangle (char *, int);
+
+static void maintenance_time_display (char *, int);
+
+static void maintenance_space_display (char *, int);
+
+static void maintenance_info_command (char *, int);
+
+static void maintenance_info_sections (char *, int);
+
+static void maintenance_print_command (char *, int);
+
+static void maintenance_do_deprecate (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 (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);
+}
+
+#ifndef _WIN32
+static void
+maintenance_dump_me (char *args, int from_tty)
+{
+ if (query ("Should GDB dump core? "))
+ {
+#ifdef __DJGPP__
+ /* SIGQUIT by default is ignored, so use SIGABRT instead. */
+ signal (SIGABRT, SIG_DFL);
+ kill (getpid (), SIGABRT);
+#else
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+#endif
+ }
+}
+#endif
+
+/* Stimulate the internal error mechanism that GDB uses when an
+ internal problem is detected. Allows testing of the mechanism.
+ Also useful when the user wants to drop a core file but not exit
+ GDB. */
+
+static void
+maintenance_internal_error (char *args, int from_tty)
+{
+ internal_error (__FILE__, __LINE__, "%s", (args == NULL ? "" : args));
+}
+
+/* Stimulate the internal error mechanism that GDB uses when an
+ internal problem is detected. Allows testing of the mechanism.
+ Also useful when the user wants to drop a core file but not exit
+ GDB. */
+
+static void
+maintenance_internal_warning (char *args, int from_tty)
+{
+ internal_warning (__FILE__, __LINE__, "%s", (args == NULL ? "" : args));
+}
+
+/* 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 (char *args, int from_tty)
+{
+ char *demangled;
+
+ if (args == NULL || *args == '\0')
+ {
+ printf_unfiltered ("\"maintenance demangle\" takes an argument to demangle.\n");
+ }
+ else
+ {
+ demangled = language_demangle (current_language, args,
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled != NULL)
+ {
+ printf_unfiltered ("%s\n", demangled);
+ xfree (demangled);
+ }
+ else
+ {
+ printf_unfiltered ("Can't demangle \"%s\"\n", args);
+ }
+ }
+}
+
+static void
+maintenance_time_display (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 (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. */
+
+static void
+maintenance_info_command (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);
+}
+
+/* Mini tokenizing lexer for 'maint info sections' command. */
+
+static int
+match_substring (const char *string, const char *substr)
+{
+ int substr_len = strlen(substr);
+ const char *tok;
+
+ while ((tok = strstr (string, substr)) != NULL)
+ {
+ /* Got a partial match. Is it a whole word? */
+ if (tok == string
+ || tok[-1] == ' '
+ || tok[-1] == '\t')
+ {
+ /* Token is delimited at the front... */
+ if (tok[substr_len] == ' '
+ || tok[substr_len] == '\t'
+ || tok[substr_len] == '\0')
+ {
+ /* Token is delimited at the rear. Got a whole-word match. */
+ return 1;
+ }
+ }
+ /* Token didn't match as a whole word. Advance and try again. */
+ string = tok + 1;
+ }
+ return 0;
+}
+
+static int
+match_bfd_flags (char *string, flagword flags)
+{
+ if (flags & SEC_ALLOC)
+ if (match_substring (string, "ALLOC"))
+ return 1;
+ if (flags & SEC_LOAD)
+ if (match_substring (string, "LOAD"))
+ return 1;
+ if (flags & SEC_RELOC)
+ if (match_substring (string, "RELOC"))
+ return 1;
+ if (flags & SEC_READONLY)
+ if (match_substring (string, "READONLY"))
+ return 1;
+ if (flags & SEC_CODE)
+ if (match_substring (string, "CODE"))
+ return 1;
+ if (flags & SEC_DATA)
+ if (match_substring (string, "DATA"))
+ return 1;
+ if (flags & SEC_ROM)
+ if (match_substring (string, "ROM"))
+ return 1;
+ if (flags & SEC_CONSTRUCTOR)
+ if (match_substring (string, "CONSTRUCTOR"))
+ return 1;
+ if (flags & SEC_HAS_CONTENTS)
+ if (match_substring (string, "HAS_CONTENTS"))
+ return 1;
+ if (flags & SEC_NEVER_LOAD)
+ if (match_substring (string, "NEVER_LOAD"))
+ return 1;
+ if (flags & SEC_COFF_SHARED_LIBRARY)
+ if (match_substring (string, "COFF_SHARED_LIBRARY"))
+ return 1;
+ if (flags & SEC_IS_COMMON)
+ if (match_substring (string, "IS_COMMON"))
+ return 1;
+
+ return 0;
+}
+
+static void
+print_bfd_flags (flagword flags)
+{
+ 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");
+}
+
+static void
+maint_print_section_info (const char *name, flagword flags,
+ CORE_ADDR addr, CORE_ADDR endaddr,
+ unsigned long filepos)
+{
+ /* FIXME-32x64: Need print_address_numeric with field width. */
+ printf_filtered (" 0x%s", paddr (addr));
+ printf_filtered ("->0x%s", paddr (endaddr));
+ printf_filtered (" at %s",
+ local_hex_string_custom ((unsigned long) filepos, "08l"));
+ printf_filtered (": %s", name);
+ print_bfd_flags (flags);
+ printf_filtered ("\n");
+}
+
+static void
+print_bfd_section_info (bfd *abfd,
+ asection *asect,
+ void *arg)
+{
+ flagword flags = bfd_get_section_flags (abfd, asect);
+ const char *name = bfd_section_name (abfd, asect);
+
+ if (arg == NULL || *((char *) arg) == '\0'
+ || match_substring ((char *) arg, name)
+ || match_bfd_flags ((char *) arg, flags))
+ {
+ CORE_ADDR addr, endaddr;
+
+ addr = bfd_section_vma (abfd, asect);
+ endaddr = addr + bfd_section_size (abfd, asect);
+ maint_print_section_info (name, flags, addr, endaddr, asect->filepos);
+ }
+}
+
+static void
+print_objfile_section_info (bfd *abfd,
+ struct obj_section *asect,
+ char *string)
+{
+ flagword flags = bfd_get_section_flags (abfd, asect->the_bfd_section);
+ const char *name = bfd_section_name (abfd, asect->the_bfd_section);
+
+ if (string == NULL || *string == '\0'
+ || match_substring (string, name)
+ || match_bfd_flags (string, flags))
+ {
+ maint_print_section_info (name, flags, asect->addr, asect->endaddr,
+ asect->the_bfd_section->filepos);
+ }
+}
+
+static void
+maintenance_info_sections (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));
+ if (arg && *arg && match_substring (arg, "ALLOBJ"))
+ {
+ struct objfile *ofile;
+ struct obj_section *osect;
+
+ /* Only this function cares about the 'ALLOBJ' argument;
+ if 'ALLOBJ' is the only argument, discard it rather than
+ passing it down to print_objfile_section_info (which
+ wouldn't know how to handle it). */
+ if (strcmp (arg, "ALLOBJ") == 0)
+ arg = NULL;
+
+ ALL_OBJFILES (ofile)
+ {
+ printf_filtered (" Object file: %s\n",
+ bfd_get_filename (ofile->obfd));
+ ALL_OBJFILE_OSECTIONS (ofile, osect)
+ {
+ print_objfile_section_info (ofile->obfd, osect, arg);
+ }
+ }
+ }
+ else
+ bfd_map_over_sections (exec_bfd, print_bfd_section_info, arg);
+ }
+
+ 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_bfd_section_info, arg);
+ }
+}
+
+void
+maintenance_print_statistics (char *args, int from_tty)
+{
+ print_objfile_statistics ();
+ print_symbol_bcache_statistics ();
+}
+
+static void
+maintenance_print_architecture (char *args, int from_tty)
+{
+ if (args == NULL)
+ gdbarch_dump (current_gdbarch, gdb_stdout);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print architecture");
+ gdbarch_dump (current_gdbarch, file);
+ ui_file_delete (file);
+ }
+}
+
+/* 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. */
+
+static void
+maintenance_print_command (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);
+}
+
+/* The "maintenance translate-address" command converts a section and address
+ to a symbol. This can be called in two ways:
+ maintenance translate-address <secname> <addr>
+ or maintenance translate-address <addr>
+ */
+
+static void
+maintenance_translate_address (char *arg, int from_tty)
+{
+ CORE_ADDR address;
+ asection *sect;
+ char *p;
+ struct minimal_symbol *sym;
+ struct objfile *objfile;
+
+ if (arg == NULL || *arg == 0)
+ error ("requires argument (address or section + address)");
+
+ sect = NULL;
+ p = arg;
+
+ if (!isdigit (*p))
+ { /* See if we have a valid section name */
+ while (*p && !isspace (*p)) /* Find end of section name */
+ p++;
+ if (*p == '\000') /* End of command? */
+ error ("Need to specify <section-name> and <address>");
+ *p++ = '\000';
+ while (isspace (*p))
+ p++; /* Skip whitespace */
+
+ ALL_OBJFILES (objfile)
+ {
+ sect = bfd_get_section_by_name (objfile->obfd, arg);
+ if (sect != NULL)
+ break;
+ }
+
+ if (!sect)
+ error ("Unknown section %s.", arg);
+ }
+
+ address = parse_and_eval_address (p);
+
+ if (sect)
+ sym = lookup_minimal_symbol_by_pc_section (address, sect);
+ else
+ sym = lookup_minimal_symbol_by_pc (address);
+
+ if (sym)
+ printf_filtered ("%s+%s\n",
+ SYMBOL_PRINT_NAME (sym),
+ paddr_u (address - SYMBOL_VALUE_ADDRESS (sym)));
+ else if (sect)
+ printf_filtered ("no symbol at %s:0x%s\n", sect->name, paddr (address));
+ else
+ printf_filtered ("no symbol at 0x%s\n", paddr (address));
+
+ return;
+}
+
+
+/* When a command is deprecated the user will be warned the first time
+ the command is used. If possible, a replacement will be
+ offered. */
+
+static void
+maintenance_deprecate (char *args, int from_tty)
+{
+ if (args == NULL || *args == '\0')
+ {
+ printf_unfiltered ("\"maintenance deprecate\" takes an argument, \n\
+the command you want to deprecate, and optionally the replacement command \n\
+enclosed in quotes.\n");
+ }
+
+ maintenance_do_deprecate (args, 1);
+
+}
+
+
+static void
+maintenance_undeprecate (char *args, int from_tty)
+{
+ if (args == NULL || *args == '\0')
+ {
+ printf_unfiltered ("\"maintenance undeprecate\" takes an argument, \n\
+the command you want to undeprecate.\n");
+ }
+
+ maintenance_do_deprecate (args, 0);
+
+}
+
+/* You really shouldn't be using this. It is just for the testsuite.
+ Rather, you should use deprecate_cmd() when the command is created
+ in _initialize_blah().
+
+ This function deprecates a command and optionally assigns it a
+ replacement. */
+
+static void
+maintenance_do_deprecate (char *text, int deprecate)
+{
+
+ struct cmd_list_element *alias = NULL;
+ struct cmd_list_element *prefix_cmd = NULL;
+ struct cmd_list_element *cmd = NULL;
+
+ char *start_ptr = NULL;
+ char *end_ptr = NULL;
+ int len;
+ char *replacement = NULL;
+
+ if (text == NULL)
+ return;
+
+ if (!lookup_cmd_composition (text, &alias, &prefix_cmd, &cmd))
+ {
+ printf_filtered ("Can't find command '%s' to deprecate.\n", text);
+ return;
+ }
+
+ if (deprecate)
+ {
+ /* look for a replacement command */
+ start_ptr = strchr (text, '\"');
+ if (start_ptr != NULL)
+ {
+ start_ptr++;
+ end_ptr = strrchr (start_ptr, '\"');
+ if (end_ptr != NULL)
+ {
+ len = end_ptr - start_ptr;
+ start_ptr[len] = '\0';
+ replacement = xstrdup (start_ptr);
+ }
+ }
+ }
+
+ if (!start_ptr || !end_ptr)
+ replacement = NULL;
+
+
+ /* If they used an alias, we only want to deprecate the alias.
+
+ Note the MALLOCED_REPLACEMENT test. If the command's replacement
+ string was allocated at compile time we don't want to free the
+ memory. */
+ if (alias)
+ {
+
+ if (alias->flags & MALLOCED_REPLACEMENT)
+ xfree (alias->replacement);
+
+ if (deprecate)
+ alias->flags |= (DEPRECATED_WARN_USER | CMD_DEPRECATED);
+ else
+ alias->flags &= ~(DEPRECATED_WARN_USER | CMD_DEPRECATED);
+ alias->replacement = replacement;
+ alias->flags |= MALLOCED_REPLACEMENT;
+ return;
+ }
+ else if (cmd)
+ {
+ if (cmd->flags & MALLOCED_REPLACEMENT)
+ xfree (cmd->replacement);
+
+ if (deprecate)
+ cmd->flags |= (DEPRECATED_WARN_USER | CMD_DEPRECATED);
+ else
+ cmd->flags &= ~(DEPRECATED_WARN_USER | CMD_DEPRECATED);
+ cmd->replacement = replacement;
+ cmd->flags |= MALLOCED_REPLACEMENT;
+ return;
+ }
+}
+
+/* Maintenance set/show framework. */
+
+static struct cmd_list_element *maintenance_set_cmdlist;
+static struct cmd_list_element *maintenance_show_cmdlist;
+
+static void
+maintenance_set_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"maintenance set\" must be followed by the name of a set command.\n");
+ help_list (maintenance_set_cmdlist, "maintenance set ", -1, gdb_stdout);
+}
+
+static void
+maintenance_show_cmd (char *args, int from_tty)
+{
+ cmd_show_list (maintenance_show_cmdlist, from_tty, "");
+}
+
+/* Profiling support. */
+
+static int maintenance_profile_p;
+
+#if defined (HAVE_MONSTARTUP) && defined (HAVE__MCLEANUP)
+
+#ifdef HAVE__ETEXT
+extern char _etext;
+#define TEXTEND &_etext
+#else
+extern char etext;
+#define TEXTEND &etext
+#endif
+
+static int profiling_state;
+
+static void
+mcleanup_wrapper (void)
+{
+ extern void _mcleanup (void);
+
+ if (profiling_state)
+ _mcleanup ();
+}
+
+static void
+maintenance_set_profile_cmd (char *args, int from_tty, struct cmd_list_element *c)
+{
+ if (maintenance_profile_p == profiling_state)
+ return;
+
+ profiling_state = maintenance_profile_p;
+
+ if (maintenance_profile_p)
+ {
+ static int profiling_initialized;
+
+ extern void monstartup (unsigned long, unsigned long);
+ extern int main();
+
+ if (!profiling_initialized)
+ {
+ atexit (mcleanup_wrapper);
+ profiling_initialized = 1;
+ }
+
+ /* "main" is now always the first function in the text segment, so use
+ its address for monstartup. */
+ monstartup ((unsigned long) &main, (unsigned long) TEXTEND);
+ }
+ else
+ {
+ extern void _mcleanup (void);
+ _mcleanup ();
+ }
+}
+#else
+static void
+maintenance_set_profile_cmd (char *args, int from_tty, struct cmd_list_element *c)
+{
+ error ("Profiling support is not available on this system.");
+}
+#endif
+
+void
+_initialize_maint_cmds (void)
+{
+ struct cmd_list_element *tmpcmd;
+
+ 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++/ObjC 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_alias_cmd ("i", "info", class_maintenance, 1, &maintenancelist);
+
+ add_cmd ("sections", class_maintenance, maintenance_info_sections,
+ "List the BFD sections of the exec and core files. \n\
+Arguments may be any combination of:\n\
+ [one or more section names]\n\
+ ALLOC LOAD RELOC READONLY CODE DATA ROM CONSTRUCTOR\n\
+ HAS_CONTENTS NEVER_LOAD COFF_SHARED_LIBRARY IS_COMMON\n\
+Sections matching any argument will be listed (no argument\n\
+implies all sections). In addition, the special argument\n\
+ ALLOBJ\n\
+lists all sections from all object files, including shared libraries.",
+ &maintenanceinfolist);
+
+ add_prefix_cmd ("print", class_maintenance, maintenance_print_command,
+ "Maintenance command for printing GDB internal state.",
+ &maintenanceprintlist, "maintenance print ", 0,
+ &maintenancelist);
+
+ add_prefix_cmd ("set", class_maintenance, maintenance_set_cmd, "\
+Set GDB internal variables used by the GDB maintainer.\n\
+Configure variables internal to GDB that aid in GDB's maintenance",
+ &maintenance_set_cmdlist, "maintenance set ",
+ 0/*allow-unknown*/,
+ &maintenancelist);
+
+ add_prefix_cmd ("show", class_maintenance, maintenance_show_cmd, "\
+Show GDB internal variables used by the GDB maintainer.\n\
+Configure variables internal to GDB that aid in GDB's maintenance",
+ &maintenance_show_cmdlist, "maintenance show ",
+ 0/*allow-unknown*/,
+ &maintenancelist);
+
+#ifndef _WIN32
+ add_cmd ("dump-me", class_maintenance, maintenance_dump_me,
+ "Get fatal error; make debugger dump its core.\n\
+GDB sets its handling of SIGQUIT back to SIG_DFL and then sends\n\
+itself a SIGQUIT signal.",
+ &maintenancelist);
+#endif
+
+ add_cmd ("internal-error", class_maintenance, maintenance_internal_error,
+ "Give GDB an internal error.\n\
+Cause GDB to behave as if an internal error was detected.",
+ &maintenancelist);
+
+ add_cmd ("internal-warning", class_maintenance, maintenance_internal_warning,
+ "Give GDB an internal warning.\n\
+Cause GDB to behave as if an internal warning was reported.",
+ &maintenancelist);
+
+ add_cmd ("demangle", class_maintenance, maintenance_demangle,
+ "Demangle a C++/ObjC 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 ("symtabs", class_maintenance, maintenance_info_symtabs,
+ "List the full symbol tables for all object files.\n\
+This does not include information about individual symbols, blocks, or\n\
+linetables --- just the symbol table structures themselves.\n\
+With an argument REGEXP, list the symbol tables whose names that match that.",
+ &maintenanceinfolist);
+
+ add_cmd ("psymtabs", class_maintenance, maintenance_info_psymtabs,
+ "List the partial symbol tables for all object files.\n\
+This does not include information about individual partial symbols,\n\
+just the symbol table structures themselves.",
+ &maintenanceinfolist);
+
+ add_cmd ("statistics", class_maintenance, maintenance_print_statistics,
+ "Print statistics about internal gdb state.",
+ &maintenanceprintlist);
+
+ add_cmd ("architecture", class_maintenance, maintenance_print_architecture,
+ "Print the internal architecture configuration.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+
+ add_cmd ("check-symtabs", class_maintenance, maintenance_check_symtabs,
+ "Check consistency of psymtabs and symtabs.",
+ &maintenancelist);
+
+ add_cmd ("translate-address", class_maintenance, maintenance_translate_address,
+ "Translate a section name and address to a symbol.",
+ &maintenancelist);
+
+ add_cmd ("deprecate", class_maintenance, maintenance_deprecate,
+ "Deprecate a command. Note that this is just in here so the \n\
+testsuite can check the comamnd deprecator. You probably shouldn't use this,\n\
+rather you should use the C function deprecate_cmd(). If you decide you \n\
+want to use it: maintenance deprecate 'commandname' \"replacement\". The \n\
+replacement is optional.", &maintenancelist);
+
+ add_cmd ("undeprecate", class_maintenance, maintenance_undeprecate,
+ "Undeprecate a command. Note that this is just in here so the \n\
+testsuite can check the comamnd deprecator. You probably shouldn't use this,\n\
+If you decide you want to use it: maintenance undeprecate 'commandname'",
+ &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);
+
+
+ add_setshow_boolean_cmd ("profile", class_maintenance,
+ &maintenance_profile_p,
+ "Set internal profiling.\n"
+ "When enabled GDB is profiled.",
+ "Show internal profiling.\n",
+ maintenance_set_profile_cmd, NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
+}
diff --git a/contrib/gdb/gdb/mdebugread.c b/contrib/gdb/gdb/mdebugread.c
new file mode 100644
index 0000000..89d0282
--- /dev/null
+++ b/contrib/gdb/gdb/mdebugread.c
@@ -0,0 +1,4996 @@
+/* Read a symbol table in ECOFF format (Third-Eye).
+
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 "objfiles.h"
+#include "gdb_obstack.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "complaints.h"
+#include "demangle.h"
+#include "gdb_assert.h"
+#include "block.h"
+#include "dictionary.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__"
+extern void ecoff_relocate_efi (struct symbol *, CORE_ADDR);
+#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 <sys/types.h>
+#endif
+
+#include "gdb_stat.h"
+#include "gdb_string.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" /* For local_hex_string() */
+
+extern void _initialize_mdebugread (void);
+
+/* Provide a way to test if we have both ECOFF and ELF symbol tables.
+ We use this define in order to know whether we should override a
+ symbol's ECOFF section with its ELF section. This is necessary in
+ case the symbol's ELF section could not be represented in ECOFF. */
+#define ECOFF_IN_ELF(bfd) (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && bfd_get_section_by_name (bfd, ".mdebug") != NULL)
+
+
+/* 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)
+
+#define SC_IS_TEXT(sc) ((sc) == scText \
+ || (sc) == scRConst \
+ || (sc) == scInit \
+ || (sc) == scFini)
+#define SC_IS_DATA(sc) ((sc) == scData \
+ || (sc) == scSData \
+ || (sc) == scRData \
+ || (sc) == scPData \
+ || (sc) == scXData)
+#define SC_IS_COMMON(sc) ((sc) == scCommon || (sc) == scSCommon)
+#define SC_IS_BSS(sc) ((sc) == scBss)
+#define SC_IS_SBSS(sc) ((sc) == scSBss)
+#define SC_IS_UNDEF(sc) ((sc) == scUndefined || (sc) == scSUndefined)
+
+/* Various complaints about symbol reading that don't abort the process */
+static void
+index_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints, "bad aux index at symbol %s", arg1);
+}
+
+static void
+unknown_ext_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints, "unknown external symbol %s", arg1);
+}
+
+static void
+basic_type_complaint (int arg1, const char *arg2)
+{
+ complaint (&symfile_complaints, "cannot map ECOFF basic type 0x%x for %s",
+ arg1, arg2);
+}
+
+static void
+bad_tag_guess_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints, "guessed tag type of %s incorrectly", arg1);
+}
+
+static void
+bad_rfd_entry_complaint (const char *arg1, int arg2, int arg3)
+{
+ complaint (&symfile_complaints, "bad rfd entry for %s: file %d, index %d",
+ arg1, arg2, arg3);
+}
+
+static void
+unexpected_type_code_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints, "unexpected type code for %s", arg1);
+}
+
+/* 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 int max_gdbinfo;
+static int 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 (int, struct type **, int, union aux_ext *,
+ int, char *);
+
+static void parse_partial_symbols (struct objfile *);
+
+static int has_opaque_xref (FDR *, SYMR *);
+
+static int cross_ref (int, union aux_ext *, struct type **, enum type_code,
+ char **, int, char *);
+
+static struct symbol *new_symbol (char *);
+
+static struct type *new_type (char *);
+
+enum block_type { FUNCTION_BLOCK, NON_FUNCTION_BLOCK };
+
+static struct block *new_block (enum block_type);
+
+static struct symtab *new_symtab (char *, int, struct objfile *);
+
+static struct linetable *new_linetable (int);
+
+static struct blockvector *new_bvect (int);
+
+static struct type *parse_type (int, union aux_ext *, unsigned int, int *,
+ int, char *);
+
+static struct symbol *mylookup_symbol (char *, struct block *, domain_enum,
+ enum address_class);
+
+static void sort_blocks (struct symtab *);
+
+static struct partial_symtab *new_psymtab (char *, struct objfile *);
+
+static void psymtab_to_symtab_1 (struct partial_symtab *, char *);
+
+static void add_block (struct block *, struct symtab *);
+
+static void add_symbol (struct symbol *, struct block *);
+
+static int add_line (struct linetable *, int, CORE_ADDR, int);
+
+static struct linetable *shrink_linetable (struct linetable *);
+
+static void handle_psymbol_enumerators (struct objfile *, FDR *, int,
+ CORE_ADDR);
+
+static char *mdebug_next_symbol_text (struct objfile *);
+
+/* Address bounds for the signal trampoline in inferior, if any */
+
+CORE_ADDR sigtramp_address, sigtramp_end;
+
+/* Allocate zeroed memory */
+
+static void *
+xzalloc (unsigned int size)
+{
+ void *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 (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 (int cf, int rf)
+{
+ FDR *fdrs;
+ 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 (FDR *f)
+{
+ if (f->rss == -1)
+ return "<stripped file>";
+ if (f->rss == 0)
+ return "<NFY>";
+ 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 (struct objfile *objfile,
+ const struct ecoff_debug_swap *swap,
+ struct ecoff_debug_info *info)
+{
+ cur_bfd = objfile->obfd;
+ debug_swap = swap;
+ debug_info = info;
+
+ stabsread_new_init ();
+ buildsym_new_init ();
+ free_header_files ();
+ init_header_files ();
+
+ /* 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->objfile_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);
+
+#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;
+
+ 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 (void)
+{
+ 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)
+ {
+ 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 (void)
+{
+ 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 (FDR *fh, char *sh)
+{
+ int f_idx = fh - debug_info->fdr;
+ 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 (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 (&current_objfile->objfile_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 (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend,
+ struct section_offsets *section_offsets, struct objfile *objfile)
+{
+ const bfd_size_type external_sym_size = debug_swap->external_sym_size;
+ void (*const swap_sym_in) (bfd *, void *, 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:
+ case scRConst:
+ /* 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 (objfile));
+ break;
+ case scData:
+ case scSData:
+ case scRData:
+ case scPData:
+ case scXData:
+ sh->value += ANOFFSET (section_offsets, SECT_OFF_DATA (objfile));
+ break;
+ case scBss:
+ case scSBss:
+ sh->value += ANOFFSET (section_offsets, SECT_OFF_BSS (objfile));
+ 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 (SC_IS_COMMON (sh->sc))
+ {
+ /* 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 (DEPRECATED_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_DOMAIN (s) = VAR_DOMAIN;
+ SYMBOL_CLASS (s) = class;
+ add_symbol (s, b);
+
+ /* Type could be missing if file is compiled without debugging info. */
+ if (SC_IS_UNDEF (sh->sc)
+ || 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_DOMAIN (s) = VAR_DOMAIN;
+ 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_DOMAIN (s) = VAR_DOMAIN; /* 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 */
+ /* For stProc symbol records, we need to check the storage class
+ as well, as only (stProc, scText) entries represent "real"
+ procedures - See the Compaq document titled "Object File /
+ Symbol Table Format Specification" for more information.
+ If the storage class is not scText, we discard the whole block
+ of symbol records for this stProc. */
+ if (sh->st == stProc && sh->sc != scText)
+ {
+ char *ext_tsym = ext_sh;
+ int keep_counting = 1;
+ SYMR tsym;
+
+ while (keep_counting)
+ {
+ ext_tsym += external_sym_size;
+ (*swap_sym_in) (cur_bfd, ext_tsym, &tsym);
+ count++;
+ switch (tsym.st)
+ {
+ case stParam:
+ break;
+ case stEnd:
+ keep_counting = 0;
+ break;
+ default:
+ complaint (&symfile_complaints,
+ "unknown symbol type 0x%x", sh->st);
+ break;
+ }
+ }
+ break;
+ }
+ s = new_symbol (name);
+ SYMBOL_DOMAIN (s) = VAR_DOMAIN;
+ SYMBOL_CLASS (s) = LOC_BLOCK;
+ /* Type of the return value */
+ if (SC_IS_UNDEF (sh->sc) || sh->sc == scNil)
+ t = mdebug_type_int;
+ else
+ {
+ t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name);
+ if (strcmp (name, "malloc") == 0
+ && TYPE_CODE (t) == TYPE_CODE_VOID)
+ {
+ /* I don't know why, but, at least under Alpha GNU/Linux,
+ when linking against a malloc without debugging
+ symbols, its read as a function returning void---this
+ is bad because it means we cannot call functions with
+ string arguments interactively; i.e., "call
+ printf("howdy\n")" would fail with the error message
+ "program has no memory available". To avoid this, we
+ patch up the type and make it void*
+ instead. (davidm@azstarnet.com)
+ */
+ t = make_pointer_type (t, NULL);
+ }
+ }
+ 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);
+
+ /* All functions in C++ have prototypes. For C we don't have enough
+ information in the debug info. */
+ if (SYMBOL_LANGUAGE (s) == language_cplus)
+ TYPE_FLAGS (SYMBOL_TYPE (s)) |= TYPE_FLAG_PROTOTYPED;
+
+ /* Create and enter a new lexical context */
+ b = new_block (FUNCTION_BLOCK);
+ 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 (SC_IS_UNDEF (sh->sc) || 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 && !SC_IS_COMMON (sh->sc))
+ 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:
+ /* C++ encodes class types as structures where there the
+ methods are encoded as stProc. The scope of stProc
+ symbols also ends with stEnd, thus creating a risk of
+ taking the wrong stEnd symbol record as the end of
+ the current struct, which would cause GDB to undercount
+ the real number of fields in this struct. To make sure
+ we really reached the right stEnd symbol record, we
+ check the associated name, and match it against the
+ struct name. Since method names are mangled while
+ the class name is not, there is no risk of having a
+ method whose name is identical to the class name
+ (in particular constructor method names are different
+ from the class name). There is therefore no risk that
+ this check stops the count on the StEnd of a method.
+
+ Also, assume that we're really at the end when tsym.iss
+ is 0 (issNull). */
+ if (tsym.iss == issNull
+ || strcmp (debug_info->ss + cur_fdr->issBase + tsym.iss,
+ name) == 0)
+ goto end_of_fields;
+ break;
+
+ 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.
+ DU 4.0 cc enums are recognized by a member type of
+ btEnum without qualifiers 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.bt == btEnum && sh->value == 0))
+ && 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:
+ complaint (&symfile_complaints,
+ "declaration block contains unhandled symbol type %d",
+ 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 (&current_objfile->objfile_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;
+
+ FIELD_BITPOS (*f) = tsym.value;
+ FIELD_TYPE (*f) = t;
+ FIELD_NAME (*f) = debug_info->ss + cur_fdr->issBase + tsym.iss;
+ FIELD_BITSIZE (*f) = 0;
+ FIELD_STATIC_KIND (*f) = 0;
+
+ enum_sym = ((struct symbol *)
+ obstack_alloc (&current_objfile->objfile_obstack,
+ sizeof (struct symbol)));
+ memset (enum_sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (enum_sym) =
+ obsavestring (f->name, strlen (f->name),
+ &current_objfile->objfile_obstack);
+ SYMBOL_CLASS (enum_sym) = LOC_CONST;
+ SYMBOL_TYPE (enum_sym) = t;
+ SYMBOL_DOMAIN (enum_sym) = VAR_DOMAIN;
+ 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_DOMAIN (s) = STRUCT_DOMAIN;
+ 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 (NON_FUNCTION_BLOCK);
+ 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 || SC_IS_COMMON (sh->sc))
+ {
+ /* 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 = top_stack->cur_block;
+ 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_DOMAIN (s) = LABEL_DOMAIN;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = mdebug_type_void;
+ e = ((struct mips_extra_func_info *)
+ obstack_alloc (&current_objfile->objfile_obstack,
+ sizeof (struct mips_extra_func_info)));
+ memset (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);
+
+ /* 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)
+ {
+ struct dict_iterator iter;
+ TYPE_NFIELDS (ftype) = nparams;
+ TYPE_FIELDS (ftype) = (struct field *)
+ TYPE_ALLOC (ftype, nparams * sizeof (struct field));
+
+ iparams = 0;
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ if (iparams == nparams)
+ break;
+
+ 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);
+ TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0;
+ 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;
+ }
+ 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
+ complaint (&symfile_complaints,
+ "stEnd with storage class %d not handled", 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++];
+ FIELD_NAME (*f) = name;
+ FIELD_BITPOS (*f) = sh->value;
+ bitsize = 0;
+ FIELD_TYPE (*f) = parse_type (cur_fd, ax, sh->index, &bitsize, bigend, name);
+ FIELD_BITSIZE (*f) = bitsize;
+ FIELD_STATIC_KIND (*f) = 0;
+ 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_DOMAIN (s) = VAR_DOMAIN;
+ 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)) = DEPRECATED_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:
+ complaint (&symfile_complaints, "unknown symbol type 0x%x", 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 (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)
+ {
+ 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)))
+ {
+ 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:
+ 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 if TIR is corrupted. */
+ 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
+ complaint (&symfile_complaints, "can't handle TIR fBitfield for %s",
+ 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)
+ {
+ complaint (&symfile_complaints,
+ "unable to cross ref btIndirect for %s", 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 = TYPE_TARGET_TYPE (tp);
+
+ /* 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)
+ {
+ 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))
+ {
+ 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
+ || strcmp (TYPE_TAG_NAME (tp), name) != 0)
+ TYPE_TAG_NAME (tp) = obsavestring (name, strlen (name),
+ &current_objfile->objfile_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)
+ {
+ 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)
+ {
+ bad_tag_guess_complaint (sym_name);
+ TYPE_CODE (tp) = type_code;
+ }
+ if (TYPE_NAME (tp) == NULL
+ || strcmp (TYPE_NAME (tp), name) != 0)
+ TYPE_NAME (tp) = obsavestring (name, strlen (name),
+ &current_objfile->objfile_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)
+ {
+ complaint (&symfile_complaints,
+ "unable to cross ref btTypedef for %s", 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"),
+ &current_objfile->objfile_obstack);
+ TYPE_FIELD_BITPOS (tp, 0) = AUX_GET_DNLOW (bigend, ax);
+ ax++;
+ TYPE_FIELD_NAME (tp, 1) = obsavestring ("High", strlen ("High"),
+ &current_objfile->objfile_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)
+ complaint (&symfile_complaints, "illegal TIR continued for %s", 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 (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)
+ {
+ complaint (&symfile_complaints,
+ "illegal array index type for %s, assuming int", 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:
+ complaint (&symfile_complaints, "unknown type qualifier 0x%x", 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 (PDR *, struct symtab *, struct partial_symtab *);
+
+static void
+parse_procedure (PDR *pr, struct symtab *search_symtab,
+ 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. */
+ complaint (&symfile_complaints,
+ "can't handle PDR for static proc at 0x%lx",
+ (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_DOMAIN, 0, NULL);
+ cur_fdr = save_cur_fdr;
+#else
+ s = mylookup_symbol
+ (sh_name,
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (search_symtab), STATIC_BLOCK),
+ VAR_DOMAIN,
+ LOC_BLOCK);
+#endif
+ }
+ else
+ s = mylookup_symbol (sh_name, top_stack->cur_block,
+ VAR_DOMAIN, LOC_BLOCK);
+
+ if (s != 0)
+ {
+ b = SYMBOL_BLOCK_VALUE (s);
+ }
+ else
+ {
+ complaint (&symfile_complaints, "PDR for %s, but no symbol", 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_DOMAIN (s) = VAR_DOMAIN;
+ 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_DOMAIN, LOC_CONST);
+
+ if (i)
+ {
+ e = (struct mips_extra_func_info *) SYMBOL_VALUE (i);
+ e->pdr = *pr;
+ e->pdr.isym = (long) s;
+
+ /* GDB expects the absolute function start address for the
+ procedure descriptor in e->pdr.adr.
+ As the address in the procedure descriptor is usually relative,
+ we would have to relocate e->pdr.adr with cur_fdr->adr and
+ ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (pst->objfile)).
+ Unfortunately cur_fdr->adr and e->pdr.adr are both absolute
+ in shared libraries on some systems, and on other systems
+ e->pdr.adr is sometimes offset by a bogus value.
+ To work around these problems, we replace e->pdr.adr with
+ the start address of the function. */
+ e->pdr.adr = BLOCK_START (b);
+
+ /* Correct incorrect setjmp procedure descriptor from the library
+ to make backtrace through setjmp work. */
+ if (e->pdr.pcreg == 0
+ && strcmp (sh_name, "setjmp") == 0)
+ {
+ complaint (&symfile_complaints, "fixing bad setjmp PDR from libc");
+ 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 (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 (EXTR *, int, struct section_offsets *,
+ struct objfile *);
+
+static void
+parse_external (EXTR *es, int bigend, struct section_offsets *section_offsets,
+ struct objfile *objfile)
+{
+ 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 (SC_IS_UNDEF (es->asym.sc) || 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 (SC_IS_COMMON (es->asym.sc))
+ 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, objfile);
+ 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 (FDR *, PDR *, struct linetable *, int,
+ struct partial_symtab *, CORE_ADDR);
+
+static void
+parse_lines (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)
+ {
+ complaint (&symfile_complaints,
+ "guessed size of linetable for %s incorrectly",
+ fdr_name (fh));
+ break;
+ }
+ k = add_line (lt, lineno, l, k);
+ l += count + 1;
+ }
+ }
+}
+
+static void
+function_outside_compilation_unit_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints,
+ "function `%s' appears to be defined outside of all compilation units",
+ arg1);
+}
+
+/* Master parsing procedure for first-pass reading of file symbols
+ into a partial_symtab. */
+
+static void
+parse_partial_symbols (struct objfile *objfile)
+{
+ 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) (bfd *, void *, EXTR *) = debug_swap->swap_ext_in;
+ void (*const swap_sym_in) (bfd *, void *, SYMR *) = debug_swap->swap_sym_in;
+ void (*const swap_rfd_in) (bfd *, void *, 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;
+ EXTR *ext_in;
+ EXTR *ext_in_end;
+ SYMR sh;
+ struct partial_symtab *pst;
+ int textlow_not_set = 1;
+ 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->objfile_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 (xfree, fdr_to_pst);
+ fdr_to_pst++;
+ {
+ struct partial_symtab *pst = new_psymtab ("", objfile);
+ fdr_to_pst[-1].pst = pst;
+ FDR_IDX (pst) = -1;
+ }
+
+ /* Allocate the global pending list. */
+ pending_list =
+ ((struct mdebug_pending **)
+ obstack_alloc (&objfile->objfile_obstack,
+ hdr->ifdMax * sizeof (struct mdebug_pending *)));
+ memset (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 (xfree, 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;
+ }
+
+ /* ECOFF in ELF:
+
+ For ECOFF in ELF, we skip the creation of the minimal symbols.
+ The ECOFF symbols should be a subset of the Elf symbols, and the
+ section information of the elf symbols will be more accurate.
+ FIXME! What about Irix 5's native linker?
+
+ By default, Elf sections which don't exist in ECOFF
+ get put in ECOFF's absolute section by the gnu linker.
+ Since absolute sections don't get relocated, we
+ end up calculating an address different from that of
+ the symbol's minimal symbol (created earlier from the
+ Elf symtab).
+
+ To fix this, either :
+ 1) don't create the duplicate symbol
+ (assumes ECOFF symtab is a subset of the ELF symtab;
+ assumes no side-effects result from ignoring ECOFF symbol)
+ 2) create it, only if lookup for existing symbol in ELF's minimal
+ symbols fails
+ (inefficient;
+ assumes no side-effects result from ignoring ECOFF symbol)
+ 3) create it, but lookup ELF's minimal symbol and use it's section
+ during relocation, then modify "uniqify" phase to merge and
+ eliminate the duplicate symbol
+ (highly inefficient)
+
+ I've implemented #1 here...
+ Skip the creation of the minimal symbols based on the ECOFF
+ symbol table. */
+
+ /* 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)
+ {
+ complaint (&symfile_complaints,
+ "bad ifd for external symbol: %d (max %ld)", ext_in->ifd,
+ hdr->ifdMax);
+ continue;
+ }
+ if (ext_in->asym.iss < 0 || ext_in->asym.iss >= hdr->issExtMax)
+ {
+ complaint (&symfile_complaints,
+ "bad iss for external symbol: %ld (max %ld)",
+ 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 (SC_IS_UNDEF (ext_in->asym.sc) || ext_in->asym.sc == scNil)
+ continue;
+
+
+ /* Pass 3 over files, over local syms: fill in static symbols */
+ name = debug_info->ssext + ext_in->asym.iss;
+
+ /* Process ECOFF Symbol Types and Storage Classes */
+ switch (ext_in->asym.st)
+ {
+ case stProc:
+ /* Beginnning of Procedure */
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ break;
+ case stStaticProc:
+ /* Load time only static procs */
+ ms_type = mst_file_text;
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ break;
+ case stGlobal:
+ /* External symbol */
+ if (SC_IS_COMMON (ext_in->asym.sc))
+ {
+ /* The value of a common symbol is its size, not its address.
+ Ignore it. */
+ continue;
+ }
+ else if (SC_IS_DATA (ext_in->asym.sc))
+ {
+ ms_type = mst_data;
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ }
+ else if (SC_IS_BSS (ext_in->asym.sc))
+ {
+ ms_type = mst_bss;
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ }
+ else if (SC_IS_SBSS (ext_in->asym.sc))
+ {
+ ms_type = mst_bss;
+ svalue += ANOFFSET (objfile->section_offsets,
+ get_section_index (objfile, ".sbss"));
+ }
+ else
+ ms_type = mst_abs;
+ break;
+ case stLabel:
+ /* Label */
+
+ /* On certain platforms, some extra label symbols can be
+ generated by the linker. One possible usage for this kind
+ of symbols is to represent the address of the begining of a
+ given section. For instance, on Tru64 5.1, the address of
+ the _ftext label is the start address of the .text section.
+
+ The storage class of these symbols is usually directly
+ related to the section to which the symbol refers. For
+ instance, on Tru64 5.1, the storage class for the _fdata
+ label is scData, refering to the .data section.
+
+ It is actually possible that the section associated to the
+ storage class of the label does not exist. On True64 5.1
+ for instance, the libm.so shared library does not contain
+ any .data section, although it contains a _fpdata label
+ which storage class is scData... Since these symbols are
+ usually useless for the debugger user anyway, we just
+ discard these symbols.
+ */
+
+ if (SC_IS_TEXT (ext_in->asym.sc))
+ {
+ if (objfile->sect_index_text == -1)
+ continue;
+
+ ms_type = mst_file_text;
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ }
+ else if (SC_IS_DATA (ext_in->asym.sc))
+ {
+ if (objfile->sect_index_data == -1)
+ continue;
+
+ ms_type = mst_file_data;
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ }
+ else if (SC_IS_BSS (ext_in->asym.sc))
+ {
+ if (objfile->sect_index_bss == -1)
+ continue;
+
+ ms_type = mst_file_bss;
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ }
+ else if (SC_IS_SBSS (ext_in->asym.sc))
+ {
+ const int sbss_sect_index = get_section_index (objfile, ".sbss");
+
+ if (sbss_sect_index == -1)
+ continue;
+
+ ms_type = mst_file_bss;
+ svalue += ANOFFSET (objfile->section_offsets, sbss_sect_index);
+ }
+ else
+ ms_type = mst_abs;
+ break;
+ case stLocal:
+ case stNil:
+ /* The alpha has the section start addresses in stLocal symbols
+ whose name starts with a `.'. Skip those but complain for all
+ other stLocal symbols.
+ Irix6 puts the section start addresses in stNil symbols, skip
+ those too. */
+ if (name[0] == '.')
+ continue;
+ /* Fall through. */
+ default:
+ ms_type = mst_unknown;
+ unknown_ext_complaint (name);
+ }
+ if (!ECOFF_IN_ELF (cur_bfd))
+ 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 (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ }
+ else
+ textlow = 0;
+ pst = start_psymtab_common (objfile, objfile->section_offsets,
+ fdr_name (fh),
+ textlow,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ pst->read_symtab_private = ((char *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symloc)));
+ memset (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 (strcmp (debug_info->ss + fh->issBase + sh.iss,
+ stabs_symbol) == 0)
+ 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)
+ {
+ CORE_ADDR procaddr;
+ long isym;
+
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ 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),
+ NULL,
+ 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)
+ {
+ CORE_ADDR 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 scSUndefined:
+ 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 (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ prim_record_minimal_symbol_and_info (namestring,
+ sh.value,
+ mst_file_data,
+ NULL,
+ SECT_OFF_DATA (objfile),
+ NULL,
+ objfile);
+ break;
+
+ default:
+ /* FIXME! Shouldn't this use cases for bss,
+ then have the default be abs? */
+ namestring = debug_info->ss + fh->issBase + sh.iss;
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ prim_record_minimal_symbol_and_info (namestring,
+ sh.value,
+ mst_file_bss,
+ NULL,
+ SECT_OFF_BSS (objfile),
+ NULL,
+ objfile);
+ break;
+ }
+ }
+ continue;
+ }
+ /* Handle stabs continuation */
+ {
+ char *stabstring = debug_info->ss + fh->issBase + sh.iss;
+ int len = strlen (stabstring);
+ while (stabstring[len - 1] == '\\')
+ {
+ SYMR sh2;
+ char *stabstring1 = stabstring;
+ char *stabstring2;
+ int len2;
+
+ /* Ignore continuation char from 1st string */
+ len--;
+
+ /* Read next stabstring */
+ cur_sdx++;
+ (*swap_sym_in) (cur_bfd,
+ (((char *) debug_info->external_sym)
+ + (fh->isymBase + cur_sdx)
+ * external_sym_size),
+ &sh2);
+ stabstring2 = debug_info->ss + fh->issBase + sh2.iss;
+ len2 = strlen (stabstring2);
+
+ /* Concatinate stabstring2 with stabstring1 */
+ if (stabstring
+ && stabstring != debug_info->ss + fh->issBase + sh.iss)
+ stabstring = xrealloc (stabstring, len + len2 + 1);
+ else
+ {
+ stabstring = xmalloc (len + len2 + 1);
+ strcpy (stabstring, stabstring1);
+ }
+ strcpy (stabstring + len, stabstring2);
+ len += len2;
+ }
+
+ switch (type_code)
+ {
+ char *p;
+ /*
+ * Standard, external, non-debugger, symbols
+ */
+
+ case N_TEXT | N_EXT:
+ case N_NBTEXT | N_EXT:
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ goto record_it;
+
+ case N_DATA | N_EXT:
+ case N_NBDATA | N_EXT:
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ 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? */
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ goto record_it;
+
+ case N_ABS | N_EXT:
+ record_it:
+ 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:
+ continue;
+
+ case N_DATA:
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ goto record_it;
+
+ case N_UNDF | N_EXT:
+ continue; /* Just undefined, not COMMON */
+
+ case N_UNDF:
+ 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:
+ {
+ CORE_ADDR valu;
+ static int prev_so_symnum = -10;
+ static int first_so_symnum;
+ char *p;
+ int prev_textlow_not_set;
+
+ valu = sh.value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ prev_textlow_not_set = textlow_not_set;
+
+#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 (sh.value == 0)
+ {
+ textlow_not_set = 1;
+ valu = 0;
+ }
+ else
+ textlow_not_set = 0;
+#else
+ textlow_not_set = 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)
+ {
+ 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 ();*/
+ namestring = stabstring;
+
+ /* 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 = save_pst;
+ continue;
+ }
+
+ case N_BINCL:
+ continue;
+
+ case N_SOL:
+ {
+ enum language tmp_language;
+ /* Mark down an include file in the current psymtab */
+
+ /* SET_NAMESTRING ();*/
+ namestring = stabstring;
+
+ 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 && strcmp (namestring, pst->filename) == 0)
+ continue;
+ {
+ int i;
+ for (i = 0; i < includes_used; i++)
+ if (strcmp (namestring,
+ psymtab_include_list[i]) == 0)
+ {
+ i = -1;
+ break;
+ }
+ if (i == -1)
+ continue;
+ }
+
+ 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 (psymtab_include_list, 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 ();*/
+ namestring = stabstring;
+ 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':
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+#ifdef STATIC_TRANSFORM_NAME
+ namestring = STATIC_TRANSFORM_NAME (namestring);
+#endif
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->static_psymbols,
+ 0, sh.value,
+ psymtab_language, objfile);
+ continue;
+ case 'G':
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ /* 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_DOMAIN, LOC_STATIC,
+ &objfile->global_psymbols,
+ 0, sh.value,
+ psymtab_language, objfile);
+ continue;
+
+ case 'T':
+ /* When a 'T' entry is defining an anonymous enum, it
+ may have a name which is the empty string, or a
+ single space. Since they're not really defining a
+ symbol, those shouldn't go in the partial symbol
+ table. We do pick up the elements of such enums at
+ 'check_enum:', below. */
+ if (p >= namestring + 2
+ || (p == namestring + 1
+ && namestring[0] != ' '))
+ {
+ add_psymbol_to_list (namestring, p - namestring,
+ STRUCT_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ sh.value, 0,
+ psymtab_language, objfile);
+ if (p[2] == 't')
+ {
+ /* Also a typedef with the same name. */
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ sh.value, 0,
+ psymtab_language, objfile);
+ p += 1;
+ }
+ }
+ goto check_enum;
+ case 't':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ sh.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
+ <name> ":" ("t" | "T") [<number> "="] "e"
+ {<constant> ":" <value> ","} ";". */
+
+ /* 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_DOMAIN, 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_DOMAIN, LOC_CONST,
+ &objfile->static_psymbols, sh.value,
+ 0, psymtab_language, objfile);
+ continue;
+
+ case 'f':
+ if (! pst)
+ {
+ int name_len = p - namestring;
+ char *name = xmalloc (name_len + 1);
+ memcpy (name, namestring, name_len);
+ name[name_len] = '\0';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols,
+ 0, sh.value,
+ 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':
+ if (! pst)
+ {
+ int name_len = p - namestring;
+ char *name = xmalloc (name_len + 1);
+ memcpy (name, namestring, name_len);
+ name[name_len] = '\0';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols,
+ 0, sh.value,
+ 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 '-':
+ case '#': /* for symbol identification (used in live ranges) */
+ 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. */
+
+ complaint (&symfile_complaints,
+ "unknown symbol descriptor `%c'", p[1]);
+
+ /* Ignore it; perhaps it is an extension that we don't
+ know about. */
+ continue;
+ }
+
+ case N_EXCL:
+ 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)
+ {
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+#endif
+ continue;
+
+ case N_RBRAC:
+ if (sh.value > save_pst->texthigh)
+ save_pst->texthigh = sh.value;
+ continue;
+ 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_ALIAS: /* SunPro F77: alias name, ignore for now. */
+
+ 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. */
+ complaint (&symfile_complaints, "unknown symbol type %s",
+ local_hex_string (type_code)); /*CUR_SYMBOL_TYPE*/
+ continue;
+ }
+ if (stabstring
+ && stabstring != debug_info->ss + fh->issBase + sh.iss)
+ xfree (stabstring);
+ }
+ /* end - Handle continuation */
+ }
+ }
+ 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 (SC_IS_UNDEF (sh.sc) || 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:
+ case scRConst:
+ /* 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 (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ break;
+ case scData:
+ case scSData:
+ case scRData:
+ case scPData:
+ case scXData:
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ break;
+ case scBss:
+ case scSBss:
+ sh.value += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ break;
+ }
+
+ switch (sh.st)
+ {
+ CORE_ADDR high;
+ CORE_ADDR procaddr;
+ int new_sdx;
+
+ case stStaticProc:
+ prim_record_minimal_symbol_and_info (name, sh.value,
+ mst_file_text, NULL,
+ SECT_OFF_TEXT (objfile), NULL,
+ objfile);
+
+ /* FALLTHROUGH */
+
+ case stProc:
+ /* Ignore all parameter symbol records. */
+ if (sh.index >= hdr->iauxMax)
+ {
+ /* Should not happen, but does when cross-compiling
+ with the MIPS compiler. FIXME -- pull later. */
+ 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));
+
+ if (new_sdx <= cur_sdx)
+ {
+ /* This should not happen either... FIXME. */
+ complaint (&symfile_complaints,
+ "bad proc end in aux found from symbol %s",
+ name);
+ new_sdx = cur_sdx + 1; /* Don't skip backward */
+ }
+
+ /* For stProc symbol records, we need to check the
+ storage class as well, as only (stProc, scText)
+ entries represent "real" procedures - See the
+ Compaq document titled "Object File / Symbol Table
+ Format Specification" for more information. If the
+ storage class is not scText, we discard the whole
+ block of symbol records for this stProc. */
+ if (sh.st == stProc && sh.sc != scText)
+ goto skip;
+
+ /* 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_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols,
+ 0, sh.value, psymtab_language, objfile);
+ else
+ add_psymbol_to_list (name, strlen (name),
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols,
+ 0, sh.value, psymtab_language, objfile);
+
+ procaddr = sh.value;
+
+ 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 (SC_IS_DATA (sh.sc))
+ prim_record_minimal_symbol_and_info (name, sh.value,
+ mst_file_data, NULL,
+ SECT_OFF_DATA (objfile),
+ NULL,
+ objfile);
+ else
+ prim_record_minimal_symbol_and_info (name, sh.value,
+ mst_file_bss, NULL,
+ SECT_OFF_BSS (objfile),
+ NULL,
+ 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
+ || SC_IS_COMMON (sh.sc))
+ && sh.iss != 0
+ && sh.index != cur_sdx + 2)
+ {
+ add_psymbol_to_list (name, strlen (name),
+ STRUCT_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ 0, (CORE_ADDR) 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. */
+ complaint (&symfile_complaints,
+ "bad aux index at block symbol %s", 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. */
+ complaint (&symfile_complaints, "unknown local symbol %s",
+ name);
+ complaint (&symfile_complaints, "with type %d", sh.st);
+ cur_sdx++;
+ continue;
+ }
+ /* Use this gdb symbol */
+ add_psymbol_to_list (name, strlen (name),
+ VAR_DOMAIN, class,
+ &objfile->static_psymbols,
+ 0, sh.value, 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)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ psh = &ext_ptr->asym;
+
+ /* Do not add undefined symbols to the partial symbol table. */
+ if (SC_IS_UNDEF (psh->sc) || psh->sc == scNil)
+ continue;
+
+ svalue = psh->value;
+ switch (psh->sc)
+ {
+ case scText:
+ case scRConst:
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ break;
+ case scData:
+ case scSData:
+ case scRData:
+ case scPData:
+ case scXData:
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ break;
+ case scBss:
+ case scSBss:
+ svalue += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile));
+ 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:
+ 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 (SC_IS_COMMON (psh->sc))
+ continue;
+
+ class = LOC_STATIC;
+ break;
+ }
+ name = debug_info->ssext + psh->iss;
+ add_psymbol_to_list (name, strlen (name),
+ VAR_DOMAIN, 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, textlow_not_set);
+ includes_used = 0;
+ dependencies_used = 0;
+
+ if (objfile->ei.entry_point >= save_pst->textlow &&
+ objfile->ei.entry_point < save_pst->texthigh)
+ {
+ objfile->ei.deprecated_entry_file_lowpc = save_pst->textlow;
+ objfile->ei.deprecated_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->objfile_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)
+ {
+ complaint (&symfile_complaints, "bad file number %ld", 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 (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) (bfd *, void *, 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.
+ DU 4.0 cc enums are recognized by a member type of btEnum without
+ qualifiers 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.bt != btEnum || svalue != 0))
+ || 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_DOMAIN, LOC_CONST,
+ &objfile->static_psymbols, 0,
+ (CORE_ADDR) 0, psymtab_language, objfile);
+ ext_sym += external_sym_size;
+ }
+}
+
+/* Get the next symbol. OBJFILE is unused. */
+
+static char *
+mdebug_next_symbol_text (struct objfile *objfile)
+{
+ 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 (struct partial_symtab *pst, char *filename)
+{
+ bfd_size_type external_sym_size;
+ bfd_size_type external_pdr_size;
+ void (*swap_sym_in) (bfd *, void *, SYMR *);
+ void (*swap_pdr_in) (bfd *, void *, PDR *);
+ int i;
+ struct symtab *st = NULL;
+ FDR *fh;
+ struct linetable *lines;
+ CORE_ADDR lowest_pdr_addr = 0;
+ int last_symtab_ended = 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 (strcmp (debug_info->ss + fh->issBase + sh.iss,
+ stabs_symbol) == 0)
+ {
+ /* 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;
+ /* XXX This is a hack. It will go away! */
+ if (ECOFF_IS_STAB (&sh) || (name[0] == '#'))
+ {
+ 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)
+ {
+ /* If we found a trailing N_SO with no name, process
+ it here instead of in process_one_symbol, so we
+ can keep a handle to its symtab. The symtab
+ would otherwise be ended twice, once in
+ process_one_symbol, and once after this loop. */
+ if (type_code == N_SO
+ && last_source_file
+ && previous_stab_code != (unsigned char) N_SO
+ && *name == '\000')
+ {
+ valu += ANOFFSET (pst->section_offsets,
+ SECT_OFF_TEXT (pst->objfile));
+ previous_stab_code = N_SO;
+ st = end_symtab (valu, pst->objfile,
+ SECT_OFF_TEXT (pst->objfile));
+ end_stabs ();
+ last_symtab_ended = 1;
+ }
+ else
+ {
+ last_symtab_ended = 0;
+ process_one_symbol (type_code, 0, valu, name,
+ pst->section_offsets, pst->objfile);
+ }
+ }
+ /* Similarly a hack. */
+ else if (name[0] == '#')
+ {
+ process_one_symbol (N_SLINE, 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 (&current_objfile->objfile_obstack,
+ sizeof (struct mips_extra_func_info)));
+ struct symbol *s = new_symbol (MIPS_EFI_SYMBOL_NAME);
+
+ memset (e, 0, sizeof (struct mips_extra_func_info));
+ SYMBOL_DOMAIN (s) = LABEL_DOMAIN;
+ 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 (pst->objfile));
+ 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
+ complaint (&symfile_complaints, "unknown stabs symbol %s", name);
+ }
+
+ if (! last_symtab_ended)
+ {
+ st = end_symtab (pst->texthigh, pst->objfile, SECT_OFF_TEXT (pst->objfile));
+ end_stabs ();
+ }
+
+ /* 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 (xfree, 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, pst);
+
+ do_cleanups (old_chain);
+ }
+ }
+ else
+ {
+ /* This symbol table contains ordinary ecoff entries. */
+
+ int f_max;
+ int maxlines;
+ EXTR *ext_ptr;
+
+ if (fh == 0)
+ {
+ maxlines = 0;
+ st = new_symtab ("unknown", 0, pst->objfile);
+ }
+ else
+ {
+ maxlines = 2 * fh->cline;
+ st = new_symtab (pst->filename, 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->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, pst->objfile);
+ 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 (xfree, 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, 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;
+
+ 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, pst->objfile);
+
+ /* 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_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 (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 (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 = "<undefined>";
+ *tpp = init_type (type_code, 0, TYPE_FLAG_STUB, (char *) NULL, current_objfile);
+ 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 = "<undefined>";
+ 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 = "<illegal>";
+ 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 || !SC_IS_COMMON (sh.sc)))
+ {
+ /* File indirect entry is corrupt. */
+ *pname = "<illegal>";
+ 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)
+ complaint (&symfile_complaints,
+ "illegal tq0 in forward typedef for %s", sym_name);
+ switch (tir.bt)
+ {
+ case btVoid:
+ *tpp = init_type (type_code, 0, 0, (char *) NULL,
+ current_objfile);
+ *pname = "<undefined>";
+ 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:
+ complaint (&symfile_complaints,
+ "illegal bt %d in forward typedef for %s", 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 (char *name, struct block *block,
+ domain_enum domain, enum address_class class)
+{
+ struct dict_iterator iter;
+ int inc;
+ struct symbol *sym;
+
+ inc = name[0];
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ if (DEPRECATED_SYMBOL_NAME (sym)[0] == inc
+ && SYMBOL_DOMAIN (sym) == domain
+ && SYMBOL_CLASS (sym) == class
+ && strcmp (DEPRECATED_SYMBOL_NAME (sym), name) == 0)
+ return sym;
+ }
+
+ block = BLOCK_SUPERBLOCK (block);
+ if (block)
+ return mylookup_symbol (name, block, domain, class);
+ return 0;
+}
+
+
+/* Add a new symbol S to a block B. */
+
+static void
+add_symbol (struct symbol *s, struct block *b)
+{
+ dict_add_symbol (BLOCK_DICT (b), s);
+}
+
+/* Add a new block B to a symtab S */
+
+static void
+add_block (struct block *b, struct symtab *s)
+{
+ struct blockvector *bv = BLOCKVECTOR (s);
+
+ bv = (struct blockvector *) xrealloc ((void *) 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 (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 (const void *arg1, const void *arg2)
+{
+ LONGEST 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 (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);
+
+ {
+ CORE_ADDR high = 0;
+ 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
+ linenumbers MAXLINES we'll put in it */
+
+static struct symtab *
+new_symtab (char *name, 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 (NON_FUNCTION_BLOCK);
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)
+ = new_block (NON_FUNCTION_BLOCK);
+ BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)) =
+ BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+
+ s->free_code = free_linetable;
+ s->debugformat = obsavestring ("ECOFF", 5,
+ &objfile->objfile_obstack);
+ return (s);
+}
+
+/* Allocate a new partial_symtab NAME */
+
+static struct partial_symtab *
+new_psymtab (char *name, struct objfile *objfile)
+{
+ struct partial_symtab *psymtab;
+
+ psymtab = allocate_psymtab (name, objfile);
+ psymtab->section_offsets = objfile->section_offsets;
+
+ /* Keep a backpointer to the file's symbols */
+
+ psymtab->read_symtab_private = ((char *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symloc)));
+ memset (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 (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 (struct linetable *lt)
+{
+
+ return (struct linetable *) xrealloc ((void *) lt,
+ (sizeof (struct linetable)
+ + ((lt->nitems - 1)
+ * sizeof (lt->item))));
+}
+
+/* Allocate and zero a new blockvector of NBLOCKS blocks. */
+
+static struct blockvector *
+new_bvect (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, and set its BLOCK_DICT. If function
+ is non-zero, assume the block is associated to a function, and make
+ sure that the symbols are stored linearly; otherwise, store them
+ hashed. */
+
+static struct block *
+new_block (enum block_type type)
+{
+ /* FIXME: carlton/2003-09-11: This should use allocate_block to
+ allocate the block. Which, in turn, suggests that the block
+ should be allocated on an obstack. */
+ struct block *retval = xzalloc (sizeof (struct block));
+
+ if (type == FUNCTION_BLOCK)
+ BLOCK_DICT (retval) = dict_create_linear_expandable ();
+ else
+ BLOCK_DICT (retval) = dict_create_hashed_expandable ();
+
+ return retval;
+}
+
+/* Create a new symbol with printname NAME */
+
+static struct symbol *
+new_symbol (char *name)
+{
+ struct symbol *s = ((struct symbol *)
+ obstack_alloc (&current_objfile->objfile_obstack,
+ sizeof (struct symbol)));
+
+ memset (s, 0, sizeof (*s));
+ SYMBOL_LANGUAGE (s) = psymtab_language;
+ SYMBOL_SET_NAMES (s, name, strlen (name), current_objfile);
+ return s;
+}
+
+/* Create a new type with printname NAME */
+
+static struct type *
+new_type (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 (struct objfile *objfile,
+ const struct ecoff_debug_swap *swap, asection *sec)
+{
+ bfd *abfd = objfile->obfd;
+ struct ecoff_debug_info *info;
+ struct cleanup *back_to;
+
+ /* FIXME: It's not clear whether we should be getting minimal symbol
+ information from .mdebug in an ELF file, or whether we will.
+ Re-initialize the minimal symbol reader in case we do. */
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup_discard_minimal_symbols ();
+
+ info = ((struct ecoff_debug_info *)
+ obstack_alloc (&objfile->objfile_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);
+
+ install_minimal_symbols (objfile);
+ do_cleanups (back_to);
+}
+
+
+/* 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. Only compile it in when
+ tm-mips.h is included. */
+
+#ifdef TM_MIPS_H
+
+void
+fixup_sigtramp (void)
+{
+ 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_DOMAIN, 0, NULL);
+ if (s != 0)
+ {
+ b0 = SYMBOL_BLOCK_VALUE (s);
+ s = lookup_symbol ("sigtramp", b0, VAR_DOMAIN, 0, NULL);
+ }
+ if (s == 0)
+ {
+ /* No sigvec or no sigtramp inside sigvec, try _sigtramp. */
+ s = lookup_symbol ("_sigtramp", 0, VAR_DOMAIN, 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_DOMAIN (s) = VAR_DOMAIN;
+ 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 (NON_FUNCTION_BLOCK);
+ 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_DOMAIN (s) = LABEL_DOMAIN;
+ SYMBOL_CLASS (s) = LOC_CONST;
+ SYMBOL_TYPE (s) = mdebug_type_void;
+ current_objfile = NULL;
+ }
+
+ dict_add_symbol (BLOCK_DICT (b), s);
+}
+
+#endif /* TM_MIPS_H */
+
+void
+_initialize_mdebugread (void)
+{
+ 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,
+ "<function, no debug info>", 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,
+ "<variable, no debug info>", NULL);
+}
diff --git a/contrib/gdb/gdb/mem-break.c b/contrib/gdb/gdb/mem-break.c
new file mode 100644
index 0000000..96750c8
--- /dev/null
+++ b/contrib/gdb/gdb/mem-break.c
@@ -0,0 +1,92 @@
+/* Simulate breakpoints by patching locations in the target system, for GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 1999, 2000,
+ 2002 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"
+
+/* This file is only useful if BREAKPOINT_FROM_PC is set. If not, we
+ punt. */
+
+#include "symtab.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "target.h"
+
+
+/* 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
+default_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ int val;
+ const unsigned char *bp;
+ int bplen;
+
+ /* Determine appropriate breakpoint contents and size for this address. */
+ bp = BREAKPOINT_FROM_PC (&addr, &bplen);
+ if (bp == NULL)
+ error ("Software breakpoints not implemented for this target.");
+
+ /* Save the memory contents. */
+ val = target_read_memory (addr, contents_cache, bplen);
+
+ /* Write the breakpoint. */
+ if (val == 0)
+ val = target_write_memory (addr, (char *) bp, bplen);
+
+ return val;
+}
+
+
+int
+default_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ const unsigned char *bp;
+ int bplen;
+
+ /* Determine appropriate breakpoint contents and size for this address. */
+ bp = BREAKPOINT_FROM_PC (&addr, &bplen);
+ if (bp == NULL)
+ error ("Software breakpoints not implemented for this target.");
+
+ return target_write_memory (addr, contents_cache, bplen);
+}
+
+
+int
+memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return MEMORY_INSERT_BREAKPOINT(addr, contents_cache);
+}
+
+int
+memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return MEMORY_REMOVE_BREAKPOINT(addr, contents_cache);
+}
diff --git a/contrib/gdb/gdb/memattr.c b/contrib/gdb/gdb/memattr.c
new file mode 100644
index 0000000..4ab5dbf
--- /dev/null
+++ b/contrib/gdb/gdb/memattr.c
@@ -0,0 +1,549 @@
+/* Memory attributes support, for GDB.
+
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "command.h"
+#include "gdbcmd.h"
+#include "memattr.h"
+#include "target.h"
+#include "value.h"
+#include "language.h"
+#include "gdb_string.h"
+
+const struct mem_attrib default_mem_attrib =
+{
+ MEM_RW, /* mode */
+ MEM_WIDTH_UNSPECIFIED,
+ 0, /* hwbreak */
+ 0, /* cache */
+ 0 /* verify */
+};
+
+static struct mem_region *mem_region_chain = NULL;
+static int mem_number = 0;
+
+static struct mem_region *
+create_mem_region (CORE_ADDR lo, CORE_ADDR hi,
+ const struct mem_attrib *attrib)
+{
+ struct mem_region *n, *new;
+
+ /* lo == hi is a useless empty region */
+ if (lo >= hi && hi != 0)
+ {
+ printf_unfiltered ("invalid memory region: low >= high\n");
+ return NULL;
+ }
+
+ n = mem_region_chain;
+ while (n)
+ {
+ /* overlapping node */
+ if ((lo >= n->lo && (lo < n->hi || n->hi == 0))
+ || (hi > n->lo && (hi <= n->hi || n->hi == 0))
+ || (lo <= n->lo && (hi >= n->hi || hi == 0)))
+ {
+ printf_unfiltered ("overlapping memory region\n");
+ return NULL;
+ }
+ n = n->next;
+ }
+
+ new = xmalloc (sizeof (struct mem_region));
+ new->lo = lo;
+ new->hi = hi;
+ new->number = ++mem_number;
+ new->enabled_p = 1;
+ new->attrib = *attrib;
+
+ /* link in new node */
+ new->next = mem_region_chain;
+ mem_region_chain = new;
+
+ return new;
+}
+
+static void
+delete_mem_region (struct mem_region *m)
+{
+ xfree (m);
+}
+
+/*
+ * Look up the memory region cooresponding to ADDR.
+ */
+struct mem_region *
+lookup_mem_region (CORE_ADDR addr)
+{
+ static struct mem_region region;
+ struct mem_region *m;
+ CORE_ADDR lo;
+ CORE_ADDR hi;
+
+ /* First we initialize LO and HI so that they describe the entire
+ memory space. As we process the memory region chain, they are
+ redefined to describe the minimal region containing ADDR. LO
+ and HI are used in the case where no memory region is defined
+ that contains ADDR. If a memory region is disabled, it is
+ treated as if it does not exist. */
+
+ lo = (CORE_ADDR) 0;
+ hi = (CORE_ADDR) ~ 0;
+
+ for (m = mem_region_chain; m; m = m->next)
+ {
+ if (m->enabled_p == 1)
+ {
+ if (addr >= m->lo && (addr < m->hi || m->hi == 0))
+ return m;
+
+ if (addr >= m->hi && lo < m->hi)
+ lo = m->hi;
+
+ if (addr <= m->lo && hi > m->lo)
+ hi = m->lo;
+ }
+ }
+
+ /* Because no region was found, we must cons up one based on what
+ was learned above. */
+ region.lo = lo;
+ region.hi = hi;
+ region.attrib = default_mem_attrib;
+ return &region;
+}
+
+
+static void
+mem_command (char *args, int from_tty)
+{
+ CORE_ADDR lo, hi;
+ char *tok;
+ struct mem_attrib attrib;
+
+ if (!args)
+ error_no_arg ("No mem");
+
+ tok = strtok (args, " \t");
+ if (!tok)
+ error ("no lo address");
+ lo = parse_and_eval_address (tok);
+
+ tok = strtok (NULL, " \t");
+ if (!tok)
+ error ("no hi address");
+ hi = parse_and_eval_address (tok);
+
+ attrib = default_mem_attrib;
+ while ((tok = strtok (NULL, " \t")) != NULL)
+ {
+ if (strcmp (tok, "rw") == 0)
+ attrib.mode = MEM_RW;
+ else if (strcmp (tok, "ro") == 0)
+ attrib.mode = MEM_RO;
+ else if (strcmp (tok, "wo") == 0)
+ attrib.mode = MEM_WO;
+
+ else if (strcmp (tok, "8") == 0)
+ attrib.width = MEM_WIDTH_8;
+ else if (strcmp (tok, "16") == 0)
+ {
+ if ((lo % 2 != 0) || (hi % 2 != 0))
+ error ("region bounds not 16 bit aligned");
+ attrib.width = MEM_WIDTH_16;
+ }
+ else if (strcmp (tok, "32") == 0)
+ {
+ if ((lo % 4 != 0) || (hi % 4 != 0))
+ error ("region bounds not 32 bit aligned");
+ attrib.width = MEM_WIDTH_32;
+ }
+ else if (strcmp (tok, "64") == 0)
+ {
+ if ((lo % 8 != 0) || (hi % 8 != 0))
+ error ("region bounds not 64 bit aligned");
+ attrib.width = MEM_WIDTH_64;
+ }
+
+#if 0
+ else if (strcmp (tok, "hwbreak") == 0)
+ attrib.hwbreak = 1;
+ else if (strcmp (tok, "swbreak") == 0)
+ attrib.hwbreak = 0;
+#endif
+
+ else if (strcmp (tok, "cache") == 0)
+ attrib.cache = 1;
+ else if (strcmp (tok, "nocache") == 0)
+ attrib.cache = 0;
+
+#if 0
+ else if (strcmp (tok, "verify") == 0)
+ attrib.verify = 1;
+ else if (strcmp (tok, "noverify") == 0)
+ attrib.verify = 0;
+#endif
+
+ else
+ error ("unknown attribute: %s", tok);
+ }
+
+ create_mem_region (lo, hi, &attrib);
+}
+
+
+static void
+mem_info_command (char *args, int from_tty)
+{
+ struct mem_region *m;
+ struct mem_attrib *attrib;
+
+ if (!mem_region_chain)
+ {
+ printf_unfiltered ("There are no memory regions defined.\n");
+ return;
+ }
+
+ printf_filtered ("Num ");
+ printf_filtered ("Enb ");
+ printf_filtered ("Low Addr ");
+ if (TARGET_ADDR_BIT > 32)
+ printf_filtered (" ");
+ printf_filtered ("High Addr ");
+ if (TARGET_ADDR_BIT > 32)
+ printf_filtered (" ");
+ printf_filtered ("Attrs ");
+ printf_filtered ("\n");
+
+ for (m = mem_region_chain; m; m = m->next)
+ {
+ char *tmp;
+ printf_filtered ("%-3d %-3c\t",
+ m->number,
+ m->enabled_p ? 'y' : 'n');
+ if (TARGET_ADDR_BIT <= 32)
+ tmp = local_hex_string_custom ((unsigned long) m->lo, "08l");
+ else
+ tmp = local_hex_string_custom ((unsigned long) m->lo, "016l");
+
+ printf_filtered ("%s ", tmp);
+
+ if (TARGET_ADDR_BIT <= 32)
+ {
+ if (m->hi == 0)
+ tmp = "0x100000000";
+ else
+ tmp = local_hex_string_custom ((unsigned long) m->hi, "08l");
+ }
+ else
+ {
+ if (m->hi == 0)
+ tmp = "0x10000000000000000";
+ else
+ tmp = local_hex_string_custom ((unsigned long) m->hi, "016l");
+ }
+
+ printf_filtered ("%s ", tmp);
+
+ /* Print a token for each attribute.
+
+ * FIXME: Should we output a comma after each token? It may
+ * make it easier for users to read, but we'd lose the ability
+ * to cut-and-paste the list of attributes when defining a new
+ * region. Perhaps that is not important.
+ *
+ * FIXME: If more attributes are added to GDB, the output may
+ * become cluttered and difficult for users to read. At that
+ * time, we may want to consider printing tokens only if they
+ * are different from the default attribute. */
+
+ attrib = &m->attrib;
+ switch (attrib->mode)
+ {
+ case MEM_RW:
+ printf_filtered ("rw ");
+ break;
+ case MEM_RO:
+ printf_filtered ("ro ");
+ break;
+ case MEM_WO:
+ printf_filtered ("wo ");
+ break;
+ }
+
+ switch (attrib->width)
+ {
+ case MEM_WIDTH_8:
+ printf_filtered ("8 ");
+ break;
+ case MEM_WIDTH_16:
+ printf_filtered ("16 ");
+ break;
+ case MEM_WIDTH_32:
+ printf_filtered ("32 ");
+ break;
+ case MEM_WIDTH_64:
+ printf_filtered ("64 ");
+ break;
+ case MEM_WIDTH_UNSPECIFIED:
+ break;
+ }
+
+#if 0
+ if (attrib->hwbreak)
+ printf_filtered ("hwbreak");
+ else
+ printf_filtered ("swbreak");
+#endif
+
+ if (attrib->cache)
+ printf_filtered ("cache ");
+ else
+ printf_filtered ("nocache ");
+
+#if 0
+ if (attrib->verify)
+ printf_filtered ("verify ");
+ else
+ printf_filtered ("noverify ");
+#endif
+
+ printf_filtered ("\n");
+
+ gdb_flush (gdb_stdout);
+ }
+}
+
+
+/* Enable the memory region number NUM. */
+
+static void
+mem_enable (int num)
+{
+ struct mem_region *m;
+
+ for (m = mem_region_chain; m; m = m->next)
+ if (m->number == num)
+ {
+ m->enabled_p = 1;
+ return;
+ }
+ printf_unfiltered ("No memory region number %d.\n", num);
+}
+
+static void
+mem_enable_command (char *args, int from_tty)
+{
+ char *p = args;
+ char *p1;
+ int num;
+ struct mem_region *m;
+
+ dcache_invalidate (target_dcache);
+
+ if (p == 0)
+ {
+ for (m = mem_region_chain; m; m = m->next)
+ m->enabled_p = 1;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be memory region numbers.");
+
+ num = atoi (p);
+ mem_enable (num);
+
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+
+/* Disable the memory region number NUM. */
+
+static void
+mem_disable (int num)
+{
+ struct mem_region *m;
+
+ for (m = mem_region_chain; m; m = m->next)
+ if (m->number == num)
+ {
+ m->enabled_p = 0;
+ return;
+ }
+ printf_unfiltered ("No memory region number %d.\n", num);
+}
+
+static void
+mem_disable_command (char *args, int from_tty)
+{
+ char *p = args;
+ char *p1;
+ int num;
+ struct mem_region *m;
+
+ dcache_invalidate (target_dcache);
+
+ if (p == 0)
+ {
+ for (m = mem_region_chain; m; m = m->next)
+ m->enabled_p = 0;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be memory region numbers.");
+
+ num = atoi (p);
+ mem_disable (num);
+
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+/* Clear memory region list */
+
+static void
+mem_clear (void)
+{
+ struct mem_region *m;
+
+ while ((m = mem_region_chain) != 0)
+ {
+ mem_region_chain = m->next;
+ delete_mem_region (m);
+ }
+}
+
+/* Delete the memory region number NUM. */
+
+static void
+mem_delete (int num)
+{
+ struct mem_region *m1, *m;
+
+ if (!mem_region_chain)
+ {
+ printf_unfiltered ("No memory region number %d.\n", num);
+ return;
+ }
+
+ if (mem_region_chain->number == num)
+ {
+ m1 = mem_region_chain;
+ mem_region_chain = m1->next;
+ delete_mem_region (m1);
+ }
+ else
+ for (m = mem_region_chain; m->next; m = m->next)
+ {
+ if (m->next->number == num)
+ {
+ m1 = m->next;
+ m->next = m1->next;
+ delete_mem_region (m1);
+ break;
+ }
+ }
+}
+
+static void
+mem_delete_command (char *args, int from_tty)
+{
+ char *p = args;
+ char *p1;
+ int num;
+
+ dcache_invalidate (target_dcache);
+
+ if (p == 0)
+ {
+ if (query ("Delete all memory regions? "))
+ mem_clear ();
+ dont_repeat ();
+ return;
+ }
+
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be memory region numbers.");
+
+ num = atoi (p);
+ mem_delete (num);
+
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+
+ dont_repeat ();
+}
+
+extern initialize_file_ftype _initialize_mem; /* -Wmissing-prototype */
+
+void
+_initialize_mem (void)
+{
+ add_com ("mem", class_vars, mem_command,
+ "Define attributes for memory region.\n\
+Usage: mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\
+where <mode> may be rw (read/write), ro (read-only) or wo (write-only), \n\
+ <width> may be 8, 16, 32, or 64, and \n\
+ <cache> may be cache or nocache");
+
+ add_cmd ("mem", class_vars, mem_enable_command,
+ "Enable memory region.\n\
+Arguments are the code numbers of the memory regions to enable.\n\
+Usage: enable mem <code number>\n\
+Do \"info mem\" to see current list of code numbers.", &enablelist);
+
+ add_cmd ("mem", class_vars, mem_disable_command,
+ "Disable memory region.\n\
+Arguments are the code numbers of the memory regions to disable.\n\
+Usage: disable mem <code number>\n\
+Do \"info mem\" to see current list of code numbers.", &disablelist);
+
+ add_cmd ("mem", class_vars, mem_delete_command,
+ "Delete memory region.\n\
+Arguments are the code numbers of the memory regions to delete.\n\
+Usage: delete mem <code number>\n\
+Do \"info mem\" to see current list of code numbers.", &deletelist);
+
+ add_info ("mem", mem_info_command,
+ "Memory region attributes");
+}
diff --git a/contrib/gdb/gdb/memattr.h b/contrib/gdb/gdb/memattr.h
new file mode 100644
index 0000000..8643a23
--- /dev/null
+++ b/contrib/gdb/gdb/memattr.h
@@ -0,0 +1,91 @@
+/* Memory attributes support, for GDB.
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MEMATTR_H
+#define MEMATTR_H
+
+enum mem_access_mode
+{
+ MEM_RW, /* read/write */
+ MEM_RO, /* read only */
+ MEM_WO /* write only */
+};
+
+enum mem_access_width
+{
+ MEM_WIDTH_UNSPECIFIED,
+ MEM_WIDTH_8, /* 8 bit accesses */
+ MEM_WIDTH_16, /* 16 " " */
+ MEM_WIDTH_32, /* 32 " " */
+ MEM_WIDTH_64 /* 64 " " */
+};
+
+/* The set of all attributes that can be set for a memory region.
+
+ This structure was created so that memory attributes can be passed
+ to target_ functions without exposing the details of memory region
+ list, which would be necessary if these fields were simply added to
+ the mem_region structure.
+
+ FIXME: It would be useful if there was a mechanism for targets to
+ add their own attributes. For example, the number of wait states. */
+
+struct mem_attrib
+{
+ /* read/write, read-only, or write-only */
+ enum mem_access_mode mode;
+
+ enum mem_access_width width;
+
+ /* enables hardware breakpoints */
+ int hwbreak;
+
+ /* enables host-side caching of memory region data */
+ int cache;
+
+ /* enables memory verification. after a write, memory is re-read
+ to verify that the write was successful. */
+ int verify;
+};
+
+struct mem_region
+{
+ /* FIXME: memory regions are stored in an unsorted singly-linked
+ list. This probably won't scale to handle hundreds of memory
+ regions --- that many could be needed to describe the allowed
+ access modes for memory mapped i/o device registers. */
+ struct mem_region *next;
+
+ CORE_ADDR lo;
+ CORE_ADDR hi;
+
+ /* Item number of this memory region. */
+ int number;
+
+ /* Status of this memory region (enabled if non-zero, otherwise disabled) */
+ int enabled_p;
+
+ /* Attributes for this region */
+ struct mem_attrib attrib;
+};
+
+extern struct mem_region *lookup_mem_region(CORE_ADDR);
+
+#endif /* MEMATTR_H */
diff --git a/contrib/gdb/gdb/mi/mi-cmd-break.c b/contrib/gdb/gdb/mi/mi-cmd-break.c
new file mode 100644
index 0000000..5d15aa9
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmd-break.c
@@ -0,0 +1,240 @@
+/* MI Command Set - breakpoint and watchpoint commands.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mi-cmds.h"
+#include "ui-out.h"
+#include "mi-out.h"
+#include "breakpoint.h"
+#include "gdb_string.h"
+#include "mi-getopt.h"
+#include "gdb-events.h"
+#include "gdb.h"
+
+enum
+ {
+ FROM_TTY = 0
+ };
+
+/* Output a single breakpoint. */
+
+static void
+breakpoint_notify (int b)
+{
+ gdb_breakpoint_query (uiout, b);
+}
+
+
+struct gdb_events breakpoint_hooks =
+{
+ breakpoint_notify,
+ breakpoint_notify,
+ breakpoint_notify,
+};
+
+
+enum bp_type
+ {
+ REG_BP,
+ HW_BP,
+ REGEXP_BP
+ };
+
+/* Insert a breakpoint. The type of breakpoint is specified by the
+ first argument: -break-insert <location> --> insert a regular
+ breakpoint. -break-insert -t <location> --> insert a temporary
+ breakpoint. -break-insert -h <location> --> insert an hardware
+ breakpoint. -break-insert -t -h <location> --> insert a temporary
+ hw bp.
+ -break-insert -r <regexp> --> insert a bp at functions matching
+ <regexp> */
+
+enum mi_cmd_result
+mi_cmd_break_insert (char *command, char **argv, int argc)
+{
+ char *address = NULL;
+ enum bp_type type = REG_BP;
+ int temp_p = 0;
+ int thread = -1;
+ int ignore_count = 0;
+ char *condition = NULL;
+ enum gdb_rc rc;
+ struct gdb_events *old_hooks;
+ enum opt
+ {
+ HARDWARE_OPT, TEMP_OPT /*, REGEXP_OPT */ , CONDITION_OPT,
+ IGNORE_COUNT_OPT, THREAD_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"h", HARDWARE_OPT, 0},
+ {"t", TEMP_OPT, 0},
+ {"c", CONDITION_OPT, 1},
+ {"i", IGNORE_COUNT_OPT, 1},
+ {"p", THREAD_OPT, 1},
+ 0
+ };
+
+ /* Parse arguments. It could be -r or -h or -t, <location> or ``--''
+ to denote the end of the option list. */
+ int optind = 0;
+ char *optarg;
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_break_insert", argc, argv, opts, &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case TEMP_OPT:
+ temp_p = 1;
+ break;
+ case HARDWARE_OPT:
+ type = HW_BP;
+ break;
+#if 0
+ case REGEXP_OPT:
+ type = REGEXP_BP;
+ break;
+#endif
+ case CONDITION_OPT:
+ condition = optarg;
+ break;
+ case IGNORE_COUNT_OPT:
+ ignore_count = atol (optarg);
+ break;
+ case THREAD_OPT:
+ thread = atol (optarg);
+ break;
+ }
+ }
+
+ if (optind >= argc)
+ error ("mi_cmd_break_insert: Missing <location>");
+ if (optind < argc - 1)
+ error ("mi_cmd_break_insert: Garbage following <location>");
+ address = argv[optind];
+
+ /* Now we have what we need, let's insert the breakpoint! */
+ old_hooks = set_gdb_event_hooks (&breakpoint_hooks);
+ switch (type)
+ {
+ case REG_BP:
+ rc = gdb_breakpoint (address, condition,
+ 0 /*hardwareflag */ , temp_p,
+ thread, ignore_count);
+ break;
+ case HW_BP:
+ rc = gdb_breakpoint (address, condition,
+ 1 /*hardwareflag */ , temp_p,
+ thread, ignore_count);
+ break;
+#if 0
+ case REGEXP_BP:
+ if (temp_p)
+ error ("mi_cmd_break_insert: Unsupported tempoary regexp breakpoint");
+ else
+ rbreak_command_wrapper (address, FROM_TTY);
+ return MI_CMD_DONE;
+ break;
+#endif
+ default:
+ internal_error (__FILE__, __LINE__,
+ "mi_cmd_break_insert: Bad switch.");
+ }
+ set_gdb_event_hooks (old_hooks);
+
+ if (rc == GDB_RC_FAIL)
+ return MI_CMD_CAUGHT_ERROR;
+ else
+ return MI_CMD_DONE;
+}
+
+enum wp_type
+{
+ REG_WP,
+ READ_WP,
+ ACCESS_WP
+};
+
+/* Insert a watchpoint. The type of watchpoint is specified by the
+ first argument:
+ -break-watch <expr> --> insert a regular wp.
+ -break-watch -r <expr> --> insert a read watchpoint.
+ -break-watch -a <expr> --> insert an access wp. */
+
+enum mi_cmd_result
+mi_cmd_break_watch (char *command, char **argv, int argc)
+{
+ char *expr = NULL;
+ enum wp_type type = REG_WP;
+ enum opt
+ {
+ READ_OPT, ACCESS_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"r", READ_OPT, 0},
+ {"a", ACCESS_OPT, 0},
+ 0
+ };
+
+ /* Parse arguments. */
+ int optind = 0;
+ char *optarg;
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_break_watch", argc, argv, opts, &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case READ_OPT:
+ type = READ_WP;
+ break;
+ case ACCESS_OPT:
+ type = ACCESS_WP;
+ break;
+ }
+ }
+ if (optind >= argc)
+ error ("mi_cmd_break_watch: Missing <expression>");
+ if (optind < argc - 1)
+ error ("mi_cmd_break_watch: Garbage following <expression>");
+ expr = argv[optind];
+
+ /* Now we have what we need, let's insert the watchpoint! */
+ switch (type)
+ {
+ case REG_WP:
+ watch_command_wrapper (expr, FROM_TTY);
+ break;
+ case READ_WP:
+ rwatch_command_wrapper (expr, FROM_TTY);
+ break;
+ case ACCESS_WP:
+ awatch_command_wrapper (expr, FROM_TTY);
+ break;
+ default:
+ error ("mi_cmd_break_watch: Unknown watchpoint type.");
+ }
+ return MI_CMD_DONE;
+}
diff --git a/contrib/gdb/gdb/mi/mi-cmd-disas.c b/contrib/gdb/gdb/mi/mi-cmd-disas.c
new file mode 100644
index 0000000..168ca17
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmd-disas.c
@@ -0,0 +1,163 @@
+/* MI Command Set - disassemble commands.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "target.h"
+#include "value.h"
+#include "mi-cmds.h"
+#include "mi-getopt.h"
+#include "gdb_string.h"
+#include "ui-out.h"
+#include "disasm.h"
+
+/* The arguments to be passed on the command line and parsed here are:
+
+ either:
+
+ START-ADDRESS: address to start the disassembly at.
+ END-ADDRESS: address to end the disassembly at.
+
+ or:
+
+ FILENAME: The name of the file where we want disassemble from.
+ LINE: The line around which we want to disassemble. It will
+ disassemble the function that contins that line.
+ HOW_MANY: Number of disassembly lines to display. In mixed mode, it
+ is the number of disassembly lines only, not counting the source
+ lines.
+
+ always required:
+
+ MODE: 0 or 1 for disassembly only, or mixed source and disassembly,
+ respectively. */
+enum mi_cmd_result
+mi_cmd_disassemble (char *command, char **argv, int argc)
+{
+ enum mi_cmd_result retval;
+ CORE_ADDR start;
+
+ int mixed_source_and_assembly;
+ struct symtab *s;
+
+ /* Which options have we processed ... */
+ int file_seen = 0;
+ int line_seen = 0;
+ int num_seen = 0;
+ int start_seen = 0;
+ int end_seen = 0;
+
+ /* ... and their corresponding value. */
+ char *file_string = NULL;
+ int line_num = -1;
+ int how_many = -1;
+ CORE_ADDR low = 0;
+ CORE_ADDR high = 0;
+
+ /* Options processing stuff. */
+ int optind = 0;
+ char *optarg;
+ enum opt
+ {
+ FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT
+ };
+ static struct mi_opt opts[] = {
+ {"f", FILE_OPT, 1},
+ {"l", LINE_OPT, 1},
+ {"n", NUM_OPT, 1},
+ {"s", START_OPT, 1},
+ {"e", END_OPT, 1},
+ 0
+ };
+
+ /* Get the options with their arguments. Keep track of what we
+ encountered. */
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_disassemble", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case FILE_OPT:
+ file_string = xstrdup (optarg);
+ file_seen = 1;
+ break;
+ case LINE_OPT:
+ line_num = atoi (optarg);
+ line_seen = 1;
+ break;
+ case NUM_OPT:
+ how_many = atoi (optarg);
+ num_seen = 1;
+ break;
+ case START_OPT:
+ low = parse_and_eval_address (optarg);
+ start_seen = 1;
+ break;
+ case END_OPT:
+ high = parse_and_eval_address (optarg);
+ end_seen = 1;
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ /* Allow only filename + linenum (with how_many which is not
+ required) OR start_addr + and_addr */
+
+ if (!((line_seen && file_seen && num_seen && !start_seen && !end_seen)
+ || (line_seen && file_seen && !num_seen && !start_seen && !end_seen)
+ || (!line_seen && !file_seen && !num_seen && start_seen && end_seen)))
+ error
+ ("mi_cmd_disassemble: Usage: ( [-f filename -l linenum [-n howmany]] | [-s startaddr -e endaddr]) [--] mixed_mode.");
+
+ if (argc != 1)
+ error
+ ("mi_cmd_disassemble: Usage: [-f filename -l linenum [-n howmany]] [-s startaddr -e endaddr] [--] mixed_mode.");
+
+ mixed_source_and_assembly = atoi (argv[0]);
+ if ((mixed_source_and_assembly != 0) && (mixed_source_and_assembly != 1))
+ error ("mi_cmd_disassemble: Mixed_mode argument must be 0 or 1.");
+
+
+ /* We must get the function beginning and end where line_num is
+ contained. */
+
+ if (line_seen && file_seen)
+ {
+ s = lookup_symtab (file_string);
+ if (s == NULL)
+ error ("mi_cmd_disassemble: Invalid filename.");
+ if (!find_line_pc (s, line_num, &start))
+ error ("mi_cmd_disassemble: Invalid line number");
+ if (find_pc_partial_function (start, NULL, &low, &high) == 0)
+ error ("mi_cmd_disassemble: No function contains specified address");
+ }
+
+ gdb_disassembly (uiout,
+ file_string,
+ line_num,
+ mixed_source_and_assembly, how_many, low, high);
+
+ return MI_CMD_DONE;
+}
diff --git a/contrib/gdb/gdb/mi/mi-cmd-env.c b/contrib/gdb/gdb/mi/mi-cmd-env.c
new file mode 100644
index 0000000..439c719
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmd-env.c
@@ -0,0 +1,259 @@
+/* MI Command Set - environment commands.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Red Hat Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "value.h"
+#include "mi-out.h"
+#include "mi-cmds.h"
+#include "mi-getopt.h"
+#include "symtab.h"
+#include "target.h"
+#include "environ.h"
+#include "command.h"
+#include "ui-out.h"
+#include "top.h"
+
+#include "gdb_string.h"
+#include "gdb_stat.h"
+
+static void env_mod_path (char *dirname, char **which_path);
+extern void _initialize_mi_cmd_env (void);
+
+static const char path_var_name[] = "PATH";
+static char *orig_path = NULL;
+
+/* The following is copied from mi-main.c so for m1 and below we can
+ perform old behavior and use cli commands. If ARGS is non-null,
+ append it to the CMD. */
+static void
+env_execute_cli_command (const char *cmd, const char *args)
+{
+ if (cmd != 0)
+ {
+ struct cleanup *old_cleanups;
+ char *run;
+ if (args != NULL)
+ xasprintf (&run, "%s %s", cmd, args);
+ else
+ run = xstrdup (cmd);
+ old_cleanups = make_cleanup (xfree, run);
+ execute_command ( /*ui */ run, 0 /*from_tty */ );
+ do_cleanups (old_cleanups);
+ return;
+ }
+}
+
+
+/* Print working directory. */
+enum mi_cmd_result
+mi_cmd_env_pwd (char *command, char **argv, int argc)
+{
+ if (argc > 0)
+ error ("mi_cmd_env_pwd: No arguments required");
+
+ if (mi_version (uiout) < 2)
+ {
+ env_execute_cli_command ("pwd", NULL);
+ return MI_CMD_DONE;
+ }
+
+ /* Otherwise the mi level is 2 or higher. */
+
+ getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+ ui_out_field_string (uiout, "cwd", gdb_dirbuf);
+
+ return MI_CMD_DONE;
+}
+
+/* Change working directory. */
+enum mi_cmd_result
+mi_cmd_env_cd (char *command, char **argv, int argc)
+{
+ if (argc == 0 || argc > 1)
+ error ("mi_cmd_env_cd: Usage DIRECTORY");
+
+ env_execute_cli_command ("cd", argv[0]);
+
+ return MI_CMD_DONE;
+}
+
+static void
+env_mod_path (char *dirname, char **which_path)
+{
+ if (dirname == 0 || dirname[0] == '\0')
+ return;
+
+ /* Call add_path with last arg 0 to indicate not to parse for
+ separator characters. */
+ add_path (dirname, which_path, 0);
+}
+
+/* Add one or more directories to start of executable search path. */
+enum mi_cmd_result
+mi_cmd_env_path (char *command, char **argv, int argc)
+{
+ char *exec_path;
+ char *env;
+ int reset = 0;
+ int optind = 0;
+ int i;
+ char *optarg;
+ enum opt
+ {
+ RESET_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"r", RESET_OPT, 0},
+ 0
+ };
+
+ dont_repeat ();
+
+ if (mi_version (uiout) < 2)
+ {
+ for (i = argc - 1; i >= 0; --i)
+ env_execute_cli_command ("path", argv[i]);
+ return MI_CMD_DONE;
+ }
+
+ /* Otherwise the mi level is 2 or higher. */
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_env_path", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case RESET_OPT:
+ reset = 1;
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+
+ if (reset)
+ {
+ /* Reset implies resetting to original path first. */
+ exec_path = xstrdup (orig_path);
+ }
+ else
+ {
+ /* Otherwise, get current path to modify. */
+ env = get_in_environ (inferior_environ, path_var_name);
+
+ /* Can be null if path is not set. */
+ if (!env)
+ env = "";
+ exec_path = xstrdup (env);
+ }
+
+ for (i = argc - 1; i >= 0; --i)
+ env_mod_path (argv[i], &exec_path);
+
+ set_in_environ (inferior_environ, path_var_name, exec_path);
+ xfree (exec_path);
+ env = get_in_environ (inferior_environ, path_var_name);
+ ui_out_field_string (uiout, "path", env);
+
+ return MI_CMD_DONE;
+}
+
+/* Add zero or more directories to the front of the source path. */
+enum mi_cmd_result
+mi_cmd_env_dir (char *command, char **argv, int argc)
+{
+ int i;
+ int optind = 0;
+ int reset = 0;
+ char *optarg;
+ enum opt
+ {
+ RESET_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"r", RESET_OPT, 0},
+ 0
+ };
+
+ dont_repeat ();
+
+ if (mi_version (uiout) < 2)
+ {
+ for (i = argc - 1; i >= 0; --i)
+ env_execute_cli_command ("dir", argv[i]);
+ return MI_CMD_DONE;
+ }
+
+ /* Otherwise mi level is 2 or higher. */
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_env_dir", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case RESET_OPT:
+ reset = 1;
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (reset)
+ {
+ /* Reset means setting to default path first. */
+ xfree (source_path);
+ init_source_path ();
+ }
+
+ for (i = argc - 1; i >= 0; --i)
+ env_mod_path (argv[i], &source_path);
+ init_last_source_visited ();
+
+ ui_out_field_string (uiout, "source-path", source_path);
+ forget_cached_source_info ();
+
+ return MI_CMD_DONE;
+}
+
+void
+_initialize_mi_cmd_env (void)
+{
+ char *env;
+
+ /* We want original execution path to reset to, if desired later. */
+ env = get_in_environ (inferior_environ, path_var_name);
+
+ /* Can be null if path is not set. */
+ if (!env)
+ env = "";
+ orig_path = xstrdup (env);
+}
diff --git a/contrib/gdb/gdb/mi/mi-cmd-file.c b/contrib/gdb/gdb/mi/mi-cmd-file.c
new file mode 100644
index 0000000..eb1d67a
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmd-file.c
@@ -0,0 +1,67 @@
+/* MI Command Set - breakpoint and watchpoint commands.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mi-cmds.h"
+#include "mi-getopt.h"
+#include "ui-out.h"
+#include "symtab.h"
+#include "source.h"
+
+/* Return to the client the absolute path and line number of the
+ current file being executed. */
+
+enum mi_cmd_result
+mi_cmd_file_list_exec_source_file(char *command, char **argv, int argc)
+{
+ struct symtab_and_line st;
+ int optind = 0;
+ char *optarg;
+
+ if ( !mi_valid_noargs("mi_cmd_file_list_exec_source_file", argc, argv) )
+ error ("mi_cmd_file_list_exec_source_file: Usage: No args");
+
+
+ /* Set the default file and line, also get them */
+ set_default_source_symtab_and_line();
+ st = get_current_source_symtab_and_line();
+
+ /* We should always get a symtab.
+ Apparently, filename does not need to be tested for NULL.
+ The documentation in symtab.h suggests it will always be correct */
+ if (!st.symtab)
+ error ("mi_cmd_file_list_exec_source_file: No symtab");
+
+ /* Extract the fullname if it is not known yet */
+ if (st.symtab->fullname == NULL)
+ symtab_to_filename (st.symtab);
+
+ /* We may not be able to open the file (not available). */
+ if (st.symtab->fullname == NULL)
+ error ("mi_cmd_file_list_exec_source_file: File not found");
+
+ /* Print to the user the line, filename and fullname */
+ ui_out_field_int (uiout, "line", st.line);
+ ui_out_field_string (uiout, "file", st.symtab->filename);
+ ui_out_field_string (uiout, "fullname", st.symtab->fullname);
+
+ return MI_CMD_DONE;
+}
diff --git a/contrib/gdb/gdb/mi/mi-cmd-stack.c b/contrib/gdb/gdb/mi/mi-cmd-stack.c
new file mode 100644
index 0000000..7db9ffb
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmd-stack.c
@@ -0,0 +1,349 @@
+/* MI Command Set - stack commands.
+ Copyright 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "target.h"
+#include "frame.h"
+#include "value.h"
+#include "mi-cmds.h"
+#include "ui-out.h"
+#include "symtab.h"
+#include "block.h"
+#include "stack.h"
+#include "dictionary.h"
+#include "gdb_string.h"
+
+static void list_args_or_locals (int locals, int values, struct frame_info *fi);
+
+/* Print a list of the stack frames. Args can be none, in which case
+ we want to print the whole backtrace, or a pair of numbers
+ specifying the frame numbers at which to start and stop the
+ display. If the two numbers are equal, a single frame will be
+ displayed. */
+enum mi_cmd_result
+mi_cmd_stack_list_frames (char *command, char **argv, int argc)
+{
+ int frame_low;
+ int frame_high;
+ int i;
+ struct cleanup *cleanup_stack;
+ struct frame_info *fi;
+
+ if (!target_has_stack)
+ error ("mi_cmd_stack_list_frames: No stack.");
+
+ if (argc > 2 || argc == 1)
+ error ("mi_cmd_stack_list_frames: Usage: [FRAME_LOW FRAME_HIGH]");
+
+ if (argc == 2)
+ {
+ frame_low = atoi (argv[0]);
+ frame_high = atoi (argv[1]);
+ }
+ else
+ {
+ /* Called with no arguments, it means we want the whole
+ backtrace. */
+ frame_low = -1;
+ frame_high = -1;
+ }
+
+ /* Let's position fi on the frame at which to start the
+ display. Could be the innermost frame if the whole stack needs
+ displaying, or if frame_low is 0. */
+ for (i = 0, fi = get_current_frame ();
+ fi && i < frame_low;
+ i++, fi = get_prev_frame (fi));
+
+ if (fi == NULL)
+ error ("mi_cmd_stack_list_frames: Not enough frames in stack.");
+
+ cleanup_stack = make_cleanup_ui_out_list_begin_end (uiout, "stack");
+
+ /* Now let;s print the frames up to frame_high, or until there are
+ frames in the stack. */
+ for (;
+ fi && (i <= frame_high || frame_high == -1);
+ i++, fi = get_prev_frame (fi))
+ {
+ QUIT;
+ /* level == i: always print the level 'i'
+ source == LOC_AND_ADDRESS: print the location and the address
+ always, even for level 0.
+ args == 0: don't print the arguments. */
+ print_frame_info (fi /* frame info */ ,
+ i /* level */ ,
+ LOC_AND_ADDRESS /* source */ ,
+ 0 /* args */ );
+ }
+
+ do_cleanups (cleanup_stack);
+ if (i < frame_high)
+ error ("mi_cmd_stack_list_frames: Not enough frames in stack.");
+
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_stack_info_depth (char *command, char **argv, int argc)
+{
+ int frame_high;
+ int i;
+ struct frame_info *fi;
+
+ if (!target_has_stack)
+ error ("mi_cmd_stack_info_depth: No stack.");
+
+ if (argc > 1)
+ error ("mi_cmd_stack_info_depth: Usage: [MAX_DEPTH]");
+
+ if (argc == 1)
+ frame_high = atoi (argv[0]);
+ else
+ /* Called with no arguments, it means we want the real depth of
+ the stack. */
+ frame_high = -1;
+
+ for (i = 0, fi = get_current_frame ();
+ fi && (i < frame_high || frame_high == -1);
+ i++, fi = get_prev_frame (fi))
+ QUIT;
+
+ ui_out_field_int (uiout, "depth", i);
+
+ return MI_CMD_DONE;
+}
+
+/* Print a list of the locals for the current frame. With argument of
+ 0, print only the names, with argument of 1 print also the
+ values. */
+enum mi_cmd_result
+mi_cmd_stack_list_locals (char *command, char **argv, int argc)
+{
+ struct frame_info *frame;
+ enum print_values print_values;
+
+ if (argc != 1)
+ error ("mi_cmd_stack_list_locals: Usage: PRINT_VALUES");
+
+ frame = get_selected_frame ();
+
+ if (strcmp (argv[0], "0") == 0
+ || strcmp (argv[0], "--no-values") == 0)
+ print_values = PRINT_NO_VALUES;
+ else if (strcmp (argv[0], "1") == 0
+ || strcmp (argv[0], "--all-values") == 0)
+ print_values = PRINT_ALL_VALUES;
+ else if (strcmp (argv[0], "2") == 0
+ || strcmp (argv[0], "--simple-values") == 0)
+ print_values = PRINT_SIMPLE_VALUES;
+ else
+ error ("Unknown value for PRINT_VALUES: must be: 0 or \"--no-values\", 1 or \"--all-values\", 2 or \"--simple-values\"");
+ list_args_or_locals (1, print_values, frame);
+ return MI_CMD_DONE;
+}
+
+/* Print a list of the arguments for the current frame. With argument
+ of 0, print only the names, with argument of 1 print also the
+ values. */
+enum mi_cmd_result
+mi_cmd_stack_list_args (char *command, char **argv, int argc)
+{
+ int frame_low;
+ int frame_high;
+ int i;
+ struct frame_info *fi;
+ struct cleanup *cleanup_stack_args;
+
+ if (argc < 1 || argc > 3 || argc == 2)
+ error ("mi_cmd_stack_list_args: Usage: PRINT_VALUES [FRAME_LOW FRAME_HIGH]");
+
+ if (argc == 3)
+ {
+ frame_low = atoi (argv[1]);
+ frame_high = atoi (argv[2]);
+ }
+ else
+ {
+ /* Called with no arguments, it means we want args for the whole
+ backtrace. */
+ frame_low = -1;
+ frame_high = -1;
+ }
+
+ /* Let's position fi on the frame at which to start the
+ display. Could be the innermost frame if the whole stack needs
+ displaying, or if frame_low is 0. */
+ for (i = 0, fi = get_current_frame ();
+ fi && i < frame_low;
+ i++, fi = get_prev_frame (fi));
+
+ if (fi == NULL)
+ error ("mi_cmd_stack_list_args: Not enough frames in stack.");
+
+ cleanup_stack_args = make_cleanup_ui_out_list_begin_end (uiout, "stack-args");
+
+ /* Now let's print the frames up to frame_high, or until there are
+ frames in the stack. */
+ for (;
+ fi && (i <= frame_high || frame_high == -1);
+ i++, fi = get_prev_frame (fi))
+ {
+ struct cleanup *cleanup_frame;
+ QUIT;
+ cleanup_frame = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
+ ui_out_field_int (uiout, "level", i);
+ list_args_or_locals (0, atoi (argv[0]), fi);
+ do_cleanups (cleanup_frame);
+ }
+
+ do_cleanups (cleanup_stack_args);
+ if (i < frame_high)
+ error ("mi_cmd_stack_list_args: Not enough frames in stack.");
+
+ return MI_CMD_DONE;
+}
+
+/* Print a list of the locals or the arguments for the currently
+ selected frame. If the argument passed is 0, printonly the names
+ of the variables, if an argument of 1 is passed, print the values
+ as well. */
+static void
+list_args_or_locals (int locals, int values, struct frame_info *fi)
+{
+ struct block *block;
+ struct symbol *sym;
+ struct dict_iterator iter;
+ int nsyms;
+ struct cleanup *cleanup_list;
+ static struct ui_stream *stb = NULL;
+ struct type *type;
+
+ stb = ui_out_stream_new (uiout);
+
+ block = get_frame_block (fi, 0);
+
+ cleanup_list = make_cleanup_ui_out_list_begin_end (uiout, locals ? "locals" : "args");
+
+ while (block != 0)
+ {
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ int print_me = 0;
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ default:
+ case LOC_UNDEF: /* catches errors */
+ case LOC_CONST: /* constant */
+ case LOC_TYPEDEF: /* local typedef */
+ case LOC_LABEL: /* local label */
+ case LOC_BLOCK: /* local function */
+ case LOC_CONST_BYTES: /* loc. byte seq. */
+ case LOC_UNRESOLVED: /* unresolved static */
+ case LOC_OPTIMIZED_OUT: /* optimized out */
+ print_me = 0;
+ break;
+
+ case LOC_ARG: /* argument */
+ case LOC_REF_ARG: /* reference arg */
+ case LOC_REGPARM: /* register arg */
+ case LOC_REGPARM_ADDR: /* indirect register arg */
+ case LOC_LOCAL_ARG: /* stack arg */
+ case LOC_BASEREG_ARG: /* basereg arg */
+ case LOC_COMPUTED_ARG: /* arg with computed location */
+ if (!locals)
+ print_me = 1;
+ break;
+
+ case LOC_LOCAL: /* stack local */
+ case LOC_BASEREG: /* basereg local */
+ case LOC_STATIC: /* static */
+ case LOC_REGISTER: /* register */
+ case LOC_COMPUTED: /* computed location */
+ if (locals)
+ print_me = 1;
+ break;
+ }
+ if (print_me)
+ {
+ struct cleanup *cleanup_tuple = NULL;
+ struct symbol *sym2;
+ if (values != PRINT_NO_VALUES)
+ cleanup_tuple =
+ make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_string (uiout, "name", SYMBOL_PRINT_NAME (sym));
+
+ if (!locals)
+ sym2 = lookup_symbol (SYMBOL_NATURAL_NAME (sym),
+ block, VAR_DOMAIN,
+ (int *) NULL,
+ (struct symtab **) NULL);
+ else
+ sym2 = sym;
+ switch (values)
+ {
+ case PRINT_SIMPLE_VALUES:
+ type = check_typedef (sym2->type);
+ type_print (sym2->type, "", stb->stream, -1);
+ ui_out_field_stream (uiout, "type", stb);
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY
+ && TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ {
+ print_variable_value (sym2, fi, stb->stream);
+ ui_out_field_stream (uiout, "value", stb);
+ }
+ do_cleanups (cleanup_tuple);
+ break;
+ case PRINT_ALL_VALUES:
+ print_variable_value (sym2, fi, stb->stream);
+ ui_out_field_stream (uiout, "value", stb);
+ do_cleanups (cleanup_tuple);
+ break;
+ }
+ }
+ }
+ if (BLOCK_FUNCTION (block))
+ break;
+ else
+ block = BLOCK_SUPERBLOCK (block);
+ }
+ do_cleanups (cleanup_list);
+ ui_out_stream_delete (stb);
+}
+
+enum mi_cmd_result
+mi_cmd_stack_select_frame (char *command, char **argv, int argc)
+{
+ if (!target_has_stack)
+ error ("mi_cmd_stack_select_frame: No stack.");
+
+ if (argc > 1)
+ error ("mi_cmd_stack_select_frame: Usage: [FRAME_SPEC]");
+
+ /* with no args, don't change frame */
+ if (argc == 0)
+ select_frame_command (0, 1 /* not used */ );
+ else
+ select_frame_command (argv[0], 1 /* not used */ );
+ return MI_CMD_DONE;
+}
diff --git a/contrib/gdb/gdb/mi/mi-cmd-var.c b/contrib/gdb/gdb/mi/mi-cmd-var.c
new file mode 100644
index 0000000..709ed30
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmd-var.c
@@ -0,0 +1,538 @@
+/* MI Command Set - varobj commands.
+
+ Copyright 2000, 2002, 2004 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mi-cmds.h"
+#include "ui-out.h"
+#include "mi-out.h"
+#include "varobj.h"
+#include "value.h"
+#include <ctype.h>
+#include "gdb_string.h"
+
+extern int varobjdebug; /* defined in varobj.c */
+
+static int varobj_update_one (struct varobj *var);
+
+/* VAROBJ operations */
+
+enum mi_cmd_result
+mi_cmd_var_create (char *command, char **argv, int argc)
+{
+ CORE_ADDR frameaddr = 0;
+ struct varobj *var;
+ char *name;
+ char *frame;
+ char *expr;
+ char *type;
+ struct cleanup *old_cleanups;
+ enum varobj_type var_type;
+
+ if (argc != 3)
+ {
+ /* xasprintf (&mi_error_message,
+ "mi_cmd_var_create: Usage: .");
+ return MI_CMD_ERROR; */
+ error ("mi_cmd_var_create: Usage: NAME FRAME EXPRESSION.");
+ }
+
+ name = xstrdup (argv[0]);
+ /* Add cleanup for name. Must be free_current_contents as
+ name can be reallocated */
+ old_cleanups = make_cleanup (free_current_contents, &name);
+
+ frame = xstrdup (argv[1]);
+ old_cleanups = make_cleanup (xfree, frame);
+
+ expr = xstrdup (argv[2]);
+
+ if (strcmp (name, "-") == 0)
+ {
+ xfree (name);
+ name = varobj_gen_name ();
+ }
+ else if (!isalpha (*name))
+ error ("mi_cmd_var_create: name of object must begin with a letter");
+
+ if (strcmp (frame, "*") == 0)
+ var_type = USE_CURRENT_FRAME;
+ else if (strcmp (frame, "@") == 0)
+ var_type = USE_SELECTED_FRAME;
+ else
+ {
+ var_type = USE_SPECIFIED_FRAME;
+ frameaddr = string_to_core_addr (frame);
+ }
+
+ if (varobjdebug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Name=\"%s\", Frame=\"%s\" (0x%s), Expression=\"%s\"\n",
+ name, frame, paddr (frameaddr), expr);
+
+ var = varobj_create (name, expr, frameaddr, var_type);
+
+ if (var == NULL)
+ error ("mi_cmd_var_create: unable to create variable object");
+
+ ui_out_field_string (uiout, "name", name);
+ ui_out_field_int (uiout, "numchild", varobj_get_num_children (var));
+ type = varobj_get_type (var);
+ if (type == NULL)
+ ui_out_field_string (uiout, "type", "");
+ else
+ {
+ ui_out_field_string (uiout, "type", type);
+ xfree (type);
+ }
+
+ do_cleanups (old_cleanups);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_delete (char *command, char **argv, int argc)
+{
+ char *name;
+ char *expr;
+ struct varobj *var;
+ int numdel;
+ int children_only_p = 0;
+ struct cleanup *old_cleanups;
+
+ if (argc < 1 || argc > 2)
+ error ("mi_cmd_var_delete: Usage: [-c] EXPRESSION.");
+
+ name = xstrdup (argv[0]);
+ /* Add cleanup for name. Must be free_current_contents as
+ name can be reallocated */
+ old_cleanups = make_cleanup (free_current_contents, &name);
+
+ /* If we have one single argument it cannot be '-c' or any string
+ starting with '-'. */
+ if (argc == 1)
+ {
+ if (strcmp (name, "-c") == 0)
+ error ("mi_cmd_var_delete: Missing required argument after '-c': variable object name");
+ if (*name == '-')
+ error ("mi_cmd_var_delete: Illegal variable object name");
+ }
+
+ /* If we have 2 arguments they must be '-c' followed by a string
+ which would be the variable name. */
+ if (argc == 2)
+ {
+ expr = xstrdup (argv[1]);
+ if (strcmp (name, "-c") != 0)
+ error ("mi_cmd_var_delete: Invalid option.");
+ children_only_p = 1;
+ xfree (name);
+ name = xstrdup (expr);
+ xfree (expr);
+ }
+
+ /* If we didn't error out, now NAME contains the name of the
+ variable. */
+
+ var = varobj_get_handle (name);
+
+ if (var == NULL)
+ error ("mi_cmd_var_delete: Variable object not found.");
+
+ numdel = varobj_delete (var, NULL, children_only_p);
+
+ ui_out_field_int (uiout, "ndeleted", numdel);
+
+ do_cleanups (old_cleanups);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_set_format (char *command, char **argv, int argc)
+{
+ enum varobj_display_formats format;
+ int len;
+ struct varobj *var;
+ char *formspec;
+
+ if (argc != 2)
+ error ("mi_cmd_var_set_format: Usage: NAME FORMAT.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+
+ if (var == NULL)
+ error ("mi_cmd_var_set_format: Variable object not found");
+
+ formspec = xstrdup (argv[1]);
+ if (formspec == NULL)
+ error ("mi_cmd_var_set_format: Must specify the format as: \"natural\", \"binary\", \"decimal\", \"hexadecimal\", or \"octal\"");
+
+ len = strlen (formspec);
+
+ if (strncmp (formspec, "natural", len) == 0)
+ format = FORMAT_NATURAL;
+ else if (strncmp (formspec, "binary", len) == 0)
+ format = FORMAT_BINARY;
+ else if (strncmp (formspec, "decimal", len) == 0)
+ format = FORMAT_DECIMAL;
+ else if (strncmp (formspec, "hexadecimal", len) == 0)
+ format = FORMAT_HEXADECIMAL;
+ else if (strncmp (formspec, "octal", len) == 0)
+ format = FORMAT_OCTAL;
+ else
+ error ("mi_cmd_var_set_format: Unknown display format: must be: \"natural\", \"binary\", \"decimal\", \"hexadecimal\", or \"octal\"");
+
+ /* Set the format of VAR to given format */
+ varobj_set_display_format (var, format);
+
+ /* Report the new current format */
+ ui_out_field_string (uiout, "format", varobj_format_string[(int) format]);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_show_format (char *command, char **argv, int argc)
+{
+ enum varobj_display_formats format;
+ struct varobj *var;
+
+ if (argc != 1)
+ error ("mi_cmd_var_show_format: Usage: NAME.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_show_format: Variable object not found");
+
+ format = varobj_get_display_format (var);
+
+ /* Report the current format */
+ ui_out_field_string (uiout, "format", varobj_format_string[(int) format]);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_info_num_children (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+
+ if (argc != 1)
+ error ("mi_cmd_var_info_num_children: Usage: NAME.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_info_num_children: Variable object not found");
+
+ ui_out_field_int (uiout, "numchild", varobj_get_num_children (var));
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_list_children (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+ struct varobj **childlist;
+ struct varobj **cc;
+ struct cleanup *cleanup_children;
+ int numchild;
+ char *type;
+ enum print_values print_values;
+
+ if (argc != 1 && argc != 2)
+ error ("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ if (argc == 1) var = varobj_get_handle (argv[0]);
+ else var = varobj_get_handle (argv[1]);
+ if (var == NULL)
+ error ("Variable object not found");
+
+ numchild = varobj_list_children (var, &childlist);
+ ui_out_field_int (uiout, "numchild", numchild);
+ if (argc == 2)
+ if (strcmp (argv[0], "0") == 0
+ || strcmp (argv[0], "--no-values") == 0)
+ print_values = PRINT_NO_VALUES;
+ else if (strcmp (argv[0], "1") == 0
+ || strcmp (argv[0], "--all-values") == 0)
+ print_values = PRINT_ALL_VALUES;
+ else
+ error ("Unknown value for PRINT_VALUES: must be: 0 or \"--no-values\", 1 or \"--all-values\"");
+ else print_values = PRINT_NO_VALUES;
+
+ if (numchild <= 0)
+ return MI_CMD_DONE;
+
+ if (mi_version (uiout) == 1)
+ cleanup_children = make_cleanup_ui_out_tuple_begin_end (uiout, "children");
+ else
+ cleanup_children = make_cleanup_ui_out_list_begin_end (uiout, "children");
+ cc = childlist;
+ while (*cc != NULL)
+ {
+ struct cleanup *cleanup_child;
+ cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, "child");
+ ui_out_field_string (uiout, "name", varobj_get_objname (*cc));
+ ui_out_field_string (uiout, "exp", varobj_get_expression (*cc));
+ ui_out_field_int (uiout, "numchild", varobj_get_num_children (*cc));
+ if (print_values)
+ ui_out_field_string (uiout, "value", varobj_get_value (*cc));
+ type = varobj_get_type (*cc);
+ /* C++ pseudo-variables (public, private, protected) do not have a type */
+ if (type)
+ ui_out_field_string (uiout, "type", varobj_get_type (*cc));
+ do_cleanups (cleanup_child);
+ cc++;
+ }
+ do_cleanups (cleanup_children);
+ xfree (childlist);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_info_type (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+
+ if (argc != 1)
+ error ("mi_cmd_var_info_type: Usage: NAME.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_info_type: Variable object not found");
+
+ ui_out_field_string (uiout, "type", varobj_get_type (var));
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_info_expression (char *command, char **argv, int argc)
+{
+ enum varobj_languages lang;
+ struct varobj *var;
+
+ if (argc != 1)
+ error ("mi_cmd_var_info_expression: Usage: NAME.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_info_expression: Variable object not found");
+
+ lang = varobj_get_language (var);
+
+ ui_out_field_string (uiout, "lang", varobj_language_string[(int) lang]);
+ ui_out_field_string (uiout, "exp", varobj_get_expression (var));
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_show_attributes (char *command, char **argv, int argc)
+{
+ int attr;
+ char *attstr;
+ struct varobj *var;
+
+ if (argc != 1)
+ error ("mi_cmd_var_show_attributes: Usage: NAME.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_show_attributes: Variable object not found");
+
+ attr = varobj_get_attributes (var);
+ /* FIXME: define masks for attributes */
+ if (attr & 0x00000001)
+ attstr = "editable";
+ else
+ attstr = "noneditable";
+
+ ui_out_field_string (uiout, "attr", attstr);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_evaluate_expression (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+
+ if (argc != 1)
+ error ("mi_cmd_var_evaluate_expression: Usage: NAME.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_evaluate_expression: Variable object not found");
+
+ ui_out_field_string (uiout, "value", varobj_get_value (var));
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_assign (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+ char *expression;
+
+ if (argc != 2)
+ error ("mi_cmd_var_assign: Usage: NAME EXPRESSION.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_assign: Variable object not found");
+
+ /* FIXME: define masks for attributes */
+ if (!(varobj_get_attributes (var) & 0x00000001))
+ error ("mi_cmd_var_assign: Variable object is not editable");
+
+ expression = xstrdup (argv[1]);
+
+ if (!varobj_set_value (var, expression))
+ error ("mi_cmd_var_assign: Could not assign expression to varible object");
+
+ ui_out_field_string (uiout, "value", varobj_get_value (var));
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_update (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+ struct varobj **rootlist;
+ struct varobj **cr;
+ struct cleanup *cleanup;
+ char *name;
+ int nv;
+
+ if (argc != 1)
+ error ("mi_cmd_var_update: Usage: NAME.");
+
+ name = argv[0];
+
+ /* Check if the parameter is a "*" which means that we want
+ to update all variables */
+
+ if ((*name == '*') && (*(name + 1) == '\0'))
+ {
+ nv = varobj_list (&rootlist);
+ if (mi_version (uiout) <= 1)
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "changelist");
+ else
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changelist");
+ if (nv <= 0)
+ {
+ do_cleanups (cleanup);
+ return MI_CMD_DONE;
+ }
+ cr = rootlist;
+ while (*cr != NULL)
+ {
+ varobj_update_one (*cr);
+ cr++;
+ }
+ xfree (rootlist);
+ do_cleanups (cleanup);
+ }
+ else
+ {
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (name);
+ if (var == NULL)
+ error ("mi_cmd_var_update: Variable object not found");
+
+ if (mi_version (uiout) <= 1)
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "changelist");
+ else
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changelist");
+ varobj_update_one (var);
+ do_cleanups (cleanup);
+ }
+ return MI_CMD_DONE;
+}
+
+/* Helper for mi_cmd_var_update() Returns 0 if the update for
+ the variable fails (usually because the variable is out of
+ scope), and 1 if it succeeds. */
+
+static int
+varobj_update_one (struct varobj *var)
+{
+ struct varobj **changelist;
+ struct varobj **cc;
+ struct cleanup *cleanup = NULL;
+ int nc;
+
+ nc = varobj_update (&var, &changelist);
+
+ /* nc == 0 means that nothing has changed.
+ nc == -1 means that an error occured in updating the variable.
+ nc == -2 means the variable has changed type. */
+
+ if (nc == 0)
+ return 1;
+ else if (nc == -1)
+ {
+ if (mi_version (uiout) > 1)
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_string (uiout, "name", varobj_get_objname(var));
+ ui_out_field_string (uiout, "in_scope", "false");
+ if (mi_version (uiout) > 1)
+ do_cleanups (cleanup);
+ return -1;
+ }
+ else if (nc == -2)
+ {
+ if (mi_version (uiout) > 1)
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_string (uiout, "name", varobj_get_objname (var));
+ ui_out_field_string (uiout, "in_scope", "true");
+ ui_out_field_string (uiout, "new_type", varobj_get_type(var));
+ ui_out_field_int (uiout, "new_num_children",
+ varobj_get_num_children(var));
+ if (mi_version (uiout) > 1)
+ do_cleanups (cleanup);
+ }
+ else
+ {
+
+ cc = changelist;
+ while (*cc != NULL)
+ {
+ if (mi_version (uiout) > 1)
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_string (uiout, "name", varobj_get_objname (*cc));
+ ui_out_field_string (uiout, "in_scope", "true");
+ ui_out_field_string (uiout, "type_changed", "false");
+ if (mi_version (uiout) > 1)
+ do_cleanups (cleanup);
+ cc++;
+ }
+ xfree (changelist);
+ return 1;
+ }
+ return 1;
+}
diff --git a/contrib/gdb/gdb/mi/mi-cmds.c b/contrib/gdb/gdb/mi/mi-cmds.c
new file mode 100644
index 0000000..0dfc217
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmds.c
@@ -0,0 +1,267 @@
+/* MI Command Set for GDB, the GNU debugger.
+
+ Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "top.h"
+#include "mi-cmds.h"
+#include "gdb_string.h"
+
+extern void _initialize_mi_cmds (void);
+struct mi_cmd;
+static struct mi_cmd **lookup_table (const char *command);
+static void build_table (struct mi_cmd *commands);
+
+
+struct mi_cmd mi_cmds[] =
+{
+ { "break-after", { "ignore", 1 }, NULL, NULL },
+ { "break-catch", { NULL, 0 }, NULL, NULL },
+ { "break-commands", { NULL, 0 }, NULL, NULL },
+ { "break-condition", { "cond", 1 }, NULL, NULL },
+ { "break-delete", { "delete breakpoint", 1 }, NULL, NULL },
+ { "break-disable", { "disable breakpoint", 1 }, NULL, NULL },
+ { "break-enable", { "enable breakpoint", 1 }, NULL, NULL },
+ { "break-info", { "info break", 1 }, NULL, NULL },
+ { "break-insert", { NULL, 0 }, 0, mi_cmd_break_insert},
+ { "break-list", { "info break", }, NULL, NULL },
+ { "break-watch", { NULL, 0 }, 0, mi_cmd_break_watch},
+ { "data-disassemble", { NULL, 0 }, 0, mi_cmd_disassemble},
+ { "data-evaluate-expression", { NULL, 0 }, 0, mi_cmd_data_evaluate_expression},
+ { "data-list-changed-registers", { NULL, 0 }, 0, mi_cmd_data_list_changed_registers},
+ { "data-list-register-names", { NULL, 0 }, 0, mi_cmd_data_list_register_names},
+ { "data-list-register-values", { NULL, 0 }, 0, mi_cmd_data_list_register_values},
+ { "data-read-memory", { NULL, 0 }, 0, mi_cmd_data_read_memory},
+ { "data-write-memory", { NULL, 0 }, 0, mi_cmd_data_write_memory},
+ { "data-write-register-values", { NULL, 0 }, 0, mi_cmd_data_write_register_values},
+ { "display-delete", { NULL, 0 }, NULL, NULL },
+ { "display-disable", { NULL, 0 }, NULL, NULL },
+ { "display-enable", { NULL, 0 }, NULL, NULL },
+ { "display-insert", { NULL, 0 }, NULL, NULL },
+ { "display-list", { NULL, 0 }, NULL, NULL },
+ { "environment-cd", { NULL, 0 }, 0, mi_cmd_env_cd},
+ { "environment-directory", { NULL, 0 }, 0, mi_cmd_env_dir},
+ { "environment-path", { NULL, 0 }, 0, mi_cmd_env_path},
+ { "environment-pwd", { NULL, 0 }, 0, mi_cmd_env_pwd},
+ { "exec-abort", { NULL, 0 }, NULL, NULL },
+ { "exec-arguments", { "set args", 1 }, NULL, NULL },
+ { "exec-continue", { NULL, 0 }, mi_cmd_exec_continue},
+ { "exec-finish", { NULL, 0 }, mi_cmd_exec_finish},
+ { "exec-interrupt", { NULL, 0 }, mi_cmd_exec_interrupt},
+ { "exec-next", { NULL, 0 }, mi_cmd_exec_next},
+ { "exec-next-instruction", { NULL, 0 }, mi_cmd_exec_next_instruction},
+ { "exec-return", { NULL, 0 }, mi_cmd_exec_return},
+ { "exec-run", { NULL, 0 }, mi_cmd_exec_run},
+ { "exec-show-arguments", { NULL, 0 }, NULL, NULL },
+ { "exec-signal", { NULL, 0 }, NULL, NULL },
+ { "exec-step", { NULL, 0 }, mi_cmd_exec_step},
+ { "exec-step-instruction", { NULL, 0 }, mi_cmd_exec_step_instruction},
+ { "exec-until", { NULL, 0 }, mi_cmd_exec_until},
+ { "file-clear", { NULL, 0 }, NULL, NULL },
+ { "file-exec-and-symbols", { "file", 1 }, NULL, NULL },
+ { "file-exec-file", { "exec-file", 1 }, NULL, NULL },
+ { "file-list-exec-sections", { NULL, 0 }, NULL, NULL },
+ { "file-list-exec-source-file", { NULL, 0 }, 0, mi_cmd_file_list_exec_source_file},
+ { "file-list-exec-source-files", { NULL, 0 }, NULL, NULL },
+ { "file-list-shared-libraries", { NULL, 0 }, NULL, NULL },
+ { "file-list-symbol-files", { NULL, 0 }, NULL, NULL },
+ { "file-symbol-file", { "symbol-file", 1 }, NULL, NULL },
+ { "gdb-complete", { NULL, 0 }, NULL, NULL },
+ { "gdb-exit", { NULL, 0 }, 0, mi_cmd_gdb_exit},
+ { "gdb-set", { "set", 1 }, NULL, NULL },
+ { "gdb-show", { "show", 1 }, NULL, NULL },
+ { "gdb-source", { NULL, 0 }, NULL, NULL },
+ { "gdb-version", { "show version", 0 }, 0 },
+ { "interpreter-exec", { NULL, 0 }, 0, mi_cmd_interpreter_exec},
+ { "kod-info", { NULL, 0 }, NULL, NULL },
+ { "kod-list", { NULL, 0 }, NULL, NULL },
+ { "kod-list-object-types", { NULL, 0 }, NULL, NULL },
+ { "kod-show", { NULL, 0 }, NULL, NULL },
+ { "overlay-auto", { NULL, 0 }, NULL, NULL },
+ { "overlay-list-mapping-state", { NULL, 0 }, NULL, NULL },
+ { "overlay-list-overlays", { NULL, 0 }, NULL, NULL },
+ { "overlay-map", { NULL, 0 }, NULL, NULL },
+ { "overlay-off", { NULL, 0 }, NULL, NULL },
+ { "overlay-on", { NULL, 0 }, NULL, NULL },
+ { "overlay-unmap", { NULL, 0 }, NULL, NULL },
+ { "signal-handle", { NULL, 0 }, NULL, NULL },
+ { "signal-list-handle-actions", { NULL, 0 }, NULL, NULL },
+ { "signal-list-signal-types", { NULL, 0 }, NULL, NULL },
+ { "stack-info-depth", { NULL, 0 }, 0, mi_cmd_stack_info_depth},
+ { "stack-info-frame", { NULL, 0 }, NULL, NULL },
+ { "stack-list-arguments", { NULL, 0 }, 0, mi_cmd_stack_list_args},
+ { "stack-list-exception-handlers", { NULL, 0 }, NULL, NULL },
+ { "stack-list-frames", { NULL, 0 }, 0, mi_cmd_stack_list_frames},
+ { "stack-list-locals", { NULL, 0 }, 0, mi_cmd_stack_list_locals},
+ { "stack-select-frame", { NULL, 0 }, 0, mi_cmd_stack_select_frame},
+ { "symbol-info-address", { NULL, 0 }, NULL, NULL },
+ { "symbol-info-file", { NULL, 0 }, NULL, NULL },
+ { "symbol-info-function", { NULL, 0 }, NULL, NULL },
+ { "symbol-info-line", { NULL, 0 }, NULL, NULL },
+ { "symbol-info-symbol", { NULL, 0 }, NULL, NULL },
+ { "symbol-list-functions", { NULL, 0 }, NULL, NULL },
+ { "symbol-list-lines", { NULL, 0 }, 0, mi_cmd_symbol_list_lines},
+ { "symbol-list-types", { NULL, 0 }, NULL, NULL },
+ { "symbol-list-variables", { NULL, 0 }, NULL, NULL },
+ { "symbol-locate", { NULL, 0 }, NULL, NULL },
+ { "symbol-type", { NULL, 0 }, NULL, NULL },
+ { "target-attach", { NULL, 0 }, NULL, NULL },
+ { "target-compare-sections", { NULL, 0 }, NULL, NULL },
+ { "target-detach", { "detach", 0 }, 0 },
+ { "target-disconnect", { "disconnect", 0 }, 0 },
+ { "target-download", { NULL, 0 }, mi_cmd_target_download},
+ { "target-exec-status", { NULL, 0 }, NULL, NULL },
+ { "target-list-available-targets", { NULL, 0 }, NULL, NULL },
+ { "target-list-current-targets", { NULL, 0 }, NULL, NULL },
+ { "target-list-parameters", { NULL, 0 }, NULL, NULL },
+ { "target-select", { NULL, 0 }, mi_cmd_target_select},
+ { "thread-info", { NULL, 0 }, NULL, NULL },
+ { "thread-list-all-threads", { NULL, 0 }, NULL, NULL },
+ { "thread-list-ids", { NULL, 0 }, 0, mi_cmd_thread_list_ids},
+ { "thread-select", { NULL, 0 }, 0, mi_cmd_thread_select},
+ { "trace-actions", { NULL, 0 }, NULL, NULL },
+ { "trace-delete", { NULL, 0 }, NULL, NULL },
+ { "trace-disable", { NULL, 0 }, NULL, NULL },
+ { "trace-dump", { NULL, 0 }, NULL, NULL },
+ { "trace-enable", { NULL, 0 }, NULL, NULL },
+ { "trace-exists", { NULL, 0 }, NULL, NULL },
+ { "trace-find", { NULL, 0 }, NULL, NULL },
+ { "trace-frame-number", { NULL, 0 }, NULL, NULL },
+ { "trace-info", { NULL, 0 }, NULL, NULL },
+ { "trace-insert", { NULL, 0 }, NULL, NULL },
+ { "trace-list", { NULL, 0 }, NULL, NULL },
+ { "trace-pass-count", { NULL, 0 }, NULL, NULL },
+ { "trace-save", { NULL, 0 }, NULL, NULL },
+ { "trace-start", { NULL, 0 }, NULL, NULL },
+ { "trace-stop", { NULL, 0 }, NULL, NULL },
+ { "var-assign", { NULL, 0 }, 0, mi_cmd_var_assign},
+ { "var-create", { NULL, 0 }, 0, mi_cmd_var_create},
+ { "var-delete", { NULL, 0 }, 0, mi_cmd_var_delete},
+ { "var-evaluate-expression", { NULL, 0 }, 0, mi_cmd_var_evaluate_expression},
+ { "var-info-expression", { NULL, 0 }, 0, mi_cmd_var_info_expression},
+ { "var-info-num-children", { NULL, 0 }, 0, mi_cmd_var_info_num_children},
+ { "var-info-type", { NULL, 0 }, 0, mi_cmd_var_info_type},
+ { "var-list-children", { NULL, 0 }, 0, mi_cmd_var_list_children},
+ { "var-set-format", { NULL, 0 }, 0, mi_cmd_var_set_format},
+ { "var-show-attributes", { NULL, 0 }, 0, mi_cmd_var_show_attributes},
+ { "var-show-format", { NULL, 0 }, 0, mi_cmd_var_show_format},
+ { "var-update", { NULL, 0 }, 0, mi_cmd_var_update},
+ { NULL, }
+};
+
+/* Pointer to the mi command table (built at run time) */
+
+static struct mi_cmd **mi_table;
+
+/* A prime large enough to accomodate the entire command table */
+enum
+ {
+ MI_TABLE_SIZE = 227
+ };
+
+/* Exported function used to obtain info from the table */
+struct mi_cmd *
+mi_lookup (const char *command)
+{
+ return *lookup_table (command);
+}
+
+/* stat collecting */
+struct mi_cmd_stats
+{
+ int hit;
+ int miss;
+ int rehash;
+};
+struct mi_cmd_stats stats;
+
+/* our lookup function */
+static struct mi_cmd **
+lookup_table (const char *command)
+{
+ const char *chp;
+ unsigned int index = 0;
+ /* compute our hash */
+ for (chp = command; *chp; chp++)
+ {
+ /* some what arbitrary */
+ index = ((index << 6) + (unsigned int) *chp) % MI_TABLE_SIZE;
+ }
+ /* look it up */
+ while (1)
+ {
+ struct mi_cmd **entry = &mi_table[index];
+ if ((*entry) == 0)
+ {
+ /* not found, return pointer to next free. */
+ stats.miss++;
+ return entry;
+ }
+ if (strcmp (command, (*entry)->name) == 0)
+ {
+ stats.hit++;
+ return entry; /* found */
+ }
+ index = (index + 1) % MI_TABLE_SIZE;
+ stats.rehash++;
+ }
+}
+
+static void
+build_table (struct mi_cmd *commands)
+{
+ int nr_rehash = 0;
+ int nr_entries = 0;
+ struct mi_cmd *command;
+ int sizeof_table = sizeof (struct mi_cmd **) * MI_TABLE_SIZE;
+
+ mi_table = xmalloc (sizeof_table);
+ memset (mi_table, 0, sizeof_table);
+ for (command = commands; command->name != 0; command++)
+ {
+ struct mi_cmd **entry = lookup_table (command->name);
+ if (*entry)
+ internal_error (__FILE__, __LINE__,
+ "command `%s' appears to be duplicated",
+ command->name);
+ *entry = command;
+ if (0)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%-30s %2d\n",
+ command->name, stats.rehash - nr_rehash);
+ }
+ nr_entries++;
+ nr_rehash = stats.rehash;
+ }
+ if (0)
+ {
+ fprintf_filtered (gdb_stdlog, "Average %3.1f\n",
+ (double) nr_rehash / (double) nr_entries);
+ }
+}
+
+void
+_initialize_mi_cmds (void)
+{
+ build_table (mi_cmds);
+ memset (&stats, 0, sizeof (stats));
+}
diff --git a/contrib/gdb/gdb/mi/mi-cmds.h b/contrib/gdb/gdb/mi/mi-cmds.h
new file mode 100644
index 0000000..5453059
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-cmds.h
@@ -0,0 +1,152 @@
+/* MI Command Set for GDB, the GNU debugger.
+
+ Copyright 2000, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MI_CMDS_H
+#define MI_CMDS_H
+
+/* An MI command can return any of the following. */
+
+enum mi_cmd_result
+ {
+ /* Report the command as ``done''. Display both the ``NNN^done''
+ message and the completion prompt. */
+ MI_CMD_DONE = 0,
+ /* The command is still running in the forground. Main loop should
+ display the completion prompt. */
+ MI_CMD_FORGROUND,
+ /* An error condition was detected and an error message was
+ asprintf'd into the mi_error_message buffer. The main loop will
+ display the error message and the completion prompt. */
+ MI_CMD_ERROR,
+ /* An error condition was detected and caught. The error message is
+ in the global error message buffer. The main loop will display
+ the error message and the completion prompt. */
+ MI_CMD_CAUGHT_ERROR,
+ /* The MI command has already displayed its completion message.
+ Main loop will not display a completion message but will display
+ the completion prompt. */
+ MI_CMD_QUIET
+ };
+
+enum print_values {
+ PRINT_NO_VALUES,
+ PRINT_ALL_VALUES,
+ PRINT_SIMPLE_VALUES
+};
+
+typedef enum mi_cmd_result (mi_cmd_argv_ftype) (char *command, char **argv, int argc);
+
+/* Older MI commands have this interface. Retained until all old
+ commands are flushed. */
+
+typedef enum mi_cmd_result (mi_cmd_args_ftype) ( /*ui */ char *args, int from_tty);
+
+/* Function implementing each command */
+extern mi_cmd_argv_ftype mi_cmd_break_insert;
+extern mi_cmd_argv_ftype mi_cmd_break_watch;
+extern mi_cmd_argv_ftype mi_cmd_disassemble;
+extern mi_cmd_argv_ftype mi_cmd_data_evaluate_expression;
+extern mi_cmd_argv_ftype mi_cmd_data_list_register_names;
+extern mi_cmd_argv_ftype mi_cmd_data_list_register_values;
+extern mi_cmd_argv_ftype mi_cmd_data_list_changed_registers;
+extern mi_cmd_argv_ftype mi_cmd_data_read_memory;
+extern mi_cmd_argv_ftype mi_cmd_data_write_memory;
+extern mi_cmd_argv_ftype mi_cmd_data_write_register_values;
+extern mi_cmd_argv_ftype mi_cmd_env_cd;
+extern mi_cmd_argv_ftype mi_cmd_env_dir;
+extern mi_cmd_argv_ftype mi_cmd_env_path;
+extern mi_cmd_argv_ftype mi_cmd_env_pwd;
+extern mi_cmd_args_ftype mi_cmd_exec_continue;
+extern mi_cmd_args_ftype mi_cmd_exec_finish;
+extern mi_cmd_args_ftype mi_cmd_exec_next;
+extern mi_cmd_args_ftype mi_cmd_exec_next_instruction;
+extern mi_cmd_args_ftype mi_cmd_exec_return;
+extern mi_cmd_args_ftype mi_cmd_exec_run;
+extern mi_cmd_args_ftype mi_cmd_exec_step;
+extern mi_cmd_args_ftype mi_cmd_exec_step_instruction;
+extern mi_cmd_args_ftype mi_cmd_exec_until;
+extern mi_cmd_args_ftype mi_cmd_exec_interrupt;
+extern mi_cmd_argv_ftype mi_cmd_file_list_exec_source_file;
+extern mi_cmd_argv_ftype mi_cmd_gdb_exit;
+extern mi_cmd_argv_ftype mi_cmd_interpreter_exec;
+extern mi_cmd_argv_ftype mi_cmd_stack_info_depth;
+extern mi_cmd_argv_ftype mi_cmd_stack_list_args;
+extern mi_cmd_argv_ftype mi_cmd_stack_list_frames;
+extern mi_cmd_argv_ftype mi_cmd_stack_list_locals;
+extern mi_cmd_argv_ftype mi_cmd_stack_select_frame;
+extern mi_cmd_argv_ftype mi_cmd_symbol_list_lines;
+extern mi_cmd_args_ftype mi_cmd_target_download;
+extern mi_cmd_args_ftype mi_cmd_target_select;
+extern mi_cmd_argv_ftype mi_cmd_thread_list_ids;
+extern mi_cmd_argv_ftype mi_cmd_thread_select;
+extern mi_cmd_argv_ftype mi_cmd_var_assign;
+extern mi_cmd_argv_ftype mi_cmd_var_create;
+extern mi_cmd_argv_ftype mi_cmd_var_delete;
+extern mi_cmd_argv_ftype mi_cmd_var_evaluate_expression;
+extern mi_cmd_argv_ftype mi_cmd_var_info_expression;
+extern mi_cmd_argv_ftype mi_cmd_var_info_num_children;
+extern mi_cmd_argv_ftype mi_cmd_var_info_type;
+extern mi_cmd_argv_ftype mi_cmd_var_list_children;
+extern mi_cmd_argv_ftype mi_cmd_var_set_format;
+extern mi_cmd_argv_ftype mi_cmd_var_show_attributes;
+extern mi_cmd_argv_ftype mi_cmd_var_show_format;
+extern mi_cmd_argv_ftype mi_cmd_var_update;
+
+/* Description of a single command. */
+
+struct mi_cli
+{
+ /* Corresponding CLI command. If ARGS_P is non-zero, the MI
+ command's argument list is appended to the CLI command. */
+ const char *cmd;
+ int args_p;
+};
+
+struct mi_cmd
+{
+ /* official name of the command. */
+ const char *name;
+ /* The corresponding CLI command that can be used to implement this
+ MI command (if cli.lhs is non NULL). */
+ struct mi_cli cli;
+ /* If non-null, the function implementing the MI command. */
+ mi_cmd_args_ftype *args_func;
+ /* If non-null, the function implementing the MI command. */
+ mi_cmd_argv_ftype *argv_func;
+};
+
+/* Lookup a command in the mi comand table */
+
+extern struct mi_cmd *mi_lookup (const char *command);
+
+/* Debug flag */
+extern int mi_debug_p;
+
+/* Raw console output - FIXME: should this be a parameter? */
+extern struct ui_file *raw_stdout;
+
+extern char *mi_error_message;
+extern void mi_error_last_message (void);
+extern void mi_execute_command (char *cmd, int from_tty);
+
+#endif
diff --git a/contrib/gdb/gdb/mi/mi-console.c b/contrib/gdb/gdb/mi/mi-console.c
new file mode 100644
index 0000000..aca0086
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-console.c
@@ -0,0 +1,125 @@
+/* MI Console code.
+
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mi-console.h"
+#include "gdb_string.h"
+
+/* MI-console: send output to std-out but correcty encapsulated */
+
+static ui_file_fputs_ftype mi_console_file_fputs;
+static ui_file_flush_ftype mi_console_file_flush;
+static ui_file_delete_ftype mi_console_file_delete;
+
+struct mi_console_file
+ {
+ int *magic;
+ struct ui_file *raw;
+ struct ui_file *buffer;
+ const char *prefix;
+ char quote;
+ };
+
+int mi_console_file_magic;
+
+struct ui_file *
+mi_console_file_new (struct ui_file *raw,
+ const char *prefix, char quote)
+{
+ struct ui_file *ui_file = ui_file_new ();
+ struct mi_console_file *mi_console = XMALLOC (struct mi_console_file);
+ mi_console->magic = &mi_console_file_magic;
+ mi_console->raw = raw;
+ mi_console->buffer = mem_fileopen ();
+ mi_console->prefix = prefix;
+ mi_console->quote = quote;
+ set_ui_file_fputs (ui_file, mi_console_file_fputs);
+ set_ui_file_flush (ui_file, mi_console_file_flush);
+ set_ui_file_data (ui_file, mi_console, mi_console_file_delete);
+ return ui_file;
+}
+
+static void
+mi_console_file_delete (struct ui_file *file)
+{
+ struct mi_console_file *mi_console = ui_file_data (file);
+ if (mi_console->magic != &mi_console_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mi_console_file_delete: bad magic number");
+ xfree (mi_console);
+}
+
+static void
+mi_console_file_fputs (const char *buf,
+ struct ui_file *file)
+{
+ struct mi_console_file *mi_console = ui_file_data (file);
+ if (mi_console->magic != &mi_console_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mi_console_file_fputs: bad magic number");
+ /* Append the text to our internal buffer */
+ fputs_unfiltered (buf, mi_console->buffer);
+ /* Flush when an embedded \n */
+ if (strchr (buf, '\n') != NULL)
+ gdb_flush (file);
+}
+
+/* Transform a byte sequence into a console output packet. */
+static void
+mi_console_raw_packet (void *data,
+ const char *buf,
+ long length_buf)
+{
+ struct mi_console_file *mi_console = data;
+ if (mi_console->magic != &mi_console_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mi_console_file_transform: bad magic number");
+
+ if (length_buf > 0)
+ {
+ fputs_unfiltered (mi_console->prefix, mi_console->raw);
+ if (mi_console->quote)
+ {
+ fputs_unfiltered ("\"", mi_console->raw);
+ fputstrn_unfiltered (buf, length_buf, mi_console->quote, mi_console->raw);
+ fputs_unfiltered ("\"\n", mi_console->raw);
+ }
+ else
+ {
+ fputstrn_unfiltered (buf, length_buf, 0, mi_console->raw);
+ fputs_unfiltered ("\n", mi_console->raw);
+ }
+ gdb_flush (mi_console->raw);
+ }
+}
+
+static void
+mi_console_file_flush (struct ui_file *file)
+{
+ struct mi_console_file *mi_console = ui_file_data (file);
+ if (mi_console->magic != &mi_console_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mi_console_file_flush: bad magic number");
+ ui_file_put (mi_console->buffer, mi_console_raw_packet, mi_console);
+ ui_file_rewind (mi_console->buffer);
+}
diff --git a/contrib/gdb/gdb/mi/mi-console.h b/contrib/gdb/gdb/mi/mi-console.h
new file mode 100644
index 0000000..bc6c008
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-console.h
@@ -0,0 +1,29 @@
+/* MI Command Set - MI Console.
+ Copyright 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MI_CONSOLE_H
+#define MI_CONSOLE_H
+
+extern struct ui_file *mi_console_file_new (struct ui_file *raw,
+ const char *prefix,
+ char quote);
+
+#endif
diff --git a/contrib/gdb/gdb/mi/mi-getopt.c b/contrib/gdb/gdb/mi/mi-getopt.c
new file mode 100644
index 0000000..3f2a902
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-getopt.c
@@ -0,0 +1,92 @@
+/* MI Command Set - MI Option Parser.
+ Copyright 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mi-getopt.h"
+#include "gdb_string.h"
+
+int
+mi_getopt (const char *prefix,
+ int argc, char **argv,
+ struct mi_opt *opts,
+ int *optind, char **optarg)
+{
+ char *arg;
+ struct mi_opt *opt;
+ /* We assume that argv/argc are ok. */
+ if (*optind > argc || *optind < 0)
+ internal_error (__FILE__, __LINE__,
+ "mi_getopt_long: optind out of bounds");
+ if (*optind == argc)
+ return -1;
+ arg = argv[*optind];
+ /* ``--''? */
+ if (strcmp (arg, "--") == 0)
+ {
+ *optind += 1;
+ *optarg = NULL;
+ return -1;
+ }
+ /* End of option list. */
+ if (arg[0] != '-')
+ {
+ *optarg = NULL;
+ return -1;
+ }
+ /* Look the option up. */
+ for (opt = opts; opt->name != NULL; opt++)
+ {
+ if (strcmp (opt->name, arg + 1) != 0)
+ continue;
+ if (opt->arg_p)
+ {
+ /* A non-simple optarg option. */
+ if (argc < *optind + 2)
+ error ("%s: Option %s requires an argument", prefix, arg);
+ *optarg = argv[(*optind) + 1];
+ *optind = (*optind) + 2;
+ return opt->index;
+ }
+ else
+ {
+ *optarg = NULL;
+ *optind = (*optind) + 1;
+ return opt->index;
+ }
+ }
+ error ("%s: Unknown option ``%s''", prefix, arg + 1);
+}
+
+int
+mi_valid_noargs (const char *prefix, int argc, char **argv)
+{
+ int optind = 0;
+ char *optarg;
+ static struct mi_opt opts[] =
+ {
+ 0
+ };
+
+ if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) == -1)
+ return 1;
+ else
+ return 0;
+}
diff --git a/contrib/gdb/gdb/mi/mi-getopt.h b/contrib/gdb/gdb/mi/mi-getopt.h
new file mode 100644
index 0000000..17d66fb
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-getopt.h
@@ -0,0 +1,80 @@
+/* MI Option Parser.
+ Copyright 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MI_GETOPT_H
+#define MI_GETOPT_H
+
+/* Like getopt() but with simpler semantics.
+
+ An option has the form ``-<name>''. The special option ``--''
+ denotes the end of the option list. An option can be followed by a
+ separate argument (on a per option basis).
+
+ On entry OPTIND contains the index of the next element of ARGV that
+ needs parsing. OPTIND is updated to indicate the index of the next
+ argument before mi_getopt() returns.
+
+ If ARGV[OPTIND] is an option, that options INDEX is returned.
+ OPTARG is set to the options argument or NULL. OPTIND is updated.
+
+ If ARGV[OPTIND] is not an option, -1 is returned and OPTIND updated
+ to specify the non-option argument. OPTARG is set to NULL.
+
+ mi_getopt() calls ``error("%s: Unknown option %c", prefix,
+ option)'' if an unknown option is encountered. */
+
+struct mi_opt;
+extern int mi_getopt (const char *prefix, int argc, char **argv,
+ struct mi_opt *opt, int *optind, char **optarg);
+
+/* The option list. Terminated by NAME==NULL. ARG_P that the option
+ requires an argument. INDEX is returned to identify th option. */
+
+struct mi_opt
+ {
+ const char *name;
+ int index;
+ int arg_p;
+ };
+
+struct mi_opt;
+
+/* mi_valid_noargs
+
+ Determines if ARGC/ARGV are a valid set of parameters to satisfy
+ an MI function that is not supposed to recieve any arguments.
+
+ An MI function that should not recieve arguments can still be
+ passed parameters after the special option '--' such as below.
+
+ Example: The MI function -exec-run takes no args.
+ However, the client may pass '-exec-run -- -a ...'
+ See PR-783
+
+ PREFIX is passed to mi_getopt for an error message.
+
+ This function Returns 1 if the parameter pair ARGC/ARGV are valid
+ for an MI function that takes no arguments. Otherwise, it returns 0
+ and the appropriate error message is displayed by mi_getopt. */
+
+extern int mi_valid_noargs (const char *prefix, int argc, char **argv);
+
+#endif
diff --git a/contrib/gdb/gdb/mi/mi-interp.c b/contrib/gdb/gdb/mi/mi-interp.c
new file mode 100644
index 0000000..08201ca
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-interp.c
@@ -0,0 +1,406 @@
+/* MI Interpreter Definitions and Commands for GDB, the GNU debugger.
+
+ Copyright 2002, 2003, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "interps.h"
+#include "event-top.h"
+#include "event-loop.h"
+#include "inferior.h"
+#include "ui-out.h"
+#include "top.h"
+
+#include "mi-main.h"
+#include "mi-cmds.h"
+#include "mi-out.h"
+#include "mi-console.h"
+
+struct mi_interp
+{
+ /* MI's output channels */
+ struct ui_file *out;
+ struct ui_file *err;
+ struct ui_file *log;
+ struct ui_file *targ;
+ struct ui_file *event_channel;
+
+ /* This is the interpreter for the mi... */
+ struct interp *mi2_interp;
+ struct interp *mi1_interp;
+ struct interp *mi_interp;
+};
+
+/* These are the interpreter setup, etc. functions for the MI interpreter */
+static void mi_execute_command_wrapper (char *cmd);
+static void mi_command_loop (int mi_version);
+static char *mi_input (char *);
+
+/* These are hooks that we put in place while doing interpreter_exec
+ so we can report interesting things that happened "behind the mi's
+ back" in this command */
+static int mi_interp_query_hook (const char *ctlstr, va_list ap);
+
+static void mi3_command_loop (void);
+static void mi2_command_loop (void);
+static void mi1_command_loop (void);
+
+static void mi_insert_notify_hooks (void);
+static void mi_remove_notify_hooks (void);
+
+static void *
+mi_interpreter_init (void)
+{
+ struct mi_interp *mi = XMALLOC (struct mi_interp);
+
+ /* Why is this a part of the mi architecture? */
+
+ mi_setup_architecture_data ();
+
+ /* HACK: We need to force stdout/stderr to point at the console. This avoids
+ any potential side effects caused by legacy code that is still
+ using the TUI / fputs_unfiltered_hook. So we set up output channels for
+ this now, and swap them in when we are run. */
+
+ raw_stdout = stdio_fileopen (stdout);
+
+ /* Create MI channels */
+ mi->out = mi_console_file_new (raw_stdout, "~", '"');
+ mi->err = mi_console_file_new (raw_stdout, "&", '"');
+ mi->log = mi->err;
+ mi->targ = mi_console_file_new (raw_stdout, "@", '"');
+ mi->event_channel = mi_console_file_new (raw_stdout, "=", 0);
+
+ return mi;
+}
+
+static int
+mi_interpreter_resume (void *data)
+{
+ struct mi_interp *mi = data;
+ /* As per hack note in mi_interpreter_init, swap in the output channels... */
+
+ gdb_setup_readline ();
+
+ if (event_loop_p)
+ {
+ /* These overwrite some of the initialization done in
+ _intialize_event_loop. */
+ call_readline = gdb_readline2;
+ input_handler = mi_execute_command_wrapper;
+ add_file_handler (input_fd, stdin_event_handler, 0);
+ async_command_editing_p = 0;
+ /* FIXME: This is a total hack for now. PB's use of the MI implicitly
+ relies on a bug in the async support which allows asynchronous
+ commands to leak through the commmand loop. The bug involves
+ (but is not limited to) the fact that sync_execution was
+ erroneously initialized to 0. Duplicate by initializing it
+ thus here... */
+ sync_execution = 0;
+ }
+
+ gdb_stdout = mi->out;
+ /* Route error and log output through the MI */
+ gdb_stderr = mi->err;
+ gdb_stdlog = mi->log;
+ /* Route target output through the MI. */
+ gdb_stdtarg = mi->targ;
+
+ /* Replace all the hooks that we know about. There really needs to
+ be a better way of doing this... */
+ clear_interpreter_hooks ();
+
+ show_load_progress = mi_load_progress;
+
+ /* If we're _the_ interpreter, take control. */
+ if (current_interp_named_p (INTERP_MI1))
+ command_loop_hook = mi1_command_loop;
+ else if (current_interp_named_p (INTERP_MI2))
+ command_loop_hook = mi2_command_loop;
+ else if (current_interp_named_p (INTERP_MI3))
+ command_loop_hook = mi3_command_loop;
+ else
+ command_loop_hook = mi2_command_loop;
+
+ return 1;
+}
+
+static int
+mi_interpreter_suspend (void *data)
+{
+ gdb_disable_readline ();
+ return 1;
+}
+
+static int
+mi_interpreter_exec (void *data, const char *command)
+{
+ char *tmp = alloca (strlen (command) + 1);
+ strcpy (tmp, command);
+ mi_execute_command_wrapper (tmp);
+ return 1;
+}
+
+/* Never display the default gdb prompt in mi case. */
+static int
+mi_interpreter_prompt_p (void *data)
+{
+ return 0;
+}
+
+static void
+mi_interpreter_exec_continuation (struct continuation_arg *arg)
+{
+ bpstat_do_actions (&stop_bpstat);
+ if (!target_executing)
+ {
+ fputs_unfiltered ("*stopped", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ fputs_unfiltered ("\n", raw_stdout);
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ do_exec_cleanups (ALL_CLEANUPS);
+ }
+ else if (target_can_async_p ())
+ {
+ add_continuation (mi_interpreter_exec_continuation, NULL);
+ }
+}
+
+enum mi_cmd_result
+mi_cmd_interpreter_exec (char *command, char **argv, int argc)
+{
+ struct interp *interp_to_use;
+ enum mi_cmd_result result = MI_CMD_DONE;
+ int i;
+ struct interp_procs *procs;
+
+ if (argc < 2)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_interpreter_exec: Usage: -interpreter-exec interp command");
+ return MI_CMD_ERROR;
+ }
+
+ interp_to_use = interp_lookup (argv[0]);
+ if (interp_to_use == NULL)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_interpreter_exec: could not find interpreter \"%s\"",
+ argv[0]);
+ return MI_CMD_ERROR;
+ }
+
+ if (!interp_exec_p (interp_to_use))
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_interpreter_exec: interpreter \"%s\" does not support command execution",
+ argv[0]);
+ return MI_CMD_ERROR;
+ }
+
+ /* Insert the MI out hooks, making sure to also call the interpreter's hooks
+ if it has any. */
+ /* KRS: We shouldn't need this... Events should be installed and they should
+ just ALWAYS fire something out down the MI channel... */
+ mi_insert_notify_hooks ();
+
+ /* Now run the code... */
+
+ for (i = 1; i < argc; i++)
+ {
+ char *buff = NULL;
+ /* Do this in a cleaner way... We want to force execution to be
+ asynchronous for commands that run the target. */
+ if (target_can_async_p () && (strcmp (argv[0], "console") == 0))
+ {
+ int len = strlen (argv[i]);
+ buff = xmalloc (len + 2);
+ memcpy (buff, argv[i], len);
+ buff[len] = '&';
+ buff[len + 1] = '\0';
+ }
+
+ /* We had to set sync_execution = 0 for the mi (well really for Project
+ Builder's use of the mi - particularly so interrupting would work.
+ But for console commands to work, we need to initialize it to 1 -
+ since that is what the cli expects - before running the command,
+ and then set it back to 0 when we are done. */
+ sync_execution = 1;
+ if (interp_exec (interp_to_use, argv[i]) < 0)
+ {
+ mi_error_last_message ();
+ result = MI_CMD_ERROR;
+ break;
+ }
+ xfree (buff);
+ do_exec_error_cleanups (ALL_CLEANUPS);
+ sync_execution = 0;
+ }
+
+ mi_remove_notify_hooks ();
+
+ /* Okay, now let's see if the command set the inferior going...
+ Tricky point - have to do this AFTER resetting the interpreter, since
+ changing the interpreter will clear out all the continuations for
+ that interpreter... */
+
+ if (target_can_async_p () && target_executing)
+ {
+ fputs_unfiltered ("^running\n", raw_stdout);
+ add_continuation (mi_interpreter_exec_continuation, NULL);
+ }
+
+ return result;
+}
+
+/*
+ * mi_insert_notify_hooks - This inserts a number of hooks that are meant to produce
+ * async-notify ("=") MI messages while running commands in another interpreter
+ * using mi_interpreter_exec. The canonical use for this is to allow access to
+ * the gdb CLI interpreter from within the MI, while still producing MI style output
+ * when actions in the CLI command change gdb's state.
+*/
+
+static void
+mi_insert_notify_hooks (void)
+{
+ query_hook = mi_interp_query_hook;
+}
+
+static void
+mi_remove_notify_hooks (void)
+{
+ query_hook = NULL;
+}
+
+static int
+mi_interp_query_hook (const char *ctlstr, va_list ap)
+{
+ return 1;
+}
+
+static void
+mi_execute_command_wrapper (char *cmd)
+{
+ mi_execute_command (cmd, stdin == instream);
+}
+
+static void
+mi1_command_loop (void)
+{
+ mi_command_loop (1);
+}
+
+static void
+mi2_command_loop (void)
+{
+ mi_command_loop (2);
+}
+
+static void
+mi3_command_loop (void)
+{
+ mi_command_loop (3);
+}
+
+static void
+mi_command_loop (int mi_version)
+{
+#if 0
+ /* HACK: Force stdout/stderr to point at the console. This avoids
+ any potential side effects caused by legacy code that is still
+ using the TUI / fputs_unfiltered_hook */
+ raw_stdout = stdio_fileopen (stdout);
+ /* Route normal output through the MIx */
+ gdb_stdout = mi_console_file_new (raw_stdout, "~", '"');
+ /* Route error and log output through the MI */
+ gdb_stderr = mi_console_file_new (raw_stdout, "&", '"');
+ gdb_stdlog = gdb_stderr;
+ /* Route target output through the MI. */
+ gdb_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
+ /* HACK: Poke the ui_out table directly. Should we be creating a
+ mi_out object wired up to the above gdb_stdout / gdb_stderr? */
+ uiout = mi_out_new (mi_version);
+ /* HACK: Override any other interpreter hooks. We need to create a
+ real event table and pass in that. */
+ init_ui_hook = 0;
+ /* command_loop_hook = 0; */
+ print_frame_info_listing_hook = 0;
+ query_hook = 0;
+ warning_hook = 0;
+ create_breakpoint_hook = 0;
+ delete_breakpoint_hook = 0;
+ modify_breakpoint_hook = 0;
+ interactive_hook = 0;
+ registers_changed_hook = 0;
+ readline_begin_hook = 0;
+ readline_hook = 0;
+ readline_end_hook = 0;
+ register_changed_hook = 0;
+ memory_changed_hook = 0;
+ context_hook = 0;
+ target_wait_hook = 0;
+ call_command_hook = 0;
+ error_hook = 0;
+ error_begin_hook = 0;
+ show_load_progress = mi_load_progress;
+#endif
+ /* Turn off 8 bit strings in quoted output. Any character with the
+ high bit set is printed using C's octal format. */
+ sevenbit_strings = 1;
+ /* Tell the world that we're alive */
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ if (!event_loop_p)
+ simplified_command_loop (mi_input, mi_execute_command);
+ else
+ start_event_loop ();
+}
+
+static char *
+mi_input (char *buf)
+{
+ return gdb_readline (NULL);
+}
+
+extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
+
+void
+_initialize_mi_interp (void)
+{
+ static const struct interp_procs procs =
+ {
+ mi_interpreter_init, /* init_proc */
+ mi_interpreter_resume, /* resume_proc */
+ mi_interpreter_suspend, /* suspend_proc */
+ mi_interpreter_exec, /* exec_proc */
+ mi_interpreter_prompt_p /* prompt_proc_p */
+ };
+
+ /* The various interpreter levels. */
+ interp_add (interp_new (INTERP_MI1, NULL, mi_out_new (1), &procs));
+ interp_add (interp_new (INTERP_MI2, NULL, mi_out_new (2), &procs));
+ interp_add (interp_new (INTERP_MI3, NULL, mi_out_new (3), &procs));
+
+ /* "mi" selects the most recent released version. "mi2" was
+ released as part of GDB 6.0. */
+ interp_add (interp_new (INTERP_MI, NULL, mi_out_new (2), &procs));
+}
diff --git a/contrib/gdb/gdb/mi/mi-main.c b/contrib/gdb/gdb/mi/mi-main.c
new file mode 100644
index 0000000..c46bf63
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-main.c
@@ -0,0 +1,1494 @@
+/* MI Command Set.
+
+ Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation,
+ Inc.
+
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Work in progress */
+
+#include "defs.h"
+#include "target.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "top.h"
+#include "gdbthread.h"
+#include "mi-cmds.h"
+#include "mi-parse.h"
+#include "mi-getopt.h"
+#include "mi-console.h"
+#include "ui-out.h"
+#include "mi-out.h"
+#include "interps.h"
+#include "event-loop.h"
+#include "event-top.h"
+#include "gdbcore.h" /* for write_memory() */
+#include "value.h" /* for deprecated_write_register_bytes() */
+#include "regcache.h"
+#include "gdb.h"
+#include "frame.h"
+#include "mi-main.h"
+
+#include <ctype.h>
+#include <sys/time.h>
+
+enum
+ {
+ FROM_TTY = 0
+ };
+
+/* Enumerations of the actions that may result from calling
+ captured_mi_execute_command */
+
+enum captured_mi_execute_command_actions
+ {
+ EXECUTE_COMMAND_DISPLAY_PROMPT,
+ EXECUTE_COMMAND_SUPRESS_PROMPT,
+ EXECUTE_COMMAND_DISPLAY_ERROR
+ };
+
+/* This structure is used to pass information from captured_mi_execute_command
+ to mi_execute_command. */
+struct captured_mi_execute_command_args
+{
+ /* This return result of the MI command (output) */
+ enum mi_cmd_result rc;
+
+ /* What action to perform when the call is finished (output) */
+ enum captured_mi_execute_command_actions action;
+
+ /* The command context to be executed (input) */
+ struct mi_parse *command;
+};
+
+int mi_debug_p;
+struct ui_file *raw_stdout;
+
+/* The token of the last asynchronous command */
+static char *last_async_command;
+static char *previous_async_command;
+char *mi_error_message;
+static char *old_regs;
+
+extern void _initialize_mi_main (void);
+static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);
+
+static void mi_execute_cli_command (const char *cmd, int args_p,
+ const char *args);
+static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
+
+static void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
+
+static int register_changed_p (int regnum);
+static int get_register (int regnum, int format);
+
+/* A helper function which will set mi_error_message to
+ error_last_message. */
+void
+mi_error_last_message (void)
+{
+ char *s = error_last_message ();
+ xasprintf (&mi_error_message, "%s", s);
+ xfree (s);
+}
+
+/* Command implementations. FIXME: Is this libgdb? No. This is the MI
+ layer that calls libgdb. Any operation used in the below should be
+ formalized. */
+
+enum mi_cmd_result
+mi_cmd_gdb_exit (char *command, char **argv, int argc)
+{
+ /* We have to print everything right here because we never return */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^exit\n", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ /* FIXME: The function called is not yet a formal libgdb function */
+ quit_force (NULL, FROM_TTY);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_exec_run (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("run", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_next (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("next", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_next_instruction (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("nexti", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_step (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("step", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_step_instruction (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("stepi", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_finish (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("finish", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_until (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("until", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_return (char *args, int from_tty)
+{
+ /* This command doesn't really execute the target, it just pops the
+ specified number of frames. */
+ if (*args)
+ /* Call return_command with from_tty argument equal to 0 so as to
+ avoid being queried. */
+ return_command (args, 0);
+ else
+ /* Call return_command with from_tty argument equal to 0 so as to
+ avoid being queried. */
+ return_command (NULL, 0);
+
+ /* Because we have called return_command with from_tty = 0, we need
+ to print the frame here. */
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame),
+ LOC_AND_ADDRESS);
+
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_exec_continue (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("continue", args, from_tty);
+}
+
+/* Interrupt the execution of the target. Note how we must play around
+ with the token varialbes, in order to display the current token in
+ the result of the interrupt command, and the previous execution
+ token when the target finally stops. See comments in
+ mi_cmd_execute. */
+enum mi_cmd_result
+mi_cmd_exec_interrupt (char *args, int from_tty)
+{
+ if (!target_executing)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_exec_interrupt: Inferior not executing.");
+ return MI_CMD_ERROR;
+ }
+ interrupt_target_command (args, from_tty);
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^done", raw_stdout);
+ xfree (last_async_command);
+ if (previous_async_command)
+ last_async_command = xstrdup (previous_async_command);
+ xfree (previous_async_command);
+ previous_async_command = NULL;
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ return MI_CMD_QUIET;
+}
+
+enum mi_cmd_result
+mi_cmd_thread_select (char *command, char **argv, int argc)
+{
+ enum gdb_rc rc;
+
+ if (argc != 1)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_thread_select: USAGE: threadnum.");
+ return MI_CMD_ERROR;
+ }
+ else
+ rc = gdb_thread_select (uiout, argv[0]);
+
+ /* RC is enum gdb_rc if it is successful (>=0)
+ enum return_reason if not (<0). */
+ if ((int) rc < 0 && (enum return_reason) rc == RETURN_ERROR)
+ return MI_CMD_CAUGHT_ERROR;
+ else if ((int) rc >= 0 && rc == GDB_RC_FAIL)
+ return MI_CMD_ERROR;
+ else
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_thread_list_ids (char *command, char **argv, int argc)
+{
+ enum gdb_rc rc = MI_CMD_DONE;
+
+ if (argc != 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_thread_list_ids: No arguments required.");
+ return MI_CMD_ERROR;
+ }
+ else
+ rc = gdb_list_thread_ids (uiout);
+
+ if (rc == GDB_RC_FAIL)
+ return MI_CMD_CAUGHT_ERROR;
+ else
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_data_list_register_names (char *command, char **argv, int argc)
+{
+ int regnum, numregs;
+ int i;
+ struct cleanup *cleanup;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS + NUM_PSEUDO_REGS;
+
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-names");
+
+ if (argc == 0) /* No args, just do all the regs */
+ {
+ for (regnum = 0;
+ regnum < numregs;
+ regnum++)
+ {
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ ui_out_field_string (uiout, NULL, "");
+ else
+ ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
+ }
+ }
+
+ /* Else, list of register #s, just do listed regs */
+ for (i = 0; i < argc; i++)
+ {
+ regnum = atoi (argv[i]);
+ if (regnum < 0 || regnum >= numregs)
+ {
+ do_cleanups (cleanup);
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ ui_out_field_string (uiout, NULL, "");
+ else
+ ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
+ }
+ do_cleanups (cleanup);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_data_list_changed_registers (char *command, char **argv, int argc)
+{
+ int regnum, numregs, changed;
+ int i;
+ struct cleanup *cleanup;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS;
+
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changed-registers");
+
+ if (argc == 0) /* No args, just do all the regs */
+ {
+ for (regnum = 0;
+ regnum < numregs;
+ regnum++)
+ {
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ continue;
+ changed = register_changed_p (regnum);
+ if (changed < 0)
+ {
+ do_cleanups (cleanup);
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_changed_registers: Unable to read register contents.");
+ return MI_CMD_ERROR;
+ }
+ else if (changed)
+ ui_out_field_int (uiout, NULL, regnum);
+ }
+ }
+
+ /* Else, list of register #s, just do listed regs */
+ for (i = 0; i < argc; i++)
+ {
+ regnum = atoi (argv[i]);
+
+ if (regnum >= 0
+ && regnum < numregs
+ && REGISTER_NAME (regnum) != NULL
+ && *REGISTER_NAME (regnum) != '\000')
+ {
+ changed = register_changed_p (regnum);
+ if (changed < 0)
+ {
+ do_cleanups (cleanup);
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_register_change: Unable to read register contents.");
+ return MI_CMD_ERROR;
+ }
+ else if (changed)
+ ui_out_field_int (uiout, NULL, regnum);
+ }
+ else
+ {
+ do_cleanups (cleanup);
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ }
+ do_cleanups (cleanup);
+ return MI_CMD_DONE;
+}
+
+static int
+register_changed_p (int regnum)
+{
+ char raw_buffer[MAX_REGISTER_SIZE];
+
+ if (! frame_register_read (deprecated_selected_frame, regnum, raw_buffer))
+ return -1;
+
+ if (memcmp (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum)) == 0)
+ return 0;
+
+ /* Found a changed register. Return 1. */
+
+ memcpy (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
+
+ return 1;
+}
+
+/* Return a list of register number and value pairs. The valid
+ arguments expected are: a letter indicating the format in which to
+ display the registers contents. This can be one of: x (hexadecimal), d
+ (decimal), N (natural), t (binary), o (octal), r (raw). After the
+ format argumetn there can be a sequence of numbers, indicating which
+ registers to fetch the content of. If the format is the only argument,
+ a list of all the registers with their values is returned. */
+enum mi_cmd_result
+mi_cmd_data_list_register_values (char *command, char **argv, int argc)
+{
+ int regnum, numregs, format, result;
+ int i;
+ struct cleanup *list_cleanup, *tuple_cleanup;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS;
+
+ if (argc == 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_register_values: Usage: -data-list-register-values <format> [<regnum1>...<regnumN>]");
+ return MI_CMD_ERROR;
+ }
+
+ format = (int) argv[0][0];
+
+ if (!target_has_registers)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_register_values: No registers.");
+ return MI_CMD_ERROR;
+ }
+
+ list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-values");
+
+ if (argc == 1) /* No args, beside the format: do all the regs */
+ {
+ for (regnum = 0;
+ regnum < numregs;
+ regnum++)
+ {
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ continue;
+ tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_int (uiout, "number", regnum);
+ result = get_register (regnum, format);
+ if (result == -1)
+ {
+ do_cleanups (list_cleanup);
+ return MI_CMD_ERROR;
+ }
+ do_cleanups (tuple_cleanup);
+ }
+ }
+
+ /* Else, list of register #s, just do listed regs */
+ for (i = 1; i < argc; i++)
+ {
+ regnum = atoi (argv[i]);
+
+ if (regnum >= 0
+ && regnum < numregs
+ && REGISTER_NAME (regnum) != NULL
+ && *REGISTER_NAME (regnum) != '\000')
+ {
+ tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_int (uiout, "number", regnum);
+ result = get_register (regnum, format);
+ if (result == -1)
+ {
+ do_cleanups (list_cleanup);
+ return MI_CMD_ERROR;
+ }
+ do_cleanups (tuple_cleanup);
+ }
+ else
+ {
+ do_cleanups (list_cleanup);
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ }
+ do_cleanups (list_cleanup);
+ return MI_CMD_DONE;
+}
+
+/* Output one register's contents in the desired format. */
+static int
+get_register (int regnum, int format)
+{
+ char raw_buffer[MAX_REGISTER_SIZE];
+ char virtual_buffer[MAX_REGISTER_SIZE];
+ int optim;
+ int realnum;
+ CORE_ADDR addr;
+ enum lval_type lval;
+ static struct ui_stream *stb = NULL;
+
+ stb = ui_out_stream_new (uiout);
+
+ if (format == 'N')
+ format = 0;
+
+ frame_register (deprecated_selected_frame, regnum, &optim, &lval, &addr,
+ &realnum, raw_buffer);
+
+ if (optim)
+ {
+ xasprintf (&mi_error_message, "Optimized out");
+ return -1;
+ }
+
+ /* Convert raw data to virtual format if necessary. */
+
+ if (DEPRECATED_REGISTER_CONVERTIBLE_P ()
+ && DEPRECATED_REGISTER_CONVERTIBLE (regnum))
+ {
+ DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (regnum,
+ register_type (current_gdbarch, regnum),
+ raw_buffer, virtual_buffer);
+ }
+ else
+ memcpy (virtual_buffer, raw_buffer, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+
+ if (format == 'r')
+ {
+ int j;
+ char *ptr, buf[1024];
+
+ strcpy (buf, "0x");
+ ptr = buf + 2;
+ for (j = 0; j < DEPRECATED_REGISTER_RAW_SIZE (regnum); j++)
+ {
+ int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
+ : DEPRECATED_REGISTER_RAW_SIZE (regnum) - 1 - j;
+ sprintf (ptr, "%02x", (unsigned char) raw_buffer[idx]);
+ ptr += 2;
+ }
+ ui_out_field_string (uiout, "value", buf);
+ /*fputs_filtered (buf, gdb_stdout); */
+ }
+ else
+ {
+ val_print (register_type (current_gdbarch, regnum), virtual_buffer, 0, 0,
+ stb->stream, format, 1, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "value", stb);
+ ui_out_stream_delete (stb);
+ }
+ return 1;
+}
+
+/* Write given values into registers. The registers and values are
+ given as pairs. The corresponding MI command is
+ -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]*/
+enum mi_cmd_result
+mi_cmd_data_write_register_values (char *command, char **argv, int argc)
+{
+ int regnum;
+ int i;
+ int numregs;
+ LONGEST value;
+ char format;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS;
+
+ if (argc == 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: Usage: -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]");
+ return MI_CMD_ERROR;
+ }
+
+ format = (int) argv[0][0];
+
+ if (!target_has_registers)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: No registers.");
+ return MI_CMD_ERROR;
+ }
+
+ if (!(argc - 1))
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: No regs and values specified.");
+ return MI_CMD_ERROR;
+ }
+
+ if ((argc - 1) % 2)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: Regs and vals are not in pairs.");
+ return MI_CMD_ERROR;
+ }
+
+ for (i = 1; i < argc; i = i + 2)
+ {
+ regnum = atoi (argv[i]);
+
+ if (regnum >= 0
+ && regnum < numregs
+ && REGISTER_NAME (regnum) != NULL
+ && *REGISTER_NAME (regnum) != '\000')
+ {
+ void *buffer;
+ struct cleanup *old_chain;
+
+ /* Get the value as a number */
+ value = parse_and_eval_address (argv[i + 1]);
+ /* Get the value into an array */
+ buffer = xmalloc (DEPRECATED_REGISTER_SIZE);
+ old_chain = make_cleanup (xfree, buffer);
+ store_signed_integer (buffer, DEPRECATED_REGISTER_SIZE, value);
+ /* Write it down */
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (regnum), buffer, DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ /* Free the buffer. */
+ do_cleanups (old_chain);
+ }
+ else
+ {
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ }
+ return MI_CMD_DONE;
+}
+
+#if 0
+/*This is commented out because we decided it was not useful. I leave
+ it, just in case. ezannoni:1999-12-08 */
+
+/* Assign a value to a variable. The expression argument must be in
+ the form A=2 or "A = 2" (I.e. if there are spaces it needs to be
+ quoted. */
+enum mi_cmd_result
+mi_cmd_data_assign (char *command, char **argv, int argc)
+{
+ struct expression *expr;
+ struct cleanup *old_chain;
+
+ if (argc != 1)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_assign: Usage: -data-assign expression");
+ return MI_CMD_ERROR;
+ }
+
+ /* NOTE what follows is a clone of set_command(). FIXME: ezannoni
+ 01-12-1999: Need to decide what to do with this for libgdb purposes. */
+
+ expr = parse_expression (argv[0]);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+ return MI_CMD_DONE;
+}
+#endif
+
+/* Evaluate the value of the argument. The argument is an
+ expression. If the expression contains spaces it needs to be
+ included in double quotes. */
+enum mi_cmd_result
+mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
+{
+ struct expression *expr;
+ struct cleanup *old_chain = NULL;
+ struct value *val;
+ struct ui_stream *stb = NULL;
+
+ stb = ui_out_stream_new (uiout);
+
+ if (argc != 1)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_evaluate_expression: Usage: -data-evaluate-expression expression");
+ return MI_CMD_ERROR;
+ }
+
+ expr = parse_expression (argv[0]);
+
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+
+ /* Print the result of the expression evaluation. */
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+ VALUE_EMBEDDED_OFFSET (val), VALUE_ADDRESS (val),
+ stb->stream, 0, 0, 0, 0);
+
+ ui_out_field_stream (uiout, "value", stb);
+ ui_out_stream_delete (stb);
+
+ do_cleanups (old_chain);
+
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_target_download (char *args, int from_tty)
+{
+ char *run;
+ struct cleanup *old_cleanups = NULL;
+
+ xasprintf (&run, "load %s", args);
+ old_cleanups = make_cleanup (xfree, run);
+ execute_command (run, from_tty);
+
+ do_cleanups (old_cleanups);
+ return MI_CMD_DONE;
+}
+
+/* Connect to the remote target. */
+enum mi_cmd_result
+mi_cmd_target_select (char *args, int from_tty)
+{
+ char *run;
+ struct cleanup *old_cleanups = NULL;
+
+ xasprintf (&run, "target %s", args);
+ old_cleanups = make_cleanup (xfree, run);
+
+ /* target-select is always synchronous. once the call has returned
+ we know that we are connected. */
+ /* NOTE: At present all targets that are connected are also
+ (implicitly) talking to a halted target. In the future this may
+ change. */
+ execute_command (run, from_tty);
+
+ do_cleanups (old_cleanups);
+
+ /* Issue the completion message here. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^connected", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ do_exec_cleanups (ALL_CLEANUPS);
+ return MI_CMD_QUIET;
+}
+
+/* DATA-MEMORY-READ:
+
+ ADDR: start address of data to be dumped.
+ WORD-FORMAT: a char indicating format for the ``word''. See
+ the ``x'' command.
+ WORD-SIZE: size of each ``word''; 1,2,4, or 8 bytes
+ NR_ROW: Number of rows.
+ NR_COL: The number of colums (words per row).
+ ASCHAR: (OPTIONAL) Append an ascii character dump to each row. Use
+ ASCHAR for unprintable characters.
+
+ Reads SIZE*NR_ROW*NR_COL bytes starting at ADDR from memory and
+ displayes them. Returns:
+
+ {addr="...",rowN={wordN="..." ,... [,ascii="..."]}, ...}
+
+ Returns:
+ The number of bytes read is SIZE*ROW*COL. */
+
+enum mi_cmd_result
+mi_cmd_data_read_memory (char *command, char **argv, int argc)
+{
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ CORE_ADDR addr;
+ long total_bytes;
+ long nr_cols;
+ long nr_rows;
+ char word_format;
+ struct type *word_type;
+ long word_size;
+ char word_asize;
+ char aschar;
+ char *mbuf;
+ int nr_bytes;
+ long offset = 0;
+ int optind = 0;
+ char *optarg;
+ enum opt
+ {
+ OFFSET_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"o", OFFSET_OPT, 1},
+ 0
+ };
+
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_data_read_memory", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case OFFSET_OPT:
+ offset = atol (optarg);
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc < 5 || argc > 6)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: Usage: ADDR WORD-FORMAT WORD-SIZE NR-ROWS NR-COLS [ASCHAR].");
+ return MI_CMD_ERROR;
+ }
+
+ /* Extract all the arguments. */
+
+ /* Start address of the memory dump. */
+ addr = parse_and_eval_address (argv[0]) + offset;
+ /* The format character to use when displaying a memory word. See
+ the ``x'' command. */
+ word_format = argv[1][0];
+ /* The size of the memory word. */
+ word_size = atol (argv[2]);
+ switch (word_size)
+ {
+ case 1:
+ word_type = builtin_type_int8;
+ word_asize = 'b';
+ break;
+ case 2:
+ word_type = builtin_type_int16;
+ word_asize = 'h';
+ break;
+ case 4:
+ word_type = builtin_type_int32;
+ word_asize = 'w';
+ break;
+ case 8:
+ word_type = builtin_type_int64;
+ word_asize = 'g';
+ break;
+ default:
+ word_type = builtin_type_int8;
+ word_asize = 'b';
+ }
+ /* The number of rows */
+ nr_rows = atol (argv[3]);
+ if (nr_rows <= 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: invalid number of rows.");
+ return MI_CMD_ERROR;
+ }
+ /* number of bytes per row. */
+ nr_cols = atol (argv[4]);
+ if (nr_cols <= 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: invalid number of columns.");
+ }
+ /* The un-printable character when printing ascii. */
+ if (argc == 6)
+ aschar = *argv[5];
+ else
+ aschar = 0;
+
+ /* create a buffer and read it in. */
+ total_bytes = word_size * nr_rows * nr_cols;
+ mbuf = xcalloc (total_bytes, 1);
+ make_cleanup (xfree, mbuf);
+ if (mbuf == NULL)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: out of memory.");
+ return MI_CMD_ERROR;
+ }
+ nr_bytes = 0;
+ while (nr_bytes < total_bytes)
+ {
+ int error;
+ long num = target_read_memory_partial (addr + nr_bytes, mbuf + nr_bytes,
+ total_bytes - nr_bytes,
+ &error);
+ if (num <= 0)
+ break;
+ nr_bytes += num;
+ }
+
+ /* output the header information. */
+ ui_out_field_core_addr (uiout, "addr", addr);
+ ui_out_field_int (uiout, "nr-bytes", nr_bytes);
+ ui_out_field_int (uiout, "total-bytes", total_bytes);
+ ui_out_field_core_addr (uiout, "next-row", addr + word_size * nr_cols);
+ ui_out_field_core_addr (uiout, "prev-row", addr - word_size * nr_cols);
+ ui_out_field_core_addr (uiout, "next-page", addr + total_bytes);
+ ui_out_field_core_addr (uiout, "prev-page", addr - total_bytes);
+
+ /* Build the result as a two dimentional table. */
+ {
+ struct ui_stream *stream = ui_out_stream_new (uiout);
+ struct cleanup *cleanup_list_memory;
+ int row;
+ int row_byte;
+ cleanup_list_memory = make_cleanup_ui_out_list_begin_end (uiout, "memory");
+ for (row = 0, row_byte = 0;
+ row < nr_rows;
+ row++, row_byte += nr_cols * word_size)
+ {
+ int col;
+ int col_byte;
+ struct cleanup *cleanup_tuple;
+ struct cleanup *cleanup_list_data;
+ cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_core_addr (uiout, "addr", addr + row_byte);
+ /* ui_out_field_core_addr_symbolic (uiout, "saddr", addr + row_byte); */
+ cleanup_list_data = make_cleanup_ui_out_list_begin_end (uiout, "data");
+ for (col = 0, col_byte = row_byte;
+ col < nr_cols;
+ col++, col_byte += word_size)
+ {
+ if (col_byte + word_size > nr_bytes)
+ {
+ ui_out_field_string (uiout, NULL, "N/A");
+ }
+ else
+ {
+ ui_file_rewind (stream->stream);
+ print_scalar_formatted (mbuf + col_byte, word_type, word_format,
+ word_asize, stream->stream);
+ ui_out_field_stream (uiout, NULL, stream);
+ }
+ }
+ do_cleanups (cleanup_list_data);
+ if (aschar)
+ {
+ int byte;
+ ui_file_rewind (stream->stream);
+ for (byte = row_byte; byte < row_byte + word_size * nr_cols; byte++)
+ {
+ if (byte >= nr_bytes)
+ {
+ fputc_unfiltered ('X', stream->stream);
+ }
+ else if (mbuf[byte] < 32 || mbuf[byte] > 126)
+ {
+ fputc_unfiltered (aschar, stream->stream);
+ }
+ else
+ fputc_unfiltered (mbuf[byte], stream->stream);
+ }
+ ui_out_field_stream (uiout, "ascii", stream);
+ }
+ do_cleanups (cleanup_tuple);
+ }
+ ui_out_stream_delete (stream);
+ do_cleanups (cleanup_list_memory);
+ }
+ do_cleanups (cleanups);
+ return MI_CMD_DONE;
+}
+
+/* DATA-MEMORY-WRITE:
+
+ COLUMN_OFFSET: optional argument. Must be preceeded by '-o'. The
+ offset from the beginning of the memory grid row where the cell to
+ be written is.
+ ADDR: start address of the row in the memory grid where the memory
+ cell is, if OFFSET_COLUMN is specified. Otherwise, the address of
+ the location to write to.
+ FORMAT: a char indicating format for the ``word''. See
+ the ``x'' command.
+ WORD_SIZE: size of each ``word''; 1,2,4, or 8 bytes
+ VALUE: value to be written into the memory address.
+
+ Writes VALUE into ADDR + (COLUMN_OFFSET * WORD_SIZE).
+
+ Prints nothing. */
+enum mi_cmd_result
+mi_cmd_data_write_memory (char *command, char **argv, int argc)
+{
+ CORE_ADDR addr;
+ char word_format;
+ long word_size;
+ /* FIXME: ezannoni 2000-02-17 LONGEST could possibly not be big
+ enough when using a compiler other than GCC. */
+ LONGEST value;
+ void *buffer;
+ struct cleanup *old_chain;
+ long offset = 0;
+ int optind = 0;
+ char *optarg;
+ enum opt
+ {
+ OFFSET_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"o", OFFSET_OPT, 1},
+ 0
+ };
+
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_data_write_memory", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case OFFSET_OPT:
+ offset = atol (optarg);
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc != 4)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_memory: Usage: [-o COLUMN_OFFSET] ADDR FORMAT WORD-SIZE VALUE.");
+ return MI_CMD_ERROR;
+ }
+
+ /* Extract all the arguments. */
+ /* Start address of the memory dump. */
+ addr = parse_and_eval_address (argv[0]);
+ /* The format character to use when displaying a memory word. See
+ the ``x'' command. */
+ word_format = argv[1][0];
+ /* The size of the memory word. */
+ word_size = atol (argv[2]);
+
+ /* Calculate the real address of the write destination. */
+ addr += (offset * word_size);
+
+ /* Get the value as a number */
+ value = parse_and_eval_address (argv[3]);
+ /* Get the value into an array */
+ buffer = xmalloc (word_size);
+ old_chain = make_cleanup (xfree, buffer);
+ store_signed_integer (buffer, word_size, value);
+ /* Write it down to memory */
+ write_memory (addr, buffer, word_size);
+ /* Free the buffer. */
+ do_cleanups (old_chain);
+
+ return MI_CMD_DONE;
+}
+
+/* Execute a command within a safe environment.
+ Return <0 for error; >=0 for ok.
+
+ args->action will tell mi_execute_command what action
+ to perfrom after the given command has executed (display/supress
+ prompt, display error). */
+
+static int
+captured_mi_execute_command (struct ui_out *uiout, void *data)
+{
+ struct captured_mi_execute_command_args *args =
+ (struct captured_mi_execute_command_args *) data;
+ struct mi_parse *context = args->command;
+
+ switch (context->op)
+ {
+
+ case MI_COMMAND:
+ /* A MI command was read from the input stream */
+ if (mi_debug_p)
+ /* FIXME: gdb_???? */
+ fprintf_unfiltered (raw_stdout, " token=`%s' command=`%s' args=`%s'\n",
+ context->token, context->command, context->args);
+ /* FIXME: cagney/1999-09-25: Rather than this convoluted
+ condition expression, each function should return an
+ indication of what action is required and then switch on
+ that. */
+ args->action = EXECUTE_COMMAND_DISPLAY_PROMPT;
+ args->rc = mi_cmd_execute (context);
+
+ if (!target_can_async_p () || !target_executing)
+ {
+ /* print the result if there were no errors
+
+ Remember that on the way out of executing a command, you have
+ to directly use the mi_interp's uiout, since the command could
+ have reset the interpreter, in which case the current uiout
+ will most likely crash in the mi_out_* routines. */
+ if (args->rc == MI_CMD_DONE)
+ {
+ fputs_unfiltered (context->token, raw_stdout);
+ fputs_unfiltered ("^done", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ }
+ else if (args->rc == MI_CMD_ERROR)
+ {
+ if (mi_error_message)
+ {
+ fputs_unfiltered (context->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputstr_unfiltered (mi_error_message, '"', raw_stdout);
+ xfree (mi_error_message);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ }
+ mi_out_rewind (uiout);
+ }
+ else if (args->rc == MI_CMD_CAUGHT_ERROR)
+ {
+ mi_out_rewind (uiout);
+ args->action = EXECUTE_COMMAND_DISPLAY_ERROR;
+ return 1;
+ }
+ else
+ mi_out_rewind (uiout);
+ }
+ else if (sync_execution)
+ {
+ /* Don't print the prompt. We are executing the target in
+ synchronous mode. */
+ args->action = EXECUTE_COMMAND_SUPRESS_PROMPT;
+ return 1;
+ }
+ break;
+
+ case CLI_COMMAND:
+ /* A CLI command was read from the input stream */
+ /* This will be removed as soon as we have a complete set of
+ mi commands */
+ /* echo the command on the console. */
+ fprintf_unfiltered (gdb_stdlog, "%s\n", context->command);
+ mi_execute_cli_command (context->command, 0, NULL);
+
+ /* If we changed interpreters, DON'T print out anything. */
+ if (current_interp_named_p (INTERP_MI)
+ || current_interp_named_p (INTERP_MI1)
+ || current_interp_named_p (INTERP_MI2)
+ || current_interp_named_p (INTERP_MI3))
+ {
+ /* print the result */
+ /* FIXME: Check for errors here. */
+ fputs_unfiltered (context->token, raw_stdout);
+ fputs_unfiltered ("^done", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ args->action = EXECUTE_COMMAND_DISPLAY_PROMPT;
+ args->rc = MI_CMD_DONE;
+ }
+ break;
+
+ }
+
+ return 1;
+}
+
+
+void
+mi_execute_command (char *cmd, int from_tty)
+{
+ struct mi_parse *command;
+ struct captured_mi_execute_command_args args;
+ struct ui_out *saved_uiout = uiout;
+ int result;
+
+ /* This is to handle EOF (^D). We just quit gdb. */
+ /* FIXME: we should call some API function here. */
+ if (cmd == 0)
+ quit_force (NULL, from_tty);
+
+ command = mi_parse (cmd);
+
+ if (command != NULL)
+ {
+ /* FIXME: cagney/1999-11-04: Can this use of catch_exceptions either
+ be pushed even further down or even eliminated? */
+ args.command = command;
+ result = catch_exceptions (uiout, captured_mi_execute_command, &args, "",
+ RETURN_MASK_ALL);
+
+ if (args.action == EXECUTE_COMMAND_SUPRESS_PROMPT)
+ {
+ /* The command is executing synchronously. Bail out early
+ suppressing the finished prompt. */
+ mi_parse_free (command);
+ return;
+ }
+ if (args.action == EXECUTE_COMMAND_DISPLAY_ERROR || result < 0)
+ {
+ char *msg = error_last_message ();
+ struct cleanup *cleanup = make_cleanup (xfree, msg);
+ /* The command execution failed and error() was called
+ somewhere */
+ fputs_unfiltered (command->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputstr_unfiltered (msg, '"', raw_stdout);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ }
+ mi_parse_free (command);
+ }
+
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ /* print any buffered hook code */
+ /* ..... */
+}
+
+static enum mi_cmd_result
+mi_cmd_execute (struct mi_parse *parse)
+{
+ if (parse->cmd->argv_func != NULL
+ || parse->cmd->args_func != NULL)
+ {
+ /* FIXME: We need to save the token because the command executed
+ may be asynchronous and need to print the token again.
+ In the future we can pass the token down to the func
+ and get rid of the last_async_command */
+ /* The problem here is to keep the token around when we launch
+ the target, and we want to interrupt it later on. The
+ interrupt command will have its own token, but when the
+ target stops, we must display the token corresponding to the
+ last execution command given. So we have another string where
+ we copy the token (previous_async_command), if this was
+ indeed the token of an execution command, and when we stop we
+ print that one. This is possible because the interrupt
+ command, when over, will copy that token back into the
+ default token string (last_async_command). */
+
+ if (target_executing)
+ {
+ if (!previous_async_command)
+ previous_async_command = xstrdup (last_async_command);
+ if (strcmp (parse->command, "exec-interrupt"))
+ {
+ fputs_unfiltered (parse->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputs_unfiltered ("Cannot execute command ", raw_stdout);
+ fputstr_unfiltered (parse->command, '"', raw_stdout);
+ fputs_unfiltered (" while target running", raw_stdout);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ return MI_CMD_ERROR;
+ }
+ }
+ last_async_command = xstrdup (parse->token);
+ make_exec_cleanup (free_current_contents, &last_async_command);
+ /* FIXME: DELETE THIS! */
+ if (parse->cmd->args_func != NULL)
+ return parse->cmd->args_func (parse->args, 0 /*from_tty */ );
+ return parse->cmd->argv_func (parse->command, parse->argv, parse->argc);
+ }
+ else if (parse->cmd->cli.cmd != 0)
+ {
+ /* FIXME: DELETE THIS. */
+ /* The operation is still implemented by a cli command */
+ /* Must be a synchronous one */
+ mi_execute_cli_command (parse->cmd->cli.cmd, parse->cmd->cli.args_p,
+ parse->args);
+ return MI_CMD_DONE;
+ }
+ else
+ {
+ /* FIXME: DELETE THIS. */
+ fputs_unfiltered (parse->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputs_unfiltered ("Undefined mi command: ", raw_stdout);
+ fputstr_unfiltered (parse->command, '"', raw_stdout);
+ fputs_unfiltered (" (missing implementation)", raw_stdout);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ return MI_CMD_ERROR;
+ }
+}
+
+/* FIXME: This is just a hack so we can get some extra commands going.
+ We don't want to channel things through the CLI, but call libgdb directly */
+/* Use only for synchronous commands */
+
+void
+mi_execute_cli_command (const char *cmd, int args_p, const char *args)
+{
+ if (cmd != 0)
+ {
+ struct cleanup *old_cleanups;
+ char *run;
+ if (args_p)
+ xasprintf (&run, "%s %s", cmd, args);
+ else
+ run = xstrdup (cmd);
+ if (mi_debug_p)
+ /* FIXME: gdb_???? */
+ fprintf_unfiltered (gdb_stdout, "cli=%s run=%s\n",
+ cmd, run);
+ old_cleanups = make_cleanup (xfree, run);
+ execute_command ( /*ui */ run, 0 /*from_tty */ );
+ do_cleanups (old_cleanups);
+ return;
+ }
+}
+
+enum mi_cmd_result
+mi_execute_async_cli_command (char *mi, char *args, int from_tty)
+{
+ struct cleanup *old_cleanups;
+ char *run;
+ char *async_args;
+
+ if (target_can_async_p ())
+ {
+ async_args = (char *) xmalloc (strlen (args) + 2);
+ make_exec_cleanup (free, async_args);
+ strcpy (async_args, args);
+ strcat (async_args, "&");
+ xasprintf (&run, "%s %s", mi, async_args);
+ make_exec_cleanup (free, run);
+ add_continuation (mi_exec_async_cli_cmd_continuation, NULL);
+ old_cleanups = NULL;
+ }
+ else
+ {
+ xasprintf (&run, "%s %s", mi, args);
+ old_cleanups = make_cleanup (xfree, run);
+ }
+
+ if (!target_can_async_p ())
+ {
+ /* NOTE: For synchronous targets asynchronous behavour is faked by
+ printing out the GDB prompt before we even try to execute the
+ command. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^running\n", raw_stdout);
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
+ else
+ {
+ /* FIXME: cagney/1999-11-29: Printing this message before
+ calling execute_command is wrong. It should only be printed
+ once gdb has confirmed that it really has managed to send a
+ run command to the target. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^running\n", raw_stdout);
+ }
+
+ execute_command ( /*ui */ run, 0 /*from_tty */ );
+
+ if (!target_can_async_p ())
+ {
+ /* Do this before doing any printing. It would appear that some
+ print code leaves garbage around in the buffer. */
+ do_cleanups (old_cleanups);
+ /* If the target was doing the operation synchronously we fake
+ the stopped message. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("*stopped", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ return MI_CMD_QUIET;
+ }
+ return MI_CMD_DONE;
+}
+
+void
+mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg)
+{
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("*stopped", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ fputs_unfiltered ("\n", raw_stdout);
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ do_exec_cleanups (ALL_CLEANUPS);
+}
+
+void
+mi_load_progress (const char *section_name,
+ unsigned long sent_so_far,
+ unsigned long total_section,
+ unsigned long total_sent,
+ unsigned long grand_total)
+{
+ struct timeval time_now, delta, update_threshold;
+ static struct timeval last_update;
+ static char *previous_sect_name = NULL;
+ int new_section;
+
+ if (!current_interp_named_p (INTERP_MI)
+ && !current_interp_named_p (INTERP_MI1))
+ return;
+
+ update_threshold.tv_sec = 0;
+ update_threshold.tv_usec = 500000;
+ gettimeofday (&time_now, NULL);
+
+ delta.tv_usec = time_now.tv_usec - last_update.tv_usec;
+ delta.tv_sec = time_now.tv_sec - last_update.tv_sec;
+
+ if (delta.tv_usec < 0)
+ {
+ delta.tv_sec -= 1;
+ delta.tv_usec += 1000000;
+ }
+
+ new_section = (previous_sect_name ?
+ strcmp (previous_sect_name, section_name) : 1);
+ if (new_section)
+ {
+ struct cleanup *cleanup_tuple;
+ xfree (previous_sect_name);
+ previous_sect_name = xstrdup (section_name);
+
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("+download", raw_stdout);
+ cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_string (uiout, "section", section_name);
+ ui_out_field_int (uiout, "section-size", total_section);
+ ui_out_field_int (uiout, "total-size", grand_total);
+ do_cleanups (cleanup_tuple);
+ mi_out_put (uiout, raw_stdout);
+ fputs_unfiltered ("\n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
+
+ if (delta.tv_sec >= update_threshold.tv_sec &&
+ delta.tv_usec >= update_threshold.tv_usec)
+ {
+ struct cleanup *cleanup_tuple;
+ last_update.tv_sec = time_now.tv_sec;
+ last_update.tv_usec = time_now.tv_usec;
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("+download", raw_stdout);
+ cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_string (uiout, "section", section_name);
+ ui_out_field_int (uiout, "section-sent", sent_so_far);
+ ui_out_field_int (uiout, "section-size", total_section);
+ ui_out_field_int (uiout, "total-sent", total_sent);
+ ui_out_field_int (uiout, "total-size", grand_total);
+ do_cleanups (cleanup_tuple);
+ mi_out_put (uiout, raw_stdout);
+ fputs_unfiltered ("\n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
+}
+
+void
+mi_setup_architecture_data (void)
+{
+ old_regs = xmalloc ((NUM_REGS + NUM_PSEUDO_REGS) * MAX_REGISTER_SIZE + 1);
+ memset (old_regs, 0, (NUM_REGS + NUM_PSEUDO_REGS) * MAX_REGISTER_SIZE + 1);
+}
+
+void
+_initialize_mi_main (void)
+{
+ DEPRECATED_REGISTER_GDBARCH_SWAP (old_regs);
+ deprecated_register_gdbarch_swap (NULL, 0, mi_setup_architecture_data);
+}
diff --git a/contrib/gdb/gdb/mi/mi-main.h b/contrib/gdb/gdb/mi/mi-main.h
new file mode 100644
index 0000000..8e504c6
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-main.h
@@ -0,0 +1,33 @@
+/* MI Internal Functions for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MI_MAIN_H
+#define MI_MAIN_H
+
+extern void mi_setup_architecture_data (void);
+
+extern void mi_load_progress (const char *section_name,
+ unsigned long sent_so_far,
+ unsigned long total_section,
+ unsigned long total_sent,
+ unsigned long grand_total);
+#endif
+
diff --git a/contrib/gdb/gdb/mi/mi-out.c b/contrib/gdb/gdb/mi/mi-out.c
new file mode 100644
index 0000000..2be9d17
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-out.c
@@ -0,0 +1,409 @@
+/* MI Command Set - output generating routines.
+
+ Copyright 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ui-out.h"
+#include "mi-out.h"
+
+struct ui_out_data
+ {
+ int suppress_field_separator;
+ int suppress_output;
+ int mi_version;
+ struct ui_file *buffer;
+ };
+typedef struct ui_out_data mi_out_data;
+
+/* These are the MI output functions */
+
+static void mi_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows, const char *tblid);
+static void mi_table_body (struct ui_out *uiout);
+static void mi_table_end (struct ui_out *uiout);
+static void mi_table_header (struct ui_out *uiout, int width,
+ enum ui_align alig, const char *col_name,
+ const char *colhdr);
+static void mi_begin (struct ui_out *uiout, enum ui_out_type type,
+ int level, const char *id);
+static void mi_end (struct ui_out *uiout, enum ui_out_type type, int level);
+static void mi_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname, int value);
+static void mi_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname);
+static void mi_field_string (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname,
+ const char *string);
+static void mi_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ const char *fldname, const char *format,
+ va_list args);
+static void mi_spaces (struct ui_out *uiout, int numspaces);
+static void mi_text (struct ui_out *uiout, const char *string);
+static void mi_message (struct ui_out *uiout, int verbosity,
+ const char *format, va_list args);
+static void mi_wrap_hint (struct ui_out *uiout, char *identstring);
+static void mi_flush (struct ui_out *uiout);
+
+/* This is the MI ui-out implementation functions vector */
+
+/* FIXME: This can be initialized dynamically after default is set to
+ handle initial output in main.c */
+
+struct ui_out_impl mi_ui_out_impl =
+{
+ mi_table_begin,
+ mi_table_body,
+ mi_table_end,
+ mi_table_header,
+ mi_begin,
+ mi_end,
+ mi_field_int,
+ mi_field_skip,
+ mi_field_string,
+ mi_field_fmt,
+ mi_spaces,
+ mi_text,
+ mi_message,
+ mi_wrap_hint,
+ mi_flush,
+ NULL,
+ 1, /* Needs MI hacks. */
+};
+
+/* Prototypes for local functions */
+
+extern void _initialize_mi_out (void);
+static void field_separator (struct ui_out *uiout);
+static void mi_open (struct ui_out *uiout, const char *name,
+ enum ui_out_type type);
+static void mi_close (struct ui_out *uiout, enum ui_out_type type);
+
+/* Mark beginning of a table */
+
+void
+mi_table_begin (struct ui_out *uiout,
+ int nr_cols,
+ int nr_rows,
+ const char *tblid)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ mi_open (uiout, tblid, ui_out_type_tuple);
+ mi_field_int (uiout, -1/*fldno*/, -1/*width*/, -1/*alin*/,
+ "nr_rows", nr_rows);
+ mi_field_int (uiout, -1/*fldno*/, -1/*width*/, -1/*alin*/,
+ "nr_cols", nr_cols);
+ mi_open (uiout, "hdr", ui_out_type_list);
+}
+
+/* Mark beginning of a table body */
+
+void
+mi_table_body (struct ui_out *uiout)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ /* close the table header line if there were any headers */
+ mi_close (uiout, ui_out_type_list);
+ mi_open (uiout, "body", ui_out_type_list);
+}
+
+/* Mark end of a table */
+
+void
+mi_table_end (struct ui_out *uiout)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ data->suppress_output = 0;
+ mi_close (uiout, ui_out_type_list); /* body */
+ mi_close (uiout, ui_out_type_tuple);
+}
+
+/* Specify table header */
+
+void
+mi_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
+ const char *col_name,
+ const char *colhdr)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ mi_open (uiout, NULL, ui_out_type_tuple);
+ mi_field_int (uiout, 0, 0, 0, "width", width);
+ mi_field_int (uiout, 0, 0, 0, "alignment", alignment);
+ mi_field_string (uiout, 0, 0, 0, "col_name", col_name);
+ mi_field_string (uiout, 0, width, alignment, "colhdr", colhdr);
+ mi_close (uiout, ui_out_type_tuple);
+}
+
+/* Mark beginning of a list */
+
+void
+mi_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level,
+ const char *id)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ mi_open (uiout, id, type);
+}
+
+/* Mark end of a list */
+
+void
+mi_end (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ mi_close (uiout, type);
+}
+
+/* output an int field */
+
+void
+mi_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alignment, const char *fldname, int value)
+{
+ char buffer[20]; /* FIXME: how many chars long a %d can become? */
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+
+ sprintf (buffer, "%d", value);
+ mi_field_string (uiout, fldno, width, alignment, fldname, buffer);
+}
+
+/* used to ommit a field */
+
+void
+mi_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alignment, const char *fldname)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ mi_field_string (uiout, fldno, width, alignment, fldname, "");
+}
+
+/* other specific mi_field_* end up here so alignment and field
+ separators are both handled by mi_field_string */
+
+void
+mi_field_string (struct ui_out *uiout,
+ int fldno,
+ int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *string)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ field_separator (uiout);
+ if (fldname)
+ fprintf_unfiltered (data->buffer, "%s=", fldname);
+ fprintf_unfiltered (data->buffer, "\"");
+ if (string)
+ fputstr_unfiltered (string, '"', data->buffer);
+ fprintf_unfiltered (data->buffer, "\"");
+}
+
+/* This is the only field function that does not align */
+
+void
+mi_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ const char *fldname,
+ const char *format,
+ va_list args)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ field_separator (uiout);
+ if (fldname)
+ fprintf_unfiltered (data->buffer, "%s=\"", fldname);
+ else
+ fputs_unfiltered ("\"", data->buffer);
+ vfprintf_unfiltered (data->buffer, format, args);
+ fputs_unfiltered ("\"", data->buffer);
+}
+
+void
+mi_spaces (struct ui_out *uiout, int numspaces)
+{
+}
+
+void
+mi_text (struct ui_out *uiout, const char *string)
+{
+}
+
+void
+mi_message (struct ui_out *uiout, int verbosity,
+ const char *format,
+ va_list args)
+{
+}
+
+void
+mi_wrap_hint (struct ui_out *uiout, char *identstring)
+{
+ wrap_here (identstring);
+}
+
+void
+mi_flush (struct ui_out *uiout)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ gdb_flush (data->buffer);
+}
+
+/* local functions */
+
+/* access to ui_out format private members */
+
+static void
+field_separator (struct ui_out *uiout)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ if (data->suppress_field_separator)
+ data->suppress_field_separator = 0;
+ else
+ fputc_unfiltered (',', data->buffer);
+}
+
+static void
+mi_open (struct ui_out *uiout,
+ const char *name,
+ enum ui_out_type type)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ field_separator (uiout);
+ data->suppress_field_separator = 1;
+ if (name)
+ fprintf_unfiltered (data->buffer, "%s=", name);
+ switch (type)
+ {
+ case ui_out_type_tuple:
+ fputc_unfiltered ('{', data->buffer);
+ break;
+ case ui_out_type_list:
+ fputc_unfiltered ('[', data->buffer);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+}
+
+static void
+mi_close (struct ui_out *uiout,
+ enum ui_out_type type)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ switch (type)
+ {
+ case ui_out_type_tuple:
+ fputc_unfiltered ('}', data->buffer);
+ break;
+ case ui_out_type_list:
+ fputc_unfiltered (']', data->buffer);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ data->suppress_field_separator = 0;
+}
+
+/* add a string to the buffer */
+
+void
+mi_out_buffered (struct ui_out *uiout, char *string)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ fprintf_unfiltered (data->buffer, "%s", string);
+}
+
+/* clear the buffer */
+
+void
+mi_out_rewind (struct ui_out *uiout)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ ui_file_rewind (data->buffer);
+}
+
+/* dump the buffer onto the specified stream */
+
+static void
+do_write (void *data, const char *buffer, long length_buffer)
+{
+ ui_file_write (data, buffer, length_buffer);
+}
+
+void
+mi_out_put (struct ui_out *uiout,
+ struct ui_file *stream)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ ui_file_put (data->buffer, do_write, stream);
+ ui_file_rewind (data->buffer);
+}
+
+/* Current MI version. */
+
+int
+mi_version (struct ui_out *uiout)
+{
+ mi_out_data *data = ui_out_data (uiout);
+ return data->mi_version;
+}
+
+/* initalize private members at startup */
+
+struct ui_out *
+mi_out_new (int mi_version)
+{
+ int flags = 0;
+ mi_out_data *data = XMALLOC (mi_out_data);
+ data->suppress_field_separator = 0;
+ data->suppress_output = 0;
+ data->mi_version = mi_version;
+ /* FIXME: This code should be using a ``string_file'' and not the
+ TUI buffer hack. */
+ data->buffer = mem_fileopen ();
+ return ui_out_new (&mi_ui_out_impl, data, flags);
+}
+
+/* standard gdb initialization hook */
+void
+_initialize_mi_out (void)
+{
+ /* nothing happens here */
+}
diff --git a/contrib/gdb/gdb/mi/mi-out.h b/contrib/gdb/gdb/mi/mi-out.h
new file mode 100644
index 0000000..817f2eb
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-out.h
@@ -0,0 +1,36 @@
+/* MI Command Set - MI output generating routines for GDB.
+ Copyright 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MI_OUT_H
+#define MI_OUT_H 1
+
+struct ui_out;
+struct ui_file;
+
+extern struct ui_out *mi_out_new (int mi_version);
+extern void mi_out_put (struct ui_out *uiout, struct ui_file *stream);
+extern void mi_out_rewind (struct ui_out *uiout);
+extern void mi_out_buffered (struct ui_out *uiout, char *string);
+
+/* Return the version number of the current MI. */
+extern int mi_version (struct ui_out *uiout);
+
+#endif /* MI_OUT_H */
diff --git a/contrib/gdb/gdb/mi/mi-parse.c b/contrib/gdb/gdb/mi/mi-parse.c
new file mode 100644
index 0000000..a0ff889
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-parse.c
@@ -0,0 +1,233 @@
+/* MI Command Set - MI parser.
+
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mi-cmds.h"
+#include "mi-parse.h"
+
+#include <ctype.h>
+#include "gdb_string.h"
+
+static void
+mi_parse_argv (char *args, struct mi_parse *parse)
+{
+ char *chp = args;
+ int argc = 0;
+ char **argv = xmalloc ((argc + 1) * sizeof (char *));
+ argv[argc] = NULL;
+ while (1)
+ {
+ char *arg;
+ /* skip leading white space */
+ while (isspace (*chp))
+ chp++;
+ /* Three possibilities: EOF, quoted string, or other text. */
+ switch (*chp)
+ {
+ case '\0':
+ parse->argv = argv;
+ parse->argc = argc;
+ return;
+ case '"':
+ {
+ /* A quoted string. */
+ int len;
+ char *start = chp + 1;
+ /* Determine the buffer size. */
+ chp = start;
+ len = 0;
+ while (*chp != '\0' && *chp != '"')
+ {
+ if (*chp == '\\')
+ {
+ chp++;
+ if (parse_escape (&chp) <= 0)
+ {
+ /* Do not allow split lines or "\000" */
+ freeargv (argv);
+ return;
+ }
+ }
+ else
+ chp++;
+ len++;
+ }
+ /* Insist on a closing quote. */
+ if (*chp != '"')
+ {
+ freeargv (argv);
+ return;
+ }
+ /* Insist on trailing white space. */
+ if (chp[1] != '\0' && !isspace (chp[1]))
+ {
+ freeargv (argv);
+ return;
+ }
+ /* create the buffer. */
+ arg = xmalloc ((len + 1) * sizeof (char));
+ /* And copy the characters in. */
+ chp = start;
+ len = 0;
+ while (*chp != '\0' && *chp != '"')
+ {
+ if (*chp == '\\')
+ {
+ chp++;
+ arg[len] = parse_escape (&chp);
+ }
+ else
+ arg[len] = *chp++;
+ len++;
+ }
+ arg[len] = '\0';
+ chp++; /* that closing quote. */
+ break;
+ }
+ default:
+ {
+ /* An unquoted string. Accumulate all non blank
+ characters into a buffer. */
+ int len;
+ char *start = chp;
+ while (*chp != '\0' && !isspace (*chp))
+ {
+ chp++;
+ }
+ len = chp - start;
+ arg = xmalloc ((len + 1) * sizeof (char));
+ strncpy (arg, start, len);
+ arg[len] = '\0';
+ break;
+ }
+ }
+ /* Append arg to argv. */
+ argv = xrealloc (argv, (argc + 2) * sizeof (char *));
+ argv[argc++] = arg;
+ argv[argc] = NULL;
+ }
+}
+
+
+void
+mi_parse_free (struct mi_parse *parse)
+{
+ if (parse == NULL)
+ return;
+ if (parse->command != NULL)
+ xfree (parse->command);
+ if (parse->token != NULL)
+ xfree (parse->token);
+ if (parse->args != NULL)
+ xfree (parse->args);
+ if (parse->argv != NULL)
+ freeargv (parse->argv);
+ xfree (parse);
+}
+
+
+struct mi_parse *
+mi_parse (char *cmd)
+{
+ char *chp;
+ struct mi_parse *parse = XMALLOC (struct mi_parse);
+ memset (parse, 0, sizeof (*parse));
+
+ /* Before starting, skip leading white space. */
+ while (isspace (*cmd))
+ cmd++;
+
+ /* Find/skip any token and then extract it. */
+ for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
+ ;
+ parse->token = xmalloc ((chp - cmd + 1) * sizeof (char *));
+ memcpy (parse->token, cmd, (chp - cmd));
+ parse->token[chp - cmd] = '\0';
+
+ /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
+ if (*chp != '-')
+ {
+ while (isspace (*chp))
+ chp++;
+ parse->command = xstrdup (chp);
+ parse->op = CLI_COMMAND;
+ return parse;
+ }
+
+ /* Extract the command. */
+ {
+ char *tmp = chp + 1; /* discard ``-'' */
+ for (; *chp && !isspace (*chp); chp++)
+ ;
+ parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *));
+ memcpy (parse->command, tmp, chp - tmp);
+ parse->command[chp - tmp] = '\0';
+ }
+
+ /* Find the command in the MI table. */
+ parse->cmd = mi_lookup (parse->command);
+ if (parse->cmd == NULL)
+ {
+ /* FIXME: This should be a function call. */
+ fprintf_unfiltered
+ (raw_stdout,
+ "%s^error,msg=\"Undefined MI command: %s\"\n",
+ parse->token, parse->command);
+ mi_parse_free (parse);
+ return NULL;
+ }
+
+ /* Skip white space following the command. */
+ while (isspace (*chp))
+ chp++;
+
+ /* For new argv commands, attempt to return the parsed argument
+ list. */
+ if (parse->cmd->argv_func != NULL)
+ {
+ mi_parse_argv (chp, parse);
+ if (parse->argv == NULL)
+ {
+ /* FIXME: This should be a function call. */
+ fprintf_unfiltered
+ (raw_stdout,
+ "%s^error,msg=\"Problem parsing arguments: %s %s\"\n",
+ parse->token, parse->command, chp);
+ mi_parse_free (parse);
+ return NULL;
+ }
+ }
+
+ /* FIXME: DELETE THIS */
+ /* For CLI and old ARGS commands, also return the remainder of the
+ command line as a single string. */
+ if (parse->cmd->args_func != NULL
+ || parse->cmd->cli.cmd != NULL)
+ {
+ parse->args = xstrdup (chp);
+ }
+
+ /* Fully parsed. */
+ parse->op = MI_COMMAND;
+ return parse;
+}
diff --git a/contrib/gdb/gdb/mi/mi-parse.h b/contrib/gdb/gdb/mi/mi-parse.h
new file mode 100644
index 0000000..ae9f181
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-parse.h
@@ -0,0 +1,55 @@
+/* MI Command Set - MI Command Parser.
+ Copyright 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MI_PARSE_H
+#define MI_PARSE_H
+
+/* MI parser */
+
+enum mi_command_type
+ {
+ MI_COMMAND, CLI_COMMAND
+ };
+
+struct mi_parse
+ {
+ enum mi_command_type op;
+ char *command;
+ char *token;
+ const struct mi_cmd *cmd;
+ char *args;
+ char **argv;
+ int argc;
+ };
+
+/* Attempts to parse CMD returning a ``struct mi_command''. If CMD is
+ invalid, an error mesage is reported (MI format) and NULL is
+ returned. For a CLI_COMMAND, COMMAND, TOKEN and OP are initialized.
+ For an MI_COMMAND COMMAND, TOKEN, ARGS and OP are
+ initialized. Un-initialized fields are zero. */
+
+extern struct mi_parse *mi_parse (char *cmd);
+
+/* Free a command returned by mi_parse_command. */
+
+extern void mi_parse_free (struct mi_parse *cmd);
+
+#endif
diff --git a/contrib/gdb/gdb/mi/mi-symbol-cmds.c b/contrib/gdb/gdb/mi/mi-symbol-cmds.c
new file mode 100644
index 0000000..1d86d21
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-symbol-cmds.c
@@ -0,0 +1,67 @@
+/* MI Command Set - symbol commands.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "mi-cmds.h"
+#include "symtab.h"
+#include "ui-out.h"
+
+/* SYMBOL-LIST-LINES:
+
+ Print the list of all pc addresses and lines of code for
+ the provided (full or base) source file name. The entries
+ are sorted in ascending PC order. */
+
+enum mi_cmd_result
+mi_cmd_symbol_list_lines (char *command, char **argv, int argc)
+{
+ char *filename;
+ struct symtab *s;
+ int i;
+ struct cleanup *cleanup_stack, *cleanup_tuple;
+
+ if (argc != 1)
+ error ("mi_cmd_symbol_list_lines: Usage: SOURCE_FILENAME");
+
+ filename = argv[0];
+ s = lookup_symtab (filename);
+
+ if (s == NULL)
+ error ("mi_cmd_symbol_list_lines: Unknown source file name.");
+
+ /* Now, dump the associated line table. The pc addresses are already
+ sorted by increasing values in the symbol table, so no need to
+ perform any other sorting. */
+
+ cleanup_stack = make_cleanup_ui_out_list_begin_end (uiout, "lines");
+
+ if (LINETABLE (s) != NULL && LINETABLE (s)->nitems > 0)
+ for (i = 0; i < LINETABLE (s)->nitems; i++)
+ {
+ cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ ui_out_field_core_addr (uiout, "pc", LINETABLE (s)->item[i].pc);
+ ui_out_field_int (uiout, "line", LINETABLE (s)->item[i].line);
+ do_cleanups (cleanup_tuple);
+ }
+
+ do_cleanups (cleanup_stack);
+
+ return MI_CMD_DONE;
+}
diff --git a/contrib/gdb/gdb/minimon.h b/contrib/gdb/gdb/minimon.h
new file mode 100644
index 0000000..94fd774
--- /dev/null
+++ b/contrib/gdb/gdb/minimon.h
@@ -0,0 +1,601 @@
+/* Definitions and macros for support of AMD's remote debugger, MiniMON.
+ Copyright 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 0000000..83aef9d
--- /dev/null
+++ b/contrib/gdb/gdb/minsyms.c
@@ -0,0 +1,996 @@
+/* GDB routines for manipulating the minimal symbol tables.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004
+ 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 <ctype.h>
+#include "gdb_string.h"
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "demangle.h"
+#include "value.h"
+#include "cp-abi.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;
+
+/* Compute a hash code based using the same criteria as `strcmp_iw'. */
+
+unsigned int
+msymbol_hash_iw (const char *string)
+{
+ unsigned int hash = 0;
+ while (*string && *string != '(')
+ {
+ while (isspace (*string))
+ ++string;
+ if (*string && *string != '(')
+ {
+ hash = hash * 67 + *string - 113;
+ ++string;
+ }
+ }
+ return hash;
+}
+
+/* Compute a hash code for a string. */
+
+unsigned int
+msymbol_hash (const char *string)
+{
+ unsigned int hash = 0;
+ for (; *string; ++string)
+ hash = hash * 67 + *string - 113;
+ return hash;
+}
+
+/* Add the minimal symbol SYM to an objfile's minsym hash table, TABLE. */
+void
+add_minsym_to_hash_table (struct minimal_symbol *sym,
+ struct minimal_symbol **table)
+{
+ if (sym->hash_next == NULL)
+ {
+ unsigned int hash
+ = msymbol_hash (SYMBOL_LINKAGE_NAME (sym)) % MINIMAL_SYMBOL_HASH_SIZE;
+ sym->hash_next = table[hash];
+ table[hash] = sym;
+ }
+}
+
+/* Add the minimal symbol SYM to an objfile's minsym demangled hash table,
+ TABLE. */
+static void
+add_minsym_to_demangled_hash_table (struct minimal_symbol *sym,
+ struct minimal_symbol **table)
+{
+ if (sym->demangled_hash_next == NULL)
+ {
+ unsigned int hash = msymbol_hash_iw (SYMBOL_DEMANGLED_NAME (sym)) % MINIMAL_SYMBOL_HASH_SIZE;
+ sym->demangled_hash_next = table[hash];
+ table[hash] = sym;
+ }
+}
+
+
+/* Look through all the current minimal symbol tables and find the
+ first minimal symbol that matches NAME. If OBJF is non-NULL, limit
+ the search to that objfile. If SFILE is non-NULL, the only file-scope
+ symbols considered will be from that source file (global symbols are
+ still preferred). Returns a pointer to the minimal symbol that
+ matches, or NULL if no match is found.
+
+ 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 (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;
+
+ unsigned int hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ unsigned int dem_hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE;
+
+#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)
+ {
+ /* Do two passes: the first over the ordinary hash table,
+ and the second over the demangled hash table. */
+ int pass;
+
+ for (pass = 1; pass <= 2 && found_symbol == NULL; pass++)
+ {
+ /* Select hash list according to pass. */
+ if (pass == 1)
+ msymbol = objfile->msymbol_hash[hash];
+ else
+ msymbol = objfile->msymbol_demangled_hash[dem_hash];
+
+ while (msymbol != NULL && found_symbol == NULL)
+ {
+ /* FIXME: carlton/2003-02-27: This is an unholy
+ mixture of linkage names and natural names. If
+ you want to test the linkage names with strcmp,
+ do that. If you want to test the natural names
+ with strcmp_iw, use SYMBOL_MATCHES_NATURAL_NAME. */
+ if (strcmp (DEPRECATED_SYMBOL_NAME (msymbol), (name)) == 0
+ || (SYMBOL_DEMANGLED_NAME (msymbol) != NULL
+ && strcmp_iw (SYMBOL_DEMANGLED_NAME (msymbol),
+ (name)) == 0))
+ {
+ switch (MSYMBOL_TYPE (msymbol))
+ {
+ case mst_file_text:
+ case mst_file_data:
+ case mst_file_bss:
+#ifdef SOFUN_ADDRESS_MAYBE_MISSING
+ if (sfile == NULL
+ || strcmp (msymbol->filename, sfile) == 0)
+ 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;
+ }
+ }
+
+ /* Find the next symbol on the hash chain. */
+ if (pass == 1)
+ msymbol = msymbol->hash_next;
+ else
+ msymbol = msymbol->demangled_hash_next;
+ }
+ }
+ }
+ }
+ /* 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 has text type. If OBJF
+ is non-NULL, limit the search to that objfile. Returns a pointer
+ to the minimal symbol that matches, or NULL if no match is found.
+
+ This function only searches the mangled (linkage) names. */
+
+struct minimal_symbol *
+lookup_minimal_symbol_text (const char *name, struct objfile *objf)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ struct minimal_symbol *found_symbol = NULL;
+ struct minimal_symbol *found_file_symbol = NULL;
+
+ unsigned int hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+
+ for (objfile = object_files;
+ objfile != NULL && found_symbol == NULL;
+ objfile = objfile->next)
+ {
+ if (objf == NULL || objf == objfile)
+ {
+ for (msymbol = objfile->msymbol_hash[hash];
+ msymbol != NULL && found_symbol == NULL;
+ msymbol = msymbol->hash_next)
+ {
+ if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0 &&
+ (MSYMBOL_TYPE (msymbol) == mst_text ||
+ MSYMBOL_TYPE (msymbol) == mst_file_text))
+ {
+ switch (MSYMBOL_TYPE (msymbol))
+ {
+ case mst_file_text:
+ found_file_symbol = msymbol;
+ 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 is a solib trampoline.
+ If OBJF is non-NULL, limit the search to that objfile. Returns a
+ pointer to the minimal symbol that matches, or NULL if no match is
+ found.
+
+ This function only searches the mangled (linkage) names. */
+
+struct minimal_symbol *
+lookup_minimal_symbol_solib_trampoline (const char *name,
+ struct objfile *objf)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ struct minimal_symbol *found_symbol = NULL;
+
+ unsigned int hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+
+ for (objfile = object_files;
+ objfile != NULL && found_symbol == NULL;
+ objfile = objfile->next)
+ {
+ if (objf == NULL || objf == objfile)
+ {
+ for (msymbol = objfile->msymbol_hash[hash];
+ msymbol != NULL && found_symbol == NULL;
+ msymbol = msymbol->hash_next)
+ {
+ if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0 &&
+ 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, and matches SECTION (if non-NULL). 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_section (CORE_ADDR pc, asection *section)
+{
+ int lo;
+ int hi;
+ int new;
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ struct minimal_symbol *best_symbol = NULL;
+ struct obj_section *pc_section;
+
+ /* PC has to be in a known section. This ensures that anything
+ beyond the end of the last segment doesn't appear to be part of
+ the last function in the last segment. */
+ pc_section = find_pc_section (pc);
+ if (pc_section == NULL)
+ return NULL;
+
+ /* NOTE: cagney/2004-01-27: Removed code (added 2003-07-19) that was
+ trying to force the PC into a valid section as returned by
+ find_pc_section. It broke IRIX 6.5 mdebug which relies on this
+ code returning an absolute symbol - the problem was that
+ find_pc_section wasn't returning an absolute section and hence
+ the code below would skip over absolute symbols. Since the
+ original problem was with finding a frame's function, and that
+ uses [indirectly] lookup_minimal_symbol_by_pc, the original
+ problem has been fixed by having that function use
+ find_pc_section. */
+
+ 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 (objfile->minimal_symbol_count > 0)
+ {
+ msymbol = objfile->msymbols;
+ 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 require 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 "section" specified, skip any symbol from wrong section */
+ /* This is the new code that distinguishes it from the old function */
+ if (section)
+ while (hi >= 0
+ /* Some types of debug info, such as COFF,
+ don't fill the bfd_section member, so don't
+ throw away symbols on those platforms. */
+ && SYMBOL_BFD_SECTION (&msymbol[hi]) != NULL
+ && SYMBOL_BFD_SECTION (&msymbol[hi]) != section)
+ --hi;
+
+ if (hi >= 0
+ && ((best_symbol == NULL) ||
+ (SYMBOL_VALUE_ADDRESS (best_symbol) <
+ SYMBOL_VALUE_ADDRESS (&msymbol[hi]))))
+ {
+ best_symbol = &msymbol[hi];
+ }
+ }
+ }
+ }
+ return (best_symbol);
+}
+
+/* Backward compatibility: search through the minimal symbol table
+ for a matching PC (no section given) */
+
+struct minimal_symbol *
+lookup_minimal_symbol_by_pc (CORE_ADDR pc)
+{
+ /* NOTE: cagney/2004-01-27: This was using find_pc_mapped_section to
+ force the section but that (well unless you're doing overlay
+ debugging) always returns NULL making the call somewhat useless. */
+ struct obj_section *section = find_pc_section (pc);
+ if (section == NULL)
+ return NULL;
+ return lookup_minimal_symbol_by_pc_section (pc, section->the_bfd_section);
+}
+
+
+/* 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 (bfd *);
+
+static int
+get_symbol_leading_char (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 (void)
+{
+ msym_count = 0;
+ msym_bunch = NULL;
+ msym_bunch_index = BUNCH_SIZE;
+}
+
+void
+prim_record_minimal_symbol (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 (objfile);
+ break;
+ case mst_data:
+ case mst_file_data:
+ section = SECT_OFF_DATA (objfile);
+ break;
+ case mst_bss:
+ case mst_file_bss:
+ section = SECT_OFF_BSS (objfile);
+ break;
+ default:
+ section = -1;
+ }
+
+ prim_record_minimal_symbol_and_info (name, address, ms_type,
+ NULL, section, NULL, objfile);
+}
+
+/* Record a minimal symbol in the msym bunches. Returns the symbol
+ newly created. */
+
+struct minimal_symbol *
+prim_record_minimal_symbol_and_info (const char *name, CORE_ADDR address,
+ enum minimal_symbol_type ms_type,
+ char *info, int section,
+ asection *bfd_section,
+ struct objfile *objfile)
+{
+ struct msym_bunch *new;
+ 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 (strncmp (tempstring, "__gnu_compiled", 14) == 0)
+ 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_INIT_LANGUAGE_SPECIFIC (msymbol, language_unknown);
+ SYMBOL_LANGUAGE (msymbol) = language_auto;
+ SYMBOL_SET_NAMES (msymbol, (char *)name, strlen (name), objfile);
+
+ SYMBOL_VALUE_ADDRESS (msymbol) = address;
+ SYMBOL_SECTION (msymbol) = section;
+ SYMBOL_BFD_SECTION (msymbol) = bfd_section;
+
+ MSYMBOL_TYPE (msymbol) = ms_type;
+ /* FIXME: This info, if it remains, needs its own field. */
+ MSYMBOL_INFO (msymbol) = info; /* FIXME! */
+ MSYMBOL_SIZE (msymbol) = 0;
+
+ /* The hash pointers must be cleared! If they're not,
+ add_minsym_to_hash_table will NOT add this msymbol to the hash table. */
+ msymbol->hash_next = NULL;
+ msymbol->demangled_hash_next = NULL;
+
+ 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.
+ Within groups with the same address, sort by name. */
+
+static int
+compare_minimal_symbols (const void *fn1p, const void *fn2p)
+{
+ const struct minimal_symbol *fn1;
+ 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); /* addr 1 is less than addr 2 */
+ }
+ else if (SYMBOL_VALUE_ADDRESS (fn1) > SYMBOL_VALUE_ADDRESS (fn2))
+ {
+ return (1); /* addr 1 is greater than addr 2 */
+ }
+ else
+ /* addrs are equal: sort by name */
+ {
+ char *name1 = SYMBOL_LINKAGE_NAME (fn1);
+ char *name2 = SYMBOL_LINKAGE_NAME (fn2);
+
+ if (name1 && name2) /* both have names */
+ return strcmp (name1, name2);
+ else if (name2)
+ return 1; /* fn1 has no name, so it is "less" */
+ else if (name1) /* fn2 has no name, so it is "less" */
+ return -1;
+ else
+ return (0); /* neither has a name, so they're equal. */
+ }
+}
+
+/* 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? */
+
+static void
+do_discard_minimal_symbols_cleanup (void *arg)
+{
+ struct msym_bunch *next;
+
+ while (msym_bunch != NULL)
+ {
+ next = msym_bunch->next;
+ xfree (msym_bunch);
+ msym_bunch = next;
+ }
+}
+
+struct cleanup *
+make_cleanup_discard_minimal_symbols (void)
+{
+ return make_cleanup (do_discard_minimal_symbols_cleanup, 0);
+}
+
+
+
+/* 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 objfile_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 (struct minimal_symbol *msymbol, int mcount,
+ struct objfile *objfile)
+{
+ 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))
+ && strcmp (SYMBOL_LINKAGE_NAME (copyfrom),
+ SYMBOL_LINKAGE_NAME ((copyfrom + 1))) == 0)
+ {
+ 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);
+}
+
+/* Build (or rebuild) the minimal symbol hash tables. This is necessary
+ after compacting or sorting the table since the entries move around
+ thus causing the internal minimal_symbol pointers to become jumbled. */
+
+static void
+build_minimal_symbol_hash_tables (struct objfile *objfile)
+{
+ int i;
+ struct minimal_symbol *msym;
+
+ /* Clear the hash tables. */
+ for (i = 0; i < MINIMAL_SYMBOL_HASH_SIZE; i++)
+ {
+ objfile->msymbol_hash[i] = 0;
+ objfile->msymbol_demangled_hash[i] = 0;
+ }
+
+ /* Now, (re)insert the actual entries. */
+ for (i = objfile->minimal_symbol_count, msym = objfile->msymbols;
+ i > 0;
+ i--, msym++)
+ {
+ msym->hash_next = 0;
+ add_minsym_to_hash_table (msym, objfile->msymbol_hash);
+
+ msym->demangled_hash_next = 0;
+ if (SYMBOL_DEMANGLED_NAME (msym) != NULL)
+ add_minsym_to_demangled_hash_table (msym,
+ objfile->msymbol_demangled_hash);
+ }
+}
+
+/* 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 (struct objfile *objfile)
+{
+ int bindex;
+ int mcount;
+ struct msym_bunch *bunch;
+ struct minimal_symbol *msymbols;
+ int alloc_count;
+ 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->objfile_obstack,
+ alloc_count * sizeof (struct minimal_symbol));
+ msymbols = (struct minimal_symbol *)
+ obstack_base (&objfile->objfile_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];
+ if (SYMBOL_LINKAGE_NAME (&msymbols[mcount])[0] == leading_char)
+ {
+ SYMBOL_LINKAGE_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, objfile);
+
+ obstack_blank (&objfile->objfile_obstack,
+ (mcount + 1 - alloc_count) * sizeof (struct minimal_symbol));
+ msymbols = (struct minimal_symbol *)
+ obstack_finish (&objfile->objfile_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_LINKAGE_NAME (&msymbols[mcount]) = NULL;
+ SYMBOL_VALUE_ADDRESS (&msymbols[mcount]) = 0;
+ MSYMBOL_INFO (&msymbols[mcount]) = NULL;
+ MSYMBOL_SIZE (&msymbols[mcount]) = 0;
+ 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 objfile_obstack
+ of this objfile. */
+
+ objfile->minimal_symbol_count = mcount;
+ objfile->msymbols = msymbols;
+
+ /* Try to guess the appropriate C++ ABI by looking at the names
+ of the minimal symbols in the table. */
+ {
+ int i;
+
+ for (i = 0; i < mcount; i++)
+ {
+ /* If a symbol's name starts with _Z and was successfully
+ demangled, then we can assume we've found a GNU v3 symbol.
+ For now we set the C++ ABI globally; if the user is
+ mixing ABIs then the user will need to "set cp-abi"
+ manually. */
+ const char *name = SYMBOL_LINKAGE_NAME (&objfile->msymbols[i]);
+ if (name[0] == '_' && name[1] == 'Z'
+ && SYMBOL_DEMANGLED_NAME (&objfile->msymbols[i]) != NULL)
+ {
+ set_cp_abi_as_auto_default ("gnu-v3");
+ break;
+ }
+ }
+ }
+
+ /* Now build the hash tables; we can't do this incrementally
+ at an earlier point since we weren't finished with the obstack
+ yet. (And if the msymbol obstack gets moved, all the internal
+ pointers to other msymbols need to be adjusted.) */
+ build_minimal_symbol_hash_tables (objfile);
+ }
+}
+
+/* Sort all the minimal symbols in OBJFILE. */
+
+void
+msymbols_sort (struct objfile *objfile)
+{
+ qsort (objfile->msymbols, objfile->minimal_symbol_count,
+ sizeof (struct minimal_symbol), compare_minimal_symbols);
+ build_minimal_symbol_hash_tables (objfile);
+}
+
+/* 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 (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 (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
+ && strcmp (SYMBOL_LINKAGE_NAME (msymbol),
+ SYMBOL_LINKAGE_NAME (tsymbol)) == 0)
+ return SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+ }
+ return 0;
+}
diff --git a/contrib/gdb/gdb/mips-nat.c b/contrib/gdb/gdb/mips-nat.c
new file mode 100644
index 0000000..626f770
--- /dev/null
+++ b/contrib/gdb/gdb/mips-nat.c
@@ -0,0 +1,254 @@
+/* Low level DECstation interface to ptrace, for GDB when running native.
+ Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1999, 2000, 2001
+ 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.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/user.h>
+#undef JB_S0
+#undef JB_S1
+#undef JB_S2
+#undef JB_S3
+#undef JB_S4
+#undef JB_S5
+#undef JB_S6
+#undef JB_S7
+#undef JB_SP
+#undef JB_S8
+#undef JB_PC
+#undef JB_SR
+#undef NJBREGS
+#include <setjmp.h> /* For JB_XXX. */
+
+/* Size of elements in jmpbuf */
+
+#define JB_ELEMENT_SIZE 4
+
+/* Map gdb internal register number to ptrace ``address''.
+ These ``addresses'' are defined in DECstation <sys/ptrace.h> */
+
+static int
+register_ptrace_addr (int regno)
+{
+ return (regno < 32 ? GPR_BASE + regno
+ : regno == mips_regnum (current_gdbarch)->pc ? PC
+ : regno == mips_regnum (current_gdbarch)->cause ? CAUSE
+ : regno == mips_regnum (current_gdbarch)->hi ? MMHI
+ : regno == mips_regnum (current_gdbarch)->lo ? MMLO
+ : regno == mips_regnum (current_gdbarch)->fp_control_status ? FPC_CSR
+ : regno == mips_regnum (current_gdbarch)->fp_implementation_revision ? FPC_EIR
+ : regno >= FP0_REGNUM ? FPR_BASE + (regno - FP0_REGNUM)
+ : 0);
+}
+
+static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
+
+/* Get all registers from the inferior */
+
+void
+fetch_inferior_registers (int regno)
+{
+ unsigned int regaddr;
+ char buf[MAX_REGISTER_SIZE];
+ int i;
+ char zerobuf[MAX_REGISTER_SIZE];
+ memset (zerobuf, 0, MAX_REGISTER_SIZE);
+
+ deprecated_registers_fetched ();
+
+ for (regno = 1; regno < NUM_REGS; regno++)
+ {
+ regaddr = register_ptrace_addr (regno);
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ *(int *) &buf[i] = ptrace (PT_READ_U, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) regaddr, 0);
+ regaddr += sizeof (int);
+ }
+ supply_register (regno, buf);
+ }
+
+ supply_register (ZERO_REGNUM, zerobuf);
+ /* Frame ptr reg must appear to be 0; it is faked by stack handling code. */
+ supply_register (DEPRECATED_FP_REGNUM, zerobuf);
+}
+
+/* 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 (int regno)
+{
+ unsigned int regaddr;
+ char buf[80];
+
+ if (regno > 0)
+ {
+ if (regno == ZERO_REGNUM || regno == PS_REGNUM
+ || regno == mips_regnum (current_gdbarch)->badvaddr
+ || regno == mips_regnum (current_gdbarch)->cause
+ || regno == mips_regnum (current_gdbarch)->fp_implementation_revision
+ || regno == DEPRECATED_FP_REGNUM
+ || (regno >= FIRST_EMBED_REGNUM && regno <= LAST_EMBED_REGNUM))
+ return;
+ regaddr = register_ptrace_addr (regno);
+ errno = 0;
+ ptrace (PT_WRITE_U, PIDGET (inferior_ptid), (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++)
+ store_inferior_registers (regno);
+ }
+}
+
+
+/* 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 (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char *buf;
+
+ buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
+ 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_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+
+ 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 (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR reg_addr)
+{
+ int regno;
+ unsigned int addr;
+ int bad_reg = -1;
+ reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */
+
+ char zerobuf[MAX_REGISTER_SIZE];
+ memset (zerobuf, 0, MAX_REGISTER_SIZE);
+
+
+ /* 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
+ 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 > core_reg_size)
+#ifdef KERNEL_U_ADDR
+ reg_ptr -= KERNEL_U_ADDR;
+#else
+ error ("Old mips core file can't be processed on this machine.");
+#endif
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ addr = 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.", REGISTER_NAME (bad_reg));
+ }
+ supply_register (ZERO_REGNUM, zerobuf);
+ /* Frame ptr reg must appear to be 0; it is faked by stack handling code. */
+ supply_register (DEPRECATED_FP_REGNUM, zerobuf);
+}
+
+/* Return the address in the core dump or inferior of register REGNO.
+ BLOCKEND is the address of the end of the user structure. */
+
+CORE_ADDR
+register_addr (int regno, CORE_ADDR blockend)
+{
+ CORE_ADDR addr;
+
+ if (regno < 0 || regno >= NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+
+/* Register that we are able to handle mips core file formats.
+ FIXME: is this really bfd_target_unknown_flavour? */
+
+static struct core_fns mips_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_mips (void)
+{
+ add_core_fns (&mips_core_fns);
+}
diff --git a/contrib/gdb/gdb/mips-tdep.c b/contrib/gdb/gdb/mips-tdep.c
new file mode 100644
index 0000000..cd37764
--- /dev/null
+++ b/contrib/gdb/gdb/mips-tdep.c
@@ -0,0 +1,6190 @@
+/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
+
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 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.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_assert.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "mips-tdep.h"
+#include "block.h"
+#include "reggroups.h"
+#include "opcode/mips.h"
+#include "elf/mips.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+
+static const struct objfile_data *mips_pdr_data;
+
+static void set_reg_offset (CORE_ADDR *saved_regs, int regnum, CORE_ADDR off);
+static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum);
+
+/* A useful bit in the CP0 status register (PS_REGNUM). */
+/* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip. */
+#define ST0_FR (1 << 26)
+
+/* The sizes of floating point registers. */
+
+enum
+{
+ MIPS_FPU_SINGLE_REGSIZE = 4,
+ MIPS_FPU_DOUBLE_REGSIZE = 8
+};
+
+
+static const char *mips_abi_string;
+
+static const char *mips_abi_strings[] = {
+ "auto",
+ "n32",
+ "o32",
+ "n64",
+ "o64",
+ "eabi32",
+ "eabi64",
+ NULL
+};
+
+struct frame_extra_info
+{
+ mips_extra_func_info_t proc_desc;
+ int num_args;
+};
+
+/* Various MIPS ISA options (related to stack analysis) can be
+ overridden dynamically. Establish an enum/array for managing
+ them. */
+
+static const char size_auto[] = "auto";
+static const char size_32[] = "32";
+static const char size_64[] = "64";
+
+static const char *size_enums[] = {
+ size_auto,
+ size_32,
+ size_64,
+ 0
+};
+
+/* Some MIPS boards don't support floating point while others only
+ support single-precision floating-point operations. See also
+ FP_REGISTER_DOUBLE. */
+
+enum mips_fpu_type
+{
+ MIPS_FPU_DOUBLE, /* Full double precision floating point. */
+ MIPS_FPU_SINGLE, /* Single precision floating point (R4650). */
+ MIPS_FPU_NONE /* No floating point. */
+};
+
+#ifndef MIPS_DEFAULT_FPU_TYPE
+#define MIPS_DEFAULT_FPU_TYPE MIPS_FPU_DOUBLE
+#endif
+static int mips_fpu_type_auto = 1;
+static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE;
+
+static int mips_debug = 0;
+
+/* MIPS specific per-architecture information */
+struct gdbarch_tdep
+{
+ /* from the elf header */
+ int elf_flags;
+
+ /* mips options */
+ enum mips_abi mips_abi;
+ enum mips_abi found_abi;
+ enum mips_fpu_type mips_fpu_type;
+ int mips_last_arg_regnum;
+ int mips_last_fp_arg_regnum;
+ int mips_default_saved_regsize;
+ int mips_fp_register_double;
+ int mips_default_stack_argsize;
+ int default_mask_address_p;
+ /* Is the target using 64-bit raw integer registers but only
+ storing a left-aligned 32-bit value in each? */
+ int mips64_transfers_32bit_regs_p;
+ /* Indexes for various registers. IRIX and embedded have
+ different values. This contains the "public" fields. Don't
+ add any that do not need to be public. */
+ const struct mips_regnum *regnum;
+ /* Register names table for the current register set. */
+ const char **mips_processor_reg_names;
+};
+
+const struct mips_regnum *
+mips_regnum (struct gdbarch *gdbarch)
+{
+ return gdbarch_tdep (gdbarch)->regnum;
+}
+
+static int
+mips_fpa0_regnum (struct gdbarch *gdbarch)
+{
+ return mips_regnum (gdbarch)->fp0 + 12;
+}
+
+#define MIPS_EABI (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI32 \
+ || gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI64)
+
+#define MIPS_LAST_FP_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_fp_arg_regnum)
+
+#define MIPS_LAST_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_arg_regnum)
+
+#define MIPS_FPU_TYPE (gdbarch_tdep (current_gdbarch)->mips_fpu_type)
+
+/* MIPS16 function addresses are odd (bit 0 is set). Here are some
+ functions to test, set, or clear bit 0 of addresses. */
+
+static CORE_ADDR
+is_mips16_addr (CORE_ADDR addr)
+{
+ return ((addr) & 1);
+}
+
+static CORE_ADDR
+make_mips16_addr (CORE_ADDR addr)
+{
+ return ((addr) | 1);
+}
+
+static CORE_ADDR
+unmake_mips16_addr (CORE_ADDR addr)
+{
+ return ((addr) & ~1);
+}
+
+/* Return the contents of register REGNUM as a signed integer. */
+
+static LONGEST
+read_signed_register (int regnum)
+{
+ void *buf = alloca (register_size (current_gdbarch, regnum));
+ deprecated_read_register_gen (regnum, buf);
+ return (extract_signed_integer
+ (buf, register_size (current_gdbarch, regnum)));
+}
+
+static LONGEST
+read_signed_register_pid (int regnum, ptid_t ptid)
+{
+ ptid_t save_ptid;
+ LONGEST retval;
+
+ if (ptid_equal (ptid, inferior_ptid))
+ return read_signed_register (regnum);
+
+ save_ptid = inferior_ptid;
+
+ inferior_ptid = ptid;
+
+ retval = read_signed_register (regnum);
+
+ inferior_ptid = save_ptid;
+
+ return retval;
+}
+
+/* Return the MIPS ABI associated with GDBARCH. */
+enum mips_abi
+mips_abi (struct gdbarch *gdbarch)
+{
+ return gdbarch_tdep (gdbarch)->mips_abi;
+}
+
+int
+mips_regsize (struct gdbarch *gdbarch)
+{
+ return (gdbarch_bfd_arch_info (gdbarch)->bits_per_word
+ / gdbarch_bfd_arch_info (gdbarch)->bits_per_byte);
+}
+
+/* Return the currently configured (or set) saved register size. */
+
+static const char *mips_saved_regsize_string = size_auto;
+
+static unsigned int
+mips_saved_regsize (struct gdbarch_tdep *tdep)
+{
+ if (mips_saved_regsize_string == size_auto)
+ return tdep->mips_default_saved_regsize;
+ else if (mips_saved_regsize_string == size_64)
+ return 8;
+ else /* if (mips_saved_regsize_string == size_32) */
+ return 4;
+}
+
+/* Functions for setting and testing a bit in a minimal symbol that
+ marks it as 16-bit function. The MSB of the minimal symbol's
+ "info" field is used for this purpose.
+
+ ELF_MAKE_MSYMBOL_SPECIAL tests whether an ELF symbol is "special",
+ i.e. refers to a 16-bit function, and sets a "special" bit in a
+ minimal symbol to mark it as a 16-bit function
+
+ MSYMBOL_IS_SPECIAL tests the "special" bit in a minimal symbol */
+
+static void
+mips_elf_make_msymbol_special (asymbol * sym, struct minimal_symbol *msym)
+{
+ if (((elf_symbol_type *) (sym))->internal_elf_sym.st_other == STO_MIPS16)
+ {
+ MSYMBOL_INFO (msym) = (char *)
+ (((long) MSYMBOL_INFO (msym)) | 0x80000000);
+ SYMBOL_VALUE_ADDRESS (msym) |= 1;
+ }
+}
+
+static int
+msymbol_is_special (struct minimal_symbol *msym)
+{
+ return (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0);
+}
+
+/* XFER a value from the big/little/left end of the register.
+ Depending on the size of the value it might occupy the entire
+ register or just part of it. Make an allowance for this, aligning
+ things accordingly. */
+
+static void
+mips_xfer_register (struct regcache *regcache, int reg_num, int length,
+ enum bfd_endian endian, bfd_byte * in,
+ const bfd_byte * out, int buf_offset)
+{
+ int reg_offset = 0;
+ gdb_assert (reg_num >= NUM_REGS);
+ /* Need to transfer the left or right part of the register, based on
+ the targets byte order. */
+ switch (endian)
+ {
+ case BFD_ENDIAN_BIG:
+ reg_offset = register_size (current_gdbarch, reg_num) - length;
+ break;
+ case BFD_ENDIAN_LITTLE:
+ reg_offset = 0;
+ break;
+ case BFD_ENDIAN_UNKNOWN: /* Indicates no alignment. */
+ reg_offset = 0;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr,
+ "xfer $%d, reg offset %d, buf offset %d, length %d, ",
+ reg_num, reg_offset, buf_offset, length);
+ if (mips_debug && out != NULL)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, "out ");
+ for (i = 0; i < length; i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", out[buf_offset + i]);
+ }
+ if (in != NULL)
+ regcache_cooked_read_part (regcache, reg_num, reg_offset, length,
+ in + buf_offset);
+ if (out != NULL)
+ regcache_cooked_write_part (regcache, reg_num, reg_offset, length,
+ out + buf_offset);
+ if (mips_debug && in != NULL)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, "in ");
+ for (i = 0; i < length; i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", in[buf_offset + i]);
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+}
+
+/* Determine if a MIPS3 or later cpu is operating in MIPS{1,2} FPU
+ compatiblity mode. A return value of 1 means that we have
+ physical 64-bit registers, but should treat them as 32-bit registers. */
+
+static int
+mips2_fp_compat (void)
+{
+ /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not
+ meaningful. */
+ if (register_size (current_gdbarch, mips_regnum (current_gdbarch)->fp0) ==
+ 4)
+ return 0;
+
+#if 0
+ /* FIXME drow 2002-03-10: This is disabled until we can do it consistently,
+ in all the places we deal with FP registers. PR gdb/413. */
+ /* Otherwise check the FR bit in the status register - it controls
+ the FP compatiblity mode. If it is clear we are in compatibility
+ mode. */
+ if ((read_register (PS_REGNUM) & ST0_FR) == 0)
+ return 1;
+#endif
+
+ return 0;
+}
+
+/* Indicate that the ABI makes use of double-precision registers
+ provided by the FPU (rather than combining pairs of registers to
+ form double-precision values). See also MIPS_FPU_TYPE. */
+#define FP_REGISTER_DOUBLE (gdbarch_tdep (current_gdbarch)->mips_fp_register_double)
+
+/* The amount of space reserved on the stack for registers. This is
+ different to MIPS_SAVED_REGSIZE as it determines the alignment of
+ data allocated after the registers have run out. */
+
+static const char *mips_stack_argsize_string = size_auto;
+
+static unsigned int
+mips_stack_argsize (struct gdbarch_tdep *tdep)
+{
+ if (mips_stack_argsize_string == size_auto)
+ return tdep->mips_default_stack_argsize;
+ else if (mips_stack_argsize_string == size_64)
+ return 8;
+ else /* if (mips_stack_argsize_string == size_32) */
+ return 4;
+}
+
+#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
+
+static mips_extra_func_info_t heuristic_proc_desc (CORE_ADDR, CORE_ADDR,
+ struct frame_info *, int);
+
+static CORE_ADDR heuristic_proc_start (CORE_ADDR);
+
+static CORE_ADDR read_next_frame_reg (struct frame_info *, int);
+
+static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *);
+
+static mips_extra_func_info_t find_proc_desc (CORE_ADDR pc,
+ struct frame_info *next_frame,
+ int cur_frame);
+
+static CORE_ADDR after_prologue (CORE_ADDR pc,
+ mips_extra_func_info_t proc_desc);
+
+static struct type *mips_float_register_type (void);
+static struct type *mips_double_register_type (void);
+
+/* The list of available "set mips " and "show mips " commands */
+
+static struct cmd_list_element *setmipscmdlist = NULL;
+static struct cmd_list_element *showmipscmdlist = NULL;
+
+/* Integer registers 0 thru 31 are handled explicitly by
+ mips_register_name(). Processor specific registers 32 and above
+ are listed in the followign tables. */
+
+enum
+{ NUM_MIPS_PROCESSOR_REGS = (90 - 32) };
+
+/* Generic MIPS. */
+
+static const char *mips_generic_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
+ "sr", "lo", "hi", "bad", "cause", "pc",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "fsr", "fir", "" /*"fp" */ , "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+};
+
+/* Names of IDT R3041 registers. */
+
+static const char *mips_r3041_reg_names[] = {
+ "sr", "lo", "hi", "bad", "cause", "pc",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "fsr", "fir", "", /*"fp" */ "",
+ "", "", "bus", "ccfg", "", "", "", "",
+ "", "", "port", "cmp", "", "", "epc", "prid",
+};
+
+/* Names of tx39 registers. */
+
+static const char *mips_tx39_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
+ "sr", "lo", "hi", "bad", "cause", "pc",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "config", "cache", "debug", "depc", "epc", ""
+};
+
+/* Names of IRIX registers. */
+static const char *mips_irix_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "pc", "cause", "bad", "hi", "lo", "fsr", "fir"
+};
+
+
+/* Return the name of the register corresponding to REGNO. */
+static const char *
+mips_register_name (int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ /* GPR names for all ABIs other than n32/n64. */
+ static char *mips_gpr_names[] = {
+ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
+ };
+
+ /* GPR names for n32 and n64 ABIs. */
+ static char *mips_n32_n64_gpr_names[] = {
+ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
+ };
+
+ enum mips_abi abi = mips_abi (current_gdbarch);
+
+ /* Map [NUM_REGS .. 2*NUM_REGS) onto the raw registers, but then
+ don't make the raw register names visible. */
+ int rawnum = regno % NUM_REGS;
+ if (regno < NUM_REGS)
+ return "";
+
+ /* The MIPS integer registers are always mapped from 0 to 31. The
+ names of the registers (which reflects the conventions regarding
+ register use) vary depending on the ABI. */
+ if (0 <= rawnum && rawnum < 32)
+ {
+ if (abi == MIPS_ABI_N32 || abi == MIPS_ABI_N64)
+ return mips_n32_n64_gpr_names[rawnum];
+ else
+ return mips_gpr_names[rawnum];
+ }
+ else if (32 <= rawnum && rawnum < NUM_REGS)
+ {
+ gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS);
+ return tdep->mips_processor_reg_names[rawnum - 32];
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ "mips_register_name: bad register number %d", rawnum);
+}
+
+/* Return the groups that a MIPS register can be categorised into. */
+
+static int
+mips_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *reggroup)
+{
+ int vector_p;
+ int float_p;
+ int raw_p;
+ int rawnum = regnum % NUM_REGS;
+ int pseudo = regnum / NUM_REGS;
+ if (reggroup == all_reggroup)
+ return pseudo;
+ vector_p = TYPE_VECTOR (register_type (gdbarch, regnum));
+ float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT;
+ /* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs
+ (gdbarch), as not all architectures are multi-arch. */
+ raw_p = rawnum < NUM_REGS;
+ if (REGISTER_NAME (regnum) == NULL || REGISTER_NAME (regnum)[0] == '\0')
+ return 0;
+ if (reggroup == float_reggroup)
+ return float_p && pseudo;
+ if (reggroup == vector_reggroup)
+ return vector_p && pseudo;
+ if (reggroup == general_reggroup)
+ return (!vector_p && !float_p) && pseudo;
+ /* Save the pseudo registers. Need to make certain that any code
+ extracting register values from a saved register cache also uses
+ pseudo registers. */
+ if (reggroup == save_reggroup)
+ return raw_p && pseudo;
+ /* Restore the same pseudo register. */
+ if (reggroup == restore_reggroup)
+ return raw_p && pseudo;
+ return 0;
+}
+
+/* Map the symbol table registers which live in the range [1 *
+ NUM_REGS .. 2 * NUM_REGS) back onto the corresponding raw
+ registers. Take care of alignment and size problems. */
+
+static void
+mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int cookednum, void *buf)
+{
+ int rawnum = cookednum % NUM_REGS;
+ gdb_assert (cookednum >= NUM_REGS && cookednum < 2 * NUM_REGS);
+ if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+ regcache_raw_read (regcache, rawnum, buf);
+ else if (register_size (gdbarch, rawnum) >
+ register_size (gdbarch, cookednum))
+ {
+ if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
+ || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ regcache_raw_read_part (regcache, rawnum, 0, 4, buf);
+ else
+ regcache_raw_read_part (regcache, rawnum, 4, 4, buf);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "bad register size");
+}
+
+static void
+mips_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache, int cookednum,
+ const void *buf)
+{
+ int rawnum = cookednum % NUM_REGS;
+ gdb_assert (cookednum >= NUM_REGS && cookednum < 2 * NUM_REGS);
+ if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+ regcache_raw_write (regcache, rawnum, buf);
+ else if (register_size (gdbarch, rawnum) >
+ register_size (gdbarch, cookednum))
+ {
+ if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
+ || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ regcache_raw_write_part (regcache, rawnum, 0, 4, buf);
+ else
+ regcache_raw_write_part (regcache, rawnum, 4, 4, buf);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "bad register size");
+}
+
+/* Table to translate MIPS16 register field to actual register number. */
+static int mips16_to_32_reg[8] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+
+/* 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;
+
+#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */
+#define PROC_HIGH_ADDR(proc) ((proc)->high_addr) /* upper address bound */
+#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)
+#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)
+#define PROC_FRAME_ADJUST(proc) ((proc)->frame_adjust)
+#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)
+/* FIXME drow/2002-06-10: If a pointer on the host is bigger than a long,
+ this will corrupt pdr.iline. Fortunately we don't use it. */
+#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 mips_extra_func_info info;
+ struct linked_proc_info *next;
+}
+ *linked_proc_desc_table = NULL;
+
+/* Number of bytes of storage in the actual machine representation for
+ register N. NOTE: This defines the pseudo register type so need to
+ rebuild the architecture vector. */
+
+static int mips64_transfers_32bit_regs_p = 0;
+
+static void
+set_mips64_transfers_32bit_regs (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+ /* FIXME: cagney/2003-11-15: Should be setting a field in "info"
+ instead of relying on globals. Doing that would let generic code
+ handle the search for this specific architecture. */
+ if (!gdbarch_update_p (info))
+ {
+ mips64_transfers_32bit_regs_p = 0;
+ error ("32-bit compatibility mode not supported");
+ }
+}
+
+/* Convert to/from a register and the corresponding memory value. */
+
+static int
+mips_convert_register_p (int regnum, struct type *type)
+{
+ return (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && register_size (current_gdbarch, regnum) == 4
+ && (regnum % NUM_REGS) >= mips_regnum (current_gdbarch)->fp0
+ && (regnum % NUM_REGS) < mips_regnum (current_gdbarch)->fp0 + 32
+ && TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8);
+}
+
+static void
+mips_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, void *to)
+{
+ get_frame_register (frame, regnum + 0, (char *) to + 4);
+ get_frame_register (frame, regnum + 1, (char *) to + 0);
+}
+
+static void
+mips_value_to_register (struct frame_info *frame, int regnum,
+ struct type *type, const void *from)
+{
+ put_frame_register (frame, regnum + 0, (const char *) from + 4);
+ put_frame_register (frame, regnum + 1, (const char *) from + 0);
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REG. */
+
+static struct type *
+mips_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ gdb_assert (regnum >= 0 && regnum < 2 * NUM_REGS);
+ if ((regnum % NUM_REGS) >= mips_regnum (current_gdbarch)->fp0
+ && (regnum % NUM_REGS) < mips_regnum (current_gdbarch)->fp0 + 32)
+ {
+ /* The floating-point registers raw, or cooked, always match
+ mips_regsize(), and also map 1:1, byte for byte. */
+ switch (gdbarch_byte_order (gdbarch))
+ {
+ case BFD_ENDIAN_BIG:
+ if (mips_regsize (gdbarch) == 4)
+ return builtin_type_ieee_single_big;
+ else
+ return builtin_type_ieee_double_big;
+ case BFD_ENDIAN_LITTLE:
+ if (mips_regsize (gdbarch) == 4)
+ return builtin_type_ieee_single_little;
+ else
+ return builtin_type_ieee_double_little;
+ case BFD_ENDIAN_UNKNOWN:
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ }
+ else if (regnum >=
+ (NUM_REGS + mips_regnum (current_gdbarch)->fp_control_status)
+ && regnum <= NUM_REGS + LAST_EMBED_REGNUM)
+ /* The pseudo/cooked view of the embedded registers is always
+ 32-bit. The raw view is handled below. */
+ return builtin_type_int32;
+ else if (regnum >= NUM_REGS && mips_regsize (gdbarch)
+ && gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p)
+ /* The target, while using a 64-bit register buffer, is only
+ transfering 32-bits of each integer register. Reflect this in
+ the cooked/pseudo register value. */
+ return builtin_type_int32;
+ else if (mips_regsize (gdbarch) == 8)
+ /* 64-bit ISA. */
+ return builtin_type_int64;
+ else
+ /* 32-bit ISA. */
+ return builtin_type_int32;
+}
+
+/* TARGET_READ_SP -- Remove useless bits from the stack pointer. */
+
+static CORE_ADDR
+mips_read_sp (void)
+{
+ return read_signed_register (SP_REGNUM);
+}
+
+/* Should the upper word of 64-bit addresses be zeroed? */
+enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
+
+static int
+mips_mask_address_p (struct gdbarch_tdep *tdep)
+{
+ switch (mask_address_var)
+ {
+ case AUTO_BOOLEAN_TRUE:
+ return 1;
+ case AUTO_BOOLEAN_FALSE:
+ return 0;
+ break;
+ case AUTO_BOOLEAN_AUTO:
+ return tdep->default_mask_address_p;
+ default:
+ internal_error (__FILE__, __LINE__, "mips_mask_address_p: bad switch");
+ return -1;
+ }
+}
+
+static void
+show_mask_address (char *cmd, int from_tty, struct cmd_list_element *c)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ switch (mask_address_var)
+ {
+ case AUTO_BOOLEAN_TRUE:
+ printf_filtered ("The 32 bit mips address mask is enabled\n");
+ break;
+ case AUTO_BOOLEAN_FALSE:
+ printf_filtered ("The 32 bit mips address mask is disabled\n");
+ break;
+ case AUTO_BOOLEAN_AUTO:
+ printf_filtered
+ ("The 32 bit address mask is set automatically. Currently %s\n",
+ mips_mask_address_p (tdep) ? "enabled" : "disabled");
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "show_mask_address: bad switch");
+ break;
+ }
+}
+
+/* Tell if the program counter value in MEMADDR is in a MIPS16 function. */
+
+static int
+pc_is_mips16 (bfd_vma memaddr)
+{
+ struct minimal_symbol *sym;
+
+ /* If bit 0 of the address is set, assume this is a MIPS16 address. */
+ if (is_mips16_addr (memaddr))
+ return 1;
+
+ /* A flag indicating that this is a MIPS16 function is stored by elfread.c in
+ the high bit of the info field. Use this to decide if the function is
+ MIPS16 or normal MIPS. */
+ sym = lookup_minimal_symbol_by_pc (memaddr);
+ if (sym)
+ return msymbol_is_special (sym);
+ else
+ return 0;
+}
+
+/* MIPS believes that the PC has a sign extended value. Perhaphs the
+ all registers should be sign extended for simplicity? */
+
+static CORE_ADDR
+mips_read_pc (ptid_t ptid)
+{
+ return read_signed_register_pid (mips_regnum (current_gdbarch)->pc, ptid);
+}
+
+static CORE_ADDR
+mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_signed (next_frame,
+ NUM_REGS + mips_regnum (gdbarch)->pc);
+}
+
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+ dummy frame. The frame ID's base needs to match the TOS value
+ saved by save_dummy_frame_tos(), and the PC match the dummy frame's
+ breakpoint. */
+
+static struct frame_id
+mips_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_id_build (frame_unwind_register_signed (next_frame, NUM_REGS + SP_REGNUM),
+ frame_pc_unwind (next_frame));
+}
+
+static void
+mips_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+ write_register_pid (mips_regnum (current_gdbarch)->pc, pc, ptid);
+}
+
+/* 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 (CORE_ADDR pc, mips_extra_func_info_t proc_desc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_addr, func_end;
+
+ /* Pass cur_frame == 0 to find_proc_desc. We should not attempt
+ to read the stack pointer from the current machine state, because
+ the current machine state has nothing to do with the information
+ we need from the proc_desc; and the process may or may not exist
+ right now. */
+ if (!proc_desc)
+ proc_desc = find_proc_desc (pc, NULL, 0);
+
+ 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;
+}
+
+/* Decode a MIPS32 instruction that saves a register in the stack, and
+ set the appropriate bit in the general register mask or float register mask
+ to indicate which register is saved. This is a helper function
+ for mips_find_saved_regs. */
+
+static void
+mips32_decode_reg_save (t_inst inst, unsigned long *gen_mask,
+ unsigned long *float_mask)
+{
+ int reg;
+
+ if ((inst & 0xffe00000) == 0xafa00000 /* sw reg,n($sp) */
+ || (inst & 0xffe00000) == 0xafc00000 /* sw reg,n($r30) */
+ || (inst & 0xffe00000) == 0xffa00000) /* sd reg,n($sp) */
+ {
+ /* It might be possible to use the instruction to
+ find the offset, rather than the code below which
+ is based on things being in a certain order in the
+ frame, but figuring out what the instruction's offset
+ is relative to might be a little tricky. */
+ reg = (inst & 0x001f0000) >> 16;
+ *gen_mask |= (1 << reg);
+ }
+ else if ((inst & 0xffe00000) == 0xe7a00000 /* swc1 freg,n($sp) */
+ || (inst & 0xffe00000) == 0xe7c00000 /* swc1 freg,n($r30) */
+ || (inst & 0xffe00000) == 0xf7a00000) /* sdc1 freg,n($sp) */
+
+ {
+ reg = ((inst & 0x001f0000) >> 16);
+ *float_mask |= (1 << reg);
+ }
+}
+
+/* Decode a MIPS16 instruction that saves a register in the stack, and
+ set the appropriate bit in the general register or float register mask
+ to indicate which register is saved. This is a helper function
+ for mips_find_saved_regs. */
+
+static void
+mips16_decode_reg_save (t_inst inst, unsigned long *gen_mask)
+{
+ if ((inst & 0xf800) == 0xd000) /* sw reg,n($sp) */
+ {
+ int reg = mips16_to_32_reg[(inst & 0x700) >> 8];
+ *gen_mask |= (1 << reg);
+ }
+ else if ((inst & 0xff00) == 0xf900) /* sd reg,n($sp) */
+ {
+ int reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
+ *gen_mask |= (1 << reg);
+ }
+ else if ((inst & 0xff00) == 0x6200 /* sw $ra,n($sp) */
+ || (inst & 0xff00) == 0xfa00) /* sd $ra,n($sp) */
+ *gen_mask |= (1 << RA_REGNUM);
+}
+
+
+/* Fetch and return instruction from the specified location. If the PC
+ is odd, assume it's a MIPS16 instruction; otherwise MIPS32. */
+
+static t_inst
+mips_fetch_instruction (CORE_ADDR addr)
+{
+ char buf[MIPS_INSTLEN];
+ int instlen;
+ int status;
+
+ if (pc_is_mips16 (addr))
+ {
+ instlen = MIPS16_INSTLEN;
+ addr = unmake_mips16_addr (addr);
+ }
+ else
+ instlen = MIPS_INSTLEN;
+ status = read_memory_nobpt (addr, buf, instlen);
+ if (status)
+ memory_error (status, addr);
+ return extract_unsigned_integer (buf, instlen);
+}
+
+static ULONGEST
+mips16_fetch_instruction (CORE_ADDR addr)
+{
+ char buf[MIPS_INSTLEN];
+ int instlen;
+ int status;
+
+ instlen = MIPS16_INSTLEN;
+ addr = unmake_mips16_addr (addr);
+ status = read_memory_nobpt (addr, buf, instlen);
+ if (status)
+ memory_error (status, addr);
+ return extract_unsigned_integer (buf, instlen);
+}
+
+static ULONGEST
+mips32_fetch_instruction (CORE_ADDR addr)
+{
+ char buf[MIPS_INSTLEN];
+ int instlen;
+ int status;
+ instlen = MIPS_INSTLEN;
+ status = read_memory_nobpt (addr, buf, instlen);
+ if (status)
+ memory_error (status, addr);
+ return extract_unsigned_integer (buf, instlen);
+}
+
+
+/* These the fields of 32 bit mips instructions */
+#define mips32_op(x) (x >> 26)
+#define itype_op(x) (x >> 26)
+#define itype_rs(x) ((x >> 21) & 0x1f)
+#define itype_rt(x) ((x >> 16) & 0x1f)
+#define itype_immediate(x) (x & 0xffff)
+
+#define jtype_op(x) (x >> 26)
+#define jtype_target(x) (x & 0x03ffffff)
+
+#define rtype_op(x) (x >> 26)
+#define rtype_rs(x) ((x >> 21) & 0x1f)
+#define rtype_rt(x) ((x >> 16) & 0x1f)
+#define rtype_rd(x) ((x >> 11) & 0x1f)
+#define rtype_shamt(x) ((x >> 6) & 0x1f)
+#define rtype_funct(x) (x & 0x3f)
+
+static CORE_ADDR
+mips32_relative_offset (unsigned long inst)
+{
+ long x;
+ x = itype_immediate (inst);
+ if (x & 0x8000) /* sign bit set */
+ {
+ x |= 0xffff0000; /* sign extension */
+ }
+ x = x << 2;
+ return x;
+}
+
+/* Determine whate to set a single step breakpoint while considering
+ branch prediction */
+static CORE_ADDR
+mips32_next_pc (CORE_ADDR pc)
+{
+ unsigned long inst;
+ int op;
+ inst = mips_fetch_instruction (pc);
+ if ((inst & 0xe0000000) != 0) /* Not a special, jump or branch instruction */
+ {
+ if (itype_op (inst) >> 2 == 5)
+ /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
+ {
+ op = (itype_op (inst) & 0x03);
+ switch (op)
+ {
+ case 0: /* BEQL */
+ goto equal_branch;
+ case 1: /* BNEL */
+ goto neq_branch;
+ case 2: /* BLEZL */
+ goto less_branch;
+ case 3: /* BGTZ */
+ goto greater_branch;
+ default:
+ pc += 4;
+ }
+ }
+ else if (itype_op (inst) == 17 && itype_rs (inst) == 8)
+ /* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */
+ {
+ int tf = itype_rt (inst) & 0x01;
+ int cnum = itype_rt (inst) >> 2;
+ int fcrcs =
+ read_signed_register (mips_regnum (current_gdbarch)->
+ fp_control_status);
+ int cond = ((fcrcs >> 24) & 0x0e) | ((fcrcs >> 23) & 0x01);
+
+ if (((cond >> cnum) & 0x01) == tf)
+ pc += mips32_relative_offset (inst) + 4;
+ else
+ pc += 8;
+ }
+ else
+ pc += 4; /* Not a branch, next instruction is easy */
+ }
+ else
+ { /* This gets way messy */
+
+ /* Further subdivide into SPECIAL, REGIMM and other */
+ switch (op = itype_op (inst) & 0x07) /* extract bits 28,27,26 */
+ {
+ case 0: /* SPECIAL */
+ op = rtype_funct (inst);
+ switch (op)
+ {
+ case 8: /* JR */
+ case 9: /* JALR */
+ /* Set PC to that address */
+ pc = read_signed_register (rtype_rs (inst));
+ break;
+ default:
+ pc += 4;
+ }
+
+ break; /* end SPECIAL */
+ case 1: /* REGIMM */
+ {
+ op = itype_rt (inst); /* branch condition */
+ switch (op)
+ {
+ case 0: /* BLTZ */
+ case 2: /* BLTZL */
+ case 16: /* BLTZAL */
+ case 18: /* BLTZALL */
+ less_branch:
+ if (read_signed_register (itype_rs (inst)) < 0)
+ pc += mips32_relative_offset (inst) + 4;
+ else
+ pc += 8; /* after the delay slot */
+ break;
+ case 1: /* BGEZ */
+ case 3: /* BGEZL */
+ case 17: /* BGEZAL */
+ case 19: /* BGEZALL */
+ if (read_signed_register (itype_rs (inst)) >= 0)
+ pc += mips32_relative_offset (inst) + 4;
+ else
+ pc += 8; /* after the delay slot */
+ break;
+ /* All of the other instructions in the REGIMM category */
+ default:
+ pc += 4;
+ }
+ }
+ break; /* end REGIMM */
+ case 2: /* J */
+ case 3: /* JAL */
+ {
+ unsigned long reg;
+ reg = jtype_target (inst) << 2;
+ /* Upper four bits get never changed... */
+ pc = reg + ((pc + 4) & 0xf0000000);
+ }
+ break;
+ /* FIXME case JALX : */
+ {
+ unsigned long reg;
+ reg = jtype_target (inst) << 2;
+ pc = reg + ((pc + 4) & 0xf0000000) + 1; /* yes, +1 */
+ /* Add 1 to indicate 16 bit mode - Invert ISA mode */
+ }
+ break; /* The new PC will be alternate mode */
+ case 4: /* BEQ, BEQL */
+ equal_branch:
+ if (read_signed_register (itype_rs (inst)) ==
+ read_signed_register (itype_rt (inst)))
+ pc += mips32_relative_offset (inst) + 4;
+ else
+ pc += 8;
+ break;
+ case 5: /* BNE, BNEL */
+ neq_branch:
+ if (read_signed_register (itype_rs (inst)) !=
+ read_signed_register (itype_rt (inst)))
+ pc += mips32_relative_offset (inst) + 4;
+ else
+ pc += 8;
+ break;
+ case 6: /* BLEZ, BLEZL */
+ if (read_signed_register (itype_rs (inst) <= 0))
+ pc += mips32_relative_offset (inst) + 4;
+ else
+ pc += 8;
+ break;
+ case 7:
+ default:
+ greater_branch: /* BGTZ, BGTZL */
+ if (read_signed_register (itype_rs (inst) > 0))
+ pc += mips32_relative_offset (inst) + 4;
+ else
+ pc += 8;
+ break;
+ } /* switch */
+ } /* else */
+ return pc;
+} /* mips32_next_pc */
+
+/* Decoding the next place to set a breakpoint is irregular for the
+ mips 16 variant, but fortunately, there fewer instructions. We have to cope
+ ith extensions for 16 bit instructions and a pair of actual 32 bit instructions.
+ We dont want to set a single step instruction on the extend instruction
+ either.
+ */
+
+/* Lots of mips16 instruction formats */
+/* Predicting jumps requires itype,ritype,i8type
+ and their extensions extItype,extritype,extI8type
+ */
+enum mips16_inst_fmts
+{
+ itype, /* 0 immediate 5,10 */
+ ritype, /* 1 5,3,8 */
+ rrtype, /* 2 5,3,3,5 */
+ rritype, /* 3 5,3,3,5 */
+ rrrtype, /* 4 5,3,3,3,2 */
+ rriatype, /* 5 5,3,3,1,4 */
+ shifttype, /* 6 5,3,3,3,2 */
+ i8type, /* 7 5,3,8 */
+ i8movtype, /* 8 5,3,3,5 */
+ i8mov32rtype, /* 9 5,3,5,3 */
+ i64type, /* 10 5,3,8 */
+ ri64type, /* 11 5,3,3,5 */
+ jalxtype, /* 12 5,1,5,5,16 - a 32 bit instruction */
+ exiItype, /* 13 5,6,5,5,1,1,1,1,1,1,5 */
+ extRitype, /* 14 5,6,5,5,3,1,1,1,5 */
+ extRRItype, /* 15 5,5,5,5,3,3,5 */
+ extRRIAtype, /* 16 5,7,4,5,3,3,1,4 */
+ EXTshifttype, /* 17 5,5,1,1,1,1,1,1,5,3,3,1,1,1,2 */
+ extI8type, /* 18 5,6,5,5,3,1,1,1,5 */
+ extI64type, /* 19 5,6,5,5,3,1,1,1,5 */
+ extRi64type, /* 20 5,6,5,5,3,3,5 */
+ extshift64type /* 21 5,5,1,1,1,1,1,1,5,1,1,1,3,5 */
+};
+/* I am heaping all the fields of the formats into one structure and
+ then, only the fields which are involved in instruction extension */
+struct upk_mips16
+{
+ CORE_ADDR offset;
+ unsigned int regx; /* Function in i8 type */
+ unsigned int regy;
+};
+
+
+/* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same format
+ for the bits which make up the immediatate extension. */
+
+static CORE_ADDR
+extended_offset (unsigned int extension)
+{
+ CORE_ADDR value;
+ value = (extension >> 21) & 0x3f; /* * extract 15:11 */
+ value = value << 6;
+ value |= (extension >> 16) & 0x1f; /* extrace 10:5 */
+ value = value << 5;
+ value |= extension & 0x01f; /* extract 4:0 */
+ return value;
+}
+
+/* Only call this function if you know that this is an extendable
+ instruction, It wont malfunction, but why make excess remote memory references?
+ If the immediate operands get sign extended or somthing, do it after
+ the extension is performed.
+ */
+/* FIXME: Every one of these cases needs to worry about sign extension
+ when the offset is to be used in relative addressing */
+
+
+static unsigned int
+fetch_mips_16 (CORE_ADDR pc)
+{
+ char buf[8];
+ pc &= 0xfffffffe; /* clear the low order bit */
+ target_read_memory (pc, buf, 2);
+ return extract_unsigned_integer (buf, 2);
+}
+
+static void
+unpack_mips16 (CORE_ADDR pc,
+ unsigned int extension,
+ unsigned int inst,
+ enum mips16_inst_fmts insn_format, struct upk_mips16 *upk)
+{
+ CORE_ADDR offset;
+ int regx;
+ int regy;
+ switch (insn_format)
+ {
+ case itype:
+ {
+ CORE_ADDR value;
+ if (extension)
+ {
+ value = extended_offset (extension);
+ value = value << 11; /* rom for the original value */
+ value |= inst & 0x7ff; /* eleven bits from instruction */
+ }
+ else
+ {
+ value = inst & 0x7ff;
+ /* FIXME : Consider sign extension */
+ }
+ offset = value;
+ regx = -1;
+ regy = -1;
+ }
+ break;
+ case ritype:
+ case i8type:
+ { /* A register identifier and an offset */
+ /* Most of the fields are the same as I type but the
+ immediate value is of a different length */
+ CORE_ADDR value;
+ if (extension)
+ {
+ value = extended_offset (extension);
+ value = value << 8; /* from the original instruction */
+ value |= inst & 0xff; /* eleven bits from instruction */
+ regx = (extension >> 8) & 0x07; /* or i8 funct */
+ if (value & 0x4000) /* test the sign bit , bit 26 */
+ {
+ value &= ~0x3fff; /* remove the sign bit */
+ value = -value;
+ }
+ }
+ else
+ {
+ value = inst & 0xff; /* 8 bits */
+ regx = (inst >> 8) & 0x07; /* or i8 funct */
+ /* FIXME: Do sign extension , this format needs it */
+ if (value & 0x80) /* THIS CONFUSES ME */
+ {
+ value &= 0xef; /* remove the sign bit */
+ value = -value;
+ }
+ }
+ offset = value;
+ regy = -1;
+ break;
+ }
+ case jalxtype:
+ {
+ unsigned long value;
+ unsigned int nexthalf;
+ value = ((inst & 0x1f) << 5) | ((inst >> 5) & 0x1f);
+ value = value << 16;
+ nexthalf = mips_fetch_instruction (pc + 2); /* low bit still set */
+ value |= nexthalf;
+ offset = value;
+ regx = -1;
+ regy = -1;
+ break;
+ }
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ upk->offset = offset;
+ upk->regx = regx;
+ upk->regy = regy;
+}
+
+
+static CORE_ADDR
+add_offset_16 (CORE_ADDR pc, int offset)
+{
+ return ((offset << 2) | ((pc + 2) & (0xf0000000)));
+}
+
+static CORE_ADDR
+extended_mips16_next_pc (CORE_ADDR pc,
+ unsigned int extension, unsigned int insn)
+{
+ int op = (insn >> 11);
+ switch (op)
+ {
+ case 2: /* Branch */
+ {
+ CORE_ADDR offset;
+ struct upk_mips16 upk;
+ unpack_mips16 (pc, extension, insn, itype, &upk);
+ offset = upk.offset;
+ if (offset & 0x800)
+ {
+ offset &= 0xeff;
+ offset = -offset;
+ }
+ pc += (offset << 1) + 2;
+ break;
+ }
+ case 3: /* JAL , JALX - Watch out, these are 32 bit instruction */
+ {
+ struct upk_mips16 upk;
+ unpack_mips16 (pc, extension, insn, jalxtype, &upk);
+ pc = add_offset_16 (pc, upk.offset);
+ if ((insn >> 10) & 0x01) /* Exchange mode */
+ pc = pc & ~0x01; /* Clear low bit, indicate 32 bit mode */
+ else
+ pc |= 0x01;
+ break;
+ }
+ case 4: /* beqz */
+ {
+ struct upk_mips16 upk;
+ int reg;
+ unpack_mips16 (pc, extension, insn, ritype, &upk);
+ reg = read_signed_register (upk.regx);
+ if (reg == 0)
+ pc += (upk.offset << 1) + 2;
+ else
+ pc += 2;
+ break;
+ }
+ case 5: /* bnez */
+ {
+ struct upk_mips16 upk;
+ int reg;
+ unpack_mips16 (pc, extension, insn, ritype, &upk);
+ reg = read_signed_register (upk.regx);
+ if (reg != 0)
+ pc += (upk.offset << 1) + 2;
+ else
+ pc += 2;
+ break;
+ }
+ case 12: /* I8 Formats btez btnez */
+ {
+ struct upk_mips16 upk;
+ int reg;
+ unpack_mips16 (pc, extension, insn, i8type, &upk);
+ /* upk.regx contains the opcode */
+ reg = read_signed_register (24); /* Test register is 24 */
+ if (((upk.regx == 0) && (reg == 0)) /* BTEZ */
+ || ((upk.regx == 1) && (reg != 0))) /* BTNEZ */
+ /* pc = add_offset_16(pc,upk.offset) ; */
+ pc += (upk.offset << 1) + 2;
+ else
+ pc += 2;
+ break;
+ }
+ case 29: /* RR Formats JR, JALR, JALR-RA */
+ {
+ struct upk_mips16 upk;
+ /* upk.fmt = rrtype; */
+ op = insn & 0x1f;
+ if (op == 0)
+ {
+ int reg;
+ upk.regx = (insn >> 8) & 0x07;
+ upk.regy = (insn >> 5) & 0x07;
+ switch (upk.regy)
+ {
+ case 0:
+ reg = upk.regx;
+ break;
+ case 1:
+ reg = 31;
+ break; /* Function return instruction */
+ case 2:
+ reg = upk.regx;
+ break;
+ default:
+ reg = 31;
+ break; /* BOGUS Guess */
+ }
+ pc = read_signed_register (reg);
+ }
+ else
+ pc += 2;
+ break;
+ }
+ case 30:
+ /* This is an instruction extension. Fetch the real instruction
+ (which follows the extension) and decode things based on
+ that. */
+ {
+ pc += 2;
+ pc = extended_mips16_next_pc (pc, insn, fetch_mips_16 (pc));
+ break;
+ }
+ default:
+ {
+ pc += 2;
+ break;
+ }
+ }
+ return pc;
+}
+
+static CORE_ADDR
+mips16_next_pc (CORE_ADDR pc)
+{
+ unsigned int insn = fetch_mips_16 (pc);
+ return extended_mips16_next_pc (pc, 0, insn);
+}
+
+/* The mips_next_pc function supports single_step when the remote
+ target monitor or stub is not developed enough to do a single_step.
+ It works by decoding the current instruction and predicting where a
+ branch will go. This isnt hard because all the data is available.
+ The MIPS32 and MIPS16 variants are quite different */
+CORE_ADDR
+mips_next_pc (CORE_ADDR pc)
+{
+ if (pc & 0x01)
+ return mips16_next_pc (pc);
+ else
+ return mips32_next_pc (pc);
+}
+
+struct mips_frame_cache
+{
+ CORE_ADDR base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+
+static struct mips_frame_cache *
+mips_mdebug_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ mips_extra_func_info_t proc_desc;
+ struct mips_frame_cache *cache;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* r0 bit means kernel trap */
+ int kernel_trap;
+ /* What registers have been saved? Bitmasks. */
+ unsigned long gen_mask, float_mask;
+
+ if ((*this_cache) != NULL)
+ return (*this_cache);
+ cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
+ (*this_cache) = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* Get the mdebug proc descriptor. */
+ proc_desc = find_proc_desc (frame_pc_unwind (next_frame), next_frame, 1);
+ 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 cache;
+
+ /* Extract the frame's base. */
+ cache->base = (frame_unwind_register_signed (next_frame, NUM_REGS + PROC_FRAME_REG (proc_desc))
+ + PROC_FRAME_OFFSET (proc_desc) - PROC_FRAME_ADJUST (proc_desc));
+
+ kernel_trap = PROC_REG_MASK (proc_desc) & 1;
+ gen_mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK (proc_desc);
+ float_mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK (proc_desc);
+
+ /* In any frame other than the innermost or a frame interrupted by a
+ signal, we assume that all registers have been saved. This
+ assumes that all register saves in a function happen before the
+ first function call. */
+ if (in_prologue (frame_pc_unwind (next_frame), PROC_LOW_ADDR (proc_desc))
+ /* Not sure exactly what kernel_trap means, but if it means the
+ kernel saves the registers without a prologue doing it, we
+ better not examine the prologue to see whether registers
+ have been saved yet. */
+ && !kernel_trap)
+ {
+ /* We need to figure out whether the registers that the
+ proc_desc claims are saved have been saved yet. */
+
+ CORE_ADDR addr;
+
+ /* Bitmasks; set if we have found a save for the register. */
+ unsigned long gen_save_found = 0;
+ unsigned long float_save_found = 0;
+ int mips16;
+
+ /* If the address is odd, assume this is MIPS16 code. */
+ addr = PROC_LOW_ADDR (proc_desc);
+ mips16 = pc_is_mips16 (addr);
+
+ /* Scan through this function's instructions preceding the
+ current PC, and look for those that save registers. */
+ while (addr < frame_pc_unwind (next_frame))
+ {
+ if (mips16)
+ {
+ mips16_decode_reg_save (mips16_fetch_instruction (addr),
+ &gen_save_found);
+ addr += MIPS16_INSTLEN;
+ }
+ else
+ {
+ mips32_decode_reg_save (mips32_fetch_instruction (addr),
+ &gen_save_found, &float_save_found);
+ addr += MIPS_INSTLEN;
+ }
+ }
+ gen_mask = gen_save_found;
+ float_mask = float_save_found;
+ }
+
+ /* Fill in the offsets for the registers which gen_mask says were
+ saved. */
+ {
+ CORE_ADDR reg_position = (cache->base
+ + PROC_REG_OFFSET (proc_desc));
+ int ireg;
+ for (ireg = MIPS_NUMREGS - 1; gen_mask; --ireg, gen_mask <<= 1)
+ if (gen_mask & 0x80000000)
+ {
+ cache->saved_regs[NUM_REGS + ireg].addr = reg_position;
+ reg_position -= mips_saved_regsize (tdep);
+ }
+ }
+
+ /* The MIPS16 entry instruction saves $s0 and $s1 in the reverse
+ order of that normally used by gcc. Therefore, we have to fetch
+ the first instruction of the function, and if it's an entry
+ instruction that saves $s0 or $s1, correct their saved addresses. */
+ if (pc_is_mips16 (PROC_LOW_ADDR (proc_desc)))
+ {
+ ULONGEST inst = mips16_fetch_instruction (PROC_LOW_ADDR (proc_desc));
+ if ((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700)
+ /* entry */
+ {
+ int reg;
+ int sreg_count = (inst >> 6) & 3;
+
+ /* Check if the ra register was pushed on the stack. */
+ CORE_ADDR reg_position = (cache->base
+ + PROC_REG_OFFSET (proc_desc));
+ if (inst & 0x20)
+ reg_position -= mips_saved_regsize (tdep);
+
+ /* Check if the s0 and s1 registers were pushed on the
+ stack. */
+ /* NOTE: cagney/2004-02-08: Huh? This is doing no such
+ check. */
+ for (reg = 16; reg < sreg_count + 16; reg++)
+ {
+ cache->saved_regs[NUM_REGS + reg].addr = reg_position;
+ reg_position -= mips_saved_regsize (tdep);
+ }
+ }
+ }
+
+ /* Fill in the offsets for the registers which float_mask says were
+ saved. */
+ {
+ CORE_ADDR reg_position = (cache->base
+ + PROC_FREG_OFFSET (proc_desc));
+ int ireg;
+ /* Fill in the offsets for the float registers which float_mask
+ says were saved. */
+ for (ireg = MIPS_NUMREGS - 1; float_mask; --ireg, float_mask <<= 1)
+ if (float_mask & 0x80000000)
+ {
+ if (mips_saved_regsize (tdep) == 4
+ && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ /* On a big endian 32 bit ABI, floating point registers
+ are paired to form doubles such that the most
+ significant part is in $f[N+1] and the least
+ significant in $f[N] vis: $f[N+1] ||| $f[N]. The
+ registers are also spilled as a pair and stored as a
+ double.
+
+ When little-endian the least significant part is
+ stored first leading to the memory order $f[N] and
+ then $f[N+1].
+
+ Unfortunately, when big-endian the most significant
+ part of the double is stored first, and the least
+ significant is stored second. This leads to the
+ registers being ordered in memory as firt $f[N+1] and
+ then $f[N].
+
+ For the big-endian case make certain that the
+ addresses point at the correct (swapped) locations
+ $f[N] and $f[N+1] pair (keep in mind that
+ reg_position is decremented each time through the
+ loop). */
+ if ((ireg & 1))
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->fp0 + ireg]
+ .addr = reg_position - mips_saved_regsize (tdep);
+ else
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->fp0 + ireg]
+ .addr = reg_position + mips_saved_regsize (tdep);
+ }
+ else
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->fp0 + ireg]
+ .addr = reg_position;
+ reg_position -= mips_saved_regsize (tdep);
+ }
+
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
+ = cache->saved_regs[NUM_REGS + RA_REGNUM];
+ }
+
+ /* SP_REGNUM, contains the value and not the address. */
+ trad_frame_set_value (cache->saved_regs, NUM_REGS + SP_REGNUM, cache->base);
+
+ return (*this_cache);
+}
+
+static void
+mips_mdebug_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct mips_frame_cache *info = mips_mdebug_frame_cache (next_frame,
+ this_cache);
+ (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+}
+
+static void
+mips_mdebug_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct mips_frame_cache *info = mips_mdebug_frame_cache (next_frame,
+ this_cache);
+ trad_frame_prev_register (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind mips_mdebug_frame_unwind =
+{
+ NORMAL_FRAME,
+ mips_mdebug_frame_this_id,
+ mips_mdebug_frame_prev_register
+};
+
+static const struct frame_unwind *
+mips_mdebug_frame_sniffer (struct frame_info *next_frame)
+{
+ return &mips_mdebug_frame_unwind;
+}
+
+static CORE_ADDR
+mips_mdebug_frame_base_address (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct mips_frame_cache *info = mips_mdebug_frame_cache (next_frame,
+ this_cache);
+ return info->base;
+}
+
+static const struct frame_base mips_mdebug_frame_base = {
+ &mips_mdebug_frame_unwind,
+ mips_mdebug_frame_base_address,
+ mips_mdebug_frame_base_address,
+ mips_mdebug_frame_base_address
+};
+
+static const struct frame_base *
+mips_mdebug_frame_base_sniffer (struct frame_info *next_frame)
+{
+ return &mips_mdebug_frame_base;
+}
+
+static CORE_ADDR
+read_next_frame_reg (struct frame_info *fi, int regno)
+{
+ /* Always a pseudo. */
+ gdb_assert (regno >= NUM_REGS);
+ if (fi == NULL)
+ {
+ LONGEST val;
+ regcache_cooked_read_signed (current_regcache, regno, &val);
+ return val;
+ }
+ else if ((regno % NUM_REGS) == SP_REGNUM)
+ /* The SP_REGNUM is special, its value is stored in saved_regs.
+ In fact, it is so special that it can even only be fetched
+ using a raw register number! Once this code as been converted
+ to frame-unwind the problem goes away. */
+ return frame_unwind_register_signed (fi, regno % NUM_REGS);
+ else
+ return frame_unwind_register_signed (fi, regno);
+
+}
+
+/* mips_addr_bits_remove - remove useless address bits */
+
+static CORE_ADDR
+mips_addr_bits_remove (CORE_ADDR addr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
+ /* This hack is a work-around for existing boards using PMON, the
+ simulator, and any other 64-bit targets that doesn't have true
+ 64-bit addressing. On these targets, the upper 32 bits of
+ addresses are ignored by the hardware. Thus, the PC or SP are
+ likely to have been sign extended to all 1s by instruction
+ sequences that load 32-bit addresses. For example, a typical
+ piece of code that loads an address is this:
+
+ lui $r2, <upper 16 bits>
+ ori $r2, <lower 16 bits>
+
+ But the lui sign-extends the value such that the upper 32 bits
+ may be all 1s. The workaround is simply to mask off these
+ bits. In the future, gcc may be changed to support true 64-bit
+ addressing, and this masking will have to be disabled. */
+ return addr &= 0xffffffffUL;
+ else
+ return addr;
+}
+
+/* mips_software_single_step() is called just before we want to resume
+ the inferior, if we want to single-step it but there is no hardware
+ or kernel single-step support (MIPS on GNU/Linux for example). We find
+ the target of the coming instruction and breakpoint it.
+
+ single_step is also called just after the inferior stops. If we had
+ set up a simulated single-step, we undo our damage. */
+
+void
+mips_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+{
+ static CORE_ADDR next_pc;
+ typedef char binsn_quantum[BREAKPOINT_MAX];
+ static binsn_quantum break_mem;
+ CORE_ADDR pc;
+
+ if (insert_breakpoints_p)
+ {
+ pc = read_register (mips_regnum (current_gdbarch)->pc);
+ next_pc = mips_next_pc (pc);
+
+ target_insert_breakpoint (next_pc, break_mem);
+ }
+ else
+ target_remove_breakpoint (next_pc, break_mem);
+}
+
+static struct mips_extra_func_info temp_proc_desc;
+
+/* This hack will go away once the get_prev_frame() code has been
+ modified to set the frame's type first. That is BEFORE init extra
+ frame info et.al. is called. This is because it will become
+ possible to skip the init extra info call for sigtramp and dummy
+ frames. */
+static CORE_ADDR *temp_saved_regs;
+
+/* Set a register's saved stack address in temp_saved_regs. If an
+ address has already been set for this register, do nothing; this
+ way we will only recognize the first save of a given register in a
+ function prologue.
+
+ For simplicity, save the address in both [0 .. NUM_REGS) and
+ [NUM_REGS .. 2*NUM_REGS). Strictly speaking, only the second range
+ is used as it is only second range (the ABI instead of ISA
+ registers) that comes into play when finding saved registers in a
+ frame. */
+
+static void
+set_reg_offset (CORE_ADDR *saved_regs, int regno, CORE_ADDR offset)
+{
+ if (saved_regs[regno] == 0)
+ {
+ saved_regs[regno + 0 * NUM_REGS] = offset;
+ saved_regs[regno + 1 * NUM_REGS] = offset;
+ }
+}
+
+
+/* Test whether the PC points to the return instruction at the
+ end of a function. */
+
+static int
+mips_about_to_return (CORE_ADDR pc)
+{
+ if (pc_is_mips16 (pc))
+ /* This mips16 case isn't necessarily reliable. Sometimes the compiler
+ generates a "jr $ra"; other times it generates code to load
+ the return address from the stack to an accessible register (such
+ as $a3), then a "jr" using that register. This second case
+ is almost impossible to distinguish from an indirect jump
+ used for switch statements, so we don't even try. */
+ return mips_fetch_instruction (pc) == 0xe820; /* jr $ra */
+ else
+ return mips_fetch_instruction (pc) == 0x3e00008; /* jr $ra */
+}
+
+
+/* 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 (CORE_ADDR pc)
+{
+ CORE_ADDR start_pc;
+ CORE_ADDR fence;
+ int instlen;
+ int seen_adjsp = 0;
+
+ pc = ADDR_BITS_REMOVE (pc);
+ start_pc = pc;
+ 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;
+
+ instlen = pc_is_mips16 (pc) ? MIPS16_INSTLEN : MIPS_INSTLEN;
+
+ /* search back for previous return */
+ for (start_pc -= instlen;; start_pc -= instlen)
+ if (start_pc < fence)
+ {
+ /* It's not clear to me why we reach this point when
+ stop_soon, 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 == NO_STOP_QUIETLY)
+ {
+ static int blurb_printed = 0;
+
+ warning
+ ("Warning: GDB can't find the start of the function at 0x%s.",
+ paddr_nz (pc));
+
+ if (!blurb_printed)
+ {
+ /* This actually happens frequently in embedded
+ development, when you first connect to a board
+ and your stack pointer and pc are nowhere in
+ particular. This message needs to give people
+ in that situation enough information to
+ determine that it's no big deal. */
+ printf_filtered ("\n\
+ GDB is unable to find the start of the function at 0x%s\n\
+and thus can't determine the size of that function's stack frame.\n\
+This means that GDB may be unable to access that stack frame, or\n\
+the frames below it.\n\
+ This problem is most likely caused by an invalid program counter or\n\
+stack pointer.\n\
+ However, if you think GDB should simply search farther back\n\
+from 0x%s for code which looks like the beginning of a\n\
+function, you can increase the range of the search using the `set\n\
+heuristic-fence-post' command.\n", paddr_nz (pc), paddr_nz (pc));
+ blurb_printed = 1;
+ }
+ }
+
+ return 0;
+ }
+ else if (pc_is_mips16 (start_pc))
+ {
+ unsigned short inst;
+
+ /* On MIPS16, any one of the following is likely to be the
+ start of a function:
+ entry
+ addiu sp,-n
+ daddiu sp,-n
+ extend -n followed by 'addiu sp,+n' or 'daddiu sp,+n' */
+ inst = mips_fetch_instruction (start_pc);
+ if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700) /* entry */
+ || (inst & 0xff80) == 0x6380 /* addiu sp,-n */
+ || (inst & 0xff80) == 0xfb80 /* daddiu sp,-n */
+ || ((inst & 0xf810) == 0xf010 && seen_adjsp)) /* extend -n */
+ break;
+ else if ((inst & 0xff00) == 0x6300 /* addiu sp */
+ || (inst & 0xff00) == 0xfb00) /* daddiu sp */
+ seen_adjsp = 1;
+ else
+ seen_adjsp = 0;
+ }
+ else if (mips_about_to_return (start_pc))
+ {
+ start_pc += 2 * MIPS_INSTLEN; /* skip return, and its delay slot */
+ break;
+ }
+
+ return start_pc;
+}
+
+/* Fetch the immediate value from a MIPS16 instruction.
+ If the previous instruction was an EXTEND, use it to extend
+ the upper bits of the immediate value. This is a helper function
+ for mips16_heuristic_proc_desc. */
+
+static int
+mips16_get_imm (unsigned short prev_inst, /* previous instruction */
+ unsigned short inst, /* current instruction */
+ int nbits, /* number of bits in imm field */
+ int scale, /* scale factor to be applied to imm */
+ int is_signed) /* is the imm field signed? */
+{
+ int offset;
+
+ if ((prev_inst & 0xf800) == 0xf000) /* prev instruction was EXTEND? */
+ {
+ offset = ((prev_inst & 0x1f) << 11) | (prev_inst & 0x7e0);
+ if (offset & 0x8000) /* check for negative extend */
+ offset = 0 - (0x10000 - (offset & 0xffff));
+ return offset | (inst & 0x1f);
+ }
+ else
+ {
+ int max_imm = 1 << nbits;
+ int mask = max_imm - 1;
+ int sign_bit = max_imm >> 1;
+
+ offset = inst & mask;
+ if (is_signed && (offset & sign_bit))
+ offset = 0 - (max_imm - offset);
+ return offset * scale;
+ }
+}
+
+
+/* Fill in values in temp_proc_desc based on the MIPS16 instruction
+ stream from start_pc to limit_pc. */
+
+static void
+mips16_heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+ struct frame_info *next_frame, CORE_ADDR sp)
+{
+ CORE_ADDR cur_pc;
+ CORE_ADDR frame_addr = 0; /* Value of $r17, used as frame pointer */
+ unsigned short prev_inst = 0; /* saved copy of previous instruction */
+ unsigned inst = 0; /* current instruction */
+ unsigned entry_inst = 0; /* the entry instruction */
+ int reg, offset;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ PROC_FRAME_OFFSET (&temp_proc_desc) = 0; /* size of stack frame */
+ PROC_FRAME_ADJUST (&temp_proc_desc) = 0; /* offset of FP from SP */
+
+ for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS16_INSTLEN)
+ {
+ /* Save the previous instruction. If it's an EXTEND, we'll extract
+ the immediate offset extension from it in mips16_get_imm. */
+ prev_inst = inst;
+
+ /* Fetch and decode the instruction. */
+ inst = (unsigned short) mips_fetch_instruction (cur_pc);
+ if ((inst & 0xff00) == 0x6300 /* addiu sp */
+ || (inst & 0xff00) == 0xfb00) /* daddiu sp */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 8, 8, 1);
+ if (offset < 0) /* negative stack adjustment? */
+ PROC_FRAME_OFFSET (&temp_proc_desc) -= offset;
+ else
+ /* Exit loop if a positive stack adjustment is found, which
+ usually means that the stack cleanup code in the function
+ epilogue is reached. */
+ break;
+ }
+ else if ((inst & 0xf800) == 0xd000) /* sw reg,n($sp) */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
+ reg = mips16_to_32_reg[(inst & 0x700) >> 8];
+ PROC_REG_MASK (&temp_proc_desc) |= (1 << reg);
+ set_reg_offset (temp_saved_regs, reg, sp + offset);
+ }
+ else if ((inst & 0xff00) == 0xf900) /* sd reg,n($sp) */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
+ reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
+ PROC_REG_MASK (&temp_proc_desc) |= (1 << reg);
+ set_reg_offset (temp_saved_regs, reg, sp + offset);
+ }
+ else if ((inst & 0xff00) == 0x6200) /* sw $ra,n($sp) */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
+ PROC_REG_MASK (&temp_proc_desc) |= (1 << RA_REGNUM);
+ set_reg_offset (temp_saved_regs, RA_REGNUM, sp + offset);
+ }
+ else if ((inst & 0xff00) == 0xfa00) /* sd $ra,n($sp) */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 8, 8, 0);
+ PROC_REG_MASK (&temp_proc_desc) |= (1 << RA_REGNUM);
+ set_reg_offset (temp_saved_regs, RA_REGNUM, sp + offset);
+ }
+ else if (inst == 0x673d) /* move $s1, $sp */
+ {
+ frame_addr = sp;
+ PROC_FRAME_REG (&temp_proc_desc) = 17;
+ }
+ else if ((inst & 0xff00) == 0x0100) /* addiu $s1,sp,n */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
+ frame_addr = sp + offset;
+ PROC_FRAME_REG (&temp_proc_desc) = 17;
+ PROC_FRAME_ADJUST (&temp_proc_desc) = offset;
+ }
+ else if ((inst & 0xFF00) == 0xd900) /* sw reg,offset($s1) */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 5, 4, 0);
+ reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
+ set_reg_offset (temp_saved_regs, reg, frame_addr + offset);
+ }
+ else if ((inst & 0xFF00) == 0x7900) /* sd reg,offset($s1) */
+ {
+ offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
+ reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
+ set_reg_offset (temp_saved_regs, reg, frame_addr + offset);
+ }
+ else if ((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700) /* entry */
+ entry_inst = inst; /* save for later processing */
+ else if ((inst & 0xf800) == 0x1800) /* jal(x) */
+ cur_pc += MIPS16_INSTLEN; /* 32-bit instruction */
+ }
+
+ /* The entry instruction is typically the first instruction in a function,
+ and it stores registers at offsets relative to the value of the old SP
+ (before the prologue). But the value of the sp parameter to this
+ function is the new SP (after the prologue has been executed). So we
+ can't calculate those offsets until we've seen the entire prologue,
+ and can calculate what the old SP must have been. */
+ if (entry_inst != 0)
+ {
+ int areg_count = (entry_inst >> 8) & 7;
+ int sreg_count = (entry_inst >> 6) & 3;
+
+ /* The entry instruction always subtracts 32 from the SP. */
+ PROC_FRAME_OFFSET (&temp_proc_desc) += 32;
+
+ /* Now we can calculate what the SP must have been at the
+ start of the function prologue. */
+ sp += PROC_FRAME_OFFSET (&temp_proc_desc);
+
+ /* Check if a0-a3 were saved in the caller's argument save area. */
+ for (reg = 4, offset = 0; reg < areg_count + 4; reg++)
+ {
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
+ set_reg_offset (temp_saved_regs, reg, sp + offset);
+ offset += mips_saved_regsize (tdep);
+ }
+
+ /* Check if the ra register was pushed on the stack. */
+ offset = -4;
+ if (entry_inst & 0x20)
+ {
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << RA_REGNUM;
+ set_reg_offset (temp_saved_regs, RA_REGNUM, sp + offset);
+ offset -= mips_saved_regsize (tdep);
+ }
+
+ /* Check if the s0 and s1 registers were pushed on the stack. */
+ for (reg = 16; reg < sreg_count + 16; reg++)
+ {
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
+ set_reg_offset (temp_saved_regs, reg, sp + offset);
+ offset -= mips_saved_regsize (tdep);
+ }
+ }
+}
+
+static void
+mips32_heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+ struct frame_info *next_frame, CORE_ADDR sp)
+{
+ CORE_ADDR cur_pc;
+ CORE_ADDR frame_addr = 0; /* Value of $r30. Used by gcc for frame-pointer */
+restart:
+ temp_saved_regs = xrealloc (temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
+ memset (temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
+ PROC_FRAME_OFFSET (&temp_proc_desc) = 0;
+ PROC_FRAME_ADJUST (&temp_proc_desc) = 0; /* offset of FP from SP */
+ for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSTLEN)
+ {
+ unsigned long inst, high_word, low_word;
+ int reg;
+
+ /* Fetch the instruction. */
+ inst = (unsigned long) mips_fetch_instruction (cur_pc);
+
+ /* Save some code by pre-extracting some useful fields. */
+ high_word = (inst >> 16) & 0xffff;
+ low_word = inst & 0xffff;
+ reg = high_word & 0x1f;
+
+ if (high_word == 0x27bd /* addiu $sp,$sp,-i */
+ || high_word == 0x23bd /* addi $sp,$sp,-i */
+ || high_word == 0x67bd) /* daddiu $sp,$sp,-i */
+ {
+ if (low_word & 0x8000) /* negative stack adjustment? */
+ PROC_FRAME_OFFSET (&temp_proc_desc) += 0x10000 - low_word;
+ else
+ /* Exit loop if a positive stack adjustment is found, which
+ usually means that the stack cleanup code in the function
+ epilogue is reached. */
+ break;
+ }
+ else if ((high_word & 0xFFE0) == 0xafa0) /* sw reg,offset($sp) */
+ {
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
+ set_reg_offset (temp_saved_regs, reg, sp + low_word);
+ }
+ else if ((high_word & 0xFFE0) == 0xffa0) /* sd reg,offset($sp) */
+ {
+ /* Irix 6.2 N32 ABI uses sd instructions for saving $gp and $ra,
+ but the register size used is only 32 bits. Make the address
+ for the saved register point to the lower 32 bits. */
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
+ set_reg_offset (temp_saved_regs, reg,
+ sp + low_word + 8 - mips_regsize (current_gdbarch));
+ }
+ else if (high_word == 0x27be) /* addiu $30,$sp,size */
+ {
+ /* Old gcc frame, r30 is virtual frame pointer. */
+ if ((long) low_word != PROC_FRAME_OFFSET (&temp_proc_desc))
+ frame_addr = sp + low_word;
+ else if (PROC_FRAME_REG (&temp_proc_desc) == SP_REGNUM)
+ {
+ unsigned alloca_adjust;
+ PROC_FRAME_REG (&temp_proc_desc) = 30;
+ frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
+ alloca_adjust = (unsigned) (frame_addr - (sp + low_word));
+ if (alloca_adjust > 0)
+ {
+ /* FP > SP + frame_size. This may be because
+ * of an alloca or somethings similar.
+ * Fix sp to "pre-alloca" value, and try again.
+ */
+ sp += alloca_adjust;
+ goto restart;
+ }
+ }
+ }
+ /* move $30,$sp. With different versions of gas this will be either
+ `addu $30,$sp,$zero' or `or $30,$sp,$zero' or `daddu 30,sp,$0'.
+ Accept any one of these. */
+ else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
+ {
+ /* New gcc frame, virtual frame pointer is at r30 + frame_size. */
+ if (PROC_FRAME_REG (&temp_proc_desc) == SP_REGNUM)
+ {
+ unsigned alloca_adjust;
+ PROC_FRAME_REG (&temp_proc_desc) = 30;
+ frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
+ alloca_adjust = (unsigned) (frame_addr - sp);
+ if (alloca_adjust > 0)
+ {
+ /* FP > SP + frame_size. This may be because
+ * of an alloca or somethings similar.
+ * Fix sp to "pre-alloca" value, and try again.
+ */
+ sp += alloca_adjust;
+ goto restart;
+ }
+ }
+ }
+ else if ((high_word & 0xFFE0) == 0xafc0) /* sw reg,offset($30) */
+ {
+ PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
+ set_reg_offset (temp_saved_regs, reg, frame_addr + low_word);
+ }
+ }
+}
+
+static mips_extra_func_info_t
+heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+ struct frame_info *next_frame, int cur_frame)
+{
+ CORE_ADDR sp;
+
+ if (cur_frame)
+ sp = read_next_frame_reg (next_frame, NUM_REGS + SP_REGNUM);
+ else
+ sp = 0;
+
+ if (start_pc == 0)
+ return NULL;
+ memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc));
+ temp_saved_regs = xrealloc (temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
+ memset (temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
+ PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
+ PROC_FRAME_REG (&temp_proc_desc) = SP_REGNUM;
+ PROC_PC_REG (&temp_proc_desc) = RA_REGNUM;
+
+ if (start_pc + 200 < limit_pc)
+ limit_pc = start_pc + 200;
+ if (pc_is_mips16 (start_pc))
+ mips16_heuristic_proc_desc (start_pc, limit_pc, next_frame, sp);
+ else
+ mips32_heuristic_proc_desc (start_pc, limit_pc, next_frame, sp);
+ return &temp_proc_desc;
+}
+
+struct mips_objfile_private
+{
+ bfd_size_type size;
+ char *contents;
+};
+
+/* Global used to communicate between non_heuristic_proc_desc and
+ compare_pdr_entries within qsort (). */
+static bfd *the_bfd;
+
+static int
+compare_pdr_entries (const void *a, const void *b)
+{
+ CORE_ADDR lhs = bfd_get_32 (the_bfd, (bfd_byte *) a);
+ CORE_ADDR rhs = bfd_get_32 (the_bfd, (bfd_byte *) b);
+
+ if (lhs < rhs)
+ return -1;
+ else if (lhs == rhs)
+ return 0;
+ else
+ return 1;
+}
+
+static mips_extra_func_info_t
+non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
+{
+ CORE_ADDR startaddr;
+ mips_extra_func_info_t proc_desc;
+ struct block *b = block_for_pc (pc);
+ struct symbol *sym;
+ struct obj_section *sec;
+ struct mips_objfile_private *priv;
+
+ if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+ return NULL;
+
+ find_pc_partial_function (pc, NULL, &startaddr, NULL);
+ if (addrptr)
+ *addrptr = startaddr;
+
+ priv = NULL;
+
+ sec = find_pc_section (pc);
+ if (sec != NULL)
+ {
+ priv = (struct mips_objfile_private *) objfile_data (sec->objfile, mips_pdr_data);
+
+ /* Search the ".pdr" section generated by GAS. This includes most of
+ the information normally found in ECOFF PDRs. */
+
+ the_bfd = sec->objfile->obfd;
+ if (priv == NULL
+ && (the_bfd->format == bfd_object
+ && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour
+ && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64))
+ {
+ /* Right now GAS only outputs the address as a four-byte sequence.
+ This means that we should not bother with this method on 64-bit
+ targets (until that is fixed). */
+
+ priv = obstack_alloc (&sec->objfile->objfile_obstack,
+ sizeof (struct mips_objfile_private));
+ priv->size = 0;
+ set_objfile_data (sec->objfile, mips_pdr_data, priv);
+ }
+ else if (priv == NULL)
+ {
+ asection *bfdsec;
+
+ priv = obstack_alloc (&sec->objfile->objfile_obstack,
+ sizeof (struct mips_objfile_private));
+
+ bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr");
+ if (bfdsec != NULL)
+ {
+ priv->size = bfd_section_size (sec->objfile->obfd, bfdsec);
+ priv->contents = obstack_alloc (&sec->objfile->objfile_obstack,
+ priv->size);
+ bfd_get_section_contents (sec->objfile->obfd, bfdsec,
+ priv->contents, 0, priv->size);
+
+ /* In general, the .pdr section is sorted. However, in the
+ presence of multiple code sections (and other corner cases)
+ it can become unsorted. Sort it so that we can use a faster
+ binary search. */
+ qsort (priv->contents, priv->size / 32, 32,
+ compare_pdr_entries);
+ }
+ else
+ priv->size = 0;
+
+ set_objfile_data (sec->objfile, mips_pdr_data, priv);
+ }
+ the_bfd = NULL;
+
+ if (priv->size != 0)
+ {
+ int low, mid, high;
+ char *ptr;
+
+ low = 0;
+ high = priv->size / 32;
+
+ do
+ {
+ CORE_ADDR pdr_pc;
+
+ mid = (low + high) / 2;
+
+ ptr = priv->contents + mid * 32;
+ pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
+ pdr_pc += ANOFFSET (sec->objfile->section_offsets,
+ SECT_OFF_TEXT (sec->objfile));
+ if (pdr_pc == startaddr)
+ break;
+ if (pdr_pc > startaddr)
+ high = mid;
+ else
+ low = mid + 1;
+ }
+ while (low != high);
+
+ if (low != high)
+ {
+ struct symbol *sym = find_pc_function (pc);
+
+ /* Fill in what we need of the proc_desc. */
+ proc_desc = (mips_extra_func_info_t)
+ obstack_alloc (&sec->objfile->objfile_obstack,
+ sizeof (struct mips_extra_func_info));
+ PROC_LOW_ADDR (proc_desc) = startaddr;
+
+ /* Only used for dummy frames. */
+ PROC_HIGH_ADDR (proc_desc) = 0;
+
+ PROC_FRAME_OFFSET (proc_desc)
+ = bfd_get_32 (sec->objfile->obfd, ptr + 20);
+ PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 24);
+ PROC_FRAME_ADJUST (proc_desc) = 0;
+ PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 4);
+ PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 12);
+ PROC_REG_OFFSET (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 8);
+ PROC_FREG_OFFSET (proc_desc)
+ = bfd_get_32 (sec->objfile->obfd, ptr + 16);
+ PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 28);
+ proc_desc->pdr.isym = (long) sym;
+
+ return proc_desc;
+ }
+ }
+ }
+
+ if (b == NULL)
+ return NULL;
+
+ 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. */
+ return NULL;
+ }
+
+ sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0, NULL);
+
+ /* If we never found a PDR for this function in symbol reading, then
+ examine prologues to find the information. */
+ if (sym)
+ {
+ proc_desc = (mips_extra_func_info_t) SYMBOL_VALUE (sym);
+ if (PROC_FRAME_REG (proc_desc) == -1)
+ return NULL;
+ else
+ return proc_desc;
+ }
+ else
+ return NULL;
+}
+
+
+static mips_extra_func_info_t
+find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
+{
+ mips_extra_func_info_t proc_desc;
+ CORE_ADDR startaddr = 0;
+
+ proc_desc = non_heuristic_proc_desc (pc, &startaddr);
+
+ if (proc_desc)
+ {
+ /* 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.
+ */
+ if (next_frame == NULL)
+ {
+ struct symtab_and_line val;
+ struct symbol *proc_symbol =
+ PROC_DESC_IS_DUMMY (proc_desc) ? 0 : PROC_SYMBOL (proc_desc);
+
+ if (proc_symbol)
+ {
+ val = find_pc_line (BLOCK_START
+ (SYMBOL_BLOCK_VALUE (proc_symbol)), 0);
+ val.pc = val.end ? val.end : pc;
+ }
+ if (!proc_symbol || pc < val.pc)
+ {
+ mips_extra_func_info_t found_heuristic =
+ heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
+ pc, next_frame, cur_frame);
+ if (found_heuristic)
+ 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! */
+
+ 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, cur_frame);
+ }
+ return proc_desc;
+}
+
+/* MIPS 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 (int argc, CORE_ADDR *argv)
+{
+ if (argc != 2)
+ error ("MIPS frame specifications require two arguments: sp and pc");
+
+ return create_new_frame (argv[0], argv[1]);
+}
+
+/* According to the current ABI, should the type be passed in a
+ floating-point register (assuming that there is space)? When there
+ is no FPU, FP are not even considered as possibile candidates for
+ FP registers and, consequently this returns false - forces FP
+ arguments into integer registers. */
+
+static int
+fp_register_arg_p (enum type_code typecode, struct type *arg_type)
+{
+ return ((typecode == TYPE_CODE_FLT
+ || (MIPS_EABI
+ && (typecode == TYPE_CODE_STRUCT
+ || typecode == TYPE_CODE_UNION)
+ && TYPE_NFIELDS (arg_type) == 1
+ && TYPE_CODE (TYPE_FIELD_TYPE (arg_type, 0)) == TYPE_CODE_FLT))
+ && MIPS_FPU_TYPE != MIPS_FPU_NONE);
+}
+
+/* On o32, argument passing in GPRs depends on the alignment of the type being
+ passed. Return 1 if this type must be aligned to a doubleword boundary. */
+
+static int
+mips_type_needs_double_align (struct type *type)
+{
+ enum type_code typecode = TYPE_CODE (type);
+
+ if (typecode == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8)
+ return 1;
+ else if (typecode == TYPE_CODE_STRUCT)
+ {
+ if (TYPE_NFIELDS (type) < 1)
+ return 0;
+ return mips_type_needs_double_align (TYPE_FIELD_TYPE (type, 0));
+ }
+ else if (typecode == TYPE_CODE_UNION)
+ {
+ int i, n;
+
+ n = TYPE_NFIELDS (type);
+ for (i = 0; i < n; i++)
+ if (mips_type_needs_double_align (TYPE_FIELD_TYPE (type, i)))
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/* Adjust the address downward (direction of stack growth) so that it
+ is correctly aligned for a new stack frame. */
+static CORE_ADDR
+mips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return align_down (addr, 16);
+}
+
+/* Determine how a return value is stored within the MIPS register
+ file, given the return type `valtype'. */
+
+struct return_value_word
+{
+ int len;
+ int reg;
+ int reg_offset;
+ int buf_offset;
+};
+
+static void
+return_value_location (struct type *valtype,
+ struct return_value_word *hi,
+ struct return_value_word *lo)
+{
+ int len = TYPE_LENGTH (valtype);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (TYPE_CODE (valtype) == TYPE_CODE_FLT
+ && ((MIPS_FPU_TYPE == MIPS_FPU_DOUBLE && (len == 4 || len == 8))
+ || (MIPS_FPU_TYPE == MIPS_FPU_SINGLE && len == 4)))
+ {
+ if (!FP_REGISTER_DOUBLE && len == 8)
+ {
+ /* We need to break a 64bit float in two 32 bit halves and
+ spread them across a floating-point register pair. */
+ lo->buf_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+ hi->buf_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 0 : 4;
+ lo->reg_offset = ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && register_size (current_gdbarch,
+ mips_regnum (current_gdbarch)->
+ fp0) == 8) ? 4 : 0);
+ hi->reg_offset = lo->reg_offset;
+ lo->reg = mips_regnum (current_gdbarch)->fp0 + 0;
+ hi->reg = mips_regnum (current_gdbarch)->fp0 + 1;
+ lo->len = 4;
+ hi->len = 4;
+ }
+ else
+ {
+ /* The floating point value fits in a single floating-point
+ register. */
+ lo->reg_offset = ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && register_size (current_gdbarch,
+ mips_regnum (current_gdbarch)->
+ fp0) == 8
+ && len == 4) ? 4 : 0);
+ lo->reg = mips_regnum (current_gdbarch)->fp0;
+ lo->len = len;
+ lo->buf_offset = 0;
+ hi->len = 0;
+ hi->reg_offset = 0;
+ hi->buf_offset = 0;
+ hi->reg = 0;
+ }
+ }
+ else
+ {
+ /* Locate a result possibly spread across two registers. */
+ int regnum = 2;
+ lo->reg = regnum + 0;
+ hi->reg = regnum + 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && len < mips_saved_regsize (tdep))
+ {
+ /* "un-left-justify" the value in the low register */
+ lo->reg_offset = mips_saved_regsize (tdep) - len;
+ lo->len = len;
+ hi->reg_offset = 0;
+ hi->len = 0;
+ }
+ else if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG && len > mips_saved_regsize (tdep) /* odd-size structs */
+ && len < mips_saved_regsize (tdep) * 2
+ && (TYPE_CODE (valtype) == TYPE_CODE_STRUCT ||
+ TYPE_CODE (valtype) == TYPE_CODE_UNION))
+ {
+ /* "un-left-justify" the value spread across two registers. */
+ lo->reg_offset = 2 * mips_saved_regsize (tdep) - len;
+ lo->len = mips_saved_regsize (tdep) - lo->reg_offset;
+ hi->reg_offset = 0;
+ hi->len = len - lo->len;
+ }
+ else
+ {
+ /* Only perform a partial copy of the second register. */
+ lo->reg_offset = 0;
+ hi->reg_offset = 0;
+ if (len > mips_saved_regsize (tdep))
+ {
+ lo->len = mips_saved_regsize (tdep);
+ hi->len = len - mips_saved_regsize (tdep);
+ }
+ else
+ {
+ lo->len = len;
+ hi->len = 0;
+ }
+ }
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && register_size (current_gdbarch, regnum) == 8
+ && mips_saved_regsize (tdep) == 4)
+ {
+ /* Account for the fact that only the least-signficant part
+ of the register is being used */
+ lo->reg_offset += 4;
+ hi->reg_offset += 4;
+ }
+ lo->buf_offset = 0;
+ hi->buf_offset = lo->len;
+ }
+}
+
+/* Should call_function allocate stack space for a struct return? */
+
+static int
+mips_eabi_use_struct_convention (int gcc_p, struct type *type)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ return (TYPE_LENGTH (type) > 2 * mips_saved_regsize (tdep));
+}
+
+/* Should call_function pass struct by reference?
+ For each architecture, structs are passed either by
+ value or by reference, depending on their size. */
+
+static int
+mips_eabi_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ enum type_code typecode = TYPE_CODE (check_typedef (type));
+ int len = TYPE_LENGTH (check_typedef (type));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)
+ return (len > mips_saved_regsize (tdep));
+
+ return 0;
+}
+
+static CORE_ADDR
+mips_eabi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* For shared libraries, "t9" needs to point at the function
+ address. */
+ regcache_cooked_write_signed (regcache, T9_REGNUM, func_addr);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_signed (regcache, RA_REGNUM, bp_addr);
+
+ /* First ensure that the stack and structure return address (if any)
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
+ sp = align_down (sp, 16);
+ struct_addr = align_down (struct_addr, 16);
+
+ /* Now make space on the stack for the args. We allocate more
+ than necessary for EABI, because the first few arguments are
+ passed in registers, but that's OK. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ len += align_up (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ mips_stack_argsize (tdep));
+ sp -= align_up (len, 16);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_eabi_push_dummy_call: sp=0x%s allocated %ld\n",
+ paddr_nz (sp), (long) align_up (len, 16));
+
+ /* Initialize the integer and float register pointers. */
+ argreg = A0_REGNUM;
+ float_argreg = mips_fpa0_regnum (current_gdbarch);
+
+ /* The struct_return pointer occupies the first parameter-passing reg. */
+ if (struct_return)
+ {
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_eabi_push_dummy_call: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
+ write_register (argreg++, struct_addr);
+ }
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. Loop thru args
+ from first to last. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val;
+ char valbuf[MAX_REGISTER_SIZE];
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (arg_type);
+ enum type_code typecode = TYPE_CODE (arg_type);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_eabi_push_dummy_call: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
+
+ /* The EABI passes structures that do not fit in a register by
+ reference. */
+ if (len > mips_saved_regsize (tdep)
+ && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
+ {
+ store_unsigned_integer (valbuf, mips_saved_regsize (tdep),
+ VALUE_ADDRESS (arg));
+ typecode = TYPE_CODE_PTR;
+ len = mips_saved_regsize (tdep);
+ val = valbuf;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " push");
+ }
+ else
+ val = (char *) VALUE_CONTENTS (arg);
+
+ /* 32-bit ABIs always start floating point arguments in an
+ even-numbered floating point register. Round the FP register
+ up before the check to see if there are any FP registers
+ left. Non MIPS_EABI targets also pass the FP in the integer
+ registers so also round up normal registers. */
+ if (!FP_REGISTER_DOUBLE && fp_register_arg_p (typecode, arg_type))
+ {
+ if ((float_argreg & 1))
+ float_argreg++;
+ }
+
+ /* Floating point arguments passed in registers have to be
+ treated specially. On 32-bit architectures, doubles
+ are passed in register pairs; the even register gets
+ the low word, and the odd register gets the high word.
+ On non-EABI processors, the first two floating point arguments are
+ also copied to general registers, because MIPS16 functions
+ don't use float registers for arguments. This duplication of
+ arguments in general registers can't hurt non-MIPS16 functions
+ because those registers are normally skipped. */
+ /* MIPS_EABI squeezes a struct that contains a single floating
+ point value into an FP register instead of pushing it onto the
+ stack. */
+ if (fp_register_arg_p (typecode, arg_type)
+ && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ {
+ if (!FP_REGISTER_DOUBLE && len == 8)
+ {
+ int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+ unsigned long regval;
+
+ /* Write the low word of the double to the even register(s). */
+ regval = extract_unsigned_integer (val + low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+
+ /* Write the high word of the double to the odd register(s). */
+ regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+ }
+ else
+ {
+ /* This is a floating point value that fits entirely
+ in a single register. */
+ /* On 32 bit ABI's the float_argreg is further adjusted
+ above to ensure that it is even register aligned. */
+ LONGEST regval = extract_unsigned_integer (val, len);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, len));
+ write_register (float_argreg++, regval);
+ }
+ }
+ else
+ {
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ /* Note: structs whose size is not a multiple of
+ mips_regsize() are treated specially: Irix cc passes them
+ in registers where gcc sometimes puts them on the stack.
+ For maximum compatibility, we will put them in both
+ places. */
+ int odd_sized_struct = ((len > mips_saved_regsize (tdep))
+ && (len % mips_saved_regsize (tdep) != 0));
+
+ /* Note: Floating-point values that didn't fit into an FP
+ register are only written to memory. */
+ while (len > 0)
+ {
+ /* Remember if the argument was written to the stack. */
+ int stack_used_p = 0;
+ int partial_len = (len < mips_saved_regsize (tdep)
+ ? len : mips_saved_regsize (tdep));
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ partial_len);
+
+ /* Write this portion of the argument to the stack. */
+ if (argreg > MIPS_LAST_ARG_REGNUM
+ || odd_sized_struct
+ || fp_register_arg_p (typecode, arg_type))
+ {
+ /* Should shorter than int integer values be
+ promoted to int before being stored? */
+ int longword_offset = 0;
+ CORE_ADDR addr;
+ stack_used_p = 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (mips_stack_argsize (tdep) == 8
+ && (typecode == TYPE_CODE_INT
+ || typecode == TYPE_CODE_PTR
+ || typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = mips_stack_argsize (tdep) - len;
+ else if ((typecode == TYPE_CODE_STRUCT
+ || typecode == TYPE_CODE_UNION)
+ && (TYPE_LENGTH (arg_type)
+ < mips_stack_argsize (tdep)))
+ longword_offset = mips_stack_argsize (tdep) - len;
+ }
+
+ if (mips_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
+ }
+
+ addr = sp + stack_offset + longword_offset;
+
+ if (mips_debug)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
+ for (i = 0; i < partial_len; i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
+ }
+ }
+ write_memory (addr, val, partial_len);
+ }
+
+ /* Note!!! This is NOT an else clause. Odd sized
+ structs may go thru BOTH paths. Floating point
+ arguments will not. */
+ /* Write this portion of the argument to a general
+ purpose register. */
+ if (argreg <= MIPS_LAST_ARG_REGNUM
+ && !fp_register_arg_p (typecode, arg_type))
+ {
+ LONGEST regval =
+ extract_unsigned_integer (val, partial_len);
+
+ if (mips_debug)
+ fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ argreg,
+ phex (regval,
+ mips_saved_regsize (tdep)));
+ write_register (argreg, regval);
+ argreg++;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+
+ /* Compute the the offset into the stack at which we
+ will copy the next parameter.
+
+ In the new EABI (and the NABI32), the stack_offset
+ only needs to be adjusted when it has been used. */
+
+ if (stack_used_p)
+ stack_offset += align_up (partial_len,
+ mips_stack_argsize (tdep));
+ }
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+/* Given a return value in `regbuf' with a type `valtype', extract and
+ copy its value into `valbuf'. */
+
+static void
+mips_eabi_extract_return_value (struct type *valtype,
+ char regbuf[], char *valbuf)
+{
+ struct return_value_word lo;
+ struct return_value_word hi;
+ return_value_location (valtype, &hi, &lo);
+
+ memcpy (valbuf + lo.buf_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + lo.reg) +
+ lo.reg_offset, lo.len);
+
+ if (hi.len > 0)
+ memcpy (valbuf + hi.buf_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + hi.reg) +
+ hi.reg_offset, hi.len);
+}
+
+/* Given a return value in `valbuf' with a type `valtype', write it's
+ value into the appropriate register. */
+
+static void
+mips_eabi_store_return_value (struct type *valtype, char *valbuf)
+{
+ char raw_buffer[MAX_REGISTER_SIZE];
+ struct return_value_word lo;
+ struct return_value_word hi;
+ return_value_location (valtype, &hi, &lo);
+
+ memset (raw_buffer, 0, sizeof (raw_buffer));
+ memcpy (raw_buffer + lo.reg_offset, valbuf + lo.buf_offset, lo.len);
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (lo.reg),
+ raw_buffer, register_size (current_gdbarch,
+ lo.reg));
+
+ if (hi.len > 0)
+ {
+ memset (raw_buffer, 0, sizeof (raw_buffer));
+ memcpy (raw_buffer + hi.reg_offset, valbuf + hi.buf_offset, hi.len);
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (hi.reg),
+ raw_buffer,
+ register_size (current_gdbarch,
+ hi.reg));
+ }
+}
+
+/* N32/N64 ABI stuff. */
+
+static CORE_ADDR
+mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* For shared libraries, "t9" needs to point at the function
+ address. */
+ regcache_cooked_write_signed (regcache, T9_REGNUM, func_addr);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_signed (regcache, RA_REGNUM, bp_addr);
+
+ /* First ensure that the stack and structure return address (if any)
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
+ sp = align_down (sp, 16);
+ struct_addr = align_down (struct_addr, 16);
+
+ /* Now make space on the stack for the args. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ len += align_up (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ mips_stack_argsize (tdep));
+ sp -= align_up (len, 16);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_n32n64_push_dummy_call: sp=0x%s allocated %ld\n",
+ paddr_nz (sp), (long) align_up (len, 16));
+
+ /* Initialize the integer and float register pointers. */
+ argreg = A0_REGNUM;
+ float_argreg = mips_fpa0_regnum (current_gdbarch);
+
+ /* The struct_return pointer occupies the first parameter-passing reg. */
+ if (struct_return)
+ {
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_n32n64_push_dummy_call: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
+ write_register (argreg++, struct_addr);
+ }
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. Loop thru args
+ from first to last. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val;
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (arg_type);
+ enum type_code typecode = TYPE_CODE (arg_type);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_n32n64_push_dummy_call: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
+
+ val = (char *) VALUE_CONTENTS (arg);
+
+ if (fp_register_arg_p (typecode, arg_type)
+ && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ {
+ /* This is a floating point value that fits entirely
+ in a single register. */
+ /* On 32 bit ABI's the float_argreg is further adjusted
+ above to ensure that it is even register aligned. */
+ LONGEST regval = extract_unsigned_integer (val, len);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, len));
+ write_register (float_argreg++, regval);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, len));
+ write_register (argreg, regval);
+ argreg += 1;
+ }
+ else
+ {
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ /* Note: structs whose size is not a multiple of
+ mips_regsize() are treated specially: Irix cc passes them
+ in registers where gcc sometimes puts them on the stack.
+ For maximum compatibility, we will put them in both
+ places. */
+ int odd_sized_struct = ((len > mips_saved_regsize (tdep))
+ && (len % mips_saved_regsize (tdep) != 0));
+ /* Note: Floating-point values that didn't fit into an FP
+ register are only written to memory. */
+ while (len > 0)
+ {
+ /* Rememer if the argument was written to the stack. */
+ int stack_used_p = 0;
+ int partial_len = (len < mips_saved_regsize (tdep)
+ ? len : mips_saved_regsize (tdep));
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ partial_len);
+
+ /* Write this portion of the argument to the stack. */
+ if (argreg > MIPS_LAST_ARG_REGNUM
+ || odd_sized_struct
+ || fp_register_arg_p (typecode, arg_type))
+ {
+ /* Should shorter than int integer values be
+ promoted to int before being stored? */
+ int longword_offset = 0;
+ CORE_ADDR addr;
+ stack_used_p = 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (mips_stack_argsize (tdep) == 8
+ && (typecode == TYPE_CODE_INT
+ || typecode == TYPE_CODE_PTR
+ || typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = mips_stack_argsize (tdep) - len;
+ }
+
+ if (mips_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
+ }
+
+ addr = sp + stack_offset + longword_offset;
+
+ if (mips_debug)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
+ for (i = 0; i < partial_len; i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
+ }
+ }
+ write_memory (addr, val, partial_len);
+ }
+
+ /* Note!!! This is NOT an else clause. Odd sized
+ structs may go thru BOTH paths. Floating point
+ arguments will not. */
+ /* Write this portion of the argument to a general
+ purpose register. */
+ if (argreg <= MIPS_LAST_ARG_REGNUM
+ && !fp_register_arg_p (typecode, arg_type))
+ {
+ LONGEST regval =
+ extract_unsigned_integer (val, partial_len);
+
+ /* A non-floating-point argument being passed in a
+ general register. If a struct or union, and if
+ the remaining length is smaller than the register
+ size, we have to adjust the register value on
+ big endian targets.
+
+ It does not seem to be necessary to do the
+ same for integral types.
+
+ cagney/2001-07-23: gdb/179: Also, GCC, when
+ outputting LE O32 with sizeof (struct) <
+ mips_saved_regsize(), generates a left shift as
+ part of storing the argument in a register a
+ register (the left shift isn't generated when
+ sizeof (struct) >= mips_saved_regsize()). Since
+ it is quite possible that this is GCC
+ contradicting the LE/O32 ABI, GDB has not been
+ adjusted to accommodate this. Either someone
+ needs to demonstrate that the LE/O32 ABI
+ specifies such a left shift OR this new ABI gets
+ identified as such and GDB gets tweaked
+ accordingly. */
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && partial_len < mips_saved_regsize (tdep)
+ && (typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION))
+ regval <<= ((mips_saved_regsize (tdep) - partial_len) *
+ TARGET_CHAR_BIT);
+
+ if (mips_debug)
+ fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ argreg,
+ phex (regval,
+ mips_saved_regsize (tdep)));
+ write_register (argreg, regval);
+ argreg++;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+
+ /* Compute the the offset into the stack at which we
+ will copy the next parameter.
+
+ In N32 (N64?), the stack_offset only needs to be
+ adjusted when it has been used. */
+
+ if (stack_used_p)
+ stack_offset += align_up (partial_len,
+ mips_stack_argsize (tdep));
+ }
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+static enum return_value_convention
+mips_n32n64_return_value (struct gdbarch *gdbarch,
+ struct type *type, struct regcache *regcache,
+ void *readbuf, const void *writebuf)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION
+ || TYPE_CODE (type) == TYPE_CODE_ARRAY
+ || TYPE_LENGTH (type) > 2 * mips_saved_regsize (tdep))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A floating-point value belongs in the least significant part
+ of FP0. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0,
+ TYPE_LENGTH (type),
+ TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) <= 2
+ && TYPE_NFIELDS (type) >= 1
+ && ((TYPE_NFIELDS (type) == 1
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT))
+ || (TYPE_NFIELDS (type) == 2
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT)
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
+ == TYPE_CODE_FLT)))
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A struct that contains one or two floats. Each value is part
+ in the least significant part of their floating point
+ register.. */
+ int regnum;
+ int field;
+ for (field = 0, regnum = mips_regnum (current_gdbarch)->fp0;
+ field < TYPE_NFIELDS (type); field++, regnum += 2)
+ {
+ int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
+ / TARGET_CHAR_BIT);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n",
+ offset);
+ mips_xfer_register (regcache, NUM_REGS + regnum,
+ TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ /* A structure or union. Extract the left justified value,
+ regardless of the byte order. I.e. DO NOT USE
+ mips_xfer_lower. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += register_size (current_gdbarch, regnum), regnum++)
+ {
+ int xfer = register_size (current_gdbarch, regnum);
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
+ BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else
+ {
+ /* A scalar extract each part but least-significant-byte
+ justified. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += register_size (current_gdbarch, regnum), regnum++)
+ {
+ int xfer = register_size (current_gdbarch, regnum);
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+}
+
+/* O32 ABI stuff. */
+
+static CORE_ADDR
+mips_o32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* For shared libraries, "t9" needs to point at the function
+ address. */
+ regcache_cooked_write_signed (regcache, T9_REGNUM, func_addr);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_signed (regcache, RA_REGNUM, bp_addr);
+
+ /* First ensure that the stack and structure return address (if any)
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
+ sp = align_down (sp, 16);
+ struct_addr = align_down (struct_addr, 16);
+
+ /* Now make space on the stack for the args. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ len += align_up (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ mips_stack_argsize (tdep));
+ sp -= align_up (len, 16);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o32_push_dummy_call: sp=0x%s allocated %ld\n",
+ paddr_nz (sp), (long) align_up (len, 16));
+
+ /* Initialize the integer and float register pointers. */
+ argreg = A0_REGNUM;
+ float_argreg = mips_fpa0_regnum (current_gdbarch);
+
+ /* The struct_return pointer occupies the first parameter-passing reg. */
+ if (struct_return)
+ {
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o32_push_dummy_call: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
+ write_register (argreg++, struct_addr);
+ stack_offset += mips_stack_argsize (tdep);
+ }
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. Loop thru args
+ from first to last. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val;
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (arg_type);
+ enum type_code typecode = TYPE_CODE (arg_type);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o32_push_dummy_call: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
+
+ val = (char *) VALUE_CONTENTS (arg);
+
+ /* 32-bit ABIs always start floating point arguments in an
+ even-numbered floating point register. Round the FP register
+ up before the check to see if there are any FP registers
+ left. O32/O64 targets also pass the FP in the integer
+ registers so also round up normal registers. */
+ if (!FP_REGISTER_DOUBLE && fp_register_arg_p (typecode, arg_type))
+ {
+ if ((float_argreg & 1))
+ float_argreg++;
+ }
+
+ /* Floating point arguments passed in registers have to be
+ treated specially. On 32-bit architectures, doubles
+ are passed in register pairs; the even register gets
+ the low word, and the odd register gets the high word.
+ On O32/O64, the first two floating point arguments are
+ also copied to general registers, because MIPS16 functions
+ don't use float registers for arguments. This duplication of
+ arguments in general registers can't hurt non-MIPS16 functions
+ because those registers are normally skipped. */
+
+ if (fp_register_arg_p (typecode, arg_type)
+ && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ {
+ if (!FP_REGISTER_DOUBLE && len == 8)
+ {
+ int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+ unsigned long regval;
+
+ /* Write the low word of the double to the even register(s). */
+ regval = extract_unsigned_integer (val + low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
+
+ /* Write the high word of the double to the odd register(s). */
+ regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
+ }
+ else
+ {
+ /* This is a floating point value that fits entirely
+ in a single register. */
+ /* On 32 bit ABI's the float_argreg is further adjusted
+ above to ensure that it is even register aligned. */
+ LONGEST regval = extract_unsigned_integer (val, len);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, len));
+ write_register (float_argreg++, regval);
+ /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
+ registers for each argument. The below is (my
+ guess) to ensure that the corresponding integer
+ register has reserved the same space. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, len));
+ write_register (argreg, regval);
+ argreg += FP_REGISTER_DOUBLE ? 1 : 2;
+ }
+ /* Reserve space for the FP register. */
+ stack_offset += align_up (len, mips_stack_argsize (tdep));
+ }
+ else
+ {
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ /* Note: structs whose size is not a multiple of
+ mips_regsize() are treated specially: Irix cc passes them
+ in registers where gcc sometimes puts them on the stack.
+ For maximum compatibility, we will put them in both
+ places. */
+ int odd_sized_struct = ((len > mips_saved_regsize (tdep))
+ && (len % mips_saved_regsize (tdep) != 0));
+ /* Structures should be aligned to eight bytes (even arg registers)
+ on MIPS_ABI_O32, if their first member has double precision. */
+ if (mips_saved_regsize (tdep) < 8
+ && mips_type_needs_double_align (arg_type))
+ {
+ if ((argreg & 1))
+ argreg++;
+ }
+ /* Note: Floating-point values that didn't fit into an FP
+ register are only written to memory. */
+ while (len > 0)
+ {
+ /* Remember if the argument was written to the stack. */
+ int stack_used_p = 0;
+ int partial_len = (len < mips_saved_regsize (tdep)
+ ? len : mips_saved_regsize (tdep));
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ partial_len);
+
+ /* Write this portion of the argument to the stack. */
+ if (argreg > MIPS_LAST_ARG_REGNUM
+ || odd_sized_struct
+ || fp_register_arg_p (typecode, arg_type))
+ {
+ /* Should shorter than int integer values be
+ promoted to int before being stored? */
+ int longword_offset = 0;
+ CORE_ADDR addr;
+ stack_used_p = 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (mips_stack_argsize (tdep) == 8
+ && (typecode == TYPE_CODE_INT
+ || typecode == TYPE_CODE_PTR
+ || typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = mips_stack_argsize (tdep) - len;
+ }
+
+ if (mips_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
+ }
+
+ addr = sp + stack_offset + longword_offset;
+
+ if (mips_debug)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
+ for (i = 0; i < partial_len; i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
+ }
+ }
+ write_memory (addr, val, partial_len);
+ }
+
+ /* Note!!! This is NOT an else clause. Odd sized
+ structs may go thru BOTH paths. Floating point
+ arguments will not. */
+ /* Write this portion of the argument to a general
+ purpose register. */
+ if (argreg <= MIPS_LAST_ARG_REGNUM
+ && !fp_register_arg_p (typecode, arg_type))
+ {
+ LONGEST regval = extract_signed_integer (val, partial_len);
+ /* Value may need to be sign extended, because
+ mips_regsize() != mips_saved_regsize(). */
+
+ /* A non-floating-point argument being passed in a
+ general register. If a struct or union, and if
+ the remaining length is smaller than the register
+ size, we have to adjust the register value on
+ big endian targets.
+
+ It does not seem to be necessary to do the
+ same for integral types.
+
+ Also don't do this adjustment on O64 binaries.
+
+ cagney/2001-07-23: gdb/179: Also, GCC, when
+ outputting LE O32 with sizeof (struct) <
+ mips_saved_regsize(), generates a left shift as
+ part of storing the argument in a register a
+ register (the left shift isn't generated when
+ sizeof (struct) >= mips_saved_regsize()). Since
+ it is quite possible that this is GCC
+ contradicting the LE/O32 ABI, GDB has not been
+ adjusted to accommodate this. Either someone
+ needs to demonstrate that the LE/O32 ABI
+ specifies such a left shift OR this new ABI gets
+ identified as such and GDB gets tweaked
+ accordingly. */
+
+ if (mips_saved_regsize (tdep) < 8
+ && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && partial_len < mips_saved_regsize (tdep)
+ && (typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION))
+ regval <<= ((mips_saved_regsize (tdep) - partial_len) *
+ TARGET_CHAR_BIT);
+
+ if (mips_debug)
+ fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ argreg,
+ phex (regval,
+ mips_saved_regsize (tdep)));
+ write_register (argreg, regval);
+ argreg++;
+
+ /* Prevent subsequent floating point arguments from
+ being passed in floating point registers. */
+ float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+
+ /* Compute the the offset into the stack at which we
+ will copy the next parameter.
+
+ In older ABIs, the caller reserved space for
+ registers that contained arguments. This was loosely
+ refered to as their "home". Consequently, space is
+ always allocated. */
+
+ stack_offset += align_up (partial_len,
+ mips_stack_argsize (tdep));
+ }
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+static enum return_value_convention
+mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache,
+ void *readbuf, const void *writebuf)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION
+ || TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 4 && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A single-precision floating-point value. It fits in the
+ least significant part of FP0. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0,
+ TYPE_LENGTH (type),
+ TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 8 && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A double-precision floating-point value. The most
+ significant part goes in FP1, and the least significant in
+ FP0. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n");
+ switch (TARGET_BYTE_ORDER)
+ {
+ case BFD_ENDIAN_LITTLE:
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
+ 0, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
+ 1, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
+ break;
+ case BFD_ENDIAN_BIG:
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
+ 1, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
+ 0, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+#if 0
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) <= 2
+ && TYPE_NFIELDS (type) >= 1
+ && ((TYPE_NFIELDS (type) == 1
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT))
+ || (TYPE_NFIELDS (type) == 2
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT)
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
+ == TYPE_CODE_FLT)))
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A struct that contains one or two floats. Each value is part
+ in the least significant part of their floating point
+ register.. */
+ bfd_byte reg[MAX_REGISTER_SIZE];
+ int regnum;
+ int field;
+ for (field = 0, regnum = mips_regnum (current_gdbarch)->fp0;
+ field < TYPE_NFIELDS (type); field++, regnum += 2)
+ {
+ int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
+ / TARGET_CHAR_BIT);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n",
+ offset);
+ mips_xfer_register (regcache, NUM_REGS + regnum,
+ TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+#endif
+#if 0
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ /* A structure or union. Extract the left justified value,
+ regardless of the byte order. I.e. DO NOT USE
+ mips_xfer_lower. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += register_size (current_gdbarch, regnum), regnum++)
+ {
+ int xfer = register_size (current_gdbarch, regnum);
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
+ BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+#endif
+ else
+ {
+ /* A scalar extract each part but least-significant-byte
+ justified. o32 thinks registers are 4 byte, regardless of
+ the ISA. mips_stack_argsize controls this. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += mips_stack_argsize (tdep), regnum++)
+ {
+ int xfer = mips_stack_argsize (tdep);
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+}
+
+/* O64 ABI. This is a hacked up kind of 64-bit version of the o32
+ ABI. */
+
+static CORE_ADDR
+mips_o64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs,
+ struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* For shared libraries, "t9" needs to point at the function
+ address. */
+ regcache_cooked_write_signed (regcache, T9_REGNUM, func_addr);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_signed (regcache, RA_REGNUM, bp_addr);
+
+ /* First ensure that the stack and structure return address (if any)
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
+ sp = align_down (sp, 16);
+ struct_addr = align_down (struct_addr, 16);
+
+ /* Now make space on the stack for the args. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ len += align_up (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ mips_stack_argsize (tdep));
+ sp -= align_up (len, 16);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o64_push_dummy_call: sp=0x%s allocated %ld\n",
+ paddr_nz (sp), (long) align_up (len, 16));
+
+ /* Initialize the integer and float register pointers. */
+ argreg = A0_REGNUM;
+ float_argreg = mips_fpa0_regnum (current_gdbarch);
+
+ /* The struct_return pointer occupies the first parameter-passing reg. */
+ if (struct_return)
+ {
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o64_push_dummy_call: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
+ write_register (argreg++, struct_addr);
+ stack_offset += mips_stack_argsize (tdep);
+ }
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. Loop thru args
+ from first to last. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val;
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (arg_type);
+ enum type_code typecode = TYPE_CODE (arg_type);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o64_push_dummy_call: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
+
+ val = (char *) VALUE_CONTENTS (arg);
+
+ /* 32-bit ABIs always start floating point arguments in an
+ even-numbered floating point register. Round the FP register
+ up before the check to see if there are any FP registers
+ left. O32/O64 targets also pass the FP in the integer
+ registers so also round up normal registers. */
+ if (!FP_REGISTER_DOUBLE && fp_register_arg_p (typecode, arg_type))
+ {
+ if ((float_argreg & 1))
+ float_argreg++;
+ }
+
+ /* Floating point arguments passed in registers have to be
+ treated specially. On 32-bit architectures, doubles
+ are passed in register pairs; the even register gets
+ the low word, and the odd register gets the high word.
+ On O32/O64, the first two floating point arguments are
+ also copied to general registers, because MIPS16 functions
+ don't use float registers for arguments. This duplication of
+ arguments in general registers can't hurt non-MIPS16 functions
+ because those registers are normally skipped. */
+
+ if (fp_register_arg_p (typecode, arg_type)
+ && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ {
+ if (!FP_REGISTER_DOUBLE && len == 8)
+ {
+ int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+ unsigned long regval;
+
+ /* Write the low word of the double to the even register(s). */
+ regval = extract_unsigned_integer (val + low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
+
+ /* Write the high word of the double to the odd register(s). */
+ regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
+ }
+ else
+ {
+ /* This is a floating point value that fits entirely
+ in a single register. */
+ /* On 32 bit ABI's the float_argreg is further adjusted
+ above to ensure that it is even register aligned. */
+ LONGEST regval = extract_unsigned_integer (val, len);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, len));
+ write_register (float_argreg++, regval);
+ /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
+ registers for each argument. The below is (my
+ guess) to ensure that the corresponding integer
+ register has reserved the same space. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, len));
+ write_register (argreg, regval);
+ argreg += FP_REGISTER_DOUBLE ? 1 : 2;
+ }
+ /* Reserve space for the FP register. */
+ stack_offset += align_up (len, mips_stack_argsize (tdep));
+ }
+ else
+ {
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ /* Note: structs whose size is not a multiple of
+ mips_regsize() are treated specially: Irix cc passes them
+ in registers where gcc sometimes puts them on the stack.
+ For maximum compatibility, we will put them in both
+ places. */
+ int odd_sized_struct = ((len > mips_saved_regsize (tdep))
+ && (len % mips_saved_regsize (tdep) != 0));
+ /* Structures should be aligned to eight bytes (even arg registers)
+ on MIPS_ABI_O32, if their first member has double precision. */
+ if (mips_saved_regsize (tdep) < 8
+ && mips_type_needs_double_align (arg_type))
+ {
+ if ((argreg & 1))
+ argreg++;
+ }
+ /* Note: Floating-point values that didn't fit into an FP
+ register are only written to memory. */
+ while (len > 0)
+ {
+ /* Remember if the argument was written to the stack. */
+ int stack_used_p = 0;
+ int partial_len = (len < mips_saved_regsize (tdep)
+ ? len : mips_saved_regsize (tdep));
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ partial_len);
+
+ /* Write this portion of the argument to the stack. */
+ if (argreg > MIPS_LAST_ARG_REGNUM
+ || odd_sized_struct
+ || fp_register_arg_p (typecode, arg_type))
+ {
+ /* Should shorter than int integer values be
+ promoted to int before being stored? */
+ int longword_offset = 0;
+ CORE_ADDR addr;
+ stack_used_p = 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (mips_stack_argsize (tdep) == 8
+ && (typecode == TYPE_CODE_INT
+ || typecode == TYPE_CODE_PTR
+ || typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = mips_stack_argsize (tdep) - len;
+ }
+
+ if (mips_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
+ }
+
+ addr = sp + stack_offset + longword_offset;
+
+ if (mips_debug)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
+ for (i = 0; i < partial_len; i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
+ }
+ }
+ write_memory (addr, val, partial_len);
+ }
+
+ /* Note!!! This is NOT an else clause. Odd sized
+ structs may go thru BOTH paths. Floating point
+ arguments will not. */
+ /* Write this portion of the argument to a general
+ purpose register. */
+ if (argreg <= MIPS_LAST_ARG_REGNUM
+ && !fp_register_arg_p (typecode, arg_type))
+ {
+ LONGEST regval = extract_signed_integer (val, partial_len);
+ /* Value may need to be sign extended, because
+ mips_regsize() != mips_saved_regsize(). */
+
+ /* A non-floating-point argument being passed in a
+ general register. If a struct or union, and if
+ the remaining length is smaller than the register
+ size, we have to adjust the register value on
+ big endian targets.
+
+ It does not seem to be necessary to do the
+ same for integral types.
+
+ Also don't do this adjustment on O64 binaries.
+
+ cagney/2001-07-23: gdb/179: Also, GCC, when
+ outputting LE O32 with sizeof (struct) <
+ mips_saved_regsize(), generates a left shift as
+ part of storing the argument in a register a
+ register (the left shift isn't generated when
+ sizeof (struct) >= mips_saved_regsize()). Since
+ it is quite possible that this is GCC
+ contradicting the LE/O32 ABI, GDB has not been
+ adjusted to accommodate this. Either someone
+ needs to demonstrate that the LE/O32 ABI
+ specifies such a left shift OR this new ABI gets
+ identified as such and GDB gets tweaked
+ accordingly. */
+
+ if (mips_saved_regsize (tdep) < 8
+ && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && partial_len < mips_saved_regsize (tdep)
+ && (typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION))
+ regval <<= ((mips_saved_regsize (tdep) - partial_len) *
+ TARGET_CHAR_BIT);
+
+ if (mips_debug)
+ fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ argreg,
+ phex (regval,
+ mips_saved_regsize (tdep)));
+ write_register (argreg, regval);
+ argreg++;
+
+ /* Prevent subsequent floating point arguments from
+ being passed in floating point registers. */
+ float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+
+ /* Compute the the offset into the stack at which we
+ will copy the next parameter.
+
+ In older ABIs, the caller reserved space for
+ registers that contained arguments. This was loosely
+ refered to as their "home". Consequently, space is
+ always allocated. */
+
+ stack_offset += align_up (partial_len,
+ mips_stack_argsize (tdep));
+ }
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+static void
+mips_o64_extract_return_value (struct type *valtype,
+ char regbuf[], char *valbuf)
+{
+ struct return_value_word lo;
+ struct return_value_word hi;
+ return_value_location (valtype, &hi, &lo);
+
+ memcpy (valbuf + lo.buf_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + lo.reg) +
+ lo.reg_offset, lo.len);
+
+ if (hi.len > 0)
+ memcpy (valbuf + hi.buf_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + hi.reg) +
+ hi.reg_offset, hi.len);
+}
+
+static void
+mips_o64_store_return_value (struct type *valtype, char *valbuf)
+{
+ char raw_buffer[MAX_REGISTER_SIZE];
+ struct return_value_word lo;
+ struct return_value_word hi;
+ return_value_location (valtype, &hi, &lo);
+
+ memset (raw_buffer, 0, sizeof (raw_buffer));
+ memcpy (raw_buffer + lo.reg_offset, valbuf + lo.buf_offset, lo.len);
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (lo.reg),
+ raw_buffer, register_size (current_gdbarch,
+ lo.reg));
+
+ if (hi.len > 0)
+ {
+ memset (raw_buffer, 0, sizeof (raw_buffer));
+ memcpy (raw_buffer + hi.reg_offset, valbuf + hi.buf_offset, hi.len);
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (hi.reg),
+ raw_buffer,
+ register_size (current_gdbarch,
+ hi.reg));
+ }
+}
+
+/* Floating point register management.
+
+ Background: MIPS1 & 2 fp registers are 32 bits wide. To support
+ 64bit operations, these early MIPS cpus treat fp register pairs
+ (f0,f1) as a single register (d0). Later MIPS cpu's have 64 bit fp
+ registers and offer a compatibility mode that emulates the MIPS2 fp
+ model. When operating in MIPS2 fp compat mode, later cpu's split
+ double precision floats into two 32-bit chunks and store them in
+ consecutive fp regs. To display 64-bit floats stored in this
+ fashion, we have to combine 32 bits from f0 and 32 bits from f1.
+ Throw in user-configurable endianness and you have a real mess.
+
+ The way this works is:
+ - If we are in 32-bit mode or on a 32-bit processor, then a 64-bit
+ double-precision value will be split across two logical registers.
+ The lower-numbered logical register will hold the low-order bits,
+ regardless of the processor's endianness.
+ - If we are on a 64-bit processor, and we are looking for a
+ single-precision value, it will be in the low ordered bits
+ of a 64-bit GPR (after mfc1, for example) or a 64-bit register
+ save slot in memory.
+ - If we are in 64-bit mode, everything is straightforward.
+
+ Note that this code only deals with "live" registers at the top of the
+ stack. We will attempt to deal with saved registers later, when
+ the raw/cooked register interface is in place. (We need a general
+ interface that can deal with dynamic saved register sizes -- fp
+ regs could be 32 bits wide in one frame and 64 on the frame above
+ and below). */
+
+static struct type *
+mips_float_register_type (void)
+{
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return builtin_type_ieee_single_big;
+ else
+ return builtin_type_ieee_single_little;
+}
+
+static struct type *
+mips_double_register_type (void)
+{
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return builtin_type_ieee_double_big;
+ else
+ return builtin_type_ieee_double_little;
+}
+
+/* Copy a 32-bit single-precision value from the current frame
+ into rare_buffer. */
+
+static void
+mips_read_fp_register_single (struct frame_info *frame, int regno,
+ char *rare_buffer)
+{
+ int raw_size = register_size (current_gdbarch, regno);
+ char *raw_buffer = alloca (raw_size);
+
+ if (!frame_register_read (frame, regno, raw_buffer))
+ error ("can't read register %d (%s)", regno, REGISTER_NAME (regno));
+ if (raw_size == 8)
+ {
+ /* We have a 64-bit value for this register. Find the low-order
+ 32 bits. */
+ int offset;
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = 4;
+ else
+ offset = 0;
+
+ memcpy (rare_buffer, raw_buffer + offset, 4);
+ }
+ else
+ {
+ memcpy (rare_buffer, raw_buffer, 4);
+ }
+}
+
+/* Copy a 64-bit double-precision value from the current frame into
+ rare_buffer. This may include getting half of it from the next
+ register. */
+
+static void
+mips_read_fp_register_double (struct frame_info *frame, int regno,
+ char *rare_buffer)
+{
+ int raw_size = register_size (current_gdbarch, regno);
+
+ if (raw_size == 8 && !mips2_fp_compat ())
+ {
+ /* We have a 64-bit value for this register, and we should use
+ all 64 bits. */
+ if (!frame_register_read (frame, regno, rare_buffer))
+ error ("can't read register %d (%s)", regno, REGISTER_NAME (regno));
+ }
+ else
+ {
+ if ((regno - mips_regnum (current_gdbarch)->fp0) & 1)
+ internal_error (__FILE__, __LINE__,
+ "mips_read_fp_register_double: bad access to "
+ "odd-numbered FP register");
+
+ /* mips_read_fp_register_single will find the correct 32 bits from
+ each register. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ mips_read_fp_register_single (frame, regno, rare_buffer + 4);
+ mips_read_fp_register_single (frame, regno + 1, rare_buffer);
+ }
+ else
+ {
+ mips_read_fp_register_single (frame, regno, rare_buffer);
+ mips_read_fp_register_single (frame, regno + 1, rare_buffer + 4);
+ }
+ }
+}
+
+static void
+mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
+ int regnum)
+{ /* do values for FP (float) regs */
+ char *raw_buffer;
+ double doub, flt1; /* doubles extracted from raw hex data */
+ int inv1, inv2;
+
+ raw_buffer =
+ (char *) alloca (2 *
+ register_size (current_gdbarch,
+ mips_regnum (current_gdbarch)->fp0));
+
+ fprintf_filtered (file, "%s:", REGISTER_NAME (regnum));
+ fprintf_filtered (file, "%*s", 4 - (int) strlen (REGISTER_NAME (regnum)),
+ "");
+
+ if (register_size (current_gdbarch, regnum) == 4 || mips2_fp_compat ())
+ {
+ /* 4-byte registers: Print hex and floating. Also print even
+ numbered registers as doubles. */
+ mips_read_fp_register_single (frame, regnum, raw_buffer);
+ flt1 = unpack_double (mips_float_register_type (), raw_buffer, &inv1);
+
+ print_scalar_formatted (raw_buffer, builtin_type_uint32, 'x', 'w',
+ file);
+
+ fprintf_filtered (file, " flt: ");
+ if (inv1)
+ fprintf_filtered (file, " <invalid float> ");
+ else
+ fprintf_filtered (file, "%-17.9g", flt1);
+
+ if (regnum % 2 == 0)
+ {
+ mips_read_fp_register_double (frame, regnum, raw_buffer);
+ doub = unpack_double (mips_double_register_type (), raw_buffer,
+ &inv2);
+
+ fprintf_filtered (file, " dbl: ");
+ if (inv2)
+ fprintf_filtered (file, "<invalid double>");
+ else
+ fprintf_filtered (file, "%-24.17g", doub);
+ }
+ }
+ else
+ {
+ /* Eight byte registers: print each one as hex, float and double. */
+ mips_read_fp_register_single (frame, regnum, raw_buffer);
+ flt1 = unpack_double (mips_float_register_type (), raw_buffer, &inv1);
+
+ mips_read_fp_register_double (frame, regnum, raw_buffer);
+ doub = unpack_double (mips_double_register_type (), raw_buffer, &inv2);
+
+
+ print_scalar_formatted (raw_buffer, builtin_type_uint64, 'x', 'g',
+ file);
+
+ fprintf_filtered (file, " flt: ");
+ if (inv1)
+ fprintf_filtered (file, "<invalid float>");
+ else
+ fprintf_filtered (file, "%-17.9g", flt1);
+
+ fprintf_filtered (file, " dbl: ");
+ if (inv2)
+ fprintf_filtered (file, "<invalid double>");
+ else
+ fprintf_filtered (file, "%-24.17g", doub);
+ }
+}
+
+static void
+mips_print_register (struct ui_file *file, struct frame_info *frame,
+ int regnum, int all)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ char raw_buffer[MAX_REGISTER_SIZE];
+ int offset;
+
+ if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) == TYPE_CODE_FLT)
+ {
+ mips_print_fp_register (file, frame, regnum);
+ return;
+ }
+
+ /* Get the data in raw format. */
+ if (!frame_register_read (frame, regnum, raw_buffer))
+ {
+ fprintf_filtered (file, "%s: [Invalid]", REGISTER_NAME (regnum));
+ return;
+ }
+
+ fputs_filtered (REGISTER_NAME (regnum), file);
+
+ /* The problem with printing numeric register names (r26, etc.) is that
+ the user can't use them on input. Probably the best solution is to
+ fix it so that either the numeric or the funky (a2, etc.) names
+ are accepted on input. */
+ if (regnum < MIPS_NUMREGS)
+ fprintf_filtered (file, "(r%d): ", regnum);
+ else
+ fprintf_filtered (file, ": ");
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset =
+ register_size (current_gdbarch,
+ regnum) - register_size (current_gdbarch, regnum);
+ else
+ offset = 0;
+
+ print_scalar_formatted (raw_buffer + offset,
+ gdbarch_register_type (gdbarch, regnum), 'x', 0,
+ file);
+}
+
+/* Replacement for generic do_registers_info.
+ Print regs in pretty columns. */
+
+static int
+print_fp_register_row (struct ui_file *file, struct frame_info *frame,
+ int regnum)
+{
+ fprintf_filtered (file, " ");
+ mips_print_fp_register (file, frame, regnum);
+ fprintf_filtered (file, "\n");
+ return regnum + 1;
+}
+
+
+/* Print a row's worth of GP (int) registers, with name labels above */
+
+static int
+print_gp_register_row (struct ui_file *file, struct frame_info *frame,
+ int start_regnum)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ /* do values for GP (int) regs */
+ char raw_buffer[MAX_REGISTER_SIZE];
+ int ncols = (mips_regsize (gdbarch) == 8 ? 4 : 8); /* display cols per row */
+ int col, byte;
+ int regnum;
+
+ /* For GP registers, we print a separate row of names above the vals */
+ fprintf_filtered (file, " ");
+ for (col = 0, regnum = start_regnum;
+ col < ncols && regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ if (*REGISTER_NAME (regnum) == '\0')
+ continue; /* unused register */
+ if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
+ TYPE_CODE_FLT)
+ break; /* end the row: reached FP register */
+ fprintf_filtered (file,
+ mips_regsize (current_gdbarch) == 8 ? "%17s" : "%9s",
+ REGISTER_NAME (regnum));
+ col++;
+ }
+ /* print the R0 to R31 names */
+ if ((start_regnum % NUM_REGS) < MIPS_NUMREGS)
+ fprintf_filtered (file, "\n R%-4d", start_regnum % NUM_REGS);
+ else
+ fprintf_filtered (file, "\n ");
+
+ /* now print the values in hex, 4 or 8 to the row */
+ for (col = 0, regnum = start_regnum;
+ col < ncols && regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ if (*REGISTER_NAME (regnum) == '\0')
+ continue; /* unused register */
+ if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
+ TYPE_CODE_FLT)
+ break; /* end row: reached FP register */
+ /* OK: get the data in raw format. */
+ if (!frame_register_read (frame, regnum, raw_buffer))
+ error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
+ /* pad small registers */
+ for (byte = 0;
+ byte < (mips_regsize (current_gdbarch)
+ - register_size (current_gdbarch, regnum)); byte++)
+ printf_filtered (" ");
+ /* Now print the register value in hex, endian order. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ for (byte =
+ register_size (current_gdbarch,
+ regnum) - register_size (current_gdbarch, regnum);
+ byte < register_size (current_gdbarch, regnum); byte++)
+ fprintf_filtered (file, "%02x", (unsigned char) raw_buffer[byte]);
+ else
+ for (byte = register_size (current_gdbarch, regnum) - 1;
+ byte >= 0; byte--)
+ fprintf_filtered (file, "%02x", (unsigned char) raw_buffer[byte]);
+ fprintf_filtered (file, " ");
+ col++;
+ }
+ if (col > 0) /* ie. if we actually printed anything... */
+ fprintf_filtered (file, "\n");
+
+ return regnum;
+}
+
+/* MIPS_DO_REGISTERS_INFO(): called by "info register" command */
+
+static void
+mips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, int regnum, int all)
+{
+ if (regnum != -1) /* do one specified register */
+ {
+ gdb_assert (regnum >= NUM_REGS);
+ if (*(REGISTER_NAME (regnum)) == '\0')
+ error ("Not a valid register for the current processor type");
+
+ mips_print_register (file, frame, regnum, 0);
+ fprintf_filtered (file, "\n");
+ }
+ else
+ /* do all (or most) registers */
+ {
+ regnum = NUM_REGS;
+ while (regnum < NUM_REGS + NUM_PSEUDO_REGS)
+ {
+ if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
+ TYPE_CODE_FLT)
+ {
+ if (all) /* true for "INFO ALL-REGISTERS" command */
+ regnum = print_fp_register_row (file, frame, regnum);
+ else
+ regnum += MIPS_NUMREGS; /* skip floating point regs */
+ }
+ else
+ regnum = print_gp_register_row (file, frame, regnum);
+ }
+ }
+}
+
+/* Is this a branch with a delay slot? */
+
+static int is_delayed (unsigned long);
+
+static int
+is_delayed (unsigned long insn)
+{
+ int i;
+ for (i = 0; i < NUMOPCODES; ++i)
+ if (mips_opcodes[i].pinfo != INSN_MACRO
+ && (insn & mips_opcodes[i].mask) == mips_opcodes[i].match)
+ break;
+ return (i < NUMOPCODES
+ && (mips_opcodes[i].pinfo & (INSN_UNCOND_BRANCH_DELAY
+ | INSN_COND_BRANCH_DELAY
+ | INSN_COND_BRANCH_LIKELY)));
+}
+
+int
+mips_step_skips_delay (CORE_ADDR pc)
+{
+ char buf[MIPS_INSTLEN];
+
+ /* There is no branch delay slot on MIPS16. */
+ if (pc_is_mips16 (pc))
+ return 0;
+
+ if (target_read_memory (pc, buf, MIPS_INSTLEN) != 0)
+ /* If error reading memory, guess that it is not a delayed branch. */
+ return 0;
+ return is_delayed ((unsigned long)
+ extract_unsigned_integer (buf, MIPS_INSTLEN));
+}
+
+/* Skip the PC past function prologue instructions (32-bit version).
+ This is a helper function for mips_skip_prologue. */
+
+static CORE_ADDR
+mips32_skip_prologue (CORE_ADDR pc)
+{
+ t_inst inst;
+ CORE_ADDR end_pc;
+ int seen_sp_adjust = 0;
+ int load_immediate_bytes = 0;
+
+ /* Find an upper bound on the prologue. */
+ end_pc = skip_prologue_using_sal (pc);
+ if (end_pc == 0)
+ end_pc = pc + 100; /* Magic. */
+
+ /* 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 (; pc < end_pc; pc += MIPS_INSTLEN)
+ {
+ unsigned long high_word;
+
+ inst = mips_fetch_instruction (pc);
+ high_word = (inst >> 16) & 0xffff;
+
+ if (high_word == 0x27bd /* addiu $sp,$sp,offset */
+ || high_word == 0x67bd) /* daddiu $sp,$sp,offset */
+ seen_sp_adjust = 1;
+ else if (inst == 0x03a1e823 || /* subu $sp,$sp,$at */
+ inst == 0x03a8e823) /* subu $sp,$sp,$t0 */
+ seen_sp_adjust = 1;
+ else if (((inst & 0xFFE00000) == 0xAFA00000 /* sw reg,n($sp) */
+ || (inst & 0xFFE00000) == 0xFFA00000) /* sd reg,n($sp) */
+ && (inst & 0x001F0000)) /* reg != $zero */
+ continue;
+
+ else if ((inst & 0xFFE00000) == 0xE7A00000) /* swc1 freg,n($sp) */
+ continue;
+ else if ((inst & 0xF3E00000) == 0xA3C00000 && (inst & 0x001F0000))
+ /* sx reg,n($s8) */
+ continue; /* reg != $zero */
+
+ /* move $s8,$sp. With different versions of gas this will be either
+ `addu $s8,$sp,$zero' or `or $s8,$sp,$zero' or `daddu s8,sp,$0'.
+ Accept any one of these. */
+ else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
+ continue;
+
+ else if ((inst & 0xFF9F07FF) == 0x00800021) /* move reg,$a0-$a3 */
+ continue;
+ else if (high_word == 0x3c1c) /* lui $gp,n */
+ continue;
+ else if (high_word == 0x279c) /* addiu $gp,$gp,n */
+ continue;
+ else if (inst == 0x0399e021 /* addu $gp,$gp,$t9 */
+ || inst == 0x033ce021) /* addu $gp,$t9,$gp */
+ continue;
+ /* The following instructions load $at or $t0 with an immediate
+ value in preparation for a stack adjustment via
+ subu $sp,$sp,[$at,$t0]. These instructions could also initialize
+ a local variable, so we accept them only before a stack adjustment
+ instruction was seen. */
+ else if (!seen_sp_adjust)
+ {
+ if (high_word == 0x3c01 || /* lui $at,n */
+ high_word == 0x3c08) /* lui $t0,n */
+ {
+ load_immediate_bytes += MIPS_INSTLEN; /* FIXME!! */
+ continue;
+ }
+ else if (high_word == 0x3421 || /* ori $at,$at,n */
+ high_word == 0x3508 || /* ori $t0,$t0,n */
+ high_word == 0x3401 || /* ori $at,$zero,n */
+ high_word == 0x3408) /* ori $t0,$zero,n */
+ {
+ load_immediate_bytes += MIPS_INSTLEN; /* FIXME!! */
+ continue;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ /* In a frameless function, we might have incorrectly
+ skipped some load immediate instructions. Undo the skipping
+ if the load immediate was not followed by a stack adjustment. */
+ if (load_immediate_bytes && !seen_sp_adjust)
+ pc -= load_immediate_bytes;
+ return pc;
+}
+
+/* Skip the PC past function prologue instructions (16-bit version).
+ This is a helper function for mips_skip_prologue. */
+
+static CORE_ADDR
+mips16_skip_prologue (CORE_ADDR pc)
+{
+ CORE_ADDR end_pc;
+ int extend_bytes = 0;
+ int prev_extend_bytes;
+
+ /* Table of instructions likely to be found in a function prologue. */
+ static struct
+ {
+ unsigned short inst;
+ unsigned short mask;
+ }
+ table[] =
+ {
+ {
+ 0x6300, 0xff00}
+ , /* addiu $sp,offset */
+ {
+ 0xfb00, 0xff00}
+ , /* daddiu $sp,offset */
+ {
+ 0xd000, 0xf800}
+ , /* sw reg,n($sp) */
+ {
+ 0xf900, 0xff00}
+ , /* sd reg,n($sp) */
+ {
+ 0x6200, 0xff00}
+ , /* sw $ra,n($sp) */
+ {
+ 0xfa00, 0xff00}
+ , /* sd $ra,n($sp) */
+ {
+ 0x673d, 0xffff}
+ , /* move $s1,sp */
+ {
+ 0xd980, 0xff80}
+ , /* sw $a0-$a3,n($s1) */
+ {
+ 0x6704, 0xff1c}
+ , /* move reg,$a0-$a3 */
+ {
+ 0xe809, 0xf81f}
+ , /* entry pseudo-op */
+ {
+ 0x0100, 0xff00}
+ , /* addiu $s1,$sp,n */
+ {
+ 0, 0} /* end of table marker */
+ };
+
+ /* Find an upper bound on the prologue. */
+ end_pc = skip_prologue_using_sal (pc);
+ if (end_pc == 0)
+ end_pc = pc + 100; /* Magic. */
+
+ /* 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 (; pc < end_pc; pc += MIPS16_INSTLEN)
+ {
+ unsigned short inst;
+ int i;
+
+ inst = mips_fetch_instruction (pc);
+
+ /* Normally we ignore an extend instruction. However, if it is
+ not followed by a valid prologue instruction, we must adjust
+ the pc back over the extend so that it won't be considered
+ part of the prologue. */
+ if ((inst & 0xf800) == 0xf000) /* extend */
+ {
+ extend_bytes = MIPS16_INSTLEN;
+ continue;
+ }
+ prev_extend_bytes = extend_bytes;
+ extend_bytes = 0;
+
+ /* Check for other valid prologue instructions besides extend. */
+ for (i = 0; table[i].mask != 0; i++)
+ if ((inst & table[i].mask) == table[i].inst) /* found, get out */
+ break;
+ if (table[i].mask != 0) /* it was in table? */
+ continue; /* ignore it */
+ else
+ /* non-prologue */
+ {
+ /* Return the current pc, adjusted backwards by 2 if
+ the previous instruction was an extend. */
+ return pc - prev_extend_bytes;
+ }
+ }
+ return pc;
+}
+
+/* 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.
+ We must skip more in the case where part of the prologue is in the
+ delay slot of a non-prologue instruction). */
+
+static CORE_ADDR
+mips_skip_prologue (CORE_ADDR pc)
+{
+ /* 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. */
+
+ CORE_ADDR 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. */
+
+ if (pc_is_mips16 (pc))
+ return mips16_skip_prologue (pc);
+ else
+ return mips32_skip_prologue (pc);
+}
+
+/* Exported procedure: Is PC in the signal trampoline code */
+
+static int
+mips_pc_in_sigtramp (CORE_ADDR pc, char *ignore)
+{
+ if (sigtramp_address == 0)
+ fixup_sigtramp ();
+ return (pc >= sigtramp_address && pc < sigtramp_end);
+}
+
+/* Root of all "set mips "/"show mips " commands. This will eventually be
+ used for all MIPS-specific commands. */
+
+static void
+show_mips_command (char *args, int from_tty)
+{
+ help_list (showmipscmdlist, "show mips ", all_commands, gdb_stdout);
+}
+
+static void
+set_mips_command (char *args, int from_tty)
+{
+ printf_unfiltered
+ ("\"set mips\" must be followed by an appropriate subcommand.\n");
+ help_list (setmipscmdlist, "set mips ", all_commands, gdb_stdout);
+}
+
+/* Commands to show/set the MIPS FPU type. */
+
+static void
+show_mipsfpu_command (char *args, int from_tty)
+{
+ char *fpu;
+ switch (MIPS_FPU_TYPE)
+ {
+ case MIPS_FPU_SINGLE:
+ fpu = "single-precision";
+ break;
+ case MIPS_FPU_DOUBLE:
+ fpu = "double-precision";
+ break;
+ case MIPS_FPU_NONE:
+ fpu = "absent (none)";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ if (mips_fpu_type_auto)
+ printf_unfiltered
+ ("The MIPS floating-point coprocessor is set automatically (currently %s)\n",
+ fpu);
+ else
+ printf_unfiltered
+ ("The MIPS floating-point coprocessor is assumed to be %s\n", fpu);
+}
+
+
+static void
+set_mipsfpu_command (char *args, int from_tty)
+{
+ printf_unfiltered
+ ("\"set mipsfpu\" must be followed by \"double\", \"single\",\"none\" or \"auto\".\n");
+ show_mipsfpu_command (args, from_tty);
+}
+
+static void
+set_mipsfpu_single_command (char *args, int from_tty)
+{
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+ mips_fpu_type = MIPS_FPU_SINGLE;
+ mips_fpu_type_auto = 0;
+ /* FIXME: cagney/2003-11-15: Should be setting a field in "info"
+ instead of relying on globals. Doing that would let generic code
+ handle the search for this specific architecture. */
+ if (!gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "set mipsfpu failed");
+}
+
+static void
+set_mipsfpu_double_command (char *args, int from_tty)
+{
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+ mips_fpu_type = MIPS_FPU_DOUBLE;
+ mips_fpu_type_auto = 0;
+ /* FIXME: cagney/2003-11-15: Should be setting a field in "info"
+ instead of relying on globals. Doing that would let generic code
+ handle the search for this specific architecture. */
+ if (!gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "set mipsfpu failed");
+}
+
+static void
+set_mipsfpu_none_command (char *args, int from_tty)
+{
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+ mips_fpu_type = MIPS_FPU_NONE;
+ mips_fpu_type_auto = 0;
+ /* FIXME: cagney/2003-11-15: Should be setting a field in "info"
+ instead of relying on globals. Doing that would let generic code
+ handle the search for this specific architecture. */
+ if (!gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "set mipsfpu failed");
+}
+
+static void
+set_mipsfpu_auto_command (char *args, int from_tty)
+{
+ mips_fpu_type_auto = 1;
+}
+
+/* Attempt to identify the particular processor model by reading the
+ processor id. NOTE: cagney/2003-11-15: Firstly it isn't clear that
+ the relevant processor still exists (it dates back to '94) and
+ secondly this is not the way to do this. The processor type should
+ be set by forcing an architecture change. */
+
+void
+deprecated_mips_set_processor_regs_hack (void)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ CORE_ADDR prid;
+
+ prid = read_register (PRID_REGNUM);
+
+ if ((prid & ~0xf) == 0x700)
+ tdep->mips_processor_reg_names = mips_r3041_reg_names;
+}
+
+/* Just like reinit_frame_cache, but with the right arguments to be
+ callable as an sfunc. */
+
+static void
+reinit_frame_cache_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ reinit_frame_cache ();
+}
+
+static int
+gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ mips_extra_func_info_t proc_desc;
+
+ /* Search for the function containing this address. Set the low bit
+ of the address when searching, in case we were given an even address
+ that is the start of a 16-bit function. If we didn't do this,
+ the search would fail because the symbol table says the function
+ starts at an odd address, i.e. 1 byte past the given address. */
+ memaddr = ADDR_BITS_REMOVE (memaddr);
+ proc_desc = non_heuristic_proc_desc (make_mips16_addr (memaddr), NULL);
+
+ /* Make an attempt to determine if this is a 16-bit function. If
+ the procedure descriptor exists and the address therein is odd,
+ it's definitely a 16-bit function. Otherwise, we have to just
+ guess that if the address passed in is odd, it's 16-bits. */
+ /* FIXME: cagney/2003-06-26: Is this even necessary? The
+ disassembler needs to be able to locally determine the ISA, and
+ not rely on GDB. Otherwize the stand-alone 'objdump -d' will not
+ work. */
+ if (proc_desc)
+ {
+ if (pc_is_mips16 (PROC_LOW_ADDR (proc_desc)))
+ info->mach = bfd_mach_mips16;
+ }
+ else
+ {
+ if (pc_is_mips16 (memaddr))
+ info->mach = bfd_mach_mips16;
+ }
+
+ /* Round down the instruction address to the appropriate boundary. */
+ memaddr &= (info->mach == bfd_mach_mips16 ? ~1 : ~3);
+
+ /* Set the disassembler options. */
+ if (tdep->mips_abi == MIPS_ABI_N32 || tdep->mips_abi == MIPS_ABI_N64)
+ {
+ /* Set up the disassembler info, so that we get the right
+ register names from libopcodes. */
+ if (tdep->mips_abi == MIPS_ABI_N32)
+ info->disassembler_options = "gpr-names=n32";
+ else
+ info->disassembler_options = "gpr-names=64";
+ info->flavour = bfd_target_elf_flavour;
+ }
+ else
+ /* This string is not recognized explicitly by the disassembler,
+ but it tells the disassembler to not try to guess the ABI from
+ the bfd elf headers, such that, if the user overrides the ABI
+ of a program linked as NewABI, the disassembly will follow the
+ register naming conventions specified by the user. */
+ info->disassembler_options = "gpr-names=32";
+
+ /* Call the appropriate disassembler based on the target endian-ness. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return print_insn_big_mips (memaddr, info);
+ else
+ return print_insn_little_mips (memaddr, info);
+}
+
+/* This function implements the BREAKPOINT_FROM_PC macro. It uses the program
+ counter value to determine whether a 16- or 32-bit breakpoint should be
+ used. It returns a pointer to a string of bytes that encode a breakpoint
+ instruction, stores the length of the string to *lenptr, and adjusts pc
+ (if necessary) to point to the actual memory location where the
+ breakpoint should be inserted. */
+
+static const unsigned char *
+mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (pc_is_mips16 (*pcptr))
+ {
+ static unsigned char mips16_big_breakpoint[] = { 0xe8, 0xa5 };
+ *pcptr = unmake_mips16_addr (*pcptr);
+ *lenptr = sizeof (mips16_big_breakpoint);
+ return mips16_big_breakpoint;
+ }
+ else
+ {
+ /* The IDT board uses an unusual breakpoint value, and
+ sometimes gets confused when it sees the usual MIPS
+ breakpoint instruction. */
+ static unsigned char big_breakpoint[] = { 0, 0x5, 0, 0xd };
+ static unsigned char pmon_big_breakpoint[] = { 0, 0, 0, 0xd };
+ static unsigned char idt_big_breakpoint[] = { 0, 0, 0x0a, 0xd };
+
+ *lenptr = sizeof (big_breakpoint);
+
+ if (strcmp (target_shortname, "mips") == 0)
+ return idt_big_breakpoint;
+ else if (strcmp (target_shortname, "ddb") == 0
+ || strcmp (target_shortname, "pmon") == 0
+ || strcmp (target_shortname, "lsi") == 0)
+ return pmon_big_breakpoint;
+ else
+ return big_breakpoint;
+ }
+ }
+ else
+ {
+ if (pc_is_mips16 (*pcptr))
+ {
+ static unsigned char mips16_little_breakpoint[] = { 0xa5, 0xe8 };
+ *pcptr = unmake_mips16_addr (*pcptr);
+ *lenptr = sizeof (mips16_little_breakpoint);
+ return mips16_little_breakpoint;
+ }
+ else
+ {
+ static unsigned char little_breakpoint[] = { 0xd, 0, 0x5, 0 };
+ static unsigned char pmon_little_breakpoint[] = { 0xd, 0, 0, 0 };
+ static unsigned char idt_little_breakpoint[] = { 0xd, 0x0a, 0, 0 };
+
+ *lenptr = sizeof (little_breakpoint);
+
+ if (strcmp (target_shortname, "mips") == 0)
+ return idt_little_breakpoint;
+ else if (strcmp (target_shortname, "ddb") == 0
+ || strcmp (target_shortname, "pmon") == 0
+ || strcmp (target_shortname, "lsi") == 0)
+ return pmon_little_breakpoint;
+ else
+ return little_breakpoint;
+ }
+ }
+}
+
+/* If PC is in a mips16 call or return stub, return the address of the target
+ PC, which is either the callee or the caller. There are several
+ cases which must be handled:
+
+ * If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
+ target PC is in $31 ($ra).
+ * If the PC is in __mips16_call_stub_{1..10}, this is a call stub
+ and the target PC is in $2.
+ * If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub
+ and the the target PC is in $2. Otherwise this is effectively
+ a return stub and the target PC is in $18.
+
+ See the source code for the stubs in gcc/config/mips/mips16.S for
+ gory details.
+
+ This function implements the SKIP_TRAMPOLINE_CODE macro.
+ */
+
+static CORE_ADDR
+mips_skip_stub (CORE_ADDR pc)
+{
+ char *name;
+ CORE_ADDR start_addr;
+
+ /* Find the starting address and name of the function containing the PC. */
+ if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
+ target PC is in $31 ($ra). */
+ if (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0)
+ return read_signed_register (RA_REGNUM);
+
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0)
+ {
+ /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub
+ and the target PC is in $2. */
+ if (name[19] >= '0' && name[19] <= '9')
+ return read_signed_register (2);
+
+ /* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub
+ and the the target PC is in $2. Otherwise this is effectively
+ a return stub and the target PC is in $18. */
+ else if (name[19] == 's' || name[19] == 'd')
+ {
+ if (pc == start_addr)
+ {
+ /* Check if the target of the stub is a compiler-generated
+ stub. Such a stub for a function bar might have a name
+ like __fn_stub_bar, and might look like this:
+ mfc1 $4,$f13
+ mfc1 $5,$f12
+ mfc1 $6,$f15
+ mfc1 $7,$f14
+ la $1,bar (becomes a lui/addiu pair)
+ jr $1
+ So scan down to the lui/addi and extract the target
+ address from those two instructions. */
+
+ CORE_ADDR target_pc = read_signed_register (2);
+ t_inst inst;
+ int i;
+
+ /* See if the name of the target function is __fn_stub_*. */
+ if (find_pc_partial_function (target_pc, &name, NULL, NULL) ==
+ 0)
+ return target_pc;
+ if (strncmp (name, "__fn_stub_", 10) != 0
+ && strcmp (name, "etext") != 0
+ && strcmp (name, "_etext") != 0)
+ return target_pc;
+
+ /* Scan through this _fn_stub_ code for the lui/addiu pair.
+ The limit on the search is arbitrarily set to 20
+ instructions. FIXME. */
+ for (i = 0, pc = 0; i < 20; i++, target_pc += MIPS_INSTLEN)
+ {
+ inst = mips_fetch_instruction (target_pc);
+ if ((inst & 0xffff0000) == 0x3c010000) /* lui $at */
+ pc = (inst << 16) & 0xffff0000; /* high word */
+ else if ((inst & 0xffff0000) == 0x24210000) /* addiu $at */
+ return pc | (inst & 0xffff); /* low word */
+ }
+
+ /* Couldn't find the lui/addui pair, so return stub address. */
+ return target_pc;
+ }
+ else
+ /* This is the 'return' part of a call stub. The return
+ address is in $r18. */
+ return read_signed_register (18);
+ }
+ }
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is inside a call thunk (aka stub or trampoline).
+ This implements the IN_SOLIB_CALL_TRAMPOLINE macro. */
+
+static int
+mips_in_call_stub (CORE_ADDR pc, char *name)
+{
+ CORE_ADDR start_addr;
+
+ /* Find the starting address of the function containing the PC. If the
+ caller didn't give us a name, look it up at the same time. */
+ if (find_pc_partial_function (pc, name ? NULL : &name, &start_addr, NULL) ==
+ 0)
+ return 0;
+
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0)
+ {
+ /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub. */
+ if (name[19] >= '0' && name[19] <= '9')
+ return 1;
+ /* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub. */
+ else if (name[19] == 's' || name[19] == 'd')
+ return pc == start_addr;
+ }
+
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is inside a return thunk (aka stub or trampoline).
+ This implements the IN_SOLIB_RETURN_TRAMPOLINE macro. */
+
+static int
+mips_in_return_stub (CORE_ADDR pc, char *name)
+{
+ CORE_ADDR start_addr;
+
+ /* Find the starting address of the function containing the PC. */
+ if (find_pc_partial_function (pc, NULL, &start_addr, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a return stub. */
+ if (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0)
+ return 1;
+
+ /* If the PC is in __mips16_call_stub_{s,d}f_{0..10} but not at the start,
+ i.e. after the jal instruction, this is effectively a return stub. */
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0
+ && (name[19] == 's' || name[19] == 'd') && pc != start_addr)
+ return 1;
+
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is in a library helper function that should
+ be ignored. This implements the IGNORE_HELPER_CALL macro. */
+
+int
+mips_ignore_helper (CORE_ADDR pc)
+{
+ char *name;
+
+ /* Find the starting address and name of the function containing the PC. */
+ if (find_pc_partial_function (pc, &name, NULL, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a library helper function
+ that we want to ignore. */
+ return (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0);
+}
+
+
+/* Convert a dbx stab register number (from `r' declaration) to a GDB
+ [1 * NUM_REGS .. 2 * NUM_REGS) REGNUM. */
+
+static int
+mips_stab_reg_to_regnum (int num)
+{
+ int regnum;
+ if (num >= 0 && num < 32)
+ regnum = num;
+ else if (num >= 38 && num < 70)
+ regnum = num + mips_regnum (current_gdbarch)->fp0 - 38;
+ else if (num == 70)
+ regnum = mips_regnum (current_gdbarch)->hi;
+ else if (num == 71)
+ regnum = mips_regnum (current_gdbarch)->lo;
+ else
+ /* This will hopefully (eventually) provoke a warning. Should
+ we be calling complaint() here? */
+ return NUM_REGS + NUM_PSEUDO_REGS;
+ return NUM_REGS + regnum;
+}
+
+
+/* Convert a dwarf, dwarf2, or ecoff register number to a GDB [1 *
+ NUM_REGS .. 2 * NUM_REGS) REGNUM. */
+
+static int
+mips_dwarf_dwarf2_ecoff_reg_to_regnum (int num)
+{
+ int regnum;
+ if (num >= 0 && num < 32)
+ regnum = num;
+ else if (num >= 32 && num < 64)
+ regnum = num + mips_regnum (current_gdbarch)->fp0 - 32;
+ else if (num == 64)
+ regnum = mips_regnum (current_gdbarch)->hi;
+ else if (num == 65)
+ regnum = mips_regnum (current_gdbarch)->lo;
+ else
+ /* This will hopefully (eventually) provoke a warning. Should we
+ be calling complaint() here? */
+ return NUM_REGS + NUM_PSEUDO_REGS;
+ return NUM_REGS + regnum;
+}
+
+static int
+mips_register_sim_regno (int regnum)
+{
+ /* Only makes sense to supply raw registers. */
+ gdb_assert (regnum >= 0 && regnum < NUM_REGS);
+ /* FIXME: cagney/2002-05-13: Need to look at the pseudo register to
+ decide if it is valid. Should instead define a standard sim/gdb
+ register numbering scheme. */
+ if (REGISTER_NAME (NUM_REGS + regnum) != NULL
+ && REGISTER_NAME (NUM_REGS + regnum)[0] != '\0')
+ return regnum;
+ else
+ return LEGACY_SIM_REGNO_IGNORE;
+}
+
+
+/* Convert an integer into an address. By first converting the value
+ into a pointer and then extracting it signed, the address is
+ guarenteed to be correctly sign extended. */
+
+static CORE_ADDR
+mips_integer_to_address (struct type *type, void *buf)
+{
+ char *tmp = alloca (TYPE_LENGTH (builtin_type_void_data_ptr));
+ LONGEST val = unpack_long (type, buf);
+ store_signed_integer (tmp, TYPE_LENGTH (builtin_type_void_data_ptr), val);
+ return extract_signed_integer (tmp,
+ TYPE_LENGTH (builtin_type_void_data_ptr));
+}
+
+static void
+mips_find_abi_section (bfd *abfd, asection *sect, void *obj)
+{
+ enum mips_abi *abip = (enum mips_abi *) obj;
+ const char *name = bfd_get_section_name (abfd, sect);
+
+ if (*abip != MIPS_ABI_UNKNOWN)
+ return;
+
+ if (strncmp (name, ".mdebug.", 8) != 0)
+ return;
+
+ if (strcmp (name, ".mdebug.abi32") == 0)
+ *abip = MIPS_ABI_O32;
+ else if (strcmp (name, ".mdebug.abiN32") == 0)
+ *abip = MIPS_ABI_N32;
+ else if (strcmp (name, ".mdebug.abi64") == 0)
+ *abip = MIPS_ABI_N64;
+ else if (strcmp (name, ".mdebug.abiO64") == 0)
+ *abip = MIPS_ABI_O64;
+ else if (strcmp (name, ".mdebug.eabi32") == 0)
+ *abip = MIPS_ABI_EABI32;
+ else if (strcmp (name, ".mdebug.eabi64") == 0)
+ *abip = MIPS_ABI_EABI64;
+ else
+ warning ("unsupported ABI %s.", name + 8);
+}
+
+static enum mips_abi
+global_mips_abi (void)
+{
+ int i;
+
+ for (i = 0; mips_abi_strings[i] != NULL; i++)
+ if (mips_abi_strings[i] == mips_abi_string)
+ return (enum mips_abi) i;
+
+ internal_error (__FILE__, __LINE__, "unknown ABI string");
+}
+
+static struct gdbarch *
+mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ int elf_flags;
+ enum mips_abi mips_abi, found_abi, wanted_abi;
+ int num_regs;
+ enum mips_fpu_type fpu_type;
+
+ /* First of all, extract the elf_flags, if available. */
+ if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+ elf_flags = elf_elfheader (info.abfd)->e_flags;
+ else if (arches != NULL)
+ elf_flags = gdbarch_tdep (arches->gdbarch)->elf_flags;
+ else
+ elf_flags = 0;
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: elf_flags = 0x%08x\n", elf_flags);
+
+ /* Check ELF_FLAGS to see if it specifies the ABI being used. */
+ switch ((elf_flags & EF_MIPS_ABI))
+ {
+ case E_MIPS_ABI_O32:
+ found_abi = MIPS_ABI_O32;
+ break;
+ case E_MIPS_ABI_O64:
+ found_abi = MIPS_ABI_O64;
+ break;
+ case E_MIPS_ABI_EABI32:
+ found_abi = MIPS_ABI_EABI32;
+ break;
+ case E_MIPS_ABI_EABI64:
+ found_abi = MIPS_ABI_EABI64;
+ break;
+ default:
+ if ((elf_flags & EF_MIPS_ABI2))
+ found_abi = MIPS_ABI_N32;
+ else
+ found_abi = MIPS_ABI_UNKNOWN;
+ break;
+ }
+
+ /* GCC creates a pseudo-section whose name describes the ABI. */
+ if (found_abi == MIPS_ABI_UNKNOWN && info.abfd != NULL)
+ bfd_map_over_sections (info.abfd, mips_find_abi_section, &found_abi);
+
+ /* If we have no usefu BFD information, use the ABI from the last
+ MIPS architecture (if there is one). */
+ if (found_abi == MIPS_ABI_UNKNOWN && info.abfd == NULL && arches != NULL)
+ found_abi = gdbarch_tdep (arches->gdbarch)->found_abi;
+
+ /* Try the architecture for any hint of the correct ABI. */
+ if (found_abi == MIPS_ABI_UNKNOWN
+ && info.bfd_arch_info != NULL
+ && info.bfd_arch_info->arch == bfd_arch_mips)
+ {
+ switch (info.bfd_arch_info->mach)
+ {
+ case bfd_mach_mips3900:
+ found_abi = MIPS_ABI_EABI32;
+ break;
+ case bfd_mach_mips4100:
+ case bfd_mach_mips5000:
+ found_abi = MIPS_ABI_EABI64;
+ break;
+ case bfd_mach_mips8000:
+ case bfd_mach_mips10000:
+ /* On Irix, ELF64 executables use the N64 ABI. The
+ pseudo-sections which describe the ABI aren't present
+ on IRIX. (Even for executables created by gcc.) */
+ if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour
+ && elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+ found_abi = MIPS_ABI_N64;
+ else
+ found_abi = MIPS_ABI_N32;
+ break;
+ }
+ }
+
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: found_abi = %d\n",
+ found_abi);
+
+ /* What has the user specified from the command line? */
+ wanted_abi = global_mips_abi ();
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: wanted_abi = %d\n",
+ wanted_abi);
+
+ /* Now that we have found what the ABI for this binary would be,
+ check whether the user is overriding it. */
+ if (wanted_abi != MIPS_ABI_UNKNOWN)
+ mips_abi = wanted_abi;
+ else if (found_abi != MIPS_ABI_UNKNOWN)
+ mips_abi = found_abi;
+ else
+ mips_abi = MIPS_ABI_O32;
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: mips_abi = %d\n",
+ mips_abi);
+
+ /* Also used when doing an architecture lookup. */
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: mips64_transfers_32bit_regs_p = %d\n",
+ mips64_transfers_32bit_regs_p);
+
+ /* Determine the MIPS FPU type. */
+ if (!mips_fpu_type_auto)
+ fpu_type = mips_fpu_type;
+ else if (info.bfd_arch_info != NULL
+ && info.bfd_arch_info->arch == bfd_arch_mips)
+ switch (info.bfd_arch_info->mach)
+ {
+ case bfd_mach_mips3900:
+ case bfd_mach_mips4100:
+ case bfd_mach_mips4111:
+ fpu_type = MIPS_FPU_NONE;
+ break;
+ case bfd_mach_mips4650:
+ fpu_type = MIPS_FPU_SINGLE;
+ break;
+ default:
+ fpu_type = MIPS_FPU_DOUBLE;
+ break;
+ }
+ else if (arches != NULL)
+ fpu_type = gdbarch_tdep (arches->gdbarch)->mips_fpu_type;
+ else
+ fpu_type = MIPS_FPU_DOUBLE;
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: fpu_type = %d\n", fpu_type);
+
+ /* try to find a pre-existing architecture */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* MIPS needs to be pedantic about which ABI the object is
+ using. */
+ if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+ continue;
+ if (gdbarch_tdep (arches->gdbarch)->mips_abi != mips_abi)
+ continue;
+ /* Need to be pedantic about which register virtual size is
+ used. */
+ if (gdbarch_tdep (arches->gdbarch)->mips64_transfers_32bit_regs_p
+ != mips64_transfers_32bit_regs_p)
+ continue;
+ /* Be pedantic about which FPU is selected. */
+ if (gdbarch_tdep (arches->gdbarch)->mips_fpu_type != fpu_type)
+ continue;
+ return arches->gdbarch;
+ }
+
+ /* Need a new architecture. Fill in a target specific vector. */
+ tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->elf_flags = elf_flags;
+ tdep->mips64_transfers_32bit_regs_p = mips64_transfers_32bit_regs_p;
+ tdep->found_abi = found_abi;
+ tdep->mips_abi = mips_abi;
+ tdep->mips_fpu_type = fpu_type;
+
+ /* Initially set everything according to the default ABI/ISA. */
+ set_gdbarch_short_bit (gdbarch, 16);
+ set_gdbarch_int_bit (gdbarch, 32);
+ set_gdbarch_float_bit (gdbarch, 32);
+ set_gdbarch_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ set_gdbarch_register_reggroup_p (gdbarch, mips_register_reggroup_p);
+ set_gdbarch_pseudo_register_read (gdbarch, mips_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, mips_pseudo_register_write);
+
+ set_gdbarch_elf_make_msymbol_special (gdbarch,
+ mips_elf_make_msymbol_special);
+
+ /* Fill in the OS dependant register numbers and names. */
+ {
+ const char **reg_names;
+ struct mips_regnum *regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch,
+ struct mips_regnum);
+ if (info.osabi == GDB_OSABI_IRIX)
+ {
+ regnum->fp0 = 32;
+ regnum->pc = 64;
+ regnum->cause = 65;
+ regnum->badvaddr = 66;
+ regnum->hi = 67;
+ regnum->lo = 68;
+ regnum->fp_control_status = 69;
+ regnum->fp_implementation_revision = 70;
+ num_regs = 71;
+ reg_names = mips_irix_reg_names;
+ }
+ else
+ {
+ regnum->lo = MIPS_EMBED_LO_REGNUM;
+ regnum->hi = MIPS_EMBED_HI_REGNUM;
+ regnum->badvaddr = MIPS_EMBED_BADVADDR_REGNUM;
+ regnum->cause = MIPS_EMBED_CAUSE_REGNUM;
+ regnum->pc = MIPS_EMBED_PC_REGNUM;
+ regnum->fp0 = MIPS_EMBED_FP0_REGNUM;
+ regnum->fp_control_status = 70;
+ regnum->fp_implementation_revision = 71;
+ num_regs = 90;
+ if (info.bfd_arch_info != NULL
+ && info.bfd_arch_info->mach == bfd_mach_mips3900)
+ reg_names = mips_tx39_reg_names;
+ else
+ reg_names = mips_generic_reg_names;
+ }
+ /* FIXME: cagney/2003-11-15: For MIPS, hasn't PC_REGNUM been
+ replaced by read_pc? */
+ set_gdbarch_pc_regnum (gdbarch, regnum->pc);
+ set_gdbarch_fp0_regnum (gdbarch, regnum->fp0);
+ set_gdbarch_num_regs (gdbarch, num_regs);
+ set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
+ set_gdbarch_register_name (gdbarch, mips_register_name);
+ tdep->mips_processor_reg_names = reg_names;
+ tdep->regnum = regnum;
+ }
+
+ switch (mips_abi)
+ {
+ case MIPS_ABI_O32:
+ set_gdbarch_push_dummy_call (gdbarch, mips_o32_push_dummy_call);
+ set_gdbarch_return_value (gdbarch, mips_o32_return_value);
+ tdep->mips_default_saved_regsize = 4;
+ tdep->mips_default_stack_argsize = 4;
+ tdep->mips_fp_register_double = 0;
+ tdep->mips_last_arg_regnum = A0_REGNUM + 4 - 1;
+ tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 4 - 1;
+ tdep->default_mask_address_p = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case MIPS_ABI_O64:
+ set_gdbarch_push_dummy_call (gdbarch, mips_o64_push_dummy_call);
+ set_gdbarch_deprecated_store_return_value (gdbarch,
+ mips_o64_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch,
+ mips_o64_extract_return_value);
+ tdep->mips_default_saved_regsize = 8;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
+ tdep->mips_last_arg_regnum = A0_REGNUM + 4 - 1;
+ tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 4 - 1;
+ tdep->default_mask_address_p = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_use_struct_convention (gdbarch,
+ always_use_struct_convention);
+ break;
+ case MIPS_ABI_EABI32:
+ set_gdbarch_push_dummy_call (gdbarch, mips_eabi_push_dummy_call);
+ set_gdbarch_deprecated_store_return_value (gdbarch,
+ mips_eabi_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch,
+ mips_eabi_extract_return_value);
+ tdep->mips_default_saved_regsize = 4;
+ tdep->mips_default_stack_argsize = 4;
+ tdep->mips_fp_register_double = 0;
+ tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
+ tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
+ tdep->default_mask_address_p = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_deprecated_reg_struct_has_addr
+ (gdbarch, mips_eabi_reg_struct_has_addr);
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_eabi_use_struct_convention);
+ break;
+ case MIPS_ABI_EABI64:
+ set_gdbarch_push_dummy_call (gdbarch, mips_eabi_push_dummy_call);
+ set_gdbarch_deprecated_store_return_value (gdbarch,
+ mips_eabi_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch,
+ mips_eabi_extract_return_value);
+ tdep->mips_default_saved_regsize = 8;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
+ tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
+ tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
+ tdep->default_mask_address_p = 0;
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_deprecated_reg_struct_has_addr
+ (gdbarch, mips_eabi_reg_struct_has_addr);
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_eabi_use_struct_convention);
+ break;
+ case MIPS_ABI_N32:
+ set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
+ set_gdbarch_return_value (gdbarch, mips_n32n64_return_value);
+ tdep->mips_default_saved_regsize = 8;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
+ tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
+ tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
+ tdep->default_mask_address_p = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case MIPS_ABI_N64:
+ set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
+ set_gdbarch_return_value (gdbarch, mips_n32n64_return_value);
+ tdep->mips_default_saved_regsize = 8;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
+ tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
+ tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
+ tdep->default_mask_address_p = 0;
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "unknown ABI in switch");
+ }
+
+ /* FIXME: jlarmour/2000-04-07: There *is* a flag EF_MIPS_32BIT_MODE
+ that could indicate -gp32 BUT gas/config/tc-mips.c contains the
+ comment:
+
+ ``We deliberately don't allow "-gp32" to set the MIPS_32BITMODE
+ flag in object files because to do so would make it impossible to
+ link with libraries compiled without "-gp32". This is
+ unnecessarily restrictive.
+
+ We could solve this problem by adding "-gp32" multilibs to gcc,
+ but to set this flag before gcc is built with such multilibs will
+ break too many systems.''
+
+ But even more unhelpfully, the default linker output target for
+ mips64-elf is elf32-bigmips, and has EF_MIPS_32BIT_MODE set, even
+ for 64-bit programs - you need to change the ABI to change this,
+ and not all gcc targets support that currently. Therefore using
+ this flag to detect 32-bit mode would do the wrong thing given
+ the current gcc - it would make GDB treat these 64-bit programs
+ as 32-bit programs by default. */
+
+ set_gdbarch_read_pc (gdbarch, mips_read_pc);
+ set_gdbarch_write_pc (gdbarch, mips_write_pc);
+ set_gdbarch_read_sp (gdbarch, mips_read_sp);
+
+ /* Add/remove bits from an address. The MIPS needs be careful to
+ ensure that all 32 bit addresses are sign extended to 64 bits. */
+ set_gdbarch_addr_bits_remove (gdbarch, mips_addr_bits_remove);
+
+ /* Unwind the frame. */
+ set_gdbarch_unwind_pc (gdbarch, mips_unwind_pc);
+ frame_unwind_append_sniffer (gdbarch, mips_mdebug_frame_sniffer);
+ set_gdbarch_unwind_dummy_id (gdbarch, mips_unwind_dummy_id);
+ frame_base_append_sniffer (gdbarch, mips_mdebug_frame_base_sniffer);
+
+ /* Map debug register numbers onto internal register numbers. */
+ set_gdbarch_stab_reg_to_regnum (gdbarch, mips_stab_reg_to_regnum);
+ set_gdbarch_ecoff_reg_to_regnum (gdbarch,
+ mips_dwarf_dwarf2_ecoff_reg_to_regnum);
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch,
+ mips_dwarf_dwarf2_ecoff_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch,
+ mips_dwarf_dwarf2_ecoff_reg_to_regnum);
+ set_gdbarch_register_sim_regno (gdbarch, mips_register_sim_regno);
+
+ /* MIPS version of CALL_DUMMY */
+
+ /* NOTE: cagney/2003-08-05: Eventually call dummy location will be
+ replaced by a command, and all targets will default to on stack
+ (regardless of the stack's execute status). */
+ set_gdbarch_call_dummy_location (gdbarch, AT_SYMBOL);
+ set_gdbarch_frame_align (gdbarch, mips_frame_align);
+
+ set_gdbarch_convert_register_p (gdbarch, mips_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, mips_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, mips_value_to_register);
+
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_breakpoint_from_pc (gdbarch, mips_breakpoint_from_pc);
+
+ set_gdbarch_skip_prologue (gdbarch, mips_skip_prologue);
+
+ set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address);
+ set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer);
+ set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address);
+
+ set_gdbarch_register_type (gdbarch, mips_register_type);
+
+ set_gdbarch_print_registers_info (gdbarch, mips_print_registers_info);
+ set_gdbarch_pc_in_sigtramp (gdbarch, mips_pc_in_sigtramp);
+
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips);
+
+ /* FIXME: cagney/2003-08-29: The macros HAVE_STEPPABLE_WATCHPOINT,
+ HAVE_NONSTEPPABLE_WATCHPOINT, and HAVE_CONTINUABLE_WATCHPOINT
+ need to all be folded into the target vector. Since they are
+ being used as guards for STOPPED_BY_WATCHPOINT, why not have
+ STOPPED_BY_WATCHPOINT return the type of watchpoint that the code
+ is sitting on? */
+ set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
+ set_gdbarch_skip_trampoline_code (gdbarch, mips_skip_stub);
+
+ /* NOTE drow/2004-02-11: We overload the core solib trampoline code
+ to support MIPS16. This is a bad thing. Make sure not to do it
+ if we have an OS ABI that actually supports shared libraries, since
+ shared library support is more important. If we have an OS someday
+ that supports both shared libraries and MIPS16, we'll have to find
+ a better place for these. */
+ if (info.osabi == GDB_OSABI_UNKNOWN)
+ {
+ set_gdbarch_in_solib_call_trampoline (gdbarch, mips_in_call_stub);
+ set_gdbarch_in_solib_return_trampoline (gdbarch, mips_in_return_stub);
+ }
+
+ /* Hook in OS ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ return gdbarch;
+}
+
+static void
+mips_abi_update (char *ignore_args, int from_tty, struct cmd_list_element *c)
+{
+ struct gdbarch_info info;
+
+ /* Force the architecture to update, and (if it's a MIPS architecture)
+ mips_gdbarch_init will take care of the rest. */
+ gdbarch_info_init (&info);
+ gdbarch_update_p (info);
+}
+
+/* Print out which MIPS ABI is in use. */
+
+static void
+show_mips_abi (char *ignore_args, int from_tty)
+{
+ if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+ printf_filtered
+ ("The MIPS ABI is unknown because the current architecture is not MIPS.\n");
+ else
+ {
+ enum mips_abi global_abi = global_mips_abi ();
+ enum mips_abi actual_abi = mips_abi (current_gdbarch);
+ const char *actual_abi_str = mips_abi_strings[actual_abi];
+
+ if (global_abi == MIPS_ABI_UNKNOWN)
+ printf_filtered
+ ("The MIPS ABI is set automatically (currently \"%s\").\n",
+ actual_abi_str);
+ else if (global_abi == actual_abi)
+ printf_filtered
+ ("The MIPS ABI is assumed to be \"%s\" (due to user setting).\n",
+ actual_abi_str);
+ else
+ {
+ /* Probably shouldn't happen... */
+ printf_filtered
+ ("The (auto detected) MIPS ABI \"%s\" is in use even though the user setting was \"%s\".\n",
+ actual_abi_str, mips_abi_strings[global_abi]);
+ }
+ }
+}
+
+static void
+mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (tdep != NULL)
+ {
+ int ef_mips_arch;
+ int ef_mips_32bitmode;
+ /* determine the ISA */
+ switch (tdep->elf_flags & EF_MIPS_ARCH)
+ {
+ case E_MIPS_ARCH_1:
+ ef_mips_arch = 1;
+ break;
+ case E_MIPS_ARCH_2:
+ ef_mips_arch = 2;
+ break;
+ case E_MIPS_ARCH_3:
+ ef_mips_arch = 3;
+ break;
+ case E_MIPS_ARCH_4:
+ ef_mips_arch = 4;
+ break;
+ default:
+ ef_mips_arch = 0;
+ break;
+ }
+ /* determine the size of a pointer */
+ ef_mips_32bitmode = (tdep->elf_flags & EF_MIPS_32BITMODE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: tdep->elf_flags = 0x%x\n",
+ tdep->elf_flags);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: ef_mips_32bitmode = %d\n",
+ ef_mips_32bitmode);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: ef_mips_arch = %d\n",
+ ef_mips_arch);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: tdep->mips_abi = %d (%s)\n",
+ tdep->mips_abi, mips_abi_strings[tdep->mips_abi]);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: mips_mask_address_p() %d (default %d)\n",
+ mips_mask_address_p (tdep),
+ tdep->default_mask_address_p);
+ }
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: FP_REGISTER_DOUBLE = %d\n",
+ FP_REGISTER_DOUBLE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_DEFAULT_FPU_TYPE = %d (%s)\n",
+ MIPS_DEFAULT_FPU_TYPE,
+ (MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_NONE ? "none"
+ : MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
+ : MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
+ : "???"));
+ fprintf_unfiltered (file, "mips_dump_tdep: MIPS_EABI = %d\n", MIPS_EABI);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_FPU_TYPE = %d (%s)\n",
+ MIPS_FPU_TYPE,
+ (MIPS_FPU_TYPE == MIPS_FPU_NONE ? "none"
+ : MIPS_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
+ : MIPS_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
+ : "???"));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: FP_REGISTER_DOUBLE = %d\n",
+ FP_REGISTER_DOUBLE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: mips_stack_argsize() = %d\n",
+ mips_stack_argsize (tdep));
+ fprintf_unfiltered (file, "mips_dump_tdep: A0_REGNUM = %d\n", A0_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: ADDR_BITS_REMOVE # %s\n",
+ XSTRING (ADDR_BITS_REMOVE (ADDR)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: ATTACH_DETACH # %s\n",
+ XSTRING (ATTACH_DETACH));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: DWARF_REG_TO_REGNUM # %s\n",
+ XSTRING (DWARF_REG_TO_REGNUM (REGNUM)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: ECOFF_REG_TO_REGNUM # %s\n",
+ XSTRING (ECOFF_REG_TO_REGNUM (REGNUM)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: FIRST_EMBED_REGNUM = %d\n",
+ FIRST_EMBED_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: IGNORE_HELPER_CALL # %s\n",
+ XSTRING (IGNORE_HELPER_CALL (PC)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: IN_SOLIB_CALL_TRAMPOLINE # %s\n",
+ XSTRING (IN_SOLIB_CALL_TRAMPOLINE (PC, NAME)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: IN_SOLIB_RETURN_TRAMPOLINE # %s\n",
+ XSTRING (IN_SOLIB_RETURN_TRAMPOLINE (PC, NAME)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: LAST_EMBED_REGNUM = %d\n",
+ LAST_EMBED_REGNUM);
+#ifdef MACHINE_CPROC_FP_OFFSET
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MACHINE_CPROC_FP_OFFSET = %d\n",
+ MACHINE_CPROC_FP_OFFSET);
+#endif
+#ifdef MACHINE_CPROC_PC_OFFSET
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MACHINE_CPROC_PC_OFFSET = %d\n",
+ MACHINE_CPROC_PC_OFFSET);
+#endif
+#ifdef MACHINE_CPROC_SP_OFFSET
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MACHINE_CPROC_SP_OFFSET = %d\n",
+ MACHINE_CPROC_SP_OFFSET);
+#endif
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS16_INSTLEN = %d\n",
+ MIPS16_INSTLEN);
+ fprintf_unfiltered (file, "mips_dump_tdep: MIPS_DEFAULT_ABI = FIXME!\n");
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_EFI_SYMBOL_NAME = multi-arch!!\n");
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_INSTLEN = %d\n", MIPS_INSTLEN);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_LAST_ARG_REGNUM = %d (%d regs)\n",
+ MIPS_LAST_ARG_REGNUM,
+ MIPS_LAST_ARG_REGNUM - A0_REGNUM + 1);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_NUMREGS = %d\n", MIPS_NUMREGS);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: mips_saved_regsize() = %d\n",
+ mips_saved_regsize (tdep));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: PRID_REGNUM = %d\n", PRID_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: PROC_DESC_IS_DUMMY = function?\n");
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: PROC_FRAME_ADJUST = function?\n");
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: PROC_FRAME_OFFSET = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_FRAME_REG = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_FREG_MASK = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_FREG_OFFSET = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_HIGH_ADDR = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_LOW_ADDR = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_PC_REG = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_REG_MASK = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_REG_OFFSET = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PROC_SYMBOL = function?\n");
+ fprintf_unfiltered (file, "mips_dump_tdep: PS_REGNUM = %d\n", PS_REGNUM);
+ fprintf_unfiltered (file, "mips_dump_tdep: RA_REGNUM = %d\n", RA_REGNUM);
+#ifdef SAVED_BYTES
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: SAVED_BYTES = %d\n", SAVED_BYTES);
+#endif
+#ifdef SAVED_FP
+ fprintf_unfiltered (file, "mips_dump_tdep: SAVED_FP = %d\n", SAVED_FP);
+#endif
+#ifdef SAVED_PC
+ fprintf_unfiltered (file, "mips_dump_tdep: SAVED_PC = %d\n", SAVED_PC);
+#endif
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: SETUP_ARBITRARY_FRAME # %s\n",
+ XSTRING (SETUP_ARBITRARY_FRAME (NUMARGS, ARGS)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: SET_PROC_DESC_IS_DUMMY = function?\n");
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: SKIP_TRAMPOLINE_CODE # %s\n",
+ XSTRING (SKIP_TRAMPOLINE_CODE (PC)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: SOFTWARE_SINGLE_STEP # %s\n",
+ XSTRING (SOFTWARE_SINGLE_STEP (SIG, BP_P)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: SOFTWARE_SINGLE_STEP_P () = %d\n",
+ SOFTWARE_SINGLE_STEP_P ());
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: STAB_REG_TO_REGNUM # %s\n",
+ XSTRING (STAB_REG_TO_REGNUM (REGNUM)));
+#ifdef STACK_END_ADDR
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: STACK_END_ADDR = %d\n",
+ STACK_END_ADDR);
+#endif
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: STEP_SKIPS_DELAY # %s\n",
+ XSTRING (STEP_SKIPS_DELAY (PC)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: STEP_SKIPS_DELAY_P = %d\n",
+ STEP_SKIPS_DELAY_P);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: STOPPED_BY_WATCHPOINT # %s\n",
+ XSTRING (STOPPED_BY_WATCHPOINT (WS)));
+ fprintf_unfiltered (file, "mips_dump_tdep: T9_REGNUM = %d\n", T9_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: TABULAR_REGISTER_OUTPUT = used?\n");
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: TARGET_CAN_USE_HARDWARE_WATCHPOINT # %s\n",
+ XSTRING (TARGET_CAN_USE_HARDWARE_WATCHPOINT
+ (TYPE, CNT, OTHERTYPE)));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: TARGET_HAS_HARDWARE_WATCHPOINTS # %s\n",
+ XSTRING (TARGET_HAS_HARDWARE_WATCHPOINTS));
+#ifdef TRACE_CLEAR
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: TRACE_CLEAR # %s\n",
+ XSTRING (TRACE_CLEAR (THREAD, STATE)));
+#endif
+#ifdef TRACE_FLAVOR
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: TRACE_FLAVOR = %d\n", TRACE_FLAVOR);
+#endif
+#ifdef TRACE_FLAVOR_SIZE
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: TRACE_FLAVOR_SIZE = %d\n",
+ TRACE_FLAVOR_SIZE);
+#endif
+#ifdef TRACE_SET
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: TRACE_SET # %s\n",
+ XSTRING (TRACE_SET (X, STATE)));
+#endif
+#ifdef UNUSED_REGNUM
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: UNUSED_REGNUM = %d\n", UNUSED_REGNUM);
+#endif
+ fprintf_unfiltered (file, "mips_dump_tdep: V0_REGNUM = %d\n", V0_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: VM_MIN_ADDRESS = %ld\n",
+ (long) VM_MIN_ADDRESS);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: ZERO_REGNUM = %d\n", ZERO_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: _PROC_MAGIC_ = %d\n", _PROC_MAGIC_);
+}
+
+extern initialize_file_ftype _initialize_mips_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_mips_tdep (void)
+{
+ static struct cmd_list_element *mipsfpulist = NULL;
+ struct cmd_list_element *c;
+
+ mips_abi_string = mips_abi_strings[MIPS_ABI_UNKNOWN];
+ if (MIPS_ABI_LAST + 1
+ != sizeof (mips_abi_strings) / sizeof (mips_abi_strings[0]))
+ internal_error (__FILE__, __LINE__, "mips_abi_strings out of sync");
+
+ gdbarch_register (bfd_arch_mips, mips_gdbarch_init, mips_dump_tdep);
+
+ mips_pdr_data = register_objfile_data ();
+
+ /* Add root prefix command for all "set mips"/"show mips" commands */
+ add_prefix_cmd ("mips", no_class, set_mips_command,
+ "Various MIPS specific commands.",
+ &setmipscmdlist, "set mips ", 0, &setlist);
+
+ add_prefix_cmd ("mips", no_class, show_mips_command,
+ "Various MIPS specific commands.",
+ &showmipscmdlist, "show mips ", 0, &showlist);
+
+ /* Allow the user to override the saved register size. */
+ add_show_from_set (add_set_enum_cmd ("saved-gpreg-size",
+ class_obscure,
+ size_enums,
+ &mips_saved_regsize_string, "\
+Set size of general purpose registers saved on the stack.\n\
+This option can be set to one of:\n\
+ 32 - Force GDB to treat saved GP registers as 32-bit\n\
+ 64 - Force GDB to treat saved GP registers as 64-bit\n\
+ auto - Allow GDB to use the target's default setting or autodetect the\n\
+ saved GP register size from information contained in the executable.\n\
+ (default: auto)", &setmipscmdlist), &showmipscmdlist);
+
+ /* Allow the user to override the argument stack size. */
+ add_show_from_set (add_set_enum_cmd ("stack-arg-size",
+ class_obscure,
+ size_enums,
+ &mips_stack_argsize_string, "\
+Set the amount of stack space reserved for each argument.\n\
+This option can be set to one of:\n\
+ 32 - Force GDB to allocate 32-bit chunks per argument\n\
+ 64 - Force GDB to allocate 64-bit chunks per argument\n\
+ auto - Allow GDB to determine the correct setting from the current\n\
+ target and executable (default)", &setmipscmdlist), &showmipscmdlist);
+
+ /* Allow the user to override the ABI. */
+ c = add_set_enum_cmd
+ ("abi", class_obscure, mips_abi_strings, &mips_abi_string,
+ "Set the ABI used by this program.\n"
+ "This option can be set to one of:\n"
+ " auto - the default ABI associated with the current binary\n"
+ " o32\n"
+ " o64\n" " n32\n" " n64\n" " eabi32\n" " eabi64", &setmipscmdlist);
+ set_cmd_sfunc (c, mips_abi_update);
+ add_cmd ("abi", class_obscure, show_mips_abi,
+ "Show ABI in use by MIPS target", &showmipscmdlist);
+
+ /* Let the user turn off floating point and set the fence post for
+ heuristic_proc_start. */
+
+ add_prefix_cmd ("mipsfpu", class_support, set_mipsfpu_command,
+ "Set use of MIPS floating-point coprocessor.",
+ &mipsfpulist, "set mipsfpu ", 0, &setlist);
+ add_cmd ("single", class_support, set_mipsfpu_single_command,
+ "Select single-precision MIPS floating-point coprocessor.",
+ &mipsfpulist);
+ add_cmd ("double", class_support, set_mipsfpu_double_command,
+ "Select double-precision MIPS floating-point coprocessor.",
+ &mipsfpulist);
+ add_alias_cmd ("on", "double", class_support, 1, &mipsfpulist);
+ add_alias_cmd ("yes", "double", class_support, 1, &mipsfpulist);
+ add_alias_cmd ("1", "double", class_support, 1, &mipsfpulist);
+ add_cmd ("none", class_support, set_mipsfpu_none_command,
+ "Select no MIPS floating-point coprocessor.", &mipsfpulist);
+ add_alias_cmd ("off", "none", class_support, 1, &mipsfpulist);
+ add_alias_cmd ("no", "none", class_support, 1, &mipsfpulist);
+ add_alias_cmd ("0", "none", class_support, 1, &mipsfpulist);
+ add_cmd ("auto", class_support, set_mipsfpu_auto_command,
+ "Select MIPS floating-point coprocessor automatically.",
+ &mipsfpulist);
+ add_cmd ("mipsfpu", class_support, show_mipsfpu_command,
+ "Show current use of MIPS floating-point coprocessor target.",
+ &showlist);
+
+ /* 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. */
+ set_cmd_sfunc (c, reinit_frame_cache_sfunc);
+ add_show_from_set (c, &showlist);
+
+ /* Allow the user to control whether the upper bits of 64-bit
+ addresses should be zeroed. */
+ add_setshow_auto_boolean_cmd ("mask-address", no_class, &mask_address_var, "\
+Set zeroing of upper 32 bits of 64-bit addresses.\n\
+Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to \n\
+allow GDB to determine the correct value.\n", "\
+Show zeroing of upper 32 bits of 64-bit addresses.",
+ NULL, show_mask_address, &setmipscmdlist, &showmipscmdlist);
+
+ /* Allow the user to control the size of 32 bit registers within the
+ raw remote packet. */
+ add_setshow_cmd ("remote-mips64-transfers-32bit-regs", class_obscure,
+ var_boolean, &mips64_transfers_32bit_regs_p, "\
+Set compatibility with 64-bit MIPS targets that transfer 32-bit quantities.\n\
+Use \"on\" to enable backward compatibility with older MIPS 64 GDB+target\n\
+that would transfer 32 bits for some registers (e.g. SR, FSR) and\n\
+64 bits for others. Use \"off\" to disable compatibility mode", "\
+Show compatibility with 64-bit MIPS targets that transfer 32-bit quantities.\n\
+Use \"on\" to enable backward compatibility with older MIPS 64 GDB+target\n\
+that would transfer 32 bits for some registers (e.g. SR, FSR) and\n\
+64 bits for others. Use \"off\" to disable compatibility mode", set_mips64_transfers_32bit_regs, NULL, &setlist, &showlist);
+
+ /* Debug this files internals. */
+ add_show_from_set (add_set_cmd ("mips", class_maintenance, var_zinteger,
+ &mips_debug, "Set mips debugging.\n\
+When non-zero, mips specific debugging is enabled.", &setdebuglist), &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/mips-tdep.h b/contrib/gdb/gdb/mips-tdep.h
new file mode 100644
index 0000000..af9a3c8
--- /dev/null
+++ b/contrib/gdb/gdb/mips-tdep.h
@@ -0,0 +1,88 @@
+/* Target-dependent header for the MIPS architecture, for GDB, the GNU Debugger.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MIPS_TDEP_H
+#define MIPS_TDEP_H
+
+struct gdbarch;
+
+/* All the possible MIPS ABIs. */
+enum mips_abi
+ {
+ MIPS_ABI_UNKNOWN = 0,
+ MIPS_ABI_N32,
+ MIPS_ABI_O32,
+ MIPS_ABI_N64,
+ MIPS_ABI_O64,
+ MIPS_ABI_EABI32,
+ MIPS_ABI_EABI64,
+ MIPS_ABI_LAST
+ };
+
+/* Return the MIPS ABI associated with GDBARCH. */
+enum mips_abi mips_abi (struct gdbarch *gdbarch);
+
+/* For wince :-(. */
+extern CORE_ADDR mips_next_pc (CORE_ADDR pc);
+
+/* Return the "MIPS" register size. Just a short cut to the BFD
+ architecture's word size. */
+extern int mips_regsize (struct gdbarch *gdbarch);
+
+/* Return the current index for various MIPS registers. */
+struct mips_regnum
+{
+ int pc;
+ int fp0;
+ int fp_implementation_revision;
+ int fp_control_status;
+ int badvaddr; /* Bad vaddr for addressing exception. */
+ int cause; /* Describes last exception. */
+ int hi; /* Multiply/divide temp. */
+ int lo; /* ... */
+};
+extern const struct mips_regnum *mips_regnum (struct gdbarch *gdbarch);
+
+enum {
+ MIPS_S0_REGNUM = 16,
+ MIPS_S1_REGNUM = 17,
+ MIPS_S2_REGNUM = 18,
+ MIPS_S3_REGNUM = 19,
+ MIPS_S4_REGNUM = 20,
+ MIPS_S5_REGNUM = 21,
+ MIPS_S6_REGNUM = 22,
+ MIPS_S7_REGNUM = 23,
+ MIPS_SP_REGNUM = 29,
+ MIPS_FP_REGNUM = 30,
+ MIPS_RA_REGNUM = 31,
+ MIPS_EMBED_LO_REGNUM = 33,
+ MIPS_EMBED_HI_REGNUM = 34,
+ MIPS_EMBED_BADVADDR_REGNUM = 35,
+ MIPS_EMBED_CAUSE_REGNUM = 36,
+ MIPS_EMBED_PC_REGNUM = 37,
+ MIPS_EMBED_FP0_REGNUM = 38
+};
+
+/* Defined in mips-tdep.c and used in remote-mips.c */
+extern void deprecated_mips_set_processor_regs_hack (void);
+
+
+#endif /* MIPS_TDEP_H */
diff --git a/contrib/gdb/gdb/mipsfbsd-nat.c b/contrib/gdb/gdb/mipsfbsd-nat.c
new file mode 100644
index 0000000..8b58971
--- /dev/null
+++ b/contrib/gdb/gdb/mipsfbsd-nat.c
@@ -0,0 +1,108 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Native-dependent code for MIPS systems running NetBSD.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include "mipsfbsd-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+/* Determine if PT_GETREGS fetches this register. */
+static int
+getregs_supplies (int regno)
+{
+ return ((regno) >= ZERO_REGNUM && (regno) <= PC_REGNUM);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ mipsfbsd_supply_reg ((char *) &regs, regno);
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ mipsfbsd_supply_fpreg ((char *) &fpregs, regno);
+ }
+}
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ mipsfbsd_fill_reg ((char *) &regs, regno);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ mipsfbsd_fill_fpreg ((char *) &fpregs, regno);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't write floating point status");
+ }
+}
diff --git a/contrib/gdb/gdb/mipsfbsd-tdep.c b/contrib/gdb/gdb/mipsfbsd-tdep.c
new file mode 100644
index 0000000..0be5d27
--- /dev/null
+++ b/contrib/gdb/gdb/mipsfbsd-tdep.c
@@ -0,0 +1,579 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Target-dependent code for MIPS systems running NetBSD.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include "target.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "nbsd-tdep.h"
+#include "mipsfbsd-tdep.h"
+#include "mips-tdep.h"
+
+#include "solib-svr4.h"
+
+#include <sys/procfs.h>
+#include "gregset.h"
+#include "trad-frame.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "bfd.h"
+#include "objfiles.h"
+
+/* Conveniently, GDB uses the same register numbering as the
+ ptrace register structure used by NetBSD/mips. */
+
+void
+mipsfbsd_supply_reg (char *regs, int regno)
+{
+ int i;
+
+ for (i = 0; i <= PC_REGNUM; i++)
+ {
+ if (regno == i || regno == -1)
+ {
+ if (CANNOT_FETCH_REGISTER (i))
+ supply_register (i, NULL);
+ else
+ supply_register (i, regs + (i * mips_regsize (current_gdbarch)));
+ }
+ }
+}
+void
+supply_gregset (gdb_gregset_t *gregs)
+{
+ mipsfbsd_supply_reg((char *)gregs, -1);
+}
+
+void
+mipsfbsd_fill_reg (char *regs, int regno)
+{
+ int i;
+
+ for (i = 0; i <= PC_REGNUM; i++)
+ if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+ regcache_collect (i, regs + (i * mips_regsize (current_gdbarch)));
+}
+
+void
+fill_gregset (gdb_gregset_t *gregs, int regno)
+{
+ mipsfbsd_fill_reg ((char *)gregs, regno);
+}
+
+void
+mipsfbsd_supply_fpreg (char *fpregs, int regno)
+{
+ int i;
+
+ for (i = FP0_REGNUM;
+ i <= mips_regnum (current_gdbarch)->fp_implementation_revision;
+ i++)
+ {
+ if (regno == i || regno == -1)
+ {
+ if (CANNOT_FETCH_REGISTER (i))
+ supply_register (i, NULL);
+ else
+ supply_register (i,
+ fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
+ }
+ }
+}
+
+void
+supply_fpregset (gdb_fpregset_t *fpregs)
+{
+ mipsfbsd_supply_fpreg((char *)fpregs, -1);
+}
+
+void
+mipsfbsd_fill_fpreg (char *fpregs, int regno)
+{
+ int i;
+
+ for (i = FP0_REGNUM; i <= mips_regnum (current_gdbarch)->fp_control_status;
+ i++)
+ if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+ regcache_collect (i,
+ fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
+}
+
+void
+fill_fpregset (gdb_fpregset_t *fpregs, int regno)
+{
+ mipsfbsd_fill_fpreg ((char *)fpregs, regno);
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ char *regs, *fpregs;
+
+ /* We get everything from one section. */
+ if (which != 0)
+ return;
+
+ regs = core_reg_sect;
+ fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
+
+ /* Integer registers. */
+ mipsfbsd_supply_reg (regs, -1);
+
+ /* Floating point registers. */
+ mipsfbsd_supply_fpreg (fpregs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ switch (which)
+ {
+ case 0: /* Integer registers. */
+ if (core_reg_size != SIZEOF_STRUCT_REG)
+ warning ("Wrong size register set in core file.");
+ else
+ mipsfbsd_supply_reg (core_reg_sect, -1);
+ break;
+
+ case 2: /* Floating point registers. */
+ if (core_reg_size != SIZEOF_STRUCT_FPREG)
+ warning ("Wrong size register set in core file.");
+ else
+ mipsfbsd_supply_fpreg (core_reg_sect, -1);
+ break;
+
+ default:
+ /* Don't know what kind of register request this is; just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns mipsfbsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+
+/*
+ * MIPSFBSD Offsets
+ * 0x7fff0000 User high mem -> USRSTACK [64K]
+ *
+ * 0x7ffefff0 ps_strings -> 16 bytes
+ *
+ * 0x7ffeffec sigcode -> 44 bytes
+ *
+ * 0x7ffeffc4 sigcode end env strings etc start
+ */
+#define MIPS_FBSD_SIGTRAMP_START (0x7ffeffc4)
+#define MIPS_FBSD_SIGTRAMP_END (0x7ffeffec)
+#define MIPS_FBSD_SIGTRAMP_STACK_MOD_START (0x7ffeffc8)
+#define MIPS_FBSD_SIGTRAMP_STACK_MOD_END (0x7ffeffd8)
+
+static LONGEST
+mipsfbsd_sigtramp_offset (CORE_ADDR pc)
+{
+ return pc < MIPS_FBSD_SIGTRAMP_END &&
+ pc >= MIPS_FBSD_SIGTRAMP_START ? 1 : -1;
+}
+
+static int
+fbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ return (name && strcmp (name, "__sigtramp") == 0);
+}
+
+static int
+mipsfbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ return (fbsd_pc_in_sigtramp (pc, func_name)
+ || mipsfbsd_sigtramp_offset (pc) >= 0);
+}
+
+static int
+is_sigtramp_sp_modified (CORE_ADDR pc)
+{
+ return (pc >= MIPS_FBSD_SIGTRAMP_STACK_MOD_START &&
+ pc <= MIPS_FBSD_SIGTRAMP_STACK_MOD_END);
+}
+
+
+/* Figure out where the longjmp will land. We expect that we have
+ just entered longjmp and haven't yet setup the stack frame, so
+ the args are still in the argument regs. A0_REGNUM points at the
+ jmp_buf structure from which we extract the PC that we will land
+ at. The PC is copied into *pc. This routine returns true on
+ success. */
+
+#define FBSD_MIPS_JB_PC (12)
+#define FBSD_MIPS_JB_ELEMENT_SIZE mips_regsize (current_gdbarch)
+#define FBSD_MIPS_JB_OFFSET (FBSD_MIPS_JB_PC * \
+ FBSD_MIPS_JB_ELEMENT_SIZE)
+
+static int
+mipsfbsd_get_longjmp_target (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char *buf;
+
+ buf = alloca (FBSD_MIPS_JB_ELEMENT_SIZE);
+
+ jb_addr = read_register (A0_REGNUM);
+
+ if (target_read_memory (jb_addr + FBSD_MIPS_JB_OFFSET, buf,
+ FBSD_MIPS_JB_ELEMENT_SIZE))
+ return 0;
+
+ *pc = extract_unsigned_integer (buf, FBSD_MIPS_JB_ELEMENT_SIZE);
+
+ return 1;
+}
+
+static int
+mipsfbsd_cannot_fetch_register (int regno)
+{
+ return (regno == ZERO_REGNUM
+ || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
+ /* XXX TODO: Are there other registers that we cannot fetch ? */
+}
+
+static int
+mipsfbsd_cannot_store_register (int regno)
+{
+ return (regno == ZERO_REGNUM
+ || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
+ /* XXX TODO: Are there other registers that we cannot write ? */
+}
+
+/*
+ * This structure is defined in mips-tdep.c.
+ */
+struct mips_frame_cache
+{
+ CORE_ADDR base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/*
+ * Prologue cache for sigtramp frame
+ * When we land in sigtramp, sigcontext is saved on the
+ * stack just below the sigtramp's stack frame. We have
+ * the Registers saved at fixed offsets on the stack.
+ */
+
+#define MIPS_FBSD_SIGTRAMP_STACK_SIZE (48)
+#define MIPS_FBSD_SIGCONTEXT_REG_OFFSET (32)
+
+static struct mips_frame_cache *
+mipsfbsd_sigtramp_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct mips_frame_cache *cache;
+ CORE_ADDR gregs_addr, sp, pc;
+ int regnum;
+ int sigtramp_stack_size;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
+ *this_cache = cache;
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /*
+ * Get sp of next frame which is the adjusted sp of
+ * tramp code.
+ */
+ sp = frame_unwind_register_unsigned(next_frame, NUM_REGS + SP_REGNUM);
+ pc = frame_unwind_register_unsigned(next_frame, NUM_REGS + PC_REGNUM);
+ sigtramp_stack_size = is_sigtramp_sp_modified(pc) ?
+ MIPS_FBSD_SIGTRAMP_STACK_SIZE : 0;
+ gregs_addr = sp + sigtramp_stack_size + MIPS_FBSD_SIGCONTEXT_REG_OFFSET;
+
+ for (regnum = 0; regnum < PC_REGNUM; regnum++) {
+ cache->saved_regs[NUM_REGS + regnum].addr = gregs_addr +
+ regnum * mips_regsize (current_gdbarch);
+ }
+ /* Only retrieve PC and SP */
+ cache->saved_regs[NUM_REGS + SP_REGNUM].addr = gregs_addr +
+ SP_REGNUM * ( mips_regsize (current_gdbarch));
+
+ cache->saved_regs[NUM_REGS + RA_REGNUM].addr = gregs_addr +
+ RA_REGNUM * ( mips_regsize (current_gdbarch));
+
+ cache->base = get_frame_memory_unsigned (next_frame,
+ cache->saved_regs[NUM_REGS + SP_REGNUM].addr,
+ mips_regsize (current_gdbarch));
+
+ /* Todo: Floating point registers */
+
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
+ = cache->saved_regs[NUM_REGS + RA_REGNUM];
+
+ return *this_cache;
+}
+
+static void
+mipsfbsd_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base,
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc].addr);
+}
+
+static void
+mipsfbsd_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+
+static const struct frame_unwind mipsfbsd_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ mipsfbsd_sigtramp_frame_this_id,
+ mipsfbsd_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+mipsfbsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (mipsfbsd_pc_in_sigtramp (pc, name) )
+ return &mipsfbsd_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+/*
+ * Find out if PC has landed into dynamic library stub.
+ * We can find it by seeing if the name of the object
+ * file section where the PC lies is "MIPS.stubs"
+ */
+
+int
+mipsfbsd_in_stub_section (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
+ && strcmp (s->the_bfd_section->name, ".MIPS.stubs") == 0);
+ return (retval);
+}
+
+
+/*
+ * Prologue cache for dynamic library stub frame.
+ * This stub does not modify the SP, so we set the
+ * cache base to calling frame's SP
+ */
+static struct mips_frame_cache *
+mipsfbsd_stub_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct mips_frame_cache *cache;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
+ *this_cache = cache;
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc].realreg =
+ NUM_REGS + RA_REGNUM;
+ cache->base = frame_unwind_register_unsigned (next_frame,
+ NUM_REGS + SP_REGNUM);
+
+ return (*this_cache);
+}
+
+
+static void
+mipsfbsd_stub_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_stub_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base,
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc].addr);
+}
+
+static void
+mipsfbsd_stub_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_stub_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+
+
+static const struct frame_unwind mipsfbsd_stub_frame_unwind = {
+ NORMAL_FRAME,
+ mipsfbsd_stub_frame_this_id,
+ mipsfbsd_stub_frame_prev_register
+};
+
+static const struct frame_unwind *
+mipsfbsd_stub_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+ if (mipsfbsd_in_stub_section(pc, NULL))
+ return &mipsfbsd_stub_frame_unwind;
+
+ return NULL;
+}
+
+/*
+ * typedef struct link_map {
+ * caddr_t l_addr; /* Base Address of library
+ * #ifdef __mips__
+ * caddr_t l_offs; /* Load Offset of library
+ * #endif
+ * const char *l_name; /* Absolute Path to Library
+ * const void *l_ld; /* Pointer to .dynamic in memory
+ * struct link_map *l_next, *l_prev; /* linked list of of mapped libs
+ * } Link_map;
+ *
+ * struct r_debug {
+ * int r_version; /* not used
+ * struct link_map *r_map; /* list of loaded images
+ * void (*r_brk)(struct r_debug *, struct link_map *);
+ * /* pointer to break point
+ * enum {
+ * RT_CONSISTENT, /* things are stable
+ * RT_ADD, /* adding a shared library
+ * RT_DELETE /* removing a shared library
+ * } r_state;
+ * };
+ *
+ */
+
+static struct link_map_offsets *
+mipsfbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 16;
+
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 24;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 16;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 20;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+static void
+mipsfbsd_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ set_gdbarch_pc_in_sigtramp (gdbarch, mipsfbsd_pc_in_sigtramp);
+
+ set_gdbarch_get_longjmp_target (gdbarch, mipsfbsd_get_longjmp_target);
+
+ set_gdbarch_cannot_fetch_register (gdbarch, mipsfbsd_cannot_fetch_register);
+ set_gdbarch_cannot_store_register (gdbarch, mipsfbsd_cannot_store_register);
+
+ set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ mipsfbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_in_solib_call_trampoline (gdbarch, mipsfbsd_in_stub_section);
+
+ /* frame sniffers */
+ frame_unwind_append_sniffer (gdbarch, mipsfbsd_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, mipsfbsd_stub_frame_sniffer);
+
+}
+
+void
+_initialize_mipsfbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD_ELF,
+ mipsfbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/mipsfbsd-tdep.h b/contrib/gdb/gdb/mipsfbsd-tdep.h
new file mode 100644
index 0000000..6b00bb4
--- /dev/null
+++ b/contrib/gdb/gdb/mipsfbsd-tdep.h
@@ -0,0 +1,40 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Common target dependent code for GDB on MIPS systems running NetBSD.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 mipsfbsd_TDEP_H
+#define mipsfbsd_TDEP_H
+
+void mipsfbsd_supply_reg (char *, int);
+void mipsfbsd_fill_reg (char *, int);
+
+void mipsfbsd_supply_fpreg (char *, int);
+void mipsfbsd_fill_fpreg (char *, int);
+
+#define SIZEOF_STRUCT_REG (38 * mips_regsize (current_gdbarch))
+#define SIZEOF_STRUCT_FPREG (33 * mips_regsize (current_gdbarch))
+
+#endif /* mipsfbsd_TDEP_H */
diff --git a/contrib/gdb/gdb/mipsnbsd-nat.c b/contrib/gdb/gdb/mipsnbsd-nat.c
new file mode 100644
index 0000000..16521f6
--- /dev/null
+++ b/contrib/gdb/gdb/mipsnbsd-nat.c
@@ -0,0 +1,101 @@
+/* Native-dependent code for MIPS systems running NetBSD.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include "mipsnbsd-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+/* Determine if PT_GETREGS fetches this register. */
+static int
+getregs_supplies (int regno)
+{
+ return ((regno) >= ZERO_REGNUM && (regno) <= PC_REGNUM);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ mipsnbsd_supply_reg ((char *) &regs, regno);
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ mipsnbsd_supply_fpreg ((char *) &fpregs, regno);
+ }
+}
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ mipsnbsd_fill_reg ((char *) &regs, regno);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ mipsnbsd_fill_fpreg ((char *) &fpregs, regno);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't write floating point status");
+ }
+}
diff --git a/contrib/gdb/gdb/mipsnbsd-tdep.c b/contrib/gdb/gdb/mipsnbsd-tdep.c
new file mode 100644
index 0000000..01d8262
--- /dev/null
+++ b/contrib/gdb/gdb/mipsnbsd-tdep.c
@@ -0,0 +1,370 @@
+/* Target-dependent code for MIPS systems running NetBSD.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include "target.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "nbsd-tdep.h"
+#include "mipsnbsd-tdep.h"
+
+#include "solib-svr4.h"
+
+/* Conveniently, GDB uses the same register numbering as the
+ ptrace register structure used by NetBSD/mips. */
+
+void
+mipsnbsd_supply_reg (char *regs, int regno)
+{
+ int i;
+
+ for (i = 0; i <= PC_REGNUM; i++)
+ {
+ if (regno == i || regno == -1)
+ {
+ if (CANNOT_FETCH_REGISTER (i))
+ supply_register (i, NULL);
+ else
+ supply_register (i, regs + (i * mips_regsize (current_gdbarch)));
+ }
+ }
+}
+
+void
+mipsnbsd_fill_reg (char *regs, int regno)
+{
+ int i;
+
+ for (i = 0; i <= PC_REGNUM; i++)
+ if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+ regcache_collect (i, regs + (i * mips_regsize (current_gdbarch)));
+}
+
+void
+mipsnbsd_supply_fpreg (char *fpregs, int regno)
+{
+ int i;
+
+ for (i = FP0_REGNUM;
+ i <= mips_regnum (current_gdbarch)->fp_implementation_revision;
+ i++)
+ {
+ if (regno == i || regno == -1)
+ {
+ if (CANNOT_FETCH_REGISTER (i))
+ supply_register (i, NULL);
+ else
+ supply_register (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
+ }
+ }
+}
+
+void
+mipsnbsd_fill_fpreg (char *fpregs, int regno)
+{
+ int i;
+
+ for (i = FP0_REGNUM; i <= mips_regnum (current_gdbarch)->fp_control_status;
+ i++)
+ if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+ regcache_collect (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ char *regs, *fpregs;
+
+ /* We get everything from one section. */
+ if (which != 0)
+ return;
+
+ regs = core_reg_sect;
+ fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
+
+ /* Integer registers. */
+ mipsnbsd_supply_reg (regs, -1);
+
+ /* Floating point registers. */
+ mipsnbsd_supply_fpreg (fpregs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ switch (which)
+ {
+ case 0: /* Integer registers. */
+ if (core_reg_size != SIZEOF_STRUCT_REG)
+ warning ("Wrong size register set in core file.");
+ else
+ mipsnbsd_supply_reg (core_reg_sect, -1);
+ break;
+
+ case 2: /* Floating point registers. */
+ if (core_reg_size != SIZEOF_STRUCT_FPREG)
+ warning ("Wrong size register set in core file.");
+ else
+ mipsnbsd_supply_fpreg (core_reg_sect, -1);
+ break;
+
+ default:
+ /* Don't know what kind of register request this is; just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns mipsnbsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+static struct core_fns mipsnbsd_elfcore_fns =
+{
+ bfd_target_elf_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_elfcore_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+/* Under NetBSD/mips, signal handler invocations can be identified by the
+ designated code sequence that is used to return from a signal handler.
+ In particular, the return address of a signal handler points to the
+ following code sequence:
+
+ addu a0, sp, 16
+ li v0, 295 # __sigreturn14
+ syscall
+
+ Each instruction has a unique encoding, so we simply attempt to match
+ the instruction the PC is pointing to with any of the above instructions.
+ If there is a hit, we know the offset to the start of the designated
+ sequence and can then check whether we really are executing in the
+ signal trampoline. If not, -1 is returned, otherwise the offset from the
+ start of the return sequence is returned. */
+
+#define RETCODE_NWORDS 3
+#define RETCODE_SIZE (RETCODE_NWORDS * 4)
+
+static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
+{
+ 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */
+ 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */
+ 0x0c, 0x00, 0x00, 0x00, /* syscall */
+};
+
+static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
+{
+ 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */
+ 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */
+ 0x00, 0x00, 0x00, 0x0c, /* syscall */
+};
+
+static LONGEST
+mipsnbsd_sigtramp_offset (CORE_ADDR pc)
+{
+ const char *retcode = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel;
+ unsigned char ret[RETCODE_SIZE], w[4];
+ LONGEST off;
+ int i;
+
+ if (read_memory_nobpt (pc, (char *) w, sizeof (w)) != 0)
+ return -1;
+
+ for (i = 0; i < RETCODE_NWORDS; i++)
+ {
+ if (memcmp (w, retcode + (i * 4), 4) == 0)
+ break;
+ }
+ if (i == RETCODE_NWORDS)
+ return -1;
+
+ off = i * 4;
+ pc -= off;
+
+ if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
+ return -1;
+
+ if (memcmp (ret, retcode, RETCODE_SIZE) == 0)
+ return off;
+
+ return -1;
+}
+
+static int
+mipsnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ return (nbsd_pc_in_sigtramp (pc, func_name)
+ || mipsnbsd_sigtramp_offset (pc) >= 0);
+}
+
+/* Figure out where the longjmp will land. We expect that we have
+ just entered longjmp and haven't yet setup the stack frame, so
+ the args are still in the argument regs. A0_REGNUM points at the
+ jmp_buf structure from which we extract the PC that we will land
+ at. The PC is copied into *pc. This routine returns true on
+ success. */
+
+#define NBSD_MIPS_JB_PC (2 * 4)
+#define NBSD_MIPS_JB_ELEMENT_SIZE mips_regsize (current_gdbarch)
+#define NBSD_MIPS_JB_OFFSET (NBSD_MIPS_JB_PC * \
+ NBSD_MIPS_JB_ELEMENT_SIZE)
+
+static int
+mipsnbsd_get_longjmp_target (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char *buf;
+
+ buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE);
+
+ jb_addr = read_register (A0_REGNUM);
+
+ if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf,
+ NBSD_MIPS_JB_ELEMENT_SIZE))
+ return 0;
+
+ *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE);
+
+ return 1;
+}
+
+static int
+mipsnbsd_cannot_fetch_register (int regno)
+{
+ return (regno == ZERO_REGNUM
+ || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
+}
+
+static int
+mipsnbsd_cannot_store_register (int regno)
+{
+ return (regno == ZERO_REGNUM
+ || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
+}
+
+/* NetBSD/mips uses a slightly different link_map structure from the
+ other NetBSD platforms. */
+static struct link_map_offsets *
+mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 16;
+
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 24;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 16;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 20;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+static struct link_map_offsets *
+mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 32;
+
+ lmo.r_map_offset = 8;
+ lmo.r_map_size = 8;
+
+ lmo.link_map_size = 48;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 8;
+
+ lmo.l_name_offset = 16;
+ lmo.l_name_size = 8;
+
+ lmo.l_next_offset = 32;
+ lmo.l_next_size = 8;
+
+ lmo.l_prev_offset = 40;
+ lmo.l_prev_size = 8;
+ }
+
+ return lmp;
+}
+
+static void
+mipsnbsd_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ set_gdbarch_pc_in_sigtramp (gdbarch, mipsnbsd_pc_in_sigtramp);
+
+ set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
+
+ set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
+ set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
+
+ set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
+
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ gdbarch_ptr_bit (gdbarch) == 32 ?
+ mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets :
+ mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets);
+}
+
+void
+_initialize_mipsnbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF,
+ mipsnbsd_init_abi);
+
+ add_core_fns (&mipsnbsd_core_fns);
+ add_core_fns (&mipsnbsd_elfcore_fns);
+}
diff --git a/contrib/gdb/gdb/mipsnbsd-tdep.h b/contrib/gdb/gdb/mipsnbsd-tdep.h
new file mode 100644
index 0000000..0feca87
--- /dev/null
+++ b/contrib/gdb/gdb/mipsnbsd-tdep.h
@@ -0,0 +1,33 @@
+/* Common target dependent code for GDB on MIPS systems running NetBSD.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MIPSNBSD_TDEP_H
+#define MIPSNBSD_TDEP_H
+
+void mipsnbsd_supply_reg (char *, int);
+void mipsnbsd_fill_reg (char *, int);
+
+void mipsnbsd_supply_fpreg (char *, int);
+void mipsnbsd_fill_fpreg (char *, int);
+
+#define SIZEOF_STRUCT_REG (38 * mips_regsize (current_gdbarch))
+#define SIZEOF_STRUCT_FPREG (33 * mips_regsize (current_gdbarch))
+
+#endif /* MIPSNBSD_TDEP_H */
diff --git a/contrib/gdb/gdb/mipsread.c b/contrib/gdb/gdb/mipsread.c
new file mode 100644
index 0000000..f67eeea
--- /dev/null
+++ b/contrib/gdb/gdb/mipsread.c
@@ -0,0 +1,444 @@
+/* Read a symbol table in MIPS' format (Third-Eye).
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1998, 1999, 2000, 2001, 2003, 2004
+ 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 "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.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"
+
+extern void _initialize_mipsread (void);
+
+static void mipscoff_new_init (struct objfile *);
+
+static void mipscoff_symfile_init (struct objfile *);
+
+static void mipscoff_symfile_read (struct objfile *, int);
+
+static void mipscoff_symfile_finish (struct objfile *);
+
+static void
+read_alphacoff_dynamic_symtab (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 (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 (struct objfile *objfile)
+{
+}
+
+/* Read a symbol file from a file. */
+
+static void
+mipscoff_symfile_read (struct objfile *objfile, int mainline)
+{
+ bfd *abfd = objfile->obfd;
+ struct cleanup *back_to;
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup_discard_minimal_symbols ();
+
+ /* 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);
+
+ /* Add alpha coff dynamic symbols. */
+
+ read_alphacoff_dynamic_symtab (objfile->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.deprecated_entry_file_lowpc == INVALID_ENTRY_LOWPC)
+ {
+ struct minimal_symbol *m;
+
+ m = lookup_minimal_symbol_by_pc (objfile->ei.entry_point);
+ if (m && DEPRECATED_SYMBOL_NAME (m + 1))
+ {
+ objfile->ei.deprecated_entry_file_lowpc = SYMBOL_VALUE_ADDRESS (m);
+ objfile->ei.deprecated_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 (struct objfile *objfile)
+{
+}
+
+/* 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 */
+ };
+
+/* 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 (bfd *ignore_abfd, asection *sectp, void *sip)
+{
+ struct alphacoff_dynsecinfo *si;
+
+ si = (struct alphacoff_dynsecinfo *) sip;
+
+ if (DEPRECATED_STREQ (sectp->name, ".dynsym"))
+ {
+ si->sym_sect = sectp;
+ }
+ else if (DEPRECATED_STREQ (sectp->name, ".dynstr"))
+ {
+ si->str_sect = sectp;
+ }
+ else if (DEPRECATED_STREQ (sectp->name, ".dynamic"))
+ {
+ si->dyninfo_sect = sectp;
+ }
+ else if (DEPRECATED_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 (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;
+ struct cleanup *cleanups;
+
+
+ /* 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, (void *) & 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 = xmalloc (sym_secsize);
+ cleanups = make_cleanup (free, sym_secptr);
+ str_secptr = xmalloc (str_secsize);
+ make_cleanup (free, str_secptr);
+ dyninfo_secptr = xmalloc (dyninfo_secsize);
+ make_cleanup (free, dyninfo_secptr);
+ got_secptr = xmalloc (got_secsize);
+ make_cleanup (free, got_secptr);
+
+ 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 (objfile));
+ }
+ 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 (objfile));
+ }
+ 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 (objfile));
+ }
+ else if (sym_shndx == SHN_ABS)
+ {
+ ms_type = mst_abs;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ prim_record_minimal_symbol (name, sym_value, ms_type, objfile);
+ }
+
+ do_cleanups (cleanups);
+}
+
+/* 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 */
+ default_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_mipsread (void)
+{
+ add_symtab_fns (&ecoff_sym_fns);
+}
diff --git a/contrib/gdb/gdb/mipsv4-nat.c b/contrib/gdb/gdb/mipsv4-nat.c
new file mode 100644
index 0000000..3a3e732
--- /dev/null
+++ b/contrib/gdb/gdb/mipsv4-nat.c
@@ -0,0 +1,168 @@
+/* Native support for MIPS running SVR4, for GDB.
+ Copyright 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include <sys/time.h>
+#include <sys/procfs.h>
+#include <setjmp.h> /* For JB_XXX. */
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* 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 (gregset_t *gregsetp)
+{
+ int regi;
+ greg_t *regp = &(*gregsetp)[0];
+ char zerobuf[MAX_REGISTER_SIZE];
+ memset (zerobuf, 0, MAX_REGISTER_SIZE);
+
+ for (regi = 0; regi <= CXT_RA; regi++)
+ supply_register (regi, (char *) (regp + regi));
+
+ supply_register (mips_regnum (current_gdbarch)->pc,
+ (char *) (regp + CXT_EPC));
+ supply_register (mips_regnum (current_gdbarch)->hi,
+ (char *) (regp + CXT_MDHI));
+ supply_register (mips_regnum (current_gdbarch)->lo,
+ (char *) (regp + CXT_MDLO));
+ supply_register (mips_regnum (current_gdbarch)->cause,
+ (char *) (regp + CXT_CAUSE));
+
+ /* Fill inaccessible registers with zero. */
+ supply_register (PS_REGNUM, zerobuf);
+ supply_register (mips_regnum (current_gdbarch)->badvaddr, zerobuf);
+ supply_register (DEPRECATED_FP_REGNUM, zerobuf);
+ supply_register (UNUSED_REGNUM, zerobuf);
+ for (regi = FIRST_EMBED_REGNUM; regi <= LAST_EMBED_REGNUM; regi++)
+ supply_register (regi, zerobuf);
+}
+
+void
+fill_gregset (gregset_t *gregsetp, int regno)
+{
+ int regi;
+ greg_t *regp = &(*gregsetp)[0];
+
+ for (regi = 0; regi <= 32; regi++)
+ if ((regno == -1) || (regno == regi))
+ *(regp + regi) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (regi)];
+
+ if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->pc))
+ *(regp + CXT_EPC) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->pc)];
+
+ if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->cause))
+ *(regp + CXT_CAUSE) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->cause)];
+
+ if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->hi))
+ *(regp + CXT_MDHI) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->hi)];
+
+ if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->lo))
+ *(regp + CXT_MDLO) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->lo)];
+}
+
+/*
+ * 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 (fpregset_t *fpregsetp)
+{
+ int regi;
+ char zerobuf[MAX_REGISTER_SIZE];
+ memset (zerobuf, 0, MAX_REGISTER_SIZE);
+
+ for (regi = 0; regi < 32; regi++)
+ supply_register (mips_regnum (current_gdbarch)->fp0 + regi,
+ (char *) &fpregsetp->fp_r.fp_regs[regi]);
+
+ supply_register (mips_regnum (current_gdbarch)->fp_control_status,
+ (char *) &fpregsetp->fp_csr);
+
+ /* FIXME: how can we supply FCRIR? The ABI doesn't tell us. */
+ supply_register (mips_regnum (current_gdbarch)->fp_implementation_revision,
+ zerobuf);
+}
+
+void
+fill_fpregset (fpregset_t *fpregsetp, int regno)
+{
+ int regi;
+ char *from, *to;
+
+ for (regi = mips_regnum (current_gdbarch)->fp0;
+ regi < mips_regnum (current_gdbarch)->fp0 + 32; regi++)
+ {
+ if ((regno == -1) || (regno == regi))
+ {
+ from = (char *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regi)];
+ to = (char *) &(fpregsetp->fp_r.fp_regs[regi - mips_regnum (current_gdbarch)->fp0]);
+ memcpy (to, from, DEPRECATED_REGISTER_RAW_SIZE (regi));
+ }
+ }
+
+ if ((regno == -1)
+ || (regno == mips_regnum (current_gdbarch)->fp_control_status))
+ fpregsetp->fp_csr = *(unsigned *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)];
+}
+
+
+/* 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 (CORE_ADDR *pc)
+{
+ char *buf;
+ CORE_ADDR jb_addr;
+
+ buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
+ 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_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+
+ return 1;
+}
diff --git a/contrib/gdb/gdb/monitor.c b/contrib/gdb/gdb/monitor.c
new file mode 100644
index 0000000..cd4f045
--- /dev/null
+++ b/contrib/gdb/gdb/monitor.c
@@ -0,0 +1,2310 @@
+/* Remote debugging interface for boot monitors, for GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002 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 existence, 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. */
+
+/* FIXME 32x64: This code assumes that registers and addresses are at
+ most 32 bits long. If they can be larger, you will need to declare
+ values as LONGEST and use %llx or some such to print values when
+ building commands to send to the monitor. Since we don't know of
+ any actual 64-bit targets with ROM monitors that use this code,
+ it's not an issue right now. -sts 4/18/96 */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include <signal.h>
+#include <ctype.h>
+#include "gdb_string.h"
+#include <sys/types.h>
+#include "command.h"
+#include "serial.h"
+#include "monitor.h"
+#include "gdbcmd.h"
+#include "inferior.h"
+#include "gdb_regex.h"
+#include "srec.h"
+#include "regcache.h"
+
+static char *dev_name;
+static struct target_ops *targ_ops;
+
+static void monitor_vsprintf (char *sndbuf, char *pattern, va_list args);
+
+static int readchar (int timeout);
+
+static void monitor_fetch_register (int regno);
+static void monitor_store_register (int regno);
+
+static void monitor_printable_string (char *newstr, char *oldstr, int len);
+static void monitor_error (char *function, char *message, CORE_ADDR memaddr, int len, char *string, int final_char);
+static void monitor_detach (char *args, int from_tty);
+static void monitor_resume (ptid_t ptid, int step, enum target_signal sig);
+static void monitor_interrupt (int signo);
+static void monitor_interrupt_twice (int signo);
+static void monitor_interrupt_query (void);
+static void monitor_wait_cleanup (void *old_timeout);
+
+static ptid_t monitor_wait (ptid_t ptid, struct target_waitstatus *status);
+static void monitor_fetch_registers (int regno);
+static void monitor_store_registers (int regno);
+static void monitor_prepare_to_store (void);
+static int monitor_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+static void monitor_files_info (struct target_ops *ops);
+static int monitor_insert_breakpoint (CORE_ADDR addr, char *shadow);
+static int monitor_remove_breakpoint (CORE_ADDR addr, char *shadow);
+static void monitor_kill (void);
+static void monitor_load (char *file, int from_tty);
+static void monitor_mourn_inferior (void);
+static void monitor_stop (void);
+
+static int monitor_read_memory (CORE_ADDR addr, char *myaddr, int len);
+static int monitor_write_memory (CORE_ADDR addr, char *myaddr, int len);
+static int monitor_write_memory_bytes (CORE_ADDR addr, char *myaddr, int len);
+static int monitor_write_memory_block (CORE_ADDR memaddr,
+ char *myaddr, int len);
+static int monitor_expect_regexp (struct re_pattern_buffer *pat,
+ char *buf, int buflen);
+static void monitor_dump_regs (void);
+#if 0
+static int from_hex (int a);
+static unsigned long get_hex_word (void);
+#endif
+static void parse_register_dump (char *, int);
+
+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 */
+
+static CORE_ADDR *breakaddr;
+
+/* 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 struct serial *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 struct re_pattern_buffer setmem_resp_delim_pattern;
+static char setmem_resp_delim_fastmap[256];
+
+static struct re_pattern_buffer setreg_resp_delim_pattern;
+static char setreg_resp_delim_fastmap[256];
+
+static int dump_reg_flag; /* Non-zero means do a dump_registers cmd when
+ monitor_wait wakes up. */
+
+static int first_time = 0; /* is this the first time we're executing after
+ gaving created the child proccess? */
+
+#define TARGET_BUF_SIZE 2048
+
+/* Monitor specific debugging information. Typically only useful to
+ the developer of a new monitor interface. */
+
+static void monitor_debug (const char *fmt, ...) ATTR_FORMAT(printf, 1, 2);
+
+static int monitor_debug_p = 0;
+
+/* NOTE: This file alternates between monitor_debug_p and remote_debug
+ when determining if debug information is printed. Perhaphs this
+ could be simplified. */
+
+static void
+monitor_debug (const char *fmt, ...)
+{
+ if (monitor_debug_p)
+ {
+ va_list args;
+ va_start (args, fmt);
+ vfprintf_filtered (gdb_stdlog, fmt, args);
+ va_end (args);
+ }
+}
+
+
+/* Convert a string into a printable representation, Return # byte in
+ the new string. When LEN is >0 it specifies the size of the
+ string. Otherwize strlen(oldstr) is used. */
+
+static void
+monitor_printable_string (char *newstr, char *oldstr, int len)
+{
+ int ch;
+ int i;
+
+ if (len <= 0)
+ len = strlen (oldstr);
+
+ for (i = 0; i < len; i++)
+ {
+ ch = oldstr[i];
+ switch (ch)
+ {
+ default:
+ if (isprint (ch))
+ *newstr++ = ch;
+
+ else
+ {
+ sprintf (newstr, "\\x%02x", ch & 0xff);
+ newstr += 4;
+ }
+ break;
+
+ case '\\':
+ *newstr++ = '\\';
+ *newstr++ = '\\';
+ break;
+ case '\b':
+ *newstr++ = '\\';
+ *newstr++ = 'b';
+ break;
+ case '\f':
+ *newstr++ = '\\';
+ *newstr++ = 't';
+ break;
+ case '\n':
+ *newstr++ = '\\';
+ *newstr++ = 'n';
+ break;
+ case '\r':
+ *newstr++ = '\\';
+ *newstr++ = 'r';
+ break;
+ case '\t':
+ *newstr++ = '\\';
+ *newstr++ = 't';
+ break;
+ case '\v':
+ *newstr++ = '\\';
+ *newstr++ = 'v';
+ break;
+ }
+ }
+
+ *newstr++ = '\0';
+}
+
+/* Print monitor errors with a string, converting the string to printable
+ representation. */
+
+static void
+monitor_error (char *function, char *message,
+ CORE_ADDR memaddr, int len, char *string, int final_char)
+{
+ int real_len = (len == 0 && string != (char *) 0) ? strlen (string) : len;
+ char *safe_string = alloca ((real_len * 4) + 1);
+ monitor_printable_string (safe_string, string, real_len);
+
+ if (final_char)
+ error ("%s (0x%s): %s: %s%c", function, paddr_nz (memaddr), message, safe_string, final_char);
+ else
+ error ("%s (0x%s): %s: %s", function, paddr_nz (memaddr), message, safe_string);
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (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 ("Invalid hex digit %d", a);
+}
+
+/* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses
+
+ This function exists to get around the problem that many host platforms
+ don't have a printf that can print 64-bit addresses. The %A format
+ specification is recognized as a special case, and causes the argument
+ to be printed as a 64-bit hexadecimal address.
+
+ Only format specifiers of the form "[0-9]*[a-z]" are recognized.
+ If it is a '%s' format, the argument is a string; otherwise the
+ argument is assumed to be a long integer.
+
+ %% is also turned into a single %.
+ */
+
+static void
+monitor_vsprintf (char *sndbuf, char *pattern, va_list args)
+{
+ char format[10];
+ char fmt;
+ char *p;
+ int i;
+ long arg_int;
+ CORE_ADDR arg_addr;
+ char *arg_string;
+
+ for (p = pattern; *p; p++)
+ {
+ if (*p == '%')
+ {
+ /* Copy the format specifier to a separate buffer. */
+ format[0] = *p++;
+ for (i = 1; *p >= '0' && *p <= '9' && i < (int) sizeof (format) - 2;
+ i++, p++)
+ format[i] = *p;
+ format[i] = fmt = *p;
+ format[i + 1] = '\0';
+
+ /* Fetch the next argument and print it. */
+ switch (fmt)
+ {
+ case '%':
+ strcpy (sndbuf, "%");
+ break;
+ case 'A':
+ arg_addr = va_arg (args, CORE_ADDR);
+ strcpy (sndbuf, paddr_nz (arg_addr));
+ break;
+ case 's':
+ arg_string = va_arg (args, char *);
+ sprintf (sndbuf, format, arg_string);
+ break;
+ default:
+ arg_int = va_arg (args, long);
+ sprintf (sndbuf, format, arg_int);
+ break;
+ }
+ sndbuf += strlen (sndbuf);
+ }
+ else
+ *sndbuf++ = *p;
+ }
+ *sndbuf = '\0';
+}
+
+
+/* monitor_printf_noecho -- Send data to monitor, but don't expect an echo.
+ Works just like printf. */
+
+void
+monitor_printf_noecho (char *pattern,...)
+{
+ va_list args;
+ char sndbuf[2000];
+ int len;
+
+ va_start (args, pattern);
+
+ monitor_vsprintf (sndbuf, pattern, args);
+
+ len = strlen (sndbuf);
+ if (len + 1 > sizeof sndbuf)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ if (monitor_debug_p)
+ {
+ char *safe_string = (char *) alloca ((strlen (sndbuf) * 4) + 1);
+ monitor_printable_string (safe_string, sndbuf, 0);
+ fprintf_unfiltered (gdb_stdlog, "sent[%s]\n", safe_string);
+ }
+
+ monitor_write (sndbuf, len);
+}
+
+/* monitor_printf -- Send data to monitor and check the echo. Works just like
+ printf. */
+
+void
+monitor_printf (char *pattern,...)
+{
+ va_list args;
+ char sndbuf[2000];
+ int len;
+
+ va_start (args, pattern);
+
+ monitor_vsprintf (sndbuf, pattern, args);
+
+ len = strlen (sndbuf);
+ if (len + 1 > sizeof sndbuf)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ if (monitor_debug_p)
+ {
+ char *safe_string = (char *) alloca ((len * 4) + 1);
+ monitor_printable_string (safe_string, sndbuf, 0);
+ fprintf_unfiltered (gdb_stdlog, "sent[%s]\n", safe_string);
+ }
+
+ monitor_write (sndbuf, len);
+
+ /* 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_debug ("ExpectEcho\n");
+ monitor_expect (sndbuf, (char *) 0, 0);
+}
+
+
+/* Write characters to the remote system. */
+
+void
+monitor_write (char *buf, int buflen)
+{
+ if (serial_write (monitor_desc, buf, buflen))
+ fprintf_unfiltered (gdb_stderr, "serial_write failed: %s\n",
+ safe_strerror (errno));
+}
+
+
+/* Read a binary character from the remote system, doing all the fancy
+ timeout stuff, but without interpreting the character in any way,
+ and without printing remote debug information. */
+
+int
+monitor_readchar (void)
+{
+ int c;
+ int looping;
+
+ do
+ {
+ looping = 0;
+ c = serial_readchar (monitor_desc, timeout);
+
+ if (c >= 0)
+ c &= 0xff; /* don't lose bit 7 */
+ }
+ while (looping);
+
+ if (c >= 0)
+ return c;
+
+ if (c == SERIAL_TIMEOUT)
+ error ("Timeout reading from remote system.");
+
+ perror_with_name ("remote-monitor");
+}
+
+
+/* Read a character from the remote system, doing all the fancy
+ timeout stuff. */
+
+static int
+readchar (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;
+ /* This seems to interfere with proper function of the
+ input stream */
+ if (monitor_debug_p || remote_debug)
+ {
+ char buf[2];
+ buf[0] = c;
+ buf[1] = '\0';
+ puts_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)
+#if 0
+ /* I fail to see how detaching here can be useful */
+ if (in_monitor_wait) /* Watchdog went off */
+ {
+ target_mourn_inferior ();
+ error ("GDB serial timeout 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 (char *string, char *buf, int buflen)
+{
+ char *p = string;
+ int obuflen = buflen;
+ int c;
+
+ if (monitor_debug_p)
+ {
+ char *safe_string = (char *) alloca ((strlen (string) * 4) + 1);
+ monitor_printable_string (safe_string, string, 0);
+ fprintf_unfiltered (gdb_stdlog, "MON Expecting '%s'\n", safe_string);
+ }
+
+ immediate_quit++;
+ while (1)
+ {
+ if (buf)
+ {
+ if (buflen < 2)
+ {
+ *buf = '\000';
+ immediate_quit--;
+ 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--;
+
+ if (buf)
+ {
+ *buf++ = '\000';
+ return obuflen - buflen;
+ }
+ else
+ return 0;
+ }
+ }
+ else
+ {
+ /* We got a character that doesn't match the string. We need to
+ back up p, but how far? If we're looking for "..howdy" and the
+ monitor sends "...howdy"? There's certainly a match in there,
+ but when we receive the third ".", we won't find it if we just
+ restart the matching at the beginning of the string.
+
+ This is a Boyer-Moore kind of situation. We want to reset P to
+ the end of the longest prefix of STRING that is a suffix of
+ what we've read so far. In the example above, that would be
+ ".." --- the longest prefix of "..howdy" that is a suffix of
+ "...". This longest prefix could be the empty string, if C
+ is nowhere to be found in STRING.
+
+ If this longest prefix is not the empty string, it must contain
+ C, so let's search from the end of STRING for instances of C,
+ and see if the portion of STRING before that is a suffix of
+ what we read before C. Actually, we can search backwards from
+ p, since we know no prefix can be longer than that.
+
+ Note that we can use STRING itself, along with C, as a record
+ of what we've received so far. :) */
+ int i;
+
+ for (i = (p - string) - 1; i >= 0; i--)
+ if (string[i] == c)
+ {
+ /* Is this prefix a suffix of what we've read so far?
+ In other words, does
+ string[0 .. i-1] == string[p - i, p - 1]? */
+ if (! memcmp (string, p - i, i))
+ {
+ p = string + i + 1;
+ break;
+ }
+ }
+ if (i < 0)
+ p = string;
+ }
+ }
+}
+
+/* Search for a regexp. */
+
+static int
+monitor_expect_regexp (struct re_pattern_buffer *pat, char *buf, int buflen)
+{
+ char *mybuf;
+ char *p;
+ monitor_debug ("MON Expecting regexp\n");
+ if (buf)
+ mybuf = buf;
+ else
+ {
+ mybuf = alloca (TARGET_BUF_SIZE);
+ buflen = TARGET_BUF_SIZE;
+ }
+
+ 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 (char *buf, int buflen)
+{
+ monitor_debug ("MON Expecting prompt\n");
+ return monitor_expect (current_monitor->prompt, buf, buflen);
+}
+
+/* Get N 32-bit words from remote, each preceded by a space, and put
+ them in registers starting at REGNO. */
+
+#if 0
+static unsigned long
+get_hex_word (void)
+{
+ 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;
+}
+#endif
+
+static void
+compile_pattern (char *pattern, struct re_pattern_buffer *compiled_pattern,
+ char *fastmap)
+{
+ int tmp;
+ const 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. */
+
+void
+monitor_open (char *args, struct monitor_ops *mon_ops, int from_tty)
+{
+ char *name;
+ 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, &register_pattern,
+ register_fastmap);
+
+ if (mon_ops->getmem.resp_delim)
+ compile_pattern (mon_ops->getmem.resp_delim, &getmem_resp_delim_pattern,
+ getmem_resp_delim_fastmap);
+
+ if (mon_ops->setmem.resp_delim)
+ compile_pattern (mon_ops->setmem.resp_delim, &setmem_resp_delim_pattern,
+ setmem_resp_delim_fastmap);
+
+ if (mon_ops->setreg.resp_delim)
+ compile_pattern (mon_ops->setreg.resp_delim, &setreg_resp_delim_pattern,
+ setreg_resp_delim_fastmap);
+
+ unpush_target (targ_ops);
+
+ if (dev_name)
+ xfree (dev_name);
+ dev_name = xstrdup (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_debug ("EXP Open echo\n");
+ 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);
+
+ /* Alloc breakpoints */
+ if (mon_ops->set_break != NULL)
+ {
+ if (mon_ops->num_breakpoints == 0)
+ mon_ops->num_breakpoints = 8;
+
+ breakaddr = (CORE_ADDR *) xmalloc (mon_ops->num_breakpoints * sizeof (CORE_ADDR));
+ memset (breakaddr, 0, mon_ops->num_breakpoints * sizeof (CORE_ADDR));
+ }
+
+ /* 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_ptid = pid_to_ptid (42000); /* Make run command think we are busy... */
+
+ /* Give monitor_wait something to read */
+
+ monitor_printf (current_monitor->line_term);
+
+ start_remote ();
+}
+
+/* Close out all files and local state before this target loses
+ control. */
+
+void
+monitor_close (int quitting)
+{
+ if (monitor_desc)
+ serial_close (monitor_desc);
+
+ /* Free breakpoint memory */
+ if (breakaddr != NULL)
+ {
+ xfree (breakaddr);
+ breakaddr = NULL;
+ }
+
+ 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 (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 (int regno, char *valstr)
+{
+ ULONGEST val;
+ unsigned char regbuf[MAX_REGISTER_SIZE];
+ char *p;
+
+ val = 0;
+ p = valstr;
+ while (p && *p != '\0')
+ {
+ if (*p == '\r' || *p == '\n')
+ {
+ while (*p != '\0')
+ p++;
+ break;
+ }
+ if (isspace (*p))
+ {
+ p++;
+ continue;
+ }
+ if (!isxdigit (*p) && *p != 'x')
+ {
+ break;
+ }
+
+ val <<= 4;
+ val += fromhex (*p++);
+ }
+ monitor_debug ("Supplying Register %d %s\n", regno, valstr);
+
+ 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, DEPRECATED_REGISTER_RAW_SIZE (regno), val);
+
+ supply_register (regno, regbuf);
+
+ return p;
+}
+
+/* Tell the remote machine to resume. */
+
+static void
+monitor_resume (ptid_t ptid, int step, enum target_signal sig)
+{
+ /* Some monitors require a different command when starting a program */
+ monitor_debug ("MON resume\n");
+ if (current_monitor->flags & MO_RUN_FIRST_TIME && first_time == 1)
+ {
+ first_time = 0;
+ monitor_printf ("run\r");
+ if (current_monitor->flags & MO_NEED_REGDUMP_AFTER_CONT)
+ dump_reg_flag = 1;
+ return;
+ }
+ if (step)
+ monitor_printf (current_monitor->step);
+ else
+ {
+ if (current_monitor->continue_hook)
+ (*current_monitor->continue_hook) ();
+ else
+ monitor_printf (current_monitor->cont);
+ 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 void
+parse_register_dump (char *buf, int len)
+{
+ monitor_debug ("MON Parsing register dump\n");
+ 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;
+
+ memset (&register_strings, 0, sizeof (struct re_registers));
+
+ if (re_search (&register_pattern, buf, len, 0, len,
+ &register_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 (int signo)
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, monitor_interrupt_twice);
+
+ if (monitor_debug_p || remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "monitor_interrupt called\n");
+
+ target_stop ();
+}
+
+/* The user typed ^C twice. */
+
+static void
+monitor_interrupt_twice (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 (void)
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ throw_exception (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+static void
+monitor_wait_cleanup (void *old_timeout)
+{
+ timeout = *(int *) old_timeout;
+ signal (SIGINT, ofunc);
+ in_monitor_wait = 0;
+}
+
+
+
+static void
+monitor_wait_filter (char *buf,
+ int bufmax,
+ int *ext_resp_len,
+ struct target_waitstatus *status)
+{
+ int resp_len;
+ do
+ {
+ resp_len = monitor_expect_prompt (buf, bufmax);
+ *ext_resp_len = resp_len;
+
+ if (resp_len <= 0)
+ fprintf_unfiltered (gdb_stderr, "monitor_wait: excessive response from monitor: %s.", buf);
+ }
+ while (resp_len < 0);
+
+ /* Print any output characters that were preceded by ^O. */
+ /* FIXME - This would be great as a user settabgle flag */
+ if (monitor_debug_p || remote_debug
+ || current_monitor->flags & MO_PRINT_PROGRAM_OUTPUT)
+ {
+ int i;
+
+ for (i = 0; i < resp_len - 1; i++)
+ if (buf[i] == 0x0f)
+ putchar_unfiltered (buf[++i]);
+ }
+}
+
+
+
+/* Wait until the remote machine stops, then return, storing status in
+ status just as `wait' would. */
+
+static ptid_t
+monitor_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ int old_timeout = timeout;
+ char buf[TARGET_BUF_SIZE];
+ 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);
+ monitor_debug ("MON wait\n");
+
+#if 0
+ /* This is somthing other than a maintenance command */
+ 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);
+
+ if (current_monitor->wait_filter)
+ (*current_monitor->wait_filter) (buf, sizeof (buf), &resp_len, status);
+ else
+ monitor_wait_filter (buf, sizeof (buf), &resp_len, status);
+
+#if 0 /* Transferred to monitor wait filter */
+ 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);
+
+ /* Print any output characters that were preceded by ^O. */
+ /* FIXME - This would be great as a user settabgle flag */
+ if (monitor_debug_p || remote_debug
+ || current_monitor->flags & MO_PRINT_PROGRAM_OUTPUT)
+ {
+ int i;
+
+ for (i = 0; i < resp_len - 1; i++)
+ if (buf[i] == 0x0f)
+ putchar_unfiltered (buf[++i]);
+ }
+#endif
+
+ signal (SIGINT, ofunc);
+
+ timeout = old_timeout;
+#if 0
+ 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);
+#else
+ monitor_debug ("Wait fetching registers after stop\n");
+ monitor_dump_regs ();
+#endif
+
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+
+ discard_cleanups (old_chain);
+
+ in_monitor_wait = 0;
+
+ return inferior_ptid;
+}
+
+/* Fetch register REGNO, or all registers if REGNO is -1. Returns
+ errno value. */
+
+static void
+monitor_fetch_register (int regno)
+{
+ const char *name;
+ char *zerobuf;
+ char *regbuf;
+ int i;
+
+ regbuf = alloca (MAX_REGISTER_SIZE * 2 + 1);
+ zerobuf = alloca (MAX_REGISTER_SIZE);
+ memset (zerobuf, 0, MAX_REGISTER_SIZE);
+
+ if (current_monitor->regname != NULL)
+ name = current_monitor->regname (regno);
+ else
+ name = current_monitor->regnames[regno];
+ monitor_debug ("MON fetchreg %d '%s'\n", regno, name ? name : "(null name)");
+
+ if (!name || (*name == '\0'))
+ {
+ monitor_debug ("No register known for %d\n", regno);
+ 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_debug ("EXP getreg.resp_delim\n");
+ monitor_expect (current_monitor->getreg.resp_delim, NULL, 0);
+ /* Handle case of first 32 registers listed in pairs. */
+ if (current_monitor->flags & MO_32_REGS_PAIRED
+ && (regno & 1) != 0 && regno < 32)
+ {
+ monitor_debug ("EXP getreg.resp_delim\n");
+ monitor_expect (current_monitor->getreg.resp_delim, NULL, 0);
+ }
+ }
+
+ /* Skip leading spaces and "0x" if MO_HEX_PREFIX flag is set */
+ if (current_monitor->flags & MO_HEX_PREFIX)
+ {
+ int c;
+ c = readchar (timeout);
+ while (c == ' ')
+ c = readchar (timeout);
+ if ((c == '0') && ((c = readchar (timeout)) == 'x'))
+ ;
+ else
+ error ("Bad value returned from monitor while fetching register %x.",
+ regno);
+ }
+
+ /* 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 < DEPRECATED_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 */
+ monitor_debug ("REGVAL '%s'\n", regbuf);
+
+ /* 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_debug ("EXP getreg.term\n");
+ monitor_expect (current_monitor->getreg.term, NULL, 0); /* get response */
+ }
+
+ if (current_monitor->getreg.term_cmd)
+ {
+ monitor_debug ("EMIT getreg.term.cmd\n");
+ monitor_printf (current_monitor->getreg.term_cmd);
+ }
+ if (!current_monitor->getreg.term || /* Already expected or */
+ current_monitor->getreg.term_cmd) /* ack expected */
+ monitor_expect_prompt (NULL, 0); /* get response */
+
+ monitor_supply_register (regno, regbuf);
+}
+
+/* Sometimes, it takes several commands to dump the registers */
+/* This is a primitive for use by variations of monitor interfaces in
+ case they need to compose the operation.
+ */
+int
+monitor_dump_reg_block (char *block_cmd)
+{
+ char buf[TARGET_BUF_SIZE];
+ int resp_len;
+ monitor_printf (block_cmd);
+ resp_len = monitor_expect_prompt (buf, sizeof (buf));
+ parse_register_dump (buf, resp_len);
+ return 1;
+}
+
+
+/* Read the remote registers into the block regs. */
+/* Call the specific function if it has been provided */
+
+static void
+monitor_dump_regs (void)
+{
+ char buf[TARGET_BUF_SIZE];
+ int resp_len;
+ if (current_monitor->dumpregs)
+ (*(current_monitor->dumpregs)) (); /* call supplied function */
+ else if (current_monitor->dump_registers) /* default version */
+ {
+ monitor_printf (current_monitor->dump_registers);
+ resp_len = monitor_expect_prompt (buf, sizeof (buf));
+ parse_register_dump (buf, resp_len);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* Need some way to read registers */
+}
+
+static void
+monitor_fetch_registers (int regno)
+{
+ monitor_debug ("MON fetchregs\n");
+ 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 (int regno)
+{
+ const char *name;
+ ULONGEST val;
+
+ if (current_monitor->regname != NULL)
+ name = current_monitor->regname (regno);
+ else
+ name = current_monitor->regnames[regno];
+
+ if (!name || (*name == '\0'))
+ {
+ monitor_debug ("MON Cannot store unknown register\n");
+ return;
+ }
+
+ val = read_register (regno);
+ monitor_debug ("MON storeg %d %s\n", regno,
+ phex (val, DEPRECATED_REGISTER_RAW_SIZE (regno)));
+
+ /* send the register deposit command */
+
+ if (current_monitor->flags & MO_REGISTER_VALUE_FIRST)
+ monitor_printf (current_monitor->setreg.cmd, val, name);
+ else if (current_monitor->flags & MO_SETREG_INTERACTIVE)
+ monitor_printf (current_monitor->setreg.cmd, name);
+ else
+ monitor_printf (current_monitor->setreg.cmd, name, val);
+
+ if (current_monitor->setreg.resp_delim)
+ {
+ monitor_debug ("EXP setreg.resp_delim\n");
+ monitor_expect_regexp (&setreg_resp_delim_pattern, NULL, 0);
+ if (current_monitor->flags & MO_SETREG_INTERACTIVE)
+ monitor_printf ("%s\r", paddr_nz (val));
+ }
+ if (current_monitor->setreg.term)
+ {
+ monitor_debug ("EXP setreg.term\n");
+ monitor_expect (current_monitor->setreg.term, NULL, 0);
+ if (current_monitor->flags & MO_SETREG_INTERACTIVE)
+ monitor_printf ("%s\r", paddr_nz (val));
+ monitor_expect_prompt (NULL, 0);
+ }
+ else
+ monitor_expect_prompt (NULL, 0);
+ if (current_monitor->setreg.term_cmd) /* Mode exit required */
+ {
+ monitor_debug ("EXP setreg_termcmd\n");
+ monitor_printf ("%s", current_monitor->setreg.term_cmd);
+ monitor_expect_prompt (NULL, 0);
+ }
+} /* monitor_store_register */
+
+/* Store the remote registers. */
+
+static void
+monitor_store_registers (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 (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static void
+monitor_files_info (struct target_ops *ops)
+{
+ printf_unfiltered ("\tAttached to %s at %d baud.\n", dev_name, baud_rate);
+}
+
+static int
+monitor_write_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ unsigned int val, hostval;
+ char *cmd;
+ int i;
+
+ monitor_debug ("MON write %d %s\n", len, paddr (memaddr));
+
+ if (current_monitor->flags & MO_ADDR_BITS_REMOVE)
+ memaddr = ADDR_BITS_REMOVE (memaddr);
+
+ /* 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 */
+ {
+ monitor_debug ("MON FILL %d\n", i);
+ if (current_monitor->flags & MO_FILL_USES_ADDR)
+ monitor_printf (current_monitor->fill, memaddr, (memaddr + i) - 1, 0);
+ else
+ monitor_printf (current_monitor->fill, memaddr, i, 0);
+
+ monitor_expect_prompt (NULL, 0);
+
+ return i;
+ }
+ }
+
+#if 0
+ /* Can't actually use long longs if VAL is an int (nice idea, though). */
+ if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->setmem.cmdll)
+ {
+ len = 8;
+ cmd = current_monitor->setmem.cmdll;
+ }
+ else
+#endif
+ 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);
+
+ if (len == 4)
+ {
+ hostval = *(unsigned int *) myaddr;
+ monitor_debug ("Hostval(%08x) val(%08x)\n", hostval, val);
+ }
+
+
+ if (current_monitor->flags & MO_NO_ECHO_ON_SETMEM)
+ monitor_printf_noecho (cmd, memaddr, val);
+ else if (current_monitor->flags & MO_SETMEM_INTERACTIVE)
+ {
+
+ monitor_printf_noecho (cmd, memaddr);
+
+ if (current_monitor->setmem.resp_delim)
+ {
+ monitor_debug ("EXP setmem.resp_delim");
+ monitor_expect_regexp (&setmem_resp_delim_pattern, NULL, 0);
+ monitor_printf ("%x\r", val);
+ }
+ if (current_monitor->setmem.term)
+ {
+ monitor_debug ("EXP setmem.term");
+ monitor_expect (current_monitor->setmem.term, NULL, 0);
+ monitor_printf ("%x\r", val);
+ }
+ if (current_monitor->setmem.term_cmd)
+ { /* Emit this to get out of the memory editing state */
+ monitor_printf ("%s", current_monitor->setmem.term_cmd);
+ /* Drop through to expecting a prompt */
+ }
+ }
+ else
+ monitor_printf (cmd, memaddr, val);
+
+ monitor_expect_prompt (NULL, 0);
+
+ return len;
+}
+
+
+static int
+monitor_write_memory_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ unsigned char val;
+ int written = 0;
+ if (len == 0)
+ return 0;
+ /* Enter the sub mode */
+ monitor_printf (current_monitor->setmem.cmdb, memaddr);
+ monitor_expect_prompt (NULL, 0);
+ while (len)
+ {
+ val = *myaddr;
+ monitor_printf ("%x\r", val);
+ myaddr++;
+ memaddr++;
+ written++;
+ /* If we wanted to, here we could validate the address */
+ monitor_expect_prompt (NULL, 0);
+ len--;
+ }
+ /* Now exit the sub mode */
+ monitor_printf (current_monitor->getreg.term_cmd);
+ monitor_expect_prompt (NULL, 0);
+ return written;
+}
+
+
+static void
+longlongendswap (unsigned char *a)
+{
+ int i, j;
+ unsigned char x;
+ i = 0;
+ j = 7;
+ while (i < 4)
+ {
+ x = *(a + i);
+ *(a + i) = *(a + j);
+ *(a + j) = x;
+ i++, j--;
+ }
+}
+/* Format 32 chars of long long value, advance the pointer */
+static char *hexlate = "0123456789abcdef";
+static char *
+longlong_hexchars (unsigned long long value,
+ char *outbuff)
+{
+ if (value == 0)
+ {
+ *outbuff++ = '0';
+ return outbuff;
+ }
+ else
+ {
+ static unsigned char disbuf[8]; /* disassembly buffer */
+ unsigned char *scan, *limit; /* loop controls */
+ unsigned char c, nib;
+ int leadzero = 1;
+ scan = disbuf;
+ limit = scan + 8;
+ {
+ unsigned long long *dp;
+ dp = (unsigned long long *) scan;
+ *dp = value;
+ }
+ longlongendswap (disbuf); /* FIXME: ONly on big endian hosts */
+ while (scan < limit)
+ {
+ c = *scan++; /* a byte of our long long value */
+ if (leadzero)
+ {
+ if (c == 0)
+ continue;
+ else
+ leadzero = 0; /* henceforth we print even zeroes */
+ }
+ nib = c >> 4; /* high nibble bits */
+ *outbuff++ = hexlate[nib];
+ nib = c & 0x0f; /* low nibble bits */
+ *outbuff++ = hexlate[nib];
+ }
+ return outbuff;
+ }
+} /* longlong_hexchars */
+
+
+
+/* I am only going to call this when writing virtual byte streams.
+ Which possably entails endian conversions
+ */
+static int
+monitor_write_memory_longlongs (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ static char hexstage[20]; /* At least 16 digits required, plus null */
+ char *endstring;
+ long long *llptr;
+ long long value;
+ int written = 0;
+ llptr = (unsigned long long *) myaddr;
+ if (len == 0)
+ return 0;
+ monitor_printf (current_monitor->setmem.cmdll, memaddr);
+ monitor_expect_prompt (NULL, 0);
+ while (len >= 8)
+ {
+ value = *llptr;
+ endstring = longlong_hexchars (*llptr, hexstage);
+ *endstring = '\0'; /* NUll terminate for printf */
+ monitor_printf ("%s\r", hexstage);
+ llptr++;
+ memaddr += 8;
+ written += 8;
+ /* If we wanted to, here we could validate the address */
+ monitor_expect_prompt (NULL, 0);
+ len -= 8;
+ }
+ /* Now exit the sub mode */
+ monitor_printf (current_monitor->getreg.term_cmd);
+ monitor_expect_prompt (NULL, 0);
+ return written;
+} /* */
+
+
+
+/* ----- MONITOR_WRITE_MEMORY_BLOCK ---------------------------- */
+/* This is for the large blocks of memory which may occur in downloading.
+ And for monitors which use interactive entry,
+ And for monitors which do not have other downloading methods.
+ Without this, we will end up calling monitor_write_memory many times
+ and do the entry and exit of the sub mode many times
+ This currently assumes...
+ MO_SETMEM_INTERACTIVE
+ ! MO_NO_ECHO_ON_SETMEM
+ To use this, the you have to patch the monitor_cmds block with
+ this function. Otherwise, its not tuned up for use by all
+ monitor variations.
+ */
+
+static int
+monitor_write_memory_block (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int written;
+ written = 0;
+ /* FIXME: This would be a good place to put the zero test */
+#if 1
+ if ((len > 8) && (((len & 0x07)) == 0) && current_monitor->setmem.cmdll)
+ {
+ return monitor_write_memory_longlongs (memaddr, myaddr, len);
+ }
+#endif
+ written = monitor_write_memory_bytes (memaddr, myaddr, len);
+ return written;
+}
+
+/* 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 (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ unsigned int val;
+ char membuf[sizeof (int) * 2 + 1];
+ char *p;
+ char *cmd;
+
+ monitor_debug ("MON read single\n");
+#if 0
+ /* Can't actually use long longs (nice idea, though). In fact, the
+ call to strtoul below will fail if it tries to convert a value
+ that's too big to fit in a long. */
+ if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->getmem.cmdll)
+ {
+ len = 8;
+ cmd = current_monitor->getmem.cmdll;
+ }
+ else
+#endif
+ 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 memory value. Otherwise, we just start
+ searching from the start of the buf. */
+
+ if (current_monitor->getmem.resp_delim)
+ {
+ monitor_debug ("EXP getmem.resp_delim\n");
+ monitor_expect_regexp (&getmem_resp_delim_pattern, NULL, 0);
+ }
+
+ /* Now, read the appropriate number of hex digits for this loc,
+ skipping spaces. */
+
+ /* Skip leading spaces and "0x" if MO_HEX_PREFIX flag is set. */
+ if (current_monitor->flags & MO_HEX_PREFIX)
+ {
+ int c;
+
+ c = readchar (timeout);
+ while (c == ' ')
+ c = readchar (timeout);
+ if ((c == '0') && ((c = readchar (timeout)) == 'x'))
+ ;
+ else
+ monitor_error ("monitor_read_memory_single",
+ "bad response from monitor",
+ memaddr, 0, NULL, 0);
+ }
+
+ {
+ int i;
+ for (i = 0; i < len * 2; i++)
+ {
+ int c;
+
+ while (1)
+ {
+ c = readchar (timeout);
+ if (isxdigit (c))
+ break;
+ if (c == ' ')
+ continue;
+
+ monitor_error ("monitor_read_memory_single",
+ "bad response from monitor",
+ memaddr, i, membuf, 0);
+ }
+ 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)
+ monitor_error ("monitor_read_memory_single",
+ "bad value from monitor",
+ memaddr, 0, membuf, 0);
+
+ /* 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 do no more
+ than 16 bytes at a time. */
+
+static int
+monitor_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ unsigned int val;
+ char buf[512];
+ char *p, *p1;
+ int resp_len;
+ int i;
+ CORE_ADDR dumpaddr;
+
+ if (len <= 0)
+ {
+ monitor_debug ("Zero length call to monitor_read_memory\n");
+ return 0;
+ }
+
+ monitor_debug ("MON read block ta(%s) ha(%lx) %d\n",
+ paddr_nz (memaddr), (long) myaddr, len);
+
+ if (current_monitor->flags & MO_ADDR_BITS_REMOVE)
+ memaddr = ADDR_BITS_REMOVE (memaddr);
+
+ if (current_monitor->flags & MO_GETMEM_READ_SINGLE)
+ return monitor_read_memory_single (memaddr, myaddr, len);
+
+ len = min (len, 16);
+
+ /* Some dumpers align the first data with the preceeding 16
+ byte boundary. Some print blanks and start at the
+ requested boundary. EXACT_DUMPADDR
+ */
+
+ dumpaddr = (current_monitor->flags & MO_EXACT_DUMPADDR)
+ ? memaddr : memaddr & ~0x0f;
+
+ /* 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);
+ else if (current_monitor->flags & MO_GETMEM_16_BOUNDARY)
+ monitor_printf (current_monitor->getmem.cmdb, dumpaddr);
+ 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)
+ monitor_error ("monitor_read_memory",
+ "excessive response from monitor",
+ memaddr, resp_len, buf, 0);
+
+ 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;
+ monitor_debug ("MON getmem.resp_delim %s\n", current_monitor->getmem.resp_delim);
+
+ memset (&resp_strings, 0, sizeof (struct re_registers));
+ tmp = strlen (p);
+ retval = re_search (&getmem_resp_delim_pattern, p, tmp, 0, tmp,
+ &resp_strings);
+
+ if (retval < 0)
+ monitor_error ("monitor_read_memory",
+ "bad response from monitor",
+ memaddr, resp_len, buf, 0);
+
+ p += resp_strings.end[0];
+#if 0
+ p = strstr (p, current_monitor->getmem.resp_delim);
+ if (!p)
+ monitor_error ("monitor_read_memory",
+ "bad response from monitor",
+ memaddr, resp_len, buf, 0);
+ p += strlen (current_monitor->getmem.resp_delim);
+#endif
+ }
+ monitor_debug ("MON scanning %d ,%lx '%s'\n", len, (long) p, p);
+ if (current_monitor->flags & MO_GETMEM_16_BOUNDARY)
+ {
+ char c;
+ int fetched = 0;
+ i = len;
+ c = *p;
+
+
+ while (!(c == '\000' || c == '\n' || c == '\r') && i > 0)
+ {
+ if (isxdigit (c))
+ {
+ if ((dumpaddr >= memaddr) && (i > 0))
+ {
+ val = fromhex (c) * 16 + fromhex (*(p + 1));
+ *myaddr++ = val;
+ if (monitor_debug_p || remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "[%02x]", val);
+ --i;
+ fetched++;
+ }
+ ++dumpaddr;
+ ++p;
+ }
+ ++p; /* skip a blank or other non hex char */
+ c = *p;
+ }
+ if (fetched == 0)
+ error ("Failed to read via monitor");
+ if (monitor_debug_p || remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ return fetched; /* Return the number of bytes actually read */
+ }
+ monitor_debug ("MON scanning bytes\n");
+
+ 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')
+ monitor_error ("monitor_read_memory",
+ "badly terminated response from monitor",
+ memaddr, resp_len, buf, 0);
+ p++;
+ }
+
+ val = strtoul (p, &p1, 16);
+
+ if (val == 0 && p == p1)
+ monitor_error ("monitor_read_memory",
+ "bad value from monitor",
+ memaddr, resp_len, buf, 0);
+
+ *myaddr++ = val;
+
+ if (i == 1)
+ break;
+
+ p = p1;
+ }
+
+ return len;
+}
+
+/* Transfer LEN bytes between target address MEMADDR and GDB address
+ MYADDR. Returns 0 for success, errno code for failure. TARGET is
+ unused. */
+
+static int
+monitor_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int res;
+
+ if (write)
+ {
+ if (current_monitor->flags & MO_HAS_BLOCKWRITES)
+ res = monitor_write_memory_block(memaddr, myaddr, len);
+ else
+ res = monitor_write_memory(memaddr, myaddr, len);
+ }
+ else
+ {
+ res = monitor_read_memory(memaddr, myaddr, len);
+ }
+
+ return res;
+}
+
+static void
+monitor_kill (void)
+{
+ 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 (char *exec_file, char *args, char **env)
+{
+ if (args && (*args != '\000'))
+ error ("Args are not supported by the monitor.");
+
+ first_time = 1;
+ 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 (void)
+{
+ unpush_target (targ_ops);
+ generic_mourn_inferior (); /* Do all the proper things now */
+}
+
+/* Tell the monitor to add a breakpoint. */
+
+static int
+monitor_insert_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int i;
+ const unsigned char *bp;
+ int bplen;
+
+ monitor_debug ("MON inst bkpt %s\n", paddr (addr));
+ if (current_monitor->set_break == NULL)
+ error ("No set_break defined for this monitor");
+
+ if (current_monitor->flags & MO_ADDR_BITS_REMOVE)
+ addr = ADDR_BITS_REMOVE (addr);
+
+ /* Determine appropriate breakpoint size for this address. */
+ bp = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &bplen);
+
+ for (i = 0; i < current_monitor->num_breakpoints; i++)
+ {
+ if (breakaddr[i] == 0)
+ {
+ breakaddr[i] = addr;
+ monitor_read_memory (addr, shadow, bplen);
+ monitor_printf (current_monitor->set_break, addr);
+ monitor_expect_prompt (NULL, 0);
+ return 0;
+ }
+ }
+
+ error ("Too many breakpoints (> %d) for monitor.", current_monitor->num_breakpoints);
+}
+
+/* Tell the monitor to remove a breakpoint. */
+
+static int
+monitor_remove_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int i;
+
+ monitor_debug ("MON rmbkpt %s\n", paddr (addr));
+ if (current_monitor->clr_break == NULL)
+ error ("No clr_break defined for this monitor");
+
+ if (current_monitor->flags & MO_ADDR_BITS_REMOVE)
+ addr = ADDR_BITS_REMOVE (addr);
+
+ for (i = 0; i < current_monitor->num_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 (current_monitor->clr_break, addr);
+ else if (current_monitor->flags & MO_CLR_BREAK_1_BASED)
+ monitor_printf (current_monitor->clr_break, i + 1);
+ else
+ monitor_printf (current_monitor->clr_break, i);
+ monitor_expect_prompt (NULL, 0);
+ return 0;
+ }
+ }
+ fprintf_unfiltered (gdb_stderr,
+ "Can't find breakpoint associated with 0x%s\n",
+ paddr_nz (addr));
+ return 1;
+}
+
+/* monitor_wait_srec_ack -- wait for the target to send an acknowledgement for
+ an S-record. Return non-zero if the ACK is received properly. */
+
+static int
+monitor_wait_srec_ack (void)
+{
+ int ch;
+
+ if (current_monitor->flags & MO_SREC_ACK_PLUS)
+ {
+ return (readchar (timeout) == '+');
+ }
+ else if (current_monitor->flags & MO_SREC_ACK_ROTATE)
+ {
+ /* Eat two backspaces, a "rotating" char (|/-\), and a space. */
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ if ((ch = readchar (1)) < 0)
+ return 0;
+ }
+ return 1;
+}
+
+/* monitor_load -- download a file. */
+
+static void
+monitor_load (char *file, int from_tty)
+{
+ monitor_debug ("MON load\n");
+
+ if (current_monitor->load_routine)
+ current_monitor->load_routine (monitor_desc, file, hashmark);
+ else
+ { /* The default is ascii S-records */
+ int n;
+ unsigned long load_offset;
+ char buf[128];
+
+ /* enable user to specify address for downloading as 2nd arg to load */
+ n = sscanf (file, "%s 0x%lx", buf, &load_offset);
+ if (n > 1)
+ file = buf;
+ else
+ load_offset = 0;
+
+ monitor_printf (current_monitor->load);
+ if (current_monitor->loadresp)
+ monitor_expect (current_monitor->loadresp, NULL, 0);
+
+ load_srec (monitor_desc, file, (bfd_vma) load_offset,
+ 32, SREC_ALL, hashmark,
+ current_monitor->flags & MO_SREC_ACK ?
+ monitor_wait_srec_ack : NULL);
+
+ 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));
+
+ /* There used to be code here which would clear inferior_ptid and
+ call clear_symtab_users. None of that should be necessary:
+ monitor targets should behave like remote protocol targets, and
+ since generic_load does none of those things, this function
+ shouldn't either.
+
+ Furthermore, clearing inferior_ptid is *incorrect*. After doing
+ a load, we still have a valid connection to the monitor, with a
+ live processor state to fiddle with. The user can type
+ `continue' or `jump *start' and make the program run. If they do
+ these things, however, GDB will be talking to a running program
+ while inferior_ptid is null_ptid; this makes things like
+ reinit_frame_cache very confused. */
+}
+
+static void
+monitor_stop (void)
+{
+ monitor_debug ("MON stop\n");
+ 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 out to MONITOR. Output from MONITOR is placed
+ in OUTPUT until the prompt is seen. FIXME: We read the characters
+ ourseleves here cause of a nasty echo. */
+
+static void
+monitor_rcmd (char *command,
+ struct ui_file *outbuf)
+{
+ char *p;
+ int resp_len;
+ char buf[1000];
+
+ if (monitor_desc == NULL)
+ error ("monitor target not open.");
+
+ p = current_monitor->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", (command ? command : ""));
+
+ resp_len = monitor_expect_prompt (buf, sizeof buf);
+
+ fputs_unfiltered (buf, outbuf); /* Output the response */
+}
+
+/* Convert hex digit A to a number. */
+
+#if 0
+static int
+from_hex (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);
+}
+#endif
+
+char *
+monitor_get_dev_name (void)
+{
+ return dev_name;
+}
+
+static struct target_ops monitor_ops;
+
+static void
+init_base_monitor_ops (void)
+{
+ monitor_ops.to_close = monitor_close;
+ monitor_ops.to_detach = monitor_detach;
+ monitor_ops.to_resume = monitor_resume;
+ monitor_ops.to_wait = monitor_wait;
+ monitor_ops.to_fetch_registers = monitor_fetch_registers;
+ monitor_ops.to_store_registers = monitor_store_registers;
+ monitor_ops.to_prepare_to_store = monitor_prepare_to_store;
+ monitor_ops.to_xfer_memory = monitor_xfer_memory;
+ monitor_ops.to_files_info = monitor_files_info;
+ monitor_ops.to_insert_breakpoint = monitor_insert_breakpoint;
+ monitor_ops.to_remove_breakpoint = monitor_remove_breakpoint;
+ monitor_ops.to_kill = monitor_kill;
+ monitor_ops.to_load = monitor_load;
+ monitor_ops.to_create_inferior = monitor_create_inferior;
+ monitor_ops.to_mourn_inferior = monitor_mourn_inferior;
+ monitor_ops.to_stop = monitor_stop;
+ monitor_ops.to_rcmd = monitor_rcmd;
+ monitor_ops.to_stratum = process_stratum;
+ monitor_ops.to_has_all_memory = 1;
+ monitor_ops.to_has_memory = 1;
+ monitor_ops.to_has_stack = 1;
+ monitor_ops.to_has_registers = 1;
+ monitor_ops.to_has_execution = 1;
+ monitor_ops.to_magic = OPS_MAGIC;
+} /* init_base_monitor_ops */
+
+/* Init the target_ops structure pointed at by OPS */
+
+void
+init_monitor_ops (struct target_ops *ops)
+{
+ if (monitor_ops.to_magic != OPS_MAGIC)
+ init_base_monitor_ops ();
+
+ memcpy (ops, &monitor_ops, sizeof monitor_ops);
+}
+
+/* Define additional commands that are usually only used by monitors. */
+
+extern initialize_file_ftype _initialize_remote_monitors; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_monitors (void)
+{
+ init_base_monitor_ops ();
+ 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_show_from_set
+ (add_set_cmd ("monitor", no_class, var_zinteger,
+ (char *) &monitor_debug_p,
+ "Set debugging of remote monitor communication.\n\
+When enabled, communication between GDB and the remote monitor\n\
+is displayed.", &setdebuglist),
+ &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/monitor.h b/contrib/gdb/gdb/monitor.h
new file mode 100644
index 0000000..2f8ca22
--- /dev/null
+++ b/contrib/gdb/gdb/monitor.h
@@ -0,0 +1,260 @@
+/* Definitions for remote debugging interface for ROM monitors.
+ Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ 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.
+ */
+
+#ifndef MONITOR_H
+#define MONITOR_H
+
+struct target_waitstatus;
+struct serial;
+
+/* 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. If NULL, monitor implementation
+ sets its own to_insert_breakpoint method. */
+ 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) (char *name, int namelen, char *val, int vallen);
+ void (*load_routine) (struct serial *desc, char *file,
+ int hashmark); /* Download routine */
+ int (*dumpregs) (void); /* routine to dump all registers */
+ int (*continue_hook) (void); /* Emit the continue command */
+ int (*wait_filter) (char *buf, /* Maybe contains registers */
+ int bufmax,
+ int *response_length,
+ struct target_waitstatus * status);
+ 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 */
+ /* deprecated: use regname instead */
+ const char *(*regname) (int index);
+ /* function for dynamic regname array */
+ int num_breakpoints; /* If set_break != NULL, number of supported
+ breakpoints */
+ int magic; /* Check value */
+ };
+
+/* The monitor ops magic number, used to detect if an ops structure doesn't
+ have the right number of entries filled in. */
+
+#define MONITOR_OPS_MAGIC 600925
+
+/* Flag definitions. */
+
+/* If set, then clear breakpoint command uses address, otherwise it
+ uses an index returned by the monitor. */
+
+#define MO_CLR_BREAK_USES_ADDR 0x1
+
+/* If set, then memory fill command uses STARTADDR, ENDADDR+1, VALUE
+ as args, else it uses STARTADDR, LENGTH, VALUE as args. */
+
+#define MO_FILL_USES_ADDR 0x2
+
+/* If set, then monitor doesn't automatically supply register dump
+ when coming back after a continue. */
+
+#define MO_NEED_REGDUMP_AFTER_CONT 0x4
+
+/* getmem needs start addr and end addr */
+
+#define MO_GETMEM_NEEDS_RANGE 0x8
+
+/* getmem can only read one loc at a time */
+
+#define MO_GETMEM_READ_SINGLE 0x10
+
+/* handle \r\n combinations */
+
+#define MO_HANDLE_NL 0x20
+
+/* don't expect echos in monitor_open */
+
+#define MO_NO_ECHO_ON_OPEN 0x40
+
+/* If set, send break to stop monitor */
+
+#define MO_SEND_BREAK_ON_STOP 0x80
+
+/* If set, target sends an ACK after each S-record */
+
+#define MO_SREC_ACK 0x100
+
+/* Allow 0x prefix on addresses retured from monitor */
+
+#define MO_HEX_PREFIX 0x200
+
+/* Some monitors require a different command when starting a program */
+
+#define MO_RUN_FIRST_TIME 0x400
+
+/* Don't expect echos when getting memory */
+
+#define MO_NO_ECHO_ON_SETMEM 0x800
+
+/* If set, then register store command expects value BEFORE regname */
+
+#define MO_REGISTER_VALUE_FIRST 0x1000
+
+/* If set, then the monitor displays registers as pairs. */
+
+#define MO_32_REGS_PAIRED 0x2000
+
+/* If set, then register setting happens interactively. */
+
+#define MO_SETREG_INTERACTIVE 0x4000
+
+/* If set, then memory setting happens interactively. */
+
+#define MO_SETMEM_INTERACTIVE 0x8000
+
+/* If set, then memory dumps are always on 16-byte boundaries, even
+ when less is desired. */
+
+#define MO_GETMEM_16_BOUNDARY 0x10000
+
+/* If set, then the monitor numbers its breakpoints starting from 1. */
+
+#define MO_CLR_BREAK_1_BASED 0x20000
+
+/* If set, then the monitor acks srecords with a plus sign. */
+
+#define MO_SREC_ACK_PLUS 0x40000
+
+/* If set, then the monitor "acks" srecords with rotating lines. */
+
+#define MO_SREC_ACK_ROTATE 0x80000
+
+/* If set, then remove useless address bits from memory addresses. */
+
+#define MO_ADDR_BITS_REMOVE 0x100000
+
+/* If set, then display target program output if prefixed by ^O. */
+
+#define MO_PRINT_PROGRAM_OUTPUT 0x200000
+
+/* Some dump bytes commands align the first data with the preceeding
+ 16 byte boundary. Some print blanks and start at the exactly the
+ requested boundary. */
+
+#define MO_EXACT_DUMPADDR 0x400000
+
+/* Rather entering and exiting the write memory dialog for each word byte,
+ we can save time by transferring the whole block without exiting
+ the memory editing mode. You only need to worry about this
+ if you are doing memory downloading.
+ This engages a new write function registered with dcache.
+ */
+#define MO_HAS_BLOCKWRITES 0x800000
+
+#define SREC_SIZE 160
+
+extern void monitor_open (char *args, struct monitor_ops *ops, int from_tty);
+extern void monitor_close (int quitting);
+extern char *monitor_supply_register (int regno, char *valstr);
+extern int monitor_expect (char *prompt, char *buf, int buflen);
+extern int monitor_expect_prompt (char *buf, int buflen);
+/* Note: The variable argument functions monitor_printf and
+ monitor_printf_noecho vararg do not take take standard format style
+ arguments. Instead they take custom formats interpretered directly
+ by monitor_vsprintf. */
+extern void monitor_printf (char *, ...);
+extern void monitor_printf_noecho (char *, ...);
+extern void monitor_write (char *buf, int buflen);
+extern int monitor_readchar (void);
+extern char *monitor_get_dev_name (void);
+extern void init_monitor_ops (struct target_ops *);
+extern int monitor_dump_reg_block (char *dump_cmd);
+
+#endif
diff --git a/contrib/gdb/gdb/msg.defs b/contrib/gdb/gdb/msg.defs
new file mode 100644
index 0000000..7c9fcd1
--- /dev/null
+++ b/contrib/gdb/gdb/msg.defs
@@ -0,0 +1 @@
+#include <hurd/msg.defs>
diff --git a/contrib/gdb/gdb/msg_reply.defs b/contrib/gdb/gdb/msg_reply.defs
new file mode 100644
index 0000000..049bfa8
--- /dev/null
+++ b/contrib/gdb/gdb/msg_reply.defs
@@ -0,0 +1 @@
+#include <hurd/msg_reply.defs>
diff --git a/contrib/gdb/gdb/nbsd-tdep.c b/contrib/gdb/gdb/nbsd-tdep.c
new file mode 100644
index 0000000..a2d8f7d
--- /dev/null
+++ b/contrib/gdb/gdb/nbsd-tdep.c
@@ -0,0 +1,109 @@
+/* Common target-dependent code for NetBSD systems.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "solib-svr4.h"
+
+/* Fetch (and possibly build) an appropriate link_map_offsets
+ structure for NetBSD targets using the struct offsets defined
+ in <link.h> (but without actual reference to that file).
+
+ This makes it possible to access NetBSD shared libraries from a
+ GDB that was not built on the same platform (for cross debugging).
+
+ We provide versions for ILP32 and LP64 NetBSD targets here. */
+
+struct link_map_offsets *
+nbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 16;
+
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 20;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+struct link_map_offsets *
+nbsd_lp64_solib_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 32;
+
+ lmo.r_map_offset = 8;
+ lmo.r_map_size = 8;
+
+ lmo.link_map_size = 40;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 8;
+
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 8;
+
+ lmo.l_next_offset = 24;
+ lmo.l_next_size = 8;
+
+ lmo.l_prev_offset = 32;
+ lmo.l_prev_size = 8;
+ }
+
+ return lmp;
+}
+
+int
+nbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ /* Check for libc-provided signal trampoline. All such trampolines
+ have function names which begin with "__sigtramp". */
+
+ return (func_name != NULL
+ && strncmp (func_name, "__sigtramp", 10) == 0);
+}
diff --git a/contrib/gdb/gdb/nbsd-tdep.h b/contrib/gdb/gdb/nbsd-tdep.h
new file mode 100644
index 0000000..9d26ae9
--- /dev/null
+++ b/contrib/gdb/gdb/nbsd-tdep.h
@@ -0,0 +1,30 @@
+/* Common target-dependent definitions for NetBSD systems.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 NBSD_TDEP_H
+#define NBSD_TDEP_H
+
+struct link_map_offsets *nbsd_ilp32_solib_svr4_fetch_link_map_offsets (void);
+struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);
+
+int nbsd_pc_in_sigtramp (CORE_ADDR, char *);
+
+#endif /* NBSD_TDEP_H */
diff --git a/contrib/gdb/gdb/nlmread.c b/contrib/gdb/gdb/nlmread.c
new file mode 100644
index 0000000..4e9c87d
--- /dev/null
+++ b/contrib/gdb/gdb/nlmread.c
@@ -0,0 +1,248 @@
+/* Read NLM (NetWare Loadable Module) format executable files for GDB.
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000
+ 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 "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "block.h"
+
+extern void _initialize_nlmread (void);
+
+static void nlm_new_init (struct objfile *);
+
+static void nlm_symfile_init (struct objfile *);
+
+static void nlm_symfile_read (struct objfile *, int);
+
+static void nlm_symfile_finish (struct objfile *);
+
+static void nlm_symtab_read (bfd *, CORE_ADDR, 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 (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 (struct objfile *ignore)
+{
+}
+
+/*
+
+ 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 (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 (xfree, 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;
+
+ prim_record_minimal_symbol (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 (struct objfile *objfile, 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 ();
+
+ /* FIXME, should take a section_offsets param, not just an offset. */
+
+ offset = ANOFFSET (objfile->section_offsets, 0);
+
+ /* Process the NLM export records, which become the bfd's canonical symbol
+ table. */
+
+ nlm_symtab_read (abfd, offset, 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);
+
+ stabsect_build_psymtabs (objfile, mainline, ".stab",
+ ".stabstr", ".text");
+
+ mainsym = lookup_symbol (main_name (), NULL, VAR_DOMAIN, 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. */
+}
+
+
+/* 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 (struct objfile *objfile)
+{
+ if (objfile->sym_private != NULL)
+ {
+ xmfree (objfile->md, objfile->sym_private);
+ }
+}
+
+/* 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 */
+ default_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_nlmread (void)
+{
+ 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 0000000..2014be5
--- /dev/null
+++ b/contrib/gdb/gdb/notify.defs
@@ -0,0 +1 @@
+#include <mach/notify.defs>
diff --git a/contrib/gdb/gdb/nto-procfs.c b/contrib/gdb/gdb/nto-procfs.c
new file mode 100755
index 0000000..00b4096
--- /dev/null
+++ b/contrib/gdb/gdb/nto-procfs.c
@@ -0,0 +1,1389 @@
+/* Machine independent support for QNX Neutrino /proc (process file system)
+ for GDB. Written by Colin Burgess at QNX Software Systems Limited.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by QNX Software Systems Ltd.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <fcntl.h>
+#include <spawn.h>
+#include <sys/debug.h>
+#include <sys/procfs.h>
+#include <sys/neutrino.h>
+#include <sys/syspage.h>
+#include "gdb_dirent.h"
+#include <sys/netmgr.h>
+
+#include "gdb_string.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "target.h"
+#include "objfiles.h"
+#include "gdbthread.h"
+#include "nto-tdep.h"
+#include "command.h"
+#include "regcache.h"
+
+#define NULL_PID 0
+#define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\
+ _DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY)
+
+static struct target_ops procfs_ops;
+
+int ctl_fd;
+
+static void (*ofunc) ();
+
+static procfs_run run;
+
+static void procfs_open (char *, int);
+
+static int procfs_can_run (void);
+
+static ptid_t procfs_wait (ptid_t, struct target_waitstatus *);
+
+static int procfs_xfer_memory (CORE_ADDR, char *, int, int,
+ struct mem_attrib *attrib,
+ struct target_ops *);
+
+static void procfs_fetch_registers (int);
+
+static void notice_signals (void);
+
+static void init_procfs_ops (void);
+
+static ptid_t do_attach (ptid_t ptid);
+
+static int procfs_can_use_hw_breakpoint (int, int, int);
+
+static int procfs_insert_hw_breakpoint (CORE_ADDR, char *);
+
+static int procfs_remove_hw_breakpoint (CORE_ADDR addr, char *);
+
+static int procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type);
+
+static int procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type);
+
+static int procfs_stopped_by_watchpoint (void);
+
+/* These two globals are only ever set in procfs_open(), but are
+ referenced elsewhere. 'nto_procfs_node' is a flag used to say
+ whether we are local, or we should get the current node descriptor
+ for the remote QNX node. */
+static char nto_procfs_path[PATH_MAX] = { "/proc" };
+static unsigned nto_procfs_node = ND_LOCAL_NODE;
+
+/* Return the current QNX Node, or error out. This is a simple
+ wrapper for the netmgr_strtond() function. The reason this
+ is required is because QNX node descriptors are transient so
+ we have to re-acquire them every time. */
+static unsigned
+nto_node(void)
+{
+ unsigned node;
+
+ if (ND_NODE_CMP(nto_procfs_node, ND_LOCAL_NODE) == 0)
+ return ND_LOCAL_NODE;
+
+ node = netmgr_strtond(nto_procfs_path,0);
+ if (node == -1)
+ error ("Lost the QNX node. Debug session probably over.");
+
+ return (node);
+}
+
+/* This is called when we call 'target procfs <arg>' from the (gdb) prompt.
+ For QNX6 (nto), the only valid arg will be a QNX node string,
+ eg: "/net/some_node". If arg is not a valid QNX node, we will
+ default to local. */
+static void
+procfs_open (char *arg, int from_tty)
+{
+ char *nodestr;
+ char *endstr;
+ char buffer[50];
+ int fd, total_size;
+ procfs_sysinfo *sysinfo;
+
+ /* Set the default node used for spawning to this one,
+ and only override it if there is a valid arg. */
+
+ nto_procfs_node = ND_LOCAL_NODE;
+ nodestr = arg ? xstrdup (arg) : arg;
+
+ init_thread_list ();
+
+ if (nodestr)
+ {
+ nto_procfs_node = netmgr_strtond (nodestr, &endstr);
+ if (nto_procfs_node == -1)
+ {
+ if (errno == ENOTSUP)
+ printf_filtered ("QNX Net Manager not found.\n");
+ printf_filtered ("Invalid QNX node %s: error %d (%s).\n", nodestr,
+ errno, safe_strerror (errno));
+ xfree (nodestr);
+ nodestr = NULL;
+ nto_procfs_node = ND_LOCAL_NODE;
+ }
+ else if (*endstr)
+ {
+ if (*(endstr - 1) == '/')
+ *(endstr - 1) = 0;
+ else
+ *endstr = 0;
+ }
+ }
+ snprintf (nto_procfs_path, PATH_MAX - 1, "%s%s", nodestr ? nodestr : "", "/proc");
+ if (nodestr)
+ xfree (nodestr);
+
+ fd = open (nto_procfs_path, O_RDONLY);
+ if (fd == -1)
+ {
+ printf_filtered ("Error opening %s : %d (%s)\n", nto_procfs_path, errno,
+ safe_strerror (errno));
+ error ("Invalid procfs arg");
+ }
+
+ sysinfo = (void *) buffer;
+ if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, sizeof buffer, 0) != EOK)
+ {
+ printf_filtered ("Error getting size: %d (%s)\n", errno,
+ safe_strerror (errno));
+ close (fd);
+ error ("Devctl failed.");
+ }
+ else
+ {
+ total_size = sysinfo->total_size;
+ sysinfo = alloca (total_size);
+ if (!sysinfo)
+ {
+ printf_filtered ("Memory error: %d (%s)\n", errno,
+ safe_strerror (errno));
+ close (fd);
+ error ("alloca failed.");
+ }
+ else
+ {
+ if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, total_size, 0) != EOK)
+ {
+ printf_filtered ("Error getting sysinfo: %d (%s)\n", errno,
+ safe_strerror (errno));
+ close (fd);
+ error ("Devctl failed.");
+ }
+ else
+ {
+ if (sysinfo->type !=
+ nto_map_arch_to_cputype (TARGET_ARCHITECTURE->arch_name))
+ {
+ close (fd);
+ error ("Invalid target CPU.");
+ }
+ }
+ }
+ }
+ close (fd);
+ printf_filtered ("Debugging using %s\n", nto_procfs_path);
+}
+
+static void
+procfs_set_thread (ptid_t ptid)
+{
+ pid_t tid;
+
+ tid = ptid_get_tid (ptid);
+ devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0);
+}
+
+/* Return nonzero if the thread TH is still alive. */
+static int
+procfs_thread_alive (ptid_t ptid)
+{
+ pid_t tid;
+
+ tid = ptid_get_tid (ptid);
+ if (devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) == EOK)
+ return 1;
+ return 0;
+}
+
+void
+procfs_find_new_threads (void)
+{
+ procfs_status status;
+ pid_t pid;
+ ptid_t ptid;
+
+ if (ctl_fd == -1)
+ return;
+
+ pid = ptid_get_pid (inferior_ptid);
+
+ for (status.tid = 1;; ++status.tid)
+ {
+ if (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0)
+ != EOK && status.tid != 0)
+ break;
+ ptid = ptid_build (pid, 0, status.tid);
+ if (!in_thread_list (ptid))
+ add_thread (ptid);
+ }
+ return;
+}
+
+void
+procfs_pidlist (char *args, int from_tty)
+{
+ DIR *dp = NULL;
+ struct dirent *dirp = NULL;
+ int fd = -1;
+ char buf[512];
+ procfs_info *pidinfo = NULL;
+ procfs_debuginfo *info = NULL;
+ procfs_status *status = NULL;
+ pid_t num_threads = 0;
+ pid_t pid;
+ char name[512];
+
+ dp = opendir (nto_procfs_path);
+ if (dp == NULL)
+ {
+ fprintf_unfiltered (gdb_stderr, "failed to opendir \"%s\" - %d (%s)",
+ nto_procfs_path, errno, safe_strerror (errno));
+ return;
+ }
+
+ /* Start scan at first pid. */
+ rewinddir (dp);
+
+ do
+ {
+ /* Get the right pid and procfs path for the pid. */
+ do
+ {
+ dirp = readdir (dp);
+ if (dirp == NULL)
+ {
+ closedir (dp);
+ return;
+ }
+ snprintf (buf, 511, "%s/%s/as", nto_procfs_path, dirp->d_name);
+ pid = atoi (dirp->d_name);
+ }
+ while (pid == 0);
+
+ /* Open the procfs path. */
+ fd = open (buf, O_RDONLY);
+ if (fd == -1)
+ {
+ fprintf_unfiltered (gdb_stderr, "failed to open %s - %d (%s)\n",
+ buf, errno, safe_strerror (errno));
+ closedir (dp);
+ return;
+ }
+
+ pidinfo = (procfs_info *) buf;
+ if (devctl (fd, DCMD_PROC_INFO, pidinfo, sizeof (buf), 0) != EOK)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "devctl DCMD_PROC_INFO failed - %d (%s)\n", errno,
+ safe_strerror (errno));
+ break;
+ }
+ num_threads = pidinfo->num_threads;
+
+ info = (procfs_debuginfo *) buf;
+ if (devctl (fd, DCMD_PROC_MAPDEBUG_BASE, info, sizeof (buf), 0) != EOK)
+ strcpy (name, "unavailable");
+ else
+ strcpy (name, info->path);
+
+ /* Collect state info on all the threads. */
+ status = (procfs_status *) buf;
+ for (status->tid = 1; status->tid <= num_threads; status->tid++)
+ {
+ if (devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0) != EOK
+ && status->tid != 0)
+ break;
+ if (status->tid != 0)
+ printf_filtered ("%s - %d/%d\n", name, pid, status->tid);
+ }
+ close (fd);
+ }
+ while (dirp != NULL);
+
+ close (fd);
+ closedir (dp);
+ return;
+}
+
+void
+procfs_meminfo (char *args, int from_tty)
+{
+ procfs_mapinfo *mapinfos = NULL;
+ static int num_mapinfos = 0;
+ procfs_mapinfo *mapinfo_p, *mapinfo_p2;
+ int flags = ~0, err, num, i, j;
+
+ struct
+ {
+ procfs_debuginfo info;
+ char buff[_POSIX_PATH_MAX];
+ } map;
+
+ struct info
+ {
+ unsigned addr;
+ unsigned size;
+ unsigned flags;
+ unsigned debug_vaddr;
+ unsigned long long offset;
+ };
+
+ struct printinfo
+ {
+ unsigned long long ino;
+ unsigned dev;
+ struct info text;
+ struct info data;
+ char name[256];
+ } printme;
+
+ /* Get the number of map entrys. */
+ err = devctl (ctl_fd, DCMD_PROC_MAPINFO, NULL, 0, &num);
+ if (err != EOK)
+ {
+ printf ("failed devctl num mapinfos - %d (%s)\n", err, safe_strerror (err));
+ return;
+ }
+
+ mapinfos = xmalloc (num * sizeof (procfs_mapinfo));
+
+ num_mapinfos = num;
+ mapinfo_p = mapinfos;
+
+ /* Fill the map entrys. */
+ err = devctl (ctl_fd, DCMD_PROC_MAPINFO, mapinfo_p, num
+ * sizeof (procfs_mapinfo), &num);
+ if (err != EOK)
+ {
+ printf ("failed devctl mapinfos - %d (%s)\n", err, safe_strerror (err));
+ xfree (mapinfos);
+ return;
+ }
+
+ num = min (num, num_mapinfos);
+
+ /* Run through the list of mapinfos, and store the data and text info
+ so we can print it at the bottom of the loop. */
+ for (mapinfo_p = mapinfos, i = 0; i < num; i++, mapinfo_p++)
+ {
+ if (!(mapinfo_p->flags & flags))
+ mapinfo_p->ino = 0;
+
+ if (mapinfo_p->ino == 0) /* Already visited. */
+ continue;
+
+ map.info.vaddr = mapinfo_p->vaddr;
+
+ err = devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
+ if (err != EOK)
+ continue;
+
+ memset (&printme, 0, sizeof printme);
+ printme.dev = mapinfo_p->dev;
+ printme.ino = mapinfo_p->ino;
+ printme.text.addr = mapinfo_p->vaddr;
+ printme.text.size = mapinfo_p->size;
+ printme.text.flags = mapinfo_p->flags;
+ printme.text.offset = mapinfo_p->offset;
+ printme.text.debug_vaddr = map.info.vaddr;
+ strcpy (printme.name, map.info.path);
+
+ /* Check for matching data. */
+ for (mapinfo_p2 = mapinfos, j = 0; j < num; j++, mapinfo_p2++)
+ {
+ if (mapinfo_p2->vaddr != mapinfo_p->vaddr
+ && mapinfo_p2->ino == mapinfo_p->ino
+ && mapinfo_p2->dev == mapinfo_p->dev)
+ {
+ map.info.vaddr = mapinfo_p2->vaddr;
+ err =
+ devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
+ if (err != EOK)
+ continue;
+
+ if (strcmp (map.info.path, printme.name))
+ continue;
+
+ /* Lower debug_vaddr is always text, if nessessary, swap. */
+ if ((int) map.info.vaddr < (int) printme.text.debug_vaddr)
+ {
+ memcpy (&(printme.data), &(printme.text),
+ sizeof (printme.data));
+ printme.text.addr = mapinfo_p2->vaddr;
+ printme.text.size = mapinfo_p2->size;
+ printme.text.flags = mapinfo_p2->flags;
+ printme.text.offset = mapinfo_p2->offset;
+ printme.text.debug_vaddr = map.info.vaddr;
+ }
+ else
+ {
+ printme.data.addr = mapinfo_p2->vaddr;
+ printme.data.size = mapinfo_p2->size;
+ printme.data.flags = mapinfo_p2->flags;
+ printme.data.offset = mapinfo_p2->offset;
+ printme.data.debug_vaddr = map.info.vaddr;
+ }
+ mapinfo_p2->ino = 0;
+ }
+ }
+ mapinfo_p->ino = 0;
+
+ printf_filtered ("%s\n", printme.name);
+ printf_filtered ("\ttext=%08x bytes @ 0x%08x\n", printme.text.size,
+ printme.text.addr);
+ printf_filtered ("\t\tflags=%08x\n", printme.text.flags);
+ printf_filtered ("\t\tdebug=%08x\n", printme.text.debug_vaddr);
+ printf_filtered ("\t\toffset=%016llx\n", printme.text.offset);
+ if (printme.data.size)
+ {
+ printf_filtered ("\tdata=%08x bytes @ 0x%08x\n", printme.data.size,
+ printme.data.addr);
+ printf_filtered ("\t\tflags=%08x\n", printme.data.flags);
+ printf_filtered ("\t\tdebug=%08x\n", printme.data.debug_vaddr);
+ printf_filtered ("\t\toffset=%016llx\n", printme.data.offset);
+ }
+ printf_filtered ("\tdev=0x%x\n", printme.dev);
+ printf_filtered ("\tino=0x%x\n", (unsigned int) printme.ino);
+ }
+ xfree (mapinfos);
+ return;
+}
+
+/* Print status information about what we're accessing. */
+static void
+procfs_files_info (struct target_ops *ignore)
+{
+ printf_unfiltered ("\tUsing the running image of %s %s via %s.\n",
+ attach_flag ? "attached" : "child",
+ target_pid_to_str (inferior_ptid), nto_procfs_path);
+}
+
+/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
+static int
+procfs_can_run (void)
+{
+ return 1;
+}
+
+/* Attach to process PID, then initialize for debugging it. */
+static void
+procfs_attach (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 ())
+ error ("Attaching GDB to itself is not a good idea...");
+
+ 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_to_ptid (pid)));
+ else
+ printf_unfiltered ("Attaching to %s\n",
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ gdb_flush (gdb_stdout);
+ }
+ inferior_ptid = do_attach (pid_to_ptid (pid));
+ push_target (&procfs_ops);
+}
+
+static void
+procfs_post_attach (pid_t pid)
+{
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ if (exec_bfd)
+ SOLIB_CREATE_INFERIOR_HOOK (pid);
+#endif
+}
+
+static ptid_t
+do_attach (ptid_t ptid)
+{
+ procfs_status status;
+ struct sigevent event;
+ char path[PATH_MAX];
+
+ snprintf (path, PATH_MAX - 1, "%s/%d/as", nto_procfs_path, PIDGET (ptid));
+ ctl_fd = open (path, O_RDWR);
+ if (ctl_fd == -1)
+ error ("Couldn't open proc file %s, error %d (%s)", path, errno,
+ safe_strerror (errno));
+ if (devctl (ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) != EOK)
+ error ("Couldn't stop process");
+
+ /* Define a sigevent for process stopped notification. */
+ event.sigev_notify = SIGEV_SIGNAL_THREAD;
+ event.sigev_signo = SIGUSR1;
+ event.sigev_code = 0;
+ event.sigev_value.sival_ptr = NULL;
+ event.sigev_priority = -1;
+ devctl (ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
+
+ if (devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0) == EOK
+ && status.flags & _DEBUG_FLAG_STOPPED)
+ SignalKill (nto_node(), PIDGET (ptid), 0, SIGCONT, 0, 0);
+ attach_flag = 1;
+ nto_init_solib_absolute_prefix ();
+ return ptid;
+}
+
+/* Ask the user what to do when an interrupt is received. */
+static void
+interrupt_query (void)
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ throw_exception (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+/* The user typed ^C twice. */
+static void
+nto_interrupt_twice (int signo)
+{
+ signal (signo, ofunc);
+ interrupt_query ();
+ signal (signo, nto_interrupt_twice);
+}
+
+static void
+nto_interrupt (int signo)
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, nto_interrupt_twice);
+
+ target_stop ();
+}
+
+static ptid_t
+procfs_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ sigset_t set;
+ siginfo_t info;
+ procfs_status status;
+ static int exit_signo = 0; /* To track signals that cause termination. */
+
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+
+ if (ptid_equal (inferior_ptid, null_ptid))
+ {
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ ourstatus->value.sig = TARGET_SIGNAL_0;
+ exit_signo = 0;
+ return null_ptid;
+ }
+
+ sigemptyset (&set);
+ sigaddset (&set, SIGUSR1);
+
+ devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
+ while (!(status.flags & _DEBUG_FLAG_ISTOP))
+ {
+ ofunc = (void (*)()) signal (SIGINT, nto_interrupt);
+ sigwaitinfo (&set, &info);
+ signal (SIGINT, ofunc);
+ devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
+ }
+
+ if (status.flags & _DEBUG_FLAG_SSTEP)
+ {
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ }
+ /* Was it a breakpoint? */
+ else if (status.flags & _DEBUG_FLAG_TRACE)
+ {
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ }
+ else if (status.flags & _DEBUG_FLAG_ISTOP)
+ {
+ switch (status.why)
+ {
+ case _DEBUG_WHY_SIGNALLED:
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ ourstatus->value.sig =
+ target_signal_from_host (status.info.si_signo);
+ exit_signo = 0;
+ break;
+ case _DEBUG_WHY_FAULTED:
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ if (status.info.si_signo == SIGTRAP)
+ {
+ ourstatus->value.sig = 0;
+ exit_signo = 0;
+ }
+ else
+ {
+ ourstatus->value.sig =
+ target_signal_from_host (status.info.si_signo);
+ exit_signo = ourstatus->value.sig;
+ }
+ break;
+
+ case _DEBUG_WHY_TERMINATED:
+ {
+ int waitval = 0;
+
+ waitpid (PIDGET (inferior_ptid), &waitval, WNOHANG);
+ if (exit_signo)
+ {
+ /* Abnormal death. */
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig = exit_signo;
+ }
+ else
+ {
+ /* Normal death. */
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = WEXITSTATUS (waitval);
+ }
+ exit_signo = 0;
+ break;
+ }
+
+ case _DEBUG_WHY_REQUESTED:
+ /* We are assuming a requested stop is due to a SIGINT. */
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ ourstatus->value.sig = TARGET_SIGNAL_INT;
+ exit_signo = 0;
+ break;
+ }
+ }
+
+ return inferior_ptid;
+}
+
+/* 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 (int regno)
+{
+ union
+ {
+ procfs_greg greg;
+ procfs_fpreg fpreg;
+ procfs_altreg altreg;
+ }
+ reg;
+ int regsize;
+
+ procfs_set_thread (inferior_ptid);
+ if (devctl (ctl_fd, DCMD_PROC_GETGREG, &reg, sizeof (reg), &regsize) == EOK)
+ nto_supply_gregset ((char *) &reg.greg);
+ if (devctl (ctl_fd, DCMD_PROC_GETFPREG, &reg, sizeof (reg), &regsize)
+ == EOK)
+ nto_supply_fpregset ((char *) &reg.fpreg);
+ if (devctl (ctl_fd, DCMD_PROC_GETALTREG, &reg, sizeof (reg), &regsize)
+ == EOK)
+ nto_supply_altregset ((char *) &reg.altreg);
+}
+
+/* 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. */
+static int
+procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int nbytes = 0;
+
+ if (lseek (ctl_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr)
+ {
+ if (dowrite)
+ nbytes = write (ctl_fd, myaddr, len);
+ else
+ nbytes = read (ctl_fd, myaddr, len);
+ if (nbytes < 0)
+ nbytes = 0;
+ }
+ return (nbytes);
+}
+
+/* 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. */
+static void
+procfs_detach (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_ptid));
+ gdb_flush (gdb_stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ if (siggnal)
+ SignalKill (nto_node(), PIDGET (inferior_ptid), 0, siggnal, 0, 0);
+
+ close (ctl_fd);
+ ctl_fd = -1;
+ init_thread_list ();
+ inferior_ptid = null_ptid;
+ attach_flag = 0;
+ unpush_target (&procfs_ops); /* Pop out of handling an inferior. */
+}
+
+static int
+procfs_breakpoint (CORE_ADDR addr, int type, int size)
+{
+ procfs_break brk;
+
+ brk.type = type;
+ brk.addr = addr;
+ brk.size = size;
+ errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
+ if (errno != EOK)
+ return 1;
+ return 0;
+}
+
+static int
+procfs_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, 0);
+}
+
+static int
+procfs_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, -1);
+}
+
+static int
+procfs_insert_hw_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0);
+}
+
+static int
+procfs_remove_hw_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1);
+}
+
+static void
+procfs_resume (ptid_t ptid, int step, enum target_signal signo)
+{
+ int signal_to_pass;
+ procfs_status status;
+
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return;
+
+ procfs_set_thread (ptid_equal (ptid, minus_one_ptid) ? inferior_ptid :
+ ptid);
+
+ run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
+ if (step)
+ run.flags |= _DEBUG_RUN_STEP;
+
+ sigemptyset ((sigset_t *) &run.fault);
+ sigaddset ((sigset_t *) &run.fault, FLTBPT);
+ sigaddset ((sigset_t *) &run.fault, FLTTRACE);
+ sigaddset ((sigset_t *) &run.fault, FLTILL);
+ sigaddset ((sigset_t *) &run.fault, FLTPRIV);
+ sigaddset ((sigset_t *) &run.fault, FLTBOUNDS);
+ sigaddset ((sigset_t *) &run.fault, FLTIOVF);
+ sigaddset ((sigset_t *) &run.fault, FLTIZDIV);
+ sigaddset ((sigset_t *) &run.fault, FLTFPE);
+ /* Peter V will be changing this at some point. */
+ sigaddset ((sigset_t *) &run.fault, FLTPAGE);
+
+ run.flags |= _DEBUG_RUN_ARM;
+
+ sigemptyset (&run.trace);
+ notice_signals ();
+ signal_to_pass = target_signal_to_host (signo);
+
+ if (signal_to_pass)
+ {
+ devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
+ signal_to_pass = target_signal_to_host (signo);
+ if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
+ {
+ if (signal_to_pass != status.info.si_signo)
+ {
+ SignalKill (nto_node(), PIDGET (inferior_ptid), 0, signal_to_pass,
+ 0, 0);
+ run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
+ }
+ else /* Let it kill the program without telling us. */
+ sigdelset (&run.trace, signal_to_pass);
+ }
+ }
+ else
+ run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
+
+ errno = devctl (ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
+ if (errno != EOK)
+ {
+ perror ("run error!\n");
+ return;
+ }
+}
+
+static void
+procfs_mourn_inferior (void)
+{
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ {
+ SignalKill (nto_node(), PIDGET (inferior_ptid), 0, SIGKILL, 0, 0);
+ close (ctl_fd);
+ }
+ inferior_ptid = null_ptid;
+ init_thread_list ();
+ unpush_target (&procfs_ops);
+ generic_mourn_inferior ();
+ attach_flag = 0;
+}
+
+/* This function breaks up an argument string into an argument
+ vector suitable for passing to execvp().
+ E.g., on "run a b c d" this routine would get as input
+ the string "a b c d", and as output it would fill in argv with
+ the four arguments "a", "b", "c", "d". The only additional
+ functionality is simple quoting. The gdb command:
+ run a "b c d" f
+ will fill in argv with the three args "a", "b c d", "e". */
+static void
+breakup_args (char *scratch, char **argv)
+{
+ char *pp, *cp = scratch;
+ char quoting = 0;
+
+ for (;;)
+ {
+ /* Scan past leading separators. */
+ quoting = 0;
+ while (*cp == ' ' || *cp == '\t' || *cp == '\n')
+ cp++;
+
+ /* Break if at end of string. */
+ if (*cp == '\0')
+ break;
+
+ /* Take an arg. */
+ if (*cp == '"')
+ {
+ cp++;
+ quoting = strchr (cp, '"') ? 1 : 0;
+ }
+
+ *argv++ = cp;
+
+ /* Scan for next arg separator. */
+ pp = cp;
+ if (quoting)
+ cp = strchr (pp, '"');
+ if ((cp == NULL) || (!quoting))
+ cp = strchr (pp, ' ');
+ if (cp == NULL)
+ cp = strchr (pp, '\t');
+ if (cp == NULL)
+ cp = strchr (pp, '\n');
+
+ /* No separators => end of string => break. */
+ if (cp == NULL)
+ {
+ pp = cp;
+ break;
+ }
+
+ /* Replace the separator with a terminator. */
+ *cp++ = '\0';
+ }
+
+ /* Execv requires a null-terminated arg vector. */
+ *argv = NULL;
+}
+
+static void
+procfs_create_inferior (char *exec_file, char *allargs, char **env)
+{
+ struct inheritance inherit;
+ pid_t pid;
+ int flags, errn;
+ char **argv, *args;
+ char *in = "", *out = "", *err = "";
+ int fd, fds[3];
+ sigset_t set;
+
+ argv = xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) *
+ sizeof (*argv));
+ argv[0] = get_exec_file (1);
+ if (!argv[0])
+ {
+ if (exec_file)
+ argv[0] = exec_file;
+ else
+ return;
+ }
+
+ args = xstrdup (allargs);
+ breakup_args (args, exec_file ? &argv[1] : &argv[0]);
+
+ argv = nto_parse_redirection (argv, &in, &out, &err);
+
+ fds[0] = STDIN_FILENO;
+ fds[1] = STDOUT_FILENO;
+ fds[2] = STDERR_FILENO;
+
+ /* If the user specified I/O via gdb's --tty= arg, use it, but only
+ if the i/o is not also being specified via redirection. */
+ if (inferior_io_terminal)
+ {
+ if (!in[0])
+ in = inferior_io_terminal;
+ if (!out[0])
+ out = inferior_io_terminal;
+ if (!err[0])
+ err = inferior_io_terminal;
+ }
+
+ if (in[0])
+ {
+ fd = open (in, O_RDONLY);
+ if (fd == -1)
+ perror (in);
+ else
+ fds[0] = fd;
+ }
+ if (out[0])
+ {
+ fd = open (out, O_WRONLY);
+ if (fd == -1)
+ perror (out);
+ else
+ fds[1] = fd;
+ }
+ if (err[0])
+ {
+ fd = open (err, O_WRONLY);
+ if (fd == -1)
+ perror (err);
+ else
+ fds[2] = fd;
+ }
+
+ /* Clear any pending SIGUSR1's but keep the behavior the same. */
+ signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
+
+ sigemptyset (&set);
+ sigaddset (&set, SIGUSR1);
+ sigprocmask (SIG_UNBLOCK, &set, NULL);
+
+ memset (&inherit, 0, sizeof (inherit));
+
+ if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) != 0)
+ {
+ inherit.nd = nto_node();
+ inherit.flags |= SPAWN_SETND;
+ inherit.flags &= ~SPAWN_EXEC;
+ }
+ inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
+ inherit.pgroup = SPAWN_NEWPGROUP;
+ pid = spawnp (argv[0], 3, fds, &inherit, argv,
+ ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0 ? env : 0);
+ xfree (args);
+
+ sigprocmask (SIG_BLOCK, &set, NULL);
+
+ if (pid == -1)
+ error ("Error spawning %s: %d (%s)", argv[0], errno, safe_strerror (errno));
+
+ if (fds[0] != STDIN_FILENO)
+ close (fds[0]);
+ if (fds[1] != STDOUT_FILENO)
+ close (fds[1]);
+ if (fds[2] != STDERR_FILENO)
+ close (fds[2]);
+
+ inferior_ptid = do_attach (pid_to_ptid (pid));
+
+ attach_flag = 0;
+ flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag. */
+ errn = devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0);
+ if (errn != EOK)
+ {
+ /* FIXME: expected warning? */
+ /* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n",
+ errn, strerror(errn) ); */
+ }
+ push_target (&procfs_ops);
+ target_terminal_init ();
+
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ if (exec_bfd != NULL
+ || (symfile_objfile != NULL && symfile_objfile->obfd != NULL))
+ SOLIB_CREATE_INFERIOR_HOOK (pid);
+#endif
+}
+
+static void
+procfs_stop (void)
+{
+ devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0);
+}
+
+static void
+procfs_kill_inferior (void)
+{
+ target_mourn_inferior ();
+}
+
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+ of REGISTERS. */
+static void
+procfs_prepare_to_store (void)
+{
+}
+
+/* Fill buf with regset and return devctl cmd to do the setting. Return
+ -1 if we fail to get the regset. Store size of regset in regsize. */
+static int
+get_regset (int regset, char *buf, int bufsize, int *regsize)
+{
+ int dev_get, dev_set;
+ switch (regset)
+ {
+ case NTO_REG_GENERAL:
+ dev_get = DCMD_PROC_GETGREG;
+ dev_set = DCMD_PROC_SETGREG;
+ break;
+
+ case NTO_REG_FLOAT:
+ dev_get = DCMD_PROC_GETFPREG;
+ dev_set = DCMD_PROC_SETFPREG;
+ break;
+
+ case NTO_REG_ALT:
+ dev_get = DCMD_PROC_GETALTREG;
+ dev_set = DCMD_PROC_SETALTREG;
+ break;
+
+ case NTO_REG_SYSTEM:
+ default:
+ return -1;
+ }
+ if (devctl (ctl_fd, dev_get, &buf, bufsize, regsize) != EOK)
+ return -1;
+
+ return dev_set;
+}
+
+void
+procfs_store_registers (int regno)
+{
+ union
+ {
+ procfs_greg greg;
+ procfs_fpreg fpreg;
+ procfs_altreg altreg;
+ }
+ reg;
+ unsigned off;
+ int len, regset, regsize, dev_set, err;
+ char *data;
+
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return;
+ procfs_set_thread (inferior_ptid);
+
+ if (regno == -1)
+ {
+ for (regset = NTO_REG_GENERAL; regset < NTO_REG_END; regset++)
+ {
+ dev_set = get_regset (regset, (char *) &reg,
+ sizeof (reg), &regsize);
+ if (dev_set == -1)
+ continue;
+
+ if (nto_regset_fill (regset, (char *) &reg) == -1)
+ continue;
+
+ err = devctl (ctl_fd, dev_set, &reg, regsize, 0);
+ if (err != EOK)
+ fprintf_unfiltered (gdb_stderr,
+ "Warning unable to write regset %d: %s\n",
+ regno, safe_strerror (err));
+ }
+ }
+ else
+ {
+ regset = nto_regset_id (regno);
+ if (regset == -1)
+ return;
+
+ dev_set = get_regset (regset, (char *) &reg, sizeof (reg), &regsize);
+ if (dev_set == -1)
+ return;
+
+ len = nto_register_area (regno, regset, &off);
+
+ if (len < 1)
+ return;
+
+ regcache_collect (regno, (char *) &reg + off);
+
+ err = devctl (ctl_fd, dev_set, &reg, regsize, 0);
+ if (err != EOK)
+ fprintf_unfiltered (gdb_stderr,
+ "Warning unable to write regset %d: %s\n", regno,
+ safe_strerror (err));
+ }
+}
+
+static void
+notice_signals (void)
+{
+ int signo;
+
+ for (signo = 1; 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)
+ sigdelset (&run.trace, signo);
+ else
+ sigaddset (&run.trace, signo);
+ }
+}
+
+/* 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. */
+static void
+procfs_notice_signals (ptid_t ptid)
+{
+ sigemptyset (&run.trace);
+ notice_signals ();
+}
+
+static struct tidinfo *
+procfs_thread_info (pid_t pid, short tid)
+{
+/* NYI */
+ return NULL;
+}
+
+char *
+procfs_pid_to_str (ptid_t ptid)
+{
+ static char buf[1024];
+ int pid, tid, n;
+ struct tidinfo *tip;
+
+ pid = ptid_get_pid (ptid);
+ tid = ptid_get_tid (ptid);
+
+ n = snprintf (buf, 1023, "process %d", pid);
+
+#if 0 /* NYI */
+ tip = procfs_thread_info (pid, tid);
+ if (tip != NULL)
+ snprintf (&buf[n], 1023, " (state = 0x%02x)", tip->state);
+#endif
+
+ return buf;
+}
+
+static void
+init_procfs_ops (void)
+{
+ procfs_ops.to_shortname = "procfs";
+ procfs_ops.to_longname = "QNX Neutrino procfs child process";
+ procfs_ops.to_doc =
+ "QNX Neutrino procfs child process (started by the \"run\" command).\n\
+ target procfs <node>";
+ procfs_ops.to_open = procfs_open;
+ procfs_ops.to_attach = procfs_attach;
+ procfs_ops.to_post_attach = procfs_post_attach;
+ procfs_ops.to_detach = procfs_detach;
+ procfs_ops.to_resume = procfs_resume;
+ procfs_ops.to_wait = procfs_wait;
+ procfs_ops.to_fetch_registers = procfs_fetch_registers;
+ procfs_ops.to_store_registers = procfs_store_registers;
+ procfs_ops.to_prepare_to_store = procfs_prepare_to_store;
+ procfs_ops.to_xfer_memory = procfs_xfer_memory;
+ procfs_ops.to_files_info = procfs_files_info;
+ procfs_ops.to_insert_breakpoint = procfs_insert_breakpoint;
+ procfs_ops.to_remove_breakpoint = procfs_remove_breakpoint;
+ procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint;
+ procfs_ops.to_insert_hw_breakpoint = procfs_insert_hw_breakpoint;
+ procfs_ops.to_remove_hw_breakpoint = procfs_remove_breakpoint;
+ procfs_ops.to_insert_watchpoint = procfs_insert_hw_watchpoint;
+ procfs_ops.to_remove_watchpoint = procfs_remove_hw_watchpoint;
+ procfs_ops.to_stopped_by_watchpoint = procfs_stopped_by_watchpoint;
+ procfs_ops.to_terminal_init = terminal_init_inferior;
+ procfs_ops.to_terminal_inferior = terminal_inferior;
+ procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ procfs_ops.to_terminal_ours = terminal_ours;
+ procfs_ops.to_terminal_info = child_terminal_info;
+ procfs_ops.to_kill = procfs_kill_inferior;
+ procfs_ops.to_create_inferior = procfs_create_inferior;
+ procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
+ procfs_ops.to_can_run = procfs_can_run;
+ procfs_ops.to_notice_signals = procfs_notice_signals;
+ procfs_ops.to_thread_alive = procfs_thread_alive;
+ procfs_ops.to_find_new_threads = procfs_find_new_threads;
+ procfs_ops.to_pid_to_str = procfs_pid_to_str;
+ procfs_ops.to_stop = procfs_stop;
+ procfs_ops.to_stratum = process_stratum;
+ procfs_ops.to_has_all_memory = 1;
+ procfs_ops.to_has_memory = 1;
+ procfs_ops.to_has_stack = 1;
+ procfs_ops.to_has_registers = 1;
+ procfs_ops.to_has_execution = 1;
+ procfs_ops.to_magic = OPS_MAGIC;
+ procfs_ops.to_have_continuable_watchpoint = 1;
+}
+
+#define OSTYPE_NTO 1
+
+void
+_initialize_procfs (void)
+{
+ sigset_t set;
+
+ init_procfs_ops ();
+ add_target (&procfs_ops);
+
+ /* We use SIGUSR1 to gain control after we block waiting for a process.
+ We use sigwaitevent to wait. */
+ sigemptyset (&set);
+ sigaddset (&set, SIGUSR1);
+ sigprocmask (SIG_BLOCK, &set, NULL);
+
+ /* Set up trace and fault sets, as gdb expects them. */
+ sigemptyset (&run.trace);
+ notice_signals ();
+
+ /* Stuff some information. */
+ nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags;
+ nto_cpuinfo_valid = 1;
+
+ add_info ("pidlist", procfs_pidlist, "pidlist");
+ add_info ("meminfo", procfs_meminfo, "memory information");
+}
+
+
+static int
+procfs_hw_watchpoint (int addr, int len, int type)
+{
+ procfs_break brk;
+
+ switch (type)
+ {
+ case 1: /* Read. */
+ brk.type = _DEBUG_BREAK_RD;
+ break;
+ case 2: /* Read/Write. */
+ brk.type = _DEBUG_BREAK_RW;
+ break;
+ default: /* Modify. */
+/* FIXME: brk.type = _DEBUG_BREAK_RWM gives EINVAL for some reason. */
+ brk.type = _DEBUG_BREAK_RW;
+ }
+ brk.type |= _DEBUG_BREAK_HW; /* Always ask for HW. */
+ brk.addr = addr;
+ brk.size = len;
+
+ errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
+ if (errno != EOK)
+ {
+ perror ("Failed to set hardware watchpoint");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
+{
+ return 1;
+}
+
+static int
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ return procfs_hw_watchpoint (addr, -1, type);
+}
+
+static int
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ return procfs_hw_watchpoint (addr, len, type);
+}
+
+static int
+procfs_stopped_by_watchpoint (void)
+{
+ return 0;
+}
diff --git a/contrib/gdb/gdb/nto-tdep.c b/contrib/gdb/gdb/nto-tdep.c
new file mode 100755
index 0000000..056b93f
--- /dev/null
+++ b/contrib/gdb/gdb/nto-tdep.c
@@ -0,0 +1,337 @@
+/* nto-tdep.c - general QNX Neutrino target functionality.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by QNX Software Systems Ltd.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_stat.h"
+#include "gdb_string.h"
+#include "nto-tdep.h"
+#include "top.h"
+#include "cli/cli-decode.h"
+#include "cli/cli-cmds.h"
+#include "inferior.h"
+#include "gdbarch.h"
+#include "bfd.h"
+#include "elf-bfd.h"
+#include "solib-svr4.h"
+#include "gdbcore.h"
+
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif
+
+#ifdef __CYGWIN__
+static char default_nto_target[] = "C:\\QNXsdk\\target\\qnx6";
+#elif defined(__sun__) || defined(linux)
+static char default_nto_target[] = "/opt/QNXsdk/target/qnx6";
+#else
+static char default_nto_target[] = "";
+#endif
+
+struct nto_target_ops current_nto_target;
+
+static char *
+nto_target (void)
+{
+ char *p = getenv ("QNX_TARGET");
+
+#ifdef __CYGWIN__
+ static char buf[PATH_MAX];
+ if (p)
+ cygwin_conv_to_posix_path (p, buf);
+ else
+ cygwin_conv_to_posix_path (default_nto_target, buf);
+ return buf;
+#else
+ return p ? p : default_nto_target;
+#endif
+}
+
+/* Take a string such as i386, rs6000, etc. and map it onto CPUTYPE_X86,
+ CPUTYPE_PPC, etc. as defined in nto-share/dsmsgs.h. */
+int
+nto_map_arch_to_cputype (const char *arch)
+{
+ if (!strcmp (arch, "i386") || !strcmp (arch, "x86"))
+ return CPUTYPE_X86;
+ if (!strcmp (arch, "rs6000") || !strcmp (arch, "powerpc"))
+ return CPUTYPE_PPC;
+ if (!strcmp (arch, "mips"))
+ return CPUTYPE_MIPS;
+ if (!strcmp (arch, "arm"))
+ return CPUTYPE_ARM;
+ if (!strcmp (arch, "sh"))
+ return CPUTYPE_SH;
+ return CPUTYPE_UNKNOWN;
+}
+
+int
+nto_find_and_open_solib (char *solib, unsigned o_flags, char **temp_pathname)
+{
+ char *buf, arch_path[PATH_MAX], *nto_root, *endian;
+ const char *arch;
+ char *path_fmt = "%s/lib:%s/usr/lib:%s/usr/photon/lib\
+:%s/usr/photon/dll:%s/lib/dll";
+
+ nto_root = nto_target ();
+ if (strcmp (TARGET_ARCHITECTURE->arch_name, "i386") == 0)
+ {
+ arch = "x86";
+ endian = "";
+ }
+ else if (strcmp (TARGET_ARCHITECTURE->arch_name, "rs6000") == 0
+ || strcmp (TARGET_ARCHITECTURE->arch_name, "powerpc") == 0)
+ {
+ arch = "ppc";
+ endian = "be";
+ }
+ else
+ {
+ arch = TARGET_ARCHITECTURE->arch_name;
+ endian = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "be" : "le";
+ }
+
+ sprintf (arch_path, "%s/%s%s", nto_root, arch, endian);
+
+ buf = alloca (strlen (path_fmt) + strlen (arch_path) * 5 + 1);
+ sprintf (buf, path_fmt, arch_path, arch_path, arch_path, arch_path,
+ arch_path);
+
+ return openp (buf, 1, solib, o_flags, 0, temp_pathname);
+}
+
+void
+nto_init_solib_absolute_prefix (void)
+{
+ char buf[PATH_MAX * 2], arch_path[PATH_MAX];
+ char *nto_root, *endian;
+ const char *arch;
+
+ nto_root = nto_target ();
+ if (strcmp (TARGET_ARCHITECTURE->arch_name, "i386") == 0)
+ {
+ arch = "x86";
+ endian = "";
+ }
+ else if (strcmp (TARGET_ARCHITECTURE->arch_name, "rs6000") == 0
+ || strcmp (TARGET_ARCHITECTURE->arch_name, "powerpc") == 0)
+ {
+ arch = "ppc";
+ endian = "be";
+ }
+ else
+ {
+ arch = TARGET_ARCHITECTURE->arch_name;
+ endian = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "be" : "le";
+ }
+
+ sprintf (arch_path, "%s/%s%s", nto_root, arch, endian);
+
+ sprintf (buf, "set solib-absolute-prefix %s", arch_path);
+ execute_command (buf, 0);
+}
+
+char **
+nto_parse_redirection (char *pargv[], char **pin, char **pout, char **perr)
+{
+ char **argv;
+ char *in, *out, *err, *p;
+ int argc, i, n;
+
+ for (n = 0; pargv[n]; n++);
+ if (n == 0)
+ return NULL;
+ in = "";
+ out = "";
+ err = "";
+
+ argv = xcalloc (n + 1, sizeof argv[0]);
+ argc = n;
+ for (i = 0, n = 0; n < argc; n++)
+ {
+ p = pargv[n];
+ if (*p == '>')
+ {
+ p++;
+ if (*p)
+ out = p;
+ else
+ out = pargv[++n];
+ }
+ else if (*p == '<')
+ {
+ p++;
+ if (*p)
+ in = p;
+ else
+ in = pargv[++n];
+ }
+ else if (*p++ == '2' && *p++ == '>')
+ {
+ if (*p == '&' && *(p + 1) == '1')
+ err = out;
+ else if (*p)
+ err = p;
+ else
+ err = pargv[++n];
+ }
+ else
+ argv[i++] = pargv[n];
+ }
+ *pin = in;
+ *pout = out;
+ *perr = err;
+ return argv;
+}
+
+/* The struct lm_info, LM_ADDR, and nto_truncate_ptr are copied from
+ solib-svr4.c to support nto_relocate_section_addresses
+ which is different from the svr4 version. */
+
+struct lm_info
+{
+ /* Pointer to copy of link map from inferior. The type is char *
+ rather than void *, so that we may use byte offsets to find the
+ various fields without the need for a cast. */
+ char *lm;
+};
+
+static CORE_ADDR
+LM_ADDR (struct so_list *so)
+{
+ struct link_map_offsets *lmo = nto_fetch_link_map_offsets ();
+
+ return (CORE_ADDR) extract_signed_integer (so->lm_info->lm +
+ lmo->l_addr_offset,
+ lmo->l_addr_size);
+}
+
+static CORE_ADDR
+nto_truncate_ptr (CORE_ADDR addr)
+{
+ if (TARGET_PTR_BIT == sizeof (CORE_ADDR) * 8)
+ /* We don't need to truncate anything, and the bit twiddling below
+ will fail due to overflow problems. */
+ return addr;
+ else
+ return addr & (((CORE_ADDR) 1 << TARGET_PTR_BIT) - 1);
+}
+
+Elf_Internal_Phdr *
+find_load_phdr (bfd *abfd)
+{
+ Elf_Internal_Phdr *phdr;
+ unsigned int i;
+
+ if (!elf_tdata (abfd))
+ return NULL;
+
+ phdr = elf_tdata (abfd)->phdr;
+ for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+ {
+ if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
+ return phdr;
+ }
+ return NULL;
+}
+
+void
+nto_relocate_section_addresses (struct so_list *so, struct section_table *sec)
+{
+ /* Neutrino treats the l_addr base address field in link.h as different than
+ the base address in the System V ABI and so the offset needs to be
+ calculated and applied to relocations. */
+ Elf_Internal_Phdr *phdr = find_load_phdr (sec->bfd);
+ unsigned vaddr = phdr ? phdr->p_vaddr : 0;
+
+ sec->addr = nto_truncate_ptr (sec->addr + LM_ADDR (so) - vaddr);
+ sec->endaddr = nto_truncate_ptr (sec->endaddr + LM_ADDR (so) - vaddr);
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR reg_addr)
+{
+ nto_regset_t regset;
+
+/* See corelow.c:get_core_registers for values of WHICH. */
+ if (which == 0)
+ {
+ memcpy ((char *) &regset, core_reg_sect,
+ min (core_reg_size, sizeof (regset)));
+ nto_supply_gregset ((char *) &regset);
+ }
+ else if (which == 2)
+ {
+ memcpy ((char *) &regset, core_reg_sect,
+ min (core_reg_size, sizeof (regset)));
+ nto_supply_fpregset ((char *) &regset);
+ }
+}
+
+void
+nto_dummy_supply_regset (char *regs)
+{
+ /* Do nothing. */
+}
+
+/* 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, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_nto_tdep (void)
+{
+ add_setshow_cmd ("nto-debug", class_maintenance, var_zinteger,
+ &nto_internal_debugging, "Set QNX NTO internal debugging.\n\
+When non-zero, nto specific debug info is\n\
+displayed. Different information is displayed\n\
+for different positive values.", "Show QNX NTO internal debugging.\n",
+ NULL, NULL, &setdebuglist, &showdebuglist);
+
+ /* We use SIG45 for pulses, or something, so nostop, noprint
+ and pass them. */
+ signal_stop_update (target_signal_from_name ("SIG45"), 0);
+ signal_print_update (target_signal_from_name ("SIG45"), 0);
+ signal_pass_update (target_signal_from_name ("SIG45"), 1);
+
+ /* By default we don't want to stop on these two, but we do want to pass. */
+#if defined(SIGSELECT)
+ signal_stop_update (SIGSELECT, 0);
+ signal_print_update (SIGSELECT, 0);
+ signal_pass_update (SIGSELECT, 1);
+#endif
+
+#if defined(SIGPHOTON)
+ signal_stop_update (SIGPHOTON, 0);
+ signal_print_update (SIGPHOTON, 0);
+ signal_pass_update (SIGPHOTON, 1);
+#endif
+
+ /* Register core file support. */
+ add_core_fns (&regset_core_fns);
+}
diff --git a/contrib/gdb/gdb/nto-tdep.h b/contrib/gdb/gdb/nto-tdep.h
new file mode 100755
index 0000000..e22e8fd
--- /dev/null
+++ b/contrib/gdb/gdb/nto-tdep.h
@@ -0,0 +1,156 @@
+/* nto-tdep.h - QNX Neutrino target header.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by QNX Software Systems Ltd.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _NTO_TDEP_H
+#define _NTO_TDEP_H
+
+#include "defs.h"
+#include "solist.h"
+
+/* Generic functions in nto-tdep.c. */
+
+extern void nto_init_solib_absolute_prefix (void);
+
+char **nto_parse_redirection (char *start_argv[], char **in,
+ char **out, char **err);
+
+int proc_iterate_over_mappings (int (*func) (int, CORE_ADDR));
+
+void nto_relocate_section_addresses (struct so_list *, struct section_table *);
+
+int nto_map_arch_to_cputype (const char *);
+
+int nto_find_and_open_solib (char *, unsigned, char **);
+
+/* Dummy function for initializing nto_target_ops on targets which do
+ not define a particular regset. */
+void nto_dummy_supply_regset (char *regs);
+
+/* Target operations defined for Neutrino targets (<target>-nto-tdep.c). */
+
+struct nto_target_ops
+{
+ int nto_internal_debugging;
+ unsigned nto_cpuinfo_flags;
+ int nto_cpuinfo_valid;
+
+ int (*nto_regset_id) (int);
+ void (*nto_supply_gregset) (char *);
+ void (*nto_supply_fpregset) (char *);
+ void (*nto_supply_altregset) (char *);
+ void (*nto_supply_regset) (int, char *);
+ int (*nto_register_area) (int, int, unsigned *);
+ int (*nto_regset_fill) (int, char *);
+ struct link_map_offsets *(*nto_fetch_link_map_offsets) (void);
+};
+
+extern struct nto_target_ops current_nto_target;
+
+/* For 'maintenance debug nto-debug' command. */
+#define nto_internal_debugging \
+ (current_nto_target.nto_internal_debugging)
+
+/* The CPUINFO flags from the remote. Currently used by
+ i386 for fxsave but future proofing other hosts.
+ This is initialized in procfs_attach or nto_start_remote
+ depending on our host/target. It would only be invalid
+ if we were talking to an older pdebug which didn't support
+ the cpuinfo message. */
+#define nto_cpuinfo_flags \
+ (current_nto_target.nto_cpuinfo_flags)
+
+/* True if successfully retrieved cpuinfo from remote. */
+#define nto_cpuinfo_valid \
+ (current_nto_target.nto_cpuinfo_valid)
+
+/* Given a register, return an id that represents the Neutrino
+ regset it came from. If reg == -1 update all regsets. */
+#define nto_regset_id(reg) \
+ (*current_nto_target.nto_regset_id) (reg)
+
+#define nto_supply_gregset(regs) \
+ (*current_nto_target.nto_supply_gregset) (regs)
+
+#define nto_supply_fpregset(regs) \
+ (*current_nto_target.nto_supply_fpregset) (regs)
+
+#define nto_supply_altregset(regs) \
+ (*current_nto_target.nto_supply_altregset) (regs)
+
+/* Given a regset, tell gdb about registers stored in data. */
+#define nto_supply_regset(regset, data) \
+ (*current_nto_target.nto_supply_regset) (regset, data)
+
+/* Given a register and regset, calculate the offset into the regset
+ and stuff it into the last argument. If regno is -1, calculate the
+ size of the entire regset. Returns length of data, -1 if unknown
+ regset, 0 if unknown register. */
+#define nto_register_area(reg, regset, off) \
+ (*current_nto_target.nto_register_area) (reg, regset, off)
+
+/* Build the Neutrino register set info into the data buffer.
+ Return -1 if unknown regset, 0 otherwise. */
+#define nto_regset_fill(regset, data) \
+ (*current_nto_target.nto_regset_fill) (regset, data)
+
+/* Gives the fetch_link_map_offsets function exposure outside of
+ solib-svr4.c so that we can override relocate_section_addresses(). */
+#define nto_fetch_link_map_offsets() \
+ (*current_nto_target.nto_fetch_link_map_offsets) ()
+
+/* Keep this consistant with neutrino syspage.h. */
+enum
+{
+ CPUTYPE_X86,
+ CPUTYPE_PPC,
+ CPUTYPE_MIPS,
+ CPUTYPE_SPARE,
+ CPUTYPE_ARM,
+ CPUTYPE_SH,
+ CPUTYPE_UNKNOWN
+};
+
+enum
+{
+ OSTYPE_QNX4,
+ OSTYPE_NTO
+};
+
+/* These correspond to the DSMSG_* versions in dsmsgs.h. */
+enum
+{
+ NTO_REG_GENERAL,
+ NTO_REG_FLOAT,
+ NTO_REG_SYSTEM,
+ NTO_REG_ALT,
+ NTO_REG_END
+};
+
+typedef char qnx_reg64[8];
+
+typedef struct _debug_regs
+{
+ qnx_reg64 padding[1024];
+} nto_regset_t;
+
+#endif
diff --git a/contrib/gdb/gdb/objc-exp.c b/contrib/gdb/gdb/objc-exp.c
new file mode 100644
index 0000000..dfeba70
--- /dev/null
+++ b/contrib/gdb/gdb/objc-exp.c
@@ -0,0 +1,3464 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ FLOAT = 259,
+ STRING = 260,
+ NSSTRING = 261,
+ SELECTOR = 262,
+ NAME = 263,
+ TYPENAME = 264,
+ CLASSNAME = 265,
+ NAME_OR_INT = 266,
+ STRUCT = 267,
+ CLASS = 268,
+ UNION = 269,
+ ENUM = 270,
+ SIZEOF = 271,
+ UNSIGNED = 272,
+ COLONCOLON = 273,
+ TEMPLATE = 274,
+ ERROR = 275,
+ SIGNED_KEYWORD = 276,
+ LONG = 277,
+ SHORT = 278,
+ INT_KEYWORD = 279,
+ CONST_KEYWORD = 280,
+ VOLATILE_KEYWORD = 281,
+ DOUBLE_KEYWORD = 282,
+ VARIABLE = 283,
+ ASSIGN_MODIFY = 284,
+ ABOVE_COMMA = 285,
+ OROR = 286,
+ ANDAND = 287,
+ NOTEQUAL = 288,
+ EQUAL = 289,
+ GEQ = 290,
+ LEQ = 291,
+ RSH = 292,
+ LSH = 293,
+ DECREMENT = 294,
+ INCREMENT = 295,
+ UNARY = 296,
+ ARROW = 297,
+ BLOCKNAME = 298
+ };
+#endif
+#define INT 258
+#define FLOAT 259
+#define STRING 260
+#define NSSTRING 261
+#define SELECTOR 262
+#define NAME 263
+#define TYPENAME 264
+#define CLASSNAME 265
+#define NAME_OR_INT 266
+#define STRUCT 267
+#define CLASS 268
+#define UNION 269
+#define ENUM 270
+#define SIZEOF 271
+#define UNSIGNED 272
+#define COLONCOLON 273
+#define TEMPLATE 274
+#define ERROR 275
+#define SIGNED_KEYWORD 276
+#define LONG 277
+#define SHORT 278
+#define INT_KEYWORD 279
+#define CONST_KEYWORD 280
+#define VOLATILE_KEYWORD 281
+#define DOUBLE_KEYWORD 282
+#define VARIABLE 283
+#define ASSIGN_MODIFY 284
+#define ABOVE_COMMA 285
+#define OROR 286
+#define ANDAND 287
+#define NOTEQUAL 288
+#define EQUAL 289
+#define GEQ 290
+#define LEQ 291
+#define RSH 292
+#define LSH 293
+#define DECREMENT 294
+#define INCREMENT 295
+#define UNARY 296
+#define ARROW 297
+#define BLOCKNAME 298
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 37 "objc-exp.y"
+
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include "expression.h"
+
+#include "objc-lang.h" /* For objc language constructs. */
+
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "c-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols. */
+#include "top.h"
+#include "completer.h" /* For skip_quoted(). */
+#include "block.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror,
+ etc), as well as gratuitiously global symbol names, so we can have
+ multiple yacc generated parsers in gdb. Note that these are only
+ the variables produced by yacc. If other parser generators (bison,
+ byacc, etc) produce additional global names that conflict at link
+ time, then those parser generators need to be fixed instead of
+ adding those names to this list. */
+
+#define yymaxdepth objc_maxdepth
+#define yyparse objc_parse
+#define yylex objc_lex
+#define yyerror objc_error
+#define yylval objc_lval
+#define yychar objc_char
+#define yydebug objc_debug
+#define yypact objc_pact
+#define yyr1 objc_r1
+#define yyr2 objc_r2
+#define yydef objc_def
+#define yychk objc_chk
+#define yypgo objc_pgo
+#define yyact objc_act
+#define yyexca objc_exca
+#define yyerrflag objc_errflag
+#define yynerrs objc_nerrs
+#define yyps objc_ps
+#define yypv objc_pv
+#define yys objc_s
+#define yy_yys objc_yys
+#define yystate objc_state
+#define yytmp objc_tmp
+#define yyv objc_v
+#define yy_yyv objc_yyv
+#define yyval objc_val
+#define yylloc objc_lloc
+#define yyreds objc_reds /* With YYDEBUG defined */
+#define yytoks objc_toks /* With YYDEBUG defined */
+#define yyname objc_name /* With YYDEBUG defined */
+#define yyrule objc_rule /* With YYDEBUG defined */
+#define yylhs objc_yylhs
+#define yylen objc_yylen
+#define yydefred objc_yydefred
+#define yydgoto objc_yydgoto
+#define yysindex objc_yysindex
+#define yyrindex objc_yyrindex
+#define yygindex objc_yygindex
+#define yytable objc_yytable
+#define yycheck objc_yycheck
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support. */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 126 "objc-exp.y"
+typedef union YYSTYPE {
+ LONGEST lval;
+ struct {
+ LONGEST val;
+ struct type *type;
+ } typed_val_int;
+ struct {
+ DOUBLEST dval;
+ struct type *type;
+ } typed_val_float;
+ struct symbol *sym;
+ struct type *tval;
+ struct stoken sval;
+ struct ttype tsym;
+ struct symtoken ssym;
+ int voidval;
+ struct block *bval;
+ enum exp_opcode opcode;
+ struct internalvar *ivar;
+ struct objc_class_str class;
+
+ struct type **tvec;
+ int *ivec;
+ } YYSTYPE;
+/* Line 191 of yacc.c. */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+#line 151 "objc-exp.y"
+
+/* YYSTYPE gets defined by %union. */
+static int
+parse_number PARAMS ((char *, int, int, YYSTYPE *));
+
+
+/* Line 214 of yacc.c. */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC xmalloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 89
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 772
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 68
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 29
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 147
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 239
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 298
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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, 61, 2, 2, 2, 52, 38, 2,
+ 58, 65, 50, 48, 30, 49, 56, 51, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 64, 2,
+ 41, 32, 42, 33, 47, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 57, 2, 63, 37, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 66, 36, 67, 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, 31, 34, 35, 39, 40,
+ 43, 44, 45, 46, 53, 54, 55, 59, 60
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 11, 15, 18, 21,
+ 24, 27, 30, 33, 36, 39, 42, 45, 49, 53,
+ 58, 62, 66, 71, 76, 77, 83, 84, 90, 91,
+ 97, 99, 101, 103, 106, 110, 113, 116, 117, 123,
+ 125, 126, 128, 132, 134, 138, 143, 148, 152, 156,
+ 160, 164, 168, 172, 176, 180, 184, 188, 192, 196,
+ 200, 204, 208, 212, 216, 220, 224, 228, 234, 238,
+ 242, 244, 246, 248, 250, 252, 254, 259, 261, 263,
+ 265, 269, 273, 277, 282, 284, 287, 289, 291, 294,
+ 297, 300, 304, 308, 310, 313, 315, 318, 320, 324,
+ 327, 329, 332, 334, 337, 341, 344, 348, 350, 354,
+ 356, 358, 360, 362, 364, 367, 371, 374, 378, 382,
+ 387, 390, 394, 396, 399, 402, 405, 408, 411, 414,
+ 416, 419, 421, 427, 430, 433, 435, 437, 439, 441,
+ 443, 447, 449, 451, 453, 455, 457, 459
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 69, 0, -1, 71, -1, 70, -1, 91, -1, 72,
+ -1, 71, 30, 72, -1, 50, 72, -1, 38, 72,
+ -1, 49, 72, -1, 61, 72, -1, 62, 72, -1,
+ 54, 72, -1, 53, 72, -1, 72, 54, -1, 72,
+ 53, -1, 16, 72, -1, 72, 59, 95, -1, 72,
+ 59, 85, -1, 72, 59, 50, 72, -1, 72, 56,
+ 95, -1, 72, 56, 85, -1, 72, 56, 50, 72,
+ -1, 72, 57, 71, 63, -1, -1, 57, 9, 73,
+ 76, 63, -1, -1, 57, 10, 74, 76, 63, -1,
+ -1, 57, 72, 75, 76, 63, -1, 95, -1, 77,
+ -1, 78, -1, 77, 78, -1, 95, 64, 72, -1,
+ 64, 72, -1, 30, 72, -1, -1, 72, 58, 79,
+ 81, 65, -1, 66, -1, -1, 72, -1, 81, 30,
+ 72, -1, 67, -1, 80, 81, 82, -1, 80, 91,
+ 82, 72, -1, 58, 91, 65, 72, -1, 58, 71,
+ 65, -1, 72, 47, 72, -1, 72, 50, 72, -1,
+ 72, 51, 72, -1, 72, 52, 72, -1, 72, 48,
+ 72, -1, 72, 49, 72, -1, 72, 46, 72, -1,
+ 72, 45, 72, -1, 72, 40, 72, -1, 72, 39,
+ 72, -1, 72, 44, 72, -1, 72, 43, 72, -1,
+ 72, 41, 72, -1, 72, 42, 72, -1, 72, 38,
+ 72, -1, 72, 37, 72, -1, 72, 36, 72, -1,
+ 72, 35, 72, -1, 72, 34, 72, -1, 72, 33,
+ 72, 64, 72, -1, 72, 32, 72, -1, 72, 29,
+ 72, -1, 3, -1, 11, -1, 4, -1, 84, -1,
+ 28, -1, 7, -1, 16, 58, 91, 65, -1, 5,
+ -1, 6, -1, 60, -1, 83, 18, 95, -1, 83,
+ 18, 95, -1, 92, 18, 95, -1, 92, 18, 62,
+ 95, -1, 85, -1, 18, 95, -1, 96, -1, 92,
+ -1, 92, 25, -1, 92, 26, -1, 92, 87, -1,
+ 92, 25, 87, -1, 92, 26, 87, -1, 50, -1,
+ 50, 87, -1, 38, -1, 38, 87, -1, 88, -1,
+ 58, 87, 65, -1, 88, 89, -1, 89, -1, 88,
+ 90, -1, 90, -1, 57, 63, -1, 57, 3, 63,
+ -1, 58, 65, -1, 58, 94, 65, -1, 86, -1,
+ 92, 18, 50, -1, 9, -1, 10, -1, 24, -1,
+ 22, -1, 23, -1, 22, 24, -1, 17, 22, 24,
+ -1, 22, 22, -1, 22, 22, 24, -1, 17, 22,
+ 22, -1, 17, 22, 22, 24, -1, 23, 24, -1,
+ 17, 23, 24, -1, 27, -1, 22, 27, -1, 12,
+ 95, -1, 13, 95, -1, 14, 95, -1, 15, 95,
+ -1, 17, 93, -1, 17, -1, 21, 93, -1, 21,
+ -1, 19, 95, 41, 91, 42, -1, 25, 92, -1,
+ 26, 92, -1, 9, -1, 24, -1, 22, -1, 23,
+ -1, 91, -1, 94, 30, 91, -1, 8, -1, 60,
+ -1, 9, -1, 10, -1, 11, -1, 8, -1, 60,
+ -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 231, 231, 232, 235, 242, 243, 248, 252, 256,
+ 260, 264, 268, 272, 276, 280, 284, 288, 294, 301,
+ 305, 312, 320, 324, 333, 332, 354, 353, 369, 368,
+ 377, 379, 382, 383, 386, 388, 390, 397, 394, 404,
+ 408, 411, 415, 419, 422, 429, 435, 441, 447, 451,
+ 455, 459, 463, 467, 471, 475, 479, 483, 487, 491,
+ 495, 499, 503, 507, 511, 515, 519, 523, 527, 531,
+ 537, 544, 555, 562, 565, 569, 576, 584, 609, 617,
+ 634, 645, 661, 674, 699, 700, 734, 793, 799, 800,
+ 801, 803, 805, 809, 811, 813, 815, 817, 820, 822,
+ 827, 834, 836, 840, 842, 846, 848, 860, 861, 866,
+ 868, 876, 878, 880, 882, 884, 886, 888, 890, 892,
+ 894, 896, 898, 900, 902, 905, 908, 911, 914, 916,
+ 918, 920, 922, 929, 930, 933, 934, 940, 946, 955,
+ 960, 967, 968, 969, 970, 971, 974, 975
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INT", "FLOAT", "STRING", "NSSTRING",
+ "SELECTOR", "NAME", "TYPENAME", "CLASSNAME", "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", "','", "ABOVE_COMMA", "'='", "'?'", "OROR", "ANDAND",
+ "'|'", "'^'", "'&'", "NOTEQUAL", "EQUAL", "'<'", "'>'", "GEQ", "LEQ",
+ "RSH", "LSH", "'@'", "'+'", "'-'", "'*'", "'/'", "'%'", "DECREMENT",
+ "INCREMENT", "UNARY", "'.'", "'['", "'('", "ARROW", "BLOCKNAME", "'!'",
+ "'~'", "']'", "':'", "')'", "'{'", "'}'", "$accept", "start",
+ "type_exp", "exp1", "exp", "@1", "@2", "@3", "msglist", "msgarglist",
+ "msgarg", "@4", "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", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 44, 285, 61, 63, 286, 287, 124, 94, 38, 288,
+ 289, 60, 62, 290, 291, 292, 293, 64, 43, 45,
+ 42, 47, 37, 294, 295, 296, 46, 91, 40, 297,
+ 298, 33, 126, 93, 58, 41, 123, 125
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 68, 69, 69, 70, 71, 71, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 73, 72, 74, 72, 75, 72,
+ 76, 76, 77, 77, 78, 78, 78, 79, 72, 80,
+ 81, 81, 81, 82, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 83,
+ 83, 84, 85, 85, 84, 84, 84, 86, 86, 86,
+ 86, 86, 86, 87, 87, 87, 87, 87, 88, 88,
+ 88, 88, 88, 89, 89, 90, 90, 91, 91, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 93, 93, 93, 93, 94,
+ 94, 95, 95, 95, 95, 95, 96, 96
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 3, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 4,
+ 3, 3, 4, 4, 0, 5, 0, 5, 0, 5,
+ 1, 1, 1, 2, 3, 2, 2, 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, 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, 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, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 0, 70, 72, 77, 78, 75, 146, 109, 110, 71,
+ 0, 0, 0, 0, 0, 129, 0, 0, 131, 112,
+ 113, 111, 0, 0, 122, 74, 0, 0, 0, 0,
+ 0, 0, 0, 147, 0, 0, 39, 0, 3, 2,
+ 5, 40, 0, 73, 84, 107, 4, 87, 86, 141,
+ 143, 144, 145, 142, 124, 125, 126, 127, 0, 16,
+ 0, 135, 137, 138, 136, 128, 85, 0, 137, 138,
+ 130, 116, 114, 123, 120, 133, 134, 8, 9, 7,
+ 13, 12, 24, 26, 28, 0, 0, 10, 11, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 15, 14, 0, 0, 37, 0, 41,
+ 0, 0, 0, 0, 88, 89, 95, 93, 0, 0,
+ 90, 97, 100, 102, 0, 0, 118, 115, 121, 0,
+ 117, 0, 0, 0, 47, 0, 6, 69, 68, 0,
+ 66, 65, 64, 63, 62, 57, 56, 60, 61, 59,
+ 58, 55, 54, 48, 52, 53, 49, 50, 51, 143,
+ 144, 0, 21, 20, 0, 40, 0, 18, 17, 0,
+ 43, 44, 0, 81, 108, 0, 82, 91, 92, 96,
+ 94, 0, 103, 105, 0, 139, 87, 0, 0, 99,
+ 101, 76, 119, 0, 0, 0, 0, 31, 32, 30,
+ 0, 0, 46, 0, 22, 23, 0, 19, 42, 45,
+ 83, 104, 98, 0, 0, 106, 132, 36, 35, 25,
+ 33, 0, 0, 27, 29, 67, 38, 140, 34
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short yydefgoto[] =
+{
+ -1, 37, 38, 85, 40, 141, 142, 143, 206, 207,
+ 208, 175, 41, 120, 181, 42, 43, 44, 45, 130,
+ 131, 132, 133, 195, 60, 65, 197, 209, 48
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -90
+static const short yypact[] =
+{
+ 223, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ 19, 19, 19, 19, 287, 195, 19, 19, 234, 82,
+ -9, -90, 307, 307, -90, -90, 223, 223, 223, 223,
+ 223, 351, 223, 8, 223, 223, -90, 39, -90, 13,
+ 542, 223, 32, -90, -90, -90, -90, 149, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, 223, 212,
+ 38, -90, 33, 45, -90, -90, -90, 30, -90, -90,
+ -90, 83, -90, -90, -90, -90, -90, 212, 212, 212,
+ 212, 212, 107, 108, 542, -20, 66, 212, 212, -90,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, -90, -90, 436, 223, -90, 480, 542,
+ -21, 65, 19, 202, 70, 70, 70, 70, -1, 132,
+ -90, 54, -90, -90, 68, 43, 110, -90, -90, 307,
+ -90, 113, 113, 113, -90, 223, 542, 542, 542, 509,
+ 567, 591, 614, 636, 657, 676, 676, 691, 691, 691,
+ 691, 334, 334, 703, 713, 713, 212, 212, 212, 107,
+ 108, 223, -90, -90, 4, 223, 223, -90, -90, 223,
+ -90, -90, 223, 118, -90, 19, -90, -90, -90, -90,
+ -90, 74, -90, -90, 73, -90, 158, -17, 51, -90,
+ -90, 415, -90, 106, 223, 223, 87, 113, -90, 88,
+ 97, 99, 212, 223, 212, -90, -16, 212, 542, 212,
+ -90, -90, -90, 114, 307, -90, -90, 542, 542, -90,
+ -90, 88, 223, -90, -90, 475, -90, -90, 542
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const short yypgoto[] =
+{
+ -90, -90, -90, 3, -10, -90, -90, -90, -28, -90,
+ -44, -90, -90, -7, 50, -90, -90, -71, -90, -89,
+ -90, 47, 48, 1, 0, 163, -90, -5, -90
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -111
+static const short yytable[] =
+{
+ 47, 46, 191, 39, 59, 54, 55, 56, 57, 179,
+ 90, 66, 67, 224, 179, 74, 77, 78, 79, 80,
+ 81, 84, 75, 76, 87, 88, -79, 49, 50, 51,
+ 52, 119, 47, 86, 90, 187, 188, 189, 190, 89,
+ 194, 47, 121, 90, 172, 144, 180, 177, 225, 236,
+ 122, 49, 50, 51, 52, 136, 135, 137, 47, 134,
+ 7, 8, 192, 10, 11, 12, 13, 215, 15, 138,
+ 17, 139, 18, 19, 20, 21, 22, 23, 24, 53,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
+ 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
+ 166, 167, 168, 53, 71, 185, 72, 140, 126, 73,
+ 173, 128, 198, 178, 210, 211, 193, 183, 186, 174,
+ 127, 49, 50, 51, 52, -109, -110, 128, 129, 196,
+ 186, 145, 180, 201, 202, 212, -80, 221, 222, 196,
+ 203, 7, 8, 204, 10, 11, 12, 13, 226, 15,
+ 229, 17, 232, 18, 19, 20, 21, 22, 23, 24,
+ 233, 214, 234, 230, 184, 119, 217, 123, 216, 218,
+ 126, 182, 219, 53, 124, 125, 223, 205, 199, 200,
+ 220, 70, 127, 124, 125, 0, 0, 126, 0, 128,
+ 129, 212, 0, 0, 227, 228, 126, 193, 196, 127,
+ 0, 0, 231, 235, 61, 0, 128, 129, 127, 0,
+ 49, 50, 51, 52, 0, 128, 129, 62, 63, 64,
+ 0, 0, 238, 0, 196, 237, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 61, 18, 19, 20, 21, 22, 23,
+ 24, 25, 184, 0, 0, 0, 68, 69, 64, 0,
+ 0, 26, 53, 0, 185, 113, 114, 0, 115, 116,
+ 117, 118, 27, 28, 0, 0, 29, 30, 0, 0,
+ 31, 32, 0, 33, 34, 35, 0, 0, 0, 36,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 0, 18, 19,
+ 20, 21, 22, 23, 24, 25, 7, 8, 0, 10,
+ 11, 12, 13, 0, 15, 26, 17, 0, 18, 19,
+ 20, 21, 22, 23, 24, 0, 27, 28, 0, 0,
+ 29, 30, 0, 0, 31, 58, 0, 33, 34, 35,
+ 0, 0, 0, 36, 1, 2, 3, 4, 5, 6,
+ 82, 83, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 0, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0, 107, 108, 109, 110, 111, 112, 113, 114, 26,
+ 115, 116, 117, 118, 0, 0, 0, 0, 0, 0,
+ 27, 28, 0, 0, 29, 30, 0, 0, 31, 32,
+ 0, 33, 34, 35, 0, 0, 0, 36, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 0, 18, 19, 20, 21,
+ 22, 23, 24, 25, 49, 169, 170, 52, 10, 11,
+ 12, 13, 0, 15, 0, 17, 0, 18, 19, 20,
+ 21, 22, 23, 24, 0, 0, 0, 0, 29, 30,
+ 0, 0, 31, 32, 0, 33, 34, 35, 0, 0,
+ 0, 36, 0, 0, 0, 0, 171, 0, 49, 169,
+ 170, 52, 10, 11, 12, 13, 53, 15, 0, 17,
+ 0, 18, 19, 20, 21, 22, 23, 24, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 176, 115, 116, 117, 118, 0, 0, 0, 91, 0,
+ 53, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 0, 115, 116, 117, 118, 0,
+ 0, 91, 0, 213, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 0, 115, 116,
+ 117, 118, 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 0, 115, 116, 117, 118, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 0, 115, 116, 117,
+ 118, 97, 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113, 114, 0,
+ 115, 116, 117, 118, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ 114, 0, 115, 116, 117, 118, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 0, 115, 116, 117, 118, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ 114, 0, 115, 116, 117, 118, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 0, 115, 116, 117,
+ 118, 108, 109, 110, 111, 112, 113, 114, 0, 115,
+ 116, 117, 118, 110, 111, 112, 113, 114, 0, 115,
+ 116, 117, 118
+};
+
+static const short yycheck[] =
+{
+ 0, 0, 3, 0, 14, 10, 11, 12, 13, 30,
+ 30, 16, 17, 30, 30, 24, 26, 27, 28, 29,
+ 30, 31, 22, 23, 34, 35, 18, 8, 9, 10,
+ 11, 41, 32, 32, 30, 124, 125, 126, 127, 0,
+ 129, 41, 41, 30, 115, 65, 67, 118, 65, 65,
+ 18, 8, 9, 10, 11, 22, 18, 24, 58, 58,
+ 9, 10, 63, 12, 13, 14, 15, 63, 17, 24,
+ 19, 41, 21, 22, 23, 24, 25, 26, 27, 60,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 60, 22, 62, 24, 24, 38, 27,
+ 115, 57, 58, 118, 142, 143, 65, 122, 123, 116,
+ 50, 8, 9, 10, 11, 18, 18, 57, 58, 129,
+ 135, 65, 67, 65, 24, 145, 18, 63, 65, 139,
+ 139, 9, 10, 30, 12, 13, 14, 15, 42, 17,
+ 63, 19, 64, 21, 22, 23, 24, 25, 26, 27,
+ 63, 171, 63, 207, 50, 175, 176, 18, 175, 179,
+ 38, 121, 182, 60, 25, 26, 18, 64, 131, 131,
+ 185, 18, 50, 25, 26, -1, -1, 38, -1, 57,
+ 58, 201, -1, -1, 204, 205, 38, 65, 198, 50,
+ -1, -1, 207, 213, 9, -1, 57, 58, 50, -1,
+ 8, 9, 10, 11, -1, 57, 58, 22, 23, 24,
+ -1, -1, 232, -1, 224, 224, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 9, 21, 22, 23, 24, 25, 26,
+ 27, 28, 50, -1, -1, -1, 22, 23, 24, -1,
+ -1, 38, 60, -1, 62, 53, 54, -1, 56, 57,
+ 58, 59, 49, 50, -1, -1, 53, 54, -1, -1,
+ 57, 58, -1, 60, 61, 62, -1, -1, -1, 66,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, -1, 21, 22,
+ 23, 24, 25, 26, 27, 28, 9, 10, -1, 12,
+ 13, 14, 15, -1, 17, 38, 19, -1, 21, 22,
+ 23, 24, 25, 26, 27, -1, 49, 50, -1, -1,
+ 53, 54, -1, -1, 57, 58, -1, 60, 61, 62,
+ -1, -1, -1, 66, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, -1, 21, 22, 23, 24, 25, 26, 27, 28,
+ -1, 47, 48, 49, 50, 51, 52, 53, 54, 38,
+ 56, 57, 58, 59, -1, -1, -1, -1, -1, -1,
+ 49, 50, -1, -1, 53, 54, -1, -1, 57, 58,
+ -1, 60, 61, 62, -1, -1, -1, 66, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, -1, 21, 22, 23, 24,
+ 25, 26, 27, 28, 8, 9, 10, 11, 12, 13,
+ 14, 15, -1, 17, -1, 19, -1, 21, 22, 23,
+ 24, 25, 26, 27, -1, -1, -1, -1, 53, 54,
+ -1, -1, 57, 58, -1, 60, 61, 62, -1, -1,
+ -1, 66, -1, -1, -1, -1, 50, -1, 8, 9,
+ 10, 11, 12, 13, 14, 15, 60, 17, -1, 19,
+ -1, 21, 22, 23, 24, 25, 26, 27, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 50, 56, 57, 58, 59, -1, -1, -1, 29, -1,
+ 60, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, -1, 56, 57, 58, 59, -1,
+ -1, 29, -1, 64, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, -1, 56, 57,
+ 58, 59, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, -1, 56, 57, 58, 59, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, -1, 56, 57, 58,
+ 59, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, -1,
+ 56, 57, 58, 59, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, -1, 56, 57, 58, 59, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, -1, 56, 57, 58, 59, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, -1, 56, 57, 58, 59, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, -1, 56, 57, 58,
+ 59, 48, 49, 50, 51, 52, 53, 54, -1, 56,
+ 57, 58, 59, 50, 51, 52, 53, 54, -1, 56,
+ 57, 58, 59
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 21, 22,
+ 23, 24, 25, 26, 27, 28, 38, 49, 50, 53,
+ 54, 57, 58, 60, 61, 62, 66, 69, 70, 71,
+ 72, 80, 83, 84, 85, 86, 91, 92, 96, 8,
+ 9, 10, 11, 60, 95, 95, 95, 95, 58, 72,
+ 92, 9, 22, 23, 24, 93, 95, 95, 22, 23,
+ 93, 22, 24, 27, 24, 92, 92, 72, 72, 72,
+ 72, 72, 9, 10, 72, 71, 91, 72, 72, 0,
+ 30, 29, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 56, 57, 58, 59, 72,
+ 81, 91, 18, 18, 25, 26, 38, 50, 57, 58,
+ 87, 88, 89, 90, 91, 18, 22, 24, 24, 41,
+ 24, 73, 74, 75, 65, 65, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 9,
+ 10, 50, 85, 95, 71, 79, 50, 85, 95, 30,
+ 67, 82, 82, 95, 50, 62, 95, 87, 87, 87,
+ 87, 3, 63, 65, 87, 91, 92, 94, 58, 89,
+ 90, 65, 24, 91, 30, 64, 76, 77, 78, 95,
+ 76, 76, 72, 64, 72, 63, 81, 72, 72, 72,
+ 95, 63, 65, 18, 30, 65, 42, 72, 72, 63,
+ 78, 95, 64, 63, 63, 72, 65, 91, 72
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to xreallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to xreallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 236 "objc-exp.y"
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(yyvsp[0].tval);
+ write_exp_elt_opcode(OP_TYPE);}
+ break;
+
+ case 6:
+#line 244 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ break;
+
+ case 7:
+#line 249 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_IND); }
+ break;
+
+ case 8:
+#line 253 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ break;
+
+ case 9:
+#line 257 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_NEG); }
+ break;
+
+ case 10:
+#line 261 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ break;
+
+ case 11:
+#line 265 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+ break;
+
+ case 12:
+#line 269 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ break;
+
+ case 13:
+#line 273 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ break;
+
+ case 14:
+#line 277 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+ break;
+
+ case 15:
+#line 281 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+ break;
+
+ case 16:
+#line 285 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ break;
+
+ case 17:
+#line 289 "objc-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_PTR); }
+ break;
+
+ case 18:
+#line 295 "objc-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 19:
+#line 302 "objc-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_MPTR); }
+ break;
+
+ case 20:
+#line 306 "objc-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ break;
+
+ case 21:
+#line 313 "objc-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 22:
+#line 321 "objc-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ break;
+
+ case 23:
+#line 325 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ break;
+
+ case 24:
+#line 333 "objc-exp.y"
+ {
+ CORE_ADDR class;
+
+ class = lookup_objc_class (copy_name (yyvsp[0].tsym.stoken));
+ if (class == 0)
+ error ("%s is not an ObjC Class",
+ copy_name (yyvsp[0].tsym.stoken));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) class);
+ write_exp_elt_opcode (OP_LONG);
+ start_msglist();
+ }
+ break;
+
+ case 25:
+#line 347 "objc-exp.y"
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ break;
+
+ case 26:
+#line 354 "objc-exp.y"
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].class.class);
+ write_exp_elt_opcode (OP_LONG);
+ start_msglist();
+ }
+ break;
+
+ case 27:
+#line 362 "objc-exp.y"
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ break;
+
+ case 28:
+#line 369 "objc-exp.y"
+ { start_msglist(); }
+ break;
+
+ case 29:
+#line 371 "objc-exp.y"
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ break;
+
+ case 30:
+#line 378 "objc-exp.y"
+ { add_msglist(&yyvsp[0].sval, 0); }
+ break;
+
+ case 34:
+#line 387 "objc-exp.y"
+ { add_msglist(&yyvsp[-2].sval, 1); }
+ break;
+
+ case 35:
+#line 389 "objc-exp.y"
+ { add_msglist(0, 1); }
+ break;
+
+ case 36:
+#line 391 "objc-exp.y"
+ { add_msglist(0, 0); }
+ break;
+
+ case 37:
+#line 397 "objc-exp.y"
+ { start_arglist (); }
+ break;
+
+ case 38:
+#line 399 "objc-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 405 "objc-exp.y"
+ { start_arglist (); }
+ break;
+
+ case 41:
+#line 412 "objc-exp.y"
+ { arglist_len = 1; }
+ break;
+
+ case 42:
+#line 416 "objc-exp.y"
+ { arglist_len++; }
+ break;
+
+ case 43:
+#line 420 "objc-exp.y"
+ { yyval.lval = end_arglist () - 1; }
+ break;
+
+ case 44:
+#line 423 "objc-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 45:
+#line 430 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ break;
+
+ case 46:
+#line 436 "objc-exp.y"
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_CAST); }
+ break;
+
+ case 47:
+#line 442 "objc-exp.y"
+ { }
+ break;
+
+ case 48:
+#line 448 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ break;
+
+ case 49:
+#line 452 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_MUL); }
+ break;
+
+ case 50:
+#line 456 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_DIV); }
+ break;
+
+ case 51:
+#line 460 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_REM); }
+ break;
+
+ case 52:
+#line 464 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_ADD); }
+ break;
+
+ case 53:
+#line 468 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_SUB); }
+ break;
+
+ case 54:
+#line 472 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_LSH); }
+ break;
+
+ case 55:
+#line 476 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_RSH); }
+ break;
+
+ case 56:
+#line 480 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ break;
+
+ case 57:
+#line 484 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 58:
+#line 488 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ break;
+
+ case 59:
+#line 492 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ break;
+
+ case 60:
+#line 496 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_LESS); }
+ break;
+
+ case 61:
+#line 500 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_GTR); }
+ break;
+
+ case 62:
+#line 504 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ break;
+
+ case 63:
+#line 508 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ break;
+
+ case 64:
+#line 512 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ break;
+
+ case 65:
+#line 516 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ break;
+
+ case 66:
+#line 520 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ break;
+
+ case 67:
+#line 524 "objc-exp.y"
+ { write_exp_elt_opcode (TERNOP_COND); }
+ break;
+
+ case 68:
+#line 528 "objc-exp.y"
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ break;
+
+ case 69:
+#line 532 "objc-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 70:
+#line 538 "objc-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 71:
+#line 545 "objc-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 72:
+#line 556 "objc-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 75:
+#line 570 "objc-exp.y"
+ {
+ write_exp_elt_opcode (OP_OBJC_SELECTOR);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_OBJC_SELECTOR); }
+ break;
+
+ case 76:
+#line 577 "objc-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 77:
+#line 585 "objc-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 78:
+#line 612 "objc-exp.y"
+ { write_exp_elt_opcode (OP_OBJC_NSSTRING);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_OBJC_NSSTRING); }
+ break;
+
+ case 79:
+#line 618 "objc-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 80:
+#line 635 "objc-exp.y"
+ { struct symbol *tem
+ = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, (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 81:
+#line 646 "objc-exp.y"
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, (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 82:
+#line 662 "objc-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 83:
+#line 675 "objc-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 (!DEPRECATED_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 85:
+#line 701 "objc-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_DOMAIN, (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 86:
+#line 735 "objc-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++/ObjC: it hangs off of `this'/'self'.
+ Must not inadvertently convert from a
+ method call to data ref. */
+ if (innermost_block == 0 ||
+ contained_in (block_found, innermost_block))
+ innermost_block = block_found;
+ write_exp_elt_opcode (OP_OBJC_SELF);
+ write_exp_elt_opcode (OP_OBJC_SELF);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string (yyvsp[0].ssym.stoken);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ 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 90:
+#line 802 "objc-exp.y"
+ { yyval.tval = follow_types (yyvsp[-1].tval); }
+ break;
+
+ case 91:
+#line 804 "objc-exp.y"
+ { yyval.tval = follow_types (yyvsp[-2].tval); }
+ break;
+
+ case 92:
+#line 806 "objc-exp.y"
+ { yyval.tval = follow_types (yyvsp[-2].tval); }
+ break;
+
+ case 93:
+#line 810 "objc-exp.y"
+ { push_type (tp_pointer); yyval.voidval = 0; }
+ break;
+
+ case 94:
+#line 812 "objc-exp.y"
+ { push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; }
+ break;
+
+ case 95:
+#line 814 "objc-exp.y"
+ { push_type (tp_reference); yyval.voidval = 0; }
+ break;
+
+ case 96:
+#line 816 "objc-exp.y"
+ { push_type (tp_reference); yyval.voidval = yyvsp[0].voidval; }
+ break;
+
+ case 98:
+#line 821 "objc-exp.y"
+ { yyval.voidval = yyvsp[-1].voidval; }
+ break;
+
+ case 99:
+#line 823 "objc-exp.y"
+ {
+ push_type_int (yyvsp[0].lval);
+ push_type (tp_array);
+ }
+ break;
+
+ case 100:
+#line 828 "objc-exp.y"
+ {
+ push_type_int (yyvsp[0].lval);
+ push_type (tp_array);
+ yyval.voidval = 0;
+ }
+ break;
+
+ case 101:
+#line 835 "objc-exp.y"
+ { push_type (tp_function); }
+ break;
+
+ case 102:
+#line 837 "objc-exp.y"
+ { push_type (tp_function); }
+ break;
+
+ case 103:
+#line 841 "objc-exp.y"
+ { yyval.lval = -1; }
+ break;
+
+ case 104:
+#line 843 "objc-exp.y"
+ { yyval.lval = yyvsp[-1].typed_val_int.val; }
+ break;
+
+ case 105:
+#line 847 "objc-exp.y"
+ { yyval.voidval = 0; }
+ break;
+
+ case 106:
+#line 849 "objc-exp.y"
+ { free (yyvsp[-1].tvec); yyval.voidval = 0; }
+ break;
+
+ case 108:
+#line 862 "objc-exp.y"
+ { yyval.tval = lookup_member_type (builtin_type_int, yyvsp[-2].tval); }
+ break;
+
+ case 109:
+#line 867 "objc-exp.y"
+ { yyval.tval = yyvsp[0].tsym.type; }
+ break;
+
+ case 110:
+#line 869 "objc-exp.y"
+ {
+ if (yyvsp[0].class.type == NULL)
+ error ("No symbol \"%s\" in current context.",
+ copy_name(yyvsp[0].class.stoken));
+ else
+ yyval.tval = yyvsp[0].class.type;
+ }
+ break;
+
+ case 111:
+#line 877 "objc-exp.y"
+ { yyval.tval = builtin_type_int; }
+ break;
+
+ case 112:
+#line 879 "objc-exp.y"
+ { yyval.tval = builtin_type_long; }
+ break;
+
+ case 113:
+#line 881 "objc-exp.y"
+ { yyval.tval = builtin_type_short; }
+ break;
+
+ case 114:
+#line 883 "objc-exp.y"
+ { yyval.tval = builtin_type_long; }
+ break;
+
+ case 115:
+#line 885 "objc-exp.y"
+ { yyval.tval = builtin_type_unsigned_long; }
+ break;
+
+ case 116:
+#line 887 "objc-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 117:
+#line 889 "objc-exp.y"
+ { yyval.tval = builtin_type_long_long; }
+ break;
+
+ case 118:
+#line 891 "objc-exp.y"
+ { yyval.tval = builtin_type_unsigned_long_long; }
+ break;
+
+ case 119:
+#line 893 "objc-exp.y"
+ { yyval.tval = builtin_type_unsigned_long_long; }
+ break;
+
+ case 120:
+#line 895 "objc-exp.y"
+ { yyval.tval = builtin_type_short; }
+ break;
+
+ case 121:
+#line 897 "objc-exp.y"
+ { yyval.tval = builtin_type_unsigned_short; }
+ break;
+
+ case 122:
+#line 899 "objc-exp.y"
+ { yyval.tval = builtin_type_double; }
+ break;
+
+ case 123:
+#line 901 "objc-exp.y"
+ { yyval.tval = builtin_type_long_double; }
+ break;
+
+ case 124:
+#line 903 "objc-exp.y"
+ { yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 125:
+#line 906 "objc-exp.y"
+ { yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 126:
+#line 909 "objc-exp.y"
+ { yyval.tval = lookup_union (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 127:
+#line 912 "objc-exp.y"
+ { yyval.tval = lookup_enum (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 128:
+#line 915 "objc-exp.y"
+ { yyval.tval = lookup_unsigned_typename (TYPE_NAME(yyvsp[0].tsym.type)); }
+ break;
+
+ case 129:
+#line 917 "objc-exp.y"
+ { yyval.tval = builtin_type_unsigned_int; }
+ break;
+
+ case 130:
+#line 919 "objc-exp.y"
+ { yyval.tval = lookup_signed_typename (TYPE_NAME(yyvsp[0].tsym.type)); }
+ break;
+
+ case 131:
+#line 921 "objc-exp.y"
+ { yyval.tval = builtin_type_int; }
+ break;
+
+ case 132:
+#line 923 "objc-exp.y"
+ { yyval.tval = lookup_template_type(copy_name(yyvsp[-3].sval), yyvsp[-1].tval,
+ expression_context_block);
+ }
+ break;
+
+ case 133:
+#line 929 "objc-exp.y"
+ { yyval.tval = yyvsp[0].tval; }
+ break;
+
+ case 134:
+#line 930 "objc-exp.y"
+ { yyval.tval = yyvsp[0].tval; }
+ break;
+
+ case 136:
+#line 935 "objc-exp.y"
+ {
+ yyval.tsym.stoken.ptr = "int";
+ yyval.tsym.stoken.length = 3;
+ yyval.tsym.type = builtin_type_int;
+ }
+ break;
+
+ case 137:
+#line 941 "objc-exp.y"
+ {
+ yyval.tsym.stoken.ptr = "long";
+ yyval.tsym.stoken.length = 4;
+ yyval.tsym.type = builtin_type_long;
+ }
+ break;
+
+ case 138:
+#line 947 "objc-exp.y"
+ {
+ yyval.tsym.stoken.ptr = "short";
+ yyval.tsym.stoken.length = 5;
+ yyval.tsym.type = builtin_type_short;
+ }
+ break;
+
+ case 139:
+#line 956 "objc-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 140:
+#line 961 "objc-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 141:
+#line 967 "objc-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+ case 142:
+#line 968 "objc-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+ case 143:
+#line 969 "objc-exp.y"
+ { yyval.sval = yyvsp[0].tsym.stoken; }
+ break;
+
+ case 144:
+#line 970 "objc-exp.y"
+ { yyval.sval = yyvsp[0].class.stoken; }
+ break;
+
+ case 145:
+#line 971 "objc-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+
+ }
+
+/* Line 991 of yacc.c. */
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ 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)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab2;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+
+ /* Suppress GCC warning that yyerrlab1 is unused when no action
+ invokes YYERROR. Doesn't work in C++ */
+#ifndef __cplusplus
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+#endif
+#endif
+
+
+ goto yyerrlab2;
+
+
+/*---------------------------------------------------------------.
+| yyerrlab2 -- pop states until the error token can be shifted. |
+`---------------------------------------------------------------*/
+yyerrlab2:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 985 "objc-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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ /* FIXME: Shouldn't these be unsigned? We don't deal with negative
+ values here, and we do kind of silly things like cast to
+ unsigned. */
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ unsigned LONGEST un;
+
+ int i = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
+ int long_p = 0;
+
+ /* We have found a "L" or "U" suffix. */
+ int found_suffix = 0;
+
+ unsigned LONGEST high_bit;
+ struct type *signed_type;
+ struct type *unsigned_type;
+
+ if (parsed_float)
+ {
+ 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", (float *)&putithere->typed_val_float.dval);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ sscanf (p, "%lg", (double *)&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, and 0. */
+ if (p[0] == '0')
+ switch (p[1])
+ {
+ case 'x':
+ case 'X':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ break;
+
+ case 't':
+ case 'T':
+ case 'd':
+ case 'D':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 10;
+ len -= 2;
+ }
+ break;
+
+ default:
+ base = 8;
+ break;
+ }
+
+ while (len-- > 0)
+ {
+ c = *p++;
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != 'l' && c != 'u')
+ n *= base;
+ if (c >= '0' && c <= '9')
+ {
+ if (found_suffix)
+ return ERROR;
+ n += i = c - '0';
+ }
+ else
+ {
+ if (base > 10 && c >= 'a' && c <= 'f')
+ {
+ if (found_suffix)
+ return ERROR;
+ n += i = c - 'a' + 10;
+ }
+ else if (c == 'l')
+ {
+ ++long_p;
+ found_suffix = 1;
+ }
+ else if (c == 'u')
+ {
+ unsigned_p = 1;
+ found_suffix = 1;
+ }
+ else
+ return ERROR; /* Char not a digit. */
+ }
+ if (i >= base)
+ return ERROR; /* Invalid digit in this base. */
+
+ /* Portably test for overflow (only works for nonzero values, so
+ make a second check for zero). FIXME: Can't we just make n
+ and prevn unsigned and avoid this? */
+ if (c != 'l' && c != 'u' && (prevn >= n) && n != 0)
+ unsigned_p = 1; /* Try something unsigned. */
+
+ /* Portably test for unsigned overflow.
+ FIXME: This check is wrong; for example it doesn't find
+ overflow on 0x123456789 when LONGEST is 32 bits. */
+ if (c != 'l' && c != 'u' && n != 0)
+ {
+ if ((unsigned_p && (unsigned LONGEST) prevn >= (unsigned LONGEST) n))
+ error ("Numeric constant too large.");
+ }
+ prevn = n;
+ }
+
+ /* An integer constant is an int, a long, or a long long. An L
+ suffix forces it to be long; an LL suffix forces it to be long
+ long. If not forced to a larger size, it gets the first type of
+ the above that it fits in. To figure out whether it fits, we
+ shift it right and see whether anything remains. Note that we
+ can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one
+ operation, because many compilers will warn about such a shift
+ (which always produces a zero result). Sometimes 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, tokchr;
+ int namelen;
+ unsigned int i;
+ char *tokstart;
+ char *tokptr;
+ int tempbufindex;
+ static char *tempbuf;
+ static int tempbufsize;
+
+ retry:
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (DEPRECATED_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 (DEPRECATED_STREQN (tokstart, tokentab2[i].operator, 2))
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ c = 0;
+ switch (tokchr = *tokstart)
+ {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ /* We either have a character constant ('0' or '\177' for
+ example) or we have a quoted symbol reference ('foo(int,int)'
+ in C++ for example). */
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&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 '(';
+
+ case ')':
+ if (paren_depth == 0)
+ return 0;
+ paren_depth--;
+ lexptr++;
+ return ')';
+
+ case ',':
+ if (comma_terminates && paren_depth == 0)
+ return 0;
+ lexptr++;
+ return ',';
+
+ case '.':
+ /* Might be a floating point number. */
+ if (lexptr[1] < '0' || lexptr[1] > '9')
+ goto symbol; /* Nope, must be a symbol. */
+ /* FALL THRU into number case. */
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0, toktype = FLOAT;
+ /* Initialize toktype to anything other than ERROR. */
+ char *p = tokstart;
+ int hex = input_radix > 10;
+ int local_radix = input_radix;
+ if (tokchr == '0' && (p[1] == 'x' || p[1] == 'X'))
+ {
+ p += 2;
+ hex = 1;
+ local_radix = 16;
+ }
+ else if (tokchr == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
+ {
+ p += 2;
+ hex = 0;
+ local_radix = 10;
+ }
+
+ for (;; ++p)
+ {
+ /* This test includes !hex because 'e' is a valid hex digit
+ and thus does not indicate a floating point number when
+ the radix is hex. */
+
+ if (!hex && (*p == 'e' || *p == 'E'))
+ if (got_e)
+ toktype = ERROR; /* Only one 'e' in a float. */
+ else
+ got_e = 1;
+ /* This test does not include !hex, because a '.' always
+ indicates a decimal floating point number regardless of
+ the radix. */
+ else if (*p == '.')
+ if (got_dot)
+ toktype = ERROR; /* Only one '.' in a float. */
+ else
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E') &&
+ (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ /* Always take decimal digits; parse_number handles radix
+ error. */
+ else if (*p >= '0' && *p <= '9')
+ continue;
+ /* We will take letters only if hex is true, and only up
+ to what the input radix would permit. FSF was content
+ to rely on parse_number to validate; but it leaks. */
+ else if (*p >= 'a' && *p <= 'z')
+ {
+ if (!hex || *p >= ('a' + local_radix - 10))
+ toktype = ERROR;
+ }
+ else if (*p >= 'A' && *p <= 'Z')
+ {
+ if (!hex || *p >= ('A' + local_radix - 10))
+ toktype = ERROR;
+ }
+ else break;
+ }
+ if (toktype != ERROR)
+ toktype = parse_number (tokstart, p - tokstart,
+ got_dot | got_e, &yylval);
+ if (toktype == ERROR)
+ {
+ char *err_copy = (char *) alloca (p - tokstart + 1);
+
+ memcpy (err_copy, tokstart, p - tokstart);
+ err_copy[p - tokstart] = 0;
+ error ("Invalid number \"%s\".", err_copy);
+ }
+ lexptr = p;
+ return toktype;
+ }
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+#if 0
+ case '@': /* Moved out below. */
+#endif
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ symbol:
+ lexptr++;
+ return tokchr;
+
+ case '@':
+ if (strncmp(tokstart, "@selector", 9) == 0)
+ {
+ tokptr = strchr(tokstart, '(');
+ if (tokptr == NULL)
+ {
+ error ("Missing '(' in @selector(...)");
+ }
+ tempbufindex = 0;
+ tokptr++; /* Skip the '('. */
+ do {
+ /* Grow the static temp buffer if necessary, including
+ allocating the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) xrealloc (tempbuf, tempbufsize += 64);
+ }
+ tempbuf[tempbufindex++] = *tokptr++;
+ } while ((*tokptr != ')') && (*tokptr != '\0'));
+ if (*tokptr++ != ')')
+ {
+ error ("Missing ')' in @selector(...)");
+ }
+ tempbuf[tempbufindex] = '\0';
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbufindex;
+ lexptr = tokptr;
+ return SELECTOR;
+ }
+ if (tokstart[1] != '"')
+ {
+ lexptr++;
+ return tokchr;
+ }
+ /* ObjC NextStep NSString constant: fall thru and parse like
+ STRING. */
+ tokstart++;
+
+ case '"':
+
+ /* Build the gdb internal form of the input string in tempbuf,
+ translating any standard C escape forms seen. Note that the
+ buffer is null byte terminated *only* for the convenience of
+ debugging gdb itself and printing the buffer contents when
+ the buffer contains no embedded nulls. Gdb does not depend
+ upon the buffer being null byte terminated, it uses the
+ length string instead. This allows gdb to handle C strings
+ (as well as strings in other languages) with embedded null
+ bytes. */
+
+ tokptr = ++tokstart;
+ tempbufindex = 0;
+
+ do {
+ /* Grow the static temp buffer if necessary, including
+ allocating the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) 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 (tokchr == '@' ? NSSTRING : STRING);
+ }
+
+ if (!(tokchr == '_' || tokchr == '$' ||
+ (tokchr >= 'a' && tokchr <= 'z') || (tokchr >= 'A' && tokchr <= 'Z')))
+ /* We must have come across a bad character (e.g. ';'). */
+ error ("Invalid character '%c' in expression.", c);
+
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ for (c = tokstart[namelen];
+ (c == '_' || c == '$' || (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');)
+ {
+ if (c == '<')
+ {
+ int i = namelen;
+ while (tokstart[++i] && tokstart[i] != '>');
+ if (tokstart[i] == '>')
+ namelen = i;
+ }
+ c = tokstart[++namelen];
+ }
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ tryname:
+
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 8:
+ if (DEPRECATED_STREQN (tokstart, "unsigned", 8))
+ return UNSIGNED;
+ if (current_language->la_language == language_cplus
+ && strncmp (tokstart, "template", 8) == 0)
+ return TEMPLATE;
+ if (DEPRECATED_STREQN (tokstart, "volatile", 8))
+ return VOLATILE_KEYWORD;
+ break;
+ case 6:
+ if (DEPRECATED_STREQN (tokstart, "struct", 6))
+ return STRUCT;
+ if (DEPRECATED_STREQN (tokstart, "signed", 6))
+ return SIGNED_KEYWORD;
+ if (DEPRECATED_STREQN (tokstart, "sizeof", 6))
+ return SIZEOF;
+ if (DEPRECATED_STREQN (tokstart, "double", 6))
+ return DOUBLE_KEYWORD;
+ break;
+ case 5:
+ if ((current_language->la_language == language_cplus)
+ && strncmp (tokstart, "class", 5) == 0)
+ return CLASS;
+ if (DEPRECATED_STREQN (tokstart, "union", 5))
+ return UNION;
+ if (DEPRECATED_STREQN (tokstart, "short", 5))
+ return SHORT;
+ if (DEPRECATED_STREQN (tokstart, "const", 5))
+ return CONST_KEYWORD;
+ break;
+ case 4:
+ if (DEPRECATED_STREQN (tokstart, "enum", 4))
+ return ENUM;
+ if (DEPRECATED_STREQN (tokstart, "long", 4))
+ return LONG;
+ break;
+ case 3:
+ if (DEPRECATED_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, *need_this;
+ int hextype;
+
+ if (current_language->la_language == language_cplus ||
+ current_language->la_language == language_objc)
+ need_this = &is_a_field_of_this;
+ else
+ need_this = (int *) NULL;
+
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ need_this,
+ (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 symbols are read). */
+ if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) ||
+ lookup_symtab (tmp))
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return BLOCKNAME;
+ }
+ if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+#if 1
+ /* Despite the following flaw, we need to keep this code
+ enabled. Because we can get called from
+ check_stub_method, if we don't handle nested types then
+ it screws many operations in any program which uses
+ nested types. */
+ /* In "A::x", if x is a member function of A and there
+ happens to be a type (nested or not, since the stabs
+ don't make that distinction) named x, then this code
+ incorrectly thinks we are dealing with nested types
+ rather than a member function. */
+
+ char *p;
+ char *namestart;
+ struct symbol *best_sym;
+
+ /* Look ahead to detect nested types. This probably should
+ be done in the grammar, but trying seemed to introduce a
+ lot of shift/reduce and reduce/reduce conflicts. It's
+ possible that it could be done, though. Or perhaps a
+ non-grammar, but less ad hoc, approach would work well. */
+
+ /* Since we do not currently have any way of distinguishing
+ a nested type from a non-nested one (the stabs don't tell
+ us whether a type is nested), we just ignore the
+ containing type. */
+
+ p = lexptr;
+ best_sym = sym;
+ while (1)
+ {
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ if (*p == ':' && p[1] == ':')
+ {
+ /* Skip the `::'. */
+ p += 2;
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ namestart = p;
+ while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9')
+ || (*p >= 'a' && *p <= 'z')
+ || (*p >= 'A' && *p <= 'Z'))
+ ++p;
+ if (p != namestart)
+ {
+ struct symbol *cur_sym;
+ /* As big as the whole rest of the expression,
+ which is at least big enough. */
+ char *ncopy = alloca (strlen (tmp) +
+ strlen (namestart) + 3);
+ char *tmp1;
+
+ tmp1 = ncopy;
+ memcpy (tmp1, tmp, strlen (tmp));
+ tmp1 += strlen (tmp);
+ memcpy (tmp1, "::", 2);
+ tmp1 += 2;
+ memcpy (tmp1, namestart, p - namestart);
+ tmp1[p - namestart] = '\0';
+ cur_sym = lookup_symbol (ncopy,
+ expression_context_block,
+ VAR_DOMAIN, (int *) NULL,
+ (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;
+
+ /* See if it's an ObjC classname. */
+ if (!sym)
+ {
+ CORE_ADDR Class = lookup_objc_class(tmp);
+ if (Class)
+ {
+ yylval.class.class = Class;
+ if ((sym = lookup_struct_typedef (tmp,
+ expression_context_block,
+ 1)))
+ yylval.class.type = SYMBOL_TYPE (sym);
+ return CLASSNAME;
+ }
+ }
+
+ /* Input names that aren't symbols but ARE valid hex numbers,
+ when the input radix permits them, can be names or numbers
+ depending on the parse. Note we support radixes > 16 here. */
+ if (!sym &&
+ ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) ||
+ (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
+ {
+ YYSTYPE newlval; /* Its value is ignored. */
+ hextype = parse_number (tokstart, namelen, 0, &newlval);
+ if (hextype == INT)
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME_OR_INT;
+ }
+ }
+
+ /* Any other kind of symbol. */
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME;
+ }
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ if (*lexptr == '\0')
+ error("A %s near end of expression.", (msg ? msg : "error"));
+ else
+ error ("A %s in expression, near `%s'.", (msg ? msg : "error"),
+ lexptr);
+}
+
+
diff --git a/contrib/gdb/gdb/objc-exp.y b/contrib/gdb/gdb/objc-exp.y
new file mode 100644
index 0000000..f56f68d
--- /dev/null
+++ b/contrib/gdb/gdb/objc-exp.y
@@ -0,0 +1,1820 @@
+/* YACC parser for C expressions, for GDB.
+
+ Copyright 1986, 1989, 1990, 1991, 1993, 1994, 2002 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* 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 (<malloc.h> and <stdlib.h> 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 <ctype.h>
+#include "expression.h"
+
+#include "objc-lang.h" /* For objc language constructs. */
+
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "c-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols. */
+#include "top.h"
+#include "completer.h" /* For skip_quoted(). */
+#include "block.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror,
+ etc), as well as gratuitiously global symbol names, so we can have
+ multiple yacc generated parsers in gdb. Note that these are only
+ the variables produced by yacc. If other parser generators (bison,
+ byacc, etc) produce additional global names that conflict at link
+ time, then those parser generators need to be fixed instead of
+ adding those names to this list. */
+
+#define yymaxdepth objc_maxdepth
+#define yyparse objc_parse
+#define yylex objc_lex
+#define yyerror objc_error
+#define yylval objc_lval
+#define yychar objc_char
+#define yydebug objc_debug
+#define yypact objc_pact
+#define yyr1 objc_r1
+#define yyr2 objc_r2
+#define yydef objc_def
+#define yychk objc_chk
+#define yypgo objc_pgo
+#define yyact objc_act
+#define yyexca objc_exca
+#define yyerrflag objc_errflag
+#define yynerrs objc_nerrs
+#define yyps objc_ps
+#define yypv objc_pv
+#define yys objc_s
+#define yy_yys objc_yys
+#define yystate objc_state
+#define yytmp objc_tmp
+#define yyv objc_v
+#define yy_yyv objc_yyv
+#define yyval objc_val
+#define yylloc objc_lloc
+#define yyreds objc_reds /* With YYDEBUG defined */
+#define yytoks objc_toks /* With YYDEBUG defined */
+#define yyname objc_name /* With YYDEBUG defined */
+#define yyrule objc_rule /* With YYDEBUG defined */
+#define yylhs objc_yylhs
+#define yylen objc_yylen
+#define yydefred objc_yydefred
+#define yydgoto objc_yydgoto
+#define yysindex objc_yysindex
+#define yyrindex objc_yyrindex
+#define yygindex objc_yygindex
+#define yytable objc_yytable
+#define yycheck objc_yycheck
+
+#ifndef YYDEBUG
+#define YYDEBUG 0 /* Default to no yydebug support. */
+#endif
+
+int
+yyparse 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 objc_class_str class;
+
+ struct type **tvec;
+ int *ivec;
+ }
+
+%{
+/* YYSTYPE gets defined by %union. */
+static int
+parse_number PARAMS ((char *, int, int, YYSTYPE *));
+%}
+
+%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
+%type <lval> rcurly
+%type <tval> type typebase
+%type <tvec> nonempty_typelist
+/* %type <bval> block */
+
+/* Fancy type parsing. */
+%type <voidval> func_mod direct_abs_decl abs_decl
+%type <tval> ptype
+%type <lval> array_mod
+
+%token <typed_val_int> INT
+%token <typed_val_float> 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 <sval> STRING
+%token <sval> NSSTRING /* ObjC Foundation "NSString" literal */
+%token <sval> SELECTOR /* ObjC "@selector" pseudo-operator */
+%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
+%token <tsym> TYPENAME
+%token <class> CLASSNAME /* ObjC Class name */
+%type <sval> name
+%type <ssym> name_not_typename
+%type <tsym> 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 <ssym> 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 <voidval> VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+%left ','
+%left ABOVE_COMMA
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '@'
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY INCREMENT DECREMENT
+%right ARROW '.' '[' '('
+%token <ssym> BLOCKNAME
+%type <bval> block
+%left COLONCOLON
+
+
+%%
+
+start : exp1
+ | type_exp
+ ;
+
+type_exp: type
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);}
+ ;
+
+/* Expressions, including the comma operator. */
+exp1 : exp
+ | exp1 ',' exp
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ ;
+
+/* Expressions, not including the comma operator. */
+exp : '*' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_IND); }
+ ;
+
+exp : '&' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_ADDR); }
+ ;
+
+exp : '-' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_NEG); }
+ ;
+
+exp : '!' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ ;
+
+exp : '~' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+ ;
+
+exp : INCREMENT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ ;
+
+exp : DECREMENT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ ;
+
+exp : exp INCREMENT %prec UNARY
+ { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+ ;
+
+exp : exp DECREMENT %prec UNARY
+ { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+ ;
+
+exp : SIZEOF exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_SIZEOF); }
+ ;
+
+exp : exp ARROW name
+ { write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_PTR); }
+ ;
+
+exp : exp ARROW qualified_name
+ { /* exp->type::name becomes exp->*(&type::name) */
+ /* Note: this doesn't work if name is a
+ static member! FIXME */
+ write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (STRUCTOP_MPTR); }
+ ;
+exp : exp ARROW '*' exp
+ { write_exp_elt_opcode (STRUCTOP_MPTR); }
+ ;
+
+exp : exp '.' name
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ ;
+
+
+exp : exp '.' qualified_name
+ { /* exp.type::name becomes exp.*(&type::name) */
+ /* Note: this doesn't work if name is a
+ static member! FIXME */
+ write_exp_elt_opcode (UNOP_ADDR);
+ write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ ;
+
+exp : exp '.' '*' exp
+ { write_exp_elt_opcode (STRUCTOP_MEMBER); }
+ ;
+
+exp : exp '[' exp1 ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ ;
+/*
+ * The rules below parse ObjC message calls of the form:
+ * '[' target selector {':' argument}* ']'
+ */
+
+exp : '[' TYPENAME
+ {
+ CORE_ADDR class;
+
+ class = lookup_objc_class (copy_name ($2.stoken));
+ if (class == 0)
+ error ("%s is not an ObjC Class",
+ copy_name ($2.stoken));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) class);
+ write_exp_elt_opcode (OP_LONG);
+ start_msglist();
+ }
+ msglist ']'
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ ;
+
+exp : '[' CLASSNAME
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) $2.class);
+ write_exp_elt_opcode (OP_LONG);
+ start_msglist();
+ }
+ msglist ']'
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ ;
+
+exp : '[' exp
+ { start_msglist(); }
+ msglist ']'
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ ;
+
+msglist : name
+ { add_msglist(&$1, 0); }
+ | msgarglist
+ ;
+
+msgarglist : msgarg
+ | msgarglist msgarg
+ ;
+
+msgarg : name ':' exp
+ { add_msglist(&$1, 1); }
+ | ':' exp /* Unnamed arg. */
+ { add_msglist(0, 1); }
+ | ',' exp /* Variable number of args. */
+ { add_msglist(0, 0); }
+ ;
+
+exp : exp '('
+ /* This is to save the value of arglist_len
+ being accumulated by an outer function call. */
+ { start_arglist (); }
+ arglist ')' %prec ARROW
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+ ;
+
+lcurly : '{'
+ { start_arglist (); }
+ ;
+
+arglist :
+ ;
+
+arglist : exp
+ { arglist_len = 1; }
+ ;
+
+arglist : arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+rcurly : '}'
+ { $$ = end_arglist () - 1; }
+ ;
+exp : lcurly arglist rcurly %prec ARROW
+ { write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) $3);
+ write_exp_elt_opcode (OP_ARRAY); }
+ ;
+
+exp : lcurly type rcurly exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+ ;
+
+exp : '(' type ')' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($2);
+ write_exp_elt_opcode (UNOP_CAST); }
+ ;
+
+exp : '(' exp1 ')'
+ { }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+
+exp : exp '@' exp
+ { write_exp_elt_opcode (BINOP_REPEAT); }
+ ;
+
+exp : exp '*' exp
+ { write_exp_elt_opcode (BINOP_MUL); }
+ ;
+
+exp : exp '/' exp
+ { write_exp_elt_opcode (BINOP_DIV); }
+ ;
+
+exp : exp '%' exp
+ { write_exp_elt_opcode (BINOP_REM); }
+ ;
+
+exp : exp '+' exp
+ { write_exp_elt_opcode (BINOP_ADD); }
+ ;
+
+exp : exp '-' exp
+ { write_exp_elt_opcode (BINOP_SUB); }
+ ;
+
+exp : exp LSH exp
+ { write_exp_elt_opcode (BINOP_LSH); }
+ ;
+
+exp : exp RSH exp
+ { write_exp_elt_opcode (BINOP_RSH); }
+ ;
+
+exp : exp EQUAL exp
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ ;
+
+exp : exp NOTEQUAL exp
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ ;
+
+exp : exp LEQ exp
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ ;
+
+exp : exp GEQ exp
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ ;
+
+exp : exp '<' exp
+ { write_exp_elt_opcode (BINOP_LESS); }
+ ;
+
+exp : exp '>' exp
+ { write_exp_elt_opcode (BINOP_GTR); }
+ ;
+
+exp : exp '&' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ ;
+
+exp : exp '^' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ ;
+
+exp : exp '|' exp
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ ;
+
+exp : exp ANDAND exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+ ;
+
+exp : exp OROR exp
+ { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+ ;
+
+exp : exp '?' exp ':' exp %prec '?'
+ { write_exp_elt_opcode (TERNOP_COND); }
+ ;
+
+exp : exp '=' exp
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ ;
+
+exp : exp ASSIGN_MODIFY exp
+ { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode ($2);
+ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
+ ;
+
+exp : INT
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_longcst ((LONGEST)($1.val));
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : NAME_OR_INT
+ { YYSTYPE val;
+ parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val);
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (val.typed_val_int.type);
+ write_exp_elt_longcst ((LONGEST)val.typed_val_int.val);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ ;
+
+
+exp : FLOAT
+ { write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_dblcst ($1.dval);
+ write_exp_elt_opcode (OP_DOUBLE); }
+ ;
+
+exp : variable
+ ;
+
+exp : VARIABLE
+ /* Already written by write_dollar_variable. */
+ ;
+
+exp : SELECTOR
+ {
+ write_exp_elt_opcode (OP_OBJC_SELECTOR);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_OBJC_SELECTOR); }
+ ;
+
+exp : SIZEOF '(' type ')' %prec UNARY
+ { write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (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); }
+ ;
+
+exp : NSSTRING /* ObjC NextStep NSString constant
+ * of the form '@' '"' string '"'.
+ */
+ { write_exp_elt_opcode (OP_OBJC_NSSTRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_OBJC_NSSTRING); }
+ ;
+
+block : BLOCKNAME
+ {
+ if ($1.sym != 0)
+ $$ = SYMBOL_BLOCK_VALUE ($1.sym);
+ else
+ {
+ struct symtab *tem =
+ lookup_symtab (copy_name ($1.stoken));
+ if (tem)
+ $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), STATIC_BLOCK);
+ else
+ error ("No file or function \"%s\".",
+ copy_name ($1.stoken));
+ }
+ }
+ ;
+
+block : block COLONCOLON name
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_DOMAIN, (int *) NULL,
+ (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_DOMAIN, (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 (!DEPRECATED_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_DOMAIN, (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++/ObjC: it hangs off of `this'/'self'.
+ Must not inadvertently convert from a
+ method call to data ref. */
+ if (innermost_block == 0 ||
+ contained_in (block_found, innermost_block))
+ innermost_block = block_found;
+ write_exp_elt_opcode (OP_OBJC_SELF);
+ write_exp_elt_opcode (OP_OBJC_SELF);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string ($1.stoken);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ char *arg = copy_name ($1.stoken);
+
+ msymbol =
+ lookup_minimal_symbol (arg, NULL, NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_msymbol (msymbol,
+ 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 ($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; }
+ | CLASSNAME
+ {
+ if ($1.type == NULL)
+ error ("No symbol \"%s\" in current context.",
+ copy_name($1.stoken));
+ else
+ $$ = $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);
+ $<ivec>$[0] = 1; /* Number of types in vector. */
+ $$[1] = $1;
+ }
+ | nonempty_typelist ',' type
+ { int len = sizeof (struct type *) * (++($<ivec>1[0]) + 1);
+ $$ = (struct type **) realloc ((char *) $1, len);
+ $$[$<ivec>$[0]] = $3;
+ }
+ ;
+
+name : NAME { $$ = $1.stoken; }
+ | BLOCKNAME { $$ = $1.stoken; }
+ | TYPENAME { $$ = $1.stoken; }
+ | CLASSNAME { $$ = $1.stoken; }
+ | NAME_OR_INT { $$ = $1.stoken; }
+ ;
+
+name_not_typename : NAME
+ | BLOCKNAME
+/* These would be useful if name_not_typename was useful, but it is
+ just a fake for "variable", so these cause reduce/reduce conflicts
+ because the parser can't tell whether NAME_OR_INT is a
+ name_not_typename (=variable, =exp) or just an exp. If
+ name_not_typename was ever used in an lvalue context where only a
+ name could occur, this might be useful. */
+/* | NAME_OR_INT */
+ ;
+
+%%
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr. LEN is the
+ number of characters in it. */
+
+/*** Needs some error checking for the float case. ***/
+
+static int
+parse_number (p, len, parsed_float, putithere)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ /* FIXME: Shouldn't these be unsigned? We don't deal with negative
+ values here, and we do kind of silly things like cast to
+ unsigned. */
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ unsigned LONGEST un;
+
+ int i = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
+ int long_p = 0;
+
+ /* We have found a "L" or "U" suffix. */
+ int found_suffix = 0;
+
+ unsigned LONGEST high_bit;
+ struct type *signed_type;
+ struct type *unsigned_type;
+
+ if (parsed_float)
+ {
+ 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", (float *)&putithere->typed_val_float.dval);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ sscanf (p, "%lg", (double *)&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, and 0. */
+ if (p[0] == '0')
+ switch (p[1])
+ {
+ case 'x':
+ case 'X':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ break;
+
+ case 't':
+ case 'T':
+ case 'd':
+ case 'D':
+ if (len >= 3)
+ {
+ p += 2;
+ base = 10;
+ len -= 2;
+ }
+ break;
+
+ default:
+ base = 8;
+ break;
+ }
+
+ while (len-- > 0)
+ {
+ c = *p++;
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != 'l' && c != 'u')
+ n *= base;
+ if (c >= '0' && c <= '9')
+ {
+ if (found_suffix)
+ return ERROR;
+ n += i = c - '0';
+ }
+ else
+ {
+ if (base > 10 && c >= 'a' && c <= 'f')
+ {
+ if (found_suffix)
+ return ERROR;
+ n += i = c - 'a' + 10;
+ }
+ else if (c == 'l')
+ {
+ ++long_p;
+ found_suffix = 1;
+ }
+ else if (c == 'u')
+ {
+ unsigned_p = 1;
+ found_suffix = 1;
+ }
+ else
+ return ERROR; /* Char not a digit. */
+ }
+ if (i >= base)
+ return ERROR; /* Invalid digit in this base. */
+
+ /* Portably test for overflow (only works for nonzero values, so
+ make a second check for zero). FIXME: Can't we just make n
+ and prevn unsigned and avoid this? */
+ if (c != 'l' && c != 'u' && (prevn >= n) && n != 0)
+ unsigned_p = 1; /* Try something unsigned. */
+
+ /* Portably test for unsigned overflow.
+ FIXME: This check is wrong; for example it doesn't find
+ overflow on 0x123456789 when LONGEST is 32 bits. */
+ if (c != 'l' && c != 'u' && n != 0)
+ {
+ if ((unsigned_p && (unsigned LONGEST) prevn >= (unsigned LONGEST) n))
+ error ("Numeric constant too large.");
+ }
+ prevn = n;
+ }
+
+ /* An integer constant is an int, a long, or a long long. An L
+ suffix forces it to be long; an LL suffix forces it to be long
+ long. If not forced to a larger size, it gets the first type of
+ the above that it fits in. To figure out whether it fits, we
+ shift it right and see whether anything remains. Note that we
+ can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one
+ operation, because many compilers will warn about such a shift
+ (which always produces a zero result). Sometimes 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, tokchr;
+ int namelen;
+ unsigned int i;
+ char *tokstart;
+ char *tokptr;
+ int tempbufindex;
+ static char *tempbuf;
+ static int tempbufsize;
+
+ retry:
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (DEPRECATED_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 (DEPRECATED_STREQN (tokstart, tokentab2[i].operator, 2))
+ {
+ lexptr += 2;
+ yylval.opcode = tokentab2[i].opcode;
+ return tokentab2[i].token;
+ }
+
+ c = 0;
+ switch (tokchr = *tokstart)
+ {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ /* We either have a character constant ('0' or '\177' for
+ example) or we have a quoted symbol reference ('foo(int,int)'
+ in C++ for example). */
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&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 '(';
+
+ case ')':
+ if (paren_depth == 0)
+ return 0;
+ paren_depth--;
+ lexptr++;
+ return ')';
+
+ case ',':
+ if (comma_terminates && paren_depth == 0)
+ return 0;
+ lexptr++;
+ return ',';
+
+ case '.':
+ /* Might be a floating point number. */
+ if (lexptr[1] < '0' || lexptr[1] > '9')
+ goto symbol; /* Nope, must be a symbol. */
+ /* FALL THRU into number case. */
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0, toktype = FLOAT;
+ /* Initialize toktype to anything other than ERROR. */
+ char *p = tokstart;
+ int hex = input_radix > 10;
+ int local_radix = input_radix;
+ if (tokchr == '0' && (p[1] == 'x' || p[1] == 'X'))
+ {
+ p += 2;
+ hex = 1;
+ local_radix = 16;
+ }
+ else if (tokchr == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
+ {
+ p += 2;
+ hex = 0;
+ local_radix = 10;
+ }
+
+ for (;; ++p)
+ {
+ /* This test includes !hex because 'e' is a valid hex digit
+ and thus does not indicate a floating point number when
+ the radix is hex. */
+
+ if (!hex && (*p == 'e' || *p == 'E'))
+ if (got_e)
+ toktype = ERROR; /* Only one 'e' in a float. */
+ else
+ got_e = 1;
+ /* This test does not include !hex, because a '.' always
+ indicates a decimal floating point number regardless of
+ the radix. */
+ else if (*p == '.')
+ if (got_dot)
+ toktype = ERROR; /* Only one '.' in a float. */
+ else
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E') &&
+ (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ /* Always take decimal digits; parse_number handles radix
+ error. */
+ else if (*p >= '0' && *p <= '9')
+ continue;
+ /* We will take letters only if hex is true, and only up
+ to what the input radix would permit. FSF was content
+ to rely on parse_number to validate; but it leaks. */
+ else if (*p >= 'a' && *p <= 'z')
+ {
+ if (!hex || *p >= ('a' + local_radix - 10))
+ toktype = ERROR;
+ }
+ else if (*p >= 'A' && *p <= 'Z')
+ {
+ if (!hex || *p >= ('A' + local_radix - 10))
+ toktype = ERROR;
+ }
+ else break;
+ }
+ if (toktype != ERROR)
+ toktype = parse_number (tokstart, p - tokstart,
+ got_dot | got_e, &yylval);
+ if (toktype == ERROR)
+ {
+ char *err_copy = (char *) alloca (p - tokstart + 1);
+
+ memcpy (err_copy, tokstart, p - tokstart);
+ err_copy[p - tokstart] = 0;
+ error ("Invalid number \"%s\".", err_copy);
+ }
+ lexptr = p;
+ return toktype;
+ }
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+#if 0
+ case '@': /* Moved out below. */
+#endif
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ symbol:
+ lexptr++;
+ return tokchr;
+
+ case '@':
+ if (strncmp(tokstart, "@selector", 9) == 0)
+ {
+ tokptr = strchr(tokstart, '(');
+ if (tokptr == NULL)
+ {
+ error ("Missing '(' in @selector(...)");
+ }
+ tempbufindex = 0;
+ tokptr++; /* Skip the '('. */
+ do {
+ /* Grow the static temp buffer if necessary, including
+ allocating the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) realloc (tempbuf, tempbufsize += 64);
+ }
+ tempbuf[tempbufindex++] = *tokptr++;
+ } while ((*tokptr != ')') && (*tokptr != '\0'));
+ if (*tokptr++ != ')')
+ {
+ error ("Missing ')' in @selector(...)");
+ }
+ tempbuf[tempbufindex] = '\0';
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbufindex;
+ lexptr = tokptr;
+ return SELECTOR;
+ }
+ if (tokstart[1] != '"')
+ {
+ lexptr++;
+ return tokchr;
+ }
+ /* ObjC NextStep NSString constant: fall thru and parse like
+ STRING. */
+ tokstart++;
+
+ case '"':
+
+ /* Build the gdb internal form of the input string in tempbuf,
+ translating any standard C escape forms seen. Note that the
+ buffer is null byte terminated *only* for the convenience of
+ debugging gdb itself and printing the buffer contents when
+ the buffer contains no embedded nulls. Gdb does not depend
+ upon the buffer being null byte terminated, it uses the
+ length string instead. This allows gdb to handle C strings
+ (as well as strings in other languages) with embedded null
+ bytes. */
+
+ tokptr = ++tokstart;
+ tempbufindex = 0;
+
+ do {
+ /* Grow the static temp buffer if necessary, including
+ allocating the first one on demand. */
+ if (tempbufindex + 1 >= tempbufsize)
+ {
+ tempbuf = (char *) realloc (tempbuf, tempbufsize += 64);
+ }
+ switch (*tokptr)
+ {
+ case '\0':
+ case '"':
+ /* Do nothing, loop will terminate. */
+ break;
+ case '\\':
+ tokptr++;
+ c = parse_escape (&tokptr);
+ if (c == -1)
+ {
+ continue;
+ }
+ tempbuf[tempbufindex++] = c;
+ break;
+ default:
+ tempbuf[tempbufindex++] = *tokptr++;
+ break;
+ }
+ } while ((*tokptr != '"') && (*tokptr != '\0'));
+ if (*tokptr++ != '"')
+ {
+ error ("Unterminated string in expression.");
+ }
+ tempbuf[tempbufindex] = '\0'; /* See note above. */
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = tempbufindex;
+ lexptr = tokptr;
+ return (tokchr == '@' ? NSSTRING : STRING);
+ }
+
+ if (!(tokchr == '_' || tokchr == '$' ||
+ (tokchr >= 'a' && tokchr <= 'z') || (tokchr >= 'A' && tokchr <= 'Z')))
+ /* We must have come across a bad character (e.g. ';'). */
+ error ("Invalid character '%c' in expression.", c);
+
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ for (c = tokstart[namelen];
+ (c == '_' || c == '$' || (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');)
+ {
+ if (c == '<')
+ {
+ int i = namelen;
+ while (tokstart[++i] && tokstart[i] != '>');
+ if (tokstart[i] == '>')
+ namelen = i;
+ }
+ c = tokstart[++namelen];
+ }
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ tryname:
+
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 8:
+ if (DEPRECATED_STREQN (tokstart, "unsigned", 8))
+ return UNSIGNED;
+ if (current_language->la_language == language_cplus
+ && strncmp (tokstart, "template", 8) == 0)
+ return TEMPLATE;
+ if (DEPRECATED_STREQN (tokstart, "volatile", 8))
+ return VOLATILE_KEYWORD;
+ break;
+ case 6:
+ if (DEPRECATED_STREQN (tokstart, "struct", 6))
+ return STRUCT;
+ if (DEPRECATED_STREQN (tokstart, "signed", 6))
+ return SIGNED_KEYWORD;
+ if (DEPRECATED_STREQN (tokstart, "sizeof", 6))
+ return SIZEOF;
+ if (DEPRECATED_STREQN (tokstart, "double", 6))
+ return DOUBLE_KEYWORD;
+ break;
+ case 5:
+ if ((current_language->la_language == language_cplus)
+ && strncmp (tokstart, "class", 5) == 0)
+ return CLASS;
+ if (DEPRECATED_STREQN (tokstart, "union", 5))
+ return UNION;
+ if (DEPRECATED_STREQN (tokstart, "short", 5))
+ return SHORT;
+ if (DEPRECATED_STREQN (tokstart, "const", 5))
+ return CONST_KEYWORD;
+ break;
+ case 4:
+ if (DEPRECATED_STREQN (tokstart, "enum", 4))
+ return ENUM;
+ if (DEPRECATED_STREQN (tokstart, "long", 4))
+ return LONG;
+ break;
+ case 3:
+ if (DEPRECATED_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, *need_this;
+ int hextype;
+
+ if (current_language->la_language == language_cplus ||
+ current_language->la_language == language_objc)
+ need_this = &is_a_field_of_this;
+ else
+ need_this = (int *) NULL;
+
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ need_this,
+ (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 symbols are read). */
+ if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) ||
+ lookup_symtab (tmp))
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return BLOCKNAME;
+ }
+ if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+#if 1
+ /* Despite the following flaw, we need to keep this code
+ enabled. Because we can get called from
+ check_stub_method, if we don't handle nested types then
+ it screws many operations in any program which uses
+ nested types. */
+ /* In "A::x", if x is a member function of A and there
+ happens to be a type (nested or not, since the stabs
+ don't make that distinction) named x, then this code
+ incorrectly thinks we are dealing with nested types
+ rather than a member function. */
+
+ char *p;
+ char *namestart;
+ struct symbol *best_sym;
+
+ /* Look ahead to detect nested types. This probably should
+ be done in the grammar, but trying seemed to introduce a
+ lot of shift/reduce and reduce/reduce conflicts. It's
+ possible that it could be done, though. Or perhaps a
+ non-grammar, but less ad hoc, approach would work well. */
+
+ /* Since we do not currently have any way of distinguishing
+ a nested type from a non-nested one (the stabs don't tell
+ us whether a type is nested), we just ignore the
+ containing type. */
+
+ p = lexptr;
+ best_sym = sym;
+ while (1)
+ {
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ if (*p == ':' && p[1] == ':')
+ {
+ /* Skip the `::'. */
+ p += 2;
+ /* Skip whitespace. */
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ ++p;
+ namestart = p;
+ while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9')
+ || (*p >= 'a' && *p <= 'z')
+ || (*p >= 'A' && *p <= 'Z'))
+ ++p;
+ if (p != namestart)
+ {
+ struct symbol *cur_sym;
+ /* As big as the whole rest of the expression,
+ which is at least big enough. */
+ char *ncopy = alloca (strlen (tmp) +
+ strlen (namestart) + 3);
+ char *tmp1;
+
+ tmp1 = ncopy;
+ memcpy (tmp1, tmp, strlen (tmp));
+ tmp1 += strlen (tmp);
+ memcpy (tmp1, "::", 2);
+ tmp1 += 2;
+ memcpy (tmp1, namestart, p - namestart);
+ tmp1[p - namestart] = '\0';
+ cur_sym = lookup_symbol (ncopy,
+ expression_context_block,
+ VAR_DOMAIN, (int *) NULL,
+ (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;
+
+ /* See if it's an ObjC classname. */
+ if (!sym)
+ {
+ CORE_ADDR Class = lookup_objc_class(tmp);
+ if (Class)
+ {
+ yylval.class.class = Class;
+ if ((sym = lookup_struct_typedef (tmp,
+ expression_context_block,
+ 1)))
+ yylval.class.type = SYMBOL_TYPE (sym);
+ return CLASSNAME;
+ }
+ }
+
+ /* Input names that aren't symbols but ARE valid hex numbers,
+ when the input radix permits them, can be names or numbers
+ depending on the parse. Note we support radixes > 16 here. */
+ if (!sym &&
+ ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) ||
+ (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
+ {
+ YYSTYPE newlval; /* Its value is ignored. */
+ hextype = parse_number (tokstart, namelen, 0, &newlval);
+ if (hextype == INT)
+ {
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME_OR_INT;
+ }
+ }
+
+ /* Any other kind of symbol. */
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME;
+ }
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ if (*lexptr == '\0')
+ error("A %s near end of expression.", (msg ? msg : "error"));
+ else
+ error ("A %s in expression, near `%s'.", (msg ? msg : "error"),
+ lexptr);
+}
diff --git a/contrib/gdb/gdb/objc-lang.c b/contrib/gdb/gdb/objc-lang.c
new file mode 100644
index 0000000..5c184f3
--- /dev/null
+++ b/contrib/gdb/gdb/objc-lang.c
@@ -0,0 +1,1929 @@
+/* Objective-C language support routines for GDB, the GNU debugger.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Apple Computer, Inc.
+ Written by Michael Snyder.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "objc-lang.h"
+#include "complaints.h"
+#include "value.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h" /* for strchr */
+#include "target.h" /* for target_has_execution */
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "frame.h"
+#include "gdb_regex.h"
+#include "regcache.h"
+#include "block.h"
+#include "infcall.h"
+#include "valprint.h"
+#include "gdb_assert.h"
+
+#include <ctype.h>
+
+struct objc_object {
+ CORE_ADDR isa;
+};
+
+struct objc_class {
+ CORE_ADDR isa;
+ CORE_ADDR super_class;
+ CORE_ADDR name;
+ long version;
+ long info;
+ long instance_size;
+ CORE_ADDR ivars;
+ CORE_ADDR methods;
+ CORE_ADDR cache;
+ CORE_ADDR protocols;
+};
+
+struct objc_super {
+ CORE_ADDR receiver;
+ CORE_ADDR class;
+};
+
+struct objc_method {
+ CORE_ADDR name;
+ CORE_ADDR types;
+ CORE_ADDR imp;
+};
+
+/* Lookup a structure type named "struct NAME", visible in lexical
+ block BLOCK. If NOERR is nonzero, return zero if NAME is not
+ suitably defined. */
+
+struct symbol *
+lookup_struct_typedef (char *name, struct block *block, int noerr)
+{
+ struct symbol *sym;
+
+ sym = lookup_symbol (name, block, STRUCT_DOMAIN, 0,
+ (struct symtab **) NULL);
+
+ if (sym == NULL)
+ {
+ if (noerr)
+ return 0;
+ else
+ error ("No struct type named %s.", name);
+ }
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
+ {
+ if (noerr)
+ return 0;
+ else
+ error ("This context has class, union or enum %s, not a struct.",
+ name);
+ }
+ return sym;
+}
+
+CORE_ADDR
+lookup_objc_class (char *classname)
+{
+ struct value * function, *classval;
+
+ if (! target_has_execution)
+ {
+ /* Can't call into inferior to lookup class. */
+ return 0;
+ }
+
+ if (lookup_minimal_symbol("objc_lookUpClass", 0, 0))
+ function = find_function_in_inferior("objc_lookUpClass");
+ else if (lookup_minimal_symbol ("objc_lookup_class", 0, 0))
+ function = find_function_in_inferior("objc_lookup_class");
+ else
+ {
+ complaint (&symfile_complaints, "no way to lookup Objective-C classes");
+ return 0;
+ }
+
+ classval = value_string (classname, strlen (classname) + 1);
+ classval = value_coerce_array (classval);
+ return (CORE_ADDR) value_as_long (call_function_by_hand (function,
+ 1, &classval));
+}
+
+CORE_ADDR
+lookup_child_selector (char *selname)
+{
+ struct value * function, *selstring;
+
+ if (! target_has_execution)
+ {
+ /* Can't call into inferior to lookup selector. */
+ return 0;
+ }
+
+ if (lookup_minimal_symbol("sel_getUid", 0, 0))
+ function = find_function_in_inferior("sel_getUid");
+ else if (lookup_minimal_symbol ("sel_get_any_uid", 0, 0))
+ function = find_function_in_inferior("sel_get_any_uid");
+ else
+ {
+ complaint (&symfile_complaints, "no way to lookup Objective-C selectors");
+ return 0;
+ }
+
+ selstring = value_coerce_array (value_string (selname,
+ strlen (selname) + 1));
+ return value_as_long (call_function_by_hand (function, 1, &selstring));
+}
+
+struct value *
+value_nsstring (char *ptr, int len)
+{
+ struct value *stringValue[3];
+ struct value *function, *nsstringValue;
+ struct symbol *sym;
+ struct type *type;
+
+ if (!target_has_execution)
+ return 0; /* Can't call into inferior to create NSString. */
+
+ sym = lookup_struct_typedef("NSString", 0, 1);
+ if (sym == NULL)
+ sym = lookup_struct_typedef("NXString", 0, 1);
+ if (sym == NULL)
+ type = lookup_pointer_type(builtin_type_void);
+ else
+ type = lookup_pointer_type(SYMBOL_TYPE (sym));
+
+ stringValue[2] = value_string(ptr, len);
+ stringValue[2] = value_coerce_array(stringValue[2]);
+ /* _NSNewStringFromCString replaces "istr" after Lantern2A. */
+ if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0))
+ {
+ function = find_function_in_inferior("_NSNewStringFromCString");
+ nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
+ }
+ else if (lookup_minimal_symbol("istr", 0, 0))
+ {
+ function = find_function_in_inferior("istr");
+ nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
+ }
+ else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0))
+ {
+ function = find_function_in_inferior("+[NSString stringWithCString:]");
+ stringValue[0] = value_from_longest
+ (builtin_type_long, lookup_objc_class ("NSString"));
+ stringValue[1] = value_from_longest
+ (builtin_type_long, lookup_child_selector ("stringWithCString:"));
+ nsstringValue = call_function_by_hand(function, 3, &stringValue[0]);
+ }
+ else
+ error ("NSString: internal error -- no way to create new NSString");
+
+ VALUE_TYPE(nsstringValue) = type;
+ return nsstringValue;
+}
+
+/* Objective-C name demangling. */
+
+char *
+objc_demangle (const char *mangled, int options)
+{
+ char *demangled, *cp;
+
+ if (mangled[0] == '_' &&
+ (mangled[1] == 'i' || mangled[1] == 'c') &&
+ mangled[2] == '_')
+ {
+ cp = demangled = xmalloc(strlen(mangled) + 2);
+
+ if (mangled[1] == 'i')
+ *cp++ = '-'; /* for instance method */
+ else
+ *cp++ = '+'; /* for class method */
+
+ *cp++ = '['; /* opening left brace */
+ strcpy(cp, mangled+3); /* tack on the rest of the mangled name */
+
+ while (*cp && *cp == '_')
+ cp++; /* skip any initial underbars in class name */
+
+ cp = strchr(cp, '_');
+ if (!cp) /* find first non-initial underbar */
+ {
+ xfree(demangled); /* not mangled name */
+ return NULL;
+ }
+ if (cp[1] == '_') { /* easy case: no category name */
+ *cp++ = ' '; /* replace two '_' with one ' ' */
+ strcpy(cp, mangled + (cp - demangled) + 2);
+ }
+ else {
+ *cp++ = '('; /* less easy case: category name */
+ cp = strchr(cp, '_');
+ if (!cp)
+ {
+ xfree(demangled); /* not mangled name */
+ return NULL;
+ }
+ *cp++ = ')';
+ *cp++ = ' '; /* overwriting 1st char of method name... */
+ strcpy(cp, mangled + (cp - demangled)); /* get it back */
+ }
+
+ while (*cp && *cp == '_')
+ cp++; /* skip any initial underbars in method name */
+
+ for (; *cp; cp++)
+ if (*cp == '_')
+ *cp = ':'; /* replace remaining '_' with ':' */
+
+ *cp++ = ']'; /* closing right brace */
+ *cp++ = 0; /* string terminator */
+ return demangled;
+ }
+ else
+ return NULL; /* Not an objc mangled name. */
+}
+
+/* Print the character C on STREAM as part of the contents of a
+ literal string whose delimiter is QUOTER. Note that that format
+ for printing characters and strings is language specific. */
+
+static void
+objc_emit_char (int c, struct ui_file *stream, int quoter)
+{
+
+ c &= 0xFF; /* Avoid sign bit follies. */
+
+ if (PRINT_LITERAL_FORM (c))
+ {
+ if (c == '\\' || c == quoter)
+ {
+ fputs_filtered ("\\", stream);
+ }
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\n':
+ fputs_filtered ("\\n", stream);
+ break;
+ case '\b':
+ fputs_filtered ("\\b", stream);
+ break;
+ case '\t':
+ fputs_filtered ("\\t", stream);
+ break;
+ case '\f':
+ fputs_filtered ("\\f", stream);
+ break;
+ case '\r':
+ fputs_filtered ("\\r", stream);
+ break;
+ case '\033':
+ fputs_filtered ("\\e", stream);
+ break;
+ case '\007':
+ fputs_filtered ("\\a", stream);
+ break;
+ default:
+ fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+}
+
+static void
+objc_printchar (int c, struct ui_file *stream)
+{
+ fputs_filtered ("'", stream);
+ objc_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. */
+
+static void
+objc_printstr (struct ui_file *stream, char *string,
+ unsigned int length, int width, int force_ellipses)
+{
+ unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+
+ /* If the string was not truncated due to `set print elements', and
+ the last byte of it is a null, we don't print that, in
+ traditional C style. */
+ if ((!force_ellipses) && length > 0 && string[length-1] == '\0')
+ length--;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", stream);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < 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;
+ }
+ objc_printchar (string[i], stream);
+ fprintf_filtered (stream, " <repeats %u times>", 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;
+ }
+ objc_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.
+
+ 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 disagreement 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 */
+
+static struct type *
+objc_create_fundamental_type (struct objfile *objfile, int typeid)
+{
+ 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 "<?type?>". 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, "<?type?>", 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);
+}
+
+/* Determine if we are currently in the Objective-C dispatch function.
+ If so, get the address of the method function that the dispatcher
+ would call and use that as the function to step into instead. Also
+ skip over the trampoline for the function (if any). This is better
+ for the user since they are only interested in stepping into the
+ method function anyway. */
+static CORE_ADDR
+objc_skip_trampoline (CORE_ADDR stop_pc)
+{
+ CORE_ADDR real_stop_pc;
+ CORE_ADDR method_stop_pc;
+
+ real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc);
+
+ if (real_stop_pc != 0)
+ find_objc_msgcall (real_stop_pc, &method_stop_pc);
+ else
+ find_objc_msgcall (stop_pc, &method_stop_pc);
+
+ if (method_stop_pc)
+ {
+ real_stop_pc = SKIP_TRAMPOLINE_CODE (method_stop_pc);
+ if (real_stop_pc == 0)
+ real_stop_pc = method_stop_pc;
+ }
+
+ return real_stop_pc;
+}
+
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+static const struct op_print objc_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},
+ {NULL, OP_NULL, PREC_NULL, 0}
+};
+
+struct type ** const (objc_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 objc_language_defn = {
+ "objective-c", /* Language name */
+ language_objc,
+ objc_builtin_types,
+ range_check_off,
+ type_check_off,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ objc_parse,
+ objc_error,
+ objc_printchar, /* Print a character constant */
+ objc_printstr, /* Function to print string constant */
+ objc_emit_char,
+ objc_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 */
+ objc_skip_trampoline, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ objc_demangle, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"0x%lx", "0x", "x", ""}, /* Hex format info */
+ objc_op_print_tab, /* Expression operators for printing */
+ 1, /* C-style arrays */
+ 0, /* String lower bound */
+ &builtin_type_char, /* Type of string elements */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+/*
+ * ObjC:
+ * Following functions help construct Objective-C message calls
+ */
+
+struct selname /* For parsing Objective-C. */
+ {
+ struct selname *next;
+ char *msglist_sel;
+ int msglist_len;
+ };
+
+static int msglist_len;
+static struct selname *selname_chain;
+static char *msglist_sel;
+
+void
+start_msglist(void)
+{
+ struct selname *new =
+ (struct selname *) xmalloc (sizeof (struct selname));
+
+ new->next = selname_chain;
+ new->msglist_len = msglist_len;
+ new->msglist_sel = msglist_sel;
+ msglist_len = 0;
+ msglist_sel = (char *)xmalloc(1);
+ *msglist_sel = 0;
+ selname_chain = new;
+}
+
+void
+add_msglist(struct stoken *str, int addcolon)
+{
+ char *s, *p;
+ int len, plen;
+
+ if (str == 0) { /* Unnamed arg, or... */
+ if (addcolon == 0) { /* variable number of args. */
+ msglist_len++;
+ return;
+ }
+ p = "";
+ plen = 0;
+ } else {
+ p = str->ptr;
+ plen = str->length;
+ }
+ len = plen + strlen(msglist_sel) + 2;
+ s = (char *)xmalloc(len);
+ strcpy(s, msglist_sel);
+ strncat(s, p, plen);
+ xfree(msglist_sel);
+ msglist_sel = s;
+ if (addcolon) {
+ s[len-2] = ':';
+ s[len-1] = 0;
+ msglist_len++;
+ } else
+ s[len-2] = '\0';
+}
+
+int
+end_msglist(void)
+{
+ int val = msglist_len;
+ struct selname *sel = selname_chain;
+ char *p = msglist_sel;
+ CORE_ADDR selid;
+
+ selname_chain = sel->next;
+ msglist_len = sel->msglist_len;
+ msglist_sel = sel->msglist_sel;
+ selid = lookup_child_selector(p);
+ if (!selid)
+ error("Can't find selector \"%s\"", p);
+ write_exp_elt_longcst (selid);
+ xfree(p);
+ write_exp_elt_longcst (val); /* Number of args */
+ xfree(sel);
+
+ return val;
+}
+
+/*
+ * Function: specialcmp (char *a, char *b)
+ *
+ * Special strcmp: treats ']' and ' ' as end-of-string.
+ * Used for qsorting lists of objc methods (either by class or selector).
+ */
+
+static int
+specialcmp (char *a, char *b)
+{
+ while (*a && *a != ' ' && *a != ']' && *b && *b != ' ' && *b != ']')
+ {
+ if (*a != *b)
+ return *a - *b;
+ a++, b++;
+ }
+ if (*a && *a != ' ' && *a != ']')
+ return 1; /* a is longer therefore greater */
+ if (*b && *b != ' ' && *b != ']')
+ return -1; /* a is shorter therefore lesser */
+ return 0; /* a and b are identical */
+}
+
+/*
+ * Function: compare_selectors (const void *, const void *)
+ *
+ * Comparison function for use with qsort. Arguments are symbols or
+ * msymbols Compares selector part of objc method name alphabetically.
+ */
+
+static int
+compare_selectors (const void *a, const void *b)
+{
+ char *aname, *bname;
+
+ aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
+ bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
+ if (aname == NULL || bname == NULL)
+ error ("internal: compare_selectors(1)");
+
+ aname = strchr(aname, ' ');
+ bname = strchr(bname, ' ');
+ if (aname == NULL || bname == NULL)
+ error ("internal: compare_selectors(2)");
+
+ return specialcmp (aname+1, bname+1);
+}
+
+/*
+ * Function: selectors_info (regexp, from_tty)
+ *
+ * Implements the "Info selectors" command. Takes an optional regexp
+ * arg. Lists all objective c selectors that match the regexp. Works
+ * by grepping thru all symbols for objective c methods. Output list
+ * is sorted and uniqued.
+ */
+
+static void
+selectors_info (char *regexp, int from_tty)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ char *name;
+ char *val;
+ int matches = 0;
+ int maxlen = 0;
+ int ix;
+ char myregexp[2048];
+ char asel[256];
+ struct symbol **sym_arr;
+ int plusminus = 0;
+
+ if (regexp == NULL)
+ strcpy(myregexp, ".*]"); /* Null input, match all objc methods. */
+ else
+ {
+ if (*regexp == '+' || *regexp == '-')
+ { /* User wants only class methods or only instance methods. */
+ plusminus = *regexp++;
+ while (*regexp == ' ' || *regexp == '\t')
+ regexp++;
+ }
+ if (*regexp == '\0')
+ strcpy(myregexp, ".*]");
+ else
+ {
+ strcpy(myregexp, regexp);
+ if (myregexp[strlen(myregexp) - 1] == '$') /* end of selector */
+ myregexp[strlen(myregexp) - 1] = ']'; /* end of method name */
+ else
+ strcat(myregexp, ".*]");
+ }
+ }
+
+ if (regexp != NULL)
+ {
+ val = re_comp (myregexp);
+ if (val != 0)
+ error ("Invalid regexp (%s): %s", val, regexp);
+ }
+
+ /* First time thru is JUST to get max length and count. */
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ QUIT;
+ name = SYMBOL_NATURAL_NAME (msymbol);
+ if (name &&
+ (name[0] == '-' || name[0] == '+') &&
+ name[1] == '[') /* Got a method name. */
+ {
+ /* Filter for class/instance methods. */
+ if (plusminus && name[0] != plusminus)
+ continue;
+ /* Find selector part. */
+ name = (char *) strchr(name+2, ' ');
+ if (regexp == NULL || re_exec(++name) != 0)
+ {
+ char *mystart = name;
+ char *myend = (char *) strchr(mystart, ']');
+
+ if (myend && (myend - mystart > maxlen))
+ maxlen = myend - mystart; /* Get longest selector. */
+ matches++;
+ }
+ }
+ }
+ if (matches)
+ {
+ printf_filtered ("Selectors matching \"%s\":\n\n",
+ regexp ? regexp : "*");
+
+ sym_arr = alloca (matches * sizeof (struct symbol *));
+ matches = 0;
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ QUIT;
+ name = SYMBOL_NATURAL_NAME (msymbol);
+ if (name &&
+ (name[0] == '-' || name[0] == '+') &&
+ name[1] == '[') /* Got a method name. */
+ {
+ /* Filter for class/instance methods. */
+ if (plusminus && name[0] != plusminus)
+ continue;
+ /* Find selector part. */
+ name = (char *) strchr(name+2, ' ');
+ if (regexp == NULL || re_exec(++name) != 0)
+ sym_arr[matches++] = (struct symbol *) msymbol;
+ }
+ }
+
+ qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
+ compare_selectors);
+ /* Prevent compare on first iteration. */
+ asel[0] = 0;
+ for (ix = 0; ix < matches; ix++) /* Now do the output. */
+ {
+ char *p = asel;
+
+ QUIT;
+ name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
+ name = strchr (name, ' ') + 1;
+ if (p[0] && specialcmp(name, p) == 0)
+ continue; /* Seen this one already (not unique). */
+
+ /* Copy selector part. */
+ while (*name && *name != ']')
+ *p++ = *name++;
+ *p++ = '\0';
+ /* Print in columns. */
+ puts_filtered_tabular(asel, maxlen + 1, 0);
+ }
+ begin_line();
+ }
+ else
+ printf_filtered ("No selectors matching \"%s\"\n", regexp ? regexp : "*");
+}
+
+/*
+ * Function: compare_classes (const void *, const void *)
+ *
+ * Comparison function for use with qsort. Arguments are symbols or
+ * msymbols Compares class part of objc method name alphabetically.
+ */
+
+static int
+compare_classes (const void *a, const void *b)
+{
+ char *aname, *bname;
+
+ aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
+ bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
+ if (aname == NULL || bname == NULL)
+ error ("internal: compare_classes(1)");
+
+ return specialcmp (aname+1, bname+1);
+}
+
+/*
+ * Function: classes_info(regexp, from_tty)
+ *
+ * Implements the "info classes" command for objective c classes.
+ * Lists all objective c classes that match the optional regexp.
+ * Works by grepping thru the list of objective c methods. List will
+ * be sorted and uniqued (since one class may have many methods).
+ * BUGS: will not list a class that has no methods.
+ */
+
+static void
+classes_info (char *regexp, int from_tty)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ char *name;
+ char *val;
+ int matches = 0;
+ int maxlen = 0;
+ int ix;
+ char myregexp[2048];
+ char aclass[256];
+ struct symbol **sym_arr;
+
+ if (regexp == NULL)
+ strcpy(myregexp, ".* "); /* Null input: match all objc classes. */
+ else
+ {
+ strcpy(myregexp, regexp);
+ if (myregexp[strlen(myregexp) - 1] == '$')
+ /* In the method name, the end of the class name is marked by ' '. */
+ myregexp[strlen(myregexp) - 1] = ' ';
+ else
+ strcat(myregexp, ".* ");
+ }
+
+ if (regexp != NULL)
+ {
+ val = re_comp (myregexp);
+ if (val != 0)
+ error ("Invalid regexp (%s): %s", val, regexp);
+ }
+
+ /* First time thru is JUST to get max length and count. */
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ QUIT;
+ name = SYMBOL_NATURAL_NAME (msymbol);
+ if (name &&
+ (name[0] == '-' || name[0] == '+') &&
+ name[1] == '[') /* Got a method name. */
+ if (regexp == NULL || re_exec(name+2) != 0)
+ {
+ /* Compute length of classname part. */
+ char *mystart = name + 2;
+ char *myend = (char *) strchr(mystart, ' ');
+
+ if (myend && (myend - mystart > maxlen))
+ maxlen = myend - mystart;
+ matches++;
+ }
+ }
+ if (matches)
+ {
+ printf_filtered ("Classes matching \"%s\":\n\n",
+ regexp ? regexp : "*");
+ sym_arr = alloca (matches * sizeof (struct symbol *));
+ matches = 0;
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ QUIT;
+ name = SYMBOL_NATURAL_NAME (msymbol);
+ if (name &&
+ (name[0] == '-' || name[0] == '+') &&
+ name[1] == '[') /* Got a method name. */
+ if (regexp == NULL || re_exec(name+2) != 0)
+ sym_arr[matches++] = (struct symbol *) msymbol;
+ }
+
+ qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
+ compare_classes);
+ /* Prevent compare on first iteration. */
+ aclass[0] = 0;
+ for (ix = 0; ix < matches; ix++) /* Now do the output. */
+ {
+ char *p = aclass;
+
+ QUIT;
+ name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
+ name += 2;
+ if (p[0] && specialcmp(name, p) == 0)
+ continue; /* Seen this one already (not unique). */
+
+ /* Copy class part of method name. */
+ while (*name && *name != ' ')
+ *p++ = *name++;
+ *p++ = '\0';
+ /* Print in columns. */
+ puts_filtered_tabular(aclass, maxlen + 1, 0);
+ }
+ begin_line();
+ }
+ else
+ printf_filtered ("No classes matching \"%s\"\n", regexp ? regexp : "*");
+}
+
+/*
+ * Function: find_imps (char *selector, struct symbol **sym_arr)
+ *
+ * Input: a string representing a selector
+ * a pointer to an array of symbol pointers
+ * possibly a pointer to a symbol found by the caller.
+ *
+ * Output: number of methods that implement that selector. Side
+ * effects: The array of symbol pointers is filled with matching syms.
+ *
+ * By analogy with function "find_methods" (symtab.c), builds a list
+ * of symbols matching the ambiguous input, so that "decode_line_2"
+ * (symtab.c) can list them and ask the user to choose one or more.
+ * In this case the matches are objective c methods
+ * ("implementations") matching an objective c selector.
+ *
+ * Note that it is possible for a normal (c-style) function to have
+ * the same name as an objective c selector. To prevent the selector
+ * from eclipsing the function, we allow the caller (decode_line_1) to
+ * search for such a function first, and if it finds one, pass it in
+ * to us. We will then integrate it into the list. We also search
+ * for one here, among the minsyms.
+ *
+ * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
+ * into two parts: debuggable (struct symbol) syms, and
+ * non_debuggable (struct minimal_symbol) syms. The debuggable
+ * ones will come first, before NUM_DEBUGGABLE (which will thus
+ * be the index of the first non-debuggable one).
+ */
+
+/*
+ * Function: total_number_of_imps (char *selector);
+ *
+ * Input: a string representing a selector
+ * Output: number of methods that implement that selector.
+ *
+ * By analogy with function "total_number_of_methods", this allows
+ * decode_line_1 (symtab.c) to detect if there are objective c methods
+ * matching the input, and to allocate an array of pointers to them
+ * which can be manipulated by "decode_line_2" (also in symtab.c).
+ */
+
+char *
+parse_selector (char *method, char **selector)
+{
+ char *s1 = NULL;
+ char *s2 = NULL;
+ int found_quote = 0;
+
+ char *nselector = NULL;
+
+ gdb_assert (selector != NULL);
+
+ s1 = method;
+
+ while (isspace (*s1))
+ s1++;
+ if (*s1 == '\'')
+ {
+ found_quote = 1;
+ s1++;
+ }
+ while (isspace (*s1))
+ s1++;
+
+ nselector = s1;
+ s2 = s1;
+
+ for (;;) {
+ if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
+ *s1++ = *s2;
+ else if (isspace (*s2))
+ ;
+ else if ((*s2 == '\0') || (*s2 == '\''))
+ break;
+ else
+ return NULL;
+ s2++;
+ }
+ *s1++ = '\0';
+
+ while (isspace (*s2))
+ s2++;
+ if (found_quote)
+ {
+ if (*s2 == '\'')
+ s2++;
+ while (isspace (*s2))
+ s2++;
+ }
+
+ if (selector != NULL)
+ *selector = nselector;
+
+ return s2;
+}
+
+char *
+parse_method (char *method, char *type, char **class,
+ char **category, char **selector)
+{
+ char *s1 = NULL;
+ char *s2 = NULL;
+ int found_quote = 0;
+
+ char ntype = '\0';
+ char *nclass = NULL;
+ char *ncategory = NULL;
+ char *nselector = NULL;
+
+ gdb_assert (type != NULL);
+ gdb_assert (class != NULL);
+ gdb_assert (category != NULL);
+ gdb_assert (selector != NULL);
+
+ s1 = method;
+
+ while (isspace (*s1))
+ s1++;
+ if (*s1 == '\'')
+ {
+ found_quote = 1;
+ s1++;
+ }
+ while (isspace (*s1))
+ s1++;
+
+ if ((s1[0] == '+') || (s1[0] == '-'))
+ ntype = *s1++;
+
+ while (isspace (*s1))
+ s1++;
+
+ if (*s1 != '[')
+ return NULL;
+ s1++;
+
+ nclass = s1;
+ while (isalnum (*s1) || (*s1 == '_'))
+ s1++;
+
+ s2 = s1;
+ while (isspace (*s2))
+ s2++;
+
+ if (*s2 == '(')
+ {
+ s2++;
+ while (isspace (*s2))
+ s2++;
+ ncategory = s2;
+ while (isalnum (*s2) || (*s2 == '_'))
+ s2++;
+ *s2++ = '\0';
+ }
+
+ /* Truncate the class name now that we're not using the open paren. */
+ *s1++ = '\0';
+
+ nselector = s2;
+ s1 = s2;
+
+ for (;;) {
+ if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
+ *s1++ = *s2;
+ else if (isspace (*s2))
+ ;
+ else if (*s2 == ']')
+ break;
+ else
+ return NULL;
+ s2++;
+ }
+ *s1++ = '\0';
+ s2++;
+
+ while (isspace (*s2))
+ s2++;
+ if (found_quote)
+ {
+ if (*s2 != '\'')
+ return NULL;
+ s2++;
+ while (isspace (*s2))
+ s2++;
+ }
+
+ if (type != NULL)
+ *type = ntype;
+ if (class != NULL)
+ *class = nclass;
+ if (category != NULL)
+ *category = ncategory;
+ if (selector != NULL)
+ *selector = nselector;
+
+ return s2;
+}
+
+static void
+find_methods (struct symtab *symtab, char type,
+ const char *class, const char *category,
+ const char *selector, struct symbol **syms,
+ unsigned int *nsym, unsigned int *ndebug)
+{
+ struct objfile *objfile = NULL;
+ struct minimal_symbol *msymbol = NULL;
+ struct block *block = NULL;
+ struct symbol *sym = NULL;
+
+ char *symname = NULL;
+
+ char ntype = '\0';
+ char *nclass = NULL;
+ char *ncategory = NULL;
+ char *nselector = NULL;
+
+ unsigned int csym = 0;
+ unsigned int cdebug = 0;
+
+ static char *tmp = NULL;
+ static unsigned int tmplen = 0;
+
+ gdb_assert (nsym != NULL);
+ gdb_assert (ndebug != NULL);
+
+ if (symtab)
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ QUIT;
+
+ if ((msymbol->type != mst_text) && (msymbol->type != mst_file_text))
+ /* Not a function or method. */
+ continue;
+
+ if (symtab)
+ if ((SYMBOL_VALUE_ADDRESS (msymbol) < BLOCK_START (block)) ||
+ (SYMBOL_VALUE_ADDRESS (msymbol) >= BLOCK_END (block)))
+ /* Not in the specified symtab. */
+ continue;
+
+ symname = SYMBOL_NATURAL_NAME (msymbol);
+ if (symname == NULL)
+ continue;
+
+ if ((symname[0] != '-' && symname[0] != '+') || (symname[1] != '['))
+ /* Not a method name. */
+ continue;
+
+ while ((strlen (symname) + 1) >= tmplen)
+ {
+ tmplen = (tmplen == 0) ? 1024 : tmplen * 2;
+ tmp = xrealloc (tmp, tmplen);
+ }
+ strcpy (tmp, symname);
+
+ if (parse_method (tmp, &ntype, &nclass, &ncategory, &nselector) == NULL)
+ continue;
+
+ if ((type != '\0') && (ntype != type))
+ continue;
+
+ if ((class != NULL)
+ && ((nclass == NULL) || (strcmp (class, nclass) != 0)))
+ continue;
+
+ if ((category != NULL) &&
+ ((ncategory == NULL) || (strcmp (category, ncategory) != 0)))
+ continue;
+
+ if ((selector != NULL) &&
+ ((nselector == NULL) || (strcmp (selector, nselector) != 0)))
+ continue;
+
+ sym = find_pc_function (SYMBOL_VALUE_ADDRESS (msymbol));
+ if (sym != NULL)
+ {
+ const char *newsymname = SYMBOL_NATURAL_NAME (sym);
+
+ if (strcmp (symname, newsymname) == 0)
+ {
+ /* Found a high-level method sym: swap it into the
+ lower part of sym_arr (below num_debuggable). */
+ if (syms != NULL)
+ {
+ syms[csym] = syms[cdebug];
+ syms[cdebug] = sym;
+ }
+ csym++;
+ cdebug++;
+ }
+ else
+ {
+ warning (
+"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
+ newsymname, symname);
+ if (syms != NULL)
+ syms[csym] = (struct symbol *) msymbol;
+ csym++;
+ }
+ }
+ else
+ {
+ /* Found a non-debuggable method symbol. */
+ if (syms != NULL)
+ syms[csym] = (struct symbol *) msymbol;
+ csym++;
+ }
+ }
+
+ if (nsym != NULL)
+ *nsym = csym;
+ if (ndebug != NULL)
+ *ndebug = cdebug;
+}
+
+char *find_imps (struct symtab *symtab, struct block *block,
+ char *method, struct symbol **syms,
+ unsigned int *nsym, unsigned int *ndebug)
+{
+ char type = '\0';
+ char *class = NULL;
+ char *category = NULL;
+ char *selector = NULL;
+
+ unsigned int csym = 0;
+ unsigned int cdebug = 0;
+
+ unsigned int ncsym = 0;
+ unsigned int ncdebug = 0;
+
+ char *buf = NULL;
+ char *tmp = NULL;
+
+ gdb_assert (nsym != NULL);
+ gdb_assert (ndebug != NULL);
+
+ if (nsym != NULL)
+ *nsym = 0;
+ if (ndebug != NULL)
+ *ndebug = 0;
+
+ buf = (char *) alloca (strlen (method) + 1);
+ strcpy (buf, method);
+ tmp = parse_method (buf, &type, &class, &category, &selector);
+
+ if (tmp == NULL) {
+
+ struct symbol *sym = NULL;
+ struct minimal_symbol *msym = NULL;
+
+ strcpy (buf, method);
+ tmp = parse_selector (buf, &selector);
+
+ if (tmp == NULL)
+ return NULL;
+
+ sym = lookup_symbol (selector, block, VAR_DOMAIN, 0, NULL);
+ if (sym != NULL)
+ {
+ if (syms)
+ syms[csym] = sym;
+ csym++;
+ cdebug++;
+ }
+
+ if (sym == NULL)
+ msym = lookup_minimal_symbol (selector, 0, 0);
+
+ if (msym != NULL)
+ {
+ if (syms)
+ syms[csym] = (struct symbol *)msym;
+ csym++;
+ }
+ }
+
+ if (syms != NULL)
+ find_methods (symtab, type, class, category, selector,
+ syms + csym, &ncsym, &ncdebug);
+ else
+ find_methods (symtab, type, class, category, selector,
+ NULL, &ncsym, &ncdebug);
+
+ /* If we didn't find any methods, just return. */
+ if (ncsym == 0 && ncdebug == 0)
+ return method;
+
+ /* Take debug symbols from the second batch of symbols and swap them
+ * with debug symbols from the first batch. Repeat until either the
+ * second section is out of debug symbols or the first section is
+ * full of debug symbols. Either way we have all debug symbols
+ * packed to the beginning of the buffer.
+ */
+
+ if (syms != NULL)
+ {
+ while ((cdebug < csym) && (ncdebug > 0))
+ {
+ struct symbol *s = NULL;
+ /* First non-debugging symbol. */
+ unsigned int i = cdebug;
+ /* Last of second batch of debug symbols. */
+ unsigned int j = csym + ncdebug - 1;
+
+ s = syms[j];
+ syms[j] = syms[i];
+ syms[i] = s;
+
+ /* We've moved a symbol from the second debug section to the
+ first one. */
+ cdebug++;
+ ncdebug--;
+ }
+ }
+
+ csym += ncsym;
+ cdebug += ncdebug;
+
+ if (nsym != NULL)
+ *nsym = csym;
+ if (ndebug != NULL)
+ *ndebug = cdebug;
+
+ if (syms == NULL)
+ return method + (tmp - buf);
+
+ if (csym > 1)
+ {
+ /* Sort debuggable symbols. */
+ if (cdebug > 1)
+ qsort (syms, cdebug, sizeof (struct minimal_symbol *),
+ compare_classes);
+
+ /* Sort minimal_symbols. */
+ if ((csym - cdebug) > 1)
+ qsort (&syms[cdebug], csym - cdebug,
+ sizeof (struct minimal_symbol *), compare_classes);
+ }
+ /* Terminate the sym_arr list. */
+ syms[csym] = 0;
+
+ return method + (tmp - buf);
+}
+
+static void
+print_object_command (char *args, int from_tty)
+{
+ struct value *object, *function, *description;
+ CORE_ADDR string_addr, object_addr;
+ int i = 0;
+ char c = -1;
+
+ if (!args || !*args)
+ error (
+"The 'print-object' command requires an argument (an Objective-C object)");
+
+ {
+ struct expression *expr = parse_expression (args);
+ struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+ int pc = 0;
+
+ object = expr->language_defn->la_exp_desc->evaluate_exp
+ (builtin_type_void_data_ptr, expr, &pc, EVAL_NORMAL);
+ do_cleanups (old_chain);
+ }
+
+ /* Validate the address for sanity. */
+ object_addr = value_as_long (object);
+ read_memory (object_addr, &c, 1);
+
+ function = find_function_in_inferior ("_NSPrintForDebugger");
+ if (function == NULL)
+ error ("Unable to locate _NSPrintForDebugger in child process");
+
+ description = call_function_by_hand (function, 1, &object);
+
+ string_addr = value_as_long (description);
+ if (string_addr == 0)
+ error ("object returns null description");
+
+ read_memory (string_addr + i++, &c, 1);
+ if (c != '\0')
+ do
+ { /* Read and print characters up to EOS. */
+ QUIT;
+ printf_filtered ("%c", c);
+ read_memory (string_addr + i++, &c, 1);
+ } while (c != 0);
+ else
+ printf_filtered("<object returns empty description>");
+ printf_filtered ("\n");
+}
+
+/* The data structure 'methcalls' is used to detect method calls (thru
+ * ObjC runtime lib functions objc_msgSend, objc_msgSendSuper, etc.),
+ * and ultimately find the method being called.
+ */
+
+struct objc_methcall {
+ char *name;
+ /* Return instance method to be called. */
+ int (*stop_at) (CORE_ADDR, CORE_ADDR *);
+ /* Start of pc range corresponding to method invocation. */
+ CORE_ADDR begin;
+ /* End of pc range corresponding to method invocation. */
+ CORE_ADDR end;
+};
+
+static int resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc);
+static int resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
+static int resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc);
+static int resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
+
+static struct objc_methcall methcalls[] = {
+ { "_objc_msgSend", resolve_msgsend, 0, 0},
+ { "_objc_msgSend_stret", resolve_msgsend_stret, 0, 0},
+ { "_objc_msgSendSuper", resolve_msgsend_super, 0, 0},
+ { "_objc_msgSendSuper_stret", resolve_msgsend_super_stret, 0, 0},
+ { "_objc_getClass", NULL, 0, 0},
+ { "_objc_getMetaClass", NULL, 0, 0}
+};
+
+#define nmethcalls (sizeof (methcalls) / sizeof (methcalls[0]))
+
+/* The following function, "find_objc_msgsend", fills in the data
+ * structure "objc_msgs" by finding the addresses of each of the
+ * (currently four) functions that it holds (of which objc_msgSend is
+ * the first). This must be called each time symbols are loaded, in
+ * case the functions have moved for some reason.
+ */
+
+static void
+find_objc_msgsend (void)
+{
+ unsigned int i;
+ for (i = 0; i < nmethcalls; i++) {
+
+ struct minimal_symbol *func;
+
+ /* Try both with and without underscore. */
+ func = lookup_minimal_symbol (methcalls[i].name, NULL, NULL);
+ if ((func == NULL) && (methcalls[i].name[0] == '_')) {
+ func = lookup_minimal_symbol (methcalls[i].name + 1, NULL, NULL);
+ }
+ if (func == NULL) {
+ methcalls[i].begin = 0;
+ methcalls[i].end = 0;
+ continue;
+ }
+
+ methcalls[i].begin = SYMBOL_VALUE_ADDRESS (func);
+ do {
+ methcalls[i].end = SYMBOL_VALUE_ADDRESS (++func);
+ } while (methcalls[i].begin == methcalls[i].end);
+ }
+}
+
+/* find_objc_msgcall (replaces pc_off_limits)
+ *
+ * ALL that this function now does is to determine whether the input
+ * address ("pc") is the address of one of the Objective-C message
+ * dispatch functions (mainly objc_msgSend or objc_msgSendSuper), and
+ * if so, it returns the address of the method that will be called.
+ *
+ * The old function "pc_off_limits" used to do a lot of other things
+ * in addition, such as detecting shared library jump stubs and
+ * returning the address of the shlib function that would be called.
+ * That functionality has been moved into the SKIP_TRAMPOLINE_CODE and
+ * IN_SOLIB_TRAMPOLINE macros, which are resolved in the target-
+ * dependent modules.
+ */
+
+struct objc_submethod_helper_data {
+ int (*f) (CORE_ADDR, CORE_ADDR *);
+ CORE_ADDR pc;
+ CORE_ADDR *new_pc;
+};
+
+static int
+find_objc_msgcall_submethod_helper (void * arg)
+{
+ struct objc_submethod_helper_data *s =
+ (struct objc_submethod_helper_data *) arg;
+
+ if (s->f (s->pc, s->new_pc) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+static int
+find_objc_msgcall_submethod (int (*f) (CORE_ADDR, CORE_ADDR *),
+ CORE_ADDR pc,
+ CORE_ADDR *new_pc)
+{
+ struct objc_submethod_helper_data s;
+
+ s.f = f;
+ s.pc = pc;
+ s.new_pc = new_pc;
+
+ if (catch_errors (find_objc_msgcall_submethod_helper,
+ (void *) &s,
+ "Unable to determine target of Objective-C method call (ignoring):\n",
+ RETURN_MASK_ALL) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+int
+find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc)
+{
+ unsigned int i;
+
+ find_objc_msgsend ();
+ if (new_pc != NULL)
+ {
+ *new_pc = 0;
+ }
+
+ for (i = 0; i < nmethcalls; i++)
+ if ((pc >= methcalls[i].begin) && (pc < methcalls[i].end))
+ {
+ if (methcalls[i].stop_at != NULL)
+ return find_objc_msgcall_submethod (methcalls[i].stop_at,
+ pc, new_pc);
+ else
+ return 0;
+ }
+
+ return 0;
+}
+
+extern initialize_file_ftype _initialize_objc_language; /* -Wmissing-prototypes */
+
+void
+_initialize_objc_language (void)
+{
+ add_language (&objc_language_defn);
+ add_info ("selectors", selectors_info, /* INFO SELECTORS command. */
+ "All Objective-C selectors, or those matching REGEXP.");
+ add_info ("classes", classes_info, /* INFO CLASSES command. */
+ "All Objective-C classes, or those matching REGEXP.");
+ add_com ("print-object", class_vars, print_object_command,
+ "Ask an Objective-C object to print itself.");
+ add_com_alias ("po", "print-object", class_vars, 1);
+}
+
+static void
+read_objc_method (CORE_ADDR addr, struct objc_method *method)
+{
+ method->name = read_memory_unsigned_integer (addr + 0, 4);
+ method->types = read_memory_unsigned_integer (addr + 4, 4);
+ method->imp = read_memory_unsigned_integer (addr + 8, 4);
+}
+
+static
+unsigned long read_objc_methlist_nmethods (CORE_ADDR addr)
+{
+ return read_memory_unsigned_integer (addr + 4, 4);
+}
+
+static void
+read_objc_methlist_method (CORE_ADDR addr, unsigned long num,
+ struct objc_method *method)
+{
+ gdb_assert (num < read_objc_methlist_nmethods (addr));
+ read_objc_method (addr + 8 + (12 * num), method);
+}
+
+static void
+read_objc_object (CORE_ADDR addr, struct objc_object *object)
+{
+ object->isa = read_memory_unsigned_integer (addr, 4);
+}
+
+static void
+read_objc_super (CORE_ADDR addr, struct objc_super *super)
+{
+ super->receiver = read_memory_unsigned_integer (addr, 4);
+ super->class = read_memory_unsigned_integer (addr + 4, 4);
+};
+
+static void
+read_objc_class (CORE_ADDR addr, struct objc_class *class)
+{
+ class->isa = read_memory_unsigned_integer (addr, 4);
+ class->super_class = read_memory_unsigned_integer (addr + 4, 4);
+ class->name = read_memory_unsigned_integer (addr + 8, 4);
+ class->version = read_memory_unsigned_integer (addr + 12, 4);
+ class->info = read_memory_unsigned_integer (addr + 16, 4);
+ class->instance_size = read_memory_unsigned_integer (addr + 18, 4);
+ class->ivars = read_memory_unsigned_integer (addr + 24, 4);
+ class->methods = read_memory_unsigned_integer (addr + 28, 4);
+ class->cache = read_memory_unsigned_integer (addr + 32, 4);
+ class->protocols = read_memory_unsigned_integer (addr + 36, 4);
+}
+
+static CORE_ADDR
+find_implementation_from_class (CORE_ADDR class, CORE_ADDR sel)
+{
+ CORE_ADDR subclass = class;
+
+ while (subclass != 0)
+ {
+
+ struct objc_class class_str;
+ unsigned mlistnum = 0;
+
+ read_objc_class (subclass, &class_str);
+
+ for (;;)
+ {
+ CORE_ADDR mlist;
+ unsigned long nmethods;
+ unsigned long i;
+
+ mlist = read_memory_unsigned_integer (class_str.methods +
+ (4 * mlistnum), 4);
+ if (mlist == 0)
+ break;
+
+ nmethods = read_objc_methlist_nmethods (mlist);
+
+ for (i = 0; i < nmethods; i++)
+ {
+ struct objc_method meth_str;
+ read_objc_methlist_method (mlist, i, &meth_str);
+
+#if 0
+ fprintf (stderr,
+ "checking method 0x%lx against selector 0x%lx\n",
+ meth_str.name, sel);
+#endif
+
+ if (meth_str.name == sel)
+ /* FIXME: hppa arch was doing a pointer dereference
+ here. There needs to be a better way to do that. */
+ return meth_str.imp;
+ }
+ mlistnum++;
+ }
+ subclass = class_str.super_class;
+ }
+
+ return 0;
+}
+
+static CORE_ADDR
+find_implementation (CORE_ADDR object, CORE_ADDR sel)
+{
+ struct objc_object ostr;
+
+ if (object == 0)
+ return 0;
+ read_objc_object (object, &ostr);
+ if (ostr.isa == 0)
+ return 0;
+
+ return find_implementation_from_class (ostr.isa, sel);
+}
+
+#define OBJC_FETCH_POINTER_ARGUMENT(argi) \
+ FETCH_POINTER_ARGUMENT (get_current_frame (), argi, builtin_type_void_func_ptr)
+
+static int
+resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc)
+{
+ CORE_ADDR object;
+ CORE_ADDR sel;
+ CORE_ADDR res;
+
+ object = OBJC_FETCH_POINTER_ARGUMENT (0);
+ sel = OBJC_FETCH_POINTER_ARGUMENT (1);
+
+ res = find_implementation (object, sel);
+ if (new_pc != 0)
+ *new_pc = res;
+ if (res == 0)
+ return 1;
+ return 0;
+}
+
+static int
+resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
+{
+ CORE_ADDR object;
+ CORE_ADDR sel;
+ CORE_ADDR res;
+
+ object = OBJC_FETCH_POINTER_ARGUMENT (1);
+ sel = OBJC_FETCH_POINTER_ARGUMENT (2);
+
+ res = find_implementation (object, sel);
+ if (new_pc != 0)
+ *new_pc = res;
+ if (res == 0)
+ return 1;
+ return 0;
+}
+
+static int
+resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc)
+{
+ struct objc_super sstr;
+
+ CORE_ADDR super;
+ CORE_ADDR sel;
+ CORE_ADDR res;
+
+ super = OBJC_FETCH_POINTER_ARGUMENT (0);
+ sel = OBJC_FETCH_POINTER_ARGUMENT (1);
+
+ read_objc_super (super, &sstr);
+ if (sstr.class == 0)
+ return 0;
+
+ res = find_implementation_from_class (sstr.class, sel);
+ if (new_pc != 0)
+ *new_pc = res;
+ if (res == 0)
+ return 1;
+ return 0;
+}
+
+static int
+resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
+{
+ struct objc_super sstr;
+
+ CORE_ADDR super;
+ CORE_ADDR sel;
+ CORE_ADDR res;
+
+ super = OBJC_FETCH_POINTER_ARGUMENT (1);
+ sel = OBJC_FETCH_POINTER_ARGUMENT (2);
+
+ read_objc_super (super, &sstr);
+ if (sstr.class == 0)
+ return 0;
+
+ res = find_implementation_from_class (sstr.class, sel);
+ if (new_pc != 0)
+ *new_pc = res;
+ if (res == 0)
+ return 1;
+ return 0;
+}
diff --git a/contrib/gdb/gdb/objc-lang.h b/contrib/gdb/gdb/objc-lang.h
new file mode 100644
index 0000000..5a11c5d
--- /dev/null
+++ b/contrib/gdb/gdb/objc-lang.h
@@ -0,0 +1,68 @@
+/* Objective-C language support definitions for GDB, the GNU debugger.
+
+ Copyright 1992 Free Software Foundation, Inc.
+
+ Contributed by Apple Computer, 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(OBJC_LANG_H)
+#define OBJC_LANG_H
+
+struct stoken;
+
+struct value;
+struct block;
+
+extern int objc_parse (void); /* Defined in c-exp.y */
+
+extern void objc_error (char *); /* Defined in c-exp.y */
+
+extern int c_val_print (struct type *, char *, int,
+ CORE_ADDR, struct ui_file *, int,
+ int, int, enum val_prettyprint);
+
+extern int c_value_print (struct value *, struct ui_file *,
+ int, enum val_prettyprint);
+
+extern CORE_ADDR lookup_objc_class (char *classname);
+extern CORE_ADDR lookup_child_selector (char *methodname);
+
+extern char *objc_demangle (const char *mangled, int options);
+
+extern int find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc);
+
+extern char *parse_selector (char *method, char **selector);
+
+extern char *parse_method (char *method, char *type,
+ char **class, char **category,
+ char **selector);
+
+extern char *find_imps (struct symtab *symtab, struct block *block,
+ char *method, struct symbol **syms,
+ unsigned int *nsym, unsigned int *ndebug);
+
+extern struct value *value_nsstring (char *ptr, int len);
+
+/* for parsing Objective C */
+extern void start_msglist (void);
+extern void add_msglist (struct stoken *str, int addcolon);
+extern int end_msglist (void);
+
+struct symbol *lookup_struct_typedef (char *name, struct block *block,
+ int noerr);
+
+#endif
diff --git a/contrib/gdb/gdb/objfiles.c b/contrib/gdb/gdb/objfiles.c
new file mode 100644
index 0000000..6179077
--- /dev/null
+++ b/contrib/gdb/gdb/objfiles.c
@@ -0,0 +1,896 @@
+/* GDB routines for manipulating objfiles.
+
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004 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 "bcache.h"
+
+#include "gdb_assert.h"
+#include <sys/types.h>
+#include "gdb_stat.h"
+#include <fcntl.h>
+#include "gdb_obstack.h"
+#include "gdb_string.h"
+#include "hashtab.h"
+
+#include "breakpoint.h"
+#include "block.h"
+#include "dictionary.h"
+
+/* Prototypes for local functions */
+
+static void objfile_alloc_data (struct objfile *objfile);
+static void objfile_free_data (struct objfile *objfile);
+
+/* 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 */
+
+/* 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. */
+
+#ifndef TARGET_KEEP_SECTION
+#define TARGET_KEEP_SECTION(ASECT) 0
+#endif
+
+/* Called via bfd_map_over_sections to build up the section table that
+ the objfile references. The objfile contains pointers to the start
+ of the table (objfile->sections) and to the first location after
+ the end of the table (objfile->sections_end). */
+
+static void
+add_to_objfile_sections (struct bfd *abfd, struct bfd_section *asect,
+ void *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) && !(TARGET_KEEP_SECTION (asect)))
+ return;
+
+ if (0 == bfd_section_size (abfd, asect))
+ return;
+ section.offset = 0;
+ section.objfile = objfile;
+ section.the_bfd_section = asect;
+ section.ovly_mapped = 0;
+ section.addr = bfd_section_vma (abfd, asect);
+ section.endaddr = section.addr + bfd_section_size (abfd, asect);
+ obstack_grow (&objfile->objfile_obstack, (char *) &section, 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).
+
+ Note that while we are building the table, which goes into the
+ psymbol obstack, we hijack the sections_end pointer to instead hold
+ a count of the number of sections. When bfd_map_over_sections
+ returns, this count is used to compute the pointer to the end of
+ the sections table, which then overwrites the count.
+
+ Also note that the OFFSET and OVLY_MAPPED in each table entry
+ are initialized to zero.
+
+ Also note that if anything else writes to the psymbol obstack while
+ we are building the table, we're pretty much hosed. */
+
+int
+build_objfile_section_table (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 objfile_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->objfile_obstack);
+ objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end;
+ return (0);
+}
+
+/* Given a pointer to an initialized bfd (ABFD) and some flag bits
+ 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.
+
+ The FLAGS word contains various bits (OBJF_*) that can be taken as
+ requests for specific operations. Other bits like OBJF_SHARED are
+ simply copied through to the new objfile flags member. */
+
+/* NOTE: carlton/2003-02-04: This function is called with args NULL, 0
+ by jv-lang.c, to create an artificial objfile used to hold
+ information about dynamically-loaded Java classes. Unfortunately,
+ that branch of this function doesn't get tested very frequently, so
+ it's prone to breakage. (E.g. at one time the name was set to NULL
+ in that situation, which broke a loop over all names in the dynamic
+ library loader.) If you change this function, please try to leave
+ things in a consistent state even if abfd is NULL. */
+
+struct objfile *
+allocate_objfile (bfd *abfd, int flags)
+{
+ struct objfile *objfile = NULL;
+ struct objfile *last_one = NULL;
+
+ /* 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;
+ objfile->psymbol_cache = bcache_xmalloc ();
+ objfile->macro_cache = bcache_xmalloc ();
+ /* We could use obstack_specify_allocation here instead, but
+ gdb_obstack.h specifies the alloc/dealloc functions. */
+ obstack_init (&objfile->objfile_obstack);
+ terminate_minimal_symbol_table (objfile);
+ }
+
+ objfile_alloc_data (objfile);
+
+ /* 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)
+ {
+ xmfree (objfile->md, objfile->name);
+ }
+ if (abfd != NULL)
+ {
+ 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 ()));
+ }
+ }
+ else
+ {
+ objfile->name = mstrsave (objfile->md, "<<anonymous objfile>>");
+ }
+
+ /* Initialize the section indexes for this objfile, so that we can
+ later detect if they are used w/o being properly assigned to. */
+
+ objfile->sect_index_text = -1;
+ objfile->sect_index_data = -1;
+ objfile->sect_index_bss = -1;
+ objfile->sect_index_rodata = -1;
+
+ /* We don't yet have a C++-specific namespace symtab. */
+
+ objfile->cp_namespace_symtab = NULL;
+
+ /* 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;
+ }
+
+ /* Save passed in flag bits. */
+ objfile->flags |= flags;
+
+ return (objfile);
+}
+
+/* Initialize entry point information for this objfile. */
+
+void
+init_entry_point_info (struct objfile *objfile)
+{
+ /* Save startup file's range of PC addresses to help blockframe.c
+ decide where the bottom of the stack is. */
+
+ if (bfd_get_file_flags (objfile->obfd) & EXEC_P)
+ {
+ /* Executable file -- record its entry point so we'll recognize
+ the startup file because it contains the entry point. */
+ objfile->ei.entry_point = bfd_get_start_address (objfile->obfd);
+ }
+ else
+ {
+ /* Examination of non-executable.o files. Short-circuit this stuff. */
+ objfile->ei.entry_point = INVALID_ENTRY_POINT;
+ }
+ objfile->ei.deprecated_entry_file_lowpc = INVALID_ENTRY_LOWPC;
+ objfile->ei.deprecated_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 (void)
+{
+ return symfile_objfile ? symfile_objfile->ei.entry_point : 0;
+}
+
+/* Create the terminating entry of OBJFILE's minimal symbol table.
+ If OBJFILE->msymbols is zero, allocate a single entry from
+ OBJFILE->objfile_obstack; otherwise, just initialize
+ OBJFILE->msymbols[OBJFILE->minimal_symbol_count]. */
+void
+terminate_minimal_symbol_table (struct objfile *objfile)
+{
+ if (! objfile->msymbols)
+ objfile->msymbols = ((struct minimal_symbol *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (objfile->msymbols[0])));
+
+ {
+ struct minimal_symbol *m
+ = &objfile->msymbols[objfile->minimal_symbol_count];
+
+ memset (m, 0, sizeof (*m));
+ /* Don't rely on these enumeration values being 0's. */
+ MSYMBOL_TYPE (m) = mst_unknown;
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (m, language_unknown);
+ }
+}
+
+
+/* Put one object file before a specified on in the global list.
+ This can be used to make sure an object file is destroyed before
+ another when using ALL_OBJFILES_SAFE to free all objfiles. */
+void
+put_objfile_before (struct objfile *objfile, struct objfile *before_this)
+{
+ struct objfile **objp;
+
+ unlink_objfile (objfile);
+
+ for (objp = &object_files; *objp != NULL; objp = &((*objp)->next))
+ {
+ if (*objp == before_this)
+ {
+ objfile->next = *objp;
+ *objp = objfile;
+ return;
+ }
+ }
+
+ internal_error (__FILE__, __LINE__,
+ "put_objfile_before: before objfile not in list");
+}
+
+/* Put OBJFILE at the front of the list. */
+
+void
+objfile_to_front (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 (struct objfile *objfile)
+{
+ struct objfile **objpp;
+
+ for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp)->next))
+ {
+ if (*objpp == objfile)
+ {
+ *objpp = (*objpp)->next;
+ objfile->next = NULL;
+ return;
+ }
+ }
+
+ internal_error (__FILE__, __LINE__,
+ "unlink_objfile: objfile already unlinked");
+}
+
+
+/* Destroy an objfile and all the symtabs and psymtabs under it. Note
+ that as much as possible is allocated on the objfile_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 (struct objfile *objfile)
+{
+ if (objfile->separate_debug_objfile)
+ {
+ free_objfile (objfile->separate_debug_objfile);
+ }
+
+ if (objfile->separate_debug_objfile_backlink)
+ {
+ /* We freed the separate debug file, make sure the base objfile
+ doesn't reference it. */
+ objfile->separate_debug_objfile_backlink->separate_debug_objfile = NULL;
+ }
+
+ /* 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 ()));
+ xfree (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. */
+
+ /* 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. */
+
+ objfile_free_data (objfile);
+ if (objfile->name != NULL)
+ {
+ xmfree (objfile->md, objfile->name);
+ }
+ if (objfile->global_psymbols.list)
+ xmfree (objfile->md, objfile->global_psymbols.list);
+ if (objfile->static_psymbols.list)
+ xmfree (objfile->md, objfile->static_psymbols.list);
+ /* Free the obstacks for non-reusable objfiles */
+ bcache_xfree (objfile->psymbol_cache);
+ bcache_xfree (objfile->macro_cache);
+ if (objfile->demangled_names_hash)
+ htab_delete (objfile->demangled_names_hash);
+ obstack_free (&objfile->objfile_obstack, 0);
+ xmfree (objfile->md, objfile);
+ objfile = NULL;
+}
+
+static void
+do_free_objfile_cleanup (void *obj)
+{
+ free_objfile (obj);
+}
+
+struct cleanup *
+make_cleanup_free_objfile (struct objfile *obj)
+{
+ return make_cleanup (do_free_objfile_cleanup, obj);
+}
+
+/* Free all the object files at once and clean up their users. */
+
+void
+free_all_objfiles (void)
+{
+ 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 (struct objfile *objfile, struct section_offsets *new_offsets)
+{
+ struct section_offsets *delta =
+ ((struct section_offsets *)
+ alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections)));
+
+ {
+ int i;
+ int something_changed = 0;
+ for (i = 0; i < objfile->num_sections; ++i)
+ {
+ delta->offsets[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;
+ struct symbol *sym;
+ struct dict_iterator iter;
+
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
+ BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ fixup_symbol_section (sym, objfile);
+
+ /* The RS6000 code from which this was taken skipped
+ any symbols in STRUCT_DOMAIN or UNDEF_DOMAIN.
+ 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_CLASS (sym) == LOC_INDIRECT)
+ && 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_DOMAIN (sym) == LABEL_DOMAIN
+ && strcmp (DEPRECATED_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 (objfile));
+ p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ }
+ }
+
+ {
+ struct partial_symbol **psym;
+
+ for (psym = objfile->global_psymbols.list;
+ psym < objfile->global_psymbols.next;
+ psym++)
+ {
+ fixup_psymbol_section (*psym, objfile);
+ 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++)
+ {
+ fixup_psymbol_section (*psym, objfile);
+ 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)
+ (objfile->section_offsets)->offsets[i] = ANOFFSET (new_offsets, i);
+ }
+
+ if (objfile->ei.entry_point != ~(CORE_ADDR) 0)
+ {
+ /* Relocate ei.entry_point with its section offset, use SECT_OFF_TEXT
+ only as a fallback. */
+ struct obj_section *s;
+ s = find_pc_section (objfile->ei.entry_point);
+ if (s)
+ objfile->ei.entry_point += ANOFFSET (delta, s->the_bfd_section->index);
+ else
+ objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ }
+
+ {
+ struct obj_section *s;
+ bfd *abfd;
+
+ abfd = objfile->obfd;
+
+ ALL_OBJFILE_OSECTIONS (objfile, s)
+ {
+ int idx = s->the_bfd_section->index;
+
+ s->addr += ANOFFSET (delta, idx);
+ s->endaddr += ANOFFSET (delta, idx);
+ }
+ }
+
+ if (objfile->ei.entry_func_lowpc != INVALID_ENTRY_LOWPC)
+ {
+ objfile->ei.entry_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ objfile->ei.entry_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ }
+
+ if (objfile->ei.deprecated_entry_file_lowpc != INVALID_ENTRY_LOWPC)
+ {
+ objfile->ei.deprecated_entry_file_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ objfile->ei.deprecated_entry_file_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ }
+
+ if (objfile->ei.main_func_lowpc != INVALID_ENTRY_LOWPC)
+ {
+ objfile->ei.main_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ objfile->ei.main_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ }
+
+ /* Relocate breakpoints as necessary, after things are relocated. */
+ breakpoint_re_set ();
+}
+
+/* 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 (void)
+{
+ 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 (void)
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp->symtabs != NULL)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* This operations deletes all objfile entries that represent solibs that
+ weren't explicitly loaded by the user, via e.g., the add-symbol-file
+ command.
+ */
+void
+objfile_purge_solibs (void)
+{
+ struct objfile *objf;
+ struct objfile *temp;
+
+ ALL_OBJFILES_SAFE (objf, temp)
+ {
+ /* We assume that the solib package has been purged already, or will
+ be soon.
+ */
+ if (!(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED))
+ free_objfile (objf);
+ }
+}
+
+
+/* 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 (void)
+{
+ struct objfile *ofp;
+
+ ALL_OBJFILES (ofp)
+ {
+ if (ofp->minimal_symbol_count > 0)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Returns a section whose range includes PC and SECTION, or NULL if
+ none found. Note the distinction between the return type, struct
+ obj_section (which is defined in gdb), and the input type "struct
+ bfd_section" (which is a bfd-defined data type). The obj_section
+ contains a pointer to the "struct bfd_section". */
+
+struct obj_section *
+find_pc_sect_section (CORE_ADDR pc, struct bfd_section *section)
+{
+ struct obj_section *s;
+ struct objfile *objfile;
+
+ ALL_OBJSECTIONS (objfile, s)
+ if ((section == 0 || section == s->the_bfd_section) &&
+ s->addr <= pc && pc < s->endaddr)
+ return (s);
+
+ return (NULL);
+}
+
+/* Returns a section whose range includes PC or NULL if none found.
+ Backward compatibility, no section. */
+
+struct obj_section *
+find_pc_section (CORE_ADDR pc)
+{
+ return find_pc_sect_section (pc, find_pc_mapped_section (pc));
+}
+
+
+/* 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 (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
+ && strcmp (s->the_bfd_section->name, ".plt") == 0);
+ return (retval);
+}
+
+/* Return nonzero if NAME is in the import list of OBJFILE. Else
+ return zero. */
+
+int
+is_in_import_list (char *name, struct objfile *objfile)
+{
+ int i;
+
+ if (!objfile || !name || !*name)
+ return 0;
+
+ for (i = 0; i < objfile->import_list_size; i++)
+ if (objfile->import_list[i] && DEPRECATED_STREQ (name, objfile->import_list[i]))
+ return 1;
+ return 0;
+}
+
+
+/* Keep a registry of per-objfile data-pointers required by other GDB
+ modules. */
+
+struct objfile_data
+{
+ unsigned index;
+};
+
+struct objfile_data_registration
+{
+ struct objfile_data *data;
+ struct objfile_data_registration *next;
+};
+
+struct objfile_data_registry
+{
+ struct objfile_data_registration *registrations;
+ unsigned num_registrations;
+};
+
+static struct objfile_data_registry objfile_data_registry = { NULL, 0 };
+
+const struct objfile_data *
+register_objfile_data (void)
+{
+ struct objfile_data_registration **curr;
+
+ /* Append new registration. */
+ for (curr = &objfile_data_registry.registrations;
+ *curr != NULL; curr = &(*curr)->next);
+
+ *curr = XMALLOC (struct objfile_data_registration);
+ (*curr)->next = NULL;
+ (*curr)->data = XMALLOC (struct objfile_data);
+ (*curr)->data->index = objfile_data_registry.num_registrations++;
+
+ return (*curr)->data;
+}
+
+static void
+objfile_alloc_data (struct objfile *objfile)
+{
+ gdb_assert (objfile->data == NULL);
+ objfile->num_data = objfile_data_registry.num_registrations;
+ objfile->data = XCALLOC (objfile->num_data, void *);
+}
+
+static void
+objfile_free_data (struct objfile *objfile)
+{
+ gdb_assert (objfile->data != NULL);
+ xfree (objfile->data);
+ objfile->data = NULL;
+}
+
+void
+clear_objfile_data (struct objfile *objfile)
+{
+ gdb_assert (objfile->data != NULL);
+ memset (objfile->data, 0, objfile->num_data * sizeof (void *));
+}
+
+void
+set_objfile_data (struct objfile *objfile, const struct objfile_data *data,
+ void *value)
+{
+ gdb_assert (data->index < objfile->num_data);
+ objfile->data[data->index] = value;
+}
+
+void *
+objfile_data (struct objfile *objfile, const struct objfile_data *data)
+{
+ gdb_assert (data->index < objfile->num_data);
+ return objfile->data[data->index];
+}
diff --git a/contrib/gdb/gdb/objfiles.h b/contrib/gdb/gdb/objfiles.h
new file mode 100644
index 0000000..2b8ca7d
--- /dev/null
+++ b/contrib/gdb/gdb/objfiles.h
@@ -0,0 +1,663 @@
+/* Definitions for symbol file management in GDB.
+
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+#include "gdb_obstack.h" /* For obstack internals. */
+#include "symfile.h" /* For struct psymbol_allocation_list */
+
+struct bcache;
+struct htab;
+struct symtab;
+struct objfile_data;
+
+/* 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
+ deprecated_entry_file_lowpc and deprecated_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.
+
+ NOTE: cagney/2003-09-09: It turns out that this "traditional"
+ method doesn't work. Corinna writes: ``It turns out that the call
+ to deprecated_inside_entry_file destroys a meaningful backtrace
+ under some conditions. E. g. the backtrace tests in the asm-source
+ testcase are broken for some targets. In this test the functions
+ are all implemented as part of one file and the testcase is not
+ necessarily linked with a start file (depending on the target).
+ What happens is, that the first frame is printed normaly and
+ following frames are treated as being inside the enttry file then.
+ This way, only the #0 frame is printed in the backtrace output.''
+ Ref "frame.c" "NOTE: vinschen/2003-04-01".
+
+ 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
+ DEPRECATED_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. */
+
+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 deprecated_entry_file_lowpc;
+ CORE_ADDR deprecated_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;
+
+ struct bfd_section *the_bfd_section; /* BFD section pointer */
+
+ /* Objfile this section is part of. */
+ struct objfile *objfile;
+
+ /* True if this "overlay section" is mapped into an "overlay region". */
+ int ovly_mapped;
+ };
+
+/* An import entry contains information about a symbol that
+ is used in this objfile but not defined in it, and so needs
+ to be imported from some other objfile */
+/* Currently we just store the name; no attributes. 1997-08-05 */
+typedef char *ImportEntry;
+
+
+/* An export entry contains information about a symbol that
+ is defined in this objfile and available for use in other
+ objfiles */
+typedef struct
+ {
+ char *name; /* name of exported symbol */
+ int address; /* offset subject to relocation */
+ /* Currently no other attributes 1997-08-05 */
+ }
+ExportEntry;
+
+
+/* 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. */
+
+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 (void);
+extern void print_symbol_bcache_statistics (void);
+
+/* Number of entries in the minimal symbol hash table. */
+#define MINIMAL_SYMBOL_HASH_SIZE 2039
+
+/* 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, tilde-expanded and absolute.
+ 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;
+
+ /* Obstack to hold objects that should be freed when we load a new symbol
+ table from this object file. */
+
+ struct obstack objfile_obstack;
+
+ /* A byte cache where we can stash arbitrary "chunks" of bytes that
+ will not change. */
+
+ struct bcache *psymbol_cache; /* Byte cache for partial syms */
+ struct bcache *macro_cache; /* Byte cache for macros */
+
+ /* Hash table for mapping symbol names to demangled names. Each
+ entry in the hash table is actually two consecutive strings,
+ both null-terminated; the first one is a mangled or linkage
+ name, and the second is the demangled name or just a zero byte
+ if the name doesn't demangle. */
+ struct htab *demangled_names_hash;
+
+ /* Vectors of all partial symbols read in from file. The actual data
+ is stored in the objfile_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 objfile_obstack for this file. */
+
+ struct minimal_symbol *msymbols;
+ int minimal_symbol_count;
+
+ /* This is a hash table used to index the minimal symbols by name. */
+
+ struct minimal_symbol *msymbol_hash[MINIMAL_SYMBOL_HASH_SIZE];
+
+ /* This hash table is used to index the minimal symbols by their
+ demangled names. */
+
+ struct minimal_symbol *msymbol_demangled_hash[MINIMAL_SYMBOL_HASH_SIZE];
+
+ /* 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. */
+
+ void *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. */
+
+ struct dbx_symfile_info *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. */
+
+ void *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. */
+
+ void *obj_private;
+
+ /* Per objfile data-pointers required by other GDB modules. */
+ /* FIXME: kettenis/20030711: This mechanism could replace
+ sym_stab_info, sym_private and obj_private entirely. */
+
+ void **data;
+ unsigned num_data;
+
+ /* Set of relocation offsets to apply to each section.
+ Currently on the objfile_obstack (which makes no sense, but I'm
+ not sure it's harming anything).
+
+ 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;
+
+ /* Indexes in the section_offsets array. These are initialized by the
+ *_symfile_offsets() family of functions (som_symfile_offsets,
+ xcoff_symfile_offsets, default_symfile_offsets). In theory they
+ should correspond to the section indexes used by bfd for the
+ current objfile. The exception to this for the time being is the
+ SOM version. */
+
+ int sect_index_text;
+ int sect_index_data;
+ int sect_index_bss;
+ int sect_index_rodata;
+
+ /* These pointers are used to locate the section table, which
+ among other things, is used to map pc addresses into sections.
+ SECTIONS points to the first entry in the table, and
+ SECTIONS_END points to the first location past the last entry
+ in the table. Currently the table is stored on the
+ objfile_obstack (which makes no sense, but I'm not sure it's
+ harming anything). */
+
+ struct obj_section
+ *sections, *sections_end;
+
+ /* Imported symbols */
+ /* FIXME: ezannoni 2004-02-10: This is just SOM (HP) specific (see
+ somread.c). It should not pollute generic objfiles. */
+ ImportEntry *import_list;
+ int import_list_size;
+
+ /* Exported symbols */
+ /* FIXME: ezannoni 2004-02-10: This is just SOM (HP) specific (see
+ somread.c). It should not pollute generic objfiles. */
+ ExportEntry *export_list;
+ int export_list_size;
+
+ /* Link to objfile that contains the debug symbols for this one.
+ One is loaded if this file has an debug link to an existing
+ debug file with the right checksum */
+ struct objfile *separate_debug_objfile;
+
+ /* If this is a separate debug object, this is used as a link to the
+ actual executable objfile. */
+ struct objfile *separate_debug_objfile_backlink;
+
+ /* Place to stash various statistics about this objfile */
+ OBJSTATS;
+
+ /* A symtab that the C++ code uses to stash special symbols
+ associated to namespaces. */
+
+ /* FIXME/carlton-2003-06-27: Delete this in a few years once
+ "possible namespace symbols" go away. */
+ struct symtab *cp_namespace_symtab;
+ };
+
+/* Defines for the objfile flag word. */
+
+/* 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 (1 << 2) /* Functions are reordered */
+
+/* Distinguish between an objfile for a shared library and a "vanilla"
+ objfile. (If not set, the objfile may still actually be a solib.
+ This can happen if the user created the objfile by using the
+ add-symbol-file command. GDB doesn't in that situation actually
+ check whether the file is a solib. Rather, the target's
+ implementation of the solib interface is responsible for setting
+ this flag when noticing solibs used by an inferior.) */
+
+#define OBJF_SHARED (1 << 3) /* From a shared library */
+
+/* User requested that this objfile be read in it's entirety. */
+
+#define OBJF_READNOW (1 << 4) /* Immediate full read */
+
+/* This objfile was created because the user explicitly caused it
+ (e.g., used the add-symbol-file command). This bit offers a way
+ for run_command to remove old objfile entries which are no longer
+ valid (i.e., are associated with an old inferior), but to preserve
+ ones that the user explicitly loaded via the add-symbol-file
+ command. */
+
+#define OBJF_USERLOADED (1 << 5) /* User loaded */
+
+/* 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 objfile_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 (bfd *, int);
+
+extern void init_entry_point_info (struct objfile *);
+
+extern CORE_ADDR entry_point_address (void);
+
+extern int build_objfile_section_table (struct objfile *);
+
+extern void terminate_minimal_symbol_table (struct objfile *objfile);
+
+extern void put_objfile_before (struct objfile *, struct objfile *);
+
+extern void objfile_to_front (struct objfile *);
+
+extern void unlink_objfile (struct objfile *);
+
+extern void free_objfile (struct objfile *);
+
+extern struct cleanup *make_cleanup_free_objfile (struct objfile *);
+
+extern void free_all_objfiles (void);
+
+extern void objfile_relocate (struct objfile *, struct section_offsets *);
+
+extern int have_partial_symbols (void);
+
+extern int have_full_symbols (void);
+
+/* This operation deletes all objfile entries that represent solibs that
+ weren't explicitly loaded by the user, via e.g., the add-symbol-file
+ command.
+ */
+extern void objfile_purge_solibs (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 (void);
+
+extern struct obj_section *find_pc_section (CORE_ADDR pc);
+
+extern struct obj_section *find_pc_sect_section (CORE_ADDR pc,
+ asection * section);
+
+extern int in_plt_section (CORE_ADDR, char *);
+
+extern int is_in_import_list (char *, struct objfile *);
+
+/* Keep a registry of per-objfile data-pointers required by other GDB
+ modules. */
+
+extern const struct objfile_data *register_objfile_data (void);
+extern void clear_objfile_data (struct objfile *objfile);
+extern void set_objfile_data (struct objfile *objfile,
+ const struct objfile_data *data, void *value);
+extern void *objfile_data (struct objfile *objfile,
+ const struct objfile_data *data);
+
+
+/* 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; DEPRECATED_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) \
+ ALL_OBJFILE_MSYMBOLS (objfile, m)
+
+#define ALL_OBJFILE_OSECTIONS(objfile, osect) \
+ for (osect = objfile->sections; osect < objfile->sections_end; osect++)
+
+#define ALL_OBJSECTIONS(objfile, osect) \
+ ALL_OBJFILES (objfile) \
+ ALL_OBJFILE_OSECTIONS (objfile, osect)
+
+#define SECT_OFF_DATA(objfile) \
+ ((objfile->sect_index_data == -1) \
+ ? (internal_error (__FILE__, __LINE__, "sect_index_data not initialized"), -1) \
+ : objfile->sect_index_data)
+
+#define SECT_OFF_RODATA(objfile) \
+ ((objfile->sect_index_rodata == -1) \
+ ? (internal_error (__FILE__, __LINE__, "sect_index_rodata not initialized"), -1) \
+ : objfile->sect_index_rodata)
+
+#define SECT_OFF_TEXT(objfile) \
+ ((objfile->sect_index_text == -1) \
+ ? (internal_error (__FILE__, __LINE__, "sect_index_text not initialized"), -1) \
+ : objfile->sect_index_text)
+
+/* Sometimes the .bss section is missing from the objfile, so we don't
+ want to die here. Let the users of SECT_OFF_BSS deal with an
+ uninitialized section index. */
+#define SECT_OFF_BSS(objfile) (objfile)->sect_index_bss
+
+#endif /* !defined (OBJFILES_H) */
diff --git a/contrib/gdb/gdb/observer.c b/contrib/gdb/gdb/observer.c
new file mode 100644
index 0000000..fce5f9287
--- /dev/null
+++ b/contrib/gdb/gdb/observer.c
@@ -0,0 +1,222 @@
+/* GDB Notifications to Observers.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 observer is an entity who is interested in being notified when GDB
+ reaches certain states, or certain events occur in GDB. The entity being
+ observed is called the Subject. To receive notifications, the observer
+ attaches a callback to the subject. One subject can have several
+ observers.
+
+ This file implements an internal generic low-level event notification
+ mechanism based on the Observer paradigm described in the book "Design
+ Patterns". This generic event notification mechansim is then re-used
+ to implement the exported high-level notification management routines
+ for all possible notifications.
+
+ The current implementation of the generic observer provides support
+ for contextual data. This contextual data is given to the subject
+ when attaching the callback. In return, the subject will provide
+ this contextual data back to the observer as a parameter of the
+ callback.
+
+ FIXME: The current support for the contextual data is only partial,
+ as it lacks a mechanism that would deallocate this data when the
+ callback is detached. This is not a problem so far, as this contextual
+ data is only used internally to hold a function pointer. Later on,
+ if a certain observer needs to provide support for user-level
+ contextual data, then the generic notification mechanism will need
+ need to be enhanced to allow the observer to provide a routine to
+ deallocate the data when attaching the callback.
+
+ This file is currently maintained by hand, but the long term plan
+ if the number of different notifications starts growing is to create
+ a new script (observer.sh) that would generate this file, and the
+ associated documentation. */
+
+#include "defs.h"
+#include "observer.h"
+
+/* The internal generic observer. */
+
+typedef void (generic_observer_notification_ftype) (const void *data,
+ const void *args);
+
+struct observer
+{
+ generic_observer_notification_ftype *notify;
+ /* No memory management needed for the following field for now. */
+ void *data;
+};
+
+/* A list of observers, maintained by the subject. A subject is
+ actually represented by its list of observers. */
+
+struct observer_list
+{
+ struct observer_list *next;
+ struct observer *observer;
+};
+
+/* Allocate a struct observer_list, intended to be used as a node
+ in the list of observers maintained by a subject. */
+
+static struct observer_list *
+xalloc_observer_list_node (void)
+{
+ struct observer_list *node = XMALLOC (struct observer_list);
+ node->observer = XMALLOC (struct observer);
+ return node;
+}
+
+/* The opposite of xalloc_observer_list_node, frees the memory for
+ the given node. */
+
+static void
+xfree_observer_list_node (struct observer_list *node)
+{
+ xfree (node->observer);
+ xfree (node);
+}
+
+/* Attach the callback NOTIFY to a SUBJECT. The DATA is also stored,
+ in order for the subject to provide it back to the observer during
+ a notification. */
+
+static struct observer *
+generic_observer_attach (struct observer_list **subject,
+ generic_observer_notification_ftype * notify,
+ void *data)
+{
+ struct observer_list *observer_list = xalloc_observer_list_node ();
+
+ observer_list->next = *subject;
+ observer_list->observer->notify = notify;
+ observer_list->observer->data = data;
+ *subject = observer_list;
+
+ return observer_list->observer;
+}
+
+/* Remove the given OBSERVER from the SUBJECT. Once detached, OBSERVER
+ should no longer be used, as it is no longer valid. */
+
+static void
+generic_observer_detach (struct observer_list **subject,
+ const struct observer *observer)
+{
+ struct observer_list *previous_node = NULL;
+ struct observer_list *current_node = *subject;
+
+ while (current_node != NULL)
+ {
+ if (current_node->observer == observer)
+ {
+ if (previous_node != NULL)
+ previous_node->next = current_node->next;
+ else
+ *subject = current_node->next;
+ xfree_observer_list_node (current_node);
+ return;
+ }
+ previous_node = current_node;
+ current_node = current_node->next;
+ }
+
+ /* We should never reach this point. However, this should not be
+ a very serious error, so simply report a warning to the user. */
+ warning ("Failed to detach observer");
+}
+
+/* Send a notification to all the observers of SUBJECT. ARGS is passed to
+ all observers as an argument to the notification callback. */
+
+static void
+generic_observer_notify (struct observer_list *subject, const void *args)
+{
+ struct observer_list *current_node = subject;
+
+ while (current_node != NULL)
+ {
+ (*current_node->observer->notify) (current_node->observer->data, args);
+ current_node = current_node->next;
+ }
+}
+
+/* normal_stop notifications. */
+
+static struct observer_list *normal_stop_subject = NULL;
+
+static void
+observer_normal_stop_notification_stub (const void *data,
+ const void *unused_args)
+{
+ observer_normal_stop_ftype *notify = (observer_normal_stop_ftype *) data;
+ (*notify) ();
+}
+
+struct observer *
+observer_attach_normal_stop (observer_normal_stop_ftype *f)
+{
+ return generic_observer_attach (&normal_stop_subject,
+ &observer_normal_stop_notification_stub,
+ (void *) f);
+}
+
+void
+observer_detach_normal_stop (struct observer *observer)
+{
+ generic_observer_detach (&normal_stop_subject, observer);
+}
+
+void
+observer_notify_normal_stop (void)
+{
+ generic_observer_notify (normal_stop_subject, NULL);
+}
+
+/* The following code is only used to unit-test the observers from our
+ testsuite. DO NOT USE IT within observer.c (or anywhere else for
+ that matter)! */
+
+/* If we define these variables and functions as `static', the
+ compiler will optimize them out. */
+
+int observer_test_first_observer = 0;
+int observer_test_second_observer = 0;
+int observer_test_third_observer = 0;
+
+void
+observer_test_first_notification_function (void)
+{
+ observer_test_first_observer++;
+}
+
+void
+observer_test_second_notification_function (void)
+{
+ observer_test_second_observer++;
+}
+
+void
+observer_test_third_notification_function (void)
+{
+ observer_test_third_observer++;
+}
+
diff --git a/contrib/gdb/gdb/observer.h b/contrib/gdb/gdb/observer.h
new file mode 100644
index 0000000..8b9a6db
--- /dev/null
+++ b/contrib/gdb/gdb/observer.h
@@ -0,0 +1,35 @@
+/* GDB Notifications to Observers.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 OBSERVER_H
+#define OBSERVER_H
+
+struct observer;
+
+/* normal_stop notifications. */
+
+typedef void (observer_normal_stop_ftype) (void);
+
+extern struct observer *
+ observer_attach_normal_stop (observer_normal_stop_ftype *f);
+extern void observer_detach_normal_stop (struct observer *observer);
+extern void observer_notify_normal_stop (void);
+
+#endif /* OBSERVER_H */
diff --git a/contrib/gdb/gdb/ocd.c b/contrib/gdb/gdb/ocd.c
new file mode 100644
index 0000000..c53db89f
--- /dev/null
+++ b/contrib/gdb/gdb/ocd.c
@@ -0,0 +1,1169 @@
+/* Target communications support for Macraigor Systems' On-Chip Debugging
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_string.h"
+#include <fcntl.h>
+#include "frame.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include <sys/types.h>
+#include <signal.h>
+#include "serial.h"
+#include "ocd.h"
+#include "regcache.h"
+
+/* Prototypes for local functions */
+
+static int ocd_read_bytes (CORE_ADDR memaddr, char *myaddr, int len);
+
+static int ocd_start_remote (void *dummy);
+
+static int readchar (int timeout);
+
+static void ocd_interrupt (int signo);
+
+static void ocd_interrupt_twice (int signo);
+
+static void interrupt_query (void);
+
+static unsigned char *ocd_do_command (int cmd, int *statusp, int *lenp);
+
+static void ocd_put_packet (unsigned char *packet, int pktlen);
+
+static unsigned char *ocd_get_packet (int cmd, int *pktlen, int timeout);
+
+static struct target_ops *current_ops = NULL;
+
+static int last_run_status;
+
+/* Descriptor for I/O to remote machine. Initialize it to NULL so that
+ ocd_open knows that we don't have a file open when the program
+ starts. */
+static struct serial *ocd_desc = NULL;
+
+void
+ocd_error (char *s, int error_code)
+{
+ char buf[100];
+
+ fputs_filtered (s, gdb_stderr);
+ fputs_filtered (" ", gdb_stderr);
+
+ switch (error_code)
+ {
+ case 0x1:
+ s = "Unknown fault";
+ break;
+ case 0x2:
+ s = "Power failed";
+ break;
+ case 0x3:
+ s = "Cable disconnected";
+ break;
+ case 0x4:
+ s = "Couldn't enter OCD mode";
+ break;
+ case 0x5:
+ s = "Target stuck in reset";
+ break;
+ case 0x6:
+ s = "OCD hasn't been initialized";
+ break;
+ case 0x7:
+ s = "Write verify failed";
+ break;
+ case 0x8:
+ s = "Reg buff error (during MPC5xx fp reg read/write)";
+ break;
+ case 0x9:
+ s = "Invalid CPU register access attempt failed";
+ break;
+ case 0x11:
+ s = "Bus error";
+ break;
+ case 0x12:
+ s = "Checksum error";
+ break;
+ case 0x13:
+ s = "Illegal command";
+ break;
+ case 0x14:
+ s = "Parameter error";
+ break;
+ case 0x15:
+ s = "Internal error";
+ break;
+ case 0x80:
+ s = "Flash erase error";
+ break;
+ default:
+ sprintf (buf, "Unknown error code %d", error_code);
+ s = buf;
+ }
+
+ error ("%s", s);
+}
+
+/* Return nonzero if the thread TH is still alive on the remote system. */
+
+int
+ocd_thread_alive (ptid_t th)
+{
+ return 1;
+}
+
+/* Clean up connection to a remote debugger. */
+
+void
+ocd_close (int quitting)
+{
+ if (ocd_desc)
+ serial_close (ocd_desc);
+ ocd_desc = NULL;
+}
+
+/* Stub for catch_errors. */
+
+static int
+ocd_start_remote (void *dummy)
+{
+ unsigned char buf[10], *p;
+ int pktlen;
+ int status;
+ int error_code;
+ int speed;
+ enum ocd_target_type target_type;
+
+ target_type = *(enum ocd_target_type *) dummy;
+
+ immediate_quit++; /* Allow user to interrupt it */
+
+ serial_send_break (ocd_desc); /* Wake up the wiggler */
+
+ speed = 80; /* Divide clock by 4000 */
+
+ buf[0] = OCD_INIT;
+ buf[1] = speed >> 8;
+ buf[2] = speed & 0xff;
+ buf[3] = target_type;
+ ocd_put_packet (buf, 4); /* Init OCD params */
+ p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
+
+ if (pktlen < 2)
+ error ("Truncated response packet from OCD device");
+
+ status = p[1];
+ error_code = p[2];
+
+ if (error_code != 0)
+ ocd_error ("OCD_INIT:", error_code);
+
+ ocd_do_command (OCD_AYT, &status, &pktlen);
+
+ p = ocd_do_command (OCD_GET_VERSION, &status, &pktlen);
+
+ printf_unfiltered ("[Wiggler version %x.%x, capability 0x%x]\n",
+ p[0], p[1], (p[2] << 16) | p[3]);
+
+ /* If processor is still running, stop it. */
+
+ if (!(status & OCD_FLAG_BDM))
+ ocd_stop ();
+
+ /* When using a target box, we want to asynchronously return status when
+ target stops. The OCD_SET_CTL_FLAGS command is ignored by Wigglers.dll
+ when using a parallel Wiggler */
+ buf[0] = OCD_SET_CTL_FLAGS;
+ buf[1] = 0;
+ buf[2] = 1;
+ ocd_put_packet (buf, 3);
+
+ p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
+
+ if (pktlen < 2)
+ error ("Truncated response packet from OCD device");
+
+ status = p[1];
+ error_code = p[2];
+
+ if (error_code != 0)
+ ocd_error ("OCD_SET_CTL_FLAGS:", error_code);
+
+ immediate_quit--;
+
+/* 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 ();
+ print_stack_frame (get_selected_frame (), -1, 1);
+
+ buf[0] = OCD_LOG_FILE;
+ buf[1] = 3; /* close existing WIGGLERS.LOG */
+ ocd_put_packet (buf, 2);
+ p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
+
+ buf[0] = OCD_LOG_FILE;
+ buf[1] = 2; /* append to existing WIGGLERS.LOG */
+ ocd_put_packet (buf, 2);
+ p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
+
+ return 1;
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+void
+ocd_open (char *name, int from_tty, enum ocd_target_type target_type,
+ struct target_ops *ops)
+{
+ unsigned char buf[10], *p;
+ int pktlen;
+
+ if (name == 0)
+ error ("To open an OCD connection, you need to specify the\n\
+device the OCD device is attached to (e.g. /dev/ttya).");
+
+ target_preopen (from_tty);
+
+ current_ops = ops;
+
+ unpush_target (current_ops);
+
+ ocd_desc = serial_open (name);
+ if (!ocd_desc)
+ perror_with_name (name);
+
+ if (baud_rate != -1)
+ {
+ if (serial_setbaudrate (ocd_desc, baud_rate))
+ {
+ serial_close (ocd_desc);
+ perror_with_name (name);
+ }
+ }
+
+ serial_raw (ocd_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 (ocd_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote target wiggler connected to ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+ push_target (current_ops); /* Switch to using remote target now */
+
+ /* Without this, some commands which require an active target (such as kill)
+ won't work. This variable serves (at least) double duty as both the pid
+ of the target process (if it has such), and as a flag indicating that a
+ target is active. These functions should be split out into seperate
+ variables, especially since GDB will someday have a notion of debugging
+ several processes. */
+
+ inferior_ptid = pid_to_ptid (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 (ocd_start_remote, &target_type,
+ "Couldn't establish connection to remote target\n",
+ RETURN_MASK_ALL))
+ {
+ pop_target ();
+ error ("Failed to connect to OCD.");
+ }
+}
+
+/* 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. */
+
+void
+ocd_detach (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");
+}
+
+/* Tell the remote machine to resume. */
+
+void
+ocd_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ int pktlen;
+
+ if (step)
+ ocd_do_command (OCD_STEP, &last_run_status, &pktlen);
+ else
+ ocd_do_command (OCD_RUN, &last_run_status, &pktlen);
+}
+
+void
+ocd_stop (void)
+{
+ int status;
+ int pktlen;
+
+ ocd_do_command (OCD_STOP, &status, &pktlen);
+
+ if (!(status & OCD_FLAG_BDM))
+ error ("Can't stop target via BDM");
+}
+
+static volatile int ocd_interrupt_flag;
+
+/* Send ^C to target to halt it. Target will respond, and send us a
+ packet. */
+
+static void
+ocd_interrupt (int signo)
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, ocd_interrupt_twice);
+
+ if (remote_debug)
+ printf_unfiltered ("ocd_interrupt called\n");
+
+ {
+ char buf[1];
+
+ ocd_stop ();
+ buf[0] = OCD_AYT;
+ ocd_put_packet (buf, 1);
+ ocd_interrupt_flag = 1;
+ }
+}
+
+static void (*ofunc) ();
+
+/* The user typed ^C twice. */
+static void
+ocd_interrupt_twice (int signo)
+{
+ signal (signo, ofunc);
+
+ interrupt_query ();
+
+ signal (signo, ocd_interrupt);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+interrupt_query (void)
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ throw_exception (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+/* If nonzero, ignore the next kill. */
+static 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). */
+
+int
+ocd_wait (void)
+{
+ unsigned char *p;
+ int error_code;
+ int pktlen;
+ char buf[1];
+
+ ocd_interrupt_flag = 0;
+
+ /* Target might already be stopped by the time we get here. */
+ /* If we aren't already stopped, we need to loop until we've dropped
+ back into BDM mode */
+
+ while (!(last_run_status & OCD_FLAG_BDM))
+ {
+ buf[0] = OCD_AYT;
+ ocd_put_packet (buf, 1);
+ p = ocd_get_packet (OCD_AYT, &pktlen, -1);
+
+ ofunc = (void (*)()) signal (SIGINT, ocd_interrupt);
+ signal (SIGINT, ofunc);
+
+ if (pktlen < 2)
+ error ("Truncated response packet from OCD device");
+
+ last_run_status = p[1];
+ error_code = p[2];
+
+ if (error_code != 0)
+ ocd_error ("target_wait:", error_code);
+
+ if (last_run_status & OCD_FLAG_PWF)
+ error ("OCD device lost VCC at BDM interface.");
+ else if (last_run_status & OCD_FLAG_CABLE_DISC)
+ error ("OCD device cable appears to have been disconnected.");
+ }
+
+ if (ocd_interrupt_flag)
+ return 1;
+ else
+ return 0;
+}
+
+/* Read registers from the OCD device. Specify the starting and ending
+ register number. Return the number of regs actually read in *NUMREGS.
+ Returns a pointer to a static array containing the register contents. */
+
+unsigned char *
+ocd_read_bdm_registers (int first_bdm_regno, int last_bdm_regno, int *reglen)
+{
+ unsigned char buf[10];
+ int i;
+ unsigned char *p;
+ unsigned char *regs;
+ int error_code, status;
+ int pktlen;
+
+ buf[0] = OCD_READ_REGS;
+ buf[1] = first_bdm_regno >> 8;
+ buf[2] = first_bdm_regno & 0xff;
+ buf[3] = last_bdm_regno >> 8;
+ buf[4] = last_bdm_regno & 0xff;
+
+ ocd_put_packet (buf, 5);
+ p = ocd_get_packet (OCD_READ_REGS, &pktlen, remote_timeout);
+
+ status = p[1];
+ error_code = p[2];
+
+ if (error_code != 0)
+ ocd_error ("read_bdm_registers:", error_code);
+
+ i = p[3];
+ if (i == 0)
+ i = 256;
+
+ if (i > pktlen - 4
+ || ((i & 3) != 0))
+ error ("Register block size bad: %d", i);
+
+ *reglen = i;
+
+ regs = p + 4;
+
+ return regs;
+}
+
+/* Read register BDM_REGNO and returns its value ala read_register() */
+
+CORE_ADDR
+ocd_read_bdm_register (int bdm_regno)
+{
+ int reglen;
+ unsigned char *p;
+ CORE_ADDR regval;
+
+ p = ocd_read_bdm_registers (bdm_regno, bdm_regno, &reglen);
+ regval = extract_unsigned_integer (p, reglen);
+
+ return regval;
+}
+
+void
+ocd_write_bdm_registers (int first_bdm_regno, unsigned char *regptr, int reglen)
+{
+ unsigned char *buf;
+ unsigned char *p;
+ int error_code, status;
+ int pktlen;
+
+ buf = alloca (4 + reglen);
+
+ buf[0] = OCD_WRITE_REGS;
+ buf[1] = first_bdm_regno >> 8;
+ buf[2] = first_bdm_regno & 0xff;
+ buf[3] = reglen;
+ memcpy (buf + 4, regptr, reglen);
+
+ ocd_put_packet (buf, 4 + reglen);
+ p = ocd_get_packet (OCD_WRITE_REGS, &pktlen, remote_timeout);
+
+ if (pktlen < 3)
+ error ("Truncated response packet from OCD device");
+
+ status = p[1];
+ error_code = p[2];
+
+ if (error_code != 0)
+ ocd_error ("ocd_write_bdm_registers:", error_code);
+}
+
+void
+ocd_write_bdm_register (int bdm_regno, CORE_ADDR reg)
+{
+ unsigned char buf[4];
+
+ store_unsigned_integer (buf, 4, reg);
+
+ ocd_write_bdm_registers (bdm_regno, buf, 4);
+}
+
+void
+ocd_prepare_to_store (void)
+{
+}
+
+/* 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 write_mem_command = OCD_WRITE_MEM;
+
+int
+ocd_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ char buf[256 + 10];
+ unsigned char *p;
+ int origlen;
+
+ origlen = len;
+
+ buf[0] = write_mem_command;
+ buf[5] = 1; /* Write as bytes */
+ buf[6] = 0; /* Don't verify */
+
+ while (len > 0)
+ {
+ int numbytes;
+ int pktlen;
+ int status, error_code;
+
+ numbytes = min (len, 256 - 8);
+
+ buf[1] = memaddr >> 24;
+ buf[2] = memaddr >> 16;
+ buf[3] = memaddr >> 8;
+ buf[4] = memaddr;
+
+ buf[7] = numbytes;
+
+ memcpy (&buf[8], myaddr, numbytes);
+ ocd_put_packet (buf, 8 + numbytes);
+ p = ocd_get_packet (OCD_WRITE_MEM, &pktlen, remote_timeout);
+ if (pktlen < 3)
+ error ("Truncated response packet from OCD device");
+
+ status = p[1];
+ error_code = p[2];
+
+ if (error_code == 0x11) /* Got a bus error? */
+ {
+ CORE_ADDR error_address;
+
+ error_address = p[3] << 24;
+ error_address |= p[4] << 16;
+ error_address |= p[5] << 8;
+ error_address |= p[6];
+ numbytes = error_address - memaddr;
+
+ len -= numbytes;
+
+ errno = EIO;
+
+ break;
+ }
+ else if (error_code != 0)
+ ocd_error ("ocd_write_bytes:", error_code);
+
+ len -= numbytes;
+ memaddr += numbytes;
+ myaddr += numbytes;
+ }
+
+ return origlen - 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
+ocd_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ char buf[256 + 10];
+ unsigned char *p;
+ int origlen;
+
+ origlen = len;
+
+ buf[0] = OCD_READ_MEM;
+ buf[5] = 1; /* Read as bytes */
+
+ while (len > 0)
+ {
+ int numbytes;
+ int pktlen;
+ int status, error_code;
+
+ numbytes = min (len, 256 - 7);
+
+ buf[1] = memaddr >> 24;
+ buf[2] = memaddr >> 16;
+ buf[3] = memaddr >> 8;
+ buf[4] = memaddr;
+
+ buf[6] = numbytes;
+
+ ocd_put_packet (buf, 7);
+ p = ocd_get_packet (OCD_READ_MEM, &pktlen, remote_timeout);
+ if (pktlen < 4)
+ error ("Truncated response packet from OCD device");
+
+ status = p[1];
+ error_code = p[2];
+
+ if (error_code == 0x11) /* Got a bus error? */
+ {
+ CORE_ADDR error_address;
+
+ error_address = p[3] << 24;
+ error_address |= p[4] << 16;
+ error_address |= p[5] << 8;
+ error_address |= p[6];
+ numbytes = error_address - memaddr;
+
+ len -= numbytes;
+
+ errno = EIO;
+
+ break;
+ }
+ else if (error_code != 0)
+ ocd_error ("ocd_read_bytes:", error_code);
+
+ memcpy (myaddr, &p[4], numbytes);
+
+ len -= numbytes;
+ memaddr += numbytes;
+ myaddr += numbytes;
+ }
+
+ return origlen - 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. TARGET
+ is ignored. */
+
+int
+ocd_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int should_write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int res;
+
+ if (should_write)
+ res = ocd_write_bytes (memaddr, myaddr, len);
+ else
+ res = ocd_read_bytes (memaddr, myaddr, len);
+
+ return res;
+}
+
+void
+ocd_files_info (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 side, handling wierd errors. */
+
+static int
+readchar (int timeout)
+{
+ int ch;
+
+ ch = serial_readchar (ocd_desc, timeout);
+
+ switch (ch)
+ {
+ case SERIAL_EOF:
+ error ("Remote connection closed");
+ case SERIAL_ERROR:
+ perror_with_name ("Remote communication error");
+ case SERIAL_TIMEOUT:
+ default:
+ return ch;
+ }
+}
+
+/* Send a packet to the OCD device. The packet framed by a SYN character,
+ a byte count and a checksum. The byte count only counts the number of
+ bytes between the count and the checksum. A count of zero actually
+ means 256. Any SYNs within the packet (including the checksum and
+ count) must be quoted. The quote character must be quoted as well.
+ Quoting is done by replacing the character with the two-character sequence
+ DLE, {char} | 0100. Note that the quoting mechanism has no effect on the
+ byte count. */
+
+static void
+ocd_put_packet (unsigned char *buf, int len)
+{
+ unsigned char checksum;
+ unsigned char c;
+ unsigned char *packet, *packet_ptr;
+
+ packet = alloca (len + 1 + 1); /* packet + SYN + checksum */
+ packet_ptr = packet;
+
+ checksum = 0;
+
+ *packet_ptr++ = 0x55;
+
+ while (len-- > 0)
+ {
+ c = *buf++;
+
+ checksum += c;
+ *packet_ptr++ = c;
+ }
+
+ *packet_ptr++ = -checksum;
+ if (serial_write (ocd_desc, packet, packet_ptr - packet))
+ perror_with_name ("output_packet: write failed");
+}
+
+/* Get a packet from the OCD device. Timeout is only enforced for the
+ first byte of the packet. Subsequent bytes are expected to arrive in
+ time <= remote_timeout. Returns a pointer to a static buffer containing
+ the payload of the packet. *LENP contains the length of the packet.
+ */
+
+static unsigned char *
+ocd_get_packet (int cmd, int *lenp, int timeout)
+{
+ int ch;
+ int len;
+ static unsigned char packet[512];
+ unsigned char *packet_ptr;
+ unsigned char checksum;
+
+ ch = readchar (timeout);
+
+ if (ch < 0)
+ error ("ocd_get_packet (readchar): %d", ch);
+
+ if (ch != 0x55)
+ error ("ocd_get_packet (readchar): %d", ch);
+
+/* Found the start of a packet */
+
+ packet_ptr = packet;
+ checksum = 0;
+
+/* Read command char. That sort of tells us how long the packet is. */
+
+ ch = readchar (timeout);
+
+ if (ch < 0)
+ error ("ocd_get_packet (readchar): %d", ch);
+
+ *packet_ptr++ = ch;
+ checksum += ch;
+
+/* Get status. */
+
+ ch = readchar (timeout);
+
+ if (ch < 0)
+ error ("ocd_get_packet (readchar): %d", ch);
+ *packet_ptr++ = ch;
+ checksum += ch;
+
+/* Get error code. */
+
+ ch = readchar (timeout);
+
+ if (ch < 0)
+ error ("ocd_get_packet (readchar): %d", ch);
+ *packet_ptr++ = ch;
+ checksum += ch;
+
+ switch (ch) /* Figure out length of packet */
+ {
+ case 0x7: /* Write verify error? */
+ len = 8; /* write address, value read back */
+ break;
+ case 0x11: /* Bus error? */
+ /* write address, read flag */
+ case 0x15: /* Internal error */
+ len = 5; /* error code, vector */
+ break;
+ default: /* Error w/no params */
+ len = 0;
+ break;
+ case 0x0: /* Normal result */
+ switch (packet[0])
+ {
+ case OCD_AYT: /* Are You There? */
+ case OCD_SET_BAUD_RATE: /* Set Baud Rate */
+ case OCD_INIT: /* Initialize OCD device */
+ case OCD_SET_SPEED: /* Set Speed */
+ case OCD_SET_FUNC_CODE: /* Set Function Code */
+ case OCD_SET_CTL_FLAGS: /* Set Control Flags */
+ case OCD_SET_BUF_ADDR: /* Set Register Buffer Address */
+ case OCD_RUN: /* Run Target from PC */
+ case OCD_RUN_ADDR: /* Run Target from Specified Address */
+ case OCD_STOP: /* Stop Target */
+ case OCD_RESET_RUN: /* Reset Target and Run */
+ case OCD_RESET: /* Reset Target and Halt */
+ case OCD_STEP: /* Single Step */
+ case OCD_WRITE_REGS: /* Write Register */
+ case OCD_WRITE_MEM: /* Write Memory */
+ case OCD_FILL_MEM: /* Fill Memory */
+ case OCD_MOVE_MEM: /* Move Memory */
+ case OCD_WRITE_INT_MEM: /* Write Internal Memory */
+ case OCD_JUMP: /* Jump to Subroutine */
+ case OCD_ERASE_FLASH: /* Erase flash memory */
+ case OCD_PROGRAM_FLASH: /* Write flash memory */
+ case OCD_EXIT_MON: /* Exit the flash programming monitor */
+ case OCD_ENTER_MON: /* Enter the flash programming monitor */
+ case OCD_LOG_FILE: /* Make Wigglers.dll save Wigglers.log */
+ case OCD_SET_CONNECTION: /* Set type of connection in Wigglers.dll */
+ len = 0;
+ break;
+ case OCD_GET_VERSION: /* Get Version */
+ len = 10;
+ break;
+ case OCD_GET_STATUS_MASK: /* Get Status Mask */
+ len = 1;
+ break;
+ case OCD_GET_CTRS: /* Get Error Counters */
+ case OCD_READ_REGS: /* Read Register */
+ case OCD_READ_MEM: /* Read Memory */
+ case OCD_READ_INT_MEM: /* Read Internal Memory */
+ len = 257;
+ break;
+ default:
+ error ("ocd_get_packet: unknown packet type 0x%x\n", ch);
+ }
+ }
+
+ if (len == 257) /* Byte stream? */
+ { /* Yes, byte streams contain the length */
+ ch = readchar (timeout);
+
+ if (ch < 0)
+ error ("ocd_get_packet (readchar): %d", ch);
+ *packet_ptr++ = ch;
+ checksum += ch;
+ len = ch;
+ if (len == 0)
+ len = 256;
+ }
+
+ while (len-- >= 0) /* Do rest of packet and checksum */
+ {
+ ch = readchar (timeout);
+
+ if (ch < 0)
+ error ("ocd_get_packet (readchar): %d", ch);
+ *packet_ptr++ = ch;
+ checksum += ch;
+ }
+
+ if (checksum != 0)
+ error ("ocd_get_packet: bad packet checksum");
+
+ if (cmd != -1 && cmd != packet[0])
+ error ("Response phase error. Got 0x%x, expected 0x%x", packet[0], cmd);
+
+ *lenp = packet_ptr - packet - 1; /* Subtract checksum byte */
+ return packet;
+}
+
+/* Execute a simple (one-byte) command. Returns a pointer to the data
+ following the error code. */
+
+static unsigned char *
+ocd_do_command (int cmd, int *statusp, int *lenp)
+{
+ unsigned char buf[100], *p;
+ int status, error_code;
+ char errbuf[100];
+
+ unsigned char logbuf[100];
+ int logpktlen;
+
+ buf[0] = cmd;
+ ocd_put_packet (buf, 1); /* Send command */
+ p = ocd_get_packet (*buf, lenp, remote_timeout);
+
+ if (*lenp < 3)
+ error ("Truncated response packet from OCD device");
+
+ status = p[1];
+ error_code = p[2];
+
+ if (error_code != 0)
+ {
+ sprintf (errbuf, "ocd_do_command (0x%x):", cmd);
+ ocd_error (errbuf, error_code);
+ }
+
+ if (status & OCD_FLAG_PWF)
+ error ("OCD device can't detect VCC at BDM interface.");
+ else if (status & OCD_FLAG_CABLE_DISC)
+ error ("BDM cable appears to be disconnected.");
+
+ *statusp = status;
+
+ logbuf[0] = OCD_LOG_FILE;
+ logbuf[1] = 3; /* close existing WIGGLERS.LOG */
+ ocd_put_packet (logbuf, 2);
+ ocd_get_packet (logbuf[0], &logpktlen, remote_timeout);
+
+ logbuf[0] = OCD_LOG_FILE;
+ logbuf[1] = 2; /* append to existing WIGGLERS.LOG */
+ ocd_put_packet (logbuf, 2);
+ ocd_get_packet (logbuf[0], &logpktlen, remote_timeout);
+
+ return p + 3;
+}
+
+void
+ocd_kill (void)
+{
+ /* 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;
+ }
+
+ /* Don't wait for it to die. I'm not really sure it matters whether
+ we do or not. */
+ target_mourn_inferior ();
+}
+
+void
+ocd_mourn (void)
+{
+ unpush_target (current_ops);
+ generic_mourn_inferior ();
+}
+
+/* All we actually do is set the PC to the start address of exec_bfd, and start
+ the program at that point. */
+
+void
+ocd_create_inferior (char *exec_file, char *args, char **env)
+{
+ if (args && (*args != '\000'))
+ error ("Args are not supported by BDM.");
+
+ clear_proceed_status ();
+ proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
+}
+
+void
+ocd_load (char *args, int from_tty)
+{
+ generic_load (args, from_tty);
+
+ inferior_ptid = null_ptid;
+
+/* 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 ();
+}
+
+/* This should be defined for each target */
+/* But we want to be able to compile this file for some configurations
+ not yet supported fully */
+
+#define BDM_BREAKPOINT {0x0,0x0,0x0,0x0} /* For ppc 8xx */
+
+/* BDM (at least on CPU32) uses a different breakpoint */
+
+int
+ocd_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ static char break_insn[] = BDM_BREAKPOINT;
+ int val;
+
+ val = target_read_memory (addr, contents_cache, sizeof (break_insn));
+
+ if (val == 0)
+ val = target_write_memory (addr, break_insn, sizeof (break_insn));
+
+ return val;
+}
+
+int
+ocd_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ static char break_insn[] = BDM_BREAKPOINT;
+ int val;
+
+ val = target_write_memory (addr, contents_cache, sizeof (break_insn));
+
+ return val;
+}
+
+static void
+bdm_command (char *args, int from_tty)
+{
+ error ("bdm command must be followed by `reset'");
+}
+
+static void
+bdm_reset_command (char *args, int from_tty)
+{
+ int status, pktlen;
+
+ if (!ocd_desc)
+ error ("Not connected to OCD device.");
+
+ ocd_do_command (OCD_RESET, &status, &pktlen);
+ dcache_invalidate (target_dcache);
+ registers_changed ();
+}
+
+static void
+bdm_restart_command (char *args, int from_tty)
+{
+ int status, pktlen;
+
+ if (!ocd_desc)
+ error ("Not connected to OCD device.");
+
+ ocd_do_command (OCD_RESET_RUN, &status, &pktlen);
+ last_run_status = status;
+ clear_proceed_status ();
+ wait_for_inferior ();
+ normal_stop ();
+}
+
+/* Temporary replacement for target_store_registers(). This prevents
+ generic_load from trying to set the PC. */
+
+static void
+noop_store_registers (int regno)
+{
+}
+
+static void
+bdm_update_flash_command (char *args, int from_tty)
+{
+ int status, pktlen;
+ struct cleanup *old_chain;
+ void (*store_registers_tmp) (int);
+
+ if (!ocd_desc)
+ error ("Not connected to OCD device.");
+
+ if (!args)
+ error ("Must specify file containing new OCD code.");
+
+/* old_chain = make_cleanup (flash_cleanup, 0); */
+
+ ocd_do_command (OCD_ENTER_MON, &status, &pktlen);
+
+ ocd_do_command (OCD_ERASE_FLASH, &status, &pktlen);
+
+ write_mem_command = OCD_PROGRAM_FLASH;
+ store_registers_tmp = current_target.to_store_registers;
+ current_target.to_store_registers = noop_store_registers;
+
+ generic_load (args, from_tty);
+
+ current_target.to_store_registers = store_registers_tmp;
+ write_mem_command = OCD_WRITE_MEM;
+
+ ocd_do_command (OCD_EXIT_MON, &status, &pktlen);
+
+/* discard_cleanups (old_chain); */
+}
+
+extern initialize_file_ftype _initialize_remote_ocd; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_ocd (void)
+{
+ extern struct cmd_list_element *cmdlist;
+ static struct cmd_list_element *ocd_cmd_list = NULL;
+
+ 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_prefix_cmd ("ocd", class_obscure, bdm_command, "", &ocd_cmd_list, "ocd ",
+ 0, &cmdlist);
+
+ add_cmd ("reset", class_obscure, bdm_reset_command, "", &ocd_cmd_list);
+ add_cmd ("restart", class_obscure, bdm_restart_command, "", &ocd_cmd_list);
+ add_cmd ("update-flash", class_obscure, bdm_update_flash_command, "", &ocd_cmd_list);
+}
diff --git a/contrib/gdb/gdb/ocd.h b/contrib/gdb/gdb/ocd.h
new file mode 100644
index 0000000..64d695a
--- /dev/null
+++ b/contrib/gdb/gdb/ocd.h
@@ -0,0 +1,142 @@
+/* Definitions for the Macraigor Systems BDM Wiggler
+ Copyright 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 OCD_H
+#define OCD_H
+
+struct mem_attrib;
+struct target_ops;
+
+/* Wiggler serial protocol definitions */
+
+#define DLE 020 /* Quote char */
+#define SYN 026 /* Start of packet */
+#define RAW_SYN ((026 << 8) | 026) /* get_quoted_char found a naked SYN */
+
+/* Status flags */
+
+#define OCD_FLAG_RESET 0x01 /* Target is being reset */
+#define OCD_FLAG_STOPPED 0x02 /* Target is halted */
+#define OCD_FLAG_BDM 0x04 /* Target is in BDM */
+#define OCD_FLAG_PWF 0x08 /* Power failed */
+#define OCD_FLAG_CABLE_DISC 0x10 /* BDM cable disconnected */
+
+/* Commands */
+
+#define OCD_AYT 0x0 /* Are you there? */
+#define OCD_GET_VERSION 0x1 /* Get Version */
+#define OCD_SET_BAUD_RATE 0x2 /* Set Baud Rate */
+#define OCD_INIT 0x10 /* Initialize Wiggler */
+#define OCD_SET_SPEED 0x11 /* Set Speed */
+#define OCD_GET_STATUS_MASK 0x12 /* Get Status Mask */
+#define OCD_GET_CTRS 0x13 /* Get Error Counters */
+#define OCD_SET_FUNC_CODE 0x14 /* Set Function Code */
+#define OCD_SET_CTL_FLAGS 0x15 /* Set Control Flags */
+#define OCD_SET_BUF_ADDR 0x16 /* Set Register Buffer Address */
+#define OCD_RUN 0x20 /* Run Target from PC */
+#define OCD_RUN_ADDR 0x21 /* Run Target from Specified Address */
+#define OCD_STOP 0x22 /* Stop Target */
+#define OCD_RESET_RUN 0x23 /* Reset Target and Run */
+#define OCD_RESET 0x24 /* Reset Target and Halt */
+#define OCD_STEP 0x25 /* Single step */
+#define OCD_READ_REGS 0x30 /* Read Registers */
+#define OCD_WRITE_REGS 0x31 /* Write Registers */
+#define OCD_READ_MEM 0x32 /* Read Memory */
+#define OCD_WRITE_MEM 0x33 /* Write Memory */
+#define OCD_FILL_MEM 0x34 /* Fill Memory */
+#define OCD_MOVE_MEM 0x35 /* Move Memory */
+
+#define OCD_READ_INT_MEM 0x80 /* Read Internal Memory */
+#define OCD_WRITE_INT_MEM 0x81 /* Write Internal Memory */
+#define OCD_JUMP 0x82 /* Jump to Subroutine */
+
+#define OCD_ERASE_FLASH 0x90 /* Erase flash memory */
+#define OCD_PROGRAM_FLASH 0x91 /* Write flash memory */
+#define OCD_EXIT_MON 0x93 /* Exit the flash programming monitor */
+#define OCD_ENTER_MON 0x94 /* Enter the flash programming monitor */
+
+#define OCD_SET_STATUS 0x0a /* Set status */
+#define OCD_SET_CONNECTION 0xf0 /* Set connection (init Wigglers.dll) */
+#define OCD_LOG_FILE 0xf1 /* Cmd to get Wigglers.dll to log cmds */
+#define OCD_FLAG_STOP 0x0 /* Stop the target, enter BDM */
+#define OCD_FLAG_START 0x01 /* Start the target at PC */
+#define OCD_FLAG_RETURN_STATUS 0x04 /* Return async status */
+
+/* Target type (for OCD_INIT command) */
+
+enum ocd_target_type
+ {
+ OCD_TARGET_CPU32 = 0x0, /* Moto cpu32 family */
+ OCD_TARGET_CPU16 = 0x1,
+ OCD_TARGET_MOTO_PPC = 0x2, /* Motorola PPC 5xx/8xx */
+ OCD_TARGET_IBM_PPC = 0x3
+ }; /* IBM PPC 4xx */
+
+void ocd_open (char *name, int from_tty, enum ocd_target_type,
+ struct target_ops *ops);
+
+void ocd_close (int quitting);
+
+void ocd_detach (char *args, int from_tty);
+
+void ocd_resume (ptid_t ptid, int step, enum target_signal siggnal);
+
+void ocd_prepare_to_store (void);
+
+void ocd_stop (void);
+
+void ocd_files_info (struct target_ops *ignore);
+
+
+int ocd_xfer_memory (CORE_ADDR memaddr, char *myaddr,
+ int len, int should_write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+
+void ocd_mourn (void);
+
+void ocd_create_inferior (char *exec_file, char *args, char **env);
+
+int ocd_thread_alive (ptid_t th);
+
+void ocd_error (char *s, int error_code);
+
+void ocd_kill (void);
+
+void ocd_load (char *args, int from_tty);
+
+unsigned char *ocd_read_bdm_registers (int first_bdm_regno,
+ int last_bdm_regno, int *reglen);
+
+CORE_ADDR ocd_read_bdm_register (int bdm_regno);
+
+void ocd_write_bdm_registers (int first_bdm_regno,
+ unsigned char *regptr, int reglen);
+
+void ocd_write_bdm_register (int bdm_regno, CORE_ADDR reg);
+
+int ocd_wait (void);
+
+int ocd_insert_breakpoint (CORE_ADDR addr, char *contents_cache);
+int ocd_remove_breakpoint (CORE_ADDR addr, char *contents_cache);
+
+int ocd_write_bytes (CORE_ADDR memaddr, char *myaddr, int len);
+
+#endif /* OCD_H */
diff --git a/contrib/gdb/gdb/osabi.c b/contrib/gdb/gdb/osabi.c
new file mode 100644
index 0000000..3acfc70
--- /dev/null
+++ b/contrib/gdb/gdb/osabi.c
@@ -0,0 +1,630 @@
+/* OS ABI variant handling for GDB.
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_assert.h"
+#include "gdb_string.h"
+
+#include "osabi.h"
+#include "arch-utils.h"
+#include "gdbcmd.h"
+#include "command.h"
+
+#include "elf-bfd.h"
+
+#ifndef GDB_OSABI_DEFAULT
+#define GDB_OSABI_DEFAULT GDB_OSABI_UNKNOWN
+#endif
+
+/* State for the "set osabi" command. */
+static enum { osabi_auto, osabi_default, osabi_user } user_osabi_state;
+static enum gdb_osabi user_selected_osabi;
+static const char *gdb_osabi_available_names[GDB_OSABI_INVALID + 3] = {
+ "auto",
+ "default",
+ "none",
+ NULL
+};
+static const char *set_osabi_string;
+
+/* This table matches the indices assigned to enum gdb_osabi. Keep
+ them in sync. */
+static const char * const gdb_osabi_names[] =
+{
+ "none",
+
+ "SVR4",
+ "GNU/Hurd",
+ "Solaris",
+ "OSF/1",
+ "GNU/Linux",
+ "FreeBSD a.out",
+ "FreeBSD ELF",
+ "NetBSD a.out",
+ "NetBSD ELF",
+ "OpenBSD ELF",
+ "Windows CE",
+ "DJGPP",
+ "NetWare",
+ "Irix",
+ "LynxOS",
+ "Interix",
+ "HP/UX ELF",
+ "HP/UX SOM",
+
+ "ARM EABI v1",
+ "ARM EABI v2",
+ "ARM APCS",
+ "QNX Neutrino",
+
+ "Cygwin",
+
+ "<invalid>"
+};
+
+const char *
+gdbarch_osabi_name (enum gdb_osabi osabi)
+{
+ if (osabi >= GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID)
+ return gdb_osabi_names[osabi];
+
+ return gdb_osabi_names[GDB_OSABI_INVALID];
+}
+
+/* Handler for a given architecture/OS ABI pair. There should be only
+ one handler for a given OS ABI each architecture family. */
+struct gdb_osabi_handler
+{
+ struct gdb_osabi_handler *next;
+ const struct bfd_arch_info *arch_info;
+ enum gdb_osabi osabi;
+ void (*init_osabi)(struct gdbarch_info, struct gdbarch *);
+};
+
+static struct gdb_osabi_handler *gdb_osabi_handler_list;
+
+void
+gdbarch_register_osabi (enum bfd_architecture arch, unsigned long machine,
+ enum gdb_osabi osabi,
+ void (*init_osabi)(struct gdbarch_info,
+ struct gdbarch *))
+{
+ struct gdb_osabi_handler **handler_p;
+ const struct bfd_arch_info *arch_info = bfd_lookup_arch (arch, machine);
+ const char **name_ptr;
+
+ /* Registering an OS ABI handler for "unknown" is not allowed. */
+ if (osabi == GDB_OSABI_UNKNOWN)
+ {
+ internal_error
+ (__FILE__, __LINE__,
+ "gdbarch_register_osabi: An attempt to register a handler for "
+ "OS ABI \"%s\" for architecture %s was made. The handler will "
+ "not be registered",
+ gdbarch_osabi_name (osabi),
+ bfd_printable_arch_mach (arch, machine));
+ return;
+ }
+
+ gdb_assert (arch_info);
+
+ for (handler_p = &gdb_osabi_handler_list; *handler_p != NULL;
+ handler_p = &(*handler_p)->next)
+ {
+ if ((*handler_p)->arch_info == arch_info
+ && (*handler_p)->osabi == osabi)
+ {
+ internal_error
+ (__FILE__, __LINE__,
+ "gdbarch_register_osabi: A handler for OS ABI \"%s\" "
+ "has already been registered for architecture %s",
+ gdbarch_osabi_name (osabi),
+ arch_info->printable_name);
+ /* If user wants to continue, override previous definition. */
+ (*handler_p)->init_osabi = init_osabi;
+ return;
+ }
+ }
+
+ (*handler_p)
+ = (struct gdb_osabi_handler *) xmalloc (sizeof (struct gdb_osabi_handler));
+ (*handler_p)->next = NULL;
+ (*handler_p)->arch_info = arch_info;
+ (*handler_p)->osabi = osabi;
+ (*handler_p)->init_osabi = init_osabi;
+
+ /* Add this OS ABI to the list of enum values for "set osabi", if it isn't
+ already there. */
+ for (name_ptr = gdb_osabi_available_names; *name_ptr; name_ptr ++)
+ {
+ if (*name_ptr == gdbarch_osabi_name (osabi))
+ return;
+ }
+ *name_ptr++ = gdbarch_osabi_name (osabi);
+ *name_ptr = NULL;
+}
+
+
+/* Sniffer to find the OS ABI for a given file's architecture and flavour.
+ It is legal to have multiple sniffers for each arch/flavour pair, to
+ disambiguate one OS's a.out from another, for example. The first sniffer
+ to return something other than GDB_OSABI_UNKNOWN wins, so a sniffer should
+ be careful to claim a file only if it knows for sure what it is. */
+struct gdb_osabi_sniffer
+{
+ struct gdb_osabi_sniffer *next;
+ enum bfd_architecture arch; /* bfd_arch_unknown == wildcard */
+ enum bfd_flavour flavour;
+ enum gdb_osabi (*sniffer)(bfd *);
+};
+
+static struct gdb_osabi_sniffer *gdb_osabi_sniffer_list;
+
+void
+gdbarch_register_osabi_sniffer (enum bfd_architecture arch,
+ enum bfd_flavour flavour,
+ enum gdb_osabi (*sniffer_fn)(bfd *))
+{
+ struct gdb_osabi_sniffer *sniffer;
+
+ sniffer =
+ (struct gdb_osabi_sniffer *) xmalloc (sizeof (struct gdb_osabi_sniffer));
+ sniffer->arch = arch;
+ sniffer->flavour = flavour;
+ sniffer->sniffer = sniffer_fn;
+
+ sniffer->next = gdb_osabi_sniffer_list;
+ gdb_osabi_sniffer_list = sniffer;
+}
+
+
+enum gdb_osabi
+gdbarch_lookup_osabi (bfd *abfd)
+{
+ struct gdb_osabi_sniffer *sniffer;
+ enum gdb_osabi osabi, match;
+ int match_specific;
+
+ /* If we aren't in "auto" mode, return the specified OS ABI. */
+ if (user_osabi_state == osabi_user)
+ return user_selected_osabi;
+
+ /* If we don't have a binary, return the default OS ABI (if set) or
+ an inconclusive result (otherwise). */
+ if (abfd == NULL)
+ {
+ if (GDB_OSABI_DEFAULT != GDB_OSABI_UNKNOWN)
+ return GDB_OSABI_DEFAULT;
+ else
+ return GDB_OSABI_UNINITIALIZED;
+ }
+
+ match = GDB_OSABI_UNKNOWN;
+ match_specific = 0;
+
+ for (sniffer = gdb_osabi_sniffer_list; sniffer != NULL;
+ sniffer = sniffer->next)
+ {
+ if ((sniffer->arch == bfd_arch_unknown /* wildcard */
+ || sniffer->arch == bfd_get_arch (abfd))
+ && sniffer->flavour == bfd_get_flavour (abfd))
+ {
+ osabi = (*sniffer->sniffer) (abfd);
+ if (osabi < GDB_OSABI_UNKNOWN || osabi >= GDB_OSABI_INVALID)
+ {
+ internal_error
+ (__FILE__, __LINE__,
+ "gdbarch_lookup_osabi: invalid OS ABI (%d) from sniffer "
+ "for architecture %s flavour %d",
+ (int) osabi,
+ bfd_printable_arch_mach (bfd_get_arch (abfd), 0),
+ (int) bfd_get_flavour (abfd));
+ }
+ else if (osabi != GDB_OSABI_UNKNOWN)
+ {
+ /* A specific sniffer always overrides a generic sniffer.
+ Croak on multiple match if the two matches are of the
+ same class. If the user wishes to continue, we'll use
+ the first match. */
+ if (match != GDB_OSABI_UNKNOWN)
+ {
+ if ((match_specific && sniffer->arch != bfd_arch_unknown)
+ || (!match_specific && sniffer->arch == bfd_arch_unknown))
+ {
+ internal_error
+ (__FILE__, __LINE__,
+ "gdbarch_lookup_osabi: multiple %sspecific OS ABI "
+ "match for architecture %s flavour %d: first "
+ "match \"%s\", second match \"%s\"",
+ match_specific ? "" : "non-",
+ bfd_printable_arch_mach (bfd_get_arch (abfd), 0),
+ (int) bfd_get_flavour (abfd),
+ gdbarch_osabi_name (match),
+ gdbarch_osabi_name (osabi));
+ }
+ else if (sniffer->arch != bfd_arch_unknown)
+ {
+ match = osabi;
+ match_specific = 1;
+ }
+ }
+ else
+ {
+ match = osabi;
+ if (sniffer->arch != bfd_arch_unknown)
+ match_specific = 1;
+ }
+ }
+ }
+ }
+
+ /* If we didn't find a match, but a default was specified at configure
+ time, return the default. */
+ if (GDB_OSABI_DEFAULT != GDB_OSABI_UNKNOWN && match == GDB_OSABI_UNKNOWN)
+ return GDB_OSABI_DEFAULT;
+ else
+ return match;
+}
+
+
+/* Return non-zero if architecture A can run code written for
+ architecture B. */
+static int
+can_run_code_for (const struct bfd_arch_info *a, const struct bfd_arch_info *b)
+{
+ /* BFD's 'A->compatible (A, B)' functions return zero if A and B are
+ incompatible. But if they are compatible, it returns the 'more
+ featureful' of the two arches. That is, if A can run code
+ written for B, but B can't run code written for A, then it'll
+ return A.
+
+ struct bfd_arch_info objects are singletons: that is, there's
+ supposed to be exactly one instance for a given machine. So you
+ can tell whether two are equivalent by comparing pointers. */
+ return (a == b || a->compatible (a, b) == a);
+}
+
+
+void
+gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdb_osabi_handler *handler;
+
+ if (info.osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* Don't complain about an unknown OSABI. Assume the user knows
+ what they are doing. */
+ return;
+ }
+
+ for (handler = gdb_osabi_handler_list; handler != NULL;
+ handler = handler->next)
+ {
+ if (handler->osabi != info.osabi)
+ continue;
+
+ /* If the architecture described by ARCH_INFO can run code for
+ the architcture we registered the handler for, then the
+ handler is applicable. Note, though, that if the handler is
+ for an architecture that is a superset of ARCH_INFO, we can't
+ use that --- it would be perfectly correct for it to install
+ gdbarch methods that refer to registers / instructions /
+ other facilities ARCH_INFO doesn't have.
+
+ NOTE: kettenis/20021027: There may be more than one machine
+ type that is compatible with the desired machine type. Right
+ now we simply return the first match, which is fine for now.
+ However, we might want to do something smarter in the future. */
+ /* NOTE: cagney/2003-10-23: The code for "a can_run_code_for b"
+ is implemented using BFD's compatible method (a->compatible
+ (b) == a -- the lowest common denominator between a and b is
+ a). That method's definition of compatible may not be as you
+ expect. For instance the test "amd64 can run code for i386"
+ (or more generally "64-bit ISA can run code for the 32-bit
+ ISA"). BFD doesn't normally consider 32-bit and 64-bit
+ "compatible" so it doesn't succeed. */
+ if (can_run_code_for (info.bfd_arch_info, handler->arch_info))
+ {
+ (*handler->init_osabi) (info, gdbarch);
+ return;
+ }
+ }
+
+ warning
+ ("A handler for the OS ABI \"%s\" is not built into this configuration\n"
+ "of GDB. Attempting to continue with the default %s settings.\n",
+ gdbarch_osabi_name (info.osabi),
+ info.bfd_arch_info->printable_name);
+}
+
+/* Limit on the amount of data to be read. */
+#define MAX_NOTESZ 128
+
+/* Return non-zero if NOTE matches NAME, DESCSZ and TYPE. */
+
+static int
+check_note (bfd *abfd, asection *sect, const char *note,
+ const char *name, unsigned long descsz, unsigned long type)
+{
+ unsigned long notesz;
+
+ /* Calculate the size of this note. */
+ notesz = strlen (name) + 1;
+ notesz = ((notesz + 3) & ~3);
+ notesz += descsz;
+ notesz = ((notesz + 3) & ~3);
+
+ /* If this assertion triggers, increase MAX_NOTESZ. */
+ gdb_assert (notesz <= MAX_NOTESZ);
+
+ /* Check whether SECT is big enough to comtain the complete note. */
+ if (notesz > bfd_section_size (abfd, sect))
+ return 0;
+
+ /* Check the note name. */
+ if (bfd_h_get_32 (abfd, note) != (strlen (name) + 1)
+ || strcmp (note + 12, name) != 0)
+ return 0;
+
+ /* Check the descriptor size. */
+ if (bfd_h_get_32 (abfd, note + 4) != descsz)
+ return 0;
+
+ /* Check the note type. */
+ if (bfd_h_get_32 (abfd, note + 8) != type)
+ return 0;
+
+ return 1;
+}
+
+/* Generic sniffer for ELF flavoured files. */
+
+void
+generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+ enum gdb_osabi *osabi = obj;
+ const char *name;
+ unsigned int sectsize;
+ char *note;
+
+ name = bfd_get_section_name (abfd, sect);
+ sectsize = bfd_section_size (abfd, sect);
+
+ /* Limit the amount of data to read. */
+ if (sectsize > MAX_NOTESZ)
+ sectsize = MAX_NOTESZ;
+
+ note = alloca (sectsize);
+ bfd_get_section_contents (abfd, sect, note, 0, sectsize);
+
+ /* .note.ABI-tag notes, used by GNU/Linux and FreeBSD. */
+ if (strcmp (name, ".note.ABI-tag") == 0)
+ {
+ /* GNU. */
+ if (check_note (abfd, sect, note, "GNU", 16, NT_GNU_ABI_TAG))
+ {
+ unsigned int abi_tag = bfd_h_get_32 (abfd, note + 16);
+
+ switch (abi_tag)
+ {
+ case GNU_ABI_TAG_LINUX:
+ *osabi = GDB_OSABI_LINUX;
+ break;
+
+ case GNU_ABI_TAG_HURD:
+ *osabi = GDB_OSABI_HURD;
+ break;
+
+ case GNU_ABI_TAG_SOLARIS:
+ *osabi = GDB_OSABI_SOLARIS;
+ break;
+
+ case GNU_ABI_TAG_FREEBSD:
+ *osabi = GDB_OSABI_FREEBSD_ELF;
+ break;
+
+ case GNU_ABI_TAG_NETBSD:
+ *osabi = GDB_OSABI_NETBSD_ELF;
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "\
+generic_elf_osabi_sniff_abi_tag_sections: unknown OS number %d",
+ abi_tag);
+ }
+ return;
+ }
+
+ /* FreeBSD. */
+ if (check_note (abfd, sect, note, "FreeBSD", 4, NT_FREEBSD_ABI_TAG))
+ {
+ /* There is no need to check the version yet. */
+ *osabi = GDB_OSABI_FREEBSD_ELF;
+ return;
+ }
+
+ return;
+ }
+
+ /* .note.netbsd.ident notes, used by NetBSD. */
+ if (strcmp (name, ".note.netbsd.ident") == 0
+ && check_note (abfd, sect, note, "NetBSD", 4, NT_NETBSD_IDENT))
+ {
+ /* There is no need to check the version yet. */
+ *osabi = GDB_OSABI_NETBSD_ELF;
+ return;
+ }
+
+ /* .note.openbsd.ident notes, used by OpenBSD. */
+ if (strcmp (name, ".note.openbsd.ident") == 0
+ && check_note (abfd, sect, note, "OpenBSD", 4, NT_OPENBSD_IDENT))
+ {
+ /* There is no need to check the version yet. */
+ *osabi = GDB_OSABI_OPENBSD_ELF;
+ return;
+ }
+
+ /* .note.netbsdcore.procinfo notes, used by NetBSD. */
+ if (strcmp (name, ".note.netbsdcore.procinfo") == 0)
+ {
+ *osabi = GDB_OSABI_NETBSD_ELF;
+ return;
+ }
+}
+
+static enum gdb_osabi
+generic_elf_osabi_sniffer (bfd *abfd)
+{
+ unsigned int elfosabi;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+ elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+ switch (elfosabi)
+ {
+ case ELFOSABI_NONE:
+ /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the
+ file are conforming to the base specification for that machine
+ (there are no OS-specific extensions). In order to determine the
+ real OS in use we must look for OS notes that have been added. */
+ bfd_map_over_sections (abfd,
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ break;
+
+ case ELFOSABI_FREEBSD:
+ osabi = GDB_OSABI_FREEBSD_ELF;
+ break;
+
+ case ELFOSABI_NETBSD:
+ osabi = GDB_OSABI_NETBSD_ELF;
+ break;
+
+ case ELFOSABI_LINUX:
+ osabi = GDB_OSABI_LINUX;
+ break;
+
+ case ELFOSABI_HURD:
+ osabi = GDB_OSABI_HURD;
+ break;
+
+ case ELFOSABI_SOLARIS:
+ osabi = GDB_OSABI_SOLARIS;
+ break;
+
+ case ELFOSABI_HPUX:
+ osabi = GDB_OSABI_HPUX_ELF;
+ break;
+ }
+
+ if (osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* The FreeBSD folks have been naughty; they stored the string
+ "FreeBSD" in the padding of the e_ident field of the ELF
+ header to "brand" their ELF binaries in FreeBSD 3.x. */
+ if (strcmp (&elf_elfheader (abfd)->e_ident[8], "FreeBSD") == 0)
+ osabi = GDB_OSABI_FREEBSD_ELF;
+ }
+
+ return osabi;
+}
+
+static void
+set_osabi (char *args, int from_tty, struct cmd_list_element *c)
+{
+ struct gdbarch_info info;
+
+ if (strcmp (set_osabi_string, "auto") == 0)
+ user_osabi_state = osabi_auto;
+ else if (strcmp (set_osabi_string, "default") == 0)
+ {
+ user_selected_osabi = GDB_OSABI_DEFAULT;
+ user_osabi_state = osabi_user;
+ }
+ else if (strcmp (set_osabi_string, "none") == 0)
+ {
+ user_selected_osabi = GDB_OSABI_UNKNOWN;
+ user_osabi_state = osabi_user;
+ }
+ else
+ {
+ int i;
+ for (i = 1; i < GDB_OSABI_INVALID; i++)
+ if (strcmp (set_osabi_string, gdbarch_osabi_name (i)) == 0)
+ {
+ user_selected_osabi = i;
+ user_osabi_state = osabi_user;
+ break;
+ }
+ if (i == GDB_OSABI_INVALID)
+ internal_error (__FILE__, __LINE__,
+ "Invalid OS ABI \"%s\" passed to command handler.",
+ set_osabi_string);
+ }
+
+ /* NOTE: At some point (true multiple architectures) we'll need to be more
+ graceful here. */
+ gdbarch_info_init (&info);
+ if (! gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "Updating OS ABI failed.");
+}
+
+static void
+show_osabi (char *args, int from_tty)
+{
+ if (user_osabi_state == osabi_auto)
+ printf_filtered ("The current OS ABI is \"auto\" (currently \"%s\").\n",
+ gdbarch_osabi_name (gdbarch_osabi (current_gdbarch)));
+ else
+ printf_filtered ("The current OS ABI is \"%s\".\n",
+ gdbarch_osabi_name (user_selected_osabi));
+
+ if (GDB_OSABI_DEFAULT != GDB_OSABI_UNKNOWN)
+ printf_filtered ("The default OS ABI is \"%s\".\n",
+ gdbarch_osabi_name (GDB_OSABI_DEFAULT));
+}
+
+extern initialize_file_ftype _initialize_gdb_osabi; /* -Wmissing-prototype */
+
+void
+_initialize_gdb_osabi (void)
+{
+ struct cmd_list_element *c;
+
+ if (strcmp (gdb_osabi_names[GDB_OSABI_INVALID], "<invalid>") != 0)
+ internal_error
+ (__FILE__, __LINE__,
+ "_initialize_gdb_osabi: gdb_osabi_names[] is inconsistent");
+
+ /* Register a generic sniffer for ELF flavoured files. */
+ gdbarch_register_osabi_sniffer (bfd_arch_unknown,
+ bfd_target_elf_flavour,
+ generic_elf_osabi_sniffer);
+
+ /* Register the "set osabi" command. */
+ c = add_set_enum_cmd ("osabi", class_support, gdb_osabi_available_names,
+ &set_osabi_string, "Set OS ABI of target.", &setlist);
+
+ set_cmd_sfunc (c, set_osabi);
+ add_cmd ("osabi", class_support, show_osabi, "Show OS/ABI of target.",
+ &showlist);
+ user_osabi_state = osabi_auto;
+}
diff --git a/contrib/gdb/gdb/osabi.h b/contrib/gdb/gdb/osabi.h
new file mode 100644
index 0000000..d0e33b3
--- /dev/null
+++ b/contrib/gdb/gdb/osabi.h
@@ -0,0 +1,55 @@
+/* OS ABI variant handling for GDB.
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 OSABI_H
+#define OSABI_H
+
+/* Register an OS ABI sniffer. Each arch/flavour may have more than
+ one sniffer. This is used to e.g. differentiate one OS's a.out from
+ another. The first sniffer to return something other than
+ GDB_OSABI_UNKNOWN wins, so a sniffer should be careful to claim a file
+ only if it knows for sure what it is. */
+void gdbarch_register_osabi_sniffer (enum bfd_architecture,
+ enum bfd_flavour,
+ enum gdb_osabi (*)(bfd *));
+
+/* Register a handler for an OS ABI variant for a given architecture
+ and machine type. There should be only one handler for a given OS
+ ABI for each architecture and machine type combination. */
+void gdbarch_register_osabi (enum bfd_architecture, unsigned long,
+ enum gdb_osabi,
+ void (*)(struct gdbarch_info,
+ struct gdbarch *));
+
+/* Lookup the OS ABI corresponding to the specified BFD. */
+enum gdb_osabi gdbarch_lookup_osabi (bfd *);
+
+/* Initialize the gdbarch for the specified OS ABI variant. */
+void gdbarch_init_osabi (struct gdbarch_info, struct gdbarch *);
+
+/* Return the name of the specified OS ABI. */
+const char *gdbarch_osabi_name (enum gdb_osabi);
+
+/* Helper routine for ELF file sniffers. This looks at ABI tag note
+ sections to determine the OS ABI from the note. It should be called
+ via bfd_map_over_sections. */
+void generic_elf_osabi_sniff_abi_tag_sections (bfd *, asection *, void *);
+
+#endif /* OSABI_H */
diff --git a/contrib/gdb/gdb/p-exp.c b/contrib/gdb/gdb/p-exp.c
new file mode 100644
index 0000000..d96a856
--- /dev/null
+++ b/contrib/gdb/gdb/p-exp.c
@@ -0,0 +1,2974 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ FLOAT = 259,
+ STRING = 260,
+ FIELDNAME = 261,
+ NAME = 262,
+ TYPENAME = 263,
+ NAME_OR_INT = 264,
+ STRUCT = 265,
+ CLASS = 266,
+ SIZEOF = 267,
+ COLONCOLON = 268,
+ ERROR = 269,
+ VARIABLE = 270,
+ THIS = 271,
+ TRUEKEYWORD = 272,
+ FALSEKEYWORD = 273,
+ ABOVE_COMMA = 274,
+ ASSIGN = 275,
+ NOT = 276,
+ OR = 277,
+ XOR = 278,
+ ANDAND = 279,
+ NOTEQUAL = 280,
+ GEQ = 281,
+ LEQ = 282,
+ MOD = 283,
+ DIV = 284,
+ RSH = 285,
+ LSH = 286,
+ DECREMENT = 287,
+ INCREMENT = 288,
+ UNARY = 289,
+ ARROW = 290,
+ BLOCKNAME = 291
+ };
+#endif
+#define INT 258
+#define FLOAT 259
+#define STRING 260
+#define FIELDNAME 261
+#define NAME 262
+#define TYPENAME 263
+#define NAME_OR_INT 264
+#define STRUCT 265
+#define CLASS 266
+#define SIZEOF 267
+#define COLONCOLON 268
+#define ERROR 269
+#define VARIABLE 270
+#define THIS 271
+#define TRUEKEYWORD 272
+#define FALSEKEYWORD 273
+#define ABOVE_COMMA 274
+#define ASSIGN 275
+#define NOT 276
+#define OR 277
+#define XOR 278
+#define ANDAND 279
+#define NOTEQUAL 280
+#define GEQ 281
+#define LEQ 282
+#define MOD 283
+#define DIV 284
+#define RSH 285
+#define LSH 286
+#define DECREMENT 287
+#define INCREMENT 288
+#define UNARY 289
+#define ARROW 290
+#define BLOCKNAME 291
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 46 "p-exp.y"
+
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "p-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "block.h"
+
+/* 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 pascal_maxdepth
+#define yyparse pascal_parse
+#define yylex pascal_lex
+#define yyerror pascal_error
+#define yylval pascal_lval
+#define yychar pascal_char
+#define yydebug pascal_debug
+#define yypact pascal_pact
+#define yyr1 pascal_r1
+#define yyr2 pascal_r2
+#define yydef pascal_def
+#define yychk pascal_chk
+#define yypgo pascal_pgo
+#define yyact pascal_act
+#define yyexca pascal_exca
+#define yyerrflag pascal_errflag
+#define yynerrs pascal_nerrs
+#define yyps pascal_ps
+#define yypv pascal_pv
+#define yys pascal_s
+#define yy_yys pascal_yys
+#define yystate pascal_state
+#define yytmp pascal_tmp
+#define yyv pascal_v
+#define yy_yyv pascal_yyv
+#define yyval pascal_val
+#define yylloc pascal_lloc
+#define yyreds pascal_reds /* With YYDEBUG defined */
+#define yytoks pascal_toks /* With YYDEBUG defined */
+#define yyname pascal_name /* With YYDEBUG defined */
+#define yyrule pascal_rule /* With YYDEBUG defined */
+#define yylhs pascal_yylhs
+#define yylen pascal_yylen
+#define yydefred pascal_yydefred
+#define yydgoto pascal_yydgoto
+#define yysindex pascal_yysindex
+#define yyrindex pascal_yyrindex
+#define yygindex pascal_yygindex
+#define yytable pascal_yytable
+#define yycheck pascal_yycheck
+
+#ifndef YYDEBUG
+#define YYDEBUG 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void
+yyerror (char *);
+
+static char * uptok (char *, int);
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 130 "p-exp.y"
+typedef union YYSTYPE {
+ 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 191 of yacc.c. */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+#line 154 "p-exp.y"
+
+/* YYSTYPE gets defined by %union */
+static int
+parse_number (char *, int, int, YYSTYPE *);
+
+static struct type *current_type;
+
+static void push_current_type (void);
+static void pop_current_type (void);
+static int search_field;
+
+
+/* Line 214 of yacc.c. */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC xmalloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 3
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 359
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 52
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 19
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 73
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 123
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 291
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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, 2, 2, 2,
+ 46, 50, 39, 37, 19, 38, 44, 40, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 28, 26, 29, 2, 36, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 45, 2, 51, 48, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 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, 20, 21, 22, 23, 24, 25,
+ 27, 30, 31, 32, 33, 34, 35, 41, 42, 43,
+ 47, 49
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 9, 11, 13, 15, 19,
+ 22, 25, 28, 31, 36, 41, 42, 47, 48, 54,
+ 55, 61, 62, 64, 68, 73, 77, 81, 85, 89,
+ 93, 97, 101, 105, 109, 113, 117, 121, 125, 129,
+ 133, 137, 141, 145, 149, 151, 153, 155, 157, 159,
+ 161, 163, 168, 170, 172, 174, 178, 182, 186, 188,
+ 191, 193, 195, 197, 201, 204, 206, 209, 212, 214,
+ 216, 218, 220, 222
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 53, 0, -1, -1, 54, 55, -1, 57, -1, 56,
+ -1, 67, -1, 58, -1, 57, 19, 58, -1, 58,
+ 48, -1, 36, 58, -1, 38, 58, -1, 22, 58,
+ -1, 42, 46, 58, 50, -1, 41, 46, 58, 50,
+ -1, -1, 58, 44, 59, 6, -1, -1, 58, 45,
+ 60, 57, 51, -1, -1, 58, 46, 61, 62, 50,
+ -1, -1, 58, -1, 62, 19, 58, -1, 67, 46,
+ 58, 50, -1, 46, 57, 50, -1, 58, 39, 58,
+ -1, 58, 40, 58, -1, 58, 33, 58, -1, 58,
+ 32, 58, -1, 58, 37, 58, -1, 58, 38, 58,
+ -1, 58, 35, 58, -1, 58, 34, 58, -1, 58,
+ 26, 58, -1, 58, 27, 58, -1, 58, 31, 58,
+ -1, 58, 30, 58, -1, 58, 28, 58, -1, 58,
+ 29, 58, -1, 58, 25, 58, -1, 58, 24, 58,
+ -1, 58, 23, 58, -1, 58, 21, 58, -1, 17,
+ -1, 18, -1, 3, -1, 9, -1, 4, -1, 64,
+ -1, 15, -1, 12, 46, 67, 50, -1, 5, -1,
+ 16, -1, 49, -1, 63, 13, 69, -1, 63, 13,
+ 69, -1, 68, 13, 69, -1, 65, -1, 13, 69,
+ -1, 70, -1, 68, -1, 66, -1, 68, 13, 39,
+ -1, 48, 68, -1, 8, -1, 10, 69, -1, 11,
+ 69, -1, 7, -1, 49, -1, 8, -1, 9, -1,
+ 7, -1, 49, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 234, 234, 234, 241, 242, 245, 252, 253, 258,
+ 264, 270, 274, 278, 282, 286, 286, 301, 299, 329,
+ 326, 338, 339, 341, 345, 360, 366, 370, 374, 378,
+ 382, 386, 390, 394, 398, 402, 406, 410, 414, 418,
+ 422, 426, 430, 434, 438, 444, 450, 457, 468, 475,
+ 478, 482, 490, 515, 542, 559, 570, 586, 601, 602,
+ 636, 708, 719, 720, 725, 727, 729, 732, 740, 741,
+ 742, 743, 746, 747
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INT", "FLOAT", "STRING", "FIELDNAME",
+ "NAME", "TYPENAME", "NAME_OR_INT", "STRUCT", "CLASS", "SIZEOF",
+ "COLONCOLON", "ERROR", "VARIABLE", "THIS", "TRUEKEYWORD",
+ "FALSEKEYWORD", "','", "ABOVE_COMMA", "ASSIGN", "NOT", "OR", "XOR",
+ "ANDAND", "'='", "NOTEQUAL", "'<'", "'>'", "GEQ", "LEQ", "MOD", "DIV",
+ "RSH", "LSH", "'@'", "'+'", "'-'", "'*'", "'/'", "DECREMENT",
+ "INCREMENT", "UNARY", "'.'", "'['", "'('", "ARROW", "'^'", "BLOCKNAME",
+ "')'", "']'", "$accept", "start", "@1", "normal_start", "type_exp",
+ "exp1", "exp", "@2", "@3", "@4", "arglist", "block", "variable",
+ "qualified_name", "ptype", "type", "typebase", "name",
+ "name_not_typename", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 44,
+ 274, 275, 276, 277, 278, 279, 61, 280, 60, 62,
+ 281, 282, 283, 284, 285, 286, 64, 43, 45, 42,
+ 47, 287, 288, 289, 46, 91, 40, 290, 94, 291,
+ 41, 93
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 52, 54, 53, 55, 55, 56, 57, 57, 58,
+ 58, 58, 58, 58, 58, 59, 58, 60, 58, 61,
+ 58, 62, 62, 62, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 63, 63, 64, 65, 64, 64,
+ 64, 66, 67, 67, 68, 68, 68, 68, 69, 69,
+ 69, 69, 70, 70
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 1, 3, 2,
+ 2, 2, 2, 4, 4, 0, 4, 0, 5, 0,
+ 5, 0, 1, 3, 4, 3, 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, 3, 3, 1, 2,
+ 1, 1, 1, 3, 2, 1, 2, 2, 1, 1,
+ 1, 1, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 2, 0, 0, 1, 46, 48, 52, 72, 65, 47,
+ 0, 0, 0, 0, 50, 53, 44, 45, 0, 0,
+ 0, 0, 0, 0, 0, 73, 3, 5, 4, 7,
+ 0, 49, 58, 62, 6, 61, 60, 68, 70, 71,
+ 69, 66, 67, 0, 59, 12, 0, 10, 11, 0,
+ 0, 0, 64, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 15, 17, 19, 9, 0, 0, 0, 0,
+ 61, 0, 0, 25, 8, 43, 42, 41, 40, 34,
+ 35, 38, 39, 37, 36, 29, 28, 33, 32, 30,
+ 31, 26, 27, 0, 0, 21, 56, 0, 63, 57,
+ 51, 0, 14, 13, 16, 0, 22, 0, 24, 18,
+ 0, 20, 23
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 1, 2, 26, 27, 28, 29, 103, 104, 105,
+ 117, 30, 31, 32, 33, 46, 35, 41, 36
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -37
+static const short yypact[] =
+{
+ -37, 5, 88, -37, -37, -37, -37, -37, -37, -37,
+ 6, 6, -35, 6, -37, -37, -37, -37, 88, 88,
+ 88, -29, -27, 88, 10, 12, -37, -37, 8, 201,
+ 16, -37, -37, -37, -13, 21, -37, -37, -37, -37,
+ -37, -37, -37, 10, -37, -36, -13, -36, -36, 88,
+ 88, 11, -37, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, -37, -37, -37, -37, 6, 88, 15, 20,
+ 43, 117, 145, -37, 201, 201, 226, 250, 273, 294,
+ 294, 311, 311, 311, 311, 28, 28, 28, 28, 68,
+ 68, -36, -36, 56, 88, 88, 62, 173, -37, -37,
+ -37, 38, -37, -37, -37, 9, 201, 44, -37, -37,
+ 88, -37, 201
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -37, -37, -37, -37, -37, -20, -18, -37, -37, -37,
+ -37, -37, -37, -37, -37, 14, -17, -7, -37
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -56
+static const yysigned_char yytable[] =
+{
+ 45, 47, 48, 51, 42, 3, 44, 52, 72, 73,
+ 74, 43, 75, 37, 38, 39, 34, 49, 8, 50,
+ 10, 11, 37, 38, 39, -54, 80, 53, 53, 76,
+ 53, 81, 82, 77, 78, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 108, 40, 111, 79, 24, 107,
+ 119, 83, 114, 120, 40, 68, 69, 70, 71, 106,
+ 110, 109, 72, 73, 74, -55, 75, 108, 0, 0,
+ 0, 0, 0, 0, 115, 0, 0, 116, 0, 0,
+ 0, 4, 5, 6, 121, 7, 8, 9, 10, 11,
+ 12, 13, 122, 14, 15, 16, 17, 70, 71, 0,
+ 18, 0, 72, 73, 74, 0, 75, 0, 0, 0,
+ 0, 0, 0, 0, 19, 0, 20, 0, 0, 21,
+ 22, 0, 0, 0, 23, 0, 24, 25, 54, 0,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 0, 68, 69, 70, 71, 0, 0,
+ 0, 72, 73, 74, 0, 75, 54, 112, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 0, 68, 69, 70, 71, 0, 0, 0, 72,
+ 73, 74, 0, 75, 54, 113, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 0,
+ 68, 69, 70, 71, 0, 0, 0, 72, 73, 74,
+ 0, 75, 54, 118, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 0, 68, 69,
+ 70, 71, 0, 0, 0, 72, 73, 74, 0, 75,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 0, 68, 69, 70, 71, 0, 0, 0,
+ 72, 73, 74, 0, 75, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 0, 68, 69, 70,
+ 71, 0, 0, 0, 72, 73, 74, 0, 75, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 0,
+ 68, 69, 70, 71, 0, 0, 0, 72, 73, 74,
+ 0, 75, 60, 61, 62, 63, 64, 65, 66, 67,
+ 0, 68, 69, 70, 71, 0, 0, 0, 72, 73,
+ 74, 0, 75, 64, 65, 66, 67, 0, 68, 69,
+ 70, 71, 0, 0, 0, 72, 73, 74, 0, 75
+};
+
+static const yysigned_char yycheck[] =
+{
+ 18, 19, 20, 23, 11, 0, 13, 24, 44, 45,
+ 46, 46, 48, 7, 8, 9, 2, 46, 8, 46,
+ 10, 11, 7, 8, 9, 13, 43, 19, 19, 13,
+ 19, 49, 50, 46, 13, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 39, 49, 13, 43, 48, 77,
+ 51, 50, 6, 19, 49, 37, 38, 39, 40, 76,
+ 50, 78, 44, 45, 46, 13, 48, 39, -1, -1,
+ -1, -1, -1, -1, 104, -1, -1, 105, -1, -1,
+ -1, 3, 4, 5, 50, 7, 8, 9, 10, 11,
+ 12, 13, 120, 15, 16, 17, 18, 39, 40, -1,
+ 22, -1, 44, 45, 46, -1, 48, -1, -1, -1,
+ -1, -1, -1, -1, 36, -1, 38, -1, -1, 41,
+ 42, -1, -1, -1, 46, -1, 48, 49, 21, -1,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, -1, 37, 38, 39, 40, -1, -1,
+ -1, 44, 45, 46, -1, 48, 21, 50, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, -1, 37, 38, 39, 40, -1, -1, -1, 44,
+ 45, 46, -1, 48, 21, 50, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, -1,
+ 37, 38, 39, 40, -1, -1, -1, 44, 45, 46,
+ -1, 48, 21, 50, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, -1, 37, 38,
+ 39, 40, -1, -1, -1, 44, 45, 46, -1, 48,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, -1, 37, 38, 39, 40, -1, -1, -1,
+ 44, 45, 46, -1, 48, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, -1, 37, 38, 39,
+ 40, -1, -1, -1, 44, 45, 46, -1, 48, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, -1,
+ 37, 38, 39, 40, -1, -1, -1, 44, 45, 46,
+ -1, 48, 28, 29, 30, 31, 32, 33, 34, 35,
+ -1, 37, 38, 39, 40, -1, -1, -1, 44, 45,
+ 46, -1, 48, 32, 33, 34, 35, -1, 37, 38,
+ 39, 40, -1, -1, -1, 44, 45, 46, -1, 48
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 53, 54, 0, 3, 4, 5, 7, 8, 9,
+ 10, 11, 12, 13, 15, 16, 17, 18, 22, 36,
+ 38, 41, 42, 46, 48, 49, 55, 56, 57, 58,
+ 63, 64, 65, 66, 67, 68, 70, 7, 8, 9,
+ 49, 69, 69, 46, 69, 58, 67, 58, 58, 46,
+ 46, 57, 68, 19, 21, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 37, 38,
+ 39, 40, 44, 45, 46, 48, 13, 46, 13, 67,
+ 68, 58, 58, 50, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 59, 60, 61, 69, 58, 39, 69,
+ 50, 13, 50, 50, 6, 57, 58, 62, 50, 51,
+ 19, 50, 58
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to xreallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to xreallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 234 "p-exp.y"
+ { current_type = NULL;
+ search_field = 0;
+ }
+ break;
+
+ case 3:
+#line 237 "p-exp.y"
+ {}
+ break;
+
+ case 6:
+#line 246 "p-exp.y"
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(yyvsp[0].tval);
+ write_exp_elt_opcode(OP_TYPE);
+ current_type = yyvsp[0].tval; }
+ break;
+
+ case 8:
+#line 254 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_COMMA); }
+ break;
+
+ case 9:
+#line 259 "p-exp.y"
+ { write_exp_elt_opcode (UNOP_IND);
+ if (current_type)
+ current_type = TYPE_TARGET_TYPE (current_type); }
+ break;
+
+ case 10:
+#line 265 "p-exp.y"
+ { write_exp_elt_opcode (UNOP_ADDR);
+ if (current_type)
+ current_type = TYPE_POINTER_TYPE (current_type); }
+ break;
+
+ case 11:
+#line 271 "p-exp.y"
+ { write_exp_elt_opcode (UNOP_NEG); }
+ break;
+
+ case 12:
+#line 275 "p-exp.y"
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ break;
+
+ case 13:
+#line 279 "p-exp.y"
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ break;
+
+ case 14:
+#line 283 "p-exp.y"
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ break;
+
+ case 15:
+#line 286 "p-exp.y"
+ { search_field = 1; }
+ break;
+
+ case 16:
+#line 289 "p-exp.y"
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ search_field = 0;
+ if (current_type)
+ { while (TYPE_CODE (current_type) == TYPE_CODE_PTR)
+ current_type = TYPE_TARGET_TYPE (current_type);
+ current_type = lookup_struct_elt_type (
+ current_type, yyvsp[0].sval.ptr, 0); };
+ }
+ break;
+
+ case 17:
+#line 301 "p-exp.y"
+ { char *arrayname;
+ int arrayfieldindex;
+ arrayfieldindex = is_pascal_string_type (
+ current_type, NULL, NULL,
+ NULL, NULL, &arrayname);
+ if (arrayfieldindex)
+ {
+ struct stoken stringsval;
+ stringsval.ptr = alloca (strlen (arrayname) + 1);
+ stringsval.length = strlen (arrayname);
+ strcpy (stringsval.ptr, arrayname);
+ current_type = TYPE_FIELD_TYPE (current_type,
+ arrayfieldindex - 1);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (stringsval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ }
+ push_current_type (); }
+ break;
+
+ case 18:
+#line 320 "p-exp.y"
+ { pop_current_type ();
+ write_exp_elt_opcode (BINOP_SUBSCRIPT);
+ if (current_type)
+ current_type = TYPE_TARGET_TYPE (current_type); }
+ break;
+
+ case 19:
+#line 329 "p-exp.y"
+ { push_current_type ();
+ start_arglist (); }
+ break;
+
+ case 20:
+#line 332 "p-exp.y"
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL);
+ pop_current_type (); }
+ break;
+
+ case 22:
+#line 340 "p-exp.y"
+ { arglist_len = 1; }
+ break;
+
+ case 23:
+#line 342 "p-exp.y"
+ { arglist_len++; }
+ break;
+
+ case 24:
+#line 346 "p-exp.y"
+ { if (current_type)
+ {
+ /* Allow automatic dereference of classes. */
+ if ((TYPE_CODE (current_type) == TYPE_CODE_PTR)
+ && (TYPE_CODE (TYPE_TARGET_TYPE (current_type)) == TYPE_CODE_CLASS)
+ && (TYPE_CODE (yyvsp[-3].tval) == TYPE_CODE_CLASS))
+ write_exp_elt_opcode (UNOP_IND);
+ }
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-3].tval);
+ write_exp_elt_opcode (UNOP_CAST);
+ current_type = yyvsp[-3].tval; }
+ break;
+
+ case 25:
+#line 361 "p-exp.y"
+ { }
+ break;
+
+ case 26:
+#line 367 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_MUL); }
+ break;
+
+ case 27:
+#line 371 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_DIV); }
+ break;
+
+ case 28:
+#line 375 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_INTDIV); }
+ break;
+
+ case 29:
+#line 379 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_REM); }
+ break;
+
+ case 30:
+#line 383 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_ADD); }
+ break;
+
+ case 31:
+#line 387 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_SUB); }
+ break;
+
+ case 32:
+#line 391 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_LSH); }
+ break;
+
+ case 33:
+#line 395 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_RSH); }
+ break;
+
+ case 34:
+#line 399 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_EQUAL); }
+ break;
+
+ case 35:
+#line 403 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+ break;
+
+ case 36:
+#line 407 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_LEQ); }
+ break;
+
+ case 37:
+#line 411 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_GEQ); }
+ break;
+
+ case 38:
+#line 415 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_LESS); }
+ break;
+
+ case 39:
+#line 419 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_GTR); }
+ break;
+
+ case 40:
+#line 423 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ break;
+
+ case 41:
+#line 427 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ break;
+
+ case 42:
+#line 431 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ break;
+
+ case 43:
+#line 435 "p-exp.y"
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ break;
+
+ case 44:
+#line 439 "p-exp.y"
+ { write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_BOOL); }
+ break;
+
+ case 45:
+#line 445 "p-exp.y"
+ { write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_BOOL); }
+ break;
+
+ case 46:
+#line 451 "p-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 47:
+#line 458 "p-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 48:
+#line 469 "p-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 51:
+#line 483 "p-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 52:
+#line 491 "p-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 53:
+#line 516 "p-exp.y"
+ {
+ struct value * this_val;
+ struct type * this_type;
+ write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS);
+ /* we need type of this */
+ this_val = value_of_this (0);
+ if (this_val)
+ this_type = this_val->type;
+ else
+ this_type = NULL;
+ if (this_type)
+ {
+ if (TYPE_CODE (this_type) == TYPE_CODE_PTR)
+ {
+ this_type = TYPE_TARGET_TYPE (this_type);
+ write_exp_elt_opcode (UNOP_IND);
+ }
+ }
+
+ current_type = this_type;
+ }
+ break;
+
+ case 54:
+#line 543 "p-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 55:
+#line 560 "p-exp.y"
+ { struct symbol *tem
+ = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, (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 56:
+#line 571 "p-exp.y"
+ { struct symbol *sym;
+ sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_DOMAIN, (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 57:
+#line 587 "p-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 59:
+#line 603 "p-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_DOMAIN, (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 60:
+#line 637 "p-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);
+ current_type = sym->type; }
+ else if (yyvsp[0].ssym.is_a_field_of_this)
+ {
+ struct value * this_val;
+ struct type * this_type;
+ /* Object pascal: 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);
+ /* we need type of this */
+ this_val = value_of_this (0);
+ if (this_val)
+ this_type = this_val->type;
+ else
+ this_type = NULL;
+ if (this_type)
+ current_type = lookup_struct_elt_type (
+ this_type,
+ copy_name (yyvsp[0].ssym.stoken), 0);
+ else
+ current_type = NULL;
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ 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 63:
+#line 721 "p-exp.y"
+ { yyval.tval = lookup_member_type (builtin_type_int, yyvsp[-2].tval); }
+ break;
+
+ case 64:
+#line 726 "p-exp.y"
+ { yyval.tval = lookup_pointer_type (yyvsp[0].tval); }
+ break;
+
+ case 65:
+#line 728 "p-exp.y"
+ { yyval.tval = yyvsp[0].tsym.type; }
+ break;
+
+ case 66:
+#line 730 "p-exp.y"
+ { yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 67:
+#line 733 "p-exp.y"
+ { yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+ break;
+
+ case 68:
+#line 740 "p-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+ case 69:
+#line 741 "p-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+ case 70:
+#line 742 "p-exp.y"
+ { yyval.sval = yyvsp[0].tsym.stoken; }
+ break;
+
+ case 71:
+#line 743 "p-exp.y"
+ { yyval.sval = yyvsp[0].ssym.stoken; }
+ break;
+
+
+ }
+
+/* Line 991 of yacc.c. */
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ 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)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab2;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+
+ /* Suppress GCC warning that yyerrlab1 is unused when no action
+ invokes YYERROR. Doesn't work in C++ */
+#ifndef __cplusplus
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+#endif
+#endif
+
+
+ goto yyerrlab2;
+
+
+/*---------------------------------------------------------------.
+| yyerrlab2 -- pop states until the error token can be shifted. |
+`---------------------------------------------------------------*/
+yyerrlab2:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 757 "p-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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ /* FIXME: Shouldn't these be unsigned? We don't deal with negative values
+ here, and we do kind of silly things like cast to unsigned. */
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ ULONGEST un;
+
+ int i = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
+ int long_p = 0;
+
+ /* We have found a "L" or "U" suffix. */
+ int found_suffix = 0;
+
+ ULONGEST 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. */
+ char c;
+ int num = 0; /* number of tokens scanned by scanf */
+ char saved_char = p[len];
+
+ p[len] = 0; /* null-terminate the token */
+ if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
+ num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval,&c);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval,&c);
+ else
+ {
+#ifdef SCANF_HAS_LONG_DOUBLE
+ num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval,&c);
+#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;
+ num = sscanf (p, "%lg%c", &temp,&c);
+ putithere->typed_val_float.dval = temp;
+#endif
+ }
+ p[len] = saved_char; /* restore the input stream */
+ if (num != 1) /* check scanf found ONLY a float ... */
+ return ERROR;
+ /* 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 && (ULONGEST) prevn >= (ULONGEST) 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 = (ULONGEST)n >> 2;
+ if (long_p == 0
+ && (un >> (TARGET_INT_BIT - 2)) == 0)
+ {
+ high_bit = ((ULONGEST)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 = ((ULONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ int shift;
+ if (sizeof (ULONGEST) * HOST_CHAR_BIT < TARGET_LONG_LONG_BIT)
+ /* A long long does not fit in a LONGEST. */
+ shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
+ else
+ shift = (TARGET_LONG_LONG_BIT - 1);
+ high_bit = (ULONGEST) 1 << shift;
+ 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 type_push
+{
+ struct type *stored;
+ struct type_push *next;
+};
+
+static struct type_push *tp_top = NULL;
+
+static void
+push_current_type (void)
+{
+ struct type_push *tpnew;
+ tpnew = (struct type_push *) xmalloc (sizeof (struct type_push));
+ tpnew->next = tp_top;
+ tpnew->stored = current_type;
+ current_type = NULL;
+ tp_top = tpnew;
+}
+
+static void
+pop_current_type (void)
+{
+ struct type_push *tp = tp_top;
+ if (tp)
+ {
+ current_type = tp->stored;
+ tp_top = tp->next;
+ xfree (tp);
+ }
+}
+
+struct token
+{
+ char *operator;
+ int token;
+ enum exp_opcode opcode;
+};
+
+static const struct token tokentab3[] =
+ {
+ {"shr", RSH, BINOP_END},
+ {"shl", LSH, BINOP_END},
+ {"and", ANDAND, BINOP_END},
+ {"div", DIV, BINOP_END},
+ {"not", NOT, BINOP_END},
+ {"mod", MOD, BINOP_END},
+ {"inc", INCREMENT, BINOP_END},
+ {"dec", DECREMENT, BINOP_END},
+ {"xor", XOR, BINOP_END}
+ };
+
+static const struct token tokentab2[] =
+ {
+ {"or", OR, BINOP_END},
+ {"<>", NOTEQUAL, BINOP_END},
+ {"<=", LEQ, BINOP_END},
+ {">=", GEQ, BINOP_END},
+ {":=", ASSIGN, BINOP_END},
+ {"::", COLONCOLON, BINOP_END} };
+
+/* Allocate uppercased var */
+/* make an uppercased copy of tokstart */
+static char * uptok (tokstart, namelen)
+ char *tokstart;
+ int namelen;
+{
+ int i;
+ char *uptokstart = (char *)xmalloc(namelen+1);
+ for (i = 0;i <= namelen;i++)
+ {
+ if ((tokstart[i]>='a' && tokstart[i]<='z'))
+ uptokstart[i] = tokstart[i]-('a'-'A');
+ else
+ uptokstart[i] = tokstart[i];
+ }
+ uptokstart[namelen]='\0';
+ return uptokstart;
+}
+/* Read one token, getting characters through lexptr. */
+
+
+static int
+yylex ()
+{
+ int c;
+ int namelen;
+ unsigned int i;
+ char *tokstart;
+ char *uptokstart;
+ char *tokptr;
+ char *p;
+ int explen, tempbufindex;
+ static char *tempbuf;
+ static int tempbufsize;
+
+ retry:
+
+ prev_lexptr = lexptr;
+
+ tokstart = lexptr;
+ explen = strlen (lexptr);
+ /* See if it is a special token of length 3. */
+ if (explen > 2)
+ for (i = 0; i < sizeof (tokentab3) / sizeof (tokentab3[0]); i++)
+ if (strncasecmp (tokstart, tokentab3[i].operator, 3) == 0
+ && (!isalpha (tokentab3[i].operator[0]) || explen == 3
+ || (!isalpha (tokstart[3]) && !isdigit (tokstart[3]) && tokstart[3] != '_')))
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ if (explen > 1)
+ for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++)
+ if (strncasecmp (tokstart, tokentab2[i].operator, 2) == 0
+ && (!isalpha (tokentab2[i].operator[0]) || explen == 2
+ || (!isalpha (tokstart[2]) && !isdigit (tokstart[2]) && tokstart[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 object pascal
+ 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++;
+ uptokstart = uptok(tokstart,namelen);
+ 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;
+ 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 '}':
+ 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 == '<');)
+ {
+ /* Template parameter lists are part of the name.
+ FIXME: This mishandles `print $a<4&&$a>3'. */
+ if (c == '<')
+ {
+ int i = namelen;
+ int nesting_level = 1;
+ while (tokstart[++i])
+ {
+ if (tokstart[i] == '<')
+ nesting_level++;
+ else if (tokstart[i] == '>')
+ {
+ if (--nesting_level == 0)
+ break;
+ }
+ }
+ if (tokstart[i] == '>')
+ namelen = i;
+ else
+ break;
+ }
+
+ /* do NOT uppercase internals because of registers !!! */
+ c = tokstart[++namelen];
+ }
+
+ uptokstart = uptok(tokstart,namelen);
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && uptokstart[0] == 'I' && uptokstart[1] == 'F')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ tryname:
+
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 6:
+ if (DEPRECATED_STREQ (uptokstart, "OBJECT"))
+ return CLASS;
+ if (DEPRECATED_STREQ (uptokstart, "RECORD"))
+ return STRUCT;
+ if (DEPRECATED_STREQ (uptokstart, "SIZEOF"))
+ return SIZEOF;
+ break;
+ case 5:
+ if (DEPRECATED_STREQ (uptokstart, "CLASS"))
+ return CLASS;
+ if (DEPRECATED_STREQ (uptokstart, "FALSE"))
+ {
+ yylval.lval = 0;
+ return FALSEKEYWORD;
+ }
+ break;
+ case 4:
+ if (DEPRECATED_STREQ (uptokstart, "TRUE"))
+ {
+ yylval.lval = 1;
+ return TRUEKEYWORD;
+ }
+ if (DEPRECATED_STREQ (uptokstart, "SELF"))
+ {
+ /* here we search for 'this' like
+ inserted in FPC stabs debug info */
+ static const char this_name[] = "this";
+
+ if (lookup_symbol (this_name, expression_context_block,
+ VAR_DOMAIN, (int *) NULL,
+ (struct symtab **) NULL))
+ return THIS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ if (*tokstart == '$')
+ {
+ /* $ is the normal prefix for pascal hexadecimal values
+ but this conflicts with the GDB use for debugger variables
+ so in expression to enter hexadecimal values
+ we still need to use C syntax with 0xff */
+ 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 is_a_field = 0;
+ int hextype;
+
+
+ if (search_field && current_type)
+ is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL);
+ if (is_a_field)
+ sym = NULL;
+ else
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ &is_a_field_of_this,
+ (struct symtab **) NULL);
+ /* second chance uppercased (as Free Pascal does). */
+ if (!sym && !is_a_field_of_this && !is_a_field)
+ {
+ for (i = 0; i <= namelen; i++)
+ {
+ if ((tmp[i] >= 'a' && tmp[i] <= 'z'))
+ tmp[i] -= ('a'-'A');
+ }
+ if (search_field && current_type)
+ is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL);
+ if (is_a_field)
+ sym = NULL;
+ else
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ &is_a_field_of_this,
+ (struct symtab **) NULL);
+ if (sym || is_a_field_of_this || is_a_field)
+ for (i = 0; i <= namelen; i++)
+ {
+ if ((tokstart[i] >= 'a' && tokstart[i] <= 'z'))
+ tokstart[i] -= ('a'-'A');
+ }
+ }
+ /* Third chance Capitalized (as GPC does). */
+ if (!sym && !is_a_field_of_this && !is_a_field)
+ {
+ for (i = 0; i <= namelen; i++)
+ {
+ if (i == 0)
+ {
+ if ((tmp[i] >= 'a' && tmp[i] <= 'z'))
+ tmp[i] -= ('a'-'A');
+ }
+ else
+ if ((tmp[i] >= 'A' && tmp[i] <= 'Z'))
+ tmp[i] -= ('A'-'a');
+ }
+ if (search_field && current_type)
+ is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL);
+ if (is_a_field)
+ sym = NULL;
+ else
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ &is_a_field_of_this,
+ (struct symtab **) NULL);
+ if (sym || is_a_field_of_this || is_a_field)
+ for (i = 0; i <= namelen; i++)
+ {
+ if (i == 0)
+ {
+ if ((tokstart[i] >= 'a' && tokstart[i] <= 'z'))
+ tokstart[i] -= ('a'-'A');
+ }
+ else
+ if ((tokstart[i] >= 'A' && tokstart[i] <= 'Z'))
+ tokstart[i] -= ('A'-'a');
+ }
+ }
+
+ if (is_a_field)
+ {
+ tempbuf = (char *) xrealloc (tempbuf, namelen + 1);
+ strncpy (tempbuf, tokstart, namelen); tempbuf [namelen] = 0;
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = namelen;
+ return FIELDNAME;
+ }
+ /* 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_DOMAIN, (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;
+ }
+ }
+
+ free(uptokstart);
+ /* Any other kind of symbol */
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME;
+ }
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+}
+
+
diff --git a/contrib/gdb/gdb/p-exp.y b/contrib/gdb/gdb/p-exp.y
new file mode 100644
index 0000000..779424e
--- /dev/null
+++ b/contrib/gdb/gdb/p-exp.y
@@ -0,0 +1,1650 @@
+/* YACC parser for Pascal expressions, for GDB.
+ Copyright 2000
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 derived from c-exp.y */
+
+/* Parse a Pascal 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 (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator. */
+
+/* Known bugs or limitations:
+ - pascal string operations are not supported at all.
+ - there are some problems with boolean types.
+ - Pascal type hexadecimal constants are not supported
+ because they conflict with the internal variables format.
+ Probably also lots of other problems, less well defined PM */
+%{
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "p-lang.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h" /* Required by objfiles.h. */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "block.h"
+
+/* 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 pascal_maxdepth
+#define yyparse pascal_parse
+#define yylex pascal_lex
+#define yyerror pascal_error
+#define yylval pascal_lval
+#define yychar pascal_char
+#define yydebug pascal_debug
+#define yypact pascal_pact
+#define yyr1 pascal_r1
+#define yyr2 pascal_r2
+#define yydef pascal_def
+#define yychk pascal_chk
+#define yypgo pascal_pgo
+#define yyact pascal_act
+#define yyexca pascal_exca
+#define yyerrflag pascal_errflag
+#define yynerrs pascal_nerrs
+#define yyps pascal_ps
+#define yypv pascal_pv
+#define yys pascal_s
+#define yy_yys pascal_yys
+#define yystate pascal_state
+#define yytmp pascal_tmp
+#define yyv pascal_v
+#define yy_yyv pascal_yyv
+#define yyval pascal_val
+#define yylloc pascal_lloc
+#define yyreds pascal_reds /* With YYDEBUG defined */
+#define yytoks pascal_toks /* With YYDEBUG defined */
+#define yyname pascal_name /* With YYDEBUG defined */
+#define yyrule pascal_rule /* With YYDEBUG defined */
+#define yylhs pascal_yylhs
+#define yylen pascal_yylen
+#define yydefred pascal_yydefred
+#define yydgoto pascal_yydgoto
+#define yysindex pascal_yysindex
+#define yyrindex pascal_yyrindex
+#define yygindex pascal_yygindex
+#define yytable pascal_yytable
+#define yycheck pascal_yycheck
+
+#ifndef YYDEBUG
+#define YYDEBUG 1 /* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void
+yyerror (char *);
+
+static char * uptok (char *, int);
+%}
+
+/* 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 (char *, int, int, YYSTYPE *);
+
+static struct type *current_type;
+
+static void push_current_type (void);
+static void pop_current_type (void);
+static int search_field;
+%}
+
+%type <voidval> exp exp1 type_exp start normal_start variable qualified_name
+%type <tval> type typebase
+/* %type <bval> block */
+
+/* Fancy type parsing. */
+%type <tval> ptype
+
+%token <typed_val_int> INT
+%token <typed_val_float> 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 <sval> STRING
+%token <sval> FIELDNAME
+%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
+%token <tsym> TYPENAME
+%type <sval> name
+%type <ssym> name_not_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 <ssym> NAME_OR_INT
+
+%token STRUCT CLASS SIZEOF COLONCOLON
+%token ERROR
+
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+
+%token <voidval> VARIABLE
+
+
+/* Object pascal */
+%token THIS
+%token <lval> TRUEKEYWORD FALSEKEYWORD
+
+%left ','
+%left ABOVE_COMMA
+%right ASSIGN
+%left NOT
+%left OR
+%left XOR
+%left ANDAND
+%left '=' NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH DIV MOD
+%left '@'
+%left '+' '-'
+%left '*' '/'
+%right UNARY INCREMENT DECREMENT
+%right ARROW '.' '[' '('
+%left '^'
+%token <ssym> BLOCKNAME
+%type <bval> block
+%left COLONCOLON
+
+
+%%
+
+start : { current_type = NULL;
+ search_field = 0;
+ }
+ normal_start {}
+ ;
+
+normal_start :
+ exp1
+ | type_exp
+ ;
+
+type_exp: type
+ { write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);
+ current_type = $1; } ;
+
+/* 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);
+ if (current_type)
+ current_type = TYPE_TARGET_TYPE (current_type); }
+ ;
+
+exp : '@' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_ADDR);
+ if (current_type)
+ current_type = TYPE_POINTER_TYPE (current_type); }
+ ;
+
+exp : '-' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_NEG); }
+ ;
+
+exp : NOT exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+ ;
+
+exp : INCREMENT '(' exp ')' %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+ ;
+
+exp : DECREMENT '(' exp ')' %prec UNARY
+ { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+ ;
+
+exp : exp '.' { search_field = 1; }
+ FIELDNAME
+ /* name */
+ { write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($4);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ search_field = 0;
+ if (current_type)
+ { while (TYPE_CODE (current_type) == TYPE_CODE_PTR)
+ current_type = TYPE_TARGET_TYPE (current_type);
+ current_type = lookup_struct_elt_type (
+ current_type, $4.ptr, 0); };
+ } ;
+exp : exp '['
+ /* We need to save the current_type value */
+ { char *arrayname;
+ int arrayfieldindex;
+ arrayfieldindex = is_pascal_string_type (
+ current_type, NULL, NULL,
+ NULL, NULL, &arrayname);
+ if (arrayfieldindex)
+ {
+ struct stoken stringsval;
+ stringsval.ptr = alloca (strlen (arrayname) + 1);
+ stringsval.length = strlen (arrayname);
+ strcpy (stringsval.ptr, arrayname);
+ current_type = TYPE_FIELD_TYPE (current_type,
+ arrayfieldindex - 1);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (stringsval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ }
+ push_current_type (); }
+ exp1 ']'
+ { pop_current_type ();
+ write_exp_elt_opcode (BINOP_SUBSCRIPT);
+ if (current_type)
+ current_type = TYPE_TARGET_TYPE (current_type); }
+ ;
+
+exp : exp '('
+ /* This is to save the value of arglist_len
+ being accumulated by an outer function call. */
+ { push_current_type ();
+ start_arglist (); }
+ arglist ')' %prec ARROW
+ { write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL);
+ pop_current_type (); }
+ ;
+
+arglist :
+ | exp
+ { arglist_len = 1; }
+ | arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+exp : type '(' exp ')' %prec UNARY
+ { if (current_type)
+ {
+ /* Allow automatic dereference of classes. */
+ if ((TYPE_CODE (current_type) == TYPE_CODE_PTR)
+ && (TYPE_CODE (TYPE_TARGET_TYPE (current_type)) == TYPE_CODE_CLASS)
+ && (TYPE_CODE ($1) == TYPE_CODE_CLASS))
+ write_exp_elt_opcode (UNOP_IND);
+ }
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type ($1);
+ write_exp_elt_opcode (UNOP_CAST);
+ current_type = $1; }
+ ;
+
+exp : '(' exp1 ')'
+ { }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+
+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 LSH exp
+ { write_exp_elt_opcode (BINOP_LSH); }
+ ;
+
+exp : exp RSH exp
+ { write_exp_elt_opcode (BINOP_RSH); }
+ ;
+
+exp : exp '=' 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 ANDAND exp
+ { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+ ;
+
+exp : exp XOR exp
+ { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+ ;
+
+exp : exp OR exp
+ { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+ ;
+
+exp : exp ASSIGN exp
+ { write_exp_elt_opcode (BINOP_ASSIGN); }
+ ;
+
+exp : TRUEKEYWORD
+ { write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_BOOL); }
+ ;
+
+exp : FALSEKEYWORD
+ { 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 ($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); }
+ ;
+
+/* Object pascal */
+exp : THIS
+ {
+ struct value * this_val;
+ struct type * this_type;
+ write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS);
+ /* we need type of this */
+ this_val = value_of_this (0);
+ if (this_val)
+ this_type = this_val->type;
+ else
+ this_type = NULL;
+ if (this_type)
+ {
+ if (TYPE_CODE (this_type) == TYPE_CODE_PTR)
+ {
+ this_type = TYPE_TARGET_TYPE (this_type);
+ write_exp_elt_opcode (UNOP_IND);
+ }
+ }
+
+ current_type = this_type;
+ }
+ ;
+
+/* end of object pascal. */
+
+block : BLOCKNAME
+ {
+ if ($1.sym != 0)
+ $$ = SYMBOL_BLOCK_VALUE ($1.sym);
+ else
+ {
+ struct symtab *tem =
+ lookup_symtab (copy_name ($1.stoken));
+ if (tem)
+ $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), STATIC_BLOCK);
+ else
+ error ("No file or function \"%s\".",
+ copy_name ($1.stoken));
+ }
+ }
+ ;
+
+block : block COLONCOLON name
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1,
+ VAR_DOMAIN, (int *) NULL,
+ (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_DOMAIN, (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);
+ }
+ ;
+
+variable: qualified_name
+ | COLONCOLON name
+ {
+ char *name = copy_name ($2);
+ struct symbol *sym;
+ struct minimal_symbol *msymbol;
+
+ sym =
+ lookup_symbol (name, (const struct block *) NULL,
+ VAR_DOMAIN, (int *) NULL,
+ (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);
+ current_type = sym->type; }
+ else if ($1.is_a_field_of_this)
+ {
+ struct value * this_val;
+ struct type * this_type;
+ /* Object pascal: 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);
+ /* we need type of this */
+ this_val = value_of_this (0);
+ if (this_val)
+ this_type = this_val->type;
+ else
+ this_type = NULL;
+ if (this_type)
+ current_type = lookup_struct_elt_type (
+ this_type,
+ copy_name ($1.stoken), 0);
+ else
+ current_type = NULL;
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ char *arg = copy_name ($1.stoken);
+
+ msymbol =
+ lookup_minimal_symbol (arg, NULL, NULL);
+ if (msymbol != NULL)
+ {
+ write_exp_msymbol (msymbol,
+ 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
+ ;
+
+/* 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 */
+ : '^' typebase
+ { $$ = lookup_pointer_type ($2); }
+ | TYPENAME
+ { $$ = $1.type; }
+ | STRUCT name
+ { $$ = lookup_struct (copy_name ($2),
+ expression_context_block); }
+ | CLASS name
+ { $$ = lookup_struct (copy_name ($2),
+ 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. */
+ ;
+
+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)
+ char *p;
+ int len;
+ int parsed_float;
+ YYSTYPE *putithere;
+{
+ /* FIXME: Shouldn't these be unsigned? We don't deal with negative values
+ here, and we do kind of silly things like cast to unsigned. */
+ LONGEST n = 0;
+ LONGEST prevn = 0;
+ ULONGEST un;
+
+ int i = 0;
+ int c;
+ int base = input_radix;
+ int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
+ int long_p = 0;
+
+ /* We have found a "L" or "U" suffix. */
+ int found_suffix = 0;
+
+ ULONGEST 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. */
+ char c;
+ int num = 0; /* number of tokens scanned by scanf */
+ char saved_char = p[len];
+
+ p[len] = 0; /* null-terminate the token */
+ if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
+ num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval,&c);
+ else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+ num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval,&c);
+ else
+ {
+#ifdef SCANF_HAS_LONG_DOUBLE
+ num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval,&c);
+#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;
+ num = sscanf (p, "%lg%c", &temp,&c);
+ putithere->typed_val_float.dval = temp;
+#endif
+ }
+ p[len] = saved_char; /* restore the input stream */
+ if (num != 1) /* check scanf found ONLY a float ... */
+ return ERROR;
+ /* 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 && (ULONGEST) prevn >= (ULONGEST) 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 = (ULONGEST)n >> 2;
+ if (long_p == 0
+ && (un >> (TARGET_INT_BIT - 2)) == 0)
+ {
+ high_bit = ((ULONGEST)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 = ((ULONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ int shift;
+ if (sizeof (ULONGEST) * HOST_CHAR_BIT < TARGET_LONG_LONG_BIT)
+ /* A long long does not fit in a LONGEST. */
+ shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
+ else
+ shift = (TARGET_LONG_LONG_BIT - 1);
+ high_bit = (ULONGEST) 1 << shift;
+ 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 type_push
+{
+ struct type *stored;
+ struct type_push *next;
+};
+
+static struct type_push *tp_top = NULL;
+
+static void
+push_current_type (void)
+{
+ struct type_push *tpnew;
+ tpnew = (struct type_push *) malloc (sizeof (struct type_push));
+ tpnew->next = tp_top;
+ tpnew->stored = current_type;
+ current_type = NULL;
+ tp_top = tpnew;
+}
+
+static void
+pop_current_type (void)
+{
+ struct type_push *tp = tp_top;
+ if (tp)
+ {
+ current_type = tp->stored;
+ tp_top = tp->next;
+ xfree (tp);
+ }
+}
+
+struct token
+{
+ char *operator;
+ int token;
+ enum exp_opcode opcode;
+};
+
+static const struct token tokentab3[] =
+ {
+ {"shr", RSH, BINOP_END},
+ {"shl", LSH, BINOP_END},
+ {"and", ANDAND, BINOP_END},
+ {"div", DIV, BINOP_END},
+ {"not", NOT, BINOP_END},
+ {"mod", MOD, BINOP_END},
+ {"inc", INCREMENT, BINOP_END},
+ {"dec", DECREMENT, BINOP_END},
+ {"xor", XOR, BINOP_END}
+ };
+
+static const struct token tokentab2[] =
+ {
+ {"or", OR, BINOP_END},
+ {"<>", NOTEQUAL, BINOP_END},
+ {"<=", LEQ, BINOP_END},
+ {">=", GEQ, BINOP_END},
+ {":=", ASSIGN, BINOP_END},
+ {"::", COLONCOLON, BINOP_END} };
+
+/* Allocate uppercased var */
+/* make an uppercased copy of tokstart */
+static char * uptok (tokstart, namelen)
+ char *tokstart;
+ int namelen;
+{
+ int i;
+ char *uptokstart = (char *)malloc(namelen+1);
+ for (i = 0;i <= namelen;i++)
+ {
+ if ((tokstart[i]>='a' && tokstart[i]<='z'))
+ uptokstart[i] = tokstart[i]-('a'-'A');
+ else
+ uptokstart[i] = tokstart[i];
+ }
+ uptokstart[namelen]='\0';
+ return uptokstart;
+}
+/* Read one token, getting characters through lexptr. */
+
+
+static int
+yylex ()
+{
+ int c;
+ int namelen;
+ unsigned int i;
+ char *tokstart;
+ char *uptokstart;
+ char *tokptr;
+ char *p;
+ int explen, tempbufindex;
+ static char *tempbuf;
+ static int tempbufsize;
+
+ retry:
+
+ prev_lexptr = lexptr;
+
+ tokstart = lexptr;
+ explen = strlen (lexptr);
+ /* See if it is a special token of length 3. */
+ if (explen > 2)
+ for (i = 0; i < sizeof (tokentab3) / sizeof (tokentab3[0]); i++)
+ if (strncasecmp (tokstart, tokentab3[i].operator, 3) == 0
+ && (!isalpha (tokentab3[i].operator[0]) || explen == 3
+ || (!isalpha (tokstart[3]) && !isdigit (tokstart[3]) && tokstart[3] != '_')))
+ {
+ lexptr += 3;
+ yylval.opcode = tokentab3[i].opcode;
+ return tokentab3[i].token;
+ }
+
+ /* See if it is a special token of length 2. */
+ if (explen > 1)
+ for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++)
+ if (strncasecmp (tokstart, tokentab2[i].operator, 2) == 0
+ && (!isalpha (tokentab2[i].operator[0]) || explen == 2
+ || (!isalpha (tokstart[2]) && !isdigit (tokstart[2]) && tokstart[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 object pascal
+ 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++;
+ uptokstart = uptok(tokstart,namelen);
+ 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;
+ 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 '}':
+ 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 == '<');)
+ {
+ /* Template parameter lists are part of the name.
+ FIXME: This mishandles `print $a<4&&$a>3'. */
+ if (c == '<')
+ {
+ int i = namelen;
+ int nesting_level = 1;
+ while (tokstart[++i])
+ {
+ if (tokstart[i] == '<')
+ nesting_level++;
+ else if (tokstart[i] == '>')
+ {
+ if (--nesting_level == 0)
+ break;
+ }
+ }
+ if (tokstart[i] == '>')
+ namelen = i;
+ else
+ break;
+ }
+
+ /* do NOT uppercase internals because of registers !!! */
+ c = tokstart[++namelen];
+ }
+
+ uptokstart = uptok(tokstart,namelen);
+
+ /* The token "if" terminates the expression and is NOT
+ removed from the input stream. */
+ if (namelen == 2 && uptokstart[0] == 'I' && uptokstart[1] == 'F')
+ {
+ return 0;
+ }
+
+ lexptr += namelen;
+
+ tryname:
+
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
+ {
+ case 6:
+ if (DEPRECATED_STREQ (uptokstart, "OBJECT"))
+ return CLASS;
+ if (DEPRECATED_STREQ (uptokstart, "RECORD"))
+ return STRUCT;
+ if (DEPRECATED_STREQ (uptokstart, "SIZEOF"))
+ return SIZEOF;
+ break;
+ case 5:
+ if (DEPRECATED_STREQ (uptokstart, "CLASS"))
+ return CLASS;
+ if (DEPRECATED_STREQ (uptokstart, "FALSE"))
+ {
+ yylval.lval = 0;
+ return FALSEKEYWORD;
+ }
+ break;
+ case 4:
+ if (DEPRECATED_STREQ (uptokstart, "TRUE"))
+ {
+ yylval.lval = 1;
+ return TRUEKEYWORD;
+ }
+ if (DEPRECATED_STREQ (uptokstart, "SELF"))
+ {
+ /* here we search for 'this' like
+ inserted in FPC stabs debug info */
+ static const char this_name[] = "this";
+
+ if (lookup_symbol (this_name, expression_context_block,
+ VAR_DOMAIN, (int *) NULL,
+ (struct symtab **) NULL))
+ return THIS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ yylval.sval.ptr = tokstart;
+ yylval.sval.length = namelen;
+
+ if (*tokstart == '$')
+ {
+ /* $ is the normal prefix for pascal hexadecimal values
+ but this conflicts with the GDB use for debugger variables
+ so in expression to enter hexadecimal values
+ we still need to use C syntax with 0xff */
+ 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 is_a_field = 0;
+ int hextype;
+
+
+ if (search_field && current_type)
+ is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL);
+ if (is_a_field)
+ sym = NULL;
+ else
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ &is_a_field_of_this,
+ (struct symtab **) NULL);
+ /* second chance uppercased (as Free Pascal does). */
+ if (!sym && !is_a_field_of_this && !is_a_field)
+ {
+ for (i = 0; i <= namelen; i++)
+ {
+ if ((tmp[i] >= 'a' && tmp[i] <= 'z'))
+ tmp[i] -= ('a'-'A');
+ }
+ if (search_field && current_type)
+ is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL);
+ if (is_a_field)
+ sym = NULL;
+ else
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ &is_a_field_of_this,
+ (struct symtab **) NULL);
+ if (sym || is_a_field_of_this || is_a_field)
+ for (i = 0; i <= namelen; i++)
+ {
+ if ((tokstart[i] >= 'a' && tokstart[i] <= 'z'))
+ tokstart[i] -= ('a'-'A');
+ }
+ }
+ /* Third chance Capitalized (as GPC does). */
+ if (!sym && !is_a_field_of_this && !is_a_field)
+ {
+ for (i = 0; i <= namelen; i++)
+ {
+ if (i == 0)
+ {
+ if ((tmp[i] >= 'a' && tmp[i] <= 'z'))
+ tmp[i] -= ('a'-'A');
+ }
+ else
+ if ((tmp[i] >= 'A' && tmp[i] <= 'Z'))
+ tmp[i] -= ('A'-'a');
+ }
+ if (search_field && current_type)
+ is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL);
+ if (is_a_field)
+ sym = NULL;
+ else
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_DOMAIN,
+ &is_a_field_of_this,
+ (struct symtab **) NULL);
+ if (sym || is_a_field_of_this || is_a_field)
+ for (i = 0; i <= namelen; i++)
+ {
+ if (i == 0)
+ {
+ if ((tokstart[i] >= 'a' && tokstart[i] <= 'z'))
+ tokstart[i] -= ('a'-'A');
+ }
+ else
+ if ((tokstart[i] >= 'A' && tokstart[i] <= 'Z'))
+ tokstart[i] -= ('A'-'a');
+ }
+ }
+
+ if (is_a_field)
+ {
+ tempbuf = (char *) realloc (tempbuf, namelen + 1);
+ strncpy (tempbuf, tokstart, namelen); tempbuf [namelen] = 0;
+ yylval.sval.ptr = tempbuf;
+ yylval.sval.length = namelen;
+ return FIELDNAME;
+ }
+ /* 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_DOMAIN, (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;
+ }
+ }
+
+ free(uptokstart);
+ /* Any other kind of symbol */
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ return NAME;
+ }
+}
+
+void
+yyerror (msg)
+ char *msg;
+{
+ if (prev_lexptr)
+ lexptr = prev_lexptr;
+
+ error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+}
diff --git a/contrib/gdb/gdb/p-lang.c b/contrib/gdb/gdb/p-lang.c
new file mode 100644
index 0000000..a402532
--- /dev/null
+++ b/contrib/gdb/gdb/p-lang.c
@@ -0,0 +1,485 @@
+/* Pascal language support routines for GDB, the GNU debugger.
+ Copyright 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 derived from c-lang.c */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "p-lang.h"
+#include "valprint.h"
+#include "value.h"
+#include <ctype.h>
+
+extern void _initialize_pascal_language (void);
+
+
+/* Determines if type TYPE is a pascal string type.
+ Returns 1 if the type is a known pascal type
+ This function is used by p-valprint.c code to allow better string display.
+ If it is a pascal string type, then it also sets info needed
+ to get the length and the data of the string
+ length_pos, length_size and string_pos are given in bytes.
+ char_size gives the element size in bytes.
+ FIXME: if the position or the size of these fields
+ are not multiple of TARGET_CHAR_BIT then the results are wrong
+ but this does not happen for Free Pascal nor for GPC. */
+int
+is_pascal_string_type (struct type *type,int *length_pos,
+ int *length_size, int *string_pos, int *char_size,
+ char **arrayname)
+{
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ /* Old Borland type pascal strings from Free Pascal Compiler. */
+ /* Two fields: length and st. */
+ if (TYPE_NFIELDS (type) == 2
+ && strcmp (TYPE_FIELDS (type)[0].name, "length") == 0
+ && strcmp (TYPE_FIELDS (type)[1].name, "st") == 0)
+ {
+ if (length_pos)
+ *length_pos = TYPE_FIELD_BITPOS (type, 0) / TARGET_CHAR_BIT;
+ if (length_size)
+ *length_size = TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0));
+ if (string_pos)
+ *string_pos = TYPE_FIELD_BITPOS (type, 1) / TARGET_CHAR_BIT;
+ if (char_size)
+ *char_size = 1;
+ if (arrayname)
+ *arrayname = TYPE_FIELDS (type)[1].name;
+ return 2;
+ };
+ /* GNU pascal strings. */
+ /* Three fields: Capacity, length and schema$ or _p_schema. */
+ if (TYPE_NFIELDS (type) == 3
+ && strcmp (TYPE_FIELDS (type)[0].name, "Capacity") == 0
+ && strcmp (TYPE_FIELDS (type)[1].name, "length") == 0)
+ {
+ if (length_pos)
+ *length_pos = TYPE_FIELD_BITPOS (type, 1) / TARGET_CHAR_BIT;
+ if (length_size)
+ *length_size = TYPE_LENGTH (TYPE_FIELD_TYPE (type, 1));
+ if (string_pos)
+ *string_pos = TYPE_FIELD_BITPOS (type, 2) / TARGET_CHAR_BIT;
+ /* FIXME: how can I detect wide chars in GPC ?? */
+ if (char_size)
+ *char_size = 1;
+ if (arrayname)
+ *arrayname = TYPE_FIELDS (type)[2].name;
+ return 3;
+ };
+ }
+ return 0;
+}
+
+static void pascal_one_char (int, struct ui_file *, int *);
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string.
+ In_quotes is reset to 0 if a char is written with #4 notation */
+
+static void
+pascal_one_char (int c, struct ui_file *stream, int *in_quotes)
+{
+
+ c &= 0xFF; /* Avoid sign bit follies */
+
+ if ((c == '\'') || (PRINT_LITERAL_FORM (c)))
+ {
+ if (!(*in_quotes))
+ fputs_filtered ("'", stream);
+ *in_quotes = 1;
+ if (c == '\'')
+ {
+ fputs_filtered ("''", stream);
+ }
+ else
+ fprintf_filtered (stream, "%c", c);
+ }
+ else
+ {
+ if (*in_quotes)
+ fputs_filtered ("'", stream);
+ *in_quotes = 0;
+ fprintf_filtered (stream, "#%d", (unsigned int) c);
+ }
+}
+
+static void pascal_emit_char (int c, struct ui_file *stream, int quoter);
+
+/* Print the character C on STREAM as part of the contents of a literal
+ string whose delimiter is QUOTER. Note that that format for printing
+ characters and strings is language specific. */
+
+static void
+pascal_emit_char (int c, struct ui_file *stream, int quoter)
+{
+ int in_quotes = 0;
+ pascal_one_char (c, stream, &in_quotes);
+ if (in_quotes)
+ fputs_filtered ("'", stream);
+}
+
+void
+pascal_printchar (int c, struct ui_file *stream)
+{
+ int in_quotes = 0;
+ pascal_one_char (c, stream, &in_quotes);
+ if (in_quotes)
+ 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
+pascal_printstr (struct ui_file *stream, char *string, unsigned int length,
+ int width, int force_ellipses)
+{
+ unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+
+ /* If the string was not truncated due to `set print elements', and
+ the last byte of it is a null, we don't print that, in traditional C
+ style. */
+ if ((!force_ellipses) && length > 0 && string[length - 1] == '\0')
+ length--;
+
+ if (length == 0)
+ {
+ fputs_filtered ("''", stream);
+ return;
+ }
+
+ for (i = 0; i < length && things_printed < 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;
+ }
+ pascal_printchar (string[i], stream);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ need_comma = 1;
+ }
+ else
+ {
+ int c = string[i];
+ if ((!in_quotes) && (PRINT_LITERAL_FORM (c)))
+ {
+ if (inspect_it)
+ fputs_filtered ("\\'", stream);
+ else
+ fputs_filtered ("'", stream);
+ in_quotes = 1;
+ }
+ pascal_one_char (c, stream, &in_quotes);
+ ++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 Pascal 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 */
+
+/* Note there might be some discussion about the choosen correspondance
+ because it mainly reflects Free Pascal Compiler setup for now PM */
+
+
+struct type *
+pascal_create_fundamental_type (struct objfile *objfile, int typeid)
+{
+ 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 "<?type?>". 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, "<?type?>", objfile);
+ warning ("internal error: no Pascal 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_CHAR,
+ 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, "shortint", objfile);
+ break;
+ case FT_UNSIGNED_CHAR:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "byte", objfile);
+ break;
+ case FT_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "integer", objfile);
+ break;
+ case FT_SIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ 0, "integer", objfile); /* FIXME-fnf */
+ break;
+ case FT_UNSIGNED_SHORT:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "word", objfile);
+ break;
+ case FT_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "longint", objfile);
+ break;
+ case FT_SIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "longint", objfile); /* FIXME -fnf */
+ break;
+ case FT_UNSIGNED_INTEGER:
+ type = init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, "cardinal", 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, "extended", objfile);
+ break;
+ }
+ return (type);
+}
+
+
+/* Table mapping opcodes into strings for printing operators
+ and precedences of the operators. */
+
+const struct op_print pascal_op_print_tab[] =
+{
+ {",", BINOP_COMMA, PREC_COMMA, 0},
+ {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"or", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+ {"xor", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+ {"and", 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},
+ {"shr", BINOP_RSH, PREC_SHIFT, 0},
+ {"shl", 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},
+ {"div", BINOP_INTDIV, PREC_MUL, 0},
+ {"mod", BINOP_REM, PREC_MUL, 0},
+ {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+ {"-", UNOP_NEG, PREC_PREFIX, 0},
+ {"not", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+ {"^", UNOP_IND, PREC_SUFFIX, 1},
+ {"@", UNOP_ADDR, PREC_PREFIX, 0},
+ {"sizeof", UNOP_SIZEOF, PREC_PREFIX, 0},
+ {NULL, 0, 0, 0}
+};
+
+struct type **const (pascal_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 pascal_language_defn =
+{
+ "pascal", /* Language name */
+ language_pascal,
+ pascal_builtin_types,
+ range_check_on,
+ type_check_on,
+ case_sensitive_on,
+ &exp_descriptor_standard,
+ pascal_parse,
+ pascal_error,
+ pascal_printchar, /* Print a character constant */
+ pascal_printstr, /* Function to print string constant */
+ pascal_emit_char, /* Print a single char */
+ pascal_create_fundamental_type, /* Create fundamental type in this language */
+ pascal_print_type, /* Print a type using appropriate syntax */
+ pascal_val_print, /* Print a value using appropriate syntax */
+ pascal_value_print, /* Print a top-level value */
+ NULL, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "%", "b", ""}, /* Binary format info */
+ {"0%lo", "0", "o", ""}, /* Octal format info */
+ {"%ld", "", "d", ""}, /* Decimal format info */
+ {"$%lx", "$", "x", ""}, /* Hex format info */
+ pascal_op_print_tab, /* expression operators for printing */
+ 1, /* c-style arrays */
+ 0, /* String lower bound */
+ &builtin_type_char, /* Type of string elements */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+void
+_initialize_pascal_language (void)
+{
+ add_language (&pascal_language_defn);
+}
diff --git a/contrib/gdb/gdb/p-lang.h b/contrib/gdb/gdb/p-lang.h
new file mode 100644
index 0000000..39eb043
--- /dev/null
+++ b/contrib/gdb/gdb/p-lang.h
@@ -0,0 +1,76 @@
+/* Pascal language support definitions for GDB, the GNU debugger.
+ Copyright 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 derived from c-lang.h */
+
+struct value;
+
+extern int pascal_parse (void); /* Defined in p-exp.y */
+
+extern void pascal_error (char *); /* Defined in p-exp.y */
+
+/* Defined in p-typeprint.c */
+extern void pascal_print_type (struct type *, char *, struct ui_file *, int, int);
+
+extern int pascal_val_print (struct type *, char *, int, CORE_ADDR, struct ui_file *, int, int,
+ int, enum val_prettyprint);
+
+extern int pascal_value_print (struct value *, struct ui_file *, int, enum val_prettyprint);
+
+extern void pascal_type_print_method_args (char *, char *,
+ struct ui_file *);
+
+/* These are in p-lang.c: */
+
+extern int
+ is_pascal_string_type (struct type *, int *, int *, int *, int *, char **);
+
+extern void pascal_printchar (int, struct ui_file *);
+
+extern void pascal_printstr (struct ui_file *, char *, unsigned int, int, int);
+
+extern struct type *pascal_create_fundamental_type (struct objfile *, int);
+
+extern struct type **const (pascal_builtin_types[]);
+
+/* These are in p-typeprint.c: */
+
+extern void
+ pascal_type_print_base (struct type *, struct ui_file *, int, int);
+
+extern void
+ pascal_type_print_varspec_prefix (struct type *, struct ui_file *, int, int);
+
+/* These are in cp-valprint.c */
+
+extern int vtblprint; /* Controls printing of vtbl's */
+
+extern int static_field_print;
+
+extern void pascal_object_print_class_member (char *, struct type *, struct ui_file *, char *);
+
+extern void pascal_object_print_class_method (char *, struct type *, struct ui_file *);
+
+extern void pascal_object_print_value_fields (struct type *, char *, CORE_ADDR,
+ struct ui_file *, int, int, enum val_prettyprint,
+ struct type **, int);
+
+extern int pascal_object_is_vtbl_ptr_type (struct type *);
+
+extern int pascal_object_is_vtbl_member (struct type *);
diff --git a/contrib/gdb/gdb/p-typeprint.c b/contrib/gdb/gdb/p-typeprint.c
new file mode 100644
index 0000000..a8908b1
--- /dev/null
+++ b/contrib/gdb/gdb/p-typeprint.c
@@ -0,0 +1,817 @@
+/* Support for printing Pascal types for GDB, the GNU debugger.
+ Copyright 2000, 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 derived from p-typeprint.c */
+
+#include "defs.h"
+#include "gdb_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 "language.h"
+#include "p-lang.h"
+#include "typeprint.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+#include <ctype.h>
+
+static void pascal_type_print_varspec_suffix (struct type *, struct ui_file *, int, int, int);
+
+static void pascal_type_print_derivation_info (struct ui_file *, struct type *);
+
+void pascal_type_print_varspec_prefix (struct type *, struct ui_file *, int, int);
+
+
+/* LEVEL is the depth to indent lines by. */
+
+void
+pascal_print_type (struct type *type, char *varstring, struct ui_file *stream,
+ int show, int level)
+{
+ enum type_code code;
+ int demangled_args;
+
+ code = TYPE_CODE (type);
+
+ if (show > 0)
+ CHECK_TYPEDEF (type);
+
+ if ((code == TYPE_CODE_FUNC ||
+ code == TYPE_CODE_METHOD))
+ {
+ pascal_type_print_varspec_prefix (type, stream, show, 0);
+ }
+ /* first the name */
+ fputs_filtered (varstring, stream);
+
+ if ((varstring != NULL && *varstring != '\0') &&
+ !(code == TYPE_CODE_FUNC ||
+ code == TYPE_CODE_METHOD))
+ {
+ fputs_filtered (" : ", stream);
+ }
+
+ if (!(code == TYPE_CODE_FUNC ||
+ code == TYPE_CODE_METHOD))
+ {
+ pascal_type_print_varspec_prefix (type, stream, show, 0);
+ }
+
+ pascal_type_print_base (type, stream, show, level);
+ /* For demangled function names, we have the arglist as part of the name,
+ so don't print an additional pair of ()'s */
+
+ demangled_args = varstring ? strchr (varstring, '(') != NULL : 0;
+ pascal_type_print_varspec_suffix (type, stream, show, 0, demangled_args);
+
+}
+
+/* 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
+pascal_type_print_derivation_info (struct ui_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 the Pascal method arguments ARGS to the file STREAM. */
+
+void
+pascal_type_print_method_args (char *physname, char *methodname,
+ struct ui_file *stream)
+{
+ int is_constructor = DEPRECATED_STREQN (physname, "__ct__", 6);
+ int is_destructor = DEPRECATED_STREQN (physname, "__dt__", 6);
+
+ if (is_constructor || is_destructor)
+ {
+ physname += 6;
+ }
+
+ fputs_filtered (methodname, stream);
+
+ if (physname && (*physname != 0))
+ {
+ int i = 0;
+ int len = 0;
+ char storec;
+ char *argname;
+ fputs_filtered (" (", stream);
+ /* we must demangle this */
+ while (isdigit (physname[0]))
+ {
+ while (isdigit (physname[len]))
+ {
+ len++;
+ }
+ i = strtol (physname, &argname, 0);
+ physname += len;
+ storec = physname[i];
+ physname[i] = 0;
+ fputs_filtered (physname, stream);
+ physname[i] = storec;
+ physname += i;
+ if (physname[0] != 0)
+ {
+ fputs_filtered (", ", stream);
+ }
+ }
+ 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
+pascal_type_print_varspec_prefix (struct type *type, struct ui_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:
+ fprintf_filtered (stream, "^");
+ pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ break; /* pointer should be handled normally in pascal */
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ pascal_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
+ pascal_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_filtered (stream, "(");
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, "function ");
+ }
+ else
+ {
+ fprintf_filtered (stream, "procedure ");
+ }
+
+ if (passed_a_ptr)
+ {
+ fprintf_filtered (stream, " ");
+ pascal_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
+ fprintf_filtered (stream, "::");
+ }
+ break;
+
+ case TYPE_CODE_REF:
+ pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fprintf_filtered (stream, "&");
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, "function ");
+ }
+ else
+ {
+ fprintf_filtered (stream, "procedure ");
+ }
+
+ break;
+
+ case TYPE_CODE_ARRAY:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ fprintf_filtered (stream, "array ");
+ 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..%d] ",
+ TYPE_ARRAY_LOWER_BOUND_VALUE (type),
+ TYPE_ARRAY_UPPER_BOUND_VALUE (type)
+ );
+ fprintf_filtered (stream, "of ");
+ 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:
+ case TYPE_CODE_TEMPLATE:
+ /* These types need no prefix. They are listed here so that
+ gcc -Wall will reveal any types that haven't been handled. */
+ break;
+ default:
+ error ("type not handled in pascal_type_print_varspec_prefix()");
+ break;
+ }
+}
+
+static void
+pascal_print_func_args (struct type *type, struct ui_file *stream)
+{
+ int i, len = TYPE_NFIELDS (type);
+ if (len)
+ {
+ fprintf_filtered (stream, "(");
+ }
+ for (i = 0; i < len; i++)
+ {
+ if (i > 0)
+ {
+ fputs_filtered (", ", stream);
+ wrap_here (" ");
+ }
+ /* can we find if it is a var parameter ??
+ if ( TYPE_FIELD(type, i) == )
+ {
+ fprintf_filtered (stream, "var ");
+ } */
+ pascal_print_type (TYPE_FIELD_TYPE (type, i), "" /* TYPE_FIELD_NAME seems invalid ! */
+ ,stream, -1, 0);
+ }
+ if (len)
+ {
+ fprintf_filtered (stream, ")");
+ }
+}
+
+/* Print any array sizes, function arguments or close parentheses
+ needed after the variable name (to describe its type).
+ Args work like pascal_type_print_varspec_prefix. */
+
+static void
+pascal_type_print_varspec_suffix (struct type *type, struct ui_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, ")");
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
+ break;
+
+ case TYPE_CODE_METHOD:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ pascal_type_print_method_args ("",
+ "",
+ stream);
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, " : ");
+ pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0);
+ pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr, 0);
+ }
+ break;
+
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ pascal_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)
+ pascal_print_func_args (type, stream);
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, " : ");
+ pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0);
+ pascal_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:
+ case TYPE_CODE_TEMPLATE:
+ /* These types do not need a suffix. They are listed so that
+ gcc -Wall will report types that may not have been considered. */
+ break;
+ default:
+ error ("type not handled in pascal_type_print_varspec_suffix()");
+ 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
+pascal_type_print_base (struct type *type, struct ui_file *stream, int show,
+ int level)
+{
+ int i;
+ int len;
+ int lastval;
+ enum
+ {
+ s_none, s_public, s_private, s_protected
+ }
+ section_type;
+ QUIT;
+
+ wrap_here (" ");
+ if (type == NULL)
+ {
+ fputs_filtered ("<type unknown>", stream);
+ return;
+ }
+
+ /* void pointer */
+ if ((TYPE_CODE (type) == TYPE_CODE_PTR) && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID))
+ {
+ fputs_filtered (TYPE_NAME (type) ? TYPE_NAME (type) : "pointer",
+ 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;
+ }
+
+ CHECK_TYPEDEF (type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_TYPEDEF:
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_REF:
+ /* case TYPE_CODE_FUNC:
+ case TYPE_CODE_METHOD: */
+ pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_ARRAY:
+ /* pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); */
+ pascal_print_type (TYPE_TARGET_TYPE (type), NULL, stream, 0, 0);
+ break;
+
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_METHOD:
+ /*
+ pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ only after args !! */
+ break;
+ case TYPE_CODE_STRUCT:
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ fputs_filtered (" = ", stream);
+ }
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ fprintf_filtered (stream, "class ");
+ }
+ else
+ {
+ fprintf_filtered (stream, "record ");
+ }
+ goto struct_union;
+
+ case TYPE_CODE_UNION:
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ fputs_filtered (" = ", stream);
+ }
+ fprintf_filtered (stream, "case <?> of ");
+
+ struct_union:
+ 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)
+ {
+ pascal_type_print_derivation_info (stream, type);
+
+ fprintf_filtered (stream, "\n");
+ if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+ {
+ if (TYPE_STUB (type))
+ fprintfi_filtered (level + 4, stream, "<incomplete type>\n");
+ else
+ fprintfi_filtered (level + 4, stream, "<no data fields>\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 (DEPRECATED_STREQN (TYPE_FIELD_NAME (type, i), "_vptr", 5)
+ && is_cplus_marker ((TYPE_FIELD_NAME (type, i))[5]))
+ continue;
+
+ /* If this is a pascal object or class we can print the
+ various 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 ");
+ }
+ pascal_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");
+
+ /* Pbject pascal: 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);
+ /* this is GNU C++ specific
+ how can we know constructor/destructor?
+ It might work for GNU pascal */
+ for (j = 0; j < len2; j++)
+ {
+ char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
+
+ int is_constructor = DEPRECATED_STREQN (physname, "__ct__", 6);
+ int is_destructor = DEPRECATED_STREQN (physname, "__dt__", 6);
+
+ 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_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_filtered (stream, "<undefined type> %s;\n",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+ break;
+ }
+
+ if (is_constructor)
+ {
+ fprintf_filtered (stream, "constructor ");
+ }
+ else if (is_destructor)
+ {
+ fprintf_filtered (stream, "destructor ");
+ }
+ else if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) != 0 &&
+ TYPE_CODE (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j))) != TYPE_CODE_VOID)
+ {
+ fprintf_filtered (stream, "function ");
+ }
+ else
+ {
+ fprintf_filtered (stream, "procedure ");
+ }
+ /* this does not work, no idea why !! */
+
+ pascal_type_print_method_args (physname,
+ method_name,
+ stream);
+
+ if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) != 0 &&
+ TYPE_CODE (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j))) != TYPE_CODE_VOID)
+ {
+ fputs_filtered (" : ", stream);
+ type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
+ "", stream, -1);
+ }
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ fprintf_filtered (stream, "; virtual");
+
+ fprintf_filtered (stream, ";\n");
+ }
+ }
+ fprintfi_filtered (level, stream, "end");
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ if (TYPE_TAG_NAME (type) != NULL)
+ {
+ fputs_filtered (TYPE_TAG_NAME (type), stream);
+ if (show > 0)
+ fputs_filtered (" ", stream);
+ }
+ /* enum is just defined by
+ type enume_name = (enum_member1,enum_member2,...) */
+ fprintf_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, "record <unknown>");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<unknown type>");
+ break;
+
+ /* this probably does not work for enums */
+ case TYPE_CODE_RANGE:
+ {
+ struct type *target = TYPE_TARGET_TYPE (type);
+ if (target == NULL)
+ target = builtin_type_long;
+ print_type_scalar (target, TYPE_LOW_BOUND (type), stream);
+ fputs_filtered ("..", stream);
+ print_type_scalar (target, TYPE_HIGH_BOUND (type), stream);
+ }
+ break;
+
+ case TYPE_CODE_SET:
+ fputs_filtered ("set of ", stream);
+ pascal_print_type (TYPE_INDEX_TYPE (type), "", stream,
+ show - 1, level);
+ break;
+
+ case TYPE_CODE_BITSTRING:
+ fputs_filtered ("BitString", stream);
+ break;
+
+ case TYPE_CODE_STRING:
+ fputs_filtered ("String", 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, "<invalid unnamed pascal type code %d>",
+ TYPE_CODE (type));
+ }
+ break;
+ }
+}
diff --git a/contrib/gdb/gdb/p-valprint.c b/contrib/gdb/gdb/p-valprint.c
new file mode 100644
index 0000000..eb92f77
--- /dev/null
+++ b/contrib/gdb/gdb/p-valprint.c
@@ -0,0 +1,1114 @@
+/* Support for printing Pascal values for GDB, the GNU debugger.
+ Copyright 2000, 2001, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 derived from c-valprint.c */
+
+#include "defs.h"
+#include "gdb_obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "typeprint.h"
+#include "language.h"
+#include "target.h"
+#include "annotate.h"
+#include "p-lang.h"
+#include "cp-abi.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
+pascal_val_print (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+ unsigned int i = 0; /* Number of characters printed */
+ unsigned len;
+ struct type *elttype;
+ unsigned eltlen;
+ int length_pos, length_size, string_pos;
+ int char_size;
+ 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)
+ {
+ unsigned int temp_len;
+
+ /* Look for a NULL char. */
+ for (temp_len = 0;
+ (valaddr + embedded_offset)[temp_len]
+ && temp_len < len && temp_len < print_max;
+ temp_len++);
+ len = temp_len;
+ }
+
+ LA_PRINT_STRING (stream, valaddr + embedded_offset, len, 1, 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 (pascal_object_is_vtbl_ptr_type (elttype))
+ {
+ i = 1;
+ fprintf_filtered (stream, "%d vtable entries", len - 1);
+ }
+ else
+ {
+ i = 0;
+ }
+ val_print_array_elements (type, valaddr + embedded_offset, 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 + embedded_offset, type, format, 0, stream);
+ break;
+ }
+ if (vtblprint && pascal_object_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.) */
+ /* Extract the address, assume that it is unsigned. */
+ print_address_demangle (extract_unsigned_integer (valaddr + embedded_offset, TYPE_LENGTH (type)),
+ stream, demangle);
+ break;
+ }
+ elttype = check_typedef (TYPE_TARGET_TYPE (type));
+ if (TYPE_CODE (elttype) == TYPE_CODE_METHOD)
+ {
+ pascal_object_print_class_method (valaddr + embedded_offset, type, stream);
+ }
+ else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
+ {
+ pascal_object_print_class_member (valaddr + embedded_offset,
+ TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
+ stream, "&");
+ }
+ else
+ {
+ addr = unpack_pointer (type, valaddr + embedded_offset);
+ print_unpacked_pointer:
+ 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')
+ {
+ 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)
+ {
+ /* no wide string yet */
+ i = val_print_string (addr, -1, 1, stream);
+ }
+ /* also for pointers to pascal strings */
+ /* Note: this is Free Pascal specific:
+ as GDB does not recognize stabs pascal strings
+ Pascal strings are mapped to records
+ with lowercase names PM */
+ if (is_pascal_string_type (elttype, &length_pos, &length_size,
+ &string_pos, &char_size, NULL)
+ && addr != 0)
+ {
+ ULONGEST string_length;
+ void *buffer;
+ buffer = xmalloc (length_size);
+ read_memory (addr + length_pos, buffer, length_size);
+ string_length = extract_unsigned_integer (buffer, length_size);
+ xfree (buffer);
+ i = val_print_string (addr + string_pos, string_length, char_size, stream);
+ }
+ else if (pascal_object_is_vtbl_member (type))
+ {
+ /* print vtbl's nicely */
+ CORE_ADDR vt_address = unpack_pointer (type, valaddr + embedded_offset);
+
+ 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_PRINT_NAME (msymbol), stream);
+ fputs_filtered (">", stream);
+ }
+ if (vt_address && vtblprint)
+ {
+ struct value *vt_val;
+ struct symbol *wsym = (struct symbol *) NULL;
+ struct type *wtype;
+ struct block *block = (struct block *) NULL;
+ int is_this_fld;
+
+ if (msymbol != NULL)
+ wsym = lookup_symbol (DEPRECATED_SYMBOL_NAME (msymbol), block,
+ VAR_DOMAIN, &is_this_fld, NULL);
+
+ if (wsym)
+ {
+ wtype = SYMBOL_TYPE (wsym);
+ }
+ else
+ {
+ wtype = TYPE_TARGET_TYPE (type);
+ }
+ vt_val = value_at (wtype, vt_address, NULL);
+ val_print (VALUE_TYPE (vt_val), VALUE_CONTENTS (vt_val), 0,
+ 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 pascal_val_print");
+ break;
+
+ case TYPE_CODE_REF:
+ elttype = check_typedef (TYPE_TARGET_TYPE (type));
+ if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
+ {
+ pascal_object_print_class_member (valaddr + embedded_offset,
+ TYPE_DOMAIN_TYPE (elttype),
+ stream, "");
+ break;
+ }
+ if (addressprint)
+ {
+ fprintf_filtered (stream, "@");
+ /* Extract the address, assume that it is unsigned. */
+ print_address_numeric
+ (extract_unsigned_integer (valaddr + embedded_offset,
+ 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)
+ {
+ struct value *deref_val =
+ value_at
+ (TYPE_TARGET_TYPE (type),
+ unpack_pointer (lookup_pointer_type (builtin_type_void),
+ valaddr + embedded_offset),
+ NULL);
+ val_print (VALUE_TYPE (deref_val),
+ VALUE_CONTENTS (deref_val), 0,
+ 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 && pascal_object_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.) */
+ /* Extract the address, assume that it is unsigned. */
+ print_address_demangle
+ (extract_unsigned_integer (valaddr + embedded_offset + TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8,
+ TYPE_LENGTH (TYPE_FIELD_TYPE (type, VTBL_FNADDR_OFFSET))),
+ stream, demangle);
+ }
+ else
+ {
+ if (is_pascal_string_type (type, &length_pos, &length_size,
+ &string_pos, &char_size, NULL))
+ {
+ len = extract_unsigned_integer (valaddr + embedded_offset + length_pos, length_size);
+ LA_PRINT_STRING (stream, valaddr + embedded_offset + string_pos, len, char_size, 0);
+ }
+ else
+ pascal_object_print_value_fields (type, valaddr + embedded_offset, address, stream, format,
+ recurse, pretty, NULL, 0);
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ break;
+ }
+ len = TYPE_NFIELDS (type);
+ val = unpack_long (type, valaddr + embedded_offset);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (val == TYPE_FIELD_BITPOS (type, i))
+ {
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ else
+ {
+ print_longest (stream, 'd', 0, val);
+ }
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, 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 + embedded_offset, type, format, 0, stream);
+ else
+ {
+ val = unpack_long (type, valaddr + embedded_offset);
+ if (val == 0)
+ fputs_filtered ("false", stream);
+ else if (val == 1)
+ fputs_filtered ("true", stream);
+ else
+ {
+ fputs_filtered ("true (", stream);
+ fprintf_filtered (stream, "%ld)", (long int) val);
+ }
+ }
+ break;
+
+ case TYPE_CODE_RANGE:
+ /* FIXME: create_range_type does not set the unsigned bit in a
+ range type (I think it probably should copy it from the target
+ type), so we won't print values which are too large to
+ fit in a signed integer correctly. */
+ /* FIXME: Doesn't handle ranges of enums correctly. (Can't just
+ print with the target type, though, because the size of our type
+ and the target type might differ). */
+ /* FALLTHROUGH */
+
+ case TYPE_CODE_INT:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ }
+ else
+ {
+ val_print_type_code_int (type, valaddr + embedded_offset, stream);
+ }
+ break;
+
+ case TYPE_CODE_CHAR:
+ format = format ? format : output_format;
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ }
+ else
+ {
+ val = unpack_long (type, valaddr + embedded_offset);
+ if (TYPE_UNSIGNED (type))
+ fprintf_filtered (stream, "%u", (unsigned int) val);
+ else
+ fprintf_filtered (stream, "%d", (int) val);
+ fputs_filtered (" ", stream);
+ LA_PRINT_CHAR ((unsigned char) val, stream);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ }
+ else
+ {
+ print_floating (valaddr + embedded_offset, type, stream);
+ }
+ break;
+
+ case TYPE_CODE_BITSTRING:
+ case TYPE_CODE_SET:
+ elttype = TYPE_INDEX_TYPE (type);
+ CHECK_TYPEDEF (elttype);
+ if (TYPE_STUB (elttype))
+ {
+ fprintf_filtered (stream, "<incomplete type>");
+ gdb_flush (stream);
+ break;
+ }
+ else
+ {
+ 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 ("<error value>", stream);
+ goto done;
+ }
+
+ for (i = low_bound; i <= high_bound; i++)
+ {
+ int element = value_bit_index (type, valaddr + embedded_offset, 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);
+ print_type_scalar (range, i, stream);
+ need_comma = 1;
+
+ if (i + 1 <= high_bound && value_bit_index (type, valaddr + embedded_offset, ++i))
+ {
+ int j = i;
+ fputs_filtered ("..", stream);
+ while (i + 1 <= high_bound
+ && value_bit_index (type, valaddr + embedded_offset, ++i))
+ j = i;
+ print_type_scalar (range, j, stream);
+ }
+ }
+ }
+ done:
+ if (is_bitstring)
+ fputs_filtered ("'", stream);
+ else
+ fputs_filtered ("]", stream);
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf_filtered (stream, "void");
+ break;
+
+ case TYPE_CODE_ERROR:
+ fprintf_filtered (stream, "<error type>");
+ break;
+
+ case TYPE_CODE_UNDEF:
+ /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+ dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+ and no complete type for struct foo in that file. */
+ fprintf_filtered (stream, "<incomplete type>");
+ break;
+
+ default:
+ error ("Invalid pascal type code %d in symbol table.", TYPE_CODE (type));
+ }
+ gdb_flush (stream);
+ return (0);
+}
+
+int
+pascal_value_print (struct value *val, struct ui_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.
+
+ Object pascal: 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
+ && strcmp (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char") == 0)
+ {
+ /* Print nothing */
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") ");
+ }
+ }
+ return val_print (type, VALUE_CONTENTS (val), VALUE_EMBEDDED_OFFSET (val),
+ VALUE_ADDRESS (val) + VALUE_OFFSET (val),
+ stream, format, 1, 0, pretty);
+}
+
+
+/******************************************************************************
+ Inserted from cp-valprint
+******************************************************************************/
+
+extern int vtblprint; /* Controls printing of vtbl's */
+extern int objectprint; /* Controls looking up an object's derived type
+ using what we find in its vtables. */
+static int pascal_static_field_print; /* Controls printing of static fields. */
+
+static struct obstack dont_print_vb_obstack;
+static struct obstack dont_print_statmem_obstack;
+
+static void pascal_object_print_static_field (struct type *, struct value *,
+ struct ui_file *, int, int,
+ enum val_prettyprint);
+
+static void
+ pascal_object_print_value (struct type *, char *, CORE_ADDR, struct ui_file *,
+ int, int, enum val_prettyprint, struct type **);
+
+void
+pascal_object_print_class_method (char *valaddr, struct type *type,
+ struct ui_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, "<unknown>");
+ 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);
+
+ check_stub_method_group (domain, i);
+ for (j = 0; j < len2; j++)
+ {
+ 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);
+
+ check_stub_method_group (domain, i);
+ for (j = 0; j < len2; j++)
+ {
+ if (DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
+ goto common;
+ }
+ }
+ }
+common:
+ if (i < len)
+ {
+ char *demangled_name;
+
+ fprintf_filtered (stream, "&");
+ fputs_filtered (kind, stream);
+ demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name == NULL)
+ fprintf_filtered (stream, "<badly mangled name %s>",
+ TYPE_FN_FIELD_PHYSNAME (f, j));
+ else
+ {
+ fputs_filtered (demangled_name, stream);
+ xfree (demangled_name);
+ }
+ }
+ else
+ {
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") %d", (int) addr >> 3);
+ }
+}
+
+/* It was changed to this after 2.4.5. */
+const char pascal_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
+pascal_object_is_vtbl_ptr_type (struct type *type)
+{
+ char *typename = type_name_no_tag (type);
+
+ return (typename != NULL
+ && strcmp (typename, pascal_vtbl_ptr_name) == 0);
+}
+
+/* Return truth value for the assertion that TYPE is of the type
+ "pointer to virtual function table". */
+
+int
+pascal_object_is_vtbl_member (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 pascal_object_is_vtbl_ptr_type (type);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Mutually recursive subroutines of pascal_object_print_value and c_val_print to
+ print out a structure's fields: pascal_object_print_value_fields and pascal_object_print_value.
+
+ TYPE, VALADDR, ADDRESS, STREAM, RECURSE, and PRETTY have the
+ same meanings as in pascal_object_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
+pascal_object_print_value_fields (struct type *type, char *valaddr,
+ CORE_ADDR address, struct ui_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)
+ pascal_object_print_value (type, valaddr, address, stream,
+ format, recurse + 1, pretty, dont_print_vb);
+
+ if (!len && n_baseclasses == 1)
+ fprintf_filtered (stream, "<No data fields>");
+ else
+ {
+ 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 (!pascal_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))
+ {
+ struct value *v;
+
+ /* Bitfields require special handling, especially due to byte
+ order problems. */
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", 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, 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ }
+ else
+ {
+ if (TYPE_FIELD_IGNORE (type, i))
+ {
+ fputs_filtered ("<optimized out or zero length>", stream);
+ }
+ else if (TYPE_FIELD_STATIC (type, i))
+ {
+ /* struct value *v = value_static_field (type, i); v4.17 specific */
+ struct value *v;
+ v = value_from_longest (TYPE_FIELD_TYPE (type, i),
+ unpack_field_as_long (type, valaddr, i));
+
+ if (v == NULL)
+ fputs_filtered ("<optimized out>", stream);
+ else
+ pascal_object_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,
+ address + TYPE_FIELD_BITPOS (type, i) / 8, 0,
+ stream, format, 0, recurse + 1, pretty); */
+ val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr, TYPE_FIELD_BITPOS (type, i) / 8,
+ address + TYPE_FIELD_BITPOS (type, i) / 8,
+ 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. */
+
+void
+pascal_object_print_value (struct type *type, char *valaddr, CORE_ADDR address,
+ struct ui_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);
+ char *base_valaddr;
+
+ 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);
+
+ /* The virtual base class pointer might have been clobbered by the
+ user program. Make sure that it still points to a valid memory
+ location. */
+
+ if (boffset != -1 && (boffset < 0 || boffset >= TYPE_LENGTH (type)))
+ {
+ /* FIXME (alloc): not safe is baseclass is really really big. */
+ base_valaddr = (char *) alloca (TYPE_LENGTH (baseclass));
+ if (target_read_memory (address + boffset, base_valaddr,
+ TYPE_LENGTH (baseclass)) != 0)
+ boffset = -1;
+ }
+ else
+ base_valaddr = valaddr + boffset;
+
+ if (boffset == -1)
+ fprintf_filtered (stream, "<invalid address>");
+ else
+ pascal_object_print_value_fields (baseclass, base_valaddr, 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
+pascal_object_print_static_field (struct type *type, struct value *val,
+ struct ui_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 ("<same as static member of an already seen type>",
+ stream);
+ return;
+ }
+ }
+
+ obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val),
+ sizeof (CORE_ADDR));
+
+ CHECK_TYPEDEF (type);
+ pascal_object_print_value_fields (type, VALUE_CONTENTS (val), VALUE_ADDRESS (val),
+ stream, format, recurse, pretty, NULL, 1);
+ return;
+ }
+ val_print (type, VALUE_CONTENTS (val), 0, VALUE_ADDRESS (val),
+ stream, format, 0, recurse, pretty);
+}
+
+void
+pascal_object_print_class_member (char *valaddr, struct type *domain,
+ struct ui_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;
+ 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;
+ fputs_filtered (prefix, stream);
+ name = type_name_no_tag (domain);
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ pascal_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, "%ld", (long int) (val >> 3));
+}
+
+extern initialize_file_ftype _initialize_pascal_valprint; /* -Wmissing-prototypes */
+
+void
+_initialize_pascal_valprint (void)
+{
+ add_show_from_set
+ (add_set_cmd ("pascal_static-members", class_support, var_boolean,
+ (char *) &pascal_static_field_print,
+ "Set printing of pascal static members.",
+ &setprintlist),
+ &showprintlist);
+ /* Turn on printing of static fields. */
+ pascal_static_field_print = 1;
+
+}
diff --git a/contrib/gdb/gdb/pa64solib.c b/contrib/gdb/gdb/pa64solib.c
new file mode 100644
index 0000000..4e29455
--- /dev/null
+++ b/contrib/gdb/gdb/pa64solib.c
@@ -0,0 +1,1247 @@
+/* Handle HP ELF shared libraries for GDB, the GNU Debugger.
+
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ HP in their infinite stupidity choose not to use standard ELF dynamic
+ linker interfaces. They also choose not to make their ELF dymamic
+ linker interfaces compatible with the SOM dynamic linker. The
+ net result is we can not use either of the existing somsolib.c or
+ solib.c. What a crock.
+
+ Even more disgusting. This file depends on functions provided only
+ in certain PA64 libraries. Thus this file is supposed to only be
+ used native. When will HP ever learn that they need to provide the
+ same functionality in all their libraries! */
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <elf_hp.h>
+
+#include "defs.h"
+
+#include "frame.h"
+#include "bfd.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 "gdb_stat.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "regcache.h"
+#include "exec.h"
+
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static CORE_ADDR bfd_lookup_symbol (bfd *, char *);
+/* This lives in hppa-tdep.c. */
+extern struct unwind_table_entry *find_unwind_entry (CORE_ADDR pc);
+
+/* These ought to be defined in some public interface, but aren't. They
+ identify dynamic linker events. */
+#define DLD_CB_LOAD 1
+#define DLD_CB_UNLOAD 0
+
+/* A structure to keep track of all the known shared objects. */
+struct so_list
+ {
+ bfd *abfd;
+ char *name;
+ struct so_list *next;
+ struct objfile *objfile;
+ CORE_ADDR pa64_solib_desc_addr;
+ struct load_module_desc pa64_solib_desc;
+ struct section_table *sections;
+ struct section_table *sections_end;
+ int loaded;
+ };
+
+static struct so_list *so_list_head;
+
+/* This is the cumulative size in bytes of the symbol tables of all
+ shared objects on the so_list_head list. (When we say size, here
+ we mean of the information before it is brought into memory and
+ potentially expanded by GDB.) When adding a new shlib, this value
+ is compared against a threshold size, held by auto_solib_limit (in
+ megabytes). If adding symbols for the new shlib would cause the
+ total size to exceed the threshold, then the new shlib's symbols
+ are not loaded. */
+static LONGEST pa64_solib_total_st_size;
+
+/* When the threshold is reached for any shlib, we refuse to add
+ symbols for subsequent shlibs, even if those shlibs' symbols would
+ be small enough to fit under the threshold. Although this may
+ result in one, early large shlib preventing the loading of later,
+ smaller shlibs' symbols, it allows us to issue one informational
+ message. The alternative, to issue a message for each shlib whose
+ symbols aren't loaded, could be a big annoyance where the threshold
+ is exceeded due to a very large number of shlibs. */
+static int pa64_solib_st_size_threshold_exceeded;
+
+/* When adding fields, be sure to clear them in _initialize_pa64_solib. */
+typedef struct
+ {
+ CORE_ADDR dld_flags_addr;
+ LONGEST dld_flags;
+ struct bfd_section *dyninfo_sect;
+ int have_read_dld_descriptor;
+ int is_valid;
+ CORE_ADDR load_map;
+ CORE_ADDR load_map_addr;
+ struct load_module_desc dld_desc;
+ }
+dld_cache_t;
+
+static dld_cache_t dld_cache;
+
+static void pa64_sharedlibrary_info_command (char *, int);
+
+static void pa64_solib_sharedlibrary_command (char *, int);
+
+static void *pa64_target_read_memory (void *, CORE_ADDR, size_t, int);
+
+static int read_dld_descriptor (struct target_ops *, int readsyms);
+
+static int read_dynamic_info (asection *, dld_cache_t *);
+
+static void add_to_solist (int, char *, int, struct load_module_desc *,
+ CORE_ADDR, struct target_ops *);
+
+/* When examining the shared library for debugging information we have to
+ look for HP debug symbols, stabs and dwarf2 debug symbols. */
+static char *pa64_debug_section_names[] = {
+ ".debug_header", ".debug_gntt", ".debug_lntt", ".debug_slt", ".debug_vt",
+ ".stabs", ".stabstr", ".debug_info", ".debug_abbrev", ".debug_aranges",
+ ".debug_macinfo", ".debug_line", ".debug_loc", ".debug_pubnames",
+ ".debug_str", NULL
+};
+
+/* Return a ballbark figure for the amount of memory GDB will need to
+ allocate to read in the debug symbols from FILENAME. */
+static LONGEST
+pa64_solib_sizeof_symbol_table (char *filename)
+{
+ bfd *abfd;
+ int i;
+ int desc;
+ char *absolute_name;
+ LONGEST st_size = (LONGEST) 0;
+ asection *sect;
+
+ /* We believe that filename was handed to us by the dynamic linker, and
+ is therefore always an absolute path. */
+ desc = openp (getenv ("PATH"), 1, filename, O_RDONLY | O_BINARY,
+ 0, &absolute_name);
+ if (desc < 0)
+ {
+ perror_with_name (filename);
+ }
+ filename = absolute_name;
+
+ abfd = bfd_fdopenr (filename, gnutarget, desc);
+ if (!abfd)
+ {
+ close (desc);
+ make_cleanup (xfree, filename);
+ error ("\"%s\": can't open to read symbols: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ bfd_close (abfd);
+ make_cleanup (xfree, filename);
+ error ("\"%s\": can't read symbols: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* Sum the sizes of the various sections that compose debug info. */
+ for (i = 0; pa64_debug_section_names[i] != NULL; i++)
+ {
+ asection *sect;
+
+ sect = bfd_get_section_by_name (abfd, pa64_debug_section_names[i]);
+ if (sect)
+ st_size += (LONGEST)bfd_section_size (abfd, sect);
+ }
+
+ bfd_close (abfd);
+ xfree (filename);
+
+ /* Unfortunately, just summing the sizes of various debug info
+ sections isn't a very accurate measurement of how much heap
+ space the debugger will need to hold them. It also doesn't
+ account for space needed by linker (aka "minimal") symbols.
+
+ Anecdotal evidence suggests that just summing the sizes of
+ debug-info-related sections understates the heap space needed
+ to represent it internally by about an order of magnitude.
+
+ Since it's not exactly brain surgery we're doing here, rather
+ than attempt to more accurately measure the size of a shlib's
+ symbol table in GDB's heap, we'll just apply a 10x fudge-
+ factor to the debug info sections' size-sum. No, this doesn't
+ account for minimal symbols in non-debuggable shlibs. But it
+ all roughly washes out in the end. */
+ return st_size * (LONGEST) 10;
+}
+
+/* Add a shared library to the objfile list and load its symbols into
+ GDB's symbol table. */
+static void
+pa64_solib_add_solib_objfile (struct so_list *so, char *name, int from_tty,
+ CORE_ADDR text_addr)
+{
+ bfd *tmp_bfd;
+ asection *sec;
+ obj_private_data_t *obj_private;
+ struct section_addr_info *section_addrs;
+ struct cleanup *my_cleanups;
+
+ /* We need the BFD so that we can look at its sections. We open up the
+ file temporarily, then close it when we are done. */
+ tmp_bfd = bfd_openr (name, gnutarget);
+ if (tmp_bfd == NULL)
+ {
+ perror_with_name (name);
+ return;
+ }
+
+ if (!bfd_check_format (tmp_bfd, bfd_object))
+ {
+ bfd_close (tmp_bfd);
+ error ("\"%s\" is not an object file: %s", name,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+
+ /* Undo some braindamage from symfile.c.
+
+ First, symfile.c will subtract the VMA of the first .text section
+ in the shared library that it finds. Undo that. */
+ sec = bfd_get_section_by_name (tmp_bfd, ".text");
+ text_addr += bfd_section_vma (tmp_bfd, sec);
+
+ /* Now find the true lowest section in the shared library. */
+ sec = NULL;
+ bfd_map_over_sections (tmp_bfd, find_lowest_section, &sec);
+
+ if (sec)
+ {
+ /* Subtract out the VMA of the lowest section. */
+ text_addr -= bfd_section_vma (tmp_bfd, sec);
+
+ /* ??? Add back in the filepos of that lowest section. */
+ text_addr += sec->filepos;
+ }
+
+ section_addrs = alloc_section_addr_info (bfd_count_sections (tmp_bfd));
+ my_cleanups = make_cleanup (xfree, section_addrs);
+
+ /* We are done with the temporary bfd. Get rid of it and make sure
+ nobody else can us it. */
+ bfd_close (tmp_bfd);
+ tmp_bfd = NULL;
+
+ /* Now let the generic code load up symbols for this library. */
+ section_addrs->other[0].addr = text_addr;
+ section_addrs->other[0].name = ".text";
+ so->objfile = symbol_file_add (name, from_tty, section_addrs, 0, OBJF_SHARED);
+ so->abfd = so->objfile->obfd;
+
+ /* Mark this as a shared library and save private data. */
+ so->objfile->flags |= OBJF_SHARED;
+
+ if (so->objfile->obj_private == NULL)
+ {
+ obj_private = (obj_private_data_t *)
+ obstack_alloc (&so->objfile->objfile_obstack,
+ sizeof (obj_private_data_t));
+ obj_private->unwind_info = NULL;
+ obj_private->so_info = NULL;
+ so->objfile->obj_private = obj_private;
+ }
+
+ obj_private = (obj_private_data_t *) so->objfile->obj_private;
+ obj_private->so_info = so;
+ obj_private->dp = so->pa64_solib_desc.linkage_ptr;
+ do_cleanups (my_cleanups);
+}
+
+/* Load debugging information for a shared library. TARGET may be
+ NULL if we are not attaching to a process or reading a core file. */
+
+static void
+pa64_solib_load_symbols (struct so_list *so, char *name, int from_tty,
+ CORE_ADDR text_addr, struct target_ops *target)
+{
+ struct section_table *p;
+ asection *sec;
+ int status;
+ char buf[4];
+ CORE_ADDR presumed_data_start;
+
+ if (text_addr == 0)
+ text_addr = so->pa64_solib_desc.text_base;
+
+ pa64_solib_add_solib_objfile (so, name, from_tty, text_addr);
+
+ /* 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 (so->abfd,
+ &so->sections,
+ &so->sections_end))
+ {
+ error ("Unable to build section table for shared library\n.");
+ return;
+ }
+
+ (so->objfile->section_offsets)->offsets[SECT_OFF_TEXT (so->objfile)]
+ = so->pa64_solib_desc.text_base;
+ (so->objfile->section_offsets)->offsets[SECT_OFF_DATA (so->objfile)]
+ = so->pa64_solib_desc.data_base;
+
+ /* Relocate all the sections based on where they got loaded. */
+ for (p = so->sections; p < so->sections_end; p++)
+ {
+ if (p->the_bfd_section->flags & SEC_CODE)
+ {
+ p->addr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_TEXT (so->objfile));
+ p->endaddr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_TEXT (so->objfile));
+ }
+ else if (p->the_bfd_section->flags & SEC_DATA)
+ {
+ p->addr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_DATA (so->objfile));
+ p->endaddr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_DATA (so->objfile));
+ }
+ }
+
+ /* 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 new, old;
+
+ new = so->sections_end - so->sections;
+
+ old = target_resize_to_sections (target, new);
+
+ /* Copy over the old data before it gets clobbered. */
+ memcpy ((char *) (target->to_sections + old),
+ so->sections,
+ ((sizeof (struct section_table)) * new));
+ }
+}
+
+
+/* Add symbols from shared libraries into the symtab list, unless the
+ size threshold specified by auto_solib_limit (in megabytes) would
+ be exceeded. */
+
+void
+pa64_solib_add (char *arg_string, int from_tty, struct target_ops *target, int readsyms)
+{
+ struct minimal_symbol *msymbol;
+ CORE_ADDR addr;
+ asection *shlib_info;
+ int status;
+ unsigned int dld_flags;
+ char buf[4], *re_err;
+ int threshold_warning_given = 0;
+ int dll_index;
+ struct load_module_desc dll_desc;
+ char *dll_path;
+
+ /* 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 pa64_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, ".dynamic");
+ if (!shlib_info)
+ return;
+
+ /* It's got a .dynamic section, make sure it's not empty. */
+ if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0)
+ return;
+
+ /* Read in the load map pointer if we have not done so already. */
+ if (! dld_cache.have_read_dld_descriptor)
+ if (! read_dld_descriptor (target, readsyms))
+ return;
+
+ /* If the libraries were not mapped private, warn the user. */
+ if ((dld_cache.dld_flags & DT_HP_DEBUG_PRIVATE) == 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");
+
+ /* For each shaerd library, add it to the shared library list. */
+ for (dll_index = 1; ; dll_index++)
+ {
+ /* Read in the load module descriptor. */
+ if (dlgetmodinfo (dll_index, &dll_desc, sizeof (dll_desc),
+ pa64_target_read_memory, 0, dld_cache.load_map)
+ == 0)
+ return;
+
+ /* Get the name of the shared library. */
+ dll_path = (char *)dlgetname (&dll_desc, sizeof (dll_desc),
+ pa64_target_read_memory,
+ 0, dld_cache.load_map);
+
+ if (!dll_path)
+ error ("pa64_solib_add, unable to read shared library path.");
+
+ add_to_solist (from_tty, dll_path, readsyms, &dll_desc, 0, target);
+ }
+}
+
+
+/* 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).
+
+ We need to set two flag bits in this routine.
+
+ DT_HP_DEBUG_PRIVATE to indicate that shared libraries should be
+ mapped private.
+
+ DT_HP_DEBUG_CALLBACK to indicate that we want the dynamic linker to
+ call the breakpoint routine for significant events. */
+
+void
+pa64_solib_create_inferior_hook (void)
+{
+ struct minimal_symbol *msymbol;
+ unsigned int dld_flags, status;
+ asection *shlib_info, *interp_sect;
+ char 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, ".dynamic");
+ if (!shlib_info)
+ return;
+
+ /* It's got a .dynamic section, make sure it's not empty. */
+ if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0)
+ return;
+
+ /* Read in the .dynamic section. */
+ if (! read_dynamic_info (shlib_info, &dld_cache))
+ error ("Unable to read the .dynamic section.");
+
+ /* Turn on the flags we care about. */
+ dld_cache.dld_flags |= DT_HP_DEBUG_PRIVATE;
+ dld_cache.dld_flags |= DT_HP_DEBUG_CALLBACK;
+ status = target_write_memory (dld_cache.dld_flags_addr,
+ (char *) &dld_cache.dld_flags,
+ sizeof (dld_cache.dld_flags));
+ if (status != 0)
+ error ("Unable to modify dynamic linker flags.");
+
+ /* Now we have to create a shared library breakpoint in the dynamic
+ linker. This can be somewhat tricky since the symbol is inside
+ the dynamic linker (for which we do not have symbols or a base
+ load address! Luckily I wrote this code for solib.c years ago. */
+ 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 GNU/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 get_out;
+
+ /* 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 get_out;
+ }
+
+ /* 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.
+
+ Also note the breakpoint is the second instruction in the
+ routine. */
+ load_addr = read_pc () - tmp_bfd->start_address;
+ sym_addr = bfd_lookup_symbol (tmp_bfd, "__dld_break");
+ sym_addr = load_addr + sym_addr + 4;
+
+ /* Create the shared library breakpoint. */
+ {
+ struct breakpoint *b
+ = create_solib_event_breakpoint (sym_addr);
+
+ /* The breakpoint is actually hard-coded into the dynamic linker,
+ so we don't need to actually insert a breakpoint instruction
+ there. In fact, the dynamic linker's code is immutable, even to
+ ttrace, so we shouldn't even try to do that. For cases like
+ this, we have "permanent" breakpoints. */
+ make_breakpoint_permanent (b);
+ }
+
+ /* We're done with the temporary bfd. */
+ bfd_close (tmp_bfd);
+ }
+
+get_out:
+ /* 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;
+
+ temp = so_list_head;
+ xfree (so_list_head);
+ so_list_head = temp->next;
+ }
+ clear_symtab_users ();
+}
+
+/* This operation removes the "hook" between GDB and the dynamic linker,
+ which causes the dld to notify GDB of shared library events.
+
+ After this operation completes, the dld will no longer notify GDB of
+ shared library events. To resume notifications, GDB must call
+ pa64_solib_create_inferior_hook.
+
+ This operation does not remove any knowledge of shared libraries which
+ GDB may already have been notified of. */
+
+void
+pa64_solib_remove_inferior_hook (int pid)
+{
+ /* Turn off the DT_HP_DEBUG_CALLBACK bit in the dynamic linker flags. */
+ dld_cache.dld_flags &= ~DT_HP_DEBUG_CALLBACK;
+ target_write_memory (dld_cache.dld_flags_addr,
+ (char *)&dld_cache.dld_flags,
+ sizeof (dld_cache.dld_flags));
+}
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_load call is made.
+
+ If filename is NULL, then loads of any dll will be caught. Else,
+ only loads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ pa64_solib_create_inferior_hook. */
+
+void
+pa64_solib_create_catch_load_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_load_event_breakpoint ("", tempflag, filename, cond_string);
+}
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_unload call is made.
+
+ If filename is NULL, then unloads of any dll will be caught. Else,
+ only unloads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ pa64_solib_create_inferior_hook. */
+
+void
+pa64_solib_create_catch_unload_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_unload_event_breakpoint ("", tempflag, filename, cond_string);
+}
+
+/* Return nonzero if the dynamic linker has reproted that a library
+ has been loaded. */
+
+int
+pa64_solib_have_load_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == DLD_CB_LOAD);
+}
+
+/* Return nonzero if the dynamic linker has reproted that a library
+ has been unloaded. */
+int
+pa64_solib_have_unload_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == DLD_CB_UNLOAD);
+}
+
+/* Return a pointer to a string indicating the pathname of the most
+ recently loaded library.
+
+ The caller is reposible for copying the string before the inferior is
+ restarted. */
+
+char *
+pa64_solib_loaded_library_pathname (int pid)
+{
+ static char dll_path[MAXPATHLEN];
+ CORE_ADDR dll_path_addr = read_register (ARG3_REGNUM);
+ read_memory_string (dll_path_addr, dll_path, MAXPATHLEN);
+ return dll_path;
+}
+
+/* Return a pointer to a string indicating the pathname of the most
+ recently unloaded library.
+
+ The caller is reposible for copying the string before the inferior is
+ restarted. */
+
+char *
+pa64_solib_unloaded_library_pathname (int pid)
+{
+ static char dll_path[MAXPATHLEN];
+ CORE_ADDR dll_path_addr = read_register (ARG3_REGNUM);
+ read_memory_string (dll_path_addr, dll_path, MAXPATHLEN);
+ return dll_path;
+}
+
+/* Return nonzero if PC is an address inside the dynamic linker. */
+
+int
+pa64_solib_in_dynamic_linker (int pid, CORE_ADDR pc)
+{
+ asection *shlib_info;
+
+ if (symfile_objfile == NULL)
+ return 0;
+
+ if (!dld_cache.have_read_dld_descriptor)
+ if (!read_dld_descriptor (&current_target, auto_solib_add))
+ return 0;
+
+ return (pc >= dld_cache.dld_desc.text_base
+ && pc < dld_cache.dld_desc.text_base + dld_cache.dld_desc.text_size);
+}
+
+
+/* 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
+pa64_solib_get_got_by_pc (CORE_ADDR addr)
+{
+ struct so_list *so_list = so_list_head;
+ CORE_ADDR got_value = 0;
+
+ while (so_list)
+ {
+ if (so_list->pa64_solib_desc.text_base <= addr
+ && ((so_list->pa64_solib_desc.text_base
+ + so_list->pa64_solib_desc.text_size)
+ > addr))
+ {
+ got_value = so_list->pa64_solib_desc.linkage_ptr;
+ break;
+ }
+ so_list = so_list->next;
+ }
+ return got_value;
+}
+
+/* Return the address of the handle of the shared library in which ADDR
+ belongs. If ADDR isn't in any known shared library, return zero.
+
+ This function is used in hppa_fix_call_dummy in hppa-tdep.c. */
+
+CORE_ADDR
+pa64_solib_get_solib_by_pc (CORE_ADDR addr)
+{
+ struct so_list *so_list = so_list_head;
+ CORE_ADDR retval = 0;
+
+ while (so_list)
+ {
+ if (so_list->pa64_solib_desc.text_base <= addr
+ && ((so_list->pa64_solib_desc.text_base
+ + so_list->pa64_solib_desc.text_size)
+ > addr))
+ {
+ retval = so_list->pa64_solib_desc_addr;
+ break;
+ }
+ so_list = so_list->next;
+ }
+ return retval;
+}
+
+/* Dump information about all the currently loaded shared libraries. */
+
+static void
+pa64_sharedlibrary_info_command (char *ignore, int from_tty)
+{
+ struct so_list *so_list = so_list_head;
+
+ if (exec_bfd == NULL)
+ {
+ printf_unfiltered ("No executable 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 (" %-19s%-19s%-19s%-19s\n",
+ " text start", " text end",
+ " data start", " data end");
+ while (so_list)
+ {
+ unsigned int flags;
+
+ printf_unfiltered ("%s", so_list->name);
+ if (so_list->objfile == NULL)
+ printf_unfiltered (" (symbols not loaded)");
+ if (so_list->loaded == 0)
+ printf_unfiltered (" (shared library unloaded)");
+ printf_unfiltered (" %-18s",
+ local_hex_string_custom (so_list->pa64_solib_desc.linkage_ptr,
+ "016l"));
+ printf_unfiltered ("\n");
+ printf_unfiltered ("%-18s",
+ local_hex_string_custom (so_list->pa64_solib_desc.text_base,
+ "016l"));
+ printf_unfiltered (" %-18s",
+ local_hex_string_custom ((so_list->pa64_solib_desc.text_base
+ + so_list->pa64_solib_desc.text_size),
+ "016l"));
+ printf_unfiltered (" %-18s",
+ local_hex_string_custom (so_list->pa64_solib_desc.data_base,
+ "016l"));
+ printf_unfiltered (" %-18s\n",
+ local_hex_string_custom ((so_list->pa64_solib_desc.data_base
+ + so_list->pa64_solib_desc.data_size),
+ "016l"));
+ so_list = so_list->next;
+ }
+}
+
+/* Load up one or more shared libraries as directed by the user. */
+
+static void
+pa64_solib_sharedlibrary_command (char *args, int from_tty)
+{
+ dont_repeat ();
+ pa64_solib_add (args, from_tty, (struct target_ops *) 0, 1);
+}
+
+/* Return the name of the shared library containing ADDR or NULL if ADDR
+ is not contained in any known shared library. */
+
+char *
+pa64_solib_address (CORE_ADDR addr)
+{
+ struct so_list *so = so_list_head;
+
+ while (so)
+ {
+ /* Is this address within this shlib's text range? If so,
+ return the shlib's name. */
+ if (addr >= so->pa64_solib_desc.text_base
+ && addr < (so->pa64_solib_desc.text_base
+ | so->pa64_solib_desc.text_size))
+ return so->name;
+
+ /* Nope, keep looking... */
+ so = so->next;
+ }
+
+ /* No, we couldn't prove that the address is within a shlib. */
+ return NULL;
+}
+
+/* We are killing the inferior and restarting the program. */
+
+void
+pa64_solib_restart (void)
+{
+ struct so_list *sl = so_list_head;
+
+ /* Before the shlib info vanishes, use it to disable any breakpoints
+ that may still be active in those shlibs. */
+ disable_breakpoints_in_shlibs (0);
+
+ /* Discard all the shlib descriptors. */
+ while (sl)
+ {
+ struct so_list *next_sl = sl->next;
+ xfree (sl);
+ sl = next_sl;
+ }
+ so_list_head = NULL;
+
+ pa64_solib_total_st_size = (LONGEST) 0;
+ pa64_solib_st_size_threshold_exceeded = 0;
+
+ dld_cache.is_valid = 0;
+ dld_cache.have_read_dld_descriptor = 0;
+ dld_cache.dld_flags_addr = 0;
+ dld_cache.load_map = 0;
+ dld_cache.load_map_addr = 0;
+ dld_cache.dld_desc.data_base = 0;
+ dld_cache.dld_flags = 0;
+ dld_cache.dyninfo_sect = 0;
+}
+
+void
+_initialize_pa64_solib (void)
+{
+ add_com ("sharedlibrary", class_files, pa64_solib_sharedlibrary_command,
+ "Load shared object library symbols for files matching REGEXP.");
+ add_info ("sharedlibrary", pa64_sharedlibrary_info_command,
+ "Status of loaded shared object libraries.");
+
+ add_show_from_set
+ (add_set_cmd ("auto-solib-add", class_support, var_boolean,
+ (char *) &auto_solib_add,
+ "Set autoloading of shared library symbols.\n\
+If \"on\", symbols from all shared object libraries will be loaded\n\
+automatically when the inferior begins execution, when the dynamic linker\n\
+informs gdb that a new library has been loaded, or when attaching to the\n\
+inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("auto-solib-limit", class_support, var_zinteger,
+ (char *) &auto_solib_limit,
+ "Set threshold (in Mb) for autoloading shared library symbols.\n\
+When shared library autoloading is enabled, new libraries will be loaded\n\
+only until the total size of shared library symbols exceeds this\n\
+threshold in megabytes. Is ignored when using `sharedlibrary'.",
+ &setlist),
+ &showlist);
+
+ /* ??rehrauer: On HP-UX, the kernel parameter MAXDSIZ limits how
+ much data space a process can use. We ought to be reading
+ MAXDSIZ and setting auto_solib_limit to some large fraction of
+ that value. If not that, we maybe ought to be setting it smaller
+ than the default for MAXDSIZ (that being 64Mb, I believe).
+ However, [1] this threshold is only crudely approximated rather
+ than actually measured, and [2] 50 Mbytes is too small for
+ debugging gdb itself. Thus, the arbitrary 100 figure. */
+ auto_solib_limit = 100; /* Megabytes */
+
+ pa64_solib_restart ();
+}
+
+/* Get some HPUX-specific data from a shared lib. */
+CORE_ADDR
+so_lib_thread_start_addr (struct so_list *so)
+{
+ return so->pa64_solib_desc.tls_start_addr;
+}
+
+/* Read the dynamic linker's internal shared library descriptor.
+
+ This must happen after dld starts running, so we can't do it in
+ read_dynamic_info. Record the fact that we have loaded the
+ descriptor. If the library is archive bound, then return zero, else
+ return nonzero. */
+
+static int
+read_dld_descriptor (struct target_ops *target, int readsyms)
+{
+ char *dll_path;
+ asection *dyninfo_sect;
+
+ /* If necessary call read_dynamic_info to extract the contents of the
+ .dynamic section from the shared library. */
+ if (!dld_cache.is_valid)
+ {
+ if (symfile_objfile == NULL)
+ error ("No object file symbols.");
+
+ dyninfo_sect = bfd_get_section_by_name (symfile_objfile->obfd,
+ ".dynamic");
+ if (!dyninfo_sect)
+ {
+ return 0;
+ }
+
+ if (!read_dynamic_info (dyninfo_sect, &dld_cache))
+ error ("Unable to read in .dynamic section information.");
+ }
+
+ /* Read the load map pointer. */
+ if (target_read_memory (dld_cache.load_map_addr,
+ (char*) &dld_cache.load_map,
+ sizeof(dld_cache.load_map))
+ != 0)
+ {
+ error ("Error while reading in load map pointer.");
+ }
+
+ /* Read in the dld load module descriptor */
+ if (dlgetmodinfo (-1,
+ &dld_cache.dld_desc,
+ sizeof(dld_cache.dld_desc),
+ pa64_target_read_memory,
+ 0,
+ dld_cache.load_map)
+ == 0)
+ {
+ error ("Error trying to get information about dynamic linker.");
+ }
+
+ /* Indicate that we have loaded the dld descriptor. */
+ dld_cache.have_read_dld_descriptor = 1;
+
+ /* Add dld.sl to the list of known shared libraries so that we can
+ do unwind, etc.
+
+ ?!? This may not be correct. Consider of dld.sl contains symbols
+ which are also referenced/defined by the user program or some user
+ shared library. We need to make absolutely sure that we do not
+ pollute the namespace from GDB's point of view. */
+ dll_path = dlgetname (&dld_cache.dld_desc,
+ sizeof(dld_cache.dld_desc),
+ pa64_target_read_memory,
+ 0,
+ dld_cache.load_map);
+ add_to_solist(0, dll_path, readsyms, &dld_cache.dld_desc, 0, target);
+
+ return 1;
+}
+
+/* Read the .dynamic section and extract the information of interest,
+ which is stored in dld_cache. The routine elf_locate_base in solib.c
+ was used as a model for this. */
+
+static int
+read_dynamic_info (asection *dyninfo_sect, dld_cache_t *dld_cache_p)
+{
+ char *buf;
+ char *bufend;
+ CORE_ADDR dyninfo_addr;
+ int dyninfo_sect_size;
+ CORE_ADDR entry_addr;
+
+ /* Read in .dynamic section, silently ignore errors. */
+ dyninfo_addr = bfd_section_vma (symfile_objfile->obfd, dyninfo_sect);
+ 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;
+
+ /* Scan the .dynamic section and record the items of interest.
+ In particular, DT_HP_DLD_FLAGS */
+ for (bufend = buf + dyninfo_sect_size, entry_addr = dyninfo_addr;
+ buf < bufend;
+ buf += sizeof (Elf64_Dyn), entry_addr += sizeof (Elf64_Dyn))
+ {
+ Elf64_Dyn *x_dynp = (Elf64_Dyn*)buf;
+ Elf64_Sxword dyn_tag;
+ CORE_ADDR dyn_ptr;
+ char *pbuf;
+
+ pbuf = alloca (TARGET_PTR_BIT / HOST_CHAR_BIT);
+ dyn_tag = bfd_h_get_64 (symfile_objfile->obfd,
+ (bfd_byte*) &x_dynp->d_tag);
+
+ /* We can't use a switch here because dyn_tag is 64 bits and HP's
+ lame comiler does not handle 64bit items in switch statements. */
+ if (dyn_tag == DT_NULL)
+ break;
+ else if (dyn_tag == DT_HP_DLD_FLAGS)
+ {
+ /* Set dld_flags_addr and dld_flags in *dld_cache_p */
+ dld_cache_p->dld_flags_addr = entry_addr + offsetof(Elf64_Dyn, d_un);
+ if (target_read_memory (dld_cache_p->dld_flags_addr,
+ (char*) &dld_cache_p->dld_flags,
+ sizeof(dld_cache_p->dld_flags))
+ != 0)
+ {
+ error ("Error while reading in .dynamic section of the program.");
+ }
+ }
+ else if (dyn_tag == DT_HP_LOAD_MAP)
+ {
+ /* Dld will place the address of the load map at load_map_addr
+ after it starts running. */
+ if (target_read_memory (entry_addr + offsetof(Elf64_Dyn,
+ d_un.d_ptr),
+ (char*) &dld_cache_p->load_map_addr,
+ sizeof(dld_cache_p->load_map_addr))
+ != 0)
+ {
+ error ("Error while reading in .dynamic section of the program.");
+ }
+ }
+ else
+ {
+ /* tag is not of interest */
+ }
+ }
+
+ /* Record other information and set is_valid to 1. */
+ dld_cache_p->dyninfo_sect = dyninfo_sect;
+
+ /* Verify that we read in required info. These fields are re-set to zero
+ in pa64_solib_restart. */
+
+ if (dld_cache_p->dld_flags_addr != 0 && dld_cache_p->load_map_addr != 0)
+ dld_cache_p->is_valid = 1;
+ else
+ return 0;
+
+ return 1;
+}
+
+/* Wrapper for target_read_memory to make dlgetmodinfo happy. */
+
+static void *
+pa64_target_read_memory (void *buffer, CORE_ADDR ptr, size_t bufsiz, int ident)
+{
+ if (target_read_memory (ptr, buffer, bufsiz) != 0)
+ return 0;
+ return buffer;
+}
+
+/* Called from handle_dynlink_load_event and pa64_solib_add to add
+ a shared library to so_list_head list and possibly to read in the
+ debug information for the library.
+
+ If load_module_desc_p is NULL, then the load module descriptor must
+ be read from the inferior process at the address load_module_desc_addr. */
+
+static void
+add_to_solist (int from_tty, char *dll_path, int readsyms,
+ struct load_module_desc *load_module_desc_p,
+ CORE_ADDR load_module_desc_addr, struct target_ops *target)
+{
+ struct so_list *new_so, *so_list_tail;
+ int pa64_solib_st_size_threshhold_exceeded;
+ LONGEST st_size;
+
+ if (symfile_objfile == NULL)
+ return;
+
+ so_list_tail = so_list_head;
+ /* Find the end of the list of shared objects. */
+ while (so_list_tail && so_list_tail->next)
+ {
+ if (strcmp (so_list_tail->name, dll_path) == 0)
+ return;
+ so_list_tail = so_list_tail->next;
+ }
+
+ if (so_list_tail && strcmp (so_list_tail->name, dll_path) == 0)
+ return;
+
+ /* Add the shared library to the so_list_head list */
+ 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;
+ }
+
+ /* Initialize the new_so */
+ if (load_module_desc_p)
+ {
+ new_so->pa64_solib_desc = *load_module_desc_p;
+ }
+ else
+ {
+ if (target_read_memory (load_module_desc_addr,
+ (char*) &new_so->pa64_solib_desc,
+ sizeof(struct load_module_desc))
+ != 0)
+ {
+ error ("Error while reading in dynamic library %s", dll_path);
+ }
+ }
+
+ new_so->pa64_solib_desc_addr = load_module_desc_addr;
+ new_so->loaded = 1;
+ new_so->name = obsavestring (dll_path, strlen(dll_path),
+ &symfile_objfile->objfile_obstack);
+
+ /* If we are not going to load the library, tell the user if we
+ haven't already and return. */
+
+ st_size = pa64_solib_sizeof_symbol_table (dll_path);
+ pa64_solib_st_size_threshhold_exceeded =
+ !from_tty
+ && readsyms
+ && ( (st_size + pa64_solib_total_st_size)
+ > (auto_solib_limit * (LONGEST) (1024 * 1024)));
+ if (pa64_solib_st_size_threshhold_exceeded)
+ {
+ pa64_solib_add_solib_objfile (new_so, dll_path, from_tty, 1);
+ return;
+ }
+
+ /* Now read in debug info. */
+ pa64_solib_total_st_size += st_size;
+
+ /* This fills in new_so->objfile, among others. */
+ pa64_solib_load_symbols (new_so,
+ dll_path,
+ from_tty,
+ 0,
+ target);
+ return;
+}
+
+
+/*
+ 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 (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 (xfree, symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = *symbol_table++;
+ if (strcmp (sym->name, symname) == 0)
+ {
+ /* Bfd symbols are section relative. */
+ symaddr = sym->value + sym->section->vma;
+ break;
+ }
+ }
+ do_cleanups (back_to);
+ }
+ return (symaddr);
+}
+
diff --git a/contrib/gdb/gdb/pa64solib.h b/contrib/gdb/gdb/pa64solib.h
new file mode 100644
index 0000000..7a3a068
--- /dev/null
+++ b/contrib/gdb/gdb/pa64solib.h
@@ -0,0 +1,149 @@
+/* HP PA64 ELF Shared library declarations for GDB, the GNU Debugger.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Forward decl's for prototypes */
+struct target_ops;
+struct objfile;
+struct section_offsets;
+
+/* Called to add symbols from a shared library to gdb's symbol table. */
+
+#define SOLIB_ADD(filename, from_tty, targ, readsyms) \
+ pa64_solib_add (filename, from_tty, targ, readsyms)
+
+extern void pa64_solib_add (char *, int, struct target_ops *, int);
+
+extern CORE_ADDR pa64_solib_get_got_by_pc (CORE_ADDR);
+
+/* 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) pa64_solib_create_inferior_hook()
+
+extern void pa64_solib_create_inferior_hook (void);
+
+/* Function to be called to remove the connection between debugger and
+ dynamic linker that was established by SOLIB_CREATE_INFERIOR_HOOK.
+ (This operation does not remove shared library information from
+ the debugger, as CLEAR_SOLIB does.) */
+#define SOLIB_REMOVE_INFERIOR_HOOK(PID) pa64_solib_remove_inferior_hook(PID)
+
+extern void pa64_solib_remove_inferior_hook (int);
+
+/* This function is called by the "catch load" command. It allows
+ the debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is loaded. */
+#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag, filename,cond_string) \
+ pa64_solib_create_catch_load_hook (pid, tempflag, filename, cond_string)
+
+extern void pa64_solib_create_catch_load_hook (int, int, char *, char *);
+
+/* This function is called by the "catch unload" command. It allows
+ the debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is unloaded. */
+#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename, cond_string) \
+ pa64_solib_create_catch_unload_hook (pid, tempflag, filename, cond_string)
+
+extern void pa64_solib_create_catch_unload_hook (int, int, char *, char *);
+
+/* This function returns TRUE if the dynamic linker has just reported
+ a load of a library.
+
+ This function must be used only when the inferior has stopped in
+ the dynamic linker hook, or undefined results are guaranteed. */
+#define SOLIB_HAVE_LOAD_EVENT(pid) \
+ pa64_solib_have_load_event (pid)
+
+extern int pa64_solib_have_load_event (int);
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been loaded.
+
+ This function must be used only when SOLIB_HAVE_LOAD_EVENT is TRUE,
+ or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the inferior
+ has stopped in the dynamic linker hook, and becomes invalid as soon
+ as the inferior is continued. Clients should make a copy of this
+ string if they wish to continue the inferior and then access the string. */
+#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) \
+ pa64_solib_loaded_library_pathname (pid)
+
+extern char *pa64_solib_loaded_library_pathname (int);
+
+/* This function returns TRUE if the dynamic linker has just reported
+ an unload of a library.
+
+ This function must be used only when the inferior has stopped in
+ the dynamic linker hook, or undefined results are guaranteed. */
+#define SOLIB_HAVE_UNLOAD_EVENT(pid) \
+ pa64_solib_have_unload_event (pid)
+
+extern int pa64_solib_have_unload_event (int);
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been unloaded.
+
+ This function must be used only when SOLIB_HAVE_UNLOAD_EVENT is TRUE,
+ or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the inferior
+ has stopped in the dynamic linker hook, and becomes invalid as soon
+ as the inferior is continued. Clients should make a copy of this
+ string if they wish to continue the inferior and then access the string. */
+#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) \
+ pa64_solib_unloaded_library_pathname (pid)
+
+extern char *pa64_solib_unloaded_library_pathname (int);
+
+/* This function returns TRUE if pc is the address of an instruction that
+ lies within the dynamic linker (such as the event hook, or the dld
+ itself).
+
+ This function must be used only when a dynamic linker event has been
+ caught, and the inferior is being stepped out of the hook, or undefined
+ results are guaranteed. */
+#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
+ pa64_solib_in_dynamic_linker (pid, pc)
+
+extern int pa64_solib_in_dynamic_linker (int, CORE_ADDR);
+
+/* This function must be called when the inferior is killed, and the program
+ restarted. This is not the same as CLEAR_SOLIB, in that it doesn't discard
+ any symbol tables.
+
+ Presently, this functionality is not implemented. */
+#define SOLIB_RESTART() \
+ pa64_solib_restart ()
+
+extern void pa64_solib_restart (void);
+
+/* If we can't set a breakpoint, and it's in a shared library, just
+ disable it. */
+
+#define DISABLE_UNSETTABLE_BREAK(addr) (pa64_solib_address(addr) != NULL)
+
+extern char *pa64_solib_address (CORE_ADDR); /* somsolib.c */
+
+/* If ADDR lies in a shared library, return its name. */
+
+#define PC_SOLIB(addr) pa64_solib_address (addr)
diff --git a/contrib/gdb/gdb/parse.c b/contrib/gdb/gdb/parse.c
new file mode 100644
index 0000000..374e88e
--- /dev/null
+++ b/contrib/gdb/gdb/parse.c
@@ -0,0 +1,1308 @@
+/* Parse expressions for GDB.
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2001 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 <ctype.h>
+
+#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"
+#include "gdbcmd.h"
+#include "symfile.h" /* for overlay functions */
+#include "inferior.h" /* for NUM_PSEUDO_REGS. NOTE: replace
+ with "gdbarch.h" when appropriate. */
+#include "doublest.h"
+#include "gdb_assert.h"
+#include "block.h"
+
+/* Standard set of definitions for printing, dumping, prefixifying,
+ * and evaluating expressions. */
+
+const struct exp_descriptor exp_descriptor_standard =
+ {
+ print_subexp_standard,
+ operator_length_standard,
+ op_name_standard,
+ dump_subexp_body_standard,
+ evaluate_subexp_standard
+ };
+
+/* Symbols which architectures can redefine. */
+
+/* Some systems have routines whose names start with `$'. Giving this
+ macro a non-zero value tells GDB's expression parser to check for
+ such routines when parsing tokens that begin with `$'.
+
+ On HP-UX, certain system routines (millicode) have names beginning
+ with `$' or `$$'. For example, `$$dyncall' is a millicode routine
+ that handles inter-space procedure calls on PA-RISC. */
+#ifndef SYMBOLS_CAN_START_WITH_DOLLAR
+#define SYMBOLS_CAN_START_WITH_DOLLAR (0)
+#endif
+
+
+
+/* Global variables declared in parser-defs.h (and commented there). */
+struct expression *expout;
+int expout_size;
+int expout_ptr;
+struct block *expression_context_block;
+CORE_ADDR expression_context_pc;
+struct block *innermost_block;
+int arglist_len;
+union type_stack_elt *type_stack;
+int type_stack_depth, type_stack_size;
+char *lexptr;
+char *prev_lexptr;
+char *namecopy;
+int paren_depth;
+int comma_terminates;
+
+static int expressiondebug = 0;
+
+extern int hp_som_som_object_present;
+
+static void free_funcalls (void *ignore);
+
+static void prefixify_expression (struct expression *);
+
+static void prefixify_subexp (struct expression *, struct expression *, int,
+ int);
+
+void _initialize_parse (void);
+
+/* 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;
+
+/* Begin counting arguments for a function call,
+ saving the data about any containing call. */
+
+void
+start_arglist (void)
+{
+ 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 (void)
+{
+ int val = arglist_len;
+ struct funcall *call = funcall_chain;
+ funcall_chain = call->next;
+ arglist_len = call->arglist_len;
+ xfree (call);
+ return val;
+}
+
+/* Free everything in the funcall chain.
+ Used when there is an error inside parsing. */
+
+static void
+free_funcalls (void *ignore)
+{
+ struct funcall *call, *next;
+
+ for (call = funcall_chain; call; call = next)
+ {
+ next = call->next;
+ xfree (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 (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 (enum exp_opcode expelt)
+{
+ union exp_element tmp;
+
+ tmp.opcode = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_sym (struct symbol *expelt)
+{
+ union exp_element tmp;
+
+ tmp.symbol = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_block (struct block *b)
+{
+ union exp_element tmp;
+ tmp.block = b;
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_longcst (LONGEST expelt)
+{
+ union exp_element tmp;
+
+ tmp.longconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_dblcst (DOUBLEST expelt)
+{
+ union exp_element tmp;
+
+ tmp.doubleconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_type (struct type *expelt)
+{
+ union exp_element tmp;
+
+ tmp.type = expelt;
+
+ write_exp_elt (tmp);
+}
+
+void
+write_exp_elt_intern (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 (struct stoken str)
+{
+ int len = str.length;
+ int lenelt;
+ 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 (struct stoken str)
+{
+ int bits = str.length; /* length in bits */
+ int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ int lenelt;
+ 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 (struct minimal_symbol *msymbol,
+ struct type *text_symbol_type,
+ struct type *data_symbol_type)
+{
+ CORE_ADDR addr;
+
+ write_exp_elt_opcode (OP_LONG);
+ /* Let's make the type big enough to hold a 64-bit address. */
+ write_exp_elt_type (builtin_type_CORE_ADDR);
+
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (overlay_debugging)
+ addr = symbol_overlayed_address (addr, SYMBOL_BFD_SECTION (msymbol));
+ write_exp_elt_longcst ((LONGEST) addr);
+
+ 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 <digits>, starting
+ from the first value which has index 1.
+
+ $$digits Value history with index <digits> 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 (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. */
+ i = frame_map_name_to_regnum (deprecated_selected_frame,
+ str.ptr + 1, str.length - 1);
+ if (i >= 0)
+ goto handle_register;
+
+ if (SYMBOLS_CAN_START_WITH_DOLLAR)
+ {
+ struct symbol *sym = NULL;
+ struct minimal_symbol *msym = NULL;
+
+ /* On HP-UX, certain system routines (millicode) have names beginning
+ with $ or $$, e.g. $$dyncall, which handles inter-space procedure
+ calls on PA-RISC. Check for those, first. */
+
+ /* This code is not enabled on non HP-UX systems, since worst case
+ symbol table lookup performance is awful, to put it mildly. */
+
+ sym = lookup_symbol (copy_name (str), (struct block *) NULL,
+ VAR_DOMAIN, (int *) NULL, (struct symtab **) NULL);
+ if (sym)
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (block_found); /* set by lookup_symbol */
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ return;
+ }
+ msym = lookup_minimal_symbol (copy_name (str), NULL, NULL);
+ if (msym)
+ {
+ write_exp_msymbol (msym,
+ lookup_function_type (builtin_type_int),
+ builtin_type_int);
+ return;
+ }
+ }
+
+ /* 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;
+}
+
+
+/* Parse a string that is possibly a namespace / nested class
+ specification, i.e., something of the form A::B::C::x. Input
+ (NAME) is the entire string; LEN is the current valid length; the
+ output is a string, TOKEN, which points to the largest recognized
+ prefix which is a series of namespaces or classes. CLASS_PREFIX is
+ another output, which records whether a nested class spec was
+ recognized (= 1) or a fully qualified variable name was found (=
+ 0). ARGPTR is side-effected (if non-NULL) to point to beyond the
+ string recognized and consumed by this routine.
+
+ The return value is a pointer to the symbol for the base class or
+ variable if found, or NULL if not found. Callers must check this
+ first -- if NULL, the outputs may not be correct.
+
+ This function is used c-exp.y. This is used specifically to get
+ around HP aCC (and possibly other compilers), which insists on
+ generating names with embedded colons for namespace or nested class
+ members.
+
+ (Argument LEN is currently unused. 1997-08-27)
+
+ Callers must free memory allocated for the output string TOKEN. */
+
+static const char coloncolon[2] =
+{':', ':'};
+
+struct symbol *
+parse_nested_classes_for_hpacc (char *name, int len, char **token,
+ int *class_prefix, char **argptr)
+{
+ /* Comment below comes from decode_line_1 which has very similar
+ code, which is called for "break" command parsing. */
+
+ /* We have what looks like a class or namespace
+ scope specification (A::B), possibly with many
+ levels of namespaces or classes (A::B::C::D).
+
+ Some versions of the HP ANSI C++ compiler (as also possibly
+ other compilers) generate class/function/member names with
+ embedded double-colons if they are inside namespaces. To
+ handle this, we loop a few times, considering larger and
+ larger prefixes of the string as though they were single
+ symbols. So, if the initially supplied string is
+ A::B::C::D::foo, we have to look up "A", then "A::B",
+ then "A::B::C", then "A::B::C::D", and finally
+ "A::B::C::D::foo" as single, monolithic symbols, because
+ A, B, C or D may be namespaces.
+
+ Note that namespaces can nest only inside other
+ namespaces, and not inside classes. So we need only
+ consider *prefixes* of the string; there is no need to look up
+ "B::C" separately as a symbol in the previous example. */
+
+ char *p;
+ char *start, *end;
+ char *prefix = NULL;
+ char *tmp;
+ struct symbol *sym_class = NULL;
+ struct symbol *sym_var = NULL;
+ struct type *t;
+ int prefix_len = 0;
+ int done = 0;
+ char *q;
+
+ /* Check for HP-compiled executable -- in other cases
+ return NULL, and caller must default to standard GDB
+ behaviour. */
+
+ if (!hp_som_som_object_present)
+ return (struct symbol *) NULL;
+
+ p = name;
+
+ /* Skip over whitespace and possible global "::" */
+ while (*p && (*p == ' ' || *p == '\t'))
+ p++;
+ if (p[0] == ':' && p[1] == ':')
+ p += 2;
+ while (*p && (*p == ' ' || *p == '\t'))
+ p++;
+
+ while (1)
+ {
+ /* Get to the end of the next namespace or class spec. */
+ /* If we're looking at some non-token, fail immediately */
+ start = p;
+ if (!(isalpha (*p) || *p == '$' || *p == '_'))
+ return (struct symbol *) NULL;
+ p++;
+ while (*p && (isalnum (*p) || *p == '$' || *p == '_'))
+ p++;
+
+ if (*p == '<')
+ {
+ /* If we have the start of a template specification,
+ scan right ahead to its end */
+ q = find_template_name_end (p);
+ if (q)
+ p = q;
+ }
+
+ end = p;
+
+ /* Skip over "::" and whitespace for next time around */
+ while (*p && (*p == ' ' || *p == '\t'))
+ p++;
+ if (p[0] == ':' && p[1] == ':')
+ p += 2;
+ while (*p && (*p == ' ' || *p == '\t'))
+ p++;
+
+ /* Done with tokens? */
+ if (!*p || !(isalpha (*p) || *p == '$' || *p == '_'))
+ done = 1;
+
+ tmp = (char *) alloca (prefix_len + end - start + 3);
+ if (prefix)
+ {
+ memcpy (tmp, prefix, prefix_len);
+ memcpy (tmp + prefix_len, coloncolon, 2);
+ memcpy (tmp + prefix_len + 2, start, end - start);
+ tmp[prefix_len + 2 + end - start] = '\000';
+ }
+ else
+ {
+ memcpy (tmp, start, end - start);
+ tmp[end - start] = '\000';
+ }
+
+ prefix = tmp;
+ prefix_len = strlen (prefix);
+
+ /* See if the prefix we have now is something we know about */
+
+ if (!done)
+ {
+ /* More tokens to process, so this must be a class/namespace */
+ sym_class = lookup_symbol (prefix, 0, STRUCT_DOMAIN,
+ 0, (struct symtab **) NULL);
+ }
+ else
+ {
+ /* No more tokens, so try as a variable first */
+ sym_var = lookup_symbol (prefix, 0, VAR_DOMAIN,
+ 0, (struct symtab **) NULL);
+ /* If failed, try as class/namespace */
+ if (!sym_var)
+ sym_class = lookup_symbol (prefix, 0, STRUCT_DOMAIN,
+ 0, (struct symtab **) NULL);
+ }
+
+ if (sym_var ||
+ (sym_class &&
+ (t = check_typedef (SYMBOL_TYPE (sym_class)),
+ (TYPE_CODE (t) == TYPE_CODE_STRUCT
+ || TYPE_CODE (t) == TYPE_CODE_UNION))))
+ {
+ /* We found a valid token */
+ *token = (char *) xmalloc (prefix_len + 1);
+ memcpy (*token, prefix, prefix_len);
+ (*token)[prefix_len] = '\000';
+ break;
+ }
+
+ /* No variable or class/namespace found, no more tokens */
+ if (done)
+ return (struct symbol *) NULL;
+ }
+
+ /* Out of loop, so we must have found a valid token */
+ if (sym_var)
+ *class_prefix = 0;
+ else
+ *class_prefix = 1;
+
+ if (argptr)
+ *argptr = done ? p : end;
+
+ return sym_var ? sym_var : sym_class; /* found */
+}
+
+char *
+find_template_name_end (char *p)
+{
+ int depth = 1;
+ int just_seen_right = 0;
+ int just_seen_colon = 0;
+ int just_seen_space = 0;
+
+ if (!p || (*p != '<'))
+ return 0;
+
+ while (*++p)
+ {
+ switch (*p)
+ {
+ case '\'':
+ case '\"':
+ case '{':
+ case '}':
+ /* In future, may want to allow these?? */
+ return 0;
+ case '<':
+ depth++; /* start nested template */
+ if (just_seen_colon || just_seen_right || just_seen_space)
+ return 0; /* but not after : or :: or > or space */
+ break;
+ case '>':
+ if (just_seen_colon || just_seen_right)
+ return 0; /* end a (nested?) template */
+ just_seen_right = 1; /* but not after : or :: */
+ if (--depth == 0) /* also disallow >>, insist on > > */
+ return ++p; /* if outermost ended, return */
+ break;
+ case ':':
+ if (just_seen_space || (just_seen_colon > 1))
+ return 0; /* nested class spec coming up */
+ just_seen_colon++; /* we allow :: but not :::: */
+ break;
+ case ' ':
+ break;
+ default:
+ if (!((*p >= 'a' && *p <= 'z') || /* allow token chars */
+ (*p >= 'A' && *p <= 'Z') ||
+ (*p >= '0' && *p <= '9') ||
+ (*p == '_') || (*p == ',') || /* commas for template args */
+ (*p == '&') || (*p == '*') || /* pointer and ref types */
+ (*p == '(') || (*p == ')') || /* function types */
+ (*p == '[') || (*p == ']'))) /* array types */
+ return 0;
+ }
+ if (*p != ' ')
+ just_seen_space = 0;
+ if (*p != ':')
+ just_seen_colon = 0;
+ if (*p != '>')
+ just_seen_right = 0;
+ }
+ return 0;
+}
+
+
+
+/* Return a null-terminated temporary copy of the name
+ of a string token. */
+
+char *
+copy_name (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 (struct expression *expr)
+{
+ int len =
+ sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts);
+ struct expression *temp;
+ 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 postfix subexpression
+ of EXPR whose operator is at index ENDPOS - 1 in EXPR. */
+
+int
+length_of_subexp (struct expression *expr, int endpos)
+{
+ int oplen, args, i;
+
+ operator_length (expr, endpos, &oplen, &args);
+
+ while (args > 0)
+ {
+ oplen += length_of_subexp (expr, endpos - oplen);
+ args--;
+ }
+
+ return oplen;
+}
+
+/* Sets *OPLENP to the length of the operator whose (last) index is
+ ENDPOS - 1 in EXPR, and sets *ARGSP to the number of arguments that
+ operator takes. */
+
+void
+operator_length (struct expression *expr, int endpos, int *oplenp, int *argsp)
+{
+ expr->language_defn->la_exp_desc->operator_length (expr, endpos,
+ oplenp, argsp);
+}
+
+/* Default value for operator_length in exp_descriptor vectors. */
+
+void
+operator_length_standard (struct expression *expr, int endpos,
+ int *oplenp, int *argsp)
+{
+ int oplen = 1;
+ int args = 0;
+ int i;
+
+ if (endpos < 1)
+ error ("?error in operator_length_standard");
+
+ 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 OP_OBJC_MSGCALL: /* Objective C message (method) call */
+ oplen = 4;
+ 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_OBJC_NSSTRING: /* Objective C Foundation Class NSString constant */
+ case OP_OBJC_SELECTOR: /* Objective C "@selector" pseudo-op */
+ 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:
+ case OP_OBJC_SELF:
+ oplen = 2;
+ break;
+
+ default:
+ args = 1 + (i < (int) BINOP_END);
+ }
+
+ *oplenp = oplen;
+ *argsp = args;
+}
+
+/* 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 (struct expression *inexpr,
+ struct expression *outexpr, int inend, int outbeg)
+{
+ int oplen;
+ int args;
+ int i;
+ int *arglens;
+ enum exp_opcode opcode;
+
+ operator_length (inexpr, inend, &oplen, &args);
+
+ /* 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 (char **stringptr, struct block *block, int comma)
+{
+ struct cleanup *old_chain;
+
+ lexptr = *stringptr;
+ prev_lexptr = NULL;
+
+ 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 /*ignore*/);
+ funcall_chain = 0;
+
+ if (block)
+ {
+ expression_context_block = block;
+ expression_context_pc = BLOCK_START (block);
+ }
+ else
+ expression_context_block = get_selected_block (&expression_context_pc);
+
+ 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. */
+
+ if (expressiondebug)
+ dump_raw_expression (expout, gdb_stdlog,
+ "before conversion to prefix form");
+
+ prefixify_expression (expout);
+
+ if (expressiondebug)
+ dump_prefix_expression (expout, gdb_stdlog);
+
+ *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 (char *string)
+{
+ 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". */
+
+static void
+check_type_stack_depth (void)
+{
+ 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));
+ }
+}
+
+void
+push_type (enum type_pieces tp)
+{
+ check_type_stack_depth ();
+ type_stack[type_stack_depth++].piece = tp;
+}
+
+void
+push_type_int (int n)
+{
+ check_type_stack_depth ();
+ type_stack[type_stack_depth++].int_val = n;
+}
+
+void
+push_type_address_space (char *string)
+{
+ push_type_int (address_space_name_to_int (string));
+}
+
+enum type_pieces
+pop_type (void)
+{
+ if (type_stack_depth)
+ return type_stack[--type_stack_depth].piece;
+ return tp_end;
+}
+
+int
+pop_type_int (void)
+{
+ 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 (struct type *follow_type)
+{
+ int done = 0;
+ int make_const = 0;
+ int make_volatile = 0;
+ int make_addr_space = 0;
+ int array_size;
+ struct type *range_type;
+
+ while (!done)
+ switch (pop_type ())
+ {
+ case tp_end:
+ done = 1;
+ if (make_const)
+ follow_type = make_cv_type (make_const,
+ TYPE_VOLATILE (follow_type),
+ follow_type, 0);
+ if (make_volatile)
+ follow_type = make_cv_type (TYPE_CONST (follow_type),
+ make_volatile,
+ follow_type, 0);
+ if (make_addr_space)
+ follow_type = make_type_with_address_space (follow_type,
+ make_addr_space);
+ make_const = make_volatile = 0;
+ make_addr_space = 0;
+ break;
+ case tp_const:
+ make_const = 1;
+ break;
+ case tp_volatile:
+ make_volatile = 1;
+ break;
+ case tp_space_identifier:
+ make_addr_space = pop_type_int ();
+ break;
+ case tp_pointer:
+ follow_type = lookup_pointer_type (follow_type);
+ if (make_const)
+ follow_type = make_cv_type (make_const,
+ TYPE_VOLATILE (follow_type),
+ follow_type, 0);
+ if (make_volatile)
+ follow_type = make_cv_type (TYPE_CONST (follow_type),
+ make_volatile,
+ follow_type, 0);
+ if (make_addr_space)
+ follow_type = make_type_with_address_space (follow_type,
+ make_addr_space);
+ make_const = make_volatile = 0;
+ make_addr_space = 0;
+ break;
+ case tp_reference:
+ follow_type = lookup_reference_type (follow_type);
+ if (make_const)
+ follow_type = make_cv_type (make_const,
+ TYPE_VOLATILE (follow_type),
+ follow_type, 0);
+ if (make_volatile)
+ follow_type = make_cv_type (TYPE_CONST (follow_type),
+ make_volatile,
+ follow_type, 0);
+ if (make_addr_space)
+ follow_type = make_type_with_address_space (follow_type,
+ make_addr_space);
+ make_const = make_volatile = 0;
+ make_addr_space = 0;
+ 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;
+}
+
+static void build_parse (void);
+static void
+build_parse (void)
+{
+ int i;
+
+ msym_text_symbol_type =
+ init_type (TYPE_CODE_FUNC, 1, 0, "<text variable, no debug info>", 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,
+ "<data variable, no debug info>", NULL);
+ msym_unknown_symbol_type =
+ init_type (TYPE_CODE_INT, 1, 0,
+ "<variable (not text or data), no debug info>",
+ NULL);
+}
+
+/* This function avoids direct calls to fprintf
+ in the parser generated debug code. */
+void
+parser_fprintf (FILE *x, const char *y, ...)
+{
+ va_list args;
+ va_start (args, y);
+ if (x == stderr)
+ vfprintf_unfiltered (gdb_stderr, y, args);
+ else
+ {
+ fprintf_unfiltered (gdb_stderr, " Unknown FILE used.\n");
+ vfprintf_unfiltered (gdb_stderr, y, args);
+ }
+ va_end (args);
+}
+
+void
+_initialize_parse (void)
+{
+ type_stack_size = 80;
+ type_stack_depth = 0;
+ type_stack = (union type_stack_elt *)
+ xmalloc (type_stack_size * sizeof (*type_stack));
+
+ build_parse ();
+
+ /* FIXME - For the moment, handle types by swapping them in and out.
+ Should be using the per-architecture data-pointer and a large
+ struct. */
+ DEPRECATED_REGISTER_GDBARCH_SWAP (msym_text_symbol_type);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (msym_data_symbol_type);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (msym_unknown_symbol_type);
+ deprecated_register_gdbarch_swap (NULL, 0, build_parse);
+
+ add_show_from_set (
+ add_set_cmd ("expression", class_maintenance, var_zinteger,
+ (char *) &expressiondebug,
+ "Set expression debugging.\n\
+When non-zero, the internal representation of expressions will be printed.",
+ &setdebuglist),
+ &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/parser-defs.h b/contrib/gdb/gdb/parser-defs.h
new file mode 100644
index 0000000..c84fcad
--- /dev/null
+++ b/contrib/gdb/gdb/parser-defs.h
@@ -0,0 +1,279 @@
+/* Parser definitions for GDB.
+
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2002 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
+
+#include "doublest.h"
+
+struct block;
+
+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;
+
+/* If expression_context_block is non-zero, then this is the PC within
+ the block that we want to evaluate expressions at. When debugging
+ C or C++ code, we use this to find the exact line we're at, and
+ then look up the macro definitions active at that point. */
+extern CORE_ADDR expression_context_pc;
+
+/* The innermost context required by the stack and register variables
+ we've encountered so far. */
+extern struct block *innermost_block;
+
+/* 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;
+ };
+
+struct objc_class_str
+ {
+ struct stoken stoken;
+ struct type *type;
+ int class;
+ };
+
+
+/* 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,
+ tp_const,
+ tp_volatile,
+ tp_space_identifier
+ };
+/* 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 (union exp_element);
+
+extern void write_exp_elt_opcode (enum exp_opcode);
+
+extern void write_exp_elt_sym (struct symbol *);
+
+extern void write_exp_elt_longcst (LONGEST);
+
+extern void write_exp_elt_dblcst (DOUBLEST);
+
+extern void write_exp_elt_type (struct type *);
+
+extern void write_exp_elt_intern (struct internalvar *);
+
+extern void write_exp_string (struct stoken);
+
+extern void write_exp_bitstring (struct stoken);
+
+extern void write_exp_elt_block (struct block *);
+
+extern void write_exp_msymbol (struct minimal_symbol *,
+ struct type *, struct type *);
+
+extern void write_dollar_variable (struct stoken str);
+
+extern struct symbol *parse_nested_classes_for_hpacc (char *, int, char **,
+ int *, char **);
+
+extern char *find_template_name_end (char *);
+
+extern void start_arglist (void);
+
+extern int end_arglist (void);
+
+extern char *copy_name (struct stoken);
+
+extern void push_type (enum type_pieces);
+
+extern void push_type_int (int);
+
+extern void push_type_address_space (char *);
+
+extern enum type_pieces pop_type (void);
+
+extern int pop_type_int (void);
+
+extern int length_of_subexp (struct expression *, int);
+
+extern int dump_subexp (struct expression *, struct ui_file *, int);
+
+extern int dump_subexp_body_standard (struct expression *,
+ struct ui_file *, int);
+
+extern void operator_length (struct expression *, int, int *, int *);
+
+extern void operator_length_standard (struct expression *, int, int *, int *);
+
+extern char *op_name_standard (enum exp_opcode);
+
+extern struct type *follow_types (struct type *);
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+extern char *lexptr;
+
+/* After a token has been recognized, this variable points to it.
+ Currently used only for error reporting. */
+extern char *prev_lexptr;
+
+/* Tokens that refer to names do so with explicit pointer and length,
+ so they can share the storage that lexptr is parsing.
+
+ When it is necessary to pass a name to a function that expects
+ a null-terminated string, the substring is copied out
+ into a block of storage that namecopy points to.
+
+ namecopy is allocated once, guaranteed big enough, for each parsing. */
+
+extern char *namecopy;
+
+/* Current depth in parentheses within the expression. */
+
+extern int paren_depth;
+
+/* 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;
+ };
+
+/* Information needed to print, prefixify, and evaluate expressions for
+ a given language. */
+
+struct exp_descriptor
+ {
+ /* Print subexpression. */
+ void (*print_subexp) (struct expression *, int *, struct ui_file *,
+ enum precedence);
+
+ /* Returns number of exp_elements needed to represent an operator and
+ the number of subexpressions it takes. */
+ void (*operator_length) (struct expression*, int, int*, int *);
+
+ /* Name of this operator for dumping purposes. */
+ char *(*op_name) (enum exp_opcode);
+
+ /* Dump the rest of this (prefix) expression after the operator
+ itself has been printed. See dump_subexp_body_standard in
+ (expprint.c). */
+ int (*dump_subexp_body) (struct expression *, struct ui_file *, int);
+
+ /* Evaluate an expression. */
+ struct value *(*evaluate_exp) (struct type *, struct expression *,
+ int *, enum noside);
+ };
+
+
+/* Default descriptor containing standard definitions of all
+ elements. */
+extern const struct exp_descriptor exp_descriptor_standard;
+
+/* Functions used by language-specific extended operators to (recursively)
+ print/dump subexpressions. */
+
+extern void print_subexp (struct expression *, int *, struct ui_file *,
+ enum precedence);
+
+extern void print_subexp_standard (struct expression *, int *,
+ struct ui_file *, enum precedence);
+
+/* Function used to avoid direct calls to fprintf
+ in the code generated by the bison parser. */
+
+extern void parser_fprintf (FILE *, const char *, ...) ATTR_FORMAT (printf, 2 ,3);
+
+#endif /* PARSER_DEFS_H */
diff --git a/contrib/gdb/gdb/ppc-bdm.c b/contrib/gdb/gdb/ppc-bdm.c
new file mode 100644
index 0000000..2355b2c
--- /dev/null
+++ b/contrib/gdb/gdb/ppc-bdm.c
@@ -0,0 +1,356 @@
+/* Remote target communications for the Macraigor Systems BDM Wiggler
+ talking to a Motorola PPC 8xx ADS board
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_string.h"
+#include <fcntl.h>
+#include "frame.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include <sys/types.h>
+#include "serial.h"
+#include "ocd.h"
+#include "ppc-tdep.h"
+#include "regcache.h"
+
+static void bdm_ppc_open (char *name, int from_tty);
+
+static ptid_t bdm_ppc_wait (ptid_t ptid,
+ struct target_waitstatus *target_status);
+
+static void bdm_ppc_fetch_registers (int regno);
+
+static void bdm_ppc_store_registers (int regno);
+
+extern struct target_ops bdm_ppc_ops; /* Forward decl */
+
+/*#define BDM_NUM_REGS 71 */
+#define BDM_NUM_REGS 24
+
+#define BDM_REGMAP \
+ 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, /* r0-r7 */ \
+ 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, /* r8-r15 */ \
+ 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, /* r16-r23 */ \
+ 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, /* r24-r31 */ \
+\
+ 2080, 2082, 2084, 2086, 2088, 2090, 2092, 2094, /* fp0->fp8 */ \
+ 2096, 2098, 2100, 2102, 2104, 2106, 2108, 2110, /* fp0->fp8 */ \
+ 2112, 2114, 2116, 2118, 2120, 2122, 2124, 2126, /* fp0->fp8 */ \
+ 2128, 2130, 2132, 2134, 2136, 2138, 2140, 2142, /* fp0->fp8 */ \
+\
+ 26, /* pc (SRR0 (SPR 26)) */ \
+ 2146, /* ps (MSR) */ \
+ 2144, /* cnd (CR) */ \
+ 8, /* lr (SPR 8) */ \
+ 9, /* cnt (CTR (SPR 9)) */ \
+ 1, /* xer (SPR 1) */ \
+ 0, /* mq (SPR 0) */
+
+
+char nowatchdog[4] =
+{0xff, 0xff, 0xff, 0x88};
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static void
+bdm_ppc_open (char *name, int from_tty)
+{
+ CORE_ADDR watchdogaddr = 0xff000004;
+
+ ocd_open (name, from_tty, OCD_TARGET_MOTO_PPC, &bdm_ppc_ops);
+
+ /* We want interrupts to drop us into debugging mode. */
+ /* Modify the DER register to accomplish this. */
+ ocd_write_bdm_register (149, 0x20024000);
+
+ /* Disable watchdog timer on the board */
+ ocd_write_bytes (watchdogaddr, nowatchdog, 4);
+}
+
+/* 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 ptid_t
+bdm_ppc_wait (ptid_t ptid, struct target_waitstatus *target_status)
+{
+ int stop_reason;
+
+ target_status->kind = TARGET_WAITKIND_STOPPED;
+
+ stop_reason = ocd_wait ();
+
+ if (stop_reason)
+ {
+ target_status->value.sig = TARGET_SIGNAL_INT;
+ return inferior_ptid;
+ }
+
+ target_status->value.sig = TARGET_SIGNAL_TRAP; /* XXX for now */
+
+#if 0
+ {
+ unsigned long ecr, der;
+
+ ecr = ocd_read_bdm_register (148); /* Read the exception cause register */
+ der = ocd_read_bdm_register (149); /* Read the debug enables register */
+ fprintf_unfiltered (gdb_stdout, "ecr = 0x%x, der = 0x%x\n", ecr, der);
+ }
+#endif
+
+ return inferior_ptid;
+}
+
+static int bdm_regmap[] =
+{BDM_REGMAP};
+
+/* Read the remote registers into regs.
+ Fetch register REGNO, or all registers if REGNO == -1
+
+ The Wiggler uses the following codes to access the registers:
+
+ 0 -> 1023 SPR 0 -> 1023
+ 0 - SPR 0 - MQ
+ 1 - SPR 1 - XER
+ 8 - SPR 8 - LR
+ 9 - SPR 9 - CTR (known as cnt in GDB)
+ 26 - SPR 26 - SRR0 - pc
+ 1024 -> 2047 DCR 0 -> DCR 1023 (IBM PPC 4xx only)
+ 2048 -> 2079 R0 -> R31
+ 2080 -> 2143 FP0 -> FP31 (64 bit regs) (IBM PPC 5xx only)
+ 2144 CR (known as cnd in GDB)
+ 2145 FPCSR
+ 2146 MSR (known as ps in GDB)
+ */
+
+static void
+bdm_ppc_fetch_registers (int regno)
+{
+ int i;
+ unsigned char *regs, *beginregs, *endregs, *almostregs;
+ unsigned char midregs[32];
+ unsigned char mqreg[1];
+ int first_regno, last_regno;
+ int first_bdm_regno, last_bdm_regno;
+ int reglen, beginreglen, endreglen;
+
+#if 1
+ for (i = 0; i < (FPLAST_REGNUM - FP0_REGNUM + 1); i++)
+ {
+ midregs[i] = -1;
+ }
+ mqreg[0] = -1;
+#endif
+
+ if (regno == -1)
+ {
+ first_regno = 0;
+ last_regno = NUM_REGS - 1;
+
+ first_bdm_regno = 0;
+ last_bdm_regno = BDM_NUM_REGS - 1;
+ }
+ else
+ {
+ first_regno = regno;
+ last_regno = regno;
+
+ first_bdm_regno = bdm_regmap[regno];
+ last_bdm_regno = bdm_regmap[regno];
+ }
+
+ if (first_bdm_regno == -1)
+ {
+ supply_register (first_regno, NULL);
+ return; /* Unsupported register */
+ }
+
+#if 1
+ /* Can't ask for floating point regs on ppc 8xx, also need to
+ avoid asking for the mq register. */
+ if (first_regno == last_regno) /* only want one reg */
+ {
+/* printf("Asking for register %d\n", first_regno); */
+
+ /* if asking for an invalid register */
+ if ((first_regno == gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
+ || (first_regno == gdbarch_tdep (current_gdbarch)->ppc_fpscr_regnum)
+ || ((first_regno >= FP0_REGNUM) && (first_regno <= FPLAST_REGNUM)))
+ {
+/* printf("invalid reg request!\n"); */
+ supply_register (first_regno, NULL);
+ return; /* Unsupported register */
+ }
+ else
+ {
+ regs = ocd_read_bdm_registers (first_bdm_regno,
+ last_bdm_regno, &reglen);
+ }
+ }
+ else
+ /* want all regs */
+ {
+/* printf("Asking for registers %d to %d\n", first_regno, last_regno); */
+ beginregs = ocd_read_bdm_registers (first_bdm_regno,
+ FP0_REGNUM - 1, &beginreglen);
+ endregs = (strcat (midregs,
+ ocd_read_bdm_registers (FPLAST_REGNUM + 1,
+ last_bdm_regno - 1, &endreglen)));
+ almostregs = (strcat (beginregs, endregs));
+ regs = (strcat (almostregs, mqreg));
+ reglen = beginreglen + 32 + endreglen + 1;
+ }
+
+#endif
+#if 0
+ regs = ocd_read_bdm_registers (first_bdm_regno, last_bdm_regno, &reglen);
+#endif
+
+ for (i = first_regno; i <= last_regno; i++)
+ {
+ int bdm_regno, regoffset;
+
+ bdm_regno = bdm_regmap[i];
+ if (bdm_regno != -1)
+ {
+ regoffset = bdm_regno - first_bdm_regno;
+
+ if (regoffset >= reglen / 4)
+ continue;
+
+ supply_register (i, regs + 4 * regoffset);
+ }
+ else
+ supply_register (i, NULL); /* Unsupported register */
+ }
+}
+
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+ of REGISTERS. FIXME: ignores errors. */
+
+static void
+bdm_ppc_store_registers (int regno)
+{
+ int i;
+ int first_regno, last_regno;
+ int first_bdm_regno, last_bdm_regno;
+
+ if (regno == -1)
+ {
+ first_regno = 0;
+ last_regno = NUM_REGS - 1;
+
+ first_bdm_regno = 0;
+ last_bdm_regno = BDM_NUM_REGS - 1;
+ }
+ else
+ {
+ first_regno = regno;
+ last_regno = regno;
+
+ first_bdm_regno = bdm_regmap[regno];
+ last_bdm_regno = bdm_regmap[regno];
+ }
+
+ if (first_bdm_regno == -1)
+ return; /* Unsupported register */
+
+ for (i = first_regno; i <= last_regno; i++)
+ {
+ int bdm_regno;
+
+ bdm_regno = bdm_regmap[i];
+
+ /* only attempt to write if it's a valid ppc 8xx register */
+ /* (need to avoid FP regs and MQ reg) */
+ if ((i != gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
+ && (i != gdbarch_tdep (current_gdbarch)->ppc_fpscr_regnum)
+ && ((i < FP0_REGNUM) || (i > FPLAST_REGNUM)))
+ {
+/* printf("write valid reg %d\n", bdm_regno); */
+ ocd_write_bdm_registers (bdm_regno, deprecated_registers + DEPRECATED_REGISTER_BYTE (i), 4);
+ }
+/*
+ else if (i == gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
+ printf("don't write invalid reg %d (PPC_MQ_REGNUM)\n", bdm_regno);
+ else
+ printf("don't write invalid reg %d\n", bdm_regno);
+ */
+ }
+}
+
+/* Define the target subroutine names */
+
+struct target_ops bdm_ppc_ops;
+
+static void
+init_bdm_ppc_ops (void)
+{
+ bdm_ppc_ops.to_shortname = "ocd";
+ bdm_ppc_ops.to_longname = "Remote target with On-Chip Debugging";
+ bdm_ppc_ops.to_doc = "Use a remote target with On-Chip Debugging. To use a target box;\n\
+specify the serial device it is connected to (e.g. /dev/ttya). To use\n\
+a wiggler, specify wiggler and then the port it is connected to\n\
+(e.g. wiggler lpt1)."; /* to_doc */
+ bdm_ppc_ops.to_open = bdm_ppc_open;
+ bdm_ppc_ops.to_close = ocd_close;
+ bdm_ppc_ops.to_detach = ocd_detach;
+ bdm_ppc_ops.to_resume = ocd_resume;
+ bdm_ppc_ops.to_wait = bdm_ppc_wait;
+ bdm_ppc_ops.to_fetch_registers = bdm_ppc_fetch_registers;
+ bdm_ppc_ops.to_store_registers = bdm_ppc_store_registers;
+ bdm_ppc_ops.to_prepare_to_store = ocd_prepare_to_store;
+ bdm_ppc_ops.to_xfer_memory = ocd_xfer_memory;
+ bdm_ppc_ops.to_files_info = ocd_files_info;
+ bdm_ppc_ops.to_insert_breakpoint = ocd_insert_breakpoint;
+ bdm_ppc_ops.to_remove_breakpoint = ocd_remove_breakpoint;
+ bdm_ppc_ops.to_kill = ocd_kill;
+ bdm_ppc_ops.to_load = ocd_load;
+ bdm_ppc_ops.to_create_inferior = ocd_create_inferior;
+ bdm_ppc_ops.to_mourn_inferior = ocd_mourn;
+ bdm_ppc_ops.to_thread_alive = ocd_thread_alive;
+ bdm_ppc_ops.to_stop = ocd_stop;
+ bdm_ppc_ops.to_stratum = process_stratum;
+ bdm_ppc_ops.to_has_all_memory = 1;
+ bdm_ppc_ops.to_has_memory = 1;
+ bdm_ppc_ops.to_has_stack = 1;
+ bdm_ppc_ops.to_has_registers = 1;
+ bdm_ppc_ops.to_has_execution = 1;
+ bdm_ppc_ops.to_magic = OPS_MAGIC;
+} /* init_bdm_ppc_ops */
+
+extern initialize_file_ftype _initialize_bdm_ppc; /* -Wmissing-prototypes */
+
+void
+_initialize_bdm_ppc (void)
+{
+ init_bdm_ppc_ops ();
+ add_target (&bdm_ppc_ops);
+}
diff --git a/contrib/gdb/gdb/ppc-sysv-tdep.c b/contrib/gdb/gdb/ppc-sysv-tdep.c
new file mode 100644
index 0000000..60cf986
--- /dev/null
+++ b/contrib/gdb/gdb/ppc-sysv-tdep.c
@@ -0,0 +1,1002 @@
+/* Target-dependent code for PowerPC systems using the SVR4 ABI
+ for GDB, the GNU debugger.
+
+ Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "inferior.h"
+#include "regcache.h"
+#include "value.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "ppc-tdep.h"
+#include "target.h"
+#include "objfiles.h"
+
+/* Pass the arguments in either registers, or in the stack. Using the
+ ppc sysv ABI, the first eight words of the argument list (that might
+ be less than eight parameters if some parameters occupy more than one
+ word) are passed in r3..r10 registers. float and double parameters are
+ passed in fpr's, in addition to that. Rest of the parameters if any
+ are passed in user stack.
+
+ If the function is returning a structure, then the return address is passed
+ in r3, then the first 7 words of the parametes can be passed in registers,
+ starting from r4. */
+
+CORE_ADDR
+ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ const CORE_ADDR saved_sp = read_sp ();
+ int argspace = 0; /* 0 is an initial wrong guess. */
+ int write_pass;
+
+ /* Go through the argument list twice.
+
+ Pass 1: Figure out how much new stack space is required for
+ arguments and pushed values. Unlike the PowerOpen ABI, the SysV
+ ABI doesn't reserve any extra space for parameters which are put
+ in registers, but does always push structures and then pass their
+ address.
+
+ Pass 2: Replay the same computation but this time also write the
+ values out to the target. */
+
+ for (write_pass = 0; write_pass < 2; write_pass++)
+ {
+ int argno;
+ /* Next available floating point register for float and double
+ arguments. */
+ int freg = 1;
+ /* Next available general register for non-float, non-vector
+ arguments. */
+ int greg = 3;
+ /* Next available vector register for vector arguments. */
+ int vreg = 2;
+ /* Arguments start above the "LR save word" and "Back chain". */
+ int argoffset = 2 * tdep->wordsize;
+ /* Structures start after the arguments. */
+ int structoffset = argoffset + argspace;
+
+ /* If the function is returning a `struct', then the first word
+ (which will be passed in r3) is used for struct return
+ address. In that case we should advance one word and start
+ from r4 register to copy parameters. */
+ if (struct_return)
+ {
+ if (write_pass)
+ regcache_cooked_write_signed (regcache,
+ tdep->ppc_gp0_regnum + greg,
+ struct_addr);
+ greg++;
+ }
+
+ for (argno = 0; argno < nargs; argno++)
+ {
+ struct value *arg = args[argno];
+ struct type *type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (type);
+ char *val = VALUE_CONTENTS (arg);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && ppc_floating_point_unit_p (current_gdbarch) && len <= 8)
+ {
+ /* Floating point value converted to "double" then
+ passed in an FP register, when the registers run out,
+ 8 byte aligned stack is used. */
+ if (freg <= 8)
+ {
+ if (write_pass)
+ {
+ /* Always store the floating point value using
+ the register's floating-point format. */
+ char regval[MAX_REGISTER_SIZE];
+ struct type *regtype
+ = register_type (gdbarch, FP0_REGNUM + freg);
+ convert_typed_floating (val, type, regval, regtype);
+ regcache_cooked_write (regcache, FP0_REGNUM + freg,
+ regval);
+ }
+ freg++;
+ }
+ else
+ {
+ /* SysV ABI converts floats to doubles before
+ writing them to an 8 byte aligned stack location. */
+ argoffset = align_up (argoffset, 8);
+ if (write_pass)
+ {
+ char memval[8];
+ struct type *memtype;
+ switch (TARGET_BYTE_ORDER)
+ {
+ case BFD_ENDIAN_BIG:
+ memtype = builtin_type_ieee_double_big;
+ break;
+ case BFD_ENDIAN_LITTLE:
+ memtype = builtin_type_ieee_double_little;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ convert_typed_floating (val, type, memval, memtype);
+ write_memory (sp + argoffset, val, len);
+ }
+ argoffset += 8;
+ }
+ }
+ else if (len == 8 && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
+ || (!ppc_floating_point_unit_p (current_gdbarch) && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
+ {
+ /* "long long" or "double" passed in an odd/even
+ register pair with the low addressed word in the odd
+ register and the high addressed word in the even
+ register, or when the registers run out an 8 byte
+ aligned stack location. */
+ if (greg > 9)
+ {
+ /* Just in case GREG was 10. */
+ greg = 11;
+ argoffset = align_up (argoffset, 8);
+ if (write_pass)
+ write_memory (sp + argoffset, val, len);
+ argoffset += 8;
+ }
+ else if (tdep->wordsize == 8)
+ {
+ if (write_pass)
+ regcache_cooked_write (regcache,
+ tdep->ppc_gp0_regnum + greg, val);
+ greg += 1;
+ }
+ else
+ {
+ /* Must start on an odd register - r3/r4 etc. */
+ if ((greg & 1) == 0)
+ greg++;
+ if (write_pass)
+ {
+ regcache_cooked_write (regcache,
+ tdep->ppc_gp0_regnum + greg + 0,
+ val + 0);
+ regcache_cooked_write (regcache,
+ tdep->ppc_gp0_regnum + greg + 1,
+ val + 4);
+ }
+ greg += 2;
+ }
+ }
+ else if (len == 16
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type) && tdep->ppc_vr0_regnum >= 0)
+ {
+ /* Vector parameter passed in an Altivec register, or
+ when that runs out, 16 byte aligned stack location. */
+ if (vreg <= 13)
+ {
+ if (write_pass)
+ regcache_cooked_write (current_regcache,
+ tdep->ppc_vr0_regnum + vreg, val);
+ vreg++;
+ }
+ else
+ {
+ argoffset = align_up (argoffset, 16);
+ if (write_pass)
+ write_memory (sp + argoffset, val, 16);
+ argoffset += 16;
+ }
+ }
+ else if (len == 8
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type) && tdep->ppc_ev0_regnum >= 0)
+ {
+ /* Vector parameter passed in an e500 register, or when
+ that runs out, 8 byte aligned stack location. Note
+ that since e500 vector and general purpose registers
+ both map onto the same underlying register set, a
+ "greg" and not a "vreg" is consumed here. A cooked
+ write stores the value in the correct locations
+ within the raw register cache. */
+ if (greg <= 10)
+ {
+ if (write_pass)
+ regcache_cooked_write (current_regcache,
+ tdep->ppc_ev0_regnum + greg, val);
+ greg++;
+ }
+ else
+ {
+ argoffset = align_up (argoffset, 8);
+ if (write_pass)
+ write_memory (sp + argoffset, val, 8);
+ argoffset += 8;
+ }
+ }
+ else
+ {
+ /* Reduce the parameter down to something that fits in a
+ "word". */
+ char word[MAX_REGISTER_SIZE];
+ memset (word, 0, MAX_REGISTER_SIZE);
+ if (len > tdep->wordsize
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ /* Structs and large values are put on an 8 byte
+ aligned stack ... */
+ structoffset = align_up (structoffset, 8);
+ if (write_pass)
+ write_memory (sp + structoffset, val, len);
+ /* ... and then a "word" pointing to that address is
+ passed as the parameter. */
+ store_unsigned_integer (word, tdep->wordsize,
+ sp + structoffset);
+ structoffset += len;
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_INT)
+ /* Sign or zero extend the "int" into a "word". */
+ store_unsigned_integer (word, tdep->wordsize,
+ unpack_long (type, val));
+ else
+ /* Always goes in the low address. */
+ memcpy (word, val, len);
+ /* Store that "word" in a register, or on the stack.
+ The words have "4" byte alignment. */
+ if (greg <= 10)
+ {
+ if (write_pass)
+ regcache_cooked_write (regcache,
+ tdep->ppc_gp0_regnum + greg, word);
+ greg++;
+ }
+ else
+ {
+ argoffset = align_up (argoffset, tdep->wordsize);
+ if (write_pass)
+ write_memory (sp + argoffset, word, tdep->wordsize);
+ argoffset += tdep->wordsize;
+ }
+ }
+ }
+
+ /* Compute the actual stack space requirements. */
+ if (!write_pass)
+ {
+ /* Remember the amount of space needed by the arguments. */
+ argspace = argoffset;
+ /* Allocate space for both the arguments and the structures. */
+ sp -= (argoffset + structoffset);
+ /* Ensure that the stack is still 16 byte aligned. */
+ sp = align_down (sp, 16);
+ }
+ }
+
+ /* Update %sp. */
+ regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+ /* Write the backchain (it occupies WORDSIZED bytes). */
+ write_memory_signed_integer (sp, tdep->wordsize, saved_sp);
+
+ /* Point the inferior function call's return address at the dummy's
+ breakpoint. */
+ regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+ return sp;
+}
+
+/* Handle the return-value conventions specified by the SysV 32-bit
+ PowerPC ABI (including all the supplements):
+
+ no floating-point: floating-point values returned using 32-bit
+ general-purpose registers.
+
+ Altivec: 128-bit vectors returned using vector registers.
+
+ e500: 64-bit vectors returned using the full full 64 bit EV
+ register, floating-point values returned using 32-bit
+ general-purpose registers.
+
+ GCC (broken): Small struct values right (instead of left) aligned
+ when returned in general-purpose registers. */
+
+static enum return_value_convention
+do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf, int broken_gcc)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ gdb_assert (tdep->wordsize == 4);
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) <= 8
+ && ppc_floating_point_unit_p (gdbarch))
+ {
+ if (readbuf)
+ {
+ /* Floats and doubles stored in "f1". Convert the value to
+ the required type. */
+ char regval[MAX_REGISTER_SIZE];
+ struct type *regtype = register_type (gdbarch, FP0_REGNUM + 1);
+ regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
+ convert_typed_floating (regval, regtype, readbuf, type);
+ }
+ if (writebuf)
+ {
+ /* Floats and doubles stored in "f1". Convert the value to
+ the register's "double" type. */
+ char regval[MAX_REGISTER_SIZE];
+ struct type *regtype = register_type (gdbarch, FP0_REGNUM);
+ convert_typed_floating (writebuf, type, regval, regtype);
+ regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if ((TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
+ || (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8))
+ {
+ if (readbuf)
+ {
+ /* A long long, or a double stored in the 32 bit r3/r4. */
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
+ (bfd_byte *) readbuf + 0);
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+ (bfd_byte *) readbuf + 4);
+ }
+ if (writebuf)
+ {
+ /* A long long, or a double stored in the 32 bit r3/r4. */
+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
+ (const bfd_byte *) writebuf + 0);
+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+ (const bfd_byte *) writebuf + 4);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_CODE (type) == TYPE_CODE_INT
+ && TYPE_LENGTH (type) <= tdep->wordsize)
+ {
+ if (readbuf)
+ {
+ /* Some sort of integer stored in r3. Since TYPE isn't
+ bigger than the register, sign extension isn't a problem
+ - just do everything unsigned. */
+ ULONGEST regval;
+ regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+ &regval);
+ store_unsigned_integer (readbuf, TYPE_LENGTH (type), regval);
+ }
+ if (writebuf)
+ {
+ /* Some sort of integer stored in r3. Use unpack_long since
+ that should handle any required sign extension. */
+ regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+ unpack_long (type, writebuf));
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_LENGTH (type) == 16
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type) && tdep->ppc_vr0_regnum >= 0)
+ {
+ if (readbuf)
+ {
+ /* Altivec places the return value in "v2". */
+ regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
+ }
+ if (writebuf)
+ {
+ /* Altivec places the return value in "v2". */
+ regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, writebuf);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_LENGTH (type) == 8
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type) && tdep->ppc_ev0_regnum >= 0)
+ {
+ /* The e500 ABI places return values for the 64-bit DSP types
+ (__ev64_opaque__) in r3. However, in GDB-speak, ev3
+ corresponds to the entire r3 value for e500, whereas GDB's r3
+ only corresponds to the least significant 32-bits. So place
+ the 64-bit DSP type's value in ev3. */
+ if (readbuf)
+ regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 3, readbuf);
+ if (writebuf)
+ regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 3, writebuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (broken_gcc && TYPE_LENGTH (type) <= 8)
+ {
+ if (readbuf)
+ {
+ /* GCC screwed up. The last register isn't "left" aligned.
+ Need to extract the least significant part of each
+ register and then store that. */
+ /* Transfer any full words. */
+ int word = 0;
+ while (1)
+ {
+ ULONGEST reg;
+ int len = TYPE_LENGTH (type) - word * tdep->wordsize;
+ if (len <= 0)
+ break;
+ if (len > tdep->wordsize)
+ len = tdep->wordsize;
+ regcache_cooked_read_unsigned (regcache,
+ tdep->ppc_gp0_regnum + 3 + word,
+ &reg);
+ store_unsigned_integer (((bfd_byte *) readbuf
+ + word * tdep->wordsize), len, reg);
+ word++;
+ }
+ }
+ if (writebuf)
+ {
+ /* GCC screwed up. The last register isn't "left" aligned.
+ Need to extract the least significant part of each
+ register and then store that. */
+ /* Transfer any full words. */
+ int word = 0;
+ while (1)
+ {
+ ULONGEST reg;
+ int len = TYPE_LENGTH (type) - word * tdep->wordsize;
+ if (len <= 0)
+ break;
+ if (len > tdep->wordsize)
+ len = tdep->wordsize;
+ reg = extract_unsigned_integer (((const bfd_byte *) writebuf
+ + word * tdep->wordsize), len);
+ regcache_cooked_write_unsigned (regcache,
+ tdep->ppc_gp0_regnum + 3 + word,
+ reg);
+ word++;
+ }
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_LENGTH (type) <= 8)
+ {
+ if (readbuf)
+ {
+ /* This matches SVr4 PPC, it does not match GCC. */
+ /* The value is right-padded to 8 bytes and then loaded, as
+ two "words", into r3/r4. */
+ char regvals[MAX_REGISTER_SIZE * 2];
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
+ regvals + 0 * tdep->wordsize);
+ if (TYPE_LENGTH (type) > tdep->wordsize)
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+ regvals + 1 * tdep->wordsize);
+ memcpy (readbuf, regvals, TYPE_LENGTH (type));
+ }
+ if (writebuf)
+ {
+ /* This matches SVr4 PPC, it does not match GCC. */
+ /* The value is padded out to 8 bytes and then loaded, as
+ two "words" into r3/r4. */
+ char regvals[MAX_REGISTER_SIZE * 2];
+ memset (regvals, 0, sizeof regvals);
+ memcpy (regvals, writebuf, TYPE_LENGTH (type));
+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
+ regvals + 0 * tdep->wordsize);
+ if (TYPE_LENGTH (type) > tdep->wordsize)
+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+ regvals + 1 * tdep->wordsize);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ return RETURN_VALUE_STRUCT_CONVENTION;
+}
+
+enum return_value_convention
+ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
+ writebuf, 0);
+}
+
+enum return_value_convention
+ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
+ struct type *valtype,
+ struct regcache *regcache,
+ void *readbuf, const void *writebuf)
+{
+ return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
+ writebuf, 1);
+}
+
+/* Pass the arguments in either registers, or in the stack. Using the
+ ppc 64 bit SysV ABI.
+
+ This implements a dumbed down version of the ABI. It always writes
+ values to memory, GPR and FPR, even when not necessary. Doing this
+ greatly simplifies the logic. */
+
+CORE_ADDR
+ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ /* By this stage in the proceedings, SP has been decremented by "red
+ zone size" + "struct return size". Fetch the stack-pointer from
+ before this and use that as the BACK_CHAIN. */
+ const CORE_ADDR back_chain = read_sp ();
+ /* See for-loop comment below. */
+ int write_pass;
+ /* Size of the Altivec's vector parameter region, the final value is
+ computed in the for-loop below. */
+ LONGEST vparam_size = 0;
+ /* Size of the general parameter region, the final value is computed
+ in the for-loop below. */
+ LONGEST gparam_size = 0;
+ /* Kevin writes ... I don't mind seeing tdep->wordsize used in the
+ calls to align_up(), align_down(), etc. because this makes it
+ easier to reuse this code (in a copy/paste sense) in the future,
+ but it is a 64-bit ABI and asserting that the wordsize is 8 bytes
+ at some point makes it easier to verify that this function is
+ correct without having to do a non-local analysis to figure out
+ the possible values of tdep->wordsize. */
+ gdb_assert (tdep->wordsize == 8);
+
+ /* Go through the argument list twice.
+
+ Pass 1: Compute the function call's stack space and register
+ requirements.
+
+ Pass 2: Replay the same computation but this time also write the
+ values out to the target. */
+
+ for (write_pass = 0; write_pass < 2; write_pass++)
+ {
+ int argno;
+ /* Next available floating point register for float and double
+ arguments. */
+ int freg = 1;
+ /* Next available general register for non-vector (but possibly
+ float) arguments. */
+ int greg = 3;
+ /* Next available vector register for vector arguments. */
+ int vreg = 2;
+ /* The address, at which the next general purpose parameter
+ (integer, struct, float, ...) should be saved. */
+ CORE_ADDR gparam;
+ /* Address, at which the next Altivec vector parameter should be
+ saved. */
+ CORE_ADDR vparam;
+
+ if (!write_pass)
+ {
+ /* During the first pass, GPARAM and VPARAM are more like
+ offsets (start address zero) than addresses. That way
+ the accumulate the total stack space each region
+ requires. */
+ gparam = 0;
+ vparam = 0;
+ }
+ else
+ {
+ /* Decrement the stack pointer making space for the Altivec
+ and general on-stack parameters. Set vparam and gparam
+ to their corresponding regions. */
+ vparam = align_down (sp - vparam_size, 16);
+ gparam = align_down (vparam - gparam_size, 16);
+ /* Add in space for the TOC, link editor double word,
+ compiler double word, LR save area, CR save area. */
+ sp = align_down (gparam - 48, 16);
+ }
+
+ /* If the function is returning a `struct', then there is an
+ extra hidden parameter (which will be passed in r3)
+ containing the address of that struct.. In that case we
+ should advance one word and start from r4 register to copy
+ parameters. This also consumes one on-stack parameter slot. */
+ if (struct_return)
+ {
+ if (write_pass)
+ regcache_cooked_write_signed (regcache,
+ tdep->ppc_gp0_regnum + greg,
+ struct_addr);
+ greg++;
+ gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+ }
+
+ for (argno = 0; argno < nargs; argno++)
+ {
+ struct value *arg = args[argno];
+ struct type *type = check_typedef (VALUE_TYPE (arg));
+ char *val = VALUE_CONTENTS (arg);
+ if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
+ {
+ /* Floats and Doubles go in f1 .. f13. They also
+ consume a left aligned GREG,, and can end up in
+ memory. */
+ if (write_pass)
+ {
+ if (ppc_floating_point_unit_p (current_gdbarch)
+ && freg <= 13)
+ {
+ char regval[MAX_REGISTER_SIZE];
+ struct type *regtype = register_type (gdbarch,
+ FP0_REGNUM);
+ convert_typed_floating (val, type, regval, regtype);
+ regcache_cooked_write (regcache, FP0_REGNUM + freg,
+ regval);
+ }
+ if (greg <= 10)
+ {
+ /* The ABI states "Single precision floating
+ point values are mapped to the first word in
+ a single doubleword" and "... floating point
+ values mapped to the first eight doublewords
+ of the parameter save area are also passed in
+ general registers").
+
+ This code interprets that to mean: store it,
+ left aligned, in the general register. */
+ char regval[MAX_REGISTER_SIZE];
+ memset (regval, 0, sizeof regval);
+ memcpy (regval, val, TYPE_LENGTH (type));
+ regcache_cooked_write (regcache,
+ tdep->ppc_gp0_regnum + greg,
+ regval);
+ }
+ write_memory (gparam, val, TYPE_LENGTH (type));
+ }
+ /* Always consume parameter stack space. */
+ freg++;
+ greg++;
+ gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+ }
+ else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && tdep->ppc_vr0_regnum >= 0)
+ {
+ /* In the Altivec ABI, vectors go in the vector
+ registers v2 .. v13, or when that runs out, a vector
+ annex which goes above all the normal parameters.
+ NOTE: cagney/2003-09-21: This is a guess based on the
+ PowerOpen Altivec ABI. */
+ if (vreg <= 13)
+ {
+ if (write_pass)
+ regcache_cooked_write (regcache,
+ tdep->ppc_vr0_regnum + vreg, val);
+ vreg++;
+ }
+ else
+ {
+ if (write_pass)
+ write_memory (vparam, val, TYPE_LENGTH (type));
+ vparam = align_up (vparam + TYPE_LENGTH (type), 16);
+ }
+ }
+ else if ((TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ && TYPE_LENGTH (type) <= 8)
+ {
+ /* Scalars get sign[un]extended and go in gpr3 .. gpr10.
+ They can also end up in memory. */
+ if (write_pass)
+ {
+ /* Sign extend the value, then store it unsigned. */
+ ULONGEST word = unpack_long (type, val);
+ if (greg <= 10)
+ regcache_cooked_write_unsigned (regcache,
+ tdep->ppc_gp0_regnum +
+ greg, word);
+ write_memory_unsigned_integer (gparam, tdep->wordsize,
+ word);
+ }
+ greg++;
+ gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+ }
+ else
+ {
+ int byte;
+ for (byte = 0; byte < TYPE_LENGTH (type);
+ byte += tdep->wordsize)
+ {
+ if (write_pass && greg <= 10)
+ {
+ char regval[MAX_REGISTER_SIZE];
+ int len = TYPE_LENGTH (type) - byte;
+ if (len > tdep->wordsize)
+ len = tdep->wordsize;
+ memset (regval, 0, sizeof regval);
+ /* WARNING: cagney/2003-09-21: As best I can
+ tell, the ABI specifies that the value should
+ be left aligned. Unfortunately, GCC doesn't
+ do this - it instead right aligns even sized
+ values and puts odd sized values on the
+ stack. Work around that by putting both a
+ left and right aligned value into the
+ register (hopefully no one notices :-^).
+ Arrrgh! */
+ /* Left aligned (8 byte values such as pointers
+ fill the buffer). */
+ memcpy (regval, val + byte, len);
+ /* Right aligned (but only if even). */
+ if (len == 1 || len == 2 || len == 4)
+ memcpy (regval + tdep->wordsize - len,
+ val + byte, len);
+ regcache_cooked_write (regcache, greg, regval);
+ }
+ greg++;
+ }
+ if (write_pass)
+ /* WARNING: cagney/2003-09-21: Strictly speaking, this
+ isn't necessary, unfortunately, GCC appears to get
+ "struct convention" parameter passing wrong putting
+ odd sized structures in memory instead of in a
+ register. Work around this by always writing the
+ value to memory. Fortunately, doing this
+ simplifies the code. */
+ write_memory (gparam, val, TYPE_LENGTH (type));
+ /* Always consume parameter stack space. */
+ gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+ }
+ }
+
+ if (!write_pass)
+ {
+ /* Save the true region sizes ready for the second pass. */
+ vparam_size = vparam;
+ /* Make certain that the general parameter save area is at
+ least the minimum 8 registers (or doublewords) in size. */
+ if (greg < 8)
+ gparam_size = 8 * tdep->wordsize;
+ else
+ gparam_size = gparam;
+ }
+ }
+
+ /* Update %sp. */
+ regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+ /* Write the backchain (it occupies WORDSIZED bytes). */
+ write_memory_signed_integer (sp, tdep->wordsize, back_chain);
+
+ /* Point the inferior function call's return address at the dummy's
+ breakpoint. */
+ regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+ /* Find a value for the TOC register. Every symbol should have both
+ ".FN" and "FN" in the minimal symbol table. "FN" points at the
+ FN's descriptor, while ".FN" points at the entry point (which
+ matches FUNC_ADDR). Need to reverse from FUNC_ADDR back to the
+ FN's descriptor address (while at the same time being careful to
+ find "FN" in the same object file as ".FN"). */
+ {
+ /* Find the minimal symbol that corresponds to FUNC_ADDR (should
+ have the name ".FN"). */
+ struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr);
+ if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.')
+ {
+ /* Get the section that contains FUNC_ADR. Need this for the
+ "objfile" that it contains. */
+ struct obj_section *dot_fn_section = find_pc_section (func_addr);
+ if (dot_fn_section != NULL && dot_fn_section->objfile != NULL)
+ {
+ /* Now find the corresponding "FN" (dropping ".") minimal
+ symbol's address. Only look for the minimal symbol in
+ ".FN"'s object file - avoids problems when two object
+ files (i.e., shared libraries) contain a minimal symbol
+ with the same name. */
+ struct minimal_symbol *fn =
+ lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL,
+ dot_fn_section->objfile);
+ if (fn != NULL)
+ {
+ /* Got the address of that descriptor. The TOC is the
+ second double word. */
+ CORE_ADDR toc =
+ read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn)
+ + tdep->wordsize,
+ tdep->wordsize);
+ regcache_cooked_write_unsigned (regcache,
+ tdep->ppc_gp0_regnum + 2, toc);
+ }
+ }
+ }
+ }
+
+ return sp;
+}
+
+
+/* The 64 bit ABI retun value convention.
+
+ Return non-zero if the return-value is stored in a register, return
+ 0 if the return-value is instead stored on the stack (a.k.a.,
+ struct return convention).
+
+ For a return-value stored in a register: when WRITEBUF is non-NULL,
+ copy the buffer to the corresponding register return-value location
+ location; when READBUF is non-NULL, fill the buffer from the
+ corresponding register return-value location. */
+enum return_value_convention
+ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* Floats and doubles in F1. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_FLT && TYPE_LENGTH (valtype) <= 8)
+ {
+ char regval[MAX_REGISTER_SIZE];
+ struct type *regtype = register_type (gdbarch, FP0_REGNUM);
+ if (writebuf != NULL)
+ {
+ convert_typed_floating (writebuf, valtype, regval, regtype);
+ regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
+ }
+ if (readbuf != NULL)
+ {
+ regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
+ convert_typed_floating (regval, regtype, readbuf, valtype);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 8)
+ {
+ /* Integers in r3. */
+ if (writebuf != NULL)
+ {
+ /* Be careful to sign extend the value. */
+ regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+ unpack_long (valtype, writebuf));
+ }
+ if (readbuf != NULL)
+ {
+ /* Extract the integer from r3. Since this is truncating the
+ value, there isn't a sign extension problem. */
+ ULONGEST regval;
+ regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+ &regval);
+ store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), regval);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ /* All pointers live in r3. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_PTR)
+ {
+ /* All pointers live in r3. */
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+ && TYPE_LENGTH (valtype) <= 8
+ && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
+ && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
+ {
+ /* Small character arrays are returned, right justified, in r3. */
+ int offset = (register_size (gdbarch, tdep->ppc_gp0_regnum + 3)
+ - TYPE_LENGTH (valtype));
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
+ offset, TYPE_LENGTH (valtype), writebuf);
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
+ offset, TYPE_LENGTH (valtype), readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ /* Big floating point values get stored in adjacent floating
+ point registers. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_FLT
+ && (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32))
+ {
+ if (writebuf || readbuf != NULL)
+ {
+ int i;
+ for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
+ {
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
+ (const bfd_byte *) writebuf + i * 8);
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
+ (bfd_byte *) readbuf + i * 8);
+ }
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ /* Complex values get returned in f1:f2, need to convert. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
+ && (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16))
+ {
+ if (regcache != NULL)
+ {
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ char regval[MAX_REGISTER_SIZE];
+ struct type *regtype =
+ register_type (current_gdbarch, FP0_REGNUM);
+ if (writebuf != NULL)
+ {
+ convert_typed_floating ((const bfd_byte *) writebuf +
+ i * (TYPE_LENGTH (valtype) / 2),
+ valtype, regval, regtype);
+ regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
+ regval);
+ }
+ if (readbuf != NULL)
+ {
+ regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, regval);
+ convert_typed_floating (regval, regtype,
+ (bfd_byte *) readbuf +
+ i * (TYPE_LENGTH (valtype) / 2),
+ valtype);
+ }
+ }
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ /* Big complex values get stored in f1:f4. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX && TYPE_LENGTH (valtype) == 32)
+ {
+ if (regcache != NULL)
+ {
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
+ (const bfd_byte *) writebuf + i * 8);
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
+ (bfd_byte *) readbuf + i * 8);
+ }
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ return RETURN_VALUE_STRUCT_CONVENTION;
+}
+
+CORE_ADDR
+ppc64_sysv_abi_adjust_breakpoint_address (struct gdbarch *gdbarch,
+ CORE_ADDR bpaddr)
+{
+ /* PPC64 SYSV specifies that the minimal-symbol "FN" should point at
+ a function-descriptor while the corresponding minimal-symbol
+ ".FN" should point at the entry point. Consequently, a command
+ like "break FN" applied to an object file with only minimal
+ symbols, will insert the breakpoint into the descriptor at "FN"
+ and not the function at ".FN". Avoid this confusion by adjusting
+ any attempt to set a descriptor breakpoint into a corresponding
+ function breakpoint. Note that GDB warns the user when this
+ adjustment is applied - that's ok as otherwise the user will have
+ no way of knowing why their breakpoint at "FN" resulted in the
+ program stopping at ".FN". */
+ return gdbarch_convert_from_func_ptr_addr (gdbarch, bpaddr, &current_target);
+}
diff --git a/contrib/gdb/gdb/ppc-tdep.h b/contrib/gdb/gdb/ppc-tdep.h
new file mode 100644
index 0000000..1c1c9ef
--- /dev/null
+++ b/contrib/gdb/gdb/ppc-tdep.h
@@ -0,0 +1,113 @@
+/* Target-dependent code for GDB, the GNU debugger.
+ Copyright 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 PPC_TDEP_H
+#define PPC_TDEP_H
+
+struct gdbarch;
+struct frame_info;
+struct value;
+struct regcache;
+struct type;
+
+/* From ppc-linux-tdep.c... */
+CORE_ADDR ppc_linux_frame_saved_pc (struct frame_info *fi);
+void ppc_linux_init_extra_frame_info (int fromleaf, struct frame_info *);
+int ppc_linux_frameless_function_invocation (struct frame_info *);
+void ppc_linux_frame_init_saved_regs (struct frame_info *);
+CORE_ADDR ppc_linux_frame_chain (struct frame_info *);
+enum return_value_convention ppc_sysv_abi_return_value (struct gdbarch *gdbarch,
+ struct type *valtype,
+ struct regcache *regcache,
+ void *readbuf,
+ const void *writebuf);
+enum return_value_convention ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
+ struct type *valtype,
+ struct regcache *regcache,
+ void *readbuf,
+ const void *writebuf);
+CORE_ADDR ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
+ CORE_ADDR func_addr,
+ struct regcache *regcache,
+ CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr);
+CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
+ CORE_ADDR func_addr,
+ struct regcache *regcache,
+ CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr);
+CORE_ADDR ppc64_sysv_abi_adjust_breakpoint_address (struct gdbarch *gdbarch,
+ CORE_ADDR bpaddr);
+int ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache);
+struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
+void ppc_linux_supply_gregset (char *buf);
+void ppc_linux_supply_fpregset (char *buf);
+
+enum return_value_convention ppc64_sysv_abi_return_value (struct gdbarch *gdbarch,
+ struct type *valtype,
+ struct regcache *regcache,
+ void *readbuf,
+ const void *writebuf);
+
+/* From rs6000-tdep.c... */
+CORE_ADDR rs6000_frame_saved_pc (struct frame_info *fi);
+void rs6000_init_extra_frame_info (int fromleaf, struct frame_info *);
+int rs6000_frameless_function_invocation (struct frame_info *);
+void rs6000_frame_init_saved_regs (struct frame_info *);
+CORE_ADDR rs6000_frame_chain (struct frame_info *);
+int altivec_register_p (int regno);
+
+
+/* Return non-zero when the architecture has an FPU (or at least when
+ the ABI is using the FPU). */
+int ppc_floating_point_unit_p (struct gdbarch *gdbarch);
+
+/* Private data that this module attaches to struct gdbarch. */
+
+struct gdbarch_tdep
+ {
+ int wordsize; /* size in bytes of fixed-point word */
+ int *regoff; /* byte offsets in register arrays */
+ const struct reg *regs; /* from current variant */
+ int ppc_gp0_regnum; /* GPR register 0 */
+ int ppc_gplast_regnum; /* GPR register 31 */
+ int ppc_toc_regnum; /* TOC register */
+ int ppc_ps_regnum; /* Processor (or machine) status (%msr) */
+ int ppc_cr_regnum; /* Condition register */
+ int ppc_lr_regnum; /* Link register */
+ int ppc_ctr_regnum; /* Count register */
+ int ppc_xer_regnum; /* Integer exception register */
+ int ppc_fpscr_regnum; /* Floating point status and condition
+ register */
+ int ppc_mq_regnum; /* Multiply/Divide extension register */
+ int ppc_vr0_regnum; /* First AltiVec register */
+ int ppc_vrsave_regnum; /* Last AltiVec register */
+ int ppc_ev0_regnum; /* First ev register */
+ int ppc_ev31_regnum; /* Last ev register */
+ int lr_frame_offset; /* Offset to ABI specific location where
+ link register is saved. */
+};
+
+#endif
diff --git a/contrib/gdb/gdb/ppcbug-rom.c b/contrib/gdb/gdb/ppcbug-rom.c
new file mode 100644
index 0000000..0619964
--- /dev/null
+++ b/contrib/gdb/gdb/ppcbug-rom.c
@@ -0,0 +1,225 @@
+/* Remote debugging interface for PPCbug (PowerPC) Rom monitor
+ for GDB, the GNU debugger.
+ Copyright 1995, 1998, 1999, 2000, 2001 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"
+#include "regcache.h"
+
+static void
+ppcbug_supply_register (char *regname, int regnamelen, char *val, int vallen)
+{
+ int regno = 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[] =
+{
+ "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};
+
+static void
+init_ppc_cmds (char *LOAD_CMD,
+ struct monitor_ops *OPS,
+ struct target_ops *targops)
+{
+ OPS->flags = MO_CLR_BREAK_USES_ADDR | MO_HANDLE_NL;
+ OPS->init = ppcbug_inits; /* Init strings */
+ OPS->cont = "g\r"; /* continue command */
+ OPS->step = "t\r"; /* single step */
+ OPS->stop = NULL; /* interrupt command */
+ OPS->set_break = "br %x\r"; /* set a breakpoint */
+ OPS->clr_break = "nobr %x\r"; /* clear a breakpoint */
+ OPS->clr_all_break = "nobr\r"; /* clear all breakpoints */
+ OPS->fill = "bf %x:%x %x;b\r"; /* fill (start count val) */
+ OPS->setmem.cmdb = "ms %x %02x\r"; /* setmem.cmdb (addr, value) */
+ OPS->setmem.cmdw = "ms %x %04x\r"; /* setmem.cmdw (addr, value) */
+ OPS->setmem.cmdl = "ms %x %08x\r"; /* setmem.cmdl (addr, value) */
+ OPS->setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ OPS->setmem.resp_delim = NULL; /* setreg.resp_delim */
+ OPS->setmem.term = NULL; /* setreg.term */
+ OPS->setmem.term_cmd = NULL; /* setreg.term_cmd */
+ OPS->getmem.cmdb = "md %x:%x;b\r"; /* getmem.cmdb (addr, len) */
+ OPS->getmem.cmdw = "md %x:%x;b\r"; /* getmem.cmdw (addr, len) */
+ OPS->getmem.cmdl = "md %x:%x;b\r"; /* getmem.cmdl (addr, len) */
+ OPS->getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
+ OPS->getmem.resp_delim = " "; /* getmem.resp_delim */
+ OPS->getmem.term = NULL; /* getmem.term */
+ OPS->getmem.term_cmd = NULL; /* getmem.term_cmd */
+ OPS->setreg.cmd = "rs %s %x\r"; /* setreg.cmd (name, value) */
+ OPS->setreg.resp_delim = NULL; /* setreg.resp_delim */
+ OPS->setreg.term = NULL; /* setreg.term */
+ OPS->setreg.term_cmd = NULL; /* setreg.term_cmd */
+ OPS->getreg.cmd = "rs %s\r"; /* getreg.cmd (name) */
+ OPS->getreg.resp_delim = "="; /* getreg.resp_delim */
+ OPS->getreg.term = NULL; /* getreg.term */
+ OPS->getreg.term_cmd = NULL; /* getreg.term_cmd */
+ OPS->register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
+ OPS->supply_register = ppcbug_supply_register; /* supply_register */
+ OPS->dump_registers = "rd\r"; /* dump all registers */
+ OPS->load_routine = NULL; /* load_routine (defaults to SRECs) */
+ OPS->load = LOAD_CMD; /* download command */
+ OPS->loadresp = NULL; /* load response */
+ OPS->prompt = "PPC1-Bug>"; /* monitor command prompt */
+ OPS->line_term = "\r"; /* end-of-line terminator */
+ OPS->cmd_end = NULL; /* optional command terminator */
+ OPS->target = targops; /* target operations */
+ OPS->stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ OPS->regnames = ppcbug_regnames; /* registers names */
+ OPS->magic = MONITOR_OPS_MAGIC; /* magic */
+}
+
+
+static struct monitor_ops ppcbug_cmds0;
+static struct monitor_ops ppcbug_cmds1;
+
+static void
+ppcbug_open0 (char *args, int from_tty)
+{
+ monitor_open (args, &ppcbug_cmds0, from_tty);
+}
+
+static void
+ppcbug_open1 (char *args, int from_tty)
+{
+ monitor_open (args, &ppcbug_cmds1, from_tty);
+}
+
+extern initialize_file_ftype _initialize_ppcbug_rom; /* -Wmissing-prototypes */
+
+void
+_initialize_ppcbug_rom (void)
+{
+ init_ppc_cmds ("lo 0\r", &ppcbug_cmds0, &ppcbug_ops0);
+ init_ppc_cmds ("lo 1\r", &ppcbug_cmds1, &ppcbug_ops1);
+ 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/ppcfbsd-nat.c b/contrib/gdb/gdb/ppcfbsd-nat.c
new file mode 100644
index 0000000..a6efa9d
--- /dev/null
+++ b/contrib/gdb/gdb/ppcfbsd-nat.c
@@ -0,0 +1,169 @@
+/* Native-dependent code for PowerPC's running FreeBSD, for GDB.
+ Copyright 2002, 2004 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+
+#include "defs.h"
+#include "inferior.h"
+#include "gdb_assert.h"
+#include "gdbcore.h"
+#include "regcache.h"
+
+#include "ppc-tdep.h"
+#include "ppcfbsd-tdep.h"
+
+/* Returns true if PT_GETREGS fetches this register. */
+static int
+getregs_supplies (int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ return ((regno >= tdep->ppc_gp0_regnum && regno <= tdep->ppc_gplast_regnum)
+ || regno == tdep->ppc_lr_regnum
+ || regno == tdep->ppc_cr_regnum
+ || regno == tdep->ppc_xer_regnum
+ || regno == tdep->ppc_ctr_regnum
+ || regno == PC_REGNUM);
+}
+
+/* Like above, but for PT_GETFPREGS. */
+static int
+getfpregs_supplies (int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+ point registers. Traditionally, GDB's register set has still
+ listed the floating point registers for such machines, so this
+ code is harmless. However, the new E500 port actually omits the
+ floating point registers entirely from the register set --- they
+ don't even have register numbers assigned to them.
+
+ It's not clear to me how best to update this code, so this assert
+ will alert the first person to encounter the NetBSD/E500
+ combination to the problem. */
+ gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
+
+ return ((regno >= FP0_REGNUM && regno <= FPLAST_REGNUM)
+ || regno == tdep->ppc_fpscr_regnum);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name (_("Couldn't get registers"));
+
+ ppcfbsd_supply_reg ((char *) &regs, regno);
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || getfpregs_supplies (regno))
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name (_("Couldn't get FP registers"));
+
+ ppcfbsd_supply_fpreg ((char *) &fpregs, regno);
+ if (regno != -1)
+ return;
+ }
+}
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name (_("Couldn't get registers"));
+
+ ppcfbsd_fill_reg ((char *) &regs, regno);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name (_("Couldn't write registers"));
+
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || getfpregs_supplies (regno))
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name (_("Couldn't get FP registers"));
+
+ ppcfbsd_fill_fpreg ((char *) &fpregs, regno);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name (_("Couldn't set FP registers"));
+ }
+}
+
+void
+fill_gregset (char *regs, int regnum)
+{
+ ppcfbsd_fill_reg (regs, regnum);
+}
+
+void
+supply_gregset (char *regs)
+{
+ ppcfbsd_supply_reg (regs, -1);
+}
+
+void
+fill_fpregset (char *fpregs, int regnum)
+{
+ ppcfbsd_fill_fpreg (fpregs, regnum);
+}
+
+void
+supply_fpregset (char *fpregs)
+{
+ ppcfbsd_supply_fpreg (fpregs, -1);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_ppcfbsd_nat (void);
+
+void
+_initialize_ppcfbsd_nat (void)
+{
+}
diff --git a/contrib/gdb/gdb/ppcfbsd-tdep.c b/contrib/gdb/gdb/ppcfbsd-tdep.c
new file mode 100644
index 0000000..3828e7f
--- /dev/null
+++ b/contrib/gdb/gdb/ppcfbsd-tdep.c
@@ -0,0 +1,296 @@
+/* Target-dependent code for PowerPC systems running FreeBSD.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "ppc-tdep.h"
+#include "ppcfbsd-tdep.h"
+#include "trad-frame.h"
+#include "gdb_assert.h"
+#include "solib-svr4.h"
+
+#define REG_FIXREG_OFFSET(x) ((x) * sizeof(register_t))
+#define REG_LR_OFFSET (32 * sizeof(register_t))
+#define REG_CR_OFFSET (33 * sizeof(register_t))
+#define REG_XER_OFFSET (34 * sizeof(register_t))
+#define REG_CTR_OFFSET (35 * sizeof(register_t))
+#define REG_PC_OFFSET (36 * sizeof(register_t))
+#define SIZEOF_STRUCT_REG (37 * sizeof(register_t))
+
+#define FPREG_FPR_OFFSET(x) ((x) * 8)
+#define FPREG_FPSCR_OFFSET (32 * 8)
+#define SIZEOF_STRUCT_FPREG (33 * 8)
+
+void
+ppcfbsd_supply_reg (char *regs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ for (i = tdep->ppc_gp0_regnum; i <= tdep->ppc_gplast_regnum; i++)
+ {
+ if (regno == i || regno == -1)
+ regcache_raw_supply (current_regcache, i, regs +
+ REG_FIXREG_OFFSET (i - tdep->ppc_gp0_regnum));
+ }
+
+ if (regno == tdep->ppc_lr_regnum || regno == -1)
+ regcache_raw_supply (current_regcache, tdep->ppc_lr_regnum,
+ regs + REG_LR_OFFSET);
+
+ if (regno == tdep->ppc_cr_regnum || regno == -1)
+ regcache_raw_supply (current_regcache, tdep->ppc_cr_regnum,
+ regs + REG_CR_OFFSET);
+
+ if (regno == tdep->ppc_xer_regnum || regno == -1)
+ regcache_raw_supply (current_regcache, tdep->ppc_xer_regnum,
+ regs + REG_XER_OFFSET);
+
+ if (regno == tdep->ppc_ctr_regnum || regno == -1)
+ regcache_raw_supply (current_regcache, tdep->ppc_ctr_regnum,
+ regs + REG_CTR_OFFSET);
+
+ if (regno == PC_REGNUM || regno == -1)
+ regcache_raw_supply (current_regcache, PC_REGNUM,
+ regs + REG_PC_OFFSET);
+}
+
+void
+ppcfbsd_fill_reg (char *regs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ for (i = tdep->ppc_gp0_regnum; i <= tdep->ppc_gplast_regnum; i++)
+ {
+ if (regno == i || regno == -1)
+ regcache_raw_collect (current_regcache, i, regs +
+ REG_FIXREG_OFFSET (i - tdep->ppc_gp0_regnum));
+ }
+
+ if (regno == tdep->ppc_lr_regnum || regno == -1)
+ regcache_raw_collect (current_regcache, tdep->ppc_lr_regnum,
+ regs + REG_LR_OFFSET);
+
+ if (regno == tdep->ppc_cr_regnum || regno == -1)
+ regcache_raw_collect (current_regcache, tdep->ppc_cr_regnum,
+ regs + REG_CR_OFFSET);
+
+ if (regno == tdep->ppc_xer_regnum || regno == -1)
+ regcache_raw_collect (current_regcache, tdep->ppc_xer_regnum,
+ regs + REG_XER_OFFSET);
+
+ if (regno == tdep->ppc_ctr_regnum || regno == -1)
+ regcache_raw_collect (current_regcache, tdep->ppc_ctr_regnum,
+ regs + REG_CTR_OFFSET);
+
+ if (regno == PC_REGNUM || regno == -1)
+ regcache_raw_collect (current_regcache, PC_REGNUM, regs + REG_PC_OFFSET);
+}
+
+void
+ppcfbsd_supply_fpreg (char *fpregs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+ point registers. Traditionally, GDB's register set has still
+ listed the floating point registers for such machines, so this
+ code is harmless. However, the new E500 port actually omits the
+ floating point registers entirely from the register set --- they
+ don't even have register numbers assigned to them.
+
+ It's not clear to me how best to update this code, so this assert
+ will alert the first person to encounter the NetBSD/E500
+ combination to the problem. */
+ gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
+
+ for (i = FP0_REGNUM; i <= FPLAST_REGNUM; i++)
+ {
+ if (regno == i || regno == -1)
+ regcache_raw_supply (current_regcache, i, fpregs +
+ FPREG_FPR_OFFSET (i - FP0_REGNUM));
+ }
+
+ if (regno == tdep->ppc_fpscr_regnum || regno == -1)
+ regcache_raw_supply (current_regcache, tdep->ppc_fpscr_regnum,
+ fpregs + FPREG_FPSCR_OFFSET);
+}
+
+void
+ppcfbsd_fill_fpreg (char *fpregs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+ point registers. Traditionally, GDB's register set has still
+ listed the floating point registers for such machines, so this
+ code is harmless. However, the new E500 port actually omits the
+ floating point registers entirely from the register set --- they
+ don't even have register numbers assigned to them.
+
+ It's not clear to me how best to update this code, so this assert
+ will alert the first person to encounter the NetBSD/E500
+ combination to the problem. */
+ gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
+
+ for (i = FP0_REGNUM; i <= FPLAST_REGNUM; i++)
+ {
+ if (regno == i || regno == -1)
+ regcache_raw_collect (current_regcache, i, fpregs +
+ FPREG_FPR_OFFSET (i - FP0_REGNUM));
+ }
+
+ if (regno == tdep->ppc_fpscr_regnum || regno == -1)
+ regcache_raw_collect (current_regcache, tdep->ppc_fpscr_regnum,
+ fpregs + FPREG_FPSCR_OFFSET);
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ char *regs, *fpregs;
+
+ /* We get everything from one section. */
+ if (which != 0)
+ return;
+
+ regs = core_reg_sect;
+ fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
+
+ /* Integer registers. */
+ ppcfbsd_supply_reg (regs, -1);
+
+ /* Floating point registers. */
+ ppcfbsd_supply_fpreg (fpregs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ switch (which)
+ {
+ case 0: /* Integer registers. */
+ if (core_reg_size != SIZEOF_STRUCT_REG)
+ warning (_("Wrong size register set in core file."));
+ else
+ ppcfbsd_supply_reg (core_reg_sect, -1);
+ break;
+
+ case 2: /* Floating point registers. */
+ if (core_reg_size != SIZEOF_STRUCT_FPREG)
+ warning (_("Wrong size FP register set in core file."));
+ else
+ ppcfbsd_supply_fpreg (core_reg_sect, -1);
+ break;
+
+ default:
+ /* Don't know what kind of register request this is; just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns ppcfbsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+static struct core_fns ppcfbsd_elfcore_fns =
+{
+ bfd_target_elf_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_elfcore_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+static int
+ppcfbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ return (pc >= 0x7fffef00U) ? 1 : 0;
+}
+
+/* NetBSD is confused. It appears that 1.5 was using the correct SVr4
+ convention but, 1.6 switched to the below broken convention. For
+ the moment use the broken convention. Ulgh!. */
+
+static enum return_value_convention
+ppcfbsd_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+ && !((TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 8))
+ && !(TYPE_LENGTH (valtype) == 1
+ || TYPE_LENGTH (valtype) == 2
+ || TYPE_LENGTH (valtype) == 4
+ || TYPE_LENGTH (valtype) == 8))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else
+ return ppc_sysv_abi_broken_return_value (gdbarch, valtype, regcache,
+ readbuf, writebuf);
+}
+
+static void
+ppcfbsd_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ set_gdbarch_pc_in_sigtramp (gdbarch, ppcfbsd_pc_in_sigtramp);
+ /* For NetBSD, this is an on again, off again thing. Some systems
+ do use the broken struct convention, and some don't. */
+ set_gdbarch_return_value (gdbarch, ppcfbsd_return_value);
+#ifdef __powerpc64__
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+#else
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+#endif
+}
+
+void
+_initialize_ppcfbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_FREEBSD_ELF,
+ ppcfbsd_init_abi);
+ gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_FREEBSD_ELF,
+ ppcfbsd_init_abi);
+
+ add_core_fns (&ppcfbsd_core_fns);
+ add_core_fns (&ppcfbsd_elfcore_fns);
+}
diff --git a/contrib/gdb/gdb/ppcfbsd-tdep.h b/contrib/gdb/gdb/ppcfbsd-tdep.h
new file mode 100644
index 0000000..1fe90be
--- /dev/null
+++ b/contrib/gdb/gdb/ppcfbsd-tdep.h
@@ -0,0 +1,30 @@
+/* Common target dependent code for GDB on PowerPC systems running FreeBSD.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 PPCFBSD_TDEP_H
+#define PPCFBSD_TDEP_H
+
+void ppcfbsd_supply_reg (char *, int);
+void ppcfbsd_fill_reg (char *, int);
+
+void ppcfbsd_supply_fpreg (char *, int);
+void ppcfbsd_fill_fpreg (char *, int);
+
+#endif /* PPCFBSD_TDEP_H */
diff --git a/contrib/gdb/gdb/ppcnbsd-nat.c b/contrib/gdb/gdb/ppcnbsd-nat.c
new file mode 100644
index 0000000..ce097d7
--- /dev/null
+++ b/contrib/gdb/gdb/ppcnbsd-nat.c
@@ -0,0 +1,121 @@
+/* Native-dependent code for PowerPC's running NetBSD, for GDB.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#include "defs.h"
+#include "inferior.h"
+
+#include "ppc-tdep.h"
+#include "ppcnbsd-tdep.h"
+
+/* Returns true if PT_GETREGS fetches this register. */
+static int
+getregs_supplies (int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ return ((regno >= 0 && regno <= 31)
+ || regno == tdep->ppc_lr_regnum
+ || regno == tdep->ppc_cr_regnum
+ || regno == tdep->ppc_xer_regnum
+ || regno == tdep->ppc_ctr_regnum
+ || regno == PC_REGNUM);
+}
+
+/* Like above, but for PT_GETFPREGS. */
+static int
+getfpregs_supplies (int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ return ((regno >= FP0_REGNUM && regno <= FP0_REGNUM + 31)
+ || regno == tdep->ppc_fpscr_regnum);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ ppcnbsd_supply_reg ((char *) &regs, regno);
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || getfpregs_supplies (regno))
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get FP registers");
+
+ ppcnbsd_supply_fpreg ((char *) &fpregs, regno);
+ if (regno != -1)
+ return;
+ }
+}
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ ppcnbsd_fill_reg ((char *) &regs, regno);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || getfpregs_supplies (regno))
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get FP registers");
+
+ ppcnbsd_fill_fpreg ((char *) &fpregs, regno);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't set FP registers");
+ }
+}
diff --git a/contrib/gdb/gdb/ppcnbsd-tdep.c b/contrib/gdb/gdb/ppcnbsd-tdep.c
new file mode 100644
index 0000000..adc2a4f
--- /dev/null
+++ b/contrib/gdb/gdb/ppcnbsd-tdep.c
@@ -0,0 +1,250 @@
+/* Target-dependent code for PowerPC systems running NetBSD.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "ppc-tdep.h"
+#include "ppcnbsd-tdep.h"
+#include "nbsd-tdep.h"
+
+#include "solib-svr4.h"
+
+#define REG_FIXREG_OFFSET(x) ((x) * 4)
+#define REG_LR_OFFSET (32 * 4)
+#define REG_CR_OFFSET (33 * 4)
+#define REG_XER_OFFSET (34 * 4)
+#define REG_CTR_OFFSET (35 * 4)
+#define REG_PC_OFFSET (36 * 4)
+#define SIZEOF_STRUCT_REG (37 * 4)
+
+#define FPREG_FPR_OFFSET(x) ((x) * 8)
+#define FPREG_FPSCR_OFFSET (32 * 8)
+#define SIZEOF_STRUCT_FPREG (33 * 8)
+
+void
+ppcnbsd_supply_reg (char *regs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ for (i = 0; i <= 31; i++)
+ {
+ if (regno == i || regno == -1)
+ supply_register (i, regs + REG_FIXREG_OFFSET (i));
+ }
+
+ if (regno == tdep->ppc_lr_regnum || regno == -1)
+ supply_register (tdep->ppc_lr_regnum, regs + REG_LR_OFFSET);
+
+ if (regno == tdep->ppc_cr_regnum || regno == -1)
+ supply_register (tdep->ppc_cr_regnum, regs + REG_CR_OFFSET);
+
+ if (regno == tdep->ppc_xer_regnum || regno == -1)
+ supply_register (tdep->ppc_xer_regnum, regs + REG_XER_OFFSET);
+
+ if (regno == tdep->ppc_ctr_regnum || regno == -1)
+ supply_register (tdep->ppc_ctr_regnum, regs + REG_CTR_OFFSET);
+
+ if (regno == PC_REGNUM || regno == -1)
+ supply_register (PC_REGNUM, regs + REG_PC_OFFSET);
+}
+
+void
+ppcnbsd_fill_reg (char *regs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ for (i = 0; i <= 31; i++)
+ {
+ if (regno == i || regno == -1)
+ regcache_collect (i, regs + REG_FIXREG_OFFSET (i));
+ }
+
+ if (regno == tdep->ppc_lr_regnum || regno == -1)
+ regcache_collect (tdep->ppc_lr_regnum, regs + REG_LR_OFFSET);
+
+ if (regno == tdep->ppc_cr_regnum || regno == -1)
+ regcache_collect (tdep->ppc_cr_regnum, regs + REG_CR_OFFSET);
+
+ if (regno == tdep->ppc_xer_regnum || regno == -1)
+ regcache_collect (tdep->ppc_xer_regnum, regs + REG_XER_OFFSET);
+
+ if (regno == tdep->ppc_ctr_regnum || regno == -1)
+ regcache_collect (tdep->ppc_ctr_regnum, regs + REG_CTR_OFFSET);
+
+ if (regno == PC_REGNUM || regno == -1)
+ regcache_collect (PC_REGNUM, regs + REG_PC_OFFSET);
+}
+
+void
+ppcnbsd_supply_fpreg (char *fpregs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
+ {
+ if (regno == i || regno == -1)
+ supply_register (i, fpregs + FPREG_FPR_OFFSET (i - FP0_REGNUM));
+ }
+
+ if (regno == tdep->ppc_fpscr_regnum || regno == -1)
+ supply_register (tdep->ppc_fpscr_regnum, fpregs + FPREG_FPSCR_OFFSET);
+}
+
+void
+ppcnbsd_fill_fpreg (char *fpregs, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int i;
+
+ for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
+ {
+ if (regno == i || regno == -1)
+ regcache_collect (i, fpregs + FPREG_FPR_OFFSET (i - FP0_REGNUM));
+ }
+
+ if (regno == tdep->ppc_fpscr_regnum || regno == -1)
+ regcache_collect (tdep->ppc_fpscr_regnum, fpregs + FPREG_FPSCR_OFFSET);
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ char *regs, *fpregs;
+
+ /* We get everything from one section. */
+ if (which != 0)
+ return;
+
+ regs = core_reg_sect;
+ fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
+
+ /* Integer registers. */
+ ppcnbsd_supply_reg (regs, -1);
+
+ /* Floating point registers. */
+ ppcnbsd_supply_fpreg (fpregs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ switch (which)
+ {
+ case 0: /* Integer registers. */
+ if (core_reg_size != SIZEOF_STRUCT_REG)
+ warning ("Wrong size register set in core file.");
+ else
+ ppcnbsd_supply_reg (core_reg_sect, -1);
+ break;
+
+ case 2: /* Floating point registers. */
+ if (core_reg_size != SIZEOF_STRUCT_FPREG)
+ warning ("Wrong size FP register set in core file.");
+ else
+ ppcnbsd_supply_fpreg (core_reg_sect, -1);
+ break;
+
+ default:
+ /* Don't know what kind of register request this is; just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns ppcnbsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+static struct core_fns ppcnbsd_elfcore_fns =
+{
+ bfd_target_elf_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_elfcore_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+static int
+ppcnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ /* FIXME: Need to add support for kernel-provided signal trampolines. */
+ return (nbsd_pc_in_sigtramp (pc, func_name));
+}
+
+/* NetBSD is confused. It appears that 1.5 was using the correct SVr4
+ convention but, 1.6 switched to the below broken convention. For
+ the moment use the broken convention. Ulgh!. */
+
+static enum return_value_convention
+ppcnbsd_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+ && !((TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 8)
+ && TYPE_VECTOR (valtype))
+ && !(TYPE_LENGTH (valtype) == 1
+ || TYPE_LENGTH (valtype) == 2
+ || TYPE_LENGTH (valtype) == 4
+ || TYPE_LENGTH (valtype) == 8))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else
+ return ppc_sysv_abi_broken_return_value (gdbarch, valtype, regcache,
+ readbuf, writebuf);
+}
+
+static void
+ppcnbsd_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ set_gdbarch_pc_in_sigtramp (gdbarch, ppcnbsd_pc_in_sigtramp);
+ /* For NetBSD, this is an on again, off again thing. Some systems
+ do use the broken struct convention, and some don't. */
+ set_gdbarch_return_value (gdbarch, ppcnbsd_return_value);
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+}
+
+void
+_initialize_ppcnbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_NETBSD_ELF,
+ ppcnbsd_init_abi);
+
+ add_core_fns (&ppcnbsd_core_fns);
+ add_core_fns (&ppcnbsd_elfcore_fns);
+}
diff --git a/contrib/gdb/gdb/ppcnbsd-tdep.h b/contrib/gdb/gdb/ppcnbsd-tdep.h
new file mode 100644
index 0000000..3eae72d
--- /dev/null
+++ b/contrib/gdb/gdb/ppcnbsd-tdep.h
@@ -0,0 +1,30 @@
+/* Common target dependent code for GDB on PowerPC systems running NetBSD.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 PPCNBSD_TDEP_H
+#define PPCNBSD_TDEP_H
+
+void ppcnbsd_supply_reg (char *, int);
+void ppcnbsd_fill_reg (char *, int);
+
+void ppcnbsd_supply_fpreg (char *, int);
+void ppcnbsd_fill_fpreg (char *, int);
+
+#endif /* PPCNBSD_TDEP_H */
diff --git a/contrib/gdb/gdb/printcmd.c b/contrib/gdb/gdb/printcmd.c
new file mode 100644
index 0000000..9734ec1
--- /dev/null
+++ b/contrib/gdb/gdb/printcmd.c
@@ -0,0 +1,2172 @@
+/* Print values for GNU debugger GDB.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "symfile.h" /* for overlay functions */
+#include "objfiles.h" /* ditto */
+#include "completer.h" /* for completion functions */
+#include "ui-out.h"
+#include "gdb_assert.h"
+#include "block.h"
+#include "disasm.h"
+
+#ifdef TUI
+#include "tui/tui.h" /* For tui_active et.al. */
+#endif
+
+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;
+
+/* Default section to examine next. */
+
+static asection *next_section;
+
+/* 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 struct value *last_examine_value;
+
+/* Largest offset between a symbolic value and an address, that will be
+ printed as `0x1234 <symbol+offset>'. */
+
+static unsigned int max_symbolic_offset = UINT_MAX;
+
+/* Append the source filename and linenumber of the symbol when
+ printing a symbolic value as `<symbol at filename:linenum>' 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) */
+ int enabled_p;
+ };
+
+/* Chain of expressions whose values should be displayed
+ automatically each time the program stops. */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* Prototypes for exported functions. */
+
+void output_command (char *, int);
+
+void _initialize_printcmd (void);
+
+/* Prototypes for local functions. */
+
+static void delete_display (int);
+
+static void enable_display (char *, int);
+
+static void disable_display_command (char *, int);
+
+static void printf_command (char *, int);
+
+static void display_info (char *, int);
+
+static void do_one_display (struct display *);
+
+static void undisplay_command (char *, int);
+
+static void free_display (struct display *);
+
+static void display_command (char *, int);
+
+void x_command (char *, int);
+
+static void address_info (char *, int);
+
+static void set_command (char *, int);
+
+static void call_command (char *, int);
+
+static void inspect_command (char *, int);
+
+static void print_command (char *, int);
+
+static void print_command_1 (char *, int, int);
+
+static void validate_format (struct format_data, char *);
+
+static void do_examine (struct format_data, CORE_ADDR addr,
+ asection * section);
+
+static void print_formatted (struct value *, int, int, struct ui_file *);
+
+static struct format_data decode_format (char **, int, int);
+
+static void sym_info (char *, int);
+
+
+/* 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 (char **string_ptr, int oformat, int osize)
+{
+ struct format_data val;
+ 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 */
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ 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 stream 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 (struct value *val, int format, int size,
+ struct ui_file *stream)
+{
+ 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;
+ next_section = VALUE_BFD_SECTION (val);
+ }
+
+ switch (format)
+ {
+ case 's':
+ /* FIXME: Need to handle wchar_t's here... */
+ next_address = VALUE_ADDRESS (val)
+ + val_print_string (VALUE_ADDRESS (val), -1, 1, stream);
+ next_section = VALUE_BFD_SECTION (val);
+ 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.
+ --Yes, it does filter now, and so this is obsolete. -JB */
+
+ /* We often wrap here if there are long symbolic names. */
+ wrap_here (" ");
+ next_address = VALUE_ADDRESS (val)
+ + gdb_print_insn (VALUE_ADDRESS (val), stream);
+ next_section = VALUE_BFD_SECTION (val);
+ 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
+ || TYPE_CODE (type) == TYPE_CODE_NAMESPACE)
+ /* If format is 0, use the 'natural' format for
+ * that type of value. If the type is non-scalar,
+ * we have to use language rules to print it as
+ * a series of scalars.
+ */
+ value_print (val, stream, format, Val_pretty_default);
+ else
+ /* User specified format, so don't look to the
+ * the type to tell us what to do.
+ */
+ print_scalar_formatted (VALUE_CONTENTS (val), type,
+ format, size, stream);
+ }
+}
+
+/* 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 (void *valaddr, struct type *type, int format, int size,
+ struct ui_file *stream)
+{
+ LONGEST val_long = 0;
+ unsigned int len = TYPE_LENGTH (type);
+
+ if (len > sizeof(LONGEST) &&
+ (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_ENUM))
+ {
+ switch (format)
+ {
+ case 'o':
+ print_octal_chars (stream, valaddr, len);
+ return;
+ case 'u':
+ case 'd':
+ print_decimal_chars (stream, valaddr, len);
+ return;
+ case 't':
+ print_binary_chars (stream, valaddr, len);
+ return;
+ case 'x':
+ print_hex_chars (stream, valaddr, len);
+ return;
+ case 'c':
+ print_char_chars (stream, valaddr, len);
+ return;
+ default:
+ break;
+ };
+ }
+
+ if (format != 'f')
+ val_long = unpack_long (type, valaddr);
+
+ /* If the value is a pointer, and pointers and addresses are not the
+ same, then at this point, the value's length (in target bytes) is
+ TARGET_ADDR_BIT/TARGET_CHAR_BIT, not TYPE_LENGTH (type). */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ len = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
+
+ /* 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':
+ {
+ CORE_ADDR addr = unpack_pointer (type, valaddr);
+ print_address (addr, stream);
+ }
+ break;
+
+ case 'c':
+ value_print (value_from_longest (builtin_type_true_char, val_long),
+ stream, 0, Val_pretty_default);
+ break;
+
+ case 'f':
+ if (len == TYPE_LENGTH (builtin_type_float))
+ type = builtin_type_float;
+ else if (len == TYPE_LENGTH (builtin_type_double))
+ type = builtin_type_double;
+ else if (len == TYPE_LENGTH (builtin_type_long_double))
+ type = builtin_type_long_double;
+ print_floating (valaddr, type, stream);
+ break;
+
+ case 0:
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ case 't':
+ /* Binary; 't' stands for "two". */
+ {
+ char bits[8 * (sizeof val_long) + 1];
+ char buf[8 * (sizeof val_long) + 32];
+ 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--;
+ }
+ strcpy (buf, local_binary_format_prefix ());
+ strcat (buf, cp);
+ strcat (buf, local_binary_format_suffix ());
+ fputs_filtered (buf, stream);
+ }
+ break;
+
+ default:
+ error ("Undefined output format \"%c\".", format);
+ }
+}
+
+/* Specify default address for `x' command.
+ `info lines' uses this. */
+
+void
+set_next_address (CORE_ADDR addr)
+{
+ next_address = addr;
+
+ /* Make address available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_pointer (lookup_pointer_type (builtin_type_void),
+ addr));
+}
+
+/* Optionally print address ADDR symbolically as <SYMBOL+OFFSET> 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 (CORE_ADDR addr, struct ui_file *stream, int do_demangle,
+ char *leadin)
+{
+ char *name = NULL;
+ char *filename = NULL;
+ int unmapped = 0;
+ int offset = 0;
+ int line = 0;
+
+ /* throw away both name and filename */
+ struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &name);
+ make_cleanup (free_current_contents, &filename);
+
+ if (build_address_symbolic (addr, do_demangle, &name, &offset, &filename, &line, &unmapped))
+ {
+ do_cleanups (cleanup_chain);
+ return;
+ }
+
+ fputs_filtered (leadin, stream);
+ if (unmapped)
+ fputs_filtered ("<*", stream);
+ else
+ fputs_filtered ("<", stream);
+ fputs_filtered (name, stream);
+ if (offset != 0)
+ fprintf_filtered (stream, "+%u", (unsigned int) offset);
+
+ /* 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 && filename != NULL)
+ {
+ if (line != -1)
+ fprintf_filtered (stream, " at %s:%d", filename, line);
+ else
+ fprintf_filtered (stream, " in %s", filename);
+ }
+ if (unmapped)
+ fputs_filtered ("*>", stream);
+ else
+ fputs_filtered (">", stream);
+
+ do_cleanups (cleanup_chain);
+}
+
+/* Given an address ADDR return all the elements needed to print the
+ address in a symbolic form. NAME can be mangled or not depending
+ on DO_DEMANGLE (and also on the asm_demangle global variable,
+ manipulated via ''set print asm-demangle''). Return 0 in case of
+ success, when all the info in the OUT paramters is valid. Return 1
+ otherwise. */
+int
+build_address_symbolic (CORE_ADDR addr, /* IN */
+ int do_demangle, /* IN */
+ char **name, /* OUT */
+ int *offset, /* OUT */
+ char **filename, /* OUT */
+ int *line, /* OUT */
+ int *unmapped) /* OUT */
+{
+ struct minimal_symbol *msymbol;
+ struct symbol *symbol;
+ struct symtab *symtab = 0;
+ CORE_ADDR name_location = 0;
+ asection *section = 0;
+ char *name_temp = "";
+
+ /* Let's say it is unmapped. */
+ *unmapped = 0;
+
+ /* Determine if the address is in an overlay, and whether it is
+ mapped. */
+ if (overlay_debugging)
+ {
+ section = find_pc_overlay (addr);
+ if (pc_in_unmapped_range (addr, section))
+ {
+ *unmapped = 1;
+ addr = overlay_mapped_address (addr, section);
+ }
+ }
+
+ /* 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). */
+ msymbol = lookup_minimal_symbol_by_pc_section (addr, section);
+ symbol = find_pc_sect_function (addr, section);
+
+ if (symbol)
+ {
+ name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol));
+ if (do_demangle || asm_demangle)
+ name_temp = SYMBOL_PRINT_NAME (symbol);
+ else
+ name_temp = DEPRECATED_SYMBOL_NAME (symbol);
+ }
+
+ 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 || asm_demangle)
+ name_temp = SYMBOL_PRINT_NAME (msymbol);
+ else
+ name_temp = DEPRECATED_SYMBOL_NAME (msymbol);
+ }
+ }
+ if (symbol == NULL && msymbol == NULL)
+ return 1;
+
+ /* 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 1;
+
+ *offset = addr - name_location;
+
+ *name = xstrdup (name_temp);
+
+ if (print_symbol_filename)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_sect_line (addr, section, 0);
+
+ if (sal.symtab)
+ {
+ *filename = xstrdup (sal.symtab->filename);
+ *line = sal.line;
+ }
+ else if (symtab && symbol && symbol->line)
+ {
+ *filename = xstrdup (symtab->filename);
+ *line = symbol->line;
+ }
+ else if (symtab)
+ {
+ *filename = xstrdup (symtab->filename);
+ *line = -1;
+ }
+ }
+ return 0;
+}
+
+/* Print address ADDR on STREAM. USE_LOCAL means the same thing as for
+ print_longest. */
+void
+print_address_numeric (CORE_ADDR addr, int use_local, struct ui_file *stream)
+{
+ /* Truncate address to the size of a target address, avoiding shifts
+ larger or equal than the width of a CORE_ADDR. The local
+ variable ADDR_BIT stops the compiler reporting a shift overflow
+ when it won't occur. */
+ /* NOTE: This assumes that the significant address information is
+ kept in the least significant bits of ADDR - the upper bits were
+ either zero or sign extended. Should ADDRESS_TO_POINTER() or
+ some ADDRESS_TO_PRINTABLE() be used to do the conversion? */
+
+ int addr_bit = TARGET_ADDR_BIT;
+
+ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+ addr &= ((CORE_ADDR) 1 << addr_bit) - 1;
+ print_longest (stream, 'x', use_local, (ULONGEST) addr);
+}
+
+/* Print address ADDR symbolically on STREAM.
+ First print it as a number. Then perhaps print
+ <SYMBOL + OFFSET> after the number. */
+
+void
+print_address (CORE_ADDR addr, struct ui_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 (CORE_ADDR addr, struct ui_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_i_type;
+
+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 (struct format_data fmt, CORE_ADDR addr, asection *sect)
+{
+ char format = 0;
+ char size;
+ int count = 1;
+ struct type *val_type = NULL;
+ int i;
+ int maxelts;
+
+ format = fmt.format;
+ size = fmt.size;
+ count = fmt.count;
+ next_address = addr;
+ next_section = sect;
+
+ /* String or instruction format implies fetch single bytes
+ regardless of the specified size. */
+ if (format == 's' || format == 'i')
+ size = 'b';
+
+ if (format == 'i')
+ val_type = examine_i_type;
+ else 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;
+
+ if (last_examine_value)
+ value_free (last_examine_value);
+
+ /* The value to be displayed is not fetched greedily.
+ Instead, to avoid the posibility of a fetched value not
+ being used, its retreval is delayed until the print code
+ uses it. When examining an instruction stream, the
+ disassembler will perform its own memory fetch using just
+ the address stored in LAST_EXAMINE_VALUE. FIXME: Should
+ the disassembler be modified so that LAST_EXAMINE_VALUE
+ is left with the byte sequence from the last complete
+ instruction fetched from memory? */
+ last_examine_value = value_at_lazy (val_type, next_address, sect);
+
+ if (last_examine_value)
+ release_value (last_examine_value);
+
+ print_formatted (last_examine_value, format, size, gdb_stdout);
+ }
+ printf_filtered ("\n");
+ gdb_flush (gdb_stdout);
+ }
+}
+
+static void
+validate_format (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 (char *exp, int inspect, int voidprint)
+{
+ struct expression *expr;
+ struct cleanup *old_chain = 0;
+ char format = 0;
+ struct value *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)
+ {
+ struct type *type;
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ cleanup = 1;
+ val = evaluate_expression (expr);
+ }
+ 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, gdb_stdout);
+ 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 */
+}
+
+static void
+print_command (char *exp, int from_tty)
+{
+ print_command_1 (exp, 0, 1);
+}
+
+/* Same as print, except in epoch, it gets its own window */
+static void
+inspect_command (char *exp, int from_tty)
+{
+ extern int epoch_interface;
+
+ print_command_1 (exp, epoch_interface, 1);
+}
+
+/* Same as print, except it doesn't print void results. */
+static void
+call_command (char *exp, int from_tty)
+{
+ print_command_1 (exp, 0, 0);
+}
+
+void
+output_command (char *exp, int from_tty)
+{
+ struct expression *expr;
+ struct cleanup *old_chain;
+ char format = 0;
+ struct value *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, gdb_stdout);
+
+ annotate_value_end ();
+
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+
+ do_cleanups (old_chain);
+}
+
+static void
+set_command (char *exp, int from_tty)
+{
+ struct expression *expr = parse_expression (exp);
+ struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+}
+
+static void
+sym_info (char *arg, int from_tty)
+{
+ struct minimal_symbol *msymbol;
+ struct objfile *objfile;
+ struct obj_section *osect;
+ asection *sect;
+ CORE_ADDR addr, sect_addr;
+ int matches = 0;
+ unsigned int offset;
+
+ if (!arg)
+ error_no_arg ("address");
+
+ addr = parse_and_eval_address (arg);
+ ALL_OBJSECTIONS (objfile, osect)
+ {
+ sect = osect->the_bfd_section;
+ sect_addr = overlay_mapped_address (addr, sect);
+
+ if (osect->addr <= sect_addr && sect_addr < osect->endaddr &&
+ (msymbol = lookup_minimal_symbol_by_pc_section (sect_addr, sect)))
+ {
+ matches = 1;
+ offset = sect_addr - SYMBOL_VALUE_ADDRESS (msymbol);
+ if (offset)
+ printf_filtered ("%s + %u in ",
+ SYMBOL_PRINT_NAME (msymbol), offset);
+ else
+ printf_filtered ("%s in ",
+ SYMBOL_PRINT_NAME (msymbol));
+ if (pc_in_unmapped_range (addr, sect))
+ printf_filtered ("load address range of ");
+ if (section_is_overlay (sect))
+ printf_filtered ("%s overlay ",
+ section_is_mapped (sect) ? "mapped" : "unmapped");
+ printf_filtered ("section %s", sect->name);
+ printf_filtered ("\n");
+ }
+ }
+ if (matches == 0)
+ printf_filtered ("No symbol matches %s.\n", arg);
+}
+
+static void
+address_info (char *exp, int from_tty)
+{
+ struct symbol *sym;
+ struct minimal_symbol *msymbol;
+ long val;
+ long basereg;
+ asection *section;
+ CORE_ADDR load_addr;
+ 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 (0), VAR_DOMAIN,
+ &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 ");
+ if (current_language->la_language == language_objc)
+ printf_filtered ("`self'\n"); /* ObjC equivalent of "this" */
+ else
+ printf_filtered ("`this'\n");
+ return;
+ }
+
+ msymbol = lookup_minimal_symbol (exp, NULL, NULL);
+
+ if (msymbol != NULL)
+ {
+ load_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ printf_filtered ("Symbol \"");
+ fprintf_symbol_filtered (gdb_stdout, exp,
+ current_language->la_language, DMGL_ANSI);
+ printf_filtered ("\" is at ");
+ print_address_numeric (load_addr, 1, gdb_stdout);
+ printf_filtered (" in a file compiled without debugging");
+ section = SYMBOL_BFD_SECTION (msymbol);
+ if (section_is_overlay (section))
+ {
+ load_addr = overlay_unmapped_address (load_addr, section);
+ printf_filtered (",\n -- loaded at ");
+ print_address_numeric (load_addr, 1, gdb_stdout);
+ printf_filtered (" in overlay section %s", section->name);
+ }
+ printf_filtered (".\n");
+ }
+ else
+ error ("No symbol \"%s\" in current context.", exp);
+ return;
+ }
+
+ printf_filtered ("Symbol \"");
+ fprintf_symbol_filtered (gdb_stdout, DEPRECATED_SYMBOL_NAME (sym),
+ current_language->la_language, DMGL_ANSI);
+ printf_filtered ("\" is ");
+ val = SYMBOL_VALUE (sym);
+ basereg = SYMBOL_BASEREG (sym);
+ section = SYMBOL_BFD_SECTION (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 (load_addr = SYMBOL_VALUE_ADDRESS (sym),
+ 1, gdb_stdout);
+ if (section_is_overlay (section))
+ {
+ load_addr = overlay_unmapped_address (load_addr, section);
+ printf_filtered (",\n -- loaded at ");
+ print_address_numeric (load_addr, 1, gdb_stdout);
+ printf_filtered (" in overlay section %s", section->name);
+ }
+ break;
+
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ /* FIXME: cagney/2004-01-26: It should be possible to
+ unconditionally call the SYMBOL_OPS method when available.
+ Unfortunately DWARF 2 stores the frame-base (instead of the
+ function) location in a function's symbol. Oops! For the
+ moment enable this when/where applicable. */
+ SYMBOL_OPS (sym)->describe_location (sym, gdb_stdout);
+ break;
+
+ case LOC_REGISTER:
+ printf_filtered ("a variable in register %s", REGISTER_NAME (val));
+ break;
+
+ case LOC_STATIC:
+ printf_filtered ("static storage at address ");
+ print_address_numeric (load_addr = SYMBOL_VALUE_ADDRESS (sym),
+ 1, gdb_stdout);
+ if (section_is_overlay (section))
+ {
+ load_addr = overlay_unmapped_address (load_addr, section);
+ printf_filtered (",\n -- loaded at ");
+ print_address_numeric (load_addr, 1, gdb_stdout);
+ printf_filtered (" in overlay section %s", section->name);
+ }
+ break;
+
+ case LOC_INDIRECT:
+ printf_filtered ("external global (indirect addressing), at address *(");
+ print_address_numeric (load_addr = SYMBOL_VALUE_ADDRESS (sym),
+ 1, gdb_stdout);
+ printf_filtered (")");
+ if (section_is_overlay (section))
+ {
+ load_addr = overlay_unmapped_address (load_addr, section);
+ printf_filtered (",\n -- loaded at ");
+ print_address_numeric (load_addr, 1, gdb_stdout);
+ printf_filtered (" in overlay section %s", section->name);
+ }
+ break;
+
+ case LOC_REGPARM:
+ printf_filtered ("an argument in register %s", REGISTER_NAME (val));
+ break;
+
+ case LOC_REGPARM_ADDR:
+ printf_filtered ("address of an argument in register %s", REGISTER_NAME (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, REGISTER_NAME (basereg));
+ break;
+
+ case LOC_BASEREG_ARG:
+ printf_filtered ("an argument at offset %ld from register %s",
+ val, REGISTER_NAME (basereg));
+ break;
+
+ case LOC_TYPEDEF:
+ printf_filtered ("a typedef");
+ break;
+
+ case LOC_BLOCK:
+ printf_filtered ("a function at address ");
+ print_address_numeric (load_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)),
+ 1, gdb_stdout);
+ if (section_is_overlay (section))
+ {
+ load_addr = overlay_unmapped_address (load_addr, section);
+ printf_filtered (",\n -- loaded at ");
+ print_address_numeric (load_addr, 1, gdb_stdout);
+ printf_filtered (" in overlay section %s", section->name);
+ }
+ break;
+
+ case LOC_UNRESOLVED:
+ {
+ struct minimal_symbol *msym;
+
+ msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (sym), NULL, NULL);
+ if (msym == NULL)
+ printf_filtered ("unresolved");
+ else
+ {
+ section = SYMBOL_BFD_SECTION (msym);
+ printf_filtered ("static storage at address ");
+ print_address_numeric (load_addr = SYMBOL_VALUE_ADDRESS (msym),
+ 1, gdb_stdout);
+ if (section_is_overlay (section))
+ {
+ load_addr = overlay_unmapped_address (load_addr, section);
+ printf_filtered (",\n -- loaded at ");
+ print_address_numeric (load_addr, 1, gdb_stdout);
+ printf_filtered (" in overlay section %s", section->name);
+ }
+ }
+ }
+ break;
+
+ case LOC_HP_THREAD_LOCAL_STATIC:
+ printf_filtered (
+ "a thread-local variable at offset %ld from the thread base register %s",
+ val, REGISTER_NAME (basereg));
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ printf_filtered ("optimized out");
+ break;
+
+ default:
+ printf_filtered ("of unknown (botched) type");
+ break;
+ }
+ printf_filtered (".\n");
+}
+
+void
+x_command (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_address (val);
+ if (VALUE_BFD_SECTION (val))
+ next_section = VALUE_BFD_SECTION (val);
+ do_cleanups (old_chain);
+ }
+
+ do_examine (fmt, next_address, next_section);
+
+ /* 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. */
+ struct type *pointer_type
+ = lookup_pointer_type (VALUE_TYPE (last_examine_value));
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_pointer (pointer_type,
+ last_examine_address));
+
+ /* Make contents of last address examined available to the user as $__. */
+ /* If the last value has not been fetched from memory then don't
+ fetch it now - instead mark it by voiding the $__ variable. */
+ if (VALUE_LAZY (last_examine_value))
+ set_internalvar (lookup_internalvar ("__"),
+ allocate_value (builtin_type_void));
+ else
+ set_internalvar (lookup_internalvar ("__"), last_examine_value);
+ }
+}
+
+
+/* Add an expression to the auto-display chain.
+ Specify the expression. */
+
+static void
+display_command (char *exp, int from_tty)
+{
+ struct format_data fmt;
+ struct expression *expr;
+ struct display *new;
+ int display_it = 1;
+
+#if defined(TUI)
+ /* NOTE: cagney/2003-02-13 The `tui_active' was previously
+ `tui_version'. */
+ if (tui_active && exp != NULL && *exp == '$')
+ display_it = (tui_set_layout_for_display_command (exp) == TUI_FAILURE);
+#endif
+
+ if (display_it)
+ {
+ 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->enabled_p = 1;
+ display_chain = new;
+
+ if (from_tty && target_has_execution)
+ do_one_display (new);
+
+ dont_repeat ();
+ }
+}
+
+static void
+free_display (struct display *d)
+{
+ xfree (d->exp);
+ xfree (d);
+}
+
+/* Clear out the display_chain.
+ Done when new symtabs are loaded, since this invalidates
+ the types stored in many expressions. */
+
+void
+clear_displays (void)
+{
+ struct display *d;
+
+ while ((d = display_chain) != NULL)
+ {
+ xfree (d->exp);
+ display_chain = d->next;
+ xfree (d);
+ }
+}
+
+/* Delete the auto-display number NUM. */
+
+static void
+delete_display (int num)
+{
+ 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 (char *args, int from_tty)
+{
+ char *p = args;
+ char *p1;
+ 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 (struct display *d)
+{
+ int within_current_scope;
+
+ if (d->enabled_p == 0)
+ return;
+
+ if (d->block)
+ within_current_scope = contained_in (get_selected_block (0), 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;
+ struct value *val;
+
+ 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 (" ");
+
+ val = evaluate_expression (d->exp);
+ addr = value_as_address (val);
+ if (d->format.format == 'i')
+ addr = ADDR_BITS_REMOVE (addr);
+
+ annotate_display_value ();
+
+ do_examine (d->format, addr, VALUE_BFD_SECTION (val));
+ }
+ 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, gdb_stdout);
+ 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 (void)
+{
+ 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 (int num)
+{
+ struct display *d;
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->enabled_p = 0;
+ return;
+ }
+ printf_unfiltered ("No display number %d.\n", num);
+}
+
+void
+disable_current_display (void)
+{
+ 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 (char *ignore, int from_tty)
+{
+ 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->enabled_p]);
+ 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 (0), d->block))
+ printf_filtered (" (cannot be evaluated in the current context)");
+ printf_filtered ("\n");
+ gdb_flush (gdb_stdout);
+ }
+}
+
+static void
+enable_display (char *args, int from_tty)
+{
+ char *p = args;
+ char *p1;
+ int num;
+ struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d = d->next)
+ d->enabled_p = 1;
+ }
+ 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->enabled_p = 1;
+ goto win;
+ }
+ printf_unfiltered ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+static void
+disable_display_command (char *args, int from_tty)
+{
+ char *p = args;
+ char *p1;
+ struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d = d->next)
+ d->enabled_p = 0;
+ }
+ 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 (struct symbol *var, struct frame_info *frame,
+ struct ui_file *stream)
+{
+ struct value *val = read_var_value (var, frame);
+
+ value_print (val, stream, 0, Val_pretty_default);
+}
+
+static void
+printf_command (char *arg, int from_tty)
+{
+ char *f = NULL;
+ char *s = arg;
+ char *string = NULL;
+ struct value **val_args;
+ char *substrings;
+ char *current_substring;
+ int nargs = 0;
+ int allocated_args = 20;
+ struct cleanup *old_cleanups;
+
+ val_args = (struct value **) xmalloc (allocated_args
+ * sizeof (struct value *));
+ 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':
+ *f++ = '\a';
+ break;
+ case 'b':
+ *f++ = '\b';
+ break;
+ case 'f':
+ *f++ = '\f';
+ break;
+ case 'n':
+ *f++ = '\n';
+ break;
+ case 'r':
+ *f++ = '\r';
+ break;
+ case 't':
+ *f++ = '\t';
+ break;
+ case 'v':
+ *f++ = '\v';
+ break;
+ case '"':
+ *f++ = '"';
+ break;
+ default:
+ /* ??? TODO: handle other escape sequences */
+ error ("Unrecognized escape character \\%c in format string.",
+ c);
+ }
+ break;
+
+ default:
+ *f++ = c;
+ }
+ }
+
+ /* 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 = (struct value **) xrealloc ((char *) val_args,
+ (allocated_args *= 2)
+ * sizeof (struct value *));
+ 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_address (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);
+ if (j != 0)
+ 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: /* purecov: deadcode */
+ error ("internal error in printf_command"); /* purecov: deadcode */
+ }
+ /* Skip to the next substring. */
+ current_substring += strlen (current_substring) + 1;
+ }
+ /* Print the portion of the format string after the last argument. */
+ puts_filtered (last_arg);
+ }
+ do_cleanups (old_cleanups);
+}
+
+void
+_initialize_printcmd (void)
+{
+ struct cmd_list_element *c;
+
+ current_display_number = -1;
+
+ add_info ("address", address_info,
+ "Describe where symbol SYM is stored.");
+
+ add_info ("symbol", sym_info,
+ "Describe what symbol is at location ADDR.\n\
+Only for symbols with fixed locations (global or static scope).");
+
+ 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));
+
+#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);
+ if (dbx_commands)
+ add_com ("assign", 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));
+
+ /* "call" is the same as "set", but handy for dbx users to call fns. */
+ c = 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.");
+ set_cmd_completer (c, location_completer);
+
+ 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);
+
+ c = 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));
+ set_cmd_completer (c, location_completer);
+ add_com_alias ("p", "print", class_vars, 1);
+
+ c = add_com ("inspect", class_vars, inspect_command,
+ "Same as \"print\" command, except that if you are running in the epoch\n\
+environment, the value is printed in its own window.");
+ set_cmd_completer (c, location_completer);
+
+ 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 <symbol+1234> 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 <symbol>.",
+ &setprintlist),
+ &showprintlist);
+
+ /* For examine/instruction a single byte quantity is specified as
+ the data. This avoids problems with value_at_lazy() requiring a
+ valid data type (and rejecting VOID). */
+ examine_i_type = init_type (TYPE_CODE_INT, 1, 0, "examine_i_type", NULL);
+
+ 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/proc-api.c b/contrib/gdb/gdb/proc-api.c
new file mode 100755
index 0000000..e6d30ea
--- /dev/null
+++ b/contrib/gdb/gdb/proc-api.c
@@ -0,0 +1,797 @@
+/* Machine independent support for SVR4 /proc (process file system) for GDB.
+
+ Copyright 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ Written by Michael Snyder at Cygnus Solutions.
+ Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ * Pretty-print trace of api calls to the /proc api
+ * (ioctl or read/write calls).
+ *
+ */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "completer.h"
+
+#if defined (NEW_PROC_API)
+#define _STRUCTURED_PROC 1
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+#ifdef HAVE_SYS_PROC_H
+#include <sys/proc.h> /* for struct proc */
+#endif
+#ifdef HAVE_SYS_USER_H
+#include <sys/user.h> /* for struct user */
+#endif
+#include <fcntl.h> /* for O_RDWR etc. */
+#include "gdb_wait.h"
+
+#include "proc-utils.h"
+
+/* 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 {
+ long value; /* The numeric value */
+ char *name; /* The equivalent symbolic value */
+ char *desc; /* Short description of value */
+};
+
+static int procfs_trace = 0;
+static FILE *procfs_file = NULL;
+static char *procfs_filename = "procfs_trace";
+
+static void
+prepare_to_trace (void)
+{
+ if (procfs_trace) /* if procfs tracing turned on */
+ if (procfs_file == NULL) /* if output file not yet open */
+ if (procfs_filename != NULL) /* if output filename known */
+ procfs_file = fopen (procfs_filename, "a"); /* open output file */
+}
+
+static void
+set_procfs_trace_cmd (char *args, int from_tty, struct cmd_list_element *c)
+{
+#if 0 /* not sure what I might actually need to do here, if anything */
+ if (procfs_file)
+ fflush (procfs_file);
+#endif
+}
+
+static void
+set_procfs_file_cmd (char *args, int from_tty, struct cmd_list_element *c)
+{
+ /* Just changed the filename for procfs tracing.
+ If a file was already open, close it. */
+ if (procfs_file)
+ fclose (procfs_file);
+ procfs_file = NULL;
+}
+
+
+#ifndef NEW_PROC_API
+
+static struct trans ioctl_table[] = {
+#ifdef PIOCACINFO /* irix */
+ { PIOCACINFO, "PIOCACINFO", "get process account info" },
+#endif
+ { PIOCACTION, "PIOCACTION", "get signal action structs" },
+#ifdef PIOCARGUMENTS /* osf */
+ { PIOCARGUMENTS, "PIOCARGUMENTS", "command line args" },
+#endif
+#ifdef PIOCAUXV /* solaris aux vectors */
+ { PIOCAUXV, "PIOCAUXV", "get aux vector" },
+ { PIOCNAUXV, "PIOCNAUXV", "get number of aux vector entries" },
+#endif /* AUXV */
+ { PIOCCFAULT, "PIOCCFAULT", "clear current fault" },
+ { PIOCCRED, "PIOCCRED", "get process credentials" },
+#ifdef PIOCENEVCTRS /* irix event counters */
+ { PIOCENEVCTRS, "PIOCENEVCTRS", "acquire and start event counters" },
+ { PIOCGETEVCTRL, "PIOCGETEVCTRL", "get control info of event counters" },
+ { PIOCGETEVCTRS, "PIOCGETEVCTRS", "dump event counters" },
+ { PIOCGETPREVCTRS, "PIOCGETPREVCTRS", "dump event counters & prusage info" },
+ { PIOCRELEVCTRS, "PIOCRELEVCTRS", "release/stop event counters" },
+ { PIOCSETEVCTRL, "PIOCSETEVCTRL", "set control info of event counters" },
+ { PIOCGETPTIMER, "PIOCGETPTIMER", "get process timers" },
+#endif /* irix event counters */
+ { PIOCGENTRY, "PIOCGENTRY", "get traced syscall entry set" },
+#if defined (PIOCGETPR)
+ { PIOCGETPR, "PIOCGETPR", "read struct proc" },
+#endif
+#if defined (PIOCGETU)
+ { PIOCGETU, "PIOCGETU", "read user area" },
+#endif
+#if defined (PIOCGETUTK) && (defined(KERNEL) || defined(SHOW_UTT)) /* osf */
+ { PIOCGETUTK, "PIOCGETUTK", "get the utask struct" },
+#endif
+ { PIOCGEXIT, "PIOCGEXIT", "get traced syscall exit set" },
+ { PIOCGFAULT, "PIOCGFAULT", "get traced fault set" },
+#ifdef PIOCGFPCR /* osf */
+ { PIOCGFPCR, "PIOCGFPCR", "get FP control register" },
+ { PIOCSFPCR, "PIOCSFPCR", "set FP conrtol register" },
+#endif
+ { PIOCGFPREG, "PIOCGFPREG", "get floating point registers" },
+ { PIOCGHOLD, "PIOCGHOLD", "get held signal set" },
+ { PIOCGREG, "PIOCGREG", "get general registers" },
+ { PIOCGROUPS, "PIOCGROUPS", "get supplementary groups" },
+#ifdef PIOCGSPCACT /* osf */
+ { PIOCGSPCACT, "PIOCGSPCACT", "get special action" },
+ { PIOCSSPCACT, "PIOCSSPCACT", "set special action" },
+#endif
+ { PIOCGTRACE, "PIOCGTRACE", "get traced signal set" },
+#ifdef PIOCGWATCH /* irix watchpoints */
+ { PIOCGWATCH, "PIOCGWATCH", "get watchpoint" },
+ { PIOCSWATCH, "PIOCSWATCH", "set watchpoint" },
+ { PIOCNWATCH, "PIOCNWATCH", "get number of watchpoints" },
+#endif /* irix watchpoints */
+#ifdef PIOCGWIN /* solaris sparc */
+ { PIOCGWIN, "PIOCGWIN", "get gwindows_t" },
+#endif
+#ifdef PIOCGXREG /* solaris sparc extra regs */
+ { PIOCGXREGSIZE, "PIOCXREGSIZE", "get extra register state size" },
+ { PIOCGXREG, "PIOCGXREG", "get extra register state" },
+ { PIOCSXREG, "PIOCSXREG", "set extra register state" },
+#endif /* XREG */
+ { PIOCKILL, "PIOCKILL", "send signal" },
+#ifdef PIOCLDT /* solaris i386 */
+ { PIOCLDT, "PIOCLDT", "get LDT" },
+ { PIOCNLDT, "PIOCNLDT", "get number of LDT entries" },
+#endif
+#ifdef PIOCLSTATUS /* solaris and unixware */
+ { PIOCLSTATUS, "PIOCLSTATUS", "get status of all lwps" },
+ { PIOCLUSAGE, "PIOCLUSAGE", "get resource usage of all lwps" },
+ { PIOCOPENLWP, "PIOCOPENLWP", "get lwp file descriptor" },
+ { PIOCLWPIDS, "PIOCLWPIDS", "get lwp identifiers" },
+#endif /* LWP */
+ { PIOCMAP, "PIOCMAP", "get memory map information" },
+ { PIOCMAXSIG, "PIOCMAXSIG", "get max signal number" },
+ { PIOCNICE, "PIOCNICE", "set nice priority" },
+ { PIOCNMAP, "PIOCNMAP", "get number of memory mappings" },
+ { PIOCOPENM, "PIOCOPENM", "open mapped object for reading" },
+#ifdef PIOCOPENMOBS /* osf */
+ { PIOCOPENMOBS, "PIOCOPENMOBS", "open mapped object" },
+#endif
+#ifdef PIOCOPENPD /* solaris */
+ { PIOCOPENPD, "PIOCOPENPD", "get page data file descriptor" },
+#endif
+ { PIOCPSINFO, "PIOCPSINFO", "get ps(1) information" },
+ { PIOCRESET, "PIOCRESET", "reset process flags" },
+ { PIOCRFORK, "PIOCRFORK", "reset inherit-on-fork flag" },
+ { PIOCRRLC, "PIOCRRLC", "reset run-on-last-close flag" },
+ { PIOCRUN, "PIOCRUN", "make process runnable" },
+#ifdef PIOCSAVECCNTRS /* irix */
+ { PIOCSAVECCNTRS, "PIOCSAVECCNTRS", "parent gets child cntrs" },
+#endif
+ { PIOCSENTRY, "PIOCSENTRY", "set traced syscall entry set" },
+ { PIOCSET, "PIOCSET", "set process flags" },
+ { PIOCSEXIT, "PIOCSEXIT", "set traced syscall exit set" },
+ { PIOCSFAULT, "PIOCSFAULT", "set traced fault set" },
+ { PIOCSFORK, "PIOCSFORK", "set inherit-on-fork flag" },
+ { PIOCSFPREG, "PIOCSFPREG", "set floating point registers" },
+ { PIOCSHOLD, "PIOCSHOLD", "set held signal set" },
+ { PIOCSREG, "PIOCSREG", "set general registers" },
+ { PIOCSRLC, "PIOCSRLC", "set run-on-last-close flag" },
+ { PIOCSSIG, "PIOCSSIG", "set current signal" },
+ { PIOCSTATUS, "PIOCSTATUS", "get process status" },
+ { PIOCSTOP, "PIOCSTOP", "post stop request" },
+ { PIOCSTRACE, "PIOCSTRACE", "set traced signal set" },
+ { PIOCUNKILL, "PIOCUNKILL", "delete a signal" },
+#ifdef PIOCUSAGE /* solaris */
+ { PIOCUSAGE, "PIOCUSAGE", "get resource usage" },
+#endif
+ { PIOCWSTOP, "PIOCWSTOP", "wait for process to stop" },
+
+#ifdef PIOCNTHR /* osf threads */
+ { PIOCNTHR, "PIOCNTHR", "get thread count" },
+ { PIOCRTINH, "PIOCRTINH", "reset inherit-on-thread-creation" },
+ { PIOCSTINH, "PIOCSTINH", "set inherit-on-thread-creation" },
+ { PIOCTLIST, "PIOCTLIST", "get thread ids" },
+ { PIOCXPTH, "PIOCXPTH", "translate port to thread handle" },
+ { PIOCTRUN, "PIOCTRUN", "make thread runnable" },
+ { PIOCTSTATUS, "PIOCTSTATUS", "get thread status" },
+ { PIOCTSTOP, "PIOCTSTOP", "stop a thread" },
+ /* ... TGTRACE TSTRACE TSSIG TKILL TUNKILL TCFAULT TGFAULT TSFAULT
+ TGFPREG TSFPREG TGREG TSREG TACTION TTERM TABRUN TGENTRY TSENTRY
+ TGEXIT TSEXIT TSHOLD ... thread functions */
+#endif /* osf threads */
+ { -1, NULL, NULL }
+};
+
+int
+ioctl_with_trace (int fd, long opcode, void *ptr, char *file, int line)
+{
+ int i = 0;
+ int ret;
+ int arg1;
+
+ prepare_to_trace ();
+
+ if (procfs_trace)
+ {
+ for (i = 0; ioctl_table[i].name != NULL; i++)
+ if (ioctl_table[i].value == opcode)
+ break;
+
+ if (info_verbose)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%s:%d -- ", file, line);
+ switch (opcode) {
+ case PIOCSET:
+ arg1 = ptr ? *(long *) ptr : 0;
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (PIOCSET, %s) %s\n",
+ arg1 == PR_FORK ? "PR_FORK" :
+ arg1 == PR_RLC ? "PR_RLC" :
+#ifdef PR_ASYNC
+ arg1 == PR_ASYNC ? "PR_ASYNC" :
+#endif
+ "<unknown flag>",
+ info_verbose ? ioctl_table[i].desc : "");
+ break;
+ case PIOCRESET:
+ arg1 = ptr ? *(long *) ptr : 0;
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (PIOCRESET, %s) %s\n",
+ arg1 == PR_FORK ? "PR_FORK" :
+ arg1 == PR_RLC ? "PR_RLC" :
+#ifdef PR_ASYNC
+ arg1 == PR_ASYNC ? "PR_ASYNC" :
+#endif
+ "<unknown flag>",
+ info_verbose ? ioctl_table[i].desc : "");
+ break;
+ case PIOCSTRACE:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (PIOCSTRACE) ");
+ proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
+ (sigset_t *) ptr, 0);
+ break;
+ case PIOCSFAULT:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (%s) ",
+ opcode == PIOCSFAULT ? "PIOCSFAULT" : "PIOCGFAULT");
+ proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
+ (fltset_t *) ptr, 0);
+ break;
+ case PIOCSENTRY:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (%s) ",
+ opcode == PIOCSENTRY ? "PIOCSENTRY" : "PIOCGENTRY");
+ proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
+ (sysset_t *) ptr, 0);
+ break;
+ case PIOCSEXIT:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (%s) ",
+ opcode == PIOCSEXIT ? "PIOCSEXIT" : "PIOCGEXIT");
+ proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
+ (sysset_t *) ptr, 0);
+ break;
+ case PIOCSHOLD:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (%s) ",
+ opcode == PIOCSHOLD ? "PIOCSHOLD" : "PIOCGHOLD");
+ proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
+ (sigset_t *) ptr, 0);
+ break;
+ case PIOCSSIG:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (PIOCSSIG) ");
+ proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
+ ptr ? ((siginfo_t *) ptr)->si_signo : 0,
+ 0);
+ fprintf (procfs_file ? procfs_file : stdout, "\n");
+ break;
+ case PIOCRUN:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (PIOCRUN) ");
+
+ arg1 = ptr ? *(long *) ptr : 0;
+ if (arg1 & PRCSIG)
+ fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
+ if (arg1 & PRCFAULT)
+ fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
+ if (arg1 & PRSTRACE)
+ fprintf (procfs_file ? procfs_file : stdout, "setTrace ");
+ if (arg1 & PRSHOLD)
+ fprintf (procfs_file ? procfs_file : stdout, "setHold ");
+ if (arg1 & PRSFAULT)
+ fprintf (procfs_file ? procfs_file : stdout, "setFlt ");
+ if (arg1 & PRSVADDR)
+ fprintf (procfs_file ? procfs_file : stdout, "setVaddr ");
+ if (arg1 & PRSTEP)
+ fprintf (procfs_file ? procfs_file : stdout, "step ");
+ if (arg1 & PRSABORT)
+ fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
+ if (arg1 & PRSTOP)
+ fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
+
+ fprintf (procfs_file ? procfs_file : stdout, "\n");
+ break;
+ case PIOCKILL:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (PIOCKILL) ");
+ proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
+ ptr ? *(long *) ptr : 0, 0);
+ fprintf (procfs_file ? procfs_file : stdout, "\n");
+ break;
+#ifdef PIOCSSPCACT
+ case PIOCSSPCACT:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (PIOCSSPCACT) ");
+ arg1 = ptr ? *(long *) ptr : 0;
+ if (arg1 & PRFS_STOPFORK)
+ fprintf (procfs_file ? procfs_file : stdout, "stopFork ");
+ if (arg1 & PRFS_STOPEXEC)
+ fprintf (procfs_file ? procfs_file : stdout, "stopExec ");
+ if (arg1 & PRFS_STOPTERM)
+ fprintf (procfs_file ? procfs_file : stdout, "stopTerm ");
+ if (arg1 & PRFS_STOPTCR)
+ fprintf (procfs_file ? procfs_file : stdout, "stopThreadCreate ");
+ if (arg1 & PRFS_STOPTTERM)
+ fprintf (procfs_file ? procfs_file : stdout, "stopThreadTerm ");
+ if (arg1 & PRFS_KOLC)
+ fprintf (procfs_file ? procfs_file : stdout, "killOnLastClose ");
+ fprintf (procfs_file ? procfs_file : stdout, "\n");
+ break;
+#endif /* PIOCSSPCACT */
+ default:
+ if (ioctl_table[i].name)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (%s) %s\n",
+ ioctl_table[i].name,
+ info_verbose ? ioctl_table[i].desc : "");
+ else
+ fprintf (procfs_file ? procfs_file : stdout,
+ "ioctl (<unknown %ld (0x%lx)) \n", opcode, opcode);
+ break;
+ }
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+ errno = 0;
+ ret = ioctl (fd, opcode, ptr);
+ if (procfs_trace && ret < 0)
+ {
+ fprintf (procfs_file ? procfs_file : stdout,
+ "[ioctl (%s) FAILED! (%s)]\n",
+ ioctl_table[i].name != NULL ?
+ ioctl_table[i].name : "<unknown>",
+ safe_strerror (errno));
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+
+ return ret;
+}
+
+#else /* NEW_PROC_API */
+
+static struct trans rw_table[] = {
+#ifdef PCAGENT /* solaris */
+ { PCAGENT, "PCAGENT", "create agent lwp with regs from argument" },
+#endif
+ { PCCFAULT, "PCCFAULT", "clear current fault" },
+#ifdef PCCSIG /* solaris */
+ { PCCSIG, "PCCSIG", "clear current signal" },
+#endif
+#ifdef PCDSTOP /* solaris */
+ { PCDSTOP, "PCDSTOP", "post stop request" },
+#endif
+ { PCKILL, "PCKILL", "post a signal" },
+#ifdef PCNICE /* solaris */
+ { PCNICE, "PCNICE", "set nice priority" },
+#endif
+#ifdef PCREAD /* solaris */
+ { PCREAD, "PCREAD", "read from the address space" },
+ { PCWRITE, "PCWRITE", "write to the address space" },
+#endif
+#ifdef PCRESET /* unixware */
+ { PCRESET, "PCRESET", "unset modes" },
+#endif
+ { PCRUN, "PCRUN", "make process/lwp runnable" },
+#ifdef PCSASRS /* solaris 2.7 only */
+ { PCSASRS, "PCSASRS", "set ancillary state registers" },
+#endif
+#ifdef PCSCRED /* solaris */
+ { PCSCRED, "PCSCRED", "set process credentials" },
+#endif
+ { PCSENTRY, "PCSENTRY", "set traced syscall entry set" },
+ { PCSET, "PCSET", "set modes" },
+ { PCSEXIT, "PCSEXIT", "set traced syscall exit set" },
+ { PCSFAULT, "PCSFAULT", "set traced fault set" },
+ { PCSFPREG, "PCSFPREG", "set floating point registers" },
+#ifdef PCSHOLD /* solaris */
+ { PCSHOLD, "PCSHOLD", "set signal mask" },
+#endif
+ { PCSREG, "PCSREG", "set general registers" },
+ { PCSSIG, "PCSSIG", "set current signal" },
+ { PCSTOP, "PCSTOP", "post stop request and wait" },
+ { PCSTRACE, "PCSTRACE", "set traced signal set" },
+#ifdef PCSVADDR /* solaris */
+ { PCSVADDR, "PCSVADDR", "set pc virtual address" },
+#endif
+#ifdef PCSXREG /* solaris sparc only */
+ { PCSXREG, "PCSXREG", "set extra registers" },
+#endif
+#ifdef PCTWSTOP /* solaris */
+ { PCTWSTOP, "PCTWSTOP", "wait for stop, with timeout arg" },
+#endif
+#ifdef PCUNKILL /* solaris */
+ { PCUNKILL, "PCUNKILL", "delete a pending signal" },
+#endif
+#ifdef PCUNSET /* solaris */
+ { PCUNSET, "PCUNSET", "unset modes" },
+#endif
+#ifdef PCWATCH /* solaris */
+ { PCWATCH, "PCWATCH", "set/unset watched memory area" },
+#endif
+ { PCWSTOP, "PCWSTOP", "wait for process/lwp to stop, no timeout" },
+ { 0, NULL, NULL }
+};
+
+static off_t lseek_offset;
+
+int
+write_with_trace (int fd, void *varg, size_t len, char *file, int line)
+{
+ int i = ARRAY_SIZE (rw_table) - 1;
+ int ret;
+ procfs_ctl_t *arg = (procfs_ctl_t *) varg;
+
+ prepare_to_trace ();
+ if (procfs_trace)
+ {
+ procfs_ctl_t opcode = arg[0];
+ for (i = 0; rw_table[i].name != NULL; i++)
+ if (rw_table[i].value == opcode)
+ break;
+
+ if (info_verbose)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%s:%d -- ", file, line);
+ switch (opcode) {
+ case PCSET:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCSET, %s) %s\n",
+ arg[1] == PR_FORK ? "PR_FORK" :
+ arg[1] == PR_RLC ? "PR_RLC" :
+#ifdef PR_ASYNC
+ arg[1] == PR_ASYNC ? "PR_ASYNC" :
+#endif
+ "<unknown flag>",
+ info_verbose ? rw_table[i].desc : "");
+ break;
+#ifdef PCUNSET
+ case PCUNSET:
+#endif
+#ifdef PCRESET
+#if PCRESET != PCUNSET
+ case PCRESET:
+#endif
+#endif
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCRESET, %s) %s\n",
+ arg[1] == PR_FORK ? "PR_FORK" :
+ arg[1] == PR_RLC ? "PR_RLC" :
+#ifdef PR_ASYNC
+ arg[1] == PR_ASYNC ? "PR_ASYNC" :
+#endif
+ "<unknown flag>",
+ info_verbose ? rw_table[i].desc : "");
+ break;
+ case PCSTRACE:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCSTRACE) ");
+ proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
+ (sigset_t *) &arg[1], 0);
+ break;
+ case PCSFAULT:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCSFAULT) ");
+ proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
+ (fltset_t *) &arg[1], 0);
+ break;
+ case PCSENTRY:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCSENTRY) ");
+ proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
+ (sysset_t *) &arg[1], 0);
+ break;
+ case PCSEXIT:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCSEXIT) ");
+ proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
+ (sysset_t *) &arg[1], 0);
+ break;
+#ifdef PCSHOLD
+ case PCSHOLD:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCSHOLD) ");
+ proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
+ (sigset_t *) &arg[1], 0);
+ break;
+#endif
+ case PCSSIG:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCSSIG) ");
+ proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
+ arg[1] ? ((siginfo_t *) &arg[1])->si_signo
+ : 0,
+ 0);
+ fprintf (procfs_file ? procfs_file : stdout, "\n");
+ break;
+ case PCRUN:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCRUN) ");
+ if (arg[1] & PRCSIG)
+ fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
+ if (arg[1] & PRCFAULT)
+ fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
+ if (arg[1] & PRSTEP)
+ fprintf (procfs_file ? procfs_file : stdout, "step ");
+#ifdef PRSABORT
+ if (arg[1] & PRSABORT)
+ fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
+#endif
+#ifdef PRSTOP
+ if (arg[1] & PRSTOP)
+ fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
+#endif
+
+ fprintf (procfs_file ? procfs_file : stdout, "\n");
+ break;
+ case PCKILL:
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (PCKILL) ");
+ proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
+ arg[1], 0);
+ fprintf (procfs_file ? procfs_file : stdout, "\n");
+ break;
+ default:
+ {
+ if (rw_table[i].name)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (%s) %s\n",
+ rw_table[i].name,
+ info_verbose ? rw_table[i].desc : "");
+ else
+ {
+ if (lseek_offset != -1)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (<unknown>, %lud bytes at 0x%08lx) \n",
+ (unsigned long) len, (unsigned long) lseek_offset);
+ else
+ fprintf (procfs_file ? procfs_file : stdout,
+ "write (<unknown>, %lud bytes) \n",
+ (unsigned long) len);
+ }
+ break;
+ }
+ }
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+ errno = 0;
+ ret = write (fd, (void *) arg, len);
+ if (procfs_trace && ret != len)
+ {
+ fprintf (procfs_file ? procfs_file : stdout,
+ "[write (%s) FAILED! (%s)]\n",
+ rw_table[i].name != NULL ?
+ rw_table[i].name : "<unknown>",
+ safe_strerror (errno));
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+
+ lseek_offset = -1;
+ return ret;
+}
+
+off_t
+lseek_with_trace (int fd, off_t offset, int whence, char *file, int line)
+{
+ off_t ret;
+
+ prepare_to_trace ();
+ errno = 0;
+ ret = lseek (fd, offset, whence);
+ lseek_offset = ret;
+ if (procfs_trace && (ret == -1 || errno != 0))
+ {
+ fprintf (procfs_file ? procfs_file : stdout,
+ "[lseek (0x%08lx) FAILED! (%s)]\n",
+ (unsigned long) offset, safe_strerror (errno));
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+
+ return ret;
+}
+
+#endif /* NEW_PROC_API */
+
+int
+open_with_trace (char *filename, int mode, char *file, int line)
+{
+ int ret;
+
+ prepare_to_trace ();
+ errno = 0;
+ ret = open (filename, mode);
+ if (procfs_trace)
+ {
+ if (info_verbose)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%s:%d -- ", file, line);
+
+ if (errno)
+ {
+ fprintf (procfs_file ? procfs_file : stdout,
+ "[open FAILED! (%s) line %d]\\n",
+ safe_strerror (errno), line);
+ }
+ else
+ {
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%d = open (%s, ", ret, filename);
+ if (mode == O_RDONLY)
+ fprintf (procfs_file ? procfs_file : stdout, "O_RDONLY) %d\n",
+ line);
+ else if (mode == O_WRONLY)
+ fprintf (procfs_file ? procfs_file : stdout, "O_WRONLY) %d\n",
+ line);
+ else if (mode == O_RDWR)
+ fprintf (procfs_file ? procfs_file : stdout, "O_RDWR) %d\n",
+ line);
+ }
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+
+ return ret;
+}
+
+int
+close_with_trace (int fd, char *file, int line)
+{
+ int ret;
+
+ prepare_to_trace ();
+ errno = 0;
+ ret = close (fd);
+ if (procfs_trace)
+ {
+ if (info_verbose)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%s:%d -- ", file, line);
+ if (errno)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "[close FAILED! (%s)]\n", safe_strerror (errno));
+ else
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%d = close (%d)\n", ret, fd);
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+
+ return ret;
+}
+
+pid_t
+wait_with_trace (int *wstat, char *file, int line)
+{
+ int ret, lstat = 0;
+
+ prepare_to_trace ();
+ if (procfs_trace)
+ {
+ if (info_verbose)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%s:%d -- ", file, line);
+ fprintf (procfs_file ? procfs_file : stdout,
+ "wait (line %d) ", line);
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+ errno = 0;
+ ret = wait (&lstat);
+ if (procfs_trace)
+ {
+ if (errno)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "[wait FAILED! (%s)]\n", safe_strerror (errno));
+ else
+ fprintf (procfs_file ? procfs_file : stdout,
+ "returned pid %d, status 0x%x\n", ret, lstat);
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+ if (wstat)
+ *wstat = lstat;
+
+ return ret;
+}
+
+void
+procfs_note (char *msg, char *file, int line)
+{
+ prepare_to_trace ();
+ if (procfs_trace)
+ {
+ if (info_verbose)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "%s:%d -- ", file, line);
+ fprintf (procfs_file ? procfs_file : stdout, "%s", msg);
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+}
+
+void
+proc_prettyfprint_status (long flags, int why, int what, int thread)
+{
+ prepare_to_trace ();
+ if (procfs_trace)
+ {
+ if (thread)
+ fprintf (procfs_file ? procfs_file : stdout,
+ "Thread %d: ", thread);
+
+ proc_prettyfprint_flags (procfs_file ? procfs_file : stdout,
+ flags, 0);
+
+ if (flags & (PR_STOPPED | PR_ISTOP))
+ proc_prettyfprint_why (procfs_file ? procfs_file : stdout,
+ why, what, 0);
+ if (procfs_file)
+ fflush (procfs_file);
+ }
+}
+
+
+void
+_initialize_proc_api (void)
+{
+ struct cmd_list_element *c;
+
+ c = add_set_cmd ("procfs-trace", no_class,
+ var_boolean, (char *) &procfs_trace,
+ "Set tracing for /proc api calls.\n", &setlist);
+
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_procfs_trace_cmd);
+ set_cmd_completer (c, filename_completer);
+
+ c = add_set_cmd ("procfs-file", no_class, var_filename,
+ (char *) &procfs_filename,
+ "Set filename for /proc tracefile.\n", &setlist);
+
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_procfs_file_cmd);
+}
diff --git a/contrib/gdb/gdb/proc-events.c b/contrib/gdb/gdb/proc-events.c
new file mode 100755
index 0000000..5365fef
--- /dev/null
+++ b/contrib/gdb/gdb/proc-events.c
@@ -0,0 +1,1777 @@
+/* Machine independent support for SVR4 /proc (process file system) for GDB.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+ Written by Michael Snyder at Cygnus Solutions.
+ Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ * Pretty-print "events of interest".
+ *
+ * This module includes pretty-print routines for:
+ * faults (hardware exceptions):
+ * signals (software interrupts):
+ * syscalls
+ *
+ * FIXME: At present, the syscall translation table must be initialized,
+ * which is not true of the other translation tables.
+ */
+
+#include "defs.h"
+
+#if defined (NEW_PROC_API)
+#define _STRUCTURED_PROC 1
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
+#ifdef HAVE_SYS_FAULT_H
+#include <sys/fault.h>
+#endif
+
+/* 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 */
+};
+
+/*
+ * pretty print syscalls
+ */
+
+/* Ugh -- Unixware and Solaris spell these differently! */
+
+#ifdef SYS_lwpcreate
+#define SYS_lwp_create SYS_lwpcreate
+#endif
+
+#ifdef SYS_lwpexit
+#define SYS_lwp_exit SYS_lwpexit
+#endif
+
+#ifdef SYS_lwpwait
+#define SYS_lwp_wait SYS_lwpwait
+#endif
+
+#ifdef SYS_lwpself
+#define SYS_lwp_self SYS_lwpself
+#endif
+
+#ifdef SYS_lwpinfo
+#define SYS_lwp_info SYS_lwpinfo
+#endif
+
+#ifdef SYS_lwpprivate
+#define SYS_lwp_private SYS_lwpprivate
+#endif
+
+#ifdef SYS_lwpkill
+#define SYS_lwp_kill SYS_lwpkill
+#endif
+
+#ifdef SYS_lwpsuspend
+#define SYS_lwp_suspend SYS_lwpsuspend
+#endif
+
+#ifdef SYS_lwpcontinue
+#define SYS_lwp_continue SYS_lwpcontinue
+#endif
+
+
+/* Syscall translation table. */
+
+#define MAX_SYSCALLS 262 /* pretty arbitrary */
+static char * syscall_table[MAX_SYSCALLS];
+
+void
+init_syscall_table (void)
+{
+#if defined (SYS_BSD_getime)
+ syscall_table[SYS_BSD_getime] = "BSD_getime";
+#endif
+#if defined (SYS_BSDgetpgrp)
+ syscall_table[SYS_BSDgetpgrp] = "BSDgetpgrp";
+#endif
+#if defined (SYS_BSDsetpgrp)
+ syscall_table[SYS_BSDsetpgrp] = "BSDsetpgrp";
+#endif
+#if defined (SYS_acancel)
+ syscall_table[SYS_acancel] = "acancel";
+#endif
+#if defined (SYS_accept)
+ syscall_table[SYS_accept] = "accept";
+#endif
+#if defined (SYS_access)
+ syscall_table[SYS_access] = "access";
+#endif
+#if defined (SYS_acct)
+ syscall_table[SYS_acct] = "acct";
+#endif
+#if defined (SYS_acl)
+ syscall_table[SYS_acl] = "acl";
+#endif
+#if defined (SYS_aclipc)
+ syscall_table[SYS_aclipc] = "aclipc";
+#endif
+#if defined (SYS_adjtime)
+ syscall_table[SYS_adjtime] = "adjtime";
+#endif
+#if defined (SYS_afs_syscall)
+ syscall_table[SYS_afs_syscall] = "afs_syscall";
+#endif
+#if defined (SYS_alarm)
+ syscall_table[SYS_alarm] = "alarm";
+#endif
+#if defined (SYS_alt_plock)
+ syscall_table[SYS_alt_plock] = "alt_plock";
+#endif
+#if defined (SYS_alt_sigpending)
+ syscall_table[SYS_alt_sigpending] = "alt_sigpending";
+#endif
+#if defined (SYS_async)
+ syscall_table[SYS_async] = "async";
+#endif
+#if defined (SYS_async_daemon)
+ syscall_table[SYS_async_daemon] = "async_daemon";
+#endif
+#if defined (SYS_audcntl)
+ syscall_table[SYS_audcntl] = "audcntl";
+#endif
+#if defined (SYS_audgen)
+ syscall_table[SYS_audgen] = "audgen";
+#endif
+#if defined (SYS_auditbuf)
+ syscall_table[SYS_auditbuf] = "auditbuf";
+#endif
+#if defined (SYS_auditctl)
+ syscall_table[SYS_auditctl] = "auditctl";
+#endif
+#if defined (SYS_auditdmp)
+ syscall_table[SYS_auditdmp] = "auditdmp";
+#endif
+#if defined (SYS_auditevt)
+ syscall_table[SYS_auditevt] = "auditevt";
+#endif
+#if defined (SYS_auditlog)
+ syscall_table[SYS_auditlog] = "auditlog";
+#endif
+#if defined (SYS_auditsys)
+ syscall_table[SYS_auditsys] = "auditsys";
+#endif
+#if defined (SYS_bind)
+ syscall_table[SYS_bind] = "bind";
+#endif
+#if defined (SYS_block)
+ syscall_table[SYS_block] = "block";
+#endif
+#if defined (SYS_brk)
+ syscall_table[SYS_brk] = "brk";
+#endif
+#if defined (SYS_cachectl)
+ syscall_table[SYS_cachectl] = "cachectl";
+#endif
+#if defined (SYS_cacheflush)
+ syscall_table[SYS_cacheflush] = "cacheflush";
+#endif
+#if defined (SYS_cancelblock)
+ syscall_table[SYS_cancelblock] = "cancelblock";
+#endif
+#if defined (SYS_cg_bind)
+ syscall_table[SYS_cg_bind] = "cg_bind";
+#endif
+#if defined (SYS_cg_current)
+ syscall_table[SYS_cg_current] = "cg_current";
+#endif
+#if defined (SYS_cg_ids)
+ syscall_table[SYS_cg_ids] = "cg_ids";
+#endif
+#if defined (SYS_cg_info)
+ syscall_table[SYS_cg_info] = "cg_info";
+#endif
+#if defined (SYS_cg_memloc)
+ syscall_table[SYS_cg_memloc] = "cg_memloc";
+#endif
+#if defined (SYS_cg_processors)
+ syscall_table[SYS_cg_processors] = "cg_processors";
+#endif
+#if defined (SYS_chdir)
+ syscall_table[SYS_chdir] = "chdir";
+#endif
+#if defined (SYS_chflags)
+ syscall_table[SYS_chflags] = "chflags";
+#endif
+#if defined (SYS_chmod)
+ syscall_table[SYS_chmod] = "chmod";
+#endif
+#if defined (SYS_chown)
+ syscall_table[SYS_chown] = "chown";
+#endif
+#if defined (SYS_chroot)
+ syscall_table[SYS_chroot] = "chroot";
+#endif
+#if defined (SYS_clocal)
+ syscall_table[SYS_clocal] = "clocal";
+#endif
+#if defined (SYS_clock_getres)
+ syscall_table[SYS_clock_getres] = "clock_getres";
+#endif
+#if defined (SYS_clock_gettime)
+ syscall_table[SYS_clock_gettime] = "clock_gettime";
+#endif
+#if defined (SYS_clock_settime)
+ syscall_table[SYS_clock_settime] = "clock_settime";
+#endif
+#if defined (SYS_close)
+ syscall_table[SYS_close] = "close";
+#endif
+#if defined (SYS_connect)
+ syscall_table[SYS_connect] = "connect";
+#endif
+#if defined (SYS_context)
+ syscall_table[SYS_context] = "context";
+#endif
+#if defined (SYS_creat)
+ syscall_table[SYS_creat] = "creat";
+#endif
+#if defined (SYS_creat64)
+ syscall_table[SYS_creat64] = "creat64";
+#endif
+#if defined (SYS_devstat)
+ syscall_table[SYS_devstat] = "devstat";
+#endif
+#if defined (SYS_dmi)
+ syscall_table[SYS_dmi] = "dmi";
+#endif
+#if defined (SYS_door)
+ syscall_table[SYS_door] = "door";
+#endif
+#if defined (SYS_dshmsys)
+ syscall_table[SYS_dshmsys] = "dshmsys";
+#endif
+#if defined (SYS_dup)
+ syscall_table[SYS_dup] = "dup";
+#endif
+#if defined (SYS_dup2)
+ syscall_table[SYS_dup2] = "dup2";
+#endif
+#if defined (SYS_evsys)
+ syscall_table[SYS_evsys] = "evsys";
+#endif
+#if defined (SYS_evtrapret)
+ syscall_table[SYS_evtrapret] = "evtrapret";
+#endif
+#if defined (SYS_exec)
+ syscall_table[SYS_exec] = "exec";
+#endif
+#if defined (SYS_exec_with_loader)
+ syscall_table[SYS_exec_with_loader] = "exec_with_loader";
+#endif
+#if defined (SYS_execv)
+ syscall_table[SYS_execv] = "execv";
+#endif
+#if defined (SYS_execve)
+ syscall_table[SYS_execve] = "execve";
+#endif
+#if defined (SYS_exit)
+ syscall_table[SYS_exit] = "exit";
+#endif
+#if defined (SYS_exportfs)
+ syscall_table[SYS_exportfs] = "exportfs";
+#endif
+#if defined (SYS_facl)
+ syscall_table[SYS_facl] = "facl";
+#endif
+#if defined (SYS_fchdir)
+ syscall_table[SYS_fchdir] = "fchdir";
+#endif
+#if defined (SYS_fchflags)
+ syscall_table[SYS_fchflags] = "fchflags";
+#endif
+#if defined (SYS_fchmod)
+ syscall_table[SYS_fchmod] = "fchmod";
+#endif
+#if defined (SYS_fchown)
+ syscall_table[SYS_fchown] = "fchown";
+#endif
+#if defined (SYS_fchroot)
+ syscall_table[SYS_fchroot] = "fchroot";
+#endif
+#if defined (SYS_fcntl)
+ syscall_table[SYS_fcntl] = "fcntl";
+#endif
+#if defined (SYS_fdatasync)
+ syscall_table[SYS_fdatasync] = "fdatasync";
+#endif
+#if defined (SYS_fdevstat)
+ syscall_table[SYS_fdevstat] = "fdevstat";
+#endif
+#if defined (SYS_fdsync)
+ syscall_table[SYS_fdsync] = "fdsync";
+#endif
+#if defined (SYS_filepriv)
+ syscall_table[SYS_filepriv] = "filepriv";
+#endif
+#if defined (SYS_flock)
+ syscall_table[SYS_flock] = "flock";
+#endif
+#if defined (SYS_flvlfile)
+ syscall_table[SYS_flvlfile] = "flvlfile";
+#endif
+#if defined (SYS_fork)
+ syscall_table[SYS_fork] = "fork";
+#endif
+#if defined (SYS_fork1)
+ syscall_table[SYS_fork1] = "fork1";
+#endif
+#if defined (SYS_forkall)
+ syscall_table[SYS_forkall] = "forkall";
+#endif
+#if defined (SYS_fpathconf)
+ syscall_table[SYS_fpathconf] = "fpathconf";
+#endif
+#if defined (SYS_fstat)
+ syscall_table[SYS_fstat] = "fstat";
+#endif
+#if defined (SYS_fstat64)
+ syscall_table[SYS_fstat64] = "fstat64";
+#endif
+#if defined (SYS_fstatfs)
+ syscall_table[SYS_fstatfs] = "fstatfs";
+#endif
+#if defined (SYS_fstatvfs)
+ syscall_table[SYS_fstatvfs] = "fstatvfs";
+#endif
+#if defined (SYS_fstatvfs64)
+ syscall_table[SYS_fstatvfs64] = "fstatvfs64";
+#endif
+#if defined (SYS_fsync)
+ syscall_table[SYS_fsync] = "fsync";
+#endif
+#if defined (SYS_ftruncate)
+ syscall_table[SYS_ftruncate] = "ftruncate";
+#endif
+#if defined (SYS_ftruncate64)
+ syscall_table[SYS_ftruncate64] = "ftruncate64";
+#endif
+#if defined (SYS_fuser)
+ syscall_table[SYS_fuser] = "fuser";
+#endif
+#if defined (SYS_fxstat)
+ syscall_table[SYS_fxstat] = "fxstat";
+#endif
+#if defined (SYS_get_sysinfo)
+ syscall_table[SYS_get_sysinfo] = "get_sysinfo";
+#endif
+#if defined (SYS_getaddressconf)
+ syscall_table[SYS_getaddressconf] = "getaddressconf";
+#endif
+#if defined (SYS_getcontext)
+ syscall_table[SYS_getcontext] = "getcontext";
+#endif
+#if defined (SYS_getdents)
+ syscall_table[SYS_getdents] = "getdents";
+#endif
+#if defined (SYS_getdents64)
+ syscall_table[SYS_getdents64] = "getdents64";
+#endif
+#if defined (SYS_getdirentries)
+ syscall_table[SYS_getdirentries] = "getdirentries";
+#endif
+#if defined (SYS_getdomainname)
+ syscall_table[SYS_getdomainname] = "getdomainname";
+#endif
+#if defined (SYS_getdtablesize)
+ syscall_table[SYS_getdtablesize] = "getdtablesize";
+#endif
+#if defined (SYS_getfh)
+ syscall_table[SYS_getfh] = "getfh";
+#endif
+#if defined (SYS_getfsstat)
+ syscall_table[SYS_getfsstat] = "getfsstat";
+#endif
+#if defined (SYS_getgid)
+ syscall_table[SYS_getgid] = "getgid";
+#endif
+#if defined (SYS_getgroups)
+ syscall_table[SYS_getgroups] = "getgroups";
+#endif
+#if defined (SYS_gethostid)
+ syscall_table[SYS_gethostid] = "gethostid";
+#endif
+#if defined (SYS_gethostname)
+ syscall_table[SYS_gethostname] = "gethostname";
+#endif
+#if defined (SYS_getitimer)
+ syscall_table[SYS_getitimer] = "getitimer";
+#endif
+#if defined (SYS_getksym)
+ syscall_table[SYS_getksym] = "getksym";
+#endif
+#if defined (SYS_getlogin)
+ syscall_table[SYS_getlogin] = "getlogin";
+#endif
+#if defined (SYS_getmnt)
+ syscall_table[SYS_getmnt] = "getmnt";
+#endif
+#if defined (SYS_getmsg)
+ syscall_table[SYS_getmsg] = "getmsg";
+#endif
+#if defined (SYS_getpagesize)
+ syscall_table[SYS_getpagesize] = "getpagesize";
+#endif
+#if defined (SYS_getpeername)
+ syscall_table[SYS_getpeername] = "getpeername";
+#endif
+#if defined (SYS_getpgid)
+ syscall_table[SYS_getpgid] = "getpgid";
+#endif
+#if defined (SYS_getpgrp)
+ syscall_table[SYS_getpgrp] = "getpgrp";
+#endif
+#if defined (SYS_getpid)
+ syscall_table[SYS_getpid] = "getpid";
+#endif
+#if defined (SYS_getpmsg)
+ syscall_table[SYS_getpmsg] = "getpmsg";
+#endif
+#if defined (SYS_getpriority)
+ syscall_table[SYS_getpriority] = "getpriority";
+#endif
+#if defined (SYS_getrlimit)
+ syscall_table[SYS_getrlimit] = "getrlimit";
+#endif
+#if defined (SYS_getrlimit64)
+ syscall_table[SYS_getrlimit64] = "getrlimit64";
+#endif
+#if defined (SYS_getrusage)
+ syscall_table[SYS_getrusage] = "getrusage";
+#endif
+#if defined (SYS_getsid)
+ syscall_table[SYS_getsid] = "getsid";
+#endif
+#if defined (SYS_getsockname)
+ syscall_table[SYS_getsockname] = "getsockname";
+#endif
+#if defined (SYS_getsockopt)
+ syscall_table[SYS_getsockopt] = "getsockopt";
+#endif
+#if defined (SYS_gettimeofday)
+ syscall_table[SYS_gettimeofday] = "gettimeofday";
+#endif
+#if defined (SYS_getuid)
+ syscall_table[SYS_getuid] = "getuid";
+#endif
+#if defined (SYS_gtty)
+ syscall_table[SYS_gtty] = "gtty";
+#endif
+#if defined (SYS_hrtsys)
+ syscall_table[SYS_hrtsys] = "hrtsys";
+#endif
+#if defined (SYS_inst_sync)
+ syscall_table[SYS_inst_sync] = "inst_sync";
+#endif
+#if defined (SYS_install_utrap)
+ syscall_table[SYS_install_utrap] = "install_utrap";
+#endif
+#if defined (SYS_invlpg)
+ syscall_table[SYS_invlpg] = "invlpg";
+#endif
+#if defined (SYS_ioctl)
+ syscall_table[SYS_ioctl] = "ioctl";
+#endif
+#if defined (SYS_kaio)
+ syscall_table[SYS_kaio] = "kaio";
+#endif
+#if defined (SYS_keyctl)
+ syscall_table[SYS_keyctl] = "keyctl";
+#endif
+#if defined (SYS_kill)
+ syscall_table[SYS_kill] = "kill";
+#endif
+#if defined (SYS_killpg)
+ syscall_table[SYS_killpg] = "killpg";
+#endif
+#if defined (SYS_kloadcall)
+ syscall_table[SYS_kloadcall] = "kloadcall";
+#endif
+#if defined (SYS_kmodcall)
+ syscall_table[SYS_kmodcall] = "kmodcall";
+#endif
+#if defined (SYS_ksigaction)
+ syscall_table[SYS_ksigaction] = "ksigaction";
+#endif
+#if defined (SYS_ksigprocmask)
+ syscall_table[SYS_ksigprocmask] = "ksigprocmask";
+#endif
+#if defined (SYS_ksigqueue)
+ syscall_table[SYS_ksigqueue] = "ksigqueue";
+#endif
+#if defined (SYS_lchown)
+ syscall_table[SYS_lchown] = "lchown";
+#endif
+#if defined (SYS_link)
+ syscall_table[SYS_link] = "link";
+#endif
+#if defined (SYS_listen)
+ syscall_table[SYS_listen] = "listen";
+#endif
+#if defined (SYS_llseek)
+ syscall_table[SYS_llseek] = "llseek";
+#endif
+#if defined (SYS_lseek)
+ syscall_table[SYS_lseek] = "lseek";
+#endif
+#if defined (SYS_lseek64)
+ syscall_table[SYS_lseek64] = "lseek64";
+#endif
+#if defined (SYS_lstat)
+ syscall_table[SYS_lstat] = "lstat";
+#endif
+#if defined (SYS_lstat64)
+ syscall_table[SYS_lstat64] = "lstat64";
+#endif
+#if defined (SYS_lvldom)
+ syscall_table[SYS_lvldom] = "lvldom";
+#endif
+#if defined (SYS_lvlequal)
+ syscall_table[SYS_lvlequal] = "lvlequal";
+#endif
+#if defined (SYS_lvlfile)
+ syscall_table[SYS_lvlfile] = "lvlfile";
+#endif
+#if defined (SYS_lvlipc)
+ syscall_table[SYS_lvlipc] = "lvlipc";
+#endif
+#if defined (SYS_lvlproc)
+ syscall_table[SYS_lvlproc] = "lvlproc";
+#endif
+#if defined (SYS_lvlvfs)
+ syscall_table[SYS_lvlvfs] = "lvlvfs";
+#endif
+#if defined (SYS_lwp_alarm)
+ syscall_table[SYS_lwp_alarm] = "lwp_alarm";
+#endif
+#if defined (SYS_lwp_cond_broadcast)
+ syscall_table[SYS_lwp_cond_broadcast] = "lwp_cond_broadcast";
+#endif
+#if defined (SYS_lwp_cond_signal)
+ syscall_table[SYS_lwp_cond_signal] = "lwp_cond_signal";
+#endif
+#if defined (SYS_lwp_cond_wait)
+ syscall_table[SYS_lwp_cond_wait] = "lwp_cond_wait";
+#endif
+#if defined (SYS_lwp_continue)
+ syscall_table[SYS_lwp_continue] = "lwp_continue";
+#endif
+#if defined (SYS_lwp_create)
+ syscall_table[SYS_lwp_create] = "lwp_create";
+#endif
+#if defined (SYS_lwp_exit)
+ syscall_table[SYS_lwp_exit] = "lwp_exit";
+#endif
+#if defined (SYS_lwp_getprivate)
+ syscall_table[SYS_lwp_getprivate] = "lwp_getprivate";
+#endif
+#if defined (SYS_lwp_info)
+ syscall_table[SYS_lwp_info] = "lwp_info";
+#endif
+#if defined (SYS_lwp_kill)
+ syscall_table[SYS_lwp_kill] = "lwp_kill";
+#endif
+#if defined (SYS_lwp_mutex_init)
+ syscall_table[SYS_lwp_mutex_init] = "lwp_mutex_init";
+#endif
+#if defined (SYS_lwp_mutex_lock)
+ syscall_table[SYS_lwp_mutex_lock] = "lwp_mutex_lock";
+#endif
+#if defined (SYS_lwp_mutex_trylock)
+ syscall_table[SYS_lwp_mutex_trylock] = "lwp_mutex_trylock";
+#endif
+#if defined (SYS_lwp_mutex_unlock)
+ syscall_table[SYS_lwp_mutex_unlock] = "lwp_mutex_unlock";
+#endif
+#if defined (SYS_lwp_private)
+ syscall_table[SYS_lwp_private] = "lwp_private";
+#endif
+#if defined (SYS_lwp_self)
+ syscall_table[SYS_lwp_self] = "lwp_self";
+#endif
+#if defined (SYS_lwp_sema_post)
+ syscall_table[SYS_lwp_sema_post] = "lwp_sema_post";
+#endif
+#if defined (SYS_lwp_sema_trywait)
+ syscall_table[SYS_lwp_sema_trywait] = "lwp_sema_trywait";
+#endif
+#if defined (SYS_lwp_sema_wait)
+ syscall_table[SYS_lwp_sema_wait] = "lwp_sema_wait";
+#endif
+#if defined (SYS_lwp_setprivate)
+ syscall_table[SYS_lwp_setprivate] = "lwp_setprivate";
+#endif
+#if defined (SYS_lwp_sigredirect)
+ syscall_table[SYS_lwp_sigredirect] = "lwp_sigredirect";
+#endif
+#if defined (SYS_lwp_suspend)
+ syscall_table[SYS_lwp_suspend] = "lwp_suspend";
+#endif
+#if defined (SYS_lwp_wait)
+ syscall_table[SYS_lwp_wait] = "lwp_wait";
+#endif
+#if defined (SYS_lxstat)
+ syscall_table[SYS_lxstat] = "lxstat";
+#endif
+#if defined (SYS_madvise)
+ syscall_table[SYS_madvise] = "madvise";
+#endif
+#if defined (SYS_memcntl)
+ syscall_table[SYS_memcntl] = "memcntl";
+#endif
+#if defined (SYS_mincore)
+ syscall_table[SYS_mincore] = "mincore";
+#endif
+#if defined (SYS_mincore)
+ syscall_table[SYS_mincore] = "mincore";
+#endif
+#if defined (SYS_mkdir)
+ syscall_table[SYS_mkdir] = "mkdir";
+#endif
+#if defined (SYS_mkmld)
+ syscall_table[SYS_mkmld] = "mkmld";
+#endif
+#if defined (SYS_mknod)
+ syscall_table[SYS_mknod] = "mknod";
+#endif
+#if defined (SYS_mldmode)
+ syscall_table[SYS_mldmode] = "mldmode";
+#endif
+#if defined (SYS_mmap)
+ syscall_table[SYS_mmap] = "mmap";
+#endif
+#if defined (SYS_mmap64)
+ syscall_table[SYS_mmap64] = "mmap64";
+#endif
+#if defined (SYS_modadm)
+ syscall_table[SYS_modadm] = "modadm";
+#endif
+#if defined (SYS_modctl)
+ syscall_table[SYS_modctl] = "modctl";
+#endif
+#if defined (SYS_modload)
+ syscall_table[SYS_modload] = "modload";
+#endif
+#if defined (SYS_modpath)
+ syscall_table[SYS_modpath] = "modpath";
+#endif
+#if defined (SYS_modstat)
+ syscall_table[SYS_modstat] = "modstat";
+#endif
+#if defined (SYS_moduload)
+ syscall_table[SYS_moduload] = "moduload";
+#endif
+#if defined (SYS_mount)
+ syscall_table[SYS_mount] = "mount";
+#endif
+#if defined (SYS_mprotect)
+ syscall_table[SYS_mprotect] = "mprotect";
+#endif
+#if defined (SYS_mremap)
+ syscall_table[SYS_mremap] = "mremap";
+#endif
+#if defined (SYS_msfs_syscall)
+ syscall_table[SYS_msfs_syscall] = "msfs_syscall";
+#endif
+#if defined (SYS_msgctl)
+ syscall_table[SYS_msgctl] = "msgctl";
+#endif
+#if defined (SYS_msgget)
+ syscall_table[SYS_msgget] = "msgget";
+#endif
+#if defined (SYS_msgrcv)
+ syscall_table[SYS_msgrcv] = "msgrcv";
+#endif
+#if defined (SYS_msgsnd)
+ syscall_table[SYS_msgsnd] = "msgsnd";
+#endif
+#if defined (SYS_msgsys)
+ syscall_table[SYS_msgsys] = "msgsys";
+#endif
+#if defined (SYS_msleep)
+ syscall_table[SYS_msleep] = "msleep";
+#endif
+#if defined (SYS_msync)
+ syscall_table[SYS_msync] = "msync";
+#endif
+#if defined (SYS_munmap)
+ syscall_table[SYS_munmap] = "munmap";
+#endif
+#if defined (SYS_mvalid)
+ syscall_table[SYS_mvalid] = "mvalid";
+#endif
+#if defined (SYS_mwakeup)
+ syscall_table[SYS_mwakeup] = "mwakeup";
+#endif
+#if defined (SYS_naccept)
+ syscall_table[SYS_naccept] = "naccept";
+#endif
+#if defined (SYS_nanosleep)
+ syscall_table[SYS_nanosleep] = "nanosleep";
+#endif
+#if defined (SYS_nfssvc)
+ syscall_table[SYS_nfssvc] = "nfssvc";
+#endif
+#if defined (SYS_nfssys)
+ syscall_table[SYS_nfssys] = "nfssys";
+#endif
+#if defined (SYS_ngetpeername)
+ syscall_table[SYS_ngetpeername] = "ngetpeername";
+#endif
+#if defined (SYS_ngetsockname)
+ syscall_table[SYS_ngetsockname] = "ngetsockname";
+#endif
+#if defined (SYS_nice)
+ syscall_table[SYS_nice] = "nice";
+#endif
+#if defined (SYS_nrecvfrom)
+ syscall_table[SYS_nrecvfrom] = "nrecvfrom";
+#endif
+#if defined (SYS_nrecvmsg)
+ syscall_table[SYS_nrecvmsg] = "nrecvmsg";
+#endif
+#if defined (SYS_nsendmsg)
+ syscall_table[SYS_nsendmsg] = "nsendmsg";
+#endif
+#if defined (SYS_ntp_adjtime)
+ syscall_table[SYS_ntp_adjtime] = "ntp_adjtime";
+#endif
+#if defined (SYS_ntp_gettime)
+ syscall_table[SYS_ntp_gettime] = "ntp_gettime";
+#endif
+#if defined (SYS_nuname)
+ syscall_table[SYS_nuname] = "nuname";
+#endif
+#if defined (SYS_obreak)
+ syscall_table[SYS_obreak] = "obreak";
+#endif
+#if defined (SYS_old_accept)
+ syscall_table[SYS_old_accept] = "old_accept";
+#endif
+#if defined (SYS_old_fstat)
+ syscall_table[SYS_old_fstat] = "old_fstat";
+#endif
+#if defined (SYS_old_getpeername)
+ syscall_table[SYS_old_getpeername] = "old_getpeername";
+#endif
+#if defined (SYS_old_getpgrp)
+ syscall_table[SYS_old_getpgrp] = "old_getpgrp";
+#endif
+#if defined (SYS_old_getsockname)
+ syscall_table[SYS_old_getsockname] = "old_getsockname";
+#endif
+#if defined (SYS_old_killpg)
+ syscall_table[SYS_old_killpg] = "old_killpg";
+#endif
+#if defined (SYS_old_lstat)
+ syscall_table[SYS_old_lstat] = "old_lstat";
+#endif
+#if defined (SYS_old_recv)
+ syscall_table[SYS_old_recv] = "old_recv";
+#endif
+#if defined (SYS_old_recvfrom)
+ syscall_table[SYS_old_recvfrom] = "old_recvfrom";
+#endif
+#if defined (SYS_old_recvmsg)
+ syscall_table[SYS_old_recvmsg] = "old_recvmsg";
+#endif
+#if defined (SYS_old_send)
+ syscall_table[SYS_old_send] = "old_send";
+#endif
+#if defined (SYS_old_sendmsg)
+ syscall_table[SYS_old_sendmsg] = "old_sendmsg";
+#endif
+#if defined (SYS_old_sigblock)
+ syscall_table[SYS_old_sigblock] = "old_sigblock";
+#endif
+#if defined (SYS_old_sigsetmask)
+ syscall_table[SYS_old_sigsetmask] = "old_sigsetmask";
+#endif
+#if defined (SYS_old_sigvec)
+ syscall_table[SYS_old_sigvec] = "old_sigvec";
+#endif
+#if defined (SYS_old_stat)
+ syscall_table[SYS_old_stat] = "old_stat";
+#endif
+#if defined (SYS_old_vhangup)
+ syscall_table[SYS_old_vhangup] = "old_vhangup";
+#endif
+#if defined (SYS_old_wait)
+ syscall_table[SYS_old_wait] = "old_wait";
+#endif
+#if defined (SYS_oldquota)
+ syscall_table[SYS_oldquota] = "oldquota";
+#endif
+#if defined (SYS_online)
+ syscall_table[SYS_online] = "online";
+#endif
+#if defined (SYS_open)
+ syscall_table[SYS_open] = "open";
+#endif
+#if defined (SYS_open64)
+ syscall_table[SYS_open64] = "open64";
+#endif
+#if defined (SYS_ovadvise)
+ syscall_table[SYS_ovadvise] = "ovadvise";
+#endif
+#if defined (SYS_p_online)
+ syscall_table[SYS_p_online] = "p_online";
+#endif
+#if defined (SYS_pagelock)
+ syscall_table[SYS_pagelock] = "pagelock";
+#endif
+#if defined (SYS_pathconf)
+ syscall_table[SYS_pathconf] = "pathconf";
+#endif
+#if defined (SYS_pause)
+ syscall_table[SYS_pause] = "pause";
+#endif
+#if defined (SYS_pgrpsys)
+ syscall_table[SYS_pgrpsys] = "pgrpsys";
+#endif
+#if defined (SYS_pid_block)
+ syscall_table[SYS_pid_block] = "pid_block";
+#endif
+#if defined (SYS_pid_unblock)
+ syscall_table[SYS_pid_unblock] = "pid_unblock";
+#endif
+#if defined (SYS_pipe)
+ syscall_table[SYS_pipe] = "pipe";
+#endif
+#if defined (SYS_plock)
+ syscall_table[SYS_plock] = "plock";
+#endif
+#if defined (SYS_poll)
+ syscall_table[SYS_poll] = "poll";
+#endif
+#if defined (SYS_prctl)
+ syscall_table[SYS_prctl] = "prctl";
+#endif
+#if defined (SYS_pread)
+ syscall_table[SYS_pread] = "pread";
+#endif
+#if defined (SYS_pread64)
+ syscall_table[SYS_pread64] = "pread64";
+#endif
+#if defined (SYS_pread64)
+ syscall_table[SYS_pread64] = "pread64";
+#endif
+#if defined (SYS_prepblock)
+ syscall_table[SYS_prepblock] = "prepblock";
+#endif
+#if defined (SYS_priocntl)
+ syscall_table[SYS_priocntl] = "priocntl";
+#endif
+#if defined (SYS_priocntllst)
+ syscall_table[SYS_priocntllst] = "priocntllst";
+#endif
+#if defined (SYS_priocntlset)
+ syscall_table[SYS_priocntlset] = "priocntlset";
+#endif
+#if defined (SYS_priocntlsys)
+ syscall_table[SYS_priocntlsys] = "priocntlsys";
+#endif
+#if defined (SYS_procblk)
+ syscall_table[SYS_procblk] = "procblk";
+#endif
+#if defined (SYS_processor_bind)
+ syscall_table[SYS_processor_bind] = "processor_bind";
+#endif
+#if defined (SYS_processor_exbind)
+ syscall_table[SYS_processor_exbind] = "processor_exbind";
+#endif
+#if defined (SYS_processor_info)
+ syscall_table[SYS_processor_info] = "processor_info";
+#endif
+#if defined (SYS_procpriv)
+ syscall_table[SYS_procpriv] = "procpriv";
+#endif
+#if defined (SYS_profil)
+ syscall_table[SYS_profil] = "profil";
+#endif
+#if defined (SYS_proplist_syscall)
+ syscall_table[SYS_proplist_syscall] = "proplist_syscall";
+#endif
+#if defined (SYS_pset)
+ syscall_table[SYS_pset] = "pset";
+#endif
+#if defined (SYS_ptrace)
+ syscall_table[SYS_ptrace] = "ptrace";
+#endif
+#if defined (SYS_putmsg)
+ syscall_table[SYS_putmsg] = "putmsg";
+#endif
+#if defined (SYS_putpmsg)
+ syscall_table[SYS_putpmsg] = "putpmsg";
+#endif
+#if defined (SYS_pwrite)
+ syscall_table[SYS_pwrite] = "pwrite";
+#endif
+#if defined (SYS_pwrite64)
+ syscall_table[SYS_pwrite64] = "pwrite64";
+#endif
+#if defined (SYS_quotactl)
+ syscall_table[SYS_quotactl] = "quotactl";
+#endif
+#if defined (SYS_rdblock)
+ syscall_table[SYS_rdblock] = "rdblock";
+#endif
+#if defined (SYS_read)
+ syscall_table[SYS_read] = "read";
+#endif
+#if defined (SYS_readlink)
+ syscall_table[SYS_readlink] = "readlink";
+#endif
+#if defined (SYS_readv)
+ syscall_table[SYS_readv] = "readv";
+#endif
+#if defined (SYS_reboot)
+ syscall_table[SYS_reboot] = "reboot";
+#endif
+#if defined (SYS_recv)
+ syscall_table[SYS_recv] = "recv";
+#endif
+#if defined (SYS_recvfrom)
+ syscall_table[SYS_recvfrom] = "recvfrom";
+#endif
+#if defined (SYS_recvmsg)
+ syscall_table[SYS_recvmsg] = "recvmsg";
+#endif
+#if defined (SYS_rename)
+ syscall_table[SYS_rename] = "rename";
+#endif
+#if defined (SYS_resolvepath)
+ syscall_table[SYS_resolvepath] = "resolvepath";
+#endif
+#if defined (SYS_revoke)
+ syscall_table[SYS_revoke] = "revoke";
+#endif
+#if defined (SYS_rfsys)
+ syscall_table[SYS_rfsys] = "rfsys";
+#endif
+#if defined (SYS_rmdir)
+ syscall_table[SYS_rmdir] = "rmdir";
+#endif
+#if defined (SYS_rpcsys)
+ syscall_table[SYS_rpcsys] = "rpcsys";
+#endif
+#if defined (SYS_sbrk)
+ syscall_table[SYS_sbrk] = "sbrk";
+#endif
+#if defined (SYS_schedctl)
+ syscall_table[SYS_schedctl] = "schedctl";
+#endif
+#if defined (SYS_secadvise)
+ syscall_table[SYS_secadvise] = "secadvise";
+#endif
+#if defined (SYS_secsys)
+ syscall_table[SYS_secsys] = "secsys";
+#endif
+#if defined (SYS_security)
+ syscall_table[SYS_security] = "security";
+#endif
+#if defined (SYS_select)
+ syscall_table[SYS_select] = "select";
+#endif
+#if defined (SYS_semctl)
+ syscall_table[SYS_semctl] = "semctl";
+#endif
+#if defined (SYS_semget)
+ syscall_table[SYS_semget] = "semget";
+#endif
+#if defined (SYS_semop)
+ syscall_table[SYS_semop] = "semop";
+#endif
+#if defined (SYS_semsys)
+ syscall_table[SYS_semsys] = "semsys";
+#endif
+#if defined (SYS_send)
+ syscall_table[SYS_send] = "send";
+#endif
+#if defined (SYS_sendmsg)
+ syscall_table[SYS_sendmsg] = "sendmsg";
+#endif
+#if defined (SYS_sendto)
+ syscall_table[SYS_sendto] = "sendto";
+#endif
+#if defined (SYS_set_program_attributes)
+ syscall_table[SYS_set_program_attributes] = "set_program_attributes";
+#endif
+#if defined (SYS_set_speculative)
+ syscall_table[SYS_set_speculative] = "set_speculative";
+#endif
+#if defined (SYS_set_sysinfo)
+ syscall_table[SYS_set_sysinfo] = "set_sysinfo";
+#endif
+#if defined (SYS_setcontext)
+ syscall_table[SYS_setcontext] = "setcontext";
+#endif
+#if defined (SYS_setdomainname)
+ syscall_table[SYS_setdomainname] = "setdomainname";
+#endif
+#if defined (SYS_setegid)
+ syscall_table[SYS_setegid] = "setegid";
+#endif
+#if defined (SYS_seteuid)
+ syscall_table[SYS_seteuid] = "seteuid";
+#endif
+#if defined (SYS_setgid)
+ syscall_table[SYS_setgid] = "setgid";
+#endif
+#if defined (SYS_setgroups)
+ syscall_table[SYS_setgroups] = "setgroups";
+#endif
+#if defined (SYS_sethostid)
+ syscall_table[SYS_sethostid] = "sethostid";
+#endif
+#if defined (SYS_sethostname)
+ syscall_table[SYS_sethostname] = "sethostname";
+#endif
+#if defined (SYS_setitimer)
+ syscall_table[SYS_setitimer] = "setitimer";
+#endif
+#if defined (SYS_setlogin)
+ syscall_table[SYS_setlogin] = "setlogin";
+#endif
+#if defined (SYS_setpgid)
+ syscall_table[SYS_setpgid] = "setpgid";
+#endif
+#if defined (SYS_setpgrp)
+ syscall_table[SYS_setpgrp] = "setpgrp";
+#endif
+#if defined (SYS_setpriority)
+ syscall_table[SYS_setpriority] = "setpriority";
+#endif
+#if defined (SYS_setregid)
+ syscall_table[SYS_setregid] = "setregid";
+#endif
+#if defined (SYS_setreuid)
+ syscall_table[SYS_setreuid] = "setreuid";
+#endif
+#if defined (SYS_setrlimit)
+ syscall_table[SYS_setrlimit] = "setrlimit";
+#endif
+#if defined (SYS_setrlimit64)
+ syscall_table[SYS_setrlimit64] = "setrlimit64";
+#endif
+#if defined (SYS_setsid)
+ syscall_table[SYS_setsid] = "setsid";
+#endif
+#if defined (SYS_setsockopt)
+ syscall_table[SYS_setsockopt] = "setsockopt";
+#endif
+#if defined (SYS_settimeofday)
+ syscall_table[SYS_settimeofday] = "settimeofday";
+#endif
+#if defined (SYS_setuid)
+ syscall_table[SYS_setuid] = "setuid";
+#endif
+#if defined (SYS_sgi)
+ syscall_table[SYS_sgi] = "sgi";
+#endif
+#if defined (SYS_sgifastpath)
+ syscall_table[SYS_sgifastpath] = "sgifastpath";
+#endif
+#if defined (SYS_sgikopt)
+ syscall_table[SYS_sgikopt] = "sgikopt";
+#endif
+#if defined (SYS_sginap)
+ syscall_table[SYS_sginap] = "sginap";
+#endif
+#if defined (SYS_shmat)
+ syscall_table[SYS_shmat] = "shmat";
+#endif
+#if defined (SYS_shmctl)
+ syscall_table[SYS_shmctl] = "shmctl";
+#endif
+#if defined (SYS_shmdt)
+ syscall_table[SYS_shmdt] = "shmdt";
+#endif
+#if defined (SYS_shmget)
+ syscall_table[SYS_shmget] = "shmget";
+#endif
+#if defined (SYS_shmsys)
+ syscall_table[SYS_shmsys] = "shmsys";
+#endif
+#if defined (SYS_shutdown)
+ syscall_table[SYS_shutdown] = "shutdown";
+#endif
+#if defined (SYS_sigaction)
+ syscall_table[SYS_sigaction] = "sigaction";
+#endif
+#if defined (SYS_sigaltstack)
+ syscall_table[SYS_sigaltstack] = "sigaltstack";
+#endif
+#if defined (SYS_sigaltstack)
+ syscall_table[SYS_sigaltstack] = "sigaltstack";
+#endif
+#if defined (SYS_sigblock)
+ syscall_table[SYS_sigblock] = "sigblock";
+#endif
+#if defined (SYS_signal)
+ syscall_table[SYS_signal] = "signal";
+#endif
+#if defined (SYS_signotify)
+ syscall_table[SYS_signotify] = "signotify";
+#endif
+#if defined (SYS_signotifywait)
+ syscall_table[SYS_signotifywait] = "signotifywait";
+#endif
+#if defined (SYS_sigpending)
+ syscall_table[SYS_sigpending] = "sigpending";
+#endif
+#if defined (SYS_sigpoll)
+ syscall_table[SYS_sigpoll] = "sigpoll";
+#endif
+#if defined (SYS_sigprocmask)
+ syscall_table[SYS_sigprocmask] = "sigprocmask";
+#endif
+#if defined (SYS_sigqueue)
+ syscall_table[SYS_sigqueue] = "sigqueue";
+#endif
+#if defined (SYS_sigreturn)
+ syscall_table[SYS_sigreturn] = "sigreturn";
+#endif
+#if defined (SYS_sigsendset)
+ syscall_table[SYS_sigsendset] = "sigsendset";
+#endif
+#if defined (SYS_sigsendsys)
+ syscall_table[SYS_sigsendsys] = "sigsendsys";
+#endif
+#if defined (SYS_sigsetmask)
+ syscall_table[SYS_sigsetmask] = "sigsetmask";
+#endif
+#if defined (SYS_sigstack)
+ syscall_table[SYS_sigstack] = "sigstack";
+#endif
+#if defined (SYS_sigsuspend)
+ syscall_table[SYS_sigsuspend] = "sigsuspend";
+#endif
+#if defined (SYS_sigvec)
+ syscall_table[SYS_sigvec] = "sigvec";
+#endif
+#if defined (SYS_sigwait)
+ syscall_table[SYS_sigwait] = "sigwait";
+#endif
+#if defined (SYS_sigwaitprim)
+ syscall_table[SYS_sigwaitprim] = "sigwaitprim";
+#endif
+#if defined (SYS_sleep)
+ syscall_table[SYS_sleep] = "sleep";
+#endif
+#if defined (SYS_so_socket)
+ syscall_table[SYS_so_socket] = "so_socket";
+#endif
+#if defined (SYS_so_socketpair)
+ syscall_table[SYS_so_socketpair] = "so_socketpair";
+#endif
+#if defined (SYS_sockconfig)
+ syscall_table[SYS_sockconfig] = "sockconfig";
+#endif
+#if defined (SYS_socket)
+ syscall_table[SYS_socket] = "socket";
+#endif
+#if defined (SYS_socketpair)
+ syscall_table[SYS_socketpair] = "socketpair";
+#endif
+#if defined (SYS_sproc)
+ syscall_table[SYS_sproc] = "sproc";
+#endif
+#if defined (SYS_sprocsp)
+ syscall_table[SYS_sprocsp] = "sprocsp";
+#endif
+#if defined (SYS_sstk)
+ syscall_table[SYS_sstk] = "sstk";
+#endif
+#if defined (SYS_stat)
+ syscall_table[SYS_stat] = "stat";
+#endif
+#if defined (SYS_stat64)
+ syscall_table[SYS_stat64] = "stat64";
+#endif
+#if defined (SYS_statfs)
+ syscall_table[SYS_statfs] = "statfs";
+#endif
+#if defined (SYS_statvfs)
+ syscall_table[SYS_statvfs] = "statvfs";
+#endif
+#if defined (SYS_statvfs64)
+ syscall_table[SYS_statvfs64] = "statvfs64";
+#endif
+#if defined (SYS_stime)
+ syscall_table[SYS_stime] = "stime";
+#endif
+#if defined (SYS_stty)
+ syscall_table[SYS_stty] = "stty";
+#endif
+#if defined (SYS_subsys_info)
+ syscall_table[SYS_subsys_info] = "subsys_info";
+#endif
+#if defined (SYS_swapctl)
+ syscall_table[SYS_swapctl] = "swapctl";
+#endif
+#if defined (SYS_swapon)
+ syscall_table[SYS_swapon] = "swapon";
+#endif
+#if defined (SYS_symlink)
+ syscall_table[SYS_symlink] = "symlink";
+#endif
+#if defined (SYS_sync)
+ syscall_table[SYS_sync] = "sync";
+#endif
+#if defined (SYS_sys3b)
+ syscall_table[SYS_sys3b] = "sys3b";
+#endif
+#if defined (SYS_syscall)
+ syscall_table[SYS_syscall] = "syscall";
+#endif
+#if defined (SYS_sysconfig)
+ syscall_table[SYS_sysconfig] = "sysconfig";
+#endif
+#if defined (SYS_sysfs)
+ syscall_table[SYS_sysfs] = "sysfs";
+#endif
+#if defined (SYS_sysi86)
+ syscall_table[SYS_sysi86] = "sysi86";
+#endif
+#if defined (SYS_sysinfo)
+ syscall_table[SYS_sysinfo] = "sysinfo";
+#endif
+#if defined (SYS_sysmips)
+ syscall_table[SYS_sysmips] = "sysmips";
+#endif
+#if defined (SYS_syssun)
+ syscall_table[SYS_syssun] = "syssun";
+#endif
+#if defined (SYS_systeminfo)
+ syscall_table[SYS_systeminfo] = "systeminfo";
+#endif
+#if defined (SYS_table)
+ syscall_table[SYS_table] = "table";
+#endif
+#if defined (SYS_time)
+ syscall_table[SYS_time] = "time";
+#endif
+#if defined (SYS_timedwait)
+ syscall_table[SYS_timedwait] = "timedwait";
+#endif
+#if defined (SYS_timer_create)
+ syscall_table[SYS_timer_create] = "timer_create";
+#endif
+#if defined (SYS_timer_delete)
+ syscall_table[SYS_timer_delete] = "timer_delete";
+#endif
+#if defined (SYS_timer_getoverrun)
+ syscall_table[SYS_timer_getoverrun] = "timer_getoverrun";
+#endif
+#if defined (SYS_timer_gettime)
+ syscall_table[SYS_timer_gettime] = "timer_gettime";
+#endif
+#if defined (SYS_timer_settime)
+ syscall_table[SYS_timer_settime] = "timer_settime";
+#endif
+#if defined (SYS_times)
+ syscall_table[SYS_times] = "times";
+#endif
+#if defined (SYS_truncate)
+ syscall_table[SYS_truncate] = "truncate";
+#endif
+#if defined (SYS_truncate64)
+ syscall_table[SYS_truncate64] = "truncate64";
+#endif
+#if defined (SYS_tsolsys)
+ syscall_table[SYS_tsolsys] = "tsolsys";
+#endif
+#if defined (SYS_uadmin)
+ syscall_table[SYS_uadmin] = "uadmin";
+#endif
+#if defined (SYS_ulimit)
+ syscall_table[SYS_ulimit] = "ulimit";
+#endif
+#if defined (SYS_umask)
+ syscall_table[SYS_umask] = "umask";
+#endif
+#if defined (SYS_umount)
+ syscall_table[SYS_umount] = "umount";
+#endif
+#if defined (SYS_uname)
+ syscall_table[SYS_uname] = "uname";
+#endif
+#if defined (SYS_unblock)
+ syscall_table[SYS_unblock] = "unblock";
+#endif
+#if defined (SYS_unlink)
+ syscall_table[SYS_unlink] = "unlink";
+#endif
+#if defined (SYS_unmount)
+ syscall_table[SYS_unmount] = "unmount";
+#endif
+#if defined (SYS_usleep_thread)
+ syscall_table[SYS_usleep_thread] = "usleep_thread";
+#endif
+#if defined (SYS_uswitch)
+ syscall_table[SYS_uswitch] = "uswitch";
+#endif
+#if defined (SYS_utc_adjtime)
+ syscall_table[SYS_utc_adjtime] = "utc_adjtime";
+#endif
+#if defined (SYS_utc_gettime)
+ syscall_table[SYS_utc_gettime] = "utc_gettime";
+#endif
+#if defined (SYS_utime)
+ syscall_table[SYS_utime] = "utime";
+#endif
+#if defined (SYS_utimes)
+ syscall_table[SYS_utimes] = "utimes";
+#endif
+#if defined (SYS_utssys)
+ syscall_table[SYS_utssys] = "utssys";
+#endif
+#if defined (SYS_vfork)
+ syscall_table[SYS_vfork] = "vfork";
+#endif
+#if defined (SYS_vhangup)
+ syscall_table[SYS_vhangup] = "vhangup";
+#endif
+#if defined (SYS_vtrace)
+ syscall_table[SYS_vtrace] = "vtrace";
+#endif
+#if defined (SYS_wait)
+ syscall_table[SYS_wait] = "wait";
+#endif
+#if defined (SYS_waitid)
+ syscall_table[SYS_waitid] = "waitid";
+#endif
+#if defined (SYS_waitsys)
+ syscall_table[SYS_waitsys] = "waitsys";
+#endif
+#if defined (SYS_write)
+ syscall_table[SYS_write] = "write";
+#endif
+#if defined (SYS_writev)
+ syscall_table[SYS_writev] = "writev";
+#endif
+#if defined (SYS_xenix)
+ syscall_table[SYS_xenix] = "xenix";
+#endif
+#if defined (SYS_xmknod)
+ syscall_table[SYS_xmknod] = "xmknod";
+#endif
+#if defined (SYS_xstat)
+ syscall_table[SYS_xstat] = "xstat";
+#endif
+#if defined (SYS_yield)
+ syscall_table[SYS_yield] = "yield";
+#endif
+}
+
+/*
+ * Prettyprint a single syscall by number.
+ */
+
+void
+proc_prettyfprint_syscall (FILE *file, int num, int verbose)
+{
+ if (syscall_table[num])
+ fprintf (file, "SYS_%s ", syscall_table[num]);
+ else
+ fprintf (file, "<Unknown syscall %d> ", num);
+}
+
+void
+proc_prettyprint_syscall (int num, int verbose)
+{
+ proc_prettyfprint_syscall (stdout, num, verbose);
+}
+
+/*
+ * Prettyprint all of the syscalls in a sysset_t set.
+ */
+
+void
+proc_prettyfprint_syscalls (FILE *file, sysset_t *sysset, int verbose)
+{
+ int i;
+
+ for (i = 0; i < MAX_SYSCALLS; i++)
+ if (prismember (sysset, i))
+ {
+ proc_prettyfprint_syscall (file, i, verbose);
+ }
+ fprintf (file, "\n");
+}
+
+void
+proc_prettyprint_syscalls (sysset_t *sysset, int verbose)
+{
+ proc_prettyfprint_syscalls (stdout, sysset, verbose);
+}
+
+/* FIXME: add real-time signals */
+
+static struct trans signal_table[] =
+{
+ { 0, "<no signal>", "no signal" },
+#ifdef SIGHUP
+ { SIGHUP, "SIGHUP", "Hangup" },
+#endif
+#ifdef SIGINT
+ { SIGINT, "SIGINT", "Interrupt (rubout)" },
+#endif
+#ifdef SIGQUIT
+ { SIGQUIT, "SIGQUIT", "Quit (ASCII FS)" },
+#endif
+#ifdef SIGILL
+ { SIGILL, "SIGILL", "Illegal instruction" }, /* not reset when caught */
+#endif
+#ifdef SIGTRAP
+ { SIGTRAP, "SIGTRAP", "Trace trap" }, /* not reset when caught */
+#endif
+#ifdef SIGABRT
+ { SIGABRT, "SIGABRT", "used by abort()" }, /* replaces SIGIOT */
+#endif
+#ifdef SIGIOT
+ { SIGIOT, "SIGIOT", "IOT instruction" },
+#endif
+#ifdef SIGEMT
+ { SIGEMT, "SIGEMT", "EMT instruction" },
+#endif
+#ifdef SIGFPE
+ { SIGFPE, "SIGFPE", "Floating point exception" },
+#endif
+#ifdef SIGKILL
+ { SIGKILL, "SIGKILL", "Kill" }, /* Solaris: cannot be caught/ignored */
+#endif
+#ifdef SIGBUS
+ { SIGBUS, "SIGBUS", "Bus error" },
+#endif
+#ifdef SIGSEGV
+ { SIGSEGV, "SIGSEGV", "Segmentation violation" },
+#endif
+#ifdef SIGSYS
+ { SIGSYS, "SIGSYS", "Bad argument to system call" },
+#endif
+#ifdef SIGPIPE
+ { SIGPIPE, "SIGPIPE", "Write to pipe with no one to read it" },
+#endif
+#ifdef SIGALRM
+ { SIGALRM, "SIGALRM", "Alarm clock" },
+#endif
+#ifdef SIGTERM
+ { SIGTERM, "SIGTERM", "Software termination signal from kill" },
+#endif
+#ifdef SIGUSR1
+ { SIGUSR1, "SIGUSR1", "User defined signal 1" },
+#endif
+#ifdef SIGUSR2
+ { SIGUSR2, "SIGUSR2", "User defined signal 2" },
+#endif
+#ifdef SIGCHLD
+ { SIGCHLD, "SIGCHLD", "Child status changed" }, /* Posix version */
+#endif
+#ifdef SIGCLD
+ { SIGCLD, "SIGCLD", "Child status changed" }, /* Solaris version */
+#endif
+#ifdef SIGPWR
+ { SIGPWR, "SIGPWR", "Power-fail restart" },
+#endif
+#ifdef SIGWINCH
+ { SIGWINCH, "SIGWINCH", "Window size change" },
+#endif
+#ifdef SIGURG
+ { SIGURG, "SIGURG", "Urgent socket condition" },
+#endif
+#ifdef SIGPOLL
+ { SIGPOLL, "SIGPOLL", "Pollable event" },
+#endif
+#ifdef SIGIO
+ { SIGIO, "SIGIO", "Socket I/O possible" }, /* alias for SIGPOLL */
+#endif
+#ifdef SIGSTOP
+ { SIGSTOP, "SIGSTOP", "Stop, not from tty" }, /* cannot be caught or ignored */
+#endif
+#ifdef SIGTSTP
+ { SIGTSTP, "SIGTSTP", "User stop from tty" },
+#endif
+#ifdef SIGCONT
+ { SIGCONT, "SIGCONT", "Stopped process has been continued" },
+#endif
+#ifdef SIGTTIN
+ { SIGTTIN, "SIGTTIN", "Background tty read attempted" },
+#endif
+#ifdef SIGTTOU
+ { SIGTTOU, "SIGTTOU", "Background tty write attempted" },
+#endif
+#ifdef SIGVTALRM
+ { SIGVTALRM, "SIGVTALRM", "Virtual timer expired" },
+#endif
+#ifdef SIGPROF
+ { SIGPROF, "SIGPROF", "Profiling timer expired" },
+#endif
+#ifdef SIGXCPU
+ { SIGXCPU, "SIGXCPU", "Exceeded CPU limit" },
+#endif
+#ifdef SIGXFSZ
+ { SIGXFSZ, "SIGXFSZ", "Exceeded file size limit" },
+#endif
+#ifdef SIGWAITING
+ { SIGWAITING, "SIGWAITING", "Process's LWPs are blocked" },
+#endif
+#ifdef SIGLWP
+ { SIGLWP, "SIGLWP", "Used by thread library" },
+#endif
+#ifdef SIGFREEZE
+ { SIGFREEZE, "SIGFREEZE", "Used by CPR" },
+#endif
+#ifdef SIGTHAW
+ { SIGTHAW, "SIGTHAW", "Used by CPR" },
+#endif
+#ifdef SIGCANCEL
+ { SIGCANCEL, "SIGCANCEL", "Used by libthread" },
+#endif
+#ifdef SIGLOST
+ { SIGLOST, "SIGLOST", "Resource lost" },
+#endif
+#ifdef SIG32
+ { SIG32, "SIG32", "Reserved for kernel usage (Irix)" },
+#endif
+#ifdef SIGPTINTR
+ { SIGPTINTR, "SIGPTINTR", "Posix 1003.1b" },
+#endif
+#ifdef SIGTRESCHED
+ { SIGTRESCHED, "SIGTRESCHED", "Posix 1003.1b" },
+#endif
+#ifdef SIGINFO
+ { SIGINFO, "SIGINFO", "Information request" },
+#endif
+#ifdef SIGRESV
+ { SIGRESV, "SIGRESV", "Reserved by Digital for future use" },
+#endif
+#ifdef SIGAIO
+ { SIGAIO, "SIGAIO", "Asynchronous I/O signal" },
+#endif
+};
+
+/*
+ * Prettyprint a single signal by number.
+ * Accepts a signal number and finds it in the signal table,
+ * then pretty-prints it.
+ */
+
+void
+proc_prettyfprint_signal (FILE *file, int signo, int verbose)
+{
+ int i;
+
+ for (i = 0; i < sizeof (signal_table) / sizeof (signal_table[0]); i++)
+ if (signo == signal_table[i].value)
+ {
+ fprintf (file, "%s", signal_table[i].name);
+ if (verbose)
+ fprintf (file, ": %s\n", signal_table[i].desc);
+ else
+ fprintf (file, " ");
+ return;
+ }
+ fprintf (file, "Unknown signal %d%c", signo, verbose ? '\n' : ' ');
+}
+
+void
+proc_prettyprint_signal (int signo, int verbose)
+{
+ proc_prettyfprint_signal (stdout, signo, verbose);
+}
+
+/*
+ * Prettyprint all of the signals in a sigset_t set.
+ *
+ * This function loops over all signal numbers from 0 to NSIG,
+ * uses them as indexes for prismember, and prints them pretty.
+ *
+ * It does not loop over the signal table, as is done with the
+ * fault table, because the signal table may contain aliases.
+ * If it did, both aliases would be printed.
+ */
+
+void
+proc_prettyfprint_signalset (FILE *file, sigset_t *sigset, int verbose)
+{
+ int i;
+
+ for (i = 0; i < NSIG; i++)
+ if (prismember (sigset, i))
+ proc_prettyfprint_signal (file, i, verbose);
+
+ if (!verbose)
+ fprintf (file, "\n");
+}
+
+void
+proc_prettyprint_signalset (sigset_t *sigset, int verbose)
+{
+ proc_prettyfprint_signalset (stdout, sigset, verbose);
+}
+
+/* Hardware fault translation table. */
+
+static struct trans fault_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
+#if defined (FLTPCINVAL)
+ { FLTPCINVAL, "FLTPCINVAL", "Invalid PC exception" },
+#endif
+#if defined (FLTWATCH)
+ { FLTWATCH, "FLTWATCH", "User watchpoint" },
+#endif
+#if defined (FLTKWATCH)
+ { FLTKWATCH, "FLTKWATCH", "Kernel watchpoint" },
+#endif
+#if defined (FLTSCWATCH)
+ { FLTSCWATCH, "FLTSCWATCH", "Hit a store conditional on a watched page" },
+#endif
+};
+
+/*
+ * Work horse. Accepts an index into the fault table, prints it pretty.
+ */
+
+static void
+prettyfprint_faulttable_entry (FILE *file, int i, int verbose)
+{
+ fprintf (file, "%s", fault_table[i].name);
+ if (verbose)
+ fprintf (file, ": %s\n", fault_table[i].desc);
+ else
+ fprintf (file, " ");
+}
+
+/*
+ * Prettyprint a hardware fault by number.
+ */
+
+void
+proc_prettyfprint_fault (FILE *file, int faultno, int verbose)
+{
+ int i;
+
+ for (i = 0; i < sizeof (fault_table) / sizeof (fault_table[0]); i++)
+ if (faultno == fault_table[i].value)
+ {
+ prettyfprint_faulttable_entry (file, i, verbose);
+ return;
+ }
+
+ fprintf (file, "Unknown hardware fault %d%c",
+ faultno, verbose ? '\n' : ' ');
+}
+
+void
+proc_prettyprint_fault (int faultno, int verbose)
+{
+ proc_prettyfprint_fault (stdout, faultno, verbose);
+}
+
+/*
+ * Prettyprint all the faults in a fltset_t set.
+ *
+ * This function loops thru the fault table,
+ * using the value field as the index to prismember.
+ * The fault table had better not contain aliases,
+ * for if it does they will both be printed.
+ */
+
+void
+proc_prettyfprint_faultset (FILE *file, fltset_t *fltset, int verbose)
+{
+ int i;
+
+ for (i = 0; i < sizeof (fault_table) / sizeof (fault_table[0]); i++)
+ if (prismember (fltset, fault_table[i].value))
+ prettyfprint_faulttable_entry (file, i, verbose);
+
+ if (!verbose)
+ fprintf (file, "\n");
+}
+
+void
+proc_prettyprint_faultset (fltset_t *fltset, int verbose)
+{
+ proc_prettyfprint_faultset (stdout, fltset, verbose);
+}
+
+/*
+ * Todo: actions, holds...
+ */
+
+void
+proc_prettyprint_actionset (struct sigaction *actions, int verbose)
+{
+}
+
+void
+_initialize_proc_events (void)
+{
+ init_syscall_table ();
+}
diff --git a/contrib/gdb/gdb/proc-flags.c b/contrib/gdb/gdb/proc-flags.c
new file mode 100755
index 0000000..6e737d1
--- /dev/null
+++ b/contrib/gdb/gdb/proc-flags.c
@@ -0,0 +1,291 @@
+/* Machine independent support for SVR4 /proc (process file system) for GDB.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+ Written by Michael Snyder at Cygnus Solutions.
+ Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ * Pretty-print the prstatus flags.
+ *
+ * Arguments: unsigned long flags, int verbose
+ *
+ */
+
+#include "defs.h"
+
+#if defined (NEW_PROC_API)
+#define _STRUCTURED_PROC 1
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+
+/* 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)
+ /* Sol2.5: lwp is stopped
+ * Sol2.6: lwp is stopped
+ * Sol2.7: lwp is stopped
+ * IRIX6: process is stopped
+ * OSF: task/thread is stopped
+ * UW: LWP is stopped
+ */
+ { PR_STOPPED, "PR_STOPPED", "Process (LWP) is stopped" },
+#endif
+#if defined (PR_ISTOP)
+ /* Sol2.5: lwp is stopped on an event of interest
+ * Sol2.6: lwp is stopped on an event of interest
+ * Sol2.7: lwp is stopped on an event of interest
+ * IRIX6: process is stopped on event of interest
+ * OSF: task/thread stopped on event of interest
+ * UW: LWP stopped on an event of interest
+ */
+ { PR_ISTOP, "PR_ISTOP", "Stopped on an event of interest" },
+#endif
+#if defined (PR_DSTOP)
+ /* Sol2.5: lwp has a stop directive in effect
+ * Sol2.6: lwp has a stop directive in effect
+ * Sol2.7: lwp has a stop directive in effect
+ * IRIX6: process has stop directive in effect
+ * OSF: task/thread has stop directive in effect
+ * UW: A stop directive is in effect
+ */
+ { PR_DSTOP, "PR_DSTOP", "A stop directive is in effect" },
+#endif
+#if defined (PR_STEP)
+ /* Sol2.5: lwp has a single-step directive in effect
+ * Sol2.6: lwp has a single-step directive in effect
+ * Sol2.7: lwp has a single-step directive in effect
+ * IRIX6: process has single step pending
+ */
+ { PR_STEP, "PR_STEP", "A single step directive is in effect" },
+#endif
+#if defined (PR_ASLEEP)
+ /* Sol2.5: lwp is sleeping in a system call
+ * Sol2.6: lwp is sleeping in a system call
+ * Sol2.7: lwp is sleeping in a system call
+ * IRIX6: process is in an interruptible sleep
+ * OSF: task/thread is asleep within a system call
+ * UW: LWP is sleep()ing in a system call
+ */
+ { PR_ASLEEP, "PR_ASLEEP", "Sleeping in an (interruptible) system call" },
+#endif
+#if defined (PR_PCINVAL)
+ /* Sol2.5: contents of pr_instr undefined
+ * Sol2.6: contents of pr_instr undefined
+ * Sol2.7: contents of pr_instr undefined
+ * IRIX6: current pc is invalid
+ * OSF: program counter contains invalid address
+ * UW: %pc refers to an invalid virtual address
+ */
+ { PR_PCINVAL, "PR_PCINVAL", "PC (pr_instr) is invalid" },
+#endif
+#if defined (PR_ASLWP)
+ /* Sol2.5: this lwp is the aslwp
+ * Sol2.6: this lwp is the aslwp
+ * Sol2.7: this lwp is the aslwp
+ */
+ { PR_ASLWP, "PR_ASLWP", "This is the asynchronous signal LWP" },
+#endif
+#if defined (PR_AGENT)
+ /* Sol2.6: this lwp is the /proc agent lwp
+ * Sol2.7: this lwp is the /proc agent lwp
+ */
+ { PR_AGENT, "PR_AGENT", "This is the /proc agent LWP" },
+#endif
+#if defined (PR_ISSYS)
+ /* Sol2.5: system process
+ * Sol2.6: this is a system process
+ * Sol2.7: this is a system process
+ * IRIX6: process is a system process
+ * OSF: task/thread is a system task/thread
+ * UW: System process
+ */
+ { PR_ISSYS, "PR_ISSYS", "Is a system process/thread" },
+#endif
+#if defined (PR_VFORKP)
+ /* Sol2.6: process is the parent of a vfork()d child
+ * Sol2.7: process is the parent of a vfork()d child
+ */
+ { PR_VFORKP, "PR_VFORKP", "Process is the parent of a vforked child" },
+#endif
+#ifdef PR_ORPHAN
+ /* Sol2.6: process's process group is orphaned
+ * Sol2.7: process's process group is orphaned
+ */
+ { PR_ORPHAN, "PR_ORPHAN", "Process's process group is orphaned" },
+#endif
+#if defined (PR_FORK)
+ /* Sol2.5: inherit-on-fork is in effect
+ * Sol2.6: inherit-on-fork is in effect
+ * Sol2.7: inherit-on-fork is in effect
+ * IRIX6: process has inherit-on-fork flag set
+ * OSF: task/thread has inherit-on-fork flag set
+ * UW: inherit-on-fork is in effect
+ */
+ { PR_FORK, "PR_FORK", "Inherit-on-fork is in effect" },
+#endif
+#if defined (PR_RLC)
+ /* Sol2.5: run-on-last-close is in effect
+ * Sol2.6: run-on-last-close is in effect
+ * Sol2.7: run-on-last-close is in effect
+ * IRIX6: process has run-on-last-close flag set
+ * OSF: task/thread has run-on-last-close flag set
+ * UW: Run-on-last-close is in effect
+ */
+ { PR_RLC, "PR_RLC", "Run-on-last-close is in effect" },
+#endif
+#if defined (PR_KLC)
+ /* Sol2.5: kill-on-last-close is in effect
+ * Sol2.6: kill-on-last-close is in effect
+ * Sol2.7: kill-on-last-close is in effect
+ * IRIX6: process has kill-on-last-close flag set
+ * OSF: kill-on-last-close, superceeds RLC
+ * UW: kill-on-last-close is in effect
+ */
+ { PR_KLC, "PR_KLC", "Kill-on-last-close is in effect" },
+#endif
+#if defined (PR_ASYNC)
+ /* Sol2.5: asynchronous-stop is in effect
+ * Sol2.6: asynchronous-stop is in effect
+ * Sol2.7: asynchronous-stop is in effect
+ * OSF: asynchronous stop mode is in effect
+ * UW: asynchronous stop mode is in effect
+ */
+ { PR_ASYNC, "PR_ASYNC", "Asynchronous stop is in effect" },
+#endif
+#if defined (PR_MSACCT)
+ /* Sol2.5: micro-state usage accounting is in effect
+ * Sol2.6: micro-state usage accounting is in effect
+ * Sol2.7: micro-state usage accounting is in effect
+ */
+ { PR_MSACCT, "PR_MSACCT", "Microstate accounting enabled" },
+#endif
+#if defined (PR_BPTADJ)
+ /* Sol2.5: breakpoint trap pc adjustment is in effect
+ * Sol2.6: breakpoint trap pc adjustment is in effect
+ * Sol2.7: breakpoint trap pc adjustment is in effect
+ */
+ { PR_BPTADJ, "PR_BPTADJ", "Breakpoint PC adjustment in effect" },
+#endif
+#if defined (PR_PTRACE)
+ /* Note: different meanings on Solaris and Irix 6
+ * Sol2.5: obsolete, never set in SunOS5.0
+ * Sol2.6: ptrace-compatibility mode is in effect
+ * Sol2.7: ptrace-compatibility mode is in effect
+ * IRIX6: process is traced with ptrace() too
+ * OSF: task/thread is being traced by ptrace
+ * UW: Process is being controlled by ptrace(2)
+ */
+ { PR_PTRACE, "PR_PTRACE", "Process is being controlled by ptrace" },
+#endif
+#if defined (PR_PCOMPAT)
+ /* Note: PCOMPAT on Sol2.5 means same thing as PTRACE on Sol2.6
+ * Sol2.5 (only): ptrace-compatibility mode is in effect
+ */
+ { PR_PCOMPAT, "PR_PCOMPAT", "Ptrace compatibility mode in effect" },
+#endif
+#ifdef PR_MSFORK
+ /* Sol2.6: micro-state accounting inherited on fork
+ * Sol2.7: micro-state accounting inherited on fork
+ */
+ { PR_MSFORK, "PR_PCOMPAT", "Micro-state accounting inherited on fork" },
+#endif
+
+#ifdef PR_ISKTHREAD
+ /* Irix6: process is a kernel thread */
+ { PR_ISKTHREAD, "PR_KTHREAD", "Process is a kernel thread" },
+#endif
+
+#ifdef PR_ABORT
+ /* OSF (only): abort the current stop condition */
+ { PR_ABORT, "PR_ABORT", "Abort the current stop condition" },
+#endif
+
+#ifdef PR_TRACING
+ /* OSF: task is traced */
+ { PR_TRACING, "PR_TRACING", "Task is traced" },
+#endif
+
+#ifdef PR_STOPFORK
+ /* OSF: stop child on fork */
+ { PR_STOPFORK, "PR_STOPFORK", "Stop child on fork" },
+#endif
+
+#ifdef PR_STOPEXEC
+ /* OSF: stop on exec */
+ { PR_STOPEXEC, "PR_STOPEXEC", "Stop on exec" },
+#endif
+
+#ifdef PR_STOPTERM
+ /* OSF: stop on task exit */
+ { PR_STOPTERM, "PR_STOPTERM", "Stop on task exit" },
+#endif
+
+#ifdef PR_STOPTCR
+ /* OSF: stop on thread creation */
+ { PR_STOPTCR, "PR_STOPTCR", "Stop on thread creation" },
+#endif
+
+#ifdef PR_STOPTTERM
+ /* OSF: stop on thread exit */
+ { PR_STOPTTERM, "PR_STOPTTERM", "Stop on thread exit" },
+#endif
+
+#ifdef PR_USCHED
+ /* OSF: user level scheduling is in effect */
+ { PR_USCHED, "PR_USCHED", "User level scheduling is in effect" },
+#endif
+};
+
+void
+proc_prettyfprint_flags (FILE *file, unsigned long flags, int verbose)
+{
+ int i;
+
+ for (i = 0; i < sizeof (pr_flag_table) / sizeof (pr_flag_table[0]); i++)
+ if (flags & pr_flag_table[i].value)
+ {
+ fprintf (file, "%s ", pr_flag_table[i].name);
+ if (verbose)
+ fprintf (file, "%s\n", pr_flag_table[i].desc);
+ }
+ if (!verbose)
+ fprintf (file, "\n");
+}
+
+void
+proc_prettyprint_flags (unsigned long flags, int verbose)
+{
+ proc_prettyfprint_flags (stdout, flags, verbose);
+}
diff --git a/contrib/gdb/gdb/proc-service.c b/contrib/gdb/gdb/proc-service.c
new file mode 100644
index 0000000..d7cd1aa
--- /dev/null
+++ b/contrib/gdb/gdb/proc-service.c
@@ -0,0 +1,312 @@
+/* <proc_service.h> implementation.
+
+ Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_proc_service.h"
+#include <sys/procfs.h>
+
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+
+/* Fix-up some broken systems. */
+
+/* The prototypes in <proc_service.h> are slightly different on older
+ systems. Compensate for the discrepancies. */
+
+#ifdef PROC_SERVICE_IS_OLD
+typedef const struct ps_prochandle *gdb_ps_prochandle_t;
+typedef char *gdb_ps_read_buf_t;
+typedef char *gdb_ps_write_buf_t;
+typedef int gdb_ps_size_t;
+#else
+typedef struct ps_prochandle *gdb_ps_prochandle_t;
+typedef void *gdb_ps_read_buf_t;
+typedef const void *gdb_ps_write_buf_t;
+typedef size_t gdb_ps_size_t;
+#endif
+
+
+/* Building process ids. */
+
+#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
+
+
+/* Helper functions. */
+
+/* Transfer LEN bytes of memory between BUF and address ADDR in the
+ process specified by PH. If WRITE, transfer them to the process,
+ else transfer them from the process. Returns PS_OK for success,
+ PS_ERR on failure.
+
+ This is a helper function for ps_pdread, ps_pdwrite, ps_ptread and
+ ps_ptwrite. */
+
+static ps_err_e
+ps_xfer_memory (const struct ps_prochandle *ph, paddr_t addr,
+ char *buf, size_t len, int write)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+ int ret;
+
+ inferior_ptid = pid_to_ptid (ph->pid);
+
+ if (write)
+ ret = target_write_memory (addr, buf, len);
+ else
+ ret = target_read_memory (addr, buf, len);
+
+ do_cleanups (old_chain);
+
+ return (ret == 0 ? PS_OK : PS_ERR);
+}
+
+
+/* Stop the target process PH. */
+
+ps_err_e
+ps_pstop (gdb_ps_prochandle_t ph)
+{
+ /* The process is always stopped when under control of GDB. */
+ return PS_OK;
+}
+
+/* Resume the target process PH. */
+
+ps_err_e
+ps_pcontinue (gdb_ps_prochandle_t ph)
+{
+ /* Pretend we did successfully continue the process. GDB will take
+ care of it later on. */
+ return PS_OK;
+}
+
+/* Stop the lightweight process LWPID within the target process PH. */
+
+ps_err_e
+ps_lstop (gdb_ps_prochandle_t ph, lwpid_t lwpid)
+{
+ /* All lightweight processes are stopped when under control of GDB. */
+ return PS_OK;
+}
+
+/* Resume the lightweight process (LWP) LWPID within the target
+ process PH. */
+
+ps_err_e
+ps_lcontinue (gdb_ps_prochandle_t ph, lwpid_t lwpid)
+{
+ /* Pretend we did successfully continue LWPID. GDB will take care
+ of it later on. */
+ return PS_OK;
+}
+
+/* Get the size of the architecture-dependent extra state registers
+ for LWP LWPID within the target process PH and return it in
+ *XREGSIZE. */
+
+ps_err_e
+ps_lgetxregsize (gdb_ps_prochandle_t ph, lwpid_t lwpid, int *xregsize)
+{
+ /* FIXME: Not supported yet. */
+ return PS_OK;
+}
+
+/* Get the extra state registers of LWP LWPID within the target
+ process PH and store them in XREGSET. */
+
+ps_err_e
+ps_lgetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
+{
+ /* FIXME: Not supported yet. */
+ return PS_OK;
+}
+
+/* Set the extra state registers of LWP LWPID within the target
+ process PH from XREGSET. */
+
+ps_err_e
+ps_lsetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
+{
+ /* FIXME: Not supported yet. */
+ return PS_OK;
+}
+
+/* Log (additional) diognostic information. */
+
+void
+ps_plog (const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vfprintf_filtered (gdb_stderr, fmt, args);
+}
+
+/* Search for the symbol named NAME within the object named OBJ within
+ the target process PH. If the symbol is found the address of the
+ symbol is stored in SYM_ADDR. */
+
+ps_err_e
+ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
+ const char *name, paddr_t *sym_addr)
+{
+ struct minimal_symbol *ms;
+
+ /* FIXME: kettenis/2000-09-03: What should we do with OBJ? */
+ ms = lookup_minimal_symbol (name, NULL, NULL);
+ if (ms == NULL)
+ return PS_NOSYM;
+
+ *sym_addr = SYMBOL_VALUE_ADDRESS (ms);
+ return PS_OK;
+}
+
+/* Read SIZE bytes from the target process PH at address ADDR and copy
+ them into BUF. */
+
+ps_err_e
+ps_pdread (gdb_ps_prochandle_t ph, paddr_t addr,
+ gdb_ps_read_buf_t buf, gdb_ps_size_t size)
+{
+ return ps_xfer_memory (ph, addr, buf, size, 0);
+}
+
+/* Write SIZE bytes from BUF into the target process PH at address ADDR. */
+
+ps_err_e
+ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr,
+ gdb_ps_write_buf_t buf, gdb_ps_size_t size)
+{
+ return ps_xfer_memory (ph, addr, (char *) buf, size, 1);
+}
+
+/* Read SIZE bytes from the target process PH at address ADDR and copy
+ them into BUF. */
+
+ps_err_e
+ps_ptread (gdb_ps_prochandle_t ph, paddr_t addr,
+ gdb_ps_read_buf_t buf, gdb_ps_size_t size)
+{
+ return ps_xfer_memory (ph, addr, buf, size, 0);
+}
+
+/* Write SIZE bytes from BUF into the target process PH at address ADDR. */
+
+ps_err_e
+ps_ptwrite (gdb_ps_prochandle_t ph, paddr_t addr,
+ gdb_ps_write_buf_t buf, gdb_ps_size_t size)
+{
+ return ps_xfer_memory (ph, addr, (char *) buf, size, 1);
+}
+
+/* Get the general registers of LWP LWPID within the target process PH
+ and store them in GREGSET. */
+
+ps_err_e
+ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, ph->pid);
+
+ target_fetch_registers (-1);
+ fill_gregset ((gdb_gregset_t *) gregset, -1);
+
+ do_cleanups (old_chain);
+ return PS_OK;
+}
+
+/* Set the general registers of LWP LWPID within the target process PH
+ from GREGSET. */
+
+ps_err_e
+ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, ph->pid);
+
+ /* FIXME: We should really make supply_gregset const-correct. */
+ supply_gregset ((gdb_gregset_t *) gregset);
+ target_store_registers (-1);
+
+ do_cleanups (old_chain);
+ return PS_OK;
+}
+
+/* Get the floating-point registers of LWP LWPID within the target
+ process PH and store them in FPREGSET. */
+
+ps_err_e
+ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ gdb_prfpregset_t *fpregset)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, ph->pid);
+
+ target_fetch_registers (-1);
+ fill_fpregset ((gdb_fpregset_t *) fpregset, -1);
+
+ do_cleanups (old_chain);
+ return PS_OK;
+}
+
+/* Set the floating-point registers of LWP LWPID within the target
+ process PH from FPREGSET. */
+
+ps_err_e
+ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ const gdb_prfpregset_t *fpregset)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, ph->pid);
+
+ /* FIXME: We should really make supply_fpregset const-correct. */
+ supply_fpregset ((gdb_fpregset_t *) fpregset);
+ target_store_registers (-1);
+
+ do_cleanups (old_chain);
+ return PS_OK;
+}
+
+/* Return overall process id of the target PH. Special for GNU/Linux
+ -- not used on Solaris. */
+
+pid_t
+ps_getpid (gdb_ps_prochandle_t ph)
+{
+ return ph->pid;
+}
+
+void
+_initialize_proc_service (void)
+{
+ /* This function solely exists to make sure this module is linked
+ into the final binary. */
+}
diff --git a/contrib/gdb/gdb/proc-utils.h b/contrib/gdb/gdb/proc-utils.h
new file mode 100644
index 0000000..d9f38a8
--- /dev/null
+++ b/contrib/gdb/gdb/proc-utils.h
@@ -0,0 +1,95 @@
+/* Machine independent support for SVR4 /proc (process file system) for GDB.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+/*
+ * Pretty-print functions for /proc data
+ */
+
+extern void proc_prettyprint_why (unsigned long why, unsigned long what,
+ int verbose);
+
+extern void proc_prettyprint_syscalls (sysset_t *sysset, int verbose);
+
+extern void proc_prettyprint_syscall (int num, int verbose);
+
+extern void proc_prettyprint_flags (unsigned long flags, int verbose);
+
+extern void proc_prettyfprint_signalset (FILE *file, sigset_t *sigset,
+ int verbose);
+
+extern void proc_prettyfprint_faultset (FILE *file, fltset_t *fltset,
+ int verbose);
+
+extern void proc_prettyfprint_syscall (FILE *file, int num, int verbose);
+
+extern void proc_prettyfprint_signal (FILE *file, int signo, int verbose);
+
+extern void proc_prettyfprint_flags (FILE *file, unsigned long flags,
+ int verbose);
+
+extern void proc_prettyfprint_why (FILE *file, unsigned long why,
+ unsigned long what, int verbose);
+
+extern void proc_prettyfprint_fault (FILE *file, int faultno, int verbose);
+
+extern void proc_prettyfprint_syscalls (FILE *file, sysset_t *sysset,
+ int verbose);
+
+extern void proc_prettyfprint_status (long, int, int, int);
+
+/*
+ * Trace functions for /proc api.
+ */
+
+extern int write_with_trace (int, void *, size_t, char *, int);
+extern off_t lseek_with_trace (int, off_t, int, char *, int);
+extern int ioctl_with_trace (int, long, void *, char *, int);
+extern pid_t wait_with_trace (int *, char *, int);
+extern int open_with_trace (char *, int, char *, int);
+extern int close_with_trace (int, char *, int);
+extern void procfs_note (char *, char *, int);
+
+#ifdef PROCFS_TRACE
+/*
+ * Debugging code:
+ *
+ * These macros allow me to trace the system calls that we make
+ * to control the child process. This is quite handy for comparing
+ * with the older version of procfs.
+ */
+
+#define write(X,Y,Z) write_with_trace (X, Y, Z, __FILE__, __LINE__)
+#define lseek(X,Y,Z) lseek_with_trace (X, Y, Z, __FILE__, __LINE__)
+#define ioctl(X,Y,Z) ioctl_with_trace (X, Y, Z, __FILE__, __LINE__)
+#define open(X,Y) open_with_trace (X, Y, __FILE__, __LINE__)
+#define close(X) close_with_trace (X, __FILE__, __LINE__)
+#define wait(X) wait_with_trace (X, __FILE__, __LINE__)
+#endif
+#define PROCFS_NOTE(X) procfs_note (X, __FILE__, __LINE__)
+#define PROC_PRETTYFPRINT_STATUS(X,Y,Z,T) \
+ proc_prettyfprint_status (X, Y, Z, T)
+
+/* Define the type (and more importantly the width) of the control
+ word used to write to the /proc/PID/ctl file. */
+#if defined (PROC_CTL_WORD_TYPE)
+typedef PROC_CTL_WORD_TYPE procfs_ctl_t;
+#else
+typedef long procfs_ctl_t;
+#endif
diff --git a/contrib/gdb/gdb/proc-why.c b/contrib/gdb/gdb/proc-why.c
new file mode 100755
index 0000000..15af16c
--- /dev/null
+++ b/contrib/gdb/gdb/proc-why.c
@@ -0,0 +1,175 @@
+/* Machine independent support for SVR4 /proc (process file system) for GDB.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+ Written by Michael Snyder at Cygnus Solutions.
+ Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ * Pretty-print the pr_why value.
+ *
+ * Arguments: unsigned long flags, int verbose
+ *
+ */
+
+#include "defs.h"
+
+#if defined(NEW_PROC_API)
+#define _STRUCTURED_PROC 1
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+
+#include "proc-utils.h"
+
+/* 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 values in the pr_why field of the prstatus struct. */
+
+static struct trans pr_why_table[] =
+{
+#if defined (PR_REQUESTED)
+ /* All platforms */
+ { PR_REQUESTED, "PR_REQUESTED",
+ "Directed to stop by debugger via P(IO)CSTOP or P(IO)CWSTOP" },
+#endif
+#if defined (PR_SIGNALLED)
+ /* All platforms */
+ { PR_SIGNALLED, "PR_SIGNALLED", "Receipt of a traced signal" },
+#endif
+#if defined (PR_SYSENTRY)
+ /* All platforms */
+ { PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call" },
+#endif
+#if defined (PR_SYSEXIT)
+ /* All platforms */
+ { PR_SYSEXIT, "PR_SYSEXIT", "Exit from a traced system call" },
+#endif
+#if defined (PR_JOBCONTROL)
+ /* All platforms */
+ { PR_JOBCONTROL, "PR_JOBCONTROL", "Default job control stop signal action" },
+#endif
+#if defined (PR_FAULTED)
+ /* All platforms */
+ { PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault" },
+#endif
+#if defined (PR_SUSPENDED)
+ /* Solaris and UnixWare */
+ { PR_SUSPENDED, "PR_SUSPENDED", "Process suspended" },
+#endif
+#if defined (PR_CHECKPOINT)
+ /* Solaris only */
+ { PR_CHECKPOINT, "PR_CHECKPOINT", "Process stopped at checkpoint" },
+#endif
+#if defined (PR_FORKSTOP)
+ /* OSF only */
+ { PR_FORKSTOP, "PR_FORKSTOP", "Process stopped at end of fork call" },
+#endif
+#if defined (PR_TCRSTOP)
+ /* OSF only */
+ { PR_TCRSTOP, "PR_TCRSTOP", "Process stopped on thread creation" },
+#endif
+#if defined (PR_TTSTOP)
+ /* OSF only */
+ { PR_TTSTOP, "PR_TTSTOP", "Process stopped on thread termination" },
+#endif
+#if defined (PR_DEAD)
+ /* OSF only */
+ { PR_DEAD, "PR_DEAD", "Process stopped in exit system call" },
+#endif
+};
+
+void
+proc_prettyfprint_why (FILE *file, unsigned long why, unsigned long what,
+ int verbose)
+{
+ int i;
+
+ if (why == 0)
+ return;
+
+ for (i = 0; i < sizeof (pr_why_table) / sizeof (pr_why_table[0]); i++)
+ if (why == pr_why_table[i].value)
+ {
+ fprintf (file, "%s ", pr_why_table[i].name);
+ if (verbose)
+ fprintf (file, ": %s ", pr_why_table[i].desc);
+
+ switch (why) {
+#ifdef PR_REQUESTED
+ case PR_REQUESTED:
+ break; /* Nothing more to print. */
+#endif
+#ifdef PR_SIGNALLED
+ case PR_SIGNALLED:
+ proc_prettyfprint_signal (file, what, verbose);
+ break;
+#endif
+#ifdef PR_FAULTED
+ case PR_FAULTED:
+ proc_prettyfprint_fault (file, what, verbose);
+ break;
+#endif
+#ifdef PR_SYSENTRY
+ case PR_SYSENTRY:
+ fprintf (file, "Entry to ");
+ proc_prettyfprint_syscall (file, what, verbose);
+ break;
+#endif
+#ifdef PR_SYSEXIT
+ case PR_SYSEXIT:
+ fprintf (file, "Exit from ");
+ proc_prettyfprint_syscall (file, what, verbose);
+ break;
+#endif
+#ifdef PR_JOBCONTROL
+ case PR_JOBCONTROL:
+ proc_prettyfprint_signal (file, what, verbose);
+ break;
+#endif
+#ifdef PR_DEAD
+ case PR_DEAD:
+ fprintf (file, "Exit status: %d\n", what);
+ break;
+#endif
+ default:
+ fprintf (file, "Unknown why %ld, what %ld\n", why, what);
+ break;
+ }
+ fprintf (file, "\n");
+
+ return;
+ }
+ fprintf (file, "Unknown pr_why.\n");
+}
+
+void
+proc_prettyprint_why (unsigned long why, unsigned long what, int verbose)
+{
+ proc_prettyfprint_why (stdout, why, what, verbose);
+}
diff --git a/contrib/gdb/gdb/process_reply.defs b/contrib/gdb/gdb/process_reply.defs
new file mode 100644
index 0000000..824b5c6
--- /dev/null
+++ b/contrib/gdb/gdb/process_reply.defs
@@ -0,0 +1 @@
+#include <hurd/process_reply.defs>
diff --git a/contrib/gdb/gdb/procfs.c b/contrib/gdb/gdb/procfs.c
new file mode 100644
index 0000000..352b735
--- /dev/null
+++ b/contrib/gdb/gdb/procfs.c
@@ -0,0 +1,5960 @@
+/* Machine independent support for SVR4 /proc (process file system) for GDB.
+
+ Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
+ Inc.
+
+ Written by Michael Snyder at Cygnus Solutions.
+ Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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"
+#include "gdbcore.h"
+#include "elf-bfd.h" /* for elfcore_write_* */
+#include "gdbcmd.h"
+#include "gdbthread.h"
+
+#if defined (NEW_PROC_API)
+#define _STRUCTURED_PROC 1 /* Should be done by configure script. */
+#endif
+
+#include <sys/procfs.h>
+#ifdef HAVE_SYS_FAULT_H
+#include <sys/fault.h>
+#endif
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
+#include <sys/errno.h>
+#include "gdb_wait.h"
+#include <signal.h>
+#include <ctype.h>
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "inflow.h"
+#include "auxv.h"
+
+/*
+ * PROCFS.C
+ *
+ * This module provides the interface between GDB and the
+ * /proc file system, which is used on many versions of Unix
+ * as a means for debuggers to control other processes.
+ * Examples of the systems that use this interface are:
+ * Irix
+ * Solaris
+ * OSF
+ * Unixware
+ * AIX5
+ *
+ * /proc works by imitating a file system: you open a simulated file
+ * that represents the process you wish to interact with, and
+ * perform operations on that "file" in order to examine or change
+ * the state of the other process.
+ *
+ * The most important thing to know about /proc and this module
+ * is that there are two very different interfaces to /proc:
+ * One that uses the ioctl system call, and
+ * another that uses read and write system calls.
+ * This module has to support both /proc interfaces. This means
+ * that there are two different ways of doing every basic operation.
+ *
+ * In order to keep most of the code simple and clean, I have
+ * defined an interface "layer" which hides all these system calls.
+ * An ifdef (NEW_PROC_API) determines which interface we are using,
+ * and most or all occurrances of this ifdef should be confined to
+ * this interface layer.
+ */
+
+
+/* Determine which /proc API we are using:
+ The ioctl API defines PIOCSTATUS, while
+ the read/write (multiple fd) API never does. */
+
+#ifdef NEW_PROC_API
+#include <sys/types.h>
+#include "gdb_dirent.h" /* opendir/readdir, for listing the LWP's */
+#endif
+
+#include <fcntl.h> /* for O_RDONLY */
+#include <unistd.h> /* for "X_OK" */
+#include "gdb_stat.h" /* for struct stat */
+
+/* Note: procfs-utils.h must be included after the above system header
+ files, because it redefines various system calls using macros.
+ This may be incompatible with the prototype declarations. */
+
+#include "proc-utils.h"
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* =================== TARGET_OPS "MODULE" =================== */
+
+/*
+ * This module defines the GDB target vector and its methods.
+ */
+
+static void procfs_open (char *, int);
+static void procfs_attach (char *, int);
+static void procfs_detach (char *, int);
+static void procfs_resume (ptid_t, int, enum target_signal);
+static int procfs_can_run (void);
+static void procfs_stop (void);
+static void procfs_files_info (struct target_ops *);
+static void procfs_fetch_registers (int);
+static void procfs_store_registers (int);
+static void procfs_notice_signals (ptid_t);
+static void procfs_prepare_to_store (void);
+static void procfs_kill_inferior (void);
+static void procfs_mourn_inferior (void);
+static void procfs_create_inferior (char *, char *, char **);
+static ptid_t procfs_wait (ptid_t, struct target_waitstatus *);
+static int procfs_xfer_memory (CORE_ADDR, char *, int, int,
+ struct mem_attrib *attrib,
+ struct target_ops *);
+static LONGEST procfs_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len);
+
+static int procfs_thread_alive (ptid_t);
+
+void procfs_find_new_threads (void);
+char *procfs_pid_to_str (ptid_t);
+
+static int proc_find_memory_regions (int (*) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *);
+
+static char * procfs_make_note_section (bfd *, int *);
+
+static int procfs_can_use_hw_breakpoint (int, int, int);
+
+struct target_ops procfs_ops; /* the target vector */
+
+static void
+init_procfs_ops (void)
+{
+ procfs_ops.to_shortname = "procfs";
+ procfs_ops.to_longname = "Unix /proc child process";
+ procfs_ops.to_doc =
+ "Unix /proc child process (started by the \"run\" command).";
+ procfs_ops.to_open = procfs_open;
+ procfs_ops.to_can_run = procfs_can_run;
+ procfs_ops.to_create_inferior = procfs_create_inferior;
+ procfs_ops.to_kill = procfs_kill_inferior;
+ procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
+ procfs_ops.to_attach = procfs_attach;
+ procfs_ops.to_detach = procfs_detach;
+ procfs_ops.to_wait = procfs_wait;
+ procfs_ops.to_resume = procfs_resume;
+ procfs_ops.to_prepare_to_store = procfs_prepare_to_store;
+ procfs_ops.to_fetch_registers = procfs_fetch_registers;
+ procfs_ops.to_store_registers = procfs_store_registers;
+ procfs_ops.to_xfer_partial = procfs_xfer_partial;
+ procfs_ops.to_xfer_memory = procfs_xfer_memory;
+ procfs_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ procfs_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ procfs_ops.to_notice_signals = procfs_notice_signals;
+ procfs_ops.to_files_info = procfs_files_info;
+ procfs_ops.to_stop = procfs_stop;
+
+ procfs_ops.to_terminal_init = terminal_init_inferior;
+ procfs_ops.to_terminal_inferior = terminal_inferior;
+ procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ procfs_ops.to_terminal_ours = terminal_ours;
+ procfs_ops.to_terminal_save_ours = terminal_save_ours;
+ procfs_ops.to_terminal_info = child_terminal_info;
+
+ procfs_ops.to_find_new_threads = procfs_find_new_threads;
+ procfs_ops.to_thread_alive = procfs_thread_alive;
+ procfs_ops.to_pid_to_str = procfs_pid_to_str;
+
+ procfs_ops.to_has_all_memory = 1;
+ procfs_ops.to_has_memory = 1;
+ procfs_ops.to_has_execution = 1;
+ procfs_ops.to_has_stack = 1;
+ procfs_ops.to_has_registers = 1;
+ procfs_ops.to_stratum = process_stratum;
+ procfs_ops.to_has_thread_control = tc_schedlock;
+ procfs_ops.to_find_memory_regions = proc_find_memory_regions;
+ procfs_ops.to_make_corefile_notes = procfs_make_note_section;
+ procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint;
+ procfs_ops.to_magic = OPS_MAGIC;
+}
+
+/* =================== END, TARGET_OPS "MODULE" =================== */
+
+/*
+ * World Unification:
+ *
+ * Put any typedefs, defines etc. here that are required for
+ * the unification of code that handles different versions of /proc.
+ */
+
+#ifdef NEW_PROC_API /* Solaris 7 && 8 method for watchpoints */
+#ifdef WA_READ
+ enum { READ_WATCHFLAG = WA_READ,
+ WRITE_WATCHFLAG = WA_WRITE,
+ EXEC_WATCHFLAG = WA_EXEC,
+ AFTER_WATCHFLAG = WA_TRAPAFTER
+ };
+#endif
+#else /* Irix method for watchpoints */
+ enum { READ_WATCHFLAG = MA_READ,
+ WRITE_WATCHFLAG = MA_WRITE,
+ EXEC_WATCHFLAG = MA_EXEC,
+ AFTER_WATCHFLAG = 0 /* trapafter not implemented */
+ };
+#endif
+
+/* gdb_sigset_t */
+#ifdef HAVE_PR_SIGSET_T
+typedef pr_sigset_t gdb_sigset_t;
+#else
+typedef sigset_t gdb_sigset_t;
+#endif
+
+/* sigaction */
+#ifdef HAVE_PR_SIGACTION64_T
+typedef pr_sigaction64_t gdb_sigaction_t;
+#else
+typedef struct sigaction gdb_sigaction_t;
+#endif
+
+/* siginfo */
+#ifdef HAVE_PR_SIGINFO64_T
+typedef pr_siginfo64_t gdb_siginfo_t;
+#else
+typedef struct siginfo gdb_siginfo_t;
+#endif
+
+/* gdb_premptysysset */
+#ifdef premptysysset
+#define gdb_premptysysset premptysysset
+#else
+#define gdb_premptysysset premptyset
+#endif
+
+/* praddsysset */
+#ifdef praddsysset
+#define gdb_praddsysset praddsysset
+#else
+#define gdb_praddsysset praddset
+#endif
+
+/* prdelsysset */
+#ifdef prdelsysset
+#define gdb_prdelsysset prdelsysset
+#else
+#define gdb_prdelsysset prdelset
+#endif
+
+/* prissyssetmember */
+#ifdef prissyssetmember
+#define gdb_pr_issyssetmember prissyssetmember
+#else
+#define gdb_pr_issyssetmember prismember
+#endif
+
+/* As a feature test, saying ``#if HAVE_PRSYSENT_T'' everywhere isn't
+ as intuitively descriptive as it could be, so we'll define
+ DYNAMIC_SYSCALLS to mean the same thing. Anyway, at the time of
+ this writing, this feature is only found on AIX5 systems and
+ basically means that the set of syscalls is not fixed. I.e,
+ there's no nice table that one can #include to get all of the
+ syscall numbers. Instead, they're stored in /proc/PID/sysent
+ for each process. We are at least guaranteed that they won't
+ change over the lifetime of the process. But each process could
+ (in theory) have different syscall numbers.
+*/
+#ifdef HAVE_PRSYSENT_T
+#define DYNAMIC_SYSCALLS
+#endif
+
+
+
+/* =================== STRUCT PROCINFO "MODULE" =================== */
+
+ /* FIXME: this comment will soon be out of date W.R.T. threads. */
+
+/* The procinfo struct is a wrapper to hold all the state information
+ concerning a /proc process. There should be exactly one procinfo
+ for each process, and since GDB currently can debug only one
+ process at a time, that means there should be only one procinfo.
+ All of the LWP's of a process can be accessed indirectly thru the
+ single process procinfo.
+
+ However, against the day when GDB may debug more than one process,
+ this data structure is kept in a list (which for now will hold no
+ more than one member), and many functions will have a pointer to a
+ procinfo as an argument.
+
+ There will be a separate procinfo structure for use by the (not yet
+ implemented) "info proc" command, so that we can print useful
+ information about any random process without interfering with the
+ inferior's procinfo information. */
+
+#ifdef NEW_PROC_API
+/* format strings for /proc paths */
+# ifndef CTL_PROC_NAME_FMT
+# define MAIN_PROC_NAME_FMT "/proc/%d"
+# define CTL_PROC_NAME_FMT "/proc/%d/ctl"
+# define AS_PROC_NAME_FMT "/proc/%d/as"
+# define MAP_PROC_NAME_FMT "/proc/%d/map"
+# define STATUS_PROC_NAME_FMT "/proc/%d/status"
+# define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/8096/lstatus")
+# endif
+/* the name of the proc status struct depends on the implementation */
+typedef pstatus_t gdb_prstatus_t;
+typedef lwpstatus_t gdb_lwpstatus_t;
+#else /* ! NEW_PROC_API */
+/* format strings for /proc paths */
+# ifndef CTL_PROC_NAME_FMT
+# define MAIN_PROC_NAME_FMT "/proc/%05d"
+# define CTL_PROC_NAME_FMT "/proc/%05d"
+# define AS_PROC_NAME_FMT "/proc/%05d"
+# define MAP_PROC_NAME_FMT "/proc/%05d"
+# define STATUS_PROC_NAME_FMT "/proc/%05d"
+# define MAX_PROC_NAME_SIZE sizeof("/proc/ttttppppp")
+# endif
+/* the name of the proc status struct depends on the implementation */
+typedef prstatus_t gdb_prstatus_t;
+typedef prstatus_t gdb_lwpstatus_t;
+#endif /* NEW_PROC_API */
+
+typedef struct procinfo {
+ struct procinfo *next;
+ int pid; /* Process ID */
+ int tid; /* Thread/LWP id */
+
+ /* process state */
+ int was_stopped;
+ int ignore_next_sigstop;
+
+ /* The following four fd fields may be identical, or may contain
+ several different fd's, depending on the version of /proc
+ (old ioctl or new read/write). */
+
+ int ctl_fd; /* File descriptor for /proc control file */
+ /*
+ * The next three file descriptors are actually only needed in the
+ * read/write, multiple-file-descriptor implemenation (NEW_PROC_API).
+ * However, to avoid a bunch of #ifdefs in the code, we will use
+ * them uniformly by (in the case of the ioctl single-file-descriptor
+ * implementation) filling them with copies of the control fd.
+ */
+ int status_fd; /* File descriptor for /proc status file */
+ int as_fd; /* File descriptor for /proc as file */
+
+ char pathname[MAX_PROC_NAME_SIZE]; /* Pathname to /proc entry */
+
+ fltset_t saved_fltset; /* Saved traced hardware fault set */
+ gdb_sigset_t saved_sigset; /* Saved traced signal set */
+ gdb_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 */
+
+ gdb_prstatus_t prstatus; /* Current process status info */
+
+#ifndef NEW_PROC_API
+ gdb_fpregset_t fpregset; /* Current floating point registers */
+#endif
+
+#ifdef DYNAMIC_SYSCALLS
+ int num_syscalls; /* Total number of syscalls */
+ char **syscall_names; /* Syscall number to name map */
+#endif
+
+ struct procinfo *thread_list;
+
+ int status_valid : 1;
+ int gregs_valid : 1;
+ int fpregs_valid : 1;
+ int threads_valid: 1;
+} procinfo;
+
+static char errmsg[128]; /* shared error msg buffer */
+
+/* Function prototypes for procinfo module: */
+
+static procinfo *find_procinfo_or_die (int pid, int tid);
+static procinfo *find_procinfo (int pid, int tid);
+static procinfo *create_procinfo (int pid, int tid);
+static void destroy_procinfo (procinfo * p);
+static void do_destroy_procinfo_cleanup (void *);
+static void dead_procinfo (procinfo * p, char *msg, int killp);
+static int open_procinfo_files (procinfo * p, int which);
+static void close_procinfo_files (procinfo * p);
+static int sysset_t_size (procinfo *p);
+static sysset_t *sysset_t_alloc (procinfo * pi);
+#ifdef DYNAMIC_SYSCALLS
+static void load_syscalls (procinfo *pi);
+static void free_syscalls (procinfo *pi);
+static int find_syscall (procinfo *pi, char *name);
+#endif /* DYNAMIC_SYSCALLS */
+
+/* The head of the procinfo list: */
+static procinfo * procinfo_list;
+
+/*
+ * Function: find_procinfo
+ *
+ * Search the procinfo list.
+ *
+ * Returns: pointer to procinfo, or NULL if not found.
+ */
+
+static procinfo *
+find_procinfo (int pid, int tid)
+{
+ procinfo *pi;
+
+ for (pi = procinfo_list; pi; pi = pi->next)
+ if (pi->pid == pid)
+ break;
+
+ if (pi)
+ if (tid)
+ {
+ /* Don't check threads_valid. If we're updating the
+ thread_list, we want to find whatever threads are already
+ here. This means that in general it is the caller's
+ responsibility to check threads_valid and update before
+ calling find_procinfo, if the caller wants to find a new
+ thread. */
+
+ for (pi = pi->thread_list; pi; pi = pi->next)
+ if (pi->tid == tid)
+ break;
+ }
+
+ return pi;
+}
+
+/*
+ * Function: find_procinfo_or_die
+ *
+ * Calls find_procinfo, but errors on failure.
+ */
+
+static procinfo *
+find_procinfo_or_die (int pid, int tid)
+{
+ procinfo *pi = find_procinfo (pid, tid);
+
+ if (pi == NULL)
+ {
+ if (tid)
+ error ("procfs: couldn't find pid %d (kernel thread %d) in procinfo list.",
+ pid, tid);
+ else
+ error ("procfs: couldn't find pid %d in procinfo list.", pid);
+ }
+ return pi;
+}
+
+/* open_with_retry() is a wrapper for open(). The appropriate
+ open() call is attempted; if unsuccessful, it will be retried as
+ many times as needed for the EAGAIN and EINTR conditions.
+
+ For other conditions, open_with_retry() will retry the open() a
+ limited number of times. In addition, a short sleep is imposed
+ prior to retrying the open(). The reason for this sleep is to give
+ the kernel a chance to catch up and create the file in question in
+ the event that GDB "wins" the race to open a file before the kernel
+ has created it. */
+
+static int
+open_with_retry (const char *pathname, int flags)
+{
+ int retries_remaining, status;
+
+ retries_remaining = 2;
+
+ while (1)
+ {
+ status = open (pathname, flags);
+
+ if (status >= 0 || retries_remaining == 0)
+ break;
+ else if (errno != EINTR && errno != EAGAIN)
+ {
+ retries_remaining--;
+ sleep (1);
+ }
+ }
+
+ return status;
+}
+
+/*
+ * Function: open_procinfo_files
+ *
+ * Open the file descriptor for the process or LWP.
+ * ifdef NEW_PROC_API, we only open the control file descriptor;
+ * the others are opened lazily as needed.
+ * else (if not NEW_PROC_API), there is only one real
+ * file descriptor, but we keep multiple copies of it so that
+ * the code that uses them does not have to be #ifdef'd.
+ *
+ * Return: file descriptor, or zero for failure.
+ */
+
+enum { FD_CTL, FD_STATUS, FD_AS };
+
+static int
+open_procinfo_files (procinfo *pi, int which)
+{
+#ifdef NEW_PROC_API
+ char tmp[MAX_PROC_NAME_SIZE];
+#endif
+ int fd;
+
+ /*
+ * This function is getting ALMOST long enough to break up into several.
+ * Here is some rationale:
+ *
+ * NEW_PROC_API (Solaris 2.6, Solaris 2.7, Unixware):
+ * There are several file descriptors that may need to be open
+ * for any given process or LWP. The ones we're intereted in are:
+ * - control (ctl) write-only change the state
+ * - status (status) read-only query the state
+ * - address space (as) read/write access memory
+ * - map (map) read-only virtual addr map
+ * Most of these are opened lazily as they are needed.
+ * The pathnames for the 'files' for an LWP look slightly
+ * different from those of a first-class process:
+ * Pathnames for a process (<proc-id>):
+ * /proc/<proc-id>/ctl
+ * /proc/<proc-id>/status
+ * /proc/<proc-id>/as
+ * /proc/<proc-id>/map
+ * Pathnames for an LWP (lwp-id):
+ * /proc/<proc-id>/lwp/<lwp-id>/lwpctl
+ * /proc/<proc-id>/lwp/<lwp-id>/lwpstatus
+ * An LWP has no map or address space file descriptor, since
+ * the memory map and address space are shared by all LWPs.
+ *
+ * Everyone else (Solaris 2.5, Irix, OSF)
+ * There is only one file descriptor for each process or LWP.
+ * For convenience, we copy the same file descriptor into all
+ * three fields of the procinfo struct (ctl_fd, status_fd, and
+ * as_fd, see NEW_PROC_API above) so that code that uses them
+ * doesn't need any #ifdef's.
+ * Pathname for all:
+ * /proc/<proc-id>
+ *
+ * Solaris 2.5 LWP's:
+ * Each LWP has an independent file descriptor, but these
+ * are not obtained via the 'open' system call like the rest:
+ * instead, they're obtained thru an ioctl call (PIOCOPENLWP)
+ * to the file descriptor of the parent process.
+ *
+ * OSF threads:
+ * These do not even have their own independent file descriptor.
+ * All operations are carried out on the file descriptor of the
+ * parent process. Therefore we just call open again for each
+ * thread, getting a new handle for the same 'file'.
+ */
+
+#ifdef NEW_PROC_API
+ /*
+ * In this case, there are several different file descriptors that
+ * we might be asked to open. The control file descriptor will be
+ * opened early, but the others will be opened lazily as they are
+ * needed.
+ */
+
+ strcpy (tmp, pi->pathname);
+ switch (which) { /* which file descriptor to open? */
+ case FD_CTL:
+ if (pi->tid)
+ strcat (tmp, "/lwpctl");
+ else
+ strcat (tmp, "/ctl");
+ fd = open_with_retry (tmp, O_WRONLY);
+ if (fd <= 0)
+ return 0; /* fail */
+ pi->ctl_fd = fd;
+ break;
+ case FD_AS:
+ if (pi->tid)
+ return 0; /* there is no 'as' file descriptor for an lwp */
+ strcat (tmp, "/as");
+ fd = open_with_retry (tmp, O_RDWR);
+ if (fd <= 0)
+ return 0; /* fail */
+ pi->as_fd = fd;
+ break;
+ case FD_STATUS:
+ if (pi->tid)
+ strcat (tmp, "/lwpstatus");
+ else
+ strcat (tmp, "/status");
+ fd = open_with_retry (tmp, O_RDONLY);
+ if (fd <= 0)
+ return 0; /* fail */
+ pi->status_fd = fd;
+ break;
+ default:
+ return 0; /* unknown file descriptor */
+ }
+#else /* not NEW_PROC_API */
+ /*
+ * In this case, there is only one file descriptor for each procinfo
+ * (ie. each process or LWP). In fact, only the file descriptor for
+ * the process can actually be opened by an 'open' system call.
+ * The ones for the LWPs have to be obtained thru an IOCTL call
+ * on the process's file descriptor.
+ *
+ * For convenience, we copy each procinfo's single file descriptor
+ * into all of the fields occupied by the several file descriptors
+ * of the NEW_PROC_API implementation. That way, the code that uses
+ * them can be written without ifdefs.
+ */
+
+
+#ifdef PIOCTSTATUS /* OSF */
+ /* Only one FD; just open it. */
+ if ((fd = open_with_retry (pi->pathname, O_RDWR)) == 0)
+ return 0;
+#else /* Sol 2.5, Irix, other? */
+ if (pi->tid == 0) /* Master procinfo for the process */
+ {
+ fd = open_with_retry (pi->pathname, O_RDWR);
+ if (fd <= 0)
+ return 0; /* fail */
+ }
+ else /* LWP thread procinfo */
+ {
+#ifdef PIOCOPENLWP /* Sol 2.5, thread/LWP */
+ procinfo *process;
+ int lwpid = pi->tid;
+
+ /* Find the procinfo for the entire process. */
+ if ((process = find_procinfo (pi->pid, 0)) == NULL)
+ return 0; /* fail */
+
+ /* Now obtain the file descriptor for the LWP. */
+ if ((fd = ioctl (process->ctl_fd, PIOCOPENLWP, &lwpid)) <= 0)
+ return 0; /* fail */
+#else /* Irix, other? */
+ return 0; /* Don't know how to open threads */
+#endif /* Sol 2.5 PIOCOPENLWP */
+ }
+#endif /* OSF PIOCTSTATUS */
+ pi->ctl_fd = pi->as_fd = pi->status_fd = fd;
+#endif /* NEW_PROC_API */
+
+ return 1; /* success */
+}
+
+/*
+ * Function: create_procinfo
+ *
+ * Allocate a data structure and link it into the procinfo list.
+ * (First tries to find a pre-existing one (FIXME: why?)
+ *
+ * Return: pointer to new procinfo struct.
+ */
+
+static procinfo *
+create_procinfo (int pid, int tid)
+{
+ procinfo *pi, *parent;
+
+ if ((pi = find_procinfo (pid, tid)))
+ return pi; /* Already exists, nothing to do. */
+
+ /* find parent before doing malloc, to save having to cleanup */
+ if (tid != 0)
+ parent = find_procinfo_or_die (pid, 0); /* FIXME: should I
+ create it if it
+ doesn't exist yet? */
+
+ pi = (procinfo *) xmalloc (sizeof (procinfo));
+ memset (pi, 0, sizeof (procinfo));
+ pi->pid = pid;
+ pi->tid = tid;
+
+#ifdef DYNAMIC_SYSCALLS
+ load_syscalls (pi);
+#endif
+
+ pi->saved_entryset = sysset_t_alloc (pi);
+ pi->saved_exitset = sysset_t_alloc (pi);
+
+ /* Chain into list. */
+ if (tid == 0)
+ {
+ sprintf (pi->pathname, MAIN_PROC_NAME_FMT, pid);
+ pi->next = procinfo_list;
+ procinfo_list = pi;
+ }
+ else
+ {
+#ifdef NEW_PROC_API
+ sprintf (pi->pathname, "/proc/%05d/lwp/%d", pid, tid);
+#else
+ sprintf (pi->pathname, MAIN_PROC_NAME_FMT, pid);
+#endif
+ pi->next = parent->thread_list;
+ parent->thread_list = pi;
+ }
+ return pi;
+}
+
+/*
+ * Function: close_procinfo_files
+ *
+ * Close all file descriptors associated with the procinfo
+ */
+
+static void
+close_procinfo_files (procinfo *pi)
+{
+ if (pi->ctl_fd > 0)
+ close (pi->ctl_fd);
+#ifdef NEW_PROC_API
+ if (pi->as_fd > 0)
+ close (pi->as_fd);
+ if (pi->status_fd > 0)
+ close (pi->status_fd);
+#endif
+ pi->ctl_fd = pi->as_fd = pi->status_fd = 0;
+}
+
+/*
+ * Function: destroy_procinfo
+ *
+ * Destructor function. Close, unlink and deallocate the object.
+ */
+
+static void
+destroy_one_procinfo (procinfo **list, procinfo *pi)
+{
+ procinfo *ptr;
+
+ /* Step one: unlink the procinfo from its list */
+ if (pi == *list)
+ *list = pi->next;
+ else
+ for (ptr = *list; ptr; ptr = ptr->next)
+ if (ptr->next == pi)
+ {
+ ptr->next = pi->next;
+ break;
+ }
+
+ /* Step two: close any open file descriptors */
+ close_procinfo_files (pi);
+
+ /* Step three: free the memory. */
+#ifdef DYNAMIC_SYSCALLS
+ free_syscalls (pi);
+#endif
+ xfree (pi->saved_entryset);
+ xfree (pi->saved_exitset);
+ xfree (pi);
+}
+
+static void
+destroy_procinfo (procinfo *pi)
+{
+ procinfo *tmp;
+
+ if (pi->tid != 0) /* destroy a thread procinfo */
+ {
+ tmp = find_procinfo (pi->pid, 0); /* find the parent process */
+ destroy_one_procinfo (&tmp->thread_list, pi);
+ }
+ else /* destroy a process procinfo and all its threads */
+ {
+ /* First destroy the children, if any; */
+ while (pi->thread_list != NULL)
+ destroy_one_procinfo (&pi->thread_list, pi->thread_list);
+ /* Then destroy the parent. Genocide!!! */
+ destroy_one_procinfo (&procinfo_list, pi);
+ }
+}
+
+static void
+do_destroy_procinfo_cleanup (void *pi)
+{
+ destroy_procinfo (pi);
+}
+
+enum { NOKILL, KILL };
+
+/*
+ * Function: dead_procinfo
+ *
+ * To be called on a non_recoverable error for a procinfo.
+ * Prints error messages, optionally sends a SIGKILL to the process,
+ * then destroys the data structure.
+ */
+
+static void
+dead_procinfo (procinfo *pi, char *msg, int kill_p)
+{
+ char procfile[80];
+
+ if (pi->pathname)
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ }
+ else
+ {
+ sprintf (procfile, "process %d", pi->pid);
+ print_sys_errmsg (procfile, errno);
+ }
+ if (kill_p == KILL)
+ kill (pi->pid, SIGKILL);
+
+ destroy_procinfo (pi);
+ error (msg);
+}
+
+/*
+ * Function: sysset_t_size
+ *
+ * Returns the (complete) size of a sysset_t struct. Normally, this
+ * is just sizeof (syset_t), but in the case of Monterey/64, the actual
+ * size of sysset_t isn't known until runtime.
+ */
+
+static int
+sysset_t_size (procinfo * pi)
+{
+#ifndef DYNAMIC_SYSCALLS
+ return sizeof (sysset_t);
+#else
+ return sizeof (sysset_t) - sizeof (uint64_t)
+ + sizeof (uint64_t) * ((pi->num_syscalls + (8 * sizeof (uint64_t) - 1))
+ / (8 * sizeof (uint64_t)));
+#endif
+}
+
+/* Function: sysset_t_alloc
+
+ Allocate and (partially) initialize a sysset_t struct. */
+
+static sysset_t *
+sysset_t_alloc (procinfo * pi)
+{
+ sysset_t *ret;
+ int size = sysset_t_size (pi);
+ ret = xmalloc (size);
+#ifdef DYNAMIC_SYSCALLS
+ ret->pr_size = (pi->num_syscalls + (8 * sizeof (uint64_t) - 1))
+ / (8 * sizeof (uint64_t));
+#endif
+ return ret;
+}
+
+#ifdef DYNAMIC_SYSCALLS
+
+/* Function: load_syscalls
+
+ Extract syscall numbers and names from /proc/<pid>/sysent. Initialize
+ pi->num_syscalls with the number of syscalls and pi->syscall_names
+ with the names. (Certain numbers may be skipped in which case the
+ names for these numbers will be left as NULL.) */
+
+#define MAX_SYSCALL_NAME_LENGTH 256
+#define MAX_SYSCALLS 65536
+
+static void
+load_syscalls (procinfo *pi)
+{
+ char pathname[MAX_PROC_NAME_SIZE];
+ int sysent_fd;
+ prsysent_t header;
+ prsyscall_t *syscalls;
+ int i, size, maxcall;
+
+ pi->num_syscalls = 0;
+ pi->syscall_names = 0;
+
+ /* Open the file descriptor for the sysent file */
+ sprintf (pathname, "/proc/%d/sysent", pi->pid);
+ sysent_fd = open_with_retry (pathname, O_RDONLY);
+ if (sysent_fd < 0)
+ {
+ error ("load_syscalls: Can't open /proc/%d/sysent", pi->pid);
+ }
+
+ size = sizeof header - sizeof (prsyscall_t);
+ if (read (sysent_fd, &header, size) != size)
+ {
+ error ("load_syscalls: Error reading /proc/%d/sysent", pi->pid);
+ }
+
+ if (header.pr_nsyscalls == 0)
+ {
+ error ("load_syscalls: /proc/%d/sysent contains no syscalls!", pi->pid);
+ }
+
+ size = header.pr_nsyscalls * sizeof (prsyscall_t);
+ syscalls = xmalloc (size);
+
+ if (read (sysent_fd, syscalls, size) != size)
+ {
+ xfree (syscalls);
+ error ("load_syscalls: Error reading /proc/%d/sysent", pi->pid);
+ }
+
+ /* Find maximum syscall number. This may not be the same as
+ pr_nsyscalls since that value refers to the number of entries
+ in the table. (Also, the docs indicate that some system
+ call numbers may be skipped.) */
+
+ maxcall = syscalls[0].pr_number;
+
+ for (i = 1; i < header.pr_nsyscalls; i++)
+ if (syscalls[i].pr_number > maxcall
+ && syscalls[i].pr_nameoff > 0
+ && syscalls[i].pr_number < MAX_SYSCALLS)
+ maxcall = syscalls[i].pr_number;
+
+ pi->num_syscalls = maxcall+1;
+ pi->syscall_names = xmalloc (pi->num_syscalls * sizeof (char *));
+
+ for (i = 0; i < pi->num_syscalls; i++)
+ pi->syscall_names[i] = NULL;
+
+ /* Read the syscall names in */
+ for (i = 0; i < header.pr_nsyscalls; i++)
+ {
+ char namebuf[MAX_SYSCALL_NAME_LENGTH];
+ int nread;
+ int callnum;
+
+ if (syscalls[i].pr_number >= MAX_SYSCALLS
+ || syscalls[i].pr_number < 0
+ || syscalls[i].pr_nameoff <= 0
+ || (lseek (sysent_fd, (off_t) syscalls[i].pr_nameoff, SEEK_SET)
+ != (off_t) syscalls[i].pr_nameoff))
+ continue;
+
+ nread = read (sysent_fd, namebuf, sizeof namebuf);
+ if (nread <= 0)
+ continue;
+
+ callnum = syscalls[i].pr_number;
+
+ if (pi->syscall_names[callnum] != NULL)
+ {
+ /* FIXME: Generate warning */
+ continue;
+ }
+
+ namebuf[nread-1] = '\0';
+ size = strlen (namebuf) + 1;
+ pi->syscall_names[callnum] = xmalloc (size);
+ strncpy (pi->syscall_names[callnum], namebuf, size-1);
+ pi->syscall_names[callnum][size-1] = '\0';
+ }
+
+ close (sysent_fd);
+ xfree (syscalls);
+}
+
+/* Function: free_syscalls
+
+ Free the space allocated for the syscall names from the procinfo
+ structure. */
+
+static void
+free_syscalls (procinfo *pi)
+{
+ if (pi->syscall_names)
+ {
+ int i;
+
+ for (i = 0; i < pi->num_syscalls; i++)
+ if (pi->syscall_names[i] != NULL)
+ xfree (pi->syscall_names[i]);
+
+ xfree (pi->syscall_names);
+ pi->syscall_names = 0;
+ }
+}
+
+/* Function: find_syscall
+
+ Given a name, look up (and return) the corresponding syscall number.
+ If no match is found, return -1. */
+
+static int
+find_syscall (procinfo *pi, char *name)
+{
+ int i;
+ for (i = 0; i < pi->num_syscalls; i++)
+ {
+ if (pi->syscall_names[i] && strcmp (name, pi->syscall_names[i]) == 0)
+ return i;
+ }
+ return -1;
+}
+#endif
+
+/* =================== END, STRUCT PROCINFO "MODULE" =================== */
+
+/* =================== /proc "MODULE" =================== */
+
+/*
+ * This "module" is the interface layer between the /proc system API
+ * and the gdb target vector functions. This layer consists of
+ * access functions that encapsulate each of the basic operations
+ * that we need to use from the /proc API.
+ *
+ * The main motivation for this layer is to hide the fact that
+ * there are two very different implementations of the /proc API.
+ * Rather than have a bunch of #ifdefs all thru the gdb target vector
+ * functions, we do our best to hide them all in here.
+ */
+
+int proc_get_status (procinfo * pi);
+long proc_flags (procinfo * pi);
+int proc_why (procinfo * pi);
+int proc_what (procinfo * pi);
+int proc_set_run_on_last_close (procinfo * pi);
+int proc_unset_run_on_last_close (procinfo * pi);
+int proc_set_inherit_on_fork (procinfo * pi);
+int proc_unset_inherit_on_fork (procinfo * pi);
+int proc_set_async (procinfo * pi);
+int proc_unset_async (procinfo * pi);
+int proc_stop_process (procinfo * pi);
+int proc_trace_signal (procinfo * pi, int signo);
+int proc_ignore_signal (procinfo * pi, int signo);
+int proc_clear_current_fault (procinfo * pi);
+int proc_set_current_signal (procinfo * pi, int signo);
+int proc_clear_current_signal (procinfo * pi);
+int proc_set_gregs (procinfo * pi);
+int proc_set_fpregs (procinfo * pi);
+int proc_wait_for_stop (procinfo * pi);
+int proc_run_process (procinfo * pi, int step, int signo);
+int proc_kill (procinfo * pi, int signo);
+int proc_parent_pid (procinfo * pi);
+int proc_get_nthreads (procinfo * pi);
+int proc_get_current_thread (procinfo * pi);
+int proc_set_held_signals (procinfo * pi, gdb_sigset_t * sighold);
+int proc_set_traced_sysexit (procinfo * pi, sysset_t * sysset);
+int proc_set_traced_sysentry (procinfo * pi, sysset_t * sysset);
+int proc_set_traced_faults (procinfo * pi, fltset_t * fltset);
+int proc_set_traced_signals (procinfo * pi, gdb_sigset_t * sigset);
+
+int proc_update_threads (procinfo * pi);
+int proc_iterate_over_threads (procinfo * pi,
+ int (*func) (procinfo *, procinfo *, void *),
+ void *ptr);
+
+gdb_gregset_t *proc_get_gregs (procinfo * pi);
+gdb_fpregset_t *proc_get_fpregs (procinfo * pi);
+sysset_t *proc_get_traced_sysexit (procinfo * pi, sysset_t * save);
+sysset_t *proc_get_traced_sysentry (procinfo * pi, sysset_t * save);
+fltset_t *proc_get_traced_faults (procinfo * pi, fltset_t * save);
+gdb_sigset_t *proc_get_traced_signals (procinfo * pi, gdb_sigset_t * save);
+gdb_sigset_t *proc_get_held_signals (procinfo * pi, gdb_sigset_t * save);
+gdb_sigset_t *proc_get_pending_signals (procinfo * pi, gdb_sigset_t * save);
+gdb_sigaction_t *proc_get_signal_actions (procinfo * pi, gdb_sigaction_t *save);
+
+void proc_warn (procinfo * pi, char *func, int line);
+void proc_error (procinfo * pi, char *func, int line);
+
+void
+proc_warn (procinfo *pi, char *func, int line)
+{
+ sprintf (errmsg, "procfs: %s line %d, %s", func, line, pi->pathname);
+ print_sys_errmsg (errmsg, errno);
+}
+
+void
+proc_error (procinfo *pi, char *func, int line)
+{
+ sprintf (errmsg, "procfs: %s line %d, %s", func, line, pi->pathname);
+ perror_with_name (errmsg);
+}
+
+/*
+ * Function: proc_get_status
+ *
+ * Updates the status struct in the procinfo.
+ * There is a 'valid' flag, to let other functions know when
+ * this function needs to be called (so the status is only
+ * read when it is needed). The status file descriptor is
+ * also only opened when it is needed.
+ *
+ * Return: non-zero for success, zero for failure.
+ */
+
+int
+proc_get_status (procinfo *pi)
+{
+ /* Status file descriptor is opened "lazily" */
+ if (pi->status_fd == 0 &&
+ open_procinfo_files (pi, FD_STATUS) == 0)
+ {
+ pi->status_valid = 0;
+ return 0;
+ }
+
+#ifdef NEW_PROC_API
+ if (lseek (pi->status_fd, 0, SEEK_SET) < 0)
+ pi->status_valid = 0; /* fail */
+ else
+ {
+ /* Sigh... I have to read a different data structure,
+ depending on whether this is a main process or an LWP. */
+ if (pi->tid)
+ pi->status_valid = (read (pi->status_fd,
+ (char *) &pi->prstatus.pr_lwp,
+ sizeof (lwpstatus_t))
+ == sizeof (lwpstatus_t));
+ else
+ {
+ pi->status_valid = (read (pi->status_fd,
+ (char *) &pi->prstatus,
+ sizeof (gdb_prstatus_t))
+ == sizeof (gdb_prstatus_t));
+#if 0 /*def UNIXWARE*/
+ if (pi->status_valid &&
+ (pi->prstatus.pr_lwp.pr_flags & PR_ISTOP) &&
+ pi->prstatus.pr_lwp.pr_why == PR_REQUESTED)
+ /* Unixware peculiarity -- read the damn thing again! */
+ pi->status_valid = (read (pi->status_fd,
+ (char *) &pi->prstatus,
+ sizeof (gdb_prstatus_t))
+ == sizeof (gdb_prstatus_t));
+#endif /* UNIXWARE */
+ }
+ }
+#else /* ioctl method */
+#ifdef PIOCTSTATUS /* osf */
+ if (pi->tid == 0) /* main process */
+ {
+ /* Just read the danged status. Now isn't that simple? */
+ pi->status_valid =
+ (ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) >= 0);
+ }
+ else
+ {
+ int win;
+ struct {
+ long pr_count;
+ tid_t pr_error_thread;
+ struct prstatus status;
+ } thread_status;
+
+ thread_status.pr_count = 1;
+ thread_status.status.pr_tid = pi->tid;
+ win = (ioctl (pi->status_fd, PIOCTSTATUS, &thread_status) >= 0);
+ if (win)
+ {
+ memcpy (&pi->prstatus, &thread_status.status,
+ sizeof (pi->prstatus));
+ pi->status_valid = 1;
+ }
+ }
+#else
+ /* Just read the danged status. Now isn't that simple? */
+ pi->status_valid = (ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) >= 0);
+#endif
+#endif
+
+ if (pi->status_valid)
+ {
+ PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
+ proc_why (pi),
+ proc_what (pi),
+ proc_get_current_thread (pi));
+ }
+
+ /* The status struct includes general regs, so mark them valid too */
+ pi->gregs_valid = pi->status_valid;
+#ifdef NEW_PROC_API
+ /* In the read/write multiple-fd model,
+ the status struct includes the fp regs too, so mark them valid too */
+ pi->fpregs_valid = pi->status_valid;
+#endif
+ return pi->status_valid; /* True if success, false if failure. */
+}
+
+/*
+ * Function: proc_flags
+ *
+ * returns the process flags (pr_flags field).
+ */
+
+long
+proc_flags (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0; /* FIXME: not a good failure value (but what is?) */
+
+#ifdef NEW_PROC_API
+# ifdef UNIXWARE
+ /* UnixWare 7.1 puts process status flags, e.g. PR_ASYNC, in
+ pstatus_t and LWP status flags, e.g. PR_STOPPED, in lwpstatus_t.
+ The two sets of flags don't overlap. */
+ return pi->prstatus.pr_flags | pi->prstatus.pr_lwp.pr_flags;
+# else
+ return pi->prstatus.pr_lwp.pr_flags;
+# endif
+#else
+ return pi->prstatus.pr_flags;
+#endif
+}
+
+/*
+ * Function: proc_why
+ *
+ * returns the pr_why field (why the process stopped).
+ */
+
+int
+proc_why (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0; /* FIXME: not a good failure value (but what is?) */
+
+#ifdef NEW_PROC_API
+ return pi->prstatus.pr_lwp.pr_why;
+#else
+ return pi->prstatus.pr_why;
+#endif
+}
+
+/*
+ * Function: proc_what
+ *
+ * returns the pr_what field (details of why the process stopped).
+ */
+
+int
+proc_what (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0; /* FIXME: not a good failure value (but what is?) */
+
+#ifdef NEW_PROC_API
+ return pi->prstatus.pr_lwp.pr_what;
+#else
+ return pi->prstatus.pr_what;
+#endif
+}
+
+#ifndef PIOCSSPCACT /* The following is not supported on OSF. */
+/*
+ * Function: proc_nsysarg
+ *
+ * returns the pr_nsysarg field (number of args to the current syscall).
+ */
+
+int
+proc_nsysarg (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0;
+
+#ifdef NEW_PROC_API
+ return pi->prstatus.pr_lwp.pr_nsysarg;
+#else
+ return pi->prstatus.pr_nsysarg;
+#endif
+}
+
+/*
+ * Function: proc_sysargs
+ *
+ * returns the pr_sysarg field (pointer to the arguments of current syscall).
+ */
+
+long *
+proc_sysargs (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+#ifdef NEW_PROC_API
+ return (long *) &pi->prstatus.pr_lwp.pr_sysarg;
+#else
+ return (long *) &pi->prstatus.pr_sysarg;
+#endif
+}
+
+/*
+ * Function: proc_syscall
+ *
+ * returns the pr_syscall field (id of current syscall if we are in one).
+ */
+
+int
+proc_syscall (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0;
+
+#ifdef NEW_PROC_API
+ return pi->prstatus.pr_lwp.pr_syscall;
+#else
+ return pi->prstatus.pr_syscall;
+#endif
+}
+#endif /* PIOCSSPCACT */
+
+/*
+ * Function: proc_cursig:
+ *
+ * returns the pr_cursig field (current signal).
+ */
+
+long
+proc_cursig (struct procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0; /* FIXME: not a good failure value (but what is?) */
+
+#ifdef NEW_PROC_API
+ return pi->prstatus.pr_lwp.pr_cursig;
+#else
+ return pi->prstatus.pr_cursig;
+#endif
+}
+
+/*
+ * Function: proc_modify_flag
+ *
+ * === I appologize for the messiness of this function.
+ * === This is an area where the different versions of
+ * === /proc are more inconsistent than usual. MVS
+ *
+ * Set or reset any of the following process flags:
+ * PR_FORK -- forked child will inherit trace flags
+ * PR_RLC -- traced process runs when last /proc file closed.
+ * PR_KLC -- traced process is killed when last /proc file closed.
+ * PR_ASYNC -- LWP's get to run/stop independently.
+ *
+ * There are three methods for doing this function:
+ * 1) Newest: read/write [PCSET/PCRESET/PCUNSET]
+ * [Sol6, Sol7, UW]
+ * 2) Middle: PIOCSET/PIOCRESET
+ * [Irix, Sol5]
+ * 3) Oldest: PIOCSFORK/PIOCRFORK/PIOCSRLC/PIOCRRLC
+ * [OSF, Sol5]
+ *
+ * Note: Irix does not define PR_ASYNC.
+ * Note: OSF does not define PR_KLC.
+ * Note: OSF is the only one that can ONLY use the oldest method.
+ *
+ * Arguments:
+ * pi -- the procinfo
+ * flag -- one of PR_FORK, PR_RLC, or PR_ASYNC
+ * mode -- 1 for set, 0 for reset.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+enum { FLAG_RESET, FLAG_SET };
+
+static int
+proc_modify_flag (procinfo *pi, long flag, long mode)
+{
+ long win = 0; /* default to fail */
+
+ /*
+ * These operations affect the process as a whole, and applying
+ * them to an individual LWP has the same meaning as applying them
+ * to the main process. Therefore, if we're ever called with a
+ * pointer to an LWP's procinfo, let's substitute the process's
+ * procinfo and avoid opening the LWP's file descriptor
+ * unnecessarily.
+ */
+
+ if (pi->pid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API /* Newest method: UnixWare and newer Solarii */
+ /* First normalize the PCUNSET/PCRESET command opcode
+ (which for no obvious reason has a different definition
+ from one operating system to the next...) */
+#ifdef PCUNSET
+#define GDBRESET PCUNSET
+#else
+#ifdef PCRESET
+#define GDBRESET PCRESET
+#endif
+#endif
+ {
+ procfs_ctl_t arg[2];
+
+ if (mode == FLAG_SET) /* Set the flag (RLC, FORK, or ASYNC) */
+ arg[0] = PCSET;
+ else /* Reset the flag */
+ arg[0] = GDBRESET;
+
+ arg[1] = flag;
+ win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
+ }
+#else
+#ifdef PIOCSET /* Irix/Sol5 method */
+ if (mode == FLAG_SET) /* Set the flag (hopefully RLC, FORK, or ASYNC) */
+ {
+ win = (ioctl (pi->ctl_fd, PIOCSET, &flag) >= 0);
+ }
+ else /* Reset the flag */
+ {
+ win = (ioctl (pi->ctl_fd, PIOCRESET, &flag) >= 0);
+ }
+
+#else
+#ifdef PIOCSRLC /* Oldest method: OSF */
+ switch (flag) {
+ case PR_RLC:
+ if (mode == FLAG_SET) /* Set run-on-last-close */
+ {
+ win = (ioctl (pi->ctl_fd, PIOCSRLC, NULL) >= 0);
+ }
+ else /* Clear run-on-last-close */
+ {
+ win = (ioctl (pi->ctl_fd, PIOCRRLC, NULL) >= 0);
+ }
+ break;
+ case PR_FORK:
+ if (mode == FLAG_SET) /* Set inherit-on-fork */
+ {
+ win = (ioctl (pi->ctl_fd, PIOCSFORK, NULL) >= 0);
+ }
+ else /* Clear inherit-on-fork */
+ {
+ win = (ioctl (pi->ctl_fd, PIOCRFORK, NULL) >= 0);
+ }
+ break;
+ default:
+ win = 0; /* fail -- unknown flag (can't do PR_ASYNC) */
+ break;
+ }
+#endif
+#endif
+#endif
+#undef GDBRESET
+ /* The above operation renders the procinfo's cached pstatus obsolete. */
+ pi->status_valid = 0;
+
+ if (!win)
+ warning ("procfs: modify_flag failed to turn %s %s",
+ flag == PR_FORK ? "PR_FORK" :
+ flag == PR_RLC ? "PR_RLC" :
+#ifdef PR_ASYNC
+ flag == PR_ASYNC ? "PR_ASYNC" :
+#endif
+#ifdef PR_KLC
+ flag == PR_KLC ? "PR_KLC" :
+#endif
+ "<unknown flag>",
+ mode == FLAG_RESET ? "off" : "on");
+
+ return win;
+}
+
+/*
+ * Function: proc_set_run_on_last_close
+ *
+ * Set the run_on_last_close flag.
+ * Process with all threads will become runnable
+ * when debugger closes all /proc fds.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_run_on_last_close (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_RLC, FLAG_SET);
+}
+
+/*
+ * Function: proc_unset_run_on_last_close
+ *
+ * Reset the run_on_last_close flag.
+ * Process will NOT become runnable
+ * when debugger closes its file handles.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_unset_run_on_last_close (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_RLC, FLAG_RESET);
+}
+
+#ifdef PR_KLC
+/*
+ * Function: proc_set_kill_on_last_close
+ *
+ * Set the kill_on_last_close flag.
+ * Process with all threads will be killed when debugger
+ * closes all /proc fds (or debugger exits or dies).
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_kill_on_last_close (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_KLC, FLAG_SET);
+}
+
+/*
+ * Function: proc_unset_kill_on_last_close
+ *
+ * Reset the kill_on_last_close flag.
+ * Process will NOT be killed when debugger
+ * closes its file handles (or exits or dies).
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_unset_kill_on_last_close (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_KLC, FLAG_RESET);
+}
+#endif /* PR_KLC */
+
+/*
+ * Function: proc_set_inherit_on_fork
+ *
+ * Set inherit_on_fork flag.
+ * If the process forks a child while we are registered for events
+ * in the parent, then we will also recieve events from the child.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_inherit_on_fork (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_FORK, FLAG_SET);
+}
+
+/*
+ * Function: proc_unset_inherit_on_fork
+ *
+ * Reset inherit_on_fork flag.
+ * If the process forks a child while we are registered for events
+ * in the parent, then we will NOT recieve events from the child.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_unset_inherit_on_fork (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_FORK, FLAG_RESET);
+}
+
+#ifdef PR_ASYNC
+/*
+ * Function: proc_set_async
+ *
+ * Set PR_ASYNC flag.
+ * If one LWP stops because of a debug event (signal etc.),
+ * the remaining LWPs will continue to run.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_async (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_ASYNC, FLAG_SET);
+}
+
+/*
+ * Function: proc_unset_async
+ *
+ * Reset PR_ASYNC flag.
+ * If one LWP stops because of a debug event (signal etc.),
+ * then all other LWPs will stop as well.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_unset_async (procinfo *pi)
+{
+ return proc_modify_flag (pi, PR_ASYNC, FLAG_RESET);
+}
+#endif /* PR_ASYNC */
+
+/*
+ * Function: proc_stop_process
+ *
+ * Request the process/LWP to stop. Does not wait.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_stop_process (procinfo *pi)
+{
+ int win;
+
+ /*
+ * We might conceivably apply this operation to an LWP, and
+ * the LWP's ctl file descriptor might not be open.
+ */
+
+ if (pi->ctl_fd == 0 &&
+ open_procinfo_files (pi, FD_CTL) == 0)
+ return 0;
+ else
+ {
+#ifdef NEW_PROC_API
+ procfs_ctl_t cmd = PCSTOP;
+ win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
+#else /* ioctl method */
+ win = (ioctl (pi->ctl_fd, PIOCSTOP, &pi->prstatus) >= 0);
+ /* Note: the call also reads the prstatus. */
+ if (win)
+ {
+ pi->status_valid = 1;
+ PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
+ proc_why (pi),
+ proc_what (pi),
+ proc_get_current_thread (pi));
+ }
+#endif
+ }
+
+ return win;
+}
+
+/*
+ * Function: proc_wait_for_stop
+ *
+ * Wait for the process or LWP to stop (block until it does).
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_wait_for_stop (procinfo *pi)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ procfs_ctl_t cmd = PCWSTOP;
+ win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
+ /* We been runnin' and we stopped -- need to update status. */
+ pi->status_valid = 0;
+ }
+#else /* ioctl method */
+ win = (ioctl (pi->ctl_fd, PIOCWSTOP, &pi->prstatus) >= 0);
+ /* Above call also refreshes the prstatus. */
+ if (win)
+ {
+ pi->status_valid = 1;
+ PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
+ proc_why (pi),
+ proc_what (pi),
+ proc_get_current_thread (pi));
+ }
+#endif
+
+ return win;
+}
+
+/*
+ * Function: proc_run_process
+ *
+ * Make the process or LWP runnable.
+ * Options (not all are implemented):
+ * - single-step
+ * - clear current fault
+ * - clear current signal
+ * - abort the current system call
+ * - stop as soon as finished with system call
+ * - (ioctl): set traced signal set
+ * - (ioctl): set held signal set
+ * - (ioctl): set traced fault set
+ * - (ioctl): set start pc (vaddr)
+ * Always clear the current fault.
+ * Clear the current signal if 'signo' is zero.
+ *
+ * Arguments:
+ * pi the process or LWP to operate on.
+ * step if true, set the process or LWP to trap after one instr.
+ * signo if zero, clear the current signal if any.
+ * if non-zero, set the current signal to this one.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_run_process (procinfo *pi, int step, int signo)
+{
+ int win;
+ int runflags;
+
+ /*
+ * We will probably have to apply this operation to individual threads,
+ * so make sure the control file descriptor is open.
+ */
+
+ if (pi->ctl_fd == 0 &&
+ open_procinfo_files (pi, FD_CTL) == 0)
+ {
+ return 0;
+ }
+
+ runflags = PRCFAULT; /* always clear current fault */
+ if (step)
+ runflags |= PRSTEP;
+ if (signo == 0)
+ runflags |= PRCSIG;
+ else if (signo != -1) /* -1 means do nothing W.R.T. signals */
+ proc_set_current_signal (pi, signo);
+
+#ifdef NEW_PROC_API
+ {
+ procfs_ctl_t cmd[2];
+
+ cmd[0] = PCRUN;
+ cmd[1] = runflags;
+ win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
+ }
+#else /* ioctl method */
+ {
+ prrun_t prrun;
+
+ memset (&prrun, 0, sizeof (prrun));
+ prrun.pr_flags = runflags;
+ win = (ioctl (pi->ctl_fd, PIOCRUN, &prrun) >= 0);
+ }
+#endif
+
+ return win;
+}
+
+/*
+ * Function: proc_set_traced_signals
+ *
+ * Register to trace signals in the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_traced_signals (procinfo *pi, gdb_sigset_t *sigset)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ struct {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char sigset[sizeof (gdb_sigset_t)];
+ } arg;
+
+ arg.cmd = PCSTRACE;
+ memcpy (&arg.sigset, sigset, sizeof (gdb_sigset_t));
+
+ win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
+ }
+#else /* ioctl method */
+ win = (ioctl (pi->ctl_fd, PIOCSTRACE, sigset) >= 0);
+#endif
+ /* The above operation renders the procinfo's cached pstatus obsolete. */
+ pi->status_valid = 0;
+
+ if (!win)
+ warning ("procfs: set_traced_signals failed");
+ return win;
+}
+
+/*
+ * Function: proc_set_traced_faults
+ *
+ * Register to trace hardware faults in the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_traced_faults (procinfo *pi, fltset_t *fltset)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ struct {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char fltset[sizeof (fltset_t)];
+ } arg;
+
+ arg.cmd = PCSFAULT;
+ memcpy (&arg.fltset, fltset, sizeof (fltset_t));
+
+ win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
+ }
+#else /* ioctl method */
+ win = (ioctl (pi->ctl_fd, PIOCSFAULT, fltset) >= 0);
+#endif
+ /* The above operation renders the procinfo's cached pstatus obsolete. */
+ pi->status_valid = 0;
+
+ return win;
+}
+
+/*
+ * Function: proc_set_traced_sysentry
+ *
+ * Register to trace entry to system calls in the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_traced_sysentry (procinfo *pi, sysset_t *sysset)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ struct gdb_proc_ctl_pcsentry {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char sysset[sizeof (sysset_t)];
+ } *argp;
+ int argp_size = sizeof (struct gdb_proc_ctl_pcsentry)
+ - sizeof (sysset_t)
+ + sysset_t_size (pi);
+
+ argp = xmalloc (argp_size);
+
+ argp->cmd = PCSENTRY;
+ memcpy (&argp->sysset, sysset, sysset_t_size (pi));
+
+ win = (write (pi->ctl_fd, (char *) argp, argp_size) == argp_size);
+ xfree (argp);
+ }
+#else /* ioctl method */
+ win = (ioctl (pi->ctl_fd, PIOCSENTRY, sysset) >= 0);
+#endif
+ /* The above operation renders the procinfo's cached pstatus obsolete. */
+ pi->status_valid = 0;
+
+ return win;
+}
+
+/*
+ * Function: proc_set_traced_sysexit
+ *
+ * Register to trace exit from system calls in the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_traced_sysexit (procinfo *pi, sysset_t *sysset)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ struct gdb_proc_ctl_pcsexit {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char sysset[sizeof (sysset_t)];
+ } *argp;
+ int argp_size = sizeof (struct gdb_proc_ctl_pcsexit)
+ - sizeof (sysset_t)
+ + sysset_t_size (pi);
+
+ argp = xmalloc (argp_size);
+
+ argp->cmd = PCSEXIT;
+ memcpy (&argp->sysset, sysset, sysset_t_size (pi));
+
+ win = (write (pi->ctl_fd, (char *) argp, argp_size) == argp_size);
+ xfree (argp);
+ }
+#else /* ioctl method */
+ win = (ioctl (pi->ctl_fd, PIOCSEXIT, sysset) >= 0);
+#endif
+ /* The above operation renders the procinfo's cached pstatus obsolete. */
+ pi->status_valid = 0;
+
+ return win;
+}
+
+/*
+ * Function: proc_set_held_signals
+ *
+ * Specify the set of blocked / held signals in the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_held_signals (procinfo *pi, gdb_sigset_t *sighold)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ struct {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char hold[sizeof (gdb_sigset_t)];
+ } arg;
+
+ arg.cmd = PCSHOLD;
+ memcpy (&arg.hold, sighold, sizeof (gdb_sigset_t));
+ win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
+ }
+#else
+ win = (ioctl (pi->ctl_fd, PIOCSHOLD, sighold) >= 0);
+#endif
+ /* The above operation renders the procinfo's cached pstatus obsolete. */
+ pi->status_valid = 0;
+
+ return win;
+}
+
+/*
+ * Function: proc_get_pending_signals
+ *
+ * returns the set of signals that are pending in the process or LWP.
+ * Will also copy the sigset if 'save' is non-zero.
+ */
+
+gdb_sigset_t *
+proc_get_pending_signals (procinfo *pi, gdb_sigset_t *save)
+{
+ gdb_sigset_t *ret = NULL;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+#ifdef NEW_PROC_API
+ ret = &pi->prstatus.pr_lwp.pr_lwppend;
+#else
+ ret = &pi->prstatus.pr_sigpend;
+#endif
+ if (save && ret)
+ memcpy (save, ret, sizeof (gdb_sigset_t));
+
+ return ret;
+}
+
+/*
+ * Function: proc_get_signal_actions
+ *
+ * returns the set of signal actions.
+ * Will also copy the sigactionset if 'save' is non-zero.
+ */
+
+gdb_sigaction_t *
+proc_get_signal_actions (procinfo *pi, gdb_sigaction_t *save)
+{
+ gdb_sigaction_t *ret = NULL;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+#ifdef NEW_PROC_API
+ ret = &pi->prstatus.pr_lwp.pr_action;
+#else
+ ret = &pi->prstatus.pr_action;
+#endif
+ if (save && ret)
+ memcpy (save, ret, sizeof (gdb_sigaction_t));
+
+ return ret;
+}
+
+/*
+ * Function: proc_get_held_signals
+ *
+ * returns the set of signals that are held / blocked.
+ * Will also copy the sigset if 'save' is non-zero.
+ */
+
+gdb_sigset_t *
+proc_get_held_signals (procinfo *pi, gdb_sigset_t *save)
+{
+ gdb_sigset_t *ret = NULL;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+#ifdef UNIXWARE
+ ret = &pi->prstatus.pr_lwp.pr_context.uc_sigmask;
+#else
+ ret = &pi->prstatus.pr_lwp.pr_lwphold;
+#endif /* UNIXWARE */
+#else /* not NEW_PROC_API */
+ {
+ static gdb_sigset_t sigheld;
+
+ if (ioctl (pi->ctl_fd, PIOCGHOLD, &sigheld) >= 0)
+ ret = &sigheld;
+ }
+#endif /* NEW_PROC_API */
+ if (save && ret)
+ memcpy (save, ret, sizeof (gdb_sigset_t));
+
+ return ret;
+}
+
+/*
+ * Function: proc_get_traced_signals
+ *
+ * returns the set of signals that are traced / debugged.
+ * Will also copy the sigset if 'save' is non-zero.
+ */
+
+gdb_sigset_t *
+proc_get_traced_signals (procinfo *pi, gdb_sigset_t *save)
+{
+ gdb_sigset_t *ret = NULL;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+ ret = &pi->prstatus.pr_sigtrace;
+#else
+ {
+ static gdb_sigset_t sigtrace;
+
+ if (ioctl (pi->ctl_fd, PIOCGTRACE, &sigtrace) >= 0)
+ ret = &sigtrace;
+ }
+#endif
+ if (save && ret)
+ memcpy (save, ret, sizeof (gdb_sigset_t));
+
+ return ret;
+}
+
+/*
+ * Function: proc_trace_signal
+ *
+ * Add 'signo' to the set of signals that are traced.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_trace_signal (procinfo *pi, int signo)
+{
+ gdb_sigset_t temp;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ if (pi)
+ {
+ if (proc_get_traced_signals (pi, &temp))
+ {
+ praddset (&temp, signo);
+ return proc_set_traced_signals (pi, &temp);
+ }
+ }
+
+ return 0; /* failure */
+}
+
+/*
+ * Function: proc_ignore_signal
+ *
+ * Remove 'signo' from the set of signals that are traced.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_ignore_signal (procinfo *pi, int signo)
+{
+ gdb_sigset_t temp;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ if (pi)
+ {
+ if (proc_get_traced_signals (pi, &temp))
+ {
+ prdelset (&temp, signo);
+ return proc_set_traced_signals (pi, &temp);
+ }
+ }
+
+ return 0; /* failure */
+}
+
+/*
+ * Function: proc_get_traced_faults
+ *
+ * returns the set of hardware faults that are traced /debugged.
+ * Will also copy the faultset if 'save' is non-zero.
+ */
+
+fltset_t *
+proc_get_traced_faults (procinfo *pi, fltset_t *save)
+{
+ fltset_t *ret = NULL;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+ ret = &pi->prstatus.pr_flttrace;
+#else
+ {
+ static fltset_t flttrace;
+
+ if (ioctl (pi->ctl_fd, PIOCGFAULT, &flttrace) >= 0)
+ ret = &flttrace;
+ }
+#endif
+ if (save && ret)
+ memcpy (save, ret, sizeof (fltset_t));
+
+ return ret;
+}
+
+/*
+ * Function: proc_get_traced_sysentry
+ *
+ * returns the set of syscalls that are traced /debugged on entry.
+ * Will also copy the syscall set if 'save' is non-zero.
+ */
+
+sysset_t *
+proc_get_traced_sysentry (procinfo *pi, sysset_t *save)
+{
+ sysset_t *ret = NULL;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+#ifndef DYNAMIC_SYSCALLS
+ ret = &pi->prstatus.pr_sysentry;
+#else /* DYNAMIC_SYSCALLS */
+ {
+ static sysset_t *sysentry;
+ size_t size;
+
+ if (!sysentry)
+ sysentry = sysset_t_alloc (pi);
+ ret = sysentry;
+ if (pi->status_fd == 0 && open_procinfo_files (pi, FD_STATUS) == 0)
+ return NULL;
+ if (pi->prstatus.pr_sysentry_offset == 0)
+ {
+ gdb_premptysysset (sysentry);
+ }
+ else
+ {
+ int rsize;
+
+ if (lseek (pi->status_fd, (off_t) pi->prstatus.pr_sysentry_offset,
+ SEEK_SET)
+ != (off_t) pi->prstatus.pr_sysentry_offset)
+ return NULL;
+ size = sysset_t_size (pi);
+ gdb_premptysysset (sysentry);
+ rsize = read (pi->status_fd, sysentry, size);
+ if (rsize < 0)
+ return NULL;
+ }
+ }
+#endif /* DYNAMIC_SYSCALLS */
+#else /* !NEW_PROC_API */
+ {
+ static sysset_t sysentry;
+
+ if (ioctl (pi->ctl_fd, PIOCGENTRY, &sysentry) >= 0)
+ ret = &sysentry;
+ }
+#endif /* NEW_PROC_API */
+ if (save && ret)
+ memcpy (save, ret, sysset_t_size (pi));
+
+ return ret;
+}
+
+/*
+ * Function: proc_get_traced_sysexit
+ *
+ * returns the set of syscalls that are traced /debugged on exit.
+ * Will also copy the syscall set if 'save' is non-zero.
+ */
+
+sysset_t *
+proc_get_traced_sysexit (procinfo *pi, sysset_t *save)
+{
+ sysset_t * ret = NULL;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+#ifndef DYNAMIC_SYSCALLS
+ ret = &pi->prstatus.pr_sysexit;
+#else /* DYNAMIC_SYSCALLS */
+ {
+ static sysset_t *sysexit;
+ size_t size;
+
+ if (!sysexit)
+ sysexit = sysset_t_alloc (pi);
+ ret = sysexit;
+ if (pi->status_fd == 0 && open_procinfo_files (pi, FD_STATUS) == 0)
+ return NULL;
+ if (pi->prstatus.pr_sysexit_offset == 0)
+ {
+ gdb_premptysysset (sysexit);
+ }
+ else
+ {
+ int rsize;
+
+ if (lseek (pi->status_fd, (off_t) pi->prstatus.pr_sysexit_offset, SEEK_SET)
+ != (off_t) pi->prstatus.pr_sysexit_offset)
+ return NULL;
+ size = sysset_t_size (pi);
+ gdb_premptysysset (sysexit);
+ rsize = read (pi->status_fd, sysexit, size);
+ if (rsize < 0)
+ return NULL;
+ }
+ }
+#endif /* DYNAMIC_SYSCALLS */
+#else
+ {
+ static sysset_t sysexit;
+
+ if (ioctl (pi->ctl_fd, PIOCGEXIT, &sysexit) >= 0)
+ ret = &sysexit;
+ }
+#endif
+ if (save && ret)
+ memcpy (save, ret, sysset_t_size (pi));
+
+ return ret;
+}
+
+/*
+ * Function: proc_clear_current_fault
+ *
+ * The current fault (if any) is cleared; the associated signal
+ * will not be sent to the process or LWP when it resumes.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_clear_current_fault (procinfo *pi)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ procfs_ctl_t cmd = PCCFAULT;
+ win = (write (pi->ctl_fd, (void *) &cmd, sizeof (cmd)) == sizeof (cmd));
+ }
+#else
+ win = (ioctl (pi->ctl_fd, PIOCCFAULT, 0) >= 0);
+#endif
+
+ return win;
+}
+
+/*
+ * Function: proc_set_current_signal
+ *
+ * Set the "current signal" that will be delivered next to the process.
+ * NOTE: semantics are different from those of KILL.
+ * This signal will be delivered to the process or LWP
+ * immediately when it is resumed (even if the signal is held/blocked);
+ * it will NOT immediately cause another event of interest, and will NOT
+ * first trap back to the debugger.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_current_signal (procinfo *pi, int signo)
+{
+ int win;
+ struct {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char sinfo[sizeof (gdb_siginfo_t)];
+ } arg;
+ gdb_siginfo_t *mysinfo;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#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 > 0 &&
+ signo == proc_cursig (pi))
+ return 1; /* I assume this is a success? */
+#endif
+
+ /* The pointer is just a type alias. */
+ mysinfo = (gdb_siginfo_t *) &arg.sinfo;
+ mysinfo->si_signo = signo;
+ mysinfo->si_code = 0;
+ mysinfo->si_pid = getpid (); /* ?why? */
+ mysinfo->si_uid = getuid (); /* ?why? */
+
+#ifdef NEW_PROC_API
+ arg.cmd = PCSSIG;
+ win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
+#else
+ win = (ioctl (pi->ctl_fd, PIOCSSIG, (void *) &arg.sinfo) >= 0);
+#endif
+
+ return win;
+}
+
+/*
+ * Function: proc_clear_current_signal
+ *
+ * The current signal (if any) is cleared, and
+ * is not sent to the process or LWP when it resumes.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_clear_current_signal (procinfo *pi)
+{
+ int win;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+#ifdef NEW_PROC_API
+ {
+ struct {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char sinfo[sizeof (gdb_siginfo_t)];
+ } arg;
+ gdb_siginfo_t *mysinfo;
+
+ arg.cmd = PCSSIG;
+ /* The pointer is just a type alias. */
+ mysinfo = (gdb_siginfo_t *) &arg.sinfo;
+ mysinfo->si_signo = 0;
+ mysinfo->si_code = 0;
+ mysinfo->si_errno = 0;
+ mysinfo->si_pid = getpid (); /* ?why? */
+ mysinfo->si_uid = getuid (); /* ?why? */
+
+ win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
+ }
+#else
+ win = (ioctl (pi->ctl_fd, PIOCSSIG, 0) >= 0);
+#endif
+
+ return win;
+}
+
+/*
+ * Function: proc_get_gregs
+ *
+ * Get the general registers for the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+gdb_gregset_t *
+proc_get_gregs (procinfo *pi)
+{
+ if (!pi->status_valid || !pi->gregs_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+ /*
+ * OK, sorry about the ifdef's.
+ * There's three cases instead of two, because
+ * in this instance Unixware and Solaris/RW differ.
+ */
+
+#ifdef NEW_PROC_API
+#ifdef UNIXWARE /* ugh, a true architecture dependency */
+ return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs;
+#else /* not Unixware */
+ return &pi->prstatus.pr_lwp.pr_reg;
+#endif /* Unixware */
+#else /* not NEW_PROC_API */
+ return &pi->prstatus.pr_reg;
+#endif /* NEW_PROC_API */
+}
+
+/*
+ * Function: proc_get_fpregs
+ *
+ * Get the floating point registers for the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+gdb_fpregset_t *
+proc_get_fpregs (procinfo *pi)
+{
+#ifdef NEW_PROC_API
+ if (!pi->status_valid || !pi->fpregs_valid)
+ if (!proc_get_status (pi))
+ return NULL;
+
+#ifdef UNIXWARE /* a true architecture dependency */
+ return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs;
+#else
+ return &pi->prstatus.pr_lwp.pr_fpreg;
+#endif /* Unixware */
+
+#else /* not NEW_PROC_API */
+ if (pi->fpregs_valid)
+ return &pi->fpregset; /* already got 'em */
+ else
+ {
+ if (pi->ctl_fd == 0 &&
+ open_procinfo_files (pi, FD_CTL) == 0)
+ {
+ return NULL;
+ }
+ else
+ {
+#ifdef PIOCTGFPREG
+ struct {
+ long pr_count;
+ tid_t pr_error_thread;
+ tfpregset_t thread_1;
+ } thread_fpregs;
+
+ thread_fpregs.pr_count = 1;
+ thread_fpregs.thread_1.tid = pi->tid;
+
+ if (pi->tid == 0 &&
+ ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0)
+ {
+ pi->fpregs_valid = 1;
+ return &pi->fpregset; /* got 'em now! */
+ }
+ else if (pi->tid != 0 &&
+ ioctl (pi->ctl_fd, PIOCTGFPREG, &thread_fpregs) >= 0)
+ {
+ memcpy (&pi->fpregset, &thread_fpregs.thread_1.pr_fpregs,
+ sizeof (pi->fpregset));
+ pi->fpregs_valid = 1;
+ return &pi->fpregset; /* got 'em now! */
+ }
+ else
+ {
+ return NULL;
+ }
+#else
+ if (ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0)
+ {
+ pi->fpregs_valid = 1;
+ return &pi->fpregset; /* got 'em now! */
+ }
+ else
+ {
+ return NULL;
+ }
+#endif
+ }
+ }
+#endif
+}
+
+/*
+ * Function: proc_set_gregs
+ *
+ * Write the general registers back to the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_gregs (procinfo *pi)
+{
+ gdb_gregset_t *gregs;
+ int win;
+
+ if ((gregs = proc_get_gregs (pi)) == NULL)
+ return 0; /* get_regs has already warned */
+
+ if (pi->ctl_fd == 0 &&
+ open_procinfo_files (pi, FD_CTL) == 0)
+ {
+ return 0;
+ }
+ else
+ {
+#ifdef NEW_PROC_API
+ struct {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char gregs[sizeof (gdb_gregset_t)];
+ } arg;
+
+ arg.cmd = PCSREG;
+ memcpy (&arg.gregs, gregs, sizeof (arg.gregs));
+ win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
+#else
+ win = (ioctl (pi->ctl_fd, PIOCSREG, gregs) >= 0);
+#endif
+ }
+
+ /* Policy: writing the regs invalidates our cache. */
+ pi->gregs_valid = 0;
+ return win;
+}
+
+/*
+ * Function: proc_set_fpregs
+ *
+ * Modify the floating point register set of the process or LWP.
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_set_fpregs (procinfo *pi)
+{
+ gdb_fpregset_t *fpregs;
+ int win;
+
+ if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ return 0; /* get_fpregs has already warned */
+
+ if (pi->ctl_fd == 0 &&
+ open_procinfo_files (pi, FD_CTL) == 0)
+ {
+ return 0;
+ }
+ else
+ {
+#ifdef NEW_PROC_API
+ struct {
+ procfs_ctl_t cmd;
+ /* Use char array to avoid alignment issues. */
+ char fpregs[sizeof (gdb_fpregset_t)];
+ } arg;
+
+ arg.cmd = PCSFPREG;
+ memcpy (&arg.fpregs, fpregs, sizeof (arg.fpregs));
+ win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
+#else
+#ifdef PIOCTSFPREG
+ if (pi->tid == 0)
+ win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0);
+ else
+ {
+ struct {
+ long pr_count;
+ tid_t pr_error_thread;
+ tfpregset_t thread_1;
+ } thread_fpregs;
+
+ thread_fpregs.pr_count = 1;
+ thread_fpregs.thread_1.tid = pi->tid;
+ memcpy (&thread_fpregs.thread_1.pr_fpregs, fpregs,
+ sizeof (*fpregs));
+ win = (ioctl (pi->ctl_fd, PIOCTSFPREG, &thread_fpregs) >= 0);
+ }
+#else
+ win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0);
+#endif /* osf PIOCTSFPREG */
+#endif /* NEW_PROC_API */
+ }
+
+ /* Policy: writing the regs invalidates our cache. */
+ pi->fpregs_valid = 0;
+ return win;
+}
+
+/*
+ * Function: proc_kill
+ *
+ * Send a signal to the proc or lwp with the semantics of "kill()".
+ * Returns non-zero for success, zero for failure.
+ */
+
+int
+proc_kill (procinfo *pi, int signo)
+{
+ int win;
+
+ /*
+ * We might conceivably apply this operation to an LWP, and
+ * the LWP's ctl file descriptor might not be open.
+ */
+
+ if (pi->ctl_fd == 0 &&
+ open_procinfo_files (pi, FD_CTL) == 0)
+ {
+ return 0;
+ }
+ else
+ {
+#ifdef NEW_PROC_API
+ procfs_ctl_t cmd[2];
+
+ cmd[0] = PCKILL;
+ cmd[1] = signo;
+ win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
+#else /* ioctl method */
+ /* FIXME: do I need the Alpha OSF fixups present in
+ procfs.c/unconditionally_kill_inferior? Perhaps only for SIGKILL? */
+ win = (ioctl (pi->ctl_fd, PIOCKILL, &signo) >= 0);
+#endif
+ }
+
+ return win;
+}
+
+/*
+ * Function: proc_parent_pid
+ *
+ * Find the pid of the process that started this one.
+ * Returns the parent process pid, or zero.
+ */
+
+int
+proc_parent_pid (procinfo *pi)
+{
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0;
+
+ return pi->prstatus.pr_ppid;
+}
+
+
+/* Convert a target address (a.k.a. CORE_ADDR) into a host address
+ (a.k.a void pointer)! */
+
+static void *
+procfs_address_to_host_pointer (CORE_ADDR addr)
+{
+ void *ptr;
+
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
+ return ptr;
+}
+
+/*
+ * Function: proc_set_watchpoint
+ *
+ */
+
+int
+proc_set_watchpoint (procinfo *pi, CORE_ADDR addr, int len, int wflags)
+{
+#if !defined (TARGET_HAS_HARDWARE_WATCHPOINTS)
+ return 0;
+#else
+/* Horrible hack! Detect Solaris 2.5, because this doesn't work on 2.5 */
+#if defined (PIOCOPENLWP) || defined (UNIXWARE) /* Solaris 2.5: bail out */
+ return 0;
+#else
+ struct {
+ procfs_ctl_t cmd;
+ char watch[sizeof (prwatch_t)];
+ } arg;
+ prwatch_t *pwatch;
+
+ pwatch = (prwatch_t *) &arg.watch;
+ /* NOTE: cagney/2003-02-01: Even more horrible hack. Need to
+ convert a target address into something that can be stored in a
+ native data structure. */
+#ifdef PCAGENT /* Horrible hack: only defined on Solaris 2.6+ */
+ pwatch->pr_vaddr = (uintptr_t) procfs_address_to_host_pointer (addr);
+#else
+ pwatch->pr_vaddr = (caddr_t) procfs_address_to_host_pointer (addr);
+#endif
+ pwatch->pr_size = len;
+ pwatch->pr_wflags = wflags;
+#if defined(NEW_PROC_API) && defined (PCWATCH)
+ arg.cmd = PCWATCH;
+ return (write (pi->ctl_fd, &arg, sizeof (arg)) == sizeof (arg));
+#else
+#if defined (PIOCSWATCH)
+ return (ioctl (pi->ctl_fd, PIOCSWATCH, pwatch) >= 0);
+#else
+ return 0; /* Fail */
+#endif
+#endif
+#endif
+#endif
+}
+
+#ifdef TM_I386SOL2_H /* Is it hokey to use this? */
+
+#include <sys/sysi86.h>
+
+/*
+ * Function: proc_get_LDT_entry
+ *
+ * Inputs:
+ * procinfo *pi;
+ * int key;
+ *
+ * The 'key' is actually the value of the lower 16 bits of
+ * the GS register for the LWP that we're interested in.
+ *
+ * Return: matching ssh struct (LDT entry).
+ */
+
+struct ssd *
+proc_get_LDT_entry (procinfo *pi, int key)
+{
+ static struct ssd *ldt_entry = NULL;
+#ifdef NEW_PROC_API
+ char pathname[MAX_PROC_NAME_SIZE];
+ struct cleanup *old_chain = NULL;
+ int fd;
+
+ /* Allocate space for one LDT entry.
+ This alloc must persist, because we return a pointer to it. */
+ if (ldt_entry == NULL)
+ ldt_entry = (struct ssd *) xmalloc (sizeof (struct ssd));
+
+ /* Open the file descriptor for the LDT table. */
+ sprintf (pathname, "/proc/%d/ldt", pi->pid);
+ if ((fd = open_with_retry (pathname, O_RDONLY)) < 0)
+ {
+ proc_warn (pi, "proc_get_LDT_entry (open)", __LINE__);
+ return NULL;
+ }
+ /* Make sure it gets closed again! */
+ old_chain = make_cleanup_close (fd);
+
+ /* Now 'read' thru the table, find a match and return it. */
+ while (read (fd, ldt_entry, sizeof (struct ssd)) == sizeof (struct ssd))
+ {
+ if (ldt_entry->sel == 0 &&
+ ldt_entry->bo == 0 &&
+ ldt_entry->acc1 == 0 &&
+ ldt_entry->acc2 == 0)
+ break; /* end of table */
+ /* If key matches, return this entry. */
+ if (ldt_entry->sel == key)
+ return ldt_entry;
+ }
+ /* Loop ended, match not found. */
+ return NULL;
+#else
+ int nldt, i;
+ static int nalloc = 0;
+
+ /* Get the number of LDT entries. */
+ if (ioctl (pi->ctl_fd, PIOCNLDT, &nldt) < 0)
+ {
+ proc_warn (pi, "proc_get_LDT_entry (PIOCNLDT)", __LINE__);
+ return NULL;
+ }
+
+ /* Allocate space for the number of LDT entries. */
+ /* This alloc has to persist, 'cause we return a pointer to it. */
+ if (nldt > nalloc)
+ {
+ ldt_entry = (struct ssd *)
+ xrealloc (ldt_entry, (nldt + 1) * sizeof (struct ssd));
+ nalloc = nldt;
+ }
+
+ /* Read the whole table in one gulp. */
+ if (ioctl (pi->ctl_fd, PIOCLDT, ldt_entry) < 0)
+ {
+ proc_warn (pi, "proc_get_LDT_entry (PIOCLDT)", __LINE__);
+ return NULL;
+ }
+
+ /* Search the table and return the (first) entry matching 'key'. */
+ for (i = 0; i < nldt; i++)
+ if (ldt_entry[i].sel == key)
+ return &ldt_entry[i];
+
+ /* Loop ended, match not found. */
+ return NULL;
+#endif
+}
+
+#endif /* TM_I386SOL2_H */
+
+/* =============== END, non-thread part of /proc "MODULE" =============== */
+
+/* =================== Thread "MODULE" =================== */
+
+/* NOTE: you'll see more ifdefs and duplication of functions here,
+ since there is a different way to do threads on every OS. */
+
+/*
+ * Function: proc_get_nthreads
+ *
+ * Return the number of threads for the process
+ */
+
+#if defined (PIOCNTHR) && defined (PIOCTLIST)
+/*
+ * OSF version
+ */
+int
+proc_get_nthreads (procinfo *pi)
+{
+ int nthreads = 0;
+
+ if (ioctl (pi->ctl_fd, PIOCNTHR, &nthreads) < 0)
+ proc_warn (pi, "procfs: PIOCNTHR failed", __LINE__);
+
+ return nthreads;
+}
+
+#else
+#if defined (SYS_lwpcreate) || defined (SYS_lwp_create) /* FIXME: multiple */
+/*
+ * Solaris and Unixware version
+ */
+int
+proc_get_nthreads (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0;
+
+ /*
+ * NEW_PROC_API: only works for the process procinfo,
+ * because the LWP procinfos do not get prstatus filled in.
+ */
+#ifdef NEW_PROC_API
+ if (pi->tid != 0) /* find the parent process procinfo */
+ pi = find_procinfo_or_die (pi->pid, 0);
+#endif
+ return pi->prstatus.pr_nlwp;
+}
+
+#else
+/*
+ * Default version
+ */
+int
+proc_get_nthreads (procinfo *pi)
+{
+ return 0;
+}
+#endif
+#endif
+
+/*
+ * Function: proc_get_current_thread (LWP version)
+ *
+ * Return the ID of the thread that had an event of interest.
+ * (ie. the one that hit a breakpoint or other traced event).
+ * All other things being equal, this should be the ID of a
+ * thread that is currently executing.
+ */
+
+#if defined (SYS_lwpcreate) || defined (SYS_lwp_create) /* FIXME: multiple */
+/*
+ * Solaris and Unixware version
+ */
+int
+proc_get_current_thread (procinfo *pi)
+{
+ /*
+ * Note: this should be applied to the root procinfo for the process,
+ * not to the procinfo for an LWP. If applied to the procinfo for
+ * an LWP, it will simply return that LWP's ID. In that case,
+ * find the parent process procinfo.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0;
+
+#ifdef NEW_PROC_API
+ return pi->prstatus.pr_lwp.pr_lwpid;
+#else
+ return pi->prstatus.pr_who;
+#endif
+}
+
+#else
+#if defined (PIOCNTHR) && defined (PIOCTLIST)
+/*
+ * OSF version
+ */
+int
+proc_get_current_thread (procinfo *pi)
+{
+#if 0 /* FIXME: not ready for prime time? */
+ return pi->prstatus.pr_tid;
+#else
+ return 0;
+#endif
+}
+
+#else
+/*
+ * Default version
+ */
+int
+proc_get_current_thread (procinfo *pi)
+{
+ return 0;
+}
+
+#endif
+#endif
+
+/*
+ * Function: proc_update_threads
+ *
+ * Discover the IDs of all the threads within the process, and
+ * create a procinfo for each of them (chained to the parent).
+ *
+ * This unfortunately requires a different method on every OS.
+ *
+ * Return: non-zero for success, zero for failure.
+ */
+
+int
+proc_delete_dead_threads (procinfo *parent, procinfo *thread, void *ignore)
+{
+ if (thread && parent) /* sanity */
+ {
+ thread->status_valid = 0;
+ if (!proc_get_status (thread))
+ destroy_one_procinfo (&parent->thread_list, thread);
+ }
+ return 0; /* keep iterating */
+}
+
+#if defined (PIOCLSTATUS)
+/*
+ * Solaris 2.5 (ioctl) version
+ */
+int
+proc_update_threads (procinfo *pi)
+{
+ gdb_prstatus_t *prstatus;
+ struct cleanup *old_chain = NULL;
+ procinfo *thread;
+ int nlwp, i;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
+
+ if ((nlwp = proc_get_nthreads (pi)) <= 1)
+ return 1; /* Process is not multi-threaded; nothing to do. */
+
+ prstatus = xmalloc (sizeof (gdb_prstatus_t) * (nlwp + 1));
+
+ old_chain = make_cleanup (xfree, prstatus);
+ if (ioctl (pi->ctl_fd, PIOCLSTATUS, prstatus) < 0)
+ proc_error (pi, "update_threads (PIOCLSTATUS)", __LINE__);
+
+ /* Skip element zero, which represents the process as a whole. */
+ for (i = 1; i < nlwp + 1; i++)
+ {
+ if ((thread = create_procinfo (pi->pid, prstatus[i].pr_who)) == NULL)
+ proc_error (pi, "update_threads, create_procinfo", __LINE__);
+
+ memcpy (&thread->prstatus, &prstatus[i], sizeof (*prstatus));
+ thread->status_valid = 1;
+ }
+ pi->threads_valid = 1;
+ do_cleanups (old_chain);
+ return 1;
+}
+#else
+#ifdef NEW_PROC_API
+/*
+ * Unixware and Solaris 6 (and later) version
+ */
+static void
+do_closedir_cleanup (void *dir)
+{
+ closedir (dir);
+}
+
+int
+proc_update_threads (procinfo *pi)
+{
+ char pathname[MAX_PROC_NAME_SIZE + 16];
+ struct dirent *direntry;
+ struct cleanup *old_chain = NULL;
+ procinfo *thread;
+ DIR *dirp;
+ int lwpid;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
+
+ /*
+ * Unixware
+ *
+ * Note: this brute-force method is the only way I know of
+ * to accomplish this task on Unixware. This method will
+ * also work on Solaris 2.6 and 2.7. There is a much simpler
+ * and more elegant way to do this on Solaris, but the margins
+ * of this manuscript are too small to write it here... ;-)
+ */
+
+ strcpy (pathname, pi->pathname);
+ strcat (pathname, "/lwp");
+ if ((dirp = opendir (pathname)) == NULL)
+ proc_error (pi, "update_threads, opendir", __LINE__);
+
+ old_chain = make_cleanup (do_closedir_cleanup, dirp);
+ while ((direntry = readdir (dirp)) != NULL)
+ if (direntry->d_name[0] != '.') /* skip '.' and '..' */
+ {
+ lwpid = atoi (&direntry->d_name[0]);
+ if ((thread = create_procinfo (pi->pid, lwpid)) == NULL)
+ proc_error (pi, "update_threads, create_procinfo", __LINE__);
+ }
+ pi->threads_valid = 1;
+ do_cleanups (old_chain);
+ return 1;
+}
+#else
+#ifdef PIOCTLIST
+/*
+ * OSF version
+ */
+int
+proc_update_threads (procinfo *pi)
+{
+ int nthreads, i;
+ tid_t *threads;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
+
+ nthreads = proc_get_nthreads (pi);
+ if (nthreads < 2)
+ return 0; /* nothing to do for 1 or fewer threads */
+
+ threads = xmalloc (nthreads * sizeof (tid_t));
+
+ if (ioctl (pi->ctl_fd, PIOCTLIST, threads) < 0)
+ proc_error (pi, "procfs: update_threads (PIOCTLIST)", __LINE__);
+
+ for (i = 0; i < nthreads; i++)
+ {
+ if (!find_procinfo (pi->pid, threads[i]))
+ if (!create_procinfo (pi->pid, threads[i]))
+ proc_error (pi, "update_threads, create_procinfo", __LINE__);
+ }
+ pi->threads_valid = 1;
+ return 1;
+}
+#else
+/*
+ * Default version
+ */
+int
+proc_update_threads (procinfo *pi)
+{
+ return 0;
+}
+#endif /* OSF PIOCTLIST */
+#endif /* NEW_PROC_API */
+#endif /* SOL 2.5 PIOCLSTATUS */
+
+/*
+ * Function: proc_iterate_over_threads
+ *
+ * Description:
+ * Given a pointer to a function, call that function once
+ * for each lwp in the procinfo list, until the function
+ * returns non-zero, in which event return the value
+ * returned by the function.
+ *
+ * Note: this function does NOT call update_threads.
+ * If you want to discover new threads first, you must
+ * call that function explicitly. This function just makes
+ * a quick pass over the currently-known procinfos.
+ *
+ * Arguments:
+ * pi - parent process procinfo
+ * func - per-thread function
+ * ptr - opaque parameter for function.
+ *
+ * Return:
+ * First non-zero return value from the callee, or zero.
+ */
+
+int
+proc_iterate_over_threads (procinfo *pi,
+ int (*func) (procinfo *, procinfo *, void *),
+ void *ptr)
+{
+ procinfo *thread, *next;
+ int retval = 0;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ for (thread = pi->thread_list; thread != NULL; thread = next)
+ {
+ next = thread->next; /* in case thread is destroyed */
+ if ((retval = (*func) (pi, thread, ptr)) != 0)
+ break;
+ }
+
+ return retval;
+}
+
+/* =================== END, Thread "MODULE" =================== */
+
+/* =================== END, /proc "MODULE" =================== */
+
+/* =================== GDB "MODULE" =================== */
+
+/*
+ * Here are all of the gdb target vector functions and their friends.
+ */
+
+static ptid_t do_attach (ptid_t ptid);
+static void do_detach (int signo);
+static int register_gdb_signals (procinfo *, gdb_sigset_t *);
+
+/*
+ * Function: procfs_debug_inferior
+ *
+ * Sets up the inferior to be debugged.
+ * Registers to trace signals, hardware faults, and syscalls.
+ * Note: does not set RLC flag: caller may want to customize that.
+ *
+ * Returns: zero for success (note! unlike most functions in this module)
+ * On failure, returns the LINE NUMBER where it failed!
+ */
+
+static int
+procfs_debug_inferior (procinfo *pi)
+{
+ fltset_t traced_faults;
+ gdb_sigset_t traced_signals;
+ sysset_t *traced_syscall_entries;
+ sysset_t *traced_syscall_exits;
+ int status;
+
+#ifdef PROCFS_DONT_TRACE_FAULTS
+ /* On some systems (OSF), we don't trace hardware faults.
+ Apparently it's enough that we catch them as signals.
+ Wonder why we don't just do that in general? */
+ premptyset (&traced_faults); /* don't trace faults. */
+#else
+ /* Register to trace hardware faults in the child. */
+ prfillset (&traced_faults); /* trace all faults... */
+ prdelset (&traced_faults, FLTPAGE); /* except page fault. */
+#endif
+ if (!proc_set_traced_faults (pi, &traced_faults))
+ return __LINE__;
+
+ /* Register to trace selected signals in the child. */
+ premptyset (&traced_signals);
+ if (!register_gdb_signals (pi, &traced_signals))
+ return __LINE__;
+
+
+ /* Register to trace the 'exit' system call (on entry). */
+ traced_syscall_entries = sysset_t_alloc (pi);
+ gdb_premptysysset (traced_syscall_entries);
+#ifdef SYS_exit
+ gdb_praddsysset (traced_syscall_entries, SYS_exit);
+#endif
+#ifdef SYS_lwpexit
+ gdb_praddsysset (traced_syscall_entries, SYS_lwpexit); /* And _lwp_exit... */
+#endif
+#ifdef SYS_lwp_exit
+ gdb_praddsysset (traced_syscall_entries, SYS_lwp_exit);
+#endif
+#ifdef DYNAMIC_SYSCALLS
+ {
+ int callnum = find_syscall (pi, "_exit");
+ if (callnum >= 0)
+ gdb_praddsysset (traced_syscall_entries, callnum);
+ }
+#endif
+
+ status = proc_set_traced_sysentry (pi, traced_syscall_entries);
+ xfree (traced_syscall_entries);
+ if (!status)
+ return __LINE__;
+
+#ifdef PRFS_STOPEXEC /* defined on OSF */
+ /* OSF method for tracing exec syscalls. Quoting:
+ Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace
+ exits from exec system calls because of the user level loader. */
+ /* FIXME: make nice and maybe move into an access function. */
+ {
+ int prfs_flags;
+
+ if (ioctl (pi->ctl_fd, PIOCGSPCACT, &prfs_flags) < 0)
+ return __LINE__;
+
+ prfs_flags |= PRFS_STOPEXEC;
+
+ if (ioctl (pi->ctl_fd, PIOCSSPCACT, &prfs_flags) < 0)
+ return __LINE__;
+ }
+#else /* not PRFS_STOPEXEC */
+ /* Everyone else's (except OSF) method for tracing exec syscalls */
+ /* 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. */
+
+ traced_syscall_exits = sysset_t_alloc (pi);
+ gdb_premptysysset (traced_syscall_exits);
+#ifdef SYS_exec
+ gdb_praddsysset (traced_syscall_exits, SYS_exec);
+#endif
+#ifdef SYS_execve
+ gdb_praddsysset (traced_syscall_exits, SYS_execve);
+#endif
+#ifdef SYS_execv
+ gdb_praddsysset (traced_syscall_exits, SYS_execv);
+#endif
+
+#ifdef SYS_lwpcreate
+ gdb_praddsysset (traced_syscall_exits, SYS_lwpcreate);
+ gdb_praddsysset (traced_syscall_exits, SYS_lwpexit);
+#endif
+
+#ifdef SYS_lwp_create /* FIXME: once only, please */
+ gdb_praddsysset (traced_syscall_exits, SYS_lwp_create);
+ gdb_praddsysset (traced_syscall_exits, SYS_lwp_exit);
+#endif
+
+#ifdef DYNAMIC_SYSCALLS
+ {
+ int callnum = find_syscall (pi, "execve");
+ if (callnum >= 0)
+ gdb_praddsysset (traced_syscall_exits, callnum);
+ callnum = find_syscall (pi, "ra_execve");
+ if (callnum >= 0)
+ gdb_praddsysset (traced_syscall_exits, callnum);
+ }
+#endif
+
+ status = proc_set_traced_sysexit (pi, traced_syscall_exits);
+ xfree (traced_syscall_exits);
+ if (!status)
+ return __LINE__;
+
+#endif /* PRFS_STOPEXEC */
+ return 0;
+}
+
+static void
+procfs_attach (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 ())
+ error ("Attaching GDB to itself is not a good idea...");
+
+ if (from_tty)
+ {
+ exec_file = get_exec_file (0);
+
+ if (exec_file)
+ printf_filtered ("Attaching to program `%s', %s\n",
+ exec_file, target_pid_to_str (pid_to_ptid (pid)));
+ else
+ printf_filtered ("Attaching to %s\n",
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ fflush (stdout);
+ }
+ inferior_ptid = do_attach (pid_to_ptid (pid));
+ push_target (&procfs_ops);
+}
+
+static void
+procfs_detach (char *args, int from_tty)
+{
+ char *exec_file;
+ int signo = 0;
+
+ if (from_tty)
+ {
+ exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf_filtered ("Detaching from program: %s %s\n",
+ exec_file, target_pid_to_str (inferior_ptid));
+ fflush (stdout);
+ }
+ if (args)
+ signo = atoi (args);
+
+ do_detach (signo);
+ inferior_ptid = null_ptid;
+ unpush_target (&procfs_ops); /* Pop out of handling an inferior */
+}
+
+static ptid_t
+do_attach (ptid_t ptid)
+{
+ procinfo *pi;
+ int fail;
+
+ if ((pi = create_procinfo (PIDGET (ptid), 0)) == NULL)
+ perror ("procfs: out of memory in 'attach'");
+
+ if (!open_procinfo_files (pi, FD_CTL))
+ {
+ fprintf_filtered (gdb_stderr, "procfs:%d -- ", __LINE__);
+ sprintf (errmsg, "do_attach: couldn't open /proc file for process %d",
+ PIDGET (ptid));
+ dead_procinfo (pi, errmsg, NOKILL);
+ }
+
+ /* Stop the process (if it isn't already stopped). */
+ if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
+ {
+ pi->was_stopped = 1;
+ proc_prettyprint_why (proc_why (pi), proc_what (pi), 1);
+ }
+ else
+ {
+ pi->was_stopped = 0;
+ /* Set the process to run again when we close it. */
+ if (!proc_set_run_on_last_close (pi))
+ dead_procinfo (pi, "do_attach: couldn't set RLC.", NOKILL);
+
+ /* Now stop the process. */
+ if (!proc_stop_process (pi))
+ dead_procinfo (pi, "do_attach: couldn't stop the process.", NOKILL);
+ pi->ignore_next_sigstop = 1;
+ }
+ /* Save some of the /proc state to be restored if we detach. */
+ if (!proc_get_traced_faults (pi, &pi->saved_fltset))
+ dead_procinfo (pi, "do_attach: couldn't save traced faults.", NOKILL);
+ if (!proc_get_traced_signals (pi, &pi->saved_sigset))
+ dead_procinfo (pi, "do_attach: couldn't save traced signals.", NOKILL);
+ if (!proc_get_traced_sysentry (pi, pi->saved_entryset))
+ dead_procinfo (pi, "do_attach: couldn't save traced syscall entries.",
+ NOKILL);
+ if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
+ dead_procinfo (pi, "do_attach: couldn't save traced syscall exits.",
+ NOKILL);
+ if (!proc_get_held_signals (pi, &pi->saved_sighold))
+ dead_procinfo (pi, "do_attach: couldn't save held signals.", NOKILL);
+
+ if ((fail = procfs_debug_inferior (pi)) != 0)
+ dead_procinfo (pi, "do_attach: failed in procfs_debug_inferior", NOKILL);
+
+ /* Let GDB know that the inferior was attached. */
+ attach_flag = 1;
+ return MERGEPID (pi->pid, proc_get_current_thread (pi));
+}
+
+static void
+do_detach (int signo)
+{
+ procinfo *pi;
+
+ /* Find procinfo for the main process */
+ pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); /* FIXME: threads */
+ if (signo)
+ if (!proc_set_current_signal (pi, signo))
+ proc_warn (pi, "do_detach, set_current_signal", __LINE__);
+
+ if (!proc_set_traced_signals (pi, &pi->saved_sigset))
+ proc_warn (pi, "do_detach, set_traced_signal", __LINE__);
+
+ if (!proc_set_traced_faults (pi, &pi->saved_fltset))
+ proc_warn (pi, "do_detach, set_traced_faults", __LINE__);
+
+ if (!proc_set_traced_sysentry (pi, pi->saved_entryset))
+ proc_warn (pi, "do_detach, set_traced_sysentry", __LINE__);
+
+ if (!proc_set_traced_sysexit (pi, pi->saved_exitset))
+ proc_warn (pi, "do_detach, set_traced_sysexit", __LINE__);
+
+ if (!proc_set_held_signals (pi, &pi->saved_sighold))
+ proc_warn (pi, "do_detach, set_held_signals", __LINE__);
+
+ if (signo || (proc_flags (pi) & (PR_STOPPED | PR_ISTOP)))
+ if (signo || !(pi->was_stopped) ||
+ query ("Was stopped when attached, make it runnable again? "))
+ {
+ /* Clear any pending signal. */
+ if (!proc_clear_current_fault (pi))
+ proc_warn (pi, "do_detach, clear_current_fault", __LINE__);
+
+ if (signo == 0 && !proc_clear_current_signal (pi))
+ proc_warn (pi, "do_detach, clear_current_signal", __LINE__);
+
+ if (!proc_set_run_on_last_close (pi))
+ proc_warn (pi, "do_detach, set_rlc", __LINE__);
+ }
+
+ attach_flag = 0;
+ destroy_procinfo (pi);
+}
+
+/*
+ * fetch_registers
+ *
+ * Since the /proc interface cannot give us individual registers,
+ * we pay no attention to the (regno) argument, and just fetch them all.
+ * This results in the possibility that we will do unnecessarily many
+ * fetches, since we may be called repeatedly for individual registers.
+ * So we cache the results, and mark the cache invalid when the process
+ * is resumed.
+ */
+
+static void
+procfs_fetch_registers (int regno)
+{
+ gdb_fpregset_t *fpregs;
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid;
+ int tid;
+
+ pid = PIDGET (inferior_ptid);
+ tid = TIDGET (inferior_ptid);
+
+ /* First look up procinfo for the main process. */
+ pi = find_procinfo_or_die (pid, 0);
+
+ /* If the event thread is not the same as GDB's requested thread
+ (ie. inferior_ptid), then look up procinfo for the requested
+ thread. */
+ if ((tid != 0) &&
+ (tid != proc_get_current_thread (pi)))
+ pi = find_procinfo_or_die (pid, tid);
+
+ if (pi == NULL)
+ error ("procfs: fetch_registers failed to find procinfo for %s",
+ target_pid_to_str (inferior_ptid));
+
+ if ((gregs = proc_get_gregs (pi)) == NULL)
+ proc_error (pi, "fetch_registers, get_gregs", __LINE__);
+
+ supply_gregset (gregs);
+
+ if (FP0_REGNUM >= 0) /* need floating point? */
+ {
+ if ((regno >= 0 && regno < FP0_REGNUM)
+ || regno == PC_REGNUM
+ || regno == DEPRECATED_FP_REGNUM
+ || regno == SP_REGNUM)
+ return; /* not a floating point register */
+
+ if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ proc_error (pi, "fetch_registers, get_fpregs", __LINE__);
+
+ supply_fpregset (fpregs);
+ }
+}
+
+/* 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, such as
+ /proc, this makes sure that registers contains all the registers
+ from the program being debugged. */
+
+static void
+procfs_prepare_to_store (void)
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/*
+ * store_registers
+ *
+ * Since the /proc interface will not read individual registers,
+ * we will cache these requests until the process is resumed, and
+ * only then write them back to the inferior process.
+ *
+ * FIXME: is that a really bad idea? Have to think about cases
+ * where writing one register might affect the value of others, etc.
+ */
+
+static void
+procfs_store_registers (int regno)
+{
+ gdb_fpregset_t *fpregs;
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid;
+ int tid;
+
+ pid = PIDGET (inferior_ptid);
+ tid = TIDGET (inferior_ptid);
+
+ /* First find procinfo for main process */
+ pi = find_procinfo_or_die (pid, 0);
+
+ /* If current lwp for process is not the same as requested thread
+ (ie. inferior_ptid), then find procinfo for the requested thread. */
+
+ if ((tid != 0) &&
+ (tid != proc_get_current_thread (pi)))
+ pi = find_procinfo_or_die (pid, tid);
+
+ if (pi == NULL)
+ error ("procfs: store_registers: failed to find procinfo for %s",
+ target_pid_to_str (inferior_ptid));
+
+ if ((gregs = proc_get_gregs (pi)) == NULL)
+ proc_error (pi, "store_registers, get_gregs", __LINE__);
+
+ fill_gregset (gregs, regno);
+ if (!proc_set_gregs (pi))
+ proc_error (pi, "store_registers, set_gregs", __LINE__);
+
+ if (FP0_REGNUM >= 0) /* need floating point? */
+ {
+ if ((regno >= 0 && regno < FP0_REGNUM)
+ || regno == PC_REGNUM
+ || regno == DEPRECATED_FP_REGNUM
+ || regno == SP_REGNUM)
+ return; /* not a floating point register */
+
+ if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ proc_error (pi, "store_registers, get_fpregs", __LINE__);
+
+ fill_fpregset (fpregs, regno);
+ if (!proc_set_fpregs (pi))
+ proc_error (pi, "store_registers, set_fpregs", __LINE__);
+ }
+}
+
+static int
+syscall_is_lwp_exit (procinfo *pi, int scall)
+{
+
+#ifdef SYS_lwp_exit
+ if (scall == SYS_lwp_exit)
+ return 1;
+#endif
+#ifdef SYS_lwpexit
+ if (scall == SYS_lwpexit)
+ return 1;
+#endif
+ return 0;
+}
+
+static int
+syscall_is_exit (procinfo *pi, int scall)
+{
+#ifdef SYS_exit
+ if (scall == SYS_exit)
+ return 1;
+#endif
+#ifdef DYNAMIC_SYSCALLS
+ if (find_syscall (pi, "_exit") == scall)
+ return 1;
+#endif
+ return 0;
+}
+
+static int
+syscall_is_exec (procinfo *pi, int scall)
+{
+#ifdef SYS_exec
+ if (scall == SYS_exec)
+ return 1;
+#endif
+#ifdef SYS_execv
+ if (scall == SYS_execv)
+ return 1;
+#endif
+#ifdef SYS_execve
+ if (scall == SYS_execve)
+ return 1;
+#endif
+#ifdef DYNAMIC_SYSCALLS
+ if (find_syscall (pi, "_execve"))
+ return 1;
+ if (find_syscall (pi, "ra_execve"))
+ return 1;
+#endif
+ return 0;
+}
+
+static int
+syscall_is_lwp_create (procinfo *pi, int scall)
+{
+#ifdef SYS_lwp_create
+ if (scall == SYS_lwp_create)
+ return 1;
+#endif
+#ifdef SYS_lwpcreate
+ if (scall == SYS_lwpcreate)
+ return 1;
+#endif
+ return 0;
+}
+
+/*
+ * Function: target_wait
+ *
+ * Retrieve the next stop event from the child process.
+ * If child has not stopped yet, wait for it to stop.
+ * Translate /proc eventcodes (or possibly wait eventcodes)
+ * into gdb internal event codes.
+ *
+ * Return: id of process (and possibly thread) that incurred the event.
+ * event codes are returned thru a pointer parameter.
+ */
+
+static ptid_t
+procfs_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ /* First cut: loosely based on original version 2.1 */
+ procinfo *pi;
+ int wstat;
+ int temp_tid;
+ ptid_t retval, temp_ptid;
+ int why, what, flags;
+ int retry = 0;
+
+wait_again:
+
+ retry++;
+ wstat = 0;
+ retval = pid_to_ptid (-1);
+
+ /* Find procinfo for main process */
+ pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ if (pi)
+ {
+ /* We must assume that the status is stale now... */
+ pi->status_valid = 0;
+ pi->gregs_valid = 0;
+ pi->fpregs_valid = 0;
+
+#if 0 /* just try this out... */
+ flags = proc_flags (pi);
+ why = proc_why (pi);
+ if ((flags & PR_STOPPED) && (why == PR_REQUESTED))
+ pi->status_valid = 0; /* re-read again, IMMEDIATELY... */
+#endif
+ /* If child is not stopped, wait for it to stop. */
+ if (!(proc_flags (pi) & (PR_STOPPED | PR_ISTOP)) &&
+ !proc_wait_for_stop (pi))
+ {
+ /* wait_for_stop failed: has the child terminated? */
+ if (errno == ENOENT)
+ {
+ int wait_retval;
+
+ /* /proc file not found; presumably child has terminated. */
+ wait_retval = wait (&wstat); /* "wait" for the child's exit */
+
+ if (wait_retval != PIDGET (inferior_ptid)) /* wrong child? */
+ error ("procfs: couldn't stop process %d: wait returned %d\n",
+ PIDGET (inferior_ptid), wait_retval);
+ /* FIXME: might I not just use waitpid?
+ Or try find_procinfo to see if I know about this child? */
+ retval = pid_to_ptid (wait_retval);
+ }
+ else if (errno == EINTR)
+ goto wait_again;
+ else
+ {
+ /* Unknown error from wait_for_stop. */
+ proc_error (pi, "target_wait (wait_for_stop)", __LINE__);
+ }
+ }
+ else
+ {
+ /* This long block is reached if either:
+ a) the child was already stopped, or
+ b) we successfully waited for the child with wait_for_stop.
+ This block will analyze the /proc status, and translate it
+ into a waitstatus for GDB.
+
+ If we actually had to call wait because the /proc file
+ is gone (child terminated), then we skip this block,
+ because we already have a waitstatus. */
+
+ flags = proc_flags (pi);
+ why = proc_why (pi);
+ what = proc_what (pi);
+
+ if (flags & (PR_STOPPED | PR_ISTOP))
+ {
+#ifdef PR_ASYNC
+ /* If it's running async (for single_thread control),
+ set it back to normal again. */
+ if (flags & PR_ASYNC)
+ if (!proc_unset_async (pi))
+ proc_error (pi, "target_wait, unset_async", __LINE__);
+#endif
+
+ if (info_verbose)
+ proc_prettyprint_why (why, what, 1);
+
+ /* The 'pid' we will return to GDB is composed of
+ the process ID plus the lwp ID. */
+ retval = MERGEPID (pi->pid, proc_get_current_thread (pi));
+
+ switch (why) {
+ case PR_SIGNALLED:
+ wstat = (what << 8) | 0177;
+ break;
+ case PR_SYSENTRY:
+ if (syscall_is_lwp_exit (pi, what))
+ {
+ printf_filtered ("[%s exited]\n",
+ target_pid_to_str (retval));
+ delete_thread (retval);
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return retval;
+ }
+ else if (syscall_is_exit (pi, what))
+ {
+ /* Handle SYS_exit call only */
+ /* Stopped at entry to SYS_exit.
+ Make it runnable, resume it, then use
+ the wait system call to get its exit code.
+ Proc_run_process always clears the current
+ fault and signal.
+ Then return its exit status. */
+ pi->status_valid = 0;
+ wstat = 0;
+ /* FIXME: what we should do is return
+ TARGET_WAITKIND_SPURIOUS. */
+ if (!proc_run_process (pi, 0, 0))
+ proc_error (pi, "target_wait, run_process", __LINE__);
+ if (attach_flag)
+ {
+ /* Don't call wait: simulate waiting for exit,
+ return a "success" exit code. Bogus: what if
+ it returns something else? */
+ wstat = 0;
+ retval = inferior_ptid; /* ? ? ? */
+ }
+ else
+ {
+ int temp = wait (&wstat);
+
+ /* FIXME: shouldn't I make sure I get the right
+ event from the right process? If (for
+ instance) I have killed an earlier inferior
+ process but failed to clean up after it
+ somehow, I could get its termination event
+ here. */
+
+ /* If wait returns -1, that's what we return to GDB. */
+ if (temp < 0)
+ retval = pid_to_ptid (temp);
+ }
+ }
+ else
+ {
+ printf_filtered ("procfs: trapped on entry to ");
+ proc_prettyprint_syscall (proc_what (pi), 0);
+ printf_filtered ("\n");
+#ifndef PIOCSSPCACT
+ {
+ long i, nsysargs, *sysargs;
+
+ if ((nsysargs = proc_nsysarg (pi)) > 0 &&
+ (sysargs = proc_sysargs (pi)) != NULL)
+ {
+ printf_filtered ("%ld syscall arguments:\n", nsysargs);
+ for (i = 0; i < nsysargs; i++)
+ printf_filtered ("#%ld: 0x%08lx\n",
+ i, sysargs[i]);
+ }
+
+ }
+#endif
+ if (status)
+ {
+ /* How to exit gracefully, returning "unknown event" */
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return inferior_ptid;
+ }
+ else
+ {
+ /* How to keep going without returning to wfi: */
+ target_resume (ptid, 0, TARGET_SIGNAL_0);
+ goto wait_again;
+ }
+ }
+ break;
+ case PR_SYSEXIT:
+ if (syscall_is_exec (pi, what))
+ {
+ /* Hopefully this is our own "fork-child" execing
+ the real child. Hoax this event into a trap, and
+ GDB will see the child about to execute its start
+ address. */
+ wstat = (SIGTRAP << 8) | 0177;
+ }
+ else if (syscall_is_lwp_create (pi, what))
+ {
+ /*
+ * This syscall is somewhat like fork/exec.
+ * We will get the event twice: once for the parent LWP,
+ * and once for the child. We should already know about
+ * the parent LWP, but the child will be new to us. So,
+ * whenever we get this event, if it represents a new
+ * thread, simply add the thread to the list.
+ */
+
+ /* If not in procinfo list, add it. */
+ temp_tid = proc_get_current_thread (pi);
+ if (!find_procinfo (pi->pid, temp_tid))
+ create_procinfo (pi->pid, temp_tid);
+
+ temp_ptid = MERGEPID (pi->pid, temp_tid);
+ /* If not in GDB's thread list, add it. */
+ if (!in_thread_list (temp_ptid))
+ {
+ printf_filtered ("[New %s]\n",
+ target_pid_to_str (temp_ptid));
+ add_thread (temp_ptid);
+ }
+ /* Return to WFI, but tell it to immediately resume. */
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return inferior_ptid;
+ }
+ else if (syscall_is_lwp_exit (pi, what))
+ {
+ printf_filtered ("[%s exited]\n",
+ target_pid_to_str (retval));
+ delete_thread (retval);
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return retval;
+ }
+ else if (0)
+ {
+ /* FIXME: Do we need to handle SYS_sproc,
+ SYS_fork, or SYS_vfork here? The old procfs
+ seemed to use this event to handle threads on
+ older (non-LWP) systems, where I'm assuming
+ that threads were actually separate processes.
+ Irix, maybe? Anyway, low priority for now. */
+ }
+ else
+ {
+ printf_filtered ("procfs: trapped on exit from ");
+ proc_prettyprint_syscall (proc_what (pi), 0);
+ printf_filtered ("\n");
+#ifndef PIOCSSPCACT
+ {
+ long i, nsysargs, *sysargs;
+
+ if ((nsysargs = proc_nsysarg (pi)) > 0 &&
+ (sysargs = proc_sysargs (pi)) != NULL)
+ {
+ printf_filtered ("%ld syscall arguments:\n", nsysargs);
+ for (i = 0; i < nsysargs; i++)
+ printf_filtered ("#%ld: 0x%08lx\n",
+ i, sysargs[i]);
+ }
+ }
+#endif
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return inferior_ptid;
+ }
+ break;
+ case PR_REQUESTED:
+#if 0 /* FIXME */
+ wstat = (SIGSTOP << 8) | 0177;
+ break;
+#else
+ if (retry < 5)
+ {
+ printf_filtered ("Retry #%d:\n", retry);
+ pi->status_valid = 0;
+ goto wait_again;
+ }
+ else
+ {
+ /* If not in procinfo list, add it. */
+ temp_tid = proc_get_current_thread (pi);
+ if (!find_procinfo (pi->pid, temp_tid))
+ create_procinfo (pi->pid, temp_tid);
+
+ /* If not in GDB's thread list, add it. */
+ temp_ptid = MERGEPID (pi->pid, temp_tid);
+ if (!in_thread_list (temp_ptid))
+ {
+ printf_filtered ("[New %s]\n",
+ target_pid_to_str (temp_ptid));
+ add_thread (temp_ptid);
+ }
+
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = 0;
+ return retval;
+ }
+#endif
+ case PR_JOBCONTROL:
+ wstat = (what << 8) | 0177;
+ break;
+ case PR_FAULTED:
+ switch (what) {
+#ifdef FLTWATCH
+ case FLTWATCH:
+ wstat = (SIGTRAP << 8) | 0177;
+ break;
+#endif
+#ifdef FLTKWATCH
+ case FLTKWATCH:
+ wstat = (SIGTRAP << 8) | 0177;
+ break;
+#endif
+ /* FIXME: use si_signo where possible. */
+ case FLTPRIV:
+#if (FLTILL != FLTPRIV) /* avoid "duplicate case" error */
+ case FLTILL:
+#endif
+ wstat = (SIGILL << 8) | 0177;
+ break;
+ case FLTBPT:
+#if (FLTTRACE != FLTBPT) /* avoid "duplicate case" error */
+ case FLTTRACE:
+#endif
+ wstat = (SIGTRAP << 8) | 0177;
+ break;
+ case FLTSTACK:
+ case FLTACCESS:
+#if (FLTBOUNDS != FLTSTACK) /* avoid "duplicate case" error */
+ case FLTBOUNDS:
+#endif
+ wstat = (SIGSEGV << 8) | 0177;
+ break;
+ case FLTIOVF:
+ case FLTIZDIV:
+#if (FLTFPE != FLTIOVF) /* avoid "duplicate case" error */
+ case FLTFPE:
+#endif
+ wstat = (SIGFPE << 8) | 0177;
+ break;
+ case FLTPAGE: /* Recoverable page fault */
+ default: /* FIXME: use si_signo if possible for fault */
+ retval = pid_to_ptid (-1);
+ printf_filtered ("procfs:%d -- ", __LINE__);
+ printf_filtered ("child stopped for unknown reason:\n");
+ proc_prettyprint_why (why, what, 1);
+ error ("... giving up...");
+ break;
+ }
+ break; /* case PR_FAULTED: */
+ default: /* switch (why) unmatched */
+ printf_filtered ("procfs:%d -- ", __LINE__);
+ printf_filtered ("child stopped for unknown reason:\n");
+ proc_prettyprint_why (why, what, 1);
+ error ("... giving up...");
+ break;
+ }
+ /*
+ * Got this far without error:
+ * If retval isn't in the threads database, add it.
+ */
+ if (PIDGET (retval) > 0 &&
+ !ptid_equal (retval, inferior_ptid) &&
+ !in_thread_list (retval))
+ {
+ /*
+ * We have a new thread.
+ * We need to add it both to GDB's list and to our own.
+ * If we don't create a procinfo, resume may be unhappy
+ * later.
+ */
+ printf_filtered ("[New %s]\n", target_pid_to_str (retval));
+ add_thread (retval);
+ if (find_procinfo (PIDGET (retval), TIDGET (retval)) == NULL)
+ create_procinfo (PIDGET (retval), TIDGET (retval));
+
+ /* In addition, it's possible that this is the first
+ * new thread we've seen, in which case we may not
+ * have created entries for inferior_ptid yet.
+ */
+ if (TIDGET (inferior_ptid) != 0)
+ {
+ if (!in_thread_list (inferior_ptid))
+ add_thread (inferior_ptid);
+ if (find_procinfo (PIDGET (inferior_ptid),
+ TIDGET (inferior_ptid)) == NULL)
+ create_procinfo (PIDGET (inferior_ptid),
+ TIDGET (inferior_ptid));
+ }
+ }
+ }
+ else /* flags do not indicate STOPPED */
+ {
+ /* surely this can't happen... */
+ printf_filtered ("procfs:%d -- process not stopped.\n",
+ __LINE__);
+ proc_prettyprint_flags (flags, 1);
+ error ("procfs: ...giving up...");
+ }
+ }
+
+ if (status)
+ store_waitstatus (status, wstat);
+ }
+
+ return retval;
+}
+
+/* Perform a partial transfer to/from the specified object. For
+ memory transfers, fall back to the old memory xfer functions. */
+
+static LONGEST
+procfs_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_MEMORY:
+ if (readbuf)
+ return (*ops->to_xfer_memory) (offset, readbuf, len, 0/*write*/,
+ NULL, ops);
+ if (writebuf)
+ return (*ops->to_xfer_memory) (offset, readbuf, len, 1/*write*/,
+ NULL, ops);
+ return -1;
+
+#ifdef NEW_PROC_API
+ case TARGET_OBJECT_AUXV:
+ return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
+ offset, len);
+#endif
+
+ default:
+ if (ops->beneath != NULL)
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
+ return -1;
+ }
+}
+
+
+/* Transfer LEN bytes between GDB address MYADDR and target address
+ MEMADDR. If DOWRITE is non-zero, transfer them to the target,
+ otherwise transfer them from the target. TARGET is unused.
+
+ The return value is 0 if an error occurred or no bytes were
+ transferred. Otherwise, it will be a positive value which
+ indicates the number of bytes transferred between gdb and the
+ target. (Note that the interface also makes provisions for
+ negative values, but this capability isn't implemented here.) */
+
+static int
+procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ procinfo *pi;
+ int nbytes = 0;
+
+ /* Find procinfo for main process */
+ pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ if (pi->as_fd == 0 &&
+ open_procinfo_files (pi, FD_AS) == 0)
+ {
+ proc_warn (pi, "xfer_memory, open_proc_files", __LINE__);
+ return 0;
+ }
+
+ if (lseek (pi->as_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr)
+ {
+ if (dowrite)
+ {
+#ifdef NEW_PROC_API
+ PROCFS_NOTE ("write memory: ");
+#else
+ PROCFS_NOTE ("write memory: \n");
+#endif
+ nbytes = write (pi->as_fd, myaddr, len);
+ }
+ else
+ {
+ PROCFS_NOTE ("read memory: \n");
+ nbytes = read (pi->as_fd, myaddr, len);
+ }
+ if (nbytes < 0)
+ {
+ nbytes = 0;
+ }
+ }
+ return nbytes;
+}
+
+/*
+ * Function: invalidate_cache
+ *
+ * Called by target_resume before making child runnable.
+ * Mark cached registers and status's invalid.
+ * If there are "dirty" caches that need to be written back
+ * to the child process, do that.
+ *
+ * File descriptors are also cached.
+ * As they are a limited resource, we cannot hold onto them indefinitely.
+ * However, as they are expensive to open, we don't want to throw them
+ * away indescriminately either. As a compromise, we will keep the
+ * file descriptors for the parent process, but discard any file
+ * descriptors we may have accumulated for the threads.
+ *
+ * Return value:
+ * As this function is called by iterate_over_threads, it always
+ * returns zero (so that iterate_over_threads will keep iterating).
+ */
+
+
+static int
+invalidate_cache (procinfo *parent, procinfo *pi, void *ptr)
+{
+ /*
+ * About to run the child; invalidate caches and do any other cleanup.
+ */
+
+#if 0
+ if (pi->gregs_dirty)
+ if (parent == NULL ||
+ proc_get_current_thread (parent) != pi->tid)
+ if (!proc_set_gregs (pi)) /* flush gregs cache */
+ proc_warn (pi, "target_resume, set_gregs",
+ __LINE__);
+ if (FP0_REGNUM >= 0)
+ if (pi->fpregs_dirty)
+ if (parent == NULL ||
+ proc_get_current_thread (parent) != pi->tid)
+ if (!proc_set_fpregs (pi)) /* flush fpregs cache */
+ proc_warn (pi, "target_resume, set_fpregs",
+ __LINE__);
+#endif
+
+ if (parent != NULL)
+ {
+ /* The presence of a parent indicates that this is an LWP.
+ Close any file descriptors that it might have open.
+ We don't do this to the master (parent) procinfo. */
+
+ close_procinfo_files (pi);
+ }
+ pi->gregs_valid = 0;
+ pi->fpregs_valid = 0;
+#if 0
+ pi->gregs_dirty = 0;
+ pi->fpregs_dirty = 0;
+#endif
+ pi->status_valid = 0;
+ pi->threads_valid = 0;
+
+ return 0;
+}
+
+#if 0
+/*
+ * Function: make_signal_thread_runnable
+ *
+ * A callback function for iterate_over_threads.
+ * Find the asynchronous signal thread, and make it runnable.
+ * See if that helps matters any.
+ */
+
+static int
+make_signal_thread_runnable (procinfo *process, procinfo *pi, void *ptr)
+{
+#ifdef PR_ASLWP
+ if (proc_flags (pi) & PR_ASLWP)
+ {
+ if (!proc_run_process (pi, 0, -1))
+ proc_error (pi, "make_signal_thread_runnable", __LINE__);
+ return 1;
+ }
+#endif
+ return 0;
+}
+#endif
+
+/*
+ * Function: target_resume
+ *
+ * Make the child process runnable. Normally we will then call
+ * procfs_wait and wait for it to stop again (unles gdb is async).
+ *
+ * Arguments:
+ * step: if true, then arrange for the child to stop again
+ * after executing a single instruction.
+ * signo: if zero, then cancel any pending signal.
+ * If non-zero, then arrange for the indicated signal
+ * to be delivered to the child when it runs.
+ * pid: if -1, then allow any child thread to run.
+ * if non-zero, then allow only the indicated thread to run.
+ ******* (not implemented yet)
+ */
+
+static void
+procfs_resume (ptid_t ptid, int step, enum target_signal signo)
+{
+ procinfo *pi, *thread;
+ int native_signo;
+
+ /* 2.1:
+ prrun.prflags |= PRSVADDR;
+ prrun.pr_vaddr = $PC; set resume address
+ prrun.prflags |= PRSTRACE; trace signals in pr_trace (all)
+ prrun.prflags |= PRSFAULT; trace faults in pr_fault (all but PAGE)
+ prrun.prflags |= PRCFAULT; clear current fault.
+
+ PRSTRACE and PRSFAULT can be done by other means
+ (proc_trace_signals, proc_trace_faults)
+ PRSVADDR is unnecessary.
+ PRCFAULT may be replaced by a PIOCCFAULT call (proc_clear_current_fault)
+ This basically leaves PRSTEP and PRCSIG.
+ PRCSIG is like PIOCSSIG (proc_clear_current_signal).
+ So basically PR_STEP is the sole argument that must be passed
+ to proc_run_process (for use in the prrun struct by ioctl). */
+
+ /* Find procinfo for main process */
+ pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+
+ /* First cut: ignore pid argument */
+ errno = 0;
+
+ /* Convert signal to host numbering. */
+ if (signo == 0 ||
+ (signo == TARGET_SIGNAL_STOP && pi->ignore_next_sigstop))
+ native_signo = 0;
+ else
+ native_signo = target_signal_to_host (signo);
+
+ pi->ignore_next_sigstop = 0;
+
+ /* Running the process voids all cached registers and status. */
+ /* Void the threads' caches first */
+ proc_iterate_over_threads (pi, invalidate_cache, NULL);
+ /* Void the process procinfo's caches. */
+ invalidate_cache (NULL, pi, NULL);
+
+ if (PIDGET (ptid) != -1)
+ {
+ /* Resume a specific thread, presumably suppressing the others. */
+ thread = find_procinfo (PIDGET (ptid), TIDGET (ptid));
+ if (thread != NULL)
+ {
+ if (thread->tid != 0)
+ {
+ /* We're to resume a specific thread, and not the others.
+ * Set the child process's PR_ASYNC flag.
+ */
+#ifdef PR_ASYNC
+ if (!proc_set_async (pi))
+ proc_error (pi, "target_resume, set_async", __LINE__);
+#endif
+#if 0
+ proc_iterate_over_threads (pi,
+ make_signal_thread_runnable,
+ NULL);
+#endif
+ pi = thread; /* substitute the thread's procinfo for run */
+ }
+ }
+ }
+
+ if (!proc_run_process (pi, step, native_signo))
+ {
+ if (errno == EBUSY)
+ warning ("resume: target already running. Pretend to resume, and hope for the best!\n");
+ else
+ proc_error (pi, "target_resume", __LINE__);
+ }
+}
+
+/*
+ * Function: register_gdb_signals
+ *
+ * Traverse the list of signals that GDB knows about
+ * (see "handle" command), and arrange for the target
+ * to be stopped or not, according to these settings.
+ *
+ * Returns non-zero for success, zero for failure.
+ */
+
+static int
+register_gdb_signals (procinfo *pi, gdb_sigset_t *signals)
+{
+ int signo;
+
+ 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 (signals, signo);
+ else
+ praddset (signals, signo);
+
+ return proc_set_traced_signals (pi, signals);
+}
+
+/*
+ * Function: target_notice_signals
+ *
+ * Set up to trace signals in the child process.
+ */
+
+static void
+procfs_notice_signals (ptid_t ptid)
+{
+ gdb_sigset_t signals;
+ procinfo *pi = find_procinfo_or_die (PIDGET (ptid), 0);
+
+ if (proc_get_traced_signals (pi, &signals) &&
+ register_gdb_signals (pi, &signals))
+ return;
+ else
+ proc_error (pi, "notice_signals", __LINE__);
+}
+
+/*
+ * Function: target_files_info
+ *
+ * Print status information about the child process.
+ */
+
+static void
+procfs_files_info (struct target_ops *ignore)
+{
+ printf_filtered ("\tUsing the running image of %s %s via /proc.\n",
+ attach_flag? "attached": "child",
+ target_pid_to_str (inferior_ptid));
+}
+
+/*
+ * Function: target_open
+ *
+ * A dummy: you don't open procfs.
+ */
+
+static void
+procfs_open (char *args, int from_tty)
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
+
+/*
+ * Function: target_can_run
+ *
+ * This tells GDB that this target vector can be invoked
+ * for "run" or "attach".
+ */
+
+int procfs_suppress_run = 0; /* Non-zero if procfs should pretend not to
+ be a runnable target. Used by targets
+ that can sit atop procfs, such as solaris
+ thread support. */
+
+
+static int
+procfs_can_run (void)
+{
+ /* This variable is controlled by modules that sit atop procfs that
+ may layer their own process structure atop that provided here.
+ sol-thread.c does this because of the Solaris two-level thread
+ model. */
+
+ /* NOTE: possibly obsolete -- use the thread_stratum approach instead. */
+
+ return !procfs_suppress_run;
+}
+
+/*
+ * Function: target_stop
+ *
+ * Stop the child process asynchronously, as when the
+ * gdb user types control-c or presses a "stop" button.
+ *
+ * Works by sending kill(SIGINT) to the child's process group.
+ */
+
+static void
+procfs_stop (void)
+{
+ kill (-inferior_process_group, SIGINT);
+}
+
+/*
+ * Function: unconditionally_kill_inferior
+ *
+ * Make it die. Wait for it to die. Clean up after it.
+ * Note: this should only be applied to the real process,
+ * not to an LWP, because of the check for parent-process.
+ * If we need this to work for an LWP, it needs some more logic.
+ */
+
+static void
+unconditionally_kill_inferior (procinfo *pi)
+{
+ int parent_pid;
+
+ parent_pid = proc_parent_pid (pi);
+#ifdef PROCFS_NEED_CLEAR_CURSIG_FOR_KILL
+ /* FIXME: use access functions */
+ /* 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. */
+ if (ioctl (pi->ctl_fd, PIOCSSIG, NULL) < 0)
+ {
+ printf_filtered ("unconditionally_kill: SSIG failed!\n");
+ }
+#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. */
+ {
+ gdb_siginfo_t newsiginfo;
+
+ memset ((char *) &newsiginfo, 0, sizeof (newsiginfo));
+ newsiginfo.si_signo = SIGKILL;
+ newsiginfo.si_code = 0;
+ newsiginfo.si_errno = 0;
+ newsiginfo.si_pid = getpid ();
+ newsiginfo.si_uid = getuid ();
+ /* FIXME: use proc_set_current_signal */
+ ioctl (pi->ctl_fd, PIOCSSIG, &newsiginfo);
+ }
+#else /* PROCFS_NEED_PIOCSSIG_FOR_KILL */
+ if (!proc_kill (pi, SIGKILL))
+ proc_error (pi, "unconditionally_kill, proc_kill", __LINE__);
+#endif /* PROCFS_NEED_PIOCSSIG_FOR_KILL */
+ destroy_procinfo (pi);
+
+ /* If pi is GDB's child, wait for it to die. */
+ if (parent_pid == getpid ())
+ /* FIXME: should we use waitpid to make sure we get the right event?
+ Should we check the returned event? */
+ {
+#if 0
+ int status, ret;
+
+ ret = waitpid (pi->pid, &status, 0);
+#else
+ wait (NULL);
+#endif
+ }
+}
+
+/*
+ * Function: target_kill_inferior
+ *
+ * We're done debugging it, and we want it to go away.
+ * Then we want GDB to forget all about it.
+ */
+
+static void
+procfs_kill_inferior (void)
+{
+ if (!ptid_equal (inferior_ptid, null_ptid)) /* ? */
+ {
+ /* Find procinfo for main process */
+ procinfo *pi = find_procinfo (PIDGET (inferior_ptid), 0);
+
+ if (pi)
+ unconditionally_kill_inferior (pi);
+ target_mourn_inferior ();
+ }
+}
+
+/*
+ * Function: target_mourn_inferior
+ *
+ * Forget we ever debugged this thing!
+ */
+
+static void
+procfs_mourn_inferior (void)
+{
+ procinfo *pi;
+
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ {
+ /* Find procinfo for main process */
+ pi = find_procinfo (PIDGET (inferior_ptid), 0);
+ if (pi)
+ destroy_procinfo (pi);
+ }
+ unpush_target (&procfs_ops);
+ generic_mourn_inferior ();
+}
+
+/*
+ * Function: init_inferior
+ *
+ * When GDB forks to create a runnable inferior process,
+ * this function is called on the parent side of the fork.
+ * It's job is to do whatever is necessary to make the child
+ * ready to be debugged, and then wait for the child to synchronize.
+ */
+
+static void
+procfs_init_inferior (int pid)
+{
+ procinfo *pi;
+ gdb_sigset_t signals;
+ int fail;
+
+ /* This routine called on the parent side (GDB side)
+ after GDB forks the inferior. */
+
+ push_target (&procfs_ops);
+
+ if ((pi = create_procinfo (pid, 0)) == NULL)
+ perror ("procfs: out of memory in 'init_inferior'");
+
+ if (!open_procinfo_files (pi, FD_CTL))
+ proc_error (pi, "init_inferior, open_proc_files", __LINE__);
+
+ /*
+ xmalloc // done
+ open_procinfo_files // done
+ link list // done
+ prfillset (trace)
+ procfs_notice_signals
+ prfillset (fault)
+ prdelset (FLTPAGE)
+ PIOCWSTOP
+ PIOCSFAULT
+ */
+
+ /* If not stopped yet, wait for it to stop. */
+ if (!(proc_flags (pi) & PR_STOPPED) &&
+ !(proc_wait_for_stop (pi)))
+ dead_procinfo (pi, "init_inferior: wait_for_stop failed", KILL);
+
+ /* Save some of the /proc state to be restored if we detach. */
+ /* FIXME: Why? In case another debugger was debugging it?
+ We're it's parent, for Ghu's sake! */
+ if (!proc_get_traced_signals (pi, &pi->saved_sigset))
+ proc_error (pi, "init_inferior, get_traced_signals", __LINE__);
+ if (!proc_get_held_signals (pi, &pi->saved_sighold))
+ proc_error (pi, "init_inferior, get_held_signals", __LINE__);
+ if (!proc_get_traced_faults (pi, &pi->saved_fltset))
+ proc_error (pi, "init_inferior, get_traced_faults", __LINE__);
+ if (!proc_get_traced_sysentry (pi, pi->saved_entryset))
+ proc_error (pi, "init_inferior, get_traced_sysentry", __LINE__);
+ if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
+ proc_error (pi, "init_inferior, get_traced_sysexit", __LINE__);
+
+ /* Register to trace selected signals in the child. */
+ prfillset (&signals);
+ if (!register_gdb_signals (pi, &signals))
+ proc_error (pi, "init_inferior, register_signals", __LINE__);
+
+ if ((fail = procfs_debug_inferior (pi)) != 0)
+ proc_error (pi, "init_inferior (procfs_debug_inferior)", fail);
+
+ /* FIXME: logically, we should really be turning OFF run-on-last-close,
+ and possibly even turning ON kill-on-last-close at this point. But
+ I can't make that change without careful testing which I don't have
+ time to do right now... */
+ /* Turn on run-on-last-close flag so that the child
+ will die if GDB goes away for some reason. */
+ if (!proc_set_run_on_last_close (pi))
+ proc_error (pi, "init_inferior, set_RLC", __LINE__);
+
+ /* The 'process ID' we return to GDB is composed of
+ the actual process ID plus the lwp ID. */
+ inferior_ptid = MERGEPID (pi->pid, proc_get_current_thread (pi));
+
+ /* Typically two, one trap to exec the shell, one to exec the
+ program being debugged. Defined by "inferior.h". */
+ startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+}
+
+/*
+ * Function: set_exec_trap
+ *
+ * When GDB forks to create a new process, this function is called
+ * on the child side of the fork before GDB exec's the user program.
+ * Its job is to make the child minimally debuggable, so that the
+ * parent GDB process can connect to the child and take over.
+ * This function should do only the minimum to make that possible,
+ * and to synchronize with the parent process. The parent process
+ * should take care of the details.
+ */
+
+static void
+procfs_set_exec_trap (void)
+{
+ /* This routine called on the child side (inferior side)
+ after GDB forks the inferior. It must use only local variables,
+ because it may be sharing data space with its parent. */
+
+ procinfo *pi;
+ sysset_t *exitset;
+
+ if ((pi = create_procinfo (getpid (), 0)) == NULL)
+ perror_with_name ("procfs: create_procinfo failed in child.");
+
+ if (open_procinfo_files (pi, FD_CTL) == 0)
+ {
+ proc_warn (pi, "set_exec_trap, open_proc_files", __LINE__);
+ gdb_flush (gdb_stderr);
+ /* no need to call "dead_procinfo", because we're going to exit. */
+ _exit (127);
+ }
+
+#ifdef PRFS_STOPEXEC /* defined on OSF */
+ /* OSF method for tracing exec syscalls. Quoting:
+ Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace
+ exits from exec system calls because of the user level loader. */
+ /* FIXME: make nice and maybe move into an access function. */
+ {
+ int prfs_flags;
+
+ if (ioctl (pi->ctl_fd, PIOCGSPCACT, &prfs_flags) < 0)
+ {
+ proc_warn (pi, "set_exec_trap (PIOCGSPCACT)", __LINE__);
+ gdb_flush (gdb_stderr);
+ _exit (127);
+ }
+ prfs_flags |= PRFS_STOPEXEC;
+
+ if (ioctl (pi->ctl_fd, PIOCSSPCACT, &prfs_flags) < 0)
+ {
+ proc_warn (pi, "set_exec_trap (PIOCSSPCACT)", __LINE__);
+ gdb_flush (gdb_stderr);
+ _exit (127);
+ }
+ }
+#else /* not PRFS_STOPEXEC */
+ /* Everyone else's (except OSF) method for tracing exec syscalls */
+ /* 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. */
+
+ exitset = sysset_t_alloc (pi);
+ gdb_premptysysset (exitset);
+#ifdef SYS_exec
+ gdb_praddsysset (exitset, SYS_exec);
+#endif
+#ifdef SYS_execve
+ gdb_praddsysset (exitset, SYS_execve);
+#endif
+#ifdef SYS_execv
+ gdb_praddsysset (exitset, SYS_execv);
+#endif
+#ifdef DYNAMIC_SYSCALLS
+ {
+ int callnum = find_syscall (pi, "execve");
+
+ if (callnum >= 0)
+ gdb_praddsysset (exitset, callnum);
+
+ callnum = find_syscall (pi, "ra_execve");
+ if (callnum >= 0)
+ gdb_praddsysset (exitset, callnum);
+ }
+#endif /* DYNAMIC_SYSCALLS */
+
+ if (!proc_set_traced_sysexit (pi, exitset))
+ {
+ proc_warn (pi, "set_exec_trap, set_traced_sysexit", __LINE__);
+ gdb_flush (gdb_stderr);
+ _exit (127);
+ }
+#endif /* PRFS_STOPEXEC */
+
+ /* FIXME: should this be done in the parent instead? */
+ /* Turn off inherit on fork flag so that all grand-children
+ of gdb start with tracing flags cleared. */
+ if (!proc_unset_inherit_on_fork (pi))
+ proc_warn (pi, "set_exec_trap, unset_inherit", __LINE__);
+
+ /* Turn off run on last close flag, so that the child process
+ cannot run away just because we close our handle on it.
+ We want it to wait for the parent to attach. */
+ if (!proc_unset_run_on_last_close (pi))
+ proc_warn (pi, "set_exec_trap, unset_RLC", __LINE__);
+
+ /* FIXME: No need to destroy the procinfo --
+ we have our own address space, and we're about to do an exec! */
+ /*destroy_procinfo (pi);*/
+}
+
+/*
+ * Function: create_inferior
+ *
+ * This function is called BEFORE gdb forks the inferior process.
+ * Its only real responsibility is to set things up for the fork,
+ * and tell GDB which two functions to call after the fork (one
+ * for the parent, and one for the child).
+ *
+ * This function does a complicated search for a unix shell program,
+ * which it then uses to parse arguments and environment variables
+ * to be sent to the child. I wonder whether this code could not
+ * be abstracted out and shared with other unix targets such as
+ * infptrace?
+ */
+
+static void
+procfs_create_inferior (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 ("procfs:%d -- Can't find shell %s in PATH",
+ __LINE__, shell_file);
+
+ shell_file = tryname;
+ }
+
+ fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
+ procfs_init_inferior, NULL, shell_file);
+
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+}
+
+/*
+ * Function: notice_thread
+ *
+ * Callback for find_new_threads.
+ * Calls "add_thread".
+ */
+
+static int
+procfs_notice_thread (procinfo *pi, procinfo *thread, void *ptr)
+{
+ ptid_t gdb_threadid = MERGEPID (pi->pid, thread->tid);
+
+ if (!in_thread_list (gdb_threadid))
+ add_thread (gdb_threadid);
+
+ return 0;
+}
+
+/*
+ * Function: target_find_new_threads
+ *
+ * Query all the threads that the target knows about,
+ * and give them back to GDB to add to its list.
+ */
+
+void
+procfs_find_new_threads (void)
+{
+ procinfo *pi;
+
+ /* Find procinfo for main process */
+ pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ proc_update_threads (pi);
+ proc_iterate_over_threads (pi, procfs_notice_thread, NULL);
+}
+
+/*
+ * Function: target_thread_alive
+ *
+ * Return true if the thread is still 'alive'.
+ *
+ * This guy doesn't really seem to be doing his job.
+ * Got to investigate how to tell when a thread is really gone.
+ */
+
+static int
+procfs_thread_alive (ptid_t ptid)
+{
+ int proc, thread;
+ procinfo *pi;
+
+ proc = PIDGET (ptid);
+ thread = TIDGET (ptid);
+ /* If I don't know it, it ain't alive! */
+ if ((pi = find_procinfo (proc, thread)) == NULL)
+ return 0;
+
+ /* If I can't get its status, it ain't alive!
+ What's more, I need to forget about it! */
+ if (!proc_get_status (pi))
+ {
+ destroy_procinfo (pi);
+ return 0;
+ }
+ /* I couldn't have got its status if it weren't alive, so it's alive. */
+ return 1;
+}
+
+/*
+ * Function: target_pid_to_str
+ *
+ * Return a string to be used to identify the thread in
+ * the "info threads" display.
+ */
+
+char *
+procfs_pid_to_str (ptid_t ptid)
+{
+ static char buf[80];
+ int proc, thread;
+ procinfo *pi;
+
+ proc = PIDGET (ptid);
+ thread = TIDGET (ptid);
+ pi = find_procinfo (proc, thread);
+
+ if (thread == 0)
+ sprintf (buf, "Process %d", proc);
+ else
+ sprintf (buf, "LWP %d", thread);
+ return &buf[0];
+}
+
+/*
+ * Function: procfs_set_watchpoint
+ * Insert a watchpoint
+ */
+
+int
+procfs_set_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rwflag,
+ int after)
+{
+#ifndef UNIXWARE
+#ifndef AIX5
+ int pflags = 0;
+ procinfo *pi;
+
+ pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
+ PIDGET (inferior_ptid) : PIDGET (ptid), 0);
+
+ /* Translate from GDB's flags to /proc's */
+ if (len > 0) /* len == 0 means delete watchpoint */
+ {
+ switch (rwflag) { /* FIXME: need an enum! */
+ case hw_write: /* default watchpoint (write) */
+ pflags = WRITE_WATCHFLAG;
+ break;
+ case hw_read: /* read watchpoint */
+ pflags = READ_WATCHFLAG;
+ break;
+ case hw_access: /* access watchpoint */
+ pflags = READ_WATCHFLAG | WRITE_WATCHFLAG;
+ break;
+ case hw_execute: /* execution HW breakpoint */
+ pflags = EXEC_WATCHFLAG;
+ break;
+ default: /* Something weird. Return error. */
+ return -1;
+ }
+ if (after) /* Stop after r/w access is completed. */
+ pflags |= AFTER_WATCHFLAG;
+ }
+
+ if (!proc_set_watchpoint (pi, addr, len, pflags))
+ {
+ if (errno == E2BIG) /* Typical error for no resources */
+ return -1; /* fail */
+ /* GDB may try to remove the same watchpoint twice.
+ If a remove request returns no match, don't error. */
+ if (errno == ESRCH && len == 0)
+ return 0; /* ignore */
+ proc_error (pi, "set_watchpoint", __LINE__);
+ }
+#endif /* AIX5 */
+#endif /* UNIXWARE */
+ return 0;
+}
+
+/* Return 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_watchpoint. CNT is the number of watchpoints used so
+ far.
+
+ Note: procfs_can_use_hw_breakpoint() is not yet used by all
+ procfs.c targets due to the fact that some of them still define
+ TARGET_CAN_USE_HARDWARE_WATCHPOINT. */
+
+static int
+procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
+{
+#ifndef TARGET_HAS_HARDWARE_WATCHPOINTS
+ return 0;
+#else
+ /* Due to the way that proc_set_watchpoint() is implemented, host
+ and target pointers must be of the same size. If they are not,
+ we can't use hardware watchpoints. This limitation is due to the
+ fact that proc_set_watchpoint() calls
+ procfs_address_to_host_pointer(); a close inspection of
+ procfs_address_to_host_pointer will reveal that an internal error
+ will be generated when the host and target pointer sizes are
+ different. */
+ if (sizeof (void *) != TYPE_LENGTH (builtin_type_void_data_ptr))
+ return 0;
+
+ /* Other tests here??? */
+
+ return 1;
+#endif
+}
+
+/*
+ * Function: stopped_by_watchpoint
+ *
+ * Returns non-zero if process is stopped on a hardware watchpoint fault,
+ * else returns zero.
+ */
+
+int
+procfs_stopped_by_watchpoint (ptid_t ptid)
+{
+ procinfo *pi;
+
+ pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
+ PIDGET (inferior_ptid) : PIDGET (ptid), 0);
+
+ if (!pi) /* If no process, then not stopped by watchpoint! */
+ return 0;
+
+ if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
+ {
+ if (proc_why (pi) == PR_FAULTED)
+ {
+#ifdef FLTWATCH
+ if (proc_what (pi) == FLTWATCH)
+ return 1;
+#endif
+#ifdef FLTKWATCH
+ if (proc_what (pi) == FLTKWATCH)
+ return 1;
+#endif
+ }
+ }
+ return 0;
+}
+
+#ifdef TM_I386SOL2_H
+/*
+ * Function: procfs_find_LDT_entry
+ *
+ * Input:
+ * ptid_t ptid; // The GDB-style pid-plus-LWP.
+ *
+ * Return:
+ * pointer to the corresponding LDT entry.
+ */
+
+struct ssd *
+procfs_find_LDT_entry (ptid_t ptid)
+{
+ gdb_gregset_t *gregs;
+ int key;
+ procinfo *pi;
+
+ /* Find procinfo for the lwp. */
+ if ((pi = find_procinfo (PIDGET (ptid), TIDGET (ptid))) == NULL)
+ {
+ warning ("procfs_find_LDT_entry: could not find procinfo for %d:%d.",
+ PIDGET (ptid), TIDGET (ptid));
+ return NULL;
+ }
+ /* get its general registers. */
+ if ((gregs = proc_get_gregs (pi)) == NULL)
+ {
+ warning ("procfs_find_LDT_entry: could not read gregs for %d:%d.",
+ PIDGET (ptid), TIDGET (ptid));
+ return NULL;
+ }
+ /* Now extract the GS register's lower 16 bits. */
+ key = (*gregs)[GS] & 0xffff;
+
+ /* Find the matching entry and return it. */
+ return proc_get_LDT_entry (pi, key);
+}
+#endif /* TM_I386SOL2_H */
+
+/*
+ * Memory Mappings Functions:
+ */
+
+/*
+ * Function: iterate_over_mappings
+ *
+ * Call a callback function once for each mapping, passing it the mapping,
+ * an optional secondary callback function, and some optional opaque data.
+ * Quit and return the first non-zero value returned from the callback.
+ *
+ * Arguments:
+ * pi -- procinfo struct for the process to be mapped.
+ * func -- callback function to be called by this iterator.
+ * data -- optional opaque data to be passed to the callback function.
+ * child_func -- optional secondary function pointer to be passed
+ * to the child function.
+ *
+ * Return: First non-zero return value from the callback function,
+ * or zero.
+ */
+
+static int
+iterate_over_mappings (procinfo *pi, int (*child_func) (), void *data,
+ int (*func) (struct prmap *map,
+ int (*child_func) (),
+ void *data))
+{
+ char pathname[MAX_PROC_NAME_SIZE];
+ struct prmap *prmaps;
+ struct prmap *prmap;
+ int funcstat;
+ int map_fd;
+ int nmap;
+#ifdef NEW_PROC_API
+ struct stat sbuf;
+#endif
+
+ /* Get the number of mappings, allocate space,
+ and read the mappings into prmaps. */
+#ifdef NEW_PROC_API
+ /* Open map fd. */
+ sprintf (pathname, "/proc/%d/map", pi->pid);
+ if ((map_fd = open (pathname, O_RDONLY)) < 0)
+ proc_error (pi, "iterate_over_mappings (open)", __LINE__);
+
+ /* Make sure it gets closed again. */
+ make_cleanup_close (map_fd);
+
+ /* Use stat to determine the file size, and compute
+ the number of prmap_t objects it contains. */
+ if (fstat (map_fd, &sbuf) != 0)
+ proc_error (pi, "iterate_over_mappings (fstat)", __LINE__);
+
+ nmap = sbuf.st_size / sizeof (prmap_t);
+ prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
+ if (read (map_fd, (char *) prmaps, nmap * sizeof (*prmaps))
+ != (nmap * sizeof (*prmaps)))
+ proc_error (pi, "iterate_over_mappings (read)", __LINE__);
+#else
+ /* Use ioctl command PIOCNMAP to get number of mappings. */
+ if (ioctl (pi->ctl_fd, PIOCNMAP, &nmap) != 0)
+ proc_error (pi, "iterate_over_mappings (PIOCNMAP)", __LINE__);
+
+ prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
+ if (ioctl (pi->ctl_fd, PIOCMAP, prmaps) != 0)
+ proc_error (pi, "iterate_over_mappings (PIOCMAP)", __LINE__);
+#endif
+
+ for (prmap = prmaps; nmap > 0; prmap++, nmap--)
+ if ((funcstat = (*func) (prmap, child_func, data)) != 0)
+ return funcstat;
+
+ return 0;
+}
+
+/*
+ * Function: solib_mappings_callback
+ *
+ * Calls the supplied callback function once for each mapped address
+ * space in the process. The callback function receives an open
+ * file descriptor for the file corresponding to that mapped
+ * address space (if there is one), and the base address of the
+ * mapped space. Quit when the callback function returns a
+ * nonzero value, or at teh end of the mappings.
+ *
+ * Returns: the first non-zero return value of the callback function,
+ * or zero.
+ */
+
+int solib_mappings_callback (struct prmap *map,
+ int (*func) (int, CORE_ADDR),
+ void *data)
+{
+ procinfo *pi = data;
+ int fd;
+
+#ifdef NEW_PROC_API
+ char name[MAX_PROC_NAME_SIZE + sizeof (map->pr_mapname)];
+
+ if (map->pr_vaddr == 0 && map->pr_size == 0)
+ return -1; /* sanity */
+
+ if (map->pr_mapname[0] == 0)
+ {
+ fd = -1; /* no map file */
+ }
+ else
+ {
+ sprintf (name, "/proc/%d/object/%s", pi->pid, map->pr_mapname);
+ /* Note: caller's responsibility to close this fd! */
+ fd = open_with_retry (name, O_RDONLY);
+ /* Note: we don't test the above call for failure;
+ we just pass the FD on as given. Sometimes there is
+ no file, so the open may return failure, but that's
+ not a problem. */
+ }
+#else
+ fd = ioctl (pi->ctl_fd, PIOCOPENM, &map->pr_vaddr);
+ /* Note: we don't test the above call for failure;
+ we just pass the FD on as given. Sometimes there is
+ no file, so the ioctl may return failure, but that's
+ not a problem. */
+#endif
+ return (*func) (fd, (CORE_ADDR) map->pr_vaddr);
+}
+
+/*
+ * Function: proc_iterate_over_mappings
+ *
+ * Uses the unified "iterate_over_mappings" function
+ * to implement the exported interface to solib-svr4.c.
+ *
+ * Given a pointer to a function, call that function once for every
+ * mapped address space in the process. The callback function
+ * receives an open file descriptor for the file corresponding to
+ * that mapped address space (if there is one), and the base address
+ * of the mapped space. Quit when the callback function returns a
+ * nonzero value, or at teh end of the mappings.
+ *
+ * Returns: the first non-zero return value of the callback function,
+ * or zero.
+ */
+
+int
+proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
+{
+ procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+
+ return iterate_over_mappings (pi, func, pi, solib_mappings_callback);
+}
+
+/*
+ * Function: find_memory_regions_callback
+ *
+ * Implements the to_find_memory_regions method.
+ * Calls an external function for each memory region.
+ * External function will have the signiture:
+ *
+ * int callback (CORE_ADDR vaddr,
+ * unsigned long size,
+ * int read, int write, int execute,
+ * void *data);
+ *
+ * Returns the integer value returned by the callback.
+ */
+
+static int
+find_memory_regions_callback (struct prmap *map,
+ int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ return (*func) ((CORE_ADDR) map->pr_vaddr,
+ map->pr_size,
+ (map->pr_mflags & MA_READ) != 0,
+ (map->pr_mflags & MA_WRITE) != 0,
+ (map->pr_mflags & MA_EXEC) != 0,
+ data);
+}
+
+/*
+ * Function: proc_find_memory_regions
+ *
+ * External interface. Calls a callback function once for each
+ * mapped memory region in the child process, passing as arguments
+ * CORE_ADDR virtual_address,
+ * unsigned long size,
+ * int read, TRUE if region is readable by the child
+ * int write, TRUE if region is writable by the child
+ * int execute TRUE if region is executable by the child.
+ *
+ * Stops iterating and returns the first non-zero value
+ * returned by the callback.
+ */
+
+static int
+proc_find_memory_regions (int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+
+ return iterate_over_mappings (pi, func, data,
+ find_memory_regions_callback);
+}
+
+/*
+ * Function: mappingflags
+ *
+ * Returns an ascii representation of a memory mapping's flags.
+ */
+
+static char *
+mappingflags (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);
+}
+
+/*
+ * Function: info_mappings_callback
+ *
+ * Callback function, does the actual work for 'info proc mappings'.
+ */
+
+static int
+info_mappings_callback (struct prmap *map, int (*ignore) (), void *unused)
+{
+ char *data_fmt_string;
+
+ if (TARGET_ADDR_BIT == 32)
+ data_fmt_string = "\t%#10lx %#10lx %#10x %#10x %7s\n";
+ else
+ data_fmt_string = " %#18lx %#18lx %#10x %#10x %7s\n";
+
+ printf_filtered (data_fmt_string,
+ (unsigned long) map->pr_vaddr,
+ (unsigned long) map->pr_vaddr + map->pr_size - 1,
+ map->pr_size,
+#ifdef PCAGENT /* Horrible hack: only defined on Solaris 2.6+ */
+ (unsigned int) map->pr_offset,
+#else
+ map->pr_off,
+#endif
+ mappingflags (map->pr_mflags));
+
+ return 0;
+}
+
+/*
+ * Function: info_proc_mappings
+ *
+ * Implement the "info proc mappings" subcommand.
+ */
+
+static void
+info_proc_mappings (procinfo *pi, int summary)
+{
+ char *header_fmt_string;
+
+ if (TARGET_PTR_BIT == 32)
+ header_fmt_string = "\t%10s %10s %10s %10s %7s\n";
+ else
+ header_fmt_string = " %18s %18s %10s %10s %7s\n";
+
+ if (summary)
+ return; /* No output for summary mode. */
+
+ printf_filtered ("Mapped address spaces:\n\n");
+ printf_filtered (header_fmt_string,
+ "Start Addr",
+ " End Addr",
+ " Size",
+ " Offset",
+ "Flags");
+
+ iterate_over_mappings (pi, NULL, NULL, info_mappings_callback);
+ printf_filtered ("\n");
+}
+
+/*
+ * Function: info_proc_cmd
+ *
+ * Implement the "info proc" command.
+ */
+
+static void
+info_proc_cmd (char *args, int from_tty)
+{
+ struct cleanup *old_chain;
+ procinfo *process = NULL;
+ procinfo *thread = NULL;
+ char **argv = NULL;
+ char *tmp = NULL;
+ int pid = 0;
+ int tid = 0;
+ int mappings = 0;
+
+ old_chain = make_cleanup (null_cleanup, 0);
+ if (args)
+ {
+ if ((argv = buildargv (args)) == NULL)
+ nomem (0);
+ else
+ make_cleanup_freeargv (argv);
+ }
+ while (argv != NULL && *argv != NULL)
+ {
+ if (isdigit (argv[0][0]))
+ {
+ pid = strtoul (argv[0], &tmp, 10);
+ if (*tmp == '/')
+ tid = strtoul (++tmp, NULL, 10);
+ }
+ else if (argv[0][0] == '/')
+ {
+ tid = strtoul (argv[0] + 1, NULL, 10);
+ }
+ else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+ {
+ mappings = 1;
+ }
+ else
+ {
+ /* [...] */
+ }
+ argv++;
+ }
+ if (pid == 0)
+ pid = PIDGET (inferior_ptid);
+ if (pid == 0)
+ error ("No current process: you must name one.");
+ else
+ {
+ /* Have pid, will travel.
+ First see if it's a process we're already debugging. */
+ process = find_procinfo (pid, 0);
+ if (process == NULL)
+ {
+ /* No. So open a procinfo for it, but
+ remember to close it again when finished. */
+ process = create_procinfo (pid, 0);
+ make_cleanup (do_destroy_procinfo_cleanup, process);
+ if (!open_procinfo_files (process, FD_CTL))
+ proc_error (process, "info proc, open_procinfo_files", __LINE__);
+ }
+ }
+ if (tid != 0)
+ thread = create_procinfo (pid, tid);
+
+ if (process)
+ {
+ printf_filtered ("process %d flags:\n", process->pid);
+ proc_prettyprint_flags (proc_flags (process), 1);
+ if (proc_flags (process) & (PR_STOPPED | PR_ISTOP))
+ proc_prettyprint_why (proc_why (process), proc_what (process), 1);
+ if (proc_get_nthreads (process) > 1)
+ printf_filtered ("Process has %d threads.\n",
+ proc_get_nthreads (process));
+ }
+ if (thread)
+ {
+ printf_filtered ("thread %d flags:\n", thread->tid);
+ proc_prettyprint_flags (proc_flags (thread), 1);
+ if (proc_flags (thread) & (PR_STOPPED | PR_ISTOP))
+ proc_prettyprint_why (proc_why (thread), proc_what (thread), 1);
+ }
+
+ if (mappings)
+ {
+ info_proc_mappings (process, 0);
+ }
+
+ do_cleanups (old_chain);
+}
+
+static void
+proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode)
+{
+ procinfo *pi;
+ sysset_t *sysset;
+ int syscallnum = 0;
+
+ if (PIDGET (inferior_ptid) <= 0)
+ error ("you must be debugging a process to use this command.");
+
+ if (args == NULL || args[0] == 0)
+ error_no_arg ("system call to trace");
+
+ pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ if (isdigit (args[0]))
+ {
+ syscallnum = atoi (args);
+ if (entry_or_exit == PR_SYSENTRY)
+ sysset = proc_get_traced_sysentry (pi, NULL);
+ else
+ sysset = proc_get_traced_sysexit (pi, NULL);
+
+ if (sysset == NULL)
+ proc_error (pi, "proc-trace, get_traced_sysset", __LINE__);
+
+ if (mode == FLAG_SET)
+ gdb_praddsysset (sysset, syscallnum);
+ else
+ gdb_prdelsysset (sysset, syscallnum);
+
+ if (entry_or_exit == PR_SYSENTRY)
+ {
+ if (!proc_set_traced_sysentry (pi, sysset))
+ proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__);
+ }
+ else
+ {
+ if (!proc_set_traced_sysexit (pi, sysset))
+ proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__);
+ }
+ }
+}
+
+static void
+proc_trace_sysentry_cmd (char *args, int from_tty)
+{
+ proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_SET);
+}
+
+static void
+proc_trace_sysexit_cmd (char *args, int from_tty)
+{
+ proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_SET);
+}
+
+static void
+proc_untrace_sysentry_cmd (char *args, int from_tty)
+{
+ proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_RESET);
+}
+
+static void
+proc_untrace_sysexit_cmd (char *args, int from_tty)
+{
+ proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_RESET);
+}
+
+
+void
+_initialize_procfs (void)
+{
+ init_procfs_ops ();
+ add_target (&procfs_ops);
+ add_info ("proc", info_proc_cmd,
+ "Show /proc process information about any running process.\n\
+Specify process id, or use the program being debugged by default.\n\
+Specify keyword 'mappings' for detailed info on memory mappings.");
+ add_com ("proc-trace-entry", no_class, proc_trace_sysentry_cmd,
+ "Give a trace of entries into the syscall.");
+ add_com ("proc-trace-exit", no_class, proc_trace_sysexit_cmd,
+ "Give a trace of exits from the syscall.");
+ add_com ("proc-untrace-entry", no_class, proc_untrace_sysentry_cmd,
+ "Cancel a trace of entries into the syscall.");
+ add_com ("proc-untrace-exit", no_class, proc_untrace_sysexit_cmd,
+ "Cancel a trace of exits from the syscall.");
+}
+
+/* =================== END, GDB "MODULE" =================== */
+
+
+
+/* miscellaneous stubs: */
+/* The following satisfy a few random symbols mostly created by */
+/* the solaris threads implementation, which I will chase down */
+/* later. */
+
+/*
+ * Return a pid for which we guarantee
+ * we will be able to find a 'live' procinfo.
+ */
+
+ptid_t
+procfs_first_available (void)
+{
+ return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1);
+}
+
+/* =================== GCORE .NOTE "MODULE" =================== */
+#if defined (UNIXWARE) || defined (PIOCOPENLWP) || defined (PCAGENT)
+/* gcore only implemented on solaris and unixware (so far) */
+
+static char *
+procfs_do_thread_registers (bfd *obfd, ptid_t ptid,
+ char *note_data, int *note_size)
+{
+ gdb_gregset_t gregs;
+ gdb_fpregset_t fpregs;
+ unsigned long merged_pid;
+
+ merged_pid = TIDGET (ptid) << 16 | PIDGET (ptid);
+
+ fill_gregset (&gregs, -1);
+#if defined (UNIXWARE)
+ note_data = (char *) elfcore_write_lwpstatus (obfd,
+ note_data,
+ note_size,
+ merged_pid,
+ stop_signal,
+ &gregs);
+#else
+ note_data = (char *) elfcore_write_prstatus (obfd,
+ note_data,
+ note_size,
+ merged_pid,
+ stop_signal,
+ &gregs);
+#endif
+ fill_fpregset (&fpregs, -1);
+ note_data = (char *) elfcore_write_prfpreg (obfd,
+ note_data,
+ note_size,
+ &fpregs,
+ sizeof (fpregs));
+ return note_data;
+}
+
+struct procfs_corefile_thread_data {
+ bfd *obfd;
+ char *note_data;
+ int *note_size;
+};
+
+static int
+procfs_corefile_thread_callback (procinfo *pi, procinfo *thread, void *data)
+{
+ struct procfs_corefile_thread_data *args = data;
+
+ if (pi != NULL && thread->tid != 0)
+ {
+ ptid_t saved_ptid = inferior_ptid;
+ inferior_ptid = MERGEPID (pi->pid, thread->tid);
+ args->note_data = procfs_do_thread_registers (args->obfd, inferior_ptid,
+ args->note_data,
+ args->note_size);
+ inferior_ptid = saved_ptid;
+ }
+ return 0;
+}
+
+static char *
+procfs_make_note_section (bfd *obfd, int *note_size)
+{
+ struct cleanup *old_chain;
+ gdb_gregset_t gregs;
+ gdb_fpregset_t fpregs;
+ char fname[16] = {'\0'};
+ char psargs[80] = {'\0'};
+ procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ char *note_data = NULL;
+ char *inf_args;
+ struct procfs_corefile_thread_data thread_args;
+ char *auxv;
+ int auxv_len;
+
+ if (get_exec_file (0))
+ {
+ strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
+ strncpy (psargs, get_exec_file (0),
+ sizeof (psargs));
+
+ inf_args = get_inferior_args ();
+ if (inf_args && *inf_args &&
+ strlen (inf_args) < ((int) sizeof (psargs) - (int) strlen (psargs)))
+ {
+ strncat (psargs, " ",
+ sizeof (psargs) - strlen (psargs));
+ strncat (psargs, inf_args,
+ sizeof (psargs) - strlen (psargs));
+ }
+ }
+
+ note_data = (char *) elfcore_write_prpsinfo (obfd,
+ note_data,
+ note_size,
+ fname,
+ psargs);
+
+#ifdef UNIXWARE
+ fill_gregset (&gregs, -1);
+ note_data = elfcore_write_pstatus (obfd, note_data, note_size,
+ PIDGET (inferior_ptid),
+ stop_signal, &gregs);
+#endif
+
+ thread_args.obfd = obfd;
+ thread_args.note_data = note_data;
+ thread_args.note_size = note_size;
+ proc_iterate_over_threads (pi, procfs_corefile_thread_callback, &thread_args);
+
+ if (thread_args.note_data == note_data)
+ {
+ /* iterate_over_threads didn't come up with any threads;
+ just use inferior_ptid. */
+ note_data = procfs_do_thread_registers (obfd, inferior_ptid,
+ note_data, note_size);
+ }
+ else
+ {
+ note_data = thread_args.note_data;
+ }
+
+ auxv_len = target_auxv_read (&current_target, &auxv);
+ if (auxv_len > 0)
+ {
+ note_data = elfcore_write_note (obfd, note_data, note_size,
+ "CORE", NT_AUXV, auxv, auxv_len);
+ xfree (auxv);
+ }
+
+ make_cleanup (xfree, note_data);
+ return note_data;
+}
+#else /* !(Solaris or Unixware) */
+static char *
+procfs_make_note_section (bfd *obfd, int *note_size)
+{
+ error ("gcore not implemented for this host.");
+ return NULL; /* lint */
+}
+#endif /* Solaris or Unixware */
+/* =================== END GCORE .NOTE "MODULE" =================== */
diff --git a/contrib/gdb/gdb/regcache.c b/contrib/gdb/gdb/regcache.c
new file mode 100644
index 0000000..154fc5e
--- /dev/null
+++ b/contrib/gdb/gdb/regcache.c
@@ -0,0 +1,1742 @@
+/* Cache and manage the values of registers for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
+ 2001, 2002, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "gdbarch.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "reggroups.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdbcmd.h" /* For maintenanceprintlist. */
+
+/*
+ * DATA STRUCTURE
+ *
+ * Here is the actual register cache.
+ */
+
+/* Per-architecture object describing the layout of a register cache.
+ Computed once when the architecture is created */
+
+struct gdbarch_data *regcache_descr_handle;
+
+struct regcache_descr
+{
+ /* The architecture this descriptor belongs to. */
+ struct gdbarch *gdbarch;
+
+ /* Is this a ``legacy'' register cache? Such caches reserve space
+ for raw and pseudo registers and allow access to both. */
+ int legacy_p;
+
+ /* The raw register cache. Each raw (or hard) register is supplied
+ by the target interface. The raw cache should not contain
+ redundant information - if the PC is constructed from two
+ registers then those regigisters and not the PC lives in the raw
+ cache. */
+ int nr_raw_registers;
+ long sizeof_raw_registers;
+ long sizeof_raw_register_valid_p;
+
+ /* The cooked register space. Each cooked register in the range
+ [0..NR_RAW_REGISTERS) is direct-mapped onto the corresponding raw
+ register. The remaining [NR_RAW_REGISTERS
+ .. NR_COOKED_REGISTERS) (a.k.a. pseudo regiters) are mapped onto
+ both raw registers and memory by the architecture methods
+ gdbarch_register_read and gdbarch_register_write. */
+ int nr_cooked_registers;
+ long sizeof_cooked_registers;
+ long sizeof_cooked_register_valid_p;
+
+ /* Offset and size (in 8 bit bytes), of reach register in the
+ register cache. All registers (including those in the range
+ [NR_RAW_REGISTERS .. NR_COOKED_REGISTERS) are given an offset.
+ Assigning all registers an offset makes it possible to keep
+ legacy code, such as that found in read_register_bytes() and
+ write_register_bytes() working. */
+ long *register_offset;
+ long *sizeof_register;
+
+ /* Cached table containing the type of each register. */
+ struct type **register_type;
+};
+
+static void
+init_legacy_regcache_descr (struct gdbarch *gdbarch,
+ struct regcache_descr *descr)
+{
+ int i;
+ /* FIXME: cagney/2002-05-11: gdbarch_data() should take that
+ ``gdbarch'' as a parameter. */
+ gdb_assert (gdbarch != NULL);
+
+ /* Compute the offset of each register. Legacy architectures define
+ DEPRECATED_REGISTER_BYTE() so use that. */
+ /* FIXME: cagney/2002-11-07: Instead of using
+ DEPRECATED_REGISTER_BYTE() this code should, as is done in
+ init_regcache_descr(), compute the offets at runtime. This
+ currently isn't possible as some ISAs define overlapping register
+ regions - see the mess in read_register_bytes() and
+ write_register_bytes() registers. */
+ descr->sizeof_register
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+ descr->register_offset
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+ for (i = 0; i < descr->nr_cooked_registers; i++)
+ {
+ /* FIXME: cagney/2001-12-04: This code shouldn't need to use
+ DEPRECATED_REGISTER_BYTE(). Unfortunately, legacy code likes
+ to lay the buffer out so that certain registers just happen
+ to overlap. Ulgh! New targets use gdbarch's register
+ read/write and entirely avoid this uglyness. */
+ descr->register_offset[i] = DEPRECATED_REGISTER_BYTE (i);
+ descr->sizeof_register[i] = DEPRECATED_REGISTER_RAW_SIZE (i);
+ gdb_assert (MAX_REGISTER_SIZE >= DEPRECATED_REGISTER_RAW_SIZE (i));
+ gdb_assert (MAX_REGISTER_SIZE >= DEPRECATED_REGISTER_VIRTUAL_SIZE (i));
+ }
+
+ /* Compute the real size of the register buffer. Start out by
+ trusting DEPRECATED_REGISTER_BYTES, but then adjust it upwards
+ should that be found to not be sufficient. */
+ /* FIXME: cagney/2002-11-05: Instead of using the macro
+ DEPRECATED_REGISTER_BYTES, this code should, as is done in
+ init_regcache_descr(), compute the total number of register bytes
+ using the accumulated offsets. */
+ descr->sizeof_cooked_registers = DEPRECATED_REGISTER_BYTES; /* OK */
+ for (i = 0; i < descr->nr_cooked_registers; i++)
+ {
+ long regend;
+ /* Keep extending the buffer so that there is always enough
+ space for all registers. The comparison is necessary since
+ legacy code is free to put registers in random places in the
+ buffer separated by holes. Once DEPRECATED_REGISTER_BYTE()
+ is killed this can be greatly simplified. */
+ regend = descr->register_offset[i] + descr->sizeof_register[i];
+ if (descr->sizeof_cooked_registers < regend)
+ descr->sizeof_cooked_registers = regend;
+ }
+ /* FIXME: cagney/2002-05-11: Shouldn't be including pseudo-registers
+ in the register cache. Unfortunately some architectures still
+ rely on this and the pseudo_register_write() method. */
+ descr->sizeof_raw_registers = descr->sizeof_cooked_registers;
+}
+
+static void *
+init_regcache_descr (struct gdbarch *gdbarch)
+{
+ int i;
+ struct regcache_descr *descr;
+ gdb_assert (gdbarch != NULL);
+
+ /* Create an initial, zero filled, table. */
+ descr = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct regcache_descr);
+ descr->gdbarch = gdbarch;
+
+ /* Total size of the register space. The raw registers are mapped
+ directly onto the raw register cache while the pseudo's are
+ either mapped onto raw-registers or memory. */
+ descr->nr_cooked_registers = NUM_REGS + NUM_PSEUDO_REGS;
+ descr->sizeof_cooked_register_valid_p = NUM_REGS + NUM_PSEUDO_REGS;
+
+ /* Fill in a table of register types. */
+ descr->register_type
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, struct type *);
+ for (i = 0; i < descr->nr_cooked_registers; i++)
+ {
+ if (gdbarch_register_type_p (gdbarch))
+ {
+ gdb_assert (!DEPRECATED_REGISTER_VIRTUAL_TYPE_P ()); /* OK */
+ descr->register_type[i] = gdbarch_register_type (gdbarch, i);
+ }
+ else
+ descr->register_type[i] = DEPRECATED_REGISTER_VIRTUAL_TYPE (i); /* OK */
+ }
+
+ /* Construct a strictly RAW register cache. Don't allow pseudo's
+ into the register cache. */
+ descr->nr_raw_registers = NUM_REGS;
+
+ /* FIXME: cagney/2002-08-13: Overallocate the register_valid_p
+ array. This pretects GDB from erant code that accesses elements
+ of the global register_valid_p[] array in the range [NUM_REGS
+ .. NUM_REGS + NUM_PSEUDO_REGS). */
+ descr->sizeof_raw_register_valid_p = descr->sizeof_cooked_register_valid_p;
+
+ /* If an old style architecture, fill in the remainder of the
+ register cache descriptor using the register macros. */
+ /* NOTE: cagney/2003-06-29: If either of DEPRECATED_REGISTER_BYTE or
+ DEPRECATED_REGISTER_RAW_SIZE are still present, things are most likely
+ totally screwed. Ex: an architecture with raw register sizes
+ smaller than what DEPRECATED_REGISTER_BYTE indicates; non
+ monotonic DEPRECATED_REGISTER_BYTE values. For GDB 6 check for
+ these nasty methods and fall back to legacy code when present.
+ Sigh! */
+ if ((!gdbarch_pseudo_register_read_p (gdbarch)
+ && !gdbarch_pseudo_register_write_p (gdbarch)
+ && !gdbarch_register_type_p (gdbarch))
+ || DEPRECATED_REGISTER_BYTE_P ()
+ || DEPRECATED_REGISTER_RAW_SIZE_P ())
+ {
+ descr->legacy_p = 1;
+ init_legacy_regcache_descr (gdbarch, descr);
+ return descr;
+ }
+
+ /* Lay out the register cache.
+
+ NOTE: cagney/2002-05-22: Only register_type() is used when
+ constructing the register cache. It is assumed that the
+ register's raw size, virtual size and type length are all the
+ same. */
+
+ {
+ long offset = 0;
+ descr->sizeof_register
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+ descr->register_offset
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+ for (i = 0; i < descr->nr_cooked_registers; i++)
+ {
+ descr->sizeof_register[i] = TYPE_LENGTH (descr->register_type[i]);
+ descr->register_offset[i] = offset;
+ offset += descr->sizeof_register[i];
+ gdb_assert (MAX_REGISTER_SIZE >= descr->sizeof_register[i]);
+ }
+ /* Set the real size of the register cache buffer. */
+ descr->sizeof_cooked_registers = offset;
+ }
+
+ /* FIXME: cagney/2002-05-22: Should only need to allocate space for
+ the raw registers. Unfortunately some code still accesses the
+ register array directly using the global registers[]. Until that
+ code has been purged, play safe and over allocating the register
+ buffer. Ulgh! */
+ descr->sizeof_raw_registers = descr->sizeof_cooked_registers;
+
+ /* Sanity check. Confirm that there is agreement between the
+ regcache and the target's redundant DEPRECATED_REGISTER_BYTE (new
+ targets should not even be defining it). */
+ for (i = 0; i < descr->nr_cooked_registers; i++)
+ {
+ if (DEPRECATED_REGISTER_BYTE_P ())
+ gdb_assert (descr->register_offset[i] == DEPRECATED_REGISTER_BYTE (i));
+#if 0
+ gdb_assert (descr->sizeof_register[i] == DEPRECATED_REGISTER_RAW_SIZE (i));
+ gdb_assert (descr->sizeof_register[i] == DEPRECATED_REGISTER_VIRTUAL_SIZE (i));
+#endif
+ }
+ /* gdb_assert (descr->sizeof_raw_registers == DEPRECATED_REGISTER_BYTES (i)); */
+
+ return descr;
+}
+
+static struct regcache_descr *
+regcache_descr (struct gdbarch *gdbarch)
+{
+ return gdbarch_data (gdbarch, regcache_descr_handle);
+}
+
+/* Utility functions returning useful register attributes stored in
+ the regcache descr. */
+
+struct type *
+register_type (struct gdbarch *gdbarch, int regnum)
+{
+ struct regcache_descr *descr = regcache_descr (gdbarch);
+ gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+ return descr->register_type[regnum];
+}
+
+/* Utility functions returning useful register attributes stored in
+ the regcache descr. */
+
+int
+register_size (struct gdbarch *gdbarch, int regnum)
+{
+ struct regcache_descr *descr = regcache_descr (gdbarch);
+ int size;
+ gdb_assert (regnum >= 0 && regnum < (NUM_REGS + NUM_PSEUDO_REGS));
+ size = descr->sizeof_register[regnum];
+ /* NB: The deprecated DEPRECATED_REGISTER_RAW_SIZE, if not provided, defaults
+ to the size of the register's type. */
+ gdb_assert (size == DEPRECATED_REGISTER_RAW_SIZE (regnum)); /* OK */
+ /* NB: Don't check the register's virtual size. It, in say the case
+ of the MIPS, may not match the raw size! */
+ return size;
+}
+
+/* The register cache for storing raw register values. */
+
+struct regcache
+{
+ struct regcache_descr *descr;
+ /* The register buffers. A read-only register cache can hold the
+ full [0 .. NUM_REGS + NUM_PSEUDO_REGS) while a read/write
+ register cache can only hold [0 .. NUM_REGS). */
+ char *registers;
+ char *register_valid_p;
+ /* Is this a read-only cache? A read-only cache is used for saving
+ the target's register state (e.g, across an inferior function
+ call or just before forcing a function return). A read-only
+ cache can only be updated via the methods regcache_dup() and
+ regcache_cpy(). The actual contents are determined by the
+ reggroup_save and reggroup_restore methods. */
+ int readonly_p;
+};
+
+struct regcache *
+regcache_xmalloc (struct gdbarch *gdbarch)
+{
+ struct regcache_descr *descr;
+ struct regcache *regcache;
+ gdb_assert (gdbarch != NULL);
+ descr = regcache_descr (gdbarch);
+ regcache = XMALLOC (struct regcache);
+ regcache->descr = descr;
+ regcache->registers
+ = XCALLOC (descr->sizeof_raw_registers, char);
+ regcache->register_valid_p
+ = XCALLOC (descr->sizeof_raw_register_valid_p, char);
+ regcache->readonly_p = 1;
+ return regcache;
+}
+
+void
+regcache_xfree (struct regcache *regcache)
+{
+ if (regcache == NULL)
+ return;
+ xfree (regcache->registers);
+ xfree (regcache->register_valid_p);
+ xfree (regcache);
+}
+
+static void
+do_regcache_xfree (void *data)
+{
+ regcache_xfree (data);
+}
+
+struct cleanup *
+make_cleanup_regcache_xfree (struct regcache *regcache)
+{
+ return make_cleanup (do_regcache_xfree, regcache);
+}
+
+/* Return REGCACHE's architecture. */
+
+struct gdbarch *
+get_regcache_arch (const struct regcache *regcache)
+{
+ return regcache->descr->gdbarch;
+}
+
+/* Return a pointer to register REGNUM's buffer cache. */
+
+static char *
+register_buffer (const struct regcache *regcache, int regnum)
+{
+ return regcache->registers + regcache->descr->register_offset[regnum];
+}
+
+void
+regcache_save (struct regcache *dst, regcache_cooked_read_ftype *cooked_read,
+ void *src)
+{
+ struct gdbarch *gdbarch = dst->descr->gdbarch;
+ char buf[MAX_REGISTER_SIZE];
+ int regnum;
+ /* The DST should be `read-only', if it wasn't then the save would
+ end up trying to write the register values back out to the
+ target. */
+ gdb_assert (dst->readonly_p);
+ /* Clear the dest. */
+ memset (dst->registers, 0, dst->descr->sizeof_cooked_registers);
+ memset (dst->register_valid_p, 0, dst->descr->sizeof_cooked_register_valid_p);
+ /* Copy over any registers (identified by their membership in the
+ save_reggroup) and mark them as valid. The full [0 .. NUM_REGS +
+ NUM_PSEUDO_REGS) range is checked since some architectures need
+ to save/restore `cooked' registers that live in memory. */
+ for (regnum = 0; regnum < dst->descr->nr_cooked_registers; regnum++)
+ {
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
+ {
+ int valid = cooked_read (src, regnum, buf);
+ if (valid)
+ {
+ memcpy (register_buffer (dst, regnum), buf,
+ register_size (gdbarch, regnum));
+ dst->register_valid_p[regnum] = 1;
+ }
+ }
+ }
+}
+
+void
+regcache_restore (struct regcache *dst,
+ regcache_cooked_read_ftype *cooked_read,
+ void *src)
+{
+ struct gdbarch *gdbarch = dst->descr->gdbarch;
+ char buf[MAX_REGISTER_SIZE];
+ int regnum;
+ /* The dst had better not be read-only. If it is, the `restore'
+ doesn't make much sense. */
+ gdb_assert (!dst->readonly_p);
+ /* Copy over any registers, being careful to only restore those that
+ were both saved and need to be restored. The full [0 .. NUM_REGS
+ + NUM_PSEUDO_REGS) range is checked since some architectures need
+ to save/restore `cooked' registers that live in memory. */
+ for (regnum = 0; regnum < dst->descr->nr_cooked_registers; regnum++)
+ {
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup))
+ {
+ int valid = cooked_read (src, regnum, buf);
+ if (valid)
+ regcache_cooked_write (dst, regnum, buf);
+ }
+ }
+}
+
+static int
+do_cooked_read (void *src, int regnum, void *buf)
+{
+ struct regcache *regcache = src;
+ if (!regcache->register_valid_p[regnum] && regcache->readonly_p)
+ /* Don't even think about fetching a register from a read-only
+ cache when the register isn't yet valid. There isn't a target
+ from which the register value can be fetched. */
+ return 0;
+ regcache_cooked_read (regcache, regnum, buf);
+ return 1;
+}
+
+
+void
+regcache_cpy (struct regcache *dst, struct regcache *src)
+{
+ int i;
+ char *buf;
+ gdb_assert (src != NULL && dst != NULL);
+ gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
+ gdb_assert (src != dst);
+ gdb_assert (src->readonly_p || dst->readonly_p);
+ if (!src->readonly_p)
+ regcache_save (dst, do_cooked_read, src);
+ else if (!dst->readonly_p)
+ regcache_restore (dst, do_cooked_read, src);
+ else
+ regcache_cpy_no_passthrough (dst, src);
+}
+
+void
+regcache_cpy_no_passthrough (struct regcache *dst, struct regcache *src)
+{
+ int i;
+ gdb_assert (src != NULL && dst != NULL);
+ gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
+ /* NOTE: cagney/2002-05-17: Don't let the caller do a no-passthrough
+ move of data into the current_regcache(). Doing this would be
+ silly - it would mean that valid_p would be completely invalid. */
+ gdb_assert (dst != current_regcache);
+ memcpy (dst->registers, src->registers, dst->descr->sizeof_raw_registers);
+ memcpy (dst->register_valid_p, src->register_valid_p,
+ dst->descr->sizeof_raw_register_valid_p);
+}
+
+struct regcache *
+regcache_dup (struct regcache *src)
+{
+ struct regcache *newbuf;
+ gdb_assert (current_regcache != NULL);
+ newbuf = regcache_xmalloc (src->descr->gdbarch);
+ regcache_cpy (newbuf, src);
+ return newbuf;
+}
+
+struct regcache *
+regcache_dup_no_passthrough (struct regcache *src)
+{
+ struct regcache *newbuf;
+ gdb_assert (current_regcache != NULL);
+ newbuf = regcache_xmalloc (src->descr->gdbarch);
+ regcache_cpy_no_passthrough (newbuf, src);
+ return newbuf;
+}
+
+int
+regcache_valid_p (struct regcache *regcache, int regnum)
+{
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ return regcache->register_valid_p[regnum];
+}
+
+char *
+deprecated_grub_regcache_for_registers (struct regcache *regcache)
+{
+ return regcache->registers;
+}
+
+/* Global structure containing the current regcache. */
+/* FIXME: cagney/2002-05-11: The two global arrays registers[] and
+ deprecated_register_valid[] currently point into this structure. */
+struct regcache *current_regcache;
+
+/* NOTE: this is a write-through cache. There is no "dirty" bit for
+ recording if the register values have been changed (eg. by the
+ user). Therefore all registers must be written back to the
+ target when appropriate. */
+
+/* REGISTERS contains the cached register values (in target byte order). */
+
+char *deprecated_registers;
+
+/* DEPRECATED_REGISTER_VALID is 0 if the register needs to be fetched,
+ 1 if it has been fetched, and
+ -1 if the register value was not available.
+
+ "Not available" indicates that the target is not not able to supply
+ the register at this state. The register may become available at a
+ later time (after the next resume). This often occures when GDB is
+ manipulating a target that contains only a snapshot of the entire
+ system being debugged - some of the registers in such a system may
+ not have been saved. */
+
+signed char *deprecated_register_valid;
+
+/* The thread/process associated with the current set of registers. */
+
+static ptid_t registers_ptid;
+
+/*
+ * FUNCTIONS:
+ */
+
+/* REGISTER_CACHED()
+
+ Returns 0 if the value is not in the cache (needs fetch).
+ >0 if the value is in the cache.
+ <0 if the value is permanently unavailable (don't ask again). */
+
+int
+register_cached (int regnum)
+{
+ return deprecated_register_valid[regnum];
+}
+
+/* Record that REGNUM's value is cached if STATE is >0, uncached but
+ fetchable if STATE is 0, and uncached and unfetchable if STATE is <0. */
+
+void
+set_register_cached (int regnum, int state)
+{
+ gdb_assert (regnum >= 0);
+ gdb_assert (regnum < current_regcache->descr->nr_raw_registers);
+ current_regcache->register_valid_p[regnum] = state;
+}
+
+/* Return whether register REGNUM is a real register. */
+
+static int
+real_register (int regnum)
+{
+ return regnum >= 0 && regnum < NUM_REGS;
+}
+
+/* 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). */
+
+/* REGISTERS_CHANGED ()
+
+ Indicate that registers may have changed, so invalidate the cache. */
+
+void
+registers_changed (void)
+{
+ int i;
+
+ registers_ptid = pid_to_ptid (-1);
+
+ /* Force cleanup of any alloca areas if using C alloca instead of
+ a builtin alloca. This particular call is used to clean up
+ areas allocated by low level target code which may build up
+ during lengthy interactions between gdb and the target before
+ gdb gives control to the user (ie watchpoints). */
+ alloca (0);
+
+ for (i = 0; i < current_regcache->descr->nr_raw_registers; i++)
+ set_register_cached (i, 0);
+
+ if (registers_changed_hook)
+ registers_changed_hook ();
+}
+
+/* DEPRECATED_REGISTERS_FETCHED ()
+
+ Indicate that all registers have been fetched, so mark them all valid. */
+
+/* NOTE: cagney/2001-12-04: This function does not set valid on the
+ pseudo-register range since pseudo registers are always supplied
+ using supply_register(). */
+/* FIXME: cagney/2001-12-04: This function is DEPRECATED. The target
+ code was blatting the registers[] array and then calling this.
+ Since targets should only be using supply_register() the need for
+ this function/hack is eliminated. */
+
+void
+deprecated_registers_fetched (void)
+{
+ int i;
+
+ for (i = 0; i < NUM_REGS; i++)
+ set_register_cached (i, 1);
+ /* Do not assume that the pseudo-regs have also been fetched.
+ Fetching all real regs NEVER accounts for pseudo-regs. */
+}
+
+/* deprecated_read_register_bytes and deprecated_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
+ and write_register_gen if you want to get at the raw register
+ contents, as it only takes a regnum as an argument, and therefore
+ can't do a partial register update.
+
+ Prior to the recent fixes to check for partial updates, both read
+ and deprecated_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
+deprecated_read_register_bytes (int in_start, char *in_buf, int in_len)
+{
+ int in_end = in_start + in_len;
+ int regnum;
+ char reg_buf[MAX_REGISTER_SIZE];
+
+ /* See if we are trying to read bytes from out-of-date registers. If so,
+ update just those registers. */
+
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ int reg_start;
+ int reg_end;
+ int reg_len;
+ int start;
+ int end;
+ int byte;
+
+ reg_start = DEPRECATED_REGISTER_BYTE (regnum);
+ reg_len = DEPRECATED_REGISTER_RAW_SIZE (regnum);
+ reg_end = reg_start + reg_len;
+
+ if (reg_end <= in_start || in_end <= reg_start)
+ /* The range the user wants to read doesn't overlap with regnum. */
+ continue;
+
+ if (REGISTER_NAME (regnum) != NULL && *REGISTER_NAME (regnum) != '\0')
+ /* Force the cache to fetch the entire register. */
+ deprecated_read_register_gen (regnum, reg_buf);
+ else
+ /* Legacy note: even though this register is ``invalid'' we
+ still need to return something. It would appear that some
+ code relies on apparent gaps in the register array also
+ being returned. */
+ /* FIXME: cagney/2001-08-18: This is just silly. It defeats
+ the entire register read/write flow of control. Must
+ resist temptation to return 0xdeadbeef. */
+ memcpy (reg_buf, &deprecated_registers[reg_start], reg_len);
+
+ /* Legacy note: This function, for some reason, allows a NULL
+ input buffer. If the buffer is NULL, the registers are still
+ fetched, just the final transfer is skipped. */
+ if (in_buf == NULL)
+ continue;
+
+ /* start = max (reg_start, in_start) */
+ if (reg_start > in_start)
+ start = reg_start;
+ else
+ start = in_start;
+
+ /* end = min (reg_end, in_end) */
+ if (reg_end < in_end)
+ end = reg_end;
+ else
+ end = in_end;
+
+ /* Transfer just the bytes common to both IN_BUF and REG_BUF */
+ for (byte = start; byte < end; byte++)
+ {
+ in_buf[byte - in_start] = reg_buf[byte - reg_start];
+ }
+ }
+}
+
+/* Read register REGNUM into memory at MYADDR, which must be large
+ enough for REGISTER_RAW_BYTES (REGNUM). Target byte-order. If the
+ register is known to be the size of a CORE_ADDR or smaller,
+ read_register can be used instead. */
+
+static void
+legacy_read_register_gen (int regnum, char *myaddr)
+{
+ gdb_assert (regnum >= 0 && regnum < (NUM_REGS + NUM_PSEUDO_REGS));
+ if (! ptid_equal (registers_ptid, inferior_ptid))
+ {
+ registers_changed ();
+ registers_ptid = inferior_ptid;
+ }
+
+ if (!register_cached (regnum))
+ target_fetch_registers (regnum);
+
+ memcpy (myaddr, register_buffer (current_regcache, regnum),
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
+}
+
+void
+regcache_raw_read (struct regcache *regcache, int regnum, void *buf)
+{
+ gdb_assert (regcache != NULL && buf != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ if (regcache->descr->legacy_p
+ && !regcache->readonly_p)
+ {
+ gdb_assert (regcache == current_regcache);
+ /* For moment, just use underlying legacy code. Ulgh!!! This
+ silently and very indirectly updates the regcache's regcache
+ via the global deprecated_register_valid[]. */
+ legacy_read_register_gen (regnum, buf);
+ return;
+ }
+ /* Make certain that the register cache is up-to-date with respect
+ to the current thread. This switching shouldn't be necessary
+ only there is still only one target side register cache. Sigh!
+ On the bright side, at least there is a regcache object. */
+ if (!regcache->readonly_p)
+ {
+ gdb_assert (regcache == current_regcache);
+ if (! ptid_equal (registers_ptid, inferior_ptid))
+ {
+ registers_changed ();
+ registers_ptid = inferior_ptid;
+ }
+ if (!register_cached (regnum))
+ target_fetch_registers (regnum);
+ }
+ /* Copy the value directly into the register cache. */
+ memcpy (buf, register_buffer (regcache, regnum),
+ regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_raw_read (regcache, regnum, buf);
+ (*val) = extract_signed_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
+ ULONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_raw_read (regcache, regnum, buf);
+ (*val) = extract_unsigned_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_raw_write_signed (struct regcache *regcache, int regnum, LONGEST val)
+{
+ void *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >=0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ store_signed_integer (buf, regcache->descr->sizeof_register[regnum], val);
+ regcache_raw_write (regcache, regnum, buf);
+}
+
+void
+regcache_raw_write_unsigned (struct regcache *regcache, int regnum,
+ ULONGEST val)
+{
+ void *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >=0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ store_unsigned_integer (buf, regcache->descr->sizeof_register[regnum], val);
+ regcache_raw_write (regcache, regnum, buf);
+}
+
+void
+deprecated_read_register_gen (int regnum, char *buf)
+{
+ gdb_assert (current_regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == current_gdbarch);
+ if (current_regcache->descr->legacy_p)
+ {
+ legacy_read_register_gen (regnum, buf);
+ return;
+ }
+ regcache_cooked_read (current_regcache, regnum, buf);
+}
+
+void
+regcache_cooked_read (struct regcache *regcache, int regnum, void *buf)
+{
+ gdb_assert (regnum >= 0);
+ gdb_assert (regnum < regcache->descr->nr_cooked_registers);
+ if (regnum < regcache->descr->nr_raw_registers)
+ regcache_raw_read (regcache, regnum, buf);
+ else if (regcache->readonly_p
+ && regnum < regcache->descr->nr_cooked_registers
+ && regcache->register_valid_p[regnum])
+ /* Read-only register cache, perhaphs the cooked value was cached? */
+ memcpy (buf, register_buffer (regcache, regnum),
+ regcache->descr->sizeof_register[regnum]);
+ else
+ gdbarch_pseudo_register_read (regcache->descr->gdbarch, regcache,
+ regnum, buf);
+}
+
+void
+regcache_cooked_read_signed (struct regcache *regcache, int regnum,
+ LONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_cooked_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_cooked_read (regcache, regnum, buf);
+ (*val) = extract_signed_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_cooked_read_unsigned (struct regcache *regcache, int regnum,
+ ULONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_cooked_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_cooked_read (regcache, regnum, buf);
+ (*val) = extract_unsigned_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_cooked_write_signed (struct regcache *regcache, int regnum,
+ LONGEST val)
+{
+ void *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >=0 && regnum < regcache->descr->nr_cooked_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ store_signed_integer (buf, regcache->descr->sizeof_register[regnum], val);
+ regcache_cooked_write (regcache, regnum, buf);
+}
+
+void
+regcache_cooked_write_unsigned (struct regcache *regcache, int regnum,
+ ULONGEST val)
+{
+ void *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >=0 && regnum < regcache->descr->nr_cooked_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ store_unsigned_integer (buf, regcache->descr->sizeof_register[regnum], val);
+ regcache_cooked_write (regcache, regnum, buf);
+}
+
+/* Write register REGNUM at MYADDR to the target. MYADDR points at
+ REGISTER_RAW_BYTES(REGNUM), which must be in target byte-order. */
+
+static void
+legacy_write_register_gen (int regnum, const void *myaddr)
+{
+ int size;
+ gdb_assert (regnum >= 0 && regnum < (NUM_REGS + NUM_PSEUDO_REGS));
+
+ /* 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 (regnum))
+ return;
+
+ if (! ptid_equal (registers_ptid, inferior_ptid))
+ {
+ registers_changed ();
+ registers_ptid = inferior_ptid;
+ }
+
+ size = DEPRECATED_REGISTER_RAW_SIZE (regnum);
+
+ if (real_register (regnum))
+ {
+ /* If we have a valid copy of the register, and new value == old
+ value, then don't bother doing the actual store. */
+ if (register_cached (regnum)
+ && (memcmp (register_buffer (current_regcache, regnum), myaddr, size)
+ == 0))
+ return;
+ else
+ target_prepare_to_store ();
+ }
+
+ memcpy (register_buffer (current_regcache, regnum), myaddr, size);
+
+ set_register_cached (regnum, 1);
+ target_store_registers (regnum);
+}
+
+void
+regcache_raw_write (struct regcache *regcache, int regnum, const void *buf)
+{
+ gdb_assert (regcache != NULL && buf != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ gdb_assert (!regcache->readonly_p);
+
+ if (regcache->descr->legacy_p)
+ {
+ /* For moment, just use underlying legacy code. Ulgh!!! This
+ silently and very indirectly updates the regcache's buffers
+ via the globals deprecated_register_valid[] and registers[]. */
+ gdb_assert (regcache == current_regcache);
+ legacy_write_register_gen (regnum, buf);
+ return;
+ }
+
+ /* 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 (regnum))
+ return;
+
+ /* Make certain that the correct cache is selected. */
+ gdb_assert (regcache == current_regcache);
+ if (! ptid_equal (registers_ptid, inferior_ptid))
+ {
+ registers_changed ();
+ registers_ptid = inferior_ptid;
+ }
+
+ /* If we have a valid copy of the register, and new value == old
+ value, then don't bother doing the actual store. */
+ if (regcache_valid_p (regcache, regnum)
+ && (memcmp (register_buffer (regcache, regnum), buf,
+ regcache->descr->sizeof_register[regnum]) == 0))
+ return;
+
+ target_prepare_to_store ();
+ memcpy (register_buffer (regcache, regnum), buf,
+ regcache->descr->sizeof_register[regnum]);
+ regcache->register_valid_p[regnum] = 1;
+ target_store_registers (regnum);
+}
+
+void
+deprecated_write_register_gen (int regnum, char *buf)
+{
+ gdb_assert (current_regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == current_gdbarch);
+ if (current_regcache->descr->legacy_p)
+ {
+ legacy_write_register_gen (regnum, buf);
+ return;
+ }
+ regcache_cooked_write (current_regcache, regnum, buf);
+}
+
+void
+regcache_cooked_write (struct regcache *regcache, int regnum, const void *buf)
+{
+ gdb_assert (regnum >= 0);
+ gdb_assert (regnum < regcache->descr->nr_cooked_registers);
+ if (regnum < regcache->descr->nr_raw_registers)
+ regcache_raw_write (regcache, regnum, buf);
+ else
+ gdbarch_pseudo_register_write (regcache->descr->gdbarch, regcache,
+ regnum, buf);
+}
+
+/* Copy INLEN bytes of consecutive data from memory at MYADDR
+ into registers starting with the MYREGSTART'th byte of register data. */
+
+void
+deprecated_write_register_bytes (int myregstart, char *myaddr, int inlen)
+{
+ int myregend = myregstart + inlen;
+ int regnum;
+
+ 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 (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ int regstart, regend;
+
+ regstart = DEPRECATED_REGISTER_BYTE (regnum);
+ regend = regstart + DEPRECATED_REGISTER_RAW_SIZE (regnum);
+
+ /* Is this register completely outside the range the user is writing? */
+ if (myregend <= regstart || regend <= myregstart)
+ /* do nothing */ ;
+
+ /* Is this register completely within the range the user is writing? */
+ else if (myregstart <= regstart && regend <= myregend)
+ deprecated_write_register_gen (regnum, myaddr + (regstart - myregstart));
+
+ /* The register partially overlaps the range being written. */
+ else
+ {
+ char regbuf[MAX_REGISTER_SIZE];
+ /* What's the overlap between this register's bytes and
+ those the caller wants to write? */
+ int overlapstart = max (regstart, myregstart);
+ int overlapend = min (regend, myregend);
+
+ /* We may be doing a partial update of an invalid register.
+ Update it from the target before scribbling on it. */
+ deprecated_read_register_gen (regnum, regbuf);
+
+ memcpy (&deprecated_registers[overlapstart],
+ myaddr + (overlapstart - myregstart),
+ overlapend - overlapstart);
+
+ target_store_registers (regnum);
+ }
+ }
+}
+
+/* Perform a partial register transfer using a read, modify, write
+ operation. */
+
+typedef void (regcache_read_ftype) (struct regcache *regcache, int regnum,
+ void *buf);
+typedef void (regcache_write_ftype) (struct regcache *regcache, int regnum,
+ const void *buf);
+
+static void
+regcache_xfer_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *in, const void *out,
+ regcache_read_ftype *read, regcache_write_ftype *write)
+{
+ struct regcache_descr *descr = regcache->descr;
+ bfd_byte reg[MAX_REGISTER_SIZE];
+ gdb_assert (offset >= 0 && offset <= descr->sizeof_register[regnum]);
+ gdb_assert (len >= 0 && offset + len <= descr->sizeof_register[regnum]);
+ /* Something to do? */
+ if (offset + len == 0)
+ return;
+ /* Read (when needed) ... */
+ if (in != NULL
+ || offset > 0
+ || offset + len < descr->sizeof_register[regnum])
+ {
+ gdb_assert (read != NULL);
+ read (regcache, regnum, reg);
+ }
+ /* ... modify ... */
+ if (in != NULL)
+ memcpy (in, reg + offset, len);
+ if (out != NULL)
+ memcpy (reg + offset, out, len);
+ /* ... write (when needed). */
+ if (out != NULL)
+ {
+ gdb_assert (write != NULL);
+ write (regcache, regnum, reg);
+ }
+}
+
+void
+regcache_raw_read_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
+ regcache_raw_read, regcache_raw_write);
+}
+
+void
+regcache_raw_write_part (struct regcache *regcache, int regnum,
+ int offset, int len, const void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
+ regcache_raw_read, regcache_raw_write);
+}
+
+void
+regcache_cooked_read_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
+ regcache_cooked_read, regcache_cooked_write);
+}
+
+void
+regcache_cooked_write_part (struct regcache *regcache, int regnum,
+ int offset, int len, const void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
+ regcache_cooked_read, regcache_cooked_write);
+}
+
+/* Hack to keep code that view the register buffer as raw bytes
+ working. */
+
+int
+register_offset_hack (struct gdbarch *gdbarch, int regnum)
+{
+ struct regcache_descr *descr = regcache_descr (gdbarch);
+ gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+ return descr->register_offset[regnum];
+}
+
+/* Return the contents of register REGNUM as an unsigned integer. */
+
+ULONGEST
+read_register (int regnum)
+{
+ char *buf = alloca (DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ deprecated_read_register_gen (regnum, buf);
+ return (extract_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (regnum)));
+}
+
+ULONGEST
+read_register_pid (int regnum, ptid_t ptid)
+{
+ ptid_t save_ptid;
+ int save_pid;
+ CORE_ADDR retval;
+
+ if (ptid_equal (ptid, inferior_ptid))
+ return read_register (regnum);
+
+ save_ptid = inferior_ptid;
+
+ inferior_ptid = ptid;
+
+ retval = read_register (regnum);
+
+ inferior_ptid = save_ptid;
+
+ return retval;
+}
+
+/* Store VALUE into the raw contents of register number REGNUM. */
+
+void
+write_register (int regnum, LONGEST val)
+{
+ void *buf;
+ int size;
+ size = DEPRECATED_REGISTER_RAW_SIZE (regnum);
+ buf = alloca (size);
+ store_signed_integer (buf, size, (LONGEST) val);
+ deprecated_write_register_gen (regnum, buf);
+}
+
+void
+write_register_pid (int regnum, CORE_ADDR val, ptid_t ptid)
+{
+ ptid_t save_ptid;
+
+ if (ptid_equal (ptid, inferior_ptid))
+ {
+ write_register (regnum, val);
+ return;
+ }
+
+ save_ptid = inferior_ptid;
+
+ inferior_ptid = ptid;
+
+ write_register (regnum, val);
+
+ inferior_ptid = save_ptid;
+}
+
+/* FIXME: kettenis/20030828: We should get rid of supply_register and
+ regcache_collect in favour of regcache_raw_supply and
+ regcache_raw_collect. */
+
+/* SUPPLY_REGISTER()
+
+ Record that register REGNUM 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.
+
+ If VAL is a NULL pointer, then it's probably an unsupported register.
+ We just set its value to all zeros. We might want to record this
+ fact, and report it to the users of read_register and friends. */
+
+void
+supply_register (int regnum, const void *val)
+{
+ regcache_raw_supply (current_regcache, regnum, val);
+
+ /* 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. */
+
+ /* NOTE: cagney/2001-03-16: The macro CLEAN_UP_REGISTER_VALUE is
+ going to be deprecated. Instead architectures will leave the raw
+ register value as is and instead clean things up as they pass
+ through the method gdbarch_pseudo_register_read() clean up the
+ values. */
+
+#ifdef DEPRECATED_CLEAN_UP_REGISTER_VALUE
+ DEPRECATED_CLEAN_UP_REGISTER_VALUE \
+ (regnum, register_buffer (current_regcache, regnum));
+#endif
+}
+
+void
+regcache_collect (int regnum, void *buf)
+{
+ regcache_raw_collect (current_regcache, regnum, buf);
+}
+
+/* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE. */
+
+void
+regcache_raw_supply (struct regcache *regcache, int regnum, const void *buf)
+{
+ void *regbuf;
+ size_t size;
+
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ gdb_assert (!regcache->readonly_p);
+
+ /* FIXME: kettenis/20030828: It shouldn't be necessary to handle
+ CURRENT_REGCACHE specially here. */
+ if (regcache == current_regcache
+ && !ptid_equal (registers_ptid, inferior_ptid))
+ {
+ registers_changed ();
+ registers_ptid = inferior_ptid;
+ }
+
+ regbuf = register_buffer (regcache, regnum);
+ size = regcache->descr->sizeof_register[regnum];
+
+ if (buf)
+ memcpy (regbuf, buf, size);
+ else
+ memset (regbuf, 0, size);
+
+ /* Mark the register as cached. */
+ regcache->register_valid_p[regnum] = 1;
+}
+
+/* Collect register REGNUM from REGCACHE and store its contents in BUF. */
+
+void
+regcache_raw_collect (const struct regcache *regcache, int regnum, void *buf)
+{
+ const void *regbuf;
+ size_t size;
+
+ gdb_assert (regcache != NULL && buf != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+
+ regbuf = register_buffer (regcache, regnum);
+ size = regcache->descr->sizeof_register[regnum];
+ memcpy (buf, regbuf, size);
+}
+
+
+/* read_pc, write_pc, read_sp, deprecated_read_fp, etc. Special
+ handling for registers PC, SP, and FP. */
+
+/* NOTE: cagney/2001-02-18: The functions read_pc_pid(), read_pc(),
+ read_sp(), and deprecated_read_fp(), will eventually be replaced by
+ per-frame methods. Instead of relying on the global INFERIOR_PTID,
+ they will use the contextual information provided by the FRAME.
+ These functions do not belong in the register cache. */
+
+/* NOTE: cagney/2003-06-07: The functions generic_target_write_pc(),
+ write_pc_pid(), write_pc(), and deprecated_read_fp(), all need to
+ be replaced by something that does not rely on global state. But
+ what? */
+
+CORE_ADDR
+read_pc_pid (ptid_t ptid)
+{
+ ptid_t saved_inferior_ptid;
+ CORE_ADDR pc_val;
+
+ /* In case ptid != inferior_ptid. */
+ saved_inferior_ptid = inferior_ptid;
+ inferior_ptid = ptid;
+
+ if (TARGET_READ_PC_P ())
+ pc_val = TARGET_READ_PC (ptid);
+ /* Else use per-frame method on get_current_frame. */
+ else if (PC_REGNUM >= 0)
+ {
+ CORE_ADDR raw_val = read_register_pid (PC_REGNUM, ptid);
+ pc_val = ADDR_BITS_REMOVE (raw_val);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "read_pc_pid: Unable to find PC");
+
+ inferior_ptid = saved_inferior_ptid;
+ return pc_val;
+}
+
+CORE_ADDR
+read_pc (void)
+{
+ return read_pc_pid (inferior_ptid);
+}
+
+void
+generic_target_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+ if (PC_REGNUM >= 0)
+ write_register_pid (PC_REGNUM, pc, ptid);
+ else
+ internal_error (__FILE__, __LINE__,
+ "generic_target_write_pc");
+}
+
+void
+write_pc_pid (CORE_ADDR pc, ptid_t ptid)
+{
+ ptid_t saved_inferior_ptid;
+
+ /* In case ptid != inferior_ptid. */
+ saved_inferior_ptid = inferior_ptid;
+ inferior_ptid = ptid;
+
+ TARGET_WRITE_PC (pc, ptid);
+
+ inferior_ptid = saved_inferior_ptid;
+}
+
+void
+write_pc (CORE_ADDR pc)
+{
+ write_pc_pid (pc, inferior_ptid);
+}
+
+/* Cope with strage ways of getting to the stack and frame pointers */
+
+CORE_ADDR
+read_sp (void)
+{
+ if (TARGET_READ_SP_P ())
+ return TARGET_READ_SP ();
+ else if (gdbarch_unwind_sp_p (current_gdbarch))
+ return get_frame_sp (get_current_frame ());
+ else if (SP_REGNUM >= 0)
+ /* Try SP_REGNUM last: this makes all sorts of [wrong] assumptions
+ about the architecture so put it at the end. */
+ return read_register (SP_REGNUM);
+ internal_error (__FILE__, __LINE__, "read_sp: Unable to find SP");
+}
+
+void
+deprecated_write_sp (CORE_ADDR val)
+{
+ gdb_assert (SP_REGNUM >= 0);
+ write_register (SP_REGNUM, val);
+}
+
+CORE_ADDR
+deprecated_read_fp (void)
+{
+ if (DEPRECATED_TARGET_READ_FP_P ())
+ return DEPRECATED_TARGET_READ_FP ();
+ else if (DEPRECATED_FP_REGNUM >= 0)
+ return read_register (DEPRECATED_FP_REGNUM);
+ else
+ internal_error (__FILE__, __LINE__, "deprecated_read_fp");
+}
+
+static void
+reg_flush_command (char *command, int from_tty)
+{
+ /* Force-flush the register cache. */
+ registers_changed ();
+ if (from_tty)
+ printf_filtered ("Register cache flushed.\n");
+}
+
+static void
+build_regcache (void)
+{
+ current_regcache = regcache_xmalloc (current_gdbarch);
+ current_regcache->readonly_p = 0;
+ deprecated_registers = deprecated_grub_regcache_for_registers (current_regcache);
+ deprecated_register_valid = current_regcache->register_valid_p;
+}
+
+static void
+dump_endian_bytes (struct ui_file *file, enum bfd_endian endian,
+ const unsigned char *buf, long len)
+{
+ int i;
+ switch (endian)
+ {
+ case BFD_ENDIAN_BIG:
+ for (i = 0; i < len; i++)
+ fprintf_unfiltered (file, "%02x", buf[i]);
+ break;
+ case BFD_ENDIAN_LITTLE:
+ for (i = len - 1; i >= 0; i--)
+ fprintf_unfiltered (file, "%02x", buf[i]);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "Bad switch");
+ }
+}
+
+enum regcache_dump_what
+{
+ regcache_dump_none, regcache_dump_raw, regcache_dump_cooked, regcache_dump_groups
+};
+
+static void
+regcache_dump (struct regcache *regcache, struct ui_file *file,
+ enum regcache_dump_what what_to_dump)
+{
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ struct gdbarch *gdbarch = regcache->descr->gdbarch;
+ int regnum;
+ int footnote_nr = 0;
+ int footnote_register_size = 0;
+ int footnote_register_offset = 0;
+ int footnote_register_type_name_null = 0;
+ long register_offset = 0;
+ unsigned char buf[MAX_REGISTER_SIZE];
+
+#if 0
+ fprintf_unfiltered (file, "legacy_p %d\n", regcache->descr->legacy_p);
+ fprintf_unfiltered (file, "nr_raw_registers %d\n",
+ regcache->descr->nr_raw_registers);
+ fprintf_unfiltered (file, "nr_cooked_registers %d\n",
+ regcache->descr->nr_cooked_registers);
+ fprintf_unfiltered (file, "sizeof_raw_registers %ld\n",
+ regcache->descr->sizeof_raw_registers);
+ fprintf_unfiltered (file, "sizeof_raw_register_valid_p %ld\n",
+ regcache->descr->sizeof_raw_register_valid_p);
+ fprintf_unfiltered (file, "NUM_REGS %d\n", NUM_REGS);
+ fprintf_unfiltered (file, "NUM_PSEUDO_REGS %d\n", NUM_PSEUDO_REGS);
+#endif
+
+ gdb_assert (regcache->descr->nr_cooked_registers
+ == (NUM_REGS + NUM_PSEUDO_REGS));
+
+ for (regnum = -1; regnum < regcache->descr->nr_cooked_registers; regnum++)
+ {
+ /* Name. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %-10s", "Name");
+ else
+ {
+ const char *p = REGISTER_NAME (regnum);
+ if (p == NULL)
+ p = "";
+ else if (p[0] == '\0')
+ p = "''";
+ fprintf_unfiltered (file, " %-10s", p);
+ }
+
+ /* Number. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %4s", "Nr");
+ else
+ fprintf_unfiltered (file, " %4d", regnum);
+
+ /* Relative number. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %4s", "Rel");
+ else if (regnum < NUM_REGS)
+ fprintf_unfiltered (file, " %4d", regnum);
+ else
+ fprintf_unfiltered (file, " %4d", (regnum - NUM_REGS));
+
+ /* Offset. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %6s ", "Offset");
+ else
+ {
+ fprintf_unfiltered (file, " %6ld",
+ regcache->descr->register_offset[regnum]);
+ if (register_offset != regcache->descr->register_offset[regnum]
+ || register_offset != DEPRECATED_REGISTER_BYTE (regnum)
+ || (regnum > 0
+ && (regcache->descr->register_offset[regnum]
+ != (regcache->descr->register_offset[regnum - 1]
+ + regcache->descr->sizeof_register[regnum - 1])))
+ )
+ {
+ if (!footnote_register_offset)
+ footnote_register_offset = ++footnote_nr;
+ fprintf_unfiltered (file, "*%d", footnote_register_offset);
+ }
+ else
+ fprintf_unfiltered (file, " ");
+ register_offset = (regcache->descr->register_offset[regnum]
+ + regcache->descr->sizeof_register[regnum]);
+ }
+
+ /* Size. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %5s ", "Size");
+ else
+ {
+ fprintf_unfiltered (file, " %5ld",
+ regcache->descr->sizeof_register[regnum]);
+ if ((regcache->descr->sizeof_register[regnum]
+ != DEPRECATED_REGISTER_RAW_SIZE (regnum))
+ || (regcache->descr->sizeof_register[regnum]
+ != DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum))
+ || (regcache->descr->sizeof_register[regnum]
+ != TYPE_LENGTH (register_type (regcache->descr->gdbarch,
+ regnum)))
+ )
+ {
+ if (!footnote_register_size)
+ footnote_register_size = ++footnote_nr;
+ fprintf_unfiltered (file, "*%d", footnote_register_size);
+ }
+ else
+ fprintf_unfiltered (file, " ");
+ }
+
+ /* Type. */
+ {
+ const char *t;
+ if (regnum < 0)
+ t = "Type";
+ else
+ {
+ static const char blt[] = "builtin_type";
+ t = TYPE_NAME (register_type (regcache->descr->gdbarch, regnum));
+ if (t == NULL)
+ {
+ char *n;
+ if (!footnote_register_type_name_null)
+ footnote_register_type_name_null = ++footnote_nr;
+ xasprintf (&n, "*%d", footnote_register_type_name_null);
+ make_cleanup (xfree, n);
+ t = n;
+ }
+ /* Chop a leading builtin_type. */
+ if (strncmp (t, blt, strlen (blt)) == 0)
+ t += strlen (blt);
+ }
+ fprintf_unfiltered (file, " %-15s", t);
+ }
+
+ /* Leading space always present. */
+ fprintf_unfiltered (file, " ");
+
+ /* Value, raw. */
+ if (what_to_dump == regcache_dump_raw)
+ {
+ if (regnum < 0)
+ fprintf_unfiltered (file, "Raw value");
+ else if (regnum >= regcache->descr->nr_raw_registers)
+ fprintf_unfiltered (file, "<cooked>");
+ else if (!regcache_valid_p (regcache, regnum))
+ fprintf_unfiltered (file, "<invalid>");
+ else
+ {
+ regcache_raw_read (regcache, regnum, buf);
+ fprintf_unfiltered (file, "0x");
+ dump_endian_bytes (file, TARGET_BYTE_ORDER, buf,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ }
+ }
+
+ /* Value, cooked. */
+ if (what_to_dump == regcache_dump_cooked)
+ {
+ if (regnum < 0)
+ fprintf_unfiltered (file, "Cooked value");
+ else
+ {
+ regcache_cooked_read (regcache, regnum, buf);
+ fprintf_unfiltered (file, "0x");
+ dump_endian_bytes (file, TARGET_BYTE_ORDER, buf,
+ DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+ }
+ }
+
+ /* Group members. */
+ if (what_to_dump == regcache_dump_groups)
+ {
+ if (regnum < 0)
+ fprintf_unfiltered (file, "Groups");
+ else
+ {
+ const char *sep = "";
+ struct reggroup *group;
+ for (group = reggroup_next (gdbarch, NULL);
+ group != NULL;
+ group = reggroup_next (gdbarch, group))
+ {
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, group))
+ {
+ fprintf_unfiltered (file, "%s%s", sep, reggroup_name (group));
+ sep = ",";
+ }
+ }
+ }
+ }
+
+ fprintf_unfiltered (file, "\n");
+ }
+
+ if (footnote_register_size)
+ fprintf_unfiltered (file, "*%d: Inconsistent register sizes.\n",
+ footnote_register_size);
+ if (footnote_register_offset)
+ fprintf_unfiltered (file, "*%d: Inconsistent register offsets.\n",
+ footnote_register_offset);
+ if (footnote_register_type_name_null)
+ fprintf_unfiltered (file,
+ "*%d: Register type's name NULL.\n",
+ footnote_register_type_name_null);
+ do_cleanups (cleanups);
+}
+
+static void
+regcache_print (char *args, enum regcache_dump_what what_to_dump)
+{
+ if (args == NULL)
+ regcache_dump (current_regcache, gdb_stdout, what_to_dump);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print architecture");
+ regcache_dump (current_regcache, file, what_to_dump);
+ ui_file_delete (file);
+ }
+}
+
+static void
+maintenance_print_registers (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_none);
+}
+
+static void
+maintenance_print_raw_registers (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_raw);
+}
+
+static void
+maintenance_print_cooked_registers (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_cooked);
+}
+
+static void
+maintenance_print_register_groups (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_groups);
+}
+
+extern initialize_file_ftype _initialize_regcache; /* -Wmissing-prototype */
+
+void
+_initialize_regcache (void)
+{
+ regcache_descr_handle = register_gdbarch_data (init_regcache_descr);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (current_regcache);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (deprecated_registers);
+ DEPRECATED_REGISTER_GDBARCH_SWAP (deprecated_register_valid);
+ deprecated_register_gdbarch_swap (NULL, 0, build_regcache);
+
+ add_com ("flushregs", class_maintenance, reg_flush_command,
+ "Force gdb to flush its register cache (maintainer command)");
+
+ /* Initialize the thread/process associated with the current set of
+ registers. For now, -1 is special, and means `no current process'. */
+ registers_ptid = pid_to_ptid (-1);
+
+ add_cmd ("registers", class_maintenance,
+ maintenance_print_registers,
+ "Print the internal register configuration.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+ add_cmd ("raw-registers", class_maintenance,
+ maintenance_print_raw_registers,
+ "Print the internal register configuration including raw values.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+ add_cmd ("cooked-registers", class_maintenance,
+ maintenance_print_cooked_registers,
+ "Print the internal register configuration including cooked values.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+ add_cmd ("register-groups", class_maintenance,
+ maintenance_print_register_groups,
+ "Print the internal register configuration including each register's group.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+
+}
diff --git a/contrib/gdb/gdb/regcache.h b/contrib/gdb/gdb/regcache.h
new file mode 100644
index 0000000..26a1b8a
--- /dev/null
+++ b/contrib/gdb/gdb/regcache.h
@@ -0,0 +1,255 @@
+/* Cache and manage the values of registers for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
+ 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 REGCACHE_H
+#define REGCACHE_H
+
+struct regcache;
+struct gdbarch;
+
+extern struct regcache *current_regcache;
+
+void regcache_xfree (struct regcache *regcache);
+struct cleanup *make_cleanup_regcache_xfree (struct regcache *regcache);
+struct regcache *regcache_xmalloc (struct gdbarch *gdbarch);
+
+/* Return REGCACHE's architecture. */
+
+extern struct gdbarch *get_regcache_arch (const struct regcache *regcache);
+
+/* Transfer a raw register [0..NUM_REGS) between core-gdb and the
+ regcache. */
+
+void regcache_raw_read (struct regcache *regcache, int rawnum, void *buf);
+void regcache_raw_write (struct regcache *regcache, int rawnum,
+ const void *buf);
+extern void regcache_raw_read_signed (struct regcache *regcache,
+ int regnum, LONGEST *val);
+extern void regcache_raw_read_unsigned (struct regcache *regcache,
+ int regnum, ULONGEST *val);
+extern void regcache_raw_write_signed (struct regcache *regcache,
+ int regnum, LONGEST val);
+extern void regcache_raw_write_unsigned (struct regcache *regcache,
+ int regnum, ULONGEST val);
+
+/* Partial transfer of a raw registers. These perform read, modify,
+ write style operations. */
+
+void regcache_raw_read_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *buf);
+void regcache_raw_write_part (struct regcache *regcache, int regnum,
+ int offset, int len, const void *buf);
+
+int regcache_valid_p (struct regcache *regcache, int regnum);
+
+/* Transfer a cooked register [0..NUM_REGS+NUM_PSEUDO_REGS). */
+void regcache_cooked_read (struct regcache *regcache, int rawnum, void *buf);
+void regcache_cooked_write (struct regcache *regcache, int rawnum,
+ const void *buf);
+
+/* NOTE: cagney/2002-08-13: At present GDB has no reliable mechanism
+ for indicating when a ``cooked'' register was constructed from
+ invalid or unavailable ``raw'' registers. One fairly easy way of
+ adding such a mechanism would be for the cooked functions to return
+ a register valid indication. Given the possibility of such a
+ change, the extract functions below use a reference parameter,
+ rather than a function result. */
+
+/* Read a register as a signed/unsigned quantity. */
+extern void regcache_cooked_read_signed (struct regcache *regcache,
+ int regnum, LONGEST *val);
+extern void regcache_cooked_read_unsigned (struct regcache *regcache,
+ int regnum, ULONGEST *val);
+extern void regcache_cooked_write_signed (struct regcache *regcache,
+ int regnum, LONGEST val);
+extern void regcache_cooked_write_unsigned (struct regcache *regcache,
+ int regnum, ULONGEST val);
+
+/* Partial transfer of a cooked register. These perform read, modify,
+ write style operations. */
+
+void regcache_cooked_read_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *buf);
+void regcache_cooked_write_part (struct regcache *regcache, int regnum,
+ int offset, int len, const void *buf);
+
+/* Transfer a raw register [0..NUM_REGS) between the regcache and the
+ target. These functions are called by the target in response to a
+ target_fetch_registers() or target_store_registers(). */
+
+extern void supply_register (int regnum, const void *val);
+extern void regcache_collect (int regnum, void *buf);
+extern void regcache_raw_supply (struct regcache *regcache,
+ int regnum, const void *buf);
+extern void regcache_raw_collect (const struct regcache *regcache,
+ int regnum, void *buf);
+
+
+/* The register's ``offset''.
+
+ FIXME: cagney/2002-11-07: The frame_register() function, when
+ specifying the real location of a register, does so using that
+ registers offset in the register cache. That offset is then used
+ by valops.c to determine the location of the register. The code
+ should instead use the register's number and a location expression
+ to describe a value spread across multiple registers or memory. */
+
+extern int register_offset_hack (struct gdbarch *gdbarch, int regnum);
+
+
+/* The type of a register. This function is slightly more efficient
+ then its gdbarch vector counterpart since it returns a precomputed
+ value stored in a table.
+
+ NOTE: cagney/2002-08-17: The original macro was called
+ DEPRECATED_REGISTER_VIRTUAL_TYPE. This was because the register
+ could have different raw and cooked (nee virtual) representations.
+ The CONVERTABLE methods being used to convert between the two
+ representations. Current code does not do this. Instead, the
+ first [0..NUM_REGS) registers are 1:1 raw:cooked, and the type
+ exactly describes the register's representation. Consequently, the
+ ``virtual'' has been dropped.
+
+ FIXME: cagney/2002-08-17: A number of architectures, including the
+ MIPS, are currently broken in this regard. */
+
+extern struct type *register_type (struct gdbarch *gdbarch, int regnum);
+
+
+/* Return the size of register REGNUM. All registers should have only
+ one size.
+
+ FIXME: cagney/2003-02-28:
+
+ Unfortunately, thanks to some legacy architectures, this doesn't
+ hold. A register's cooked (nee virtual) and raw size can differ
+ (see MIPS). Such architectures should be using different register
+ numbers for the different sized views of identical registers.
+
+ Anyway, the up-shot is that, until that mess is fixed, core code
+ can end up being very confused - should the RAW or VIRTUAL size be
+ used? As a rule of thumb, use DEPRECATED_REGISTER_VIRTUAL_SIZE in
+ cooked code, but with the comment:
+
+ OK: REGISTER_VIRTUAL_SIZE
+
+ or just
+
+ OK
+
+ appended to the end of the line. */
+
+extern int register_size (struct gdbarch *gdbarch, int regnum);
+
+
+/* Save/restore a register cache. The set of registers saved /
+ restored into the DST regcache determined by the save_reggroup /
+ restore_reggroup respectively. COOKED_READ returns zero iff the
+ register's value can't be returned. */
+
+typedef int (regcache_cooked_read_ftype) (void *src, int regnum, void *buf);
+
+extern void regcache_save (struct regcache *dst,
+ regcache_cooked_read_ftype *cooked_read,
+ void *src);
+extern void regcache_restore (struct regcache *dst,
+ regcache_cooked_read_ftype *cooked_read,
+ void *src);
+
+/* Copy/duplicate the contents of a register cache. By default, the
+ operation is pass-through. Writes to DST and reads from SRC will
+ go through to the target.
+
+ The ``cpy'' functions can not have overlapping SRC and DST buffers.
+
+ ``no passthrough'' versions do not go through to the target. They
+ only transfer values already in the cache. */
+
+extern struct regcache *regcache_dup (struct regcache *regcache);
+extern struct regcache *regcache_dup_no_passthrough (struct regcache *regcache);
+extern void regcache_cpy (struct regcache *dest, struct regcache *src);
+extern void regcache_cpy_no_passthrough (struct regcache *dest, struct regcache *src);
+
+/* NOTE: cagney/2002-11-02: The below have been superseded by the
+ regcache_cooked_*() functions found above, and the frame_*()
+ functions found in "frame.h". Take care though, often more than a
+ simple substitution is required when updating the code. The
+ change, as far as practical, should avoid adding references to
+ global variables (e.g., current_regcache, current_frame,
+ current_gdbarch or deprecated_selected_frame) and instead refer to
+ the FRAME or REGCACHE that has been passed into the containing
+ function as parameters. Consequently, the change typically
+ involves modifying the containing function so that it takes a FRAME
+ or REGCACHE parameter. In the case of an architecture vector
+ method, there should already be a non-deprecated variant that is
+ parameterized with FRAME or REGCACHE. */
+
+extern char *deprecated_grub_regcache_for_registers (struct regcache *);
+extern void deprecated_read_register_gen (int regnum, char *myaddr);
+extern void deprecated_write_register_gen (int regnum, char *myaddr);
+extern void deprecated_read_register_bytes (int regbyte, char *myaddr,
+ int len);
+extern void deprecated_write_register_bytes (int regbyte, char *myaddr,
+ int len);
+
+/* Character array containing the current state of each register
+ (unavailable<0, invalid=0, valid>0) for the most recently
+ referenced thread. This global is often found in close proximity
+ to code that is directly manipulating the deprecated_registers[]
+ array. In such cases, it should be possible to replace the lot
+ with a call to supply_register(). If you find yourself in dire
+ straits, still needing access to the cache status bit, the
+ regcache_valid_p() and set_register_cached() functions are
+ available. */
+extern signed char *deprecated_register_valid;
+
+/* Character array containing an image of the inferior programs'
+ registers for the most recently referenced thread.
+
+ NOTE: cagney/2002-11-14: Target side code should be using
+ supply_register() and/or regcache_collect() while architecture side
+ code should use the more generic regcache methods. */
+
+extern char *deprecated_registers;
+
+/* NOTE: cagney/2002-11-05: This function, and its co-conspirator
+ deprecated_registers[], have been superseeded by supply_register(). */
+extern void deprecated_registers_fetched (void);
+
+extern int register_cached (int regnum);
+
+extern void set_register_cached (int regnum, int state);
+
+extern void registers_changed (void);
+
+
+/* Rename to read_unsigned_register()? */
+extern ULONGEST read_register (int regnum);
+
+/* Rename to read_unsigned_register_pid()? */
+extern ULONGEST read_register_pid (int regnum, ptid_t ptid);
+
+extern void write_register (int regnum, LONGEST val);
+
+extern void write_register_pid (int regnum, CORE_ADDR val, ptid_t ptid);
+
+#endif /* REGCACHE_H */
diff --git a/contrib/gdb/gdb/regformats/reg-arm.dat b/contrib/gdb/gdb/regformats/reg-arm.dat
new file mode 100644
index 0000000..5a60025
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-arm.dat
@@ -0,0 +1,28 @@
+name:arm
+expedite:r11,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:sp
+32:lr
+32:pc
+96:f0
+96:f1
+96:f2
+96:f3
+96:f4
+96:f5
+96:f6
+96:f7
+32:fps
+32:cpsr
diff --git a/contrib/gdb/gdb/regformats/reg-i386.dat b/contrib/gdb/gdb/regformats/reg-i386.dat
new file mode 100644
index 0000000..69c2d90
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-i386.dat
@@ -0,0 +1,43 @@
+name:i386
+expedite:ebp,esp,eip
+32:eax
+32:ecx
+32:edx
+32:ebx
+32:esp
+32:ebp
+32:esi
+32:edi
+32:eip
+32:eflags
+32:cs
+32:ss
+32:ds
+32:es
+32:fs
+32:gs
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+128:xmm0
+128:xmm1
+128:xmm2
+128:xmm3
+128:xmm4
+128:xmm5
+128:xmm6
+128:xmm7
+32:mxcsr
diff --git a/contrib/gdb/gdb/regformats/reg-ia64.dat b/contrib/gdb/gdb/regformats/reg-ia64.dat
new file mode 100644
index 0000000..125902d
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-ia64.dat
@@ -0,0 +1,603 @@
+name:ia64
+expedite:ip,psr,r12,bsp,cfm
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:r32
+64:r33
+64:r34
+64:r35
+64:r36
+64:r37
+64:r38
+64:r39
+64:r40
+64:r41
+64:r42
+64:r43
+64:r44
+64:r45
+64:r46
+64:r47
+64:r48
+64:r49
+64:r50
+64:r51
+64:r52
+64:r53
+64:r54
+64:r55
+64:r56
+64:r57
+64:r58
+64:r59
+64:r60
+64:r61
+64:r62
+64:r63
+64:r64
+64:r65
+64:r66
+64:r67
+64:r68
+64:r69
+64:r70
+64:r71
+64:r72
+64:r73
+64:r74
+64:r75
+64:r76
+64:r77
+64:r78
+64:r79
+64:r80
+64:r81
+64:r82
+64:r83
+64:r84
+64:r85
+64:r86
+64:r87
+64:r88
+64:r89
+64:r90
+64:r91
+64:r92
+64:r93
+64:r94
+64:r95
+64:r96
+64:r97
+64:r98
+64:r99
+64:r100
+64:r101
+64:r102
+64:r103
+64:r104
+64:r105
+64:r106
+64:r107
+64:r108
+64:r109
+64:r110
+64:r111
+64:r112
+64:r113
+64:r114
+64:r115
+64:r116
+64:r117
+64:r118
+64:r119
+64:r120
+64:r121
+64:r122
+64:r123
+64:r124
+64:r125
+64:r126
+64:r127
+
+128:f0
+128:f1
+128:f2
+128:f3
+128:f4
+128:f5
+128:f6
+128:f7
+128:f8
+128:f9
+128:f10
+128:f11
+128:f12
+128:f13
+128:f14
+128:f15
+128:f16
+128:f17
+128:f18
+128:f19
+128:f20
+128:f21
+128:f22
+128:f23
+128:f24
+128:f25
+128:f26
+128:f27
+128:f28
+128:f29
+128:f30
+128:f31
+128:f32
+128:f33
+128:f34
+128:f35
+128:f36
+128:f37
+128:f38
+128:f39
+128:f40
+128:f41
+128:f42
+128:f43
+128:f44
+128:f45
+128:f46
+128:f47
+128:f48
+128:f49
+128:f50
+128:f51
+128:f52
+128:f53
+128:f54
+128:f55
+128:f56
+128:f57
+128:f58
+128:f59
+128:f60
+128:f61
+128:f62
+128:f63
+128:f64
+128:f65
+128:f66
+128:f67
+128:f68
+128:f69
+128:f70
+128:f71
+128:f72
+128:f73
+128:f74
+128:f75
+128:f76
+128:f77
+128:f78
+128:f79
+128:f80
+128:f81
+128:f82
+128:f83
+128:f84
+128:f85
+128:f86
+128:f87
+128:f88
+128:f89
+128:f90
+128:f91
+128:f92
+128:f93
+128:f94
+128:f95
+128:f96
+128:f97
+128:f98
+128:f99
+128:f100
+128:f101
+128:f102
+128:f103
+128:f104
+128:f105
+128:f106
+128:f107
+128:f108
+128:f109
+128:f110
+128:f111
+128:f112
+128:f113
+128:f114
+128:f115
+128:f116
+128:f117
+128:f118
+128:f119
+128:f120
+128:f121
+128:f122
+128:f123
+128:f124
+128:f125
+128:f126
+128:f127
+
+64:p0
+64:p1
+64:p2
+64:p3
+64:p4
+64:p5
+64:p6
+64:p7
+64:p8
+64:p9
+64:p10
+64:p11
+64:p12
+64:p13
+64:p14
+64:p15
+64:p16
+64:p17
+64:p18
+64:p19
+64:p20
+64:p21
+64:p22
+64:p23
+64:p24
+64:p25
+64:p26
+64:p27
+64:p28
+64:p29
+64:p30
+64:p31
+64:p32
+64:p33
+64:p34
+64:p35
+64:p36
+64:p37
+64:p38
+64:p39
+64:p40
+64:p41
+64:p42
+64:p43
+64:p44
+64:p45
+64:p46
+64:p47
+64:p48
+64:p49
+64:p50
+64:p51
+64:p52
+64:p53
+64:p54
+64:p55
+64:p56
+64:p57
+64:p58
+64:p59
+64:p60
+64:p61
+64:p62
+64:p63
+
+64:b0
+64:b1
+64:b2
+64:b3
+64:b4
+64:b5
+64:b6
+64:b7
+
+64:vfp
+64:vrap
+
+64:pr
+64:ip
+64:psr
+64:cfm
+
+64:kr0
+64:kr1
+64:kr2
+64:kr3
+64:kr4
+64:kr5
+64:kr6
+64:kr7
+
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+
+64:rsc
+64:bsp
+64:bspstore
+64:rnat
+
+64:
+64:fcr
+64:
+64:
+
+64:eflag
+64:csd
+64:ssd
+64:cflg
+64:fsr
+64:fir
+64:fdr
+64:
+64:ccv
+64:
+64:
+64:
+64:unat
+64:
+64:
+64:
+64:fpsr
+64:
+64:
+64:
+64:itc
+
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:pfs
+64:lc
+64:ec
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:nat0
+64:nat1
+64:nat2
+64:nat3
+64:nat4
+64:nat5
+64:nat6
+64:nat7
+64:nat8
+64:nat9
+64:nat10
+64:nat11
+64:nat12
+64:nat13
+64:nat14
+64:nat15
+64:nat16
+64:nat17
+64:nat18
+64:nat19
+64:nat20
+64:nat21
+64:nat22
+64:nat23
+64:nat24
+64:nat25
+64:nat26
+64:nat27
+64:nat28
+64:nat29
+64:nat30
+64:nat31
+64:nat32
+64:nat33
+64:nat34
+64:nat35
+64:nat36
+64:nat37
+64:nat38
+64:nat39
+64:nat40
+64:nat41
+64:nat42
+64:nat43
+64:nat44
+64:nat45
+64:nat46
+64:nat47
+64:nat48
+64:nat49
+64:nat50
+64:nat51
+64:nat52
+64:nat53
+64:nat54
+64:nat55
+64:nat56
+64:nat57
+64:nat58
+64:nat59
+64:nat60
+64:nat61
+64:nat62
+64:nat63
+64:nat64
+64:nat65
+64:nat66
+64:nat67
+64:nat68
+64:nat69
+64:nat70
+64:nat71
+64:nat72
+64:nat73
+64:nat74
+64:nat75
+64:nat76
+64:nat77
+64:nat78
+64:nat79
+64:nat80
+64:nat81
+64:nat82
+64:nat83
+64:nat84
+64:nat85
+64:nat86
+64:nat87
+64:nat88
+64:nat89
+64:nat90
+64:nat91
+64:nat92
+64:nat93
+64:nat94
+64:nat95
+64:nat96
+64:nat97
+64:nat98
+64:nat99
+64:nat100
+64:nat101
+64:nat102
+64:nat103
+64:nat104
+64:nat105
+64:nat106
+64:nat107
+64:nat108
+64:nat109
+64:nat110
+64:nat111
+64:nat112
+64:nat113
+64:nat114
+64:nat115
+64:nat116
+64:nat117
+64:nat118
+64:nat119
+64:nat120
+64:nat121
+64:nat122
+64:nat123
+64:nat124
+64:nat125
+64:nat126
+64:nat127
diff --git a/contrib/gdb/gdb/regformats/reg-m68k.dat b/contrib/gdb/gdb/regformats/reg-m68k.dat
new file mode 100644
index 0000000..8928b45
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-m68k.dat
@@ -0,0 +1,33 @@
+name:m68k
+expedite:sp,fp,pc
+32:d0
+32:d1
+32:d2
+32:d3
+32:d4
+32:d5
+32:d6
+32:d7
+32:a0
+32:a1
+32:a2
+32:a3
+32:a4
+32:a5
+32:fp
+32:sp
+32:ps
+32:pc
+
+96:fp0
+96:fp1
+96:fp2
+96:fp3
+96:fp4
+96:fp5
+96:fp6
+96:fp7
+
+32:fpcontrol
+32:fpstatus
+32:fpiaddr
diff --git a/contrib/gdb/gdb/regformats/reg-mips.dat b/contrib/gdb/gdb/regformats/reg-mips.dat
new file mode 100644
index 0000000..7a7c808
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-mips.dat
@@ -0,0 +1,112 @@
+name:mips
+expedite:pc,sp
+32:zero
+32:at
+32:v0
+32:v1
+
+32:a0
+32:a1
+32:a2
+32:a3
+
+32:t0
+32:t1
+32:t2
+32:t3
+
+32:t4
+32:t5
+32:t6
+32:t7
+
+32:s0
+32:s1
+32:s2
+32:s3
+
+32:s4
+32:s5
+32:s6
+32:s7
+
+32:t8
+32:t9
+32:k0
+32:k1
+
+32:gp
+32:sp
+32:s8
+32:ra
+
+32:sr
+32:lo
+32:hi
+32:bad
+
+32:cause
+32:pc
+
+32:f0
+32:f1
+32:f2
+32:f3
+
+32:f4
+32:f5
+32:f6
+32:f7
+
+32:f8
+32:f9
+32:f10
+32:f11
+
+32:f12
+32:f13
+32:f14
+32:f15
+
+32:f16
+32:f17
+32:f18
+32:f19
+
+32:f20
+32:f21
+32:f22
+32:f23
+
+32:f24
+32:f25
+32:f26
+32:f27
+
+32:f28
+32:f29
+32:f30
+32:f31
+
+32:fsr
+32:fir
+
+32:fp
+32:
+
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
diff --git a/contrib/gdb/gdb/regformats/reg-ppc.dat b/contrib/gdb/gdb/regformats/reg-ppc.dat
new file mode 100644
index 0000000..d7f9b88
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-ppc.dat
@@ -0,0 +1,76 @@
+name:ppc
+expedite:r1,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:r26
+32:r27
+32:r28
+32:r29
+32:r30
+32:r31
+
+64:f0
+64:f1
+64:f2
+64:f3
+64:f4
+64:f5
+64:f6
+64:f7
+64:f8
+64:f9
+64:f10
+64:f11
+64:f12
+64:f13
+64:f14
+64:f15
+64:f16
+64:f17
+64:f18
+64:f19
+64:f20
+64:f21
+64:f22
+64:f23
+64:f24
+64:f25
+64:f26
+64:f27
+64:f28
+64:f29
+64:f30
+64:f31
+
+32:pc
+32:ps
+
+32:cr
+32:lr
+32:ctr
+32:xer
+32:fpscr
diff --git a/contrib/gdb/gdb/regformats/reg-s390.dat b/contrib/gdb/gdb/regformats/reg-s390.dat
new file mode 100644
index 0000000..79e07b9
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-s390.dat
@@ -0,0 +1,53 @@
+name:s390
+expedite:r14,r15,pswa
+32:pswm
+32:pswa
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:acr0
+32:acr1
+32:acr2
+32:acr3
+32:acr4
+32:acr5
+32:acr6
+32:acr7
+32:acr8
+32:acr9
+32:acr10
+32:acr11
+32:acr12
+32:acr13
+32:acr14
+32:acr15
+32:fpc
+64:f0
+64:f1
+64:f2
+64:f3
+64:f4
+64:f5
+64:f6
+64:f7
+64:f8
+64:f9
+64:f10
+64:f11
+64:f12
+64:f13
+64:f14
+64:f15
diff --git a/contrib/gdb/gdb/regformats/reg-s390x.dat b/contrib/gdb/gdb/regformats/reg-s390x.dat
new file mode 100644
index 0000000..2e24f53
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-s390x.dat
@@ -0,0 +1,53 @@
+name:s390
+expedite:r14,r15,pswa
+64:pswm
+64:pswa
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+32:acr0
+32:acr1
+32:acr2
+32:acr3
+32:acr4
+32:acr5
+32:acr6
+32:acr7
+32:acr8
+32:acr9
+32:acr10
+32:acr11
+32:acr12
+32:acr13
+32:acr14
+32:acr15
+32:fpc
+64:f0
+64:f1
+64:f2
+64:f3
+64:f4
+64:f5
+64:f6
+64:f7
+64:f8
+64:f9
+64:f10
+64:f11
+64:f12
+64:f13
+64:f14
+64:f15
diff --git a/contrib/gdb/gdb/regformats/reg-sh.dat b/contrib/gdb/gdb/regformats/reg-sh.dat
new file mode 100644
index 0000000..d670b46
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-sh.dat
@@ -0,0 +1,62 @@
+name:sh
+expedite:pc,r14,r15
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:pc
+32:pr
+32:gbr
+32:vbr
+32:mach
+32:macl
+32:sr
+32:fpul
+32:fpscr
+32:fr0
+32:fr1
+32:fr2
+32:fr3
+32:fr4
+32:fr5
+32:fr6
+32:fr7
+32:fr8
+32:fr9
+32:fr10
+32:fr11
+32:fr12
+32:fr13
+32:fr14
+32:fr15
+
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
+32:
diff --git a/contrib/gdb/gdb/regformats/reg-x86-64.dat b/contrib/gdb/gdb/regformats/reg-x86-64.dat
new file mode 100644
index 0000000..dd1f78f
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/reg-x86-64.dat
@@ -0,0 +1,59 @@
+name:x86_64
+expedite:rbp,rsp,rip
+64:rax
+64:rbx
+64:rcx
+64:rdx
+64:rsi
+64:rdi
+64:rbp
+64:rsp
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:rip
+32:eflags
+32:cs
+32:ss
+32:ds
+32:es
+32:fs
+32:gs
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+128:xmm0
+128:xmm1
+128:xmm2
+128:xmm3
+128:xmm4
+128:xmm5
+128:xmm6
+128:xmm7
+128:xmm8
+128:xmm9
+128:xmm10
+128:xmm11
+128:xmm12
+128:xmm13
+128:xmm14
+128:xmm15
+32:mxcsr
diff --git a/contrib/gdb/gdb/regformats/regdat.sh b/contrib/gdb/gdb/regformats/regdat.sh
new file mode 100755
index 0000000..9035b3d
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/regdat.sh
@@ -0,0 +1,169 @@
+#!/bin/sh -u
+
+# Register protocol definitions for GDB, the GNU debugger.
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+move_if_change ()
+{
+ file=$1
+ if test -r ${file} && cmp -s "${file}" new-"${file}"
+ then
+ echo "${file} unchanged." 1>&2
+ else
+ mv new-"${file}" "${file}"
+ echo "${file} updated." 1>&2
+ fi
+}
+
+# Format of the input files
+read="type entry"
+
+do_read ()
+{
+ type=""
+ entry=""
+ while read line
+ do
+ if test "${line}" = ""
+ then
+ continue
+ elif test "${line}" = "#" -a "${comment}" = ""
+ then
+ continue
+ elif expr "${line}" : "#" > /dev/null
+ then
+ comment="${comment}
+${line}"
+ else
+
+ # The semantics of IFS varies between different SH's. Some
+ # treat ``::' as three fields while some treat it as just too.
+ # Work around this by eliminating ``::'' ....
+ line="`echo "${line}" | sed -e 's/::/: :/g' -e 's/::/: :/g'`"
+
+ OFS="${IFS}" ; IFS="[:]"
+ eval read ${read} <<EOF
+${line}
+EOF
+ IFS="${OFS}"
+
+ # .... and then going back through each field and strip out those
+ # that ended up with just that space character.
+ for r in ${read}
+ do
+ if eval test \"\${${r}}\" = \"\ \"
+ then
+ eval ${r}=""
+ fi
+ done
+
+ break
+ fi
+ done
+ if [ -n "${type}" ]
+ then
+ true
+ else
+ false
+ fi
+}
+
+if test ! -r $1; then
+ echo "$0: Could not open $1." 1>&2
+ exit 1
+fi
+
+copyright ()
+{
+cat <<EOF
+/* *INDENT-OFF* */ /* THIS FILE IS GENERATED */
+
+/* A register protocol for GDB, the GNU debugger.
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This file was created with the aid of \`\`regdat.sh'' and \`\`$1''. */
+
+EOF
+}
+
+
+exec > new-$2
+copyright $1
+echo '#include "regdef.h"'
+echo '#include "regcache.h"'
+echo
+offset=0
+i=0
+name=x
+expedite=x
+exec < $1
+while do_read
+do
+ if test "${type}" = "name"; then
+ name="${entry}"
+ echo "struct reg regs_${name}[] = {"
+ continue
+ elif test "${type}" = "expedite"; then
+ expedite="${entry}"
+ continue
+ elif test "${name}" = x; then
+ echo "$0: $1 does not specify \`\`name''." 1>&2
+ exit 1
+ else
+ echo " { \"${entry}\", ${offset}, ${type} },"
+ offset=`expr ${offset} + ${type}`
+ i=`expr $i + 1`
+ fi
+done
+
+echo "};"
+echo
+echo "const char *expedite_regs_${name}[] = { \"`echo ${expedite} | sed 's/,/", "/g'`\", 0 };"
+echo
+
+cat <<EOF
+void
+init_registers ()
+{
+ set_register_cache (regs_${name},
+ sizeof (regs_${name}) / sizeof (regs_${name}[0]));
+ gdbserver_expedite_regs = expedite_regs_${name};
+}
+EOF
+
+# close things off
+exec 1>&2
+move_if_change $2
diff --git a/contrib/gdb/gdb/regformats/regdef.h b/contrib/gdb/gdb/regformats/regdef.h
new file mode 100644
index 0000000..c1f862c
--- /dev/null
+++ b/contrib/gdb/gdb/regformats/regdef.h
@@ -0,0 +1,46 @@
+/* Register protocol definition structures for the GNU Debugger
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 REGDEF_H
+#define REGDEF_H
+
+struct reg
+{
+ /* The name of this register - NULL for pad entries. */
+ const char *name;
+
+ /* At the moment, both of the following bit counts must be divisible
+ by eight (to match the representation as two hex digits) and divisible
+ by the size of a byte (to match the layout of each register in
+ memory). */
+
+ /* The offset (in bits) of the value of this register in the buffer. */
+ int offset;
+
+ /* The size (in bits) of the value of this register, as transmitted. */
+ int size;
+};
+
+/* Set the current remote protocol and register cache according to the array
+ ``regs'', with ``n'' elements. */
+
+void set_register_cache (struct reg *regs, int n);
+
+#endif /* REGDEF_H */
diff --git a/contrib/gdb/gdb/reggroups.c b/contrib/gdb/gdb/reggroups.c
new file mode 100644
index 0000000..7dd0562
--- /dev/null
+++ b/contrib/gdb/gdb/reggroups.c
@@ -0,0 +1,288 @@
+/* Register groupings for GDB, the GNU debugger.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "reggroups.h"
+#include "gdbtypes.h"
+#include "gdb_assert.h"
+#include "regcache.h"
+#include "command.h"
+#include "gdbcmd.h" /* For maintenanceprintlist. */
+
+/* Individual register groups. */
+
+struct reggroup
+{
+ const char *name;
+ enum reggroup_type type;
+};
+
+struct reggroup *
+reggroup_new (const char *name, enum reggroup_type type)
+{
+ struct reggroup *group = XMALLOC (struct reggroup);
+ group->name = name;
+ group->type = type;
+ return group;
+}
+
+/* Register group attributes. */
+
+const char *
+reggroup_name (struct reggroup *group)
+{
+ return group->name;
+}
+
+enum reggroup_type
+reggroup_type (struct reggroup *group)
+{
+ return group->type;
+}
+
+/* A linked list of groups for the given architecture. */
+
+struct reggroup_el
+{
+ struct reggroup *group;
+ struct reggroup_el *next;
+};
+
+struct reggroups
+{
+ struct reggroup_el *first;
+ struct reggroup_el **last;
+};
+
+static struct gdbarch_data *reggroups_data;
+
+static void *
+reggroups_init (struct gdbarch *gdbarch)
+{
+ struct reggroups *groups = GDBARCH_OBSTACK_ZALLOC (gdbarch,
+ struct reggroups);
+ groups->last = &groups->first;
+ return groups;
+}
+
+/* Add a register group (with attribute values) to the pre-defined
+ list. */
+
+static void
+add_group (struct reggroups *groups, struct reggroup *group,
+ struct reggroup_el *el)
+{
+ gdb_assert (group != NULL);
+ el->group = group;
+ el->next = NULL;
+ (*groups->last) = el;
+ groups->last = &el->next;
+}
+
+void
+reggroup_add (struct gdbarch *gdbarch, struct reggroup *group)
+{
+ struct reggroups *groups = gdbarch_data (gdbarch, reggroups_data);
+
+ if (groups == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ groups = reggroups_init (gdbarch);
+ set_gdbarch_data (gdbarch, reggroups_data, groups);
+ }
+ add_group (groups, group,
+ GDBARCH_OBSTACK_ZALLOC (gdbarch, struct reggroup_el));
+}
+
+/* The default register groups for an architecture. */
+
+static struct reggroups default_groups = { NULL, &default_groups.first };
+
+/* A register group iterator. */
+
+struct reggroup *
+reggroup_next (struct gdbarch *gdbarch, struct reggroup *last)
+{
+ struct reggroups *groups;
+ struct reggroup_el *el;
+
+ /* Don't allow this function to be called during architecture
+ creation. If there are no groups, use the default groups list. */
+ groups = gdbarch_data (gdbarch, reggroups_data);
+ gdb_assert (groups != NULL);
+ if (groups->first == NULL)
+ groups = &default_groups;
+
+ /* Return the first/next reggroup. */
+ if (last == NULL)
+ return groups->first->group;
+ for (el = groups->first; el != NULL; el = el->next)
+ {
+ if (el->group == last)
+ {
+ if (el->next != NULL)
+ return el->next->group;
+ else
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+/* Is REGNUM a member of REGGROUP? */
+int
+default_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ int vector_p;
+ int float_p;
+ int raw_p;
+
+ if (REGISTER_NAME (regnum) == NULL
+ || *REGISTER_NAME (regnum) == '\0')
+ return 0;
+ if (group == all_reggroup)
+ return 1;
+ vector_p = TYPE_VECTOR (register_type (gdbarch, regnum));
+ float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT;
+ /* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs
+ (gdbarch), as not all architectures are multi-arch. */
+ raw_p = regnum < NUM_REGS;
+ if (group == float_reggroup)
+ return float_p;
+ if (group == vector_reggroup)
+ return vector_p;
+ if (group == general_reggroup)
+ return (!vector_p && !float_p);
+ if (group == save_reggroup || group == restore_reggroup)
+ return raw_p;
+ return 0;
+}
+
+/* Dump out a table of register groups for the current architecture. */
+
+static void
+reggroups_dump (struct gdbarch *gdbarch, struct ui_file *file)
+{
+ struct reggroup *group = NULL;
+
+ do
+ {
+ /* Group name. */
+ {
+ const char *name;
+ if (group == NULL)
+ name = "Group";
+ else
+ name = reggroup_name (group);
+ fprintf_unfiltered (file, " %-10s", name);
+ }
+
+ /* Group type. */
+ {
+ const char *type;
+ if (group == NULL)
+ type = "Type";
+ else
+ {
+ switch (reggroup_type (group))
+ {
+ case USER_REGGROUP:
+ type = "user";
+ break;
+ case INTERNAL_REGGROUP:
+ type = "internal";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ }
+ fprintf_unfiltered (file, " %-10s", type);
+ }
+
+ /* Note: If you change this, be sure to also update the
+ documentation. */
+
+ fprintf_unfiltered (file, "\n");
+
+ group = reggroup_next (gdbarch, group);
+ }
+ while (group != NULL);
+}
+
+static void
+maintenance_print_reggroups (char *args, int from_tty)
+{
+ if (args == NULL)
+ reggroups_dump (current_gdbarch, gdb_stdout);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print reggroups");
+ reggroups_dump (current_gdbarch, file);
+ ui_file_delete (file);
+ }
+}
+
+/* Pre-defined register groups. */
+static struct reggroup general_group = { "general", USER_REGGROUP };
+static struct reggroup float_group = { "float", USER_REGGROUP };
+static struct reggroup system_group = { "system", USER_REGGROUP };
+static struct reggroup vector_group = { "vector", USER_REGGROUP };
+static struct reggroup all_group = { "all", USER_REGGROUP };
+static struct reggroup save_group = { "save", INTERNAL_REGGROUP };
+static struct reggroup restore_group = { "restore", INTERNAL_REGGROUP };
+
+struct reggroup *const general_reggroup = &general_group;
+struct reggroup *const float_reggroup = &float_group;
+struct reggroup *const system_reggroup = &system_group;
+struct reggroup *const vector_reggroup = &vector_group;
+struct reggroup *const all_reggroup = &all_group;
+struct reggroup *const save_reggroup = &save_group;
+struct reggroup *const restore_reggroup = &restore_group;
+
+extern initialize_file_ftype _initialize_reggroup; /* -Wmissing-prototypes */
+
+void
+_initialize_reggroup (void)
+{
+ reggroups_data = register_gdbarch_data (reggroups_init);
+
+ /* The pre-defined list of groups. */
+ add_group (&default_groups, general_reggroup, XMALLOC (struct reggroup_el));
+ add_group (&default_groups, float_reggroup, XMALLOC (struct reggroup_el));
+ add_group (&default_groups, system_reggroup, XMALLOC (struct reggroup_el));
+ add_group (&default_groups, vector_reggroup, XMALLOC (struct reggroup_el));
+ add_group (&default_groups, all_reggroup, XMALLOC (struct reggroup_el));
+ add_group (&default_groups, save_reggroup, XMALLOC (struct reggroup_el));
+ add_group (&default_groups, restore_reggroup, XMALLOC (struct reggroup_el));
+
+ add_cmd ("reggroups", class_maintenance,
+ maintenance_print_reggroups, "\
+Print the internal register group names.\n\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+
+}
diff --git a/contrib/gdb/gdb/reggroups.h b/contrib/gdb/gdb/reggroups.h
new file mode 100644
index 0000000..22c0a6f
--- /dev/null
+++ b/contrib/gdb/gdb/reggroups.h
@@ -0,0 +1,64 @@
+/* Register groupings for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 REGGROUPS_H
+#define REGGROUPS_H
+
+struct gdbarch;
+struct reggroup;
+
+enum reggroup_type { USER_REGGROUP, INTERNAL_REGGROUP };
+
+/* Pre-defined, user visible, register groups. */
+extern struct reggroup *const general_reggroup;
+extern struct reggroup *const float_reggroup;
+extern struct reggroup *const system_reggroup;
+extern struct reggroup *const vector_reggroup;
+extern struct reggroup *const all_reggroup;
+
+/* Pre-defined, internal, register groups. */
+extern struct reggroup *const save_reggroup;
+extern struct reggroup *const restore_reggroup;
+
+/* Create a new local register group. */
+extern struct reggroup *reggroup_new (const char *name,
+ enum reggroup_type type);
+
+/* Add a register group (with attribute values) to the pre-defined list. */
+extern void reggroup_add (struct gdbarch *gdbarch, struct reggroup *group);
+
+/* Register group attributes. */
+extern const char *reggroup_name (struct reggroup *reggroup);
+extern enum reggroup_type reggroup_type (struct reggroup *reggroup);
+
+/* Interator for the architecture's register groups. Pass in NULL,
+ returns the first group. Pass in a group, returns the next group,
+ or NULL when the last group is reached. */
+extern struct reggroup *reggroup_next (struct gdbarch *gdbarch,
+ struct reggroup *last);
+
+/* Is REGNUM a member of REGGROUP? */
+extern int default_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *reggroup);
+
+#endif
diff --git a/contrib/gdb/gdb/regset.h b/contrib/gdb/gdb/regset.h
new file mode 100644
index 0000000..6172f0f
--- /dev/null
+++ b/contrib/gdb/gdb/regset.h
@@ -0,0 +1,41 @@
+/* Manage register sets.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 REGSET_H
+#define REGSET_H 1
+
+struct gdbarch;
+struct regcache;
+
+/* Data structure describing a register set. */
+
+struct regset
+{
+ /* Data pointer for private use by the methods below, presumably
+ providing some sort of description of the register set. */
+ const void *descr;
+
+ /* Function supplying a register set to a register cache. */
+ void (*supply_regset) (const struct regset *, struct regcache *,
+ int, const void *, size_t);
+};
+
+#endif /* regset.h */
diff --git a/contrib/gdb/gdb/remote-e7000.c b/contrib/gdb/gdb/remote-e7000.c
new file mode 100644
index 0000000..c422c94
--- /dev/null
+++ b/contrib/gdb/gdb/remote-e7000.c
@@ -0,0 +1,2194 @@
+/* Remote debugging interface for Renesas E7000 ICE, for GDB
+
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003 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 Renesas H8/300-H and
+ Renesas-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 "gdbarch.h"
+#include "inferior.h"
+#include "target.h"
+#include "value.h"
+#include "command.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"
+#include <sys/types.h>
+#include "serial.h"
+#include "remote-utils.h"
+#include "symfile.h"
+#include "regcache.h"
+#include <time.h>
+#include <ctype.h>
+
+
+#if 1
+#define HARD_BREAKPOINTS /* Now handled by set option. */
+#define BC_BREAKPOINTS use_hard_breakpoints
+#endif
+
+#define CTRLC 0x03
+#define ENQ 0x05
+#define ACK 0x06
+#define CTRLZ 0x1a
+
+/* This file is used by 2 different targets, sh-elf and h8300. The
+ h8300 is not multiarched and doesn't use the registers defined in
+ tm-sh.h. To avoid using a macro GDB_TARGET_IS_SH, we do runtime check
+ of the target, which requires that these namse below are always
+ defined also in the h8300 case. */
+
+#if !defined (PR_REGNUM)
+#define PR_REGNUM -1
+#endif
+#if !defined (GBR_REGNUM)
+#define GBR_REGNUM -1
+#endif
+#if !defined (VBR_REGNUM)
+#define VBR_REGNUM -1
+#endif
+#if !defined (MACH_REGNUM)
+#define MACH_REGNUM -1
+#endif
+#if !defined (MACL_REGNUM)
+#define MACL_REGNUM -1
+#endif
+#if !defined (SR_REGNUM)
+#define SR_REGNUM -1
+#endif
+
+extern void report_transfer_performance (unsigned long, time_t, time_t);
+
+extern char *sh_processor_type;
+
+/* Local function declarations. */
+
+static void e7000_close (int);
+
+static void e7000_fetch_register (int);
+
+static void e7000_store_register (int);
+
+static void e7000_command (char *, int);
+
+static void e7000_login_command (char *, int);
+
+static void e7000_ftp_command (char *, int);
+
+static void e7000_drain_command (char *, int);
+
+static void expect (char *);
+
+static void expect_full_prompt (void);
+
+static void expect_prompt (void);
+
+static int e7000_parse_device (char *args, char *dev_name, int baudrate);
+/* Variables. */
+
+static struct serial *e7000_desc;
+
+/* Allow user to chose between using hardware breakpoints or memory. */
+static int use_hard_breakpoints = 0; /* use sw breakpoints by default */
+
+/* Nonzero if using the tcp serial driver. */
+
+static int using_tcp; /* direct tcp connection to target */
+static int using_tcp_remote; /* indirect connection to target
+ via tcp to controller */
+
+/* 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 = 20;
+
+/* Send data to e7000debug. */
+
+static void
+puts_e7000debug (char *buf)
+{
+ if (!e7000_desc)
+ error ("Use \"target e7000 ...\" first.");
+
+ if (remote_debug)
+ printf_unfiltered ("Sending %s\n", buf);
+
+ if (serial_write (e7000_desc, buf, strlen (buf)))
+ fprintf_unfiltered (gdb_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 (int x)
+{
+ char b[1];
+
+ b[0] = x;
+ serial_write (e7000_desc, b, 1);
+}
+
+static void
+write_e7000 (char *s)
+{
+ serial_write (e7000_desc, s, strlen (s));
+}
+
+static int
+normal (int x)
+{
+ if (x == '\n')
+ return '\r';
+ return x;
+}
+
+/* Read a character from the remote system, doing all the fancy timeout
+ stuff. Handles serial errors and EOF. If TIMEOUT == 0, and no chars,
+ returns -1, else returns next char. Discards chars > 127. */
+
+static int
+readchar (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.");
+ }
+ else if (c < 0)
+ error ("Serial communication error");
+
+ if (remote_debug)
+ {
+ putchar_unfiltered (c);
+ gdb_flush (gdb_stdout);
+ }
+
+ return normal (c);
+}
+
+#if 0
+char *
+tl (int 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 (char *string)
+{
+ char *p = string;
+ int c;
+ int nl = 0;
+
+ while (1)
+ {
+ c = readchar (timeout);
+
+ if (echo)
+ {
+ if (c == '\r' || c == '\n')
+ {
+ if (!nl)
+ putchar_unfiltered ('\n');
+ nl = 1;
+ }
+ else
+ {
+ nl = 0;
+ putchar_unfiltered (c);
+ }
+ gdb_flush (gdb_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 (void)
+{
+ expect (":");
+}
+
+static void
+expect_full_prompt (void)
+{
+ expect ("\r:");
+}
+
+static int
+convert_hex_digit (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 (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 (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 (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 executable 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 (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 (char *args, int from_tty)
+{
+ if (args)
+ {
+ machine = next (&args);
+ user = next (&args);
+ passwd = next (&args);
+ dir = next (&args);
+ if (from_tty)
+ {
+ printf_unfiltered ("Set info to %s %s %s %s\n", machine, user, passwd, dir);
+ }
+ }
+ else
+ {
+ error ("Syntax is ftplogin <machine> <user> <passwd> <directory>");
+ }
+}
+
+/* Start an ftp transfer from the E7000 to a host */
+
+static void
+e7000_ftp_command (char *args, int from_tty)
+{
+ /* FIXME: arbitrary limit on machine names and such. */
+ char buf[200];
+
+ int oldtimeout = timeout;
+ timeout = remote_timeout;
+
+ 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 int
+e7000_parse_device (char *args, char *dev_name, int baudrate)
+{
+ char junk[128];
+ int n = 0;
+ if (args && strcasecmp (args, "pc") == 0)
+ {
+ strcpy (dev_name, args);
+ using_pc = 1;
+ }
+ else
+ {
+ /* FIXME! temp hack to allow use with port master -
+ target tcp_remote <device> */
+ if (args && strncmp (args, "tcp", 10) == 0)
+ {
+ char com_type[128];
+ n = sscanf (args, " %s %s %d %s", com_type, dev_name, &baudrate, junk);
+ using_tcp_remote = 1;
+ n--;
+ }
+ else if (args)
+ {
+ n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk);
+ }
+
+ if (n != 1 && n != 2)
+ {
+ error ("Bad arguments. Usage:\ttarget e7000 <device> <speed>\n\
+or \t\ttarget e7000 <host>[:<port>]\n\
+or \t\ttarget e7000 tcp_remote <host>[:<port>]\n\
+or \t\ttarget e7000 pc\n");
+ }
+
+#if !defined(__GO32__) && !defined(_WIN32) && !defined(__CYGWIN__)
+ /* FIXME! test for ':' is ambiguous */
+ if (n == 1 && strchr (dev_name, ':') == 0)
+ {
+ /* Default to normal telnet port */
+ /* serial_open will use this to determine tcp communication */
+ strcat (dev_name, ":23");
+ }
+#endif
+ if (!using_tcp_remote && strchr (dev_name, ':'))
+ using_tcp = 1;
+ }
+
+ return n;
+}
+
+/* Stub for catch_errors. */
+
+static int
+e7000_start_remote (void *dummy)
+{
+ int loop;
+ int sync;
+ int try;
+ int quit_trying;
+
+ immediate_quit++; /* Allow user to interrupt it */
+
+ /* Hello? Are you there? */
+ sync = 0;
+ loop = 0;
+ try = 0;
+ quit_trying = 20;
+ putchar_e7000 (CTRLC);
+ while (!sync && ++try <= quit_trying)
+ {
+ int c;
+
+ printf_unfiltered ("[waiting for e7000...]\n");
+
+ write_e7000 ("\r");
+ c = readchar (1);
+
+ /* FIXME! this didn't seem right-> while (c != SERIAL_TIMEOUT)
+ * we get stuck in this loop ...
+ * We may never timeout, and never sync up :-(
+ */
+ while (!sync && c != -1)
+ {
+ /* Dont echo cr's */
+ if (c != '\r')
+ {
+ putchar_unfiltered (c);
+ gdb_flush (gdb_stdout);
+ }
+ /* Shouldn't we either break here, or check for sync in inner loop? */
+ if (c == ':')
+ sync = 1;
+
+ if (loop++ == 20)
+ {
+ putchar_e7000 (CTRLC);
+ loop = 0;
+ }
+
+ QUIT;
+
+ if (quit_flag)
+ {
+ putchar_e7000 (CTRLC);
+ /* Was-> quit_flag = 0; */
+ c = -1;
+ quit_trying = try + 1; /* we don't want to try anymore */
+ }
+ else
+ {
+ c = readchar (1);
+ }
+ }
+ }
+
+ if (!sync)
+ {
+ fprintf_unfiltered (gdb_stderr, "Giving up after %d tries...\n", try);
+ error ("Unable to synchronize with target.\n");
+ }
+
+ puts_e7000debug ("\r");
+ expect_prompt ();
+ puts_e7000debug ("b -\r"); /* Clear breakpoints */
+ expect_prompt ();
+
+ immediate_quit--;
+
+/* 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. */
+
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc ();
+ print_stack_frame (get_selected_frame (), -1, 1);
+
+ return 1;
+}
+
+static void
+e7000_open (char *args, int from_tty)
+{
+ int n;
+
+ target_preopen (from_tty);
+
+ n = e7000_parse_device (args, dev_name, baudrate);
+
+ push_target (&e7000_ops);
+
+ e7000_desc = serial_open (dev_name);
+
+ if (!e7000_desc)
+ perror_with_name (dev_name);
+
+ if (serial_setbaudrate (e7000_desc, baudrate))
+ {
+ serial_close (e7000_desc);
+ perror_with_name (dev_name);
+ }
+ serial_raw (e7000_desc);
+
+ /* 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 (e7000_start_remote, (char *) 0,
+ "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
+ if (from_tty)
+ printf_filtered ("Remote target %s connected to %s\n", target_shortname,
+ dev_name);
+}
+
+/* Close out all files and local state before this target loses control. */
+
+static void
+e7000_close (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 (char *arg, int from_tty)
+{
+ pop_target (); /* calls e7000_close to do the real work */
+ if (from_tty)
+ printf_unfiltered ("Ending remote %s debugging\n", target_shortname);
+}
+
+/* Tell the remote machine to resume. */
+
+static void
+e7000_resume (ptid_t ptid, int step, enum target_signal sigal)
+{
+ 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
+ */
+
+char *want_h8300h = "PC=%p CCR=%c\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7\n";
+
+char *want_nopc_h8300h = "%p CCR=%c\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7";
+
+char *want_h8300s = "PC=%p CCR=%c\n\
+ MACH=\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7\n";
+
+char *want_nopc_h8300s = "%p CCR=%c EXR=%9\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7";
+
+char *want_sh = "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_sh = "%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";
+
+char *want_sh3 = "PC=%16 SR=%22\n\
+PR=%17 GBR=%18 VBR=%19\n\
+MACH=%20 MACL=%21 SSR=%23 SPC=%24\n\
+R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\
+R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\
+R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\
+R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\
+R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\
+R4_BANK1-R7_BANK1 %37 %38 %39 %40";
+
+char *want_nopc_sh3 = "%16 SR=%22\n\
+ PR=%17 GBR=%18 VBR=%19\n\
+ MACH=%20 MACL=%21 SSR=%22 SPC=%23\n\
+ R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\
+ R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\
+ R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\
+ R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\
+ R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\
+ R4_BANK1-R7_BANK1 %37 %38 %39 %40";
+
+static int
+gch (void)
+{
+ return readchar (timeout);
+}
+
+static unsigned int
+gbyte (void)
+{
+ int high = convert_hex_digit (gch ());
+ int low = convert_hex_digit (gch ());
+
+ return (high << 4) + low;
+}
+
+static void
+fetch_regs_from_dump (int (*nextchar) (), char *want)
+{
+ int regno;
+ char buf[MAX_REGISTER_SIZE];
+
+ int thischar = nextchar ();
+
+ if (want == NULL)
+ internal_error (__FILE__, __LINE__, "Register set not selected.");
+
+ 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 DEPRECATED_FP_REGNUM
+ case 'f':
+ regno = DEPRECATED_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
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ store_signed_integer (buf,
+ DEPRECATED_REGISTER_RAW_SIZE (regno),
+ (LONGEST) get_hex (&thischar));
+ supply_register (regno, buf);
+ break;
+ }
+ }
+}
+
+static void
+e7000_fetch_registers (void)
+{
+ int regno;
+ char *wanted = NULL;
+
+ puts_e7000debug ("R\r");
+
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_sh)
+ {
+ wanted = want_sh;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_sh3:
+ case bfd_mach_sh3e:
+ case bfd_mach_sh4:
+ wanted = want_sh3;
+ }
+ }
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_h8300)
+ {
+ wanted = want_h8300h;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_h8300s:
+ case bfd_mach_h8300sn:
+ case bfd_mach_h8300sx:
+ case bfd_mach_h8300sxn:
+ wanted = want_h8300s;
+ }
+ }
+
+ fetch_regs_from_dump (gch, wanted);
+
+ /* 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 (int regno)
+{
+ e7000_fetch_registers ();
+}
+
+/* Store the remote registers from the contents of the block REGS. */
+
+static void
+e7000_store_registers (void)
+{
+ 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 (int regno)
+{
+ char buf[200];
+
+ if (regno == -1)
+ {
+ e7000_store_registers ();
+ return;
+ }
+
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_h8300)
+ {
+ if (regno <= 7)
+ {
+ sprintf (buf, ".ER%d %s\r", regno, phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+ else if (regno == PC_REGNUM)
+ {
+ sprintf (buf, ".PC %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+#ifdef CCR_REGNUM
+ else if (regno == CCR_REGNUM)
+ {
+ sprintf (buf, ".CCR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+#endif
+ }
+
+ else if (TARGET_ARCHITECTURE->arch == bfd_arch_sh)
+ {
+ if (regno == PC_REGNUM)
+ {
+ sprintf (buf, ".PC %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == SR_REGNUM)
+ {
+ sprintf (buf, ".SR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == PR_REGNUM)
+ {
+ sprintf (buf, ".PR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == GBR_REGNUM)
+ {
+ sprintf (buf, ".GBR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == VBR_REGNUM)
+ {
+ sprintf (buf, ".VBR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == MACH_REGNUM)
+ {
+ sprintf (buf, ".MACH %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == MACL_REGNUM)
+ {
+ sprintf (buf, ".MACL %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+ else
+ {
+ sprintf (buf, ".R%d %s\r", regno, phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+ }
+
+ 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 (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static void
+e7000_files_info (struct target_ops *ops)
+{
+ printf_unfiltered ("\tAttached to %s at %d baud.\n", dev_name, baudrate);
+}
+
+static int
+stickbyte (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 (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 %s %x%02x%02x%02x;l\r",
+ paddr_nz (memaddr + i),
+ myaddr[i], myaddr[i + 1], myaddr[i + 2], myaddr[i + 3]);
+ puts_e7000debug (buf);
+ i += 3;
+ }
+ else
+ {
+ sprintf (buf, "m %s %x\r", paddr_nz (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 (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 = readchar (0);
+ if (j == -1)
+ {
+ /* This is ok - nothing there */
+ }
+ else if (j == ENQ)
+ {
+ /* Hmm, it's trying to tell us something */
+ expect (":");
+ error ("Error writing memory");
+ }
+ else
+ {
+ printf_unfiltered ("@%d}@", j);
+ while ((j = readchar (0)) > 0)
+ {
+ printf_unfiltered ("@{%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 (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 <addr>;l
+ and receive
+ 00000000 12345678 ?
+ */
+
+static int
+e7000_read_inferior_memory (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 %s;l\r", paddr_nz (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 */
+ puts_e7000debug (".\r"); /* Some errors leave us in memory input mode */
+ expect_full_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;
+}
+
+
+
+/*
+ For large transfers we used to send
+
+
+ d <addr> <endaddr>\r
+
+ and receive
+ <ADDRESS> < D A T A > < ASCII CODE >
+ 00000000 5F FD FD FF DF 7F DF FF 01 00 01 00 02 00 08 04 "_..............."
+ 00000010 FF D7 FF 7F D7 F1 7F FF 00 05 00 00 08 00 40 00 "..............@."
+ 00000020 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_large (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 %s %s\r", paddr_nz (memaddr), paddr_nz (memaddr + len - 1));
+ puts_e7000debug (buf);
+
+ count = 0;
+ c = gch ();
+
+ /* skip down to the first ">" */
+ while (c != '>')
+ c = gch ();
+ /* now skip to the end of that line */
+ while (c != '\r')
+ c = gch ();
+ c = gch ();
+
+ while (count < len)
+ {
+ /* get rid of any white space before the address */
+ while (c <= ' ')
+ c = gch ();
+
+ /* Skip the address */
+ get_hex (&c);
+
+ /* read in the bytes on the line */
+ while (c != '"' && count < len)
+ {
+ if (c == ' ')
+ c = gch ();
+ else
+ {
+ myaddr[count++] = get_hex (&c);
+ }
+ }
+ /* throw out the rest of the line */
+ while (c != '\r')
+ c = gch ();
+ }
+
+ /* wait for the ":" prompt */
+ while (c != ':')
+ c = gch ();
+
+ return len;
+}
+
+#if 0
+
+static int
+fast_but_for_the_pause_e7000_read_inferior_memory (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
+
+/* Transfer LEN bytes between GDB address MYADDR and target address
+ MEMADDR. If WRITE is non-zero, transfer them to the target,
+ otherwise transfer them from the target. TARGET is unused.
+
+ Returns the number of bytes transferred. */
+
+static int
+e7000_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ if (write)
+ return e7000_write_inferior_memory (memaddr, myaddr, len);
+ else if (len < 16)
+ return e7000_read_inferior_memory (memaddr, myaddr, len);
+ else
+ return e7000_read_inferior_memory_large (memaddr, myaddr, len);
+}
+
+static void
+e7000_kill (void)
+{
+}
+
+static void
+e7000_load (char *args, int from_tty)
+{
+ struct cleanup *old_chain;
+ asection *section;
+ bfd *pbfd;
+ bfd_vma entry;
+#define WRITESIZE 0x1000
+ char buf[2 + 4 + 4 + WRITESIZE]; /* `DT' + <addr> + <len> + <data> */
+ 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 */
+ int oldtimeout = timeout;
+
+ timeout = remote_timeout;
+
+
+ /* FIXME! change test to test for type of download */
+ if (!using_tcp)
+ {
+ generic_load (args, from_tty);
+ return;
+ }
+
+ /* for direct tcp connections, we can do a fast binary download */
+ 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%s (%s bytes)]\n",
+ bfd_get_section_name (pbfd, section),
+ paddr_nz (section_address),
+ paddr_u (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_ptid = null_ptid; /* 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%s]\n", filename, paddr_nz (entry));
+
+/* start_routine (entry); */
+ }
+
+ report_transfer_performance (data_count, start_time, end_time);
+
+ do_cleanups (old_chain);
+ timeout = oldtimeout;
+}
+
+/* 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 (void)
+{
+ remove_breakpoints ();
+ unpush_target (&e7000_ops);
+ generic_mourn_inferior (); /* Do all the proper things now */
+}
+
+#define MAX_BREAKPOINTS 200
+#ifdef HARD_BREAKPOINTS
+#define MAX_E7000DEBUG_BREAKPOINTS (BC_BREAKPOINTS ? 5 : MAX_BREAKPOINTS)
+#else
+#define MAX_E7000DEBUG_BREAKPOINTS MAX_BREAKPOINTS
+#endif
+
+/* Since we can change to soft breakpoints dynamically, we must define
+ more than enough. Was breakaddr[MAX_E7000DEBUG_BREAKPOINTS]. */
+static CORE_ADDR breakaddr[MAX_BREAKPOINTS] =
+{0};
+
+static int
+e7000_insert_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int i;
+ char buf[200];
+#if 0
+ static char nop[2] = NOP;
+#endif
+
+ 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=%s\r", i + 1, paddr_nz (addr));
+ puts_e7000debug (buf);
+ }
+ else
+ {
+ sprintf (buf, "B %s\r", paddr_nz (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 (CORE_ADDR addr, 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 - %s\r", paddr_nz (addr));
+ puts_e7000debug (buf);
+ }
+ expect_prompt ();
+#else
+ sprintf (buf, "B - %s\r", paddr_nz (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%s\n", paddr_nz (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 (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 (char *args, int fromtty)
+{
+ int c;
+
+ puts_e7000debug ("end\r");
+ putchar_e7000 (CTRLC);
+
+ while ((c = readchar (1)) != -1)
+ {
+ if (quit_flag)
+ {
+ putchar_e7000 (CTRLC);
+ quit_flag = 0;
+ }
+ if (c > ' ' && c < 127)
+ printf_unfiltered ("%c", c & 0xff);
+ else
+ printf_unfiltered ("<%x>", c & 0xff);
+ }
+}
+
+#define NITEMS 7
+
+static int
+why_stop (void)
+{
+ 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. */
+
+static int
+expect_n (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 = readchar (1);
+ if (c == -1)
+ {
+ 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_unfiltered ("%s", buffer);
+ buffer = saveaway;
+ }
+ if (c != -1)
+ {
+ putchar_unfiltered (c);
+ gdb_flush (gdb_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 (void)
+{
+ char buf[4];
+ char buf2[200];
+
+ store_signed_integer (buf,
+ DEPRECATED_REGISTER_RAW_SIZE (PC_REGNUM),
+ read_register (PC_REGNUM) - 2);
+ supply_register (PC_REGNUM, buf);
+ sprintf (buf2, ".PC %s\r", phex_nz (read_register (PC_REGNUM), 0));
+ 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 ptid_t
+e7000_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ int stop_reason;
+ int regno;
+ int running_count = 0;
+ int had_sleep = 0;
+ int loop = 1;
+ char *wanted_nopc = NULL;
+
+ /* 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 ("=");
+
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_sh)
+ {
+ wanted_nopc = want_nopc_sh;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_sh3:
+ case bfd_mach_sh3e:
+ case bfd_mach_sh4:
+ wanted_nopc = want_nopc_sh3;
+ }
+ }
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_h8300)
+ {
+ wanted_nopc = want_nopc_h8300h;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_h8300s:
+ case bfd_mach_h8300sn:
+ case bfd_mach_h8300sx:
+ case bfd_mach_h8300sxn:
+ wanted_nopc = want_nopc_h8300s;
+ }
+ }
+ fetch_regs_from_dump (gch, wanted_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. */
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+
+ return inferior_ptid;
+}
+
+/* Stop the running program. */
+
+static void
+e7000_stop (void)
+{
+ /* Sending a ^C is supposed to stop the running program. */
+ putchar_e7000 (CTRLC);
+}
+
+/* Define the target subroutine names. */
+
+struct target_ops e7000_ops;
+
+static void
+init_e7000_ops (void)
+{
+ e7000_ops.to_shortname = "e7000";
+ e7000_ops.to_longname = "Remote Renesas e7000 target";
+ e7000_ops.to_doc = "Use a remote Renesas 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_ops.to_open = e7000_open;
+ e7000_ops.to_close = e7000_close;
+ e7000_ops.to_detach = e7000_detach;
+ e7000_ops.to_resume = e7000_resume;
+ e7000_ops.to_wait = e7000_wait;
+ e7000_ops.to_fetch_registers = e7000_fetch_register;
+ e7000_ops.to_store_registers = e7000_store_register;
+ e7000_ops.to_prepare_to_store = e7000_prepare_to_store;
+ e7000_ops.to_xfer_memory = e7000_xfer_inferior_memory;
+ e7000_ops.to_files_info = e7000_files_info;
+ e7000_ops.to_insert_breakpoint = e7000_insert_breakpoint;
+ e7000_ops.to_remove_breakpoint = e7000_remove_breakpoint;
+ e7000_ops.to_kill = e7000_kill;
+ e7000_ops.to_load = e7000_load;
+ e7000_ops.to_create_inferior = e7000_create_inferior;
+ e7000_ops.to_mourn_inferior = e7000_mourn_inferior;
+ e7000_ops.to_stop = e7000_stop;
+ e7000_ops.to_stratum = process_stratum;
+ e7000_ops.to_has_all_memory = 1;
+ e7000_ops.to_has_memory = 1;
+ e7000_ops.to_has_stack = 1;
+ e7000_ops.to_has_registers = 1;
+ e7000_ops.to_has_execution = 1;
+ e7000_ops.to_magic = OPS_MAGIC;
+};
+
+extern initialize_file_ftype _initialize_remote_e7000; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_e7000 (void)
+{
+ init_e7000_ops ();
+ 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.");
+
+ add_show_from_set (add_set_cmd ("usehardbreakpoints", no_class,
+ var_integer, (char *) &use_hard_breakpoints,
+ "Set use of hardware breakpoints for all breakpoints.\n", &setlist),
+ &showlist);
+}
diff --git a/contrib/gdb/gdb/remote-est.c b/contrib/gdb/gdb/remote-est.c
new file mode 100644
index 0000000..a2c0f7c
--- /dev/null
+++ b/contrib/gdb/gdb/remote-est.c
@@ -0,0 +1,186 @@
+/* Remote debugging interface for EST-300 ICE, for GDB
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ 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"
+#include "regcache.h"
+
+#include "m68k-tdep.h"
+
+static void est_open (char *args, int from_tty);
+
+static void
+est_supply_register (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' + M68K_D0_REGNUM;
+ break;
+ case 'A':
+ if (regname[1] < '0' || regname[1] > '7')
+ return;
+ regno = regname[1] - '0' + M68K_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 const char *
+est_regname (int index)
+{
+
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "SR", "PC",
+ };
+
+
+ if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+}
+
+/*
+ * 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;
+
+static void
+init_est_cmds (void)
+{
+ est_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_NEED_REGDUMP_AFTER_CONT |
+ MO_SREC_ACK | MO_SREC_ACK_PLUS;
+ est_cmds.init = est_inits; /* Init strings */
+ est_cmds.cont = "go\r"; /* continue command */
+ est_cmds.step = "sidr\r"; /* single step */
+ est_cmds.stop = "\003"; /* ^C interrupts the program */
+ est_cmds.set_break = "sb %x\r"; /* set a breakpoint */
+ est_cmds.clr_break = "rb %x\r"; /* clear a breakpoint */
+ est_cmds.clr_all_break = "rb\r"; /* clear all breakpoints */
+ est_cmds.fill = "bfb %x %x %x\r"; /* fill (start end val) */
+ est_cmds.setmem.cmdb = "smb %x %x\r"; /* setmem.cmdb (addr, value) */
+ est_cmds.setmem.cmdw = "smw %x %x\r"; /* setmem.cmdw (addr, value) */
+ est_cmds.setmem.cmdl = "sml %x %x\r"; /* setmem.cmdl (addr, value) */
+ est_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ est_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ est_cmds.setmem.term = NULL; /* setreg.term */
+ est_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ est_cmds.getmem.cmdb = "dmb %x %x\r"; /* getmem.cmdb (addr, len) */
+ est_cmds.getmem.cmdw = "dmw %x %x\r"; /* getmem.cmdw (addr, len) */
+ est_cmds.getmem.cmdl = "dml %x %x\r"; /* getmem.cmdl (addr, len) */
+ est_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
+ est_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
+ est_cmds.getmem.term = NULL; /* getmem.term */
+ est_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
+ est_cmds.setreg.cmd = "sr %s %x\r"; /* setreg.cmd (name, value) */
+ est_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ est_cmds.setreg.term = NULL; /* setreg.term */
+ est_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ est_cmds.getreg.cmd = "dr %s\r"; /* getreg.cmd (name) */
+ est_cmds.getreg.resp_delim = " = "; /* getreg.resp_delim */
+ est_cmds.getreg.term = NULL; /* getreg.term */
+ est_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
+ est_cmds.dump_registers = "dr\r"; /* dump_registers */
+ est_cmds.register_pattern = "\\(\\w+\\) = \\([0-9a-fA-F]+\\)"; /* register_pattern */
+ est_cmds.supply_register = est_supply_register; /* supply_register */
+ est_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ est_cmds.load = "dl\r"; /* download command */
+ est_cmds.loadresp = "+"; /* load response */
+ est_cmds.prompt = ">BKM>"; /* monitor command prompt */
+ est_cmds.line_term = "\r"; /* end-of-line terminator */
+ est_cmds.cmd_end = NULL; /* optional command terminator */
+ est_cmds.target = &est_ops; /* target operations */
+ est_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ est_cmds.regnames = NULL;
+ est_cmds.regname = est_regname; /*register names*/
+ est_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+} /* init_est_cmds */
+
+static void
+est_open (char *args, int from_tty)
+{
+ monitor_open (args, &est_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_est; /* -Wmissing-prototypes */
+
+void
+_initialize_est (void)
+{
+ init_est_cmds ();
+ 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-fileio.c b/contrib/gdb/gdb/remote-fileio.c
new file mode 100644
index 0000000..281872e
--- /dev/null
+++ b/contrib/gdb/gdb/remote-fileio.c
@@ -0,0 +1,1384 @@
+/* Remote File-I/O communications
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* See the GDB User Guide for details of the GDB remote protocol. */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"
+#include "remote.h"
+#include "gdb/fileio.h"
+#include "gdb_wait.h"
+#include "gdb_stat.h"
+#include "remote-fileio.h"
+
+#include <fcntl.h>
+#include <sys/time.h>
+#ifdef __CYGWIN__
+#include <sys/cygwin.h> /* For cygwin_conv_to_full_posix_path. */
+#endif
+#include <signal.h>
+
+static struct {
+ int *fd_map;
+ int fd_map_size;
+} remote_fio_data;
+
+#define FIO_FD_INVALID -1
+#define FIO_FD_CONSOLE_IN -2
+#define FIO_FD_CONSOLE_OUT -3
+
+static int remote_fio_system_call_allowed = 0;
+
+static int
+remote_fileio_init_fd_map (void)
+{
+ int i;
+
+ if (!remote_fio_data.fd_map)
+ {
+ remote_fio_data.fd_map = (int *) xmalloc (10 * sizeof (int));
+ remote_fio_data.fd_map_size = 10;
+ remote_fio_data.fd_map[0] = FIO_FD_CONSOLE_IN;
+ remote_fio_data.fd_map[1] = FIO_FD_CONSOLE_OUT;
+ remote_fio_data.fd_map[2] = FIO_FD_CONSOLE_OUT;
+ for (i = 3; i < 10; ++i)
+ remote_fio_data.fd_map[i] = FIO_FD_INVALID;
+ }
+ return 3;
+}
+
+static int
+remote_fileio_resize_fd_map (void)
+{
+ if (!remote_fio_data.fd_map)
+ return remote_fileio_init_fd_map ();
+ remote_fio_data.fd_map_size += 10;
+ remote_fio_data.fd_map =
+ (int *) xrealloc (remote_fio_data.fd_map,
+ remote_fio_data.fd_map_size * sizeof (int));
+ return remote_fio_data.fd_map_size - 10;
+}
+
+static int
+remote_fileio_next_free_fd (void)
+{
+ int i;
+
+ for (i = 0; i < remote_fio_data.fd_map_size; ++i)
+ if (remote_fio_data.fd_map[i] == FIO_FD_INVALID)
+ return i;
+ return remote_fileio_resize_fd_map ();
+}
+
+static int
+remote_fileio_fd_to_targetfd (int fd)
+{
+ int target_fd = remote_fileio_next_free_fd ();
+ remote_fio_data.fd_map[target_fd] = fd;
+ return target_fd;
+}
+
+static int
+remote_fileio_map_fd (int target_fd)
+{
+ remote_fileio_init_fd_map ();
+ if (target_fd < 0 || target_fd >= remote_fio_data.fd_map_size)
+ return FIO_FD_INVALID;
+ return remote_fio_data.fd_map[target_fd];
+}
+
+static void
+remote_fileio_close_target_fd (int target_fd)
+{
+ remote_fileio_init_fd_map ();
+ if (target_fd >= 0 && target_fd < remote_fio_data.fd_map_size)
+ remote_fio_data.fd_map[target_fd] = FIO_FD_INVALID;
+}
+
+static int
+remote_fileio_oflags_to_host (long flags)
+{
+ int hflags = 0;
+
+ if (flags & FILEIO_O_CREAT)
+ hflags |= O_CREAT;
+ if (flags & FILEIO_O_EXCL)
+ hflags |= O_EXCL;
+ if (flags & FILEIO_O_TRUNC)
+ hflags |= O_TRUNC;
+ if (flags & FILEIO_O_APPEND)
+ hflags |= O_APPEND;
+ if (flags & FILEIO_O_RDONLY)
+ hflags |= O_RDONLY;
+ if (flags & FILEIO_O_WRONLY)
+ hflags |= O_WRONLY;
+ if (flags & FILEIO_O_RDWR)
+ hflags |= O_RDWR;
+/* On systems supporting binary and text mode, always open files in
+ binary mode. */
+#ifdef O_BINARY
+ hflags |= O_BINARY;
+#endif
+ return hflags;
+}
+
+static mode_t
+remote_fileio_mode_to_host (long mode, int open_call)
+{
+ mode_t hmode = 0;
+
+ if (!open_call)
+ {
+ if (mode & FILEIO_S_IFREG)
+ hmode |= S_IFREG;
+ if (mode & FILEIO_S_IFDIR)
+ hmode |= S_IFDIR;
+ if (mode & FILEIO_S_IFCHR)
+ hmode |= S_IFCHR;
+ }
+ if (mode & FILEIO_S_IRUSR)
+ hmode |= S_IRUSR;
+ if (mode & FILEIO_S_IWUSR)
+ hmode |= S_IWUSR;
+ if (mode & FILEIO_S_IXUSR)
+ hmode |= S_IXUSR;
+ if (mode & FILEIO_S_IRGRP)
+ hmode |= S_IRGRP;
+ if (mode & FILEIO_S_IWGRP)
+ hmode |= S_IWGRP;
+ if (mode & FILEIO_S_IXGRP)
+ hmode |= S_IXGRP;
+ if (mode & FILEIO_S_IROTH)
+ hmode |= S_IROTH;
+ if (mode & FILEIO_S_IWOTH)
+ hmode |= S_IWOTH;
+ if (mode & FILEIO_S_IXOTH)
+ hmode |= S_IXOTH;
+ return hmode;
+}
+
+static LONGEST
+remote_fileio_mode_to_target (mode_t mode)
+{
+ mode_t tmode = 0;
+
+ if (mode & S_IFREG)
+ tmode |= FILEIO_S_IFREG;
+ if (mode & S_IFDIR)
+ tmode |= FILEIO_S_IFDIR;
+ if (mode & S_IFCHR)
+ tmode |= FILEIO_S_IFCHR;
+ if (mode & S_IRUSR)
+ tmode |= FILEIO_S_IRUSR;
+ if (mode & S_IWUSR)
+ tmode |= FILEIO_S_IWUSR;
+ if (mode & S_IXUSR)
+ tmode |= FILEIO_S_IXUSR;
+ if (mode & S_IRGRP)
+ tmode |= FILEIO_S_IRGRP;
+ if (mode & S_IWGRP)
+ tmode |= FILEIO_S_IWGRP;
+ if (mode & S_IXGRP)
+ tmode |= FILEIO_S_IXGRP;
+ if (mode & S_IROTH)
+ tmode |= FILEIO_S_IROTH;
+ if (mode & S_IWOTH)
+ tmode |= FILEIO_S_IWOTH;
+ if (mode & S_IXOTH)
+ tmode |= FILEIO_S_IXOTH;
+ return tmode;
+}
+
+static int
+remote_fileio_errno_to_target (int error)
+{
+ switch (error)
+ {
+ case EPERM:
+ return FILEIO_EPERM;
+ case ENOENT:
+ return FILEIO_ENOENT;
+ case EINTR:
+ return FILEIO_EINTR;
+ case EIO:
+ return FILEIO_EIO;
+ case EBADF:
+ return FILEIO_EBADF;
+ case EACCES:
+ return FILEIO_EACCES;
+ case EFAULT:
+ return FILEIO_EFAULT;
+ case EBUSY:
+ return FILEIO_EBUSY;
+ case EEXIST:
+ return FILEIO_EEXIST;
+ case ENODEV:
+ return FILEIO_ENODEV;
+ case ENOTDIR:
+ return FILEIO_ENOTDIR;
+ case EISDIR:
+ return FILEIO_EISDIR;
+ case EINVAL:
+ return FILEIO_EINVAL;
+ case ENFILE:
+ return FILEIO_ENFILE;
+ case EMFILE:
+ return FILEIO_EMFILE;
+ case EFBIG:
+ return FILEIO_EFBIG;
+ case ENOSPC:
+ return FILEIO_ENOSPC;
+ case ESPIPE:
+ return FILEIO_ESPIPE;
+ case EROFS:
+ return FILEIO_EROFS;
+ case ENOSYS:
+ return FILEIO_ENOSYS;
+ case ENAMETOOLONG:
+ return FILEIO_ENAMETOOLONG;
+ }
+ return FILEIO_EUNKNOWN;
+}
+
+static int
+remote_fileio_seek_flag_to_host (long num, int *flag)
+{
+ if (!flag)
+ return 0;
+ switch (num)
+ {
+ case FILEIO_SEEK_SET:
+ *flag = SEEK_SET;
+ break;
+ case FILEIO_SEEK_CUR:
+ *flag = SEEK_CUR;
+ break;
+ case FILEIO_SEEK_END:
+ *flag = SEEK_END;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int
+remote_fileio_extract_long (char **buf, LONGEST *retlong)
+{
+ char *c;
+ int sign = 1;
+
+ if (!buf || !*buf || !**buf || !retlong)
+ return -1;
+ c = strchr (*buf, ',');
+ if (c)
+ *c++ = '\0';
+ else
+ c = strchr (*buf, '\0');
+ while (strchr ("+-", **buf))
+ {
+ if (**buf == '-')
+ sign = -sign;
+ ++*buf;
+ }
+ for (*retlong = 0; **buf; ++*buf)
+ {
+ *retlong <<= 4;
+ if (**buf >= '0' && **buf <= '9')
+ *retlong += **buf - '0';
+ else if (**buf >= 'a' && **buf <= 'f')
+ *retlong += **buf - 'a' + 10;
+ else if (**buf >= 'A' && **buf <= 'F')
+ *retlong += **buf - 'A' + 10;
+ else
+ return -1;
+ }
+ *retlong *= sign;
+ *buf = c;
+ return 0;
+}
+
+static int
+remote_fileio_extract_int (char **buf, long *retint)
+{
+ int ret;
+ LONGEST retlong;
+
+ if (!retint)
+ return -1;
+ ret = remote_fileio_extract_long (buf, &retlong);
+ if (!ret)
+ *retint = (long) retlong;
+ return ret;
+}
+
+static int
+remote_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length)
+{
+ char *c;
+ LONGEST retlong;
+
+ if (!buf || !*buf || !**buf || !ptrval || !length)
+ return -1;
+ c = strchr (*buf, '/');
+ if (!c)
+ return -1;
+ *c++ = '\0';
+ if (remote_fileio_extract_long (buf, &retlong))
+ return -1;
+ *ptrval = (CORE_ADDR) retlong;
+ *buf = c;
+ if (remote_fileio_extract_long (buf, &retlong))
+ return -1;
+ *length = (int) retlong;
+ return 0;
+}
+
+/* Convert to big endian */
+static void
+remote_fileio_to_be (LONGEST num, char *buf, int bytes)
+{
+ int i;
+
+ for (i = 0; i < bytes; ++i)
+ buf[i] = (num >> (8 * (bytes - i - 1))) & 0xff;
+}
+
+static void
+remote_fileio_to_fio_uint (long num, fio_uint_t fnum)
+{
+ remote_fileio_to_be ((LONGEST) num, (char *) fnum, 4);
+}
+
+static void
+remote_fileio_to_fio_mode (mode_t num, fio_mode_t fnum)
+{
+ remote_fileio_to_be (remote_fileio_mode_to_target(num), (char *) fnum, 4);
+}
+
+static void
+remote_fileio_to_fio_time (time_t num, fio_time_t fnum)
+{
+ remote_fileio_to_be ((LONGEST) num, (char *) fnum, 4);
+}
+
+static void
+remote_fileio_to_fio_long (LONGEST num, fio_long_t fnum)
+{
+ remote_fileio_to_be (num, (char *) fnum, 8);
+}
+
+static void
+remote_fileio_to_fio_ulong (LONGEST num, fio_ulong_t fnum)
+{
+ remote_fileio_to_be (num, (char *) fnum, 8);
+}
+
+static void
+remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
+{
+ /* `st_dev' is set in the calling function */
+ remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);
+ remote_fileio_to_fio_mode (st->st_mode, fst->fst_mode);
+ remote_fileio_to_fio_uint ((long) st->st_nlink, fst->fst_nlink);
+ remote_fileio_to_fio_uint ((long) st->st_uid, fst->fst_uid);
+ remote_fileio_to_fio_uint ((long) st->st_gid, fst->fst_gid);
+ remote_fileio_to_fio_uint ((long) st->st_rdev, fst->fst_rdev);
+ remote_fileio_to_fio_ulong ((LONGEST) st->st_size, fst->fst_size);
+ remote_fileio_to_fio_ulong ((LONGEST) st->st_blksize, fst->fst_blksize);
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+ remote_fileio_to_fio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks);
+#else
+ /* FIXME: This is correct for DJGPP, but other systems that don't
+ have st_blocks, if any, might prefer 512 instead of st_blksize.
+ (eliz, 30-12-2003) */
+ remote_fileio_to_fio_ulong (((LONGEST) st->st_size + st->st_blksize - 1)
+ / (LONGEST) st->st_blksize,
+ fst->fst_blocks);
+#endif
+ remote_fileio_to_fio_time (st->st_atime, fst->fst_atime);
+ remote_fileio_to_fio_time (st->st_mtime, fst->fst_mtime);
+ remote_fileio_to_fio_time (st->st_ctime, fst->fst_ctime);
+}
+
+static void
+remote_fileio_to_fio_timeval (struct timeval *tv, struct fio_timeval *ftv)
+{
+ remote_fileio_to_fio_time (tv->tv_sec, ftv->ftv_sec);
+ remote_fileio_to_fio_long (tv->tv_usec, ftv->ftv_usec);
+}
+
+static int remote_fio_ctrl_c_flag = 0;
+static int remote_fio_no_longjmp = 0;
+
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+static struct sigaction remote_fio_sa;
+static struct sigaction remote_fio_osa;
+#else
+static void (*remote_fio_ofunc)(int);
+#endif
+
+static void
+remote_fileio_sig_init (void)
+{
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+ remote_fio_sa.sa_handler = SIG_IGN;
+ sigemptyset (&remote_fio_sa.sa_mask);
+ remote_fio_sa.sa_flags = 0;
+ sigaction (SIGINT, &remote_fio_sa, &remote_fio_osa);
+#else
+ remote_fio_ofunc = signal (SIGINT, SIG_IGN);
+#endif
+}
+
+static void
+remote_fileio_sig_set (void (*sigint_func)(int))
+{
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+ remote_fio_sa.sa_handler = sigint_func;
+ sigemptyset (&remote_fio_sa.sa_mask);
+ remote_fio_sa.sa_flags = 0;
+ sigaction (SIGINT, &remote_fio_sa, NULL);
+#else
+ signal (SIGINT, sigint_func);
+#endif
+}
+
+static void
+remote_fileio_sig_exit (void)
+{
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+ sigaction (SIGINT, &remote_fio_osa, NULL);
+#else
+ signal (SIGINT, remote_fio_ofunc);
+#endif
+}
+
+static void
+remote_fileio_ctrl_c_signal_handler (int signo)
+{
+ remote_fileio_sig_set (SIG_IGN);
+ remote_fio_ctrl_c_flag = 1;
+ if (!remote_fio_no_longjmp)
+ throw_exception (RETURN_QUIT);
+ remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
+}
+
+static void
+remote_fileio_reply (int retcode, int error)
+{
+ char buf[32];
+
+ remote_fileio_sig_set (SIG_IGN);
+ strcpy (buf, "F");
+ if (retcode < 0)
+ {
+ strcat (buf, "-");
+ retcode = -retcode;
+ }
+ sprintf (buf + strlen (buf), "%x", retcode);
+ if (error || remote_fio_ctrl_c_flag)
+ {
+ if (error && remote_fio_ctrl_c_flag)
+ error = FILEIO_EINTR;
+ if (error < 0)
+ {
+ strcat (buf, "-");
+ error = -error;
+ }
+ sprintf (buf + strlen (buf), ",%x", error);
+ if (remote_fio_ctrl_c_flag)
+ strcat (buf, ",C");
+ }
+ remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
+ putpkt (buf);
+}
+
+static void
+remote_fileio_ioerror (void)
+{
+ remote_fileio_reply (-1, FILEIO_EIO);
+}
+
+static void
+remote_fileio_badfd (void)
+{
+ remote_fileio_reply (-1, FILEIO_EBADF);
+}
+
+static void
+remote_fileio_return_errno (int retcode)
+{
+ remote_fileio_reply (retcode,
+ retcode < 0 ? remote_fileio_errno_to_target (errno) : 0);
+}
+
+static void
+remote_fileio_return_success (int retcode)
+{
+ remote_fileio_reply (retcode, 0);
+}
+
+/* Wrapper function for remote_write_bytes() which has the disadvantage to
+ write only one packet, regardless of the requested number of bytes to
+ transfer. This wrapper calls remote_write_bytes() as often as needed. */
+static int
+remote_fileio_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int ret = 0, written;
+
+ while (len > 0 && (written = remote_write_bytes (memaddr, myaddr, len)) > 0)
+ {
+ len -= written;
+ memaddr += written;
+ myaddr += written;
+ ret += written;
+ }
+ return ret;
+}
+
+static void
+remote_fileio_func_open (char *buf)
+{
+ CORE_ADDR ptrval;
+ int length, retlength;
+ long num;
+ int flags, fd;
+ mode_t mode;
+ char *pathname;
+ struct stat st;
+
+ /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
+ if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* 2. Parameter: open flags */
+ if (remote_fileio_extract_int (&buf, &num))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ flags = remote_fileio_oflags_to_host (num);
+ /* 3. Parameter: open mode */
+ if (remote_fileio_extract_int (&buf, &num))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ mode = remote_fileio_mode_to_host (num, 1);
+
+ /* Request pathname using 'm' packet */
+ pathname = alloca (length);
+ retlength = remote_read_bytes (ptrval, pathname, length);
+ if (retlength != length)
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+
+ /* Check if pathname exists and is not a regular file or directory. If so,
+ return an appropriate error code. Same for trying to open directories
+ for writing. */
+ if (!stat (pathname, &st))
+ {
+ if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+ {
+ remote_fileio_reply (-1, FILEIO_ENODEV);
+ return;
+ }
+ if (S_ISDIR (st.st_mode)
+ && ((flags & O_WRONLY) == O_WRONLY || (flags & O_RDWR) == O_RDWR))
+ {
+ remote_fileio_reply (-1, FILEIO_EISDIR);
+ return;
+ }
+ }
+
+ remote_fio_no_longjmp = 1;
+ fd = open (pathname, flags, mode);
+ if (fd < 0)
+ {
+ remote_fileio_return_errno (-1);
+ return;
+ }
+
+ fd = remote_fileio_fd_to_targetfd (fd);
+ remote_fileio_return_success (fd);
+}
+
+static void
+remote_fileio_func_close (char *buf)
+{
+ long num;
+ int fd;
+
+ /* Parameter: file descriptor */
+ if (remote_fileio_extract_int (&buf, &num))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ fd = remote_fileio_map_fd ((int) num);
+ if (fd == FIO_FD_INVALID)
+ {
+ remote_fileio_badfd ();
+ return;
+ }
+
+ remote_fio_no_longjmp = 1;
+ if (fd != FIO_FD_CONSOLE_IN && fd != FIO_FD_CONSOLE_OUT && close (fd))
+ remote_fileio_return_errno (-1);
+ remote_fileio_close_target_fd ((int) num);
+ remote_fileio_return_success (0);
+}
+
+static void
+remote_fileio_func_read (char *buf)
+{
+ long target_fd, num;
+ LONGEST lnum;
+ CORE_ADDR ptrval;
+ int fd, ret, retlength;
+ char *buffer;
+ size_t length;
+ off_t old_offset, new_offset;
+
+ /* 1. Parameter: file descriptor */
+ if (remote_fileio_extract_int (&buf, &target_fd))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ fd = remote_fileio_map_fd ((int) target_fd);
+ if (fd == FIO_FD_INVALID)
+ {
+ remote_fileio_badfd ();
+ return;
+ }
+ /* 2. Parameter: buffer pointer */
+ if (remote_fileio_extract_long (&buf, &lnum))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+ /* 3. Parameter: buffer length */
+ if (remote_fileio_extract_int (&buf, &num))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ length = (size_t) num;
+
+ switch (fd)
+ {
+ case FIO_FD_CONSOLE_OUT:
+ remote_fileio_badfd ();
+ return;
+ case FIO_FD_CONSOLE_IN:
+ {
+ static char *remaining_buf = NULL;
+ static int remaining_length = 0;
+
+ buffer = (char *) xmalloc (32768);
+ if (remaining_buf)
+ {
+ remote_fio_no_longjmp = 1;
+ if (remaining_length > length)
+ {
+ memcpy (buffer, remaining_buf, length);
+ memmove (remaining_buf, remaining_buf + length,
+ remaining_length - length);
+ remaining_length -= length;
+ ret = length;
+ }
+ else
+ {
+ memcpy (buffer, remaining_buf, remaining_length);
+ xfree (remaining_buf);
+ remaining_buf = NULL;
+ ret = remaining_length;
+ }
+ }
+ else
+ {
+ ret = ui_file_read (gdb_stdtargin, buffer, 32767);
+ remote_fio_no_longjmp = 1;
+ if (ret > 0 && (size_t)ret > length)
+ {
+ remaining_buf = (char *) xmalloc (ret - length);
+ remaining_length = ret - length;
+ memcpy (remaining_buf, buffer + length, remaining_length);
+ ret = length;
+ }
+ }
+ }
+ break;
+ default:
+ buffer = (char *) xmalloc (length);
+ /* POSIX defines EINTR behaviour of read in a weird way. It's allowed
+ for read() to return -1 even if "some" bytes have been read. It
+ has been corrected in SUSv2 but that doesn't help us much...
+ Therefore a complete solution must check how many bytes have been
+ read on EINTR to return a more reliable value to the target */
+ old_offset = lseek (fd, 0, SEEK_CUR);
+ remote_fio_no_longjmp = 1;
+ ret = read (fd, buffer, length);
+ if (ret < 0 && errno == EINTR)
+ {
+ new_offset = lseek (fd, 0, SEEK_CUR);
+ /* If some data has been read, return the number of bytes read.
+ The Ctrl-C flag is set in remote_fileio_reply() anyway */
+ if (old_offset != new_offset)
+ ret = new_offset - old_offset;
+ }
+ break;
+ }
+
+ if (ret > 0)
+ {
+ retlength = remote_fileio_write_bytes (ptrval, buffer, ret);
+ if (retlength != ret)
+ ret = -1; /* errno has been set to EIO in remote_fileio_write_bytes() */
+ }
+
+ if (ret < 0)
+ remote_fileio_return_errno (-1);
+ else
+ remote_fileio_return_success (ret);
+
+ xfree (buffer);
+}
+
+static void
+remote_fileio_func_write (char *buf)
+{
+ long target_fd, num;
+ LONGEST lnum;
+ CORE_ADDR ptrval;
+ int fd, ret, retlength;
+ char *buffer;
+ size_t length;
+
+ /* 1. Parameter: file descriptor */
+ if (remote_fileio_extract_int (&buf, &target_fd))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ fd = remote_fileio_map_fd ((int) target_fd);
+ if (fd == FIO_FD_INVALID)
+ {
+ remote_fileio_badfd ();
+ return;
+ }
+ /* 2. Parameter: buffer pointer */
+ if (remote_fileio_extract_long (&buf, &lnum))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+ /* 3. Parameter: buffer length */
+ if (remote_fileio_extract_int (&buf, &num))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ length = (size_t) num;
+
+ buffer = (char *) xmalloc (length);
+ retlength = remote_read_bytes (ptrval, buffer, length);
+ if (retlength != length)
+ {
+ xfree (buffer);
+ remote_fileio_ioerror ();
+ return;
+ }
+
+ remote_fio_no_longjmp = 1;
+ switch (fd)
+ {
+ case FIO_FD_CONSOLE_IN:
+ remote_fileio_badfd ();
+ return;
+ case FIO_FD_CONSOLE_OUT:
+ ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr, buffer,
+ length);
+ gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr);
+ ret = length;
+ break;
+ default:
+ ret = write (fd, buffer, length);
+ if (ret < 0 && errno == EACCES)
+ errno = EBADF; /* Cygwin returns EACCESS when writing to a R/O file.*/
+ break;
+ }
+
+ if (ret < 0)
+ remote_fileio_return_errno (-1);
+ else
+ remote_fileio_return_success (ret);
+
+ xfree (buffer);
+}
+
+static void
+remote_fileio_func_lseek (char *buf)
+{
+ long num;
+ LONGEST lnum;
+ int fd, flag;
+ off_t offset, ret;
+
+ /* 1. Parameter: file descriptor */
+ if (remote_fileio_extract_int (&buf, &num))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ fd = remote_fileio_map_fd ((int) num);
+ if (fd == FIO_FD_INVALID)
+ {
+ remote_fileio_badfd ();
+ return;
+ }
+ else if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
+ {
+ remote_fileio_reply (-1, FILEIO_ESPIPE);
+ return;
+ }
+
+ /* 2. Parameter: offset */
+ if (remote_fileio_extract_long (&buf, &lnum))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ offset = (off_t) lnum;
+ /* 3. Parameter: flag */
+ if (remote_fileio_extract_int (&buf, &num))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ if (remote_fileio_seek_flag_to_host (num, &flag))
+ {
+ remote_fileio_reply (-1, FILEIO_EINVAL);
+ return;
+ }
+
+ remote_fio_no_longjmp = 1;
+ ret = lseek (fd, offset, flag);
+
+ if (ret == (off_t) -1)
+ remote_fileio_return_errno (-1);
+ else
+ remote_fileio_return_success (ret);
+}
+
+static void
+remote_fileio_func_rename (char *buf)
+{
+ CORE_ADDR ptrval;
+ int length, retlength;
+ char *oldpath, *newpath;
+ int ret, of, nf;
+ struct stat ost, nst;
+
+ /* 1. Parameter: Ptr to oldpath / length incl. trailing zero */
+ if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* Request oldpath using 'm' packet */
+ oldpath = alloca (length);
+ retlength = remote_read_bytes (ptrval, oldpath, length);
+ if (retlength != length)
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* 2. Parameter: Ptr to newpath / length incl. trailing zero */
+ if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* Request newpath using 'm' packet */
+ newpath = alloca (length);
+ retlength = remote_read_bytes (ptrval, newpath, length);
+ if (retlength != length)
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+
+ /* Only operate on regular files and directories */
+ of = stat (oldpath, &ost);
+ nf = stat (newpath, &nst);
+ if ((!of && !S_ISREG (ost.st_mode) && !S_ISDIR (ost.st_mode))
+ || (!nf && !S_ISREG (nst.st_mode) && !S_ISDIR (nst.st_mode)))
+ {
+ remote_fileio_reply (-1, FILEIO_EACCES);
+ return;
+ }
+
+ remote_fio_no_longjmp = 1;
+ ret = rename (oldpath, newpath);
+
+ if (ret == -1)
+ {
+ /* Special case: newpath is a non-empty directory. Some systems
+ return ENOTEMPTY, some return EEXIST. We coerce that to be
+ always EEXIST. */
+ if (errno == ENOTEMPTY)
+ errno = EEXIST;
+#ifdef __CYGWIN__
+ /* Workaround some Cygwin problems with correct errnos. */
+ if (errno == EACCES)
+ {
+ if (!of && !nf && S_ISDIR (nst.st_mode))
+ {
+ if (S_ISREG (ost.st_mode))
+ errno = EISDIR;
+ else
+ {
+ char oldfullpath[PATH_MAX + 1];
+ char newfullpath[PATH_MAX + 1];
+ int len;
+
+ cygwin_conv_to_full_posix_path (oldpath, oldfullpath);
+ cygwin_conv_to_full_posix_path (newpath, newfullpath);
+ len = strlen (oldfullpath);
+ if (newfullpath[len] == '/'
+ && !strncmp (oldfullpath, newfullpath, len))
+ errno = EINVAL;
+ else
+ errno = EEXIST;
+ }
+ }
+ }
+#endif
+
+ remote_fileio_return_errno (-1);
+ }
+ else
+ remote_fileio_return_success (ret);
+}
+
+static void
+remote_fileio_func_unlink (char *buf)
+{
+ CORE_ADDR ptrval;
+ int length, retlength;
+ char *pathname;
+ int ret;
+ struct stat st;
+
+ /* Parameter: Ptr to pathname / length incl. trailing zero */
+ if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* Request pathname using 'm' packet */
+ pathname = alloca (length);
+ retlength = remote_read_bytes (ptrval, pathname, length);
+ if (retlength != length)
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+
+ /* Only operate on regular files (and directories, which allows to return
+ the correct return code) */
+ if (!stat (pathname, &st) && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+ {
+ remote_fileio_reply (-1, FILEIO_ENODEV);
+ return;
+ }
+
+ remote_fio_no_longjmp = 1;
+ ret = unlink (pathname);
+
+ if (ret == -1)
+ remote_fileio_return_errno (-1);
+ else
+ remote_fileio_return_success (ret);
+}
+
+static void
+remote_fileio_func_stat (char *buf)
+{
+ CORE_ADDR ptrval;
+ int ret, length, retlength;
+ char *pathname;
+ LONGEST lnum;
+ struct stat st;
+ struct fio_stat fst;
+
+ /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
+ if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* Request pathname using 'm' packet */
+ pathname = alloca (length);
+ retlength = remote_read_bytes (ptrval, pathname, length);
+ if (retlength != length)
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+
+ /* 2. Parameter: Ptr to struct stat */
+ if (remote_fileio_extract_long (&buf, &lnum))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+
+ remote_fio_no_longjmp = 1;
+ ret = stat (pathname, &st);
+
+ if (ret == -1)
+ {
+ remote_fileio_return_errno (-1);
+ return;
+ }
+ /* Only operate on regular files and directories */
+ if (!ret && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+ {
+ remote_fileio_reply (-1, FILEIO_EACCES);
+ return;
+ }
+ if (ptrval)
+ {
+ remote_fileio_to_fio_stat (&st, &fst);
+ remote_fileio_to_fio_uint (0, fst.fst_dev);
+
+ retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst);
+ if (retlength != sizeof fst)
+ {
+ remote_fileio_return_errno (-1);
+ return;
+ }
+ }
+ remote_fileio_return_success (ret);
+}
+
+static void
+remote_fileio_func_fstat (char *buf)
+{
+ CORE_ADDR ptrval;
+ int fd, ret, retlength;
+ long target_fd;
+ LONGEST lnum;
+ struct stat st;
+ struct fio_stat fst;
+ struct timeval tv;
+
+ /* 1. Parameter: file descriptor */
+ if (remote_fileio_extract_int (&buf, &target_fd))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ fd = remote_fileio_map_fd ((int) target_fd);
+ if (fd == FIO_FD_INVALID)
+ {
+ remote_fileio_badfd ();
+ return;
+ }
+ /* 2. Parameter: Ptr to struct stat */
+ if (remote_fileio_extract_long (&buf, &lnum))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+
+ remote_fio_no_longjmp = 1;
+ if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
+ {
+ remote_fileio_to_fio_uint (1, fst.fst_dev);
+ st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR);
+ st.st_nlink = 1;
+ st.st_uid = getuid ();
+ st.st_gid = getgid ();
+ st.st_rdev = 0;
+ st.st_size = 0;
+ st.st_blksize = 512;
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+ st.st_blocks = 0;
+#endif
+ if (!gettimeofday (&tv, NULL))
+ st.st_atime = st.st_mtime = st.st_ctime = tv.tv_sec;
+ else
+ st.st_atime = st.st_mtime = st.st_ctime = (time_t) 0;
+ ret = 0;
+ }
+ else
+ ret = fstat (fd, &st);
+
+ if (ret == -1)
+ {
+ remote_fileio_return_errno (-1);
+ return;
+ }
+ if (ptrval)
+ {
+ remote_fileio_to_fio_stat (&st, &fst);
+
+ retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst);
+ if (retlength != sizeof fst)
+ {
+ remote_fileio_return_errno (-1);
+ return;
+ }
+ }
+ remote_fileio_return_success (ret);
+}
+
+static void
+remote_fileio_func_gettimeofday (char *buf)
+{
+ LONGEST lnum;
+ CORE_ADDR ptrval;
+ int ret, retlength;
+ struct timeval tv;
+ struct fio_timeval ftv;
+
+ /* 1. Parameter: struct timeval pointer */
+ if (remote_fileio_extract_long (&buf, &lnum))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+ /* 2. Parameter: some pointer value... */
+ if (remote_fileio_extract_long (&buf, &lnum))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* ...which has to be NULL */
+ if (lnum)
+ {
+ remote_fileio_reply (-1, FILEIO_EINVAL);
+ return;
+ }
+
+ remote_fio_no_longjmp = 1;
+ ret = gettimeofday (&tv, NULL);
+
+ if (ret == -1)
+ {
+ remote_fileio_return_errno (-1);
+ return;
+ }
+
+ if (ptrval)
+ {
+ remote_fileio_to_fio_timeval (&tv, &ftv);
+
+ retlength = remote_fileio_write_bytes (ptrval, (char *) &ftv, sizeof ftv);
+ if (retlength != sizeof ftv)
+ {
+ remote_fileio_return_errno (-1);
+ return;
+ }
+ }
+ remote_fileio_return_success (ret);
+}
+
+static void
+remote_fileio_func_isatty (char *buf)
+{
+ long target_fd;
+ int fd;
+
+ /* Parameter: file descriptor */
+ if (remote_fileio_extract_int (&buf, &target_fd))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ remote_fio_no_longjmp = 1;
+ fd = remote_fileio_map_fd ((int) target_fd);
+ remote_fileio_return_success (fd == FIO_FD_CONSOLE_IN ||
+ fd == FIO_FD_CONSOLE_OUT ? 1 : 0);
+}
+
+static void
+remote_fileio_func_system (char *buf)
+{
+ CORE_ADDR ptrval;
+ int ret, length, retlength;
+ char *cmdline;
+
+ /* Check if system(3) has been explicitely allowed using the
+ `set remote system-call-allowed 1' command. If not, return
+ EPERM */
+ if (!remote_fio_system_call_allowed)
+ {
+ remote_fileio_reply (-1, FILEIO_EPERM);
+ return;
+ }
+
+ /* Parameter: Ptr to commandline / length incl. trailing zero */
+ if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ /* Request commandline using 'm' packet */
+ cmdline = alloca (length);
+ retlength = remote_read_bytes (ptrval, cmdline, length);
+ if (retlength != length)
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+
+ remote_fio_no_longjmp = 1;
+ ret = system (cmdline);
+
+ if (ret == -1)
+ remote_fileio_return_errno (-1);
+ else
+ remote_fileio_return_success (WEXITSTATUS (ret));
+}
+
+static struct {
+ char *name;
+ void (*func)(char *);
+} remote_fio_func_map[] = {
+ "open", remote_fileio_func_open,
+ "close", remote_fileio_func_close,
+ "read", remote_fileio_func_read,
+ "write", remote_fileio_func_write,
+ "lseek", remote_fileio_func_lseek,
+ "rename", remote_fileio_func_rename,
+ "unlink", remote_fileio_func_unlink,
+ "stat", remote_fileio_func_stat,
+ "fstat", remote_fileio_func_fstat,
+ "gettimeofday", remote_fileio_func_gettimeofday,
+ "isatty", remote_fileio_func_isatty,
+ "system", remote_fileio_func_system,
+ NULL, NULL
+};
+
+static int
+do_remote_fileio_request (struct ui_out *uiout, void *buf_arg)
+{
+ char *buf = buf_arg;
+ char *c;
+ int idx;
+
+ remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
+
+ c = strchr (++buf, ',');
+ if (c)
+ *c++ = '\0';
+ else
+ c = strchr (buf, '\0');
+ for (idx = 0; remote_fio_func_map[idx].name; ++idx)
+ if (!strcmp (remote_fio_func_map[idx].name, buf))
+ break;
+ if (!remote_fio_func_map[idx].name) /* ERROR: No such function. */
+ return RETURN_ERROR;
+ remote_fio_func_map[idx].func (c);
+ return 0;
+}
+
+void
+remote_fileio_request (char *buf)
+{
+ int ex;
+
+ remote_fileio_sig_init ();
+
+ remote_fio_ctrl_c_flag = 0;
+ remote_fio_no_longjmp = 0;
+
+ ex = catch_exceptions (uiout, do_remote_fileio_request, (void *)buf,
+ NULL, RETURN_MASK_ALL);
+ switch (ex)
+ {
+ case RETURN_ERROR:
+ remote_fileio_reply (-1, FILEIO_ENOSYS);
+ break;
+ case RETURN_QUIT:
+ remote_fileio_reply (-1, FILEIO_EINTR);
+ break;
+ default:
+ break;
+ }
+
+ remote_fileio_sig_exit ();
+}
+
+static void
+set_system_call_allowed (char *args, int from_tty)
+{
+ if (args)
+ {
+ char *arg_end;
+ int val = strtoul (args, &arg_end, 10);
+ if (*args && *arg_end == '\0')
+ {
+ remote_fio_system_call_allowed = !!val;
+ return;
+ }
+ }
+ error ("Illegal argument for \"set remote system-call-allowed\" command");
+}
+
+static void
+show_system_call_allowed (char *args, int from_tty)
+{
+ if (args)
+ error ("Garbage after \"show remote system-call-allowed\" command: `%s'", args);
+ printf_unfiltered ("Calling host system(3) call from target is %sallowed\n",
+ remote_fio_system_call_allowed ? "" : "not ");
+}
+
+void
+initialize_remote_fileio (struct cmd_list_element *remote_set_cmdlist,
+ struct cmd_list_element *remote_show_cmdlist)
+{
+ add_cmd ("system-call-allowed", no_class,
+ set_system_call_allowed,
+ "Set if the host system(3) call is allowed for the target.\n",
+ &remote_set_cmdlist);
+ add_cmd ("system-call-allowed", no_class,
+ show_system_call_allowed,
+ "Show if the host system(3) call is allowed for the target.\n",
+ &remote_show_cmdlist);
+}
diff --git a/contrib/gdb/gdb/remote-fileio.h b/contrib/gdb/gdb/remote-fileio.h
new file mode 100644
index 0000000..68c6450
--- /dev/null
+++ b/contrib/gdb/gdb/remote-fileio.h
@@ -0,0 +1,38 @@
+/* Remote File-I/O communications
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* See the GDB User Guide for details of the GDB remote protocol. */
+
+#ifndef REMOTE_FILEIO_H
+#define REMOTE_FILEIO_H
+
+struct cmd_list_element;
+
+/* Unified interface to remote fileio, called in remote.c from
+ remote_wait () and remote_async_wait () */
+extern void remote_fileio_request (char *buf);
+
+/* Called from _initialize_remote () */
+extern void initialize_remote_fileio (
+ struct cmd_list_element *remote_set_cmdlist,
+ struct cmd_list_element *remote_show_cmdlist);
+
+#endif
diff --git a/contrib/gdb/gdb/remote-hms.c b/contrib/gdb/gdb/remote-hms.c
new file mode 100644
index 0000000..ee40051
--- /dev/null
+++ b/contrib/gdb/gdb/remote-hms.c
@@ -0,0 +1,159 @@
+/* Remote debugging interface for Renesas HMS Monitor Version 1.0
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001
+ 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"
+#include "regcache.h"
+
+static void hms_open (char *args, int from_tty);
+static void
+hms_supply_register (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[] =
+{
+ "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;
+
+static void
+init_hms_cmds (void)
+{
+ hms_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_GETMEM_NEEDS_RANGE;
+ hms_cmds.init = hms_inits; /* Init strings */
+ hms_cmds.cont = "g\r"; /* continue command */
+ hms_cmds.step = "s\r"; /* single step */
+ hms_cmds.stop = "\003"; /* ^C interrupts the program */
+ hms_cmds.set_break = "b %x\r"; /* set a breakpoint */
+ hms_cmds.clr_break = "b - %x\r"; /* clear a breakpoint */
+ hms_cmds.clr_all_break = "b -\r"; /* clear all breakpoints */
+ hms_cmds.fill = "f %x %x %x\r"; /* fill (start end val) */
+ hms_cmds.setmem.cmdb = "m.b %x=%x\r"; /* setmem.cmdb (addr, value) */
+ hms_cmds.setmem.cmdw = "m.w %x=%x\r"; /* setmem.cmdw (addr, value) */
+ hms_cmds.setmem.cmdl = NULL; /* setmem.cmdl (addr, value) */
+ hms_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ hms_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ hms_cmds.setmem.term = NULL; /* setreg.term */
+ hms_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ hms_cmds.getmem.cmdb = "m.b %x %x\r"; /* getmem.cmdb (addr, addr) */
+ hms_cmds.getmem.cmdw = "m.w %x %x\r"; /* getmem.cmdw (addr, addr) */
+ hms_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, addr) */
+ hms_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, addr) */
+ hms_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
+ hms_cmds.getmem.term = ">"; /* getmem.term */
+ hms_cmds.getmem.term_cmd = "\003"; /* getmem.term_cmd */
+ hms_cmds.setreg.cmd = "r %s=%x\r"; /* setreg.cmd (name, value) */
+ hms_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ hms_cmds.setreg.term = NULL; /* setreg.term */
+ hms_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ hms_cmds.getreg.cmd = "r %s\r"; /* getreg.cmd (name) */
+ hms_cmds.getreg.resp_delim = " ("; /* getreg.resp_delim */
+ hms_cmds.getreg.term = ":"; /* getreg.term */
+ hms_cmds.getreg.term_cmd = "\003"; /* getreg.term_cmd */
+ hms_cmds.dump_registers = "r\r"; /* dump_registers */
+ hms_cmds.register_pattern = "\\(\\w+\\)=\\([0-9a-fA-F]+\\)"; /* register_pattern */
+ hms_cmds.supply_register = hms_supply_register; /* supply_register */
+ hms_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ hms_cmds.load = "tl\r"; /* download command */
+ hms_cmds.loadresp = NULL; /* load response */
+ hms_cmds.prompt = ">"; /* monitor command prompt */
+ hms_cmds.line_term = "\r"; /* end-of-command delimitor */
+ hms_cmds.cmd_end = NULL; /* optional command terminator */
+ hms_cmds.target = &hms_ops; /* target operations */
+ hms_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ hms_cmds.regnames = hms_regnames; /* registers names */
+ hms_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+} /* init_hms-cmds */
+
+static void
+hms_open (char *args, int from_tty)
+{
+ monitor_open (args, &hms_cmds, from_tty);
+}
+
+int write_dos_tick_delay;
+
+extern initialize_file_ftype _initialize_remote_hms; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_hms (void)
+{
+ init_hms_cmds ();
+ init_monitor_ops (&hms_ops);
+
+ hms_ops.to_shortname = "hms";
+ hms_ops.to_longname = "Renesas 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);
+}
diff --git a/contrib/gdb/gdb/remote-mips.c b/contrib/gdb/gdb/remote-mips.c
new file mode 100644
index 0000000..c757684
--- /dev/null
+++ b/contrib/gdb/gdb/remote-mips.c
@@ -0,0 +1,3421 @@
+/* Remote debugging interface for MIPS remote debugging protocol.
+
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Support. Written by Ian Lance Taylor
+ <ian@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 "bfd.h"
+#include "symfile.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "serial.h"
+#include "target.h"
+#include "remote-utils.h"
+#include "gdb_string.h"
+#include "gdb_stat.h"
+#include "regcache.h"
+#include <ctype.h>
+#include "mips-tdep.h"
+
+
+/* Breakpoint types. Values 0, 1, and 2 must agree with the watch
+ types passed by breakpoint.c to target_insert_watchpoint.
+ Value 3 is our own invention, and is used for ordinary instruction
+ breakpoints. Value 4 is used to mark an unused watchpoint in tables. */
+enum break_type
+ {
+ BREAK_WRITE, /* 0 */
+ BREAK_READ, /* 1 */
+ BREAK_ACCESS, /* 2 */
+ BREAK_FETCH, /* 3 */
+ BREAK_UNUSED /* 4 */
+ };
+
+/* Prototypes for local functions. */
+
+static int mips_readchar (int timeout);
+
+static int mips_receive_header (unsigned char *hdr, int *pgarbage,
+ int ch, int timeout);
+
+static int mips_receive_trailer (unsigned char *trlr, int *pgarbage,
+ int *pch, int timeout);
+
+static int mips_cksum (const unsigned char *hdr,
+ const unsigned char *data, int len);
+
+static void mips_send_packet (const char *s, int get_ack);
+
+static void mips_send_command (const char *cmd, int prompt);
+
+static int mips_receive_packet (char *buff, int throw_error, int timeout);
+
+static ULONGEST mips_request (int cmd, ULONGEST addr, ULONGEST data,
+ int *perr, int timeout, char *buff);
+
+static void mips_initialize (void);
+
+static void mips_open (char *name, int from_tty);
+
+static void pmon_open (char *name, int from_tty);
+
+static void ddb_open (char *name, int from_tty);
+
+static void lsi_open (char *name, int from_tty);
+
+static void mips_close (int quitting);
+
+static void mips_detach (char *args, int from_tty);
+
+static void mips_resume (ptid_t ptid, int step,
+ enum target_signal siggnal);
+
+static ptid_t mips_wait (ptid_t ptid,
+ struct target_waitstatus *status);
+
+static int mips_map_regno (int regno);
+
+static void mips_fetch_registers (int regno);
+
+static void mips_prepare_to_store (void);
+
+static void mips_store_registers (int regno);
+
+static unsigned int mips_fetch_word (CORE_ADDR addr);
+
+static int mips_store_word (CORE_ADDR addr, unsigned int value,
+ char *old_contents);
+
+static int mips_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+
+static void mips_files_info (struct target_ops *ignore);
+
+static void mips_create_inferior (char *execfile, char *args, char **env);
+
+static void mips_mourn_inferior (void);
+
+static int pmon_makeb64 (unsigned long v, char *p, int n, int *chksum);
+
+static int pmon_zeroset (int recsize, char **buff, int *amount,
+ unsigned int *chksum);
+
+static int pmon_checkset (int recsize, char **buff, int *value);
+
+static void pmon_make_fastrec (char **outbuf, unsigned char *inbuf,
+ int *inptr, int inamount, int *recsize,
+ unsigned int *csum, unsigned int *zerofill);
+
+static int pmon_check_ack (char *mesg);
+
+static void pmon_start_download (void);
+
+static void pmon_end_download (int final, int bintotal);
+
+static void pmon_download (char *buffer, int length);
+
+static void pmon_load_fast (char *file);
+
+static void mips_load (char *file, int from_tty);
+
+static int mips_make_srec (char *buffer, int type, CORE_ADDR memaddr,
+ unsigned char *myaddr, int len);
+
+static int set_breakpoint (CORE_ADDR addr, int len, enum break_type type);
+
+static int clear_breakpoint (CORE_ADDR addr, int len, enum break_type type);
+
+static int common_breakpoint (int set, CORE_ADDR addr, int len,
+ enum break_type type);
+
+/* Forward declarations. */
+extern struct target_ops mips_ops;
+extern struct target_ops pmon_ops;
+extern struct target_ops ddb_ops;
+ /* *INDENT-OFF* */
+/* 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. */
+/* *INDENT-ON* */
+
+
+/* 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) ((unsigned int)(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)
+
+/* PMON commands to load from the serial port or UDP socket. */
+#define LOAD_CMD "load -b -s tty0\r"
+#define LOAD_CMD_UDP "load -b -s udp\r"
+
+/* The target vectors for the four different remote MIPS targets.
+ These are initialized with code in _initialize_remote_mips instead
+ of static initializers, to make it easier to extend the target_ops
+ vector later. */
+struct target_ops mips_ops, pmon_ops, ddb_ops, lsi_ops;
+
+enum mips_monitor_type
+ {
+ /* IDT/SIM monitor being used: */
+ MON_IDT,
+ /* PMON monitor being used: */
+ MON_PMON, /* 3.0.83 [COGENT,EB,FP,NET] Algorithmics Ltd. Nov 9 1995 17:19:50 */
+ MON_DDB, /* 2.7.473 [DDBVR4300,EL,FP,NET] Risq Modular Systems, Thu Jun 6 09:28:40 PDT 1996 */
+ MON_LSI, /* 4.3.12 [EB,FP], LSI LOGIC Corp. Tue Feb 25 13:22:14 1997 */
+ /* Last and unused value, for sizing vectors, etc. */
+ MON_LAST
+ };
+static enum mips_monitor_type mips_monitor = MON_LAST;
+
+/* The monitor prompt text. If the user sets the PMON prompt
+ to some new value, the GDB `set monitor-prompt' command must also
+ be used to inform GDB about the expected prompt. Otherwise, GDB
+ will not be able to connect to PMON in mips_initialize().
+ If the `set monitor-prompt' command is not used, the expected
+ default prompt will be set according the target:
+ target prompt
+ ----- -----
+ pmon PMON>
+ ddb NEC010>
+ lsi PMON>
+ */
+static char *mips_monitor_prompt;
+
+/* 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;
+
+/* Set to 1 while the connection is being brought down. */
+static int mips_exiting;
+
+/* 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 = 10;
+
+/* 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 struct serial *mips_desc;
+
+/* UDP handle used to download files to target. */
+static struct serial *udp_desc;
+static int udp_in_use;
+
+/* TFTP filename used to download files to DDB board, in the form
+ host:filename. */
+static char *tftp_name; /* host:filename */
+static char *tftp_localname; /* filename portion of above */
+static int tftp_in_use;
+static FILE *tftp_file;
+
+/* 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 int monitor_supports_breakpoints = 0;
+
+/* Data cache header. */
+
+#if 0 /* not used (yet?) */
+static DCACHE *mips_dcache;
+#endif
+
+/* Non-zero means that we've just hit a read or write watchpoint */
+static int hit_watchpoint;
+
+/* Table of breakpoints/watchpoints (used only on LSI PMON target).
+ The table is indexed by a breakpoint number, which is an integer
+ from 0 to 255 returned by the LSI PMON when a breakpoint is set.
+ */
+#define MAX_LSI_BREAKPOINTS 256
+struct lsi_breakpoint_info
+ {
+ enum break_type type; /* type of breakpoint */
+ CORE_ADDR addr; /* address of breakpoint */
+ int len; /* length of region being watched */
+ unsigned long value; /* value to watch */
+ }
+lsi_breakpoints[MAX_LSI_BREAKPOINTS];
+
+/* Error/warning codes returned by LSI PMON for breakpoint commands.
+ Warning values may be ORed together; error values may not. */
+#define W_WARN 0x100 /* This bit is set if the error code is a warning */
+#define W_MSK 0x101 /* warning: Range feature is supported via mask */
+#define W_VAL 0x102 /* warning: Value check is not supported in hardware */
+#define W_QAL 0x104 /* warning: Requested qualifiers are not supported in hardware */
+
+#define E_ERR 0x200 /* This bit is set if the error code is an error */
+#define E_BPT 0x200 /* error: No such breakpoint number */
+#define E_RGE 0x201 /* error: Range is not supported */
+#define E_QAL 0x202 /* error: The requested qualifiers can not be used */
+#define E_OUT 0x203 /* error: Out of hardware resources */
+#define E_NON 0x204 /* error: Hardware breakpoint not supported */
+
+struct lsi_error
+ {
+ int code; /* error code */
+ char *string; /* string associated with this code */
+ };
+
+struct lsi_error lsi_warning_table[] =
+{
+ {W_MSK, "Range feature is supported via mask"},
+ {W_VAL, "Value check is not supported in hardware"},
+ {W_QAL, "Requested qualifiers are not supported in hardware"},
+ {0, NULL}
+};
+
+struct lsi_error lsi_error_table[] =
+{
+ {E_BPT, "No such breakpoint number"},
+ {E_RGE, "Range is not supported"},
+ {E_QAL, "The requested qualifiers can not be used"},
+ {E_OUT, "Out of hardware resources"},
+ {E_NON, "Hardware breakpoint not supported"},
+ {0, NULL}
+};
+
+/* Set to 1 with the 'set monitor-warnings' command to enable printing
+ of warnings returned by PMON when hardware breakpoints are used. */
+static int monitor_warnings;
+
+
+static void
+close_ports (void)
+{
+ mips_is_open = 0;
+ serial_close (mips_desc);
+
+ if (udp_in_use)
+ {
+ serial_close (udp_desc);
+ udp_in_use = 0;
+ }
+ tftp_in_use = 0;
+}
+
+/* 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
+mips_error (char *string,...)
+{
+ va_list args;
+
+ va_start (args, string);
+
+ target_terminal_ours ();
+ wrap_here (""); /* Force out any buffered output */
+ gdb_flush (gdb_stdout);
+ if (error_pre_print)
+ fputs_filtered (error_pre_print, gdb_stderr);
+ 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). */
+ close_ports ();
+
+ printf_unfiltered ("Ending remote MIPS debugging.\n");
+ target_mourn_inferior ();
+
+ throw_exception (RETURN_ERROR);
+}
+
+/* putc_readable - print a character, displaying non-printable chars in
+ ^x notation or in hex. */
+
+static void
+fputc_readable (int ch, struct ui_file *file)
+{
+ if (ch == '\n')
+ fputc_unfiltered ('\n', file);
+ else if (ch == '\r')
+ fprintf_unfiltered (file, "\\r");
+ else if (ch < 0x20) /* ASCII control character */
+ fprintf_unfiltered (file, "^%c", ch + '@');
+ else if (ch >= 0x7f) /* non-ASCII characters (rubout or greater) */
+ fprintf_unfiltered (file, "[%02x]", ch & 0xff);
+ else
+ fputc_unfiltered (ch, file);
+}
+
+
+/* puts_readable - print a string, displaying non-printable chars in
+ ^x notation or in hex. */
+
+static void
+fputs_readable (const char *string, struct ui_file *file)
+{
+ int c;
+
+ while ((c = *string++) != '\0')
+ fputc_readable (c, file);
+}
+
+
+/* Wait until STRING shows up in mips_desc. Returns 1 if successful, else 0 if
+ timed out. TIMEOUT specifies timeout value in seconds.
+ */
+
+static int
+mips_expect_timeout (const char *string, int timeout)
+{
+ const char *p = string;
+
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Expected \"");
+ fputs_readable (string, gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, "\", got \"");
+ }
+
+ immediate_quit++;
+ 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, timeout);
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "\": FAIL\n");
+ return 0;
+ }
+
+ if (remote_debug)
+ fputc_readable (c, gdb_stdlog);
+
+ if (c == *p++)
+ {
+ if (*p == '\0')
+ {
+ immediate_quit--;
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "\": OK\n");
+ return 1;
+ }
+ }
+ else
+ {
+ p = string;
+ if (c == *p)
+ p++;
+ }
+ }
+}
+
+/* Wait until STRING shows up in mips_desc. Returns 1 if successful, else 0 if
+ timed out. The timeout value is hard-coded to 2 seconds. Use
+ mips_expect_timeout if a different timeout value is needed.
+ */
+
+static int
+mips_expect (const char *string)
+{
+ return mips_expect_timeout (string, remote_timeout);
+}
+
+/* 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 (int timeout)
+{
+ int ch;
+ static int state = 0;
+ int mips_monitor_prompt_len = strlen (mips_monitor_prompt);
+
+ {
+ int i;
+
+ i = timeout;
+ if (i == -1 && watchdog > 0)
+ i = watchdog;
+ }
+
+ if (state == mips_monitor_prompt_len)
+ timeout = 1;
+ ch = serial_readchar (mips_desc, timeout);
+
+ if (ch == SERIAL_TIMEOUT && timeout == -1) /* Watchdog went off */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+
+ 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)
+ fprintf_unfiltered (gdb_stdlog, "Read '%c' %d 0x%x\n", ch, ch, ch);
+ else
+ fprintf_unfiltered (gdb_stdlog, "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
+ && !mips_exiting)
+ {
+ 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. */
+ fprintf_unfiltered (gdb_stdlog, "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 (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 and
+ buffered target output confuses the user. */
+ if (!mips_initializing || remote_debug > 0)
+ {
+ if (isprint (ch) || isspace (ch))
+ {
+ fputc_unfiltered (ch, gdb_stdtarg);
+ }
+ else
+ {
+ fputc_readable (ch, gdb_stdtarg);
+ }
+ gdb_flush (gdb_stdtarg);
+ }
+
+ /* Only count unprintable characters. */
+ if (! (isprint (ch) || isspace (ch)))
+ (*pgarbage) += 1;
+
+ 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 (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 (const unsigned char *hdr, const unsigned char *data, int len)
+{
+ const unsigned char *p;
+ int c;
+ 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 (const char *s, int get_ack)
+{
+ /* unsigned */ int len;
+ unsigned char *packet;
+ 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';
+ fprintf_unfiltered (gdb_stdlog, "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;
+ unsigned 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 (remote_timeout);
+ if (rch == SYN)
+ {
+ ch = SYN;
+ break;
+ }
+ if (rch == SERIAL_TIMEOUT)
+ break;
+ /* ignore the character */
+ }
+
+ if (i == len)
+ (void) mips_receive_trailer (trlr, &garbage, &ch,
+ remote_timeout);
+
+ /* 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. */
+ fprintf_unfiltered (gdb_stdlog, "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 (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)
+ fprintf_unfiltered (gdb_stdlog, "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)
+ fprintf_unfiltered (gdb_stdlog,
+ "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)
+ fprintf_unfiltered (gdb_stdlog, "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)
+ fprintf_unfiltered (gdb_stdlog,
+ "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 ULONGEST
+mips_request (int cmd,
+ ULONGEST addr,
+ ULONGEST data,
+ int *perr,
+ int timeout,
+ char *buff)
+{
+ char myBuff[DATA_MAXLEN + 1];
+ int len;
+ int rpid;
+ char rcmd;
+ int rerrflg;
+ unsigned long rresponse;
+
+ if (buff == (char *) NULL)
+ buff = myBuff;
+
+ if (cmd != '\0')
+ {
+ if (mips_need_reply)
+ internal_error (__FILE__, __LINE__,
+ "mips_request: Trying to send command before reply");
+ sprintf (buff, "0x0 %c 0x%s 0x%s", cmd, paddr_nz (addr), paddr_nz (data));
+ mips_send_packet (buff, 1);
+ mips_need_reply = 1;
+ }
+
+ if (perr == (int *) NULL)
+ return 0;
+
+ if (!mips_need_reply)
+ internal_error (__FILE__, __LINE__,
+ "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%lx",
+ &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 (void *arg)
+{
+ mips_initializing = 0;
+}
+
+static void
+mips_exit_cleanups (void *arg)
+{
+ mips_exiting = 0;
+}
+
+static void
+mips_send_command (const char *cmd, int prompt)
+{
+ serial_write (mips_desc, cmd, strlen (cmd));
+ mips_expect (cmd);
+ mips_expect ("\n");
+ if (prompt)
+ mips_expect (mips_monitor_prompt);
+}
+
+/* Enter remote (dbx) debug mode: */
+static void
+mips_enter_debug (void)
+{
+ /* Reset the sequence numbers, ready for the new debug sequence: */
+ mips_send_seq = 0;
+ mips_receive_seq = 0;
+
+ if (mips_monitor != MON_IDT)
+ mips_send_command ("debug\r", 0);
+ else /* assume IDT monitor by default */
+ mips_send_command ("db tty0\r", 0);
+
+ sleep (1);
+ serial_write (mips_desc, "\r", sizeof "\r" - 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_IDT)
+ mips_expect ("\r");
+
+ {
+ 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 (void)
+{
+ int err;
+ struct cleanup *old_cleanups = make_cleanup (mips_exit_cleanups, NULL);
+
+ mips_exiting = 1;
+
+ if (mips_monitor != MON_IDT)
+ {
+ /* The DDB (NEC) and MiniRISC (LSI) versions of PMON exit immediately,
+ so we do not get a reply to this command: */
+ mips_request ('x', 0, 0, NULL, mips_receive_wait, NULL);
+ mips_need_reply = 0;
+ if (!mips_expect (" break!"))
+ return -1;
+ }
+ else
+ mips_request ('x', 0, 0, &err, mips_receive_wait, NULL);
+
+ if (!mips_expect (mips_monitor_prompt))
+ return -1;
+
+ do_cleanups (old_cleanups);
+
+ return 0;
+}
+
+/* Initialize a new connection to the MIPS board, and make sure we are
+ really connected. */
+
+static void
+mips_initialize (void)
+{
+ 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_IDT)
+ 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, "\r", 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_IDT)
+ {
+ 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, "\r/E/E\r");
+ 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_IDT)
+ {
+ /* Sometimes PMON ignores the first few characters in the first
+ command sent after a load. Sending a blank command gets
+ around that. */
+ mips_send_command ("\r", -1);
+
+ /* Ensure the correct target state: */
+ if (mips_monitor != MON_LSI)
+ mips_send_command ("set regsize 64\r", -1);
+ mips_send_command ("set hostport tty0\r", -1);
+ mips_send_command ("set brkcmd \"\"\r", -1);
+ /* Delete all the current breakpoints: */
+ mips_send_command ("db *\r", -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 ((mips_monitor == MON_IDT
+ && clear_breakpoint (-1, 0, BREAK_UNUSED) == 0)
+ || mips_monitor == MON_LSI)
+ monitor_supports_breakpoints = 1;
+ else
+ monitor_supports_breakpoints = 0;
+
+ 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', 0, 0, &err, mips_receive_wait, NULL);
+}
+
+/* Open a connection to the remote board. */
+static void
+common_open (struct target_ops *ops, char *name, int from_tty,
+ enum mips_monitor_type new_monitor,
+ const char *new_monitor_prompt)
+{
+ char *ptype;
+ char *serial_port_name;
+ char *remote_name = 0;
+ char *local_name = 0;
+ char **argv;
+
+ 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).\n"
+ "If you want to use TFTP to download to the board, specify the name of a\n"
+ "temporary file to be used by GDB for downloads as the second argument.\n"
+ "This filename must be in the form host:filename, where host is the name\n"
+ "of the host running the TFTP server, and the file must be readable by the\n"
+ "world. If the local name of the temporary file differs from the name as\n"
+ "seen from the board via TFTP, specify that name as the third parameter.\n");
+
+ /* Parse the serial port name, the optional TFTP name, and the
+ optional local TFTP name. */
+ if ((argv = buildargv (name)) == NULL)
+ nomem (0);
+ make_cleanup_freeargv (argv);
+
+ serial_port_name = xstrdup (argv[0]);
+ if (argv[1]) /* remote TFTP name specified? */
+ {
+ remote_name = argv[1];
+ if (argv[2]) /* local TFTP filename specified? */
+ local_name = argv[2];
+ }
+
+ target_preopen (from_tty);
+
+ if (mips_is_open)
+ unpush_target (current_ops);
+
+ /* Open and initialize the serial port. */
+ mips_desc = serial_open (serial_port_name);
+ if (mips_desc == NULL)
+ perror_with_name (serial_port_name);
+
+ if (baud_rate != -1)
+ {
+ if (serial_setbaudrate (mips_desc, baud_rate))
+ {
+ serial_close (mips_desc);
+ perror_with_name (serial_port_name);
+ }
+ }
+
+ serial_raw (mips_desc);
+
+ /* Open and initialize the optional download port. If it is in the form
+ hostname#portnumber, it's a UDP socket. If it is in the form
+ hostname:filename, assume it's the TFTP filename that must be
+ passed to the DDB board to tell it where to get the load file. */
+ if (remote_name)
+ {
+ if (strchr (remote_name, '#'))
+ {
+ udp_desc = serial_open (remote_name);
+ if (!udp_desc)
+ perror_with_name ("Unable to open UDP port");
+ udp_in_use = 1;
+ }
+ else
+ {
+ /* Save the remote and local names of the TFTP temp file. If
+ the user didn't specify a local name, assume it's the same
+ as the part of the remote name after the "host:". */
+ if (tftp_name)
+ xfree (tftp_name);
+ if (tftp_localname)
+ xfree (tftp_localname);
+ if (local_name == NULL)
+ if ((local_name = strchr (remote_name, ':')) != NULL)
+ local_name++; /* skip over the colon */
+ if (local_name == NULL)
+ local_name = remote_name; /* local name same as remote name */
+ tftp_name = xstrdup (remote_name);
+ tftp_localname = xstrdup (local_name);
+ tftp_in_use = 1;
+ }
+ }
+
+ current_ops = ops;
+ mips_is_open = 1;
+
+ /* Reset the expected monitor prompt if it's never been set before. */
+ if (mips_monitor_prompt == NULL)
+ mips_monitor_prompt = xstrdup (new_monitor_prompt);
+ mips_monitor = new_monitor;
+
+ mips_initialize ();
+
+ if (from_tty)
+ printf_unfiltered ("Remote MIPS debugging using %s\n", serial_port_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. */
+ deprecated_mips_set_processor_regs_hack ();
+
+ /* 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 ();
+ print_stack_frame (get_selected_frame (), -1, 1);
+ xfree (serial_port_name);
+}
+
+static void
+mips_open (char *name, int from_tty)
+{
+ const char *monitor_prompt = NULL;
+ if (TARGET_ARCHITECTURE != NULL
+ && TARGET_ARCHITECTURE->arch == bfd_arch_mips)
+ {
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_mips4100:
+ case bfd_mach_mips4300:
+ case bfd_mach_mips4600:
+ case bfd_mach_mips4650:
+ case bfd_mach_mips5000:
+ monitor_prompt = "<RISQ> ";
+ break;
+ }
+ }
+ if (monitor_prompt == NULL)
+ monitor_prompt = "<IDT>";
+ common_open (&mips_ops, name, from_tty, MON_IDT, monitor_prompt);
+}
+
+static void
+pmon_open (char *name, int from_tty)
+{
+ common_open (&pmon_ops, name, from_tty, MON_PMON, "PMON> ");
+}
+
+static void
+ddb_open (char *name, int from_tty)
+{
+ common_open (&ddb_ops, name, from_tty, MON_DDB, "NEC010>");
+}
+
+static void
+lsi_open (char *name, int from_tty)
+{
+ int i;
+
+ /* Clear the LSI breakpoint table. */
+ for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
+ lsi_breakpoints[i].type = BREAK_UNUSED;
+
+ common_open (&lsi_ops, name, from_tty, MON_LSI, "PMON> ");
+}
+
+/* Close a connection to the remote board. */
+
+static void
+mips_close (int quitting)
+{
+ if (mips_is_open)
+ {
+ /* Get the board out of remote debugging mode. */
+ (void) mips_exit_debug ();
+
+ close_ports ();
+ }
+}
+
+/* Detach from the remote board. */
+
+static void
+mips_detach (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, except in the case of single-stepping on LSI boards,
+ where PMON does return a reply. */
+
+static void
+mips_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ int err;
+
+ /* LSI PMON requires returns a reply packet "0x1 s 0x0 0x57f" after
+ a single step, so we wait for that. */
+ mips_request (step ? 's' : 'c', 1, siggnal,
+ mips_monitor == MON_LSI && step ? &err : (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. */
+static enum target_signal
+mips_signal_from_protocol (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 ptid_t
+mips_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ int rstatus;
+ int err;
+ char buff[DATA_MAXLEN];
+ int rpc, rfp, rsp;
+ char flags[20];
+ int nfields;
+ int i;
+
+ 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 inferior_ptid;
+ }
+
+ /* No timeout; we sit here as long as the program continues to execute. */
+ mips_wait_flag = 1;
+ rstatus = mips_request ('\000', 0, 0, &err, -1, buff);
+ mips_wait_flag = 0;
+ if (err)
+ mips_error ("Remote failure: %s", safe_strerror (errno));
+
+ /* 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. */
+ if (mips_monitor == MON_PMON)
+ {
+ mips_exit_debug ();
+ mips_enter_debug ();
+ }
+
+ /* See if we got back extended status. If so, pick out the pc, fp, sp, etc... */
+
+ nfields = sscanf (buff, "0x%*x %*c 0x%*x 0x%*x 0x%x 0x%x 0x%x 0x%*x %s",
+ &rpc, &rfp, &rsp, flags);
+ if (nfields >= 3)
+ {
+ char buf[MAX_REGISTER_SIZE];
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (PC_REGNUM), rpc);
+ supply_register (PC_REGNUM, buf);
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (PC_REGNUM), rfp);
+ supply_register (30, buf); /* This register they are avoiding and so it is unnamed */
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (SP_REGNUM), rsp);
+ supply_register (SP_REGNUM, buf);
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (DEPRECATED_FP_REGNUM), 0);
+ supply_register (DEPRECATED_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;
+ }
+ }
+
+ if (strcmp (target_shortname, "lsi") == 0)
+ {
+#if 0
+ /* If this is an LSI PMON target, see if we just hit a hardrdware watchpoint.
+ Right now, PMON doesn't give us enough information to determine which
+ breakpoint we hit. So we have to look up the PC in our own table
+ of breakpoints, and if found, assume it's just a normal instruction
+ fetch breakpoint, not a data watchpoint. FIXME when PMON
+ provides some way to tell us what type of breakpoint it is. */
+ int i;
+ CORE_ADDR pc = read_pc ();
+
+ hit_watchpoint = 1;
+ for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
+ {
+ if (lsi_breakpoints[i].addr == pc
+ && lsi_breakpoints[i].type == BREAK_FETCH)
+ {
+ hit_watchpoint = 0;
+ break;
+ }
+ }
+#else
+ /* If a data breakpoint was hit, PMON returns the following packet:
+ 0x1 c 0x0 0x57f 0x1
+ The return packet from an ordinary breakpoint doesn't have the
+ extra 0x01 field tacked onto the end. */
+ if (nfields == 1 && rpc == 1)
+ hit_watchpoint = 1;
+#endif
+ }
+
+ /* 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 */
+
+ /* 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 & 0xff) == 0)
+ {
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = (((rstatus) >> 8) & 0xff);
+ }
+ else if ((rstatus & 0xff) == 0x7f)
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0xff);
+
+ /* If the stop PC is in the _exit function, assume
+ we hit the 'break 0x3ff' instruction in _exit, so this
+ is not a normal breakpoint. */
+ if (strcmp (target_shortname, "lsi") == 0)
+ {
+ char *func_name;
+ CORE_ADDR func_start;
+ CORE_ADDR pc = read_pc ();
+
+ find_pc_partial_function (pc, &func_name, &func_start, NULL);
+ if (func_name != NULL && strcmp (func_name, "_exit") == 0
+ && func_start == pc)
+ status->kind = TARGET_WAITKIND_EXITED;
+ }
+ }
+ else
+ {
+ status->kind = TARGET_WAITKIND_SIGNALLED;
+ status->value.sig = mips_signal_from_protocol (rstatus & 0x7f);
+ }
+
+ return inferior_ptid;
+}
+
+/* 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 (int regno)
+{
+ if (regno < 32)
+ return regno;
+ if (regno >= mips_regnum (current_gdbarch)->fp0
+ && regno < mips_regnum (current_gdbarch)->fp0 + 32)
+ return regno - mips_regnum (current_gdbarch)->fp0 + 32;
+ else if (regno == mips_regnum (current_gdbarch)->pc)
+ return REGNO_OFFSET + 0;
+ else if (regno == mips_regnum (current_gdbarch)->cause)
+ return REGNO_OFFSET + 1;
+ else if (regno == mips_regnum (current_gdbarch)->hi)
+ return REGNO_OFFSET + 2;
+ else if (regno == mips_regnum (current_gdbarch)->lo)
+ return REGNO_OFFSET + 3;
+ else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+ return REGNO_OFFSET + 4;
+ else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
+ return REGNO_OFFSET + 5;
+ else
+ /* FIXME: Is there a way to get the status register? */
+ return 0;
+}
+
+/* Fetch the remote registers. */
+
+static void
+mips_fetch_registers (int regno)
+{
+ unsigned LONGEST val;
+ int err;
+
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ mips_fetch_registers (regno);
+ return;
+ }
+
+ if (regno == DEPRECATED_FP_REGNUM || regno == ZERO_REGNUM)
+ /* DEPRECATED_FP_REGNUM on the mips is a hack which is just
+ supposed to read zero (see also mips-nat.c). */
+ val = 0;
+ else
+ {
+ /* If PMON doesn't support this register, don't waste serial
+ bandwidth trying to read it. */
+ int pmon_reg = mips_map_regno (regno);
+ if (regno != 0 && pmon_reg == 0)
+ val = 0;
+ else
+ {
+ /* 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_DDB)
+ val = (unsigned) mips_request ('t', pmon_reg, 0,
+ &err, mips_receive_wait, NULL);
+ else
+ val = mips_request ('r', pmon_reg, 0,
+ &err, mips_receive_wait, NULL);
+ if (err)
+ mips_error ("Can't read register %d: %s", regno,
+ safe_strerror (errno));
+ }
+ }
+
+ {
+ char buf[MAX_REGISTER_SIZE];
+
+ /* We got the number the register holds, but gdb expects to see a
+ value in the target byte ordering. */
+ store_unsigned_integer (buf, DEPRECATED_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 (void)
+{
+}
+
+/* Store remote register(s). */
+
+static void
+mips_store_registers (int regno)
+{
+ int err;
+
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ mips_store_registers (regno);
+ return;
+ }
+
+ mips_request ('R', mips_map_regno (regno),
+ 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 unsigned int
+mips_fetch_word (CORE_ADDR addr)
+{
+ unsigned int val;
+ int err;
+
+ val = mips_request ('d', addr, 0, &err, mips_receive_wait, NULL);
+ if (err)
+ {
+ /* Data space failed; try instruction space. */
+ val = mips_request ('i', addr, 0, &err,
+ mips_receive_wait, NULL);
+ if (err)
+ mips_error ("Can't read address 0x%s: %s",
+ paddr_nz (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. */
+
+/* FIXME! make sure only 32-bit quantities get stored! */
+static int
+mips_store_word (CORE_ADDR addr, unsigned int val, char *old_contents)
+{
+ int err;
+ unsigned int oldcontents;
+
+ oldcontents = mips_request ('D', addr, val, &err,
+ mips_receive_wait, NULL);
+ if (err)
+ {
+ /* Data space failed; try instruction space. */
+ oldcontents = mips_request ('I', addr, 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 mask_address_p = 1;
+
+static int
+mips_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int i;
+ CORE_ADDR addr;
+ int count;
+ char *buffer;
+ int status;
+
+ /* PMON targets do not cope well with 64 bit addresses. Mask the
+ value down to 32 bits. */
+ if (mask_address_p)
+ memaddr &= (CORE_ADDR) 0xffffffff;
+
+ /* Round starting address down to longword boundary. */
+ addr = memaddr & ~3;
+ /* Round ending address up; get number of longwords that makes. */
+ count = (((memaddr + len) - addr) + 3) / 4;
+ /* Allocate buffer of that many longwords. */
+ buffer = alloca (count * 4);
+
+ 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 ("*");
+ gdb_flush (gdb_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 (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 (void)
+{
+ 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;
+ close_ports ();
+
+ printf_unfiltered ("Ending remote MIPS debugging.\n");
+ target_mourn_inferior ();
+
+ throw_exception (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 (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_ptid here? */
+
+ proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+/* Clean up after a process. Actually nothing to do. */
+
+static void
+mips_mourn_inferior (void)
+{
+ if (current_ops != NULL)
+ unpush_target (current_ops);
+ generic_mourn_inferior ();
+}
+
+/* We can write a breakpoint and read the shadow contents in one
+ operation. */
+
+/* Insert a breakpoint. On targets that don't have built-in
+ 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 the breakpoint
+ length returned by BREAKPOINT_FROM_PC. */
+
+static int
+mips_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ if (monitor_supports_breakpoints)
+ return set_breakpoint (addr, MIPS_INSTLEN, BREAK_FETCH);
+ else
+ return memory_insert_breakpoint (addr, contents_cache);
+}
+
+static int
+mips_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ if (monitor_supports_breakpoints)
+ return clear_breakpoint (addr, MIPS_INSTLEN, BREAK_FETCH);
+ else
+ return memory_remove_breakpoint (addr, contents_cache);
+}
+
+/* Tell whether this target can support a hardware breakpoint. CNT
+ is the number of hardware breakpoints already installed. This
+ implements the TARGET_CAN_USE_HARDWARE_WATCHPOINT macro. */
+
+int
+mips_can_use_watchpoint (int type, int cnt, int othertype)
+{
+ return cnt < MAX_LSI_BREAKPOINTS && strcmp (target_shortname, "lsi") == 0;
+}
+
+
+/* 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 (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 0
+ for a write watchpoint, 1 for a read watchpoint, or 2 for a read/write
+ watchpoint. */
+
+int
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ if (set_breakpoint (addr, len, type))
+ return -1;
+
+ return 0;
+}
+
+int
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ if (clear_breakpoint (addr, len, type))
+ return -1;
+
+ return 0;
+}
+
+int
+mips_stopped_by_watchpoint (void)
+{
+ return hit_watchpoint;
+}
+
+
+/* Insert a breakpoint. */
+
+static int
+set_breakpoint (CORE_ADDR addr, int len, enum break_type type)
+{
+ return common_breakpoint (1, addr, len, type);
+}
+
+
+/* Clear a breakpoint. */
+
+static int
+clear_breakpoint (CORE_ADDR addr, int len, enum break_type type)
+{
+ return common_breakpoint (0, addr, len, type);
+}
+
+
+/* Check the error code from the return packet for an LSI breakpoint
+ command. If there's no error, just return 0. If it's a warning,
+ print the warning text and return 0. If it's an error, print
+ the error text and return 1. <ADDR> is the address of the breakpoint
+ that was being set. <RERRFLG> is the error code returned by PMON.
+ This is a helper function for common_breakpoint. */
+
+static int
+check_lsi_error (CORE_ADDR addr, int rerrflg)
+{
+ struct lsi_error *err;
+ char *saddr = paddr_nz (addr); /* printable address string */
+
+ if (rerrflg == 0) /* no error */
+ return 0;
+
+ /* Warnings can be ORed together, so check them all. */
+ if (rerrflg & W_WARN)
+ {
+ if (monitor_warnings)
+ {
+ int found = 0;
+ for (err = lsi_warning_table; err->code != 0; err++)
+ {
+ if ((err->code & rerrflg) == err->code)
+ {
+ found = 1;
+ fprintf_unfiltered (gdb_stderr,
+ "common_breakpoint (0x%s): Warning: %s\n",
+ saddr,
+ err->string);
+ }
+ }
+ if (!found)
+ fprintf_unfiltered (gdb_stderr,
+ "common_breakpoint (0x%s): Unknown warning: 0x%x\n",
+ saddr,
+ rerrflg);
+ }
+ return 0;
+ }
+
+ /* Errors are unique, i.e. can't be ORed together. */
+ for (err = lsi_error_table; err->code != 0; err++)
+ {
+ if ((err->code & rerrflg) == err->code)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "common_breakpoint (0x%s): Error: %s\n",
+ saddr,
+ err->string);
+ return 1;
+ }
+ }
+ fprintf_unfiltered (gdb_stderr,
+ "common_breakpoint (0x%s): Unknown error: 0x%x\n",
+ saddr,
+ rerrflg);
+ return 1;
+}
+
+
+/* This routine sends a breakpoint command to the remote target.
+
+ <SET> is 1 if setting a breakpoint, or 0 if clearing a breakpoint.
+ <ADDR> is the address of the breakpoint.
+ <LEN> the length of the region to break on.
+ <TYPE> is the type of breakpoint:
+ 0 = write (BREAK_WRITE)
+ 1 = read (BREAK_READ)
+ 2 = read/write (BREAK_ACCESS)
+ 3 = instruction fetch (BREAK_FETCH)
+
+ Return 0 if successful; otherwise 1. */
+
+static int
+common_breakpoint (int set, CORE_ADDR addr, int len, enum break_type type)
+{
+ char buf[DATA_MAXLEN + 1];
+ char cmd, rcmd;
+ int rpid, rerrflg, rresponse, rlen;
+ int nfields;
+
+ addr = ADDR_BITS_REMOVE (addr);
+
+ if (mips_monitor == MON_LSI)
+ {
+ if (set == 0) /* clear breakpoint */
+ {
+ /* The LSI PMON "clear breakpoint" has this form:
+ <pid> 'b' <bptn> 0x0
+ reply:
+ <pid> 'b' 0x0 <code>
+
+ <bptn> is a breakpoint number returned by an earlier 'B' command.
+ Possible return codes: OK, E_BPT. */
+
+ int i;
+
+ /* Search for the breakpoint in the table. */
+ for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
+ if (lsi_breakpoints[i].type == type
+ && lsi_breakpoints[i].addr == addr
+ && lsi_breakpoints[i].len == len)
+ break;
+
+ /* Clear the table entry and tell PMON to clear the breakpoint. */
+ if (i == MAX_LSI_BREAKPOINTS)
+ {
+ warning ("common_breakpoint: Attempt to clear bogus breakpoint at %s\n",
+ paddr_nz (addr));
+ return 1;
+ }
+
+ lsi_breakpoints[i].type = BREAK_UNUSED;
+ sprintf (buf, "0x0 b 0x%x 0x0", i);
+ mips_send_packet (buf, 1);
+
+ rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+ buf[rlen] = '\0';
+
+ nfields = sscanf (buf, "0x%x b 0x0 0x%x", &rpid, &rerrflg);
+ if (nfields != 2)
+ mips_error ("common_breakpoint: Bad response from remote board: %s", buf);
+
+ return (check_lsi_error (addr, rerrflg));
+ }
+ else
+ /* set a breakpoint */
+ {
+ /* The LSI PMON "set breakpoint" command has this form:
+ <pid> 'B' <addr> 0x0
+ reply:
+ <pid> 'B' <bptn> <code>
+
+ The "set data breakpoint" command has this form:
+
+ <pid> 'A' <addr1> <type> [<addr2> [<value>]]
+
+ where: type= "0x1" = read
+ "0x2" = write
+ "0x3" = access (read or write)
+
+ The reply returns two values:
+ bptn - a breakpoint number, which is a small integer with
+ possible values of zero through 255.
+ code - an error return code, a value of zero indicates a
+ succesful completion, other values indicate various
+ errors and warnings.
+
+ Possible return codes: OK, W_QAL, E_QAL, E_OUT, E_NON.
+
+ */
+
+ if (type == BREAK_FETCH) /* instruction breakpoint */
+ {
+ cmd = 'B';
+ sprintf (buf, "0x0 B 0x%s 0x0", paddr_nz (addr));
+ }
+ else
+ /* watchpoint */
+ {
+ cmd = 'A';
+ sprintf (buf, "0x0 A 0x%s 0x%x 0x%s", paddr_nz (addr),
+ type == BREAK_READ ? 1 : (type == BREAK_WRITE ? 2 : 3),
+ paddr_nz (addr + len - 1));
+ }
+ mips_send_packet (buf, 1);
+
+ rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+ buf[rlen] = '\0';
+
+ nfields = sscanf (buf, "0x%x %c 0x%x 0x%x",
+ &rpid, &rcmd, &rresponse, &rerrflg);
+ if (nfields != 4 || rcmd != cmd || rresponse > 255)
+ mips_error ("common_breakpoint: Bad response from remote board: %s", buf);
+
+ if (rerrflg != 0)
+ if (check_lsi_error (addr, rerrflg))
+ return 1;
+
+ /* rresponse contains PMON's breakpoint number. Record the
+ information for this breakpoint so we can clear it later. */
+ lsi_breakpoints[rresponse].type = type;
+ lsi_breakpoints[rresponse].addr = addr;
+ lsi_breakpoints[rresponse].len = len;
+
+ return 0;
+ }
+ }
+ else
+ {
+ /* On non-LSI targets, the breakpoint command has this form:
+ 0x0 <CMD> <ADDR> <MASK> <FLAGS>
+ <MASK> is a don't care mask for addresses.
+ <FLAGS> is any combination of `r', `w', or `f' for read/write/fetch.
+ */
+ unsigned long mask;
+
+ mask = calculate_mask (addr, len);
+ addr &= ~mask;
+
+ if (set) /* set a breakpoint */
+ {
+ char *flags;
+ switch (type)
+ {
+ case BREAK_WRITE: /* write */
+ flags = "w";
+ break;
+ case BREAK_READ: /* read */
+ flags = "r";
+ break;
+ case BREAK_ACCESS: /* read/write */
+ flags = "rw";
+ break;
+ case BREAK_FETCH: /* fetch */
+ flags = "f";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+
+ cmd = 'B';
+ sprintf (buf, "0x0 B 0x%s 0x%s %s", paddr_nz (addr),
+ paddr_nz (mask), flags);
+ }
+ else
+ {
+ cmd = 'b';
+ sprintf (buf, "0x0 b 0x%s", paddr_nz (addr));
+ }
+
+ mips_send_packet (buf, 1);
+
+ rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+ buf[rlen] = '\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)
+ {
+ /* Ddb returns "0x0 b 0x16 0x0\000", whereas
+ Cogent returns "0x0 b 0xffffffff 0x16\000": */
+ if (mips_monitor == MON_DDB)
+ rresponse = rerrflg;
+ if (rresponse != 22) /* invalid argument */
+ fprintf_unfiltered (gdb_stderr,
+ "common_breakpoint (0x%s): Got error: 0x%x\n",
+ paddr_nz (addr), rresponse);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+send_srec (char *srec, int len, CORE_ADDR addr)
+{
+ while (1)
+ {
+ int ch;
+
+ serial_write (mips_desc, srec, len);
+
+ ch = mips_readchar (remote_timeout);
+
+ 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 %s! Retrying.\n", paddr_u (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 (char *args)
+{
+ bfd *abfd;
+ asection *s;
+ char *buffer, srec[1024];
+ unsigned int i;
+ unsigned 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: */
+ mips_send_command (LOAD_CMD, 0);
+
+ for (s = abfd->sections; s; s = s->next)
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ unsigned int numbytes;
+
+ /* FIXME! vma too small????? */
+ printf_filtered ("%s\t: 0x%4lx .. 0x%4lx ", s->name,
+ (long) s->vma,
+ (long) (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 (ui_load_progress_hook)
+ ui_load_progress_hook (s->name, 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<type><length><address><data><checksum>
+ *
+ * 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 (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. */
+
+ /* FIXME!! bigger buf required for 64-bit! */
+ 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[] = "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 (unsigned long v, char *p, int n, int *chksum)
+{
+ int count = (n / 6);
+
+ if ((n % 12) != 0)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "Fast encoding bitcount must be a multiple of 12bits: %dbit%s\n", n, (n == 1) ? "" : "s");
+ return (0);
+ }
+ if (n > 36)
+ {
+ fprintf_unfiltered (gdb_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 (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 (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, "\n");
+ *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 (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;
+}
+
+static int
+pmon_check_ack (char *mesg)
+{
+#if defined(DOETXACK)
+ int c;
+
+ if (!tftp_in_use)
+ {
+ c = serial_readchar (udp_in_use ? udp_desc : mips_desc,
+ remote_timeout);
+ if ((c == SERIAL_TIMEOUT) || (c != 0x06))
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "Failed to receive valid ACK for %s\n", mesg);
+ return (-1); /* terminate the download */
+ }
+ }
+#endif /* DOETXACK */
+ return (0);
+}
+
+/* pmon_download - Send a sequence of characters to the PMON download port,
+ which is either a serial port or a UDP socket. */
+
+static void
+pmon_start_download (void)
+{
+ if (tftp_in_use)
+ {
+ /* Create the temporary download file. */
+ if ((tftp_file = fopen (tftp_localname, "w")) == NULL)
+ perror_with_name (tftp_localname);
+ }
+ else
+ {
+ mips_send_command (udp_in_use ? LOAD_CMD_UDP : LOAD_CMD, 0);
+ mips_expect ("Downloading from ");
+ mips_expect (udp_in_use ? "udp" : "tty0");
+ mips_expect (", ^C to abort\r\n");
+ }
+}
+
+static int
+mips_expect_download (char *string)
+{
+ if (!mips_expect (string))
+ {
+ fprintf_unfiltered (gdb_stderr, "Load did not complete successfully.\n");
+ if (tftp_in_use)
+ remove (tftp_localname); /* Remove temporary file */
+ return 0;
+ }
+ else
+ return 1;
+}
+
+static void
+pmon_check_entry_address (char *entry_address, int final)
+{
+ char hexnumber[9]; /* includes '\0' space */
+ mips_expect_timeout (entry_address, tftp_in_use ? 15 : remote_timeout);
+ sprintf (hexnumber, "%x", final);
+ mips_expect (hexnumber);
+ mips_expect ("\r\n");
+}
+
+static int
+pmon_check_total (int bintotal)
+{
+ char hexnumber[9]; /* includes '\0' space */
+ mips_expect ("\r\ntotal = 0x");
+ sprintf (hexnumber, "%x", bintotal);
+ mips_expect (hexnumber);
+ return mips_expect_download (" bytes\r\n");
+}
+
+static void
+pmon_end_download (int final, int bintotal)
+{
+ char hexnumber[9]; /* includes '\0' space */
+
+ if (tftp_in_use)
+ {
+ static char *load_cmd_prefix = "load -b -s ";
+ char *cmd;
+ struct stat stbuf;
+
+ /* Close off the temporary file containing the load data. */
+ fclose (tftp_file);
+ tftp_file = NULL;
+
+ /* Make the temporary file readable by the world. */
+ if (stat (tftp_localname, &stbuf) == 0)
+ chmod (tftp_localname, stbuf.st_mode | S_IROTH);
+
+ /* Must reinitialize the board to prevent PMON from crashing. */
+ mips_send_command ("initEther\r", -1);
+
+ /* Send the load command. */
+ cmd = xmalloc (strlen (load_cmd_prefix) + strlen (tftp_name) + 2);
+ strcpy (cmd, load_cmd_prefix);
+ strcat (cmd, tftp_name);
+ strcat (cmd, "\r");
+ mips_send_command (cmd, 0);
+ xfree (cmd);
+ if (!mips_expect_download ("Downloading from "))
+ return;
+ if (!mips_expect_download (tftp_name))
+ return;
+ if (!mips_expect_download (", ^C to abort\r\n"))
+ return;
+ }
+
+ /* Wait for the stuff that PMON prints after the load has completed.
+ The timeout value for use in the tftp case (15 seconds) was picked
+ arbitrarily but might be too small for really large downloads. FIXME. */
+ switch (mips_monitor)
+ {
+ case MON_LSI:
+ pmon_check_ack ("termination");
+ pmon_check_entry_address ("Entry address is ", final);
+ if (!pmon_check_total (bintotal))
+ return;
+ break;
+ default:
+ pmon_check_entry_address ("Entry Address = ", final);
+ pmon_check_ack ("termination");
+ if (!pmon_check_total (bintotal))
+ return;
+ break;
+ }
+
+ if (tftp_in_use)
+ remove (tftp_localname); /* Remove temporary file */
+}
+
+static void
+pmon_download (char *buffer, int length)
+{
+ if (tftp_in_use)
+ fwrite (buffer, 1, length, tftp_file);
+ else
+ serial_write (udp_in_use ? udp_desc : mips_desc, buffer, length);
+}
+
+static void
+pmon_load_fast (char *file)
+{
+ bfd *abfd;
+ asection *s;
+ unsigned char *binbuf;
+ char *buffer;
+ int reclen;
+ unsigned int csum = 0;
+ int hashmark = !tftp_in_use;
+ int bintotal = 0;
+ int final = 0;
+ 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\r", -1);
+ mips_send_command ("set dlecho off\r", -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: */
+ pmon_start_download ();
+
+ /* Zero the checksum */
+ sprintf (buffer, "/Kxx\n");
+ reclen = strlen (buffer);
+ pmon_download (buffer, reclen);
+ finished = pmon_check_ack ("/Kxx");
+
+ 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, (unsigned int) s->vma,
+ (unsigned int) (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] = '\n';
+ buffer[3 + reclen] = '\0';
+ reclen += 3; /* for the initial escape code and carriage return */
+ pmon_download (buffer, reclen);
+ finished = pmon_check_ack ("/A");
+
+ if (!finished)
+ {
+ unsigned int binamount;
+ unsigned int zerofill = 0;
+ char *bp = buffer;
+ unsigned 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);
+ pmon_download (buffer, reclen);
+ finished = pmon_check_ack ("data record");
+ if (finished)
+ {
+ zerofill = 0; /* do not transmit pending zerofills */
+ break;
+ }
+
+ if (ui_load_progress_hook)
+ ui_load_progress_hook (s->name, i);
+
+ 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: */
+ pmon_download (buffer, reclen);
+ finished = pmon_check_ack ("record remnant");
+ }
+ }
+
+ putchar_unfiltered ('\n');
+ }
+
+ /* Terminate the transfer. We know that we have an empty output
+ buffer at this point. */
+ sprintf (buffer, "/E/E\n"); /* include dummy padding characters */
+ reclen = strlen (buffer);
+ pmon_download (buffer, reclen);
+
+ if (finished)
+ { /* Ignore the termination message: */
+ serial_flush_input (udp_in_use ? udp_desc : mips_desc);
+ }
+ else
+ { /* Deal with termination message: */
+ pmon_end_download (final, bintotal);
+ }
+
+ return;
+}
+
+/* mips_load -- download a file. */
+
+static void
+mips_load (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_IDT)
+ pmon_load_fast (file);
+ else
+ mips_load_srec (file);
+
+ mips_initialize ();
+
+ /* Finally, make the PC point at the start address */
+ if (mips_monitor != MON_IDT)
+ {
+ /* Work around problem where PMON monitor updates the PC after a load
+ to a different value than GDB thinks it has. The following ensures
+ that the write_pc() WILL update the PC value: */
+ deprecated_register_valid[PC_REGNUM] = 0;
+ }
+ if (exec_bfd)
+ write_pc (bfd_get_start_address (exec_bfd));
+
+ inferior_ptid = null_ptid; /* 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 ();
+}
+
+
+/* Pass the command argument as a packet to PMON verbatim. */
+
+static void
+pmon_command (char *args, int from_tty)
+{
+ char buf[DATA_MAXLEN + 1];
+ int rlen;
+
+ sprintf (buf, "0x0 %s", args);
+ mips_send_packet (buf, 1);
+ printf_filtered ("Send packet: %s\n", buf);
+
+ rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+ buf[rlen] = '\0';
+ printf_filtered ("Received packet: %s\n", buf);
+}
+
+extern initialize_file_ftype _initialize_remote_mips; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_mips (void)
+{
+ /* Initialize the fields in mips_ops that are common to all four targets. */
+ mips_ops.to_longname = "Remote MIPS debugging over serial line";
+ mips_ops.to_close = mips_close;
+ mips_ops.to_detach = mips_detach;
+ mips_ops.to_resume = mips_resume;
+ mips_ops.to_fetch_registers = mips_fetch_registers;
+ mips_ops.to_store_registers = mips_store_registers;
+ mips_ops.to_prepare_to_store = mips_prepare_to_store;
+ mips_ops.to_xfer_memory = mips_xfer_memory;
+ mips_ops.to_files_info = mips_files_info;
+ mips_ops.to_insert_breakpoint = mips_insert_breakpoint;
+ mips_ops.to_remove_breakpoint = mips_remove_breakpoint;
+ mips_ops.to_insert_watchpoint = mips_insert_watchpoint;
+ mips_ops.to_remove_watchpoint = mips_remove_watchpoint;
+ mips_ops.to_stopped_by_watchpoint = mips_stopped_by_watchpoint;
+ mips_ops.to_can_use_hw_breakpoint = mips_can_use_watchpoint;
+ mips_ops.to_kill = mips_kill;
+ mips_ops.to_load = mips_load;
+ mips_ops.to_create_inferior = mips_create_inferior;
+ mips_ops.to_mourn_inferior = mips_mourn_inferior;
+ mips_ops.to_stratum = process_stratum;
+ mips_ops.to_has_all_memory = 1;
+ mips_ops.to_has_memory = 1;
+ mips_ops.to_has_stack = 1;
+ mips_ops.to_has_registers = 1;
+ mips_ops.to_has_execution = 1;
+ mips_ops.to_magic = OPS_MAGIC;
+
+ /* Copy the common fields to all four target vectors. */
+ pmon_ops = ddb_ops = lsi_ops = mips_ops;
+
+ /* Initialize target-specific fields in the target vectors. */
+ mips_ops.to_shortname = "mips";
+ mips_ops.to_doc = "\
+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";
+ mips_ops.to_open = mips_open;
+ mips_ops.to_wait = mips_wait;
+
+ pmon_ops.to_shortname = "pmon";
+ pmon_ops.to_doc = "\
+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";
+ pmon_ops.to_open = pmon_open;
+ pmon_ops.to_wait = mips_wait;
+
+ ddb_ops.to_shortname = "ddb";
+ ddb_ops.to_doc = "\
+Debug a board using the PMON MIPS remote debugging protocol over a serial\n\
+line. The first argument is the device it is connected to or, if it contains\n\
+a colon, HOST:PORT to access a board over a network. The optional second\n\
+parameter is the temporary file in the form HOST:FILENAME to be used for\n\
+TFTP downloads to the board. The optional third parameter is the local name\n\
+of the TFTP temporary file, if it differs from the filename seen by the board.";
+ ddb_ops.to_open = ddb_open;
+ ddb_ops.to_wait = mips_wait;
+
+ lsi_ops.to_shortname = "lsi";
+ lsi_ops.to_doc = pmon_ops.to_doc;
+ lsi_ops.to_open = lsi_open;
+ lsi_ops.to_wait = mips_wait;
+
+ /* Add the targets. */
+ add_target (&mips_ops);
+ add_target (&pmon_ops);
+ add_target (&ddb_ops);
+ add_target (&lsi_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);
+
+ add_show_from_set
+ (add_set_cmd ("monitor-prompt", class_obscure, var_string,
+ (char *) &mips_monitor_prompt,
+ "Set the prompt that GDB expects from the monitor.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("monitor-warnings", class_obscure, var_zinteger,
+ (char *) &monitor_warnings,
+ "Set printing of monitor warnings.\n"
+ "When enabled, monitor warnings about hardware breakpoints "
+ "will be displayed.",
+ &setlist),
+ &showlist);
+
+ add_com ("pmon <command>", class_obscure, pmon_command,
+ "Send a packet to PMON (must be in debug mode).");
+
+ add_show_from_set (add_set_cmd ("mask-address", no_class,
+ var_boolean, &mask_address_p,
+ "Set zeroing of upper 32 bits of 64-bit addresses when talking to PMON targets.\n\
+Use \"on\" to enable the masking and \"off\" to disable it.\n",
+ &setlist),
+ &showlist);
+}
diff --git a/contrib/gdb/gdb/remote-rdi.c b/contrib/gdb/gdb/remote-rdi.c
new file mode 100644
index 0000000..268ed32
--- /dev/null
+++ b/contrib/gdb/gdb/remote-rdi.c
@@ -0,0 +1,1026 @@
+/* GDB interface to ARM RDI library.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <fcntl.h>
+#include "frame.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "gdbthread.h"
+#include "gdbcore.h"
+#include "breakpoint.h"
+#include "completer.h"
+#include "regcache.h"
+#include "arm-tdep.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <signal.h>
+
+#include "rdi-share/ardi.h"
+#include "rdi-share/adp.h"
+#include "rdi-share/hsys.h"
+
+extern int isascii (int);
+
+/* Prototypes for local functions */
+
+static void arm_rdi_files_info (struct target_ops *ignore);
+
+static int arm_rdi_xfer_memory (CORE_ADDR memaddr, char *myaddr,
+ int len, int should_write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+
+static void arm_rdi_prepare_to_store (void);
+
+static void arm_rdi_fetch_registers (int regno);
+
+static void arm_rdi_resume (ptid_t pid, int step,
+ enum target_signal siggnal);
+
+static void arm_rdi_open (char *name, int from_tty);
+
+static void arm_rdi_create_inferior (char *exec_file, char *args, char **env);
+
+static void arm_rdi_close (int quitting);
+
+static void arm_rdi_store_registers (int regno);
+
+static ptid_t arm_rdi_wait (ptid_t ptid, struct target_waitstatus *status);
+
+static void arm_rdi_kill (void);
+
+static void arm_rdi_detach (char *args, int from_tty);
+
+static int arm_rdi_insert_breakpoint (CORE_ADDR, char *);
+
+static int arm_rdi_remove_breakpoint (CORE_ADDR, char *);
+
+static char *rdi_error_message (int err);
+
+static enum target_signal rdi_error_signal (int err);
+
+/* Global variables. */
+
+struct target_ops arm_rdi_ops;
+
+static struct Dbg_ConfigBlock gdb_config;
+
+static struct Dbg_HostosInterface gdb_hostif;
+
+static int max_load_size;
+
+static int execute_status;
+
+/* Send heatbeat packets? */
+static int rdi_heartbeat = 0;
+
+/* Target has ROM at address 0. */
+static int rom_at_zero = 0;
+
+/* Enable logging? */
+static int log_enable = 0;
+
+/* Name of the log file. Default is "rdi.log". */
+static char *log_filename;
+
+/* A little list of breakpoints that have been set. */
+
+static struct local_bp_list_entry
+ {
+ CORE_ADDR addr;
+ PointHandle point;
+ struct local_bp_list_entry *next;
+ }
+ *local_bp_list;
+
+/* Helper callbacks for the "host interface" structure. RDI functions call
+ these to forward output from the target system and so forth. */
+
+static void
+voiddummy (void *dummy)
+{
+ fprintf_unfiltered (gdb_stdout, "void dummy\n");
+}
+
+static void
+myprint (void *arg, const char *format, va_list ap)
+{
+ vfprintf_unfiltered (gdb_stdout, format, ap);
+}
+
+static void
+mywritec (void *arg, int c)
+{
+ if (isascii (c))
+ fputc_unfiltered (c, gdb_stdout);
+}
+
+static int
+mywrite (void *arg, char const *buffer, int len)
+{
+ int i;
+ char *e;
+
+ e = (char *) buffer;
+ for (i = 0; i < len; i++)
+ {
+ if (isascii ((int) *e))
+ {
+ fputc_unfiltered ((int) *e, gdb_stdout);
+ e++;
+ }
+ }
+
+ return len;
+}
+
+static void
+mypause (void *arg)
+{
+}
+
+/* These last two are tricky as we have to handle the special case of
+ being interrupted more carefully */
+
+static int
+myreadc (void *arg)
+{
+ return fgetc (stdin);
+}
+
+static char *
+mygets (void *arg, char *buffer, int len)
+{
+ return fgets (buffer, len, stdin);
+}
+
+/* Prevent multiple calls to angel_RDI_close(). */
+static int closed_already = 1;
+
+/* Open a connection to a remote debugger. NAME is the filename used
+ for communication. */
+
+static void
+arm_rdi_open (char *name, int from_tty)
+{
+ int rslt, i;
+ unsigned long arg1, arg2;
+ char *openArgs = NULL;
+ char *devName = NULL;
+ char *p;
+
+ if (name == NULL)
+ error ("To open an RDI connection, you need to specify what serial\n\
+device is attached to the remote system (e.g. /dev/ttya).");
+
+ /* split name after whitespace, pass tail as arg to open command */
+
+ devName = xstrdup (name);
+ p = strchr (devName, ' ');
+ if (p)
+ {
+ *p = '\0';
+ ++p;
+
+ while (*p == ' ')
+ ++p;
+
+ openArgs = p;
+ }
+
+ /* Make the basic low-level connection. */
+
+ arm_rdi_close (0);
+ rslt = Adp_OpenDevice (devName, openArgs, rdi_heartbeat);
+
+ if (rslt != adp_ok)
+ error ("Could not open device \"%s\"", name);
+
+ gdb_config.bytesex = 2 | (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 1 : 0);
+ gdb_config.fpe = 1;
+ gdb_config.rditype = 2;
+ gdb_config.heartbeat_on = 1;
+ gdb_config.flags = 2;
+
+ gdb_hostif.dbgprint = myprint;
+ gdb_hostif.dbgpause = mypause;
+ gdb_hostif.dbgarg = NULL;
+ gdb_hostif.writec = mywritec;
+ gdb_hostif.readc = myreadc;
+ gdb_hostif.write = mywrite;
+ gdb_hostif.gets = mygets;
+ gdb_hostif.hostosarg = NULL;
+ gdb_hostif.reset = voiddummy;
+
+ rslt = angel_RDI_open (10, &gdb_config, &gdb_hostif, NULL);
+ if (rslt == RDIError_BigEndian || rslt == RDIError_LittleEndian)
+ ; /* do nothing, this is the expected return */
+ else if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_open: %s\n", rdi_error_message (rslt));
+ Adp_CloseDevice ();
+ error ("RDI_open failed\n");
+ }
+
+ rslt = angel_RDI_info (RDIInfo_Target, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ rslt = angel_RDI_info (RDIInfo_Points, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ rslt = angel_RDI_info (RDIInfo_Step, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ rslt = angel_RDI_info (RDIInfo_CoPro, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ rslt = angel_RDI_info (RDIInfo_SemiHosting, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+
+ rslt = angel_RDI_info (RDIInfo_GetLoadSize, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ max_load_size = arg1;
+
+ push_target (&arm_rdi_ops);
+
+ target_fetch_registers (-1);
+
+ rslt = angel_RDI_open (1, &gdb_config, NULL, NULL);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_open: %s\n", rdi_error_message (rslt));
+ }
+
+ arg1 = rom_at_zero ? 0x0 : 0x13b;
+
+ rslt = angel_RDI_info (RDIVector_Catch, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+
+ arg1 = (unsigned long) "";
+ rslt = angel_RDI_info (RDISet_Cmdline, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+
+ /* Clear out any existing records of breakpoints. */
+ {
+ struct local_bp_list_entry *entry, *preventry = NULL;
+
+ for (entry = local_bp_list; entry != NULL; entry = entry->next)
+ {
+ if (preventry)
+ xfree (preventry);
+ }
+ }
+
+ printf_filtered ("Connected to ARM RDI target.\n");
+ closed_already = 0;
+ inferior_ptid = pid_to_ptid (42);
+}
+
+/* Start an inferior process and set inferior_ptid to its pid.
+ EXEC_FILE is the file to run.
+ ARGS 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
+arm_rdi_create_inferior (char *exec_file, char *args, char **env)
+{
+ int len, rslt;
+ unsigned long arg1, arg2;
+ char *arg_buf;
+ CORE_ADDR entry_point;
+
+ if (exec_file == 0 || exec_bfd == 0)
+ error ("No executable file specified.");
+
+ entry_point = (CORE_ADDR) bfd_get_start_address (exec_bfd);
+
+ arm_rdi_kill ();
+ remove_breakpoints ();
+ init_wait_for_inferior ();
+
+ len = 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);
+
+ inferior_ptid = pid_to_ptid (42);
+ insert_breakpoints (); /* Needed to get correct instruction in cache */
+
+ if (env != NULL)
+ {
+ while (*env)
+ {
+ if (strncmp (*env, "MEMSIZE=", sizeof ("MEMSIZE=") - 1) == 0)
+ {
+ unsigned long top_of_memory;
+ char *end_of_num;
+
+ /* Set up memory limit */
+ top_of_memory = strtoul (*env + sizeof ("MEMSIZE=") - 1,
+ &end_of_num, 0);
+ printf_filtered ("Setting top-of-memory to 0x%lx\n",
+ top_of_memory);
+
+ rslt = angel_RDI_info (RDIInfo_SetTopMem, &top_of_memory, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ }
+ env++;
+ }
+ }
+
+ arg1 = (unsigned long) arg_buf;
+ rslt = angel_RDI_info (RDISet_Cmdline, /* &arg1 */ (unsigned long *) arg_buf, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+
+ proceed (entry_point, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+/* 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
+arm_rdi_detach (char *args, int from_tty)
+{
+ pop_target ();
+}
+
+/* Clean up connection to a remote debugger. */
+
+static void
+arm_rdi_close (int quitting)
+{
+ int rslt;
+
+ if (!closed_already)
+ {
+ rslt = angel_RDI_close ();
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_close: %s\n", rdi_error_message (rslt));
+ }
+ closed_already = 1;
+ inferior_ptid = null_ptid;
+ Adp_CloseDevice ();
+ generic_mourn_inferior ();
+ }
+}
+
+/* Tell the remote machine to resume. */
+
+static void
+arm_rdi_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ int rslt;
+ PointHandle point;
+
+ if (0 /* turn on when hardware supports single-stepping */ )
+ {
+ rslt = angel_RDI_step (1, &point);
+ if (rslt != RDIError_NoError)
+ printf_filtered ("RDI_step: %s\n", rdi_error_message (rslt));
+ }
+ else
+ {
+ char handle[4];
+ CORE_ADDR pc = 0;
+
+ if (step)
+ {
+ pc = read_register (ARM_PC_REGNUM);
+ pc = arm_get_next_pc (pc);
+ arm_rdi_insert_breakpoint (pc, handle);
+ }
+
+ execute_status = rslt = angel_RDI_execute (&point);
+ if (rslt != RDIError_NoError && rslt != RDIError_BreakpointReached)
+ printf_filtered ("RDI_execute: %s\n", rdi_error_message (rslt));
+
+ if (step)
+ arm_rdi_remove_breakpoint (pc, handle);
+ }
+}
+
+/* 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 ptid_t
+arm_rdi_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ status->kind = (execute_status == RDIError_NoError ?
+ TARGET_WAITKIND_EXITED : TARGET_WAITKIND_STOPPED);
+
+ /* convert stopped code from target into right signal */
+ status->value.sig = rdi_error_signal (execute_status);
+
+ return inferior_ptid;
+}
+
+/* Read the remote registers into the block REGS. */
+
+static void
+arm_rdi_fetch_registers (int regno)
+{
+ int rslt, rdi_regmask;
+ unsigned long rawreg, rawregs[32];
+ char cookedreg[4];
+
+ if (regno == -1)
+ {
+ rslt = angel_RDI_CPUread (255, 0x27fff, rawregs);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_CPUread: %s\n", rdi_error_message (rslt));
+ }
+
+ for (regno = 0; regno < 15; regno++)
+ {
+ store_unsigned_integer (cookedreg, 4, rawregs[regno]);
+ supply_register (regno, (char *) cookedreg);
+ }
+ store_unsigned_integer (cookedreg, 4, rawregs[15]);
+ supply_register (ARM_PS_REGNUM, (char *) cookedreg);
+ arm_rdi_fetch_registers (ARM_PC_REGNUM);
+ }
+ else
+ {
+ if (regno == ARM_PC_REGNUM)
+ rdi_regmask = RDIReg_PC;
+ else if (regno == ARM_PS_REGNUM)
+ rdi_regmask = RDIReg_CPSR;
+ else if (regno < 0 || regno > 15)
+ {
+ rawreg = 0;
+ supply_register (regno, (char *) &rawreg);
+ return;
+ }
+ else
+ rdi_regmask = 1 << regno;
+
+ rslt = angel_RDI_CPUread (255, rdi_regmask, &rawreg);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_CPUread: %s\n", rdi_error_message (rslt));
+ }
+ store_unsigned_integer (cookedreg, 4, rawreg);
+ supply_register (regno, (char *) cookedreg);
+ }
+}
+
+static void
+arm_rdi_prepare_to_store (void)
+{
+ /* Nothing to do. */
+}
+
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+ of REGISTERS. FIXME: ignores errors. */
+
+static void
+arm_rdi_store_registers (int regno)
+{
+ int rslt, rdi_regmask;
+
+ /* These need to be able to take 'floating point register' contents */
+ unsigned long rawreg[3], rawerreg[3];
+
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ arm_rdi_store_registers (regno);
+ }
+ else
+ {
+ deprecated_read_register_gen (regno, (char *) rawreg);
+ /* RDI manipulates data in host byte order, so convert now. */
+ store_unsigned_integer (rawerreg, 4, rawreg[0]);
+
+ if (regno == ARM_PC_REGNUM)
+ rdi_regmask = RDIReg_PC;
+ else if (regno == ARM_PS_REGNUM)
+ rdi_regmask = RDIReg_CPSR;
+ else if (regno < 0 || regno > 15)
+ return;
+ else
+ rdi_regmask = 1 << regno;
+
+ rslt = angel_RDI_CPUwrite (255, rdi_regmask, rawerreg);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_CPUwrite: %s\n", rdi_error_message (rslt));
+ }
+ }
+}
+
+/* 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. TARGET is unused. */
+
+static int
+arm_rdi_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int should_write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ int rslt, i;
+
+ if (should_write)
+ {
+ rslt = angel_RDI_write (myaddr, memaddr, &len);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_write: %s\n", rdi_error_message (rslt));
+ }
+ }
+ else
+ {
+ rslt = angel_RDI_read (memaddr, myaddr, &len);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_read: %s\n", rdi_error_message (rslt));
+ len = 0;
+ }
+ }
+ return len;
+}
+
+/* Display random info collected from the target. */
+
+static void
+arm_rdi_files_info (struct target_ops *ignore)
+{
+ char *file = "nothing";
+ int rslt;
+ unsigned long arg1, arg2;
+
+ rslt = angel_RDI_info (RDIInfo_Target, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ if (arg1 & (1 << 15))
+ printf_filtered ("Target supports Thumb code.\n");
+ if (arg1 & (1 << 14))
+ printf_filtered ("Target can do profiling.\n");
+ if (arg1 & (1 << 4))
+ printf_filtered ("Target is real hardware.\n");
+
+ rslt = angel_RDI_info (RDIInfo_Step, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ printf_filtered ("Target can%s single-step.\n", (arg1 & 0x4 ? "" : "not"));
+
+ rslt = angel_RDI_info (RDIInfo_Icebreaker, &arg1, &arg2);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt));
+ }
+ else
+ printf_filtered ("Target includes an EmbeddedICE.\n");
+}
+
+static void
+arm_rdi_kill (void)
+{
+ int rslt;
+
+ rslt = angel_RDI_open (1, &gdb_config, NULL, NULL);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_open: %s\n", rdi_error_message (rslt));
+ }
+}
+
+static void
+arm_rdi_mourn_inferior (void)
+{
+ /* We remove the inserted breakpoints in case the user wants to
+ issue another target and load commands to rerun his application;
+ This is something that wouldn't work on a native target, for instance,
+ as the process goes away when the inferior exits, but it works with
+ some remote targets like this one. That is why this is done here. */
+ remove_breakpoints();
+ unpush_target (&arm_rdi_ops);
+ generic_mourn_inferior ();
+}
+
+/* While the RDI library keeps track of its own breakpoints, we need
+ to remember "handles" so that we can delete them later. Since
+ breakpoints get used for stepping, be careful not to leak memory
+ here. */
+
+static int
+arm_rdi_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ int rslt;
+ PointHandle point;
+ struct local_bp_list_entry *entry;
+ int type = RDIPoint_EQ;
+
+ if (arm_pc_is_thumb (addr) || arm_pc_is_thumb_dummy (addr))
+ type |= RDIPoint_16Bit;
+ rslt = angel_RDI_setbreak (addr, type, 0, &point);
+ if (rslt != RDIError_NoError)
+ {
+ printf_filtered ("RDI_setbreak: %s\n", rdi_error_message (rslt));
+ }
+ entry =
+ (struct local_bp_list_entry *) xmalloc (sizeof (struct local_bp_list_entry));
+ entry->addr = addr;
+ entry->point = point;
+ entry->next = local_bp_list;
+ local_bp_list = entry;
+ return rslt;
+}
+
+static int
+arm_rdi_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ int rslt;
+ PointHandle point;
+ struct local_bp_list_entry **entryp, *dead;
+
+ for (entryp = &local_bp_list; *entryp != NULL; entryp = &(*entryp)->next)
+ if ((*entryp)->addr == addr)
+ break;
+
+ if (*entryp)
+ {
+ dead = *entryp;
+ rslt = angel_RDI_clearbreak (dead->point);
+ if (rslt != RDIError_NoError)
+ printf_filtered ("RDI_clearbreak: %s\n", rdi_error_message (rslt));
+
+ /* Delete the breakpoint entry locally. */
+ *entryp = dead->next;
+ xfree (dead);
+ }
+
+ return 0;
+}
+
+
+static char *
+rdi_error_message (int err)
+{
+ switch (err)
+ {
+ case RDIError_NoError:
+ return "no error";
+ case RDIError_Reset:
+ return "debuggee reset";
+ case RDIError_UndefinedInstruction:
+ return "undefined instruction";
+ case RDIError_SoftwareInterrupt:
+ return "SWI trapped";
+ case RDIError_PrefetchAbort:
+ return "prefetch abort, execution ran into unmapped memory?";
+ case RDIError_DataAbort:
+ return "data abort, no memory at specified address?";
+ case RDIError_AddressException:
+ return "address exception, access >26bit in 26bit mode";
+ case RDIError_IRQ:
+ return "IRQ, interrupt trapped";
+ case RDIError_FIQ:
+ return "FIQ, fast interrupt trapped";
+ case RDIError_Error:
+ return "a miscellaneous type of error";
+ case RDIError_BranchThrough0:
+ return "branch through location 0";
+ case RDIError_NotInitialised:
+ return "internal error, RDI_open not called first";
+ case RDIError_UnableToInitialise:
+ return "internal error, target world is broken";
+ case RDIError_WrongByteSex:
+ return "See Operator: WrongByteSex";
+ case RDIError_UnableToTerminate:
+ return "See Operator: Unable to Terminate";
+ case RDIError_BadInstruction:
+ return "bad instruction, illegal to execute this instruction";
+ case RDIError_IllegalInstruction:
+ return "illegal instruction, the effect of executing it is undefined";
+ case RDIError_BadCPUStateSetting:
+ return "internal error, tried to set SPSR of user mode";
+ case RDIError_UnknownCoPro:
+ return "unknown co-processor";
+ case RDIError_UnknownCoProState:
+ return "cannot execute co-processor request";
+ case RDIError_BadCoProState:
+ return "recognizably broken co-processor request";
+ case RDIError_BadPointType:
+ return "internal error, bad point yype";
+ case RDIError_UnimplementedType:
+ return "internal error, unimplemented type";
+ case RDIError_BadPointSize:
+ return "internal error, bad point size";
+ case RDIError_UnimplementedSize:
+ return "internal error, unimplemented size";
+ case RDIError_NoMorePoints:
+ return "last break/watch point was used";
+ case RDIError_BreakpointReached:
+ return "breakpoint reached";
+ case RDIError_WatchpointAccessed:
+ return "watchpoint accessed";
+ case RDIError_NoSuchPoint:
+ return "attempted to clear non-existent break/watch point";
+ case RDIError_ProgramFinishedInStep:
+ return "end of the program reached while stepping";
+ case RDIError_UserInterrupt:
+ return "you pressed Escape";
+ case RDIError_CantSetPoint:
+ return "no more break/watch points available";
+ case RDIError_IncompatibleRDILevels:
+ return "incompatible RDI levels";
+ case RDIError_LittleEndian:
+ return "debuggee is little endian";
+ case RDIError_BigEndian:
+ return "debuggee is big endian";
+ case RDIError_SoftInitialiseError:
+ return "recoverable error in RDI initialization";
+ case RDIError_InsufficientPrivilege:
+ return "internal error, supervisor state not accessible to monitor";
+ case RDIError_UnimplementedMessage:
+ return "internal error, unimplemented message";
+ case RDIError_UndefinedMessage:
+ return "internal error, undefined message";
+ default:
+ return "undefined error message, should reset target";
+ }
+}
+
+/* Convert the ARM error messages to signals that GDB knows about. */
+
+static enum target_signal
+rdi_error_signal (int err)
+{
+ switch (err)
+ {
+ case RDIError_NoError:
+ return 0;
+ case RDIError_Reset:
+ return TARGET_SIGNAL_TERM; /* ??? */
+ case RDIError_UndefinedInstruction:
+ return TARGET_SIGNAL_ILL;
+ case RDIError_SoftwareInterrupt:
+ case RDIError_PrefetchAbort:
+ case RDIError_DataAbort:
+ return TARGET_SIGNAL_TRAP;
+ case RDIError_AddressException:
+ return TARGET_SIGNAL_SEGV;
+ case RDIError_IRQ:
+ case RDIError_FIQ:
+ return TARGET_SIGNAL_TRAP;
+ case RDIError_Error:
+ return TARGET_SIGNAL_TERM;
+ case RDIError_BranchThrough0:
+ return TARGET_SIGNAL_TRAP;
+ case RDIError_NotInitialised:
+ case RDIError_UnableToInitialise:
+ case RDIError_WrongByteSex:
+ case RDIError_UnableToTerminate:
+ return TARGET_SIGNAL_UNKNOWN;
+ case RDIError_BadInstruction:
+ case RDIError_IllegalInstruction:
+ return TARGET_SIGNAL_ILL;
+ case RDIError_BadCPUStateSetting:
+ case RDIError_UnknownCoPro:
+ case RDIError_UnknownCoProState:
+ case RDIError_BadCoProState:
+ case RDIError_BadPointType:
+ case RDIError_UnimplementedType:
+ case RDIError_BadPointSize:
+ case RDIError_UnimplementedSize:
+ case RDIError_NoMorePoints:
+ return TARGET_SIGNAL_UNKNOWN;
+ case RDIError_BreakpointReached:
+ case RDIError_WatchpointAccessed:
+ return TARGET_SIGNAL_TRAP;
+ case RDIError_NoSuchPoint:
+ case RDIError_ProgramFinishedInStep:
+ return TARGET_SIGNAL_UNKNOWN;
+ case RDIError_UserInterrupt:
+ return TARGET_SIGNAL_INT;
+ case RDIError_IncompatibleRDILevels:
+ case RDIError_LittleEndian:
+ case RDIError_BigEndian:
+ case RDIError_SoftInitialiseError:
+ case RDIError_InsufficientPrivilege:
+ case RDIError_UnimplementedMessage:
+ case RDIError_UndefinedMessage:
+ default:
+ return TARGET_SIGNAL_UNKNOWN;
+ }
+}
+
+static void
+arm_rdi_stop(void)
+{
+ angel_RDI_stop_request();
+}
+
+
+/* Define the target operations structure. */
+
+static void
+init_rdi_ops (void)
+{
+ arm_rdi_ops.to_shortname = "rdi";
+ arm_rdi_ops.to_longname = "ARM RDI";
+ arm_rdi_ops.to_doc = "Use a remote ARM-based computer; via the RDI library.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ arm_rdi_ops.to_open = arm_rdi_open;
+ arm_rdi_ops.to_close = arm_rdi_close;
+ arm_rdi_ops.to_detach = arm_rdi_detach;
+ arm_rdi_ops.to_resume = arm_rdi_resume;
+ arm_rdi_ops.to_wait = arm_rdi_wait;
+ arm_rdi_ops.to_stop = arm_rdi_stop;
+ arm_rdi_ops.to_fetch_registers = arm_rdi_fetch_registers;
+ arm_rdi_ops.to_store_registers = arm_rdi_store_registers;
+ arm_rdi_ops.to_prepare_to_store = arm_rdi_prepare_to_store;
+ arm_rdi_ops.to_xfer_memory = arm_rdi_xfer_memory;
+ arm_rdi_ops.to_files_info = arm_rdi_files_info;
+ arm_rdi_ops.to_insert_breakpoint = arm_rdi_insert_breakpoint;
+ arm_rdi_ops.to_remove_breakpoint = arm_rdi_remove_breakpoint;
+ arm_rdi_ops.to_kill = arm_rdi_kill;
+ arm_rdi_ops.to_load = generic_load;
+ arm_rdi_ops.to_create_inferior = arm_rdi_create_inferior;
+ arm_rdi_ops.to_mourn_inferior = arm_rdi_mourn_inferior;
+ arm_rdi_ops.to_stratum = process_stratum;
+ arm_rdi_ops.to_has_all_memory = 1;
+ arm_rdi_ops.to_has_memory = 1;
+ arm_rdi_ops.to_has_stack = 1;
+ arm_rdi_ops.to_has_registers = 1;
+ arm_rdi_ops.to_has_execution = 1;
+ arm_rdi_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+rdilogfile_command (char *arg, int from_tty)
+{
+ if (!arg || strlen (arg) == 0)
+ {
+ printf_filtered ("rdi log file is '%s'\n", log_filename);
+ return;
+ }
+
+ if (log_filename)
+ xfree (log_filename);
+
+ log_filename = xstrdup (arg);
+
+ Adp_SetLogfile (log_filename);
+}
+
+static void
+rdilogenable_command (char *args, int from_tty)
+{
+ if (!args || strlen (args) == 0)
+ {
+ printf_filtered ("rdi log is %s\n", log_enable ? "enabled" : "disabled");
+ return;
+ }
+
+ if (!strcasecmp (args, "1") ||
+ !strcasecmp (args, "y") ||
+ !strcasecmp (args, "yes") ||
+ !strcasecmp (args, "on") ||
+ !strcasecmp (args, "t") ||
+ !strcasecmp (args, "true"))
+ Adp_SetLogEnable (log_enable = 1);
+ else if (!strcasecmp (args, "0") ||
+ !strcasecmp (args, "n") ||
+ !strcasecmp (args, "no") ||
+ !strcasecmp (args, "off") ||
+ !strcasecmp (args, "f") ||
+ !strcasecmp (args, "false"))
+ Adp_SetLogEnable (log_enable = 0);
+ else
+ printf_filtered ("rdilogenable: unrecognized argument '%s'\n"
+ " try y or n\n", args);
+}
+
+extern initialize_file_ftype _initialize_remote_rdi; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_rdi (void)
+{
+ struct cmd_list_element *c;
+
+ init_rdi_ops ();
+ add_target (&arm_rdi_ops);
+
+ log_filename = xstrdup ("rdi.log");
+ Adp_SetLogfile (log_filename);
+ Adp_SetLogEnable (log_enable);
+
+ c = add_cmd ("rdilogfile", class_maintenance,
+ rdilogfile_command,
+ "Set filename for ADP packet log.\n"
+ "This file is used to log Angel Debugger Protocol packets.\n"
+ "With a single argument, sets the logfile name to that value.\n"
+ "Without an argument, shows the current logfile name.\n"
+ "See also: rdilogenable\n",
+ &maintenancelist);
+ set_cmd_completer (c, filename_completer);
+
+ add_cmd ("rdilogenable", class_maintenance,
+ rdilogenable_command,
+ "Set enable logging of ADP packets.\n"
+ "This will log ADP packets exchanged between gdb and the\n"
+ "rdi target device.\n"
+ "An argument of 1, t, true, y or yes will enable.\n"
+ "An argument of 0, f, false, n or no will disabled.\n"
+ "Withough an argument, it will display current state.\n",
+ &maintenancelist);
+
+ add_setshow_boolean_cmd
+ ("rdiromatzero", no_class, &rom_at_zero,
+ "Set target has ROM at addr 0.\n"
+ "A true value disables vector catching, false enables vector catching.\n"
+ "This is evaluated at the time the 'target rdi' command is executed\n",
+ "Show if target has ROM at addr 0.\n",
+ NULL, NULL,
+ &setlist, &showlist);
+
+ add_setshow_boolean_cmd
+ ("rdiheartbeat", no_class, &rdi_heartbeat,
+ "Set enable for ADP heartbeat packets.\n"
+ "I don't know why you would want this. If you enable them,\n"
+ "it will confuse ARM and EPI JTAG interface boxes as well\n"
+ "as the Angel Monitor.\n",
+ "Show enable for ADP heartbeat packets.\n",
+ NULL, NULL,
+ &setlist, &showlist);
+}
+
+/* A little dummy to make linking with the library succeed. */
+
+void
+Fail (const char *ignored, ...)
+{
+
+}
diff --git a/contrib/gdb/gdb/remote-rdp.c b/contrib/gdb/gdb/remote-rdp.c
new file mode 100644
index 0000000..eab68ea
--- /dev/null
+++ b/contrib/gdb/gdb/remote-rdp.c
@@ -0,0 +1,1431 @@
+/* Remote debugging for the ARM RDP interface.
+
+ Copyright 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "value.h"
+#include "gdb/callback.h"
+#include "command.h"
+#include <ctype.h>
+#include <fcntl.h>
+#include "symfile.h"
+#include "remote-utils.h"
+#include "gdb_string.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "serial.h"
+
+#include "arm-tdep.h"
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+extern struct target_ops remote_rdp_ops;
+static struct serial *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_INFO_VECTOR_CATCH (0x180)
+#define RDP_INFO_ICEBREAKER (7)
+#define RDP_INFO_SET_CMDLINE (0x300)
+
+#define RDP_SELECT_CONFIG (0x16)
+#define RDI_ConfigCPU 0
+#define RDI_ConfigSystem 1
+#define RDI_MatchAny 0
+#define RDI_MatchExactly 1
+#define RDI_MatchNoEarlier 2
+
+#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 char *commandline = NULL;
+
+static int
+remote_rdp_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+
+
+/* Stuff for talking to the serial layer. */
+
+static unsigned char
+get_byte (void)
+{
+ int c = serial_readchar (io, timeout);
+
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "[%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 (void)
+{
+ 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 (char val)
+{
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "(%02x)\n", val);
+ serial_write (io, &val, 1);
+}
+
+static void
+put_word (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)
+ fprintf_unfiltered (gdb_stdlog, "(%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 (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);
+
+ /*
+ ** It seems necessary to reset an EmbeddedICE to get it going.
+ ** This has the side benefit of displaying the startup banner.
+ */
+ if (cold)
+ {
+ put_byte (RDP_RESET);
+ while ((restype = serial_readchar (io, 1)) > 0)
+ {
+ switch (restype)
+ {
+ case SERIAL_TIMEOUT:
+ break;
+ case RDP_RESET:
+ /* Sent at start of reset process: ignore */
+ break;
+ default:
+ printf_unfiltered ("%c", isgraph (restype) ? restype : ' ');
+ break;
+ }
+ }
+
+ if (restype == 0)
+ {
+ /* Got end-of-banner mark */
+ printf_filtered ("\n");
+ }
+ }
+
+ 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)
+ fprintf_unfiltered (gdb_stdlog, "[%02x]\n", restype);
+
+ switch (restype)
+ {
+ case SERIAL_TIMEOUT:
+ break;
+
+ case RDP_RESET:
+ while ((restype = serial_readchar (io, 1)) == RDP_RESET)
+ ;
+ do
+ {
+ 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");
+ cold = 0;
+ break;
+
+ default:
+ break;
+
+ case RDP_RES_VALUE:
+ {
+ int resval = serial_readchar (io, 1);
+
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "[%02x]\n", resval);
+
+ switch (resval)
+ {
+ case SERIAL_TIMEOUT:
+ break;
+ case RDP_RES_VALUE_LITTLE_ENDIAN:
+#if 0
+ /* FIXME: cagney/2003-11-22: Ever since the ARM
+ was multi-arched (in 2002-02-08), this
+ assignment has had no effect. There needs to
+ be some sort of check/decision based on the
+ current architecture's byte-order vs the remote
+ target's byte order. For the moment disable
+ the assignment to keep things building. */
+ target_byte_order = BFD_ENDIAN_LITTLE;
+#endif
+ sync = 1;
+ break;
+ case RDP_RES_VALUE_BIG_ENDIAN:
+#if 0
+ /* FIXME: cagney/2003-11-22: Ever since the ARM
+ was multi-arched (in 2002-02-08), this
+ assignment has had no effect. There needs to
+ be some sort of check/decision based on the
+ current architecture's byte-order vs the remote
+ target's byte order. For the moment disable
+ the assignment to keep things building. */
+ target_byte_order = BFD_ENDIAN_BIG;
+#endif
+ sync = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!sync)
+ {
+ error ("Couldn't reset the board, try pressing the reset button");
+ }
+}
+
+
+static void
+send_rdp (char *template,...)
+{
+ char buf[200];
+ char *dst = buf;
+ va_list alist;
+ va_start (alist, template);
+
+ 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 */
+ switch (get_byte ())
+ {
+ case 0:
+ /* Success */
+ break;
+ case 253:
+ /* Target can't do it; never mind */
+ printf_unfiltered ("RDP: Insufficient privilege\n");
+ return;
+ case 254:
+ /* Target can't do it; never mind */
+ printf_unfiltered ("RDP: Unimplemented message\n");
+ return;
+ case 255:
+ error ("Command garbled");
+ break;
+ default:
+ error ("Corrupt reply from target");
+ break;
+ }
+ 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:
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ }
+ va_end (alist);
+
+ if (dst != buf)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+}
+
+
+static int
+rdp_write (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 (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 (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 (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_SIZE);
+}
+
+
+static void
+rdp_store_one_register (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 (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 (int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ remote_rdp_fetch_register (regno);
+ }
+ else
+ {
+ char buf[MAX_REGISTER_SIZE];
+ if (regno < 15)
+ rdp_fetch_one_register (1 << regno, buf);
+ else if (regno == ARM_PC_REGNUM)
+ rdp_fetch_one_register (RDP_CPU_READWRITE_MASK_PC, buf);
+ else if (regno == ARM_PS_REGNUM)
+ rdp_fetch_one_register (RDP_CPU_READWRITE_MASK_CPSR, buf);
+ else if (regno == ARM_FPS_REGNUM)
+ rdp_fetch_one_fpu_register (RDP_FPU_READWRITE_MASK_FPS, buf);
+ else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
+ rdp_fetch_one_fpu_register (1 << (regno - ARM_F0_REGNUM), buf);
+ else
+ {
+ printf ("Help me with fetch reg %d\n", regno);
+ }
+ supply_register (regno, buf);
+ }
+}
+
+
+static void
+remote_rdp_store_register (int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ remote_rdp_store_register (regno);
+ }
+ else
+ {
+ char tmp[MAX_REGISTER_SIZE];
+ deprecated_read_register_gen (regno, tmp);
+ if (regno < 15)
+ rdp_store_one_register (1 << regno, tmp);
+ else if (regno == ARM_PC_REGNUM)
+ rdp_store_one_register (RDP_CPU_READWRITE_MASK_PC, tmp);
+ else if (regno == ARM_PS_REGNUM)
+ rdp_store_one_register (RDP_CPU_READWRITE_MASK_CPSR, tmp);
+ else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
+ rdp_store_one_fpu_register (1 << (regno - ARM_F0_REGNUM), tmp);
+ else
+ {
+ printf ("Help me with reg %d\n", regno);
+ }
+ }
+}
+
+static void
+remote_rdp_kill (void)
+{
+ callback->shutdown (callback);
+}
+
+
+static void
+rdp_info (void)
+{
+ 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 (void)
+{
+ /* Start it off, but don't wait for it */
+ send_rdp ("bb-", RDP_EXEC, RDP_EXEC_TYPE_SYNC);
+}
+
+
+static void
+rdp_set_command_line (char *command, char *args)
+{
+ /*
+ ** We could use RDP_INFO_SET_CMDLINE to send this, but EmbeddedICE systems
+ ** don't implement that, and get all confused at the unexpected text.
+ ** Instead, just keep a copy, and send it when the target does a SWI_GetEnv
+ */
+
+ if (commandline != NULL)
+ xfree (commandline);
+
+ xasprintf (&commandline, "%s %s", command, args);
+}
+
+static void
+rdp_catch_vectors (void)
+{
+ /*
+ ** We want the target monitor to intercept the abort vectors
+ ** i.e. stop the program if any of these are used.
+ */
+ send_rdp ("bww-SZ", RDP_INFO, RDP_INFO_VECTOR_CATCH,
+ /*
+ ** Specify a bitmask including
+ ** the reset vector
+ ** the undefined instruction vector
+ ** the prefetch abort vector
+ ** the data abort vector
+ ** the address exception vector
+ */
+ (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5)
+ );
+}
+
+
+
+#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
+
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static int translate_open_mode[] =
+{
+ O_RDONLY, /* "r" */
+ O_RDONLY + O_BINARY, /* "rb" */
+ O_RDWR, /* "r+" */
+ O_RDWR + O_BINARY, /* "r+b" */
+ O_WRONLY + O_CREAT + O_TRUNC, /* "w" */
+ O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */
+ O_RDWR + O_CREAT + O_TRUNC, /* "w+" */
+ O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */
+ O_WRONLY + O_APPEND + O_CREAT, /* "a" */
+ O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */
+ O_RDWR + O_APPEND + O_CREAT, /* "a+" */
+ O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */
+};
+
+static int
+exec_swi (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_Clock:
+ /* return number of centi-seconds... */
+ args->n =
+#ifdef CLOCKS_PER_SEC
+ (CLOCKS_PER_SEC >= 100)
+ ? (clock () / (CLOCKS_PER_SEC / 100))
+ : ((clock () * 100) / CLOCKS_PER_SEC);
+#else
+ /* presume unix... clock() returns microseconds */
+ clock () / 10000;
+#endif
+ 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:
+ /* Now we need to decode the Demon open mode */
+ i = translate_open_mode[args[1].n];
+
+ /* Filename ":tt" is special: it denotes stdin/out */
+ if (strcmp (args->s, ":tt") == 0)
+ {
+ if (i == O_RDONLY) /* opening tty "r" */
+ args->n = 0 /* stdin */ ;
+ else
+ args->n = 1 /* stdout */ ;
+ }
+ else
+ 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:
+ /* Return the number of bytes *not* written */
+ args->n = args[1].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[1].n, copy, done, 1, 0, 0);
+ args->n = args[2].n - done;
+ return 1;
+ }
+
+ case SWI_Seek:
+ /* Return non-zero on failure */
+ 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, 0, SEEK_CUR);
+ args->n = callback->lseek (callback, args->n, 0, SEEK_END);
+ callback->lseek (callback, args->n, old, 0);
+ return 1;
+ }
+
+ case SWI_IsTTY:
+ args->n = callback->isatty (callback, args->n);
+ return 1;
+
+ case SWI_GetEnv:
+ if (commandline != NULL)
+ {
+ int len = strlen (commandline);
+ if (len > 255)
+ {
+ len = 255;
+ commandline[255] = '\0';
+ }
+ remote_rdp_xfer_inferior_memory (args[0].n,
+ commandline, len + 1, 1, 0, 0);
+ }
+ else
+ remote_rdp_xfer_inferior_memory (args[0].n, "", 1, 1, 0, 0);
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+static void
+handle_swi (void)
+{
+ 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,
+ 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 ("Unimplemented 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 (void)
+{
+ 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 (void)
+{
+ rdp_execute_start ();
+ rdp_execute_finish ();
+}
+
+static int
+remote_rdp_insert_breakpoint (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 (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 (void)
+{
+ 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 (ARM_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 (char *args, int from_tty)
+{
+ int not_icebreaker;
+
+ 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 ();
+
+ /* Need to set up the vector interception state */
+ rdp_catch_vectors ();
+
+ /*
+ ** If it's an EmbeddedICE, we need to set the processor config.
+ ** Assume we can always have ARM7TDI...
+ */
+ send_rdp ("bw-SB", RDP_INFO, RDP_INFO_ICEBREAKER, &not_icebreaker);
+ if (!not_icebreaker)
+ {
+ const char *CPU = "ARM7TDI";
+ int ICEversion;
+ int len = strlen (CPU);
+
+ send_rdp ("bbbbw-p-SWZ",
+ RDP_SELECT_CONFIG,
+ RDI_ConfigCPU, /* Aspect: set the CPU */
+ len, /* The number of bytes in the name */
+ RDI_MatchAny, /* We'll take whatever we get */
+ 0, /* We'll take whatever version's there */
+ CPU, len,
+ &ICEversion);
+ }
+
+ /* command line initialised on 'run' */
+
+ push_target (&remote_rdp_ops);
+
+ callback->init (callback);
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc ();
+ print_stack_frame (get_selected_frame (), -1, 1);
+}
+
+
+
+/* Close out all files and local state before this target loses control. */
+
+static void
+remote_rdp_close (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 (ptid_t ptid, int 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 ptid_t
+remote_rdp_wait (ptid_t ptid, 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_ptid;
+}
+
+/* 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 (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+/* Transfer LEN bytes between GDB address MYADDR and target address
+ MEMADDR. If WRITE is non-zero, transfer them to the target,
+ otherwise transfer them from the target. TARGET is unused.
+
+ Returns the number of bytes transferred. */
+
+static int
+remote_rdp_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ /* 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 (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 (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);
+}
+
+
+static void
+remote_rdp_create_inferior (char *exec_file, char *allargs, char **env)
+{
+ CORE_ADDR entry_point;
+
+ if (exec_file == 0 || exec_bfd == 0)
+ error ("No executable file specified.");
+
+ entry_point = (CORE_ADDR) bfd_get_start_address (exec_bfd);
+
+ remote_rdp_kill ();
+ remove_breakpoints ();
+ init_wait_for_inferior ();
+
+ /* This gives us a chance to set up the command line */
+ rdp_set_command_line (exec_file, allargs);
+
+ inferior_ptid = pid_to_ptid (42);
+ insert_breakpoints (); /* Needed to get correct instruction in cache */
+
+ /*
+ ** RDP targets don't provide any facility to set the top of memory,
+ ** so we don't bother to look for MEMSIZE in the environment.
+ */
+
+ /* Let's go! */
+ proceed (entry_point, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+/* Attach doesn't need to do anything */
+static void
+remote_rdp_attach (char *args, int from_tty)
+{
+ return;
+}
+
+/* Define the target subroutine names */
+
+struct target_ops remote_rdp_ops;
+
+static void
+init_remote_rdp_ops (void)
+{
+ remote_rdp_ops.to_shortname = "rdp";
+ remote_rdp_ops.to_longname = "Remote Target using the RDProtocol";
+ remote_rdp_ops.to_doc = "Use a remote ARM system which uses the ARM Remote Debugging Protocol";
+ remote_rdp_ops.to_open = remote_rdp_open;
+ remote_rdp_ops.to_close = remote_rdp_close;
+ remote_rdp_ops.to_attach = remote_rdp_attach;
+ remote_rdp_ops.to_resume = remote_rdp_resume;
+ remote_rdp_ops.to_wait = remote_rdp_wait;
+ remote_rdp_ops.to_fetch_registers = remote_rdp_fetch_register;
+ remote_rdp_ops.to_store_registers = remote_rdp_store_register;
+ remote_rdp_ops.to_prepare_to_store = remote_rdp_prepare_to_store;
+ remote_rdp_ops.to_xfer_memory = remote_rdp_xfer_inferior_memory;
+ remote_rdp_ops.to_files_info = remote_rdp_files_info;
+ remote_rdp_ops.to_insert_breakpoint = remote_rdp_insert_breakpoint;
+ remote_rdp_ops.to_remove_breakpoint = remote_rdp_remove_breakpoint;
+ remote_rdp_ops.to_kill = remote_rdp_kill;
+ remote_rdp_ops.to_load = generic_load;
+ remote_rdp_ops.to_create_inferior = remote_rdp_create_inferior;
+ remote_rdp_ops.to_mourn_inferior = generic_mourn_inferior;
+ remote_rdp_ops.to_stratum = process_stratum;
+ remote_rdp_ops.to_has_all_memory = 1;
+ remote_rdp_ops.to_has_memory = 1;
+ remote_rdp_ops.to_has_stack = 1;
+ remote_rdp_ops.to_has_registers = 1;
+ remote_rdp_ops.to_has_execution = 1;
+ remote_rdp_ops.to_magic = OPS_MAGIC;
+}
+
+extern initialize_file_ftype _initialize_remote_rdp; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_rdp (void)
+{
+ init_remote_rdp_ops ();
+ add_target (&remote_rdp_ops);
+}
diff --git a/contrib/gdb/gdb/remote-sds.c b/contrib/gdb/gdb/remote-sds.c
new file mode 100644
index 0000000..d74fd7d
--- /dev/null
+++ b/contrib/gdb/gdb/remote-sds.c
@@ -0,0 +1,1130 @@
+/* Remote target communications for serial-line targets using SDS' protocol.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 interface was written by studying the behavior of the SDS
+ monitor on an ADS 821/860 board, and by consulting the
+ documentation of the monitor that is available on Motorola's web
+ site. -sts 8/13/97 */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <fcntl.h>
+#include "frame.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "gdbthread.h"
+#include "gdbcore.h"
+#include "regcache.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <signal.h>
+#include "serial.h"
+
+extern void _initialize_remote_sds (void);
+
+/* Declarations of local functions. */
+
+static int sds_write_bytes (CORE_ADDR, char *, int);
+
+static int sds_read_bytes (CORE_ADDR, char *, int);
+
+static void sds_files_info (struct target_ops *ignore);
+
+static int sds_xfer_memory (CORE_ADDR, char *, int, int,
+ struct mem_attrib *, struct target_ops *);
+
+static void sds_prepare_to_store (void);
+
+static void sds_fetch_registers (int);
+
+static void sds_resume (ptid_t, int, enum target_signal);
+
+static int sds_start_remote (void *);
+
+static void sds_open (char *, int);
+
+static void sds_close (int);
+
+static void sds_store_registers (int);
+
+static void sds_mourn (void);
+
+static void sds_create_inferior (char *, char *, char **);
+
+static void sds_load (char *, int);
+
+static int getmessage (unsigned char *, int);
+
+static int putmessage (unsigned char *, int);
+
+static int sds_send (unsigned char *, int);
+
+static int readchar (int);
+
+static ptid_t sds_wait (ptid_t, struct target_waitstatus *);
+
+static void sds_kill (void);
+
+static int fromhex (int);
+
+static void sds_detach (char *, int);
+
+static void sds_interrupt (int);
+
+static void sds_interrupt_twice (int);
+
+static void interrupt_query (void);
+
+static int read_frame (char *);
+
+static int sds_insert_breakpoint (CORE_ADDR, char *);
+
+static int sds_remove_breakpoint (CORE_ADDR, char *);
+
+static void init_sds_ops (void);
+
+static void sds_command (char *args, int from_tty);
+
+/* Define the target operations vector. */
+
+static struct target_ops sds_ops;
+
+/* 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 sds_timeout = 2;
+
+/* Descriptor for I/O to remote machine. Initialize it to NULL so
+ that sds_open knows that we don't have a file open when the program
+ starts. */
+
+static struct serial *sds_desc = NULL;
+
+/* This limit comes from the monitor. */
+
+#define PBUFSIZ 250
+
+/* 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)
+
+static int next_msg_id;
+
+static int just_started;
+
+static int message_pending;
+
+
+/* Clean up connection to a remote debugger. */
+
+static void
+sds_close (int quitting)
+{
+ if (sds_desc)
+ serial_close (sds_desc);
+ sds_desc = NULL;
+}
+
+/* Stub for catch_errors. */
+
+static int
+sds_start_remote (void *dummy)
+{
+ int c;
+ unsigned char buf[200];
+
+ immediate_quit++; /* Allow user to interrupt it */
+
+ /* Ack any packet which the remote side has already sent. */
+ serial_write (sds_desc, "{#*\r\n", 5);
+ serial_write (sds_desc, "{#}\r\n", 5);
+
+ while ((c = readchar (1)) >= 0)
+ printf_unfiltered ("%c", c);
+ printf_unfiltered ("\n");
+
+ next_msg_id = 251;
+
+ buf[0] = 26;
+ sds_send (buf, 1);
+
+ buf[0] = 0;
+ sds_send (buf, 1);
+
+ immediate_quit--;
+
+ start_remote (); /* Initialize gdb process mechanisms */
+ return 1;
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static void
+sds_open (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 (&sds_ops);
+
+ sds_desc = serial_open (name);
+ if (!sds_desc)
+ perror_with_name (name);
+
+ if (baud_rate != -1)
+ {
+ if (serial_setbaudrate (sds_desc, baud_rate))
+ {
+ serial_close (sds_desc);
+ perror_with_name (name);
+ }
+ }
+
+
+ serial_raw (sds_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 (sds_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote debugging using ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+ push_target (&sds_ops); /* Switch to using remote target now */
+
+ just_started = 1;
+
+ /* 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 (sds_start_remote, NULL,
+ "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
+sds_detach (char *args, int from_tty)
+{
+ char buf[PBUFSIZ];
+
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+#if 0
+ /* Tell the remote target to detach. */
+ strcpy (buf, "D");
+ sds_send (buf, 1);
+#endif
+
+ pop_target ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (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);
+}
+
+static int
+tob64 (unsigned char *inbuf, char *outbuf, int len)
+{
+ int i, sum;
+ char *p;
+
+ if (len % 3 != 0)
+ error ("bad length");
+
+ p = outbuf;
+ for (i = 0; i < len; i += 3)
+ {
+ /* Collect the next three bytes into a number. */
+ sum = ((long) *inbuf++) << 16;
+ sum |= ((long) *inbuf++) << 8;
+ sum |= ((long) *inbuf++);
+
+ /* Spit out 4 6-bit encodings. */
+ *p++ = ((sum >> 18) & 0x3f) + '0';
+ *p++ = ((sum >> 12) & 0x3f) + '0';
+ *p++ = ((sum >> 6) & 0x3f) + '0';
+ *p++ = (sum & 0x3f) + '0';
+ }
+ return (p - outbuf);
+}
+
+static int
+fromb64 (char *inbuf, char *outbuf, int len)
+{
+ int i, sum;
+
+ if (len % 4 != 0)
+ error ("bad length");
+
+ for (i = 0; i < len; i += 4)
+ {
+ /* Collect 4 6-bit digits. */
+ sum = (*inbuf++ - '0') << 18;
+ sum |= (*inbuf++ - '0') << 12;
+ sum |= (*inbuf++ - '0') << 6;
+ sum |= (*inbuf++ - '0');
+
+ /* Now take the resulting 24-bit number and get three bytes out
+ of it. */
+ *outbuf++ = (sum >> 16) & 0xff;
+ *outbuf++ = (sum >> 8) & 0xff;
+ *outbuf++ = sum & 0xff;
+ }
+
+ return (len / 4) * 3;
+}
+
+
+/* Tell the remote machine to resume. */
+
+static enum target_signal last_sent_signal = TARGET_SIGNAL_0;
+int last_sent_step;
+
+static void
+sds_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ unsigned char buf[PBUFSIZ];
+
+ last_sent_signal = siggnal;
+ last_sent_step = step;
+
+ buf[0] = (step ? 21 : 20);
+ buf[1] = 0; /* (should be signal?) */
+
+ sds_send (buf, 2);
+}
+
+/* Send a message to target to halt it. Target will respond, and send
+ us a message pending notice. */
+
+static void
+sds_interrupt (int signo)
+{
+ unsigned char buf[PBUFSIZ];
+
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, sds_interrupt_twice);
+
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "sds_interrupt called\n");
+
+ buf[0] = 25;
+ sds_send (buf, 1);
+}
+
+static void (*ofunc) ();
+
+/* The user typed ^C twice. */
+
+static void
+sds_interrupt_twice (int signo)
+{
+ signal (signo, ofunc);
+
+ interrupt_query ();
+
+ signal (signo, sds_interrupt);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+interrupt_query (void)
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ throw_exception (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 ptid_t
+sds_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ unsigned char buf[PBUFSIZ];
+ int retlen;
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ ofunc = (void (*)()) signal (SIGINT, sds_interrupt);
+
+ signal (SIGINT, ofunc);
+
+ if (just_started)
+ {
+ just_started = 0;
+ status->kind = TARGET_WAITKIND_STOPPED;
+ return inferior_ptid;
+ }
+
+ while (1)
+ {
+ getmessage (buf, 1);
+
+ if (message_pending)
+ {
+ buf[0] = 26;
+ retlen = sds_send (buf, 1);
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Signals: %02x%02x %02x %02x\n",
+ buf[0], buf[1],
+ buf[2], buf[3]);
+ }
+ message_pending = 0;
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ goto got_status;
+ }
+ }
+got_status:
+ return inferior_ptid;
+}
+
+static unsigned char sprs[16];
+
+/* Read the remote registers into the block REGS. */
+/* Currently we just read all the registers, so we don't use regno. */
+
+static void
+sds_fetch_registers (int regno)
+{
+ unsigned char buf[PBUFSIZ];
+ int i, retlen;
+ char *regs = alloca (DEPRECATED_REGISTER_BYTES);
+
+ /* Unimplemented registers read as all bits zero. */
+ memset (regs, 0, DEPRECATED_REGISTER_BYTES);
+
+ buf[0] = 18;
+ buf[1] = 1;
+ buf[2] = 0;
+ retlen = sds_send (buf, 3);
+
+ for (i = 0; i < 4 * 6; ++i)
+ regs[i + 4 * 32 + 8 * 32] = buf[i];
+ for (i = 0; i < 4 * 4; ++i)
+ sprs[i] = buf[i + 4 * 7];
+
+ buf[0] = 18;
+ buf[1] = 2;
+ buf[2] = 0;
+ retlen = sds_send (buf, 3);
+
+ for (i = 0; i < retlen; i++)
+ regs[i] = buf[i];
+
+ /* (should warn about reply too short) */
+
+ for (i = 0; i < NUM_REGS; i++)
+ supply_register (i, &regs[DEPRECATED_REGISTER_BYTE (i)]);
+}
+
+/* Prepare to store registers. Since we may send them all, we have to
+ read out the ones we don't want to change first. */
+
+static void
+sds_prepare_to_store (void)
+{
+ /* Make sure the entire registers array is valid. */
+ deprecated_read_register_bytes (0, (char *) NULL, DEPRECATED_REGISTER_BYTES);
+}
+
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+ of REGISTERS. FIXME: ignores errors. */
+
+static void
+sds_store_registers (int regno)
+{
+ unsigned char *p, buf[PBUFSIZ];
+ int i;
+
+ /* Store all the special-purpose registers. */
+ p = buf;
+ *p++ = 19;
+ *p++ = 1;
+ *p++ = 0;
+ *p++ = 0;
+ for (i = 0; i < 4 * 6; i++)
+ *p++ = deprecated_registers[i + 4 * 32 + 8 * 32];
+ for (i = 0; i < 4 * 1; i++)
+ *p++ = 0;
+ for (i = 0; i < 4 * 4; i++)
+ *p++ = sprs[i];
+
+ sds_send (buf, p - buf);
+
+ /* Store all the general-purpose registers. */
+ p = buf;
+ *p++ = 19;
+ *p++ = 2;
+ *p++ = 0;
+ *p++ = 0;
+ for (i = 0; i < 4 * 32; i++)
+ *p++ = deprecated_registers[i];
+
+ sds_send (buf, p - buf);
+
+}
+
+/* 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
+sds_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen;
+ unsigned char buf[PBUFSIZ];
+ int todo;
+ int i;
+
+ /* Chop the transfer down if necessary */
+
+ max_buf_size = 150;
+
+ origlen = len;
+ while (len > 0)
+ {
+ todo = min (len, max_buf_size);
+
+ buf[0] = 13;
+ buf[1] = 0;
+ buf[2] = (int) (memaddr >> 24) & 0xff;
+ buf[3] = (int) (memaddr >> 16) & 0xff;
+ buf[4] = (int) (memaddr >> 8) & 0xff;
+ buf[5] = (int) (memaddr) & 0xff;
+ buf[6] = 1;
+ buf[7] = 0;
+
+ for (i = 0; i < todo; i++)
+ buf[i + 8] = myaddr[i];
+
+ sds_send (buf, 8 + todo);
+
+ /* (should look at result) */
+
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
+ }
+ return origlen;
+}
+
+/* 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
+sds_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen, retlen;
+ unsigned char buf[PBUFSIZ];
+ int todo;
+ int i;
+
+ /* Chop the transfer down if necessary */
+
+ max_buf_size = 150;
+
+ origlen = len;
+ while (len > 0)
+ {
+ todo = min (len, max_buf_size);
+
+ buf[0] = 12;
+ buf[1] = 0;
+ buf[2] = (int) (memaddr >> 24) & 0xff;
+ buf[3] = (int) (memaddr >> 16) & 0xff;
+ buf[4] = (int) (memaddr >> 8) & 0xff;
+ buf[5] = (int) (memaddr) & 0xff;
+ buf[6] = (int) (todo >> 8) & 0xff;
+ buf[7] = (int) (todo) & 0xff;
+ buf[8] = 1;
+
+ retlen = sds_send (buf, 9);
+
+ if (retlen - 2 != todo)
+ {
+ return 0;
+ }
+
+ /* Reply describes memory byte by byte. */
+
+ for (i = 0; i < todo; i++)
+ myaddr[i] = buf[i + 2];
+
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
+ }
+
+ return origlen;
+}
+
+/* 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. TARGET is unused. */
+
+static int
+sds_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int should_write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int res;
+
+ if (should_write)
+ res = sds_write_bytes (memaddr, myaddr, len);
+ else
+ res = sds_read_bytes (memaddr, myaddr, len);
+
+ return res;
+}
+
+
+static void
+sds_files_info (struct target_ops *ignore)
+{
+ puts_filtered ("Debugging over a serial connection, using SDS protocol.\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 (int timeout)
+{
+ int ch;
+
+ ch = serial_readchar (sds_desc, timeout);
+
+ if (remote_debug > 1 && ch >= 0)
+ fprintf_unfiltered (gdb_stdlog, "%c(%x)", ch, ch);
+
+ 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;
+ }
+}
+
+/* An SDS-style checksum is a sum of the bytes modulo 253. (Presumably
+ because 253, 254, and 255 are special flags in the protocol.) */
+
+static int
+compute_checksum (int csum, char *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; ++i)
+ csum += (unsigned char) buf[i];
+
+ csum %= 253;
+ return csum;
+}
+
+/* Send the command in BUF to the remote machine, and read the reply
+ into BUF also. */
+
+static int
+sds_send (unsigned char *buf, int len)
+{
+ putmessage (buf, len);
+
+ return getmessage (buf, 0);
+}
+
+/* Send a message to the remote machine. */
+
+static int
+putmessage (unsigned char *buf, int len)
+{
+ int i, enclen;
+ unsigned char csum = 0;
+ char buf2[PBUFSIZ], buf3[PBUFSIZ];
+ unsigned char header[3];
+ char *p;
+
+ /* Copy the packet into buffer BUF2, encapsulating it
+ and giving it a checksum. */
+
+ if (len > 170) /* Prosanity check */
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Message to send: \"");
+ for (i = 0; i < len; ++i)
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ fprintf_unfiltered (gdb_stdlog, "\"\n");
+ }
+
+ p = buf2;
+ *p++ = '$';
+
+ if (len % 3 != 0)
+ {
+ buf[len] = '\0';
+ buf[len + 1] = '\0';
+ }
+
+ header[1] = next_msg_id;
+
+ header[2] = len;
+
+ csum = compute_checksum (csum, buf, len);
+ csum = compute_checksum (csum, header + 1, 2);
+
+ header[0] = csum;
+
+ tob64 (header, p, 3);
+ p += 4;
+ enclen = tob64 (buf, buf3, ((len + 2) / 3) * 3);
+
+ for (i = 0; i < enclen; ++i)
+ *p++ = buf3[i];
+ *p++ = '\r';
+ *p++ = '\n';
+
+ next_msg_id = (next_msg_id + 3) % 245;
+
+ /* Send it over and over until we get a positive ack. */
+
+ while (1)
+ {
+ if (remote_debug)
+ {
+ *p = '\0';
+ fprintf_unfiltered (gdb_stdlog, "Sending encoded: \"%s\"", buf2);
+ fprintf_unfiltered (gdb_stdlog,
+ " (Checksum %d, id %d, length %d)\n",
+ header[0], header[1], header[2]);
+ gdb_flush (gdb_stdlog);
+ }
+ if (serial_write (sds_desc, buf2, p - buf2))
+ perror_with_name ("putmessage: write failed");
+
+ return 1;
+ }
+}
+
+/* Come here after finding the start of the frame. Collect the rest
+ into BUF. Returns 0 on any error, 1 on success. */
+
+static int
+read_frame (char *buf)
+{
+ char *bp;
+ int c;
+
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar (sds_timeout);
+
+ switch (c)
+ {
+ case SERIAL_TIMEOUT:
+ if (remote_debug)
+ fputs_filtered ("Timeout in mid-message, retrying\n", gdb_stdlog);
+ return 0;
+ case '$':
+ if (remote_debug)
+ fputs_filtered ("Saw new packet start in middle of old one\n",
+ gdb_stdlog);
+ return 0; /* Start a new packet, count retries */
+ case '\r':
+ break;
+
+ case '\n':
+ {
+ *bp = '\000';
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Received encoded: \"%s\"\n",
+ buf);
+ return 1;
+ }
+
+ default:
+ if (bp < buf + PBUFSIZ - 1)
+ {
+ *bp++ = c;
+ continue;
+ }
+
+ *bp = '\0';
+ puts_filtered ("Message 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 int
+getmessage (unsigned char *buf, int forever)
+{
+ int c, c2, c3;
+ int tries;
+ int timeout;
+ int val, i, len, csum;
+ unsigned char header[3];
+ unsigned char inbuf[500];
+
+ strcpy (buf, "timeout");
+
+ if (forever)
+ {
+ timeout = watchdog > 0 ? watchdog : -1;
+ }
+
+ else
+ timeout = sds_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 sds_timeout intervals. */
+
+ do
+ {
+ c = readchar (timeout);
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (forever) /* Watchdog went off. Kill the target. */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+ if (remote_debug)
+ fputs_filtered ("Timed out.\n", gdb_stdlog);
+ goto retry;
+ }
+ }
+ while (c != '$' && c != '{');
+
+ /* We might have seen a "trigraph", a sequence of three characters
+ that indicate various sorts of communication state. */
+
+ if (c == '{')
+ {
+ /* Read the other two chars of the trigraph. */
+ c2 = readchar (timeout);
+ c3 = readchar (timeout);
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Trigraph %c%c%c received\n",
+ c, c2, c3);
+ if (c3 == '+')
+ {
+ message_pending = 1;
+ return 0; /*???? */
+ }
+ continue;
+ }
+
+ val = read_frame (inbuf);
+
+ if (val == 1)
+ {
+ fromb64 (inbuf, header, 4);
+ /* (should check out other bits) */
+ fromb64 (inbuf + 4, buf, strlen (inbuf) - 4);
+
+ len = header[2];
+
+ csum = 0;
+ csum = compute_checksum (csum, buf, len);
+ csum = compute_checksum (csum, header + 1, 2);
+
+ if (csum != header[0])
+ fprintf_unfiltered (gdb_stderr,
+ "Checksum mismatch: computed %d, received %d\n",
+ csum, header[0]);
+
+ if (header[2] == 0xff)
+ fprintf_unfiltered (gdb_stderr, "Requesting resend...\n");
+
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "... (Got checksum %d, id %d, length %d)\n",
+ header[0], header[1], header[2]);
+ fprintf_unfiltered (gdb_stdlog, "Message received: \"");
+ for (i = 0; i < len; ++i)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x", (unsigned char) buf[i]);
+ }
+ fprintf_unfiltered (gdb_stdlog, "\"\n");
+ }
+
+ /* no ack required? */
+ return len;
+ }
+
+ /* Try the whole thing again. */
+ retry:
+ /* need to do something here */
+ ;
+ }
+
+ /* We have tried hard enough, and just can't receive the packet. Give up. */
+
+ printf_unfiltered ("Ignoring packet error, continuing...\n");
+ return 0;
+}
+
+static void
+sds_kill (void)
+{
+ /* Don't try to do anything to the target. */
+}
+
+static void
+sds_mourn (void)
+{
+ unpush_target (&sds_ops);
+ generic_mourn_inferior ();
+}
+
+static void
+sds_create_inferior (char *exec_file, char *args, char **env)
+{
+ inferior_ptid = pid_to_ptid (42000);
+
+ /* Clean up from the last time we were running. */
+ clear_proceed_status ();
+
+ /* Let the remote process run. */
+ proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
+}
+
+static void
+sds_load (char *filename, int from_tty)
+{
+ generic_load (filename, from_tty);
+
+ inferior_ptid = null_ptid;
+}
+
+/* The SDS monitor has commands for breakpoint insertion, although it
+ it doesn't actually manage the breakpoints, it just returns the
+ replaced instruction back to the debugger. */
+
+static int
+sds_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ int i, retlen;
+ unsigned char *p, buf[PBUFSIZ];
+
+ p = buf;
+ *p++ = 16;
+ *p++ = 0;
+ *p++ = (int) (addr >> 24) & 0xff;
+ *p++ = (int) (addr >> 16) & 0xff;
+ *p++ = (int) (addr >> 8) & 0xff;
+ *p++ = (int) (addr) & 0xff;
+
+ retlen = sds_send (buf, p - buf);
+
+ for (i = 0; i < 4; ++i)
+ contents_cache[i] = buf[i + 2];
+
+ return 0;
+}
+
+static int
+sds_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ int i, retlen;
+ unsigned char *p, buf[PBUFSIZ];
+
+ p = buf;
+ *p++ = 17;
+ *p++ = 0;
+ *p++ = (int) (addr >> 24) & 0xff;
+ *p++ = (int) (addr >> 16) & 0xff;
+ *p++ = (int) (addr >> 8) & 0xff;
+ *p++ = (int) (addr) & 0xff;
+ for (i = 0; i < 4; ++i)
+ *p++ = contents_cache[i];
+
+ retlen = sds_send (buf, p - buf);
+
+ return 0;
+}
+
+static void
+init_sds_ops (void)
+{
+ sds_ops.to_shortname = "sds";
+ sds_ops.to_longname = "Remote serial target with SDS protocol";
+ sds_ops.to_doc = "Use a remote computer via a serial line; using the SDS protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ sds_ops.to_open = sds_open;
+ sds_ops.to_close = sds_close;
+ sds_ops.to_detach = sds_detach;
+ sds_ops.to_resume = sds_resume;
+ sds_ops.to_wait = sds_wait;
+ sds_ops.to_fetch_registers = sds_fetch_registers;
+ sds_ops.to_store_registers = sds_store_registers;
+ sds_ops.to_prepare_to_store = sds_prepare_to_store;
+ sds_ops.to_xfer_memory = sds_xfer_memory;
+ sds_ops.to_files_info = sds_files_info;
+ sds_ops.to_insert_breakpoint = sds_insert_breakpoint;
+ sds_ops.to_remove_breakpoint = sds_remove_breakpoint;
+ sds_ops.to_kill = sds_kill;
+ sds_ops.to_load = sds_load;
+ sds_ops.to_create_inferior = sds_create_inferior;
+ sds_ops.to_mourn_inferior = sds_mourn;
+ sds_ops.to_stratum = process_stratum;
+ sds_ops.to_has_all_memory = 1;
+ sds_ops.to_has_memory = 1;
+ sds_ops.to_has_stack = 1;
+ sds_ops.to_has_registers = 1;
+ sds_ops.to_has_execution = 1;
+ sds_ops.to_magic = OPS_MAGIC;
+}
+
+/* Put a command string, in args, out to the monitor and display the
+ reply message. */
+
+static void
+sds_command (char *args, int from_tty)
+{
+ char *p;
+ int i, len, retlen;
+ unsigned char buf[1000];
+
+ /* Convert hexadecimal chars into a byte buffer. */
+ p = args;
+ len = 0;
+ while (*p != '\0')
+ {
+ buf[len++] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ if (p[1] == '\0')
+ break;
+ p += 2;
+ }
+
+ retlen = sds_send (buf, len);
+
+ printf_filtered ("Reply is ");
+ for (i = 0; i < retlen; ++i)
+ {
+ printf_filtered ("%02x", buf[i]);
+ }
+ printf_filtered ("\n");
+}
+
+void
+_initialize_remote_sds (void)
+{
+ init_sds_ops ();
+ add_target (&sds_ops);
+
+ add_show_from_set (add_set_cmd ("sdstimeout", no_class,
+ var_integer, (char *) &sds_timeout,
+ "Set timeout value for sds read.\n", &setlist),
+ &showlist);
+
+ add_com ("sds", class_obscure, sds_command,
+ "Send a command to the SDS monitor.");
+}
diff --git a/contrib/gdb/gdb/remote-sim.c b/contrib/gdb/gdb/remote-sim.c
new file mode 100644
index 0000000..9b0b3fd
--- /dev/null
+++ b/contrib/gdb/gdb/remote-sim.c
@@ -0,0 +1,900 @@
+/* Generic remote debugging interface for simulators.
+
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2004 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 "value.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <errno.h>
+#include "terminal.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "gdb/callback.h"
+#include "gdb/remote-sim.h"
+#include "remote-utils.h"
+#include "command.h"
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "sim-regno.h"
+#include "arch-utils.h"
+
+/* Prototypes */
+
+extern void _initialize_remote_sim (void);
+
+extern int (*ui_loop_hook) (int signo);
+
+static void dump_mem (char *buf, int len);
+
+static void init_callbacks (void);
+
+static void end_callbacks (void);
+
+static int gdb_os_write_stdout (host_callback *, const char *, int);
+
+static void gdb_os_flush_stdout (host_callback *);
+
+static int gdb_os_write_stderr (host_callback *, const char *, int);
+
+static void gdb_os_flush_stderr (host_callback *);
+
+static int gdb_os_poll_quit (host_callback *);
+
+/* printf_filtered is depreciated */
+static void gdb_os_printf_filtered (host_callback *, const char *, ...);
+
+static void gdb_os_vprintf_filtered (host_callback *, const char *, va_list);
+
+static void gdb_os_evprintf_filtered (host_callback *, const char *, va_list);
+
+static void gdb_os_error (host_callback *, const char *, ...);
+
+static void gdbsim_fetch_register (int regno);
+
+static void gdbsim_store_register (int regno);
+
+static void gdbsim_kill (void);
+
+static void gdbsim_load (char *prog, int fromtty);
+
+static void gdbsim_create_inferior (char *exec_file, char *args, char **env);
+
+static void gdbsim_open (char *args, int from_tty);
+
+static void gdbsim_close (int quitting);
+
+static void gdbsim_detach (char *args, int from_tty);
+
+static void gdbsim_resume (ptid_t ptid, int step, enum target_signal siggnal);
+
+static ptid_t gdbsim_wait (ptid_t ptid, struct target_waitstatus *status);
+
+static void gdbsim_prepare_to_store (void);
+
+static int gdbsim_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr,
+ int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+
+static void gdbsim_files_info (struct target_ops *target);
+
+static void gdbsim_mourn_inferior (void);
+
+static void gdbsim_stop (void);
+
+void simulator_command (char *args, int from_tty);
+
+/* Naming convention:
+
+ sim_* are the interface to the simulator (see remote-sim.h).
+ gdbsim_* are stuff which is internal to gdb. */
+
+/* Forward data declarations */
+extern struct target_ops gdbsim_ops;
+
+static int program_loaded = 0;
+
+/* We must keep track of whether the simulator has been opened or not because
+ GDB can call a target's close routine twice, but sim_close doesn't allow
+ this. We also need to record the result of sim_open so we can pass it
+ back to the other sim_foo routines. */
+static SIM_DESC gdbsim_desc = 0;
+
+static void
+dump_mem (char *buf, int len)
+{
+ if (len <= 8)
+ {
+ if (len == 8 || len == 4)
+ {
+ long l[2];
+ memcpy (l, buf, len);
+ printf_filtered ("\t0x%lx", l[0]);
+ if (len == 8)
+ printf_filtered (" 0x%lx", l[1]);
+ printf_filtered ("\n");
+ }
+ else
+ {
+ int i;
+ printf_filtered ("\t");
+ for (i = 0; i < len; i++)
+ printf_filtered ("0x%x ", buf[i]);
+ printf_filtered ("\n");
+ }
+ }
+}
+
+static host_callback gdb_callback;
+static int callbacks_initialized = 0;
+
+/* Initialize gdb_callback. */
+
+static void
+init_callbacks (void)
+{
+ if (!callbacks_initialized)
+ {
+ gdb_callback = default_callback;
+ gdb_callback.init (&gdb_callback);
+ gdb_callback.write_stdout = gdb_os_write_stdout;
+ gdb_callback.flush_stdout = gdb_os_flush_stdout;
+ gdb_callback.write_stderr = gdb_os_write_stderr;
+ gdb_callback.flush_stderr = gdb_os_flush_stderr;
+ gdb_callback.printf_filtered = gdb_os_printf_filtered;
+ gdb_callback.vprintf_filtered = gdb_os_vprintf_filtered;
+ gdb_callback.evprintf_filtered = gdb_os_evprintf_filtered;
+ gdb_callback.error = gdb_os_error;
+ gdb_callback.poll_quit = gdb_os_poll_quit;
+ gdb_callback.magic = HOST_CALLBACK_MAGIC;
+ callbacks_initialized = 1;
+ }
+}
+
+/* Release callbacks (free resources used by them). */
+
+static void
+end_callbacks (void)
+{
+ if (callbacks_initialized)
+ {
+ gdb_callback.shutdown (&gdb_callback);
+ callbacks_initialized = 0;
+ }
+}
+
+/* GDB version of os_write_stdout callback. */
+
+static int
+gdb_os_write_stdout (host_callback *p, const char *buf, int len)
+{
+ int i;
+ char b[2];
+
+ ui_file_write (gdb_stdtarg, buf, len);
+ return len;
+}
+
+/* GDB version of os_flush_stdout callback. */
+
+static void
+gdb_os_flush_stdout (host_callback *p)
+{
+ gdb_flush (gdb_stdtarg);
+}
+
+/* GDB version of os_write_stderr callback. */
+
+static int
+gdb_os_write_stderr (host_callback *p, const char *buf, int len)
+{
+ int i;
+ char b[2];
+
+ for (i = 0; i < len; i++)
+ {
+ b[0] = buf[i];
+ b[1] = 0;
+ fputs_unfiltered (b, gdb_stdtargerr);
+ }
+ return len;
+}
+
+/* GDB version of os_flush_stderr callback. */
+
+static void
+gdb_os_flush_stderr (host_callback *p)
+{
+ gdb_flush (gdb_stdtargerr);
+}
+
+/* GDB version of printf_filtered callback. */
+
+static void
+gdb_os_printf_filtered (host_callback * p, const char *format,...)
+{
+ va_list args;
+ va_start (args, format);
+
+ vfprintf_filtered (gdb_stdout, format, args);
+
+ va_end (args);
+}
+
+/* GDB version of error vprintf_filtered. */
+
+static void
+gdb_os_vprintf_filtered (host_callback * p, const char *format, va_list ap)
+{
+ vfprintf_filtered (gdb_stdout, format, ap);
+}
+
+/* GDB version of error evprintf_filtered. */
+
+static void
+gdb_os_evprintf_filtered (host_callback * p, const char *format, va_list ap)
+{
+ vfprintf_filtered (gdb_stderr, format, ap);
+}
+
+/* GDB version of error callback. */
+
+static void
+gdb_os_error (host_callback * p, const char *format,...)
+{
+ if (error_hook)
+ (*error_hook) ();
+ else
+ {
+ va_list args;
+ va_start (args, format);
+ verror (format, args);
+ va_end (args);
+ }
+}
+
+int
+one2one_register_sim_regno (int regnum)
+{
+ /* Only makes sense to supply raw registers. */
+ gdb_assert (regnum >= 0 && regnum < NUM_REGS);
+ return regnum;
+}
+
+static void
+gdbsim_fetch_register (int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ gdbsim_fetch_register (regno);
+ return;
+ }
+
+ switch (REGISTER_SIM_REGNO (regno))
+ {
+ case LEGACY_SIM_REGNO_IGNORE:
+ break;
+ case SIM_REGNO_DOES_NOT_EXIST:
+ {
+ /* For moment treat a `does not exist' register the same way
+ as an ``unavailable'' register. */
+ char buf[MAX_REGISTER_SIZE];
+ int nr_bytes;
+ memset (buf, 0, MAX_REGISTER_SIZE);
+ supply_register (regno, buf);
+ set_register_cached (regno, -1);
+ break;
+ }
+ default:
+ {
+ static int warn_user = 1;
+ char buf[MAX_REGISTER_SIZE];
+ int nr_bytes;
+ gdb_assert (regno >= 0 && regno < NUM_REGS);
+ memset (buf, 0, MAX_REGISTER_SIZE);
+ nr_bytes = sim_fetch_register (gdbsim_desc,
+ REGISTER_SIM_REGNO (regno),
+ buf, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ if (nr_bytes > 0 && nr_bytes != DEPRECATED_REGISTER_RAW_SIZE (regno) && warn_user)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "Size of register %s (%d/%d) incorrect (%d instead of %d))",
+ REGISTER_NAME (regno),
+ regno, REGISTER_SIM_REGNO (regno),
+ nr_bytes, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ warn_user = 0;
+ }
+ /* FIXME: cagney/2002-05-27: Should check `nr_bytes == 0'
+ indicating that GDB and the SIM have different ideas about
+ which registers are fetchable. */
+ /* Else if (nr_bytes < 0): an old simulator, that doesn't
+ think to return the register size. Just assume all is ok. */
+ 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, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ }
+ break;
+ }
+ }
+}
+
+
+static void
+gdbsim_store_register (int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ gdbsim_store_register (regno);
+ return;
+ }
+ else if (REGISTER_SIM_REGNO (regno) >= 0)
+ {
+ char tmp[MAX_REGISTER_SIZE];
+ int nr_bytes;
+ deprecated_read_register_gen (regno, tmp);
+ nr_bytes = sim_store_register (gdbsim_desc,
+ REGISTER_SIM_REGNO (regno),
+ tmp, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ if (nr_bytes > 0 && nr_bytes != DEPRECATED_REGISTER_RAW_SIZE (regno))
+ internal_error (__FILE__, __LINE__,
+ "Register size different to expected");
+ /* FIXME: cagney/2002-05-27: Should check `nr_bytes == 0'
+ indicating that GDB and the SIM have different ideas about
+ which registers are fetchable. */
+ if (sr_get_debug ())
+ {
+ printf_filtered ("gdbsim_store_register: %d", regno);
+ /* FIXME: We could print something more intelligible. */
+ dump_mem (tmp, DEPRECATED_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 (void)
+{
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_kill\n");
+
+ /* There is no need to `kill' running simulator - the simulator is
+ not running */
+ inferior_ptid = null_ptid;
+}
+
+/* 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 (char *prog, int fromtty)
+{
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_load: prog \"%s\"\n", prog);
+
+ inferior_ptid = null_ptid;
+
+ /* FIXME: We will print two messages on error.
+ Need error to either not print anything if passed NULL or need
+ another routine that doesn't take any arguments. */
+ if (sim_load (gdbsim_desc, prog, NULL, fromtty) == SIM_RC_FAIL)
+ error ("unable to load program");
+
+ /* FIXME: If a load command should reset the targets registers then
+ a call to sim_create_inferior() should go here. */
+
+ program_loaded = 1;
+}
+
+
+/* Start an inferior process and set inferior_ptid to its pid.
+ EXEC_FILE is the file to run.
+ ARGS 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 (char *exec_file, char *args, char **env)
+{
+ int len;
+ char *arg_buf, **argv;
+
+ if (exec_file == 0 || exec_bfd == 0)
+ warning ("No executable file specified.");
+ if (!program_loaded)
+ warning ("No program loaded.");
+
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_create_inferior: exec_file \"%s\", args \"%s\"\n",
+ (exec_file ? exec_file : "(NULL)"),
+ args);
+
+ gdbsim_kill ();
+ remove_breakpoints ();
+ init_wait_for_inferior ();
+
+ if (exec_file != NULL)
+ {
+ len = 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 (argv);
+ }
+ else
+ argv = NULL;
+ sim_create_inferior (gdbsim_desc, exec_bfd, argv, env);
+
+ inferior_ptid = pid_to_ptid (42);
+ insert_breakpoints (); /* Needed to get correct instruction in cache */
+
+ clear_proceed_status ();
+
+ /* NB: Entry point already set by sim_create_inferior. */
+ proceed ((CORE_ADDR) -1, 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 (char *args, int from_tty)
+{
+ int len;
+ char *arg_buf;
+ char **argv;
+
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_open: args \"%s\"\n", args ? args : "(null)");
+
+ /* Remove current simulator if one exists. Only do this if the simulator
+ has been opened because sim_close requires it.
+ This is important because the call to push_target below will cause
+ sim_close to be called if the simulator is already open, but push_target
+ is called after sim_open! We can't move the call to push_target before
+ the call to sim_open because sim_open may invoke `error'. */
+ if (gdbsim_desc != NULL)
+ unpush_target (&gdbsim_ops);
+
+ len = (7 + 1 /* gdbsim */
+ + strlen (" -E little")
+ + strlen (" --architecture=xxxxxxxxxx")
+ + (args ? strlen (args) : 0)
+ + 50) /* slack */ ;
+ arg_buf = (char *) alloca (len);
+ strcpy (arg_buf, "gdbsim"); /* 7 */
+ /* Specify the byte order for the target when it is both selectable
+ and explicitly specified by the user (not auto detected). */
+ switch (selected_byte_order ())
+ {
+ case BFD_ENDIAN_BIG:
+ strcat (arg_buf, " -E big");
+ break;
+ case BFD_ENDIAN_LITTLE:
+ strcat (arg_buf, " -E little");
+ break;
+ case BFD_ENDIAN_UNKNOWN:
+ break;
+ }
+ /* Specify the architecture of the target when it has been
+ explicitly specified */
+ if (selected_architecture_name () != NULL)
+ {
+ strcat (arg_buf, " --architecture=");
+ strcat (arg_buf, selected_architecture_name ());
+ }
+ /* finally, any explicit args */
+ if (args)
+ {
+ strcat (arg_buf, " "); /* 1 */
+ strcat (arg_buf, args);
+ }
+ argv = buildargv (arg_buf);
+ if (argv == NULL)
+ error ("Insufficient memory available to allocate simulator arg list.");
+ make_cleanup_freeargv (argv);
+
+ init_callbacks ();
+ gdbsim_desc = sim_open (SIM_OPEN_DEBUG, &gdb_callback, exec_bfd, argv);
+
+ if (gdbsim_desc == 0)
+ error ("unable to create simulator instance");
+
+ 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 (int quitting)
+{
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_close: quitting %d\n", quitting);
+
+ program_loaded = 0;
+
+ if (gdbsim_desc != NULL)
+ {
+ sim_close (gdbsim_desc, quitting);
+ gdbsim_desc = NULL;
+ }
+
+ end_callbacks ();
+ generic_mourn_inferior ();
+}
+
+/* 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 (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 enum target_signal resume_siggnal;
+static int resume_step;
+
+static void
+gdbsim_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ if (PIDGET (inferior_ptid) != 42)
+ error ("The program is not being run.");
+
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_resume: step %d, signal %d\n", step, siggnal);
+
+ resume_siggnal = siggnal;
+ resume_step = step;
+}
+
+/* Notify the simulator of an asynchronous request to stop.
+
+ The simulator shall ensure that the stop request is eventually
+ delivered to the simulator. If the call is made while the
+ simulator is not running then the stop request is processed when
+ the simulator is next resumed.
+
+ For simulators that do not support this operation, just abort */
+
+static void
+gdbsim_stop (void)
+{
+ if (!sim_stop (gdbsim_desc))
+ {
+ quit ();
+ }
+}
+
+/* GDB version of os_poll_quit callback.
+ Taken from gdb/util.c - should be in a library */
+
+static int
+gdb_os_poll_quit (host_callback *p)
+{
+ if (ui_loop_hook != NULL)
+ ui_loop_hook (0);
+
+ if (quit_flag) /* gdb's idea of quit */
+ {
+ quit_flag = 0; /* we've stolen it */
+ return 1;
+ }
+ else if (immediate_quit)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/* 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 void
+gdbsim_cntrl_c (int signo)
+{
+ gdbsim_stop ();
+}
+
+static ptid_t
+gdbsim_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ static RETSIGTYPE (*prev_sigint) ();
+ int sigrc = 0;
+ enum sim_stop reason = sim_running;
+
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_wait\n");
+
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+ {
+ struct sigaction sa, osa;
+ sa.sa_handler = gdbsim_cntrl_c;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction (SIGINT, &sa, &osa);
+ prev_sigint = osa.sa_handler;
+ }
+#else
+ prev_sigint = signal (SIGINT, gdbsim_cntrl_c);
+#endif
+ sim_resume (gdbsim_desc, resume_step,
+ target_signal_to_host (resume_siggnal));
+ signal (SIGINT, prev_sigint);
+ resume_step = 0;
+
+ sim_stop_reason (gdbsim_desc, &reason, &sigrc);
+
+ switch (reason)
+ {
+ case sim_exited:
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = sigrc;
+ break;
+ case sim_stopped:
+ switch (sigrc)
+ {
+ case SIGABRT:
+ quit ();
+ break;
+ case SIGINT:
+ case SIGTRAP:
+ default:
+ 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;
+ }
+ 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;
+ case sim_running:
+ case sim_polling:
+ /* FIXME: Is this correct? */
+ break;
+ }
+
+ return inferior_ptid;
+}
+
+/* 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 (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+/* Transfer LEN bytes between GDB address MYADDR and target address
+ MEMADDR. If WRITE is non-zero, transfer them to the target,
+ otherwise transfer them from the target. TARGET is unused.
+
+ Returns the number of bytes transferred. */
+
+static int
+gdbsim_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ if (!program_loaded)
+ error ("No program loaded.");
+
+ if (sr_get_debug ())
+ {
+ /* FIXME: Send to something other than STDOUT? */
+ printf_filtered ("gdbsim_xfer_inferior_memory: myaddr 0x");
+ gdb_print_host_address (myaddr, gdb_stdout);
+ printf_filtered (", memaddr 0x%s, len %d, write %d\n",
+ paddr_nz (memaddr), len, write);
+ if (sr_get_debug () && write)
+ dump_mem (myaddr, len);
+ }
+
+ if (write)
+ {
+ len = sim_write (gdbsim_desc, memaddr, myaddr, len);
+ }
+ else
+ {
+ len = sim_read (gdbsim_desc, memaddr, myaddr, len);
+ if (sr_get_debug () && len > 0)
+ dump_mem (myaddr, len);
+ }
+ return len;
+}
+
+static void
+gdbsim_files_info (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 (gdbsim_desc, 0);
+ }
+}
+
+/* Clear the simulator's notion of what the break points are. */
+
+static void
+gdbsim_mourn_inferior (void)
+{
+ if (sr_get_debug ())
+ printf_filtered ("gdbsim_mourn_inferior:\n");
+
+ remove_breakpoints ();
+ generic_mourn_inferior ();
+}
+
+static int
+gdbsim_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return memory_insert_breakpoint (addr, contents_cache);
+}
+
+static int
+gdbsim_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return memory_remove_breakpoint (addr, contents_cache);
+}
+
+/* Pass the command argument through to the simulator verbatim. The
+ simulator must do any command interpretation work. */
+
+void
+simulator_command (char *args, int from_tty)
+{
+ if (gdbsim_desc == NULL)
+ {
+
+ /* PREVIOUSLY: The user may give a command before the simulator
+ is opened. [...] (??? assuming of course one wishes to
+ continue to allow commands to be sent to unopened simulators,
+ which isn't entirely unreasonable). */
+
+ /* The simulator is a builtin abstraction of a remote target.
+ Consistent with that model, access to the simulator, via sim
+ commands, is restricted to the period when the channel to the
+ simulator is open. */
+
+ error ("Not connected to the simulator target");
+ }
+
+ sim_do_command (gdbsim_desc, args);
+
+ /* Invalidate the register cache, in case the simulator command does
+ something funny. */
+ registers_changed ();
+}
+
+/* Define the target subroutine names */
+
+struct target_ops gdbsim_ops;
+
+static void
+init_gdbsim_ops (void)
+{
+ gdbsim_ops.to_shortname = "sim";
+ gdbsim_ops.to_longname = "simulator";
+ gdbsim_ops.to_doc = "Use the compiled-in simulator.";
+ gdbsim_ops.to_open = gdbsim_open;
+ gdbsim_ops.to_close = gdbsim_close;
+ gdbsim_ops.to_detach = gdbsim_detach;
+ gdbsim_ops.to_resume = gdbsim_resume;
+ gdbsim_ops.to_wait = gdbsim_wait;
+ gdbsim_ops.to_fetch_registers = gdbsim_fetch_register;
+ gdbsim_ops.to_store_registers = gdbsim_store_register;
+ gdbsim_ops.to_prepare_to_store = gdbsim_prepare_to_store;
+ gdbsim_ops.to_xfer_memory = gdbsim_xfer_inferior_memory;
+ gdbsim_ops.to_files_info = gdbsim_files_info;
+ gdbsim_ops.to_insert_breakpoint = gdbsim_insert_breakpoint;
+ gdbsim_ops.to_remove_breakpoint = gdbsim_remove_breakpoint;
+ gdbsim_ops.to_kill = gdbsim_kill;
+ gdbsim_ops.to_load = gdbsim_load;
+ gdbsim_ops.to_create_inferior = gdbsim_create_inferior;
+ gdbsim_ops.to_mourn_inferior = gdbsim_mourn_inferior;
+ gdbsim_ops.to_stop = gdbsim_stop;
+ gdbsim_ops.to_stratum = process_stratum;
+ gdbsim_ops.to_has_all_memory = 1;
+ gdbsim_ops.to_has_memory = 1;
+ gdbsim_ops.to_has_stack = 1;
+ gdbsim_ops.to_has_registers = 1;
+ gdbsim_ops.to_has_execution = 1;
+ gdbsim_ops.to_magic = OPS_MAGIC;
+
+#ifdef TARGET_REDEFINE_DEFAULT_OPS
+ TARGET_REDEFINE_DEFAULT_OPS (&gdbsim_ops);
+#endif
+}
+
+void
+_initialize_remote_sim (void)
+{
+ init_gdbsim_ops ();
+ add_target (&gdbsim_ops);
+
+ add_com ("sim <command>", class_obscure, simulator_command,
+ "Send a command to the simulator.");
+}
diff --git a/contrib/gdb/gdb/remote-st.c b/contrib/gdb/gdb/remote-st.c
new file mode 100644
index 0000000..ce4c7ab
--- /dev/null
+++ b/contrib/gdb/gdb/remote-st.c
@@ -0,0 +1,803 @@
+/* Remote debugging interface for Tandem ST2000 phone switch, for GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000,
+ 2001, 2002 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 "gdb_string.h"
+#include <sys/types.h>
+#include "serial.h"
+#include "regcache.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 struct serial *st2000_desc;
+
+/* Send data to stdebug. Works just like printf. */
+
+static void
+printf_stdebug (char *pattern,...)
+{
+ va_list args;
+ char buf[200];
+
+ va_start (args, pattern);
+
+ vsprintf (buf, pattern, args);
+ va_end (args);
+
+ if (serial_write (st2000_desc, buf, strlen (buf)))
+ fprintf_unfiltered (gdb_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 (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 (char *string, int discard)
+{
+ char *p = string;
+ int c;
+
+ immediate_quit++;
+ while (1)
+ {
+ c = readchar (timeout);
+ if (c == *p++)
+ {
+ if (*p == '\0')
+ {
+ immediate_quit--;
+ 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 (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 (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 (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 (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 (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 executable 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 (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 <device> <speed>\n\
+or target st2000 <host> <port>\n");
+
+ st2000_close (0);
+
+ st2000_desc = serial_open (dev_name);
+
+ if (!st2000_desc)
+ perror_with_name (dev_name);
+
+ if (serial_setbaudrate (st2000_desc, baudrate))
+ {
+ serial_close (dev_name);
+ perror_with_name (dev_name);
+ }
+
+ 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 (int quitting)
+{
+ serial_close (st2000_desc);
+
+#if defined (LOG_FILE)
+ if (log_file)
+ {
+ if (ferror (log_file))
+ fprintf_unfiltered (gdb_stderr, "Error writing log file.\n");
+ if (fclose (log_file) != 0)
+ fprintf_unfiltered (gdb_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 (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 (ptid_t ptid, int 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 ptid_t
+st2000_wait (ptid_t ptid, 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 inferior_ptid;
+}
+
+/* Return the name of register number REGNO in the form input and
+ output by STDEBUG. Currently, REGISTER_NAME just happens return
+ exactly what STDEBUG wants. Lets take advantage of that just as
+ long as possible! */
+
+static char *
+get_reg_name (int regno)
+{
+ static char buf[50];
+ const char *p;
+ char *b;
+
+ b = buf;
+
+ for (p = REGISTER_NAME (regno); *p; p++)
+ *b++ = toupper (*p);
+ *b = '\000';
+
+ return buf;
+}
+
+/* Read the remote registers into the block REGS. */
+
+static void
+st2000_fetch_registers (void)
+{
+ 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 (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 (void)
+{
+ 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 (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 (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static void
+st2000_files_info (void)
+{
+ 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 (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 (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;
+}
+
+/* Transfer LEN bytes between GDB address MYADDR and target address
+ MEMADDR. If WRITE is non-zero, transfer them to the target,
+ otherwise transfer them from the target. TARGET is unused.
+
+ Returns the number of bytes transferred. */
+
+static int
+st2000_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ if (write)
+ return st2000_write_inferior_memory (memaddr, myaddr, len);
+ else
+ return st2000_read_inferior_memory (memaddr, myaddr, len);
+}
+
+static void
+st2000_kill (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 (void)
+{
+ remove_breakpoints ();
+ unpush_target (&st2000_ops);
+ generic_mourn_inferior (); /* Do all the proper things now */
+}
+
+#define MAX_STDEBUG_BREAKPOINTS 16
+
+static CORE_ADDR breakaddr[MAX_STDEBUG_BREAKPOINTS] =
+{0};
+
+static int
+st2000_insert_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int i;
+ CORE_ADDR bp_addr = addr;
+ int bp_size = 0;
+
+ BREAKPOINT_FROM_PC (&bp_addr, &bp_size);
+
+ for (i = 0; i <= MAX_STDEBUG_BREAKPOINTS; i++)
+ if (breakaddr[i] == 0)
+ {
+ breakaddr[i] = addr;
+
+ st2000_read_inferior_memory (bp_addr, shadow, bp_size);
+ printf_stdebug ("BR %x H\r", addr);
+ expect_prompt (1);
+ return 0;
+ }
+
+ fprintf_unfiltered (gdb_stderr, "Too many breakpoints (> 16) for STDBUG\n");
+ return 1;
+}
+
+static int
+st2000_remove_breakpoint (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_unfiltered (gdb_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 (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 <CR>~. or <CR>~^D to break out. */
+
+/*static struct ttystate ttystate; */
+
+static void
+cleanup_tty (void)
+{
+ 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 (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 (deprecated_serial_fd (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 (deprecated_serial_fd (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;
+
+static void
+init_st2000_ops (void)
+{
+ st2000_ops.to_shortname = "st2000";
+ st2000_ops.to_longname = "Remote serial Tandem ST2000 target";
+ st2000_ops.to_doc = "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_ops.to_open = st2000_open;
+ st2000_ops.to_close = st2000_close;
+ st2000_ops.to_detach = st2000_detach;
+ st2000_ops.to_resume = st2000_resume;
+ st2000_ops.to_wait = st2000_wait;
+ st2000_ops.to_fetch_registers = st2000_fetch_register;
+ st2000_ops.to_store_registers = st2000_store_register;
+ st2000_ops.to_prepare_to_store = st2000_prepare_to_store;
+ st2000_ops.to_xfer_memory = st2000_xfer_inferior_memory;
+ st2000_ops.to_files_info = st2000_files_info;
+ st2000_ops.to_insert_breakpoint = st2000_insert_breakpoint;
+ st2000_ops.to_remove_breakpoint = st2000_remove_breakpoint; /* Breakpoints */
+ st2000_ops.to_kill = st2000_kill;
+ st2000_ops.to_create_inferior = st2000_create_inferior;
+ st2000_ops.to_mourn_inferior = st2000_mourn_inferior;
+ st2000_ops.to_stratum = process_stratum;
+ st2000_ops.to_has_all_memory = 1;
+ st2000_ops.to_has_memory = 1;
+ st2000_ops.to_has_stack = 1;
+ st2000_ops.to_has_registers = 1;
+ st2000_ops.to_has_execution = 1; /* all mem, mem, stack, regs, exec */
+ st2000_ops.to_magic = OPS_MAGIC; /* Always the last thing */
+};
+
+void
+_initialize_remote_st2000 (void)
+{
+ init_st2000_ops ();
+ add_target (&st2000_ops);
+ add_com ("st2000 <command>", 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 <CR>~. or <CR>~^D to break out.");
+}
diff --git a/contrib/gdb/gdb/remote-utils.c b/contrib/gdb/gdb/remote-utils.c
new file mode 100644
index 0000000..ba150e3
--- /dev/null
+++ b/contrib/gdb/gdb/remote-utils.c
@@ -0,0 +1,609 @@
+/* Generic support for remote debugging interfaces.
+
+ Copyright 1993, 1994, 1995, 1996, 1998, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+
+#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"
+#include "regcache.h"
+
+
+void _initialize_sr_support (void);
+
+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 (char *, char *);
+static void sr_com (char *, int);
+
+static void
+usage (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);
+
+ return;
+}
+
+#define CHECKDONE(p, q) \
+{ \
+ if (q == p) \
+ { \
+ if (*p == '\0') \
+ return; \
+ else \
+ usage(proto, p); \
+ } \
+}
+
+void
+sr_scan_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 (void)
+{
+ sr_write_cr ("");
+ gr_expect_prompt ();
+}
+
+void
+gr_open (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;
+
+ 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 (void)
+{
+ 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 (void)
+{
+ 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 ("<empty character poll>");
+ }
+
+ return buf & 0x7f;
+}
+
+/* Keep discarding input from the remote system, until STRING is found.
+ Let the user break out immediately. */
+void
+sr_expect (char *string)
+{
+ char *p = string;
+
+ immediate_quit++;
+ while (1)
+ {
+ if (sr_readchar () == *p)
+ {
+ p++;
+ if (*p == '\0')
+ {
+ immediate_quit--;
+ return;
+ }
+ }
+ else
+ p = string;
+ }
+}
+
+void
+sr_write (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 (char *s)
+{
+ sr_write (s, strlen (s));
+ sr_write ("\r", 1);
+ return;
+}
+
+int
+sr_timed_read (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 (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 (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 (void)
+{
+ 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. */
+
+static void
+sr_com (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 (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 (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 (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 (void)
+{
+ gr_clear_all_breakpoints ();
+ unpush_target (gr_get_ops ());
+ generic_mourn_inferior ();
+}
+
+void
+gr_kill (void)
+{
+ return;
+}
+
+/* This is called not only when we first attach, but also when the
+ user types "run" after having attached. */
+void
+gr_create_inferior (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 executable 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 (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 (void)
+{
+ /* Do nothing, since we assume we can store individual regs */
+}
+
+void
+_initialize_sr_support (void)
+{
+/* 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 <command>", 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 0000000..cae5d5e
--- /dev/null
+++ b/contrib/gdb/gdb/remote-utils.h
@@ -0,0 +1,135 @@
+/* Generic support for remote debugging interfaces.
+
+ Copyright 1993, 1994, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+struct target_ops;
+
+#include "target.h"
+struct serial;
+
+/* Stuff that should be shared (and handled consistently) among the various
+ remote targets. */
+
+struct _sr_settings
+ {
+ unsigned int timeout;
+
+ int retries;
+
+ char *device;
+ struct serial *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) xfree (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
+ {
+ char *prompt;
+ struct target_ops *ops;
+ int (*clear_all_breakpoints) (void);
+ void (*checkin) (void);
+ };
+
+extern struct gr_settings *gr_settings;
+
+/* 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_multi_scan (char *list[], int passthrough);
+int sr_get_hex_digit (int ignore_space);
+int sr_pollchar (void);
+int sr_readchar (void);
+int sr_timed_read (char *buf, int n);
+long sr_get_hex_word (void);
+void gr_close (int quitting);
+void gr_create_inferior (char *execfile, char *args, char **env);
+void gr_detach (char *args, int from_tty);
+void gr_files_info (struct target_ops *ops);
+void gr_generic_checkin (void);
+void gr_kill (void);
+void gr_mourn (void);
+void gr_prepare_to_store (void);
+void sr_expect (char *string);
+void sr_get_hex_byte (char *byt);
+void sr_scan_args (char *proto, char *args);
+void sr_write (char *a, int l);
+void sr_write_cr (char *s);
+
+void gr_open (char *args, int from_tty, struct gr_settings *gr_settings);
+void gr_load_image (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 0000000..fd51781
--- /dev/null
+++ b/contrib/gdb/gdb/remote-vx.c
@@ -0,0 +1,1409 @@
+/* Memory-access and commands for remote VxWorks processes, for GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999,
+ 2000, 2001, 2002 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 "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"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#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 <rpc/rpc.h>
+#undef malloc
+#undef free
+#undef realloc
+#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
+#include <netdb.h>
+#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 <symtab.h>
+
+/* 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 enum stop_kind stop_soon; /* 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 */
+
+/* Target ops structure for accessing memory and such over the net */
+
+static struct target_ops vx_ops;
+
+/* Target ops structure for accessing VxWorks child processes over the net */
+
+static struct target_ops vx_run_ops;
+
+/* 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 (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 (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 = PIDGET (inferior_ptid);
+
+ 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 (int addr)
+{
+ return net_break (addr, VX_BREAK_ADD);
+}
+
+/* returns 0 if successful, errno otherwise */
+
+static int
+vx_remove_breakpoint (int addr)
+{
+ return net_break (addr, VX_BREAK_DELETE);
+}
+
+/* Start an inferior process and sets inferior_ptid 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 (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_ptid = pid_to_ptid (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 = STOP_QUIETLY;
+ wait_for_inferior (); /* Get the task spawn event */
+ stop_soon = NO_STOP_QUIETLY;
+
+ /* 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 (char *arg_string, arg_array *arg_struct)
+{
+ int arg_count = 0; /* number of arguments */
+ int arg_index = 0;
+ 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 (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 (char *p)
+{
+ 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 (RDB_EVENT *pEvent)
+{
+ int pid;
+ enum clnt_stat status;
+
+ memset ((char *) pEvent, '\0', sizeof (RDB_EVENT));
+
+ pid = PIDGET (inferior_ptid);
+ 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 (void)
+{
+ 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 = PIDGET (inferior_ptid)) == 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 (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 = PIDGET (inferior_ptid);
+ 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_num;
+ 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 (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 = PIDGET (inferior_ptid);
+ 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_num;
+ 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 (void)
+{
+ /* Fetch all registers, if any of them are not yet fetched. */
+ deprecated_read_register_bytes (0, NULL, DEPRECATED_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. TARGET is unused.
+ 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 (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ 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 = PIDGET (inferior_ptid); /* 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_num;
+ }
+ }
+
+ /* Return the number of bytes transferred. */
+
+ return (len - nleft);
+}
+
+static void
+vx_files_info (void)
+{
+ 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 (void)
+{
+ printf_unfiltered ("\tRunning %s VxWorks process %s",
+ vx_running ? "child" : "attached",
+ local_hex_string (PIDGET (inferior_ptid)));
+ if (vx_running)
+ printf_unfiltered (", function `%s'", vx_running);
+ printf_unfiltered (".\n");
+}
+
+static void
+vx_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ int status;
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ CORE_ADDR cont_addr;
+
+ if (ptid_equal (ptid, minus_one_ptid))
+ ptid = inferior_ptid;
+
+ 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 = PIDGET (ptid);
+ 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_num;
+ perror_with_name ("Resuming remote process");
+ }
+}
+
+static void
+vx_mourn_inferior (void)
+{
+ pop_target (); /* Pop back to no-child state */
+ generic_mourn_inferior ();
+}
+
+
+static void vx_add_symbols (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 (bfd *, asection *, void *);
+
+static void
+find_sect (bfd *abfd, asection *sect, void *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 (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, NULL, 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_N_SECTION_OFFSETS (objfile->num_sections));
+ memcpy (offs, objfile->section_offsets,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ 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. */
+ offs->offsets[SECT_OFF_TEXT (objfile)] = text_addr - ss.text_start;
+ offs->offsets[SECT_OFF_DATA (objfile)] = data_addr - ss.data_start;
+ offs->offsets[SECT_OFF_BSS (objfile)] = bss_addr - ss.bss_start;
+ objfile_relocate (objfile, offs);
+}
+
+/* This function allows the addition of incrementally linked object files. */
+
+static void
+vx_load_command (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 (xfree, 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 (PIDGET (inferior_ptid) != 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 canceled.");
+ }
+
+ 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 (void)
+{
+ enum clnt_stat status;
+ int step_status;
+ SOURCE_STEP source_step;
+
+ source_step.taskId = PIDGET (inferior_ptid);
+
+ 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 (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 (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
+ and store in PLOADTABLE.
+ 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 (ldtabl *pLoadTable)
+{
+ 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. */
+
+static int
+vx_lookup_symbol (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)
+ {
+ complaint (&symfile_complaints, "Lost contact with VxWorks 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 (void)
+{
+ 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 (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 (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 ptid_t
+vx_wait (ptid_t ptid_to_wait_for, struct target_waitstatus *status)
+{
+ 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 != PIDGET (inferior_ptid))
+ internal_error (__FILE__, __LINE__,
+ "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_to_ptid (pid);
+}
+
+static int
+symbol_stub (char *arg)
+{
+ symbol_file_add_main (arg, 0);
+ return 1;
+}
+
+static int
+add_symbol_stub (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 (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
+ {
+ 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 (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_num;
+ perror_with_name ("Attaching remote process");
+ }
+
+ /* It worked... */
+
+ inferior_ptid = pid_to_ptid (pid);
+ push_target (&vx_run_ops);
+
+ if (vx_running)
+ xfree (vx_running);
+ vx_running = 0;
+}
+
+/* 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 (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) PIDGET (inferior_ptid)));
+
+ 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 = PIDGET (inferior_ptid);
+
+ 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_num;
+ perror_with_name ("Detaching VxWorks process");
+ }
+
+ inferior_ptid = null_ptid;
+ pop_target (); /* go back to non-executing VxWorks connection */
+}
+
+/* vx_kill -- takes a running task and wipes it out. */
+
+static void
+vx_kill (void)
+{
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ int status;
+
+ printf_unfiltered ("Killing pid %s.\n", local_hex_string ((unsigned long) PIDGET (inferior_ptid)));
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+ ptrace_in.pid = PIDGET (inferior_ptid);
+
+ 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_num;
+ 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_ptid = null_ptid;
+ 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 (int quitting)
+{
+ inferior_ptid = null_ptid; /* No longer have a process. */
+ if (vx_running)
+ xfree (vx_running);
+ vx_running = 0;
+}
+
+/* Make an RPC call to the VxWorks target.
+ Returns RPC status. */
+
+static enum clnt_stat
+net_clnt_call (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 (int quitting)
+{
+ if (pClient)
+ clnt_destroy (pClient); /* The net connection */
+ pClient = 0;
+
+ if (vx_host)
+ xfree (vx_host); /* The hostname */
+ vx_host = 0;
+}
+
+/* A vxprocess target should be started via "run" not "target". */
+static void
+vx_proc_open (char *name, int from_tty)
+{
+ error ("Use the \"run\" command to start a VxWorks process.");
+}
+
+static void
+init_vx_ops (void)
+{
+ vx_ops.to_shortname = "vxworks";
+ vx_ops.to_longname = "VxWorks target memory via RPC over TCP/IP";
+ vx_ops.to_doc = "Use VxWorks target memory. \n\
+Specify the name of the machine to connect to.";
+ vx_ops.to_open = vx_open;
+ vx_ops.to_close = vx_close;
+ vx_ops.to_attach = vx_attach;
+ vx_ops.to_xfer_memory = vx_xfer_memory;
+ vx_ops.to_files_info = vx_files_info;
+ vx_ops.to_load = vx_load_command;
+ vx_ops.to_lookup_symbol = vx_lookup_symbol;
+ vx_ops.to_create_inferior = vx_create_inferior;
+ vx_ops.to_stratum = core_stratum;
+ vx_ops.to_has_all_memory = 1;
+ vx_ops.to_has_memory = 1;
+ vx_ops.to_magic = OPS_MAGIC; /* Always the last thing */
+};
+
+static void
+init_vx_run_ops (void)
+{
+ vx_run_ops.to_shortname = "vxprocess";
+ vx_run_ops.to_longname = "VxWorks process";
+ vx_run_ops.to_doc = "VxWorks process; started by the \"run\" command.";
+ vx_run_ops.to_open = vx_proc_open;
+ vx_run_ops.to_close = vx_proc_close;
+ vx_run_ops.to_detach = vx_detach;
+ vx_run_ops.to_resume = vx_resume;
+ vx_run_ops.to_wait = vx_wait;
+ vx_run_ops.to_fetch_registers = vx_read_register;
+ vx_run_ops.to_store_registers = vx_write_register;
+ vx_run_ops.to_prepare_to_store = vx_prepare_to_store;
+ vx_run_ops.to_xfer_memory = vx_xfer_memory;
+ vx_run_ops.to_files_info = vx_run_files_info;
+ vx_run_ops.to_insert_breakpoint = vx_insert_breakpoint;
+ vx_run_ops.to_remove_breakpoint = vx_remove_breakpoint;
+ vx_run_ops.to_kill = vx_kill;
+ vx_run_ops.to_load = vx_load_command;
+ vx_run_ops.to_lookup_symbol = vx_lookup_symbol;
+ vx_run_ops.to_mourn_inferior = vx_mourn_inferior;
+ vx_run_ops.to_stratum = process_stratum;
+ vx_run_ops.to_has_memory = 1;
+ vx_run_ops.to_has_stack = 1;
+ vx_run_ops.to_has_registers = 1;
+ vx_run_ops.to_has_execution = 1;
+ vx_run_ops.to_magic = OPS_MAGIC;
+}
+
+void
+_initialize_vx (void)
+{
+ init_vx_ops ();
+ add_target (&vx_ops);
+ init_vx_run_ops ();
+ add_target (&vx_run_ops);
+
+ 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);
+}
diff --git a/contrib/gdb/gdb/remote-vx68.c b/contrib/gdb/gdb/remote-vx68.c
new file mode 100644
index 0000000..8cdac6f
--- /dev/null
+++ b/contrib/gdb/gdb/remote-vx68.c
@@ -0,0 +1,160 @@
+/* 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 <stdio.h>
+#include "defs.h"
+
+#include "vx-share/regPacket.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#ifdef _AIX /* IBM claims "void *malloc()" not char * */
+#define malloc bogon_malloc
+#endif
+
+#include <rpc/rpc.h>
+
+#ifdef _AIX
+#undef malloc
+#endif
+
+#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
+#include <netdb.h>
+#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 <value.h>
+#include <symtab.h>
+
+/* 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 (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], deprecated_registers,
+ 16 * MC68K_GREG_SIZE);
+ bcopy (&mc68k_greg_packet[MC68K_R_SR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)],
+ MC68K_GREG_SIZE);
+ bcopy (&mc68k_greg_packet[MC68K_R_PC],
+ &deprecated_registers[DEPRECATED_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],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ MC68K_FPREG_SIZE * 8);
+ bcopy (&mc68k_fpreg_packet[MC68K_R_FPCR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
+ }
+ else
+ {
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ 0, MC68K_FPREG_SIZE * 8);
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ 0, MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
+ }
+
+ /* Mark the register cache valid. */
+
+ deprecated_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 (int regno)
+{
+ char mc68k_greg_packet[MC68K_GREG_PLEN];
+ char mc68k_fpreg_packet[MC68K_FPREG_PLEN];
+
+ /* Store general-purpose registers. */
+
+ bcopy (deprecated_registers, &mc68k_greg_packet[MC68K_R_D0],
+ 16 * MC68K_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)],
+ &mc68k_greg_packet[MC68K_R_SR], MC68K_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_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 (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ &mc68k_fpreg_packet[MC68K_R_FP0],
+ MC68K_FPREG_SIZE * 8);
+ bcopy (&deprecated_registers[DEPRECATED_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-vxmips.c b/contrib/gdb/gdb/remote-vxmips.c
new file mode 100644
index 0000000..55ba49b
--- /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 <stdio.h>
+#include "defs.h"
+
+#include "vx-share/regPacket.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
+#include <netdb.h>
+#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 <value.h>
+#include <symtab.h>
+
+/* 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 (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], &deprecated_registers[0],
+ 32 * MIPS_GREG_SIZE);
+
+ /* Copy SR, LO, HI, and PC. */
+
+ bcopy (&mips_greg_packet[MIPS_R_SR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)], MIPS_GREG_SIZE);
+ bcopy (&mips_greg_packet[MIPS_R_LO],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->lo)], MIPS_GREG_SIZE);
+ bcopy (&mips_greg_packet[MIPS_R_HI],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->hi)], MIPS_GREG_SIZE);
+ bcopy (&mips_greg_packet[MIPS_R_PC],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->pc)], 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],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ DEPRECATED_REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
+
+ /* Copy the floating point control/status register (fpcsr). */
+
+ bcopy (&mips_fpreg_packet[MIPS_R_FPCSR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)],
+ DEPRECATED_REGISTER_RAW_SIZE (mips_regnum (current_gdbarch)->fp_control_status));
+ }
+ else
+ {
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ 0, DEPRECATED_REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)],
+ 0, DEPRECATED_REGISTER_RAW_SIZE (mips_regnum (current_gdbarch)->fp_control_status));
+ }
+
+ /* Mark the register cache valid. */
+
+ deprecated_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 (int regno)
+{
+ char mips_greg_packet[MIPS_GREG_PLEN];
+ char mips_fpreg_packet[MIPS_FPREG_PLEN];
+
+ /* Store general registers. */
+
+ bcopy (&deprecated_registers[0], &mips_greg_packet[MIPS_R_GP0],
+ 32 * MIPS_GREG_SIZE);
+
+ /* Copy SR, LO, HI, and PC. */
+
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)],
+ &mips_greg_packet[MIPS_R_SR], MIPS_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->lo)],
+ &mips_greg_packet[MIPS_R_LO], MIPS_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->hi)],
+ &mips_greg_packet[MIPS_R_HI], MIPS_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->pc)],
+ &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 (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ &mips_fpreg_packet[MIPS_R_FP0],
+ DEPRECATED_REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
+
+ /* Copy the floating point control/status register (fpcsr). */
+
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)],
+ &mips_fpreg_packet[MIPS_R_FPCSR],
+ DEPRECATED_REGISTER_RAW_SIZE (mips_regnum (current_gdbarch)->fp_control_status));
+
+ 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 0000000..118e517
--- /dev/null
+++ b/contrib/gdb/gdb/remote-vxsparc.c
@@ -0,0 +1,128 @@
+/* SPARC-specific portions of the RPC protocol for VxWorks.
+
+ 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 "defs.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+
+#include "sparc-tdep.h"
+
+#include "vx-share/ptrace.h"
+#include "vx-share/regPacket.h"
+
+#define SPARC_R_G1 (SPARC_R_G0 + SPARC_GREG_SIZE)
+
+const struct sparc_gregset vxsparc_gregset =
+{
+ SPARC_R_PSR, /* %psr */
+ SPARC_R_PC, /* %pc */
+ SPARC_R_NPC, /* %npc */
+ SPARC_R_Y, /* %y */
+ SPARC_R_WIM, /* %wim */
+ SPARC_R_TBR, /* %tbr */
+ SPARC_R_G1, /* %g1 */
+ SPARC_R_I0 /* %l0 */
+};
+
+/* Flag set if target has an 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. REGNUM is
+ the register to read, or -1 for all; currently, it is ignored.
+ FIXME: Look at REGNUM to improve efficiency. */
+
+void
+vx_read_register (int regnum)
+{
+ struct regcache *regcache = current_regcache;
+ char gregs[SPARC_GREG_PLEN];
+ char fpregs[SPARC_FPREG_PLEN];
+ CORE_ADDR sp;
+
+ /* Get the general-purpose registers. */
+ net_read_registers (gregs, SPARC_GREG_PLEN, PTRACE_GETREGS);
+ sparc32_supply_gregset (&vxsparc_gregset, regcache, -1, gregs);
+
+ /* If the target has floating-point registers, fetch them.
+ Otherwise, zero the floating-point register values in GDB's
+ register cache for good measure, even though we might not need
+ to. */
+ if (target_has_fp)
+ net_read_registers (fpregs, SPARC_FPREG_PLEN, PTRACE_GETFPREGS);
+ else
+ memset (fpregs, 0, SPARC_FPREG_PLEN);
+ sparc32_supply_fpregset (regcache, -1, fpregs);
+}
+
+/* Store a register or registers into the VxWorks target. REGNUM is
+ the register to store, or -1 for all; currently, it is ignored.
+ FIXME: Look at REGNUM to improve efficiency. */
+
+void
+vx_write_register (int regnum)
+{
+ struct regcache *regcache = current_regcache;
+ char gregs[SPARC_GREG_PLEN];
+ char fpregs[SPARC_FPREG_PLEN];
+ int gregs_p = 1;
+ int fpregs_p = 1;
+ CORE_ADDR sp;
+
+ if (regnum != -1)
+ {
+ if ((SPARC_G0_REGNUM <= regnum && regnum <= SPARC_I7_REGNUM)
+ || (SPARC32_Y_REGNUM <= regnum && regnum <= SPARC32_NPC_REGNUM))
+ fpregs_p = 0;
+ else
+ gregs_p = 0;
+ }
+
+ /* Store the general-purpose registers. */
+ if (gregs_p)
+ {
+ sparc32_collect_gregset (&vxsparc_gregset, regcache, -1, gregs);
+ net_write_registers (gregs, SPARC_GREG_PLEN, PTRACE_SETREGS);
+
+ /* Deal with the stack regs. */
+ if (regnum == -1 || regnum == SPARC_SP_REGNUM
+ || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM))
+ {
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ sparc_collect_rwindow (regcache, sp, regnum);
+ }
+ }
+
+ /* Store the floating-point registers if the target has them. */
+ if (fpregs_p && target_has_fp)
+ {
+ sparc32_collect_fpregset (regcache, -1, fpregs);
+ net_write_registers (fpregs, SPARC_FPREG_PLEN, PTRACE_SETFPREGS);
+ }
+}
diff --git a/contrib/gdb/gdb/remote.c b/contrib/gdb/gdb/remote.c
new file mode 100644
index 0000000..36da449
--- /dev/null
+++ b/contrib/gdb/gdb/remote.c
@@ -0,0 +1,5730 @@
+/* Remote target communications for serial-line targets in custom GDB protocol
+
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* See the GDB User Guide for details of the GDB remote protocol. */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include <fcntl.h>
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+/*#include "terminal.h" */
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "gdbthread.h"
+#include "remote.h"
+#include "regcache.h"
+#include "value.h"
+#include "gdb_assert.h"
+
+#include <ctype.h>
+#include <sys/time.h>
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include "event-loop.h"
+#include "event-top.h"
+#include "inf-loop.h"
+
+#include <signal.h>
+#include "serial.h"
+
+#include "gdbcore.h" /* for exec_bfd */
+
+#include "remote-fileio.h"
+
+/* Prototypes for local functions */
+static void cleanup_sigint_signal_handler (void *dummy);
+static void initialize_sigint_signal_handler (void);
+static int getpkt_sane (char *buf, long sizeof_buf, int forever);
+
+static void handle_remote_sigint (int);
+static void handle_remote_sigint_twice (int);
+static void async_remote_interrupt (gdb_client_data);
+void async_remote_interrupt_twice (gdb_client_data);
+
+static void build_remote_gdbarch_data (void);
+
+static void remote_files_info (struct target_ops *ignore);
+
+static int remote_xfer_memory (CORE_ADDR memaddr, char *myaddr,
+ int len, int should_write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+
+static void remote_prepare_to_store (void);
+
+static void remote_fetch_registers (int regno);
+
+static void remote_resume (ptid_t ptid, int step,
+ enum target_signal siggnal);
+static void remote_async_resume (ptid_t ptid, int step,
+ enum target_signal siggnal);
+static int remote_start_remote (struct ui_out *uiout, void *dummy);
+
+static void remote_open (char *name, int from_tty);
+static void remote_async_open (char *name, int from_tty);
+
+static void extended_remote_open (char *name, int from_tty);
+static void extended_remote_async_open (char *name, int from_tty);
+
+static void remote_open_1 (char *, int, struct target_ops *, int extended_p,
+ int async_p);
+
+static void remote_close (int quitting);
+
+static void remote_store_registers (int regno);
+
+static void remote_mourn (void);
+static void remote_async_mourn (void);
+
+static void extended_remote_restart (void);
+
+static void extended_remote_mourn (void);
+
+static void extended_remote_create_inferior (char *, char *, char **);
+static void extended_remote_async_create_inferior (char *, char *, char **);
+
+static void remote_mourn_1 (struct target_ops *);
+
+static void remote_send (char *buf, long sizeof_buf);
+
+static int readchar (int timeout);
+
+static ptid_t remote_wait (ptid_t ptid,
+ struct target_waitstatus *status);
+static ptid_t remote_async_wait (ptid_t ptid,
+ struct target_waitstatus *status);
+
+static void remote_kill (void);
+static void remote_async_kill (void);
+
+static int tohex (int nib);
+
+static void remote_detach (char *args, int from_tty);
+
+static void remote_interrupt (int signo);
+
+static void remote_interrupt_twice (int signo);
+
+static void interrupt_query (void);
+
+static void set_thread (int, int);
+
+static int remote_thread_alive (ptid_t);
+
+static void get_offsets (void);
+
+static long read_frame (char *buf, long sizeof_buf);
+
+static int remote_insert_breakpoint (CORE_ADDR, char *);
+
+static int remote_remove_breakpoint (CORE_ADDR, char *);
+
+static int hexnumlen (ULONGEST num);
+
+static void init_remote_ops (void);
+
+static void init_extended_remote_ops (void);
+
+static void remote_stop (void);
+
+static int ishex (int ch, int *val);
+
+static int stubhex (int ch);
+
+static int hexnumstr (char *, ULONGEST);
+
+static int hexnumnstr (char *, ULONGEST, int);
+
+static CORE_ADDR remote_address_masked (CORE_ADDR);
+
+static void print_packet (char *);
+
+static unsigned long crc32 (unsigned char *, int, unsigned int);
+
+static void compare_sections_command (char *, int);
+
+static void packet_command (char *, int);
+
+static int stub_unpack_int (char *buff, int fieldlength);
+
+static ptid_t remote_current_thread (ptid_t oldptid);
+
+static void remote_find_new_threads (void);
+
+static void record_currthread (int currthread);
+
+static int fromhex (int a);
+
+static int hex2bin (const char *hex, char *bin, int count);
+
+static int bin2hex (const char *bin, char *hex, int count);
+
+static int putpkt_binary (char *buf, int cnt);
+
+static void check_binary_download (CORE_ADDR addr);
+
+struct packet_config;
+
+static void show_packet_config_cmd (struct packet_config *config);
+
+static void update_packet_config (struct packet_config *config);
+
+void _initialize_remote (void);
+
+/* Description of the remote protocol. Strictly speaking, when the
+ target is open()ed, remote.c should create a per-target description
+ of the remote protocol using that target's architecture.
+ Unfortunately, the target stack doesn't include local state. For
+ the moment keep the information in the target's architecture
+ object. Sigh.. */
+
+struct packet_reg
+{
+ long offset; /* Offset into G packet. */
+ long regnum; /* GDB's internal register number. */
+ LONGEST pnum; /* Remote protocol register number. */
+ int in_g_packet; /* Always part of G packet. */
+ /* long size in bytes; == DEPRECATED_REGISTER_RAW_SIZE (regnum); at present. */
+ /* char *name; == REGISTER_NAME (regnum); at present. */
+};
+
+struct remote_state
+{
+ /* Description of the remote protocol registers. */
+ long sizeof_g_packet;
+
+ /* Description of the remote protocol registers indexed by REGNUM
+ (making an array of NUM_REGS + NUM_PSEUDO_REGS in size). */
+ struct packet_reg *regs;
+
+ /* This is the size (in chars) of the first response to the ``g''
+ packet. It is used as a heuristic when determining the maximum
+ size of memory-read and memory-write packets. A target will
+ typically only reserve a buffer large enough to hold the ``g''
+ packet. The size does not include packet overhead (headers and
+ trailers). */
+ long actual_register_packet_size;
+
+ /* This is the maximum size (in chars) of a non read/write packet.
+ It is also used as a cap on the size of read/write packets. */
+ long remote_packet_size;
+};
+
+
+/* Handle for retreving the remote protocol data from gdbarch. */
+static struct gdbarch_data *remote_gdbarch_data_handle;
+
+static struct remote_state *
+get_remote_state (void)
+{
+ return gdbarch_data (current_gdbarch, remote_gdbarch_data_handle);
+}
+
+static void *
+init_remote_state (struct gdbarch *gdbarch)
+{
+ int regnum;
+ struct remote_state *rs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_state);
+
+ if (DEPRECATED_REGISTER_BYTES != 0)
+ rs->sizeof_g_packet = DEPRECATED_REGISTER_BYTES;
+ else
+ rs->sizeof_g_packet = 0;
+
+ /* Assume a 1:1 regnum<->pnum table. */
+ rs->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS + NUM_PSEUDO_REGS,
+ struct packet_reg);
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ struct packet_reg *r = &rs->regs[regnum];
+ r->pnum = regnum;
+ r->regnum = regnum;
+ r->offset = DEPRECATED_REGISTER_BYTE (regnum);
+ r->in_g_packet = (regnum < NUM_REGS);
+ /* ...name = REGISTER_NAME (regnum); */
+
+ /* Compute packet size by accumulating the size of all registers. */
+ if (DEPRECATED_REGISTER_BYTES == 0)
+ rs->sizeof_g_packet += register_size (current_gdbarch, regnum);
+ }
+
+ /* Default maximum number of characters in a packet body. Many
+ remote stubs have a hardwired buffer size of 400 bytes
+ (c.f. BUFMAX in m68k-stub.c and i386-stub.c). BUFMAX-1 is used
+ as the maximum packet-size to ensure that the packet and an extra
+ NUL character can always fit in the buffer. This stops GDB
+ trashing stubs that try to squeeze an extra NUL into what is
+ already a full buffer (As of 1999-12-04 that was most stubs. */
+ rs->remote_packet_size = 400 - 1;
+
+ /* Should rs->sizeof_g_packet needs more space than the
+ default, adjust the size accordingly. Remember that each byte is
+ encoded as two characters. 32 is the overhead for the packet
+ header / footer. NOTE: cagney/1999-10-26: I suspect that 8
+ (``$NN:G...#NN'') is a better guess, the below has been padded a
+ little. */
+ if (rs->sizeof_g_packet > ((rs->remote_packet_size - 32) / 2))
+ rs->remote_packet_size = (rs->sizeof_g_packet * 2 + 32);
+
+ /* This one is filled in when a ``g'' packet is received. */
+ rs->actual_register_packet_size = 0;
+
+ return rs;
+}
+
+static struct packet_reg *
+packet_reg_from_regnum (struct remote_state *rs, long regnum)
+{
+ if (regnum < 0 && regnum >= NUM_REGS + NUM_PSEUDO_REGS)
+ return NULL;
+ else
+ {
+ struct packet_reg *r = &rs->regs[regnum];
+ gdb_assert (r->regnum == regnum);
+ return r;
+ }
+}
+
+static struct packet_reg *
+packet_reg_from_pnum (struct remote_state *rs, LONGEST pnum)
+{
+ int i;
+ for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+ {
+ struct packet_reg *r = &rs->regs[i];
+ if (r->pnum == pnum)
+ return r;
+ }
+ return NULL;
+}
+
+/* FIXME: graces/2002-08-08: These variables should eventually be
+ bound to an instance of the target object (as in gdbarch-tdep()),
+ when such a thing exists. */
+
+/* This is set to the data address of the access causing the target
+ to stop for a watchpoint. */
+static CORE_ADDR remote_watch_data_address;
+
+/* This is non-zero if taregt stopped for a watchpoint. */
+static int remote_stopped_by_watchpoint_p;
+
+
+static struct target_ops remote_ops;
+
+static struct target_ops extended_remote_ops;
+
+/* Temporary target ops. Just like the remote_ops and
+ extended_remote_ops, but with asynchronous support. */
+static struct target_ops remote_async_ops;
+
+static struct target_ops extended_async_remote_ops;
+
+/* FIXME: cagney/1999-09-23: Even though getpkt was called with
+ ``forever'' still use the normal timeout mechanism. This is
+ currently used by the ASYNC code to guarentee that target reads
+ during the initial connect always time-out. Once getpkt has been
+ modified to return a timeout indication and, in turn
+ remote_wait()/wait_for_inferior() have gained a timeout parameter
+ this can go away. */
+static int wait_forever_enabled_p = 1;
+
+
+/* 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. */
+static struct serial *remote_desc = NULL;
+
+/* This variable sets the number of bits in an address that are to be
+ sent in a memory ("M" or "m") packet. Normally, after stripping
+ leading zeros, the entire address would be sent. This variable
+ restricts the address to REMOTE_ADDRESS_SIZE bits. HISTORY: The
+ initial implementation of remote.c restricted the address sent in
+ memory packets to ``host::sizeof long'' bytes - (typically 32
+ bits). Consequently, for 64 bit targets, the upper 32 bits of an
+ address was never sent. Since fixing this bug may cause a break in
+ some remote targets this variable is principly provided to
+ facilitate backward compatibility. */
+
+static int remote_address_size;
+
+/* Tempoary to track who currently owns the terminal. See
+ target_async_terminal_* for more details. */
+
+static int remote_async_terminal_ours_p;
+
+
+/* User configurable variables for the number of characters in a
+ memory read/write packet. MIN ((rs->remote_packet_size),
+ rs->sizeof_g_packet) is the default. Some targets need smaller
+ values (fifo overruns, et.al.) and some users need larger values
+ (speed up transfers). The variables ``preferred_*'' (the user
+ request), ``current_*'' (what was actually set) and ``forced_*''
+ (Positive - a soft limit, negative - a hard limit). */
+
+struct memory_packet_config
+{
+ char *name;
+ long size;
+ int fixed_p;
+};
+
+/* Compute the current size of a read/write packet. Since this makes
+ use of ``actual_register_packet_size'' the computation is dynamic. */
+
+static long
+get_memory_packet_size (struct memory_packet_config *config)
+{
+ struct remote_state *rs = get_remote_state ();
+ /* NOTE: The somewhat arbitrary 16k comes from the knowledge (folk
+ law?) that some hosts don't cope very well with large alloca()
+ calls. Eventually the alloca() code will be replaced by calls to
+ xmalloc() and make_cleanups() allowing this restriction to either
+ be lifted or removed. */
+#ifndef MAX_REMOTE_PACKET_SIZE
+#define MAX_REMOTE_PACKET_SIZE 16384
+#endif
+ /* NOTE: 16 is just chosen at random. */
+#ifndef MIN_REMOTE_PACKET_SIZE
+#define MIN_REMOTE_PACKET_SIZE 16
+#endif
+ long what_they_get;
+ if (config->fixed_p)
+ {
+ if (config->size <= 0)
+ what_they_get = MAX_REMOTE_PACKET_SIZE;
+ else
+ what_they_get = config->size;
+ }
+ else
+ {
+ what_they_get = (rs->remote_packet_size);
+ /* Limit the packet to the size specified by the user. */
+ if (config->size > 0
+ && what_they_get > config->size)
+ what_they_get = config->size;
+ /* Limit it to the size of the targets ``g'' response. */
+ if ((rs->actual_register_packet_size) > 0
+ && what_they_get > (rs->actual_register_packet_size))
+ what_they_get = (rs->actual_register_packet_size);
+ }
+ if (what_they_get > MAX_REMOTE_PACKET_SIZE)
+ what_they_get = MAX_REMOTE_PACKET_SIZE;
+ if (what_they_get < MIN_REMOTE_PACKET_SIZE)
+ what_they_get = MIN_REMOTE_PACKET_SIZE;
+ return what_they_get;
+}
+
+/* Update the size of a read/write packet. If they user wants
+ something really big then do a sanity check. */
+
+static void
+set_memory_packet_size (char *args, struct memory_packet_config *config)
+{
+ int fixed_p = config->fixed_p;
+ long size = config->size;
+ if (args == NULL)
+ error ("Argument required (integer, `fixed' or `limited').");
+ else if (strcmp (args, "hard") == 0
+ || strcmp (args, "fixed") == 0)
+ fixed_p = 1;
+ else if (strcmp (args, "soft") == 0
+ || strcmp (args, "limit") == 0)
+ fixed_p = 0;
+ else
+ {
+ char *end;
+ size = strtoul (args, &end, 0);
+ if (args == end)
+ error ("Invalid %s (bad syntax).", config->name);
+#if 0
+ /* Instead of explicitly capping the size of a packet to
+ MAX_REMOTE_PACKET_SIZE or dissallowing it, the user is
+ instead allowed to set the size to something arbitrarily
+ large. */
+ if (size > MAX_REMOTE_PACKET_SIZE)
+ error ("Invalid %s (too large).", config->name);
+#endif
+ }
+ /* Extra checks? */
+ if (fixed_p && !config->fixed_p)
+ {
+ if (! query ("The target may not be able to correctly handle a %s\n"
+ "of %ld bytes. Change the packet size? ",
+ config->name, size))
+ error ("Packet size not changed.");
+ }
+ /* Update the config. */
+ config->fixed_p = fixed_p;
+ config->size = size;
+}
+
+static void
+show_memory_packet_size (struct memory_packet_config *config)
+{
+ printf_filtered ("The %s is %ld. ", config->name, config->size);
+ if (config->fixed_p)
+ printf_filtered ("Packets are fixed at %ld bytes.\n",
+ get_memory_packet_size (config));
+ else
+ printf_filtered ("Packets are limited to %ld bytes.\n",
+ get_memory_packet_size (config));
+}
+
+static struct memory_packet_config memory_write_packet_config =
+{
+ "memory-write-packet-size",
+};
+
+static void
+set_memory_write_packet_size (char *args, int from_tty)
+{
+ set_memory_packet_size (args, &memory_write_packet_config);
+}
+
+static void
+show_memory_write_packet_size (char *args, int from_tty)
+{
+ show_memory_packet_size (&memory_write_packet_config);
+}
+
+static long
+get_memory_write_packet_size (void)
+{
+ return get_memory_packet_size (&memory_write_packet_config);
+}
+
+static struct memory_packet_config memory_read_packet_config =
+{
+ "memory-read-packet-size",
+};
+
+static void
+set_memory_read_packet_size (char *args, int from_tty)
+{
+ set_memory_packet_size (args, &memory_read_packet_config);
+}
+
+static void
+show_memory_read_packet_size (char *args, int from_tty)
+{
+ show_memory_packet_size (&memory_read_packet_config);
+}
+
+static long
+get_memory_read_packet_size (void)
+{
+ struct remote_state *rs = get_remote_state ();
+ long size = get_memory_packet_size (&memory_read_packet_config);
+ /* FIXME: cagney/1999-11-07: Functions like getpkt() need to get an
+ extra buffer size argument before the memory read size can be
+ increased beyond (rs->remote_packet_size). */
+ if (size > (rs->remote_packet_size))
+ size = (rs->remote_packet_size);
+ return size;
+}
+
+
+/* Generic configuration support for packets the stub optionally
+ supports. Allows the user to specify the use of the packet as well
+ as allowing GDB to auto-detect support in the remote stub. */
+
+enum packet_support
+ {
+ PACKET_SUPPORT_UNKNOWN = 0,
+ PACKET_ENABLE,
+ PACKET_DISABLE
+ };
+
+struct packet_config
+ {
+ char *name;
+ char *title;
+ enum auto_boolean detect;
+ enum packet_support support;
+ };
+
+/* Analyze a packet's return value and update the packet config
+ accordingly. */
+
+enum packet_result
+{
+ PACKET_ERROR,
+ PACKET_OK,
+ PACKET_UNKNOWN
+};
+
+static void
+update_packet_config (struct packet_config *config)
+{
+ switch (config->detect)
+ {
+ case AUTO_BOOLEAN_TRUE:
+ config->support = PACKET_ENABLE;
+ break;
+ case AUTO_BOOLEAN_FALSE:
+ config->support = PACKET_DISABLE;
+ break;
+ case AUTO_BOOLEAN_AUTO:
+ config->support = PACKET_SUPPORT_UNKNOWN;
+ break;
+ }
+}
+
+static void
+show_packet_config_cmd (struct packet_config *config)
+{
+ char *support = "internal-error";
+ switch (config->support)
+ {
+ case PACKET_ENABLE:
+ support = "enabled";
+ break;
+ case PACKET_DISABLE:
+ support = "disabled";
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ support = "unknown";
+ break;
+ }
+ switch (config->detect)
+ {
+ case AUTO_BOOLEAN_AUTO:
+ printf_filtered ("Support for remote protocol `%s' (%s) packet is auto-detected, currently %s.\n",
+ config->name, config->title, support);
+ break;
+ case AUTO_BOOLEAN_TRUE:
+ case AUTO_BOOLEAN_FALSE:
+ printf_filtered ("Support for remote protocol `%s' (%s) packet is currently %s.\n",
+ config->name, config->title, support);
+ break;
+ }
+}
+
+static void
+add_packet_config_cmd (struct packet_config *config,
+ char *name,
+ char *title,
+ cmd_sfunc_ftype *set_func,
+ cmd_sfunc_ftype *show_func,
+ struct cmd_list_element **set_remote_list,
+ struct cmd_list_element **show_remote_list,
+ int legacy)
+{
+ struct cmd_list_element *set_cmd;
+ struct cmd_list_element *show_cmd;
+ char *set_doc;
+ char *show_doc;
+ char *cmd_name;
+ config->name = name;
+ config->title = title;
+ config->detect = AUTO_BOOLEAN_AUTO;
+ config->support = PACKET_SUPPORT_UNKNOWN;
+ xasprintf (&set_doc, "Set use of remote protocol `%s' (%s) packet",
+ name, title);
+ xasprintf (&show_doc, "Show current use of remote protocol `%s' (%s) packet",
+ name, title);
+ /* set/show TITLE-packet {auto,on,off} */
+ xasprintf (&cmd_name, "%s-packet", title);
+ add_setshow_auto_boolean_cmd (cmd_name, class_obscure,
+ &config->detect, set_doc, show_doc,
+ set_func, show_func,
+ set_remote_list, show_remote_list);
+ /* set/show remote NAME-packet {auto,on,off} -- legacy */
+ if (legacy)
+ {
+ char *legacy_name;
+ xasprintf (&legacy_name, "%s-packet", name);
+ add_alias_cmd (legacy_name, cmd_name, class_obscure, 0,
+ set_remote_list);
+ add_alias_cmd (legacy_name, cmd_name, class_obscure, 0,
+ show_remote_list);
+ }
+}
+
+static enum packet_result
+packet_ok (const char *buf, struct packet_config *config)
+{
+ if (buf[0] != '\0')
+ {
+ /* The stub recognized the packet request. Check that the
+ operation succeeded. */
+ switch (config->support)
+ {
+ case PACKET_SUPPORT_UNKNOWN:
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Packet %s (%s) is supported\n",
+ config->name, config->title);
+ config->support = PACKET_ENABLE;
+ break;
+ case PACKET_DISABLE:
+ internal_error (__FILE__, __LINE__,
+ "packet_ok: attempt to use a disabled packet");
+ break;
+ case PACKET_ENABLE:
+ break;
+ }
+ if (buf[0] == 'O' && buf[1] == 'K' && buf[2] == '\0')
+ /* "OK" - definitly OK. */
+ return PACKET_OK;
+ if (buf[0] == 'E'
+ && isxdigit (buf[1]) && isxdigit (buf[2])
+ && buf[3] == '\0')
+ /* "Enn" - definitly an error. */
+ return PACKET_ERROR;
+ /* The packet may or may not be OK. Just assume it is */
+ return PACKET_OK;
+ }
+ else
+ {
+ /* The stub does not support the packet. */
+ switch (config->support)
+ {
+ case PACKET_ENABLE:
+ if (config->detect == AUTO_BOOLEAN_AUTO)
+ /* If the stub previously indicated that the packet was
+ supported then there is a protocol error.. */
+ error ("Protocol error: %s (%s) conflicting enabled responses.",
+ config->name, config->title);
+ else
+ /* The user set it wrong. */
+ error ("Enabled packet %s (%s) not recognized by stub",
+ config->name, config->title);
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Packet %s (%s) is NOT supported\n",
+ config->name, config->title);
+ config->support = PACKET_DISABLE;
+ break;
+ case PACKET_DISABLE:
+ break;
+ }
+ return PACKET_UNKNOWN;
+ }
+}
+
+/* Should we try the 'vCont' (descriptive resume) request? */
+static struct packet_config remote_protocol_vcont;
+
+static void
+set_remote_protocol_vcont_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_vcont);
+}
+
+static void
+show_remote_protocol_vcont_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_vcont);
+}
+
+/* Should we try the 'qSymbol' (target symbol lookup service) request? */
+static struct packet_config remote_protocol_qSymbol;
+
+static void
+set_remote_protocol_qSymbol_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_qSymbol);
+}
+
+static void
+show_remote_protocol_qSymbol_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_qSymbol);
+}
+
+/* Should we try the 'e' (step over range) request? */
+static struct packet_config remote_protocol_e;
+
+static void
+set_remote_protocol_e_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_e);
+}
+
+static void
+show_remote_protocol_e_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_e);
+}
+
+
+/* Should we try the 'E' (step over range / w signal #) request? */
+static struct packet_config remote_protocol_E;
+
+static void
+set_remote_protocol_E_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_E);
+}
+
+static void
+show_remote_protocol_E_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_E);
+}
+
+
+/* Should we try the 'P' (set register) request? */
+
+static struct packet_config remote_protocol_P;
+
+static void
+set_remote_protocol_P_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_P);
+}
+
+static void
+show_remote_protocol_P_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_P);
+}
+
+/* Should we try one of the 'Z' requests? */
+
+enum Z_packet_type
+{
+ Z_PACKET_SOFTWARE_BP,
+ Z_PACKET_HARDWARE_BP,
+ Z_PACKET_WRITE_WP,
+ Z_PACKET_READ_WP,
+ Z_PACKET_ACCESS_WP,
+ NR_Z_PACKET_TYPES
+};
+
+static struct packet_config remote_protocol_Z[NR_Z_PACKET_TYPES];
+
+/* FIXME: Instead of having all these boiler plate functions, the
+ command callback should include a context argument. */
+
+static void
+set_remote_protocol_Z_software_bp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP]);
+}
+
+static void
+show_remote_protocol_Z_software_bp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP]);
+}
+
+static void
+set_remote_protocol_Z_hardware_bp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_HARDWARE_BP]);
+}
+
+static void
+show_remote_protocol_Z_hardware_bp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_HARDWARE_BP]);
+}
+
+static void
+set_remote_protocol_Z_write_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_WRITE_WP]);
+}
+
+static void
+show_remote_protocol_Z_write_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_WRITE_WP]);
+}
+
+static void
+set_remote_protocol_Z_read_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_READ_WP]);
+}
+
+static void
+show_remote_protocol_Z_read_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_READ_WP]);
+}
+
+static void
+set_remote_protocol_Z_access_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_Z[Z_PACKET_ACCESS_WP]);
+}
+
+static void
+show_remote_protocol_Z_access_wp_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_ACCESS_WP]);
+}
+
+/* For compatibility with older distributions. Provide a ``set remote
+ Z-packet ...'' command that updates all the Z packet types. */
+
+static enum auto_boolean remote_Z_packet_detect;
+
+static void
+set_remote_protocol_Z_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ int i;
+ for (i = 0; i < NR_Z_PACKET_TYPES; i++)
+ {
+ remote_protocol_Z[i].detect = remote_Z_packet_detect;
+ update_packet_config (&remote_protocol_Z[i]);
+ }
+}
+
+static void
+show_remote_protocol_Z_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ int i;
+ for (i = 0; i < NR_Z_PACKET_TYPES; i++)
+ {
+ show_packet_config_cmd (&remote_protocol_Z[i]);
+ }
+}
+
+/* Should we try the 'X' (remote binary download) packet?
+
+ This variable (available to the user via "set remote X-packet")
+ dictates whether downloads are sent in binary (via the 'X' packet).
+ We assume that the stub can, and attempt to do it. This will be
+ cleared if the stub does not understand it. This switch is still
+ needed, though in cases when the packet is supported in the stub,
+ but the connection does not allow it (i.e., 7-bit serial connection
+ only). */
+
+static struct packet_config remote_protocol_binary_download;
+
+/* Should we try the 'ThreadInfo' query packet?
+
+ This variable (NOT available to the user: auto-detect only!)
+ determines whether GDB will use the new, simpler "ThreadInfo"
+ query or the older, more complex syntax for thread queries.
+ This is an auto-detect variable (set to true at each connect,
+ and set to false when the target fails to recognize it). */
+
+static int use_threadinfo_query;
+static int use_threadextra_query;
+
+static void
+set_remote_protocol_binary_download_cmd (char *args,
+ int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_binary_download);
+}
+
+static void
+show_remote_protocol_binary_download_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_binary_download);
+}
+
+/* Should we try the 'qPart:auxv' (target auxiliary vector read) request? */
+static struct packet_config remote_protocol_qPart_auxv;
+
+static void
+set_remote_protocol_qPart_auxv_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_qPart_auxv);
+}
+
+static void
+show_remote_protocol_qPart_auxv_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_qPart_auxv);
+}
+
+/* Should we try the 'qPart:dirty' (target dirty register read) request? */
+static struct packet_config remote_protocol_qPart_dirty;
+
+static void
+set_remote_protocol_qPart_dirty_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ update_packet_config (&remote_protocol_qPart_dirty);
+}
+
+static void
+show_remote_protocol_qPart_dirty_packet_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ show_packet_config_cmd (&remote_protocol_qPart_dirty);
+}
+
+
+/* Tokens for use by the asynchronous signal handlers for SIGINT */
+static void *sigint_remote_twice_token;
+static void *sigint_remote_token;
+
+/* These are pointers to hook functions that may be set in order to
+ modify resume/wait behavior for a particular architecture. */
+
+void (*target_resume_hook) (void);
+void (*target_wait_loop_hook) (void);
+
+
+
+/* These are the threads which we last sent to the remote system.
+ -1 for all or -2 for not sent yet. */
+static int general_thread;
+static int continue_thread;
+
+/* Call this function as a result of
+ 1) A halt indication (T packet) containing a thread id
+ 2) A direct query of currthread
+ 3) Successful execution of set thread
+ */
+
+static void
+record_currthread (int currthread)
+{
+ general_thread = currthread;
+
+ /* If this is a new thread, add it to GDB's thread list.
+ If we leave it up to WFI to do this, bad things will happen. */
+ if (!in_thread_list (pid_to_ptid (currthread)))
+ {
+ add_thread (pid_to_ptid (currthread));
+ ui_out_text (uiout, "[New ");
+ ui_out_text (uiout, target_pid_to_str (pid_to_ptid (currthread)));
+ ui_out_text (uiout, "]\n");
+ }
+}
+
+#define MAGIC_NULL_PID 42000
+
+static void
+set_thread (int th, int gen)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ int state = gen ? general_thread : continue_thread;
+
+ if (state == th)
+ return;
+
+ buf[0] = 'H';
+ buf[1] = gen ? 'g' : 'c';
+ if (th == MAGIC_NULL_PID)
+ {
+ 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, (rs->remote_packet_size), 0);
+ if (gen)
+ general_thread = th;
+ else
+ continue_thread = th;
+}
+
+/* Return nonzero if the thread TH is still alive on the remote system. */
+
+static int
+remote_thread_alive (ptid_t ptid)
+{
+ int tid = PIDGET (ptid);
+ char buf[16];
+
+ if (tid < 0)
+ sprintf (buf, "T-%08x", -tid);
+ else
+ sprintf (buf, "T%08x", tid);
+ putpkt (buf);
+ getpkt (buf, sizeof (buf), 0);
+ return (buf[0] == 'O' && buf[1] == 'K');
+}
+
+/* About these extended threadlist and threadinfo packets. They are
+ variable length packets but, the fields within them are often fixed
+ length. They are redundent enough to send over UDP as is the
+ remote protocol in general. There is a matching unit test module
+ in libstub. */
+
+#define OPAQUETHREADBYTES 8
+
+/* a 64 bit opaque identifier */
+typedef unsigned char threadref[OPAQUETHREADBYTES];
+
+/* WARNING: This threadref data structure comes from the remote O.S., libstub
+ protocol encoding, and remote.c. it is not particularly changable */
+
+/* Right now, the internal structure is int. We want it to be bigger.
+ Plan to fix this.
+ */
+
+typedef int gdb_threadref; /* internal GDB thread reference */
+
+/* gdb_ext_thread_info is an internal GDB data structure which is
+ equivalint to the reply of the remote threadinfo packet */
+
+struct gdb_ext_thread_info
+ {
+ threadref threadid; /* External form of thread reference */
+ int active; /* Has state interesting to GDB? , regs, stack */
+ char display[256]; /* Brief state display, name, blocked/syspended */
+ char shortname[32]; /* To be used to name threads */
+ char more_display[256]; /* Long info, statistics, queue depth, whatever */
+ };
+
+/* The volume of remote transfers can be limited by submitting
+ a mask containing bits specifying the desired information.
+ Use a union of these values as the 'selection' parameter to
+ get_thread_info. FIXME: Make these TAG names more thread specific.
+ */
+
+#define TAG_THREADID 1
+#define TAG_EXISTS 2
+#define TAG_DISPLAY 4
+#define TAG_THREADNAME 8
+#define TAG_MOREDISPLAY 16
+
+#define BUF_THREAD_ID_SIZE (OPAQUETHREADBYTES*2)
+
+char *unpack_varlen_hex (char *buff, ULONGEST *result);
+
+static char *unpack_nibble (char *buf, int *val);
+
+static char *pack_nibble (char *buf, int nibble);
+
+static char *pack_hex_byte (char *pkt, int /*unsigned char */ byte);
+
+static char *unpack_byte (char *buf, int *value);
+
+static char *pack_int (char *buf, int value);
+
+static char *unpack_int (char *buf, int *value);
+
+static char *unpack_string (char *src, char *dest, int length);
+
+static char *pack_threadid (char *pkt, threadref * id);
+
+static char *unpack_threadid (char *inbuf, threadref * id);
+
+void int_to_threadref (threadref * id, int value);
+
+static int threadref_to_int (threadref * ref);
+
+static void copy_threadref (threadref * dest, threadref * src);
+
+static int threadmatch (threadref * dest, threadref * src);
+
+static char *pack_threadinfo_request (char *pkt, int mode, threadref * id);
+
+static int remote_unpack_thread_info_response (char *pkt,
+ threadref * expectedref,
+ struct gdb_ext_thread_info
+ *info);
+
+
+static int remote_get_threadinfo (threadref * threadid, int fieldset, /*TAG mask */
+ struct gdb_ext_thread_info *info);
+
+static char *pack_threadlist_request (char *pkt, int startflag,
+ int threadcount,
+ threadref * nextthread);
+
+static int parse_threadlist_response (char *pkt,
+ int result_limit,
+ threadref * original_echo,
+ threadref * resultlist, int *doneflag);
+
+static int remote_get_threadlist (int startflag,
+ threadref * nextthread,
+ int result_limit,
+ int *done,
+ int *result_count, threadref * threadlist);
+
+typedef int (*rmt_thread_action) (threadref * ref, void *context);
+
+static int remote_threadlist_iterator (rmt_thread_action stepfunction,
+ void *context, int looplimit);
+
+static int remote_newthread_step (threadref * ref, void *context);
+
+/* encode 64 bits in 16 chars of hex */
+
+static const char hexchars[] = "0123456789abcdef";
+
+static int
+ishex (int ch, int *val)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ {
+ *val = ch - 'a' + 10;
+ return 1;
+ }
+ if ((ch >= 'A') && (ch <= 'F'))
+ {
+ *val = ch - 'A' + 10;
+ return 1;
+ }
+ if ((ch >= '0') && (ch <= '9'))
+ {
+ *val = ch - '0';
+ return 1;
+ }
+ return 0;
+}
+
+static int
+stubhex (int ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch - 'a' + 10;
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch - 'A' + 10;
+ return -1;
+}
+
+static int
+stub_unpack_int (char *buff, int fieldlength)
+{
+ int nibble;
+ int retval = 0;
+
+ while (fieldlength)
+ {
+ nibble = stubhex (*buff++);
+ retval |= nibble;
+ fieldlength--;
+ if (fieldlength)
+ retval = retval << 4;
+ }
+ return retval;
+}
+
+char *
+unpack_varlen_hex (char *buff, /* packet to parse */
+ ULONGEST *result)
+{
+ int nibble;
+ int retval = 0;
+
+ while (ishex (*buff, &nibble))
+ {
+ buff++;
+ retval = retval << 4;
+ retval |= nibble & 0x0f;
+ }
+ *result = retval;
+ return buff;
+}
+
+static char *
+unpack_nibble (char *buf, int *val)
+{
+ ishex (*buf++, val);
+ return buf;
+}
+
+static char *
+pack_nibble (char *buf, int nibble)
+{
+ *buf++ = hexchars[(nibble & 0x0f)];
+ return buf;
+}
+
+static char *
+pack_hex_byte (char *pkt, int byte)
+{
+ *pkt++ = hexchars[(byte >> 4) & 0xf];
+ *pkt++ = hexchars[(byte & 0xf)];
+ return pkt;
+}
+
+static char *
+unpack_byte (char *buf, int *value)
+{
+ *value = stub_unpack_int (buf, 2);
+ return buf + 2;
+}
+
+static char *
+pack_int (char *buf, int value)
+{
+ buf = pack_hex_byte (buf, (value >> 24) & 0xff);
+ buf = pack_hex_byte (buf, (value >> 16) & 0xff);
+ buf = pack_hex_byte (buf, (value >> 8) & 0x0ff);
+ buf = pack_hex_byte (buf, (value & 0xff));
+ return buf;
+}
+
+static char *
+unpack_int (char *buf, int *value)
+{
+ *value = stub_unpack_int (buf, 8);
+ return buf + 8;
+}
+
+#if 0 /* currently unused, uncomment when needed */
+static char *pack_string (char *pkt, char *string);
+
+static char *
+pack_string (char *pkt, char *string)
+{
+ char ch;
+ int len;
+
+ len = strlen (string);
+ if (len > 200)
+ len = 200; /* Bigger than most GDB packets, junk??? */
+ pkt = pack_hex_byte (pkt, len);
+ while (len-- > 0)
+ {
+ ch = *string++;
+ if ((ch == '\0') || (ch == '#'))
+ ch = '*'; /* Protect encapsulation */
+ *pkt++ = ch;
+ }
+ return pkt;
+}
+#endif /* 0 (unused) */
+
+static char *
+unpack_string (char *src, char *dest, int length)
+{
+ while (length--)
+ *dest++ = *src++;
+ *dest = '\0';
+ return src;
+}
+
+static char *
+pack_threadid (char *pkt, threadref *id)
+{
+ char *limit;
+ unsigned char *altid;
+
+ altid = (unsigned char *) id;
+ limit = pkt + BUF_THREAD_ID_SIZE;
+ while (pkt < limit)
+ pkt = pack_hex_byte (pkt, *altid++);
+ return pkt;
+}
+
+
+static char *
+unpack_threadid (char *inbuf, threadref *id)
+{
+ char *altref;
+ char *limit = inbuf + BUF_THREAD_ID_SIZE;
+ int x, y;
+
+ altref = (char *) id;
+
+ while (inbuf < limit)
+ {
+ x = stubhex (*inbuf++);
+ y = stubhex (*inbuf++);
+ *altref++ = (x << 4) | y;
+ }
+ return inbuf;
+}
+
+/* Externally, threadrefs are 64 bits but internally, they are still
+ ints. This is due to a mismatch of specifications. We would like
+ to use 64bit thread references internally. This is an adapter
+ function. */
+
+void
+int_to_threadref (threadref *id, int value)
+{
+ unsigned char *scan;
+
+ scan = (unsigned char *) id;
+ {
+ int i = 4;
+ while (i--)
+ *scan++ = 0;
+ }
+ *scan++ = (value >> 24) & 0xff;
+ *scan++ = (value >> 16) & 0xff;
+ *scan++ = (value >> 8) & 0xff;
+ *scan++ = (value & 0xff);
+}
+
+static int
+threadref_to_int (threadref *ref)
+{
+ int i, value = 0;
+ unsigned char *scan;
+
+ scan = (char *) ref;
+ scan += 4;
+ i = 4;
+ while (i-- > 0)
+ value = (value << 8) | ((*scan++) & 0xff);
+ return value;
+}
+
+static void
+copy_threadref (threadref *dest, threadref *src)
+{
+ int i;
+ unsigned char *csrc, *cdest;
+
+ csrc = (unsigned char *) src;
+ cdest = (unsigned char *) dest;
+ i = 8;
+ while (i--)
+ *cdest++ = *csrc++;
+}
+
+static int
+threadmatch (threadref *dest, threadref *src)
+{
+ /* things are broken right now, so just assume we got a match */
+#if 0
+ unsigned char *srcp, *destp;
+ int i, result;
+ srcp = (char *) src;
+ destp = (char *) dest;
+
+ result = 1;
+ while (i-- > 0)
+ result &= (*srcp++ == *destp++) ? 1 : 0;
+ return result;
+#endif
+ return 1;
+}
+
+/*
+ threadid:1, # always request threadid
+ context_exists:2,
+ display:4,
+ unique_name:8,
+ more_display:16
+ */
+
+/* Encoding: 'Q':8,'P':8,mask:32,threadid:64 */
+
+static char *
+pack_threadinfo_request (char *pkt, int mode, threadref *id)
+{
+ *pkt++ = 'q'; /* Info Query */
+ *pkt++ = 'P'; /* process or thread info */
+ pkt = pack_int (pkt, mode); /* mode */
+ pkt = pack_threadid (pkt, id); /* threadid */
+ *pkt = '\0'; /* terminate */
+ return pkt;
+}
+
+/* These values tag the fields in a thread info response packet */
+/* Tagging the fields allows us to request specific fields and to
+ add more fields as time goes by */
+
+#define TAG_THREADID 1 /* Echo the thread identifier */
+#define TAG_EXISTS 2 /* Is this process defined enough to
+ fetch registers and its stack */
+#define TAG_DISPLAY 4 /* A short thing maybe to put on a window */
+#define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */
+#define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about
+ the process */
+
+static int
+remote_unpack_thread_info_response (char *pkt, threadref *expectedref,
+ struct gdb_ext_thread_info *info)
+{
+ struct remote_state *rs = get_remote_state ();
+ int mask, length;
+ unsigned int tag;
+ threadref ref;
+ char *limit = pkt + (rs->remote_packet_size); /* plausable parsing limit */
+ int retval = 1;
+
+ /* info->threadid = 0; FIXME: implement zero_threadref */
+ info->active = 0;
+ info->display[0] = '\0';
+ info->shortname[0] = '\0';
+ info->more_display[0] = '\0';
+
+ /* Assume the characters indicating the packet type have been stripped */
+ pkt = unpack_int (pkt, &mask); /* arg mask */
+ pkt = unpack_threadid (pkt, &ref);
+
+ if (mask == 0)
+ warning ("Incomplete response to threadinfo request\n");
+ if (!threadmatch (&ref, expectedref))
+ { /* This is an answer to a different request */
+ warning ("ERROR RMT Thread info mismatch\n");
+ return 0;
+ }
+ copy_threadref (&info->threadid, &ref);
+
+ /* Loop on tagged fields , try to bail if somthing goes wrong */
+
+ while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */
+ {
+ pkt = unpack_int (pkt, &tag); /* tag */
+ pkt = unpack_byte (pkt, &length); /* length */
+ if (!(tag & mask)) /* tags out of synch with mask */
+ {
+ warning ("ERROR RMT: threadinfo tag mismatch\n");
+ retval = 0;
+ break;
+ }
+ if (tag == TAG_THREADID)
+ {
+ if (length != 16)
+ {
+ warning ("ERROR RMT: length of threadid is not 16\n");
+ retval = 0;
+ break;
+ }
+ pkt = unpack_threadid (pkt, &ref);
+ mask = mask & ~TAG_THREADID;
+ continue;
+ }
+ if (tag == TAG_EXISTS)
+ {
+ info->active = stub_unpack_int (pkt, length);
+ pkt += length;
+ mask = mask & ~(TAG_EXISTS);
+ if (length > 8)
+ {
+ warning ("ERROR RMT: 'exists' length too long\n");
+ retval = 0;
+ break;
+ }
+ continue;
+ }
+ if (tag == TAG_THREADNAME)
+ {
+ pkt = unpack_string (pkt, &info->shortname[0], length);
+ mask = mask & ~TAG_THREADNAME;
+ continue;
+ }
+ if (tag == TAG_DISPLAY)
+ {
+ pkt = unpack_string (pkt, &info->display[0], length);
+ mask = mask & ~TAG_DISPLAY;
+ continue;
+ }
+ if (tag == TAG_MOREDISPLAY)
+ {
+ pkt = unpack_string (pkt, &info->more_display[0], length);
+ mask = mask & ~TAG_MOREDISPLAY;
+ continue;
+ }
+ warning ("ERROR RMT: unknown thread info tag\n");
+ break; /* Not a tag we know about */
+ }
+ return retval;
+}
+
+static int
+remote_get_threadinfo (threadref *threadid, int fieldset, /* TAG mask */
+ struct gdb_ext_thread_info *info)
+{
+ struct remote_state *rs = get_remote_state ();
+ int result;
+ char *threadinfo_pkt = alloca (rs->remote_packet_size);
+
+ pack_threadinfo_request (threadinfo_pkt, fieldset, threadid);
+ putpkt (threadinfo_pkt);
+ getpkt (threadinfo_pkt, (rs->remote_packet_size), 0);
+ result = remote_unpack_thread_info_response (threadinfo_pkt + 2, threadid,
+ info);
+ return result;
+}
+
+/* Format: i'Q':8,i"L":8,initflag:8,batchsize:16,lastthreadid:32 */
+
+static char *
+pack_threadlist_request (char *pkt, int startflag, int threadcount,
+ threadref *nextthread)
+{
+ *pkt++ = 'q'; /* info query packet */
+ *pkt++ = 'L'; /* Process LIST or threadLIST request */
+ pkt = pack_nibble (pkt, startflag); /* initflag 1 bytes */
+ pkt = pack_hex_byte (pkt, threadcount); /* threadcount 2 bytes */
+ pkt = pack_threadid (pkt, nextthread); /* 64 bit thread identifier */
+ *pkt = '\0';
+ return pkt;
+}
+
+/* Encoding: 'q':8,'M':8,count:16,done:8,argthreadid:64,(threadid:64)* */
+
+static int
+parse_threadlist_response (char *pkt, int result_limit,
+ threadref *original_echo, threadref *resultlist,
+ int *doneflag)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *limit;
+ int count, resultcount, done;
+
+ resultcount = 0;
+ /* Assume the 'q' and 'M chars have been stripped. */
+ limit = pkt + ((rs->remote_packet_size) - BUF_THREAD_ID_SIZE); /* done parse past here */
+ pkt = unpack_byte (pkt, &count); /* count field */
+ pkt = unpack_nibble (pkt, &done);
+ /* The first threadid is the argument threadid. */
+ pkt = unpack_threadid (pkt, original_echo); /* should match query packet */
+ while ((count-- > 0) && (pkt < limit))
+ {
+ pkt = unpack_threadid (pkt, resultlist++);
+ if (resultcount++ >= result_limit)
+ break;
+ }
+ if (doneflag)
+ *doneflag = done;
+ return resultcount;
+}
+
+static int
+remote_get_threadlist (int startflag, threadref *nextthread, int result_limit,
+ int *done, int *result_count, threadref *threadlist)
+{
+ struct remote_state *rs = get_remote_state ();
+ static threadref echo_nextthread;
+ char *threadlist_packet = alloca (rs->remote_packet_size);
+ char *t_response = alloca (rs->remote_packet_size);
+ int result = 1;
+
+ /* Trancate result limit to be smaller than the packet size */
+ if ((((result_limit + 1) * BUF_THREAD_ID_SIZE) + 10) >= (rs->remote_packet_size))
+ result_limit = ((rs->remote_packet_size) / BUF_THREAD_ID_SIZE) - 2;
+
+ pack_threadlist_request (threadlist_packet,
+ startflag, result_limit, nextthread);
+ putpkt (threadlist_packet);
+ getpkt (t_response, (rs->remote_packet_size), 0);
+
+ *result_count =
+ parse_threadlist_response (t_response + 2, result_limit, &echo_nextthread,
+ threadlist, done);
+
+ if (!threadmatch (&echo_nextthread, nextthread))
+ {
+ /* FIXME: This is a good reason to drop the packet */
+ /* Possably, there is a duplicate response */
+ /* Possabilities :
+ retransmit immediatly - race conditions
+ retransmit after timeout - yes
+ exit
+ wait for packet, then exit
+ */
+ warning ("HMM: threadlist did not echo arg thread, dropping it\n");
+ return 0; /* I choose simply exiting */
+ }
+ if (*result_count <= 0)
+ {
+ if (*done != 1)
+ {
+ warning ("RMT ERROR : failed to get remote thread list\n");
+ result = 0;
+ }
+ return result; /* break; */
+ }
+ if (*result_count > result_limit)
+ {
+ *result_count = 0;
+ warning ("RMT ERROR: threadlist response longer than requested\n");
+ return 0;
+ }
+ return result;
+}
+
+/* This is the interface between remote and threads, remotes upper interface */
+
+/* remote_find_new_threads retrieves the thread list and for each
+ thread in the list, looks up the thread in GDB's internal list,
+ ading the thread if it does not already exist. This involves
+ getting partial thread lists from the remote target so, polling the
+ quit_flag is required. */
+
+
+/* About this many threadisds fit in a packet. */
+
+#define MAXTHREADLISTRESULTS 32
+
+static int
+remote_threadlist_iterator (rmt_thread_action stepfunction, void *context,
+ int looplimit)
+{
+ int done, i, result_count;
+ int startflag = 1;
+ int result = 1;
+ int loopcount = 0;
+ static threadref nextthread;
+ static threadref resultthreadlist[MAXTHREADLISTRESULTS];
+
+ done = 0;
+ while (!done)
+ {
+ if (loopcount++ > looplimit)
+ {
+ result = 0;
+ warning ("Remote fetch threadlist -infinite loop-\n");
+ break;
+ }
+ if (!remote_get_threadlist (startflag, &nextthread, MAXTHREADLISTRESULTS,
+ &done, &result_count, resultthreadlist))
+ {
+ result = 0;
+ break;
+ }
+ /* clear for later iterations */
+ startflag = 0;
+ /* Setup to resume next batch of thread references, set nextthread. */
+ if (result_count >= 1)
+ copy_threadref (&nextthread, &resultthreadlist[result_count - 1]);
+ i = 0;
+ while (result_count--)
+ if (!(result = (*stepfunction) (&resultthreadlist[i++], context)))
+ break;
+ }
+ return result;
+}
+
+static int
+remote_newthread_step (threadref *ref, void *context)
+{
+ ptid_t ptid;
+
+ ptid = pid_to_ptid (threadref_to_int (ref));
+
+ if (!in_thread_list (ptid))
+ add_thread (ptid);
+ return 1; /* continue iterator */
+}
+
+#define CRAZY_MAX_THREADS 1000
+
+static ptid_t
+remote_current_thread (ptid_t oldpid)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+
+ putpkt ("qC");
+ getpkt (buf, (rs->remote_packet_size), 0);
+ if (buf[0] == 'Q' && buf[1] == 'C')
+ return pid_to_ptid (strtol (&buf[2], NULL, 16));
+ else
+ return oldpid;
+}
+
+/* Find new threads for info threads command.
+ * Original version, using John Metzler's thread protocol.
+ */
+
+static void
+remote_find_new_threads (void)
+{
+ remote_threadlist_iterator (remote_newthread_step, 0,
+ CRAZY_MAX_THREADS);
+ if (PIDGET (inferior_ptid) == MAGIC_NULL_PID) /* ack ack ack */
+ inferior_ptid = remote_current_thread (inferior_ptid);
+}
+
+/*
+ * Find all threads for info threads command.
+ * Uses new thread protocol contributed by Cisco.
+ * Falls back and attempts to use the older method (above)
+ * if the target doesn't respond to the new method.
+ */
+
+static void
+remote_threads_info (void)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ char *bufp;
+ int tid;
+
+ if (remote_desc == 0) /* paranoia */
+ error ("Command can only be used when connected to the remote target.");
+
+ if (use_threadinfo_query)
+ {
+ putpkt ("qfThreadInfo");
+ bufp = buf;
+ getpkt (bufp, (rs->remote_packet_size), 0);
+ if (bufp[0] != '\0') /* q packet recognized */
+ {
+ while (*bufp++ == 'm') /* reply contains one or more TID */
+ {
+ do
+ {
+ tid = strtol (bufp, &bufp, 16);
+ if (tid != 0 && !in_thread_list (pid_to_ptid (tid)))
+ add_thread (pid_to_ptid (tid));
+ }
+ while (*bufp++ == ','); /* comma-separated list */
+ putpkt ("qsThreadInfo");
+ bufp = buf;
+ getpkt (bufp, (rs->remote_packet_size), 0);
+ }
+ return; /* done */
+ }
+ }
+
+ /* Else fall back to old method based on jmetzler protocol. */
+ use_threadinfo_query = 0;
+ remote_find_new_threads ();
+ return;
+}
+
+/*
+ * Collect a descriptive string about the given thread.
+ * The target may say anything it wants to about the thread
+ * (typically info about its blocked / runnable state, name, etc.).
+ * This string will appear in the info threads display.
+ *
+ * Optional: targets are not required to implement this function.
+ */
+
+static char *
+remote_threads_extra_info (struct thread_info *tp)
+{
+ struct remote_state *rs = get_remote_state ();
+ int result;
+ int set;
+ threadref id;
+ struct gdb_ext_thread_info threadinfo;
+ static char display_buf[100]; /* arbitrary... */
+ char *bufp = alloca (rs->remote_packet_size);
+ int n = 0; /* position in display_buf */
+
+ if (remote_desc == 0) /* paranoia */
+ internal_error (__FILE__, __LINE__,
+ "remote_threads_extra_info");
+
+ if (use_threadextra_query)
+ {
+ sprintf (bufp, "qThreadExtraInfo,%x", PIDGET (tp->ptid));
+ putpkt (bufp);
+ getpkt (bufp, (rs->remote_packet_size), 0);
+ if (bufp[0] != 0)
+ {
+ n = min (strlen (bufp) / 2, sizeof (display_buf));
+ result = hex2bin (bufp, display_buf, n);
+ display_buf [result] = '\0';
+ return display_buf;
+ }
+ }
+
+ /* If the above query fails, fall back to the old method. */
+ use_threadextra_query = 0;
+ set = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME
+ | TAG_MOREDISPLAY | TAG_DISPLAY;
+ int_to_threadref (&id, PIDGET (tp->ptid));
+ if (remote_get_threadinfo (&id, set, &threadinfo))
+ if (threadinfo.active)
+ {
+ if (*threadinfo.shortname)
+ n += sprintf(&display_buf[0], " Name: %s,", threadinfo.shortname);
+ if (*threadinfo.display)
+ n += sprintf(&display_buf[n], " State: %s,", threadinfo.display);
+ if (*threadinfo.more_display)
+ n += sprintf(&display_buf[n], " Priority: %s",
+ threadinfo.more_display);
+
+ if (n > 0)
+ {
+ /* for purely cosmetic reasons, clear up trailing commas */
+ if (',' == display_buf[n-1])
+ display_buf[n-1] = ' ';
+ return display_buf;
+ }
+ }
+ return NULL;
+}
+
+
+
+/* Restart the remote side; this is an extended protocol operation. */
+
+static void
+extended_remote_restart (void)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+
+ /* 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, (rs->remote_packet_size), 0);
+}
+
+/* Clean up connection to a remote debugger. */
+
+static void
+remote_close (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 (void)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ char *ptr;
+ int lose;
+ CORE_ADDR text_addr, data_addr, bss_addr;
+ struct section_offsets *offs;
+
+ putpkt ("qOffsets");
+
+ getpkt (buf, (rs->remote_packet_size), 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;
+ }
+
+ /* Pick up each field in turn. This used to be done with scanf, but
+ scanf will make trouble if CORE_ADDR size doesn't match
+ conversion directives correctly. The following code will work
+ with any size of CORE_ADDR. */
+ text_addr = data_addr = bss_addr = 0;
+ ptr = buf;
+ lose = 0;
+
+ if (strncmp (ptr, "Text=", 5) == 0)
+ {
+ ptr += 5;
+ /* Don't use strtol, could lose on big values. */
+ while (*ptr && *ptr != ';')
+ text_addr = (text_addr << 4) + fromhex (*ptr++);
+ }
+ else
+ lose = 1;
+
+ if (!lose && strncmp (ptr, ";Data=", 6) == 0)
+ {
+ ptr += 6;
+ while (*ptr && *ptr != ';')
+ data_addr = (data_addr << 4) + fromhex (*ptr++);
+ }
+ else
+ lose = 1;
+
+ if (!lose && strncmp (ptr, ";Bss=", 5) == 0)
+ {
+ ptr += 5;
+ while (*ptr && *ptr != ';')
+ bss_addr = (bss_addr << 4) + fromhex (*ptr++);
+ }
+ else
+ lose = 1;
+
+ if (lose)
+ error ("Malformed response to offset query, %s", buf);
+
+ if (symfile_objfile == NULL)
+ return;
+
+ offs = ((struct section_offsets *)
+ alloca (SIZEOF_N_SECTION_OFFSETS (symfile_objfile->num_sections)));
+ memcpy (offs, symfile_objfile->section_offsets,
+ SIZEOF_N_SECTION_OFFSETS (symfile_objfile->num_sections));
+
+ offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = 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. */
+
+ offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_addr;
+ offs->offsets[SECT_OFF_BSS (symfile_objfile)] = data_addr;
+
+ objfile_relocate (symfile_objfile, offs);
+}
+
+/* Stub for catch_errors. */
+
+static int
+remote_start_remote_dummy (struct ui_out *uiout, void *dummy)
+{
+ start_remote (); /* Initialize gdb process mechanisms */
+ /* NOTE: Return something >=0. A -ve value is reserved for
+ catch_exceptions. */
+ return 1;
+}
+
+static int
+remote_start_remote (struct ui_out *uiout, void *dummy)
+{
+ immediate_quit++; /* 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);
+
+ inferior_ptid = remote_current_thread (inferior_ptid);
+
+ get_offsets (); /* Get text, data & bss offsets */
+
+ putpkt ("?"); /* initiate a query from remote machine */
+ immediate_quit--;
+
+ /* NOTE: See comment above in remote_start_remote_dummy(). This
+ function returns something >=0. */
+ return remote_start_remote_dummy (uiout, dummy);
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static void
+remote_open (char *name, int from_tty)
+{
+ remote_open_1 (name, from_tty, &remote_ops, 0, 0);
+}
+
+/* Just like remote_open, but with asynchronous support. */
+static void
+remote_async_open (char *name, int from_tty)
+{
+ remote_open_1 (name, from_tty, &remote_async_ops, 0, 1);
+}
+
+/* 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 (char *name, int from_tty)
+{
+ remote_open_1 (name, from_tty, &extended_remote_ops, 1 /*extended_p */,
+ 0 /* async_p */);
+}
+
+/* Just like extended_remote_open, but with asynchronous support. */
+static void
+extended_remote_async_open (char *name, int from_tty)
+{
+ remote_open_1 (name, from_tty, &extended_async_remote_ops,
+ 1 /*extended_p */, 1 /* async_p */);
+}
+
+/* Generic code for opening a connection to a remote target. */
+
+static void
+init_all_packet_configs (void)
+{
+ int i;
+ update_packet_config (&remote_protocol_e);
+ update_packet_config (&remote_protocol_E);
+ update_packet_config (&remote_protocol_P);
+ update_packet_config (&remote_protocol_qSymbol);
+ update_packet_config (&remote_protocol_vcont);
+ for (i = 0; i < NR_Z_PACKET_TYPES; i++)
+ update_packet_config (&remote_protocol_Z[i]);
+ /* Force remote_write_bytes to check whether target supports binary
+ downloading. */
+ update_packet_config (&remote_protocol_binary_download);
+ update_packet_config (&remote_protocol_qPart_auxv);
+ update_packet_config (&remote_protocol_qPart_dirty);
+}
+
+/* Symbol look-up. */
+
+static void
+remote_check_symbols (struct objfile *objfile)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *msg, *reply, *tmp;
+ struct minimal_symbol *sym;
+ int end;
+
+ if (remote_protocol_qSymbol.support == PACKET_DISABLE)
+ return;
+
+ msg = alloca (rs->remote_packet_size);
+ reply = alloca (rs->remote_packet_size);
+
+ /* Invite target to request symbol lookups. */
+
+ putpkt ("qSymbol::");
+ getpkt (reply, (rs->remote_packet_size), 0);
+ packet_ok (reply, &remote_protocol_qSymbol);
+
+ while (strncmp (reply, "qSymbol:", 8) == 0)
+ {
+ tmp = &reply[8];
+ end = hex2bin (tmp, msg, strlen (tmp) / 2);
+ msg[end] = '\0';
+ sym = lookup_minimal_symbol (msg, NULL, NULL);
+ if (sym == NULL)
+ sprintf (msg, "qSymbol::%s", &reply[8]);
+ else
+ sprintf (msg, "qSymbol:%s:%s",
+ paddr_nz (SYMBOL_VALUE_ADDRESS (sym)),
+ &reply[8]);
+ putpkt (msg);
+ getpkt (reply, (rs->remote_packet_size), 0);
+ }
+}
+
+static struct serial *
+remote_serial_open (char *name)
+{
+ static int udp_warning = 0;
+
+ /* FIXME: Parsing NAME here is a hack. But we want to warn here instead
+ of in ser-tcp.c, because it is the remote protocol assuming that the
+ serial connection is reliable and not the serial connection promising
+ to be. */
+ if (!udp_warning && strncmp (name, "udp:", 4) == 0)
+ {
+ warning ("The remote protocol may be unreliable over UDP.");
+ warning ("Some events may be lost, rendering further debugging "
+ "impossible.");
+ udp_warning = 1;
+ }
+
+ return serial_open (name);
+}
+
+static void
+remote_open_1 (char *name, int from_tty, struct target_ops *target,
+ int extended_p, int async_p)
+{
+ int ex;
+ struct remote_state *rs = get_remote_state ();
+ if (name == 0)
+ error ("To open a remote debug connection, you need to specify what\n"
+ "serial device is attached to the remote system\n"
+ "(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.).");
+
+ /* See FIXME above */
+ if (!async_p)
+ wait_forever_enabled_p = 1;
+
+ target_preopen (from_tty);
+
+ unpush_target (target);
+
+ remote_desc = remote_serial_open (name);
+ if (!remote_desc)
+ perror_with_name (name);
+
+ if (baud_rate != -1)
+ {
+ if (serial_setbaudrate (remote_desc, baud_rate))
+ {
+ /* The requested speed could not be set. Error out to
+ top level after closing remote_desc. Take care to
+ set remote_desc to NULL to avoid closing remote_desc
+ more than once. */
+ serial_close (remote_desc);
+ remote_desc = NULL;
+ 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 */
+
+ init_all_packet_configs ();
+
+ general_thread = -2;
+ continue_thread = -2;
+
+ /* Probe for ability to use "ThreadInfo" query, as required. */
+ use_threadinfo_query = 1;
+ use_threadextra_query = 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_ptid = pid_to_ptid (MAGIC_NULL_PID);
+
+ if (async_p)
+ {
+ /* With this target we start out by owning the terminal. */
+ remote_async_terminal_ours_p = 1;
+
+ /* FIXME: cagney/1999-09-23: During the initial connection it is
+ assumed that the target is already ready and able to respond to
+ requests. Unfortunately remote_start_remote() eventually calls
+ wait_for_inferior() with no timeout. wait_forever_enabled_p gets
+ around this. Eventually a mechanism that allows
+ wait_for_inferior() to expect/get timeouts will be
+ implemented. */
+ wait_forever_enabled_p = 0;
+ }
+
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ /* First delete any symbols previously loaded from shared libraries. */
+ no_shared_libraries (NULL, 0);
+#endif
+
+ /* Start the remote connection. If error() or QUIT, discard this
+ target (we'd otherwise be in an inconsistent state) and then
+ propogate the error on up the exception chain. This ensures that
+ the caller doesn't stumble along blindly assuming that the
+ function succeeded. The CLI doesn't have this problem but other
+ UI's, such as MI do.
+
+ FIXME: cagney/2002-05-19: Instead of re-throwing the exception,
+ this function should return an error indication letting the
+ caller restore the previous state. Unfortunately the command
+ ``target remote'' is directly wired to this function making that
+ impossible. On a positive note, the CLI side of this problem has
+ been fixed - the function set_cmd_context() makes it possible for
+ all the ``target ....'' commands to share a common callback
+ function. See cli-dump.c. */
+ ex = catch_exceptions (uiout,
+ remote_start_remote, NULL,
+ "Couldn't establish connection to remote"
+ " target\n",
+ RETURN_MASK_ALL);
+ if (ex < 0)
+ {
+ pop_target ();
+ if (async_p)
+ wait_forever_enabled_p = 1;
+ throw_exception (ex);
+ }
+
+ if (async_p)
+ wait_forever_enabled_p = 1;
+
+ if (extended_p)
+ {
+ /* Tell the remote that we are using the extended protocol. */
+ char *buf = alloca (rs->remote_packet_size);
+ putpkt ("!");
+ getpkt (buf, (rs->remote_packet_size), 0);
+ }
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ /* FIXME: need a master target_open vector from which all
+ remote_opens can be called, so that stuff like this can
+ go there. Failing that, the following code must be copied
+ to the open function for any remote target that wants to
+ support svr4 shared libraries. */
+
+ /* Set up to detect and load shared libraries. */
+ if (exec_bfd) /* No use without an exec file. */
+ {
+ SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
+ remote_check_symbols (symfile_objfile);
+ }
+#endif
+}
+
+/* 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 (char *args, int from_tty)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ /* Tell the remote target to detach. */
+ strcpy (buf, "D");
+ remote_send (buf, (rs->remote_packet_size));
+
+ /* Unregister the file descriptor from the event loop. */
+ if (target_is_async_p ())
+ serial_async (remote_desc, NULL, 0);
+
+ target_mourn_inferior ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+}
+
+/* Same as remote_detach, but don't send the "D" packet; just disconnect. */
+
+static void
+remote_disconnect (char *args, int from_tty)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ /* Unregister the file descriptor from the event loop. */
+ if (target_is_async_p ())
+ serial_async (remote_desc, NULL, 0);
+
+ target_mourn_inferior ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (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 %d", a);
+}
+
+static int
+hex2bin (const char *hex, char *bin, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ if (hex[0] == 0 || hex[1] == 0)
+ {
+ /* Hex string is short, or of uneven length.
+ Return the count that has been converted so far. */
+ return i;
+ }
+ *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
+ hex += 2;
+ }
+ return i;
+}
+
+/* Convert number NIB to a hex digit. */
+
+static int
+tohex (int nib)
+{
+ if (nib < 10)
+ return '0' + nib;
+ else
+ return 'a' + nib - 10;
+}
+
+static int
+bin2hex (const char *bin, char *hex, int count)
+{
+ int i;
+ /* May use a length, or a nul-terminated string as input. */
+ if (count == 0)
+ count = strlen (bin);
+
+ for (i = 0; i < count; i++)
+ {
+ *hex++ = tohex ((*bin >> 4) & 0xf);
+ *hex++ = tohex (*bin++ & 0xf);
+ }
+ *hex = 0;
+ return i;
+}
+
+/* Check for the availability of vCont. This function should also check
+ the response. */
+
+static void
+remote_vcont_probe (struct remote_state *rs, char *buf)
+{
+ strcpy (buf, "vCont?");
+ putpkt (buf);
+ getpkt (buf, rs->remote_packet_size, 0);
+
+ /* Make sure that the features we assume are supported. */
+ if (strncmp (buf, "vCont", 5) == 0)
+ {
+ char *p = &buf[5];
+ int support_s, support_S, support_c, support_C;
+
+ support_s = 0;
+ support_S = 0;
+ support_c = 0;
+ support_C = 0;
+ while (p && *p == ';')
+ {
+ p++;
+ if (*p == 's' && (*(p + 1) == ';' || *(p + 1) == 0))
+ support_s = 1;
+ else if (*p == 'S' && (*(p + 1) == ';' || *(p + 1) == 0))
+ support_S = 1;
+ else if (*p == 'c' && (*(p + 1) == ';' || *(p + 1) == 0))
+ support_c = 1;
+ else if (*p == 'C' && (*(p + 1) == ';' || *(p + 1) == 0))
+ support_C = 1;
+
+ p = strchr (p, ';');
+ }
+
+ /* If s, S, c, and C are not all supported, we can't use vCont. Clearing
+ BUF will make packet_ok disable the packet. */
+ if (!support_s || !support_S || !support_c || !support_C)
+ buf[0] = 0;
+ }
+
+ packet_ok (buf, &remote_protocol_vcont);
+}
+
+/* Resume the remote inferior by using a "vCont" packet. The thread
+ to be resumed is PTID; STEP and SIGGNAL indicate whether the
+ resumed thread should be single-stepped and/or signalled. If PTID's
+ PID is -1, then all threads are resumed; the thread to be stepped and/or
+ signalled is given in the global INFERIOR_PTID. This function returns
+ non-zero iff it resumes the inferior.
+
+ This function issues a strict subset of all possible vCont commands at the
+ moment. */
+
+static int
+remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ struct remote_state *rs = get_remote_state ();
+ int pid = PIDGET (ptid);
+ char *buf = NULL, *outbuf;
+ struct cleanup *old_cleanup;
+
+ buf = xmalloc (rs->remote_packet_size);
+ old_cleanup = make_cleanup (xfree, buf);
+
+ if (remote_protocol_vcont.support == PACKET_SUPPORT_UNKNOWN)
+ remote_vcont_probe (rs, buf);
+
+ if (remote_protocol_vcont.support == PACKET_DISABLE)
+ {
+ do_cleanups (old_cleanup);
+ return 0;
+ }
+
+ /* If we could generate a wider range of packets, we'd have to worry
+ about overflowing BUF. Should there be a generic
+ "multi-part-packet" packet? */
+
+ if (PIDGET (inferior_ptid) == MAGIC_NULL_PID)
+ {
+ /* MAGIC_NULL_PTID means that we don't have any active threads, so we
+ don't have any PID numbers the inferior will understand. Make sure
+ to only send forms that do not specify a PID. */
+ if (step && siggnal != TARGET_SIGNAL_0)
+ outbuf = xstrprintf ("vCont;S%02x", siggnal);
+ else if (step)
+ outbuf = xstrprintf ("vCont;s");
+ else if (siggnal != TARGET_SIGNAL_0)
+ outbuf = xstrprintf ("vCont;C%02x", siggnal);
+ else
+ outbuf = xstrprintf ("vCont;c");
+ }
+ else if (pid == -1)
+ {
+ /* Resume all threads, with preference for INFERIOR_PTID. */
+ if (step && siggnal != TARGET_SIGNAL_0)
+ outbuf = xstrprintf ("vCont;S%02x:%x;c", siggnal,
+ PIDGET (inferior_ptid));
+ else if (step)
+ outbuf = xstrprintf ("vCont;s:%x;c", PIDGET (inferior_ptid));
+ else if (siggnal != TARGET_SIGNAL_0)
+ outbuf = xstrprintf ("vCont;C%02x:%x;c", siggnal,
+ PIDGET (inferior_ptid));
+ else
+ outbuf = xstrprintf ("vCont;c");
+ }
+ else
+ {
+ /* Scheduler locking; resume only PTID. */
+ if (step && siggnal != TARGET_SIGNAL_0)
+ outbuf = xstrprintf ("vCont;S%02x:%x", siggnal, pid);
+ else if (step)
+ outbuf = xstrprintf ("vCont;s:%x", pid);
+ else if (siggnal != TARGET_SIGNAL_0)
+ outbuf = xstrprintf ("vCont;C%02x:%x", siggnal, pid);
+ else
+ outbuf = xstrprintf ("vCont;c:%x", pid);
+ }
+
+ gdb_assert (outbuf && strlen (outbuf) < rs->remote_packet_size);
+ make_cleanup (xfree, outbuf);
+
+ putpkt (outbuf);
+
+ do_cleanups (old_cleanup);
+
+ return 1;
+}
+
+/* Tell the remote machine to resume. */
+
+static enum target_signal last_sent_signal = TARGET_SIGNAL_0;
+
+static int last_sent_step;
+
+static void
+remote_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ int pid = PIDGET (ptid);
+ char *p;
+
+ last_sent_signal = siggnal;
+ last_sent_step = step;
+
+ /* A hook for when we need to do something at the last moment before
+ resumption. */
+ if (target_resume_hook)
+ (*target_resume_hook) ();
+
+ /* The vCont packet doesn't need to specify threads via Hc. */
+ if (remote_vcont_resume (ptid, step, siggnal))
+ return;
+
+ /* All other supported resume packets do use Hc, so call set_thread. */
+ if (pid == -1)
+ set_thread (0, 0); /* run any thread */
+ else
+ set_thread (pid, 0); /* run this thread */
+
+ /* The s/S/c/C packets do not return status. So if the target does
+ not support the S or C packets, the debug agent returns an empty
+ string which is detected in remote_wait(). This protocol defect
+ is fixed in the e/E packets. */
+
+ if (step && step_range_end)
+ {
+ /* If the target does not support the 'E' packet, we try the 'S'
+ packet. Ideally we would fall back to the 'e' packet if that
+ too is not supported. But that would require another copy of
+ the code to issue the 'e' packet (and fall back to 's' if not
+ supported) in remote_wait(). */
+
+ if (siggnal != TARGET_SIGNAL_0)
+ {
+ if (remote_protocol_E.support != PACKET_DISABLE)
+ {
+ p = buf;
+ *p++ = 'E';
+ *p++ = tohex (((int) siggnal >> 4) & 0xf);
+ *p++ = tohex (((int) siggnal) & 0xf);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) step_range_start);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) step_range_end);
+ *p++ = 0;
+
+ putpkt (buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ if (packet_ok (buf, &remote_protocol_E) == PACKET_OK)
+ return;
+ }
+ }
+ else
+ {
+ if (remote_protocol_e.support != PACKET_DISABLE)
+ {
+ p = buf;
+ *p++ = 'e';
+ p += hexnumstr (p, (ULONGEST) step_range_start);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) step_range_end);
+ *p++ = 0;
+
+ putpkt (buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ if (packet_ok (buf, &remote_protocol_e) == PACKET_OK)
+ return;
+ }
+ }
+ }
+
+ 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);
+}
+
+/* Same as remote_resume, but with async support. */
+static void
+remote_async_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ remote_resume (ptid, step, siggnal);
+
+ /* We are about to start executing the inferior, let's register it
+ with the event loop. NOTE: this is the one place where all the
+ execution commands end up. We could alternatively do this in each
+ of the execution commands in infcmd.c.*/
+ /* FIXME: ezannoni 1999-09-28: We may need to move this out of here
+ into infcmd.c in order to allow inferior function calls to work
+ NOT asynchronously. */
+ if (event_loop_p && target_can_async_p ())
+ target_async (inferior_event_handler, 0);
+ /* Tell the world that the target is now executing. */
+ /* FIXME: cagney/1999-09-23: Is it the targets responsibility to set
+ this? Instead, should the client of target just assume (for
+ async targets) that the target is going to start executing? Is
+ this information already found in the continuation block? */
+ if (target_is_async_p ())
+ target_executing = 1;
+}
+
+
+/* Set up the signal handler for SIGINT, while the target is
+ executing, ovewriting the 'regular' SIGINT signal handler. */
+static void
+initialize_sigint_signal_handler (void)
+{
+ sigint_remote_token =
+ create_async_signal_handler (async_remote_interrupt, NULL);
+ signal (SIGINT, handle_remote_sigint);
+}
+
+/* Signal handler for SIGINT, while the target is executing. */
+static void
+handle_remote_sigint (int sig)
+{
+ signal (sig, handle_remote_sigint_twice);
+ sigint_remote_twice_token =
+ create_async_signal_handler (async_remote_interrupt_twice, NULL);
+ mark_async_signal_handler_wrapper (sigint_remote_token);
+}
+
+/* Signal handler for SIGINT, installed after SIGINT has already been
+ sent once. It will take effect the second time that the user sends
+ a ^C. */
+static void
+handle_remote_sigint_twice (int sig)
+{
+ signal (sig, handle_sigint);
+ sigint_remote_twice_token =
+ create_async_signal_handler (inferior_event_handler_wrapper, NULL);
+ mark_async_signal_handler_wrapper (sigint_remote_twice_token);
+}
+
+/* Perform the real interruption of the target execution, in response
+ to a ^C. */
+static void
+async_remote_interrupt (gdb_client_data arg)
+{
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+ target_stop ();
+}
+
+/* Perform interrupt, if the first attempt did not succeed. Just give
+ up on the target alltogether. */
+void
+async_remote_interrupt_twice (gdb_client_data arg)
+{
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_interrupt_twice called\n");
+ /* Do something only if the target was not killed by the previous
+ cntl-C. */
+ if (target_executing)
+ {
+ interrupt_query ();
+ signal (SIGINT, handle_remote_sigint);
+ }
+}
+
+/* Reinstall the usual SIGINT handlers, after the target has
+ stopped. */
+static void
+cleanup_sigint_signal_handler (void *dummy)
+{
+ signal (SIGINT, handle_sigint);
+ if (sigint_remote_twice_token)
+ delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_twice_token);
+ if (sigint_remote_token)
+ delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_token);
+}
+
+/* Send ^C to target to halt it. Target will respond, and send us a
+ packet. */
+static void (*ofunc) (int);
+
+/* The command line interface's stop routine. This function is installed
+ as a signal handler for SIGINT. The first time a user requests a
+ stop, we call remote_stop to send a break or ^C. If there is no
+ response from the target (it didn't stop when the user requested it),
+ we ask the user if he'd like to detach from the target. */
+static void
+remote_interrupt (int signo)
+{
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, remote_interrupt_twice);
+
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+ target_stop ();
+}
+
+/* The user typed ^C twice. */
+
+static void
+remote_interrupt_twice (int signo)
+{
+ signal (signo, ofunc);
+ interrupt_query ();
+ signal (signo, remote_interrupt);
+}
+
+/* This is the generic stop called via the target vector. When a target
+ interrupt is requested, either by the command line or the GUI, we
+ will eventually end up here. */
+static void
+remote_stop (void)
+{
+ /* Send a break or a ^C, depending on user preference. */
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_stop called\n");
+
+ if (remote_break)
+ serial_send_break (remote_desc);
+ else
+ serial_write (remote_desc, "\003", 1);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+interrupt_query (void)
+{
+ target_terminal_ours ();
+
+ if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+ {
+ target_mourn_inferior ();
+ throw_exception (RETURN_QUIT);
+ }
+
+ target_terminal_inferior ();
+}
+
+/* Enable/disable target terminal ownership. Most targets can use
+ terminal groups to control terminal ownership. Remote targets are
+ different in that explicit transfer of ownership to/from GDB/target
+ is required. */
+
+static void
+remote_async_terminal_inferior (void)
+{
+ /* FIXME: cagney/1999-09-27: Shouldn't need to test for
+ sync_execution here. This function should only be called when
+ GDB is resuming the inferior in the forground. A background
+ resume (``run&'') should leave GDB in control of the terminal and
+ consequently should not call this code. */
+ if (!sync_execution)
+ return;
+ /* FIXME: cagney/1999-09-27: Closely related to the above. Make
+ calls target_terminal_*() idenpotent. The event-loop GDB talking
+ to an asynchronous target with a synchronous command calls this
+ function from both event-top.c and infrun.c/infcmd.c. Once GDB
+ stops trying to transfer the terminal to the target when it
+ shouldn't this guard can go away. */
+ if (!remote_async_terminal_ours_p)
+ return;
+ delete_file_handler (input_fd);
+ remote_async_terminal_ours_p = 0;
+ initialize_sigint_signal_handler ();
+ /* NOTE: At this point we could also register our selves as the
+ recipient of all input. Any characters typed could then be
+ passed on down to the target. */
+}
+
+static void
+remote_async_terminal_ours (void)
+{
+ /* See FIXME in remote_async_terminal_inferior. */
+ if (!sync_execution)
+ return;
+ /* See FIXME in remote_async_terminal_inferior. */
+ if (remote_async_terminal_ours_p)
+ return;
+ cleanup_sigint_signal_handler (NULL);
+ add_file_handler (input_fd, stdin_event_handler, 0);
+ remote_async_terminal_ours_p = 1;
+}
+
+/* If nonzero, ignore the next kill. */
+
+int kill_kludge;
+
+void
+remote_console_output (char *msg)
+{
+ char *p;
+
+ for (p = msg; p[0] && p[1]; p += 2)
+ {
+ char tb[2];
+ char c = fromhex (p[0]) * 16 + fromhex (p[1]);
+ tb[0] = c;
+ tb[1] = 0;
+ fputs_unfiltered (tb, gdb_stdtarg);
+ }
+ gdb_flush (gdb_stdtarg);
+}
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would.
+ Returns "pid", which in the case of a multi-threaded
+ remote OS, is the thread-id. */
+
+static ptid_t
+remote_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ struct remote_state *rs = get_remote_state ();
+ unsigned char *buf = alloca (rs->remote_packet_size);
+ ULONGEST thread_num = -1;
+ ULONGEST addr;
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ while (1)
+ {
+ unsigned char *p;
+
+ ofunc = signal (SIGINT, remote_interrupt);
+ getpkt (buf, (rs->remote_packet_size), 1);
+ signal (SIGINT, ofunc);
+
+ /* This is a hook for when we need to do something (perhaps the
+ collection of trace data) every time the target stops. */
+ if (target_wait_loop_hook)
+ (*target_wait_loop_hook) ();
+
+ remote_stopped_by_watchpoint_p = 0;
+
+ switch (buf[0])
+ {
+ case 'E': /* Error of some sort */
+ warning ("Remote failure reply: %s", buf);
+ continue;
+ case 'F': /* File-I/O request */
+ remote_fileio_request (buf);
+ continue;
+ case 'T': /* Status with PC, SP, FP, ... */
+ {
+ int i;
+ char regs[MAX_REGISTER_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;
+ int fieldsize;
+ LONGEST pnum = 0;
+
+ /* If the packet contains a register number save it in pnum
+ and set p1 to point to the character following it.
+ Otherwise p1 points to p. */
+
+ /* If this packet is an awatch packet, don't parse the 'a'
+ as a register number. */
+
+ if (strncmp (p, "awatch", strlen("awatch")) != 0)
+ {
+ /* Read the ``P'' register number. */
+ pnum = strtol (p, &p_temp, 16);
+ p1 = (unsigned char *) p_temp;
+ }
+ else
+ p1 = p;
+
+ if (p1 == p) /* No register number present here */
+ {
+ p1 = (unsigned char *) strchr (p, ':');
+ if (p1 == NULL)
+ warning ("Malformed packet(a) (missing colon): %s\n\
+Packet: '%s'\n",
+ p, buf);
+ if (strncmp (p, "thread", p1 - p) == 0)
+ {
+ p_temp = unpack_varlen_hex (++p1, &thread_num);
+ record_currthread (thread_num);
+ p = (unsigned char *) p_temp;
+ }
+ else if ((strncmp (p, "watch", p1 - p) == 0)
+ || (strncmp (p, "rwatch", p1 - p) == 0)
+ || (strncmp (p, "awatch", p1 - p) == 0))
+ {
+ remote_stopped_by_watchpoint_p = 1;
+ p = unpack_varlen_hex (++p1, &addr);
+ remote_watch_data_address = (CORE_ADDR)addr;
+ }
+ else
+ {
+ /* Silently skip unknown optional info. */
+ p_temp = strchr (p1 + 1, ';');
+ if (p_temp)
+ p = (unsigned char *) p_temp;
+ }
+ }
+ else
+ {
+ struct packet_reg *reg = packet_reg_from_pnum (rs, pnum);
+ p = p1;
+
+ if (*p++ != ':')
+ error ("Malformed packet(b) (missing colon): %s\nPacket: '%s'\n",
+ p, buf);
+
+ if (reg == NULL)
+ error ("Remote sent bad register number %s: %s\nPacket: '%s'\n",
+ phex_nz (pnum, 0), p, buf);
+
+ fieldsize = hex2bin (p, regs, DEPRECATED_REGISTER_RAW_SIZE (reg->regnum));
+ p += 2 * fieldsize;
+ if (fieldsize < DEPRECATED_REGISTER_RAW_SIZE (reg->regnum))
+ warning ("Remote reply is too short: %s", buf);
+ supply_register (reg->regnum, regs);
+ }
+
+ if (*p++ != ';')
+ error ("Remote register badly formatted: %s\nhere: %s", buf, p);
+ }
+ }
+ /* 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])));
+
+ if (buf[3] == 'p')
+ {
+ thread_num = strtol ((const char *) &buf[4], NULL, 16);
+ record_currthread (thread_num);
+ }
+ 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 */
+ remote_console_output (buf + 1);
+ 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)
+ {
+ return pid_to_ptid (thread_num);
+ }
+ return inferior_ptid;
+}
+
+/* Async version of remote_wait. */
+static ptid_t
+remote_async_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ struct remote_state *rs = get_remote_state ();
+ unsigned char *buf = alloca (rs->remote_packet_size);
+ ULONGEST thread_num = -1;
+ ULONGEST addr;
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ remote_stopped_by_watchpoint_p = 0;
+
+ while (1)
+ {
+ unsigned char *p;
+
+ if (!target_is_async_p ())
+ ofunc = signal (SIGINT, remote_interrupt);
+ /* FIXME: cagney/1999-09-27: If we're in async mode we should
+ _never_ wait for ever -> test on target_is_async_p().
+ However, before we do that we need to ensure that the caller
+ knows how to take the target into/out of async mode. */
+ getpkt (buf, (rs->remote_packet_size), wait_forever_enabled_p);
+ if (!target_is_async_p ())
+ signal (SIGINT, ofunc);
+
+ /* This is a hook for when we need to do something (perhaps the
+ collection of trace data) every time the target stops. */
+ if (target_wait_loop_hook)
+ (*target_wait_loop_hook) ();
+
+ switch (buf[0])
+ {
+ case 'E': /* Error of some sort */
+ warning ("Remote failure reply: %s", buf);
+ continue;
+ case 'F': /* File-I/O request */
+ remote_fileio_request (buf);
+ continue;
+ case 'T': /* Status with PC, SP, FP, ... */
+ {
+ int i;
+ char regs[MAX_REGISTER_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;
+ int fieldsize;
+ long pnum = 0;
+
+ /* If the packet contains a register number, save it in pnum
+ and set p1 to point to the character following it.
+ Otherwise p1 points to p. */
+
+ /* If this packet is an awatch packet, don't parse the 'a'
+ as a register number. */
+
+ if (!strncmp (p, "awatch", strlen ("awatch")) != 0)
+ {
+ /* Read the register number. */
+ pnum = strtol (p, &p_temp, 16);
+ p1 = (unsigned char *) p_temp;
+ }
+ else
+ p1 = p;
+
+ if (p1 == p) /* No register number present here */
+ {
+ p1 = (unsigned char *) strchr (p, ':');
+ if (p1 == NULL)
+ error ("Malformed packet(a) (missing colon): %s\nPacket: '%s'\n",
+ p, buf);
+ if (strncmp (p, "thread", p1 - p) == 0)
+ {
+ p_temp = unpack_varlen_hex (++p1, &thread_num);
+ record_currthread (thread_num);
+ p = (unsigned char *) p_temp;
+ }
+ else if ((strncmp (p, "watch", p1 - p) == 0)
+ || (strncmp (p, "rwatch", p1 - p) == 0)
+ || (strncmp (p, "awatch", p1 - p) == 0))
+ {
+ remote_stopped_by_watchpoint_p = 1;
+ p = unpack_varlen_hex (++p1, &addr);
+ remote_watch_data_address = (CORE_ADDR)addr;
+ }
+ else
+ {
+ /* Silently skip unknown optional info. */
+ p_temp = (unsigned char *) strchr (p1 + 1, ';');
+ if (p_temp)
+ p = p_temp;
+ }
+ }
+
+ else
+ {
+ struct packet_reg *reg = packet_reg_from_pnum (rs, pnum);
+ p = p1;
+ if (*p++ != ':')
+ error ("Malformed packet(b) (missing colon): %s\nPacket: '%s'\n",
+ p, buf);
+
+ if (reg == NULL)
+ error ("Remote sent bad register number %ld: %s\nPacket: '%s'\n",
+ pnum, p, buf);
+
+ fieldsize = hex2bin (p, regs, DEPRECATED_REGISTER_RAW_SIZE (reg->regnum));
+ p += 2 * fieldsize;
+ if (fieldsize < DEPRECATED_REGISTER_RAW_SIZE (reg->regnum))
+ warning ("Remote reply is too short: %s", buf);
+ supply_register (reg->regnum, regs);
+ }
+
+ if (*p++ != ';')
+ error ("Remote register badly formatted: %s\nhere: %s",
+ buf, p);
+ }
+ }
+ /* 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])));
+
+ if (buf[3] == 'p')
+ {
+ thread_num = strtol ((const char *) &buf[4], NULL, 16);
+ record_currthread (thread_num);
+ }
+ 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 */
+ remote_console_output (buf + 1);
+ /* Return immediately to the event loop. The event loop will
+ still be waiting on the inferior afterwards. */
+ status->kind = TARGET_WAITKIND_IGNORE;
+ goto got_status;
+ 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)
+ {
+ return pid_to_ptid (thread_num);
+ }
+ return inferior_ptid;
+}
+
+/* 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 regnum. */
+
+static void
+remote_fetch_registers (int regnum)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ int i;
+ char *p;
+ char *regs = alloca (rs->sizeof_g_packet);
+
+ set_thread (PIDGET (inferior_ptid), 1);
+
+ if (regnum >= 0)
+ {
+ struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
+ gdb_assert (reg != NULL);
+ if (!reg->in_g_packet)
+ internal_error (__FILE__, __LINE__,
+ "Attempt to fetch a non G-packet register when this "
+ "remote.c does not support the p-packet.");
+ }
+
+ sprintf (buf, "g");
+ remote_send (buf, (rs->remote_packet_size));
+
+ /* Save the size of the packet sent to us by the target. Its used
+ as a heuristic when determining the max size of packets that the
+ target can safely receive. */
+ if ((rs->actual_register_packet_size) == 0)
+ (rs->actual_register_packet_size) = strlen (buf);
+
+ /* Unimplemented registers read as all bits zero. */
+ memset (regs, 0, rs->sizeof_g_packet);
+
+ /* 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')
+ && buf[0] != 'x') /* New: unavailable register value */
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Bad register packet; fetching a new packet\n");
+ getpkt (buf, (rs->remote_packet_size), 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 < rs->sizeof_g_packet; 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;
+ }
+ if (p[0] == 'x' && p[1] == 'x')
+ regs[i] = 0; /* 'x' */
+ else
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+
+ if (i != register_bytes_found)
+ {
+ register_bytes_found = i;
+ if (REGISTER_BYTES_OK_P ()
+ && !REGISTER_BYTES_OK (i))
+ warning ("Remote reply is too short: %s", buf);
+ }
+
+ supply_them:
+ {
+ int i;
+ for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+ {
+ struct packet_reg *r = &rs->regs[i];
+ if (r->in_g_packet)
+ {
+ if (r->offset * 2 >= strlen (buf))
+ /* A short packet that didn't include the register's
+ value, this implies that the register is zero (and
+ not that the register is unavailable). Supply that
+ zero value. */
+ regcache_raw_supply (current_regcache, r->regnum, NULL);
+ else if (buf[r->offset * 2] == 'x')
+ {
+ gdb_assert (r->offset * 2 < strlen (buf));
+ /* The register isn't available, mark it as such (at
+ the same time setting the value to zero). */
+ regcache_raw_supply (current_regcache, r->regnum, NULL);
+ set_register_cached (i, -1);
+ }
+ else
+ regcache_raw_supply (current_regcache, r->regnum,
+ regs + r->offset);
+ }
+ }
+ }
+}
+
+/* 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 (void)
+{
+ struct remote_state *rs = get_remote_state ();
+ int i;
+ char buf[MAX_REGISTER_SIZE];
+
+ /* Make sure the entire registers array is valid. */
+ switch (remote_protocol_P.support)
+ {
+ case PACKET_DISABLE:
+ case PACKET_SUPPORT_UNKNOWN:
+ /* Make sure all the necessary registers are cached. */
+ for (i = 0; i < NUM_REGS; i++)
+ if (rs->regs[i].in_g_packet)
+ regcache_raw_read (current_regcache, rs->regs[i].regnum, buf);
+ break;
+ case PACKET_ENABLE:
+ break;
+ }
+}
+
+/* Helper: Attempt to store REGNUM using the P packet. Return fail IFF
+ packet was not recognized. */
+
+static int
+store_register_using_P (int regnum)
+{
+ struct remote_state *rs = get_remote_state ();
+ struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
+ /* Try storing a single register. */
+ char *buf = alloca (rs->remote_packet_size);
+ char regp[MAX_REGISTER_SIZE];
+ char *p;
+ int i;
+
+ sprintf (buf, "P%s=", phex_nz (reg->pnum, 0));
+ p = buf + strlen (buf);
+ regcache_collect (reg->regnum, regp);
+ bin2hex (regp, p, DEPRECATED_REGISTER_RAW_SIZE (reg->regnum));
+ remote_send (buf, rs->remote_packet_size);
+
+ return buf[0] != '\0';
+}
+
+
+/* Store register REGNUM, or all registers if REGNUM == -1, from the contents
+ of the register cache buffer. FIXME: ignores errors. */
+
+static void
+remote_store_registers (int regnum)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf;
+ char *regs;
+ int i;
+ char *p;
+
+ set_thread (PIDGET (inferior_ptid), 1);
+
+ if (regnum >= 0)
+ {
+ switch (remote_protocol_P.support)
+ {
+ case PACKET_DISABLE:
+ break;
+ case PACKET_ENABLE:
+ if (store_register_using_P (regnum))
+ return;
+ else
+ error ("Protocol error: P packet not recognized by stub");
+ case PACKET_SUPPORT_UNKNOWN:
+ if (store_register_using_P (regnum))
+ {
+ /* The stub recognized the 'P' packet. Remember this. */
+ remote_protocol_P.support = PACKET_ENABLE;
+ return;
+ }
+ else
+ {
+ /* The stub does not support the 'P' packet. Use 'G'
+ instead, and don't try using 'P' in the future (it
+ will just waste our time). */
+ remote_protocol_P.support = PACKET_DISABLE;
+ break;
+ }
+ }
+ }
+
+ /* Extract all the registers in the regcache copying them into a
+ local buffer. */
+ {
+ int i;
+ regs = alloca (rs->sizeof_g_packet);
+ memset (regs, rs->sizeof_g_packet, 0);
+ for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+ {
+ struct packet_reg *r = &rs->regs[i];
+ if (r->in_g_packet)
+ regcache_collect (r->regnum, regs + r->offset);
+ }
+ }
+
+ /* Command describes registers byte by byte,
+ each byte encoded as two hex characters. */
+ buf = alloca (rs->remote_packet_size);
+ p = buf;
+ *p++ = 'G';
+ /* remote_prepare_to_store insures that register_bytes_found gets set. */
+ bin2hex (regs, p, register_bytes_found);
+ remote_send (buf, (rs->remote_packet_size));
+}
+
+
+/* Return the number of hex digits in num. */
+
+static int
+hexnumlen (ULONGEST num)
+{
+ int i;
+
+ for (i = 0; num != 0; i++)
+ num >>= 4;
+
+ return max (i, 1);
+}
+
+/* Set BUF to the minimum number of hex digits representing NUM. */
+
+static int
+hexnumstr (char *buf, ULONGEST num)
+{
+ int len = hexnumlen (num);
+ return hexnumnstr (buf, num, len);
+}
+
+
+/* Set BUF to the hex digits representing NUM, padded to WIDTH characters. */
+
+static int
+hexnumnstr (char *buf, ULONGEST num, int width)
+{
+ int i;
+
+ buf[width] = '\0';
+
+ for (i = width - 1; i >= 0; i--)
+ {
+ buf[i] = "0123456789abcdef"[(num & 0xf)];
+ num >>= 4;
+ }
+
+ return width;
+}
+
+/* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */
+
+static CORE_ADDR
+remote_address_masked (CORE_ADDR addr)
+{
+ if (remote_address_size > 0
+ && remote_address_size < (sizeof (ULONGEST) * 8))
+ {
+ /* Only create a mask when that mask can safely be constructed
+ in a ULONGEST variable. */
+ ULONGEST mask = 1;
+ mask = (mask << remote_address_size) - 1;
+ addr &= mask;
+ }
+ return addr;
+}
+
+/* Determine whether the remote target supports binary downloading.
+ This is accomplished by sending a no-op memory write of zero length
+ to the target at the specified address. It does not suffice to send
+ the whole packet, since many stubs strip the eighth bit and subsequently
+ compute a wrong checksum, which causes real havoc with remote_write_bytes.
+
+ NOTE: This can still lose if the serial line is not eight-bit
+ clean. In cases like this, the user should clear "remote
+ X-packet". */
+
+static void
+check_binary_download (CORE_ADDR addr)
+{
+ struct remote_state *rs = get_remote_state ();
+ switch (remote_protocol_binary_download.support)
+ {
+ case PACKET_DISABLE:
+ break;
+ case PACKET_ENABLE:
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ {
+ char *buf = alloca (rs->remote_packet_size);
+ char *p;
+
+ p = buf;
+ *p++ = 'X';
+ p += hexnumstr (p, (ULONGEST) addr);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) 0);
+ *p++ = ':';
+ *p = '\0';
+
+ putpkt_binary (buf, (int) (p - buf));
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ if (buf[0] == '\0')
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "binary downloading NOT suppported by target\n");
+ remote_protocol_binary_download.support = PACKET_DISABLE;
+ }
+ else
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "binary downloading suppported by target\n");
+ remote_protocol_binary_download.support = PACKET_ENABLE;
+ }
+ break;
+ }
+ }
+}
+
+/* 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 (setting errno) for
+ error. Only transfer a single packet. */
+
+int
+remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ unsigned char *buf;
+ unsigned char *p;
+ unsigned char *plen;
+ long sizeof_buf;
+ int plenlen;
+ int todo;
+ int nr_bytes;
+ int payload_size;
+ unsigned char *payload_start;
+
+ /* Verify that the target can support a binary download. */
+ check_binary_download (memaddr);
+
+ /* Compute the size, and then allocate space for the largest
+ possible packet. Include space for an extra trailing NUL. */
+ sizeof_buf = get_memory_write_packet_size () + 1;
+ buf = alloca (sizeof_buf);
+
+ /* Compute the size of the actual payload by subtracting out the
+ packet header and footer overhead: "$M<memaddr>,<len>:...#nn". */
+ payload_size = (get_memory_write_packet_size () - (strlen ("$M,:#NN")
+ + hexnumlen (memaddr)
+ + hexnumlen (len)));
+
+ /* Construct the packet header: "[MX]<memaddr>,<len>:". */
+
+ /* Append "[XM]". Compute a best guess of the number of bytes
+ actually transfered. */
+ p = buf;
+ switch (remote_protocol_binary_download.support)
+ {
+ case PACKET_ENABLE:
+ *p++ = 'X';
+ /* Best guess at number of bytes that will fit. */
+ todo = min (len, payload_size);
+ break;
+ case PACKET_DISABLE:
+ *p++ = 'M';
+ /* num bytes that will fit */
+ todo = min (len, payload_size / 2);
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ internal_error (__FILE__, __LINE__,
+ "remote_write_bytes: bad internal state");
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ /* Append "<memaddr>". */
+ memaddr = remote_address_masked (memaddr);
+ p += hexnumstr (p, (ULONGEST) memaddr);
+
+ /* Append ",". */
+ *p++ = ',';
+
+ /* Append <len>. Retain the location/size of <len>. It may need to
+ be adjusted once the packet body has been created. */
+ plen = p;
+ plenlen = hexnumstr (p, (ULONGEST) todo);
+ p += plenlen;
+
+ /* Append ":". */
+ *p++ = ':';
+ *p = '\0';
+
+ /* Append the packet body. */
+ payload_start = p;
+ switch (remote_protocol_binary_download.support)
+ {
+ case PACKET_ENABLE:
+ /* Binary mode. Send target system values byte by byte, in
+ increasing byte addresses. Only escape certain critical
+ characters. */
+ for (nr_bytes = 0;
+ (nr_bytes < todo) && (p - payload_start) < payload_size;
+ nr_bytes++)
+ {
+ switch (myaddr[nr_bytes] & 0xff)
+ {
+ case '$':
+ case '#':
+ case 0x7d:
+ /* These must be escaped */
+ *p++ = 0x7d;
+ *p++ = (myaddr[nr_bytes] & 0xff) ^ 0x20;
+ break;
+ default:
+ *p++ = myaddr[nr_bytes] & 0xff;
+ break;
+ }
+ }
+ if (nr_bytes < todo)
+ {
+ /* Escape chars have filled up the buffer prematurely,
+ and we have actually sent fewer bytes than planned.
+ Fix-up the length field of the packet. Use the same
+ number of characters as before. */
+ plen += hexnumnstr (plen, (ULONGEST) nr_bytes, plenlen);
+ *plen = ':'; /* overwrite \0 from hexnumnstr() */
+ }
+ break;
+ case PACKET_DISABLE:
+ /* Normal mode: Send target system values byte by byte, in
+ increasing byte addresses. Each byte is encoded as a two hex
+ value. */
+ nr_bytes = bin2hex (myaddr, p, todo);
+ p += 2 * nr_bytes;
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ internal_error (__FILE__, __LINE__,
+ "remote_write_bytes: bad internal state");
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ putpkt_binary (buf, (int) (p - buf));
+ getpkt (buf, sizeof_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 NR_BYTES, not TODO, in case escape chars caused us to send fewer
+ bytes than we'd planned. */
+ return nr_bytes;
+}
+
+/* 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. */
+
+/* NOTE: cagney/1999-10-18: This function (and its siblings in other
+ remote targets) shouldn't attempt to read the entire buffer.
+ Instead it should read a single packet worth of data and then
+ return the byte size of that packet to the caller. The caller (its
+ caller and its callers caller ;-) already contains code for
+ handling partial reads. */
+
+int
+remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ char *buf;
+ int max_buf_size; /* Max size of packet output buffer */
+ long sizeof_buf;
+ int origlen;
+
+ /* Create a buffer big enough for this packet. */
+ max_buf_size = get_memory_read_packet_size ();
+ sizeof_buf = max_buf_size + 1; /* Space for trailing NUL */
+ buf = alloca (sizeof_buf);
+
+ origlen = len;
+ while (len > 0)
+ {
+ char *p;
+ int todo;
+ int i;
+
+ todo = min (len, max_buf_size / 2); /* num bytes that will fit */
+
+ /* construct "m"<memaddr>","<len>" */
+ /* sprintf (buf, "m%lx,%x", (unsigned long) memaddr, todo); */
+ memaddr = remote_address_masked (memaddr);
+ p = buf;
+ *p++ = 'm';
+ p += hexnumstr (p, (ULONGEST) memaddr);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) todo);
+ *p = '\0';
+
+ putpkt (buf);
+ getpkt (buf, sizeof_buf, 0);
+
+ if (buf[0] == 'E'
+ && isxdigit (buf[1]) && isxdigit (buf[2])
+ && buf[3] == '\0')
+ {
+ /* 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;
+ if ((i = hex2bin (p, myaddr, todo)) < todo)
+ {
+ /* Reply is short. This means that we were able to read
+ only part of what we wanted to. */
+ return i + (origlen - len);
+ }
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
+ }
+ return origlen;
+}
+
+/* Read or write LEN bytes from inferior memory at MEMADDR,
+ transferring to or from debugger address BUFFER. Write to inferior if
+ SHOULD_WRITE is nonzero. Returns length of data written or read; 0
+ for error. TARGET is unused. */
+
+static int
+remote_xfer_memory (CORE_ADDR mem_addr, char *buffer, int mem_len,
+ int should_write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ CORE_ADDR targ_addr;
+ int targ_len;
+ int res;
+
+ /* Should this be the selected frame? */
+ gdbarch_remote_translate_xfer_address (current_gdbarch, current_regcache,
+ mem_addr, mem_len,
+ &targ_addr, &targ_len);
+ if (targ_len <= 0)
+ return 0;
+
+ if (should_write)
+ res = remote_write_bytes (targ_addr, buffer, targ_len);
+ else
+ res = remote_read_bytes (targ_addr, buffer, targ_len);
+
+ return res;
+}
+
+static void
+remote_files_info (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 (int timeout)
+{
+ int ch;
+
+ ch = serial_readchar (remote_desc, timeout);
+
+ if (ch >= 0)
+ return (ch & 0x7f);
+
+ switch ((enum serial_rc) ch)
+ {
+ case SERIAL_EOF:
+ target_mourn_inferior ();
+ error ("Remote connection closed");
+ /* no return */
+ case SERIAL_ERROR:
+ perror_with_name ("Remote communication error");
+ /* no return */
+ case SERIAL_TIMEOUT:
+ break;
+ }
+ return ch;
+}
+
+/* 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 (char *buf,
+ long sizeof_buf)
+{
+ putpkt (buf);
+ getpkt (buf, sizeof_buf, 0);
+
+ if (buf[0] == 'E')
+ error ("Remote failure reply: %s", buf);
+}
+
+/* Display a null-terminated packet on stdout, for debugging, using C
+ string notation. */
+
+static void
+print_packet (char *buf)
+{
+ puts_filtered ("\"");
+ fputstr_filtered (buf, '"', gdb_stdout);
+ puts_filtered ("\"");
+}
+
+int
+putpkt (char *buf)
+{
+ return putpkt_binary (buf, strlen (buf));
+}
+
+/* Send a packet to the remote machine, with error checking. The data
+ of the packet is in BUF. The string in BUF can be at most (rs->remote_packet_size) - 5
+ to account for the $, # and checksum, and for a possible /0 if we are
+ debugging (remote_debug) and want to print the sent packet as a string */
+
+static int
+putpkt_binary (char *buf, int cnt)
+{
+ struct remote_state *rs = get_remote_state ();
+ int i;
+ unsigned char csum = 0;
+ char *buf2 = alloca (cnt + 6);
+ long sizeof_junkbuf = (rs->remote_packet_size);
+ char *junkbuf = alloca (sizeof_junkbuf);
+
+ int ch;
+ int tcount = 0;
+ 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. */
+
+ while (1)
+ {
+ int started_error_output = 0;
+
+ if (remote_debug)
+ {
+ *p = '\0';
+ fprintf_unfiltered (gdb_stdlog, "Sending packet: ");
+ fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, "...");
+ gdb_flush (gdb_stdlog);
+ }
+ 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 '-':
+ case SERIAL_TIMEOUT:
+ case '$':
+ if (started_error_output)
+ {
+ putchar_unfiltered ('\n');
+ started_error_output = 0;
+ }
+ }
+ }
+
+ switch (ch)
+ {
+ case '+':
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Ack\n");
+ return 1;
+ case '-':
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Nak\n");
+ case SERIAL_TIMEOUT:
+ tcount++;
+ if (tcount > 3)
+ return 0;
+ break; /* Retransmit buffer */
+ case '$':
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Packet instead of Ack, ignoring it\n");
+ /* It's probably an old response, and we're out of sync.
+ Just gobble up the packet and ignore it. */
+ read_frame (junkbuf, sizeof_junkbuf);
+ continue; /* Now, go look for + */
+ }
+ default:
+ if (remote_debug)
+ {
+ if (!started_error_output)
+ {
+ started_error_output = 1;
+ fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: ");
+ }
+ fputc_unfiltered (ch & 0177, gdb_stdlog);
+ }
+ 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. No more than sizeof_buf-1 characters are read so that
+ the buffer can be NUL terminated.
+
+ Returns -1 on error, number of characters in buffer (ignoring the
+ trailing NULL) on success. (could be extended to return one of the
+ SERIAL status indications). */
+
+static long
+read_frame (char *buf,
+ long sizeof_buf)
+{
+ unsigned char csum;
+ long bc;
+ int c;
+
+ csum = 0;
+ bc = 0;
+
+ while (1)
+ {
+ /* ASSERT (bc < sizeof_buf - 1) - space for trailing NUL */
+ c = readchar (remote_timeout);
+ switch (c)
+ {
+ case SERIAL_TIMEOUT:
+ if (remote_debug)
+ fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog);
+ return -1;
+ case '$':
+ if (remote_debug)
+ fputs_filtered ("Saw new packet start in middle of old one\n",
+ gdb_stdlog);
+ return -1; /* Start a new packet, count retries */
+ case '#':
+ {
+ unsigned char pktcsum;
+ int check_0 = 0;
+ int check_1 = 0;
+
+ buf[bc] = '\0';
+
+ check_0 = readchar (remote_timeout);
+ if (check_0 >= 0)
+ check_1 = readchar (remote_timeout);
+
+ if (check_0 == SERIAL_TIMEOUT || check_1 == SERIAL_TIMEOUT)
+ {
+ if (remote_debug)
+ fputs_filtered ("Timeout in checksum, retrying\n", gdb_stdlog);
+ return -1;
+ }
+ else if (check_0 < 0 || check_1 < 0)
+ {
+ if (remote_debug)
+ fputs_filtered ("Communication error in checksum\n", gdb_stdlog);
+ return -1;
+ }
+
+ pktcsum = (fromhex (check_0) << 4) | fromhex (check_1);
+ if (csum == pktcsum)
+ return bc;
+
+ if (remote_debug)
+ {
+ fprintf_filtered (gdb_stdlog,
+ "Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ pktcsum, csum);
+ fputs_filtered (buf, gdb_stdlog);
+ fputs_filtered ("\n", gdb_stdlog);
+ }
+ /* Number of characters in buffer ignoring trailing
+ NUL. */
+ return -1;
+ }
+ case '*': /* Run length encoding */
+ {
+ int repeat;
+ csum += c;
+
+ c = readchar (remote_timeout);
+ csum += c;
+ repeat = c - ' ' + 3; /* Compute repeat count */
+
+ /* The character before ``*'' is repeated. */
+
+ if (repeat > 0 && repeat <= 255
+ && bc > 0
+ && bc + repeat - 1 < sizeof_buf - 1)
+ {
+ memset (&buf[bc], buf[bc - 1], repeat);
+ bc += repeat;
+ continue;
+ }
+
+ buf[bc] = '\0';
+ printf_filtered ("Repeat count %d too large for buffer: ", repeat);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ return -1;
+ }
+ default:
+ if (bc < sizeof_buf - 1)
+ {
+ buf[bc++] = c;
+ csum += c;
+ continue;
+ }
+
+ buf[bc] = '\0';
+ puts_filtered ("Remote packet too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return -1;
+ }
+ }
+}
+
+/* Read a packet from the remote machine, with error checking, and
+ store it in BUF. If FOREVER, wait forever rather than timing out;
+ this is used (in synchronous mode) to wait for a target that is is
+ executing user code to stop. */
+/* FIXME: ezannoni 2000-02-01 this wrapper is necessary so that we
+ don't have to change all the calls to getpkt to deal with the
+ return value, because at the moment I don't know what the right
+ thing to do it for those. */
+void
+getpkt (char *buf,
+ long sizeof_buf,
+ int forever)
+{
+ int timed_out;
+
+ timed_out = getpkt_sane (buf, sizeof_buf, forever);
+}
+
+
+/* Read a packet from the remote machine, with error checking, and
+ store it in BUF. If FOREVER, wait forever rather than timing out;
+ this is used (in synchronous mode) to wait for a target that is is
+ executing user code to stop. If FOREVER == 0, this function is
+ allowed to time out gracefully and return an indication of this to
+ the caller. */
+static int
+getpkt_sane (char *buf,
+ long sizeof_buf,
+ int forever)
+{
+ int c;
+ int tries;
+ int timeout;
+ int val;
+
+ strcpy (buf, "timeout");
+
+ if (forever)
+ {
+ timeout = watchdog > 0 ? watchdog : -1;
+ }
+
+ 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)
+ {
+ if (forever) /* Watchdog went off? Kill the target. */
+ {
+ QUIT;
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+ if (remote_debug)
+ fputs_filtered ("Timed out.\n", gdb_stdlog);
+ goto retry;
+ }
+ }
+ while (c != '$');
+
+ /* We've found the start of a packet, now collect the data. */
+
+ val = read_frame (buf, sizeof_buf);
+
+ if (val >= 0)
+ {
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Packet received: ");
+ fputstr_unfiltered (buf, 0, gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+ serial_write (remote_desc, "+", 1);
+ return 0;
+ }
+
+ /* 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);
+ return 1;
+}
+
+static void
+remote_kill (void)
+{
+ /* 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 ((catch_errors_ftype *) 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 ();
+}
+
+/* Async version of remote_kill. */
+static void
+remote_async_kill (void)
+{
+ /* Unregister the file descriptor from the event loop. */
+ if (target_is_async_p ())
+ serial_async (remote_desc, NULL, 0);
+
+ /* 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 ((catch_errors_ftype *) 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 (void)
+{
+ remote_mourn_1 (&remote_ops);
+}
+
+static void
+remote_async_mourn (void)
+{
+ remote_mourn_1 (&remote_async_ops);
+}
+
+static void
+extended_remote_mourn (void)
+{
+ /* 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 (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 (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);
+}
+
+/* Async version of extended_remote_create_inferior. */
+static void
+extended_remote_async_create_inferior (char *exec_file, char *args, char **env)
+{
+ /* Rip out the breakpoints; we'll reinsert them after restarting
+ the remote server. */
+ remove_breakpoints ();
+
+ /* If running asynchronously, register the target file descriptor
+ with the event loop. */
+ if (event_loop_p && target_can_async_p ())
+ target_async (inferior_event_handler, 0);
+
+ /* 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);
+}
+
+
+/* On some machines, e.g. 68k, we may use a different breakpoint
+ instruction than other targets; in those use
+ DEPRECATED_REMOTE_BREAKPOINT instead of just BREAKPOINT_FROM_PC.
+ Also, bi-endian targets may define
+ DEPRECATED_LITTLE_REMOTE_BREAKPOINT and
+ DEPRECATED_BIG_REMOTE_BREAKPOINT. If none of these are defined, we
+ just call the standard routines that are in mem-break.c. */
+
+/* NOTE: cagney/2003-06-08: This is silly. A remote and simulator
+ target should use an identical BREAKPOINT_FROM_PC. As for native,
+ the ARCH-OS-tdep.c code can override the default. */
+
+#if defined (DEPRECATED_LITTLE_REMOTE_BREAKPOINT) && defined (DEPRECATED_BIG_REMOTE_BREAKPOINT) && !defined(DEPRECATED_REMOTE_BREAKPOINT)
+#define DEPRECATED_REMOTE_BREAKPOINT
+#endif
+
+#ifdef DEPRECATED_REMOTE_BREAKPOINT
+
+/* If the target isn't bi-endian, just pretend it is. */
+#if !defined (DEPRECATED_LITTLE_REMOTE_BREAKPOINT) && !defined (DEPRECATED_BIG_REMOTE_BREAKPOINT)
+#define DEPRECATED_LITTLE_REMOTE_BREAKPOINT DEPRECATED_REMOTE_BREAKPOINT
+#define DEPRECATED_BIG_REMOTE_BREAKPOINT DEPRECATED_REMOTE_BREAKPOINT
+#endif
+
+static unsigned char big_break_insn[] = DEPRECATED_BIG_REMOTE_BREAKPOINT;
+static unsigned char little_break_insn[] = DEPRECATED_LITTLE_REMOTE_BREAKPOINT;
+
+#endif /* DEPRECATED_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 the number
+ of bytes returned by BREAKPOINT_FROM_PC. */
+
+static int
+remote_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ struct remote_state *rs = get_remote_state ();
+#ifdef DEPRECATED_REMOTE_BREAKPOINT
+ int val;
+#endif
+ int bp_size;
+
+ /* Try the "Z" s/w breakpoint packet if it is not already disabled.
+ If it succeeds, then set the support to PACKET_ENABLE. If it
+ fails, and the user has explicitly requested the Z support then
+ report an error, otherwise, mark it disabled and go on. */
+
+ if (remote_protocol_Z[Z_PACKET_SOFTWARE_BP].support != PACKET_DISABLE)
+ {
+ char *buf = alloca (rs->remote_packet_size);
+ char *p = buf;
+
+ addr = remote_address_masked (addr);
+ *(p++) = 'Z';
+ *(p++) = '0';
+ *(p++) = ',';
+ p += hexnumstr (p, (ULONGEST) addr);
+ BREAKPOINT_FROM_PC (&addr, &bp_size);
+ sprintf (p, ",%d", bp_size);
+
+ putpkt (buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_SOFTWARE_BP]))
+ {
+ case PACKET_ERROR:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ case PACKET_UNKNOWN:
+ break;
+ }
+ }
+
+#ifdef DEPRECATED_REMOTE_BREAKPOINT
+ val = target_read_memory (addr, contents_cache, sizeof big_break_insn);
+
+ if (val == 0)
+ {
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ val = target_write_memory (addr, (char *) big_break_insn,
+ sizeof big_break_insn);
+ else
+ val = target_write_memory (addr, (char *) little_break_insn,
+ sizeof little_break_insn);
+ }
+
+ return val;
+#else
+ return memory_insert_breakpoint (addr, contents_cache);
+#endif /* DEPRECATED_REMOTE_BREAKPOINT */
+}
+
+static int
+remote_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ struct remote_state *rs = get_remote_state ();
+ int bp_size;
+
+ if (remote_protocol_Z[Z_PACKET_SOFTWARE_BP].support != PACKET_DISABLE)
+ {
+ char *buf = alloca (rs->remote_packet_size);
+ char *p = buf;
+
+ *(p++) = 'z';
+ *(p++) = '0';
+ *(p++) = ',';
+
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ BREAKPOINT_FROM_PC (&addr, &bp_size);
+ sprintf (p, ",%d", bp_size);
+
+ putpkt (buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ return (buf[0] == 'E');
+ }
+
+#ifdef DEPRECATED_REMOTE_BREAKPOINT
+ return target_write_memory (addr, contents_cache, sizeof big_break_insn);
+#else
+ return memory_remove_breakpoint (addr, contents_cache);
+#endif /* DEPRECATED_REMOTE_BREAKPOINT */
+}
+
+static int
+watchpoint_to_Z_packet (int type)
+{
+ switch (type)
+ {
+ case hw_write:
+ return 2;
+ break;
+ case hw_read:
+ return 3;
+ break;
+ case hw_access:
+ return 4;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "hw_bp_to_z: bad watchpoint type %d", type);
+ }
+}
+
+static int
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ char *p;
+ enum Z_packet_type packet = watchpoint_to_Z_packet (type);
+
+ if (remote_protocol_Z[packet].support == PACKET_DISABLE)
+ error ("Can't set hardware watchpoints without the '%s' (%s) packet\n",
+ remote_protocol_Z[packet].name,
+ remote_protocol_Z[packet].title);
+
+ sprintf (buf, "Z%x,", packet);
+ p = strchr (buf, '\0');
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+
+ putpkt (buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[packet]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error (__FILE__, __LINE__,
+ "remote_insert_watchpoint: reached end of function");
+}
+
+
+static int
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ char *p;
+ enum Z_packet_type packet = watchpoint_to_Z_packet (type);
+
+ if (remote_protocol_Z[packet].support == PACKET_DISABLE)
+ error ("Can't clear hardware watchpoints without the '%s' (%s) packet\n",
+ remote_protocol_Z[packet].name,
+ remote_protocol_Z[packet].title);
+
+ sprintf (buf, "z%x,", packet);
+ p = strchr (buf, '\0');
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+ putpkt (buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[packet]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error (__FILE__, __LINE__,
+ "remote_remove_watchpoint: reached end of function");
+}
+
+
+int remote_hw_watchpoint_limit = -1;
+int remote_hw_breakpoint_limit = -1;
+
+static int
+remote_check_watch_resources (int type, int cnt, int ot)
+{
+ if (type == bp_hardware_breakpoint)
+ {
+ if (remote_hw_breakpoint_limit == 0)
+ return 0;
+ else if (remote_hw_breakpoint_limit < 0)
+ return 1;
+ else if (cnt <= remote_hw_breakpoint_limit)
+ return 1;
+ }
+ else
+ {
+ if (remote_hw_watchpoint_limit == 0)
+ return 0;
+ else if (remote_hw_watchpoint_limit < 0)
+ return 1;
+ else if (ot)
+ return -1;
+ else if (cnt <= remote_hw_watchpoint_limit)
+ return 1;
+ }
+ return -1;
+}
+
+static int
+remote_stopped_by_watchpoint (void)
+{
+ return remote_stopped_by_watchpoint_p;
+}
+
+static CORE_ADDR
+remote_stopped_data_address (void)
+{
+ if (remote_stopped_by_watchpoint ())
+ return remote_watch_data_address;
+ return (CORE_ADDR)0;
+}
+
+
+static int
+remote_insert_hw_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int len = 0;
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ char *p = buf;
+
+ /* The length field should be set to the size of a breakpoint
+ instruction. */
+
+ BREAKPOINT_FROM_PC (&addr, &len);
+
+ if (remote_protocol_Z[Z_PACKET_HARDWARE_BP].support == PACKET_DISABLE)
+ error ("Can't set hardware breakpoint without the '%s' (%s) packet\n",
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].name,
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].title);
+
+ *(p++) = 'Z';
+ *(p++) = '1';
+ *(p++) = ',';
+
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+
+ putpkt (buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_HARDWARE_BP]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error (__FILE__, __LINE__,
+ "remote_insert_hw_breakpoint: reached end of function");
+}
+
+
+static int
+remote_remove_hw_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int len;
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+ char *p = buf;
+
+ /* The length field should be set to the size of a breakpoint
+ instruction. */
+
+ BREAKPOINT_FROM_PC (&addr, &len);
+
+ if (remote_protocol_Z[Z_PACKET_HARDWARE_BP].support == PACKET_DISABLE)
+ error ("Can't clear hardware breakpoint without the '%s' (%s) packet\n",
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].name,
+ remote_protocol_Z[Z_PACKET_HARDWARE_BP].title);
+
+ *(p++) = 'z';
+ *(p++) = '1';
+ *(p++) = ',';
+
+ addr = remote_address_masked (addr);
+ p += hexnumstr (p, (ULONGEST) addr);
+ sprintf (p, ",%x", len);
+
+ putpkt(buf);
+ getpkt (buf, (rs->remote_packet_size), 0);
+
+ switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_HARDWARE_BP]))
+ {
+ case PACKET_ERROR:
+ case PACKET_UNKNOWN:
+ return -1;
+ case PACKET_OK:
+ return 0;
+ }
+ internal_error (__FILE__, __LINE__,
+ "remote_remove_hw_breakpoint: reached end of function");
+}
+
+/* Some targets are only capable of doing downloads, and afterwards
+ they switch to the remote serial protocol. This function provides
+ a clean way to get from the download target to the remote target.
+ It's basically just a wrapper so that we don't have to expose any
+ of the internal workings of remote.c.
+
+ Prior to calling this routine, you should shutdown the current
+ target code, else you will get the "A program is being debugged
+ already..." message. Usually a call to pop_target() suffices. */
+
+void
+push_remote_target (char *name, int from_tty)
+{
+ printf_filtered ("Switching to remote protocol\n");
+ remote_open (name, from_tty);
+}
+
+/* Table used by the crc32 function to calcuate the checksum. */
+
+static unsigned long crc32_table[256] =
+{0, 0};
+
+static unsigned long
+crc32 (unsigned char *buf, int len, unsigned int crc)
+{
+ if (!crc32_table[1])
+ {
+ /* Initialize the CRC table and the decoding table. */
+ int i, j;
+ unsigned int c;
+
+ for (i = 0; i < 256; i++)
+ {
+ for (c = i << 24, j = 8; j > 0; --j)
+ c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
+ crc32_table[i] = c;
+ }
+ }
+
+ while (len--)
+ {
+ crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
+ buf++;
+ }
+ return crc;
+}
+
+/* compare-sections command
+
+ With no arguments, compares each loadable section in the exec bfd
+ with the same memory range on the target, and reports mismatches.
+ Useful for verifying the image on the target against the exec file.
+ Depends on the target understanding the new "qCRC:" request. */
+
+/* FIXME: cagney/1999-10-26: This command should be broken down into a
+ target method (target verify memory) and generic version of the
+ actual command. This will allow other high-level code (especially
+ generic_load()) to make use of this target functionality. */
+
+static void
+compare_sections_command (char *args, int from_tty)
+{
+ struct remote_state *rs = get_remote_state ();
+ asection *s;
+ unsigned long host_crc, target_crc;
+ extern bfd *exec_bfd;
+ struct cleanup *old_chain;
+ char *tmp;
+ char *sectdata;
+ const char *sectname;
+ char *buf = alloca (rs->remote_packet_size);
+ bfd_size_type size;
+ bfd_vma lma;
+ int matched = 0;
+ int mismatched = 0;
+
+ if (!exec_bfd)
+ error ("command cannot be used without an exec file");
+ if (!current_target.to_shortname ||
+ strcmp (current_target.to_shortname, "remote") != 0)
+ error ("command can only be used with remote target");
+
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ if (!(s->flags & SEC_LOAD))
+ continue; /* skip non-loadable section */
+
+ size = bfd_get_section_size_before_reloc (s);
+ if (size == 0)
+ continue; /* skip zero-length section */
+
+ sectname = bfd_get_section_name (exec_bfd, s);
+ if (args && strcmp (args, sectname) != 0)
+ continue; /* not the section selected by user */
+
+ matched = 1; /* do this section */
+ lma = s->lma;
+ /* FIXME: assumes lma can fit into long */
+ sprintf (buf, "qCRC:%lx,%lx", (long) lma, (long) size);
+ putpkt (buf);
+
+ /* be clever; compute the host_crc before waiting for target reply */
+ sectdata = xmalloc (size);
+ old_chain = make_cleanup (xfree, sectdata);
+ bfd_get_section_contents (exec_bfd, s, sectdata, 0, size);
+ host_crc = crc32 ((unsigned char *) sectdata, size, 0xffffffff);
+
+ getpkt (buf, (rs->remote_packet_size), 0);
+ if (buf[0] == 'E')
+ error ("target memory fault, section %s, range 0x%s -- 0x%s",
+ sectname, paddr (lma), paddr (lma + size));
+ if (buf[0] != 'C')
+ error ("remote target does not support this operation");
+
+ for (target_crc = 0, tmp = &buf[1]; *tmp; tmp++)
+ target_crc = target_crc * 16 + fromhex (*tmp);
+
+ printf_filtered ("Section %s, range 0x%s -- 0x%s: ",
+ sectname, paddr (lma), paddr (lma + size));
+ if (host_crc == target_crc)
+ printf_filtered ("matched.\n");
+ else
+ {
+ printf_filtered ("MIS-MATCHED!\n");
+ mismatched++;
+ }
+
+ do_cleanups (old_chain);
+ }
+ if (mismatched > 0)
+ warning ("One or more sections of the remote executable does not match\n\
+the loaded file\n");
+ if (args && !matched)
+ printf_filtered ("No loaded section named '%s'.\n", args);
+}
+
+static LONGEST
+remote_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ struct remote_state *rs = get_remote_state ();
+ int i;
+ char *buf2 = alloca (rs->remote_packet_size);
+ char *p2 = &buf2[0];
+ char query_type;
+
+ /* Only handle reads. */
+ if (writebuf != NULL || readbuf == NULL)
+ return -1;
+
+ /* Map pre-existing objects onto letters. DO NOT do this for new
+ objects!!! Instead specify new query packets. */
+ switch (object)
+ {
+ case TARGET_OBJECT_KOD:
+ query_type = 'K';
+ break;
+ case TARGET_OBJECT_AVR:
+ query_type = 'R';
+ break;
+
+ case TARGET_OBJECT_AUXV:
+ if (remote_protocol_qPart_auxv.support != PACKET_DISABLE)
+ {
+ unsigned int total = 0;
+ while (len > 0)
+ {
+ LONGEST n = min ((rs->remote_packet_size - 2) / 2, len);
+ snprintf (buf2, rs->remote_packet_size,
+ "qPart:auxv:read::%s,%s",
+ phex_nz (offset, sizeof offset),
+ phex_nz (n, sizeof n));
+ i = putpkt (buf2);
+ if (i < 0)
+ return total > 0 ? total : i;
+ buf2[0] = '\0';
+ getpkt (buf2, rs->remote_packet_size, 0);
+ if (packet_ok (buf2, &remote_protocol_qPart_auxv) != PACKET_OK)
+ return total > 0 ? total : -1;
+ if (buf2[0] == 'O' && buf2[1] == 'K' && buf2[2] == '\0')
+ break; /* Got EOF indicator. */
+ /* Got some data. */
+ i = hex2bin (buf2, readbuf, len);
+ if (i > 0)
+ {
+ readbuf = (void *) ((char *) readbuf + i);
+ offset += i;
+ len -= i;
+ total += i;
+ }
+ }
+ return total;
+ }
+ return -1;
+
+ case TARGET_OBJECT_DIRTY:
+ if (remote_protocol_qPart_dirty.support != PACKET_DISABLE)
+ {
+ snprintf (buf2, rs->remote_packet_size, "qPart:dirty:read::%lx",
+ (long)(offset >> 3));
+ i = putpkt (buf2);
+ if (i < 0)
+ return i;
+ buf2[0] = '\0';
+ getpkt (buf2, rs->remote_packet_size, 0);
+ if (packet_ok (buf2, &remote_protocol_qPart_dirty) != PACKET_OK)
+ return -1;
+ i = hex2bin (buf2, readbuf, len);
+ return i;
+ }
+ return -1;
+
+ default:
+ return -1;
+ }
+
+ /* Note: a zero OFFSET and LEN can be used to query the minimum
+ buffer size. */
+ if (offset == 0 && len == 0)
+ return (rs->remote_packet_size);
+ /* Minimum outbuf size is (rs->remote_packet_size) - if bufsiz is
+ not large enough let the caller. */
+ if (len < (rs->remote_packet_size))
+ return -1;
+ len = rs->remote_packet_size;
+
+ /* except for querying the minimum buffer size, target must be open */
+ if (!remote_desc)
+ error ("remote query is only available after target open");
+
+ gdb_assert (annex != NULL);
+ gdb_assert (readbuf != NULL);
+
+ *p2++ = 'q';
+ *p2++ = query_type;
+
+ /* we used one buffer char for the remote protocol q command and another
+ for the query type. As the remote protocol encapsulation uses 4 chars
+ plus one extra in case we are debugging (remote_debug),
+ we have PBUFZIZ - 7 left to pack the query string */
+ i = 0;
+ while (annex[i] && (i < ((rs->remote_packet_size) - 8)))
+ {
+ /* Bad caller may have sent forbidden characters. */
+ gdb_assert (isprint (annex[i]) && annex[i] != '$' && annex[i] != '#');
+ *p2++ = annex[i];
+ i++;
+ }
+ *p2 = '\0';
+ gdb_assert (annex[i] == '\0');
+
+ i = putpkt (buf2);
+ if (i < 0)
+ return i;
+
+ getpkt (readbuf, len, 0);
+
+ return strlen (readbuf);
+}
+
+static void
+remote_rcmd (char *command,
+ struct ui_file *outbuf)
+{
+ struct remote_state *rs = get_remote_state ();
+ int i;
+ char *buf = alloca (rs->remote_packet_size);
+ char *p = buf;
+
+ if (!remote_desc)
+ error ("remote rcmd is only available after target open");
+
+ /* Send a NULL command across as an empty command */
+ if (command == NULL)
+ command = "";
+
+ /* The query prefix */
+ strcpy (buf, "qRcmd,");
+ p = strchr (buf, '\0');
+
+ if ((strlen (buf) + strlen (command) * 2 + 8/*misc*/) > (rs->remote_packet_size))
+ error ("\"monitor\" command ``%s'' is too long\n", command);
+
+ /* Encode the actual command */
+ bin2hex (command, p, 0);
+
+ if (putpkt (buf) < 0)
+ error ("Communication problem with target\n");
+
+ /* get/display the response */
+ while (1)
+ {
+ /* XXX - see also tracepoint.c:remote_get_noisy_reply() */
+ buf[0] = '\0';
+ getpkt (buf, (rs->remote_packet_size), 0);
+ if (buf[0] == '\0')
+ error ("Target does not support this command\n");
+ if (buf[0] == 'O' && buf[1] != 'K')
+ {
+ remote_console_output (buf + 1); /* 'O' message from stub */
+ continue;
+ }
+ if (strcmp (buf, "OK") == 0)
+ break;
+ if (strlen (buf) == 3 && buf[0] == 'E'
+ && isdigit (buf[1]) && isdigit (buf[2]))
+ {
+ error ("Protocol error with Rcmd");
+ }
+ for (p = buf; p[0] != '\0' && p[1] != '\0'; p += 2)
+ {
+ char c = (fromhex (p[0]) << 4) + fromhex (p[1]);
+ fputc_unfiltered (c, outbuf);
+ }
+ break;
+ }
+}
+
+static void
+packet_command (char *args, int from_tty)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf = alloca (rs->remote_packet_size);
+
+ if (!remote_desc)
+ error ("command can only be used with remote target");
+
+ if (!args)
+ error ("remote-packet command requires packet text as argument");
+
+ puts_filtered ("sending: ");
+ print_packet (args);
+ puts_filtered ("\n");
+ putpkt (args);
+
+ getpkt (buf, (rs->remote_packet_size), 0);
+ puts_filtered ("received: ");
+ print_packet (buf);
+ puts_filtered ("\n");
+}
+
+#if 0
+/* --------- UNIT_TEST for THREAD oriented PACKETS ------------------------- */
+
+static void display_thread_info (struct gdb_ext_thread_info *info);
+
+static void threadset_test_cmd (char *cmd, int tty);
+
+static void threadalive_test (char *cmd, int tty);
+
+static void threadlist_test_cmd (char *cmd, int tty);
+
+int get_and_display_threadinfo (threadref * ref);
+
+static void threadinfo_test_cmd (char *cmd, int tty);
+
+static int thread_display_step (threadref * ref, void *context);
+
+static void threadlist_update_test_cmd (char *cmd, int tty);
+
+static void init_remote_threadtests (void);
+
+#define SAMPLE_THREAD 0x05060708 /* Truncated 64 bit threadid */
+
+static void
+threadset_test_cmd (char *cmd, int tty)
+{
+ int sample_thread = SAMPLE_THREAD;
+
+ printf_filtered ("Remote threadset test\n");
+ set_thread (sample_thread, 1);
+}
+
+
+static void
+threadalive_test (char *cmd, int tty)
+{
+ int sample_thread = SAMPLE_THREAD;
+
+ if (remote_thread_alive (pid_to_ptid (sample_thread)))
+ printf_filtered ("PASS: Thread alive test\n");
+ else
+ printf_filtered ("FAIL: Thread alive test\n");
+}
+
+void output_threadid (char *title, threadref * ref);
+
+void
+output_threadid (char *title, threadref *ref)
+{
+ char hexid[20];
+
+ pack_threadid (&hexid[0], ref); /* Convert threead id into hex */
+ hexid[16] = 0;
+ printf_filtered ("%s %s\n", title, (&hexid[0]));
+}
+
+static void
+threadlist_test_cmd (char *cmd, int tty)
+{
+ int startflag = 1;
+ threadref nextthread;
+ int done, result_count;
+ threadref threadlist[3];
+
+ printf_filtered ("Remote Threadlist test\n");
+ if (!remote_get_threadlist (startflag, &nextthread, 3, &done,
+ &result_count, &threadlist[0]))
+ printf_filtered ("FAIL: threadlist test\n");
+ else
+ {
+ threadref *scan = threadlist;
+ threadref *limit = scan + result_count;
+
+ while (scan < limit)
+ output_threadid (" thread ", scan++);
+ }
+}
+
+void
+display_thread_info (struct gdb_ext_thread_info *info)
+{
+ output_threadid ("Threadid: ", &info->threadid);
+ printf_filtered ("Name: %s\n ", info->shortname);
+ printf_filtered ("State: %s\n", info->display);
+ printf_filtered ("other: %s\n\n", info->more_display);
+}
+
+int
+get_and_display_threadinfo (threadref *ref)
+{
+ int result;
+ int set;
+ struct gdb_ext_thread_info threadinfo;
+
+ set = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME
+ | TAG_MOREDISPLAY | TAG_DISPLAY;
+ if (0 != (result = remote_get_threadinfo (ref, set, &threadinfo)))
+ display_thread_info (&threadinfo);
+ return result;
+}
+
+static void
+threadinfo_test_cmd (char *cmd, int tty)
+{
+ int athread = SAMPLE_THREAD;
+ threadref thread;
+ int set;
+
+ int_to_threadref (&thread, athread);
+ printf_filtered ("Remote Threadinfo test\n");
+ if (!get_and_display_threadinfo (&thread))
+ printf_filtered ("FAIL cannot get thread info\n");
+}
+
+static int
+thread_display_step (threadref *ref, void *context)
+{
+ /* output_threadid(" threadstep ",ref); *//* simple test */
+ return get_and_display_threadinfo (ref);
+}
+
+static void
+threadlist_update_test_cmd (char *cmd, int tty)
+{
+ printf_filtered ("Remote Threadlist update test\n");
+ remote_threadlist_iterator (thread_display_step, 0, CRAZY_MAX_THREADS);
+}
+
+static void
+init_remote_threadtests (void)
+{
+ add_com ("tlist", class_obscure, threadlist_test_cmd,
+ "Fetch and print the remote list of thread identifiers, one pkt only");
+ add_com ("tinfo", class_obscure, threadinfo_test_cmd,
+ "Fetch and display info about one thread");
+ add_com ("tset", class_obscure, threadset_test_cmd,
+ "Test setting to a different thread");
+ add_com ("tupd", class_obscure, threadlist_update_test_cmd,
+ "Iterate through updating all remote thread info");
+ add_com ("talive", class_obscure, threadalive_test,
+ " Remote thread alive test ");
+}
+
+#endif /* 0 */
+
+/* Convert a thread ID to a string. Returns the string in a static
+ buffer. */
+
+static char *
+remote_pid_to_str (ptid_t ptid)
+{
+ static char buf[30];
+
+ sprintf (buf, "Thread %d", PIDGET (ptid));
+ return buf;
+}
+
+static void
+init_remote_ops (void)
+{
+ remote_ops.to_shortname = "remote";
+ remote_ops.to_longname = "Remote serial target in gdb-specific protocol";
+ remote_ops.to_doc =
+ "Use a remote computer via a serial line, using a gdb-specific protocol.\n\
+Specify the serial device it is connected to\n\
+(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.).";
+ remote_ops.to_open = remote_open;
+ remote_ops.to_close = remote_close;
+ remote_ops.to_detach = remote_detach;
+ remote_ops.to_disconnect = remote_disconnect;
+ remote_ops.to_resume = remote_resume;
+ remote_ops.to_wait = remote_wait;
+ remote_ops.to_fetch_registers = remote_fetch_registers;
+ remote_ops.to_store_registers = remote_store_registers;
+ remote_ops.to_prepare_to_store = remote_prepare_to_store;
+ remote_ops.to_xfer_memory = remote_xfer_memory;
+ remote_ops.to_files_info = remote_files_info;
+ remote_ops.to_insert_breakpoint = remote_insert_breakpoint;
+ remote_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint;
+ remote_ops.to_stopped_data_address = remote_stopped_data_address;
+ remote_ops.to_can_use_hw_breakpoint = remote_check_watch_resources;
+ remote_ops.to_insert_hw_breakpoint = remote_insert_hw_breakpoint;
+ remote_ops.to_remove_hw_breakpoint = remote_remove_hw_breakpoint;
+ remote_ops.to_insert_watchpoint = remote_insert_watchpoint;
+ remote_ops.to_remove_watchpoint = remote_remove_watchpoint;
+ remote_ops.to_kill = remote_kill;
+ remote_ops.to_load = generic_load;
+ remote_ops.to_mourn_inferior = remote_mourn;
+ remote_ops.to_thread_alive = remote_thread_alive;
+ remote_ops.to_find_new_threads = remote_threads_info;
+ remote_ops.to_pid_to_str = remote_pid_to_str;
+ remote_ops.to_extra_thread_info = remote_threads_extra_info;
+ remote_ops.to_stop = remote_stop;
+ remote_ops.to_xfer_partial = remote_xfer_partial;
+ remote_ops.to_rcmd = remote_rcmd;
+ remote_ops.to_stratum = process_stratum;
+ remote_ops.to_has_all_memory = 1;
+ remote_ops.to_has_memory = 1;
+ remote_ops.to_has_stack = 1;
+ remote_ops.to_has_registers = 1;
+ remote_ops.to_has_execution = 1;
+ remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
+ remote_ops.to_magic = OPS_MAGIC;
+}
+
+/* Set up the extended remote vector by making a copy of the standard
+ remote vector and adding to it. */
+
+static void
+init_extended_remote_ops (void)
+{
+ extended_remote_ops = remote_ops;
+
+ extended_remote_ops.to_shortname = "extended-remote";
+ extended_remote_ops.to_longname =
+ "Extended remote serial target in gdb-specific protocol";
+ extended_remote_ops.to_doc =
+ "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).",
+ extended_remote_ops.to_open = extended_remote_open;
+ extended_remote_ops.to_create_inferior = extended_remote_create_inferior;
+ extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
+}
+
+static int
+remote_can_async_p (void)
+{
+ /* We're async whenever the serial device is. */
+ return (current_target.to_async_mask_value) && serial_can_async_p (remote_desc);
+}
+
+static int
+remote_is_async_p (void)
+{
+ /* We're async whenever the serial device is. */
+ return (current_target.to_async_mask_value) && serial_is_async_p (remote_desc);
+}
+
+/* Pass the SERIAL event on and up to the client. One day this code
+ will be able to delay notifying the client of an event until the
+ point where an entire packet has been received. */
+
+static void (*async_client_callback) (enum inferior_event_type event_type, void *context);
+static void *async_client_context;
+static serial_event_ftype remote_async_serial_handler;
+
+static void
+remote_async_serial_handler (struct serial *scb, void *context)
+{
+ /* Don't propogate error information up to the client. Instead let
+ the client find out about the error by querying the target. */
+ async_client_callback (INF_REG_EVENT, async_client_context);
+}
+
+static void
+remote_async (void (*callback) (enum inferior_event_type event_type, void *context), void *context)
+{
+ if (current_target.to_async_mask_value == 0)
+ internal_error (__FILE__, __LINE__,
+ "Calling remote_async when async is masked");
+
+ if (callback != NULL)
+ {
+ serial_async (remote_desc, remote_async_serial_handler, NULL);
+ async_client_callback = callback;
+ async_client_context = context;
+ }
+ else
+ serial_async (remote_desc, NULL, NULL);
+}
+
+/* Target async and target extended-async.
+
+ This are temporary targets, until it is all tested. Eventually
+ async support will be incorporated int the usual 'remote'
+ target. */
+
+static void
+init_remote_async_ops (void)
+{
+ remote_async_ops.to_shortname = "async";
+ remote_async_ops.to_longname = "Remote serial target in async version of the gdb-specific protocol";
+ remote_async_ops.to_doc =
+ "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).";
+ remote_async_ops.to_open = remote_async_open;
+ remote_async_ops.to_close = remote_close;
+ remote_async_ops.to_detach = remote_detach;
+ remote_async_ops.to_disconnect = remote_disconnect;
+ remote_async_ops.to_resume = remote_async_resume;
+ remote_async_ops.to_wait = remote_async_wait;
+ remote_async_ops.to_fetch_registers = remote_fetch_registers;
+ remote_async_ops.to_store_registers = remote_store_registers;
+ remote_async_ops.to_prepare_to_store = remote_prepare_to_store;
+ remote_async_ops.to_xfer_memory = remote_xfer_memory;
+ remote_async_ops.to_files_info = remote_files_info;
+ remote_async_ops.to_insert_breakpoint = remote_insert_breakpoint;
+ remote_async_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_async_ops.to_can_use_hw_breakpoint = remote_check_watch_resources;
+ remote_async_ops.to_insert_hw_breakpoint = remote_insert_hw_breakpoint;
+ remote_async_ops.to_remove_hw_breakpoint = remote_remove_hw_breakpoint;
+ remote_async_ops.to_insert_watchpoint = remote_insert_watchpoint;
+ remote_async_ops.to_remove_watchpoint = remote_remove_watchpoint;
+ remote_async_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint;
+ remote_async_ops.to_stopped_data_address = remote_stopped_data_address;
+ remote_async_ops.to_terminal_inferior = remote_async_terminal_inferior;
+ remote_async_ops.to_terminal_ours = remote_async_terminal_ours;
+ remote_async_ops.to_kill = remote_async_kill;
+ remote_async_ops.to_load = generic_load;
+ remote_async_ops.to_mourn_inferior = remote_async_mourn;
+ remote_async_ops.to_thread_alive = remote_thread_alive;
+ remote_async_ops.to_find_new_threads = remote_threads_info;
+ remote_async_ops.to_pid_to_str = remote_pid_to_str;
+ remote_async_ops.to_extra_thread_info = remote_threads_extra_info;
+ remote_async_ops.to_stop = remote_stop;
+ remote_async_ops.to_xfer_partial = remote_xfer_partial;
+ remote_async_ops.to_rcmd = remote_rcmd;
+ remote_async_ops.to_stratum = process_stratum;
+ remote_async_ops.to_has_all_memory = 1;
+ remote_async_ops.to_has_memory = 1;
+ remote_async_ops.to_has_stack = 1;
+ remote_async_ops.to_has_registers = 1;
+ remote_async_ops.to_has_execution = 1;
+ remote_async_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
+ remote_async_ops.to_can_async_p = remote_can_async_p;
+ remote_async_ops.to_is_async_p = remote_is_async_p;
+ remote_async_ops.to_async = remote_async;
+ remote_async_ops.to_async_mask_value = 1;
+ remote_async_ops.to_magic = OPS_MAGIC;
+}
+
+/* Set up the async extended remote vector by making a copy of the standard
+ remote vector and adding to it. */
+
+static void
+init_extended_async_remote_ops (void)
+{
+ extended_async_remote_ops = remote_async_ops;
+
+ extended_async_remote_ops.to_shortname = "extended-async";
+ extended_async_remote_ops.to_longname =
+ "Extended remote serial target in async gdb-specific protocol";
+ extended_async_remote_ops.to_doc =
+ "Use a remote computer via a serial line, using an async gdb-specific protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).",
+ extended_async_remote_ops.to_open = extended_remote_async_open;
+ extended_async_remote_ops.to_create_inferior = extended_remote_async_create_inferior;
+ extended_async_remote_ops.to_mourn_inferior = extended_remote_mourn;
+}
+
+static void
+set_remote_cmd (char *args, int from_tty)
+{
+}
+
+static void
+show_remote_cmd (char *args, int from_tty)
+{
+ /* FIXME: cagney/2002-06-15: This function should iterate over
+ remote_show_cmdlist for a list of sub commands to show. */
+ show_remote_protocol_Z_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_e_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_E_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_P_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_qSymbol_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_vcont_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_binary_download_cmd (args, from_tty, NULL);
+ show_remote_protocol_qPart_auxv_packet_cmd (args, from_tty, NULL);
+ show_remote_protocol_qPart_dirty_packet_cmd (args, from_tty, NULL);
+}
+
+static void
+build_remote_gdbarch_data (void)
+{
+ remote_address_size = TARGET_ADDR_BIT;
+}
+
+/* Saved pointer to previous owner of the new_objfile event. */
+static void (*remote_new_objfile_chain) (struct objfile *);
+
+/* Function to be called whenever a new objfile (shlib) is detected. */
+static void
+remote_new_objfile (struct objfile *objfile)
+{
+ if (remote_desc != 0) /* Have a remote connection */
+ {
+ remote_check_symbols (objfile);
+ }
+ /* Call predecessor on chain, if any. */
+ if (remote_new_objfile_chain != 0 &&
+ remote_desc == 0)
+ remote_new_objfile_chain (objfile);
+}
+
+void
+_initialize_remote (void)
+{
+ static struct cmd_list_element *remote_set_cmdlist;
+ static struct cmd_list_element *remote_show_cmdlist;
+ struct cmd_list_element *tmpcmd;
+
+ /* architecture specific data */
+ remote_gdbarch_data_handle = register_gdbarch_data (init_remote_state);
+
+ /* Old tacky stuff. NOTE: This comes after the remote protocol so
+ that the remote protocol has been initialized. */
+ DEPRECATED_REGISTER_GDBARCH_SWAP (remote_address_size);
+ deprecated_register_gdbarch_swap (NULL, 0, build_remote_gdbarch_data);
+
+ init_remote_ops ();
+ add_target (&remote_ops);
+
+ init_extended_remote_ops ();
+ add_target (&extended_remote_ops);
+
+ init_remote_async_ops ();
+ add_target (&remote_async_ops);
+
+ init_extended_async_remote_ops ();
+ add_target (&extended_async_remote_ops);
+
+ /* Hook into new objfile notification. */
+ remote_new_objfile_chain = target_new_objfile_hook;
+ target_new_objfile_hook = remote_new_objfile;
+
+#if 0
+ init_remote_threadtests ();
+#endif
+
+ /* set/show remote ... */
+
+ add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, "\
+Remote protocol specific variables\n\
+Configure various remote-protocol specific variables such as\n\
+the packets being used",
+ &remote_set_cmdlist, "set remote ",
+ 0/*allow-unknown*/, &setlist);
+ add_prefix_cmd ("remote", class_maintenance, show_remote_cmd, "\
+Remote protocol specific variables\n\
+Configure various remote-protocol specific variables such as\n\
+the packets being used",
+ &remote_show_cmdlist, "show remote ",
+ 0/*allow-unknown*/, &showlist);
+
+ add_cmd ("compare-sections", class_obscure, compare_sections_command,
+ "Compare section data on target to the exec file.\n\
+Argument is a single section name (default: all loaded sections).",
+ &cmdlist);
+
+ add_cmd ("packet", class_maintenance, packet_command,
+ "Send an arbitrary packet to a remote target.\n\
+ maintenance packet TEXT\n\
+If GDB is talking to an inferior via the GDB serial protocol, then\n\
+this command sends the string TEXT to the inferior, and displays the\n\
+response packet. GDB supplies the initial `$' character, and the\n\
+terminating `#' character and checksum.",
+ &maintenancelist);
+
+ add_setshow_boolean_cmd ("remotebreak", no_class, &remote_break,
+ "Set whether to send break if interrupted.\n",
+ "Show whether to send break if interrupted.\n",
+ NULL, NULL,
+ &setlist, &showlist);
+
+ /* Install commands for configuring memory read/write packets. */
+
+ add_cmd ("remotewritesize", no_class, set_memory_write_packet_size,
+ "Set the maximum number of bytes per memory write packet (deprecated).\n",
+ &setlist);
+ add_cmd ("remotewritesize", no_class, show_memory_write_packet_size,
+ "Show the maximum number of bytes per memory write packet (deprecated).\n",
+ &showlist);
+ add_cmd ("memory-write-packet-size", no_class,
+ set_memory_write_packet_size,
+ "Set the maximum number of bytes per memory-write packet.\n"
+ "Specify the number of bytes in a packet or 0 (zero) for the\n"
+ "default packet size. The actual limit is further reduced\n"
+ "dependent on the target. Specify ``fixed'' to disable the\n"
+ "further restriction and ``limit'' to enable that restriction\n",
+ &remote_set_cmdlist);
+ add_cmd ("memory-read-packet-size", no_class,
+ set_memory_read_packet_size,
+ "Set the maximum number of bytes per memory-read packet.\n"
+ "Specify the number of bytes in a packet or 0 (zero) for the\n"
+ "default packet size. The actual limit is further reduced\n"
+ "dependent on the target. Specify ``fixed'' to disable the\n"
+ "further restriction and ``limit'' to enable that restriction\n",
+ &remote_set_cmdlist);
+ add_cmd ("memory-write-packet-size", no_class,
+ show_memory_write_packet_size,
+ "Show the maximum number of bytes per memory-write packet.\n",
+ &remote_show_cmdlist);
+ add_cmd ("memory-read-packet-size", no_class,
+ show_memory_read_packet_size,
+ "Show the maximum number of bytes per memory-read packet.\n",
+ &remote_show_cmdlist);
+
+ add_setshow_cmd ("hardware-watchpoint-limit", no_class,
+ var_zinteger, &remote_hw_watchpoint_limit, "\
+Set the maximum number of target hardware watchpoints.\n\
+Specify a negative limit for unlimited.", "\
+Show the maximum number of target hardware watchpoints.\n",
+ NULL, NULL, &remote_set_cmdlist, &remote_show_cmdlist);
+ add_setshow_cmd ("hardware-breakpoint-limit", no_class,
+ var_zinteger, &remote_hw_breakpoint_limit, "\
+Set the maximum number of target hardware breakpoints.\n\
+Specify a negative limit for unlimited.", "\
+Show the maximum number of target hardware breakpoints.\n",
+ NULL, NULL, &remote_set_cmdlist, &remote_show_cmdlist);
+
+ add_show_from_set
+ (add_set_cmd ("remoteaddresssize", class_obscure,
+ var_integer, (char *) &remote_address_size,
+ "Set the maximum size of the address (in bits) \
+in a memory packet.\n",
+ &setlist),
+ &showlist);
+
+ add_packet_config_cmd (&remote_protocol_binary_download,
+ "X", "binary-download",
+ set_remote_protocol_binary_download_cmd,
+ show_remote_protocol_binary_download_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 1);
+#if 0
+ /* XXXX - should ``set remotebinarydownload'' be retained for
+ compatibility. */
+ add_show_from_set
+ (add_set_cmd ("remotebinarydownload", no_class,
+ var_boolean, (char *) &remote_binary_download,
+ "Set binary downloads.\n", &setlist),
+ &showlist);
+#endif
+
+ add_packet_config_cmd (&remote_protocol_vcont,
+ "vCont", "verbose-resume",
+ set_remote_protocol_vcont_packet_cmd,
+ show_remote_protocol_vcont_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_qSymbol,
+ "qSymbol", "symbol-lookup",
+ set_remote_protocol_qSymbol_packet_cmd,
+ show_remote_protocol_qSymbol_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_e,
+ "e", "step-over-range",
+ set_remote_protocol_e_packet_cmd,
+ show_remote_protocol_e_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+ /* Disable by default. The ``e'' packet has nasty interactions with
+ the threading code - it relies on global state. */
+ remote_protocol_e.detect = AUTO_BOOLEAN_FALSE;
+ update_packet_config (&remote_protocol_e);
+
+ add_packet_config_cmd (&remote_protocol_E,
+ "E", "step-over-range-w-signal",
+ set_remote_protocol_E_packet_cmd,
+ show_remote_protocol_E_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+ /* Disable by default. The ``e'' packet has nasty interactions with
+ the threading code - it relies on global state. */
+ remote_protocol_E.detect = AUTO_BOOLEAN_FALSE;
+ update_packet_config (&remote_protocol_E);
+
+ add_packet_config_cmd (&remote_protocol_P,
+ "P", "set-register",
+ set_remote_protocol_P_packet_cmd,
+ show_remote_protocol_P_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 1);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP],
+ "Z0", "software-breakpoint",
+ set_remote_protocol_Z_software_bp_packet_cmd,
+ show_remote_protocol_Z_software_bp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_HARDWARE_BP],
+ "Z1", "hardware-breakpoint",
+ set_remote_protocol_Z_hardware_bp_packet_cmd,
+ show_remote_protocol_Z_hardware_bp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_WRITE_WP],
+ "Z2", "write-watchpoint",
+ set_remote_protocol_Z_write_wp_packet_cmd,
+ show_remote_protocol_Z_write_wp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_READ_WP],
+ "Z3", "read-watchpoint",
+ set_remote_protocol_Z_read_wp_packet_cmd,
+ show_remote_protocol_Z_read_wp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_ACCESS_WP],
+ "Z4", "access-watchpoint",
+ set_remote_protocol_Z_access_wp_packet_cmd,
+ show_remote_protocol_Z_access_wp_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_qPart_auxv,
+ "qPart_auxv", "read-aux-vector",
+ set_remote_protocol_qPart_auxv_packet_cmd,
+ show_remote_protocol_qPart_auxv_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_qPart_dirty,
+ "qPart_dirty", "read-dirty-registers",
+ set_remote_protocol_qPart_dirty_packet_cmd,
+ show_remote_protocol_qPart_dirty_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist,
+ 0);
+
+ /* Keep the old ``set remote Z-packet ...'' working. */
+ add_setshow_auto_boolean_cmd ("Z-packet", class_obscure,
+ &remote_Z_packet_detect, "\
+Set use of remote protocol `Z' packets",
+ "Show use of remote protocol `Z' packets ",
+ set_remote_protocol_Z_packet_cmd,
+ show_remote_protocol_Z_packet_cmd,
+ &remote_set_cmdlist, &remote_show_cmdlist);
+
+ /* Eventually initialize fileio. See fileio.c */
+ initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);
+}
diff --git a/contrib/gdb/gdb/remote.h b/contrib/gdb/gdb/remote.h
new file mode 100644
index 0000000..7c0df32
--- /dev/null
+++ b/contrib/gdb/gdb/remote.h
@@ -0,0 +1,64 @@
+/* Remote target communications for serial-line targets in custom GDB protocol
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef REMOTE_H
+#define REMOTE_H
+
+/* FIXME?: move this interface down to tgt vector) */
+
+/* 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. */
+
+extern void getpkt (char *buf, long sizeof_buf, int forever);
+
+/* Send a packet to the remote machine, with error checking. The data
+ of the packet is in BUF. The string in BUF can be at most PBUFSIZ
+ - 5 to account for the $, # and checksum, and for a possible /0 if
+ we are debugging (remote_debug) and want to print the sent packet
+ as a string */
+
+extern int putpkt (char *buf);
+
+/* Send HEX encoded string to the target console. (gdb_stdtarg) */
+
+extern void remote_console_output (char *);
+
+
+/* FIXME: cagney/1999-09-20: The remote cisco stuff in remote.c needs
+ to be broken out into a separate file (remote-cisco.[hc]?). Before
+ that can happen, a remote protocol stack framework needs to be
+ implemented. */
+
+extern void remote_cisco_objfile_relocate (bfd_signed_vma text_off,
+ bfd_signed_vma data_off,
+ bfd_signed_vma bss_off);
+
+extern void async_remote_interrupt_twice (void *arg);
+
+extern int remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len);
+
+extern int remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len);
+
+extern void (*target_resume_hook) (void);
+extern void (*target_wait_loop_hook) (void);
+
+#endif
diff --git a/contrib/gdb/gdb/reply_mig_hack.awk b/contrib/gdb/gdb/reply_mig_hack.awk
new file mode 100644
index 0000000..85c935d
--- /dev/null
+++ b/contrib/gdb/gdb/reply_mig_hack.awk
@@ -0,0 +1,123 @@
+# Reply server mig-output massager
+#
+# Copyright 1995, 1996, 1999 Free Software Foundation, Inc.
+#
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# This program is free software; you can redistribute 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.
+#
+# 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/rom68k-rom.c b/contrib/gdb/gdb/rom68k-rom.c
new file mode 100644
index 0000000..2ddba0a
--- /dev/null
+++ b/contrib/gdb/gdb/rom68k-rom.c
@@ -0,0 +1,264 @@
+/* Remote target glue for the ROM68K ROM monitor.
+ Copyright 1988, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include "value.h"
+
+#include "m68k-tdep.h"
+
+static void rom68k_open (char *args, int from_tty);
+
+/* Return true if C is a hex digit.
+ We can't use isxdigit here: that is affected by the current locale;
+ ROM68K is not. */
+static int
+is_hex_digit (int c)
+{
+ return (('0' <= c && c <= '9')
+ || ('a' <= c && c <= 'f')
+ || ('A' <= c && c <= 'F'));
+}
+
+
+/* Convert hex digit A to a number. */
+static int
+hex_digit_value (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 ("Invalid hex digit %d", a);
+}
+
+
+/* Return true iff C is a whitespace character.
+ We can't use isspace here: that is affected by the current locale;
+ ROM68K is not. */
+static int
+is_whitespace (int c)
+{
+ return (c == ' '
+ || c == '\r'
+ || c == '\n'
+ || c == '\t'
+ || c == '\f');
+}
+
+
+/* Parse a string of hex digits starting at HEX, supply them as the
+ value of register REGNO, skip any whitespace, and return a pointer
+ to the next character.
+
+ There is a function in monitor.c, monitor_supply_register, which is
+ supposed to do this job. However, there is some rather odd stuff
+ in there (whitespace characters don't terminate numbers, for
+ example) that is incorrect for ROM68k. It's basically impossible
+ to safely tweak monitor_supply_register --- it's used by a zillion
+ other monitors; who knows what behaviors they're depending on. So
+ instead, we'll just use our own function, which can behave exactly
+ the way we want it to. */
+static char *
+rom68k_supply_one_register (int regno, unsigned char *hex)
+{
+ ULONGEST value;
+ unsigned char regbuf[MAX_REGISTER_SIZE];
+
+ value = 0;
+ while (*hex != '\0')
+ if (is_hex_digit (*hex))
+ value = (value * 16) + hex_digit_value (*hex++);
+ else
+ break;
+
+ /* Skip any whitespace. */
+ while (is_whitespace (*hex))
+ hex++;
+
+ store_unsigned_integer (regbuf, DEPRECATED_REGISTER_RAW_SIZE (regno), value);
+ supply_register (regno, regbuf);
+
+ return hex;
+}
+
+
+static void
+rom68k_supply_register (char *regname, int regnamelen, char *val, int vallen)
+{
+ int numregs;
+ int regno;
+
+ numregs = 1;
+ regno = -1;
+
+ if (regnamelen == 2)
+ switch (regname[0])
+ {
+ case 'S':
+ if (regname[1] == 'R')
+ regno = PS_REGNUM;
+ break;
+ case 'P':
+ if (regname[1] == 'C')
+ regno = PC_REGNUM;
+ break;
+ case 'D':
+ if (regname[1] != 'R')
+ break;
+ regno = M68K_D0_REGNUM;
+ numregs = 8;
+ break;
+ case 'A':
+ if (regname[1] != 'R')
+ break;
+ regno = M68K_A0_REGNUM;
+ numregs = 7;
+ break;
+ }
+ else if (regnamelen == 3)
+ switch (regname[0])
+ {
+ case 'I':
+ if (regname[1] == 'S' && regname[2] == 'P')
+ regno = SP_REGNUM;
+ }
+
+ if (regno >= 0)
+ while (numregs-- > 0)
+ val = rom68k_supply_one_register (regno++, val);
+}
+
+/* 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". */
+
+static const char *
+rom68k_regname (int index)
+{
+
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "ISP",
+ "SR", "PC"
+ };
+
+ if ((index >= (sizeof (regnames) / sizeof(regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+
+}
+
+/* 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 rom68k_ops;
+
+static char *rom68k_inits[] =
+{".\r\r", NULL}; /* Exits pm/pr & download cmds */
+
+static struct monitor_ops rom68k_cmds;
+
+static void
+init_rom68k_cmds (void)
+{
+ rom68k_cmds.flags = MO_PRINT_PROGRAM_OUTPUT;
+ rom68k_cmds.init = rom68k_inits; /* monitor init string */
+ rom68k_cmds.cont = "go\r";
+ rom68k_cmds.step = "st\r";
+ rom68k_cmds.stop = NULL;
+ rom68k_cmds.set_break = "db %x\r";
+ rom68k_cmds.clr_break = "cb %x\r";
+ rom68k_cmds.clr_all_break = "cb *\r";
+ rom68k_cmds.fill = "fm %x %x %x\r";
+ rom68k_cmds.setmem.cmdb = "pm %x %x\r";
+ rom68k_cmds.setmem.cmdw = "pm.w %x %x\r";
+ rom68k_cmds.setmem.cmdl = "pm.l %x %x\r";
+ rom68k_cmds.setmem.cmdll = NULL;
+ rom68k_cmds.setmem.resp_delim = NULL;
+ rom68k_cmds.setmem.term = NULL;
+ rom68k_cmds.setmem.term_cmd = NULL;
+ rom68k_cmds.getmem.cmdb = "dm %x %x\r";
+ rom68k_cmds.getmem.cmdw = "dm.w %x %x\r";
+ rom68k_cmds.getmem.cmdl = "dm.l %x %x\r";
+ rom68k_cmds.getmem.cmdll = NULL;
+ rom68k_cmds.getmem.resp_delim = " ";
+ rom68k_cmds.getmem.term = NULL;
+ rom68k_cmds.getmem.term_cmd = NULL;
+ rom68k_cmds.setreg.cmd = "pr %s %x\r";
+ rom68k_cmds.setreg.resp_delim = NULL;
+ rom68k_cmds.setreg.term = NULL;
+ rom68k_cmds.setreg.term_cmd = NULL;
+ rom68k_cmds.getreg.cmd = "pr %s\r";
+ rom68k_cmds.getreg.resp_delim = ": ";
+ rom68k_cmds.getreg.term = "= ";
+ rom68k_cmds.getreg.term_cmd = ".\r";
+ rom68k_cmds.dump_registers = "dr\r";
+ rom68k_cmds.register_pattern =
+ "\\(\\w+\\)=\\([0-9a-fA-F]+\\( +[0-9a-fA-F]+\\b\\)*\\)";
+ rom68k_cmds.supply_register = rom68k_supply_register;
+ rom68k_cmds.load_routine = NULL;
+ rom68k_cmds.load = "dc\r";
+ rom68k_cmds.loadresp = "Waiting for S-records from host... ";
+ rom68k_cmds.prompt = "ROM68K :-> ";
+ rom68k_cmds.line_term = "\r";
+ rom68k_cmds.cmd_end = ".\r";
+ rom68k_cmds.target = &rom68k_ops;
+ rom68k_cmds.stopbits = SERIAL_1_STOPBITS;
+ rom68k_cmds.regnames = NULL;
+ rom68k_cmds.regname = rom68k_regname;
+ rom68k_cmds.magic = MONITOR_OPS_MAGIC;
+} /* init_rom68k_cmds */
+
+static void
+rom68k_open (char *args, int from_tty)
+{
+ monitor_open (args, &rom68k_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_rom68k; /* -Wmissing-prototypes */
+
+void
+_initialize_rom68k (void)
+{
+ init_rom68k_cmds ();
+ init_monitor_ops (&rom68k_ops);
+
+ rom68k_ops.to_shortname = "rom68k";
+ rom68k_ops.to_longname = "Rom68k debug monitor for the IDP Eval board";
+ rom68k_ops.to_doc = "Debug on a Motorola IDP eval board running the ROM68K monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ rom68k_ops.to_open = rom68k_open;
+
+ add_target (&rom68k_ops);
+}
diff --git a/contrib/gdb/gdb/rs6000-nat.c b/contrib/gdb/gdb/rs6000-nat.c
new file mode 100644
index 0000000..3d6c07c
--- /dev/null
+++ b/contrib/gdb/gdb/rs6000-nat.c
@@ -0,0 +1,1227 @@
+/* IBM RS/6000 native-dependent code for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "gdbcore.h"
+#include "xcoffsolib.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "libbfd.h" /* For bfd_cache_lookup (FIXME) */
+#include "bfd.h"
+#include "gdb-stabs.h"
+#include "regcache.h"
+#include "arch-utils.h"
+#include "language.h" /* for local_hex_string(). */
+#include "ppc-tdep.h"
+#include "exec.h"
+
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <a.out.h>
+#include <sys/file.h>
+#include "gdb_stat.h"
+#include <sys/core.h>
+#define __LDINFO_PTRACE32__ /* for __ld_info32 */
+#define __LDINFO_PTRACE64__ /* for __ld_info64 */
+#include <sys/ldr.h>
+#include <sys/systemcfg.h>
+
+/* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
+ debugging 32-bit and 64-bit processes. Define a typedef and macros for
+ accessing fields in the appropriate structures. */
+
+/* In 32-bit compilation mode (which is the only mode from which ptrace()
+ works on 4.3), __ld_info32 is #defined as equivalent to ld_info. */
+
+#ifdef __ld_info32
+# define ARCH3264
+#endif
+
+/* Return whether the current architecture is 64-bit. */
+
+#ifndef ARCH3264
+# define ARCH64() 0
+#else
+# define ARCH64() (DEPRECATED_REGISTER_RAW_SIZE (0) == 8)
+#endif
+
+/* Union of 32-bit and 64-bit ".reg" core file sections. */
+
+typedef union {
+#ifdef ARCH3264
+ struct __context64 r64;
+#else
+ struct mstsave r64;
+#endif
+ struct mstsave r32;
+} CoreRegs;
+
+/* Union of 32-bit and 64-bit versions of ld_info. */
+
+typedef union {
+#ifndef ARCH3264
+ struct ld_info l32;
+ struct ld_info l64;
+#else
+ struct __ld_info32 l32;
+ struct __ld_info64 l64;
+#endif
+} LdInfo;
+
+/* If compiling with 32-bit and 64-bit debugging capability (e.g. AIX 4.x),
+ declare and initialize a variable named VAR suitable for use as the arch64
+ parameter to the various LDI_*() macros. */
+
+#ifndef ARCH3264
+# define ARCH64_DECL(var)
+#else
+# define ARCH64_DECL(var) int var = ARCH64 ()
+#endif
+
+/* Return LDI's FIELD for a 64-bit process if ARCH64 and for a 32-bit process
+ otherwise. This technique only works for FIELDs with the same data type in
+ 32-bit and 64-bit versions of ld_info. */
+
+#ifndef ARCH3264
+# define LDI_FIELD(ldi, arch64, field) (ldi)->l32.ldinfo_##field
+#else
+# define LDI_FIELD(ldi, arch64, field) \
+ (arch64 ? (ldi)->l64.ldinfo_##field : (ldi)->l32.ldinfo_##field)
+#endif
+
+/* Return various LDI fields for a 64-bit process if ARCH64 and for a 32-bit
+ process otherwise. */
+
+#define LDI_NEXT(ldi, arch64) LDI_FIELD(ldi, arch64, next)
+#define LDI_FD(ldi, arch64) LDI_FIELD(ldi, arch64, fd)
+#define LDI_FILENAME(ldi, arch64) LDI_FIELD(ldi, arch64, filename)
+
+extern struct vmap *map_vmap (bfd * bf, bfd * arch);
+
+static void vmap_exec (void);
+
+static void vmap_ldinfo (LdInfo *);
+
+static struct vmap *add_vmap (LdInfo *);
+
+static int objfile_symbol_add (void *);
+
+static void vmap_symtab (struct vmap *);
+
+static void fetch_core_registers (char *, unsigned int, int, CORE_ADDR);
+
+static void exec_one_dummy_insn (void);
+
+extern void fixup_breakpoints (CORE_ADDR low, CORE_ADDR high, CORE_ADDR delta);
+
+/* Given REGNO, a gdb register number, return the corresponding
+ number suitable for use as a ptrace() parameter. Return -1 if
+ there's no suitable mapping. Also, set the int pointed to by
+ ISFLOAT to indicate whether REGNO is a floating point register. */
+
+static int
+regmap (int regno, int *isfloat)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ *isfloat = 0;
+ if (tdep->ppc_gp0_regnum <= regno && regno <= tdep->ppc_gplast_regnum)
+ return regno;
+ else if (FP0_REGNUM <= regno && regno <= FPLAST_REGNUM)
+ {
+ *isfloat = 1;
+ return regno - FP0_REGNUM + FPR0;
+ }
+ else if (regno == PC_REGNUM)
+ return IAR;
+ else if (regno == tdep->ppc_ps_regnum)
+ return MSR;
+ else if (regno == tdep->ppc_cr_regnum)
+ return CR;
+ else if (regno == tdep->ppc_lr_regnum)
+ return LR;
+ else if (regno == tdep->ppc_ctr_regnum)
+ return CTR;
+ else if (regno == tdep->ppc_xer_regnum)
+ return XER;
+ else if (regno == tdep->ppc_fpscr_regnum)
+ return FPSCR;
+ else if (tdep->ppc_mq_regnum >= 0 && regno == tdep->ppc_mq_regnum)
+ return MQ;
+ else
+ return -1;
+}
+
+/* Call ptrace(REQ, ID, ADDR, DATA, BUF). */
+
+static int
+rs6000_ptrace32 (int req, int id, int *addr, int data, int *buf)
+{
+ int ret = ptrace (req, id, (int *)addr, data, buf);
+#if 0
+ printf ("rs6000_ptrace32 (%d, %d, 0x%x, %08x, 0x%x) = 0x%x\n",
+ req, id, (unsigned int)addr, data, (unsigned int)buf, ret);
+#endif
+ return ret;
+}
+
+/* Call ptracex(REQ, ID, ADDR, DATA, BUF). */
+
+static int
+rs6000_ptrace64 (int req, int id, long long addr, int data, int *buf)
+{
+#ifdef ARCH3264
+ int ret = ptracex (req, id, addr, data, buf);
+#else
+ int ret = 0;
+#endif
+#if 0
+ printf ("rs6000_ptrace64 (%d, %d, 0x%llx, %08x, 0x%x) = 0x%x\n",
+ req, id, addr, data, (unsigned int)buf, ret);
+#endif
+ return ret;
+}
+
+/* Fetch register REGNO from the inferior. */
+
+static void
+fetch_register (int regno)
+{
+ int addr[MAX_REGISTER_SIZE];
+ int nr, isfloat;
+
+ /* Retrieved values may be -1, so infer errors from errno. */
+ errno = 0;
+
+ nr = regmap (regno, &isfloat);
+
+ /* Floating-point registers. */
+ if (isfloat)
+ rs6000_ptrace32 (PT_READ_FPR, PIDGET (inferior_ptid), addr, nr, 0);
+
+ /* Bogus register number. */
+ else if (nr < 0)
+ {
+ if (regno >= NUM_REGS)
+ fprintf_unfiltered (gdb_stderr,
+ "gdb error: register no %d not implemented.\n",
+ regno);
+ return;
+ }
+
+ /* Fixed-point registers. */
+ else
+ {
+ if (!ARCH64 ())
+ *addr = rs6000_ptrace32 (PT_READ_GPR, PIDGET (inferior_ptid), (int *)nr, 0, 0);
+ else
+ {
+ /* PT_READ_GPR requires the buffer parameter to point to long long,
+ even if the register is really only 32 bits. */
+ long long buf;
+ rs6000_ptrace64 (PT_READ_GPR, PIDGET (inferior_ptid), nr, 0, (int *)&buf);
+ if (DEPRECATED_REGISTER_RAW_SIZE (regno) == 8)
+ memcpy (addr, &buf, 8);
+ else
+ *addr = buf;
+ }
+ }
+
+ if (!errno)
+ supply_register (regno, (char *) addr);
+ else
+ {
+#if 0
+ /* FIXME: this happens 3 times at the start of each 64-bit program. */
+ perror ("ptrace read");
+#endif
+ errno = 0;
+ }
+}
+
+/* Store register REGNO back into the inferior. */
+
+static void
+store_register (int regno)
+{
+ int addr[MAX_REGISTER_SIZE];
+ int nr, isfloat;
+
+ /* Fetch the register's value from the register cache. */
+ regcache_collect (regno, addr);
+
+ /* -1 can be a successful return value, so infer errors from errno. */
+ errno = 0;
+
+ nr = regmap (regno, &isfloat);
+
+ /* Floating-point registers. */
+ if (isfloat)
+ rs6000_ptrace32 (PT_WRITE_FPR, PIDGET (inferior_ptid), addr, nr, 0);
+
+ /* Bogus register number. */
+ else if (nr < 0)
+ {
+ if (regno >= NUM_REGS)
+ fprintf_unfiltered (gdb_stderr,
+ "gdb error: register no %d not implemented.\n",
+ regno);
+ }
+
+ /* Fixed-point registers. */
+ else
+ {
+ if (regno == SP_REGNUM)
+ /* Execute one dummy instruction (which is a breakpoint) in inferior
+ process to give kernel a chance to do internal housekeeping.
+ Otherwise the following ptrace(2) calls will mess up user stack
+ since kernel will get confused about the bottom of the stack
+ (%sp). */
+ exec_one_dummy_insn ();
+
+ /* The PT_WRITE_GPR operation is rather odd. For 32-bit inferiors,
+ the register's value is passed by value, but for 64-bit inferiors,
+ the address of a buffer containing the value is passed. */
+ if (!ARCH64 ())
+ rs6000_ptrace32 (PT_WRITE_GPR, PIDGET (inferior_ptid), (int *)nr, *addr, 0);
+ else
+ {
+ /* PT_WRITE_GPR requires the buffer parameter to point to an 8-byte
+ area, even if the register is really only 32 bits. */
+ long long buf;
+ if (DEPRECATED_REGISTER_RAW_SIZE (regno) == 8)
+ memcpy (&buf, addr, 8);
+ else
+ buf = *addr;
+ rs6000_ptrace64 (PT_WRITE_GPR, PIDGET (inferior_ptid), nr, 0, (int *)&buf);
+ }
+ }
+
+ if (errno)
+ {
+ perror ("ptrace write");
+ errno = 0;
+ }
+}
+
+/* Read from the inferior all registers if REGNO == -1 and just register
+ REGNO otherwise. */
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno != -1)
+ fetch_register (regno);
+
+ else
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* Read 32 general purpose registers. */
+ for (regno = tdep->ppc_gp0_regnum;
+ regno <= tdep->ppc_gplast_regnum;
+ regno++)
+ {
+ fetch_register (regno);
+ }
+
+ /* Read general purpose floating point registers. */
+ for (regno = FP0_REGNUM; regno <= FPLAST_REGNUM; regno++)
+ fetch_register (regno);
+
+ /* Read special registers. */
+ fetch_register (PC_REGNUM);
+ fetch_register (tdep->ppc_ps_regnum);
+ fetch_register (tdep->ppc_cr_regnum);
+ fetch_register (tdep->ppc_lr_regnum);
+ fetch_register (tdep->ppc_ctr_regnum);
+ fetch_register (tdep->ppc_xer_regnum);
+ fetch_register (tdep->ppc_fpscr_regnum);
+ if (tdep->ppc_mq_regnum >= 0)
+ fetch_register (tdep->ppc_mq_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 (int regno)
+{
+ if (regno != -1)
+ store_register (regno);
+
+ else
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* Write general purpose registers first. */
+ for (regno = tdep->ppc_gp0_regnum;
+ regno <= tdep->ppc_gplast_regnum;
+ regno++)
+ {
+ store_register (regno);
+ }
+
+ /* Write floating point registers. */
+ for (regno = FP0_REGNUM; regno <= FPLAST_REGNUM; regno++)
+ store_register (regno);
+
+ /* Write special registers. */
+ store_register (PC_REGNUM);
+ store_register (tdep->ppc_ps_regnum);
+ store_register (tdep->ppc_cr_regnum);
+ store_register (tdep->ppc_lr_regnum);
+ store_register (tdep->ppc_ctr_regnum);
+ store_register (tdep->ppc_xer_regnum);
+ store_register (tdep->ppc_fpscr_regnum);
+ if (tdep->ppc_mq_regnum >= 0)
+ store_register (tdep->ppc_mq_regnum);
+ }
+}
+
+/* Store in *TO the 32-bit word at 32-bit-aligned ADDR in the child
+ process, which is 64-bit if ARCH64 and 32-bit otherwise. Return
+ success. */
+
+static int
+read_word (CORE_ADDR from, int *to, int arch64)
+{
+ /* Retrieved values may be -1, so infer errors from errno. */
+ errno = 0;
+
+ if (arch64)
+ *to = rs6000_ptrace64 (PT_READ_I, PIDGET (inferior_ptid), from, 0, NULL);
+ else
+ *to = rs6000_ptrace32 (PT_READ_I, PIDGET (inferior_ptid), (int *)(long) from,
+ 0, NULL);
+
+ return !errno;
+}
+
+/* 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 (CORE_ADDR memaddr, char *myaddr, int len,
+ int write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ /* Round starting address down to 32-bit word boundary. */
+ int mask = sizeof (int) - 1;
+ CORE_ADDR addr = memaddr & ~(CORE_ADDR)mask;
+
+ /* Round ending address up to 32-bit word boundary. */
+ int count = ((memaddr + len - addr + mask) & ~(CORE_ADDR)mask)
+ / sizeof (int);
+
+ /* Allocate word transfer buffer. */
+ /* FIXME (alloca): This code, cloned from infptrace.c, is unsafe
+ because it uses alloca to allocate a buffer of arbitrary size.
+ For very large xfers, this could crash GDB's stack. */
+ int *buf = (int *) alloca (count * sizeof (int));
+
+ int arch64 = ARCH64 ();
+ int i;
+
+ if (!write)
+ {
+ /* Retrieve memory a word at a time. */
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ if (!read_word (addr, buf + i, arch64))
+ return 0;
+ QUIT;
+ }
+
+ /* Copy memory to supplied buffer. */
+ addr -= count * sizeof (int);
+ memcpy (myaddr, (char *)buf + (memaddr - addr), len);
+ }
+ else
+ {
+ /* Fetch leading memory needed for alignment. */
+ if (addr < memaddr)
+ if (!read_word (addr, buf, arch64))
+ return 0;
+
+ /* Fetch trailing memory needed for alignment. */
+ if (addr + count * sizeof (int) > memaddr + len)
+ if (!read_word (addr + (count - 1) * sizeof (int),
+ buf + count - 1, arch64))
+ return 0;
+
+ /* Copy supplied data into memory buffer. */
+ memcpy ((char *)buf + (memaddr - addr), myaddr, len);
+
+ /* Store memory one word at a time. */
+ for (i = 0, errno = 0; i < count; i++, addr += sizeof (int))
+ {
+ if (arch64)
+ rs6000_ptrace64 (PT_WRITE_D, PIDGET (inferior_ptid), addr, buf[i], NULL);
+ else
+ rs6000_ptrace32 (PT_WRITE_D, PIDGET (inferior_ptid), (int *)(long) addr,
+ buf[i], NULL);
+
+ if (errno)
+ return 0;
+ QUIT;
+ }
+ }
+
+ return len;
+}
+
+/* Execute one dummy breakpoint instruction. This way we give the kernel
+ a chance to do some housekeeping and update inferior's internal data,
+ including u_area. */
+
+static void
+exec_one_dummy_insn (void)
+{
+#define DUMMY_INSN_ADDR (TEXT_SEGMENT_BASE)+0x200
+
+ char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */
+ int ret, status, pid;
+ CORE_ADDR prev_pc;
+
+ /* We plant one dummy breakpoint into DUMMY_INSN_ADDR address. We
+ assume that this address will never be executed again by the real
+ code. */
+
+ target_insert_breakpoint (DUMMY_INSN_ADDR, shadow_contents);
+
+ /* You might think this could be done with a single ptrace call, and
+ you'd be correct for just about every platform I've ever worked
+ on. However, rs6000-ibm-aix4.1.3 seems to have screwed this up --
+ the inferior never hits the breakpoint (it's also worth noting
+ powerpc-ibm-aix4.1.3 works correctly). */
+ prev_pc = read_pc ();
+ write_pc (DUMMY_INSN_ADDR);
+ if (ARCH64 ())
+ ret = rs6000_ptrace64 (PT_CONTINUE, PIDGET (inferior_ptid), 1, 0, NULL);
+ else
+ ret = rs6000_ptrace32 (PT_CONTINUE, PIDGET (inferior_ptid), (int *)1, 0, NULL);
+
+ if (ret != 0)
+ perror ("pt_continue");
+
+ do
+ {
+ pid = wait (&status);
+ }
+ while (pid != PIDGET (inferior_ptid));
+
+ write_pc (prev_pc);
+ target_remove_breakpoint (DUMMY_INSN_ADDR, shadow_contents);
+}
+
+/* Fetch registers from the register section in core bfd. */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR reg_addr)
+{
+ CoreRegs *regs;
+ int regi;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (which != 0)
+ {
+ fprintf_unfiltered
+ (gdb_stderr,
+ "Gdb error: unknown parameter to fetch_core_registers().\n");
+ return;
+ }
+
+ regs = (CoreRegs *) core_reg_sect;
+
+ /* Put the register values from the core file section in the regcache. */
+
+ if (ARCH64 ())
+ {
+ for (regi = 0; regi < 32; regi++)
+ supply_register (regi, (char *) &regs->r64.gpr[regi]);
+
+ for (regi = 0; regi < 32; regi++)
+ supply_register (FP0_REGNUM + regi, (char *) &regs->r64.fpr[regi]);
+
+ supply_register (PC_REGNUM, (char *) &regs->r64.iar);
+ supply_register (tdep->ppc_ps_regnum, (char *) &regs->r64.msr);
+ supply_register (tdep->ppc_cr_regnum, (char *) &regs->r64.cr);
+ supply_register (tdep->ppc_lr_regnum, (char *) &regs->r64.lr);
+ supply_register (tdep->ppc_ctr_regnum, (char *) &regs->r64.ctr);
+ supply_register (tdep->ppc_xer_regnum, (char *) &regs->r64.xer);
+ supply_register (tdep->ppc_fpscr_regnum, (char *) &regs->r64.fpscr);
+ }
+ else
+ {
+ for (regi = 0; regi < 32; regi++)
+ supply_register (regi, (char *) &regs->r32.gpr[regi]);
+
+ for (regi = 0; regi < 32; regi++)
+ supply_register (FP0_REGNUM + regi, (char *) &regs->r32.fpr[regi]);
+
+ supply_register (PC_REGNUM, (char *) &regs->r32.iar);
+ supply_register (tdep->ppc_ps_regnum, (char *) &regs->r32.msr);
+ supply_register (tdep->ppc_cr_regnum, (char *) &regs->r32.cr);
+ supply_register (tdep->ppc_lr_regnum, (char *) &regs->r32.lr);
+ supply_register (tdep->ppc_ctr_regnum, (char *) &regs->r32.ctr);
+ supply_register (tdep->ppc_xer_regnum, (char *) &regs->r32.xer);
+ supply_register (tdep->ppc_fpscr_regnum, (char *) &regs->r32.fpscr);
+ if (tdep->ppc_mq_regnum >= 0)
+ supply_register (tdep->ppc_mq_regnum, (char *) &regs->r32.mq);
+ }
+}
+
+
+/* Copy information about text and data sections from LDI to VP for a 64-bit
+ process if ARCH64 and for a 32-bit process otherwise. */
+
+static void
+vmap_secs (struct vmap *vp, LdInfo *ldi, int arch64)
+{
+ if (arch64)
+ {
+ vp->tstart = (CORE_ADDR) ldi->l64.ldinfo_textorg;
+ vp->tend = vp->tstart + ldi->l64.ldinfo_textsize;
+ vp->dstart = (CORE_ADDR) ldi->l64.ldinfo_dataorg;
+ vp->dend = vp->dstart + ldi->l64.ldinfo_datasize;
+ }
+ else
+ {
+ vp->tstart = (unsigned long) ldi->l32.ldinfo_textorg;
+ vp->tend = vp->tstart + ldi->l32.ldinfo_textsize;
+ vp->dstart = (unsigned long) ldi->l32.ldinfo_dataorg;
+ vp->dend = vp->dstart + ldi->l32.ldinfo_datasize;
+ }
+
+ /* The run time loader maps the file header in addition to the text
+ section and returns a pointer to the header in ldinfo_textorg.
+ Adjust the text start address to point to the real start address
+ of the text section. */
+ vp->tstart += vp->toffs;
+}
+
+/* handle symbol translation on vmapping */
+
+static void
+vmap_symtab (struct vmap *vp)
+{
+ struct objfile *objfile;
+ struct section_offsets *new_offsets;
+ int i;
+
+ objfile = vp->objfile;
+ if (objfile == NULL)
+ {
+ /* OK, it's not an objfile we opened ourselves.
+ Currently, that can only happen with the exec file, so
+ relocate the symbols for the symfile. */
+ if (symfile_objfile == NULL)
+ return;
+ objfile = symfile_objfile;
+ }
+ else if (!vp->loaded)
+ /* If symbols are not yet loaded, offsets are not yet valid. */
+ return;
+
+ new_offsets =
+ (struct section_offsets *)
+ alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ for (i = 0; i < objfile->num_sections; ++i)
+ new_offsets->offsets[i] = ANOFFSET (objfile->section_offsets, i);
+
+ /* The symbols in the object file are linked to the VMA of the section,
+ relocate them VMA relative. */
+ new_offsets->offsets[SECT_OFF_TEXT (objfile)] = vp->tstart - vp->tvma;
+ new_offsets->offsets[SECT_OFF_DATA (objfile)] = vp->dstart - vp->dvma;
+ new_offsets->offsets[SECT_OFF_BSS (objfile)] = vp->dstart - vp->dvma;
+
+ objfile_relocate (objfile, new_offsets);
+}
+
+/* Add symbols for an objfile. */
+
+static int
+objfile_symbol_add (void *arg)
+{
+ struct objfile *obj = (struct objfile *) arg;
+
+ syms_from_objfile (obj, NULL, 0, 0, 0, 0);
+ new_symfile_objfile (obj, 0, 0);
+ return 1;
+}
+
+/* Add symbols for a vmap. Return zero upon error. */
+
+int
+vmap_add_symbols (struct vmap *vp)
+{
+ if (catch_errors (objfile_symbol_add, vp->objfile,
+ "Error while reading shared library symbols:\n",
+ RETURN_MASK_ALL))
+ {
+ /* Note this is only done if symbol reading was successful. */
+ vp->loaded = 1;
+ vmap_symtab (vp);
+ return 1;
+ }
+ return 0;
+}
+
+/* Add a new vmap entry based on ldinfo() information.
+
+ If ldi->ldinfo_fd is not valid (e.g. this struct ld_info is from a
+ core file), the caller should set it to -1, and we will open the file.
+
+ Return the vmap new entry. */
+
+static struct vmap *
+add_vmap (LdInfo *ldi)
+{
+ bfd *abfd, *last;
+ char *mem, *objname, *filename;
+ struct objfile *obj;
+ struct vmap *vp;
+ int fd;
+ ARCH64_DECL (arch64);
+
+ /* This ldi structure was allocated using alloca() in
+ xcoff_relocate_symtab(). Now we need to have persistent object
+ and member names, so we should save them. */
+
+ filename = LDI_FILENAME (ldi, arch64);
+ mem = filename + strlen (filename) + 1;
+ mem = savestring (mem, strlen (mem));
+ objname = savestring (filename, strlen (filename));
+
+ fd = LDI_FD (ldi, arch64);
+ if (fd < 0)
+ /* Note that this opens it once for every member; a possible
+ enhancement would be to only open it once for every object. */
+ abfd = bfd_openr (objname, gnutarget);
+ else
+ abfd = bfd_fdopenr (objname, gnutarget, fd);
+ if (!abfd)
+ {
+ warning ("Could not open `%s' as an executable file: %s",
+ objname, bfd_errmsg (bfd_get_error ()));
+ return NULL;
+ }
+
+ /* make sure we have an object file */
+
+ if (bfd_check_format (abfd, bfd_object))
+ vp = map_vmap (abfd, 0);
+
+ else if (bfd_check_format (abfd, bfd_archive))
+ {
+ last = 0;
+ /* FIXME??? am I tossing BFDs? bfd? */
+ while ((last = bfd_openr_next_archived_file (abfd, last)))
+ if (DEPRECATED_STREQ (mem, last->filename))
+ break;
+
+ if (!last)
+ {
+ warning ("\"%s\": member \"%s\" missing.", objname, mem);
+ bfd_close (abfd);
+ return NULL;
+ }
+
+ if (!bfd_check_format (last, bfd_object))
+ {
+ warning ("\"%s\": member \"%s\" not in executable format: %s.",
+ objname, mem, bfd_errmsg (bfd_get_error ()));
+ bfd_close (last);
+ bfd_close (abfd);
+ return NULL;
+ }
+
+ vp = map_vmap (last, abfd);
+ }
+ else
+ {
+ warning ("\"%s\": not in executable format: %s.",
+ objname, bfd_errmsg (bfd_get_error ()));
+ bfd_close (abfd);
+ return NULL;
+ }
+ obj = allocate_objfile (vp->bfd, 0);
+ vp->objfile = obj;
+
+ /* Always add symbols for the main objfile. */
+ if (vp == vmap || auto_solib_add)
+ vmap_add_symbols (vp);
+ return vp;
+}
+
+/* update VMAP info with ldinfo() information
+ Input is ptr to ldinfo() results. */
+
+static void
+vmap_ldinfo (LdInfo *ldi)
+{
+ struct stat ii, vi;
+ struct vmap *vp;
+ int got_one, retried;
+ int got_exec_file = 0;
+ uint next;
+ int arch64 = ARCH64 ();
+
+ /* For each *ldi, see if we have a corresponding *vp.
+ If so, update the mapping, and symbol table.
+ If not, add an entry and symbol table. */
+
+ do
+ {
+ char *name = LDI_FILENAME (ldi, arch64);
+ char *memb = name + strlen (name) + 1;
+ int fd = LDI_FD (ldi, arch64);
+
+ retried = 0;
+
+ if (fstat (fd, &ii) < 0)
+ {
+ /* The kernel sets ld_info to -1, if the process is still using the
+ object, and the object is removed. Keep the symbol info for the
+ removed object and issue a warning. */
+ warning ("%s (fd=%d) has disappeared, keeping its symbols",
+ name, fd);
+ continue;
+ }
+ retry:
+ for (got_one = 0, vp = vmap; vp; vp = vp->nxt)
+ {
+ struct objfile *objfile;
+
+ /* First try to find a `vp', which is the same as in ldinfo.
+ If not the same, just continue and grep the next `vp'. If same,
+ relocate its tstart, tend, dstart, dend values. If no such `vp'
+ found, get out of this for loop, add this ldi entry as a new vmap
+ (add_vmap) and come back, find its `vp' and so on... */
+
+ /* The filenames are not always sufficient to match on. */
+
+ if ((name[0] == '/' && !DEPRECATED_STREQ (name, vp->name))
+ || (memb[0] && !DEPRECATED_STREQ (memb, vp->member)))
+ continue;
+
+ /* See if we are referring to the same file.
+ We have to check objfile->obfd, symfile.c:reread_symbols might
+ have updated the obfd after a change. */
+ objfile = vp->objfile == NULL ? symfile_objfile : vp->objfile;
+ if (objfile == NULL
+ || objfile->obfd == NULL
+ || bfd_stat (objfile->obfd, &vi) < 0)
+ {
+ warning ("Unable to stat %s, keeping its symbols", name);
+ continue;
+ }
+
+ if (ii.st_dev != vi.st_dev || ii.st_ino != vi.st_ino)
+ continue;
+
+ if (!retried)
+ close (fd);
+
+ ++got_one;
+
+ /* Found a corresponding VMAP. Remap! */
+
+ vmap_secs (vp, ldi, arch64);
+
+ /* The objfile is only NULL for the exec file. */
+ if (vp->objfile == NULL)
+ got_exec_file = 1;
+
+ /* relocate symbol table(s). */
+ vmap_symtab (vp);
+
+ /* Announce new object files. Doing this after symbol relocation
+ makes aix-thread.c's job easier. */
+ if (target_new_objfile_hook && vp->objfile)
+ target_new_objfile_hook (vp->objfile);
+
+ /* There may be more, so we don't break out of the loop. */
+ }
+
+ /* if there was no matching *vp, we must perforce create the sucker(s) */
+ if (!got_one && !retried)
+ {
+ add_vmap (ldi);
+ ++retried;
+ goto retry;
+ }
+ }
+ while ((next = LDI_NEXT (ldi, arch64))
+ && (ldi = (void *) (next + (char *) ldi)));
+
+ /* If we don't find the symfile_objfile anywhere in the ldinfo, it
+ is unlikely that the symbol file is relocated to the proper
+ address. And we might have attached to a process which is
+ running a different copy of the same executable. */
+ if (symfile_objfile != NULL && !got_exec_file)
+ {
+ warning ("Symbol file %s\nis not mapped; discarding it.\n\
+If in fact that file has symbols which the mapped files listed by\n\
+\"info files\" lack, you can load symbols with the \"symbol-file\" or\n\
+\"add-symbol-file\" commands (note that you must take care of relocating\n\
+symbols to the proper address).",
+ symfile_objfile->name);
+ free_objfile (symfile_objfile);
+ symfile_objfile = NULL;
+ }
+ breakpoint_re_set ();
+}
+
+/* As well as symbol tables, exec_sections need relocation. After
+ the inferior process' termination, there will be a relocated symbol
+ table exist with no corresponding inferior process. At that time, we
+ need to use `exec' bfd, rather than the inferior process's memory space
+ to look up symbols.
+
+ `exec_sections' need to be relocated only once, as long as the exec
+ file remains unchanged.
+ */
+
+static void
+vmap_exec (void)
+{
+ static bfd *execbfd;
+ int i;
+
+ if (execbfd == exec_bfd)
+ return;
+
+ execbfd = exec_bfd;
+
+ if (!vmap || !exec_ops.to_sections)
+ error ("vmap_exec: vmap or exec_ops.to_sections == 0\n");
+
+ for (i = 0; &exec_ops.to_sections[i] < exec_ops.to_sections_end; i++)
+ {
+ if (DEPRECATED_STREQ (".text", exec_ops.to_sections[i].the_bfd_section->name))
+ {
+ exec_ops.to_sections[i].addr += vmap->tstart - vmap->tvma;
+ exec_ops.to_sections[i].endaddr += vmap->tstart - vmap->tvma;
+ }
+ else if (DEPRECATED_STREQ (".data", exec_ops.to_sections[i].the_bfd_section->name))
+ {
+ exec_ops.to_sections[i].addr += vmap->dstart - vmap->dvma;
+ exec_ops.to_sections[i].endaddr += vmap->dstart - vmap->dvma;
+ }
+ else if (DEPRECATED_STREQ (".bss", exec_ops.to_sections[i].the_bfd_section->name))
+ {
+ exec_ops.to_sections[i].addr += vmap->dstart - vmap->dvma;
+ exec_ops.to_sections[i].endaddr += vmap->dstart - vmap->dvma;
+ }
+ }
+}
+
+/* Set the current architecture from the host running GDB. Called when
+ starting a child process. */
+
+static void
+set_host_arch (int pid)
+{
+ enum bfd_architecture arch;
+ unsigned long mach;
+ bfd abfd;
+ struct gdbarch_info info;
+
+ if (__power_rs ())
+ {
+ arch = bfd_arch_rs6000;
+ mach = bfd_mach_rs6k;
+ }
+ else
+ {
+ arch = bfd_arch_powerpc;
+ mach = bfd_mach_ppc;
+ }
+
+ /* FIXME: schauer/2002-02-25:
+ We don't know if we are executing a 32 or 64 bit executable,
+ and have no way to pass the proper word size to rs6000_gdbarch_init.
+ So we have to avoid switching to a new architecture, if the architecture
+ matches already.
+ Blindly calling rs6000_gdbarch_init used to work in older versions of
+ GDB, as rs6000_gdbarch_init incorrectly used the previous tdep to
+ determine the wordsize. */
+ if (exec_bfd)
+ {
+ const struct bfd_arch_info *exec_bfd_arch_info;
+
+ exec_bfd_arch_info = bfd_get_arch_info (exec_bfd);
+ if (arch == exec_bfd_arch_info->arch)
+ return;
+ }
+
+ bfd_default_set_arch_mach (&abfd, arch, mach);
+
+ gdbarch_info_init (&info);
+ info.bfd_arch_info = bfd_get_arch_info (&abfd);
+ info.abfd = exec_bfd;
+
+ if (!gdbarch_update_p (info))
+ {
+ internal_error (__FILE__, __LINE__,
+ "set_host_arch: failed to select architecture");
+ }
+}
+
+
+/* xcoff_relocate_symtab - hook for symbol table relocation.
+ also reads shared libraries.. */
+
+void
+xcoff_relocate_symtab (unsigned int pid)
+{
+ int load_segs = 64; /* number of load segments */
+ int rc;
+ LdInfo *ldi = NULL;
+ int arch64 = ARCH64 ();
+ int ldisize = arch64 ? sizeof (ldi->l64) : sizeof (ldi->l32);
+ int size;
+
+ do
+ {
+ size = load_segs * ldisize;
+ ldi = (void *) xrealloc (ldi, size);
+
+#if 0
+ /* According to my humble theory, AIX has some timing problems and
+ when the user stack grows, kernel doesn't update stack info in time
+ and ptrace calls step on user stack. That is why we sleep here a
+ little, and give kernel to update its internals. */
+ usleep (36000);
+#endif
+
+ if (arch64)
+ rc = rs6000_ptrace64 (PT_LDINFO, pid, (unsigned long) ldi, size, NULL);
+ else
+ rc = rs6000_ptrace32 (PT_LDINFO, pid, (int *) ldi, size, NULL);
+
+ if (rc == -1)
+ {
+ if (errno == ENOMEM)
+ load_segs *= 2;
+ else
+ perror_with_name ("ptrace ldinfo");
+ }
+ else
+ {
+ vmap_ldinfo (ldi);
+ vmap_exec (); /* relocate the exec and core sections as well. */
+ }
+ } while (rc == -1);
+ if (ldi)
+ xfree (ldi);
+}
+
+/* Core file stuff. */
+
+/* Relocate symtabs and read in shared library info, based on symbols
+ from the core file. */
+
+void
+xcoff_relocate_core (struct target_ops *target)
+{
+ struct bfd_section *ldinfo_sec;
+ int offset = 0;
+ LdInfo *ldi;
+ struct vmap *vp;
+ int arch64 = ARCH64 ();
+
+ /* Size of a struct ld_info except for the variable-length filename. */
+ int nonfilesz = (int)LDI_FILENAME ((LdInfo *)0, arch64);
+
+ /* Allocated size of buffer. */
+ int buffer_size = nonfilesz;
+ char *buffer = xmalloc (buffer_size);
+ struct cleanup *old = make_cleanup (free_current_contents, &buffer);
+
+ ldinfo_sec = bfd_get_section_by_name (core_bfd, ".ldinfo");
+ if (ldinfo_sec == NULL)
+ {
+ bfd_err:
+ fprintf_filtered (gdb_stderr, "Couldn't get ldinfo from core file: %s\n",
+ bfd_errmsg (bfd_get_error ()));
+ do_cleanups (old);
+ return;
+ }
+ do
+ {
+ int i;
+ int names_found = 0;
+
+ /* Read in everything but the name. */
+ if (bfd_get_section_contents (core_bfd, ldinfo_sec, buffer,
+ offset, nonfilesz) == 0)
+ goto bfd_err;
+
+ /* Now the name. */
+ i = nonfilesz;
+ do
+ {
+ if (i == buffer_size)
+ {
+ buffer_size *= 2;
+ buffer = xrealloc (buffer, buffer_size);
+ }
+ if (bfd_get_section_contents (core_bfd, ldinfo_sec, &buffer[i],
+ offset + i, 1) == 0)
+ goto bfd_err;
+ if (buffer[i++] == '\0')
+ ++names_found;
+ }
+ while (names_found < 2);
+
+ ldi = (LdInfo *) buffer;
+
+ /* Can't use a file descriptor from the core file; need to open it. */
+ if (arch64)
+ ldi->l64.ldinfo_fd = -1;
+ else
+ ldi->l32.ldinfo_fd = -1;
+
+ /* The first ldinfo is for the exec file, allocated elsewhere. */
+ if (offset == 0 && vmap != NULL)
+ vp = vmap;
+ else
+ vp = add_vmap (ldi);
+
+ /* Process next shared library upon error. */
+ offset += LDI_NEXT (ldi, arch64);
+ if (vp == NULL)
+ continue;
+
+ vmap_secs (vp, ldi, arch64);
+
+ /* Unless this is the exec file,
+ add our sections to the section table for the core target. */
+ if (vp != vmap)
+ {
+ struct section_table *stp;
+
+ target_resize_to_sections (target, 2);
+ stp = target->to_sections_end - 2;
+
+ stp->bfd = vp->bfd;
+ stp->the_bfd_section = bfd_get_section_by_name (stp->bfd, ".text");
+ stp->addr = vp->tstart;
+ stp->endaddr = vp->tend;
+ stp++;
+
+ stp->bfd = vp->bfd;
+ stp->the_bfd_section = bfd_get_section_by_name (stp->bfd, ".data");
+ stp->addr = vp->dstart;
+ stp->endaddr = vp->dend;
+ }
+
+ vmap_symtab (vp);
+
+ if (target_new_objfile_hook && vp != vmap && vp->objfile)
+ target_new_objfile_hook (vp->objfile);
+ }
+ while (LDI_NEXT (ldi, arch64) != 0);
+ vmap_exec ();
+ breakpoint_re_set ();
+ do_cleanups (old);
+}
+
+int
+kernel_u_size (void)
+{
+ return (sizeof (struct user));
+}
+
+/* Under AIX, we have to pass the correct TOC pointer to a function
+ when calling functions in the inferior.
+ We try to find the relative toc offset of the objfile containing PC
+ and add the current load address of the data segment from the vmap. */
+
+static CORE_ADDR
+find_toc_address (CORE_ADDR pc)
+{
+ struct vmap *vp;
+ extern CORE_ADDR get_toc_offset (struct objfile *); /* xcoffread.c */
+
+ for (vp = vmap; vp; vp = vp->nxt)
+ {
+ if (pc >= vp->tstart && pc < vp->tend)
+ {
+ /* vp->objfile is only NULL for the exec file. */
+ return vp->dstart + get_toc_offset (vp->objfile == NULL
+ ? symfile_objfile
+ : vp->objfile);
+ }
+ }
+ error ("Unable to find TOC entry for pc %s\n", local_hex_string (pc));
+}
+
+/* Register that we are able to handle rs6000 core file formats. */
+
+static struct core_fns rs6000_core_fns =
+{
+ bfd_target_xcoff_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_rs6000 (void)
+{
+ /* Initialize hook in rs6000-tdep.c for determining the TOC address when
+ calling functions in the inferior. */
+ rs6000_find_toc_address_hook = find_toc_address;
+
+ /* Initialize hook in rs6000-tdep.c to set the current architecture when
+ starting a child process. */
+ rs6000_set_host_arch_hook = set_host_arch;
+
+ add_core_fns (&rs6000_core_fns);
+}
diff --git a/contrib/gdb/gdb/rs6000-tdep.c b/contrib/gdb/gdb/rs6000-tdep.c
new file mode 100644
index 0000000..5eef895
--- /dev/null
+++ b/contrib/gdb/gdb/rs6000-tdep.c
@@ -0,0 +1,2981 @@
+/* Target-dependent code for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "target.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "doublest.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "osabi.h"
+
+#include "libbfd.h" /* for bfd_default_set_arch_mach */
+#include "coff/internal.h" /* for libcoff.h */
+#include "libcoff.h" /* for xcoff_data */
+#include "coff/xcoff.h"
+#include "libxcoff.h"
+
+#include "elf-bfd.h"
+
+#include "solib-svr4.h"
+#include "ppc-tdep.h"
+
+#include "gdb_assert.h"
+#include "dis-asm.h"
+
+/* If the kernel has to deliver a signal, it pushes a sigcontext
+ structure on the stack and then calls the signal handler, passing
+ the address of the sigcontext in an argument register. Usually
+ the signal handler doesn't save this register, so we have to
+ access the sigcontext structure via an offset from the signal handler
+ frame.
+ The following constants were determined by experimentation on AIX 3.2. */
+#define SIG_FRAME_PC_OFFSET 96
+#define SIG_FRAME_LR_OFFSET 108
+#define SIG_FRAME_FP_OFFSET 284
+
+/* To be used by skip_prologue. */
+
+struct rs6000_framedata
+ {
+ int offset; /* total size of frame --- the distance
+ by which we decrement sp to allocate
+ the frame */
+ int saved_gpr; /* smallest # of saved gpr */
+ int saved_fpr; /* smallest # of saved fpr */
+ int saved_vr; /* smallest # of saved vr */
+ int saved_ev; /* smallest # of saved ev */
+ int alloca_reg; /* alloca register number (frame ptr) */
+ char frameless; /* true if frameless functions. */
+ char nosavedpc; /* true if pc not saved. */
+ int gpr_offset; /* offset of saved gprs from prev sp */
+ int fpr_offset; /* offset of saved fprs from prev sp */
+ int vr_offset; /* offset of saved vrs from prev sp */
+ int ev_offset; /* offset of saved evs from prev sp */
+ int lr_offset; /* offset of saved lr */
+ int cr_offset; /* offset of saved cr */
+ int vrsave_offset; /* offset of saved vrsave register */
+ };
+
+/* Description of a single register. */
+
+struct reg
+ {
+ char *name; /* name of register */
+ unsigned char sz32; /* size on 32-bit arch, 0 if nonextant */
+ unsigned char sz64; /* size on 64-bit arch, 0 if nonextant */
+ unsigned char fpr; /* whether register is floating-point */
+ unsigned char pseudo; /* whether register is pseudo */
+ };
+
+/* Breakpoint shadows for the single step instructions will be kept here. */
+
+static struct sstep_breaks
+ {
+ /* Address, or 0 if this is not in use. */
+ CORE_ADDR address;
+ /* Shadow contents. */
+ char data[4];
+ }
+stepBreaks[2];
+
+/* Hook for determining the TOC address when calling functions in the
+ inferior under AIX. The initialization code in rs6000-nat.c sets
+ this hook to point to find_toc_address. */
+
+CORE_ADDR (*rs6000_find_toc_address_hook) (CORE_ADDR) = NULL;
+
+/* Hook to set the current architecture when starting a child process.
+ rs6000-nat.c sets this. */
+
+void (*rs6000_set_host_arch_hook) (int) = NULL;
+
+/* Static function prototypes */
+
+static CORE_ADDR branch_dest (int opcode, int instr, CORE_ADDR pc,
+ CORE_ADDR safety);
+static CORE_ADDR skip_prologue (CORE_ADDR, CORE_ADDR,
+ struct rs6000_framedata *);
+static void frame_get_saved_regs (struct frame_info * fi,
+ struct rs6000_framedata * fdatap);
+static CORE_ADDR frame_initial_stack_address (struct frame_info *);
+
+/* Is REGNO an AltiVec register? Return 1 if so, 0 otherwise. */
+int
+altivec_register_p (int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (tdep->ppc_vr0_regnum < 0 || tdep->ppc_vrsave_regnum < 0)
+ return 0;
+ else
+ return (regno >= tdep->ppc_vr0_regnum && regno <= tdep->ppc_vrsave_regnum);
+}
+
+/* Use the architectures FP registers? */
+int
+ppc_floating_point_unit_p (struct gdbarch *gdbarch)
+{
+ const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
+ if (info->arch == bfd_arch_powerpc)
+ return (info->mach != bfd_mach_ppc_e500);
+ if (info->arch == bfd_arch_rs6000)
+ return 1;
+ return 0;
+}
+
+/* Read a LEN-byte address from debugged memory address MEMADDR. */
+
+static CORE_ADDR
+read_memory_addr (CORE_ADDR memaddr, int len)
+{
+ return read_memory_unsigned_integer (memaddr, len);
+}
+
+static CORE_ADDR
+rs6000_skip_prologue (CORE_ADDR pc)
+{
+ struct rs6000_framedata frame;
+ pc = skip_prologue (pc, 0, &frame);
+ return pc;
+}
+
+
+/* Fill in fi->saved_regs */
+
+struct frame_extra_info
+{
+ /* Functions calling alloca() change the value of the stack
+ pointer. We need to use initial stack pointer (which is saved in
+ r31 by gcc) in such cases. If a compiler emits traceback table,
+ then we should use the alloca register specified in traceback
+ table. FIXME. */
+ CORE_ADDR initial_sp; /* initial stack pointer. */
+};
+
+void
+rs6000_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+ struct frame_extra_info *extra_info =
+ frame_extra_info_zalloc (fi, sizeof (struct frame_extra_info));
+ extra_info->initial_sp = 0;
+ if (get_next_frame (fi) != NULL
+ && get_frame_pc (fi) < TEXT_SEGMENT_BASE)
+ /* We're in get_prev_frame */
+ /* and this is a special signal frame. */
+ /* (fi->pc will be some low address in the kernel, */
+ /* to which the signal handler returns). */
+ deprecated_set_frame_type (fi, SIGTRAMP_FRAME);
+}
+
+/* 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. */
+
+/* In this implementation for RS/6000, we do *not* save sp. I am
+ not sure if it will be needed. The following function takes care of gpr's
+ and fpr's only. */
+
+void
+rs6000_frame_init_saved_regs (struct frame_info *fi)
+{
+ frame_get_saved_regs (fi, NULL);
+}
+
+static CORE_ADDR
+rs6000_frame_args_address (struct frame_info *fi)
+{
+ struct frame_extra_info *extra_info = get_frame_extra_info (fi);
+ if (extra_info->initial_sp != 0)
+ return extra_info->initial_sp;
+ else
+ return frame_initial_stack_address (fi);
+}
+
+/* Immediately after a function call, return the saved pc.
+ Can't go through the frames for this because on some machines
+ the new frame is not set up until the new function executes
+ some instructions. */
+
+static CORE_ADDR
+rs6000_saved_pc_after_call (struct frame_info *fi)
+{
+ return read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum);
+}
+
+/* Get the ith function argument for the current function. */
+static CORE_ADDR
+rs6000_fetch_pointer_argument (struct frame_info *frame, int argi,
+ struct type *type)
+{
+ CORE_ADDR addr;
+ get_frame_register (frame, 3 + argi, &addr);
+ return addr;
+}
+
+/* Calculate the destination of a branch/jump. Return -1 if not a branch. */
+
+static CORE_ADDR
+branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety)
+{
+ CORE_ADDR dest;
+ int immediate;
+ int absolute;
+ int ext_op;
+
+ absolute = (int) ((instr >> 1) & 1);
+
+ switch (opcode)
+ {
+ case 18:
+ immediate = ((instr & ~3) << 6) >> 6; /* br unconditional */
+ if (absolute)
+ dest = immediate;
+ else
+ dest = pc + immediate;
+ break;
+
+ case 16:
+ immediate = ((instr & ~3) << 16) >> 16; /* br conditional */
+ if (absolute)
+ dest = immediate;
+ else
+ dest = pc + immediate;
+ break;
+
+ case 19:
+ ext_op = (instr >> 1) & 0x3ff;
+
+ if (ext_op == 16) /* br conditional register */
+ {
+ dest = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum) & ~3;
+
+ /* If we are about to return from a signal handler, dest is
+ something like 0x3c90. The current frame is a signal handler
+ caller frame, upon completion of the sigreturn system call
+ execution will return to the saved PC in the frame. */
+ if (dest < TEXT_SEGMENT_BASE)
+ {
+ struct frame_info *fi;
+
+ fi = get_current_frame ();
+ if (fi != NULL)
+ dest = read_memory_addr (get_frame_base (fi) + SIG_FRAME_PC_OFFSET,
+ gdbarch_tdep (current_gdbarch)->wordsize);
+ }
+ }
+
+ else if (ext_op == 528) /* br cond to count reg */
+ {
+ dest = read_register (gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum) & ~3;
+
+ /* If we are about to execute a system call, dest is something
+ like 0x22fc or 0x3b00. Upon completion the system call
+ will return to the address in the link register. */
+ if (dest < TEXT_SEGMENT_BASE)
+ dest = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum) & ~3;
+ }
+ else
+ return -1;
+ break;
+
+ default:
+ return -1;
+ }
+ return (dest < TEXT_SEGMENT_BASE) ? safety : dest;
+}
+
+
+/* Sequence of bytes for breakpoint instruction. */
+
+const static unsigned char *
+rs6000_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size)
+{
+ static unsigned char big_breakpoint[] = { 0x7d, 0x82, 0x10, 0x08 };
+ static unsigned char little_breakpoint[] = { 0x08, 0x10, 0x82, 0x7d };
+ *bp_size = 4;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return big_breakpoint;
+ else
+ return little_breakpoint;
+}
+
+
+/* AIX does not support PT_STEP. Simulate it. */
+
+void
+rs6000_software_single_step (enum target_signal signal,
+ int insert_breakpoints_p)
+{
+ CORE_ADDR dummy;
+ int breakp_sz;
+ const char *breakp = rs6000_breakpoint_from_pc (&dummy, &breakp_sz);
+ int ii, insn;
+ CORE_ADDR loc;
+ CORE_ADDR breaks[2];
+ int opcode;
+
+ if (insert_breakpoints_p)
+ {
+
+ loc = read_pc ();
+
+ insn = read_memory_integer (loc, 4);
+
+ breaks[0] = loc + breakp_sz;
+ opcode = insn >> 26;
+ breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);
+
+ /* Don't put two breakpoints on the same address. */
+ if (breaks[1] == breaks[0])
+ breaks[1] = -1;
+
+ stepBreaks[1].address = 0;
+
+ for (ii = 0; ii < 2; ++ii)
+ {
+
+ /* ignore invalid breakpoint. */
+ if (breaks[ii] == -1)
+ continue;
+ target_insert_breakpoint (breaks[ii], stepBreaks[ii].data);
+ stepBreaks[ii].address = breaks[ii];
+ }
+
+ }
+ else
+ {
+
+ /* remove step breakpoints. */
+ for (ii = 0; ii < 2; ++ii)
+ if (stepBreaks[ii].address != 0)
+ target_remove_breakpoint (stepBreaks[ii].address,
+ stepBreaks[ii].data);
+ }
+ errno = 0; /* FIXME, don't ignore errors! */
+ /* What errors? {read,write}_memory call error(). */
+}
+
+
+/* return pc value after skipping a function prologue and also return
+ information about a function frame.
+
+ in struct rs6000_framedata fdata:
+ - frameless is TRUE, if function does not have a frame.
+ - nosavedpc is TRUE, if function does not save %pc value in its frame.
+ - offset is the initial size of this stack frame --- the amount by
+ which we decrement the sp to allocate the frame.
+ - saved_gpr is the number of the first saved gpr.
+ - saved_fpr is the number of the first saved fpr.
+ - saved_vr is the number of the first saved vr.
+ - saved_ev is the number of the first saved ev.
+ - alloca_reg is the number of the register used for alloca() handling.
+ Otherwise -1.
+ - gpr_offset is the offset of the first saved gpr from the previous frame.
+ - fpr_offset is the offset of the first saved fpr from the previous frame.
+ - vr_offset is the offset of the first saved vr from the previous frame.
+ - ev_offset is the offset of the first saved ev from the previous frame.
+ - lr_offset is the offset of the saved lr
+ - cr_offset is the offset of the saved cr
+ - vrsave_offset is the offset of the saved vrsave register
+ */
+
+#define SIGNED_SHORT(x) \
+ ((sizeof (short) == 2) \
+ ? ((int)(short)(x)) \
+ : ((int)((((x) & 0xffff) ^ 0x8000) - 0x8000)))
+
+#define GET_SRC_REG(x) (((x) >> 21) & 0x1f)
+
+/* Limit the number of skipped non-prologue instructions, as the examining
+ of the prologue is expensive. */
+static int max_skip_non_prologue_insns = 10;
+
+/* Given PC representing the starting address of a function, and
+ LIM_PC which is the (sloppy) limit to which to scan when looking
+ for a prologue, attempt to further refine this limit by using
+ the line data in the symbol table. If successful, a better guess
+ on where the prologue ends is returned, otherwise the previous
+ value of lim_pc is returned. */
+
+/* FIXME: cagney/2004-02-14: This function and logic have largely been
+ superseded by skip_prologue_using_sal. */
+
+static CORE_ADDR
+refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc)
+{
+ struct symtab_and_line prologue_sal;
+
+ prologue_sal = find_pc_line (pc, 0);
+ if (prologue_sal.line != 0)
+ {
+ int i;
+ CORE_ADDR addr = prologue_sal.end;
+
+ /* Handle the case in which compiler's optimizer/scheduler
+ has moved instructions into the prologue. We scan ahead
+ in the function looking for address ranges whose corresponding
+ line number is less than or equal to the first one that we
+ found for the function. (It can be less than when the
+ scheduler puts a body instruction before the first prologue
+ instruction.) */
+ for (i = 2 * max_skip_non_prologue_insns;
+ i > 0 && (lim_pc == 0 || addr < lim_pc);
+ i--)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (addr, 0);
+ if (sal.line == 0)
+ break;
+ if (sal.line <= prologue_sal.line
+ && sal.symtab == prologue_sal.symtab)
+ {
+ prologue_sal = sal;
+ }
+ addr = sal.end;
+ }
+
+ if (lim_pc == 0 || prologue_sal.end < lim_pc)
+ lim_pc = prologue_sal.end;
+ }
+ return lim_pc;
+}
+
+
+static CORE_ADDR
+skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
+{
+ CORE_ADDR orig_pc = pc;
+ CORE_ADDR last_prologue_pc = pc;
+ CORE_ADDR li_found_pc = 0;
+ char buf[4];
+ unsigned long op;
+ long offset = 0;
+ long vr_saved_offset = 0;
+ int lr_reg = -1;
+ int cr_reg = -1;
+ int vr_reg = -1;
+ int ev_reg = -1;
+ long ev_offset = 0;
+ int vrsave_reg = -1;
+ int reg;
+ int framep = 0;
+ int minimal_toc_loaded = 0;
+ int prev_insn_was_prologue_insn = 1;
+ int num_skip_non_prologue_insns = 0;
+ const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* Attempt to find the end of the prologue when no limit is specified.
+ Note that refine_prologue_limit() has been written so that it may
+ be used to "refine" the limits of non-zero PC values too, but this
+ is only safe if we 1) trust the line information provided by the
+ compiler and 2) iterate enough to actually find the end of the
+ prologue.
+
+ It may become a good idea at some point (for both performance and
+ accuracy) to unconditionally call refine_prologue_limit(). But,
+ until we can make a clear determination that this is beneficial,
+ we'll play it safe and only use it to obtain a limit when none
+ has been specified. */
+ if (lim_pc == 0)
+ lim_pc = refine_prologue_limit (pc, lim_pc);
+
+ memset (fdata, 0, sizeof (struct rs6000_framedata));
+ fdata->saved_gpr = -1;
+ fdata->saved_fpr = -1;
+ fdata->saved_vr = -1;
+ fdata->saved_ev = -1;
+ fdata->alloca_reg = -1;
+ fdata->frameless = 1;
+ fdata->nosavedpc = 1;
+
+ for (;; pc += 4)
+ {
+ /* Sometimes it isn't clear if an instruction is a prologue
+ instruction or not. When we encounter one of these ambiguous
+ cases, we'll set prev_insn_was_prologue_insn to 0 (false).
+ Otherwise, we'll assume that it really is a prologue instruction. */
+ if (prev_insn_was_prologue_insn)
+ last_prologue_pc = pc;
+
+ /* Stop scanning if we've hit the limit. */
+ if (lim_pc != 0 && pc >= lim_pc)
+ break;
+
+ prev_insn_was_prologue_insn = 1;
+
+ /* Fetch the instruction and convert it to an integer. */
+ if (target_read_memory (pc, buf, 4))
+ break;
+ op = extract_signed_integer (buf, 4);
+
+ if ((op & 0xfc1fffff) == 0x7c0802a6)
+ { /* mflr Rx */
+ lr_reg = (op & 0x03e00000);
+ continue;
+
+ }
+ else if ((op & 0xfc1fffff) == 0x7c000026)
+ { /* mfcr Rx */
+ cr_reg = (op & 0x03e00000);
+ continue;
+
+ }
+ else if ((op & 0xfc1f0000) == 0xd8010000)
+ { /* stfd Rx,NUM(r1) */
+ reg = GET_SRC_REG (op);
+ if (fdata->saved_fpr == -1 || fdata->saved_fpr > reg)
+ {
+ fdata->saved_fpr = reg;
+ fdata->fpr_offset = SIGNED_SHORT (op) + offset;
+ }
+ continue;
+
+ }
+ else if (((op & 0xfc1f0000) == 0xbc010000) || /* stm Rx, NUM(r1) */
+ (((op & 0xfc1f0000) == 0x90010000 || /* st rx,NUM(r1) */
+ (op & 0xfc1f0003) == 0xf8010000) && /* std rx,NUM(r1) */
+ (op & 0x03e00000) >= 0x01a00000)) /* rx >= r13 */
+ {
+
+ reg = GET_SRC_REG (op);
+ if (fdata->saved_gpr == -1 || fdata->saved_gpr > reg)
+ {
+ fdata->saved_gpr = reg;
+ if ((op & 0xfc1f0003) == 0xf8010000)
+ op &= ~3UL;
+ fdata->gpr_offset = SIGNED_SHORT (op) + offset;
+ }
+ continue;
+
+ }
+ else if ((op & 0xffff0000) == 0x60000000)
+ {
+ /* nop */
+ /* Allow nops in the prologue, but do not consider them to
+ be part of the prologue unless followed by other prologue
+ instructions. */
+ prev_insn_was_prologue_insn = 0;
+ continue;
+
+ }
+ else if ((op & 0xffff0000) == 0x3c000000)
+ { /* addis 0,0,NUM, used
+ for >= 32k frames */
+ fdata->offset = (op & 0x0000ffff) << 16;
+ fdata->frameless = 0;
+ continue;
+
+ }
+ else if ((op & 0xffff0000) == 0x60000000)
+ { /* ori 0,0,NUM, 2nd ha
+ lf of >= 32k frames */
+ fdata->offset |= (op & 0x0000ffff);
+ fdata->frameless = 0;
+ continue;
+
+ }
+ else if (lr_reg != -1 &&
+ /* std Rx, NUM(r1) || stdu Rx, NUM(r1) */
+ (((op & 0xffff0000) == (lr_reg | 0xf8010000)) ||
+ /* stw Rx, NUM(r1) */
+ ((op & 0xffff0000) == (lr_reg | 0x90010000)) ||
+ /* stwu Rx, NUM(r1) */
+ ((op & 0xffff0000) == (lr_reg | 0x94010000))))
+ { /* where Rx == lr */
+ fdata->lr_offset = offset;
+ fdata->nosavedpc = 0;
+ lr_reg = 0;
+ if ((op & 0xfc000003) == 0xf8000000 || /* std */
+ (op & 0xfc000000) == 0x90000000) /* stw */
+ {
+ /* Does not update r1, so add displacement to lr_offset. */
+ fdata->lr_offset += SIGNED_SHORT (op);
+ }
+ continue;
+
+ }
+ else if (cr_reg != -1 &&
+ /* std Rx, NUM(r1) || stdu Rx, NUM(r1) */
+ (((op & 0xffff0000) == (cr_reg | 0xf8010000)) ||
+ /* stw Rx, NUM(r1) */
+ ((op & 0xffff0000) == (cr_reg | 0x90010000)) ||
+ /* stwu Rx, NUM(r1) */
+ ((op & 0xffff0000) == (cr_reg | 0x94010000))))
+ { /* where Rx == cr */
+ fdata->cr_offset = offset;
+ cr_reg = 0;
+ if ((op & 0xfc000003) == 0xf8000000 ||
+ (op & 0xfc000000) == 0x90000000)
+ {
+ /* Does not update r1, so add displacement to cr_offset. */
+ fdata->cr_offset += SIGNED_SHORT (op);
+ }
+ continue;
+
+ }
+ else if (op == 0x48000005)
+ { /* bl .+4 used in
+ -mrelocatable */
+ continue;
+
+ }
+ else if (op == 0x48000004)
+ { /* b .+4 (xlc) */
+ break;
+
+ }
+ else if ((op & 0xffff0000) == 0x3fc00000 || /* addis 30,0,foo@ha, used
+ in V.4 -mminimal-toc */
+ (op & 0xffff0000) == 0x3bde0000)
+ { /* addi 30,30,foo@l */
+ continue;
+
+ }
+ else if ((op & 0xfc000001) == 0x48000001)
+ { /* bl foo,
+ to save fprs??? */
+
+ fdata->frameless = 0;
+ /* Don't skip over the subroutine call if it is not within
+ the first three instructions of the prologue. */
+ if ((pc - orig_pc) > 8)
+ break;
+
+ op = read_memory_integer (pc + 4, 4);
+
+ /* At this point, make sure this is not a trampoline
+ function (a function that simply calls another functions,
+ and nothing else). If the next is not a nop, this branch
+ was part of the function prologue. */
+
+ if (op == 0x4def7b82 || op == 0) /* crorc 15, 15, 15 */
+ break; /* don't skip over
+ this branch */
+ continue;
+
+ }
+ /* update stack pointer */
+ else if ((op & 0xfc1f0000) == 0x94010000)
+ { /* stu rX,NUM(r1) || stwu rX,NUM(r1) */
+ fdata->frameless = 0;
+ fdata->offset = SIGNED_SHORT (op);
+ offset = fdata->offset;
+ continue;
+ }
+ else if ((op & 0xfc1f016a) == 0x7c01016e)
+ { /* stwux rX,r1,rY */
+ /* no way to figure out what r1 is going to be */
+ fdata->frameless = 0;
+ offset = fdata->offset;
+ continue;
+ }
+ else if ((op & 0xfc1f0003) == 0xf8010001)
+ { /* stdu rX,NUM(r1) */
+ fdata->frameless = 0;
+ fdata->offset = SIGNED_SHORT (op & ~3UL);
+ offset = fdata->offset;
+ continue;
+ }
+ else if ((op & 0xfc1f016a) == 0x7c01016a)
+ { /* stdux rX,r1,rY */
+ /* no way to figure out what r1 is going to be */
+ fdata->frameless = 0;
+ offset = fdata->offset;
+ continue;
+ }
+ /* Load up minimal toc pointer */
+ else if (((op >> 22) == 0x20f || /* l r31,... or l r30,... */
+ (op >> 22) == 0x3af) /* ld r31,... or ld r30,... */
+ && !minimal_toc_loaded)
+ {
+ minimal_toc_loaded = 1;
+ continue;
+
+ /* move parameters from argument registers to local variable
+ registers */
+ }
+ else if ((op & 0xfc0007fe) == 0x7c000378 && /* mr(.) Rx,Ry */
+ (((op >> 21) & 31) >= 3) && /* R3 >= Ry >= R10 */
+ (((op >> 21) & 31) <= 10) &&
+ ((long) ((op >> 16) & 31) >= fdata->saved_gpr)) /* Rx: local var reg */
+ {
+ continue;
+
+ /* store parameters in stack */
+ }
+ else if ((op & 0xfc1f0003) == 0xf8010000 || /* std rx,NUM(r1) */
+ (op & 0xfc1f0000) == 0xd8010000 || /* stfd Rx,NUM(r1) */
+ (op & 0xfc1f0000) == 0xfc010000) /* frsp, fp?,NUM(r1) */
+ {
+ continue;
+
+ /* store parameters in stack via frame pointer */
+ }
+ else if (framep &&
+ ((op & 0xfc1f0000) == 0x901f0000 || /* st rx,NUM(r1) */
+ (op & 0xfc1f0000) == 0xd81f0000 || /* stfd Rx,NUM(r1) */
+ (op & 0xfc1f0000) == 0xfc1f0000))
+ { /* frsp, fp?,NUM(r1) */
+ continue;
+
+ /* Set up frame pointer */
+ }
+ else if (op == 0x603f0000 /* oril r31, r1, 0x0 */
+ || op == 0x7c3f0b78)
+ { /* mr r31, r1 */
+ fdata->frameless = 0;
+ framep = 1;
+ fdata->alloca_reg = (tdep->ppc_gp0_regnum + 31);
+ continue;
+
+ /* Another way to set up the frame pointer. */
+ }
+ else if ((op & 0xfc1fffff) == 0x38010000)
+ { /* addi rX, r1, 0x0 */
+ fdata->frameless = 0;
+ framep = 1;
+ fdata->alloca_reg = (tdep->ppc_gp0_regnum
+ + ((op & ~0x38010000) >> 21));
+ continue;
+ }
+ /* AltiVec related instructions. */
+ /* Store the vrsave register (spr 256) in another register for
+ later manipulation, or load a register into the vrsave
+ register. 2 instructions are used: mfvrsave and
+ mtvrsave. They are shorthand notation for mfspr Rn, SPR256
+ and mtspr SPR256, Rn. */
+ /* mfspr Rn SPR256 == 011111 nnnnn 0000001000 01010100110
+ mtspr SPR256 Rn == 011111 nnnnn 0000001000 01110100110 */
+ else if ((op & 0xfc1fffff) == 0x7c0042a6) /* mfvrsave Rn */
+ {
+ vrsave_reg = GET_SRC_REG (op);
+ continue;
+ }
+ else if ((op & 0xfc1fffff) == 0x7c0043a6) /* mtvrsave Rn */
+ {
+ continue;
+ }
+ /* Store the register where vrsave was saved to onto the stack:
+ rS is the register where vrsave was stored in a previous
+ instruction. */
+ /* 100100 sssss 00001 dddddddd dddddddd */
+ else if ((op & 0xfc1f0000) == 0x90010000) /* stw rS, d(r1) */
+ {
+ if (vrsave_reg == GET_SRC_REG (op))
+ {
+ fdata->vrsave_offset = SIGNED_SHORT (op) + offset;
+ vrsave_reg = -1;
+ }
+ continue;
+ }
+ /* Compute the new value of vrsave, by modifying the register
+ where vrsave was saved to. */
+ else if (((op & 0xfc000000) == 0x64000000) /* oris Ra, Rs, UIMM */
+ || ((op & 0xfc000000) == 0x60000000))/* ori Ra, Rs, UIMM */
+ {
+ continue;
+ }
+ /* li r0, SIMM (short for addi r0, 0, SIMM). This is the first
+ in a pair of insns to save the vector registers on the
+ stack. */
+ /* 001110 00000 00000 iiii iiii iiii iiii */
+ /* 001110 01110 00000 iiii iiii iiii iiii */
+ else if ((op & 0xffff0000) == 0x38000000 /* li r0, SIMM */
+ || (op & 0xffff0000) == 0x39c00000) /* li r14, SIMM */
+ {
+ li_found_pc = pc;
+ vr_saved_offset = SIGNED_SHORT (op);
+ }
+ /* Store vector register S at (r31+r0) aligned to 16 bytes. */
+ /* 011111 sssss 11111 00000 00111001110 */
+ else if ((op & 0xfc1fffff) == 0x7c1f01ce) /* stvx Vs, R31, R0 */
+ {
+ if (pc == (li_found_pc + 4))
+ {
+ vr_reg = GET_SRC_REG (op);
+ /* If this is the first vector reg to be saved, or if
+ it has a lower number than others previously seen,
+ reupdate the frame info. */
+ if (fdata->saved_vr == -1 || fdata->saved_vr > vr_reg)
+ {
+ fdata->saved_vr = vr_reg;
+ fdata->vr_offset = vr_saved_offset + offset;
+ }
+ vr_saved_offset = -1;
+ vr_reg = -1;
+ li_found_pc = 0;
+ }
+ }
+ /* End AltiVec related instructions. */
+
+ /* Start BookE related instructions. */
+ /* Store gen register S at (r31+uimm).
+ Any register less than r13 is volatile, so we don't care. */
+ /* 000100 sssss 11111 iiiii 01100100001 */
+ else if (arch_info->mach == bfd_mach_ppc_e500
+ && (op & 0xfc1f07ff) == 0x101f0321) /* evstdd Rs,uimm(R31) */
+ {
+ if ((op & 0x03e00000) >= 0x01a00000) /* Rs >= r13 */
+ {
+ unsigned int imm;
+ ev_reg = GET_SRC_REG (op);
+ imm = (op >> 11) & 0x1f;
+ ev_offset = imm * 8;
+ /* If this is the first vector reg to be saved, or if
+ it has a lower number than others previously seen,
+ reupdate the frame info. */
+ if (fdata->saved_ev == -1 || fdata->saved_ev > ev_reg)
+ {
+ fdata->saved_ev = ev_reg;
+ fdata->ev_offset = ev_offset + offset;
+ }
+ }
+ continue;
+ }
+ /* Store gen register rS at (r1+rB). */
+ /* 000100 sssss 00001 bbbbb 01100100000 */
+ else if (arch_info->mach == bfd_mach_ppc_e500
+ && (op & 0xffe007ff) == 0x13e00320) /* evstddx RS,R1,Rb */
+ {
+ if (pc == (li_found_pc + 4))
+ {
+ ev_reg = GET_SRC_REG (op);
+ /* If this is the first vector reg to be saved, or if
+ it has a lower number than others previously seen,
+ reupdate the frame info. */
+ /* We know the contents of rB from the previous instruction. */
+ if (fdata->saved_ev == -1 || fdata->saved_ev > ev_reg)
+ {
+ fdata->saved_ev = ev_reg;
+ fdata->ev_offset = vr_saved_offset + offset;
+ }
+ vr_saved_offset = -1;
+ ev_reg = -1;
+ li_found_pc = 0;
+ }
+ continue;
+ }
+ /* Store gen register r31 at (rA+uimm). */
+ /* 000100 11111 aaaaa iiiii 01100100001 */
+ else if (arch_info->mach == bfd_mach_ppc_e500
+ && (op & 0xffe007ff) == 0x13e00321) /* evstdd R31,Ra,UIMM */
+ {
+ /* Wwe know that the source register is 31 already, but
+ it can't hurt to compute it. */
+ ev_reg = GET_SRC_REG (op);
+ ev_offset = ((op >> 11) & 0x1f) * 8;
+ /* If this is the first vector reg to be saved, or if
+ it has a lower number than others previously seen,
+ reupdate the frame info. */
+ if (fdata->saved_ev == -1 || fdata->saved_ev > ev_reg)
+ {
+ fdata->saved_ev = ev_reg;
+ fdata->ev_offset = ev_offset + offset;
+ }
+
+ continue;
+ }
+ /* Store gen register S at (r31+r0).
+ Store param on stack when offset from SP bigger than 4 bytes. */
+ /* 000100 sssss 11111 00000 01100100000 */
+ else if (arch_info->mach == bfd_mach_ppc_e500
+ && (op & 0xfc1fffff) == 0x101f0320) /* evstddx Rs,R31,R0 */
+ {
+ if (pc == (li_found_pc + 4))
+ {
+ if ((op & 0x03e00000) >= 0x01a00000)
+ {
+ ev_reg = GET_SRC_REG (op);
+ /* If this is the first vector reg to be saved, or if
+ it has a lower number than others previously seen,
+ reupdate the frame info. */
+ /* We know the contents of r0 from the previous
+ instruction. */
+ if (fdata->saved_ev == -1 || fdata->saved_ev > ev_reg)
+ {
+ fdata->saved_ev = ev_reg;
+ fdata->ev_offset = vr_saved_offset + offset;
+ }
+ ev_reg = -1;
+ }
+ vr_saved_offset = -1;
+ li_found_pc = 0;
+ continue;
+ }
+ }
+ /* End BookE related instructions. */
+
+ else
+ {
+ /* Not a recognized prologue instruction.
+ Handle optimizer code motions into the prologue by continuing
+ the search if we have no valid frame yet or if the return
+ address is not yet saved in the frame. */
+ if (fdata->frameless == 0
+ && (lr_reg == -1 || fdata->nosavedpc == 0))
+ break;
+
+ if (op == 0x4e800020 /* blr */
+ || op == 0x4e800420) /* bctr */
+ /* Do not scan past epilogue in frameless functions or
+ trampolines. */
+ break;
+ if ((op & 0xf4000000) == 0x40000000) /* bxx */
+ /* Never skip branches. */
+ break;
+
+ if (num_skip_non_prologue_insns++ > max_skip_non_prologue_insns)
+ /* Do not scan too many insns, scanning insns is expensive with
+ remote targets. */
+ break;
+
+ /* Continue scanning. */
+ prev_insn_was_prologue_insn = 0;
+ continue;
+ }
+ }
+
+#if 0
+/* I have problems with skipping over __main() that I need to address
+ * sometime. Previously, I used to use misc_function_vector which
+ * didn't work as well as I wanted to be. -MGO */
+
+ /* If the first thing after skipping a prolog is a branch to a function,
+ this might be a call to an initializer in main(), introduced by gcc2.
+ We'd like to skip over it as well. Fortunately, xlc does some extra
+ work before calling a function right after a prologue, thus we can
+ single out such gcc2 behaviour. */
+
+
+ if ((op & 0xfc000001) == 0x48000001)
+ { /* bl foo, an initializer function? */
+ op = read_memory_integer (pc + 4, 4);
+
+ if (op == 0x4def7b82)
+ { /* cror 0xf, 0xf, 0xf (nop) */
+
+ /* Check and see if we are in main. If so, skip over this
+ initializer function as well. */
+
+ tmp = find_pc_misc_function (pc);
+ if (tmp >= 0
+ && strcmp (misc_function_vector[tmp].name, main_name ()) == 0)
+ return pc + 8;
+ }
+ }
+#endif /* 0 */
+
+ fdata->offset = -fdata->offset;
+ return last_prologue_pc;
+}
+
+
+/*************************************************************************
+ Support for creating pushing a dummy frame into the stack, and popping
+ frames, etc.
+*************************************************************************/
+
+
+/* Pop the innermost frame, go back to the caller. */
+
+static void
+rs6000_pop_frame (void)
+{
+ CORE_ADDR pc, lr, sp, prev_sp, addr; /* %pc, %lr, %sp */
+ struct rs6000_framedata fdata;
+ struct frame_info *frame = get_current_frame ();
+ int ii, wordsize;
+
+ pc = read_pc ();
+ sp = get_frame_base (frame);
+
+ if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame),
+ get_frame_base (frame),
+ get_frame_base (frame)))
+ {
+ generic_pop_dummy_frame ();
+ flush_cached_frames ();
+ return;
+ }
+
+ /* Make sure that all registers are valid. */
+ deprecated_read_register_bytes (0, NULL, DEPRECATED_REGISTER_BYTES);
+
+ /* Figure out previous %pc value. If the function is frameless, it is
+ still in the link register, otherwise walk the frames and retrieve the
+ saved %pc value in the previous frame. */
+
+ addr = get_frame_func (frame);
+ (void) skip_prologue (addr, get_frame_pc (frame), &fdata);
+
+ wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
+ if (fdata.frameless)
+ prev_sp = sp;
+ else
+ prev_sp = read_memory_addr (sp, wordsize);
+ if (fdata.lr_offset == 0)
+ lr = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum);
+ else
+ lr = read_memory_addr (prev_sp + fdata.lr_offset, wordsize);
+
+ /* reset %pc value. */
+ write_register (PC_REGNUM, lr);
+
+ /* reset register values if any was saved earlier. */
+
+ if (fdata.saved_gpr != -1)
+ {
+ addr = prev_sp + fdata.gpr_offset;
+ for (ii = fdata.saved_gpr; ii <= 31; ++ii)
+ {
+ read_memory (addr, &deprecated_registers[DEPRECATED_REGISTER_BYTE (ii)],
+ wordsize);
+ addr += wordsize;
+ }
+ }
+
+ if (fdata.saved_fpr != -1)
+ {
+ addr = prev_sp + fdata.fpr_offset;
+ for (ii = fdata.saved_fpr; ii <= 31; ++ii)
+ {
+ read_memory (addr, &deprecated_registers[DEPRECATED_REGISTER_BYTE (ii + FP0_REGNUM)], 8);
+ addr += 8;
+ }
+ }
+
+ write_register (SP_REGNUM, prev_sp);
+ target_store_registers (-1);
+ flush_cached_frames ();
+}
+
+/* All the ABI's require 16 byte alignment. */
+static CORE_ADDR
+rs6000_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return (addr & -16);
+}
+
+/* Pass the arguments in either registers, or in the stack. In RS/6000,
+ the first eight words of the argument list (that might be less than
+ eight parameters if some parameters occupy more than one word) are
+ passed in r3..r10 registers. float and double parameters are
+ passed in fpr's, in addition to that. Rest of the parameters if any
+ are passed in user stack. There might be cases in which half of the
+ parameter is copied into registers, the other half is pushed into
+ stack.
+
+ Stack must be aligned on 64-bit boundaries when synthesizing
+ function calls.
+
+ If the function is returning a structure, then the return address is passed
+ in r3, then the first 7 words of the parameters can be passed in registers,
+ starting from r4. */
+
+static CORE_ADDR
+rs6000_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int ii;
+ int len = 0;
+ int argno; /* current argument number */
+ int argbytes; /* current argument byte */
+ char tmp_buffer[50];
+ int f_argno = 0; /* current floating point argno */
+ int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
+
+ struct value *arg = 0;
+ struct type *type;
+
+ CORE_ADDR saved_sp;
+
+ /* The first eight words of ther arguments are passed in registers.
+ Copy them appropriately. */
+ ii = 0;
+
+ /* If the function is returning a `struct', then the first word
+ (which will be passed in r3) is used for struct return address.
+ In that case we should advance one word and start from r4
+ register to copy parameters. */
+ if (struct_return)
+ {
+ regcache_raw_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+ struct_addr);
+ ii++;
+ }
+
+/*
+ effectively indirect call... gcc does...
+
+ return_val example( float, int);
+
+ eabi:
+ float in fp0, int in r3
+ offset of stack on overflow 8/16
+ for varargs, must go by type.
+ power open:
+ float in r3&r4, int in r5
+ offset of stack on overflow different
+ both:
+ return in r3 or f0. If no float, must study how gcc emulates floats;
+ pay attention to arg promotion.
+ User may have to cast\args to handle promotion correctly
+ since gdb won't know if prototype supplied or not.
+ */
+
+ for (argno = 0, argbytes = 0; argno < nargs && ii < 8; ++ii)
+ {
+ int reg_size = DEPRECATED_REGISTER_RAW_SIZE (ii + 3);
+
+ arg = args[argno];
+ type = check_typedef (VALUE_TYPE (arg));
+ len = TYPE_LENGTH (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+
+ /* Floating point arguments are passed in fpr's, as well as gpr's.
+ There are 13 fpr's reserved for passing parameters. At this point
+ there is no way we would run out of them. */
+
+ if (len > 8)
+ printf_unfiltered (
+ "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
+
+ memcpy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM + 1 + f_argno)],
+ VALUE_CONTENTS (arg),
+ len);
+ ++f_argno;
+ }
+
+ if (len > reg_size)
+ {
+
+ /* Argument takes more than one register. */
+ while (argbytes < len)
+ {
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (ii + 3)], 0,
+ reg_size);
+ memcpy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (ii + 3)],
+ ((char *) VALUE_CONTENTS (arg)) + argbytes,
+ (len - argbytes) > reg_size
+ ? reg_size : len - argbytes);
+ ++ii, argbytes += reg_size;
+
+ if (ii >= 8)
+ goto ran_out_of_registers_for_arguments;
+ }
+ argbytes = 0;
+ --ii;
+ }
+ else
+ {
+ /* Argument can fit in one register. No problem. */
+ int adj = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? reg_size - len : 0;
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (ii + 3)], 0, reg_size);
+ memcpy ((char *)&deprecated_registers[DEPRECATED_REGISTER_BYTE (ii + 3)] + adj,
+ VALUE_CONTENTS (arg), len);
+ }
+ ++argno;
+ }
+
+ran_out_of_registers_for_arguments:
+
+ saved_sp = read_sp ();
+
+ /* Location for 8 parameters are always reserved. */
+ sp -= wordsize * 8;
+
+ /* Another six words for back chain, TOC register, link register, etc. */
+ sp -= wordsize * 6;
+
+ /* Stack pointer must be quadword aligned. */
+ sp &= -16;
+
+ /* If there are more arguments, allocate space for them in
+ the stack, then push them starting from the ninth one. */
+
+ if ((argno < nargs) || argbytes)
+ {
+ int space = 0, jj;
+
+ if (argbytes)
+ {
+ space += ((len - argbytes + 3) & -4);
+ jj = argno + 1;
+ }
+ else
+ jj = argno;
+
+ for (; jj < nargs; ++jj)
+ {
+ struct value *val = args[jj];
+ space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4;
+ }
+
+ /* Add location required for the rest of the parameters. */
+ space = (space + 15) & -16;
+ sp -= space;
+
+ /* This is another instance we need to be concerned about
+ securing our stack space. If we write anything underneath %sp
+ (r1), we might conflict with the kernel who thinks he is free
+ to use this area. So, update %sp first before doing anything
+ else. */
+
+ regcache_raw_write_signed (regcache, SP_REGNUM, sp);
+
+ /* If the last argument copied into the registers didn't fit there
+ completely, push the rest of it into stack. */
+
+ if (argbytes)
+ {
+ write_memory (sp + 24 + (ii * 4),
+ ((char *) VALUE_CONTENTS (arg)) + argbytes,
+ len - argbytes);
+ ++argno;
+ ii += ((len - argbytes + 3) & -4) / 4;
+ }
+
+ /* Push the rest of the arguments into stack. */
+ for (; argno < nargs; ++argno)
+ {
+
+ arg = args[argno];
+ type = check_typedef (VALUE_TYPE (arg));
+ len = TYPE_LENGTH (type);
+
+
+ /* Float types should be passed in fpr's, as well as in the
+ stack. */
+ if (TYPE_CODE (type) == TYPE_CODE_FLT && f_argno < 13)
+ {
+
+ if (len > 8)
+ printf_unfiltered (
+ "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
+
+ memcpy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM + 1 + f_argno)],
+ VALUE_CONTENTS (arg),
+ len);
+ ++f_argno;
+ }
+
+ write_memory (sp + 24 + (ii * 4), (char *) VALUE_CONTENTS (arg), len);
+ ii += ((len + 3) & -4) / 4;
+ }
+ }
+
+ /* Set the stack pointer. According to the ABI, the SP is meant to
+ be set _before_ the corresponding stack space is used. On AIX,
+ this even applies when the target has been completely stopped!
+ Not doing this can lead to conflicts with the kernel which thinks
+ that it still has control over this not-yet-allocated stack
+ region. */
+ regcache_raw_write_signed (regcache, SP_REGNUM, sp);
+
+ /* Set back chain properly. */
+ store_unsigned_integer (tmp_buffer, 4, saved_sp);
+ write_memory (sp, tmp_buffer, 4);
+
+ /* Point the inferior function call's return address at the dummy's
+ breakpoint. */
+ regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+ /* Set the TOC register, get the value from the objfile reader
+ which, in turn, gets it from the VMAP table. */
+ if (rs6000_find_toc_address_hook != NULL)
+ {
+ CORE_ADDR tocvalue = (*rs6000_find_toc_address_hook) (func_addr);
+ regcache_raw_write_signed (regcache, tdep->ppc_toc_regnum, tocvalue);
+ }
+
+ target_store_registers (-1);
+ return sp;
+}
+
+/* PowerOpen always puts structures in memory. Vectors, which were
+ added later, do get returned in a register though. */
+
+static int
+rs6000_use_struct_convention (int gcc_p, struct type *value_type)
+{
+ if ((TYPE_LENGTH (value_type) == 16 || TYPE_LENGTH (value_type) == 8)
+ && TYPE_VECTOR (value_type))
+ return 0;
+ return 1;
+}
+
+static void
+rs6000_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
+{
+ int offset = 0;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+ {
+
+ double dd;
+ float ff;
+ /* floats and doubles are returned in fpr1. fpr's have a size of 8 bytes.
+ We need to truncate the return value into float size (4 byte) if
+ necessary. */
+
+ if (TYPE_LENGTH (valtype) > 4) /* this is a double */
+ memcpy (valbuf,
+ &regbuf[DEPRECATED_REGISTER_BYTE (FP0_REGNUM + 1)],
+ TYPE_LENGTH (valtype));
+ else
+ { /* float */
+ memcpy (&dd, &regbuf[DEPRECATED_REGISTER_BYTE (FP0_REGNUM + 1)], 8);
+ ff = (float) dd;
+ memcpy (valbuf, &ff, sizeof (float));
+ }
+ }
+ else if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+ && TYPE_LENGTH (valtype) == 16
+ && TYPE_VECTOR (valtype))
+ {
+ memcpy (valbuf, regbuf + DEPRECATED_REGISTER_BYTE (tdep->ppc_vr0_regnum + 2),
+ TYPE_LENGTH (valtype));
+ }
+ else
+ {
+ /* return value is copied starting from r3. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && TYPE_LENGTH (valtype) < DEPRECATED_REGISTER_RAW_SIZE (3))
+ offset = DEPRECATED_REGISTER_RAW_SIZE (3) - TYPE_LENGTH (valtype);
+
+ memcpy (valbuf,
+ regbuf + DEPRECATED_REGISTER_BYTE (3) + offset,
+ TYPE_LENGTH (valtype));
+ }
+}
+
+/* Return whether handle_inferior_event() should proceed through code
+ starting at PC in function NAME when stepping.
+
+ The AIX -bbigtoc linker option generates functions @FIX0, @FIX1, etc. to
+ handle memory references that are too distant to fit in instructions
+ generated by the compiler. For example, if 'foo' in the following
+ instruction:
+
+ lwz r9,foo(r2)
+
+ is greater than 32767, the linker might replace the lwz with a branch to
+ somewhere in @FIX1 that does the load in 2 instructions and then branches
+ back to where execution should continue.
+
+ GDB should silently step over @FIX code, just like AIX dbx does.
+ Unfortunately, the linker uses the "b" instruction for the branches,
+ meaning that the link register doesn't get set. Therefore, GDB's usual
+ step_over_function() mechanism won't work.
+
+ Instead, use the IN_SOLIB_RETURN_TRAMPOLINE and SKIP_TRAMPOLINE_CODE hooks
+ in handle_inferior_event() to skip past @FIX code. */
+
+int
+rs6000_in_solib_return_trampoline (CORE_ADDR pc, char *name)
+{
+ return name && !strncmp (name, "@FIX", 4);
+}
+
+/* Skip code that the user doesn't want to see when stepping:
+
+ 1. Indirect function calls use a piece of trampoline code to do context
+ switching, i.e. to set the new TOC table. Skip such code if we are on
+ its first instruction (as when we have single-stepped to here).
+
+ 2. Skip shared library trampoline code (which is different from
+ indirect function call trampolines).
+
+ 3. Skip bigtoc fixup code.
+
+ Result is desired PC to step until, or NULL if we are not in
+ code that should be skipped. */
+
+CORE_ADDR
+rs6000_skip_trampoline_code (CORE_ADDR pc)
+{
+ unsigned int ii, op;
+ int rel;
+ CORE_ADDR solib_target_pc;
+ struct minimal_symbol *msymbol;
+
+ static unsigned trampoline_code[] =
+ {
+ 0x800b0000, /* l r0,0x0(r11) */
+ 0x90410014, /* st r2,0x14(r1) */
+ 0x7c0903a6, /* mtctr r0 */
+ 0x804b0004, /* l r2,0x4(r11) */
+ 0x816b0008, /* l r11,0x8(r11) */
+ 0x4e800420, /* bctr */
+ 0x4e800020, /* br */
+ 0
+ };
+
+ /* Check for bigtoc fixup code. */
+ msymbol = lookup_minimal_symbol_by_pc (pc);
+ if (msymbol && rs6000_in_solib_return_trampoline (pc, DEPRECATED_SYMBOL_NAME (msymbol)))
+ {
+ /* Double-check that the third instruction from PC is relative "b". */
+ op = read_memory_integer (pc + 8, 4);
+ if ((op & 0xfc000003) == 0x48000000)
+ {
+ /* Extract bits 6-29 as a signed 24-bit relative word address and
+ add it to the containing PC. */
+ rel = ((int)(op << 6) >> 6);
+ return pc + 8 + rel;
+ }
+ }
+
+ /* If pc is in a shared library trampoline, return its target. */
+ solib_target_pc = find_solib_trampoline_target (pc);
+ if (solib_target_pc)
+ return solib_target_pc;
+
+ for (ii = 0; trampoline_code[ii]; ++ii)
+ {
+ op = read_memory_integer (pc + (ii * 4), 4);
+ if (op != trampoline_code[ii])
+ return 0;
+ }
+ ii = read_register (11); /* r11 holds destination addr */
+ pc = read_memory_addr (ii, gdbarch_tdep (current_gdbarch)->wordsize); /* (r11) value */
+ return pc;
+}
+
+/* Determines whether the function FI has a frame on the stack or not. */
+
+int
+rs6000_frameless_function_invocation (struct frame_info *fi)
+{
+ CORE_ADDR func_start;
+ struct rs6000_framedata fdata;
+
+ /* Don't even think about framelessness except on the innermost frame
+ or if the function was interrupted by a signal. */
+ if (get_next_frame (fi) != NULL
+ && !(get_frame_type (get_next_frame (fi)) == SIGTRAMP_FRAME))
+ return 0;
+
+ func_start = get_frame_func (fi);
+
+ /* If we failed to find the start of the function, it is a mistake
+ to inspect the instructions. */
+
+ if (!func_start)
+ {
+ /* A frame with a zero PC is usually created by dereferencing a NULL
+ function pointer, normally causing an immediate core dump of the
+ inferior. Mark function as frameless, as the inferior has no chance
+ of setting up a stack frame. */
+ if (get_frame_pc (fi) == 0)
+ return 1;
+ else
+ return 0;
+ }
+
+ (void) skip_prologue (func_start, get_frame_pc (fi), &fdata);
+ return fdata.frameless;
+}
+
+/* Return the PC saved in a frame. */
+
+CORE_ADDR
+rs6000_frame_saved_pc (struct frame_info *fi)
+{
+ CORE_ADDR func_start;
+ struct rs6000_framedata fdata;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int wordsize = tdep->wordsize;
+
+ if ((get_frame_type (fi) == SIGTRAMP_FRAME))
+ return read_memory_addr (get_frame_base (fi) + SIG_FRAME_PC_OFFSET,
+ wordsize);
+
+ if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi),
+ get_frame_base (fi),
+ get_frame_base (fi)))
+ return deprecated_read_register_dummy (get_frame_pc (fi),
+ get_frame_base (fi), PC_REGNUM);
+
+ func_start = get_frame_func (fi);
+
+ /* If we failed to find the start of the function, it is a mistake
+ to inspect the instructions. */
+ if (!func_start)
+ return 0;
+
+ (void) skip_prologue (func_start, get_frame_pc (fi), &fdata);
+
+ if (fdata.lr_offset == 0 && get_next_frame (fi) != NULL)
+ {
+ if ((get_frame_type (get_next_frame (fi)) == SIGTRAMP_FRAME))
+ return read_memory_addr ((get_frame_base (get_next_frame (fi))
+ + SIG_FRAME_LR_OFFSET),
+ wordsize);
+ else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (get_next_frame (fi)), 0, 0))
+ /* The link register wasn't saved by this frame and the next
+ (inner, newer) frame is a dummy. Get the link register
+ value by unwinding it from that [dummy] frame. */
+ {
+ ULONGEST lr;
+ frame_unwind_unsigned_register (get_next_frame (fi),
+ tdep->ppc_lr_regnum, &lr);
+ return lr;
+ }
+ else
+ return read_memory_addr (DEPRECATED_FRAME_CHAIN (fi)
+ + tdep->lr_frame_offset,
+ wordsize);
+ }
+
+ if (fdata.lr_offset == 0)
+ return read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum);
+
+ return read_memory_addr (DEPRECATED_FRAME_CHAIN (fi) + fdata.lr_offset,
+ wordsize);
+}
+
+/* If saved registers of frame FI are not known yet, read and cache them.
+ &FDATAP contains rs6000_framedata; TDATAP can be NULL,
+ in which case the framedata are read. */
+
+static void
+frame_get_saved_regs (struct frame_info *fi, struct rs6000_framedata *fdatap)
+{
+ CORE_ADDR frame_addr;
+ struct rs6000_framedata work_fdata;
+ struct gdbarch_tdep * tdep = gdbarch_tdep (current_gdbarch);
+ int wordsize = tdep->wordsize;
+
+ if (deprecated_get_frame_saved_regs (fi))
+ return;
+
+ if (fdatap == NULL)
+ {
+ fdatap = &work_fdata;
+ (void) skip_prologue (get_frame_func (fi), get_frame_pc (fi), fdatap);
+ }
+
+ frame_saved_regs_zalloc (fi);
+
+ /* If there were any saved registers, figure out parent's stack
+ pointer. */
+ /* The following is true only if the frame doesn't have a call to
+ alloca(), FIXME. */
+
+ if (fdatap->saved_fpr == 0
+ && fdatap->saved_gpr == 0
+ && fdatap->saved_vr == 0
+ && fdatap->saved_ev == 0
+ && fdatap->lr_offset == 0
+ && fdatap->cr_offset == 0
+ && fdatap->vr_offset == 0
+ && fdatap->ev_offset == 0)
+ frame_addr = 0;
+ else
+ /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most
+ address of the current frame. Things might be easier if the
+ ->frame pointed to the outer-most address of the frame. In the
+ mean time, the address of the prev frame is used as the base
+ address of this frame. */
+ frame_addr = DEPRECATED_FRAME_CHAIN (fi);
+
+ /* if != -1, fdatap->saved_fpr is the smallest number of saved_fpr.
+ All fpr's from saved_fpr to fp31 are saved. */
+
+ if (fdatap->saved_fpr >= 0)
+ {
+ int i;
+ CORE_ADDR fpr_addr = frame_addr + fdatap->fpr_offset;
+ for (i = fdatap->saved_fpr; i < 32; i++)
+ {
+ deprecated_get_frame_saved_regs (fi)[FP0_REGNUM + i] = fpr_addr;
+ fpr_addr += 8;
+ }
+ }
+
+ /* if != -1, fdatap->saved_gpr is the smallest number of saved_gpr.
+ All gpr's from saved_gpr to gpr31 are saved. */
+
+ if (fdatap->saved_gpr >= 0)
+ {
+ int i;
+ CORE_ADDR gpr_addr = frame_addr + fdatap->gpr_offset;
+ for (i = fdatap->saved_gpr; i < 32; i++)
+ {
+ deprecated_get_frame_saved_regs (fi)[tdep->ppc_gp0_regnum + i] = gpr_addr;
+ gpr_addr += wordsize;
+ }
+ }
+
+ /* if != -1, fdatap->saved_vr is the smallest number of saved_vr.
+ All vr's from saved_vr to vr31 are saved. */
+ if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+ {
+ if (fdatap->saved_vr >= 0)
+ {
+ int i;
+ CORE_ADDR vr_addr = frame_addr + fdatap->vr_offset;
+ for (i = fdatap->saved_vr; i < 32; i++)
+ {
+ deprecated_get_frame_saved_regs (fi)[tdep->ppc_vr0_regnum + i] = vr_addr;
+ vr_addr += DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
+ }
+ }
+ }
+
+ /* if != -1, fdatap->saved_ev is the smallest number of saved_ev.
+ All vr's from saved_ev to ev31 are saved. ????? */
+ if (tdep->ppc_ev0_regnum != -1 && tdep->ppc_ev31_regnum != -1)
+ {
+ if (fdatap->saved_ev >= 0)
+ {
+ int i;
+ CORE_ADDR ev_addr = frame_addr + fdatap->ev_offset;
+ for (i = fdatap->saved_ev; i < 32; i++)
+ {
+ deprecated_get_frame_saved_regs (fi)[tdep->ppc_ev0_regnum + i] = ev_addr;
+ deprecated_get_frame_saved_regs (fi)[tdep->ppc_gp0_regnum + i] = ev_addr + 4;
+ ev_addr += DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_ev0_regnum);
+ }
+ }
+ }
+
+ /* If != 0, fdatap->cr_offset is the offset from the frame that holds
+ the CR. */
+ if (fdatap->cr_offset != 0)
+ deprecated_get_frame_saved_regs (fi)[tdep->ppc_cr_regnum] = frame_addr + fdatap->cr_offset;
+
+ /* If != 0, fdatap->lr_offset is the offset from the frame that holds
+ the LR. */
+ if (fdatap->lr_offset != 0)
+ deprecated_get_frame_saved_regs (fi)[tdep->ppc_lr_regnum] = frame_addr + fdatap->lr_offset;
+
+ /* If != 0, fdatap->vrsave_offset is the offset from the frame that holds
+ the VRSAVE. */
+ if (fdatap->vrsave_offset != 0)
+ deprecated_get_frame_saved_regs (fi)[tdep->ppc_vrsave_regnum] = frame_addr + fdatap->vrsave_offset;
+}
+
+/* Return the address of a frame. This is the inital %sp value when the frame
+ was first allocated. For functions calling alloca(), it might be saved in
+ an alloca register. */
+
+static CORE_ADDR
+frame_initial_stack_address (struct frame_info *fi)
+{
+ CORE_ADDR tmpaddr;
+ struct rs6000_framedata fdata;
+ struct frame_info *callee_fi;
+
+ /* If the initial stack pointer (frame address) of this frame is known,
+ just return it. */
+
+ if (get_frame_extra_info (fi)->initial_sp)
+ return get_frame_extra_info (fi)->initial_sp;
+
+ /* Find out if this function is using an alloca register. */
+
+ (void) skip_prologue (get_frame_func (fi), get_frame_pc (fi), &fdata);
+
+ /* If saved registers of this frame are not known yet, read and
+ cache them. */
+
+ if (!deprecated_get_frame_saved_regs (fi))
+ frame_get_saved_regs (fi, &fdata);
+
+ /* If no alloca register used, then fi->frame is the value of the %sp for
+ this frame, and it is good enough. */
+
+ if (fdata.alloca_reg < 0)
+ {
+ get_frame_extra_info (fi)->initial_sp = get_frame_base (fi);
+ return get_frame_extra_info (fi)->initial_sp;
+ }
+
+ /* There is an alloca register, use its value, in the current frame,
+ as the initial stack pointer. */
+ {
+ char tmpbuf[MAX_REGISTER_SIZE];
+ if (frame_register_read (fi, fdata.alloca_reg, tmpbuf))
+ {
+ get_frame_extra_info (fi)->initial_sp
+ = extract_unsigned_integer (tmpbuf,
+ DEPRECATED_REGISTER_RAW_SIZE (fdata.alloca_reg));
+ }
+ else
+ /* NOTE: cagney/2002-04-17: At present the only time
+ frame_register_read will fail is when the register isn't
+ available. If that does happen, use the frame. */
+ get_frame_extra_info (fi)->initial_sp = get_frame_base (fi);
+ }
+ return get_frame_extra_info (fi)->initial_sp;
+}
+
+/* Describe the pointer in each stack frame to the previous stack frame
+ (its caller). */
+
+/* DEPRECATED_FRAME_CHAIN takes a frame's nominal address and produces
+ the frame's chain-pointer. */
+
+/* In the case of the RS/6000, the frame's nominal address
+ is the address of a 4-byte word containing the calling frame's address. */
+
+CORE_ADDR
+rs6000_frame_chain (struct frame_info *thisframe)
+{
+ CORE_ADDR fp, fpp, lr;
+ int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
+
+ if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (thisframe),
+ get_frame_base (thisframe),
+ get_frame_base (thisframe)))
+ /* A dummy frame always correctly chains back to the previous
+ frame. */
+ return read_memory_addr (get_frame_base (thisframe), wordsize);
+
+ if (deprecated_inside_entry_file (get_frame_pc (thisframe))
+ || get_frame_pc (thisframe) == entry_point_address ())
+ return 0;
+
+ if ((get_frame_type (thisframe) == SIGTRAMP_FRAME))
+ fp = read_memory_addr (get_frame_base (thisframe) + SIG_FRAME_FP_OFFSET,
+ wordsize);
+ else if (get_next_frame (thisframe) != NULL
+ && (get_frame_type (get_next_frame (thisframe)) == SIGTRAMP_FRAME)
+ && (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ()
+ && DEPRECATED_FRAMELESS_FUNCTION_INVOCATION (thisframe)))
+ /* A frameless function interrupted by a signal did not change the
+ frame pointer. */
+ fp = get_frame_base (thisframe);
+ else
+ fp = read_memory_addr (get_frame_base (thisframe), wordsize);
+ return fp;
+}
+
+/* Return the size of register REG when words are WORDSIZE bytes long. If REG
+ isn't available with that word size, return 0. */
+
+static int
+regsize (const struct reg *reg, int wordsize)
+{
+ return wordsize == 8 ? reg->sz64 : reg->sz32;
+}
+
+/* Return the name of register number N, or null if no such register exists
+ in the current architecture. */
+
+static const char *
+rs6000_register_name (int n)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ const struct reg *reg = tdep->regs + n;
+
+ if (!regsize (reg, tdep->wordsize))
+ return NULL;
+ return reg->name;
+}
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+
+static int
+rs6000_register_byte (int n)
+{
+ return gdbarch_tdep (current_gdbarch)->regoff[n];
+}
+
+/* Return the number of bytes of storage in the actual machine representation
+ for register N if that register is available, else return 0. */
+
+static int
+rs6000_register_raw_size (int n)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ const struct reg *reg = tdep->regs + n;
+ return regsize (reg, tdep->wordsize);
+}
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+
+static struct type *
+rs6000_register_virtual_type (int n)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ const struct reg *reg = tdep->regs + n;
+
+ if (reg->fpr)
+ return builtin_type_double;
+ else
+ {
+ int size = regsize (reg, tdep->wordsize);
+ switch (size)
+ {
+ case 0:
+ return builtin_type_int0;
+ case 4:
+ return builtin_type_int32;
+ case 8:
+ if (tdep->ppc_ev0_regnum <= n && n <= tdep->ppc_ev31_regnum)
+ return builtin_type_vec64;
+ else
+ return builtin_type_int64;
+ break;
+ case 16:
+ return builtin_type_vec128;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "Register %d size %d unknown",
+ n, size);
+ }
+ }
+}
+
+/* Return whether register N requires conversion when moving from raw format
+ to virtual format.
+
+ The register format for RS/6000 floating point registers is always
+ double, we need a conversion if the memory format is float. */
+
+static int
+rs6000_register_convertible (int n)
+{
+ const struct reg *reg = gdbarch_tdep (current_gdbarch)->regs + n;
+ return reg->fpr;
+}
+
+/* Convert data from raw format for register N in buffer FROM
+ to virtual format with type TYPE in buffer TO. */
+
+static void
+rs6000_register_convert_to_virtual (int n, struct type *type,
+ char *from, char *to)
+{
+ if (TYPE_LENGTH (type) != DEPRECATED_REGISTER_RAW_SIZE (n))
+ {
+ double val = deprecated_extract_floating (from, DEPRECATED_REGISTER_RAW_SIZE (n));
+ deprecated_store_floating (to, TYPE_LENGTH (type), val);
+ }
+ else
+ memcpy (to, from, DEPRECATED_REGISTER_RAW_SIZE (n));
+}
+
+/* Convert data from virtual format with type TYPE in buffer FROM
+ to raw format for register N in buffer TO. */
+
+static void
+rs6000_register_convert_to_raw (struct type *type, int n,
+ const char *from, char *to)
+{
+ if (TYPE_LENGTH (type) != DEPRECATED_REGISTER_RAW_SIZE (n))
+ {
+ double val = deprecated_extract_floating (from, TYPE_LENGTH (type));
+ deprecated_store_floating (to, DEPRECATED_REGISTER_RAW_SIZE (n), val);
+ }
+ else
+ memcpy (to, from, DEPRECATED_REGISTER_RAW_SIZE (n));
+}
+
+static void
+e500_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int reg_nr, void *buffer)
+{
+ int base_regnum;
+ int offset = 0;
+ char temp_buffer[MAX_REGISTER_SIZE];
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (reg_nr >= tdep->ppc_gp0_regnum
+ && reg_nr <= tdep->ppc_gplast_regnum)
+ {
+ base_regnum = reg_nr - tdep->ppc_gp0_regnum + tdep->ppc_ev0_regnum;
+
+ /* Build the value in the provided buffer. */
+ /* Read the raw register of which this one is the lower portion. */
+ regcache_raw_read (regcache, base_regnum, temp_buffer);
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = 4;
+ memcpy ((char *) buffer, temp_buffer + offset, 4);
+ }
+}
+
+static void
+e500_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int reg_nr, const void *buffer)
+{
+ int base_regnum;
+ int offset = 0;
+ char temp_buffer[MAX_REGISTER_SIZE];
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (reg_nr >= tdep->ppc_gp0_regnum
+ && reg_nr <= tdep->ppc_gplast_regnum)
+ {
+ base_regnum = reg_nr - tdep->ppc_gp0_regnum + tdep->ppc_ev0_regnum;
+ /* reg_nr is 32 bit here, and base_regnum is 64 bits. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = 4;
+
+ /* Let's read the value of the base register into a temporary
+ buffer, so that overwriting the last four bytes with the new
+ value of the pseudo will leave the upper 4 bytes unchanged. */
+ regcache_raw_read (regcache, base_regnum, temp_buffer);
+
+ /* Write as an 8 byte quantity. */
+ memcpy (temp_buffer + offset, (char *) buffer, 4);
+ regcache_raw_write (regcache, base_regnum, temp_buffer);
+ }
+}
+
+/* Convert a dwarf2 register number to a gdb REGNUM. */
+static int
+e500_dwarf2_reg_to_regnum (int num)
+{
+ int regnum;
+ if (0 <= num && num <= 31)
+ return num + gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum;
+ else
+ return num;
+}
+
+/* Convert a dbx stab register number (from `r' declaration) to a gdb
+ REGNUM. */
+static int
+rs6000_stab_reg_to_regnum (int num)
+{
+ int regnum;
+ switch (num)
+ {
+ case 64:
+ regnum = gdbarch_tdep (current_gdbarch)->ppc_mq_regnum;
+ break;
+ case 65:
+ regnum = gdbarch_tdep (current_gdbarch)->ppc_lr_regnum;
+ break;
+ case 66:
+ regnum = gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum;
+ break;
+ case 76:
+ regnum = gdbarch_tdep (current_gdbarch)->ppc_xer_regnum;
+ break;
+ default:
+ regnum = num;
+ break;
+ }
+ return regnum;
+}
+
+static void
+rs6000_store_return_value (struct type *type, char *valbuf)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+
+ /* Floating point values are returned starting from FPR1 and up.
+ Say a double_double_double type could be returned in
+ FPR1/FPR2/FPR3 triple. */
+
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (FP0_REGNUM + 1), valbuf,
+ TYPE_LENGTH (type));
+ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ if (TYPE_LENGTH (type) == 16
+ && TYPE_VECTOR (type))
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (tdep->ppc_vr0_regnum + 2),
+ valbuf, TYPE_LENGTH (type));
+ }
+ else
+ /* Everything else is returned in GPR3 and up. */
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + 3),
+ 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). */
+
+static CORE_ADDR
+rs6000_extract_struct_value_address (struct regcache *regcache)
+{
+ /* FIXME: cagney/2002-09-26: PR gdb/724: When making an inferior
+ function call GDB knows the address of the struct return value
+ and hence, should not need to call this function. Unfortunately,
+ the current call_function_by_hand() code only saves the most
+ recent struct address leading to occasional calls. The code
+ should instead maintain a stack of such addresses (in the dummy
+ frame object). */
+ /* NOTE: cagney/2002-09-26: Return 0 which indicates that we've
+ really got no idea where the return value is being stored. While
+ r3, on function entry, contained the address it will have since
+ been reused (scratch) and hence wouldn't be valid */
+ return 0;
+}
+
+/* Hook called when a new child process is started. */
+
+void
+rs6000_create_inferior (int pid)
+{
+ if (rs6000_set_host_arch_hook)
+ rs6000_set_host_arch_hook (pid);
+}
+
+/* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG).
+
+ Usually a function pointer's representation is simply the address
+ of the function. On the RS/6000 however, a function pointer is
+ represented by a pointer to a TOC entry. This TOC entry contains
+ three words, the first word is the address of the function, the
+ second word is the TOC pointer (r2), and the third word is the
+ static chain value. Throughout GDB it is currently assumed that a
+ function pointer contains the address of the function, which is not
+ easy to fix. In addition, the conversion of a function address to
+ a function pointer would require allocation of a TOC entry in the
+ inferior's memory space, with all its drawbacks. To be able to
+ call C++ virtual methods in the inferior (which are called via
+ function pointers), find_function_addr uses this function to get the
+ function address from a function pointer. */
+
+/* Return real function address if ADDR (a function pointer) is in the data
+ space and is therefore a special function pointer. */
+
+static CORE_ADDR
+rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ struct obj_section *s;
+
+ s = find_pc_section (addr);
+ if (s && s->the_bfd_section->flags & SEC_CODE)
+ return addr;
+
+ /* ADDR is in the data space, so it's a special function pointer. */
+ return read_memory_addr (addr, gdbarch_tdep (current_gdbarch)->wordsize);
+}
+
+
+/* Handling the various POWER/PowerPC variants. */
+
+
+/* The arrays here called registers_MUMBLE hold information about available
+ registers.
+
+ For each family of PPC variants, I've tried to isolate out the
+ common registers and put them up front, so that as long as you get
+ the general family right, GDB will correctly identify the registers
+ common to that family. The common register sets are:
+
+ For the 60x family: hid0 hid1 iabr dabr pir
+
+ For the 505 and 860 family: eie eid nri
+
+ For the 403 and 403GC: icdbdr esr dear evpr cdbcr tsr tcr pit tbhi
+ tblo srr2 srr3 dbsr dbcr iac1 iac2 dac1 dac2 dccr iccr pbl1
+ pbu1 pbl2 pbu2
+
+ Most of these register groups aren't anything formal. I arrived at
+ them by looking at the registers that occurred in more than one
+ processor.
+
+ Note: kevinb/2002-04-30: Support for the fpscr register was added
+ during April, 2002. Slot 70 is being used for PowerPC and slot 71
+ for Power. For PowerPC, slot 70 was unused and was already in the
+ PPC_UISA_SPRS which is ideally where fpscr should go. For Power,
+ slot 70 was being used for "mq", so the next available slot (71)
+ was chosen. It would have been nice to be able to make the
+ register numbers the same across processor cores, but this wasn't
+ possible without either 1) renumbering some registers for some
+ processors or 2) assigning fpscr to a really high slot that's
+ larger than any current register number. Doing (1) is bad because
+ existing stubs would break. Doing (2) is undesirable because it
+ would introduce a really large gap between fpscr and the rest of
+ the registers for most processors. */
+
+/* Convenience macros for populating register arrays. */
+
+/* Within another macro, convert S to a string. */
+
+#define STR(s) #s
+
+/* Return a struct reg defining register NAME that's 32 bits on 32-bit systems
+ and 64 bits on 64-bit systems. */
+#define R(name) { STR(name), 4, 8, 0, 0 }
+
+/* Return a struct reg defining register NAME that's 32 bits on all
+ systems. */
+#define R4(name) { STR(name), 4, 4, 0, 0 }
+
+/* Return a struct reg defining register NAME that's 64 bits on all
+ systems. */
+#define R8(name) { STR(name), 8, 8, 0, 0 }
+
+/* Return a struct reg defining register NAME that's 128 bits on all
+ systems. */
+#define R16(name) { STR(name), 16, 16, 0, 0 }
+
+/* Return a struct reg defining floating-point register NAME. */
+#define F(name) { STR(name), 8, 8, 1, 0 }
+
+/* Return a struct reg defining a pseudo register NAME. */
+#define P(name) { STR(name), 4, 8, 0, 1}
+
+/* Return a struct reg defining register NAME that's 32 bits on 32-bit
+ systems and that doesn't exist on 64-bit systems. */
+#define R32(name) { STR(name), 4, 0, 0, 0 }
+
+/* Return a struct reg defining register NAME that's 64 bits on 64-bit
+ systems and that doesn't exist on 32-bit systems. */
+#define R64(name) { STR(name), 0, 8, 0, 0 }
+
+/* Return a struct reg placeholder for a register that doesn't exist. */
+#define R0 { 0, 0, 0, 0, 0 }
+
+/* UISA registers common across all architectures, including POWER. */
+
+#define COMMON_UISA_REGS \
+ /* 0 */ R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), \
+ /* 8 */ R(r8), R(r9), R(r10),R(r11),R(r12),R(r13),R(r14),R(r15), \
+ /* 16 */ R(r16),R(r17),R(r18),R(r19),R(r20),R(r21),R(r22),R(r23), \
+ /* 24 */ R(r24),R(r25),R(r26),R(r27),R(r28),R(r29),R(r30),R(r31), \
+ /* 32 */ F(f0), F(f1), F(f2), F(f3), F(f4), F(f5), F(f6), F(f7), \
+ /* 40 */ F(f8), F(f9), F(f10),F(f11),F(f12),F(f13),F(f14),F(f15), \
+ /* 48 */ F(f16),F(f17),F(f18),F(f19),F(f20),F(f21),F(f22),F(f23), \
+ /* 56 */ F(f24),F(f25),F(f26),F(f27),F(f28),F(f29),F(f30),F(f31), \
+ /* 64 */ R(pc), R(ps)
+
+#define COMMON_UISA_NOFP_REGS \
+ /* 0 */ R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), \
+ /* 8 */ R(r8), R(r9), R(r10),R(r11),R(r12),R(r13),R(r14),R(r15), \
+ /* 16 */ R(r16),R(r17),R(r18),R(r19),R(r20),R(r21),R(r22),R(r23), \
+ /* 24 */ R(r24),R(r25),R(r26),R(r27),R(r28),R(r29),R(r30),R(r31), \
+ /* 32 */ R0, R0, R0, R0, R0, R0, R0, R0, \
+ /* 40 */ R0, R0, R0, R0, R0, R0, R0, R0, \
+ /* 48 */ R0, R0, R0, R0, R0, R0, R0, R0, \
+ /* 56 */ R0, R0, R0, R0, R0, R0, R0, R0, \
+ /* 64 */ R(pc), R(ps)
+
+/* UISA-level SPRs for PowerPC. */
+#define PPC_UISA_SPRS \
+ /* 66 */ R4(cr), R(lr), R(ctr), R4(xer), R4(fpscr)
+
+/* UISA-level SPRs for PowerPC without floating point support. */
+#define PPC_UISA_NOFP_SPRS \
+ /* 66 */ R4(cr), R(lr), R(ctr), R4(xer), R0
+
+/* Segment registers, for PowerPC. */
+#define PPC_SEGMENT_REGS \
+ /* 71 */ R32(sr0), R32(sr1), R32(sr2), R32(sr3), \
+ /* 75 */ R32(sr4), R32(sr5), R32(sr6), R32(sr7), \
+ /* 79 */ R32(sr8), R32(sr9), R32(sr10), R32(sr11), \
+ /* 83 */ R32(sr12), R32(sr13), R32(sr14), R32(sr15)
+
+/* OEA SPRs for PowerPC. */
+#define PPC_OEA_SPRS \
+ /* 87 */ R4(pvr), \
+ /* 88 */ R(ibat0u), R(ibat0l), R(ibat1u), R(ibat1l), \
+ /* 92 */ R(ibat2u), R(ibat2l), R(ibat3u), R(ibat3l), \
+ /* 96 */ R(dbat0u), R(dbat0l), R(dbat1u), R(dbat1l), \
+ /* 100 */ R(dbat2u), R(dbat2l), R(dbat3u), R(dbat3l), \
+ /* 104 */ R(sdr1), R64(asr), R(dar), R4(dsisr), \
+ /* 108 */ R(sprg0), R(sprg1), R(sprg2), R(sprg3), \
+ /* 112 */ R(srr0), R(srr1), R(tbl), R(tbu), \
+ /* 116 */ R4(dec), R(dabr), R4(ear)
+
+/* AltiVec registers. */
+#define PPC_ALTIVEC_REGS \
+ /*119*/R16(vr0), R16(vr1), R16(vr2), R16(vr3), R16(vr4), R16(vr5), R16(vr6), R16(vr7), \
+ /*127*/R16(vr8), R16(vr9), R16(vr10),R16(vr11),R16(vr12),R16(vr13),R16(vr14),R16(vr15), \
+ /*135*/R16(vr16),R16(vr17),R16(vr18),R16(vr19),R16(vr20),R16(vr21),R16(vr22),R16(vr23), \
+ /*143*/R16(vr24),R16(vr25),R16(vr26),R16(vr27),R16(vr28),R16(vr29),R16(vr30),R16(vr31), \
+ /*151*/R4(vscr), R4(vrsave)
+
+/* Vectors of hi-lo general purpose registers. */
+#define PPC_EV_REGS \
+ /* 0*/R8(ev0), R8(ev1), R8(ev2), R8(ev3), R8(ev4), R8(ev5), R8(ev6), R8(ev7), \
+ /* 8*/R8(ev8), R8(ev9), R8(ev10),R8(ev11),R8(ev12),R8(ev13),R8(ev14),R8(ev15), \
+ /*16*/R8(ev16),R8(ev17),R8(ev18),R8(ev19),R8(ev20),R8(ev21),R8(ev22),R8(ev23), \
+ /*24*/R8(ev24),R8(ev25),R8(ev26),R8(ev27),R8(ev28),R8(ev29),R8(ev30),R8(ev31)
+
+/* Lower half of the EV registers. */
+#define PPC_GPRS_PSEUDO_REGS \
+ /* 0 */ P(r0), P(r1), P(r2), P(r3), P(r4), P(r5), P(r6), P(r7), \
+ /* 8 */ P(r8), P(r9), P(r10),P(r11),P(r12),P(r13),P(r14),P(r15), \
+ /* 16 */ P(r16),P(r17),P(r18),P(r19),P(r20),P(r21),P(r22),P(r23), \
+ /* 24 */ P(r24),P(r25),P(r26),P(r27),P(r28),P(r29),P(r30),P(r31)
+
+/* IBM POWER (pre-PowerPC) architecture, user-level view. We only cover
+ user-level SPR's. */
+static const struct reg registers_power[] =
+{
+ COMMON_UISA_REGS,
+ /* 66 */ R4(cnd), R(lr), R(cnt), R4(xer), R4(mq),
+ /* 71 */ R4(fpscr)
+};
+
+/* PowerPC UISA - a PPC processor as viewed by user-level code. A UISA-only
+ view of the PowerPC. */
+static const struct reg registers_powerpc[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_ALTIVEC_REGS
+};
+
+/* PowerPC UISA - a PPC processor as viewed by user-level
+ code, but without floating point registers. */
+static const struct reg registers_powerpc_nofp[] =
+{
+ COMMON_UISA_NOFP_REGS,
+ PPC_UISA_SPRS
+};
+
+/* IBM PowerPC 403. */
+static const struct reg registers_403[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(icdbdr), R(esr), R(dear), R(evpr),
+ /* 123 */ R(cdbcr), R(tsr), R(tcr), R(pit),
+ /* 127 */ R(tbhi), R(tblo), R(srr2), R(srr3),
+ /* 131 */ R(dbsr), R(dbcr), R(iac1), R(iac2),
+ /* 135 */ R(dac1), R(dac2), R(dccr), R(iccr),
+ /* 139 */ R(pbl1), R(pbu1), R(pbl2), R(pbu2)
+};
+
+/* IBM PowerPC 403GC. */
+static const struct reg registers_403GC[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(icdbdr), R(esr), R(dear), R(evpr),
+ /* 123 */ R(cdbcr), R(tsr), R(tcr), R(pit),
+ /* 127 */ R(tbhi), R(tblo), R(srr2), R(srr3),
+ /* 131 */ R(dbsr), R(dbcr), R(iac1), R(iac2),
+ /* 135 */ R(dac1), R(dac2), R(dccr), R(iccr),
+ /* 139 */ R(pbl1), R(pbu1), R(pbl2), R(pbu2),
+ /* 143 */ R(zpr), R(pid), R(sgr), R(dcwr),
+ /* 147 */ R(tbhu), R(tblu)
+};
+
+/* Motorola PowerPC 505. */
+static const struct reg registers_505[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(eie), R(eid), R(nri)
+};
+
+/* Motorola PowerPC 860 or 850. */
+static const struct reg registers_860[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(eie), R(eid), R(nri), R(cmpa),
+ /* 123 */ R(cmpb), R(cmpc), R(cmpd), R(icr),
+ /* 127 */ R(der), R(counta), R(countb), R(cmpe),
+ /* 131 */ R(cmpf), R(cmpg), R(cmph), R(lctrl1),
+ /* 135 */ R(lctrl2), R(ictrl), R(bar), R(ic_cst),
+ /* 139 */ R(ic_adr), R(ic_dat), R(dc_cst), R(dc_adr),
+ /* 143 */ R(dc_dat), R(dpdr), R(dpir), R(immr),
+ /* 147 */ R(mi_ctr), R(mi_ap), R(mi_epn), R(mi_twc),
+ /* 151 */ R(mi_rpn), R(md_ctr), R(m_casid), R(md_ap),
+ /* 155 */ R(md_epn), R(md_twb), R(md_twc), R(md_rpn),
+ /* 159 */ R(m_tw), R(mi_dbcam), R(mi_dbram0), R(mi_dbram1),
+ /* 163 */ R(md_dbcam), R(md_dbram0), R(md_dbram1)
+};
+
+/* Motorola PowerPC 601. Note that the 601 has different register numbers
+ for reading and writing RTCU and RTCL. However, how one reads and writes a
+ register is the stub's problem. */
+static const struct reg registers_601[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(hid0), R(hid1), R(iabr), R(dabr),
+ /* 123 */ R(pir), R(mq), R(rtcu), R(rtcl)
+};
+
+/* Motorola PowerPC 602. */
+static const struct reg registers_602[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(hid0), R(hid1), R(iabr), R0,
+ /* 123 */ R0, R(tcr), R(ibr), R(esassr),
+ /* 127 */ R(sebr), R(ser), R(sp), R(lt)
+};
+
+/* Motorola/IBM PowerPC 603 or 603e. */
+static const struct reg registers_603[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(hid0), R(hid1), R(iabr), R0,
+ /* 123 */ R0, R(dmiss), R(dcmp), R(hash1),
+ /* 127 */ R(hash2), R(imiss), R(icmp), R(rpa)
+};
+
+/* Motorola PowerPC 604 or 604e. */
+static const struct reg registers_604[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(hid0), R(hid1), R(iabr), R(dabr),
+ /* 123 */ R(pir), R(mmcr0), R(pmc1), R(pmc2),
+ /* 127 */ R(sia), R(sda)
+};
+
+/* Motorola/IBM PowerPC 750 or 740. */
+static const struct reg registers_750[] =
+{
+ COMMON_UISA_REGS,
+ PPC_UISA_SPRS,
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* 119 */ R(hid0), R(hid1), R(iabr), R(dabr),
+ /* 123 */ R0, R(ummcr0), R(upmc1), R(upmc2),
+ /* 127 */ R(usia), R(ummcr1), R(upmc3), R(upmc4),
+ /* 131 */ R(mmcr0), R(pmc1), R(pmc2), R(sia),
+ /* 135 */ R(mmcr1), R(pmc3), R(pmc4), R(l2cr),
+ /* 139 */ R(ictc), R(thrm1), R(thrm2), R(thrm3)
+};
+
+
+/* Motorola PowerPC 7400. */
+static const struct reg registers_7400[] =
+{
+ /* gpr0-gpr31, fpr0-fpr31 */
+ COMMON_UISA_REGS,
+ /* ctr, xre, lr, cr */
+ PPC_UISA_SPRS,
+ /* sr0-sr15 */
+ PPC_SEGMENT_REGS,
+ PPC_OEA_SPRS,
+ /* vr0-vr31, vrsave, vscr */
+ PPC_ALTIVEC_REGS
+ /* FIXME? Add more registers? */
+};
+
+/* Motorola e500. */
+static const struct reg registers_e500[] =
+{
+ R(pc), R(ps),
+ /* cr, lr, ctr, xer, "" */
+ PPC_UISA_NOFP_SPRS,
+ /* 7...38 */
+ PPC_EV_REGS,
+ R8(acc), R(spefscr),
+ /* NOTE: Add new registers here the end of the raw register
+ list and just before the first pseudo register. */
+ /* 39...70 */
+ PPC_GPRS_PSEUDO_REGS
+};
+
+/* Information about a particular processor variant. */
+
+struct variant
+ {
+ /* Name of this variant. */
+ char *name;
+
+ /* English description of the variant. */
+ char *description;
+
+ /* bfd_arch_info.arch corresponding to variant. */
+ enum bfd_architecture arch;
+
+ /* bfd_arch_info.mach corresponding to variant. */
+ unsigned long mach;
+
+ /* Number of real registers. */
+ int nregs;
+
+ /* Number of pseudo registers. */
+ int npregs;
+
+ /* Number of total registers (the sum of nregs and npregs). */
+ int num_tot_regs;
+
+ /* Table of register names; registers[R] is the name of the register
+ number R. */
+ const struct reg *regs;
+ };
+
+#define tot_num_registers(list) (sizeof (list) / sizeof((list)[0]))
+
+static int
+num_registers (const struct reg *reg_list, int num_tot_regs)
+{
+ int i;
+ int nregs = 0;
+
+ for (i = 0; i < num_tot_regs; i++)
+ if (!reg_list[i].pseudo)
+ nregs++;
+
+ return nregs;
+}
+
+static int
+num_pseudo_registers (const struct reg *reg_list, int num_tot_regs)
+{
+ int i;
+ int npregs = 0;
+
+ for (i = 0; i < num_tot_regs; i++)
+ if (reg_list[i].pseudo)
+ npregs ++;
+
+ return npregs;
+}
+
+/* Information in this table comes from the following web sites:
+ IBM: http://www.chips.ibm.com:80/products/embedded/
+ Motorola: http://www.mot.com/SPS/PowerPC/
+
+ I'm sure I've got some of the variant descriptions not quite right.
+ Please report any inaccuracies you find to GDB's maintainer.
+
+ If you add entries to this table, please be sure to allow the new
+ value as an argument to the --with-cpu flag, in configure.in. */
+
+static struct variant variants[] =
+{
+
+ {"powerpc", "PowerPC user-level", bfd_arch_powerpc,
+ bfd_mach_ppc, -1, -1, tot_num_registers (registers_powerpc),
+ registers_powerpc},
+ {"power", "POWER user-level", bfd_arch_rs6000,
+ bfd_mach_rs6k, -1, -1, tot_num_registers (registers_power),
+ registers_power},
+ {"403", "IBM PowerPC 403", bfd_arch_powerpc,
+ bfd_mach_ppc_403, -1, -1, tot_num_registers (registers_403),
+ registers_403},
+ {"601", "Motorola PowerPC 601", bfd_arch_powerpc,
+ bfd_mach_ppc_601, -1, -1, tot_num_registers (registers_601),
+ registers_601},
+ {"602", "Motorola PowerPC 602", bfd_arch_powerpc,
+ bfd_mach_ppc_602, -1, -1, tot_num_registers (registers_602),
+ registers_602},
+ {"603", "Motorola/IBM PowerPC 603 or 603e", bfd_arch_powerpc,
+ bfd_mach_ppc_603, -1, -1, tot_num_registers (registers_603),
+ registers_603},
+ {"604", "Motorola PowerPC 604 or 604e", bfd_arch_powerpc,
+ 604, -1, -1, tot_num_registers (registers_604),
+ registers_604},
+ {"403GC", "IBM PowerPC 403GC", bfd_arch_powerpc,
+ bfd_mach_ppc_403gc, -1, -1, tot_num_registers (registers_403GC),
+ registers_403GC},
+ {"505", "Motorola PowerPC 505", bfd_arch_powerpc,
+ bfd_mach_ppc_505, -1, -1, tot_num_registers (registers_505),
+ registers_505},
+ {"860", "Motorola PowerPC 860 or 850", bfd_arch_powerpc,
+ bfd_mach_ppc_860, -1, -1, tot_num_registers (registers_860),
+ registers_860},
+ {"750", "Motorola/IBM PowerPC 750 or 740", bfd_arch_powerpc,
+ bfd_mach_ppc_750, -1, -1, tot_num_registers (registers_750),
+ registers_750},
+ {"7400", "Motorola/IBM PowerPC 7400 (G4)", bfd_arch_powerpc,
+ bfd_mach_ppc_7400, -1, -1, tot_num_registers (registers_7400),
+ registers_7400},
+ {"e500", "Motorola PowerPC e500", bfd_arch_powerpc,
+ bfd_mach_ppc_e500, -1, -1, tot_num_registers (registers_e500),
+ registers_e500},
+
+ /* 64-bit */
+ {"powerpc64", "PowerPC 64-bit user-level", bfd_arch_powerpc,
+ bfd_mach_ppc64, -1, -1, tot_num_registers (registers_powerpc),
+ registers_powerpc},
+ {"620", "Motorola PowerPC 620", bfd_arch_powerpc,
+ bfd_mach_ppc_620, -1, -1, tot_num_registers (registers_powerpc),
+ registers_powerpc},
+ {"630", "Motorola PowerPC 630", bfd_arch_powerpc,
+ bfd_mach_ppc_630, -1, -1, tot_num_registers (registers_powerpc),
+ registers_powerpc},
+ {"a35", "PowerPC A35", bfd_arch_powerpc,
+ bfd_mach_ppc_a35, -1, -1, tot_num_registers (registers_powerpc),
+ registers_powerpc},
+ {"rs64ii", "PowerPC rs64ii", bfd_arch_powerpc,
+ bfd_mach_ppc_rs64ii, -1, -1, tot_num_registers (registers_powerpc),
+ registers_powerpc},
+ {"rs64iii", "PowerPC rs64iii", bfd_arch_powerpc,
+ bfd_mach_ppc_rs64iii, -1, -1, tot_num_registers (registers_powerpc),
+ registers_powerpc},
+
+ /* FIXME: I haven't checked the register sets of the following. */
+ {"rs1", "IBM POWER RS1", bfd_arch_rs6000,
+ bfd_mach_rs6k_rs1, -1, -1, tot_num_registers (registers_power),
+ registers_power},
+ {"rsc", "IBM POWER RSC", bfd_arch_rs6000,
+ bfd_mach_rs6k_rsc, -1, -1, tot_num_registers (registers_power),
+ registers_power},
+ {"rs2", "IBM POWER RS2", bfd_arch_rs6000,
+ bfd_mach_rs6k_rs2, -1, -1, tot_num_registers (registers_power),
+ registers_power},
+
+ {0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+/* Initialize the number of registers and pseudo registers in each variant. */
+
+static void
+init_variants (void)
+{
+ struct variant *v;
+
+ for (v = variants; v->name; v++)
+ {
+ if (v->nregs == -1)
+ v->nregs = num_registers (v->regs, v->num_tot_regs);
+ if (v->npregs == -1)
+ v->npregs = num_pseudo_registers (v->regs, v->num_tot_regs);
+ }
+}
+
+/* Return the variant corresponding to architecture ARCH and machine number
+ MACH. If no such variant exists, return null. */
+
+static const struct variant *
+find_variant_by_arch (enum bfd_architecture arch, unsigned long mach)
+{
+ const struct variant *v;
+
+ for (v = variants; v->name; v++)
+ if (arch == v->arch && mach == v->mach)
+ return v;
+
+ return NULL;
+}
+
+static int
+gdb_print_insn_powerpc (bfd_vma memaddr, disassemble_info *info)
+{
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return print_insn_big_powerpc (memaddr, info);
+ else
+ return print_insn_little_powerpc (memaddr, info);
+}
+
+/* Initialize the current architecture based on INFO. If possible, re-use an
+ architecture from ARCHES, which is a list of architectures already created
+ during this debugging session.
+
+ Called e.g. at program startup, when reading a core file, and when reading
+ a binary file. */
+
+static struct gdbarch *
+rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ int wordsize, from_xcoff_exec, from_elf_exec, power, i, off;
+ struct reg *regs;
+ const struct variant *v;
+ enum bfd_architecture arch;
+ unsigned long mach;
+ bfd abfd;
+ int sysv_abi;
+ asection *sect;
+
+ from_xcoff_exec = info.abfd && info.abfd->format == bfd_object &&
+ bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour;
+
+ from_elf_exec = info.abfd && info.abfd->format == bfd_object &&
+ bfd_get_flavour (info.abfd) == bfd_target_elf_flavour;
+
+ sysv_abi = info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour;
+
+ /* Check word size. If INFO is from a binary file, infer it from
+ that, else choose a likely default. */
+ if (from_xcoff_exec)
+ {
+ if (bfd_xcoff_is_xcoff64 (info.abfd))
+ wordsize = 8;
+ else
+ wordsize = 4;
+ }
+ else if (from_elf_exec)
+ {
+ if (elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+ wordsize = 8;
+ else
+ wordsize = 4;
+ }
+ else
+ {
+ if (info.bfd_arch_info != NULL && info.bfd_arch_info->bits_per_word != 0)
+ wordsize = info.bfd_arch_info->bits_per_word /
+ info.bfd_arch_info->bits_per_byte;
+ else
+ wordsize = 4;
+ }
+
+ /* Find a candidate among extant architectures. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* Word size in the various PowerPC bfd_arch_info structs isn't
+ meaningful, because 64-bit CPUs can run in 32-bit mode. So, perform
+ separate word size check. */
+ tdep = gdbarch_tdep (arches->gdbarch);
+ if (tdep && tdep->wordsize == wordsize)
+ return arches->gdbarch;
+ }
+
+ /* None found, create a new architecture from INFO, whose bfd_arch_info
+ validity depends on the source:
+ - executable useless
+ - rs6000_host_arch() good
+ - core file good
+ - "set arch" trust blindly
+ - GDB startup useless but harmless */
+
+ if (!from_xcoff_exec)
+ {
+ arch = info.bfd_arch_info->arch;
+ mach = info.bfd_arch_info->mach;
+ }
+ else
+ {
+ arch = bfd_arch_powerpc;
+ bfd_default_set_arch_mach (&abfd, arch, 0);
+ info.bfd_arch_info = bfd_get_arch_info (&abfd);
+ mach = info.bfd_arch_info->mach;
+ }
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ tdep->wordsize = wordsize;
+
+ /* For e500 executables, the apuinfo section is of help here. Such
+ section contains the identifier and revision number of each
+ Application-specific Processing Unit that is present on the
+ chip. The content of the section is determined by the assembler
+ which looks at each instruction and determines which unit (and
+ which version of it) can execute it. In our case we just look for
+ the existance of the section. */
+
+ if (info.abfd)
+ {
+ sect = bfd_get_section_by_name (info.abfd, ".PPC.EMB.apuinfo");
+ if (sect)
+ {
+ arch = info.bfd_arch_info->arch;
+ mach = bfd_mach_ppc_e500;
+ bfd_default_set_arch_mach (&abfd, arch, mach);
+ info.bfd_arch_info = bfd_get_arch_info (&abfd);
+ }
+ }
+
+ gdbarch = gdbarch_alloc (&info, tdep);
+ power = arch == bfd_arch_rs6000;
+
+ /* Initialize the number of real and pseudo registers in each variant. */
+ init_variants ();
+
+ /* Choose variant. */
+ v = find_variant_by_arch (arch, mach);
+ if (!v)
+ return NULL;
+
+ tdep->regs = v->regs;
+
+ tdep->ppc_gp0_regnum = 0;
+ tdep->ppc_gplast_regnum = 31;
+ tdep->ppc_toc_regnum = 2;
+ tdep->ppc_ps_regnum = 65;
+ tdep->ppc_cr_regnum = 66;
+ tdep->ppc_lr_regnum = 67;
+ tdep->ppc_ctr_regnum = 68;
+ tdep->ppc_xer_regnum = 69;
+ if (v->mach == bfd_mach_ppc_601)
+ tdep->ppc_mq_regnum = 124;
+ else if (power)
+ tdep->ppc_mq_regnum = 70;
+ else
+ tdep->ppc_mq_regnum = -1;
+ tdep->ppc_fpscr_regnum = power ? 71 : 70;
+
+ set_gdbarch_pc_regnum (gdbarch, 64);
+ set_gdbarch_sp_regnum (gdbarch, 1);
+ set_gdbarch_deprecated_fp_regnum (gdbarch, 1);
+ if (sysv_abi && wordsize == 8)
+ set_gdbarch_return_value (gdbarch, ppc64_sysv_abi_return_value);
+ else if (sysv_abi && wordsize == 4)
+ set_gdbarch_return_value (gdbarch, ppc_sysv_abi_return_value);
+ else
+ {
+ set_gdbarch_deprecated_extract_return_value (gdbarch, rs6000_extract_return_value);
+ set_gdbarch_deprecated_store_return_value (gdbarch, rs6000_store_return_value);
+ }
+
+ if (v->arch == bfd_arch_powerpc)
+ switch (v->mach)
+ {
+ case bfd_mach_ppc:
+ tdep->ppc_vr0_regnum = 71;
+ tdep->ppc_vrsave_regnum = 104;
+ tdep->ppc_ev0_regnum = -1;
+ tdep->ppc_ev31_regnum = -1;
+ break;
+ case bfd_mach_ppc_7400:
+ tdep->ppc_vr0_regnum = 119;
+ tdep->ppc_vrsave_regnum = 152;
+ tdep->ppc_ev0_regnum = -1;
+ tdep->ppc_ev31_regnum = -1;
+ break;
+ case bfd_mach_ppc_e500:
+ tdep->ppc_gp0_regnum = 41;
+ tdep->ppc_gplast_regnum = tdep->ppc_gp0_regnum + 32 - 1;
+ tdep->ppc_toc_regnum = -1;
+ tdep->ppc_ps_regnum = 1;
+ tdep->ppc_cr_regnum = 2;
+ tdep->ppc_lr_regnum = 3;
+ tdep->ppc_ctr_regnum = 4;
+ tdep->ppc_xer_regnum = 5;
+ tdep->ppc_ev0_regnum = 7;
+ tdep->ppc_ev31_regnum = 38;
+ set_gdbarch_pc_regnum (gdbarch, 0);
+ set_gdbarch_sp_regnum (gdbarch, tdep->ppc_gp0_regnum + 1);
+ set_gdbarch_deprecated_fp_regnum (gdbarch, tdep->ppc_gp0_regnum + 1);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, e500_dwarf2_reg_to_regnum);
+ set_gdbarch_pseudo_register_read (gdbarch, e500_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, e500_pseudo_register_write);
+ break;
+ default:
+ tdep->ppc_vr0_regnum = -1;
+ tdep->ppc_vrsave_regnum = -1;
+ tdep->ppc_ev0_regnum = -1;
+ tdep->ppc_ev31_regnum = -1;
+ break;
+ }
+
+ /* Sanity check on registers. */
+ gdb_assert (strcmp (tdep->regs[tdep->ppc_gp0_regnum].name, "r0") == 0);
+
+ /* Set lr_frame_offset. */
+ if (wordsize == 8)
+ tdep->lr_frame_offset = 16;
+ else if (sysv_abi)
+ tdep->lr_frame_offset = 4;
+ else
+ tdep->lr_frame_offset = 8;
+
+ /* Calculate byte offsets in raw register array. */
+ tdep->regoff = xmalloc (v->num_tot_regs * sizeof (int));
+ for (i = off = 0; i < v->num_tot_regs; i++)
+ {
+ tdep->regoff[i] = off;
+ off += regsize (v->regs + i, wordsize);
+ }
+
+ /* Select instruction printer. */
+ if (arch == power)
+ set_gdbarch_print_insn (gdbarch, print_insn_rs6000);
+ else
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_powerpc);
+
+ set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
+
+ set_gdbarch_num_regs (gdbarch, v->nregs);
+ set_gdbarch_num_pseudo_regs (gdbarch, v->npregs);
+ set_gdbarch_register_name (gdbarch, rs6000_register_name);
+ set_gdbarch_deprecated_register_size (gdbarch, wordsize);
+ set_gdbarch_deprecated_register_bytes (gdbarch, off);
+ set_gdbarch_deprecated_register_byte (gdbarch, rs6000_register_byte);
+ set_gdbarch_deprecated_register_raw_size (gdbarch, rs6000_register_raw_size);
+ set_gdbarch_deprecated_register_virtual_type (gdbarch, rs6000_register_virtual_type);
+
+ set_gdbarch_ptr_bit (gdbarch, wordsize * TARGET_CHAR_BIT);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, wordsize * TARGET_CHAR_BIT);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ if (sysv_abi)
+ set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+ else
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_char_signed (gdbarch, 0);
+
+ set_gdbarch_frame_align (gdbarch, rs6000_frame_align);
+ if (sysv_abi && wordsize == 8)
+ /* PPC64 SYSV. */
+ set_gdbarch_frame_red_zone_size (gdbarch, 288);
+ else if (!sysv_abi && wordsize == 4)
+ /* PowerOpen / AIX 32 bit. The saved area or red zone consists of
+ 19 4 byte GPRS + 18 8 byte FPRs giving a total of 220 bytes.
+ Problem is, 220 isn't frame (16 byte) aligned. Round it up to
+ 224. */
+ set_gdbarch_frame_red_zone_size (gdbarch, 224);
+ set_gdbarch_deprecated_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+ set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+
+ set_gdbarch_deprecated_register_convertible (gdbarch, rs6000_register_convertible);
+ set_gdbarch_deprecated_register_convert_to_virtual (gdbarch, rs6000_register_convert_to_virtual);
+ set_gdbarch_deprecated_register_convert_to_raw (gdbarch, rs6000_register_convert_to_raw);
+ set_gdbarch_stab_reg_to_regnum (gdbarch, rs6000_stab_reg_to_regnum);
+ /* Note: kevinb/2002-04-12: I'm not convinced that rs6000_push_arguments()
+ is correct for the SysV ABI when the wordsize is 8, but I'm also
+ fairly certain that ppc_sysv_abi_push_arguments() will give even
+ worse results since it only works for 32-bit code. So, for the moment,
+ we're better off calling rs6000_push_arguments() since it works for
+ 64-bit code. At some point in the future, this matter needs to be
+ revisited. */
+ if (sysv_abi && wordsize == 4)
+ set_gdbarch_push_dummy_call (gdbarch, ppc_sysv_abi_push_dummy_call);
+ else if (sysv_abi && wordsize == 8)
+ set_gdbarch_push_dummy_call (gdbarch, ppc64_sysv_abi_push_dummy_call);
+ else
+ set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call);
+
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
+ set_gdbarch_deprecated_pop_frame (gdbarch, rs6000_pop_frame);
+
+ set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
+
+ /* Handle the 64-bit SVR4 minimal-symbol convention of using "FN"
+ for the descriptor and ".FN" for the entry-point -- a user
+ specifying "break FN" will unexpectedly end up with a breakpoint
+ on the descriptor and not the function. This architecture method
+ transforms any breakpoints on descriptors into breakpoints on the
+ corresponding entry point. */
+ if (sysv_abi && wordsize == 8)
+ set_gdbarch_adjust_breakpoint_address (gdbarch, ppc64_sysv_abi_adjust_breakpoint_address);
+
+ /* Not sure on this. FIXMEmgo */
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+ if (!sysv_abi)
+ set_gdbarch_use_struct_convention (gdbarch,
+ rs6000_use_struct_convention);
+
+ set_gdbarch_deprecated_frameless_function_invocation (gdbarch, rs6000_frameless_function_invocation);
+ set_gdbarch_deprecated_frame_chain (gdbarch, rs6000_frame_chain);
+ set_gdbarch_deprecated_frame_saved_pc (gdbarch, rs6000_frame_saved_pc);
+
+ set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs);
+ set_gdbarch_deprecated_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info);
+
+ if (!sysv_abi)
+ {
+ /* Handle RS/6000 function pointers (which are really function
+ descriptors). */
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ rs6000_convert_from_func_ptr_addr);
+ }
+ set_gdbarch_deprecated_frame_args_address (gdbarch, rs6000_frame_args_address);
+ set_gdbarch_deprecated_frame_locals_address (gdbarch, rs6000_frame_args_address);
+ set_gdbarch_deprecated_saved_pc_after_call (gdbarch, rs6000_saved_pc_after_call);
+
+ /* Helpers for function argument information. */
+ set_gdbarch_fetch_pointer_argument (gdbarch, rs6000_fetch_pointer_argument);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ if (from_xcoff_exec)
+ {
+ /* NOTE: jimix/2003-06-09: This test should really check for
+ GDB_OSABI_AIX when that is defined and becomes
+ available. (Actually, once things are properly split apart,
+ the test goes away.) */
+ /* RS6000/AIX does not support PT_STEP. Has to be simulated. */
+ set_gdbarch_software_single_step (gdbarch, rs6000_software_single_step);
+ }
+
+ return gdbarch;
+}
+
+static void
+rs6000_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep == NULL)
+ return;
+
+ /* FIXME: Dump gdbarch_tdep. */
+}
+
+static struct cmd_list_element *info_powerpc_cmdlist = NULL;
+
+static void
+rs6000_info_powerpc_command (char *args, int from_tty)
+{
+ help_list (info_powerpc_cmdlist, "info powerpc ", class_info, gdb_stdout);
+}
+
+/* Initialization code. */
+
+extern initialize_file_ftype _initialize_rs6000_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_rs6000_tdep (void)
+{
+ gdbarch_register (bfd_arch_rs6000, rs6000_gdbarch_init, rs6000_dump_tdep);
+ gdbarch_register (bfd_arch_powerpc, rs6000_gdbarch_init, rs6000_dump_tdep);
+
+ /* Add root prefix command for "info powerpc" commands */
+ add_prefix_cmd ("powerpc", class_info, rs6000_info_powerpc_command,
+ "Various POWERPC info specific commands.",
+ &info_powerpc_cmdlist, "info powerpc ", 0, &infolist);
+}
diff --git a/contrib/gdb/gdb/s390-nat.c b/contrib/gdb/gdb/s390-nat.c
new file mode 100644
index 0000000..b8da548
--- /dev/null
+++ b/contrib/gdb/gdb/s390-nat.c
@@ -0,0 +1,359 @@
+/* S390 native-dependent code for GDB, the GNU debugger.
+ Copyright 2001, 2003 Free Software Foundation, Inc
+
+ Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ for IBM Deutschland Entwicklung GmbH, 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. */
+
+#include "defs.h"
+#include "tm.h"
+#include "regcache.h"
+#include "inferior.h"
+
+#include "s390-tdep.h"
+
+#include <asm/ptrace.h>
+#include <sys/ptrace.h>
+#include <asm/types.h>
+#include <sys/procfs.h>
+#include <sys/user.h>
+#include <sys/ucontext.h>
+
+
+/* Map registers to gregset/ptrace offsets.
+ These arrays are defined in s390-tdep.c. */
+
+#ifdef __s390x__
+#define regmap_gregset s390x_regmap_gregset
+#else
+#define regmap_gregset s390_regmap_gregset
+#endif
+
+#define regmap_fpregset s390_regmap_fpregset
+
+/* When debugging a 32-bit executable running under a 64-bit kernel,
+ we have to fix up the 64-bit registers we get from the kernel
+ to make them look like 32-bit registers. */
+#ifdef __s390x__
+#define SUBOFF(i) \
+ ((TARGET_PTR_BIT == 32 \
+ && ((i) == S390_PSWA_REGNUM \
+ || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
+#else
+#define SUBOFF(i) 0
+#endif
+
+
+/* Fill GDB's register array with the general-purpose register values
+ in *REGP. */
+void
+supply_gregset (gregset_t *regp)
+{
+ int i;
+ for (i = 0; i < S390_NUM_REGS; i++)
+ if (regmap_gregset[i] != -1)
+ regcache_raw_supply (current_regcache, i,
+ (char *)regp + regmap_gregset[i] + SUBOFF (i));
+}
+
+/* Fill register REGNO (if it is a general-purpose register) in
+ *REGP with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+void
+fill_gregset (gregset_t *regp, int regno)
+{
+ int i;
+ for (i = 0; i < S390_NUM_REGS; i++)
+ if (regmap_gregset[i] != -1)
+ if (regno == -1 || regno == i)
+ regcache_raw_collect (current_regcache, i,
+ (char *)regp + regmap_gregset[i] + SUBOFF (i));
+}
+
+/* Fill GDB's register array with the floating-point register values
+ in *REGP. */
+void
+supply_fpregset (fpregset_t *regp)
+{
+ int i;
+ for (i = 0; i < S390_NUM_REGS; i++)
+ if (regmap_fpregset[i] != -1)
+ regcache_raw_supply (current_regcache, i,
+ ((char *)regp) + regmap_fpregset[i]);
+}
+
+/* Fill register REGNO (if it is a general-purpose register) in
+ *REGP with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+void
+fill_fpregset (fpregset_t *regp, int regno)
+{
+ int i;
+ for (i = 0; i < S390_NUM_REGS; i++)
+ if (regmap_fpregset[i] != -1)
+ if (regno == -1 || regno == i)
+ regcache_raw_collect (current_regcache, i,
+ ((char *)regp) + regmap_fpregset[i]);
+}
+
+/* Find the TID for the current inferior thread to use with ptrace. */
+static int
+s390_inferior_tid (void)
+{
+ /* GNU/Linux LWP ID's are process ID's. */
+ int tid = TIDGET (inferior_ptid);
+ if (tid == 0)
+ tid = PIDGET (inferior_ptid); /* Not a threaded program. */
+
+ return tid;
+}
+
+/* Fetch all general-purpose registers from process/thread TID and
+ store their values in GDB's register cache. */
+static void
+fetch_regs (int tid)
+{
+ gregset_t regs;
+ ptrace_area parea;
+
+ parea.len = sizeof (regs);
+ parea.process_addr = (addr_t) &regs;
+ parea.kernel_addr = offsetof (struct user_regs_struct, psw);
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ perror_with_name ("Couldn't get registers");
+
+ supply_gregset (&regs);
+}
+
+/* Store all valid general-purpose registers in GDB's register cache
+ into the process/thread specified by TID. */
+static void
+store_regs (int tid, int regnum)
+{
+ gregset_t regs;
+ ptrace_area parea;
+
+ parea.len = sizeof (regs);
+ parea.process_addr = (addr_t) &regs;
+ parea.kernel_addr = offsetof (struct user_regs_struct, psw);
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ perror_with_name ("Couldn't get registers");
+
+ fill_gregset (&regs, regnum);
+
+ if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
+ perror_with_name ("Couldn't write registers");
+}
+
+/* Fetch all floating-point registers from process/thread TID and store
+ their values in GDB's register cache. */
+static void
+fetch_fpregs (int tid)
+{
+ fpregset_t fpregs;
+ ptrace_area parea;
+
+ parea.len = sizeof (fpregs);
+ parea.process_addr = (addr_t) &fpregs;
+ parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ perror_with_name ("Couldn't get floating point status");
+
+ supply_fpregset (&fpregs);
+}
+
+/* Store all valid floating-point registers in GDB's register cache
+ into the process/thread specified by TID. */
+static void
+store_fpregs (int tid, int regnum)
+{
+ fpregset_t fpregs;
+ ptrace_area parea;
+
+ parea.len = sizeof (fpregs);
+ parea.process_addr = (addr_t) &fpregs;
+ parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
+ perror_with_name ("Couldn't get floating point status");
+
+ fill_fpregset (&fpregs, regnum);
+
+ if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
+ perror_with_name ("Couldn't write floating point status");
+}
+
+/* Fetch register REGNUM from the child process. If REGNUM is -1, do
+ this for all registers. */
+void
+fetch_inferior_registers (int regnum)
+{
+ int tid = s390_inferior_tid ();
+
+ if (regnum == -1
+ || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
+ fetch_regs (tid);
+
+ if (regnum == -1
+ || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
+ fetch_fpregs (tid);
+}
+
+/* Store register REGNUM back into the child process. If REGNUM is
+ -1, do this for all registers. */
+void
+store_inferior_registers (int regnum)
+{
+ int tid = s390_inferior_tid ();
+
+ if (regnum == -1
+ || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
+ store_regs (tid, regnum);
+
+ if (regnum == -1
+ || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
+ store_fpregs (tid, regnum);
+}
+
+
+/* Hardware-assisted watchpoint handling. */
+
+/* We maintain a list of all currently active watchpoints in order
+ to properly handle watchpoint removal.
+
+ The only thing we actually need is the total address space area
+ spanned by the watchpoints. */
+
+struct watch_area
+{
+ struct watch_area *next;
+ CORE_ADDR lo_addr;
+ CORE_ADDR hi_addr;
+};
+
+static struct watch_area *watch_base = NULL;
+
+int
+s390_stopped_by_watchpoint (void)
+{
+ per_lowcore_bits per_lowcore;
+ ptrace_area parea;
+
+ /* Speed up common case. */
+ if (!watch_base)
+ return 0;
+
+ parea.len = sizeof (per_lowcore);
+ parea.process_addr = (addr_t) & per_lowcore;
+ parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
+ if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
+ perror_with_name ("Couldn't retrieve watchpoint status");
+
+ return per_lowcore.perc_storage_alteration == 1
+ && per_lowcore.perc_store_real_address == 0;
+}
+
+static void
+s390_fix_watch_points (void)
+{
+ int tid = s390_inferior_tid ();
+
+ per_struct per_info;
+ ptrace_area parea;
+
+ CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
+ struct watch_area *area;
+
+ for (area = watch_base; area; area = area->next)
+ {
+ watch_lo_addr = min (watch_lo_addr, area->lo_addr);
+ watch_hi_addr = max (watch_hi_addr, area->hi_addr);
+ }
+
+ parea.len = sizeof (per_info);
+ parea.process_addr = (addr_t) & per_info;
+ parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
+ perror_with_name ("Couldn't retrieve watchpoint status");
+
+ if (watch_base)
+ {
+ per_info.control_regs.bits.em_storage_alteration = 1;
+ per_info.control_regs.bits.storage_alt_space_ctl = 1;
+ }
+ else
+ {
+ per_info.control_regs.bits.em_storage_alteration = 0;
+ per_info.control_regs.bits.storage_alt_space_ctl = 0;
+ }
+ per_info.starting_addr = watch_lo_addr;
+ per_info.ending_addr = watch_hi_addr;
+
+ if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
+ perror_with_name ("Couldn't modify watchpoint status");
+}
+
+int
+s390_insert_watchpoint (CORE_ADDR addr, int len)
+{
+ struct watch_area *area = xmalloc (sizeof (struct watch_area));
+ if (!area)
+ return -1;
+
+ area->lo_addr = addr;
+ area->hi_addr = addr + len - 1;
+
+ area->next = watch_base;
+ watch_base = area;
+
+ s390_fix_watch_points ();
+ return 0;
+}
+
+int
+s390_remove_watchpoint (CORE_ADDR addr, int len)
+{
+ struct watch_area *area, **parea;
+
+ for (parea = &watch_base; *parea; parea = &(*parea)->next)
+ if ((*parea)->lo_addr == addr
+ && (*parea)->hi_addr == addr + len - 1)
+ break;
+
+ if (!*parea)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "Attempt to remove nonexistent watchpoint.\n");
+ return -1;
+ }
+
+ area = *parea;
+ *parea = area->next;
+ xfree (area);
+
+ s390_fix_watch_points ();
+ return 0;
+}
+
+
+int
+kernel_u_size (void)
+{
+ return sizeof (struct user);
+}
+
diff --git a/contrib/gdb/gdb/s390-tdep.c b/contrib/gdb/gdb/s390-tdep.c
new file mode 100644
index 0000000..0f8f65d
--- /dev/null
+++ b/contrib/gdb/gdb/s390-tdep.c
@@ -0,0 +1,3102 @@
+/* Target-dependent code for GDB, the GNU debugger.
+
+ Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ for IBM Deutschland Entwicklung GmbH, 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. */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "tm.h"
+#include "../bfd/bfd.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "trad-frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "reggroups.h"
+#include "regset.h"
+#include "value.h"
+#include "gdb_assert.h"
+#include "dis-asm.h"
+#include "solib-svr4.h" /* For struct link_map_offsets. */
+
+#include "s390-tdep.h"
+
+
+/* The tdep structure. */
+
+struct gdbarch_tdep
+{
+ /* ABI version. */
+ enum { ABI_LINUX_S390, ABI_LINUX_ZSERIES } abi;
+
+ /* Core file register sets. */
+ const struct regset *gregset;
+ int sizeof_gregset;
+
+ const struct regset *fpregset;
+ int sizeof_fpregset;
+};
+
+
+/* Register information. */
+
+struct s390_register_info
+{
+ char *name;
+ struct type **type;
+};
+
+static struct s390_register_info s390_register_info[S390_NUM_TOTAL_REGS] =
+{
+ /* Program Status Word. */
+ { "pswm", &builtin_type_long },
+ { "pswa", &builtin_type_long },
+
+ /* General Purpose Registers. */
+ { "r0", &builtin_type_long },
+ { "r1", &builtin_type_long },
+ { "r2", &builtin_type_long },
+ { "r3", &builtin_type_long },
+ { "r4", &builtin_type_long },
+ { "r5", &builtin_type_long },
+ { "r6", &builtin_type_long },
+ { "r7", &builtin_type_long },
+ { "r8", &builtin_type_long },
+ { "r9", &builtin_type_long },
+ { "r10", &builtin_type_long },
+ { "r11", &builtin_type_long },
+ { "r12", &builtin_type_long },
+ { "r13", &builtin_type_long },
+ { "r14", &builtin_type_long },
+ { "r15", &builtin_type_long },
+
+ /* Access Registers. */
+ { "acr0", &builtin_type_int },
+ { "acr1", &builtin_type_int },
+ { "acr2", &builtin_type_int },
+ { "acr3", &builtin_type_int },
+ { "acr4", &builtin_type_int },
+ { "acr5", &builtin_type_int },
+ { "acr6", &builtin_type_int },
+ { "acr7", &builtin_type_int },
+ { "acr8", &builtin_type_int },
+ { "acr9", &builtin_type_int },
+ { "acr10", &builtin_type_int },
+ { "acr11", &builtin_type_int },
+ { "acr12", &builtin_type_int },
+ { "acr13", &builtin_type_int },
+ { "acr14", &builtin_type_int },
+ { "acr15", &builtin_type_int },
+
+ /* Floating Point Control Word. */
+ { "fpc", &builtin_type_int },
+
+ /* Floating Point Registers. */
+ { "f0", &builtin_type_double },
+ { "f1", &builtin_type_double },
+ { "f2", &builtin_type_double },
+ { "f3", &builtin_type_double },
+ { "f4", &builtin_type_double },
+ { "f5", &builtin_type_double },
+ { "f6", &builtin_type_double },
+ { "f7", &builtin_type_double },
+ { "f8", &builtin_type_double },
+ { "f9", &builtin_type_double },
+ { "f10", &builtin_type_double },
+ { "f11", &builtin_type_double },
+ { "f12", &builtin_type_double },
+ { "f13", &builtin_type_double },
+ { "f14", &builtin_type_double },
+ { "f15", &builtin_type_double },
+
+ /* Pseudo registers. */
+ { "pc", &builtin_type_void_func_ptr },
+ { "cc", &builtin_type_int },
+};
+
+/* Return the name of register REGNUM. */
+static const char *
+s390_register_name (int regnum)
+{
+ gdb_assert (regnum >= 0 && regnum < S390_NUM_TOTAL_REGS);
+ return s390_register_info[regnum].name;
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. */
+static struct type *
+s390_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ gdb_assert (regnum >= 0 && regnum < S390_NUM_TOTAL_REGS);
+ return *s390_register_info[regnum].type;
+}
+
+/* DWARF Register Mapping. */
+
+static int s390_dwarf_regmap[] =
+{
+ /* General Purpose Registers. */
+ S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM,
+ S390_R4_REGNUM, S390_R5_REGNUM, S390_R6_REGNUM, S390_R7_REGNUM,
+ S390_R8_REGNUM, S390_R9_REGNUM, S390_R10_REGNUM, S390_R11_REGNUM,
+ S390_R12_REGNUM, S390_R13_REGNUM, S390_R14_REGNUM, S390_R15_REGNUM,
+
+ /* Floating Point Registers. */
+ S390_F0_REGNUM, S390_F2_REGNUM, S390_F4_REGNUM, S390_F6_REGNUM,
+ S390_F1_REGNUM, S390_F3_REGNUM, S390_F5_REGNUM, S390_F7_REGNUM,
+ S390_F8_REGNUM, S390_F10_REGNUM, S390_F12_REGNUM, S390_F14_REGNUM,
+ S390_F9_REGNUM, S390_F11_REGNUM, S390_F13_REGNUM, S390_F15_REGNUM,
+
+ /* Control Registers (not mapped). */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+
+ /* Access Registers. */
+ S390_A0_REGNUM, S390_A1_REGNUM, S390_A2_REGNUM, S390_A3_REGNUM,
+ S390_A4_REGNUM, S390_A5_REGNUM, S390_A6_REGNUM, S390_A7_REGNUM,
+ S390_A8_REGNUM, S390_A9_REGNUM, S390_A10_REGNUM, S390_A11_REGNUM,
+ S390_A12_REGNUM, S390_A13_REGNUM, S390_A14_REGNUM, S390_A15_REGNUM,
+
+ /* Program Status Word. */
+ S390_PSWM_REGNUM,
+ S390_PSWA_REGNUM
+};
+
+/* Convert DWARF register number REG to the appropriate register
+ number used by GDB. */
+static int
+s390_dwarf_reg_to_regnum (int reg)
+{
+ int regnum = -1;
+
+ if (reg >= 0 || reg < ARRAY_SIZE (s390_dwarf_regmap))
+ regnum = s390_dwarf_regmap[reg];
+
+ if (regnum == -1)
+ warning ("Unmapped DWARF Register #%d encountered\n", reg);
+
+ return regnum;
+}
+
+/* Pseudo registers - PC and condition code. */
+
+static void
+s390_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, void *buf)
+{
+ ULONGEST val;
+
+ switch (regnum)
+ {
+ case S390_PC_REGNUM:
+ regcache_raw_read_unsigned (regcache, S390_PSWA_REGNUM, &val);
+ store_unsigned_integer (buf, 4, val & 0x7fffffff);
+ break;
+
+ case S390_CC_REGNUM:
+ regcache_raw_read_unsigned (regcache, S390_PSWM_REGNUM, &val);
+ store_unsigned_integer (buf, 4, (val >> 12) & 3);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "invalid regnum");
+ }
+}
+
+static void
+s390_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, const void *buf)
+{
+ ULONGEST val, psw;
+
+ switch (regnum)
+ {
+ case S390_PC_REGNUM:
+ val = extract_unsigned_integer (buf, 4);
+ regcache_raw_read_unsigned (regcache, S390_PSWA_REGNUM, &psw);
+ psw = (psw & 0x80000000) | (val & 0x7fffffff);
+ regcache_raw_write_unsigned (regcache, S390_PSWA_REGNUM, psw);
+ break;
+
+ case S390_CC_REGNUM:
+ val = extract_unsigned_integer (buf, 4);
+ regcache_raw_read_unsigned (regcache, S390_PSWM_REGNUM, &psw);
+ psw = (psw & ~((ULONGEST)3 << 12)) | ((val & 3) << 12);
+ regcache_raw_write_unsigned (regcache, S390_PSWM_REGNUM, psw);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "invalid regnum");
+ }
+}
+
+static void
+s390x_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, void *buf)
+{
+ ULONGEST val;
+
+ switch (regnum)
+ {
+ case S390_PC_REGNUM:
+ regcache_raw_read (regcache, S390_PSWA_REGNUM, buf);
+ break;
+
+ case S390_CC_REGNUM:
+ regcache_raw_read_unsigned (regcache, S390_PSWM_REGNUM, &val);
+ store_unsigned_integer (buf, 4, (val >> 44) & 3);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "invalid regnum");
+ }
+}
+
+static void
+s390x_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, const void *buf)
+{
+ ULONGEST val, psw;
+
+ switch (regnum)
+ {
+ case S390_PC_REGNUM:
+ regcache_raw_write (regcache, S390_PSWA_REGNUM, buf);
+ break;
+
+ case S390_CC_REGNUM:
+ val = extract_unsigned_integer (buf, 4);
+ regcache_raw_read_unsigned (regcache, S390_PSWM_REGNUM, &psw);
+ psw = (psw & ~((ULONGEST)3 << 44)) | ((val & 3) << 44);
+ regcache_raw_write_unsigned (regcache, S390_PSWM_REGNUM, psw);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "invalid regnum");
+ }
+}
+
+/* 'float' values are stored in the upper half of floating-point
+ registers, even though we are otherwise a big-endian platform. */
+
+static int
+s390_convert_register_p (int regno, struct type *type)
+{
+ return (regno >= S390_F0_REGNUM && regno <= S390_F15_REGNUM)
+ && TYPE_LENGTH (type) < 8;
+}
+
+static void
+s390_register_to_value (struct frame_info *frame, int regnum,
+ struct type *valtype, void *out)
+{
+ char in[8];
+ int len = TYPE_LENGTH (valtype);
+ gdb_assert (len < 8);
+
+ get_frame_register (frame, regnum, in);
+ memcpy (out, in, len);
+}
+
+static void
+s390_value_to_register (struct frame_info *frame, int regnum,
+ struct type *valtype, const void *in)
+{
+ char out[8];
+ int len = TYPE_LENGTH (valtype);
+ gdb_assert (len < 8);
+
+ memset (out, 0, 8);
+ memcpy (out, in, len);
+ put_frame_register (frame, regnum, out);
+}
+
+/* Register groups. */
+
+static int
+s390_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Registers displayed via 'info regs'. */
+ if (group == general_reggroup)
+ return (regnum >= S390_R0_REGNUM && regnum <= S390_R15_REGNUM)
+ || regnum == S390_PC_REGNUM
+ || regnum == S390_CC_REGNUM;
+
+ /* Registers displayed via 'info float'. */
+ if (group == float_reggroup)
+ return (regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM)
+ || regnum == S390_FPC_REGNUM;
+
+ /* Registers that need to be saved/restored in order to
+ push or pop frames. */
+ if (group == save_reggroup || group == restore_reggroup)
+ return regnum != S390_PSWM_REGNUM && regnum != S390_PSWA_REGNUM;
+
+ return default_register_reggroup_p (gdbarch, regnum, group);
+}
+
+
+/* Core file register sets. */
+
+int s390_regmap_gregset[S390_NUM_REGS] =
+{
+ /* Program Status Word. */
+ 0x00, 0x04,
+ /* General Purpose Registers. */
+ 0x08, 0x0c, 0x10, 0x14,
+ 0x18, 0x1c, 0x20, 0x24,
+ 0x28, 0x2c, 0x30, 0x34,
+ 0x38, 0x3c, 0x40, 0x44,
+ /* Access Registers. */
+ 0x48, 0x4c, 0x50, 0x54,
+ 0x58, 0x5c, 0x60, 0x64,
+ 0x68, 0x6c, 0x70, 0x74,
+ 0x78, 0x7c, 0x80, 0x84,
+ /* Floating Point Control Word. */
+ -1,
+ /* Floating Point Registers. */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+int s390x_regmap_gregset[S390_NUM_REGS] =
+{
+ 0x00, 0x08,
+ /* General Purpose Registers. */
+ 0x10, 0x18, 0x20, 0x28,
+ 0x30, 0x38, 0x40, 0x48,
+ 0x50, 0x58, 0x60, 0x68,
+ 0x70, 0x78, 0x80, 0x88,
+ /* Access Registers. */
+ 0x90, 0x94, 0x98, 0x9c,
+ 0xa0, 0xa4, 0xa8, 0xac,
+ 0xb0, 0xb4, 0xb8, 0xbc,
+ 0xc0, 0xc4, 0xc8, 0xcc,
+ /* Floating Point Control Word. */
+ -1,
+ /* Floating Point Registers. */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+int s390_regmap_fpregset[S390_NUM_REGS] =
+{
+ /* Program Status Word. */
+ -1, -1,
+ /* General Purpose Registers. */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* Access Registers. */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* Floating Point Control Word. */
+ 0x00,
+ /* Floating Point Registers. */
+ 0x08, 0x10, 0x18, 0x20,
+ 0x28, 0x30, 0x38, 0x40,
+ 0x48, 0x50, 0x58, 0x60,
+ 0x68, 0x70, 0x78, 0x80,
+};
+
+/* Supply register REGNUM from the register set REGSET to register cache
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
+static void
+s390_supply_regset (const struct regset *regset, struct regcache *regcache,
+ int regnum, const void *regs, size_t len)
+{
+ const int *offset = regset->descr;
+ int i;
+
+ for (i = 0; i < S390_NUM_REGS; i++)
+ {
+ if ((regnum == i || regnum == -1) && offset[i] != -1)
+ regcache_raw_supply (regcache, i, (const char *)regs + offset[i]);
+ }
+}
+
+static const struct regset s390_gregset = {
+ s390_regmap_gregset,
+ s390_supply_regset
+};
+
+static const struct regset s390x_gregset = {
+ s390x_regmap_gregset,
+ s390_supply_regset
+};
+
+static const struct regset s390_fpregset = {
+ s390_regmap_fpregset,
+ s390_supply_regset
+};
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+const struct regset *
+s390_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (strcmp (sect_name, ".reg") == 0 && sect_size == tdep->sizeof_gregset)
+ return tdep->gregset;
+
+ if (strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
+ return tdep->fpregset;
+
+ return NULL;
+}
+
+
+/* Prologue analysis. */
+
+/* When we analyze a prologue, we're really doing 'abstract
+ interpretation' or 'pseudo-evaluation': running the function's code
+ in simulation, but using conservative approximations of the values
+ it would have when it actually runs. For example, if our function
+ starts with the instruction:
+
+ ahi r1, 42 # add halfword immediate 42 to r1
+
+ we don't know exactly what value will be in r1 after executing this
+ instruction, but we do know it'll be 42 greater than its original
+ value.
+
+ If we then see an instruction like:
+
+ ahi r1, 22 # add halfword immediate 22 to r1
+
+ we still don't know what r1's value is, but again, we can say it is
+ now 64 greater than its original value.
+
+ If the next instruction were:
+
+ lr r2, r1 # set r2 to r1's value
+
+ then we can say that r2's value is now the original value of r1
+ plus 64. And so on.
+
+ Of course, this can only go so far before it gets unreasonable. If
+ we wanted to be able to say anything about the value of r1 after
+ the instruction:
+
+ xr r1, r3 # exclusive-or r1 and r3, place result in r1
+
+ then things would get pretty complex. But remember, we're just
+ doing a conservative approximation; if exclusive-or instructions
+ aren't relevant to prologues, we can just say r1's value is now
+ 'unknown'. We can ignore things that are too complex, if that loss
+ of information is acceptable for our application.
+
+ Once you've reached an instruction that you don't know how to
+ simulate, you stop. Now you examine the state of the registers and
+ stack slots you've kept track of. For example:
+
+ - To see how large your stack frame is, just check the value of sp;
+ if it's the original value of sp minus a constant, then that
+ constant is the stack frame's size. If the sp's value has been
+ marked as 'unknown', then that means the prologue has done
+ something too complex for us to track, and we don't know the
+ frame size.
+
+ - To see whether we've saved the SP in the current frame's back
+ chain slot, we just check whether the current value of the back
+ chain stack slot is the original value of the sp.
+
+ Sure, this takes some work. But prologue analyzers aren't
+ quick-and-simple pattern patching to recognize a few fixed prologue
+ forms any more; they're big, hairy functions. Along with inferior
+ function calls, prologue analysis accounts for a substantial
+ portion of the time needed to stabilize a GDB port. So I think
+ it's worthwhile to look for an approach that will be easier to
+ understand and maintain. In the approach used here:
+
+ - It's easier to see that the analyzer is correct: you just see
+ whether the analyzer properly (albiet conservatively) simulates
+ the effect of each instruction.
+
+ - It's easier to extend the analyzer: you can add support for new
+ instructions, and know that you haven't broken anything that
+ wasn't already broken before.
+
+ - It's orthogonal: to gather new information, you don't need to
+ complicate the code for each instruction. As long as your domain
+ of conservative values is already detailed enough to tell you
+ what you need, then all the existing instruction simulations are
+ already gathering the right data for you.
+
+ A 'struct prologue_value' is a conservative approximation of the
+ real value the register or stack slot will have. */
+
+struct prologue_value {
+
+ /* What sort of value is this? This determines the interpretation
+ of subsequent fields. */
+ enum {
+
+ /* We don't know anything about the value. This is also used for
+ values we could have kept track of, when doing so would have
+ been too complex and we don't want to bother. The bottom of
+ our lattice. */
+ pv_unknown,
+
+ /* A known constant. K is its value. */
+ pv_constant,
+
+ /* The value that register REG originally had *UPON ENTRY TO THE
+ FUNCTION*, plus K. If K is zero, this means, obviously, just
+ the value REG had upon entry to the function. REG is a GDB
+ register number. Before we start interpreting, we initialize
+ every register R to { pv_register, R, 0 }. */
+ pv_register,
+
+ } kind;
+
+ /* The meanings of the following fields depend on 'kind'; see the
+ comments for the specific 'kind' values. */
+ int reg;
+ CORE_ADDR k;
+};
+
+
+/* Set V to be unknown. */
+static void
+pv_set_to_unknown (struct prologue_value *v)
+{
+ v->kind = pv_unknown;
+}
+
+
+/* Set V to the constant K. */
+static void
+pv_set_to_constant (struct prologue_value *v, CORE_ADDR k)
+{
+ v->kind = pv_constant;
+ v->k = k;
+}
+
+
+/* Set V to the original value of register REG, plus K. */
+static void
+pv_set_to_register (struct prologue_value *v, int reg, CORE_ADDR k)
+{
+ v->kind = pv_register;
+ v->reg = reg;
+ v->k = k;
+}
+
+
+/* If one of *A and *B is a constant, and the other isn't, swap the
+ pointers as necessary to ensure that *B points to the constant.
+ This can reduce the number of cases we need to analyze in the
+ functions below. */
+static void
+pv_constant_last (struct prologue_value **a,
+ struct prologue_value **b)
+{
+ if ((*a)->kind == pv_constant
+ && (*b)->kind != pv_constant)
+ {
+ struct prologue_value *temp = *a;
+ *a = *b;
+ *b = temp;
+ }
+}
+
+
+/* Set SUM to the sum of A and B. SUM, A, and B may point to the same
+ 'struct prologue_value' object. */
+static void
+pv_add (struct prologue_value *sum,
+ struct prologue_value *a,
+ struct prologue_value *b)
+{
+ pv_constant_last (&a, &b);
+
+ /* We can handle adding constants to registers, and other constants. */
+ if (b->kind == pv_constant
+ && (a->kind == pv_register
+ || a->kind == pv_constant))
+ {
+ sum->kind = a->kind;
+ sum->reg = a->reg; /* not meaningful if a is pv_constant, but
+ harmless */
+ sum->k = a->k + b->k;
+ }
+
+ /* Anything else we don't know how to add. We don't have a
+ representation for, say, the sum of two registers, or a multiple
+ of a register's value (adding a register to itself). */
+ else
+ sum->kind = pv_unknown;
+}
+
+
+/* Add the constant K to V. */
+static void
+pv_add_constant (struct prologue_value *v, CORE_ADDR k)
+{
+ struct prologue_value pv_k;
+
+ /* Rather than thinking of all the cases we can and can't handle,
+ we'll just let pv_add take care of that for us. */
+ pv_set_to_constant (&pv_k, k);
+ pv_add (v, v, &pv_k);
+}
+
+
+/* Subtract B from A, and put the result in DIFF.
+
+ This isn't quite the same as negating B and adding it to A, since
+ we don't have a representation for the negation of anything but a
+ constant. For example, we can't negate { pv_register, R1, 10 },
+ but we do know that { pv_register, R1, 10 } minus { pv_register,
+ R1, 5 } is { pv_constant, <ignored>, 5 }.
+
+ This means, for example, that we can subtract two stack addresses;
+ they're both relative to the original SP. Since the frame pointer
+ is set based on the SP, its value will be the original SP plus some
+ constant (probably zero), so we can use its value just fine. */
+static void
+pv_subtract (struct prologue_value *diff,
+ struct prologue_value *a,
+ struct prologue_value *b)
+{
+ pv_constant_last (&a, &b);
+
+ /* We can subtract a constant from another constant, or from a
+ register. */
+ if (b->kind == pv_constant
+ && (a->kind == pv_register
+ || a->kind == pv_constant))
+ {
+ diff->kind = a->kind;
+ diff->reg = a->reg; /* not always meaningful, but harmless */
+ diff->k = a->k - b->k;
+ }
+
+ /* We can subtract a register from itself, yielding a constant. */
+ else if (a->kind == pv_register
+ && b->kind == pv_register
+ && a->reg == b->reg)
+ {
+ diff->kind = pv_constant;
+ diff->k = a->k - b->k;
+ }
+
+ /* We don't know how to subtract anything else. */
+ else
+ diff->kind = pv_unknown;
+}
+
+
+/* Set AND to the logical and of A and B. */
+static void
+pv_logical_and (struct prologue_value *and,
+ struct prologue_value *a,
+ struct prologue_value *b)
+{
+ pv_constant_last (&a, &b);
+
+ /* We can 'and' two constants. */
+ if (a->kind == pv_constant
+ && b->kind == pv_constant)
+ {
+ and->kind = pv_constant;
+ and->k = a->k & b->k;
+ }
+
+ /* We can 'and' anything with the constant zero. */
+ else if (b->kind == pv_constant
+ && b->k == 0)
+ {
+ and->kind = pv_constant;
+ and->k = 0;
+ }
+
+ /* We can 'and' anything with ~0. */
+ else if (b->kind == pv_constant
+ && b->k == ~ (CORE_ADDR) 0)
+ *and = *a;
+
+ /* We can 'and' a register with itself. */
+ else if (a->kind == pv_register
+ && b->kind == pv_register
+ && a->reg == b->reg
+ && a->k == b->k)
+ *and = *a;
+
+ /* Otherwise, we don't know. */
+ else
+ pv_set_to_unknown (and);
+}
+
+
+/* Return non-zero iff A and B are identical expressions.
+
+ This is not the same as asking if the two values are equal; the
+ result of such a comparison would have to be a pv_boolean, and
+ asking whether two 'unknown' values were equal would give you
+ pv_maybe. Same for comparing, say, { pv_register, R1, 0 } and {
+ pv_register, R2, 0}. Instead, this is asking whether the two
+ representations are the same. */
+static int
+pv_is_identical (struct prologue_value *a,
+ struct prologue_value *b)
+{
+ if (a->kind != b->kind)
+ return 0;
+
+ switch (a->kind)
+ {
+ case pv_unknown:
+ return 1;
+ case pv_constant:
+ return (a->k == b->k);
+ case pv_register:
+ return (a->reg == b->reg && a->k == b->k);
+ default:
+ gdb_assert (0);
+ }
+}
+
+
+/* Return non-zero if A is the original value of register number R
+ plus K, zero otherwise. */
+static int
+pv_is_register (struct prologue_value *a, int r, CORE_ADDR k)
+{
+ return (a->kind == pv_register
+ && a->reg == r
+ && a->k == k);
+}
+
+
+/* A prologue-value-esque boolean type, including "maybe", when we
+ can't figure out whether something is true or not. */
+enum pv_boolean {
+ pv_maybe,
+ pv_definite_yes,
+ pv_definite_no,
+};
+
+
+/* Decide whether a reference to SIZE bytes at ADDR refers exactly to
+ an element of an array. The array starts at ARRAY_ADDR, and has
+ ARRAY_LEN values of ELT_SIZE bytes each. If ADDR definitely does
+ refer to an array element, set *I to the index of the referenced
+ element in the array, and return pv_definite_yes. If it definitely
+ doesn't, return pv_definite_no. If we can't tell, return pv_maybe.
+
+ If the reference does touch the array, but doesn't fall exactly on
+ an element boundary, or doesn't refer to the whole element, return
+ pv_maybe. */
+static enum pv_boolean
+pv_is_array_ref (struct prologue_value *addr,
+ CORE_ADDR size,
+ struct prologue_value *array_addr,
+ CORE_ADDR array_len,
+ CORE_ADDR elt_size,
+ int *i)
+{
+ struct prologue_value offset;
+
+ /* Note that, since ->k is a CORE_ADDR, and CORE_ADDR is unsigned,
+ if addr is *before* the start of the array, then this isn't going
+ to be negative... */
+ pv_subtract (&offset, addr, array_addr);
+
+ if (offset.kind == pv_constant)
+ {
+ /* This is a rather odd test. We want to know if the SIZE bytes
+ at ADDR don't overlap the array at all, so you'd expect it to
+ be an || expression: "if we're completely before || we're
+ completely after". But with unsigned arithmetic, things are
+ different: since it's a number circle, not a number line, the
+ right values for offset.k are actually one contiguous range. */
+ if (offset.k <= -size
+ && offset.k >= array_len * elt_size)
+ return pv_definite_no;
+ else if (offset.k % elt_size != 0
+ || size != elt_size)
+ return pv_maybe;
+ else
+ {
+ *i = offset.k / elt_size;
+ return pv_definite_yes;
+ }
+ }
+ else
+ return pv_maybe;
+}
+
+
+
+/* Decoding S/390 instructions. */
+
+/* Named opcode values for the S/390 instructions we recognize. Some
+ instructions have their opcode split across two fields; those are the
+ op1_* and op2_* enums. */
+enum
+ {
+ op1_lhi = 0xa7, op2_lhi = 0x08,
+ op1_lghi = 0xa7, op2_lghi = 0x09,
+ op_lr = 0x18,
+ op_lgr = 0xb904,
+ op_l = 0x58,
+ op1_ly = 0xe3, op2_ly = 0x58,
+ op1_lg = 0xe3, op2_lg = 0x04,
+ op_lm = 0x98,
+ op1_lmy = 0xeb, op2_lmy = 0x98,
+ op1_lmg = 0xeb, op2_lmg = 0x04,
+ op_st = 0x50,
+ op1_sty = 0xe3, op2_sty = 0x50,
+ op1_stg = 0xe3, op2_stg = 0x24,
+ op_std = 0x60,
+ op_stm = 0x90,
+ op1_stmy = 0xeb, op2_stmy = 0x90,
+ op1_stmg = 0xeb, op2_stmg = 0x24,
+ op1_aghi = 0xa7, op2_aghi = 0x0b,
+ op1_ahi = 0xa7, op2_ahi = 0x0a,
+ op_ar = 0x1a,
+ op_agr = 0xb908,
+ op_a = 0x5a,
+ op1_ay = 0xe3, op2_ay = 0x5a,
+ op1_ag = 0xe3, op2_ag = 0x08,
+ op_sr = 0x1b,
+ op_sgr = 0xb909,
+ op_s = 0x5b,
+ op1_sy = 0xe3, op2_sy = 0x5b,
+ op1_sg = 0xe3, op2_sg = 0x09,
+ op_nr = 0x14,
+ op_ngr = 0xb980,
+ op_la = 0x41,
+ op1_lay = 0xe3, op2_lay = 0x71,
+ op1_larl = 0xc0, op2_larl = 0x00,
+ op_basr = 0x0d,
+ op_bas = 0x4d,
+ op_bcr = 0x07,
+ op_bc = 0x0d,
+ op1_bras = 0xa7, op2_bras = 0x05,
+ op1_brasl= 0xc0, op2_brasl= 0x05,
+ op1_brc = 0xa7, op2_brc = 0x04,
+ op1_brcl = 0xc0, op2_brcl = 0x04,
+ };
+
+
+/* Read a single instruction from address AT. */
+
+#define S390_MAX_INSTR_SIZE 6
+static int
+s390_readinstruction (bfd_byte instr[], CORE_ADDR at)
+{
+ static int s390_instrlen[] = { 2, 4, 4, 6 };
+ int instrlen;
+
+ if (read_memory_nobpt (at, &instr[0], 2))
+ return -1;
+ instrlen = s390_instrlen[instr[0] >> 6];
+ if (instrlen > 2)
+ {
+ if (read_memory_nobpt (at + 2, &instr[2], instrlen - 2))
+ return -1;
+ }
+ return instrlen;
+}
+
+
+/* The functions below are for recognizing and decoding S/390
+ instructions of various formats. Each of them checks whether INSN
+ is an instruction of the given format, with the specified opcodes.
+ If it is, it sets the remaining arguments to the values of the
+ instruction's fields, and returns a non-zero value; otherwise, it
+ returns zero.
+
+ These functions' arguments appear in the order they appear in the
+ instruction, not in the machine-language form. So, opcodes always
+ come first, even though they're sometimes scattered around the
+ instructions. And displacements appear before base and extension
+ registers, as they do in the assembly syntax, not at the end, as
+ they do in the machine language. */
+static int
+is_ri (bfd_byte *insn, int op1, int op2, unsigned int *r1, int *i2)
+{
+ if (insn[0] == op1 && (insn[1] & 0xf) == op2)
+ {
+ *r1 = (insn[1] >> 4) & 0xf;
+ /* i2 is a 16-bit signed quantity. */
+ *i2 = (((insn[2] << 8) | insn[3]) ^ 0x8000) - 0x8000;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+is_ril (bfd_byte *insn, int op1, int op2,
+ unsigned int *r1, int *i2)
+{
+ if (insn[0] == op1 && (insn[1] & 0xf) == op2)
+ {
+ *r1 = (insn[1] >> 4) & 0xf;
+ /* i2 is a signed quantity. If the host 'int' is 32 bits long,
+ no sign extension is necessary, but we don't want to assume
+ that. */
+ *i2 = (((insn[2] << 24)
+ | (insn[3] << 16)
+ | (insn[4] << 8)
+ | (insn[5])) ^ 0x80000000) - 0x80000000;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+is_rr (bfd_byte *insn, int op, unsigned int *r1, unsigned int *r2)
+{
+ if (insn[0] == op)
+ {
+ *r1 = (insn[1] >> 4) & 0xf;
+ *r2 = insn[1] & 0xf;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+is_rre (bfd_byte *insn, int op, unsigned int *r1, unsigned int *r2)
+{
+ if (((insn[0] << 8) | insn[1]) == op)
+ {
+ /* Yes, insn[3]. insn[2] is unused in RRE format. */
+ *r1 = (insn[3] >> 4) & 0xf;
+ *r2 = insn[3] & 0xf;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+is_rs (bfd_byte *insn, int op,
+ unsigned int *r1, unsigned int *r3, unsigned int *d2, unsigned int *b2)
+{
+ if (insn[0] == op)
+ {
+ *r1 = (insn[1] >> 4) & 0xf;
+ *r3 = insn[1] & 0xf;
+ *b2 = (insn[2] >> 4) & 0xf;
+ *d2 = ((insn[2] & 0xf) << 8) | insn[3];
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+is_rsy (bfd_byte *insn, int op1, int op2,
+ unsigned int *r1, unsigned int *r3, unsigned int *d2, unsigned int *b2)
+{
+ if (insn[0] == op1
+ && insn[5] == op2)
+ {
+ *r1 = (insn[1] >> 4) & 0xf;
+ *r3 = insn[1] & 0xf;
+ *b2 = (insn[2] >> 4) & 0xf;
+ /* The 'long displacement' is a 20-bit signed integer. */
+ *d2 = ((((insn[2] & 0xf) << 8) | insn[3] | (insn[4] << 12))
+ ^ 0x80000) - 0x80000;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+is_rx (bfd_byte *insn, int op,
+ unsigned int *r1, unsigned int *d2, unsigned int *x2, unsigned int *b2)
+{
+ if (insn[0] == op)
+ {
+ *r1 = (insn[1] >> 4) & 0xf;
+ *x2 = insn[1] & 0xf;
+ *b2 = (insn[2] >> 4) & 0xf;
+ *d2 = ((insn[2] & 0xf) << 8) | insn[3];
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static int
+is_rxy (bfd_byte *insn, int op1, int op2,
+ unsigned int *r1, unsigned int *d2, unsigned int *x2, unsigned int *b2)
+{
+ if (insn[0] == op1
+ && insn[5] == op2)
+ {
+ *r1 = (insn[1] >> 4) & 0xf;
+ *x2 = insn[1] & 0xf;
+ *b2 = (insn[2] >> 4) & 0xf;
+ /* The 'long displacement' is a 20-bit signed integer. */
+ *d2 = ((((insn[2] & 0xf) << 8) | insn[3] | (insn[4] << 12))
+ ^ 0x80000) - 0x80000;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+/* Set ADDR to the effective address for an X-style instruction, like:
+
+ L R1, D2(X2, B2)
+
+ Here, X2 and B2 are registers, and D2 is a signed 20-bit
+ constant; the effective address is the sum of all three. If either
+ X2 or B2 are zero, then it doesn't contribute to the sum --- this
+ means that r0 can't be used as either X2 or B2.
+
+ GPR is an array of general register values, indexed by GPR number,
+ not GDB register number. */
+static void
+compute_x_addr (struct prologue_value *addr,
+ struct prologue_value *gpr,
+ int d2, unsigned int x2, unsigned int b2)
+{
+ /* We can't just add stuff directly in addr; it might alias some of
+ the registers we need to read. */
+ struct prologue_value result;
+
+ pv_set_to_constant (&result, d2);
+ if (x2)
+ pv_add (&result, &result, &gpr[x2]);
+ if (b2)
+ pv_add (&result, &result, &gpr[b2]);
+
+ *addr = result;
+}
+
+
+/* The number of GPR and FPR spill slots in an S/390 stack frame. We
+ track general-purpose registers r2 -- r15, and floating-point
+ registers f0, f2, f4, and f6. */
+#define S390_NUM_SPILL_SLOTS (14 + 4)
+#define S390_NUM_GPRS 16
+#define S390_NUM_FPRS 16
+
+struct s390_prologue_data {
+
+ /* The size of a GPR or FPR. */
+ int gpr_size;
+ int fpr_size;
+
+ /* The general-purpose registers. */
+ struct prologue_value gpr[S390_NUM_GPRS];
+
+ /* The floating-point registers. */
+ struct prologue_value fpr[S390_NUM_FPRS];
+
+ /* The register spill stack slots in the caller's frame ---
+ general-purpose registers r2 through r15, and floating-point
+ registers. spill[i] is where gpr i+2 gets spilled;
+ spill[(14, 15, 16, 17)] is where (f0, f2, f4, f6) get spilled. */
+ struct prologue_value spill[S390_NUM_SPILL_SLOTS];
+
+ /* The value of the back chain slot. This is only valid if the stack
+ pointer is known to be less than its original value --- that is,
+ if we have indeed allocated space on the stack. */
+ struct prologue_value back_chain;
+};
+
+
+/* If the SIZE bytes at ADDR are a stack slot we're actually tracking,
+ return pv_definite_yes and set *STACK to point to the slot. If
+ we're sure that they are not any of our stack slots, then return
+ pv_definite_no. Otherwise, return pv_maybe.
+
+ DATA describes our current state (registers and stack slots). */
+static enum pv_boolean
+s390_on_stack (struct prologue_value *addr,
+ CORE_ADDR size,
+ struct s390_prologue_data *data,
+ struct prologue_value **stack)
+{
+ struct prologue_value gpr_spill_addr;
+ struct prologue_value fpr_spill_addr;
+ struct prologue_value back_chain_addr;
+ int i;
+ enum pv_boolean b;
+
+ /* Construct the addresses of the spill arrays and the back chain. */
+ pv_set_to_register (&gpr_spill_addr, S390_SP_REGNUM, 2 * data->gpr_size);
+ pv_set_to_register (&fpr_spill_addr, S390_SP_REGNUM, 16 * data->gpr_size);
+ back_chain_addr = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+
+ /* We have to check for GPR and FPR references using two separate
+ calls to pv_is_array_ref, since the GPR and FPR spill slots are
+ different sizes. (SPILL is an array, but the thing it tracks
+ isn't really an array.) */
+
+ /* Was it a reference to the GPR spill array? */
+ b = pv_is_array_ref (addr, size, &gpr_spill_addr, 14, data->gpr_size, &i);
+ if (b == pv_definite_yes)
+ {
+ *stack = &data->spill[i];
+ return pv_definite_yes;
+ }
+ if (b == pv_maybe)
+ return pv_maybe;
+
+ /* Was it a reference to the FPR spill array? */
+ b = pv_is_array_ref (addr, size, &fpr_spill_addr, 4, data->fpr_size, &i);
+ if (b == pv_definite_yes)
+ {
+ *stack = &data->spill[14 + i];
+ return pv_definite_yes;
+ }
+ if (b == pv_maybe)
+ return pv_maybe;
+
+ /* Was it a reference to the back chain?
+ This isn't quite right. We ought to check whether we have
+ actually allocated any new frame at all. */
+ b = pv_is_array_ref (addr, size, &back_chain_addr, 1, data->gpr_size, &i);
+ if (b == pv_definite_yes)
+ {
+ *stack = &data->back_chain;
+ return pv_definite_yes;
+ }
+ if (b == pv_maybe)
+ return pv_maybe;
+
+ /* All the above queries returned definite 'no's. */
+ return pv_definite_no;
+}
+
+
+/* Do a SIZE-byte store of VALUE to ADDR. */
+static void
+s390_store (struct prologue_value *addr,
+ CORE_ADDR size,
+ struct prologue_value *value,
+ struct s390_prologue_data *data)
+{
+ struct prologue_value *stack;
+
+ /* We can do it if it's definitely a reference to something on the stack. */
+ if (s390_on_stack (addr, size, data, &stack) == pv_definite_yes)
+ {
+ *stack = *value;
+ return;
+ }
+
+ /* Note: If s390_on_stack returns pv_maybe, you might think we should
+ forget our cached values, as any of those might have been hit.
+
+ However, we make the assumption that --since the fields we track
+ are save areas private to compiler, and never directly exposed to
+ the user-- every access to our data is explicit. Hence, every
+ memory access we cannot follow can't hit our data. */
+}
+
+/* Do a SIZE-byte load from ADDR into VALUE. */
+static void
+s390_load (struct prologue_value *addr,
+ CORE_ADDR size,
+ struct prologue_value *value,
+ struct s390_prologue_data *data)
+{
+ struct prologue_value *stack;
+
+ /* If it's a load from an in-line constant pool, then we can
+ simulate that, under the assumption that the code isn't
+ going to change between the time the processor actually
+ executed it creating the current frame, and the time when
+ we're analyzing the code to unwind past that frame. */
+ if (addr->kind == pv_constant)
+ {
+ struct section_table *secp;
+ secp = target_section_by_addr (&current_target, addr->k);
+ if (secp != NULL
+ && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
+ & SEC_READONLY))
+ {
+ pv_set_to_constant (value, read_memory_integer (addr->k, size));
+ return;
+ }
+ }
+
+ /* If it's definitely a reference to something on the stack,
+ we can do that. */
+ if (s390_on_stack (addr, size, data, &stack) == pv_definite_yes)
+ {
+ *value = *stack;
+ return;
+ }
+
+ /* Otherwise, we don't know the value. */
+ pv_set_to_unknown (value);
+}
+
+
+/* Analyze the prologue of the function starting at START_PC,
+ continuing at most until CURRENT_PC. Initialize DATA to
+ hold all information we find out about the state of the registers
+ and stack slots. Return the address of the instruction after
+ the last one that changed the SP, FP, or back chain; or zero
+ on error. */
+static CORE_ADDR
+s390_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR start_pc,
+ CORE_ADDR current_pc,
+ struct s390_prologue_data *data)
+{
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+
+ /* Our return value:
+ The address of the instruction after the last one that changed
+ the SP, FP, or back chain; zero if we got an error trying to
+ read memory. */
+ CORE_ADDR result = start_pc;
+
+ /* The current PC for our abstract interpretation. */
+ CORE_ADDR pc;
+
+ /* The address of the next instruction after that. */
+ CORE_ADDR next_pc;
+
+ /* Set up everything's initial value. */
+ {
+ int i;
+
+ /* For the purpose of prologue tracking, we consider the GPR size to
+ be equal to the ABI word size, even if it is actually larger
+ (i.e. when running a 32-bit binary under a 64-bit kernel). */
+ data->gpr_size = word_size;
+ data->fpr_size = 8;
+
+ for (i = 0; i < S390_NUM_GPRS; i++)
+ pv_set_to_register (&data->gpr[i], S390_R0_REGNUM + i, 0);
+
+ for (i = 0; i < S390_NUM_FPRS; i++)
+ pv_set_to_register (&data->fpr[i], S390_F0_REGNUM + i, 0);
+
+ for (i = 0; i < S390_NUM_SPILL_SLOTS; i++)
+ pv_set_to_unknown (&data->spill[i]);
+
+ pv_set_to_unknown (&data->back_chain);
+ }
+
+ /* Start interpreting instructions, until we hit the frame's
+ current PC or the first branch instruction. */
+ for (pc = start_pc; pc > 0 && pc < current_pc; pc = next_pc)
+ {
+ bfd_byte insn[S390_MAX_INSTR_SIZE];
+ int insn_len = s390_readinstruction (insn, pc);
+
+ /* Fields for various kinds of instructions. */
+ unsigned int b2, r1, r2, x2, r3;
+ int i2, d2;
+
+ /* The values of SP, FP, and back chain before this instruction,
+ for detecting instructions that change them. */
+ struct prologue_value pre_insn_sp, pre_insn_fp, pre_insn_back_chain;
+
+ /* If we got an error trying to read the instruction, report it. */
+ if (insn_len < 0)
+ {
+ result = 0;
+ break;
+ }
+
+ next_pc = pc + insn_len;
+
+ pre_insn_sp = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+ pre_insn_fp = data->gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
+ pre_insn_back_chain = data->back_chain;
+
+ /* LHI r1, i2 --- load halfword immediate */
+ if (word_size == 4
+ && is_ri (insn, op1_lhi, op2_lhi, &r1, &i2))
+ pv_set_to_constant (&data->gpr[r1], i2);
+
+ /* LGHI r1, i2 --- load halfword immediate (64-bit version) */
+ else if (word_size == 8
+ && is_ri (insn, op1_lghi, op2_lghi, &r1, &i2))
+ pv_set_to_constant (&data->gpr[r1], i2);
+
+ /* LR r1, r2 --- load from register */
+ else if (word_size == 4
+ && is_rr (insn, op_lr, &r1, &r2))
+ data->gpr[r1] = data->gpr[r2];
+
+ /* LGR r1, r2 --- load from register (64-bit version) */
+ else if (word_size == 8
+ && is_rre (insn, op_lgr, &r1, &r2))
+ data->gpr[r1] = data->gpr[r2];
+
+ /* L r1, d2(x2, b2) --- load */
+ else if (word_size == 4
+ && is_rx (insn, op_l, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 4, &data->gpr[r1], data);
+ }
+
+ /* LY r1, d2(x2, b2) --- load (long-displacement version) */
+ else if (word_size == 4
+ && is_rxy (insn, op1_ly, op2_ly, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 4, &data->gpr[r1], data);
+ }
+
+ /* LG r1, d2(x2, b2) --- load (64-bit version) */
+ else if (word_size == 8
+ && is_rxy (insn, op1_lg, op2_lg, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 8, &data->gpr[r1], data);
+ }
+
+ /* ST r1, d2(x2, b2) --- store */
+ else if (word_size == 4
+ && is_rx (insn, op_st, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_store (&addr, 4, &data->gpr[r1], data);
+ }
+
+ /* STY r1, d2(x2, b2) --- store (long-displacement version) */
+ else if (word_size == 4
+ && is_rxy (insn, op1_sty, op2_sty, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_store (&addr, 4, &data->gpr[r1], data);
+ }
+
+ /* STG r1, d2(x2, b2) --- store (64-bit version) */
+ else if (word_size == 8
+ && is_rxy (insn, op1_stg, op2_stg, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_store (&addr, 8, &data->gpr[r1], data);
+ }
+
+ /* STD r1, d2(x2,b2) --- store floating-point register */
+ else if (is_rx (insn, op_std, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_store (&addr, 8, &data->fpr[r1], data);
+ }
+
+ /* STM r1, r3, d2(b2) --- store multiple */
+ else if (word_size == 4
+ && is_rs (insn, op_stm, &r1, &r3, &d2, &b2))
+ {
+ int regnum;
+ int offset;
+ struct prologue_value addr;
+
+ for (regnum = r1, offset = 0;
+ regnum <= r3;
+ regnum++, offset += 4)
+ {
+ compute_x_addr (&addr, data->gpr, d2 + offset, 0, b2);
+ s390_store (&addr, 4, &data->gpr[regnum], data);
+ }
+ }
+
+ /* STMY r1, r3, d2(b2) --- store multiple (long-displacement version) */
+ else if (word_size == 4
+ && is_rsy (insn, op1_stmy, op2_stmy, &r1, &r3, &d2, &b2))
+ {
+ int regnum;
+ int offset;
+ struct prologue_value addr;
+
+ for (regnum = r1, offset = 0;
+ regnum <= r3;
+ regnum++, offset += 4)
+ {
+ compute_x_addr (&addr, data->gpr, d2 + offset, 0, b2);
+ s390_store (&addr, 4, &data->gpr[regnum], data);
+ }
+ }
+
+ /* STMG r1, r3, d2(b2) --- store multiple (64-bit version) */
+ else if (word_size == 8
+ && is_rsy (insn, op1_stmg, op2_stmg, &r1, &r3, &d2, &b2))
+ {
+ int regnum;
+ int offset;
+ struct prologue_value addr;
+
+ for (regnum = r1, offset = 0;
+ regnum <= r3;
+ regnum++, offset += 8)
+ {
+ compute_x_addr (&addr, data->gpr, d2 + offset, 0, b2);
+ s390_store (&addr, 8, &data->gpr[regnum], data);
+ }
+ }
+
+ /* AHI r1, i2 --- add halfword immediate */
+ else if (word_size == 4
+ && is_ri (insn, op1_ahi, op2_ahi, &r1, &i2))
+ pv_add_constant (&data->gpr[r1], i2);
+
+ /* AGHI r1, i2 --- add halfword immediate (64-bit version) */
+ else if (word_size == 8
+ && is_ri (insn, op1_aghi, op2_aghi, &r1, &i2))
+ pv_add_constant (&data->gpr[r1], i2);
+
+ /* AR r1, r2 -- add register */
+ else if (word_size == 4
+ && is_rr (insn, op_ar, &r1, &r2))
+ pv_add (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
+
+ /* AGR r1, r2 -- add register (64-bit version) */
+ else if (word_size == 8
+ && is_rre (insn, op_agr, &r1, &r2))
+ pv_add (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
+
+ /* A r1, d2(x2, b2) -- add */
+ else if (word_size == 4
+ && is_rx (insn, op_a, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value value;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 4, &value, data);
+
+ pv_add (&data->gpr[r1], &data->gpr[r1], &value);
+ }
+
+ /* AY r1, d2(x2, b2) -- add (long-displacement version) */
+ else if (word_size == 4
+ && is_rxy (insn, op1_ay, op2_ay, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value value;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 4, &value, data);
+
+ pv_add (&data->gpr[r1], &data->gpr[r1], &value);
+ }
+
+ /* AG r1, d2(x2, b2) -- add (64-bit version) */
+ else if (word_size == 8
+ && is_rxy (insn, op1_ag, op2_ag, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value value;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 8, &value, data);
+
+ pv_add (&data->gpr[r1], &data->gpr[r1], &value);
+ }
+
+ /* SR r1, r2 -- subtract register */
+ else if (word_size == 4
+ && is_rr (insn, op_sr, &r1, &r2))
+ pv_subtract (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
+
+ /* SGR r1, r2 -- subtract register (64-bit version) */
+ else if (word_size == 8
+ && is_rre (insn, op_sgr, &r1, &r2))
+ pv_subtract (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
+
+ /* S r1, d2(x2, b2) -- subtract */
+ else if (word_size == 4
+ && is_rx (insn, op_s, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value value;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 4, &value, data);
+
+ pv_subtract (&data->gpr[r1], &data->gpr[r1], &value);
+ }
+
+ /* SY r1, d2(x2, b2) -- subtract (long-displacement version) */
+ else if (word_size == 4
+ && is_rxy (insn, op1_sy, op2_sy, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value value;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 4, &value, data);
+
+ pv_subtract (&data->gpr[r1], &data->gpr[r1], &value);
+ }
+
+ /* SG r1, d2(x2, b2) -- subtract (64-bit version) */
+ else if (word_size == 8
+ && is_rxy (insn, op1_sg, op2_sg, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value value;
+
+ compute_x_addr (&addr, data->gpr, d2, x2, b2);
+ s390_load (&addr, 8, &value, data);
+
+ pv_subtract (&data->gpr[r1], &data->gpr[r1], &value);
+ }
+
+ /* NR r1, r2 --- logical and */
+ else if (word_size == 4
+ && is_rr (insn, op_nr, &r1, &r2))
+ pv_logical_and (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
+
+ /* NGR r1, r2 >--- logical and (64-bit version) */
+ else if (word_size == 8
+ && is_rre (insn, op_ngr, &r1, &r2))
+ pv_logical_and (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
+
+ /* LA r1, d2(x2, b2) --- load address */
+ else if (is_rx (insn, op_la, &r1, &d2, &x2, &b2))
+ compute_x_addr (&data->gpr[r1], data->gpr, d2, x2, b2);
+
+ /* LAY r1, d2(x2, b2) --- load address (long-displacement version) */
+ else if (is_rxy (insn, op1_lay, op2_lay, &r1, &d2, &x2, &b2))
+ compute_x_addr (&data->gpr[r1], data->gpr, d2, x2, b2);
+
+ /* LARL r1, i2 --- load address relative long */
+ else if (is_ril (insn, op1_larl, op2_larl, &r1, &i2))
+ pv_set_to_constant (&data->gpr[r1], pc + i2 * 2);
+
+ /* BASR r1, 0 --- branch and save
+ Since r2 is zero, this saves the PC in r1, but doesn't branch. */
+ else if (is_rr (insn, op_basr, &r1, &r2)
+ && r2 == 0)
+ pv_set_to_constant (&data->gpr[r1], next_pc);
+
+ /* BRAS r1, i2 --- branch relative and save */
+ else if (is_ri (insn, op1_bras, op2_bras, &r1, &i2))
+ {
+ pv_set_to_constant (&data->gpr[r1], next_pc);
+ next_pc = pc + i2 * 2;
+
+ /* We'd better not interpret any backward branches. We'll
+ never terminate. */
+ if (next_pc <= pc)
+ break;
+ }
+
+ /* Terminate search when hitting any other branch instruction. */
+ else if (is_rr (insn, op_basr, &r1, &r2)
+ || is_rx (insn, op_bas, &r1, &d2, &x2, &b2)
+ || is_rr (insn, op_bcr, &r1, &r2)
+ || is_rx (insn, op_bc, &r1, &d2, &x2, &b2)
+ || is_ri (insn, op1_brc, op2_brc, &r1, &i2)
+ || is_ril (insn, op1_brcl, op2_brcl, &r1, &i2)
+ || is_ril (insn, op1_brasl, op2_brasl, &r2, &i2))
+ break;
+
+ else
+ /* An instruction we don't know how to simulate. The only
+ safe thing to do would be to set every value we're tracking
+ to 'unknown'. Instead, we'll be optimistic: we assume that
+ we *can* interpret every instruction that the compiler uses
+ to manipulate any of the data we're interested in here --
+ then we can just ignore anything else. */
+ ;
+
+ /* Record the address after the last instruction that changed
+ the FP, SP, or backlink. Ignore instructions that changed
+ them back to their original values --- those are probably
+ restore instructions. (The back chain is never restored,
+ just popped.) */
+ {
+ struct prologue_value *sp = &data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+ struct prologue_value *fp = &data->gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
+
+ if ((! pv_is_identical (&pre_insn_sp, sp)
+ && ! pv_is_register (sp, S390_SP_REGNUM, 0))
+ || (! pv_is_identical (&pre_insn_fp, fp)
+ && ! pv_is_register (fp, S390_FRAME_REGNUM, 0))
+ || ! pv_is_identical (&pre_insn_back_chain, &data->back_chain))
+ result = next_pc;
+ }
+ }
+
+ return result;
+}
+
+/* Advance PC across any function entry prologue instructions to reach
+ some "real" code. */
+static CORE_ADDR
+s390_skip_prologue (CORE_ADDR pc)
+{
+ struct s390_prologue_data data;
+ CORE_ADDR skip_pc;
+ skip_pc = s390_analyze_prologue (current_gdbarch, pc, (CORE_ADDR)-1, &data);
+ return skip_pc ? skip_pc : pc;
+}
+
+/* Return true if we are in the functin's epilogue, i.e. after the
+ instruction that destroyed the function's stack frame. */
+static int
+s390_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+
+ /* In frameless functions, there's not frame to destroy and thus
+ we don't care about the epilogue.
+
+ In functions with frame, the epilogue sequence is a pair of
+ a LM-type instruction that restores (amongst others) the
+ return register %r14 and the stack pointer %r15, followed
+ by a branch 'br %r14' --or equivalent-- that effects the
+ actual return.
+
+ In that situation, this function needs to return 'true' in
+ exactly one case: when pc points to that branch instruction.
+
+ Thus we try to disassemble the one instructions immediately
+ preceeding pc and check whether it is an LM-type instruction
+ modifying the stack pointer.
+
+ Note that disassembling backwards is not reliable, so there
+ is a slight chance of false positives here ... */
+
+ bfd_byte insn[6];
+ unsigned int r1, r3, b2;
+ int d2;
+
+ if (word_size == 4
+ && !read_memory_nobpt (pc - 4, insn, 4)
+ && is_rs (insn, op_lm, &r1, &r3, &d2, &b2)
+ && r3 == S390_SP_REGNUM - S390_R0_REGNUM)
+ return 1;
+
+ if (word_size == 4
+ && !read_memory_nobpt (pc - 6, insn, 6)
+ && is_rsy (insn, op1_lmy, op2_lmy, &r1, &r3, &d2, &b2)
+ && r3 == S390_SP_REGNUM - S390_R0_REGNUM)
+ return 1;
+
+ if (word_size == 8
+ && !read_memory_nobpt (pc - 6, insn, 6)
+ && is_rsy (insn, op1_lmg, op2_lmg, &r1, &r3, &d2, &b2)
+ && r3 == S390_SP_REGNUM - S390_R0_REGNUM)
+ return 1;
+
+ return 0;
+}
+
+
+/* Normal stack frames. */
+
+struct s390_unwind_cache {
+
+ CORE_ADDR func;
+ CORE_ADDR frame_base;
+ CORE_ADDR local_base;
+
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+static int
+s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
+ struct s390_unwind_cache *info)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+ struct s390_prologue_data data;
+ struct prologue_value *fp = &data.gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
+ struct prologue_value *sp = &data.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+ int slot_num;
+ CORE_ADDR slot_addr;
+ CORE_ADDR func;
+ CORE_ADDR result;
+ ULONGEST reg;
+ CORE_ADDR prev_sp;
+ int frame_pointer;
+ int size;
+
+ /* Try to find the function start address. If we can't find it, we don't
+ bother searching for it -- with modern compilers this would be mostly
+ pointless anyway. Trust that we'll either have valid DWARF-2 CFI data
+ or else a valid backchain ... */
+ func = frame_func_unwind (next_frame);
+ if (!func)
+ return 0;
+
+ /* Try to analyze the prologue. */
+ result = s390_analyze_prologue (gdbarch, func,
+ frame_pc_unwind (next_frame), &data);
+ if (!result)
+ return 0;
+
+ /* If this was successful, we should have found the instruction that
+ sets the stack pointer register to the previous value of the stack
+ pointer minus the frame size. */
+ if (sp->kind != pv_register || sp->reg != S390_SP_REGNUM)
+ return 0;
+
+ /* A frame size of zero at this point can mean either a real
+ frameless function, or else a failure to find the prologue.
+ Perform some sanity checks to verify we really have a
+ frameless function. */
+ if (sp->k == 0)
+ {
+ /* If the next frame is a NORMAL_FRAME, this frame *cannot* have frame
+ size zero. This is only possible if the next frame is a sentinel
+ frame, a dummy frame, or a signal trampoline frame. */
+ if (get_frame_type (next_frame) == NORMAL_FRAME
+ /* For some reason, sentinel frames are NORMAL_FRAMEs
+ -- but they have negative frame level. */
+ && frame_relative_level (next_frame) >= 0)
+ return 0;
+
+ /* If we really have a frameless function, %r14 must be valid
+ -- in particular, it must point to a different function. */
+ reg = frame_unwind_register_unsigned (next_frame, S390_RETADDR_REGNUM);
+ reg = gdbarch_addr_bits_remove (gdbarch, reg) - 1;
+ if (get_pc_function_start (reg) == func)
+ {
+ /* However, there is one case where it *is* valid for %r14
+ to point to the same function -- if this is a recursive
+ call, and we have stopped in the prologue *before* the
+ stack frame was allocated.
+
+ Recognize this case by looking ahead a bit ... */
+
+ struct s390_prologue_data data2;
+ struct prologue_value *sp = &data2.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+
+ if (!(s390_analyze_prologue (gdbarch, func, (CORE_ADDR)-1, &data2)
+ && sp->kind == pv_register
+ && sp->reg == S390_SP_REGNUM
+ && sp->k != 0))
+ return 0;
+ }
+ }
+
+
+ /* OK, we've found valid prologue data. */
+ size = -sp->k;
+
+ /* If the frame pointer originally also holds the same value
+ as the stack pointer, we're probably using it. If it holds
+ some other value -- even a constant offset -- it is most
+ likely used as temp register. */
+ if (pv_is_identical (sp, fp))
+ frame_pointer = S390_FRAME_REGNUM;
+ else
+ frame_pointer = S390_SP_REGNUM;
+
+ /* If we've detected a function with stack frame, we'll still have to
+ treat it as frameless if we're currently within the function epilog
+ code at a point where the frame pointer has already been restored.
+ This can only happen in an innermost frame. */
+ if (size > 0
+ && (get_frame_type (next_frame) != NORMAL_FRAME
+ || frame_relative_level (next_frame) < 0))
+ {
+ /* See the comment in s390_in_function_epilogue_p on why this is
+ not completely reliable ... */
+ if (s390_in_function_epilogue_p (gdbarch, frame_pc_unwind (next_frame)))
+ {
+ memset (&data, 0, sizeof (data));
+ size = 0;
+ frame_pointer = S390_SP_REGNUM;
+ }
+ }
+
+ /* Once we know the frame register and the frame size, we can unwind
+ the current value of the frame register from the next frame, and
+ add back the frame size to arrive that the previous frame's
+ stack pointer value. */
+ prev_sp = frame_unwind_register_unsigned (next_frame, frame_pointer) + size;
+
+ /* Scan the spill array; if a spill slot says it holds the
+ original value of some register, then record that slot's
+ address as the place that register was saved. */
+
+ /* Slots for %r2 .. %r15. */
+ for (slot_num = 0, slot_addr = prev_sp + 2 * data.gpr_size;
+ slot_num < 14;
+ slot_num++, slot_addr += data.gpr_size)
+ {
+ struct prologue_value *slot = &data.spill[slot_num];
+
+ if (slot->kind == pv_register
+ && slot->k == 0)
+ info->saved_regs[slot->reg].addr = slot_addr;
+ }
+
+ /* Slots for %f0 .. %f6. */
+ for (slot_num = 14, slot_addr = prev_sp + 16 * data.gpr_size;
+ slot_num < S390_NUM_SPILL_SLOTS;
+ slot_num++, slot_addr += data.fpr_size)
+ {
+ struct prologue_value *slot = &data.spill[slot_num];
+
+ if (slot->kind == pv_register
+ && slot->k == 0)
+ info->saved_regs[slot->reg].addr = slot_addr;
+ }
+
+ /* Function return will set PC to %r14. */
+ info->saved_regs[S390_PC_REGNUM] = info->saved_regs[S390_RETADDR_REGNUM];
+
+ /* In frameless functions, we unwind simply by moving the return
+ address to the PC. However, if we actually stored to the
+ save area, use that -- we might only think the function frameless
+ because we're in the middle of the prologue ... */
+ if (size == 0
+ && !trad_frame_addr_p (info->saved_regs, S390_PC_REGNUM))
+ {
+ info->saved_regs[S390_PC_REGNUM].realreg = S390_RETADDR_REGNUM;
+ }
+
+ /* Another sanity check: unless this is a frameless function,
+ we should have found spill slots for SP and PC.
+ If not, we cannot unwind further -- this happens e.g. in
+ libc's thread_start routine. */
+ if (size > 0)
+ {
+ if (!trad_frame_addr_p (info->saved_regs, S390_SP_REGNUM)
+ || !trad_frame_addr_p (info->saved_regs, S390_PC_REGNUM))
+ prev_sp = -1;
+ }
+
+ /* We use the current value of the frame register as local_base,
+ and the top of the register save area as frame_base. */
+ if (prev_sp != -1)
+ {
+ info->frame_base = prev_sp + 16*word_size + 32;
+ info->local_base = prev_sp - size;
+ }
+
+ info->func = func;
+ return 1;
+}
+
+static void
+s390_backchain_frame_unwind_cache (struct frame_info *next_frame,
+ struct s390_unwind_cache *info)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+ CORE_ADDR backchain;
+ ULONGEST reg;
+ LONGEST sp;
+
+ /* Get the backchain. */
+ reg = frame_unwind_register_unsigned (next_frame, S390_SP_REGNUM);
+ backchain = read_memory_unsigned_integer (reg, word_size);
+
+ /* A zero backchain terminates the frame chain. As additional
+ sanity check, let's verify that the spill slot for SP in the
+ save area pointed to by the backchain in fact links back to
+ the save area. */
+ if (backchain != 0
+ && safe_read_memory_integer (backchain + 15*word_size, word_size, &sp)
+ && (CORE_ADDR)sp == backchain)
+ {
+ /* We don't know which registers were saved, but it will have
+ to be at least %r14 and %r15. This will allow us to continue
+ unwinding, but other prev-frame registers may be incorrect ... */
+ info->saved_regs[S390_SP_REGNUM].addr = backchain + 15*word_size;
+ info->saved_regs[S390_RETADDR_REGNUM].addr = backchain + 14*word_size;
+
+ /* Function return will set PC to %r14. */
+ info->saved_regs[S390_PC_REGNUM] = info->saved_regs[S390_RETADDR_REGNUM];
+
+ /* We use the current value of the frame register as local_base,
+ and the top of the register save area as frame_base. */
+ info->frame_base = backchain + 16*word_size + 32;
+ info->local_base = reg;
+ }
+
+ info->func = frame_pc_unwind (next_frame);
+}
+
+static struct s390_unwind_cache *
+s390_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct s390_unwind_cache *info;
+ if (*this_prologue_cache)
+ return *this_prologue_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct s390_unwind_cache);
+ *this_prologue_cache = info;
+ info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+ info->func = -1;
+ info->frame_base = -1;
+ info->local_base = -1;
+
+ /* Try to use prologue analysis to fill the unwind cache.
+ If this fails, fall back to reading the stack backchain. */
+ if (!s390_prologue_frame_unwind_cache (next_frame, info))
+ s390_backchain_frame_unwind_cache (next_frame, info);
+
+ return info;
+}
+
+static void
+s390_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct s390_unwind_cache *info
+ = s390_frame_unwind_cache (next_frame, this_prologue_cache);
+
+ if (info->frame_base == -1)
+ return;
+
+ *this_id = frame_id_build (info->frame_base, info->func);
+}
+
+static void
+s390_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct s390_unwind_cache *info
+ = s390_frame_unwind_cache (next_frame, this_prologue_cache);
+ trad_frame_prev_register (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
+}
+
+static const struct frame_unwind s390_frame_unwind = {
+ NORMAL_FRAME,
+ s390_frame_this_id,
+ s390_frame_prev_register
+};
+
+static const struct frame_unwind *
+s390_frame_sniffer (struct frame_info *next_frame)
+{
+ return &s390_frame_unwind;
+}
+
+
+/* Code stubs and their stack frames. For things like PLTs and NULL
+ function calls (where there is no true frame and the return address
+ is in the RETADDR register). */
+
+struct s390_stub_unwind_cache
+{
+ CORE_ADDR frame_base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct s390_stub_unwind_cache *
+s390_stub_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+ struct s390_stub_unwind_cache *info;
+ ULONGEST reg;
+
+ if (*this_prologue_cache)
+ return *this_prologue_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct s390_stub_unwind_cache);
+ *this_prologue_cache = info;
+ info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* The return address is in register %r14. */
+ info->saved_regs[S390_PC_REGNUM].realreg = S390_RETADDR_REGNUM;
+
+ /* Retrieve stack pointer and determine our frame base. */
+ reg = frame_unwind_register_unsigned (next_frame, S390_SP_REGNUM);
+ info->frame_base = reg + 16*word_size + 32;
+
+ return info;
+}
+
+static void
+s390_stub_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct s390_stub_unwind_cache *info
+ = s390_stub_frame_unwind_cache (next_frame, this_prologue_cache);
+ *this_id = frame_id_build (info->frame_base, frame_pc_unwind (next_frame));
+}
+
+static void
+s390_stub_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct s390_stub_unwind_cache *info
+ = s390_stub_frame_unwind_cache (next_frame, this_prologue_cache);
+ trad_frame_prev_register (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
+}
+
+static const struct frame_unwind s390_stub_frame_unwind = {
+ NORMAL_FRAME,
+ s390_stub_frame_this_id,
+ s390_stub_frame_prev_register
+};
+
+static const struct frame_unwind *
+s390_stub_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ bfd_byte insn[S390_MAX_INSTR_SIZE];
+
+ /* If the current PC points to non-readable memory, we assume we
+ have trapped due to an invalid function pointer call. We handle
+ the non-existing current function like a PLT stub. */
+ if (in_plt_section (pc, NULL)
+ || s390_readinstruction (insn, pc) < 0)
+ return &s390_stub_frame_unwind;
+ return NULL;
+}
+
+
+/* Signal trampoline stack frames. */
+
+struct s390_sigtramp_unwind_cache {
+ CORE_ADDR frame_base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct s390_sigtramp_unwind_cache *
+s390_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+ struct s390_sigtramp_unwind_cache *info;
+ ULONGEST this_sp, prev_sp;
+ CORE_ADDR next_ra, next_cfa, sigreg_ptr;
+ int i;
+
+ if (*this_prologue_cache)
+ return *this_prologue_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct s390_sigtramp_unwind_cache);
+ *this_prologue_cache = info;
+ info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ this_sp = frame_unwind_register_unsigned (next_frame, S390_SP_REGNUM);
+ next_ra = frame_pc_unwind (next_frame);
+ next_cfa = this_sp + 16*word_size + 32;
+
+ /* New-style RT frame:
+ retcode + alignment (8 bytes)
+ siginfo (128 bytes)
+ ucontext (contains sigregs at offset 5 words) */
+ if (next_ra == next_cfa)
+ {
+ sigreg_ptr = next_cfa + 8 + 128 + 5*word_size;
+ }
+
+ /* Old-style RT frame and all non-RT frames:
+ old signal mask (8 bytes)
+ pointer to sigregs */
+ else
+ {
+ sigreg_ptr = read_memory_unsigned_integer (next_cfa + 8, word_size);
+ }
+
+ /* The sigregs structure looks like this:
+ long psw_mask;
+ long psw_addr;
+ long gprs[16];
+ int acrs[16];
+ int fpc;
+ int __pad;
+ double fprs[16]; */
+
+ /* Let's ignore the PSW mask, it will not be restored anyway. */
+ sigreg_ptr += word_size;
+
+ /* Next comes the PSW address. */
+ info->saved_regs[S390_PC_REGNUM].addr = sigreg_ptr;
+ sigreg_ptr += word_size;
+
+ /* Then the GPRs. */
+ for (i = 0; i < 16; i++)
+ {
+ info->saved_regs[S390_R0_REGNUM + i].addr = sigreg_ptr;
+ sigreg_ptr += word_size;
+ }
+
+ /* Then the ACRs. */
+ for (i = 0; i < 16; i++)
+ {
+ info->saved_regs[S390_A0_REGNUM + i].addr = sigreg_ptr;
+ sigreg_ptr += 4;
+ }
+
+ /* The floating-point control word. */
+ info->saved_regs[S390_FPC_REGNUM].addr = sigreg_ptr;
+ sigreg_ptr += 8;
+
+ /* And finally the FPRs. */
+ for (i = 0; i < 16; i++)
+ {
+ info->saved_regs[S390_F0_REGNUM + i].addr = sigreg_ptr;
+ sigreg_ptr += 8;
+ }
+
+ /* Restore the previous frame's SP. */
+ prev_sp = read_memory_unsigned_integer (
+ info->saved_regs[S390_SP_REGNUM].addr,
+ word_size);
+
+ /* Determine our frame base. */
+ info->frame_base = prev_sp + 16*word_size + 32;
+
+ return info;
+}
+
+static void
+s390_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct s390_sigtramp_unwind_cache *info
+ = s390_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+ *this_id = frame_id_build (info->frame_base, frame_pc_unwind (next_frame));
+}
+
+static void
+s390_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct s390_sigtramp_unwind_cache *info
+ = s390_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+ trad_frame_prev_register (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
+}
+
+static const struct frame_unwind s390_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ s390_sigtramp_frame_this_id,
+ s390_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+s390_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ bfd_byte sigreturn[2];
+
+ if (read_memory_nobpt (pc, sigreturn, 2))
+ return NULL;
+
+ if (sigreturn[0] != 0x0a /* svc */)
+ return NULL;
+
+ if (sigreturn[1] != 119 /* sigreturn */
+ && sigreturn[1] != 173 /* rt_sigreturn */)
+ return NULL;
+
+ return &s390_sigtramp_frame_unwind;
+}
+
+
+/* Frame base handling. */
+
+static CORE_ADDR
+s390_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct s390_unwind_cache *info
+ = s390_frame_unwind_cache (next_frame, this_cache);
+ return info->frame_base;
+}
+
+static CORE_ADDR
+s390_local_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct s390_unwind_cache *info
+ = s390_frame_unwind_cache (next_frame, this_cache);
+ return info->local_base;
+}
+
+static const struct frame_base s390_frame_base = {
+ &s390_frame_unwind,
+ s390_frame_base_address,
+ s390_local_base_address,
+ s390_local_base_address
+};
+
+static CORE_ADDR
+s390_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ ULONGEST pc;
+ pc = frame_unwind_register_unsigned (next_frame, S390_PC_REGNUM);
+ return gdbarch_addr_bits_remove (gdbarch, pc);
+}
+
+static CORE_ADDR
+s390_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ ULONGEST sp;
+ sp = frame_unwind_register_unsigned (next_frame, S390_SP_REGNUM);
+ return gdbarch_addr_bits_remove (gdbarch, sp);
+}
+
+
+/* DWARF-2 frame support. */
+
+static void
+s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ switch (tdep->abi)
+ {
+ case ABI_LINUX_S390:
+ /* Call-saved registers. */
+ if ((regnum >= S390_R6_REGNUM && regnum <= S390_R15_REGNUM)
+ || regnum == S390_F4_REGNUM
+ || regnum == S390_F6_REGNUM)
+ reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+
+ /* Call-clobbered registers. */
+ else if ((regnum >= S390_R0_REGNUM && regnum <= S390_R5_REGNUM)
+ || (regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM
+ && regnum != S390_F4_REGNUM && regnum != S390_F6_REGNUM))
+ reg->how = DWARF2_FRAME_REG_UNDEFINED;
+
+ /* The return address column. */
+ else if (regnum == S390_PC_REGNUM)
+ reg->how = DWARF2_FRAME_REG_RA;
+ break;
+
+ case ABI_LINUX_ZSERIES:
+ /* Call-saved registers. */
+ if ((regnum >= S390_R6_REGNUM && regnum <= S390_R15_REGNUM)
+ || (regnum >= S390_F8_REGNUM && regnum <= S390_F15_REGNUM))
+ reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+
+ /* Call-clobbered registers. */
+ else if ((regnum >= S390_R0_REGNUM && regnum <= S390_R5_REGNUM)
+ || (regnum >= S390_F0_REGNUM && regnum <= S390_F7_REGNUM))
+ reg->how = DWARF2_FRAME_REG_UNDEFINED;
+
+ /* The return address column. */
+ else if (regnum == S390_PC_REGNUM)
+ reg->how = DWARF2_FRAME_REG_RA;
+ break;
+ }
+}
+
+
+/* Dummy function calls. */
+
+/* Return non-zero if TYPE is an integer-like type, zero otherwise.
+ "Integer-like" types are those that should be passed the way
+ integers are: integers, enums, ranges, characters, and booleans. */
+static int
+is_integer_like (struct type *type)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ return (code == TYPE_CODE_INT
+ || code == TYPE_CODE_ENUM
+ || code == TYPE_CODE_RANGE
+ || code == TYPE_CODE_CHAR
+ || code == TYPE_CODE_BOOL);
+}
+
+/* Return non-zero if TYPE is a pointer-like type, zero otherwise.
+ "Pointer-like" types are those that should be passed the way
+ pointers are: pointers and references. */
+static int
+is_pointer_like (struct type *type)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ return (code == TYPE_CODE_PTR
+ || code == TYPE_CODE_REF);
+}
+
+
+/* Return non-zero if TYPE is a `float singleton' or `double
+ singleton', zero otherwise.
+
+ A `T singleton' is a struct type with one member, whose type is
+ either T or a `T singleton'. So, the following are all float
+ singletons:
+
+ struct { float x };
+ struct { struct { float x; } x; };
+ struct { struct { struct { float x; } x; } x; };
+
+ ... and so on.
+
+ All such structures are passed as if they were floats or doubles,
+ as the (revised) ABI says. */
+static int
+is_float_singleton (struct type *type)
+{
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
+ {
+ struct type *singleton_type = TYPE_FIELD_TYPE (type, 0);
+ CHECK_TYPEDEF (singleton_type);
+
+ return (TYPE_CODE (singleton_type) == TYPE_CODE_FLT
+ || is_float_singleton (singleton_type));
+ }
+
+ return 0;
+}
+
+
+/* Return non-zero if TYPE is a struct-like type, zero otherwise.
+ "Struct-like" types are those that should be passed as structs are:
+ structs and unions.
+
+ As an odd quirk, not mentioned in the ABI, GCC passes float and
+ double singletons as if they were a plain float, double, etc. (The
+ corresponding union types are handled normally.) So we exclude
+ those types here. *shrug* */
+static int
+is_struct_like (struct type *type)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ return (code == TYPE_CODE_UNION
+ || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type)));
+}
+
+
+/* Return non-zero if TYPE is a float-like type, zero otherwise.
+ "Float-like" types are those that should be passed as
+ floating-point values are.
+
+ You'd think this would just be floats, doubles, long doubles, etc.
+ But as an odd quirk, not mentioned in the ABI, GCC passes float and
+ double singletons as if they were a plain float, double, etc. (The
+ corresponding union types are handled normally.) So we include
+ those types here. *shrug* */
+static int
+is_float_like (struct type *type)
+{
+ return (TYPE_CODE (type) == TYPE_CODE_FLT
+ || is_float_singleton (type));
+}
+
+
+static int
+is_power_of_two (unsigned int n)
+{
+ return ((n & (n - 1)) == 0);
+}
+
+/* Return non-zero if TYPE should be passed as a pointer to a copy,
+ zero otherwise. */
+static int
+s390_function_arg_pass_by_reference (struct type *type)
+{
+ unsigned length = TYPE_LENGTH (type);
+ if (length > 8)
+ return 1;
+
+ /* FIXME: All complex and vector types are also returned by reference. */
+ return is_struct_like (type) && !is_power_of_two (length);
+}
+
+/* Return non-zero if TYPE should be passed in a float register
+ if possible. */
+static int
+s390_function_arg_float (struct type *type)
+{
+ unsigned length = TYPE_LENGTH (type);
+ if (length > 8)
+ return 0;
+
+ return is_float_like (type);
+}
+
+/* Return non-zero if TYPE should be passed in an integer register
+ (or a pair of integer registers) if possible. */
+static int
+s390_function_arg_integer (struct type *type)
+{
+ unsigned length = TYPE_LENGTH (type);
+ if (length > 8)
+ return 0;
+
+ return is_integer_like (type)
+ || is_pointer_like (type)
+ || (is_struct_like (type) && is_power_of_two (length));
+}
+
+/* Return ARG, a `SIMPLE_ARG', sign-extended or zero-extended to a full
+ word as required for the ABI. */
+static LONGEST
+extend_simple_arg (struct value *arg)
+{
+ struct type *type = VALUE_TYPE (arg);
+
+ /* Even structs get passed in the least significant bits of the
+ register / memory word. It's not really right to extract them as
+ an integer, but it does take care of the extension. */
+ if (TYPE_UNSIGNED (type))
+ return extract_unsigned_integer (VALUE_CONTENTS (arg),
+ TYPE_LENGTH (type));
+ else
+ return extract_signed_integer (VALUE_CONTENTS (arg),
+ TYPE_LENGTH (type));
+}
+
+
+/* Return the alignment required by TYPE. */
+static int
+alignment_of (struct type *type)
+{
+ int alignment;
+
+ if (is_integer_like (type)
+ || is_pointer_like (type)
+ || TYPE_CODE (type) == TYPE_CODE_FLT)
+ alignment = TYPE_LENGTH (type);
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ int i;
+
+ alignment = 1;
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ int field_alignment = alignment_of (TYPE_FIELD_TYPE (type, i));
+
+ if (field_alignment > alignment)
+ alignment = field_alignment;
+ }
+ }
+ else
+ alignment = 1;
+
+ /* Check that everything we ever return is a power of two. Lots of
+ code doesn't want to deal with aligning things to arbitrary
+ boundaries. */
+ gdb_assert ((alignment & (alignment - 1)) == 0);
+
+ return alignment;
+}
+
+
+/* Put the actual parameter values pointed to by ARGS[0..NARGS-1] in
+ place to be passed to a function, as specified by the "GNU/Linux
+ for S/390 ELF Application Binary Interface Supplement".
+
+ SP is the current stack pointer. We must put arguments, links,
+ padding, etc. whereever they belong, and return the new stack
+ pointer value.
+
+ If STRUCT_RETURN is non-zero, then the function we're calling is
+ going to return a structure by value; STRUCT_ADDR is the address of
+ a block we've allocated for it on the stack.
+
+ Our caller has taken care of any type promotions needed to satisfy
+ prototypes or the old K&R argument-passing rules. */
+static CORE_ADDR
+s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+ ULONGEST orig_sp;
+ int i;
+
+ /* If the i'th argument is passed as a reference to a copy, then
+ copy_addr[i] is the address of the copy we made. */
+ CORE_ADDR *copy_addr = alloca (nargs * sizeof (CORE_ADDR));
+
+ /* Build the reference-to-copy area. */
+ for (i = 0; i < nargs; i++)
+ {
+ struct value *arg = args[i];
+ struct type *type = VALUE_TYPE (arg);
+ unsigned length = TYPE_LENGTH (type);
+
+ if (s390_function_arg_pass_by_reference (type))
+ {
+ sp -= length;
+ sp = align_down (sp, alignment_of (type));
+ write_memory (sp, VALUE_CONTENTS (arg), length);
+ copy_addr[i] = sp;
+ }
+ }
+
+ /* Reserve space for the parameter area. As a conservative
+ simplification, we assume that everything will be passed on the
+ stack. Since every argument larger than 8 bytes will be
+ passed by reference, we use this simple upper bound. */
+ sp -= nargs * 8;
+
+ /* After all that, make sure it's still aligned on an eight-byte
+ boundary. */
+ sp = align_down (sp, 8);
+
+ /* Finally, place the actual parameters, working from SP towards
+ higher addresses. The code above is supposed to reserve enough
+ space for this. */
+ {
+ int fr = 0;
+ int gr = 2;
+ CORE_ADDR starg = sp;
+
+ /* A struct is returned using general register 2. */
+ if (struct_return)
+ {
+ regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
+ struct_addr);
+ gr++;
+ }
+
+ for (i = 0; i < nargs; i++)
+ {
+ struct value *arg = args[i];
+ struct type *type = VALUE_TYPE (arg);
+ unsigned length = TYPE_LENGTH (type);
+
+ if (s390_function_arg_pass_by_reference (type))
+ {
+ if (gr <= 6)
+ {
+ regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
+ copy_addr[i]);
+ gr++;
+ }
+ else
+ {
+ write_memory_unsigned_integer (starg, word_size, copy_addr[i]);
+ starg += word_size;
+ }
+ }
+ else if (s390_function_arg_float (type))
+ {
+ /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass arguments,
+ the GNU/Linux for zSeries ABI uses 0, 2, 4, and 6. */
+ if (fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
+ {
+ /* When we store a single-precision value in an FP register,
+ it occupies the leftmost bits. */
+ regcache_cooked_write_part (regcache, S390_F0_REGNUM + fr,
+ 0, length, VALUE_CONTENTS (arg));
+ fr += 2;
+ }
+ else
+ {
+ /* When we store a single-precision value in a stack slot,
+ it occupies the rightmost bits. */
+ starg = align_up (starg + length, word_size);
+ write_memory (starg - length, VALUE_CONTENTS (arg), length);
+ }
+ }
+ else if (s390_function_arg_integer (type) && length <= word_size)
+ {
+ if (gr <= 6)
+ {
+ /* Integer arguments are always extended to word size. */
+ regcache_cooked_write_signed (regcache, S390_R0_REGNUM + gr,
+ extend_simple_arg (arg));
+ gr++;
+ }
+ else
+ {
+ /* Integer arguments are always extended to word size. */
+ write_memory_signed_integer (starg, word_size,
+ extend_simple_arg (arg));
+ starg += word_size;
+ }
+ }
+ else if (s390_function_arg_integer (type) && length == 2*word_size)
+ {
+ if (gr <= 5)
+ {
+ regcache_cooked_write (regcache, S390_R0_REGNUM + gr,
+ VALUE_CONTENTS (arg));
+ regcache_cooked_write (regcache, S390_R0_REGNUM + gr + 1,
+ VALUE_CONTENTS (arg) + word_size);
+ gr += 2;
+ }
+ else
+ {
+ /* If we skipped r6 because we couldn't fit a DOUBLE_ARG
+ in it, then don't go back and use it again later. */
+ gr = 7;
+
+ write_memory (starg, VALUE_CONTENTS (arg), length);
+ starg += length;
+ }
+ }
+ else
+ internal_error (__FILE__, __LINE__, "unknown argument type");
+ }
+ }
+
+ /* Allocate the standard frame areas: the register save area, the
+ word reserved for the compiler (which seems kind of meaningless),
+ and the back chain pointer. */
+ sp -= 16*word_size + 32;
+
+ /* Write the back chain pointer into the first word of the stack
+ frame. This is needed to unwind across a dummy frame. */
+ regcache_cooked_read_unsigned (regcache, S390_SP_REGNUM, &orig_sp);
+ write_memory_unsigned_integer (sp, word_size, orig_sp);
+
+ /* Store return address. */
+ regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr);
+
+ /* Store updated stack pointer. */
+ regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, sp);
+
+ /* We need to return the 'stack part' of the frame ID,
+ which is actually the top of the register save area
+ allocated on the original stack. */
+ return orig_sp + 16*word_size + 32;
+}
+
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+ dummy frame. The frame ID's base needs to match the TOS value
+ returned by push_dummy_call, and the PC match the dummy frame's
+ breakpoint. */
+static struct frame_id
+s390_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+ CORE_ADDR this_sp = s390_unwind_sp (gdbarch, next_frame);
+ CORE_ADDR prev_sp = read_memory_unsigned_integer (this_sp, word_size);
+
+ return frame_id_build (prev_sp + 16*word_size + 32,
+ frame_pc_unwind (next_frame));
+}
+
+static CORE_ADDR
+s390_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ /* Both the 32- and 64-bit ABI's say that the stack pointer should
+ always be aligned on an eight-byte boundary. */
+ return (addr & -8);
+}
+
+
+/* Function return value access. */
+
+static enum return_value_convention
+s390_return_value_convention (struct gdbarch *gdbarch, struct type *type)
+{
+ int length = TYPE_LENGTH (type);
+ if (length > 8)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ARRAY:
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ default:
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+}
+
+static enum return_value_convention
+s390_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, void *out, const void *in)
+{
+ int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+ int length = TYPE_LENGTH (type);
+ enum return_value_convention rvc =
+ s390_return_value_convention (gdbarch, type);
+ if (in)
+ {
+ switch (rvc)
+ {
+ case RETURN_VALUE_REGISTER_CONVENTION:
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ /* When we store a single-precision value in an FP register,
+ it occupies the leftmost bits. */
+ regcache_cooked_write_part (regcache, S390_F0_REGNUM,
+ 0, length, in);
+ }
+ else if (length <= word_size)
+ {
+ /* Integer arguments are always extended to word size. */
+ if (TYPE_UNSIGNED (type))
+ regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM,
+ extract_unsigned_integer (in, length));
+ else
+ regcache_cooked_write_signed (regcache, S390_R2_REGNUM,
+ extract_signed_integer (in, length));
+ }
+ else if (length == 2*word_size)
+ {
+ regcache_cooked_write (regcache, S390_R2_REGNUM, in);
+ regcache_cooked_write (regcache, S390_R3_REGNUM,
+ (const char *)in + word_size);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "invalid return type");
+ break;
+
+ case RETURN_VALUE_STRUCT_CONVENTION:
+ error ("Cannot set function return value.");
+ break;
+ }
+ }
+ else if (out)
+ {
+ switch (rvc)
+ {
+ case RETURN_VALUE_REGISTER_CONVENTION:
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ /* When we store a single-precision value in an FP register,
+ it occupies the leftmost bits. */
+ regcache_cooked_read_part (regcache, S390_F0_REGNUM,
+ 0, length, out);
+ }
+ else if (length <= word_size)
+ {
+ /* Integer arguments occupy the rightmost bits. */
+ regcache_cooked_read_part (regcache, S390_R2_REGNUM,
+ word_size - length, length, out);
+ }
+ else if (length == 2*word_size)
+ {
+ regcache_cooked_read (regcache, S390_R2_REGNUM, out);
+ regcache_cooked_read (regcache, S390_R3_REGNUM,
+ (char *)out + word_size);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "invalid return type");
+ break;
+
+ case RETURN_VALUE_STRUCT_CONVENTION:
+ error ("Function return value unknown.");
+ break;
+ }
+ }
+
+ return rvc;
+}
+
+
+/* Breakpoints. */
+
+static const unsigned char *
+s390_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ static unsigned char breakpoint[] = { 0x0, 0x1 };
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+
+/* Address handling. */
+
+static CORE_ADDR
+s390_addr_bits_remove (CORE_ADDR addr)
+{
+ return addr & 0x7fffffff;
+}
+
+static int
+s390_address_class_type_flags (int byte_size, int dwarf2_addr_class)
+{
+ if (byte_size == 4)
+ return TYPE_FLAG_ADDRESS_CLASS_1;
+ else
+ return 0;
+}
+
+static const char *
+s390_address_class_type_flags_to_name (struct gdbarch *gdbarch, int type_flags)
+{
+ if (type_flags & TYPE_FLAG_ADDRESS_CLASS_1)
+ return "mode32";
+ else
+ return NULL;
+}
+
+static int
+s390_address_class_name_to_type_flags (struct gdbarch *gdbarch, const char *name,
+ int *type_flags_ptr)
+{
+ if (strcmp (name, "mode32") == 0)
+ {
+ *type_flags_ptr = TYPE_FLAG_ADDRESS_CLASS_1;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+/* Link map offsets. */
+
+static struct link_map_offsets *
+s390_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 8;
+
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 20;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+static struct link_map_offsets *
+s390x_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 16; /* All we need. */
+
+ lmo.r_map_offset = 8;
+ lmo.r_map_size = 8;
+
+ lmo.link_map_size = 40; /* All we need. */
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 8;
+
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 8;
+
+ lmo.l_next_offset = 24;
+ lmo.l_next_size = 8;
+
+ lmo.l_prev_offset = 32;
+ lmo.l_prev_size = 8;
+ }
+
+ return lmp;
+}
+
+
+/* Set up gdbarch struct. */
+
+static struct gdbarch *
+s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+
+ /* First see if there is already a gdbarch that can satisfy the request. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ /* None found: is the request for a s390 architecture? */
+ if (info.bfd_arch_info->arch != bfd_arch_s390)
+ return NULL; /* No; then it's not for us. */
+
+ /* Yes: create a new gdbarch for the specified machine type. */
+ tdep = XCALLOC (1, struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ set_gdbarch_believe_pcc_promotion (gdbarch, 0);
+ set_gdbarch_char_signed (gdbarch, 0);
+
+ /* Amount PC must be decremented by after a breakpoint. This is
+ often the number of bytes returned by BREAKPOINT_FROM_PC but not
+ always. */
+ set_gdbarch_decr_pc_after_break (gdbarch, 2);
+ /* Stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_breakpoint_from_pc (gdbarch, s390_breakpoint_from_pc);
+ set_gdbarch_skip_prologue (gdbarch, s390_skip_prologue);
+ set_gdbarch_in_function_epilogue_p (gdbarch, s390_in_function_epilogue_p);
+
+ set_gdbarch_pc_regnum (gdbarch, S390_PC_REGNUM);
+ set_gdbarch_sp_regnum (gdbarch, S390_SP_REGNUM);
+ set_gdbarch_fp0_regnum (gdbarch, S390_F0_REGNUM);
+ set_gdbarch_num_regs (gdbarch, S390_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, S390_NUM_PSEUDO_REGS);
+ set_gdbarch_register_name (gdbarch, s390_register_name);
+ set_gdbarch_register_type (gdbarch, s390_register_type);
+ set_gdbarch_stab_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
+ set_gdbarch_convert_register_p (gdbarch, s390_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, s390_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, s390_value_to_register);
+ set_gdbarch_register_reggroup_p (gdbarch, s390_register_reggroup_p);
+ set_gdbarch_regset_from_core_section (gdbarch,
+ s390_regset_from_core_section);
+
+ /* Inferior function calls. */
+ set_gdbarch_push_dummy_call (gdbarch, s390_push_dummy_call);
+ set_gdbarch_unwind_dummy_id (gdbarch, s390_unwind_dummy_id);
+ set_gdbarch_frame_align (gdbarch, s390_frame_align);
+ set_gdbarch_return_value (gdbarch, s390_return_value);
+
+ /* Frame handling. */
+ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
+ dwarf2_frame_set_init_reg (gdbarch, s390_dwarf2_frame_init_reg);
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+ frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+ frame_unwind_append_sniffer (gdbarch, s390_stub_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, s390_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, s390_frame_sniffer);
+ frame_base_set_default (gdbarch, &s390_frame_base);
+ set_gdbarch_unwind_pc (gdbarch, s390_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, s390_unwind_sp);
+
+ switch (info.bfd_arch_info->mach)
+ {
+ case bfd_mach_s390_31:
+ tdep->abi = ABI_LINUX_S390;
+
+ tdep->gregset = &s390_gregset;
+ tdep->sizeof_gregset = s390_sizeof_gregset;
+ tdep->fpregset = &s390_fpregset;
+ tdep->sizeof_fpregset = s390_sizeof_fpregset;
+
+ set_gdbarch_addr_bits_remove (gdbarch, s390_addr_bits_remove);
+ set_gdbarch_pseudo_register_read (gdbarch, s390_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, s390_pseudo_register_write);
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ s390_svr4_fetch_link_map_offsets);
+
+ break;
+ case bfd_mach_s390_64:
+ tdep->abi = ABI_LINUX_ZSERIES;
+
+ tdep->gregset = &s390x_gregset;
+ tdep->sizeof_gregset = s390x_sizeof_gregset;
+ tdep->fpregset = &s390_fpregset;
+ tdep->sizeof_fpregset = s390_sizeof_fpregset;
+
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_pseudo_register_read (gdbarch, s390x_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, s390x_pseudo_register_write);
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ s390x_svr4_fetch_link_map_offsets);
+ set_gdbarch_address_class_type_flags (gdbarch,
+ s390_address_class_type_flags);
+ set_gdbarch_address_class_type_flags_to_name (gdbarch,
+ s390_address_class_type_flags_to_name);
+ set_gdbarch_address_class_name_to_type_flags (gdbarch,
+ s390_address_class_name_to_type_flags);
+ break;
+ }
+
+ set_gdbarch_print_insn (gdbarch, print_insn_s390);
+
+ return gdbarch;
+}
+
+
+
+extern initialize_file_ftype _initialize_s390_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_s390_tdep (void)
+{
+
+ /* Hook us into the gdbarch mechanism. */
+ register_gdbarch_init (bfd_arch_s390, s390_gdbarch_init);
+}
diff --git a/contrib/gdb/gdb/s390-tdep.h b/contrib/gdb/gdb/s390-tdep.h
new file mode 100644
index 0000000..241c1fe
--- /dev/null
+++ b/contrib/gdb/gdb/s390-tdep.h
@@ -0,0 +1,105 @@
+/* Target-dependent code for GDB, the GNU debugger.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 S390_TDEP_H
+#define S390_TDEP_H
+
+/* Register information. */
+
+/* Program Status Word. */
+#define S390_PSWM_REGNUM 0
+#define S390_PSWA_REGNUM 1
+/* General Purpose Registers. */
+#define S390_R0_REGNUM 2
+#define S390_R1_REGNUM 3
+#define S390_R2_REGNUM 4
+#define S390_R3_REGNUM 5
+#define S390_R4_REGNUM 6
+#define S390_R5_REGNUM 7
+#define S390_R6_REGNUM 8
+#define S390_R7_REGNUM 9
+#define S390_R8_REGNUM 10
+#define S390_R9_REGNUM 11
+#define S390_R10_REGNUM 12
+#define S390_R11_REGNUM 13
+#define S390_R12_REGNUM 14
+#define S390_R13_REGNUM 15
+#define S390_R14_REGNUM 16
+#define S390_R15_REGNUM 17
+/* Access Registers. */
+#define S390_A0_REGNUM 18
+#define S390_A1_REGNUM 19
+#define S390_A2_REGNUM 20
+#define S390_A3_REGNUM 21
+#define S390_A4_REGNUM 22
+#define S390_A5_REGNUM 23
+#define S390_A6_REGNUM 24
+#define S390_A7_REGNUM 25
+#define S390_A8_REGNUM 26
+#define S390_A9_REGNUM 27
+#define S390_A10_REGNUM 28
+#define S390_A11_REGNUM 29
+#define S390_A12_REGNUM 30
+#define S390_A13_REGNUM 31
+#define S390_A14_REGNUM 32
+#define S390_A15_REGNUM 33
+/* Floating Point Control Word. */
+#define S390_FPC_REGNUM 34
+/* Floating Point Registers. */
+#define S390_F0_REGNUM 35
+#define S390_F1_REGNUM 36
+#define S390_F2_REGNUM 37
+#define S390_F3_REGNUM 38
+#define S390_F4_REGNUM 39
+#define S390_F5_REGNUM 40
+#define S390_F6_REGNUM 41
+#define S390_F7_REGNUM 42
+#define S390_F8_REGNUM 43
+#define S390_F9_REGNUM 44
+#define S390_F10_REGNUM 45
+#define S390_F11_REGNUM 46
+#define S390_F12_REGNUM 47
+#define S390_F13_REGNUM 48
+#define S390_F14_REGNUM 49
+#define S390_F15_REGNUM 50
+/* Total. */
+#define S390_NUM_REGS 51
+
+/* Pseudo registers -- PC and condition code. */
+#define S390_PC_REGNUM S390_NUM_REGS
+#define S390_CC_REGNUM (S390_NUM_REGS+1)
+#define S390_NUM_PSEUDO_REGS 2
+#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2)
+
+/* Special register usage. */
+#define S390_SP_REGNUM S390_R15_REGNUM
+#define S390_RETADDR_REGNUM S390_R14_REGNUM
+#define S390_FRAME_REGNUM S390_R11_REGNUM
+
+/* Core file register sets, defined in s390-tdep.c. */
+#define s390_sizeof_gregset 0x90
+extern int s390_regmap_gregset[S390_NUM_REGS];
+#define s390x_sizeof_gregset 0xd8
+extern int s390x_regmap_gregset[S390_NUM_REGS];
+#define s390_sizeof_fpregset 0x88
+extern int s390_regmap_fpregset[S390_NUM_REGS];
+
+#endif
+
diff --git a/contrib/gdb/gdb/scm-exp.c b/contrib/gdb/gdb/scm-exp.c
new file mode 100644
index 0000000..41d78af
--- /dev/null
+++ b/contrib/gdb/gdb/scm-exp.c
@@ -0,0 +1,496 @@
+/* Scheme/Guile language support routines for GDB, the GNU debugger.
+
+ Copyright 1995, 1996, 2000, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_lreadparen (int);
+static int scm_skip_ws (void);
+static void scm_read_token (int, int);
+static LONGEST scm_istring2number (char *, int, int);
+static LONGEST scm_istr2int (char *, int, int);
+static void scm_lreadr (int);
+
+static LONGEST
+scm_istr2int (char *str, int len, int radix)
+{
+ 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);
+}
+
+static LONGEST
+scm_istring2number (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 */
+#if 0
+ SCM res;
+#endif
+ 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 (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 (void)
+{
+ 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 (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 (int skipping)
+{
+ int c, j;
+ struct stoken str;
+ LONGEST svalue = 0;
+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)
+ {
+ struct value *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:
+#if 0
+ callshrp:
+#endif
+ 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;
+#if 0
+ do_symbol:
+#endif
+ 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 (void)
+{
+ char *start;
+ 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 0000000..872dcaf
--- /dev/null
+++ b/contrib/gdb/gdb/scm-lang.c
@@ -0,0 +1,287 @@
+/* Scheme/Guile language support routines for GDB, the GNU debugger.
+
+ Copyright 1995, 1996, 1998, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "source.h"
+#include "gdb_string.h"
+#include "gdbcore.h"
+#include "infcall.h"
+
+extern void _initialize_scheme_language (void);
+static struct value *evaluate_subexp_scm (struct type *, struct expression *,
+ int *, enum noside);
+static struct value *scm_lookup_name (char *);
+static int in_eval_c (void);
+static void scm_printstr (struct ui_file * stream, char *string,
+ unsigned int length, int width,
+ int force_ellipses);
+
+extern struct type **const (c_builtin_types[]);
+
+struct type *builtin_type_scm;
+
+void
+scm_printchar (int c, struct ui_file *stream)
+{
+ fprintf_filtered (stream, "#\\%c", c);
+}
+
+static void
+scm_printstr (struct ui_file *stream, char *string, unsigned int length,
+ int width, int force_ellipses)
+{
+ fprintf_filtered (stream, "\"%s\"", string);
+}
+
+int
+is_scmvalue_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 (LONGEST svalue, int index)
+{
+ 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 (struct type *type, const 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 & (int) 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 ((int) 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 (void)
+{
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+ if (cursal.symtab && cursal.symtab->filename)
+ {
+ char *filename = cursal.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. */
+
+static struct value *
+scm_lookup_name (char *str)
+{
+ struct value *args[3];
+ int len = strlen (str);
+ struct value *func;
+ struct value *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_DOMAIN, (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_DOMAIN, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym)
+ return value_of_variable (sym, NULL);
+ error ("No symbol \"%s\" in current context.", str);
+}
+
+struct value *
+scm_evaluate_string (char *str, int len)
+{
+ struct value *func;
+ struct value *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 struct value *
+evaluate_subexp_scm (struct type *expect_type, struct expression *exp,
+ 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 exp_descriptor exp_descriptor_scm =
+{
+ print_subexp_standard,
+ operator_length_standard,
+ op_name_standard,
+ dump_subexp_body_standard,
+ evaluate_subexp_scm
+};
+
+const struct language_defn scm_language_defn =
+{
+ "scheme", /* Language name */
+ language_scm,
+ c_builtin_types,
+ range_check_off,
+ type_check_off,
+ case_sensitive_off,
+ &exp_descriptor_scm,
+ scm_parse,
+ c_error,
+ scm_printchar, /* Print a character constant */
+ scm_printstr, /* Function to print string constant */
+ NULL, /* Function to print a single character */
+ 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 */
+ NULL, /* Language specific skip_trampoline */
+ value_of_this, /* value_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ {"", "", "", ""}, /* 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 */
+ default_word_break_characters,
+ LANG_MAGIC
+};
+
+void
+_initialize_scheme_language (void)
+{
+ 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 0000000..6e24be5
--- /dev/null
+++ b/contrib/gdb/gdb/scm-lang.h
@@ -0,0 +1,72 @@
+/* Scheme/Guile language support routines for GDB, the GNU debugger.
+
+ Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 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)
+
+/* Forward decls for prototypes */
+struct value;
+
+extern int scm_value_print (struct value *, struct ui_file *,
+ int, enum val_prettyprint);
+
+extern int scm_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+extern LONGEST scm_get_field (LONGEST, int);
+
+extern void scm_scmval_print (LONGEST, struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+extern int is_scmvalue_type (struct type *);
+
+extern void scm_printchar (int, struct ui_file *);
+
+extern struct value *scm_evaluate_string (char *, int);
+
+extern struct type *builtin_type_scm;
+
+extern int scm_parse (void);
+
+extern LONGEST scm_unpack (struct type *, const 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 0000000..4fa5ce2
--- /dev/null
+++ b/contrib/gdb/gdb/scm-tags.h
@@ -0,0 +1,379 @@
+/* This is a minimally edited version of Guile's tags.h. */
+/* classes: h_files */
+
+#ifndef TAGSH
+#define TAGSH
+/* Copyright 1995, 1999 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.
+ *
+ * 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 */
+
+
+#endif /* TAGSH */
diff --git a/contrib/gdb/gdb/scm-valprint.c b/contrib/gdb/gdb/scm-valprint.c
new file mode 100644
index 0000000..737bafa
--- /dev/null
+++ b/contrib/gdb/gdb/scm-valprint.c
@@ -0,0 +1,395 @@
+/* Scheme/Guile language support routines for GDB, the GNU debugger.
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+#include "gdbcore.h"
+
+/* FIXME: Should be in a header file that we import. */
+extern int c_val_print (struct type *, char *, int, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint);
+
+static void scm_ipruk (char *, LONGEST, struct ui_file *);
+static void scm_scmlist_print (LONGEST, struct ui_file *, int, int,
+ int, enum val_prettyprint);
+static int scm_inferior_print (LONGEST, struct ui_file *, int, int,
+ int, enum val_prettyprint);
+
+/* 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. */
+
+static int
+scm_inferior_print (LONGEST value, struct ui_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",
+ "#<undefined>",
+ "#<eof>",
+ "()",
+ "#<unspecified>"
+};
+
+static void
+scm_scmlist_print (LONGEST svalue, struct ui_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;
+ }
+ 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 (char *hdr, LONGEST ptr, struct ui_file *stream)
+{
+ fprintf_filtered (stream, "#<unknown-%s", hdr);
+#define SCM_SIZE TYPE_LENGTH (builtin_type_scm)
+ if (SCM_CELLP (ptr))
+ fprintf_filtered (stream, " (0x%lx . 0x%lx) @",
+ (long) SCM_CAR (ptr), (long) SCM_CDR (ptr));
+ fprintf_filtered (stream, " 0x%s>", paddr_nz (ptr));
+}
+
+void
+scm_scmval_print (LONGEST svalue, struct ui_file *stream, int format,
+ int deref_ref, int recurse, enum val_prettyprint pretty)
+{
+taloop:
+ switch (7 & (int) 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)
+ {
+#if 0
+ SCM name;
+#endif
+ fputs_filtered ("#<latte ", stream);
+#if 1
+ fputs_filtered ("???", stream);
+#else
+ name = ((SCM n *) (STRUCT_TYPE (exp)))[struct_i_name];
+ scm_lfwrite (CHARS (name),
+ (sizet) sizeof (char),
+ (sizet) LENGTH (name),
+ port);
+#endif
+ fprintf_filtered (stream, " #X%s>", paddr_nz (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 ("#<CLOSURE ", stream);
+ scm_scmlist_print (SCM_CODE (svalue), stream, format,
+ deref_ref, recurse + 1, pretty);
+ 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 ("#<locked-vector ", port);
+ scm_intprint (CDR (exp), 16, port);
+ 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, "#<primitive-procedure %s>",
+ str);
+ }
+ break;
+#if 0
+#ifdef CCLO
+ case tc7_cclo:
+ scm_puts ("#<compiled-closure ", port);
+ scm_iprin1 (CCLO_SUBR (exp), port, writing);
+ scm_putc ('>', port);
+ break;
+#endif
+ case tc7_contin:
+ fprintf_filtered (stream, "#<continuation %d @ #X%lx >",
+ 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:
+#if 0
+ punk:
+#endif
+ scm_ipruk ("type", svalue, stream);
+ }
+ break;
+ }
+}
+
+int
+scm_val_print (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_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, 0, address, stream, format,
+ deref_ref, recurse, pretty);
+ }
+}
+
+int
+scm_value_print (struct value *val, struct ui_file *stream, int format,
+ enum val_prettyprint pretty)
+{
+ return (val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
+ VALUE_ADDRESS (val), stream, format, 1, 0, pretty));
+}
diff --git a/contrib/gdb/gdb/sentinel-frame.c b/contrib/gdb/gdb/sentinel-frame.c
new file mode 100644
index 0000000..94c1ee3
--- /dev/null
+++ b/contrib/gdb/gdb/sentinel-frame.c
@@ -0,0 +1,92 @@
+/* Code dealing with register stack frames, for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include "sentinel-frame.h"
+#include "inferior.h"
+#include "frame-unwind.h"
+
+struct frame_unwind_cache
+{
+ struct regcache *regcache;
+};
+
+void *
+sentinel_frame_cache (struct regcache *regcache)
+{
+ struct frame_unwind_cache *cache =
+ FRAME_OBSTACK_ZALLOC (struct frame_unwind_cache);
+ cache->regcache = regcache;
+ return cache;
+}
+
+/* Here the register value is taken direct from the register cache. */
+
+static void
+sentinel_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimized,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnum, void *bufferp)
+{
+ struct frame_unwind_cache *cache = *this_prologue_cache;
+ /* Describe the register's location. A reg-frame maps all registers
+ onto the corresponding hardware register. */
+ *optimized = 0;
+ *lvalp = lval_register;
+ *addrp = register_offset_hack (current_gdbarch, regnum);
+ *realnum = regnum;
+
+ /* If needed, find and return the value of the register. */
+ if (bufferp != NULL)
+ {
+ /* Return the actual value. */
+ /* Use the regcache_cooked_read() method so that it, on the fly,
+ constructs either a raw or pseudo register from the raw
+ register cache. */
+ regcache_cooked_read (cache->regcache, regnum, bufferp);
+ }
+}
+
+static void
+sentinel_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ /* The sentinel frame is used as a starting point for creating the
+ previous (inner most) frame. That frame's THIS_ID method will be
+ called to determine the inner most frame's ID. Not this one. */
+ internal_error (__FILE__, __LINE__, "sentinel_frame_this_id called");
+}
+
+const struct frame_unwind sentinel_frame_unwinder =
+{
+ /* Should the sentinel frame be given a special type? */
+ NORMAL_FRAME,
+ sentinel_frame_this_id,
+ sentinel_frame_prev_register
+};
+
+const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
diff --git a/contrib/gdb/gdb/sentinel-frame.h b/contrib/gdb/gdb/sentinel-frame.h
new file mode 100644
index 0000000..9b69f42
--- /dev/null
+++ b/contrib/gdb/gdb/sentinel-frame.h
@@ -0,0 +1,41 @@
+/* Code dealing with register stack frames, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (SENTINEL_FRAME_H)
+#define SENTINEL_FRAME_H 1
+
+struct frame_unwind;
+struct regcache;
+
+/* Implement the sentinel frame. The sentinel frame terminates the
+ inner most end of the frame chain. If unwound, it returns the
+ information need to construct an inner-most frame. */
+
+/* Pump prime the sentinel frame's cache. Since this needs the
+ REGCACHE provide that here. */
+
+extern void *sentinel_frame_cache (struct regcache *regcache);
+
+/* At present there is only one type of sentinel frame. */
+
+extern const struct frame_unwind *const sentinel_frame_unwind;
+
+#endif /* !defined (SENTINEL_FRAME_H) */
diff --git a/contrib/gdb/gdb/ser-e7kpc.c b/contrib/gdb/gdb/ser-e7kpc.c
new file mode 100644
index 0000000..1efe142
--- /dev/null
+++ b/contrib/gdb/gdb/ser-e7kpc.c
@@ -0,0 +1,436 @@
+/* Remote serial interface using Renesas E7000 PC ISA card in a PC
+ Copyright 1994, 1996, 1997, 1998, 1999, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+#include "serial.h"
+#include "gdb_string.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#ifdef __GO32__
+#include <sys/dos.h>
+#endif
+
+static int e7000pc_open (struct serial *scb, const char *name);
+static void e7000pc_raw (struct serial *scb);
+static int e7000pc_readchar (struct serial *scb, int timeout);
+static int e7000pc_setbaudrate (struct serial *scb, int rate);
+static int e7000pc_write (struct serial *scb, const char *str, int len);
+static void e7000pc_close (struct serial *scb);
+static serial_ttystate e7000pc_get_tty_state (struct serial *scb);
+static int e7000pc_set_tty_state (struct serial *scb, serial_ttystate state);
+
+#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;
+
+#ifdef __GO32__
+
+#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;
+
+#else /* win32 */
+
+#define SET_BYTE(x,y) *(volatile unsigned char *)(x) = (y)
+#define SET_WORD(x,y) *(volatile unsigned short *)(x) = (y)
+#define GET_BYTE(x) (*(volatile unsigned char *)(x))
+#define GET_WORD(x) (*(volatile unsigned short *)(x))
+#define dosmemget(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
+#define dosmemput(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
+#endif
+
+static struct sw
+ {
+ int sw;
+ int addr;
+ }
+sigs[] =
+{
+ {
+ 0x14, 0xd0000
+ }
+ ,
+ {
+ 0x15, 0xd4000
+ }
+ ,
+ {
+ 0x16, 0xd8000
+ }
+ ,
+ {
+ 0x17, 0xdc000
+ }
+ ,
+ 0
+};
+
+#define get_ds_base() 0
+
+static int
+e7000pc_init (void)
+{
+ int try;
+ unsigned long dsbase;
+
+ dsbase = get_ds_base ();
+
+ /* Look around in memory for the board's signature */
+
+ for (try = 0; sigs[try].sw; try++)
+ {
+ int val;
+ board_at = sigs[try].addr - dsbase;
+ 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_WORD (pon) & 0xf)
+ {
+ SET_WORD (fa, 0);
+ SET_WORD (fb, 0);
+
+ SET_WORD (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;
+
+/* Return next byte from cdp. If no more, then return -1. */
+
+static int
+e7000_get (void)
+{
+ static char pbuf[1000];
+ char tmp[1000];
+ int x;
+
+ if (pbuf_index < pbuf_size)
+ {
+ x = pbuf[pbuf_index++];
+ }
+ else if ((GET_WORD (fb) & 1))
+ {
+ int i;
+ pbuf_size = GET_WORD (cdp + 2);
+
+ dosmemget (cdp + 8, pbuf_size + 1, tmp);
+
+ /* Tell the E7000 we've eaten */
+ SET_WORD (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;
+}
+
+/* Works just like read(), except that it takes a TIMEOUT in seconds. Note
+ that TIMEOUT == 0 is a poll, and TIMEOUT == -1 means wait forever. */
+
+static int
+dosasync_read (int fd, char *buf, int len, int timeout)
+{
+ long now;
+ long then;
+ int i = 0;
+
+ /* 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 (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_WORD (fa) & 1);
+
+ /* Blast onto the ISA card */
+ dosmemput (dummy, 8 + len + 1, cpd);
+
+ SET_WORD (fa, 1);
+ SET_WORD (irqtod, 1); /* Interrupt the E7000 */
+
+ return len;
+}
+
+static int
+e7000pc_open (struct serial *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 (struct serial *scb)
+{
+ return 0;
+}
+
+static void
+e7000pc_raw (struct serial *scb)
+{
+ /* Always in raw mode */
+}
+
+static int
+e7000pc_readchar (struct serial *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 (struct serial *scb)
+{
+ struct e7000pc_ttystate *state;
+
+ state = (struct e7000pc_ttystate *) xmalloc (sizeof *state);
+
+ return (serial_ttystate) state;
+}
+
+static int
+e7000pc_set_tty_state (struct serial *scb, serial_ttystate ttystate)
+{
+ return 0;
+}
+
+static int
+e7000pc_noflush_set_tty_state (struct serial *scb,
+ serial_ttystate new_ttystate,
+ serial_ttystate old_ttystate)
+{
+ return 0;
+}
+
+static void
+e7000pc_print_tty_state (struct serial *scb,
+ serial_ttystate ttystate,
+ struct ui_file *stream)
+{
+ /* Nothing to print. */
+ return;
+}
+
+static int
+e7000pc_setbaudrate (struct serial *scb, int rate)
+{
+ return 0;
+}
+
+static int
+e7000pc_setstopbits (struct serial *scb, int rate)
+{
+ return 0;
+}
+
+static int
+e7000pc_write (struct serial *scb, const char *str, int len)
+{
+ dosasync_write (scb->fd, str, len);
+
+ return 0;
+}
+
+static void
+e7000pc_close (struct serial *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,
+ e7000pc_setstopbits,
+ e7000pc_noop, /* wait for output to drain */
+};
+
+#endif /*_WIN32 or __GO32__*/
+
+extern initialize_file_ftype _initialize_ser_e7000pc; /* -Wmissing-prototypes */
+
+void
+_initialize_ser_e7000pc (void)
+{
+#if defined __GO32__ || defined _WIN32
+ serial_add_interface (&e7000pc_ops);
+#endif
+}
diff --git a/contrib/gdb/gdb/ser-go32.c b/contrib/gdb/gdb/ser-go32.c
new file mode 100644
index 0000000..cea01cd
--- /dev/null
+++ b/contrib/gdb/gdb/ser-go32.c
@@ -0,0 +1,964 @@
+/* Remote serial interface for local (hardwired) serial ports for GO32.
+ Copyright 1992, 1993, 2000, 2001 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"
+#include "gdb_string.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 <time.h>
+#include <dos.h>
+#include <go32.h>
+#include <dpmi.h>
+typedef unsigned long u_long;
+
+/* 16550 rx fifo trigger point */
+#define FIFO_TRIGGER FIFO_TRIGGER_4
+
+/* input buffer size */
+#define CBSIZE 4096
+
+#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, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ ,
+ {
+ COM2ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ ,
+ {
+ COM3ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ ,
+ {
+ COM4ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+};
+
+static int dos_open (struct serial *scb, const char *name);
+static void dos_raw (struct serial *scb);
+static int dos_readchar (struct serial *scb, int timeout);
+static int dos_setbaudrate (struct serial *scb, int rate);
+static int dos_write (struct serial *scb, const char *str, int len);
+static void dos_close (struct serial *scb);
+static serial_ttystate dos_get_tty_state (struct serial *scb);
+static int dos_set_tty_state (struct serial *scb, serial_ttystate state);
+static int dos_baudconv (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 (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 (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 (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);
+ }
+}
+
+#define ISRNAME(x) dos_comisr##x
+#define ISR(x) static void ISRNAME(x)(void) {dos_comisr(x);}
+
+ISR (0) ISR (1) ISR (2) ISR (3) /* OK */
+ISR (4) ISR (5) ISR (6) ISR (7) /* OK */
+
+typedef void (*isr_t) (void);
+
+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 (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 (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 (struct serial *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;
+ }
+
+ /* FIXME: this is a Bad Idea (tm)! One should *never* invent file
+ handles, since they might be already used by other files/devices.
+ The Right Way to do this is to create a real handle by dup()'ing
+ some existing one. */
+ 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 (struct serial *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 (struct serial *scb)
+{
+ return 0;
+}
+
+static void
+dos_raw (struct serial *scb)
+{
+ /* Always in raw mode */
+}
+
+static int
+dos_readchar (struct serial *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;
+ }
+
+ return c;
+}
+
+
+static serial_ttystate
+dos_get_tty_state (struct serial *scb)
+{
+ struct dos_ttystate *port = &ports[scb->fd];
+ struct dos_ttystate *state;
+
+ /* Are they asking about a port we opened? */
+ if (port->refcnt <= 0)
+ {
+ /* We've never heard about this port. We should fail this call,
+ unless they are asking about one of the 3 standard handles,
+ in which case we pretend the handle was open by us if it is
+ connected to a terminal device. This is beacuse Unix
+ terminals use the serial interface, so GDB expects the
+ standard handles to go through here. */
+ if (scb->fd >= 3 || !isatty (scb->fd))
+ return NULL;
+ }
+
+ state = (struct dos_ttystate *) xmalloc (sizeof *state);
+ *state = *port;
+ return (serial_ttystate) state;
+}
+
+static int
+dos_set_tty_state (struct serial *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 (struct serial *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 (struct serial *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 ();
+ return 0;
+}
+
+static void
+dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
+ struct ui_file *stream)
+{
+ /* Nothing to print */
+ return;
+}
+
+static int
+dos_baudconv (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 (struct serial *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 (struct serial *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 (struct serial *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;
+ /* Francisco Pastor <fpastor.etra-id@etra.es> says OUTSB messes
+ up the communications with UARTs with FIFOs. */
+#ifdef UART_FIFO_WORKS
+ outportsb (port->base + com_data, str, cnt);
+ str += cnt;
+ len -= cnt;
+#else
+ for ( ; cnt > 0; cnt--, len--)
+ outportb (port->base + com_data, *str++);
+#endif
+#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 (struct serial *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,
+ dos_noop, /* wait for output to drain */
+ (void (*)(struct serial *, int))NULL /* change into async mode */
+};
+
+
+static void
+dos_info (char *arg, int from_tty)
+{
+ struct dos_ttystate *port;
+#ifdef DOS_STATS
+ int i;
+#endif
+
+ for (port = ports; port < &ports[4]; port++)
+ {
+ if (port->baudrate == 0)
+ continue;
+ printf_filtered ("Port:\tCOM%ld (%sactive)\n", (long)(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 (void)
+{
+ 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-pipe.c b/contrib/gdb/gdb/ser-pipe.c
new file mode 100644
index 0000000..3e04973
--- /dev/null
+++ b/contrib/gdb/gdb/ser-pipe.c
@@ -0,0 +1,161 @@
+/* Serial interface for a pipe to a separate program
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ser-unix.h"
+
+#include "gdb_vfork.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include "gdb_string.h"
+
+#include <signal.h>
+
+static int pipe_open (struct serial *scb, const char *name);
+static void pipe_close (struct serial *scb);
+
+extern void _initialize_ser_pipe (void);
+
+struct pipe_state
+ {
+ int pid;
+ };
+
+/* Open up a raw pipe */
+
+static int
+pipe_open (struct serial *scb, const char *name)
+{
+#if !HAVE_SOCKETPAIR
+ return -1;
+#else
+ struct pipe_state *state;
+ /* This chunk: */
+ /* Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ */
+ int pdes[2];
+ int pid;
+ if (socketpair (AF_UNIX, SOCK_STREAM, 0, pdes) < 0)
+ return -1;
+
+ /* Create the child process to run the command in. Note that the
+ apparent call to vfork() below *might* actually be a call to
+ fork() due to the fact that autoconf will ``#define vfork fork''
+ on certain platforms. */
+ pid = vfork ();
+
+ /* Error. */
+ if (pid == -1)
+ {
+ close (pdes[0]);
+ close (pdes[1]);
+ return -1;
+ }
+
+ /* Child. */
+ if (pid == 0)
+ {
+ /* re-wire pdes[1] to stdin/stdout */
+ close (pdes[0]);
+ if (pdes[1] != STDOUT_FILENO)
+ {
+ dup2 (pdes[1], STDOUT_FILENO);
+ close (pdes[1]);
+ }
+ dup2 (STDOUT_FILENO, STDIN_FILENO);
+#if 0
+ /* close any stray FD's - FIXME - how? */
+ /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
+ from previous popen() calls that remain open in the
+ parent process are closed in the new child process. */
+ for (old = pidlist; old; old = old->next)
+ close (fileno (old->fp)); /* don't allow a flush */
+#endif
+ execl ("/bin/sh", "sh", "-c", name, (char *) 0);
+ _exit (127);
+ }
+
+ /* Parent. */
+ close (pdes[1]);
+ /* :end chunk */
+ state = XMALLOC (struct pipe_state);
+ state->pid = pid;
+ scb->fd = pdes[0];
+ scb->state = state;
+
+ /* If we don't do this, GDB simply exits when the remote side dies. */
+ signal (SIGPIPE, SIG_IGN);
+ return 0;
+#endif
+}
+
+static void
+pipe_close (struct serial *scb)
+{
+ struct pipe_state *state = scb->state;
+ if (state != NULL)
+ {
+ int pid = state->pid;
+ close (scb->fd);
+ scb->fd = -1;
+ xfree (state);
+ scb->state = NULL;
+ kill (pid, SIGTERM);
+ /* Might be useful to check that the child does die. */
+ }
+}
+
+static struct serial_ops pipe_ops;
+
+void
+_initialize_ser_pipe (void)
+{
+ struct serial_ops *ops = XMALLOC (struct serial_ops);
+ memset (ops, 0, sizeof (struct serial_ops));
+ ops->name = "pipe";
+ ops->next = 0;
+ ops->open = pipe_open;
+ ops->close = pipe_close;
+ ops->readchar = ser_unix_readchar;
+ ops->write = ser_unix_write;
+ ops->flush_output = ser_unix_nop_flush_output;
+ ops->flush_input = ser_unix_flush_input;
+ ops->send_break = ser_unix_nop_send_break;
+ ops->go_raw = ser_unix_nop_raw;
+ ops->get_tty_state = ser_unix_nop_get_tty_state;
+ ops->set_tty_state = ser_unix_nop_set_tty_state;
+ ops->print_tty_state = ser_unix_nop_print_tty_state;
+ ops->noflush_set_tty_state = ser_unix_nop_noflush_set_tty_state;
+ ops->setbaudrate = ser_unix_nop_setbaudrate;
+ ops->setstopbits = ser_unix_nop_setstopbits;
+ ops->drain_output = ser_unix_nop_drain_output;
+ ops->async = ser_unix_async;
+ serial_add_interface (ops);
+}
diff --git a/contrib/gdb/gdb/ser-tcp.c b/contrib/gdb/gdb/ser-tcp.c
new file mode 100644
index 0000000..a9a8714
--- /dev/null
+++ b/contrib/gdb/gdb/ser-tcp.c
@@ -0,0 +1,231 @@
+/* Serial interface for raw TCP connections on Un*x like systems
+ Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ser-unix.h"
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h> /* For FIONBIO. */
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h> /* For FIONBIO. */
+#endif
+
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+
+#include <signal.h>
+#include "gdb_string.h"
+
+static int net_open (struct serial *scb, const char *name);
+static void net_close (struct serial *scb);
+extern int (*ui_loop_hook) (int);
+void _initialize_ser_tcp (void);
+
+/* seconds to wait for connect */
+#define TIMEOUT 15
+/* how many times per second to poll ui_loop_hook */
+#define POLL_INTERVAL 2
+
+/* Open a tcp socket */
+
+static int
+net_open (struct serial *scb, const char *name)
+{
+ char *port_str, hostname[100];
+ int n, port, tmp;
+ int use_udp;
+ struct hostent *hostent;
+ struct sockaddr_in sockaddr;
+
+ use_udp = 0;
+ if (strncmp (name, "udp:", 4) == 0)
+ {
+ use_udp = 1;
+ name = name + 4;
+ }
+ else if (strncmp (name, "tcp:", 4) == 0)
+ name = name + 4;
+
+ port_str = strchr (name, ':');
+
+ if (!port_str)
+ error ("net_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);
+
+ /* default hostname is localhost */
+ if (!hostname[0])
+ strcpy (hostname, "localhost");
+
+ hostent = gethostbyname (hostname);
+ if (!hostent)
+ {
+ fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname);
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (use_udp)
+ scb->fd = socket (PF_INET, SOCK_DGRAM, 0);
+ else
+ scb->fd = socket (PF_INET, SOCK_STREAM, 0);
+
+ if (scb->fd < 0)
+ return -1;
+
+ sockaddr.sin_family = PF_INET;
+ sockaddr.sin_port = htons (port);
+ memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
+ sizeof (struct in_addr));
+
+ /* set socket nonblocking */
+ tmp = 1;
+ ioctl (scb->fd, FIONBIO, &tmp);
+
+ /* Use Non-blocking connect. connect() will return 0 if connected already. */
+ n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
+
+ if (n < 0 && errno != EINPROGRESS)
+ {
+ net_close (scb);
+ return -1;
+ }
+
+ if (n)
+ {
+ /* looks like we need to wait for the connect */
+ struct timeval t;
+ fd_set rset, wset;
+ int polls = 0;
+ FD_ZERO (&rset);
+
+ do
+ {
+ /* While we wait for the connect to complete
+ poll the UI so it can update or the user can
+ interrupt. */
+ if (ui_loop_hook)
+ {
+ if (ui_loop_hook (0))
+ {
+ errno = EINTR;
+ net_close (scb);
+ return -1;
+ }
+ }
+
+ FD_SET (scb->fd, &rset);
+ wset = rset;
+ t.tv_sec = 0;
+ t.tv_usec = 1000000 / POLL_INTERVAL;
+
+ n = select (scb->fd + 1, &rset, &wset, NULL, &t);
+ polls++;
+ }
+ while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL);
+ if (n < 0 || polls > TIMEOUT * POLL_INTERVAL)
+ {
+ if (polls > TIMEOUT * POLL_INTERVAL)
+ errno = ETIMEDOUT;
+ net_close (scb);
+ return -1;
+ }
+ }
+
+ /* Got something. Is it an error? */
+ {
+ int res, err, len;
+ len = sizeof(err);
+ res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+ if (res < 0 || err)
+ {
+ if (err)
+ errno = err;
+ net_close (scb);
+ return -1;
+ }
+ }
+
+ /* turn off nonblocking */
+ tmp = 0;
+ ioctl (scb->fd, FIONBIO, &tmp);
+
+ if (use_udp == 0)
+ {
+ /* Disable Nagle algorithm. Needed in some cases. */
+ tmp = 1;
+ setsockopt (scb->fd, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&tmp, sizeof (tmp));
+ }
+
+ /* If we don't do this, then GDB simply exits
+ when the remote side dies. */
+ signal (SIGPIPE, SIG_IGN);
+
+ return 0;
+}
+
+static void
+net_close (struct serial *scb)
+{
+ if (scb->fd < 0)
+ return;
+
+ close (scb->fd);
+ scb->fd = -1;
+}
+
+void
+_initialize_ser_tcp (void)
+{
+ struct serial_ops *ops = XMALLOC (struct serial_ops);
+ memset (ops, 0, sizeof (struct serial_ops));
+ ops->name = "tcp";
+ ops->next = 0;
+ ops->open = net_open;
+ ops->close = net_close;
+ ops->readchar = ser_unix_readchar;
+ ops->write = ser_unix_write;
+ ops->flush_output = ser_unix_nop_flush_output;
+ ops->flush_input = ser_unix_flush_input;
+ ops->send_break = ser_unix_nop_send_break;
+ ops->go_raw = ser_unix_nop_raw;
+ ops->get_tty_state = ser_unix_nop_get_tty_state;
+ ops->set_tty_state = ser_unix_nop_set_tty_state;
+ ops->print_tty_state = ser_unix_nop_print_tty_state;
+ ops->noflush_set_tty_state = ser_unix_nop_noflush_set_tty_state;
+ ops->setbaudrate = ser_unix_nop_setbaudrate;
+ ops->setstopbits = ser_unix_nop_setstopbits;
+ ops->drain_output = ser_unix_nop_drain_output;
+ ops->async = ser_unix_async;
+ serial_add_interface (ops);
+}
diff --git a/contrib/gdb/gdb/ser-unix.c b/contrib/gdb/gdb/ser-unix.c
new file mode 100644
index 0000000..38b6716
--- /dev/null
+++ b/contrib/gdb/gdb/ser-unix.c
@@ -0,0 +1,1364 @@
+/* Serial interface for local (hardwired) serial ports on Un*x like systems
+
+ Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+ 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ser-unix.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include "terminal.h"
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include "gdb_string.h"
+#include "event-loop.h"
+
+#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
+struct hardwire_ttystate
+ {
+ struct sgttyb sgttyb;
+ struct tchars tc;
+ struct ltchars ltc;
+ /* Line discipline flags. */
+ int lmode;
+ };
+#endif /* sgtty */
+
+static int hardwire_open (struct serial *scb, const char *name);
+static void hardwire_raw (struct serial *scb);
+static int wait_for (struct serial *scb, int timeout);
+static int hardwire_readchar (struct serial *scb, int timeout);
+static int do_hardwire_readchar (struct serial *scb, int timeout);
+static int generic_readchar (struct serial *scb, int timeout,
+ int (*do_readchar) (struct serial *scb,
+ int timeout));
+static int rate_to_code (int rate);
+static int hardwire_setbaudrate (struct serial *scb, int rate);
+static void hardwire_close (struct serial *scb);
+static int get_tty_state (struct serial *scb,
+ struct hardwire_ttystate * state);
+static int set_tty_state (struct serial *scb,
+ struct hardwire_ttystate * state);
+static serial_ttystate hardwire_get_tty_state (struct serial *scb);
+static int hardwire_set_tty_state (struct serial *scb, serial_ttystate state);
+static int hardwire_noflush_set_tty_state (struct serial *, serial_ttystate,
+ serial_ttystate);
+static void hardwire_print_tty_state (struct serial *, serial_ttystate,
+ struct ui_file *);
+static int hardwire_drain_output (struct serial *);
+static int hardwire_flush_output (struct serial *);
+static int hardwire_flush_input (struct serial *);
+static int hardwire_send_break (struct serial *);
+static int hardwire_setstopbits (struct serial *, int);
+
+static int do_unix_readchar (struct serial *scb, int timeout);
+static timer_handler_func push_event;
+static handler_func fd_event;
+static void reschedule (struct serial *scb);
+
+void _initialize_ser_hardwire (void);
+
+extern int (*ui_loop_hook) (int);
+
+/* Open up a real live device for serial I/O */
+
+static int
+hardwire_open (struct serial *scb, const char *name)
+{
+ scb->fd = open (name, O_RDWR);
+ if (scb->fd < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+get_tty_state (struct serial *scb, struct hardwire_ttystate *state)
+{
+#ifdef HAVE_TERMIOS
+ 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 (struct serial *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 (struct serial *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 (struct serial *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 (struct serial *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 (struct serial *scb,
+ serial_ttystate ttystate,
+ struct ui_file *stream)
+{
+ struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate;
+ int i;
+
+#ifdef HAVE_TERMIOS
+ fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ (int) state->termios.c_iflag,
+ (int) state->termios.c_oflag);
+ fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n",
+ (int) state->termios.c_cflag,
+ (int) 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). */
+ fprintf_filtered (stream, "c_line = 0x%x.\n", state->termios.c_line);
+#endif
+ fprintf_filtered (stream, "c_cc: ");
+ for (i = 0; i < NCCS; i += 1)
+ fprintf_filtered (stream, "0x%x ", state->termios.c_cc[i]);
+ fprintf_filtered (stream, "\n");
+#endif
+
+#ifdef HAVE_TERMIO
+ fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ state->termio.c_iflag, state->termio.c_oflag);
+ fprintf_filtered (stream, "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);
+ fprintf_filtered (stream, "c_cc: ");
+ for (i = 0; i < NCC; i += 1)
+ fprintf_filtered (stream, "0x%x ", state->termio.c_cc[i]);
+ fprintf_filtered (stream, "\n");
+#endif
+
+#ifdef HAVE_SGTTY
+ fprintf_filtered (stream, "sgttyb.sg_flags = 0x%x.\n",
+ state->sgttyb.sg_flags);
+
+ fprintf_filtered (stream, "tchars: ");
+ for (i = 0; i < (int) sizeof (struct tchars); i++)
+ fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->tc)[i]);
+ fprintf_filtered (stream, "\n");
+
+ fprintf_filtered (stream, "ltchars: ");
+ for (i = 0; i < (int) sizeof (struct ltchars); i++)
+ fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->ltc)[i]);
+ fprintf_filtered (stream, "\n");
+
+ fprintf_filtered (stream, "lmode: 0x%x\n", state->lmode);
+#endif
+}
+
+/* Wait for the output to drain away, as opposed to flushing (discarding) it */
+
+static int
+hardwire_drain_output (struct serial *scb)
+{
+#ifdef HAVE_TERMIOS
+ return tcdrain (scb->fd);
+#endif
+
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCSBRK, 1);
+#endif
+
+#ifdef HAVE_SGTTY
+ /* Get the current state and then restore it using TIOCSETP,
+ which should cause the output to drain and pending input
+ to be discarded. */
+ {
+ struct hardwire_ttystate state;
+ if (get_tty_state (scb, &state))
+ {
+ return (-1);
+ }
+ else
+ {
+ return (ioctl (scb->fd, TIOCSETP, &state.sgttyb));
+ }
+ }
+#endif
+}
+
+static int
+hardwire_flush_output (struct serial *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 (struct serial *scb)
+{
+ ser_unix_flush_input (scb);
+
+#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 (struct serial *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 (struct serial *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().
+ */
+
+/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
+ ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
+ flushed. . */
+
+/* NOTE: cagney/1999-09-30: Much of the code below is dead. The only
+ possible values of the TIMEOUT parameter are ONE and ZERO.
+ Consequently all the code that tries to handle the possability of
+ an overflowed timer is unnecessary. */
+
+static int
+wait_for (struct serial *scb, int timeout)
+{
+#ifdef HAVE_SGTTY
+ while (1)
+ {
+ struct timeval tv;
+ fd_set readfds;
+ int numfds;
+
+ /* NOTE: Some OS's can scramble the READFDS when the select()
+ call fails (ex the kernel with Red Hat 5.2). Initialize all
+ arguments before each call. */
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO (&readfds);
+ FD_SET (scb->fd, &readfds);
+
+ 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). */
+
+/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
+ ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
+ flushed. */
+
+/* NOTE: cagney/1999-09-16: This function is not identical to
+ ser_unix_readchar() as part of replacing it with ser_unix*()
+ merging will be required - this code handles the case where read()
+ times out due to no data while ser_unix_readchar() doesn't expect
+ that. */
+
+static int
+do_hardwire_readchar (struct serial *scb, int timeout)
+{
+ int status, delta;
+ int detach = 0;
+
+ if (timeout > 0)
+ timeout++;
+
+ /* We have to be able to keep the GUI alive here, so we break the original
+ timeout into steps of 1 second, running the "keep the GUI alive" hook
+ each time through the loop.
+ Also, timeout = 0 means to poll, so we just set the delta to 0, so we
+ will only go through the loop once. */
+
+ delta = (timeout == 0 ? 0 : 1);
+ while (1)
+ {
+
+ /* N.B. The UI may destroy our world (for instance by calling
+ remote_stop,) in which case we want to get out of here as
+ quickly as possible. It is not safe to touch scb, since
+ someone else might have freed it. The ui_loop_hook signals that
+ we should exit by returning 1. */
+
+ if (ui_loop_hook)
+ detach = ui_loop_hook (0);
+
+ if (detach)
+ return SERIAL_TIMEOUT;
+
+ scb->timeout_remaining = (timeout < 0 ? timeout : timeout - delta);
+ status = wait_for (scb, delta);
+
+ if (status < 0)
+ return status;
+
+ status = read (scb->fd, scb->buf, BUFSIZ);
+
+ if (status <= 0)
+ {
+ if (status == 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 if (scb->timeout_remaining < 0)
+ continue;
+ else
+ return SERIAL_TIMEOUT;
+ }
+ else if (errno == EINTR)
+ continue;
+ else
+ return SERIAL_ERROR; /* Got an error from read */
+ }
+
+ scb->bufcnt = status;
+ scb->bufcnt--;
+ scb->bufp = scb->buf;
+ return *scb->bufp++;
+ }
+}
+
+static int
+hardwire_readchar (struct serial *scb, int timeout)
+{
+ return generic_readchar (scb, timeout, do_hardwire_readchar);
+}
+
+
+#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
+ }
+ ,
+#ifdef B57600
+ {
+ 57600, B57600
+ }
+ ,
+#endif
+#ifdef B115200
+ {
+ 115200, B115200
+ }
+ ,
+#endif
+#ifdef B230400
+ {
+ 230400, B230400
+ }
+ ,
+#endif
+#ifdef B460800
+ {
+ 460800, B460800
+ }
+ ,
+#endif
+ {
+ -1, -1
+ }
+ ,
+};
+
+static int
+rate_to_code (int rate)
+{
+ int i;
+
+ for (i = 0; baudtab[i].rate != -1; i++)
+ {
+ /* test for perfect macth. */
+ if (rate == baudtab[i].rate)
+ return baudtab[i].code;
+ else
+ {
+ /* check if it is in between valid values. */
+ if (rate < baudtab[i].rate)
+ {
+ if (i)
+ {
+ warning ("Invalid baud rate %d. Closest values are %d and %d.",
+ rate, baudtab[i - 1].rate, baudtab[i].rate);
+ }
+ else
+ {
+ warning ("Invalid baud rate %d. Minimum value is %d.",
+ rate, baudtab[0].rate);
+ }
+ return -1;
+ }
+ }
+ }
+
+ /* The requested speed was too large. */
+ warning ("Invalid baud rate %d. Maximum value is %d.",
+ rate, baudtab[i - 1].rate);
+ return -1;
+}
+
+static int
+hardwire_setbaudrate (struct serial *scb, int rate)
+{
+ struct hardwire_ttystate state;
+ int baud_code = rate_to_code (rate);
+
+ if (baud_code < 0)
+ {
+ /* The baud rate was not valid.
+ A warning has already been issued. */
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (get_tty_state (scb, &state))
+ return -1;
+
+#ifdef HAVE_TERMIOS
+ cfsetospeed (&state.termios, baud_code);
+ cfsetispeed (&state.termios, baud_code);
+#endif
+
+#ifdef HAVE_TERMIO
+#ifndef CIBAUD
+#define CIBAUD CBAUD
+#endif
+
+ state.termio.c_cflag &= ~(CBAUD | CIBAUD);
+ state.termio.c_cflag |= baud_code;
+#endif
+
+#ifdef HAVE_SGTTY
+ state.sgttyb.sg_ispeed = baud_code;
+ state.sgttyb.sg_ospeed = baud_code;
+#endif
+
+ return set_tty_state (scb, &state);
+}
+
+static int
+hardwire_setstopbits (struct serial *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 void
+hardwire_close (struct serial *scb)
+{
+ if (scb->fd < 0)
+ return;
+
+ close (scb->fd);
+ scb->fd = -1;
+}
+
+
+/* Generic operations used by all UNIX/FD based serial interfaces. */
+
+serial_ttystate
+ser_unix_nop_get_tty_state (struct serial *scb)
+{
+ /* allocate a dummy */
+ return (serial_ttystate) XMALLOC (int);
+}
+
+int
+ser_unix_nop_set_tty_state (struct serial *scb, serial_ttystate ttystate)
+{
+ return 0;
+}
+
+void
+ser_unix_nop_raw (struct serial *scb)
+{
+ return; /* Always in raw mode */
+}
+
+/* Wait for input on scb, with timeout seconds. Returns 0 on success,
+ otherwise SERIAL_TIMEOUT or SERIAL_ERROR. */
+
+int
+ser_unix_wait_for (struct serial *scb, int timeout)
+{
+ while (1)
+ {
+ int numfds;
+ struct timeval tv;
+ fd_set readfds, exceptfds;
+
+ /* NOTE: Some OS's can scramble the READFDS when the select()
+ call fails (ex the kernel with Red Hat 5.2). Initialize all
+ arguments before each call. */
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO (&readfds);
+ FD_ZERO (&exceptfds);
+ FD_SET (scb->fd, &readfds);
+ FD_SET (scb->fd, &exceptfds);
+
+ 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
+do_unix_readchar (struct serial *scb, int timeout)
+{
+ int status;
+ int delta;
+
+ /* We have to be able to keep the GUI alive here, so we break the original
+ timeout into steps of 1 second, running the "keep the GUI alive" hook
+ each time through the loop.
+
+ Also, timeout = 0 means to poll, so we just set the delta to 0, so we
+ will only go through the loop once. */
+
+ delta = (timeout == 0 ? 0 : 1);
+ while (1)
+ {
+
+ /* N.B. The UI may destroy our world (for instance by calling
+ remote_stop,) in which case we want to get out of here as
+ quickly as possible. It is not safe to touch scb, since
+ someone else might have freed it. The ui_loop_hook signals that
+ we should exit by returning 1. */
+
+ if (ui_loop_hook)
+ {
+ if (ui_loop_hook (0))
+ return SERIAL_TIMEOUT;
+ }
+
+ status = ser_unix_wait_for (scb, delta);
+ if (timeout > 0)
+ timeout -= delta;
+
+ /* If we got a character or an error back from wait_for, then we can
+ break from the loop before the timeout is completed. */
+
+ if (status != SERIAL_TIMEOUT)
+ {
+ break;
+ }
+
+ /* If we have exhausted the original timeout, then generate
+ a SERIAL_TIMEOUT, and pass it out of the loop. */
+
+ else if (timeout == 0)
+ {
+ status = SERIAL_TIMEOUT;
+ break;
+ }
+ }
+
+ if (status < 0)
+ return status;
+
+ while (1)
+ {
+ status = read (scb->fd, scb->buf, BUFSIZ);
+ if (status != -1 || errno != EINTR)
+ break;
+ }
+
+ if (status <= 0)
+ {
+ if (status == 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 = status;
+ scb->bufcnt--;
+ scb->bufp = scb->buf;
+ return *scb->bufp++;
+}
+
+/* Perform operations common to both old and new readchar. */
+
+/* Return the next character from the input FIFO. If the FIFO is
+ empty, call the SERIAL specific routine to try and read in more
+ characters.
+
+ Initially data from the input FIFO is returned (fd_event()
+ pre-reads the input into that FIFO. Once that has been emptied,
+ further data is obtained by polling the input FD using the device
+ specific readchar() function. Note: reschedule() is called after
+ every read. This is because there is no guarentee that the lower
+ level fd_event() poll_event() code (which also calls reschedule())
+ will be called. */
+
+static int
+generic_readchar (struct serial *scb, int timeout,
+ int (do_readchar) (struct serial *scb, int timeout))
+{
+ int ch;
+ if (scb->bufcnt > 0)
+ {
+ ch = *scb->bufp;
+ scb->bufcnt--;
+ scb->bufp++;
+ }
+ else if (scb->bufcnt < 0)
+ {
+ /* Some errors/eof are are sticky. */
+ ch = scb->bufcnt;
+ }
+ else
+ {
+ ch = do_readchar (scb, timeout);
+ if (ch < 0)
+ {
+ switch ((enum serial_rc) ch)
+ {
+ case SERIAL_EOF:
+ case SERIAL_ERROR:
+ /* Make the error/eof stick. */
+ scb->bufcnt = ch;
+ break;
+ case SERIAL_TIMEOUT:
+ scb->bufcnt = 0;
+ break;
+ }
+ }
+ }
+ reschedule (scb);
+ return ch;
+}
+
+int
+ser_unix_readchar (struct serial *scb, int timeout)
+{
+ return generic_readchar (scb, timeout, do_unix_readchar);
+}
+
+int
+ser_unix_nop_noflush_set_tty_state (struct serial *scb,
+ serial_ttystate new_ttystate,
+ serial_ttystate old_ttystate)
+{
+ return 0;
+}
+
+void
+ser_unix_nop_print_tty_state (struct serial *scb,
+ serial_ttystate ttystate,
+ struct ui_file *stream)
+{
+ /* Nothing to print. */
+ return;
+}
+
+int
+ser_unix_nop_setbaudrate (struct serial *scb, int rate)
+{
+ return 0; /* Never fails! */
+}
+
+int
+ser_unix_nop_setstopbits (struct serial *scb, int num)
+{
+ return 0; /* Never fails! */
+}
+
+int
+ser_unix_write (struct serial *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;
+}
+
+int
+ser_unix_nop_flush_output (struct serial *scb)
+{
+ return 0;
+}
+
+int
+ser_unix_flush_input (struct serial *scb)
+{
+ if (scb->bufcnt >= 0)
+ {
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+ return 0;
+ }
+ else
+ return SERIAL_ERROR;
+}
+
+int
+ser_unix_nop_send_break (struct serial *scb)
+{
+ return 0;
+}
+
+int
+ser_unix_nop_drain_output (struct serial *scb)
+{
+ return 0;
+}
+
+
+
+/* Event handling for ASYNC serial code.
+
+ At any time the SERIAL device either: has an empty FIFO and is
+ waiting on a FD event; or has a non-empty FIFO/error condition and
+ is constantly scheduling timer events.
+
+ ASYNC only stops pestering its client when it is de-async'ed or it
+ is told to go away. */
+
+/* Value of scb->async_state: */
+enum {
+ /* >= 0 (TIMER_SCHEDULED) */
+ /* The ID of the currently scheduled timer event. This state is
+ rarely encountered. Timer events are one-off so as soon as the
+ event is delivered the state is shanged to NOTHING_SCHEDULED. */
+ FD_SCHEDULED = -1,
+ /* The fd_event() handler is scheduled. It is called when ever the
+ file descriptor becomes ready. */
+ NOTHING_SCHEDULED = -2
+ /* Either no task is scheduled (just going into ASYNC mode) or a
+ timer event has just gone off and the current state has been
+ forced into nothing scheduled. */
+};
+
+/* Identify and schedule the next ASYNC task based on scb->async_state
+ and scb->buf* (the input FIFO). A state machine is used to avoid
+ the need to make redundant calls into the event-loop - the next
+ scheduled task is only changed when needed. */
+
+static void
+reschedule (struct serial *scb)
+{
+ if (serial_is_async_p (scb))
+ {
+ int next_state;
+ switch (scb->async_state)
+ {
+ case FD_SCHEDULED:
+ if (scb->bufcnt == 0)
+ next_state = FD_SCHEDULED;
+ else
+ {
+ delete_file_handler (scb->fd);
+ next_state = create_timer (0, push_event, scb);
+ }
+ break;
+ case NOTHING_SCHEDULED:
+ if (scb->bufcnt == 0)
+ {
+ add_file_handler (scb->fd, fd_event, scb);
+ next_state = FD_SCHEDULED;
+ }
+ else
+ {
+ next_state = create_timer (0, push_event, scb);
+ }
+ break;
+ default: /* TIMER SCHEDULED */
+ if (scb->bufcnt == 0)
+ {
+ delete_timer (scb->async_state);
+ add_file_handler (scb->fd, fd_event, scb);
+ next_state = FD_SCHEDULED;
+ }
+ else
+ next_state = scb->async_state;
+ break;
+ }
+ if (serial_debug_p (scb))
+ {
+ switch (next_state)
+ {
+ case FD_SCHEDULED:
+ if (scb->async_state != FD_SCHEDULED)
+ fprintf_unfiltered (gdb_stdlog, "[fd%d->fd-scheduled]\n",
+ scb->fd);
+ break;
+ default: /* TIMER SCHEDULED */
+ if (scb->async_state == FD_SCHEDULED)
+ fprintf_unfiltered (gdb_stdlog, "[fd%d->timer-scheduled]\n",
+ scb->fd);
+ break;
+ }
+ }
+ scb->async_state = next_state;
+ }
+}
+
+/* FD_EVENT: This is scheduled when the input FIFO is empty (and there
+ is no pending error). As soon as data arrives, it is read into the
+ input FIFO and the client notified. The client should then drain
+ the FIFO using readchar(). If the FIFO isn't immediatly emptied,
+ push_event() is used to nag the client until it is. */
+
+static void
+fd_event (int error, void *context)
+{
+ struct serial *scb = context;
+ if (error != 0)
+ {
+ scb->bufcnt = SERIAL_ERROR;
+ }
+ else if (scb->bufcnt == 0)
+ {
+ /* Prime the input FIFO. The readchar() function is used to
+ pull characters out of the buffer. See also
+ generic_readchar(). */
+ int nr;
+ do
+ {
+ nr = read (scb->fd, scb->buf, BUFSIZ);
+ }
+ while (nr == -1 && errno == EINTR);
+ if (nr == 0)
+ {
+ scb->bufcnt = SERIAL_EOF;
+ }
+ else if (nr > 0)
+ {
+ scb->bufcnt = nr;
+ scb->bufp = scb->buf;
+ }
+ else
+ {
+ scb->bufcnt = SERIAL_ERROR;
+ }
+ }
+ scb->async_handler (scb, scb->async_context);
+ reschedule (scb);
+}
+
+/* PUSH_EVENT: The input FIFO is non-empty (or there is a pending
+ error). Nag the client until all the data has been read. In the
+ case of errors, the client will need to close or de-async the
+ device before naging stops. */
+
+static void
+push_event (void *context)
+{
+ struct serial *scb = context;
+ scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */
+ scb->async_handler (scb, scb->async_context);
+ /* re-schedule */
+ reschedule (scb);
+}
+
+/* Put the SERIAL device into/out-of ASYNC mode. */
+
+void
+ser_unix_async (struct serial *scb,
+ int async_p)
+{
+ if (async_p)
+ {
+ /* Force a re-schedule. */
+ scb->async_state = NOTHING_SCHEDULED;
+ if (serial_debug_p (scb))
+ fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n",
+ scb->fd);
+ reschedule (scb);
+ }
+ else
+ {
+ if (serial_debug_p (scb))
+ fprintf_unfiltered (gdb_stdlog, "[fd%d->synchronous]\n",
+ scb->fd);
+ /* De-schedule whatever tasks are currently scheduled. */
+ switch (scb->async_state)
+ {
+ case FD_SCHEDULED:
+ delete_file_handler (scb->fd);
+ break;
+ case NOTHING_SCHEDULED:
+ break;
+ default: /* TIMER SCHEDULED */
+ delete_timer (scb->async_state);
+ break;
+ }
+ }
+}
+
+void
+_initialize_ser_hardwire (void)
+{
+ struct serial_ops *ops = XMALLOC (struct serial_ops);
+ memset (ops, 0, sizeof (struct serial_ops));
+ ops->name = "hardwire";
+ ops->next = 0;
+ ops->open = hardwire_open;
+ ops->close = hardwire_close;
+ /* FIXME: Don't replace this with the equivalent ser_unix*() until
+ the old TERMIOS/SGTTY/... timer code has been flushed. cagney
+ 1999-09-16. */
+ ops->readchar = hardwire_readchar;
+ ops->write = ser_unix_write;
+ ops->flush_output = hardwire_flush_output;
+ ops->flush_input = hardwire_flush_input;
+ ops->send_break = hardwire_send_break;
+ ops->go_raw = hardwire_raw;
+ ops->get_tty_state = hardwire_get_tty_state;
+ ops->set_tty_state = hardwire_set_tty_state;
+ ops->print_tty_state = hardwire_print_tty_state;
+ ops->noflush_set_tty_state = hardwire_noflush_set_tty_state;
+ ops->setbaudrate = hardwire_setbaudrate;
+ ops->setstopbits = hardwire_setstopbits;
+ ops->drain_output = hardwire_drain_output;
+ ops->async = ser_unix_async;
+ serial_add_interface (ops);
+}
diff --git a/contrib/gdb/gdb/ser-unix.h b/contrib/gdb/gdb/ser-unix.h
new file mode 100644
index 0000000..3bdf0bc
--- /dev/null
+++ b/contrib/gdb/gdb/ser-unix.h
@@ -0,0 +1,54 @@
+/* Serial interface for UN*X file-descriptor based connection.
+
+ Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SER_UNIX_H
+#define SER_UNIX_H
+
+struct serial;
+struct ui_file;
+
+/* Generic UNIX/FD functions */
+
+extern int ser_unix_nop_flush_output (struct serial *scb);
+extern int ser_unix_flush_input (struct serial *scb);
+extern int ser_unix_nop_send_break (struct serial *scb);
+extern void ser_unix_nop_raw (struct serial *scb);
+extern serial_ttystate ser_unix_nop_get_tty_state (struct serial *scb);
+extern int ser_unix_nop_set_tty_state (struct serial *scb,
+ serial_ttystate ttystate);
+extern void ser_unix_nop_print_tty_state (struct serial *scb,
+ serial_ttystate ttystate,
+ struct ui_file *stream);
+extern int ser_unix_nop_noflush_set_tty_state (struct serial *scb,
+ serial_ttystate new_ttystate,
+ serial_ttystate old_ttystate);
+extern int ser_unix_nop_setbaudrate (struct serial *scb, int rate);
+extern int ser_unix_nop_setstopbits (struct serial *scb, int rate);
+extern int ser_unix_nop_drain_output (struct serial *scb);
+
+extern int ser_unix_wait_for (struct serial *scb, int timeout);
+extern int ser_unix_readchar (struct serial *scb, int timeout);
+
+extern int ser_unix_write (struct serial *scb, const char *str, int len);
+
+extern void ser_unix_async (struct serial *scb, int async_p);
+
+#endif
diff --git a/contrib/gdb/gdb/serial.c b/contrib/gdb/gdb/serial.c
new file mode 100644
index 0000000..ada5631
--- /dev/null
+++ b/contrib/gdb/gdb/serial.c
@@ -0,0 +1,712 @@
+/* Generic serial interface routines
+
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#include "serial.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"
+
+extern void _initialize_serial (void);
+
+/* Is serial being debugged? */
+
+static int global_serial_debug_p;
+
+/* Linked list of serial I/O handlers */
+
+static struct serial_ops *serial_ops_list = NULL;
+
+/* This is the last serial stream opened. Used by connect command. */
+
+static struct serial *last_serial_opened = NULL;
+
+/* Pointer to list of scb's. */
+
+static struct serial *scb_base;
+
+/* Non-NULL gives filename which contains a recording of the remote session,
+ suitable for playback by gdbserver. */
+
+static char *serial_logfile = NULL;
+static struct ui_file *serial_logfp = NULL;
+
+static struct serial_ops *serial_interface_lookup (char *);
+static void serial_logchar (struct ui_file *stream, int ch_type, int ch, int timeout);
+static const char logbase_hex[] = "hex";
+static const char logbase_octal[] = "octal";
+static const char logbase_ascii[] = "ascii";
+static const char *logbase_enums[] =
+{logbase_hex, logbase_octal, logbase_ascii, NULL};
+static const char *serial_logbase = logbase_ascii;
+
+
+static int serial_current_type = 0;
+
+/* Log char CH of type CHTYPE, with TIMEOUT */
+
+/* Define bogus char to represent a BREAK. Should be careful to choose a value
+ that can't be confused with a normal char, or an error code. */
+#define SERIAL_BREAK 1235
+
+static void
+serial_logchar (struct ui_file *stream, int ch_type, int ch, int timeout)
+{
+ if (ch_type != serial_current_type)
+ {
+ fprintf_unfiltered (stream, "\n%c ", ch_type);
+ serial_current_type = ch_type;
+ }
+
+ if (serial_logbase != logbase_ascii)
+ fputc_unfiltered (' ', stream);
+
+ switch (ch)
+ {
+ case SERIAL_TIMEOUT:
+ fprintf_unfiltered (stream, "<Timeout: %d seconds>", timeout);
+ return;
+ case SERIAL_ERROR:
+ fprintf_unfiltered (stream, "<Error: %s>", safe_strerror (errno));
+ return;
+ case SERIAL_EOF:
+ fputs_unfiltered ("<Eof>", stream);
+ return;
+ case SERIAL_BREAK:
+ fputs_unfiltered ("<Break>", stream);
+ return;
+ default:
+ if (serial_logbase == logbase_hex)
+ fprintf_unfiltered (stream, "%02x", ch & 0xff);
+ else if (serial_logbase == logbase_octal)
+ fprintf_unfiltered (stream, "%03o", ch & 0xff);
+ else
+ switch (ch)
+ {
+ case '\\':
+ fputs_unfiltered ("\\\\", stream);
+ break;
+ case '\b':
+ fputs_unfiltered ("\\b", stream);
+ break;
+ case '\f':
+ fputs_unfiltered ("\\f", stream);
+ break;
+ case '\n':
+ fputs_unfiltered ("\\n", stream);
+ break;
+ case '\r':
+ fputs_unfiltered ("\\r", stream);
+ break;
+ case '\t':
+ fputs_unfiltered ("\\t", stream);
+ break;
+ case '\v':
+ fputs_unfiltered ("\\v", stream);
+ break;
+ default:
+ fprintf_unfiltered (stream, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF);
+ break;
+ }
+ }
+}
+
+void
+serial_log_command (const char *cmd)
+{
+ if (!serial_logfp)
+ return;
+
+ serial_current_type = 'c';
+
+ fputs_unfiltered ("\nc ", serial_logfp);
+ fputs_unfiltered (cmd, serial_logfp);
+
+ /* Make sure that the log file is as up-to-date as possible,
+ in case we are getting ready to dump core or something. */
+ gdb_flush (serial_logfp);
+}
+
+
+static struct serial_ops *
+serial_interface_lookup (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 (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. */
+
+struct serial *
+serial_open (const char *name)
+{
+ struct serial *scb;
+ struct serial_ops *ops;
+ const char *open_name = name;
+
+ for (scb = scb_base; scb; scb = scb->next)
+ if (scb->name && strcmp (scb->name, name) == 0)
+ {
+ scb->refcnt++;
+ return scb;
+ }
+
+ if (strcmp (name, "pc") == 0)
+ ops = serial_interface_lookup ("pc");
+ else if (strchr (name, ':'))
+ ops = serial_interface_lookup ("tcp");
+ else if (strncmp (name, "lpt", 3) == 0)
+ ops = serial_interface_lookup ("parallel");
+ else if (strncmp (name, "|", 1) == 0)
+ {
+ ops = serial_interface_lookup ("pipe");
+ open_name = name + 1; /* discard ``|'' */
+ }
+ else
+ ops = serial_interface_lookup ("hardwire");
+
+ if (!ops)
+ return NULL;
+
+ scb = XMALLOC (struct serial);
+
+ scb->ops = ops;
+
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
+ if (scb->ops->open (scb, open_name))
+ {
+ xfree (scb);
+ return NULL;
+ }
+
+ scb->name = xstrdup (name);
+ scb->next = scb_base;
+ scb->refcnt = 1;
+ scb->debug_p = 0;
+ scb->async_state = 0;
+ scb->async_handler = NULL;
+ scb->async_context = NULL;
+ scb_base = scb;
+
+ last_serial_opened = scb;
+
+ if (serial_logfile != NULL)
+ {
+ serial_logfp = gdb_fopen (serial_logfile, "w");
+ if (serial_logfp == NULL)
+ perror_with_name (serial_logfile);
+ }
+
+ return scb;
+}
+
+struct serial *
+serial_fdopen (const int fd)
+{
+ struct serial *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 = XMALLOC (struct serial);
+
+ scb->ops = ops;
+
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
+ scb->fd = fd;
+
+ scb->name = NULL;
+ scb->next = scb_base;
+ scb->refcnt = 1;
+ scb->debug_p = 0;
+ scb->async_state = 0;
+ scb->async_handler = NULL;
+ scb->async_context = NULL;
+ scb_base = scb;
+
+ last_serial_opened = scb;
+
+ return scb;
+}
+
+static void
+do_serial_close (struct serial *scb, int really_close)
+{
+ struct serial *tmp_scb;
+
+ last_serial_opened = NULL;
+
+ if (serial_logfp)
+ {
+ fputs_unfiltered ("\nEnd of log\n", serial_logfp);
+ serial_current_type = 0;
+
+ /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr? */
+ ui_file_delete (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;
+
+ /* ensure that the FD has been taken out of async mode */
+ if (scb->async_handler != NULL)
+ serial_async (scb, NULL, NULL);
+
+ if (really_close)
+ scb->ops->close (scb);
+
+ if (scb->name)
+ xfree (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;
+ }
+
+ xfree (scb);
+}
+
+void
+serial_close (struct serial *scb)
+{
+ do_serial_close (scb, 1);
+}
+
+void
+serial_un_fdopen (struct serial *scb)
+{
+ do_serial_close (scb, 0);
+}
+
+int
+serial_readchar (struct serial *scb, int timeout)
+{
+ int ch;
+
+ /* FIXME: cagney/1999-10-11: Don't enable this check until the ASYNC
+ code is finished. */
+ if (0 && serial_is_async_p (scb) && timeout < 0)
+ internal_error (__FILE__, __LINE__,
+ "serial_readchar: blocking read in async mode");
+
+ ch = scb->ops->readchar (scb, timeout);
+ if (serial_logfp != NULL)
+ {
+ serial_logchar (serial_logfp, 'r', ch, timeout);
+
+ /* Make sure that the log file is as up-to-date as possible,
+ in case we are getting ready to dump core or something. */
+ gdb_flush (serial_logfp);
+ }
+ if (serial_debug_p (scb))
+ {
+ fprintf_unfiltered (gdb_stdlog, "[");
+ serial_logchar (gdb_stdlog, 'r', ch, timeout);
+ fprintf_unfiltered (gdb_stdlog, "]");
+ gdb_flush (gdb_stdlog);
+ }
+
+ return (ch);
+}
+
+int
+serial_write (struct serial *scb, const char *str, int len)
+{
+ if (serial_logfp != NULL)
+ {
+ int count;
+
+ for (count = 0; count < len; count++)
+ serial_logchar (serial_logfp, 'w', str[count] & 0xff, 0);
+
+ /* Make sure that the log file is as up-to-date as possible,
+ in case we are getting ready to dump core or something. */
+ gdb_flush (serial_logfp);
+ }
+
+ return (scb->ops->write (scb, str, len));
+}
+
+void
+serial_printf (struct serial *desc, const char *format,...)
+{
+ va_list args;
+ char *buf;
+ va_start (args, format);
+
+ xvasprintf (&buf, format, args);
+ serial_write (desc, buf, strlen (buf));
+
+ xfree (buf);
+ va_end (args);
+}
+
+int
+serial_drain_output (struct serial *scb)
+{
+ return scb->ops->drain_output (scb);
+}
+
+int
+serial_flush_output (struct serial *scb)
+{
+ return scb->ops->flush_output (scb);
+}
+
+int
+serial_flush_input (struct serial *scb)
+{
+ return scb->ops->flush_input (scb);
+}
+
+int
+serial_send_break (struct serial *scb)
+{
+ if (serial_logfp != NULL)
+ serial_logchar (serial_logfp, 'w', SERIAL_BREAK, 0);
+
+ return (scb->ops->send_break (scb));
+}
+
+void
+serial_raw (struct serial *scb)
+{
+ scb->ops->go_raw (scb);
+}
+
+serial_ttystate
+serial_get_tty_state (struct serial *scb)
+{
+ return scb->ops->get_tty_state (scb);
+}
+
+int
+serial_set_tty_state (struct serial *scb, serial_ttystate ttystate)
+{
+ return scb->ops->set_tty_state (scb, ttystate);
+}
+
+void
+serial_print_tty_state (struct serial *scb,
+ serial_ttystate ttystate,
+ struct ui_file *stream)
+{
+ scb->ops->print_tty_state (scb, ttystate, stream);
+}
+
+int
+serial_noflush_set_tty_state (struct serial *scb,
+ serial_ttystate new_ttystate,
+ serial_ttystate old_ttystate)
+{
+ return scb->ops->noflush_set_tty_state (scb, new_ttystate, old_ttystate);
+}
+
+int
+serial_setbaudrate (struct serial *scb, int rate)
+{
+ return scb->ops->setbaudrate (scb, rate);
+}
+
+int
+serial_setstopbits (struct serial *scb, int num)
+{
+ return scb->ops->setstopbits (scb, num);
+}
+
+int
+serial_can_async_p (struct serial *scb)
+{
+ return (scb->ops->async != NULL);
+}
+
+int
+serial_is_async_p (struct serial *scb)
+{
+ return (scb->ops->async != NULL) && (scb->async_handler != NULL);
+}
+
+void
+serial_async (struct serial *scb,
+ serial_event_ftype *handler,
+ void *context)
+{
+ /* Only change mode if there is a need. */
+ if ((scb->async_handler == NULL)
+ != (handler == NULL))
+ scb->ops->async (scb, handler != NULL);
+ scb->async_handler = handler;
+ scb->async_context = context;
+}
+
+int
+deprecated_serial_fd (struct serial *scb)
+{
+ /* FIXME: should this output a warning that deprecated code is being
+ called? */
+ if (scb->fd < 0)
+ {
+ internal_error (__FILE__, __LINE__,
+ "serial: FD not valid");
+ }
+ return scb->fd; /* sigh */
+}
+
+void
+serial_debug (struct serial *scb, int debug_p)
+{
+ scb->debug_p = debug_p;
+}
+
+int
+serial_debug_p (struct serial *scb)
+{
+ return scb->debug_p || global_serial_debug_p;
+}
+
+
+#if 0
+/* The connect command is #if 0 because I hadn't thought of an elegant
+ way to wait for I/O on two `struct serial *'s simultaneously. Two
+ solutions came to mind:
+
+ 1) Fork, and have have one fork handle the to user direction,
+ and have the other hand the to target direction. This
+ obviously won't cut it for MSDOS.
+
+ 2) Use something like select. This assumes that stdin and
+ the target side can both be waited on via the same
+ mechanism. This may not be true for DOS, if GDB is
+ talking to the target via a TCP socket.
+ -grossman, 8 Jun 93 */
+
+/* Connect the user directly to the remote system. This command acts just like
+ the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
+
+static struct serial *tty_desc; /* Controlling terminal */
+
+static void
+cleanup_tty (serial_ttystate ttystate)
+{
+ printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
+ serial_set_tty_state (tty_desc, ttystate);
+ xfree (ttystate);
+ serial_close (tty_desc);
+}
+
+static void
+connect_command (char *args, int fromtty)
+{
+ int c;
+ char cur_esc = 0;
+ serial_ttystate ttystate;
+ struct serial *port_desc; /* TTY port */
+
+ dont_repeat ();
+
+ if (args)
+ fprintf_unfiltered (gdb_stderr, "This command takes no args. They have been ignored.\n");
+
+ printf_unfiltered ("[Entering connect mode. Use ~. or ~^D to escape]\n");
+
+ tty_desc = serial_fdopen (0);
+ port_desc = last_serial_opened;
+
+ ttystate = serial_get_tty_state (tty_desc);
+
+ serial_raw (tty_desc);
+ serial_raw (port_desc);
+
+ make_cleanup (cleanup_tty, ttystate);
+
+ while (1)
+ {
+ int mask;
+
+ mask = serial_wait_2 (tty_desc, port_desc, -1);
+
+ if (mask & 2)
+ { /* tty input */
+ char cx;
+
+ while (1)
+ {
+ c = serial_readchar (tty_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
+ if (c < 0)
+ perror_with_name ("connect");
+
+ cx = c;
+ serial_write (port_desc, &cx, 1);
+
+ switch (cur_esc)
+ {
+ case 0:
+ if (c == '\r')
+ cur_esc = c;
+ break;
+ case '\r':
+ if (c == '~')
+ cur_esc = c;
+ else
+ cur_esc = 0;
+ break;
+ case '~':
+ if (c == '.' || c == '\004')
+ return;
+ else
+ cur_esc = 0;
+ }
+ }
+ }
+
+ if (mask & 1)
+ { /* Port input */
+ char cx;
+
+ while (1)
+ {
+ c = serial_readchar (port_desc, 0);
+
+ if (c == SERIAL_TIMEOUT)
+ break;
+
+ if (c < 0)
+ perror_with_name ("connect");
+
+ cx = c;
+
+ serial_write (tty_desc, &cx, 1);
+ }
+ }
+ }
+}
+#endif /* 0 */
+
+/* Serial set/show framework. */
+
+static struct cmd_list_element *serial_set_cmdlist;
+static struct cmd_list_element *serial_show_cmdlist;
+
+static void
+serial_set_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set serial\" must be followed by the name of a command.\n");
+ help_list (serial_set_cmdlist, "set serial ", -1, gdb_stdout);
+}
+
+static void
+serial_show_cmd (char *args, int from_tty)
+{
+ cmd_show_list (serial_show_cmdlist, from_tty, "");
+}
+
+
+void
+_initialize_serial (void)
+{
+#if 0
+ add_com ("connect", class_obscure, connect_command,
+ "Connect the terminal directly up to the command monitor.\n\
+Use <CR>~. or <CR>~^D to break out.");
+#endif /* 0 */
+
+ add_prefix_cmd ("serial", class_maintenance, serial_set_cmd, "\
+Set default serial/parallel port configuration.",
+ &serial_set_cmdlist, "set serial ",
+ 0/*allow-unknown*/,
+ &setlist);
+
+ add_prefix_cmd ("serial", class_maintenance, serial_show_cmd, "\
+Show default serial/parallel port configuration.",
+ &serial_show_cmdlist, "show serial ",
+ 0/*allow-unknown*/,
+ &showlist);
+
+ 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);
+
+ add_show_from_set
+ (add_set_enum_cmd ("remotelogbase", no_class,
+ logbase_enums, &serial_logbase,
+ "Set numerical base for remote session logging",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("serial",
+ class_maintenance,
+ var_zinteger,
+ (char *)&global_serial_debug_p,
+ "Set serial debugging.\n\
+When non-zero, serial port debugging is enabled.", &setdebuglist),
+ &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/serial.h b/contrib/gdb/gdb/serial.h
new file mode 100644
index 0000000..7495b70
--- /dev/null
+++ b/contrib/gdb/gdb/serial.h
@@ -0,0 +1,243 @@
+/* Remote serial support interface definitions for GDB, the GNU Debugger.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+struct ui_file;
+
+/* For most routines, if a failure is indicated, then errno should be
+ examined. */
+
+/* Terminal state pointer. This is specific to each type of
+ interface. */
+
+typedef void *serial_ttystate;
+struct serial;
+
+/* Try to open NAME. Returns a new `struct serial *' on success, NULL
+ on failure. Note that some open calls can block and, if possible,
+ should be written to be non-blocking, with calls to ui_look_hook
+ so they can be cancelled. An async interface for open could be
+ added to GDB if necessary. */
+
+extern struct serial *serial_open (const char *name);
+
+/* Open a new serial stream using a file handle. */
+
+extern struct serial *serial_fdopen (const int fd);
+
+/* Push out all buffers, close the device and destroy SCB. */
+
+extern void serial_close (struct serial *scb);
+
+/* Push out all buffers and destroy SCB without closing the device. */
+
+extern void serial_un_fdopen (struct serial *scb);
+
+/* 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.
+ Infinite waits are not permitted. Returns unsigned char if ok, else
+ one of the following codes. Note that all error return-codes are
+ guaranteed to be < 0. */
+
+enum serial_rc {
+ SERIAL_ERROR = -1, /* General error. */
+ SERIAL_TIMEOUT = -2, /* Timeout or data-not-ready during read.
+ Unfortunately, through ui_loop_hook(), this
+ can also be a QUIT indication. */
+ SERIAL_EOF = -3 /* General end-of-file or remote target
+ connection closed, indication. Includes
+ things like the line dropping dead. */
+};
+
+extern int serial_readchar (struct serial *scb, int timeout);
+
+/* Write LEN chars from STRING to the port SCB. Returns 0 for
+ success, non-zero for failure. */
+
+extern int serial_write (struct serial *scb, const char *str, int len);
+
+/* Write a printf style string onto the serial port. */
+
+extern void serial_printf (struct serial *desc, const char *,...) ATTR_FORMAT (printf, 2, 3);
+
+/* Allow pending output to drain. */
+
+extern int serial_drain_output (struct serial *);
+
+/* Flush (discard) pending output. Might also flush input (if this
+ system can't flush only output). */
+
+extern int serial_flush_output (struct serial *);
+
+/* Flush pending input. Might also flush output (if this system can't
+ flush only input). */
+
+extern int serial_flush_input (struct serial *);
+
+/* Send a break between 0.25 and 0.5 seconds long. */
+
+extern int serial_send_break (struct serial *scb);
+
+/* Turn the port into raw mode. */
+
+extern void serial_raw (struct serial *scb);
+
+/* Return a pointer to a newly malloc'd ttystate containing the state
+ of the tty. */
+
+extern serial_ttystate serial_get_tty_state (struct serial *scb);
+
+/* 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). */
+
+extern int serial_set_tty_state (struct serial *scb, serial_ttystate ttystate);
+
+/* printf_filtered a user-comprehensible description of ttystate on
+ the specified STREAM. FIXME: At present this sends output to the
+ default stream - GDB_STDOUT. */
+
+extern void serial_print_tty_state (struct serial *scb, serial_ttystate ttystate, struct ui_file *);
+
+/* 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. */
+
+extern int serial_noflush_set_tty_state (struct serial *scb, serial_ttystate new_ttystate, serial_ttystate old_ttystate);
+
+/* Set the baudrate to the decimal value supplied. Returns 0 for
+ success, -1 for failure. */
+
+extern int serial_setbaudrate (struct serial *scb, int 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
+
+extern int serial_setstopbits (struct serial *scb, int num);
+
+/* Asynchronous serial interface: */
+
+/* Can the serial device support asynchronous mode? */
+
+extern int serial_can_async_p (struct serial *scb);
+
+/* Has the serial device been put in asynchronous mode? */
+
+extern int serial_is_async_p (struct serial *scb);
+
+/* For ASYNC enabled devices, register a callback and enable
+ asynchronous mode. To disable asynchronous mode, register a NULL
+ callback. */
+
+typedef void (serial_event_ftype) (struct serial *scb, void *context);
+extern void serial_async (struct serial *scb, serial_event_ftype *handler, void *context);
+
+/* Provide direct access to the underlying FD (if any) used to
+ implement the serial device. This interface is clearly
+ deprecated. Will call internal_error() if the operation isn't
+ applicable to the current serial device. */
+
+extern int deprecated_serial_fd (struct serial *scb);
+
+/* Trace/debug mechanism.
+
+ serial_debug() enables/disables internal debugging.
+ serial_debug_p() indicates the current debug state. */
+
+extern void serial_debug (struct serial *scb, int debug_p);
+
+extern int serial_debug_p (struct serial *scb);
+
+
+/* Details of an instance of a serial object */
+
+struct serial
+ {
+ int fd; /* File descriptor */
+ struct serial_ops *ops; /* Function vector */
+ void *state; /* Local context info for open FD */
+ serial_ttystate ttystate; /* Not used (yet) */
+ int bufcnt; /* Amount of data remaining in receive
+ buffer. -ve for sticky errors. */
+ unsigned char *bufp; /* Current byte */
+ unsigned char buf[BUFSIZ]; /* Da buffer itself */
+ int current_timeout; /* (ser-unix.c termio{,s} only), last
+ value of VTIME */
+ int timeout_remaining; /* (ser-unix.c termio{,s} only), we
+ still need to wait for this many
+ more seconds. */
+ char *name; /* The name of the device or host */
+ struct serial *next; /* Pointer to the next `struct serial *' */
+ int refcnt; /* Number of pointers to this block */
+ int debug_p; /* Trace this serial devices operation. */
+ int async_state; /* Async internal state. */
+ void *async_context; /* Async event thread's context */
+ serial_event_ftype *async_handler;/* Async event handler */
+ };
+
+struct serial_ops
+ {
+ char *name;
+ struct serial_ops *next;
+ int (*open) (struct serial *, const char *name);
+ void (*close) (struct serial *);
+ int (*readchar) (struct serial *, int timeout);
+ int (*write) (struct serial *, const char *str, int len);
+ /* Discard pending output */
+ int (*flush_output) (struct serial *);
+ /* Discard pending input */
+ int (*flush_input) (struct serial *);
+ int (*send_break) (struct serial *);
+ void (*go_raw) (struct serial *);
+ serial_ttystate (*get_tty_state) (struct serial *);
+ int (*set_tty_state) (struct serial *, serial_ttystate);
+ void (*print_tty_state) (struct serial *, serial_ttystate,
+ struct ui_file *);
+ int (*noflush_set_tty_state) (struct serial *, serial_ttystate,
+ serial_ttystate);
+ int (*setbaudrate) (struct serial *, int rate);
+ int (*setstopbits) (struct serial *, int num);
+ /* Wait for output to drain */
+ int (*drain_output) (struct serial *);
+ /* Change the serial device into/out of asynchronous mode, call
+ the specified function when ever there is something
+ interesting. */
+ void (*async) (struct serial *scb, int async_p);
+ };
+
+/* Add a new serial interface to the interface list */
+
+extern void serial_add_interface (struct serial_ops * optable);
+
+/* File in which to record the remote debugging session */
+
+extern void serial_log_command (const char *);
+
+#endif /* SERIAL_H */
diff --git a/contrib/gdb/gdb/signals/signals.c b/contrib/gdb/gdb/signals/signals.c
new file mode 100644
index 0000000..c808d1f
--- /dev/null
+++ b/contrib/gdb/gdb/signals/signals.c
@@ -0,0 +1,830 @@
+/* Target signal translation functions for GDB.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002 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. */
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#include "target.h"
+#include "gdb_string.h"
+#endif
+
+#include <signal.h>
+
+/* Always use __SIGRTMIN if it's available. SIGRTMIN is the lowest
+ _available_ realtime signal, not the lowest supported; glibc takes
+ several for its own use. */
+
+#ifndef REALTIME_LO
+# if defined(__SIGRTMIN)
+# define REALTIME_LO __SIGRTMIN
+# define REALTIME_HI __SIGRTMAX
+# elif defined(SIGRTMIN)
+# define REALTIME_LO SIGRTMIN
+# define REALTIME_HI SIGRTMAX
+# endif
+#endif
+
+/* This table must match in order and size the signals in enum target_signal
+ in target.h. */
+/* *INDENT-OFF* */
+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 relinquish 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"},
+ {"SIGCANCEL", "LWP internal signal"},
+ {"SIG32", "Real-time event 32"},
+ {"SIG64", "Real-time event 64"},
+ {"SIG65", "Real-time event 65"},
+ {"SIG66", "Real-time event 66"},
+ {"SIG67", "Real-time event 67"},
+ {"SIG68", "Real-time event 68"},
+ {"SIG69", "Real-time event 69"},
+ {"SIG70", "Real-time event 70"},
+ {"SIG71", "Real-time event 71"},
+ {"SIG72", "Real-time event 72"},
+ {"SIG73", "Real-time event 73"},
+ {"SIG74", "Real-time event 74"},
+ {"SIG75", "Real-time event 75"},
+ {"SIG76", "Real-time event 76"},
+ {"SIG77", "Real-time event 77"},
+ {"SIG78", "Real-time event 78"},
+ {"SIG79", "Real-time event 79"},
+ {"SIG80", "Real-time event 80"},
+ {"SIG81", "Real-time event 81"},
+ {"SIG82", "Real-time event 82"},
+ {"SIG83", "Real-time event 83"},
+ {"SIG84", "Real-time event 84"},
+ {"SIG85", "Real-time event 85"},
+ {"SIG86", "Real-time event 86"},
+ {"SIG87", "Real-time event 87"},
+ {"SIG88", "Real-time event 88"},
+ {"SIG89", "Real-time event 89"},
+ {"SIG90", "Real-time event 90"},
+ {"SIG91", "Real-time event 91"},
+ {"SIG92", "Real-time event 92"},
+ {"SIG93", "Real-time event 93"},
+ {"SIG94", "Real-time event 94"},
+ {"SIG95", "Real-time event 95"},
+ {"SIG96", "Real-time event 96"},
+ {"SIG97", "Real-time event 97"},
+ {"SIG98", "Real-time event 98"},
+ {"SIG99", "Real-time event 99"},
+ {"SIG100", "Real-time event 100"},
+ {"SIG101", "Real-time event 101"},
+ {"SIG102", "Real-time event 102"},
+ {"SIG103", "Real-time event 103"},
+ {"SIG104", "Real-time event 104"},
+ {"SIG105", "Real-time event 105"},
+ {"SIG106", "Real-time event 106"},
+ {"SIG107", "Real-time event 107"},
+ {"SIG108", "Real-time event 108"},
+ {"SIG109", "Real-time event 109"},
+ {"SIG110", "Real-time event 110"},
+ {"SIG111", "Real-time event 111"},
+ {"SIG112", "Real-time event 112"},
+ {"SIG113", "Real-time event 113"},
+ {"SIG114", "Real-time event 114"},
+ {"SIG115", "Real-time event 115"},
+ {"SIG116", "Real-time event 116"},
+ {"SIG117", "Real-time event 117"},
+ {"SIG118", "Real-time event 118"},
+ {"SIG119", "Real-time event 119"},
+ {"SIG120", "Real-time event 120"},
+ {"SIG121", "Real-time event 121"},
+ {"SIG122", "Real-time event 122"},
+ {"SIG123", "Real-time event 123"},
+ {"SIG124", "Real-time event 124"},
+ {"SIG125", "Real-time event 125"},
+ {"SIG126", "Real-time event 126"},
+ {"SIG127", "Real-time event 127"},
+
+ {"SIGINFO", "Information request"},
+
+ {NULL, "Unknown signal"},
+ {NULL, "Internal error: printing TARGET_SIGNAL_DEFAULT"},
+
+ /* Mach exceptions */
+ {"EXC_BAD_ACCESS", "Could not access memory"},
+ {"EXC_BAD_INSTRUCTION", "Illegal instruction/operand"},
+ {"EXC_ARITHMETIC", "Arithmetic exception"},
+ {"EXC_EMULATION", "Emulation instruction"},
+ {"EXC_SOFTWARE", "Software generated exception"},
+ {"EXC_BREAKPOINT", "Breakpoint"},
+
+ /* Last entry, used to check whether the table is the right size. */
+ {NULL, "TARGET_SIGNAL_MAGIC"}
+};
+/* *INDENT-ON* */
+
+
+
+/* Return the string for a signal. */
+char *
+target_signal_to_string (enum target_signal sig)
+{
+ if ((sig >= TARGET_SIGNAL_FIRST) && (sig <= TARGET_SIGNAL_LAST))
+ return signals[sig].string;
+ else
+ return signals[TARGET_SIGNAL_UNKNOWN].string;
+}
+
+/* Return the name for a signal. */
+char *
+target_signal_to_name (enum target_signal sig)
+{
+ if ((sig >= TARGET_SIGNAL_FIRST) && (sig <= TARGET_SIGNAL_LAST)
+ && signals[sig].name != NULL)
+ return signals[sig].name;
+ else
+ /* I think the code which prints this will always print it along
+ with the string, so no need to be verbose (very old comment). */
+ return "?";
+}
+
+/* Given a name, return its signal. */
+enum target_signal
+target_signal_from_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;
+ sig < TARGET_SIGNAL_LAST;
+ sig = (enum target_signal) ((int) sig + 1))
+ if (signals[sig].name != NULL
+ && strcmp (name, signals[sig].name) == 0)
+ 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 (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 (SIGCANCEL)
+ if (hostsig == SIGCANCEL)
+ return TARGET_SIGNAL_CANCEL;
+#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
+
+ /* Mach exceptions. Assumes that the values for EXC_ are positive! */
+#if defined (EXC_BAD_ACCESS) && defined (_NSIG)
+ if (hostsig == _NSIG + EXC_BAD_ACCESS)
+ return TARGET_EXC_BAD_ACCESS;
+#endif
+#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG)
+ if (hostsig == _NSIG + EXC_BAD_INSTRUCTION)
+ return TARGET_EXC_BAD_INSTRUCTION;
+#endif
+#if defined (EXC_ARITHMETIC) && defined (_NSIG)
+ if (hostsig == _NSIG + EXC_ARITHMETIC)
+ return TARGET_EXC_ARITHMETIC;
+#endif
+#if defined (EXC_EMULATION) && defined (_NSIG)
+ if (hostsig == _NSIG + EXC_EMULATION)
+ return TARGET_EXC_EMULATION;
+#endif
+#if defined (EXC_SOFTWARE) && defined (_NSIG)
+ if (hostsig == _NSIG + EXC_SOFTWARE)
+ return TARGET_EXC_SOFTWARE;
+#endif
+#if defined (EXC_BREAKPOINT) && defined (_NSIG)
+ if (hostsig == _NSIG + EXC_BREAKPOINT)
+ return TARGET_EXC_BREAKPOINT;
+#endif
+
+#if defined (SIGINFO)
+ if (hostsig == SIGINFO)
+ return TARGET_SIGNAL_INFO;
+#endif
+
+#if defined (REALTIME_LO)
+ if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI)
+ {
+ /* This block of TARGET_SIGNAL_REALTIME value is in order. */
+ if (33 <= hostsig && hostsig <= 63)
+ return (enum target_signal)
+ (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33);
+ else if (hostsig == 32)
+ return TARGET_SIGNAL_REALTIME_32;
+ else if (64 <= hostsig && hostsig <= 127)
+ return (enum target_signal)
+ (hostsig - 64 + (int) TARGET_SIGNAL_REALTIME_64);
+ else
+ error ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal");
+ }
+#endif
+
+ return TARGET_SIGNAL_UNKNOWN;
+}
+
+/* Convert a OURSIG (an enum target_signal) to the form used by the
+ target operating system (refered to as the ``host'') or zero if the
+ equivalent host signal is not available. Set/clear OURSIG_OK
+ accordingly. */
+
+static int
+do_target_signal_to_host (enum target_signal oursig,
+ int *oursig_ok)
+{
+ int retsig;
+
+ *oursig_ok = 1;
+ 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 (SIGCANCEL)
+ case TARGET_SIGNAL_CANCEL:
+ return SIGCANCEL;
+#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
+
+ /* Mach exceptions. Assumes that the values for EXC_ are positive! */
+#if defined (EXC_BAD_ACCESS) && defined (_NSIG)
+ case TARGET_EXC_BAD_ACCESS:
+ return _NSIG + EXC_BAD_ACCESS;
+#endif
+#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG)
+ case TARGET_EXC_BAD_INSTRUCTION:
+ return _NSIG + EXC_BAD_INSTRUCTION;
+#endif
+#if defined (EXC_ARITHMETIC) && defined (_NSIG)
+ case TARGET_EXC_ARITHMETIC:
+ return _NSIG + EXC_ARITHMETIC;
+#endif
+#if defined (EXC_EMULATION) && defined (_NSIG)
+ case TARGET_EXC_EMULATION:
+ return _NSIG + EXC_EMULATION;
+#endif
+#if defined (EXC_SOFTWARE) && defined (_NSIG)
+ case TARGET_EXC_SOFTWARE:
+ return _NSIG + EXC_SOFTWARE;
+#endif
+#if defined (EXC_BREAKPOINT) && defined (_NSIG)
+ case TARGET_EXC_BREAKPOINT:
+ return _NSIG + EXC_BREAKPOINT;
+#endif
+
+#if defined (SIGINFO)
+ case TARGET_SIGNAL_INFO:
+ return SIGINFO;
+#endif
+
+ default:
+#if defined (REALTIME_LO)
+ retsig = 0;
+
+ if (oursig >= TARGET_SIGNAL_REALTIME_33
+ && oursig <= TARGET_SIGNAL_REALTIME_63)
+ {
+ /* This block of signals is continuous, and
+ TARGET_SIGNAL_REALTIME_33 is 33 by definition. */
+ retsig = (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33;
+ }
+ else if (oursig == TARGET_SIGNAL_REALTIME_32)
+ {
+ /* TARGET_SIGNAL_REALTIME_32 isn't contiguous with
+ TARGET_SIGNAL_REALTIME_33. It is 32 by definition. */
+ retsig = 32;
+ }
+ else if (oursig >= TARGET_SIGNAL_REALTIME_64
+ && oursig <= TARGET_SIGNAL_REALTIME_127)
+ {
+ /* This block of signals is continuous, and
+ TARGET_SIGNAL_REALTIME_64 is 64 by definition. */
+ retsig = (int) oursig - (int) TARGET_SIGNAL_REALTIME_64 + 64;
+ }
+
+ if (retsig >= REALTIME_LO && retsig < REALTIME_HI)
+ return retsig;
+#endif
+
+ *oursig_ok = 0;
+ return 0;
+ }
+}
+
+int
+target_signal_to_host_p (enum target_signal oursig)
+{
+ int oursig_ok;
+ do_target_signal_to_host (oursig, &oursig_ok);
+ return oursig_ok;
+}
+
+int
+target_signal_to_host (enum target_signal oursig)
+{
+ int oursig_ok;
+ int targ_signo = do_target_signal_to_host (oursig, &oursig_ok);
+ if (!oursig_ok)
+ {
+ /* The user might be trying to do "signal SIGSAK" where this system
+ doesn't have SIGSAK. */
+ warning ("Signal %s does not exist on this system.\n",
+ target_signal_to_name (oursig));
+ return 0;
+ }
+ else
+ return targ_signo;
+}
+
+/* In some circumstances we allow a command to specify a numeric
+ signal. The idea is to keep these circumstances limited so that
+ users (and scripts) develop portable habits. For comparison,
+ POSIX.2 `kill' requires that 1,2,3,6,9,14, and 15 work (and using a
+ numeric signal at all is obsolescent. We are slightly more
+ lenient and allow 1-15 which should match host signal numbers on
+ most systems. Use of symbolic signal names is strongly encouraged. */
+
+enum target_signal
+target_signal_from_command (int num)
+{
+ if (num >= 1 && num <= 15)
+ return (enum target_signal) num;
+ error ("Only signals 1-15 are valid as numeric signals.\n\
+Use \"info signals\" for a list of symbolic signals.");
+}
+
+#ifndef GDBSERVER
+extern initialize_file_ftype _initialize_signals; /* -Wmissing-prototype */
+
+void
+_initialize_signals (void)
+{
+ if (strcmp (signals[TARGET_SIGNAL_LAST].string, "TARGET_SIGNAL_MAGIC") != 0)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+}
+#endif
diff --git a/contrib/gdb/gdb/sim-regno.h b/contrib/gdb/gdb/sim-regno.h
new file mode 100644
index 0000000..5a7057b
--- /dev/null
+++ b/contrib/gdb/gdb/sim-regno.h
@@ -0,0 +1,45 @@
+/* Generic remote debugging interface for simulators.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SIM_REGNO_H
+#define SIM_REGNO_H
+
+/* The REGISTER_SIM_REGNO(REGNUM) method, when there is a
+ corresponding simulator register, returns that register number as a
+ cardinal. When there is no corresponding register, it returns a
+ negative value. */
+
+enum sim_regno {
+ /* Normal sane architecture. The simulator is known to not model
+ this register. */
+ SIM_REGNO_DOES_NOT_EXIST = -1,
+ /* For possible backward compatibility. The register cache doesn't
+ have a corresponding name. Skip the register entirely. */
+ LEGACY_SIM_REGNO_IGNORE = -2
+};
+
+/* Treat all raw registers as valid. */
+
+extern int one2one_register_sim_regno (int regnum);
+
+#endif
diff --git a/contrib/gdb/gdb/sol-thread.c b/contrib/gdb/gdb/sol-thread.c
new file mode 100644
index 0000000..3ac2a34
--- /dev/null
+++ b/contrib/gdb/gdb/sol-thread.c
@@ -0,0 +1,1720 @@
+/* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 implements a sort of half target that sits between the
+ machine-independent parts of GDB and the /proc interface (procfs.c) to
+ provide access to the Solaris user-mode thread implementation.
+
+ Solaris threads are true user-mode threads, which are invoked via the thr_*
+ and pthread_* (native and Posix respectivly) interfaces. These are mostly
+ implemented in user-space, with all thread context kept in various
+ structures that live in the user's heap. These should not be confused with
+ lightweight processes (LWPs), which are implemented by the kernel, and
+ scheduled without explicit intervention by the process.
+
+ Just to confuse things a little, Solaris threads (both native and Posix) are
+ actually implemented using LWPs. In general, there are going to be more
+ threads than LWPs. There is no fixed correspondence between a thread and an
+ LWP. When a thread wants to run, it gets scheduled onto the first available
+ LWP and can therefore migrate from one LWP to another as time goes on. A
+ sleeping thread may not be associated with an LWP at all!
+
+ To make it possible to mess with threads, Sun provides a library called
+ libthread_db.so.1 (not to be confused with libthread_db.so.0, which doesn't
+ have a published interface). This interface has an upper part, which it
+ provides, and a lower part which I provide. The upper part consists of the
+ td_* routines, which allow me to find all the threads, query their state,
+ etc... The lower part consists of all of the ps_*, which are used by the
+ td_* routines to read/write memory, manipulate LWPs, lookup symbols, etc...
+ The ps_* routines actually do most of their work by calling functions in
+ procfs.c. */
+
+#include "defs.h"
+#include <thread.h>
+#include <proc_service.h>
+#include <thread_db.h>
+#include "gdbthread.h"
+#include "target.h"
+#include "inferior.h"
+#include <fcntl.h>
+#include "gdb_stat.h"
+#include <dlfcn.h>
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "symfile.h"
+
+#include "gdb_string.h"
+
+extern struct target_ops sol_thread_ops; /* Forward declaration */
+extern struct target_ops sol_core_ops; /* Forward declaration */
+
+/* place to store core_ops before we overwrite it */
+static struct target_ops orig_core_ops;
+
+struct target_ops sol_thread_ops;
+struct target_ops sol_core_ops;
+
+extern int procfs_suppress_run;
+extern struct target_ops procfs_ops; /* target vector for procfs.c */
+extern struct target_ops core_ops; /* target vector for corelow.c */
+extern char *procfs_pid_to_str (ptid_t ptid);
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* This struct is defined by us, but mainly used for the proc_service interface.
+ We don't have much use for it, except as a handy place to get a real pid
+ for memory accesses. */
+
+struct ps_prochandle
+ {
+ ptid_t ptid;
+ };
+
+struct string_map
+ {
+ int num;
+ char *str;
+ };
+
+static struct ps_prochandle main_ph;
+static td_thragent_t *main_ta;
+static int sol_thread_active = 0;
+
+static char *td_err_string (td_err_e errcode);
+static char *td_state_string (td_thr_state_e statecode);
+static ptid_t thread_to_lwp (ptid_t thread_id, int default_lwp);
+static void sol_thread_resume (ptid_t ptid, int step, enum target_signal signo);
+static ptid_t lwp_to_thread (ptid_t lwp);
+static int sol_thread_alive (ptid_t ptid);
+static void sol_core_close (int quitting);
+
+static void init_sol_thread_ops (void);
+static void init_sol_core_ops (void);
+
+/* Default definitions: These must be defined in tm.h
+ if they are to be shared with a process module such as procfs. */
+
+#define GET_PID(ptid) ptid_get_pid (ptid)
+#define GET_LWP(ptid) ptid_get_lwp (ptid)
+#define GET_THREAD(ptid) ptid_get_tid (ptid)
+
+#define is_lwp(ptid) (GET_LWP (ptid) != 0)
+#define is_thread(ptid) (GET_THREAD (ptid) != 0)
+
+#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
+#define BUILD_THREAD(tid, pid) ptid_build (pid, 0, tid)
+
+/* Pointers to routines from lithread_db resolved by dlopen() */
+
+static void (*p_td_log) (const int on_off);
+static td_err_e (*p_td_ta_new) (const struct ps_prochandle * ph_p,
+ td_thragent_t ** ta_pp);
+static td_err_e (*p_td_ta_delete) (td_thragent_t * ta_p);
+static td_err_e (*p_td_init) (void);
+static td_err_e (*p_td_ta_get_ph) (const td_thragent_t * ta_p,
+ struct ps_prochandle ** ph_pp);
+static td_err_e (*p_td_ta_get_nthreads) (const td_thragent_t * ta_p,
+ int *nthread_p);
+static td_err_e (*p_td_ta_tsd_iter) (const td_thragent_t * ta_p,
+ td_key_iter_f * cb,
+ void *cbdata_p);
+static td_err_e (*p_td_ta_thr_iter) (const td_thragent_t * ta_p,
+ td_thr_iter_f * cb,
+ void *cbdata_p,
+ td_thr_state_e state,
+ int ti_pri,
+ sigset_t * ti_sigmask_p,
+ unsigned ti_user_flags);
+static td_err_e (*p_td_thr_validate) (const td_thrhandle_t * th_p);
+static td_err_e (*p_td_thr_tsd) (const td_thrhandle_t * th_p,
+ const thread_key_t key,
+ void **data_pp);
+static td_err_e (*p_td_thr_get_info) (const td_thrhandle_t * th_p,
+ td_thrinfo_t * ti_p);
+static td_err_e (*p_td_thr_getfpregs) (const td_thrhandle_t * th_p,
+ prfpregset_t * fpregset);
+static td_err_e (*p_td_thr_getxregsize) (const td_thrhandle_t * th_p,
+ int *xregsize);
+static td_err_e (*p_td_thr_getxregs) (const td_thrhandle_t * th_p,
+ const caddr_t xregset);
+static td_err_e (*p_td_thr_sigsetmask) (const td_thrhandle_t * th_p,
+ const sigset_t ti_sigmask);
+static td_err_e (*p_td_thr_setprio) (const td_thrhandle_t * th_p,
+ const int ti_pri);
+static td_err_e (*p_td_thr_setsigpending) (const td_thrhandle_t * th_p,
+ const uchar_t ti_pending_flag,
+ const sigset_t ti_pending);
+static td_err_e (*p_td_thr_setfpregs) (const td_thrhandle_t * th_p,
+ const prfpregset_t * fpregset);
+static td_err_e (*p_td_thr_setxregs) (const td_thrhandle_t * th_p,
+ const caddr_t xregset);
+static td_err_e (*p_td_ta_map_id2thr) (const td_thragent_t * ta_p,
+ thread_t tid,
+ td_thrhandle_t * th_p);
+static td_err_e (*p_td_ta_map_lwp2thr) (const td_thragent_t * ta_p,
+ lwpid_t lwpid,
+ td_thrhandle_t * th_p);
+static td_err_e (*p_td_thr_getgregs) (const td_thrhandle_t * th_p,
+ prgregset_t regset);
+static td_err_e (*p_td_thr_setgregs) (const td_thrhandle_t * th_p,
+ const prgregset_t regset);
+
+/*
+
+ LOCAL FUNCTION
+
+ td_err_string - Convert a thread_db error code to a string
+
+ SYNOPSIS
+
+ char * td_err_string (errcode)
+
+ DESCRIPTION
+
+ Return the thread_db error string associated with errcode. If errcode
+ is unknown, then return a message.
+
+ */
+
+static char *
+td_err_string (td_err_e errcode)
+{
+ static struct string_map
+ td_err_table[] =
+ {
+ {TD_OK, "generic \"call succeeded\""},
+ {TD_ERR, "generic error."},
+ {TD_NOTHR, "no thread can be found to satisfy query"},
+ {TD_NOSV, "no synch. variable can be found to satisfy query"},
+ {TD_NOLWP, "no lwp can be found to satisfy query"},
+ {TD_BADPH, "invalid process handle"},
+ {TD_BADTH, "invalid thread handle"},
+ {TD_BADSH, "invalid synchronization handle"},
+ {TD_BADTA, "invalid thread agent"},
+ {TD_BADKEY, "invalid key"},
+ {TD_NOMSG, "td_thr_event_getmsg() called when there was no message"},
+ {TD_NOFPREGS, "FPU register set not available for given thread"},
+ {TD_NOLIBTHREAD, "application not linked with libthread"},
+ {TD_NOEVENT, "requested event is not supported"},
+ {TD_NOCAPAB, "capability not available"},
+ {TD_DBERR, "Debugger service failed"},
+ {TD_NOAPLIC, "Operation not applicable to"},
+ {TD_NOTSD, "No thread specific data for this thread"},
+ {TD_MALLOC, "Malloc failed"},
+ {TD_PARTIALREG, "Only part of register set was written/read"},
+ {TD_NOXREGS, "X register set not available for given thread"}
+ };
+ const int td_err_size = sizeof td_err_table / sizeof (struct string_map);
+ int i;
+ static char buf[50];
+
+ for (i = 0; i < td_err_size; i++)
+ if (td_err_table[i].num == errcode)
+ return td_err_table[i].str;
+
+ sprintf (buf, "Unknown thread_db error code: %d", errcode);
+
+ return buf;
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ td_state_string - Convert a thread_db state code to a string
+
+ SYNOPSIS
+
+ char * td_state_string (statecode)
+
+ DESCRIPTION
+
+ Return the thread_db state string associated with statecode. If
+ statecode is unknown, then return a message.
+
+ */
+
+static char *
+td_state_string (td_thr_state_e statecode)
+{
+ static struct string_map
+ td_thr_state_table[] =
+ {
+ {TD_THR_ANY_STATE, "any state"},
+ {TD_THR_UNKNOWN, "unknown"},
+ {TD_THR_STOPPED, "stopped"},
+ {TD_THR_RUN, "run"},
+ {TD_THR_ACTIVE, "active"},
+ {TD_THR_ZOMBIE, "zombie"},
+ {TD_THR_SLEEP, "sleep"},
+ {TD_THR_STOPPED_ASLEEP, "stopped asleep"}
+ };
+ const int td_thr_state_table_size = sizeof td_thr_state_table / sizeof (struct string_map);
+ int i;
+ static char buf[50];
+
+ for (i = 0; i < td_thr_state_table_size; i++)
+ if (td_thr_state_table[i].num == statecode)
+ return td_thr_state_table[i].str;
+
+ sprintf (buf, "Unknown thread_db state code: %d", statecode);
+
+ return buf;
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ thread_to_lwp - Convert a Posix or Solaris thread id to a LWP id.
+
+ SYNOPSIS
+
+ tpid_t thread_to_lwp (thread_id, default_lwp)
+
+ DESCRIPTION
+
+ This function converts a Posix or Solaris thread id to a lightweight
+ process id. If thread_id is non-existent, that's an error. If it's
+ an inactive thread, then we return default_lwp.
+
+ NOTES
+
+ This function probably shouldn't call error()...
+
+ */
+
+static ptid_t
+thread_to_lwp (ptid_t thread_id, int default_lwp)
+{
+ td_thrinfo_t ti;
+ td_thrhandle_t th;
+ td_err_e val;
+
+ if (is_lwp (thread_id))
+ return thread_id; /* It's already an LWP id */
+
+ /* It's a thread. Convert to lwp */
+
+ val = p_td_ta_map_id2thr (main_ta, GET_THREAD (thread_id), &th);
+ if (val == TD_NOTHR)
+ return pid_to_ptid (-1); /* thread must have terminated */
+ else if (val != TD_OK)
+ error ("thread_to_lwp: td_ta_map_id2thr %s", td_err_string (val));
+
+ val = p_td_thr_get_info (&th, &ti);
+ if (val == TD_NOTHR)
+ return pid_to_ptid (-1); /* thread must have terminated */
+ else if (val != TD_OK)
+ error ("thread_to_lwp: td_thr_get_info: %s", td_err_string (val));
+
+ if (ti.ti_state != TD_THR_ACTIVE)
+ {
+ if (default_lwp != -1)
+ return pid_to_ptid (default_lwp);
+ error ("thread_to_lwp: thread state not active: %s",
+ td_state_string (ti.ti_state));
+ }
+
+ return BUILD_LWP (ti.ti_lid, PIDGET (thread_id));
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ lwp_to_thread - Convert a LWP id to a Posix or Solaris thread id.
+
+ SYNOPSIS
+
+ int lwp_to_thread (lwp_id)
+
+ DESCRIPTION
+
+ This function converts a lightweight process id to a Posix or Solaris
+ thread id. If thread_id is non-existent, that's an error.
+
+ NOTES
+
+ This function probably shouldn't call error()...
+
+ */
+
+static ptid_t
+lwp_to_thread (ptid_t lwp)
+{
+ td_thrinfo_t ti;
+ td_thrhandle_t th;
+ td_err_e val;
+
+ if (is_thread (lwp))
+ return lwp; /* It's already a thread id */
+
+ /* It's an lwp. Convert it to a thread id. */
+
+ if (!sol_thread_alive (lwp))
+ return pid_to_ptid (-1); /* defunct lwp */
+
+ val = p_td_ta_map_lwp2thr (main_ta, GET_LWP (lwp), &th);
+ if (val == TD_NOTHR)
+ return pid_to_ptid (-1); /* thread must have terminated */
+ else if (val != TD_OK)
+ error ("lwp_to_thread: td_ta_map_lwp2thr: %s.", td_err_string (val));
+
+ val = p_td_thr_validate (&th);
+ if (val == TD_NOTHR)
+ return lwp; /* libthread doesn't know about it;
+ just return lwp */
+ else if (val != TD_OK)
+ error ("lwp_to_thread: td_thr_validate: %s.", td_err_string (val));
+
+ val = p_td_thr_get_info (&th, &ti);
+ if (val == TD_NOTHR)
+ return pid_to_ptid (-1); /* thread must have terminated */
+ else if (val != TD_OK)
+ error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val));
+
+ return BUILD_THREAD (ti.ti_tid, PIDGET (lwp));
+}
+
+
+/* Most target vector functions from here on actually just pass through to
+ procfs.c, as they don't need to do anything specific for threads. */
+
+static void
+sol_thread_open (char *arg, int from_tty)
+{
+ procfs_ops.to_open (arg, from_tty);
+}
+
+/* Attach to process PID, then initialize for debugging it
+ and wait for the trace-trap that results from attaching. */
+
+static void
+sol_thread_attach (char *args, int from_tty)
+{
+ procfs_ops.to_attach (args, from_tty);
+
+ /* Must get symbols from solibs before libthread_db can run! */
+ SOLIB_ADD ((char *) 0, from_tty, (struct target_ops *) 0, auto_solib_add);
+
+ if (sol_thread_active)
+ {
+ printf_filtered ("sol-thread active.\n");
+ main_ph.ptid = inferior_ptid; /* Save for xfer_memory */
+ push_target (&sol_thread_ops);
+ inferior_ptid = lwp_to_thread (inferior_ptid);
+ if (PIDGET (inferior_ptid) == -1)
+ inferior_ptid = main_ph.ptid;
+ else
+ add_thread (inferior_ptid);
+ }
+ /* XXX - might want to iterate over all the threads and register them. */
+}
+
+/* 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
+sol_thread_detach (char *args, int from_tty)
+{
+ inferior_ptid = pid_to_ptid (PIDGET (main_ph.ptid));
+ unpush_target (&sol_thread_ops);
+ procfs_ops.to_detach (args, from_tty);
+}
+
+/* Resume execution of process PID. If STEP is nozero, then
+ just single step it. If SIGNAL is nonzero, restart it with that
+ signal activated. We may have to convert pid from a thread-id to an LWP id
+ for procfs. */
+
+static void
+sol_thread_resume (ptid_t ptid, int step, enum target_signal signo)
+{
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = thread_to_lwp (inferior_ptid, PIDGET (main_ph.ptid));
+ if (PIDGET (inferior_ptid) == -1)
+ inferior_ptid = procfs_first_available ();
+
+ if (PIDGET (ptid) != -1)
+ {
+ ptid_t save_ptid = ptid;
+
+ ptid = thread_to_lwp (ptid, -2);
+ if (PIDGET (ptid) == -2) /* Inactive thread */
+ error ("This version of Solaris can't start inactive threads.");
+ if (info_verbose && PIDGET (ptid) == -1)
+ warning ("Specified thread %ld seems to have terminated",
+ GET_THREAD (save_ptid));
+ }
+
+ procfs_ops.to_resume (ptid, step, signo);
+
+ do_cleanups (old_chain);
+}
+
+/* Wait for any threads to stop. We may have to convert PID from a thread id
+ to a LWP id, and vice versa on the way out. */
+
+static ptid_t
+sol_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ ptid_t rtnval;
+ ptid_t save_ptid;
+ struct cleanup *old_chain;
+
+ save_ptid = inferior_ptid;
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = thread_to_lwp (inferior_ptid, PIDGET (main_ph.ptid));
+ if (PIDGET (inferior_ptid) == -1)
+ inferior_ptid = procfs_first_available ();
+
+ if (PIDGET (ptid) != -1)
+ {
+ ptid_t save_ptid = ptid;
+
+ ptid = thread_to_lwp (ptid, -2);
+ if (PIDGET (ptid) == -2) /* Inactive thread */
+ error ("This version of Solaris can't start inactive threads.");
+ if (info_verbose && PIDGET (ptid) == -1)
+ warning ("Specified thread %ld seems to have terminated",
+ GET_THREAD (save_ptid));
+ }
+
+ rtnval = procfs_ops.to_wait (ptid, ourstatus);
+
+ if (ourstatus->kind != TARGET_WAITKIND_EXITED)
+ {
+ /* Map the LWP of interest back to the appropriate thread ID */
+ rtnval = lwp_to_thread (rtnval);
+ if (PIDGET (rtnval) == -1)
+ rtnval = save_ptid;
+
+ /* See if we have a new thread */
+ if (is_thread (rtnval)
+ && !ptid_equal (rtnval, save_ptid)
+ && !in_thread_list (rtnval))
+ {
+ printf_filtered ("[New %s]\n", target_pid_to_str (rtnval));
+ add_thread (rtnval);
+ }
+ }
+
+ /* During process initialization, we may get here without the thread package
+ being initialized, since that can only happen after we've found the shared
+ libs. */
+
+ do_cleanups (old_chain);
+
+ return rtnval;
+}
+
+static void
+sol_thread_fetch_registers (int regno)
+{
+ thread_t thread;
+ td_thrhandle_t thandle;
+ td_err_e val;
+ prgregset_t gregset;
+ prfpregset_t fpregset;
+#if 0
+ int xregsize;
+ caddr_t xregset;
+#endif
+
+ if (!is_thread (inferior_ptid))
+ { /* LWP: pass the request on to procfs.c */
+ if (target_has_execution)
+ procfs_ops.to_fetch_registers (regno);
+ else
+ orig_core_ops.to_fetch_registers (regno);
+ return;
+ }
+
+ /* Solaris thread: convert inferior_ptid into a td_thrhandle_t */
+
+ thread = GET_THREAD (inferior_ptid);
+
+ if (thread == 0)
+ error ("sol_thread_fetch_registers: thread == 0");
+
+ val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
+ if (val != TD_OK)
+ error ("sol_thread_fetch_registers: td_ta_map_id2thr: %s",
+ td_err_string (val));
+
+ /* Get the integer regs */
+
+ val = p_td_thr_getgregs (&thandle, gregset);
+ if (val != TD_OK
+ && val != TD_PARTIALREG)
+ error ("sol_thread_fetch_registers: td_thr_getgregs %s",
+ td_err_string (val));
+
+ /* For the sparc, TD_PARTIALREG means that only i0->i7, l0->l7, pc and sp
+ are saved (by a thread context switch). */
+
+ /* And, now the fp regs */
+
+ val = p_td_thr_getfpregs (&thandle, &fpregset);
+ if (val != TD_OK
+ && val != TD_NOFPREGS)
+ error ("sol_thread_fetch_registers: td_thr_getfpregs %s",
+ td_err_string (val));
+
+/* Note that we must call supply_{g fp}regset *after* calling the td routines
+ because the td routines call ps_lget* which affect the values stored in the
+ registers array. */
+
+ supply_gregset ((gdb_gregset_t *) &gregset);
+ supply_fpregset ((gdb_fpregset_t *) &fpregset);
+
+#if 0
+/* thread_db doesn't seem to handle this right */
+ val = td_thr_getxregsize (&thandle, &xregsize);
+ if (val != TD_OK && val != TD_NOXREGS)
+ error ("sol_thread_fetch_registers: td_thr_getxregsize %s",
+ td_err_string (val));
+
+ if (val == TD_OK)
+ {
+ xregset = alloca (xregsize);
+ val = td_thr_getxregs (&thandle, xregset);
+ if (val != TD_OK)
+ error ("sol_thread_fetch_registers: td_thr_getxregs %s",
+ td_err_string (val));
+ }
+#endif
+}
+
+static void
+sol_thread_store_registers (int regno)
+{
+ thread_t thread;
+ td_thrhandle_t thandle;
+ td_err_e val;
+ prgregset_t gregset;
+ prfpregset_t fpregset;
+#if 0
+ int xregsize;
+ caddr_t xregset;
+#endif
+
+ if (!is_thread (inferior_ptid))
+ { /* LWP: pass the request on to procfs.c */
+ procfs_ops.to_store_registers (regno);
+ return;
+ }
+
+ /* Solaris thread: convert inferior_ptid into a td_thrhandle_t */
+
+ thread = GET_THREAD (inferior_ptid);
+
+ val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
+ if (val != TD_OK)
+ error ("sol_thread_store_registers: td_ta_map_id2thr %s",
+ td_err_string (val));
+
+ if (regno != -1)
+ { /* Not writing all the regs */
+ char old_value[MAX_REGISTER_SIZE];
+
+ /* Save new register value. */
+ regcache_collect (regno, old_value);
+
+ val = p_td_thr_getgregs (&thandle, gregset);
+ if (val != TD_OK)
+ error ("sol_thread_store_registers: td_thr_getgregs %s",
+ td_err_string (val));
+ val = p_td_thr_getfpregs (&thandle, &fpregset);
+ if (val != TD_OK)
+ error ("sol_thread_store_registers: td_thr_getfpregs %s",
+ td_err_string (val));
+
+ /* Restore new register value. */
+ supply_register (regno, old_value);
+
+#if 0
+/* thread_db doesn't seem to handle this right */
+ val = td_thr_getxregsize (&thandle, &xregsize);
+ if (val != TD_OK && val != TD_NOXREGS)
+ error ("sol_thread_store_registers: td_thr_getxregsize %s",
+ td_err_string (val));
+
+ if (val == TD_OK)
+ {
+ xregset = alloca (xregsize);
+ val = td_thr_getxregs (&thandle, xregset);
+ if (val != TD_OK)
+ error ("sol_thread_store_registers: td_thr_getxregs %s",
+ td_err_string (val));
+ }
+#endif
+ }
+
+ fill_gregset ((gdb_gregset_t *) &gregset, regno);
+ fill_fpregset ((gdb_fpregset_t *) &fpregset, regno);
+
+ val = p_td_thr_setgregs (&thandle, gregset);
+ if (val != TD_OK)
+ error ("sol_thread_store_registers: td_thr_setgregs %s",
+ td_err_string (val));
+ val = p_td_thr_setfpregs (&thandle, &fpregset);
+ if (val != TD_OK)
+ error ("sol_thread_store_registers: td_thr_setfpregs %s",
+ td_err_string (val));
+
+#if 0
+/* thread_db doesn't seem to handle this right */
+ val = td_thr_getxregsize (&thandle, &xregsize);
+ if (val != TD_OK && val != TD_NOXREGS)
+ error ("sol_thread_store_registers: td_thr_getxregsize %s",
+ td_err_string (val));
+
+ /* Should probably do something about writing the xregs here, but what are
+ they? */
+#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
+sol_thread_prepare_to_store (void)
+{
+ procfs_ops.to_prepare_to_store ();
+}
+
+/* Transfer LEN bytes between GDB address MYADDR and target address
+ MEMADDR. If DOWRITE is non-zero, transfer them to the target,
+ otherwise transfer them from the target. TARGET is unused.
+
+ Returns the number of bytes transferred. */
+
+static int
+sol_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
+ struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ int retval;
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ if (is_thread (inferior_ptid) || /* A thread */
+ !target_thread_alive (inferior_ptid)) /* An lwp, but not alive */
+ inferior_ptid = procfs_first_available (); /* Find any live lwp. */
+ /* Note: don't need to call switch_to_thread; we're just reading memory. */
+
+ if (target_has_execution)
+ retval = procfs_ops.to_xfer_memory (memaddr, myaddr, len,
+ dowrite, attrib, target);
+ else
+ retval = orig_core_ops.to_xfer_memory (memaddr, myaddr, len,
+ dowrite, attrib, target);
+
+ do_cleanups (old_chain);
+
+ return retval;
+}
+
+/* Perform partial transfers on OBJECT. See target_read_partial
+ and target_write_partial for details of each variant. One, and
+ only one, of readbuf or writebuf must be non-NULL. */
+
+static LONGEST
+sol_thread_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ int retval;
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ if (is_thread (inferior_ptid) || /* A thread */
+ !target_thread_alive (inferior_ptid)) /* An lwp, but not alive */
+ inferior_ptid = procfs_first_available (); /* Find any live lwp. */
+ /* Note: don't need to call switch_to_thread; we're just reading memory. */
+
+ if (target_has_execution)
+ retval = procfs_ops.to_xfer_partial (ops, object, annex,
+ readbuf, writebuf, offset, len);
+ else
+ retval = orig_core_ops.to_xfer_partial (ops, object, annex,
+ readbuf, writebuf, offset, len);
+
+ do_cleanups (old_chain);
+
+ return retval;
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+sol_thread_files_info (struct target_ops *ignore)
+{
+ procfs_ops.to_files_info (ignore);
+}
+
+static void
+sol_thread_kill_inferior (void)
+{
+ procfs_ops.to_kill ();
+}
+
+static void
+sol_thread_notice_signals (ptid_t ptid)
+{
+ procfs_ops.to_notice_signals (pid_to_ptid (PIDGET (ptid)));
+}
+
+/* Fork an inferior process, and start debugging it with /proc. */
+
+static void
+sol_thread_create_inferior (char *exec_file, char *allargs, char **env)
+{
+ procfs_ops.to_create_inferior (exec_file, allargs, env);
+
+ if (sol_thread_active && !ptid_equal (inferior_ptid, null_ptid))
+ {
+ main_ph.ptid = inferior_ptid; /* Save for xfer_memory */
+
+ push_target (&sol_thread_ops);
+
+ inferior_ptid = lwp_to_thread (inferior_ptid);
+ if (PIDGET (inferior_ptid) == -1)
+ inferior_ptid = main_ph.ptid;
+
+ if (!in_thread_list (inferior_ptid))
+ add_thread (inferior_ptid);
+ }
+}
+
+/* This routine is called whenever a new symbol table is read in, or when all
+ symbol tables are removed. libthread_db can only be initialized when it
+ finds the right variables in libthread.so. Since it's a shared library,
+ those variables don't show up until the library gets mapped and the symbol
+ table is read in. */
+
+/* This new_objfile event is now managed by a chained function pointer.
+ * It is the callee's responsability to call the next client on the chain.
+ */
+
+/* Saved pointer to previous owner of the new_objfile event. */
+static void (*target_new_objfile_chain) (struct objfile *);
+
+void
+sol_thread_new_objfile (struct objfile *objfile)
+{
+ td_err_e val;
+
+ if (!objfile)
+ {
+ sol_thread_active = 0;
+ goto quit;
+ }
+
+ /* don't do anything if init failed to resolve the libthread_db library */
+ if (!procfs_suppress_run)
+ goto quit;
+
+ /* Now, initialize the thread debugging library. This needs to be done after
+ the shared libraries are located because it needs information from the
+ user's thread library. */
+
+ val = p_td_init ();
+ if (val != TD_OK)
+ {
+ warning ("sol_thread_new_objfile: td_init: %s", td_err_string (val));
+ goto quit;
+ }
+
+ val = p_td_ta_new (&main_ph, &main_ta);
+ if (val == TD_NOLIBTHREAD)
+ goto quit;
+ else if (val != TD_OK)
+ {
+ warning ("sol_thread_new_objfile: td_ta_new: %s", td_err_string (val));
+ goto quit;
+ }
+
+ sol_thread_active = 1;
+quit:
+ /* Call predecessor on chain, if any. */
+ if (target_new_objfile_chain)
+ target_new_objfile_chain (objfile);
+}
+
+/* Clean up after the inferior dies. */
+
+static void
+sol_thread_mourn_inferior (void)
+{
+ unpush_target (&sol_thread_ops);
+ procfs_ops.to_mourn_inferior ();
+}
+
+/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
+
+static int
+sol_thread_can_run (void)
+{
+ return procfs_suppress_run;
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ sol_thread_alive - test thread for "aliveness"
+
+ SYNOPSIS
+
+ static bool sol_thread_alive (ptid_t ptid);
+
+ DESCRIPTION
+
+ returns true if thread still active in inferior.
+
+ */
+
+static int
+sol_thread_alive (ptid_t ptid)
+{
+ if (is_thread (ptid)) /* non-kernel thread */
+ {
+ td_err_e val;
+ td_thrhandle_t th;
+ int pid;
+
+ pid = GET_THREAD (ptid);
+ if ((val = p_td_ta_map_id2thr (main_ta, pid, &th)) != TD_OK)
+ return 0; /* thread not found */
+ if ((val = p_td_thr_validate (&th)) != TD_OK)
+ return 0; /* thread not valid */
+ return 1; /* known thread: return true */
+ }
+ else
+ /* kernel thread (LWP): let procfs test it */
+ {
+ if (target_has_execution)
+ return procfs_ops.to_thread_alive (ptid);
+ else
+ return orig_core_ops.to_thread_alive (ptid);
+ }
+}
+
+static void
+sol_thread_stop (void)
+{
+ procfs_ops.to_stop ();
+}
+
+/* These routines implement the lower half of the thread_db interface. Ie: the
+ ps_* routines. */
+
+/* Various versions of <proc_service.h> have slightly
+ different function prototypes. In particular, we have
+
+ NEWER OLDER
+ struct ps_prochandle * const struct ps_prochandle *
+ void* char*
+ const void* char*
+ int size_t
+
+ Which one you have depends on solaris version and what
+ patches you've applied. On the theory that there are
+ only two major variants, we have configure check the
+ prototype of ps_pdwrite (), and use that info to make
+ appropriate typedefs here. */
+
+#ifdef PROC_SERVICE_IS_OLD
+typedef const struct ps_prochandle *gdb_ps_prochandle_t;
+typedef char *gdb_ps_read_buf_t;
+typedef char *gdb_ps_write_buf_t;
+typedef int gdb_ps_size_t;
+typedef paddr_t gdb_ps_addr_t;
+#else
+typedef struct ps_prochandle *gdb_ps_prochandle_t;
+typedef void *gdb_ps_read_buf_t;
+typedef const void *gdb_ps_write_buf_t;
+typedef size_t gdb_ps_size_t;
+typedef psaddr_t gdb_ps_addr_t;
+#endif
+
+
+/* The next four routines are called by thread_db to tell us to stop and stop
+ a particular process or lwp. Since GDB ensures that these are all stopped
+ by the time we call anything in thread_db, these routines need to do
+ nothing. */
+
+/* Process stop */
+
+ps_err_e
+ps_pstop (gdb_ps_prochandle_t ph)
+{
+ return PS_OK;
+}
+
+/* Process continue */
+
+ps_err_e
+ps_pcontinue (gdb_ps_prochandle_t ph)
+{
+ return PS_OK;
+}
+
+/* LWP stop */
+
+ps_err_e
+ps_lstop (gdb_ps_prochandle_t ph, lwpid_t lwpid)
+{
+ return PS_OK;
+}
+
+/* LWP continue */
+
+ps_err_e
+ps_lcontinue (gdb_ps_prochandle_t ph, lwpid_t lwpid)
+{
+ return PS_OK;
+}
+
+/* Looks up the symbol LD_SYMBOL_NAME in the debugger's symbol table. */
+
+ps_err_e
+ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *ld_object_name,
+ const char *ld_symbol_name, gdb_ps_addr_t * ld_symbol_addr)
+{
+ struct minimal_symbol *ms;
+
+ ms = lookup_minimal_symbol (ld_symbol_name, NULL, NULL);
+
+ if (!ms)
+ return PS_NOSYM;
+
+ *ld_symbol_addr = SYMBOL_VALUE_ADDRESS (ms);
+
+ return PS_OK;
+}
+
+/* Common routine for reading and writing memory. */
+
+static ps_err_e
+rw_common (int dowrite, const struct ps_prochandle *ph, gdb_ps_addr_t addr,
+ char *buf, int size)
+{
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ if (is_thread (inferior_ptid) || /* A thread */
+ !target_thread_alive (inferior_ptid)) /* An lwp, but not alive */
+ inferior_ptid = procfs_first_available (); /* Find any live lwp. */
+ /* Note: don't need to call switch_to_thread; we're just reading memory. */
+
+#if defined (__sparcv9)
+ /* For Sparc64 cross Sparc32, make sure the address has not been
+ accidentally sign-extended (or whatever) to beyond 32 bits. */
+ if (bfd_get_arch_size (exec_bfd) == 32)
+ addr &= 0xffffffff;
+#endif
+
+ while (size > 0)
+ {
+ int cc;
+
+ /* FIXME: passing 0 as attrib argument. */
+ if (target_has_execution)
+ cc = procfs_ops.to_xfer_memory (addr, buf, size,
+ dowrite, 0, &procfs_ops);
+ else
+ cc = orig_core_ops.to_xfer_memory (addr, buf, size,
+ dowrite, 0, &core_ops);
+
+ if (cc < 0)
+ {
+ if (dowrite == 0)
+ print_sys_errmsg ("rw_common (): read", errno);
+ else
+ print_sys_errmsg ("rw_common (): write", errno);
+
+ do_cleanups (old_chain);
+
+ return PS_ERR;
+ }
+ else if (cc == 0)
+ {
+ if (dowrite == 0)
+ warning ("rw_common (): unable to read at addr 0x%lx",
+ (long) addr);
+ else
+ warning ("rw_common (): unable to write at addr 0x%lx",
+ (long) addr);
+
+ do_cleanups (old_chain);
+
+ return PS_ERR;
+ }
+
+ size -= cc;
+ buf += cc;
+ }
+
+ do_cleanups (old_chain);
+
+ return PS_OK;
+}
+
+/* Copies SIZE bytes from target process .data segment to debugger memory. */
+
+ps_err_e
+ps_pdread (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
+ gdb_ps_read_buf_t buf, gdb_ps_size_t size)
+{
+ return rw_common (0, ph, addr, buf, size);
+}
+
+/* Copies SIZE bytes from debugger memory .data segment to target process. */
+
+ps_err_e
+ps_pdwrite (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
+ gdb_ps_write_buf_t buf, gdb_ps_size_t size)
+{
+ return rw_common (1, ph, addr, (char *) buf, size);
+}
+
+/* Copies SIZE bytes from target process .text segment to debugger memory. */
+
+ps_err_e
+ps_ptread (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
+ gdb_ps_read_buf_t buf, gdb_ps_size_t size)
+{
+ return rw_common (0, ph, addr, buf, size);
+}
+
+/* Copies SIZE bytes from debugger memory .text segment to target process. */
+
+ps_err_e
+ps_ptwrite (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
+ gdb_ps_write_buf_t buf, gdb_ps_size_t size)
+{
+ return rw_common (1, ph, addr, (char *) buf, size);
+}
+
+/* Get integer regs for LWP */
+
+ps_err_e
+ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ prgregset_t gregset)
+{
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
+
+ if (target_has_execution)
+ procfs_ops.to_fetch_registers (-1);
+ else
+ orig_core_ops.to_fetch_registers (-1);
+ fill_gregset ((gdb_gregset_t *) gregset, -1);
+
+ do_cleanups (old_chain);
+
+ return PS_OK;
+}
+
+/* Set integer regs for LWP */
+
+ps_err_e
+ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ const prgregset_t gregset)
+{
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
+
+ supply_gregset ((gdb_gregset_t *) gregset);
+ if (target_has_execution)
+ procfs_ops.to_store_registers (-1);
+ else
+ orig_core_ops.to_store_registers (-1);
+
+ do_cleanups (old_chain);
+
+ return PS_OK;
+}
+
+/* Log a message (sends to gdb_stderr). */
+
+void
+ps_plog (const char *fmt,...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+
+ vfprintf_filtered (gdb_stderr, fmt, args);
+}
+
+/* Get size of extra register set. Currently a noop. */
+
+ps_err_e
+ps_lgetxregsize (gdb_ps_prochandle_t ph, lwpid_t lwpid, int *xregsize)
+{
+#if 0
+ int lwp_fd;
+ int regsize;
+ ps_err_e val;
+
+ val = get_lwp_fd (ph, lwpid, &lwp_fd);
+ if (val != PS_OK)
+ return val;
+
+ if (ioctl (lwp_fd, PIOCGXREGSIZE, &regsize))
+ {
+ if (errno == EINVAL)
+ return PS_NOFREGS; /* XXX Wrong code, but this is the closest
+ thing in proc_service.h */
+
+ print_sys_errmsg ("ps_lgetxregsize (): PIOCGXREGSIZE", errno);
+ return PS_ERR;
+ }
+#endif
+
+ return PS_OK;
+}
+
+/* Get extra register set. Currently a noop. */
+
+ps_err_e
+ps_lgetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
+{
+#if 0
+ int lwp_fd;
+ ps_err_e val;
+
+ val = get_lwp_fd (ph, lwpid, &lwp_fd);
+ if (val != PS_OK)
+ return val;
+
+ if (ioctl (lwp_fd, PIOCGXREG, xregset))
+ {
+ print_sys_errmsg ("ps_lgetxregs (): PIOCGXREG", errno);
+ return PS_ERR;
+ }
+#endif
+
+ return PS_OK;
+}
+
+/* Set extra register set. Currently a noop. */
+
+ps_err_e
+ps_lsetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
+{
+#if 0
+ int lwp_fd;
+ ps_err_e val;
+
+ val = get_lwp_fd (ph, lwpid, &lwp_fd);
+ if (val != PS_OK)
+ return val;
+
+ if (ioctl (lwp_fd, PIOCSXREG, xregset))
+ {
+ print_sys_errmsg ("ps_lsetxregs (): PIOCSXREG", errno);
+ return PS_ERR;
+ }
+#endif
+
+ return PS_OK;
+}
+
+/* Get floating-point regs for LWP */
+
+ps_err_e
+ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ prfpregset_t * fpregset)
+{
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
+
+ if (target_has_execution)
+ procfs_ops.to_fetch_registers (-1);
+ else
+ orig_core_ops.to_fetch_registers (-1);
+ fill_fpregset ((gdb_fpregset_t *) fpregset, -1);
+
+ do_cleanups (old_chain);
+
+ return PS_OK;
+}
+
+/* Set floating-point regs for LWP */
+
+ps_err_e
+ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ const prfpregset_t * fpregset)
+{
+ struct cleanup *old_chain;
+
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
+
+ supply_fpregset ((gdb_fpregset_t *) fpregset);
+ if (target_has_execution)
+ procfs_ops.to_store_registers (-1);
+ else
+ orig_core_ops.to_store_registers (-1);
+
+ do_cleanups (old_chain);
+
+ return PS_OK;
+}
+
+#ifdef PR_MODEL_LP64
+/* Identify process as 32-bit or 64-bit.
+ At the moment I'm using bfd to do this.
+ There might be a more solaris-specific (eg. procfs) method,
+ but this ought to work. */
+
+ps_err_e
+ps_pdmodel (gdb_ps_prochandle_t ph, int *data_model)
+{
+ if (exec_bfd == 0)
+ *data_model = PR_MODEL_UNKNOWN;
+ else if (bfd_get_arch_size (exec_bfd) == 32)
+ *data_model = PR_MODEL_ILP32;
+ else
+ *data_model = PR_MODEL_LP64;
+
+ return PS_OK;
+}
+#endif /* PR_MODEL_LP64 */
+
+#ifdef TM_I386SOL2_H
+
+/* Reads the local descriptor table of a LWP. */
+
+ps_err_e
+ps_lgetLDT (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+ struct ssd *pldt)
+{
+ /* NOTE: only used on Solaris, therefore OK to refer to procfs.c */
+ extern struct ssd *procfs_find_LDT_entry (ptid_t);
+ struct ssd *ret;
+
+ /* FIXME: can't I get the process ID from the prochandle or something?
+ */
+
+ if (PIDGET (inferior_ptid) <= 0 || lwpid <= 0)
+ return PS_BADLID;
+
+ ret = procfs_find_LDT_entry (BUILD_LWP (lwpid, PIDGET (inferior_ptid)));
+ if (ret)
+ {
+ memcpy (pldt, ret, sizeof (struct ssd));
+ return PS_OK;
+ }
+ else /* LDT not found. */
+ return PS_ERR;
+}
+#endif /* TM_I386SOL2_H */
+
+/* Convert a pid to printable form. */
+
+char *
+solaris_pid_to_str (ptid_t ptid)
+{
+ static char buf[100];
+
+ /* in case init failed to resolve the libthread_db library */
+ if (!procfs_suppress_run)
+ return procfs_pid_to_str (ptid);
+
+ if (is_thread (ptid))
+ {
+ ptid_t lwp;
+
+ lwp = thread_to_lwp (ptid, -2);
+
+ if (PIDGET (lwp) == -1)
+ sprintf (buf, "Thread %ld (defunct)", GET_THREAD (ptid));
+ else if (PIDGET (lwp) != -2)
+ sprintf (buf, "Thread %ld (LWP %ld)", GET_THREAD (ptid), GET_LWP (lwp));
+ else
+ sprintf (buf, "Thread %ld ", GET_THREAD (ptid));
+ }
+ else if (GET_LWP (ptid) != 0)
+ sprintf (buf, "LWP %ld ", GET_LWP (ptid));
+ else
+ sprintf (buf, "process %d ", PIDGET (ptid));
+
+ return buf;
+}
+
+
+/* Worker bee for find_new_threads
+ Callback function that gets called once per USER thread (i.e., not
+ kernel) thread. */
+
+static int
+sol_find_new_threads_callback (const td_thrhandle_t *th, void *ignored)
+{
+ td_err_e retval;
+ td_thrinfo_t ti;
+ ptid_t ptid;
+
+ if ((retval = p_td_thr_get_info (th, &ti)) != TD_OK)
+ {
+ return -1;
+ }
+ ptid = BUILD_THREAD (ti.ti_tid, PIDGET (inferior_ptid));
+ if (!in_thread_list (ptid))
+ add_thread (ptid);
+
+ return 0;
+}
+
+static void
+sol_find_new_threads (void)
+{
+ /* don't do anything if init failed to resolve the libthread_db library */
+ if (!procfs_suppress_run)
+ return;
+
+ if (PIDGET (inferior_ptid) == -1)
+ {
+ printf_filtered ("No process.\n");
+ return;
+ }
+ procfs_ops.to_find_new_threads (); /* first find new kernel threads */
+ p_td_ta_thr_iter (main_ta, sol_find_new_threads_callback, (void *) 0,
+ TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+ TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+}
+
+static void
+sol_core_open (char *filename, int from_tty)
+{
+ orig_core_ops.to_open (filename, from_tty);
+}
+
+static void
+sol_core_close (int quitting)
+{
+ orig_core_ops.to_close (quitting);
+}
+
+static void
+sol_core_detach (char *args, int from_tty)
+{
+ unpush_target (&core_ops);
+ orig_core_ops.to_detach (args, from_tty);
+}
+
+static void
+sol_core_files_info (struct target_ops *t)
+{
+ orig_core_ops.to_files_info (t);
+}
+
+/* Worker bee for info sol-thread command. This is a callback function that
+ gets called once for each Solaris thread (ie. not kernel thread) in the
+ inferior. Print anything interesting that we can think of. */
+
+static int
+info_cb (const td_thrhandle_t *th, void *s)
+{
+ td_err_e ret;
+ td_thrinfo_t ti;
+
+ if ((ret = p_td_thr_get_info (th, &ti)) == TD_OK)
+ {
+ printf_filtered ("%s thread #%d, lwp %d, ",
+ ti.ti_type == TD_THR_SYSTEM ? "system" : "user ",
+ ti.ti_tid, ti.ti_lid);
+ switch (ti.ti_state)
+ {
+ default:
+ case TD_THR_UNKNOWN:
+ printf_filtered ("<unknown state>");
+ break;
+ case TD_THR_STOPPED:
+ printf_filtered ("(stopped)");
+ break;
+ case TD_THR_RUN:
+ printf_filtered ("(run) ");
+ break;
+ case TD_THR_ACTIVE:
+ printf_filtered ("(active) ");
+ break;
+ case TD_THR_ZOMBIE:
+ printf_filtered ("(zombie) ");
+ break;
+ case TD_THR_SLEEP:
+ printf_filtered ("(asleep) ");
+ break;
+ case TD_THR_STOPPED_ASLEEP:
+ printf_filtered ("(stopped asleep)");
+ break;
+ }
+ /* Print thr_create start function: */
+ if (ti.ti_startfunc != 0)
+ {
+ struct minimal_symbol *msym;
+ msym = lookup_minimal_symbol_by_pc (ti.ti_startfunc);
+ if (msym)
+ printf_filtered (" startfunc: %s\n", DEPRECATED_SYMBOL_NAME (msym));
+ else
+ printf_filtered (" startfunc: 0x%s\n", paddr (ti.ti_startfunc));
+ }
+
+ /* If thread is asleep, print function that went to sleep: */
+ if (ti.ti_state == TD_THR_SLEEP)
+ {
+ struct minimal_symbol *msym;
+ msym = lookup_minimal_symbol_by_pc (ti.ti_pc);
+ if (msym)
+ printf_filtered (" - Sleep func: %s\n", DEPRECATED_SYMBOL_NAME (msym));
+ else
+ printf_filtered (" - Sleep func: 0x%s\n", paddr (ti.ti_startfunc));
+ }
+
+ /* Wrap up line, if necessary */
+ if (ti.ti_state != TD_THR_SLEEP && ti.ti_startfunc == 0)
+ printf_filtered ("\n"); /* don't you hate counting newlines? */
+ }
+ else
+ warning ("info sol-thread: failed to get info for thread.");
+
+ return 0;
+}
+
+/* List some state about each Solaris user thread in the inferior. */
+
+static void
+info_solthreads (char *args, int from_tty)
+{
+ p_td_ta_thr_iter (main_ta, info_cb, args,
+ TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+ TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+}
+
+static int
+sol_find_memory_regions (int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ return procfs_ops.to_find_memory_regions (func, data);
+}
+
+static char *
+sol_make_note_section (bfd *obfd, int *note_size)
+{
+ return procfs_ops.to_make_corefile_notes (obfd, note_size);
+}
+
+static int
+ignore (CORE_ADDR addr, char *contents)
+{
+ return 0;
+}
+
+
+static void
+init_sol_thread_ops (void)
+{
+ sol_thread_ops.to_shortname = "solaris-threads";
+ sol_thread_ops.to_longname = "Solaris threads and pthread.";
+ sol_thread_ops.to_doc = "Solaris threads and pthread support.";
+ sol_thread_ops.to_open = sol_thread_open;
+ sol_thread_ops.to_attach = sol_thread_attach;
+ sol_thread_ops.to_detach = sol_thread_detach;
+ sol_thread_ops.to_resume = sol_thread_resume;
+ sol_thread_ops.to_wait = sol_thread_wait;
+ sol_thread_ops.to_fetch_registers = sol_thread_fetch_registers;
+ sol_thread_ops.to_store_registers = sol_thread_store_registers;
+ sol_thread_ops.to_prepare_to_store = sol_thread_prepare_to_store;
+ sol_thread_ops.to_xfer_memory = sol_thread_xfer_memory;
+ sol_thread_ops.to_xfer_partial = sol_thread_xfer_partial;
+ sol_thread_ops.to_files_info = sol_thread_files_info;
+ sol_thread_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ sol_thread_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ sol_thread_ops.to_terminal_init = terminal_init_inferior;
+ sol_thread_ops.to_terminal_inferior = terminal_inferior;
+ sol_thread_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ sol_thread_ops.to_terminal_ours = terminal_ours;
+ sol_thread_ops.to_terminal_save_ours = terminal_save_ours;
+ sol_thread_ops.to_terminal_info = child_terminal_info;
+ sol_thread_ops.to_kill = sol_thread_kill_inferior;
+ sol_thread_ops.to_create_inferior = sol_thread_create_inferior;
+ sol_thread_ops.to_mourn_inferior = sol_thread_mourn_inferior;
+ sol_thread_ops.to_can_run = sol_thread_can_run;
+ sol_thread_ops.to_notice_signals = sol_thread_notice_signals;
+ sol_thread_ops.to_thread_alive = sol_thread_alive;
+ sol_thread_ops.to_pid_to_str = solaris_pid_to_str;
+ sol_thread_ops.to_find_new_threads = sol_find_new_threads;
+ sol_thread_ops.to_stop = sol_thread_stop;
+ sol_thread_ops.to_stratum = process_stratum;
+ sol_thread_ops.to_has_all_memory = 1;
+ sol_thread_ops.to_has_memory = 1;
+ sol_thread_ops.to_has_stack = 1;
+ sol_thread_ops.to_has_registers = 1;
+ sol_thread_ops.to_has_execution = 1;
+ sol_thread_ops.to_has_thread_control = tc_none;
+ sol_thread_ops.to_find_memory_regions = sol_find_memory_regions;
+ sol_thread_ops.to_make_corefile_notes = sol_make_note_section;
+ sol_thread_ops.to_magic = OPS_MAGIC;
+}
+
+
+static void
+init_sol_core_ops (void)
+{
+ sol_core_ops.to_shortname = "solaris-core";
+ sol_core_ops.to_longname = "Solaris core threads and pthread.";
+ sol_core_ops.to_doc = "Solaris threads and pthread support for core files.";
+ sol_core_ops.to_open = sol_core_open;
+ sol_core_ops.to_close = sol_core_close;
+ sol_core_ops.to_attach = sol_thread_attach;
+ sol_core_ops.to_detach = sol_core_detach;
+ sol_core_ops.to_fetch_registers = sol_thread_fetch_registers;
+ sol_core_ops.to_xfer_memory = sol_thread_xfer_memory;
+ sol_core_ops.to_xfer_partial = sol_thread_xfer_partial;
+ sol_core_ops.to_files_info = sol_core_files_info;
+ sol_core_ops.to_insert_breakpoint = ignore;
+ sol_core_ops.to_remove_breakpoint = ignore;
+ sol_core_ops.to_create_inferior = sol_thread_create_inferior;
+ sol_core_ops.to_stratum = core_stratum;
+ sol_core_ops.to_has_memory = 1;
+ sol_core_ops.to_has_stack = 1;
+ sol_core_ops.to_has_registers = 1;
+ sol_core_ops.to_has_thread_control = tc_none;
+ sol_core_ops.to_thread_alive = sol_thread_alive;
+ sol_core_ops.to_pid_to_str = solaris_pid_to_str;
+ /* On Solaris/x86, when debugging a threaded core file from process <n>,
+ the following causes "info threads" to produce "procfs: couldn't find pid
+ <n> in procinfo list" where <n> is the pid of the process that produced
+ the core file. Disable it for now. */
+ /* sol_core_ops.to_find_new_threads = sol_find_new_threads; */
+ sol_core_ops.to_magic = OPS_MAGIC;
+}
+
+/* we suppress the call to add_target of core_ops in corelow because
+ if there are two targets in the stratum core_stratum, find_core_target
+ won't know which one to return. see corelow.c for an additonal
+ comment on coreops_suppress_target. */
+int coreops_suppress_target = 1;
+
+void
+_initialize_sol_thread (void)
+{
+ void *dlhandle;
+
+ init_sol_thread_ops ();
+ init_sol_core_ops ();
+
+ dlhandle = dlopen ("libthread_db.so.1", RTLD_NOW);
+ if (!dlhandle)
+ goto die;
+
+#define resolve(X) \
+ if (!(p_##X = dlsym (dlhandle, #X))) \
+ goto die;
+
+ resolve (td_log);
+ resolve (td_ta_new);
+ resolve (td_ta_delete);
+ resolve (td_init);
+ resolve (td_ta_get_ph);
+ resolve (td_ta_get_nthreads);
+ resolve (td_ta_tsd_iter);
+ resolve (td_ta_thr_iter);
+ resolve (td_thr_validate);
+ resolve (td_thr_tsd);
+ resolve (td_thr_get_info);
+ resolve (td_thr_getfpregs);
+ resolve (td_thr_getxregsize);
+ resolve (td_thr_getxregs);
+ resolve (td_thr_sigsetmask);
+ resolve (td_thr_setprio);
+ resolve (td_thr_setsigpending);
+ resolve (td_thr_setfpregs);
+ resolve (td_thr_setxregs);
+ resolve (td_ta_map_id2thr);
+ resolve (td_ta_map_lwp2thr);
+ resolve (td_thr_getgregs);
+ resolve (td_thr_setgregs);
+
+ add_target (&sol_thread_ops);
+
+ procfs_suppress_run = 1;
+
+ add_cmd ("sol-threads", class_maintenance, info_solthreads,
+ "Show info on Solaris user threads.\n", &maintenanceinfolist);
+
+ memcpy (&orig_core_ops, &core_ops, sizeof (struct target_ops));
+ memcpy (&core_ops, &sol_core_ops, sizeof (struct target_ops));
+ add_target (&core_ops);
+
+ /* Hook into new_objfile notification. */
+ target_new_objfile_chain = target_new_objfile_hook;
+ target_new_objfile_hook = sol_thread_new_objfile;
+ return;
+
+die:
+
+ fprintf_unfiltered (gdb_stderr, "[GDB will not be able to debug user-mode threads: %s]\n", dlerror ());
+
+ if (dlhandle)
+ dlclose (dlhandle);
+
+ /* allow the user to debug non-threaded core files */
+ add_target (&core_ops);
+
+ return;
+}
diff --git a/contrib/gdb/gdb/solib-legacy.c b/contrib/gdb/gdb/solib-legacy.c
new file mode 100644
index 0000000..a87eb21
--- /dev/null
+++ b/contrib/gdb/gdb/solib-legacy.c
@@ -0,0 +1,153 @@
+/* Provide legacy r_debug and link_map support for SVR4-like native targets.
+ Copyright 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "solib-svr4.h"
+
+#ifdef HAVE_LINK_H
+
+#ifdef HAVE_NLIST_H
+/* nlist.h needs to be included before link.h on some older *BSD systems. */
+#include <nlist.h>
+#endif
+
+#include <link.h>
+
+/* Fetch (and possibly build) an appropriate link_map_offsets structure
+ for native targets using struct definitions from link.h. */
+
+static struct link_map_offsets *
+legacy_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = 0;
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ static struct link_map_offsets lmo32;
+ static struct link_map_offsets *lmp32 = 0;
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+#define fieldsize(TYPE, MEMBER) (sizeof (((TYPE *)0)->MEMBER))
+
+ if (lmp == 0)
+ {
+ lmp = &lmo;
+
+#ifdef HAVE_STRUCT_LINK_MAP_WITH_L_MEMBERS
+ lmo.r_debug_size = sizeof (struct r_debug);
+
+ lmo.r_map_offset = offsetof (struct r_debug, r_map);
+ lmo.r_map_size = fieldsize (struct r_debug, r_map);
+
+ lmo.link_map_size = sizeof (struct link_map);
+
+ lmo.l_addr_offset = offsetof (struct link_map, l_addr);
+ lmo.l_addr_size = fieldsize (struct link_map, l_addr);
+
+ lmo.l_next_offset = offsetof (struct link_map, l_next);
+ lmo.l_next_size = fieldsize (struct link_map, l_next);
+
+ lmo.l_prev_offset = offsetof (struct link_map, l_prev);
+ lmo.l_prev_size = fieldsize (struct link_map, l_prev);
+
+ lmo.l_name_offset = offsetof (struct link_map, l_name);
+ lmo.l_name_size = fieldsize (struct link_map, l_name);
+#else /* !defined(HAVE_STRUCT_LINK_MAP_WITH_L_MEMBERS) */
+#ifdef HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS
+ lmo.link_map_size = sizeof (struct link_map);
+
+ lmo.l_addr_offset = offsetof (struct link_map, lm_addr);
+ lmo.l_addr_size = fieldsize (struct link_map, lm_addr);
+
+ lmo.l_next_offset = offsetof (struct link_map, lm_next);
+ lmo.l_next_size = fieldsize (struct link_map, lm_next);
+
+ lmo.l_name_offset = offsetof (struct link_map, lm_name);
+ lmo.l_name_size = fieldsize (struct link_map, lm_name);
+#else /* !defined(HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS) */
+#if HAVE_STRUCT_SO_MAP_WITH_SOM_MEMBERS
+ lmo.link_map_size = sizeof (struct so_map);
+
+ lmo.l_addr_offset = offsetof (struct so_map, som_addr);
+ lmo.l_addr_size = fieldsize (struct so_map, som_addr);
+
+ lmo.l_next_offset = offsetof (struct so_map, som_next);
+ lmo.l_next_size = fieldsize (struct so_map, som_next);
+
+ lmo.l_name_offset = offsetof (struct so_map, som_path);
+ lmo.l_name_size = fieldsize (struct so_map, som_path);
+#endif /* HAVE_STRUCT_SO_MAP_WITH_SOM_MEMBERS */
+#endif /* HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS */
+#endif /* HAVE_STRUCT_LINK_MAP_WITH_L_MEMBERS */
+ }
+
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (lmp32 == 0)
+ {
+ lmp32 = &lmo32;
+
+ lmo32.r_debug_size = sizeof (struct r_debug32);
+
+ lmo32.r_map_offset = offsetof (struct r_debug32, r_map);
+ lmo32.r_map_size = fieldsize (struct r_debug32, r_map);
+
+ lmo32.link_map_size = sizeof (struct link_map32);
+
+ lmo32.l_addr_offset = offsetof (struct link_map32, l_addr);
+ lmo32.l_addr_size = fieldsize (struct link_map32, l_addr);
+
+ lmo32.l_next_offset = offsetof (struct link_map32, l_next);
+ lmo32.l_next_size = fieldsize (struct link_map32, l_next);
+
+ lmo32.l_prev_offset = offsetof (struct link_map32, l_prev);
+ lmo32.l_prev_size = fieldsize (struct link_map32, l_prev);
+
+ lmo32.l_name_offset = offsetof (struct link_map32, l_name);
+ lmo32.l_name_size = fieldsize (struct link_map32, l_name);
+ }
+#endif /* defined (HAVE_STRUCT_LINK_MAP32) */
+
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (exec_bfd != NULL)
+ {
+ if (bfd_get_arch_size (exec_bfd) == 32)
+ return lmp32;
+ }
+ if (TARGET_PTR_BIT == 32)
+ return lmp32;
+#endif
+ return lmp;
+}
+
+#endif /* HAVE_LINK_H */
+
+extern initialize_file_ftype _initialize_svr4_lm; /* -Wmissing-prototypes */
+
+void
+_initialize_svr4_lm (void)
+{
+#ifdef HAVE_LINK_H
+ legacy_svr4_fetch_link_map_offsets_hook = legacy_svr4_fetch_link_map_offsets;
+#endif /* HAVE_LINK_H */
+}
diff --git a/contrib/gdb/gdb/solib-osf.c b/contrib/gdb/gdb/solib-osf.c
new file mode 100644
index 0000000..b5dca60
--- /dev/null
+++ b/contrib/gdb/gdb/solib-osf.c
@@ -0,0 +1,623 @@
+/* Handle OSF/1, Digital UNIX, and Tru64 shared libraries
+ for GDB, the GNU Debugger.
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* 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 libxproc.a library, which contains the equivalent ldr_*
+ routines. The library is documented in Tru64 5.x, but as of 5.1, it
+ only allows a process to examine itself. On earlier versions, it
+ may require that the GDB executable be dynamically linked and that
+ NAT_CLIBS include -lxproc -Wl,-expect_unresolved,ldr_process_context
+ for GDB and all applications that are using libgdb.
+
+ We will use the peeking approach until libxproc.a works for other
+ processes. */
+
+#include "defs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include "gdb_string.h"
+
+#include "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "target.h"
+#include "inferior.h"
+#include "solist.h"
+
+#ifdef USE_LDR_ROUTINES
+# include <loader.h>
+#endif
+
+#ifndef USE_LDR_ROUTINES
+/* Definition of runtime loader structures, found by experimentation. */
+#define RLD_CONTEXT_ADDRESS 0x3ffc0000000
+
+/* Per-module information structure referenced by ldr_context_t.head. */
+
+typedef struct
+ {
+ CORE_ADDR next;
+ CORE_ADDR previous;
+ CORE_ADDR unknown1;
+ CORE_ADDR module_name;
+ CORE_ADDR modinfo_addr; /* used by next_link_map_member() to detect
+ the end of the shared module list */
+ long module_id;
+ CORE_ADDR unknown2;
+ CORE_ADDR unknown3;
+ long region_count;
+ CORE_ADDR regioninfo_addr;
+ }
+ldr_module_info_t;
+
+/* Per-region structure referenced by ldr_module_info_t.regioninfo_addr. */
+
+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;
+
+/* Structure at RLD_CONTEXT_ADDRESS specifying the start and finish addresses
+ of the shared module list. */
+
+typedef struct
+ {
+ CORE_ADDR unknown1;
+ CORE_ADDR unknown2;
+ CORE_ADDR head;
+ CORE_ADDR tail;
+ }
+ldr_context_t;
+#endif /* !USE_LDR_ROUTINES */
+
+/* Per-section information, stored in struct lm_info.secs. */
+
+struct lm_sec
+ {
+ CORE_ADDR offset; /* difference between default and actual
+ virtual addresses of section .name */
+ CORE_ADDR nameaddr; /* address in inferior of section name */
+ const char *name; /* name of section, null if not fetched */
+ };
+
+/* Per-module information, stored in struct so_list.lm_info. */
+
+struct lm_info
+ {
+ int isloader; /* whether the module is /sbin/loader */
+ int nsecs; /* length of .secs */
+ struct lm_sec secs[1]; /* variable-length array of sections, sorted
+ by name */
+ };
+
+/* Context for iterating through the inferior's shared module list. */
+
+struct read_map_ctxt
+ {
+#ifdef USE_LDR_ROUTINES
+ ldr_process_t proc;
+ ldr_module_t next;
+#else
+ CORE_ADDR next; /* next element in module list */
+ CORE_ADDR tail; /* last element in module list */
+#endif
+ };
+
+/* Forward declaration for this module's autoinit function. */
+
+extern void _initialize_osf_solib (void);
+
+#ifdef USE_LDR_ROUTINES
+# if 0
+/* This routine is intended to be called by ldr_* routines to read memory from
+ the current target. Usage:
+
+ ldr_process = ldr_core_process ();
+ ldr_set_core_reader (ldr_read_memory);
+ ldr_xdetach (ldr_process);
+ ldr_xattach (ldr_process);
+
+ ldr_core_process() and ldr_read_memory() are neither documented nor
+ declared in system header files. They work with OSF/1 2.x, and they might
+ work with later versions as well. */
+
+static int
+ldr_read_memory (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);
+ xfree (buffer);
+ }
+ else
+ result = target_read_memory (memaddr, myaddr, len);
+
+ if (result != 0)
+ result = -result;
+ return result;
+}
+# endif /* 0 */
+#endif /* USE_LDR_ROUTINES */
+
+/* Comparison for qsort() and bsearch(): return -1, 0, or 1 according to
+ whether lm_sec *P1's name is lexically less than, equal to, or greater
+ than that of *P2. */
+
+static int
+lm_sec_cmp (const void *p1, const void *p2)
+{
+ const struct lm_sec *lms1 = p1, *lms2 = p2;
+ return strcmp (lms1->name, lms2->name);
+}
+
+/* Sort LMI->secs so that osf_relocate_section_addresses() can binary-search
+ it. */
+
+static void
+lm_secs_sort (struct lm_info *lmi)
+{
+ qsort (lmi->secs, lmi->nsecs, sizeof *lmi->secs, lm_sec_cmp);
+}
+
+/* Populate name fields of LMI->secs. */
+
+static void
+fetch_sec_names (struct lm_info *lmi)
+{
+#ifndef USE_LDR_ROUTINES
+ int i, errcode;
+ struct lm_sec *lms;
+ char *name;
+
+ for (i = 0; i < lmi->nsecs; i++)
+ {
+ lms = lmi->secs + i;
+ target_read_string (lms->nameaddr, &name, PATH_MAX, &errcode);
+ if (errcode != 0)
+ {
+ warning ("unable to read shared sec name at 0x%lx", lms->nameaddr);
+ name = xstrdup ("");
+ }
+ lms->name = name;
+ }
+ lm_secs_sort (lmi);
+#endif
+}
+
+/* target_so_ops callback. Adjust SEC's addresses after it's been mapped into
+ the process. */
+
+static void
+osf_relocate_section_addresses (struct so_list *so,
+ struct section_table *sec)
+{
+ struct lm_info *lmi;
+ struct lm_sec lms_key, *lms;
+
+ /* Fetch SO's section names if we haven't done so already. */
+ lmi = so->lm_info;
+ if (lmi->nsecs && !lmi->secs[0].name)
+ fetch_sec_names (lmi);
+
+ /* Binary-search for offset information corresponding to SEC. */
+ lms_key.name = sec->the_bfd_section->name;
+ lms = bsearch (&lms_key, lmi->secs, lmi->nsecs, sizeof *lms, lm_sec_cmp);
+ if (lms)
+ {
+ sec->addr += lms->offset;
+ sec->endaddr += lms->offset;
+ }
+}
+
+/* target_so_ops callback. Free parts of SO allocated by this file. */
+
+static void
+osf_free_so (struct so_list *so)
+{
+ int i;
+ const char *name;
+
+ for (i = 0; i < so->lm_info->nsecs; i++)
+ {
+ name = so->lm_info->secs[i].name;
+ if (name)
+ xfree ((void *) name);
+ }
+ xfree (so->lm_info);
+}
+
+/* target_so_ops callback. Discard information accumulated by this file and
+ not freed by osf_free_so(). */
+
+static void
+osf_clear_solib (void)
+{
+ return;
+}
+
+/* target_so_ops callback. Prepare to handle shared libraries after the
+ inferior process has been created but before it's executed any
+ instructions.
+
+ For a statically bound executable, the inferior's 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. */
+
+static void
+osf_solib_create_inferior_hook (void)
+{
+ /* 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 = STOP_QUIETLY;
+ stop_signal = TARGET_SIGNAL_0;
+ do
+ {
+ target_resume (minus_one_ptid, 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 until after symbol loading
+ suppresses the warning. */
+ solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
+ stop_soon = NO_STOP_QUIETLY;
+
+ /* Enable breakpoints disabled (unnecessarily) by clear_solib(). */
+ re_enable_breakpoints_in_shlibs ();
+}
+
+/* target_so_ops callback. Do additional symbol handling, lookup, etc. after
+ symbols for a shared object have been loaded. */
+
+static void
+osf_special_symbol_handling (void)
+{
+ return;
+}
+
+/* Initialize CTXT in preparation for iterating through the inferior's module
+ list using read_map(). Return success. */
+
+static int
+open_map (struct read_map_ctxt *ctxt)
+{
+#ifdef USE_LDR_ROUTINES
+ /* Note: As originally written, ldr_my_process() was used to obtain
+ the value for ctxt->proc. This is incorrect, however, since
+ ldr_my_process() retrieves the "unique identifier" associated
+ with the current process (i.e. GDB) and not the one being
+ debugged. Presumably, the pid of the process being debugged is
+ compatible with the "unique identifier" used by the ldr_
+ routines, so we use that. */
+ ctxt->proc = ptid_get_pid (inferior_ptid);
+ if (ldr_xattach (ctxt->proc) != 0)
+ return 0;
+ ctxt->next = LDR_NULL_MODULE;
+#else
+ CORE_ADDR ldr_context_addr, prev, next;
+ ldr_context_t ldr_context;
+
+ if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS,
+ (char *) &ldr_context_addr,
+ sizeof (CORE_ADDR)) != 0)
+ return 0;
+ if (target_read_memory (ldr_context_addr,
+ (char *) &ldr_context,
+ sizeof (ldr_context_t)) != 0)
+ return 0;
+ ctxt->next = ldr_context.head;
+ ctxt->tail = ldr_context.tail;
+#endif
+ return 1;
+}
+
+/* Initialize SO to have module NAME, /sbin/loader indicator ISLOADR, and
+ space for NSECS sections. */
+
+static void
+init_so (struct so_list *so, char *name, int isloader, int nsecs)
+{
+ int namelen, i;
+
+ /* solib.c requires various fields to be initialized to 0. */
+ memset (so, 0, sizeof *so);
+
+ /* Copy the name. */
+ namelen = strlen (name);
+ if (namelen >= SO_NAME_MAX_PATH_SIZE)
+ namelen = SO_NAME_MAX_PATH_SIZE - 1;
+
+ memcpy (so->so_original_name, name, namelen);
+ so->so_original_name[namelen] = '\0';
+ memcpy (so->so_name, so->so_original_name, namelen + 1);
+
+ /* Allocate section space. */
+ so->lm_info = xmalloc ((unsigned) &(((struct lm_info *)0)->secs) +
+ nsecs * sizeof *so->lm_info);
+ so->lm_info->isloader = isloader;
+ so->lm_info->nsecs = nsecs;
+ for (i = 0; i < nsecs; i++)
+ so->lm_info->secs[i].name = NULL;
+}
+
+/* Initialize SO's section SECIDX with name address NAMEADDR, name string
+ NAME, default virtual address VADDR, and actual virtual address
+ MAPADDR. */
+
+static void
+init_sec (struct so_list *so, int secidx, CORE_ADDR nameaddr,
+ const char *name, CORE_ADDR vaddr, CORE_ADDR mapaddr)
+{
+ struct lm_sec *lms;
+
+ lms = so->lm_info->secs + secidx;
+ lms->nameaddr = nameaddr;
+ lms->name = name;
+ lms->offset = mapaddr - vaddr;
+}
+
+/* If there are more elements starting at CTXT in inferior's module list,
+ store the next element in SO, advance CTXT to the next element, and return
+ 1, else return 0. */
+
+static int
+read_map (struct read_map_ctxt *ctxt, struct so_list *so)
+{
+ ldr_module_info_t minf;
+ ldr_region_info_t rinf;
+
+#ifdef USE_LDR_ROUTINES
+ size_t size;
+ ldr_region_t i;
+
+ /* Retrieve the next element. */
+ if (ldr_next_module (ctxt->proc, &ctxt->next) != 0)
+ return 0;
+ if (ctxt->next == LDR_NULL_MODULE)
+ return 0;
+ if (ldr_inq_module (ctxt->proc, ctxt->next, &minf, sizeof minf, &size) != 0)
+ return 0;
+
+ /* Initialize the module name and section count. */
+ init_so (so, minf.lmi_name, 0, minf.lmi_nregion);
+
+ /* Retrieve section names and offsets. */
+ for (i = 0; i < minf.lmi_nregion; i++)
+ {
+ if (ldr_inq_region (ctxt->proc, ctxt->next, i, &rinf,
+ sizeof rinf, &size) != 0)
+ goto err;
+ init_sec (so, (int) i, 0, xstrdup (rinf.lri_name),
+ (CORE_ADDR) rinf.lri_vaddr, (CORE_ADDR) rinf.lri_mapaddr);
+ }
+ lm_secs_sort (so->lm_info);
+#else
+ char *name;
+ int errcode, i;
+
+ /* Retrieve the next element. */
+ if (!ctxt->next)
+ return 0;
+ if (target_read_memory (ctxt->next, (char *) &minf, sizeof minf) != 0)
+ return 0;
+ if (ctxt->next == ctxt->tail)
+ ctxt->next = 0;
+ else
+ ctxt->next = minf.next;
+
+ /* Initialize the module name and section count. */
+ target_read_string (minf.module_name, &name, PATH_MAX, &errcode);
+ if (errcode != 0)
+ return 0;
+ init_so (so, name, !minf.modinfo_addr, minf.region_count);
+ xfree (name);
+
+ /* Retrieve section names and offsets. */
+ for (i = 0; i < minf.region_count; i++)
+ {
+ if (target_read_memory (minf.regioninfo_addr + i * sizeof rinf,
+ (char *) &rinf, sizeof rinf) != 0)
+ goto err;
+ init_sec (so, i, rinf.regionname_addr, NULL, rinf.vaddr, rinf.mapaddr);
+ }
+#endif /* !USE_LDR_ROUTINES */
+ return 1;
+
+ err:
+ osf_free_so (so);
+ return 0;
+}
+
+/* Free resources allocated by open_map (CTXT). */
+
+static void
+close_map (struct read_map_ctxt *ctxt)
+{
+#ifdef USE_LDR_ROUTINES
+ ldr_xdetach (ctxt->proc);
+#endif
+}
+
+/* target_so_ops callback. Return a list of shared objects currently loaded
+ in the inferior. */
+
+static struct so_list *
+osf_current_sos (void)
+{
+ struct so_list *head = NULL, *tail, *newtail, so;
+ struct read_map_ctxt ctxt;
+ int skipped_main;
+
+ if (!open_map (&ctxt))
+ return NULL;
+
+ /* Read subsequent elements. */
+ for (skipped_main = 0;;)
+ {
+ if (!read_map (&ctxt, &so))
+ break;
+
+ /* Skip the main program module, which is first in the list after
+ /sbin/loader. */
+ if (!so.lm_info->isloader && !skipped_main)
+ {
+ osf_free_so (&so);
+ skipped_main = 1;
+ continue;
+ }
+
+ newtail = xmalloc (sizeof *newtail);
+ if (!head)
+ head = newtail;
+ else
+ tail->next = newtail;
+ tail = newtail;
+
+ memcpy (tail, &so, sizeof so);
+ tail->next = NULL;
+ }
+
+ done:
+ close_map (&ctxt);
+ return head;
+}
+
+/* target_so_ops callback. Attempt to locate and open the main symbol
+ file. */
+
+static int
+osf_open_symbol_file_object (void *from_ttyp)
+{
+ struct read_map_ctxt ctxt;
+ struct so_list so;
+ int found;
+
+ if (symfile_objfile)
+ if (!query ("Attempt to reload symbols from process? "))
+ return 0;
+
+ /* The first module after /sbin/loader is the main program. */
+ if (!open_map (&ctxt))
+ return 0;
+ for (found = 0; !found;)
+ {
+ if (!read_map (&ctxt, &so))
+ break;
+ found = !so.lm_info->isloader;
+ osf_free_so (&so);
+ }
+ close_map (&ctxt);
+
+ if (found)
+ symbol_file_add_main (so.so_name, *(int *) from_ttyp);
+ return found;
+}
+
+/* target_so_ops callback. Return whether PC is in the dynamic linker. */
+
+static int
+osf_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ /* This function currently always return False. This is a temporary
+ solution which only consequence is to introduce a minor incovenience
+ for the user: When stepping inside a subprogram located in a shared
+ library, gdb might stop inside the dynamic loader code instead of
+ inside the subprogram itself. See the explanations in infrun.c about
+ the IN_SOLIB_DYNSYM_RESOLVE_CODE macro for more details. */
+ return 0;
+}
+
+static struct target_so_ops osf_so_ops;
+
+void
+_initialize_osf_solib (void)
+{
+ osf_so_ops.relocate_section_addresses = osf_relocate_section_addresses;
+ osf_so_ops.free_so = osf_free_so;
+ osf_so_ops.clear_solib = osf_clear_solib;
+ osf_so_ops.solib_create_inferior_hook = osf_solib_create_inferior_hook;
+ osf_so_ops.special_symbol_handling = osf_special_symbol_handling;
+ osf_so_ops.current_sos = osf_current_sos;
+ osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object;
+ osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code;
+
+ /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
+ current_target_so_ops = &osf_so_ops;
+}
diff --git a/contrib/gdb/gdb/solib-sunos.c b/contrib/gdb/gdb/solib-sunos.c
new file mode 100644
index 0000000..a88e7b7
--- /dev/null
+++ b/contrib/gdb/gdb/solib-sunos.c
@@ -0,0 +1,898 @@
+/* Handle SunOS shared libraries for GDB, the GNU Debugger.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <sys/types.h>
+#include <signal.h>
+#include "gdb_string.h"
+#include <sys/param.h>
+#include <fcntl.h>
+
+ /* SunOS shared libs need the nlist structure. */
+#include <a.out.h>
+#include <link.h>
+
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "solist.h"
+#include "bcache.h"
+#include "regcache.h"
+
+/* Link map info to include in an allocated so_list entry */
+
+struct lm_info
+ {
+ /* Pointer to copy of link map from inferior. The type is char *
+ rather than void *, so that we may use byte offsets to find the
+ various fields without the need for a cast. */
+ char *lm;
+ };
+
+
+/* Symbols which are used to locate the base of the link map structures. */
+
+static char *debug_base_symbols[] =
+{
+ "_DYNAMIC",
+ "_DYNAMIC__MGC",
+ NULL
+};
+
+static char *main_name_list[] =
+{
+ "main_$main",
+ NULL
+};
+
+/* Macro to extract an address from a solib structure. When GDB is
+ configured for some 32-bit targets (e.g. Solaris 2.7 sparc), BFD is
+ configured to handle 64-bit targets, so CORE_ADDR is 64 bits. We
+ have to extract only the significant bits of addresses to get the
+ right address when accessing the core file BFD.
+
+ Assume that the address is unsigned. */
+
+#define SOLIB_EXTRACT_ADDRESS(MEMBER) \
+ extract_unsigned_integer (&(MEMBER), sizeof (MEMBER))
+
+/* local data declarations */
+
+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;
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+#define fieldsize(TYPE, MEMBER) (sizeof (((TYPE *)0)->MEMBER))
+
+/* link map access functions */
+
+static CORE_ADDR
+LM_ADDR (struct so_list *so)
+{
+ int lm_addr_offset = offsetof (struct link_map, lm_addr);
+ int lm_addr_size = fieldsize (struct link_map, lm_addr);
+
+ return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + lm_addr_offset,
+ lm_addr_size);
+}
+
+static CORE_ADDR
+LM_NEXT (struct so_list *so)
+{
+ int lm_next_offset = offsetof (struct link_map, lm_next);
+ int lm_next_size = fieldsize (struct link_map, lm_next);
+
+ /* Assume that the address is unsigned. */
+ return extract_unsigned_integer (so->lm_info->lm + lm_next_offset,
+ lm_next_size);
+}
+
+static CORE_ADDR
+LM_NAME (struct so_list *so)
+{
+ int lm_name_offset = offsetof (struct link_map, lm_name);
+ int lm_name_size = fieldsize (struct link_map, lm_name);
+
+ /* Assume that the address is unsigned. */
+ return extract_unsigned_integer (so->lm_info->lm + lm_name_offset,
+ lm_name_size);
+}
+
+static CORE_ADDR debug_base; /* Base of dynamic linker structures */
+
+/* Local function prototypes */
+
+static int match_main (char *);
+
+/* Allocate the runtime common object file. */
+
+static void
+allocate_rt_common_objfile (void)
+{
+ struct objfile *objfile;
+ struct objfile *last_one;
+
+ objfile = (struct objfile *) xmalloc (sizeof (struct objfile));
+ memset (objfile, 0, sizeof (struct objfile));
+ objfile->md = NULL;
+ objfile->psymbol_cache = bcache_xmalloc ();
+ objfile->macro_cache = bcache_xmalloc ();
+ obstack_init (&objfile->objfile_obstack);
+ 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 (CORE_ADDR rtc_symp)
+{
+ struct rtc_symb inferior_rtc_symb;
+ struct nlist inferior_rtc_nlist;
+ int len;
+ char *name;
+
+ /* Remove any runtime common symbols from previous runs. */
+
+ if (rt_common_objfile != NULL && rt_common_objfile->minimal_symbol_count)
+ {
+ obstack_free (&rt_common_objfile->objfile_obstack, 0);
+ obstack_init (&rt_common_objfile->objfile_obstack);
+ rt_common_objfile->minimal_symbol_count = 0;
+ rt_common_objfile->msymbols = NULL;
+ terminate_minimal_symbol_table (rt_common_objfile);
+ }
+
+ init_minimal_symbol_collection ();
+ make_cleanup_discard_minimal_symbols ();
+
+ while (rtc_symp)
+ {
+ read_memory (rtc_symp,
+ (char *) &inferior_rtc_symb,
+ sizeof (inferior_rtc_symb));
+ read_memory (SOLIB_EXTRACT_ADDRESS (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;
+
+ name = xmalloc (len);
+ read_memory (SOLIB_EXTRACT_ADDRESS (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 ();
+
+ prim_record_minimal_symbol (name, inferior_rtc_nlist.n_value,
+ mst_bss, rt_common_objfile);
+ xfree (name);
+ }
+ rtc_symp = SOLIB_EXTRACT_ADDRESS (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);
+}
+
+
+/*
+
+ 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 (void)
+{
+ 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);
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ first_link_map_member -- locate first member in dynamic linker's map
+
+ SYNOPSIS
+
+ static CORE_ADDR first_link_map_member (void)
+
+ DESCRIPTION
+
+ Find the first element in the inferior's dynamic link map, and
+ return its address in the inferior. This function doesn't copy the
+ link map entry itself into our address space; current_sos actually
+ does the reading. */
+
+static CORE_ADDR
+first_link_map_member (void)
+{
+ CORE_ADDR lm = 0;
+
+ 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 (SOLIB_EXTRACT_ADDRESS (dynamic_copy.ld_un.ld_2),
+ (char *) &ld_2_copy, sizeof (struct link_dynamic_2));
+ lm = SOLIB_EXTRACT_ADDRESS (ld_2_copy.ld_loaded);
+ }
+ return (lm);
+}
+
+static int
+open_symbol_file_object (void *from_ttyp)
+{
+ return 1;
+}
+
+
+/* LOCAL FUNCTION
+
+ current_sos -- build a list of currently loaded shared objects
+
+ SYNOPSIS
+
+ struct so_list *current_sos ()
+
+ DESCRIPTION
+
+ Build a list of `struct so_list' objects describing the shared
+ objects currently loaded in the inferior. This list does not
+ include an entry for the main executable file.
+
+ Note that we only gather information directly available from the
+ inferior --- we don't examine any of the shared library files
+ themselves. The declaration of `struct so_list' says which fields
+ we provide values for. */
+
+static struct so_list *
+sunos_current_sos (void)
+{
+ CORE_ADDR lm;
+ struct so_list *head = 0;
+ struct so_list **link_ptr = &head;
+ int errcode;
+ char *buffer;
+
+ /* Make sure we've looked up the inferior's dynamic linker's base
+ structure. */
+ if (! debug_base)
+ {
+ debug_base = locate_base ();
+
+ /* If we can't find the dynamic linker's base structure, this
+ must not be a dynamically linked executable. Hmm. */
+ if (! debug_base)
+ return 0;
+ }
+
+ /* Walk the inferior's link map list, and build our list of
+ `struct so_list' nodes. */
+ lm = first_link_map_member ();
+ while (lm)
+ {
+ struct so_list *new
+ = (struct so_list *) xmalloc (sizeof (struct so_list));
+ struct cleanup *old_chain = make_cleanup (xfree, new);
+
+ memset (new, 0, sizeof (*new));
+
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ make_cleanup (xfree, new->lm_info);
+
+ new->lm_info->lm = xmalloc (sizeof (struct link_map));
+ make_cleanup (xfree, new->lm_info->lm);
+ memset (new->lm_info->lm, 0, sizeof (struct link_map));
+
+ read_memory (lm, new->lm_info->lm, sizeof (struct link_map));
+
+ lm = LM_NEXT (new);
+
+ /* Extract this shared object's name. */
+ target_read_string (LM_NAME (new), &buffer,
+ SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+ if (errcode != 0)
+ {
+ warning ("current_sos: Can't read pathname for load map: %s\n",
+ safe_strerror (errcode));
+ }
+ else
+ {
+ strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ xfree (buffer);
+ strcpy (new->so_original_name, new->so_name);
+ }
+
+ /* If this entry has no name, or its name matches the name
+ for the main executable, don't include it in the list. */
+ if (! new->so_name[0]
+ || match_main (new->so_name))
+ free_so (new);
+ else
+ {
+ new->next = 0;
+ *link_ptr = new;
+ link_ptr = &new->next;
+ }
+
+ discard_cleanups (old_chain);
+ }
+
+ return head;
+}
+
+
+/* On some systems, the only way to recognize the link map entry for
+ the main executable file is by looking at its name. Return
+ non-zero iff SONAME matches one of the known main executable names. */
+
+static int
+match_main (char *soname)
+{
+ char **mainp;
+
+ for (mainp = main_name_list; *mainp != NULL; mainp++)
+ {
+ if (strcmp (soname, *mainp) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+
+static int
+sunos_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ return 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 (void)
+{
+ CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */
+
+ 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 = SOLIB_EXTRACT_ADDRESS (debug_copy.ldd_bp_addr);
+ write_memory (breakpoint_addr, (char *) &debug_copy.ldd_bp_inst,
+ sizeof (debug_copy.ldd_bp_inst));
+
+ /* 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 1;
+}
+
+
+/*
+
+ 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 (void)
+{
+ int success = 0;
+ 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 = SOLIB_EXTRACT_ADDRESS (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;
+
+ return (success);
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ special_symbol_handling -- additional shared library symbol handling
+
+ SYNOPSIS
+
+ void special_symbol_handling ()
+
+ 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
+sunos_special_symbol_handling (void)
+{
+ 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 = SOLIB_EXTRACT_ADDRESS (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 (SOLIB_EXTRACT_ADDRESS (debug_copy.ldd_cp));
+ }
+}
+
+/* Relocate the main executable. This function should be called upon
+ stopping the inferior process at the entry point to the program.
+ The entry point from BFD is compared to the PC and if they are
+ different, the main executable is relocated by the proper amount.
+
+ As written it will only attempt to relocate executables which
+ lack interpreter sections. It seems likely that only dynamic
+ linker executables will get relocated, though it should work
+ properly for a position-independent static executable as well. */
+
+static void
+sunos_relocate_main_executable (void)
+{
+ asection *interp_sect;
+ CORE_ADDR pc = read_pc ();
+
+ /* Decide if the objfile needs to be relocated. As indicated above,
+ we will only be here when execution is stopped at the beginning
+ of the program. Relocation is necessary if the address at which
+ we are presently stopped differs from the start address stored in
+ the executable AND there's no interpreter section. The condition
+ regarding the interpreter section is very important because if
+ there *is* an interpreter section, execution will begin there
+ instead. When there is an interpreter section, the start address
+ is (presumably) used by the interpreter at some point to start
+ execution of the program.
+
+ If there is an interpreter, it is normal for it to be set to an
+ arbitrary address at the outset. The job of finding it is
+ handled in enable_break().
+
+ So, to summarize, relocations are necessary when there is no
+ interpreter section and the start address obtained from the
+ executable is different from the address at which GDB is
+ currently stopped.
+
+ [ The astute reader will note that we also test to make sure that
+ the executable in question has the DYNAMIC flag set. It is my
+ opinion that this test is unnecessary (undesirable even). It
+ was added to avoid inadvertent relocation of an executable
+ whose e_type member in the ELF header is not ET_DYN. There may
+ be a time in the future when it is desirable to do relocations
+ on other types of files as well in which case this condition
+ should either be removed or modified to accomodate the new file
+ type. (E.g, an ET_EXEC executable which has been built to be
+ position-independent could safely be relocated by the OS if
+ desired. It is true that this violates the ABI, but the ABI
+ has been known to be bent from time to time.) - Kevin, Nov 2000. ]
+ */
+
+ interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+ if (interp_sect == NULL
+ && (bfd_get_file_flags (exec_bfd) & DYNAMIC) != 0
+ && bfd_get_start_address (exec_bfd) != pc)
+ {
+ struct cleanup *old_chain;
+ struct section_offsets *new_offsets;
+ int i, changed;
+ CORE_ADDR displacement;
+
+ /* It is necessary to relocate the objfile. The amount to
+ relocate by is simply the address at which we are stopped
+ minus the starting address from the executable.
+
+ We relocate all of the sections by the same amount. This
+ behavior is mandated by recent editions of the System V ABI.
+ According to the System V Application Binary Interface,
+ Edition 4.1, page 5-5:
+
+ ... Though the system chooses virtual addresses for
+ individual processes, it maintains the segments' relative
+ positions. Because position-independent code uses relative
+ addressesing between segments, the difference between
+ virtual addresses in memory must match the difference
+ between virtual addresses in the file. The difference
+ between the virtual address of any segment in memory and
+ the corresponding virtual address in the file is thus a
+ single constant value for any one executable or shared
+ object in a given process. This difference is the base
+ address. One use of the base address is to relocate the
+ memory image of the program during dynamic linking.
+
+ The same language also appears in Edition 4.0 of the System V
+ ABI and is left unspecified in some of the earlier editions. */
+
+ displacement = pc - bfd_get_start_address (exec_bfd);
+ changed = 0;
+
+ new_offsets = xcalloc (symfile_objfile->num_sections,
+ sizeof (struct section_offsets));
+ old_chain = make_cleanup (xfree, new_offsets);
+
+ for (i = 0; i < symfile_objfile->num_sections; i++)
+ {
+ if (displacement != ANOFFSET (symfile_objfile->section_offsets, i))
+ changed = 1;
+ new_offsets->offsets[i] = displacement;
+ }
+
+ if (changed)
+ objfile_relocate (symfile_objfile, new_offsets);
+
+ do_cleanups (old_chain);
+ }
+}
+
+/*
+
+ GLOBAL FUNCTION
+
+ sunos_solib_create_inferior_hook -- shared library startup support
+
+ SYNOPSIS
+
+ void sunos_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.
+ */
+
+static void
+sunos_solib_create_inferior_hook (void)
+{
+ /* Relocate the main executable if necessary. */
+ sunos_relocate_main_executable ();
+
+ if ((debug_base = locate_base ()) == 0)
+ {
+ /* Can't find the symbol or the executable is statically linked. */
+ return;
+ }
+
+ if (!enable_break ())
+ {
+ warning ("shared library handler failed to enable breakpoint");
+ return;
+ }
+
+ /* SCO and SunOS need 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 = STOP_QUIETLY;
+ stop_signal = TARGET_SIGNAL_0;
+ do
+ {
+ target_resume (pid_to_ptid (-1), 0, stop_signal);
+ wait_for_inferior ();
+ }
+ while (stop_signal != TARGET_SIGNAL_TRAP);
+ stop_soon = NO_STOP_QUIETLY;
+
+ /* 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 ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
+}
+
+static void
+sunos_clear_solib (void)
+{
+ debug_base = 0;
+}
+
+static void
+sunos_free_so (struct so_list *so)
+{
+ xfree (so->lm_info->lm);
+ xfree (so->lm_info);
+}
+
+static void
+sunos_relocate_section_addresses (struct so_list *so,
+ struct section_table *sec)
+{
+ sec->addr += LM_ADDR (so);
+ sec->endaddr += LM_ADDR (so);
+}
+
+static struct target_so_ops sunos_so_ops;
+
+void
+_initialize_sunos_solib (void)
+{
+ sunos_so_ops.relocate_section_addresses = sunos_relocate_section_addresses;
+ sunos_so_ops.free_so = sunos_free_so;
+ sunos_so_ops.clear_solib = sunos_clear_solib;
+ sunos_so_ops.solib_create_inferior_hook = sunos_solib_create_inferior_hook;
+ sunos_so_ops.special_symbol_handling = sunos_special_symbol_handling;
+ sunos_so_ops.current_sos = sunos_current_sos;
+ sunos_so_ops.open_symbol_file_object = open_symbol_file_object;
+ sunos_so_ops.in_dynsym_resolve_code = sunos_in_dynsym_resolve_code;
+
+ /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
+ current_target_so_ops = &sunos_so_ops;
+}
diff --git a/contrib/gdb/gdb/solib-svr4.c b/contrib/gdb/gdb/solib-svr4.c
new file mode 100644
index 0000000..afea156
--- /dev/null
+++ b/contrib/gdb/gdb/solib-svr4.c
@@ -0,0 +1,1605 @@
+/* Handle SVR4 shared libraries for GDB, the GNU Debugger.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
+ 2000, 2001, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "elf/external.h"
+#include "elf/common.h"
+#include "elf/mips.h"
+
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "inferior.h"
+
+#include "solist.h"
+#include "solib-svr4.h"
+
+#include "bfd-target.h"
+#include "exec.h"
+
+#ifndef SVR4_FETCH_LINK_MAP_OFFSETS
+#define SVR4_FETCH_LINK_MAP_OFFSETS() svr4_fetch_link_map_offsets ()
+#endif
+
+static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
+static struct link_map_offsets *legacy_fetch_link_map_offsets (void);
+static int svr4_have_link_map_offsets (void);
+
+/* fetch_link_map_offsets_gdbarch_data is a handle used to obtain the
+ architecture specific link map offsets fetching function. */
+
+static struct gdbarch_data *fetch_link_map_offsets_gdbarch_data;
+
+/* legacy_svr4_fetch_link_map_offsets_hook is a pointer to a function
+ which is used to fetch link map offsets. It will only be set
+ by solib-legacy.c, if at all. */
+
+struct link_map_offsets *(*legacy_svr4_fetch_link_map_offsets_hook)(void) = 0;
+
+/* Link map info to include in an allocated so_list entry */
+
+struct lm_info
+ {
+ /* Pointer to copy of link map from inferior. The type is char *
+ rather than void *, so that we may use byte offsets to find the
+ various fields without the need for a cast. */
+ char *lm;
+ };
+
+/* 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. */
+
+static char *solib_break_names[] =
+{
+ "r_debug_state",
+ "_r_debug_state",
+ "_dl_debug_state",
+ "rtld_db_dlactivity",
+ "_rtld_debug_state",
+
+ /* On the 64-bit PowerPC, the linker symbol with the same name as
+ the C function points to a function descriptor, not to the entry
+ point. The linker symbol whose name is the C function name
+ prefixed with a '.' points to the function's entry point. So
+ when we look through this table, we ignore symbols that point
+ into the data section (thus skipping the descriptor's symbol),
+ and eventually try this one, giving us the real entry point
+ address. */
+ ".r_debug_state",
+ "._dl_debug_state",
+
+ NULL
+};
+
+#define BKPT_AT_SYMBOL 1
+
+#if defined (BKPT_AT_SYMBOL)
+static char *bkpt_names[] =
+{
+#ifdef SOLIB_BKPT_NAME
+ SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */
+#endif
+ "_start",
+ "__start",
+ "main",
+ NULL
+};
+#endif
+
+static char *main_name_list[] =
+{
+ "main_$main",
+ NULL
+};
+
+/* Macro to extract an address from a solib structure. When GDB is
+ configured for some 32-bit targets (e.g. Solaris 2.7 sparc), BFD is
+ configured to handle 64-bit targets, so CORE_ADDR is 64 bits. We
+ have to extract only the significant bits of addresses to get the
+ right address when accessing the core file BFD.
+
+ Assume that the address is unsigned. */
+
+#define SOLIB_EXTRACT_ADDRESS(MEMBER) \
+ extract_unsigned_integer (&(MEMBER), sizeof (MEMBER))
+
+/* local data declarations */
+
+/* link map access functions */
+
+static CORE_ADDR
+LM_ADDR (struct so_list *so)
+{
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+
+ return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + lmo->l_addr_offset,
+ lmo->l_addr_size);
+}
+
+static CORE_ADDR
+LM_NEXT (struct so_list *so)
+{
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+
+ /* Assume that the address is unsigned. */
+ return extract_unsigned_integer (so->lm_info->lm + lmo->l_next_offset,
+ lmo->l_next_size);
+}
+
+static CORE_ADDR
+LM_NAME (struct so_list *so)
+{
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+
+ /* Assume that the address is unsigned. */
+ return extract_unsigned_integer (so->lm_info->lm + lmo->l_name_offset,
+ lmo->l_name_size);
+}
+
+static int
+IGNORE_FIRST_LINK_MAP_ENTRY (struct so_list *so)
+{
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+
+ /* Assume that the address is unsigned. */
+ return extract_unsigned_integer (so->lm_info->lm + lmo->l_prev_offset,
+ lmo->l_prev_size) == 0;
+}
+
+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 int match_main (char *);
+
+static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword);
+
+/*
+
+ LOCAL FUNCTION
+
+ bfd_lookup_symbol -- lookup the value for a specific symbol
+
+ SYNOPSIS
+
+ CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags)
+
+ 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.
+
+ If SECT_FLAGS is non-zero, only match symbols in sections whose
+ flags include all those in SECT_FLAGS.
+
+ Note that 0 is specifically allowed as an error return (no
+ such symbol).
+ */
+
+static CORE_ADDR
+bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags)
+{
+ long 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 (xfree, symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = *symbol_table++;
+ if (strcmp (sym->name, symname) == 0
+ && (sym->section->flags & sect_flags) == sect_flags)
+ {
+ /* Bfd symbols are section relative. */
+ symaddr = sym->value + sym->section->vma;
+ break;
+ }
+ }
+ do_cleanups (back_to);
+ }
+
+ if (symaddr)
+ return symaddr;
+
+ /* On FreeBSD, the dynamic linker is stripped by default. So we'll
+ have to check the dynamic string table too. */
+
+ storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (xfree, symbol_table);
+ number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = *symbol_table++;
+
+ if (strcmp (sym->name, symname) == 0
+ && (sym->section->flags & sect_flags) == sect_flags)
+ {
+ /* 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 (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 (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 ((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, 0);
+ 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 (void)
+{
+ struct bfd_section *dyninfo_sect;
+ int dyninfo_sect_size;
+ CORE_ADDR dyninfo_addr;
+ char *buf;
+ char *bufend;
+ int arch_size;
+
+ /* 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. */
+
+ arch_size = bfd_get_arch_size (exec_bfd);
+ if (arch_size == -1) /* failure */
+ return 0;
+
+ if (arch_size == 32)
+ { /* 32-bit elf */
+ 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;
+ }
+ else if (dyn_tag == DT_MIPS_RLD_MAP)
+ {
+ char *pbuf;
+ int pbuf_size = TARGET_PTR_BIT / HOST_CHAR_BIT;
+
+ pbuf = alloca (pbuf_size);
+ /* 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, pbuf_size))
+ return 0;
+ return extract_unsigned_integer (pbuf, pbuf_size);
+ }
+ }
+ }
+ else /* 64-bit elf */
+ {
+ for (bufend = buf + dyninfo_sect_size;
+ buf < bufend;
+ buf += sizeof (Elf64_External_Dyn))
+ {
+ Elf64_External_Dyn *x_dynp = (Elf64_External_Dyn *) buf;
+ long dyn_tag;
+ CORE_ADDR dyn_ptr;
+
+ dyn_tag = bfd_h_get_64 (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_64 (exec_bfd,
+ (bfd_byte *) x_dynp->d_un.d_ptr);
+ return dyn_ptr;
+ }
+ else if (dyn_tag == DT_MIPS_RLD_MAP)
+ {
+ char *pbuf;
+ int pbuf_size = TARGET_PTR_BIT / HOST_CHAR_BIT;
+
+ pbuf = alloca (pbuf_size);
+ /* DT_MIPS_RLD_MAP contains a pointer to the address
+ of the dynamic link structure. */
+ dyn_ptr = bfd_h_get_64 (exec_bfd,
+ (bfd_byte *) x_dynp->d_un.d_ptr);
+ if (target_read_memory (dyn_ptr, pbuf, pbuf_size))
+ return 0;
+ return extract_unsigned_integer (pbuf, pbuf_size);
+ }
+ }
+ }
+
+ /* DT_DEBUG entry not found. */
+ return 0;
+}
+
+/*
+
+ 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 (void)
+{
+ /* 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. There's no point in doing any of this
+ though if we don't have some link map offsets to work with. */
+
+ if (debug_base == 0 && svr4_have_link_map_offsets ())
+ {
+ 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 (!ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
+ proc_iterate_over_mappings (look_for_base);
+#endif
+ }
+ return (debug_base);
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ first_link_map_member -- locate first member in dynamic linker's map
+
+ SYNOPSIS
+
+ static CORE_ADDR first_link_map_member (void)
+
+ DESCRIPTION
+
+ Find the first element in the inferior's dynamic link map, and
+ return its address in the inferior. This function doesn't copy the
+ link map entry itself into our address space; current_sos actually
+ does the reading. */
+
+static CORE_ADDR
+first_link_map_member (void)
+{
+ CORE_ADDR lm = 0;
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+ char *r_map_buf = xmalloc (lmo->r_map_size);
+ struct cleanup *cleanups = make_cleanup (xfree, r_map_buf);
+
+ read_memory (debug_base + lmo->r_map_offset, r_map_buf, lmo->r_map_size);
+
+ /* Assume that the address is unsigned. */
+ lm = extract_unsigned_integer (r_map_buf, lmo->r_map_size);
+
+ /* FIXME: Perhaps we should validate the info somehow, perhaps by
+ checking r_version for a known version number, or r_state for
+ RT_CONSISTENT. */
+
+ do_cleanups (cleanups);
+
+ return (lm);
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ open_symbol_file_object
+
+ SYNOPSIS
+
+ void open_symbol_file_object (void *from_tty)
+
+ DESCRIPTION
+
+ If no open symbol file, attempt to locate and open the main symbol
+ file. On SVR4 systems, this is the first link map entry. If its
+ name is here, we can open it. Useful when attaching to a process
+ without first loading its symbol file.
+
+ If FROM_TTYP dereferences to a non-zero integer, allow messages to
+ be printed. This parameter is a pointer rather than an int because
+ open_symbol_file_object() is called via catch_errors() and
+ catch_errors() requires a pointer argument. */
+
+static int
+open_symbol_file_object (void *from_ttyp)
+{
+ CORE_ADDR lm, l_name;
+ char *filename;
+ int errcode;
+ int from_tty = *(int *)from_ttyp;
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+ char *l_name_buf = xmalloc (lmo->l_name_size);
+ struct cleanup *cleanups = make_cleanup (xfree, l_name_buf);
+
+ if (symfile_objfile)
+ if (!query ("Attempt to reload symbols from process? "))
+ return 0;
+
+ if ((debug_base = locate_base ()) == 0)
+ return 0; /* failed somehow... */
+
+ /* First link map member should be the executable. */
+ if ((lm = first_link_map_member ()) == 0)
+ return 0; /* failed somehow... */
+
+ /* Read address of name from target memory to GDB. */
+ read_memory (lm + lmo->l_name_offset, l_name_buf, lmo->l_name_size);
+
+ /* Convert the address to host format. Assume that the address is
+ unsigned. */
+ l_name = extract_unsigned_integer (l_name_buf, lmo->l_name_size);
+
+ /* Free l_name_buf. */
+ do_cleanups (cleanups);
+
+ if (l_name == 0)
+ return 0; /* No filename. */
+
+ /* Now fetch the filename from target memory. */
+ target_read_string (l_name, &filename, SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+
+ if (errcode)
+ {
+ warning ("failed to read exec filename from attached file: %s",
+ safe_strerror (errcode));
+ return 0;
+ }
+
+ make_cleanup (xfree, filename);
+ /* Have a pathname: read the symbol file. */
+ symbol_file_add_main (filename, from_tty);
+
+ return 1;
+}
+
+/* LOCAL FUNCTION
+
+ current_sos -- build a list of currently loaded shared objects
+
+ SYNOPSIS
+
+ struct so_list *current_sos ()
+
+ DESCRIPTION
+
+ Build a list of `struct so_list' objects describing the shared
+ objects currently loaded in the inferior. This list does not
+ include an entry for the main executable file.
+
+ Note that we only gather information directly available from the
+ inferior --- we don't examine any of the shared library files
+ themselves. The declaration of `struct so_list' says which fields
+ we provide values for. */
+
+static struct so_list *
+svr4_current_sos (void)
+{
+ CORE_ADDR lm;
+ struct so_list *head = 0;
+ struct so_list **link_ptr = &head;
+
+ /* Make sure we've looked up the inferior's dynamic linker's base
+ structure. */
+ if (! debug_base)
+ {
+ debug_base = locate_base ();
+
+ /* If we can't find the dynamic linker's base structure, this
+ must not be a dynamically linked executable. Hmm. */
+ if (! debug_base)
+ return 0;
+ }
+
+ /* Walk the inferior's link map list, and build our list of
+ `struct so_list' nodes. */
+ lm = first_link_map_member ();
+ while (lm)
+ {
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+ struct so_list *new
+ = (struct so_list *) xmalloc (sizeof (struct so_list));
+ struct cleanup *old_chain = make_cleanup (xfree, new);
+
+ memset (new, 0, sizeof (*new));
+
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ make_cleanup (xfree, new->lm_info);
+
+ new->lm_info->lm = xmalloc (lmo->link_map_size);
+ make_cleanup (xfree, new->lm_info->lm);
+ memset (new->lm_info->lm, 0, lmo->link_map_size);
+
+ read_memory (lm, new->lm_info->lm, lmo->link_map_size);
+
+ lm = LM_NEXT (new);
+
+ /* For SVR4 versions, the first entry in the link map is for the
+ inferior executable, so we must ignore it. For some versions of
+ SVR4, it has no name. For others (Solaris 2.3 for example), it
+ does have a name, so we can no longer use a missing name to
+ decide when to ignore it. */
+ if (IGNORE_FIRST_LINK_MAP_ENTRY (new))
+ free_so (new);
+ else
+ {
+ int errcode;
+ char *buffer;
+
+ /* Extract this shared object's name. */
+ target_read_string (LM_NAME (new), &buffer,
+ SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+ if (errcode != 0)
+ {
+ warning ("current_sos: Can't read pathname for load map: %s\n",
+ safe_strerror (errcode));
+ }
+ else
+ {
+ strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ xfree (buffer);
+ strcpy (new->so_original_name, new->so_name);
+ }
+
+ /* If this entry has no name, or its name matches the name
+ for the main executable, don't include it in the list. */
+ if (! new->so_name[0]
+ || match_main (new->so_name))
+ free_so (new);
+ else
+ {
+ new->next = 0;
+ *link_ptr = new;
+ link_ptr = &new->next;
+ }
+ }
+
+ discard_cleanups (old_chain);
+ }
+
+ return head;
+}
+
+/* Get the address of the link_map for a given OBJFILE. Loop through
+ the link maps, and return the address of the one corresponding to
+ the given objfile. Note that this function takes into account that
+ objfile can be the main executable, not just a shared library. The
+ main executable has always an empty name field in the linkmap. */
+
+CORE_ADDR
+svr4_fetch_objfile_link_map (struct objfile *objfile)
+{
+ CORE_ADDR lm;
+
+ if ((debug_base = locate_base ()) == 0)
+ return 0; /* failed somehow... */
+
+ /* Position ourselves on the first link map. */
+ lm = first_link_map_member ();
+ while (lm)
+ {
+ /* Get info on the layout of the r_debug and link_map structures. */
+ struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
+ int errcode;
+ char *buffer;
+ struct lm_info objfile_lm_info;
+ struct cleanup *old_chain;
+ CORE_ADDR name_address;
+ char *l_name_buf = xmalloc (lmo->l_name_size);
+ old_chain = make_cleanup (xfree, l_name_buf);
+
+ /* Set up the buffer to contain the portion of the link_map
+ structure that gdb cares about. Note that this is not the
+ whole link_map structure. */
+ objfile_lm_info.lm = xmalloc (lmo->link_map_size);
+ make_cleanup (xfree, objfile_lm_info.lm);
+ memset (objfile_lm_info.lm, 0, lmo->link_map_size);
+
+ /* Read the link map into our internal structure. */
+ read_memory (lm, objfile_lm_info.lm, lmo->link_map_size);
+
+ /* Read address of name from target memory to GDB. */
+ read_memory (lm + lmo->l_name_offset, l_name_buf, lmo->l_name_size);
+
+ /* Extract this object's name. Assume that the address is
+ unsigned. */
+ name_address = extract_unsigned_integer (l_name_buf, lmo->l_name_size);
+ target_read_string (name_address, &buffer,
+ SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+ make_cleanup (xfree, buffer);
+ if (errcode != 0)
+ {
+ warning ("svr4_fetch_objfile_link_map: Can't read pathname for load map: %s\n",
+ safe_strerror (errcode));
+ }
+ else
+ {
+ /* Is this the linkmap for the file we want? */
+ /* If the file is not a shared library and has no name,
+ we are sure it is the main executable, so we return that. */
+ if ((buffer && strcmp (buffer, objfile->name) == 0)
+ || (!(objfile->flags & OBJF_SHARED) && (strcmp (buffer, "") == 0)))
+ {
+ do_cleanups (old_chain);
+ return lm;
+ }
+ }
+ /* Not the file we wanted, continue checking. Assume that the
+ address is unsigned. */
+ lm = extract_unsigned_integer (objfile_lm_info.lm + lmo->l_next_offset,
+ lmo->l_next_size);
+ do_cleanups (old_chain);
+ }
+ return 0;
+}
+
+/* On some systems, the only way to recognize the link map entry for
+ the main executable file is by looking at its name. Return
+ non-zero iff SONAME matches one of the known main executable names. */
+
+static int
+match_main (char *soname)
+{
+ char **mainp;
+
+ for (mainp = main_name_list; *mainp != NULL; mainp++)
+ {
+ if (strcmp (soname, *mainp) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/* Return 1 if PC lies in the dynamic symbol resolution code of the
+ SVR4 run time loader. */
+static CORE_ADDR interp_text_sect_low;
+static CORE_ADDR interp_text_sect_high;
+static CORE_ADDR interp_plt_sect_low;
+static CORE_ADDR interp_plt_sect_high;
+
+static int
+svr4_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
+ || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
+ || in_plt_section (pc, NULL));
+}
+
+/* Given an executable's ABFD and target, compute the entry-point
+ address. */
+
+static CORE_ADDR
+exec_entry_point (struct bfd *abfd, struct target_ops *targ)
+{
+ /* KevinB wrote ... for most targets, the address returned by
+ bfd_get_start_address() is the entry point for the start
+ function. But, for some targets, bfd_get_start_address() returns
+ the address of a function descriptor from which the entry point
+ address may be extracted. This address is extracted by
+ gdbarch_convert_from_func_ptr_addr(). The method
+ gdbarch_convert_from_func_ptr_addr() is the merely the identify
+ function for targets which don't use function descriptors. */
+ return gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ bfd_get_start_address (abfd),
+ targ);
+}
+
+/*
+
+ 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 (void)
+{
+ int success = 0;
+
+#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 ();
+
+ interp_text_sect_low = interp_text_sect_high = 0;
+ interp_plt_sect_low = interp_plt_sect_high = 0;
+
+ /* 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 = 0;
+ int load_addr_found = 0;
+ struct so_list *inferior_sos;
+ bfd *tmp_bfd = NULL;
+ struct target_ops *tmp_bfd_target;
+ int tmp_fd = -1;
+ char *tmp_pathname = NULL;
+ 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 GNU/Linux). Therefore, we have to try an alternate
+ mechanism to find the dynamic linker's base address. */
+
+ tmp_fd = solib_open (buf, &tmp_pathname);
+ if (tmp_fd >= 0)
+ tmp_bfd = bfd_fdopenr (tmp_pathname, gnutarget, tmp_fd);
+
+ 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;
+ }
+
+ /* Now convert the TMP_BFD into a target. That way target, as
+ well as BFD operations can be used. Note that closing the
+ target will also close the underlying bfd. */
+ tmp_bfd_target = target_bfd_reopen (tmp_bfd);
+
+ /* If the entry in _DYNAMIC for the dynamic linker has already
+ been filled in, we can read its base address from there. */
+ inferior_sos = svr4_current_sos ();
+ if (inferior_sos)
+ {
+ /* Connected to a running target. Update our shared library table. */
+ solib_add (NULL, 0, NULL, auto_solib_add);
+ }
+ while (inferior_sos)
+ {
+ if (strcmp (buf, inferior_sos->so_original_name) == 0)
+ {
+ load_addr_found = 1;
+ load_addr = LM_ADDR (inferior_sos);
+ break;
+ }
+ inferior_sos = inferior_sos->next;
+ }
+
+ /* Otherwise we find the dynamic linker's base address by examining
+ the current pc (which should point at the entry point for the
+ dynamic linker) and subtracting the offset of the entry point. */
+ if (!load_addr_found)
+ load_addr = (read_pc ()
+ - exec_entry_point (tmp_bfd, tmp_bfd_target));
+
+ /* Record the relocated start and end address of the dynamic linker
+ text and plt section for svr4_in_dynsym_resolve_code. */
+ interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
+ if (interp_sect)
+ {
+ interp_text_sect_low =
+ bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
+ interp_text_sect_high =
+ interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ }
+ interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
+ if (interp_sect)
+ {
+ interp_plt_sect_low =
+ bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
+ interp_plt_sect_high =
+ interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ }
+
+ /* Now try to set a breakpoint in the dynamic linker. */
+ for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++)
+ {
+ /* On ABI's that use function descriptors, there are usually
+ two linker symbols associated with each C function: one
+ pointing at the actual entry point of the machine code,
+ and one pointing at the function's descriptor. The
+ latter symbol has the same name as the C function.
+
+ What we're looking for here is the machine code entry
+ point, so we are only interested in symbols in code
+ sections. */
+ sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep, SEC_CODE);
+ if (sym_addr != 0)
+ break;
+ }
+
+ /* We're done with both the temporary bfd and target. Remember,
+ closing the target closes the underlying bfd. */
+ target_close (tmp_bfd_target, 0);
+
+ 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.\nGDB will be unable to debug shared library initializers\nand track explicitly loaded dynamic code.");
+ }
+
+ /* 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. */
+ success = 0;
+
+#endif /* BKPT_AT_SYMBOL */
+
+ return (success);
+}
+
+/*
+
+ LOCAL FUNCTION
+
+ special_symbol_handling -- additional shared library symbol handling
+
+ SYNOPSIS
+
+ void special_symbol_handling ()
+
+ 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 consisted 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.
+
+ However, for SVR4, there's nothing to do.
+
+ */
+
+static void
+svr4_special_symbol_handling (void)
+{
+}
+
+/* Relocate the main executable. This function should be called upon
+ stopping the inferior process at the entry point to the program.
+ The entry point from BFD is compared to the PC and if they are
+ different, the main executable is relocated by the proper amount.
+
+ As written it will only attempt to relocate executables which
+ lack interpreter sections. It seems likely that only dynamic
+ linker executables will get relocated, though it should work
+ properly for a position-independent static executable as well. */
+
+static void
+svr4_relocate_main_executable (void)
+{
+ asection *interp_sect;
+ CORE_ADDR pc = read_pc ();
+
+ /* Decide if the objfile needs to be relocated. As indicated above,
+ we will only be here when execution is stopped at the beginning
+ of the program. Relocation is necessary if the address at which
+ we are presently stopped differs from the start address stored in
+ the executable AND there's no interpreter section. The condition
+ regarding the interpreter section is very important because if
+ there *is* an interpreter section, execution will begin there
+ instead. When there is an interpreter section, the start address
+ is (presumably) used by the interpreter at some point to start
+ execution of the program.
+
+ If there is an interpreter, it is normal for it to be set to an
+ arbitrary address at the outset. The job of finding it is
+ handled in enable_break().
+
+ So, to summarize, relocations are necessary when there is no
+ interpreter section and the start address obtained from the
+ executable is different from the address at which GDB is
+ currently stopped.
+
+ [ The astute reader will note that we also test to make sure that
+ the executable in question has the DYNAMIC flag set. It is my
+ opinion that this test is unnecessary (undesirable even). It
+ was added to avoid inadvertent relocation of an executable
+ whose e_type member in the ELF header is not ET_DYN. There may
+ be a time in the future when it is desirable to do relocations
+ on other types of files as well in which case this condition
+ should either be removed or modified to accomodate the new file
+ type. (E.g, an ET_EXEC executable which has been built to be
+ position-independent could safely be relocated by the OS if
+ desired. It is true that this violates the ABI, but the ABI
+ has been known to be bent from time to time.) - Kevin, Nov 2000. ]
+ */
+
+ interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+ if (interp_sect == NULL
+ && (bfd_get_file_flags (exec_bfd) & DYNAMIC) != 0
+ && (exec_entry_point (exec_bfd, &exec_ops) != pc))
+ {
+ struct cleanup *old_chain;
+ struct section_offsets *new_offsets;
+ int i, changed;
+ CORE_ADDR displacement;
+
+ /* It is necessary to relocate the objfile. The amount to
+ relocate by is simply the address at which we are stopped
+ minus the starting address from the executable.
+
+ We relocate all of the sections by the same amount. This
+ behavior is mandated by recent editions of the System V ABI.
+ According to the System V Application Binary Interface,
+ Edition 4.1, page 5-5:
+
+ ... Though the system chooses virtual addresses for
+ individual processes, it maintains the segments' relative
+ positions. Because position-independent code uses relative
+ addressesing between segments, the difference between
+ virtual addresses in memory must match the difference
+ between virtual addresses in the file. The difference
+ between the virtual address of any segment in memory and
+ the corresponding virtual address in the file is thus a
+ single constant value for any one executable or shared
+ object in a given process. This difference is the base
+ address. One use of the base address is to relocate the
+ memory image of the program during dynamic linking.
+
+ The same language also appears in Edition 4.0 of the System V
+ ABI and is left unspecified in some of the earlier editions. */
+
+ displacement = pc - exec_entry_point (exec_bfd, &exec_ops);
+ changed = 0;
+
+ new_offsets = xcalloc (symfile_objfile->num_sections,
+ sizeof (struct section_offsets));
+ old_chain = make_cleanup (xfree, new_offsets);
+
+ for (i = 0; i < symfile_objfile->num_sections; i++)
+ {
+ if (displacement != ANOFFSET (symfile_objfile->section_offsets, i))
+ changed = 1;
+ new_offsets->offsets[i] = displacement;
+ }
+
+ if (changed)
+ objfile_relocate (symfile_objfile, new_offsets);
+
+ do_cleanups (old_chain);
+ }
+}
+
+/*
+
+ GLOBAL FUNCTION
+
+ svr4_solib_create_inferior_hook -- shared library startup support
+
+ SYNOPSIS
+
+ void svr4_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.
+ */
+
+static void
+svr4_solib_create_inferior_hook (void)
+{
+ /* Relocate the main executable if necessary. */
+ svr4_relocate_main_executable ();
+
+ if (!svr4_have_link_map_offsets ())
+ {
+ warning ("no shared library support for this OS / ABI");
+ return;
+
+ }
+
+ if (!enable_break ())
+ {
+ warning ("shared library handler failed to enable breakpoint");
+ return;
+ }
+
+#if defined(_SCO_DS)
+ /* SCO needs the loop below, other systems should be using the
+ special shared library breakpoints and the shared library breakpoint
+ service routine.
+
+ Now run the target. It will eventually hit the breakpoint, at
+ which point all of the libraries will have been mapped in and we
+ can go groveling around in the dynamic linker structures to find
+ out what we need to know about them. */
+
+ clear_proceed_status ();
+ stop_soon = STOP_QUIETLY;
+ stop_signal = TARGET_SIGNAL_0;
+ do
+ {
+ target_resume (pid_to_ptid (-1), 0, stop_signal);
+ wait_for_inferior ();
+ }
+ while (stop_signal != TARGET_SIGNAL_TRAP);
+ stop_soon = NO_STOP_QUIETLY;
+#endif /* defined(_SCO_DS) */
+}
+
+static void
+svr4_clear_solib (void)
+{
+ debug_base = 0;
+}
+
+static void
+svr4_free_so (struct so_list *so)
+{
+ xfree (so->lm_info->lm);
+ xfree (so->lm_info);
+}
+
+
+/* Clear any bits of ADDR that wouldn't fit in a target-format
+ data pointer. "Data pointer" here refers to whatever sort of
+ address the dynamic linker uses to manage its sections. At the
+ moment, we don't support shared libraries on any processors where
+ code and data pointers are different sizes.
+
+ This isn't really the right solution. What we really need here is
+ a way to do arithmetic on CORE_ADDR values that respects the
+ natural pointer/address correspondence. (For example, on the MIPS,
+ converting a 32-bit pointer to a 64-bit CORE_ADDR requires you to
+ sign-extend the value. There, simply truncating the bits above
+ TARGET_PTR_BIT, as we do below, is no good.) This should probably
+ be a new gdbarch method or something. */
+static CORE_ADDR
+svr4_truncate_ptr (CORE_ADDR addr)
+{
+ if (TARGET_PTR_BIT == sizeof (CORE_ADDR) * 8)
+ /* We don't need to truncate anything, and the bit twiddling below
+ will fail due to overflow problems. */
+ return addr;
+ else
+ return addr & (((CORE_ADDR) 1 << TARGET_PTR_BIT) - 1);
+}
+
+
+static void
+svr4_relocate_section_addresses (struct so_list *so,
+ struct section_table *sec)
+{
+ sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR (so));
+ sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR (so));
+}
+
+
+/* Fetch a link_map_offsets structure for native targets using struct
+ definitions from link.h. See solib-legacy.c for the function
+ which does the actual work.
+
+ Note: For non-native targets (i.e. cross-debugging situations),
+ a target specific fetch_link_map_offsets() function should be
+ defined and registered via set_solib_svr4_fetch_link_map_offsets(). */
+
+static struct link_map_offsets *
+legacy_fetch_link_map_offsets (void)
+{
+ if (legacy_svr4_fetch_link_map_offsets_hook)
+ return legacy_svr4_fetch_link_map_offsets_hook ();
+ else
+ {
+ internal_error (__FILE__, __LINE__,
+ "legacy_fetch_link_map_offsets called without legacy "
+ "link_map support enabled.");
+ return 0;
+ }
+}
+
+/* Fetch a link_map_offsets structure using the method registered in the
+ architecture vector. */
+
+static struct link_map_offsets *
+svr4_fetch_link_map_offsets (void)
+{
+ struct link_map_offsets *(*flmo)(void) =
+ gdbarch_data (current_gdbarch, fetch_link_map_offsets_gdbarch_data);
+
+ if (flmo == NULL)
+ {
+ internal_error (__FILE__, __LINE__,
+ "svr4_fetch_link_map_offsets: fetch_link_map_offsets "
+ "method not defined for this architecture.");
+ return 0;
+ }
+ else
+ return (flmo ());
+}
+
+/* Return 1 if a link map offset fetcher has been defined, 0 otherwise. */
+static int
+svr4_have_link_map_offsets (void)
+{
+ struct link_map_offsets *(*flmo)(void) =
+ gdbarch_data (current_gdbarch, fetch_link_map_offsets_gdbarch_data);
+ if (flmo == NULL
+ || (flmo == legacy_fetch_link_map_offsets
+ && legacy_svr4_fetch_link_map_offsets_hook == NULL))
+ return 0;
+ else
+ return 1;
+}
+
+/* set_solib_svr4_fetch_link_map_offsets() is intended to be called by
+ a <arch>_gdbarch_init() function. It is used to establish an
+ architecture specific link_map_offsets fetcher for the architecture
+ being defined. */
+
+void
+set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch,
+ struct link_map_offsets *(*flmo) (void))
+{
+ set_gdbarch_data (gdbarch, fetch_link_map_offsets_gdbarch_data, flmo);
+}
+
+/* Initialize the architecture-specific link_map_offsets fetcher.
+ This is called after <arch>_gdbarch_init() has set up its `struct
+ gdbarch' for the new architecture, and is only called if the
+ link_map_offsets fetcher isn't already initialized (which is
+ usually done by calling set_solib_svr4_fetch_link_map_offsets()
+ above in <arch>_gdbarch_init()). Therefore we attempt to provide a
+ reasonable alternative (for native targets anyway) if the
+ <arch>_gdbarch_init() fails to call
+ set_solib_svr4_fetch_link_map_offsets(). */
+
+static void *
+init_fetch_link_map_offsets (struct gdbarch *gdbarch)
+{
+ return legacy_fetch_link_map_offsets;
+}
+
+/* Most OS'es that have SVR4-style ELF dynamic libraries define a
+ `struct r_debug' and a `struct link_map' that are binary compatible
+ with the origional SVR4 implementation. */
+
+/* Fetch (and possibly build) an appropriate `struct link_map_offsets'
+ for an ILP32 SVR4 system. */
+
+struct link_map_offsets *
+svr4_ilp32_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ /* Everything we need is in the first 8 bytes. */
+ lmo.r_debug_size = 8;
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ /* Everything we need is in the first 20 bytes. */
+ lmo.link_map_size = 20;
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+/* Fetch (and possibly build) an appropriate `struct link_map_offsets'
+ for an LP64 SVR4 system. */
+
+struct link_map_offsets *
+svr4_lp64_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ /* Everything we need is in the first 16 bytes. */
+ lmo.r_debug_size = 16;
+ lmo.r_map_offset = 8;
+ lmo.r_map_size = 8;
+
+ /* Everything we need is in the first 40 bytes. */
+ lmo.link_map_size = 40;
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 8;
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 8;
+ lmo.l_next_offset = 24;
+ lmo.l_next_size = 8;
+ lmo.l_prev_offset = 32;
+ lmo.l_prev_size = 8;
+ }
+
+ return lmp;
+}
+
+
+static struct target_so_ops svr4_so_ops;
+
+extern initialize_file_ftype _initialize_svr4_solib; /* -Wmissing-prototypes */
+
+void
+_initialize_svr4_solib (void)
+{
+ fetch_link_map_offsets_gdbarch_data =
+ register_gdbarch_data (init_fetch_link_map_offsets);
+
+ svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
+ svr4_so_ops.free_so = svr4_free_so;
+ svr4_so_ops.clear_solib = svr4_clear_solib;
+ svr4_so_ops.solib_create_inferior_hook = svr4_solib_create_inferior_hook;
+ svr4_so_ops.special_symbol_handling = svr4_special_symbol_handling;
+ svr4_so_ops.current_sos = svr4_current_sos;
+ svr4_so_ops.open_symbol_file_object = open_symbol_file_object;
+ svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
+
+ /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
+ current_target_so_ops = &svr4_so_ops;
+}
diff --git a/contrib/gdb/gdb/solib-svr4.h b/contrib/gdb/gdb/solib-svr4.h
new file mode 100644
index 0000000..d76c7f5
--- /dev/null
+++ b/contrib/gdb/gdb/solib-svr4.h
@@ -0,0 +1,90 @@
+/* Handle shared libraries for GDB, the GNU Debugger.
+
+ Copyright 2000, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 objfile;
+
+/* Critical offsets and sizes which describe struct r_debug and
+ struct link_map on SVR4-like targets. All offsets and sizes are
+ in bytes unless otherwise specified. */
+
+struct link_map_offsets
+ {
+ /* Size of struct r_debug (or equivalent), or at least enough of it to
+ be able to obtain the r_map field. */
+ int r_debug_size;
+
+ /* Offset to the r_map field in struct r_debug. */
+ int r_map_offset;
+
+ /* Size of the r_map field in struct r_debug. */
+ int r_map_size;
+
+ /* Size of struct link_map (or equivalent), or at least enough of it
+ to be able to obtain the fields below. */
+ int link_map_size;
+
+ /* Offset to l_addr field in struct link_map. */
+ int l_addr_offset;
+
+ /* Size of l_addr field in struct link_map. */
+ int l_addr_size;
+
+ /* Offset to l_next field in struct link_map. */
+ int l_next_offset;
+
+ /* Size of l_next field in struct link_map. */
+ int l_next_size;
+
+ /* Offset to l_prev field in struct link_map. */
+ int l_prev_offset;
+
+ /* Size of l_prev field in struct link_map. */
+ int l_prev_size;
+
+ /* Offset to l_name field in struct link_map. */
+ int l_name_offset;
+
+ /* Size of l_name field in struct link_map. */
+ int l_name_size;
+ };
+
+/* set_solib_svr4_fetch_link_map_offsets() is intended to be called by
+ a <arch>_gdbarch_init() function. It is used to establish an
+ architecture specific link_map_offsets fetcher for the architecture
+ being defined. */
+
+extern void set_solib_svr4_fetch_link_map_offsets
+ (struct gdbarch *gdbarch, struct link_map_offsets *(*func) (void));
+
+/* This function is called by thread_db.c. Return the address of the
+ link map for the given objfile. */
+extern CORE_ADDR svr4_fetch_objfile_link_map (struct objfile *objfile);
+
+/* legacy_svr4_fetch_link_map_offsets_hook is a pointer to a function
+ which is used to fetch link map offsets. It will only be set
+ by solib-legacy.c, if at all. */
+extern struct link_map_offsets *(*legacy_svr4_fetch_link_map_offsets_hook)(void);
+
+/* Fetch (and possibly build) an appropriate `struct link_map_offsets'
+ for ILP32 and LP64 SVR4 systems. */
+extern struct link_map_offsets *svr4_ilp32_fetch_link_map_offsets (void);
+extern struct link_map_offsets *svr4_lp64_fetch_link_map_offsets (void);
diff --git a/contrib/gdb/gdb/solib.c b/contrib/gdb/gdb/solib.c
new file mode 100644
index 0000000..a98c3bd
--- /dev/null
+++ b/contrib/gdb/gdb/solib.c
@@ -0,0 +1,912 @@
+/* Handle shared libraries for GDB, the GNU Debugger.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <sys/types.h>
+#include <fcntl.h>
+#include "gdb_string.h"
+#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 "gdb_regex.h"
+#include "inferior.h"
+#include "environ.h"
+#include "language.h"
+#include "gdbcmd.h"
+#include "completer.h"
+#include "filenames.h" /* for DOSish file names */
+#include "exec.h"
+#include "solist.h"
+#include "readline/readline.h"
+
+/* external data declarations */
+
+/* FIXME: gdbarch needs to control this variable */
+struct target_so_ops *current_target_so_ops;
+
+/* local data declarations */
+
+static struct so_list *so_list_head; /* List of known shared objects */
+
+static int solib_cleanup_queued = 0; /* make_run_cleanup called */
+
+/* Local function prototypes */
+
+static void do_clear_solib (void *);
+
+/* If non-zero, this is a prefix that will be added to the front of the name
+ shared libraries with an absolute filename for loading. */
+static char *solib_absolute_prefix = NULL;
+
+/* If non-empty, this is a search path for loading non-absolute shared library
+ symbol files. This takes precedence over the environment variables PATH
+ and LD_LIBRARY_PATH. */
+static char *solib_search_path = NULL;
+
+/*
+
+ GLOBAL FUNCTION
+
+ solib_open -- Find a shared library file and open it.
+
+ SYNOPSIS
+
+ int solib_open (char *in_patname, char **found_pathname);
+
+ DESCRIPTION
+
+ Global variable SOLIB_ABSOLUTE_PREFIX is used as a prefix directory
+ to search for shared libraries if they have an absolute path.
+
+ Global variable SOLIB_SEARCH_PATH is used as a prefix directory
+ (or set of directories, as in LD_LIBRARY_PATH) to search for all
+ shared libraries if not found in SOLIB_ABSOLUTE_PREFIX.
+
+ Search algorithm:
+ * If there is a solib_absolute_prefix and path is absolute:
+ * Search for solib_absolute_prefix/path.
+ * else
+ * Look for it literally (unmodified).
+ * Look in SOLIB_SEARCH_PATH.
+ * If available, use target defined search function.
+ * If solib_absolute_prefix is NOT set, perform the following two searches:
+ * Look in inferior's $PATH.
+ * Look in inferior's $LD_LIBRARY_PATH.
+ *
+ * The last check avoids doing this search when targetting remote
+ * machines since solib_absolute_prefix will almost always be set.
+
+ RETURNS
+
+ file handle for opened solib, or -1 for failure. */
+
+int
+solib_open (char *in_pathname, char **found_pathname)
+{
+ int found_file = -1;
+ char *temp_pathname = NULL;
+ char *p = in_pathname;
+
+ while (*p && !IS_DIR_SEPARATOR (*p))
+ p++;
+
+ if (*p)
+ {
+ if (! IS_ABSOLUTE_PATH (in_pathname) || solib_absolute_prefix == NULL)
+ temp_pathname = in_pathname;
+ else
+ {
+ int prefix_len = strlen (solib_absolute_prefix);
+
+ /* Remove trailing slashes from absolute prefix. */
+ while (prefix_len > 0
+ && IS_DIR_SEPARATOR (solib_absolute_prefix[prefix_len - 1]))
+ prefix_len--;
+
+ /* Cat the prefixed pathname together. */
+ temp_pathname = alloca (prefix_len + strlen (in_pathname) + 1);
+ strncpy (temp_pathname, solib_absolute_prefix, prefix_len);
+ temp_pathname[prefix_len] = '\0';
+ strcat (temp_pathname, in_pathname);
+ }
+
+ /* Now see if we can open it. */
+ found_file = open (temp_pathname, O_RDONLY, 0);
+ }
+
+ /* If the search in solib_absolute_prefix failed, and the path name is
+ absolute at this point, make it relative. (openp will try and open the
+ file according to its absolute path otherwise, which is not what we want.)
+ Affects subsequent searches for this solib. */
+ if (found_file < 0 && IS_ABSOLUTE_PATH (in_pathname))
+ {
+ /* First, get rid of any drive letters etc. */
+ while (!IS_DIR_SEPARATOR (*in_pathname))
+ in_pathname++;
+
+ /* Next, get rid of all leading dir separators. */
+ while (IS_DIR_SEPARATOR (*in_pathname))
+ in_pathname++;
+ }
+
+ /* If not found, search the solib_search_path (if any). */
+ if (found_file < 0 && solib_search_path != NULL)
+ found_file = openp (solib_search_path,
+ 1, in_pathname, O_RDONLY, 0, &temp_pathname);
+
+ /* If not found, next search the solib_search_path (if any) for the basename
+ only (ignoring the path). This is to allow reading solibs from a path
+ that differs from the opened path. */
+ if (found_file < 0 && solib_search_path != NULL)
+ found_file = openp (solib_search_path,
+ 1, lbasename (in_pathname), O_RDONLY, 0,
+ &temp_pathname);
+
+ /* If not found, try to use target supplied solib search method */
+ if (found_file < 0 && TARGET_SO_FIND_AND_OPEN_SOLIB != NULL)
+ found_file = TARGET_SO_FIND_AND_OPEN_SOLIB
+ (in_pathname, O_RDONLY, &temp_pathname);
+
+ /* If not found, next search the inferior's $PATH environment variable. */
+ if (found_file < 0 && solib_absolute_prefix == NULL)
+ found_file = openp (get_in_environ (inferior_environ, "PATH"),
+ 1, in_pathname, O_RDONLY, 0, &temp_pathname);
+
+ /* If not found, next search the inferior's $LD_LIBRARY_PATH
+ environment variable. */
+ if (found_file < 0 && solib_absolute_prefix == NULL)
+ found_file = openp (get_in_environ (inferior_environ, "LD_LIBRARY_PATH"),
+ 1, in_pathname, O_RDONLY, 0, &temp_pathname);
+
+ /* Done. If not found, tough luck. Return found_file and
+ (optionally) found_pathname. */
+ if (found_pathname != NULL && temp_pathname != NULL)
+ *found_pathname = xstrdup (temp_pathname);
+ return found_file;
+}
+
+
+/*
+
+ LOCAL FUNCTION
+
+ solib_map_sections -- open bfd and build sections for shared lib
+
+ SYNOPSIS
+
+ static int 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 int
+solib_map_sections (void *arg)
+{
+ struct so_list *so = (struct so_list *) arg; /* catch_errors bogon */
+ 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 (xfree, filename);
+ scratch_chan = solib_open (filename, &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;
+ bfd_set_cacheable (abfd, 1);
+
+ /* copy full path name into so_name, so that later symbol_file_add
+ can find it */
+ if (strlen (scratch_pathname) >= SO_NAME_MAX_PATH_SIZE)
+ error ("Full path name length of shared library exceeds SO_NAME_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. */
+ TARGET_SO_RELOCATE_SECTION_ADDRESSES (so, p);
+ if (strcmp (p->the_bfd_section->name, ".text") == 0)
+ {
+ so->textsection = p;
+ }
+ }
+
+ /* Free the file names, close the file now. */
+ do_cleanups (old_chain);
+
+ return (1);
+}
+
+/* LOCAL FUNCTION
+
+ free_so --- free a `struct so_list' object
+
+ SYNOPSIS
+
+ void free_so (struct so_list *so)
+
+ DESCRIPTION
+
+ Free the storage associated with the `struct so_list' object SO.
+ If we have opened a BFD for SO, close it.
+
+ The caller is responsible for removing SO from whatever list it is
+ a member of. If we have placed SO's sections in some target's
+ section table, the caller is responsible for removing them.
+
+ This function doesn't mess with objfiles at all. If there is an
+ objfile associated with SO that needs to be removed, the caller is
+ responsible for taking care of that. */
+
+void
+free_so (struct so_list *so)
+{
+ char *bfd_filename = 0;
+
+ if (so->sections)
+ xfree (so->sections);
+
+ if (so->abfd)
+ {
+ bfd_filename = bfd_get_filename (so->abfd);
+ if (! bfd_close (so->abfd))
+ warning ("cannot close \"%s\": %s",
+ bfd_filename, bfd_errmsg (bfd_get_error ()));
+ }
+
+ if (bfd_filename)
+ xfree (bfd_filename);
+
+ TARGET_SO_FREE_SO (so);
+
+ xfree (so);
+}
+
+
+/* A small stub to get us past the arg-passing pinhole of catch_errors. */
+
+static int
+symbol_add_stub (void *arg)
+{
+ struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */
+ struct section_addr_info *sap;
+
+ /* Have we already loaded this shared object? */
+ ALL_OBJFILES (so->objfile)
+ {
+ if (strcmp (so->objfile->name, so->so_name) == 0)
+ return 1;
+ }
+
+ sap = build_section_addr_info_from_section_table (so->sections,
+ so->sections_end);
+
+ so->objfile = symbol_file_add (so->so_name, so->from_tty,
+ sap, 0, OBJF_SHARED);
+ free_section_addr_info (sap);
+
+ return (1);
+}
+
+
+/* LOCAL FUNCTION
+
+ update_solib_list --- synchronize GDB's shared object list with inferior's
+
+ SYNOPSIS
+
+ void update_solib_list (int from_tty, struct target_ops *TARGET)
+
+ Extract the list of currently loaded shared objects from the
+ inferior, and compare it with the list of shared objects currently
+ in GDB's so_list_head list. Edit so_list_head to bring it in sync
+ with the inferior's new list.
+
+ If we notice that the inferior has unloaded some shared objects,
+ free any symbolic info GDB had read about those shared objects.
+
+ Don't load symbolic info for any new shared objects; just add them
+ to the list, and leave their symbols_loaded flag clear.
+
+ If FROM_TTY is non-null, feel free to print messages about what
+ we're doing.
+
+ If TARGET is non-null, add the sections of all new shared objects
+ to TARGET's section table. Note that this doesn't remove any
+ sections for shared objects that have been unloaded, and it
+ doesn't check to see if the new shared objects are already present in
+ the section table. But we only use this for core files and
+ processes we've just attached to, so that's okay. */
+
+static void
+update_solib_list (int from_tty, struct target_ops *target)
+{
+ struct so_list *inferior = TARGET_SO_CURRENT_SOS ();
+ struct so_list *gdb, **gdb_link;
+
+ /* If we are attaching to a running process for which we
+ have not opened a symbol file, we may be able to get its
+ symbols now! */
+ if (attach_flag &&
+ symfile_objfile == NULL)
+ catch_errors (TARGET_SO_OPEN_SYMBOL_FILE_OBJECT, &from_tty,
+ "Error reading attached process's symbol file.\n",
+ RETURN_MASK_ALL);
+
+ /* Since this function might actually add some elements to the
+ so_list_head list, arrange for it to be cleaned up when
+ appropriate. */
+ if (!solib_cleanup_queued)
+ {
+ make_run_cleanup (do_clear_solib, NULL);
+ solib_cleanup_queued = 1;
+ }
+
+ /* GDB and the inferior's dynamic linker each maintain their own
+ list of currently loaded shared objects; we want to bring the
+ former in sync with the latter. Scan both lists, seeing which
+ shared objects appear where. There are three cases:
+
+ - A shared object appears on both lists. This means that GDB
+ knows about it already, and it's still loaded in the inferior.
+ Nothing needs to happen.
+
+ - A shared object appears only on GDB's list. This means that
+ the inferior has unloaded it. We should remove the shared
+ object from GDB's tables.
+
+ - A shared object appears only on the inferior's list. This
+ means that it's just been loaded. We should add it to GDB's
+ tables.
+
+ So we walk GDB's list, checking each entry to see if it appears
+ in the inferior's list too. If it does, no action is needed, and
+ we remove it from the inferior's list. If it doesn't, the
+ inferior has unloaded it, and we remove it from GDB's list. By
+ the time we're done walking GDB's list, the inferior's list
+ contains only the new shared objects, which we then add. */
+
+ gdb = so_list_head;
+ gdb_link = &so_list_head;
+ while (gdb)
+ {
+ struct so_list *i = inferior;
+ struct so_list **i_link = &inferior;
+
+ /* Check to see whether the shared object *gdb also appears in
+ the inferior's current list. */
+ while (i)
+ {
+ if (! strcmp (gdb->so_original_name, i->so_original_name))
+ break;
+
+ i_link = &i->next;
+ i = *i_link;
+ }
+
+ /* If the shared object appears on the inferior's list too, then
+ it's still loaded, so we don't need to do anything. Delete
+ it from the inferior's list, and leave it on GDB's list. */
+ if (i)
+ {
+ *i_link = i->next;
+ free_so (i);
+ gdb_link = &gdb->next;
+ gdb = *gdb_link;
+ }
+
+ /* If it's not on the inferior's list, remove it from GDB's tables. */
+ else
+ {
+ *gdb_link = gdb->next;
+
+ /* Unless the user loaded it explicitly, free SO's objfile. */
+ if (gdb->objfile && ! (gdb->objfile->flags & OBJF_USERLOADED))
+ free_objfile (gdb->objfile);
+
+ /* Some targets' section tables might be referring to
+ sections from so->abfd; remove them. */
+ remove_target_sections (gdb->abfd);
+
+ free_so (gdb);
+ gdb = *gdb_link;
+ }
+ }
+
+ /* Now the inferior's list contains only shared objects that don't
+ appear in GDB's list --- those that are newly loaded. Add them
+ to GDB's shared object list. */
+ if (inferior)
+ {
+ struct so_list *i;
+
+ /* Add the new shared objects to GDB's list. */
+ *gdb_link = inferior;
+
+ /* Fill in the rest of each of the `struct so_list' nodes. */
+ for (i = inferior; i; i = i->next)
+ {
+ i->from_tty = from_tty;
+
+ /* Fill in the rest of the `struct so_list' node. */
+ catch_errors (solib_map_sections, i,
+ "Error while mapping shared library sections:\n",
+ RETURN_MASK_ALL);
+
+ /* If requested, add the shared object's sections to the TARGET's
+ section table. Do this immediately after mapping the object so
+ that later nodes in the list can query this object, as is needed
+ in solib-osf.c. */
+ if (target)
+ {
+ int count = (i->sections_end - i->sections);
+ if (count > 0)
+ {
+ int space = target_resize_to_sections (target, count);
+ memcpy (target->to_sections + space,
+ i->sections,
+ count * sizeof (i->sections[0]));
+ }
+ }
+ }
+ }
+}
+
+
+/* GLOBAL FUNCTION
+
+ solib_add -- read in symbol info for newly added shared libraries
+
+ SYNOPSIS
+
+ void solib_add (char *pattern, int from_tty, struct target_ops
+ *TARGET, int readsyms)
+
+ DESCRIPTION
+
+ Read in symbolic information for any shared objects whose names
+ match PATTERN. (If we've already read a shared object's symbol
+ info, leave it alone.) If PATTERN is zero, read them all.
+
+ If READSYMS is 0, defer reading symbolic information until later
+ but still do any needed low level processing.
+
+ FROM_TTY and TARGET are as described for update_solib_list, above. */
+
+void
+solib_add (char *pattern, int from_tty, struct target_ops *target, int readsyms)
+{
+ struct so_list *gdb;
+
+ if (pattern)
+ {
+ char *re_err = re_comp (pattern);
+
+ if (re_err)
+ error ("Invalid regexp: %s", re_err);
+ }
+
+ update_solib_list (from_tty, target);
+
+ /* Walk the list of currently loaded shared libraries, and read
+ symbols for any that match the pattern --- or any whose symbols
+ aren't already loaded, if no pattern was given. */
+ {
+ int any_matches = 0;
+ int loaded_any_symbols = 0;
+
+ for (gdb = so_list_head; gdb; gdb = gdb->next)
+ if (! pattern || re_exec (gdb->so_name))
+ {
+ any_matches = 1;
+
+ if (gdb->symbols_loaded)
+ {
+ if (from_tty)
+ printf_unfiltered ("Symbols already loaded for %s\n",
+ gdb->so_name);
+ }
+ else if (readsyms)
+ {
+ if (catch_errors
+ (symbol_add_stub, gdb,
+ "Error while reading shared library symbols:\n",
+ RETURN_MASK_ALL))
+ {
+ if (from_tty)
+ printf_unfiltered ("Loaded symbols for %s\n",
+ gdb->so_name);
+ gdb->symbols_loaded = 1;
+ loaded_any_symbols = 1;
+ }
+ }
+ }
+
+ if (from_tty && pattern && ! any_matches)
+ printf_unfiltered
+ ("No loaded shared libraries match the pattern `%s'.\n", pattern);
+
+ if (loaded_any_symbols)
+ {
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ reinit_frame_cache ();
+
+ TARGET_SO_SPECIAL_SYMBOL_HANDLING ();
+ }
+ }
+}
+
+
+/*
+
+ 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 (char *ignore, int from_tty)
+{
+ struct so_list *so = NULL; /* link map state variable */
+ int header_done = 0;
+ int addr_width;
+ char *addr_fmt;
+
+ if (TARGET_PTR_BIT == 32)
+ {
+ addr_width = 8 + 4;
+ addr_fmt = "08l";
+ }
+ else if (TARGET_PTR_BIT == 64)
+ {
+ addr_width = 16 + 4;
+ addr_fmt = "016l";
+ }
+ else
+ {
+ internal_error (__FILE__, __LINE__,
+ "TARGET_PTR_BIT returned unknown size %d",
+ TARGET_PTR_BIT);
+ }
+
+ update_solib_list (from_tty, 0);
+
+ for (so = so_list_head; so; so = so->next)
+ {
+ if (so->so_name[0])
+ {
+ if (!header_done)
+ {
+ printf_unfiltered ("%-*s%-*s%-12s%s\n", addr_width, "From",
+ addr_width, "To", "Syms Read",
+ "Shared Object Library");
+ header_done++;
+ }
+
+ printf_unfiltered ("%-*s", addr_width,
+ so->textsection != NULL
+ ? local_hex_string_custom (
+ (LONGEST) so->textsection->addr,
+ addr_fmt)
+ : "");
+ printf_unfiltered ("%-*s", addr_width,
+ so->textsection != NULL
+ ? local_hex_string_custom (
+ (LONGEST) so->textsection->endaddr,
+ addr_fmt)
+ : "");
+ 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.
+
+ 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 (CORE_ADDR address)
+{
+ struct so_list *so = 0; /* link map state variable */
+
+ for (so = so_list_head; so; so = so->next)
+ {
+ struct section_table *p;
+
+ for (p = so->sections; p < so->sections_end; p++)
+ {
+ if (p->addr <= address && address < p->endaddr)
+ return (so->so_name);
+ }
+ }
+
+ return (0);
+}
+
+/* Called by free_all_symtabs */
+
+void
+clear_solib (void)
+{
+ /* This function is expected to handle ELF shared libraries. It is
+ also used on Solaris, which can run either ELF or a.out binaries
+ (for compatibility with SunOS 4), both of which can use shared
+ libraries. So we don't know whether we have an ELF executable or
+ an a.out executable until the user chooses an executable file.
+
+ ELF shared libraries don't get mapped into the address space
+ until after the program starts, so we'd better not try to insert
+ breakpoints in them immediately. We have to wait until the
+ dynamic linker has loaded them; we'll hit a bp_shlib_event
+ breakpoint (look for calls to create_solib_event_breakpoint) when
+ it's ready.
+
+ SunOS shared libraries seem to be different --- they're present
+ as soon as the process begins execution, so there's no need to
+ put off inserting breakpoints. There's also nowhere to put a
+ bp_shlib_event breakpoint, so if we put it off, we'll never get
+ around to it.
+
+ So: disable breakpoints only if we're using ELF shared libs. */
+ if (exec_bfd != NULL
+ && bfd_get_flavour (exec_bfd) != bfd_target_aout_flavour)
+ disable_breakpoints_in_shlibs (1);
+
+ while (so_list_head)
+ {
+ struct so_list *so = so_list_head;
+ so_list_head = so->next;
+ if (so->abfd)
+ remove_target_sections (so->abfd);
+ free_so (so);
+ }
+
+ TARGET_SO_CLEAR_SOLIB ();
+}
+
+static void
+do_clear_solib (void *dummy)
+{
+ solib_cleanup_queued = 0;
+ clear_solib ();
+}
+
+/* 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. */
+
+void
+solib_create_inferior_hook (void)
+{
+ TARGET_SO_SOLIB_CREATE_INFERIOR_HOOK ();
+}
+
+/* GLOBAL FUNCTION
+
+ in_solib_dynsym_resolve_code -- check to see if an address is in
+ dynamic loader's dynamic symbol
+ resolution code
+
+ SYNOPSIS
+
+ int in_solib_dynsym_resolve_code (CORE_ADDR pc)
+
+ DESCRIPTION
+
+ Determine if PC is in the dynamic linker's symbol resolution
+ code. Return 1 if so, 0 otherwise.
+*/
+
+int
+in_solib_dynsym_resolve_code (CORE_ADDR pc)
+{
+ return TARGET_SO_IN_DYNSYM_RESOLVE_CODE (pc);
+}
+
+/*
+
+ 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 (char *args, int from_tty)
+{
+ dont_repeat ();
+ solib_add (args, from_tty, (struct target_ops *) 0, 1);
+}
+
+/* LOCAL FUNCTION
+
+ no_shared_libraries -- handle command to explicitly discard symbols
+ from shared libraries.
+
+ DESCRIPTION
+
+ Implements the command "nosharedlibrary", which discards symbols
+ that have been auto-loaded from shared libraries. Symbols from
+ shared libraries that were added by explicit request of the user
+ are not discarded. Also called from remote.c. */
+
+void
+no_shared_libraries (char *ignored, int from_tty)
+{
+ objfile_purge_solibs ();
+ do_clear_solib (NULL);
+}
+
+static void
+reload_shared_libraries (char *ignored, int from_tty)
+{
+ no_shared_libraries (NULL, from_tty);
+ solib_add (NULL, from_tty, NULL, auto_solib_add);
+}
+
+extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */
+
+void
+_initialize_solib (void)
+{
+ struct cmd_list_element *c;
+
+ 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_com ("nosharedlibrary", class_files, no_shared_libraries,
+ "Unload all shared object library symbols.");
+
+ add_show_from_set
+ (add_set_cmd ("auto-solib-add", class_support, var_boolean,
+ (char *) &auto_solib_add,
+ "Set autoloading of shared library symbols.\n\
+If \"on\", symbols from all shared object libraries will be loaded\n\
+automatically when the inferior begins execution, when the dynamic linker\n\
+informs gdb that a new library has been loaded, or when attaching to the\n\
+inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.",
+ &setlist),
+ &showlist);
+
+ c = add_set_cmd ("solib-absolute-prefix", class_support, var_filename,
+ (char *) &solib_absolute_prefix,
+ "Set prefix for loading absolute shared library symbol files.\n\
+For other (relative) files, you can add values using `set solib-search-path'.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ set_cmd_cfunc (c, reload_shared_libraries);
+ set_cmd_completer (c, filename_completer);
+
+ /* Set the default value of "solib-absolute-prefix" from the sysroot, if
+ one is set. */
+ solib_absolute_prefix = xstrdup (gdb_sysroot);
+
+ c = add_set_cmd ("solib-search-path", class_support, var_string,
+ (char *) &solib_search_path,
+ "Set the search path for loading non-absolute shared library symbol files.\n\
+This takes precedence over the environment variables PATH and LD_LIBRARY_PATH.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ set_cmd_cfunc (c, reload_shared_libraries);
+ set_cmd_completer (c, filename_completer);
+}
diff --git a/contrib/gdb/gdb/solib.h b/contrib/gdb/gdb/solib.h
new file mode 100644
index 0000000..cb4ba2d
--- /dev/null
+++ b/contrib/gdb/gdb/solib.h
@@ -0,0 +1,110 @@
+/* Shared library declarations for GDB, the GNU Debugger.
+ Copyright 1992, 1993, 1995, 1998, 1999, 2000, 2001, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SOLIB_H
+#define SOLIB_H
+
+/* Forward decl's for prototypes */
+struct target_ops;
+
+/* Called when we free all symtabs, to free the shared library information
+ as well. */
+
+#define CLEAR_SOLIB clear_solib
+
+extern void clear_solib (void);
+
+/* Called to add symbols from a shared library to gdb's symbol table. */
+
+#define SOLIB_ADD(filename, from_tty, targ, readsyms) \
+ solib_add (filename, from_tty, targ, readsyms)
+
+extern void solib_add (char *, int, struct target_ops *, int);
+
+/* 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()
+
+/* Function to be called to remove the connection between debugger and
+ dynamic linker that was established by SOLIB_CREATE_INFERIOR_HOOK.
+ (This operation does not remove shared library information from
+ the debugger, as CLEAR_SOLIB does.)
+
+ This functionality is presently not implemented for this target.
+ */
+#define SOLIB_REMOVE_INFERIOR_HOOK(PID) (0)
+
+extern void solib_create_inferior_hook (void); /* solib.c */
+
+/* This function returns TRUE if pc is the address of an instruction that
+ lies within the dynamic linker (such as the event hook, or the dld
+ itself).
+
+ This function must be used only when a dynamic linker event has been
+ caught, and the inferior is being stepped out of the hook, or undefined
+ results are guaranteed.
+
+ Presently, this functionality is not implemented.
+ */
+
+/*
+ #define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
+ error("catch of library loads/unloads not yet implemented on this platform")
+ */
+
+#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
+(0)
+
+/* This function must be called when the inferior is killed, and the program
+ restarted. This is not the same as CLEAR_SOLIB, in that it doesn't discard
+ any symbol tables.
+
+ Presently, this functionality is not implemented.
+ */
+#define SOLIB_RESTART() \
+ (0)
+
+/* 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 (CORE_ADDR); /* solib.c */
+
+/* If ADDR lies in a shared library, return its name. */
+
+#define PC_SOLIB(addr) solib_address (addr)
+
+/* Return 1 if PC lies in the dynamic symbol resolution code of the
+ run time loader. */
+
+#define IN_SOLIB_DYNSYM_RESOLVE_CODE(pc) in_solib_dynsym_resolve_code (pc)
+
+extern int in_solib_dynsym_resolve_code (CORE_ADDR); /* solib.c */
+
+/* Discard symbols that were auto-loaded from shared libraries. */
+
+extern void no_shared_libraries (char *ignored, int from_tty);
+
+#endif /* SOLIB_H */
diff --git a/contrib/gdb/gdb/solist.h b/contrib/gdb/gdb/solist.h
new file mode 100644
index 0000000..8e5c432
--- /dev/null
+++ b/contrib/gdb/gdb/solist.h
@@ -0,0 +1,134 @@
+/* Shared library declarations for GDB, the GNU Debugger.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SOLIST_H
+#define SOLIST_H
+
+#define SO_NAME_MAX_PATH_SIZE 512 /* FIXME: Should be dynamic */
+
+/* Forward declaration for target specific link map information. This
+ struct is opaque to all but the target specific file. */
+struct lm_info;
+
+struct so_list
+ {
+ /* The following fields of the structure come directly from the
+ dynamic linker's tables in the inferior, and are initialized by
+ current_sos. */
+
+ struct so_list *next; /* next structure in linked list */
+
+ /* A pointer to target specific link map information. Often this
+ will be a copy of struct link_map from the user process, but
+ it need not be; it can be any collection of data needed to
+ traverse the dynamic linker's data structures. */
+ struct lm_info *lm_info;
+
+ /* Shared object file name, exactly as it appears in the
+ inferior's link map. This may be a relative path, or something
+ which needs to be looked up in LD_LIBRARY_PATH, etc. We use it
+ to tell which entries in the inferior's dynamic linker's link
+ map we've already loaded. */
+ char so_original_name[SO_NAME_MAX_PATH_SIZE];
+
+ /* shared object file name, expanded to something GDB can open */
+ char so_name[SO_NAME_MAX_PATH_SIZE];
+
+ /* The following fields of the structure are built from
+ information gathered from the shared object file itself, and
+ are set when we actually add it to our symbol tables.
+
+ current_sos must initialize these fields to 0. */
+
+ bfd *abfd;
+ 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;
+ };
+
+struct target_so_ops
+ {
+ /* Adjust the section binding addresses by the base address at
+ which the object was actually mapped. */
+ void (*relocate_section_addresses) (struct so_list *so,
+ struct section_table *);
+
+ /* Free the the link map info and any other private data
+ structures associated with a so_list entry. */
+ void (*free_so) (struct so_list *so);
+
+ /* Reset or free private data structures not associated with
+ so_list entries. */
+ void (*clear_solib) (void);
+
+ /* Target dependent code to run after child process fork. */
+ void (*solib_create_inferior_hook) (void);
+
+ /* Do additional symbol handling, lookup, etc. after symbols
+ for a shared object have been loaded. */
+ void (*special_symbol_handling) (void);
+
+ /* Construct a list of the currently loaded shared objects. */
+ struct so_list *(*current_sos) (void);
+
+ /* Find, open, and read the symbols for the main executable. */
+ int (*open_symbol_file_object) (void *from_ttyp);
+
+ /* Determine if PC lies in the dynamic symbol resolution code of
+ the run time loader */
+ int (*in_dynsym_resolve_code) (CORE_ADDR pc);
+
+ /* Extra hook for finding and opening a solib. Convenience function
+ for remote debuggers finding host libs */
+ int (*find_and_open_solib) (char *soname,
+ unsigned o_flags, char **temp_pathname);
+
+ };
+
+void free_so (struct so_list *so);
+
+/* Find solib binary file and open it. */
+extern int solib_open (char *in_pathname, char **found_pathname);
+
+/* FIXME: gdbarch needs to control this variable */
+extern struct target_so_ops *current_target_so_ops;
+
+#define TARGET_SO_RELOCATE_SECTION_ADDRESSES \
+ (current_target_so_ops->relocate_section_addresses)
+#define TARGET_SO_FREE_SO (current_target_so_ops->free_so)
+#define TARGET_SO_CLEAR_SOLIB (current_target_so_ops->clear_solib)
+#define TARGET_SO_SOLIB_CREATE_INFERIOR_HOOK \
+ (current_target_so_ops->solib_create_inferior_hook)
+#define TARGET_SO_SPECIAL_SYMBOL_HANDLING \
+ (current_target_so_ops->special_symbol_handling)
+#define TARGET_SO_CURRENT_SOS (current_target_so_ops->current_sos)
+#define TARGET_SO_OPEN_SYMBOL_FILE_OBJECT \
+ (current_target_so_ops->open_symbol_file_object)
+#define TARGET_SO_IN_DYNSYM_RESOLVE_CODE \
+ (current_target_so_ops->in_dynsym_resolve_code)
+#define TARGET_SO_FIND_AND_OPEN_SOLIB \
+ (current_target_so_ops->find_and_open_solib)
+
+#endif
diff --git a/contrib/gdb/gdb/somread.c b/contrib/gdb/gdb/somread.c
new file mode 100644
index 0000000..4ffa4c1
--- /dev/null
+++ b/contrib/gdb/gdb/somread.c
@@ -0,0 +1,736 @@
+/* Read HP PA/Risc object files for GDB.
+ Copyright 1991, 1992, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002,
+ 2004 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 <syms.h>
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "complaints.h"
+#include "gdb_string.h"
+#include "demangle.h"
+#include "som.h"
+#include "libhppa.h"
+
+/* Various things we might complain about... */
+
+static int init_import_symbols (struct objfile *objfile);
+
+static void som_symfile_init (struct objfile *);
+
+static void som_new_init (struct objfile *);
+
+static void som_symfile_read (struct objfile *, int);
+
+static void som_symfile_finish (struct objfile *);
+
+static void som_symtab_read (bfd *, struct objfile *,
+ struct section_offsets *);
+
+static void som_symfile_offsets (struct objfile *, struct section_addr_info *);
+
+/* FIXME: These should really be in a common header somewhere */
+
+extern void hpread_build_psymtabs (struct objfile *, int);
+
+extern void hpread_symfile_finish (struct objfile *);
+
+extern void hpread_symfile_init (struct objfile *);
+
+extern void do_pxdb (bfd *);
+
+/*
+
+ 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 (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);
+
+ /* FIXME (alloca): could be quite large. */
+ buf = alloca (symsize * number_of_symbols);
+ bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET);
+ val = bfd_bread (buf, symsize * number_of_symbols, abfd);
+ if (val != symsize * number_of_symbols)
+ error ("Couldn't read symbol dictionary!");
+
+ /* FIXME (alloca): could be quite large. */
+ stringtab = alloca (obj_som_stringtab_size (abfd));
+ bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET);
+ val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd);
+ if (val != obj_som_stringtab_size (abfd))
+ error ("Can't read in HP string table.");
+
+ /* We need to determine if objfile is a dynamic executable (so we
+ can do the right thing for ST_ENTRY vs ST_CODE symbols).
+
+ There's nothing in the header which easily allows us to do
+ this.
+
+ This code used to rely upon the existence of a $SHLIB_INFO$
+ section to make this determination. HP claims that it is
+ more accurate to check for a nonzero text offset, but they
+ have not provided any information about why that test is
+ more accurate. */
+ dynamic = (text_offset != 0);
+
+ endbufp = buf + number_of_symbols;
+ for (bufp = buf; bufp < endbufp; ++bufp)
+ {
+ enum minimal_symbol_type ms_type;
+
+ 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;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ 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;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_STUB:
+ symname = bufp->name.n_strx + stringtab;
+ ms_type = mst_solib_trampoline;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ 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;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+
+ check_strange_names:
+ /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local
+ label prefixes for stabs, constant data, etc. So we need
+ only filter out L$ symbols which are left in due to
+ limitations in how GAS generates SOM relocations.
+
+ When linking in the HPUX C-library the HP linker has
+ the nasty habit of placing section symbols from the literal
+ subspaces in the middle of the program's text. Filter
+ those out as best we can. Check for first and last character
+ being '$'.
+
+ And finally, the newer HP compilers emit crud like $PIC_foo$N
+ in some circumstance (PIC code I guess). It's also claimed
+ that they emit D$ symbols too. What stupidity. */
+ if ((symname[0] == 'L' && symname[1] == '$')
+ || (symname[0] == '$' && symname[strlen (symname) - 1] == '$')
+ || (symname[0] == 'D' && symname[1] == '$')
+ || (strncmp (symname, "$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;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_ENTRY:
+ symname = bufp->name.n_strx + stringtab;
+ /* SS_LOCAL symbols in a shared library do not have
+ export stubs, so we do not have to worry about
+ using mst_file_text vs mst_solib_trampoline here like
+ we do for SS_UNIVERSAL and SS_EXTERNAL symbols above. */
+ ms_type = mst_file_text;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_STUB:
+ symname = bufp->name.n_strx + stringtab;
+ ms_type = mst_solib_trampoline;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ 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.
+
+ This also happens for weak symbols, but their type is
+ ST_DATA. */
+ case SS_UNSAT:
+ switch (bufp->symbol_type)
+ {
+ case ST_STORAGE:
+ case ST_DATA:
+ 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);
+
+ prim_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 (struct objfile *objfile, int mainline)
+{
+ bfd *abfd = objfile->obfd;
+ struct cleanup *back_to;
+
+ do_pxdb (symfile_bfd_open (objfile->name));
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup_discard_minimal_symbols ();
+
+ /* Read in the import list and the export list. Currently
+ the export list isn't used; the import list is used in
+ hp-symtab-read.c to handle static vars declared in other
+ shared libraries. */
+ init_import_symbols (objfile);
+#if 0 /* Export symbols not used today 1997-08-05 */
+ init_export_symbols (objfile);
+#else
+ objfile->export_list = NULL;
+ objfile->export_list_size = 0;
+#endif
+
+ /* Process the normal SOM symbol table first.
+ This reads in the DNTT and string table, but doesn't
+ actually scan the DNTT. It does scan the linker symbol
+ table and thus build up a "minimal symbol table". */
+
+ som_symtab_read (abfd, objfile, objfile->section_offsets);
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile.
+ Further symbol-reading is done incrementally, file-by-file,
+ in a step known as "psymtab-to-symtab" expansion. hp-symtab-read.c
+ contains the code to do the actual DNTT scanning and symtab building. */
+ install_minimal_symbols (objfile);
+ do_cleanups (back_to);
+
+ /* Now read information from the stabs debug sections.
+ This is a no-op for SOM.
+ Perhaps it is intended for some kind of mixed STABS/SOM
+ situation? */
+ stabsect_build_psymtabs (objfile, mainline,
+ "$GDB_SYMBOLS$", "$GDB_STRINGS$", "$TEXT$");
+
+ /* Now read the native debug information.
+ This builds the psymtab. This used to be done via a scan of
+ the DNTT, but is now done via the PXDB-built quick-lookup tables
+ together with a scan of the GNTT. See hp-psymtab-read.c. */
+ hpread_build_psymtabs (objfile, mainline);
+
+ /* Force hppa-tdep.c to re-read the unwind descriptors. */
+ objfile->obj_private = 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).
+
+ We reinitialize buildsym, since we may be reading stabs from a SOM file. */
+
+static void
+som_new_init (struct objfile *ignore)
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+som_symfile_finish (struct objfile *objfile)
+{
+ if (objfile->sym_stab_info != NULL)
+ {
+ xmfree (objfile->md, objfile->sym_stab_info);
+ }
+ hpread_symfile_finish (objfile);
+}
+
+/* SOM specific initialization routine for reading symbols. */
+
+static void
+som_symfile_init (struct objfile *objfile)
+{
+ /* SOM objects may be reordered, so set OBJF_REORDERED. If we
+ find this causes a significant slowdown in gdb then we could
+ set it in the debug symbol readers only when necessary. */
+ objfile->flags |= OBJF_REORDERED;
+ hpread_symfile_init (objfile);
+}
+
+/* SOM specific parsing routine for section offsets.
+
+ Plain and simple for now. */
+
+static void
+som_symfile_offsets (struct objfile *objfile, struct section_addr_info *addrs)
+{
+ int i;
+ CORE_ADDR text_addr;
+
+ objfile->num_sections = bfd_count_sections (objfile->obfd);
+ objfile->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ /* FIXME: ezannoni 2000-04-20 The section names in SOM are not
+ .text, .data, etc, but $TEXT$, $DATA$,... We should initialize
+ SET_OFF_* from bfd. (See default_symfile_offsets()). But I don't
+ know the correspondence between SOM sections and GDB's idea of
+ section names. So for now we default to what is was before these
+ changes.*/
+ objfile->sect_index_text = 0;
+ objfile->sect_index_data = 1;
+ objfile->sect_index_bss = 2;
+ objfile->sect_index_rodata = 3;
+
+ /* First see if we're a shared library. If so, get the section
+ offsets from the library, else get them from addrs. */
+ if (!som_solib_section_offsets (objfile, objfile->section_offsets))
+ {
+ /* Note: Here is OK to compare with ".text" because this is the
+ name that gdb itself gives to that section, not the SOM
+ name. */
+ for (i = 0; i < objfile->num_sections && addrs->other[i].name; i++)
+ if (strcmp (addrs->other[i].name, ".text") == 0)
+ break;
+ text_addr = addrs->other[i].addr;
+
+ for (i = 0; i < objfile->num_sections; i++)
+ (objfile->section_offsets)->offsets[i] = text_addr;
+ }
+}
+
+/* Read in and initialize the SOM import list which is present
+ for all executables and shared libraries. The import list
+ consists of the symbols that are referenced in OBJFILE but
+ not defined there. (Variables that are imported are dealt
+ with as "loc_indirect" vars.)
+ Return value = number of import symbols read in. */
+static int
+init_import_symbols (struct objfile *objfile)
+{
+ unsigned int import_list;
+ unsigned int import_list_size;
+ unsigned int string_table;
+ unsigned int string_table_size;
+ char *string_buffer;
+ int i;
+ int j;
+ int k;
+ asection *text_section; /* section handle */
+ unsigned int dl_header[12]; /* SOM executable header */
+
+ /* A struct for an entry in the SOM import list */
+ typedef struct
+ {
+ int name; /* index into the string table */
+ short dont_care1; /* we don't use this */
+ unsigned char type; /* 0 = NULL, 2 = Data, 3 = Code, 7 = Storage, 13 = Plabel */
+ unsigned int reserved2:8; /* not used */
+ }
+ SomImportEntry;
+
+ /* We read 100 entries in at a time from the disk file. */
+#define SOM_READ_IMPORTS_NUM 100
+#define SOM_READ_IMPORTS_CHUNK_SIZE (sizeof (SomImportEntry) * SOM_READ_IMPORTS_NUM)
+ SomImportEntry buffer[SOM_READ_IMPORTS_NUM];
+
+ /* Initialize in case we error out */
+ objfile->import_list = NULL;
+ objfile->import_list_size = 0;
+
+ /* It doesn't work, for some reason, to read in space $TEXT$;
+ the subspace $SHLIB_INFO$ has to be used. Some BFD quirk? pai/1997-08-05 */
+ text_section = bfd_get_section_by_name (objfile->obfd, "$SHLIB_INFO$");
+ if (!text_section)
+ return 0;
+ /* Get the SOM executable header */
+ bfd_get_section_contents (objfile->obfd, text_section, dl_header, 0, 12 * sizeof (int));
+
+ /* Check header version number for 10.x HP-UX */
+ /* Currently we deal only with 10.x systems; on 9.x the version # is 89060912.
+ FIXME: Change for future HP-UX releases and mods to the SOM executable format */
+ if (dl_header[0] != 93092112)
+ return 0;
+
+ import_list = dl_header[4];
+ import_list_size = dl_header[5];
+ if (!import_list_size)
+ return 0;
+ string_table = dl_header[10];
+ string_table_size = dl_header[11];
+ if (!string_table_size)
+ return 0;
+
+ /* Suck in SOM string table */
+ string_buffer = (char *) xmalloc (string_table_size);
+ bfd_get_section_contents (objfile->obfd, text_section, string_buffer,
+ string_table, string_table_size);
+
+ /* Allocate import list in the psymbol obstack; this has nothing
+ to do with psymbols, just a matter of convenience. We want the
+ import list to be freed when the objfile is deallocated */
+ objfile->import_list
+ = (ImportEntry *) obstack_alloc (&objfile->objfile_obstack,
+ import_list_size * sizeof (ImportEntry));
+
+ /* Read in the import entries, a bunch at a time */
+ for (j = 0, k = 0;
+ j < (import_list_size / SOM_READ_IMPORTS_NUM);
+ j++)
+ {
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ import_list + j * SOM_READ_IMPORTS_CHUNK_SIZE,
+ SOM_READ_IMPORTS_CHUNK_SIZE);
+ for (i = 0; i < SOM_READ_IMPORTS_NUM; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->import_list[k]
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->import_list[k], string_buffer + buffer[i].name);
+ /* Some day we might want to record the type and other information too */
+ }
+ else /* null type */
+ objfile->import_list[k] = NULL;
+
+ }
+ }
+
+ /* Get the leftovers */
+ if (k < import_list_size)
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ import_list + k * sizeof (SomImportEntry),
+ (import_list_size - k) * sizeof (SomImportEntry));
+ for (i = 0; k < import_list_size; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->import_list[k]
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->import_list[k], string_buffer + buffer[i].name);
+ /* Some day we might want to record the type and other information too */
+ }
+ else
+ objfile->import_list[k] = NULL;
+ }
+
+ objfile->import_list_size = import_list_size;
+ xfree (string_buffer);
+ return import_list_size;
+}
+
+/* Read in and initialize the SOM export list which is present
+ for all executables and shared libraries. The import list
+ consists of the symbols that are referenced in OBJFILE but
+ not defined there. (Variables that are imported are dealt
+ with as "loc_indirect" vars.)
+ Return value = number of import symbols read in. */
+int
+init_export_symbols (struct objfile *objfile)
+{
+ unsigned int export_list;
+ unsigned int export_list_size;
+ unsigned int string_table;
+ unsigned int string_table_size;
+ char *string_buffer;
+ int i;
+ int j;
+ int k;
+ asection *text_section; /* section handle */
+ unsigned int dl_header[12]; /* SOM executable header */
+
+ /* A struct for an entry in the SOM export list */
+ typedef struct
+ {
+ int next; /* for hash table use -- we don't use this */
+ int name; /* index into string table */
+ int value; /* offset or plabel */
+ int dont_care1; /* not used */
+ unsigned char type; /* 0 = NULL, 2 = Data, 3 = Code, 7 = Storage, 13 = Plabel */
+ char dont_care2; /* not used */
+ short dont_care3; /* not used */
+ }
+ SomExportEntry;
+
+ /* We read 100 entries in at a time from the disk file. */
+#define SOM_READ_EXPORTS_NUM 100
+#define SOM_READ_EXPORTS_CHUNK_SIZE (sizeof (SomExportEntry) * SOM_READ_EXPORTS_NUM)
+ SomExportEntry buffer[SOM_READ_EXPORTS_NUM];
+
+ /* Initialize in case we error out */
+ objfile->export_list = NULL;
+ objfile->export_list_size = 0;
+
+ /* It doesn't work, for some reason, to read in space $TEXT$;
+ the subspace $SHLIB_INFO$ has to be used. Some BFD quirk? pai/1997-08-05 */
+ text_section = bfd_get_section_by_name (objfile->obfd, "$SHLIB_INFO$");
+ if (!text_section)
+ return 0;
+ /* Get the SOM executable header */
+ bfd_get_section_contents (objfile->obfd, text_section, dl_header, 0, 12 * sizeof (int));
+
+ /* Check header version number for 10.x HP-UX */
+ /* Currently we deal only with 10.x systems; on 9.x the version # is 89060912.
+ FIXME: Change for future HP-UX releases and mods to the SOM executable format */
+ if (dl_header[0] != 93092112)
+ return 0;
+
+ export_list = dl_header[8];
+ export_list_size = dl_header[9];
+ if (!export_list_size)
+ return 0;
+ string_table = dl_header[10];
+ string_table_size = dl_header[11];
+ if (!string_table_size)
+ return 0;
+
+ /* Suck in SOM string table */
+ string_buffer = (char *) xmalloc (string_table_size);
+ bfd_get_section_contents (objfile->obfd, text_section, string_buffer,
+ string_table, string_table_size);
+
+ /* Allocate export list in the psymbol obstack; this has nothing
+ to do with psymbols, just a matter of convenience. We want the
+ export list to be freed when the objfile is deallocated */
+ objfile->export_list
+ = (ExportEntry *) obstack_alloc (&objfile->objfile_obstack,
+ export_list_size * sizeof (ExportEntry));
+
+ /* Read in the export entries, a bunch at a time */
+ for (j = 0, k = 0;
+ j < (export_list_size / SOM_READ_EXPORTS_NUM);
+ j++)
+ {
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ export_list + j * SOM_READ_EXPORTS_CHUNK_SIZE,
+ SOM_READ_EXPORTS_CHUNK_SIZE);
+ for (i = 0; i < SOM_READ_EXPORTS_NUM; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->export_list[k].name
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->export_list[k].name, string_buffer + buffer[i].name);
+ objfile->export_list[k].address = buffer[i].value;
+ /* Some day we might want to record the type and other information too */
+ }
+ else
+ /* null type */
+ {
+ objfile->export_list[k].name = NULL;
+ objfile->export_list[k].address = 0;
+ }
+ }
+ }
+
+ /* Get the leftovers */
+ if (k < export_list_size)
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ export_list + k * sizeof (SomExportEntry),
+ (export_list_size - k) * sizeof (SomExportEntry));
+ for (i = 0; k < export_list_size; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->export_list[k].name
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->export_list[k].name, string_buffer + buffer[i].name);
+ /* Some day we might want to record the type and other information too */
+ objfile->export_list[k].address = buffer[i].value;
+ }
+ else
+ {
+ objfile->export_list[k].name = NULL;
+ objfile->export_list[k].address = 0;
+ }
+ }
+
+ objfile->export_list_size = export_list_size;
+ xfree (string_buffer);
+ return export_list_size;
+}
+
+
+
+/* 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 (void)
+{
+ 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 0000000..d8c971b
--- /dev/null
+++ b/contrib/gdb/gdb/somsolib.c
@@ -0,0 +1,1624 @@
+/* Handle HP SOM shared libraries for GDB, the GNU Debugger.
+
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_stat.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "exec.h"
+
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Uncomment this to turn on some debugging output.
+ */
+
+/* #define SOLIB_DEBUG
+ */
+
+/* This lives in hppa-tdep.c. */
+extern struct unwind_table_entry *find_unwind_entry (CORE_ADDR pc);
+
+/* These ought to be defined in some public interface, but aren't. They
+ define the meaning of the various bits in the distinguished __dld_flags
+ variable that is declared in every debuggable a.out on HP-UX, and that
+ is shared between the debugger and the dynamic linker.
+ */
+#define DLD_FLAGS_MAPPRIVATE 0x1
+#define DLD_FLAGS_HOOKVALID 0x2
+#define DLD_FLAGS_LISTVALID 0x4
+#define DLD_FLAGS_BOR_ENABLE 0x8
+
+/* TODO:
+
+ * 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 (length of text area),
+ * 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. */
+
+ /* For versions from HPUX-10.30 and up */
+
+ /* Address in target of offset from thread-local register of
+ * start of this thread's data. I.e., the first thread-local
+ * variable in this shared library starts at *(tsd_start_addr)
+ * from that area pointed to by cr27 (mpsfu_hi).
+ *
+ * We do the indirection as soon as we read it, so from then
+ * on it's the offset itself.
+ */
+ CORE_ADDR tsd_start_addr;
+
+ /* Following this are longwords holding:
+
+ * ?, ?, ?, ptr to -1, ptr to-1, ptr to lib name (leaf name),
+ * ptr to __data_start, ptr to __data_end
+ */
+
+
+ };
+
+/* 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;
+/* elz: added this field to store the address in target space (in the
+ library) of the library descriptor (handle) which we read into
+ som_solib_mapped_entry structure */
+ CORE_ADDR solib_addr;
+ struct so_list *next;
+
+ };
+
+static struct so_list *so_list_head;
+
+
+/* This is the cumulative size in bytes of the symbol tables of all
+ shared objects on the so_list_head list. (When we say size, here
+ we mean of the information before it is brought into memory and
+ potentially expanded by GDB.) When adding a new shlib, this value
+ is compared against the threshold size, held by auto_solib_limit
+ (in megabytes). If adding symbols for the new shlib would cause
+ the total size to exceed the threshold, then the new shlib's
+ symbols are not loaded. */
+static LONGEST som_solib_total_st_size;
+
+/* When the threshold is reached for any shlib, we refuse to add
+ symbols for subsequent shlibs, even if those shlibs' symbols would
+ be small enough to fit under the threshold. (Although this may
+ result in one, early large shlib preventing the loading of later,
+ smalller shlibs' symbols, it allows us to issue one informational
+ message. The alternative, to issue a message for each shlib whose
+ symbols aren't loaded, could be a big annoyance where the threshold
+ is exceeded due to a very large number of shlibs.)
+ */
+static int som_solib_st_size_threshold_exceeded;
+
+/* These addresses should be filled in by som_solib_create_inferior_hook.
+ They are also used elsewhere in this module.
+ */
+typedef struct
+ {
+ CORE_ADDR address;
+ struct unwind_table_entry *unwind;
+ }
+addr_and_unwind_t;
+
+/* When adding fields, be sure to clear them in _initialize_som_solib. */
+static struct
+ {
+ int is_valid;
+ addr_and_unwind_t hook;
+ addr_and_unwind_t hook_stub;
+ addr_and_unwind_t load;
+ addr_and_unwind_t load_stub;
+ addr_and_unwind_t unload;
+ addr_and_unwind_t unload2;
+ addr_and_unwind_t unload_stub;
+ }
+dld_cache;
+
+
+
+static void som_sharedlibrary_info_command (char *, int);
+
+static void som_solib_sharedlibrary_command (char *, int);
+
+static LONGEST
+som_solib_sizeof_symbol_table (char *filename)
+{
+ bfd *abfd;
+ int desc;
+ char *absolute_name;
+ LONGEST st_size = (LONGEST) 0;
+ asection *sect;
+
+ /* We believe that filename was handed to us by the dynamic linker, and
+ is therefore always an absolute path.
+ */
+ desc = openp (getenv ("PATH"), 1, filename, O_RDONLY | O_BINARY, 0, &absolute_name);
+ if (desc < 0)
+ {
+ perror_with_name (filename);
+ }
+ filename = absolute_name;
+
+ abfd = bfd_fdopenr (filename, gnutarget, desc);
+ if (!abfd)
+ {
+ close (desc);
+ make_cleanup (xfree, filename);
+ error ("\"%s\": can't open to read symbols: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ if (!bfd_check_format (abfd, bfd_object)) /* Reads in section info */
+ {
+ bfd_close (abfd); /* This also closes desc */
+ make_cleanup (xfree, filename);
+ error ("\"%s\": can't read symbols: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* Sum the sizes of the various sections that compose debug info. */
+
+ /* This contains non-DOC information. */
+ sect = bfd_get_section_by_name (abfd, "$DEBUG$");
+ if (sect)
+ st_size += (LONGEST) bfd_section_size (abfd, sect);
+
+ /* This contains DOC information. */
+ sect = bfd_get_section_by_name (abfd, "$PINFO$");
+ if (sect)
+ st_size += (LONGEST) bfd_section_size (abfd, sect);
+
+ bfd_close (abfd); /* This also closes desc */
+ xfree (filename);
+
+ /* Unfortunately, just summing the sizes of various debug info
+ sections isn't a very accurate measurement of how much heap
+ space the debugger will need to hold them. It also doesn't
+ account for space needed by linker (aka "minimal") symbols.
+
+ Anecdotal evidence suggests that just summing the sizes of
+ debug-info-related sections understates the heap space needed
+ to represent it internally by about an order of magnitude.
+
+ Since it's not exactly brain surgery we're doing here, rather
+ than attempt to more accurately measure the size of a shlib's
+ symbol table in GDB's heap, we'll just apply a 10x fudge-
+ factor to the debug info sections' size-sum. No, this doesn't
+ account for minimal symbols in non-debuggable shlibs. But it
+ all roughly washes out in the end.
+ */
+ return st_size * (LONGEST) 10;
+}
+
+
+static void
+som_solib_add_solib_objfile (struct so_list *so, char *name, int from_tty,
+ CORE_ADDR text_addr)
+{
+ obj_private_data_t *obj_private;
+ struct obj_section *s;
+
+ so->objfile = symbol_file_add (name, from_tty, NULL, 0, OBJF_SHARED);
+ so->abfd = so->objfile->obfd;
+
+ /* syms_from_objfile has bizarre section offset code,
+ so I do my own right here. */
+ for (s = so->objfile->sections; s < so->objfile->sections_end; s++)
+ {
+ flagword aflag = bfd_get_section_flags(so->abfd, s->the_bfd_section);
+ if (aflag & SEC_CODE)
+ {
+ s->addr += so->som_solib.text_addr - so->som_solib.text_link_addr;
+ s->endaddr += so->som_solib.text_addr - so->som_solib.text_link_addr;
+ }
+ else if (aflag & SEC_DATA)
+ {
+ s->addr += so->som_solib.data_start;
+ s->endaddr += so->som_solib.data_start;
+ }
+ else
+ ;
+ }
+
+ /* Mark this as a shared library and save private data.
+ */
+ so->objfile->flags |= OBJF_SHARED;
+
+ if (so->objfile->obj_private == NULL)
+ {
+ obj_private = (obj_private_data_t *)
+ obstack_alloc (&so->objfile->objfile_obstack,
+ sizeof (obj_private_data_t));
+ obj_private->unwind_info = NULL;
+ obj_private->so_info = NULL;
+ so->objfile->obj_private = obj_private;
+ }
+
+ obj_private = (obj_private_data_t *) so->objfile->obj_private;
+ obj_private->so_info = so;
+
+ if (!bfd_check_format (so->abfd, bfd_object))
+ {
+ error ("\"%s\": not in executable format: %s.",
+ name, bfd_errmsg (bfd_get_error ()));
+ }
+}
+
+
+static void
+som_solib_load_symbols (struct so_list *so, char *name, int from_tty,
+ CORE_ADDR text_addr, struct target_ops *target)
+{
+ struct section_table *p;
+ int status;
+ char buf[4];
+ CORE_ADDR presumed_data_start;
+
+#ifdef SOLIB_DEBUG
+ printf ("--Adding symbols for shared library \"%s\"\n", name);
+#endif
+
+ som_solib_add_solib_objfile (so, name, from_tty, text_addr);
+
+ /* 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 (so->abfd,
+ &so->sections,
+ &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 = so->sections; p < so->sections_end; p++)
+ {
+ if (p->the_bfd_section->flags & SEC_CODE)
+ {
+ p->addr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_TEXT (so->objfile));
+ p->endaddr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_TEXT (so->objfile));
+ }
+ else if (p->the_bfd_section->flags & SEC_DATA)
+ {
+ p->addr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_DATA (so->objfile));
+ p->endaddr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_DATA (so->objfile));
+ }
+ }
+
+ /* 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;
+
+ new = so->sections_end - so->sections;
+
+ old = target_resize_to_sections (target, new);
+
+ /* Copy over the old data before it gets clobbered. */
+ memcpy ((char *) (target->to_sections + old),
+ so->sections,
+ ((sizeof (struct section_table)) * new));
+ }
+}
+
+
+/* FIXME: cagney/2003-02-01: This just isn't right. Given an address
+ within the target's address space, this converts the value into an
+ address within the host's (i.e., GDB's) address space. Given that
+ the host/target address spaces are separate, this can't be right. */
+
+static void *
+hpux_address_to_host_pointer_hack (CORE_ADDR addr)
+{
+ void *ptr;
+
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
+ return ptr;
+}
+
+/* Add symbols from shared libraries into the symtab list, unless the
+ size threshold specified by auto_solib_limit (in megabytes) would
+ be exceeded. */
+
+void
+som_solib_add (char *arg_string, int from_tty, struct target_ops *target, int readsyms)
+{
+ 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;
+ int threshold_warning_given = 0;
+
+ /* First validate our arguments. */
+ re_err = re_comp (arg_string ? arg_string : ".");
+ if (re_err != 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 not, then we punt, warning the user if
+ we were called as a result of the add-symfile command.
+ */
+ if ((dld_flags & DLD_FLAGS_LISTVALID) == 0)
+ {
+ if (from_tty)
+ 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 & DLD_FLAGS_MAPPRIVATE) == 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 /opt/langtools/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;
+
+#ifdef SOLIB_DEBUG
+ printf ("--About to read shared library list data\n");
+#endif
+
+ /* "addr" will always point to the base of the
+ * current data entry describing the current
+ * shared library.
+ */
+ 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 stat statbuf;
+ LONGEST st_size;
+ int is_main_program;
+
+ 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. */
+ is_main_program = (strcmp (name, symfile_objfile->name) == 0);
+ if (so_list || is_main_program)
+ {
+ /* This is the "next" pointer in the strcuture.
+ */
+ status = target_read_memory (addr + 36, buf, 4);
+ if (status != 0)
+ goto err;
+
+ addr = (CORE_ADDR) extract_unsigned_integer (buf, 4);
+
+ /* Record the main program's symbol table size. */
+ if (is_main_program && !so_list)
+ {
+ st_size = som_solib_sizeof_symbol_table (name);
+ som_solib_total_st_size += st_size;
+ }
+
+ /* Was this a shlib that we noted but didn't load the symbols for?
+ If so, were we invoked this time from the command-line, via
+ a 'sharedlibrary' or 'add-symbol-file' command? If yes to
+ both, we'd better load the symbols this time.
+ */
+ if (from_tty && so_list && !is_main_program && (so_list->objfile == NULL))
+ som_solib_load_symbols (so_list,
+ name,
+ from_tty,
+ so_list->som_solib.text_addr,
+ target);
+
+ continue;
+ }
+
+ name = obsavestring (name, name_len - 1,
+ &symfile_objfile->objfile_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->solib_addr = addr;
+ 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);
+ /* Following is "high water mark", highest version number
+ * seen, rather than plain version number.
+ */
+ new_so->som_solib.library_version = extract_unsigned_integer (buf, 2);
+ new_so->som_solib.text_addr = text_addr;
+
+ /* Q: What about longword at "addr + 8"?
+ * A: It's read above, out of order, into "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;
+
+ /* FIXME: cagney/2003-02-01: I think som_solib.next should be a
+ CORE_ADDR. */
+ new_so->som_solib.next =
+ hpux_address_to_host_pointer_hack (extract_unsigned_integer (buf, 4));
+
+ /* Note that we don't re-set "addr" to the next pointer
+ * until after we've read the trailing data.
+ */
+
+ status = target_read_memory (addr + 40, buf, 4);
+ new_so->som_solib.tsd_start_addr = extract_unsigned_integer (buf, 4);
+ if (status != 0)
+ goto err;
+
+ /* Now indirect via that value!
+ */
+ status = target_read_memory (new_so->som_solib.tsd_start_addr, buf, 4);
+ new_so->som_solib.tsd_start_addr = extract_unsigned_integer (buf, 4);
+ if (status != 0)
+ goto err;
+#ifdef SOLIB_DEBUG
+ printf ("\n+ library \"%s\" is described at 0x%x\n", name, addr);
+ printf (" 'version' is %d\n", new_so->som_solib.struct_version);
+ printf (" 'bind_mode' is %d\n", new_so->som_solib.bind_mode);
+ printf (" 'library_version' is %d\n", new_so->som_solib.library_version);
+ printf (" 'text_addr' is 0x%x\n", new_so->som_solib.text_addr);
+ printf (" 'text_link_addr' is 0x%x\n", new_so->som_solib.text_link_addr);
+ printf (" 'text_end' is 0x%x\n", new_so->som_solib.text_end);
+ printf (" 'data_start' is 0x%x\n", new_so->som_solib.data_start);
+ printf (" 'bss_start' is 0x%x\n", new_so->som_solib.bss_start);
+ printf (" 'data_end' is 0x%x\n", new_so->som_solib.data_end);
+ printf (" 'got_value' is %x\n", new_so->som_solib.got_value);
+ printf (" 'next' is 0x%x\n", new_so->som_solib.next);
+ printf (" 'tsd_start_addr' is 0x%x\n", new_so->som_solib.tsd_start_addr);
+#endif
+
+ /* Go on to the next shared library descriptor.
+ */
+ addr = (CORE_ADDR) new_so->som_solib.next;
+
+
+
+ /* At this point, we have essentially hooked the shlib into the
+ "info share" command. However, we haven't yet loaded its
+ symbol table. We must now decide whether we ought to, i.e.,
+ whether doing so would exceed the symbol table size threshold.
+
+ If the threshold has just now been exceeded, then we'll issue
+ a warning message (which explains how to load symbols manually,
+ if the user so desires).
+
+ If the threshold has just now or previously been exceeded,
+ we'll just add the shlib to the list of object files, but won't
+ actually load its symbols. (This is more useful than it might
+ sound, for it allows us to e.g., still load and use the shlibs'
+ unwind information for stack tracebacks.)
+ */
+
+ /* Note that we DON'T want to preclude the user from using the
+ add-symbol-file command! Thus, we only worry about the threshold
+ when we're invoked for other reasons.
+ */
+ st_size = som_solib_sizeof_symbol_table (name);
+ som_solib_st_size_threshold_exceeded =
+ !from_tty &&
+ auto_solib_limit > 0 &&
+ readsyms &&
+ ((st_size + som_solib_total_st_size) > (auto_solib_limit * (LONGEST) (1024 * 1024)));
+
+ if (som_solib_st_size_threshold_exceeded)
+ {
+ if (!threshold_warning_given)
+ warning ("Symbols for some libraries have not been loaded, because\ndoing so would exceed the size threshold specified by auto-solib-limit.\nTo manually load symbols, use the 'sharedlibrary' command.\nTo raise the threshold, set auto-solib-limit to a larger value and rerun\nthe program.\n");
+ threshold_warning_given = 1;
+
+ /* We'll still make note of this shlib, even if we don't
+ read its symbols. This allows us to use its unwind
+ information well enough to know how to e.g., correctly
+ do a traceback from a PC within the shlib, even if we
+ can't symbolize those PCs...
+ */
+ som_solib_add_solib_objfile (new_so, name, from_tty, text_addr);
+ continue;
+ }
+
+ som_solib_total_st_size += st_size;
+
+ /* This fills in new_so->objfile, among others. */
+ som_solib_load_symbols (new_so, name, from_tty, text_addr, target);
+ }
+
+#ifdef SOLIB_DEBUG
+ printf ("--Done reading shared library data\n");
+#endif
+
+ /* 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 (void)
+{
+ struct minimal_symbol *msymbol;
+ unsigned int dld_flags, status, have_endo;
+ asection *shlib_info;
+ char 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.
+
+ We used to warn when this failed, but that warning is only useful
+ on very old HP systems (hpux9 and older). The warnings are an
+ annoyance to users of modern systems and foul up the testsuite as
+ well. As a result, the warnings have been disabled. */
+ msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ goto keep_going;
+
+ anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
+ store_unsigned_integer (buf, 4, PIDGET (inferior_ptid));
+ status = target_write_memory (anaddr, buf, 4);
+ if (status != 0)
+ {
+ warning ("Unable to write __d_pid");
+ warning ("Suggest linking with /opt/langtools/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.
+
+ Note that the above is the pre-HP-UX 9.0 behaviour. At 9.0 and above,
+ the dld provides an export stub named "__d_trap" as well as the
+ function named "__d_trap" itself, but doesn't provide "_DLD_HOOK".
+ We'll look first for the old flavor and then the new.
+ */
+ msymbol = lookup_minimal_symbol ("_DLD_HOOK", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ msymbol = lookup_minimal_symbol ("__d_trap", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ {
+ warning ("Unable to find _DLD_HOOK symbol in object file.");
+ warning ("Suggest linking with /opt/langtools/lib/end.o.");
+ warning ("GDB will be unable to track shl_load/shl_unload calls");
+ goto keep_going;
+ }
+ anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
+ dld_cache.hook.address = anaddr;
+
+ /* Grrr, this might not be an export symbol! We have to find the
+ export stub. */
+ ALL_OBJFILES (objfile)
+ {
+ struct unwind_table_entry *u;
+ struct minimal_symbol *msymbol2;
+
+ /* What a crock. */
+ msymbol2 = lookup_minimal_symbol_solib_trampoline (DEPRECATED_SYMBOL_NAME (msymbol),
+ objfile);
+ /* Found a symbol with the right name. */
+ if (msymbol2)
+ {
+ struct unwind_table_entry *u;
+ /* It must be a shared library trampoline. */
+ if (SYMBOL_TYPE (msymbol2) != mst_solib_trampoline)
+ continue;
+
+ /* It must also be an export stub. */
+ u = find_unwind_entry (SYMBOL_VALUE (msymbol2));
+ if (!u || u->stub_unwind.stub_type != EXPORT)
+ continue;
+
+ /* OK. Looks like the correct import stub. */
+ anaddr = SYMBOL_VALUE (msymbol2);
+ dld_cache.hook_stub.address = anaddr;
+ }
+ }
+ 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 /opt/langtools/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 /opt/langtools/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");
+ }
+
+ 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");
+ }
+ dld_flags = extract_unsigned_integer (buf, 4);
+
+ /* Turn on the flags we care about. */
+ dld_flags |= DLD_FLAGS_MAPPRIVATE;
+ if (have_endo)
+ dld_flags |= DLD_FLAGS_HOOKVALID;
+ store_unsigned_integer (buf, 4, dld_flags);
+ status = target_write_memory (anaddr, buf, 4);
+ if (status != 0)
+ {
+ error ("Unable to write __dld_flags\n");
+ }
+
+ /* Now find the address of _start and set a breakpoint there.
+ We still need this code for two reasons:
+
+ * Not all sites have /opt/langtools/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");
+ }
+
+ 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;
+
+ temp = so_list_head;
+ xfree (so_list_head);
+ so_list_head = temp->next;
+ }
+ clear_symtab_users ();
+}
+
+/* This operation removes the "hook" between GDB and the dynamic linker,
+ which causes the dld to notify GDB of shared library events.
+
+ After this operation completes, the dld will no longer notify GDB of
+ shared library events. To resume notifications, GDB must call
+ som_solib_create_inferior_hook.
+
+ This operation does not remove any knowledge of shared libraries which
+ GDB may already have been notified of.
+ */
+void
+som_solib_remove_inferior_hook (int pid)
+{
+ CORE_ADDR addr;
+ struct minimal_symbol *msymbol;
+ int status;
+ char dld_flags_buffer[4];
+ unsigned int dld_flags_value;
+ struct cleanup *old_cleanups = save_inferior_ptid ();
+
+ /* Ensure that we're really operating on the specified process. */
+ inferior_ptid = pid_to_ptid (pid);
+
+ /* We won't bother to remove the solib breakpoints from this process.
+
+ In fact, on PA64 the breakpoint is hard-coded into the dld callback,
+ and thus we're not supposed to remove it.
+
+ Rather, we'll merely clear the dld_flags bit that enables callbacks.
+ */
+ msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
+
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ status = target_read_memory (addr, dld_flags_buffer, 4);
+
+ dld_flags_value = extract_unsigned_integer (dld_flags_buffer, 4);
+
+ dld_flags_value &= ~DLD_FLAGS_HOOKVALID;
+ store_unsigned_integer (dld_flags_buffer, 4, dld_flags_value);
+ status = target_write_memory (addr, dld_flags_buffer, 4);
+
+ do_cleanups (old_cleanups);
+}
+
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_load call is made.
+
+ If filename is NULL, then loads of any dll will be caught. Else,
+ only loads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ som_solib_create_inferior_hook.
+ */
+void
+som_solib_create_catch_load_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_load_event_breakpoint ("__d_trap", tempflag, filename, cond_string);
+}
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_unload call is made.
+
+ If filename is NULL, then unloads of any dll will be caught. Else,
+ only unloads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ som_solib_create_inferior_hook.
+ */
+void
+som_solib_create_catch_unload_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_unload_event_breakpoint ("__d_trap", tempflag, filename, cond_string);
+}
+
+int
+som_solib_have_load_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == SHL_LOAD);
+}
+
+int
+som_solib_have_unload_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == SHL_UNLOAD);
+}
+
+static char *
+som_solib_library_pathname (int pid)
+{
+ CORE_ADDR dll_handle_address;
+ CORE_ADDR dll_pathname_address;
+ struct som_solib_mapped_entry dll_descriptor;
+ char *p;
+ static char dll_pathname[1024];
+
+ /* Read the descriptor of this newly-loaded library. */
+ dll_handle_address = read_register (ARG1_REGNUM);
+ read_memory (dll_handle_address, (char *) &dll_descriptor, sizeof (dll_descriptor));
+
+ /* We can find a pointer to the dll's pathname within the descriptor. */
+ dll_pathname_address = (CORE_ADDR) dll_descriptor.name;
+
+ /* Read the pathname, one byte at a time. */
+ p = dll_pathname;
+ for (;;)
+ {
+ char b;
+ read_memory (dll_pathname_address++, (char *) &b, 1);
+ *p++ = b;
+ if (b == '\0')
+ break;
+ }
+
+ return dll_pathname;
+}
+
+char *
+som_solib_loaded_library_pathname (int pid)
+{
+ if (!som_solib_have_load_event (pid))
+ error ("Must have a load event to use this query");
+
+ return som_solib_library_pathname (pid);
+}
+
+char *
+som_solib_unloaded_library_pathname (int pid)
+{
+ if (!som_solib_have_unload_event (pid))
+ error ("Must have an unload event to use this query");
+
+ return som_solib_library_pathname (pid);
+}
+
+static void
+som_solib_desire_dynamic_linker_symbols (void)
+{
+ struct objfile *objfile;
+ struct unwind_table_entry *u;
+ struct minimal_symbol *dld_msymbol;
+
+ /* Do we already know the value of these symbols? If so, then
+ we've no work to do.
+
+ (If you add clauses to this test, be sure to likewise update the
+ test within the loop.)
+ */
+ if (dld_cache.is_valid)
+ return;
+
+ ALL_OBJFILES (objfile)
+ {
+ dld_msymbol = lookup_minimal_symbol ("shl_load", NULL, objfile);
+ if (dld_msymbol != NULL)
+ {
+ dld_cache.load.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.load.unwind = find_unwind_entry (dld_cache.load.address);
+ }
+
+ dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_load",
+ objfile);
+ if (dld_msymbol != NULL)
+ {
+ if (SYMBOL_TYPE (dld_msymbol) == mst_solib_trampoline)
+ {
+ u = find_unwind_entry (SYMBOL_VALUE (dld_msymbol));
+ if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT))
+ {
+ dld_cache.load_stub.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.load_stub.unwind = u;
+ }
+ }
+ }
+
+ dld_msymbol = lookup_minimal_symbol ("shl_unload", NULL, objfile);
+ if (dld_msymbol != NULL)
+ {
+ dld_cache.unload.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.unload.unwind = find_unwind_entry (dld_cache.unload.address);
+
+ /* ??rehrauer: I'm not sure exactly what this is, but it appears
+ that on some HPUX 10.x versions, there's two unwind regions to
+ cover the body of "shl_unload", the second being 4 bytes past
+ the end of the first. This is a large hack to handle that
+ case, but since I don't seem to have any legitimate way to
+ look for this thing via the symbol table...
+ */
+ if (dld_cache.unload.unwind != NULL)
+ {
+ u = find_unwind_entry (dld_cache.unload.unwind->region_end + 4);
+ if (u != NULL)
+ {
+ dld_cache.unload2.address = u->region_start;
+ dld_cache.unload2.unwind = u;
+ }
+ }
+ }
+
+ dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_unload",
+ objfile);
+ if (dld_msymbol != NULL)
+ {
+ if (SYMBOL_TYPE (dld_msymbol) == mst_solib_trampoline)
+ {
+ u = find_unwind_entry (SYMBOL_VALUE (dld_msymbol));
+ if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT))
+ {
+ dld_cache.unload_stub.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.unload_stub.unwind = u;
+ }
+ }
+ }
+
+ /* Did we find everything we were looking for? If so, stop. */
+ if ((dld_cache.load.address != 0)
+ && (dld_cache.load_stub.address != 0)
+ && (dld_cache.unload.address != 0)
+ && (dld_cache.unload_stub.address != 0))
+ {
+ dld_cache.is_valid = 1;
+ break;
+ }
+ }
+
+ dld_cache.hook.unwind = find_unwind_entry (dld_cache.hook.address);
+ dld_cache.hook_stub.unwind = find_unwind_entry (dld_cache.hook_stub.address);
+
+ /* We're prepared not to find some of these symbols, which is why
+ this function is a "desire" operation, and not a "require".
+ */
+}
+
+int
+som_solib_in_dynamic_linker (int pid, CORE_ADDR pc)
+{
+ struct unwind_table_entry *u_pc;
+
+ /* Are we in the dld itself?
+
+ ??rehrauer: Large hack -- We'll assume that any address in a
+ shared text region is the dld's text. This would obviously
+ fall down if the user attached to a process, whose shlibs
+ weren't mapped to a (writeable) private region. However, in
+ that case the debugger probably isn't able to set the fundamental
+ breakpoint in the dld callback anyways, so this hack should be
+ safe.
+ */
+ if ((pc & (CORE_ADDR) 0xc0000000) == (CORE_ADDR) 0xc0000000)
+ return 1;
+
+ /* Cache the address of some symbols that are part of the dynamic
+ linker, if not already known.
+ */
+ som_solib_desire_dynamic_linker_symbols ();
+
+ /* Are we in the dld callback? Or its export stub? */
+ u_pc = find_unwind_entry (pc);
+ if (u_pc == NULL)
+ return 0;
+
+ if ((u_pc == dld_cache.hook.unwind) || (u_pc == dld_cache.hook_stub.unwind))
+ return 1;
+
+ /* Or the interface of the dld (i.e., "shl_load" or friends)? */
+ if ((u_pc == dld_cache.load.unwind)
+ || (u_pc == dld_cache.unload.unwind)
+ || (u_pc == dld_cache.unload2.unwind)
+ || (u_pc == dld_cache.load_stub.unwind)
+ || (u_pc == dld_cache.unload_stub.unwind))
+ return 1;
+
+ /* Apparently this address isn't part of the dld's text. */
+ return 0;
+}
+
+
+/* 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 (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;
+}
+
+/* elz:
+ Return the address of the handle of the shared library
+ in which ADDR belongs. If
+ ADDR isn't in any known shared library, return zero. */
+/* this function is used in hppa_fix_call_dummy in hppa-tdep.c */
+
+CORE_ADDR
+som_solib_get_solib_by_pc (CORE_ADDR addr)
+{
+ struct so_list *so_list = so_list_head;
+
+ while (so_list)
+ {
+ if (so_list->som_solib.text_addr <= addr
+ && so_list->som_solib.text_end > addr)
+ {
+ break;
+ }
+ so_list = so_list->next;
+ }
+ if (so_list)
+ return so_list->solib_addr;
+ else
+ return 0;
+}
+
+
+int
+som_solib_section_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. */
+ offsets->offsets[SECT_OFF_TEXT (objfile)]
+ = (so_list->som_solib.text_addr
+ - so_list->som_solib.text_link_addr);
+ offsets->offsets[SECT_OFF_RODATA (objfile)]
+ = ANOFFSET (offsets, SECT_OFF_TEXT (objfile));
+
+ /* 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!");
+ offsets->offsets[SECT_OFF_DATA (objfile)] = 0;
+ offsets->offsets[SECT_OFF_BSS (objfile)] = 0;
+ return 1;
+ }
+ offsets->offsets[SECT_OFF_DATA (objfile)]
+ = (so_list->som_solib.data_start - private_section->vma);
+ offsets->offsets[SECT_OFF_BSS (objfile)]
+ = ANOFFSET (offsets, SECT_OFF_DATA (objfile));
+ return 1;
+ }
+ so_list = so_list->next;
+ }
+ return 0;
+}
+
+/* Dump information about all the currently loaded shared libraries. */
+
+static void
+som_sharedlibrary_info_command (char *ignore, int from_tty)
+{
+ struct so_list *so_list = so_list_head;
+
+ if (exec_bfd == NULL)
+ {
+ printf_unfiltered ("No executable 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", so_list->som_solib.name);
+ if (so_list->objfile == NULL)
+ printf_unfiltered (" (symbols not loaded)");
+ printf_unfiltered ("\n");
+ 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 (char *args, int from_tty)
+{
+ dont_repeat ();
+ som_solib_add (args, from_tty, (struct target_ops *) 0, 1);
+}
+
+
+
+char *
+som_solib_address (CORE_ADDR addr)
+{
+ struct so_list *so = so_list_head;
+
+ while (so)
+ {
+ /* Is this address within this shlib's text range? If so,
+ return the shlib's name.
+ */
+ if ((addr >= so->som_solib.text_addr) && (addr <= so->som_solib.text_end))
+ return so->som_solib.name;
+
+ /* Nope, keep looking... */
+ so = so->next;
+ }
+
+ /* No, we couldn't prove that the address is within a shlib. */
+ return NULL;
+}
+
+
+void
+som_solib_restart (void)
+{
+ struct so_list *sl = so_list_head;
+
+ /* Before the shlib info vanishes, use it to disable any breakpoints
+ that may still be active in those shlibs.
+ */
+ disable_breakpoints_in_shlibs (0);
+
+ /* Discard all the shlib descriptors.
+ */
+ while (sl)
+ {
+ struct so_list *next_sl = sl->next;
+ xfree (sl);
+ sl = next_sl;
+ }
+ so_list_head = NULL;
+
+ som_solib_total_st_size = (LONGEST) 0;
+ som_solib_st_size_threshold_exceeded = 0;
+
+ dld_cache.is_valid = 0;
+
+ dld_cache.hook.address = 0;
+ dld_cache.hook.unwind = NULL;
+
+ dld_cache.hook_stub.address = 0;
+ dld_cache.hook_stub.unwind = NULL;
+
+ dld_cache.load.address = 0;
+ dld_cache.load.unwind = NULL;
+
+ dld_cache.load_stub.address = 0;
+ dld_cache.load_stub.unwind = NULL;
+
+ dld_cache.unload.address = 0;
+ dld_cache.unload.unwind = NULL;
+
+ dld_cache.unload2.address = 0;
+ dld_cache.unload2.unwind = NULL;
+
+ dld_cache.unload_stub.address = 0;
+ dld_cache.unload_stub.unwind = NULL;
+}
+
+
+/* LOCAL FUNCTION
+
+ no_shared_libraries -- handle command to explicitly discard symbols
+ from shared libraries.
+
+ DESCRIPTION
+
+ Implements the command "nosharedlibrary", which discards symbols
+ that have been auto-loaded from shared libraries. Symbols from
+ shared libraries that were added by explicit request of the user
+ are not discarded. Also called from remote.c. */
+
+void
+no_shared_libraries (char *ignored, int from_tty)
+{
+ /* FIXME */
+}
+
+
+void
+_initialize_som_solib (void)
+{
+ 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_boolean,
+ (char *) &auto_solib_add,
+ "Set autoloading of shared library symbols.\n\
+If \"on\", symbols from all shared object libraries will be loaded\n\
+automatically when the inferior begins execution, when the dynamic linker\n\
+informs gdb that a new library has been loaded, or when attaching to the\n\
+inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("auto-solib-limit", class_support, var_zinteger,
+ (char *) &auto_solib_limit,
+ "Set threshold (in Mb) for autoloading shared library symbols.\n\
+When shared library autoloading is enabled, new libraries will be loaded\n\
+only until the total size of shared library symbols exceeds this\n\
+threshold in megabytes. Is ignored when using `sharedlibrary'.",
+ &setlist),
+ &showlist);
+
+ /* ??rehrauer: On HP-UX, the kernel parameter MAXDSIZ limits how
+ much data space a process can use. We ought to be reading
+ MAXDSIZ and setting auto_solib_limit to some large fraction of
+ that value. If not that, we maybe ought to be setting it smaller
+ than the default for MAXDSIZ (that being 64Mb, I believe).
+ However, [1] this threshold is only crudely approximated rather
+ than actually measured, and [2] 50 Mbytes is too small for
+ debugging gdb itself. Thus, the arbitrary 100 figure. */
+ auto_solib_limit = 100; /* Megabytes */
+
+ som_solib_restart ();
+}
+
+/* Get some HPUX-specific data from a shared lib.
+ */
+CORE_ADDR
+so_lib_thread_start_addr (struct so_list *so)
+{
+ return so->som_solib.tsd_start_addr;
+}
diff --git a/contrib/gdb/gdb/somsolib.h b/contrib/gdb/gdb/somsolib.h
new file mode 100644
index 0000000..c241411
--- /dev/null
+++ b/contrib/gdb/gdb/somsolib.h
@@ -0,0 +1,178 @@
+/* HP SOM Shared library declarations for GDB, the GNU Debugger.
+
+ Copyright 1992, 1994, 1995, 1998, 1999, 2000, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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. */
+
+#ifndef SOMSOLIB_H
+#define SOMSOLIB_H
+
+/* Forward decl's for prototypes */
+struct target_ops;
+struct objfile;
+struct section_offsets;
+
+/* Called to add symbols from a shared library to gdb's symbol table. */
+
+#define SOLIB_ADD(filename, from_tty, targ, readsyms) \
+ som_solib_add (filename, from_tty, targ, readsyms)
+
+extern void som_solib_add (char *, int, struct target_ops *, int);
+
+extern CORE_ADDR som_solib_get_got_by_pc (CORE_ADDR);
+
+extern int som_solib_section_offsets (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 (void);
+
+/* Function to be called to remove the connection between debugger and
+ dynamic linker that was established by SOLIB_CREATE_INFERIOR_HOOK.
+ (This operation does not remove shared library information from
+ the debugger, as CLEAR_SOLIB does.)
+ */
+#define SOLIB_REMOVE_INFERIOR_HOOK(PID) som_solib_remove_inferior_hook(PID)
+
+extern void som_solib_remove_inferior_hook (int);
+
+/* This function is called by the "catch load" command. It allows
+ the debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is loaded.
+ */
+#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag, filename,cond_string) \
+ som_solib_create_catch_load_hook (pid, tempflag, filename, cond_string)
+
+extern void som_solib_create_catch_load_hook (int, int, char *, char *);
+
+/* This function is called by the "catch unload" command. It allows
+ the debugger to be notified by the dynamic linker when a specified
+ library file (or any library file, if filename is NULL) is unloaded.
+ */
+#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename, cond_string) \
+ som_solib_create_catch_unload_hook (pid, tempflag, filename, cond_string)
+
+extern void som_solib_create_catch_unload_hook (int, int, char *, char *);
+
+/* This function returns TRUE if the dynamic linker has just reported
+ a load of a library.
+
+ This function must be used only when the inferior has stopped in
+ the dynamic linker hook, or undefined results are guaranteed.
+ */
+#define SOLIB_HAVE_LOAD_EVENT(pid) \
+ som_solib_have_load_event (pid)
+
+extern int som_solib_have_load_event (int);
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been loaded.
+
+ This function must be used only when SOLIB_HAVE_LOAD_EVENT is TRUE,
+ or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the inferior
+ has stopped in the dynamic linker hook, and becomes invalid as soon
+ as the inferior is continued. Clients should make a copy of this
+ string if they wish to continue the inferior and then access the string.
+ */
+#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) \
+ som_solib_loaded_library_pathname (pid)
+
+extern char *som_solib_loaded_library_pathname (int);
+
+/* This function returns TRUE if the dynamic linker has just reported
+ an unload of a library.
+
+ This function must be used only when the inferior has stopped in
+ the dynamic linker hook, or undefined results are guaranteed.
+ */
+#define SOLIB_HAVE_UNLOAD_EVENT(pid) \
+ som_solib_have_unload_event (pid)
+
+extern int som_solib_have_unload_event (int);
+
+/* This function returns a pointer to the string representation of the
+ pathname of the dynamically-linked library that has just been unloaded.
+
+ This function must be used only when SOLIB_HAVE_UNLOAD_EVENT is TRUE,
+ or undefined results are guaranteed.
+
+ This string's contents are only valid immediately after the inferior
+ has stopped in the dynamic linker hook, and becomes invalid as soon
+ as the inferior is continued. Clients should make a copy of this
+ string if they wish to continue the inferior and then access the string.
+ */
+#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) \
+ som_solib_unloaded_library_pathname (pid)
+
+extern char *som_solib_unloaded_library_pathname (int);
+
+/* This function returns TRUE if pc is the address of an instruction that
+ lies within the dynamic linker (such as the event hook, or the dld
+ itself).
+
+ This function must be used only when a dynamic linker event has been
+ caught, and the inferior is being stepped out of the hook, or undefined
+ results are guaranteed.
+ */
+#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
+ som_solib_in_dynamic_linker (pid, pc)
+
+extern int som_solib_in_dynamic_linker (int, CORE_ADDR);
+
+/* This function must be called when the inferior is killed, and the program
+ restarted. This is not the same as CLEAR_SOLIB, in that it doesn't discard
+ any symbol tables.
+
+ Presently, this functionality is not implemented.
+ */
+#define SOLIB_RESTART() \
+ som_solib_restart ()
+
+extern void som_solib_restart (void);
+
+/* If we can't set a breakpoint, and it's in a shared library, just
+ disable it. */
+
+#define DISABLE_UNSETTABLE_BREAK(addr) (som_solib_address(addr) != NULL)
+
+extern char *som_solib_address (CORE_ADDR); /* somsolib.c */
+
+/* If ADDR lies in a shared library, return its name. */
+
+#define PC_SOLIB(addr) som_solib_address (addr)
+
+extern CORE_ADDR som_solib_get_solib_by_pc (CORE_ADDR addr);
+
+struct so_list;
+extern CORE_ADDR so_lib_thread_start_addr (struct so_list *so);
+
+extern void no_shared_libraries (char *ignored, int from_tty);
+
+#endif
diff --git a/contrib/gdb/gdb/source.c b/contrib/gdb/gdb/source.c
new file mode 100644
index 0000000..92cdce4
--- /dev/null
+++ b/contrib/gdb/gdb/source.c
@@ -0,0 +1,1596 @@
+/* List lines of source files for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "source.h"
+#include "gdbcmd.h"
+#include "frame.h"
+#include "value.h"
+
+#include <sys/types.h>
+#include "gdb_string.h"
+#include "gdb_stat.h"
+#include <fcntl.h>
+#include "gdbcore.h"
+#include "gdb_regex.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "annotate.h"
+#include "gdbtypes.h"
+#include "linespec.h"
+#include "filenames.h" /* for DOSish file names */
+#include "completer.h"
+#include "ui-out.h"
+#include "readline/readline.h"
+
+#ifdef CRLF_SOURCE_FILES
+
+/* Define CRLF_SOURCE_FILES in an xm-*.h file if source files on the
+ host use \r\n rather than just \n. Defining CRLF_SOURCE_FILES is
+ much faster than defining LSEEK_NOT_LINEAR. */
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define OPEN_MODE (O_RDONLY | O_BINARY)
+#define FDOPEN_MODE FOPEN_RB
+
+#else /* ! defined (CRLF_SOURCE_FILES) */
+
+#define OPEN_MODE O_RDONLY
+#define FDOPEN_MODE FOPEN_RT
+
+#endif /* ! defined (CRLF_SOURCE_FILES) */
+
+/* Prototypes for exported functions. */
+
+void _initialize_source (void);
+
+/* Prototypes for local functions. */
+
+static int get_filename_and_charpos (struct symtab *, char **);
+
+static void reverse_search_command (char *, int);
+
+static void forward_search_command (char *, int);
+
+static void line_info (char *, int);
+
+static void source_info (char *, int);
+
+static void show_directories (char *, int);
+
+/* 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. */
+
+static struct symtab *current_source_symtab;
+
+/* Default next line to list. */
+
+static 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;
+
+/* Saves the name of the last source file visited and a possible error code.
+ Used to prevent repeating annoying "No such file or directories" msgs */
+
+static struct symtab *last_source_visited = NULL;
+static int last_source_error = 0;
+
+/* Return the first line listed by print_source_lines.
+ Used by command interpreters to request listing from
+ a previous point. */
+
+int
+get_first_line_listed (void)
+{
+ return first_line_listed;
+}
+
+/* Return the default number of lines to print with commands like the
+ cli "list". The caller of print_source_lines must use this to
+ calculate the end line and use it in the call to print_source_lines
+ as it does not automatically use this value. */
+
+int
+get_lines_to_list (void)
+{
+ return lines_to_list;
+}
+
+/* Return the current source file for listing and next line to list.
+ NOTE: The returned sal pc and end fields are not valid. */
+
+struct symtab_and_line
+get_current_source_symtab_and_line (void)
+{
+ struct symtab_and_line cursal;
+
+ cursal.symtab = current_source_symtab;
+ cursal.line = current_source_line;
+ cursal.pc = 0;
+ cursal.end = 0;
+
+ return cursal;
+}
+
+/* If the current source file for listing is not set, try and get a default.
+ Usually called before get_current_source_symtab_and_line() is called.
+ It may err out if a default cannot be determined.
+ We must be cautious about where it is called, as it can recurse as the
+ process of determining a new default may call the caller!
+ Use get_current_source_symtab_and_line only to get whatever
+ we have without erroring out or trying to get a default. */
+
+void
+set_default_source_symtab_and_line (void)
+{
+ struct symtab_and_line cursal;
+
+ 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)
+ select_source_symtab (0);
+}
+
+/* Return the current default file for listing and next line to list
+ (the returned sal pc and end fields are not valid.)
+ and set the current default to whatever is in SAL.
+ NOTE: The returned sal pc and end fields are not valid. */
+
+struct symtab_and_line
+set_current_source_symtab_and_line (const struct symtab_and_line *sal)
+{
+ struct symtab_and_line cursal;
+
+ cursal.symtab = current_source_symtab;
+ cursal.line = current_source_line;
+
+ current_source_symtab = sal->symtab;
+ current_source_line = sal->line;
+ cursal.pc = 0;
+ cursal.end = 0;
+
+ return cursal;
+}
+
+/* Reset any information stored about a default file and line to print. */
+
+void
+clear_current_source_symtab_and_line (void)
+{
+ current_source_symtab = 0;
+ current_source_line = 0;
+}
+
+/* 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 (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_name (), 0, VAR_DOMAIN, 0, NULL))
+ {
+ sals = decode_line_spec (main_name (), 1);
+ sal = sals.sals[0];
+ xfree (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 && (DEPRECATED_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 && (DEPRECATED_STREQ (&name[len - 2], ".h"))))
+ {
+ cs_pst = ps;
+ }
+ }
+ }
+ if (cs_pst)
+ {
+ if (cs_pst->readin)
+ {
+ internal_error (__FILE__, __LINE__,
+ "select_source_symtab: "
+ "readin pst found and no symtabs.");
+ }
+ else
+ {
+ current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
+ }
+ }
+ if (current_source_symtab)
+ return;
+
+ error ("Can't find a default source file");
+}
+
+static void
+show_directories (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 (void)
+{
+ struct symtab *s;
+ struct objfile *objfile;
+ struct partial_symtab *pst;
+
+ for (objfile = object_files; objfile != NULL; objfile = objfile->next)
+ {
+ for (s = objfile->symtabs; s != NULL; s = s->next)
+ {
+ if (s->line_charpos != NULL)
+ {
+ xmfree (objfile->md, s->line_charpos);
+ s->line_charpos = NULL;
+ }
+ if (s->fullname != NULL)
+ {
+ xmfree (objfile->md, s->fullname);
+ s->fullname = NULL;
+ }
+ }
+
+ ALL_OBJFILE_PSYMTABS (objfile, pst)
+ {
+ if (pst->fullname != NULL)
+ {
+ xfree (pst->fullname);
+ pst->fullname = NULL;
+ }
+ }
+ }
+}
+
+void
+init_source_path (void)
+{
+ char buf[20];
+
+ sprintf (buf, "$cdir%c$cwd", DIRNAME_SEPARATOR);
+ source_path = xstrdup (buf);
+ forget_cached_source_info ();
+}
+
+void
+init_last_source_visited (void)
+{
+ last_source_visited = NULL;
+}
+
+/* Add zero or more directories to the front of the source path. */
+
+void
+directory_command (char *dirname, int from_tty)
+{
+ dont_repeat ();
+ /* FIXME, this goes to "delete dir"... */
+ if (dirname == 0)
+ {
+ if (from_tty && query ("Reinitialize source path to empty? "))
+ {
+ xfree (source_path);
+ init_source_path ();
+ }
+ }
+ else
+ {
+ mod_path (dirname, &source_path);
+ last_source_visited = NULL;
+ }
+ 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 (char *dirname, char **which_path)
+{
+ add_path (dirname, which_path, 1);
+}
+
+/* Workhorse of mod_path. Takes an extra argument to determine
+ if dirname should be parsed for separators that indicate multiple
+ directories. This allows for interfaces that pre-parse the dirname
+ and allow specification of traditional separator characters such
+ as space or tab. */
+
+void
+add_path (char *dirname, char **which_path, int parse_separators)
+{
+ char *old = *which_path;
+ int prefix = 0;
+
+ if (dirname == 0)
+ return;
+
+ dirname = xstrdup (dirname);
+ make_cleanup (xfree, dirname);
+
+ do
+ {
+ char *name = dirname;
+ char *p;
+ struct stat st;
+
+ {
+ char *separator = NULL;
+ char *space = NULL;
+ char *tab = NULL;
+
+ if (parse_separators)
+ {
+ separator = strchr (name, DIRNAME_SEPARATOR);
+ space = strchr (name, ' ');
+ 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;
+ }
+ }
+
+ if (!(IS_DIR_SEPARATOR (*name) && p <= name + 1) /* "/" */
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ /* On MS-DOS and MS-Windows, h:\ is different from h: */
+ && !(p == name + 3 && name[1] == ':') /* "d:/" */
+#endif
+ && IS_DIR_SEPARATOR (p[-1]))
+ /* Sigh. "foo/" => "foo" */
+ --p;
+ *p = '\0';
+
+ while (p > name && p[-1] == '.')
+ {
+ if (p - name == 1)
+ {
+ /* "." => getwd (). */
+ name = current_directory;
+ goto append;
+ }
+ else if (p > name + 1 && IS_DIR_SEPARATOR (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);
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ else if (IS_ABSOLUTE_PATH (name) && p == name + 2) /* "d:" => "d:." */
+ name = concat (name, ".", NULL);
+#endif
+ else if (!IS_ABSOLUTE_PATH (name) && name[0] != '$')
+ name = concat (current_directory, SLASH_STRING, name, NULL);
+ else
+ name = savestring (name, p - name);
+ make_cleanup (xfree, 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:
+ {
+ unsigned int len = strlen (name);
+
+ p = *which_path;
+ while (1)
+ {
+ /* FIXME: strncmp loses in interesting ways on MS-DOS and
+ MS-Windows because of case-insensitivity and two different
+ but functionally identical slash characters. We need a
+ special filesystem-dependent file-name comparison function.
+
+ Actually, even on Unix I would use realpath() or its work-
+ alike before comparing. Then all the code above which
+ removes excess slashes and dots could simply go away. */
+ 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);
+ xfree (temp);
+ }
+ else
+ {
+ *which_path = concat (name, (old[0] ? tinybuf : old), old, NULL);
+ prefix = strlen (name);
+ }
+ xfree (old);
+ old = *which_path;
+ }
+ }
+ skip_dup:;
+ }
+ while (*dirname != '\0');
+}
+
+
+static void
+source_info (char *ignore, int from_tty)
+{
+ 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));
+ printf_filtered ("Compiled with %s debugging format.\n", s->debugformat);
+ printf_filtered ("%s preprocessor macro info.\n",
+ s->macro_table ? "Includes" : "Does not include");
+}
+
+
+/* Return True if the file NAME exists and is a regular file */
+static int
+is_regular_file (const char *name)
+{
+ struct stat st;
+ const int status = stat (name, &st);
+
+ /* Stat should never fail except when the file does not exist.
+ If stat fails, analyze the source of error and return True
+ unless the file does not exist, to avoid returning false results
+ on obscure systems where stat does not work as expected.
+ */
+ if (status != 0)
+ return (errno != ENOENT);
+
+ return S_ISREG (st.st_mode);
+}
+
+/* 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 FILENAME_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 (const char *path, int try_cwd_first, const char *string,
+ int mode, int prot,
+ char **filename_opened)
+{
+ int fd;
+ char *filename;
+ const char *p;
+ const char *p1;
+ int len;
+ int alloclen;
+
+ if (!path)
+ path = ".";
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ mode |= O_BINARY;
+#endif
+
+ if (try_cwd_first || IS_ABSOLUTE_PATH (string))
+ {
+ int i;
+
+ if (is_regular_file (string))
+ {
+ filename = alloca (strlen (string) + 1);
+ strcpy (filename, string);
+ fd = open (filename, mode, prot);
+ if (fd >= 0)
+ goto done;
+ }
+ else
+ {
+ filename = NULL;
+ fd = -1;
+ }
+
+ for (i = 0; string[i]; i++)
+ if (IS_DIR_SEPARATOR (string[i]))
+ goto done;
+ }
+
+ /* ./foo => foo */
+ while (string[0] == '.' && IS_DIR_SEPARATOR (string[1]))
+ string += 2;
+
+ alloclen = strlen (path) + strlen (string) + 2;
+ filename = alloca (alloclen);
+ fd = -1;
+ for (p = path; p; p = p1 ? p1 + 1 : 0)
+ {
+ p1 = 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 = 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 && IS_DIR_SEPARATOR (filename[len - 1]))
+ filename[--len] = 0;
+
+ strcat (filename + len, SLASH_STRING);
+ strcat (filename, string);
+
+ if (is_regular_file (filename))
+ {
+ fd = open (filename, mode);
+ if (fd >= 0)
+ break;
+ }
+ }
+
+done:
+ if (filename_opened)
+ {
+ /* If a file was opened, canonicalize its filename. Use xfullpath
+ rather than gdb_realpath to avoid resolving the basename part
+ of filenames when the associated file is a symbolic link. This
+ fixes a potential inconsistency between the filenames known to
+ GDB and the filenames it prints in the annotations. */
+ if (fd < 0)
+ *filename_opened = NULL;
+ else if (IS_ABSOLUTE_PATH (filename))
+ *filename_opened = xfullpath (filename);
+ else
+ {
+ /* Beware the // my son, the Emacs barfs, the botch that catch... */
+
+ char *f = concat (current_directory,
+ IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1])
+ ? "" : SLASH_STRING,
+ filename, NULL);
+ *filename_opened = xfullpath (f);
+ xfree (f);
+ }
+ }
+
+ return fd;
+}
+
+
+/* This is essentially a convenience, for clients that want the behaviour
+ of openp, using source_path, but that really don't want the file to be
+ opened but want instead just to know what the full pathname is (as
+ qualified against source_path).
+
+ The current working directory is searched first.
+
+ If the file was found, this function returns 1, and FULL_PATHNAME is
+ set to the fully-qualified pathname.
+
+ Else, this functions returns 0, and FULL_PATHNAME is set to NULL.
+ */
+int
+source_full_path_of (char *filename, char **full_pathname)
+{
+ int fd;
+
+ fd = openp (source_path, 1, filename, O_RDONLY, 0, full_pathname);
+ if (fd < 0)
+ {
+ *full_pathname = NULL;
+ return 0;
+ }
+
+ close (fd);
+ return 1;
+}
+
+
+/* Open a source file given a symtab S. Returns a file descriptor or
+ negative number for error. */
+
+int
+open_source_file (struct symtab *s)
+{
+ char *path = source_path;
+ const char *p;
+ int result;
+ char *fullname;
+
+ /* Quick way out if we already know its full name */
+ if (s->fullname)
+ {
+ result = open (s->fullname, OPEN_MODE);
+ if (result >= 0)
+ return result;
+ /* Didn't work -- free old one, try again. */
+ xmfree (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, OPEN_MODE, 0, &s->fullname);
+ if (result < 0)
+ {
+ /* Didn't work. Try using just the basename. */
+ p = lbasename (s->filename);
+ if (p != s->filename)
+ result = openp (path, 0, p, OPEN_MODE, 0, &s->fullname);
+ }
+
+ if (result >= 0)
+ {
+ fullname = s->fullname;
+ s->fullname = mstrsave (s->objfile->md, s->fullname);
+ xfree (fullname);
+ }
+ return result;
+}
+
+/* Return the path to the source file associated with symtab. Returns NULL
+ if no symtab. */
+
+char *
+symtab_to_filename (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. */
+
+void
+find_source_lines (struct symtab *s, int desc)
+{
+ struct stat st;
+ char *data, *p, *end;
+ int nlines = 0;
+ int lines_allocated = 1000;
+ int *line_charpos;
+ long mtime = 0;
+ int size;
+
+ line_charpos = (int *) xmmalloc (s->objfile->md,
+ lines_allocated * sizeof (int));
+ if (fstat (desc, &st) < 0)
+ perror_with_name (s->filename);
+
+ if (s && s->objfile && s->objfile->obfd)
+ mtime = bfd_get_mtime (s->objfile->obfd);
+ else if (exec_bfd)
+ mtime = bfd_get_mtime (exec_bfd);
+
+ if (mtime && mtime < st.st_mtime)
+ {
+ warning ("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 (xfree, data);
+
+ /* Reassign `size' to result of read for systems where \r\n -> \n. */
+ size = myread (desc, data, size);
+ if (size < 0)
+ perror_with_name (s->filename);
+ 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 (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 (struct symtab *s, int chr)
+{
+ int line = 0;
+ 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 (struct symtab *s, char **fullname)
+{
+ 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 (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. */
+
+static void print_source_lines_base (struct symtab *s, int line, int stopline,
+ int noerror);
+static void
+print_source_lines_base (struct symtab *s, int line, int stopline, int noerror)
+{
+ int c;
+ int desc;
+ 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;
+
+ /* If printing of source lines is disabled, just print file and line number */
+ if (ui_out_test_flags (uiout, ui_source_list))
+ {
+ /* Only prints "No such file or directory" once */
+ if ((s != last_source_visited) || (!last_source_error))
+ {
+ last_source_visited = s;
+ desc = open_source_file (s);
+ }
+ else
+ {
+ desc = last_source_error;
+ noerror = 1;
+ }
+ }
+ else
+ {
+ desc = -1;
+ noerror = 1;
+ }
+
+ if (desc < 0)
+ {
+ last_source_error = desc;
+
+ if (!noerror)
+ {
+ char *name = alloca (strlen (s->filename) + 100);
+ sprintf (name, "%d\t%s", line, s->filename);
+ print_sys_errmsg (name, errno);
+ }
+ else
+ ui_out_field_int (uiout, "line", line);
+ ui_out_text (uiout, "\tin ");
+ ui_out_field_string (uiout, "file", s->filename);
+ ui_out_text (uiout, "\n");
+
+ return;
+ }
+
+ last_source_error = 0;
+
+ 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, FDOPEN_MODE);
+ clearerr (stream);
+
+ while (nlines-- > 0)
+ {
+ char buf[20];
+
+ c = fgetc (stream);
+ if (c == EOF)
+ break;
+ last_line_listed = current_source_line;
+ sprintf (buf, "%d\t", current_source_line++);
+ ui_out_text (uiout, buf);
+ do
+ {
+ if (c < 040 && c != '\t' && c != '\n' && c != '\r')
+ {
+ sprintf (buf, "^%c", c + 0100);
+ ui_out_text (uiout, buf);
+ }
+ else if (c == 0177)
+ ui_out_text (uiout, "^?");
+#ifdef CRLF_SOURCE_FILES
+ else if (c == '\r')
+ {
+ /* Skip a \r character, but only before a \n. */
+ int c1 = fgetc (stream);
+
+ if (c1 != '\n')
+ printf_filtered ("^%c", c + 0100);
+ if (c1 != EOF)
+ ungetc (c1, stream);
+ }
+#endif
+ else
+ {
+ sprintf (buf, "%c", c);
+ ui_out_text (uiout, buf);
+ }
+ }
+ while (c != '\n' && (c = fgetc (stream)) >= 0);
+ }
+
+ fclose (stream);
+}
+
+/* Show source lines from the file of symtab S, starting with line
+ number LINE and stopping before line number STOPLINE. If this is the
+ not the command line version, then the source is shown in the source
+ window otherwise it is simply printed */
+
+void
+print_source_lines (struct symtab *s, int line, int stopline, int noerror)
+{
+ print_source_lines_base (s, line, stopline, noerror);
+}
+
+/* Print info on range of pc's in a specified line. */
+
+static void
+line_info (char *arg, int from_tty)
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ CORE_ADDR start_pc, end_pc;
+ int i;
+
+ init_sal (&sal); /* initialize to zeroes */
+
+ if (arg == 0)
+ {
+ sal.symtab = current_source_symtab;
+ sal.line = last_line_listed;
+ 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);
+ }
+ xfree (sals.sals);
+}
+
+/* Commands to search the source file for a regexp. */
+
+static void
+forward_search_command (char *regex, int from_tty)
+{
+ int c;
+ int desc;
+ FILE *stream;
+ int line;
+ char *msg;
+
+ line = last_line_listed + 1;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error ("%s", msg);
+
+ if (current_source_symtab == 0)
+ select_source_symtab (0);
+
+ 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, FDOPEN_MODE);
+ clearerr (stream);
+ while (1)
+ {
+ static char *buf = NULL;
+ 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);
+
+#ifdef CRLF_SOURCE_FILES
+ /* Remove the \r, if any, at the end of the line, otherwise
+ regular expressions that end with $ or \n won't work. */
+ if (p - buf > 1 && p[-2] == '\r')
+ {
+ p--;
+ p[-1] = '\n';
+ }
+#endif
+
+ /* 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);
+}
+
+static void
+reverse_search_command (char *regex, int from_tty)
+{
+ int c;
+ int desc;
+ FILE *stream;
+ int line;
+ char *msg;
+
+ line = last_line_listed - 1;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error ("%s", msg);
+
+ if (current_source_symtab == 0)
+ select_source_symtab (0);
+
+ 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, FDOPEN_MODE);
+ 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??? */
+ char *p = buf;
+
+ c = getc (stream);
+ if (c == EOF)
+ break;
+ do
+ {
+ *p++ = c;
+ }
+ while (c != '\n' && (c = getc (stream)) >= 0);
+
+#ifdef CRLF_SOURCE_FILES
+ /* Remove the \r, if any, at the end of the line, otherwise
+ regular expressions that end with $ or \n won't work. */
+ if (p - buf > 1 && p[-2] == '\r')
+ {
+ p--;
+ p[-1] = '\n';
+ }
+#endif
+
+ /* 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 (void)
+{
+ 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);
+
+ if (dbx_commands)
+ add_com_alias ("use", "directory", class_files, 0);
+
+ set_cmd_completer (c, 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);
+
+ if (xdb_commands)
+ {
+ add_com_alias ("D", "directory", class_files, 0);
+ add_cmd ("ld", 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.",
+ &cmdlist);
+ }
+
+ 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 \"$_\".");
+
+ if (xdb_commands)
+ {
+ add_com_alias ("/", "forward-search", class_files, 0);
+ add_com_alias ("?", "reverse-search", class_files, 0);
+ }
+
+ 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/source.h b/contrib/gdb/gdb/source.h
new file mode 100644
index 0000000..7cfed1a
--- /dev/null
+++ b/contrib/gdb/gdb/source.h
@@ -0,0 +1,68 @@
+/* List lines of source files for GDB, the GNU debugger.
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef SOURCE_H
+#define SOURCE_H
+
+struct symtab;
+
+/* Open a source file given a symtab S. Returns a file descriptor or
+ negative number for error. */
+extern int open_source_file (struct symtab *s);
+
+/* 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. */
+extern void find_source_lines (struct symtab *s, int desc);
+
+/* Return the first line listed by print_source_lines.
+ Used by command interpreters to request listing from
+ a previous point. */
+extern int get_first_line_listed (void);
+
+/* Return the default number of lines to print with commands like the
+ cli "list". The caller of print_source_lines must use this to
+ calculate the end line and use it in the call to print_source_lines
+ as it does not automatically use this value. */
+extern int get_lines_to_list (void);
+
+/* Return the current source file for listing and next line to list.
+ NOTE: The returned sal pc and end fields are not valid. */
+extern struct symtab_and_line get_current_source_symtab_and_line (void);
+
+/* If the current source file for listing is not set, try and get a default.
+ Usually called before get_current_source_symtab_and_line() is called.
+ It may err out if a default cannot be determined.
+ We must be cautious about where it is called, as it can recurse as the
+ process of determining a new default may call the caller!
+ Use get_current_source_symtab_and_line only to get whatever
+ we have without erroring out or trying to get a default. */
+extern void set_default_source_symtab_and_line (void);
+
+/* Return the current default file for listing and next line to list
+ (the returned sal pc and end fields are not valid.)
+ and set the current default to whatever is in SAL.
+ NOTE: The returned sal pc and end fields are not valid. */
+extern struct symtab_and_line set_current_source_symtab_and_line (const struct symtab_and_line *);
+
+/* Reset any information stored about a default file and line to print. */
+extern void clear_current_source_symtab_and_line (void);
+#endif
diff --git a/contrib/gdb/gdb/sparc-nat.c b/contrib/gdb/gdb/sparc-nat.c
new file mode 100644
index 0000000..955e65e
--- /dev/null
+++ b/contrib/gdb/gdb/sparc-nat.c
@@ -0,0 +1,330 @@
+/* Native-dependent code for SPARC.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+#include "target.h"
+
+#include "gdb_assert.h"
+#include <signal.h>
+#include "gdb_string.h"
+#include <sys/ptrace.h>
+#include "gdb_wait.h"
+#ifdef HAVE_MACHINE_REG_H
+#include <machine/reg.h>
+#endif
+
+#include "sparc-tdep.h"
+#include "sparc-nat.h"
+
+/* With some trickery we can use the code in this file for most (if
+ not all) ptrace(2) based SPARC systems, which includes SunOS 4,
+ GNU/Linux and the various SPARC BSD's.
+
+ First, we need a data structure for use with ptrace(2). SunOS has
+ `struct regs' and `struct fp_status' in <machine/reg.h>. BSD's
+ have `struct reg' and `struct fpreg' in <machine/reg.h>. GNU/Linux
+ has the same structures as SunOS 4, but they're in <asm/reg.h>,
+ which is a kernel header. As a general rule we avoid including
+ GNU/Linux kernel headers. Fortunately GNU/Linux has a `gregset_t'
+ and a `fpregset_t' that are equivalent to `struct regs' and `struct
+ fp_status' in <sys/ucontext.h>, which is automatically included by
+ <signal.h>. Settling on using the `gregset_t' and `fpregset_t'
+ typedefs, providing them for the other systems, therefore solves
+ the puzzle. */
+
+#ifdef HAVE_MACHINE_REG_H
+#ifdef HAVE_STRUCT_REG
+typedef struct reg gregset_t;
+typedef struct fpreg fpregset_t;
+#else
+typedef struct regs gregset_t;
+typedef struct fp_status fpregset_t;
+#endif
+#endif
+
+/* Second, we need to remap the BSD ptrace(2) requests to their SunOS
+ equivalents. GNU/Linux already follows SunOS here. */
+
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS PT_GETREGS
+#endif
+
+#ifndef PTRACE_SETREGS
+#define PTRACE_SETREGS PT_SETREGS
+#endif
+
+#ifndef PTRACE_GETFPREGS
+#define PTRACE_GETFPREGS PT_GETFPREGS
+#endif
+
+#ifndef PTRACE_SETFPREGS
+#define PTRACE_SETFPREGS PT_SETFPREGS
+#endif
+
+/* Register set description. */
+const struct sparc_gregset *sparc_gregset;
+void (*sparc_supply_gregset) (const struct sparc_gregset *,
+ struct regcache *, int , const void *);
+void (*sparc_collect_gregset) (const struct sparc_gregset *,
+ const struct regcache *, int, void *);
+void (*sparc_supply_fpregset) (struct regcache *, int , const void *);
+void (*sparc_collect_fpregset) (const struct regcache *, int , void *);
+int (*sparc_gregset_supplies_p) (int);
+int (*sparc_fpregset_supplies_p) (int);
+
+/* Determine whether `gregset_t' contains register REGNUM. */
+
+int
+sparc32_gregset_supplies_p (int regnum)
+{
+ /* Integer registers. */
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
+ || (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+ || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
+ || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM))
+ return 1;
+
+ /* Control registers. */
+ if (regnum == SPARC32_PC_REGNUM
+ || regnum == SPARC32_NPC_REGNUM
+ || regnum == SPARC32_PSR_REGNUM
+ || regnum == SPARC32_Y_REGNUM)
+ return 1;
+
+ return 0;
+}
+
+/* Determine whether `fpregset_t' contains register REGNUM. */
+
+int
+sparc32_fpregset_supplies_p (int regnum)
+{
+ /* Floating-point registers. */
+ if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
+ return 1;
+
+ /* Control registers. */
+ if (regnum == SPARC32_FSR_REGNUM)
+ return 1;
+
+ return 0;
+}
+
+/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
+ for all registers (including the floating-point registers). */
+
+void
+fetch_inferior_registers (int regnum)
+{
+ struct regcache *regcache = current_regcache;
+ int pid;
+
+ /* NOTE: cagney/2002-12-03: This code assumes that the currently
+ selected light weight processes' registers can be written
+ directly into the selected thread's register cache. This works
+ fine when given an 1:1 LWP:thread model (such as found on
+ GNU/Linux) but will, likely, have problems when used on an N:1
+ (userland threads) or N:M (userland multiple LWP) model. In the
+ case of the latter two, the LWP's registers do not necessarily
+ belong to the selected thread (the LWP could be in the middle of
+ executing the thread switch code).
+
+ These functions should instead be paramaterized with an explicit
+ object (struct regcache, struct thread_info?) into which the LWPs
+ registers can be written. */
+ pid = TIDGET (inferior_ptid);
+ if (pid == 0)
+ pid = PIDGET (inferior_ptid);
+
+ if (regnum == SPARC_G0_REGNUM)
+ {
+ regcache_raw_supply (regcache, SPARC_G0_REGNUM, NULL);
+ return;
+ }
+
+ if (regnum == -1 || sparc_gregset_supplies_p (regnum))
+ {
+ gregset_t regs;
+
+ if (ptrace (PTRACE_GETREGS, pid, (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ sparc_supply_gregset (sparc_gregset, regcache, -1, &regs);
+ if (regnum != -1)
+ return;
+ }
+
+ if (regnum == -1 || sparc_fpregset_supplies_p (regnum))
+ {
+ fpregset_t fpregs;
+
+ if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ sparc_supply_fpregset (regcache, -1, &fpregs);
+ }
+}
+
+void
+store_inferior_registers (int regnum)
+{
+ struct regcache *regcache = current_regcache;
+ int pid;
+
+ /* NOTE: cagney/2002-12-02: See comment in fetch_inferior_registers
+ about threaded assumptions. */
+ pid = TIDGET (inferior_ptid);
+ if (pid == 0)
+ pid = PIDGET (inferior_ptid);
+
+ if (regnum == -1 || sparc_gregset_supplies_p (regnum))
+ {
+ gregset_t regs;
+
+ if (ptrace (PTRACE_GETREGS, pid, (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ sparc_collect_gregset (sparc_gregset, regcache, regnum, &regs);
+
+ if (ptrace (PTRACE_SETREGS, pid, (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ /* Deal with the stack regs. */
+ if (regnum == -1 || regnum == SPARC_SP_REGNUM
+ || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM))
+ {
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ sparc_collect_rwindow (regcache, sp, regnum);
+ }
+
+ if (regnum != -1)
+ return;
+ }
+
+ if (regnum == -1 || sparc_fpregset_supplies_p (regnum))
+ {
+ fpregset_t fpregs, saved_fpregs;
+
+ if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating-point registers");
+
+ memcpy (&saved_fpregs, &fpregs, sizeof (fpregs));
+ sparc_collect_fpregset (regcache, regnum, &fpregs);
+
+ /* Writing the floating-point registers will fail on NetBSD with
+ EINVAL if the inferior process doesn't have an FPU state
+ (i.e. if it didn't use the FPU yet). Therefore we don't try
+ to write the registers if nothing changed. */
+ if (memcmp (&saved_fpregs, &fpregs, sizeof (fpregs)) != 0)
+ {
+ if (ptrace (PTRACE_SETFPREGS, pid,
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't write floating-point registers");
+ }
+
+ if (regnum != -1)
+ return;
+ }
+}
+
+
+/* Fetch StackGhost Per-Process XOR cookie. */
+
+LONGEST
+sparc_xfer_wcookie (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ unsigned long wcookie = 0;
+ char *buf = (char *)&wcookie;
+
+ gdb_assert (object == TARGET_OBJECT_WCOOKIE);
+ gdb_assert (readbuf && writebuf == NULL);
+
+ if (offset >= sizeof (unsigned long))
+ return -1;
+
+#ifdef PT_WCOOKIE
+ /* If PT_WCOOKIE is defined (by <sys/ptrace.h>), assume we're
+ running on an OpenBSD release that uses StackGhost (3.1 or
+ later). As of release 3.4, OpenBSD doesn't use a randomized
+ cookie yet, but a future release probably will. */
+ {
+ int pid;
+
+ pid = TIDGET (inferior_ptid);
+ if (pid == 0)
+ pid = PIDGET (inferior_ptid);
+
+ /* Sanity check. The proper type for a cookie is register_t, but
+ we can't assume that this type exists on all systems supported
+ by the code in this file. */
+ gdb_assert (sizeof (wcookie) == sizeof (register_t));
+
+ /* Fetch the cookie. */
+ if (ptrace (PT_WCOOKIE, pid, (PTRACE_ARG3_TYPE) &wcookie, 0) == -1)
+ {
+ if (errno != EINVAL)
+ perror_with_name ("Couldn't get StackGhost cookie");
+
+ /* Although PT_WCOOKIE is defined on OpenBSD 3.1 and later,
+ the request wasn't implemented until after OpenBSD 3.4. If
+ the kernel doesn't support the PT_WCOOKIE request, assume
+ we're running on a kernel that uses non-randomized cookies. */
+ wcookie = 0x3;
+ }
+ }
+#endif /* PT_WCOOKIE */
+
+ if (len > sizeof (unsigned long) - offset)
+ len = sizeof (unsigned long) - offset;
+
+ memcpy (readbuf, buf + offset, len);
+ return len;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc_nat (void);
+
+void
+_initialize_sparc_nat (void)
+{
+ /* Deafult to using SunOS 4 register sets. */
+ if (sparc_gregset == NULL)
+ sparc_gregset = &sparc32_sunos4_gregset;
+ if (sparc_supply_gregset == NULL)
+ sparc_supply_gregset = sparc32_supply_gregset;
+ if (sparc_collect_gregset == NULL)
+ sparc_collect_gregset = sparc32_collect_gregset;
+ if (sparc_supply_fpregset == NULL)
+ sparc_supply_fpregset = sparc32_supply_fpregset;
+ if (sparc_collect_fpregset == NULL)
+ sparc_collect_fpregset = sparc32_collect_fpregset;
+ if (sparc_gregset_supplies_p == NULL)
+ sparc_gregset_supplies_p = sparc32_gregset_supplies_p;
+ if (sparc_fpregset_supplies_p == NULL)
+ sparc_fpregset_supplies_p = sparc32_fpregset_supplies_p;
+}
diff --git a/contrib/gdb/gdb/sparc-nat.h b/contrib/gdb/gdb/sparc-nat.h
new file mode 100644
index 0000000..8f99b1e
--- /dev/null
+++ b/contrib/gdb/gdb/sparc-nat.h
@@ -0,0 +1,40 @@
+/* Native-dependent code for SPARC.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SPARC_NAT_H
+#define SPARC_NAT_H 1
+
+struct sparc_gregset;
+
+extern const struct sparc_gregset *sparc_gregset;
+extern void (*sparc_supply_gregset) (const struct sparc_gregset *,
+ struct regcache *, int , const void *);
+extern void (*sparc_collect_gregset) (const struct sparc_gregset *,
+ const struct regcache *, int, void *);
+extern void (*sparc_supply_fpregset) (struct regcache *, int , const void *);
+extern void (*sparc_collect_fpregset) (const struct regcache *, int , void *);
+extern int (*sparc_gregset_supplies_p) (int);
+extern int (*sparc_fpregset_supplies_p) (int);
+
+extern int sparc32_gregset_supplies_p (int regnum);
+extern int sparc32_fpregset_supplies_p (int regnum);
+
+#endif /* sparc-nat.h */
diff --git a/contrib/gdb/gdb/sparc-sol2-nat.c b/contrib/gdb/gdb/sparc-sol2-nat.c
new file mode 100644
index 0000000..61ca712
--- /dev/null
+++ b/contrib/gdb/gdb/sparc-sol2-nat.c
@@ -0,0 +1,98 @@
+/* Native-dependent code for Solaris SPARC.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include <sys/procfs.h>
+#include "gregset.h"
+
+#include "sparc-tdep.h"
+
+/* This file provids the (temporary) glue between the Solaris SPARC
+ target dependent code and the machine independent SVR4 /proc
+ support. */
+
+/* Solaris 7 (Solaris 2.7, SunOS 5.7) and up support two process data
+ models, the traditional 32-bit data model (ILP32) and the 64-bit
+ data model (LP64). The format of /proc depends on the data model
+ of the observer (the controlling process, GDB in our case). The
+ Solaris header files conveniently define PR_MODEL_NATIVE to the
+ data model of the controlling process. If its value is
+ PR_MODEL_LP64, we know that GDB is being compiled as a 64-bit
+ program.
+
+ GNU/Linux uses the same formats as Solaris for its core files (but
+ not for ptrace(2)). The GNU/Linux headers don't define
+ PR_MODEL_NATIVE though. Therefore we rely on the __arch64__ define
+ provided by GCC to determine the appropriate data model.
+
+ Note that a 32-bit GDB won't be able to debug a 64-bit target
+ process using /proc on Solaris. */
+
+#if (defined (__arch64__) || \
+ (defined (PR_MODEL_NATIVE) && (PR_MODEL_NATIVE == PR_MODEL_LP64)))
+
+#include "sparc64-tdep.h"
+
+#define sparc_supply_gregset sparc64_supply_gregset
+#define sparc_supply_fpregset sparc64_supply_fpregset
+#define sparc_collect_gregset sparc64_collect_gregset
+#define sparc_collect_fpregset sparc64_collect_fpregset
+
+#define sparc_sol2_gregset sparc64_sol2_gregset
+#define sparc_sol2_fpregset sparc64_sol2_fpregset
+
+#else
+
+#define sparc_supply_gregset sparc32_supply_gregset
+#define sparc_supply_fpregset sparc32_supply_fpregset
+#define sparc_collect_gregset sparc32_collect_gregset
+#define sparc_collect_fpregset sparc32_collect_fpregset
+
+#define sparc_sol2_gregset sparc32_sol2_gregset
+#define sparc_sol2_fpregset sparc32_sol2_fpregset
+
+#endif
+
+void
+supply_gregset (prgregset_t *gregs)
+{
+ sparc_supply_gregset (&sparc_sol2_gregset, current_regcache, -1, gregs);
+}
+
+void
+supply_fpregset (prfpregset_t *fpregs)
+{
+ sparc_supply_fpregset (current_regcache, -1, fpregs);
+}
+
+void
+fill_gregset (prgregset_t *gregs, int regnum)
+{
+ sparc_collect_gregset (&sparc_sol2_gregset, current_regcache, regnum, gregs);
+}
+
+void
+fill_fpregset (prfpregset_t *fpregs, int regnum)
+{
+ sparc_collect_fpregset (current_regcache, regnum, fpregs);
+}
diff --git a/contrib/gdb/gdb/sparc-sol2-tdep.c b/contrib/gdb/gdb/sparc-sol2-tdep.c
new file mode 100644
index 0000000..5f65b78
--- /dev/null
+++ b/contrib/gdb/gdb/sparc-sol2-tdep.c
@@ -0,0 +1,201 @@
+/* Target-dependent code for Solaris SPARC.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame-unwind.h"
+#include "gdbcore.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "target.h"
+#include "trad-frame.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "sparc-tdep.h"
+
+/* From <sys/regset.h>. */
+const struct sparc_gregset sparc32_sol2_gregset =
+{
+ 32 * 4, /* %psr */
+ 33 * 4, /* %pc */
+ 34 * 4, /* %npc */
+ 35 * 4, /* %y */
+ 36 * 4, /* %wim */
+ 37 * 4, /* %tbr */
+ 1 * 4, /* %g1 */
+ 16 * 4, /* %l0 */
+};
+
+
+/* The Solaris signal trampolines reside in libc. For normal signals,
+ the function `sigacthandler' is used. This signal trampoline will
+ call the signal handler using the System V calling convention,
+ where the third argument is a pointer to an instance of
+ `ucontext_t', which has a member `uc_mcontext' that contains the
+ saved registers. Incidentally, the kernel passes the `ucontext_t'
+ pointer as the third argument of the signal trampoline too, and
+ `sigacthandler' simply passes it on. However, if you link your
+ program with "-L/usr/ucblib -R/usr/ucblib -lucb", the function
+ `ucbsigvechandler' will be used, which invokes the using the BSD
+ convention, where the third argument is a pointer to an instance of
+ `struct sigcontext'. It is the `ucbsigvechandler' function that
+ converts the `ucontext_t' to a `sigcontext', and back. Unless the
+ signal handler modifies the `struct sigcontext' we can safely
+ ignore this. */
+
+int
+sparc_sol2_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ return (name && (strcmp (name, "sigacthandler") == 0
+ || strcmp (name, "ucbsigvechandler") == 0));
+}
+
+static struct sparc_frame_cache *
+sparc32_sol2_sigtramp_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR mcontext_addr, addr;
+ int regnum;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* The third argument is a pointer to an instance of `ucontext_t',
+ which has a member `uc_mcontext' that contains the saved
+ registers. */
+ regnum = (cache->frameless_p ? SPARC_O2_REGNUM : SPARC_I2_REGNUM);
+ mcontext_addr = frame_unwind_register_unsigned (next_frame, regnum) + 40;
+
+ cache->saved_regs[SPARC32_PSR_REGNUM].addr = mcontext_addr + 0 * 4;
+ cache->saved_regs[SPARC32_PC_REGNUM].addr = mcontext_addr + 1 * 4;
+ cache->saved_regs[SPARC32_NPC_REGNUM].addr = mcontext_addr + 2 * 4;
+ cache->saved_regs[SPARC32_Y_REGNUM].addr = mcontext_addr + 3 * 4;
+
+ /* Since %g0 is always zero, keep the identity encoding. */
+ for (regnum = SPARC_G1_REGNUM, addr = mcontext_addr + 4 * 4;
+ regnum <= SPARC_O7_REGNUM; regnum++, addr += 4)
+ cache->saved_regs[regnum].addr = addr;
+
+ if (get_frame_memory_unsigned (next_frame, mcontext_addr + 19 * 4, 4))
+ {
+ /* The register windows haven't been flushed. */
+ for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
+ trad_frame_set_unknown (cache->saved_regs, regnum);
+ }
+ else
+ {
+ addr = cache->saved_regs[SPARC_SP_REGNUM].addr;
+ addr = get_frame_memory_unsigned (next_frame, addr, 4);
+ for (regnum = SPARC_L0_REGNUM;
+ regnum <= SPARC_I7_REGNUM; regnum++, addr += 4)
+ cache->saved_regs[regnum].addr = addr;
+ }
+
+ return cache;
+}
+
+static void
+sparc32_sol2_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc32_sol2_sigtramp_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc32_sol2_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc32_sol2_sigtramp_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc32_sol2_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ sparc32_sol2_sigtramp_frame_this_id,
+ sparc32_sol2_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc32_sol2_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (sparc_sol2_pc_in_sigtramp (pc, name))
+ return &sparc32_sol2_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+
+void
+sparc32_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Solaris has SVR4-style shared libraries... */
+ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+ /* ...which means that we need some special handling when doing
+ prologue analysis. */
+ tdep->plt_entry_size = 12;
+
+ /* Solaris has kernel-assisted single-stepping support. */
+ set_gdbarch_software_single_step (gdbarch, NULL);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, sparc_sol2_pc_in_sigtramp);
+ frame_unwind_append_sniffer (gdbarch, sparc32_sol2_sigtramp_frame_sniffer);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc_sol2_tdep (void);
+
+void
+_initialize_sparc_sol2_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_sparc, 0,
+ GDB_OSABI_SOLARIS, sparc32_sol2_init_abi);
+}
diff --git a/contrib/gdb/gdb/sparc-stub.c b/contrib/gdb/gdb/sparc-stub.c
new file mode 100644
index 0000000..1e6298a
--- /dev/null
+++ b/contrib/gdb/gdb/sparc-stub.c
@@ -0,0 +1,778 @@
+/****************************************************************************
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ HP offers the following for use in the public domain. HP makes no
+ warranty with regard to the software or it's performance and the
+ user accepts the software "AS IS" with all faults.
+
+ HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+ TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ * Module name: remcom.c $
+ * Revision: 1.34 $
+ * Date: 91/03/09 12:29:49 $
+ * Contributor: Lake Stevens Instrument Division$
+ *
+ * Description: low level support for gdb debugger. $
+ *
+ * Considerations: only works on target hardware $
+ *
+ * Written by: Glenn Engel $
+ * ModuleState: Experimental $
+ *
+ * NOTES: See Below $
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ * This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * 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 <string.h>
+#include <signal.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+
+extern void putDebugChar(); /* write a single character */
+extern int getDebugChar(); /* read and return a single char */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+#define BUFMAX 2048
+
+static int initialized = 0; /* !0 means we've been initialized */
+
+static void set_mem_fault_trap();
+
+static const char hexchars[]="0123456789abcdef";
+
+#define NUMREGS 72
+
+/* Number of bytes of registers. */
+#define NUMREGBYTES (NUMREGS * 4)
+enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
+ O0, O1, O2, O3, O4, O5, SP, O7,
+ L0, L1, L2, L3, L4, L5, L6, L7,
+ I0, I1, I2, I3, I4, I5, FP, I7,
+
+ F0, F1, F2, F3, F4, F5, F6, F7,
+ F8, F9, F10, F11, F12, F13, F14, F15,
+ F16, F17, F18, F19, F20, F21, F22, F23,
+ F24, F25, F26, F27, F28, F29, F30, F31,
+ Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
+
+/*************************** ASSEMBLY CODE MACROS *************************/
+/* */
+
+extern void trap_low();
+
+asm("
+ .reserve trapstack, 1000 * 4, \"bss\", 8
+
+ .data
+ .align 4
+
+in_trap_handler:
+ .word 0
+
+ .text
+ .align 4
+
+! This function is called when any SPARC trap (except window overflow or
+! underflow) occurs. It makes sure that the invalid register window is still
+! available before jumping into C code. It will also restore the world if you
+! return from handle_exception.
+
+ .globl _trap_low
+_trap_low:
+ mov %psr, %l0
+ mov %wim, %l3
+
+ srl %l3, %l0, %l4 ! wim >> cwp
+ cmp %l4, 1
+ bne window_fine ! Branch if not in the invalid window
+ nop
+
+! Handle window overflow
+
+ mov %g1, %l4 ! Save g1, we use it to hold the wim
+ srl %l3, 1, %g1 ! Rotate wim right
+ tst %g1
+ bg good_wim ! Branch if new wim is non-zero
+ nop
+
+! At this point, we need to bring a 1 into the high order bit of the wim.
+! Since we don't want to make any assumptions about the number of register
+! windows, we figure it out dynamically so as to setup the wim correctly.
+
+ not %g1 ! Fill g1 with ones
+ mov %g1, %wim ! Fill the wim with ones
+ nop
+ nop
+ nop
+ mov %wim, %g1 ! Read back the wim
+ inc %g1 ! Now g1 has 1 just to left of wim
+ srl %g1, 1, %g1 ! Now put 1 at top of wim
+ mov %g0, %wim ! Clear wim so that subsequent save
+ nop ! won't trap
+ nop
+ nop
+
+good_wim:
+ save %g0, %g0, %g0 ! Slip into next window
+ mov %g1, %wim ! Install the new wim
+
+ std %l0, [%sp + 0 * 4] ! save L & I registers
+ std %l2, [%sp + 2 * 4]
+ std %l4, [%sp + 4 * 4]
+ std %l6, [%sp + 6 * 4]
+
+ std %i0, [%sp + 8 * 4]
+ std %i2, [%sp + 10 * 4]
+ std %i4, [%sp + 12 * 4]
+ std %i6, [%sp + 14 * 4]
+
+ restore ! Go back to trap window.
+ mov %l4, %g1 ! Restore %g1
+
+window_fine:
+ sethi %hi(in_trap_handler), %l4
+ ld [%lo(in_trap_handler) + %l4], %l5
+ tst %l5
+ bg recursive_trap
+ inc %l5
+
+ set trapstack+1000*4, %sp ! Switch to trap stack
+
+recursive_trap:
+ st %l5, [%lo(in_trap_handler) + %l4]
+ sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
+ ! + hidden arg + arg spill
+ ! + doubleword alignment
+ ! + registers[72] local var
+
+ std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
+ std %g2, [%sp + (24 + 2) * 4]
+ std %g4, [%sp + (24 + 4) * 4]
+ std %g6, [%sp + (24 + 6) * 4]
+
+ std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
+ std %i2, [%sp + (24 + 10) * 4]
+ std %i4, [%sp + (24 + 12) * 4]
+ std %i6, [%sp + (24 + 14) * 4]
+ ! F0->F31 not implemented
+ mov %y, %l4
+ mov %tbr, %l5
+ st %l4, [%sp + (24 + 64) * 4] ! Y
+ st %l0, [%sp + (24 + 65) * 4] ! PSR
+ st %l3, [%sp + (24 + 66) * 4] ! WIM
+ st %l5, [%sp + (24 + 67) * 4] ! TBR
+ st %l1, [%sp + (24 + 68) * 4] ! PC
+ st %l2, [%sp + (24 + 69) * 4] ! NPC
+
+ ! CPSR and FPSR not impl
+
+ or %l0, 0xf20, %l4
+ mov %l4, %psr ! Turn on traps, disable interrupts
+
+ call _handle_exception
+ add %sp, 24 * 4, %o0 ! Pass address of registers
+
+! Reload all of the registers that aren't on the stack
+
+ ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
+ ldd [%sp + (24 + 2) * 4], %g2
+ ldd [%sp + (24 + 4) * 4], %g4
+ ldd [%sp + (24 + 6) * 4], %g6
+
+ ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
+ ldd [%sp + (24 + 10) * 4], %i2
+ ldd [%sp + (24 + 12) * 4], %i4
+ ldd [%sp + (24 + 14) * 4], %i6
+
+ ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
+ ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
+
+ restore ! Ensure that previous window is valid
+ save %g0, %g0, %g0 ! by causing a window_underflow trap
+
+ mov %l0, %y
+ mov %l1, %psr ! Make sure that traps are disabled
+ ! for rett
+
+ sethi %hi(in_trap_handler), %l4
+ ld [%lo(in_trap_handler) + %l4], %l5
+ dec %l5
+ st %l5, [%lo(in_trap_handler) + %l4]
+
+ jmpl %l2, %g0 ! Restore old PC
+ rett %l3 ! Restore old nPC
+");
+
+/* Convert ch from a hex digit to an int */
+
+static int
+hex (unsigned char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch-'a'+10;
+ if (ch >= '0' && ch <= '9')
+ return ch-'0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch-'A'+10;
+ return -1;
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+/* scan for the sequence $<data>#<checksum> */
+
+unsigned char *
+getpacket (void)
+{
+ unsigned char *buffer = &remcomInBuffer[0];
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int count;
+ char ch;
+
+ while (1)
+ {
+ /* wait around for the start character, ignore all other characters */
+ while ((ch = getDebugChar ()) != '$')
+ ;
+
+retry:
+ checksum = 0;
+ xmitcsum = -1;
+ count = 0;
+
+ /* now, read until a # or end of buffer is found */
+ while (count < BUFMAX)
+ {
+ ch = getDebugChar ();
+ if (ch == '$')
+ goto retry;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+ buffer[count] = 0;
+
+ if (ch == '#')
+ {
+ ch = getDebugChar ();
+ xmitcsum = hex (ch) << 4;
+ ch = getDebugChar ();
+ xmitcsum += hex (ch);
+
+ if (checksum != xmitcsum)
+ {
+ putDebugChar ('-'); /* failed checksum */
+ }
+ else
+ {
+ putDebugChar ('+'); /* successful transfer */
+
+ /* if a sequence char is present, reply the sequence ID */
+ if (buffer[2] == ':')
+ {
+ putDebugChar (buffer[0]);
+ putDebugChar (buffer[1]);
+
+ return &buffer[3];
+ }
+
+ return &buffer[0];
+ }
+ }
+ }
+}
+
+/* send the packet in buffer. */
+
+static void
+putpacket (unsigned char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch;
+
+ /* $<packet info>#<checksum>. */
+ do
+ {
+ putDebugChar('$');
+ checksum = 0;
+ count = 0;
+
+ while (ch = buffer[count])
+ {
+ putDebugChar(ch);
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar('#');
+ putDebugChar(hexchars[checksum >> 4]);
+ putDebugChar(hexchars[checksum & 0xf]);
+
+ }
+ while (getDebugChar() != '+');
+}
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+ error. */
+static volatile int mem_err = 0;
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ * If MAY_FAULT is non-zero, then we will handle memory faults by returning
+ * a 0, else treat a fault like any other fault in the stub.
+ */
+
+static unsigned char *
+mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
+{
+ unsigned char ch;
+
+ set_mem_fault_trap(may_fault);
+
+ while (count-- > 0)
+ {
+ ch = *mem++;
+ if (mem_err)
+ return 0;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+
+ *buf = 0;
+
+ set_mem_fault_trap(0);
+
+ return buf;
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written */
+
+static char *
+hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
+{
+ int i;
+ unsigned char ch;
+
+ set_mem_fault_trap(may_fault);
+
+ for (i=0; i<count; i++)
+ {
+ ch = hex(*buf++) << 4;
+ ch |= hex(*buf++);
+ *mem++ = ch;
+ if (mem_err)
+ return 0;
+ }
+
+ set_mem_fault_trap(0);
+
+ return mem;
+}
+
+/* This table contains the mapping between SPARC hardware trap types, and
+ signals, which are primarily what GDB understands. It also indicates
+ which hardware traps we need to commandeer when initializing the stub. */
+
+static struct hard_trap_info
+{
+ unsigned char tt; /* Trap type code for SPARClite */
+ unsigned char signo; /* Signal that we map this trap into */
+} hard_trap_info[] = {
+ {1, SIGSEGV}, /* instruction access error */
+ {2, SIGILL}, /* privileged instruction */
+ {3, SIGILL}, /* illegal instruction */
+ {4, SIGEMT}, /* fp disabled */
+ {36, SIGEMT}, /* cp disabled */
+ {7, SIGBUS}, /* mem address not aligned */
+ {9, SIGSEGV}, /* data access exception */
+ {10, SIGEMT}, /* tag overflow */
+ {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
+ {0, 0} /* Must be last */
+};
+
+/* Set up exception handlers for tracing and breakpoints */
+
+void
+set_debug_traps (void)
+{
+ struct hard_trap_info *ht;
+
+ for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+ exceptionHandler(ht->tt, trap_low);
+
+ initialized = 1;
+}
+
+asm ("
+! Trap handler for memory errors. This just sets mem_err to be non-zero. It
+! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
+! 0 would ever contain code that could mem fault. This routine will skip
+! past the faulting instruction after setting mem_err.
+
+ .text
+ .align 4
+
+_fltr_set_mem_err:
+ sethi %hi(_mem_err), %l0
+ st %l1, [%l0 + %lo(_mem_err)]
+ jmpl %l2, %g0
+ rett %l2+4
+");
+
+static void
+set_mem_fault_trap (int enable)
+{
+ extern void fltr_set_mem_err();
+ mem_err = 0;
+
+ if (enable)
+ exceptionHandler(9, fltr_set_mem_err);
+ else
+ exceptionHandler(9, trap_low);
+}
+
+/* Convert the SPARC hardware trap type code to a unix signal number. */
+
+static int
+computeSignal (int tt)
+{
+ struct hard_trap_info *ht;
+
+ for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+ if (ht->tt == tt)
+ return ht->signo;
+
+ return SIGHUP; /* default for things we don't know about */
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+
+static int
+hexToInt(char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ while (**ptr)
+ {
+ hexValue = hex(**ptr);
+ if (hexValue < 0)
+ break;
+
+ *intValue = (*intValue << 4) | hexValue;
+ numChars ++;
+
+ (*ptr)++;
+ }
+
+ return (numChars);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb. It
+ * returns 1 if you should skip the instruction at the trap address, 0
+ * otherwise.
+ */
+
+extern void breakinst();
+
+static void
+handle_exception (unsigned long *registers)
+{
+ int tt; /* Trap type */
+ int sigval;
+ int addr;
+ int length;
+ char *ptr;
+ unsigned long *sp;
+
+/* First, we must force all of the windows to be spilled out */
+
+ asm(" save %sp, -64, %sp
+ save %sp, -64, %sp
+ save %sp, -64, %sp
+ save %sp, -64, %sp
+ save %sp, -64, %sp
+ save %sp, -64, %sp
+ save %sp, -64, %sp
+ save %sp, -64, %sp
+ restore
+ restore
+ restore
+ restore
+ restore
+ restore
+ restore
+ restore
+");
+
+ if (registers[PC] == (unsigned long)breakinst)
+ {
+ registers[PC] = registers[NPC];
+ registers[NPC] += 4;
+ }
+
+ sp = (unsigned long *)registers[SP];
+
+ tt = (registers[TBR] >> 4) & 0xff;
+
+ /* reply to host that an exception has occurred */
+ sigval = computeSignal(tt);
+ ptr = remcomOutBuffer;
+
+ *ptr++ = 'T';
+ *ptr++ = hexchars[sigval >> 4];
+ *ptr++ = hexchars[sigval & 0xf];
+
+ *ptr++ = hexchars[PC >> 4];
+ *ptr++ = hexchars[PC & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[FP >> 4];
+ *ptr++ = hexchars[FP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[SP >> 4];
+ *ptr++ = hexchars[SP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&sp, ptr, 4, 0);
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[NPC >> 4];
+ *ptr++ = hexchars[NPC & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[O7 >> 4];
+ *ptr++ = hexchars[O7 & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
+ *ptr++ = ';';
+
+ *ptr++ = 0;
+
+ putpacket(remcomOutBuffer);
+
+ while (1)
+ {
+ remcomOutBuffer[0] = 0;
+
+ ptr = getpacket();
+ switch (*ptr++)
+ {
+ case '?':
+ remcomOutBuffer[0] = 'S';
+ remcomOutBuffer[1] = hexchars[sigval >> 4];
+ remcomOutBuffer[2] = hexchars[sigval & 0xf];
+ remcomOutBuffer[3] = 0;
+ break;
+
+ case 'd': /* toggle debug flag */
+ break;
+
+ case 'g': /* return the value of the CPU registers */
+ {
+ ptr = remcomOutBuffer;
+ ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
+ ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
+ memset(ptr, '0', 32 * 8); /* Floating point */
+ mem2hex((char *)&registers[Y],
+ ptr + 32 * 4 * 2,
+ 8 * 4,
+ 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+ }
+ break;
+
+ case 'G': /* set the value of the CPU registers - return OK */
+ {
+ unsigned long *newsp, psr;
+
+ psr = registers[PSR];
+
+ hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
+ hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
+ hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
+ 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+
+ /* See if the stack pointer has moved. If so, then copy the saved
+ locals and ins to the new location. This keeps the window
+ overflow and underflow routines happy. */
+
+ newsp = (unsigned long *)registers[SP];
+ if (sp != newsp)
+ sp = memcpy(newsp, sp, 16 * 4);
+
+ /* Don't allow CWP to be modified. */
+
+ if (psr != registers[PSR])
+ registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
+
+ strcpy(remcomOutBuffer,"OK");
+ }
+ break;
+
+ case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
+ /* Try to read %x,%x. */
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length))
+ {
+ if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
+ break;
+
+ strcpy (remcomOutBuffer, "E03");
+ }
+ else
+ strcpy(remcomOutBuffer,"E01");
+ break;
+
+ case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+ /* Try to read '%x,%x:'. */
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':')
+ {
+ if (hex2mem(ptr, (char *)addr, length, 1))
+ strcpy(remcomOutBuffer, "OK");
+ else
+ strcpy(remcomOutBuffer, "E03");
+ }
+ else
+ strcpy(remcomOutBuffer, "E02");
+ break;
+
+ case 'c': /* cAA..AA Continue at address AA..AA(optional) */
+ /* try to read optional parameter, pc unchanged if no parm */
+
+ if (hexToInt(&ptr, &addr))
+ {
+ registers[PC] = addr;
+ registers[NPC] = addr + 4;
+ }
+
+/* Need to flush the instruction cache here, as we may have deposited a
+ breakpoint, and the icache probably has no way of knowing that a data ref to
+ some location may have changed something that is in the instruction cache.
+ */
+
+ flush_i_cache();
+ return;
+
+ /* kill the program */
+ case 'k' : /* do nothing */
+ break;
+#if 0
+ case 't': /* Test feature */
+ asm (" std %f30,[%sp]");
+ break;
+#endif
+ case 'r': /* Reset */
+ asm ("call 0
+ nop ");
+ break;
+ } /* switch */
+
+ /* reply to the request */
+ putpacket(remcomOutBuffer);
+ }
+}
+
+/* This function will generate a breakpoint exception. It is used at the
+ beginning of a program to sync up with a debugger and can be used
+ otherwise as a quick means to stop program execution and "break" into
+ the debugger. */
+
+void
+breakpoint (void)
+{
+ if (!initialized)
+ return;
+
+ asm(" .globl _breakinst
+
+ _breakinst: ta 1
+ ");
+}
diff --git a/contrib/gdb/gdb/sparc-tdep.c b/contrib/gdb/gdb/sparc-tdep.c
new file mode 100644
index 0000000..ac8eb48
--- /dev/null
+++ b/contrib/gdb/gdb/sparc-tdep.c
@@ -0,0 +1,1488 @@
+/* Target-dependent code for SPARC.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "dis-asm.h"
+#include "floatformat.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "gdbcore.h"
+#include "gdbtypes.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "target.h"
+#include "value.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "sparc-tdep.h"
+
+struct regset;
+
+/* This file implements the The SPARC 32-bit ABI as defined by the
+ section "Low-Level System Information" of the SPARC Compliance
+ Definition (SCD) 2.4.1, which is the 32-bit System V psABI for
+ SPARC. The SCD lists changes with respect to the origional 32-bit
+ psABI as defined in the "System V ABI, SPARC Processor
+ Supplement".
+
+ Note that if we talk about SunOS, we mean SunOS 4.x, which was
+ BSD-based, which is sometimes (retroactively?) referred to as
+ Solaris 1.x. If we talk about Solaris we mean Solaris 2.x and
+ above (Solaris 7, 8 and 9 are nothing but Solaris 2.7, 2.8 and 2.9
+ suffering from severe version number inflation). Solaris 2.x is
+ also known as SunOS 5.x, since that's what uname(1) says. Solaris
+ 2.x is SVR4-based. */
+
+/* Please use the sparc32_-prefix for 32-bit specific code, the
+ sparc64_-prefix for 64-bit specific code and the sparc_-prefix for
+ code that can handle both. The 64-bit specific code lives in
+ sparc64-tdep.c; don't add any here. */
+
+/* The SPARC Floating-Point Quad-Precision format is similar to
+ big-endian IA-64 Quad-recision format. */
+#define floatformat_sparc_quad floatformat_ia64_quad_big
+
+/* The stack pointer is offset from the stack frame by a BIAS of 2047
+ (0x7ff) for 64-bit code. BIAS is likely to be defined on SPARC
+ hosts, so undefine it first. */
+#undef BIAS
+#define BIAS 2047
+
+/* Macros to extract fields from SPARC instructions. */
+#define X_OP(i) (((i) >> 30) & 0x3)
+#define X_RD(i) (((i) >> 25) & 0x1f)
+#define X_A(i) (((i) >> 29) & 1)
+#define X_COND(i) (((i) >> 25) & 0xf)
+#define X_OP2(i) (((i) >> 22) & 0x7)
+#define X_IMM22(i) ((i) & 0x3fffff)
+#define X_OP3(i) (((i) >> 19) & 0x3f)
+#define X_I(i) (((i) >> 13) & 1)
+/* Sign extension macros. */
+#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
+#define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000)
+
+/* Fetch the instruction at PC. Instructions are always big-endian
+ even if the processor operates in little-endian mode. */
+
+unsigned long
+sparc_fetch_instruction (CORE_ADDR pc)
+{
+ unsigned char buf[4];
+ unsigned long insn;
+ int i;
+
+ /* If we can't read the instruction at PC, return zero. */
+ if (target_read_memory (pc, buf, sizeof (buf)))
+ return 0;
+
+ insn = 0;
+ for (i = 0; i < sizeof (buf); i++)
+ insn = (insn << 8) | buf[i];
+ return insn;
+}
+
+
+/* OpenBSD/sparc includes StackGhost, which according to the author's
+ website http://stackghost.cerias.purdue.edu "... transparently and
+ automatically protects applications' stack frames; more
+ specifically, it guards the return pointers. The protection
+ mechanisms require no application source or binary modification and
+ imposes only a negligible performance penalty."
+
+ The same website provides the following description of how
+ StackGhost works:
+
+ "StackGhost interfaces with the kernel trap handler that would
+ normally write out registers to the stack and the handler that
+ would read them back in. By XORing a cookie into the
+ return-address saved in the user stack when it is actually written
+ to the stack, and then XOR it out when the return-address is pulled
+ from the stack, StackGhost can cause attacker corrupted return
+ pointers to behave in a manner the attacker cannot predict.
+ StackGhost can also use several unused bits in the return pointer
+ to detect a smashed return pointer and abort the process."
+
+ For GDB this means that whenever we're reading %i7 from a stack
+ frame's window save area, we'll have to XOR the cookie.
+
+ More information on StackGuard can be found on in:
+
+ Mike Frantzen and Mike Shuey. "StackGhost: Hardware Facilitated
+ Stack Protection." 2001. Published in USENIX Security Symposium
+ '01. */
+
+/* Fetch StackGhost Per-Process XOR cookie. */
+
+ULONGEST
+sparc_fetch_wcookie (void)
+{
+ struct target_ops *ops = &current_target;
+ char buf[8];
+ int len;
+
+ len = target_read_partial (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
+ if (len == -1)
+ return 0;
+
+ /* We should have either an 32-bit or an 64-bit cookie. */
+ gdb_assert (len == 4 || len == 8);
+
+ return extract_unsigned_integer (buf, len);
+}
+
+
+/* Return the contents if register REGNUM as an address. */
+
+static CORE_ADDR
+sparc_address_from_register (int regnum)
+{
+ ULONGEST addr;
+
+ regcache_cooked_read_unsigned (current_regcache, regnum, &addr);
+ return addr;
+}
+
+
+/* The functions on this page are intended to be used to classify
+ function arguments. */
+
+/* Check whether TYPE is "Integral or Pointer". */
+
+static int
+sparc_integral_or_pointer_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_RANGE:
+ {
+ /* We have byte, half-word, word and extended-word/doubleword
+ integral types. The doubleword is an extension to the
+ origional 32-bit ABI by the SCD 2.4.x. */
+ int len = TYPE_LENGTH (type);
+ return (len == 1 || len == 2 || len == 4 || len == 8);
+ }
+ return 1;
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ {
+ /* Allow either 32-bit or 64-bit pointers. */
+ int len = TYPE_LENGTH (type);
+ return (len == 4 || len == 8);
+ }
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Check whether TYPE is "Floating". */
+
+static int
+sparc_floating_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_FLT:
+ {
+ int len = TYPE_LENGTH (type);
+ return (len == 4 || len == 8 || len == 16);
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Check whether TYPE is "Structure or Union". */
+
+static int
+sparc_structure_or_union_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Register information. */
+
+static const char *sparc32_register_names[] =
+{
+ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
+ "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
+ "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
+ "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
+
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+
+ "y", "psr", "wim", "tbr", "pc", "npc", "fsr", "csr"
+};
+
+/* Total number of registers. */
+#define SPARC32_NUM_REGS ARRAY_SIZE (sparc32_register_names)
+
+/* We provide the aliases %d0..%d30 for the floating registers as
+ "psuedo" registers. */
+
+static const char *sparc32_pseudo_register_names[] =
+{
+ "d0", "d2", "d4", "d6", "d8", "d10", "d12", "d14",
+ "d16", "d18", "d20", "d22", "d24", "d26", "d28", "d30"
+};
+
+/* Total number of pseudo registers. */
+#define SPARC32_NUM_PSEUDO_REGS ARRAY_SIZE (sparc32_pseudo_register_names)
+
+/* Return the name of register REGNUM. */
+
+static const char *
+sparc32_register_name (int regnum)
+{
+ if (regnum >= 0 && regnum < SPARC32_NUM_REGS)
+ return sparc32_register_names[regnum];
+
+ if (regnum < SPARC32_NUM_REGS + SPARC32_NUM_PSEUDO_REGS)
+ return sparc32_pseudo_register_names[regnum - SPARC32_NUM_REGS];
+
+ return NULL;
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. */
+
+static struct type *
+sparc32_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
+ return builtin_type_float;
+
+ if (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM)
+ return builtin_type_double;
+
+ if (regnum == SPARC_SP_REGNUM || regnum == SPARC_FP_REGNUM)
+ return builtin_type_void_data_ptr;
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
+ return builtin_type_void_func_ptr;
+
+ return builtin_type_int32;
+}
+
+static void
+sparc32_pseudo_register_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, void *buf)
+{
+ gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM);
+
+ regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_D0_REGNUM);
+ regcache_raw_read (regcache, regnum, buf);
+ regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 4);
+}
+
+static void
+sparc32_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, const void *buf)
+{
+ gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM);
+
+ regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_D0_REGNUM);
+ regcache_raw_write (regcache, regnum, buf);
+ regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 4);
+}
+
+
+static CORE_ADDR
+sparc32_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
+ CORE_ADDR funcaddr, int using_gcc,
+ struct value **args, int nargs,
+ struct type *value_type,
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+{
+ *bp_addr = sp - 4;
+ *real_pc = funcaddr;
+
+ if (using_struct_return (value_type, using_gcc))
+ {
+ char buf[4];
+
+ /* This is an UNIMP instruction. */
+ store_unsigned_integer (buf, 4, TYPE_LENGTH (value_type) & 0x1fff);
+ write_memory (sp - 8, buf, 4);
+ return sp - 8;
+ }
+
+ return sp - 4;
+}
+
+static CORE_ADDR
+sparc32_store_arguments (struct regcache *regcache, int nargs,
+ struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ /* Number of words in the "parameter array". */
+ int num_elements = 0;
+ int element = 0;
+ int i;
+
+ for (i = 0; i < nargs; i++)
+ {
+ struct type *type = VALUE_TYPE (args[i]);
+ int len = TYPE_LENGTH (type);
+
+ if (sparc_structure_or_union_p (type)
+ || (sparc_floating_p (type) && len == 16))
+ {
+ /* Structure, Union and Quad-Precision Arguments. */
+ sp -= len;
+
+ /* Use doubleword alignment for these values. That's always
+ correct, and wasting a few bytes shouldn't be a problem. */
+ sp &= ~0x7;
+
+ write_memory (sp, VALUE_CONTENTS (args[i]), len);
+ args[i] = value_from_pointer (lookup_pointer_type (type), sp);
+ num_elements++;
+ }
+ else if (sparc_floating_p (type))
+ {
+ /* Floating arguments. */
+ gdb_assert (len == 4 || len == 8);
+ num_elements += (len / 4);
+ }
+ else
+ {
+ /* Integral and pointer arguments. */
+ gdb_assert (sparc_integral_or_pointer_p (type));
+
+ if (len < 4)
+ args[i] = value_cast (builtin_type_int32, args[i]);
+ num_elements += ((len + 3) / 4);
+ }
+ }
+
+ /* Always allocate at least six words. */
+ sp -= max (6, num_elements) * 4;
+
+ /* The psABI says that "Software convention requires space for the
+ struct/union return value pointer, even if the word is unused." */
+ sp -= 4;
+
+ /* The psABI says that "Although software convention and the
+ operating system require every stack frame to be doubleword
+ aligned." */
+ sp &= ~0x7;
+
+ for (i = 0; i < nargs; i++)
+ {
+ char *valbuf = VALUE_CONTENTS (args[i]);
+ struct type *type = VALUE_TYPE (args[i]);
+ int len = TYPE_LENGTH (type);
+
+ gdb_assert (len == 4 || len == 8);
+
+ if (element < 6)
+ {
+ int regnum = SPARC_O0_REGNUM + element;
+
+ regcache_cooked_write (regcache, regnum, valbuf);
+ if (len > 4 && element < 5)
+ regcache_cooked_write (regcache, regnum + 1, valbuf + 4);
+ }
+
+ /* Always store the argument in memory. */
+ write_memory (sp + 4 + element * 4, valbuf, len);
+ element += len / 4;
+ }
+
+ gdb_assert (element == num_elements);
+
+ if (struct_return)
+ {
+ char buf[4];
+
+ store_unsigned_integer (buf, 4, struct_addr);
+ write_memory (sp, buf, 4);
+ }
+
+ return sp;
+}
+
+static CORE_ADDR
+sparc32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ CORE_ADDR call_pc = (struct_return ? (bp_addr - 12) : (bp_addr - 8));
+
+ /* Set return address. */
+ regcache_cooked_write_unsigned (regcache, SPARC_O7_REGNUM, call_pc);
+
+ /* Set up function arguments. */
+ sp = sparc32_store_arguments (regcache, nargs, args, sp,
+ struct_return, struct_addr);
+
+ /* Allocate the 16-word window save area. */
+ sp -= 16 * 4;
+
+ /* Stack should be doubleword aligned at this point. */
+ gdb_assert (sp % 8 == 0);
+
+ /* Finally, update the stack pointer. */
+ regcache_cooked_write_unsigned (regcache, SPARC_SP_REGNUM, sp);
+
+ return sp;
+}
+
+
+/* Use the program counter to determine the contents and size of a
+ breakpoint instruction. Return a pointer to a string of bytes that
+ encode a breakpoint instruction, store the length of the string in
+ *LEN and optionally adjust *PC to point to the correct memory
+ location for inserting the breakpoint. */
+
+static const unsigned char *
+sparc_breakpoint_from_pc (CORE_ADDR *pc, int *len)
+{
+ static unsigned char break_insn[] = { 0x91, 0xd0, 0x20, 0x01 };
+
+ *len = sizeof (break_insn);
+ return break_insn;
+}
+
+
+/* Allocate and initialize a frame cache. */
+
+static struct sparc_frame_cache *
+sparc_alloc_frame_cache (void)
+{
+ struct sparc_frame_cache *cache;
+ int i;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct sparc_frame_cache);
+
+ /* Base address. */
+ cache->base = 0;
+ cache->pc = 0;
+
+ /* Frameless until proven otherwise. */
+ cache->frameless_p = 1;
+
+ cache->struct_return_p = 0;
+
+ return cache;
+}
+
+CORE_ADDR
+sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct sparc_frame_cache *cache)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ unsigned long insn;
+ int offset = 0;
+ int dest = -1;
+
+ if (current_pc <= pc)
+ return current_pc;
+
+ /* We have to handle to "Procedure Linkage Table" (PLT) special. On
+ SPARC the linker usually defines a symbol (typically
+ _PROCEDURE_LINKAGE_TABLE_) at the start of the .plt section.
+ This symbol makes us end up here with PC pointing at the start of
+ the PLT and CURRENT_PC probably pointing at a PLT entry. If we
+ would do our normal prologue analysis, we would probably conclude
+ that we've got a frame when in reality we don't, since the
+ dynamic linker patches up the first PLT with some code that
+ starts with a SAVE instruction. Patch up PC such that it points
+ at the start of our PLT entry. */
+ if (tdep->plt_entry_size > 0 && in_plt_section (current_pc, NULL))
+ pc = current_pc - ((current_pc - pc) % tdep->plt_entry_size);
+
+ insn = sparc_fetch_instruction (pc);
+
+ /* Recognize a SETHI insn and record its destination. */
+ if (X_OP (insn) == 0 && X_OP2 (insn) == 0x04)
+ {
+ dest = X_RD (insn);
+ offset += 4;
+
+ insn = sparc_fetch_instruction (pc + 4);
+ }
+
+ /* Allow for an arithmetic operation on DEST or %g1. */
+ if (X_OP (insn) == 2 && X_I (insn)
+ && (X_RD (insn) == 1 || X_RD (insn) == dest))
+ {
+ offset += 4;
+
+ insn = sparc_fetch_instruction (pc + 8);
+ }
+
+ /* Check for the SAVE instruction that sets up the frame. */
+ if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3c)
+ {
+ cache->frameless_p = 0;
+ return pc + offset + 4;
+ }
+
+ return pc;
+}
+
+static CORE_ADDR
+sparc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ return frame_unwind_register_unsigned (next_frame, tdep->pc_regnum);
+}
+
+/* Return PC of first real instruction of the function starting at
+ START_PC. */
+
+static CORE_ADDR
+sparc32_skip_prologue (CORE_ADDR start_pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+ struct sparc_frame_cache cache;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end
+ && start_pc <= sal.end)
+ return sal.end;
+ }
+
+ return sparc_analyze_prologue (start_pc, 0xffffffffUL, &cache);
+}
+
+/* Normal frames. */
+
+struct sparc_frame_cache *
+sparc_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_alloc_frame_cache ();
+ *this_cache = cache;
+
+ cache->pc = frame_func_unwind (next_frame);
+ if (cache->pc != 0)
+ {
+ CORE_ADDR addr_in_block = frame_unwind_address_in_block (next_frame);
+ sparc_analyze_prologue (cache->pc, addr_in_block, cache);
+ }
+
+ if (cache->frameless_p)
+ {
+ /* This function is frameless, so %fp (%i6) holds the frame
+ pointer for our calling frame. Use %sp (%o6) as this frame's
+ base address. */
+ cache->base =
+ frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
+ }
+ else
+ {
+ /* For normal frames, %fp (%i6) holds the frame pointer, the
+ base address for the current stack frame. */
+ cache->base =
+ frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+ }
+
+ return cache;
+}
+
+struct sparc_frame_cache *
+sparc32_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ struct symbol *sym;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+
+ sym = find_pc_function (cache->pc);
+ if (sym)
+ {
+ struct type *type = check_typedef (SYMBOL_TYPE (sym));
+ enum type_code code = TYPE_CODE (type);
+
+ if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+ {
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ if (sparc_structure_or_union_p (type)
+ || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
+ cache->struct_return_p = 1;
+ }
+ }
+
+ return cache;
+}
+
+static void
+sparc32_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc32_frame_cache (next_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc32_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc32_frame_cache (next_frame, this_cache);
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ CORE_ADDR pc = (regnum == SPARC32_NPC_REGNUM) ? 4 : 0;
+
+ /* If this functions has a Structure, Union or
+ Quad-Precision return value, we have to skip the UNIMP
+ instruction that encodes the size of the structure. */
+ if (cache->struct_return_p)
+ pc += 4;
+
+ regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
+ pc += frame_unwind_register_unsigned (next_frame, regnum) + 8;
+ store_unsigned_integer (valuep, 4, pc);
+ }
+ return;
+ }
+
+ /* Handle StackGhost. */
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+
+ if (wcookie != 0 && !cache->frameless_p && regnum == SPARC_I7_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
+ ULONGEST i7;
+
+ /* Read the value in from memory. */
+ i7 = get_frame_memory_unsigned (next_frame, addr, 4);
+ store_unsigned_integer (valuep, 4, i7 ^ wcookie);
+ }
+ return;
+ }
+ }
+
+ /* The previous frame's `local' and `in' registers have been saved
+ in the register save area. */
+ if (!cache->frameless_p
+ && regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
+ *realnump = -1;
+ if (valuep)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+
+ /* Read the value in from memory. */
+ read_memory (*addrp, valuep, register_size (gdbarch, regnum));
+ }
+ return;
+ }
+
+ /* The previous frame's `out' registers are accessable as the
+ current frame's `in' registers. */
+ if (!cache->frameless_p
+ && regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+ regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
+
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc32_frame_unwind =
+{
+ NORMAL_FRAME,
+ sparc32_frame_this_id,
+ sparc32_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc32_frame_sniffer (struct frame_info *next_frame)
+{
+ return &sparc32_frame_unwind;
+}
+
+
+static CORE_ADDR
+sparc32_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct sparc_frame_cache *cache =
+ sparc32_frame_cache (next_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_base sparc32_frame_base =
+{
+ &sparc32_frame_unwind,
+ sparc32_frame_base_address,
+ sparc32_frame_base_address,
+ sparc32_frame_base_address
+};
+
+static struct frame_id
+sparc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ CORE_ADDR sp;
+
+ sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
+ return frame_id_build (sp, frame_pc_unwind (next_frame));
+}
+
+
+/* Extract from an array REGBUF containing the (raw) register state, a
+ function return value of TYPE, and copy that into VALBUF. */
+
+static void
+sparc32_extract_return_value (struct type *type, struct regcache *regcache,
+ void *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ char buf[8];
+
+ gdb_assert (!sparc_structure_or_union_p (type));
+ gdb_assert (!(sparc_floating_p (type) && len == 16));
+
+ if (sparc_floating_p (type))
+ {
+ /* Floating return values. */
+ regcache_cooked_read (regcache, SPARC_F0_REGNUM, buf);
+ if (len > 4)
+ regcache_cooked_read (regcache, SPARC_F1_REGNUM, buf + 4);
+ memcpy (valbuf, buf, len);
+ }
+ else
+ {
+ /* Integral and pointer return values. */
+ gdb_assert (sparc_integral_or_pointer_p (type));
+
+ regcache_cooked_read (regcache, SPARC_O0_REGNUM, buf);
+ if (len > 4)
+ {
+ regcache_cooked_read (regcache, SPARC_O1_REGNUM, buf + 4);
+ gdb_assert (len == 8);
+ memcpy (valbuf, buf, 8);
+ }
+ else
+ {
+ /* Just stripping off any unused bytes should preserve the
+ signed-ness just fine. */
+ memcpy (valbuf, buf + 4 - len, len);
+ }
+ }
+}
+
+/* Write into the appropriate registers a function return value stored
+ in VALBUF of type TYPE. */
+
+static void
+sparc32_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ char buf[8];
+
+ gdb_assert (!sparc_structure_or_union_p (type));
+ gdb_assert (!(sparc_floating_p (type) && len == 16));
+
+ if (sparc_floating_p (type))
+ {
+ /* Floating return values. */
+ memcpy (buf, valbuf, len);
+ regcache_cooked_write (regcache, SPARC_F0_REGNUM, buf);
+ if (len > 4)
+ regcache_cooked_write (regcache, SPARC_F1_REGNUM, buf + 4);
+ }
+ else
+ {
+ /* Integral and pointer return values. */
+ gdb_assert (sparc_integral_or_pointer_p (type));
+
+ if (len > 4)
+ {
+ gdb_assert (len == 8);
+ memcpy (buf, valbuf, 8);
+ regcache_cooked_write (regcache, SPARC_O1_REGNUM, buf + 4);
+ }
+ else
+ {
+ /* ??? Do we need to do any sign-extension here? */
+ memcpy (buf + 4 - len, valbuf, len);
+ }
+ regcache_cooked_write (regcache, SPARC_O0_REGNUM, buf);
+ }
+}
+
+static enum return_value_convention
+sparc32_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ if (sparc_structure_or_union_p (type)
+ || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ if (readbuf)
+ sparc32_extract_return_value (type, regcache, readbuf);
+ if (writebuf)
+ sparc32_store_return_value (type, regcache, writebuf);
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+#if 0
+/* NOTE: cagney/2004-01-17: For the moment disable this method. The
+ architecture and CORE-gdb will need new code (and a replacement for
+ DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS) before this can be made to
+ work robustly. Here is a possible function signature: */
+/* NOTE: cagney/2004-01-17: So far only the 32-bit SPARC ABI has been
+ identifed as having a way to robustly recover the address of a
+ struct-convention return-value (after the function has returned).
+ For all other ABIs so far examined, the calling convention makes no
+ guarenteed that the register containing the return-value will be
+ preserved and hence that the return-value's address can be
+ recovered. */
+/* Extract from REGCACHE, which contains the (raw) register state, the
+ address in which a function should return its structure value, as a
+ CORE_ADDR. */
+
+static CORE_ADDR
+sparc32_extract_struct_value_address (struct regcache *regcache)
+{
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ return read_memory_unsigned_integer (sp + 64, 4);
+}
+#endif
+
+static int
+sparc32_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
+{
+ return (sparc_structure_or_union_p (type)
+ || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16));
+}
+
+
+/* The SPARC Architecture doesn't have hardware single-step support,
+ and most operating systems don't implement it either, so we provide
+ software single-step mechanism. */
+
+static CORE_ADDR
+sparc_analyze_control_transfer (CORE_ADDR pc, CORE_ADDR *npc)
+{
+ unsigned long insn = sparc_fetch_instruction (pc);
+ int conditional_p = X_COND (insn) & 0x7;
+ int branch_p = 0;
+ long offset = 0; /* Must be signed for sign-extend. */
+
+ if (X_OP (insn) == 0 && X_OP2 (insn) == 3 && (insn & 0x1000000) == 0)
+ {
+ /* Branch on Integer Register with Prediction (BPr). */
+ branch_p = 1;
+ conditional_p = 1;
+ }
+ else if (X_OP (insn) == 0 && X_OP2 (insn) == 6)
+ {
+ /* Branch on Floating-Point Condition Codes (FBfcc). */
+ branch_p = 1;
+ offset = 4 * X_DISP22 (insn);
+ }
+ else if (X_OP (insn) == 0 && X_OP2 (insn) == 5)
+ {
+ /* Branch on Floating-Point Condition Codes with Prediction
+ (FBPfcc). */
+ branch_p = 1;
+ offset = 4 * X_DISP19 (insn);
+ }
+ else if (X_OP (insn) == 0 && X_OP2 (insn) == 2)
+ {
+ /* Branch on Integer Condition Codes (Bicc). */
+ branch_p = 1;
+ offset = 4 * X_DISP22 (insn);
+ }
+ else if (X_OP (insn) == 0 && X_OP2 (insn) == 1)
+ {
+ /* Branch on Integer Condition Codes with Prediction (BPcc). */
+ branch_p = 1;
+ offset = 4 * X_DISP19 (insn);
+ }
+
+ /* FIXME: Handle DONE and RETRY instructions. */
+
+ /* FIXME: Handle the Trap instruction. */
+
+ if (branch_p)
+ {
+ if (conditional_p)
+ {
+ /* For conditional branches, return nPC + 4 iff the annul
+ bit is 1. */
+ return (X_A (insn) ? *npc + 4 : 0);
+ }
+ else
+ {
+ /* For unconditional branches, return the target if its
+ specified condition is "always" and return nPC + 4 if the
+ condition is "never". If the annul bit is 1, set *NPC to
+ zero. */
+ if (X_COND (insn) == 0x0)
+ pc = *npc, offset = 4;
+ if (X_A (insn))
+ *npc = 0;
+
+ gdb_assert (offset != 0);
+ return pc + offset;
+ }
+ }
+
+ return 0;
+}
+
+void
+sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ static CORE_ADDR npc, nnpc;
+ static char npc_save[4], nnpc_save[4];
+
+ if (insert_breakpoints_p)
+ {
+ CORE_ADDR pc;
+
+ pc = sparc_address_from_register (tdep->pc_regnum);
+ npc = sparc_address_from_register (tdep->npc_regnum);
+
+ /* Analyze the instruction at PC. */
+ nnpc = sparc_analyze_control_transfer (pc, &npc);
+ if (npc != 0)
+ target_insert_breakpoint (npc, npc_save);
+ if (nnpc != 0)
+ target_insert_breakpoint (nnpc, nnpc_save);
+
+ /* Assert that we have set at least one breakpoint, and that
+ they're not set at the same spot. */
+ gdb_assert (npc != 0 || nnpc != 0);
+ gdb_assert (nnpc != npc);
+ }
+ else
+ {
+ if (npc != 0)
+ target_remove_breakpoint (npc, npc_save);
+ if (nnpc != 0)
+ target_remove_breakpoint (nnpc, nnpc_save);
+ }
+}
+
+static void
+sparc_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ write_register_pid (tdep->pc_regnum, pc, ptid);
+ write_register_pid (tdep->npc_regnum, pc + 4, ptid);
+}
+
+/* Unglobalize NAME. */
+
+char *
+sparc_stabs_unglobalize_name (char *name)
+{
+ /* The Sun compilers (Sun ONE Studio, Forte Developer, Sun WorkShop,
+ SunPRO) convert file static variables into global values, a
+ process known as globalization. In order to do this, the
+ compiler will create a unique prefix and prepend it to each file
+ static variable. For static variables within a function, this
+ globalization prefix is followed by the function name (nested
+ static variables within a function are supposed to generate a
+ warning message, and are left alone). The procedure is
+ documented in the Stabs Interface Manual, which is distrubuted
+ with the compilers, although version 4.0 of the manual seems to
+ be incorrect in some places, at least for SPARC. The
+ globalization prefix is encoded into an N_OPT stab, with the form
+ "G=<prefix>". The globalization prefix always seems to start
+ with a dollar sign '$'; a dot '.' is used as a seperator. So we
+ simply strip everything up until the last dot. */
+
+ if (name[0] == '$')
+ {
+ char *p = strrchr (name, '.');
+ if (p)
+ return p + 1;
+ }
+
+ return name;
+}
+
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+
+const struct regset *
+sparc_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (strcmp (sect_name, ".reg") == 0 && sect_size >= tdep->sizeof_gregset)
+ return tdep->gregset;
+
+ if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset)
+ return tdep->fpregset;
+
+ return NULL;
+}
+
+
+static struct gdbarch *
+sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ /* Allocate space for the new architecture. */
+ tdep = XMALLOC (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->pc_regnum = SPARC32_PC_REGNUM;
+ tdep->npc_regnum = SPARC32_NPC_REGNUM;
+ tdep->gregset = NULL;
+ tdep->sizeof_gregset = 0;
+ tdep->fpregset = NULL;
+ tdep->sizeof_fpregset = 0;
+ tdep->plt_entry_size = 0;
+
+ set_gdbarch_long_double_bit (gdbarch, 128);
+ set_gdbarch_long_double_format (gdbarch, &floatformat_sparc_quad);
+
+ set_gdbarch_num_regs (gdbarch, SPARC32_NUM_REGS);
+ set_gdbarch_register_name (gdbarch, sparc32_register_name);
+ set_gdbarch_register_type (gdbarch, sparc32_register_type);
+ set_gdbarch_num_pseudo_regs (gdbarch, SPARC32_NUM_PSEUDO_REGS);
+ set_gdbarch_pseudo_register_read (gdbarch, sparc32_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, sparc32_pseudo_register_write);
+
+ /* Register numbers of various important registers. */
+ set_gdbarch_sp_regnum (gdbarch, SPARC_SP_REGNUM); /* %sp */
+ set_gdbarch_pc_regnum (gdbarch, SPARC32_PC_REGNUM); /* %pc */
+ set_gdbarch_fp0_regnum (gdbarch, SPARC_F0_REGNUM); /* %f0 */
+
+ /* Call dummy code. */
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_push_dummy_code (gdbarch, sparc32_push_dummy_code);
+ set_gdbarch_push_dummy_call (gdbarch, sparc32_push_dummy_call);
+
+ set_gdbarch_return_value (gdbarch, sparc32_return_value);
+ set_gdbarch_stabs_argument_has_addr
+ (gdbarch, sparc32_stabs_argument_has_addr);
+
+ set_gdbarch_skip_prologue (gdbarch, sparc32_skip_prologue);
+
+ /* Stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, sparc_breakpoint_from_pc);
+
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_sparc);
+
+ set_gdbarch_software_single_step (gdbarch, sparc_software_single_step);
+ set_gdbarch_write_pc (gdbarch, sparc_write_pc);
+
+ set_gdbarch_unwind_dummy_id (gdbarch, sparc_unwind_dummy_id);
+
+ set_gdbarch_unwind_pc (gdbarch, sparc_unwind_pc);
+
+ frame_base_set_default (gdbarch, &sparc32_frame_base);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ frame_unwind_append_sniffer (gdbarch, sparc32_frame_sniffer);
+
+ /* If we have register sets, enable the generic core file support. */
+ if (tdep->gregset)
+ set_gdbarch_regset_from_core_section (gdbarch,
+ sparc_regset_from_core_section);
+
+ return gdbarch;
+}
+
+/* Helper functions for dealing with register windows. */
+
+void
+sparc_supply_rwindow (struct regcache *regcache, CORE_ADDR sp, int regnum)
+{
+ int offset = 0;
+ char buf[8];
+ int i;
+
+ if (sp & 1)
+ {
+ /* Registers are 64-bit. */
+ sp += BIAS;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ {
+ target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8);
+ regcache_raw_supply (regcache, i, buf);
+ }
+ }
+ }
+ else
+ {
+ /* Registers are 32-bit. Toss any sign-extension of the stack
+ pointer. */
+ sp &= 0xffffffffUL;
+
+ /* Clear out the top half of the temporary buffer, and put the
+ register value in the bottom half if we're in 64-bit mode. */
+ if (gdbarch_ptr_bit (current_gdbarch) == 64)
+ {
+ memset (buf, 0, 4);
+ offset = 4;
+ }
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ {
+ target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
+ buf + offset, 4);
+
+ /* Handle StackGhost. */
+ if (i == SPARC_I7_REGNUM)
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+ ULONGEST i7 = extract_unsigned_integer (buf + offset, 4);
+
+ store_unsigned_integer (buf + offset, 4, i7 ^ wcookie);
+ }
+
+ regcache_raw_supply (regcache, i, buf);
+ }
+ }
+ }
+}
+
+void
+sparc_collect_rwindow (const struct regcache *regcache,
+ CORE_ADDR sp, int regnum)
+{
+ int offset = 0;
+ char buf[8];
+ int i;
+
+ if (sp & 1)
+ {
+ /* Registers are 64-bit. */
+ sp += BIAS;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
+ {
+ regcache_raw_collect (regcache, i, buf);
+ target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8);
+ }
+ }
+ }
+ else
+ {
+ /* Registers are 32-bit. Toss any sign-extension of the stack
+ pointer. */
+ sp &= 0xffffffffUL;
+
+ /* Only use the bottom half if we're in 64-bit mode. */
+ if (gdbarch_ptr_bit (current_gdbarch) == 64)
+ offset = 4;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
+ {
+ regcache_raw_collect (regcache, i, buf);
+
+ /* Handle StackGhost. */
+ if (i == SPARC_I7_REGNUM)
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+ ULONGEST i7 = extract_unsigned_integer (buf + offset, 4);
+
+ store_unsigned_integer (buf + offset, 4, i7 ^ wcookie);
+ }
+
+ target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
+ buf + offset, 4);
+ }
+ }
+ }
+}
+
+/* Helper functions for dealing with register sets. */
+
+void
+sparc32_supply_gregset (const struct sparc_gregset *gregset,
+ struct regcache *regcache,
+ int regnum, const void *gregs)
+{
+ const char *regs = gregs;
+ int i;
+
+ if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_PSR_REGNUM,
+ regs + gregset->r_psr_offset);
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset);
+
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset);
+
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_Y_REGNUM,
+ regs + gregset->r_y_offset);
+
+ if (regnum == SPARC_G0_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC_G0_REGNUM, NULL);
+
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
+ {
+ int offset = gregset->r_g1_offset;
+
+ for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ offset += 4;
+ }
+ }
+
+ if ((regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) || regnum == -1)
+ {
+ /* Not all of the register set variants include Locals and
+ Inputs. For those that don't, we read them off the stack. */
+ if (gregset->r_l0_offset == -1)
+ {
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ sparc_supply_rwindow (regcache, sp, regnum);
+ }
+ else
+ {
+ int offset = gregset->r_l0_offset;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ offset += 4;
+ }
+ }
+ }
+}
+
+void
+sparc32_collect_gregset (const struct sparc_gregset *gregset,
+ const struct regcache *regcache,
+ int regnum, void *gregs)
+{
+ char *regs = gregs;
+ int i;
+
+ if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_PSR_REGNUM,
+ regs + gregset->r_psr_offset);
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset);
+
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset);
+
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_Y_REGNUM,
+ regs + gregset->r_y_offset);
+
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
+ {
+ int offset = gregset->r_g1_offset;
+
+ /* %g0 is always zero. */
+ for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ offset += 4;
+ }
+ }
+
+ if ((regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) || regnum == -1)
+ {
+ /* Not all of the register set variants include Locals and
+ Inputs. For those that don't, we read them off the stack. */
+ if (gregset->r_l0_offset != -1)
+ {
+ int offset = gregset->r_l0_offset;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ offset += 4;
+ }
+ }
+ }
+}
+
+void
+sparc32_supply_fpregset (struct regcache *regcache,
+ int regnum, const void *fpregs)
+{
+ const char *regs = fpregs;
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
+ regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ }
+
+ if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_FSR_REGNUM, regs + (32 * 4) + 4);
+}
+
+void
+sparc32_collect_fpregset (const struct regcache *regcache,
+ int regnum, void *fpregs)
+{
+ char *regs = fpregs;
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
+ regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ }
+
+ if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_FSR_REGNUM, regs + (32 * 4) + 4);
+}
+
+
+/* SunOS 4. */
+
+/* From <machine/reg.h>. */
+const struct sparc_gregset sparc32_sunos4_gregset =
+{
+ 0 * 4, /* %psr */
+ 1 * 4, /* %pc */
+ 2 * 4, /* %npc */
+ 3 * 4, /* %y */
+ -1, /* %wim */
+ -1, /* %tbr */
+ 4 * 4, /* %g1 */
+ -1 /* %l0 */
+};
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc_tdep (void);
+
+void
+_initialize_sparc_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_sparc, sparc32_gdbarch_init);
+}
diff --git a/contrib/gdb/gdb/sparc-tdep.h b/contrib/gdb/gdb/sparc-tdep.h
new file mode 100644
index 0000000..bbfbb42
--- /dev/null
+++ b/contrib/gdb/gdb/sparc-tdep.h
@@ -0,0 +1,204 @@
+/* Target-dependent code for SPARC.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SPARC_TDEP_H
+#define SPARC_TDEP_H 1
+
+struct frame_info;
+struct gdbarch;
+struct regcache;
+struct regset;
+struct trad_frame_saved_reg;
+
+/* Register offsets for the general-purpose register set. */
+
+struct sparc_gregset
+{
+ int r_psr_offset;
+ int r_pc_offset;
+ int r_npc_offset;
+ int r_y_offset;
+ int r_wim_offset;
+ int r_tbr_offset;
+ int r_g1_offset;
+ int r_l0_offset;
+ int r_y_size;
+};
+
+/* SPARC architecture-specific information. */
+
+struct gdbarch_tdep
+{
+ /* Register numbers for the PN and nPC registers. The definitions
+ for (64-bit) UltraSPARC differ from the (32-bit) SPARC
+ definitions. */
+ int pc_regnum;
+ int npc_regnum;
+
+ /* Register sets. */
+ struct regset *gregset;
+ size_t sizeof_gregset;
+ struct regset *fpregset;
+ size_t sizeof_fpregset;
+
+ /* Offset of saved PC in jmp_buf. */
+ int jb_pc_offset;
+
+ /* Size of an Procedure Linkage Table (PLT) entry, 0 if we shouldn't
+ treat the PLT special when doing prologue analysis. */
+ size_t plt_entry_size;
+};
+
+/* Register numbers of various important registers. */
+
+enum sparc_regnum
+{
+ SPARC_G0_REGNUM, /* %g0 */
+ SPARC_G1_REGNUM,
+ SPARC_G2_REGNUM,
+ SPARC_G3_REGNUM,
+ SPARC_G4_REGNUM,
+ SPARC_G5_REGNUM,
+ SPARC_G6_REGNUM,
+ SPARC_G7_REGNUM, /* %g7 */
+ SPARC_O0_REGNUM, /* %o0 */
+ SPARC_O1_REGNUM,
+ SPARC_O2_REGNUM,
+ SPARC_O3_REGNUM,
+ SPARC_O4_REGNUM,
+ SPARC_O5_REGNUM,
+ SPARC_SP_REGNUM, /* %sp (%o6) */
+ SPARC_O7_REGNUM, /* %o7 */
+ SPARC_L0_REGNUM, /* %l0 */
+ SPARC_L1_REGNUM,
+ SPARC_L2_REGNUM,
+ SPARC_L3_REGNUM,
+ SPARC_L4_REGNUM,
+ SPARC_L5_REGNUM,
+ SPARC_L6_REGNUM,
+ SPARC_L7_REGNUM, /* %l7 */
+ SPARC_I0_REGNUM, /* %i0 */
+ SPARC_I1_REGNUM,
+ SPARC_I2_REGNUM,
+ SPARC_I3_REGNUM,
+ SPARC_I4_REGNUM,
+ SPARC_I5_REGNUM,
+ SPARC_FP_REGNUM, /* %fp (%i6) */
+ SPARC_I7_REGNUM, /* %i7 */
+ SPARC_F0_REGNUM, /* %f0 */
+ SPARC_F1_REGNUM,
+ SPARC_F31_REGNUM /* %f31 */
+ = SPARC_F0_REGNUM + 31
+};
+
+enum sparc32_regnum
+{
+ SPARC32_Y_REGNUM /* %y */
+ = SPARC_F31_REGNUM + 1,
+ SPARC32_PSR_REGNUM, /* %psr */
+ SPARC32_WIM_REGNUM, /* %wim */
+ SPARC32_TBR_REGNUM, /* %tbr */
+ SPARC32_PC_REGNUM, /* %pc */
+ SPARC32_NPC_REGNUM, /* %npc */
+ SPARC32_FSR_REGNUM, /* %fsr */
+ SPARC32_CSR_REGNUM, /* %csr */
+
+ /* Pseudo registers. */
+ SPARC32_D0_REGNUM, /* %d0 */
+ SPARC32_D30_REGNUM /* %d30 */
+ = SPARC32_D0_REGNUM + 15
+};
+
+
+struct sparc_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR pc;
+
+ /* Do we have a frame? */
+ int frameless_p;
+
+ /* Do we have a Structure, Union or Quad-Precision return value?. */
+ int struct_return_p;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Fetch the instruction at PC. */
+extern unsigned long sparc_fetch_instruction (CORE_ADDR pc);
+
+/* Fetch StackGhost Per-Process XOR cookie. */
+extern ULONGEST sparc_fetch_wcookie (void);
+
+extern CORE_ADDR sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct sparc_frame_cache *cache);
+
+extern struct sparc_frame_cache *
+ sparc_frame_cache (struct frame_info *next_frame, void **this_cache);
+
+extern struct sparc_frame_cache *
+ sparc32_frame_cache (struct frame_info *next_frame, void **this_cache);
+
+
+
+extern void sparc_software_single_step (enum target_signal sig,
+ int insert_breakpoints_p);
+
+extern void sparc_supply_rwindow (struct regcache *regcache,
+ CORE_ADDR sp, int regnum);
+extern void sparc_collect_rwindow (const struct regcache *regcache,
+ CORE_ADDR sp, int regnum);
+
+/* Register offsets for SunOS 4. */
+extern const struct sparc_gregset sparc32_sunos4_gregset;
+
+extern void sparc32_supply_gregset (const struct sparc_gregset *gregset,
+ struct regcache *regcache,
+ int regnum, const void *gregs);
+extern void sparc32_collect_gregset (const struct sparc_gregset *gregset,
+ const struct regcache *regcache,
+ int regnum, void *gregs);
+extern void sparc32_supply_fpregset (struct regcache *regcache,
+ int regnum, const void *fpregs);
+extern void sparc32_collect_fpregset (const struct regcache *regcache,
+ int regnum, void *fpregs);
+
+/* Functions and variables exported from sparc-sol2-tdep.c. */
+
+/* Register offsets for Solaris 2. */
+extern const struct sparc_gregset sparc32_sol2_gregset;
+
+extern int sparc_sol2_pc_in_sigtramp (CORE_ADDR pc, char *name);
+
+extern void sparc32_sol2_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch);
+
+/* Functions and variables exported from sparcnbsd-tdep.c. */
+
+/* Register offsets for NetBSD. */
+extern const struct sparc_gregset sparc32nbsd_gregset;
+
+extern struct trad_frame_saved_reg *
+ sparc32nbsd_sigcontext_saved_regs (struct frame_info *next_frame);
+
+#endif /* sparc-tdep.h */
diff --git a/contrib/gdb/gdb/sparc64-nat.c b/contrib/gdb/gdb/sparc64-nat.c
new file mode 100644
index 0000000..40a8b3b
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64-nat.c
@@ -0,0 +1,87 @@
+/* Native-dependent code for GNU/Linux UltraSPARC.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbarch.h"
+
+#include "sparc64-tdep.h"
+#include "sparc-nat.h"
+
+/* Determine whether `gregset_t' contains register REGNUM. */
+
+static int
+sparc64_gregset_supplies_p (int regnum)
+{
+ if (gdbarch_ptr_bit (current_gdbarch) == 32)
+ return sparc32_gregset_supplies_p (regnum);
+
+ /* Integer registers. */
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
+ || (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+ || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
+ || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM))
+ return 1;
+
+ /* Control registers. */
+ if (regnum == SPARC64_PC_REGNUM
+ || regnum == SPARC64_NPC_REGNUM
+ || regnum == SPARC64_STATE_REGNUM
+ || regnum == SPARC64_Y_REGNUM
+ || regnum == SPARC64_FPRS_REGNUM)
+ return 1;
+
+ return 0;
+}
+
+/* Determine whether `fpregset_t' contains register REGNUM. */
+
+static int
+sparc64_fpregset_supplies_p (int regnum)
+{
+ if (gdbarch_ptr_bit (current_gdbarch) == 32)
+ return sparc32_fpregset_supplies_p (regnum);
+
+ /* Floating-point registers. */
+ if ((regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
+ || (regnum >= SPARC64_F32_REGNUM && regnum <= SPARC64_F62_REGNUM))
+ return 1;
+
+ /* Control registers. */
+ if (regnum == SPARC64_FSR_REGNUM)
+ return 1;
+
+ return 0;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc64_nat (void);
+
+void
+_initialize_sparc64_nat (void)
+{
+ sparc_supply_gregset = sparc64_supply_gregset;
+ sparc_collect_gregset = sparc64_collect_gregset;
+ sparc_supply_fpregset = sparc64_supply_fpregset;
+ sparc_collect_fpregset = sparc64_collect_fpregset;
+ sparc_gregset_supplies_p = sparc64_gregset_supplies_p;
+ sparc_fpregset_supplies_p = sparc64_fpregset_supplies_p;
+}
diff --git a/contrib/gdb/gdb/sparc64-sol2-tdep.c b/contrib/gdb/gdb/sparc64-sol2-tdep.c
new file mode 100644
index 0000000..079f3c5
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64-sol2-tdep.c
@@ -0,0 +1,182 @@
+/* Target-dependent code for Solaris UltraSPARC.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame-unwind.h"
+#include "gdbarch.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "trad-frame.h"
+
+#include "gdb_assert.h"
+
+#include "sparc64-tdep.h"
+
+/* From <sys/regset.h>. */
+const struct sparc_gregset sparc64_sol2_gregset =
+{
+ 32 * 8, /* "tstate" */
+ 33 * 8, /* %pc */
+ 34 * 8, /* %npc */
+ 35 * 8, /* %y */
+ -1, /* %wim */
+ -1, /* %tbr */
+ 1 * 8, /* %g1 */
+ 16 * 8, /* %l0 */
+ 8 /* sizeof (%y) */
+};
+
+
+static struct sparc_frame_cache *
+sparc64_sol2_sigtramp_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR mcontext_addr, addr;
+ int regnum;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* The third argument is a pointer to an instance of `ucontext_t',
+ which has a member `uc_mcontext' that contains the saved
+ registers. */
+ regnum = (cache->frameless_p ? SPARC_O2_REGNUM : SPARC_I2_REGNUM);
+ mcontext_addr = frame_unwind_register_unsigned (next_frame, regnum) + 64;
+
+ cache->saved_regs[SPARC64_CCR_REGNUM].addr = mcontext_addr + 0 * 8;
+ cache->saved_regs[SPARC64_PC_REGNUM].addr = mcontext_addr + 1 * 8;
+ cache->saved_regs[SPARC64_NPC_REGNUM].addr = mcontext_addr + 2 * 8;
+ cache->saved_regs[SPARC64_Y_REGNUM].addr = mcontext_addr + 3 * 8;
+ cache->saved_regs[SPARC64_ASI_REGNUM].addr = mcontext_addr + 19 * 8;
+ cache->saved_regs[SPARC64_FPRS_REGNUM].addr = mcontext_addr + 20 * 8;
+
+ /* Since %g0 is always zero, keep the identity encoding. */
+ for (regnum = SPARC_G1_REGNUM, addr = mcontext_addr + 4 * 8;
+ regnum <= SPARC_O7_REGNUM; regnum++, addr += 8)
+ cache->saved_regs[regnum].addr = addr;
+
+ if (get_frame_memory_unsigned (next_frame, mcontext_addr + 21 * 8, 8))
+ {
+ /* The register windows haven't been flushed. */
+ for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
+ trad_frame_set_unknown (cache->saved_regs, regnum);
+ }
+ else
+ {
+ CORE_ADDR sp;
+
+ addr = cache->saved_regs[SPARC_SP_REGNUM].addr;
+ sp = get_frame_memory_unsigned (next_frame, addr, 8);
+ for (regnum = SPARC_L0_REGNUM, addr = sp + BIAS;
+ regnum <= SPARC_I7_REGNUM; regnum++, addr += 8)
+ cache->saved_regs[regnum].addr = addr;
+ }
+
+ return cache;
+}
+
+static void
+sparc64_sol2_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc64_sol2_sigtramp_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc64_sol2_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc64_sol2_sigtramp_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc64_sol2_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ sparc64_sol2_sigtramp_frame_this_id,
+ sparc64_sol2_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc64_sol2_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (sparc_sol2_pc_in_sigtramp (pc, name))
+ return &sparc64_sol2_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+
+void
+sparc64_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, sparc_sol2_pc_in_sigtramp);
+ frame_unwind_append_sniffer (gdbarch, sparc64_sol2_sigtramp_frame_sniffer);
+
+ sparc64_init_abi (info, gdbarch);
+
+ /* Solaris has SVR4-style shared libraries... */
+ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+ /* ...which means that we need some special handling when doing
+ prologue analysis. */
+ tdep->plt_entry_size = 16;
+
+ /* Solaris has kernel-assisted single-stepping support. */
+ set_gdbarch_software_single_step (gdbarch, NULL);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc64_sol2_tdep (void);
+
+void
+_initialize_sparc64_sol2_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
+ GDB_OSABI_SOLARIS, sparc64_sol2_init_abi);
+}
diff --git a/contrib/gdb/gdb/sparc64-tdep.c b/contrib/gdb/gdb/sparc64-tdep.c
new file mode 100644
index 0000000..8aad619
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64-tdep.c
@@ -0,0 +1,1433 @@
+/* Target-dependent code for UltraSPARC.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "arch-utils.h"
+#include "floatformat.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "gdbcore.h"
+#include "gdbtypes.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "target.h"
+#include "value.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "sparc64-tdep.h"
+
+/* This file implements the The SPARC 64-bit ABI as defined by the
+ section "Low-Level System Information" of the SPARC Compliance
+ Definition (SCD) 2.4.1, which is the 64-bit System V psABI for
+ SPARC. */
+
+/* Please use the sparc32_-prefix for 32-bit specific code, the
+ sparc64_-prefix for 64-bit specific code and the sparc_-prefix for
+ code can handle both. */
+
+/* The functions on this page are intended to be used to classify
+ function arguments. */
+
+/* Return the contents if register REGNUM as an address. */
+
+static CORE_ADDR
+sparc_address_from_register (int regnum)
+{
+ ULONGEST addr;
+
+ regcache_cooked_read_unsigned (current_regcache, regnum, &addr);
+ return addr;
+}
+
+/* Check whether TYPE is "Integral or Pointer". */
+
+static int
+sparc64_integral_or_pointer_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_RANGE:
+ {
+ int len = TYPE_LENGTH (type);
+ gdb_assert (len == 1 || len == 2 || len == 4 || len == 8);
+ }
+ return 1;
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ {
+ int len = TYPE_LENGTH (type);
+ gdb_assert (len == 8);
+ }
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Check whether TYPE is "Floating". */
+
+static int
+sparc64_floating_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_FLT:
+ {
+ int len = TYPE_LENGTH (type);
+ gdb_assert (len == 4 || len == 8 || len == 16);
+ }
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Check whether TYPE is "Structure or Union". */
+
+static int
+sparc64_structure_or_union_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Register information. */
+
+struct sparc64_register_info
+{
+ char *name;
+ struct type **type;
+};
+
+static struct sparc64_register_info sparc64_register_info[] =
+{
+ { "g0", &builtin_type_int64 },
+ { "g1", &builtin_type_int64 },
+ { "g2", &builtin_type_int64 },
+ { "g3", &builtin_type_int64 },
+ { "g4", &builtin_type_int64 },
+ { "g5", &builtin_type_int64 },
+ { "g6", &builtin_type_int64 },
+ { "g7", &builtin_type_int64 },
+
+ { "o0", &builtin_type_int64 },
+ { "o1", &builtin_type_int64 },
+ { "o2", &builtin_type_int64 },
+ { "o3", &builtin_type_int64 },
+ { "o4", &builtin_type_int64 },
+ { "o5", &builtin_type_int64 },
+ { "sp", &builtin_type_void_data_ptr },
+ { "o7", &builtin_type_int64 },
+
+ { "l0", &builtin_type_int64 },
+ { "l1", &builtin_type_int64 },
+ { "l2", &builtin_type_int64 },
+ { "l3", &builtin_type_int64 },
+ { "l4", &builtin_type_int64 },
+ { "l5", &builtin_type_int64 },
+ { "l6", &builtin_type_int64 },
+ { "l7", &builtin_type_int64 },
+
+ { "i0", &builtin_type_int64 },
+ { "i1", &builtin_type_int64 },
+ { "i2", &builtin_type_int64 },
+ { "i3", &builtin_type_int64 },
+ { "i4", &builtin_type_int64 },
+ { "i5", &builtin_type_int64 },
+ { "fp", &builtin_type_void_data_ptr },
+ { "i7", &builtin_type_int64 },
+
+ { "f0", &builtin_type_float },
+ { "f1", &builtin_type_float },
+ { "f2", &builtin_type_float },
+ { "f3", &builtin_type_float },
+ { "f4", &builtin_type_float },
+ { "f5", &builtin_type_float },
+ { "f6", &builtin_type_float },
+ { "f7", &builtin_type_float },
+ { "f8", &builtin_type_float },
+ { "f9", &builtin_type_float },
+ { "f10", &builtin_type_float },
+ { "f11", &builtin_type_float },
+ { "f12", &builtin_type_float },
+ { "f13", &builtin_type_float },
+ { "f14", &builtin_type_float },
+ { "f15", &builtin_type_float },
+ { "f16", &builtin_type_float },
+ { "f17", &builtin_type_float },
+ { "f18", &builtin_type_float },
+ { "f19", &builtin_type_float },
+ { "f20", &builtin_type_float },
+ { "f21", &builtin_type_float },
+ { "f22", &builtin_type_float },
+ { "f23", &builtin_type_float },
+ { "f24", &builtin_type_float },
+ { "f25", &builtin_type_float },
+ { "f26", &builtin_type_float },
+ { "f27", &builtin_type_float },
+ { "f28", &builtin_type_float },
+ { "f29", &builtin_type_float },
+ { "f30", &builtin_type_float },
+ { "f31", &builtin_type_float },
+ { "f32", &builtin_type_double },
+ { "f34", &builtin_type_double },
+ { "f36", &builtin_type_double },
+ { "f38", &builtin_type_double },
+ { "f40", &builtin_type_double },
+ { "f42", &builtin_type_double },
+ { "f44", &builtin_type_double },
+ { "f46", &builtin_type_double },
+ { "f48", &builtin_type_double },
+ { "f50", &builtin_type_double },
+ { "f52", &builtin_type_double },
+ { "f54", &builtin_type_double },
+ { "f56", &builtin_type_double },
+ { "f58", &builtin_type_double },
+ { "f60", &builtin_type_double },
+ { "f62", &builtin_type_double },
+
+ { "pc", &builtin_type_void_func_ptr },
+ { "npc", &builtin_type_void_func_ptr },
+
+ /* This raw register contains the contents of %cwp, %pstate, %asi
+ and %ccr as laid out in a %tstate register. */
+ /* FIXME: Give it a name until we start using register groups. */
+ { "state", &builtin_type_int64 },
+
+ { "fsr", &builtin_type_int64 },
+ { "fprs", &builtin_type_int64 },
+
+ /* "Although Y is a 64-bit register, its high-order 32 bits are
+ reserved and always read as 0." */
+ { "y", &builtin_type_int64 }
+};
+
+/* Total number of registers. */
+#define SPARC64_NUM_REGS ARRAY_SIZE (sparc64_register_info)
+
+/* We provide the aliases %d0..%d62 and %q0..%q60 for the floating
+ registers as "psuedo" registers. */
+
+static struct sparc64_register_info sparc64_pseudo_register_info[] =
+{
+ { "cwp", &builtin_type_int64 },
+ { "pstate", &builtin_type_int64 },
+ { "asi", &builtin_type_int64 },
+ { "ccr", &builtin_type_int64 },
+
+ { "d0", &builtin_type_double },
+ { "d2", &builtin_type_double },
+ { "d4", &builtin_type_double },
+ { "d6", &builtin_type_double },
+ { "d8", &builtin_type_double },
+ { "d10", &builtin_type_double },
+ { "d12", &builtin_type_double },
+ { "d14", &builtin_type_double },
+ { "d16", &builtin_type_double },
+ { "d18", &builtin_type_double },
+ { "d20", &builtin_type_double },
+ { "d22", &builtin_type_double },
+ { "d24", &builtin_type_double },
+ { "d26", &builtin_type_double },
+ { "d28", &builtin_type_double },
+ { "d30", &builtin_type_double },
+ { "d32", &builtin_type_double },
+ { "d34", &builtin_type_double },
+ { "d36", &builtin_type_double },
+ { "d38", &builtin_type_double },
+ { "d40", &builtin_type_double },
+ { "d42", &builtin_type_double },
+ { "d44", &builtin_type_double },
+ { "d46", &builtin_type_double },
+ { "d48", &builtin_type_double },
+ { "d50", &builtin_type_double },
+ { "d52", &builtin_type_double },
+ { "d54", &builtin_type_double },
+ { "d56", &builtin_type_double },
+ { "d58", &builtin_type_double },
+ { "d60", &builtin_type_double },
+ { "d62", &builtin_type_double },
+
+ { "q0", &builtin_type_long_double },
+ { "q4", &builtin_type_long_double },
+ { "q8", &builtin_type_long_double },
+ { "q12", &builtin_type_long_double },
+ { "q16", &builtin_type_long_double },
+ { "q20", &builtin_type_long_double },
+ { "q24", &builtin_type_long_double },
+ { "q28", &builtin_type_long_double },
+ { "q32", &builtin_type_long_double },
+ { "q36", &builtin_type_long_double },
+ { "q40", &builtin_type_long_double },
+ { "q44", &builtin_type_long_double },
+ { "q48", &builtin_type_long_double },
+ { "q52", &builtin_type_long_double },
+ { "q56", &builtin_type_long_double },
+ { "q60", &builtin_type_long_double }
+};
+
+/* Total number of pseudo registers. */
+#define SPARC64_NUM_PSEUDO_REGS ARRAY_SIZE (sparc64_pseudo_register_info)
+
+/* Return the name of register REGNUM. */
+
+static const char *
+sparc64_register_name (int regnum)
+{
+ if (regnum >= 0 && regnum < SPARC64_NUM_REGS)
+ return sparc64_register_info[regnum].name;
+
+ if (regnum >= SPARC64_NUM_REGS
+ && regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
+ return sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].name;
+
+ return NULL;
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. */
+
+static struct type *
+sparc64_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum >= SPARC64_NUM_REGS
+ && regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
+ return *sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].type;
+
+ gdb_assert (regnum >= 0 && regnum < SPARC64_NUM_REGS);
+ return *sparc64_register_info[regnum].type;
+}
+
+static void
+sparc64_pseudo_register_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, void *buf)
+{
+ gdb_assert (regnum >= SPARC64_NUM_REGS);
+
+ if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D30_REGNUM)
+ {
+ regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
+ regcache_raw_read (regcache, regnum, buf);
+ regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 4);
+ }
+ else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
+ {
+ regnum = SPARC64_F32_REGNUM + (regnum - SPARC64_D32_REGNUM);
+ regcache_raw_read (regcache, regnum, buf);
+ }
+ else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q28_REGNUM)
+ {
+ regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
+ regcache_raw_read (regcache, regnum, buf);
+ regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 4);
+ regcache_raw_read (regcache, regnum + 2, ((char *)buf) + 8);
+ regcache_raw_read (regcache, regnum + 3, ((char *)buf) + 12);
+ }
+ else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
+ {
+ regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
+ regcache_raw_read (regcache, regnum, buf);
+ regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 8);
+ }
+ else if (regnum == SPARC64_CWP_REGNUM
+ || regnum == SPARC64_PSTATE_REGNUM
+ || regnum == SPARC64_ASI_REGNUM
+ || regnum == SPARC64_CCR_REGNUM)
+ {
+ ULONGEST state;
+
+ regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
+ switch (regnum)
+ {
+ case SPARC64_CWP_REGNUM:
+ state = (state >> 0) & ((1 << 5) - 1);
+ break;
+ case SPARC64_PSTATE_REGNUM:
+ state = (state >> 8) & ((1 << 12) - 1);
+ break;
+ case SPARC64_ASI_REGNUM:
+ state = (state >> 24) & ((1 << 8) - 1);
+ break;
+ case SPARC64_CCR_REGNUM:
+ state = (state >> 32) & ((1 << 8) - 1);
+ break;
+ }
+ store_unsigned_integer (buf, 8, state);
+ }
+}
+
+static void
+sparc64_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, const void *buf)
+{
+ gdb_assert (regnum >= SPARC64_NUM_REGS);
+
+ if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D30_REGNUM)
+ {
+ regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
+ regcache_raw_write (regcache, regnum, buf);
+ regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 4);
+ }
+ else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
+ {
+ regnum = SPARC64_F32_REGNUM + (regnum - SPARC64_D32_REGNUM);
+ regcache_raw_write (regcache, regnum, buf);
+ }
+ else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q28_REGNUM)
+ {
+ regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
+ regcache_raw_write (regcache, regnum, buf);
+ regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 4);
+ regcache_raw_write (regcache, regnum + 2, ((const char *)buf) + 8);
+ regcache_raw_write (regcache, regnum + 3, ((const char *)buf) + 12);
+ }
+ else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
+ {
+ regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
+ regcache_raw_write (regcache, regnum, buf);
+ regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 8);
+ }
+ else if (regnum == SPARC64_CWP_REGNUM
+ || regnum == SPARC64_PSTATE_REGNUM
+ || regnum == SPARC64_ASI_REGNUM
+ || regnum == SPARC64_CCR_REGNUM)
+ {
+ ULONGEST state, bits;
+
+ regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
+ bits = extract_unsigned_integer (buf, 8);
+ switch (regnum)
+ {
+ case SPARC64_CWP_REGNUM:
+ state |= ((bits & ((1 << 5) - 1)) << 0);
+ break;
+ case SPARC64_PSTATE_REGNUM:
+ state |= ((bits & ((1 << 12) - 1)) << 8);
+ break;
+ case SPARC64_ASI_REGNUM:
+ state |= ((bits & ((1 << 8) - 1)) << 24);
+ break;
+ case SPARC64_CCR_REGNUM:
+ state |= ((bits & ((1 << 8) - 1)) << 32);
+ break;
+ }
+ regcache_raw_write_unsigned (regcache, SPARC64_STATE_REGNUM, state);
+ }
+}
+
+
+/* Return PC of first real instruction of the function starting at
+ START_PC. */
+
+static CORE_ADDR
+sparc64_skip_prologue (CORE_ADDR start_pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+ struct sparc_frame_cache cache;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end
+ && start_pc <= sal.end)
+ return sal.end;
+ }
+
+ return sparc_analyze_prologue (start_pc, 0xffffffffffffffffULL, &cache);
+}
+
+/* Normal frames. */
+
+static struct sparc_frame_cache *
+sparc64_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ return sparc_frame_cache (next_frame, this_cache);
+}
+
+static void
+sparc64_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc64_frame_cache (next_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc64_frame_cache (next_frame, this_cache);
+
+ if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
+
+ regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
+ pc += frame_unwind_register_unsigned (next_frame, regnum) + 8;
+ store_unsigned_integer (valuep, 8, pc);
+ }
+ return;
+ }
+
+ /* The previous frame's `local' and `in' registers have been saved
+ in the register save area. */
+ if (!cache->frameless_p
+ && regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = cache->base + BIAS + (regnum - SPARC_L0_REGNUM) * 8;
+ *realnump = -1;
+ if (valuep)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+
+ /* Read the value in from memory. */
+ read_memory (*addrp, valuep, register_size (gdbarch, regnum));
+ }
+ return;
+ }
+
+ /* The previous frame's `out' registers are accessable as the
+ current frame's `in' registers. */
+ if (!cache->frameless_p
+ && regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+ regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
+
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc64_frame_unwind =
+{
+ NORMAL_FRAME,
+ sparc64_frame_this_id,
+ sparc64_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc64_frame_sniffer (struct frame_info *next_frame)
+{
+ return &sparc64_frame_unwind;
+}
+
+
+static CORE_ADDR
+sparc64_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct sparc_frame_cache *cache =
+ sparc64_frame_cache (next_frame, this_cache);
+
+ /* ??? Should we take BIAS into account here? */
+ return cache->base;
+}
+
+static const struct frame_base sparc64_frame_base =
+{
+ &sparc64_frame_unwind,
+ sparc64_frame_base_address,
+ sparc64_frame_base_address,
+ sparc64_frame_base_address
+};
+
+/* Check whether TYPE must be 16-byte aligned. */
+
+static int
+sparc64_16_byte_align_p (struct type *type)
+{
+ if (sparc64_floating_p (type) && TYPE_LENGTH (type) == 16)
+ return 1;
+
+ if (sparc64_structure_or_union_p (type))
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+
+ if (sparc64_16_byte_align_p (subtype))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Store floating fields of element ELEMENT of an "parameter array"
+ that has type TYPE and is stored at BITPOS in VALBUF in the
+ apropriate registers of REGCACHE. This function can be called
+ recursively and therefore handles floating types in addition to
+ structures. */
+
+static void
+sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
+ char *valbuf, int element, int bitpos)
+{
+ gdb_assert (element < 16);
+
+ if (sparc64_floating_p (type))
+ {
+ int len = TYPE_LENGTH (type);
+ int regnum;
+
+ if (len == 16)
+ {
+ gdb_assert (bitpos == 0);
+ gdb_assert ((element % 2) == 0);
+
+ regnum = SPARC64_Q0_REGNUM + element / 2;
+ regcache_cooked_write (regcache, regnum, valbuf);
+ }
+ else if (len == 8)
+ {
+ gdb_assert (bitpos == 0 || bitpos == 64);
+
+ regnum = SPARC64_D0_REGNUM + element + bitpos / 64;
+ regcache_cooked_write (regcache, regnum, valbuf + (bitpos / 8));
+ }
+ else
+ {
+ gdb_assert (len == 4);
+ gdb_assert (bitpos % 32 == 0 && bitpos >= 0 && bitpos < 128);
+
+ regnum = SPARC_F0_REGNUM + element * 2 + bitpos / 32;
+ regcache_cooked_write (regcache, regnum, valbuf + (bitpos / 8));
+ }
+ }
+ else if (sparc64_structure_or_union_p (type))
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int subpos = bitpos + TYPE_FIELD_BITPOS (type, i);
+
+ sparc64_store_floating_fields (regcache, subtype, valbuf,
+ element, subpos);
+ }
+
+ /* GCC has an interesting bug. If TYPE is a structure that has
+ a single `float' member, GCC doesn't treat it as a structure
+ at all, but rather as an ordinary `float' argument. This
+ argument will be stored in %f1, as required by the psABI.
+ However, as a member of a structure the psABI requires it to
+ be stored in %f0. This bug is present in GCC 3.3.2, but
+ probably in older releases to. To appease GCC, if a
+ structure has only a single `float' member, we store its
+ value in %f1 too (we already have stored in %f0). */
+ if (TYPE_NFIELDS (type) == 1)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, 0));
+
+ if (sparc64_floating_p (subtype) && TYPE_LENGTH (subtype) == 4)
+ regcache_cooked_write (regcache, SPARC_F1_REGNUM, valbuf);
+ }
+ }
+}
+
+/* Fetch floating fields from a variable of type TYPE from the
+ appropriate registers for BITPOS in REGCACHE and store it at BITPOS
+ in VALBUF. This function can be called recursively and therefore
+ handles floating types in addition to structures. */
+
+static void
+sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
+ char *valbuf, int bitpos)
+{
+ if (sparc64_floating_p (type))
+ {
+ int len = TYPE_LENGTH (type);
+ int regnum;
+
+ if (len == 16)
+ {
+ gdb_assert (bitpos == 0 || bitpos == 128);
+
+ regnum = SPARC64_Q0_REGNUM + bitpos / 128;
+ regcache_cooked_read (regcache, regnum, valbuf + (bitpos / 8));
+ }
+ else if (len == 8)
+ {
+ gdb_assert (bitpos % 64 == 0 && bitpos >= 0 && bitpos < 256);
+
+ regnum = SPARC64_D0_REGNUM + bitpos / 64;
+ regcache_cooked_read (regcache, regnum, valbuf + (bitpos / 8));
+ }
+ else
+ {
+ gdb_assert (len == 4);
+ gdb_assert (bitpos % 32 == 0 && bitpos >= 0 && bitpos < 256);
+
+ regnum = SPARC_F0_REGNUM + bitpos / 32;
+ regcache_cooked_read (regcache, regnum, valbuf + (bitpos / 8));
+ }
+ }
+ else if (sparc64_structure_or_union_p (type))
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int subpos = bitpos + TYPE_FIELD_BITPOS (type, i);
+
+ sparc64_extract_floating_fields (regcache, subtype, valbuf, subpos);
+ }
+ }
+}
+
+/* Store the NARGS arguments ARGS and STRUCT_ADDR (if STRUCT_RETURN is
+ non-zero) in REGCACHE and on the stack (starting from address SP). */
+
+static CORE_ADDR
+sparc64_store_arguments (struct regcache *regcache, int nargs,
+ struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ /* Number of extended words in the "parameter array". */
+ int num_elements = 0;
+ int element = 0;
+ int i;
+
+ /* Take BIAS into account. */
+ sp += BIAS;
+
+ /* First we calculate the number of extended words in the "parameter
+ array". While doing so we also convert some of the arguments. */
+
+ if (struct_return)
+ num_elements++;
+
+ for (i = 0; i < nargs; i++)
+ {
+ struct type *type = VALUE_TYPE (args[i]);
+ int len = TYPE_LENGTH (type);
+
+ if (sparc64_structure_or_union_p (type))
+ {
+ /* Structure or Union arguments. */
+ if (len <= 16)
+ {
+ if (num_elements % 2 && sparc64_16_byte_align_p (type))
+ num_elements++;
+ num_elements += ((len + 7) / 8);
+ }
+ else
+ {
+ /* The psABI says that "Structures or unions larger than
+ sixteen bytes are copied by the caller and passed
+ indirectly; the caller will pass the address of a
+ correctly aligned structure value. This sixty-four
+ bit address will occupy one word in the parameter
+ array, and may be promoted to an %o register like any
+ other pointer value." Allocate memory for these
+ values on the stack. */
+ sp -= len;
+
+ /* Use 16-byte alignment for these values. That's
+ always correct, and wasting a few bytes shouldn't be
+ a problem. */
+ sp &= ~0xf;
+
+ write_memory (sp, VALUE_CONTENTS (args[i]), len);
+ args[i] = value_from_pointer (lookup_pointer_type (type), sp);
+ num_elements++;
+ }
+ }
+ else if (sparc64_floating_p (type))
+ {
+ /* Floating arguments. */
+
+ if (len == 16)
+ {
+ /* The psABI says that "Each quad-precision parameter
+ value will be assigned to two extended words in the
+ parameter array. */
+ num_elements += 2;
+
+ /* The psABI says that "Long doubles must be
+ quad-aligned, and thus a hole might be introduced
+ into the parameter array to force alignment." Skip
+ an element if necessary. */
+ if (num_elements % 2)
+ num_elements++;
+ }
+ else
+ num_elements++;
+ }
+ else
+ {
+ /* Integral and pointer arguments. */
+ gdb_assert (sparc64_integral_or_pointer_p (type));
+
+ /* The psABI says that "Each argument value of integral type
+ smaller than an extended word will be widened by the
+ caller to an extended word according to the signed-ness
+ of the argument type." */
+ if (len < 8)
+ args[i] = value_cast (builtin_type_int64, args[i]);
+ num_elements++;
+ }
+ }
+
+ /* Allocate the "parameter array". */
+ sp -= num_elements * 8;
+
+ /* The psABI says that "Every stack frame must be 16-byte aligned." */
+ sp &= ~0xf;
+
+ /* Now we store the arguments in to the "paramater array". Some
+ Integer or Pointer arguments and Structure or Union arguments
+ will be passed in %o registers. Some Floating arguments and
+ floating members of structures are passed in floating-point
+ registers. However, for functions with variable arguments,
+ floating arguments are stored in an %0 register, and for
+ functions without a prototype floating arguments are stored in
+ both a floating-point and an %o registers, or a floating-point
+ register and memory. To simplify the logic here we always pass
+ arguments in memory, an %o register, and a floating-point
+ register if appropriate. This should be no problem since the
+ contents of any unused memory or registers in the "parameter
+ array" are undefined. */
+
+ if (struct_return)
+ {
+ regcache_cooked_write_unsigned (regcache, SPARC_O0_REGNUM, struct_addr);
+ element++;
+ }
+
+ for (i = 0; i < nargs; i++)
+ {
+ char *valbuf = VALUE_CONTENTS (args[i]);
+ struct type *type = VALUE_TYPE (args[i]);
+ int len = TYPE_LENGTH (type);
+ int regnum = -1;
+ char buf[16];
+
+ if (sparc64_structure_or_union_p (type))
+ {
+ /* Structure or Union arguments. */
+ gdb_assert (len <= 16);
+ memset (buf, 0, sizeof (buf));
+ valbuf = memcpy (buf, valbuf, len);
+
+ if (element % 2 && sparc64_16_byte_align_p (type))
+ element++;
+
+ if (element < 6)
+ {
+ regnum = SPARC_O0_REGNUM + element;
+ if (len > 8 && element < 5)
+ regcache_cooked_write (regcache, regnum + 1, valbuf + 8);
+ }
+
+ if (element < 16)
+ sparc64_store_floating_fields (regcache, type, valbuf, element, 0);
+ }
+ else if (sparc64_floating_p (type))
+ {
+ /* Floating arguments. */
+ if (len == 16)
+ {
+ if (element % 2)
+ element++;
+ if (element < 16)
+ regnum = SPARC64_Q0_REGNUM + element / 2;
+ }
+ else if (len == 8)
+ {
+ if (element < 16)
+ regnum = SPARC64_D0_REGNUM + element;
+ }
+ else
+ {
+ /* The psABI says "Each single-precision parameter value
+ will be assigned to one extended word in the
+ parameter array, and right-justified within that
+ word; the left half (even floatregister) is
+ undefined." Even though the psABI says that "the
+ left half is undefined", set it to zero here. */
+ memset (buf, 0, 4);
+ memcpy (buf + 4, valbuf, 4);
+ valbuf = buf;
+ len = 8;
+ if (element < 16)
+ regnum = SPARC64_D0_REGNUM + element;
+ }
+ }
+ else
+ {
+ /* Integral and pointer arguments. */
+ gdb_assert (len == 8);
+ if (element < 6)
+ regnum = SPARC_O0_REGNUM + element;
+ }
+
+ if (regnum != -1)
+ {
+ regcache_cooked_write (regcache, regnum, valbuf);
+
+ /* If we're storing the value in a floating-point register,
+ also store it in the corresponding %0 register(s). */
+ if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D10_REGNUM)
+ {
+ gdb_assert (element < 6);
+ regnum = SPARC_O0_REGNUM + element;
+ regcache_cooked_write (regcache, regnum, valbuf);
+ }
+ else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q8_REGNUM)
+ {
+ gdb_assert (element < 6);
+ regnum = SPARC_O0_REGNUM + element;
+ regcache_cooked_write (regcache, regnum, valbuf);
+ regcache_cooked_write (regcache, regnum + 1, valbuf);
+ }
+ }
+
+ /* Always store the argument in memeory. */
+ write_memory (sp + element * 8, valbuf, len);
+ element += ((len + 7) / 8);
+ }
+
+ gdb_assert (element == num_elements);
+
+ /* Take BIAS into account. */
+ sp -= BIAS;
+ return sp;
+}
+
+static CORE_ADDR
+sparc64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ /* Set return address. */
+ regcache_cooked_write_unsigned (regcache, SPARC_O7_REGNUM, bp_addr - 8);
+
+ /* Set up function arguments. */
+ sp = sparc64_store_arguments (regcache, nargs, args, sp,
+ struct_return, struct_addr);
+
+ /* Allocate the register save area. */
+ sp -= 16 * 8;
+
+ /* Stack should be 16-byte aligned at this point. */
+ gdb_assert ((sp + BIAS) % 16 == 0);
+
+ /* Finally, update the stack pointer. */
+ regcache_cooked_write_unsigned (regcache, SPARC_SP_REGNUM, sp);
+
+ return sp;
+}
+
+
+/* Extract from an array REGBUF containing the (raw) register state, a
+ function return value of TYPE, and copy that into VALBUF. */
+
+static void
+sparc64_extract_return_value (struct type *type, struct regcache *regcache,
+ void *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ char buf[32];
+ int i;
+
+ if (sparc64_structure_or_union_p (type))
+ {
+ /* Structure or Union return values. */
+ gdb_assert (len <= 32);
+
+ for (i = 0; i < ((len + 7) / 8); i++)
+ regcache_cooked_read (regcache, SPARC_O0_REGNUM + i, buf + i * 8);
+ if (TYPE_CODE (type) != TYPE_CODE_UNION)
+ sparc64_extract_floating_fields (regcache, type, buf, 0);
+ memcpy (valbuf, buf, len);
+ }
+ else if (sparc64_floating_p (type))
+ {
+ /* Floating return values. */
+ for (i = 0; i < len / 4; i++)
+ regcache_cooked_read (regcache, SPARC_F0_REGNUM + i, buf + i * 4);
+ memcpy (valbuf, buf, len);
+ }
+ else
+ {
+ /* Integral and pointer return values. */
+ gdb_assert (sparc64_integral_or_pointer_p (type));
+
+ /* Just stripping off any unused bytes should preserve the
+ signed-ness just fine. */
+ regcache_cooked_read (regcache, SPARC_O0_REGNUM, buf);
+ memcpy (valbuf, buf + 8 - len, len);
+ }
+}
+
+/* Write into the appropriate registers a function return value stored
+ in VALBUF of type TYPE. */
+
+static void
+sparc64_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ char buf[16];
+ int i;
+
+ if (sparc64_structure_or_union_p (type))
+ {
+ /* Structure or Union return values. */
+ gdb_assert (len <= 32);
+
+ /* Simplify matters by storing the complete value (including
+ floating members) into %o0 and %o1. Floating members are
+ also store in the appropriate floating-point registers. */
+ memset (buf, 0, sizeof (buf));
+ memcpy (buf, valbuf, len);
+ for (i = 0; i < ((len + 7) / 8); i++)
+ regcache_cooked_write (regcache, SPARC_O0_REGNUM + i, buf + i * 8);
+ if (TYPE_CODE (type) != TYPE_CODE_UNION)
+ sparc64_store_floating_fields (regcache, type, buf, 0, 0);
+ }
+ else if (sparc64_floating_p (type))
+ {
+ /* Floating return values. */
+ memcpy (buf, valbuf, len);
+ for (i = 0; i < len / 4; i++)
+ regcache_cooked_write (regcache, SPARC_F0_REGNUM + i, buf + i * 4);
+ }
+ else
+ {
+ /* Integral and pointer return values. */
+ gdb_assert (sparc64_integral_or_pointer_p (type));
+
+ /* ??? Do we need to do any sign-extension here? */
+ memset (buf, 0, 8);
+ memcpy (buf + 8 - len, valbuf, len);
+ regcache_cooked_write (regcache, SPARC_O0_REGNUM, buf);
+ }
+}
+
+static enum return_value_convention
+sparc64_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ if (TYPE_LENGTH (type) > 32)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ if (readbuf)
+ sparc64_extract_return_value (type, regcache, readbuf);
+ if (writebuf)
+ sparc64_store_return_value (type, regcache, writebuf);
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
+void
+sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->pc_regnum = SPARC64_PC_REGNUM;
+ tdep->npc_regnum = SPARC64_NPC_REGNUM;
+
+ /* This is what all the fuss is about. */
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+
+ set_gdbarch_num_regs (gdbarch, SPARC64_NUM_REGS);
+ set_gdbarch_register_name (gdbarch, sparc64_register_name);
+ set_gdbarch_register_type (gdbarch, sparc64_register_type);
+ set_gdbarch_num_pseudo_regs (gdbarch, SPARC64_NUM_PSEUDO_REGS);
+ set_gdbarch_pseudo_register_read (gdbarch, sparc64_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, sparc64_pseudo_register_write);
+
+ /* Register numbers of various important registers. */
+ set_gdbarch_pc_regnum (gdbarch, SPARC64_PC_REGNUM); /* %pc */
+
+ /* Call dummy code. */
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_push_dummy_code (gdbarch, NULL);
+ set_gdbarch_push_dummy_call (gdbarch, sparc64_push_dummy_call);
+
+ set_gdbarch_return_value (gdbarch, sparc64_return_value);
+ set_gdbarch_stabs_argument_has_addr
+ (gdbarch, default_stabs_argument_has_addr);
+
+ set_gdbarch_skip_prologue (gdbarch, sparc64_skip_prologue);
+
+ frame_unwind_append_sniffer (gdbarch, sparc64_frame_sniffer);
+ frame_base_set_default (gdbarch, &sparc64_frame_base);
+}
+
+
+/* Helper functions for dealing with register sets. */
+
+#define TSTATE_CWP 0x000000000000001fULL
+#define TSTATE_ICC 0x0000000f00000000ULL
+#define TSTATE_XCC 0x000000f000000000ULL
+
+#define PSR_S 0x00000080
+#define PSR_ICC 0x00f00000
+#define PSR_VERS 0x0f000000
+#define PSR_IMPL 0xf0000000
+#define PSR_V8PLUS 0xff000000
+#define PSR_XCC 0x000f0000
+
+void
+sparc64_supply_gregset (const struct sparc_gregset *gregset,
+ struct regcache *regcache,
+ int regnum, const void *gregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ const char *regs = gregs;
+ int i;
+
+ if (sparc32)
+ {
+ if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
+ {
+ int offset = gregset->r_tstate_offset;
+ ULONGEST tstate, psr;
+ char buf[4];
+
+ tstate = extract_unsigned_integer (regs + offset, 8);
+ psr = ((tstate & TSTATE_CWP) | PSR_S | ((tstate & TSTATE_ICC) >> 12)
+ | ((tstate & TSTATE_XCC) >> 20) | PSR_V8PLUS);
+ store_unsigned_integer (buf, 4, psr);
+ regcache_raw_supply (regcache, SPARC32_PSR_REGNUM, buf);
+ }
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset + 4);
+
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset + 4);
+
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
+ {
+ int offset = gregset->r_y_offset + 8 - gregset->r_y_size;
+ regcache_raw_supply (regcache, SPARC32_Y_REGNUM, regs + offset);
+ }
+ }
+ else
+ {
+ if (regnum == SPARC64_STATE_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_STATE_REGNUM,
+ regs + gregset->r_tstate_offset);
+
+ if (regnum == SPARC64_PC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_PC_REGNUM,
+ regs + gregset->r_pc_offset);
+
+ if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_NPC_REGNUM,
+ regs + gregset->r_npc_offset);
+
+ if (regnum == SPARC64_Y_REGNUM || regnum == -1)
+ {
+ char buf[8];
+
+ memset (buf, 0, 8);
+ memcpy (buf + 8 - gregset->r_y_size,
+ regs + gregset->r_y_offset, gregset->r_y_size);
+ regcache_raw_supply (regcache, SPARC64_Y_REGNUM, buf);
+ }
+
+ if ((regnum == SPARC64_FPRS_REGNUM || regnum == -1)
+ && gregset->r_fprs_offset != -1)
+ regcache_raw_supply (regcache, SPARC64_FPRS_REGNUM,
+ regs + gregset->r_fprs_offset);
+ }
+
+ if (regnum == SPARC_G0_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC_G0_REGNUM, NULL);
+
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
+ {
+ int offset = gregset->r_g1_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ offset += 8;
+ }
+ }
+
+ if ((regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) || regnum == -1)
+ {
+ /* Not all of the register set variants include Locals and
+ Inputs. For those that don't, we read them off the stack. */
+ if (gregset->r_l0_offset == -1)
+ {
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ sparc_supply_rwindow (regcache, sp, regnum);
+ }
+ else
+ {
+ int offset = gregset->r_l0_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ offset += 8;
+ }
+ }
+ }
+}
+
+void
+sparc64_collect_gregset (const struct sparc_gregset *gregset,
+ const struct regcache *regcache,
+ int regnum, void *gregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ char *regs = gregs;
+ int i;
+
+ if (sparc32)
+ {
+ if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
+ {
+ int offset = gregset->r_tstate_offset;
+ ULONGEST tstate, psr;
+ char buf[8];
+
+ tstate = extract_unsigned_integer (regs + offset, 8);
+ regcache_raw_collect (regcache, SPARC32_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 4);
+ tstate |= (psr & PSR_ICC) << 12;
+ if ((psr & (PSR_VERS | PSR_IMPL)) == PSR_V8PLUS)
+ tstate |= (psr & PSR_XCC) << 20;
+ store_unsigned_integer (buf, 8, tstate);
+ memcpy (regs + offset, buf, 8);
+ }
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset + 4);
+
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset + 4);
+
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
+ {
+ int offset = gregset->r_y_offset + 8 - gregset->r_y_size;
+ regcache_raw_collect (regcache, SPARC32_Y_REGNUM, regs + offset);
+ }
+ }
+ else
+ {
+ if (regnum == SPARC64_STATE_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_STATE_REGNUM,
+ regs + gregset->r_tstate_offset);
+
+ if (regnum == SPARC64_PC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_PC_REGNUM,
+ regs + gregset->r_pc_offset);
+
+ if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_NPC_REGNUM,
+ regs + gregset->r_npc_offset);
+
+ if (regnum == SPARC64_Y_REGNUM || regnum == -1)
+ {
+ char buf[8];
+
+ regcache_raw_collect (regcache, SPARC64_Y_REGNUM, buf);
+ memcpy (regs + gregset->r_y_offset,
+ buf + 8 - gregset->r_y_size, gregset->r_y_size);
+ }
+
+ if ((regnum == SPARC64_FPRS_REGNUM || regnum == -1)
+ && gregset->r_fprs_offset != -1)
+ regcache_raw_collect (regcache, SPARC64_FPRS_REGNUM,
+ regs + gregset->r_fprs_offset);
+
+ }
+
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
+ {
+ int offset = gregset->r_g1_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ /* %g0 is always zero. */
+ for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ offset += 8;
+ }
+ }
+
+ if ((regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) || regnum == -1)
+ {
+ /* Not all of the register set variants include Locals and
+ Inputs. For those that don't, we read them off the stack. */
+ if (gregset->r_l0_offset != -1)
+ {
+ int offset = gregset->r_l0_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ offset += 8;
+ }
+ }
+ }
+}
+
+void
+sparc64_supply_fpregset (struct regcache *regcache,
+ int regnum, const void *fpregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ const char *regs = fpregs;
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
+ regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ }
+
+ if (sparc32)
+ {
+ if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8) + 4);
+ }
+ else
+ {
+ for (i = 0; i < 16; i++)
+ {
+ if (regnum == (SPARC64_F32_REGNUM + i) || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_F32_REGNUM + i,
+ regs + (32 * 4) + (i * 8));
+ }
+
+ if (regnum == SPARC64_FSR_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8));
+ }
+}
+
+void
+sparc64_collect_fpregset (const struct regcache *regcache,
+ int regnum, void *fpregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ char *regs = fpregs;
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
+ regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ }
+
+ if (sparc32)
+ {
+ if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8) + 4);
+ }
+ else
+ {
+ for (i = 0; i < 16; i++)
+ {
+ if (regnum == (SPARC64_F32_REGNUM + i) || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_F32_REGNUM + i,
+ regs + (32 * 4) + (i * 8));
+ }
+
+ if (regnum == SPARC64_FSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8));
+ }
+}
diff --git a/contrib/gdb/gdb/sparc64-tdep.h b/contrib/gdb/gdb/sparc64-tdep.h
new file mode 100644
index 0000000..c3073b9
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64-tdep.h
@@ -0,0 +1,123 @@
+/* Target-dependent code for UltraSPARC.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SPARC64_TDEP_H
+#define SPARC64_TDEP_H 1
+
+struct frame_info;
+struct gdbarch;
+struct regcache;
+struct sparc_gregset;
+struct trad_frame_saved_reg;
+
+#include "sparc-tdep.h"
+
+/* The stack pointer is offset from the stack frame by a BIAS of 2047
+ (0x7ff) for 64-bit code. BIAS is likely to be defined on SPARC
+ hosts, so undefine it first. */
+#undef BIAS
+#define BIAS 2047
+
+/* Register offsets for the general-purpose register set. */
+
+/* UltraSPARC doesn't have %psr. */
+#define r_tstate_offset r_psr_offset
+
+/* UltraSPARC doesn't have %wim either. */
+#define r_fprs_offset r_wim_offset
+
+/* Register numbers of various important registers. */
+
+enum sparc64_regnum
+{
+ SPARC64_F32_REGNUM /* %f32 */
+ = SPARC_F0_REGNUM + 32,
+ SPARC64_F62_REGNUM /* %f62 */
+ = SPARC64_F32_REGNUM + 15,
+ SPARC64_PC_REGNUM, /* %pc */
+ SPARC64_NPC_REGNUM, /* %npc */
+ SPARC64_STATE_REGNUM,
+ SPARC64_FSR_REGNUM, /* %fsr */
+ SPARC64_FPRS_REGNUM, /* %fprs */
+ SPARC64_Y_REGNUM, /* %y */
+
+ /* Pseudo registers. */
+ SPARC64_CWP_REGNUM, /* %cwp */
+ SPARC64_PSTATE_REGNUM, /* %pstate */
+ SPARC64_ASI_REGNUM, /* %asi */
+ SPARC64_CCR_REGNUM, /* %ccr */
+ SPARC64_D0_REGNUM, /* %d0 */
+ SPARC64_D10_REGNUM /* %d10 */
+ = SPARC64_D0_REGNUM + 5,
+ SPARC64_D30_REGNUM /* %d30 */
+ = SPARC64_D0_REGNUM + 15,
+ SPARC64_D32_REGNUM /* %d32 */
+ = SPARC64_D0_REGNUM + 16,
+ SPARC64_D62_REGNUM /* %d62 */
+ = SPARC64_D0_REGNUM + 31,
+ SPARC64_Q0_REGNUM, /* %q0 */
+ SPARC64_Q8_REGNUM /* %q8 */
+ = SPARC64_Q0_REGNUM + 2,
+ SPARC64_Q28_REGNUM /* %q28 */
+ = SPARC64_Q0_REGNUM + 7,
+ SPARC64_Q32_REGNUM /* %q32 */
+ = SPARC64_Q0_REGNUM + 8,
+ SPARC64_Q60_REGNUM /* %q60 */
+ = SPARC64_Q0_REGNUM + 15
+};
+
+extern void sparc64_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch);
+
+extern void sparc64_supply_gregset (const struct sparc_gregset *gregset,
+ struct regcache *regcache,
+ int regnum, const void *gregs);
+extern void sparc64_collect_gregset (const struct sparc_gregset *gregset,
+ const struct regcache *regcache,
+ int regnum, void *gregs);
+extern void sparc64_supply_fpregset (struct regcache *regcache,
+ int regnum, const void *fpregs);
+extern void sparc64_collect_fpregset (const struct regcache *regcache,
+ int regnum, void *fpregs);
+
+/* Functions and variables exported from sparc64-sol2-tdep.c. */
+
+/* Register offsets for Solaris 2. */
+extern const struct sparc_gregset sparc64_sol2_gregset;
+
+extern void sparc64_sol2_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch);
+
+/* Variables exported from sparc64fbsd-tdep.c. */
+
+/* Register offsets for FreeBSD/sparc64. */
+extern const struct sparc_gregset sparc64fbsd_gregset;
+
+/* Functions and variables exported from sparc64nbsd-tdep.c. */
+
+/* Register offsets for NetBSD/sparc64. */
+extern const struct sparc_gregset sparc64nbsd_gregset;
+
+extern struct trad_frame_saved_reg *
+ sparc64nbsd_sigcontext_saved_regs (CORE_ADDR sigcontext_addr,
+ struct frame_info *next_frame);
+
+#endif /* sparc64-tdep.h */
diff --git a/contrib/gdb/gdb/sparc64fbsd-nat.c b/contrib/gdb/gdb/sparc64fbsd-nat.c
new file mode 100644
index 0000000..09bf12a
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64fbsd-nat.c
@@ -0,0 +1,34 @@
+/* Native-dependent code for FreeBSD/sparc64.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "sparc64-tdep.h"
+#include "sparc-nat.h"
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc64fbsd_nat (void);
+
+void
+_initialize_sparc64fbsd_nat (void)
+{
+ sparc_gregset = &sparc64fbsd_gregset;
+}
diff --git a/contrib/gdb/gdb/sparc64fbsd-tdep.c b/contrib/gdb/gdb/sparc64fbsd-tdep.c
new file mode 100644
index 0000000..3c1335d
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64fbsd-tdep.c
@@ -0,0 +1,225 @@
+/* Target-dependent code for FreeBSD/sparc64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame-unwind.h"
+#include "gdbcore.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "regset.h"
+#include "target.h"
+#include "trad-frame.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "sparc64-tdep.h"
+
+/* From <machine/reg.h>. */
+const struct sparc_gregset sparc64fbsd_gregset =
+{
+ 26 * 8, /* "tstate" */
+ 25 * 8, /* %pc */
+ 24 * 8, /* %npc */
+ 28 * 8, /* %y */
+ 16 * 8, /* %fprs */
+ -1,
+ 1 * 8, /* %g1 */
+ -1, /* %l0 */
+ 8 /* sizeof (%y) */
+};
+
+
+static void
+sparc64fbsd_supply_gregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs, size_t len)
+{
+ sparc64_supply_gregset (regset->descr, regcache, regnum, gregs);
+}
+
+static void
+sparc64fbsd_supply_fpregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len)
+{
+ sparc64_supply_fpregset (regcache, regnum, fpregs);
+}
+
+
+/* Signal trampolines. */
+
+static int
+sparc64fbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ return (name && strcmp (name, "__sigtramp") == 0);
+}
+
+static struct sparc_frame_cache *
+sparc64fbsd_sigtramp_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR addr, mcontext_addr, sp;
+ LONGEST fprs;
+ int regnum;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* The third argument is a pointer to an instance of `ucontext_t',
+ which has a member `uc_mcontext' that contains the saved
+ registers. */
+ addr = frame_unwind_register_unsigned (next_frame, SPARC_O2_REGNUM);
+ mcontext_addr = addr + 64;
+
+ /* The following registers travel in the `mc_local' slots of
+ `mcontext_t'. */
+ addr = mcontext_addr + 16 * 8;
+ cache->saved_regs[SPARC64_FPRS_REGNUM].addr = addr + 0 * 8;
+ cache->saved_regs[SPARC64_FSR_REGNUM].addr = addr + 1 * 8;
+
+ /* The following registers travel in the `mc_in' slots of
+ `mcontext_t'. */
+ addr = mcontext_addr + 24 * 8;
+ cache->saved_regs[SPARC64_NPC_REGNUM].addr = addr + 0 * 8;
+ cache->saved_regs[SPARC64_PC_REGNUM].addr = addr + 1 * 8;
+ cache->saved_regs[SPARC64_STATE_REGNUM].addr = addr + 2 * 8;
+ cache->saved_regs[SPARC64_Y_REGNUM].addr = addr + 4 * 8;
+
+ /* The `global' and `out' registers travel in the `mc_global' and
+ `mc_out' slots of `mcontext_t', except for %g0. Since %g0 is
+ always zero, keep the identity encoding. */
+ for (regnum = SPARC_G1_REGNUM, addr = mcontext_addr + 8;
+ regnum <= SPARC_O7_REGNUM; regnum++, addr += 8)
+ cache->saved_regs[regnum].addr = addr;
+
+ /* The `local' and `in' registers have been saved in the register
+ save area. */
+ addr = cache->saved_regs[SPARC_SP_REGNUM].addr;
+ sp = get_frame_memory_unsigned (next_frame, addr, 8);
+ for (regnum = SPARC_L0_REGNUM, addr = sp + BIAS;
+ regnum <= SPARC_I7_REGNUM; regnum++, addr += 8)
+ cache->saved_regs[regnum].addr = addr;
+
+ /* The floating-point registers are only saved if the FEF bit in
+ %fprs has been set. */
+
+#define FPRS_FEF (1 << 2)
+
+ addr = cache->saved_regs[SPARC64_FPRS_REGNUM].addr;
+ fprs = get_frame_memory_unsigned (next_frame, addr, 8);
+ if (fprs & FPRS_FEF)
+ {
+ for (regnum = SPARC_F0_REGNUM, addr = mcontext_addr + 32 * 8;
+ regnum <= SPARC_F31_REGNUM; regnum++, addr += 4)
+ cache->saved_regs[regnum].addr = addr;
+
+ for (regnum = SPARC64_F32_REGNUM;
+ regnum <= SPARC64_F62_REGNUM; regnum++, addr += 8)
+ cache->saved_regs[regnum].addr = addr;
+ }
+
+ return cache;
+}
+
+static void
+sparc64fbsd_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc64fbsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc64fbsd_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc64fbsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc64fbsd_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ sparc64fbsd_sigtramp_frame_this_id,
+ sparc64fbsd_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc64fbsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (sparc64fbsd_pc_in_sigtramp (pc, name))
+ return &sparc64fbsd_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+
+static void
+sparc64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = &sparc64fbsd_gregset;
+ tdep->gregset->supply_regset = sparc64fbsd_supply_gregset;
+ tdep->sizeof_gregset = 256;
+
+ tdep->fpregset = XMALLOC (struct regset);
+ tdep->fpregset->supply_regset = sparc64fbsd_supply_fpregset;
+ tdep->sizeof_fpregset = 272;
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, sparc64fbsd_pc_in_sigtramp);
+ frame_unwind_append_sniffer (gdbarch, sparc64fbsd_sigtramp_frame_sniffer);
+
+ sparc64_init_abi (info, gdbarch);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc64fbsd_tdep (void);
+
+void
+_initialize_sparc64fbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
+ GDB_OSABI_FREEBSD_ELF, sparc64fbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/sparc64nbsd-nat.c b/contrib/gdb/gdb/sparc64nbsd-nat.c
new file mode 100644
index 0000000..9157703
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64nbsd-nat.c
@@ -0,0 +1,139 @@
+/* Native-dependent code for NetBSD/sparc64.
+
+ Copyright 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "sparc64-tdep.h"
+#include "sparc-nat.h"
+
+/* NetBSD is different from the other OSes that support both SPARC and
+ UltraSPARC in that the result of ptrace(2) depends on whether the
+ traced process is 32-bit or 64-bit. */
+
+static void
+sparc64nbsd_supply_gregset (const struct sparc_gregset *gregset,
+ struct regcache *regcache,
+ int regnum, const void *gregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+
+ if (sparc32)
+ sparc32_supply_gregset (&sparc32nbsd_gregset, regcache, regnum, gregs);
+ else
+ sparc64_supply_gregset (&sparc64nbsd_gregset, regcache, regnum, gregs);
+}
+
+static void
+sparc64nbsd_collect_gregset (const struct sparc_gregset *gregset,
+ const struct regcache *regcache,
+ int regnum, void *gregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+
+ if (sparc32)
+ sparc32_collect_gregset (&sparc32nbsd_gregset, regcache, regnum, gregs);
+ else
+ sparc64_collect_gregset (&sparc64nbsd_gregset, regcache, regnum, gregs);
+}
+
+static void
+sparc64nbsd_supply_fpregset (struct regcache *regcache,
+ int regnum, const void *fpregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+
+ if (sparc32)
+ sparc32_supply_fpregset (regcache, regnum, fpregs);
+ else
+ sparc64_supply_fpregset (regcache, regnum, fpregs);
+}
+
+static void
+sparc64nbsd_collect_fpregset (const struct regcache *regcache,
+ int regnum, void *fpregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+
+ if (sparc32)
+ sparc32_collect_fpregset (regcache, regnum, fpregs);
+ else
+ sparc64_collect_fpregset (regcache, regnum, fpregs);
+}
+
+/* Determine whether `gregset_t' contains register REGNUM. */
+
+static int
+sparc64nbsd_gregset_supplies_p (int regnum)
+{
+ if (gdbarch_ptr_bit (current_gdbarch) == 32)
+ return sparc32_gregset_supplies_p (regnum);
+
+ /* Integer registers. */
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
+ || (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+ || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
+ || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM))
+ return 1;
+
+ /* Control registers. */
+ if (regnum == SPARC64_PC_REGNUM
+ || regnum == SPARC64_NPC_REGNUM
+ || regnum == SPARC64_STATE_REGNUM
+ || regnum == SPARC64_Y_REGNUM)
+ return 1;
+
+ return 0;
+}
+
+/* Determine whether `fpregset_t' contains register REGNUM. */
+
+static int
+sparc64nbsd_fpregset_supplies_p (int regnum)
+{
+ if (gdbarch_ptr_bit (current_gdbarch) == 32)
+ return sparc32_fpregset_supplies_p (regnum);
+
+ /* Floating-point registers. */
+ if ((regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
+ || (regnum >= SPARC64_F32_REGNUM && regnum <= SPARC64_F62_REGNUM))
+ return 1;
+
+ /* Control registers. */
+ if (regnum == SPARC64_FSR_REGNUM)
+ return 1;
+
+ return 0;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparcnbsd_nat (void);
+
+void
+_initialize_sparcnbsd_nat (void)
+{
+ sparc_supply_gregset = sparc64nbsd_supply_gregset;
+ sparc_collect_gregset = sparc64nbsd_collect_gregset;
+ sparc_supply_fpregset = sparc64nbsd_supply_fpregset;
+ sparc_collect_fpregset = sparc64nbsd_collect_fpregset;
+ sparc_gregset_supplies_p = sparc64nbsd_gregset_supplies_p;
+ sparc_fpregset_supplies_p = sparc64nbsd_fpregset_supplies_p;
+}
diff --git a/contrib/gdb/gdb/sparc64nbsd-tdep.c b/contrib/gdb/gdb/sparc64nbsd-tdep.c
new file mode 100644
index 0000000..8e79870
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64nbsd-tdep.c
@@ -0,0 +1,256 @@
+/* Target-dependent code for NetBSD/sparc64.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+ Based on code contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame-unwind.h"
+#include "gdbcore.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "regset.h"
+#include "symtab.h"
+#include "solib-svr4.h"
+#include "trad-frame.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "sparc64-tdep.h"
+#include "nbsd-tdep.h"
+
+/* From <machine/reg.h>. */
+const struct sparc_gregset sparc64nbsd_gregset =
+{
+ 0 * 8, /* "tstate" */
+ 1 * 8, /* %pc */
+ 2 * 8, /* %npc */
+ 3 * 8, /* %y */
+ -1, /* %fprs */
+ -1,
+ 5 * 8, /* %g1 */
+ -1, /* %l0 */
+ 4 /* sizeof (%y) */
+};
+
+
+static void
+sparc64nbsd_supply_gregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs, size_t len)
+{
+ sparc64_supply_gregset (regset->descr, regcache, regnum, gregs);
+}
+
+static void
+sparc64nbsd_supply_fpregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len)
+{
+ sparc64_supply_fpregset (regcache, regnum, fpregs);
+}
+
+
+/* Signal trampolines. */
+
+/* The following variables describe the location of an on-stack signal
+ trampoline. The current values correspond to the memory layout for
+ NetBSD 1.3 and up. These shouldn't be necessary for NetBSD 2.0 and
+ up, since NetBSD uses signal trampolines provided by libc now. */
+
+static const CORE_ADDR sparc64nbsd_sigtramp_start = 0xffffffffffffdee4ULL;
+static const CORE_ADDR sparc64nbsd_sigtramp_end = 0xffffffffffffe000ULL;
+
+static int
+sparc64nbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ if (pc >= sparc64nbsd_sigtramp_start && pc < sparc64nbsd_sigtramp_end)
+ return 1;
+
+ return nbsd_pc_in_sigtramp (pc, name);
+}
+
+struct trad_frame_saved_reg *
+sparc64nbsd_sigcontext_saved_regs (CORE_ADDR sigcontext_addr,
+ struct frame_info *next_frame)
+{
+ struct trad_frame_saved_reg *saved_regs;
+ CORE_ADDR addr, sp;
+ int regnum, delta;
+
+ saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* The registers are saved in bits and pieces scattered all over the
+ place. The code below records their location on the assumption
+ that the part of the signal trampoline that saves the state has
+ been executed. */
+
+ saved_regs[SPARC_SP_REGNUM].addr = sigcontext_addr + 8;
+ saved_regs[SPARC64_PC_REGNUM].addr = sigcontext_addr + 16;
+ saved_regs[SPARC64_NPC_REGNUM].addr = sigcontext_addr + 24;
+ saved_regs[SPARC64_STATE_REGNUM].addr = sigcontext_addr + 32;
+ saved_regs[SPARC_G1_REGNUM].addr = sigcontext_addr + 40;
+ saved_regs[SPARC_O0_REGNUM].addr = sigcontext_addr + 48;
+
+ /* The remaining `global' registers and %y are saved in the `local'
+ registers. */
+ delta = SPARC_L0_REGNUM - SPARC_G0_REGNUM;
+ for (regnum = SPARC_G2_REGNUM; regnum <= SPARC_G7_REGNUM; regnum++)
+ saved_regs[regnum].realreg = regnum + delta;
+ saved_regs[SPARC64_Y_REGNUM].realreg = SPARC_L1_REGNUM;
+
+ /* The remaining `out' registers can be found in the current frame's
+ `in' registers. */
+ delta = SPARC_I0_REGNUM - SPARC_O0_REGNUM;
+ for (regnum = SPARC_O1_REGNUM; regnum <= SPARC_O5_REGNUM; regnum++)
+ saved_regs[regnum].realreg = regnum + delta;
+ saved_regs[SPARC_O7_REGNUM].realreg = SPARC_I7_REGNUM;
+
+ /* The `local' and `in' registers have been saved in the register
+ save area. */
+ addr = saved_regs[SPARC_SP_REGNUM].addr;
+ sp = get_frame_memory_unsigned (next_frame, addr, 8);
+ for (regnum = SPARC_L0_REGNUM, addr = sp + BIAS;
+ regnum <= SPARC_I7_REGNUM; regnum++, addr += 8)
+ saved_regs[regnum].addr = addr;
+
+ /* TODO: Handle the floating-point registers. */
+
+ return saved_regs;
+}
+
+static struct sparc_frame_cache *
+sparc64nbsd_sigcontext_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR addr;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ /* If we couldn't find the frame's function, we're probably dealing
+ with an on-stack signal trampoline. */
+ if (cache->pc == 0)
+ {
+ cache->pc = sparc64nbsd_sigtramp_start;
+
+ /* Since we couldn't find the frame's function, the cache was
+ initialized under the assumption that we're frameless. */
+ cache->frameless_p = 0;
+ addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+ cache->base = addr;
+ }
+
+ /* We find the appropriate instance of `struct sigcontext' at a
+ fixed offset in the signal frame. */
+ addr = cache->base + BIAS + 128 + 8;
+ cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
+
+ return cache;
+}
+
+static void
+sparc64nbsd_sigcontext_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc64nbsd_sigcontext_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc64nbsd_sigcontext_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc64nbsd_sigcontext_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc64nbsd_sigcontext_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ sparc64nbsd_sigcontext_frame_this_id,
+ sparc64nbsd_sigcontext_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc64nbsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (sparc64nbsd_pc_in_sigtramp (pc, name))
+ {
+ if (name == NULL || strncmp (name, "__sigtramp_sigcontext", 21))
+ return &sparc64nbsd_sigcontext_frame_unwind;
+ }
+
+ return NULL;
+}
+
+
+static void
+sparc64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = &sparc64nbsd_gregset;
+ tdep->gregset->supply_regset = sparc64nbsd_supply_gregset;
+ tdep->sizeof_gregset = 160;
+
+ tdep->fpregset = XMALLOC (struct regset);
+ tdep->fpregset->supply_regset = sparc64nbsd_supply_fpregset;
+ tdep->sizeof_fpregset = 272;
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, sparc64nbsd_pc_in_sigtramp);
+ frame_unwind_append_sniffer (gdbarch, sparc64nbsd_sigtramp_frame_sniffer);
+
+ sparc64_init_abi (info, gdbarch);
+
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, nbsd_lp64_solib_svr4_fetch_link_map_offsets);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc64nbsd_tdep (void);
+
+void
+_initialize_sparc64nbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
+ GDB_OSABI_NETBSD_ELF, sparc64nbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/sparc64obsd-tdep.c b/contrib/gdb/gdb/sparc64obsd-tdep.c
new file mode 100644
index 0000000..190a46b
--- /dev/null
+++ b/contrib/gdb/gdb/sparc64obsd-tdep.c
@@ -0,0 +1,210 @@
+/* Target-dependent code for OpenBSD/sparc64.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "frame-unwind.h"
+#include "osabi.h"
+#include "regset.h"
+#include "symtab.h"
+#include "solib-svr4.h"
+#include "trad-frame.h"
+
+#include "gdb_assert.h"
+
+#include "sparc64-tdep.h"
+#include "nbsd-tdep.h"
+
+/* OpenBSD uses the traditional NetBSD core file format, even for
+ ports that use ELF. The core files don't use multiple register
+ sets. Instead, the general-purpose and floating-point registers
+ are lumped together in a single section. Unlike on NetBSD, OpenBSD
+ uses a different layout for its general-purpose registers than the
+ layout used for ptrace(2). */
+
+/* From <machine/reg.h>. */
+const struct sparc_gregset sparc64obsd_core_gregset =
+{
+ 0 * 8, /* "tstate" */
+ 1 * 8, /* %pc */
+ 2 * 8, /* %npc */
+ 3 * 8, /* %y */
+ -1, /* %fprs */
+ -1,
+ 7 * 8, /* %g1 */
+ 22 * 8, /* %l0 */
+ 4 /* sizeof (%y) */
+};
+
+static void
+sparc64obsd_supply_gregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs, size_t len)
+{
+ const char *regs = gregs;
+
+ sparc64_supply_gregset (regset->descr, regcache, regnum, regs);
+ sparc64_supply_fpregset (regcache, regnum, regs + 288);
+}
+
+
+/* Signal trampolines. */
+
+/* The OpenBSD kernel maps the signal trampoline at some random
+ location in user space, which means that the traditional BSD way of
+ detecting it won't work.
+
+ The signal trampoline will be mapped at an address that is page
+ aligned. We recognize the signal trampoline by the looking for the
+ sigreturn system call. */
+
+static const int sparc64obsd_page_size = 8192;
+
+static int
+sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
+ unsigned long insn;
+
+ if (name)
+ return 0;
+
+ /* Check for "restore %g0, SYS_sigreturn, %g1". */
+ insn = sparc_fetch_instruction (start_pc + 0xe8);
+ if (insn != 0x83e82067)
+ return 0;
+
+ /* Check for "t ST_SYSCALL". */
+ insn = sparc_fetch_instruction (start_pc + 0xf0);
+ if (insn != 0x91d02000)
+ return 0;
+
+ return 1;
+}
+
+static struct sparc_frame_cache *
+sparc64obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR addr;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ /* If we couldn't find the frame's function, we're probably dealing
+ with an on-stack signal trampoline. */
+ if (cache->pc == 0)
+ {
+ cache->pc = frame_pc_unwind (next_frame);
+ cache->pc &= ~(sparc64obsd_page_size - 1);
+
+ /* Since we couldn't find the frame's function, the cache was
+ initialized under the assumption that we're frameless. */
+ cache->frameless_p = 0;
+ addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+ cache->base = addr;
+ }
+
+ /* We find the appropriate instance of `struct sigcontext' at a
+ fixed offset in the signal frame. */
+ addr = cache->base + BIAS + 128 + 16;
+ cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
+
+ return cache;
+}
+
+static void
+sparc64obsd_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc64obsd_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc64obsd_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc64obsd_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc64obsd_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ sparc64obsd_frame_this_id,
+ sparc64obsd_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (sparc64obsd_pc_in_sigtramp (pc, name))
+ return &sparc64obsd_frame_unwind;
+
+ return NULL;
+}
+
+
+static void
+sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = &sparc64obsd_core_gregset;
+ tdep->gregset->supply_regset = sparc64obsd_supply_gregset;
+ tdep->sizeof_gregset = 832;
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, sparc64obsd_pc_in_sigtramp);
+ frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer);
+
+ sparc64_init_abi (info, gdbarch);
+
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, nbsd_lp64_solib_svr4_fetch_link_map_offsets);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc64obsd_tdep (void);
+
+void
+_initialize_sparc64obsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
+ GDB_OSABI_OPENBSD_ELF, sparc64obsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/sparcnbsd-nat.c b/contrib/gdb/gdb/sparcnbsd-nat.c
new file mode 100644
index 0000000..9038ea3
--- /dev/null
+++ b/contrib/gdb/gdb/sparcnbsd-nat.c
@@ -0,0 +1,34 @@
+/* Native-dependent code for NetBSD/sparc.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "sparc-tdep.h"
+#include "sparc-nat.h"
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparcnbsd_nat (void);
+
+void
+_initialize_sparcnbsd_nat (void)
+{
+ sparc_gregset = &sparc32nbsd_gregset;
+}
diff --git a/contrib/gdb/gdb/sparcnbsd-tdep.c b/contrib/gdb/gdb/sparcnbsd-tdep.c
new file mode 100644
index 0000000..b1be7eb
--- /dev/null
+++ b/contrib/gdb/gdb/sparcnbsd-tdep.c
@@ -0,0 +1,358 @@
+/* Target-dependent code for NetBSD/sparc.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "floatformat.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "gdbcore.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "regset.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "trad-frame.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "sparc-tdep.h"
+#include "nbsd-tdep.h"
+
+const struct sparc_gregset sparc32nbsd_gregset =
+{
+ 0 * 4, /* %psr */
+ 1 * 4, /* %pc */
+ 2 * 4, /* %npc */
+ 3 * 4, /* %y */
+ -1, /* %wim */
+ -1, /* %tbr */
+ 5 * 4, /* %g1 */
+ -1 /* %l0 */
+};
+
+static void
+sparc32nbsd_supply_gregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs, size_t len)
+{
+ sparc32_supply_gregset (regset->descr, regcache, regnum, gregs);
+
+ /* Traditional NetBSD core files don't use multiple register sets.
+ Instead, the general-purpose and floating-point registers are
+ lumped together in a single section. */
+ if (len >= 212)
+ sparc32_supply_fpregset (regcache, regnum, (const char *) gregs + 80);
+}
+
+static void
+sparc32nbsd_supply_fpregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len)
+{
+ sparc32_supply_fpregset (regcache, regnum, fpregs);
+}
+
+
+/* Signal trampolines. */
+
+/* The following variables describe the location of an on-stack signal
+ trampoline. The current values correspond to the memory layout for
+ NetBSD 1.3 and up. These shouldn't be necessary for NetBSD 2.0 and
+ up, since NetBSD uses signal trampolines provided by libc now. */
+
+static const CORE_ADDR sparc32nbsd_sigtramp_start = 0xeffffef0;
+static const CORE_ADDR sparc32nbsd_sigtramp_end = 0xeffffff0;
+
+static int
+sparc32nbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ if (pc >= sparc32nbsd_sigtramp_start && pc < sparc32nbsd_sigtramp_end)
+ return 1;
+
+ return nbsd_pc_in_sigtramp (pc, name);
+}
+
+struct trad_frame_saved_reg *
+sparc32nbsd_sigcontext_saved_regs (struct frame_info *next_frame)
+{
+ struct trad_frame_saved_reg *saved_regs;
+ CORE_ADDR addr, sigcontext_addr;
+ int regnum, delta;
+ ULONGEST psr;
+
+ saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* We find the appropriate instance of `struct sigcontext' at a
+ fixed offset in the signal frame. */
+ addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+ sigcontext_addr = addr + 64 + 16;
+
+ /* The registers are saved in bits and pieces scattered all over the
+ place. The code below records their location on the assumption
+ that the part of the signal trampoline that saves the state has
+ been executed. */
+
+ saved_regs[SPARC_SP_REGNUM].addr = sigcontext_addr + 8;
+ saved_regs[SPARC32_PC_REGNUM].addr = sigcontext_addr + 12;
+ saved_regs[SPARC32_NPC_REGNUM].addr = sigcontext_addr + 16;
+ saved_regs[SPARC32_PSR_REGNUM].addr = sigcontext_addr + 20;
+ saved_regs[SPARC_G1_REGNUM].addr = sigcontext_addr + 24;
+ saved_regs[SPARC_O0_REGNUM].addr = sigcontext_addr + 28;
+
+ /* The remaining `global' registers and %y are saved in the `local'
+ registers. */
+ delta = SPARC_L0_REGNUM - SPARC_G0_REGNUM;
+ for (regnum = SPARC_G2_REGNUM; regnum <= SPARC_G7_REGNUM; regnum++)
+ saved_regs[regnum].realreg = regnum + delta;
+ saved_regs[SPARC32_Y_REGNUM].realreg = SPARC_L1_REGNUM;
+
+ /* The remaining `out' registers can be found in the current frame's
+ `in' registers. */
+ delta = SPARC_I0_REGNUM - SPARC_O0_REGNUM;
+ for (regnum = SPARC_O1_REGNUM; regnum <= SPARC_O5_REGNUM; regnum++)
+ saved_regs[regnum].realreg = regnum + delta;
+ saved_regs[SPARC_O7_REGNUM].realreg = SPARC_I7_REGNUM;
+
+ /* The `local' and `in' registers have been saved in the register
+ save area. */
+ addr = saved_regs[SPARC_SP_REGNUM].addr;
+ addr = get_frame_memory_unsigned (next_frame, addr, 4);
+ for (regnum = SPARC_L0_REGNUM;
+ regnum <= SPARC_I7_REGNUM; regnum++, addr += 4)
+ saved_regs[regnum].addr = addr;
+
+ /* Handle StackGhost. */
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+
+ if (wcookie != 0)
+ {
+ ULONGEST i7;
+
+ addr = saved_regs[SPARC_I7_REGNUM].addr;
+ i7 = get_frame_memory_unsigned (next_frame, addr, 4);
+ trad_frame_set_value (saved_regs, SPARC_I7_REGNUM, i7 ^ wcookie);
+ }
+ }
+
+ /* The floating-point registers are only saved if the EF bit in %prs
+ has been set. */
+
+#define PSR_EF 0x00001000
+
+ addr = saved_regs[SPARC32_PSR_REGNUM].addr;
+ psr = get_frame_memory_unsigned (next_frame, addr, 4);
+ if (psr & PSR_EF)
+ {
+ CORE_ADDR sp;
+
+ sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
+ saved_regs[SPARC32_FSR_REGNUM].addr = sp + 96;
+ for (regnum = SPARC_F0_REGNUM, addr = sp + 96 + 8;
+ regnum <= SPARC_F31_REGNUM; regnum++, addr += 4)
+ saved_regs[regnum].addr = addr;
+ }
+
+ return saved_regs;
+}
+
+static struct sparc_frame_cache *
+sparc32nbsd_sigcontext_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR addr;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ /* If we couldn't find the frame's function, we're probably dealing
+ with an on-stack signal trampoline. */
+ if (cache->pc == 0)
+ {
+ cache->pc = sparc32nbsd_sigtramp_start;
+
+ /* Since we couldn't find the frame's function, the cache was
+ initialized under the assumption that we're frameless. */
+ cache->frameless_p = 0;
+ addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+ cache->base = addr;
+ }
+
+ cache->saved_regs = sparc32nbsd_sigcontext_saved_regs (next_frame);
+
+ return cache;
+}
+
+static void
+sparc32nbsd_sigcontext_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc32nbsd_sigcontext_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc32nbsd_sigcontext_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc32nbsd_sigcontext_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc32nbsd_sigcontext_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ sparc32nbsd_sigcontext_frame_this_id,
+ sparc32nbsd_sigcontext_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc32nbsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (sparc32nbsd_pc_in_sigtramp (pc, name))
+ {
+ if (name == NULL || strncmp (name, "__sigtramp_sigcontext", 21))
+ return &sparc32nbsd_sigcontext_frame_unwind;
+ }
+
+ return NULL;
+}
+
+
+/* Return non-zero if we are in a shared library trampoline code stub. */
+
+static int
+sparcnbsd_aout_in_solib_call_trampoline (CORE_ADDR pc, char *name)
+{
+ return (name && !strcmp (name, "_DYNAMIC"));
+}
+
+static void
+sparc32nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* NetBSD doesn't support the 128-bit `long double' from the psABI. */
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
+
+ tdep->gregset = XMALLOC (struct regset);
+ tdep->gregset->descr = &sparc32nbsd_gregset;
+ tdep->gregset->supply_regset = sparc32nbsd_supply_gregset;
+ tdep->sizeof_gregset = 20 * 4;
+
+ tdep->fpregset = XMALLOC (struct regset);
+ tdep->fpregset->supply_regset = sparc32nbsd_supply_fpregset;
+ tdep->sizeof_fpregset = 33 * 4;
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, sparc32nbsd_pc_in_sigtramp);
+ frame_unwind_append_sniffer (gdbarch, sparc32nbsd_sigtramp_frame_sniffer);
+}
+
+static void
+sparc32nbsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ sparc32nbsd_init_abi (info, gdbarch);
+
+ set_gdbarch_in_solib_call_trampoline
+ (gdbarch, sparcnbsd_aout_in_solib_call_trampoline);
+}
+
+static void
+sparc32nbsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ sparc32nbsd_init_abi (info, gdbarch);
+
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+}
+
+static enum gdb_osabi
+sparcnbsd_aout_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "a.out-sparc-netbsd") == 0)
+ return GDB_OSABI_NETBSD_AOUT;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+/* OpenBSD uses the traditional NetBSD core file format, even for
+ ports that use ELF. Therefore, if the default OS ABI is OpenBSD
+ ELF, we return that instead of NetBSD a.out. This is mainly for
+ the benfit of OpenBSD/sparc64, which inherits the sniffer below
+ since we include this file for an OpenBSD/sparc64 target. For
+ OpenBSD/sparc, the NetBSD a.out OS ABI is probably similar enough
+ to both the OpenBSD a.out and the OpenBSD ELF OS ABI. */
+#if defined (GDB_OSABI_DEFAULT) && (GDB_OSABI_DEFAULT == GDB_OSABI_OPENBSD_ELF)
+#define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF
+#else
+#define GDB_OSABI_NETBSD_CORE GDB_OSABI_NETBSD_AOUT
+#endif
+
+static enum gdb_osabi
+sparcnbsd_core_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
+ return GDB_OSABI_NETBSD_CORE;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparcnbsd_tdep (void);
+
+void
+_initialize_sparnbsd_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_sparc, bfd_target_aout_flavour,
+ sparcnbsd_aout_osabi_sniffer);
+
+ /* BFD doesn't set the architecture for NetBSD style a.out core
+ files. */
+ gdbarch_register_osabi_sniffer (bfd_arch_unknown, bfd_target_unknown_flavour,
+ sparcnbsd_core_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_NETBSD_AOUT,
+ sparc32nbsd_aout_init_abi);
+ gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_NETBSD_ELF,
+ sparc32nbsd_elf_init_abi);
+}
diff --git a/contrib/gdb/gdb/sparcobsd-tdep.c b/contrib/gdb/gdb/sparcobsd-tdep.c
new file mode 100644
index 0000000..108e255
--- /dev/null
+++ b/contrib/gdb/gdb/sparcobsd-tdep.c
@@ -0,0 +1,171 @@
+/* Target-dependent code for OpenBSD/sparc.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "floatformat.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "osabi.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "trad-frame.h"
+
+#include "gdb_assert.h"
+
+#include "sparc-tdep.h"
+#include "nbsd-tdep.h"
+
+/* Signal trampolines. */
+
+/* The OpenBSD kernel maps the signal trampoline at some random
+ location in user space, which means that the traditional BSD way of
+ detecting it won't work.
+
+ The signal trampoline will be mapped at an address that is page
+ aligned. We recognize the signal trampoline by the looking for the
+ sigreturn system call. */
+
+static const int sparc32obsd_page_size = 4096;
+
+static int
+sparc32obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ CORE_ADDR start_pc = (pc & ~(sparc32obsd_page_size - 1));
+ unsigned long insn;
+
+ if (name)
+ return 0;
+
+ /* Check for "restore %g0, SYS_sigreturn, %g1". */
+ insn = sparc_fetch_instruction (start_pc + 0xec);
+ if (insn != 0x83e82067)
+ return 0;
+
+ /* Check for "t ST_SYSCALL". */
+ insn = sparc_fetch_instruction (start_pc + 0xf4);
+ if (insn != 0x91d02000)
+ return 0;
+
+ return 1;
+}
+
+static struct sparc_frame_cache *
+sparc32obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR addr;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (next_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ /* If we couldn't find the frame's function, we're probably dealing
+ with an on-stack signal trampoline. */
+ if (cache->pc == 0)
+ {
+ cache->pc = frame_pc_unwind (next_frame);
+ cache->pc &= ~(sparc32obsd_page_size - 1);
+
+ /* Since we couldn't find the frame's function, the cache was
+ initialized under the assumption that we're frameless. */
+ cache->frameless_p = 0;
+ addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+ cache->base = addr;
+ }
+
+ cache->saved_regs = sparc32nbsd_sigcontext_saved_regs (next_frame);
+
+ return cache;
+}
+
+static void
+sparc32obsd_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc32obsd_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static void
+sparc32obsd_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct sparc_frame_cache *cache =
+ sparc32obsd_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind sparc32obsd_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ sparc32obsd_frame_this_id,
+ sparc32obsd_frame_prev_register
+};
+
+static const struct frame_unwind *
+sparc32obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (sparc32obsd_pc_in_sigtramp (pc, name))
+ return &sparc32obsd_frame_unwind;
+
+ return NULL;
+}
+
+
+static void
+sparc32obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
+
+ set_gdbarch_pc_in_sigtramp (gdbarch, sparc32obsd_pc_in_sigtramp);
+ frame_unwind_append_sniffer (gdbarch, sparc32obsd_sigtramp_frame_sniffer);
+
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc32obsd_tdep (void);
+
+void
+_initialize_sparc32obsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_OPENBSD_ELF,
+ sparc32obsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/srec.h b/contrib/gdb/gdb/srec.h
new file mode 100644
index 0000000..8189a9b
--- /dev/null
+++ b/contrib/gdb/gdb/srec.h
@@ -0,0 +1,39 @@
+/* S-record download support for GDB, the GNU debugger.
+ Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 serial;
+
+void load_srec (struct serial *desc, const char *file, bfd_vma load_offset,
+ int maxrecsize, int flags, int hashmark,
+ int (*waitack) (void));
+
+/* 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 0000000..5cee516
--- /dev/null
+++ b/contrib/gdb/gdb/stabsread.c
@@ -0,0 +1,4456 @@
+/* Support routines for decoding "stabs" debugging information format.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_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 "doublest.h"
+#include "cp-abi.h"
+#include "cp-support.h"
+
+#include <ctype.h>
+
+/* Ask stabsread.h to define the vars it normally declares `extern'. */
+#define EXTERN
+/**/
+#include "stabsread.h" /* Our own declarations */
+#undef EXTERN
+
+extern void _initialize_stabsread (void);
+
+/* 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 void
+read_one_struct_field (struct field_info *, char **, char *,
+ struct type *, struct objfile *);
+
+static struct type *dbx_alloc_type (int[2], struct objfile *);
+
+static long read_huge_number (char **, int, int *);
+
+static struct type *error_type (char **, struct objfile *);
+
+static void
+patch_block_stabs (struct pending *, struct pending_stabs *,
+ struct objfile *);
+
+static void fix_common_block (struct symbol *, int);
+
+static int read_type_number (char **, int *);
+
+static struct type *read_type (char **, struct objfile *);
+
+static struct type *read_range_type (char **, int[2], struct objfile *);
+
+static struct type *read_sun_builtin_type (char **, int[2], struct objfile *);
+
+static struct type *read_sun_floating_type (char **, int[2],
+ struct objfile *);
+
+static struct type *read_enum_type (char **, struct type *, struct objfile *);
+
+static struct type *rs6000_builtin_type (int);
+
+static int
+read_member_functions (struct field_info *, char **, struct type *,
+ struct objfile *);
+
+static int
+read_struct_fields (struct field_info *, char **, struct type *,
+ struct objfile *);
+
+static int
+read_baseclasses (struct field_info *, char **, struct type *,
+ struct objfile *);
+
+static int
+read_tilde_fields (struct field_info *, char **, struct type *,
+ struct objfile *);
+
+static int attach_fn_fields_to_type (struct field_info *, struct type *);
+
+static int attach_fields_to_type (struct field_info *, struct type *,
+ struct objfile *);
+
+static struct type *read_struct_type (char **, struct type *,
+ enum type_code,
+ struct objfile *);
+
+static struct type *read_array_type (char **, struct type *,
+ struct objfile *);
+
+static struct field *read_args (char **, int, struct objfile *, int *, int *);
+
+static void add_undefined_type (struct type *);
+
+static int
+read_cpp_abbrev (struct field_info *, char **, struct type *,
+ struct objfile *);
+
+static char *find_name_end (char *name);
+
+static int process_reference (char **string);
+
+void stabsread_clear_cache (void);
+
+static const char vptr_name[] = "_vptr$";
+static const char vb_name[] = "_vb$";
+
+/* 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. */
+
+#if !defined (BELIEVE_PCC_PROMOTION)
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+
+static void
+invalid_cpp_abbrev_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints, "invalid C++ abbreviation `%s'", arg1);
+}
+
+static void
+reg_value_complaint (int arg1, int arg2, const char *arg3)
+{
+ complaint (&symfile_complaints,
+ "register number %d too large (max %d) in symbol %s", arg1, arg2,
+ arg3);
+}
+
+static void
+stabs_general_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints, "%s", arg1);
+}
+
+/* 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)
+
+
+/* Look up a dbx type-number pair. Return the address of the slot
+ where the type for that number-pair is stored.
+ The number-pair is in TYPENUMS.
+
+ This can be used for finding the type associated with that pair
+ or for associating a new type with the pair. */
+
+static struct type **
+dbx_lookup_type (int typenums[2])
+{
+ int filenum = typenums[0];
+ int index = typenums[1];
+ unsigned old_len;
+ int real_filenum;
+ struct header_file *f;
+ int f_orig_length;
+
+ if (filenum == -1) /* -1,-1 is for temporary types. */
+ return 0;
+
+ if (filenum < 0 || filenum >= n_this_object_header_files)
+ {
+ complaint (&symfile_complaints,
+ "Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+ 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 *));
+ }
+ return (&type_vector[index]);
+ }
+ else
+ {
+ real_filenum = this_object_header_files[filenum];
+
+ if (real_filenum >= N_HEADER_FILES (current_objfile))
+ {
+ 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 (current_objfile) + 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 (int typenums[2], struct objfile *objfile)
+{
+ 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 (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->objfile_obstack,
+ sizeof (struct symbol));
+
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+ DEPRECATED_SYMBOL_NAME (sym) =
+ obsavestring (name, pp - name, &objfile->objfile_obstack);
+ 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 (char **pp, 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;
+}
+
+
+#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 */
+
+/* Structure for storing pointers to reference definitions for fast lookup
+ during "process_later". */
+
+struct ref_map
+{
+ char *stabs;
+ CORE_ADDR value;
+ struct symbol *sym;
+};
+
+#define MAX_CHUNK_REFS 100
+#define REF_CHUNK_SIZE (MAX_CHUNK_REFS * sizeof (struct ref_map))
+#define REF_MAP_SIZE(ref_chunk) ((ref_chunk) * REF_CHUNK_SIZE)
+
+static struct ref_map *ref_map;
+
+/* Ptr to free cell in chunk's linked list. */
+static int ref_count = 0;
+
+/* Number of chunks malloced. */
+static int ref_chunk = 0;
+
+/* This file maintains a cache of stabs aliases found in the symbol
+ table. If the symbol table changes, this cache must be cleared
+ or we are left holding onto data in invalid obstacks. */
+void
+stabsread_clear_cache (void)
+{
+ ref_count = 0;
+ ref_chunk = 0;
+}
+
+/* Create array of pointers mapping refids to symbols and stab strings.
+ Add pointers to reference definition symbols and/or their values as we
+ find them, using their reference numbers as our index.
+ These will be used later when we resolve references. */
+void
+ref_add (int refnum, struct symbol *sym, char *stabs, CORE_ADDR value)
+{
+ if (ref_count == 0)
+ ref_chunk = 0;
+ if (refnum >= ref_count)
+ ref_count = refnum + 1;
+ if (ref_count > ref_chunk * MAX_CHUNK_REFS)
+ {
+ int new_slots = ref_count - ref_chunk * MAX_CHUNK_REFS;
+ int new_chunks = new_slots / MAX_CHUNK_REFS + 1;
+ ref_map = (struct ref_map *)
+ xrealloc (ref_map, REF_MAP_SIZE (ref_chunk + new_chunks));
+ memset (ref_map + ref_chunk * MAX_CHUNK_REFS, 0, new_chunks * REF_CHUNK_SIZE);
+ ref_chunk += new_chunks;
+ }
+ ref_map[refnum].stabs = stabs;
+ ref_map[refnum].sym = sym;
+ ref_map[refnum].value = value;
+}
+
+/* Return defined sym for the reference REFNUM. */
+struct symbol *
+ref_search (int refnum)
+{
+ if (refnum < 0 || refnum > ref_count)
+ return 0;
+ return ref_map[refnum].sym;
+}
+
+/* Parse a reference id in STRING and return the resulting
+ reference number. Move STRING beyond the reference id. */
+
+static int
+process_reference (char **string)
+{
+ char *p;
+ int refnum = 0;
+
+ if (**string != '#')
+ return 0;
+
+ /* Advance beyond the initial '#'. */
+ p = *string + 1;
+
+ /* Read number as reference id. */
+ while (*p && isdigit (*p))
+ {
+ refnum = refnum * 10 + *p - '0';
+ p++;
+ }
+ *string = p;
+ return refnum;
+}
+
+/* If STRING defines a reference, store away a pointer to the reference
+ definition for later use. Return the reference number. */
+
+int
+symbol_reference_defined (char **string)
+{
+ char *p = *string;
+ int refnum = 0;
+
+ refnum = process_reference (&p);
+
+ /* Defining symbols end in '=' */
+ if (*p == '=')
+ {
+ /* Symbol is being defined here. */
+ *string = p + 1;
+ return refnum;
+ }
+ else
+ {
+ /* Must be a reference. Either the symbol has already been defined,
+ or this is a forward reference to it. */
+ *string = p;
+ return -1;
+ }
+}
+
+struct symbol *
+define_symbol (CORE_ADDR valu, char *string, int desc, int type,
+ struct objfile *objfile)
+{
+ struct symbol *sym;
+ char *p = (char *) find_name_end (string);
+ int deftype;
+ int synonym = 0;
+ 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->objfile_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+
+ switch (type & N_TYPE)
+ {
+ case N_TEXT:
+ SYMBOL_SECTION (sym) = SECT_OFF_TEXT (objfile);
+ break;
+ case N_DATA:
+ SYMBOL_SECTION (sym) = SECT_OFF_DATA (objfile);
+ break;
+ case N_BSS:
+ SYMBOL_SECTION (sym) = SECT_OFF_BSS (objfile);
+ 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':
+ DEPRECATED_SYMBOL_NAME (sym) = obsavestring ("this", strlen ("this"),
+ &objfile->objfile_obstack);
+ break;
+
+ case 'v': /* $vtbl_ptr_type */
+ /* Was: DEPRECATED_SYMBOL_NAME (sym) = "vptr"; */
+ goto normal;
+
+ case 'e':
+ DEPRECATED_SYMBOL_NAME (sym) = obsavestring ("eh_throw", strlen ("eh_throw"),
+ &objfile->objfile_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:
+ complaint (&symfile_complaints, "Unknown C++ symbol name `%s'",
+ string);
+ goto normal; /* Do *something* with it */
+ }
+ }
+ else
+ {
+ normal:
+ SYMBOL_LANGUAGE (sym) = current_subfile->language;
+ SYMBOL_SET_NAMES (sym, string, p - string, objfile);
+ }
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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->objfile_obstack,
+ TYPE_LENGTH (SYMBOL_TYPE (sym)));
+ store_typed_floating (dbl_valu, 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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));
+
+ /* All functions in C++ have prototypes. Stabs does not offer an
+ explicit way to identify prototyped or unprototyped functions,
+ but both GCC and Sun CC emit stabs for the "call-as" type rather
+ than the "declared-as" type for unprototyped functions, so
+ we treat all functions as if they were prototyped. This is used
+ primarily for promotion when calling the function from GDB. */
+ TYPE_FLAGS (SYMBOL_TYPE (sym)) |= TYPE_FLAG_PROTOTYPED;
+
+ /* fall into process_prototype_types */
+
+ process_prototype_types:
+ /* Sun acc puts declared types of arguments here. */
+ if (*p == ';')
+ {
+ struct type *ftype = SYMBOL_TYPE (sym);
+ int nsemi = 0;
+ int nparams = 0;
+ char *p1 = p;
+
+ /* Obtain a worst case guess for the number of arguments
+ by counting the semicolons. */
+ while (*p1)
+ {
+ if (*p1++ == ';')
+ nsemi++;
+ }
+
+ /* Allocate parameter information fields and fill them in. */
+ TYPE_FIELDS (ftype) = (struct field *)
+ TYPE_ALLOC (ftype, nsemi * sizeof (struct field));
+ while (*p++ == ';')
+ {
+ struct type *ptype;
+
+ /* A type number of zero indicates the start of varargs.
+ FIXME: GDB currently ignores vararg functions. */
+ if (p[0] == '0' && p[1] == '\0')
+ break;
+ ptype = read_type (&p, objfile);
+
+ /* The Sun compilers mark integer arguments, which should
+ be promoted to the width of the calling conventions, with
+ a type which references itself. This type is turned into
+ a TYPE_CODE_VOID type by read_type, and we have to turn
+ it back into builtin_type_int here.
+ FIXME: Do we need a new builtin_type_promoted_int_arg ? */
+ if (TYPE_CODE (ptype) == TYPE_CODE_VOID)
+ ptype = builtin_type_int;
+ TYPE_FIELD_TYPE (ftype, nparams) = ptype;
+ TYPE_FIELD_ARTIFICIAL (ftype, nparams++) = 0;
+ }
+ TYPE_NFIELDS (ftype) = nparams;
+ TYPE_FLAGS (ftype) |= TYPE_FLAG_PROTOTYPED;
+ }
+ break;
+
+ case 'F':
+ /* A global function definition. */
+ SYMBOL_TYPE (sym) = read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ /* Don't add symbol references to global_sym_chain.
+ Symbol references don't have valid names and wont't match up with
+ minimal symbols when the global_sym_chain is relocated.
+ We'll fixup symbol references when we fixup the defining symbol. */
+ if (DEPRECATED_SYMBOL_NAME (sym) && DEPRECATED_SYMBOL_NAME (sym)[0] != '#')
+ {
+ i = hashname (DEPRECATED_SYMBOL_NAME (sym));
+ SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ }
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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);
+
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ add_symbol_to_list (sym, &local_symbols);
+
+ if (TARGET_BYTE_ORDER != BFD_ENDIAN_BIG)
+ {
+ /* 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 (BELIEVE_PCC_PROMOTION_TYPE)
+ {
+ /* This 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
+ {
+ /* 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;
+ }
+ }
+
+ 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 + NUM_PSEUDO_REGS)
+ {
+ reg_value_complaint (SYMBOL_VALUE (sym),
+ NUM_REGS + NUM_PSEUDO_REGS,
+ SYMBOL_PRINT_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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 + NUM_PSEUDO_REGS)
+ {
+ reg_value_complaint (SYMBOL_VALUE (sym),
+ NUM_REGS + NUM_PSEUDO_REGS,
+ SYMBOL_PRINT_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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
+ stabs_argument_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
+ && gdbarch_stabs_argument_has_addr (current_gdbarch,
+ SYMBOL_TYPE (sym)))
+ {
+ 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)
+ && strcmp (DEPRECATED_SYMBOL_NAME (prev_sym),
+ DEPRECATED_SYMBOL_NAME (sym)) == 0)
+ {
+ 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 (IS_STATIC_TRANSFORM_NAME (DEPRECATED_SYMBOL_NAME (sym)))
+ {
+ struct minimal_symbol *msym;
+ msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (sym), NULL, objfile);
+ if (msym != NULL)
+ {
+ DEPRECATED_SYMBOL_NAME (sym) = STATIC_TRANSFORM_NAME (DEPRECATED_SYMBOL_NAME (sym));
+ SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msym);
+ }
+ }
+#endif
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 't':
+ /* Typedef */
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ /* 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 (DEPRECATED_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. */
+ /* ezannoni: 2000-10-26. This seems to apply for
+ versions of gcc older than 2.8. This was the original
+ problem: with the following code gdb would tell that
+ the type for name1 is caddr_t, and func is char()
+ typedef char *caddr_t;
+ char *name2;
+ struct x
+ {
+ char *name1;
+ } xx;
+ char *func()
+ {
+ }
+ main () {}
+ */
+
+ /* Pascal accepts names for pointer types. */
+ if (current_subfile->language == language_pascal)
+ {
+ TYPE_NAME (SYMBOL_TYPE (sym)) = DEPRECATED_SYMBOL_NAME (sym);
+ }
+ }
+ else
+ TYPE_NAME (SYMBOL_TYPE (sym)) = DEPRECATED_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++;
+
+ 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_DOMAIN (sym) = STRUCT_DOMAIN;
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_TAG_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile->objfile_obstack, "", "", DEPRECATED_SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+
+ if (synonym)
+ {
+ /* Clone the sym and then modify it. */
+ struct symbol *typedef_sym = (struct symbol *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol));
+ *typedef_sym = *sym;
+ SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (typedef_sym) = valu;
+ SYMBOL_DOMAIN (typedef_sym) = VAR_DOMAIN;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile->objfile_obstack, "", "", DEPRECATED_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 (IS_STATIC_TRANSFORM_NAME (DEPRECATED_SYMBOL_NAME (sym)))
+ {
+ struct minimal_symbol *msym;
+ msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (sym), NULL, objfile);
+ if (msym != NULL)
+ {
+ DEPRECATED_SYMBOL_NAME (sym) = STATIC_TRANSFORM_NAME (DEPRECATED_SYMBOL_NAME (sym));
+ SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msym);
+ }
+ }
+#endif
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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 + NUM_PSEUDO_REGS)
+ {
+ reg_value_complaint (SYMBOL_VALUE (sym),
+ NUM_REGS + NUM_PSEUDO_REGS,
+ SYMBOL_PRINT_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+ }
+
+ /* Some systems pass variables of certain types by reference instead
+ of by value, i.e. they will pass the address of a structure (in a
+ register or on the stack) instead of the structure itself. */
+
+ if (gdbarch_stabs_argument_has_addr (current_gdbarch, SYMBOL_TYPE (sym))
+ && (SYMBOL_CLASS (sym) == LOC_REGPARM || SYMBOL_CLASS (sym) == LOC_ARG))
+ {
+ /* We have to convert LOC_REGPARM to LOC_REGPARM_ADDR (for
+ variables passed in a register). */
+ 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 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 (char **pp, struct objfile *objfile)
+{
+ complaint (&symfile_complaints, "couldn't parse type; debugger out of date?");
+ 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. */
+
+static struct type *
+read_type (char **pp, struct objfile *objfile)
+{
+ struct type *type = 0;
+ struct type *type1;
+ int typenums[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;
+
+ /* Used to distinguish vector from array. */
+ int is_vector = 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);
+
+ if (**pp != '=')
+ {
+ /* Type is not being defined here. Either it already
+ exists, or this is a forward reference to it.
+ dbx_alloc_type handles both cases. */
+ type = dbx_alloc_type (typenums, objfile);
+
+ /* If this is a forward reference, arrange to complain if it
+ doesn't get patched up by the time we're done
+ reading. */
+ if (TYPE_CODE (type) == TYPE_CODE_UNDEF)
+ add_undefined_type (type);
+
+ return type;
+ }
+
+ /* Type is being defined here. */
+ /* Skip the '='.
+ Also skip the type descriptor - we get it below with (*pp)[-1]. */
+ (*pp) += 2;
+ }
+ 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)++;
+ }
+
+again:
+ 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. */
+ complaint (&symfile_complaints,
+ "Unrecognized cross-reference type `%c'", (*pp)[0]);
+ code = TYPE_CODE_STRUCT;
+ break;
+ }
+ }
+
+ q1 = strchr (*pp, '<');
+ p = strchr (*pp, ':');
+ if (p == NULL)
+ return error_type (pp, objfile);
+ if (q1 && p > q1 && p[1] == ':')
+ {
+ int nesting_level = 0;
+ for (q2 = q1; *q2; q2++)
+ {
+ if (*q2 == '<')
+ nesting_level++;
+ else if (*q2 == '>')
+ nesting_level--;
+ else if (*q2 == ':' && nesting_level == 0)
+ break;
+ }
+ p = q2;
+ if (*p != ':')
+ return error_type (pp, objfile);
+ }
+ to = type_name =
+ (char *) obstack_alloc (&objfile->objfile_obstack, p - *pp + 1);
+
+ /* Copy the name. */
+ from = *pp + 1;
+ while (from < p)
+ *to++ = *from++;
+ *to = '\0';
+
+ /* Set the pointer ahead of the name which we just read, and
+ the colon. */
+ *pp = from + 1;
+ }
+
+ /* If this type has already been declared, then reuse the same
+ type, rather than allocating a new one. This saves some
+ 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_DOMAIN (sym) == STRUCT_DOMAIN
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+ && strcmp (DEPRECATED_SYMBOL_NAME (sym), type_name) == 0)
+ {
+ obstack_free (&objfile->objfile_obstack, type_name);
+ type = SYMBOL_TYPE (sym);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ 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 '(':
+ (*pp)--;
+
+ /* We deal with something like t(1,2)=(3,4)=... which
+ the Lucid compiler and recent gcc versions (post 2.7.3) use. */
+
+ /* Allocate and enter the typedef type first.
+ This handles recursive types. */
+ type = dbx_alloc_type (typenums, objfile);
+ TYPE_CODE (type) = TYPE_CODE_TYPEDEF;
+ {
+ struct type *xtype = read_type (pp, objfile);
+ if (type == xtype)
+ {
+ /* It's being defined as itself. That means it is "void". */
+ TYPE_CODE (type) = TYPE_CODE_VOID;
+ TYPE_LENGTH (type) = 1;
+ }
+ else if (type_size >= 0 || is_string)
+ {
+ /* This is the absolute wrong way to construct types. Every
+ other debug format has found a way around this problem and
+ the related problems with unnecessarily stubbed types;
+ someone motivated should attempt to clean up the issue
+ here as well. Once a type pointed to has been created it
+ should not be modified.
+
+ Well, it's not *absolutely* wrong. Constructing recursive
+ types (trees, linked lists) necessarily entails modifying
+ types after creating them. Constructing any loop structure
+ entails side effects. The Dwarf 2 reader does handle this
+ more gracefully (it never constructs more than once
+ instance of a type object, so it doesn't have to copy type
+ objects wholesale), but it still mutates type objects after
+ other folks have references to them.
+
+ Keep in mind that this circularity/mutation issue shows up
+ at the source language level, too: C's "incomplete types",
+ for example. So the proper cleanup, I think, would be to
+ limit GDB's type smashing to match exactly those required
+ by the source language. So GDB could have a
+ "complete_this_type" function, but never create unnecessary
+ copies of a type otherwise. */
+ replace_type (type, xtype);
+ TYPE_NAME (type) = NULL;
+ TYPE_TAG_NAME (type) = NULL;
+ }
+ else
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_TARGET_STUB;
+ TYPE_TARGET_TYPE (type) = xtype;
+ }
+ }
+ 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 '*': /* Pointer to another type */
+ 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 */
+ type1 = read_type (pp, objfile);
+ type = make_function_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'g': /* Prototyped function. (Sun) */
+ {
+ /* Unresolved questions:
+
+ - According to Sun's ``STABS Interface Manual'', for 'f'
+ and 'F' symbol descriptors, a `0' in the argument type list
+ indicates a varargs function. But it doesn't say how 'g'
+ type descriptors represent that info. Someone with access
+ to Sun's toolchain should try it out.
+
+ - According to the comment in define_symbol (search for
+ `process_prototype_types:'), Sun emits integer arguments as
+ types which ref themselves --- like `void' types. Do we
+ have to deal with that here, too? Again, someone with
+ access to Sun's toolchain should try it out and let us
+ know. */
+
+ const char *type_start = (*pp) - 1;
+ struct type *return_type = read_type (pp, objfile);
+ struct type *func_type
+ = make_function_type (return_type, dbx_lookup_type (typenums));
+ struct type_list {
+ struct type *type;
+ struct type_list *next;
+ } *arg_types = 0;
+ int num_args = 0;
+
+ while (**pp && **pp != '#')
+ {
+ struct type *arg_type = read_type (pp, objfile);
+ struct type_list *new = alloca (sizeof (*new));
+ new->type = arg_type;
+ new->next = arg_types;
+ arg_types = new;
+ num_args++;
+ }
+ if (**pp == '#')
+ ++*pp;
+ else
+ {
+ complaint (&symfile_complaints,
+ "Prototyped function type didn't end arguments with `#':\n%s",
+ type_start);
+ }
+
+ /* If there is just one argument whose type is `void', then
+ that's just an empty argument list. */
+ if (arg_types
+ && ! arg_types->next
+ && TYPE_CODE (arg_types->type) == TYPE_CODE_VOID)
+ num_args = 0;
+
+ TYPE_FIELDS (func_type)
+ = (struct field *) TYPE_ALLOC (func_type,
+ num_args * sizeof (struct field));
+ memset (TYPE_FIELDS (func_type), 0, num_args * sizeof (struct field));
+ {
+ int i;
+ struct type_list *t;
+
+ /* We stuck each argument type onto the front of the list
+ when we read it, so the list is reversed. Build the
+ fields array right-to-left. */
+ for (t = arg_types, i = num_args - 1; t; t = t->next, i--)
+ TYPE_FIELD_TYPE (func_type, i) = t->type;
+ }
+ TYPE_NFIELDS (func_type) = num_args;
+ TYPE_FLAGS (func_type) |= TYPE_FLAG_PROTOTYPED;
+
+ type = func_type;
+ break;
+ }
+
+ case 'k': /* Const qualifier on some type (Sun) */
+ type = read_type (pp, objfile);
+ type = make_cv_type (1, TYPE_VOLATILE (type), type,
+ dbx_lookup_type (typenums));
+ break;
+
+ case 'B': /* Volatile qual on some type (Sun) */
+ type = read_type (pp, objfile);
+ type = make_cv_type (TYPE_CONST (type), 1, type,
+ dbx_lookup_type (typenums));
+ break;
+
+ case '@':
+ if (isdigit (**pp) || **pp == '(' || **pp == '-')
+ { /* Member (class & variable) type */
+ /* FIXME -- we should be doing smash_to_XXX types here. */
+
+ 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);
+ }
+ else
+ /* type attribute */
+ {
+ char *attr = *pp;
+ /* Skip to the semicolon. */
+ while (**pp != ';' && **pp != '\0')
+ ++(*pp);
+ if (**pp == '\0')
+ return error_type (pp, objfile);
+ else
+ ++ * pp; /* Skip the semicolon. */
+
+ switch (*attr)
+ {
+ case 's': /* Size attribute */
+ type_size = atoi (attr + 1);
+ if (type_size <= 0)
+ type_size = -1;
+ break;
+
+ case 'S': /* String attribute */
+ /* FIXME: check to see if following type is array? */
+ is_string = 1;
+ break;
+
+ case 'V': /* Vector attribute */
+ /* FIXME: check to see if following type is array? */
+ is_vector = 1;
+ break;
+
+ default:
+ /* Ignore unrecognized type attributes, so future compilers
+ can invent new ones. */
+ break;
+ }
+ ++*pp;
+ goto again;
+ }
+ 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)++ != ';')
+ complaint (&symfile_complaints,
+ "invalid (minimal) member type data format at symtab pos %d.",
+ 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 field *args;
+ int nargs, varargs;
+
+ 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, &nargs, &varargs);
+ type = dbx_alloc_type (typenums, objfile);
+ smash_to_method_type (type, domain, return_type, args,
+ nargs, varargs);
+ }
+ break;
+
+ case 'r': /* Range type */
+ type = read_range_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'b':
+ {
+ /* 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 */
+ {
+ enum type_code type_code = TYPE_CODE_UNDEF;
+ type = dbx_alloc_type (typenums, objfile);
+ switch (type_descriptor)
+ {
+ case 's':
+ type_code = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ type_code = TYPE_CODE_UNION;
+ break;
+ }
+ type = read_struct_type (pp, type, type_code, 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;
+ if (is_vector)
+ TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
+ break;
+
+ case 'S': /* Set or bitstring type */
+ type1 = read_type (pp, objfile);
+ type = create_set_type ((struct type *) NULL, type1);
+ if (is_string)
+ TYPE_CODE (type) = TYPE_CODE_BITSTRING;
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = 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 (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)
+ {
+ complaint (&symfile_complaints, "Unknown builtin type %d", 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_COMPLEX, 8, 0, "complex", NULL);
+ TYPE_TARGET_TYPE (rettype) = init_type (TYPE_CODE_FLT, 4, 0, "float",
+ NULL);
+ break;
+ case 26:
+ /* Complex type consisting of two IEEE double precision values. */
+ rettype = init_type (TYPE_CODE_COMPLEX, 16, 0, "double complex", NULL);
+ TYPE_TARGET_TYPE (rettype) = init_type (TYPE_CODE_FLT, 8, 0, "double",
+ 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. */
+
+/* Replace *OLD_NAME with the method name portion of PHYSNAME. */
+
+static void
+update_method_name_from_physname (char **old_name, char *physname)
+{
+ char *method_name;
+
+ method_name = method_name_from_physname (physname);
+
+ if (method_name == NULL)
+ {
+ complaint (&symfile_complaints,
+ "Method has bad physname %s\n", physname);
+ return;
+ }
+
+ if (strcmp (*old_name, method_name) != 0)
+ {
+ xfree (*old_name);
+ *old_name = method_name;
+ }
+ else
+ xfree (method_name);
+}
+
+/* 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 (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;
+ 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 (xfree, 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] = "op$";
+ 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 (xfree, 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_STUB (new_sublist->fn_field.type))
+ {
+ 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:
+ complaint (&symfile_complaints,
+ "const/volatile indicator missing, got '%c'", **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. */
+ {
+ int slen = strlen (main_fn_name);
+
+ new_sublist->fn_field.voffset = VOFFSET_STATIC;
+
+ /* For static member functions, we can't tell if they
+ are stubbed, as they are put out as functions, and not as
+ methods.
+ GCC v2 emits the fully mangled name if
+ dbxout.c:flag_minimal_debug is not set, so we have to
+ detect a fully mangled physname here and set is_stub
+ accordingly. Fully mangled physnames in v2 start with
+ the member function name, followed by two underscores.
+ GCC v3 currently always emits stubbed member functions,
+ but with fully mangled physnames, which start with _Z. */
+ if (!(strncmp (new_sublist->fn_field.physname,
+ main_fn_name, slen) == 0
+ && new_sublist->fn_field.physname[slen] == '_'
+ && new_sublist->fn_field.physname[slen + 1] == '_'))
+ {
+ new_sublist->fn_field.is_stub = 1;
+ }
+ break;
+ }
+
+ default:
+ /* error */
+ complaint (&symfile_complaints,
+ "member function type missing, got '%c'", (*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)++;
+ STABS_CONTINUE (pp, objfile);
+
+ /* Skip GCC 3.X member functions which are duplicates of the callable
+ constructor/destructor. */
+ if (strcmp (main_fn_name, "__base_ctor") == 0
+ || strcmp (main_fn_name, "__base_dtor") == 0
+ || strcmp (main_fn_name, "__deleting_dtor") == 0)
+ {
+ xfree (main_fn_name);
+ }
+ else
+ {
+ int has_stub = 0;
+ int has_destructor = 0, has_other = 0;
+ int is_v3 = 0;
+ struct next_fnfield *tmp_sublist;
+
+ /* Various versions of GCC emit various mostly-useless
+ strings in the name field for special member functions.
+
+ For stub methods, we need to defer correcting the name
+ until we are ready to unstub the method, because the current
+ name string is used by gdb_mangle_name. The only stub methods
+ of concern here are GNU v2 operators; other methods have their
+ names correct (see caveat below).
+
+ For non-stub methods, in GNU v3, we have a complete physname.
+ Therefore we can safely correct the name now. This primarily
+ affects constructors and destructors, whose name will be
+ __comp_ctor or __comp_dtor instead of Foo or ~Foo. Cast
+ operators will also have incorrect names; for instance,
+ "operator int" will be named "operator i" (i.e. the type is
+ mangled).
+
+ For non-stub methods in GNU v2, we have no easy way to
+ know if we have a complete physname or not. For most
+ methods the result depends on the platform (if CPLUS_MARKER
+ can be `$' or `.', it will use minimal debug information, or
+ otherwise the full physname will be included).
+
+ Rather than dealing with this, we take a different approach.
+ For v3 mangled names, we can use the full physname; for v2,
+ we use cplus_demangle_opname (which is actually v2 specific),
+ because the only interesting names are all operators - once again
+ barring the caveat below. Skip this process if any method in the
+ group is a stub, to prevent our fouling up the workings of
+ gdb_mangle_name.
+
+ The caveat: GCC 2.95.x (and earlier?) put constructors and
+ destructors in the same method group. We need to split this
+ into two groups, because they should have different names.
+ So for each method group we check whether it contains both
+ routines whose physname appears to be a destructor (the physnames
+ for and destructors are always provided, due to quirks in v2
+ mangling) and routines whose physname does not appear to be a
+ destructor. If so then we break up the list into two halves.
+ Even if the constructors and destructors aren't in the same group
+ the destructor will still lack the leading tilde, so that also
+ needs to be fixed.
+
+ So, to summarize what we expect and handle here:
+
+ Given Given Real Real Action
+ method name physname physname method name
+
+ __opi [none] __opi__3Foo operator int opname
+ [now or later]
+ Foo _._3Foo _._3Foo ~Foo separate and
+ rename
+ operator i _ZN3FoocviEv _ZN3FoocviEv operator int demangle
+ __comp_ctor _ZN3FooC1ERKS_ _ZN3FooC1ERKS_ Foo demangle
+ */
+
+ tmp_sublist = sublist;
+ while (tmp_sublist != NULL)
+ {
+ if (tmp_sublist->fn_field.is_stub)
+ has_stub = 1;
+ if (tmp_sublist->fn_field.physname[0] == '_'
+ && tmp_sublist->fn_field.physname[1] == 'Z')
+ is_v3 = 1;
+
+ if (is_destructor_name (tmp_sublist->fn_field.physname))
+ has_destructor++;
+ else
+ has_other++;
+
+ tmp_sublist = tmp_sublist->next;
+ }
+
+ if (has_destructor && has_other)
+ {
+ struct next_fnfieldlist *destr_fnlist;
+ struct next_fnfield *last_sublist;
+
+ /* Create a new fn_fieldlist for the destructors. */
+
+ destr_fnlist = (struct next_fnfieldlist *)
+ xmalloc (sizeof (struct next_fnfieldlist));
+ make_cleanup (xfree, destr_fnlist);
+ memset (destr_fnlist, 0, sizeof (struct next_fnfieldlist));
+ destr_fnlist->fn_fieldlist.name
+ = obconcat (&objfile->objfile_obstack, "", "~",
+ new_fnlist->fn_fieldlist.name);
+
+ destr_fnlist->fn_fieldlist.fn_fields = (struct fn_field *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct fn_field) * has_destructor);
+ memset (destr_fnlist->fn_fieldlist.fn_fields, 0,
+ sizeof (struct fn_field) * has_destructor);
+ tmp_sublist = sublist;
+ last_sublist = NULL;
+ i = 0;
+ while (tmp_sublist != NULL)
+ {
+ if (!is_destructor_name (tmp_sublist->fn_field.physname))
+ {
+ tmp_sublist = tmp_sublist->next;
+ continue;
+ }
+
+ destr_fnlist->fn_fieldlist.fn_fields[i++]
+ = tmp_sublist->fn_field;
+ if (last_sublist)
+ last_sublist->next = tmp_sublist->next;
+ else
+ sublist = tmp_sublist->next;
+ last_sublist = tmp_sublist;
+ tmp_sublist = tmp_sublist->next;
+ }
+
+ destr_fnlist->fn_fieldlist.length = has_destructor;
+ destr_fnlist->next = fip->fnlist;
+ fip->fnlist = destr_fnlist;
+ nfn_fields++;
+ total_length += has_destructor;
+ length -= has_destructor;
+ }
+ else if (is_v3)
+ {
+ /* v3 mangling prevents the use of abbreviated physnames,
+ so we can do this here. There are stubbed methods in v3
+ only:
+ - in -gstabs instead of -gstabs+
+ - or for static methods, which are output as a function type
+ instead of a method type. */
+
+ update_method_name_from_physname (&new_fnlist->fn_fieldlist.name,
+ sublist->fn_field.physname);
+ }
+ else if (has_destructor && new_fnlist->fn_fieldlist.name[0] != '~')
+ {
+ new_fnlist->fn_fieldlist.name = concat ("~", main_fn_name, NULL);
+ xfree (main_fn_name);
+ }
+ else if (!has_stub)
+ {
+ char dem_opname[256];
+ int ret;
+ ret = cplus_demangle_opname (new_fnlist->fn_fieldlist.name,
+ dem_opname, DMGL_ANSI);
+ if (!ret)
+ ret = cplus_demangle_opname (new_fnlist->fn_fieldlist.name,
+ dem_opname, 0);
+ if (ret)
+ new_fnlist->fn_fieldlist.name
+ = obsavestring (dem_opname, strlen (dem_opname),
+ &objfile->objfile_obstack);
+ }
+
+ new_fnlist->fn_fieldlist.fn_fields = (struct fn_field *)
+ obstack_alloc (&objfile->objfile_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;
+ }
+ }
+
+ 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 (struct field_info *fip, char **pp, struct type *type,
+ struct objfile *objfile)
+{
+ 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 */
+ name = type_name_no_tag (context);
+ if (name == NULL)
+ {
+ name = "";
+ }
+ fip->list->field.name =
+ obconcat (&objfile->objfile_obstack, vptr_name, name, "");
+ break;
+
+ case 'b': /* $vb -- a virtual bsomethingorother */
+ name = type_name_no_tag (context);
+ if (name == NULL)
+ {
+ complaint (&symfile_complaints,
+ "C++ abbreviated type name unknown at symtab pos %d",
+ symnum);
+ name = "FOO";
+ }
+ fip->list->field.name =
+ obconcat (&objfile->objfile_obstack, vb_name, name, "");
+ break;
+
+ default:
+ invalid_cpp_abbrev_complaint (*pp);
+ fip->list->field.name =
+ obconcat (&objfile->objfile_obstack,
+ "INVALID_CPLUSPLUS_ABBREV", "", "");
+ break;
+ }
+
+ /* At this point, *pp points to the ':'. Skip it and read the
+ field type. */
+
+ p = ++(*pp);
+ if (p[-1] != ':')
+ {
+ 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;
+ FIELD_BITPOS (fip->list->field) = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return 0;
+ }
+ /* This field is unpacked. */
+ FIELD_BITSIZE (fip->list->field) = 0;
+ fip->list->visibility = VISIBILITY_PRIVATE;
+ }
+ else
+ {
+ 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 (struct field_info *fip, char **pp, char *p,
+ struct type *type, struct objfile *objfile)
+{
+ fip->list->field.name =
+ obsavestring (*pp, p - *pp, &objfile->objfile_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
+ while (*p != ';')
+ {
+ p++;
+ }
+ /* Static class member. */
+ SET_FIELD_PHYSNAME (fip->list->field, savestring (*pp, p - *pp));
+ *pp = p + 1;
+ return;
+ }
+ else if (**pp != ',')
+ {
+ /* Bad structure-type format. */
+ stabs_general_complaint ("bad structure-type format");
+ return;
+ }
+
+ (*pp)++; /* Skip the comma. */
+
+ {
+ int nbits;
+ FIELD_BITPOS (fip->list->field) = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ {
+ stabs_general_complaint ("bad structure-type format");
+ return;
+ }
+ FIELD_BITSIZE (fip->list->field) = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ {
+ stabs_general_complaint ("bad structure-type format");
+ return;
+ }
+ }
+
+ if (FIELD_BITPOS (fip->list->field) == 0
+ && FIELD_BITSIZE (fip->list->field) == 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 "<no value>" 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. */
+
+ struct type *field_type = check_typedef (FIELD_TYPE (fip->list->field));
+
+ if (TYPE_CODE (field_type) != TYPE_CODE_INT
+ && TYPE_CODE (field_type) != TYPE_CODE_RANGE
+ && TYPE_CODE (field_type) != TYPE_CODE_BOOL
+ && TYPE_CODE (field_type) != TYPE_CODE_ENUM)
+ {
+ FIELD_BITSIZE (fip->list->field) = 0;
+ }
+ if ((FIELD_BITSIZE (fip->list->field)
+ == TARGET_CHAR_BIT * TYPE_LENGTH (field_type)
+ || (TYPE_CODE (field_type) == TYPE_CODE_ENUM
+ && FIELD_BITSIZE (fip->list->field) == TARGET_INT_BIT)
+ )
+ &&
+ FIELD_BITPOS (fip->list->field) % 8 == 0)
+ {
+ FIELD_BITSIZE (fip->list->field) = 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 (struct field_info *fip, char **pp, struct type *type,
+ struct objfile *objfile)
+{
+ 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. */
+ /* Stab string for structure/union does not end with two ';' in
+ SUN C compiler 5.3 i.e. F6U2, hence check for end of string. */
+
+ while (**pp != ';' && **pp != '\0')
+ {
+ STABS_CONTINUE (pp, objfile);
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (xfree, 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] == ':')
+ {
+ /* (the deleted) 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;
+}
+/* *INDENT-OFF* */
+/* 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. */
+/* *INDENT-ON* */
+
+
+
+static int
+read_baseclasses (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 (xfree, new);
+ memset (new, 0, sizeof (struct nextfield));
+ new->next = fip->list;
+ fip->list = new;
+ FIELD_BITSIZE (new->field) = 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. */
+ {
+ complaint (&symfile_complaints,
+ "Unknown virtual character `%c' for baseclass", **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. */
+ {
+ complaint (&symfile_complaints,
+ "Unknown visibility `%c' for baseclass",
+ 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. */
+
+ FIELD_BITPOS (new->field) = 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 (struct field_info *fip, char **pp, struct type *type,
+ struct objfile *objfile)
+{
+ 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)
+ {
+ char *name = TYPE_FIELD_NAME (t, i);
+ if (!strncmp (name, vptr_name, sizeof (vptr_name) - 2)
+ && is_cplus_marker (name[sizeof (vptr_name) - 2]))
+ {
+ TYPE_VPTR_FIELDNO (type) = i;
+ goto gotit;
+ }
+ }
+ /* Virtual function table field not found. */
+ complaint (&symfile_complaints,
+ "virtual function table pointer not found when defining class `%s'",
+ 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 (struct field_info *fip, struct type *type)
+{
+ 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 (struct field_info *fip, struct type *type,
+ struct objfile *objfile)
+{
+ int nfields = 0;
+ int non_public_fields = 0;
+ 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. */
+ {
+ complaint (&symfile_complaints, "Unknown visibility `%c' for field",
+ fip->list->visibility);
+ }
+ break;
+ }
+ fip->list = fip->list->next;
+ }
+ return 1;
+}
+
+
+/* Complain that the compiler has emitted more than one definition for the
+ structure type TYPE. */
+static void
+complain_about_struct_wipeout (struct type *type)
+{
+ char *name = "";
+ char *kind = "";
+
+ if (TYPE_TAG_NAME (type))
+ {
+ name = TYPE_TAG_NAME (type);
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT: kind = "struct "; break;
+ case TYPE_CODE_UNION: kind = "union "; break;
+ case TYPE_CODE_ENUM: kind = "enum "; break;
+ default: kind = "";
+ }
+ }
+ else if (TYPE_NAME (type))
+ {
+ name = TYPE_NAME (type);
+ kind = "";
+ }
+ else
+ {
+ name = "<unknown>";
+ kind = "";
+ }
+
+ complaint (&symfile_complaints,
+ "struct/union type gets multiply defined: %s%s", kind, name);
+}
+
+
+/* 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 (char **pp, struct type *type, enum type_code type_code,
+ struct objfile *objfile)
+{
+ struct cleanup *back_to;
+ struct field_info fi;
+
+ fi.list = NULL;
+ fi.fnlist = NULL;
+
+ /* When describing struct/union/class types in stabs, G++ always drops
+ all qualifications from the name. So if you've got:
+ struct A { ... struct B { ... }; ... };
+ then G++ will emit stabs for `struct A::B' that call it simply
+ `struct B'. Obviously, if you've got a real top-level definition for
+ `struct B', or other nested definitions, this is going to cause
+ problems.
+
+ Obviously, GDB can't fix this by itself, but it can at least avoid
+ scribbling on existing structure type objects when new definitions
+ appear. */
+ if (! (TYPE_CODE (type) == TYPE_CODE_UNDEF
+ || TYPE_STUB (type)))
+ {
+ complain_about_struct_wipeout (type);
+
+ /* It's probably best to return the type unchanged. */
+ return type;
+ }
+
+ back_to = make_cleanup (null_cleanup, 0);
+
+ INIT_CPLUS_SPECIFIC (type);
+ TYPE_CODE (type) = type_code;
+ 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 (char **pp, 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<index type>;lower;upper;<array_contents_type>".
+ OS9000: "arlower,upper;<array_contents_type>".
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ {
+ 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, ';', &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 (char **pp, struct type *type,
+ struct objfile *objfile)
+{
+ char *p;
+ char *name;
+ long n;
+ 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;
+
+ /* 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->objfile_obstack);
+ *pp = p + 1;
+ n = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return error_type (pp, objfile);
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ DEPRECATED_SYMBOL_NAME (sym) = name;
+ SYMBOL_LANGUAGE (sym) = current_subfile->language;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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) = DEPRECATED_SYMBOL_NAME (xsym);
+ 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> <width> <format type>; <offset>; <nbits>
+ signed = u or s.
+ optional format type = c or b for char or boolean.
+ 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 (char **pp, int typenums[2], struct objfile *objfile)
+{
+ int type_bits;
+ int nbits;
+ int signed_type;
+ enum type_code code = TYPE_CODE_INT;
+
+ 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.
+ Boolean forms, e.g Fortran logical*X, put a b here. */
+
+ if (**pp == 'c')
+ (*pp)++;
+ else if (**pp == 'b')
+ {
+ code = TYPE_CODE_BOOL;
+ (*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 (code,
+ type_bits / TARGET_CHAR_BIT,
+ signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *) NULL,
+ objfile);
+}
+
+static struct type *
+read_sun_floating_type (char **pp, int typenums[2], struct objfile *objfile)
+{
+ int nbits;
+ int details;
+ int nbytes;
+ struct type *rettype;
+
+ /* 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)
+ {
+ rettype = init_type (TYPE_CODE_COMPLEX, nbytes, 0, NULL, objfile);
+ TYPE_TARGET_TYPE (rettype)
+ = init_type (TYPE_CODE_FLT, nbytes / 2, 0, NULL, objfile);
+ return rettype;
+ }
+
+ 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 (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++;
+ }
+
+ 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 (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 <large number> is an unsigned large integral type. */
+ if ((n2bits == 0 && n2 == 0) && n3bits != 0)
+ {
+ got_unsigned = 1;
+ nbits = n3bits;
+ }
+ /* Range from <large number> to <large number>-1 is a large signed
+ integral type. Take care of the case where <large number> doesn't
+ fit in a long but <large number>-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. To
+ distinguish between floats and complex, g77 (and others?) seem
+ to use self-subranges for the complexes, and subranges of int for
+ the floats.
+
+ Also note that for complexes, g77 sets n2 to the size of one of
+ the member floats, not the whole complex beast. My guess is that
+ this was to work well with pre-COMPLEX versions of gdb. */
+
+ if (n3 == 0 && n2 > 0)
+ {
+ struct type *float_type
+ = init_type (TYPE_CODE_FLT, n2, 0, NULL, objfile);
+
+ if (self_subrange)
+ {
+ struct type *complex_type =
+ init_type (TYPE_CODE_COMPLEX, 2 * n2, 0, NULL, objfile);
+ TYPE_TARGET_TYPE (complex_type) = float_type;
+ return complex_type;
+ }
+ else
+ return float_type;
+ }
+
+ /* 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, TYPE_FLAG_NOSIGN, NULL, objfile);
+
+ /* We used to do this only for subrange of self or subrange of int. */
+ else if (n2 == 0)
+ {
+ /* -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. */
+
+ if (n3 < 0)
+ /* n3 actually gives the size. */
+ return init_type (TYPE_CODE_INT, -n3, TYPE_FLAG_UNSIGNED,
+ NULL, objfile);
+
+ /* Is n3 == 2**(8n)-1 for some integer n? Then it's an
+ unsigned n-byte integer. But do require n to be a power of
+ two; we don't want 3- and 5-byte integers flying around. */
+ {
+ int bytes;
+ unsigned long bits;
+
+ bits = n3;
+ for (bytes = 0; (bits & 0xff) == 0xff; bytes++)
+ bits >>= 8;
+ if (bits == 0
+ && ((bytes - 1) & bytes) == 0) /* "bytes is a power of two" */
+ return init_type (TYPE_CODE_INT, bytes, TYPE_FLAG_UNSIGNED, NULL,
+ objfile);
+ }
+ }
+ /* 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;
+
+ complaint (&symfile_complaints,
+ "base type %d of range type is not defined", 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 field *
+read_args (char **pp, int end, struct objfile *objfile, int *nargsp,
+ int *varargsp)
+{
+ /* FIXME! Remove this arbitrary limit! */
+ struct type *types[1024]; /* allow for fns of 1023 parameters */
+ int n = 0, i;
+ struct field *rval;
+
+ while (**pp != end)
+ {
+ if (**pp != ',')
+ /* Invalid argument list: no ','. */
+ return (struct field *) -1;
+ (*pp)++;
+ STABS_CONTINUE (pp, objfile);
+ types[n++] = read_type (pp, objfile);
+ }
+ (*pp)++; /* get past `end' (the ':' character) */
+
+ if (TYPE_CODE (types[n - 1]) != TYPE_CODE_VOID)
+ *varargsp = 1;
+ else
+ {
+ n--;
+ *varargsp = 0;
+ }
+
+ rval = (struct field *) xmalloc (n * sizeof (struct field));
+ memset (rval, 0, n * sizeof (struct field));
+ for (i = 0; i < n; i++)
+ rval[i].type = types[i];
+ *nargsp = n;
+ 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 (char *name, struct objfile *objfile)
+{
+ if (common_block_name != NULL)
+ {
+ complaint (&symfile_complaints,
+ "Invalid symbol data: common block within common block");
+ }
+ common_block = local_symbols;
+ common_block_i = local_symbols ? local_symbols->nsyms : 0;
+ common_block_name = obsavestring (name, strlen (name),
+ &objfile->objfile_obstack);
+}
+
+/* Process a N_ECOMM symbol. */
+
+void
+common_block_end (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)
+ {
+ complaint (&symfile_complaints, "ECOMM symbol unmatched by BCOMM");
+ return;
+ }
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ /* Note: common_block_name already saved on objfile_obstack */
+ DEPRECATED_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 (DEPRECATED_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 (struct symbol *sym, int valu)
+{
+ struct pending *next = (struct pending *) SYMBOL_TYPE (sym);
+ for (; next; next = next->next)
+ {
+ 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. */
+
+static void
+add_undefined_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 (void)
+{
+ 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_STUB (*type))
+ {
+ struct pending *ppt;
+ int i;
+ /* Name of the type, without "struct" or "union" */
+ char *typename = TYPE_TAG_NAME (*type);
+
+ if (typename == NULL)
+ {
+ complaint (&symfile_complaints, "need a type name");
+ 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_DOMAIN (sym) == STRUCT_DOMAIN
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) ==
+ TYPE_CODE (*type))
+ && strcmp (DEPRECATED_SYMBOL_NAME (sym), typename) == 0)
+ replace_type (*type, SYMBOL_TYPE (sym));
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ complaint (&symfile_complaints,
+ "forward-referenced types left unresolved, "
+ "type code %d.",
+ 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 (struct objfile *objfile)
+{
+ int hash;
+ struct minimal_symbol *msymbol;
+ struct symbol *sym, *prev;
+ struct objfile *resolve_objfile;
+
+ /* SVR4 based linkers copy referenced global symbols from shared
+ libraries to the main executable.
+ If we are scanning the symbols for a shared library, try to resolve
+ them from the minimal symbols of the main executable first. */
+
+ if (symfile_objfile && objfile != symfile_objfile)
+ resolve_objfile = symfile_objfile;
+ else
+ resolve_objfile = objfile;
+
+ while (1)
+ {
+ /* 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 = resolve_objfile->msymbols;
+ msymbol && DEPRECATED_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 (DEPRECATED_SYMBOL_NAME (msymbol));
+
+ for (sym = global_sym_chain[hash]; sym;)
+ {
+ if (DEPRECATED_SYMBOL_NAME (msymbol)[0] == DEPRECATED_SYMBOL_NAME (sym)[0] &&
+ strcmp (DEPRECATED_SYMBOL_NAME (msymbol) + 1, DEPRECATED_SYMBOL_NAME (sym) + 1) == 0)
+ {
+ /* 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 (sym)
+ {
+ 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);
+ }
+ }
+ }
+ if (resolve_objfile == objfile)
+ break;
+ resolve_objfile = objfile;
+ }
+
+ /* 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
+ complaint (&symfile_complaints,
+ "%s: common block `%s' from global_sym_chain unresolved",
+ objfile->name, DEPRECATED_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 (void)
+{
+}
+
+/* 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 (void)
+{
+ /* 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 (void)
+{
+ 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;
+}
+
+/* Call after end_symtab() */
+
+void
+end_stabs (void)
+{
+ if (type_vector)
+ {
+ xfree (type_vector);
+ }
+ type_vector = 0;
+ type_vector_length = 0;
+ previous_stab_code = 0;
+}
+
+void
+finish_global_stabs (struct objfile *objfile)
+{
+ if (global_stabs)
+ {
+ patch_block_stabs (global_symbols, global_stabs, objfile);
+ xfree (global_stabs);
+ global_stabs = NULL;
+ }
+}
+
+/* Find the end of the name, delimited by a ':', but don't match
+ ObjC symbols which look like -[Foo bar::]:bla. */
+static char *
+find_name_end (char *name)
+{
+ char *s = name;
+ if (s[0] == '-' || *s == '+')
+ {
+ /* Must be an ObjC method symbol. */
+ if (s[1] != '[')
+ {
+ error ("invalid symbol name \"%s\"", name);
+ }
+ s = strchr (s, ']');
+ if (s == NULL)
+ {
+ error ("invalid symbol name \"%s\"", name);
+ }
+ return strchr (s, ':');
+ }
+ else
+ {
+ return strchr (s, ':');
+ }
+}
+
+/* Initializer for this module */
+
+void
+_initialize_stabsread (void)
+{
+ 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 0000000..531f9a1
--- /dev/null
+++ b/contrib/gdb/gdb/stabsread.h
@@ -0,0 +1,207 @@
+/* Include file for stabs debugging format support functions.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 objfile;
+
+/* 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
+
+/* 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 (char *, struct objfile *);
+extern void common_block_end (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;
+
+ };
+
+/* The table of header_files of this OBJFILE. */
+#define HEADER_FILES(OBJFILE) (DBX_SYMFILE_INFO (OBJFILE)->header_files)
+
+/* The actual length of HEADER_FILES. */
+#define N_HEADER_FILES(OBJFILE) (DBX_SYMFILE_INFO (OBJFILE)->n_header_files)
+
+/* The allocated lengh of HEADER_FILES. */
+#define N_ALLOCATED_HEADER_FILES(OBJFILE) \
+ (DBX_SYMFILE_INFO (OBJFILE)->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 == 0 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 void cleanup_undefined_types (void);
+
+extern long read_number (char **, int);
+
+extern struct symbol *define_symbol (CORE_ADDR, char *, int, int,
+ struct objfile *);
+
+extern void stabsread_init (void);
+
+extern void stabsread_new_init (void);
+
+extern void start_stabs (void);
+
+extern void end_stabs (void);
+
+extern void finish_global_stabs (struct objfile *objfile);
+
+/* 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 *end_psymtab (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 textlow_not_set);
+
+extern void process_one_symbol (int, int, CORE_ADDR, char *,
+ struct section_offsets *, struct objfile *);
+
+extern void elfstab_build_psymtabs (struct objfile *objfile,
+ int mainline,
+ asection *stabsect,
+ file_ptr stabstroffset,
+ unsigned int stabstrsize);
+
+extern void coffstab_build_psymtabs
+ (struct objfile *objfile,
+ int mainline,
+ CORE_ADDR textaddr, unsigned int textsize,
+ struct stab_section_list *stabs,
+ file_ptr stabstroffset, unsigned int stabstrsize);
+
+extern void stabsect_build_psymtabs
+ (struct objfile *objfile,
+ int mainline, char *stab_name, char *stabstr_name, char *text_name);
+
+extern void elfstab_offset_sections (struct objfile *,
+ struct partial_symtab *);
+extern int symbol_reference_defined (char **);
+
+extern void ref_add (int, struct symbol *, char *, CORE_ADDR);
+
+extern struct symbol *ref_search (int);
+
+extern void free_header_files (void);
+
+extern void init_header_files (void);
+
+#undef EXTERN
diff --git a/contrib/gdb/gdb/stack.c b/contrib/gdb/gdb/stack.c
new file mode 100644
index 0000000..d42af9a
--- /dev/null
+++ b/contrib/gdb/gdb/stack.c
@@ -0,0 +1,2180 @@
+/* Print and select stack frames for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#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 "source.h"
+#include "breakpoint.h"
+#include "demangle.h"
+#include "inferior.h"
+#include "annotate.h"
+#include "ui-out.h"
+#include "block.h"
+#include "stack.h"
+#include "gdb_assert.h"
+#include "dictionary.h"
+#include "reggroups.h"
+#include "regcache.h"
+
+/* Prototypes for exported functions. */
+
+void args_info (char *, int);
+
+void locals_info (char *, int);
+
+void (*selected_frame_level_changed_hook) (int);
+
+void _initialize_stack (void);
+
+/* Prototypes for local functions. */
+
+static void down_command (char *, int);
+
+static void down_silently_base (char *);
+
+static void down_silently_command (char *, int);
+
+static void up_command (char *, int);
+
+static void up_silently_base (char *);
+
+static void up_silently_command (char *, int);
+
+void frame_command (char *, int);
+
+static void current_frame_command (char *, int);
+
+static void print_frame_arg_vars (struct frame_info *, struct ui_file *);
+
+static void catch_info (char *, int);
+
+static void args_plus_locals_info (char *, int);
+
+static void print_frame_label_vars (struct frame_info *, int,
+ struct ui_file *);
+
+static void print_frame_local_vars (struct frame_info *, int,
+ struct ui_file *);
+
+static int print_block_frame_labels (struct block *, int *,
+ struct ui_file *);
+
+static int print_block_frame_locals (struct block *,
+ struct frame_info *,
+ int,
+ struct ui_file *);
+
+static void print_frame (struct frame_info *fi,
+ int level,
+ int source,
+ int args,
+ struct symtab_and_line sal);
+
+static void backtrace_command (char *, int);
+
+struct frame_info *parse_frame_specification (char *);
+
+static void frame_info (char *, int);
+
+extern int addressprint; /* Print addresses, or stay symbolic only? */
+
+/* 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;
+ };
+
+/* Show or print the frame arguments.
+ Pass the args the way catch_errors wants them. */
+static int print_stack_frame_stub (void *args);
+static int
+print_stack_frame_stub (void *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;
+}
+
+/* Show or 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 (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;
+ struct ui_file *stream;
+};
+
+static int print_args_stub (void *);
+
+/* 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 (struct frame_info *fi, long start, int num,
+ int first, struct ui_file *stream)
+{
+ int i;
+ CORE_ADDR argsaddr;
+ long arg_value;
+
+ for (i = 0; i < num; i++)
+ {
+ QUIT;
+ argsaddr = get_frame_args_address (fi);
+ if (!argsaddr)
+ return;
+ arg_value = read_memory_integer (argsaddr + start, sizeof (int));
+ if (!first)
+ fprintf_filtered (stream, ", ");
+ fprintf_filtered (stream, "%ld", arg_value);
+ first = 0;
+ start += sizeof (int);
+ }
+}
+
+/* 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. */
+
+static void
+print_frame_args (struct symbol *func, struct frame_info *fi, int num,
+ struct ui_file *stream)
+{
+ struct block *b = NULL;
+ int first = 1;
+ struct dict_iterator iter;
+ struct symbol *sym;
+ struct value *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;
+ struct cleanup *old_chain, *list_chain;
+ struct ui_stream *stb;
+
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+ if (func)
+ {
+ b = SYMBOL_BLOCK_VALUE (func);
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ QUIT;
+
+ /* 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:
+ case LOC_COMPUTED_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 (*DEPRECATED_SYMBOL_NAME (sym))
+ {
+ struct symbol *nsym;
+ nsym = lookup_symbol
+ (DEPRECATED_SYMBOL_NAME (sym),
+ b, VAR_DOMAIN, (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)
+ ui_out_text (uiout, ", ");
+ ui_out_wrap_hint (uiout, " ");
+
+ annotate_arg_begin ();
+
+ list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ fprintf_symbol_filtered (stb->stream, SYMBOL_PRINT_NAME (sym),
+ SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
+ ui_out_field_stream (uiout, "name", stb);
+ annotate_arg_name_end ();
+ ui_out_text (uiout, "=");
+
+ /* 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), 0,
+ VALUE_ADDRESS (val),
+ stb->stream, 0, 0, 2, Val_no_prettyprint);
+ ui_out_field_stream (uiout, "value", stb);
+ }
+ else
+ ui_out_text (uiout, "???");
+
+ /* Invoke ui_out_tuple_end. */
+ do_cleanups (list_chain);
+
+ 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);
+ }
+ do_cleanups (old_chain);
+}
+
+/* Pass the args the way catch_errors wants them. */
+
+static int
+print_args_stub (void *args)
+{
+ int numargs;
+ struct print_args_args *p = (struct print_args_args *) args;
+
+ if (FRAME_NUM_ARGS_P ())
+ {
+ numargs = FRAME_NUM_ARGS (p->fi);
+ gdb_assert (numargs >= 0);
+ }
+ else
+ numargs = -1;
+ print_frame_args (p->func, p->fi, numargs, p->stream);
+ return 0;
+}
+
+/* Print information about a frame for frame "fi" at level "level".
+ Used in "where" output, also used to emit breakpoint or step
+ messages.
+ LEVEL is the level of the frame, or -1 if it is the
+ innermost frame but we don't want to print the level.
+ The meaning of the SOURCE argument is:
+ SRC_LINE: Print only source line
+ LOCATION: Print only location
+ LOC_AND_SRC: Print location and source line. */
+
+void
+print_frame_info (struct frame_info *fi, int level, int source, int args)
+{
+ struct symtab_and_line sal;
+ int source_print;
+ int location_print;
+
+ if (get_frame_type (fi) == DUMMY_FRAME
+ || get_frame_type (fi) == SIGTRAMP_FRAME)
+ {
+ struct cleanup *uiout_cleanup
+ = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
+
+ annotate_frame_begin (level == -1 ? 0 : level, get_frame_pc (fi));
+
+ /* Do this regardless of SOURCE because we don't have any source
+ to list for this frame. */
+ if (level >= 0)
+ {
+ ui_out_text (uiout, "#");
+ ui_out_field_fmt_int (uiout, 2, ui_left, "level", level);
+ }
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ annotate_frame_address ();
+ ui_out_field_core_addr (uiout, "addr", get_frame_pc (fi));
+ annotate_frame_address_end ();
+ }
+
+ if (get_frame_type (fi) == DUMMY_FRAME)
+ {
+ annotate_function_call ();
+ ui_out_field_string (uiout, "func", "<function called from gdb>");
+ }
+ else if (get_frame_type (fi) == SIGTRAMP_FRAME)
+ {
+ annotate_signal_handler_caller ();
+ ui_out_field_string (uiout, "func", "<signal handler called>");
+ }
+ ui_out_text (uiout, "\n");
+ annotate_frame_end ();
+
+ do_cleanups (uiout_cleanup);
+ 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 SIGTRAMP_FRAME 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. */
+ find_frame_sal (fi, &sal);
+
+ location_print = (source == LOCATION
+ || source == LOC_AND_ADDRESS
+ || source == SRC_AND_LOC);
+
+ if (location_print || !sal.symtab)
+ print_frame (fi, level, source, args, sal);
+
+ source_print = (source == SRC_LINE || source == SRC_AND_LOC);
+
+ if (sal.symtab)
+ set_current_source_symtab_and_line (&sal);
+
+ if (source_print && sal.symtab)
+ {
+ struct symtab_and_line cursal;
+ int done = 0;
+ int mid_statement = (source == SRC_LINE) && (get_frame_pc (fi) != sal.pc);
+
+ if (annotation_level)
+ done = identify_source_line (sal.symtab, sal.line, mid_statement,
+ get_frame_pc (fi));
+ if (!done)
+ {
+ if (print_frame_info_listing_hook)
+ print_frame_info_listing_hook (sal.symtab, sal.line, sal.line + 1, 0);
+ else
+ {
+ /* We used to do this earlier, but that is clearly
+ wrong. This function is used by many different
+ parts of gdb, including normal_stop in infrun.c,
+ which uses this to print out the current PC
+ when we stepi/nexti into the middle of a source
+ line. Only the command line really wants this
+ behavior. Other UIs probably would like the
+ ability to decide for themselves if it is desired. */
+ if (addressprint && mid_statement)
+ {
+ ui_out_field_core_addr (uiout, "addr", get_frame_pc (fi));
+ ui_out_text (uiout, "\t");
+ }
+
+ print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
+ }
+ }
+ /* Make sure we have at least a default source file */
+ set_default_source_symtab_and_line ();
+ cursal = get_current_source_symtab_and_line ();
+ cursal.line = max (sal.line - get_lines_to_list () / 2, 1);
+ set_current_source_symtab_and_line (&cursal);
+ }
+
+ if (source != 0)
+ set_default_breakpoint (1, get_frame_pc (fi), sal.symtab, sal.line);
+
+ annotate_frame_end ();
+
+ gdb_flush (gdb_stdout);
+}
+
+static void
+print_frame (struct frame_info *fi,
+ int level,
+ int source,
+ int args,
+ struct symtab_and_line sal)
+{
+ struct symbol *func;
+ char *funname = 0;
+ enum language funlang = language_unknown;
+ struct ui_stream *stb;
+ struct cleanup *old_chain;
+ struct cleanup *list_chain;
+
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+ func = find_pc_function (get_frame_address_in_block (fi));
+ if (func)
+ {
+ /* In certain pathological cases, the symtabs give the wrong
+ function (when we are in the first function in a file which
+ is compiled without debugging symbols, the previous function
+ is compiled with debugging symbols, and the "foo.o" symbol
+ that is supposed to tell us where the file with debugging symbols
+ ends has been truncated by ar because it is longer than 15
+ characters). 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 (get_frame_address_in_block (fi));
+ 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 = DEPRECATED_SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ else
+ {
+ /* I'd like to use SYMBOL_PRINT_NAME() here, to display the
+ demangled name that we already have stored in the symbol
+ table, but we stored a version with DMGL_PARAMS turned
+ on, and here we don't want to display parameters. So call
+ the demangler again, with DMGL_ANSI only. (Yes, I know
+ that printf_symbol_filtered() will again try to demangle
+ the name on the fly, but the issue is that if
+ cplus_demangle() fails here, it'll fail there too. So we
+ want to catch the failure ("demangled==NULL" case below)
+ here, while we still have our hands on the function
+ symbol.) */
+ char *demangled;
+ funname = DEPRECATED_SYMBOL_NAME (func);
+ funlang = SYMBOL_LANGUAGE (func);
+ if (funlang == language_cplus)
+ {
+ demangled = cplus_demangle (funname, DMGL_ANSI);
+ if (demangled == NULL)
+ /* If the demangler fails, try the demangled name from
+ the symbol table. This'll have parameters, but
+ that's preferable to diplaying a mangled name. */
+ funname = SYMBOL_PRINT_NAME (func);
+ }
+ }
+ }
+ else
+ {
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_address_in_block (fi));
+ if (msymbol != NULL)
+ {
+ funname = DEPRECATED_SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+
+ annotate_frame_begin (level == -1 ? 0 : level, get_frame_pc (fi));
+
+ list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
+
+ if (level >= 0)
+ {
+ ui_out_text (uiout, "#");
+ ui_out_field_fmt_int (uiout, 2, ui_left, "level", level);
+ }
+ if (addressprint)
+ if (get_frame_pc (fi) != sal.pc
+ || !sal.symtab
+ || source == LOC_AND_ADDRESS)
+ {
+ annotate_frame_address ();
+ ui_out_field_core_addr (uiout, "addr", get_frame_pc (fi));
+ annotate_frame_address_end ();
+ ui_out_text (uiout, " in ");
+ }
+ annotate_frame_function_name ();
+ fprintf_symbol_filtered (stb->stream, funname ? funname : "??", funlang,
+ DMGL_ANSI);
+ ui_out_field_stream (uiout, "func", stb);
+ ui_out_wrap_hint (uiout, " ");
+ annotate_frame_args ();
+
+ ui_out_text (uiout, " (");
+ if (args)
+ {
+ struct print_args_args args;
+ struct cleanup *args_list_chain;
+ args.fi = fi;
+ args.func = func;
+ args.stream = gdb_stdout;
+ args_list_chain = make_cleanup_ui_out_list_begin_end (uiout, "args");
+ catch_errors (print_args_stub, &args, "", RETURN_MASK_ALL);
+ /* FIXME: args must be a list. If one argument is a string it will
+ have " that will not be properly escaped. */
+ /* Invoke ui_out_tuple_end. */
+ do_cleanups (args_list_chain);
+ QUIT;
+ }
+ ui_out_text (uiout, ")");
+ if (sal.symtab && sal.symtab->filename)
+ {
+ annotate_frame_source_begin ();
+ ui_out_wrap_hint (uiout, " ");
+ ui_out_text (uiout, " at ");
+ annotate_frame_source_file ();
+ ui_out_field_string (uiout, "file", sal.symtab->filename);
+ annotate_frame_source_file_end ();
+ ui_out_text (uiout, ":");
+ annotate_frame_source_line ();
+ ui_out_field_int (uiout, "line", sal.line);
+ annotate_frame_source_end ();
+ }
+
+#ifdef PC_SOLIB
+ if (!funname || (!sal.symtab || !sal.symtab->filename))
+ {
+ char *lib = PC_SOLIB (get_frame_pc (fi));
+ if (lib)
+ {
+ annotate_frame_where ();
+ ui_out_wrap_hint (uiout, " ");
+ ui_out_text (uiout, " from ");
+ ui_out_field_string (uiout, "from", lib);
+ }
+ }
+#endif /* PC_SOLIB */
+
+ /* do_cleanups will call ui_out_tuple_end() for us. */
+ do_cleanups (list_chain);
+ ui_out_text (uiout, "\n");
+ do_cleanups (old_chain);
+}
+
+/* Show the frame info. If this is the tui, it will be shown in
+ the source display otherwise, nothing is done */
+void
+show_stack_frame (struct frame_info *fi)
+{
+}
+
+
+/* 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). */
+
+struct frame_info *
+parse_frame_specification (char *frame_exp)
+{
+ int numargs = 0;
+#define MAXARGS 4
+ CORE_ADDR args[MAXARGS];
+ int level;
+
+ 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);
+
+ {
+ struct value *vp;
+
+ tmp_cleanup = make_cleanup (xfree, addr_string);
+
+ /* NOTE: we call parse_and_eval and then both
+ value_as_long and value_as_address rather than calling
+ parse_and_eval_long and parse_and_eval_address because
+ of the issue of potential side effects from evaluating
+ the expression. */
+ vp = parse_and_eval (addr_string);
+ if (numargs == 0)
+ level = value_as_long (vp);
+
+ args[numargs++] = value_as_address (vp);
+ do_cleanups (tmp_cleanup);
+ }
+
+ /* Skip spaces, move to possible next arg. */
+ while (*p == ' ')
+ p++;
+ frame_exp = p;
+ }
+ }
+
+ switch (numargs)
+ {
+ case 0:
+ if (deprecated_selected_frame == NULL)
+ error ("No selected frame.");
+ return deprecated_selected_frame;
+ /* NOTREACHED */
+ case 1:
+ {
+ 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 %s", paddr_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 && get_frame_base (fid) != args[0];
+ fid = get_prev_frame (fid))
+ ;
+
+ if (fid)
+ while ((tfid = get_prev_frame (fid)) &&
+ (get_frame_base (tfid) == 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 */
+}
+
+/* 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 (char *addr_exp, int from_tty)
+{
+ struct frame_info *fi;
+ 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;
+ const char *pc_regname;
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ /* Name of the value returned by get_frame_pc(). Per comments, "pc"
+ is not a good name. */
+ if (PC_REGNUM >= 0)
+ /* OK, this is weird. The PC_REGNUM hardware register's value can
+ easily not match that of the internal value returned by
+ get_frame_pc(). */
+ pc_regname = REGISTER_NAME (PC_REGNUM);
+ else
+ /* But then, this is weird to. Even without PC_REGNUM, an
+ architectures will often have a hardware register called "pc",
+ and that register's value, again, can easily not match
+ get_frame_pc(). */
+ pc_regname = "pc";
+
+ fi = parse_frame_specification (addr_exp);
+ if (fi == NULL)
+ error ("Invalid frame specified.");
+
+ find_frame_sal (fi, &sal);
+ func = get_frame_function (fi);
+ /* FIXME: cagney/2002-11-28: Why bother? Won't sal.symtab contain
+ the same value. */
+ s = find_pc_symtab (get_frame_pc (fi));
+ if (func)
+ {
+ /* I'd like to use SYMBOL_PRINT_NAME() here, to display
+ * the demangled name that we already have stored in
+ * the symbol table, but we stored a version with
+ * DMGL_PARAMS turned on, and here we don't want
+ * to display parameters. So call the demangler again,
+ * with DMGL_ANSI only. RT
+ * (Yes, I know that printf_symbol_filtered() will
+ * again try to demangle the name on the fly, but
+ * the issue is that if cplus_demangle() fails here,
+ * it'll fail there too. So we want to catch the failure
+ * ("demangled==NULL" case below) here, while we still
+ * have our hands on the function symbol.)
+ */
+ char *demangled;
+ funname = DEPRECATED_SYMBOL_NAME (func);
+ funlang = SYMBOL_LANGUAGE (func);
+ if (funlang == language_cplus)
+ {
+ demangled = cplus_demangle (funname, DMGL_ANSI);
+ /* If the demangler fails, try the demangled name
+ * from the symbol table. This'll have parameters,
+ * but that's preferable to diplaying a mangled name.
+ */
+ if (demangled == NULL)
+ funname = SYMBOL_PRINT_NAME (func);
+ }
+ }
+ else
+ {
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (fi));
+ if (msymbol != NULL)
+ {
+ funname = DEPRECATED_SYMBOL_NAME (msymbol);
+ funlang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+ calling_frame_info = get_prev_frame (fi);
+
+ if (!addr_exp && frame_relative_level (deprecated_selected_frame) >= 0)
+ {
+ printf_filtered ("Stack level %d, frame at ",
+ frame_relative_level (deprecated_selected_frame));
+ print_address_numeric (get_frame_base (fi), 1, gdb_stdout);
+ printf_filtered (":\n");
+ }
+ else
+ {
+ printf_filtered ("Stack frame at ");
+ print_address_numeric (get_frame_base (fi), 1, gdb_stdout);
+ printf_filtered (":\n");
+ }
+ printf_filtered (" %s = ", pc_regname);
+ print_address_numeric (get_frame_pc (fi), 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 ", pc_regname);
+ print_address_numeric (frame_pc_unwind (fi), 1, gdb_stdout);
+ printf_filtered ("\n");
+
+ {
+ int frameless;
+ frameless = (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ()
+ && DEPRECATED_FRAMELESS_FUNCTION_INVOCATION (fi));
+ if (frameless)
+ printf_filtered (" (FRAMELESS),");
+ }
+
+ if (calling_frame_info)
+ {
+ printf_filtered (" called by frame at ");
+ print_address_numeric (get_frame_base (calling_frame_info),
+ 1, gdb_stdout);
+ }
+ if (get_next_frame (fi) && calling_frame_info)
+ puts_filtered (",");
+ wrap_here (" ");
+ if (get_next_frame (fi))
+ {
+ printf_filtered (" caller of frame at ");
+ print_address_numeric (get_frame_base (get_next_frame (fi)), 1,
+ gdb_stdout);
+ }
+ if (get_next_frame (fi) || calling_frame_info)
+ puts_filtered ("\n");
+ if (s)
+ printf_filtered (" source language %s.\n",
+ language_str (s->language));
+
+ {
+ /* Address of the argument list for this frame, or 0. */
+ CORE_ADDR arg_list = get_frame_args_address (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 (",");
+
+ if (!FRAME_NUM_ARGS_P ())
+ {
+ numargs = -1;
+ puts_filtered (" args: ");
+ }
+ else
+ {
+ numargs = FRAME_NUM_ARGS (fi);
+ gdb_assert (numargs >= 0);
+ 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 = get_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 (DEPRECATED_FRAME_INIT_SAVED_REGS_P ()
+ && deprecated_get_frame_saved_regs (fi) == NULL)
+ DEPRECATED_FRAME_INIT_SAVED_REGS (fi);
+ /* Print as much information as possible on the location of all the
+ registers. */
+ {
+ enum lval_type lval;
+ int optimized;
+ CORE_ADDR addr;
+ int realnum;
+ int count;
+ int i;
+ int need_nl = 1;
+
+ /* The sp is special; what's displayed isn't the save address, but
+ the value of the previous frame's sp. This is a legacy thing,
+ at one stage the frame cached the previous frame's SP instead
+ of its address, hence it was easiest to just display the cached
+ value. */
+ if (SP_REGNUM >= 0)
+ {
+ /* Find out the location of the saved stack pointer with out
+ actually evaluating it. */
+ frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
+ &realnum, NULL);
+ if (!optimized && lval == not_lval)
+ {
+ char value[MAX_REGISTER_SIZE];
+ CORE_ADDR sp;
+ frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
+ &realnum, value);
+ /* NOTE: cagney/2003-05-22: This is assuming that the
+ stack pointer was packed as an unsigned integer. That
+ may or may not be valid. */
+ sp = extract_unsigned_integer (value, DEPRECATED_REGISTER_RAW_SIZE (SP_REGNUM));
+ printf_filtered (" Previous frame's sp is ");
+ print_address_numeric (sp, 1, gdb_stdout);
+ printf_filtered ("\n");
+ need_nl = 0;
+ }
+ else if (!optimized && lval == lval_memory)
+ {
+ printf_filtered (" Previous frame's sp at ");
+ print_address_numeric (addr, 1, gdb_stdout);
+ printf_filtered ("\n");
+ need_nl = 0;
+ }
+ else if (!optimized && lval == lval_register)
+ {
+ printf_filtered (" Previous frame's sp in %s\n",
+ REGISTER_NAME (realnum));
+ need_nl = 0;
+ }
+ /* else keep quiet. */
+ }
+
+ count = 0;
+ numregs = NUM_REGS + NUM_PSEUDO_REGS;
+ for (i = 0; i < numregs; i++)
+ if (i != SP_REGNUM
+ && gdbarch_register_reggroup_p (current_gdbarch, i, all_reggroup))
+ {
+ /* Find out the location of the saved register without
+ fetching the corresponding value. */
+ frame_register_unwind (fi, i, &optimized, &lval, &addr, &realnum,
+ NULL);
+ /* For moment, only display registers that were saved on the
+ stack. */
+ if (!optimized && lval == lval_memory)
+ {
+ if (count == 0)
+ puts_filtered (" Saved registers:\n ");
+ else
+ puts_filtered (",");
+ wrap_here (" ");
+ printf_filtered (" %s at ", REGISTER_NAME (i));
+ print_address_numeric (addr, 1, gdb_stdout);
+ count++;
+ }
+ }
+ if (count || need_nl)
+ puts_filtered ("\n");
+ }
+}
+
+#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 (char *count_exp, int from_tty)
+{
+ int count = parse_and_eval_long (count_exp);
+
+ if (count < 0)
+ error ("Negative argument not meaningful as backtrace limit.");
+
+ backtrace_limit = count;
+}
+
+static void
+backtrace_limit_info (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_1 (char *count_exp, int show_locals,
+ int from_tty);
+static void
+backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
+{
+ struct frame_info *fi;
+ int count;
+ int i;
+ struct frame_info *trailing;
+ 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 ();
+
+ /* The target can be in a state where there is no valid frames
+ (e.g., just connected). */
+ if (trailing == NULL)
+ error ("No stack.");
+
+ trailing_level = 0;
+ if (count_exp)
+ {
+ count = parse_and_eval_long (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 (get_frame_address_in_block (fi));
+ 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 (show_locals)
+ print_frame_local_vars (fi, 1, gdb_stdout);
+ }
+
+ /* If we've stopped before the end, mention that. */
+ if (fi && from_tty)
+ printf_filtered ("(More stack frames follow...)\n");
+}
+
+struct backtrace_command_args
+ {
+ char *count_exp;
+ int show_locals;
+ int from_tty;
+ };
+
+/* Stub to call backtrace_command_1 by way of an error catcher. */
+static int
+backtrace_command_stub (void *data)
+{
+ struct backtrace_command_args *args = (struct backtrace_command_args *)data;
+ backtrace_command_1 (args->count_exp, args->show_locals, args->from_tty);
+ return 0;
+}
+
+static void
+backtrace_command (char *arg, int from_tty)
+{
+ struct cleanup *old_chain = (struct cleanup *) NULL;
+ char **argv = (char **) NULL;
+ int argIndicatingFullTrace = (-1), totArgLen = 0, argc = 0;
+ char *argPtr = arg;
+ struct backtrace_command_args btargs;
+
+ if (arg != (char *) NULL)
+ {
+ int i;
+
+ argv = buildargv (arg);
+ old_chain = make_cleanup_freeargv (argv);
+ argc = 0;
+ for (i = 0; (argv[i] != (char *) NULL); i++)
+ {
+ unsigned int j;
+
+ for (j = 0; (j < strlen (argv[i])); j++)
+ argv[i][j] = tolower (argv[i][j]);
+
+ if (argIndicatingFullTrace < 0 && subset_compare (argv[i], "full"))
+ argIndicatingFullTrace = argc;
+ else
+ {
+ argc++;
+ totArgLen += strlen (argv[i]);
+ }
+ }
+ totArgLen += argc;
+ if (argIndicatingFullTrace >= 0)
+ {
+ if (totArgLen > 0)
+ {
+ argPtr = (char *) xmalloc (totArgLen + 1);
+ if (!argPtr)
+ nomem (0);
+ else
+ {
+ memset (argPtr, 0, totArgLen + 1);
+ for (i = 0; (i < (argc + 1)); i++)
+ {
+ if (i != argIndicatingFullTrace)
+ {
+ strcat (argPtr, argv[i]);
+ strcat (argPtr, " ");
+ }
+ }
+ }
+ }
+ else
+ argPtr = (char *) NULL;
+ }
+ }
+
+ btargs.count_exp = argPtr;
+ btargs.show_locals = (argIndicatingFullTrace >= 0);
+ btargs.from_tty = from_tty;
+ catch_errors (backtrace_command_stub, (char *)&btargs, "", RETURN_MASK_ERROR);
+
+ if (argIndicatingFullTrace >= 0 && totArgLen > 0)
+ xfree (argPtr);
+
+ if (old_chain)
+ do_cleanups (old_chain);
+}
+
+static void backtrace_full_command (char *arg, int from_tty);
+static void
+backtrace_full_command (char *arg, int from_tty)
+{
+ struct backtrace_command_args btargs;
+ btargs.count_exp = arg;
+ btargs.show_locals = 1;
+ btargs.from_tty = from_tty;
+ catch_errors (backtrace_command_stub, (char *)&btargs, "", RETURN_MASK_ERROR);
+}
+
+
+/* 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 (struct block *b, struct frame_info *fi,
+ int num_tabs, struct ui_file *stream)
+{
+ struct dict_iterator iter;
+ int j;
+ struct symbol *sym;
+ int values_printed = 0;
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_LOCAL:
+ case LOC_REGISTER:
+ case LOC_STATIC:
+ case LOC_BASEREG:
+ case LOC_COMPUTED:
+ values_printed = 1;
+ for (j = 0; j < num_tabs; j++)
+ fputs_filtered ("\t", stream);
+ fputs_filtered (SYMBOL_PRINT_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 (struct block *b, int *have_default,
+ struct ui_file *stream)
+{
+ struct dict_iterator iter;
+ struct symbol *sym;
+ int values_printed = 0;
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ if (DEPRECATED_STREQ (DEPRECATED_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_PRINT_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 (struct frame_info *fi, int num_tabs,
+ struct ui_file *stream)
+{
+ struct block *block = get_frame_block (fi, 0);
+ 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, num_tabs, stream))
+ values_printed = 1;
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ 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 (struct frame_info *fi, int this_level_only,
+ struct ui_file *stream)
+{
+ struct blockvector *bl;
+ struct block *block = get_frame_block (fi, 0);
+ int values_printed = 0;
+ int index, have_default = 0;
+ char *blocks_printed;
+ CORE_ADDR pc = get_frame_pc (fi);
+
+ 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");
+ }
+}
+
+void
+locals_info (char *args, int from_tty)
+{
+ if (!deprecated_selected_frame)
+ error ("No frame selected.");
+ print_frame_local_vars (deprecated_selected_frame, 0, gdb_stdout);
+}
+
+static void
+catch_info (char *ignore, int from_tty)
+{
+ struct symtab_and_line *sal;
+
+ /* Check for target support for exception handling */
+ sal = target_enable_exception_callback (EX_EVENT_CATCH, 1);
+ if (sal)
+ {
+ /* Currently not handling this */
+ /* Ideally, here we should interact with the C++ runtime
+ system to find the list of active handlers, etc. */
+ fprintf_filtered (gdb_stdout, "Info catch not supported with this target/compiler combination.\n");
+#if 0
+ if (!deprecated_selected_frame)
+ error ("No frame selected.");
+#endif
+ }
+ else
+ {
+ /* Assume g++ compiled code -- old v 4.16 behaviour */
+ if (!deprecated_selected_frame)
+ error ("No frame selected.");
+
+ print_frame_label_vars (deprecated_selected_frame, 0, gdb_stdout);
+ }
+}
+
+static void
+print_frame_arg_vars (struct frame_info *fi,
+ struct ui_file *stream)
+{
+ struct symbol *func = get_frame_function (fi);
+ struct block *b;
+ struct dict_iterator iter;
+ struct symbol *sym, *sym2;
+ int values_printed = 0;
+
+ if (func == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ return;
+ }
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ 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:
+ case LOC_COMPUTED_ARG:
+ values_printed = 1;
+ fputs_filtered (SYMBOL_PRINT_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 (DEPRECATED_SYMBOL_NAME (sym),
+ b, VAR_DOMAIN, (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");
+ }
+}
+
+void
+args_info (char *ignore, int from_tty)
+{
+ if (!deprecated_selected_frame)
+ error ("No frame selected.");
+ print_frame_arg_vars (deprecated_selected_frame, gdb_stdout);
+}
+
+
+static void
+args_plus_locals_info (char *ignore, int from_tty)
+{
+ args_info (ignore, from_tty);
+ locals_info (ignore, from_tty);
+}
+
+
+/* Select frame FI. Also print the stack frame and show the source if
+ this is the tui version. */
+static void
+select_and_print_frame (struct frame_info *fi)
+{
+ select_frame (fi);
+ if (fi)
+ {
+ print_stack_frame (fi, frame_relative_level (fi), 1);
+ }
+}
+
+/* Return the symbol-block in which the selected frame is executing.
+ Can return zero under various legitimate circumstances.
+
+ If ADDR_IN_BLOCK is non-zero, set *ADDR_IN_BLOCK to the relevant
+ code address within the block returned. We use this to decide
+ which macros are in scope. */
+
+struct block *
+get_selected_block (CORE_ADDR *addr_in_block)
+{
+ if (!target_has_stack)
+ return 0;
+
+ /* NOTE: cagney/2002-11-28: Why go to all this effort to not create
+ a selected/current frame? Perhaphs this function is called,
+ indirectly, by WFI in "infrun.c" where avoiding the creation of
+ an inner most frame is very important (it slows down single
+ step). I suspect, though that this was true in the deep dark
+ past but is no longer the case. A mindless look at all the
+ callers tends to support this theory. I think we should be able
+ to assume that there is always a selcted frame. */
+ /* gdb_assert (deprecated_selected_frame != NULL); So, do you feel
+ lucky? */
+ if (!deprecated_selected_frame)
+ {
+ CORE_ADDR pc = read_pc ();
+ if (addr_in_block != NULL)
+ *addr_in_block = pc;
+ return block_for_pc (pc);
+ }
+ return get_frame_block (deprecated_selected_frame, addr_in_block);
+}
+
+/* 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 (struct frame_info *frame,
+ int *level_offset_ptr)
+{
+ struct frame_info *prev;
+ 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. */
+
+void
+select_frame_command (char *level_exp, int from_tty)
+{
+ struct frame_info *frame;
+ int level = frame_relative_level (deprecated_selected_frame);
+
+ if (!target_has_stack)
+ error ("No stack.");
+
+ frame = parse_frame_specification (level_exp);
+
+ select_frame (frame);
+ if (level != frame_relative_level (deprecated_selected_frame))
+ selected_frame_level_changed_event (frame_relative_level (deprecated_selected_frame));
+}
+
+/* The "frame" command. With no arg, print selected frame briefly.
+ With arg, behaves like select_frame and then prints the selected
+ frame. */
+
+void
+frame_command (char *level_exp, int from_tty)
+{
+ select_frame_command (level_exp, from_tty);
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 1);
+}
+
+/* The XDB Compatibility command to print the current frame. */
+
+static void
+current_frame_command (char *level_exp, int from_tty)
+{
+ if (target_has_stack == 0 || deprecated_selected_frame == 0)
+ error ("No stack.");
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 1);
+}
+
+/* Select the frame up one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+static void
+up_silently_base (char *count_exp)
+{
+ struct frame_info *fi;
+ int count = 1, count1;
+ if (count_exp)
+ count = parse_and_eval_long (count_exp);
+ count1 = count;
+
+ if (target_has_stack == 0 || deprecated_selected_frame == 0)
+ error ("No stack.");
+
+ fi = find_relative_frame (deprecated_selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ error ("Initial frame selected; you cannot go up.");
+ select_frame (fi);
+ selected_frame_level_changed_event (frame_relative_level (deprecated_selected_frame));
+}
+
+static void
+up_silently_command (char *count_exp, int from_tty)
+{
+ up_silently_base (count_exp);
+}
+
+static void
+up_command (char *count_exp, int from_tty)
+{
+ up_silently_base (count_exp);
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 1);
+}
+
+/* Select the frame down one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+static void
+down_silently_base (char *count_exp)
+{
+ struct frame_info *frame;
+ int count = -1, count1;
+ if (count_exp)
+ count = -parse_and_eval_long (count_exp);
+ count1 = count;
+
+ if (target_has_stack == 0 || deprecated_selected_frame == 0)
+ error ("No stack.");
+
+ frame = find_relative_frame (deprecated_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_changed_event (frame_relative_level (deprecated_selected_frame));
+}
+
+static void
+down_silently_command (char *count_exp, int from_tty)
+{
+ down_silently_base (count_exp);
+}
+
+static void
+down_command (char *count_exp, int from_tty)
+{
+ down_silently_base (count_exp);
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 1);
+}
+
+void
+return_command (char *retval_exp, int from_tty)
+{
+ struct symbol *thisfun;
+ struct value *return_value = NULL;
+ const char *query_prefix = "";
+
+ /* FIXME: cagney/2003-10-20: Perform a minimal existance test on the
+ target. If that fails, error out. For the moment don't rely on
+ get_selected_frame as it's error message is the the singularly
+ obscure "No registers". */
+ if (!target_has_registers)
+ error ("No selected frame.");
+ thisfun = get_frame_function (get_selected_frame ());
+
+ /* Compute the return value. If the computation triggers an error,
+ let it bail. If the return type can't be handled, set
+ RETURN_VALUE to NULL, and QUERY_PREFIX to an informational
+ message. */
+ if (retval_exp)
+ {
+ struct type *return_type = NULL;
+
+ /* Compute the return value. Should the computation fail, this
+ call throws an error. */
+ return_value = parse_and_eval (retval_exp);
+
+ /* Cast return value to the return type of the function. Should
+ the cast fail, this call throws an error. */
+ 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 the value is fully evaluated. It may live in the
+ stack frame we're about to pop. */
+ if (VALUE_LAZY (return_value))
+ value_fetch_lazy (return_value);
+
+ if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
+ /* If the return-type is "void", don't try to find the
+ return-value's location. However, do still evaluate the
+ return expression so that, even when the expression result
+ is discarded, side effects such as "return i++" still
+ occure. */
+ return_value = NULL;
+ /* FIXME: cagney/2004-01-17: If the architecture implements both
+ return_value and extract_returned_value_address, should allow
+ "return" to work - don't set return_value to NULL. */
+ else if (!gdbarch_return_value_p (current_gdbarch)
+ && (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (return_type) == TYPE_CODE_UNION))
+ {
+ /* NOTE: cagney/2003-10-20: Compatibility hack for legacy
+ code. Old architectures don't expect STORE_RETURN_VALUE
+ to be called with with a small struct that needs to be
+ stored in registers. Don't start doing it now. */
+ query_prefix = "\
+A structure or union return type is not supported by this architecture.\n\
+If you continue, the return value that you specified will be ignored.\n";
+ return_value = NULL;
+ }
+ else if (using_struct_return (return_type, 0))
+ {
+ query_prefix = "\
+The location at which to store the function's return value is unknown.\n\
+If you continue, the return value that you specified will be ignored.\n";
+ return_value = NULL;
+ }
+ }
+
+ /* Does an interactive user really want to do this? Include
+ information, such as how well GDB can handle the return value, in
+ the query message. */
+ if (from_tty)
+ {
+ int confirmed;
+ if (thisfun == NULL)
+ confirmed = query ("%sMake selected stack frame return now? ",
+ query_prefix);
+ else
+ confirmed = query ("%sMake %s return now? ", query_prefix,
+ SYMBOL_PRINT_NAME (thisfun));
+ if (!confirmed)
+ error ("Not confirmed");
+ }
+
+ /* NOTE: cagney/2003-01-18: Is this silly? Rather than pop each
+ frame in turn, should this code just go straight to the relevant
+ frame and pop that? */
+
+ /* First discard all frames inner-to the selected frame (making the
+ selected frame current). */
+ {
+ struct frame_id selected_id = get_frame_id (get_selected_frame ());
+ while (!frame_id_eq (selected_id, get_frame_id (get_current_frame ())))
+ {
+ if (frame_id_inner (selected_id, get_frame_id (get_current_frame ())))
+ /* Caught in the safety net, oops! We've gone way past the
+ selected frame. */
+ error ("Problem while popping stack frames (corrupt stack?)");
+ frame_pop (get_current_frame ());
+ }
+ }
+
+ /* Second discard the selected frame (which is now also the current
+ frame). */
+ frame_pop (get_current_frame ());
+
+ /* Store RETURN_VAUE in the just-returned register set. */
+ if (return_value != NULL)
+ {
+ struct type *return_type = VALUE_TYPE (return_value);
+ if (!gdbarch_return_value_p (current_gdbarch))
+ {
+ STORE_RETURN_VALUE (return_type, current_regcache,
+ VALUE_CONTENTS (return_value));
+ }
+ /* FIXME: cagney/2004-01-17: If extract_returned_value_address
+ is available and the function is using
+ RETURN_VALUE_STRUCT_CONVENTION, should use it to find the
+ address of the returned value so that it can be assigned. */
+ else
+ {
+ gdb_assert (gdbarch_return_value (current_gdbarch, return_type,
+ NULL, NULL, NULL)
+ == RETURN_VALUE_REGISTER_CONVENTION);
+ gdbarch_return_value (current_gdbarch, return_type,
+ current_regcache, NULL /*read*/,
+ VALUE_CONTENTS (return_value) /*write*/);
+ }
+ }
+
+ /* If we are at the end of a call dummy now, pop the dummy frame
+ too. */
+ /* NOTE: cagney/2003-01-18: Is this silly? Instead of popping all
+ the frames in sequence, should this code just pop the dummy frame
+ directly? */
+#ifdef DEPRECATED_CALL_DUMMY_HAS_COMPLETED
+ /* Since all up-to-date architectures return direct to the dummy
+ breakpoint address, a dummy frame has, by definition, always
+ completed. Hence this method is no longer needed. */
+ if (DEPRECATED_CALL_DUMMY_HAS_COMPLETED (read_pc(), read_sp (),
+ get_frame_base (get_current_frame ())))
+ frame_pop (get_current_frame ());
+#else
+ if (get_frame_type (get_current_frame ()) == DUMMY_FRAME)
+ frame_pop (get_current_frame ());
+#endif
+
+ /* If interactive, print the frame that is now current. */
+ if (from_tty)
+ frame_command ("0", 1);
+ else
+ select_frame_command ("0", 0);
+}
+
+/* Sets the scope to input function name, provided that the
+ function is within the current stack frame */
+
+struct function_bounds
+{
+ CORE_ADDR low, high;
+};
+
+static void func_command (char *arg, int from_tty);
+static void
+func_command (char *arg, int from_tty)
+{
+ struct frame_info *fp;
+ int found = 0;
+ struct symtabs_and_lines sals;
+ int i;
+ int level = 1;
+ struct function_bounds *func_bounds = (struct function_bounds *) NULL;
+
+ if (arg != (char *) NULL)
+ return;
+
+ fp = parse_frame_specification ("0");
+ sals = decode_line_spec (arg, 1);
+ func_bounds = (struct function_bounds *) xmalloc (
+ sizeof (struct function_bounds) * sals.nelts);
+ for (i = 0; (i < sals.nelts && !found); i++)
+ {
+ if (sals.sals[i].pc == (CORE_ADDR) 0 ||
+ find_pc_partial_function (sals.sals[i].pc,
+ (char **) NULL,
+ &func_bounds[i].low,
+ &func_bounds[i].high) == 0)
+ {
+ func_bounds[i].low =
+ func_bounds[i].high = (CORE_ADDR) NULL;
+ }
+ }
+
+ do
+ {
+ for (i = 0; (i < sals.nelts && !found); i++)
+ found = (get_frame_pc (fp) >= func_bounds[i].low &&
+ get_frame_pc (fp) < func_bounds[i].high);
+ if (!found)
+ {
+ level = 1;
+ fp = find_relative_frame (fp, &level);
+ }
+ }
+ while (!found && level == 0);
+
+ if (func_bounds)
+ xfree (func_bounds);
+
+ if (!found)
+ printf_filtered ("'%s' not within current stack frame.\n", arg);
+ else if (fp != deprecated_selected_frame)
+ select_and_print_frame (fp);
+}
+
+/* Gets the language of the current frame. */
+
+enum language
+get_frame_language (void)
+{
+ struct symtab *s;
+ enum language flang; /* The language of the current frame */
+
+ if (deprecated_selected_frame)
+ {
+ /* We determine the current frame language by looking up its
+ associated symtab. To retrieve this symtab, we use the frame PC.
+ However we cannot use the frame pc as is, because it usually points
+ to the instruction following the "call", which is sometimes the first
+ instruction of another function. So we rely on
+ get_frame_address_in_block(), it provides us with a PC which is
+ guaranteed to be inside the frame's code block. */
+ s = find_pc_symtab (get_frame_address_in_block (deprecated_selected_frame));
+ if (s)
+ flang = s->language;
+ else
+ flang = language_unknown;
+ }
+ else
+ flang = language_unknown;
+
+ return flang;
+}
+
+void
+_initialize_stack (void)
+{
+#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);
+
+ if (xdb_commands)
+ {
+ add_com ("L", class_stack, current_frame_command,
+ "Print the current stack frame.\n");
+ add_com_alias ("V", "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.\n\
+Use of the 'full' qualifier also prints the values of the local variables.\n");
+ add_com_alias ("bt", "backtrace", class_stack, 0);
+ if (xdb_commands)
+ {
+ add_com_alias ("t", "backtrace", class_stack, 0);
+ add_com ("T", class_stack, backtrace_full_command,
+ "Print backtrace of all stack frames, or innermost COUNT frames \n\
+and the values of the local variables.\n\
+With a negative argument, print outermost -COUNT frames.\n\
+Usage: T <count>\n");
+ }
+
+ 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.");
+ if (xdb_commands)
+ add_com ("l", class_info, args_plus_locals_info,
+ "Argument and local variables of current stack frame.");
+
+ if (dbx_commands)
+ add_com ("func", class_stack, func_command,
+ "Select the stack frame that contains <func>.\nUsage: func <name>\n");
+
+ 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/stack.h b/contrib/gdb/gdb/stack.h
new file mode 100644
index 0000000..0891c94
--- /dev/null
+++ b/contrib/gdb/gdb/stack.h
@@ -0,0 +1,27 @@
+/* Stack manipulation commands, for GDB the GNU Debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 STACK_H
+#define STACK_H
+
+void select_frame_command (char *level_exp, int from_tty);
+
+#endif /* #ifndef STACK_H */
diff --git a/contrib/gdb/gdb/standalone.c b/contrib/gdb/gdb/standalone.c
new file mode 100644
index 0000000..906e37a
--- /dev/null
+++ b/contrib/gdb/gdb/standalone.c
@@ -0,0 +1,580 @@
+/* Interface to bare machine for GDB running as kernel debugger.
+
+ Copyright 1986, 1989, 1991, 1992, 1993, 1995, 1996, 2000, 2001,
+ 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stdio.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "gdb_stat.h"
+
+#if defined (SIGTSTP) && defined (SIGIO)
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif /* SIGTSTP and SIGIO defined (must be 4.2) */
+
+#include "defs.h"
+#include <signal.h>
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdb_wait.h"
+
+
+/* Random system calls, mostly no-ops to prevent link problems */
+
+ioctl (int desc, int code, int arg)
+{
+}
+
+int (*signal ()) ()
+{
+}
+
+kill (void)
+{
+}
+
+getpid (void)
+{
+ return 0;
+}
+
+sigsetmask (void)
+{
+}
+
+chdir (void)
+{
+}
+
+char *
+getcwd (char *buf, unsigned int len)
+{
+ buf[0] = '/';
+ buf[1] = 0;
+ return buf;
+}
+
+/* Used to check for existence of .gdbinit. Say no. */
+
+access (void)
+{
+ return -1;
+}
+
+exit (void)
+{
+ 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 (char *filename, int modes)
+{
+ 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 (int desc)
+{
+ sourceptr = 0;
+ sourcedesc++;
+ /* Don't let sourcedesc get big enough to be confused with stdin. */
+ if (sourcedesc == 100)
+ sourcedesc = 5;
+}
+
+FILE *
+fopen (char *filename, char *modes)
+{
+ return (FILE *) open (filename, *modes == 'w');
+}
+
+FILE *
+fdopen (int desc)
+{
+ return (FILE *) desc;
+}
+
+fclose (int desc)
+{
+ close (desc);
+}
+
+fstat (int desc, struct stat *statbuf)
+{
+ if (desc != sourcedesc)
+ {
+ errno = EBADF;
+ return -1;
+ }
+ statbuf->st_size = sourcesize;
+}
+
+myread (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 (int bufp, int numelts, int eltsize, int stream)
+{
+ int elts = min (numelts, sourceleft / eltsize);
+ int len = elts * eltsize;
+
+ if (stream != sourcedesc)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ memcpy (bufp, sourceptr, len);
+ sourceleft -= len;
+ return elts;
+}
+
+int
+fgetc (int desc)
+{
+
+ if (desc == (int) stdin)
+ return tty_input ();
+
+ if (desc != sourcedesc)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (sourceleft-- <= 0)
+ return EOF;
+ return *sourceptr++;
+}
+
+lseek (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 (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9)
+{
+ char buffer[1024];
+ sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ display_string (buffer);
+}
+
+fprintf (int ign, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
+ int a8, int a9)
+{
+ char buffer[1024];
+ sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ display_string (buffer);
+}
+
+fwrite (char *buf, int numelts, int size, int stream)
+{
+ int i = numelts * size;
+ while (i-- > 0)
+ fputc (*buf++, stream);
+}
+
+fputc (int c, int 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 (void)
+{
+ error ("_flsbuf was actually called.");
+}
+
+fflush (int ign)
+{
+}
+
+/* Entries into core and inflow, needed only to make things link ok. */
+
+exec_file_command (void)
+{
+}
+
+core_file_command (void)
+{
+}
+
+char *
+get_exec_file (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 (void)
+{
+ return 0;
+}
+
+kill_command (void)
+{
+ inferior_ptid = null_ptid;
+}
+
+terminal_inferior (void)
+{
+}
+
+terminal_ours (void)
+{
+}
+
+terminal_init_inferior (void)
+{
+}
+
+write_inferior_register (void)
+{
+}
+
+read_inferior_register (void)
+{
+}
+
+read_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ memcpy (myaddr, memaddr, len);
+}
+
+/* Always return 0 indicating success. */
+
+write_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ memcpy (memaddr, myaddr, len);
+ return 0;
+}
+
+static REGISTER_TYPE saved_regs[NUM_REGS];
+
+REGISTER_TYPE
+read_register (int regno)
+{
+ if (regno < 0 || regno >= NUM_REGS)
+ error ("Register number %d out of range.", regno);
+ return saved_regs[regno];
+}
+
+void
+write_register (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 (void)
+{
+ /* 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 (void)
+{
+}
+
+setpgrp (void)
+{
+}
+
+execle (void)
+{
+}
+
+_exit (void)
+{
+}
+
+/* Malloc calls these. */
+
+malloc_warning (char *str)
+{
+ printf ("\n%s.\n\n", str);
+}
+
+char *next_free;
+char *memory_limit;
+
+char *
+sbrk (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 (void)
+{
+ return memory_limit;
+}
+
+int
+vlimit (void)
+{
+ return memory_limit - next_free;
+}
+
+getrlimit (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 (void)
+{
+ 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 (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 (void)
+{
+ /* 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 (void)
+{
+ 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 (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 (WAITTYPE *w)
+{
+ WSETSTOP (*w, fault_table[fault_code / FAULT_CODE_UNITS]);
+ return PIDGET (inferior_ptid);
+}
+
+/* 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 (void)
+{
+ 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/std-regs.c b/contrib/gdb/gdb/std-regs.c
new file mode 100644
index 0000000..368720d
--- /dev/null
+++ b/contrib/gdb/gdb/std-regs.c
@@ -0,0 +1,160 @@
+/* Builtin frame register, for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "user-regs.h"
+#include "frame.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "gdb_string.h"
+
+/* Types that describe the various builtin registers. */
+
+static struct type *builtin_type_frame_reg;
+
+/* Constructors for those types. */
+
+static void
+build_builtin_type_frame_reg (void)
+{
+ /* $frame. */
+ if (builtin_type_frame_reg == NULL)
+ {
+#if 0
+ struct frame
+ {
+ void *base;
+ };
+#endif
+ builtin_type_frame_reg = init_composite_type ("frame", TYPE_CODE_STRUCT);
+ append_composite_type_field (builtin_type_frame_reg, "base",
+ builtin_type_void_data_ptr);
+ }
+}
+
+static struct value *
+value_of_builtin_frame_reg (struct frame_info *frame)
+{
+ struct value *val;
+ char *buf;
+ build_builtin_type_frame_reg ();
+ val = allocate_value (builtin_type_frame_reg);
+ VALUE_LVAL (val) = not_lval;
+ buf = VALUE_CONTENTS_RAW (val);
+ memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0);
+ /* frame.base. */
+ if (frame != NULL)
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf,
+ get_frame_base (frame));
+ buf += TYPE_LENGTH (builtin_type_void_data_ptr);
+ /* frame.XXX. */
+ return val;
+}
+
+static struct value *
+value_of_builtin_frame_fp_reg (struct frame_info *frame)
+{
+ if (DEPRECATED_FP_REGNUM >= 0)
+ /* NOTE: cagney/2003-04-24: Since the mere presence of "fp" in the
+ register name table overrides this built-in $fp register, there
+ is no real reason for this DEPRECATED_FP_REGNUM trickery here.
+ An architecture wanting to implement "$fp" as alias for a raw
+ register can do so by adding "fp" to register name table (mind
+ you, doing this is probably a dangerous thing). */
+ return value_of_register (DEPRECATED_FP_REGNUM, frame);
+ else
+ {
+ struct value *val = allocate_value (builtin_type_void_data_ptr);
+ char *buf = VALUE_CONTENTS_RAW (val);
+ if (frame == NULL)
+ memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0);
+ else
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf,
+ get_frame_base_address (frame));
+ return val;
+ }
+}
+
+static struct value *
+value_of_builtin_frame_pc_reg (struct frame_info *frame)
+{
+ if (PC_REGNUM >= 0)
+ return value_of_register (PC_REGNUM, frame);
+ else
+ {
+ struct value *val = allocate_value (builtin_type_void_data_ptr);
+ char *buf = VALUE_CONTENTS_RAW (val);
+ if (frame == NULL)
+ memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0);
+ else
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf,
+ get_frame_pc (frame));
+ return val;
+ }
+}
+
+static struct value *
+value_of_builtin_frame_sp_reg (struct frame_info *frame)
+{
+#ifdef SP_REGNUM
+ if (SP_REGNUM >= 0)
+ return value_of_register (SP_REGNUM, frame);
+#endif
+ error ("Standard register ``$sp'' is not available for this target");
+}
+
+static struct value *
+value_of_builtin_frame_ps_reg (struct frame_info *frame)
+{
+#ifdef PS_REGNUM
+ if (PS_REGNUM >= 0)
+ return value_of_register (PS_REGNUM, frame);
+#endif
+ error ("Standard register ``$ps'' is not available for this target");
+}
+
+extern initialize_file_ftype _initialize_frame_reg; /* -Wmissing-prototypes */
+
+void
+_initialize_frame_reg (void)
+{
+ /* FIXME: cagney/2002-02-08: At present the local builtin types
+ can't be initialized using _initialize*() or gdbarch. Due mainly
+ to non-multi-arch targets, GDB initializes things piece meal and,
+ as a consequence can leave these types NULL. */
+ DEPRECATED_REGISTER_GDBARCH_SWAP (builtin_type_frame_reg);
+
+ /* Frame based $fp, $pc, $sp and $ps. These only come into play
+ when the target does not define its own version of these
+ registers. */
+ user_reg_add_builtin ("fp", value_of_builtin_frame_fp_reg);
+ user_reg_add_builtin ("pc", value_of_builtin_frame_pc_reg);
+ user_reg_add_builtin ("sp", value_of_builtin_frame_sp_reg);
+ user_reg_add_builtin ("ps", value_of_builtin_frame_ps_reg);
+
+ /* NOTE: cagney/2002-04-05: For moment leave the $frame / $gdbframe
+ / $gdb.frame disabled. It isn't yet clear which of the many
+ options is the best. */
+ if (0)
+ user_reg_add_builtin ("frame", value_of_builtin_frame_reg);
+}
diff --git a/contrib/gdb/gdb/stop-gdb.c b/contrib/gdb/gdb/stop-gdb.c
new file mode 100644
index 0000000..ee84609
--- /dev/null
+++ b/contrib/gdb/gdb/stop-gdb.c
@@ -0,0 +1,109 @@
+/* A client to make GDB return to command level in Mach 3.
+ Copyright 1992, 1993, 1994, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <jtv@hut.fi> and Peter Stout <pds@cs.cmu.edu>.
+
+ 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 <stdio.h>
+
+#include "defs.h"
+
+#include <mach.h>
+#include <mach/message.h>
+#include <mach_error.h>
+#include <servers/netname.h>
+#include <servers/netname_defs.h>
+
+void
+main (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 <GDB name>\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/sun3-nat.c b/contrib/gdb/gdb/sun3-nat.c
new file mode 100644
index 0000000..6c52d33
--- /dev/null
+++ b/contrib/gdb/gdb/sun3-nat.c
@@ -0,0 +1,166 @@
+/* Host-dependent code for Sun-3 for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1996, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "regcache.h"
+
+#include <sys/ptrace.h>
+#define KERNEL /* To get floating point reg definitions */
+#include <machine/reg.h>
+
+static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
+
+void
+fetch_inferior_registers (int regno)
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+
+ deprecated_registers_fetched ();
+
+ ptrace (PTRACE_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) & inferior_registers);
+
+ if (FP0_REGNUM >= 0)
+ ptrace (PTRACE_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) & inferior_fp_registers);
+
+ memcpy (deprecated_registers, &inferior_registers, 16 * 4);
+ if (FP0_REGNUM >= 0)
+ memcpy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ &inferior_fp_registers, sizeof inferior_fp_registers.fps_regs);
+
+ *(int *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
+ *(int *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
+ if (FP0_REGNUM >= 0)
+ memcpy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ &inferior_fp_registers.fps_control,
+ sizeof inferior_fp_registers -
+ sizeof inferior_fp_registers.fps_regs);
+}
+
+/* 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 (int regno)
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+
+ memcpy (&inferior_registers, deprecated_registers, 16 * 4);
+ if (FP0_REGNUM >= 0)
+ memcpy (&inferior_fp_registers,
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ sizeof inferior_fp_registers.fps_regs);
+
+ inferior_registers.r_ps = *(int *) &&deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)];
+ inferior_registers.r_pc = *(int *) &&deprecated_registers[DEPRECATED_REGISTER_BYTE (PC_REGNUM)];
+
+ if (FP0_REGNUM >= 0)
+ memcpy (&inferior_fp_registers.fps_control,
+ &&deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ sizeof inferior_fp_registers -
+ sizeof inferior_fp_registers.fps_regs);
+
+ ptrace (PTRACE_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) & inferior_registers);
+ if (FP0_REGNUM >= 0)
+ ptrace (PTRACE_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) & inferior_fp_registers);
+}
+
+
+/* All of this stuff is only relevant if both host and target are sun3. */
+
+/* Provide registers to GDB from a core file.
+
+ CORE_REG_SECT points to an array of bytes, which were obtained from
+ a core file which BFD thinks might contain register contents.
+ CORE_REG_SIZE is its size.
+
+ WHICH says which register set corelow suspects this is:
+ 0 --- the general-purpose register set
+ 2 --- the floating-point register set
+
+ REG_ADDR isn't used. */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR reg_addr)
+{
+ struct regs *regs = (struct regs *) core_reg_sect;
+
+ if (which == 0)
+ {
+ if (core_reg_size < sizeof (struct regs))
+ error ("Can't find registers in core file");
+
+ memcpy (&deprecated_registers, (char *) regs, 16 * 4);
+ supply_register (PS_REGNUM, (char *) &regs->r_ps);
+ supply_register (PC_REGNUM, (char *) &regs->r_pc);
+
+ }
+ else if (which == 2)
+ {
+
+#define fpustruct ((struct fpu *) core_reg_sect)
+
+ if (core_reg_size >= sizeof (struct fpu))
+ {
+ if (FP0_REGNUM >= 0)
+ {
+ memcpy (&&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ fpustruct->f_fpstatus.fps_regs,
+ sizeof fpustruct->f_fpstatus.fps_regs);
+ memcpy (&&deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ &fpustruct->f_fpstatus.fps_control,
+ sizeof fpustruct->f_fpstatus -
+ sizeof fpustruct->f_fpstatus.fps_regs);
+ }
+ }
+ else
+ fprintf_unfiltered (gdb_stderr,
+ "Couldn't read float regs from core file\n");
+ }
+}
+
+
+/* Register that we are able to handle sun3 core file formats.
+ FIXME: is this really bfd_target_unknown_flavour? */
+
+static struct core_fns sun3_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_sun3 (void)
+{
+ add_core_fns (&sun3_core_fns);
+}
diff --git a/contrib/gdb/gdb/symfile.c b/contrib/gdb/gdb/symfile.c
new file mode 100644
index 0000000..19ae294
--- /dev/null
+++ b/contrib/gdb/gdb/symfile.c
@@ -0,0 +1,3610 @@
+/* Generic symbol file reading for the GNU debugger, GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004 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 "bfdlink.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 "source.h"
+#include "gdbcmd.h"
+#include "breakpoint.h"
+#include "language.h"
+#include "complaints.h"
+#include "demangle.h"
+#include "inferior.h" /* for write_pc */
+#include "filenames.h" /* for DOSish file names */
+#include "gdb-stabs.h"
+#include "gdb_obstack.h"
+#include "completer.h"
+#include "bcache.h"
+#include "hashtab.h"
+#include "readline/readline.h"
+#include "gdb_assert.h"
+#include "block.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include "gdb_string.h"
+#include "gdb_stat.h"
+#include <ctype.h>
+#include <time.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifdef HPUXHPPA
+
+/* Some HP-UX related globals to clear when a new "main"
+ symbol file is loaded. HP-specific. */
+
+extern int hp_som_som_object_present;
+extern int hp_cxx_exception_support_initialized;
+#define RESET_HP_UX_GLOBALS() do {\
+ hp_som_som_object_present = 0; /* indicates HP-compiled code */ \
+ hp_cxx_exception_support_initialized = 0; /* must reinitialize exception stuff */ \
+ } while (0)
+#endif
+
+int (*ui_load_progress_hook) (const char *section, unsigned long num);
+void (*show_load_progress) (const char *section,
+ unsigned long section_sent,
+ unsigned long section_size,
+ unsigned long total_sent,
+ unsigned long total_size);
+void (*pre_add_symbol_hook) (char *);
+void (*post_add_symbol_hook) (void);
+void (*target_new_objfile_hook) (struct objfile *);
+
+static void clear_symtab_users_cleanup (void *ignore);
+
+/* Global variables owned by this file */
+int readnow_symbol_files; /* Read full symbols immediately */
+
+/* External variables and functions referenced. */
+
+extern void report_transfer_performance (unsigned long, time_t, time_t);
+
+/* Functions this file defines */
+
+#if 0
+static int simple_read_overlay_region_table (void);
+static void simple_free_overlay_region_table (void);
+#endif
+
+static void set_initial_language (void);
+
+static void load_command (char *, int);
+
+static void symbol_file_add_main_1 (char *args, int from_tty, int flags);
+
+static void add_symbol_file_command (char *, int);
+
+static void add_shared_symbol_files_command (char *, int);
+
+static void reread_separate_symbols (struct objfile *objfile);
+
+static void cashier_psymtab (struct partial_symtab *);
+
+bfd *symfile_bfd_open (char *);
+
+int get_section_index (struct objfile *, char *);
+
+static void find_sym_fns (struct objfile *);
+
+static void decrement_reading_symtab (void *);
+
+static void overlay_invalidate_all (void);
+
+static int overlay_is_mapped (struct obj_section *);
+
+void list_overlays_command (char *, int);
+
+void map_overlay_command (char *, int);
+
+void unmap_overlay_command (char *, int);
+
+static void overlay_auto_command (char *, int);
+
+static void overlay_manual_command (char *, int);
+
+static void overlay_off_command (char *, int);
+
+static void overlay_load_command (char *, int);
+
+static void overlay_command (char *, int);
+
+static void simple_free_overlay_table (void);
+
+static void read_target_long_array (CORE_ADDR, unsigned int *, int);
+
+static int simple_read_overlay_table (void);
+
+static int simple_overlay_update_1 (struct obj_section *);
+
+static void add_filename_language (char *ext, enum language lang);
+
+static void set_ext_lang_command (char *args, int from_tty);
+
+static void info_ext_lang_command (char *args, int from_tty);
+
+static char *find_separate_debug_file (struct objfile *objfile);
+
+static void init_filename_language_table (void);
+
+void _initialize_symfile (void);
+
+/* 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 non-zero, shared library symbols will be added automatically
+ when the inferior is created, new libraries are loaded, or when
+ attaching to the inferior. This is almost always what users will
+ 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;
+
+/* For systems that support it, a threshold size in megabytes. If
+ automatically adding a new library's symbol table to those already
+ known to the debugger would cause the total shared library symbol
+ size to exceed this threshhold, then the shlib's symbols are not
+ added. The threshold is ignored if the user explicitly asks for a
+ shlib to be added, such as when using the "sharedlibrary"
+ command. */
+
+int auto_solib_limit;
+
+
+/* This compares two partial symbols by names, using strcmp_iw_ordered
+ for the comparison. */
+
+static int
+compare_psymbols (const void *s1p, const void *s2p)
+{
+ struct partial_symbol *const *s1 = s1p;
+ struct partial_symbol *const *s2 = s2p;
+
+ return strcmp_iw_ordered (SYMBOL_NATURAL_NAME (*s1),
+ SYMBOL_NATURAL_NAME (*s2));
+}
+
+void
+sort_pst_symbols (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);
+}
+
+/* Make a null terminated copy of the string at PTR with SIZE characters in
+ the obstack pointed to by OBSTACKP . Returns the address of the copy.
+ Note that the string at PTR does not have to be null terminated, I.E. it
+ may be part of a larger string and we are only saving a substring. */
+
+char *
+obsavestring (const char *ptr, int size, struct obstack *obstackp)
+{
+ char *p = (char *) obstack_alloc (obstackp, size + 1);
+ /* Open-coded memcpy--saves function call time. These strings are usually
+ short. FIXME: Is this really still true with a compiler that can
+ inline memcpy? */
+ {
+ const char *p1 = ptr;
+ char *p2 = p;
+ const char *end = ptr + size;
+ while (p1 != end)
+ *p2++ = *p1++;
+ }
+ p[size] = 0;
+ return p;
+}
+
+/* Concatenate strings S1, S2 and S3; return the new string. Space is found
+ in the obstack pointed to by OBSTACKP. */
+
+char *
+obconcat (struct obstack *obstackp, const char *s1, const char *s2,
+ const char *s3)
+{
+ int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ 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 (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 (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;
+}
+
+/* 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 (bfd *abfd, asection *sect, void *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;
+}
+
+/* Create a new section_addr_info, with room for NUM_SECTIONS. */
+
+struct section_addr_info *
+alloc_section_addr_info (size_t num_sections)
+{
+ struct section_addr_info *sap;
+ size_t size;
+
+ size = (sizeof (struct section_addr_info)
+ + sizeof (struct other_sections) * (num_sections - 1));
+ sap = (struct section_addr_info *) xmalloc (size);
+ memset (sap, 0, size);
+ sap->num_sections = num_sections;
+
+ return sap;
+}
+
+/* Build (allocate and populate) a section_addr_info struct from
+ an existing section table. */
+
+extern struct section_addr_info *
+build_section_addr_info_from_section_table (const struct section_table *start,
+ const struct section_table *end)
+{
+ struct section_addr_info *sap;
+ const struct section_table *stp;
+ int oidx;
+
+ sap = alloc_section_addr_info (end - start);
+
+ for (stp = start, oidx = 0; stp != end; stp++)
+ {
+ if (bfd_get_section_flags (stp->bfd,
+ stp->the_bfd_section) & (SEC_ALLOC | SEC_LOAD)
+ && oidx < end - start)
+ {
+ sap->other[oidx].addr = stp->addr;
+ sap->other[oidx].name
+ = xstrdup (bfd_section_name (stp->bfd, stp->the_bfd_section));
+ sap->other[oidx].sectindex = stp->the_bfd_section->index;
+ oidx++;
+ }
+ }
+
+ return sap;
+}
+
+
+/* Free all memory allocated by build_section_addr_info_from_section_table. */
+
+extern void
+free_section_addr_info (struct section_addr_info *sap)
+{
+ int idx;
+
+ for (idx = 0; idx < sap->num_sections; idx++)
+ if (sap->other[idx].name)
+ xfree (sap->other[idx].name);
+ xfree (sap);
+}
+
+
+/* Initialize OBJFILE's sect_index_* members. */
+static void
+init_objfile_sect_indices (struct objfile *objfile)
+{
+ asection *sect;
+ int i;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".text");
+ if (sect)
+ objfile->sect_index_text = sect->index;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".data");
+ if (sect)
+ objfile->sect_index_data = sect->index;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".bss");
+ if (sect)
+ objfile->sect_index_bss = sect->index;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".rodata");
+ if (sect)
+ objfile->sect_index_rodata = sect->index;
+
+ /* This is where things get really weird... We MUST have valid
+ indices for the various sect_index_* members or gdb will abort.
+ So if for example, there is no ".text" section, we have to
+ accomodate that. Except when explicitly adding symbol files at
+ some address, section_offsets contains nothing but zeros, so it
+ doesn't matter which slot in section_offsets the individual
+ sect_index_* members index into. So if they are all zero, it is
+ safe to just point all the currently uninitialized indices to the
+ first slot. */
+
+ for (i = 0; i < objfile->num_sections; i++)
+ {
+ if (ANOFFSET (objfile->section_offsets, i) != 0)
+ {
+ break;
+ }
+ }
+ if (i == objfile->num_sections)
+ {
+ if (objfile->sect_index_text == -1)
+ objfile->sect_index_text = 0;
+ if (objfile->sect_index_data == -1)
+ objfile->sect_index_data = 0;
+ if (objfile->sect_index_bss == -1)
+ objfile->sect_index_bss = 0;
+ if (objfile->sect_index_rodata == -1)
+ objfile->sect_index_rodata = 0;
+ }
+}
+
+
+/* Parse the user's idea of an offset for dynamic linking, into our idea
+ of how to represent it for fast symbol reading. This is the default
+ version of the sym_fns.sym_offsets function for symbol readers that
+ don't need to do anything special. It allocates a section_offsets table
+ for the objectfile OBJFILE and stuffs ADDR into all of the offsets. */
+
+void
+default_symfile_offsets (struct objfile *objfile,
+ struct section_addr_info *addrs)
+{
+ int i;
+
+ objfile->num_sections = bfd_count_sections (objfile->obfd);
+ objfile->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+ memset (objfile->section_offsets, 0,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ /* Now calculate offsets for section that were specified by the
+ caller. */
+ for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
+ {
+ struct other_sections *osp ;
+
+ osp = &addrs->other[i] ;
+ if (osp->addr == 0)
+ continue;
+
+ /* Record all sections in offsets */
+ /* The section_offsets in the objfile are here filled in using
+ the BFD index. */
+ (objfile->section_offsets)->offsets[osp->sectindex] = osp->addr;
+ }
+
+ /* Remember the bfd indexes for the .text, .data, .bss and
+ .rodata sections. */
+ init_objfile_sect_indices (objfile);
+}
+
+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file.
+
+ OBJFILE is where the symbols are to be read from.
+
+ ADDRS is the list of section load addresses. If the user has given
+ an 'add-symbol-file' command, then this is the list of offsets and
+ addresses he or she provided as arguments to the command; or, if
+ we're handling a shared library, these are the actual addresses the
+ sections are loaded at, according to the inferior's dynamic linker
+ (as gleaned by GDB's shared library code). We convert each address
+ into an offset from the section VMA's as it appears in the object
+ file, and then call the file's sym_offsets function to convert this
+ into a format-specific offset table --- a `struct section_offsets'.
+ If ADDRS is non-zero, OFFSETS must be zero.
+
+ OFFSETS is a table of section offsets already in the right
+ format-specific representation. NUM_OFFSETS is the number of
+ elements present in OFFSETS->offsets. If OFFSETS is non-zero, we
+ assume this is the proper table the call to sym_offsets described
+ above would produce. Instead of calling sym_offsets, we just dump
+ it right into objfile->section_offsets. (When we're re-reading
+ symbols from an objfile, we don't have the original load address
+ list any more; all we have is the section offset table.) If
+ OFFSETS is non-zero, ADDRS must be zero.
+
+ MAINLINE is nonzero if this is the main symbol file, or zero if
+ it's an extra symbol file such as dynamically loaded code.
+
+ VERBO is nonzero if the caller has printed a verbose message about
+ the symbol reading (and complaints can be more terse about it). */
+
+void
+syms_from_objfile (struct objfile *objfile,
+ struct section_addr_info *addrs,
+ struct section_offsets *offsets,
+ int num_offsets,
+ int mainline,
+ int verbo)
+{
+ struct section_addr_info *local_addr = NULL;
+ struct cleanup *old_chain;
+
+ gdb_assert (! (addrs && offsets));
+
+ init_entry_point_info (objfile);
+ find_sym_fns (objfile);
+
+ if (objfile->sf == NULL)
+ return; /* No symbols. */
+
+ /* 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 ADDRS and OFFSETS are both NULL, put together a dummy address
+ list. We now establish the convention that an addr of zero means
+ no load address was specified. */
+ if (! addrs && ! offsets)
+ {
+ local_addr
+ = alloc_section_addr_info (bfd_count_sections (objfile->obfd));
+ make_cleanup (xfree, local_addr);
+ addrs = local_addr;
+ }
+
+ /* Now either addrs or offsets is non-zero. */
+
+ 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_cleanup, 0 /*ignore*/);
+
+ /* 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 <addr> is where that got loaded.
+
+ We no longer warn if the lowest section is not a text segment (as
+ happens for the PA64 port. */
+ if (!mainline && addrs && addrs->other[0].name)
+ {
+ asection *lower_sect;
+ asection *sect;
+ CORE_ADDR lower_offset;
+ int i;
+
+ /* Find lowest loadable section to be used as starting point for
+ continguous sections. FIXME!! won't work without call to find
+ .text first, but this assumes text is lowest section. */
+ lower_sect = bfd_get_section_by_name (objfile->obfd, ".text");
+ if (lower_sect == NULL)
+ bfd_map_over_sections (objfile->obfd, find_lowest_section,
+ &lower_sect);
+ if (lower_sect == NULL)
+ warning ("no loadable sections found in added symbol-file %s",
+ objfile->name);
+ else
+ if ((bfd_get_section_flags (objfile->obfd, lower_sect) & SEC_CODE) == 0)
+ warning ("Lowest section in %s is %s at %s",
+ objfile->name,
+ bfd_section_name (objfile->obfd, lower_sect),
+ paddr (bfd_section_vma (objfile->obfd, lower_sect)));
+ if (lower_sect != NULL)
+ lower_offset = bfd_section_vma (objfile->obfd, lower_sect);
+ else
+ lower_offset = 0;
+
+ /* Calculate offsets for the loadable sections.
+ FIXME! Sections must be in order of increasing loadable section
+ so that contiguous sections can use the lower-offset!!!
+
+ Adjust offsets if the segments are not contiguous.
+ If the section is contiguous, its offset should be set to
+ the offset of the highest loadable section lower than it
+ (the loadable section directly below it in memory).
+ this_offset = lower_offset = lower_addr - lower_orig_addr */
+
+ for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
+ {
+ if (addrs->other[i].addr != 0)
+ {
+ sect = bfd_get_section_by_name (objfile->obfd,
+ addrs->other[i].name);
+ if (sect)
+ {
+ addrs->other[i].addr
+ -= bfd_section_vma (objfile->obfd, sect);
+ lower_offset = addrs->other[i].addr;
+ /* This is the index used by BFD. */
+ addrs->other[i].sectindex = sect->index ;
+ }
+ else
+ {
+ warning ("section %s not found in %s",
+ addrs->other[i].name,
+ objfile->name);
+ addrs->other[i].addr = 0;
+ }
+ }
+ else
+ addrs->other[i].addr = lower_offset;
+ }
+ }
+
+ /* 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 (&symfile_complaints, 1, verbo);
+
+ if (addrs)
+ (*objfile->sf->sym_offsets) (objfile, addrs);
+ else
+ {
+ size_t size = SIZEOF_N_SECTION_OFFSETS (num_offsets);
+
+ /* Just copy in the offset table directly as given to us. */
+ objfile->num_sections = num_offsets;
+ objfile->section_offsets
+ = ((struct section_offsets *)
+ obstack_alloc (&objfile->objfile_obstack, size));
+ memcpy (objfile->section_offsets, offsets, size);
+
+ init_objfile_sect_indices (objfile);
+ }
+
+#ifndef DEPRECATED_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 algorithm for finding section offsets.
+
+ These should probably all be collapsed into some target
+ independent form of shared library support. FIXME. */
+
+ if (addrs)
+ {
+ struct obj_section *s;
+
+ /* Map section offsets in "addr" back to the object's
+ sections by comparing the section names with bfd's
+ section names. Then adjust the section address by
+ the offset. */ /* for gdb/13815 */
+
+ ALL_OBJFILE_OSECTIONS (objfile, s)
+ {
+ CORE_ADDR s_addr = 0;
+ int i;
+
+ for (i = 0;
+ !s_addr && i < addrs->num_sections && addrs->other[i].name;
+ i++)
+ if (strcmp (bfd_section_name (s->objfile->obfd,
+ s->the_bfd_section),
+ addrs->other[i].name) == 0)
+ s_addr = addrs->other[i].addr; /* end added for gdb/13815 */
+
+ s->addr -= s->offset;
+ s->addr += s_addr;
+ s->endaddr -= s->offset;
+ s->endaddr += s_addr;
+ s->offset += s_addr;
+ }
+ }
+#endif /* not DEPRECATED_IBM6000_TARGET */
+
+ (*objfile->sf->sym_read) (objfile, mainline);
+
+ /* 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);
+}
+
+/* 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 (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 (&symfile_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.
+
+ ADDRS, OFFSETS, and NUM_OFFSETS are as described for
+ syms_from_objfile, above. ADDRS is ignored when MAINLINE is
+ non-zero.
+
+ Upon success, returns a pointer to the objfile that was added.
+ Upon failure, jumps back to command level (never returns). */
+static struct objfile *
+symbol_file_add_with_addrs_or_offsets (char *name, int from_tty,
+ struct section_addr_info *addrs,
+ struct section_offsets *offsets,
+ int num_offsets,
+ int mainline, int flags)
+{
+ struct objfile *objfile;
+ struct partial_symtab *psymtab;
+ char *debugfile;
+ bfd *abfd;
+ struct section_addr_info *orig_addrs;
+ struct cleanup *my_cleanups;
+
+ /* 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, flags);
+
+ orig_addrs = alloc_section_addr_info (bfd_count_sections (abfd));
+ my_cleanups = make_cleanup (xfree, orig_addrs);
+ if (addrs)
+ {
+ int i;
+ orig_addrs->num_sections = addrs->num_sections;
+ for (i = 0; i < addrs->num_sections; i++)
+ orig_addrs->other[i] = addrs->other[i];
+ }
+
+ /* 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)
+ {
+ if (pre_add_symbol_hook)
+ pre_add_symbol_hook (name);
+ else
+ {
+ printf_unfiltered ("Reading symbols from %s...", name);
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+ }
+ }
+ syms_from_objfile (objfile, addrs, offsets, num_offsets,
+ 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 ((flags & OBJF_READNOW) || readnow_symbol_files)
+ {
+ if (from_tty || info_verbose)
+ {
+ printf_unfiltered ("expanding to full symbols...");
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+ }
+
+ for (psymtab = objfile->psymtabs;
+ psymtab != NULL;
+ psymtab = psymtab->next)
+ {
+ psymtab_to_symtab (psymtab);
+ }
+ }
+
+ debugfile = find_separate_debug_file (objfile);
+ if (debugfile)
+ {
+ if (addrs != NULL)
+ {
+ objfile->separate_debug_objfile
+ = symbol_file_add (debugfile, from_tty, orig_addrs, 0, flags);
+ }
+ else
+ {
+ objfile->separate_debug_objfile
+ = symbol_file_add (debugfile, from_tty, NULL, 0, flags);
+ }
+ objfile->separate_debug_objfile->separate_debug_objfile_backlink
+ = objfile;
+
+ /* Put the separate debug object before the normal one, this is so that
+ usage of the ALL_OBJFILES_SAFE macro will stay safe. */
+ put_objfile_before (objfile->separate_debug_objfile, objfile);
+
+ xfree (debugfile);
+ }
+
+ if (!have_partial_symbols () && !have_full_symbols ())
+ {
+ wrap_here ("");
+ printf_unfiltered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ if (from_tty || info_verbose)
+ {
+ if (post_add_symbol_hook)
+ post_add_symbol_hook ();
+ else
+ {
+ printf_unfiltered ("done.\n");
+ }
+ }
+
+ /* We print some messages regardless of whether 'from_tty ||
+ info_verbose' is true, so make sure they go out at the right
+ time. */
+ gdb_flush (gdb_stdout);
+
+ do_cleanups (my_cleanups);
+
+ if (objfile->sf == NULL)
+ return objfile; /* No symbols. */
+
+ new_symfile_objfile (objfile, mainline, from_tty);
+
+ if (target_new_objfile_hook)
+ target_new_objfile_hook (objfile);
+
+ return (objfile);
+}
+
+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file. See symbol_file_add_with_addrs_or_offsets's comments
+ for details. */
+struct objfile *
+symbol_file_add (char *name, int from_tty, struct section_addr_info *addrs,
+ int mainline, int flags)
+{
+ return symbol_file_add_with_addrs_or_offsets (name, from_tty, addrs, 0, 0,
+ mainline, flags);
+}
+
+
+/* Call symbol_file_add() with default values and update whatever is
+ affected by the loading of a new main().
+ Used when the file is supplied in the gdb command line
+ and by some targets with special loading requirements.
+ The auxiliary function, symbol_file_add_main_1(), has the flags
+ argument for the switches that can only be specified in the symbol_file
+ command itself. */
+
+void
+symbol_file_add_main (char *args, int from_tty)
+{
+ symbol_file_add_main_1 (args, from_tty, 0);
+}
+
+static void
+symbol_file_add_main_1 (char *args, int from_tty, int flags)
+{
+ symbol_file_add (args, from_tty, NULL, 1, flags);
+
+#ifdef HPUXHPPA
+ RESET_HP_UX_GLOBALS ();
+#endif
+
+ /* Getting new symbols may change our opinion about
+ what is frameless. */
+ reinit_frame_cache ();
+
+ set_initial_language ();
+}
+
+void
+symbol_file_clear (int from_tty)
+{
+ if ((have_full_symbols () || have_partial_symbols ())
+ && from_tty
+ && !query ("Discard symbol table from `%s'? ",
+ symfile_objfile->name))
+ error ("Not confirmed.");
+ free_all_objfiles ();
+
+ /* solib descriptors may have handles to objfiles. Since their
+ storage has just been released, we'd better wipe the solib
+ descriptors as well.
+ */
+#if defined(SOLIB_RESTART)
+ SOLIB_RESTART ();
+#endif
+
+ symfile_objfile = NULL;
+ if (from_tty)
+ printf_unfiltered ("No symbol file now.\n");
+#ifdef HPUXHPPA
+ RESET_HP_UX_GLOBALS ();
+#endif
+}
+
+static char *
+get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out)
+{
+ asection *sect;
+ bfd_size_type debuglink_size;
+ unsigned long crc32;
+ char *contents;
+ int crc_offset;
+ unsigned char *p;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink");
+
+ if (sect == NULL)
+ return NULL;
+
+ debuglink_size = bfd_section_size (objfile->obfd, sect);
+
+ contents = xmalloc (debuglink_size);
+ bfd_get_section_contents (objfile->obfd, sect, contents,
+ (file_ptr)0, (bfd_size_type)debuglink_size);
+
+ /* Crc value is stored after the filename, aligned up to 4 bytes. */
+ crc_offset = strlen (contents) + 1;
+ crc_offset = (crc_offset + 3) & ~3;
+
+ crc32 = bfd_get_32 (objfile->obfd, (bfd_byte *) (contents + crc_offset));
+
+ *crc32_out = crc32;
+ return contents;
+}
+
+static int
+separate_debug_file_exists (const char *name, unsigned long crc)
+{
+ unsigned long file_crc = 0;
+ int fd;
+ char buffer[8*1024];
+ int count;
+
+ fd = open (name, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return 0;
+
+ while ((count = read (fd, buffer, sizeof (buffer))) > 0)
+ file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
+
+ close (fd);
+
+ return crc == file_crc;
+}
+
+static char *debug_file_directory = NULL;
+
+#if ! defined (DEBUG_SUBDIRECTORY)
+#define DEBUG_SUBDIRECTORY ".debug"
+#endif
+
+static char *
+find_separate_debug_file (struct objfile *objfile)
+{
+ asection *sect;
+ char *basename;
+ char *dir;
+ char *debugfile;
+ char *name_copy;
+ bfd_size_type debuglink_size;
+ unsigned long crc32;
+ int i;
+
+ basename = get_debug_link_info (objfile, &crc32);
+
+ if (basename == NULL)
+ return NULL;
+
+ dir = xstrdup (objfile->name);
+
+ /* Strip off the final filename part, leaving the directory name,
+ followed by a slash. Objfile names should always be absolute and
+ tilde-expanded, so there should always be a slash in there
+ somewhere. */
+ for (i = strlen(dir) - 1; i >= 0; i--)
+ {
+ if (IS_DIR_SEPARATOR (dir[i]))
+ break;
+ }
+ gdb_assert (i >= 0 && IS_DIR_SEPARATOR (dir[i]));
+ dir[i+1] = '\0';
+
+ debugfile = alloca (strlen (debug_file_directory) + 1
+ + strlen (dir)
+ + strlen (DEBUG_SUBDIRECTORY)
+ + strlen ("/")
+ + strlen (basename)
+ + 1);
+
+ /* First try in the same directory as the original file. */
+ strcpy (debugfile, dir);
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */
+ strcpy (debugfile, dir);
+ strcat (debugfile, DEBUG_SUBDIRECTORY);
+ strcat (debugfile, "/");
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ /* Then try in the global debugfile directory. */
+ strcpy (debugfile, debug_file_directory);
+ strcat (debugfile, "/");
+ strcat (debugfile, dir);
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ xfree (basename);
+ xfree (dir);
+ return NULL;
+}
+
+
+/* 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). */
+/* Note: ezannoni 2000-04-17. This function used to have support for
+ rombug (see remote-os9k.c). It consisted of a call to target_link()
+ (target.c) to get the address of the text segment from the target,
+ and pass that to symbol_file_add(). This is no longer supported. */
+
+void
+symbol_file_command (char *args, int from_tty)
+{
+ char **argv;
+ char *name = NULL;
+ struct cleanup *cleanups;
+ int flags = OBJF_USERLOADED;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ symbol_file_clear (from_tty);
+ }
+ else
+ {
+ if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ cleanups = make_cleanup_freeargv (argv);
+ while (*argv != NULL)
+ {
+ if (strcmp (*argv, "-readnow") == 0)
+ flags |= OBJF_READNOW;
+ else if (**argv == '-')
+ error ("unknown option `%s'", *argv);
+ else
+ {
+ name = *argv;
+
+ symbol_file_add_main_1 (name, from_tty, flags);
+ }
+ 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 (void)
+{
+ 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. */
+
+bfd *
+symfile_bfd_open (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 defined(__GO32__) || defined(_WIN32) || defined (__CYGWIN__)
+ if (desc < 0)
+ {
+ char *exename = alloca (strlen (name) + 5);
+ strcat (strcpy (exename, name), ".exe");
+ desc = openp (getenv ("PATH"), 1, exename, O_RDONLY | O_BINARY,
+ 0, &absolute_name);
+ }
+#endif
+ if (desc < 0)
+ {
+ make_cleanup (xfree, name);
+ perror_with_name (name);
+ }
+ xfree (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 (xfree, name);
+ error ("\"%s\": can't open to read symbols: %s.", name,
+ bfd_errmsg (bfd_get_error ()));
+ }
+ bfd_set_cacheable (sym_bfd, 1);
+
+ if (!bfd_check_format (sym_bfd, bfd_object))
+ {
+ /* FIXME: should be checking for errors from bfd_close (for one thing,
+ on error it does not free all the storage associated with the
+ bfd). */
+ bfd_close (sym_bfd); /* This also closes desc */
+ make_cleanup (xfree, name);
+ error ("\"%s\": can't read symbols: %s.", name,
+ bfd_errmsg (bfd_get_error ()));
+ }
+ return (sym_bfd);
+}
+
+/* Return the section index for the given section name. Return -1 if
+ the section was not found. */
+int
+get_section_index (struct objfile *objfile, char *section_name)
+{
+ asection *sect = bfd_get_section_by_name (objfile->obfd, section_name);
+ if (sect)
+ return sect->index;
+ else
+ return -1;
+}
+
+/* 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 (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 (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);
+
+ if (our_flavour == bfd_target_srec_flavour
+ || our_flavour == bfd_target_ihex_flavour
+ || our_flavour == bfd_target_tekhex_flavour)
+ return; /* No symbols. */
+
+ 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 (char *arg, int from_tty)
+{
+ if (arg == NULL)
+ arg = get_exec_file (1);
+ target_load (arg, from_tty);
+
+ /* After re-loading the executable, we don't really know which
+ overlays are mapped any more. */
+ overlay_cache_invalid = 1;
+}
+
+/* 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. */
+
+static int download_write_size = 512;
+static int validate_download = 0;
+
+/* Callback service function for generic_load (bfd_map_over_sections). */
+
+static void
+add_section_size_callback (bfd *abfd, asection *asec, void *data)
+{
+ bfd_size_type *sum = data;
+
+ *sum += bfd_get_section_size_before_reloc (asec);
+}
+
+/* Opaque data for load_section_callback. */
+struct load_section_data {
+ unsigned long load_offset;
+ unsigned long write_count;
+ unsigned long data_count;
+ bfd_size_type total_size;
+};
+
+/* Callback service function for generic_load (bfd_map_over_sections). */
+
+static void
+load_section_callback (bfd *abfd, asection *asec, void *data)
+{
+ struct load_section_data *args = data;
+
+ if (bfd_get_section_flags (abfd, asec) & SEC_LOAD)
+ {
+ bfd_size_type size = bfd_get_section_size_before_reloc (asec);
+ if (size > 0)
+ {
+ char *buffer;
+ struct cleanup *old_chain;
+ CORE_ADDR lma = bfd_section_lma (abfd, asec) + args->load_offset;
+ bfd_size_type block_size;
+ int err;
+ const char *sect_name = bfd_get_section_name (abfd, asec);
+ bfd_size_type sent;
+
+ if (download_write_size > 0 && size > download_write_size)
+ block_size = download_write_size;
+ else
+ block_size = size;
+
+ buffer = xmalloc (size);
+ old_chain = make_cleanup (xfree, buffer);
+
+ /* Is this really necessary? I guess it gives the user something
+ to look at during a long download. */
+ ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n",
+ sect_name, paddr_nz (size), paddr_nz (lma));
+
+ bfd_get_section_contents (abfd, asec, buffer, 0, size);
+
+ sent = 0;
+ do
+ {
+ int len;
+ bfd_size_type this_transfer = size - sent;
+
+ if (this_transfer >= block_size)
+ this_transfer = block_size;
+ len = target_write_memory_partial (lma, buffer,
+ this_transfer, &err);
+ if (err)
+ break;
+ if (validate_download)
+ {
+ /* Broken memories and broken monitors manifest
+ themselves here when bring new computers to
+ life. This doubles already slow downloads. */
+ /* NOTE: cagney/1999-10-18: A more efficient
+ implementation might add a verify_memory()
+ method to the target vector and then use
+ that. remote.c could implement that method
+ using the ``qCRC'' packet. */
+ char *check = xmalloc (len);
+ struct cleanup *verify_cleanups =
+ make_cleanup (xfree, check);
+
+ if (target_read_memory (lma, check, len) != 0)
+ error ("Download verify read failed at 0x%s",
+ paddr (lma));
+ if (memcmp (buffer, check, len) != 0)
+ error ("Download verify compare failed at 0x%s",
+ paddr (lma));
+ do_cleanups (verify_cleanups);
+ }
+ args->data_count += len;
+ lma += len;
+ buffer += len;
+ args->write_count += 1;
+ sent += len;
+ if (quit_flag
+ || (ui_load_progress_hook != NULL
+ && ui_load_progress_hook (sect_name, sent)))
+ error ("Canceled the download");
+
+ if (show_load_progress != NULL)
+ show_load_progress (sect_name, sent, size,
+ args->data_count, args->total_size);
+ }
+ while (sent < size);
+
+ if (err != 0)
+ error ("Memory access error while loading section %s.", sect_name);
+
+ do_cleanups (old_chain);
+ }
+ }
+}
+
+void
+generic_load (char *args, int from_tty)
+{
+ asection *s;
+ bfd *loadfile_bfd;
+ time_t start_time, end_time; /* Start and end times of download */
+ char *filename;
+ struct cleanup *old_cleanups;
+ char *offptr;
+ struct load_section_data cbdata;
+ CORE_ADDR entry;
+
+ cbdata.load_offset = 0; /* Offset to add to vma for each section. */
+ cbdata.write_count = 0; /* Number of writes needed. */
+ cbdata.data_count = 0; /* Number of bytes written to target memory. */
+ cbdata.total_size = 0; /* Total size of all bfd sectors. */
+
+ /* Parse the input argument - the user can specify a load offset as
+ a second argument. */
+ filename = xmalloc (strlen (args) + 1);
+ old_cleanups = make_cleanup (xfree, filename);
+ strcpy (filename, args);
+ offptr = strchr (filename, ' ');
+ if (offptr != NULL)
+ {
+ char *endptr;
+
+ cbdata.load_offset = strtoul (offptr, &endptr, 0);
+ if (offptr == endptr)
+ error ("Invalid download offset:%s\n", offptr);
+ *offptr = '\0';
+ }
+ else
+ cbdata.load_offset = 0;
+
+ /* Open the file for loading. */
+ 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). */
+ 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 ()));
+ }
+
+ bfd_map_over_sections (loadfile_bfd, add_section_size_callback,
+ (void *) &cbdata.total_size);
+
+ start_time = time (NULL);
+
+ bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata);
+
+ end_time = time (NULL);
+
+ entry = bfd_get_start_address (loadfile_bfd);
+ ui_out_text (uiout, "Start address ");
+ ui_out_field_fmt (uiout, "address", "0x%s", paddr_nz (entry));
+ ui_out_text (uiout, ", load size ");
+ ui_out_field_fmt (uiout, "load-size", "%lu", cbdata.data_count);
+ ui_out_text (uiout, "\n");
+ /* We were doing this in remote-mips.c, I suspect it is right
+ for other targets too. */
+ write_pc (entry);
+
+ /* 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. Some targets do (e.g., remote-vx.c) but
+ others don't (or didn't - perhaphs they have all been deleted). */
+
+ print_transfer_performance (gdb_stdout, cbdata.data_count,
+ cbdata.write_count, end_time - start_time);
+
+ do_cleanups (old_cleanups);
+}
+
+/* Report how fast the transfer went. */
+
+/* DEPRECATED: cagney/1999-10-18: report_transfer_performance is being
+ replaced by print_transfer_performance (with a very different
+ function signature). */
+
+void
+report_transfer_performance (unsigned long data_count, time_t start_time,
+ time_t end_time)
+{
+ print_transfer_performance (gdb_stdout, data_count,
+ end_time - start_time, 0);
+}
+
+void
+print_transfer_performance (struct ui_file *stream,
+ unsigned long data_count,
+ unsigned long write_count,
+ unsigned long time_count)
+{
+ ui_out_text (uiout, "Transfer rate: ");
+ if (time_count > 0)
+ {
+ ui_out_field_fmt (uiout, "transfer-rate", "%lu",
+ (data_count * 8) / time_count);
+ ui_out_text (uiout, " bits/sec");
+ }
+ else
+ {
+ ui_out_field_fmt (uiout, "transferred-bits", "%lu", (data_count * 8));
+ ui_out_text (uiout, " bits in <1 sec");
+ }
+ if (write_count > 0)
+ {
+ ui_out_text (uiout, ", ");
+ ui_out_field_fmt (uiout, "write-rate", "%lu", data_count / write_count);
+ ui_out_text (uiout, " bytes/write");
+ }
+ ui_out_text (uiout, ".\n");
+}
+
+/* This function allows the addition of incrementally linked object files.
+ It does not modify any state in the target, only in the debugger. */
+/* Note: ezannoni 2000-04-13 This function/command used to have a
+ special case syntax for the rombug target (Rombug is the boot
+ monitor for Microware's OS-9 / OS-9000, see remote-os9k.c). In the
+ rombug case, the user doesn't need to supply a text address,
+ instead a call to target_link() (in target.c) would supply the
+ value to use. We are now discontinuing this type of ad hoc syntax. */
+
+static void
+add_symbol_file_command (char *args, int from_tty)
+{
+ char *filename = NULL;
+ int flags = OBJF_USERLOADED;
+ char *arg;
+ int expecting_option = 0;
+ int section_index = 0;
+ int argcnt = 0;
+ int sec_num = 0;
+ int i;
+ int expecting_sec_name = 0;
+ int expecting_sec_addr = 0;
+
+ struct sect_opt
+ {
+ char *name;
+ char *value;
+ };
+
+ struct section_addr_info *section_addrs;
+ struct sect_opt *sect_opts = NULL;
+ size_t num_sect_opts = 0;
+ struct cleanup *my_cleanups = make_cleanup (null_cleanup, NULL);
+
+ num_sect_opts = 16;
+ sect_opts = (struct sect_opt *) xmalloc (num_sect_opts
+ * sizeof (struct sect_opt));
+
+ 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 = xstrdup (args);
+
+ while (*args != '\000')
+ {
+ /* Any leading spaces? */
+ while (isspace (*args))
+ args++;
+
+ /* Point arg to the beginning of the argument. */
+ arg = args;
+
+ /* Move args pointer over the argument. */
+ while ((*args != '\000') && !isspace (*args))
+ args++;
+
+ /* If there are more arguments, terminate arg and
+ proceed past it. */
+ if (*args != '\000')
+ *args++ = '\000';
+
+ /* Now process the argument. */
+ if (argcnt == 0)
+ {
+ /* The first argument is the file name. */
+ filename = tilde_expand (arg);
+ make_cleanup (xfree, filename);
+ }
+ else
+ if (argcnt == 1)
+ {
+ /* The second argument is always the text address at which
+ to load the program. */
+ sect_opts[section_index].name = ".text";
+ sect_opts[section_index].value = arg;
+ if (++section_index > num_sect_opts)
+ {
+ num_sect_opts *= 2;
+ sect_opts = ((struct sect_opt *)
+ xrealloc (sect_opts,
+ num_sect_opts
+ * sizeof (struct sect_opt)));
+ }
+ }
+ else
+ {
+ /* It's an option (starting with '-') or it's an argument
+ to an option */
+
+ if (*arg == '-')
+ {
+ if (strcmp (arg, "-readnow") == 0)
+ flags |= OBJF_READNOW;
+ else if (strcmp (arg, "-s") == 0)
+ {
+ expecting_sec_name = 1;
+ expecting_sec_addr = 1;
+ }
+ }
+ else
+ {
+ if (expecting_sec_name)
+ {
+ sect_opts[section_index].name = arg;
+ expecting_sec_name = 0;
+ }
+ else
+ if (expecting_sec_addr)
+ {
+ sect_opts[section_index].value = arg;
+ expecting_sec_addr = 0;
+ if (++section_index > num_sect_opts)
+ {
+ num_sect_opts *= 2;
+ sect_opts = ((struct sect_opt *)
+ xrealloc (sect_opts,
+ num_sect_opts
+ * sizeof (struct sect_opt)));
+ }
+ }
+ else
+ error ("USAGE: add-symbol-file <filename> <textaddress> [-mapped] [-readnow] [-s <secname> <addr>]*");
+ }
+ }
+ argcnt++;
+ }
+
+ /* Print the prompt for the query below. And save the arguments into
+ a sect_addr_info structure to be passed around to other
+ functions. We have to split this up into separate print
+ statements because local_hex_string returns a local static
+ string. */
+
+ printf_unfiltered ("add symbol table from file \"%s\" at\n", filename);
+ section_addrs = alloc_section_addr_info (section_index);
+ make_cleanup (xfree, section_addrs);
+ for (i = 0; i < section_index; i++)
+ {
+ CORE_ADDR addr;
+ char *val = sect_opts[i].value;
+ char *sec = sect_opts[i].name;
+
+ addr = parse_and_eval_address (val);
+
+ /* Here we store the section offsets in the order they were
+ entered on the command line. */
+ section_addrs->other[sec_num].name = sec;
+ section_addrs->other[sec_num].addr = addr;
+ printf_unfiltered ("\t%s_addr = %s\n",
+ sec,
+ local_hex_string ((unsigned long)addr));
+ sec_num++;
+
+ /* The object's sections are initialized when a
+ call is made to build_objfile_section_table (objfile).
+ This happens in reread_symbols.
+ At this point, we don't know what file type this is,
+ so we can't determine what section names are valid. */
+ }
+
+ if (from_tty && (!query ("%s", "")))
+ error ("Not confirmed.");
+
+ symbol_file_add (filename, from_tty, section_addrs, 0, flags);
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ reinit_frame_cache ();
+ do_cleanups (my_cleanups);
+}
+
+static void
+add_shared_symbol_files_command (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 (void)
+{
+ 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 DEPRECATED_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_unfiltered ("`%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;
+ char *obfd_filename;
+
+ printf_unfiltered ("`%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_cleanup, 0 /*ignore*/);
+
+ /* 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
+ objfile_obstack. */
+ num_offsets = objfile->num_sections;
+ offsets = ((struct section_offsets *)
+ alloca (SIZEOF_N_SECTION_OFFSETS (num_offsets)));
+ memcpy (offsets, objfile->section_offsets,
+ SIZEOF_N_SECTION_OFFSETS (num_offsets));
+
+ /* 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)
+ xmfree (objfile->md, objfile->global_psymbols.list);
+ memset (&objfile->global_psymbols, 0,
+ sizeof (objfile->global_psymbols));
+ if (objfile->static_psymbols.list)
+ xmfree (objfile->md, objfile->static_psymbols.list);
+ memset (&objfile->static_psymbols, 0,
+ sizeof (objfile->static_psymbols));
+
+ /* Free the obstacks for non-reusable objfiles */
+ bcache_xfree (objfile->psymbol_cache);
+ objfile->psymbol_cache = bcache_xmalloc ();
+ bcache_xfree (objfile->macro_cache);
+ objfile->macro_cache = bcache_xmalloc ();
+ if (objfile->demangled_names_hash != NULL)
+ {
+ htab_delete (objfile->demangled_names_hash);
+ objfile->demangled_names_hash = NULL;
+ }
+ obstack_free (&objfile->objfile_obstack, 0);
+ objfile->sections = NULL;
+ objfile->symtabs = NULL;
+ objfile->psymtabs = NULL;
+ objfile->free_psymtabs = NULL;
+ objfile->cp_namespace_symtab = NULL;
+ objfile->msymbols = NULL;
+ objfile->sym_private = NULL;
+ objfile->minimal_symbol_count = 0;
+ memset (&objfile->msymbol_hash, 0,
+ sizeof (objfile->msymbol_hash));
+ memset (&objfile->msymbol_demangled_hash, 0,
+ sizeof (objfile->msymbol_demangled_hash));
+ objfile->fundamental_types = NULL;
+ clear_objfile_data (objfile);
+ if (objfile->sf != NULL)
+ {
+ (*objfile->sf->sym_finish) (objfile);
+ }
+
+ /* We never make this a mapped file. */
+ objfile->md = NULL;
+ objfile->psymbol_cache = bcache_xmalloc ();
+ objfile->macro_cache = bcache_xmalloc ();
+ /* obstack_init also initializes the obstack so it is
+ empty. We could use obstack_specify_allocation but
+ gdb_obstack.h specifies the alloc/dealloc
+ functions. */
+ obstack_init (&objfile->objfile_obstack);
+ if (build_objfile_section_table (objfile))
+ {
+ error ("Can't find the file sections in `%s': %s",
+ objfile->name, bfd_errmsg (bfd_get_error ()));
+ }
+ terminate_minimal_symbol_table (objfile);
+
+ /* 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->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (num_offsets));
+ memcpy (objfile->section_offsets, offsets,
+ SIZEOF_N_SECTION_OFFSETS (num_offsets));
+ 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);
+#ifdef HPUXHPPA
+ RESET_HP_UX_GLOBALS ();
+#endif
+ }
+
+ (*objfile->sf->sym_init) (objfile);
+ clear_complaints (&symfile_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, 0);
+ if (!have_partial_symbols () && !have_full_symbols ())
+ {
+ wrap_here ("");
+ printf_unfiltered ("(no debugging symbols found)\n");
+ wrap_here ("");
+ }
+ objfile->flags |= OBJF_SYMS;
+
+ /* We're done reading the symbol file; finish off complaints. */
+ clear_complaints (&symfile_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;
+ reread_separate_symbols (objfile);
+ }
+ }
+ }
+
+ if (reread_one)
+ clear_symtab_users ();
+}
+
+
+/* Handle separate debug info for OBJFILE, which has just been
+ re-read:
+ - If we had separate debug info before, but now we don't, get rid
+ of the separated objfile.
+ - If we didn't have separated debug info before, but now we do,
+ read in the new separated debug info file.
+ - If the debug link points to a different file, toss the old one
+ and read the new one.
+ This function does *not* handle the case where objfile is still
+ using the same separate debug info file, but that file's timestamp
+ has changed. That case should be handled by the loop in
+ reread_symbols already. */
+static void
+reread_separate_symbols (struct objfile *objfile)
+{
+ char *debug_file;
+ unsigned long crc32;
+
+ /* Does the updated objfile's debug info live in a
+ separate file? */
+ debug_file = find_separate_debug_file (objfile);
+
+ if (objfile->separate_debug_objfile)
+ {
+ /* There are two cases where we need to get rid of
+ the old separated debug info objfile:
+ - if the new primary objfile doesn't have
+ separated debug info, or
+ - if the new primary objfile has separate debug
+ info, but it's under a different filename.
+
+ If the old and new objfiles both have separate
+ debug info, under the same filename, then we're
+ okay --- if the separated file's contents have
+ changed, we will have caught that when we
+ visited it in this function's outermost
+ loop. */
+ if (! debug_file
+ || strcmp (debug_file, objfile->separate_debug_objfile->name) != 0)
+ free_objfile (objfile->separate_debug_objfile);
+ }
+
+ /* If the new objfile has separate debug info, and we
+ haven't loaded it already, do so now. */
+ if (debug_file
+ && ! objfile->separate_debug_objfile)
+ {
+ /* Use the same section offset table as objfile itself.
+ Preserve the flags from objfile that make sense. */
+ objfile->separate_debug_objfile
+ = (symbol_file_add_with_addrs_or_offsets
+ (debug_file,
+ info_verbose, /* from_tty: Don't override the default. */
+ 0, /* No addr table. */
+ objfile->section_offsets, objfile->num_sections,
+ 0, /* Not mainline. See comments about this above. */
+ objfile->flags & (OBJF_REORDERED | OBJF_SHARED | OBJF_READNOW
+ | OBJF_USERLOADED)));
+ objfile->separate_debug_objfile->separate_debug_objfile_backlink
+ = objfile;
+ }
+}
+
+
+
+
+
+typedef struct
+{
+ char *ext;
+ enum language lang;
+}
+filename_language;
+
+static filename_language *filename_language_table;
+static int fl_table_size, fl_table_next;
+
+static void
+add_filename_language (char *ext, enum language lang)
+{
+ if (fl_table_next >= fl_table_size)
+ {
+ fl_table_size += 10;
+ filename_language_table =
+ xrealloc (filename_language_table,
+ fl_table_size * sizeof (*filename_language_table));
+ }
+
+ filename_language_table[fl_table_next].ext = xstrdup (ext);
+ filename_language_table[fl_table_next].lang = lang;
+ fl_table_next++;
+}
+
+static char *ext_args;
+
+static void
+set_ext_lang_command (char *args, int from_tty)
+{
+ int i;
+ char *cp = ext_args;
+ enum language lang;
+
+ /* First arg is filename extension, starting with '.' */
+ if (*cp != '.')
+ error ("'%s': Filename extension must begin with '.'", ext_args);
+
+ /* Find end of first arg. */
+ while (*cp && !isspace (*cp))
+ cp++;
+
+ if (*cp == '\0')
+ error ("'%s': two arguments required -- filename extension and language",
+ ext_args);
+
+ /* Null-terminate first arg */
+ *cp++ = '\0';
+
+ /* Find beginning of second arg, which should be a source language. */
+ while (*cp && isspace (*cp))
+ cp++;
+
+ if (*cp == '\0')
+ error ("'%s': two arguments required -- filename extension and language",
+ ext_args);
+
+ /* Lookup the language from among those we know. */
+ lang = language_enum (cp);
+
+ /* Now lookup the filename extension: do we already know it? */
+ for (i = 0; i < fl_table_next; i++)
+ if (0 == strcmp (ext_args, filename_language_table[i].ext))
+ break;
+
+ if (i >= fl_table_next)
+ {
+ /* new file extension */
+ add_filename_language (ext_args, lang);
+ }
+ else
+ {
+ /* redefining a previously known filename extension */
+
+ /* if (from_tty) */
+ /* query ("Really make files of type %s '%s'?", */
+ /* ext_args, language_str (lang)); */
+
+ xfree (filename_language_table[i].ext);
+ filename_language_table[i].ext = xstrdup (ext_args);
+ filename_language_table[i].lang = lang;
+ }
+}
+
+static void
+info_ext_lang_command (char *args, int from_tty)
+{
+ int i;
+
+ printf_filtered ("Filename extensions and the languages they represent:");
+ printf_filtered ("\n\n");
+ for (i = 0; i < fl_table_next; i++)
+ printf_filtered ("\t%s\t- %s\n",
+ filename_language_table[i].ext,
+ language_str (filename_language_table[i].lang));
+}
+
+static void
+init_filename_language_table (void)
+{
+ if (fl_table_size == 0) /* protect against repetition */
+ {
+ fl_table_size = 20;
+ fl_table_next = 0;
+ filename_language_table =
+ xmalloc (fl_table_size * sizeof (*filename_language_table));
+ add_filename_language (".c", language_c);
+ add_filename_language (".C", language_cplus);
+ add_filename_language (".cc", language_cplus);
+ add_filename_language (".cp", language_cplus);
+ add_filename_language (".cpp", language_cplus);
+ add_filename_language (".cxx", language_cplus);
+ add_filename_language (".c++", language_cplus);
+ add_filename_language (".java", language_java);
+ add_filename_language (".class", language_java);
+ add_filename_language (".m", language_objc);
+ add_filename_language (".f", language_fortran);
+ add_filename_language (".F", language_fortran);
+ add_filename_language (".s", language_asm);
+ add_filename_language (".S", language_asm);
+ add_filename_language (".pas", language_pascal);
+ add_filename_language (".p", language_pascal);
+ add_filename_language (".pp", language_pascal);
+ }
+}
+
+enum language
+deduce_language_from_filename (char *filename)
+{
+ int i;
+ char *cp;
+
+ if (filename != NULL)
+ if ((cp = strrchr (filename, '.')) != NULL)
+ for (i = 0; i < fl_table_next; i++)
+ if (strcmp (cp, filename_language_table[i].ext) == 0)
+ return filename_language_table[i].lang;
+
+ return language_unknown;
+}
+
+/* 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
+ possibly free_named_symtabs (symtab->filename);
+ */
+
+struct symtab *
+allocate_symtab (char *filename, struct objfile *objfile)
+{
+ struct symtab *symtab;
+
+ symtab = (struct symtab *)
+ obstack_alloc (&objfile->objfile_obstack, sizeof (struct symtab));
+ memset (symtab, 0, sizeof (*symtab));
+ symtab->filename = obsavestring (filename, strlen (filename),
+ &objfile->objfile_obstack);
+ symtab->fullname = NULL;
+ symtab->language = deduce_language_from_filename (filename);
+ symtab->debugformat = obsavestring ("unknown", 7,
+ &objfile->objfile_obstack);
+
+ /* Hook it to the objfile it comes from */
+
+ symtab->objfile = objfile;
+ symtab->next = objfile->symtabs;
+ objfile->symtabs = symtab;
+
+ /* FIXME: This should go away. It is only defined for the Z8000,
+ and the Z8000 definition of this macro doesn't have anything to
+ do with the now-nonexistent EXTRA_SYMTAB_INFO macro, it's just
+ here for convenience. */
+#ifdef INIT_EXTRA_SYMTAB_INFO
+ INIT_EXTRA_SYMTAB_INFO (symtab);
+#endif
+
+ return (symtab);
+}
+
+struct partial_symtab *
+allocate_psymtab (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->objfile_obstack,
+ sizeof (struct partial_symtab));
+
+ memset (psymtab, 0, sizeof (struct partial_symtab));
+ psymtab->filename = obsavestring (filename, strlen (filename),
+ &objfile->objfile_obstack);
+ psymtab->symtab = NULL;
+
+ /* Prepend it to the psymtab list for the objfile it belongs to.
+ Psymtabs are searched in most recent inserted -> least recent
+ inserted order. */
+
+ psymtab->objfile = objfile;
+ psymtab->next = objfile->psymtabs;
+ objfile->psymtabs = psymtab;
+#if 0
+ {
+ struct partial_symtab **prev_pst;
+ psymtab->objfile = objfile;
+ psymtab->next = NULL;
+ prev_pst = &(objfile->psymtabs);
+ while ((*prev_pst) != NULL)
+ prev_pst = &((*prev_pst)->next);
+ (*prev_pst) = psymtab;
+ }
+#endif
+
+ return (psymtab);
+}
+
+void
+discard_psymtab (struct partial_symtab *pst)
+{
+ struct partial_symtab **prev_pst;
+
+ /* From dbxread.c:
+ 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. */
+
+ /* First, snip it out of the psymtab chain */
+
+ prev_pst = &(pst->objfile->psymtabs);
+ while ((*prev_pst) != pst)
+ prev_pst = &((*prev_pst)->next);
+ (*prev_pst) = pst->next;
+
+ /* Next, put it on a free list for recycling */
+
+ pst->next = pst->objfile->free_psymtabs;
+ pst->objfile->free_psymtabs = pst;
+}
+
+
+/* Reset all data structures in gdb which may contain references to symbol
+ table data. */
+
+void
+clear_symtab_users (void)
+{
+ /* 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);
+ clear_current_source_symtab_and_line ();
+ clear_pc_function_cache ();
+ if (target_new_objfile_hook)
+ target_new_objfile_hook (NULL);
+}
+
+static void
+clear_symtab_users_cleanup (void *ignore)
+{
+ clear_symtab_users ();
+}
+
+/* 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 (void);
+
+static int clear_symtab_users_queued;
+static int clear_symtab_users_done;
+
+static void
+clear_symtab_users_once (void)
+{
+ /* 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 (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 objfile_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 value 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 (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. */
+
+ struct symtab *s;
+ struct symtab *prev;
+ 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 (strcmp (name, ps->filename) == 0)
+ {
+ 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 (strcmp (name, s->filename) == 0)
+ 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)))
+ {
+ complaint (&symfile_complaints, "Replacing old symbols for `%s'",
+ name);
+ clear_symtab_users_queued++;
+ make_cleanup (clear_symtab_users_once, 0);
+ blewit = 1;
+ }
+ else
+ {
+ complaint (&symfile_complaints, "Empty symbol table found for `%s'",
+ 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.
+
+ FILENAME is the name of the symbol-file we are reading from. */
+
+struct partial_symtab *
+start_psymtab_common (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).
+ Return the partial symbol that has been added. */
+
+/* NOTE: carlton/2003-09-11: The reason why we return the partial
+ symbol is so that callers can get access to the symbol's demangled
+ name, which they don't have any cheap way to determine otherwise.
+ (Currenly, dwarf2read.c is the only file who uses that information,
+ though it's possible that other readers might in the future.)
+ Elena wasn't thrilled about that, and I don't blame her, but we
+ couldn't come up with a better way to get that information. If
+ it's needed in other situations, we could consider breaking up
+ SYMBOL_SET_NAMES to provide access to the demangled name lookup
+ cache. */
+
+const struct partial_symbol *
+add_psymbol_to_list (char *name, int namelength, domain_enum domain,
+ 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)
+{
+ 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';
+ /* 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_DOMAIN (&psymbol) = domain;
+ PSYMBOL_CLASS (&psymbol) = class;
+
+ SYMBOL_SET_NAMES (&psymbol, buf, namelength, objfile);
+
+ /* Stash the partial symbol away in the cache */
+ psym = deprecated_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++);
+
+ return psym;
+}
+
+/* Add a symbol with a long value to a psymtab. This differs from
+ * add_psymbol_to_list above in taking both a mangled and a demangled
+ * name. */
+
+void
+add_psymbol_with_dem_name_to_list (char *name, int namelength, char *dem_name,
+ int dem_namelength, domain_enum domain,
+ 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)
+{
+ 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';
+ DEPRECATED_SYMBOL_NAME (&psymbol) = deprecated_bcache (buf, namelength + 1,
+ objfile->psymbol_cache);
+
+ buf = alloca (dem_namelength + 1);
+ memcpy (buf, dem_name, dem_namelength);
+ buf[dem_namelength] = '\0';
+
+ switch (language)
+ {
+ case language_c:
+ case language_cplus:
+ SYMBOL_CPLUS_DEMANGLED_NAME (&psymbol) =
+ deprecated_bcache (buf, dem_namelength + 1, objfile->psymbol_cache);
+ break;
+ /* FIXME What should be done for the default case? Ignoring for now. */
+ }
+
+ /* 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_DOMAIN (&psymbol) = domain;
+ PSYMBOL_CLASS (&psymbol) = class;
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (&psymbol, language);
+
+ /* Stash the partial symbol away in the cache */
+ psym = deprecated_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 (struct objfile *objfile, int total_symbols)
+{
+ /* Free any previously allocated psymbol lists. */
+
+ if (objfile->global_psymbols.list)
+ {
+ xmfree (objfile->md, objfile->global_psymbols.list);
+ }
+ if (objfile->static_psymbols.list)
+ {
+ xmfree (objfile->md, 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;
+
+ if (objfile->global_psymbols.size > 0)
+ {
+ objfile->global_psymbols.next =
+ objfile->global_psymbols.list = (struct partial_symbol **)
+ xmmalloc (objfile->md, (objfile->global_psymbols.size
+ * sizeof (struct partial_symbol *)));
+ }
+ if (objfile->static_psymbols.size > 0)
+ {
+ objfile->static_psymbols.next =
+ objfile->static_psymbols.list = (struct partial_symbol **)
+ xmmalloc (objfile->md, (objfile->static_psymbols.size
+ * sizeof (struct partial_symbol *)));
+ }
+}
+
+/* OVERLAYS:
+ The following code implements an abstraction for debugging overlay sections.
+
+ The target model is as follows:
+ 1) The gnu linker will permit multiple sections to be mapped into the
+ same VMA, each with its own unique LMA (or load address).
+ 2) It is assumed that some runtime mechanism exists for mapping the
+ sections, one by one, from the load address into the VMA address.
+ 3) This code provides a mechanism for gdb to keep track of which
+ sections should be considered to be mapped from the VMA to the LMA.
+ This information is used for symbol lookup, and memory read/write.
+ For instance, if a section has been mapped then its contents
+ should be read from the VMA, otherwise from the LMA.
+
+ Two levels of debugger support for overlays are available. One is
+ "manual", in which the debugger relies on the user to tell it which
+ overlays are currently mapped. This level of support is
+ implemented entirely in the core debugger, and the information about
+ whether a section is mapped is kept in the objfile->obj_section table.
+
+ The second level of support is "automatic", and is only available if
+ the target-specific code provides functionality to read the target's
+ overlay mapping table, and translate its contents for the debugger
+ (by updating the mapped state information in the obj_section tables).
+
+ The interface is as follows:
+ User commands:
+ overlay map <name> -- tell gdb to consider this section mapped
+ overlay unmap <name> -- tell gdb to consider this section unmapped
+ overlay list -- list the sections that GDB thinks are mapped
+ overlay read-target -- get the target's state of what's mapped
+ overlay off/manual/auto -- set overlay debugging state
+ Functional interface:
+ find_pc_mapped_section(pc): if the pc is in the range of a mapped
+ section, return that section.
+ find_pc_overlay(pc): find any overlay section that contains
+ the pc, either in its VMA or its LMA
+ overlay_is_mapped(sect): true if overlay is marked as mapped
+ section_is_overlay(sect): true if section's VMA != LMA
+ pc_in_mapped_range(pc,sec): true if pc belongs to section's VMA
+ pc_in_unmapped_range(...): true if pc belongs to section's LMA
+ sections_overlap(sec1, sec2): true if mapped sec1 and sec2 ranges overlap
+ overlay_mapped_address(...): map an address from section's LMA to VMA
+ overlay_unmapped_address(...): map an address from section's VMA to LMA
+ symbol_overlayed_address(...): Return a "current" address for symbol:
+ either in VMA or LMA depending on whether
+ the symbol's section is currently mapped
+ */
+
+/* Overlay debugging state: */
+
+enum overlay_debugging_state overlay_debugging = ovly_off;
+int overlay_cache_invalid = 0; /* True if need to refresh mapped state */
+
+/* Target vector for refreshing overlay mapped state */
+static void simple_overlay_update (struct obj_section *);
+void (*target_overlay_update) (struct obj_section *) = simple_overlay_update;
+
+/* Function: section_is_overlay (SECTION)
+ Returns true if SECTION has VMA not equal to LMA, ie.
+ SECTION is loaded at an address different from where it will "run". */
+
+int
+section_is_overlay (asection *section)
+{
+ /* FIXME: need bfd *, so we can use bfd_section_lma methods. */
+
+ if (overlay_debugging)
+ if (section && section->lma != 0 &&
+ section->vma != section->lma)
+ return 1;
+
+ return 0;
+}
+
+/* Function: overlay_invalidate_all (void)
+ Invalidate the mapped state of all overlay sections (mark it as stale). */
+
+static void
+overlay_invalidate_all (void)
+{
+ struct objfile *objfile;
+ struct obj_section *sect;
+
+ ALL_OBJSECTIONS (objfile, sect)
+ if (section_is_overlay (sect->the_bfd_section))
+ sect->ovly_mapped = -1;
+}
+
+/* Function: overlay_is_mapped (SECTION)
+ Returns true if section is an overlay, and is currently mapped.
+ Private: public access is thru function section_is_mapped.
+
+ Access to the ovly_mapped flag is restricted to this function, so
+ that we can do automatic update. If the global flag
+ OVERLAY_CACHE_INVALID is set (by wait_for_inferior), then call
+ overlay_invalidate_all. If the mapped state of the particular
+ section is stale, then call TARGET_OVERLAY_UPDATE to refresh it. */
+
+static int
+overlay_is_mapped (struct obj_section *osect)
+{
+ if (osect == 0 || !section_is_overlay (osect->the_bfd_section))
+ return 0;
+
+ switch (overlay_debugging)
+ {
+ default:
+ case ovly_off:
+ return 0; /* overlay debugging off */
+ case ovly_auto: /* overlay debugging automatic */
+ /* Unles there is a target_overlay_update function,
+ there's really nothing useful to do here (can't really go auto) */
+ if (target_overlay_update)
+ {
+ if (overlay_cache_invalid)
+ {
+ overlay_invalidate_all ();
+ overlay_cache_invalid = 0;
+ }
+ if (osect->ovly_mapped == -1)
+ (*target_overlay_update) (osect);
+ }
+ /* fall thru to manual case */
+ case ovly_on: /* overlay debugging manual */
+ return osect->ovly_mapped == 1;
+ }
+}
+
+/* Function: section_is_mapped
+ Returns true if section is an overlay, and is currently mapped. */
+
+int
+section_is_mapped (asection *section)
+{
+ struct objfile *objfile;
+ struct obj_section *osect;
+
+ if (overlay_debugging)
+ if (section && section_is_overlay (section))
+ ALL_OBJSECTIONS (objfile, osect)
+ if (osect->the_bfd_section == section)
+ return overlay_is_mapped (osect);
+
+ return 0;
+}
+
+/* Function: pc_in_unmapped_range
+ If PC falls into the lma range of SECTION, return true, else false. */
+
+CORE_ADDR
+pc_in_unmapped_range (CORE_ADDR pc, asection *section)
+{
+ /* FIXME: need bfd *, so we can use bfd_section_lma methods. */
+
+ int size;
+
+ if (overlay_debugging)
+ if (section && section_is_overlay (section))
+ {
+ size = bfd_get_section_size_before_reloc (section);
+ if (section->lma <= pc && pc < section->lma + size)
+ return 1;
+ }
+ return 0;
+}
+
+/* Function: pc_in_mapped_range
+ If PC falls into the vma range of SECTION, return true, else false. */
+
+CORE_ADDR
+pc_in_mapped_range (CORE_ADDR pc, asection *section)
+{
+ /* FIXME: need bfd *, so we can use bfd_section_vma methods. */
+
+ int size;
+
+ if (overlay_debugging)
+ if (section && section_is_overlay (section))
+ {
+ size = bfd_get_section_size_before_reloc (section);
+ if (section->vma <= pc && pc < section->vma + size)
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Return true if the mapped ranges of sections A and B overlap, false
+ otherwise. */
+static int
+sections_overlap (asection *a, asection *b)
+{
+ /* FIXME: need bfd *, so we can use bfd_section_vma methods. */
+
+ CORE_ADDR a_start = a->vma;
+ CORE_ADDR a_end = a->vma + bfd_get_section_size_before_reloc (a);
+ CORE_ADDR b_start = b->vma;
+ CORE_ADDR b_end = b->vma + bfd_get_section_size_before_reloc (b);
+
+ return (a_start < b_end && b_start < a_end);
+}
+
+/* Function: overlay_unmapped_address (PC, SECTION)
+ Returns the address corresponding to PC in the unmapped (load) range.
+ May be the same as PC. */
+
+CORE_ADDR
+overlay_unmapped_address (CORE_ADDR pc, asection *section)
+{
+ /* FIXME: need bfd *, so we can use bfd_section_lma methods. */
+
+ if (overlay_debugging)
+ if (section && section_is_overlay (section) &&
+ pc_in_mapped_range (pc, section))
+ return pc + section->lma - section->vma;
+
+ return pc;
+}
+
+/* Function: overlay_mapped_address (PC, SECTION)
+ Returns the address corresponding to PC in the mapped (runtime) range.
+ May be the same as PC. */
+
+CORE_ADDR
+overlay_mapped_address (CORE_ADDR pc, asection *section)
+{
+ /* FIXME: need bfd *, so we can use bfd_section_vma methods. */
+
+ if (overlay_debugging)
+ if (section && section_is_overlay (section) &&
+ pc_in_unmapped_range (pc, section))
+ return pc + section->vma - section->lma;
+
+ return pc;
+}
+
+
+/* Function: symbol_overlayed_address
+ Return one of two addresses (relative to the VMA or to the LMA),
+ depending on whether the section is mapped or not. */
+
+CORE_ADDR
+symbol_overlayed_address (CORE_ADDR address, asection *section)
+{
+ if (overlay_debugging)
+ {
+ /* If the symbol has no section, just return its regular address. */
+ if (section == 0)
+ return address;
+ /* If the symbol's section is not an overlay, just return its address */
+ if (!section_is_overlay (section))
+ return address;
+ /* If the symbol's section is mapped, just return its address */
+ if (section_is_mapped (section))
+ return address;
+ /*
+ * HOWEVER: if the symbol is in an overlay section which is NOT mapped,
+ * then return its LOADED address rather than its vma address!!
+ */
+ return overlay_unmapped_address (address, section);
+ }
+ return address;
+}
+
+/* Function: find_pc_overlay (PC)
+ Return the best-match overlay section for PC:
+ If PC matches a mapped overlay section's VMA, return that section.
+ Else if PC matches an unmapped section's VMA, return that section.
+ Else if PC matches an unmapped section's LMA, return that section. */
+
+asection *
+find_pc_overlay (CORE_ADDR pc)
+{
+ struct objfile *objfile;
+ struct obj_section *osect, *best_match = NULL;
+
+ if (overlay_debugging)
+ ALL_OBJSECTIONS (objfile, osect)
+ if (section_is_overlay (osect->the_bfd_section))
+ {
+ if (pc_in_mapped_range (pc, osect->the_bfd_section))
+ {
+ if (overlay_is_mapped (osect))
+ return osect->the_bfd_section;
+ else
+ best_match = osect;
+ }
+ else if (pc_in_unmapped_range (pc, osect->the_bfd_section))
+ best_match = osect;
+ }
+ return best_match ? best_match->the_bfd_section : NULL;
+}
+
+/* Function: find_pc_mapped_section (PC)
+ If PC falls into the VMA address range of an overlay section that is
+ currently marked as MAPPED, return that section. Else return NULL. */
+
+asection *
+find_pc_mapped_section (CORE_ADDR pc)
+{
+ struct objfile *objfile;
+ struct obj_section *osect;
+
+ if (overlay_debugging)
+ ALL_OBJSECTIONS (objfile, osect)
+ if (pc_in_mapped_range (pc, osect->the_bfd_section) &&
+ overlay_is_mapped (osect))
+ return osect->the_bfd_section;
+
+ return NULL;
+}
+
+/* Function: list_overlays_command
+ Print a list of mapped sections and their PC ranges */
+
+void
+list_overlays_command (char *args, int from_tty)
+{
+ int nmapped = 0;
+ struct objfile *objfile;
+ struct obj_section *osect;
+
+ if (overlay_debugging)
+ ALL_OBJSECTIONS (objfile, osect)
+ if (overlay_is_mapped (osect))
+ {
+ const char *name;
+ bfd_vma lma, vma;
+ int size;
+
+ vma = bfd_section_vma (objfile->obfd, osect->the_bfd_section);
+ lma = bfd_section_lma (objfile->obfd, osect->the_bfd_section);
+ size = bfd_get_section_size_before_reloc (osect->the_bfd_section);
+ name = bfd_section_name (objfile->obfd, osect->the_bfd_section);
+
+ printf_filtered ("Section %s, loaded at ", name);
+ print_address_numeric (lma, 1, gdb_stdout);
+ puts_filtered (" - ");
+ print_address_numeric (lma + size, 1, gdb_stdout);
+ printf_filtered (", mapped at ");
+ print_address_numeric (vma, 1, gdb_stdout);
+ puts_filtered (" - ");
+ print_address_numeric (vma + size, 1, gdb_stdout);
+ puts_filtered ("\n");
+
+ nmapped++;
+ }
+ if (nmapped == 0)
+ printf_filtered ("No sections are mapped.\n");
+}
+
+/* Function: map_overlay_command
+ Mark the named section as mapped (ie. residing at its VMA address). */
+
+void
+map_overlay_command (char *args, int from_tty)
+{
+ struct objfile *objfile, *objfile2;
+ struct obj_section *sec, *sec2;
+ asection *bfdsec;
+
+ if (!overlay_debugging)
+ error ("\
+Overlay debugging not enabled. Use either the 'overlay auto' or\n\
+the 'overlay manual' command.");
+
+ if (args == 0 || *args == 0)
+ error ("Argument required: name of an overlay section");
+
+ /* First, find a section matching the user supplied argument */
+ ALL_OBJSECTIONS (objfile, sec)
+ if (!strcmp (bfd_section_name (objfile->obfd, sec->the_bfd_section), args))
+ {
+ /* Now, check to see if the section is an overlay. */
+ bfdsec = sec->the_bfd_section;
+ if (!section_is_overlay (bfdsec))
+ continue; /* not an overlay section */
+
+ /* Mark the overlay as "mapped" */
+ sec->ovly_mapped = 1;
+
+ /* Next, make a pass and unmap any sections that are
+ overlapped by this new section: */
+ ALL_OBJSECTIONS (objfile2, sec2)
+ if (sec2->ovly_mapped
+ && sec != sec2
+ && sec->the_bfd_section != sec2->the_bfd_section
+ && sections_overlap (sec->the_bfd_section,
+ sec2->the_bfd_section))
+ {
+ if (info_verbose)
+ printf_unfiltered ("Note: section %s unmapped by overlap\n",
+ bfd_section_name (objfile->obfd,
+ sec2->the_bfd_section));
+ sec2->ovly_mapped = 0; /* sec2 overlaps sec: unmap sec2 */
+ }
+ return;
+ }
+ error ("No overlay section called %s", args);
+}
+
+/* Function: unmap_overlay_command
+ Mark the overlay section as unmapped
+ (ie. resident in its LMA address range, rather than the VMA range). */
+
+void
+unmap_overlay_command (char *args, int from_tty)
+{
+ struct objfile *objfile;
+ struct obj_section *sec;
+
+ if (!overlay_debugging)
+ error ("\
+Overlay debugging not enabled. Use either the 'overlay auto' or\n\
+the 'overlay manual' command.");
+
+ if (args == 0 || *args == 0)
+ error ("Argument required: name of an overlay section");
+
+ /* First, find a section matching the user supplied argument */
+ ALL_OBJSECTIONS (objfile, sec)
+ if (!strcmp (bfd_section_name (objfile->obfd, sec->the_bfd_section), args))
+ {
+ if (!sec->ovly_mapped)
+ error ("Section %s is not mapped", args);
+ sec->ovly_mapped = 0;
+ return;
+ }
+ error ("No overlay section called %s", args);
+}
+
+/* Function: overlay_auto_command
+ A utility command to turn on overlay debugging.
+ Possibly this should be done via a set/show command. */
+
+static void
+overlay_auto_command (char *args, int from_tty)
+{
+ overlay_debugging = ovly_auto;
+ enable_overlay_breakpoints ();
+ if (info_verbose)
+ printf_unfiltered ("Automatic overlay debugging enabled.");
+}
+
+/* Function: overlay_manual_command
+ A utility command to turn on overlay debugging.
+ Possibly this should be done via a set/show command. */
+
+static void
+overlay_manual_command (char *args, int from_tty)
+{
+ overlay_debugging = ovly_on;
+ disable_overlay_breakpoints ();
+ if (info_verbose)
+ printf_unfiltered ("Overlay debugging enabled.");
+}
+
+/* Function: overlay_off_command
+ A utility command to turn on overlay debugging.
+ Possibly this should be done via a set/show command. */
+
+static void
+overlay_off_command (char *args, int from_tty)
+{
+ overlay_debugging = ovly_off;
+ disable_overlay_breakpoints ();
+ if (info_verbose)
+ printf_unfiltered ("Overlay debugging disabled.");
+}
+
+static void
+overlay_load_command (char *args, int from_tty)
+{
+ if (target_overlay_update)
+ (*target_overlay_update) (NULL);
+ else
+ error ("This target does not know how to read its overlay state.");
+}
+
+/* Function: overlay_command
+ A place-holder for a mis-typed command */
+
+/* Command list chain containing all defined "overlay" subcommands. */
+struct cmd_list_element *overlaylist;
+
+static void
+overlay_command (char *args, int from_tty)
+{
+ printf_unfiltered
+ ("\"overlay\" must be followed by the name of an overlay command.\n");
+ help_list (overlaylist, "overlay ", -1, gdb_stdout);
+}
+
+
+/* Target Overlays for the "Simplest" overlay manager:
+
+ This is GDB's default target overlay layer. It works with the
+ minimal overlay manager supplied as an example by Cygnus. The
+ entry point is via a function pointer "target_overlay_update",
+ so targets that use a different runtime overlay manager can
+ substitute their own overlay_update function and take over the
+ function pointer.
+
+ The overlay_update function pokes around in the target's data structures
+ to see what overlays are mapped, and updates GDB's overlay mapping with
+ this information.
+
+ In this simple implementation, the target data structures are as follows:
+ unsigned _novlys; /# number of overlay sections #/
+ unsigned _ovly_table[_novlys][4] = {
+ {VMA, SIZE, LMA, MAPPED}, /# one entry per overlay section #/
+ {..., ..., ..., ...},
+ }
+ unsigned _novly_regions; /# number of overlay regions #/
+ unsigned _ovly_region_table[_novly_regions][3] = {
+ {VMA, SIZE, MAPPED_TO_LMA}, /# one entry per overlay region #/
+ {..., ..., ...},
+ }
+ These functions will attempt to update GDB's mappedness state in the
+ symbol section table, based on the target's mappedness state.
+
+ To do this, we keep a cached copy of the target's _ovly_table, and
+ attempt to detect when the cached copy is invalidated. The main
+ entry point is "simple_overlay_update(SECT), which looks up SECT in
+ the cached table and re-reads only the entry for that section from
+ the target (whenever possible).
+ */
+
+/* Cached, dynamically allocated copies of the target data structures: */
+static unsigned (*cache_ovly_table)[4] = 0;
+#if 0
+static unsigned (*cache_ovly_region_table)[3] = 0;
+#endif
+static unsigned cache_novlys = 0;
+#if 0
+static unsigned cache_novly_regions = 0;
+#endif
+static CORE_ADDR cache_ovly_table_base = 0;
+#if 0
+static CORE_ADDR cache_ovly_region_table_base = 0;
+#endif
+enum ovly_index
+ {
+ VMA, SIZE, LMA, MAPPED
+ };
+#define TARGET_LONG_BYTES (TARGET_LONG_BIT / TARGET_CHAR_BIT)
+
+/* Throw away the cached copy of _ovly_table */
+static void
+simple_free_overlay_table (void)
+{
+ if (cache_ovly_table)
+ xfree (cache_ovly_table);
+ cache_novlys = 0;
+ cache_ovly_table = NULL;
+ cache_ovly_table_base = 0;
+}
+
+#if 0
+/* Throw away the cached copy of _ovly_region_table */
+static void
+simple_free_overlay_region_table (void)
+{
+ if (cache_ovly_region_table)
+ xfree (cache_ovly_region_table);
+ cache_novly_regions = 0;
+ cache_ovly_region_table = NULL;
+ cache_ovly_region_table_base = 0;
+}
+#endif
+
+/* Read an array of ints from the target into a local buffer.
+ Convert to host order. int LEN is number of ints */
+static void
+read_target_long_array (CORE_ADDR memaddr, unsigned int *myaddr, int len)
+{
+ /* FIXME (alloca): Not safe if array is very large. */
+ char *buf = alloca (len * TARGET_LONG_BYTES);
+ int i;
+
+ read_memory (memaddr, buf, len * TARGET_LONG_BYTES);
+ for (i = 0; i < len; i++)
+ myaddr[i] = extract_unsigned_integer (TARGET_LONG_BYTES * i + buf,
+ TARGET_LONG_BYTES);
+}
+
+/* Find and grab a copy of the target _ovly_table
+ (and _novlys, which is needed for the table's size) */
+static int
+simple_read_overlay_table (void)
+{
+ struct minimal_symbol *novlys_msym, *ovly_table_msym;
+
+ simple_free_overlay_table ();
+ novlys_msym = lookup_minimal_symbol ("_novlys", NULL, NULL);
+ if (! novlys_msym)
+ {
+ error ("Error reading inferior's overlay table: "
+ "couldn't find `_novlys' variable\n"
+ "in inferior. Use `overlay manual' mode.");
+ return 0;
+ }
+
+ ovly_table_msym = lookup_minimal_symbol ("_ovly_table", NULL, NULL);
+ if (! ovly_table_msym)
+ {
+ error ("Error reading inferior's overlay table: couldn't find "
+ "`_ovly_table' array\n"
+ "in inferior. Use `overlay manual' mode.");
+ return 0;
+ }
+
+ cache_novlys = read_memory_integer (SYMBOL_VALUE_ADDRESS (novlys_msym), 4);
+ cache_ovly_table
+ = (void *) xmalloc (cache_novlys * sizeof (*cache_ovly_table));
+ cache_ovly_table_base = SYMBOL_VALUE_ADDRESS (ovly_table_msym);
+ read_target_long_array (cache_ovly_table_base,
+ (int *) cache_ovly_table,
+ cache_novlys * 4);
+
+ return 1; /* SUCCESS */
+}
+
+#if 0
+/* Find and grab a copy of the target _ovly_region_table
+ (and _novly_regions, which is needed for the table's size) */
+static int
+simple_read_overlay_region_table (void)
+{
+ struct minimal_symbol *msym;
+
+ simple_free_overlay_region_table ();
+ msym = lookup_minimal_symbol ("_novly_regions", NULL, NULL);
+ if (msym != NULL)
+ cache_novly_regions = read_memory_integer (SYMBOL_VALUE_ADDRESS (msym), 4);
+ else
+ return 0; /* failure */
+ cache_ovly_region_table = (void *) xmalloc (cache_novly_regions * 12);
+ if (cache_ovly_region_table != NULL)
+ {
+ msym = lookup_minimal_symbol ("_ovly_region_table", NULL, NULL);
+ if (msym != NULL)
+ {
+ cache_ovly_region_table_base = SYMBOL_VALUE_ADDRESS (msym);
+ read_target_long_array (cache_ovly_region_table_base,
+ (int *) cache_ovly_region_table,
+ cache_novly_regions * 3);
+ }
+ else
+ return 0; /* failure */
+ }
+ else
+ return 0; /* failure */
+ return 1; /* SUCCESS */
+}
+#endif
+
+/* Function: simple_overlay_update_1
+ A helper function for simple_overlay_update. Assuming a cached copy
+ of _ovly_table exists, look through it to find an entry whose vma,
+ lma and size match those of OSECT. Re-read the entry and make sure
+ it still matches OSECT (else the table may no longer be valid).
+ Set OSECT's mapped state to match the entry. Return: 1 for
+ success, 0 for failure. */
+
+static int
+simple_overlay_update_1 (struct obj_section *osect)
+{
+ int i, size;
+ bfd *obfd = osect->objfile->obfd;
+ asection *bsect = osect->the_bfd_section;
+
+ size = bfd_get_section_size_before_reloc (osect->the_bfd_section);
+ for (i = 0; i < cache_novlys; i++)
+ if (cache_ovly_table[i][VMA] == bfd_section_vma (obfd, bsect)
+ && cache_ovly_table[i][LMA] == bfd_section_lma (obfd, bsect)
+ /* && cache_ovly_table[i][SIZE] == size */ )
+ {
+ read_target_long_array (cache_ovly_table_base + i * TARGET_LONG_BYTES,
+ (int *) cache_ovly_table[i], 4);
+ if (cache_ovly_table[i][VMA] == bfd_section_vma (obfd, bsect)
+ && cache_ovly_table[i][LMA] == bfd_section_lma (obfd, bsect)
+ /* && cache_ovly_table[i][SIZE] == size */ )
+ {
+ osect->ovly_mapped = cache_ovly_table[i][MAPPED];
+ return 1;
+ }
+ else /* Warning! Warning! Target's ovly table has changed! */
+ return 0;
+ }
+ return 0;
+}
+
+/* Function: simple_overlay_update
+ If OSECT is NULL, then update all sections' mapped state
+ (after re-reading the entire target _ovly_table).
+ If OSECT is non-NULL, then try to find a matching entry in the
+ cached ovly_table and update only OSECT's mapped state.
+ If a cached entry can't be found or the cache isn't valid, then
+ re-read the entire cache, and go ahead and update all sections. */
+
+static void
+simple_overlay_update (struct obj_section *osect)
+{
+ struct objfile *objfile;
+
+ /* Were we given an osect to look up? NULL means do all of them. */
+ if (osect)
+ /* Have we got a cached copy of the target's overlay table? */
+ if (cache_ovly_table != NULL)
+ /* Does its cached location match what's currently in the symtab? */
+ if (cache_ovly_table_base ==
+ SYMBOL_VALUE_ADDRESS (lookup_minimal_symbol ("_ovly_table", NULL, NULL)))
+ /* Then go ahead and try to look up this single section in the cache */
+ if (simple_overlay_update_1 (osect))
+ /* Found it! We're done. */
+ return;
+
+ /* Cached table no good: need to read the entire table anew.
+ Or else we want all the sections, in which case it's actually
+ more efficient to read the whole table in one block anyway. */
+
+ if (! simple_read_overlay_table ())
+ return;
+
+ /* Now may as well update all sections, even if only one was requested. */
+ ALL_OBJSECTIONS (objfile, osect)
+ if (section_is_overlay (osect->the_bfd_section))
+ {
+ int i, size;
+ bfd *obfd = osect->objfile->obfd;
+ asection *bsect = osect->the_bfd_section;
+
+ size = bfd_get_section_size_before_reloc (osect->the_bfd_section);
+ for (i = 0; i < cache_novlys; i++)
+ if (cache_ovly_table[i][VMA] == bfd_section_vma (obfd, bsect)
+ && cache_ovly_table[i][LMA] == bfd_section_lma (obfd, bsect)
+ /* && cache_ovly_table[i][SIZE] == size */ )
+ { /* obj_section matches i'th entry in ovly_table */
+ osect->ovly_mapped = cache_ovly_table[i][MAPPED];
+ break; /* finished with inner for loop: break out */
+ }
+ }
+}
+
+/* Set the output sections and output offsets for section SECTP in
+ ABFD. The relocation code in BFD will read these offsets, so we
+ need to be sure they're initialized. We map each section to itself,
+ with no offset; this means that SECTP->vma will be honored. */
+
+static void
+symfile_dummy_outputs (bfd *abfd, asection *sectp, void *dummy)
+{
+ sectp->output_section = sectp;
+ sectp->output_offset = 0;
+}
+
+/* Relocate the contents of a debug section SECTP in ABFD. The
+ contents are stored in BUF if it is non-NULL, or returned in a
+ malloc'd buffer otherwise.
+
+ For some platforms and debug info formats, shared libraries contain
+ relocations against the debug sections (particularly for DWARF-2;
+ one affected platform is PowerPC GNU/Linux, although it depends on
+ the version of the linker in use). Also, ELF object files naturally
+ have unresolved relocations for their debug sections. We need to apply
+ the relocations in order to get the locations of symbols correct. */
+
+bfd_byte *
+symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf)
+{
+ /* We're only interested in debugging sections with relocation
+ information. */
+ if ((sectp->flags & SEC_RELOC) == 0)
+ return NULL;
+ if ((sectp->flags & SEC_DEBUGGING) == 0)
+ return NULL;
+
+ /* We will handle section offsets properly elsewhere, so relocate as if
+ all sections begin at 0. */
+ bfd_map_over_sections (abfd, symfile_dummy_outputs, NULL);
+
+ return bfd_simple_get_relocated_section_contents (abfd, sectp, buf, NULL);
+}
+
+void
+_initialize_symfile (void)
+{
+ 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);
+ set_cmd_completer (c, filename_completer);
+
+ c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command,
+ "Usage: add-symbol-file FILE ADDR [-s <SECT> <SECT_ADDR> -s <SECT> <SECT_ADDR> ...]\n\
+Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
+ADDR is the starting address of the file's text.\n\
+The optional arguments are section-name section-address pairs and\n\
+should be specified if the data and bss segments are not contiguous\n\
+with the text. SECT is a section name to be loaded at SECT_ADDR.",
+ &cmdlist);
+ set_cmd_completer (c, 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);
+ set_cmd_completer (c, 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);
+
+ add_prefix_cmd ("overlay", class_support, overlay_command,
+ "Commands for debugging overlays.", &overlaylist,
+ "overlay ", 0, &cmdlist);
+
+ add_com_alias ("ovly", "overlay", class_alias, 1);
+ add_com_alias ("ov", "overlay", class_alias, 1);
+
+ add_cmd ("map-overlay", class_support, map_overlay_command,
+ "Assert that an overlay section is mapped.", &overlaylist);
+
+ add_cmd ("unmap-overlay", class_support, unmap_overlay_command,
+ "Assert that an overlay section is unmapped.", &overlaylist);
+
+ add_cmd ("list-overlays", class_support, list_overlays_command,
+ "List mappings of overlay sections.", &overlaylist);
+
+ add_cmd ("manual", class_support, overlay_manual_command,
+ "Enable overlay debugging.", &overlaylist);
+ add_cmd ("off", class_support, overlay_off_command,
+ "Disable overlay debugging.", &overlaylist);
+ add_cmd ("auto", class_support, overlay_auto_command,
+ "Enable automatic overlay debugging.", &overlaylist);
+ add_cmd ("load-target", class_support, overlay_load_command,
+ "Read the overlay mapping state from the target.", &overlaylist);
+
+ /* Filename extension to source language lookup table: */
+ init_filename_language_table ();
+ c = add_set_cmd ("extension-language", class_files, var_string_noescape,
+ (char *) &ext_args,
+ "Set mapping between filename extension and source language.\n\
+Usage: set extension-language .foo bar",
+ &setlist);
+ set_cmd_cfunc (c, set_ext_lang_command);
+
+ add_info ("extensions", info_ext_lang_command,
+ "All filename extensions associated with a source language.");
+
+ add_show_from_set
+ (add_set_cmd ("download-write-size", class_obscure,
+ var_integer, (char *) &download_write_size,
+ "Set the write size used when downloading a program.\n"
+ "Only used when downloading a program onto a remote\n"
+ "target. Specify zero, or a negative value, to disable\n"
+ "blocked writes. The actual size of each transfer is also\n"
+ "limited by the size of the target packet and the memory\n"
+ "cache.\n",
+ &setlist),
+ &showlist);
+
+ debug_file_directory = xstrdup (DEBUGDIR);
+ c = (add_set_cmd
+ ("debug-file-directory", class_support, var_string,
+ (char *) &debug_file_directory,
+ "Set the directory where separate debug symbols are searched for.\n"
+ "Separate debug symbols are first searched for in the same\n"
+ "directory as the binary, then in the `" DEBUG_SUBDIRECTORY
+ "' subdirectory,\n"
+ "and lastly at the path of the directory of the binary with\n"
+ "the global debug-file directory prepended\n",
+ &setlist));
+ add_show_from_set (c, &showlist);
+ set_cmd_completer (c, filename_completer);
+}
diff --git a/contrib/gdb/gdb/symfile.h b/contrib/gdb/gdb/symfile.h
new file mode 100644
index 0000000..baa353e
--- /dev/null
+++ b/contrib/gdb/gdb/symfile.h
@@ -0,0 +1,340 @@
+/* Definitions for reading symbol files into GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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". */
+
+/* Opaque declarations. */
+struct section_table;
+struct objfile;
+struct obstack;
+struct block;
+
+/* 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
+{
+
+ /* Pointer to beginning of dynamically allocated array of pointers
+ to partial symbols. The array is dynamically expanded as
+ necessary to accommodate more pointers. */
+
+ struct partial_symbol **list;
+
+ /* Pointer to next available slot in which to store a pointer to a
+ partial symbol. */
+
+ struct partial_symbol **next;
+
+ /* Number of allocated pointer slots in current dynamic array (not
+ the number of bytes of storage). The "next" pointer will always
+ point somewhere between list[0] and list[size], and when at
+ list[size] the array will be expanded on the next attempt to
+ store a pointer. */
+
+ int size;
+};
+
+/* Define an array of addresses to accommodate non-contiguous dynamic
+ loading of modules. This is for use when entering commands, so we
+ can keep track of the section names until we read the file and can
+ map them to bfd sections. This structure is also used by solib.c
+ to communicate the section addresses in shared objects to
+ symbol_file_add (). */
+
+struct section_addr_info
+{
+ /* The number of sections for which address information is
+ available. */
+ size_t num_sections;
+ /* Sections whose names are file format dependent. */
+ struct other_sections
+ {
+ CORE_ADDR addr;
+ char *name;
+ int sectindex;
+ } other[1];
+};
+
+/* 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) (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) (struct objfile *);
+
+ /* sym_read (objfile, mainline) Reads a symbol file into a psymtab
+ (or possibly a symtab). OBJFILE is the objfile struct for the
+ file we are reading. 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) (struct objfile *, 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) (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. */
+
+ void (*sym_offsets) (struct objfile *, struct section_addr_info *);
+
+ /* 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;
+
+};
+
+/* The default version of sym_fns.sym_offsets for readers that don't
+ do anything special. */
+
+extern void default_symfile_offsets (struct objfile *objfile,
+ struct section_addr_info *);
+
+
+extern void extend_psymbol_list (struct psymbol_allocation_list *,
+ struct objfile *);
+
+/* Add any kind of symbol to a psymbol_allocation_list. */
+
+/* #include "demangle.h" */
+
+extern const
+struct partial_symbol *add_psymbol_to_list (char *, int, domain_enum,
+ enum address_class,
+ struct psymbol_allocation_list *,
+ long, CORE_ADDR,
+ enum language, struct objfile *);
+
+extern void add_psymbol_with_dem_name_to_list (char *, int, char *, int,
+ domain_enum,
+ enum address_class,
+ struct psymbol_allocation_list
+ *, long, CORE_ADDR,
+ enum language,
+ struct objfile *);
+
+
+extern void init_psymbol_list (struct objfile *, int);
+
+extern void sort_pst_symbols (struct partial_symtab *);
+
+extern struct symtab *allocate_symtab (char *, struct objfile *);
+
+extern int free_named_symtabs (char *);
+
+extern void fill_in_vptr_fieldno (struct type *);
+
+extern void add_symtab_fns (struct sym_fns *);
+
+extern void syms_from_objfile (struct objfile *,
+ struct section_addr_info *,
+ struct section_offsets *, int, int, int);
+
+extern void new_symfile_objfile (struct objfile *, int, int);
+
+extern struct objfile *symbol_file_add (char *, int,
+ struct section_addr_info *, int, int);
+
+/* Create a new section_addr_info, with room for NUM_SECTIONS. */
+
+extern struct section_addr_info *alloc_section_addr_info (size_t
+ num_sections);
+
+/* Build (allocate and populate) a section_addr_info struct from an
+ existing section table. */
+
+extern struct section_addr_info
+ *build_section_addr_info_from_section_table (const struct section_table
+ *start,
+ const struct section_table
+ *end);
+
+/* Free all memory allocated by
+ build_section_addr_info_from_section_table. */
+
+extern void free_section_addr_info (struct section_addr_info *);
+
+
+extern struct partial_symtab *start_psymtab_common (struct objfile *,
+ struct section_offsets *,
+ char *, CORE_ADDR,
+ struct partial_symbol **,
+ struct partial_symbol **);
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol
+ obstack (and add a null character at the end in the copy). Returns
+ the address of the copy. */
+
+extern char *obsavestring (const char *, int, struct obstack *);
+
+/* Concatenate strings S1, S2 and S3; return the new string. Space is
+ found in the OBSTACKP */
+
+extern char *obconcat (struct obstack *obstackp, const char *, const char *,
+ const char *);
+
+ /* Variables */
+
+/* If non-zero, shared library symbols will be added automatically
+ when the inferior is created, new libraries are loaded, or when
+ attaching to the inferior. This is almost always what users will
+ 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. */
+
+extern int auto_solib_add;
+
+/* For systems that support it, a threshold size in megabytes. If
+ automatically adding a new library's symbol table to those already
+ known to the debugger would cause the total shared library symbol
+ size to exceed this threshhold, then the shlib's symbols are not
+ added. The threshold is ignored if the user explicitly asks for a
+ shlib to be added, such as when using the "sharedlibrary" command. */
+
+extern int auto_solib_limit;
+
+/* From symfile.c */
+
+extern struct partial_symtab *allocate_psymtab (char *, struct objfile *);
+
+extern void discard_psymtab (struct partial_symtab *);
+
+extern void find_lowest_section (bfd *, asection *, void *);
+
+extern bfd *symfile_bfd_open (char *);
+
+extern int get_section_index (struct objfile *, char *);
+
+/* Utility functions for overlay sections: */
+extern enum overlay_debugging_state
+{
+ ovly_off,
+ ovly_on,
+ ovly_auto
+} overlay_debugging;
+extern int overlay_cache_invalid;
+
+/* Return the "mapped" overlay section containing the PC. */
+extern asection *find_pc_mapped_section (CORE_ADDR);
+
+/* Return any overlay section containing the PC (even in its LMA
+ region). */
+extern asection *find_pc_overlay (CORE_ADDR);
+
+/* Return true if the section is an overlay. */
+extern int section_is_overlay (asection *);
+
+/* Return true if the overlay section is currently "mapped". */
+extern int section_is_mapped (asection *);
+
+/* Return true if pc belongs to section's VMA. */
+extern CORE_ADDR pc_in_mapped_range (CORE_ADDR, asection *);
+
+/* Return true if pc belongs to section's LMA. */
+extern CORE_ADDR pc_in_unmapped_range (CORE_ADDR, asection *);
+
+/* Map an address from a section's LMA to its VMA. */
+extern CORE_ADDR overlay_mapped_address (CORE_ADDR, asection *);
+
+/* Map an address from a section's VMA to its LMA. */
+extern CORE_ADDR overlay_unmapped_address (CORE_ADDR, asection *);
+
+/* Convert an address in an overlay section (force into VMA range). */
+extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, asection *);
+
+/* Load symbols from a file. */
+extern void symbol_file_add_main (char *args, int from_tty);
+
+/* Clear GDB symbol tables. */
+extern void symbol_file_clear (int from_tty);
+
+extern bfd_byte *symfile_relocate_debug_section (bfd *abfd, asection *sectp,
+ bfd_byte * buf);
+
+/* From dwarfread.c */
+
+extern void dwarf_build_psymtabs (struct objfile *, int, file_ptr,
+ unsigned int, file_ptr, unsigned int);
+
+/* From dwarf2read.c */
+
+extern int dwarf2_has_info (bfd *abfd);
+
+extern void dwarf2_build_psymtabs (struct objfile *, int);
+extern void dwarf2_build_frame_info (struct objfile *);
+
+/* From mdebugread.c */
+
+/* Hack to force structures to exist before use in parameter list. */
+struct ecoff_debug_hack
+{
+ struct ecoff_debug_swap *a;
+ struct ecoff_debug_info *b;
+};
+
+extern void mdebug_build_psymtabs (struct objfile *,
+ const struct ecoff_debug_swap *,
+ struct ecoff_debug_info *);
+
+extern void elfmdebug_build_psymtabs (struct objfile *,
+ const struct ecoff_debug_swap *,
+ asection *);
+
+#endif /* !defined(SYMFILE_H) */
diff --git a/contrib/gdb/gdb/symmisc.c b/contrib/gdb/gdb/symmisc.c
new file mode 100644
index 0000000..c17bda4
--- /dev/null
+++ b/contrib/gdb/gdb/symmisc.c
@@ -0,0 +1,1258 @@
+/* Do various things to symbol tables (other than lookup), for GDB.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_obstack.h"
+#include "language.h"
+#include "bcache.h"
+#include "block.h"
+#include "gdb_regex.h"
+#include "dictionary.h"
+
+#include "gdb_string.h"
+#include "readline/readline.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 (struct objfile *, struct symtab *,
+ struct ui_file *);
+
+static void dump_psymtab (struct objfile *, struct partial_symtab *,
+ struct ui_file *);
+
+static void dump_msymbols (struct objfile *, struct ui_file *);
+
+static void dump_objfile (struct objfile *);
+
+static int block_depth (struct block *);
+
+static void print_partial_symbols (struct partial_symbol **, int,
+ char *, struct ui_file *);
+
+static void free_symtab_block (struct objfile *, struct block *);
+
+void _initialize_symmisc (void);
+
+struct print_symbol_args
+ {
+ struct symbol *symbol;
+ int depth;
+ struct ui_file *outfile;
+ };
+
+static int print_symbol (void *);
+
+static void free_symtab_block (struct objfile *, struct block *);
+
+
+/* Free a struct block <- B and all the symbols defined in that block. */
+
+/* FIXME: carlton/2003-04-28: I don't believe this is currently ever
+ used. */
+
+static void
+free_symtab_block (struct objfile *objfile, struct block *b)
+{
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ xmfree (objfile->md, DEPRECATED_SYMBOL_NAME (sym));
+ xmfree (objfile->md, sym);
+ }
+
+ dict_free (BLOCK_DICT (b));
+ xmfree (objfile->md, 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 (struct symtab *s)
+{
+ int i, n;
+ 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. */
+ xmfree (s->objfile->md, bv);
+ /* Also free the linetable. */
+
+ case free_linetable:
+ /* Everything will be freed either by our `free_func'
+ or by some other symtab, except for our linetable.
+ Free that now. */
+ if (LINETABLE (s))
+ xmfree (s->objfile->md, LINETABLE (s));
+ break;
+ }
+
+ /* If there is a single block of memory to free, free it. */
+ if (s->free_func != NULL)
+ s->free_func (s);
+
+ /* Free source-related stuff */
+ if (s->line_charpos != NULL)
+ xmfree (s->objfile->md, s->line_charpos);
+ if (s->fullname != NULL)
+ xmfree (s->objfile->md, s->fullname);
+ if (s->debugformat != NULL)
+ xmfree (s->objfile->md, s->debugformat);
+ xmfree (s->objfile->md, s);
+}
+
+void
+print_symbol_bcache_statistics (void)
+{
+ 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 (void)
+{
+ struct objfile *objfile;
+ struct symtab *s;
+ struct partial_symtab *ps;
+ int i, linetables, blockvectors;
+
+ 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));
+ i = 0;
+ ALL_OBJFILE_PSYMTABS (objfile, ps)
+ {
+ if (ps->readin == 0)
+ i++;
+ }
+ printf_filtered (" Number of psym tables (not yet expanded): %d\n", i);
+ i = linetables = blockvectors = 0;
+ ALL_OBJFILE_SYMTABS (objfile, s)
+ {
+ i++;
+ if (s->linetable != NULL)
+ linetables++;
+ if (s->primary == 1)
+ blockvectors++;
+ }
+ printf_filtered (" Number of symbol tables: %d\n", i);
+ printf_filtered (" Number of symbol tables with line tables: %d\n",
+ linetables);
+ printf_filtered (" Number of symbol tables with blockvectors: %d\n",
+ blockvectors);
+
+ if (OBJSTAT (objfile, sz_strtab) > 0)
+ printf_filtered (" Space used by a.out string tables: %d\n",
+ OBJSTAT (objfile, sz_strtab));
+ printf_filtered (" Total memory used for objfile obstack: %d\n",
+ obstack_memory_used (&objfile->objfile_obstack));
+ printf_filtered (" Total memory used for psymbol cache: %d\n",
+ bcache_memory_used (objfile->psymbol_cache));
+ printf_filtered (" Total memory used for macro cache: %d\n",
+ bcache_memory_used (objfile->macro_cache));
+ }
+ immediate_quit--;
+}
+
+static void
+dump_objfile (struct objfile *objfile)
+{
+ struct symtab *symtab;
+ struct partial_symtab *psymtab;
+
+ printf_filtered ("\nObject file %s: ", objfile->name);
+ printf_filtered ("Objfile at ");
+ gdb_print_host_address (objfile, gdb_stdout);
+ printf_filtered (", bfd at ");
+ gdb_print_host_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_host_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_host_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 (struct objfile *objfile, struct ui_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;
+ DEPRECATED_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 ", index, ms_type);
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (msymbol), 1, outfile);
+ fprintf_filtered (outfile, " %s", DEPRECATED_SYMBOL_NAME (msymbol));
+ if (SYMBOL_BFD_SECTION (msymbol))
+ fprintf_filtered (outfile, " section %s",
+ bfd_section_name (objfile->obfd,
+ SYMBOL_BFD_SECTION (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 (struct objfile *objfile, struct partial_symtab *psymtab,
+ struct ui_file *outfile)
+{
+ int i;
+
+ fprintf_filtered (outfile, "\nPartial symtab for source file %s ",
+ psymtab->filename);
+ fprintf_filtered (outfile, "(object ");
+ gdb_print_host_address (psymtab, outfile);
+ fprintf_filtered (outfile, ")\n\n");
+ fprintf_unfiltered (outfile, " Read from object file %s (",
+ objfile->name);
+ gdb_print_host_address (objfile, outfile);
+ fprintf_unfiltered (outfile, ")\n");
+
+ if (psymtab->readin)
+ {
+ fprintf_filtered (outfile,
+ " Full symtab was read (at ");
+ gdb_print_host_address (psymtab->symtab, outfile);
+ fprintf_filtered (outfile, " by function at ");
+ gdb_print_host_address (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_host_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 (struct objfile *objfile, struct symtab *symtab,
+ struct ui_file *outfile)
+{
+ int i;
+ struct dict_iterator iter;
+ int len, blen;
+ struct linetable *l;
+ struct blockvector *bv;
+ struct symbol *sym;
+ struct block *b;
+ int depth;
+
+ fprintf_filtered (outfile, "\nSymtab for file %s\n", symtab->filename);
+ if (symtab->dirname)
+ fprintf_filtered (outfile, "Compilation directory is %s\n",
+ symtab->dirname);
+ fprintf_filtered (outfile, "Read from object file %s (", objfile->name);
+ gdb_print_host_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, but only for primary symtabs since we will
+ print lots of duplicate info otherwise. */
+ if (symtab->primary)
+ {
+ 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 at ", i);
+ gdb_print_host_address (b, outfile);
+ if (BLOCK_SUPERBLOCK (b))
+ {
+ fprintf_filtered (outfile, " under ");
+ gdb_print_host_address (BLOCK_SUPERBLOCK (b), outfile);
+ }
+ /* drow/2002-07-10: We could save the total symbols count
+ even if we're using a hashtable, but nothing else but this message
+ wants it. */
+ fprintf_filtered (outfile, ", %d syms/buckets in ",
+ dict_size (BLOCK_DICT (b)));
+ print_address_numeric (BLOCK_START (b), 1, outfile);
+ fprintf_filtered (outfile, "..");
+ print_address_numeric (BLOCK_END (b), 1, outfile);
+ if (BLOCK_FUNCTION (b))
+ {
+ fprintf_filtered (outfile, ", function %s", DEPRECATED_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, ", compiled with gcc%d", BLOCK_GCC_COMPILED (b));
+ fprintf_filtered (outfile, "\n");
+ /* Now print each symbol in this block (in no particular order, if
+ we're using a hashtable). */
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ struct print_symbol_args s;
+ s.symbol = sym;
+ s.depth = depth + 1;
+ s.outfile = outfile;
+ catch_errors (print_symbol, &s, "Error printing symbol:\n",
+ RETURN_MASK_ALL);
+ }
+ }
+ fprintf_filtered (outfile, "\n");
+ }
+ else
+ {
+ fprintf_filtered (outfile, "\nBlockvector same as previous symtab\n\n");
+ }
+}
+
+void
+maintenance_print_symbols (char *args, int from_tty)
+{
+ char **argv;
+ struct ui_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 (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 (xfree, filename);
+
+ outfile = gdb_fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup_ui_file_delete (outfile);
+
+ immediate_quit++;
+ ALL_SYMTABS (objfile, s)
+ if (symname == NULL || strcmp (symname, s->filename) == 0)
+ 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 (void *args)
+{
+ struct symbol *symbol = ((struct print_symbol_args *) args)->symbol;
+ int depth = ((struct print_symbol_args *) args)->depth;
+ struct ui_file *outfile = ((struct print_symbol_args *) args)->outfile;
+
+ print_spaces (depth, outfile);
+ if (SYMBOL_DOMAIN (symbol) == LABEL_DOMAIN)
+ {
+ fprintf_filtered (outfile, "label %s at ", SYMBOL_PRINT_NAME (symbol));
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+ if (SYMBOL_BFD_SECTION (symbol))
+ fprintf_filtered (outfile, " section %s\n",
+ bfd_section_name (SYMBOL_BFD_SECTION (symbol)->owner,
+ SYMBOL_BFD_SECTION (symbol)));
+ else
+ fprintf_filtered (outfile, "\n");
+ return 1;
+ }
+ if (SYMBOL_DOMAIN (symbol) == STRUCT_DOMAIN)
+ {
+ 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")),
+ DEPRECATED_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_PRINT_NAME (symbol),
+ outfile,
+ TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM,
+ depth);
+ fprintf_filtered (outfile, "; ");
+ }
+ else
+ fprintf_filtered (outfile, "%s ", SYMBOL_PRINT_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]);
+ }
+ break;
+
+ case LOC_STATIC:
+ fprintf_filtered (outfile, "static at ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+ if (SYMBOL_BFD_SECTION (symbol))
+ fprintf_filtered (outfile, " section %s",
+ bfd_section_name
+ (SYMBOL_BFD_SECTION (symbol)->owner,
+ SYMBOL_BFD_SECTION (symbol)));
+ break;
+
+ case LOC_INDIRECT:
+ fprintf_filtered (outfile, "extern global 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);
+ if (SYMBOL_BFD_SECTION (symbol))
+ fprintf_filtered (outfile, " section %s",
+ bfd_section_name
+ (SYMBOL_BFD_SECTION (symbol)->owner,
+ SYMBOL_BFD_SECTION (symbol)));
+ break;
+
+ case LOC_BLOCK:
+ fprintf_filtered (outfile, "block object ");
+ gdb_print_host_address (SYMBOL_BLOCK_VALUE (symbol), outfile);
+ fprintf_filtered (outfile, ", ");
+ print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)),
+ 1,
+ outfile);
+ fprintf_filtered (outfile, "..");
+ print_address_numeric (BLOCK_END (SYMBOL_BLOCK_VALUE (symbol)),
+ 1,
+ outfile);
+ if (SYMBOL_BFD_SECTION (symbol))
+ fprintf_filtered (outfile, " section %s",
+ bfd_section_name
+ (SYMBOL_BFD_SECTION (symbol)->owner,
+ SYMBOL_BFD_SECTION (symbol)));
+ break;
+
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ fprintf_filtered (outfile, "computed at runtime");
+ 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 (char *args, int from_tty)
+{
+ char **argv;
+ struct ui_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 (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 (xfree, filename);
+
+ outfile = gdb_fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup_ui_file_delete (outfile);
+
+ immediate_quit++;
+ ALL_PSYMTABS (objfile, ps)
+ if (symname == NULL || strcmp (symname, ps->filename) == 0)
+ dump_psymtab (objfile, ps, outfile);
+ immediate_quit--;
+ do_cleanups (cleanups);
+}
+
+static void
+print_partial_symbols (struct partial_symbol **p, int count, char *what,
+ struct ui_file *outfile)
+{
+ fprintf_filtered (outfile, " %s partial symbols:\n", what);
+ while (count-- > 0)
+ {
+ fprintf_filtered (outfile, " `%s'", DEPRECATED_SYMBOL_NAME (*p));
+ if (SYMBOL_DEMANGLED_NAME (*p) != NULL)
+ {
+ fprintf_filtered (outfile, " `%s'", SYMBOL_DEMANGLED_NAME (*p));
+ }
+ fputs_filtered (", ", outfile);
+ switch (SYMBOL_DOMAIN (*p))
+ {
+ case UNDEF_DOMAIN:
+ fputs_filtered ("undefined domain, ", outfile);
+ break;
+ case VAR_DOMAIN:
+ /* This is the usual thing -- don't print it */
+ break;
+ case STRUCT_DOMAIN:
+ fputs_filtered ("struct domain, ", outfile);
+ break;
+ case LABEL_DOMAIN:
+ fputs_filtered ("label domain, ", outfile);
+ break;
+ default:
+ fputs_filtered ("<invalid domain>, ", 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_INDIRECT:
+ fputs_filtered ("extern global", 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;
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ fputs_filtered ("computed at runtime", outfile);
+ break;
+ default:
+ fputs_filtered ("<invalid location>", outfile);
+ break;
+ }
+ fputs_filtered (", ", outfile);
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (*p), 1, outfile);
+ fprintf_filtered (outfile, "\n");
+ p++;
+ }
+}
+
+void
+maintenance_print_msymbols (char *args, int from_tty)
+{
+ char **argv;
+ struct ui_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 (xfree, filename);
+
+ outfile = gdb_fopen (filename, FOPEN_WT);
+ if (outfile == 0)
+ perror_with_name (filename);
+ make_cleanup_ui_file_delete (outfile);
+
+ immediate_quit++;
+ ALL_OBJFILES (objfile)
+ if (symname == NULL || strcmp (symname, objfile->name) == 0)
+ dump_msymbols (objfile, outfile);
+ immediate_quit--;
+ fprintf_filtered (outfile, "\n\n");
+ do_cleanups (cleanups);
+}
+
+void
+maintenance_print_objfiles (char *ignore, int from_tty)
+{
+ struct objfile *objfile;
+
+ dont_repeat ();
+
+ immediate_quit++;
+ ALL_OBJFILES (objfile)
+ dump_objfile (objfile);
+ immediate_quit--;
+}
+
+
+/* List all the symbol tables whose names match REGEXP (optional). */
+void
+maintenance_info_symtabs (char *regexp, int from_tty)
+{
+ struct objfile *objfile;
+
+ if (regexp)
+ re_comp (regexp);
+
+ ALL_OBJFILES (objfile)
+ {
+ struct symtab *symtab;
+
+ /* We don't want to print anything for this objfile until we
+ actually find a symtab whose name matches. */
+ int printed_objfile_start = 0;
+
+ ALL_OBJFILE_SYMTABS (objfile, symtab)
+ if (! regexp
+ || re_exec (symtab->filename))
+ {
+ if (! printed_objfile_start)
+ {
+ printf_filtered ("{ objfile %s ", objfile->name);
+ wrap_here (" ");
+ printf_filtered ("((struct objfile *) %p)\n", objfile);
+ printed_objfile_start = 1;
+ }
+
+ printf_filtered (" { symtab %s ", symtab->filename);
+ wrap_here (" ");
+ printf_filtered ("((struct symtab *) %p)\n", symtab);
+ printf_filtered (" dirname %s\n",
+ symtab->dirname ? symtab->dirname : "(null)");
+ printf_filtered (" fullname %s\n",
+ symtab->fullname ? symtab->fullname : "(null)");
+ printf_filtered (" blockvector ((struct blockvector *) %p)%s\n",
+ symtab->blockvector,
+ symtab->primary ? " (primary)" : "");
+ printf_filtered (" debugformat %s\n", symtab->debugformat);
+ printf_filtered (" }\n");
+ }
+
+ if (printed_objfile_start)
+ printf_filtered ("}\n");
+ }
+}
+
+
+/* List all the partial symbol tables whose names match REGEXP (optional). */
+void
+maintenance_info_psymtabs (char *regexp, int from_tty)
+{
+ struct objfile *objfile;
+
+ if (regexp)
+ re_comp (regexp);
+
+ ALL_OBJFILES (objfile)
+ {
+ struct partial_symtab *psymtab;
+
+ /* We don't want to print anything for this objfile until we
+ actually find a symtab whose name matches. */
+ int printed_objfile_start = 0;
+
+ ALL_OBJFILE_PSYMTABS (objfile, psymtab)
+ if (! regexp
+ || re_exec (psymtab->filename))
+ {
+ if (! printed_objfile_start)
+ {
+ printf_filtered ("{ objfile %s ", objfile->name);
+ wrap_here (" ");
+ printf_filtered ("((struct objfile *) %p)\n", objfile);
+ printed_objfile_start = 1;
+ }
+
+ printf_filtered (" { psymtab %s ", psymtab->filename);
+ wrap_here (" ");
+ printf_filtered ("((struct partial_symtab *) %p)\n", psymtab);
+ printf_filtered (" readin %s\n",
+ psymtab->readin ? "yes" : "no");
+ printf_filtered (" fullname %s\n",
+ psymtab->fullname ? psymtab->fullname : "(null)");
+ printf_filtered (" text addresses ");
+ print_address_numeric (psymtab->textlow, 1, gdb_stdout);
+ printf_filtered (" -- ");
+ print_address_numeric (psymtab->texthigh, 1, gdb_stdout);
+ printf_filtered ("\n");
+ printf_filtered (" globals ");
+ if (psymtab->n_global_syms)
+ {
+ printf_filtered ("(* (struct partial_symbol **) %p @ %d)\n",
+ (psymtab->objfile->global_psymbols.list
+ + psymtab->globals_offset),
+ psymtab->n_global_syms);
+ }
+ else
+ printf_filtered ("(none)\n");
+ printf_filtered (" statics ");
+ if (psymtab->n_static_syms)
+ {
+ printf_filtered ("(* (struct partial_symbol **) %p @ %d)\n",
+ (psymtab->objfile->static_psymbols.list
+ + psymtab->statics_offset),
+ psymtab->n_static_syms);
+ }
+ else
+ printf_filtered ("(none)\n");
+ printf_filtered (" dependencies ");
+ if (psymtab->number_of_dependencies)
+ {
+ int i;
+
+ printf_filtered ("{\n");
+ for (i = 0; i < psymtab->number_of_dependencies; i++)
+ {
+ struct partial_symtab *dep = psymtab->dependencies[i];
+
+ /* Note the string concatenation there --- no comma. */
+ printf_filtered (" psymtab %s "
+ "((struct partial_symtab *) %p)\n",
+ dep->filename, dep);
+ }
+ printf_filtered (" }\n");
+ }
+ else
+ printf_filtered ("(none)\n");
+ printf_filtered (" }\n");
+ }
+
+ if (printed_objfile_start)
+ printf_filtered ("}\n");
+ }
+}
+
+
+/* Check consistency of psymtabs and symtabs. */
+
+void
+maintenance_check_symtabs (char *ignore, int from_tty)
+{
+ struct symbol *sym;
+ struct partial_symbol **psym;
+ struct symtab *s = NULL;
+ struct partial_symtab *ps;
+ struct blockvector *bv;
+ struct objfile *objfile;
+ 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, DEPRECATED_SYMBOL_NAME (*psym),
+ NULL, SYMBOL_DOMAIN (*psym));
+ if (!sym)
+ {
+ printf_filtered ("Static symbol `");
+ puts_filtered (DEPRECATED_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, DEPRECATED_SYMBOL_NAME (*psym),
+ NULL, SYMBOL_DOMAIN (*psym));
+ if (!sym)
+ {
+ printf_filtered ("Global symbol `");
+ puts_filtered (DEPRECATED_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, gdb_stdout);
+ printf_filtered (" - ");
+ print_address_numeric (ps->texthigh, 1, gdb_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, gdb_stdout);
+ printf_filtered (" - ");
+ print_address_numeric (ps->texthigh, 1, gdb_stdout);
+ printf_filtered (" but symtab covers only ");
+ print_address_numeric (BLOCK_START (b), 1, gdb_stdout);
+ printf_filtered (" - ");
+ print_address_numeric (BLOCK_END (b), 1, gdb_stdout);
+ printf_filtered ("\n");
+ }
+ }
+}
+
+
+/* Return the nexting depth of a block within other blocks in its symtab. */
+
+static int
+block_depth (struct block *block)
+{
+ int i = 0;
+ while ((block = BLOCK_SUPERBLOCK (block)) != NULL)
+ {
+ i++;
+ }
+ return i;
+}
+
+
+/* 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 (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 (void)
+{
+ 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 0000000..6995891
--- /dev/null
+++ b/contrib/gdb/gdb/symtab.c
@@ -0,0 +1,4042 @@
+/* Symbol table lookup for the GNU debugger, GDB.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_regex.h"
+#include "expression.h"
+#include "language.h"
+#include "demangle.h"
+#include "inferior.h"
+#include "linespec.h"
+#include "source.h"
+#include "filenames.h" /* for FILENAME_CMP */
+#include "objc-lang.h"
+
+#include "hashtab.h"
+
+#include "gdb_obstack.h"
+#include "block.h"
+#include "dictionary.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include "gdb_string.h"
+#include "gdb_stat.h"
+#include <ctype.h>
+#include "cp-abi.h"
+
+/* Prototypes for local functions */
+
+static void completion_list_add_name (char *, char *, int, char *, char *);
+
+static void rbreak_command (char *, int);
+
+static void types_info (char *, int);
+
+static void functions_info (char *, int);
+
+static void variables_info (char *, int);
+
+static void sources_info (char *, int);
+
+static void output_source_filename (char *, int *);
+
+static int find_line_common (struct linetable *, int, int *);
+
+/* This one is used by linespec.c */
+
+char *operator_chars (char *p, char **end);
+
+static struct symbol *lookup_symbol_aux (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ int *is_a_field_of_this,
+ struct symtab **symtab);
+
+static
+struct symbol *lookup_symbol_aux_local (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+static
+struct symbol *lookup_symbol_aux_symtabs (int block_index,
+ const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+static
+struct symbol *lookup_symbol_aux_psymtabs (int block_index,
+ const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+#if 0
+static
+struct symbol *lookup_symbol_aux_minsyms (const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ int *is_a_field_of_this,
+ struct symtab **symtab);
+#endif
+
+/* This flag is used in hppa-tdep.c, and set in hp-symtab-read.c */
+/* Signals the presence of objects compiled by HP compilers */
+int hp_som_som_object_present = 0;
+
+static void fixup_section (struct general_symbol_info *, struct objfile *);
+
+static int file_matches (char *, char **, int);
+
+static void print_symbol_info (domain_enum,
+ struct symtab *, struct symbol *, int, char *);
+
+static void print_msymbol_info (struct minimal_symbol *);
+
+static void symtab_symbol_info (char *, domain_enum, int);
+
+void _initialize_symtab (void);
+
+/* */
+
+/* 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;
+
+/* 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. */
+
+struct symtab *
+lookup_symtab (const char *name)
+{
+ struct symtab *s;
+ struct partial_symtab *ps;
+ struct objfile *objfile;
+ char *real_path = NULL;
+ char *full_path = NULL;
+
+ /* Here we are interested in canonicalizing an absolute path, not
+ absolutizing a relative path. */
+ if (IS_ABSOLUTE_PATH (name))
+ {
+ full_path = xfullpath (name);
+ make_cleanup (xfree, full_path);
+ real_path = gdb_realpath (name);
+ make_cleanup (xfree, real_path);
+ }
+
+got_symtab:
+
+ /* First, search for an exact match */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ if (FILENAME_CMP (name, s->filename) == 0)
+ {
+ return s;
+ }
+
+ /* If the user gave us an absolute path, try to find the file in
+ this symtab and use its absolute path. */
+
+ if (full_path != NULL)
+ {
+ const char *fp = symtab_to_filename (s);
+ if (FILENAME_CMP (full_path, fp) == 0)
+ {
+ return s;
+ }
+ }
+
+ if (real_path != NULL)
+ {
+ char *rp = gdb_realpath (symtab_to_filename (s));
+ make_cleanup (xfree, rp);
+ if (FILENAME_CMP (real_path, rp) == 0)
+ {
+ return s;
+ }
+ }
+ }
+
+ /* Now, search for a matching tail (only if name doesn't have any dirs) */
+
+ if (lbasename (name) == name)
+ ALL_SYMTABS (objfile, s)
+ {
+ if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ 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 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 (const char *name)
+{
+ struct partial_symtab *pst;
+ struct objfile *objfile;
+ char *full_path = NULL;
+ char *real_path = NULL;
+
+ /* Here we are interested in canonicalizing an absolute path, not
+ absolutizing a relative path. */
+ if (IS_ABSOLUTE_PATH (name))
+ {
+ full_path = xfullpath (name);
+ make_cleanup (xfree, full_path);
+ real_path = gdb_realpath (name);
+ make_cleanup (xfree, real_path);
+ }
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (FILENAME_CMP (name, pst->filename) == 0)
+ {
+ return (pst);
+ }
+
+ /* If the user gave us an absolute path, try to find the file in
+ this symtab and use its absolute path. */
+ if (full_path != NULL)
+ {
+ if (pst->fullname == NULL)
+ source_full_path_of (pst->filename, &pst->fullname);
+ if (pst->fullname != NULL
+ && FILENAME_CMP (full_path, pst->fullname) == 0)
+ {
+ return pst;
+ }
+ }
+
+ if (real_path != NULL)
+ {
+ char *rp = NULL;
+ if (pst->fullname == NULL)
+ source_full_path_of (pst->filename, &pst->fullname);
+ if (pst->fullname != NULL)
+ {
+ rp = gdb_realpath (pst->fullname);
+ make_cleanup (xfree, rp);
+ }
+ if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
+ {
+ return pst;
+ }
+ }
+ }
+
+ /* Now, search for a matching tail (only if name doesn't have any dirs) */
+
+ if (lbasename (name) == name)
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (FILENAME_CMP (lbasename (pst->filename), name) == 0)
+ return (pst);
+ }
+
+ return (NULL);
+}
+
+/* Mangle a GDB method stub type. This actually reassembles the pieces of the
+ full method name, which consist of the class name (from T), the unadorned
+ method name from METHOD_ID, and the signature for the specific overload,
+ specified by SIGNATURE_ID. Note that this function is g++ specific. */
+
+char *
+gdb_mangle_name (struct type *type, int method_id, int signature_id)
+{
+ int mangled_name_len;
+ char *mangled_name;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, method_id);
+ struct fn_field *method = &f[signature_id];
+ char *field_name = TYPE_FN_FIELDLIST_NAME (type, method_id);
+ char *physname = TYPE_FN_FIELD_PHYSNAME (f, signature_id);
+ 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 = is_destructor_name (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));
+
+ /* Nothing to do if physname already contains a fully mangled v3 abi name
+ or an operator name. */
+ if ((physname[0] == '_' && physname[1] == 'Z')
+ || is_operator_name (field_name))
+ return xstrdup (physname);
+
+ is_full_physname_constructor = is_constructor_name (physname);
+
+ is_constructor =
+ is_full_physname_constructor || (newname && strcmp (field_name, newname) == 0);
+
+ 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);
+ }
+ else if (physname[0] == 't' || physname[0] == 'Q')
+ {
+ /* The physname for template and qualified methods already includes
+ the class name. */
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ 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);
+
+ {
+ 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);
+}
+
+
+/* Initialize the language dependent portion of a symbol
+ depending upon the language for the symbol. */
+void
+symbol_init_language_specific (struct general_symbol_info *gsymbol,
+ enum language language)
+{
+ gsymbol->language = language;
+ if (gsymbol->language == language_cplus
+ || gsymbol->language == language_java
+ || gsymbol->language == language_objc)
+ {
+ gsymbol->language_specific.cplus_specific.demangled_name = NULL;
+ }
+ else
+ {
+ memset (&gsymbol->language_specific, 0,
+ sizeof (gsymbol->language_specific));
+ }
+}
+
+/* Functions to initialize a symbol's mangled name. */
+
+/* Create the hash table used for demangled names. Each hash entry is
+ a pair of strings; one for the mangled name and one for the demangled
+ name. The entry is hashed via just the mangled name. */
+
+static void
+create_demangled_names_hash (struct objfile *objfile)
+{
+ /* Choose 256 as the starting size of the hash table, somewhat arbitrarily.
+ The hash table code will round this up to the next prime number.
+ Choosing a much larger table size wastes memory, and saves only about
+ 1% in symbol reading. */
+
+ objfile->demangled_names_hash = htab_create_alloc_ex
+ (256, htab_hash_string, (int (*) (const void *, const void *)) streq,
+ NULL, objfile->md, xmcalloc, xmfree);
+}
+
+/* Try to determine 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. The returned name is allocated
+ by the demangler and should be xfree'd. */
+
+static char *
+symbol_find_demangled_name (struct general_symbol_info *gsymbol,
+ const char *mangled)
+{
+ char *demangled = NULL;
+
+ if (gsymbol->language == language_unknown)
+ gsymbol->language = language_auto;
+
+ if (gsymbol->language == language_objc
+ || gsymbol->language == language_auto)
+ {
+ demangled =
+ objc_demangle (mangled, 0);
+ if (demangled != NULL)
+ {
+ gsymbol->language = language_objc;
+ return demangled;
+ }
+ }
+ if (gsymbol->language == language_cplus
+ || gsymbol->language == language_auto)
+ {
+ demangled =
+ cplus_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+ if (demangled != NULL)
+ {
+ gsymbol->language = language_cplus;
+ return demangled;
+ }
+ }
+ if (gsymbol->language == language_java)
+ {
+ demangled =
+ cplus_demangle (mangled,
+ DMGL_PARAMS | DMGL_ANSI | DMGL_JAVA);
+ if (demangled != NULL)
+ {
+ gsymbol->language = language_java;
+ return demangled;
+ }
+ }
+ return NULL;
+}
+
+/* Set both the mangled and demangled (if any) names for GSYMBOL based
+ on LINKAGE_NAME and LEN. The hash table corresponding to OBJFILE
+ is used, and the memory comes from that objfile's objfile_obstack.
+ LINKAGE_NAME is copied, so the pointer can be discarded after
+ calling this function. */
+
+/* We have to be careful when dealing with Java names: when we run
+ into a Java minimal symbol, we don't know it's a Java symbol, so it
+ gets demangled as a C++ name. This is unfortunate, but there's not
+ much we can do about it: but when demangling partial symbols and
+ regular symbols, we'd better not reuse the wrong demangled name.
+ (See PR gdb/1039.) We solve this by putting a distinctive prefix
+ on Java names when storing them in the hash table. */
+
+/* FIXME: carlton/2003-03-13: This is an unfortunate situation. I
+ don't mind the Java prefix so much: different languages have
+ different demangling requirements, so it's only natural that we
+ need to keep language data around in our demangling cache. But
+ it's not good that the minimal symbol has the wrong demangled name.
+ Unfortunately, I can't think of any easy solution to that
+ problem. */
+
+#define JAVA_PREFIX "##JAVA$$"
+#define JAVA_PREFIX_LEN 8
+
+void
+symbol_set_names (struct general_symbol_info *gsymbol,
+ const char *linkage_name, int len, struct objfile *objfile)
+{
+ char **slot;
+ /* A 0-terminated copy of the linkage name. */
+ const char *linkage_name_copy;
+ /* A copy of the linkage name that might have a special Java prefix
+ added to it, for use when looking names up in the hash table. */
+ const char *lookup_name;
+ /* The length of lookup_name. */
+ int lookup_len;
+
+ if (objfile->demangled_names_hash == NULL)
+ create_demangled_names_hash (objfile);
+
+ /* The stabs reader generally provides names that are not
+ NUL-terminated; most of the other readers don't do this, so we
+ can just use the given copy, unless we're in the Java case. */
+ if (gsymbol->language == language_java)
+ {
+ char *alloc_name;
+ lookup_len = len + JAVA_PREFIX_LEN;
+
+ alloc_name = alloca (lookup_len + 1);
+ memcpy (alloc_name, JAVA_PREFIX, JAVA_PREFIX_LEN);
+ memcpy (alloc_name + JAVA_PREFIX_LEN, linkage_name, len);
+ alloc_name[lookup_len] = '\0';
+
+ lookup_name = alloc_name;
+ linkage_name_copy = alloc_name + JAVA_PREFIX_LEN;
+ }
+ else if (linkage_name[len] != '\0')
+ {
+ char *alloc_name;
+ lookup_len = len;
+
+ alloc_name = alloca (lookup_len + 1);
+ memcpy (alloc_name, linkage_name, len);
+ alloc_name[lookup_len] = '\0';
+
+ lookup_name = alloc_name;
+ linkage_name_copy = alloc_name;
+ }
+ else
+ {
+ lookup_len = len;
+ lookup_name = linkage_name;
+ linkage_name_copy = linkage_name;
+ }
+
+ slot = (char **) htab_find_slot (objfile->demangled_names_hash,
+ lookup_name, INSERT);
+
+ /* If this name is not in the hash table, add it. */
+ if (*slot == NULL)
+ {
+ char *demangled_name = symbol_find_demangled_name (gsymbol,
+ linkage_name_copy);
+ int demangled_len = demangled_name ? strlen (demangled_name) : 0;
+
+ /* If there is a demangled name, place it right after the mangled name.
+ Otherwise, just place a second zero byte after the end of the mangled
+ name. */
+ *slot = obstack_alloc (&objfile->objfile_obstack,
+ lookup_len + demangled_len + 2);
+ memcpy (*slot, lookup_name, lookup_len + 1);
+ if (demangled_name != NULL)
+ {
+ memcpy (*slot + lookup_len + 1, demangled_name, demangled_len + 1);
+ xfree (demangled_name);
+ }
+ else
+ (*slot)[lookup_len + 1] = '\0';
+ }
+
+ gsymbol->name = *slot + lookup_len - len;
+ if ((*slot)[lookup_len + 1] != '\0')
+ gsymbol->language_specific.cplus_specific.demangled_name
+ = &(*slot)[lookup_len + 1];
+ else
+ gsymbol->language_specific.cplus_specific.demangled_name = NULL;
+}
+
+/* Initialize the demangled name of GSYMBOL if possible. Any required space
+ to store the name is obtained from the specified obstack. The function
+ symbol_set_names, above, should be used instead where possible for more
+ efficient memory usage. */
+
+void
+symbol_init_demangled_name (struct general_symbol_info *gsymbol,
+ struct obstack *obstack)
+{
+ char *mangled = gsymbol->name;
+ char *demangled = NULL;
+
+ demangled = symbol_find_demangled_name (gsymbol, mangled);
+ if (gsymbol->language == language_cplus
+ || gsymbol->language == language_java
+ || gsymbol->language == language_objc)
+ {
+ if (demangled)
+ {
+ gsymbol->language_specific.cplus_specific.demangled_name
+ = obsavestring (demangled, strlen (demangled), obstack);
+ xfree (demangled);
+ }
+ else
+ gsymbol->language_specific.cplus_specific.demangled_name = NULL;
+ }
+ else
+ {
+ /* Unknown language; just clean up quietly. */
+ if (demangled)
+ xfree (demangled);
+ }
+}
+
+/* Return the source code name of a symbol. In languages where
+ demangling is necessary, this is the demangled name. */
+
+char *
+symbol_natural_name (const struct general_symbol_info *gsymbol)
+{
+ if ((gsymbol->language == language_cplus
+ || gsymbol->language == language_java
+ || gsymbol->language == language_objc)
+ && (gsymbol->language_specific.cplus_specific.demangled_name != NULL))
+ {
+ return gsymbol->language_specific.cplus_specific.demangled_name;
+ }
+ else
+ {
+ return gsymbol->name;
+ }
+}
+
+/* Return the demangled name for a symbol based on the language for
+ that symbol. If no demangled name exists, return NULL. */
+char *
+symbol_demangled_name (struct general_symbol_info *gsymbol)
+{
+ if (gsymbol->language == language_cplus
+ || gsymbol->language == language_java
+ || gsymbol->language == language_objc)
+ return gsymbol->language_specific.cplus_specific.demangled_name;
+
+ else
+ return NULL;
+}
+
+/* Initialize the structure fields to zero values. */
+void
+init_sal (struct symtab_and_line *sal)
+{
+ sal->symtab = 0;
+ sal->section = 0;
+ sal->line = 0;
+ sal->pc = 0;
+ sal->end = 0;
+}
+
+
+
+/* Find which partial symtab contains PC and SECTION. Return 0 if
+ none. We return the psymtab that contains a symbol whose address
+ exactly matches PC, or, if we cannot find an exact match, the
+ psymtab that contains a symbol whose address is closest to PC. */
+struct partial_symtab *
+find_pc_sect_psymtab (CORE_ADDR pc, asection *section)
+{
+ struct partial_symtab *pst;
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+
+ /* If we know that this is not a text address, return failure. This is
+ necessary because we loop based on texthigh and textlow, which do
+ not include the data ranges. */
+ msymbol = lookup_minimal_symbol_by_pc_section (pc, section);
+ if (msymbol
+ && (msymbol->type == mst_data
+ || msymbol->type == mst_bss
+ || msymbol->type == mst_abs
+ || msymbol->type == mst_file_data
+ || msymbol->type == mst_file_bss))
+ return NULL;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (pc >= pst->textlow && pc < pst->texthigh)
+ {
+ struct partial_symtab *tpst;
+ struct partial_symtab *best_pst = pst;
+ struct partial_symbol *best_psym = NULL;
+
+ /* 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) &&
+ section == 0) /* can't validate section this way */
+ return (pst);
+
+ if (msymbol == NULL)
+ return (pst);
+
+ /* The code range of partial symtabs sometimes overlap, so, in
+ the loop below, we need to check all partial symtabs and
+ find the one that fits better for the given PC address. We
+ select the partial symtab that contains a symbol whose
+ address is closest to the PC address. By closest we mean
+ that find_pc_sect_symbol returns the symbol with address
+ that is closest and still less than the given PC. */
+ for (tpst = pst; tpst != NULL; tpst = tpst->next)
+ {
+ if (pc >= tpst->textlow && pc < tpst->texthigh)
+ {
+ struct partial_symbol *p;
+
+ p = find_pc_sect_psymbol (tpst, pc, section);
+ if (p != NULL
+ && SYMBOL_VALUE_ADDRESS (p)
+ == SYMBOL_VALUE_ADDRESS (msymbol))
+ return (tpst);
+ if (p != NULL)
+ {
+ /* We found a symbol in this partial symtab which
+ matches (or is closest to) PC, check whether it
+ is closer than our current BEST_PSYM. Since
+ this symbol address is necessarily lower or
+ equal to PC, the symbol closer to PC is the
+ symbol which address is the highest. */
+ /* This way we return the psymtab which contains
+ such best match symbol. This can help in cases
+ where the symbol information/debuginfo is not
+ complete, like for instance on IRIX6 with gcc,
+ where no debug info is emitted for
+ statics. (See also the nodebug.exp
+ testcase.) */
+ if (best_psym == NULL
+ || SYMBOL_VALUE_ADDRESS (p)
+ > SYMBOL_VALUE_ADDRESS (best_psym))
+ {
+ best_psym = p;
+ best_pst = tpst;
+ }
+ }
+
+ }
+ }
+ return (best_pst);
+ }
+ }
+ return (NULL);
+}
+
+/* Find which partial symtab contains PC. Return 0 if none.
+ Backward compatibility, no section */
+
+struct partial_symtab *
+find_pc_psymtab (CORE_ADDR pc)
+{
+ return find_pc_sect_psymtab (pc, find_pc_mapped_section (pc));
+}
+
+/* Find which partial symbol within a psymtab matches PC and SECTION.
+ Return 0 if none. Check all psymtabs if PSYMTAB is 0. */
+
+struct partial_symbol *
+find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc,
+ asection *section)
+{
+ struct partial_symbol *best = NULL, *p, **pp;
+ CORE_ADDR best_pc;
+
+ if (!psymtab)
+ psymtab = find_pc_sect_psymtab (pc, section);
+ if (!psymtab)
+ return 0;
+
+ /* Cope with programs that start at address 0 */
+ best_pc = (psymtab->textlow != 0) ? psymtab->textlow - 1 : 0;
+
+ /* 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_DOMAIN (p) == VAR_DOMAIN
+ && SYMBOL_CLASS (p) == LOC_BLOCK
+ && pc >= SYMBOL_VALUE_ADDRESS (p)
+ && (SYMBOL_VALUE_ADDRESS (p) > best_pc
+ || (psymtab->textlow == 0
+ && best_pc == 0 && SYMBOL_VALUE_ADDRESS (p) == 0)))
+ {
+ if (section) /* match on a specific section */
+ {
+ fixup_psymbol_section (p, psymtab->objfile);
+ if (SYMBOL_BFD_SECTION (p) != section)
+ continue;
+ }
+ 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_DOMAIN (p) == VAR_DOMAIN
+ && SYMBOL_CLASS (p) == LOC_BLOCK
+ && pc >= SYMBOL_VALUE_ADDRESS (p)
+ && (SYMBOL_VALUE_ADDRESS (p) > best_pc
+ || (psymtab->textlow == 0
+ && best_pc == 0 && SYMBOL_VALUE_ADDRESS (p) == 0)))
+ {
+ if (section) /* match on a specific section */
+ {
+ fixup_psymbol_section (p, psymtab->objfile);
+ if (SYMBOL_BFD_SECTION (p) != section)
+ continue;
+ }
+ best_pc = SYMBOL_VALUE_ADDRESS (p);
+ best = p;
+ }
+ }
+
+ return best;
+}
+
+/* Find which partial symbol within a psymtab matches PC. Return 0 if none.
+ Check all psymtabs if PSYMTAB is 0. Backwards compatibility, no section. */
+
+struct partial_symbol *
+find_pc_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc)
+{
+ return find_pc_sect_psymbol (psymtab, pc, find_pc_mapped_section (pc));
+}
+
+/* Debug symbols usually don't have section information. We need to dig that
+ out of the minimal symbols and stash that in the debug symbol. */
+
+static void
+fixup_section (struct general_symbol_info *ginfo, struct objfile *objfile)
+{
+ struct minimal_symbol *msym;
+ msym = lookup_minimal_symbol (ginfo->name, NULL, objfile);
+
+ if (msym)
+ {
+ ginfo->bfd_section = SYMBOL_BFD_SECTION (msym);
+ ginfo->section = SYMBOL_SECTION (msym);
+ }
+}
+
+struct symbol *
+fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
+{
+ if (!sym)
+ return NULL;
+
+ if (SYMBOL_BFD_SECTION (sym))
+ return sym;
+
+ fixup_section (&sym->ginfo, objfile);
+
+ return sym;
+}
+
+struct partial_symbol *
+fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile)
+{
+ if (!psym)
+ return NULL;
+
+ if (SYMBOL_BFD_SECTION (psym))
+ return psym;
+
+ fixup_section (&psym->ginfo, objfile);
+
+ return psym;
+}
+
+/* Find the definition for a specified symbol name NAME
+ in domain DOMAIN, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ 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. (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 (const char *name, const struct block *block,
+ const domain_enum domain, int *is_a_field_of_this,
+ struct symtab **symtab)
+{
+ char *demangled_name = NULL;
+ const char *modified_name = NULL;
+ const char *mangled_name = NULL;
+ int needtofreename = 0;
+ struct symbol *returnval;
+
+ modified_name = name;
+
+ /* If we are using C++ language, demangle the name before doing a lookup, so
+ we can always binary search. */
+ if (current_language->la_language == language_cplus)
+ {
+ demangled_name = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name)
+ {
+ mangled_name = name;
+ modified_name = demangled_name;
+ needtofreename = 1;
+ }
+ }
+
+ if (case_sensitivity == case_sensitive_off)
+ {
+ char *copy;
+ int len, i;
+
+ len = strlen (name);
+ copy = (char *) alloca (len + 1);
+ for (i= 0; i < len; i++)
+ copy[i] = tolower (name[i]);
+ copy[len] = 0;
+ modified_name = copy;
+ }
+
+ returnval = lookup_symbol_aux (modified_name, mangled_name, block,
+ domain, is_a_field_of_this, symtab);
+ if (needtofreename)
+ xfree (demangled_name);
+
+ return returnval;
+}
+
+/* Behave like lookup_symbol_aux except that NAME is the natural name
+ of the symbol that we're looking for and, if LINKAGE_NAME is
+ non-NULL, ensure that the symbol's linkage name matches as
+ well. */
+
+static struct symbol *
+lookup_symbol_aux (const char *name, const char *linkage_name,
+ const struct block *block, const domain_enum domain,
+ int *is_a_field_of_this, struct symtab **symtab)
+{
+ struct symbol *sym;
+
+ /* Make sure we do something sensible with is_a_field_of_this, since
+ the callers that set this parameter to some non-null value will
+ certainly use it later and expect it to be either 0 or 1.
+ If we don't set it, the contents of is_a_field_of_this are
+ undefined. */
+ if (is_a_field_of_this != NULL)
+ *is_a_field_of_this = 0;
+
+ /* Search specified block and its superiors. Don't search
+ STATIC_BLOCK or GLOBAL_BLOCK. */
+
+ sym = lookup_symbol_aux_local (name, linkage_name, block, domain,
+ symtab);
+ if (sym != NULL)
+ return sym;
+
+ /* If requested to do so by the caller and if appropriate for the
+ current language, check to see if NAME is a field of `this'. */
+
+ if (current_language->la_value_of_this != NULL
+ && is_a_field_of_this != NULL)
+ {
+ struct value *v = current_language->la_value_of_this (0);
+
+ if (v && check_field (v, name))
+ {
+ *is_a_field_of_this = 1;
+ if (symtab != NULL)
+ *symtab = NULL;
+ return NULL;
+ }
+ }
+
+ /* Now do whatever is appropriate for the current language to look
+ up static and global variables. */
+
+ sym = current_language->la_lookup_symbol_nonlocal (name, linkage_name,
+ block, domain,
+ symtab);
+ if (sym != NULL)
+ return sym;
+
+ /* Now search all static file-level symbols. Not strictly correct,
+ but more useful than an error. Do the symtabs first, then check
+ the psymtabs. If a psymtab indicates the existence of the
+ desired name as a file-level static, then do psymtab-to-symtab
+ conversion on the fly and return the found symbol. */
+
+ sym = lookup_symbol_aux_symtabs (STATIC_BLOCK, name, linkage_name,
+ domain, symtab);
+ if (sym != NULL)
+ return sym;
+
+ sym = lookup_symbol_aux_psymtabs (STATIC_BLOCK, name, linkage_name,
+ domain, symtab);
+ if (sym != NULL)
+ return sym;
+
+ if (symtab != NULL)
+ *symtab = NULL;
+ return NULL;
+}
+
+/* Check to see if the symbol is defined in BLOCK or its superiors.
+ Don't search STATIC_BLOCK or GLOBAL_BLOCK. */
+
+static struct symbol *
+lookup_symbol_aux_local (const char *name, const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ struct symbol *sym;
+ const struct block *static_block = block_static_block (block);
+
+ /* Check if either no block is specified or it's a global block. */
+
+ if (static_block == NULL)
+ return NULL;
+
+ while (block != static_block)
+ {
+ sym = lookup_symbol_aux_block (name, linkage_name, block, domain,
+ symtab);
+ if (sym != NULL)
+ return sym;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* We've reached the static block without finding a result. */
+
+ return NULL;
+}
+
+/* Look up a symbol in a block; if found, locate its symtab, fixup the
+ symbol, and set block_found appropriately. */
+
+struct symbol *
+lookup_symbol_aux_block (const char *name, const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ struct symbol *sym;
+ struct objfile *objfile = NULL;
+ struct blockvector *bv;
+ struct block *b;
+ struct symtab *s = NULL;
+
+ sym = lookup_block_symbol (block, name, linkage_name, domain);
+ 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 fixup_symbol_section (sym, objfile);
+ }
+
+ return NULL;
+}
+
+/* Check to see if the symbol is defined in one of the symtabs.
+ BLOCK_INDEX should be either GLOBAL_BLOCK or STATIC_BLOCK,
+ depending on whether or not we want to search global symbols or
+ static symbols. */
+
+static struct symbol *
+lookup_symbol_aux_symtabs (int block_index,
+ const char *name, const char *linkage_name,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ struct symbol *sym;
+ struct objfile *objfile;
+ struct blockvector *bv;
+ const struct block *block;
+ struct symtab *s;
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, block_index);
+ sym = lookup_block_symbol (block, name, linkage_name, domain);
+ if (sym)
+ {
+ block_found = block;
+ if (symtab != NULL)
+ *symtab = s;
+ return fixup_symbol_section (sym, objfile);
+ }
+ }
+
+ return NULL;
+}
+
+/* Check to see if the symbol is defined in one of the partial
+ symtabs. BLOCK_INDEX should be either GLOBAL_BLOCK or
+ STATIC_BLOCK, depending on whether or not we want to search global
+ symbols or static symbols. */
+
+static struct symbol *
+lookup_symbol_aux_psymtabs (int block_index, const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ struct symbol *sym;
+ struct objfile *objfile;
+ struct blockvector *bv;
+ const struct block *block;
+ struct partial_symtab *ps;
+ struct symtab *s;
+ const int psymtab_index = (block_index == GLOBAL_BLOCK ? 1 : 0);
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin
+ && lookup_partial_symbol (ps, name, linkage_name,
+ psymtab_index, domain))
+ {
+ s = PSYMTAB_TO_SYMTAB (ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, block_index);
+ sym = lookup_block_symbol (block, name, linkage_name, domain);
+ if (!sym)
+ {
+ /* This shouldn't be necessary, but as a last resort try
+ looking in the statics even though the psymtab claimed
+ the symbol was global, or vice-versa. It's possible
+ that the psymtab gets it wrong in some cases. */
+
+ /* FIXME: carlton/2002-09-30: Should we really do that?
+ If that happens, isn't it likely to be a GDB error, in
+ which case we should fix the GDB error rather than
+ silently dealing with it here? So I'd vote for
+ removing the check for the symbol in the other
+ block. */
+ block = BLOCKVECTOR_BLOCK (bv,
+ block_index == GLOBAL_BLOCK ?
+ STATIC_BLOCK : GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, linkage_name, domain);
+ if (!sym)
+ error ("Internal: %s symbol `%s' found in %s psymtab but not in symtab.\n%s may be an inlined function, or may be a template function\n(if a template, try specifying an instantiation: %s<type>).",
+ block_index == GLOBAL_BLOCK ? "global" : "static",
+ name, ps->filename, name, name);
+ }
+ if (symtab != NULL)
+ *symtab = s;
+ return fixup_symbol_section (sym, objfile);
+ }
+ }
+
+ return NULL;
+}
+
+#if 0
+/* 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. */
+
+/* NOTE: carlton/2002-12-05: At one point, this function was part of
+ lookup_symbol_aux, and what are now 'return' statements within
+ lookup_symbol_aux_minsyms returned from lookup_symbol_aux, even if
+ sym was NULL. As far as I can tell, this was basically accidental;
+ it didn't happen every time that msymbol was non-NULL, but only if
+ some additional conditions held as well, and it caused problems
+ with HP-generated symbol tables. */
+
+/* NOTE: carlton/2003-05-14: This function was once used as part of
+ lookup_symbol. It is currently unnecessary for correctness
+ reasons, however, and using it doesn't seem to be any faster than
+ using lookup_symbol_aux_psymtabs, so I'm commenting it out. */
+
+static struct symbol *
+lookup_symbol_aux_minsyms (const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ int *is_a_field_of_this,
+ struct symtab **symtab)
+{
+ struct symbol *sym;
+ struct blockvector *bv;
+ const struct block *block;
+ struct minimal_symbol *msymbol;
+ struct symtab *s;
+
+ if (domain == VAR_DOMAIN)
+ {
+ msymbol = lookup_minimal_symbol (name, NULL, NULL);
+
+ if (msymbol != NULL)
+ {
+ /* OK, we found a minimal symbol in spite of not finding any
+ symbol. There are various possible explanations for
+ this. One possibility is the symbol exists in code not
+ compiled -g. Another possibility is that the 'psymtab'
+ isn't doing its job. A third possibility, related to #2,
+ is that we were confused by name-mangling. For instance,
+ maybe the psymtab isn't doing its job because it only
+ know about demangled names, but we were given a mangled
+ name... */
+
+ /* We first use the address in the msymbol to try to locate
+ the appropriate symtab. Note that find_pc_sect_symtab()
+ has a side-effect of doing psymtab-to-symtab expansion,
+ for the found symtab. */
+ s = find_pc_sect_symtab (SYMBOL_VALUE_ADDRESS (msymbol),
+ SYMBOL_BFD_SECTION (msymbol));
+ if (s != NULL)
+ {
+ /* This is a function which has a symtab for its address. */
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+
+ /* This call used to pass `SYMBOL_LINKAGE_NAME (msymbol)' as the
+ `name' argument to lookup_block_symbol. But the name
+ of a minimal symbol is always mangled, so that seems
+ to be clearly the wrong thing to pass as the
+ unmangled name. */
+ sym =
+ lookup_block_symbol (block, name, linkage_name, domain);
+ /* 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, name,
+ linkage_name, domain);
+ }
+
+ /* NOTE: carlton/2002-12-04: The following comment was
+ taken from a time when two versions of this function
+ were part of the body of lookup_symbol_aux: this
+ comment was taken from the version of the function
+ that was #ifdef HPUXHPPA, and the comment was right
+ before the 'return NULL' part of lookup_symbol_aux.
+ (Hence the "Fall through and return 0" comment.)
+ Elena did some digging into the situation for
+ Fortran, and she reports:
+
+ "I asked around (thanks to Jeff Knaggs), and I think
+ the story for Fortran goes like this:
+
+ "Apparently, in older Fortrans, '_' was not part of
+ the user namespace. g77 attached a final '_' to
+ procedure names as the exported symbols for linkage
+ (foo_) , but the symbols went in the debug info just
+ like 'foo'. The rationale behind this is not
+ completely clear, and maybe it was done to other
+ symbols as well, not just procedures." */
+
+ /* If we get here with sym == 0, the symbol was
+ found in the minimal symbol table
+ but not in the symtab.
+ Fall through and return 0 to use the msymbol
+ definition of "foo_".
+ (Note that outer code generally follows up a call
+ to this routine with a call to lookup_minimal_symbol(),
+ so a 0 return means we'll just flow into that other routine).
+
+ 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 && sym != NULL)
+ *symtab = s;
+ return fixup_symbol_section (sym, s->objfile);
+ }
+ }
+ }
+
+ return NULL;
+}
+#endif /* 0 */
+
+/* A default version of lookup_symbol_nonlocal for use by languages
+ that can't think of anything better to do. This implements the C
+ lookup rules. */
+
+struct symbol *
+basic_lookup_symbol_nonlocal (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ struct symbol *sym;
+
+ /* NOTE: carlton/2003-05-19: The comments below were written when
+ this (or what turned into this) was part of lookup_symbol_aux;
+ I'm much less worried about these questions now, since these
+ decisions have turned out well, but I leave these comments here
+ for posterity. */
+
+ /* NOTE: carlton/2002-12-05: There is a question as to whether or
+ not it would be appropriate to search the current global block
+ here as well. (That's what this code used to do before the
+ is_a_field_of_this check was moved up.) On the one hand, it's
+ redundant with the lookup_symbol_aux_symtabs search that happens
+ next. On the other hand, if decode_line_1 is passed an argument
+ like filename:var, then the user presumably wants 'var' to be
+ searched for in filename. On the third hand, there shouldn't be
+ multiple global variables all of which are named 'var', and it's
+ not like decode_line_1 has ever restricted its search to only
+ global variables in a single filename. All in all, only
+ searching the static block here seems best: it's correct and it's
+ cleanest. */
+
+ /* NOTE: carlton/2002-12-05: There's also a possible performance
+ issue here: if you usually search for global symbols in the
+ current file, then it would be slightly better to search the
+ current global block before searching all the symtabs. But there
+ are other factors that have a much greater effect on performance
+ than that one, so I don't think we should worry about that for
+ now. */
+
+ sym = lookup_symbol_static (name, linkage_name, block, domain, symtab);
+ if (sym != NULL)
+ return sym;
+
+ return lookup_symbol_global (name, linkage_name, domain, symtab);
+}
+
+/* Lookup a symbol in the static block associated to BLOCK, if there
+ is one; do nothing if BLOCK is NULL or a global block. */
+
+struct symbol *
+lookup_symbol_static (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ const struct block *static_block = block_static_block (block);
+
+ if (static_block != NULL)
+ return lookup_symbol_aux_block (name, linkage_name, static_block,
+ domain, symtab);
+ else
+ return NULL;
+}
+
+/* Lookup a symbol in all files' global blocks (searching psymtabs if
+ necessary). */
+
+struct symbol *
+lookup_symbol_global (const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ struct symtab **symtab)
+{
+ struct symbol *sym;
+
+ sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, linkage_name,
+ domain, symtab);
+ if (sym != NULL)
+ return sym;
+
+ return lookup_symbol_aux_psymtabs (GLOBAL_BLOCK, name, linkage_name,
+ domain, symtab);
+}
+
+/* Look, in partial_symtab PST, for symbol whose natural name is NAME.
+ If LINKAGE_NAME is non-NULL, check in addition that the symbol's
+ linkage name matches it. Check the global symbols if GLOBAL, the
+ static symbols if not */
+
+struct partial_symbol *
+lookup_partial_symbol (struct partial_symtab *pst, const char *name,
+ const char *linkage_name, int global,
+ domain_enum domain)
+{
+ struct partial_symbol *temp;
+ struct partial_symbol **start, **psym;
+ struct partial_symbol **top, **real_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 whose name might be
+ correct. At that point *all* partial symbols with an
+ appropriate name will be checked against the correct
+ domain. */
+
+ bottom = start;
+ top = start + length - 1;
+ real_top = top;
+ while (top > bottom)
+ {
+ center = bottom + (top - bottom) / 2;
+ if (!(center < top))
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ if (!do_linear_search
+ && (SYMBOL_LANGUAGE (*center) == language_java))
+ {
+ do_linear_search = 1;
+ }
+ if (strcmp_iw_ordered (SYMBOL_NATURAL_NAME (*center), name) >= 0)
+ {
+ top = center;
+ }
+ else
+ {
+ bottom = center + 1;
+ }
+ }
+ if (!(top == bottom))
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ while (top <= real_top
+ && (linkage_name != NULL
+ ? strcmp (SYMBOL_LINKAGE_NAME (*top), linkage_name) == 0
+ : SYMBOL_MATCHES_NATURAL_NAME (*top,name)))
+ {
+ if (SYMBOL_DOMAIN (*top) == domain)
+ {
+ 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 (domain == SYMBOL_DOMAIN (*psym))
+ {
+ if (linkage_name != NULL
+ ? strcmp (SYMBOL_LINKAGE_NAME (*psym), linkage_name) == 0
+ : SYMBOL_MATCHES_NATURAL_NAME (*psym, name))
+ {
+ return (*psym);
+ }
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/* Look up a type named NAME in the struct_domain. The type returned
+ must not be opaque -- i.e., must have at least one field
+ defined. */
+
+struct type *
+lookup_transparent_type (const char *name)
+{
+ return current_language->la_lookup_transparent_type (name);
+}
+
+/* The standard implementation of lookup_transparent_type. This code
+ was modeled on lookup_symbol -- the parts not relevant to looking
+ up types were just left out. In particular it's assumed here that
+ types are available in struct_domain and only at file-static or
+ global blocks. */
+
+struct type *
+basic_lookup_transparent_type (const char *name)
+{
+ struct symbol *sym;
+ struct symtab *s = NULL;
+ struct partial_symtab *ps;
+ struct blockvector *bv;
+ struct objfile *objfile;
+ struct block *block;
+
+ /* Now search all the global symbols. Do the symtab's first, then
+ check the psymtab's. If a psymtab indicates the existence
+ of the desired name as a global, then do psymtab-to-symtab
+ conversion on the fly and return the found symbol. */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN);
+ if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
+ {
+ return SYMBOL_TYPE (sym);
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, NULL,
+ 1, STRUCT_DOMAIN))
+ {
+ s = PSYMTAB_TO_SYMTAB (ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN);
+ if (!sym)
+ {
+ /* This shouldn't be necessary, but as a last resort
+ * try looking in the statics even though the psymtab
+ * claimed the symbol was global. It's possible that
+ * the psymtab gets it wrong in some cases.
+ */
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN);
+ if (!sym)
+ error ("Internal: global symbol `%s' found in %s psymtab but not in symtab.\n\
+%s may be an inlined function, or may be a template function\n\
+(if a template, try specifying an instantiation: %s<type>).",
+ name, ps->filename, name, name);
+ }
+ if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
+ return SYMBOL_TYPE (sym);
+ }
+ }
+
+ /* Now search the static file-level symbols.
+ Not strictly correct, but more useful than an error.
+ Do the symtab's first, then
+ check the psymtab's. If a psymtab indicates the existence
+ of the desired name as a file-level static, then do psymtab-to-symtab
+ conversion on the fly and return the found symbol.
+ */
+
+ ALL_SYMTABS (objfile, s)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN);
+ if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
+ {
+ return SYMBOL_TYPE (sym);
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (!ps->readin && lookup_partial_symbol (ps, name, NULL, 0, STRUCT_DOMAIN))
+ {
+ s = PSYMTAB_TO_SYMTAB (ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN);
+ if (!sym)
+ {
+ /* This shouldn't be necessary, but as a last resort
+ * try looking in the globals even though the psymtab
+ * claimed the symbol was static. It's possible that
+ * the psymtab gets it wrong in some cases.
+ */
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN);
+ if (!sym)
+ error ("Internal: static symbol `%s' found in %s psymtab but not in symtab.\n\
+%s may be an inlined function, or may be a template function\n\
+(if a template, try specifying an instantiation: %s<type>).",
+ name, ps->filename, name, name);
+ }
+ if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
+ return SYMBOL_TYPE (sym);
+ }
+ }
+ return (struct type *) 0;
+}
+
+
+/* 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 (void)
+{
+ struct partial_symtab *pst;
+ struct objfile *objfile;
+
+ ALL_PSYMTABS (objfile, pst)
+ {
+ if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN))
+ {
+ return (pst);
+ }
+ }
+ return (NULL);
+}
+
+/* Search BLOCK for symbol NAME in DOMAIN.
+
+ 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 ObjC/C++
+ symbol (language_cplus or language_objc set) has both the encoded and
+ non-encoded names tested for a match.
+
+ If LINKAGE_NAME is non-NULL, verify that any symbol we find has this
+ particular mangled name.
+*/
+
+struct symbol *
+lookup_block_symbol (const struct block *block, const char *name,
+ const char *linkage_name,
+ const domain_enum domain)
+{
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ if (!BLOCK_FUNCTION (block))
+ {
+ for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter);
+ sym != NULL;
+ sym = dict_iter_name_next (name, &iter))
+ {
+ if (SYMBOL_DOMAIN (sym) == domain
+ && (linkage_name != NULL
+ ? strcmp (SYMBOL_LINKAGE_NAME (sym), linkage_name) == 0 : 1))
+ return sym;
+ }
+ return NULL;
+ }
+ else
+ {
+ /* 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. */
+
+ struct symbol *sym_found = NULL;
+
+ for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter);
+ sym != NULL;
+ sym = dict_iter_name_next (name, &iter))
+ {
+ if (SYMBOL_DOMAIN (sym) == domain
+ && (linkage_name != NULL
+ ? strcmp (SYMBOL_LINKAGE_NAME (sym), linkage_name) == 0 : 1))
+ {
+ 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 &&
+ SYMBOL_CLASS (sym) != LOC_COMPUTED_ARG)
+ {
+ break;
+ }
+ }
+ }
+ return (sym_found); /* Will be NULL if not found. */
+ }
+}
+
+/* Find the symtab associated with PC and SECTION. Look through the
+ psymtabs and read in another symtab if necessary. */
+
+struct symtab *
+find_pc_sect_symtab (CORE_ADDR pc, asection *section)
+{
+ struct block *b;
+ struct blockvector *bv;
+ struct symtab *s = NULL;
+ struct symtab *best_s = NULL;
+ struct partial_symtab *ps;
+ struct objfile *objfile;
+ CORE_ADDR distance = 0;
+ struct minimal_symbol *msymbol;
+
+ /* If we know that this is not a text address, return failure. This is
+ necessary because we loop based on the block's high and low code
+ addresses, which do not include the data ranges, and because
+ we call find_pc_sect_psymtab which has a similar restriction based
+ on the partial_symtab's texthigh and textlow. */
+ msymbol = lookup_minimal_symbol_by_pc_section (pc, section);
+ if (msymbol
+ && (msymbol->type == mst_data
+ || msymbol->type == mst_bss
+ || msymbol->type == mst_abs
+ || msymbol->type == mst_file_data
+ || msymbol->type == mst_file_bss))
+ return NULL;
+
+ /* 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. */
+ /* In order to better support objfiles that contain both
+ stabs and coff debugging info, we continue on if a psymtab
+ can't be found. */
+ if ((objfile->flags & OBJF_REORDERED) && objfile->psymtabs)
+ {
+ ps = find_pc_sect_psymtab (pc, section);
+ if (ps)
+ return PSYMTAB_TO_SYMTAB (ps);
+ }
+ if (section != 0)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym = NULL;
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ fixup_symbol_section (sym, objfile);
+ if (section == SYMBOL_BFD_SECTION (sym))
+ break;
+ }
+ if (sym == NULL)
+ continue; /* no symbol in this symtab matches section */
+ }
+ distance = BLOCK_END (b) - BLOCK_START (b);
+ best_s = s;
+ }
+ }
+
+ if (best_s != NULL)
+ return (best_s);
+
+ s = NULL;
+ ps = find_pc_sect_psymtab (pc, section);
+ 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. */
+ warning ("\
+(Internal error: pc 0x%s in read in psymtab, but not in symtab.)\n",
+ paddr_nz (pc));
+ s = PSYMTAB_TO_SYMTAB (ps);
+ }
+ return (s);
+}
+
+/* Find the symtab associated with PC. Look through the psymtabs and
+ read in another symtab if necessary. Backward compatibility, no section */
+
+struct symtab *
+find_pc_symtab (CORE_ADDR pc)
+{
+ return find_pc_sect_symtab (pc, find_pc_mapped_section (pc));
+}
+
+
+/* Find the source file and line number for a given PC value and SECTION.
+ 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_sect_line (CORE_ADDR pc, struct bfd_section *section, int notcurrent)
+{
+ struct symtab *s;
+ struct linetable *l;
+ int len;
+ int i;
+ struct linetable_entry *item;
+ struct symtab_and_line val;
+ struct blockvector *bv;
+ struct minimal_symbol *msymbol;
+ struct minimal_symbol *mfunsym;
+
+ /* 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. */
+
+ init_sal (&val); /* initialize to zeroes */
+
+ /* It's tempting to assume that, if we can't find debugging info for
+ any function enclosing PC, that we shouldn't search for line
+ number info, either. However, GAS can emit line number info for
+ assembly files --- very helpful when debugging hand-written
+ assembly code. In such a case, we'd have no debug info for the
+ function, but we would have line info. */
+
+ if (notcurrent)
+ pc -= 1;
+
+ /* elz: added this because this function returned the wrong
+ information if the pc belongs to a stub (import/export)
+ to call a shlib function. This stub would be anywhere between
+ two functions in the target, and the line info was erroneously
+ taken to be the one of the line before the pc.
+ */
+ /* RT: Further explanation:
+
+ * We have stubs (trampolines) inserted between procedures.
+ *
+ * Example: "shr1" exists in a shared library, and a "shr1" stub also
+ * exists in the main image.
+ *
+ * In the minimal symbol table, we have a bunch of symbols
+ * sorted by start address. The stubs are marked as "trampoline",
+ * the others appear as text. E.g.:
+ *
+ * Minimal symbol table for main image
+ * main: code for main (text symbol)
+ * shr1: stub (trampoline symbol)
+ * foo: code for foo (text symbol)
+ * ...
+ * Minimal symbol table for "shr1" image:
+ * ...
+ * shr1: code for shr1 (text symbol)
+ * ...
+ *
+ * So the code below is trying to detect if we are in the stub
+ * ("shr1" stub), and if so, find the real code ("shr1" trampoline),
+ * and if found, do the symbolization from the real-code address
+ * rather than the stub address.
+ *
+ * Assumptions being made about the minimal symbol table:
+ * 1. lookup_minimal_symbol_by_pc() will return a trampoline only
+ * if we're really in the trampoline. If we're beyond it (say
+ * we're in "foo" in the above example), it'll have a closer
+ * symbol (the "foo" text symbol for example) and will not
+ * return the trampoline.
+ * 2. lookup_minimal_symbol_text() will find a real text symbol
+ * corresponding to the trampoline, and whose address will
+ * be different than the trampoline address. I put in a sanity
+ * check for the address being the same, to avoid an
+ * infinite recursion.
+ */
+ msymbol = lookup_minimal_symbol_by_pc (pc);
+ if (msymbol != NULL)
+ if (MSYMBOL_TYPE (msymbol) == mst_solib_trampoline)
+ {
+ mfunsym = lookup_minimal_symbol_text (SYMBOL_LINKAGE_NAME (msymbol),
+ NULL);
+ if (mfunsym == NULL)
+ /* I eliminated this warning since it is coming out
+ * in the following situation:
+ * gdb shmain // test program with shared libraries
+ * (gdb) break shr1 // function in shared lib
+ * Warning: In stub for ...
+ * In the above situation, the shared lib is not loaded yet,
+ * so of course we can't find the real func/line info,
+ * but the "break" still works, and the warning is annoying.
+ * So I commented out the warning. RT */
+ /* warning ("In stub for %s; unable to find real function/line info", SYMBOL_LINKAGE_NAME (msymbol)) */ ;
+ /* fall through */
+ else if (SYMBOL_VALUE (mfunsym) == SYMBOL_VALUE (msymbol))
+ /* Avoid infinite recursion */
+ /* See above comment about why warning is commented out */
+ /* warning ("In stub for %s; unable to find real function/line info", SYMBOL_LINKAGE_NAME (msymbol)) */ ;
+ /* fall through */
+ else
+ return find_pc_line (SYMBOL_VALUE (mfunsym), 0);
+ }
+
+
+ s = find_pc_sect_symtab (pc, section);
+ if (!s)
+ {
+ /* if no symbol information, return previous pc */
+ if (notcurrent)
+ pc++;
+ val.pc = pc;
+ 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++)
+ {
+ /* Leave prev pointing to the linetable entry for the last line
+ that started at or before 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. Don't
+ save prev if it represents the end of a function (i.e. line number
+ 0) instead of a real line. */
+
+ if (prev && prev->line && (!best || prev->pc > best->pc))
+ {
+ best = prev;
+ best_symtab = s;
+
+ /* Discard BEST_END if it's before the PC of the current BEST. */
+ if (best_end <= best->pc)
+ best_end = 0;
+ }
+
+ /* If another line (denoted by ITEM) is in the linetable and its
+ PC is after BEST's PC, but before the current BEST_END, then
+ use ITEM's PC as the new best_end. */
+ if (best && i < len && item->pc > best->pc
+ && (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.pc = pc;
+ }
+ 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 if (best->line == 0)
+ {
+ /* If our best fit is in a range of PC's for which no line
+ number info is available (line number is zero) then we didn't
+ find any valid line information. */
+ val.pc = 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));
+ }
+ val.section = section;
+ return val;
+}
+
+/* Backward compatibility (no section) */
+
+struct symtab_and_line
+find_pc_line (CORE_ADDR pc, int notcurrent)
+{
+ asection *section;
+
+ section = find_pc_overlay (pc);
+ if (pc_in_unmapped_range (pc, section))
+ pc = overlay_mapped_address (pc, section);
+ return find_pc_sect_line (pc, section, notcurrent);
+}
+
+/* Find line number LINE in any symtab whose name is the same as
+ SYMTAB.
+
+ If found, return the symtab that contains 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 NULL. */
+
+struct symtab *
+find_line_symtab (struct symtab *symtab, int line, 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;
+ struct symtab *best_symtab;
+
+ /* First try looking it up in the given symtab. */
+ best_linetable = LINETABLE (symtab);
+ best_symtab = 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 (strcmp (symtab->filename, s->filename) != 0)
+ continue;
+ l = LINETABLE (s);
+ ind = find_line_common (l, line, &exact);
+ if (ind >= 0)
+ {
+ if (exact)
+ {
+ best_index = ind;
+ best_linetable = l;
+ best_symtab = s;
+ goto done;
+ }
+ if (best == 0 || l->item[ind].line < best)
+ {
+ best = l->item[ind].line;
+ best_index = ind;
+ best_linetable = l;
+ best_symtab = s;
+ }
+ }
+ }
+ }
+done:
+ if (best_index < 0)
+ return NULL;
+
+ if (index)
+ *index = best_index;
+ if (exact_match)
+ *exact_match = exact;
+
+ return best_symtab;
+}
+
+/* Set the PC value for a given source file and line number and return true.
+ Returns zero for invalid line number (and sets the PC to 0).
+ The source file is specified with a struct symtab. */
+
+int
+find_line_pc (struct symtab *symtab, int line, CORE_ADDR *pc)
+{
+ struct linetable *l;
+ int ind;
+
+ *pc = 0;
+ if (symtab == 0)
+ return 0;
+
+ symtab = find_line_symtab (symtab, line, &ind, NULL);
+ if (symtab != NULL)
+ {
+ l = LINETABLE (symtab);
+ *pc = l->item[ind].pc;
+ return 1;
+ }
+ 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 (struct symtab_and_line sal, CORE_ADDR *startptr,
+ CORE_ADDR *endptr)
+{
+ CORE_ADDR startaddr;
+ struct symtab_and_line found_sal;
+
+ startaddr = sal.pc;
+ if (startaddr == 0 && !find_line_pc (sal.symtab, sal.line, &startaddr))
+ 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_sect_line (startaddr, sal.section, 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 (struct linetable *l, int lineno,
+ int *exact_match)
+{
+ int i;
+ 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++)
+ {
+ 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 (CORE_ADDR pc, CORE_ADDR *startptr, CORE_ADDR *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. */
+
+struct symtab_and_line
+find_function_start_sal (struct symbol *sym, int funfirstline)
+{
+ CORE_ADDR pc;
+ struct symtab_and_line sal;
+
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ fixup_symbol_section (sym, NULL);
+ if (funfirstline)
+ { /* skip "first line" of function (which is actually its prologue) */
+ asection *section = SYMBOL_BFD_SECTION (sym);
+ /* If function is in an unmapped overlay, use its unmapped LMA
+ address, so that SKIP_PROLOGUE has something unique to work on */
+ if (section_is_overlay (section) &&
+ !section_is_mapped (section))
+ pc = overlay_unmapped_address (pc, section);
+
+ pc += FUNCTION_START_OFFSET;
+ pc = SKIP_PROLOGUE (pc);
+
+ /* For overlays, map pc back into its mapped VMA range */
+ pc = overlay_mapped_address (pc, section);
+ }
+ sal = find_pc_sect_line (pc, SYMBOL_BFD_SECTION (sym), 0);
+
+ /* 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_sect_line (pc, SYMBOL_BFD_SECTION (sym), 0);
+ }
+ sal.pc = pc;
+
+ 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 "". */
+char *
+operator_chars (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 == '$')
+ {
+ char *q = p + 1;
+ while (isalnum (*q) || *q == '_' || *q == '$')
+ q++;
+ *end = q;
+ return p;
+ }
+
+ while (*p)
+ switch (*p)
+ {
+ case '\\': /* regexp quoting */
+ if (p[1] == '*')
+ {
+ if (p[2] == '=') /* 'operator\*=' */
+ *end = p + 3;
+ else /* 'operator\*' */
+ *end = p + 2;
+ return p;
+ }
+ else if (p[1] == '[')
+ {
+ if (p[2] == ']')
+ error ("mismatched quoting on brackets, try 'operator\\[\\]'");
+ else if (p[2] == '\\' && p[3] == ']')
+ {
+ *end = p + 4; /* 'operator\[\]' */
+ return p;
+ }
+ else
+ error ("nothing is allowed between '[' and ']'");
+ }
+ else
+ {
+ /* Gratuitous qoute: skip it and move on. */
+ p++;
+ continue;
+ }
+ break;
+ 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[0] == '-' && p[1] == '>')
+ {
+ /* Struct pointer member operator 'operator->'. */
+ if (p[2] == '*')
+ {
+ *end = p + 3; /* 'operator->*' */
+ return p;
+ }
+ else if (p[2] == '\\')
+ {
+ *end = p + 4; /* Hopefully 'operator->\*' */
+ return p;
+ }
+ else
+ {
+ *end = p + 2; /* 'operator->' */
+ return p;
+ }
+ }
+ 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;
+}
+
+
+/* If FILE is not already in the table of files, return zero;
+ otherwise return non-zero. Optionally add FILE to the table if ADD
+ is non-zero. If *FIRST is non-zero, forget the old table
+ contents. */
+static int
+filename_seen (const char *file, int add, int *first)
+{
+ /* Table of files seen so far. */
+ static const char **tab = NULL;
+ /* Allocated size of tab in elements.
+ Start with one 256-byte block (when using GNU malloc.c).
+ 24 is the malloc overhead when range checking is in effect. */
+ static int tab_alloc_size = (256 - 24) / sizeof (char *);
+ /* Current size of tab in elements. */
+ static int tab_cur_size;
+ const char **p;
+
+ if (*first)
+ {
+ if (tab == NULL)
+ tab = (const char **) xmalloc (tab_alloc_size * sizeof (*tab));
+ tab_cur_size = 0;
+ }
+
+ /* Is FILE in tab? */
+ for (p = tab; p < tab + tab_cur_size; p++)
+ if (strcmp (*p, file) == 0)
+ return 1;
+
+ /* No; maybe add it to tab. */
+ if (add)
+ {
+ if (tab_cur_size == tab_alloc_size)
+ {
+ tab_alloc_size *= 2;
+ tab = (const char **) xrealloc ((char *) tab,
+ tab_alloc_size * sizeof (*tab));
+ }
+ tab[tab_cur_size++] = file;
+ }
+
+ return 0;
+}
+
+/* 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 (char *name, int *first)
+{
+ /* 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. */
+
+ /* Was NAME already seen? */
+ if (filename_seen (name, 1, first))
+ {
+ /* Yes; don't print it again. */
+ return;
+ }
+ /* No; print it and reset *FIRST. */
+ if (*first)
+ {
+ *first = 0;
+ }
+ else
+ {
+ printf_filtered (", ");
+ }
+
+ wrap_here ("");
+ fputs_filtered (name, gdb_stdout);
+}
+
+static void
+sources_info (char *ignore, int from_tty)
+{
+ struct symtab *s;
+ struct partial_symtab *ps;
+ struct objfile *objfile;
+ int first;
+
+ if (!have_full_symbols () && !have_partial_symbols ())
+ {
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ }
+
+ 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");
+}
+
+static int
+file_matches (char *file, char *files[], int nfiles)
+{
+ int i;
+
+ if (file != NULL && nfiles != 0)
+ {
+ for (i = 0; i < nfiles; i++)
+ {
+ if (strcmp (files[i], lbasename (file)) == 0)
+ return 1;
+ }
+ }
+ else if (nfiles == 0)
+ return 1;
+ return 0;
+}
+
+/* Free any memory associated with a search. */
+void
+free_search_symbols (struct symbol_search *symbols)
+{
+ struct symbol_search *p;
+ struct symbol_search *next;
+
+ for (p = symbols; p != NULL; p = next)
+ {
+ next = p->next;
+ xfree (p);
+ }
+}
+
+static void
+do_free_search_symbols_cleanup (void *symbols)
+{
+ free_search_symbols (symbols);
+}
+
+struct cleanup *
+make_cleanup_free_search_symbols (struct symbol_search *symbols)
+{
+ return make_cleanup (do_free_search_symbols_cleanup, symbols);
+}
+
+/* Helper function for sort_search_symbols and qsort. Can only
+ sort symbols, not minimal symbols. */
+static int
+compare_search_syms (const void *sa, const void *sb)
+{
+ struct symbol_search **sym_a = (struct symbol_search **) sa;
+ struct symbol_search **sym_b = (struct symbol_search **) sb;
+
+ return strcmp (SYMBOL_PRINT_NAME ((*sym_a)->symbol),
+ SYMBOL_PRINT_NAME ((*sym_b)->symbol));
+}
+
+/* Sort the ``nfound'' symbols in the list after prevtail. Leave
+ prevtail where it is, but update its next pointer to point to
+ the first of the sorted symbols. */
+static struct symbol_search *
+sort_search_symbols (struct symbol_search *prevtail, int nfound)
+{
+ struct symbol_search **symbols, *symp, *old_next;
+ int i;
+
+ symbols = (struct symbol_search **) xmalloc (sizeof (struct symbol_search *)
+ * nfound);
+ symp = prevtail->next;
+ for (i = 0; i < nfound; i++)
+ {
+ symbols[i] = symp;
+ symp = symp->next;
+ }
+ /* Generally NULL. */
+ old_next = symp;
+
+ qsort (symbols, nfound, sizeof (struct symbol_search *),
+ compare_search_syms);
+
+ symp = prevtail;
+ for (i = 0; i < nfound; i++)
+ {
+ symp->next = symbols[i];
+ symp = symp->next;
+ }
+ symp->next = old_next;
+
+ xfree (symbols);
+ return symp;
+}
+
+/* Search the symbol table for matches to the regular expression REGEXP,
+ returning the results in *MATCHES.
+
+ Only symbols of KIND are searched:
+ FUNCTIONS_DOMAIN - search all functions
+ TYPES_DOMAIN - search all type names
+ METHODS_DOMAIN - search all methods NOT IMPLEMENTED
+ VARIABLES_DOMAIN - search all symbols, excluding functions, type names,
+ and constants (enums)
+
+ free_search_symbols should be called when *MATCHES is no longer needed.
+
+ The results are sorted locally; each symtab's global and static blocks are
+ separately alphabetized.
+ */
+void
+search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[],
+ struct symbol_search **matches)
+{
+ struct symtab *s;
+ struct partial_symtab *ps;
+ struct blockvector *bv;
+ struct blockvector *prev_bv = 0;
+ struct block *b;
+ int i = 0;
+ struct dict_iterator iter;
+ struct symbol *sym;
+ struct partial_symbol **psym;
+ struct objfile *objfile;
+ struct minimal_symbol *msymbol;
+ char *val;
+ 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;
+ enum minimal_symbol_type ourtype2;
+ enum minimal_symbol_type ourtype3;
+ enum minimal_symbol_type ourtype4;
+ struct symbol_search *sr;
+ struct symbol_search *psr;
+ struct symbol_search *tail;
+ struct cleanup *old_chain = NULL;
+
+ if (kind < VARIABLES_DOMAIN)
+ error ("must search on specific domain");
+
+ ourtype = types[(int) (kind - VARIABLES_DOMAIN)];
+ ourtype2 = types2[(int) (kind - VARIABLES_DOMAIN)];
+ ourtype3 = types3[(int) (kind - VARIABLES_DOMAIN)];
+ ourtype4 = types4[(int) (kind - VARIABLES_DOMAIN)];
+
+ sr = *matches = NULL;
+ tail = NULL;
+
+ 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 <TYPENAME> or <OPERATOR>. */
+ 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 (8 + fix + strlen (opname) + 1);
+ 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 (file_matches (ps->filename, files, nfiles)
+ && ((regexp == NULL
+ || re_exec (SYMBOL_NATURAL_NAME (*psym)) != 0)
+ && ((kind == VARIABLES_DOMAIN && SYMBOL_CLASS (*psym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (*psym) != LOC_BLOCK)
+ || (kind == FUNCTIONS_DOMAIN && SYMBOL_CLASS (*psym) == LOC_BLOCK)
+ || (kind == TYPES_DOMAIN && SYMBOL_CLASS (*psym) == LOC_TYPEDEF)
+ || (kind == METHODS_DOMAIN && 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 (nfiles == 0 && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+ {
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (MSYMBOL_TYPE (msymbol) == ourtype ||
+ MSYMBOL_TYPE (msymbol) == ourtype2 ||
+ MSYMBOL_TYPE (msymbol) == ourtype3 ||
+ MSYMBOL_TYPE (msymbol) == ourtype4)
+ {
+ if (regexp == NULL
+ || re_exec (SYMBOL_NATURAL_NAME (msymbol)) != 0)
+ {
+ if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))
+ {
+ /* FIXME: carlton/2003-02-04: Given that the
+ semantics of lookup_symbol keeps on changing
+ slightly, it would be a nice idea if we had a
+ function lookup_symbol_minsym that found the
+ symbol associated to a given minimal symbol (if
+ any). */
+ if (kind == FUNCTIONS_DOMAIN
+ || lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol),
+ (struct block *) NULL,
+ VAR_DOMAIN,
+ 0, (struct symtab **) NULL) == NULL)
+ found_misc = 1;
+ }
+ }
+ }
+ }
+ }
+
+ ALL_SYMTABS (objfile, s)
+ {
+ 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++)
+ {
+ struct symbol_search *prevtail = tail;
+ int nfound = 0;
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ QUIT;
+ if (file_matches (s->filename, files, nfiles)
+ && ((regexp == NULL
+ || re_exec (SYMBOL_NATURAL_NAME (sym)) != 0)
+ && ((kind == VARIABLES_DOMAIN && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK
+ && SYMBOL_CLASS (sym) != LOC_CONST)
+ || (kind == FUNCTIONS_DOMAIN && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ || (kind == TYPES_DOMAIN && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ || (kind == METHODS_DOMAIN && SYMBOL_CLASS (sym) == LOC_BLOCK))))
+ {
+ /* match */
+ psr = (struct symbol_search *) xmalloc (sizeof (struct symbol_search));
+ psr->block = i;
+ psr->symtab = s;
+ psr->symbol = sym;
+ psr->msymbol = NULL;
+ psr->next = NULL;
+ if (tail == NULL)
+ sr = psr;
+ else
+ tail->next = psr;
+ tail = psr;
+ nfound ++;
+ }
+ }
+ if (nfound > 0)
+ {
+ if (prevtail == NULL)
+ {
+ struct symbol_search dummy;
+
+ dummy.next = sr;
+ tail = sort_search_symbols (&dummy, nfound);
+ sr = dummy.next;
+
+ old_chain = make_cleanup_free_search_symbols (sr);
+ }
+ else
+ tail = sort_search_symbols (prevtail, nfound);
+ }
+ }
+ 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 || kind != FUNCTIONS_DOMAIN)
+ {
+ ALL_MSYMBOLS (objfile, msymbol)
+ {
+ if (MSYMBOL_TYPE (msymbol) == ourtype ||
+ MSYMBOL_TYPE (msymbol) == ourtype2 ||
+ MSYMBOL_TYPE (msymbol) == ourtype3 ||
+ MSYMBOL_TYPE (msymbol) == ourtype4)
+ {
+ if (regexp == NULL
+ || re_exec (SYMBOL_NATURAL_NAME (msymbol)) != 0)
+ {
+ /* Functions: Look up by address. */
+ if (kind != FUNCTIONS_DOMAIN ||
+ (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))))
+ {
+ /* Variables/Absolutes: Look up by name */
+ if (lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol),
+ (struct block *) NULL, VAR_DOMAIN,
+ 0, (struct symtab **) NULL) == NULL)
+ {
+ /* match */
+ psr = (struct symbol_search *) xmalloc (sizeof (struct symbol_search));
+ psr->block = i;
+ psr->msymbol = msymbol;
+ psr->symtab = NULL;
+ psr->symbol = NULL;
+ psr->next = NULL;
+ if (tail == NULL)
+ {
+ sr = psr;
+ old_chain = make_cleanup_free_search_symbols (sr);
+ }
+ else
+ tail->next = psr;
+ tail = psr;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ *matches = sr;
+ if (sr != NULL)
+ discard_cleanups (old_chain);
+}
+
+/* Helper function for symtab_symbol_info, this function uses
+ the data returned from search_symbols() to print information
+ regarding the match to gdb_stdout.
+ */
+static void
+print_symbol_info (domain_enum kind, struct symtab *s, struct symbol *sym,
+ int block, char *last)
+{
+ if (last == NULL || strcmp (last, s->filename) != 0)
+ {
+ fputs_filtered ("\nFile ", gdb_stdout);
+ fputs_filtered (s->filename, gdb_stdout);
+ fputs_filtered (":\n", gdb_stdout);
+ }
+
+ if (kind != TYPES_DOMAIN && block == STATIC_BLOCK)
+ printf_filtered ("static ");
+
+ /* Typedef that is not a C++ class */
+ if (kind == TYPES_DOMAIN
+ && SYMBOL_DOMAIN (sym) != STRUCT_DOMAIN)
+ typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout);
+ /* variable, func, or typedef-that-is-c++-class */
+ else if (kind < TYPES_DOMAIN ||
+ (kind == TYPES_DOMAIN &&
+ SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN))
+ {
+ type_print (SYMBOL_TYPE (sym),
+ (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ ? "" : SYMBOL_PRINT_NAME (sym)),
+ gdb_stdout, 0);
+
+ printf_filtered (";\n");
+ }
+}
+
+/* This help function for symtab_symbol_info() prints information
+ for non-debugging symbols to gdb_stdout.
+ */
+static void
+print_msymbol_info (struct minimal_symbol *msymbol)
+{
+ char *tmp;
+
+ if (TARGET_ADDR_BIT <= 32)
+ tmp = local_hex_string_custom (SYMBOL_VALUE_ADDRESS (msymbol)
+ & (CORE_ADDR) 0xffffffff,
+ "08l");
+ else
+ tmp = local_hex_string_custom (SYMBOL_VALUE_ADDRESS (msymbol),
+ "016l");
+ printf_filtered ("%s %s\n",
+ tmp, SYMBOL_PRINT_NAME (msymbol));
+}
+
+/* This is the guts of the commands "info functions", "info types", and
+ "info variables". It calls search_symbols to find all matches and then
+ print_[m]symbol_info to print out some useful information about the
+ matches.
+ */
+static void
+symtab_symbol_info (char *regexp, domain_enum kind, int from_tty)
+{
+ static char *classnames[]
+ =
+ {"variable", "function", "type", "method"};
+ struct symbol_search *symbols;
+ struct symbol_search *p;
+ struct cleanup *old_chain;
+ char *last_filename = NULL;
+ int first = 1;
+
+ /* must make sure that if we're interrupted, symbols gets freed */
+ search_symbols (regexp, kind, 0, (char **) NULL, &symbols);
+ old_chain = make_cleanup_free_search_symbols (symbols);
+
+ printf_filtered (regexp
+ ? "All %ss matching regular expression \"%s\":\n"
+ : "All defined %ss:\n",
+ classnames[(int) (kind - VARIABLES_DOMAIN)], regexp);
+
+ for (p = symbols; p != NULL; p = p->next)
+ {
+ QUIT;
+
+ if (p->msymbol != NULL)
+ {
+ if (first)
+ {
+ printf_filtered ("\nNon-debugging symbols:\n");
+ first = 0;
+ }
+ print_msymbol_info (p->msymbol);
+ }
+ else
+ {
+ print_symbol_info (kind,
+ p->symtab,
+ p->symbol,
+ p->block,
+ last_filename);
+ last_filename = p->symtab->filename;
+ }
+ }
+
+ do_cleanups (old_chain);
+}
+
+static void
+variables_info (char *regexp, int from_tty)
+{
+ symtab_symbol_info (regexp, VARIABLES_DOMAIN, from_tty);
+}
+
+static void
+functions_info (char *regexp, int from_tty)
+{
+ symtab_symbol_info (regexp, FUNCTIONS_DOMAIN, from_tty);
+}
+
+
+static void
+types_info (char *regexp, int from_tty)
+{
+ symtab_symbol_info (regexp, TYPES_DOMAIN, from_tty);
+}
+
+/* Breakpoint all functions matching regular expression. */
+
+void
+rbreak_command_wrapper (char *regexp, int from_tty)
+{
+ rbreak_command (regexp, from_tty);
+}
+
+static void
+rbreak_command (char *regexp, int from_tty)
+{
+ struct symbol_search *ss;
+ struct symbol_search *p;
+ struct cleanup *old_chain;
+
+ search_symbols (regexp, FUNCTIONS_DOMAIN, 0, (char **) NULL, &ss);
+ old_chain = make_cleanup_free_search_symbols (ss);
+
+ for (p = ss; p != NULL; p = p->next)
+ {
+ if (p->msymbol == NULL)
+ {
+ char *string = alloca (strlen (p->symtab->filename)
+ + strlen (SYMBOL_LINKAGE_NAME (p->symbol))
+ + 4);
+ strcpy (string, p->symtab->filename);
+ strcat (string, ":'");
+ strcat (string, SYMBOL_LINKAGE_NAME (p->symbol));
+ strcat (string, "'");
+ break_command (string, from_tty);
+ print_symbol_info (FUNCTIONS_DOMAIN,
+ p->symtab,
+ p->symbol,
+ p->block,
+ p->symtab->filename);
+ }
+ else
+ {
+ break_command (SYMBOL_LINKAGE_NAME (p->msymbol), from_tty);
+ printf_filtered ("<function, no debug info> %s;\n",
+ SYMBOL_PRINT_NAME (p->msymbol));
+ }
+ }
+
+ do_cleanups (old_chain);
+}
+
+
+/* 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) \
+ completion_list_add_name \
+ (SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
+
+/* 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 (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;
+ }
+
+ /* 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);
+ }
+
+ 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;
+ }
+}
+
+/* ObjC: In case we are completing on a selector, look as the msymbol
+ again and feed all the selectors into the mill. */
+
+static void
+completion_list_objc_symbol (struct minimal_symbol *msymbol, char *sym_text,
+ int sym_text_len, char *text, char *word)
+{
+ static char *tmp = NULL;
+ static unsigned int tmplen = 0;
+
+ char *method, *category, *selector;
+ char *tmp2 = NULL;
+
+ method = SYMBOL_NATURAL_NAME (msymbol);
+
+ /* Is it a method? */
+ if ((method[0] != '-') && (method[0] != '+'))
+ return;
+
+ if (sym_text[0] == '[')
+ /* Complete on shortened method method. */
+ completion_list_add_name (method + 1, sym_text, sym_text_len, text, word);
+
+ while ((strlen (method) + 1) >= tmplen)
+ {
+ if (tmplen == 0)
+ tmplen = 1024;
+ else
+ tmplen *= 2;
+ tmp = xrealloc (tmp, tmplen);
+ }
+ selector = strchr (method, ' ');
+ if (selector != NULL)
+ selector++;
+
+ category = strchr (method, '(');
+
+ if ((category != NULL) && (selector != NULL))
+ {
+ memcpy (tmp, method, (category - method));
+ tmp[category - method] = ' ';
+ memcpy (tmp + (category - method) + 1, selector, strlen (selector) + 1);
+ completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
+ if (sym_text[0] == '[')
+ completion_list_add_name (tmp + 1, sym_text, sym_text_len, text, word);
+ }
+
+ if (selector != NULL)
+ {
+ /* Complete on selector only. */
+ strcpy (tmp, selector);
+ tmp2 = strchr (tmp, ']');
+ if (tmp2 != NULL)
+ *tmp2 = '\0';
+
+ completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
+ }
+}
+
+/* Break the non-quoted text based on the characters which are in
+ symbols. FIXME: This should probably be language-specific. */
+
+static char *
+language_search_unquoted_string (char *text, char *p)
+{
+ for (; p > text; --p)
+ {
+ if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0')
+ continue;
+ else
+ {
+ if ((current_language->la_language == language_objc))
+ {
+ if (p[-1] == ':') /* might be part of a method name */
+ continue;
+ else if (p[-1] == '[' && (p[-2] == '-' || p[-2] == '+'))
+ p -= 2; /* beginning of a method name */
+ else if (p[-1] == ' ' || p[-1] == '(' || p[-1] == ')')
+ { /* might be part of a method name */
+ char *t = p;
+
+ /* Seeing a ' ' or a '(' is not conclusive evidence
+ that we are in the middle of a method name. However,
+ finding "-[" or "+[" should be pretty un-ambiguous.
+ Unfortunately we have to find it now to decide. */
+
+ while (t > text)
+ if (isalnum (t[-1]) || t[-1] == '_' ||
+ t[-1] == ' ' || t[-1] == ':' ||
+ t[-1] == '(' || t[-1] == ')')
+ --t;
+ else
+ break;
+
+ if (t[-1] == '[' && (t[-2] == '-' || t[-2] == '+'))
+ p = t - 2; /* method name detected */
+ /* else we leave with p unchanged */
+ }
+ }
+ break;
+ }
+ }
+ return p;
+}
+
+
+/* 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 (char *text, char *word)
+{
+ struct symbol *sym;
+ struct symtab *s;
+ struct partial_symtab *ps;
+ struct minimal_symbol *msymbol;
+ struct objfile *objfile;
+ struct block *b, *surrounding_static_block = 0;
+ struct dict_iterator iter;
+ int j;
+ struct partial_symbol **psym;
+ /* The symbol we are completing on. Points in same buffer as text. */
+ char *sym_text;
+ /* 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_val = (char **) xmalloc (sizeof (char *));
+ return_val[0] = NULL;
+ return return_val;
+ }
+ 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);
+
+ completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text, word);
+ }
+
+ /* Search upwards from currently selected frame (so that we can
+ complete on local vars. */
+
+ for (b = get_selected_block (0); 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. */
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ QUIT;
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ {
+ struct type *t = SYMBOL_TYPE (sym);
+ enum type_code c = TYPE_CODE (t);
+
+ 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);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ 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;
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ }
+ }
+
+ return (return_val);
+}
+
+/* Like make_symbol_completion_list, but returns a list of symbols
+ defined in a source file FILE. */
+
+char **
+make_file_symbol_completion_list (char *text, char *word, char *srcfile)
+{
+ struct symbol *sym;
+ struct symtab *s;
+ struct block *b;
+ struct dict_iterator iter;
+ /* 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_val = (char **) xmalloc (sizeof (char *));
+ return_val[0] = NULL;
+ return return_val;
+ }
+ else
+ {
+ /* Not a quoted string. */
+ sym_text = language_search_unquoted_string (text, p);
+ }
+ }
+
+ sym_text_len = strlen (sym_text);
+
+ return_val_size = 10;
+ return_val_index = 0;
+ return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *));
+ return_val[0] = NULL;
+
+ /* Find the symtab for SRCFILE (this loads it if it was not yet read
+ in). */
+ s = lookup_symtab (srcfile);
+ if (s == NULL)
+ {
+ /* Maybe they typed the file with leading directories, while the
+ symbol tables record only its basename. */
+ const char *tail = lbasename (srcfile);
+
+ if (tail > srcfile)
+ s = lookup_symtab (tail);
+ }
+
+ /* If we have no symtab for that file, return an empty list. */
+ if (s == NULL)
+ return (return_val);
+
+ /* Go through this symtab and check the externs and statics for
+ symbols which match. */
+
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ }
+
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ }
+
+ return (return_val);
+}
+
+/* A helper function for make_source_files_completion_list. It adds
+ another file name to a list of possible completions, growing the
+ list as necessary. */
+
+static void
+add_filename_to_list (const char *fname, char *text, char *word,
+ char ***list, int *list_used, int *list_alloced)
+{
+ char *new;
+ size_t fnlen = strlen (fname);
+
+ if (*list_used + 1 >= *list_alloced)
+ {
+ *list_alloced *= 2;
+ *list = (char **) xrealloc ((char *) *list,
+ *list_alloced * sizeof (char *));
+ }
+
+ if (word == text)
+ {
+ /* Return exactly fname. */
+ new = xmalloc (fnlen + 5);
+ strcpy (new, fname);
+ }
+ else if (word > text)
+ {
+ /* Return some portion of fname. */
+ new = xmalloc (fnlen + 5);
+ strcpy (new, fname + (word - text));
+ }
+ else
+ {
+ /* Return some of TEXT plus fname. */
+ new = xmalloc (fnlen + (text - word) + 5);
+ strncpy (new, word, text - word);
+ new[text - word] = '\0';
+ strcat (new, fname);
+ }
+ (*list)[*list_used] = new;
+ (*list)[++*list_used] = NULL;
+}
+
+static int
+not_interesting_fname (const char *fname)
+{
+ static const char *illegal_aliens[] = {
+ "_globals_", /* inserted by coff_symtab_read */
+ NULL
+ };
+ int i;
+
+ for (i = 0; illegal_aliens[i]; i++)
+ {
+ if (strcmp (fname, illegal_aliens[i]) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* Return a NULL terminated array of all source files whose names
+ begin with matching TEXT. The file names are looked up in the
+ symbol tables of this program. If the answer is no matchess, then
+ the return value is an array which contains only a NULL pointer. */
+
+char **
+make_source_files_completion_list (char *text, char *word)
+{
+ struct symtab *s;
+ struct partial_symtab *ps;
+ struct objfile *objfile;
+ int first = 1;
+ int list_alloced = 1;
+ int list_used = 0;
+ size_t text_len = strlen (text);
+ char **list = (char **) xmalloc (list_alloced * sizeof (char *));
+ const char *base_name;
+
+ list[0] = NULL;
+
+ if (!have_full_symbols () && !have_partial_symbols ())
+ return list;
+
+ ALL_SYMTABS (objfile, s)
+ {
+ if (not_interesting_fname (s->filename))
+ continue;
+ if (!filename_seen (s->filename, 1, &first)
+#if HAVE_DOS_BASED_FILE_SYSTEM
+ && strncasecmp (s->filename, text, text_len) == 0
+#else
+ && strncmp (s->filename, text, text_len) == 0
+#endif
+ )
+ {
+ /* This file matches for a completion; add it to the current
+ list of matches. */
+ add_filename_to_list (s->filename, text, word,
+ &list, &list_used, &list_alloced);
+ }
+ else
+ {
+ /* NOTE: We allow the user to type a base name when the
+ debug info records leading directories, but not the other
+ way around. This is what subroutines of breakpoint
+ command do when they parse file names. */
+ base_name = lbasename (s->filename);
+ if (base_name != s->filename
+ && !filename_seen (base_name, 1, &first)
+#if HAVE_DOS_BASED_FILE_SYSTEM
+ && strncasecmp (base_name, text, text_len) == 0
+#else
+ && strncmp (base_name, text, text_len) == 0
+#endif
+ )
+ add_filename_to_list (base_name, text, word,
+ &list, &list_used, &list_alloced);
+ }
+ }
+
+ ALL_PSYMTABS (objfile, ps)
+ {
+ if (not_interesting_fname (ps->filename))
+ continue;
+ if (!ps->readin)
+ {
+ if (!filename_seen (ps->filename, 1, &first)
+#if HAVE_DOS_BASED_FILE_SYSTEM
+ && strncasecmp (ps->filename, text, text_len) == 0
+#else
+ && strncmp (ps->filename, text, text_len) == 0
+#endif
+ )
+ {
+ /* This file matches for a completion; add it to the
+ current list of matches. */
+ add_filename_to_list (ps->filename, text, word,
+ &list, &list_used, &list_alloced);
+
+ }
+ else
+ {
+ base_name = lbasename (ps->filename);
+ if (base_name != ps->filename
+ && !filename_seen (base_name, 1, &first)
+#if HAVE_DOS_BASED_FILE_SYSTEM
+ && strncasecmp (base_name, text, text_len) == 0
+#else
+ && strncmp (base_name, text, text_len) == 0
+#endif
+ )
+ add_filename_to_list (base_name, text, word,
+ &list, &list_used, &list_alloced);
+ }
+ }
+ }
+
+ return list;
+}
+
+/* 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 think the prologue starts, possibly
+ by previous examination of symbol table information.
+ */
+
+int
+in_prologue (CORE_ADDR pc, CORE_ADDR func_start)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_addr, func_end;
+
+ /* We have several sources of information we can consult to figure
+ this out.
+ - Compilers usually emit line number info that marks the prologue
+ as its own "source line". So the ending address of that "line"
+ is the end of the prologue. If available, this is the most
+ reliable method.
+ - The minimal symbols and partial symbols, which can usually tell
+ us the starting and ending addresses of a function.
+ - If we know the function's start address, we can call the
+ architecture-defined SKIP_PROLOGUE function to analyze the
+ instruction stream and guess where the prologue ends.
+ - Our `func_start' argument; if non-zero, this is the caller's
+ best guess as to the function's entry point. At the time of
+ this writing, handle_inferior_event doesn't get this right, so
+ it should be our last resort. */
+
+ /* Consult the partial symbol table, to find which function
+ the PC is in. */
+ if (! find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ CORE_ADDR prologue_end;
+
+ /* We don't even have minsym information, so fall back to using
+ func_start, if given. */
+ if (! func_start)
+ return 1; /* We *might* be in a prologue. */
+
+ prologue_end = SKIP_PROLOGUE (func_start);
+
+ return func_start <= pc && pc < prologue_end;
+ }
+
+ /* If we have line number information for the function, that's
+ usually pretty reliable. */
+ sal = find_pc_line (func_addr, 0);
+
+ /* Now sal describes the source line at the function's entry point,
+ which (by convention) is the prologue. The end of that "line",
+ sal.end, is the end of the prologue.
+
+ Note that, for functions whose source code is all on a single
+ line, the line number information doesn't always end up this way.
+ So we must verify that our purported end-of-prologue address is
+ *within* the function, not at its start or end. */
+ if (sal.line == 0
+ || sal.end <= func_addr
+ || func_end <= sal.end)
+ {
+ /* We don't have any good line number info, so use the minsym
+ information, together with the architecture-specific prologue
+ scanning code. */
+ CORE_ADDR prologue_end = SKIP_PROLOGUE (func_addr);
+
+ return func_addr <= pc && pc < prologue_end;
+ }
+
+ /* We have line number info, and it looks good. */
+ return func_addr <= pc && pc < sal.end;
+}
+
+/* Given PC at the function's start address, attempt to find the
+ prologue end using SAL information. Return zero if the skip fails.
+
+ A non-optimized prologue traditionally has one SAL for the function
+ and a second for the function body. A single line function has
+ them both pointing at the same line.
+
+ An optimized prologue is similar but the prologue may contain
+ instructions (SALs) from the instruction body. Need to skip those
+ while not getting into the function body.
+
+ The functions end point and an increasing SAL line are used as
+ indicators of the prologue's endpoint.
+
+ This code is based on the function refine_prologue_limit (versions
+ found in both ia64 and ppc). */
+
+CORE_ADDR
+skip_prologue_using_sal (CORE_ADDR func_addr)
+{
+ struct symtab_and_line prologue_sal;
+ CORE_ADDR start_pc;
+ CORE_ADDR end_pc;
+
+ /* Get an initial range for the function. */
+ find_pc_partial_function (func_addr, NULL, &start_pc, &end_pc);
+ start_pc += FUNCTION_START_OFFSET;
+
+ prologue_sal = find_pc_line (start_pc, 0);
+ if (prologue_sal.line != 0)
+ {
+ while (prologue_sal.end < end_pc)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (prologue_sal.end, 0);
+ if (sal.line == 0)
+ break;
+ /* Assume that a consecutive SAL for the same (or larger)
+ line mark the prologue -> body transition. */
+ if (sal.line >= prologue_sal.line)
+ break;
+ /* The case in which compiler's optimizer/scheduler has
+ moved instructions into the prologue. We look ahead in
+ the function looking for address ranges whose
+ corresponding line number is less the first one that we
+ found for the function. This is more conservative then
+ refine_prologue_limit which scans a large number of SALs
+ looking for any in the prologue */
+ prologue_sal = sal;
+ }
+ }
+ return prologue_sal.end;
+}
+
+struct symtabs_and_lines
+decode_line_spec (char *string, int funfirstline)
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line cursal;
+
+ if (string == 0)
+ error ("Empty line specification.");
+
+ /* We use whatever is set as the current source line. We do not try
+ and get a default or it will recursively call us! */
+ cursal = get_current_source_symtab_and_line ();
+
+ sals = decode_line_1 (&string, funfirstline,
+ cursal.symtab, cursal.line,
+ (char ***) NULL, NULL);
+
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+/* Track MAIN */
+static char *name_of_main;
+
+void
+set_main_name (const char *name)
+{
+ if (name_of_main != NULL)
+ {
+ xfree (name_of_main);
+ name_of_main = NULL;
+ }
+ if (name != NULL)
+ {
+ name_of_main = xstrdup (name);
+ }
+}
+
+char *
+main_name (void)
+{
+ if (name_of_main != NULL)
+ return name_of_main;
+ else
+ return "main";
+}
+
+
+void
+_initialize_symtab (void)
+{
+ add_info ("variables", variables_info,
+ "All global and static variable names, or those matching REGEXP.");
+ if (dbx_commands)
+ add_com ("whereis", class_info, 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.");
+
+ add_info ("sources", sources_info,
+ "Source files in the program.");
+
+ add_com ("rbreak", class_breakpoint, rbreak_command,
+ "Set a breakpoint for all functions matching REGEXP.");
+
+ if (xdb_commands)
+ {
+ add_com ("lf", class_info, sources_info, "Source files in the program");
+ add_com ("lg", class_info, variables_info,
+ "All global and static variable names, or those matching REGEXP.");
+ }
+
+ /* Initialize the one built-in type that isn't language dependent... */
+ builtin_type_error = init_type (TYPE_CODE_ERROR, 0, 0,
+ "<unknown type>", (struct objfile *) NULL);
+}
diff --git a/contrib/gdb/gdb/symtab.h b/contrib/gdb/gdb/symtab.h
new file mode 100644
index 0000000..5a6c398
--- /dev/null
+++ b/contrib/gdb/gdb/symtab.h
@@ -0,0 +1,1368 @@
+/* Symbol table definitions for GDB.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+/* Opaque declarations. */
+struct ui_file;
+struct frame_info;
+struct symbol;
+struct obstack;
+struct objfile;
+struct block;
+struct blockvector;
+struct axs_value;
+struct agent_expr;
+
+/* Some of the structures in this file are space critical.
+ The space-critical structures are:
+
+ struct general_symbol_info
+ struct symbol
+ struct partial_symbol
+
+ These structures are layed out to encourage good packing.
+ They use ENUM_BITFIELD and short int fields, and they order the
+ structure members so that fields less than a word are next
+ to each other so they can be packed together. */
+
+/* Rearranged: used ENUM_BITFIELD and rearranged field order in
+ all the space critical structures (plus struct minimal_symbol).
+ Memory usage dropped from 99360768 bytes to 90001408 bytes.
+ I measured this with before-and-after tests of
+ "HEAD-old-gdb -readnow HEAD-old-gdb" and
+ "HEAD-new-gdb -readnow HEAD-old-gdb" on native i686-pc-linux-gnu,
+ red hat linux 8, with LD_LIBRARY_PATH=/usr/lib/debug,
+ typing "maint space 1" at the first command prompt.
+
+ Here is another measurement (from andrew c):
+ # no /usr/lib/debug, just plain glibc, like a normal user
+ gdb HEAD-old-gdb
+ (gdb) break internal_error
+ (gdb) run
+ (gdb) maint internal-error
+ (gdb) backtrace
+ (gdb) maint space 1
+
+ gdb gdb_6_0_branch 2003-08-19 space used: 8896512
+ gdb HEAD 2003-08-19 space used: 8904704
+ gdb HEAD 2003-08-21 space used: 8396800 (+symtab.h)
+ gdb HEAD 2003-08-21 space used: 8265728 (+gdbtypes.h)
+
+ The third line shows the savings from the optimizations in symtab.h.
+ The fourth line shows the savings from the optimizations in
+ gdbtypes.h. Both optimizations are in gdb HEAD now.
+
+ --chastain 2003-08-21 */
+
+
+
+/* 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. */
+
+/* This structure is space critical. See space comments at the top. */
+
+struct general_symbol_info
+{
+ /* Name of the symbol. This is a required field. Storage for the
+ name is allocated on the objfile_obstack for the associated
+ objfile. For languages like C++ that make a distinction between
+ the mangled name and demangled name, this is the mangled
+ name. */
+
+ 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
+ {
+ /* This is in fact used for C++, Java, and Objective C. */
+ char *demangled_name;
+ }
+ cplus_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_BITFIELD(language) language : 8;
+
+ /* 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;
+
+ /* The bfd section associated with this symbol. */
+
+ asection *bfd_section;
+};
+
+extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, asection *);
+
+/* Note that all the following SYMBOL_* macros are used with the
+ SYMBOL argument being either a partial symbol, a minimal symbol or
+ a full symbol. All three types have a ginfo field. In particular
+ the SYMBOL_INIT_LANGUAGE_SPECIFIC, SYMBOL_INIT_DEMANGLED_NAME,
+ SYMBOL_DEMANGLED_NAME macros cannot be entirely substituted by
+ functions, unless the callers are changed to pass in the ginfo
+ field only, instead of the SYMBOL parameter. */
+
+#define DEPRECATED_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_BFD_SECTION(symbol) (symbol)->ginfo.bfd_section
+
+#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \
+ (symbol)->ginfo.language_specific.cplus_specific.demangled_name
+
+/* Initializes the language dependent portion of a symbol
+ depending upon the language for the symbol. */
+#define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \
+ (symbol_init_language_specific (&(symbol)->ginfo, (language)))
+extern void symbol_init_language_specific (struct general_symbol_info *symbol,
+ enum language language);
+
+#define SYMBOL_INIT_DEMANGLED_NAME(symbol,obstack) \
+ (symbol_init_demangled_name (&(symbol)->ginfo, (obstack)))
+extern void symbol_init_demangled_name (struct general_symbol_info *symbol,
+ struct obstack *obstack);
+
+#define SYMBOL_SET_NAMES(symbol,linkage_name,len,objfile) \
+ symbol_set_names (&(symbol)->ginfo, linkage_name, len, objfile)
+extern void symbol_set_names (struct general_symbol_info *symbol,
+ const char *linkage_name, int len,
+ struct objfile *objfile);
+
+/* Now come lots of name accessor macros. Short version as to when to
+ use which: Use SYMBOL_NATURAL_NAME to refer to the name of the
+ symbol in the original source code. Use SYMBOL_LINKAGE_NAME if you
+ want to know what the linker thinks the symbol's name is. Use
+ SYMBOL_PRINT_NAME for output. Use SYMBOL_DEMANGLED_NAME if you
+ specifically need to know whether SYMBOL_NATURAL_NAME and
+ SYMBOL_LINKAGE_NAME are different. Don't use
+ DEPRECATED_SYMBOL_NAME at all: instances of that macro should be
+ replaced by SYMBOL_NATURAL_NAME, SYMBOL_LINKAGE_NAME, or perhaps
+ SYMBOL_PRINT_NAME. */
+
+/* Return SYMBOL's "natural" name, i.e. the name that it was called in
+ the original source code. In languages like C++ where symbols may
+ be mangled for ease of manipulation by the linker, this is the
+ demangled name. */
+
+#define SYMBOL_NATURAL_NAME(symbol) \
+ (symbol_natural_name (&(symbol)->ginfo))
+extern char *symbol_natural_name (const struct general_symbol_info *symbol);
+
+/* Return SYMBOL's name from the point of view of the linker. In
+ languages like C++ where symbols may be mangled for ease of
+ manipulation by the linker, this is the mangled name; otherwise,
+ it's the same as SYMBOL_NATURAL_NAME. This is currently identical
+ to DEPRECATED_SYMBOL_NAME, but please use SYMBOL_LINKAGE_NAME when
+ appropriate: it conveys the additional semantic information that
+ you really have thought about the issue and decided that you mean
+ SYMBOL_LINKAGE_NAME instead of SYMBOL_NATURAL_NAME. */
+
+#define SYMBOL_LINKAGE_NAME(symbol) (symbol)->ginfo.name
+
+/* Return the demangled name for a symbol based on the language for
+ that symbol. If no demangled name exists, return NULL. */
+#define SYMBOL_DEMANGLED_NAME(symbol) \
+ (symbol_demangled_name (&(symbol)->ginfo))
+extern char *symbol_demangled_name (struct general_symbol_info *symbol);
+
+/* Macro that returns a version of the name of a symbol that is
+ suitable for output. In C++ this is the "demangled" form of the
+ 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. Don't use this for internal
+ purposes (e.g. storing in a hashtable): it's only suitable for
+ output. */
+
+#define SYMBOL_PRINT_NAME(symbol) \
+ (demangle ? SYMBOL_NATURAL_NAME (symbol) : SYMBOL_LINKAGE_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. */
+
+/* Macro that tests a symbol for a match against a specified name
+ string. It tests against SYMBOL_NATURAL_NAME, and it ignores
+ whitespace and trailing parentheses. (See strcmp_iw for details
+ about its behavior.) */
+
+#define SYMBOL_MATCHES_NATURAL_NAME(symbol, name) \
+ (strcmp_iw (SYMBOL_NATURAL_NAME (symbol), (name)) == 0)
+
+/* Classification types for a minimal 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 */
+};
+
+/* 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 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
+ objfile_obstack for the associated objfile. The type would be
+ "void *" except for reasons of compatibility with older
+ compilers. This field is optional.
+
+ Currently, the AMD 29000 tdep.c uses it to remember things it has decoded
+ from the instructions in the function header, and the MIPS-16 code uses
+ it to identify 16-bit procedures. */
+
+ char *info;
+
+ /* Size of this symbol. end_psymtab in dbxread.c uses this
+ information to calculate the end of the partial symtab based on the
+ address of the last symbol plus the size of the last symbol. */
+
+ unsigned long size;
+
+#ifdef SOFUN_ADDRESS_MAYBE_MISSING
+ /* Which source file is this symbol in? Only relevant for mst_file_*. */
+ char *filename;
+#endif
+
+ /* Classification type for this minimal symbol. */
+
+ ENUM_BITFIELD(minimal_symbol_type) type : 8;
+
+ /* Minimal symbols with the same hash key are kept on a linked
+ list. This is the link. */
+
+ struct minimal_symbol *hash_next;
+
+ /* Minimal symbols are stored in two different hash tables. This is
+ the `next' pointer for the demangled hash table. */
+
+ struct minimal_symbol *demangled_hash_next;
+};
+
+#define MSYMBOL_INFO(msymbol) (msymbol)->info
+#define MSYMBOL_SIZE(msymbol) (msymbol)->size
+#define MSYMBOL_TYPE(msymbol) (msymbol)->type
+
+
+
+/* Represent one symbol name; a variable, constant, function or typedef. */
+
+/* Different name domains for symbols. Looking up a symbol specifies a
+ domain and ignores symbol definitions in other name domains. */
+
+typedef enum domain_enum_tag
+{
+ /* UNDEF_DOMAIN is used when a domain 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_DOMAIN,
+
+ /* VAR_DOMAIN is the usual domain. In C, this contains variables,
+ function names, typedef names and enum type values. */
+
+ VAR_DOMAIN,
+
+ /* STRUCT_DOMAIN 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_DOMAIN. */
+
+ STRUCT_DOMAIN,
+
+ /* LABEL_DOMAIN may be used for names of labels (for gotos);
+ currently it is not used and labels are not recorded at all. */
+
+ LABEL_DOMAIN,
+
+ /* Searching domains. These overlap with VAR_DOMAIN, providing
+ some granularity with the search_symbols function. */
+
+ /* Everything in VAR_DOMAIN minus FUNCTIONS_-, TYPES_-, and
+ METHODS_DOMAIN */
+ VARIABLES_DOMAIN,
+
+ /* All functions -- for some reason not methods, though. */
+ FUNCTIONS_DOMAIN,
+
+ /* All defined types */
+ TYPES_DOMAIN,
+
+ /* All class methods -- why is this separated out? */
+ METHODS_DOMAIN
+}
+domain_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 the frame's arguments
+ (get_frame_args_address) versus the frame's locals
+ (get_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 domain
+ STRUCT_DOMAIN 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 (get_frame_locals_address), not in
+ the arglist (get_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,
+
+ /* Value is at a thread-specific location calculated by a
+ target-specific method. This is used only by hppa. */
+
+ LOC_HP_THREAD_LOCAL_STATIC,
+
+ /* The variable does not actually exist in the program.
+ The value is ignored. */
+
+ LOC_OPTIMIZED_OUT,
+
+ /* The variable is static, but actually lives at * (address).
+ * I.e. do an extra indirection to get to it.
+ * This is used on HP-UX to get at globals that are allocated
+ * in shared libraries, where references from images other
+ * than the one where the global was allocated are done
+ * with a level of indirection.
+ */
+
+ LOC_INDIRECT,
+
+ /* The variable's address is computed by a set of location
+ functions (see "struct location_funcs" below). */
+ LOC_COMPUTED,
+
+ /* Same as LOC_COMPUTED, but for function arguments. */
+ LOC_COMPUTED_ARG
+};
+
+/* The methods needed to implement a symbol class. These methods can
+ use the symbol's .aux_value for additional per-symbol information.
+
+ At present this is only used to implement location expressions. */
+
+struct symbol_ops
+{
+
+ /* Return the value of the variable SYMBOL, relative to the stack
+ frame FRAME. If the variable has been optimized out, return
+ zero.
+
+ Iff `read_needs_frame (SYMBOL)' is zero, then FRAME may be zero. */
+
+ struct value *(*read_variable) (struct symbol * symbol,
+ struct frame_info * frame);
+
+ /* Return non-zero if we need a frame to find the value of the SYMBOL. */
+ int (*read_needs_frame) (struct symbol * symbol);
+
+ /* Write to STREAM a natural-language description of the location of
+ SYMBOL. */
+ int (*describe_location) (struct symbol * symbol, struct ui_file * stream);
+
+ /* Tracepoint support. Append bytecodes to the tracepoint agent
+ expression AX that push the address of the object SYMBOL. Set
+ VALUE appropriately. Note --- for objects in registers, this
+ needn't emit any code; as long as it sets VALUE properly, then
+ the caller will generate the right code in the process of
+ treating this as an lvalue or rvalue. */
+
+ void (*tracepoint_var_ref) (struct symbol * symbol, struct agent_expr * ax,
+ struct axs_value * value);
+};
+
+/* This structure is space critical. See space comments at the top. */
+
+struct symbol
+{
+
+ /* The general symbol info required for all types of symbols. */
+
+ struct general_symbol_info ginfo;
+
+ /* Data type of value */
+
+ struct type *type;
+
+ /* Domain code. */
+
+ ENUM_BITFIELD(domain_enum_tag) domain : 6;
+
+ /* Address class */
+ /* NOTE: cagney/2003-11-02: The fields "aclass" and "ops" contain
+ overlapping information. By creating a per-aclass ops vector, or
+ using the aclass as an index into an ops table, the aclass and
+ ops fields can be merged. The latter, for instance, would shave
+ 32-bits from each symbol (relative to a symbol lookup, any table
+ index overhead would be in the noise). */
+
+ ENUM_BITFIELD(address_class) aclass : 6;
+
+ /* 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;
+
+ /* Method's for symbol's of this class. */
+ /* NOTE: cagney/2003-11-02: See comment above attached to "aclass". */
+
+ const struct symbol_ops *ops;
+
+ /* Some symbols require additional information to be recorded on a
+ per- symbol basis. Stash those values here. */
+
+ union
+ {
+ /* Used by LOC_BASEREG and LOC_BASEREG_ARG. */
+ short basereg;
+ /* An arbitrary data pointer. Note that this data must be
+ allocated using the same obstack as the symbol itself. */
+ /* So far it is only used by LOC_COMPUTED and LOC_COMPUTED_ARG to
+ find the location location information. For a LOC_BLOCK symbol
+ for a function in a compilation unit compiled with DWARF 2
+ information, this is information used internally by the DWARF 2
+ code --- specifically, the location expression for the frame
+ base for this function. */
+ /* FIXME drow/2003-02-21: For the LOC_BLOCK case, it might be better
+ to add a magic symbol to the block containing this information,
+ or to have a generic debug info annotation slot for symbols. */
+ void *ptr;
+ }
+ aux_value;
+
+ struct symbol *hash_next;
+};
+
+
+#define SYMBOL_DOMAIN(symbol) (symbol)->domain
+#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
+#define SYMBOL_OBJFILE(symbol) (symbol)->aux_value.objfile
+#define SYMBOL_OPS(symbol) (symbol)->ops
+#define SYMBOL_LOCATION_BATON(symbol) (symbol)->aux_value.ptr
+
+/* A partial_symbol records the name, domain, 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. */
+
+/* This structure is space critical. See space comments at the top. */
+
+struct partial_symbol
+{
+
+ /* The general symbol info required for all types of symbols. */
+
+ struct general_symbol_info ginfo;
+
+ /* Name space code. */
+
+ ENUM_BITFIELD(domain_enum_tag) domain : 6;
+
+ /* Address class (for info_symbols) */
+
+ ENUM_BITFIELD(address_class) aclass : 6;
+
+};
+
+#define PSYMBOL_DOMAIN(psymbol) (psymbol)->domain
+#define PSYMBOL_CLASS(psymbol) (psymbol)->aclass
+
+
+/* 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.
+
+ If an entry has a line number of zero, it marks the start of a PC
+ range for which no line number information is available. It is
+ acceptable, though wasteful of table space, for such a range to be
+ zero length. */
+
+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];
+};
+
+/* 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) \
+ ((whichone == -1) \
+ ? (internal_error (__FILE__, __LINE__, "Section index is uninitialized"), -1) \
+ : secoff->offsets[whichone])
+
+/* The size of a section_offsets table for N sections. */
+#define SIZEOF_N_SECTION_OFFSETS(n) \
+ (sizeof (struct section_offsets) \
+ + sizeof (((struct section_offsets *) 0)->offsets) * ((n)-1))
+
+/* 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 designated the primary, so that the blockvector
+ is relocated exactly once by objfile_relocate. */
+
+ int primary;
+
+ /* The macro table for this symtab. Like the blockvector, this
+ may be shared between different symtabs --- and normally is for
+ all the symtabs in a given compilation unit. */
+ struct macro_table *macro_table;
+
+ /* 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;
+
+ /* A function to call to free space, if necessary. This is IN
+ ADDITION to the action indicated by free_code. */
+
+ void (*free_func)(struct symtab *symtab);
+
+ /* 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 that identifies the format of the debugging information, such
+ as "stabs", "dwarf 1", "dwarf 2", "coff", etc. This is mostly useful
+ for automated testing of gdb but may also be information that is
+ useful to the user. */
+
+ char *debugformat;
+
+ /* 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;
+
+};
+
+#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,
+ objfile_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;
+
+ /* Full path of the source file. NULL if not known. */
+
+ char *fullname;
+
+ /* 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) (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
+
+/* External variables and functions for the objects described above. */
+
+/* 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;
+
+/* symtab.c lookup functions */
+
+/* lookup a symbol table by source file name */
+
+extern struct symtab *lookup_symtab (const char *);
+
+/* lookup a symbol by name (optional block, optional symtab) */
+
+extern struct symbol *lookup_symbol (const char *, const struct block *,
+ const domain_enum, int *,
+ struct symtab **);
+
+/* A default version of lookup_symbol_nonlocal for use by languages
+ that can't think of anything better to do. */
+
+extern struct symbol *basic_lookup_symbol_nonlocal (const char *,
+ const char *,
+ const struct block *,
+ const domain_enum,
+ struct symtab **);
+
+/* Some helper functions for languages that need to write their own
+ lookup_symbol_nonlocal functions. */
+
+/* Lookup a symbol in the static block associated to BLOCK, if there
+ is one; do nothing if BLOCK is NULL or a global block. */
+
+extern struct symbol *lookup_symbol_static (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+/* Lookup a symbol in all files' global blocks (searching psymtabs if
+ necessary). */
+
+extern struct symbol *lookup_symbol_global (const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+/* Lookup a symbol within the block BLOCK. This, unlike
+ lookup_symbol_block, will set SYMTAB and BLOCK_FOUND correctly, and
+ will fix up the symbol if necessary. */
+
+extern struct symbol *lookup_symbol_aux_block (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain,
+ struct symtab **symtab);
+
+/* Lookup a partial symbol. */
+
+extern struct partial_symbol *lookup_partial_symbol (struct partial_symtab *,
+ const char *,
+ const char *, int,
+ domain_enum);
+
+/* lookup a symbol by name, within a specified block */
+
+extern struct symbol *lookup_block_symbol (const struct block *, const char *,
+ const char *,
+ const domain_enum);
+
+/* lookup a [struct, union, enum] by name, within a specified block */
+
+extern struct type *lookup_struct (char *, struct block *);
+
+extern struct type *lookup_union (char *, struct block *);
+
+extern struct type *lookup_enum (char *, struct block *);
+
+/* from blockframe.c: */
+
+/* lookup the function symbol corresponding to the address */
+
+extern struct symbol *find_pc_function (CORE_ADDR);
+
+/* lookup the function corresponding to the address and section */
+
+extern struct symbol *find_pc_sect_function (CORE_ADDR, asection *);
+
+/* lookup function from address, return name, start addr and end addr */
+
+extern int find_pc_partial_function (CORE_ADDR, char **, CORE_ADDR *,
+ CORE_ADDR *);
+
+extern void clear_pc_function_cache (void);
+
+extern int find_pc_sect_partial_function (CORE_ADDR, asection *,
+ char **, CORE_ADDR *, CORE_ADDR *);
+
+/* from symtab.c: */
+
+/* lookup partial symbol table by filename */
+
+extern struct partial_symtab *lookup_partial_symtab (const char *);
+
+/* lookup partial symbol table by address */
+
+extern struct partial_symtab *find_pc_psymtab (CORE_ADDR);
+
+/* lookup partial symbol table by address and section */
+
+extern struct partial_symtab *find_pc_sect_psymtab (CORE_ADDR, asection *);
+
+/* lookup full symbol table by address */
+
+extern struct symtab *find_pc_symtab (CORE_ADDR);
+
+/* lookup full symbol table by address and section */
+
+extern struct symtab *find_pc_sect_symtab (CORE_ADDR, asection *);
+
+/* lookup partial symbol by address */
+
+extern struct partial_symbol *find_pc_psymbol (struct partial_symtab *,
+ CORE_ADDR);
+
+/* lookup partial symbol by address and section */
+
+extern struct partial_symbol *find_pc_sect_psymbol (struct partial_symtab *,
+ CORE_ADDR, asection *);
+
+extern int find_pc_line_pc_range (CORE_ADDR, CORE_ADDR *, CORE_ADDR *);
+
+extern void reread_symbols (void);
+
+extern struct type *lookup_transparent_type (const char *);
+extern struct type *basic_lookup_transparent_type (const char *);
+
+
+/* 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 (const char *, CORE_ADDR,
+ enum minimal_symbol_type,
+ struct objfile *);
+
+extern struct minimal_symbol *prim_record_minimal_symbol_and_info
+ (const char *, CORE_ADDR,
+ enum minimal_symbol_type,
+ char *info, int section, asection * bfd_section, struct objfile *);
+
+extern unsigned int msymbol_hash_iw (const char *);
+
+extern unsigned int msymbol_hash (const char *);
+
+extern void
+add_minsym_to_hash_table (struct minimal_symbol *sym,
+ struct minimal_symbol **table);
+
+extern struct minimal_symbol *lookup_minimal_symbol (const char *,
+ const char *,
+ struct objfile *);
+
+extern struct minimal_symbol *lookup_minimal_symbol_text (const char *,
+ struct objfile *);
+
+struct minimal_symbol *lookup_minimal_symbol_solib_trampoline (const char *,
+ struct objfile
+ *);
+
+extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+
+extern struct minimal_symbol *lookup_minimal_symbol_by_pc_section (CORE_ADDR,
+ asection
+ *);
+
+extern struct minimal_symbol
+ *lookup_solib_trampoline_symbol_by_pc (CORE_ADDR);
+
+extern CORE_ADDR find_solib_trampoline_target (CORE_ADDR);
+
+extern void init_minimal_symbol_collection (void);
+
+extern struct cleanup *make_cleanup_discard_minimal_symbols (void);
+
+extern void install_minimal_symbols (struct objfile *);
+
+/* Sort all the minimal symbols in OBJFILE. */
+
+extern void msymbols_sort (struct objfile *objfile);
+
+struct symtab_and_line
+{
+ struct symtab *symtab;
+ asection *section;
+ /* 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;
+};
+
+extern void init_sal (struct symtab_and_line *sal);
+
+struct symtabs_and_lines
+{
+ struct symtab_and_line *sals;
+ int nelts;
+};
+
+
+
+/* Some types and macros needed for exception catchpoints.
+ Can't put these in target.h because symtab_and_line isn't
+ known there. This file will be included by breakpoint.c,
+ hppa-tdep.c, etc. */
+
+/* Enums for exception-handling support */
+enum exception_event_kind
+{
+ EX_EVENT_THROW,
+ EX_EVENT_CATCH
+};
+
+/* Type for returning info about an exception */
+struct exception_event_record
+{
+ enum exception_event_kind kind;
+ struct symtab_and_line throw_sal;
+ struct symtab_and_line catch_sal;
+ /* This may need to be extended in the future, if
+ some platforms allow reporting more information,
+ such as point of rethrow, type of exception object,
+ type expected by catch clause, etc. */
+};
+
+#define CURRENT_EXCEPTION_KIND (current_exception_event->kind)
+#define CURRENT_EXCEPTION_CATCH_SAL (current_exception_event->catch_sal)
+#define CURRENT_EXCEPTION_CATCH_LINE (current_exception_event->catch_sal.line)
+#define CURRENT_EXCEPTION_CATCH_FILE (current_exception_event->catch_sal.symtab->filename)
+#define CURRENT_EXCEPTION_CATCH_PC (current_exception_event->catch_sal.pc)
+#define CURRENT_EXCEPTION_THROW_SAL (current_exception_event->throw_sal)
+#define CURRENT_EXCEPTION_THROW_LINE (current_exception_event->throw_sal.line)
+#define CURRENT_EXCEPTION_THROW_FILE (current_exception_event->throw_sal.symtab->filename)
+#define CURRENT_EXCEPTION_THROW_PC (current_exception_event->throw_sal.pc)
+
+
+/* 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 (CORE_ADDR, int);
+
+/* Same function, but specify a section as well as an address */
+
+extern struct symtab_and_line find_pc_sect_line (CORE_ADDR, asection *, int);
+
+/* Given a symtab and line number, return the pc there. */
+
+extern int find_line_pc (struct symtab *, int, CORE_ADDR *);
+
+extern int find_line_pc_range (struct symtab_and_line, CORE_ADDR *,
+ CORE_ADDR *);
+
+extern void resolve_sal_pc (struct symtab_and_line *);
+
+/* Given a string, return the line specified by it. For commands like "list"
+ and "breakpoint". */
+
+extern struct symtabs_and_lines decode_line_spec (char *, int);
+
+extern struct symtabs_and_lines decode_line_spec_1 (char *, int);
+
+/* Symmisc.c */
+
+void maintenance_print_symbols (char *, int);
+
+void maintenance_print_psymbols (char *, int);
+
+void maintenance_print_msymbols (char *, int);
+
+void maintenance_print_objfiles (char *, int);
+
+void maintenance_info_symtabs (char *, int);
+
+void maintenance_info_psymtabs (char *, int);
+
+void maintenance_check_symtabs (char *, int);
+
+/* maint.c */
+
+void maintenance_print_statistics (char *, int);
+
+extern void free_symtab (struct symtab *);
+
+/* Symbol-reading stuff in symfile.c and solib.c. */
+
+extern struct symtab *psymtab_to_symtab (struct partial_symtab *);
+
+extern void clear_solib (void);
+
+/* source.c */
+
+extern int identify_source_line (struct symtab *, int, int, CORE_ADDR);
+
+extern void print_source_lines (struct symtab *, int, int, int);
+
+extern void forget_cached_source_info (void);
+
+extern void select_source_symtab (struct symtab *);
+
+extern char **make_symbol_completion_list (char *, char *);
+
+extern char **make_file_symbol_completion_list (char *, char *, char *);
+
+extern char **make_source_files_completion_list (char *, char *);
+
+/* symtab.c */
+
+extern struct partial_symtab *find_main_psymtab (void);
+
+extern struct symtab *find_line_symtab (struct symtab *, int, int *, int *);
+
+extern struct symtab_and_line find_function_start_sal (struct symbol *sym,
+ int);
+
+/* symfile.c */
+
+extern void clear_symtab_users (void);
+
+extern enum language deduce_language_from_filename (char *);
+
+/* symtab.c */
+
+extern int in_prologue (CORE_ADDR pc, CORE_ADDR func_start);
+
+extern CORE_ADDR skip_prologue_using_sal (CORE_ADDR func_addr);
+
+extern struct symbol *fixup_symbol_section (struct symbol *,
+ struct objfile *);
+
+extern struct partial_symbol *fixup_psymbol_section (struct partial_symbol
+ *psym,
+ struct objfile *objfile);
+
+/* Symbol searching */
+
+/* When using search_symbols, a list of the following structs is returned.
+ Callers must free the search list using free_search_symbols! */
+struct symbol_search
+{
+ /* The block in which the match was found. Could be, for example,
+ STATIC_BLOCK or GLOBAL_BLOCK. */
+ int block;
+
+ /* Information describing what was found.
+
+ If symtab abd symbol are NOT NULL, then information was found
+ for this match. */
+ struct symtab *symtab;
+ struct symbol *symbol;
+
+ /* If msymbol is non-null, then a match was made on something for
+ which only minimal_symbols exist. */
+ struct minimal_symbol *msymbol;
+
+ /* A link to the next match, or NULL for the end. */
+ struct symbol_search *next;
+};
+
+extern void search_symbols (char *, domain_enum, int, char **,
+ struct symbol_search **);
+extern void free_search_symbols (struct symbol_search *);
+extern struct cleanup *make_cleanup_free_search_symbols (struct symbol_search
+ *);
+
+/* The name of the ``main'' function.
+ FIXME: cagney/2001-03-20: Can't make main_name() const since some
+ of the calling code currently assumes that the string isn't
+ const. */
+extern void set_main_name (const char *name);
+extern /*const */ char *main_name (void);
+
+#endif /* !defined(SYMTAB_H) */
diff --git a/contrib/gdb/gdb/target.c b/contrib/gdb/gdb/target.c
new file mode 100644
index 0000000..ff47ac1
--- /dev/null
+++ b/contrib/gdb/gdb/target.c
@@ -0,0 +1,2451 @@
+/* Select target systems and architectures at runtime for GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004 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 <errno.h>
+#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 "gdb_wait.h"
+#include "dcache.h"
+#include <signal.h>
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "gdbcore.h"
+
+static void target_info (char *, int);
+
+static void maybe_kill_then_create_inferior (char *, char *, char **);
+
+static void maybe_kill_then_attach (char *, int);
+
+static void kill_or_be_killed (int);
+
+static void default_terminal_info (char *, int);
+
+static int default_region_size_ok_for_hw_watchpoint (int);
+
+static int nosymbol (char *, CORE_ADDR *);
+
+static void tcomplain (void);
+
+static int nomemory (CORE_ADDR, char *, int, int, struct target_ops *);
+
+static int return_zero (void);
+
+static int return_one (void);
+
+static int return_minus_one (void);
+
+void target_ignore (void);
+
+static void target_command (char *, int);
+
+static struct target_ops *find_default_run_target (char *);
+
+static void nosupport_runtime (void);
+
+static LONGEST default_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf,
+ ULONGEST offset, LONGEST len);
+
+/* 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 either target_read_memory_partial or
+ target_write_memory_partial). */
+
+static int target_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write);
+
+static void init_dummy_target (void);
+
+static void debug_to_open (char *, int);
+
+static void debug_to_close (int);
+
+static void debug_to_attach (char *, int);
+
+static void debug_to_detach (char *, int);
+
+static void debug_to_disconnect (char *, int);
+
+static void debug_to_resume (ptid_t, int, enum target_signal);
+
+static ptid_t debug_to_wait (ptid_t, struct target_waitstatus *);
+
+static void debug_to_fetch_registers (int);
+
+static void debug_to_store_registers (int);
+
+static void debug_to_prepare_to_store (void);
+
+static int debug_to_xfer_memory (CORE_ADDR, char *, int, int,
+ struct mem_attrib *, struct target_ops *);
+
+static void debug_to_files_info (struct target_ops *);
+
+static int debug_to_insert_breakpoint (CORE_ADDR, char *);
+
+static int debug_to_remove_breakpoint (CORE_ADDR, char *);
+
+static int debug_to_can_use_hw_breakpoint (int, int, int);
+
+static int debug_to_insert_hw_breakpoint (CORE_ADDR, char *);
+
+static int debug_to_remove_hw_breakpoint (CORE_ADDR, char *);
+
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+
+static int debug_to_stopped_by_watchpoint (void);
+
+static CORE_ADDR debug_to_stopped_data_address (void);
+
+static int debug_to_region_size_ok_for_hw_watchpoint (int);
+
+static void debug_to_terminal_init (void);
+
+static void debug_to_terminal_inferior (void);
+
+static void debug_to_terminal_ours_for_output (void);
+
+static void debug_to_terminal_save_ours (void);
+
+static void debug_to_terminal_ours (void);
+
+static void debug_to_terminal_info (char *, int);
+
+static void debug_to_kill (void);
+
+static void debug_to_load (char *, int);
+
+static int debug_to_lookup_symbol (char *, CORE_ADDR *);
+
+static void debug_to_create_inferior (char *, char *, char **);
+
+static void debug_to_mourn_inferior (void);
+
+static int debug_to_can_run (void);
+
+static void debug_to_notice_signals (ptid_t);
+
+static int debug_to_thread_alive (ptid_t);
+
+static void debug_to_stop (void);
+
+/* 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. */
+
+static struct target_ops dummy_target;
+
+/* Top of target stack. */
+
+static struct target_ops *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;
+
+/* Non-zero if we want to see trace of target level stuff. */
+
+static int targetdebug = 0;
+
+static void setup_target_debug (void);
+
+DCACHE *target_dcache;
+
+/* The user just typed 'target' without the name of a target. */
+
+static void
+target_command (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 (struct target_ops *t)
+{
+ /* Provide default values for all "must have" methods. */
+ if (t->to_xfer_partial == NULL)
+ t->to_xfer_partial = default_xfer_partial;
+
+ 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;
+
+ 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 */
+
+void
+target_ignore (void)
+{
+}
+
+void
+target_load (char *arg, int from_tty)
+{
+ dcache_invalidate (target_dcache);
+ (*current_target.to_load) (arg, from_tty);
+}
+
+static int
+nomemory (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 (void)
+{
+ error ("You can't do that when your target is `%s'",
+ current_target.to_shortname);
+}
+
+void
+noprocess (void)
+{
+ error ("You can't do that without a process to debug.");
+}
+
+static int
+nosymbol (char *name, CORE_ADDR *addrp)
+{
+ return 1; /* Symbol does not exist in target env */
+}
+
+static void
+nosupport_runtime (void)
+{
+ if (ptid_equal (inferior_ptid, null_ptid))
+ noprocess ();
+ else
+ error ("No run-time support for this");
+}
+
+
+static void
+default_terminal_info (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 (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 (char *args, int from_tty)
+{
+ kill_or_be_killed (from_tty);
+ target_attach (args, from_tty);
+}
+
+static void
+maybe_kill_then_create_inferior (char *exec, char *args, char **env)
+{
+ kill_or_be_killed (0);
+ target_create_inferior (exec, args, env);
+}
+
+/* Go through the target stack from top to bottom, copying over zero
+ entries in current_target, then filling in still empty entries. In
+ effect, we are doing class inheritance through the pushed target
+ vectors.
+
+ NOTE: cagney/2003-10-17: The problem with this inheritance, as it
+ is currently implemented, is that it discards any knowledge of
+ which target an inherited method originally belonged to.
+ Consequently, new new target methods should instead explicitly and
+ locally search the target stack for the target that can handle the
+ request. */
+
+static void
+update_current_target (void)
+{
+ struct target_ops *t;
+
+ /* First, reset curren'ts contents. */
+ memset (&current_target, 0, sizeof (current_target));
+
+#define INHERIT(FIELD, TARGET) \
+ if (!current_target.FIELD) \
+ current_target.FIELD = (TARGET)->FIELD
+
+ for (t = target_stack; t; t = t->beneath)
+ {
+ 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_post_attach, t);
+ INHERIT (to_detach, t);
+ INHERIT (to_disconnect, t);
+ INHERIT (to_resume, t);
+ INHERIT (to_wait, t);
+ INHERIT (to_post_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_can_use_hw_breakpoint, t);
+ INHERIT (to_insert_hw_breakpoint, t);
+ INHERIT (to_remove_hw_breakpoint, t);
+ INHERIT (to_insert_watchpoint, t);
+ INHERIT (to_remove_watchpoint, t);
+ INHERIT (to_stopped_data_address, t);
+ INHERIT (to_stopped_by_watchpoint, t);
+ INHERIT (to_have_continuable_watchpoint, t);
+ INHERIT (to_region_size_ok_for_hw_watchpoint, 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_save_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_post_startup_inferior, t);
+ INHERIT (to_acknowledge_created_inferior, t);
+ INHERIT (to_insert_fork_catchpoint, t);
+ INHERIT (to_remove_fork_catchpoint, t);
+ INHERIT (to_insert_vfork_catchpoint, t);
+ INHERIT (to_remove_vfork_catchpoint, t);
+ INHERIT (to_follow_fork, t);
+ INHERIT (to_insert_exec_catchpoint, t);
+ INHERIT (to_remove_exec_catchpoint, t);
+ INHERIT (to_reported_exec_events_per_exec_call, t);
+ INHERIT (to_has_exited, t);
+ INHERIT (to_mourn_inferior, t);
+ INHERIT (to_can_run, t);
+ INHERIT (to_notice_signals, t);
+ INHERIT (to_thread_alive, t);
+ INHERIT (to_find_new_threads, t);
+ INHERIT (to_pid_to_str, t);
+ INHERIT (to_extra_thread_info, t);
+ INHERIT (to_stop, t);
+ /* Do not inherit to_xfer_partial. */
+ INHERIT (to_rcmd, t);
+ INHERIT (to_enable_exception_callback, t);
+ INHERIT (to_get_current_exception_event, t);
+ INHERIT (to_pid_to_exec_file, t);
+ INHERIT (to_stratum, 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_has_thread_control, t);
+ INHERIT (to_sections, t);
+ INHERIT (to_sections_end, t);
+ INHERIT (to_can_async_p, t);
+ INHERIT (to_is_async_p, t);
+ INHERIT (to_async, t);
+ INHERIT (to_async_mask_value, t);
+ INHERIT (to_find_memory_regions, t);
+ INHERIT (to_make_corefile_notes, t);
+ INHERIT (to_get_thread_local_address, t);
+ INHERIT (to_magic, t);
+ }
+#undef INHERIT
+
+ /* Clean up a target struct so it no longer has any zero pointers in
+ it. Some entries are defaulted to a method that print an error,
+ others are hard-wired to a standard recursive default. */
+
+#define de_fault(field, value) \
+ if (!current_target.field) \
+ current_target.field = value
+
+ de_fault (to_open,
+ (void (*) (char *, int))
+ tcomplain);
+ de_fault (to_close,
+ (void (*) (int))
+ target_ignore);
+ de_fault (to_attach,
+ maybe_kill_then_attach);
+ de_fault (to_post_attach,
+ (void (*) (int))
+ target_ignore);
+ de_fault (to_detach,
+ (void (*) (char *, int))
+ target_ignore);
+ de_fault (to_disconnect,
+ (void (*) (char *, int))
+ tcomplain);
+ de_fault (to_resume,
+ (void (*) (ptid_t, int, enum target_signal))
+ noprocess);
+ de_fault (to_wait,
+ (ptid_t (*) (ptid_t, struct target_waitstatus *))
+ noprocess);
+ de_fault (to_post_wait,
+ (void (*) (ptid_t, int))
+ target_ignore);
+ de_fault (to_fetch_registers,
+ (void (*) (int))
+ target_ignore);
+ de_fault (to_store_registers,
+ (void (*) (int))
+ noprocess);
+ de_fault (to_prepare_to_store,
+ (void (*) (void))
+ noprocess);
+ de_fault (to_xfer_memory,
+ (int (*) (CORE_ADDR, char *, int, int, struct mem_attrib *, struct target_ops *))
+ nomemory);
+ de_fault (to_files_info,
+ (void (*) (struct target_ops *))
+ target_ignore);
+ de_fault (to_insert_breakpoint,
+ memory_insert_breakpoint);
+ de_fault (to_remove_breakpoint,
+ memory_remove_breakpoint);
+ de_fault (to_can_use_hw_breakpoint,
+ (int (*) (int, int, int))
+ return_zero);
+ de_fault (to_insert_hw_breakpoint,
+ (int (*) (CORE_ADDR, char *))
+ return_minus_one);
+ de_fault (to_remove_hw_breakpoint,
+ (int (*) (CORE_ADDR, char *))
+ return_minus_one);
+ de_fault (to_insert_watchpoint,
+ (int (*) (CORE_ADDR, int, int))
+ return_minus_one);
+ de_fault (to_remove_watchpoint,
+ (int (*) (CORE_ADDR, int, int))
+ return_minus_one);
+ de_fault (to_stopped_by_watchpoint,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_stopped_data_address,
+ (CORE_ADDR (*) (void))
+ return_zero);
+ de_fault (to_region_size_ok_for_hw_watchpoint,
+ default_region_size_ok_for_hw_watchpoint);
+ de_fault (to_terminal_init,
+ (void (*) (void))
+ target_ignore);
+ de_fault (to_terminal_inferior,
+ (void (*) (void))
+ target_ignore);
+ de_fault (to_terminal_ours_for_output,
+ (void (*) (void))
+ target_ignore);
+ de_fault (to_terminal_ours,
+ (void (*) (void))
+ target_ignore);
+ de_fault (to_terminal_save_ours,
+ (void (*) (void))
+ target_ignore);
+ de_fault (to_terminal_info,
+ default_terminal_info);
+ de_fault (to_kill,
+ (void (*) (void))
+ noprocess);
+ de_fault (to_load,
+ (void (*) (char *, int))
+ tcomplain);
+ de_fault (to_lookup_symbol,
+ (int (*) (char *, CORE_ADDR *))
+ nosymbol);
+ de_fault (to_create_inferior,
+ maybe_kill_then_create_inferior);
+ de_fault (to_post_startup_inferior,
+ (void (*) (ptid_t))
+ target_ignore);
+ de_fault (to_acknowledge_created_inferior,
+ (void (*) (int))
+ target_ignore);
+ de_fault (to_insert_fork_catchpoint,
+ (int (*) (int))
+ tcomplain);
+ de_fault (to_remove_fork_catchpoint,
+ (int (*) (int))
+ tcomplain);
+ de_fault (to_insert_vfork_catchpoint,
+ (int (*) (int))
+ tcomplain);
+ de_fault (to_remove_vfork_catchpoint,
+ (int (*) (int))
+ tcomplain);
+ de_fault (to_follow_fork,
+ (int (*) (int))
+ target_ignore);
+ de_fault (to_insert_exec_catchpoint,
+ (int (*) (int))
+ tcomplain);
+ de_fault (to_remove_exec_catchpoint,
+ (int (*) (int))
+ tcomplain);
+ de_fault (to_reported_exec_events_per_exec_call,
+ (int (*) (void))
+ return_one);
+ de_fault (to_has_exited,
+ (int (*) (int, int, int *))
+ return_zero);
+ de_fault (to_mourn_inferior,
+ (void (*) (void))
+ noprocess);
+ de_fault (to_can_run,
+ return_zero);
+ de_fault (to_notice_signals,
+ (void (*) (ptid_t))
+ target_ignore);
+ de_fault (to_thread_alive,
+ (int (*) (ptid_t))
+ return_zero);
+ de_fault (to_find_new_threads,
+ (void (*) (void))
+ target_ignore);
+ de_fault (to_extra_thread_info,
+ (char *(*) (struct thread_info *))
+ return_zero);
+ de_fault (to_stop,
+ (void (*) (void))
+ target_ignore);
+ current_target.to_xfer_partial = default_xfer_partial;
+ de_fault (to_rcmd,
+ (void (*) (char *, struct ui_file *))
+ tcomplain);
+ de_fault (to_enable_exception_callback,
+ (struct symtab_and_line * (*) (enum exception_event_kind, int))
+ nosupport_runtime);
+ de_fault (to_get_current_exception_event,
+ (struct exception_event_record * (*) (void))
+ nosupport_runtime);
+ de_fault (to_pid_to_exec_file,
+ (char *(*) (int))
+ return_zero);
+ de_fault (to_can_async_p,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_is_async_p,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_async,
+ (void (*) (void (*) (enum inferior_event_type, void*), void*))
+ tcomplain);
+#undef de_fault
+
+ /* Finally, position the target-stack beneath the squashed
+ "current_target". That way code looking for a non-inherited
+ target method can quickly and simply find it. */
+ current_target.beneath = target_stack;
+}
+
+/* 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 (struct target_ops *t)
+{
+ struct target_ops **cur;
+
+ /* 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);
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+
+ /* Find the proper stratum to install this target in. */
+ for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath)
+ {
+ if ((int) (t->to_stratum) >= (int) (*cur)->to_stratum)
+ break;
+ }
+
+ /* If there's already targets at this stratum, remove them. */
+ /* FIXME: cagney/2003-10-15: I think this should be poping all
+ targets to CUR, and not just those at this stratum level. */
+ while ((*cur) != NULL && t->to_stratum == (*cur)->to_stratum)
+ {
+ /* There's already something at this stratum level. Close it,
+ and un-hook it from the stack. */
+ struct target_ops *tmp = (*cur);
+ (*cur) = (*cur)->beneath;
+ tmp->beneath = NULL;
+ target_close (tmp, 0);
+ }
+
+ /* We have removed all targets in our stratum, now add the new one. */
+ t->beneath = (*cur);
+ (*cur) = t;
+
+ update_current_target ();
+
+ if (targetdebug)
+ setup_target_debug ();
+
+ /* Not on top? */
+ return (t != target_stack);
+}
+
+/* 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 (struct target_ops *t)
+{
+ struct target_ops **cur;
+ struct target_ops *tmp;
+
+ /* Look for the specified target. Note that we assume that a target
+ can only occur once in the target stack. */
+
+ for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath)
+ {
+ if ((*cur) == t)
+ break;
+ }
+
+ if ((*cur) == NULL)
+ return 0; /* Didn't find target_ops, quit now */
+
+ /* NOTE: cagney/2003-12-06: In '94 the close call was made
+ unconditional by moving it to before the above check that the
+ target was in the target stack (something about "Change the way
+ pushing and popping of targets work to support target overlays
+ and inheritance"). This doesn't make much sense - only open
+ targets should be closed. */
+ target_close (t, 0);
+
+ /* Unchain the target */
+ tmp = (*cur);
+ (*cur) = (*cur)->beneath;
+ tmp->beneath = NULL;
+
+ update_current_target ();
+
+ return 1;
+}
+
+void
+pop_target (void)
+{
+ target_close (&current_target, 0); /* Let it clean up */
+ if (unpush_target (target_stack) == 1)
+ return;
+
+ fprintf_unfiltered (gdb_stderr,
+ "pop_target couldn't find target %s\n",
+ current_target.to_shortname);
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+}
+
+#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 (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)
+ {
+ /* The transfer request might have crossed the boundary to an
+ unallocated region of memory. Retry the transfer, requesting
+ a single byte. */
+ tlen = 1;
+ offset = 0;
+ errcode = target_xfer_memory (memaddr, buf, 1, 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;
+}
+
+/* Find a section containing ADDR. */
+struct section_table *
+target_section_by_addr (struct target_ops *target, CORE_ADDR addr)
+{
+ struct section_table *secp;
+ for (secp = target->to_sections;
+ secp < target->to_sections_end;
+ secp++)
+ {
+ if (addr >= secp->addr && addr < secp->endaddr)
+ return secp;
+ }
+ return NULL;
+}
+
+/* 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 (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ return target_xfer_memory (memaddr, myaddr, len, 0);
+}
+
+int
+target_write_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ return target_xfer_memory (memaddr, myaddr, len, 1);
+}
+
+static int trust_readonly = 0;
+
+/* Move memory to or from the targets. The top target gets priority;
+ if it cannot handle it, it is offered to the next one down, etc.
+
+ Result is -1 on error, or the number of bytes transfered. */
+
+int
+do_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib)
+{
+ int res;
+ int done = 0;
+ struct target_ops *t;
+
+ /* Zero length requests are ok and require no work. */
+ if (len == 0)
+ return 0;
+
+ /* to_xfer_memory is not guaranteed to set errno, even when it returns
+ 0. */
+ errno = 0;
+
+ if (!write && trust_readonly)
+ {
+ struct section_table *secp;
+ /* User-settable option, "trust-readonly-sections". If true,
+ then memory from any SEC_READONLY bfd section may be read
+ directly from the bfd file. */
+ secp = target_section_by_addr (&current_target, memaddr);
+ if (secp != NULL
+ && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
+ & SEC_READONLY))
+ return xfer_memory (memaddr, myaddr, len, 0, attrib, &current_target);
+ }
+
+ /* The quick case is that the top target can handle the transfer. */
+ res = current_target.to_xfer_memory
+ (memaddr, myaddr, len, write, attrib, &current_target);
+
+ /* If res <= 0 then we call it again in the loop. Ah well. */
+ if (res <= 0)
+ {
+ for (t = target_stack; t != NULL; t = t->beneath)
+ {
+ if (!t->to_has_memory)
+ continue;
+
+ res = t->to_xfer_memory (memaddr, myaddr, len, write, attrib, t);
+ if (res > 0)
+ break; /* Handled all or part of xfer */
+ if (t->to_has_all_memory)
+ break;
+ }
+
+ if (res <= 0)
+ return -1;
+ }
+
+ return res;
+}
+
+
+/* Perform a memory transfer. Iterate until the entire region has
+ been transfered.
+
+ Result is 0 or errno value. */
+
+static int
+target_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write)
+{
+ int res;
+ int reg_len;
+ struct mem_region *region;
+
+ /* Zero length requests are ok and require no work. */
+ if (len == 0)
+ {
+ return 0;
+ }
+
+ while (len > 0)
+ {
+ region = lookup_mem_region(memaddr);
+ if (memaddr + len < region->hi)
+ reg_len = len;
+ else
+ reg_len = region->hi - memaddr;
+
+ switch (region->attrib.mode)
+ {
+ case MEM_RO:
+ if (write)
+ return EIO;
+ break;
+
+ case MEM_WO:
+ if (!write)
+ return EIO;
+ break;
+ }
+
+ while (reg_len > 0)
+ {
+ if (region->attrib.cache)
+ res = dcache_xfer_memory (target_dcache, memaddr, myaddr,
+ reg_len, write);
+ else
+ res = do_xfer_memory (memaddr, myaddr, reg_len, write,
+ &region->attrib);
+
+ 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;
+ }
+
+ memaddr += res;
+ myaddr += res;
+ len -= res;
+ reg_len -= res;
+ }
+ }
+
+ return 0; /* We managed to cover it all somehow. */
+}
+
+
+/* Perform a partial memory transfer.
+
+ Result is -1 on error, or the number of bytes transfered. */
+
+static int
+target_xfer_memory_partial (CORE_ADDR memaddr, char *myaddr, int len,
+ int write_p, int *err)
+{
+ int res;
+ int reg_len;
+ struct mem_region *region;
+
+ /* Zero length requests are ok and require no work. */
+ if (len == 0)
+ {
+ *err = 0;
+ return 0;
+ }
+
+ region = lookup_mem_region(memaddr);
+ if (memaddr + len < region->hi)
+ reg_len = len;
+ else
+ reg_len = region->hi - memaddr;
+
+ switch (region->attrib.mode)
+ {
+ case MEM_RO:
+ if (write_p)
+ {
+ *err = EIO;
+ return -1;
+ }
+ break;
+
+ case MEM_WO:
+ if (write_p)
+ {
+ *err = EIO;
+ return -1;
+ }
+ break;
+ }
+
+ if (region->attrib.cache)
+ res = dcache_xfer_memory (target_dcache, memaddr, myaddr,
+ reg_len, write_p);
+ else
+ res = do_xfer_memory (memaddr, myaddr, reg_len, write_p,
+ &region->attrib);
+
+ if (res <= 0)
+ {
+ if (errno != 0)
+ *err = errno;
+ else
+ *err = EIO;
+
+ return -1;
+ }
+
+ *err = 0;
+ return res;
+}
+
+int
+target_read_memory_partial (CORE_ADDR memaddr, char *buf, int len, int *err)
+{
+ return target_xfer_memory_partial (memaddr, buf, len, 0, err);
+}
+
+int
+target_write_memory_partial (CORE_ADDR memaddr, char *buf, int len, int *err)
+{
+ return target_xfer_memory_partial (memaddr, buf, len, 1, err);
+}
+
+/* More generic transfers. */
+
+static LONGEST
+default_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ if (object == TARGET_OBJECT_MEMORY
+ && ops->to_xfer_memory != NULL)
+ /* If available, fall back to the target's "to_xfer_memory"
+ method. */
+ {
+ int xfered = -1;
+ errno = 0;
+ if (writebuf != NULL)
+ {
+ void *buffer = xmalloc (len);
+ struct cleanup *cleanup = make_cleanup (xfree, buffer);
+ memcpy (buffer, writebuf, len);
+ xfered = ops->to_xfer_memory (offset, buffer, len, 1/*write*/, NULL,
+ ops);
+ do_cleanups (cleanup);
+ }
+ if (readbuf != NULL)
+ xfered = ops->to_xfer_memory (offset, readbuf, len, 0/*read*/, NULL,
+ ops);
+ if (xfered > 0)
+ return xfered;
+ else if (xfered == 0 && errno == 0)
+ /* "to_xfer_memory" uses 0, cross checked against ERRNO as one
+ indication of an error. */
+ return 0;
+ else
+ return -1;
+ }
+ else if (ops->beneath != NULL)
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
+ else
+ return -1;
+}
+
+/* Target vector read/write partial wrapper functions.
+
+ NOTE: cagney/2003-10-21: I wonder if having "to_xfer_partial
+ (inbuf, outbuf)", instead of separate read/write methods, make life
+ easier. */
+
+LONGEST
+target_read_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, void *buf,
+ ULONGEST offset, LONGEST len)
+{
+ gdb_assert (ops->to_xfer_partial != NULL);
+ return ops->to_xfer_partial (ops, object, annex, buf, NULL, offset, len);
+}
+
+LONGEST
+target_write_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const void *buf,
+ ULONGEST offset, LONGEST len)
+{
+ gdb_assert (ops->to_xfer_partial != NULL);
+ return ops->to_xfer_partial (ops, object, annex, NULL, buf, offset, len);
+}
+
+/* Wrappers to perform the full transfer. */
+LONGEST
+target_read (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, void *buf,
+ ULONGEST offset, LONGEST len)
+{
+ LONGEST xfered = 0;
+ while (xfered < len)
+ {
+ LONGEST xfer = target_read_partial (ops, object, annex,
+ (bfd_byte *) buf + xfered,
+ offset + xfered, len - xfered);
+ /* Call an observer, notifying them of the xfer progress? */
+ if (xfer <= 0)
+ /* Call memory_error? */
+ return -1;
+ xfered += xfer;
+ QUIT;
+ }
+ return len;
+}
+
+LONGEST
+target_write (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const void *buf,
+ ULONGEST offset, LONGEST len)
+{
+ LONGEST xfered = 0;
+ while (xfered < len)
+ {
+ LONGEST xfer = target_write_partial (ops, object, annex,
+ (bfd_byte *) buf + xfered,
+ offset + xfered, len - xfered);
+ /* Call an observer, notifying them of the xfer progress? */
+ if (xfer <= 0)
+ /* Call memory_error? */
+ return -1;
+ xfered += xfer;
+ QUIT;
+ }
+ return len;
+}
+
+/* Memory transfer methods. */
+
+void
+get_target_memory (struct target_ops *ops, CORE_ADDR addr, void *buf,
+ LONGEST len)
+{
+ if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, buf, addr, len)
+ != len)
+ memory_error (EIO, addr);
+}
+
+ULONGEST
+get_target_memory_unsigned (struct target_ops *ops,
+ CORE_ADDR addr, int len)
+{
+ char buf[sizeof (ULONGEST)];
+
+ gdb_assert (len <= sizeof (buf));
+ get_target_memory (ops, addr, buf, len);
+ return extract_unsigned_integer (buf, len);
+}
+
+static void
+target_info (char *args, int from_tty)
+{
+ struct target_ops *t;
+ 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 (t = target_stack; t != NULL; t = t->beneath)
+ {
+ 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 (int from_tty)
+{
+ dont_repeat ();
+
+ if (target_has_execution)
+ {
+ if (!from_tty
+ || 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 (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_disconnect (char *args, int from_tty)
+{
+ /* Handle any optimized stores to the inferior. */
+#ifdef DO_DEFERRED_STORES
+ DO_DEFERRED_STORES;
+#endif
+ (current_target.to_disconnect) (args, from_tty);
+}
+
+void
+target_link (char *modname, CORE_ADDR *t_reloc)
+{
+ if (DEPRECATED_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;
+}
+
+int
+target_async_mask (int mask)
+{
+ int saved_async_masked_status = target_async_mask_value;
+ target_async_mask_value = mask;
+ return saved_async_masked_status;
+}
+
+/* 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 (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 (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 (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
+default_region_size_ok_for_hw_watchpoint (int byte_count)
+{
+ return (byte_count <= TYPE_LENGTH (builtin_type_void_data_ptr));
+}
+
+static int
+return_zero (void)
+{
+ return 0;
+}
+
+static int
+return_one (void)
+{
+ return 1;
+}
+
+static int
+return_minus_one (void)
+{
+ return -1;
+}
+
+/*
+ * Resize the to_sections pointer. Also make sure that anyone that
+ * was holding on to an old value of it gets updated.
+ * Returns the old size.
+ */
+
+int
+target_resize_to_sections (struct target_ops *target, int num_added)
+{
+ struct target_ops **t;
+ struct section_table *old_value;
+ int old_count;
+
+ old_value = target->to_sections;
+
+ if (target->to_sections)
+ {
+ old_count = target->to_sections_end - target->to_sections;
+ target->to_sections = (struct section_table *)
+ xrealloc ((char *) target->to_sections,
+ (sizeof (struct section_table)) * (num_added + old_count));
+ }
+ else
+ {
+ old_count = 0;
+ target->to_sections = (struct section_table *)
+ xmalloc ((sizeof (struct section_table)) * num_added);
+ }
+ target->to_sections_end = target->to_sections + (num_added + old_count);
+
+ /* Check to see if anyone else was pointing to this structure.
+ If old_value was null, then no one was. */
+
+ if (old_value)
+ {
+ for (t = target_structs; t < target_structs + target_struct_size;
+ ++t)
+ {
+ if ((*t)->to_sections == old_value)
+ {
+ (*t)->to_sections = target->to_sections;
+ (*t)->to_sections_end = target->to_sections_end;
+ }
+ }
+ }
+
+ return old_count;
+
+}
+
+/* Remove all target sections taken from ABFD.
+
+ Scan the current target stack for targets whose section tables
+ refer to sections from BFD, and remove those sections. We use this
+ when we notice that the inferior has unloaded a shared object, for
+ example. */
+void
+remove_target_sections (bfd *abfd)
+{
+ struct target_ops **t;
+
+ for (t = target_structs; t < target_structs + target_struct_size; t++)
+ {
+ struct section_table *src, *dest;
+
+ dest = (*t)->to_sections;
+ for (src = (*t)->to_sections; src < (*t)->to_sections_end; src++)
+ if (src->bfd != abfd)
+ {
+ /* Keep this section. */
+ if (dest < src) *dest = *src;
+ dest++;
+ }
+
+ /* If we've dropped any sections, resize the section table. */
+ if (dest < src)
+ target_resize_to_sections (*t, dest - src);
+ }
+}
+
+
+
+
+/* Find a single runnable target in the stack and return it. If for
+ some reason there is more than one, return NULL. */
+
+struct target_ops *
+find_run_target (void)
+{
+ 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;
+ }
+ }
+
+ return (count == 1 ? runable : NULL);
+}
+
+/* Find a single core_stratum target in the list of targets and return it.
+ If for some reason there is more than one, return NULL. */
+
+struct target_ops *
+find_core_target (void)
+{
+ 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);
+}
+
+/*
+ * Find the next target down the stack from the specified target.
+ */
+
+struct target_ops *
+find_target_beneath (struct target_ops *t)
+{
+ return t->beneath;
+}
+
+
+/* The inferior process has died. Long live the inferior! */
+
+void
+generic_mourn_inferior (void)
+{
+ extern int show_breakpoint_hit_counts;
+
+ inferior_ptid = null_ptid;
+ attach_flag = 0;
+ breakpoint_init_inferior (inf_exited);
+ 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 ();
+
+ if (detach_hook)
+ detach_hook ();
+}
+
+/* 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 (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));
+ }
+}
+
+/* Returns zero to leave the inferior alone, one to interrupt it. */
+int (*target_activity_function) (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 (ptid_t ptid)
+{
+ static char buf[30];
+
+ sprintf (buf, "process %d", PIDGET (ptid));
+ return buf;
+}
+
+/* Error-catcher for target_find_memory_regions */
+static int dummy_find_memory_regions (int (*ignore1) (), void *ignore2)
+{
+ error ("No target.");
+ return 0;
+}
+
+/* Error-catcher for target_make_corefile_notes */
+static char * dummy_make_corefile_notes (bfd *ignore1, int *ignore2)
+{
+ error ("No target.");
+ return NULL;
+}
+
+/* Set up the handful of non-empty slots needed by the dummy target
+ vector. */
+
+static void
+init_dummy_target (void)
+{
+ dummy_target.to_shortname = "None";
+ dummy_target.to_longname = "None";
+ dummy_target.to_doc = "";
+ dummy_target.to_attach = find_default_attach;
+ dummy_target.to_create_inferior = find_default_create_inferior;
+ dummy_target.to_pid_to_str = normal_pid_to_str;
+ dummy_target.to_stratum = dummy_stratum;
+ dummy_target.to_find_memory_regions = dummy_find_memory_regions;
+ dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
+ dummy_target.to_xfer_partial = default_xfer_partial;
+ dummy_target.to_magic = OPS_MAGIC;
+}
+
+
+static struct target_ops debug_target;
+
+static void
+debug_to_open (char *args, int from_tty)
+{
+ debug_target.to_open (args, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog, "target_open (%s, %d)\n", args, from_tty);
+}
+
+static void
+debug_to_close (int quitting)
+{
+ target_close (&debug_target, quitting);
+ fprintf_unfiltered (gdb_stdlog, "target_close (%d)\n", quitting);
+}
+
+void
+target_close (struct target_ops *targ, int quitting)
+{
+ if (targ->to_xclose != NULL)
+ targ->to_xclose (targ, quitting);
+ else if (targ->to_close != NULL)
+ targ->to_close (quitting);
+}
+
+static void
+debug_to_attach (char *args, int from_tty)
+{
+ debug_target.to_attach (args, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog, "target_attach (%s, %d)\n", args, from_tty);
+}
+
+
+static void
+debug_to_post_attach (int pid)
+{
+ debug_target.to_post_attach (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_post_attach (%d)\n", pid);
+}
+
+static void
+debug_to_detach (char *args, int from_tty)
+{
+ debug_target.to_detach (args, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog, "target_detach (%s, %d)\n", args, from_tty);
+}
+
+static void
+debug_to_disconnect (char *args, int from_tty)
+{
+ debug_target.to_disconnect (args, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog, "target_disconnect (%s, %d)\n",
+ args, from_tty);
+}
+
+static void
+debug_to_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ debug_target.to_resume (ptid, step, siggnal);
+
+ fprintf_unfiltered (gdb_stdlog, "target_resume (%d, %s, %s)\n", PIDGET (ptid),
+ step ? "step" : "continue",
+ target_signal_to_name (siggnal));
+}
+
+static ptid_t
+debug_to_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ ptid_t retval;
+
+ retval = debug_target.to_wait (ptid, status);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_wait (%d, status) = %d, ", PIDGET (ptid),
+ PIDGET (retval));
+ fprintf_unfiltered (gdb_stdlog, "status->kind = ");
+ switch (status->kind)
+ {
+ case TARGET_WAITKIND_EXITED:
+ fprintf_unfiltered (gdb_stdlog, "exited, status = %d\n",
+ status->value.integer);
+ break;
+ case TARGET_WAITKIND_STOPPED:
+ fprintf_unfiltered (gdb_stdlog, "stopped, signal = %s\n",
+ target_signal_to_name (status->value.sig));
+ break;
+ case TARGET_WAITKIND_SIGNALLED:
+ fprintf_unfiltered (gdb_stdlog, "signalled, signal = %s\n",
+ target_signal_to_name (status->value.sig));
+ break;
+ case TARGET_WAITKIND_LOADED:
+ fprintf_unfiltered (gdb_stdlog, "loaded\n");
+ break;
+ case TARGET_WAITKIND_FORKED:
+ fprintf_unfiltered (gdb_stdlog, "forked\n");
+ break;
+ case TARGET_WAITKIND_VFORKED:
+ fprintf_unfiltered (gdb_stdlog, "vforked\n");
+ break;
+ case TARGET_WAITKIND_EXECD:
+ fprintf_unfiltered (gdb_stdlog, "execd\n");
+ break;
+ case TARGET_WAITKIND_SPURIOUS:
+ fprintf_unfiltered (gdb_stdlog, "spurious\n");
+ break;
+ default:
+ fprintf_unfiltered (gdb_stdlog, "unknown???\n");
+ break;
+ }
+
+ return retval;
+}
+
+static void
+debug_to_post_wait (ptid_t ptid, int status)
+{
+ debug_target.to_post_wait (ptid, status);
+
+ fprintf_unfiltered (gdb_stdlog, "target_post_wait (%d, %d)\n",
+ PIDGET (ptid), status);
+}
+
+static void
+debug_print_register (const char * func, int regno)
+{
+ fprintf_unfiltered (gdb_stdlog, "%s ", func);
+ if (regno >= 0 && regno < NUM_REGS + NUM_PSEUDO_REGS
+ && REGISTER_NAME (regno) != NULL && REGISTER_NAME (regno)[0] != '\0')
+ fprintf_unfiltered (gdb_stdlog, "(%s)", REGISTER_NAME (regno));
+ else
+ fprintf_unfiltered (gdb_stdlog, "(%d)", regno);
+ if (regno >= 0)
+ {
+ int i;
+ unsigned char buf[MAX_REGISTER_SIZE];
+ deprecated_read_register_gen (regno, buf);
+ fprintf_unfiltered (gdb_stdlog, " = ");
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ }
+ if (DEPRECATED_REGISTER_RAW_SIZE (regno) <= sizeof (LONGEST))
+ {
+ fprintf_unfiltered (gdb_stdlog, " 0x%s %s",
+ paddr_nz (read_register (regno)),
+ paddr_d (read_register (regno)));
+ }
+ }
+ fprintf_unfiltered (gdb_stdlog, "\n");
+}
+
+static void
+debug_to_fetch_registers (int regno)
+{
+ debug_target.to_fetch_registers (regno);
+ debug_print_register ("target_fetch_registers", regno);
+}
+
+static void
+debug_to_store_registers (int regno)
+{
+ debug_target.to_store_registers (regno);
+ debug_print_register ("target_store_registers", regno);
+ fprintf_unfiltered (gdb_stdlog, "\n");
+}
+
+static void
+debug_to_prepare_to_store (void)
+{
+ debug_target.to_prepare_to_store ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_prepare_to_store ()\n");
+}
+
+static int
+debug_to_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ int retval;
+
+ retval = debug_target.to_xfer_memory (memaddr, myaddr, len, write,
+ attrib, target);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_xfer_memory (0x%x, xxx, %d, %s, xxx) = %d",
+ (unsigned int) memaddr, /* possable truncate long long */
+ len, write ? "write" : "read", retval);
+
+
+
+ if (retval > 0)
+ {
+ int i;
+
+ fputs_unfiltered (", bytes =", gdb_stdlog);
+ for (i = 0; i < retval; i++)
+ {
+ if ((((long) &(myaddr[i])) & 0xf) == 0)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ fprintf_unfiltered (gdb_stdlog, " %02x", myaddr[i] & 0xff);
+ }
+ }
+
+ fputc_unfiltered ('\n', gdb_stdlog);
+
+ return retval;
+}
+
+static void
+debug_to_files_info (struct target_ops *target)
+{
+ debug_target.to_files_info (target);
+
+ fprintf_unfiltered (gdb_stdlog, "target_files_info (xxx)\n");
+}
+
+static int
+debug_to_insert_breakpoint (CORE_ADDR addr, char *save)
+{
+ int retval;
+
+ retval = debug_target.to_insert_breakpoint (addr, save);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_insert_breakpoint (0x%lx, xxx) = %ld\n",
+ (unsigned long) addr,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_remove_breakpoint (CORE_ADDR addr, char *save)
+{
+ int retval;
+
+ retval = debug_target.to_remove_breakpoint (addr, save);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_remove_breakpoint (0x%lx, xxx) = %ld\n",
+ (unsigned long) addr,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_can_use_hw_breakpoint (int type, int cnt, int from_tty)
+{
+ int retval;
+
+ retval = debug_target.to_can_use_hw_breakpoint (type, cnt, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_can_use_hw_breakpoint (%ld, %ld, %ld) = %ld\n",
+ (unsigned long) type,
+ (unsigned long) cnt,
+ (unsigned long) from_tty,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_region_size_ok_for_hw_watchpoint (int byte_count)
+{
+ CORE_ADDR retval;
+
+ retval = debug_target.to_region_size_ok_for_hw_watchpoint (byte_count);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT (%ld) = 0x%lx\n",
+ (unsigned long) byte_count,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_stopped_by_watchpoint (void)
+{
+ int retval;
+
+ retval = debug_target.to_stopped_by_watchpoint ();
+
+ fprintf_unfiltered (gdb_stdlog,
+ "STOPPED_BY_WATCHPOINT () = %ld\n",
+ (unsigned long) retval);
+ return retval;
+}
+
+static CORE_ADDR
+debug_to_stopped_data_address (void)
+{
+ CORE_ADDR retval;
+
+ retval = debug_target.to_stopped_data_address ();
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_stopped_data_address () = 0x%lx\n",
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_insert_hw_breakpoint (CORE_ADDR addr, char *save)
+{
+ int retval;
+
+ retval = debug_target.to_insert_hw_breakpoint (addr, save);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_insert_hw_breakpoint (0x%lx, xxx) = %ld\n",
+ (unsigned long) addr,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_remove_hw_breakpoint (CORE_ADDR addr, char *save)
+{
+ int retval;
+
+ retval = debug_target.to_remove_hw_breakpoint (addr, save);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_remove_hw_breakpoint (0x%lx, xxx) = %ld\n",
+ (unsigned long) addr,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ int retval;
+
+ retval = debug_target.to_insert_watchpoint (addr, len, type);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
+ (unsigned long) addr, len, type, (unsigned long) retval);
+ return retval;
+}
+
+static int
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ int retval;
+
+ retval = debug_target.to_insert_watchpoint (addr, len, type);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
+ (unsigned long) addr, len, type, (unsigned long) retval);
+ return retval;
+}
+
+static void
+debug_to_terminal_init (void)
+{
+ debug_target.to_terminal_init ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_terminal_init ()\n");
+}
+
+static void
+debug_to_terminal_inferior (void)
+{
+ debug_target.to_terminal_inferior ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_terminal_inferior ()\n");
+}
+
+static void
+debug_to_terminal_ours_for_output (void)
+{
+ debug_target.to_terminal_ours_for_output ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_terminal_ours_for_output ()\n");
+}
+
+static void
+debug_to_terminal_ours (void)
+{
+ debug_target.to_terminal_ours ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_terminal_ours ()\n");
+}
+
+static void
+debug_to_terminal_save_ours (void)
+{
+ debug_target.to_terminal_save_ours ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_terminal_save_ours ()\n");
+}
+
+static void
+debug_to_terminal_info (char *arg, int from_tty)
+{
+ debug_target.to_terminal_info (arg, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog, "target_terminal_info (%s, %d)\n", arg,
+ from_tty);
+}
+
+static void
+debug_to_kill (void)
+{
+ debug_target.to_kill ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_kill ()\n");
+}
+
+static void
+debug_to_load (char *args, int from_tty)
+{
+ debug_target.to_load (args, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog, "target_load (%s, %d)\n", args, from_tty);
+}
+
+static int
+debug_to_lookup_symbol (char *name, CORE_ADDR *addrp)
+{
+ int retval;
+
+ retval = debug_target.to_lookup_symbol (name, addrp);
+
+ fprintf_unfiltered (gdb_stdlog, "target_lookup_symbol (%s, xxx)\n", name);
+
+ return retval;
+}
+
+static void
+debug_to_create_inferior (char *exec_file, char *args, char **env)
+{
+ debug_target.to_create_inferior (exec_file, args, env);
+
+ fprintf_unfiltered (gdb_stdlog, "target_create_inferior (%s, %s, xxx)\n",
+ exec_file, args);
+}
+
+static void
+debug_to_post_startup_inferior (ptid_t ptid)
+{
+ debug_target.to_post_startup_inferior (ptid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_post_startup_inferior (%d)\n",
+ PIDGET (ptid));
+}
+
+static void
+debug_to_acknowledge_created_inferior (int pid)
+{
+ debug_target.to_acknowledge_created_inferior (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_acknowledge_created_inferior (%d)\n",
+ pid);
+}
+
+static int
+debug_to_insert_fork_catchpoint (int pid)
+{
+ int retval;
+
+ retval = debug_target.to_insert_fork_catchpoint (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_insert_fork_catchpoint (%d) = %d\n",
+ pid, retval);
+
+ return retval;
+}
+
+static int
+debug_to_remove_fork_catchpoint (int pid)
+{
+ int retval;
+
+ retval = debug_target.to_remove_fork_catchpoint (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_remove_fork_catchpoint (%d) = %d\n",
+ pid, retval);
+
+ return retval;
+}
+
+static int
+debug_to_insert_vfork_catchpoint (int pid)
+{
+ int retval;
+
+ retval = debug_target.to_insert_vfork_catchpoint (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_insert_vfork_catchpoint (%d)= %d\n",
+ pid, retval);
+
+ return retval;
+}
+
+static int
+debug_to_remove_vfork_catchpoint (int pid)
+{
+ int retval;
+
+ retval = debug_target.to_remove_vfork_catchpoint (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_remove_vfork_catchpoint (%d) = %d\n",
+ pid, retval);
+
+ return retval;
+}
+
+static int
+debug_to_follow_fork (int follow_child)
+{
+ int retval = debug_target.to_follow_fork (follow_child);
+
+ fprintf_unfiltered (gdb_stdlog, "target_follow_fork (%d) = %d\n",
+ follow_child, retval);
+
+ return retval;
+}
+
+static int
+debug_to_insert_exec_catchpoint (int pid)
+{
+ int retval;
+
+ retval = debug_target.to_insert_exec_catchpoint (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_insert_exec_catchpoint (%d) = %d\n",
+ pid, retval);
+
+ return retval;
+}
+
+static int
+debug_to_remove_exec_catchpoint (int pid)
+{
+ int retval;
+
+ retval = debug_target.to_remove_exec_catchpoint (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_remove_exec_catchpoint (%d) = %d\n",
+ pid, retval);
+
+ return retval;
+}
+
+static int
+debug_to_reported_exec_events_per_exec_call (void)
+{
+ int reported_exec_events;
+
+ reported_exec_events = debug_target.to_reported_exec_events_per_exec_call ();
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_reported_exec_events_per_exec_call () = %d\n",
+ reported_exec_events);
+
+ return reported_exec_events;
+}
+
+static int
+debug_to_has_exited (int pid, int wait_status, int *exit_status)
+{
+ int has_exited;
+
+ has_exited = debug_target.to_has_exited (pid, wait_status, exit_status);
+
+ fprintf_unfiltered (gdb_stdlog, "target_has_exited (%d, %d, %d) = %d\n",
+ pid, wait_status, *exit_status, has_exited);
+
+ return has_exited;
+}
+
+static void
+debug_to_mourn_inferior (void)
+{
+ debug_target.to_mourn_inferior ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_mourn_inferior ()\n");
+}
+
+static int
+debug_to_can_run (void)
+{
+ int retval;
+
+ retval = debug_target.to_can_run ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_can_run () = %d\n", retval);
+
+ return retval;
+}
+
+static void
+debug_to_notice_signals (ptid_t ptid)
+{
+ debug_target.to_notice_signals (ptid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_notice_signals (%d)\n",
+ PIDGET (ptid));
+}
+
+static int
+debug_to_thread_alive (ptid_t ptid)
+{
+ int retval;
+
+ retval = debug_target.to_thread_alive (ptid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_thread_alive (%d) = %d\n",
+ PIDGET (ptid), retval);
+
+ return retval;
+}
+
+static void
+debug_to_find_new_threads (void)
+{
+ debug_target.to_find_new_threads ();
+
+ fputs_unfiltered ("target_find_new_threads ()\n", gdb_stdlog);
+}
+
+static void
+debug_to_stop (void)
+{
+ debug_target.to_stop ();
+
+ fprintf_unfiltered (gdb_stdlog, "target_stop ()\n");
+}
+
+static LONGEST
+debug_to_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ LONGEST retval;
+
+ retval = debug_target.to_xfer_partial (&debug_target, object, annex,
+ readbuf, writebuf, offset, len);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_xfer_partial (%d, %s, 0x%lx, 0x%lx, 0x%s, %s) = %s\n",
+ (int) object, (annex ? annex : "(null)"),
+ (long) readbuf, (long) writebuf, paddr_nz (offset),
+ paddr_d (len), paddr_d (retval));
+
+ return retval;
+}
+
+static void
+debug_to_rcmd (char *command,
+ struct ui_file *outbuf)
+{
+ debug_target.to_rcmd (command, outbuf);
+ fprintf_unfiltered (gdb_stdlog, "target_rcmd (%s, ...)\n", command);
+}
+
+static struct symtab_and_line *
+debug_to_enable_exception_callback (enum exception_event_kind kind, int enable)
+{
+ struct symtab_and_line *result;
+ result = debug_target.to_enable_exception_callback (kind, enable);
+ fprintf_unfiltered (gdb_stdlog,
+ "target get_exception_callback_sal (%d, %d)\n",
+ kind, enable);
+ return result;
+}
+
+static struct exception_event_record *
+debug_to_get_current_exception_event (void)
+{
+ struct exception_event_record *result;
+ result = debug_target.to_get_current_exception_event ();
+ fprintf_unfiltered (gdb_stdlog, "target get_current_exception_event ()\n");
+ return result;
+}
+
+static char *
+debug_to_pid_to_exec_file (int pid)
+{
+ char *exec_file;
+
+ exec_file = debug_target.to_pid_to_exec_file (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_pid_to_exec_file (%d) = %s\n",
+ pid, exec_file);
+
+ return exec_file;
+}
+
+static void
+setup_target_debug (void)
+{
+ memcpy (&debug_target, &current_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_post_attach = debug_to_post_attach;
+ current_target.to_detach = debug_to_detach;
+ current_target.to_disconnect = debug_to_disconnect;
+ current_target.to_resume = debug_to_resume;
+ current_target.to_wait = debug_to_wait;
+ current_target.to_post_wait = debug_to_post_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_can_use_hw_breakpoint = debug_to_can_use_hw_breakpoint;
+ current_target.to_insert_hw_breakpoint = debug_to_insert_hw_breakpoint;
+ current_target.to_remove_hw_breakpoint = debug_to_remove_hw_breakpoint;
+ current_target.to_insert_watchpoint = debug_to_insert_watchpoint;
+ current_target.to_remove_watchpoint = debug_to_remove_watchpoint;
+ current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint;
+ current_target.to_stopped_data_address = debug_to_stopped_data_address;
+ current_target.to_region_size_ok_for_hw_watchpoint = debug_to_region_size_ok_for_hw_watchpoint;
+ 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_save_ours = debug_to_terminal_save_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_post_startup_inferior = debug_to_post_startup_inferior;
+ current_target.to_acknowledge_created_inferior = debug_to_acknowledge_created_inferior;
+ current_target.to_insert_fork_catchpoint = debug_to_insert_fork_catchpoint;
+ current_target.to_remove_fork_catchpoint = debug_to_remove_fork_catchpoint;
+ current_target.to_insert_vfork_catchpoint = debug_to_insert_vfork_catchpoint;
+ current_target.to_remove_vfork_catchpoint = debug_to_remove_vfork_catchpoint;
+ current_target.to_follow_fork = debug_to_follow_fork;
+ current_target.to_insert_exec_catchpoint = debug_to_insert_exec_catchpoint;
+ current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint;
+ current_target.to_reported_exec_events_per_exec_call = debug_to_reported_exec_events_per_exec_call;
+ current_target.to_has_exited = debug_to_has_exited;
+ 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_find_new_threads = debug_to_find_new_threads;
+ current_target.to_stop = debug_to_stop;
+ current_target.to_xfer_partial = debug_to_xfer_partial;
+ current_target.to_rcmd = debug_to_rcmd;
+ current_target.to_enable_exception_callback = debug_to_enable_exception_callback;
+ current_target.to_get_current_exception_event = debug_to_get_current_exception_event;
+ current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
+
+}
+
+
+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.";
+
+static void
+do_monitor_command (char *cmd,
+ int from_tty)
+{
+ if ((current_target.to_rcmd
+ == (void (*) (char *, struct ui_file *)) tcomplain)
+ || (current_target.to_rcmd == debug_to_rcmd
+ && (debug_target.to_rcmd
+ == (void (*) (char *, struct ui_file *)) tcomplain)))
+ {
+ error ("\"monitor\" command not supported by this target.\n");
+ }
+ target_rcmd (cmd, gdb_stdtarg);
+}
+
+void
+initialize_targets (void)
+{
+ init_dummy_target ();
+ push_target (&dummy_target);
+
+ add_info ("target", target_info, targ_desc);
+ add_info ("files", target_info, targ_desc);
+
+ add_show_from_set
+ (add_set_cmd ("target", class_maintenance, var_zinteger,
+ (char *) &targetdebug,
+ "Set target debugging.\n\
+When non-zero, target debugging is enabled.", &setdebuglist),
+ &showdebuglist);
+
+ add_setshow_boolean_cmd ("trust-readonly-sections", class_support,
+ &trust_readonly, "\
+Set mode for reading from readonly sections.\n\
+When this mode is on, memory reads from readonly sections (such as .text)\n\
+will be read from the object file instead of from the target. This will\n\
+result in significant performance improvement for remote targets.", "\
+Show mode for reading from readonly sections.\n",
+ NULL, NULL,
+ &setlist, &showlist);
+
+ add_com ("monitor", class_obscure, do_monitor_command,
+ "Send a command to the remote monitor (remote targets only).");
+
+ target_dcache = dcache_init ();
+}
diff --git a/contrib/gdb/gdb/target.h b/contrib/gdb/gdb/target.h
new file mode 100644
index 0000000..94ea970
--- /dev/null
+++ b/contrib/gdb/gdb/target.h
@@ -0,0 +1,1251 @@
+/* Interface between GDB and target environments, including files and processes
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004 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
+
+struct objfile;
+struct ui_file;
+struct mem_attrib;
+struct target_ops;
+
+/* 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"
+#include "symtab.h"
+#include "dcache.h"
+#include "memattr.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 */
+ thread_stratum /* Executing threads */
+ };
+
+enum thread_control_capabilities
+ {
+ tc_none = 0, /* Default: can't control thread execution. */
+ tc_schedlock = 1, /* Can lock the thread scheduler. */
+ tc_switch = 2 /* Can switch the running thread on demand. */
+ };
+
+/* 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,
+
+ /* The program has forked. A "related" process' ID is in
+ value.related_pid. I.e., if the child forks, value.related_pid
+ is the parent's ID. */
+
+ TARGET_WAITKIND_FORKED,
+
+ /* The program has vforked. A "related" process's ID is in
+ value.related_pid. */
+
+ TARGET_WAITKIND_VFORKED,
+
+ /* The program has exec'ed a new executable file. The new file's
+ pathname is pointed to by value.execd_pathname. */
+
+ TARGET_WAITKIND_EXECD,
+
+ /* The program has entered or returned from a system call. On
+ HP-UX, this is used in the hardware watchpoint implementation.
+ The syscall's unique integer ID number is in value.syscall_id */
+
+ TARGET_WAITKIND_SYSCALL_ENTRY,
+ TARGET_WAITKIND_SYSCALL_RETURN,
+
+ /* 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,
+
+ /* An event has occured, but we should wait again.
+ Remote_async_wait() returns this when there is an event
+ on the inferior, but the rest of the world is not interested in
+ it. The inferior has not stopped, but has just sent some output
+ to the console, for instance. In this case, we want to go back
+ to the event loop and wait there for another event from the
+ inferior, rather than being stuck in the remote_async_wait()
+ function. This way the event loop is responsive to other events,
+ like for instance the user typing. */
+ TARGET_WAITKIND_IGNORE
+ };
+
+struct target_waitstatus
+ {
+ enum target_waitkind kind;
+
+ /* Forked child pid, execd pathname, exit status or signal number. */
+ union
+ {
+ int integer;
+ enum target_signal sig;
+ int related_pid;
+ char *execd_pathname;
+ int syscall_id;
+ }
+ value;
+ };
+
+/* Possible types of events that the inferior handler will have to
+ deal with. */
+enum inferior_event_type
+ {
+ /* There is a request to quit the inferior, abandon it. */
+ INF_QUIT_REQ,
+ /* Process a normal inferior event which will result in target_wait
+ being called. */
+ INF_REG_EVENT,
+ /* Deal with an error on the inferior. */
+ INF_ERROR,
+ /* We are called because a timer went off. */
+ INF_TIMER,
+ /* We are called to do stuff after the inferior stops. */
+ INF_EXEC_COMPLETE,
+ /* We are called to do some stuff after the inferior stops, but we
+ are expected to reenter the proceed() and
+ handle_inferior_event() functions. This is used only in case of
+ 'step n' like commands. */
+ INF_EXEC_CONTINUE
+ };
+
+/* Return the string for a signal. */
+extern char *target_signal_to_string (enum target_signal);
+
+/* Return the name (SIGHUP, etc.) for a signal. */
+extern char *target_signal_to_name (enum target_signal);
+
+/* Given a name (SIGHUP, etc.), return its signal. */
+enum target_signal target_signal_from_name (char *);
+
+/* Request the transfer of up to LEN 8-bit bytes of the target's
+ OBJECT. The OFFSET, for a seekable object, specifies the starting
+ point. The ANNEX can be used to provide additional data-specific
+ information to the target.
+
+ Return the number of bytes actually transfered, zero when no
+ further transfer is possible, and -1 when the transfer is not
+ supported.
+
+ NOTE: cagney/2003-10-17: The current interface does not support a
+ "retry" mechanism. Instead it assumes that at least one byte will
+ be transfered on each call.
+
+ NOTE: cagney/2003-10-17: The current interface can lead to
+ fragmented transfers. Lower target levels should not implement
+ hacks, such as enlarging the transfer, in an attempt to compensate
+ for this. Instead, the target stack should be extended so that it
+ implements supply/collect methods and a look-aside object cache.
+ With that available, the lowest target can safely and freely "push"
+ data up the stack.
+
+ NOTE: cagney/2003-10-17: Unlike the old query and the memory
+ transfer mechanisms, these methods are explicitly parameterized by
+ the target that it should be applied to.
+
+ NOTE: cagney/2003-10-17: Just like the old query and memory xfer
+ methods, these new methods perform partial transfers. The only
+ difference is that these new methods thought to include "partial"
+ in the name. The old code's failure to do this lead to much
+ confusion and duplication of effort as each target object attempted
+ to locally take responsibility for something it didn't have to
+ worry about.
+
+ NOTE: cagney/2003-10-17: With a TARGET_OBJECT_KOD object, for
+ backward compatibility with the "target_query" method that this
+ replaced, when OFFSET and LEN are both zero, return the "minimum"
+ buffer size. See "remote.c" for further information. */
+
+enum target_object
+{
+ /* Kernel Object Display transfer. See "kod.c" and "remote.c". */
+ TARGET_OBJECT_KOD,
+ /* AVR target specific transfer. See "avr-tdep.c" and "remote.c". */
+ TARGET_OBJECT_AVR,
+ /* Transfer up-to LEN bytes of memory starting at OFFSET. */
+ TARGET_OBJECT_MEMORY,
+ /* Kernel Unwind Table. See "ia64-tdep.c". */
+ TARGET_OBJECT_UNWIND_TABLE,
+ /* Transfer auxilliary vector. */
+ TARGET_OBJECT_AUXV,
+ /* StackGhost cookie. See "sparc-tdep.c". */
+ TARGET_OBJECT_WCOOKIE,
+ /* Dirty registers. See "ia64-tdep.c". */
+ TARGET_OBJECT_DIRTY
+
+ /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
+};
+
+extern LONGEST target_read_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, void *buf,
+ ULONGEST offset, LONGEST len);
+
+extern LONGEST target_write_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const void *buf,
+ ULONGEST offset, LONGEST len);
+
+/* Wrappers to perform the full transfer. */
+extern LONGEST target_read (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, void *buf,
+ ULONGEST offset, LONGEST len);
+
+extern LONGEST target_write (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const void *buf,
+ ULONGEST offset, LONGEST len);
+
+/* Wrappers to target read/write that perform memory transfers. They
+ throw an error if the memory transfer fails.
+
+ NOTE: cagney/2003-10-23: The naming schema is lifted from
+ "frame.h". The parameter order is lifted from get_frame_memory,
+ which in turn lifted it from read_memory. */
+
+extern void get_target_memory (struct target_ops *ops, CORE_ADDR addr,
+ void *buf, LONGEST len);
+extern ULONGEST get_target_memory_unsigned (struct target_ops *ops,
+ CORE_ADDR addr, int len);
+
+
+/* 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) (void);
+
+struct thread_info; /* fwd decl for parameter list below: */
+
+struct target_ops
+ {
+ struct target_ops *beneath; /* To the target under this one. */
+ 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). */
+ /* Per-target scratch pad. */
+ void *to_data;
+ /* 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. */
+ void (*to_open) (char *, int);
+ /* Old targets with a static target vector provide "to_close".
+ New re-entrant targets provide "to_xclose" and that is expected
+ to xfree everything (including the "struct target_ops"). */
+ void (*to_xclose) (struct target_ops *targ, int quitting);
+ void (*to_close) (int);
+ void (*to_attach) (char *, int);
+ void (*to_post_attach) (int);
+ void (*to_detach) (char *, int);
+ void (*to_disconnect) (char *, int);
+ void (*to_resume) (ptid_t, int, enum target_signal);
+ ptid_t (*to_wait) (ptid_t, struct target_waitstatus *);
+ void (*to_post_wait) (ptid_t, int);
+ void (*to_fetch_registers) (int);
+ void (*to_store_registers) (int);
+ void (*to_prepare_to_store) (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) (CORE_ADDR memaddr, char *myaddr,
+ int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
+
+ void (*to_files_info) (struct target_ops *);
+ int (*to_insert_breakpoint) (CORE_ADDR, char *);
+ int (*to_remove_breakpoint) (CORE_ADDR, char *);
+ int (*to_can_use_hw_breakpoint) (int, int, int);
+ int (*to_insert_hw_breakpoint) (CORE_ADDR, char *);
+ int (*to_remove_hw_breakpoint) (CORE_ADDR, char *);
+ int (*to_remove_watchpoint) (CORE_ADDR, int, int);
+ int (*to_insert_watchpoint) (CORE_ADDR, int, int);
+ int (*to_stopped_by_watchpoint) (void);
+ int to_have_continuable_watchpoint;
+ CORE_ADDR (*to_stopped_data_address) (void);
+ int (*to_region_size_ok_for_hw_watchpoint) (int);
+ void (*to_terminal_init) (void);
+ void (*to_terminal_inferior) (void);
+ void (*to_terminal_ours_for_output) (void);
+ void (*to_terminal_ours) (void);
+ void (*to_terminal_save_ours) (void);
+ void (*to_terminal_info) (char *, int);
+ void (*to_kill) (void);
+ void (*to_load) (char *, int);
+ int (*to_lookup_symbol) (char *, CORE_ADDR *);
+ void (*to_create_inferior) (char *, char *, char **);
+ void (*to_post_startup_inferior) (ptid_t);
+ void (*to_acknowledge_created_inferior) (int);
+ int (*to_insert_fork_catchpoint) (int);
+ int (*to_remove_fork_catchpoint) (int);
+ int (*to_insert_vfork_catchpoint) (int);
+ int (*to_remove_vfork_catchpoint) (int);
+ int (*to_follow_fork) (int);
+ int (*to_insert_exec_catchpoint) (int);
+ int (*to_remove_exec_catchpoint) (int);
+ int (*to_reported_exec_events_per_exec_call) (void);
+ int (*to_has_exited) (int, int, int *);
+ void (*to_mourn_inferior) (void);
+ int (*to_can_run) (void);
+ void (*to_notice_signals) (ptid_t ptid);
+ int (*to_thread_alive) (ptid_t ptid);
+ void (*to_find_new_threads) (void);
+ char *(*to_pid_to_str) (ptid_t);
+ char *(*to_extra_thread_info) (struct thread_info *);
+ void (*to_stop) (void);
+ void (*to_rcmd) (char *command, struct ui_file *output);
+ struct symtab_and_line *(*to_enable_exception_callback) (enum
+ exception_event_kind,
+ int);
+ struct exception_event_record *(*to_get_current_exception_event) (void);
+ char *(*to_pid_to_exec_file) (int pid);
+ enum strata to_stratum;
+ int to_has_all_memory;
+ int to_has_memory;
+ int to_has_stack;
+ int to_has_registers;
+ int to_has_execution;
+ int to_has_thread_control; /* control thread execution */
+ struct section_table
+ *to_sections;
+ struct section_table
+ *to_sections_end;
+ /* ASYNC target controls */
+ int (*to_can_async_p) (void);
+ int (*to_is_async_p) (void);
+ void (*to_async) (void (*cb) (enum inferior_event_type, void *context),
+ void *context);
+ int to_async_mask_value;
+ int (*to_find_memory_regions) (int (*) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *);
+ char * (*to_make_corefile_notes) (bfd *, int *);
+
+ /* Return the thread-local address at OFFSET in the
+ thread-local storage for the thread PTID and the shared library
+ or executable file given by OBJFILE. If that block of
+ thread-local storage hasn't been allocated yet, this function
+ may return an error. */
+ CORE_ADDR (*to_get_thread_local_address) (ptid_t ptid,
+ struct objfile *objfile,
+ CORE_ADDR offset);
+
+ /* Perform partial transfers on OBJECT. See target_read_partial
+ and target_write_partial for details of each variant. One, and
+ only one, of readbuf or writebuf must be non-NULL. */
+ LONGEST (*to_xfer_partial) (struct target_ops *ops,
+ enum target_object object, const char *annex,
+ void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len);
+
+ 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;
+
+/* 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)
+
+/* Does whatever cleanup is required for a target that we are no
+ longer going to be calling. QUITTING indicates that GDB is exiting
+ and should not get hung on an error (otherwise it is important to
+ perform clean termination, even if it takes a while). This routine
+ is automatically always called when popping the target off the
+ target stack (to_beneath is undefined). Closing file descriptors
+ and freeing all memory allocated memory are typical things it
+ should do. */
+
+void target_close (struct target_ops *targ, int 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)
+
+/* The target_attach operation places a process under debugger control,
+ and stops the process.
+
+ This operation provides a target-specific hook that allows the
+ necessary bookkeeping to be performed after an attach completes. */
+#define target_post_attach(pid) \
+ (*current_target.to_post_attach) (pid)
+
+/* 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 (char *, int);
+
+/* Disconnect from the current target without resuming it (leaving it
+ waiting for a debugger). */
+
+extern void target_disconnect (char *, int);
+
+/* Resume execution of the target process PTID. 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(ptid, step, siggnal) \
+ do { \
+ dcache_invalidate(target_dcache); \
+ (*current_target.to_resume) (ptid, step, siggnal); \
+ } while (0)
+
+/* Wait for process pid to do something. PTID = -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 throw_exception() 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(ptid, status) \
+ (*current_target.to_wait) (ptid, status)
+
+/* The target_wait operation waits for a process event to occur, and
+ thereby stop the process.
+
+ On some targets, certain events may happen in sequences. gdb's
+ correct response to any single event of such a sequence may require
+ knowledge of what earlier events in the sequence have been seen.
+
+ This operation provides a target-specific hook that allows the
+ necessary bookkeeping to be performed to track such sequences. */
+
+#define target_post_wait(ptid, status) \
+ (*current_target.to_post_wait) (ptid, status)
+
+/* Fetch at least 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 DCACHE *target_dcache;
+
+extern int do_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib);
+
+extern int target_read_string (CORE_ADDR, char **, int, int *);
+
+extern int target_read_memory (CORE_ADDR memaddr, char *myaddr, int len);
+
+extern int target_write_memory (CORE_ADDR memaddr, char *myaddr, int len);
+
+extern int xfer_memory (CORE_ADDR, char *, int, int,
+ struct mem_attrib *, struct target_ops *);
+
+extern int child_xfer_memory (CORE_ADDR, char *, int, int,
+ struct mem_attrib *, struct target_ops *);
+
+/* Make a single attempt at transfering LEN bytes. On a successful
+ transfer, the number of bytes actually transfered is returned and
+ ERR is set to 0. When a transfer fails, -1 is returned (the number
+ of bytes actually transfered is not defined) and ERR is set to a
+ non-zero error indication. */
+
+extern int target_read_memory_partial (CORE_ADDR addr, char *buf, int len,
+ int *err);
+
+extern int target_write_memory_partial (CORE_ADDR addr, char *buf, int len,
+ int *err);
+
+extern char *child_pid_to_exec_file (int);
+
+extern char *child_core_file_to_sym_file (char *);
+
+#if defined(CHILD_POST_ATTACH)
+extern void child_post_attach (int);
+#endif
+
+extern void child_post_wait (ptid_t, int);
+
+extern void child_post_startup_inferior (ptid_t);
+
+extern void child_acknowledge_created_inferior (int);
+
+extern int child_insert_fork_catchpoint (int);
+
+extern int child_remove_fork_catchpoint (int);
+
+extern int child_insert_vfork_catchpoint (int);
+
+extern int child_remove_vfork_catchpoint (int);
+
+extern void child_acknowledge_created_inferior (int);
+
+extern int child_follow_fork (int);
+
+extern int child_insert_exec_catchpoint (int);
+
+extern int child_remove_exec_catchpoint (int);
+
+extern int child_reported_exec_events_per_exec_call (void);
+
+extern int child_has_exited (int, int, int *);
+
+extern int child_thread_alive (ptid_t);
+
+/* From infrun.c. */
+
+extern int inferior_has_forked (int pid, int *child_pid);
+
+extern int inferior_has_vforked (int pid, int *child_pid);
+
+extern int inferior_has_execd (int pid, char **execd_pathname);
+
+/* From exec.c */
+
+extern void print_section_info (struct target_ops *, bfd *);
+
+/* Print a line about the current target. */
+
+#define target_files_info() \
+ (*current_target.to_files_info) (&current_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 the number of
+ breakpoint bytes indicated by BREAKPOINT_FROM_PC. 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) ()
+
+/* Save our terminal settings.
+ This is called from TUI after entering or leaving the curses
+ mode. Since curses modifies our terminal this call is here
+ to take this change into account. */
+
+#define target_terminal_save_ours() \
+ (*current_target.to_terminal_save_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. */
+
+extern void target_load (char *arg, int 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_ptid 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)
+
+
+/* Some targets (such as ttrace-based HPUX) don't allow us to request
+ notification of inferior events such as fork and vork immediately
+ after the inferior is created. (This because of how gdb gets an
+ inferior created via invoking a shell to do it. In such a scenario,
+ if the shell init file has commands in it, the shell will fork and
+ exec for each of those commands, and we will see each such fork
+ event. Very bad.)
+
+ Such targets will supply an appropriate definition for this function. */
+
+#define target_post_startup_inferior(ptid) \
+ (*current_target.to_post_startup_inferior) (ptid)
+
+/* On some targets, the sequence of starting up an inferior requires
+ some synchronization between gdb and the new inferior process, PID. */
+
+#define target_acknowledge_created_inferior(pid) \
+ (*current_target.to_acknowledge_created_inferior) (pid)
+
+/* On some targets, we can catch an inferior fork or vfork event when
+ it occurs. These functions insert/remove an already-created
+ catchpoint for such events. */
+
+#define target_insert_fork_catchpoint(pid) \
+ (*current_target.to_insert_fork_catchpoint) (pid)
+
+#define target_remove_fork_catchpoint(pid) \
+ (*current_target.to_remove_fork_catchpoint) (pid)
+
+#define target_insert_vfork_catchpoint(pid) \
+ (*current_target.to_insert_vfork_catchpoint) (pid)
+
+#define target_remove_vfork_catchpoint(pid) \
+ (*current_target.to_remove_vfork_catchpoint) (pid)
+
+/* If the inferior forks or vforks, this function will be called at
+ the next resume in order to perform any bookkeeping and fiddling
+ necessary to continue debugging either the parent or child, as
+ requested, and releasing the other. Information about the fork
+ or vfork event is available via get_last_target_status ().
+ This function returns 1 if the inferior should not be resumed
+ (i.e. there is another event pending). */
+
+#define target_follow_fork(follow_child) \
+ (*current_target.to_follow_fork) (follow_child)
+
+/* On some targets, we can catch an inferior exec event when it
+ occurs. These functions insert/remove an already-created
+ catchpoint for such events. */
+
+#define target_insert_exec_catchpoint(pid) \
+ (*current_target.to_insert_exec_catchpoint) (pid)
+
+#define target_remove_exec_catchpoint(pid) \
+ (*current_target.to_remove_exec_catchpoint) (pid)
+
+/* Returns the number of exec events that are reported when a process
+ invokes a flavor of the exec() system call on this target, if exec
+ events are being reported. */
+
+#define target_reported_exec_events_per_exec_call() \
+ (*current_target.to_reported_exec_events_per_exec_call) ()
+
+/* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the
+ exit code of PID, if any. */
+
+#define target_has_exited(pid,wait_status,exit_status) \
+ (*current_target.to_has_exited) (pid,wait_status,exit_status)
+
+/* The debugger has completed a blocking wait() call. There is now
+ some process event that must be processed. This function should
+ be defined by those targets that require the debugger to perform
+ cleanup or internal state changes in response to the process event. */
+
+/* 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(ptid) \
+ (*current_target.to_notice_signals) (ptid)
+
+/* Check to see if a thread is still alive. */
+
+#define target_thread_alive(ptid) \
+ (*current_target.to_thread_alive) (ptid)
+
+/* Query for new threads and add them to the thread list. */
+
+#define target_find_new_threads() \
+ (*current_target.to_find_new_threads) (); \
+
+/* 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
+
+/* Send the specified COMMAND to the target's monitor
+ (shell,interpreter) for execution. The result of the query is
+ placed in OUTBUF. */
+
+#define target_rcmd(command, outbuf) \
+ (*current_target.to_rcmd) (command, outbuf)
+
+
+/* Get the symbol information for a breakpointable routine called when
+ an exception event occurs.
+ Intended mainly for C++, and for those
+ platforms/implementations where such a callback mechanism is available,
+ e.g. HP-UX with ANSI C++ (aCC). Some compilers (e.g. g++) support
+ different mechanisms for debugging exceptions. */
+
+#define target_enable_exception_callback(kind, enable) \
+ (*current_target.to_enable_exception_callback) (kind, enable)
+
+/* Get the current exception event kind -- throw or catch, etc. */
+
+#define target_get_current_exception_event() \
+ (*current_target.to_get_current_exception_event) ()
+
+/* 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)
+
+/* Can the target support the debugger control of thread execution?
+ a) Can it lock the thread scheduler?
+ b) Can it switch the currently running thread? */
+
+#define target_can_lock_scheduler \
+ (current_target.to_has_thread_control & tc_schedlock)
+
+#define target_can_switch_threads \
+ (current_target.to_has_thread_control & tc_switch)
+
+/* Can the target support asynchronous execution? */
+#define target_can_async_p() (current_target.to_can_async_p ())
+
+/* Is the target in asynchronous execution mode? */
+#define target_is_async_p() (current_target.to_is_async_p())
+
+/* Put the target in async mode with the specified callback function. */
+#define target_async(CALLBACK,CONTEXT) \
+ (current_target.to_async((CALLBACK), (CONTEXT)))
+
+/* This is to be used ONLY within call_function_by_hand(). It provides
+ a workaround, to have inferior function calls done in sychronous
+ mode, even though the target is asynchronous. After
+ target_async_mask(0) is called, calls to target_can_async_p() will
+ return FALSE , so that target_resume() will not try to start the
+ target asynchronously. After the inferior stops, we IMMEDIATELY
+ restore the previous nature of the target, by calling
+ target_async_mask(1). After that, target_can_async_p() will return
+ TRUE. ANY OTHER USE OF THIS FEATURE IS DEPRECATED.
+
+ FIXME ezannoni 1999-12-13: we won't need this once we move
+ the turning async on and off to the single execution commands,
+ from where it is done currently, in remote_resume(). */
+
+#define target_async_mask_value \
+ (current_target.to_async_mask_value)
+
+extern int target_async_mask (int mask);
+
+extern void target_link (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'. */
+
+#undef target_pid_to_str
+#define target_pid_to_str(PID) current_target.to_pid_to_str (PID)
+
+#ifndef target_tid_to_str
+#define target_tid_to_str(PID) \
+ target_pid_to_str (PID)
+extern char *normal_pid_to_str (ptid_t ptid);
+#endif
+
+/* Return a short string describing extra information about PID,
+ e.g. "sleeping", "runnable", "running on LWP 3". Null return value
+ is okay. */
+
+#define target_extra_thread_info(TP) \
+ (current_target.to_extra_thread_info (TP))
+
+/*
+ * New Objfile Event Hook:
+ *
+ * Sometimes a GDB component wants to get notified whenever a new
+ * objfile is loaded. Mainly this is used by thread-debugging
+ * implementations that need to know when symbols for the target
+ * thread implemenation are available.
+ *
+ * The old way of doing this is to define a macro 'target_new_objfile'
+ * that points to the function that you want to be called on every
+ * objfile/shlib load.
+ *
+ * The new way is to grab the function pointer, 'target_new_objfile_hook',
+ * and point it to the function that you want to be called on every
+ * objfile/shlib load.
+ *
+ * If multiple clients are willing to be cooperative, they can each
+ * save a pointer to the previous value of target_new_objfile_hook
+ * before modifying it, and arrange for their function to call the
+ * previous function in the chain. In that way, multiple clients
+ * can receive this notification (something like with signal handlers).
+ */
+
+extern void (*target_new_objfile_hook) (struct objfile *);
+
+#ifndef target_pid_or_tid_to_str
+#define target_pid_or_tid_to_str(ID) \
+ target_pid_to_str (ID)
+#endif
+
+/* Attempts to find the pathname of the executable file
+ that was run to create a specified process.
+
+ The process PID must be stopped when this operation is used.
+
+ If the executable file cannot be determined, NULL is returned.
+
+ Else, a pointer to a character string containing the pathname
+ is returned. This string should be copied into a buffer by
+ the client if the string will not be immediately used, or if
+ it must persist. */
+
+#define target_pid_to_exec_file(pid) \
+ (current_target.to_pid_to_exec_file) (pid)
+
+/*
+ * Iterator function for target memory regions.
+ * Calls a callback function once for each memory region 'mapped'
+ * in the child process. Defined as a simple macro rather than
+ * as a function macro so that it can be tested for nullity.
+ */
+
+#define target_find_memory_regions(FUNC, DATA) \
+ (current_target.to_find_memory_regions) (FUNC, DATA)
+
+/*
+ * Compose corefile .note section.
+ */
+
+#define target_make_corefile_notes(BFD, SIZE_P) \
+ (current_target.to_make_corefile_notes) (BFD, SIZE_P)
+
+/* Thread-local values. */
+#define target_get_thread_local_address \
+ (current_target.to_get_thread_local_address)
+#define target_get_thread_local_address_p() \
+ (target_get_thread_local_address != NULL)
+
+/* Hook to call target dependent 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) \
+ (*current_target.to_stopped_by_watchpoint) ()
+#endif
+
+/* Non-zero if we have continuable watchpoints */
+
+#ifndef HAVE_CONTINUABLE_WATCHPOINT
+#define HAVE_CONTINUABLE_WATCHPOINT \
+ (current_target.to_have_continuable_watchpoint)
+#endif
+
+/* HP-UX supplies these operations, which respectively disable and enable
+ the memory page-protections that are used to implement hardware watchpoints
+ on that platform. See wait_for_inferior's use of these. */
+
+#if !defined(TARGET_DISABLE_HW_WATCHPOINTS)
+#define TARGET_DISABLE_HW_WATCHPOINTS(pid)
+#endif
+
+#if !defined(TARGET_ENABLE_HW_WATCHPOINTS)
+#define TARGET_ENABLE_HW_WATCHPOINTS(pid)
+#endif
+
+/* Provide defaults for hardware watchpoint functions. */
+
+/* If the *_hw_beakpoint functions have not been defined
+ elsewhere use the definitions in the target vector. */
+
+/* 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... */
+
+#ifndef TARGET_CAN_USE_HARDWARE_WATCHPOINT
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(TYPE,CNT,OTHERTYPE) \
+ (*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE);
+#endif
+
+#if !defined(TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT)
+#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(byte_count) \
+ (*current_target.to_region_size_ok_for_hw_watchpoint) (byte_count)
+#endif
+
+
+/* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes. TYPE is 0
+ for write, 1 for read, and 2 for read/write accesses. Returns 0 for
+ success, non-zero for failure. */
+
+#ifndef target_insert_watchpoint
+#define target_insert_watchpoint(addr, len, type) \
+ (*current_target.to_insert_watchpoint) (addr, len, type)
+
+#define target_remove_watchpoint(addr, len, type) \
+ (*current_target.to_remove_watchpoint) (addr, len, type)
+#endif
+
+#ifndef target_insert_hw_breakpoint
+#define target_insert_hw_breakpoint(addr, save) \
+ (*current_target.to_insert_hw_breakpoint) (addr, save)
+
+#define target_remove_hw_breakpoint(addr, save) \
+ (*current_target.to_remove_hw_breakpoint) (addr, save)
+#endif
+
+#ifndef target_stopped_data_address
+#define target_stopped_data_address() \
+ (*current_target.to_stopped_data_address) ()
+#endif
+
+/* Sometimes gdb may pick up what appears to be a valid target address
+ from a minimal symbol, but the value really means, essentially,
+ "This is an index into a table which is populated when the inferior
+ is run. Therefore, do not attempt to use this as a PC." */
+
+#if !defined(PC_REQUIRES_RUN_BEFORE_USE)
+#define PC_REQUIRES_RUN_BEFORE_USE(pc) (0)
+#endif
+
+/* This will only be defined by a target that supports catching vfork events,
+ such as HP-UX.
+
+ On some targets (such as HP-UX 10.20 and earlier), resuming a newly vforked
+ child process after it has exec'd, causes the parent process to resume as
+ well. To prevent the parent from running spontaneously, such targets should
+ define this to a function that prevents that from happening. */
+#if !defined(ENSURE_VFORKING_PARENT_REMAINS_STOPPED)
+#define ENSURE_VFORKING_PARENT_REMAINS_STOPPED(PID) (0)
+#endif
+
+/* This will only be defined by a target that supports catching vfork events,
+ such as HP-UX.
+
+ On some targets (such as HP-UX 10.20 and earlier), a newly vforked child
+ process must be resumed when it delivers its exec event, before the parent
+ vfork event will be delivered to us. */
+
+#if !defined(RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK)
+#define RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK() (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 (struct target_ops *);
+
+extern int push_target (struct target_ops *);
+
+extern int unpush_target (struct target_ops *);
+
+extern void target_preopen (int);
+
+extern void pop_target (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 */
+
+ struct bfd_section *the_bfd_section;
+
+ bfd *bfd; /* BFD file pointer */
+ };
+
+/* Return the "section" containing the specified address. */
+struct section_table *target_section_by_addr (struct target_ops *target,
+ CORE_ADDR addr);
+
+
+/* From mem-break.c */
+
+extern int memory_remove_breakpoint (CORE_ADDR, char *);
+
+extern int memory_insert_breakpoint (CORE_ADDR, char *);
+
+extern int default_memory_remove_breakpoint (CORE_ADDR, char *);
+
+extern int default_memory_insert_breakpoint (CORE_ADDR, char *);
+
+
+/* From target.c */
+
+extern void initialize_targets (void);
+
+extern void noprocess (void);
+
+extern void find_default_attach (char *, int);
+
+extern void find_default_create_inferior (char *, char *, char **);
+
+extern struct target_ops *find_run_target (void);
+
+extern struct target_ops *find_core_target (void);
+
+extern struct target_ops *find_target_beneath (struct target_ops *);
+
+extern int target_resize_to_sections (struct target_ops *target,
+ int num_added);
+
+extern void remove_target_sections (bfd *abfd);
+
+
+/* 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;
+/* Timeout limit for response from target. */
+extern int remote_timeout;
+
+
+/* Functions for helping to write a native target. */
+
+/* This is for native targets which use a unix/POSIX-style waitstatus. */
+extern void store_waitstatus (struct target_waitstatus *, int);
+
+/* Predicate to target_signal_to_host(). Return non-zero if the enum
+ targ_signal SIGNO has an equivalent ``host'' representation. */
+/* FIXME: cagney/1999-11-22: The name below was chosen in preference
+ to the shorter target_signal_p() because it is far less ambigious.
+ In this context ``target_signal'' refers to GDB's internal
+ representation of the target's set of signals while ``host signal''
+ refers to the target operating system's signal. Confused? */
+
+extern int target_signal_to_host_p (enum target_signal signo);
+
+/* Convert between host signal numbers and enum target_signal's.
+ target_signal_to_host() returns 0 and prints a warning() on GDB's
+ console if SIGNO has no equivalent host representation. */
+/* FIXME: cagney/1999-11-22: Here ``host'' is used incorrectly, it is
+ refering to the target operating system's signal numbering.
+ Similarly, ``enum target_signal'' is named incorrectly, ``enum
+ gdb_signal'' would probably be better as it is refering to GDB's
+ internal representation of a target operating system's signal. */
+
+extern enum target_signal target_signal_from_host (int);
+extern int target_signal_to_host (enum target_signal);
+
+/* Convert from a number used in a GDB command to an enum target_signal. */
+extern enum target_signal target_signal_from_command (int);
+
+/* Any target can call this to switch to remote protocol (in remote.c). */
+extern void push_remote_target (char *name, int from_tty);
+
+/* Imported from machine dependent code */
+
+/* Blank target vector entries are initialized to target_ignore. */
+void target_ignore (void);
+
+#endif /* !defined (TARGET_H) */
diff --git a/contrib/gdb/gdb/terminal.h b/contrib/gdb/gdb/terminal.h
new file mode 100644
index 0000000..cb16451
--- /dev/null
+++ b/contrib/gdb/gdb/terminal.h
@@ -0,0 +1,91 @@
+/* Terminal interface definitions for GDB, the GNU Debugger.
+ Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1995, 1996, 1999, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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. */
+
+#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
+#if defined(HAVE_TERMIOS_H)
+#define HAVE_TERMIOS
+#else /* ! defined (HAVE_TERMIOS_H) */
+#if defined(HAVE_TERMIO_H)
+#define HAVE_TERMIO
+#else /* ! defined (HAVE_TERMIO_H) */
+#if defined(HAVE_SGTTY_H)
+#define HAVE_SGTTY
+#endif /* ! defined (HAVE_SGTTY_H) */
+#endif /* ! defined (HAVE_TERMIO_H) */
+#endif /* ! defined (HAVE_TERMIOS_H) */
+#endif /* !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY) */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if !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 <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif
+
+extern void new_tty (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 (void);
+
+#endif /* !defined (TERMINAL_H) */
diff --git a/contrib/gdb/gdb/thread-db.c b/contrib/gdb/gdb/thread-db.c
new file mode 100644
index 0000000..804f48a
--- /dev/null
+++ b/contrib/gdb/gdb/thread-db.c
@@ -0,0 +1,1314 @@
+/* libthread_db assisted debugging support, generic parts.
+
+ Copyright 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_assert.h"
+#include <dlfcn.h>
+#include "gdb_proc_service.h"
+#include "gdb_thread_db.h"
+
+#include "bfd.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "target.h"
+#include "regcache.h"
+#include "solib-svr4.h"
+
+#ifndef LIBTHREAD_DB_SO
+#define LIBTHREAD_DB_SO "libthread_db.so.1"
+#endif
+
+/* If we're running on GNU/Linux, we must explicitly attach to any new
+ threads. */
+
+/* FIXME: There is certainly some room for improvements:
+ - Cache LWP ids.
+ - Bypass libthread_db when fetching or storing registers for
+ threads bound to a LWP. */
+
+/* This module's target vector. */
+static struct target_ops thread_db_ops;
+
+/* The target vector that we call for things this module can't handle. */
+static struct target_ops *target_beneath;
+
+/* Pointer to the next function on the objfile event chain. */
+static void (*target_new_objfile_chain) (struct objfile * objfile);
+
+/* Non-zero if we're using this module's target vector. */
+static int using_thread_db;
+
+/* Non-zero if we have to keep this module's target vector active
+ across re-runs. */
+static int keep_thread_db;
+
+/* Non-zero if we have determined the signals used by the threads
+ library. */
+static int thread_signals;
+static sigset_t thread_stop_set;
+static sigset_t thread_print_set;
+
+/* Structure that identifies the child process for the
+ <proc_service.h> interface. */
+static struct ps_prochandle proc_handle;
+
+/* Connection to the libthread_db library. */
+static td_thragent_t *thread_agent;
+
+/* Pointers to the libthread_db functions. */
+
+static td_err_e (*td_init_p) (void);
+
+static td_err_e (*td_ta_new_p) (struct ps_prochandle * ps,
+ td_thragent_t **ta);
+static td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
+ td_thrhandle_t *__th);
+static td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta,
+ lwpid_t lwpid, td_thrhandle_t *th);
+static td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta,
+ td_thr_iter_f *callback, void *cbdata_p,
+ td_thr_state_e state, int ti_pri,
+ sigset_t *ti_sigmask_p,
+ unsigned int ti_user_flags);
+static td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
+ td_event_e event, td_notify_t *ptr);
+static td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
+ td_thr_events_t *event);
+static td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
+ td_event_msg_t *msg);
+
+static td_err_e (*td_thr_validate_p) (const td_thrhandle_t *th);
+static td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
+ td_thrinfo_t *infop);
+static td_err_e (*td_thr_getfpregs_p) (const td_thrhandle_t *th,
+ gdb_prfpregset_t *regset);
+static td_err_e (*td_thr_getgregs_p) (const td_thrhandle_t *th,
+ prgregset_t gregs);
+static td_err_e (*td_thr_setfpregs_p) (const td_thrhandle_t *th,
+ const gdb_prfpregset_t *fpregs);
+static td_err_e (*td_thr_setgregs_p) (const td_thrhandle_t *th,
+ prgregset_t gregs);
+static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th,
+ int event);
+
+static td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
+ void *map_address,
+ size_t offset, void **address);
+
+/* Location of the thread creation event breakpoint. The code at this
+ location in the child process will be called by the pthread library
+ whenever a new thread is created. By setting a special breakpoint
+ at this location, GDB can detect when a new thread is created. We
+ obtain this location via the td_ta_event_addr call. */
+static CORE_ADDR td_create_bp_addr;
+
+/* Location of the thread death event breakpoint. */
+static CORE_ADDR td_death_bp_addr;
+
+/* Prototypes for local functions. */
+static void thread_db_find_new_threads (void);
+static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
+ const td_thrinfo_t *ti_p, int verbose);
+
+
+/* Building process ids. */
+
+#define GET_PID(ptid) ptid_get_pid (ptid)
+#define GET_LWP(ptid) ptid_get_lwp (ptid)
+#define GET_THREAD(ptid) ptid_get_tid (ptid)
+
+#define is_lwp(ptid) (GET_LWP (ptid) != 0)
+#define is_thread(ptid) (GET_THREAD (ptid) != 0)
+
+#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
+#define BUILD_THREAD(tid, pid) ptid_build (pid, 0, tid)
+
+
+/* Use "struct private_thread_info" to cache thread state. This is
+ a substantial optimization. */
+
+struct private_thread_info
+{
+ /* Cached thread state. */
+ unsigned int th_valid:1;
+ unsigned int ti_valid:1;
+
+ td_thrhandle_t th;
+ td_thrinfo_t ti;
+};
+
+
+static char *
+thread_db_err_str (td_err_e err)
+{
+ static char buf[64];
+
+ switch (err)
+ {
+ case TD_OK:
+ return "generic 'call succeeded'";
+ case TD_ERR:
+ return "generic error";
+ case TD_NOTHR:
+ return "no thread to satisfy query";
+ case TD_NOSV:
+ return "no sync handle to satisfy query";
+ case TD_NOLWP:
+ return "no LWP to satisfy query";
+ case TD_BADPH:
+ return "invalid process handle";
+ case TD_BADTH:
+ return "invalid thread handle";
+ case TD_BADSH:
+ return "invalid synchronization handle";
+ case TD_BADTA:
+ return "invalid thread agent";
+ case TD_BADKEY:
+ return "invalid key";
+ case TD_NOMSG:
+ return "no event message for getmsg";
+ case TD_NOFPREGS:
+ return "FPU register set not available";
+ case TD_NOLIBTHREAD:
+ return "application not linked with libthread";
+ case TD_NOEVENT:
+ return "requested event is not supported";
+ case TD_NOCAPAB:
+ return "capability not available";
+ case TD_DBERR:
+ return "debugger service failed";
+ case TD_NOAPLIC:
+ return "operation not applicable to";
+ case TD_NOTSD:
+ return "no thread-specific data for this thread";
+ case TD_MALLOC:
+ return "malloc failed";
+ case TD_PARTIALREG:
+ return "only part of register set was written/read";
+ case TD_NOXREGS:
+ return "X register set not available for this thread";
+ default:
+ snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
+ return buf;
+ }
+}
+
+static char *
+thread_db_state_str (td_thr_state_e state)
+{
+ static char buf[64];
+
+ switch (state)
+ {
+ case TD_THR_STOPPED:
+ return "stopped by debugger";
+ case TD_THR_RUN:
+ return "runnable";
+ case TD_THR_ACTIVE:
+ return "active";
+ case TD_THR_ZOMBIE:
+ return "zombie";
+ case TD_THR_SLEEP:
+ return "sleeping";
+ case TD_THR_STOPPED_ASLEEP:
+ return "stopped by debugger AND blocked";
+ default:
+ snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
+ return buf;
+ }
+}
+
+/* A callback function for td_ta_thr_iter, which we use to map all
+ threads to LWPs.
+
+ THP is a handle to the current thread; if INFOP is not NULL, the
+ struct thread_info associated with this thread is returned in
+ *INFOP. */
+
+static int
+thread_get_info_callback (const td_thrhandle_t *thp, void *infop)
+{
+ td_thrinfo_t ti;
+ td_err_e err;
+ struct thread_info *thread_info;
+ ptid_t thread_ptid;
+
+ err = td_thr_get_info_p (thp, &ti);
+ if (err != TD_OK)
+ error ("thread_get_info_callback: cannot get thread info: %s",
+ thread_db_err_str (err));
+
+ /* Fill the cache. */
+ thread_ptid = BUILD_THREAD (ti.ti_tid, GET_PID (inferior_ptid));
+ thread_info = find_thread_pid (thread_ptid);
+
+ if (thread_info == NULL)
+ {
+ /* New thread. Attach to it now (why wait?). */
+ attach_thread (thread_ptid, thp, &ti, 1);
+ thread_info = find_thread_pid (thread_ptid);
+ gdb_assert (thread_info != NULL);
+ }
+
+ memcpy (&thread_info->private->th, thp, sizeof (*thp));
+ thread_info->private->th_valid = 1;
+ memcpy (&thread_info->private->ti, &ti, sizeof (ti));
+ thread_info->private->ti_valid = 1;
+
+ if (infop != NULL)
+ *(struct thread_info **) infop = thread_info;
+
+ return 0;
+}
+
+/* Accessor functions for the thread_db information, with caching. */
+
+static void
+thread_db_map_id2thr (struct thread_info *thread_info, int fatal)
+{
+ td_err_e err;
+
+ if (thread_info->private->th_valid)
+ return;
+
+ err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (thread_info->ptid),
+ &thread_info->private->th);
+ if (err != TD_OK)
+ {
+ if (fatal)
+ error ("Cannot find thread %ld: %s",
+ (long) GET_THREAD (thread_info->ptid),
+ thread_db_err_str (err));
+ }
+ else
+ thread_info->private->th_valid = 1;
+}
+
+static td_thrinfo_t *
+thread_db_get_info (struct thread_info *thread_info)
+{
+ td_err_e err;
+
+ if (thread_info->private->ti_valid)
+ return &thread_info->private->ti;
+
+ if (!thread_info->private->th_valid)
+ thread_db_map_id2thr (thread_info, 1);
+
+ err =
+ td_thr_get_info_p (&thread_info->private->th, &thread_info->private->ti);
+ if (err != TD_OK)
+ error ("thread_db_get_info: cannot get thread info: %s",
+ thread_db_err_str (err));
+
+ thread_info->private->ti_valid = 1;
+ return &thread_info->private->ti;
+}
+
+/* Convert between user-level thread ids and LWP ids. */
+
+static ptid_t
+thread_from_lwp (ptid_t ptid)
+{
+ td_thrhandle_t th;
+ td_err_e err;
+ struct thread_info *thread_info;
+ ptid_t thread_ptid;
+
+ if (GET_LWP (ptid) == 0)
+ ptid = BUILD_LWP (GET_PID (ptid), GET_PID (ptid));
+
+ gdb_assert (is_lwp (ptid));
+
+ err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
+ if (err != TD_OK)
+ error ("Cannot find user-level thread for LWP %ld: %s",
+ GET_LWP (ptid), thread_db_err_str (err));
+
+ thread_info = NULL;
+ thread_get_info_callback (&th, &thread_info);
+ gdb_assert (thread_info && thread_info->private->ti_valid);
+
+ return BUILD_THREAD (thread_info->private->ti.ti_tid, GET_PID (ptid));
+}
+
+static ptid_t
+lwp_from_thread (ptid_t ptid)
+{
+ struct thread_info *thread_info;
+ ptid_t thread_ptid;
+
+ if (!is_thread (ptid))
+ return ptid;
+
+ thread_info = find_thread_pid (ptid);
+ thread_db_get_info (thread_info);
+
+ return BUILD_LWP (thread_info->private->ti.ti_lid, GET_PID (ptid));
+}
+
+
+void
+thread_db_init (struct target_ops *target)
+{
+ target_beneath = target;
+}
+
+static void *
+verbose_dlsym (void *handle, const char *name)
+{
+ void *sym = dlsym (handle, name);
+ if (sym == NULL)
+ warning ("Symbol \"%s\" not found in libthread_db: %s", name, dlerror ());
+ return sym;
+}
+
+static int
+thread_db_load (void)
+{
+ void *handle;
+ td_err_e err;
+
+ handle = dlopen (LIBTHREAD_DB_SO, RTLD_NOW);
+ if (handle == NULL)
+ {
+ fprintf_filtered (gdb_stderr, "\n\ndlopen failed on '%s' - %s\n",
+ LIBTHREAD_DB_SO, dlerror ());
+ fprintf_filtered (gdb_stderr,
+ "GDB will not be able to debug pthreads.\n\n");
+ return 0;
+ }
+
+ /* Initialize pointers to the dynamic library functions we will use.
+ Essential functions first. */
+
+ td_init_p = verbose_dlsym (handle, "td_init");
+ if (td_init_p == NULL)
+ return 0;
+
+ td_ta_new_p = verbose_dlsym (handle, "td_ta_new");
+ if (td_ta_new_p == NULL)
+ return 0;
+
+ td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
+ if (td_ta_map_id2thr_p == NULL)
+ return 0;
+
+ td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr");
+ if (td_ta_map_lwp2thr_p == NULL)
+ return 0;
+
+ td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter");
+ if (td_ta_thr_iter_p == NULL)
+ return 0;
+
+ td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate");
+ if (td_thr_validate_p == NULL)
+ return 0;
+
+ td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info");
+ if (td_thr_get_info_p == NULL)
+ return 0;
+
+ td_thr_getfpregs_p = verbose_dlsym (handle, "td_thr_getfpregs");
+ if (td_thr_getfpregs_p == NULL)
+ return 0;
+
+ td_thr_getgregs_p = verbose_dlsym (handle, "td_thr_getgregs");
+ if (td_thr_getgregs_p == NULL)
+ return 0;
+
+ td_thr_setfpregs_p = verbose_dlsym (handle, "td_thr_setfpregs");
+ if (td_thr_setfpregs_p == NULL)
+ return 0;
+
+ td_thr_setgregs_p = verbose_dlsym (handle, "td_thr_setgregs");
+ if (td_thr_setgregs_p == NULL)
+ return 0;
+
+ /* Initialize the library. */
+ err = td_init_p ();
+ if (err != TD_OK)
+ {
+ warning ("Cannot initialize libthread_db: %s", thread_db_err_str (err));
+ return 0;
+ }
+
+ /* These are not essential. */
+ td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr");
+ td_ta_set_event_p = dlsym (handle, "td_ta_set_event");
+ td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
+ td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
+ td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
+
+ return 1;
+}
+
+static td_err_e
+enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp)
+{
+ td_notify_t notify;
+ td_err_e err;
+
+ /* Get the breakpoint address for thread EVENT. */
+ err = td_ta_event_addr_p (thread_agent, event, &notify);
+ if (err != TD_OK)
+ return err;
+
+ /* Set up the breakpoint. */
+ (*bp) = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ (CORE_ADDR) notify.u.bptaddr,
+ &current_target);
+ create_thread_event_breakpoint ((*bp));
+
+ return TD_OK;
+}
+
+static void
+enable_thread_event_reporting (void)
+{
+ td_thr_events_t events;
+ td_notify_t notify;
+ td_err_e err;
+
+ /* We cannot use the thread event reporting facility if these
+ functions aren't available. */
+ if (td_ta_event_addr_p == NULL || td_ta_set_event_p == NULL
+ || td_ta_event_getmsg_p == NULL || td_thr_event_enable_p == NULL)
+ return;
+
+ /* Set the process wide mask saying which events we're interested in. */
+ td_event_emptyset (&events);
+ td_event_addset (&events, TD_CREATE);
+#if 0
+ /* FIXME: kettenis/2000-04-23: The event reporting facility is
+ broken for TD_DEATH events in glibc 2.1.3, so don't enable it for
+ now. */
+ td_event_addset (&events, TD_DEATH);
+#endif
+
+ err = td_ta_set_event_p (thread_agent, &events);
+ if (err != TD_OK)
+ {
+ warning ("Unable to set global thread event mask: %s",
+ thread_db_err_str (err));
+ return;
+ }
+
+ /* Delete previous thread event breakpoints, if any. */
+ remove_thread_event_breakpoints ();
+ td_create_bp_addr = 0;
+ td_death_bp_addr = 0;
+
+ /* Set up the thread creation event. */
+ err = enable_thread_event (thread_agent, TD_CREATE, &td_create_bp_addr);
+ if (err != TD_OK)
+ {
+ warning ("Unable to get location for thread creation breakpoint: %s",
+ thread_db_err_str (err));
+ return;
+ }
+
+ /* Set up the thread death event. */
+ err = enable_thread_event (thread_agent, TD_DEATH, &td_death_bp_addr);
+ if (err != TD_OK)
+ {
+ warning ("Unable to get location for thread death breakpoint: %s",
+ thread_db_err_str (err));
+ return;
+ }
+}
+
+static void
+disable_thread_event_reporting (void)
+{
+ td_thr_events_t events;
+
+ /* Set the process wide mask saying we aren't interested in any
+ events anymore. */
+ td_event_emptyset (&events);
+ td_ta_set_event_p (thread_agent, &events);
+
+ /* Delete thread event breakpoints, if any. */
+ remove_thread_event_breakpoints ();
+ td_create_bp_addr = 0;
+ td_death_bp_addr = 0;
+}
+
+static void
+check_thread_signals (void)
+{
+#ifdef GET_THREAD_SIGNALS
+ if (!thread_signals)
+ {
+ sigset_t mask;
+ int i;
+
+ GET_THREAD_SIGNALS (&mask);
+ sigemptyset (&thread_stop_set);
+ sigemptyset (&thread_print_set);
+
+ for (i = 1; i < NSIG; i++)
+ {
+ if (sigismember (&mask, i))
+ {
+ if (signal_stop_update (target_signal_from_host (i), 0))
+ sigaddset (&thread_stop_set, i);
+ if (signal_print_update (target_signal_from_host (i), 0))
+ sigaddset (&thread_print_set, i);
+ thread_signals = 1;
+ }
+ }
+ }
+#endif
+}
+
+static void
+thread_db_new_objfile (struct objfile *objfile)
+{
+ td_err_e err;
+
+ /* First time through, report that libthread_db was successfuly
+ loaded. Can't print this in in thread_db_load as, at that stage,
+ the interpreter and it's console haven't started. The real
+ problem here is that libthread_db is loaded too early - it should
+ only be loaded when there is a program to debug. */
+ {
+ static int dejavu;
+ if (!dejavu)
+ {
+ Dl_info info;
+ const char *library = NULL;
+ /* Try dladdr. */
+ if (dladdr ((*td_ta_new_p), &info) != 0)
+ library = info.dli_fname;
+ /* Try dlinfo? */
+ if (library == NULL)
+ /* Paranoid - don't let a NULL path slip through. */
+ library = LIBTHREAD_DB_SO;
+ printf_unfiltered ("Using host libthread_db library \"%s\".\n",
+ library);
+ dejavu = 1;
+ }
+ }
+
+ /* Don't attempt to use thread_db on targets which can not run
+ (core files). */
+ if (objfile == NULL || !target_has_execution)
+ {
+ /* All symbols have been discarded. If the thread_db target is
+ active, deactivate it now. */
+ if (using_thread_db)
+ {
+ gdb_assert (proc_handle.pid == 0);
+ unpush_target (&thread_db_ops);
+ using_thread_db = 0;
+ }
+
+ keep_thread_db = 0;
+
+ goto quit;
+ }
+
+ if (using_thread_db)
+ /* Nothing to do. The thread library was already detected and the
+ target vector was already activated. */
+ goto quit;
+
+ /* Initialize the structure that identifies the child process. Note
+ that at this point there is no guarantee that we actually have a
+ child process. */
+ proc_handle.pid = GET_PID (inferior_ptid);
+
+ /* Now attempt to open a connection to the thread library. */
+ err = td_ta_new_p (&proc_handle, &thread_agent);
+ switch (err)
+ {
+ case TD_NOLIBTHREAD:
+ /* No thread library was detected. */
+ break;
+
+ case TD_OK:
+ printf_unfiltered ("[Thread debugging using libthread_db enabled]\n");
+
+ /* The thread library was detected. Activate the thread_db target. */
+ push_target (&thread_db_ops);
+ using_thread_db = 1;
+
+ /* If the thread library was detected in the main symbol file
+ itself, we assume that the program was statically linked
+ against the thread library and well have to keep this
+ module's target vector activated until forever... Well, at
+ least until all symbols have been discarded anyway (see
+ above). */
+ if (objfile == symfile_objfile)
+ {
+ gdb_assert (proc_handle.pid == 0);
+ keep_thread_db = 1;
+ }
+
+ /* We can only poke around if there actually is a child process.
+ If there is no child process alive, postpone the steps below
+ until one has been created. */
+ if (proc_handle.pid != 0)
+ {
+ enable_thread_event_reporting ();
+ thread_db_find_new_threads ();
+ }
+ break;
+
+ default:
+ warning ("Cannot initialize thread debugging library: %s",
+ thread_db_err_str (err));
+ break;
+ }
+
+quit:
+ if (target_new_objfile_chain)
+ target_new_objfile_chain (objfile);
+}
+
+static void
+attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
+ const td_thrinfo_t *ti_p, int verbose)
+{
+ struct thread_info *tp;
+ td_err_e err;
+
+ check_thread_signals ();
+
+ /* Add the thread to GDB's thread list. */
+ tp = add_thread (ptid);
+ tp->private = xmalloc (sizeof (struct private_thread_info));
+ memset (tp->private, 0, sizeof (struct private_thread_info));
+
+ if (verbose)
+ printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid));
+
+ if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
+ return; /* A zombie thread -- do not attach. */
+
+ /* Under GNU/Linux, we have to attach to each and every thread. */
+#ifdef ATTACH_LWP
+ ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0);
+#endif
+
+ /* Enable thread event reporting for this thread. */
+ err = td_thr_event_enable_p (th_p, 1);
+ if (err != TD_OK)
+ error ("Cannot enable thread event reporting for %s: %s",
+ target_pid_to_str (ptid), thread_db_err_str (err));
+}
+
+static void
+thread_db_attach (char *args, int from_tty)
+{
+ target_beneath->to_attach (args, from_tty);
+
+ /* Destroy thread info; it's no longer valid. */
+ init_thread_list ();
+
+ /* The child process is now the actual multi-threaded
+ program. Snatch its process ID... */
+ proc_handle.pid = GET_PID (inferior_ptid);
+
+ /* ...and perform the remaining initialization steps. */
+ enable_thread_event_reporting ();
+ thread_db_find_new_threads ();
+}
+
+static void
+detach_thread (ptid_t ptid, int verbose)
+{
+ if (verbose)
+ printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid));
+}
+
+static void
+thread_db_detach (char *args, int from_tty)
+{
+ disable_thread_event_reporting ();
+
+ /* There's no need to save & restore inferior_ptid here, since the
+ inferior is supposed to be survive this function call. */
+ inferior_ptid = lwp_from_thread (inferior_ptid);
+
+ /* Forget about the child's process ID. We shouldn't need it
+ anymore. */
+ proc_handle.pid = 0;
+
+ target_beneath->to_detach (args, from_tty);
+}
+
+static int
+clear_lwpid_callback (struct thread_info *thread, void *dummy)
+{
+ /* If we know that our thread implementation is 1-to-1, we could save
+ a certain amount of information; it's not clear how much, so we
+ are always conservative. */
+
+ thread->private->th_valid = 0;
+ thread->private->ti_valid = 0;
+
+ return 0;
+}
+
+static void
+thread_db_resume (ptid_t ptid, int step, enum target_signal signo)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ if (GET_PID (ptid) == -1)
+ inferior_ptid = lwp_from_thread (inferior_ptid);
+ else if (is_thread (ptid))
+ ptid = lwp_from_thread (ptid);
+
+ /* Clear cached data which may not be valid after the resume. */
+ iterate_over_threads (clear_lwpid_callback, NULL);
+
+ target_beneath->to_resume (ptid, step, signo);
+
+ do_cleanups (old_chain);
+}
+
+/* Check if PID is currently stopped at the location of a thread event
+ breakpoint location. If it is, read the event message and act upon
+ the event. */
+
+static void
+check_event (ptid_t ptid)
+{
+ td_event_msg_t msg;
+ td_thrinfo_t ti;
+ td_err_e err;
+ CORE_ADDR stop_pc;
+ int loop = 0;
+
+ /* Bail out early if we're not at a thread event breakpoint. */
+ stop_pc = read_pc_pid (ptid) - DECR_PC_AFTER_BREAK;
+ if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
+ return;
+
+ /* If we are at a create breakpoint, we do not know what new lwp
+ was created and cannot specifically locate the event message for it.
+ We have to call td_ta_event_getmsg() to get
+ the latest message. Since we have no way of correlating whether
+ the event message we get back corresponds to our breakpoint, we must
+ loop and read all event messages, processing them appropriately.
+ This guarantees we will process the correct message before continuing
+ from the breakpoint.
+
+ Currently, death events are not enabled. If they are enabled,
+ the death event can use the td_thr_event_getmsg() interface to
+ get the message specifically for that lwp and avoid looping
+ below. */
+
+ loop = 1;
+
+ do
+ {
+ err = td_ta_event_getmsg_p (thread_agent, &msg);
+ if (err != TD_OK)
+ {
+ if (err == TD_NOMSG)
+ return;
+
+ error ("Cannot get thread event message: %s",
+ thread_db_err_str (err));
+ }
+
+ err = td_thr_get_info_p (msg.th_p, &ti);
+ if (err != TD_OK)
+ error ("Cannot get thread info: %s", thread_db_err_str (err));
+
+ ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid));
+
+ switch (msg.event)
+ {
+ case TD_CREATE:
+
+ /* We may already know about this thread, for instance when the
+ user has issued the `info threads' command before the SIGTRAP
+ for hitting the thread creation breakpoint was reported. */
+ if (!in_thread_list (ptid))
+ attach_thread (ptid, msg.th_p, &ti, 1);
+
+ break;
+
+ case TD_DEATH:
+
+ if (!in_thread_list (ptid))
+ error ("Spurious thread death event.");
+
+ detach_thread (ptid, 1);
+
+ break;
+
+ default:
+ error ("Spurious thread event.");
+ }
+ }
+ while (loop);
+}
+
+static ptid_t
+thread_db_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ extern ptid_t trap_ptid;
+
+ if (GET_PID (ptid) != -1 && is_thread (ptid))
+ ptid = lwp_from_thread (ptid);
+
+ ptid = target_beneath->to_wait (ptid, ourstatus);
+
+ if (proc_handle.pid == 0)
+ /* The current child process isn't the actual multi-threaded
+ program yet, so don't try to do any special thread-specific
+ post-processing and bail out early. */
+ return ptid;
+
+ if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+ return pid_to_ptid (-1);
+
+ if (ourstatus->kind == TARGET_WAITKIND_STOPPED
+ && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
+ /* Check for a thread event. */
+ check_event (ptid);
+
+ if (!ptid_equal (trap_ptid, null_ptid))
+ trap_ptid = thread_from_lwp (trap_ptid);
+
+ return thread_from_lwp (ptid);
+}
+
+static int
+thread_db_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ struct cleanup *old_chain = save_inferior_ptid ();
+ int xfer;
+
+ if (is_thread (inferior_ptid))
+ {
+ /* FIXME: This seems to be necessary to make sure breakpoints
+ are removed. */
+ if (!target_thread_alive (inferior_ptid))
+ inferior_ptid = pid_to_ptid (GET_PID (inferior_ptid));
+ else
+ inferior_ptid = lwp_from_thread (inferior_ptid);
+ }
+
+ xfer =
+ target_beneath->to_xfer_memory (memaddr, myaddr, len, write, attrib,
+ target);
+
+ do_cleanups (old_chain);
+ return xfer;
+}
+
+static void
+thread_db_fetch_registers (int regno)
+{
+ struct thread_info *thread_info;
+ prgregset_t gregset;
+ gdb_prfpregset_t fpregset;
+ td_err_e err;
+
+ if (!is_thread (inferior_ptid))
+ {
+ /* Pass the request to the target beneath us. */
+ target_beneath->to_fetch_registers (regno);
+ return;
+ }
+
+ thread_info = find_thread_pid (inferior_ptid);
+ thread_db_map_id2thr (thread_info, 1);
+
+ err = td_thr_getgregs_p (&thread_info->private->th, gregset);
+ if (err != TD_OK)
+ error ("Cannot fetch general-purpose registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+
+ err = td_thr_getfpregs_p (&thread_info->private->th, &fpregset);
+ if (err != TD_OK)
+ error ("Cannot get floating-point registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+
+ /* Note that we must call supply_gregset after calling the thread_db
+ routines because the thread_db routines call ps_lgetgregs and
+ friends which clobber GDB's register cache. */
+ supply_gregset ((gdb_gregset_t *) gregset);
+ supply_fpregset (&fpregset);
+}
+
+static void
+thread_db_store_registers (int regno)
+{
+ prgregset_t gregset;
+ gdb_prfpregset_t fpregset;
+ td_err_e err;
+ struct thread_info *thread_info;
+
+ if (!is_thread (inferior_ptid))
+ {
+ /* Pass the request to the target beneath us. */
+ target_beneath->to_store_registers (regno);
+ return;
+ }
+
+ thread_info = find_thread_pid (inferior_ptid);
+ thread_db_map_id2thr (thread_info, 1);
+
+ if (regno != -1)
+ {
+ char raw[MAX_REGISTER_SIZE];
+
+ deprecated_read_register_gen (regno, raw);
+ thread_db_fetch_registers (-1);
+ supply_register (regno, raw);
+ }
+
+ fill_gregset ((gdb_gregset_t *) gregset, -1);
+ fill_fpregset (&fpregset, -1);
+
+ err = td_thr_setgregs_p (&thread_info->private->th, gregset);
+ if (err != TD_OK)
+ error ("Cannot store general-purpose registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+ err = td_thr_setfpregs_p (&thread_info->private->th, &fpregset);
+ if (err != TD_OK)
+ error ("Cannot store floating-point registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+}
+
+static void
+thread_db_kill (void)
+{
+ /* There's no need to save & restore inferior_ptid here, since the
+ inferior isn't supposed to survive this function call. */
+ inferior_ptid = lwp_from_thread (inferior_ptid);
+ target_beneath->to_kill ();
+}
+
+static void
+thread_db_create_inferior (char *exec_file, char *allargs, char **env)
+{
+ if (!keep_thread_db)
+ {
+ unpush_target (&thread_db_ops);
+ using_thread_db = 0;
+ }
+
+ target_beneath->to_create_inferior (exec_file, allargs, env);
+}
+
+static void
+thread_db_post_startup_inferior (ptid_t ptid)
+{
+ if (proc_handle.pid == 0)
+ {
+ /* The child process is now the actual multi-threaded
+ program. Snatch its process ID... */
+ proc_handle.pid = GET_PID (ptid);
+
+ /* ...and perform the remaining initialization steps. */
+ enable_thread_event_reporting ();
+ thread_db_find_new_threads ();
+ }
+}
+
+static void
+thread_db_mourn_inferior (void)
+{
+ remove_thread_event_breakpoints ();
+
+ /* Forget about the child's process ID. We shouldn't need it
+ anymore. */
+ proc_handle.pid = 0;
+
+ target_beneath->to_mourn_inferior ();
+
+ /* Detach thread_db target ops if not dealing with a statically
+ linked threaded program. This allows a corefile to be debugged
+ after finishing debugging of a threaded program. At present,
+ debugging a statically-linked threaded program is broken, but
+ the check is added below in the event that it is fixed in the
+ future. */
+ if (!keep_thread_db)
+ {
+ unpush_target (&thread_db_ops);
+ using_thread_db = 0;
+ }
+}
+
+static int
+thread_db_thread_alive (ptid_t ptid)
+{
+ td_thrhandle_t th;
+ td_err_e err;
+
+ if (is_thread (ptid))
+ {
+ struct thread_info *thread_info;
+ thread_info = find_thread_pid (ptid);
+
+ thread_db_map_id2thr (thread_info, 0);
+ if (!thread_info->private->th_valid)
+ return 0;
+
+ err = td_thr_validate_p (&thread_info->private->th);
+ if (err != TD_OK)
+ return 0;
+
+ if (!thread_info->private->ti_valid)
+ {
+ err =
+ td_thr_get_info_p (&thread_info->private->th,
+ &thread_info->private->ti);
+ if (err != TD_OK)
+ return 0;
+ thread_info->private->ti_valid = 1;
+ }
+
+ if (thread_info->private->ti.ti_state == TD_THR_UNKNOWN
+ || thread_info->private->ti.ti_state == TD_THR_ZOMBIE)
+ return 0; /* A zombie thread. */
+
+ return 1;
+ }
+
+ if (target_beneath->to_thread_alive)
+ return target_beneath->to_thread_alive (ptid);
+
+ return 0;
+}
+
+static int
+find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
+{
+ td_thrinfo_t ti;
+ td_err_e err;
+ ptid_t ptid;
+
+ err = td_thr_get_info_p (th_p, &ti);
+ if (err != TD_OK)
+ error ("find_new_threads_callback: cannot get thread info: %s",
+ thread_db_err_str (err));
+
+ if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
+ return 0; /* A zombie -- ignore. */
+
+ ptid = BUILD_THREAD (ti.ti_tid, GET_PID (inferior_ptid));
+
+ if (!in_thread_list (ptid))
+ attach_thread (ptid, th_p, &ti, 1);
+
+ return 0;
+}
+
+static void
+thread_db_find_new_threads (void)
+{
+ td_err_e err;
+
+ /* Iterate over all user-space threads to discover new threads. */
+ err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL,
+ TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+ TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+ if (err != TD_OK)
+ error ("Cannot find new threads: %s", thread_db_err_str (err));
+}
+
+static char *
+thread_db_pid_to_str (ptid_t ptid)
+{
+ if (is_thread (ptid))
+ {
+ static char buf[64];
+ td_thrinfo_t *ti_p;
+ td_err_e err;
+ struct thread_info *thread_info;
+
+ thread_info = find_thread_pid (ptid);
+ thread_db_map_id2thr (thread_info, 0);
+ if (!thread_info->private->th_valid)
+ {
+ snprintf (buf, sizeof (buf), "Thread %ld (Missing)",
+ GET_THREAD (ptid));
+ return buf;
+ }
+
+ ti_p = thread_db_get_info (thread_info);
+
+ if (ti_p->ti_state == TD_THR_ACTIVE && ti_p->ti_lid != 0)
+ {
+ snprintf (buf, sizeof (buf), "Thread %ld (LWP %d)",
+ (long) ti_p->ti_tid, ti_p->ti_lid);
+ }
+ else
+ {
+ snprintf (buf, sizeof (buf), "Thread %ld (%s)",
+ (long) ti_p->ti_tid,
+ thread_db_state_str (ti_p->ti_state));
+ }
+
+ return buf;
+ }
+
+ if (target_beneath->to_pid_to_str (ptid))
+ return target_beneath->to_pid_to_str (ptid);
+
+ return normal_pid_to_str (ptid);
+}
+
+/* Get the address of the thread local variable in OBJFILE which is
+ stored at OFFSET within the thread local storage for thread PTID. */
+
+static CORE_ADDR
+thread_db_get_thread_local_address (ptid_t ptid, struct objfile *objfile,
+ CORE_ADDR offset)
+{
+ if (is_thread (ptid))
+ {
+ int objfile_is_library = (objfile->flags & OBJF_SHARED);
+ td_err_e err;
+ void *address;
+ CORE_ADDR lm;
+ struct thread_info *thread_info;
+
+ /* glibc doesn't provide the needed interface. */
+ if (!td_thr_tls_get_addr_p)
+ error ("Cannot find thread-local variables in this thread library.");
+
+ /* Get the address of the link map for this objfile. */
+ lm = svr4_fetch_objfile_link_map (objfile);
+
+ /* Whoops, we couldn't find one. Bail out. */
+ if (!lm)
+ {
+ if (objfile_is_library)
+ error ("Cannot find shared library `%s' link_map in dynamic"
+ " linker's module list", objfile->name);
+ else
+ error ("Cannot find executable file `%s' link_map in dynamic"
+ " linker's module list", objfile->name);
+ }
+
+ /* Get info about the thread. */
+ thread_info = find_thread_pid (ptid);
+ thread_db_map_id2thr (thread_info, 1);
+
+ /* Finally, get the address of the variable. */
+ err = td_thr_tls_get_addr_p (&thread_info->private->th, (void *) lm,
+ offset, &address);
+
+#ifdef THREAD_DB_HAS_TD_NOTALLOC
+ /* The memory hasn't been allocated, yet. */
+ if (err == TD_NOTALLOC)
+ {
+ /* Now, if libthread_db provided the initialization image's
+ address, we *could* try to build a non-lvalue value from
+ the initialization image. */
+ if (objfile_is_library)
+ error ("The inferior has not yet allocated storage for"
+ " thread-local variables in\n"
+ "the shared library `%s'\n"
+ "for the thread %ld",
+ objfile->name, (long) GET_THREAD (ptid));
+ else
+ error ("The inferior has not yet allocated storage for"
+ " thread-local variables in\n"
+ "the executable `%s'\n"
+ "for the thread %ld",
+ objfile->name, (long) GET_THREAD (ptid));
+ }
+#endif
+
+ /* Something else went wrong. */
+ if (err != TD_OK)
+ {
+ if (objfile_is_library)
+ error ("Cannot find thread-local storage for thread %ld, "
+ "shared library %s:\n%s",
+ (long) GET_THREAD (ptid),
+ objfile->name, thread_db_err_str (err));
+ else
+ error ("Cannot find thread-local storage for thread %ld, "
+ "executable file %s:\n%s",
+ (long) GET_THREAD (ptid),
+ objfile->name, thread_db_err_str (err));
+ }
+
+ /* Cast assuming host == target. Joy. */
+ return (CORE_ADDR) address;
+ }
+
+ if (target_beneath->to_get_thread_local_address)
+ return target_beneath->to_get_thread_local_address (ptid, objfile,
+ offset);
+
+ error ("Cannot find thread-local values on this target.");
+}
+
+static void
+init_thread_db_ops (void)
+{
+ thread_db_ops.to_shortname = "multi-thread";
+ thread_db_ops.to_longname = "multi-threaded child process.";
+ thread_db_ops.to_doc = "Threads and pthreads support.";
+ thread_db_ops.to_attach = thread_db_attach;
+ thread_db_ops.to_detach = thread_db_detach;
+ thread_db_ops.to_resume = thread_db_resume;
+ thread_db_ops.to_wait = thread_db_wait;
+ thread_db_ops.to_fetch_registers = thread_db_fetch_registers;
+ thread_db_ops.to_store_registers = thread_db_store_registers;
+ thread_db_ops.to_xfer_memory = thread_db_xfer_memory;
+ thread_db_ops.to_kill = thread_db_kill;
+ thread_db_ops.to_create_inferior = thread_db_create_inferior;
+ thread_db_ops.to_post_startup_inferior = thread_db_post_startup_inferior;
+ thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
+ thread_db_ops.to_thread_alive = thread_db_thread_alive;
+ thread_db_ops.to_find_new_threads = thread_db_find_new_threads;
+ thread_db_ops.to_pid_to_str = thread_db_pid_to_str;
+ thread_db_ops.to_stratum = thread_stratum;
+ thread_db_ops.to_has_thread_control = tc_schedlock;
+ thread_db_ops.to_get_thread_local_address
+ = thread_db_get_thread_local_address;
+ thread_db_ops.to_magic = OPS_MAGIC;
+}
+
+void
+_initialize_thread_db (void)
+{
+ /* Only initialize the module if we can load libthread_db. */
+ if (thread_db_load ())
+ {
+ init_thread_db_ops ();
+ add_target (&thread_db_ops);
+
+ /* Add ourselves to objfile event chain. */
+ target_new_objfile_chain = target_new_objfile_hook;
+ target_new_objfile_hook = thread_db_new_objfile;
+ }
+}
diff --git a/contrib/gdb/gdb/thread.c b/contrib/gdb/gdb/thread.c
new file mode 100644
index 0000000..f8cc18d
--- /dev/null
+++ b/contrib/gdb/gdb/thread.c
@@ -0,0 +1,743 @@
+/* Multi-process/thread control for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbthread.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "gdb.h"
+#include "gdb_string.h"
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+#include "ui-out.h"
+
+/*#include "lynxos-core.h" */
+
+/* Definition of struct thread_info exported to gdbthread.h */
+
+/* Prototypes for exported functions. */
+
+void _initialize_thread (void);
+
+/* Prototypes for local functions. */
+
+static struct thread_info *thread_list = NULL;
+static int highest_thread_num;
+
+static struct thread_info *find_thread_id (int num);
+
+static void thread_command (char *tidstr, int from_tty);
+static void thread_apply_all_command (char *, int);
+static int thread_alive (struct thread_info *);
+static void info_threads_command (char *, int);
+static void thread_apply_command (char *, int);
+static void restore_current_thread (ptid_t);
+static void switch_to_thread (ptid_t ptid);
+static void prune_threads (void);
+
+void
+delete_step_resume_breakpoint (void *arg)
+{
+ struct breakpoint **breakpointp = (struct breakpoint **) arg;
+ struct thread_info *tp;
+
+ if (*breakpointp != NULL)
+ {
+ delete_breakpoint (*breakpointp);
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->step_resume_breakpoint == *breakpointp)
+ tp->step_resume_breakpoint = NULL;
+
+ *breakpointp = NULL;
+ }
+}
+
+static void
+free_thread (struct thread_info *tp)
+{
+ /* NOTE: this will take care of any left-over step_resume breakpoints,
+ but not any user-specified thread-specific breakpoints. */
+ if (tp->step_resume_breakpoint)
+ delete_breakpoint (tp->step_resume_breakpoint);
+
+ /* FIXME: do I ever need to call the back-end to give it a
+ chance at this private data before deleting the thread? */
+ if (tp->private)
+ xfree (tp->private);
+
+ xfree (tp);
+}
+
+void
+init_thread_list (void)
+{
+ struct thread_info *tp, *tpnext;
+
+ highest_thread_num = 0;
+ if (!thread_list)
+ return;
+
+ for (tp = thread_list; tp; tp = tpnext)
+ {
+ tpnext = tp->next;
+ free_thread (tp);
+ }
+
+ thread_list = NULL;
+}
+
+/* add_thread now returns a pointer to the new thread_info,
+ so that back_ends can initialize their private data. */
+
+struct thread_info *
+add_thread (ptid_t ptid)
+{
+ struct thread_info *tp;
+
+ tp = (struct thread_info *) xmalloc (sizeof (*tp));
+ memset (tp, 0, sizeof (*tp));
+ tp->ptid = ptid;
+ tp->num = ++highest_thread_num;
+ tp->next = thread_list;
+ thread_list = tp;
+ return tp;
+}
+
+void
+delete_thread (ptid_t ptid)
+{
+ struct thread_info *tp, *tpprev;
+
+ tpprev = NULL;
+
+ for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
+ if (ptid_equal (tp->ptid, ptid))
+ break;
+
+ if (!tp)
+ return;
+
+ if (tpprev)
+ tpprev->next = tp->next;
+ else
+ thread_list = tp->next;
+
+ free_thread (tp);
+}
+
+static struct thread_info *
+find_thread_id (int num)
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->num == num)
+ return tp;
+
+ return NULL;
+}
+
+/* Find a thread_info by matching PTID. */
+struct thread_info *
+find_thread_pid (ptid_t ptid)
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (ptid_equal (tp->ptid, ptid))
+ return tp;
+
+ return NULL;
+}
+
+/*
+ * Thread iterator function.
+ *
+ * Calls a callback function once for each thread, so long as
+ * the callback function returns false. If the callback function
+ * returns true, the iteration will end and the current thread
+ * will be returned. This can be useful for implementing a
+ * search for a thread with arbitrary attributes, or for applying
+ * some operation to every thread.
+ *
+ * FIXME: some of the existing functionality, such as
+ * "Thread apply all", might be rewritten using this functionality.
+ */
+
+struct thread_info *
+iterate_over_threads (int (*callback) (struct thread_info *, void *),
+ void *data)
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if ((*callback) (tp, data))
+ return tp;
+
+ return NULL;
+}
+
+int
+valid_thread_id (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 (ptid_t ptid)
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (ptid_equal (tp->ptid, ptid))
+ return tp->num;
+
+ return 0;
+}
+
+ptid_t
+thread_id_to_pid (int num)
+{
+ struct thread_info *thread = find_thread_id (num);
+ if (thread)
+ return thread->ptid;
+ else
+ return pid_to_ptid (-1);
+}
+
+int
+in_thread_list (ptid_t ptid)
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (ptid_equal (tp->ptid, ptid))
+ return 1;
+
+ return 0; /* Never heard of 'im */
+}
+
+/* Print a list of thread ids currently known, and the total number of
+ threads. To be used from within catch_errors. */
+static int
+do_captured_list_thread_ids (struct ui_out *uiout, void *arg)
+{
+ struct thread_info *tp;
+ int num = 0;
+ struct cleanup *cleanup_chain;
+
+ prune_threads ();
+ target_find_new_threads ();
+
+ cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "thread-ids");
+
+ for (tp = thread_list; tp; tp = tp->next)
+ {
+ num++;
+ ui_out_field_int (uiout, "thread-id", tp->num);
+ }
+
+ do_cleanups (cleanup_chain);
+ ui_out_field_int (uiout, "number-of-threads", num);
+ return GDB_RC_OK;
+}
+
+/* Official gdblib interface function to get a list of thread ids and
+ the total number. */
+enum gdb_rc
+gdb_list_thread_ids (struct ui_out *uiout)
+{
+ return catch_exceptions (uiout, do_captured_list_thread_ids, NULL,
+ NULL, RETURN_MASK_ALL);
+}
+
+/* Load infrun state for the thread PID. */
+
+void
+load_infrun_state (ptid_t ptid,
+ CORE_ADDR *prev_pc,
+ int *trap_expected,
+ struct breakpoint **step_resume_breakpoint,
+ struct breakpoint **through_sigtramp_breakpoint,
+ CORE_ADDR *step_range_start,
+ CORE_ADDR *step_range_end,
+ struct frame_id *step_frame_id,
+ int *handling_longjmp,
+ int *another_trap,
+ int *stepping_through_solib_after_catch,
+ bpstat *stepping_through_solib_catchpoints,
+ int *stepping_through_sigtramp,
+ int *current_line,
+ struct symtab **current_symtab, CORE_ADDR *step_sp)
+{
+ 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 (ptid));
+ if (tp == NULL)
+ return;
+
+ *prev_pc = tp->prev_pc;
+ *trap_expected = tp->trap_expected;
+ *step_resume_breakpoint = tp->step_resume_breakpoint;
+ *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint;
+ *step_range_start = tp->step_range_start;
+ *step_range_end = tp->step_range_end;
+ *step_frame_id = tp->step_frame_id;
+ *handling_longjmp = tp->handling_longjmp;
+ *another_trap = tp->another_trap;
+ *stepping_through_solib_after_catch =
+ tp->stepping_through_solib_after_catch;
+ *stepping_through_solib_catchpoints =
+ tp->stepping_through_solib_catchpoints;
+ *stepping_through_sigtramp = tp->stepping_through_sigtramp;
+ *current_line = tp->current_line;
+ *current_symtab = tp->current_symtab;
+ *step_sp = tp->step_sp;
+}
+
+/* Save infrun state for the thread PID. */
+
+void
+save_infrun_state (ptid_t ptid,
+ CORE_ADDR prev_pc,
+ int trap_expected,
+ struct breakpoint *step_resume_breakpoint,
+ struct breakpoint *through_sigtramp_breakpoint,
+ CORE_ADDR step_range_start,
+ CORE_ADDR step_range_end,
+ const struct frame_id *step_frame_id,
+ int handling_longjmp,
+ int another_trap,
+ int stepping_through_solib_after_catch,
+ bpstat stepping_through_solib_catchpoints,
+ int stepping_through_sigtramp,
+ int current_line,
+ struct symtab *current_symtab, CORE_ADDR step_sp)
+{
+ 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 (ptid));
+ if (tp == NULL)
+ return;
+
+ tp->prev_pc = prev_pc;
+ tp->trap_expected = trap_expected;
+ tp->step_resume_breakpoint = step_resume_breakpoint;
+ tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint;
+ tp->step_range_start = step_range_start;
+ tp->step_range_end = step_range_end;
+ tp->step_frame_id = (*step_frame_id);
+ tp->handling_longjmp = handling_longjmp;
+ tp->another_trap = another_trap;
+ tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch;
+ tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
+ tp->stepping_through_sigtramp = stepping_through_sigtramp;
+ tp->current_line = current_line;
+ tp->current_symtab = current_symtab;
+ tp->step_sp = step_sp;
+}
+
+/* Return true if TP is an active thread. */
+static int
+thread_alive (struct thread_info *tp)
+{
+ if (PIDGET (tp->ptid) == -1)
+ return 0;
+ if (!target_thread_alive (tp->ptid))
+ {
+ tp->ptid = pid_to_ptid (-1); /* Mark it as dead */
+ return 0;
+ }
+ return 1;
+}
+
+static void
+prune_threads (void)
+{
+ struct thread_info *tp, *next;
+
+ for (tp = thread_list; tp; tp = next)
+ {
+ next = tp->next;
+ if (!thread_alive (tp))
+ delete_thread (tp->ptid);
+ }
+}
+
+/* Print information about currently known threads
+
+ * Note: this has the drawback that it _really_ switches
+ * threads, which frees the frame cache. A no-side
+ * effects info-threads command would be nicer.
+ */
+
+static void
+info_threads_command (char *arg, int from_tty)
+{
+ struct thread_info *tp;
+ ptid_t current_ptid;
+ struct frame_info *cur_frame;
+ int saved_frame_level = frame_relative_level (get_selected_frame ());
+ int counter;
+ char *extra_info;
+
+ /* Check that there really is a frame. This happens when a simulator
+ is connected but not loaded or running, for instance. */
+ if (legacy_frame_p (current_gdbarch) && saved_frame_level < 0)
+ error ("No frame.");
+
+ prune_threads ();
+ target_find_new_threads ();
+ current_ptid = inferior_ptid;
+ for (tp = thread_list; tp; tp = tp->next)
+ {
+ if (ptid_equal (tp->ptid, current_ptid))
+ printf_filtered ("* ");
+ else
+ printf_filtered (" ");
+
+#ifdef HPUXHPPA
+ printf_filtered ("%d %s", tp->num, target_tid_to_str (tp->ptid));
+#else
+ printf_filtered ("%d %s", tp->num, target_pid_to_str (tp->ptid));
+#endif
+
+ extra_info = target_extra_thread_info (tp);
+ if (extra_info)
+ printf_filtered (" (%s)", extra_info);
+ puts_filtered (" ");
+
+ switch_to_thread (tp->ptid);
+ print_stack_frame (get_selected_frame (), -1, 0);
+ }
+
+ switch_to_thread (current_ptid);
+
+ /* Code below copied from "up_silently_base" in "stack.c".
+ * It restores the frame set by the user before the "info threads"
+ * command. We have finished the info-threads display by switching
+ * back to the current thread. That switch has put us at the top
+ * of the stack (leaf frame).
+ */
+ counter = saved_frame_level;
+ cur_frame = find_relative_frame (get_selected_frame (), &counter);
+ if (counter != 0)
+ {
+ /* Ooops, can't restore, tell user where we are. */
+ warning ("Couldn't restore frame in current thread, at frame 0");
+ print_stack_frame (get_selected_frame (), -1, 0);
+ }
+ else
+ {
+ select_frame (cur_frame);
+ }
+
+ /* re-show current frame. */
+ show_stack_frame (cur_frame);
+}
+
+/* Switch from one thread to another. */
+
+static void
+switch_to_thread (ptid_t ptid)
+{
+ if (ptid_equal (ptid, inferior_ptid))
+ return;
+
+ inferior_ptid = ptid;
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc ();
+ select_frame (get_current_frame ());
+}
+
+static void
+restore_current_thread (ptid_t ptid)
+{
+ if (!ptid_equal (ptid, inferior_ptid))
+ {
+ switch_to_thread (ptid);
+ print_stack_frame (get_current_frame (), 0, -1);
+ }
+}
+
+struct current_thread_cleanup
+{
+ ptid_t inferior_ptid;
+};
+
+static void
+do_restore_current_thread_cleanup (void *arg)
+{
+ struct current_thread_cleanup *old = arg;
+ restore_current_thread (old->inferior_ptid);
+ xfree (old);
+}
+
+static struct cleanup *
+make_cleanup_restore_current_thread (ptid_t inferior_ptid)
+{
+ struct current_thread_cleanup *old
+ = xmalloc (sizeof (struct current_thread_cleanup));
+ old->inferior_ptid = inferior_ptid;
+ return make_cleanup (do_restore_current_thread_cleanup, old);
+}
+
+/* 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 (char *cmd, int from_tty)
+{
+ struct thread_info *tp;
+ struct cleanup *old_chain;
+ struct cleanup *saved_cmd_cleanup_chain;
+ char *saved_cmd;
+
+ if (cmd == NULL || *cmd == '\000')
+ error ("Please specify a command following the thread ID list");
+
+ old_chain = make_cleanup_restore_current_thread (inferior_ptid);
+
+ /* It is safe to update the thread list now, before
+ traversing it for "thread apply all". MVS */
+ target_find_new_threads ();
+
+ /* Save a copy of the command in case it is clobbered by
+ execute_command */
+ saved_cmd = xstrdup (cmd);
+ saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd);
+ for (tp = thread_list; tp; tp = tp->next)
+ if (thread_alive (tp))
+ {
+ switch_to_thread (tp->ptid);
+#ifdef HPUXHPPA
+ printf_filtered ("\nThread %d (%s):\n",
+ tp->num, target_tid_to_str (inferior_ptid));
+#else
+ printf_filtered ("\nThread %d (%s):\n", tp->num,
+ target_pid_to_str (inferior_ptid));
+#endif
+ execute_command (cmd, from_tty);
+ strcpy (cmd, saved_cmd); /* Restore exact command used previously */
+ }
+
+ do_cleanups (saved_cmd_cleanup_chain);
+ do_cleanups (old_chain);
+}
+
+static void
+thread_apply_command (char *tidlist, int from_tty)
+{
+ char *cmd;
+ char *p;
+ struct cleanup *old_chain;
+ struct cleanup *saved_cmd_cleanup_chain;
+ char *saved_cmd;
+
+ 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_ptid);
+
+ /* Save a copy of the command in case it is clobbered by
+ execute_command */
+ saved_cmd = xstrdup (cmd);
+ saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd);
+ 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);
+ else if (!thread_alive (tp))
+ warning ("Thread %d has terminated.", start);
+ else
+ {
+ switch_to_thread (tp->ptid);
+#ifdef HPUXHPPA
+ printf_filtered ("\nThread %d (%s):\n", tp->num,
+ target_tid_to_str (inferior_ptid));
+#else
+ printf_filtered ("\nThread %d (%s):\n", tp->num,
+ target_pid_to_str (inferior_ptid));
+#endif
+ execute_command (cmd, from_tty);
+ strcpy (cmd, saved_cmd); /* Restore exact command used previously */
+ }
+ }
+ }
+
+ do_cleanups (saved_cmd_cleanup_chain);
+ do_cleanups (old_chain);
+}
+
+/* Switch to the specified thread. Will dispatch off to thread_apply_command
+ if prefix of arg is `apply'. */
+
+static void
+thread_command (char *tidstr, int from_tty)
+{
+ if (!tidstr)
+ {
+ /* Don't generate an error, just say which thread is current. */
+ if (target_has_stack)
+ printf_filtered ("[Current thread is %d (%s)]\n",
+ pid_to_thread_id (inferior_ptid),
+#if defined(HPUXHPPA)
+ target_tid_to_str (inferior_ptid)
+#else
+ target_pid_to_str (inferior_ptid)
+#endif
+ );
+ else
+ error ("No stack.");
+ return;
+ }
+
+ gdb_thread_select (uiout, tidstr);
+}
+
+static int
+do_captured_thread_select (struct ui_out *uiout, void *tidstr)
+{
+ int num;
+ struct thread_info *tp;
+
+ num = value_as_long (parse_and_eval (tidstr));
+
+ tp = find_thread_id (num);
+
+ if (!tp)
+ error ("Thread ID %d not known.", num);
+
+ if (!thread_alive (tp))
+ error ("Thread ID %d has terminated.\n", num);
+
+ switch_to_thread (tp->ptid);
+
+ ui_out_text (uiout, "[Switching to thread ");
+ ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
+ ui_out_text (uiout, " (");
+#if defined(HPUXHPPA)
+ ui_out_text (uiout, target_tid_to_str (inferior_ptid));
+#else
+ ui_out_text (uiout, target_pid_to_str (inferior_ptid));
+#endif
+ ui_out_text (uiout, ")]");
+
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame), 1);
+ return GDB_RC_OK;
+}
+
+enum gdb_rc
+gdb_thread_select (struct ui_out *uiout, char *tidstr)
+{
+ return catch_exceptions (uiout, do_captured_thread_select, tidstr,
+ NULL, RETURN_MASK_ALL);
+}
+
+/* Commands with a prefix of `thread'. */
+struct cmd_list_element *thread_cmd_list = NULL;
+
+void
+_initialize_thread (void)
+{
+ static struct cmd_list_element *thread_apply_list = NULL;
+
+ 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);
+
+ if (!xdb_commands)
+ add_com_alias ("t", "thread", class_run, 1);
+}
diff --git a/contrib/gdb/gdb/top.c b/contrib/gdb/gdb/top.c
new file mode 100644
index 0000000..d6bdfd0
--- /dev/null
+++ b/contrib/gdb/gdb/top.c
@@ -0,0 +1,1912 @@
+/* Top level stuff for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "cli/cli-cmds.h"
+#include "cli/cli-script.h"
+#include "cli/cli-setshow.h"
+#include "cli/cli-decode.h"
+#include "symtab.h"
+#include "inferior.h"
+#include <signal.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 "completer.h"
+#include "top.h"
+#include "version.h"
+#include "serial.h"
+#include "doublest.h"
+#include "gdb_assert.h"
+
+/* readline include files */
+#include "readline/readline.h"
+#include "readline/history.h"
+
+/* readline defines this. */
+#undef savestring
+
+#include <sys/types.h>
+
+#include <setjmp.h>
+
+#include "event-top.h"
+#include "gdb_string.h"
+#include "gdb_stat.h"
+#include <ctype.h>
+#include "ui-out.h"
+#include "cli-out.h"
+
+/* Default command line prompt. This is overriden in some configs. */
+
+#ifndef DEFAULT_PROMPT
+#define DEFAULT_PROMPT "(gdb) "
+#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 = 0;
+
+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. */
+
+/* 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 or interacting via a GUI. */
+
+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) (FILE *, char *);
+
+int epoch_interface;
+int xgdb_verbose;
+
+/* gdb prints this when reading a command interactively */
+static char *gdb_prompt_string; /* the global prompt string */
+
+/* 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, commands
+ 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;
+
+/* Timeout limit for response from target. */
+
+/* The default value has been changed many times over the years. It
+ was originally 5 seconds. But that was thought to be a long time
+ to sit and wait, so it was changed to 2 seconds. That was thought
+ to be plenty unless the connection was going through some terminal
+ server or multiplexer or other form of hairy serial connection.
+
+ In mid-1996, remote_timeout was moved from remote.c to top.c and
+ it began being used in other remote-* targets. It appears that the
+ default was changed to 20 seconds at that time, perhaps because the
+ Renesas E7000 ICE didn't always respond in a timely manner.
+
+ But if 5 seconds is a long time to sit and wait for retransmissions,
+ 20 seconds is far worse. This demonstrates the difficulty of using
+ a single variable for all protocol timeouts.
+
+ As remote.c is used much more than remote-e7000.c, it was changed
+ back to 2 seconds in 1999. */
+
+int remote_timeout = 2;
+
+/* Non-zero tells remote* modules to output debugging info. */
+
+int remote_debug = 0;
+
+/* Non-zero means the target is running. Note: this is different from
+ saying that there is an active target and we are stopped at a
+ breakpoint, for instance. This is a real indicator whether the
+ target is off and running, which gdb is doing something else. */
+int target_executing = 0;
+
+/* Level of control structure. */
+static int control_level;
+
+/* Sbrk location on entry to main. Used for statistics only. */
+#ifdef HAVE_SBRK
+char *lim_at_start;
+#endif
+
+/* 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 (int);
+#endif
+#endif
+
+/* Hooks for alternate command interfaces. */
+
+/* Called after most modules have been initialized, but before taking users
+ command file.
+
+ If the UI fails to initialize and it wants GDB to continue
+ using the default UI, then it should clear this hook before returning. */
+
+void (*init_ui_hook) (char *argv0);
+
+/* This hook is called from within gdb's many mini-event loops which could
+ steal control from a real user interface's event loop. It returns
+ non-zero if the user is requesting a detach, zero otherwise. */
+
+int (*ui_loop_hook) (int);
+
+/* Called instead of command_loop at top level. Can be invoked via
+ throw_exception(). */
+
+void (*command_loop_hook) (void);
+
+
+/* Called from print_frame_info to list the line we stopped in. */
+
+void (*print_frame_info_listing_hook) (struct symtab * s, int line,
+ int stopline, int noerror);
+/* Replaces most of query. */
+
+int (*query_hook) (const char *, va_list);
+
+/* Replaces most of warning. */
+
+void (*warning_hook) (const char *, va_list);
+
+/* These three functions support getting lines of text from the user. They
+ are used in sequence. First readline_begin_hook is called with a text
+ string that might be (for example) a message for the user to type in a
+ sequence of commands to be executed at a breakpoint. If this function
+ calls back to a GUI, it might take this opportunity to pop up a text
+ interaction window with this message. Next, readline_hook is called
+ with a prompt that is emitted prior to collecting the user input.
+ It can be called multiple times. Finally, readline_end_hook is called
+ to notify the GUI that we are done with the interaction window and it
+ can close it. */
+
+void (*readline_begin_hook) (char *, ...);
+char *(*readline_hook) (char *);
+void (*readline_end_hook) (void);
+
+/* Called as appropriate to notify the interface of the specified breakpoint
+ conditions. */
+
+void (*create_breakpoint_hook) (struct breakpoint * bpt);
+void (*delete_breakpoint_hook) (struct breakpoint * bpt);
+void (*modify_breakpoint_hook) (struct breakpoint * bpt);
+
+/* Called as appropriate to notify the interface that we have attached
+ to or detached from an already running process. */
+
+void (*attach_hook) (void);
+void (*detach_hook) (void);
+
+/* Called during long calculations to allow GUI to repair window damage, and to
+ check for stop buttons, etc... */
+
+void (*interactive_hook) (void);
+
+/* Called when the registers have changed, as a hint to a GUI
+ to minimize window update. */
+
+void (*registers_changed_hook) (void);
+
+/* Tell the GUI someone changed the register REGNO. -1 means
+ that the caller does not know which register changed or
+ that several registers have changed (see value_assign). */
+void (*register_changed_hook) (int regno);
+
+/* Tell the GUI someone changed LEN bytes of memory at ADDR */
+void (*memory_changed_hook) (CORE_ADDR addr, int len);
+
+/* Called when going to wait for the target. Usually allows the GUI to run
+ while waiting for target events. */
+
+ptid_t (*target_wait_hook) (ptid_t ptid,
+ 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) (struct cmd_list_element * c, char *cmd,
+ int from_tty);
+
+/* Called after a `set' command has finished. Is only run if the
+ `set' command succeeded. */
+
+void (*set_hook) (struct cmd_list_element * c);
+
+/* Called when the current thread changes. Argument is thread id. */
+
+void (*context_hook) (int id);
+
+/* 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) (void) ATTR_NORETURN;
+
+
+/* One should use catch_errors rather than manipulating these
+ directly. */
+#if defined(HAVE_SIGSETJMP)
+#define SIGJMP_BUF sigjmp_buf
+#define SIGSETJMP(buf) sigsetjmp((buf), 1)
+#define SIGLONGJMP(buf,val) siglongjmp((buf), (val))
+#else
+#define SIGJMP_BUF jmp_buf
+#define SIGSETJMP(buf) setjmp(buf)
+#define SIGLONGJMP(buf,val) longjmp((buf), (val))
+#endif
+
+/* Where to go for throw_exception(). */
+static SIGJMP_BUF *catch_return;
+
+/* Return for reason REASON to the nearest containing catch_errors(). */
+
+NORETURN void
+throw_exception (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 (event_loop_p && target_can_async_p () && !target_executing)
+ do_exec_cleanups (ALL_CLEANUPS);
+ if (event_loop_p && sync_execution)
+ do_exec_error_cleanups (ALL_CLEANUPS);
+
+ if (annotation_level > 1)
+ switch (reason)
+ {
+ case RETURN_QUIT:
+ annotate_quit ();
+ break;
+ case RETURN_ERROR:
+ annotate_error ();
+ break;
+ }
+
+ /* Jump to the containing catch_errors() call, communicating REASON
+ to that call via setjmp's return value. Note that REASON can't
+ be zero, by definition in defs.h. */
+
+ (NORETURN void) SIGLONGJMP (*catch_return, (int) reason);
+}
+
+/* Call FUNC() with args FUNC_UIOUT and FUNC_ARGS, catching any
+ errors. Set FUNC_CAUGHT to an ``enum return_reason'' if the
+ function is aborted (using throw_exception() or zero if the
+ function returns normally. Set FUNC_VAL to the value returned by
+ the function or 0 if the function was aborted.
+
+ 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. */
+
+/* MAYBE: cagney/1999-11-05: catch_errors() in conjunction with
+ error() et.al. could maintain a set of flags that indicate the the
+ current state of each of the longjmp buffers. This would give the
+ longjmp code the chance to detect a longjmp botch (before it gets
+ to longjmperror()). Prior to 1999-11-05 this wasn't possible as
+ code also randomly used a SET_TOP_LEVEL macro that directly
+ initialize the longjmp buffers. */
+
+/* MAYBE: cagney/1999-11-05: Should the catch_errors and cleanups code
+ be consolidated into a single file instead of being distributed
+ between utils.c and top.c? */
+
+static void
+catcher (catch_exceptions_ftype *func,
+ struct ui_out *func_uiout,
+ void *func_args,
+ int *func_val,
+ enum return_reason *func_caught,
+ char *errstring,
+ char **gdberrmsg,
+ return_mask mask)
+{
+ SIGJMP_BUF *saved_catch;
+ SIGJMP_BUF catch;
+ struct cleanup *saved_cleanup_chain;
+ char *saved_error_pre_print;
+ char *saved_quit_pre_print;
+ struct ui_out *saved_uiout;
+
+ /* Return value from SIGSETJMP(): enum return_reason if error or
+ quit caught, 0 otherwise. */
+ int caught;
+
+ /* Return value from FUNC(): Hopefully non-zero. Explicitly set to
+ zero if an error quit was caught. */
+ int val;
+
+ /* Override error/quit messages during FUNC. */
+
+ saved_error_pre_print = error_pre_print;
+ saved_quit_pre_print = quit_pre_print;
+
+ if (mask & RETURN_MASK_ERROR)
+ error_pre_print = errstring;
+ if (mask & RETURN_MASK_QUIT)
+ quit_pre_print = errstring;
+
+ /* Override the global ``struct ui_out'' builder. */
+
+ saved_uiout = uiout;
+ uiout = func_uiout;
+
+ /* Prevent error/quit during FUNC from calling cleanups established
+ prior to here. */
+
+ saved_cleanup_chain = save_cleanups ();
+
+ /* Call FUNC, catching error/quit events. */
+
+ saved_catch = catch_return;
+ catch_return = &catch;
+ caught = SIGSETJMP (catch);
+ if (!caught)
+ val = (*func) (func_uiout, func_args);
+ else
+ {
+ val = 0;
+ /* If caller wants a copy of the low-level error message, make one.
+ This is used in the case of a silent error whereby the caller
+ may optionally want to issue the message. */
+ if (gdberrmsg)
+ *gdberrmsg = error_last_message ();
+ }
+ catch_return = saved_catch;
+
+ /* FIXME: cagney/1999-11-05: A correct FUNC implementation will
+ clean things up (restoring the cleanup chain) to the state they
+ were just prior to the call. Unfortunately, many FUNC's are not
+ that well behaved. This could be fixed by adding either a
+ do_cleanups call (to cover the problem) or an assertion check to
+ detect bad FUNCs code. */
+
+ /* Restore the cleanup chain, the error/quit messages, and the uiout
+ builder, to their original states. */
+
+ restore_cleanups (saved_cleanup_chain);
+
+ uiout = saved_uiout;
+
+ if (mask & RETURN_MASK_QUIT)
+ quit_pre_print = saved_quit_pre_print;
+ if (mask & RETURN_MASK_ERROR)
+ error_pre_print = saved_error_pre_print;
+
+ /* Return normally if no error/quit event occurred or this catcher
+ can handle this exception. The caller analyses the func return
+ values. */
+
+ if (!caught || (mask & RETURN_MASK (caught)))
+ {
+ *func_val = val;
+ *func_caught = caught;
+ return;
+ }
+
+ /* The caller didn't request that the event be caught, relay the
+ event to the next containing catch_errors(). */
+
+ throw_exception (caught);
+}
+
+int
+catch_exceptions (struct ui_out *uiout,
+ catch_exceptions_ftype *func,
+ void *func_args,
+ char *errstring,
+ return_mask mask)
+{
+ int val;
+ enum return_reason caught;
+ catcher (func, uiout, func_args, &val, &caught, errstring, NULL, mask);
+ gdb_assert (val >= 0);
+ gdb_assert (caught <= 0);
+ if (caught < 0)
+ return caught;
+ return val;
+}
+
+int
+catch_exceptions_with_msg (struct ui_out *uiout,
+ catch_exceptions_ftype *func,
+ void *func_args,
+ char *errstring,
+ char **gdberrmsg,
+ return_mask mask)
+{
+ int val;
+ enum return_reason caught;
+ catcher (func, uiout, func_args, &val, &caught, errstring, gdberrmsg, mask);
+ gdb_assert (val >= 0);
+ gdb_assert (caught <= 0);
+ if (caught < 0)
+ return caught;
+ return val;
+}
+
+struct catch_errors_args
+{
+ catch_errors_ftype *func;
+ void *func_args;
+};
+
+static int
+do_catch_errors (struct ui_out *uiout, void *data)
+{
+ struct catch_errors_args *args = data;
+ return args->func (args->func_args);
+}
+
+int
+catch_errors (catch_errors_ftype *func, void *func_args, char *errstring,
+ return_mask mask)
+{
+ int val;
+ enum return_reason caught;
+ struct catch_errors_args args;
+ args.func = func;
+ args.func_args = func_args;
+ catcher (do_catch_errors, uiout, &args, &val, &caught, errstring,
+ NULL, mask);
+ if (caught != 0)
+ return 0;
+ return val;
+}
+
+struct captured_command_args
+ {
+ catch_command_errors_ftype *command;
+ char *arg;
+ int from_tty;
+ };
+
+static int
+do_captured_command (void *data)
+{
+ struct captured_command_args *context = data;
+ context->command (context->arg, context->from_tty);
+ /* FIXME: cagney/1999-11-07: Technically this do_cleanups() call
+ isn't needed. Instead an assertion check could be made that
+ simply confirmed that the called function correctly cleaned up
+ after itself. Unfortunately, old code (prior to 1999-11-04) in
+ main.c was calling SET_TOP_LEVEL(), calling the command function,
+ and then *always* calling do_cleanups(). For the moment we
+ remain ``bug compatible'' with that old code.. */
+ do_cleanups (ALL_CLEANUPS);
+ return 1;
+}
+
+int
+catch_command_errors (catch_command_errors_ftype * command,
+ char *arg, int from_tty, return_mask mask)
+{
+ struct captured_command_args args;
+ args.command = command;
+ args.arg = arg;
+ args.from_tty = from_tty;
+ return catch_errors (do_captured_command, &args, "", mask);
+}
+
+
+/* Handler for SIGHUP. */
+
+#ifdef SIGHUP
+/* Just a little helper function for disconnect(). */
+
+/* NOTE 1999-04-29: This function will be static again, once we modify
+ gdb to use the event loop as the default command loop and we merge
+ event-top.c into this file, top.c */
+/* static */ int
+quit_cover (void *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;
+}
+
+static void
+disconnect (int signo)
+{
+ catch_errors (quit_cover, NULL,
+ "Could not kill the program being debugged", RETURN_MASK_ALL);
+ signal (SIGHUP, SIG_DFL);
+ kill (getpid (), SIGHUP);
+}
+#endif /* defined SIGHUP */
+
+/* Line number we are currently in in a file which is being sourced. */
+/* NOTE 1999-04-29: This variable will be static again, once we modify
+ gdb to use the event loop as the default command loop and we merge
+ event-top.c into this file, top.c */
+/* static */ int source_line_number;
+
+/* Name of the file we are sourcing. */
+/* NOTE 1999-04-29: This variable will be static again, once we modify
+ gdb to use the event loop as the default command loop and we merge
+ event-top.c into this file, top.c */
+/* static */ char *source_file_name;
+
+/* Buffer containing the error_pre_print used by the source stuff.
+ Malloc'd. */
+/* NOTE 1999-04-29: This variable will be static again, once we modify
+ gdb to use the event loop as the default command loop and we merge
+ event-top.c into this file, top.c */
+/* 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. */
+/* NOTE 1999-04-29: This variable will be static again, once we modify
+ gdb to use the event loop as the default command loop and we merge
+ event-top.c into this file, top.c */
+/* static */ char *source_pre_error;
+
+/* Clean up on error during a "source" command (or execution of a
+ user-defined command). */
+
+void
+do_restore_instream_cleanup (void *stream)
+{
+ /* Restore the previous input stream. */
+ instream = stream;
+}
+
+/* Read commands from STREAM. */
+void
+read_command_file (FILE *stream)
+{
+ struct cleanup *cleanups;
+
+ cleanups = make_cleanup (do_restore_instream_cleanup, instream);
+ instream = stream;
+ command_loop ();
+ do_cleanups (cleanups);
+}
+
+void (*pre_init_ui_hook) (void);
+
+#ifdef __MSDOS__
+void
+do_chdir_cleanup (void *old_dir)
+{
+ chdir (old_dir);
+ xfree (old_dir);
+}
+#endif
+
+/* Execute the line P as a command.
+ Pass FROM_TTY as second argument to the defining function. */
+
+void
+execute_command (char *p, int from_tty)
+{
+ struct cmd_list_element *c;
+ enum language flang;
+ static int warned = 0;
+ char *line;
+
+ free_all_values ();
+
+ /* Force cleanup of any alloca areas if using C alloca instead of
+ a builtin alloca. */
+ alloca (0);
+
+ /* This can happen when command_line_input hits end of file. */
+ if (p == NULL)
+ return;
+
+ serial_log_command (p);
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p)
+ {
+ char *arg;
+ line = p;
+
+ c = lookup_cmd (&p, cmdlist, "", 0, 1);
+
+ /* If the target is running, we allow only a limited set of
+ commands. */
+ if (event_loop_p && target_can_async_p () && target_executing)
+ if (strcmp (c->name, "help") != 0
+ && strcmp (c->name, "pwd") != 0
+ && strcmp (c->name, "show") != 0
+ && strcmp (c->name, "stop") != 0)
+ error ("Cannot execute this command while the target is running.");
+
+ /* Pass null arg rather than an empty one. */
+ arg = *p ? p : 0;
+
+ /* FIXME: cagney/2002-02-02: The c->type test is pretty dodgy
+ while the is_complete_command(cfunc) test is just plain
+ bogus. They should both be replaced by a test of the form
+ c->strip_trailing_white_space_p. */
+ /* NOTE: cagney/2002-02-02: The function.cfunc in the below
+ can't be replaced with func. This is because it is the
+ cfunc, and not the func, that has the value that the
+ is_complete_command hack is testing for. */
+ /* Clear off trailing whitespace, except for set and complete
+ command. */
+ if (arg
+ && c->type != set_cmd
+ && !is_complete_command (c))
+ {
+ p = arg + strlen (arg) - 1;
+ while (p >= arg && (*p == ' ' || *p == '\t'))
+ p--;
+ *(p + 1) = '\0';
+ }
+
+ /* If this command has been pre-hooked, run the hook first. */
+ execute_cmd_pre_hook (c);
+
+ if (c->flags & DEPRECATED_WARN_USER)
+ deprecated_cmd_warning (&line);
+
+ 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 (!cmd_func_p (c))
+ error ("That is not a command, just a help topic.");
+ else if (call_command_hook)
+ call_command_hook (c, arg, from_tty & caution);
+ else
+ cmd_func (c, arg, from_tty & caution);
+
+ /* If this command has been post-hooked, run the hook last. */
+ execute_cmd_post_hook (c);
+
+ }
+
+ /* 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;
+ }
+ }
+}
+
+/* Read commands from `instream' and execute them
+ until end of file or error reading instream. */
+
+void
+command_loop (void)
+{
+ 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 = 0;
+#endif
+ extern int display_time;
+ extern int display_space;
+
+ while (instream && !feof (instream))
+ {
+ if (window_hook && instream == stdin)
+ (*window_hook) (instream, get_prompt ());
+
+ quit_flag = 0;
+ if (instream == stdin && stdin_is_tty)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup (null_cleanup, 0);
+
+ /* Get a command-line. This calls the readline package. */
+ command = command_line_input (instream == stdin ?
+ get_prompt () : (char *) NULL,
+ instream == stdin, "prompt");
+ if (command == 0)
+ return;
+
+ time_at_cmd_start = get_run_time ();
+
+ if (display_space)
+ {
+#ifdef HAVE_SBRK
+ char *lim = (char *) sbrk (0);
+ space_at_cmd_start = lim - lim_at_start;
+#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
+ char *lim = (char *) sbrk (0);
+ long space_now = lim - lim_at_start;
+ 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
+ }
+ }
+}
+
+/* Read commands from `instream' and execute them until end of file or
+ error reading instream. This command loop doesnt care about any
+ such things as displaying time and space usage. If the user asks
+ for those, they won't work. */
+void
+simplified_command_loop (char *(*read_input_func) (char *),
+ void (*execute_command_func) (char *, int))
+{
+ struct cleanup *old_chain;
+ char *command;
+ int stdin_is_tty = ISATTY (stdin);
+
+ while (instream && !feof (instream))
+ {
+ quit_flag = 0;
+ if (instream == stdin && stdin_is_tty)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup (null_cleanup, 0);
+
+ /* Get a command-line. */
+ command = (*read_input_func) (instream == stdin ?
+ get_prompt () : (char *) NULL);
+
+ if (command == 0)
+ return;
+
+ (*execute_command_func) (command, instream == stdin);
+
+ /* Do any commands attached to breakpoint we stopped at. */
+ bpstat_do_actions (&stop_bpstat);
+
+ do_cleanups (old_chain);
+ }
+}
+
+/* Commands call this if they do not want to be repeated by null lines. */
+
+void
+dont_repeat (void)
+{
+ 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 PROMPT_ARG 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 (char *prompt_arg)
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ if (prompt_arg)
+ {
+ /* 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 (prompt_arg, gdb_stdout);
+ 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;
+ xfree (result);
+ return NULL;
+ }
+
+ if (c == '\n')
+#ifndef CRLF_SOURCE_FILES
+ break;
+#else
+ {
+ if (input_index > 0 && result[input_index - 1] == '\r')
+ input_index--;
+ break;
+ }
+#endif
+
+ 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;
+/* NOTE 1999-04-29: This variable will be static again, once we modify
+ gdb to use the event loop as the default command loop and we merge
+ event-top.c into this file, top.c */
+/* static */ int history_expansion_p;
+static int write_history_p;
+static int history_size;
+static char *history_filename;
+
+/* This is like readline(), but it has some gdb-specific behavior.
+ gdb can use readline in both the synchronous and async modes during
+ a single gdb invocation. At the ordinary top-level prompt we might
+ be using the async readline. That means we can't use
+ rl_pre_input_hook, since it doesn't work properly in async mode.
+ However, for a secondary prompt (" >", such as occurs during a
+ `define'), gdb just calls readline() directly, running it in
+ synchronous mode. So for operate-and-get-next to work in this
+ situation, we have to switch the hooks around. That is what
+ gdb_readline_wrapper is for. */
+char *
+gdb_readline_wrapper (char *prompt)
+{
+ /* Set the hook that works in this case. */
+ if (event_loop_p && after_char_processing_hook)
+ {
+ rl_pre_input_hook = (Function *) after_char_processing_hook;
+ after_char_processing_hook = NULL;
+ }
+
+ return readline (prompt);
+}
+
+
+#ifdef STOP_SIGNAL
+static void
+stop_sig (int signo)
+{
+#if STOP_SIGNAL == SIGTSTP
+ signal (SIGTSTP, SIG_DFL);
+#if HAVE_SIGPROCMASK
+ {
+ sigset_t zero;
+
+ sigemptyset (&zero);
+ sigprocmask (SIG_SETMASK, &zero, 0);
+ }
+#elif HAVE_SIGSETMASK
+ sigsetmask (0);
+#endif
+ kill (getpid (), SIGTSTP);
+ signal (SIGTSTP, stop_sig);
+#else
+ signal (STOP_SIGNAL, stop_sig);
+#endif
+ printf_unfiltered ("%s", get_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
+float_handler (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
+do_nothing (int signo)
+{
+ /* Under System V the default disposition of a signal is reinstated after
+ the signal is caught and delivered to an application process. On such
+ systems one must restore the replacement signal handler if one wishes
+ to continue handling the signal in one's program. On BSD systems this
+ is not needed but it is harmless, and it simplifies the code to just do
+ it unconditionally. */
+ signal (signo, do_nothing);
+}
+
+static void
+init_signals (void)
+{
+ 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);
+#ifdef SIGHUP
+ if (signal (SIGHUP, do_nothing) != SIG_IGN)
+ signal (SIGHUP, disconnect);
+#endif
+ signal (SIGFPE, float_handler);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+ signal (SIGWINCH, SIGWINCH_HANDLER);
+#endif
+}
+
+/* The current saved history number from operate-and-get-next.
+ This is -1 if not valid. */
+static int operate_saved_history = -1;
+
+/* This is put on the appropriate hook and helps operate-and-get-next
+ do its work. */
+static void
+gdb_rl_operate_and_get_next_completion (void)
+{
+ int delta = where_history () - operate_saved_history;
+ /* The `key' argument to rl_get_previous_history is ignored. */
+ rl_get_previous_history (delta, 0);
+ operate_saved_history = -1;
+
+ /* readline doesn't automatically update the display for us. */
+ rl_redisplay ();
+
+ after_char_processing_hook = NULL;
+ rl_pre_input_hook = NULL;
+}
+
+/* This is a gdb-local readline command handler. It accepts the
+ current command line (like RET does) and, if this command was taken
+ from the history, arranges for the next command in the history to
+ appear on the command line when the prompt returns.
+ We ignore the arguments. */
+static int
+gdb_rl_operate_and_get_next (int count, int key)
+{
+ int where;
+
+ if (event_loop_p)
+ {
+ /* Use the async hook. */
+ after_char_processing_hook = gdb_rl_operate_and_get_next_completion;
+ }
+ else
+ {
+ /* This hook only works correctly when we are using the
+ synchronous readline. */
+ rl_pre_input_hook = (Function *) gdb_rl_operate_and_get_next_completion;
+ }
+
+ /* Find the current line, and find the next line to use. */
+ where = where_history();
+
+ /* FIXME: kettenis/20020817: max_input_history is renamed into
+ history_max_entries in readline-4.2. When we do a new readline
+ import, we should probably change it here too, even though
+ readline maintains backwards compatibility for now by still
+ defining max_input_history. */
+ if ((history_is_stifled () && (history_length >= max_input_history)) ||
+ (where >= history_length - 1))
+ operate_saved_history = where;
+ else
+ operate_saved_history = where + 1;
+
+ return rl_newline (1, key);
+}
+
+/* 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 (char *prompt_arg, int repeat, char *annotation_suffix)
+{
+ static char *linebuffer = 0;
+ static unsigned linelength = 0;
+ char *p;
+ char *p1;
+ char *rl;
+ char *local_prompt = prompt_arg;
+ 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 ((prompt_arg == NULL ? 0 : strlen (prompt_arg))
+ + strlen (annotation_suffix) + 40);
+ if (prompt_arg == NULL)
+ local_prompt[0] = '\0';
+ else
+ strcpy (local_prompt, prompt_arg);
+ 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)
+ {
+ if (event_loop_p)
+ signal (STOP_SIGNAL, handle_stop_sig);
+ else
+ 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)
+ {
+ puts_unfiltered ("\n\032\032pre-");
+ puts_unfiltered (annotation_suffix);
+ puts_unfiltered ("\n");
+ }
+
+ /* Don't use fancy stuff if not talking to stdin. */
+ if (readline_hook && instream == NULL)
+ {
+ rl = (*readline_hook) (local_prompt);
+ }
+ else if (command_editing_p && instream == stdin && ISATTY (instream))
+ {
+ rl = gdb_readline_wrapper (local_prompt);
+ }
+ else
+ {
+ rl = gdb_readline (local_prompt);
+ }
+
+ if (annotation_level > 1 && instream == stdin)
+ {
+ puts_unfiltered ("\n\032\032post-");
+ puts_unfiltered (annotation_suffix);
+ puts_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++;
+
+ xfree (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)
+ && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
+ 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)
+ {
+ xfree (history_value);
+ return command_line_input (prompt_arg, 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);
+ xfree (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;
+}
+
+/* Print the GDB banner. */
+void
+print_gdb_version (struct ui_file *stream)
+{
+ /* From GNU coding standards, first line is meant to be easy for a
+ program to parse, and is just canonical program name and version
+ number, which starts after last space. */
+
+ fprintf_filtered (stream, "GNU gdb %s\n", version);
+
+ /* Second line is a copyright notice. */
+
+ fprintf_filtered (stream, "Copyright 2004 Free Software Foundation, Inc.\n");
+
+ /* Following the copyright is a brief statement that the program is
+ free software, that users are free to copy and change it on
+ certain conditions, that it is covered by the GNU GPL, and that
+ there is no warranty. */
+
+ fprintf_filtered (stream, "\
+GDB is free software, covered by the GNU General Public License, and you are\n\
+welcome to change it and/or distribute copies of it under certain conditions.\n\
+Type \"show copying\" to see the conditions.\n\
+There is absolutely no warranty for GDB. Type \"show warranty\" for details.\n");
+
+ /* After the required info we print the configuration information. */
+
+ fprintf_filtered (stream, "This GDB was configured as \"");
+ if (strcmp (host_name, target_name) != 0)
+ {
+ fprintf_filtered (stream, "--host=%s --target=%s", host_name, target_name);
+ }
+ else
+ {
+ fprintf_filtered (stream, "%s", host_name);
+ }
+ fprintf_filtered (stream, "\".");
+}
+
+/* get_prompt: access method for the GDB prompt string. */
+
+char *
+get_prompt (void)
+{
+ if (event_loop_p)
+ return PROMPT (0);
+ else
+ return gdb_prompt_string;
+}
+
+void
+set_prompt (char *s)
+{
+/* ??rehrauer: I don't know why this fails, since it looks as though
+ assignments to prompt are wrapped in calls to savestring...
+ if (prompt != NULL)
+ xfree (prompt);
+ */
+ if (event_loop_p)
+ PROMPT (0) = savestring (s, strlen (s));
+ else
+ gdb_prompt_string = savestring (s, strlen (s));
+}
+
+
+/* If necessary, make the user confirm that we should quit. Return
+ non-zero if we should quit, zero if we shouldn't. */
+
+int
+quit_confirm (void)
+{
+ if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
+ {
+ char *s;
+
+ /* This is something of a hack. But there's no reliable way to
+ see if a GUI is running. The `use_windows' variable doesn't
+ cut it. */
+ if (init_ui_hook)
+ s = "A debugging session is active.\nDo you still want to close the debugger?";
+ else if (attach_flag)
+ s = "The program is running. Quit anyway (and detach it)? ";
+ else
+ s = "The program is running. Exit anyway? ";
+
+ if (!query ("%s", s))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Helper routine for quit_force that requires error handling. */
+
+struct qt_args
+{
+ char *args;
+ int from_tty;
+};
+
+static int
+quit_target (void *arg)
+{
+ struct qt_args *qt = (struct qt_args *)arg;
+
+ if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
+ {
+ if (attach_flag)
+ target_detach (qt->args, qt->from_tty);
+ else
+ target_kill ();
+ }
+
+ /* UDI wants this, to kill the TIP. */
+ target_close (&current_target, 1);
+
+ /* Save the history information if it is appropriate to do so. */
+ if (write_history_p && history_filename)
+ write_history (history_filename);
+
+ do_final_cleanups (ALL_CLEANUPS); /* Do any final cleanups before exiting */
+
+ return 0;
+}
+
+/* Quit without asking for confirmation. */
+
+void
+quit_force (char *args, int from_tty)
+{
+ int exit_code = 0;
+ struct qt_args qt;
+
+ /* An optional expression may be used to cause gdb to terminate with the
+ value of that expression. */
+ if (args)
+ {
+ struct value *val = parse_and_eval (args);
+
+ exit_code = (int) value_as_long (val);
+ }
+
+ qt.args = args;
+ qt.from_tty = from_tty;
+
+ /* We want to handle any quit errors and exit regardless. */
+ catch_errors (quit_target, &qt,
+ "Quitting: ", RETURN_MASK_ALL);
+
+ 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 (void)
+{
+ return gdb_has_a_terminal () && (instream == stdin) & caution;
+}
+
+static void
+dont_repeat_command (char *ignored, int from_tty)
+{
+ *line = 0; /* Can't call dont_repeat here because we're not
+ necessarily reading from stdin. */
+}
+
+/* Functions to manipulate command line editing control variables. */
+
+/* Number of commands to print in each call to show_commands. */
+#define Hist_print 10
+void
+show_commands (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;
+
+ /* 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 <exp>" should print around command number <exp>. */
+ num = (parse_and_eval_long (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. */
+static void
+set_history_size_command (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");
+ }
+}
+
+void
+set_history (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);
+}
+
+void
+show_history (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. */
+void
+set_verbose (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.";
+ }
+}
+
+/* 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 (void)
+{
+ 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. */
+#ifdef __MSDOS__
+ /* No leading dots in file names are allowed on MSDOS. */
+ history_filename = concat (current_directory, "/_gdb_history", NULL);
+#else
+ history_filename = concat (current_directory, "/.gdb_history", NULL);
+#endif
+ }
+ read_history (history_filename);
+}
+
+static void
+init_main (void)
+{
+ struct cmd_list_element *c;
+
+ /* If we are running the asynchronous version,
+ we initialize the prompts differently. */
+ if (!event_loop_p)
+ {
+ gdb_prompt_string = savestring (DEFAULT_PROMPT, strlen (DEFAULT_PROMPT));
+ }
+ else
+ {
+ /* initialize the prompt stack to a simple "(gdb) " prompt or to
+ whatever the DEFAULT_PROMPT is. */
+ the_prompts.top = 0;
+ PREFIX (0) = "";
+ PROMPT (0) = savestring (DEFAULT_PROMPT, strlen (DEFAULT_PROMPT));
+ SUFFIX (0) = "";
+ /* Set things up for annotation_level > 1, if the user ever decides
+ to use it. */
+ async_annotation_suffix = "prompt";
+ /* Set the variable associated with the setshow prompt command. */
+ new_async_prompt = savestring (PROMPT (0), strlen (PROMPT (0)));
+
+ /* If gdb was started with --annotate=2, this is equivalent to
+ the user entering the command 'set annotate 2' at the gdb
+ prompt, so we need to do extra processing. */
+ if (annotation_level > 1)
+ set_async_annotation_level (NULL, 0, NULL);
+ }
+
+ /* 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 = readline_line_completion_function;
+ rl_completer_word_break_characters = default_word_break_characters ();
+ rl_completer_quote_characters = get_gdb_completer_quote_characters ();
+ rl_readline_name = "gdb";
+ rl_terminal_name = getenv ("TERM");
+
+ /* The name for this defun comes from Bash, where it originated.
+ 15 is Control-o, the same binding this function has in Bash. */
+ rl_add_defun ("operate-and-get-next", gdb_rl_operate_and_get_next, 15);
+
+ /* The set prompt command is different depending whether or not the
+ async version is run. NOTE: this difference is going to
+ disappear as we make the event loop be the default engine of
+ gdb. */
+ if (!event_loop_p)
+ {
+ add_show_from_set
+ (add_set_cmd ("prompt", class_support, var_string,
+ (char *) &gdb_prompt_string, "Set gdb's prompt",
+ &setlist),
+ &showlist);
+ }
+ else
+ {
+ c = add_set_cmd ("prompt", class_support, var_string,
+ (char *) &new_async_prompt, "Set gdb's prompt",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_async_prompt);
+ }
+
+ 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.");
+
+ /* The set editing command is different depending whether or not the
+ async version is run. NOTE: this difference is going to disappear
+ as we make the event loop be the default engine of gdb. */
+ if (!event_loop_p)
+ {
+ 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 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);
+ }
+ else
+ {
+ c = add_set_cmd ("editing", class_support, var_boolean, (char *) &async_command_editing_p,
+ "Set editing of command lines as they are typed.\n\
+Use \"on\" 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);
+
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_async_editing_command);
+ }
+
+ 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 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);
+ set_cmd_sfunc (c, set_history_size_command);
+
+ c = 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);
+ set_cmd_completer (c, filename_completer);
+ add_show_from_set (c, &showhistlist);
+
+ add_show_from_set
+ (add_set_cmd ("confirm", class_support, var_boolean,
+ (char *) &caution,
+ "Set whether to confirm potentially dangerous operations.",
+ &setlist),
+ &showlist);
+
+ /* The set annotate command is different depending whether or not
+ the async version is run. NOTE: this difference is going to
+ disappear as we make the event loop be the default engine of
+ gdb. */
+ if (!event_loop_p)
+ {
+ c = add_set_cmd ("annotate", class_obscure, var_zinteger,
+ (char *) &annotation_level, "Set annotation_level.\n\
+0 == normal; 1 == fullname (for use when running under emacs)\n\
+2 == output annotated suitably for use by programs that control GDB.",
+ &setlist);
+ c = add_show_from_set (c, &showlist);
+ }
+ else
+ {
+ c = add_set_cmd ("annotate", class_obscure, var_zinteger,
+ (char *) &annotation_level, "Set annotation_level.\n\
+0 == normal; 1 == fullname (for use when running under emacs)\n\
+2 == output annotated suitably for use by programs that control GDB.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_async_annotation_level);
+ }
+ if (event_loop_p)
+ {
+ add_show_from_set
+ (add_set_cmd ("exec-done-display", class_support, var_boolean, (char *) &exec_done_display_p,
+ "Set notification of completion for asynchronous execution commands.\n\
+Use \"on\" to enable the notification, and \"off\" to disable it.", &setlist),
+ &showlist);
+ }
+}
+
+void
+gdb_init (char *argv0)
+{
+ 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;
+
+#ifdef __MSDOS__
+ /* Make sure we return to the original directory upon exit, come
+ what may, since the OS doesn't do that for us. */
+ make_final_cleanup (do_chdir_cleanup, xstrdup (current_directory));
+#endif
+
+ 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 ();
+ initialize_current_architecture ();
+ init_cli_cmds();
+ init_main (); /* But that omits this file! Do it now */
+
+ /* The signal handling mechanism is different depending whether or
+ not the async version is run. NOTE: in the future we plan to make
+ the event loop be the default engine of gdb, and this difference
+ will disappear. */
+ if (event_loop_p)
+ async_init_signals ();
+ else
+ init_signals ();
+
+ /* 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. */
+
+ /* Allow another UI to initialize. If the UI fails to initialize, and
+ it wants GDB to revert to the CLI, it should clear init_ui_hook. */
+ if (init_ui_hook)
+ init_ui_hook (argv0);
+}
diff --git a/contrib/gdb/gdb/top.h b/contrib/gdb/gdb/top.h
new file mode 100644
index 0000000..88b7e7a
--- /dev/null
+++ b/contrib/gdb/gdb/top.h
@@ -0,0 +1,84 @@
+/* Top level stuff for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996,
+ 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TOP_H
+#define TOP_H
+
+/* 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[];
+
+extern void print_gdb_version (struct ui_file *);
+
+extern void source_command (char *, int);
+extern void cd_command (char *, int);
+extern void read_command_file (FILE *);
+extern void init_history (void);
+extern void command_loop (void);
+extern void simplified_command_loop (char *(*read_input_func) (char *),
+ void (*execute_command_func) (char *,
+ int));
+extern int quit_confirm (void);
+extern void quit_force (char *, int);
+extern void quit_command (char *, int);
+extern int quit_cover (void *);
+extern void execute_command (char *, int);
+
+/* This function returns a pointer to the string that is used
+ by gdb for its command prompt. */
+extern char *get_prompt (void);
+
+/* This function copies the specified string into the string that
+ is used by gdb for its command prompt. */
+extern void set_prompt (char *);
+
+/* From random places. */
+extern int readnow_symbol_files;
+
+/* Perform _initialize initialization */
+extern void gdb_init (char *);
+
+/* For use by event-top.c */
+/* Variables from top.c. */
+extern int source_line_number;
+extern char *source_file_name;
+extern char *source_error;
+extern char *source_pre_error;
+extern int history_expansion_p;
+extern int server_command;
+extern char *lim_at_start;
+
+extern void show_commands (char *args, int from_tty);
+
+extern void set_history (char *, int);
+
+extern void show_history (char *, int);
+
+extern void set_verbose (char *, int, struct cmd_list_element *);
+
+extern void do_restore_instream_cleanup (void *stream);
+
+#endif
diff --git a/contrib/gdb/gdb/tracepoint.c b/contrib/gdb/gdb/tracepoint.c
new file mode 100644
index 0000000..39c6877
--- /dev/null
+++ b/contrib/gdb/gdb/tracepoint.c
@@ -0,0 +1,2811 @@
+/* Tracing functionality for remote targets in custom GDB protocol
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbtypes.h"
+#include "expression.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "target.h"
+#include "language.h"
+#include "gdb_string.h"
+#include "inferior.h"
+#include "tracepoint.h"
+#include "remote.h"
+#include "linespec.h"
+#include "regcache.h"
+#include "completer.h"
+#include "gdb-events.h"
+#include "block.h"
+#include "dictionary.h"
+
+#include "ax.h"
+#include "ax-gdb.h"
+
+/* readline include files */
+#include "readline/readline.h"
+#include "readline/history.h"
+
+/* readline defines this. */
+#undef savestring
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* maximum length of an agent aexpression.
+ this accounts for the fact that packets are limited to 400 bytes
+ (which includes everything -- including the checksum), and assumes
+ the worst case of maximum length for each of the pieces of a
+ continuation packet.
+
+ NOTE: expressions get mem2hex'ed otherwise this would be twice as
+ large. (400 - 31)/2 == 184 */
+#define MAX_AGENT_EXPR_LEN 184
+
+
+extern void (*readline_begin_hook) (char *, ...);
+extern char *(*readline_hook) (char *);
+extern void (*readline_end_hook) (void);
+extern void x_command (char *, int);
+extern int addressprint; /* Print machine addresses? */
+
+/* GDB commands implemented in other modules:
+ */
+
+extern void output_command (char *, int);
+
+/*
+ Tracepoint.c:
+
+ This module defines the following debugger commands:
+ trace : set a tracepoint on a function, line, or address.
+ info trace : list all debugger-defined tracepoints.
+ delete trace : delete one or more tracepoints.
+ enable trace : enable one or more tracepoints.
+ disable trace : disable one or more tracepoints.
+ actions : specify actions to be taken at a tracepoint.
+ passcount : specify a pass count for a tracepoint.
+ tstart : start a trace experiment.
+ tstop : stop a trace experiment.
+ tstatus : query the status of a trace experiment.
+ tfind : find a trace frame in the trace buffer.
+ tdump : print everything collected at the current tracepoint.
+ save-tracepoints : write tracepoint setup into a file.
+
+ This module defines the following user-visible debugger variables:
+ $trace_frame : sequence number of trace frame currently being debugged.
+ $trace_line : source line of trace frame currently being debugged.
+ $trace_file : source file of trace frame currently being debugged.
+ $tracepoint : tracepoint number of trace frame currently being debugged.
+ */
+
+
+/* ======= Important global variables: ======= */
+
+/* Chain of all tracepoints defined. */
+struct tracepoint *tracepoint_chain;
+
+/* Number of last tracepoint made. */
+static int tracepoint_count;
+
+/* Number of last traceframe collected. */
+static int traceframe_number;
+
+/* Tracepoint for last traceframe collected. */
+static int tracepoint_number;
+
+/* Symbol for function for last traceframe collected */
+static struct symbol *traceframe_fun;
+
+/* Symtab and line for last traceframe collected */
+static struct symtab_and_line traceframe_sal;
+
+/* Tracing command lists */
+static struct cmd_list_element *tfindlist;
+
+/* ======= Important command functions: ======= */
+static void trace_command (char *, int);
+static void tracepoints_info (char *, int);
+static void delete_trace_command (char *, int);
+static void enable_trace_command (char *, int);
+static void disable_trace_command (char *, int);
+static void trace_pass_command (char *, int);
+static void trace_actions_command (char *, int);
+static void trace_start_command (char *, int);
+static void trace_stop_command (char *, int);
+static void trace_status_command (char *, int);
+static void trace_find_command (char *, int);
+static void trace_find_pc_command (char *, int);
+static void trace_find_tracepoint_command (char *, int);
+static void trace_find_line_command (char *, int);
+static void trace_find_range_command (char *, int);
+static void trace_find_outside_command (char *, int);
+static void tracepoint_save_command (char *, int);
+static void trace_dump_command (char *, int);
+
+/* support routines */
+static void trace_mention (struct tracepoint *);
+
+struct collection_list;
+static void add_aexpr (struct collection_list *, struct agent_expr *);
+static unsigned char *mem2hex (unsigned char *, unsigned char *, int);
+static void add_register (struct collection_list *collection,
+ unsigned int regno);
+static struct cleanup *make_cleanup_free_actions (struct tracepoint *t);
+static void free_actions_list (char **actions_list);
+static void free_actions_list_cleanup_wrapper (void *);
+
+extern void _initialize_tracepoint (void);
+
+/* Utility: returns true if "target remote" */
+static int
+target_is_remote (void)
+{
+ if (current_target.to_shortname &&
+ strcmp (current_target.to_shortname, "remote") == 0)
+ return 1;
+ else
+ return 0;
+}
+
+/* Utility: generate error from an incoming stub packet. */
+static void
+trace_error (char *buf)
+{
+ if (*buf++ != 'E')
+ return; /* not an error msg */
+ switch (*buf)
+ {
+ case '1': /* malformed packet error */
+ if (*++buf == '0') /* general case: */
+ error ("tracepoint.c: error in outgoing packet.");
+ else
+ error ("tracepoint.c: error in outgoing packet at field #%ld.",
+ strtol (buf, NULL, 16));
+ case '2':
+ error ("trace API error 0x%s.", ++buf);
+ default:
+ error ("Target returns error code '%s'.", buf);
+ }
+}
+
+/* Utility: wait for reply from stub, while accepting "O" packets */
+static char *
+remote_get_noisy_reply (char *buf,
+ long sizeof_buf)
+{
+ do /* loop on reply from remote stub */
+ {
+ QUIT; /* allow user to bail out with ^C */
+ getpkt (buf, sizeof_buf, 0);
+ if (buf[0] == 0)
+ error ("Target does not support this command.");
+ else if (buf[0] == 'E')
+ trace_error (buf);
+ else if (buf[0] == 'O' &&
+ buf[1] != 'K')
+ remote_console_output (buf + 1); /* 'O' message from stub */
+ else
+ return buf; /* here's the actual reply */
+ }
+ while (1);
+}
+
+/* Set tracepoint count to NUM. */
+static void
+set_tracepoint_count (int num)
+{
+ tracepoint_count = num;
+ set_internalvar (lookup_internalvar ("tpnum"),
+ value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Set traceframe number to NUM. */
+static void
+set_traceframe_num (int num)
+{
+ traceframe_number = num;
+ set_internalvar (lookup_internalvar ("trace_frame"),
+ value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Set tracepoint number to NUM. */
+static void
+set_tracepoint_num (int num)
+{
+ tracepoint_number = num;
+ set_internalvar (lookup_internalvar ("tracepoint"),
+ value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Set externally visible debug variables for querying/printing
+ the traceframe context (line, function, file) */
+
+static void
+set_traceframe_context (CORE_ADDR trace_pc)
+{
+ static struct type *func_string, *file_string;
+ static struct type *func_range, *file_range;
+ struct value *func_val;
+ struct value *file_val;
+ static struct type *charstar;
+ int len;
+
+ if (charstar == (struct type *) NULL)
+ charstar = lookup_pointer_type (builtin_type_char);
+
+ if (trace_pc == -1) /* cease debugging any trace buffers */
+ {
+ traceframe_fun = 0;
+ traceframe_sal.pc = traceframe_sal.line = 0;
+ traceframe_sal.symtab = NULL;
+ set_internalvar (lookup_internalvar ("trace_func"),
+ value_from_pointer (charstar, (LONGEST) 0));
+ set_internalvar (lookup_internalvar ("trace_file"),
+ value_from_pointer (charstar, (LONGEST) 0));
+ set_internalvar (lookup_internalvar ("trace_line"),
+ value_from_longest (builtin_type_int, (LONGEST) - 1));
+ return;
+ }
+
+ /* save as globals for internal use */
+ traceframe_sal = find_pc_line (trace_pc, 0);
+ traceframe_fun = find_pc_function (trace_pc);
+
+ /* save linenumber as "$trace_line", a debugger variable visible to users */
+ set_internalvar (lookup_internalvar ("trace_line"),
+ value_from_longest (builtin_type_int,
+ (LONGEST) traceframe_sal.line));
+
+ /* save func name as "$trace_func", a debugger variable visible to users */
+ if (traceframe_fun == NULL ||
+ DEPRECATED_SYMBOL_NAME (traceframe_fun) == NULL)
+ set_internalvar (lookup_internalvar ("trace_func"),
+ value_from_pointer (charstar, (LONGEST) 0));
+ else
+ {
+ len = strlen (DEPRECATED_SYMBOL_NAME (traceframe_fun));
+ func_range = create_range_type (func_range,
+ builtin_type_int, 0, len - 1);
+ func_string = create_array_type (func_string,
+ builtin_type_char, func_range);
+ func_val = allocate_value (func_string);
+ VALUE_TYPE (func_val) = func_string;
+ memcpy (VALUE_CONTENTS_RAW (func_val),
+ DEPRECATED_SYMBOL_NAME (traceframe_fun),
+ len);
+ func_val->modifiable = 0;
+ set_internalvar (lookup_internalvar ("trace_func"), func_val);
+ }
+
+ /* save file name as "$trace_file", a debugger variable visible to users */
+ if (traceframe_sal.symtab == NULL ||
+ traceframe_sal.symtab->filename == NULL)
+ set_internalvar (lookup_internalvar ("trace_file"),
+ value_from_pointer (charstar, (LONGEST) 0));
+ else
+ {
+ len = strlen (traceframe_sal.symtab->filename);
+ file_range = create_range_type (file_range,
+ builtin_type_int, 0, len - 1);
+ file_string = create_array_type (file_string,
+ builtin_type_char, file_range);
+ file_val = allocate_value (file_string);
+ VALUE_TYPE (file_val) = file_string;
+ memcpy (VALUE_CONTENTS_RAW (file_val),
+ traceframe_sal.symtab->filename,
+ len);
+ file_val->modifiable = 0;
+ set_internalvar (lookup_internalvar ("trace_file"), file_val);
+ }
+}
+
+/* Low level routine to set a tracepoint.
+ Returns the tracepoint object so caller can set other things.
+ Does not set the tracepoint number!
+ Does not print anything.
+
+ ==> This routine should not be called if there is a chance of later
+ error(); otherwise it leaves a bogus tracepoint on the chain. Validate
+ your arguments BEFORE calling this routine! */
+
+static struct tracepoint *
+set_raw_tracepoint (struct symtab_and_line sal)
+{
+ struct tracepoint *t, *tc;
+ struct cleanup *old_chain;
+
+ t = (struct tracepoint *) xmalloc (sizeof (struct tracepoint));
+ old_chain = make_cleanup (xfree, t);
+ memset (t, 0, sizeof (*t));
+ t->address = sal.pc;
+ if (sal.symtab == NULL)
+ t->source_file = NULL;
+ else
+ t->source_file = savestring (sal.symtab->filename,
+ strlen (sal.symtab->filename));
+
+ t->section = sal.section;
+ t->language = current_language->la_language;
+ t->input_radix = input_radix;
+ t->line_number = sal.line;
+ t->enabled_p = 1;
+ t->next = 0;
+ t->step_count = 0;
+ t->pass_count = 0;
+ t->addr_string = NULL;
+
+ /* Add this tracepoint to the end of the chain
+ so that a list of tracepoints will come out in order
+ of increasing numbers. */
+
+ tc = tracepoint_chain;
+ if (tc == 0)
+ tracepoint_chain = t;
+ else
+ {
+ while (tc->next)
+ tc = tc->next;
+ tc->next = t;
+ }
+ discard_cleanups (old_chain);
+ return t;
+}
+
+/* Set a tracepoint according to ARG (function, linenum or *address) */
+static void
+trace_command (char *arg, int from_tty)
+{
+ char **canonical = (char **) NULL;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct tracepoint *t;
+ char *addr_start = 0, *addr_end = 0;
+ int i;
+
+ if (!arg || !*arg)
+ error ("trace command requires an argument");
+
+ if (from_tty && info_verbose)
+ printf_filtered ("TRACE %s\n", arg);
+
+ addr_start = arg;
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, &canonical, NULL);
+ addr_end = arg;
+ if (!sals.nelts)
+ return; /* ??? Presumably decode_line_1 has already warned? */
+
+ /* Resolve all line numbers to PC's */
+ for (i = 0; i < sals.nelts; i++)
+ resolve_sal_pc (&sals.sals[i]);
+
+ /* Now set all the tracepoints. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ t = set_raw_tracepoint (sal);
+ set_tracepoint_count (tracepoint_count + 1);
+ t->number = tracepoint_count;
+
+ /* If a canonical line spec is needed use that instead of the
+ command string. */
+ if (canonical != (char **) NULL && canonical[i] != NULL)
+ t->addr_string = canonical[i];
+ else if (addr_start)
+ t->addr_string = savestring (addr_start, addr_end - addr_start);
+
+ trace_mention (t);
+ }
+
+ if (sals.nelts > 1)
+ {
+ printf_filtered ("Multiple tracepoints were set.\n");
+ printf_filtered ("Use 'delete trace' to delete unwanted tracepoints.\n");
+ }
+}
+
+/* Tell the user we have just set a tracepoint TP. */
+
+static void
+trace_mention (struct tracepoint *tp)
+{
+ printf_filtered ("Tracepoint %d", tp->number);
+
+ if (addressprint || (tp->source_file == NULL))
+ {
+ printf_filtered (" at ");
+ print_address_numeric (tp->address, 1, gdb_stdout);
+ }
+ if (tp->source_file)
+ printf_filtered (": file %s, line %d.",
+ tp->source_file, tp->line_number);
+
+ printf_filtered ("\n");
+}
+
+/* Print information on tracepoint number TPNUM_EXP, or all if omitted. */
+
+static void
+tracepoints_info (char *tpnum_exp, int from_tty)
+{
+ struct tracepoint *t;
+ struct action_line *action;
+ int found_a_tracepoint = 0;
+ char wrap_indent[80];
+ struct symbol *sym;
+ int tpnum = -1;
+
+ if (tpnum_exp)
+ tpnum = parse_and_eval_long (tpnum_exp);
+
+ ALL_TRACEPOINTS (t)
+ if (tpnum == -1 || tpnum == t->number)
+ {
+ extern int addressprint; /* print machine addresses? */
+
+ if (!found_a_tracepoint++)
+ {
+ printf_filtered ("Num Enb ");
+ if (addressprint)
+ {
+ if (TARGET_ADDR_BIT <= 32)
+ printf_filtered ("Address ");
+ else
+ printf_filtered ("Address ");
+ }
+ printf_filtered ("PassC StepC What\n");
+ }
+ strcpy (wrap_indent, " ");
+ if (addressprint)
+ {
+ if (TARGET_ADDR_BIT <= 32)
+ strcat (wrap_indent, " ");
+ else
+ strcat (wrap_indent, " ");
+ }
+
+ printf_filtered ("%-3d %-3s ", t->number,
+ t->enabled_p ? "y" : "n");
+ if (addressprint)
+ {
+ char *tmp;
+
+ if (TARGET_ADDR_BIT <= 32)
+ tmp = local_hex_string_custom (t->address
+ & (CORE_ADDR) 0xffffffff,
+ "08l");
+ else
+ tmp = local_hex_string_custom (t->address, "016l");
+
+ printf_filtered ("%s ", tmp);
+ }
+ printf_filtered ("%-5d %-5ld ", t->pass_count, t->step_count);
+
+ if (t->source_file)
+ {
+ sym = find_pc_sect_function (t->address, t->section);
+ if (sym)
+ {
+ fputs_filtered ("in ", gdb_stdout);
+ fputs_filtered (SYMBOL_PRINT_NAME (sym), gdb_stdout);
+ wrap_here (wrap_indent);
+ fputs_filtered (" at ", gdb_stdout);
+ }
+ fputs_filtered (t->source_file, gdb_stdout);
+ printf_filtered (":%d", t->line_number);
+ }
+ else
+ print_address_symbolic (t->address, gdb_stdout, demangle, " ");
+
+ printf_filtered ("\n");
+ if (t->actions)
+ {
+ printf_filtered (" Actions for tracepoint %d: \n", t->number);
+ for (action = t->actions; action; action = action->next)
+ {
+ printf_filtered ("\t%s\n", action->action);
+ }
+ }
+ }
+ if (!found_a_tracepoint)
+ {
+ if (tpnum == -1)
+ printf_filtered ("No tracepoints.\n");
+ else
+ printf_filtered ("No tracepoint number %d.\n", tpnum);
+ }
+}
+
+/* Optimization: the code to parse an enable, disable, or delete TP command
+ is virtually identical except for whether it performs an enable, disable,
+ or delete. Therefore I've combined them into one function with an opcode.
+ */
+enum tracepoint_opcode
+{
+ enable_op,
+ disable_op,
+ delete_op
+};
+
+/* This function implements enable, disable and delete commands. */
+static void
+tracepoint_operation (struct tracepoint *t, int from_tty,
+ enum tracepoint_opcode opcode)
+{
+ struct tracepoint *t2;
+
+ if (t == NULL) /* no tracepoint operand */
+ return;
+
+ switch (opcode)
+ {
+ case enable_op:
+ t->enabled_p = 1;
+ tracepoint_modify_event (t->number);
+ break;
+ case disable_op:
+ t->enabled_p = 0;
+ tracepoint_modify_event (t->number);
+ break;
+ case delete_op:
+ if (tracepoint_chain == t)
+ tracepoint_chain = t->next;
+
+ ALL_TRACEPOINTS (t2)
+ if (t2->next == t)
+ {
+ tracepoint_delete_event (t2->number);
+ t2->next = t->next;
+ break;
+ }
+
+ if (t->addr_string)
+ xfree (t->addr_string);
+ if (t->source_file)
+ xfree (t->source_file);
+ if (t->actions)
+ free_actions (t);
+
+ xfree (t);
+ break;
+ }
+}
+
+/* Utility: parse a tracepoint number and look it up in the list.
+ If MULTI_P is true, there might be a range of tracepoints in ARG.
+ if OPTIONAL_P is true, then if the argument is missing, the most
+ recent tracepoint (tracepoint_count) is returned. */
+struct tracepoint *
+get_tracepoint_by_number (char **arg, int multi_p, int optional_p)
+{
+ struct tracepoint *t;
+ int tpnum;
+ char *instring = arg == NULL ? NULL : *arg;
+
+ if (arg == NULL || *arg == NULL || ! **arg)
+ {
+ if (optional_p)
+ tpnum = tracepoint_count;
+ else
+ error_no_arg ("tracepoint number");
+ }
+ else
+ tpnum = multi_p ? get_number_or_range (arg) : get_number (arg);
+
+ if (tpnum <= 0)
+ {
+ if (instring && *instring)
+ printf_filtered ("bad tracepoint number at or near '%s'\n", instring);
+ else
+ printf_filtered ("Tracepoint argument missing and no previous tracepoint\n");
+ return NULL;
+ }
+
+ ALL_TRACEPOINTS (t)
+ if (t->number == tpnum)
+ {
+ return t;
+ }
+
+ /* FIXME: if we are in the middle of a range we don't want to give
+ a message. The current interface to get_number_or_range doesn't
+ allow us to discover this. */
+ printf_unfiltered ("No tracepoint number %d.\n", tpnum);
+ return NULL;
+}
+
+/* Utility: parse a list of tracepoint numbers, and call a func for each. */
+static void
+map_args_over_tracepoints (char *args, int from_tty,
+ enum tracepoint_opcode opcode)
+{
+ struct tracepoint *t, *tmp;
+
+ if (args == 0 || *args == 0) /* do them all */
+ ALL_TRACEPOINTS_SAFE (t, tmp)
+ tracepoint_operation (t, from_tty, opcode);
+ else
+ while (*args)
+ {
+ QUIT; /* give user option to bail out with ^C */
+ t = get_tracepoint_by_number (&args, 1, 0);
+ tracepoint_operation (t, from_tty, opcode);
+ while (*args == ' ' || *args == '\t')
+ args++;
+ }
+}
+
+/* The 'enable trace' command enables tracepoints. Not supported by all targets. */
+static void
+enable_trace_command (char *args, int from_tty)
+{
+ dont_repeat ();
+ map_args_over_tracepoints (args, from_tty, enable_op);
+}
+
+/* The 'disable trace' command enables tracepoints. Not supported by all targets. */
+static void
+disable_trace_command (char *args, int from_tty)
+{
+ dont_repeat ();
+ map_args_over_tracepoints (args, from_tty, disable_op);
+}
+
+/* Remove a tracepoint (or all if no argument) */
+static void
+delete_trace_command (char *args, int from_tty)
+{
+ dont_repeat ();
+ if (!args || !*args) /* No args implies all tracepoints; */
+ if (from_tty) /* confirm only if from_tty... */
+ if (tracepoint_chain) /* and if there are tracepoints to delete! */
+ if (!query ("Delete all tracepoints? "))
+ return;
+
+ map_args_over_tracepoints (args, from_tty, delete_op);
+}
+
+/* Set passcount for tracepoint.
+
+ First command argument is passcount, second is tracepoint number.
+ If tracepoint number omitted, apply to most recently defined.
+ Also accepts special argument "all". */
+
+static void
+trace_pass_command (char *args, int from_tty)
+{
+ struct tracepoint *t1 = (struct tracepoint *) -1, *t2;
+ unsigned int count;
+ int all = 0;
+
+ if (args == 0 || *args == 0)
+ error ("passcount command requires an argument (count + optional TP num)");
+
+ count = strtoul (args, &args, 10); /* count comes first, then TP num */
+
+ while (*args && isspace ((int) *args))
+ args++;
+
+ if (*args && strncasecmp (args, "all", 3) == 0)
+ {
+ args += 3; /* skip special argument "all" */
+ all = 1;
+ if (*args)
+ error ("Junk at end of arguments.");
+ }
+ else
+ t1 = get_tracepoint_by_number (&args, 1, 1);
+
+ do
+ {
+ if (t1)
+ {
+ ALL_TRACEPOINTS (t2)
+ if (t1 == (struct tracepoint *) -1 || t1 == t2)
+ {
+ t2->pass_count = count;
+ tracepoint_modify_event (t2->number);
+ if (from_tty)
+ printf_filtered ("Setting tracepoint %d's passcount to %d\n",
+ t2->number, count);
+ }
+ if (! all && *args)
+ t1 = get_tracepoint_by_number (&args, 1, 0);
+ }
+ }
+ while (*args);
+}
+
+/* ACTIONS functions: */
+
+/* Prototypes for action-parsing utility commands */
+static void read_actions (struct tracepoint *);
+
+/* The three functions:
+ collect_pseudocommand,
+ while_stepping_pseudocommand, and
+ end_actions_pseudocommand
+ are placeholders for "commands" that are actually ONLY to be used
+ within a tracepoint action list. If the actual function is ever called,
+ it means that somebody issued the "command" at the top level,
+ which is always an error. */
+
+static void
+end_actions_pseudocommand (char *args, int from_tty)
+{
+ error ("This command cannot be used at the top level.");
+}
+
+static void
+while_stepping_pseudocommand (char *args, int from_tty)
+{
+ error ("This command can only be used in a tracepoint actions list.");
+}
+
+static void
+collect_pseudocommand (char *args, int from_tty)
+{
+ error ("This command can only be used in a tracepoint actions list.");
+}
+
+/* Enter a list of actions for a tracepoint. */
+static void
+trace_actions_command (char *args, int from_tty)
+{
+ struct tracepoint *t;
+ char tmpbuf[128];
+ char *end_msg = "End with a line saying just \"end\".";
+
+ t = get_tracepoint_by_number (&args, 0, 1);
+ if (t)
+ {
+ sprintf (tmpbuf, "Enter actions for tracepoint %d, one per line.",
+ t->number);
+
+ if (from_tty)
+ {
+ if (readline_begin_hook)
+ (*readline_begin_hook) ("%s %s\n", tmpbuf, end_msg);
+ else if (input_from_terminal_p ())
+ printf_filtered ("%s\n%s\n", tmpbuf, end_msg);
+ }
+
+ free_actions (t);
+ t->step_count = 0; /* read_actions may set this */
+ read_actions (t);
+
+ if (readline_end_hook)
+ (*readline_end_hook) ();
+ /* tracepoints_changed () */
+ }
+ /* else just return */
+}
+
+/* worker function */
+static void
+read_actions (struct tracepoint *t)
+{
+ char *line;
+ char *prompt1 = "> ", *prompt2 = " > ";
+ char *prompt = prompt1;
+ enum actionline_type linetype;
+ extern FILE *instream;
+ struct action_line *next = NULL, *temp;
+ struct cleanup *old_chain;
+
+ /* Control-C quits instantly if typed while in this loop
+ since it should not wait until the user types a newline. */
+ immediate_quit++;
+ /* FIXME: kettenis/20010823: Something is wrong here. In this file
+ STOP_SIGNAL is never defined. So this code has been left out, at
+ least for quite a while now. Replacing STOP_SIGNAL with SIGTSTP
+ leads to compilation failures since the variable job_control
+ isn't declared. Leave this alone for now. */
+#ifdef STOP_SIGNAL
+ if (job_control)
+ {
+ if (event_loop_p)
+ signal (STOP_SIGNAL, handle_stop_sig);
+ else
+ signal (STOP_SIGNAL, stop_sig);
+ }
+#endif
+ old_chain = make_cleanup_free_actions (t);
+ 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 (readline_hook && instream == NULL)
+ line = (*readline_hook) (prompt);
+ else if (instream == stdin && ISATTY (instream))
+ {
+ line = gdb_readline_wrapper (prompt);
+ if (line && *line) /* add it to command history */
+ add_history (line);
+ }
+ else
+ line = gdb_readline (0);
+
+ linetype = validate_actionline (&line, t);
+ if (linetype == BADLINE)
+ continue; /* already warned -- collect another line */
+
+ temp = xmalloc (sizeof (struct action_line));
+ temp->next = NULL;
+ temp->action = line;
+
+ if (next == NULL) /* first action for this tracepoint? */
+ t->actions = next = temp;
+ else
+ {
+ next->next = temp;
+ next = temp;
+ }
+
+ if (linetype == STEPPING) /* begin "while-stepping" */
+ {
+ if (prompt == prompt2)
+ {
+ warning ("Already processing 'while-stepping'");
+ continue;
+ }
+ else
+ prompt = prompt2; /* change prompt for stepping actions */
+ }
+ else if (linetype == END)
+ {
+ if (prompt == prompt2)
+ {
+ prompt = prompt1; /* end of single-stepping actions */
+ }
+ else
+ { /* end of actions */
+ if (t->actions->next == NULL)
+ {
+ /* an "end" all by itself with no other actions means
+ this tracepoint has no actions. Discard empty list. */
+ free_actions (t);
+ }
+ break;
+ }
+ }
+ }
+#ifdef STOP_SIGNAL
+ if (job_control)
+ signal (STOP_SIGNAL, SIG_DFL);
+#endif
+ immediate_quit--;
+ discard_cleanups (old_chain);
+}
+
+/* worker function */
+enum actionline_type
+validate_actionline (char **line, struct tracepoint *t)
+{
+ struct cmd_list_element *c;
+ struct expression *exp = NULL;
+ struct cleanup *old_chain = NULL;
+ char *p;
+
+ /* if EOF is typed, *line is NULL */
+ if (*line == NULL)
+ return END;
+
+ for (p = *line; isspace ((int) *p);)
+ p++;
+
+ /* symbol lookup etc. */
+ if (*p == '\0') /* empty line: just prompt for another line. */
+ return BADLINE;
+
+ if (*p == '#') /* comment line */
+ return GENERIC;
+
+ c = lookup_cmd (&p, cmdlist, "", -1, 1);
+ if (c == 0)
+ {
+ warning ("'%s' is not an action that I know, or is ambiguous.", p);
+ return BADLINE;
+ }
+
+ if (cmd_cfunc_eq (c, collect_pseudocommand))
+ {
+ struct agent_expr *aexpr;
+ struct agent_reqs areqs;
+
+ do
+ { /* repeat over a comma-separated list */
+ QUIT; /* allow user to bail out with ^C */
+ while (isspace ((int) *p))
+ p++;
+
+ if (*p == '$') /* look for special pseudo-symbols */
+ {
+ if ((0 == strncasecmp ("reg", p + 1, 3)) ||
+ (0 == strncasecmp ("arg", p + 1, 3)) ||
+ (0 == strncasecmp ("loc", p + 1, 3)))
+ {
+ p = strchr (p, ',');
+ continue;
+ }
+ /* else fall thru, treat p as an expression and parse it! */
+ }
+ exp = parse_exp_1 (&p, block_for_pc (t->address), 1);
+ old_chain = make_cleanup (free_current_contents, &exp);
+
+ if (exp->elts[0].opcode == OP_VAR_VALUE)
+ {
+ if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
+ {
+ warning ("constant %s (value %ld) will not be collected.",
+ DEPRECATED_SYMBOL_NAME (exp->elts[2].symbol),
+ SYMBOL_VALUE (exp->elts[2].symbol));
+ return BADLINE;
+ }
+ else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
+ {
+ warning ("%s is optimized away and cannot be collected.",
+ DEPRECATED_SYMBOL_NAME (exp->elts[2].symbol));
+ return BADLINE;
+ }
+ }
+
+ /* we have something to collect, make sure that the expr to
+ bytecode translator can handle it and that it's not too long */
+ aexpr = gen_trace_for_expr (t->address, exp);
+ make_cleanup_free_agent_expr (aexpr);
+
+ if (aexpr->len > MAX_AGENT_EXPR_LEN)
+ error ("expression too complicated, try simplifying");
+
+ ax_reqs (aexpr, &areqs);
+ (void) make_cleanup (xfree, areqs.reg_mask);
+
+ if (areqs.flaw != agent_flaw_none)
+ error ("malformed expression");
+
+ if (areqs.min_height < 0)
+ error ("gdb: Internal error: expression has min height < 0");
+
+ if (areqs.max_height > 20)
+ error ("expression too complicated, try simplifying");
+
+ do_cleanups (old_chain);
+ }
+ while (p && *p++ == ',');
+ return GENERIC;
+ }
+ else if (cmd_cfunc_eq (c, while_stepping_pseudocommand))
+ {
+ char *steparg; /* in case warning is necessary */
+
+ while (isspace ((int) *p))
+ p++;
+ steparg = p;
+
+ if (*p == '\0' ||
+ (t->step_count = strtol (p, &p, 0)) == 0)
+ {
+ warning ("'%s': bad step-count; command ignored.", *line);
+ return BADLINE;
+ }
+ return STEPPING;
+ }
+ else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
+ return END;
+ else
+ {
+ warning ("'%s' is not a supported tracepoint action.", *line);
+ return BADLINE;
+ }
+}
+
+/* worker function */
+void
+free_actions (struct tracepoint *t)
+{
+ struct action_line *line, *next;
+
+ for (line = t->actions; line; line = next)
+ {
+ next = line->next;
+ if (line->action)
+ xfree (line->action);
+ xfree (line);
+ }
+ t->actions = NULL;
+}
+
+static void
+do_free_actions_cleanup (void *t)
+{
+ free_actions (t);
+}
+
+static struct cleanup *
+make_cleanup_free_actions (struct tracepoint *t)
+{
+ return make_cleanup (do_free_actions_cleanup, t);
+}
+
+struct memrange
+{
+ int type; /* 0 for absolute memory range, else basereg number */
+ bfd_signed_vma start;
+ bfd_signed_vma end;
+};
+
+struct collection_list
+ {
+ unsigned char regs_mask[8]; /* room for up to 256 regs */
+ long listsize;
+ long next_memrange;
+ struct memrange *list;
+ long aexpr_listsize; /* size of array pointed to by expr_list elt */
+ long next_aexpr_elt;
+ struct agent_expr **aexpr_list;
+
+ }
+tracepoint_list, stepping_list;
+
+/* MEMRANGE functions: */
+
+static int memrange_cmp (const void *, const void *);
+
+/* compare memranges for qsort */
+static int
+memrange_cmp (const void *va, const void *vb)
+{
+ const struct memrange *a = va, *b = vb;
+
+ if (a->type < b->type)
+ return -1;
+ if (a->type > b->type)
+ return 1;
+ if (a->type == 0)
+ {
+ if ((bfd_vma) a->start < (bfd_vma) b->start)
+ return -1;
+ if ((bfd_vma) a->start > (bfd_vma) b->start)
+ return 1;
+ }
+ else
+ {
+ if (a->start < b->start)
+ return -1;
+ if (a->start > b->start)
+ return 1;
+ }
+ return 0;
+}
+
+/* Sort the memrange list using qsort, and merge adjacent memranges */
+static void
+memrange_sortmerge (struct collection_list *memranges)
+{
+ int a, b;
+
+ qsort (memranges->list, memranges->next_memrange,
+ sizeof (struct memrange), memrange_cmp);
+ if (memranges->next_memrange > 0)
+ {
+ for (a = 0, b = 1; b < memranges->next_memrange; b++)
+ {
+ if (memranges->list[a].type == memranges->list[b].type &&
+ memranges->list[b].start - memranges->list[a].end <=
+ MAX_REGISTER_SIZE)
+ {
+ /* memrange b starts before memrange a ends; merge them. */
+ if (memranges->list[b].end > memranges->list[a].end)
+ memranges->list[a].end = memranges->list[b].end;
+ continue; /* next b, same a */
+ }
+ a++; /* next a */
+ if (a != b)
+ memcpy (&memranges->list[a], &memranges->list[b],
+ sizeof (struct memrange));
+ }
+ memranges->next_memrange = a + 1;
+ }
+}
+
+/* Add a register to a collection list */
+static void
+add_register (struct collection_list *collection, unsigned int regno)
+{
+ if (info_verbose)
+ printf_filtered ("collect register %d\n", regno);
+ if (regno > (8 * sizeof (collection->regs_mask)))
+ error ("Internal: register number %d too large for tracepoint",
+ regno);
+ collection->regs_mask[regno / 8] |= 1 << (regno % 8);
+}
+
+/* Add a memrange to a collection list */
+static void
+add_memrange (struct collection_list *memranges, int type, bfd_signed_vma base,
+ unsigned long len)
+{
+ if (info_verbose)
+ {
+ printf_filtered ("(%d,", type);
+ printf_vma (base);
+ printf_filtered (",%ld)\n", len);
+ }
+
+ /* type: 0 == memory, n == basereg */
+ memranges->list[memranges->next_memrange].type = type;
+ /* base: addr if memory, offset if reg relative. */
+ memranges->list[memranges->next_memrange].start = base;
+ /* len: we actually save end (base + len) for convenience */
+ memranges->list[memranges->next_memrange].end = base + len;
+ memranges->next_memrange++;
+ if (memranges->next_memrange >= memranges->listsize)
+ {
+ memranges->listsize *= 2;
+ memranges->list = xrealloc (memranges->list,
+ memranges->listsize);
+ }
+
+ if (type != -1) /* better collect the base register! */
+ add_register (memranges, type);
+}
+
+/* Add a symbol to a collection list */
+static void
+collect_symbol (struct collection_list *collect, struct symbol *sym,
+ long frame_regno, long frame_offset)
+{
+ unsigned long len;
+ unsigned int reg;
+ bfd_signed_vma offset;
+
+ len = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym)));
+ switch (SYMBOL_CLASS (sym))
+ {
+ default:
+ printf_filtered ("%s: don't know symbol class %d\n",
+ DEPRECATED_SYMBOL_NAME (sym), SYMBOL_CLASS (sym));
+ break;
+ case LOC_CONST:
+ printf_filtered ("constant %s (value %ld) will not be collected.\n",
+ DEPRECATED_SYMBOL_NAME (sym), SYMBOL_VALUE (sym));
+ break;
+ case LOC_STATIC:
+ offset = SYMBOL_VALUE_ADDRESS (sym);
+ if (info_verbose)
+ {
+ char tmp[40];
+
+ sprintf_vma (tmp, offset);
+ printf_filtered ("LOC_STATIC %s: collect %ld bytes at %s.\n",
+ DEPRECATED_SYMBOL_NAME (sym), len, tmp /* address */);
+ }
+ add_memrange (collect, -1, offset, len); /* 0 == memory */
+ break;
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ reg = SYMBOL_VALUE (sym);
+ if (info_verbose)
+ printf_filtered ("LOC_REG[parm] %s: ", DEPRECATED_SYMBOL_NAME (sym));
+ add_register (collect, reg);
+ /* check for doubles stored in two registers */
+ /* FIXME: how about larger types stored in 3 or more regs? */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FLT &&
+ len > DEPRECATED_REGISTER_RAW_SIZE (reg))
+ add_register (collect, reg + 1);
+ break;
+ case LOC_REF_ARG:
+ printf_filtered ("Sorry, don't know how to do LOC_REF_ARG yet.\n");
+ printf_filtered (" (will not collect %s)\n",
+ DEPRECATED_SYMBOL_NAME (sym));
+ break;
+ case LOC_ARG:
+ reg = frame_regno;
+ offset = frame_offset + SYMBOL_VALUE (sym);
+ if (info_verbose)
+ {
+ printf_filtered ("LOC_LOCAL %s: Collect %ld bytes at offset ",
+ DEPRECATED_SYMBOL_NAME (sym), len);
+ printf_vma (offset);
+ printf_filtered (" from frame ptr reg %d\n", reg);
+ }
+ add_memrange (collect, reg, offset, len);
+ break;
+ case LOC_REGPARM_ADDR:
+ reg = SYMBOL_VALUE (sym);
+ offset = 0;
+ if (info_verbose)
+ {
+ printf_filtered ("LOC_REGPARM_ADDR %s: Collect %ld bytes at offset ",
+ DEPRECATED_SYMBOL_NAME (sym), len);
+ printf_vma (offset);
+ printf_filtered (" from reg %d\n", reg);
+ }
+ add_memrange (collect, reg, offset, len);
+ break;
+ case LOC_LOCAL:
+ case LOC_LOCAL_ARG:
+ reg = frame_regno;
+ offset = frame_offset + SYMBOL_VALUE (sym);
+ if (info_verbose)
+ {
+ printf_filtered ("LOC_LOCAL %s: Collect %ld bytes at offset ",
+ DEPRECATED_SYMBOL_NAME (sym), len);
+ printf_vma (offset);
+ printf_filtered (" from frame ptr reg %d\n", reg);
+ }
+ add_memrange (collect, reg, offset, len);
+ break;
+ case LOC_BASEREG:
+ case LOC_BASEREG_ARG:
+ reg = SYMBOL_BASEREG (sym);
+ offset = SYMBOL_VALUE (sym);
+ if (info_verbose)
+ {
+ printf_filtered ("LOC_BASEREG %s: collect %ld bytes at offset ",
+ DEPRECATED_SYMBOL_NAME (sym), len);
+ printf_vma (offset);
+ printf_filtered (" from basereg %d\n", reg);
+ }
+ add_memrange (collect, reg, offset, len);
+ break;
+ case LOC_UNRESOLVED:
+ printf_filtered ("Don't know LOC_UNRESOLVED %s\n", DEPRECATED_SYMBOL_NAME (sym));
+ break;
+ case LOC_OPTIMIZED_OUT:
+ printf_filtered ("%s has been optimized out of existence.\n",
+ DEPRECATED_SYMBOL_NAME (sym));
+ break;
+ }
+}
+
+/* Add all locals (or args) symbols to collection list */
+static void
+add_local_symbols (struct collection_list *collect, CORE_ADDR pc,
+ long frame_regno, long frame_offset, int type)
+{
+ struct symbol *sym;
+ struct block *block;
+ struct dict_iterator iter;
+ int count = 0;
+
+ block = block_for_pc (pc);
+ while (block != 0)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ switch (SYMBOL_CLASS (sym))
+ {
+ default:
+ warning ("don't know how to trace local symbol %s",
+ DEPRECATED_SYMBOL_NAME (sym));
+ case LOC_LOCAL:
+ case LOC_STATIC:
+ case LOC_REGISTER:
+ case LOC_BASEREG:
+ if (type == 'L') /* collecting Locals */
+ {
+ count++;
+ collect_symbol (collect, sym, frame_regno, frame_offset);
+ }
+ break;
+ case LOC_ARG:
+ case LOC_LOCAL_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM:
+ case LOC_REGPARM_ADDR:
+ case LOC_BASEREG_ARG:
+ if (type == 'A') /* collecting Arguments */
+ {
+ count++;
+ collect_symbol (collect, sym, frame_regno, frame_offset);
+ }
+ }
+ }
+ if (BLOCK_FUNCTION (block))
+ break;
+ else
+ block = BLOCK_SUPERBLOCK (block);
+ }
+ if (count == 0)
+ warning ("No %s found in scope.", type == 'L' ? "locals" : "args");
+}
+
+/* worker function */
+static void
+clear_collection_list (struct collection_list *list)
+{
+ int ndx;
+
+ list->next_memrange = 0;
+ for (ndx = 0; ndx < list->next_aexpr_elt; ndx++)
+ {
+ free_agent_expr (list->aexpr_list[ndx]);
+ list->aexpr_list[ndx] = NULL;
+ }
+ list->next_aexpr_elt = 0;
+ memset (list->regs_mask, 0, sizeof (list->regs_mask));
+}
+
+/* reduce a collection list to string form (for gdb protocol) */
+static char **
+stringify_collection_list (struct collection_list *list, char *string)
+{
+ char temp_buf[2048];
+ char tmp2[40];
+ int count;
+ int ndx = 0;
+ char *(*str_list)[];
+ char *end;
+ long i;
+
+ count = 1 + list->next_memrange + list->next_aexpr_elt + 1;
+ str_list = (char *(*)[]) xmalloc (count * sizeof (char *));
+
+ for (i = sizeof (list->regs_mask) - 1; i > 0; i--)
+ if (list->regs_mask[i] != 0) /* skip leading zeroes in regs_mask */
+ break;
+ if (list->regs_mask[i] != 0) /* prepare to send regs_mask to the stub */
+ {
+ if (info_verbose)
+ printf_filtered ("\nCollecting registers (mask): 0x");
+ end = temp_buf;
+ *end++ = 'R';
+ for (; i >= 0; i--)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ if (info_verbose)
+ printf_filtered ("%02X", list->regs_mask[i]);
+ sprintf (end, "%02X", list->regs_mask[i]);
+ end += 2;
+ }
+ (*str_list)[ndx] = savestring (temp_buf, end - temp_buf);
+ ndx++;
+ }
+ if (info_verbose)
+ printf_filtered ("\n");
+ if (list->next_memrange > 0 && info_verbose)
+ printf_filtered ("Collecting memranges: \n");
+ for (i = 0, count = 0, end = temp_buf; i < list->next_memrange; i++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ sprintf_vma (tmp2, list->list[i].start);
+ if (info_verbose)
+ {
+ printf_filtered ("(%d, %s, %ld)\n",
+ list->list[i].type,
+ tmp2,
+ (long) (list->list[i].end - list->list[i].start));
+ }
+ if (count + 27 > MAX_AGENT_EXPR_LEN)
+ {
+ (*str_list)[ndx] = savestring (temp_buf, count);
+ ndx++;
+ count = 0;
+ end = temp_buf;
+ }
+
+ sprintf (end, "M%X,%s,%lX",
+ list->list[i].type,
+ tmp2,
+ (long) (list->list[i].end - list->list[i].start));
+
+ count += strlen (end);
+ end += count;
+ }
+
+ for (i = 0; i < list->next_aexpr_elt; i++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ if ((count + 10 + 2 * list->aexpr_list[i]->len) > MAX_AGENT_EXPR_LEN)
+ {
+ (*str_list)[ndx] = savestring (temp_buf, count);
+ ndx++;
+ count = 0;
+ end = temp_buf;
+ }
+ sprintf (end, "X%08X,", list->aexpr_list[i]->len);
+ end += 10; /* 'X' + 8 hex digits + ',' */
+ count += 10;
+
+ end = mem2hex (list->aexpr_list[i]->buf, end, list->aexpr_list[i]->len);
+ count += 2 * list->aexpr_list[i]->len;
+ }
+
+ if (count != 0)
+ {
+ (*str_list)[ndx] = savestring (temp_buf, count);
+ ndx++;
+ count = 0;
+ end = temp_buf;
+ }
+ (*str_list)[ndx] = NULL;
+
+ if (ndx == 0)
+ return NULL;
+ else
+ return *str_list;
+}
+
+static void
+free_actions_list_cleanup_wrapper (void *al)
+{
+ free_actions_list (al);
+}
+
+static void
+free_actions_list (char **actions_list)
+{
+ int ndx;
+
+ if (actions_list == 0)
+ return;
+
+ for (ndx = 0; actions_list[ndx]; ndx++)
+ xfree (actions_list[ndx]);
+
+ xfree (actions_list);
+}
+
+/* render all actions into gdb protocol */
+static void
+encode_actions (struct tracepoint *t, char ***tdp_actions,
+ char ***stepping_actions)
+{
+ static char tdp_buff[2048], step_buff[2048];
+ char *action_exp;
+ struct expression *exp = NULL;
+ struct action_line *action;
+ int i;
+ struct value *tempval;
+ struct collection_list *collect;
+ struct cmd_list_element *cmd;
+ struct agent_expr *aexpr;
+ int frame_reg;
+ LONGEST frame_offset;
+
+
+ clear_collection_list (&tracepoint_list);
+ clear_collection_list (&stepping_list);
+ collect = &tracepoint_list;
+
+ *tdp_actions = NULL;
+ *stepping_actions = NULL;
+
+ TARGET_VIRTUAL_FRAME_POINTER (t->address, &frame_reg, &frame_offset);
+
+ for (action = t->actions; action; action = action->next)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ action_exp = action->action;
+ while (isspace ((int) *action_exp))
+ action_exp++;
+
+ if (*action_exp == '#') /* comment line */
+ return;
+
+ cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+ if (cmd == 0)
+ error ("Bad action list item: %s", action_exp);
+
+ if (cmd_cfunc_eq (cmd, collect_pseudocommand))
+ {
+ do
+ { /* repeat over a comma-separated list */
+ QUIT; /* allow user to bail out with ^C */
+ while (isspace ((int) *action_exp))
+ action_exp++;
+
+ if (0 == strncasecmp ("$reg", action_exp, 4))
+ {
+ for (i = 0; i < NUM_REGS; i++)
+ add_register (collect, i);
+ action_exp = strchr (action_exp, ','); /* more? */
+ }
+ else if (0 == strncasecmp ("$arg", action_exp, 4))
+ {
+ add_local_symbols (collect,
+ t->address,
+ frame_reg,
+ frame_offset,
+ 'A');
+ action_exp = strchr (action_exp, ','); /* more? */
+ }
+ else if (0 == strncasecmp ("$loc", action_exp, 4))
+ {
+ add_local_symbols (collect,
+ t->address,
+ frame_reg,
+ frame_offset,
+ 'L');
+ action_exp = strchr (action_exp, ','); /* more? */
+ }
+ else
+ {
+ unsigned long addr, len;
+ struct cleanup *old_chain = NULL;
+ struct cleanup *old_chain1 = NULL;
+ struct agent_reqs areqs;
+
+ exp = parse_exp_1 (&action_exp,
+ block_for_pc (t->address), 1);
+ old_chain = make_cleanup (free_current_contents, &exp);
+
+ switch (exp->elts[0].opcode)
+ {
+ case OP_REGISTER:
+ i = exp->elts[1].longconst;
+ if (info_verbose)
+ printf_filtered ("OP_REGISTER: ");
+ add_register (collect, i);
+ break;
+
+ case UNOP_MEMVAL:
+ /* safe because we know it's a simple expression */
+ tempval = evaluate_expression (exp);
+ addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval);
+ len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
+ add_memrange (collect, -1, addr, len);
+ break;
+
+ case OP_VAR_VALUE:
+ collect_symbol (collect,
+ exp->elts[2].symbol,
+ frame_reg,
+ frame_offset);
+ break;
+
+ default: /* full-fledged expression */
+ aexpr = gen_trace_for_expr (t->address, exp);
+
+ old_chain1 = make_cleanup_free_agent_expr (aexpr);
+
+ ax_reqs (aexpr, &areqs);
+ if (areqs.flaw != agent_flaw_none)
+ error ("malformed expression");
+
+ if (areqs.min_height < 0)
+ error ("gdb: Internal error: expression has min height < 0");
+ if (areqs.max_height > 20)
+ error ("expression too complicated, try simplifying");
+
+ discard_cleanups (old_chain1);
+ add_aexpr (collect, aexpr);
+
+ /* take care of the registers */
+ if (areqs.reg_mask_len > 0)
+ {
+ int ndx1;
+ int ndx2;
+
+ for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ if (areqs.reg_mask[ndx1] != 0)
+ {
+ /* assume chars have 8 bits */
+ for (ndx2 = 0; ndx2 < 8; ndx2++)
+ if (areqs.reg_mask[ndx1] & (1 << ndx2))
+ /* it's used -- record it */
+ add_register (collect, ndx1 * 8 + ndx2);
+ }
+ }
+ }
+ break;
+ } /* switch */
+ do_cleanups (old_chain);
+ } /* do */
+ }
+ while (action_exp && *action_exp++ == ',');
+ } /* if */
+ else if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+ {
+ collect = &stepping_list;
+ }
+ else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+ {
+ if (collect == &stepping_list) /* end stepping actions */
+ collect = &tracepoint_list;
+ else
+ break; /* end tracepoint actions */
+ }
+ } /* for */
+ memrange_sortmerge (&tracepoint_list);
+ memrange_sortmerge (&stepping_list);
+
+ *tdp_actions = stringify_collection_list (&tracepoint_list, tdp_buff);
+ *stepping_actions = stringify_collection_list (&stepping_list, step_buff);
+}
+
+static void
+add_aexpr (struct collection_list *collect, struct agent_expr *aexpr)
+{
+ if (collect->next_aexpr_elt >= collect->aexpr_listsize)
+ {
+ collect->aexpr_list =
+ xrealloc (collect->aexpr_list,
+ 2 * collect->aexpr_listsize * sizeof (struct agent_expr *));
+ collect->aexpr_listsize *= 2;
+ }
+ collect->aexpr_list[collect->next_aexpr_elt] = aexpr;
+ collect->next_aexpr_elt++;
+}
+
+static char target_buf[2048];
+
+/* Set "transparent" memory ranges
+
+ Allow trace mechanism to treat text-like sections
+ (and perhaps all read-only sections) transparently,
+ i.e. don't reject memory requests from these address ranges
+ just because they haven't been collected. */
+
+static void
+remote_set_transparent_ranges (void)
+{
+ extern bfd *exec_bfd;
+ asection *s;
+ bfd_size_type size;
+ bfd_vma lma;
+ int anysecs = 0;
+
+ if (!exec_bfd)
+ return; /* no information to give. */
+
+ strcpy (target_buf, "QTro");
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ char tmp1[40], tmp2[40];
+
+ if ((s->flags & SEC_LOAD) == 0 ||
+ /* (s->flags & SEC_CODE) == 0 || */
+ (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ anysecs = 1;
+ lma = s->lma;
+ size = bfd_get_section_size_before_reloc (s);
+ sprintf_vma (tmp1, lma);
+ sprintf_vma (tmp2, lma + size);
+ sprintf (target_buf + strlen (target_buf),
+ ":%s,%s", tmp1, tmp2);
+ }
+ if (anysecs)
+ {
+ putpkt (target_buf);
+ getpkt (target_buf, sizeof (target_buf), 0);
+ }
+}
+
+/* tstart command:
+
+ Tell target to clear any previous trace experiment.
+ Walk the list of tracepoints, and send them (and their actions)
+ to the target. If no errors,
+ Tell target to start a new trace experiment. */
+
+static void
+trace_start_command (char *args, int from_tty)
+{ /* STUB_COMM MOSTLY_IMPLEMENTED */
+ struct tracepoint *t;
+ char buf[2048];
+ char **tdp_actions;
+ char **stepping_actions;
+ int ndx;
+ struct cleanup *old_chain = NULL;
+
+ dont_repeat (); /* like "run", dangerous to repeat accidentally */
+
+ if (target_is_remote ())
+ {
+ putpkt ("QTinit");
+ remote_get_noisy_reply (target_buf, sizeof (target_buf));
+ if (strcmp (target_buf, "OK"))
+ error ("Target does not support this command.");
+
+ ALL_TRACEPOINTS (t)
+ {
+ char tmp[40];
+
+ sprintf_vma (tmp, t->address);
+ sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", t->number, tmp, /* address */
+ t->enabled_p ? 'E' : 'D',
+ t->step_count, t->pass_count);
+
+ if (t->actions)
+ strcat (buf, "-");
+ putpkt (buf);
+ remote_get_noisy_reply (target_buf, sizeof (target_buf));
+ if (strcmp (target_buf, "OK"))
+ error ("Target does not support tracepoints.");
+
+ if (t->actions)
+ {
+ encode_actions (t, &tdp_actions, &stepping_actions);
+ old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
+ tdp_actions);
+ (void) make_cleanup (free_actions_list_cleanup_wrapper,
+ stepping_actions);
+
+ /* do_single_steps (t); */
+ if (tdp_actions)
+ {
+ for (ndx = 0; tdp_actions[ndx]; ndx++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ sprintf (buf, "QTDP:-%x:%s:%s%c",
+ t->number, tmp, /* address */
+ tdp_actions[ndx],
+ ((tdp_actions[ndx + 1] || stepping_actions)
+ ? '-' : 0));
+ putpkt (buf);
+ remote_get_noisy_reply (target_buf, sizeof (target_buf));
+ if (strcmp (target_buf, "OK"))
+ error ("Error on target while setting tracepoints.");
+ }
+ }
+ if (stepping_actions)
+ {
+ for (ndx = 0; stepping_actions[ndx]; ndx++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ sprintf (buf, "QTDP:-%x:%s:%s%s%s",
+ t->number, tmp, /* address */
+ ((ndx == 0) ? "S" : ""),
+ stepping_actions[ndx],
+ (stepping_actions[ndx + 1] ? "-" : ""));
+ putpkt (buf);
+ remote_get_noisy_reply (target_buf, sizeof (target_buf));
+ if (strcmp (target_buf, "OK"))
+ error ("Error on target while setting tracepoints.");
+ }
+ }
+
+ do_cleanups (old_chain);
+ }
+ }
+ /* Tell target to treat text-like sections as transparent */
+ remote_set_transparent_ranges ();
+ /* Now insert traps and begin collecting data */
+ putpkt ("QTStart");
+ remote_get_noisy_reply (target_buf, sizeof (target_buf));
+ if (strcmp (target_buf, "OK"))
+ error ("Bogus reply from target: %s", target_buf);
+ set_traceframe_num (-1); /* all old traceframes invalidated */
+ set_tracepoint_num (-1);
+ set_traceframe_context (-1);
+ trace_running_p = 1;
+ if (trace_start_stop_hook)
+ trace_start_stop_hook (1, from_tty);
+
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* tstop command */
+static void
+trace_stop_command (char *args, int from_tty)
+{ /* STUB_COMM IS_IMPLEMENTED */
+ if (target_is_remote ())
+ {
+ putpkt ("QTStop");
+ remote_get_noisy_reply (target_buf, sizeof (target_buf));
+ if (strcmp (target_buf, "OK"))
+ error ("Bogus reply from target: %s", target_buf);
+ trace_running_p = 0;
+ if (trace_start_stop_hook)
+ trace_start_stop_hook (0, from_tty);
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+unsigned long trace_running_p;
+
+/* tstatus command */
+static void
+trace_status_command (char *args, int from_tty)
+{ /* STUB_COMM IS_IMPLEMENTED */
+ if (target_is_remote ())
+ {
+ putpkt ("qTStatus");
+ remote_get_noisy_reply (target_buf, sizeof (target_buf));
+
+ if (target_buf[0] != 'T' ||
+ (target_buf[1] != '0' && target_buf[1] != '1'))
+ error ("Bogus reply from target: %s", target_buf);
+
+ /* exported for use by the GUI */
+ trace_running_p = (target_buf[1] == '1');
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* Worker function for the various flavors of the tfind command */
+static void
+finish_tfind_command (char *msg,
+ long sizeof_msg,
+ int from_tty)
+{
+ int target_frameno = -1, target_tracept = -1;
+ CORE_ADDR old_frame_addr;
+ struct symbol *old_func;
+ char *reply;
+
+ old_frame_addr = get_frame_base (get_current_frame ());
+ old_func = find_pc_function (read_pc ());
+
+ putpkt (msg);
+ reply = remote_get_noisy_reply (msg, sizeof_msg);
+
+ while (reply && *reply)
+ switch (*reply)
+ {
+ case 'F':
+ if ((target_frameno = (int) strtol (++reply, &reply, 16)) == -1)
+ {
+ /* A request for a non-existant trace frame has failed.
+ Our response will be different, depending on FROM_TTY:
+
+ If FROM_TTY is true, meaning that this command was
+ typed interactively by the user, then give an error
+ and DO NOT change the state of traceframe_number etc.
+
+ However if FROM_TTY is false, meaning that we're either
+ in a script, a loop, or a user-defined command, then
+ DON'T give an error, but DO change the state of
+ traceframe_number etc. to invalid.
+
+ The rationalle is that if you typed the command, you
+ might just have committed a typo or something, and you'd
+ like to NOT lose your current debugging state. However
+ if you're in a user-defined command or especially in a
+ loop, then you need a way to detect that the command
+ failed WITHOUT aborting. This allows you to write
+ scripts that search thru the trace buffer until the end,
+ and then continue on to do something else. */
+
+ if (from_tty)
+ error ("Target failed to find requested trace frame.");
+ else
+ {
+ if (info_verbose)
+ printf_filtered ("End of trace buffer.\n");
+ /* The following will not recurse, since it's special-cased */
+ trace_find_command ("-1", from_tty);
+ reply = NULL; /* break out of loop,
+ (avoid recursive nonsense) */
+ }
+ }
+ break;
+ case 'T':
+ if ((target_tracept = (int) strtol (++reply, &reply, 16)) == -1)
+ error ("Target failed to find requested trace frame.");
+ break;
+ case 'O': /* "OK"? */
+ if (reply[1] == 'K' && reply[2] == '\0')
+ reply += 2;
+ else
+ error ("Bogus reply from target: %s", reply);
+ break;
+ default:
+ error ("Bogus reply from target: %s", reply);
+ }
+
+ flush_cached_frames ();
+ registers_changed ();
+ select_frame (get_current_frame ());
+ set_traceframe_num (target_frameno);
+ set_tracepoint_num (target_tracept);
+ if (target_frameno == -1)
+ set_traceframe_context (-1);
+ else
+ set_traceframe_context (read_pc ());
+
+ if (from_tty)
+ {
+ int source_only;
+
+ /* NOTE: in immitation of the step command, try to determine
+ whether we have made a transition from one function to another.
+ If so, we'll print the "stack frame" (ie. the new function and
+ it's arguments) -- otherwise we'll just show the new source line.
+
+ This determination is made by checking (1) whether the current
+ function has changed, and (2) whether the current FP has changed.
+ Hack: if the FP wasn't collected, either at the current or the
+ previous frame, assume that the FP has NOT changed. */
+
+ if (old_func == find_pc_function (read_pc ()) &&
+ (old_frame_addr == 0 ||
+ get_frame_base (get_current_frame ()) == 0 ||
+ old_frame_addr == get_frame_base (get_current_frame ())))
+ source_only = -1;
+ else
+ source_only = 1;
+
+ print_stack_frame (deprecated_selected_frame,
+ frame_relative_level (deprecated_selected_frame),
+ source_only);
+ do_displays ();
+ }
+}
+
+/* trace_find_command takes a trace frame number n,
+ sends "QTFrame:<n>" to the target,
+ and accepts a reply that may contain several optional pieces
+ of information: a frame number, a tracepoint number, and an
+ indication of whether this is a trap frame or a stepping frame.
+
+ The minimal response is just "OK" (which indicates that the
+ target does not give us a frame number or a tracepoint number).
+ Instead of that, the target may send us a string containing
+ any combination of:
+ F<hexnum> (gives the selected frame number)
+ T<hexnum> (gives the selected tracepoint number)
+ */
+
+/* tfind command */
+static void
+trace_find_command (char *args, int from_tty)
+{ /* STUB_COMM PART_IMPLEMENTED */
+ /* this should only be called with a numeric argument */
+ int frameno = -1;
+
+ if (target_is_remote ())
+ {
+ if (trace_find_hook)
+ trace_find_hook (args, from_tty);
+
+ if (args == 0 || *args == 0)
+ { /* TFIND with no args means find NEXT trace frame. */
+ if (traceframe_number == -1)
+ frameno = 0; /* "next" is first one */
+ else
+ frameno = traceframe_number + 1;
+ }
+ else if (0 == strcmp (args, "-"))
+ {
+ if (traceframe_number == -1)
+ error ("not debugging trace buffer");
+ else if (from_tty && traceframe_number == 0)
+ error ("already at start of trace buffer");
+
+ frameno = traceframe_number - 1;
+ }
+ else
+ frameno = parse_and_eval_long (args);
+
+ if (frameno < -1)
+ error ("invalid input (%d is less than zero)", frameno);
+
+ sprintf (target_buf, "QTFrame:%x", frameno);
+ finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* tfind end */
+static void
+trace_find_end_command (char *args, int from_tty)
+{
+ trace_find_command ("-1", from_tty);
+}
+
+/* tfind none */
+static void
+trace_find_none_command (char *args, int from_tty)
+{
+ trace_find_command ("-1", from_tty);
+}
+
+/* tfind start */
+static void
+trace_find_start_command (char *args, int from_tty)
+{
+ trace_find_command ("0", from_tty);
+}
+
+/* tfind pc command */
+static void
+trace_find_pc_command (char *args, int from_tty)
+{ /* STUB_COMM PART_IMPLEMENTED */
+ CORE_ADDR pc;
+ char tmp[40];
+
+ if (target_is_remote ())
+ {
+ if (args == 0 || *args == 0)
+ pc = read_pc (); /* default is current pc */
+ else
+ pc = parse_and_eval_address (args);
+
+ sprintf_vma (tmp, pc);
+ sprintf (target_buf, "QTFrame:pc:%s", tmp);
+ finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* tfind tracepoint command */
+static void
+trace_find_tracepoint_command (char *args, int from_tty)
+{ /* STUB_COMM PART_IMPLEMENTED */
+ int tdp;
+
+ if (target_is_remote ())
+ {
+ if (args == 0 || *args == 0)
+ {
+ if (tracepoint_number == -1)
+ error ("No current tracepoint -- please supply an argument.");
+ else
+ tdp = tracepoint_number; /* default is current TDP */
+ }
+ else
+ tdp = parse_and_eval_long (args);
+
+ sprintf (target_buf, "QTFrame:tdp:%x", tdp);
+ finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* TFIND LINE command:
+
+ This command will take a sourceline for argument, just like BREAK
+ or TRACE (ie. anything that "decode_line_1" can handle).
+
+ With no argument, this command will find the next trace frame
+ corresponding to a source line OTHER THAN THE CURRENT ONE. */
+
+static void
+trace_find_line_command (char *args, int from_tty)
+{ /* STUB_COMM PART_IMPLEMENTED */
+ static CORE_ADDR start_pc, end_pc;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct cleanup *old_chain;
+ char startpc_str[40], endpc_str[40];
+
+ if (target_is_remote ())
+ {
+ if (args == 0 || *args == 0)
+ {
+ sal = find_pc_line (get_frame_pc (get_current_frame ()), 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 (args, 1);
+ sal = sals.sals[0];
+ }
+
+ old_chain = make_cleanup (xfree, sals.sals);
+ if (sal.symtab == 0)
+ {
+ printf_filtered ("TFIND: 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);
+ printf_filtered (";\n -- will attempt to find by PC. \n");
+ }
+ else
+ {
+ printf_filtered (".\n");
+ return; /* no line, no PC; what can we do? */
+ }
+ }
+ 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");
+ sal = find_pc_line (start_pc, 0);
+ if (sal.line > 0 &&
+ find_line_pc_range (sal, &start_pc, &end_pc) &&
+ start_pc != end_pc)
+ printf_filtered ("Attempting to find line %d instead.\n",
+ sal.line);
+ else
+ error ("Cannot find a good line.");
+ }
+ }
+ 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? */
+ error ("Line number %d is out of range for \"%s\".\n",
+ sal.line, sal.symtab->filename);
+
+ sprintf_vma (startpc_str, start_pc);
+ sprintf_vma (endpc_str, end_pc - 1);
+ if (args && *args) /* find within range of stated line */
+ sprintf (target_buf, "QTFrame:range:%s:%s", startpc_str, endpc_str);
+ else /* find OUTSIDE OF range of CURRENT line */
+ sprintf (target_buf, "QTFrame:outside:%s:%s", startpc_str, endpc_str);
+ finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+ do_cleanups (old_chain);
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* tfind range command */
+static void
+trace_find_range_command (char *args, int from_tty)
+{
+ static CORE_ADDR start, stop;
+ char start_str[40], stop_str[40];
+ char *tmp;
+
+ if (target_is_remote ())
+ {
+ if (args == 0 || *args == 0)
+ { /* XXX FIXME: what should default behavior be? */
+ printf_filtered ("Usage: tfind range <startaddr>,<endaddr>\n");
+ return;
+ }
+
+ if (0 != (tmp = strchr (args, ',')))
+ {
+ *tmp++ = '\0'; /* terminate start address */
+ while (isspace ((int) *tmp))
+ tmp++;
+ start = parse_and_eval_address (args);
+ stop = parse_and_eval_address (tmp);
+ }
+ else
+ { /* no explicit end address? */
+ start = parse_and_eval_address (args);
+ stop = start + 1; /* ??? */
+ }
+
+ sprintf_vma (start_str, start);
+ sprintf_vma (stop_str, stop);
+ sprintf (target_buf, "QTFrame:range:%s:%s", start_str, stop_str);
+ finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* tfind outside command */
+static void
+trace_find_outside_command (char *args, int from_tty)
+{
+ CORE_ADDR start, stop;
+ char start_str[40], stop_str[40];
+ char *tmp;
+
+ if (target_is_remote ())
+ {
+ if (args == 0 || *args == 0)
+ { /* XXX FIXME: what should default behavior be? */
+ printf_filtered ("Usage: tfind outside <startaddr>,<endaddr>\n");
+ return;
+ }
+
+ if (0 != (tmp = strchr (args, ',')))
+ {
+ *tmp++ = '\0'; /* terminate start address */
+ while (isspace ((int) *tmp))
+ tmp++;
+ start = parse_and_eval_address (args);
+ stop = parse_and_eval_address (tmp);
+ }
+ else
+ { /* no explicit end address? */
+ start = parse_and_eval_address (args);
+ stop = start + 1; /* ??? */
+ }
+
+ sprintf_vma (start_str, start);
+ sprintf_vma (stop_str, stop);
+ sprintf (target_buf, "QTFrame:outside:%s:%s", start_str, stop_str);
+ finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+ }
+ else
+ error ("Trace can only be run on remote targets.");
+}
+
+/* save-tracepoints command */
+static void
+tracepoint_save_command (char *args, int from_tty)
+{
+ struct tracepoint *tp;
+ struct action_line *line;
+ FILE *fp;
+ char *i1 = " ", *i2 = " ";
+ char *indent, *actionline, *pathname;
+ char tmp[40];
+
+ if (args == 0 || *args == 0)
+ error ("Argument required (file name in which to save tracepoints");
+
+ if (tracepoint_chain == 0)
+ {
+ warning ("save-tracepoints: no tracepoints to save.\n");
+ return;
+ }
+
+ pathname = tilde_expand (args);
+ if (!(fp = fopen (pathname, "w")))
+ error ("Unable to open file '%s' for saving tracepoints (%s)",
+ args, safe_strerror (errno));
+ xfree (pathname);
+
+ ALL_TRACEPOINTS (tp)
+ {
+ if (tp->addr_string)
+ fprintf (fp, "trace %s\n", tp->addr_string);
+ else
+ {
+ sprintf_vma (tmp, tp->address);
+ fprintf (fp, "trace *0x%s\n", tmp);
+ }
+
+ if (tp->pass_count)
+ fprintf (fp, " passcount %d\n", tp->pass_count);
+
+ if (tp->actions)
+ {
+ fprintf (fp, " actions\n");
+ indent = i1;
+ for (line = tp->actions; line; line = line->next)
+ {
+ struct cmd_list_element *cmd;
+
+ QUIT; /* allow user to bail out with ^C */
+ actionline = line->action;
+ while (isspace ((int) *actionline))
+ actionline++;
+
+ fprintf (fp, "%s%s\n", indent, actionline);
+ if (*actionline != '#') /* skip for comment lines */
+ {
+ cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
+ if (cmd == 0)
+ error ("Bad action list item: %s", actionline);
+ if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+ indent = i2;
+ else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+ indent = i1;
+ }
+ }
+ }
+ }
+ fclose (fp);
+ if (from_tty)
+ printf_filtered ("Tracepoints saved to file '%s'.\n", args);
+ return;
+}
+
+/* info scope command: list the locals for a scope. */
+static void
+scope_info (char *args, int from_tty)
+{
+ struct symtabs_and_lines sals;
+ struct symbol *sym;
+ struct minimal_symbol *msym;
+ struct block *block;
+ char **canonical, *symname, *save_args = args;
+ struct dict_iterator iter;
+ int j, count = 0;
+
+ if (args == 0 || *args == 0)
+ error ("requires an argument (function, line or *addr) to define a scope");
+
+ sals = decode_line_1 (&args, 1, NULL, 0, &canonical, NULL);
+ if (sals.nelts == 0)
+ return; /* presumably decode_line_1 has already warned */
+
+ /* Resolve line numbers to PC */
+ resolve_sal_pc (&sals.sals[0]);
+ block = block_for_pc (sals.sals[0].pc);
+
+ while (block != 0)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ if (count == 0)
+ printf_filtered ("Scope for %s:\n", save_args);
+ count++;
+
+ symname = DEPRECATED_SYMBOL_NAME (sym);
+ if (symname == NULL || *symname == '\0')
+ continue; /* probably botched, certainly useless */
+
+ printf_filtered ("Symbol %s is ", symname);
+ switch (SYMBOL_CLASS (sym))
+ {
+ default:
+ case LOC_UNDEF: /* messed up symbol? */
+ printf_filtered ("a bogus symbol, class %d.\n",
+ SYMBOL_CLASS (sym));
+ count--; /* don't count this one */
+ continue;
+ case LOC_CONST:
+ printf_filtered ("a constant with value %ld (0x%lx)",
+ SYMBOL_VALUE (sym), SYMBOL_VALUE (sym));
+ break;
+ case LOC_CONST_BYTES:
+ printf_filtered ("constant bytes: ");
+ if (SYMBOL_TYPE (sym))
+ for (j = 0; j < TYPE_LENGTH (SYMBOL_TYPE (sym)); j++)
+ fprintf_filtered (gdb_stdout, " %02x",
+ (unsigned) SYMBOL_VALUE_BYTES (sym)[j]);
+ break;
+ case LOC_STATIC:
+ printf_filtered ("in static storage at address ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
+ break;
+ case LOC_REGISTER:
+ printf_filtered ("a local variable in register $%s",
+ REGISTER_NAME (SYMBOL_VALUE (sym)));
+ break;
+ case LOC_ARG:
+ case LOC_LOCAL_ARG:
+ printf_filtered ("an argument at stack/frame offset %ld",
+ SYMBOL_VALUE (sym));
+ break;
+ case LOC_LOCAL:
+ printf_filtered ("a local variable at frame offset %ld",
+ SYMBOL_VALUE (sym));
+ break;
+ case LOC_REF_ARG:
+ printf_filtered ("a reference argument at offset %ld",
+ SYMBOL_VALUE (sym));
+ break;
+ case LOC_REGPARM:
+ printf_filtered ("an argument in register $%s",
+ REGISTER_NAME (SYMBOL_VALUE (sym)));
+ break;
+ case LOC_REGPARM_ADDR:
+ printf_filtered ("the address of an argument, in register $%s",
+ REGISTER_NAME (SYMBOL_VALUE (sym)));
+ break;
+ case LOC_TYPEDEF:
+ printf_filtered ("a typedef.\n");
+ continue;
+ case LOC_LABEL:
+ printf_filtered ("a label at address ");
+ print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
+ 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_BASEREG:
+ printf_filtered ("a variable at offset %ld from register $%s",
+ SYMBOL_VALUE (sym),
+ REGISTER_NAME (SYMBOL_BASEREG (sym)));
+ break;
+ case LOC_BASEREG_ARG:
+ printf_filtered ("an argument at offset %ld from register $%s",
+ SYMBOL_VALUE (sym),
+ REGISTER_NAME (SYMBOL_BASEREG (sym)));
+ break;
+ case LOC_UNRESOLVED:
+ msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (sym), NULL, NULL);
+ if (msym == NULL)
+ printf_filtered ("Unresolved Static");
+ 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.\n");
+ continue;
+ }
+ if (SYMBOL_TYPE (sym))
+ printf_filtered (", length %d.\n",
+ TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym))));
+ }
+ if (BLOCK_FUNCTION (block))
+ break;
+ else
+ block = BLOCK_SUPERBLOCK (block);
+ }
+ if (count <= 0)
+ printf_filtered ("Scope for %s contains no locals or arguments.\n",
+ save_args);
+}
+
+/* worker function (cleanup) */
+static void
+replace_comma (void *data)
+{
+ char *comma = data;
+ *comma = ',';
+}
+
+/* tdump command */
+static void
+trace_dump_command (char *args, int from_tty)
+{
+ struct tracepoint *t;
+ struct action_line *action;
+ char *action_exp, *next_comma;
+ struct cleanup *old_cleanups;
+ int stepping_actions = 0;
+ int stepping_frame = 0;
+
+ if (!target_is_remote ())
+ {
+ error ("Trace can only be run on remote targets.");
+ return;
+ }
+
+ if (tracepoint_number == -1)
+ {
+ warning ("No current trace frame.");
+ return;
+ }
+
+ ALL_TRACEPOINTS (t)
+ if (t->number == tracepoint_number)
+ break;
+
+ if (t == NULL)
+ error ("No known tracepoint matches 'current' tracepoint #%d.",
+ tracepoint_number);
+
+ old_cleanups = make_cleanup (null_cleanup, NULL);
+
+ printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n",
+ tracepoint_number, traceframe_number);
+
+ /* The current frame is a trap frame if the frame PC is equal
+ to the tracepoint PC. If not, then the current frame was
+ collected during single-stepping. */
+
+ stepping_frame = (t->address != (read_pc () - DECR_PC_AFTER_BREAK));
+
+ for (action = t->actions; action; action = action->next)
+ {
+ struct cmd_list_element *cmd;
+
+ QUIT; /* allow user to bail out with ^C */
+ action_exp = action->action;
+ while (isspace ((int) *action_exp))
+ action_exp++;
+
+ /* The collection actions to be done while stepping are
+ bracketed by the commands "while-stepping" and "end". */
+
+ if (*action_exp == '#') /* comment line */
+ continue;
+
+ cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+ if (cmd == 0)
+ error ("Bad action list item: %s", action_exp);
+
+ if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+ stepping_actions = 1;
+ else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+ stepping_actions = 0;
+ else if (cmd_cfunc_eq (cmd, collect_pseudocommand))
+ {
+ /* Display the collected data.
+ For the trap frame, display only what was collected at the trap.
+ Likewise for stepping frames, display only what was collected
+ while stepping. This means that the two boolean variables,
+ STEPPING_FRAME and STEPPING_ACTIONS should be equal. */
+ if (stepping_frame == stepping_actions)
+ {
+ do
+ { /* repeat over a comma-separated list */
+ QUIT; /* allow user to bail out with ^C */
+ if (*action_exp == ',')
+ action_exp++;
+ while (isspace ((int) *action_exp))
+ action_exp++;
+
+ next_comma = strchr (action_exp, ',');
+
+ if (0 == strncasecmp (action_exp, "$reg", 4))
+ registers_info (NULL, from_tty);
+ else if (0 == strncasecmp (action_exp, "$loc", 4))
+ locals_info (NULL, from_tty);
+ else if (0 == strncasecmp (action_exp, "$arg", 4))
+ args_info (NULL, from_tty);
+ else
+ { /* variable */
+ if (next_comma)
+ {
+ make_cleanup (replace_comma, next_comma);
+ *next_comma = '\0';
+ }
+ printf_filtered ("%s = ", action_exp);
+ output_command (action_exp, from_tty);
+ printf_filtered ("\n");
+ }
+ if (next_comma)
+ *next_comma = ',';
+ action_exp = next_comma;
+ }
+ while (action_exp && *action_exp == ',');
+ }
+ }
+ }
+ discard_cleanups (old_cleanups);
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null)
+ * "stolen" from sparc-stub.c
+ */
+
+static const char hexchars[] = "0123456789abcdef";
+
+static unsigned char *
+mem2hex (unsigned char *mem, unsigned char *buf, int count)
+{
+ unsigned char ch;
+
+ while (count-- > 0)
+ {
+ ch = *mem++;
+
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+
+ *buf = 0;
+
+ return buf;
+}
+
+int
+get_traceframe_number (void)
+{
+ return traceframe_number;
+}
+
+
+/* module initialization */
+void
+_initialize_tracepoint (void)
+{
+ struct cmd_list_element *c;
+
+ tracepoint_chain = 0;
+ tracepoint_count = 0;
+ traceframe_number = -1;
+ tracepoint_number = -1;
+
+ set_internalvar (lookup_internalvar ("tpnum"),
+ value_from_longest (builtin_type_int, (LONGEST) 0));
+ set_internalvar (lookup_internalvar ("trace_frame"),
+ value_from_longest (builtin_type_int, (LONGEST) - 1));
+
+ if (tracepoint_list.list == NULL)
+ {
+ tracepoint_list.listsize = 128;
+ tracepoint_list.list = xmalloc
+ (tracepoint_list.listsize * sizeof (struct memrange));
+ }
+ if (tracepoint_list.aexpr_list == NULL)
+ {
+ tracepoint_list.aexpr_listsize = 128;
+ tracepoint_list.aexpr_list = xmalloc
+ (tracepoint_list.aexpr_listsize * sizeof (struct agent_expr *));
+ }
+
+ if (stepping_list.list == NULL)
+ {
+ stepping_list.listsize = 128;
+ stepping_list.list = xmalloc
+ (stepping_list.listsize * sizeof (struct memrange));
+ }
+
+ if (stepping_list.aexpr_list == NULL)
+ {
+ stepping_list.aexpr_listsize = 128;
+ stepping_list.aexpr_list = xmalloc
+ (stepping_list.aexpr_listsize * sizeof (struct agent_expr *));
+ }
+
+ add_info ("scope", scope_info,
+ "List the variables local to a scope");
+
+ add_cmd ("tracepoints", class_trace, NULL,
+ "Tracing of program execution without stopping the program.",
+ &cmdlist);
+
+ add_info ("tracepoints", tracepoints_info,
+ "Status of tracepoints, or tracepoint number NUMBER.\n\
+Convenience variable \"$tpnum\" contains the number of the\n\
+last tracepoint set.");
+
+ add_info_alias ("tp", "tracepoints", 1);
+
+ c = add_com ("save-tracepoints", class_trace, tracepoint_save_command,
+ "Save current tracepoint definitions as a script.\n\
+Use the 'source' command in another debug session to restore them.");
+ set_cmd_completer (c, filename_completer);
+
+ add_com ("tdump", class_trace, trace_dump_command,
+ "Print everything collected at the current tracepoint.");
+
+ add_prefix_cmd ("tfind", class_trace, trace_find_command,
+ "Select a trace frame;\n\
+No argument means forward by one frame; '-' meand backward by one frame.",
+ &tfindlist, "tfind ", 1, &cmdlist);
+
+ add_cmd ("outside", class_trace, trace_find_outside_command,
+ "Select a trace frame whose PC is outside the given \
+range.\nUsage: tfind outside addr1, addr2",
+ &tfindlist);
+
+ add_cmd ("range", class_trace, trace_find_range_command,
+ "Select a trace frame whose PC is in the given range.\n\
+Usage: tfind range addr1,addr2",
+ &tfindlist);
+
+ add_cmd ("line", class_trace, trace_find_line_command,
+ "Select a trace frame by source line.\n\
+Argument can be a line number (with optional source file), \n\
+a function name, or '*' followed by an address.\n\
+Default argument is 'the next source line that was traced'.",
+ &tfindlist);
+
+ add_cmd ("tracepoint", class_trace, trace_find_tracepoint_command,
+ "Select a trace frame by tracepoint number.\n\
+Default is the tracepoint for the current trace frame.",
+ &tfindlist);
+
+ add_cmd ("pc", class_trace, trace_find_pc_command,
+ "Select a trace frame by PC.\n\
+Default is the current PC, or the PC of the current trace frame.",
+ &tfindlist);
+
+ add_cmd ("end", class_trace, trace_find_end_command,
+ "Synonym for 'none'.\n\
+De-select any trace frame and resume 'live' debugging.",
+ &tfindlist);
+
+ add_cmd ("none", class_trace, trace_find_none_command,
+ "De-select any trace frame and resume 'live' debugging.",
+ &tfindlist);
+
+ add_cmd ("start", class_trace, trace_find_start_command,
+ "Select the first trace frame in the trace buffer.",
+ &tfindlist);
+
+ add_com ("tstatus", class_trace, trace_status_command,
+ "Display the status of the current trace data collection.");
+
+ add_com ("tstop", class_trace, trace_stop_command,
+ "Stop trace data collection.");
+
+ add_com ("tstart", class_trace, trace_start_command,
+ "Start trace data collection.");
+
+ add_com ("passcount", class_trace, trace_pass_command,
+ "Set the passcount for a tracepoint.\n\
+The trace will end when the tracepoint has been passed 'count' times.\n\
+Usage: passcount COUNT TPNUM, where TPNUM may also be \"all\";\n\
+if TPNUM is omitted, passcount refers to the last tracepoint defined.");
+
+ add_com ("end", class_trace, end_actions_pseudocommand,
+ "Ends a list of commands or actions.\n\
+Several GDB commands allow you to enter a list of commands or actions.\n\
+Entering \"end\" on a line by itself is the normal way to terminate\n\
+such a list.\n\n\
+Note: the \"end\" command cannot be used at the gdb prompt.");
+
+ add_com ("while-stepping", class_trace, while_stepping_pseudocommand,
+ "Specify single-stepping behavior at a tracepoint.\n\
+Argument is number of instructions to trace in single-step mode\n\
+following the tracepoint. This command is normally followed by\n\
+one or more \"collect\" commands, to specify what to collect\n\
+while single-stepping.\n\n\
+Note: this command can only be used in a tracepoint \"actions\" list.");
+
+ add_com_alias ("ws", "while-stepping", class_alias, 0);
+ add_com_alias ("stepping", "while-stepping", class_alias, 0);
+
+ add_com ("collect", class_trace, collect_pseudocommand,
+ "Specify one or more data items to be collected at a tracepoint.\n\
+Accepts a comma-separated list of (one or more) expressions. GDB will\n\
+collect all data (variables, registers) referenced by that expression.\n\
+Also accepts the following special arguments:\n\
+ $regs -- all registers.\n\
+ $args -- all function arguments.\n\
+ $locals -- all variables local to the block/function scope.\n\
+Note: this command can only be used in a tracepoint \"actions\" list.");
+
+ add_com ("actions", class_trace, trace_actions_command,
+ "Specify the actions to be taken at a tracepoint.\n\
+Tracepoint actions may include collecting of specified data, \n\
+single-stepping, or enabling/disabling other tracepoints, \n\
+depending on target's capabilities.");
+
+ add_cmd ("tracepoints", class_trace, delete_trace_command,
+ "Delete specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means delete all tracepoints.",
+ &deletelist);
+
+ add_cmd ("tracepoints", class_trace, disable_trace_command,
+ "Disable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means disable all tracepoints.",
+ &disablelist);
+
+ add_cmd ("tracepoints", class_trace, enable_trace_command,
+ "Enable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means enable all tracepoints.",
+ &enablelist);
+
+ c = add_com ("trace", class_trace, trace_command,
+ "Set a tracepoint at a specified line or function or address.\n\
+Argument may be a line number, function name, or '*' plus an address.\n\
+For a line number or function, trace at the start of its code.\n\
+If an address is specified, trace at that exact address.\n\n\
+Do \"help tracepoints\" for info on other tracepoint commands.");
+ set_cmd_completer (c, location_completer);
+
+ add_com_alias ("tp", "trace", class_alias, 0);
+ add_com_alias ("tr", "trace", class_alias, 1);
+ add_com_alias ("tra", "trace", class_alias, 1);
+ add_com_alias ("trac", "trace", class_alias, 1);
+}
diff --git a/contrib/gdb/gdb/tracepoint.h b/contrib/gdb/gdb/tracepoint.h
new file mode 100644
index 0000000..c464ae1
--- /dev/null
+++ b/contrib/gdb/gdb/tracepoint.h
@@ -0,0 +1,134 @@
+/* Data structures associated with tracepoints in GDB.
+ Copyright 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (TRACEPOINT_H)
+#define TRACEPOINT_H 1
+
+/* The data structure for an action: */
+struct action_line
+ {
+ struct action_line *next;
+ char *action;
+ };
+
+/* The data structure for a tracepoint: */
+
+struct tracepoint
+ {
+ struct tracepoint *next;
+
+ int enabled_p;
+
+#if 0
+ /* Type of tracepoint (MVS FIXME: needed?). */
+ enum tptype type;
+
+ /* What to do with this tracepoint after we hit it MVS FIXME: needed?). */
+ enum tpdisp disposition;
+#endif
+ /* Number assigned to distinguish tracepoints. */
+ int number;
+
+ /* Address to trace at, or NULL if not an instruction tracepoint (MVS ?). */
+ 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;
+
+ /* Number of times this tracepoint should single-step
+ and collect additional data */
+ long step_count;
+
+ /* Number of times this tracepoint should be hit before disabling/ending. */
+ int pass_count;
+
+ /* Chain of action lines to execute when this tracepoint is hit. */
+ struct action_line *actions;
+
+ /* Conditional (MVS ?). */
+ struct expression *cond;
+
+ /* String we used to set the tracepoint (malloc'd). Only matters if
+ address is non-NULL. */
+ char *addr_string;
+
+ /* Language we used to set the tracepoint. */
+ enum language language;
+
+ /* Input radix we used to set the tracepoint. */
+ int input_radix;
+
+ /* Count of the number of times this tracepoint was taken, dumped
+ with the info, but not used for anything else. Useful for
+ seeing how many times you hit a tracepoint prior to the program
+ aborting, so you can back up to just before the abort. */
+ int hit_count;
+
+ /* Thread number for thread-specific tracepoint, or -1 if don't care */
+ int thread;
+
+ /* BFD section, in case of overlays:
+ no, I don't know if tracepoints are really gonna work with overlays. */
+ asection *section;
+ };
+
+enum actionline_type
+ {
+ BADLINE = -1,
+ GENERIC = 0,
+ END = 1,
+ STEPPING = 2
+ };
+
+
+/* The tracepoint chain of all tracepoints */
+
+extern struct tracepoint *tracepoint_chain;
+
+extern unsigned long trace_running_p;
+
+/* A hook used to notify the UI of tracepoint operations */
+
+void (*create_tracepoint_hook) (struct tracepoint *);
+void (*delete_tracepoint_hook) (struct tracepoint *);
+void (*modify_tracepoint_hook) (struct tracepoint *);
+void (*trace_find_hook) (char *arg, int from_tty);
+void (*trace_start_stop_hook) (int start, int from_tty);
+
+struct tracepoint *get_tracepoint_by_number (char **, int, int);
+int get_traceframe_number (void);
+void free_actions (struct tracepoint *);
+enum actionline_type validate_actionline (char **, struct tracepoint *);
+
+
+/* Walk the following statement or block through all tracepoints.
+ ALL_TRACEPOINTS_SAFE does so even if the statment deletes the current
+ breakpoint. */
+
+#define ALL_TRACEPOINTS(t) for (t = tracepoint_chain; t; t = t->next)
+
+#define ALL_TRACEPOINTS_SAFE(t,tmp) \
+ for (t = tracepoint_chain; \
+ t ? (tmp = t->next, 1) : 0;\
+ t = tmp)
+#endif /* TRACEPOINT_H */
diff --git a/contrib/gdb/gdb/trad-frame.c b/contrib/gdb/gdb/trad-frame.c
new file mode 100644
index 0000000..f397f5d
--- /dev/null
+++ b/contrib/gdb/gdb/trad-frame.c
@@ -0,0 +1,134 @@
+/* Traditional frame unwind support, for GDB the GNU Debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "trad-frame.h"
+#include "regcache.h"
+
+/* A traditional frame is unwound by analysing the function prologue
+ and using the information gathered to track registers. For
+ non-optimized frames, the technique is reliable (just need to check
+ for all potential instruction sequences). */
+
+struct trad_frame_saved_reg *
+trad_frame_alloc_saved_regs (struct frame_info *next_frame)
+{
+ int regnum;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int numregs = NUM_REGS + NUM_PSEUDO_REGS;
+ struct trad_frame_saved_reg *this_saved_regs
+ = FRAME_OBSTACK_CALLOC (numregs, struct trad_frame_saved_reg);
+ for (regnum = 0; regnum < numregs; regnum++)
+ {
+ this_saved_regs[regnum].realreg = regnum;
+ this_saved_regs[regnum].addr = -1;
+ }
+ return this_saved_regs;
+}
+
+enum { REG_VALUE = -1, REG_UNKNOWN = -2 };
+
+int
+trad_frame_value_p (struct trad_frame_saved_reg this_saved_regs[], int regnum)
+{
+ return (this_saved_regs[regnum].realreg == REG_VALUE);
+}
+
+int
+trad_frame_addr_p (struct trad_frame_saved_reg this_saved_regs[], int regnum)
+{
+ return (this_saved_regs[regnum].realreg >= 0
+ && this_saved_regs[regnum].addr != -1);
+}
+
+int
+trad_frame_realreg_p (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum)
+{
+ return (this_saved_regs[regnum].realreg >= 0
+ && this_saved_regs[regnum].addr == -1);
+}
+
+void
+trad_frame_set_value (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum, LONGEST val)
+{
+ /* Make the REALREG invalid, indicating that the ADDR contains the
+ register's value. */
+ this_saved_regs[regnum].realreg = REG_VALUE;
+ this_saved_regs[regnum].addr = val;
+}
+
+void
+trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum)
+{
+ /* Make the REALREG invalid, indicating that the value is not known. */
+ this_saved_regs[regnum].realreg = REG_UNKNOWN;
+ this_saved_regs[regnum].addr = -1;
+}
+
+void
+trad_frame_prev_register (struct frame_info *next_frame,
+ struct trad_frame_saved_reg this_saved_regs[],
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realregp, void *bufferp)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ if (trad_frame_addr_p (this_saved_regs, regnum))
+ {
+ /* The register was saved in memory. */
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = this_saved_regs[regnum].addr;
+ *realregp = -1;
+ if (bufferp != NULL)
+ {
+ /* Read the value in from memory. */
+ get_frame_memory (next_frame, this_saved_regs[regnum].addr, bufferp,
+ register_size (gdbarch, regnum));
+ }
+ }
+ else if (trad_frame_realreg_p (this_saved_regs, regnum))
+ {
+ /* Ask the next frame to return the value of the register. */
+ frame_register_unwind (next_frame, this_saved_regs[regnum].realreg,
+ optimizedp, lvalp, addrp, realregp, bufferp);
+ }
+ else if (trad_frame_value_p (this_saved_regs, regnum))
+ {
+ /* The register's value is available. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realregp = -1;
+ if (bufferp != NULL)
+ store_unsigned_integer (bufferp, register_size (gdbarch, regnum),
+ this_saved_regs[regnum].addr);
+ }
+ else
+ {
+ error ("Register %s not available",
+ gdbarch_register_name (gdbarch, regnum));
+ }
+}
diff --git a/contrib/gdb/gdb/trad-frame.h b/contrib/gdb/gdb/trad-frame.h
new file mode 100644
index 0000000..55720c7
--- /dev/null
+++ b/contrib/gdb/gdb/trad-frame.h
@@ -0,0 +1,88 @@
+/* Traditional frame unwind support, for GDB the GNU Debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TRAD_FRAME_H
+#define TRAD_FRAME_H
+
+struct frame_info;
+
+/* A traditional saved regs table, indexed by REGNUM, encoding where
+ the value of REGNUM for the previous frame can be found in this
+ frame.
+
+ The table is initialized with an identity encoding (ADDR == -1,
+ REALREG == REGNUM) indicating that the value of REGNUM in the
+ previous frame can be found in register REGNUM (== REALREG) in this
+ frame.
+
+ The initial encoding can then be changed:
+
+ Modify ADDR (REALREG >= 0, ADDR != -1) to indicate that the value
+ of register REGNUM in the previous frame can be found in memory at
+ ADDR in this frame (addr_p, !realreg_p, !value_p).
+
+ Modify REALREG (REALREG >= 0, ADDR == -1) to indicate that the
+ value of register REGNUM in the previous frame is found in register
+ REALREG in this frame (!addr_p, realreg_p, !value_p).
+
+ Call trad_frame_set_value (REALREG == -1) to indicate that the
+ value of register REGNUM in the previous frame is found in ADDR
+ (!addr_p, !realreg_p, value_p).
+
+ Call trad_frame_set_unknown (REALREG == -2) to indicate that the
+ register's value is not known. */
+
+struct trad_frame_saved_reg
+{
+ LONGEST addr; /* A CORE_ADDR fits in a longest. */
+ int realreg;
+};
+
+/* Encode REGNUM value in the trad-frame. */
+void trad_frame_set_value (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum, LONGEST val);
+
+/* Mark REGNUM as unknown. */
+void trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum);
+
+/* Convenience functions, return non-zero if the register has been
+ encoded as specified. */
+int trad_frame_value_p (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum);
+int trad_frame_addr_p (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum);
+int trad_frame_realreg_p (struct trad_frame_saved_reg this_saved_regs[],
+ int regnum);
+
+
+/* Return a freshly allocated (and initialized) trad_frame array. */
+struct trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct frame_info *next_frame);
+
+/* Given the trad_frame info, return the location of the specified
+ register. */
+void trad_frame_prev_register (struct frame_info *next_frame,
+ struct trad_frame_saved_reg this_saved_regs[],
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realregp, void *bufferp);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-command.c b/contrib/gdb/gdb/tui/tui-command.c
new file mode 100644
index 0000000..399ef85
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-command.c
@@ -0,0 +1,131 @@
+/* Specific command window processing.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-win.h"
+#include "tui/tui-io.h"
+
+#include "gdb_curses.h"
+#include "gdb_string.h"
+
+
+/*****************************************
+** STATIC LOCAL FUNCTIONS FORWARD DECLS **
+******************************************/
+
+
+
+/*****************************************
+** PUBLIC FUNCTIONS **
+******************************************/
+
+/* Dispatch the correct tui function based upon the control character. */
+unsigned int
+tui_dispatch_ctrl_char (unsigned int ch)
+{
+ struct tui_win_info *win_info = tui_win_with_focus ();
+ WINDOW *w = TUI_CMD_WIN->generic.handle;
+
+ /*
+ ** If the command window has the logical focus, or no-one does
+ ** assume it is the command window; in this case, pass the
+ ** character on through and do nothing here.
+ */
+ if (win_info == NULL || win_info == TUI_CMD_WIN)
+ return ch;
+ else
+ {
+ unsigned int c = 0, ch_copy = ch;
+ int i;
+ char *term;
+
+ /* If this is an xterm, page next/prev keys aren't returned
+ ** by keypad as a single char, so we must handle them here.
+ ** Seems like a bug in the curses library?
+ */
+ term = (char *) getenv ("TERM");
+ for (i = 0; (term && term[i]); i++)
+ term[i] = toupper (term[i]);
+ if ((strcmp (term, "XTERM") == 0) && key_is_start_sequence (ch))
+ {
+ unsigned int page_ch = 0;
+ unsigned int tmp_char;
+
+ tmp_char = 0;
+ while (!key_is_end_sequence (tmp_char))
+ {
+ tmp_char = (int) wgetch (w);
+ if (tmp_char == ERR)
+ {
+ return ch;
+ }
+ if (!tmp_char)
+ break;
+ if (tmp_char == 53)
+ page_ch = KEY_PPAGE;
+ else if (tmp_char == 54)
+ page_ch = KEY_NPAGE;
+ else
+ {
+ return 0;
+ }
+ }
+ ch_copy = page_ch;
+ }
+
+ switch (ch_copy)
+ {
+ case KEY_NPAGE:
+ tui_scroll_forward (win_info, 0);
+ break;
+ case KEY_PPAGE:
+ tui_scroll_backward (win_info, 0);
+ break;
+ case KEY_DOWN:
+ case KEY_SF:
+ tui_scroll_forward (win_info, 1);
+ break;
+ case KEY_UP:
+ case KEY_SR:
+ tui_scroll_backward (win_info, 1);
+ break;
+ case KEY_RIGHT:
+ tui_scroll_left (win_info, 1);
+ break;
+ case KEY_LEFT:
+ tui_scroll_right (win_info, 1);
+ break;
+ case '\f':
+ tui_refresh_all_win ();
+ break;
+ default:
+ c = ch_copy;
+ break;
+ }
+ return c;
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-command.h b/contrib/gdb/gdb/tui/tui-command.h
new file mode 100644
index 0000000..9653bf0
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-command.h
@@ -0,0 +1,30 @@
+/* Specific command window processing.
+
+ Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation,
+ Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_COMMAND_H
+#define TUI_COMMAND_H
+
+extern unsigned int tui_dispatch_ctrl_char (unsigned int);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-data.c b/contrib/gdb/gdb/tui/tui-data.c
new file mode 100644
index 0000000..800d72a
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-data.c
@@ -0,0 +1,924 @@
+/* TUI data manipulation routines.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-wingeneral.h"
+
+#include "gdb_string.h"
+#include "gdb_curses.h"
+
+/****************************
+** GLOBAL DECLARATIONS
+****************************/
+struct tui_win_info *(tui_win_list[MAX_MAJOR_WINDOWS]);
+
+/***************************
+** Private data
+****************************/
+static enum tui_layout_type current_layout = UNDEFINED_LAYOUT;
+static int term_height, term_width;
+static struct tui_gen_win_info _locator;
+static struct tui_gen_win_info exec_info[2];
+static struct tui_win_info * src_win_list[2];
+static struct tui_list source_windows = {(void **) src_win_list, 0};
+static int default_tab_len = DEFAULT_TAB_LEN;
+static struct tui_win_info * win_with_focus = (struct tui_win_info *) NULL;
+static struct tui_layout_def layout_def =
+{SRC_WIN, /* DISPLAY_MODE */
+ FALSE, /* SPLIT */
+ TUI_UNDEFINED_REGS, /* REGS_DISPLAY_TYPE */
+ TUI_SFLOAT_REGS}; /* FLOAT_REGS_DISPLAY_TYPE */
+static int win_resized = FALSE;
+
+
+/*********************************
+** Static function forward decls
+**********************************/
+static void free_content (tui_win_content, int, enum tui_win_type);
+static void free_content_elements (tui_win_content, int, enum tui_win_type);
+
+
+
+/*********************************
+** PUBLIC FUNCTIONS
+**********************************/
+
+int
+tui_win_is_source_type (enum tui_win_type win_type)
+{
+ return (win_type == SRC_WIN || win_type == DISASSEM_WIN);
+}
+
+int
+tui_win_is_auxillary (enum tui_win_type win_type)
+{
+ return (win_type > MAX_MAJOR_WINDOWS);
+}
+
+int
+tui_win_has_locator (struct tui_win_info *win_info)
+{
+ return (win_info != NULL \
+ && win_info->detail.source_info.has_locator);
+}
+
+void
+tui_set_win_highlight (struct tui_win_info *win_info, int highlight)
+{
+ if (win_info != NULL)
+ win_info->is_highlighted = highlight;
+}
+
+/******************************************
+** ACCESSORS & MUTATORS FOR PRIVATE DATA
+******************************************/
+
+/* Answer a whether the terminal window has been resized or not. */
+int
+tui_win_resized (void)
+{
+ return win_resized;
+}
+
+
+/* Set a whether the terminal window has been resized or not. */
+void
+tui_set_win_resized_to (int resized)
+{
+ win_resized = resized;
+}
+
+
+/* Answer a pointer to the current layout definition. */
+struct tui_layout_def *
+tui_layout_def (void)
+{
+ return &layout_def;
+}
+
+
+/* Answer the window with the logical focus. */
+struct tui_win_info *
+tui_win_with_focus (void)
+{
+ return win_with_focus;
+}
+
+
+/* Set the window that has the logical focus. */
+void
+tui_set_win_with_focus (struct tui_win_info * win_info)
+{
+ win_with_focus = win_info;
+}
+
+
+/* Answer the length in chars, of tabs. */
+int
+tui_default_tab_len (void)
+{
+ return default_tab_len;
+}
+
+
+/* Set the length in chars, of tabs. */
+void
+tui_set_default_tab_len (int len)
+{
+ default_tab_len = len;
+}
+
+
+/* Accessor for the current source window. Usually there is only one
+ source window (either source or disassembly), but both can be
+ displayed at the same time. */
+struct tui_list *
+tui_source_windows (void)
+{
+ return &source_windows;
+}
+
+
+/* Clear the list of source windows. Usually there is only one source
+ window (either source or disassembly), but both can be displayed at
+ the same time. */
+void
+tui_clear_source_windows (void)
+{
+ source_windows.list[0] = NULL;
+ source_windows.list[1] = NULL;
+ source_windows.count = 0;
+}
+
+
+/* Clear the pertinant detail in the source windows. */
+void
+tui_clear_source_windows_detail (void)
+{
+ int i;
+
+ for (i = 0; i < (tui_source_windows ())->count; i++)
+ tui_clear_win_detail ((struct tui_win_info *) (tui_source_windows ())->list[i]);
+}
+
+
+/* Add a window to the list of source windows. Usually there is only
+ one source window (either source or disassembly), but both can be
+ displayed at the same time. */
+void
+tui_add_to_source_windows (struct tui_win_info * win_info)
+{
+ if (source_windows.count < 2)
+ source_windows.list[source_windows.count++] = (void *) win_info;
+}
+
+
+/* Clear the pertinant detail in the windows. */
+void
+tui_clear_win_detail (struct tui_win_info * win_info)
+{
+ if (win_info != NULL)
+ {
+ switch (win_info->generic.type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ win_info->detail.source_info.start_line_or_addr.addr = 0;
+ win_info->detail.source_info.horizontal_offset = 0;
+ break;
+ case CMD_WIN:
+ win_info->detail.command_info.cur_line =
+ win_info->detail.command_info.curch = 0;
+ break;
+ case DATA_WIN:
+ win_info->detail.data_display_info.data_content =
+ (tui_win_content) NULL;
+ win_info->detail.data_display_info.data_content_count = 0;
+ win_info->detail.data_display_info.regs_content =
+ (tui_win_content) NULL;
+ win_info->detail.data_display_info.regs_content_count = 0;
+ win_info->detail.data_display_info.regs_display_type =
+ TUI_UNDEFINED_REGS;
+ win_info->detail.data_display_info.regs_column_count = 1;
+ win_info->detail.data_display_info.display_regs = FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+/* Accessor for the source execution info ptr. */
+struct tui_gen_win_info *
+tui_source_exec_info_win_ptr (void)
+{
+ return &exec_info[0];
+}
+
+
+/* Accessor for the disassem execution info ptr. */
+struct tui_gen_win_info *
+tui_disassem_exec_info_win_ptr (void)
+{
+ return &exec_info[1];
+}
+
+
+/* Accessor for the locator win info. Answers a pointer to the static
+ locator win info struct. */
+struct tui_gen_win_info *
+tui_locator_win_info_ptr (void)
+{
+ return &_locator;
+}
+
+
+/* Accessor for the term_height. */
+int
+tui_term_height (void)
+{
+ return term_height;
+}
+
+
+/* Mutator for the term height. */
+void
+tui_set_term_height_to (int h)
+{
+ term_height = h;
+}
+
+
+/* Accessor for the term_width. */
+int
+tui_term_width (void)
+{
+ return term_width;
+}
+
+
+/* Mutator for the term_width. */
+void
+tui_set_term_width_to (int w)
+{
+ term_width = w;
+}
+
+
+/* Accessor for the current layout. */
+enum tui_layout_type
+tui_current_layout (void)
+{
+ return current_layout;
+}
+
+
+/* Mutator for the current layout. */
+void
+tui_set_current_layout_to (enum tui_layout_type new_layout)
+{
+ current_layout = new_layout;
+}
+
+
+/* Set the origin of the window. */
+void
+set_gen_win_origin (struct tui_gen_win_info * win_info, int x, int y)
+{
+ win_info->origin.x = x;
+ win_info->origin.y = y;
+}
+
+
+/*****************************
+** OTHER PUBLIC FUNCTIONS
+*****************************/
+
+
+/* Answer the next window in the list, cycling back to the top if
+ necessary. */
+struct tui_win_info *
+tui_next_win (struct tui_win_info * cur_win)
+{
+ enum tui_win_type type = cur_win->generic.type;
+ struct tui_win_info * next_win = (struct tui_win_info *) NULL;
+
+ if (cur_win->generic.type == CMD_WIN)
+ type = SRC_WIN;
+ else
+ type = cur_win->generic.type + 1;
+ while (type != cur_win->generic.type && (next_win == NULL))
+ {
+ if (tui_win_list[type] && tui_win_list[type]->generic.is_visible)
+ next_win = tui_win_list[type];
+ else
+ {
+ if (type == CMD_WIN)
+ type = SRC_WIN;
+ else
+ type++;
+ }
+ }
+
+ return next_win;
+}
+
+
+/* Answer the prev window in the list, cycling back to the bottom if
+ necessary. */
+struct tui_win_info *
+tui_prev_win (struct tui_win_info * cur_win)
+{
+ enum tui_win_type type = cur_win->generic.type;
+ struct tui_win_info * prev = (struct tui_win_info *) NULL;
+
+ if (cur_win->generic.type == SRC_WIN)
+ type = CMD_WIN;
+ else
+ type = cur_win->generic.type - 1;
+ while (type != cur_win->generic.type && (prev == NULL))
+ {
+ if (tui_win_list[type]->generic.is_visible)
+ prev = tui_win_list[type];
+ else
+ {
+ if (type == SRC_WIN)
+ type = CMD_WIN;
+ else
+ type--;
+ }
+ }
+
+ return prev;
+}
+
+
+/* Answer the window represented by name. */
+struct tui_win_info *
+tui_partial_win_by_name (char *name)
+{
+ struct tui_win_info * win_info = (struct tui_win_info *) NULL;
+
+ if (name != (char *) NULL)
+ {
+ int i = 0;
+
+ while (i < MAX_MAJOR_WINDOWS && win_info == NULL)
+ {
+ if (tui_win_list[i] != 0)
+ {
+ char *cur_name = tui_win_name (&tui_win_list[i]->generic);
+ if (strlen (name) <= strlen (cur_name) &&
+ strncmp (name, cur_name, strlen (name)) == 0)
+ win_info = tui_win_list[i];
+ }
+ i++;
+ }
+ }
+
+ return win_info;
+}
+
+
+/* Answer the name of the window. */
+char *
+tui_win_name (struct tui_gen_win_info * win_info)
+{
+ char *name = (char *) NULL;
+
+ switch (win_info->type)
+ {
+ case SRC_WIN:
+ name = SRC_NAME;
+ break;
+ case CMD_WIN:
+ name = CMD_NAME;
+ break;
+ case DISASSEM_WIN:
+ name = DISASSEM_NAME;
+ break;
+ case DATA_WIN:
+ name = DATA_NAME;
+ break;
+ default:
+ name = "";
+ break;
+ }
+
+ return name;
+}
+
+
+void
+tui_initialize_static_data (void)
+{
+ tui_init_generic_part (tui_source_exec_info_win_ptr ());
+ tui_init_generic_part (tui_disassem_exec_info_win_ptr ());
+ tui_init_generic_part (tui_locator_win_info_ptr ());
+}
+
+
+struct tui_gen_win_info *
+tui_alloc_generic_win_info (void)
+{
+ struct tui_gen_win_info * win;
+
+ if ((win = (struct tui_gen_win_info *) xmalloc (
+ sizeof (struct tui_gen_win_info *))) != (struct tui_gen_win_info *) NULL)
+ tui_init_generic_part (win);
+
+ return win;
+}
+
+
+void
+tui_init_generic_part (struct tui_gen_win_info * win)
+{
+ win->width =
+ win->height =
+ win->origin.x =
+ win->origin.y =
+ win->viewport_height =
+ win->content_size =
+ win->last_visible_line = 0;
+ win->handle = (WINDOW *) NULL;
+ win->content = NULL;
+ win->content_in_use =
+ win->is_visible = FALSE;
+ win->title = 0;
+}
+
+
+/*
+ ** init_content_element().
+ */
+void
+init_content_element (struct tui_win_element * element, enum tui_win_type type)
+{
+ element->highlight = FALSE;
+ switch (type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ element->which_element.source.line = (char *) NULL;
+ element->which_element.source.line_or_addr.line_no = 0;
+ element->which_element.source.is_exec_point = FALSE;
+ element->which_element.source.has_break = FALSE;
+ break;
+ case DATA_WIN:
+ tui_init_generic_part (&element->which_element.data_window);
+ element->which_element.data_window.type = DATA_ITEM_WIN;
+ ((struct tui_gen_win_info *) & element->which_element.data_window)->content =
+ (void **) tui_alloc_content (1, DATA_ITEM_WIN);
+ ((struct tui_gen_win_info *)
+ & element->which_element.data_window)->content_size = 1;
+ break;
+ case CMD_WIN:
+ element->which_element.command.line = (char *) NULL;
+ break;
+ case DATA_ITEM_WIN:
+ element->which_element.data.name = (char *) NULL;
+ element->which_element.data.type = TUI_REGISTER;
+ element->which_element.data.item_no = UNDEFINED_ITEM;
+ element->which_element.data.value = NULL;
+ element->which_element.data.highlight = FALSE;
+ element->which_element.data.content = (char*) NULL;
+ break;
+ case LOCATOR_WIN:
+ element->which_element.locator.file_name[0] =
+ element->which_element.locator.proc_name[0] = (char) 0;
+ element->which_element.locator.line_no = 0;
+ element->which_element.locator.addr = 0;
+ break;
+ case EXEC_INFO_WIN:
+ memset(element->which_element.simple_string, ' ',
+ sizeof(element->which_element.simple_string));
+ break;
+ default:
+ break;
+ }
+}
+
+void
+init_win_info (struct tui_win_info * win_info)
+{
+ tui_init_generic_part (&win_info->generic);
+ win_info->can_highlight =
+ win_info->is_highlighted = FALSE;
+ switch (win_info->generic.type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ win_info->detail.source_info.execution_info = (struct tui_gen_win_info *) NULL;
+ win_info->detail.source_info.has_locator = FALSE;
+ win_info->detail.source_info.horizontal_offset = 0;
+ win_info->detail.source_info.start_line_or_addr.addr = 0;
+ win_info->detail.source_info.filename = 0;
+ break;
+ case DATA_WIN:
+ win_info->detail.data_display_info.data_content = (tui_win_content) NULL;
+ win_info->detail.data_display_info.data_content_count = 0;
+ win_info->detail.data_display_info.regs_content = (tui_win_content) NULL;
+ win_info->detail.data_display_info.regs_content_count = 0;
+ win_info->detail.data_display_info.regs_display_type =
+ TUI_UNDEFINED_REGS;
+ win_info->detail.data_display_info.regs_column_count = 1;
+ win_info->detail.data_display_info.display_regs = FALSE;
+ win_info->detail.data_display_info.current_group = 0;
+ break;
+ case CMD_WIN:
+ win_info->detail.command_info.cur_line = 0;
+ win_info->detail.command_info.curch = 0;
+ break;
+ default:
+ win_info->detail.opaque = NULL;
+ break;
+ }
+}
+
+
+struct tui_win_info *
+tui_alloc_win_info (enum tui_win_type type)
+{
+ struct tui_win_info * win_info = (struct tui_win_info *) NULL;
+
+ win_info = (struct tui_win_info *) xmalloc (sizeof (struct tui_win_info));
+ if ((win_info != NULL))
+ {
+ win_info->generic.type = type;
+ init_win_info (win_info);
+ }
+
+ return win_info;
+}
+
+
+/* Allocates the content and elements in a block. */
+tui_win_content
+tui_alloc_content (int num_elements, enum tui_win_type type)
+{
+ tui_win_content content = (tui_win_content) NULL;
+ char *element_block_ptr = (char *) NULL;
+ int i;
+
+ if ((content = (tui_win_content)
+ xmalloc (sizeof (struct tui_win_element *) * num_elements)) != (tui_win_content) NULL)
+ { /*
+ ** All windows, except the data window, can allocate the elements
+ ** in a chunk. The data window cannot because items can be
+ ** added/removed from the data display by the user at any time.
+ */
+ if (type != DATA_WIN)
+ {
+ if ((element_block_ptr = (char *)
+ xmalloc (sizeof (struct tui_win_element) * num_elements)) != (char *) NULL)
+ {
+ for (i = 0; i < num_elements; i++)
+ {
+ content[i] = (struct tui_win_element *) element_block_ptr;
+ init_content_element (content[i], type);
+ element_block_ptr += sizeof (struct tui_win_element);
+ }
+ }
+ else
+ {
+ xfree (content);
+ content = (tui_win_content) NULL;
+ }
+ }
+ }
+
+ return content;
+}
+
+
+/* Adds the input number of elements to the windows's content. If no
+ content has been allocated yet, alloc_content() is called to do
+ this. The index of the first element added is returned, unless
+ there is a memory allocation error, in which case, (-1) is
+ returned. */
+int
+tui_add_content_elements (struct tui_gen_win_info * win_info, int num_elements)
+{
+ struct tui_win_element * element_ptr;
+ int i, index_start;
+
+ if (win_info->content == NULL)
+ {
+ win_info->content = (void **) tui_alloc_content (num_elements, win_info->type);
+ index_start = 0;
+ }
+ else
+ index_start = win_info->content_size;
+ if (win_info->content != NULL)
+ {
+ for (i = index_start; (i < num_elements + index_start); i++)
+ {
+ if ((element_ptr = (struct tui_win_element *)
+ xmalloc (sizeof (struct tui_win_element))) != (struct tui_win_element *) NULL)
+ {
+ win_info->content[i] = (void *) element_ptr;
+ init_content_element (element_ptr, win_info->type);
+ win_info->content_size++;
+ }
+ else /* things must be really hosed now! We ran out of memory!? */
+ return (-1);
+ }
+ }
+
+ return index_start;
+}
+
+
+/* Delete all curses windows associated with win_info, leaving everything
+ else intact. */
+void
+tui_del_window (struct tui_win_info * win_info)
+{
+ struct tui_gen_win_info * generic_win;
+
+ switch (win_info->generic.type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ generic_win = tui_locator_win_info_ptr ();
+ if (generic_win != (struct tui_gen_win_info *) NULL)
+ {
+ tui_delete_win (generic_win->handle);
+ generic_win->handle = (WINDOW *) NULL;
+ generic_win->is_visible = FALSE;
+ }
+ if (win_info->detail.source_info.filename)
+ {
+ xfree (win_info->detail.source_info.filename);
+ win_info->detail.source_info.filename = 0;
+ }
+ generic_win = win_info->detail.source_info.execution_info;
+ if (generic_win != (struct tui_gen_win_info *) NULL)
+ {
+ tui_delete_win (generic_win->handle);
+ generic_win->handle = (WINDOW *) NULL;
+ generic_win->is_visible = FALSE;
+ }
+ break;
+ case DATA_WIN:
+ if (win_info->generic.content != NULL)
+ {
+ tui_del_data_windows (win_info->detail.data_display_info.regs_content,
+ win_info->detail.data_display_info.regs_content_count);
+ tui_del_data_windows (win_info->detail.data_display_info.data_content,
+ win_info->detail.data_display_info.data_content_count);
+ }
+ break;
+ default:
+ break;
+ }
+ if (win_info->generic.handle != (WINDOW *) NULL)
+ {
+ tui_delete_win (win_info->generic.handle);
+ win_info->generic.handle = (WINDOW *) NULL;
+ win_info->generic.is_visible = FALSE;
+ }
+}
+
+
+void
+tui_free_window (struct tui_win_info * win_info)
+{
+ struct tui_gen_win_info * generic_win;
+
+ switch (win_info->generic.type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ generic_win = tui_locator_win_info_ptr ();
+ if (generic_win != (struct tui_gen_win_info *) NULL)
+ {
+ tui_delete_win (generic_win->handle);
+ generic_win->handle = (WINDOW *) NULL;
+ }
+ tui_free_win_content (generic_win);
+ if (win_info->detail.source_info.filename)
+ {
+ xfree (win_info->detail.source_info.filename);
+ win_info->detail.source_info.filename = 0;
+ }
+ generic_win = win_info->detail.source_info.execution_info;
+ if (generic_win != (struct tui_gen_win_info *) NULL)
+ {
+ tui_delete_win (generic_win->handle);
+ generic_win->handle = (WINDOW *) NULL;
+ tui_free_win_content (generic_win);
+ }
+ break;
+ case DATA_WIN:
+ if (win_info->generic.content != NULL)
+ {
+ tui_free_data_content (win_info->detail.data_display_info.regs_content,
+ win_info->detail.data_display_info.regs_content_count);
+ win_info->detail.data_display_info.regs_content =
+ (tui_win_content) NULL;
+ win_info->detail.data_display_info.regs_content_count = 0;
+ tui_free_data_content (win_info->detail.data_display_info.data_content,
+ win_info->detail.data_display_info.data_content_count);
+ win_info->detail.data_display_info.data_content =
+ (tui_win_content) NULL;
+ win_info->detail.data_display_info.data_content_count = 0;
+ win_info->detail.data_display_info.regs_display_type =
+ TUI_UNDEFINED_REGS;
+ win_info->detail.data_display_info.regs_column_count = 1;
+ win_info->detail.data_display_info.display_regs = FALSE;
+ win_info->generic.content = NULL;
+ win_info->generic.content_size = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ if (win_info->generic.handle != (WINDOW *) NULL)
+ {
+ tui_delete_win (win_info->generic.handle);
+ win_info->generic.handle = (WINDOW *) NULL;
+ tui_free_win_content (&win_info->generic);
+ }
+ if (win_info->generic.title)
+ xfree (win_info->generic.title);
+ xfree (win_info);
+}
+
+
+void
+tui_free_all_source_wins_content (void)
+{
+ int i;
+
+ for (i = 0; i < (tui_source_windows ())->count; i++)
+ {
+ struct tui_win_info * win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
+
+ if (win_info != NULL)
+ {
+ tui_free_win_content (&(win_info->generic));
+ tui_free_win_content (win_info->detail.source_info.execution_info);
+ }
+ }
+}
+
+
+void
+tui_free_win_content (struct tui_gen_win_info * win_info)
+{
+ if (win_info->content != NULL)
+ {
+ free_content ((tui_win_content) win_info->content,
+ win_info->content_size,
+ win_info->type);
+ win_info->content = NULL;
+ }
+ win_info->content_size = 0;
+}
+
+
+void
+tui_del_data_windows (tui_win_content content, int content_size)
+{
+ int i;
+
+ /*
+ ** Remember that data window content elements are of type struct tui_gen_win_info *,
+ ** each of which whose single element is a data element.
+ */
+ for (i = 0; i < content_size; i++)
+ {
+ struct tui_gen_win_info * generic_win = &content[i]->which_element.data_window;
+
+ if (generic_win != (struct tui_gen_win_info *) NULL)
+ {
+ tui_delete_win (generic_win->handle);
+ generic_win->handle = (WINDOW *) NULL;
+ generic_win->is_visible = FALSE;
+ }
+ }
+}
+
+
+void
+tui_free_data_content (tui_win_content content, int content_size)
+{
+ int i;
+
+ /*
+ ** Remember that data window content elements are of type struct tui_gen_win_info *,
+ ** each of which whose single element is a data element.
+ */
+ for (i = 0; i < content_size; i++)
+ {
+ struct tui_gen_win_info * generic_win = &content[i]->which_element.data_window;
+
+ if (generic_win != (struct tui_gen_win_info *) NULL)
+ {
+ tui_delete_win (generic_win->handle);
+ generic_win->handle = (WINDOW *) NULL;
+ tui_free_win_content (generic_win);
+ }
+ }
+ free_content (content,
+ content_size,
+ DATA_WIN);
+}
+
+
+/**********************************
+** LOCAL STATIC FUNCTIONS **
+**********************************/
+
+
+static void
+free_content (tui_win_content content, int content_size, enum tui_win_type win_type)
+{
+ if (content != (tui_win_content) NULL)
+ {
+ free_content_elements (content, content_size, win_type);
+ xfree (content);
+ }
+}
+
+
+/*
+ ** free_content_elements().
+ */
+static void
+free_content_elements (tui_win_content content, int content_size, enum tui_win_type type)
+{
+ if (content != (tui_win_content) NULL)
+ {
+ int i;
+
+ if (type == SRC_WIN || type == DISASSEM_WIN)
+ {
+ /* free whole source block */
+ xfree (content[0]->which_element.source.line);
+ }
+ else
+ {
+ for (i = 0; i < content_size; i++)
+ {
+ struct tui_win_element * element;
+
+ element = content[i];
+ if (element != (struct tui_win_element *) NULL)
+ {
+ switch (type)
+ {
+ case DATA_WIN:
+ xfree (element);
+ break;
+ case DATA_ITEM_WIN:
+ /*
+ ** Note that data elements are not allocated
+ ** in a single block, but individually, as needed.
+ */
+ if (element->which_element.data.type != TUI_REGISTER)
+ xfree ((void *)element->which_element.data.name);
+ xfree (element->which_element.data.value);
+ xfree (element->which_element.data.content);
+ xfree (element);
+ break;
+ case CMD_WIN:
+ xfree (element->which_element.command.line);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ if (type != DATA_WIN && type != DATA_ITEM_WIN)
+ xfree (content[0]); /* free the element block */
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-data.h b/contrib/gdb/gdb/tui/tui-data.h
new file mode 100644
index 0000000..02bebb4
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-data.h
@@ -0,0 +1,351 @@
+/* TUI data manipulation routines.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_DATA_H
+#define TUI_DATA_H
+
+#include "tui/tui.h" /* For enum tui_win_type. */
+#include "gdb_curses.h" /* For WINDOW. */
+
+/* This is a point definition. */
+struct tui_point
+{
+ int x, y;
+};
+
+/* Generic window information */
+struct tui_gen_win_info
+{
+ WINDOW *handle; /* window handle */
+ enum tui_win_type type; /* type of window */
+ int width; /* window width */
+ int height; /* window height */
+ struct tui_point origin; /* origin of window */
+ void **content; /* content of window */
+ int content_size; /* Size of content (# of elements) */
+ int content_in_use; /* Can it be used, or is it already used? */
+ int viewport_height; /* viewport height */
+ int last_visible_line; /* index of last visible line */
+ int is_visible; /* whether the window is visible or not */
+ char *title; /* Window title to display. */
+};
+
+/* Constant definitions */
+#define DEFAULT_TAB_LEN 8
+#define NO_SRC_STRING "[ No Source Available ]"
+#define NO_DISASSEM_STRING "[ No Assembly Available ]"
+#define NO_REGS_STRING "[ Register Values Unavailable ]"
+#define NO_DATA_STRING "[ No Data Values Displayed ]"
+#define MAX_CONTENT_COUNT 100
+#define SRC_NAME "SRC"
+#define CMD_NAME "CMD"
+#define DATA_NAME "REGS"
+#define DISASSEM_NAME "ASM"
+#define TUI_NULL_STR ""
+#define DEFAULT_HISTORY_COUNT 25
+#define BOX_WINDOW TRUE
+#define DONT_BOX_WINDOW FALSE
+#define HILITE TRUE
+#define NO_HILITE FALSE
+#define WITH_LOCATOR TRUE
+#define NO_LOCATOR FALSE
+#define EMPTY_SOURCE_PROMPT TRUE
+#define NO_EMPTY_SOURCE_PROMPT FALSE
+#define UNDEFINED_ITEM -1
+#define MIN_WIN_HEIGHT 3
+#define MIN_CMD_WIN_HEIGHT 3
+
+/* Strings to display in the TUI status line. */
+#define PROC_PREFIX "In: "
+#define LINE_PREFIX "Line: "
+#define PC_PREFIX "PC: "
+#define SINGLE_KEY "(SingleKey)"
+
+/* Minimum/Maximum length of some fields displayed in the TUI status line. */
+#define MIN_LINE_WIDTH 4 /* Use at least 4 digits for line numbers. */
+#define MIN_PROC_WIDTH 12
+#define MAX_TARGET_WIDTH 10
+#define MAX_PID_WIDTH 14
+
+#define TUI_FLOAT_REGS_NAME "$FREGS"
+#define TUI_FLOAT_REGS_NAME_LOWER "$fregs"
+#define TUI_GENERAL_REGS_NAME "$GREGS"
+#define TUI_GENERAL_REGS_NAME_LOWER "$gregs"
+#define TUI_SPECIAL_REGS_NAME "$SREGS"
+#define TUI_SPECIAL_REGS_NAME_LOWER "$sregs"
+#define TUI_GENERAL_SPECIAL_REGS_NAME "$REGS"
+#define TUI_GENERAL_SPECIAL_REGS_NAME_LOWER "$regs"
+
+/* Scroll direction enum. */
+enum tui_scroll_direction
+{
+ FORWARD_SCROLL,
+ BACKWARD_SCROLL,
+ LEFT_SCROLL,
+ RIGHT_SCROLL
+};
+
+
+/* General list struct. */
+struct tui_list
+{
+ void **list;
+ int count;
+};
+
+
+/* The kinds of layouts available */
+enum tui_layout_type
+{
+ SRC_COMMAND,
+ DISASSEM_COMMAND,
+ SRC_DISASSEM_COMMAND,
+ SRC_DATA_COMMAND,
+ DISASSEM_DATA_COMMAND,
+ UNDEFINED_LAYOUT
+};
+
+/* Basic data types that can be displayed in the data window. */
+enum tui_data_type
+{
+ TUI_REGISTER,
+ TUI_SCALAR,
+ TUI_COMPLEX,
+ TUI_STRUCT
+};
+
+/* Types of register displays */
+enum tui_register_display_type
+{
+ TUI_UNDEFINED_REGS,
+ TUI_GENERAL_REGS,
+ TUI_SFLOAT_REGS,
+ TUI_DFLOAT_REGS,
+ TUI_SPECIAL_REGS,
+ TUI_GENERAL_AND_SPECIAL_REGS
+};
+
+/* Structure describing source line or line address */
+union tui_line_or_address
+{
+ int line_no;
+ CORE_ADDR addr;
+};
+
+/* Current Layout definition */
+struct tui_layout_def
+{
+ enum tui_win_type display_mode;
+ int split;
+ enum tui_register_display_type regs_display_type;
+ enum tui_register_display_type float_regs_display_type;
+};
+
+/* Elements in the Source/Disassembly Window */
+struct tui_source_element
+{
+ char *line;
+ union tui_line_or_address line_or_addr;
+ int is_exec_point;
+ int has_break;
+};
+
+
+/* Elements in the data display window content */
+struct tui_data_element
+{
+ const char *name;
+ int item_no; /* the register number, or data display number */
+ enum tui_data_type type;
+ void *value;
+ int highlight;
+ char *content;
+};
+
+
+/* Elements in the command window content */
+struct tui_command_element
+{
+ char *line;
+};
+
+
+#define MAX_LOCATOR_ELEMENT_LEN 100
+
+/* Elements in the locator window content */
+struct tui_locator_element
+{
+ char file_name[MAX_LOCATOR_ELEMENT_LEN];
+ char proc_name[MAX_LOCATOR_ELEMENT_LEN];
+ int line_no;
+ CORE_ADDR addr;
+};
+
+/* Flags to tell what kind of breakpoint is at current line. */
+#define TUI_BP_ENABLED 0x01
+#define TUI_BP_DISABLED 0x02
+#define TUI_BP_HIT 0x04
+#define TUI_BP_CONDITIONAL 0x08
+#define TUI_BP_HARDWARE 0x10
+
+/* Position of breakpoint markers in the exec info string. */
+#define TUI_BP_HIT_POS 0
+#define TUI_BP_BREAK_POS 1
+#define TUI_EXEC_POS 2
+#define TUI_EXECINFO_SIZE 4
+
+typedef char tui_exec_info_content[TUI_EXECINFO_SIZE];
+
+/* An content element in a window */
+union tui_which_element
+{
+ struct tui_source_element source; /* the source elements */
+ struct tui_gen_win_info data_window; /* data display elements */
+ struct tui_data_element data; /* elements of data_window */
+ struct tui_command_element command; /* command elements */
+ struct tui_locator_element locator; /* locator elements */
+ tui_exec_info_content simple_string; /* simple char based elements */
+};
+
+struct tui_win_element
+{
+ int highlight;
+ union tui_which_element which_element;
+};
+
+
+/* This describes the content of the window. */
+typedef struct tui_win_element **tui_win_content;
+
+
+/* This struct defines the specific information about a data display window */
+struct tui_data_info
+{
+ tui_win_content data_content; /* start of data display content */
+ int data_content_count;
+ tui_win_content regs_content; /* start of regs display content */
+ int regs_content_count;
+ enum tui_register_display_type regs_display_type;
+ int regs_column_count;
+ int display_regs; /* Should regs be displayed at all? */
+ struct reggroup *current_group;
+};
+
+
+struct tui_source_info
+{
+ int has_locator; /* Does locator belongs to this window? */
+ /* Execution information window. */
+ struct tui_gen_win_info *execution_info;
+ int horizontal_offset; /* used for horizontal scroll */
+ union tui_line_or_address start_line_or_addr;
+ char* filename;
+};
+
+
+struct tui_command_info
+{
+ int cur_line; /* The current line position */
+ int curch; /* The current cursor position */
+ int start_line;
+};
+
+
+/* This defines information about each logical window */
+struct tui_win_info
+{
+ struct tui_gen_win_info generic; /* general window information */
+ union
+ {
+ struct tui_source_info source_info;
+ struct tui_data_info data_display_info;
+ struct tui_command_info command_info;
+ void *opaque;
+ }
+ detail;
+ int can_highlight; /* Can this window ever be highlighted? */
+ int is_highlighted; /* Is this window highlighted? */
+};
+
+extern int tui_win_is_source_type (enum tui_win_type win_type);
+extern int tui_win_is_auxillary (enum tui_win_type win_type);
+extern int tui_win_has_locator (struct tui_win_info *win_info);
+extern void tui_set_win_highlight (struct tui_win_info *win_info,
+ int highlight);
+
+
+/* Global Data */
+extern struct tui_win_info *(tui_win_list[MAX_MAJOR_WINDOWS]);
+
+#define TUI_SRC_WIN tui_win_list[SRC_WIN]
+#define TUI_DISASM_WIN tui_win_list[DISASSEM_WIN]
+#define TUI_DATA_WIN tui_win_list[DATA_WIN]
+#define TUI_CMD_WIN tui_win_list[CMD_WIN]
+
+/* Data Manipulation Functions */
+extern void tui_initialize_static_data (void);
+extern struct tui_gen_win_info *tui_alloc_generic_win_info (void);
+extern struct tui_win_info *tui_alloc_win_info (enum tui_win_type);
+extern void tui_init_generic_part (struct tui_gen_win_info *);
+extern void tui_init_win_info (struct tui_win_info *);
+extern tui_win_content tui_alloc_content (int, enum tui_win_type);
+extern int tui_add_content_elements (struct tui_gen_win_info *, int);
+extern void tui_init_content_element (struct tui_win_element *, enum tui_win_type);
+extern void tui_free_window (struct tui_win_info *);
+extern void tui_free_win_content (struct tui_gen_win_info *);
+extern void tui_free_data_content (tui_win_content, int);
+extern void tui_free_all_source_wins_content (void);
+extern void tui_del_window (struct tui_win_info *);
+extern void tui_del_data_windows (tui_win_content, int);
+extern struct tui_win_info *tui_partial_win_by_name (char *);
+extern char *tui_win_name (struct tui_gen_win_info *);
+extern enum tui_layout_type tui_current_layout (void);
+extern void tui_set_current_layout_to (enum tui_layout_type);
+extern int tui_term_height (void);
+extern void tui_set_term_height_to (int);
+extern int tui_term_width (void);
+extern void tui_set_term_width_to (int);
+extern void tui_set_gen_win_origin (struct tui_gen_win_info *, int, int);
+extern struct tui_gen_win_info *tui_locator_win_info_ptr (void);
+extern struct tui_gen_win_info *tui_source_exec_info_win_ptr (void);
+extern struct tui_gen_win_info *tui_disassem_exec_info_win_ptr (void);
+extern struct tui_list * tui_source_windows (void);
+extern void tui_clear_source_windows (void);
+extern void tui_clear_source_windows_detail (void);
+extern void tui_clear_win_detail (struct tui_win_info * win_info);
+extern void tui_add_to_source_windows (struct tui_win_info *);
+extern int tui_default_tab_len (void);
+extern void tui_set_default_tab_len (int);
+extern struct tui_win_info *tui_win_with_focus (void);
+extern void tui_set_win_with_focus (struct tui_win_info *);
+extern struct tui_layout_def * tui_layout_def (void);
+extern int tui_win_resized (void);
+extern void tui_set_win_resized_to (int);
+
+extern struct tui_win_info *tui_next_win (struct tui_win_info *);
+extern struct tui_win_info *tui_prev_win (struct tui_win_info *);
+
+extern void tui_add_to_source_windows (struct tui_win_info * win_info);
+
+#endif /* TUI_DATA_H */
diff --git a/contrib/gdb/gdb/tui/tui-disasm.c b/contrib/gdb/gdb/tui/tui-disasm.c
new file mode 100644
index 0000000..9c3072b
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-disasm.c
@@ -0,0 +1,397 @@
+/* Disassembly display.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "breakpoint.h"
+#include "frame.h"
+#include "value.h"
+#include "source.h"
+#include "disasm.h"
+#include "gdb_string.h"
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-win.h"
+#include "tui/tui-layout.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-file.h"
+
+#include "gdb_curses.h"
+
+struct tui_asm_line
+{
+ CORE_ADDR addr;
+ char* addr_string;
+ char* insn;
+};
+
+/* Function to set the disassembly window's content.
+ Disassemble count lines starting at pc.
+ Return address of the count'th instruction after pc. */
+static CORE_ADDR
+tui_disassemble (struct tui_asm_line* asm_lines, CORE_ADDR pc, int count)
+{
+ struct ui_file *gdb_dis_out;
+
+ /* now init the ui_file structure */
+ gdb_dis_out = tui_sfileopen (256);
+
+ /* Now construct each line */
+ for (; count > 0; count--, asm_lines++)
+ {
+ if (asm_lines->addr_string)
+ xfree (asm_lines->addr_string);
+ if (asm_lines->insn)
+ xfree (asm_lines->insn);
+
+ print_address (pc, gdb_dis_out);
+ asm_lines->addr = pc;
+ asm_lines->addr_string = xstrdup (tui_file_get_strbuf (gdb_dis_out));
+
+ ui_file_rewind (gdb_dis_out);
+
+ pc = pc + gdb_print_insn (pc, gdb_dis_out);
+
+ asm_lines->insn = xstrdup (tui_file_get_strbuf (gdb_dis_out));
+
+ /* reset the buffer to empty */
+ ui_file_rewind (gdb_dis_out);
+ }
+ ui_file_delete (gdb_dis_out);
+ return pc;
+}
+
+/* Find the disassembly address that corresponds to FROM lines
+ above or below the PC. Variable sized instructions are taken
+ into account by the algorithm. */
+static CORE_ADDR
+tui_find_disassembly_address (CORE_ADDR pc, int from)
+{
+ CORE_ADDR new_low;
+ int max_lines;
+ int i;
+ struct tui_asm_line* asm_lines;
+
+ max_lines = (from > 0) ? from : - from;
+ if (max_lines <= 1)
+ return pc;
+
+ asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line)
+ * max_lines);
+ memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
+
+ new_low = pc;
+ if (from > 0)
+ {
+ tui_disassemble (asm_lines, pc, max_lines);
+ new_low = asm_lines[max_lines - 1].addr;
+ }
+ else
+ {
+ CORE_ADDR last_addr;
+ int pos;
+ struct minimal_symbol* msymbol;
+
+ /* Find backward an address which is a symbol
+ and for which disassembling from that address will fill
+ completely the window. */
+ pos = max_lines - 1;
+ do {
+ new_low -= 1 * max_lines;
+ msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0);
+
+ if (msymbol)
+ new_low = SYMBOL_VALUE_ADDRESS (msymbol);
+ else
+ new_low += 1 * max_lines;
+
+ tui_disassemble (asm_lines, new_low, max_lines);
+ last_addr = asm_lines[pos].addr;
+ } while (last_addr > pc && msymbol);
+
+ /* Scan forward disassembling one instruction at a time
+ until the last visible instruction of the window
+ matches the pc. We keep the disassembled instructions
+ in the 'lines' window and shift it downward (increasing
+ its addresses). */
+ if (last_addr < pc)
+ do
+ {
+ CORE_ADDR next_addr;
+
+ pos++;
+ if (pos >= max_lines)
+ pos = 0;
+
+ next_addr = tui_disassemble (&asm_lines[pos], last_addr, 1);
+
+ /* If there are some problems while disassembling exit. */
+ if (next_addr <= last_addr)
+ break;
+ last_addr = next_addr;
+ } while (last_addr <= pc);
+ pos++;
+ if (pos >= max_lines)
+ pos = 0;
+ new_low = asm_lines[pos].addr;
+ }
+ for (i = 0; i < max_lines; i++)
+ {
+ xfree (asm_lines[i].addr_string);
+ xfree (asm_lines[i].insn);
+ }
+ return new_low;
+}
+
+/* Function to set the disassembly window's content. */
+enum tui_status
+tui_set_disassem_content (CORE_ADDR pc)
+{
+ enum tui_status ret = TUI_FAILURE;
+ int i;
+ int offset = TUI_DISASM_WIN->detail.source_info.horizontal_offset;
+ int line_width, max_lines;
+ CORE_ADDR cur_pc;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+ int tab_len = tui_default_tab_len ();
+ struct tui_asm_line* asm_lines;
+ int insn_pos;
+ int addr_size, max_size;
+ char* line;
+
+ if (pc == 0)
+ return TUI_FAILURE;
+
+ ret = tui_alloc_source_buffer (TUI_DISASM_WIN);
+ if (ret != TUI_SUCCESS)
+ return ret;
+
+ TUI_DISASM_WIN->detail.source_info.start_line_or_addr.addr = pc;
+ cur_pc = (CORE_ADDR)
+ (((struct tui_win_element *) locator->content[0])->which_element.locator.addr);
+
+ max_lines = TUI_DISASM_WIN->generic.height - 2; /* account for hilite */
+
+ /* Get temporary table that will hold all strings (addr & insn). */
+ asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line)
+ * max_lines);
+ memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
+
+ line_width = TUI_DISASM_WIN->generic.width - 1;
+
+ tui_disassemble (asm_lines, pc, max_lines);
+
+ /* See what is the maximum length of an address and of a line. */
+ addr_size = 0;
+ max_size = 0;
+ for (i = 0; i < max_lines; i++)
+ {
+ size_t len = strlen (asm_lines[i].addr_string);
+ if (len > addr_size)
+ addr_size = len;
+
+ len = strlen (asm_lines[i].insn) + tab_len;
+ if (len > max_size)
+ max_size = len;
+ }
+ max_size += addr_size + tab_len;
+
+ /* Allocate memory to create each line. */
+ line = (char*) alloca (max_size);
+ insn_pos = (1 + (addr_size / tab_len)) * tab_len;
+
+ /* Now construct each line */
+ for (i = 0; i < max_lines; i++)
+ {
+ struct tui_win_element * element;
+ struct tui_source_element* src;
+ int cur_len;
+
+ element = (struct tui_win_element *) TUI_DISASM_WIN->generic.content[i];
+ src = &element->which_element.source;
+ strcpy (line, asm_lines[i].addr_string);
+ cur_len = strlen (line);
+
+ /* Add spaces to make the instructions start on the same column */
+ while (cur_len < insn_pos)
+ {
+ strcat (line, " ");
+ cur_len++;
+ }
+
+ strcat (line, asm_lines[i].insn);
+
+ /* Now copy the line taking the offset into account */
+ if (strlen (line) > offset)
+ strcpy (src->line, &line[offset]);
+ else
+ src->line[0] = '\0';
+
+ src->line_or_addr.addr = asm_lines[i].addr;
+ src->is_exec_point = asm_lines[i].addr == cur_pc;
+
+ /* See whether there is a breakpoint installed. */
+ src->has_break = (!src->is_exec_point
+ && breakpoint_here_p (pc) != no_breakpoint_here);
+
+ xfree (asm_lines[i].addr_string);
+ xfree (asm_lines[i].insn);
+ }
+ TUI_DISASM_WIN->generic.content_size = i;
+ return TUI_SUCCESS;
+}
+
+
+/* Function to display the disassembly window with disassembled code. */
+void
+tui_show_disassem (CORE_ADDR start_addr)
+{
+ struct symtab *s = find_pc_symtab (start_addr);
+ struct tui_win_info * win_with_focus = tui_win_with_focus ();
+ union tui_line_or_address val;
+
+ val.addr = start_addr;
+ tui_add_win_to_layout (DISASSEM_WIN);
+ tui_update_source_window (TUI_DISASM_WIN, s, val, FALSE);
+ /*
+ ** if the focus was in the src win, put it in the asm win, if the
+ ** source view isn't split
+ */
+ if (tui_current_layout () != SRC_DISASSEM_COMMAND && win_with_focus == TUI_SRC_WIN)
+ tui_set_win_focus_to (TUI_DISASM_WIN);
+
+ return;
+}
+
+
+/* Function to display the disassembly window. */
+void
+tui_show_disassem_and_update_source (CORE_ADDR start_addr)
+{
+ struct symtab_and_line sal;
+
+ tui_show_disassem (start_addr);
+ if (tui_current_layout () == SRC_DISASSEM_COMMAND)
+ {
+ union tui_line_or_address val;
+
+ /*
+ ** Update what is in the source window if it is displayed too,
+ ** note that it follows what is in the disassembly window and visa-versa
+ */
+ sal = find_pc_line (start_addr, 0);
+ val.line_no = sal.line;
+ tui_update_source_window (TUI_SRC_WIN, sal.symtab, val, TRUE);
+ if (sal.symtab)
+ {
+ set_current_source_symtab_and_line (&sal);
+ tui_update_locator_filename (sal.symtab->filename);
+ }
+ else
+ tui_update_locator_filename ("?");
+ }
+
+ return;
+}
+
+CORE_ADDR
+tui_get_begin_asm_address (void)
+{
+ struct tui_gen_win_info * locator;
+ struct tui_locator_element * element;
+ CORE_ADDR addr;
+
+ locator = tui_locator_win_info_ptr ();
+ element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
+
+ if (element->addr == 0)
+ {
+ struct minimal_symbol *main_symbol;
+
+ /* Find address of the start of program.
+ Note: this should be language specific. */
+ main_symbol = lookup_minimal_symbol ("main", NULL, NULL);
+ if (main_symbol == 0)
+ main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL);
+ if (main_symbol == 0)
+ main_symbol = lookup_minimal_symbol ("_start", NULL, NULL);
+ if (main_symbol)
+ addr = SYMBOL_VALUE_ADDRESS (main_symbol);
+ else
+ addr = 0;
+ }
+ else /* the target is executing */
+ addr = element->addr;
+
+ return addr;
+}
+
+/* Determine what the low address will be to display in the TUI's
+ disassembly window. This may or may not be the same as the
+ low address input. */
+CORE_ADDR
+tui_get_low_disassembly_address (CORE_ADDR low, CORE_ADDR pc)
+{
+ int pos;
+
+ /* Determine where to start the disassembly so that the pc is about in the
+ middle of the viewport. */
+ pos = tui_default_win_viewport_height (DISASSEM_WIN, DISASSEM_COMMAND) / 2;
+ pc = tui_find_disassembly_address (pc, -pos);
+
+ if (pc < low)
+ pc = low;
+ return pc;
+}
+
+/* Scroll the disassembly forward or backward vertically. */
+void
+tui_vertical_disassem_scroll (enum tui_scroll_direction scroll_direction,
+ int num_to_scroll)
+{
+ if (TUI_DISASM_WIN->generic.content != NULL)
+ {
+ CORE_ADDR pc;
+ tui_win_content content;
+ struct symtab *s;
+ union tui_line_or_address val;
+ int max_lines, dir;
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+ content = (tui_win_content) TUI_DISASM_WIN->generic.content;
+ if (cursal.symtab == (struct symtab *) NULL)
+ s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
+ else
+ s = cursal.symtab;
+
+ /* account for hilite */
+ max_lines = TUI_DISASM_WIN->generic.height - 2;
+ pc = content[0]->which_element.source.line_or_addr.addr;
+ dir = (scroll_direction == FORWARD_SCROLL) ? max_lines : - max_lines;
+
+ val.addr = tui_find_disassembly_address (pc, dir);
+ tui_update_source_window_as_is (TUI_DISASM_WIN, s, val, FALSE);
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-disasm.h b/contrib/gdb/gdb/tui/tui-disasm.h
new file mode 100644
index 0000000..e72aba1
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-disasm.h
@@ -0,0 +1,37 @@
+/* Disassembly display.
+
+ Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation,
+ Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_DISASM_H
+#define TUI_DISASM_H
+
+#include "tui/tui.h" /* For enum tui_status. */
+#include "tui/tui-data.h" /* For enum tui_scroll_direction. */
+
+extern enum tui_status tui_set_disassem_content (CORE_ADDR);
+extern void tui_show_disassem (CORE_ADDR);
+extern void tui_show_disassem_and_update_source (CORE_ADDR);
+extern void tui_vertical_disassem_scroll (enum tui_scroll_direction, int);
+extern CORE_ADDR tui_get_begin_asm_address (void);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-file.c b/contrib/gdb/gdb/tui/tui-file.c
new file mode 100644
index 0000000..5d2740e
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-file.c
@@ -0,0 +1,238 @@
+/* UI_FILE - a generic STDIO like output stream.
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ui-file.h"
+#include "tui/tui-file.h"
+#include "tui/tui-io.h"
+
+#include "tui.h"
+
+#include "gdb_string.h"
+
+/* A ``struct ui_file'' that is compatible with all the legacy
+ code. */
+
+/* new */
+enum streamtype
+{
+ afile,
+ astring
+};
+
+/* new */
+struct tui_stream
+{
+ int *ts_magic;
+ enum streamtype ts_streamtype;
+ FILE *ts_filestream;
+ char *ts_strbuf;
+ int ts_buflen;
+};
+
+static ui_file_flush_ftype tui_file_flush;
+extern ui_file_fputs_ftype tui_file_fputs;
+static ui_file_isatty_ftype tui_file_isatty;
+static ui_file_rewind_ftype tui_file_rewind;
+static ui_file_put_ftype tui_file_put;
+static ui_file_delete_ftype tui_file_delete;
+static struct ui_file *tui_file_new (void);
+static int tui_file_magic;
+
+static struct ui_file *
+tui_file_new (void)
+{
+ struct tui_stream *tui = xmalloc (sizeof (struct tui_stream));
+ struct ui_file *file = ui_file_new ();
+ set_ui_file_data (file, tui, tui_file_delete);
+ set_ui_file_flush (file, tui_file_flush);
+ set_ui_file_fputs (file, tui_file_fputs);
+ set_ui_file_isatty (file, tui_file_isatty);
+ set_ui_file_rewind (file, tui_file_rewind);
+ set_ui_file_put (file, tui_file_put);
+ tui->ts_magic = &tui_file_magic;
+ return file;
+}
+
+static void
+tui_file_delete (struct ui_file *file)
+{
+ struct tui_stream *tmpstream = ui_file_data (file);
+ if (tmpstream->ts_magic != &tui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tui_file_delete: bad magic number");
+ if ((tmpstream->ts_streamtype == astring) &&
+ (tmpstream->ts_strbuf != NULL))
+ {
+ xfree (tmpstream->ts_strbuf);
+ }
+ xfree (tmpstream);
+}
+
+struct ui_file *
+tui_fileopen (FILE *stream)
+{
+ struct ui_file *file = tui_file_new ();
+ struct tui_stream *tmpstream = ui_file_data (file);
+ tmpstream->ts_streamtype = afile;
+ tmpstream->ts_filestream = stream;
+ tmpstream->ts_strbuf = NULL;
+ tmpstream->ts_buflen = 0;
+ return file;
+}
+
+struct ui_file *
+tui_sfileopen (int n)
+{
+ struct ui_file *file = tui_file_new ();
+ struct tui_stream *tmpstream = ui_file_data (file);
+ tmpstream->ts_streamtype = astring;
+ tmpstream->ts_filestream = NULL;
+ if (n > 0)
+ {
+ tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
+ tmpstream->ts_strbuf[0] = '\0';
+ }
+ else
+ /* Do not allocate the buffer now. The first time something is printed
+ one will be allocated by tui_file_adjust_strbuf() */
+ tmpstream->ts_strbuf = NULL;
+ tmpstream->ts_buflen = n;
+ return file;
+}
+
+static int
+tui_file_isatty (struct ui_file *file)
+{
+ struct tui_stream *stream = ui_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tui_file_isatty: bad magic number");
+ if (stream->ts_streamtype == afile)
+ return (isatty (fileno (stream->ts_filestream)));
+ else
+ return 0;
+}
+
+static void
+tui_file_rewind (struct ui_file *file)
+{
+ struct tui_stream *stream = ui_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tui_file_rewind: bad magic number");
+ stream->ts_strbuf[0] = '\0';
+}
+
+static void
+tui_file_put (struct ui_file *file,
+ ui_file_put_method_ftype *write,
+ void *dest)
+{
+ struct tui_stream *stream = ui_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tui_file_put: bad magic number");
+ if (stream->ts_streamtype == astring)
+ write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf));
+}
+
+/* All TUI I/O sent to the *_filtered and *_unfiltered functions
+ eventually ends up here. The fputs_unfiltered_hook is primarily
+ used by GUIs to collect all output and send it to the GUI, instead
+ of the controlling terminal. Only output to gdb_stdout and
+ gdb_stderr are sent to the hook. Everything else is sent on to
+ fputs to allow file I/O to be handled appropriately. */
+
+/* FIXME: Should be broken up and moved to a TUI specific file. */
+
+void
+tui_file_fputs (const char *linebuffer, struct ui_file *file)
+{
+ struct tui_stream *stream = ui_file_data (file);
+
+ if (stream->ts_streamtype == astring)
+ {
+ tui_file_adjust_strbuf (strlen (linebuffer), file);
+ strcat (stream->ts_strbuf, linebuffer);
+ }
+ else
+ {
+ tui_puts (linebuffer);
+ }
+}
+
+char *
+tui_file_get_strbuf (struct ui_file *file)
+{
+ struct tui_stream *stream = ui_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tui_file_get_strbuf: bad magic number");
+ return (stream->ts_strbuf);
+}
+
+/* adjust the length of the buffer by the amount necessary
+ to accomodate appending a string of length N to the buffer contents */
+void
+tui_file_adjust_strbuf (int n, struct ui_file *file)
+{
+ struct tui_stream *stream = ui_file_data (file);
+ int non_null_chars;
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tui_file_adjust_strbuf: bad magic number");
+
+ if (stream->ts_streamtype != astring)
+ return;
+
+ if (stream->ts_strbuf)
+ {
+ /* There is already a buffer allocated */
+ non_null_chars = strlen (stream->ts_strbuf);
+
+ if (n > (stream->ts_buflen - non_null_chars - 1))
+ {
+ stream->ts_buflen = n + non_null_chars + 1;
+ stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen);
+ }
+ }
+ else
+ /* No buffer yet, so allocate one of the desired size */
+ stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
+}
+
+static void
+tui_file_flush (struct ui_file *file)
+{
+ struct tui_stream *stream = ui_file_data (file);
+ if (stream->ts_magic != &tui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tui_file_flush: bad magic number");
+
+ switch (stream->ts_streamtype)
+ {
+ case astring:
+ break;
+ case afile:
+ fflush (stream->ts_filestream);
+ break;
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-file.h b/contrib/gdb/gdb/tui/tui-file.h
new file mode 100644
index 0000000..ea07297
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-file.h
@@ -0,0 +1,29 @@
+/* UI_FILE - a generic STDIO like output stream.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_FILE_H
+#define TUI_FILE_H
+
+extern struct ui_file *tui_fileopen (FILE *);
+extern struct ui_file *tui_sfileopen (int);
+extern char *tui_file_get_strbuf (struct ui_file *);
+extern void tui_file_adjust_strbuf (int, struct ui_file *);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-hooks.c b/contrib/gdb/gdb/tui/tui-hooks.c
new file mode 100644
index 0000000..a864be2
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-hooks.c
@@ -0,0 +1,320 @@
+/* GDB hooks for TUI.
+
+ Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "inferior.h"
+#include "command.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "event-loop.h"
+#include "event-top.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "gdb-events.h"
+#include "ui-out.h"
+#include "top.h"
+#include "readline/readline.h"
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "tui/tui.h"
+#include "tui/tui-hooks.h"
+#include "tui/tui-data.h"
+#include "tui/tui-layout.h"
+#include "tui/tui-io.h"
+#include "tui/tui-regs.h"
+#include "tui/tui-win.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-windata.h"
+#include "tui/tui-winsource.h"
+
+#include "gdb_curses.h"
+
+int tui_target_has_run = 0;
+
+static void (* tui_target_new_objfile_chain) (struct objfile*);
+
+static void
+tui_new_objfile_hook (struct objfile* objfile)
+{
+ if (tui_active)
+ tui_display_main ();
+
+ if (tui_target_new_objfile_chain)
+ tui_target_new_objfile_chain (objfile);
+}
+
+static int
+tui_query_hook (const char * msg, va_list argp)
+{
+ int retval;
+ int ans2;
+ int answer;
+
+ /* Automatically answer "yes" if input is not from a terminal. */
+ if (!input_from_terminal_p ())
+ return 1;
+
+ echo ();
+ while (1)
+ {
+ wrap_here (""); /* Flush any buffered output */
+ gdb_flush (gdb_stdout);
+
+ vfprintf_filtered (gdb_stdout, msg, argp);
+ printf_filtered ("(y or n) ");
+
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+
+ answer = tui_getc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer == EOF) /* C-d */
+ {
+ retval = 1;
+ break;
+ }
+ /* Eat rest of input line, to EOF or newline */
+ if (answer != '\n')
+ do
+ {
+ ans2 = tui_getc (stdin);
+ clearerr (stdin);
+ }
+ while (ans2 != EOF && ans2 != '\n' && ans2 != '\r');
+
+ 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");
+ }
+ noecho ();
+ return retval;
+}
+
+/* Prevent recursion of registers_changed_hook(). */
+static int tui_refreshing_registers = 0;
+
+static void
+tui_registers_changed_hook (void)
+{
+ struct frame_info *fi;
+
+ fi = deprecated_selected_frame;
+ if (fi && tui_refreshing_registers == 0)
+ {
+ tui_refreshing_registers = 1;
+#if 0
+ tui_check_data_values (fi);
+#endif
+ tui_refreshing_registers = 0;
+ }
+}
+
+static void
+tui_register_changed_hook (int regno)
+{
+ struct frame_info *fi;
+
+ fi = deprecated_selected_frame;
+ if (fi && tui_refreshing_registers == 0)
+ {
+ tui_refreshing_registers = 1;
+ tui_check_data_values (fi);
+ tui_refreshing_registers = 0;
+ }
+}
+
+/* Breakpoint creation hook.
+ Update the screen to show the new breakpoint. */
+static void
+tui_event_create_breakpoint (int number)
+{
+ tui_update_all_breakpoint_info ();
+}
+
+/* Breakpoint deletion hook.
+ Refresh the screen to update the breakpoint marks. */
+static void
+tui_event_delete_breakpoint (int number)
+{
+ tui_update_all_breakpoint_info ();
+}
+
+static void
+tui_event_modify_breakpoint (int number)
+{
+ tui_update_all_breakpoint_info ();
+}
+
+static void
+tui_event_default (int number)
+{
+ ;
+}
+
+static struct gdb_events *tui_old_event_hooks;
+
+static struct gdb_events tui_event_hooks =
+{
+ tui_event_create_breakpoint,
+ tui_event_delete_breakpoint,
+ tui_event_modify_breakpoint,
+ tui_event_default,
+ tui_event_default,
+ tui_event_default
+};
+
+/* Called when going to wait for the target.
+ Leave curses mode and setup program mode. */
+static ptid_t
+tui_target_wait_hook (ptid_t pid, struct target_waitstatus *status)
+{
+ ptid_t res;
+
+ /* Leave tui mode (optional). */
+#if 0
+ if (tui_active)
+ {
+ target_terminal_ours ();
+ endwin ();
+ target_terminal_inferior ();
+ }
+#endif
+ tui_target_has_run = 1;
+ res = target_wait (pid, status);
+
+ if (tui_active)
+ {
+ /* TODO: need to refresh (optional). */
+ }
+ return res;
+}
+
+/* The selected frame has changed. This is happens after a target
+ stop or when the user explicitly changes the frame (up/down/thread/...). */
+static void
+tui_selected_frame_level_changed_hook (int level)
+{
+ struct frame_info *fi;
+
+ fi = deprecated_selected_frame;
+ /* 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)
+ {
+ struct symtab *s;
+
+ s = find_pc_symtab (get_frame_pc (fi));
+ /* elz: this if here fixes the problem with the pc not being displayed
+ in the tui asm layout, with no debug symbols. The value of s
+ would be 0 here, and select_source_symtab would abort the
+ command by calling the 'error' function */
+ if (s)
+ select_source_symtab (s);
+
+ /* Display the frame position (even if there is no symbols). */
+ tui_show_frame_info (fi);
+
+ /* Refresh the register window if it's visible. */
+ if (tui_is_window_visible (DATA_WIN))
+ {
+ tui_refreshing_registers = 1;
+ tui_check_data_values (fi);
+ tui_refreshing_registers = 0;
+ }
+ }
+}
+
+/* Called from print_frame_info to list the line we stopped in. */
+static void
+tui_print_frame_info_listing_hook (struct symtab *s, int line,
+ int stopline, int noerror)
+{
+ select_source_symtab (s);
+ tui_show_frame_info (deprecated_selected_frame);
+}
+
+/* Called when the target process died or is detached.
+ Update the status line. */
+static void
+tui_detach_hook (void)
+{
+ tui_show_frame_info (0);
+ tui_display_main ();
+}
+
+/* Install the TUI specific hooks. */
+void
+tui_install_hooks (void)
+{
+ target_wait_hook = tui_target_wait_hook;
+ selected_frame_level_changed_hook = tui_selected_frame_level_changed_hook;
+ print_frame_info_listing_hook = tui_print_frame_info_listing_hook;
+
+ query_hook = tui_query_hook;
+
+ /* Install the event hooks. */
+ tui_old_event_hooks = set_gdb_event_hooks (&tui_event_hooks);
+
+ registers_changed_hook = tui_registers_changed_hook;
+ register_changed_hook = tui_register_changed_hook;
+ detach_hook = tui_detach_hook;
+}
+
+/* Remove the TUI specific hooks. */
+void
+tui_remove_hooks (void)
+{
+ target_wait_hook = 0;
+ selected_frame_level_changed_hook = 0;
+ print_frame_info_listing_hook = 0;
+ query_hook = 0;
+ registers_changed_hook = 0;
+ register_changed_hook = 0;
+ detach_hook = 0;
+
+ /* Restore the previous event hooks. */
+ set_gdb_event_hooks (tui_old_event_hooks);
+}
+
+void _initialize_tui_hooks (void);
+
+void
+_initialize_tui_hooks (void)
+{
+ /* Install the permanent hooks. */
+ tui_target_new_objfile_chain = target_new_objfile_hook;
+ target_new_objfile_hook = tui_new_objfile_hook;
+}
diff --git a/contrib/gdb/gdb/tui/tui-hooks.h b/contrib/gdb/gdb/tui/tui-hooks.h
new file mode 100644
index 0000000..fa1137d
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-hooks.h
@@ -0,0 +1,28 @@
+/* External/Public TUI hools header file, for GDB the GNU debugger.
+
+ Copyright 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_HOOKS_H
+#define TUI_HOOKS_H
+
+extern void tui_install_hooks (void);
+extern void tui_remove_hooks (void);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-interp.c b/contrib/gdb/gdb/tui/tui-interp.c
new file mode 100644
index 0000000..1e1d643
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-interp.c
@@ -0,0 +1,210 @@
+/* TUI Interpreter definitions for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "interps.h"
+#include "top.h"
+#include "event-top.h"
+#include "event-loop.h"
+#include "ui-out.h"
+#include "cli-out.h"
+#include "tui/tui-data.h"
+#include "readline/readline.h"
+#include "tui/tui-win.h"
+#include "tui/tui.h"
+#include "tui/tui-io.h"
+
+/* Set to 1 when the TUI mode must be activated when we first start gdb. */
+static int tui_start_enabled = 0;
+
+/* Cleanup the tui before exiting. */
+
+static void
+tui_exit (void)
+{
+ /* Disable the tui. Curses mode is left leaving the screen
+ in a clean state (see endwin()). */
+ tui_disable ();
+}
+
+/* These implement the TUI interpreter. */
+
+static void *
+tui_init (void)
+{
+ /* Install exit handler to leave the screen in a good shape. */
+ atexit (tui_exit);
+
+ tui_initialize_static_data ();
+
+ tui_initialize_io ();
+ tui_initialize_readline ();
+
+ return NULL;
+}
+
+static int
+tui_resume (void *data)
+{
+ struct ui_file *stream;
+
+ /* gdb_setup_readline will change gdb_stdout. If the TUI was previously
+ writing to gdb_stdout, then set it to the new gdb_stdout afterwards. */
+
+ stream = cli_out_set_stream (tui_old_uiout, gdb_stdout);
+ if (stream != gdb_stdout)
+ {
+ cli_out_set_stream (tui_old_uiout, stream);
+ stream = NULL;
+ }
+
+ gdb_setup_readline ();
+
+ if (stream != NULL)
+ cli_out_set_stream (tui_old_uiout, gdb_stdout);
+
+ if (tui_start_enabled)
+ tui_enable ();
+ return 1;
+}
+
+static int
+tui_suspend (void *data)
+{
+ tui_start_enabled = tui_active;
+ tui_disable ();
+ return 1;
+}
+
+/* Display the prompt if we are silent. */
+
+static int
+tui_display_prompt_p (void *data)
+{
+ if (interp_quiet_p (NULL))
+ return 0;
+ else
+ return 1;
+}
+
+static int
+tui_exec (void *data, const char *command_str)
+{
+ internal_error (__FILE__, __LINE__, "tui_exec called");
+}
+
+
+/* Initialize all the necessary variables, start the event loop,
+ register readline, and stdin, start the loop. */
+
+static void
+tui_command_loop (void *data)
+{
+ int length;
+ char *a_prompt;
+ char *gdb_prompt = get_prompt ();
+
+ /* If we are using readline, set things up and display the first
+ prompt, otherwise just print the prompt. */
+ if (async_command_editing_p)
+ {
+ /* Tell readline what the prompt to display is and what function
+ it will need to call after a whole line is read. This also
+ displays the first prompt. */
+ length = strlen (PREFIX (0)) + strlen (gdb_prompt) + strlen (SUFFIX (0)) + 1;
+ a_prompt = (char *) xmalloc (length);
+ strcpy (a_prompt, PREFIX (0));
+ strcat (a_prompt, gdb_prompt);
+ strcat (a_prompt, SUFFIX (0));
+ rl_callback_handler_install (a_prompt, input_handler);
+ }
+ else
+ display_gdb_prompt (0);
+
+ /* Loop until there is nothing to do. This is the entry point to the
+ event loop engine. gdb_do_one_event, called via catch_errors()
+ will process one event for each invocation. It blocks waits for
+ an event and then processes it. >0 when an event is processed, 0
+ when catch_errors() caught an error and <0 when there are no
+ longer any event sources registered. */
+ while (1)
+ {
+ int result = catch_errors (gdb_do_one_event, 0, "", RETURN_MASK_ALL);
+ if (result < 0)
+ break;
+
+ /* Update gdb output according to TUI mode. Since catch_errors
+ preserves the uiout from changing, this must be done at top
+ level of event loop. */
+ if (tui_active)
+ uiout = tui_out;
+ else
+ uiout = tui_old_uiout;
+
+ if (result == 0)
+ {
+ /* FIXME: this should really be a call to a hook that is
+ interface specific, because interfaces can display the
+ prompt in their own way. */
+ display_gdb_prompt (0);
+ /* This call looks bizarre, but it is required. If the user
+ entered a command that caused an error,
+ after_char_processing_hook won't be called from
+ rl_callback_read_char_wrapper. Using a cleanup there
+ won't work, since we want this function to be called
+ after a new prompt is printed. */
+ if (after_char_processing_hook)
+ (*after_char_processing_hook) ();
+ /* Maybe better to set a flag to be checked somewhere as to
+ whether display the prompt or not. */
+ }
+ }
+
+ /* We are done with the event loop. There are no more event sources
+ to listen to. So we exit GDB. */
+ return;
+}
+
+void
+_initialize_tui_interp (void)
+{
+ static const struct interp_procs procs = {
+ tui_init,
+ tui_resume,
+ tui_suspend,
+ tui_exec,
+ tui_display_prompt_p,
+ tui_command_loop,
+ };
+ struct interp *tui_interp;
+
+ /* Create a default uiout builder for the TUI. */
+ tui_out = tui_out_new (gdb_stdout);
+ interp_add (interp_new ("tui", NULL, tui_out, &procs));
+ if (interpreter_p && strcmp (interpreter_p, "tui") == 0)
+ tui_start_enabled = 1;
+
+ if (interpreter_p && strcmp (interpreter_p, INTERP_CONSOLE) == 0)
+ {
+ xfree (interpreter_p);
+ interpreter_p = xstrdup ("tui");
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-io.c b/contrib/gdb/gdb/tui/tui-io.c
new file mode 100644
index 0000000..addb3b0
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-io.c
@@ -0,0 +1,708 @@
+/* TUI support I/O functions.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "terminal.h"
+#include "target.h"
+#include "event-loop.h"
+#include "event-top.h"
+#include "command.h"
+#include "top.h"
+#include "readline/readline.h"
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-io.h"
+#include "tui/tui-command.h"
+#include "tui/tui-win.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-file.h"
+#include "ui-out.h"
+#include "cli-out.h"
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "gdb_curses.h"
+
+int
+key_is_start_sequence (int ch)
+{
+ return (ch == 27);
+}
+
+int
+key_is_end_sequence (int ch)
+{
+ return (ch == 126);
+}
+
+int
+key_is_backspace (int ch)
+{
+ return (ch == 8);
+}
+
+int
+key_is_command_char (int ch)
+{
+ return ((ch == KEY_NPAGE) || (ch == KEY_PPAGE)
+ || (ch == KEY_LEFT) || (ch == KEY_RIGHT)
+ || (ch == KEY_UP) || (ch == KEY_DOWN)
+ || (ch == KEY_SF) || (ch == KEY_SR)
+ || (ch == (int)'\f') || key_is_start_sequence (ch));
+}
+
+/* Use definition from readline 4.3. */
+#undef CTRL_CHAR
+#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0))
+
+/* This file controls the IO interactions between gdb and curses.
+ When the TUI is enabled, gdb has two modes a curses and a standard
+ mode.
+
+ In curses mode, the gdb outputs are made in a curses command window.
+ For this, the gdb_stdout and gdb_stderr are redirected to the specific
+ ui_file implemented by TUI. The output is handled by tui_puts().
+ The input is also controlled by curses with tui_getc(). The readline
+ library uses this function to get its input. Several readline hooks
+ are installed to redirect readline output to the TUI (see also the
+ note below).
+
+ In normal mode, the gdb outputs are restored to their origin, that
+ is as if TUI is not used. Readline also uses its original getc()
+ function with stdin.
+
+ Note SCz/2001-07-21: the current readline is not clean in its management of
+ the output. Even if we install a redisplay handler, it sometimes writes on
+ a stdout file. It is important to redirect every output produced by
+ readline, otherwise the curses window will be garbled. This is implemented
+ with a pipe that TUI reads and readline writes to. A gdb input handler
+ is created so that reading the pipe is handled automatically.
+ This will probably not work on non-Unix platforms. The best fix is
+ to make readline clean enougth so that is never write on stdout.
+
+ Note SCz/2002-09-01: we now use more readline hooks and it seems that
+ with them we don't need the pipe anymore (verified by creating the pipe
+ and closing its end so that write causes a SIGPIPE). The old pipe code
+ is still there and can be conditionally removed by
+ #undef TUI_USE_PIPE_FOR_READLINE. */
+
+/* For gdb 5.3, prefer to continue the pipe hack as a backup wheel. */
+#define TUI_USE_PIPE_FOR_READLINE
+/*#undef TUI_USE_PIPE_FOR_READLINE*/
+
+/* TUI output files. */
+static struct ui_file *tui_stdout;
+static struct ui_file *tui_stderr;
+struct ui_out *tui_out;
+
+/* GDB output files in non-curses mode. */
+static struct ui_file *tui_old_stdout;
+static struct ui_file *tui_old_stderr;
+struct ui_out *tui_old_uiout;
+
+/* Readline previous hooks. */
+static Function *tui_old_rl_getc_function;
+static VFunction *tui_old_rl_redisplay_function;
+static VFunction *tui_old_rl_prep_terminal;
+static VFunction *tui_old_rl_deprep_terminal;
+static int tui_old_readline_echoing_p;
+
+/* Readline output stream.
+ Should be removed when readline is clean. */
+static FILE *tui_rl_outstream;
+static FILE *tui_old_rl_outstream;
+#ifdef TUI_USE_PIPE_FOR_READLINE
+static int tui_readline_pipe[2];
+#endif
+
+/* The last gdb prompt that was registered in readline.
+ This may be the main gdb prompt or a secondary prompt. */
+static char *tui_rl_saved_prompt;
+
+static unsigned int tui_handle_resize_during_io (unsigned int);
+
+static void
+tui_putc (char c)
+{
+ char buf[2];
+
+ buf[0] = c;
+ buf[1] = 0;
+ tui_puts (buf);
+}
+
+/* Print the string in the curses command window. */
+void
+tui_puts (const char *string)
+{
+ static int tui_skip_line = -1;
+ char c;
+ WINDOW *w;
+
+ w = TUI_CMD_WIN->generic.handle;
+ while ((c = *string++) != 0)
+ {
+ /* Catch annotation and discard them. We need two \032 and
+ discard until a \n is seen. */
+ if (c == '\032')
+ {
+ tui_skip_line++;
+ }
+ else if (tui_skip_line != 1)
+ {
+ tui_skip_line = -1;
+ waddch (w, c);
+ }
+ else if (c == '\n')
+ tui_skip_line = -1;
+ }
+ getyx (w, TUI_CMD_WIN->detail.command_info.cur_line,
+ TUI_CMD_WIN->detail.command_info.curch);
+ TUI_CMD_WIN->detail.command_info.start_line = TUI_CMD_WIN->detail.command_info.cur_line;
+
+ /* We could defer the following. */
+ wrefresh (w);
+ fflush (stdout);
+}
+
+/* Readline callback.
+ Redisplay the command line with its prompt after readline has
+ changed the edited text. */
+void
+tui_redisplay_readline (void)
+{
+ int prev_col;
+ int height;
+ int col, line;
+ int c_pos;
+ int c_line;
+ int in;
+ WINDOW *w;
+ char *prompt;
+ int start_line;
+
+ /* Detect when we temporarily left SingleKey and now the readline
+ edit buffer is empty, automatically restore the SingleKey mode. */
+ if (tui_current_key_mode == TUI_ONE_COMMAND_MODE && rl_end == 0)
+ tui_set_key_mode (TUI_SINGLE_KEY_MODE);
+
+ if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
+ prompt = "";
+ else
+ prompt = tui_rl_saved_prompt;
+
+ c_pos = -1;
+ c_line = -1;
+ w = TUI_CMD_WIN->generic.handle;
+ start_line = TUI_CMD_WIN->detail.command_info.start_line;
+ wmove (w, start_line, 0);
+ prev_col = 0;
+ height = 1;
+ for (in = 0; prompt && prompt[in]; in++)
+ {
+ waddch (w, prompt[in]);
+ getyx (w, line, col);
+ if (col < prev_col)
+ height++;
+ prev_col = col;
+ }
+ for (in = 0; in < rl_end; in++)
+ {
+ unsigned char c;
+
+ c = (unsigned char) rl_line_buffer[in];
+ if (in == rl_point)
+ {
+ getyx (w, c_line, c_pos);
+ }
+
+ if (CTRL_CHAR (c) || c == RUBOUT)
+ {
+ waddch (w, '^');
+ waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?');
+ }
+ else
+ {
+ waddch (w, c);
+ }
+ if (c == '\n')
+ {
+ getyx (w, TUI_CMD_WIN->detail.command_info.start_line,
+ TUI_CMD_WIN->detail.command_info.curch);
+ }
+ getyx (w, line, col);
+ if (col < prev_col)
+ height++;
+ prev_col = col;
+ }
+ wclrtobot (w);
+ getyx (w, TUI_CMD_WIN->detail.command_info.start_line,
+ TUI_CMD_WIN->detail.command_info.curch);
+ if (c_line >= 0)
+ {
+ wmove (w, c_line, c_pos);
+ TUI_CMD_WIN->detail.command_info.cur_line = c_line;
+ TUI_CMD_WIN->detail.command_info.curch = c_pos;
+ }
+ TUI_CMD_WIN->detail.command_info.start_line -= height - 1;
+
+ wrefresh (w);
+ fflush(stdout);
+}
+
+/* Readline callback to prepare the terminal. It is called once
+ each time we enter readline. Terminal is already setup in curses mode. */
+static void
+tui_prep_terminal (int notused1)
+{
+ /* Save the prompt registered in readline to correctly display it.
+ (we can't use gdb_prompt() due to secondary prompts and can't use
+ rl_prompt because it points to an alloca buffer). */
+ xfree (tui_rl_saved_prompt);
+ tui_rl_saved_prompt = xstrdup (rl_prompt);
+}
+
+/* Readline callback to restore the terminal. It is called once
+ each time we leave readline. There is nothing to do in curses mode. */
+static void
+tui_deprep_terminal (void)
+{
+}
+
+#ifdef TUI_USE_PIPE_FOR_READLINE
+/* Read readline output pipe and feed the command window with it.
+ Should be removed when readline is clean. */
+static void
+tui_readline_output (int code, gdb_client_data data)
+{
+ int size;
+ char buf[256];
+
+ size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1);
+ if (size > 0 && tui_active)
+ {
+ buf[size] = 0;
+ tui_puts (buf);
+ }
+}
+#endif
+
+/* Return the portion of PATHNAME that should be output when listing
+ possible completions. If we are hacking filename completion, we
+ are only interested in the basename, the portion following the
+ final slash. Otherwise, we return what we were passed.
+
+ Comes from readline/complete.c */
+static char *
+printable_part (char *pathname)
+{
+ char *temp;
+
+ temp = rl_filename_completion_desired ? strrchr (pathname, '/') : (char *)NULL;
+#if defined (__MSDOS__)
+ if (rl_filename_completion_desired && temp == 0 && isalpha (pathname[0]) && pathname[1] == ':')
+ temp = pathname + 1;
+#endif
+ return (temp ? ++temp : pathname);
+}
+
+/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we
+ are using it, check for and output a single character for `special'
+ filenames. Return the number of characters we output. */
+
+#define PUTX(c) \
+ do { \
+ if (CTRL_CHAR (c)) \
+ { \
+ tui_puts ("^"); \
+ tui_putc (UNCTRL (c)); \
+ printed_len += 2; \
+ } \
+ else if (c == RUBOUT) \
+ { \
+ tui_puts ("^?"); \
+ printed_len += 2; \
+ } \
+ else \
+ { \
+ tui_putc (c); \
+ printed_len++; \
+ } \
+ } while (0)
+
+static int
+print_filename (char *to_print, char *full_pathname)
+{
+ int printed_len = 0;
+ char *s;
+
+ for (s = to_print; *s; s++)
+ {
+ PUTX (*s);
+ }
+ return printed_len;
+}
+
+/* The user must press "y" or "n". Non-zero return means "y" pressed.
+ Comes from readline/complete.c */
+static int
+get_y_or_n (void)
+{
+ extern int _rl_abort_internal ();
+ int c;
+
+ for (;;)
+ {
+ c = rl_read_key ();
+ if (c == 'y' || c == 'Y' || c == ' ')
+ return (1);
+ if (c == 'n' || c == 'N' || c == RUBOUT)
+ return (0);
+ if (c == ABORT_CHAR)
+ _rl_abort_internal ();
+ beep ();
+ }
+}
+
+/* A convenience function for displaying a list of strings in
+ columnar format on readline's output stream. MATCHES is the list
+ of strings, in argv format, LEN is the number of strings in MATCHES,
+ and MAX is the length of the longest string in MATCHES.
+
+ Comes from readline/complete.c and modified to write in
+ the TUI command window using tui_putc/tui_puts. */
+static void
+tui_rl_display_match_list (char **matches, int len, int max)
+{
+ typedef int QSFUNC (const void *, const void *);
+ extern int _rl_qsort_string_compare (const void*, const void*);
+ extern int _rl_print_completions_horizontally;
+
+ int count, limit, printed_len;
+ int i, j, k, l;
+ char *temp;
+
+ /* Screen dimension correspond to the TUI command window. */
+ int screenwidth = TUI_CMD_WIN->generic.width;
+
+ /* If there are many items, then ask the user if she really wants to
+ see them all. */
+ if (len >= rl_completion_query_items)
+ {
+ char msg[256];
+
+ sprintf (msg, "\nDisplay all %d possibilities? (y or n)", len);
+ tui_puts (msg);
+ if (get_y_or_n () == 0)
+ {
+ tui_puts ("\n");
+ return;
+ }
+ }
+
+ /* How many items of MAX length can we fit in the screen window? */
+ max += 2;
+ limit = screenwidth / max;
+ if (limit != 1 && (limit * max == screenwidth))
+ limit--;
+
+ /* Avoid a possible floating exception. If max > screenwidth,
+ limit will be 0 and a divide-by-zero fault will result. */
+ if (limit == 0)
+ limit = 1;
+
+ /* How many iterations of the printing loop? */
+ count = (len + (limit - 1)) / limit;
+
+ /* Watch out for special case. If LEN is less than LIMIT, then
+ just do the inner printing loop.
+ 0 < len <= limit implies count = 1. */
+
+ /* Sort the items if they are not already sorted. */
+ if (rl_ignore_completion_duplicates == 0)
+ qsort (matches + 1, len, sizeof (char *),
+ (QSFUNC *)_rl_qsort_string_compare);
+
+ tui_putc ('\n');
+
+ if (_rl_print_completions_horizontally == 0)
+ {
+ /* Print the sorted items, up-and-down alphabetically, like ls. */
+ for (i = 1; i <= count; i++)
+ {
+ for (j = 0, l = i; j < limit; j++)
+ {
+ if (l > len || matches[l] == 0)
+ break;
+ else
+ {
+ temp = printable_part (matches[l]);
+ printed_len = print_filename (temp, matches[l]);
+
+ if (j + 1 < limit)
+ for (k = 0; k < max - printed_len; k++)
+ tui_putc (' ');
+ }
+ l += count;
+ }
+ tui_putc ('\n');
+ }
+ }
+ else
+ {
+ /* Print the sorted items, across alphabetically, like ls -x. */
+ for (i = 1; matches[i]; i++)
+ {
+ temp = printable_part (matches[i]);
+ printed_len = print_filename (temp, matches[i]);
+ /* Have we reached the end of this line? */
+ if (matches[i+1])
+ {
+ if (i && (limit > 1) && (i % limit) == 0)
+ tui_putc ('\n');
+ else
+ for (k = 0; k < max - printed_len; k++)
+ tui_putc (' ');
+ }
+ }
+ tui_putc ('\n');
+ }
+}
+
+/* Setup the IO for curses or non-curses mode.
+ - In non-curses mode, readline and gdb use the standard input and
+ standard output/error directly.
+ - In curses mode, the standard output/error is controlled by TUI
+ with the tui_stdout and tui_stderr. The output is redirected in
+ the curses command window. Several readline callbacks are installed
+ so that readline asks for its input to the curses command window
+ with wgetch(). */
+void
+tui_setup_io (int mode)
+{
+ extern int readline_echoing_p;
+
+ if (mode)
+ {
+ /* Redirect readline to TUI. */
+ tui_old_rl_redisplay_function = rl_redisplay_function;
+ tui_old_rl_deprep_terminal = rl_deprep_term_function;
+ tui_old_rl_prep_terminal = rl_prep_term_function;
+ tui_old_rl_getc_function = rl_getc_function;
+ tui_old_rl_outstream = rl_outstream;
+ tui_old_readline_echoing_p = readline_echoing_p;
+ rl_redisplay_function = tui_redisplay_readline;
+ rl_deprep_term_function = tui_deprep_terminal;
+ rl_prep_term_function = tui_prep_terminal;
+ rl_getc_function = tui_getc;
+ readline_echoing_p = 0;
+ rl_outstream = tui_rl_outstream;
+ rl_prompt = 0;
+ rl_completion_display_matches_hook = tui_rl_display_match_list;
+ rl_already_prompted = 0;
+
+ /* Keep track of previous gdb output. */
+ tui_old_stdout = gdb_stdout;
+ tui_old_stderr = gdb_stderr;
+ tui_old_uiout = uiout;
+
+ /* Reconfigure gdb output. */
+ gdb_stdout = tui_stdout;
+ gdb_stderr = tui_stderr;
+ gdb_stdlog = gdb_stdout; /* for moment */
+ gdb_stdtarg = gdb_stderr; /* for moment */
+ uiout = tui_out;
+
+ /* Save tty for SIGCONT. */
+ savetty ();
+ }
+ else
+ {
+ /* Restore gdb output. */
+ gdb_stdout = tui_old_stdout;
+ gdb_stderr = tui_old_stderr;
+ gdb_stdlog = gdb_stdout; /* for moment */
+ gdb_stdtarg = gdb_stderr; /* for moment */
+ uiout = tui_old_uiout;
+
+ /* Restore readline. */
+ rl_redisplay_function = tui_old_rl_redisplay_function;
+ rl_deprep_term_function = tui_old_rl_deprep_terminal;
+ rl_prep_term_function = tui_old_rl_prep_terminal;
+ rl_getc_function = tui_old_rl_getc_function;
+ rl_outstream = tui_old_rl_outstream;
+ rl_completion_display_matches_hook = 0;
+ readline_echoing_p = tui_old_readline_echoing_p;
+ rl_already_prompted = 0;
+
+ /* Save tty for SIGCONT. */
+ savetty ();
+ }
+}
+
+#ifdef SIGCONT
+/* Catch SIGCONT to restore the terminal and refresh the screen. */
+static void
+tui_cont_sig (int sig)
+{
+ if (tui_active)
+ {
+ /* Restore the terminal setting because another process (shell)
+ might have changed it. */
+ resetty ();
+
+ /* Force a refresh of the screen. */
+ tui_refresh_all_win ();
+
+ /* Update cursor position on the screen. */
+ wmove (TUI_CMD_WIN->generic.handle,
+ TUI_CMD_WIN->detail.command_info.start_line,
+ TUI_CMD_WIN->detail.command_info.curch);
+ wrefresh (TUI_CMD_WIN->generic.handle);
+ }
+ signal (sig, tui_cont_sig);
+}
+#endif
+
+/* Initialize the IO for gdb in curses mode. */
+void
+tui_initialize_io (void)
+{
+#ifdef SIGCONT
+ signal (SIGCONT, tui_cont_sig);
+#endif
+
+ /* Create tui output streams. */
+ tui_stdout = tui_fileopen (stdout);
+ tui_stderr = tui_fileopen (stderr);
+ tui_out = tui_out_new (tui_stdout);
+
+ /* Create the default UI. It is not created because we installed
+ a init_ui_hook. */
+ tui_old_uiout = uiout = cli_out_new (gdb_stdout);
+
+#ifdef TUI_USE_PIPE_FOR_READLINE
+ /* Temporary solution for readline writing to stdout:
+ redirect readline output in a pipe, read that pipe and
+ output the content in the curses command window. */
+ if (pipe (tui_readline_pipe) != 0)
+ {
+ fprintf_unfiltered (gdb_stderr, "Cannot create pipe for readline");
+ exit (1);
+ }
+ tui_rl_outstream = fdopen (tui_readline_pipe[1], "w");
+ if (tui_rl_outstream == 0)
+ {
+ fprintf_unfiltered (gdb_stderr, "Cannot redirect readline output");
+ exit (1);
+ }
+ setvbuf (tui_rl_outstream, (char*) NULL, _IOLBF, 0);
+
+#ifdef O_NONBLOCK
+ (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK);
+#else
+#ifdef O_NDELAY
+ (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY);
+#endif
+#endif
+ add_file_handler (tui_readline_pipe[0], tui_readline_output, 0);
+#else
+ tui_rl_outstream = stdout;
+#endif
+}
+
+/* Get a character from the command window. This is called from the readline
+ package. */
+int
+tui_getc (FILE *fp)
+{
+ int ch;
+ WINDOW *w;
+
+ w = TUI_CMD_WIN->generic.handle;
+
+#ifdef TUI_USE_PIPE_FOR_READLINE
+ /* Flush readline output. */
+ tui_readline_output (GDB_READABLE, 0);
+#endif
+
+ ch = wgetch (w);
+ ch = tui_handle_resize_during_io (ch);
+
+ /* The \n must be echoed because it will not be printed by readline. */
+ if (ch == '\n')
+ {
+ /* When hitting return with an empty input, gdb executes the last
+ command. If we emit a newline, this fills up the command window
+ with empty lines with gdb prompt at beginning. Instead of that,
+ stay on the same line but provide a visual effect to show the
+ user we recognized the command. */
+ if (rl_end == 0)
+ {
+ wmove (w, TUI_CMD_WIN->detail.command_info.cur_line, 0);
+
+ /* Clear the line. This will blink the gdb prompt since
+ it will be redrawn at the same line. */
+ wclrtoeol (w);
+ wrefresh (w);
+ napms (20);
+ }
+ else
+ {
+ wmove (w, TUI_CMD_WIN->detail.command_info.cur_line,
+ TUI_CMD_WIN->detail.command_info.curch);
+ waddch (w, ch);
+ }
+ }
+
+ if (key_is_command_char (ch))
+ { /* Handle prev/next/up/down here */
+ ch = tui_dispatch_ctrl_char (ch);
+ }
+
+ if (ch == '\n' || ch == '\r' || ch == '\f')
+ TUI_CMD_WIN->detail.command_info.curch = 0;
+ if (ch == KEY_BACKSPACE)
+ return '\b';
+
+ return ch;
+}
+
+
+/* Cleanup when a resize has occured.
+ Returns the character that must be processed. */
+static unsigned int
+tui_handle_resize_during_io (unsigned int original_ch)
+{
+ if (tui_win_resized ())
+ {
+ tui_refresh_all_win ();
+ dont_repeat ();
+ tui_set_win_resized_to (FALSE);
+ return '\n';
+ }
+ else
+ return original_ch;
+}
diff --git a/contrib/gdb/gdb/tui/tui-io.h b/contrib/gdb/gdb/tui/tui-io.h
new file mode 100644
index 0000000..06d085d
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-io.h
@@ -0,0 +1,55 @@
+/* TUI support I/O functions.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_IO_H
+#define TUI_IO_H
+
+struct ui_out;
+
+/* Print the string in the curses command window. */
+extern void tui_puts (const char *);
+
+/* Setup the IO for curses or non-curses mode. */
+extern void tui_setup_io (int mode);
+
+/* Initialize the IO for gdb in curses mode. */
+extern void tui_initialize_io (void);
+
+/* Get a character from the command window. */
+extern int tui_getc (FILE *);
+
+/* Readline callback.
+ Redisplay the command line with its prompt after readline has
+ changed the edited text. */
+extern void tui_redisplay_readline (void);
+
+extern struct ui_out *tui_out;
+extern struct ui_out *tui_old_uiout;
+
+extern int key_is_start_sequence (int ch);
+extern int key_is_end_sequence (int ch);
+extern int key_is_backspace (int ch);
+extern int key_is_command_char (int ch);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-layout.c b/contrib/gdb/gdb/tui/tui-layout.c
new file mode 100644
index 0000000..f2d4412
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-layout.c
@@ -0,0 +1,1072 @@
+/* TUI layout window management.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "command.h"
+#include "symtab.h"
+#include "frame.h"
+#include "source.h"
+#include <ctype.h>
+
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-windata.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-regs.h"
+#include "tui/tui-win.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-disasm.h"
+
+#include "gdb_string.h"
+#include "gdb_curses.h"
+
+/*******************************
+** Static Local Decls
+********************************/
+static void show_layout (enum tui_layout_type);
+static void init_gen_win_info (struct tui_gen_win_info *, enum tui_win_type, int, int, int, int);
+static void init_and_make_win (void **, enum tui_win_type, int, int, int, int, int);
+static void show_source_or_disasm_and_command (enum tui_layout_type);
+static void make_source_or_disasm_window (struct tui_win_info * *, enum tui_win_type, int, int);
+static void make_command_window (struct tui_win_info * *, int, int);
+static void make_source_window (struct tui_win_info * *, int, int);
+static void make_disasm_window (struct tui_win_info * *, int, int);
+static void make_data_window (struct tui_win_info * *, int, int);
+static void show_source_command (void);
+static void show_disasm_command (void);
+static void show_source_disasm_command (void);
+static void show_data (enum tui_layout_type);
+static enum tui_layout_type next_layout (void);
+static enum tui_layout_type prev_layout (void);
+static void tui_layout_command (char *, int);
+static void tui_toggle_layout_command (char *, int);
+static void tui_toggle_split_layout_command (char *, int);
+static CORE_ADDR extract_display_start_addr (void);
+static void tui_handle_xdb_layout (struct tui_layout_def *);
+
+
+/***************************************
+** DEFINITIONS
+***************************************/
+
+#define LAYOUT_USAGE "Usage: layout prev | next | <layout_name> \n"
+
+/* Show the screen layout defined. */
+static void
+show_layout (enum tui_layout_type layout)
+{
+ enum tui_layout_type cur_layout = tui_current_layout ();
+
+ if (layout != cur_layout)
+ {
+ /*
+ ** Since the new layout may cause changes in window size, we
+ ** should free the content and reallocate on next display of
+ ** source/asm
+ */
+ tui_free_all_source_wins_content ();
+ tui_clear_source_windows ();
+ if (layout == SRC_DATA_COMMAND || layout == DISASSEM_DATA_COMMAND)
+ {
+ show_data (layout);
+ tui_refresh_all (tui_win_list);
+ }
+ else
+ {
+ /* First make the current layout be invisible */
+ tui_make_all_invisible ();
+ tui_make_invisible (tui_locator_win_info_ptr ());
+
+ switch (layout)
+ {
+ /* Now show the new layout */
+ case SRC_COMMAND:
+ show_source_command ();
+ tui_add_to_source_windows (TUI_SRC_WIN);
+ break;
+ case DISASSEM_COMMAND:
+ show_disasm_command ();
+ tui_add_to_source_windows (TUI_DISASM_WIN);
+ break;
+ case SRC_DISASSEM_COMMAND:
+ show_source_disasm_command ();
+ tui_add_to_source_windows (TUI_SRC_WIN);
+ tui_add_to_source_windows (TUI_DISASM_WIN);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+/* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
+ SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND.
+ If the layout is SRC_DATA_COMMAND, DISASSEM_DATA_COMMAND, or
+ UNDEFINED_LAYOUT, then the data window is populated according to
+ regs_display_type. */
+enum tui_status
+tui_set_layout (enum tui_layout_type layout_type,
+ enum tui_register_display_type regs_display_type)
+{
+ enum tui_status status = TUI_SUCCESS;
+
+ if (layout_type != UNDEFINED_LAYOUT || regs_display_type != TUI_UNDEFINED_REGS)
+ {
+ enum tui_layout_type cur_layout = tui_current_layout (), new_layout = UNDEFINED_LAYOUT;
+ int regs_populate = FALSE;
+ CORE_ADDR addr = extract_display_start_addr ();
+ struct tui_win_info * new_win_with_focus = (struct tui_win_info *) NULL;
+ struct tui_win_info * win_with_focus = tui_win_with_focus ();
+ struct tui_layout_def * layout_def = tui_layout_def ();
+
+
+ if (layout_type == UNDEFINED_LAYOUT &&
+ regs_display_type != TUI_UNDEFINED_REGS)
+ {
+ if (cur_layout == SRC_DISASSEM_COMMAND)
+ new_layout = DISASSEM_DATA_COMMAND;
+ else if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND)
+ new_layout = SRC_DATA_COMMAND;
+ else if (cur_layout == DISASSEM_COMMAND ||
+ cur_layout == DISASSEM_DATA_COMMAND)
+ new_layout = DISASSEM_DATA_COMMAND;
+ }
+ else
+ new_layout = layout_type;
+
+ regs_populate = (new_layout == SRC_DATA_COMMAND ||
+ new_layout == DISASSEM_DATA_COMMAND ||
+ regs_display_type != TUI_UNDEFINED_REGS);
+ if (new_layout != cur_layout || regs_display_type != TUI_UNDEFINED_REGS)
+ {
+ if (new_layout != cur_layout)
+ {
+ show_layout (new_layout);
+ /*
+ ** Now determine where focus should be
+ */
+ if (win_with_focus != TUI_CMD_WIN)
+ {
+ switch (new_layout)
+ {
+ case SRC_COMMAND:
+ tui_set_win_focus_to (TUI_SRC_WIN);
+ layout_def->display_mode = SRC_WIN;
+ layout_def->split = FALSE;
+ break;
+ case DISASSEM_COMMAND:
+ /* the previous layout was not showing
+ ** code. this can happen if there is no
+ ** source available:
+ ** 1. if the source file is in another dir OR
+ ** 2. if target was compiled without -g
+ ** We still want to show the assembly though!
+ */
+ addr = tui_get_begin_asm_address ();
+ tui_set_win_focus_to (TUI_DISASM_WIN);
+ layout_def->display_mode = DISASSEM_WIN;
+ layout_def->split = FALSE;
+ break;
+ case SRC_DISASSEM_COMMAND:
+ /* the previous layout was not showing
+ ** code. this can happen if there is no
+ ** source available:
+ ** 1. if the source file is in another dir OR
+ ** 2. if target was compiled without -g
+ ** We still want to show the assembly though!
+ */
+ addr = tui_get_begin_asm_address ();
+ if (win_with_focus == TUI_SRC_WIN)
+ tui_set_win_focus_to (TUI_SRC_WIN);
+ else
+ tui_set_win_focus_to (TUI_DISASM_WIN);
+ layout_def->split = TRUE;
+ break;
+ case SRC_DATA_COMMAND:
+ if (win_with_focus != TUI_DATA_WIN)
+ tui_set_win_focus_to (TUI_SRC_WIN);
+ else
+ tui_set_win_focus_to (TUI_DATA_WIN);
+ layout_def->display_mode = SRC_WIN;
+ layout_def->split = FALSE;
+ break;
+ case DISASSEM_DATA_COMMAND:
+ /* the previous layout was not showing
+ ** code. this can happen if there is no
+ ** source available:
+ ** 1. if the source file is in another dir OR
+ ** 2. if target was compiled without -g
+ ** We still want to show the assembly though!
+ */
+ addr = tui_get_begin_asm_address ();
+ if (win_with_focus != TUI_DATA_WIN)
+ tui_set_win_focus_to (TUI_DISASM_WIN);
+ else
+ tui_set_win_focus_to (TUI_DATA_WIN);
+ layout_def->display_mode = DISASSEM_WIN;
+ layout_def->split = FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+ if (new_win_with_focus != (struct tui_win_info *) NULL)
+ tui_set_win_focus_to (new_win_with_focus);
+ /*
+ ** Now update the window content
+ */
+ if (!regs_populate &&
+ (new_layout == SRC_DATA_COMMAND ||
+ new_layout == DISASSEM_DATA_COMMAND))
+ tui_display_all_data ();
+
+ tui_update_source_windows_with_addr (addr);
+ }
+ if (regs_populate)
+ {
+ tui_show_registers (TUI_DATA_WIN->detail.data_display_info.current_group);
+ }
+ }
+ }
+ else
+ status = TUI_FAILURE;
+
+ return status;
+}
+
+/* Add the specified window to the layout in a logical way. This
+ means setting up the most logical layout given the window to be
+ added. */
+void
+tui_add_win_to_layout (enum tui_win_type type)
+{
+ enum tui_layout_type cur_layout = tui_current_layout ();
+
+ switch (type)
+ {
+ case SRC_WIN:
+ if (cur_layout != SRC_COMMAND &&
+ cur_layout != SRC_DISASSEM_COMMAND &&
+ cur_layout != SRC_DATA_COMMAND)
+ {
+ tui_clear_source_windows_detail ();
+ if (cur_layout == DISASSEM_DATA_COMMAND)
+ show_layout (SRC_DATA_COMMAND);
+ else
+ show_layout (SRC_COMMAND);
+ }
+ break;
+ case DISASSEM_WIN:
+ if (cur_layout != DISASSEM_COMMAND &&
+ cur_layout != SRC_DISASSEM_COMMAND &&
+ cur_layout != DISASSEM_DATA_COMMAND)
+ {
+ tui_clear_source_windows_detail ();
+ if (cur_layout == SRC_DATA_COMMAND)
+ show_layout (DISASSEM_DATA_COMMAND);
+ else
+ show_layout (DISASSEM_COMMAND);
+ }
+ break;
+ case DATA_WIN:
+ if (cur_layout != SRC_DATA_COMMAND &&
+ cur_layout != DISASSEM_DATA_COMMAND)
+ {
+ if (cur_layout == DISASSEM_COMMAND)
+ show_layout (DISASSEM_DATA_COMMAND);
+ else
+ show_layout (SRC_DATA_COMMAND);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* Answer the height of a window. If it hasn't been created yet,
+ answer what the height of a window would be based upon its type and
+ the layout. */
+int
+tui_default_win_height (enum tui_win_type type, enum tui_layout_type layout)
+{
+ int h;
+
+ if (tui_win_list[type] != (struct tui_win_info *) NULL)
+ h = tui_win_list[type]->generic.height;
+ else
+ {
+ switch (layout)
+ {
+ case SRC_COMMAND:
+ case DISASSEM_COMMAND:
+ if (TUI_CMD_WIN == NULL)
+ h = tui_term_height () / 2;
+ else
+ h = tui_term_height () - TUI_CMD_WIN->generic.height;
+ break;
+ case SRC_DISASSEM_COMMAND:
+ case SRC_DATA_COMMAND:
+ case DISASSEM_DATA_COMMAND:
+ if (TUI_CMD_WIN == NULL)
+ h = tui_term_height () / 3;
+ else
+ h = (tui_term_height () - TUI_CMD_WIN->generic.height) / 2;
+ break;
+ default:
+ h = 0;
+ break;
+ }
+ }
+
+ return h;
+}
+
+
+/* Answer the height of a window. If it hasn't been created yet,
+ answer what the height of a window would be based upon its type and
+ the layout. */
+int
+tui_default_win_viewport_height (enum tui_win_type type,
+ enum tui_layout_type layout)
+{
+ int h;
+
+ h = tui_default_win_height (type, layout);
+
+ if (tui_win_list[type] == TUI_CMD_WIN)
+ h -= 1;
+ else
+ h -= 2;
+
+ return h;
+}
+
+
+/* Function to initialize gdb commands, for tui window layout
+ manipulation. */
+void
+_initialize_tui_layout (void)
+{
+ add_com ("layout", class_tui, tui_layout_command,
+ "Change the layout of windows.\n\
+Usage: layout prev | next | <layout_name> \n\
+Layout names are:\n\
+ src : Displays source and command windows.\n\
+ asm : Displays disassembly and command windows.\n\
+ split : Displays source, disassembly and command windows.\n\
+ regs : Displays register window. If existing layout\n\
+ is source/command or assembly/command, the \n\
+ register window is displayed. If the\n\
+ source/assembly/command (split) is displayed, \n\
+ the register window is displayed with \n\
+ the window that has current logical focus.\n");
+ if (xdb_commands)
+ {
+ add_com ("td", class_tui, tui_toggle_layout_command,
+ "Toggle between Source/Command and Disassembly/Command layouts.\n");
+ add_com ("ts", class_tui, tui_toggle_split_layout_command,
+ "Toggle between Source/Command or Disassembly/Command and \n\
+Source/Disassembly/Command layouts.\n");
+ }
+}
+
+
+/*************************
+** STATIC LOCAL FUNCTIONS
+**************************/
+
+
+/* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA,
+ REGS, $REGS, $GREGS, $FREGS, $SREGS. */
+enum tui_status
+tui_set_layout_for_display_command (const char *layout_name)
+{
+ enum tui_status status = TUI_SUCCESS;
+
+ if (layout_name != (char *) NULL)
+ {
+ int i;
+ char *buf_ptr;
+ enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
+ enum tui_register_display_type dpy_type = TUI_UNDEFINED_REGS;
+ enum tui_layout_type cur_layout = tui_current_layout ();
+
+ buf_ptr = (char *) xstrdup (layout_name);
+ for (i = 0; (i < strlen (layout_name)); i++)
+ buf_ptr[i] = toupper (buf_ptr[i]);
+
+ /* First check for ambiguous input */
+ if (strlen (buf_ptr) <= 1 && (*buf_ptr == 'S' || *buf_ptr == '$'))
+ {
+ warning ("Ambiguous command input.\n");
+ status = TUI_FAILURE;
+ }
+ else
+ {
+ if (subset_compare (buf_ptr, "SRC"))
+ new_layout = SRC_COMMAND;
+ else if (subset_compare (buf_ptr, "ASM"))
+ new_layout = DISASSEM_COMMAND;
+ else if (subset_compare (buf_ptr, "SPLIT"))
+ new_layout = SRC_DISASSEM_COMMAND;
+ else if (subset_compare (buf_ptr, "REGS") ||
+ subset_compare (buf_ptr, TUI_GENERAL_SPECIAL_REGS_NAME) ||
+ subset_compare (buf_ptr, TUI_GENERAL_REGS_NAME) ||
+ subset_compare (buf_ptr, TUI_FLOAT_REGS_NAME) ||
+ subset_compare (buf_ptr, TUI_SPECIAL_REGS_NAME))
+ {
+ if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND)
+ new_layout = SRC_DATA_COMMAND;
+ else
+ new_layout = DISASSEM_DATA_COMMAND;
+
+/* could ifdef out the following code. when compile with -z, there are null
+ pointer references that cause a core dump if 'layout regs' is the first
+ layout command issued by the user. HP has asked us to hook up this code
+ - edie epstein
+ */
+ if (subset_compare (buf_ptr, TUI_FLOAT_REGS_NAME))
+ {
+ if (TUI_DATA_WIN->detail.data_display_info.regs_display_type !=
+ TUI_SFLOAT_REGS &&
+ TUI_DATA_WIN->detail.data_display_info.regs_display_type !=
+ TUI_DFLOAT_REGS)
+ dpy_type = TUI_SFLOAT_REGS;
+ else
+ dpy_type =
+ TUI_DATA_WIN->detail.data_display_info.regs_display_type;
+ }
+ else if (subset_compare (buf_ptr,
+ TUI_GENERAL_SPECIAL_REGS_NAME))
+ dpy_type = TUI_GENERAL_AND_SPECIAL_REGS;
+ else if (subset_compare (buf_ptr, TUI_GENERAL_REGS_NAME))
+ dpy_type = TUI_GENERAL_REGS;
+ else if (subset_compare (buf_ptr, TUI_SPECIAL_REGS_NAME))
+ dpy_type = TUI_SPECIAL_REGS;
+ else if (TUI_DATA_WIN)
+ {
+ if (TUI_DATA_WIN->detail.data_display_info.regs_display_type !=
+ TUI_UNDEFINED_REGS)
+ dpy_type =
+ TUI_DATA_WIN->detail.data_display_info.regs_display_type;
+ else
+ dpy_type = TUI_GENERAL_REGS;
+ }
+
+/* end of potential ifdef
+ */
+
+/* if ifdefed out code above, then assume that the user wishes to display the
+ general purpose registers
+ */
+
+/* dpy_type = TUI_GENERAL_REGS;
+ */
+ }
+ else if (subset_compare (buf_ptr, "NEXT"))
+ new_layout = next_layout ();
+ else if (subset_compare (buf_ptr, "PREV"))
+ new_layout = prev_layout ();
+ else
+ status = TUI_FAILURE;
+ xfree (buf_ptr);
+
+ tui_set_layout (new_layout, dpy_type);
+ }
+ }
+ else
+ status = TUI_FAILURE;
+
+ return status;
+}
+
+
+static CORE_ADDR
+extract_display_start_addr (void)
+{
+ enum tui_layout_type cur_layout = tui_current_layout ();
+ CORE_ADDR addr;
+ CORE_ADDR pc;
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+ switch (cur_layout)
+ {
+ case SRC_COMMAND:
+ case SRC_DATA_COMMAND:
+ find_line_pc (cursal.symtab,
+ TUI_SRC_WIN->detail.source_info.start_line_or_addr.line_no,
+ &pc);
+ addr = pc;
+ break;
+ case DISASSEM_COMMAND:
+ case SRC_DISASSEM_COMMAND:
+ case DISASSEM_DATA_COMMAND:
+ addr = TUI_DISASM_WIN->detail.source_info.start_line_or_addr.addr;
+ break;
+ default:
+ addr = 0;
+ break;
+ }
+
+ return addr;
+}
+
+
+static void
+tui_handle_xdb_layout (struct tui_layout_def * layout_def)
+{
+ if (layout_def->split)
+ {
+ tui_set_layout (SRC_DISASSEM_COMMAND, TUI_UNDEFINED_REGS);
+ tui_set_win_focus_to (tui_win_list[layout_def->display_mode]);
+ }
+ else
+ {
+ if (layout_def->display_mode == SRC_WIN)
+ tui_set_layout (SRC_COMMAND, TUI_UNDEFINED_REGS);
+ else
+ tui_set_layout (DISASSEM_DATA_COMMAND, layout_def->regs_display_type);
+ }
+}
+
+
+static void
+tui_toggle_layout_command (char *arg, int from_tty)
+{
+ struct tui_layout_def * layout_def = tui_layout_def ();
+
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ if (layout_def->display_mode == SRC_WIN)
+ layout_def->display_mode = DISASSEM_WIN;
+ else
+ layout_def->display_mode = SRC_WIN;
+
+ if (!layout_def->split)
+ tui_handle_xdb_layout (layout_def);
+}
+
+
+static void
+tui_toggle_split_layout_command (char *arg, int from_tty)
+{
+ struct tui_layout_def * layout_def = tui_layout_def ();
+
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ layout_def->split = (!layout_def->split);
+ tui_handle_xdb_layout (layout_def);
+}
+
+
+static void
+tui_layout_command (char *arg, int from_tty)
+{
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+
+ /* Switch to the selected layout. */
+ if (tui_set_layout_for_display_command (arg) != TUI_SUCCESS)
+ warning ("Invalid layout specified.\n%s", LAYOUT_USAGE);
+
+}
+
+/* Answer the previous layout to cycle to. */
+static enum tui_layout_type
+next_layout (void)
+{
+ enum tui_layout_type new_layout;
+
+ new_layout = tui_current_layout ();
+ if (new_layout == UNDEFINED_LAYOUT)
+ new_layout = SRC_COMMAND;
+ else
+ {
+ new_layout++;
+ if (new_layout == UNDEFINED_LAYOUT)
+ new_layout = SRC_COMMAND;
+ }
+
+ return new_layout;
+}
+
+
+/* Answer the next layout to cycle to. */
+static enum tui_layout_type
+prev_layout (void)
+{
+ enum tui_layout_type new_layout;
+
+ new_layout = tui_current_layout ();
+ if (new_layout == SRC_COMMAND)
+ new_layout = DISASSEM_DATA_COMMAND;
+ else
+ {
+ new_layout--;
+ if (new_layout == UNDEFINED_LAYOUT)
+ new_layout = DISASSEM_DATA_COMMAND;
+ }
+
+ return new_layout;
+}
+
+
+
+static void
+make_command_window (struct tui_win_info * * win_info_ptr, int height, int origin_y)
+{
+ init_and_make_win ((void **) win_info_ptr,
+ CMD_WIN,
+ height,
+ tui_term_width (),
+ 0,
+ origin_y,
+ DONT_BOX_WINDOW);
+
+ (*win_info_ptr)->can_highlight = FALSE;
+}
+
+
+/*
+ ** make_source_window().
+ */
+static void
+make_source_window (struct tui_win_info * * win_info_ptr, int height, int origin_y)
+{
+ make_source_or_disasm_window (win_info_ptr, SRC_WIN, height, origin_y);
+
+ return;
+} /* make_source_window */
+
+
+/*
+ ** make_disasm_window().
+ */
+static void
+make_disasm_window (struct tui_win_info * * win_info_ptr, int height, int origin_y)
+{
+ make_source_or_disasm_window (win_info_ptr, DISASSEM_WIN, height, origin_y);
+
+ return;
+} /* make_disasm_window */
+
+
+static void
+make_data_window (struct tui_win_info * * win_info_ptr, int height, int origin_y)
+{
+ init_and_make_win ((void **) win_info_ptr,
+ DATA_WIN,
+ height,
+ tui_term_width (),
+ 0,
+ origin_y,
+ BOX_WINDOW);
+}
+
+
+
+/* Show the Source/Command layout. */
+static void
+show_source_command (void)
+{
+ show_source_or_disasm_and_command (SRC_COMMAND);
+}
+
+
+/* Show the Dissassem/Command layout. */
+static void
+show_disasm_command (void)
+{
+ show_source_or_disasm_and_command (DISASSEM_COMMAND);
+}
+
+
+/* Show the Source/Disassem/Command layout. */
+static void
+show_source_disasm_command (void)
+{
+ if (tui_current_layout () != SRC_DISASSEM_COMMAND)
+ {
+ int cmd_height, src_height, asm_height;
+
+ if (TUI_CMD_WIN != NULL)
+ cmd_height = TUI_CMD_WIN->generic.height;
+ else
+ cmd_height = tui_term_height () / 3;
+
+ src_height = (tui_term_height () - cmd_height) / 2;
+ asm_height = tui_term_height () - (src_height + cmd_height);
+
+ if (TUI_SRC_WIN == NULL)
+ make_source_window (&TUI_SRC_WIN, src_height, 0);
+ else
+ {
+ init_gen_win_info (&TUI_SRC_WIN->generic,
+ TUI_SRC_WIN->generic.type,
+ src_height,
+ TUI_SRC_WIN->generic.width,
+ TUI_SRC_WIN->detail.source_info.execution_info->width,
+ 0);
+ TUI_SRC_WIN->can_highlight = TRUE;
+ init_gen_win_info (TUI_SRC_WIN->detail.source_info.execution_info,
+ EXEC_INFO_WIN,
+ src_height,
+ 3,
+ 0,
+ 0);
+ tui_make_visible (&TUI_SRC_WIN->generic);
+ tui_make_visible (TUI_SRC_WIN->detail.source_info.execution_info);
+ TUI_SRC_WIN->detail.source_info.has_locator = FALSE;;
+ }
+ if (TUI_SRC_WIN != NULL)
+ {
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+
+ tui_show_source_content (TUI_SRC_WIN);
+ if (TUI_DISASM_WIN == NULL)
+ {
+ make_disasm_window (&TUI_DISASM_WIN, asm_height, src_height - 1);
+ init_and_make_win ((void **) & locator,
+ LOCATOR_WIN,
+ 2 /* 1 */ ,
+ tui_term_width (),
+ 0,
+ (src_height + asm_height) - 1,
+ DONT_BOX_WINDOW);
+ }
+ else
+ {
+ init_gen_win_info (locator,
+ LOCATOR_WIN,
+ 2 /* 1 */ ,
+ tui_term_width (),
+ 0,
+ (src_height + asm_height) - 1);
+ TUI_DISASM_WIN->detail.source_info.has_locator = TRUE;
+ init_gen_win_info (
+ &TUI_DISASM_WIN->generic,
+ TUI_DISASM_WIN->generic.type,
+ asm_height,
+ TUI_DISASM_WIN->generic.width,
+ TUI_DISASM_WIN->detail.source_info.execution_info->width,
+ src_height - 1);
+ init_gen_win_info (TUI_DISASM_WIN->detail.source_info.execution_info,
+ EXEC_INFO_WIN,
+ asm_height,
+ 3,
+ 0,
+ src_height - 1);
+ TUI_DISASM_WIN->can_highlight = TRUE;
+ tui_make_visible (&TUI_DISASM_WIN->generic);
+ tui_make_visible (TUI_DISASM_WIN->detail.source_info.execution_info);
+ }
+ if (TUI_DISASM_WIN != NULL)
+ {
+ TUI_SRC_WIN->detail.source_info.has_locator = FALSE;
+ TUI_DISASM_WIN->detail.source_info.has_locator = TRUE;
+ tui_make_visible (locator);
+ tui_show_locator_content ();
+ tui_show_source_content (TUI_DISASM_WIN);
+
+ if (TUI_CMD_WIN == NULL)
+ make_command_window (&TUI_CMD_WIN,
+ cmd_height,
+ tui_term_height () - cmd_height);
+ else
+ {
+ init_gen_win_info (&TUI_CMD_WIN->generic,
+ TUI_CMD_WIN->generic.type,
+ TUI_CMD_WIN->generic.height,
+ TUI_CMD_WIN->generic.width,
+ 0,
+ TUI_CMD_WIN->generic.origin.y);
+ TUI_CMD_WIN->can_highlight = FALSE;
+ tui_make_visible (&TUI_CMD_WIN->generic);
+ }
+ if (TUI_CMD_WIN != NULL)
+ tui_refresh_win (&TUI_CMD_WIN->generic);
+ }
+ }
+ tui_set_current_layout_to (SRC_DISASSEM_COMMAND);
+ }
+}
+
+
+/* Show the Source/Data/Command or the Dissassembly/Data/Command
+ layout. */
+static void
+show_data (enum tui_layout_type new_layout)
+{
+ int total_height = (tui_term_height () - TUI_CMD_WIN->generic.height);
+ int src_height, data_height;
+ enum tui_win_type win_type;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+
+
+ data_height = total_height / 2;
+ src_height = total_height - data_height;
+ tui_make_all_invisible ();
+ tui_make_invisible (locator);
+ make_data_window (&TUI_DATA_WIN, data_height, 0);
+ TUI_DATA_WIN->can_highlight = TRUE;
+ if (new_layout == SRC_DATA_COMMAND)
+ win_type = SRC_WIN;
+ else
+ win_type = DISASSEM_WIN;
+ if (tui_win_list[win_type] == NULL)
+ {
+ if (win_type == SRC_WIN)
+ make_source_window (&tui_win_list[win_type], src_height, data_height - 1);
+ else
+ make_disasm_window (&tui_win_list[win_type], src_height, data_height - 1);
+ init_and_make_win ((void **) & locator,
+ LOCATOR_WIN,
+ 2 /* 1 */ ,
+ tui_term_width (),
+ 0,
+ total_height - 1,
+ DONT_BOX_WINDOW);
+ }
+ else
+ {
+ init_gen_win_info (&tui_win_list[win_type]->generic,
+ tui_win_list[win_type]->generic.type,
+ src_height,
+ tui_win_list[win_type]->generic.width,
+ tui_win_list[win_type]->detail.source_info.execution_info->width,
+ data_height - 1);
+ init_gen_win_info (tui_win_list[win_type]->detail.source_info.execution_info,
+ EXEC_INFO_WIN,
+ src_height,
+ 3,
+ 0,
+ data_height - 1);
+ tui_make_visible (&tui_win_list[win_type]->generic);
+ tui_make_visible (tui_win_list[win_type]->detail.source_info.execution_info);
+ init_gen_win_info (locator,
+ LOCATOR_WIN,
+ 2 /* 1 */ ,
+ tui_term_width (),
+ 0,
+ total_height - 1);
+ }
+ tui_win_list[win_type]->detail.source_info.has_locator = TRUE;
+ tui_make_visible (locator);
+ tui_show_locator_content ();
+ tui_add_to_source_windows (tui_win_list[win_type]);
+ tui_set_current_layout_to (new_layout);
+}
+
+/*
+ ** init_gen_win_info().
+ */
+static void
+init_gen_win_info (struct tui_gen_win_info * win_info, enum tui_win_type type,
+ int height, int width, int origin_x, int origin_y)
+{
+ int h = height;
+
+ win_info->type = type;
+ win_info->width = width;
+ win_info->height = h;
+ if (h > 1)
+ {
+ win_info->viewport_height = h - 1;
+ if (win_info->type != CMD_WIN)
+ win_info->viewport_height--;
+ }
+ else
+ win_info->viewport_height = 1;
+ win_info->origin.x = origin_x;
+ win_info->origin.y = origin_y;
+
+ return;
+} /* init_gen_win_info */
+
+/*
+ ** init_and_make_win().
+ */
+static void
+init_and_make_win (void ** win_info_ptr, enum tui_win_type win_type,
+ int height, int width, int origin_x, int origin_y, int box_it)
+{
+ void *opaque_win_info = *win_info_ptr;
+ struct tui_gen_win_info * generic;
+
+ if (opaque_win_info == NULL)
+ {
+ if (tui_win_is_auxillary (win_type))
+ opaque_win_info = (void *) tui_alloc_generic_win_info ();
+ else
+ opaque_win_info = (void *) tui_alloc_win_info (win_type);
+ }
+ if (tui_win_is_auxillary (win_type))
+ generic = (struct tui_gen_win_info *) opaque_win_info;
+ else
+ generic = &((struct tui_win_info *) opaque_win_info)->generic;
+
+ if (opaque_win_info != NULL)
+ {
+ init_gen_win_info (generic, win_type, height, width, origin_x, origin_y);
+ if (!tui_win_is_auxillary (win_type))
+ {
+ if (generic->type == CMD_WIN)
+ ((struct tui_win_info *) opaque_win_info)->can_highlight = FALSE;
+ else
+ ((struct tui_win_info *) opaque_win_info)->can_highlight = TRUE;
+ }
+ tui_make_window (generic, box_it);
+ }
+ *win_info_ptr = opaque_win_info;
+}
+
+
+static void
+make_source_or_disasm_window (struct tui_win_info * * win_info_ptr, enum tui_win_type type,
+ int height, int origin_y)
+{
+ struct tui_gen_win_info * execution_info = (struct tui_gen_win_info *) NULL;
+
+ /*
+ ** Create the exeuction info window.
+ */
+ if (type == SRC_WIN)
+ execution_info = tui_source_exec_info_win_ptr ();
+ else
+ execution_info = tui_disassem_exec_info_win_ptr ();
+ init_and_make_win ((void **) & execution_info,
+ EXEC_INFO_WIN,
+ height,
+ 3,
+ 0,
+ origin_y,
+ DONT_BOX_WINDOW);
+ /*
+ ** Now create the source window.
+ */
+ init_and_make_win ((void **) win_info_ptr,
+ type,
+ height,
+ tui_term_width () - execution_info->width,
+ execution_info->width,
+ origin_y,
+ BOX_WINDOW);
+
+ (*win_info_ptr)->detail.source_info.execution_info = execution_info;
+}
+
+
+/* Show the Source/Command or the Disassem layout. */
+static void
+show_source_or_disasm_and_command (enum tui_layout_type layout_type)
+{
+ if (tui_current_layout () != layout_type)
+ {
+ struct tui_win_info * *win_info_ptr;
+ int src_height, cmd_height;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+
+ if (TUI_CMD_WIN != NULL)
+ cmd_height = TUI_CMD_WIN->generic.height;
+ else
+ cmd_height = tui_term_height () / 3;
+ src_height = tui_term_height () - cmd_height;
+
+
+ if (layout_type == SRC_COMMAND)
+ win_info_ptr = &TUI_SRC_WIN;
+ else
+ win_info_ptr = &TUI_DISASM_WIN;
+
+ if ((*win_info_ptr) == NULL)
+ {
+ if (layout_type == SRC_COMMAND)
+ make_source_window (win_info_ptr, src_height - 1, 0);
+ else
+ make_disasm_window (win_info_ptr, src_height - 1, 0);
+ init_and_make_win ((void **) & locator,
+ LOCATOR_WIN,
+ 2 /* 1 */ ,
+ tui_term_width (),
+ 0,
+ src_height - 1,
+ DONT_BOX_WINDOW);
+ }
+ else
+ {
+ init_gen_win_info (locator,
+ LOCATOR_WIN,
+ 2 /* 1 */ ,
+ tui_term_width (),
+ 0,
+ src_height - 1);
+ (*win_info_ptr)->detail.source_info.has_locator = TRUE;
+ init_gen_win_info (
+ &(*win_info_ptr)->generic,
+ (*win_info_ptr)->generic.type,
+ src_height - 1,
+ (*win_info_ptr)->generic.width,
+ (*win_info_ptr)->detail.source_info.execution_info->width,
+ 0);
+ init_gen_win_info ((*win_info_ptr)->detail.source_info.execution_info,
+ EXEC_INFO_WIN,
+ src_height - 1,
+ 3,
+ 0,
+ 0);
+ (*win_info_ptr)->can_highlight = TRUE;
+ tui_make_visible (&(*win_info_ptr)->generic);
+ tui_make_visible ((*win_info_ptr)->detail.source_info.execution_info);
+ }
+ if ((*win_info_ptr) != NULL)
+ {
+ (*win_info_ptr)->detail.source_info.has_locator = TRUE;
+ tui_make_visible (locator);
+ tui_show_locator_content ();
+ tui_show_source_content (*win_info_ptr);
+
+ if (TUI_CMD_WIN == NULL)
+ {
+ make_command_window (&TUI_CMD_WIN, cmd_height, src_height);
+ tui_refresh_win (&TUI_CMD_WIN->generic);
+ }
+ else
+ {
+ init_gen_win_info (&TUI_CMD_WIN->generic,
+ TUI_CMD_WIN->generic.type,
+ TUI_CMD_WIN->generic.height,
+ TUI_CMD_WIN->generic.width,
+ TUI_CMD_WIN->generic.origin.x,
+ TUI_CMD_WIN->generic.origin.y);
+ TUI_CMD_WIN->can_highlight = FALSE;
+ tui_make_visible (&TUI_CMD_WIN->generic);
+ }
+ }
+ tui_set_current_layout_to (layout_type);
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-layout.h b/contrib/gdb/gdb/tui/tui-layout.h
new file mode 100644
index 0000000..5df1f0b
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-layout.h
@@ -0,0 +1,38 @@
+/* TUI layout window management.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_LAYOUT_H
+#define TUI_LAYOUT_H
+
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+
+extern void tui_add_win_to_layout (enum tui_win_type);
+extern int tui_default_win_height (enum tui_win_type, enum tui_layout_type);
+extern int tui_default_win_viewport_height (enum tui_win_type,
+ enum tui_layout_type);
+extern enum tui_status tui_set_layout (enum tui_layout_type,
+ enum tui_register_display_type);
+
+#endif /*TUI_LAYOUT_H */
diff --git a/contrib/gdb/gdb/tui/tui-main.c b/contrib/gdb/gdb/tui/tui-main.c
new file mode 100644
index 0000000..920d838
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-main.c
@@ -0,0 +1,37 @@
+/* Main function for TUI gdb.
+
+ Copyright 2002, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "main.h"
+#include "gdb_string.h"
+#include "interps.h"
+
+int
+main (int argc, char **argv)
+{
+ struct captured_main_args args;
+ memset (&args, 0, sizeof args);
+ args.argc = argc;
+ args.argv = argv;
+ args.use_windows = 0;
+ args.interpreter_p = INTERP_TUI;
+ return gdb_main (&args);
+}
diff --git a/contrib/gdb/gdb/tui/tui-out.c b/contrib/gdb/gdb/tui/tui-out.c
new file mode 100644
index 0000000..1c2af68
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-out.c
@@ -0,0 +1,413 @@
+/* Output generating routines for GDB CLI.
+
+ Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
+ Inc.
+
+ Contributed by Cygnus Solutions.
+ Written by Fernando Nasser 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 "defs.h"
+#include "ui-out.h"
+#include "tui.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+
+struct ui_out_data
+ {
+ struct ui_file *stream;
+ int suppress_output;
+ int line;
+ int start_of_line;
+ };
+typedef struct ui_out_data tui_out_data;
+
+/* These are the CLI output functions */
+
+static void tui_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows, const char *tblid);
+static void tui_table_body (struct ui_out *uiout);
+static void tui_table_end (struct ui_out *uiout);
+static void tui_table_header (struct ui_out *uiout, int width,
+ enum ui_align alig, const char *col_name,
+ const char *colhdr);
+static void tui_begin (struct ui_out *uiout, enum ui_out_type type,
+ int level, const char *lstid);
+static void tui_end (struct ui_out *uiout, enum ui_out_type type, int level);
+static void tui_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname, int value);
+static void tui_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname);
+static void tui_field_string (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, const char *fldname,
+ const char *string);
+static void tui_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ const char *fldname, const char *format,
+ va_list args);
+static void tui_spaces (struct ui_out *uiout, int numspaces);
+static void tui_text (struct ui_out *uiout, const char *string);
+static void tui_message (struct ui_out *uiout, int verbosity,
+ const char *format, va_list args);
+static void tui_wrap_hint (struct ui_out *uiout, char *identstring);
+static void tui_flush (struct ui_out *uiout);
+
+/* This is the CLI ui-out implementation functions vector */
+
+/* FIXME: This can be initialized dynamically after default is set to
+ handle initial output in main.c */
+
+static struct ui_out_impl tui_ui_out_impl =
+{
+ tui_table_begin,
+ tui_table_body,
+ tui_table_end,
+ tui_table_header,
+ tui_begin,
+ tui_end,
+ tui_field_int,
+ tui_field_skip,
+ tui_field_string,
+ tui_field_fmt,
+ tui_spaces,
+ tui_text,
+ tui_message,
+ tui_wrap_hint,
+ tui_flush,
+ NULL,
+ 0, /* Does not need MI hacks (i.e. needs CLI hacks). */
+};
+
+/* Prototypes for local functions */
+
+extern void _initialize_tui_out (void);
+
+static void field_separator (void);
+
+static void out_field_fmt (struct ui_out *uiout, int fldno,
+ const char *fldname,
+ const char *format,...);
+
+/* local variables */
+
+/* (none yet) */
+
+/* Mark beginning of a table */
+
+void
+tui_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows,
+ const char *tblid)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (nr_rows == 0)
+ data->suppress_output = 1;
+ else
+ /* Only the table suppresses the output and, fortunately, a table
+ is not a recursive data structure. */
+ gdb_assert (data->suppress_output == 0);
+}
+
+/* Mark beginning of a table body */
+
+void
+tui_table_body (struct ui_out *uiout)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ /* first, close the table header line */
+ tui_text (uiout, "\n");
+}
+
+/* Mark end of a table */
+
+void
+tui_table_end (struct ui_out *uiout)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ data->suppress_output = 0;
+}
+
+/* Specify table header */
+
+void
+tui_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
+ const char *col_name,
+ const char *colhdr)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ tui_field_string (uiout, 0, width, alignment, 0, colhdr);
+}
+
+/* Mark beginning of a list */
+
+void
+tui_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level,
+ const char *id)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+}
+
+/* Mark end of a list */
+
+void
+tui_end (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+}
+
+/* output an int field */
+
+void
+tui_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alignment,
+ const char *fldname, int value)
+{
+ char buffer[20]; /* FIXME: how many chars long a %d can become? */
+
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+
+ /* Don't print line number, keep it for later. */
+ if (data->start_of_line == 0 && strcmp (fldname, "line") == 0)
+ {
+ data->start_of_line ++;
+ data->line = value;
+ return;
+ }
+ data->start_of_line ++;
+ sprintf (buffer, "%d", value);
+ tui_field_string (uiout, fldno, width, alignment, fldname, buffer);
+}
+
+/* used to ommit a field */
+
+void
+tui_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alignment,
+ const char *fldname)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ tui_field_string (uiout, fldno, width, alignment, fldname, "");
+}
+
+/* other specific tui_field_* end up here so alignment and field
+ separators are both handled by tui_field_string */
+
+void
+tui_field_string (struct ui_out *uiout,
+ int fldno,
+ int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *string)
+{
+ int before = 0;
+ int after = 0;
+
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+
+ if (fldname && data->line > 0 && strcmp (fldname, "file") == 0)
+ {
+ data->start_of_line ++;
+ if (data->line > 0)
+ {
+ tui_show_source (string, data->line);
+ }
+ return;
+ }
+
+ data->start_of_line ++;
+ if ((align != ui_noalign) && string)
+ {
+ before = width - strlen (string);
+ if (before <= 0)
+ before = 0;
+ else
+ {
+ if (align == ui_right)
+ after = 0;
+ else if (align == ui_left)
+ {
+ after = before;
+ before = 0;
+ }
+ else
+ /* ui_center */
+ {
+ after = before / 2;
+ before -= after;
+ }
+ }
+ }
+
+ if (before)
+ ui_out_spaces (uiout, before);
+ if (string)
+ out_field_fmt (uiout, fldno, fldname, "%s", string);
+ if (after)
+ ui_out_spaces (uiout, after);
+
+ if (align != ui_noalign)
+ field_separator ();
+}
+
+/* This is the only field function that does not align */
+
+void
+tui_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ const char *fldname,
+ const char *format,
+ va_list args)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+
+ data->start_of_line ++;
+ vfprintf_filtered (data->stream, format, args);
+
+ if (align != ui_noalign)
+ field_separator ();
+}
+
+void
+tui_spaces (struct ui_out *uiout, int numspaces)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ print_spaces_filtered (numspaces, data->stream);
+}
+
+void
+tui_text (struct ui_out *uiout, const char *string)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ data->start_of_line ++;
+ if (data->line > 0)
+ {
+ if (strchr (string, '\n') != 0)
+ {
+ data->line = -1;
+ data->start_of_line = 0;
+ }
+ return;
+ }
+ if (strchr (string, '\n'))
+ data->start_of_line = 0;
+ fputs_filtered (string, data->stream);
+}
+
+void
+tui_message (struct ui_out *uiout, int verbosity,
+ const char *format, va_list args)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ if (ui_out_get_verblvl (uiout) >= verbosity)
+ vfprintf_unfiltered (data->stream, format, args);
+}
+
+void
+tui_wrap_hint (struct ui_out *uiout, char *identstring)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ if (data->suppress_output)
+ return;
+ wrap_here (identstring);
+}
+
+void
+tui_flush (struct ui_out *uiout)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ gdb_flush (data->stream);
+}
+
+/* local functions */
+
+/* Like tui_field_fmt, but takes a variable number of args
+ and makes a va_list and does not insert a separator */
+
+/* VARARGS */
+static void
+out_field_fmt (struct ui_out *uiout, int fldno,
+ const char *fldname,
+ const char *format,...)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ va_list args;
+
+ va_start (args, format);
+ vfprintf_filtered (data->stream, format, args);
+
+ va_end (args);
+}
+
+/* access to ui_out format private members */
+
+static void
+field_separator (void)
+{
+ tui_out_data *data = ui_out_data (uiout);
+ fputc_filtered (' ', data->stream);
+}
+
+/* initalize private members at startup */
+
+struct ui_out *
+tui_out_new (struct ui_file *stream)
+{
+ int flags = 0;
+
+ tui_out_data *data = XMALLOC (tui_out_data);
+ data->stream = stream;
+ data->suppress_output = 0;
+ data->line = -1;
+ data->start_of_line = 0;
+ return ui_out_new (&tui_ui_out_impl, data, flags);
+}
+
+/* standard gdb initialization hook */
+void
+_initialize_tui_out (void)
+{
+ /* nothing needs to be done */
+}
diff --git a/contrib/gdb/gdb/tui/tui-regs.c b/contrib/gdb/gdb/tui/tui-regs.c
new file mode 100644
index 0000000..abb92a4
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-regs.c
@@ -0,0 +1,754 @@
+/* TUI display registers in window.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "tui/tui.h"
+#include "tui/tui-data.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "frame.h"
+#include "regcache.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdb_string.h"
+#include "tui/tui-layout.h"
+#include "tui/tui-win.h"
+#include "tui/tui-windata.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-file.h"
+#include "reggroups.h"
+
+#include "gdb_curses.h"
+
+
+/*****************************************
+** STATIC LOCAL FUNCTIONS FORWARD DECLS **
+******************************************/
+static void
+tui_display_register (struct tui_data_element *data,
+ struct tui_gen_win_info *win_info);
+
+static enum tui_status
+tui_show_register_group (struct gdbarch *gdbarch, struct reggroup *group,
+ struct frame_info *frame, int refresh_values_only);
+
+static enum tui_status
+tui_get_register (struct gdbarch *gdbarch, struct frame_info *frame,
+ struct tui_data_element *data, int regnum, int *changedp);
+static void tui_register_format
+ (struct gdbarch *, struct frame_info *, struct tui_data_element*, int);
+static void tui_scroll_regs_forward_command (char *, int);
+static void tui_scroll_regs_backward_command (char *, int);
+
+
+
+/*****************************************
+** PUBLIC FUNCTIONS **
+******************************************/
+
+/* Answer the number of the last line in the regs display. If there
+ are no registers (-1) is returned. */
+int
+tui_last_regs_line_no (void)
+{
+ int num_lines = (-1);
+
+ if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
+ {
+ num_lines = (TUI_DATA_WIN->detail.data_display_info.regs_content_count /
+ TUI_DATA_WIN->detail.data_display_info.regs_column_count);
+ if (TUI_DATA_WIN->detail.data_display_info.regs_content_count %
+ TUI_DATA_WIN->detail.data_display_info.regs_column_count)
+ num_lines++;
+ }
+ return num_lines;
+}
+
+
+/* Answer the line number that the register element at element_no is
+ on. If element_no is greater than the number of register elements
+ there are, -1 is returned. */
+int
+tui_line_from_reg_element_no (int element_no)
+{
+ if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
+ {
+ int i, line = (-1);
+
+ i = 1;
+ while (line == (-1))
+ {
+ if (element_no <
+ (TUI_DATA_WIN->detail.data_display_info.regs_column_count * i))
+ line = i - 1;
+ else
+ i++;
+ }
+
+ return line;
+ }
+ else
+ return (-1);
+}
+
+
+/* Answer the index of the first element in line_no. If line_no is past
+ the register area (-1) is returned. */
+int
+tui_first_reg_element_no_inline (int line_no)
+{
+ if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count)
+ <= TUI_DATA_WIN->detail.data_display_info.regs_content_count)
+ return ((line_no + 1) *
+ TUI_DATA_WIN->detail.data_display_info.regs_column_count) -
+ TUI_DATA_WIN->detail.data_display_info.regs_column_count;
+ else
+ return (-1);
+}
+
+
+/* Answer the index of the last element in line_no. If line_no is
+ past the register area (-1) is returned. */
+int
+tui_last_reg_element_no_in_line (int line_no)
+{
+ if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count) <=
+ TUI_DATA_WIN->detail.data_display_info.regs_content_count)
+ return ((line_no + 1) *
+ TUI_DATA_WIN->detail.data_display_info.regs_column_count) - 1;
+ else
+ return (-1);
+}
+
+/* Show the registers of the given group in the data window
+ and refresh the window. */
+void
+tui_show_registers (struct reggroup *group)
+{
+ enum tui_status ret = TUI_FAILURE;
+ struct tui_data_info *display_info;
+
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+
+ /* Make sure the register window is visible. If not, select an
+ appropriate layout. */
+ if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->generic.is_visible)
+ tui_set_layout_for_display_command (DATA_NAME);
+
+ display_info = &TUI_DATA_WIN->detail.data_display_info;
+ if (group == 0)
+ group = general_reggroup;
+
+ /* Say that registers should be displayed, even if there is a problem. */
+ display_info->display_regs = TRUE;
+
+ if (target_has_registers && target_has_stack && target_has_memory)
+ {
+ ret = tui_show_register_group (current_gdbarch, group,
+ get_current_frame (),
+ group == display_info->current_group);
+ }
+ if (ret == TUI_FAILURE)
+ {
+ display_info->current_group = 0;
+ tui_erase_data_content (NO_REGS_STRING);
+ }
+ else
+ {
+ int i;
+
+ /* Clear all notation of changed values */
+ for (i = 0; i < display_info->regs_content_count; i++)
+ {
+ struct tui_gen_win_info *data_item_win;
+ struct tui_win_element *win;
+
+ data_item_win = &display_info->regs_content[i]
+ ->which_element.data_window;
+ win = (struct tui_win_element *) data_item_win->content[0];
+ win->which_element.data.highlight = FALSE;
+ }
+ display_info->current_group = group;
+ tui_display_all_data ();
+ }
+}
+
+
+/* Set the data window to display the registers of the register group
+ using the given frame. Values are refreshed only when refresh_values_only
+ is TRUE. */
+
+static enum tui_status
+tui_show_register_group (struct gdbarch *gdbarch, struct reggroup *group,
+ struct frame_info *frame, int refresh_values_only)
+{
+ enum tui_status ret = TUI_FAILURE;
+ int nr_regs;
+ int allocated_here = FALSE;
+ int regnum, pos;
+ char title[80];
+ struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
+
+ /* Make a new title showing which group we display. */
+ snprintf (title, sizeof (title) - 1, "Register group: %s",
+ reggroup_name (group));
+ xfree (TUI_DATA_WIN->generic.title);
+ TUI_DATA_WIN->generic.title = xstrdup (title);
+
+ /* See how many registers must be displayed. */
+ nr_regs = 0;
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ /* Must be in the group and have a name. */
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, group)
+ && gdbarch_register_name (gdbarch, regnum) != 0)
+ nr_regs++;
+ }
+
+ if (display_info->regs_content_count > 0 && !refresh_values_only)
+ {
+ tui_free_data_content (display_info->regs_content,
+ display_info->regs_content_count);
+ display_info->regs_content_count = 0;
+ }
+
+ if (display_info->regs_content_count <= 0)
+ {
+ display_info->regs_content = tui_alloc_content (nr_regs, DATA_WIN);
+ allocated_here = TRUE;
+ refresh_values_only = FALSE;
+ }
+
+ if (display_info->regs_content != (tui_win_content) NULL)
+ {
+ if (!refresh_values_only || allocated_here)
+ {
+ TUI_DATA_WIN->generic.content = (void*) NULL;
+ TUI_DATA_WIN->generic.content_size = 0;
+ tui_add_content_elements (&TUI_DATA_WIN->generic, nr_regs);
+ display_info->regs_content
+ = (tui_win_content) TUI_DATA_WIN->generic.content;
+ display_info->regs_content_count = nr_regs;
+ }
+
+ /* Now set the register names and values */
+ pos = 0;
+ for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+ {
+ struct tui_gen_win_info *data_item_win;
+ struct tui_data_element *data;
+ const char *name;
+
+ if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
+ continue;
+
+ name = gdbarch_register_name (gdbarch, regnum);
+ if (name == 0)
+ continue;
+
+ data_item_win =
+ &display_info->regs_content[pos]->which_element.data_window;
+ data =
+ &((struct tui_win_element *) data_item_win->content[0])->which_element.data;
+ if (data)
+ {
+ if (!refresh_values_only)
+ {
+ data->item_no = regnum;
+ data->name = name;
+ data->highlight = FALSE;
+ }
+ if (data->value == (void*) NULL)
+ data->value = (void*) xmalloc (MAX_REGISTER_SIZE);
+
+ tui_get_register (gdbarch, frame, data, regnum, 0);
+ }
+ pos++;
+ }
+
+ TUI_DATA_WIN->generic.content_size =
+ display_info->regs_content_count + display_info->data_content_count;
+ ret = TUI_SUCCESS;
+ }
+
+ return ret;
+}
+
+/* Function to display the registers in the content from
+ 'start_element_no' until the end of the register content or the end
+ of the display height. No checking for displaying past the end of
+ the registers is done here. */
+void
+tui_display_registers_from (int start_element_no)
+{
+ struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
+
+ if (display_info->regs_content != (tui_win_content) NULL &&
+ display_info->regs_content_count > 0)
+ {
+ int i = start_element_no;
+ int j, value_chars_wide, item_win_width, cur_y;
+
+ int max_len = 0;
+ for (i = 0; i < display_info->regs_content_count; i++)
+ {
+ struct tui_data_element *data;
+ struct tui_gen_win_info *data_item_win;
+ char *p;
+ int len;
+
+ data_item_win = &display_info->regs_content[i]->which_element.data_window;
+ data = &((struct tui_win_element *)
+ data_item_win->content[0])->which_element.data;
+ len = 0;
+ p = data->content;
+ if (p != 0)
+ while (*p)
+ {
+ if (*p++ == '\t')
+ len = 8 * ((len / 8) + 1);
+ else
+ len++;
+ }
+
+ if (len > max_len)
+ max_len = len;
+ }
+ item_win_width = max_len + 1;
+ i = start_element_no;
+
+ display_info->regs_column_count =
+ (TUI_DATA_WIN->generic.width - 2) / item_win_width;
+ if (display_info->regs_column_count == 0)
+ display_info->regs_column_count = 1;
+ item_win_width =
+ (TUI_DATA_WIN->generic.width - 2) / display_info->regs_column_count;
+
+ /*
+ ** Now create each data "sub" window, and write the display into it.
+ */
+ cur_y = 1;
+ while (i < display_info->regs_content_count &&
+ cur_y <= TUI_DATA_WIN->generic.viewport_height)
+ {
+ for (j = 0;
+ (j < display_info->regs_column_count &&
+ i < display_info->regs_content_count); j++)
+ {
+ struct tui_gen_win_info * data_item_win;
+ struct tui_data_element * data_element_ptr;
+
+ /* create the window if necessary */
+ data_item_win = &display_info->regs_content[i]
+ ->which_element.data_window;
+ data_element_ptr = &((struct tui_win_element *)
+ data_item_win->content[0])->which_element.data;
+ if (data_item_win->handle != (WINDOW*) NULL
+ && (data_item_win->height != 1
+ || data_item_win->width != item_win_width
+ || data_item_win->origin.x != (item_win_width * j) + 1
+ || data_item_win->origin.y != cur_y))
+ {
+ tui_delete_win (data_item_win->handle);
+ data_item_win->handle = 0;
+ }
+
+ if (data_item_win->handle == (WINDOW *) NULL)
+ {
+ data_item_win->height = 1;
+ data_item_win->width = item_win_width;
+ data_item_win->origin.x = (item_win_width * j) + 1;
+ data_item_win->origin.y = cur_y;
+ tui_make_window (data_item_win, DONT_BOX_WINDOW);
+ scrollok (data_item_win->handle, FALSE);
+ }
+ touchwin (data_item_win->handle);
+
+ /* Get the printable representation of the register
+ and display it. */
+ tui_display_register (data_element_ptr, data_item_win);
+ i++; /* next register */
+ }
+ cur_y++; /* next row; */
+ }
+ }
+}
+
+
+/* Function to display the registers in the content from
+ 'start_element_no' on 'start_line_no' until the end of the register
+ content or the end of the display height. This function checks
+ that we won't display off the end of the register display. */
+void
+tui_display_reg_element_at_line (int start_element_no, int start_line_no)
+{
+ if (TUI_DATA_WIN->detail.data_display_info.regs_content != (tui_win_content) NULL &&
+ TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
+ {
+ int element_no = start_element_no;
+
+ if (start_element_no != 0 && start_line_no != 0)
+ {
+ int last_line_no, first_line_on_last_page;
+
+ last_line_no = tui_last_regs_line_no ();
+ first_line_on_last_page = last_line_no - (TUI_DATA_WIN->generic.height - 2);
+ if (first_line_on_last_page < 0)
+ first_line_on_last_page = 0;
+ /*
+ ** If there is no other data displayed except registers,
+ ** and the element_no causes us to scroll past the end of the
+ ** registers, adjust what element to really start the display at.
+ */
+ if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0 &&
+ start_line_no > first_line_on_last_page)
+ element_no = tui_first_reg_element_no_inline (first_line_on_last_page);
+ }
+ tui_display_registers_from (element_no);
+ }
+}
+
+
+
+/* Function to display the registers starting at line line_no in the
+ data window. Answers the line number that the display actually
+ started from. If nothing is displayed (-1) is returned. */
+int
+tui_display_registers_from_line (int line_no, int force_display)
+{
+ if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
+ {
+ int line, element_no;
+
+ if (line_no < 0)
+ line = 0;
+ else if (force_display)
+ { /*
+ ** If we must display regs (force_display is true), then make
+ ** sure that we don't display off the end of the registers.
+ */
+ if (line_no >= tui_last_regs_line_no ())
+ {
+ if ((line = tui_line_from_reg_element_no (
+ TUI_DATA_WIN->detail.data_display_info.regs_content_count - 1)) < 0)
+ line = 0;
+ }
+ else
+ line = line_no;
+ }
+ else
+ line = line_no;
+
+ element_no = tui_first_reg_element_no_inline (line);
+ if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
+ tui_display_reg_element_at_line (element_no, line);
+ else
+ line = (-1);
+
+ return line;
+ }
+
+ return (-1); /* nothing was displayed */
+}
+
+
+/* This function check all displayed registers for changes in values,
+ given a particular frame. If the values have changed, they are
+ updated with the new value and highlighted. */
+void
+tui_check_register_values (struct frame_info *frame)
+{
+ if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible)
+ {
+ struct tui_data_info *display_info
+ = &TUI_DATA_WIN->detail.data_display_info;
+
+ if (display_info->regs_content_count <= 0 && display_info->display_regs)
+ tui_show_registers (display_info->current_group);
+ else
+ {
+ int i, j;
+
+ for (i = 0; (i < display_info->regs_content_count); i++)
+ {
+ struct tui_data_element *data;
+ struct tui_gen_win_info *data_item_win_ptr;
+ int was_hilighted;
+
+ data_item_win_ptr = &display_info->regs_content[i]->
+ which_element.data_window;
+ data = &((struct tui_win_element *)
+ data_item_win_ptr->content[0])->which_element.data;
+ was_hilighted = data->highlight;
+
+ tui_get_register (current_gdbarch, frame, data,
+ data->item_no, &data->highlight);
+
+ if (data->highlight || was_hilighted)
+ {
+ tui_display_register (data, data_item_win_ptr);
+ }
+ }
+ }
+ }
+}
+
+/* Display a register in a window. If hilite is TRUE,
+ then the value will be displayed in reverse video */
+static void
+tui_display_register (struct tui_data_element *data,
+ struct tui_gen_win_info *win_info)
+{
+ if (win_info->handle != (WINDOW *) NULL)
+ {
+ int i;
+
+ if (data->highlight)
+ wstandout (win_info->handle);
+
+ wmove (win_info->handle, 0, 0);
+ for (i = 1; i < win_info->width; i++)
+ waddch (win_info->handle, ' ');
+ wmove (win_info->handle, 0, 0);
+ if (data->content)
+ waddstr (win_info->handle, data->content);
+
+ if (data->highlight)
+ wstandend (win_info->handle);
+ tui_refresh_win (win_info);
+ }
+}
+
+static void
+tui_reg_next_command (char *arg, int from_tty)
+{
+ if (TUI_DATA_WIN != 0)
+ {
+ struct reggroup *group
+ = TUI_DATA_WIN->detail.data_display_info.current_group;
+
+ group = reggroup_next (current_gdbarch, group);
+ if (group == 0)
+ group = reggroup_next (current_gdbarch, 0);
+
+ if (group)
+ tui_show_registers (group);
+ }
+}
+
+static void
+tui_reg_float_command (char *arg, int from_tty)
+{
+ tui_show_registers (float_reggroup);
+}
+
+static void
+tui_reg_general_command (char *arg, int from_tty)
+{
+ tui_show_registers (general_reggroup);
+}
+
+static void
+tui_reg_system_command (char *arg, int from_tty)
+{
+ tui_show_registers (system_reggroup);
+}
+
+static struct cmd_list_element *tuireglist;
+
+static void
+tui_reg_command (char *args, int from_tty)
+{
+ printf_unfiltered ("\"tui reg\" must be followed by the name of a "
+ "tui reg command.\n");
+ help_list (tuireglist, "tui reg ", -1, gdb_stdout);
+}
+
+void
+_initialize_tui_regs (void)
+{
+ struct cmd_list_element **tuicmd;
+
+ tuicmd = tui_get_cmd_list ();
+
+ add_prefix_cmd ("reg", class_tui, tui_reg_command,
+ "TUI commands to control the register window.",
+ &tuireglist, "tui reg ", 0,
+ tuicmd);
+
+ add_cmd ("float", class_tui, tui_reg_float_command,
+ "Display only floating point registers\n",
+ &tuireglist);
+ add_cmd ("general", class_tui, tui_reg_general_command,
+ "Display only general registers\n",
+ &tuireglist);
+ add_cmd ("system", class_tui, tui_reg_system_command,
+ "Display only system registers\n",
+ &tuireglist);
+ add_cmd ("next", class_tui, tui_reg_next_command,
+ "Display next register group\n",
+ &tuireglist);
+
+ if (xdb_commands)
+ {
+ add_com ("fr", class_tui, tui_reg_float_command,
+ "Display only floating point registers\n");
+ add_com ("gr", class_tui, tui_reg_general_command,
+ "Display only general registers\n");
+ add_com ("sr", class_tui, tui_reg_system_command,
+ "Display only special registers\n");
+ add_com ("+r", class_tui, tui_scroll_regs_forward_command,
+ "Scroll the registers window forward\n");
+ add_com ("-r", class_tui, tui_scroll_regs_backward_command,
+ "Scroll the register window backward\n");
+ }
+}
+
+
+/*****************************************
+** STATIC LOCAL FUNCTIONS **
+******************************************/
+
+extern int pagination_enabled;
+
+static void
+tui_restore_gdbout (void *ui)
+{
+ ui_file_delete (gdb_stdout);
+ gdb_stdout = (struct ui_file*) ui;
+ pagination_enabled = 1;
+}
+
+/* Get the register from the frame and make a printable representation
+ of it in the data element. */
+static void
+tui_register_format (struct gdbarch *gdbarch, struct frame_info *frame,
+ struct tui_data_element *data_element, int regnum)
+{
+ struct ui_file *stream;
+ struct ui_file *old_stdout;
+ const char *name;
+ struct cleanup *cleanups;
+ char *p, *s;
+ int pos;
+ struct type *type = gdbarch_register_type (gdbarch, regnum);
+
+ name = gdbarch_register_name (gdbarch, regnum);
+ if (name == 0)
+ {
+ return;
+ }
+
+ pagination_enabled = 0;
+ old_stdout = gdb_stdout;
+ stream = tui_sfileopen (256);
+ gdb_stdout = stream;
+ cleanups = make_cleanup (tui_restore_gdbout, (void*) old_stdout);
+ if (TYPE_VECTOR (type) != 0 && 0)
+ {
+ char buf[MAX_REGISTER_SIZE];
+ int len;
+
+ len = register_size (current_gdbarch, regnum);
+ fprintf_filtered (stream, "%-14s ", name);
+ get_frame_register (frame, regnum, buf);
+ print_scalar_formatted (buf, type, 'f', len, stream);
+ }
+ else
+ {
+ gdbarch_print_registers_info (current_gdbarch, stream,
+ frame, regnum, 1);
+ }
+
+ /* Save formatted output in the buffer. */
+ p = tui_file_get_strbuf (stream);
+
+ /* Remove the possible \n. */
+ s = strrchr (p, '\n');
+ if (s && s[1] == 0)
+ *s = 0;
+
+ xfree (data_element->content);
+ data_element->content = xstrdup (p);
+ do_cleanups (cleanups);
+}
+
+/* Get the register value from the given frame and format it for
+ the display. When changep is set, check if the new register value
+ has changed with respect to the previous call. */
+static enum tui_status
+tui_get_register (struct gdbarch *gdbarch, struct frame_info *frame,
+ struct tui_data_element *data, int regnum, int *changedp)
+{
+ enum tui_status ret = TUI_FAILURE;
+
+ if (changedp)
+ *changedp = FALSE;
+ if (target_has_registers)
+ {
+ char buf[MAX_REGISTER_SIZE];
+
+ get_frame_register (frame, regnum, buf);
+ /* NOTE: cagney/2003-03-13: This is bogus. It is refering to
+ the register cache and not the frame which could have pulled
+ the register value off the stack. */
+ if (register_cached (regnum) >= 0)
+ {
+ if (changedp)
+ {
+ int size = register_size (gdbarch, regnum);
+ char *old = (char*) data->value;
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (buf[i] != old[i])
+ {
+ *changedp = TRUE;
+ old[i] = buf[i];
+ }
+ }
+
+ /* Reformat the data content if the value changed. */
+ if (changedp == 0 || *changedp == TRUE)
+ tui_register_format (gdbarch, frame, data, regnum);
+ ret = TUI_SUCCESS;
+ }
+ }
+ return ret;
+}
+
+static void
+tui_scroll_regs_forward_command (char *arg, int from_tty)
+{
+ tui_scroll (FORWARD_SCROLL, TUI_DATA_WIN, 1);
+}
+
+
+static void
+tui_scroll_regs_backward_command (char *arg, int from_tty)
+{
+ tui_scroll (BACKWARD_SCROLL, TUI_DATA_WIN, 1);
+}
diff --git a/contrib/gdb/gdb/tui/tui-regs.h b/contrib/gdb/gdb/tui/tui-regs.h
new file mode 100644
index 0000000..01e2fba
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-regs.h
@@ -0,0 +1,39 @@
+/* TUI display registers in window.
+
+ Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation,
+ Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_REGS_H
+#define TUI_REGS_H
+
+#include "tui/tui-data.h" /* For struct tui_register_display_type. */
+
+extern void tui_check_register_values (struct frame_info *);
+extern void tui_show_registers (struct reggroup *group);
+extern void tui_display_registers_from (int);
+extern int tui_display_registers_from_line (int, int);
+extern int tui_last_regs_line_no (void);
+extern int tui_first_reg_element_inline (int);
+extern int tui_line_from_reg_element_no (int);
+extern int tui_first_reg_element_no_inline (int lineno);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-source.c b/contrib/gdb/gdb/tui/tui-source.c
new file mode 100644
index 0000000..d5154b1
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-source.c
@@ -0,0 +1,352 @@
+/* TUI display source window.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "source.h"
+#include "symtab.h"
+
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-source.h"
+
+#include "gdb_string.h"
+#include "gdb_curses.h"
+
+/* Function to display source in the source window. */
+enum tui_status
+tui_set_source_content (struct symtab *s, int line_no, int noerror)
+{
+ enum tui_status ret = TUI_FAILURE;
+
+ if (s != (struct symtab *) NULL && s->filename != (char *) NULL)
+ {
+ FILE *stream;
+ int i, desc, c, line_width, nlines;
+ char *src_line = 0;
+
+ if ((ret = tui_alloc_source_buffer (TUI_SRC_WIN)) == TUI_SUCCESS)
+ {
+ line_width = TUI_SRC_WIN->generic.width - 1;
+ /* Take hilite (window border) into account, when calculating
+ the number of lines */
+ nlines = (line_no + (TUI_SRC_WIN->generic.height - 2)) - line_no;
+ desc = open_source_file (s);
+ if (desc < 0)
+ {
+ if (!noerror)
+ {
+ char *name = alloca (strlen (s->filename) + 100);
+ sprintf (name, "%s:%d", s->filename, line_no);
+ print_sys_errmsg (name, errno);
+ }
+ ret = TUI_FAILURE;
+ }
+ else
+ {
+ if (s->line_charpos == 0)
+ find_source_lines (s, desc);
+
+ if (line_no < 1 || line_no > s->nlines)
+ {
+ close (desc);
+ printf_unfiltered (
+ "Line number %d out of range; %s has %d lines.\n",
+ line_no, s->filename, s->nlines);
+ }
+ else if (lseek (desc, s->line_charpos[line_no - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (s->filename);
+ }
+ else
+ {
+ int offset, cur_line_no, cur_line, cur_len, threshold;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+ struct tui_source_info * src = &TUI_SRC_WIN->detail.source_info;
+
+ if (TUI_SRC_WIN->generic.title)
+ xfree (TUI_SRC_WIN->generic.title);
+ TUI_SRC_WIN->generic.title = xstrdup (s->filename);
+
+ if (src->filename)
+ xfree (src->filename);
+ src->filename = xstrdup (s->filename);
+
+ /* Determine the threshold for the length of the line
+ and the offset to start the display. */
+ offset = src->horizontal_offset;
+ threshold = (line_width - 1) + offset;
+ stream = fdopen (desc, FOPEN_RT);
+ clearerr (stream);
+ cur_line = 0;
+ cur_line_no = src->start_line_or_addr.line_no = line_no;
+ if (offset > 0)
+ src_line = (char *) xmalloc (
+ (threshold + 1) * sizeof (char));
+ while (cur_line < nlines)
+ {
+ struct tui_win_element * element = (struct tui_win_element *)
+ TUI_SRC_WIN->generic.content[cur_line];
+
+ /* get the first character in the line */
+ c = fgetc (stream);
+
+ if (offset == 0)
+ src_line = ((struct tui_win_element *)
+ TUI_SRC_WIN->generic.content[
+ cur_line])->which_element.source.line;
+ /* Init the line with the line number */
+ sprintf (src_line, "%-6d", cur_line_no);
+ cur_len = strlen (src_line);
+ i = cur_len -
+ ((cur_len / tui_default_tab_len ()) * tui_default_tab_len ());
+ while (i < tui_default_tab_len ())
+ {
+ src_line[cur_len] = ' ';
+ i++;
+ cur_len++;
+ }
+ src_line[cur_len] = (char) 0;
+
+ /* Set whether element is the execution point and
+ whether there is a break point on it. */
+ element->which_element.source.line_or_addr.line_no =
+ cur_line_no;
+ element->which_element.source.is_exec_point =
+ (strcmp (((struct tui_win_element *)
+ locator->content[0])->which_element.locator.file_name,
+ s->filename) == 0
+ && cur_line_no == ((struct tui_win_element *)
+ locator->content[0])->which_element.locator.line_no);
+ if (c != EOF)
+ {
+ i = strlen (src_line) - 1;
+ do
+ {
+ if ((c != '\n') &&
+ (c != '\r') && (++i < threshold))
+ {
+ if (c < 040 && c != '\t')
+ {
+ src_line[i++] = '^';
+ src_line[i] = c + 0100;
+ }
+ else if (c == 0177)
+ {
+ src_line[i++] = '^';
+ src_line[i] = '?';
+ }
+ else
+ { /* Store the charcter in the line
+ buffer. If it is a tab, then
+ translate to the correct number of
+ chars so we don't overwrite our
+ buffer. */
+ if (c == '\t')
+ {
+ int j, max_tab_len = tui_default_tab_len ();
+
+ for (j = i - (
+ (i / max_tab_len) * max_tab_len);
+ ((j < max_tab_len) &&
+ i < threshold);
+ i++, j++)
+ src_line[i] = ' ';
+ i--;
+ }
+ else
+ src_line[i] = c;
+ }
+ src_line[i + 1] = 0;
+ }
+ else
+ { /* If we have not reached EOL, then eat
+ chars until we do */
+ while (c != EOF && c != '\n' && c != '\r')
+ c = fgetc (stream);
+ }
+ }
+ while (c != EOF && c != '\n' && c != '\r' &&
+ i < threshold && (c = fgetc (stream)));
+ }
+ /* Now copy the line taking the offset into account */
+ if (strlen (src_line) > offset)
+ strcpy (((struct tui_win_element *) TUI_SRC_WIN->generic.content[
+ cur_line])->which_element.source.line,
+ &src_line[offset]);
+ else
+ ((struct tui_win_element *)
+ TUI_SRC_WIN->generic.content[
+ cur_line])->which_element.source.line[0] = (char) 0;
+ cur_line++;
+ cur_line_no++;
+ }
+ if (offset > 0)
+ xfree (src_line);
+ fclose (stream);
+ TUI_SRC_WIN->generic.content_size = nlines;
+ ret = TUI_SUCCESS;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+
+/* elz: this function sets the contents of the source window to empty
+ except for a line in the middle with a warning message about the
+ source not being available. This function is called by
+ tui_erase_source_contents(), which in turn is invoked when the
+ source files cannot be accessed. */
+
+void
+tui_set_source_content_nil (struct tui_win_info * win_info, char *warning_string)
+{
+ int line_width;
+ int n_lines;
+ int curr_line = 0;
+
+ line_width = win_info->generic.width - 1;
+ n_lines = win_info->generic.height - 2;
+
+ /* set to empty each line in the window, except for the one
+ which contains the message */
+ while (curr_line < win_info->generic.content_size)
+ {
+ /* set the information related to each displayed line
+ to null: i.e. the line number is 0, there is no bp,
+ it is not where the program is stopped */
+
+ struct tui_win_element * element =
+ (struct tui_win_element *) win_info->generic.content[curr_line];
+ element->which_element.source.line_or_addr.line_no = 0;
+ element->which_element.source.is_exec_point = FALSE;
+ element->which_element.source.has_break = FALSE;
+
+ /* set the contents of the line to blank */
+ element->which_element.source.line[0] = (char) 0;
+
+ /* if the current line is in the middle of the screen, then we
+ want to display the 'no source available' message in it.
+ Note: the 'weird' arithmetic with the line width and height
+ comes from the function tui_erase_source_content(). We need
+ to keep the screen and the window's actual contents in synch. */
+
+ if (curr_line == (n_lines / 2 + 1))
+ {
+ int i;
+ int xpos;
+ int warning_length = strlen (warning_string);
+ char *src_line;
+
+ src_line = element->which_element.source.line;
+
+ if (warning_length >= ((line_width - 1) / 2))
+ xpos = 1;
+ else
+ xpos = (line_width - 1) / 2 - warning_length;
+
+ for (i = 0; i < xpos; i++)
+ src_line[i] = ' ';
+
+ sprintf (src_line + i, "%s", warning_string);
+
+ for (i = xpos + warning_length; i < line_width; i++)
+ src_line[i] = ' ';
+
+ src_line[i] = '\n';
+
+ } /* end if */
+
+ curr_line++;
+
+ } /* end while */
+}
+
+
+/* Function to display source in the source window. This function
+ initializes the horizontal scroll to 0. */
+void
+tui_show_symtab_source (struct symtab *s, union tui_line_or_address line, int noerror)
+{
+ TUI_SRC_WIN->detail.source_info.horizontal_offset = 0;
+ tui_update_source_window_as_is (TUI_SRC_WIN, s, line, noerror);
+}
+
+
+/* Answer whether the source is currently displayed in the source
+ window. */
+int
+tui_source_is_displayed (char *fname)
+{
+ return (TUI_SRC_WIN->generic.content_in_use &&
+ (strcmp (((struct tui_win_element *) (tui_locator_win_info_ptr ())->
+ content[0])->which_element.locator.file_name, fname) == 0));
+}
+
+
+/* Scroll the source forward or backward vertically. */
+void
+tui_vertical_source_scroll (enum tui_scroll_direction scroll_direction,
+ int num_to_scroll)
+{
+ if (TUI_SRC_WIN->generic.content != NULL)
+ {
+ union tui_line_or_address l;
+ struct symtab *s;
+ tui_win_content content = (tui_win_content) TUI_SRC_WIN->generic.content;
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+ if (cursal.symtab == (struct symtab *) NULL)
+ s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
+ else
+ s = cursal.symtab;
+
+ if (scroll_direction == FORWARD_SCROLL)
+ {
+ l.line_no = content[0]->which_element.source.line_or_addr.line_no +
+ num_to_scroll;
+ if (l.line_no > s->nlines)
+ /*line = s->nlines - win_info->generic.content_size + 1; */
+ /*elz: fix for dts 23398 */
+ l.line_no = content[0]->which_element.source.line_or_addr.line_no;
+ }
+ else
+ {
+ l.line_no = content[0]->which_element.source.line_or_addr.line_no -
+ num_to_scroll;
+ if (l.line_no <= 0)
+ l.line_no = 1;
+ }
+
+ print_source_lines (s, l.line_no, l.line_no + 1, 0);
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-source.h b/contrib/gdb/gdb/tui/tui-source.h
new file mode 100644
index 0000000..3b61ca4
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-source.h
@@ -0,0 +1,40 @@
+/* TUI display source window.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_SOURCE_H
+#define TUI_SOURCE_H
+
+#include "tui/tui-data.h"
+
+struct symtab;
+struct tui_win_info;
+
+extern void tui_set_source_content_nil (struct tui_win_info *, char *);
+
+extern enum tui_status tui_set_source_content (struct symtab *, int, int);
+extern void tui_show_symtab_source (struct symtab *, union tui_line_or_address, int);
+extern int tui_source_is_displayed (char *);
+extern void tui_vertical_source_scroll (enum tui_scroll_direction, int);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-stack.c b/contrib/gdb/gdb/tui/tui-stack.c
new file mode 100644
index 0000000..0ee5389
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-stack.c
@@ -0,0 +1,427 @@
+/* TUI display locator.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "breakpoint.h"
+#include "frame.h"
+#include "command.h"
+#include "inferior.h"
+#include "target.h"
+#include "top.h"
+#include "gdb_string.h"
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-source.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-file.h"
+
+#include "gdb_curses.h"
+
+/* Get a printable name for the function at the address.
+ The symbol name is demangled if demangling is turned on.
+ Returns a pointer to a static area holding the result. */
+static char* tui_get_function_from_frame (struct frame_info *fi);
+
+/* Set the filename portion of the locator. */
+static void tui_set_locator_filename (const char *filename);
+
+/* Update the locator, with the provided arguments. */
+static void tui_set_locator_info (const char *filename, const char *procname,
+ int lineno, CORE_ADDR addr);
+
+static void tui_update_command (char *, int);
+
+
+/* Create the status line to display as much information as we
+ can on this single line: target name, process number, current
+ function, current line, current PC, SingleKey mode. */
+static char*
+tui_make_status_line (struct tui_locator_element* loc)
+{
+ char* string;
+ char line_buf[50], *pname;
+ char* buf;
+ int status_size;
+ int i, proc_width;
+ const char* pid_name;
+ const char* pc_buf;
+ int target_width;
+ int pid_width;
+ int line_width;
+ int pc_width;
+ struct ui_file *pc_out;
+
+ if (ptid_equal (inferior_ptid, null_ptid))
+ pid_name = "No process";
+ else
+ pid_name = target_pid_to_str (inferior_ptid);
+
+ target_width = strlen (target_shortname);
+ if (target_width > MAX_TARGET_WIDTH)
+ target_width = MAX_TARGET_WIDTH;
+
+ pid_width = strlen (pid_name);
+ if (pid_width > MAX_PID_WIDTH)
+ pid_width = MAX_PID_WIDTH;
+
+ status_size = tui_term_width ();
+ string = (char *) xmalloc (status_size + 1);
+ buf = (char*) alloca (status_size + 1);
+
+ /* Translate line number and obtain its size. */
+ if (loc->line_no > 0)
+ sprintf (line_buf, "%d", loc->line_no);
+ else
+ strcpy (line_buf, "??");
+ line_width = strlen (line_buf);
+ if (line_width < MIN_LINE_WIDTH)
+ line_width = MIN_LINE_WIDTH;
+
+ /* Translate PC address. */
+ pc_out = tui_sfileopen (128);
+ print_address_numeric (loc->addr, 1, pc_out);
+ pc_buf = tui_file_get_strbuf (pc_out);
+ pc_width = strlen (pc_buf);
+
+ /* First determine the amount of proc name width we have available.
+ The +1 are for a space separator between fields.
+ The -1 are to take into account the \0 counted by sizeof. */
+ proc_width = (status_size
+ - (target_width + 1)
+ - (pid_width + 1)
+ - (sizeof (PROC_PREFIX) - 1 + 1)
+ - (sizeof (LINE_PREFIX) - 1 + line_width + 1)
+ - (sizeof (PC_PREFIX) - 1 + pc_width + 1)
+ - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
+ ? (sizeof (SINGLE_KEY) - 1 + 1)
+ : 0));
+
+ /* If there is no room to print the function name, try by removing
+ some fields. */
+ if (proc_width < MIN_PROC_WIDTH)
+ {
+ proc_width += target_width + 1;
+ target_width = 0;
+ if (proc_width < MIN_PROC_WIDTH)
+ {
+ proc_width += pid_width + 1;
+ pid_width = 0;
+ if (proc_width <= MIN_PROC_WIDTH)
+ {
+ proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
+ pc_width = 0;
+ if (proc_width < 0)
+ {
+ proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
+ line_width = 0;
+ if (proc_width < 0)
+ proc_width = 0;
+ }
+ }
+ }
+ }
+
+ /* Now convert elements to string form */
+ pname = loc->proc_name;
+
+ /* Now create the locator line from the string version
+ of the elements. We could use sprintf() here but
+ that wouldn't ensure that we don't overrun the size
+ of the allocated buffer. strcat_to_buf() will. */
+ *string = (char) 0;
+
+ if (target_width > 0)
+ {
+ sprintf (buf, "%*.*s ",
+ -target_width, target_width, target_shortname);
+ strcat_to_buf (string, status_size, buf);
+ }
+ if (pid_width > 0)
+ {
+ sprintf (buf, "%*.*s ",
+ -pid_width, pid_width, pid_name);
+ strcat_to_buf (string, status_size, buf);
+ }
+
+ /* Show whether we are in SingleKey mode. */
+ if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
+ {
+ strcat_to_buf (string, status_size, SINGLE_KEY);
+ strcat_to_buf (string, status_size, " ");
+ }
+
+ /* procedure/class name */
+ if (proc_width > 0)
+ {
+ if (strlen (pname) > proc_width)
+ sprintf (buf, "%s%*.*s* ", PROC_PREFIX,
+ 1 - proc_width, proc_width - 1, pname);
+ else
+ sprintf (buf, "%s%*.*s ", PROC_PREFIX,
+ -proc_width, proc_width, pname);
+ strcat_to_buf (string, status_size, buf);
+ }
+
+ if (line_width > 0)
+ {
+ sprintf (buf, "%s%*.*s ", LINE_PREFIX,
+ -line_width, line_width, line_buf);
+ strcat_to_buf (string, status_size, buf);
+ }
+ if (pc_width > 0)
+ {
+ strcat_to_buf (string, status_size, PC_PREFIX);
+ strcat_to_buf (string, status_size, pc_buf);
+ }
+
+
+ for (i = strlen (string); i < status_size; i++)
+ string[i] = ' ';
+ string[status_size] = (char) 0;
+
+ ui_file_delete (pc_out);
+ return string;
+}
+
+/* Get a printable name for the function at the address.
+ The symbol name is demangled if demangling is turned on.
+ Returns a pointer to a static area holding the result. */
+static char*
+tui_get_function_from_frame (struct frame_info *fi)
+{
+ static char name[256];
+ struct ui_file *stream = tui_sfileopen (256);
+ char *p;
+
+ print_address_symbolic (get_frame_pc (fi), stream, demangle, "");
+ p = tui_file_get_strbuf (stream);
+
+ /* Use simple heuristics to isolate the function name. The symbol can
+ be demangled and we can have function parameters. Remove them because
+ the status line is too short to display them. */
+ if (*p == '<')
+ p++;
+ strncpy (name, p, sizeof (name));
+ p = strchr (name, '(');
+ if (!p)
+ p = strchr (name, '>');
+ if (p)
+ *p = 0;
+ p = strchr (name, '+');
+ if (p)
+ *p = 0;
+ ui_file_delete (stream);
+ return name;
+}
+
+void
+tui_show_locator_content (void)
+{
+ char *string;
+ struct tui_gen_win_info * locator;
+
+ locator = tui_locator_win_info_ptr ();
+
+ if (locator != NULL && locator->handle != (WINDOW *) NULL)
+ {
+ struct tui_win_element * element;
+
+ element = (struct tui_win_element *) locator->content[0];
+
+ string = tui_make_status_line (&element->which_element.locator);
+ wmove (locator->handle, 0, 0);
+ wstandout (locator->handle);
+ waddstr (locator->handle, string);
+ wclrtoeol (locator->handle);
+ wstandend (locator->handle);
+ tui_refresh_win (locator);
+ wmove (locator->handle, 0, 0);
+ xfree (string);
+ locator->content_in_use = TRUE;
+ }
+}
+
+
+/* Set the filename portion of the locator. */
+static void
+tui_set_locator_filename (const char *filename)
+{
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+ struct tui_locator_element * element;
+
+ if (locator->content[0] == NULL)
+ {
+ tui_set_locator_info (filename, NULL, 0, 0);
+ return;
+ }
+
+ element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
+ element->file_name[0] = 0;
+ strcat_to_buf (element->file_name, MAX_LOCATOR_ELEMENT_LEN, filename);
+}
+
+/* Update the locator, with the provided arguments. */
+static void
+tui_set_locator_info (const char *filename, const char *procname, int lineno,
+ CORE_ADDR addr)
+{
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+ struct tui_locator_element * element;
+
+ /* Allocate the locator content if necessary. */
+ if (locator->content_size <= 0)
+ {
+ locator->content = (void **) tui_alloc_content (1, locator->type);
+ locator->content_size = 1;
+ }
+
+ element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
+ element->proc_name[0] = (char) 0;
+ strcat_to_buf (element->proc_name, MAX_LOCATOR_ELEMENT_LEN, procname);
+ element->line_no = lineno;
+ element->addr = addr;
+ tui_set_locator_filename (filename);
+}
+
+/* Update only the filename portion of the locator. */
+void
+tui_update_locator_filename (const char *filename)
+{
+ tui_set_locator_filename (filename);
+ tui_show_locator_content ();
+}
+
+/* Function to print the frame information for the TUI. */
+void
+tui_show_frame_info (struct frame_info *fi)
+{
+ struct tui_win_info * win_info;
+ int i;
+
+ if (fi)
+ {
+ int start_line, i;
+ CORE_ADDR low;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+ int source_already_displayed;
+ struct symtab_and_line sal;
+
+ find_frame_sal (fi, &sal);
+
+ source_already_displayed = sal.symtab != 0
+ && tui_source_is_displayed (sal.symtab->filename);
+ tui_set_locator_info (sal.symtab == 0 ? "??" : sal.symtab->filename,
+ tui_get_function_from_frame (fi),
+ sal.line,
+ get_frame_pc (fi));
+ tui_show_locator_content ();
+ start_line = 0;
+ for (i = 0; i < (tui_source_windows ())->count; i++)
+ {
+ union tui_which_element *item;
+ win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
+
+ item = &((struct tui_win_element *) locator->content[0])->which_element;
+ if (win_info == TUI_SRC_WIN)
+ {
+ start_line = (item->locator.line_no -
+ (win_info->generic.viewport_height / 2)) + 1;
+ if (start_line <= 0)
+ start_line = 1;
+ }
+ else
+ {
+ if (find_pc_partial_function (get_frame_pc (fi), (char **) NULL,
+ &low, (CORE_ADDR) NULL) == 0)
+ error ("No function contains program counter for selected frame.\n");
+ else
+ low = tui_get_low_disassembly_address (low, get_frame_pc (fi));
+ }
+
+ if (win_info == TUI_SRC_WIN)
+ {
+ union tui_line_or_address l;
+ l.line_no = start_line;
+ if (!(source_already_displayed
+ && tui_line_is_displayed (item->locator.line_no, win_info, TRUE)))
+ tui_update_source_window (win_info, sal.symtab, l, TRUE);
+ else
+ {
+ l.line_no = item->locator.line_no;
+ tui_set_is_exec_point_at (l, win_info);
+ }
+ }
+ else
+ {
+ if (win_info == TUI_DISASM_WIN)
+ {
+ union tui_line_or_address a;
+ a.addr = low;
+ if (!tui_addr_is_displayed (item->locator.addr, win_info, TRUE))
+ tui_update_source_window (win_info, sal.symtab, a, TRUE);
+ else
+ {
+ a.addr = item->locator.addr;
+ tui_set_is_exec_point_at (a, win_info);
+ }
+ }
+ }
+ tui_update_exec_info (win_info);
+ }
+ }
+ else
+ {
+ tui_set_locator_info (NULL, NULL, 0, (CORE_ADDR) 0);
+ tui_show_locator_content ();
+ for (i = 0; i < (tui_source_windows ())->count; i++)
+ {
+ win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
+ tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
+ tui_update_exec_info (win_info);
+ }
+ }
+}
+
+/* Function to initialize gdb commands, for tui window stack
+ manipulation. */
+void
+_initialize_tui_stack (void)
+{
+ add_com ("update", class_tui, tui_update_command,
+ "Update the source window and locator to display the current "
+ "execution point.\n");
+}
+
+/* Command to update the display with the current execution point. */
+static void
+tui_update_command (char *arg, int from_tty)
+{
+ char cmd[sizeof("frame 0")];
+
+ strcpy (cmd, "frame 0");
+ execute_command (cmd, from_tty);
+}
diff --git a/contrib/gdb/gdb/tui/tui-stack.h b/contrib/gdb/gdb/tui/tui-stack.h
new file mode 100644
index 0000000..65725b3
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-stack.h
@@ -0,0 +1,34 @@
+/* TUI display locator.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_STACK_H
+#define TUI_STACK_H
+
+struct frame_info;
+
+extern void tui_update_locator_filename (const char *);
+extern void tui_show_locator_content (void);
+extern void tui_show_frame_info (struct frame_info *);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-win.c b/contrib/gdb/gdb/tui/tui-win.c
new file mode 100644
index 0000000..1c67baa
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-win.c
@@ -0,0 +1,1520 @@
+/* TUI window generic functions.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 contains procedures for handling tui window functions
+ like resize, scrolling, scrolling, changing focus, etc.
+
+ Author: Susan B. Macchia */
+
+#include "defs.h"
+#include "command.h"
+#include "symtab.h"
+#include "breakpoint.h"
+#include "frame.h"
+#include "cli/cli-cmds.h"
+#include "top.h"
+#include "source.h"
+
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-regs.h"
+#include "tui/tui-disasm.h"
+#include "tui/tui-source.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-windata.h"
+
+#include "gdb_curses.h"
+
+#include "gdb_string.h"
+#include <ctype.h>
+#include "readline/readline.h"
+
+/*******************************
+** Static Local Decls
+********************************/
+static void make_visible_with_new_height (struct tui_win_info *);
+static void make_invisible_and_set_new_height (struct tui_win_info *, int);
+static enum tui_status tui_adjust_win_heights (struct tui_win_info *, int);
+static int new_height_ok (struct tui_win_info *, int);
+static void tui_set_tab_width_command (char *, int);
+static void tui_refresh_all_command (char *, int);
+static void tui_set_win_height_command (char *, int);
+static void tui_xdb_set_win_height_command (char *, int);
+static void tui_all_windows_info (char *, int);
+static void tui_set_focus_command (char *, int);
+static void tui_scroll_forward_command (char *, int);
+static void tui_scroll_backward_command (char *, int);
+static void tui_scroll_left_command (char *, int);
+static void tui_scroll_right_command (char *, int);
+static void parse_scrolling_args (char *, struct tui_win_info * *, int *);
+
+
+/***************************************
+** DEFINITIONS
+***************************************/
+#define WIN_HEIGHT_USAGE "Usage: winheight <win_name> [+ | -] <#lines>\n"
+#define XDBWIN_HEIGHT_USAGE "Usage: w <#lines>\n"
+#define FOCUS_USAGE "Usage: focus {<win> | next | prev}\n"
+
+/***************************************
+** PUBLIC FUNCTIONS
+***************************************/
+
+#ifndef ACS_LRCORNER
+# define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+# define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_ULCORNER
+# define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+# define ACS_URCORNER '+'
+#endif
+#ifndef ACS_HLINE
+# define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+# define ACS_VLINE '|'
+#endif
+
+/* Possible values for tui-border-kind variable. */
+static const char *tui_border_kind_enums[] = {
+ "space",
+ "ascii",
+ "acs",
+ NULL
+};
+
+/* Possible values for tui-border-mode and tui-active-border-mode. */
+static const char *tui_border_mode_enums[] = {
+ "normal",
+ "standout",
+ "reverse",
+ "half",
+ "half-standout",
+ "bold",
+ "bold-standout",
+ NULL
+};
+
+struct tui_translate
+{
+ const char *name;
+ int value;
+};
+
+/* Translation table for border-mode variables.
+ The list of values must be terminated by a NULL.
+ After the NULL value, an entry defines the default. */
+struct tui_translate tui_border_mode_translate[] = {
+ { "normal", A_NORMAL },
+ { "standout", A_STANDOUT },
+ { "reverse", A_REVERSE },
+ { "half", A_DIM },
+ { "half-standout", A_DIM | A_STANDOUT },
+ { "bold", A_BOLD },
+ { "bold-standout", A_BOLD | A_STANDOUT },
+ { 0, 0 },
+ { "normal", A_NORMAL }
+};
+
+/* Translation tables for border-kind, one for each border
+ character (see wborder, border curses operations).
+ -1 is used to indicate the ACS because ACS characters
+ are determined at run time by curses (depends on terminal). */
+struct tui_translate tui_border_kind_translate_vline[] = {
+ { "space", ' ' },
+ { "ascii", '|' },
+ { "acs", -1 },
+ { 0, 0 },
+ { "ascii", '|' }
+};
+
+struct tui_translate tui_border_kind_translate_hline[] = {
+ { "space", ' ' },
+ { "ascii", '-' },
+ { "acs", -1 },
+ { 0, 0 },
+ { "ascii", '-' }
+};
+
+struct tui_translate tui_border_kind_translate_ulcorner[] = {
+ { "space", ' ' },
+ { "ascii", '+' },
+ { "acs", -1 },
+ { 0, 0 },
+ { "ascii", '+' }
+};
+
+struct tui_translate tui_border_kind_translate_urcorner[] = {
+ { "space", ' ' },
+ { "ascii", '+' },
+ { "acs", -1 },
+ { 0, 0 },
+ { "ascii", '+' }
+};
+
+struct tui_translate tui_border_kind_translate_llcorner[] = {
+ { "space", ' ' },
+ { "ascii", '+' },
+ { "acs", -1 },
+ { 0, 0 },
+ { "ascii", '+' }
+};
+
+struct tui_translate tui_border_kind_translate_lrcorner[] = {
+ { "space", ' ' },
+ { "ascii", '+' },
+ { "acs", -1 },
+ { 0, 0 },
+ { "ascii", '+' }
+};
+
+
+/* Tui configuration variables controlled with set/show command. */
+const char *tui_active_border_mode = "bold-standout";
+const char *tui_border_mode = "normal";
+const char *tui_border_kind = "acs";
+
+/* Tui internal configuration variables. These variables are
+ updated by tui_update_variables to reflect the tui configuration
+ variables. */
+chtype tui_border_vline;
+chtype tui_border_hline;
+chtype tui_border_ulcorner;
+chtype tui_border_urcorner;
+chtype tui_border_llcorner;
+chtype tui_border_lrcorner;
+
+int tui_border_attrs;
+int tui_active_border_attrs;
+
+/* Identify the item in the translation table.
+ When the item is not recognized, use the default entry. */
+static struct tui_translate *
+translate (const char *name, struct tui_translate *table)
+{
+ while (table->name)
+ {
+ if (name && strcmp (table->name, name) == 0)
+ return table;
+ table++;
+ }
+
+ /* Not found, return default entry. */
+ table++;
+ return table;
+}
+
+/* Update the tui internal configuration according to gdb settings.
+ Returns 1 if the configuration has changed and the screen should
+ be redrawn. */
+int
+tui_update_variables (void)
+{
+ int need_redraw = 0;
+ struct tui_translate *entry;
+
+ entry = translate (tui_border_mode, tui_border_mode_translate);
+ if (tui_border_attrs != entry->value)
+ {
+ tui_border_attrs = entry->value;
+ need_redraw = 1;
+ }
+ entry = translate (tui_active_border_mode, tui_border_mode_translate);
+ if (tui_active_border_attrs != entry->value)
+ {
+ tui_active_border_attrs = entry->value;
+ need_redraw = 1;
+ }
+
+ /* If one corner changes, all characters are changed.
+ Only check the first one. The ACS characters are determined at
+ run time by curses terminal management. */
+ entry = translate (tui_border_kind, tui_border_kind_translate_lrcorner);
+ if (tui_border_lrcorner != (chtype) entry->value)
+ {
+ tui_border_lrcorner = (entry->value < 0) ? ACS_LRCORNER : entry->value;
+ need_redraw = 1;
+ }
+ entry = translate (tui_border_kind, tui_border_kind_translate_llcorner);
+ tui_border_llcorner = (entry->value < 0) ? ACS_LLCORNER : entry->value;
+
+ entry = translate (tui_border_kind, tui_border_kind_translate_ulcorner);
+ tui_border_ulcorner = (entry->value < 0) ? ACS_ULCORNER : entry->value;
+
+ entry = translate (tui_border_kind, tui_border_kind_translate_urcorner);
+ tui_border_urcorner = (entry->value < 0) ? ACS_URCORNER : entry->value;
+
+ entry = translate (tui_border_kind, tui_border_kind_translate_hline);
+ tui_border_hline = (entry->value < 0) ? ACS_HLINE : entry->value;
+
+ entry = translate (tui_border_kind, tui_border_kind_translate_vline);
+ tui_border_vline = (entry->value < 0) ? ACS_VLINE : entry->value;
+
+ return need_redraw;
+}
+
+static void
+set_tui_cmd (char *args, int from_tty)
+{
+}
+
+static void
+show_tui_cmd (char *args, int from_tty)
+{
+}
+
+static struct cmd_list_element *tuilist;
+
+static void
+tui_command (char *args, int from_tty)
+{
+ printf_unfiltered ("\"tui\" must be followed by the name of a "
+ "tui command.\n");
+ help_list (tuilist, "tui ", -1, gdb_stdout);
+}
+
+struct cmd_list_element **
+tui_get_cmd_list ()
+{
+ if (tuilist == 0)
+ add_prefix_cmd ("tui", class_tui, tui_command,
+ "Text User Interface commands.",
+ &tuilist, "tui ", 0, &cmdlist);
+ return &tuilist;
+}
+
+/* Function to initialize gdb commands, for tui window manipulation. */
+void
+_initialize_tui_win (void)
+{
+ struct cmd_list_element *c;
+ static struct cmd_list_element *tui_setlist;
+ static struct cmd_list_element *tui_showlist;
+
+ /* Define the classes of commands.
+ They will appear in the help list in the reverse of this order. */
+ add_prefix_cmd ("tui", class_tui, set_tui_cmd,
+ "TUI configuration variables",
+ &tui_setlist, "set tui ",
+ 0/*allow-unknown*/, &setlist);
+ add_prefix_cmd ("tui", class_tui, show_tui_cmd,
+ "TUI configuration variables",
+ &tui_showlist, "show tui ",
+ 0/*allow-unknown*/, &showlist);
+
+ add_com ("refresh", class_tui, tui_refresh_all_command,
+ "Refresh the terminal display.\n");
+ if (xdb_commands)
+ add_com_alias ("U", "refresh", class_tui, 0);
+ add_com ("tabset", class_tui, tui_set_tab_width_command,
+ "Set the width (in characters) of tab stops.\n\
+Usage: tabset <n>\n");
+ add_com ("winheight", class_tui, tui_set_win_height_command,
+ "Set the height of a specified window.\n\
+Usage: winheight <win_name> [+ | -] <#lines>\n\
+Window names are:\n\
+src : the source window\n\
+cmd : the command window\n\
+asm : the disassembly window\n\
+regs : the register display\n");
+ add_com_alias ("wh", "winheight", class_tui, 0);
+ add_info ("win", tui_all_windows_info,
+ "List of all displayed windows.\n");
+ add_com ("focus", class_tui, tui_set_focus_command,
+ "Set focus to named window or next/prev window.\n\
+Usage: focus {<win> | next | prev}\n\
+Valid Window names are:\n\
+src : the source window\n\
+asm : the disassembly window\n\
+regs : the register display\n\
+cmd : the command window\n");
+ add_com_alias ("fs", "focus", class_tui, 0);
+ add_com ("+", class_tui, tui_scroll_forward_command,
+ "Scroll window forward.\nUsage: + [win] [n]\n");
+ add_com ("-", class_tui, tui_scroll_backward_command,
+ "Scroll window backward.\nUsage: - [win] [n]\n");
+ add_com ("<", class_tui, tui_scroll_left_command,
+ "Scroll window forward.\nUsage: < [win] [n]\n");
+ add_com (">", class_tui, tui_scroll_right_command,
+ "Scroll window backward.\nUsage: > [win] [n]\n");
+ if (xdb_commands)
+ add_com ("w", class_xdb, tui_xdb_set_win_height_command,
+ "XDB compatibility command for setting the height of a command window.\n\
+Usage: w <#lines>\n");
+
+ /* Define the tui control variables. */
+ c = add_set_enum_cmd
+ ("border-kind", no_class,
+ tui_border_kind_enums, &tui_border_kind,
+ "Set the kind of border for TUI windows.\n"
+ "This variable controls the border of TUI windows:\n"
+ "space use a white space\n"
+ "ascii use ascii characters + - | for the border\n"
+ "acs use the Alternate Character Set\n",
+ &tui_setlist);
+ add_show_from_set (c, &tui_showlist);
+
+ c = add_set_enum_cmd
+ ("border-mode", no_class,
+ tui_border_mode_enums, &tui_border_mode,
+ "Set the attribute mode to use for the TUI window borders.\n"
+ "This variable controls the attributes to use for the window borders:\n"
+ "normal normal display\n"
+ "standout use highlight mode of terminal\n"
+ "reverse use reverse video mode\n"
+ "half use half bright\n"
+ "half-standout use half bright and standout mode\n"
+ "bold use extra bright or bold\n"
+ "bold-standout use extra bright or bold with standout mode\n",
+ &tui_setlist);
+ add_show_from_set (c, &tui_showlist);
+
+ c = add_set_enum_cmd
+ ("active-border-mode", no_class,
+ tui_border_mode_enums, &tui_active_border_mode,
+ "Set the attribute mode to use for the active TUI window border.\n"
+ "This variable controls the attributes to use for the active window border:\n"
+ "normal normal display\n"
+ "standout use highlight mode of terminal\n"
+ "reverse use reverse video mode\n"
+ "half use half bright\n"
+ "half-standout use half bright and standout mode\n"
+ "bold use extra bright or bold\n"
+ "bold-standout use extra bright or bold with standout mode\n",
+ &tui_setlist);
+ add_show_from_set (c, &tui_showlist);
+}
+
+/* Update gdb's knowledge of the terminal size. */
+void
+tui_update_gdb_sizes (void)
+{
+ char cmd[50];
+ int screenheight, screenwidth;
+
+ rl_get_screen_size (&screenheight, &screenwidth);
+ /* Set to TUI command window dimension or use readline values. */
+ sprintf (cmd, "set width %d",
+ tui_active ? TUI_CMD_WIN->generic.width : screenwidth);
+ execute_command (cmd, 0);
+ sprintf (cmd, "set height %d",
+ tui_active ? TUI_CMD_WIN->generic.height : screenheight);
+ execute_command (cmd, 0);
+}
+
+
+/* Set the logical focus to win_info. */
+void
+tui_set_win_focus_to (struct tui_win_info * win_info)
+{
+ if (win_info != NULL)
+ {
+ struct tui_win_info * win_with_focus = tui_win_with_focus ();
+
+ if (win_with_focus != NULL
+ && win_with_focus->generic.type != CMD_WIN)
+ tui_unhighlight_win (win_with_focus);
+ tui_set_win_with_focus (win_info);
+ if (win_info->generic.type != CMD_WIN)
+ tui_highlight_win (win_info);
+ }
+}
+
+
+void
+tui_scroll_forward (struct tui_win_info * win_to_scroll, int num_to_scroll)
+{
+ if (win_to_scroll != TUI_CMD_WIN)
+ {
+ int _num_to_scroll = num_to_scroll;
+
+ if (num_to_scroll == 0)
+ _num_to_scroll = win_to_scroll->generic.height - 3;
+ /*
+ ** If we are scrolling the source or disassembly window, do a
+ ** "psuedo" scroll since not all of the source is in memory,
+ ** only what is in the viewport. If win_to_scroll is the
+ ** command window do nothing since the term should handle it.
+ */
+ if (win_to_scroll == TUI_SRC_WIN)
+ tui_vertical_source_scroll (FORWARD_SCROLL, _num_to_scroll);
+ else if (win_to_scroll == TUI_DISASM_WIN)
+ tui_vertical_disassem_scroll (FORWARD_SCROLL, _num_to_scroll);
+ else if (win_to_scroll == TUI_DATA_WIN)
+ tui_vertical_data_scroll (FORWARD_SCROLL, _num_to_scroll);
+ }
+}
+
+void
+tui_scroll_backward (struct tui_win_info * win_to_scroll, int num_to_scroll)
+{
+ if (win_to_scroll != TUI_CMD_WIN)
+ {
+ int _num_to_scroll = num_to_scroll;
+
+ if (num_to_scroll == 0)
+ _num_to_scroll = win_to_scroll->generic.height - 3;
+ /*
+ ** If we are scrolling the source or disassembly window, do a
+ ** "psuedo" scroll since not all of the source is in memory,
+ ** only what is in the viewport. If win_to_scroll is the
+ ** command window do nothing since the term should handle it.
+ */
+ if (win_to_scroll == TUI_SRC_WIN)
+ tui_vertical_source_scroll (BACKWARD_SCROLL, _num_to_scroll);
+ else if (win_to_scroll == TUI_DISASM_WIN)
+ tui_vertical_disassem_scroll (BACKWARD_SCROLL, _num_to_scroll);
+ else if (win_to_scroll == TUI_DATA_WIN)
+ tui_vertical_data_scroll (BACKWARD_SCROLL, _num_to_scroll);
+ }
+}
+
+
+void
+tui_scroll_left (struct tui_win_info * win_to_scroll, int num_to_scroll)
+{
+ if (win_to_scroll != TUI_CMD_WIN)
+ {
+ int _num_to_scroll = num_to_scroll;
+
+ if (_num_to_scroll == 0)
+ _num_to_scroll = 1;
+ /*
+ ** If we are scrolling the source or disassembly window, do a
+ ** "psuedo" scroll since not all of the source is in memory,
+ ** only what is in the viewport. If win_to_scroll is the
+ ** command window do nothing since the term should handle it.
+ */
+ if (win_to_scroll == TUI_SRC_WIN || win_to_scroll == TUI_DISASM_WIN)
+ tui_horizontal_source_scroll (win_to_scroll, LEFT_SCROLL, _num_to_scroll);
+ }
+}
+
+
+void
+tui_scroll_right (struct tui_win_info * win_to_scroll, int num_to_scroll)
+{
+ if (win_to_scroll != TUI_CMD_WIN)
+ {
+ int _num_to_scroll = num_to_scroll;
+
+ if (_num_to_scroll == 0)
+ _num_to_scroll = 1;
+ /*
+ ** If we are scrolling the source or disassembly window, do a
+ ** "psuedo" scroll since not all of the source is in memory,
+ ** only what is in the viewport. If win_to_scroll is the
+ ** command window do nothing since the term should handle it.
+ */
+ if (win_to_scroll == TUI_SRC_WIN || win_to_scroll == TUI_DISASM_WIN)
+ tui_horizontal_source_scroll (win_to_scroll, RIGHT_SCROLL, _num_to_scroll);
+ }
+}
+
+
+/* Scroll a window. Arguments are passed through a va_list. */
+void
+tui_scroll (enum tui_scroll_direction direction,
+ struct tui_win_info * win_to_scroll,
+ int num_to_scroll)
+{
+ switch (direction)
+ {
+ case FORWARD_SCROLL:
+ tui_scroll_forward (win_to_scroll, num_to_scroll);
+ break;
+ case BACKWARD_SCROLL:
+ tui_scroll_backward (win_to_scroll, num_to_scroll);
+ break;
+ case LEFT_SCROLL:
+ tui_scroll_left (win_to_scroll, num_to_scroll);
+ break;
+ case RIGHT_SCROLL:
+ tui_scroll_right (win_to_scroll, num_to_scroll);
+ break;
+ default:
+ break;
+ }
+}
+
+
+void
+tui_refresh_all_win (void)
+{
+ enum tui_win_type type;
+
+ clearok (curscr, TRUE);
+ tui_refresh_all (tui_win_list);
+ for (type = SRC_WIN; type < MAX_MAJOR_WINDOWS; type++)
+ {
+ if (tui_win_list[type] && tui_win_list[type]->generic.is_visible)
+ {
+ switch (type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ tui_show_source_content (tui_win_list[type]);
+ tui_check_and_display_highlight_if_needed (tui_win_list[type]);
+ tui_erase_exec_info_content (tui_win_list[type]);
+ tui_update_exec_info (tui_win_list[type]);
+ break;
+ case DATA_WIN:
+ tui_refresh_data_win ();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ tui_show_locator_content ();
+}
+
+
+/* Resize all the windows based on the the terminal size. This
+ function gets called from within the readline sinwinch handler. */
+void
+tui_resize_all (void)
+{
+ int height_diff, width_diff;
+ int screenheight, screenwidth;
+
+ rl_get_screen_size (&screenheight, &screenwidth);
+ width_diff = screenwidth - tui_term_width ();
+ height_diff = screenheight - tui_term_height ();
+ if (height_diff || width_diff)
+ {
+ enum tui_layout_type cur_layout = tui_current_layout ();
+ struct tui_win_info * win_with_focus = tui_win_with_focus ();
+ struct tui_win_info *first_win;
+ struct tui_win_info *second_win;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+ enum tui_win_type win_type;
+ int new_height, split_diff, cmd_split_diff, num_wins_displayed = 2;
+
+#ifdef HAVE_RESIZE_TERM
+ resize_term (screenheight, screenwidth);
+#endif
+ /* turn keypad off while we resize */
+ if (win_with_focus != TUI_CMD_WIN)
+ keypad (TUI_CMD_WIN->generic.handle, FALSE);
+ tui_update_gdb_sizes ();
+ tui_set_term_height_to (screenheight);
+ tui_set_term_width_to (screenwidth);
+ if (cur_layout == SRC_DISASSEM_COMMAND ||
+ cur_layout == SRC_DATA_COMMAND || cur_layout == DISASSEM_DATA_COMMAND)
+ num_wins_displayed++;
+ split_diff = height_diff / num_wins_displayed;
+ cmd_split_diff = split_diff;
+ if (height_diff % num_wins_displayed)
+ {
+ if (height_diff < 0)
+ cmd_split_diff--;
+ else
+ cmd_split_diff++;
+ }
+ /* now adjust each window */
+ clear ();
+ refresh ();
+ switch (cur_layout)
+ {
+ case SRC_COMMAND:
+ case DISASSEM_COMMAND:
+ first_win = (struct tui_win_info *) (tui_source_windows ())->list[0];
+ first_win->generic.width += width_diff;
+ locator->width += width_diff;
+ /* check for invalid heights */
+ if (height_diff == 0)
+ new_height = first_win->generic.height;
+ else if ((first_win->generic.height + split_diff) >=
+ (screenheight - MIN_CMD_WIN_HEIGHT - 1))
+ new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
+ else if ((first_win->generic.height + split_diff) <= 0)
+ new_height = MIN_WIN_HEIGHT;
+ else
+ new_height = first_win->generic.height + split_diff;
+
+ make_invisible_and_set_new_height (first_win, new_height);
+ TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
+ TUI_CMD_WIN->generic.width += width_diff;
+ new_height = screenheight - TUI_CMD_WIN->generic.origin.y;
+ make_invisible_and_set_new_height (TUI_CMD_WIN, new_height);
+ make_visible_with_new_height (first_win);
+ make_visible_with_new_height (TUI_CMD_WIN);
+ if (first_win->generic.content_size <= 0)
+ tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT);
+ break;
+ default:
+ if (cur_layout == SRC_DISASSEM_COMMAND)
+ {
+ first_win = TUI_SRC_WIN;
+ first_win->generic.width += width_diff;
+ second_win = TUI_DISASM_WIN;
+ second_win->generic.width += width_diff;
+ }
+ else
+ {
+ first_win = TUI_DATA_WIN;
+ first_win->generic.width += width_diff;
+ second_win = (struct tui_win_info *) (tui_source_windows ())->list[0];
+ second_win->generic.width += width_diff;
+ }
+ /* Change the first window's height/width */
+ /* check for invalid heights */
+ if (height_diff == 0)
+ new_height = first_win->generic.height;
+ else if ((first_win->generic.height +
+ second_win->generic.height + (split_diff * 2)) >=
+ (screenheight - MIN_CMD_WIN_HEIGHT - 1))
+ new_height = (screenheight - MIN_CMD_WIN_HEIGHT - 1) / 2;
+ else if ((first_win->generic.height + split_diff) <= 0)
+ new_height = MIN_WIN_HEIGHT;
+ else
+ new_height = first_win->generic.height + split_diff;
+ make_invisible_and_set_new_height (first_win, new_height);
+
+ locator->width += width_diff;
+
+ /* Change the second window's height/width */
+ /* check for invalid heights */
+ if (height_diff == 0)
+ new_height = second_win->generic.height;
+ else if ((first_win->generic.height +
+ second_win->generic.height + (split_diff * 2)) >=
+ (screenheight - MIN_CMD_WIN_HEIGHT - 1))
+ {
+ new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
+ if (new_height % 2)
+ new_height = (new_height / 2) + 1;
+ else
+ new_height /= 2;
+ }
+ else if ((second_win->generic.height + split_diff) <= 0)
+ new_height = MIN_WIN_HEIGHT;
+ else
+ new_height = second_win->generic.height + split_diff;
+ second_win->generic.origin.y = first_win->generic.height - 1;
+ make_invisible_and_set_new_height (second_win, new_height);
+
+ /* Change the command window's height/width */
+ TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
+ make_invisible_and_set_new_height (
+ TUI_CMD_WIN, TUI_CMD_WIN->generic.height + cmd_split_diff);
+ make_visible_with_new_height (first_win);
+ make_visible_with_new_height (second_win);
+ make_visible_with_new_height (TUI_CMD_WIN);
+ if (first_win->generic.content_size <= 0)
+ tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT);
+ if (second_win->generic.content_size <= 0)
+ tui_erase_source_content (second_win, EMPTY_SOURCE_PROMPT);
+ break;
+ }
+ /*
+ ** Now remove all invisible windows, and their content so that they get
+ ** created again when called for with the new size
+ */
+ for (win_type = SRC_WIN; (win_type < MAX_MAJOR_WINDOWS); win_type++)
+ {
+ if (win_type != CMD_WIN && (tui_win_list[win_type] != NULL)
+ && !tui_win_list[win_type]->generic.is_visible)
+ {
+ tui_free_window (tui_win_list[win_type]);
+ tui_win_list[win_type] = (struct tui_win_info *) NULL;
+ }
+ }
+ tui_set_win_resized_to (TRUE);
+ /* turn keypad back on, unless focus is in the command window */
+ if (win_with_focus != TUI_CMD_WIN)
+ keypad (TUI_CMD_WIN->generic.handle, TRUE);
+ }
+}
+
+
+/* SIGWINCH signal handler for the tui. This signal handler is always
+ called, even when the readline package clears signals because it is
+ set as the old_sigwinch() (TUI only). */
+void
+tui_sigwinch_handler (int signal)
+{
+ /*
+ ** Say that a resize was done so that the readline can do it
+ ** later when appropriate.
+ */
+ tui_set_win_resized_to (TRUE);
+}
+
+
+
+/*************************
+** STATIC LOCAL FUNCTIONS
+**************************/
+
+
+static void
+tui_scroll_forward_command (char *arg, int from_tty)
+{
+ int num_to_scroll = 1;
+ struct tui_win_info * win_to_scroll;
+
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ if (arg == (char *) NULL)
+ parse_scrolling_args (arg, &win_to_scroll, (int *) NULL);
+ else
+ parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
+ tui_scroll (FORWARD_SCROLL, win_to_scroll, num_to_scroll);
+}
+
+
+static void
+tui_scroll_backward_command (char *arg, int from_tty)
+{
+ int num_to_scroll = 1;
+ struct tui_win_info * win_to_scroll;
+
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ if (arg == (char *) NULL)
+ parse_scrolling_args (arg, &win_to_scroll, (int *) NULL);
+ else
+ parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
+ tui_scroll (BACKWARD_SCROLL, win_to_scroll, num_to_scroll);
+}
+
+
+static void
+tui_scroll_left_command (char *arg, int from_tty)
+{
+ int num_to_scroll;
+ struct tui_win_info * win_to_scroll;
+
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
+ tui_scroll (LEFT_SCROLL, win_to_scroll, num_to_scroll);
+}
+
+
+static void
+tui_scroll_right_command (char *arg, int from_tty)
+{
+ int num_to_scroll;
+ struct tui_win_info * win_to_scroll;
+
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
+ tui_scroll (RIGHT_SCROLL, win_to_scroll, num_to_scroll);
+}
+
+
+/* Set focus to the window named by 'arg'. */
+static void
+tui_set_focus (char *arg, int from_tty)
+{
+ if (arg != (char *) NULL)
+ {
+ char *buf_ptr = (char *) xstrdup (arg);
+ int i;
+ struct tui_win_info * win_info = (struct tui_win_info *) NULL;
+
+ for (i = 0; (i < strlen (buf_ptr)); i++)
+ buf_ptr[i] = toupper (arg[i]);
+
+ if (subset_compare (buf_ptr, "NEXT"))
+ win_info = tui_next_win (tui_win_with_focus ());
+ else if (subset_compare (buf_ptr, "PREV"))
+ win_info = tui_prev_win (tui_win_with_focus ());
+ else
+ win_info = tui_partial_win_by_name (buf_ptr);
+
+ if (win_info == (struct tui_win_info *) NULL || !win_info->generic.is_visible)
+ warning ("Invalid window specified. \n\
+The window name specified must be valid and visible.\n");
+ else
+ {
+ tui_set_win_focus_to (win_info);
+ keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN));
+ }
+
+ if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible)
+ tui_refresh_data_win ();
+ xfree (buf_ptr);
+ printf_filtered ("Focus set to %s window.\n",
+ tui_win_name ((struct tui_gen_win_info *) tui_win_with_focus ()));
+ }
+ else
+ warning ("Incorrect Number of Arguments.\n%s", FOCUS_USAGE);
+}
+
+static void
+tui_set_focus_command (char *arg, int from_tty)
+{
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ tui_set_focus (arg, from_tty);
+}
+
+
+static void
+tui_all_windows_info (char *arg, int from_tty)
+{
+ enum tui_win_type type;
+ struct tui_win_info * win_with_focus = tui_win_with_focus ();
+
+ for (type = SRC_WIN; (type < MAX_MAJOR_WINDOWS); type++)
+ if (tui_win_list[type] && tui_win_list[type]->generic.is_visible)
+ {
+ if (win_with_focus == tui_win_list[type])
+ printf_filtered (" %s\t(%d lines) <has focus>\n",
+ tui_win_name (&tui_win_list[type]->generic),
+ tui_win_list[type]->generic.height);
+ else
+ printf_filtered (" %s\t(%d lines)\n",
+ tui_win_name (&tui_win_list[type]->generic),
+ tui_win_list[type]->generic.height);
+ }
+}
+
+
+static void
+tui_refresh_all_command (char *arg, int from_tty)
+{
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+
+ tui_refresh_all_win ();
+}
+
+
+/* Set the height of the specified window. */
+static void
+tui_set_tab_width_command (char *arg, int from_tty)
+{
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ if (arg != (char *) NULL)
+ {
+ int ts;
+
+ ts = atoi (arg);
+ if (ts > 0)
+ tui_set_default_tab_len (ts);
+ else
+ warning ("Tab widths greater than 0 must be specified.\n");
+ }
+}
+
+
+/* Set the height of the specified window. */
+static void
+tui_set_win_height (char *arg, int from_tty)
+{
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ if (arg != (char *) NULL)
+ {
+ char *buf = xstrdup (arg);
+ char *buf_ptr = buf;
+ char *wname = (char *) NULL;
+ int new_height, i;
+ struct tui_win_info * win_info;
+
+ wname = buf_ptr;
+ buf_ptr = strchr (buf_ptr, ' ');
+ if (buf_ptr != (char *) NULL)
+ {
+ *buf_ptr = (char) 0;
+
+ /*
+ ** Validate the window name
+ */
+ for (i = 0; i < strlen (wname); i++)
+ wname[i] = toupper (wname[i]);
+ win_info = tui_partial_win_by_name (wname);
+
+ if (win_info == (struct tui_win_info *) NULL || !win_info->generic.is_visible)
+ warning ("Invalid window specified. \n\
+The window name specified must be valid and visible.\n");
+ else
+ {
+ /* Process the size */
+ while (*(++buf_ptr) == ' ')
+ ;
+
+ if (*buf_ptr != (char) 0)
+ {
+ int negate = FALSE;
+ int fixed_size = TRUE;
+ int input_no;;
+
+ if (*buf_ptr == '+' || *buf_ptr == '-')
+ {
+ if (*buf_ptr == '-')
+ negate = TRUE;
+ fixed_size = FALSE;
+ buf_ptr++;
+ }
+ input_no = atoi (buf_ptr);
+ if (input_no > 0)
+ {
+ if (negate)
+ input_no *= (-1);
+ if (fixed_size)
+ new_height = input_no;
+ else
+ new_height = win_info->generic.height + input_no;
+ /*
+ ** Now change the window's height, and adjust all
+ ** other windows around it
+ */
+ if (tui_adjust_win_heights (win_info,
+ new_height) == TUI_FAILURE)
+ warning ("Invalid window height specified.\n%s",
+ WIN_HEIGHT_USAGE);
+ else
+ tui_update_gdb_sizes ();
+ }
+ else
+ warning ("Invalid window height specified.\n%s",
+ WIN_HEIGHT_USAGE);
+ }
+ }
+ }
+ else
+ printf_filtered (WIN_HEIGHT_USAGE);
+
+ if (buf != (char *) NULL)
+ xfree (buf);
+ }
+ else
+ printf_filtered (WIN_HEIGHT_USAGE);
+}
+
+/* Set the height of the specified window, with va_list. */
+static void
+tui_set_win_height_command (char *arg, int from_tty)
+{
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ tui_set_win_height (arg, from_tty);
+}
+
+
+/* XDB Compatibility command for setting the window height. This will
+ increase or decrease the command window by the specified amount. */
+static void
+tui_xdb_set_win_height (char *arg, int from_tty)
+{
+ /* Make sure the curses mode is enabled. */
+ tui_enable ();
+ if (arg != (char *) NULL)
+ {
+ int input_no = atoi (arg);
+
+ if (input_no > 0)
+ { /* Add 1 for the locator */
+ int new_height = tui_term_height () - (input_no + 1);
+
+ if (!new_height_ok (tui_win_list[CMD_WIN], new_height) ||
+ tui_adjust_win_heights (tui_win_list[CMD_WIN],
+ new_height) == TUI_FAILURE)
+ warning ("Invalid window height specified.\n%s",
+ XDBWIN_HEIGHT_USAGE);
+ }
+ else
+ warning ("Invalid window height specified.\n%s",
+ XDBWIN_HEIGHT_USAGE);
+ }
+ else
+ warning ("Invalid window height specified.\n%s", XDBWIN_HEIGHT_USAGE);
+}
+
+/* Set the height of the specified window, with va_list. */
+static void
+tui_xdb_set_win_height_command (char *arg, int from_tty)
+{
+ tui_xdb_set_win_height (arg, from_tty);
+}
+
+
+/* Function to adjust all window heights around the primary. */
+static enum tui_status
+tui_adjust_win_heights (struct tui_win_info * primary_win_info, int new_height)
+{
+ enum tui_status status = TUI_FAILURE;
+
+ if (new_height_ok (primary_win_info, new_height))
+ {
+ status = TUI_SUCCESS;
+ if (new_height != primary_win_info->generic.height)
+ {
+ int diff;
+ struct tui_win_info * win_info;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+ enum tui_layout_type cur_layout = tui_current_layout ();
+
+ diff = (new_height - primary_win_info->generic.height) * (-1);
+ if (cur_layout == SRC_COMMAND || cur_layout == DISASSEM_COMMAND)
+ {
+ struct tui_win_info * src_win_info;
+
+ make_invisible_and_set_new_height (primary_win_info, new_height);
+ if (primary_win_info->generic.type == CMD_WIN)
+ {
+ win_info = (struct tui_win_info *) (tui_source_windows ())->list[0];
+ src_win_info = win_info;
+ }
+ else
+ {
+ win_info = tui_win_list[CMD_WIN];
+ src_win_info = primary_win_info;
+ }
+ make_invisible_and_set_new_height (win_info,
+ win_info->generic.height + diff);
+ TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
+ make_visible_with_new_height (win_info);
+ make_visible_with_new_height (primary_win_info);
+ if (src_win_info->generic.content_size <= 0)
+ tui_erase_source_content (src_win_info, EMPTY_SOURCE_PROMPT);
+ }
+ else
+ {
+ struct tui_win_info *first_win;
+ struct tui_win_info *second_win;
+
+ if (cur_layout == SRC_DISASSEM_COMMAND)
+ {
+ first_win = TUI_SRC_WIN;
+ second_win = TUI_DISASM_WIN;
+ }
+ else
+ {
+ first_win = TUI_DATA_WIN;
+ second_win = (struct tui_win_info *) (tui_source_windows ())->list[0];
+ }
+ if (primary_win_info == TUI_CMD_WIN)
+ { /*
+ ** Split the change in height accross the 1st & 2nd windows
+ ** adjusting them as well.
+ */
+ int first_split_diff = diff / 2; /* subtract the locator */
+ int second_split_diff = first_split_diff;
+
+ if (diff % 2)
+ {
+ if (first_win->generic.height >
+ second_win->generic.height)
+ if (diff < 0)
+ first_split_diff--;
+ else
+ first_split_diff++;
+ else
+ {
+ if (diff < 0)
+ second_split_diff--;
+ else
+ second_split_diff++;
+ }
+ }
+ /* make sure that the minimum hieghts are honored */
+ while ((first_win->generic.height + first_split_diff) < 3)
+ {
+ first_split_diff++;
+ second_split_diff--;
+ }
+ while ((second_win->generic.height + second_split_diff) < 3)
+ {
+ second_split_diff++;
+ first_split_diff--;
+ }
+ make_invisible_and_set_new_height (
+ first_win,
+ first_win->generic.height + first_split_diff);
+ second_win->generic.origin.y = first_win->generic.height - 1;
+ make_invisible_and_set_new_height (
+ second_win, second_win->generic.height + second_split_diff);
+ TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
+ make_invisible_and_set_new_height (TUI_CMD_WIN, new_height);
+ }
+ else
+ {
+ if ((TUI_CMD_WIN->generic.height + diff) < 1)
+ { /*
+ ** If there is no way to increase the command window
+ ** take real estate from the 1st or 2nd window.
+ */
+ if ((TUI_CMD_WIN->generic.height + diff) < 1)
+ {
+ int i;
+ for (i = TUI_CMD_WIN->generic.height + diff;
+ (i < 1); i++)
+ if (primary_win_info == first_win)
+ second_win->generic.height--;
+ else
+ first_win->generic.height--;
+ }
+ }
+ if (primary_win_info == first_win)
+ make_invisible_and_set_new_height (first_win, new_height);
+ else
+ make_invisible_and_set_new_height (
+ first_win,
+ first_win->generic.height);
+ second_win->generic.origin.y = first_win->generic.height - 1;
+ if (primary_win_info == second_win)
+ make_invisible_and_set_new_height (second_win, new_height);
+ else
+ make_invisible_and_set_new_height (
+ second_win, second_win->generic.height);
+ TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
+ if ((TUI_CMD_WIN->generic.height + diff) < 1)
+ make_invisible_and_set_new_height (TUI_CMD_WIN, 1);
+ else
+ make_invisible_and_set_new_height (
+ TUI_CMD_WIN, TUI_CMD_WIN->generic.height + diff);
+ }
+ make_visible_with_new_height (TUI_CMD_WIN);
+ make_visible_with_new_height (second_win);
+ make_visible_with_new_height (first_win);
+ if (first_win->generic.content_size <= 0)
+ tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT);
+ if (second_win->generic.content_size <= 0)
+ tui_erase_source_content (second_win, EMPTY_SOURCE_PROMPT);
+ }
+ }
+ }
+
+ return status;
+}
+
+
+/* Function make the target window (and auxillary windows associated
+ with the targer) invisible, and set the new height and location. */
+static void
+make_invisible_and_set_new_height (struct tui_win_info * win_info, int height)
+{
+ int i;
+ struct tui_gen_win_info * gen_win_info;
+
+ tui_make_invisible (&win_info->generic);
+ win_info->generic.height = height;
+ if (height > 1)
+ win_info->generic.viewport_height = height - 1;
+ else
+ win_info->generic.viewport_height = height;
+ if (win_info != TUI_CMD_WIN)
+ win_info->generic.viewport_height--;
+
+ /* Now deal with the auxillary windows associated with win_info */
+ switch (win_info->generic.type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ gen_win_info = win_info->detail.source_info.execution_info;
+ tui_make_invisible (gen_win_info);
+ gen_win_info->height = height;
+ gen_win_info->origin.y = win_info->generic.origin.y;
+ if (height > 1)
+ gen_win_info->viewport_height = height - 1;
+ else
+ gen_win_info->viewport_height = height;
+ if (win_info != TUI_CMD_WIN)
+ gen_win_info->viewport_height--;
+
+ if (tui_win_has_locator (win_info))
+ {
+ gen_win_info = tui_locator_win_info_ptr ();
+ tui_make_invisible (gen_win_info);
+ gen_win_info->origin.y = win_info->generic.origin.y + height;
+ }
+ break;
+ case DATA_WIN:
+ /* delete all data item windows */
+ for (i = 0; i < win_info->generic.content_size; i++)
+ {
+ gen_win_info = (struct tui_gen_win_info *) & ((struct tui_win_element *)
+ win_info->generic.content[i])->which_element.data_window;
+ tui_delete_win (gen_win_info->handle);
+ gen_win_info->handle = (WINDOW *) NULL;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* Function to make the windows with new heights visible. This means
+ re-creating the windows' content since the window had to be
+ destroyed to be made invisible. */
+static void
+make_visible_with_new_height (struct tui_win_info * win_info)
+{
+ struct symtab *s;
+
+ tui_make_visible (&win_info->generic);
+ tui_check_and_display_highlight_if_needed (win_info);
+ switch (win_info->generic.type)
+ {
+ case SRC_WIN:
+ case DISASSEM_WIN:
+ tui_free_win_content (win_info->detail.source_info.execution_info);
+ tui_make_visible (win_info->detail.source_info.execution_info);
+ if (win_info->generic.content != NULL)
+ {
+ union tui_line_or_address line_or_addr;
+ struct symtab_and_line cursal
+ = get_current_source_symtab_and_line ();
+
+ if (win_info->generic.type == SRC_WIN)
+ line_or_addr.line_no =
+ win_info->detail.source_info.start_line_or_addr.line_no;
+ else
+ line_or_addr.addr =
+ win_info->detail.source_info.start_line_or_addr.addr;
+ tui_free_win_content (&win_info->generic);
+ tui_update_source_window (win_info, cursal.symtab, line_or_addr, TRUE);
+ }
+ else if (deprecated_selected_frame != (struct frame_info *) NULL)
+ {
+ union tui_line_or_address line;
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+
+ s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
+ if (win_info->generic.type == SRC_WIN)
+ line.line_no = cursal.line;
+ else
+ {
+ find_line_pc (s, cursal.line, &line.addr);
+ }
+ tui_update_source_window (win_info, s, line, TRUE);
+ }
+ if (tui_win_has_locator (win_info))
+ {
+ tui_make_visible (tui_locator_win_info_ptr ());
+ tui_show_locator_content ();
+ }
+ break;
+ case DATA_WIN:
+ tui_display_all_data ();
+ break;
+ case CMD_WIN:
+ win_info->detail.command_info.cur_line = 0;
+ win_info->detail.command_info.curch = 0;
+ wmove (win_info->generic.handle,
+ win_info->detail.command_info.cur_line,
+ win_info->detail.command_info.curch);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static int
+new_height_ok (struct tui_win_info * primary_win_info, int new_height)
+{
+ int ok = (new_height < tui_term_height ());
+
+ if (ok)
+ {
+ int diff;
+ enum tui_layout_type cur_layout = tui_current_layout ();
+
+ diff = (new_height - primary_win_info->generic.height) * (-1);
+ if (cur_layout == SRC_COMMAND || cur_layout == DISASSEM_COMMAND)
+ {
+ ok = ((primary_win_info->generic.type == CMD_WIN &&
+ new_height <= (tui_term_height () - 4) &&
+ new_height >= MIN_CMD_WIN_HEIGHT) ||
+ (primary_win_info->generic.type != CMD_WIN &&
+ new_height <= (tui_term_height () - 2) &&
+ new_height >= MIN_WIN_HEIGHT));
+ if (ok)
+ { /* check the total height */
+ struct tui_win_info * win_info;
+
+ if (primary_win_info == TUI_CMD_WIN)
+ win_info = (struct tui_win_info *) (tui_source_windows ())->list[0];
+ else
+ win_info = TUI_CMD_WIN;
+ ok = ((new_height +
+ (win_info->generic.height + diff)) <= tui_term_height ());
+ }
+ }
+ else
+ {
+ int cur_total_height, total_height, min_height = 0;
+ struct tui_win_info *first_win;
+ struct tui_win_info *second_win;
+
+ if (cur_layout == SRC_DISASSEM_COMMAND)
+ {
+ first_win = TUI_SRC_WIN;
+ second_win = TUI_DISASM_WIN;
+ }
+ else
+ {
+ first_win = TUI_DATA_WIN;
+ second_win = (struct tui_win_info *) (tui_source_windows ())->list[0];
+ }
+ /*
+ ** We could simply add all the heights to obtain the same result
+ ** but below is more explicit since we subtract 1 for the
+ ** line that the first and second windows share, and add one
+ ** for the locator.
+ */
+ total_height = cur_total_height =
+ (first_win->generic.height + second_win->generic.height - 1)
+ + TUI_CMD_WIN->generic.height + 1 /*locator */ ;
+ if (primary_win_info == TUI_CMD_WIN)
+ {
+ /* locator included since first & second win share a line */
+ ok = ((first_win->generic.height +
+ second_win->generic.height + diff) >=
+ (MIN_WIN_HEIGHT * 2) &&
+ new_height >= MIN_CMD_WIN_HEIGHT);
+ if (ok)
+ {
+ total_height = new_height + (first_win->generic.height +
+ second_win->generic.height + diff);
+ min_height = MIN_CMD_WIN_HEIGHT;
+ }
+ }
+ else
+ {
+ min_height = MIN_WIN_HEIGHT;
+ /*
+ ** First see if we can increase/decrease the command
+ ** window. And make sure that the command window is
+ ** at least 1 line
+ */
+ ok = ((TUI_CMD_WIN->generic.height + diff) > 0);
+ if (!ok)
+ { /*
+ ** Looks like we have to increase/decrease one of
+ ** the other windows
+ */
+ if (primary_win_info == first_win)
+ ok = (second_win->generic.height + diff) >= min_height;
+ else
+ ok = (first_win->generic.height + diff) >= min_height;
+ }
+ if (ok)
+ {
+ if (primary_win_info == first_win)
+ total_height = new_height +
+ second_win->generic.height +
+ TUI_CMD_WIN->generic.height + diff;
+ else
+ total_height = new_height +
+ first_win->generic.height +
+ TUI_CMD_WIN->generic.height + diff;
+ }
+ }
+ /*
+ ** Now make sure that the proposed total height doesn't exceed
+ ** the old total height.
+ */
+ if (ok)
+ ok = (new_height >= min_height && total_height <= cur_total_height);
+ }
+ }
+
+ return ok;
+}
+
+
+static void
+parse_scrolling_args (char *arg, struct tui_win_info * * win_to_scroll,
+ int *num_to_scroll)
+{
+ if (num_to_scroll)
+ *num_to_scroll = 0;
+ *win_to_scroll = tui_win_with_focus ();
+
+ /*
+ ** First set up the default window to scroll, in case there is no
+ ** window name arg
+ */
+ if (arg != (char *) NULL)
+ {
+ char *buf, *buf_ptr;
+
+ /* process the number of lines to scroll */
+ buf = buf_ptr = xstrdup (arg);
+ if (isdigit (*buf_ptr))
+ {
+ char *num_str;
+
+ num_str = buf_ptr;
+ buf_ptr = strchr (buf_ptr, ' ');
+ if (buf_ptr != (char *) NULL)
+ {
+ *buf_ptr = (char) 0;
+ if (num_to_scroll)
+ *num_to_scroll = atoi (num_str);
+ buf_ptr++;
+ }
+ else if (num_to_scroll)
+ *num_to_scroll = atoi (num_str);
+ }
+
+ /* process the window name if one is specified */
+ if (buf_ptr != (char *) NULL)
+ {
+ char *wname;
+ int i;
+
+ if (*buf_ptr == ' ')
+ while (*(++buf_ptr) == ' ')
+ ;
+
+ if (*buf_ptr != (char) 0)
+ wname = buf_ptr;
+ else
+ wname = "?";
+
+ /* Validate the window name */
+ for (i = 0; i < strlen (wname); i++)
+ wname[i] = toupper (wname[i]);
+ *win_to_scroll = tui_partial_win_by_name (wname);
+
+ if (*win_to_scroll == (struct tui_win_info *) NULL ||
+ !(*win_to_scroll)->generic.is_visible)
+ warning ("Invalid window specified. \n\
+The window name specified must be valid and visible.\n");
+ else if (*win_to_scroll == TUI_CMD_WIN)
+ *win_to_scroll = (struct tui_win_info *) (tui_source_windows ())->list[0];
+ }
+ xfree (buf);
+ }
+}
diff --git a/contrib/gdb/gdb/tui/tui-win.h b/contrib/gdb/gdb/tui/tui-win.h
new file mode 100644
index 0000000..1e9b86f
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-win.h
@@ -0,0 +1,59 @@
+/* TUI window generic functions.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_WIN_H
+#define TUI_WIN_H
+
+#include "tui/tui-data.h"
+
+struct tui_win_info;
+
+extern void tui_scroll_forward (struct tui_win_info *, int);
+extern void tui_scroll_backward (struct tui_win_info *, int);
+extern void tui_scroll_left (struct tui_win_info *, int);
+extern void tui_scroll_right (struct tui_win_info *, int);
+extern void tui_scroll (enum tui_scroll_direction, struct tui_win_info *, int);
+extern void tui_set_win_focus_to (struct tui_win_info *);
+extern void tui_resize_all (void);
+extern void tui_refresh_all_win (void);
+extern void tui_sigwinch_handler (int);
+
+extern chtype tui_border_ulcorner;
+extern chtype tui_border_urcorner;
+extern chtype tui_border_lrcorner;
+extern chtype tui_border_llcorner;
+extern chtype tui_border_vline;
+extern chtype tui_border_hline;
+extern int tui_border_attrs;
+extern int tui_active_border_attrs;
+
+extern int tui_update_variables (void);
+
+/* Update gdb's knowledge of the terminal size. */
+extern void tui_update_gdb_sizes (void);
+
+/* Create or get the TUI command list. */
+struct cmd_list_element **tui_get_cmd_list ();
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-windata.c b/contrib/gdb/gdb/tui/tui-windata.c
new file mode 100644
index 0000000..3c98cf6
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-windata.c
@@ -0,0 +1,304 @@
+/* Data/register window display.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-regs.h"
+
+#include "gdb_string.h"
+#include "gdb_curses.h"
+
+
+/*****************************************
+** STATIC LOCAL FUNCTIONS FORWARD DECLS **
+******************************************/
+
+
+
+/*****************************************
+** PUBLIC FUNCTIONS **
+******************************************/
+
+
+/* Answer the index first element displayed. If none are displayed,
+ then return (-1). */
+int
+tui_first_data_item_displayed (void)
+{
+ int element_no = (-1);
+ int i;
+
+ for (i = 0; (i < TUI_DATA_WIN->generic.content_size && element_no < 0); i++)
+ {
+ struct tui_gen_win_info * data_item_win;
+
+ data_item_win = &((tui_win_content)
+ TUI_DATA_WIN->generic.content)[i]->which_element.data_window;
+ if (data_item_win->handle != (WINDOW *) NULL && data_item_win->is_visible)
+ element_no = i;
+ }
+
+ return element_no;
+}
+
+
+/* Answer the index of the first element in line_no. If line_no is
+ past the data area (-1) is returned. */
+int
+tui_first_data_element_no_in_line (int line_no)
+{
+ int first_element_no = (-1);
+
+ /*
+ ** First see if there is a register on line_no, and if so, set the
+ ** first element number
+ */
+ if ((first_element_no = tui_first_reg_element_no_inline (line_no)) == -1)
+ { /*
+ ** Looking at the general data, the 1st element on line_no
+ */
+ }
+
+ return first_element_no;
+}
+
+
+/* Function to delete all the item windows in the data window. This
+ is usually done when the data window is scrolled. */
+void
+tui_delete_data_content_windows (void)
+{
+ int i;
+ struct tui_gen_win_info * data_item_win_ptr;
+
+ for (i = 0; (i < TUI_DATA_WIN->generic.content_size); i++)
+ {
+ data_item_win_ptr = &((tui_win_content)
+ TUI_DATA_WIN->generic.content)[i]->which_element.data_window;
+ tui_delete_win (data_item_win_ptr->handle);
+ data_item_win_ptr->handle = (WINDOW *) NULL;
+ data_item_win_ptr->is_visible = FALSE;
+ }
+}
+
+
+void
+tui_erase_data_content (char *prompt)
+{
+ werase (TUI_DATA_WIN->generic.handle);
+ tui_check_and_display_highlight_if_needed (TUI_DATA_WIN);
+ if (prompt != (char *) NULL)
+ {
+ int half_width = (TUI_DATA_WIN->generic.width - 2) / 2;
+ int x_pos;
+
+ if (strlen (prompt) >= half_width)
+ x_pos = 1;
+ else
+ x_pos = half_width - strlen (prompt);
+ mvwaddstr (TUI_DATA_WIN->generic.handle,
+ (TUI_DATA_WIN->generic.height / 2),
+ x_pos,
+ prompt);
+ }
+ wrefresh (TUI_DATA_WIN->generic.handle);
+}
+
+
+/* This function displays the data that is in the data window's
+ content. It does not set the content. */
+void
+tui_display_all_data (void)
+{
+ if (TUI_DATA_WIN->generic.content_size <= 0)
+ tui_erase_data_content (NO_DATA_STRING);
+ else
+ {
+ tui_erase_data_content ((char *) NULL);
+ tui_delete_data_content_windows ();
+ tui_check_and_display_highlight_if_needed (TUI_DATA_WIN);
+ tui_display_registers_from (0);
+ /*
+ ** Then display the other data
+ */
+ if (TUI_DATA_WIN->detail.data_display_info.data_content !=
+ (tui_win_content) NULL &&
+ TUI_DATA_WIN->detail.data_display_info.data_content_count > 0)
+ {
+ }
+ }
+}
+
+
+/* Function to display the data starting at line, line_no, in the data
+ window. */
+void
+tui_display_data_from_line (int line_no)
+{
+ int _line_no = line_no;
+
+ if (line_no < 0)
+ _line_no = 0;
+
+ tui_check_and_display_highlight_if_needed (TUI_DATA_WIN);
+
+ /* there is no general data, force regs to display (if there are any) */
+ if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0)
+ tui_display_registers_from_line (_line_no, TRUE);
+ else
+ {
+ int element_no, start_line_no;
+ int regs_last_line = tui_last_regs_line_no ();
+
+
+ /* display regs if we can */
+ if (tui_display_registers_from_line (_line_no, FALSE) < 0)
+ { /*
+ ** _line_no is past the regs display, so calc where the
+ ** start data element is
+ */
+ if (regs_last_line < _line_no)
+ { /* figure out how many lines each element is to obtain
+ the start element_no */
+ }
+ }
+ else
+ { /*
+ ** calculate the starting element of the data display, given
+ ** regs_last_line and how many lines each element is, up to
+ ** _line_no
+ */
+ }
+ /* Now display the data , starting at element_no */
+ }
+}
+
+
+/* Display data starting at element element_no. */
+void
+tui_display_data_from (int element_no, int reuse_windows)
+{
+ int first_line = (-1);
+
+ if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
+ first_line = tui_line_from_reg_element_no (element_no);
+ else
+ { /* calculate the first_line from the element number */
+ }
+
+ if (first_line >= 0)
+ {
+ tui_erase_data_content ((char *) NULL);
+ if (!reuse_windows)
+ tui_delete_data_content_windows ();
+ tui_display_data_from_line (first_line);
+ }
+}
+
+
+/* Function to redisplay the contents of the data window. */
+void
+tui_refresh_data_win (void)
+{
+ tui_erase_data_content ((char *) NULL);
+ if (TUI_DATA_WIN->generic.content_size > 0)
+ {
+ int first_element = tui_first_data_item_displayed ();
+
+ if (first_element >= 0) /* re-use existing windows */
+ tui_display_data_from (first_element, TRUE);
+ }
+}
+
+
+/* Function to check the data values and hilite any that have changed. */
+void
+tui_check_data_values (struct frame_info *frame)
+{
+ tui_check_register_values (frame);
+
+ /* Now check any other data values that there are */
+ if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible)
+ {
+ int i;
+
+ for (i = 0; TUI_DATA_WIN->detail.data_display_info.data_content_count; i++)
+ {
+#ifdef LATER
+ tui_data_element_ptr data_element_ptr;
+ struct tui_gen_win_info * data_item_win_ptr;
+ Opaque new_value;
+
+ data_item_ptr = &TUI_DATA_WIN->detail.data_display_info.
+ data_content[i]->which_element.data_window;
+ data_element_ptr = &((tui_win_content)
+ data_item_win_ptr->content)[0]->which_element.data;
+ if value
+ has changed (data_element_ptr, frame, &new_value)
+ {
+ data_element_ptr->value = new_value;
+ update the display with the new value, hiliting it.
+ }
+#endif
+ }
+ }
+}
+
+
+/* Scroll the data window vertically forward or backward. */
+void
+tui_vertical_data_scroll (enum tui_scroll_direction scroll_direction, int num_to_scroll)
+{
+ int first_element_no;
+ int first_line = (-1);
+
+ first_element_no = tui_first_data_item_displayed ();
+ if (first_element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
+ first_line = tui_line_from_reg_element_no (first_element_no);
+ else
+ { /* calculate the first line from the element number which is in
+ ** the general data content
+ */
+ }
+
+ if (first_line >= 0)
+ {
+ int last_element_no, last_line;
+
+ if (scroll_direction == FORWARD_SCROLL)
+ first_line += num_to_scroll;
+ else
+ first_line -= num_to_scroll;
+ tui_erase_data_content ((char *) NULL);
+ tui_delete_data_content_windows ();
+ tui_display_data_from_line (first_line);
+ }
+}
+
+
+/*****************************************
+** STATIC LOCAL FUNCTIONS **
+******************************************/
diff --git a/contrib/gdb/gdb/tui/tui-windata.h b/contrib/gdb/gdb/tui/tui-windata.h
new file mode 100644
index 0000000..10123a3
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-windata.h
@@ -0,0 +1,41 @@
+/* Data/register window display.
+
+ Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation,
+ Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_WINDATA_H
+#define TUI_WINDATA_H
+
+#include "tui/tui-data.h"
+
+extern void tui_erase_data_content (char *);
+extern void tui_display_all_data (void);
+extern void tui_check_data_values (struct frame_info *);
+extern void tui_display_data_from_line (int);
+extern int tui_first_data_item_displayed (void);
+extern int tui_first_data_element_no_in_line (int);
+extern void tui_delete_data_content_windows (void);
+extern void tui_refresh_data_win (void);
+extern void tui_display_data_from (int, int);
+extern void tui_vertical_data_scroll (enum tui_scroll_direction, int);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-wingeneral.c b/contrib/gdb/gdb/tui/tui-wingeneral.c
new file mode 100644
index 0000000..3dc62d5
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-wingeneral.c
@@ -0,0 +1,276 @@
+/* General window behavior.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
+ Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-win.h"
+
+#include "gdb_curses.h"
+
+/***********************
+** PUBLIC FUNCTIONS
+***********************/
+
+/* Refresh the window. */
+void
+tui_refresh_win (struct tui_gen_win_info * win_info)
+{
+ if (win_info->type == DATA_WIN && win_info->content_size > 0)
+ {
+ int i;
+
+ for (i = 0; (i < win_info->content_size); i++)
+ {
+ struct tui_gen_win_info * data_item_win_ptr;
+
+ data_item_win_ptr = &((tui_win_content)
+ win_info->content)[i]->which_element.data_window;
+ if (data_item_win_ptr != NULL
+ && data_item_win_ptr->handle != (WINDOW *) NULL)
+ wrefresh (data_item_win_ptr->handle);
+ }
+ }
+ else if (win_info->type == CMD_WIN)
+ {
+ /* Do nothing */
+ }
+ else
+ {
+ if (win_info->handle != (WINDOW *) NULL)
+ wrefresh (win_info->handle);
+ }
+
+ return;
+}
+
+
+/* Function to delete the curses window, checking for NULL. */
+void
+tui_delete_win (WINDOW * window)
+{
+ if (window != (WINDOW *) NULL)
+ delwin (window);
+
+ return;
+}
+
+
+/* Draw a border arround the window. */
+void
+box_win (struct tui_gen_win_info * win_info, int highlight_flag)
+{
+ if (win_info && win_info->handle)
+ {
+ WINDOW *win;
+ int attrs;
+
+ win = win_info->handle;
+ if (highlight_flag == HILITE)
+ attrs = tui_active_border_attrs;
+ else
+ attrs = tui_border_attrs;
+
+ wattron (win, attrs);
+ wborder (win, tui_border_vline, tui_border_vline,
+ tui_border_hline, tui_border_hline,
+ tui_border_ulcorner, tui_border_urcorner,
+ tui_border_llcorner, tui_border_lrcorner);
+ if (win_info->title)
+ mvwaddstr (win, 0, 3, win_info->title);
+ wattroff (win, attrs);
+ }
+}
+
+
+void
+tui_unhighlight_win (struct tui_win_info * win_info)
+{
+ if (win_info != NULL && win_info->generic.handle != (WINDOW *) NULL)
+ {
+ box_win ((struct tui_gen_win_info *) win_info, NO_HILITE);
+ wrefresh (win_info->generic.handle);
+ tui_set_win_highlight (win_info, 0);
+ }
+}
+
+
+void
+tui_highlight_win (struct tui_win_info * win_info)
+{
+ if (win_info != NULL
+ && win_info->can_highlight
+ && win_info->generic.handle != (WINDOW *) NULL)
+ {
+ box_win ((struct tui_gen_win_info *) win_info, HILITE);
+ wrefresh (win_info->generic.handle);
+ tui_set_win_highlight (win_info, 1);
+ }
+}
+
+void
+tui_check_and_display_highlight_if_needed (struct tui_win_info * win_info)
+{
+ if (win_info != NULL && win_info->generic.type != CMD_WIN)
+ {
+ if (win_info->is_highlighted)
+ tui_highlight_win (win_info);
+ else
+ tui_unhighlight_win (win_info);
+
+ }
+ return;
+}
+
+
+void
+tui_make_window (struct tui_gen_win_info * win_info, int box_it)
+{
+ WINDOW *handle;
+
+ handle = newwin (win_info->height,
+ win_info->width,
+ win_info->origin.y,
+ win_info->origin.x);
+ win_info->handle = handle;
+ if (handle != (WINDOW *) NULL)
+ {
+ if (box_it == BOX_WINDOW)
+ box_win (win_info, NO_HILITE);
+ win_info->is_visible = TRUE;
+ scrollok (handle, TRUE);
+ }
+}
+
+
+/* We can't really make windows visible, or invisible. So we have to
+ delete the entire window when making it visible, and create it
+ again when making it visible. */
+static void
+make_visible (struct tui_gen_win_info *win_info, int visible)
+{
+ /* Don't tear down/recreate command window */
+ if (win_info->type == CMD_WIN)
+ return;
+
+ if (visible)
+ {
+ if (!win_info->is_visible)
+ {
+ tui_make_window (win_info,
+ (win_info->type != CMD_WIN
+ && !tui_win_is_auxillary (win_info->type)));
+ win_info->is_visible = TRUE;
+ }
+ }
+ else if (!visible &&
+ win_info->is_visible && win_info->handle != (WINDOW *) NULL)
+ {
+ win_info->is_visible = FALSE;
+ tui_delete_win (win_info->handle);
+ win_info->handle = (WINDOW *) NULL;
+ }
+
+ return;
+}
+
+void
+tui_make_visible (struct tui_gen_win_info *win_info)
+{
+ make_visible (win_info, 1);
+}
+
+void
+tui_make_invisible (struct tui_gen_win_info *win_info)
+{
+ make_visible (win_info, 0);
+}
+
+
+/* Makes all windows invisible (except the command and locator windows). */
+static void
+make_all_visible (int visible)
+{
+ int i;
+
+ for (i = 0; i < MAX_MAJOR_WINDOWS; i++)
+ {
+ if (tui_win_list[i] != NULL
+ && ((tui_win_list[i])->generic.type) != CMD_WIN)
+ {
+ if (tui_win_is_source_type ((tui_win_list[i])->generic.type))
+ make_visible ((tui_win_list[i])->detail.source_info.execution_info,
+ visible);
+ make_visible ((struct tui_gen_win_info *) tui_win_list[i], visible);
+ }
+ }
+
+ return;
+}
+
+void
+tui_make_all_visible (void)
+{
+ make_all_visible (1);
+}
+
+void
+tui_make_all_invisible (void)
+{
+ make_all_visible (0);
+}
+
+/* Function to refresh all the windows currently displayed. */
+
+void
+tui_refresh_all (struct tui_win_info * * list)
+{
+ enum tui_win_type type;
+ struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
+
+ for (type = SRC_WIN; (type < MAX_MAJOR_WINDOWS); type++)
+ {
+ if (list[type] && list[type]->generic.is_visible)
+ {
+ if (type == SRC_WIN || type == DISASSEM_WIN)
+ {
+ touchwin (list[type]->detail.source_info.execution_info->handle);
+ tui_refresh_win (list[type]->detail.source_info.execution_info);
+ }
+ touchwin (list[type]->generic.handle);
+ tui_refresh_win (&list[type]->generic);
+ }
+ }
+ if (locator->is_visible)
+ {
+ touchwin (locator->handle);
+ tui_refresh_win (locator);
+ }
+}
+
+
+/*********************************
+** Local Static Functions
+*********************************/
diff --git a/contrib/gdb/gdb/tui/tui-wingeneral.h b/contrib/gdb/gdb/tui/tui-wingeneral.h
new file mode 100644
index 0000000..306d794
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-wingeneral.h
@@ -0,0 +1,45 @@
+/* General window behavior.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_WINGENERAL_H
+#define TUI_WINGENERAL_H
+
+struct tui_win_info;
+struct tui_gen_win_info;
+
+extern void tui_unhighlight_win (struct tui_win_info *);
+extern void tui_make_visible (struct tui_gen_win_info *);
+extern void tui_make_invisible (struct tui_gen_win_info *);
+extern void tui_make_all_visible (void);
+extern void tui_make_all_invisible (void);
+extern void tui_make_window (struct tui_gen_win_info *, int);
+extern struct tui_win_info *tui_copy_win (struct tui_win_info *);
+extern void tui_box_win (struct tui_gen_win_info *, int);
+extern void tui_highlight_win (struct tui_win_info *);
+extern void tui_check_and_display_highlight_if_needed (struct tui_win_info *);
+extern void tui_refresh_all (struct tui_win_info **);
+extern void tui_delete_win (WINDOW * window);
+extern void tui_refresh_win (struct tui_gen_win_info *);
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui-winsource.c b/contrib/gdb/gdb/tui/tui-winsource.c
new file mode 100644
index 0000000..de19d25
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-winsource.c
@@ -0,0 +1,654 @@
+/* TUI display source/assembly window.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "value.h"
+#include "source.h"
+
+#include "tui/tui.h"
+#include "tui/tui-data.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-win.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-source.h"
+#include "tui/tui-disasm.h"
+
+#include "gdb_string.h"
+#include "gdb_curses.h"
+
+/* Function to display the "main" routine. */
+void
+tui_display_main (void)
+{
+ if ((tui_source_windows ())->count > 0)
+ {
+ CORE_ADDR addr;
+
+ addr = tui_get_begin_asm_address ();
+ if (addr != (CORE_ADDR) 0)
+ {
+ struct symtab_and_line sal;
+
+ tui_update_source_windows_with_addr (addr);
+ sal = find_pc_line (addr, 0);
+ if (sal.symtab)
+ tui_update_locator_filename (sal.symtab->filename);
+ else
+ tui_update_locator_filename ("??");
+ }
+ }
+}
+
+
+
+/* Function to display source in the source window. This function
+ initializes the horizontal scroll to 0. */
+void
+tui_update_source_window (struct tui_win_info * win_info, struct symtab *s,
+ union tui_line_or_address line_or_addr, int noerror)
+{
+ win_info->detail.source_info.horizontal_offset = 0;
+ tui_update_source_window_as_is (win_info, s, line_or_addr, noerror);
+
+ return;
+}
+
+
+/* Function to display source in the source/asm window. This function
+ shows the source as specified by the horizontal offset. */
+void
+tui_update_source_window_as_is (struct tui_win_info * win_info, struct symtab *s,
+ union tui_line_or_address line_or_addr, int noerror)
+{
+ enum tui_status ret;
+
+ if (win_info->generic.type == SRC_WIN)
+ ret = tui_set_source_content (s, line_or_addr.line_no, noerror);
+ else
+ ret = tui_set_disassem_content (line_or_addr.addr);
+
+ if (ret == TUI_FAILURE)
+ {
+ tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
+ tui_clear_exec_info_content (win_info);
+ }
+ else
+ {
+ tui_update_breakpoint_info (win_info, 0);
+ tui_show_source_content (win_info);
+ tui_update_exec_info (win_info);
+ if (win_info->generic.type == SRC_WIN)
+ {
+ struct symtab_and_line sal;
+
+ sal.line = line_or_addr.line_no +
+ (win_info->generic.content_size - 2);
+ sal.symtab = s;
+ set_current_source_symtab_and_line (&sal);
+ /*
+ ** If the focus was in the asm win, put it in the src
+ ** win if we don't have a split layout
+ */
+ if (tui_win_with_focus () == TUI_DISASM_WIN &&
+ tui_current_layout () != SRC_DISASSEM_COMMAND)
+ tui_set_win_focus_to (TUI_SRC_WIN);
+ }
+ }
+
+
+ return;
+}
+
+
+/* Function to ensure that the source and/or disassemly windows
+ reflect the input address. */
+void
+tui_update_source_windows_with_addr (CORE_ADDR addr)
+{
+ if (addr != 0)
+ {
+ struct symtab_and_line sal;
+ union tui_line_or_address l;
+
+ switch (tui_current_layout ())
+ {
+ case DISASSEM_COMMAND:
+ case DISASSEM_DATA_COMMAND:
+ tui_show_disassem (addr);
+ break;
+ case SRC_DISASSEM_COMMAND:
+ tui_show_disassem_and_update_source (addr);
+ break;
+ default:
+ sal = find_pc_line (addr, 0);
+ l.line_no = sal.line;
+ tui_show_symtab_source (sal.symtab, l, FALSE);
+ break;
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < (tui_source_windows ())->count; i++)
+ {
+ struct tui_win_info * win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
+
+ tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
+ tui_clear_exec_info_content (win_info);
+ }
+ }
+}
+
+/* Function to ensure that the source and/or disassemly windows
+ reflect the input address. */
+void
+tui_update_source_windows_with_line (struct symtab *s, int line)
+{
+ CORE_ADDR pc;
+ union tui_line_or_address l;
+
+ switch (tui_current_layout ())
+ {
+ case DISASSEM_COMMAND:
+ case DISASSEM_DATA_COMMAND:
+ find_line_pc (s, line, &pc);
+ tui_update_source_windows_with_addr (pc);
+ break;
+ default:
+ l.line_no = line;
+ tui_show_symtab_source (s, l, FALSE);
+ if (tui_current_layout () == SRC_DISASSEM_COMMAND)
+ {
+ find_line_pc (s, line, &pc);
+ tui_show_disassem (pc);
+ }
+ break;
+ }
+
+ return;
+}
+
+void
+tui_clear_source_content (struct tui_win_info * win_info, int display_prompt)
+{
+ if (win_info != NULL)
+ {
+ int i;
+
+ win_info->generic.content_in_use = FALSE;
+ tui_erase_source_content (win_info, display_prompt);
+ for (i = 0; i < win_info->generic.content_size; i++)
+ {
+ struct tui_win_element * element =
+ (struct tui_win_element *) win_info->generic.content[i];
+ element->which_element.source.has_break = FALSE;
+ element->which_element.source.is_exec_point = FALSE;
+ }
+ }
+}
+
+
+void
+tui_erase_source_content (struct tui_win_info * win_info, int display_prompt)
+{
+ int x_pos;
+ int half_width = (win_info->generic.width - 2) / 2;
+
+ if (win_info->generic.handle != (WINDOW *) NULL)
+ {
+ werase (win_info->generic.handle);
+ tui_check_and_display_highlight_if_needed (win_info);
+ if (display_prompt == EMPTY_SOURCE_PROMPT)
+ {
+ char *no_src_str;
+
+ if (win_info->generic.type == SRC_WIN)
+ no_src_str = NO_SRC_STRING;
+ else
+ no_src_str = NO_DISASSEM_STRING;
+ if (strlen (no_src_str) >= half_width)
+ x_pos = 1;
+ else
+ x_pos = half_width - strlen (no_src_str);
+ mvwaddstr (win_info->generic.handle,
+ (win_info->generic.height / 2),
+ x_pos,
+ no_src_str);
+
+ /* elz: added this function call to set the real contents of
+ the window to what is on the screen, so that later calls
+ to refresh, do display
+ the correct stuff, and not the old image */
+
+ tui_set_source_content_nil (win_info, no_src_str);
+ }
+ tui_refresh_win (&win_info->generic);
+ }
+}
+
+
+/* Redraw the complete line of a source or disassembly window. */
+static void
+tui_show_source_line (struct tui_win_info * win_info, int lineno)
+{
+ struct tui_win_element * line;
+ int x, y;
+
+ line = (struct tui_win_element *) win_info->generic.content[lineno - 1];
+ if (line->which_element.source.is_exec_point)
+ wattron (win_info->generic.handle, A_STANDOUT);
+
+ mvwaddstr (win_info->generic.handle, lineno, 1,
+ line->which_element.source.line);
+ if (line->which_element.source.is_exec_point)
+ wattroff (win_info->generic.handle, A_STANDOUT);
+
+ /* Clear to end of line but stop before the border. */
+ getyx (win_info->generic.handle, y, x);
+ while (x + 1 < win_info->generic.width)
+ {
+ waddch (win_info->generic.handle, ' ');
+ getyx (win_info->generic.handle, y, x);
+ }
+}
+
+void
+tui_show_source_content (struct tui_win_info * win_info)
+{
+ if (win_info->generic.content_size > 0)
+ {
+ int lineno;
+
+ for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
+ tui_show_source_line (win_info, lineno);
+ }
+ else
+ tui_erase_source_content (win_info, TRUE);
+
+ tui_check_and_display_highlight_if_needed (win_info);
+ tui_refresh_win (&win_info->generic);
+ win_info->generic.content_in_use = TRUE;
+}
+
+
+/* Scroll the source forward or backward horizontally. */
+void
+tui_horizontal_source_scroll (struct tui_win_info * win_info,
+ enum tui_scroll_direction direction,
+ int num_to_scroll)
+{
+ if (win_info->generic.content != NULL)
+ {
+ int offset;
+ struct symtab *s;
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+ if (cursal.symtab == (struct symtab *) NULL)
+ s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
+ else
+ s = cursal.symtab;
+
+ if (direction == LEFT_SCROLL)
+ offset = win_info->detail.source_info.horizontal_offset + num_to_scroll;
+ else
+ {
+ if ((offset =
+ win_info->detail.source_info.horizontal_offset - num_to_scroll) < 0)
+ offset = 0;
+ }
+ win_info->detail.source_info.horizontal_offset = offset;
+ tui_update_source_window_as_is (win_info, s,
+ ((struct tui_win_element *)
+ win_info->generic.content[0])->which_element.source.line_or_addr,
+ FALSE);
+ }
+
+ return;
+}
+
+
+/* Set or clear the has_break flag in the line whose line is line_no. */
+void
+tui_set_is_exec_point_at (union tui_line_or_address l, struct tui_win_info * win_info)
+{
+ int changed = 0;
+ int i;
+ tui_win_content content = (tui_win_content) win_info->generic.content;
+
+ i = 0;
+ while (i < win_info->generic.content_size)
+ {
+ int new_state;
+
+ if (content[i]->which_element.source.line_or_addr.addr == l.addr)
+ new_state = TRUE;
+ else
+ new_state = FALSE;
+ if (new_state != content[i]->which_element.source.is_exec_point)
+ {
+ changed++;
+ content[i]->which_element.source.is_exec_point = new_state;
+ tui_show_source_line (win_info, i + 1);
+ }
+ i++;
+ }
+ if (changed)
+ tui_refresh_win (&win_info->generic);
+}
+
+/* Update the execution windows to show the active breakpoints.
+ This is called whenever a breakpoint is inserted, removed or
+ has its state changed. */
+void
+tui_update_all_breakpoint_info (void)
+{
+ struct tui_list *list = tui_source_windows ();
+ int i;
+
+ for (i = 0; i < list->count; i++)
+ {
+ struct tui_win_info * win = (struct tui_win_info *) list->list[i];
+
+ if (tui_update_breakpoint_info (win, FALSE))
+ {
+ tui_update_exec_info (win);
+ }
+ }
+}
+
+
+/* Scan the source window and the breakpoints to update the
+ has_break information for each line.
+ Returns 1 if something changed and the execution window
+ must be refreshed. */
+int
+tui_update_breakpoint_info (struct tui_win_info * win, int current_only)
+{
+ int i;
+ int need_refresh = 0;
+ struct tui_source_info * src = &win->detail.source_info;
+
+ for (i = 0; i < win->generic.content_size; i++)
+ {
+ struct breakpoint *bp;
+ extern struct breakpoint *breakpoint_chain;
+ int mode;
+ struct tui_source_element* line;
+
+ line = &((struct tui_win_element *) win->generic.content[i])->which_element.source;
+ if (current_only && !line->is_exec_point)
+ continue;
+
+ /* Scan each breakpoint to see if the current line has something to
+ do with it. Identify enable/disabled breakpoints as well as
+ those that we already hit. */
+ mode = 0;
+ for (bp = breakpoint_chain;
+ bp != (struct breakpoint *) NULL;
+ bp = bp->next)
+ {
+ if ((win == TUI_SRC_WIN
+ && bp->source_file
+ && (strcmp (src->filename, bp->source_file) == 0)
+ && bp->line_number == line->line_or_addr.line_no)
+ || (win == TUI_DISASM_WIN
+ && bp->loc->address == line->line_or_addr.addr))
+ {
+ if (bp->enable_state == bp_disabled)
+ mode |= TUI_BP_DISABLED;
+ else
+ mode |= TUI_BP_ENABLED;
+ if (bp->hit_count)
+ mode |= TUI_BP_HIT;
+ if (bp->cond)
+ mode |= TUI_BP_CONDITIONAL;
+ if (bp->type == bp_hardware_breakpoint)
+ mode |= TUI_BP_HARDWARE;
+ }
+ }
+ if (line->has_break != mode)
+ {
+ line->has_break = mode;
+ need_refresh = 1;
+ }
+ }
+ return need_refresh;
+}
+
+
+/* Function to initialize the content of the execution info window,
+ based upon the input window which is either the source or
+ disassembly window. */
+enum tui_status
+tui_set_exec_info_content (struct tui_win_info * win_info)
+{
+ enum tui_status ret = TUI_SUCCESS;
+
+ if (win_info->detail.source_info.execution_info != (struct tui_gen_win_info *) NULL)
+ {
+ struct tui_gen_win_info * exec_info_ptr = win_info->detail.source_info.execution_info;
+
+ if (exec_info_ptr->content == NULL)
+ exec_info_ptr->content =
+ (void **) tui_alloc_content (win_info->generic.height,
+ exec_info_ptr->type);
+ if (exec_info_ptr->content != NULL)
+ {
+ int i;
+
+ tui_update_breakpoint_info (win_info, 1);
+ for (i = 0; i < win_info->generic.content_size; i++)
+ {
+ struct tui_win_element * element;
+ struct tui_win_element * src_element;
+ int mode;
+
+ element = (struct tui_win_element *) exec_info_ptr->content[i];
+ src_element = (struct tui_win_element *) win_info->generic.content[i];
+
+ memset(element->which_element.simple_string, ' ',
+ sizeof(element->which_element.simple_string));
+ element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
+
+ /* Now update the exec info content based upon the state
+ of each line as indicated by the source content. */
+ mode = src_element->which_element.source.has_break;
+ if (mode & TUI_BP_HIT)
+ element->which_element.simple_string[TUI_BP_HIT_POS] =
+ (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
+ else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
+ element->which_element.simple_string[TUI_BP_HIT_POS] =
+ (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
+
+ if (mode & TUI_BP_ENABLED)
+ element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
+ else if (mode & TUI_BP_DISABLED)
+ element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
+
+ if (src_element->which_element.source.is_exec_point)
+ element->which_element.simple_string[TUI_EXEC_POS] = '>';
+ }
+ exec_info_ptr->content_size = win_info->generic.content_size;
+ }
+ else
+ ret = TUI_FAILURE;
+ }
+
+ return ret;
+}
+
+
+void
+tui_show_exec_info_content (struct tui_win_info * win_info)
+{
+ struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
+ int cur_line;
+
+ werase (exec_info->handle);
+ tui_refresh_win (exec_info);
+ for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
+ mvwaddstr (exec_info->handle,
+ cur_line,
+ 0,
+ ((struct tui_win_element *)
+ exec_info->content[cur_line - 1])->which_element.simple_string);
+ tui_refresh_win (exec_info);
+ exec_info->content_in_use = TRUE;
+}
+
+
+void
+tui_erase_exec_info_content (struct tui_win_info * win_info)
+{
+ struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
+
+ werase (exec_info->handle);
+ tui_refresh_win (exec_info);
+}
+
+void
+tui_clear_exec_info_content (struct tui_win_info * win_info)
+{
+ win_info->detail.source_info.execution_info->content_in_use = FALSE;
+ tui_erase_exec_info_content (win_info);
+
+ return;
+}
+
+/* Function to update the execution info window. */
+void
+tui_update_exec_info (struct tui_win_info * win_info)
+{
+ tui_set_exec_info_content (win_info);
+ tui_show_exec_info_content (win_info);
+}
+
+enum tui_status
+tui_alloc_source_buffer (struct tui_win_info *win_info)
+{
+ char *src_line_buf;
+ int i, line_width, max_lines;
+ enum tui_status ret = TUI_FAILURE;
+
+ max_lines = win_info->generic.height; /* less the highlight box */
+ line_width = win_info->generic.width - 1;
+ /*
+ ** Allocate the buffer for the source lines. Do this only once since they
+ ** will be re-used for all source displays. The only other time this will
+ ** be done is when a window's size changes.
+ */
+ if (win_info->generic.content == NULL)
+ {
+ src_line_buf = (char *) xmalloc ((max_lines * line_width) * sizeof (char));
+ if (src_line_buf == (char *) NULL)
+ fputs_unfiltered (
+ "Unable to Allocate Memory for Source or Disassembly Display.\n",
+ gdb_stderr);
+ else
+ {
+ /* allocate the content list */
+ if ((win_info->generic.content =
+ (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
+ {
+ xfree (src_line_buf);
+ src_line_buf = (char *) NULL;
+ fputs_unfiltered (
+ "Unable to Allocate Memory for Source or Disassembly Display.\n",
+ gdb_stderr);
+ }
+ }
+ for (i = 0; i < max_lines; i++)
+ ((struct tui_win_element *)
+ win_info->generic.content[i])->which_element.source.line =
+ src_line_buf + (line_width * i);
+ ret = TUI_SUCCESS;
+ }
+ else
+ ret = TUI_SUCCESS;
+
+ return ret;
+}
+
+
+/* Answer whether the a particular line number or address is displayed
+ in the current source window. */
+int
+tui_line_is_displayed (int line, struct tui_win_info * win_info,
+ int check_threshold)
+{
+ int is_displayed = FALSE;
+ int i, threshold;
+
+ if (check_threshold)
+ threshold = SCROLL_THRESHOLD;
+ else
+ threshold = 0;
+ i = 0;
+ while (i < win_info->generic.content_size - threshold && !is_displayed)
+ {
+ is_displayed = (((struct tui_win_element *)
+ win_info->generic.content[i])->which_element.source.line_or_addr.line_no
+ == (int) line);
+ i++;
+ }
+
+ return is_displayed;
+}
+
+
+/* Answer whether the a particular line number or address is displayed
+ in the current source window. */
+int
+tui_addr_is_displayed (CORE_ADDR addr, struct tui_win_info * win_info,
+ int check_threshold)
+{
+ int is_displayed = FALSE;
+ int i, threshold;
+
+ if (check_threshold)
+ threshold = SCROLL_THRESHOLD;
+ else
+ threshold = 0;
+ i = 0;
+ while (i < win_info->generic.content_size - threshold && !is_displayed)
+ {
+ is_displayed = (((struct tui_win_element *)
+ win_info->generic.content[i])->which_element.source.line_or_addr.addr
+ == addr);
+ i++;
+ }
+
+ return is_displayed;
+}
+
+
+/*****************************************
+** STATIC LOCAL FUNCTIONS **
+******************************************/
diff --git a/contrib/gdb/gdb/tui/tui-winsource.h b/contrib/gdb/gdb/tui/tui-winsource.h
new file mode 100644
index 0000000..e64589b
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui-winsource.h
@@ -0,0 +1,73 @@
+/* TUI display source/assembly window.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_SOURCEWIN_H
+#define TUI_SOURCEWIN_H
+
+#include "tui/tui-data.h"
+
+struct tui_win_info;
+
+/* Update the execution windows to show the active breakpoints. This
+ is called whenever a breakpoint is inserted, removed or has its
+ state changed. */
+extern void tui_update_all_breakpoint_info (void);
+
+/* Scan the source window and the breakpoints to update the hasBreak
+ information for each line. Returns 1 if something changed and the
+ execution window must be refreshed. */
+extern int tui_update_breakpoint_info (struct tui_win_info * win,
+ int current_only);
+
+/* Function to display the "main" routine. */
+extern void tui_display_main (void);
+extern void tui_update_source_window (struct tui_win_info *, struct symtab *,
+ union tui_line_or_address, int);
+extern void tui_update_source_window_as_is (struct tui_win_info *,
+ struct symtab *,
+ union tui_line_or_address, int);
+extern void tui_update_source_windows_with_addr (CORE_ADDR);
+extern void tui_update_source_windows_with_line (struct symtab *, int);
+extern void tui_clear_source_content (struct tui_win_info *, int);
+extern void tui_erase_source_content (struct tui_win_info *, int);
+extern void tui_show_source_content (struct tui_win_info *);
+extern void tui_horizontal_source_scroll (struct tui_win_info *,
+ enum tui_scroll_direction, int);
+extern enum tui_status tui_set_exec_info_content (struct tui_win_info *);
+extern void tui_show_exec_info_content (struct tui_win_info *);
+extern void tui_erase_exec_info_content (struct tui_win_info *);
+extern void tui_clear_exec_info_content (struct tui_win_info *);
+extern void tui_update_exec_info (struct tui_win_info *);
+
+extern void tui_set_is_exec_point_at (union tui_line_or_address,
+ struct tui_win_info *);
+extern enum tui_status tui_alloc_source_buffer (struct tui_win_info *);
+extern int tui_line_is_displayed (int, struct tui_win_info *, int);
+extern int tui_addr_is_displayed (CORE_ADDR, struct tui_win_info *, int);
+
+
+/* Constant definitions. */
+#define SCROLL_THRESHOLD 2 /* threshold for lazy scroll */
+
+#endif
diff --git a/contrib/gdb/gdb/tui/tui.c b/contrib/gdb/gdb/tui/tui.c
new file mode 100644
index 0000000..d6f344f
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui.c
@@ -0,0 +1,590 @@
+/* General functions for the WDB TUI.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "tui/tui.h"
+#include "tui/tui-hooks.h"
+#include "tui/tui-data.h"
+#include "tui/tui-layout.h"
+#include "tui/tui-io.h"
+#include "tui/tui-regs.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-win.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-windata.h"
+#include "target.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "source.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#if 0
+#include <termio.h>
+#endif
+#include <setjmp.h>
+
+#include "gdb_curses.h"
+
+/* This redefines CTRL if it is not already defined, so it must come
+ after terminal state releated include files like <term.h> and
+ "gdb_ncurses.h". */
+#include "readline/readline.h"
+
+/* Tells whether the TUI is active or not. */
+int tui_active = 0;
+static int tui_finish_init = 1;
+
+enum tui_key_mode tui_current_key_mode = TUI_COMMAND_MODE;
+
+struct tui_char_command
+{
+ unsigned char key;
+ const char* cmd;
+};
+
+/* Key mapping to gdb commands when the TUI is using the single key mode. */
+static const struct tui_char_command tui_commands[] = {
+ { 'c', "continue" },
+ { 'd', "down" },
+ { 'f', "finish" },
+ { 'n', "next" },
+ { 'r', "run" },
+ { 's', "step" },
+ { 'u', "up" },
+ { 'v', "info locals" },
+ { 'w', "where" },
+ { 0, 0 },
+};
+
+static Keymap tui_keymap;
+static Keymap tui_readline_standard_keymap;
+
+/* TUI readline command.
+ Switch the output mode between TUI/standard gdb. */
+static int
+tui_rl_switch_mode (int notused1, int notused2)
+{
+ if (tui_active)
+ {
+ tui_disable ();
+ rl_prep_terminal (0);
+ }
+ else
+ {
+ rl_deprep_terminal ();
+ tui_enable ();
+ }
+
+ /* Clear the readline in case switching occurred in middle of something. */
+ if (rl_end)
+ rl_kill_text (0, rl_end);
+
+ /* Since we left the curses mode, the terminal mode is restored to
+ some previous state. That state may not be suitable for readline
+ to work correctly (it may be restored in line mode). We force an
+ exit of the current readline so that readline is re-entered and it
+ will be able to setup the terminal for its needs. By re-entering
+ in readline, we also redisplay its prompt in the non-curses mode. */
+ rl_newline (1, '\n');
+
+ /* Make sure the \n we are returning does not repeat the last command. */
+ dont_repeat ();
+ return 0;
+}
+
+/* TUI readline command.
+ Change the TUI layout to show a next layout.
+ This function is bound to CTRL-X 2. It is intended to provide
+ a functionality close to the Emacs split-window command. We always
+ show two windows (src+asm), (src+regs) or (asm+regs). */
+static int
+tui_rl_change_windows (int notused1, int notused2)
+{
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ if (tui_active)
+ {
+ enum tui_layout_type new_layout;
+ enum tui_register_display_type regs_type = TUI_UNDEFINED_REGS;
+
+ new_layout = tui_current_layout ();
+
+ /* Select a new layout to have a rolling layout behavior
+ with always two windows (except when undefined). */
+ switch (new_layout)
+ {
+ case SRC_COMMAND:
+ new_layout = SRC_DISASSEM_COMMAND;
+ break;
+
+ case DISASSEM_COMMAND:
+ new_layout = SRC_DISASSEM_COMMAND;
+ break;
+
+ case SRC_DATA_COMMAND:
+ new_layout = SRC_DISASSEM_COMMAND;
+ break;
+
+ case SRC_DISASSEM_COMMAND:
+ new_layout = DISASSEM_DATA_COMMAND;
+ break;
+
+ case DISASSEM_DATA_COMMAND:
+ new_layout = SRC_DATA_COMMAND;
+ break;
+
+ default:
+ new_layout = SRC_COMMAND;
+ break;
+ }
+ tui_set_layout (new_layout, regs_type);
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Delete the second TUI window to only show one. */
+static int
+tui_rl_delete_other_windows (int notused1, int notused2)
+{
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ if (tui_active)
+ {
+ enum tui_layout_type new_layout;
+ enum tui_register_display_type regs_type = TUI_UNDEFINED_REGS;
+
+ new_layout = tui_current_layout ();
+
+ /* Kill one window. */
+ switch (new_layout)
+ {
+ case SRC_COMMAND:
+ case SRC_DATA_COMMAND:
+ case SRC_DISASSEM_COMMAND:
+ default:
+ new_layout = SRC_COMMAND;
+ break;
+
+ case DISASSEM_COMMAND:
+ case DISASSEM_DATA_COMMAND:
+ new_layout = DISASSEM_COMMAND;
+ break;
+ }
+ tui_set_layout (new_layout, regs_type);
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Switch the active window to give the focus to a next window. */
+static int
+tui_rl_other_window (int count, int key)
+{
+ struct tui_win_info * win_info;
+
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ win_info = tui_next_win (tui_win_with_focus ());
+ if (win_info)
+ {
+ tui_set_win_focus_to (win_info);
+ if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible)
+ tui_refresh_data_win ();
+ keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN));
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Execute the gdb command bound to the specified key. */
+static int
+tui_rl_command_key (int count, int key)
+{
+ int i;
+
+ reinitialize_more_filter ();
+ for (i = 0; tui_commands[i].cmd; i++)
+ {
+ if (tui_commands[i].key == key)
+ {
+ /* Must save the command because it can be modified
+ by execute_command. */
+ char* cmd = alloca (strlen (tui_commands[i].cmd) + 1);
+ strcpy (cmd, tui_commands[i].cmd);
+ execute_command (cmd, TRUE);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Temporarily leave the TUI SingleKey mode to allow editing
+ a gdb command with the normal readline. Once the command
+ is executed, the TUI SingleKey mode is installed back. */
+static int
+tui_rl_command_mode (int count, int key)
+{
+ tui_set_key_mode (TUI_ONE_COMMAND_MODE);
+ return rl_insert (count, key);
+}
+
+/* TUI readline command.
+ Switch between TUI SingleKey mode and gdb readline editing. */
+static int
+tui_rl_next_keymap (int notused1, int notused2)
+{
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ tui_set_key_mode (tui_current_key_mode == TUI_COMMAND_MODE
+ ? TUI_SINGLE_KEY_MODE : TUI_COMMAND_MODE);
+ return 0;
+}
+
+/* Readline hook to redisplay ourself the gdb prompt.
+ In the SingleKey mode, the prompt is not printed so that
+ the command window is cleaner. It will be displayed if
+ we temporarily leave the SingleKey mode. */
+static int
+tui_rl_startup_hook (void)
+{
+ rl_already_prompted = 1;
+ if (tui_current_key_mode != TUI_COMMAND_MODE)
+ tui_set_key_mode (TUI_SINGLE_KEY_MODE);
+ tui_redisplay_readline ();
+ return 0;
+}
+
+/* Change the TUI key mode by installing the appropriate readline keymap. */
+void
+tui_set_key_mode (enum tui_key_mode mode)
+{
+ tui_current_key_mode = mode;
+ rl_set_keymap (mode == TUI_SINGLE_KEY_MODE
+ ? tui_keymap : tui_readline_standard_keymap);
+ tui_show_locator_content ();
+}
+
+/* Initialize readline and configure the keymap for the switching
+ key shortcut. */
+void
+tui_initialize_readline (void)
+{
+ int i;
+ Keymap tui_ctlx_keymap;
+
+ rl_initialize ();
+
+ rl_add_defun ("tui-switch-mode", tui_rl_switch_mode, -1);
+ rl_add_defun ("gdb-command", tui_rl_command_key, -1);
+ rl_add_defun ("next-keymap", tui_rl_next_keymap, -1);
+
+ tui_keymap = rl_make_bare_keymap ();
+ tui_ctlx_keymap = rl_make_bare_keymap ();
+ tui_readline_standard_keymap = rl_get_keymap ();
+
+ for (i = 0; tui_commands[i].cmd; i++)
+ rl_bind_key_in_map (tui_commands[i].key, tui_rl_command_key, tui_keymap);
+
+ rl_generic_bind (ISKMAP, "\\C-x", (char*) tui_ctlx_keymap, tui_keymap);
+
+ /* Bind all other keys to tui_rl_command_mode so that we switch
+ temporarily from SingleKey mode and can enter a gdb command. */
+ for (i = ' '; i < 0x7f; i++)
+ {
+ int j;
+
+ for (j = 0; tui_commands[j].cmd; j++)
+ if (tui_commands[j].key == i)
+ break;
+
+ if (tui_commands[j].cmd)
+ continue;
+
+ rl_bind_key_in_map (i, tui_rl_command_mode, tui_keymap);
+ }
+
+ rl_bind_key_in_map ('a', tui_rl_switch_mode, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('a', tui_rl_switch_mode, tui_ctlx_keymap);
+ rl_bind_key_in_map ('A', tui_rl_switch_mode, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('A', tui_rl_switch_mode, tui_ctlx_keymap);
+ rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, emacs_ctlx_keymap);
+ rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, tui_ctlx_keymap);
+ rl_bind_key_in_map ('1', tui_rl_delete_other_windows, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('1', tui_rl_delete_other_windows, tui_ctlx_keymap);
+ rl_bind_key_in_map ('2', tui_rl_change_windows, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('2', tui_rl_change_windows, tui_ctlx_keymap);
+ rl_bind_key_in_map ('o', tui_rl_other_window, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('o', tui_rl_other_window, tui_ctlx_keymap);
+ rl_bind_key_in_map ('q', tui_rl_next_keymap, tui_keymap);
+ rl_bind_key_in_map ('s', tui_rl_next_keymap, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('s', tui_rl_next_keymap, tui_ctlx_keymap);
+}
+
+/* Enter in the tui mode (curses).
+ When in normal mode, it installs the tui hooks in gdb, redirects
+ the gdb output, configures the readline to work in tui mode.
+ When in curses mode, it does nothing. */
+void
+tui_enable (void)
+{
+ if (tui_active)
+ return;
+
+ /* To avoid to initialize curses when gdb starts, there is a defered
+ curses initialization. This initialization is made only once
+ and the first time the curses mode is entered. */
+ if (tui_finish_init)
+ {
+ WINDOW *w;
+
+ w = initscr ();
+
+ cbreak ();
+ noecho ();
+ /*timeout (1);*/
+ nodelay(w, FALSE);
+ nl();
+ keypad (w, TRUE);
+ rl_initialize ();
+ tui_set_term_height_to (LINES);
+ tui_set_term_width_to (COLS);
+ def_prog_mode ();
+
+ tui_show_frame_info (0);
+ tui_set_layout (SRC_COMMAND, TUI_UNDEFINED_REGS);
+ tui_set_win_focus_to (TUI_SRC_WIN);
+ keypad (TUI_CMD_WIN->generic.handle, TRUE);
+ wrefresh (TUI_CMD_WIN->generic.handle);
+ tui_finish_init = 0;
+ }
+ else
+ {
+ /* Save the current gdb setting of the terminal.
+ Curses will restore this state when endwin() is called. */
+ def_shell_mode ();
+ clearok (stdscr, TRUE);
+ }
+
+ /* Install the TUI specific hooks. */
+ tui_install_hooks ();
+ rl_startup_hook = tui_rl_startup_hook;
+
+ tui_update_variables ();
+
+ tui_setup_io (1);
+
+ tui_active = 1;
+ if (deprecated_selected_frame)
+ tui_show_frame_info (deprecated_selected_frame);
+
+ /* Restore TUI keymap. */
+ tui_set_key_mode (tui_current_key_mode);
+ tui_refresh_all_win ();
+
+ /* Update gdb's knowledge of its terminal. */
+ target_terminal_save_ours ();
+ tui_update_gdb_sizes ();
+}
+
+/* Leave the tui mode.
+ Remove the tui hooks and configure the gdb output and readline
+ back to their original state. The curses mode is left so that
+ the terminal setting is restored to the point when we entered. */
+void
+tui_disable (void)
+{
+ if (!tui_active)
+ return;
+
+ /* Restore initial readline keymap. */
+ rl_set_keymap (tui_readline_standard_keymap);
+
+ /* Remove TUI hooks. */
+ tui_remove_hooks ();
+ rl_startup_hook = 0;
+ rl_already_prompted = 0;
+
+ /* Leave curses and restore previous gdb terminal setting. */
+ endwin ();
+
+ /* gdb terminal has changed, update gdb internal copy of it
+ so that terminal management with the inferior works. */
+ tui_setup_io (0);
+
+ /* Update gdb's knowledge of its terminal. */
+ target_terminal_save_ours ();
+
+ tui_active = 0;
+ tui_update_gdb_sizes ();
+}
+
+void
+strcat_to_buf (char *buf, int buflen, const char *item_to_add)
+{
+ if (item_to_add != (char *) NULL && buf != (char *) NULL)
+ {
+ if ((strlen (buf) + strlen (item_to_add)) <= buflen)
+ strcat (buf, item_to_add);
+ else
+ strncat (buf, item_to_add, (buflen - strlen (buf)));
+ }
+}
+
+#if 0
+/* Solaris <sys/termios.h> defines CTRL. */
+#ifndef CTRL
+#define CTRL(x) (x & ~0140)
+#endif
+
+#define FILEDES 2
+#define CHK(val, dft) (val<=0 ? dft : val)
+
+static void
+tui_reset (void)
+{
+ struct termio mode;
+
+ /*
+ ** reset the teletype mode bits to a sensible state.
+ ** Copied tset.c
+ */
+#if ! defined (USG) && defined (TIOCGETC)
+ struct tchars tbuf;
+#endif /* !USG && TIOCGETC */
+#ifdef UCB_NTTY
+ struct ltchars ltc;
+
+ if (ldisc == NTTYDISC)
+ {
+ ioctl (FILEDES, TIOCGLTC, &ltc);
+ ltc.t_suspc = CHK (ltc.t_suspc, CTRL ('Z'));
+ ltc.t_dsuspc = CHK (ltc.t_dsuspc, CTRL ('Y'));
+ ltc.t_rprntc = CHK (ltc.t_rprntc, CTRL ('R'));
+ ltc.t_flushc = CHK (ltc.t_flushc, CTRL ('O'));
+ ltc.t_werasc = CHK (ltc.t_werasc, CTRL ('W'));
+ ltc.t_lnextc = CHK (ltc.t_lnextc, CTRL ('V'));
+ ioctl (FILEDES, TIOCSLTC, &ltc);
+ }
+#endif /* UCB_NTTY */
+#ifndef USG
+#ifdef TIOCGETC
+ ioctl (FILEDES, TIOCGETC, &tbuf);
+ tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
+ tbuf.t_quitc = CHK (tbuf.t_quitc, CTRL ('\\'));
+ tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
+ tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
+ tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
+ /* brkc is left alone */
+ ioctl (FILEDES, TIOCSETC, &tbuf);
+#endif /* TIOCGETC */
+ mode.sg_flags &= ~(RAW
+#ifdef CBREAK
+ | CBREAK
+#endif /* CBREAK */
+ | VTDELAY | ALLDELAY);
+ mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
+#else /*USG */
+ ioctl (FILEDES, TCGETA, &mode);
+ mode.c_cc[VINTR] = CHK (mode.c_cc[VINTR], CTRL ('?'));
+ mode.c_cc[VQUIT] = CHK (mode.c_cc[VQUIT], CTRL ('\\'));
+ mode.c_cc[VEOF] = CHK (mode.c_cc[VEOF], CTRL ('D'));
+
+ mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF);
+ mode.c_iflag |= (BRKINT | ISTRIP | ICRNL | IXON);
+ mode.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |
+ NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
+ mode.c_oflag |= (OPOST | ONLCR);
+ mode.c_cflag &= ~(CSIZE | PARODD | CLOCAL);
+#ifndef hp9000s800
+ mode.c_cflag |= (CS8 | CREAD);
+#else /*hp9000s800 */
+ mode.c_cflag |= (CS8 | CSTOPB | CREAD);
+#endif /* hp9000s800 */
+ mode.c_lflag &= ~(XCASE | ECHONL | NOFLSH);
+ mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOK);
+ ioctl (FILEDES, TCSETAW, &mode);
+#endif /* USG */
+
+ return;
+}
+#endif
+
+void
+tui_show_source (const char *file, int line)
+{
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+ /* make sure that the source window is displayed */
+ tui_add_win_to_layout (SRC_WIN);
+
+ tui_update_source_windows_with_line (cursal.symtab, line);
+ tui_update_locator_filename (file);
+}
+
+void
+tui_show_assembly (CORE_ADDR addr)
+{
+ tui_add_win_to_layout (DISASSEM_WIN);
+ tui_update_source_windows_with_addr (addr);
+}
+
+int
+tui_is_window_visible (enum tui_win_type type)
+{
+ if (tui_active == 0)
+ return 0;
+
+ if (tui_win_list[type] == 0)
+ return 0;
+
+ return tui_win_list[type]->generic.is_visible;
+}
+
+int
+tui_get_command_dimension (int *width, int *height)
+{
+ if (!tui_active || (TUI_CMD_WIN == NULL))
+ {
+ return 0;
+ }
+
+ *width = TUI_CMD_WIN->generic.width;
+ *height = TUI_CMD_WIN->generic.height;
+ return 1;
+}
diff --git a/contrib/gdb/gdb/tui/tui.h b/contrib/gdb/gdb/tui/tui.h
new file mode 100644
index 0000000..d7b741c
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui.h
@@ -0,0 +1,100 @@
+/* External/Public TUI Header File.
+
+ Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation,
+ Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TUI_H
+#define TUI_H
+
+struct ui_file;
+
+extern void strcat_to_buf (char *, int, const char *);
+
+/* Types of error returns. */
+enum tui_status
+{
+ TUI_SUCCESS,
+ TUI_FAILURE
+};
+
+/* Types of windows */
+enum tui_win_type
+{
+ SRC_WIN = 0,
+ DISASSEM_WIN,
+ DATA_WIN,
+ CMD_WIN,
+ /* This must ALWAYS be AFTER the major windows last. */
+ MAX_MAJOR_WINDOWS,
+ /* Auxillary windows. */
+ LOCATOR_WIN,
+ EXEC_INFO_WIN,
+ DATA_ITEM_WIN,
+ /* This must ALWAYS be next to last. */
+ MAX_WINDOWS,
+ UNDEFINED_WIN /* LAST */
+};
+
+/* GENERAL TUI FUNCTIONS */
+/* tui.c */
+extern CORE_ADDR tui_get_low_disassembly_address (CORE_ADDR, CORE_ADDR);
+extern void tui_show_assembly (CORE_ADDR addr);
+extern int tui_is_window_visible (enum tui_win_type type);
+extern int tui_get_command_dimension (int *width, int *height);
+
+/* Initialize readline and configure the keymap for the switching
+ key shortcut. */
+extern void tui_initialize_readline (void);
+
+/* Enter in the tui mode (curses). */
+extern void tui_enable (void);
+
+/* Leave the tui mode. */
+extern void tui_disable (void);
+
+enum tui_key_mode
+{
+ /* Plain command mode to enter gdb commands. */
+ TUI_COMMAND_MODE,
+
+ /* SingleKey mode with some keys bound to gdb commands. */
+ TUI_SINGLE_KEY_MODE,
+
+ /* Read/edit one command and return to SingleKey after it's processed. */
+ TUI_ONE_COMMAND_MODE
+};
+
+extern enum tui_key_mode tui_current_key_mode;
+
+/* Change the TUI key mode by installing the appropriate readline keymap. */
+extern void tui_set_key_mode (enum tui_key_mode mode);
+
+extern int tui_active;
+
+extern void tui_show_source (const char *file, int line);
+
+extern struct ui_out *tui_out_new (struct ui_file *stream);
+
+/* tui-layout.c */
+extern enum tui_status tui_set_layout_for_display_command (const char *name);
+
+#endif
diff --git a/contrib/gdb/gdb/typeprint.c b/contrib/gdb/gdb/typeprint.c
new file mode 100644
index 0000000..82ca5f1
--- /dev/null
+++ b/contrib/gdb/gdb/typeprint.c
@@ -0,0 +1,368 @@
+/* Language independent support for printing types for GDB, the GNU debugger.
+
+ Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1998,
+ 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_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 "cp-abi.h"
+#include "typeprint.h"
+#include "gdb_string.h"
+#include <errno.h>
+
+/* For real-type printing in whatis_exp() */
+extern int objectprint; /* Controls looking up an object's derived type
+ using what we find in its vtables. */
+
+extern void _initialize_typeprint (void);
+
+static void ptype_command (char *, int);
+
+static struct type *ptype_eval (struct expression *);
+
+static void whatis_command (char *, int);
+
+static void whatis_exp (char *, 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
+typedef_print (struct type *type, struct symbol *new, struct ui_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
+ || strcmp (TYPE_NAME ((SYMBOL_TYPE (new))), DEPRECATED_SYMBOL_NAME (new)) != 0)
+ fprintf_filtered (stream, " %s", SYMBOL_PRINT_NAME (new));
+ break;
+#endif
+#ifdef _LANG_m2
+ case language_m2:
+ fprintf_filtered (stream, "TYPE ");
+ if (!TYPE_NAME (SYMBOL_TYPE (new))
+ || strcmp (TYPE_NAME ((SYMBOL_TYPE (new))), DEPRECATED_SYMBOL_NAME (new)) != 0)
+ fprintf_filtered (stream, "%s = ", SYMBOL_PRINT_NAME (new));
+ else
+ fprintf_filtered (stream, "<builtin> = ");
+ type_print (type, "", stream, 0);
+ break;
+#endif
+#ifdef _LANG_pascal
+ case language_pascal:
+ fprintf_filtered (stream, "type ");
+ fprintf_filtered (stream, "%s = ", SYMBOL_PRINT_NAME (new));
+ type_print (type, "", stream, 0);
+ break;
+#endif
+ default:
+ error ("Language not supported.");
+ }
+ fprintf_filtered (stream, ";\n");
+}
+
+/* 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 (struct type *type, char *varstring, struct ui_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 (char *exp, int show)
+{
+ struct expression *expr;
+ struct value *val;
+ struct cleanup *old_chain = NULL;
+ struct type *real_type = NULL;
+ struct type *type;
+ int full = 0;
+ int top = -1;
+ int using_enc = 0;
+
+ if (exp)
+ {
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_type (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ type = VALUE_TYPE (val);
+
+ if (objectprint)
+ {
+ if (((TYPE_CODE (type) == TYPE_CODE_PTR) ||
+ (TYPE_CODE (type) == TYPE_CODE_REF))
+ &&
+ (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
+ {
+ real_type = value_rtti_target_type (val, &full, &top, &using_enc);
+ if (real_type)
+ {
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ real_type = lookup_pointer_type (real_type);
+ else
+ real_type = lookup_reference_type (real_type);
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
+ real_type = value_rtti_type (val, &full, &top, &using_enc);
+ }
+
+ printf_filtered ("type = ");
+
+ if (real_type)
+ {
+ printf_filtered ("/* real type = ");
+ type_print (real_type, "", gdb_stdout, -1);
+ if (! full)
+ printf_filtered (" (incomplete object)");
+ printf_filtered (" */\n");
+ }
+
+ type_print (type, "", gdb_stdout, show);
+ printf_filtered ("\n");
+
+ if (exp)
+ do_cleanups (old_chain);
+}
+
+static void
+whatis_command (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 (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. */
+
+static void
+ptype_command (char *typename, int from_tty)
+{
+ struct type *type;
+ struct expression *expr;
+ 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 <typename>" */
+ printf_filtered ("type = ");
+ type_print (type, "", gdb_stdout, 1);
+ printf_filtered ("\n");
+ do_cleanups (old_chain);
+ }
+ else
+ {
+ /* User did "ptype <symbolname>" */
+ 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 (struct type *type, LONGEST val, struct ui_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:
+ case TYPE_CODE_NAMESPACE:
+ error ("internal error: unhandled type in print_type_scalar");
+ break;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+ gdb_flush (stream);
+}
+
+/* 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 (char *typename, int from_tty)
+{
+ struct value *val;
+ struct type *type;
+ 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);
+ }
+}
+
+
+void
+_initialize_typeprint (void)
+{
+
+ 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 0000000..f2de1c5
--- /dev/null
+++ b/contrib/gdb/gdb/typeprint.h
@@ -0,0 +1,31 @@
+/* Language independent support for printing types for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991-1993, 1999, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TYPEPRINT_H
+#define TYPEPRINT_H
+
+struct ui_file;
+
+void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
+
+void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
+ int, int);
+#endif
diff --git a/contrib/gdb/gdb/ui-file.c b/contrib/gdb/gdb/ui-file.c
new file mode 100644
index 0000000..6ad5414
--- /dev/null
+++ b/contrib/gdb/gdb/ui-file.c
@@ -0,0 +1,617 @@
+/* UI_FILE - a generic STDIO like output stream.
+
+ Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Implement the ``struct ui_file'' object. */
+
+#include "defs.h"
+#include "ui-file.h"
+#include "gdb_string.h"
+
+#include <errno.h>
+
+static ui_file_isatty_ftype null_file_isatty;
+static ui_file_write_ftype null_file_write;
+static ui_file_fputs_ftype null_file_fputs;
+static ui_file_read_ftype null_file_read;
+static ui_file_flush_ftype null_file_flush;
+static ui_file_delete_ftype null_file_delete;
+static ui_file_rewind_ftype null_file_rewind;
+static ui_file_put_ftype null_file_put;
+
+struct ui_file
+ {
+ int *magic;
+ ui_file_flush_ftype *to_flush;
+ ui_file_write_ftype *to_write;
+ ui_file_fputs_ftype *to_fputs;
+ ui_file_read_ftype *to_read;
+ ui_file_delete_ftype *to_delete;
+ ui_file_isatty_ftype *to_isatty;
+ ui_file_rewind_ftype *to_rewind;
+ ui_file_put_ftype *to_put;
+ void *to_data;
+ };
+int ui_file_magic;
+
+struct ui_file *
+ui_file_new (void)
+{
+ struct ui_file *file = xmalloc (sizeof (struct ui_file));
+ file->magic = &ui_file_magic;
+ set_ui_file_data (file, NULL, null_file_delete);
+ set_ui_file_flush (file, null_file_flush);
+ set_ui_file_write (file, null_file_write);
+ set_ui_file_fputs (file, null_file_fputs);
+ set_ui_file_read (file, null_file_read);
+ set_ui_file_isatty (file, null_file_isatty);
+ set_ui_file_rewind (file, null_file_rewind);
+ set_ui_file_put (file, null_file_put);
+ return file;
+}
+
+void
+ui_file_delete (struct ui_file *file)
+{
+ file->to_delete (file);
+ xfree (file);
+}
+
+static int
+null_file_isatty (struct ui_file *file)
+{
+ return 0;
+}
+
+static void
+null_file_rewind (struct ui_file *file)
+{
+ return;
+}
+
+static void
+null_file_put (struct ui_file *file,
+ ui_file_put_method_ftype *write,
+ void *dest)
+{
+ return;
+}
+
+static void
+null_file_flush (struct ui_file *file)
+{
+ return;
+}
+
+static void
+null_file_write (struct ui_file *file,
+ const char *buf,
+ long sizeof_buf)
+{
+ if (file->to_fputs == null_file_fputs)
+ /* Both the write and fputs methods are null. Discard the
+ request. */
+ return;
+ else
+ {
+ /* The fputs method isn't null, slowly pass the write request
+ onto that. FYI, this isn't as bad as it may look - the
+ current (as of 1999-11-07) printf_* function calls fputc and
+ fputc does exactly the below. By having a write function it
+ is possible to clean up that code. */
+ int i;
+ char b[2];
+ b[1] = '\0';
+ for (i = 0; i < sizeof_buf; i++)
+ {
+ b[0] = buf[i];
+ file->to_fputs (b, file);
+ }
+ return;
+ }
+}
+
+static long
+null_file_read (struct ui_file *file,
+ char *buf,
+ long sizeof_buf)
+{
+ errno = EBADF;
+ return 0;
+}
+
+static void
+null_file_fputs (const char *buf, struct ui_file *file)
+{
+ if (file->to_write == null_file_write)
+ /* Both the write and fputs methods are null. Discard the
+ request. */
+ return;
+ else
+ {
+ /* The write method was implemented, use that. */
+ file->to_write (file, buf, strlen (buf));
+ }
+}
+
+static void
+null_file_delete (struct ui_file *file)
+{
+ return;
+}
+
+void *
+ui_file_data (struct ui_file *file)
+{
+ if (file->magic != &ui_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "ui_file_data: bad magic number");
+ return file->to_data;
+}
+
+void
+gdb_flush (struct ui_file *file)
+{
+ file->to_flush (file);
+}
+
+int
+ui_file_isatty (struct ui_file *file)
+{
+ return file->to_isatty (file);
+}
+
+void
+ui_file_rewind (struct ui_file *file)
+{
+ file->to_rewind (file);
+}
+
+void
+ui_file_put (struct ui_file *file,
+ ui_file_put_method_ftype *write,
+ void *dest)
+{
+ file->to_put (file, write, dest);
+}
+
+void
+ui_file_write (struct ui_file *file,
+ const char *buf,
+ long length_buf)
+{
+ file->to_write (file, buf, length_buf);
+}
+
+long
+ui_file_read (struct ui_file *file, char *buf, long length_buf)
+{
+ return file->to_read (file, buf, length_buf);
+}
+
+void
+fputs_unfiltered (const char *buf, struct ui_file *file)
+{
+ file->to_fputs (buf, file);
+}
+
+void
+set_ui_file_flush (struct ui_file *file, ui_file_flush_ftype *flush)
+{
+ file->to_flush = flush;
+}
+
+void
+set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty)
+{
+ file->to_isatty = isatty;
+}
+
+void
+set_ui_file_rewind (struct ui_file *file, ui_file_rewind_ftype *rewind)
+{
+ file->to_rewind = rewind;
+}
+
+void
+set_ui_file_put (struct ui_file *file, ui_file_put_ftype *put)
+{
+ file->to_put = put;
+}
+
+void
+set_ui_file_write (struct ui_file *file,
+ ui_file_write_ftype *write)
+{
+ file->to_write = write;
+}
+
+void
+set_ui_file_read (struct ui_file *file, ui_file_read_ftype *read)
+{
+ file->to_read = read;
+}
+
+void
+set_ui_file_fputs (struct ui_file *file, ui_file_fputs_ftype *fputs)
+{
+ file->to_fputs = fputs;
+}
+
+void
+set_ui_file_data (struct ui_file *file, void *data,
+ ui_file_delete_ftype *delete)
+{
+ file->to_data = data;
+ file->to_delete = delete;
+}
+
+/* ui_file utility function for converting a ``struct ui_file'' into
+ a memory buffer''. */
+
+struct accumulated_ui_file
+{
+ char *buffer;
+ long length;
+};
+
+static void
+do_ui_file_xstrdup (void *context, const char *buffer, long length)
+{
+ struct accumulated_ui_file *acc = context;
+ if (acc->buffer == NULL)
+ acc->buffer = xmalloc (length + 1);
+ else
+ acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
+ memcpy (acc->buffer + acc->length, buffer, length);
+ acc->length += length;
+ acc->buffer[acc->length] = '\0';
+}
+
+char *
+ui_file_xstrdup (struct ui_file *file,
+ long *length)
+{
+ struct accumulated_ui_file acc;
+ acc.buffer = NULL;
+ acc.length = 0;
+ ui_file_put (file, do_ui_file_xstrdup, &acc);
+ if (acc.buffer == NULL)
+ acc.buffer = xstrdup ("");
+ *length = acc.length;
+ return acc.buffer;
+}
+
+/* A pure memory based ``struct ui_file'' that can be used an output
+ buffer. The buffers accumulated contents are available via
+ ui_file_put(). */
+
+struct mem_file
+ {
+ int *magic;
+ char *buffer;
+ int sizeof_buffer;
+ int length_buffer;
+ };
+
+static ui_file_rewind_ftype mem_file_rewind;
+static ui_file_put_ftype mem_file_put;
+static ui_file_write_ftype mem_file_write;
+static ui_file_delete_ftype mem_file_delete;
+static struct ui_file *mem_file_new (void);
+static int mem_file_magic;
+
+static struct ui_file *
+mem_file_new (void)
+{
+ struct mem_file *stream = XMALLOC (struct mem_file);
+ struct ui_file *file = ui_file_new ();
+ set_ui_file_data (file, stream, mem_file_delete);
+ set_ui_file_rewind (file, mem_file_rewind);
+ set_ui_file_put (file, mem_file_put);
+ set_ui_file_write (file, mem_file_write);
+ stream->magic = &mem_file_magic;
+ stream->buffer = NULL;
+ stream->sizeof_buffer = 0;
+ stream->length_buffer = 0;
+ return file;
+}
+
+static void
+mem_file_delete (struct ui_file *file)
+{
+ struct mem_file *stream = ui_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mem_file_delete: bad magic number");
+ if (stream->buffer != NULL)
+ xfree (stream->buffer);
+ xfree (stream);
+}
+
+struct ui_file *
+mem_fileopen (void)
+{
+ return mem_file_new ();
+}
+
+static void
+mem_file_rewind (struct ui_file *file)
+{
+ struct mem_file *stream = ui_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mem_file_rewind: bad magic number");
+ stream->length_buffer = 0;
+}
+
+static void
+mem_file_put (struct ui_file *file,
+ ui_file_put_method_ftype *write,
+ void *dest)
+{
+ struct mem_file *stream = ui_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mem_file_put: bad magic number");
+ if (stream->length_buffer > 0)
+ write (dest, stream->buffer, stream->length_buffer);
+}
+
+void
+mem_file_write (struct ui_file *file,
+ const char *buffer,
+ long length_buffer)
+{
+ struct mem_file *stream = ui_file_data (file);
+ if (stream->magic != &mem_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "mem_file_write: bad magic number");
+ if (stream->buffer == NULL)
+ {
+ stream->length_buffer = length_buffer;
+ stream->sizeof_buffer = length_buffer;
+ stream->buffer = xmalloc (stream->sizeof_buffer);
+ memcpy (stream->buffer, buffer, length_buffer);
+ }
+ else
+ {
+ int new_length = stream->length_buffer + length_buffer;
+ if (new_length >= stream->sizeof_buffer)
+ {
+ stream->sizeof_buffer = new_length;
+ stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
+ }
+ memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
+ stream->length_buffer = new_length;
+ }
+}
+
+/* ``struct ui_file'' implementation that maps directly onto
+ <stdio.h>'s FILE. */
+
+static ui_file_write_ftype stdio_file_write;
+static ui_file_fputs_ftype stdio_file_fputs;
+static ui_file_read_ftype stdio_file_read;
+static ui_file_isatty_ftype stdio_file_isatty;
+static ui_file_delete_ftype stdio_file_delete;
+static struct ui_file *stdio_file_new (FILE * file, int close_p);
+static ui_file_flush_ftype stdio_file_flush;
+
+static int stdio_file_magic;
+
+struct stdio_file
+ {
+ int *magic;
+ FILE *file;
+ int close_p;
+ };
+
+static struct ui_file *
+stdio_file_new (FILE *file, int close_p)
+{
+ struct ui_file *ui_file = ui_file_new ();
+ struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
+ stdio->magic = &stdio_file_magic;
+ stdio->file = file;
+ stdio->close_p = close_p;
+ set_ui_file_data (ui_file, stdio, stdio_file_delete);
+ set_ui_file_flush (ui_file, stdio_file_flush);
+ set_ui_file_write (ui_file, stdio_file_write);
+ set_ui_file_fputs (ui_file, stdio_file_fputs);
+ set_ui_file_read (ui_file, stdio_file_read);
+ set_ui_file_isatty (ui_file, stdio_file_isatty);
+ return ui_file;
+}
+
+static void
+stdio_file_delete (struct ui_file *file)
+{
+ struct stdio_file *stdio = ui_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "stdio_file_delete: bad magic number");
+ if (stdio->close_p)
+ {
+ fclose (stdio->file);
+ }
+ xfree (stdio);
+}
+
+static void
+stdio_file_flush (struct ui_file *file)
+{
+ struct stdio_file *stdio = ui_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "stdio_file_flush: bad magic number");
+ fflush (stdio->file);
+}
+
+static long
+stdio_file_read (struct ui_file *file, char *buf, long length_buf)
+{
+ struct stdio_file *stdio = ui_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "stdio_file_read: bad magic number");
+ return read (fileno (stdio->file), buf, length_buf);
+}
+
+static void
+stdio_file_write (struct ui_file *file, const char *buf, long length_buf)
+{
+ struct stdio_file *stdio = ui_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "stdio_file_write: bad magic number");
+ fwrite (buf, length_buf, 1, stdio->file);
+}
+
+static void
+stdio_file_fputs (const char *linebuffer, struct ui_file *file)
+{
+ struct stdio_file *stdio = ui_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "stdio_file_fputs: bad magic number");
+ fputs (linebuffer, stdio->file);
+}
+
+static int
+stdio_file_isatty (struct ui_file *file)
+{
+ struct stdio_file *stdio = ui_file_data (file);
+ if (stdio->magic != &stdio_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "stdio_file_isatty: bad magic number");
+ return (isatty (fileno (stdio->file)));
+}
+
+/* Like fdopen(). Create a ui_file from a previously opened FILE. */
+
+struct ui_file *
+stdio_fileopen (FILE *file)
+{
+ return stdio_file_new (file, 0);
+}
+
+struct ui_file *
+gdb_fopen (char *name, char *mode)
+{
+ FILE *f = fopen (name, mode);
+ if (f == NULL)
+ return NULL;
+ return stdio_file_new (f, 1);
+}
+
+/* ``struct ui_file'' implementation that maps onto two ui-file objects. */
+
+static ui_file_write_ftype tee_file_write;
+static ui_file_fputs_ftype tee_file_fputs;
+static ui_file_isatty_ftype tee_file_isatty;
+static ui_file_delete_ftype tee_file_delete;
+static ui_file_flush_ftype tee_file_flush;
+
+static int tee_file_magic;
+
+struct tee_file
+ {
+ int *magic;
+ struct ui_file *one, *two;
+ int close_one, close_two;
+ };
+
+struct ui_file *
+tee_file_new (struct ui_file *one, int close_one,
+ struct ui_file *two, int close_two)
+{
+ struct ui_file *ui_file = ui_file_new ();
+ struct tee_file *tee = xmalloc (sizeof (struct tee_file));
+ tee->magic = &tee_file_magic;
+ tee->one = one;
+ tee->two = two;
+ tee->close_one = close_one;
+ tee->close_two = close_two;
+ set_ui_file_data (ui_file, tee, tee_file_delete);
+ set_ui_file_flush (ui_file, tee_file_flush);
+ set_ui_file_write (ui_file, tee_file_write);
+ set_ui_file_fputs (ui_file, tee_file_fputs);
+ set_ui_file_isatty (ui_file, tee_file_isatty);
+ return ui_file;
+}
+
+static void
+tee_file_delete (struct ui_file *file)
+{
+ struct tee_file *tee = ui_file_data (file);
+ if (tee->magic != &tee_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tee_file_delete: bad magic number");
+ if (tee->close_one)
+ ui_file_delete (tee->one);
+ if (tee->close_two)
+ ui_file_delete (tee->two);
+
+ xfree (tee);
+}
+
+static void
+tee_file_flush (struct ui_file *file)
+{
+ struct tee_file *tee = ui_file_data (file);
+ if (tee->magic != &tee_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tee_file_flush: bad magic number");
+ tee->one->to_flush (tee->one);
+ tee->two->to_flush (tee->two);
+}
+
+static void
+tee_file_write (struct ui_file *file, const char *buf, long length_buf)
+{
+ struct tee_file *tee = ui_file_data (file);
+ if (tee->magic != &tee_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tee_file_write: bad magic number");
+ ui_file_write (tee->one, buf, length_buf);
+ ui_file_write (tee->two, buf, length_buf);
+}
+
+static void
+tee_file_fputs (const char *linebuffer, struct ui_file *file)
+{
+ struct tee_file *tee = ui_file_data (file);
+ if (tee->magic != &tee_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tee_file_fputs: bad magic number");
+ tee->one->to_fputs (linebuffer, tee->one);
+ tee->two->to_fputs (linebuffer, tee->two);
+}
+
+static int
+tee_file_isatty (struct ui_file *file)
+{
+ struct tee_file *tee = ui_file_data (file);
+ if (tee->magic != &tee_file_magic)
+ internal_error (__FILE__, __LINE__,
+ "tee_file_isatty: bad magic number");
+ return (0);
+}
diff --git a/contrib/gdb/gdb/ui-file.h b/contrib/gdb/gdb/ui-file.h
new file mode 100644
index 0000000..8b28d1a
--- /dev/null
+++ b/contrib/gdb/gdb/ui-file.h
@@ -0,0 +1,105 @@
+/* UI_FILE - a generic STDIO like output stream.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 UI_FILE_H
+#define UI_FILE_H
+
+struct ui_file;
+
+/* Create a generic ui_file object with null methods. */
+
+extern struct ui_file *ui_file_new (void);
+
+/* Override methods used by specific implementations of a UI_FILE
+ object. */
+
+typedef void (ui_file_flush_ftype) (struct ui_file * stream);
+extern void set_ui_file_flush (struct ui_file *stream, ui_file_flush_ftype * flush);
+
+/* NOTE: Both fputs and write methods are available. Default
+ implementations that mapping one onto the other are included. */
+typedef void (ui_file_write_ftype) (struct ui_file * stream, const char *buf, long length_buf);
+extern void set_ui_file_write (struct ui_file *stream, ui_file_write_ftype *fputs);
+
+typedef void (ui_file_fputs_ftype) (const char *, struct ui_file * stream);
+extern void set_ui_file_fputs (struct ui_file *stream, ui_file_fputs_ftype * fputs);
+
+typedef long (ui_file_read_ftype) (struct ui_file * stream, char *buf, long length_buf);
+extern void set_ui_file_read (struct ui_file *stream, ui_file_read_ftype *fread);
+
+typedef int (ui_file_isatty_ftype) (struct ui_file * stream);
+extern void set_ui_file_isatty (struct ui_file *stream, ui_file_isatty_ftype * isatty);
+
+typedef void (ui_file_rewind_ftype) (struct ui_file * stream);
+extern void set_ui_file_rewind (struct ui_file *stream, ui_file_rewind_ftype * rewind);
+
+typedef void (ui_file_put_method_ftype) (void *object, const char *buffer, long length_buffer);
+typedef void (ui_file_put_ftype) (struct ui_file *stream, ui_file_put_method_ftype * method, void *context);
+extern void set_ui_file_put (struct ui_file *stream, ui_file_put_ftype * put);
+
+typedef void (ui_file_delete_ftype) (struct ui_file * stream);
+extern void set_ui_file_data (struct ui_file *stream, void *data, ui_file_delete_ftype * delete);
+
+extern void *ui_file_data (struct ui_file *file);
+
+
+extern void gdb_flush (struct ui_file *);
+
+extern void ui_file_delete (struct ui_file *stream);
+
+extern void ui_file_rewind (struct ui_file *stream);
+
+extern int ui_file_isatty (struct ui_file *);
+
+extern void ui_file_write (struct ui_file *file, const char *buf, long length_buf);
+
+/* NOTE: copies left to right */
+extern void ui_file_put (struct ui_file *src, ui_file_put_method_ftype *write, void *dest);
+
+/* Returns a freshly allocated buffer containing the entire contents
+ of FILE (as determined by ui_file_put()) with a NUL character
+ appended. LENGTH is set to the size of the buffer minus that
+ appended NUL. */
+extern char *ui_file_xstrdup (struct ui_file *file, long *length);
+
+
+
+extern long ui_file_read (struct ui_file *file, char *buf, long length_buf);
+
+/* Create/open a memory based file. Can be used as a scratch buffer
+ for collecting output. */
+extern struct ui_file *mem_fileopen (void);
+
+
+
+/* Open/create a an STDIO based UI_FILE using the already open FILE. */
+extern struct ui_file *stdio_fileopen (FILE *file);
+
+/* Open NAME returning an STDIO based UI_FILE. */
+extern struct ui_file *gdb_fopen (char *name, char *mode);
+
+/* Create a file which writes to both ONE and TWO. CLOSE_ONE
+ and CLOSE_TWO indicate whether the original files should be
+ closed when the new file is closed. */
+struct ui_file *tee_file_new (struct ui_file *one,
+ int close_one,
+ struct ui_file *two,
+ int close_two);
+#endif
diff --git a/contrib/gdb/gdb/ui-out.c b/contrib/gdb/gdb/ui-out.c
new file mode 100644
index 0000000..854ec49
--- /dev/null
+++ b/contrib/gdb/gdb/ui-out.c
@@ -0,0 +1,1163 @@
+/* Output generating routines for GDB.
+
+ Copyright 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions.
+ Written by Fernando Nasser 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 "defs.h"
+#include "gdb_string.h"
+#include "expression.h" /* For language.h */
+#include "language.h"
+#include "ui-out.h"
+#include "gdb_assert.h"
+
+/* table header structures */
+
+struct ui_out_hdr
+ {
+ int colno;
+ int width;
+ int alignment;
+ char *col_name;
+ char *colhdr;
+ struct ui_out_hdr *next;
+ };
+
+/* Maintain a stack so that the info applicable to the inner most list
+ is always available. Stack/nested level 0 is reserved for the
+ top-level result. */
+
+enum { MAX_UI_OUT_LEVELS = 6 };
+
+struct ui_out_level
+ {
+ /* Count each field; the first element is for non-list fields */
+ int field_count;
+ /* The type of this level. */
+ enum ui_out_type type;
+ };
+
+/* Tables are special. Maintain a separate structure that tracks
+ their state. At present an output can only contain a single table
+ but that restriction might eventually be lifted. */
+
+struct ui_out_table
+{
+ /* If on, a table is being generated. */
+ int flag;
+
+ /* If on, the body of a table is being generated. If off, the table
+ header is being generated. */
+ int body_flag;
+
+ /* The level at which each entry of the table is to be found. A row
+ (a tuple) is made up of entries. Consequently ENTRY_LEVEL is one
+ above that of the table. */
+ int entry_level;
+
+ /* Number of table columns (as specified in the table_begin call). */
+ int columns;
+
+ /* String identifying the table (as specified in the table_begin
+ call). */
+ char *id;
+
+ /* Points to the first table header (if any). */
+ struct ui_out_hdr *header_first;
+
+ /* Points to the last table header (if any). */
+ struct ui_out_hdr *header_last;
+
+ /* Points to header of NEXT column to format. */
+ struct ui_out_hdr *header_next;
+
+};
+
+
+/* The ui_out structure */
+/* Any change here requires a corresponding one in the initialization
+ of the default uiout, which is statically initialized */
+
+struct ui_out
+ {
+ int flags;
+ /* specific implementation of ui-out */
+ struct ui_out_impl *impl;
+ struct ui_out_data *data;
+
+ /* Sub structure tracking the ui-out depth. */
+ int level;
+ struct ui_out_level levels[MAX_UI_OUT_LEVELS];
+
+ /* A table, if any. At present only a single table is supported. */
+ struct ui_out_table table;
+ };
+
+/* The current (inner most) level. */
+static struct ui_out_level *
+current_level (struct ui_out *uiout)
+{
+ return &uiout->levels[uiout->level];
+}
+
+/* Create a new level, of TYPE. Return the new level's index. */
+static int
+push_level (struct ui_out *uiout,
+ enum ui_out_type type,
+ const char *id)
+{
+ struct ui_out_level *current;
+ /* We had better not overflow the buffer. */
+ uiout->level++;
+ gdb_assert (uiout->level >= 0 && uiout->level < MAX_UI_OUT_LEVELS);
+ current = current_level (uiout);
+ current->field_count = 0;
+ current->type = type;
+ return uiout->level;
+}
+
+/* Discard the current level, return the discarded level's index.
+ TYPE is the type of the level being discarded. */
+static int
+pop_level (struct ui_out *uiout,
+ enum ui_out_type type)
+{
+ /* We had better not underflow the buffer. */
+ gdb_assert (uiout->level > 0 && uiout->level < MAX_UI_OUT_LEVELS);
+ gdb_assert (current_level (uiout)->type == type);
+ uiout->level--;
+ return uiout->level + 1;
+}
+
+
+/* These are the default implementation functions */
+
+static void default_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows, const char *tblid);
+static void default_table_body (struct ui_out *uiout);
+static void default_table_end (struct ui_out *uiout);
+static void default_table_header (struct ui_out *uiout, int width,
+ enum ui_align alig, const char *col_name,
+ const char *colhdr);
+static void default_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level, const char *id);
+static void default_end (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level);
+static void default_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig,
+ const char *fldname,
+ int value);
+static void default_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig,
+ const char *fldname);
+static void default_field_string (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *string);
+static void default_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ const char *fldname,
+ const char *format,
+ va_list args);
+static void default_spaces (struct ui_out *uiout, int numspaces);
+static void default_text (struct ui_out *uiout, const char *string);
+static void default_message (struct ui_out *uiout, int verbosity,
+ const char *format,
+ va_list args);
+static void default_wrap_hint (struct ui_out *uiout, char *identstring);
+static void default_flush (struct ui_out *uiout);
+
+/* This is the default ui-out implementation functions vector */
+
+struct ui_out_impl default_ui_out_impl =
+{
+ default_table_begin,
+ default_table_body,
+ default_table_end,
+ default_table_header,
+ default_begin,
+ default_end,
+ default_field_int,
+ default_field_skip,
+ default_field_string,
+ default_field_fmt,
+ default_spaces,
+ default_text,
+ default_message,
+ default_wrap_hint,
+ default_flush,
+ NULL,
+ 0, /* Does not need MI hacks. */
+};
+
+/* The default ui_out */
+
+struct ui_out def_uiout =
+{
+ 0, /* flags */
+ &default_ui_out_impl, /* impl */
+};
+
+/* Pointer to current ui_out */
+/* FIXME: This should not be a global, but something passed down from main.c
+ or top.c */
+
+struct ui_out *uiout = &def_uiout;
+
+/* These are the interfaces to implementation functions */
+
+static void uo_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows, const char *tblid);
+static void uo_table_body (struct ui_out *uiout);
+static void uo_table_end (struct ui_out *uiout);
+static void uo_table_header (struct ui_out *uiout, int width,
+ enum ui_align align, const char *col_name,
+ const char *colhdr);
+static void uo_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level, const char *id);
+static void uo_end (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level);
+static void uo_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align, const char *fldname, int value);
+static void uo_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align, const char *fldname);
+static void uo_field_string (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align, const char *fldname,
+ const char *string);
+static void uo_field_fmt (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align, const char *fldname,
+ const char *format, va_list args);
+static void uo_spaces (struct ui_out *uiout, int numspaces);
+static void uo_text (struct ui_out *uiout, const char *string);
+static void uo_message (struct ui_out *uiout, int verbosity,
+ const char *format, va_list args);
+static void uo_wrap_hint (struct ui_out *uiout, char *identstring);
+static void uo_flush (struct ui_out *uiout);
+static int uo_redirect (struct ui_out *uiout, struct ui_file *outstream);
+
+/* Prototypes for local functions */
+
+extern void _initialize_ui_out (void);
+static void append_header_to_list (struct ui_out *uiout, int width,
+ int alignment, const char *col_name,
+ const char *colhdr);
+static int get_next_header (struct ui_out *uiout, int *colno, int *width,
+ int *alignment, char **colhdr);
+static void clear_header_list (struct ui_out *uiout);
+static void verify_field (struct ui_out *uiout, int *fldno, int *width,
+ int *align);
+
+/* exported functions (ui_out API) */
+
+/* Mark beginning of a table */
+
+static void
+ui_out_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows,
+ const char *tblid)
+{
+ if (uiout->table.flag)
+ internal_error (__FILE__, __LINE__,
+ "tables cannot be nested; table_begin found before \
+previous table_end.");
+
+ uiout->table.flag = 1;
+ uiout->table.body_flag = 0;
+ uiout->table.entry_level = uiout->level + 1;
+ uiout->table.columns = nbrofcols;
+ if (tblid != NULL)
+ uiout->table.id = xstrdup (tblid);
+ else
+ uiout->table.id = NULL;
+ clear_header_list (uiout);
+
+ uo_table_begin (uiout, nbrofcols, nr_rows, uiout->table.id);
+}
+
+void
+ui_out_table_body (struct ui_out *uiout)
+{
+ if (!uiout->table.flag)
+ internal_error (__FILE__, __LINE__,
+ "table_body outside a table is not valid; it must be \
+after a table_begin and before a table_end.");
+ if (uiout->table.body_flag)
+ internal_error (__FILE__, __LINE__,
+ "extra table_body call not allowed; there must be \
+only one table_body after a table_begin and before a table_end.");
+ if (uiout->table.header_next->colno != uiout->table.columns)
+ internal_error (__FILE__, __LINE__,
+ "number of headers differ from number of table \
+columns.");
+
+ uiout->table.body_flag = 1;
+ uiout->table.header_next = uiout->table.header_first;
+
+ uo_table_body (uiout);
+}
+
+static void
+ui_out_table_end (struct ui_out *uiout)
+{
+ if (!uiout->table.flag)
+ internal_error (__FILE__, __LINE__,
+ "misplaced table_end or missing table_begin.");
+
+ uiout->table.entry_level = 0;
+ uiout->table.body_flag = 0;
+ uiout->table.flag = 0;
+
+ uo_table_end (uiout);
+
+ if (uiout->table.id)
+ xfree (uiout->table.id);
+ clear_header_list (uiout);
+}
+
+void
+ui_out_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
+ const char *col_name,
+ const char *colhdr)
+{
+ if (!uiout->table.flag || uiout->table.body_flag)
+ internal_error (__FILE__, __LINE__,
+ "table header must be specified after table_begin \
+and before table_body.");
+
+ append_header_to_list (uiout, width, alignment, col_name, colhdr);
+
+ uo_table_header (uiout, width, alignment, col_name, colhdr);
+}
+
+static void
+do_cleanup_table_end (void *data)
+{
+ struct ui_out *ui_out = data;
+
+ ui_out_table_end (ui_out);
+}
+
+struct cleanup *
+make_cleanup_ui_out_table_begin_end (struct ui_out *ui_out, int nr_cols,
+ int nr_rows, const char *tblid)
+{
+ ui_out_table_begin (ui_out, nr_cols, nr_rows, tblid);
+ return make_cleanup (do_cleanup_table_end, ui_out);
+}
+
+void
+ui_out_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ const char *id)
+{
+ int new_level;
+ if (uiout->table.flag && !uiout->table.body_flag)
+ internal_error (__FILE__, __LINE__,
+ "table header or table_body expected; lists must be \
+specified after table_body.");
+
+ /* Be careful to verify the ``field'' before the new tuple/list is
+ pushed onto the stack. That way the containing list/table/row is
+ verified and not the newly created tuple/list. This verification
+ is needed (at least) for the case where a table row entry
+ contains either a tuple/list. For that case bookkeeping such as
+ updating the column count or advancing to the next heading still
+ needs to be performed. */
+ {
+ int fldno;
+ int width;
+ int align;
+ verify_field (uiout, &fldno, &width, &align);
+ }
+
+ new_level = push_level (uiout, type, id);
+
+ /* If the push puts us at the same level as a table row entry, we've
+ got a new table row. Put the header pointer back to the start. */
+ if (uiout->table.body_flag
+ && uiout->table.entry_level == new_level)
+ uiout->table.header_next = uiout->table.header_first;
+
+ uo_begin (uiout, type, new_level, id);
+}
+
+void
+ui_out_end (struct ui_out *uiout,
+ enum ui_out_type type)
+{
+ int old_level = pop_level (uiout, type);
+ uo_end (uiout, type, old_level);
+}
+
+struct ui_out_end_cleanup_data
+{
+ struct ui_out *uiout;
+ enum ui_out_type type;
+};
+
+static void
+do_cleanup_end (void *data)
+{
+ struct ui_out_end_cleanup_data *end_cleanup_data = data;
+ ui_out_end (end_cleanup_data->uiout, end_cleanup_data->type);
+ xfree (end_cleanup_data);
+}
+
+static struct cleanup *
+make_cleanup_ui_out_end (struct ui_out *uiout,
+ enum ui_out_type type)
+{
+ struct ui_out_end_cleanup_data *end_cleanup_data;
+ end_cleanup_data = XMALLOC (struct ui_out_end_cleanup_data);
+ end_cleanup_data->uiout = uiout;
+ end_cleanup_data->type = type;
+ return make_cleanup (do_cleanup_end, end_cleanup_data);
+}
+
+struct cleanup *
+make_cleanup_ui_out_tuple_begin_end (struct ui_out *uiout,
+ const char *id)
+{
+ ui_out_begin (uiout, ui_out_type_tuple, id);
+ return make_cleanup_ui_out_end (uiout, ui_out_type_tuple);
+}
+
+struct cleanup *
+make_cleanup_ui_out_list_begin_end (struct ui_out *uiout,
+ const char *id)
+{
+ ui_out_begin (uiout, ui_out_type_list, id);
+ return make_cleanup_ui_out_end (uiout, ui_out_type_list);
+}
+
+void
+ui_out_field_int (struct ui_out *uiout,
+ const char *fldname,
+ int value)
+{
+ int fldno;
+ int width;
+ int align;
+ struct ui_out_level *current = current_level (uiout);
+
+ verify_field (uiout, &fldno, &width, &align);
+
+ uo_field_int (uiout, fldno, width, align, fldname, value);
+}
+
+void
+ui_out_field_fmt_int (struct ui_out *uiout,
+ int input_width,
+ enum ui_align input_align,
+ const char *fldname,
+ int value)
+{
+ int fldno;
+ int width;
+ int align;
+ struct ui_out_level *current = current_level (uiout);
+
+ verify_field (uiout, &fldno, &width, &align);
+
+ uo_field_int (uiout, fldno, input_width, input_align, fldname, value);
+}
+
+void
+ui_out_field_core_addr (struct ui_out *uiout,
+ const char *fldname,
+ CORE_ADDR address)
+{
+ char addstr[20];
+
+ /* FIXME: cagney/2002-05-03: Need local_address_string() function
+ that returns the language localized string formatted to a width
+ based on TARGET_ADDR_BIT. */
+ /* print_address_numeric (address, 1, local_stream); */
+ if (TARGET_ADDR_BIT <= 32)
+ strcpy (addstr, local_hex_string_custom (address, "08l"));
+ else
+ strcpy (addstr, local_hex_string_custom (address, "016l"));
+
+ ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
+ui_out_field_stream (struct ui_out *uiout,
+ const char *fldname,
+ struct ui_stream *buf)
+{
+ long length;
+ char *buffer = ui_file_xstrdup (buf->stream, &length);
+ struct cleanup *old_cleanup = make_cleanup (xfree, buffer);
+ if (length > 0)
+ ui_out_field_string (uiout, fldname, buffer);
+ else
+ ui_out_field_skip (uiout, fldname);
+ ui_file_rewind (buf->stream);
+ do_cleanups (old_cleanup);
+}
+
+/* used to ommit a field */
+
+void
+ui_out_field_skip (struct ui_out *uiout,
+ const char *fldname)
+{
+ int fldno;
+ int width;
+ int align;
+
+ verify_field (uiout, &fldno, &width, &align);
+
+ uo_field_skip (uiout, fldno, width, align, fldname);
+}
+
+void
+ui_out_field_string (struct ui_out *uiout,
+ const char *fldname,
+ const char *string)
+{
+ int fldno;
+ int width;
+ int align;
+
+ verify_field (uiout, &fldno, &width, &align);
+
+ uo_field_string (uiout, fldno, width, align, fldname, string);
+}
+
+/* VARARGS */
+void
+ui_out_field_fmt (struct ui_out *uiout,
+ const char *fldname,
+ const char *format, ...)
+{
+ va_list args;
+ int fldno;
+ int width;
+ int align;
+
+ /* will not align, but has to call anyway */
+ verify_field (uiout, &fldno, &width, &align);
+
+ va_start (args, format);
+
+ uo_field_fmt (uiout, fldno, width, align, fldname, format, args);
+
+ va_end (args);
+}
+
+void
+ui_out_spaces (struct ui_out *uiout, int numspaces)
+{
+ uo_spaces (uiout, numspaces);
+}
+
+void
+ui_out_text (struct ui_out *uiout,
+ const char *string)
+{
+ uo_text (uiout, string);
+}
+
+void
+ui_out_message (struct ui_out *uiout, int verbosity,
+ const char *format,...)
+{
+ va_list args;
+
+ va_start (args, format);
+
+ uo_message (uiout, verbosity, format, args);
+
+ va_end (args);
+}
+
+struct ui_stream *
+ui_out_stream_new (struct ui_out *uiout)
+{
+ struct ui_stream *tempbuf;
+
+ tempbuf = XMALLOC (struct ui_stream);
+ tempbuf->uiout = uiout;
+ tempbuf->stream = mem_fileopen ();
+ return tempbuf;
+}
+
+void
+ui_out_stream_delete (struct ui_stream *buf)
+{
+ ui_file_delete (buf->stream);
+ xfree (buf);
+}
+
+static void
+do_stream_delete (void *buf)
+{
+ ui_out_stream_delete (buf);
+}
+
+struct cleanup *
+make_cleanup_ui_out_stream_delete (struct ui_stream *buf)
+{
+ return make_cleanup (do_stream_delete, buf);
+}
+
+
+void
+ui_out_wrap_hint (struct ui_out *uiout, char *identstring)
+{
+ uo_wrap_hint (uiout, identstring);
+}
+
+void
+ui_out_flush (struct ui_out *uiout)
+{
+ uo_flush (uiout);
+}
+
+int
+ui_out_redirect (struct ui_out *uiout, struct ui_file *outstream)
+{
+ return uo_redirect (uiout, outstream);
+}
+
+/* set the flags specified by the mask given */
+int
+ui_out_set_flags (struct ui_out *uiout, int mask)
+{
+ int oldflags = uiout->flags;
+
+ uiout->flags |= mask;
+
+ return oldflags;
+}
+
+/* clear the flags specified by the mask given */
+int
+ui_out_clear_flags (struct ui_out *uiout, int mask)
+{
+ int oldflags = uiout->flags;
+
+ uiout->flags &= ~mask;
+
+ return oldflags;
+}
+
+/* test the flags against the mask given */
+int
+ui_out_test_flags (struct ui_out *uiout, int mask)
+{
+ return (uiout->flags & mask);
+}
+
+/* obtain the current verbosity level (as stablished by the
+ 'set verbositylevel' command */
+
+int
+ui_out_get_verblvl (struct ui_out *uiout)
+{
+ /* FIXME: not implemented yet */
+ return 0;
+}
+
+#if 0
+void
+ui_out_result_begin (struct ui_out *uiout, char *class)
+{
+}
+
+void
+ui_out_result_end (struct ui_out *uiout)
+{
+}
+
+void
+ui_out_info_begin (struct ui_out *uiout, char *class)
+{
+}
+
+void
+ui_out_info_end (struct ui_out *uiout)
+{
+}
+
+void
+ui_out_notify_begin (struct ui_out *uiout, char *class)
+{
+}
+
+void
+ui_out_notify_end (struct ui_out *uiout)
+{
+}
+
+void
+ui_out_error_begin (struct ui_out *uiout, char *class)
+{
+}
+
+void
+ui_out_error_end (struct ui_out *uiout)
+{
+}
+#endif
+
+#if 0
+void
+gdb_error (ui_out * uiout, int severity, char *format,...)
+{
+ va_list args;
+}
+
+void
+gdb_query (struct ui_out *uiout, int qflags, char *qprompt)
+{
+}
+#endif
+
+int
+ui_out_is_mi_like_p (struct ui_out *uiout)
+{
+ return uiout->impl->is_mi_like_p;
+}
+
+/* default gdb-out hook functions */
+
+static void
+default_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows,
+ const char *tblid)
+{
+}
+
+static void
+default_table_body (struct ui_out *uiout)
+{
+}
+
+static void
+default_table_end (struct ui_out *uiout)
+{
+}
+
+static void
+default_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
+ const char *col_name,
+ const char *colhdr)
+{
+}
+
+static void
+default_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level,
+ const char *id)
+{
+}
+
+static void
+default_end (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level)
+{
+}
+
+static void
+default_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname, int value)
+{
+}
+
+static void
+default_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align, const char *fldname)
+{
+}
+
+static void
+default_field_string (struct ui_out *uiout,
+ int fldno,
+ int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *string)
+{
+}
+
+static void
+default_field_fmt (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *format,
+ va_list args)
+{
+}
+
+static void
+default_spaces (struct ui_out *uiout, int numspaces)
+{
+}
+
+static void
+default_text (struct ui_out *uiout, const char *string)
+{
+}
+
+static void
+default_message (struct ui_out *uiout, int verbosity,
+ const char *format,
+ va_list args)
+{
+}
+
+static void
+default_wrap_hint (struct ui_out *uiout, char *identstring)
+{
+}
+
+static void
+default_flush (struct ui_out *uiout)
+{
+}
+
+/* Interface to the implementation functions */
+
+void
+uo_table_begin (struct ui_out *uiout, int nbrofcols,
+ int nr_rows,
+ const char *tblid)
+{
+ if (!uiout->impl->table_begin)
+ return;
+ uiout->impl->table_begin (uiout, nbrofcols, nr_rows, tblid);
+}
+
+void
+uo_table_body (struct ui_out *uiout)
+{
+ if (!uiout->impl->table_body)
+ return;
+ uiout->impl->table_body (uiout);
+}
+
+void
+uo_table_end (struct ui_out *uiout)
+{
+ if (!uiout->impl->table_end)
+ return;
+ uiout->impl->table_end (uiout);
+}
+
+void
+uo_table_header (struct ui_out *uiout, int width, enum ui_align align,
+ const char *col_name,
+ const char *colhdr)
+{
+ if (!uiout->impl->table_header)
+ return;
+ uiout->impl->table_header (uiout, width, align, col_name, colhdr);
+}
+
+void
+uo_begin (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level,
+ const char *id)
+{
+ if (uiout->impl->begin == NULL)
+ return;
+ uiout->impl->begin (uiout, type, level, id);
+}
+
+void
+uo_end (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level)
+{
+ if (uiout->impl->end == NULL)
+ return;
+ uiout->impl->end (uiout, type, level);
+}
+
+void
+uo_field_int (struct ui_out *uiout, int fldno, int width, enum ui_align align,
+ const char *fldname,
+ int value)
+{
+ if (!uiout->impl->field_int)
+ return;
+ uiout->impl->field_int (uiout, fldno, width, align, fldname, value);
+}
+
+void
+uo_field_skip (struct ui_out *uiout, int fldno, int width, enum ui_align align,
+ const char *fldname)
+{
+ if (!uiout->impl->field_skip)
+ return;
+ uiout->impl->field_skip (uiout, fldno, width, align, fldname);
+}
+
+void
+uo_field_string (struct ui_out *uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *string)
+{
+ if (!uiout->impl->field_string)
+ return;
+ uiout->impl->field_string (uiout, fldno, width, align, fldname, string);
+}
+
+void
+uo_field_fmt (struct ui_out *uiout, int fldno, int width, enum ui_align align,
+ const char *fldname,
+ const char *format,
+ va_list args)
+{
+ if (!uiout->impl->field_fmt)
+ return;
+ uiout->impl->field_fmt (uiout, fldno, width, align, fldname, format, args);
+}
+
+void
+uo_spaces (struct ui_out *uiout, int numspaces)
+{
+ if (!uiout->impl->spaces)
+ return;
+ uiout->impl->spaces (uiout, numspaces);
+}
+
+void
+uo_text (struct ui_out *uiout,
+ const char *string)
+{
+ if (!uiout->impl->text)
+ return;
+ uiout->impl->text (uiout, string);
+}
+
+void
+uo_message (struct ui_out *uiout, int verbosity,
+ const char *format,
+ va_list args)
+{
+ if (!uiout->impl->message)
+ return;
+ uiout->impl->message (uiout, verbosity, format, args);
+}
+
+void
+uo_wrap_hint (struct ui_out *uiout, char *identstring)
+{
+ if (!uiout->impl->wrap_hint)
+ return;
+ uiout->impl->wrap_hint (uiout, identstring);
+}
+
+void
+uo_flush (struct ui_out *uiout)
+{
+ if (!uiout->impl->flush)
+ return;
+ uiout->impl->flush (uiout);
+}
+
+int
+uo_redirect (struct ui_out *uiout, struct ui_file *outstream)
+{
+ if (!uiout->impl->redirect)
+ return -1;
+ uiout->impl->redirect (uiout, outstream);
+ return 0;
+}
+
+/* local functions */
+
+/* list of column headers manipulation routines */
+
+static void
+clear_header_list (struct ui_out *uiout)
+{
+ while (uiout->table.header_first != NULL)
+ {
+ uiout->table.header_next = uiout->table.header_first;
+ uiout->table.header_first = uiout->table.header_first->next;
+ if (uiout->table.header_next->colhdr != NULL)
+ xfree (uiout->table.header_next->colhdr);
+ xfree (uiout->table.header_next);
+ }
+ gdb_assert (uiout->table.header_first == NULL);
+ uiout->table.header_last = NULL;
+ uiout->table.header_next = NULL;
+}
+
+static void
+append_header_to_list (struct ui_out *uiout,
+ int width,
+ int alignment,
+ const char *col_name,
+ const char *colhdr)
+{
+ struct ui_out_hdr *temphdr;
+
+ temphdr = XMALLOC (struct ui_out_hdr);
+ temphdr->width = width;
+ temphdr->alignment = alignment;
+ /* we have to copy the column title as the original may be an automatic */
+ if (colhdr != NULL)
+ temphdr->colhdr = xstrdup (colhdr);
+ else
+ temphdr->colhdr = NULL;
+ if (col_name != NULL)
+ temphdr->col_name = xstrdup (colhdr);
+ else
+ temphdr->col_name = xstrdup (colhdr);
+ temphdr->next = NULL;
+ if (uiout->table.header_first == NULL)
+ {
+ temphdr->colno = 1;
+ uiout->table.header_first = temphdr;
+ uiout->table.header_last = temphdr;
+ }
+ else
+ {
+ temphdr->colno = uiout->table.header_last->colno + 1;
+ uiout->table.header_last->next = temphdr;
+ uiout->table.header_last = temphdr;
+ }
+ uiout->table.header_next = uiout->table.header_last;
+}
+
+/* Extract the format information for the NEXT header and and advance
+ the header pointer. Return 0 if there was no next header. */
+
+static int
+get_next_header (struct ui_out *uiout,
+ int *colno,
+ int *width,
+ int *alignment,
+ char **colhdr)
+{
+ /* There may be no headers at all or we may have used all columns. */
+ if (uiout->table.header_next == NULL)
+ return 0;
+ *colno = uiout->table.header_next->colno;
+ *width = uiout->table.header_next->width;
+ *alignment = uiout->table.header_next->alignment;
+ *colhdr = uiout->table.header_next->colhdr;
+ /* Advance the header pointer to the next entry. */
+ uiout->table.header_next = uiout->table.header_next->next;
+ return 1;
+}
+
+
+/* Verify that the field/tuple/list is correctly positioned. Return
+ the field number and corresponding alignment (if
+ available/applicable). */
+
+static void
+verify_field (struct ui_out *uiout, int *fldno, int *width, int *align)
+{
+ struct ui_out_level *current = current_level (uiout);
+ char *text;
+
+ if (uiout->table.flag)
+ {
+ if (!uiout->table.body_flag)
+ internal_error (__FILE__, __LINE__,
+ "table_body missing; table fields must be \
+specified after table_body and inside a list.");
+ /* NOTE: cagney/2001-12-08: There was a check here to ensure
+ that this code was only executed when uiout->level was
+ greater than zero. That no longer applies - this code is run
+ before each table row tuple is started and at that point the
+ level is zero. */
+ }
+
+ current->field_count += 1;
+
+ if (uiout->table.body_flag
+ && uiout->table.entry_level == uiout->level
+ && get_next_header (uiout, fldno, width, align, &text))
+ {
+ if (*fldno != current->field_count)
+ internal_error (__FILE__, __LINE__,
+ "ui-out internal error in handling headers.");
+ }
+ else
+ {
+ *width = 0;
+ *align = ui_noalign;
+ *fldno = current->field_count;
+ }
+}
+
+
+/* access to ui_out format private members */
+
+void
+ui_out_get_field_separator (struct ui_out *uiout)
+{
+}
+
+/* Access to ui-out members data */
+
+struct ui_out_data *
+ui_out_data (struct ui_out *uiout)
+{
+ return uiout->data;
+}
+
+/* initalize private members at startup */
+
+struct ui_out *
+ui_out_new (struct ui_out_impl *impl,
+ struct ui_out_data *data,
+ int flags)
+{
+ struct ui_out *uiout = XMALLOC (struct ui_out);
+ uiout->data = data;
+ uiout->impl = impl;
+ uiout->flags = flags;
+ uiout->table.flag = 0;
+ uiout->table.body_flag = 0;
+ uiout->level = 0;
+ memset (uiout->levels, 0, sizeof (uiout->levels));
+ uiout->table.header_first = NULL;
+ uiout->table.header_last = NULL;
+ uiout->table.header_next = NULL;
+ return uiout;
+}
+
+/* standard gdb initialization hook */
+
+void
+_initialize_ui_out (void)
+{
+ /* nothing needs to be done */
+}
diff --git a/contrib/gdb/gdb/ui-out.h b/contrib/gdb/gdb/ui-out.h
new file mode 100644
index 0000000..5e19aff
--- /dev/null
+++ b/contrib/gdb/gdb/ui-out.h
@@ -0,0 +1,276 @@
+/* Output generating routines for GDB.
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+ Written by Fernando Nasser 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. */
+
+#ifndef UI_OUT_H
+#define UI_OUT_H 1
+
+/* The ui_out structure */
+
+struct ui_out;
+struct ui_out_data;
+struct ui_file;
+
+/* the current ui_out */
+
+/* FIXME: This should not be a global but something passed down from main.c
+ or top.c */
+extern struct ui_out *uiout;
+
+/* alignment enum */
+enum ui_align
+ {
+ ui_left = -1,
+ ui_center,
+ ui_right,
+ ui_noalign
+ };
+
+/* flags enum */
+enum ui_flags
+ {
+ ui_from_tty = 1,
+ ui_source_list = 2
+ };
+
+
+/* The ui_out stream structure. */
+/* NOTE: cagney/2000-02-01: The ui_stream object can be subsumed by
+ the more generic ui_file object. */
+
+struct ui_stream
+ {
+ struct ui_out *uiout;
+ struct ui_file *stream;
+ };
+
+
+/* Prototypes for ui-out API. */
+
+/* A result is a recursive data structure consisting of lists and
+ tuples. */
+
+enum ui_out_type
+ {
+ ui_out_type_tuple,
+ ui_out_type_list
+ };
+
+extern void ui_out_begin (struct ui_out *uiout,
+ enum ui_out_type level_type,
+ const char *id);
+
+extern void ui_out_end (struct ui_out *uiout, enum ui_out_type type);
+
+extern struct cleanup *ui_out_begin_cleanup_end (struct ui_out *uiout,
+ enum ui_out_type level_type,
+ const char *id);
+
+/* A table can be considered a special tuple/list combination with the
+ implied structure: ``table = { hdr = { header, ... } , body = [ {
+ field, ... }, ... ] }''. If NR_ROWS is negative then there is at
+ least one row. */
+extern void ui_out_table_header (struct ui_out *uiout, int width,
+ enum ui_align align, const char *col_name,
+ const char *colhdr);
+
+extern void ui_out_table_body (struct ui_out *uiout);
+
+extern struct cleanup *make_cleanup_ui_out_table_begin_end (struct ui_out *ui_out,
+ int nr_cols,
+ int nr_rows,
+ const char *tblid);
+/* Compatibility wrappers. */
+
+extern struct cleanup *make_cleanup_ui_out_list_begin_end (struct ui_out *uiout,
+ const char *id);
+
+extern struct cleanup *make_cleanup_ui_out_tuple_begin_end (struct ui_out *uiout,
+ const char *id);
+
+extern void ui_out_field_int (struct ui_out *uiout, const char *fldname,
+ int value);
+
+extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
+ enum ui_align align, const char *fldname,
+ int value);
+
+extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
+ CORE_ADDR address);
+
+extern void ui_out_field_string (struct ui_out * uiout, const char *fldname,
+ const char *string);
+
+extern void ui_out_field_stream (struct ui_out *uiout, const char *fldname,
+ struct ui_stream *buf);
+
+extern void ui_out_field_fmt (struct ui_out *uiout, const char *fldname,
+ const char *format, ...);
+
+extern void ui_out_field_skip (struct ui_out *uiout, const char *fldname);
+
+extern void ui_out_spaces (struct ui_out *uiout, int numspaces);
+
+extern void ui_out_text (struct ui_out *uiout, const char *string);
+
+extern void ui_out_message (struct ui_out *uiout, int verbosity,
+ const char *format, ...);
+
+extern struct ui_stream *ui_out_stream_new (struct ui_out *uiout);
+
+extern void ui_out_stream_delete (struct ui_stream *buf);
+
+struct cleanup *make_cleanup_ui_out_stream_delete (struct ui_stream *buf);
+
+extern void ui_out_wrap_hint (struct ui_out *uiout, char *identstring);
+
+extern void ui_out_flush (struct ui_out *uiout);
+
+extern void ui_out_get_field_separator (struct ui_out *uiout);
+
+extern int ui_out_set_flags (struct ui_out *uiout, int mask);
+
+extern int ui_out_clear_flags (struct ui_out *uiout, int mask);
+
+extern int ui_out_get_verblvl (struct ui_out *uiout);
+
+extern int ui_out_test_flags (struct ui_out *uiout, int mask);
+
+#if 0
+extern void ui_out_result_begin (struct ui_out *uiout, char *class);
+
+extern void ui_out_result_end (struct ui_out *uiout);
+
+extern void ui_out_info_begin (struct ui_out *uiout, char *class);
+
+extern void ui_out_info_end (struct ui_out *uiout);
+
+extern void ui_out_notify_begin (struct ui_out *uiout, char *class);
+
+extern void ui_out_notify_end (struct ui_out *uiout);
+
+extern void ui_out_error_begin (struct ui_out *uiout, char *class);
+
+extern void ui_out_error_end (struct ui_out *uiout);
+#endif
+
+#if 0
+extern void gdb_error (struct ui_out *uiout, int severity, char *format, ...);
+
+extern void gdb_query (struct ui_out *uiout, int qflags, char *qprompt);
+#endif
+
+/* HACK: Code in GDB is currently checking to see the type of ui_out
+ builder when determining which output to produce. This function is
+ a hack to encapsulate that test. Once GDB manages to separate the
+ CLI/MI from the core of GDB the problem should just go away .... */
+
+extern int ui_out_is_mi_like_p (struct ui_out *uiout);
+
+/* From here on we have things that are only needed by implementation
+ routines and main.c. We should pehaps have a separate file for that,
+ like a ui-out-impl.h file */
+
+/* User Interface Output Implementation Function Table */
+
+/* Type definition of all implementation functions. */
+
+typedef void (table_begin_ftype) (struct ui_out * uiout,
+ int nbrofcols, int nr_rows,
+ const char *tblid);
+typedef void (table_body_ftype) (struct ui_out * uiout);
+typedef void (table_end_ftype) (struct ui_out * uiout);
+typedef void (table_header_ftype) (struct ui_out * uiout, int width,
+ enum ui_align align, const char *col_name,
+ const char *colhdr);
+/* Note: level 0 is the top-level so LEVEL is always greater than
+ zero. */
+typedef void (ui_out_begin_ftype) (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level, const char *id);
+typedef void (ui_out_end_ftype) (struct ui_out *uiout,
+ enum ui_out_type type,
+ int level);
+typedef void (field_int_ftype) (struct ui_out * uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname, int value);
+typedef void (field_skip_ftype) (struct ui_out * uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname);
+typedef void (field_string_ftype) (struct ui_out * uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *string);
+typedef void (field_fmt_ftype) (struct ui_out * uiout, int fldno, int width,
+ enum ui_align align,
+ const char *fldname,
+ const char *format,
+ va_list args);
+typedef void (spaces_ftype) (struct ui_out * uiout, int numspaces);
+typedef void (text_ftype) (struct ui_out * uiout,
+ const char *string);
+typedef void (message_ftype) (struct ui_out * uiout, int verbosity,
+ const char *format, va_list args);
+typedef void (wrap_hint_ftype) (struct ui_out * uiout, char *identstring);
+typedef void (flush_ftype) (struct ui_out * uiout);
+typedef int (redirect_ftype) (struct ui_out * uiout,
+ struct ui_file * outstream);
+
+/* ui-out-impl */
+
+/* IMPORTANT: If you change this structure, make sure to change the default
+ initialization in ui-out.c */
+
+struct ui_out_impl
+ {
+ table_begin_ftype *table_begin;
+ table_body_ftype *table_body;
+ table_end_ftype *table_end;
+ table_header_ftype *table_header;
+ ui_out_begin_ftype *begin;
+ ui_out_end_ftype *end;
+ field_int_ftype *field_int;
+ field_skip_ftype *field_skip;
+ field_string_ftype *field_string;
+ field_fmt_ftype *field_fmt;
+ spaces_ftype *spaces;
+ text_ftype *text;
+ message_ftype *message;
+ wrap_hint_ftype *wrap_hint;
+ flush_ftype *flush;
+ redirect_ftype *redirect;
+ int is_mi_like_p;
+ };
+
+extern struct ui_out_data *ui_out_data (struct ui_out *uiout);
+
+
+/* Create a ui_out object */
+
+extern struct ui_out *ui_out_new (struct ui_out_impl *impl,
+ struct ui_out_data *data,
+ int flags);
+
+/* Redirect the ouptut of a ui_out object temporarily. */
+
+extern int ui_out_redirect (struct ui_out *uiout, struct ui_file *outstream);
+
+#endif /* UI_OUT_H */
diff --git a/contrib/gdb/gdb/user-regs.c b/contrib/gdb/gdb/user-regs.c
new file mode 100644
index 0000000..9de177f
--- /dev/null
+++ b/contrib/gdb/gdb/user-regs.c
@@ -0,0 +1,211 @@
+/* User visible, per-frame registers, for GDB, the GNU debugger.
+
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "user-regs.h"
+#include "gdbtypes.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "frame.h"
+
+/* A table of user registers.
+
+ User registers have regnum's that live above of the range [0
+ .. NUM_REGS + NUM_PSEUDO_REGS) (which is controlled by the target).
+ The target should never see a user register's regnum value.
+
+ Always append, never delete. By doing this, the relative regnum
+ (offset from NUM_REGS + NUM_PSEUDO_REGS) assigned to each user
+ register never changes. */
+
+struct user_reg
+{
+ const char *name;
+ struct value *(*read) (struct frame_info * frame);
+ struct user_reg *next;
+};
+
+/* This structure is named gdb_user_regs instead of user_regs to avoid
+ conflicts with any "struct user_regs" in system headers. For instance,
+ on ARM GNU/Linux native builds, nm-linux.h includes <signal.h> includes
+ <sys/ucontext.h> includes <sys/procfs.h> includes <sys/user.h>, which
+ declares "struct user_regs". */
+
+struct gdb_user_regs
+{
+ struct user_reg *first;
+ struct user_reg **last;
+};
+
+static void
+append_user_reg (struct gdb_user_regs *regs, const char *name,
+ user_reg_read_ftype *read, struct user_reg *reg)
+{
+ /* The caller is responsible for allocating memory needed to store
+ the register. By doing this, the function can operate on a
+ register list stored in the common heap or a specific obstack. */
+ gdb_assert (reg != NULL);
+ reg->name = name;
+ reg->read = read;
+ reg->next = NULL;
+ (*regs->last) = reg;
+ regs->last = &(*regs->last)->next;
+}
+
+/* An array of the builtin user registers. */
+
+static struct gdb_user_regs builtin_user_regs = { NULL, &builtin_user_regs.first };
+
+void
+user_reg_add_builtin (const char *name, user_reg_read_ftype *read)
+{
+ append_user_reg (&builtin_user_regs, name, read,
+ XMALLOC (struct user_reg));
+}
+
+/* Per-architecture user registers. Start with the builtin user
+ registers and then, again, append. */
+
+static struct gdbarch_data *user_regs_data;
+
+static void *
+user_regs_init (struct gdbarch *gdbarch)
+{
+ struct user_reg *reg;
+ struct gdb_user_regs *regs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct gdb_user_regs);
+ regs->last = &regs->first;
+ for (reg = builtin_user_regs.first; reg != NULL; reg = reg->next)
+ append_user_reg (regs, reg->name, reg->read,
+ GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg));
+ return regs;
+}
+
+void
+user_reg_add (struct gdbarch *gdbarch, const char *name,
+ user_reg_read_ftype *read)
+{
+ struct gdb_user_regs *regs = gdbarch_data (gdbarch, user_regs_data);
+ if (regs == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ regs = user_regs_init (gdbarch);
+ set_gdbarch_data (gdbarch, user_regs_data, regs);
+ }
+ append_user_reg (regs, name, read,
+ GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg));
+}
+
+int
+user_reg_map_name_to_regnum (struct gdbarch *gdbarch, const char *name,
+ int len)
+{
+ /* Make life easy, set the len to something reasonable. */
+ if (len < 0)
+ len = strlen (name);
+
+ /* Search register name space first - always let an architecture
+ specific register override the user registers. */
+ {
+ int i;
+ int maxregs = (gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch));
+ for (i = 0; i < maxregs; i++)
+ {
+ const char *regname = gdbarch_register_name (gdbarch, i);
+ if (regname != NULL && len == strlen (regname)
+ && strncmp (regname, name, len) == 0)
+ {
+ return i;
+ }
+ }
+ }
+
+ /* Search the user name space. */
+ {
+ struct gdb_user_regs *regs = gdbarch_data (gdbarch, user_regs_data);
+ struct user_reg *reg;
+ int nr;
+ for (nr = 0, reg = regs->first; reg != NULL; reg = reg->next, nr++)
+ {
+ if ((len < 0 && strcmp (reg->name, name))
+ || (len == strlen (reg->name)
+ && strncmp (reg->name, name, len) == 0))
+ return NUM_REGS + NUM_PSEUDO_REGS + nr;
+ }
+ }
+
+ return -1;
+}
+
+static struct user_reg *
+usernum_to_user_reg (struct gdbarch *gdbarch, int usernum)
+{
+ struct gdb_user_regs *regs = gdbarch_data (gdbarch, user_regs_data);
+ struct user_reg *reg;
+ for (reg = regs->first; reg != NULL; reg = reg->next)
+ {
+ if (usernum == 0)
+ return reg;
+ usernum--;
+ }
+ return NULL;
+}
+
+const char *
+user_reg_map_regnum_to_name (struct gdbarch *gdbarch, int regnum)
+{
+ int maxregs = (gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch));
+ if (regnum < 0)
+ return NULL;
+ else if (regnum < maxregs)
+ return gdbarch_register_name (gdbarch, regnum);
+ else
+ {
+ struct user_reg *reg = usernum_to_user_reg (gdbarch, regnum - maxregs);
+ if (reg == NULL)
+ return NULL;
+ else
+ return reg->name;
+ }
+}
+
+struct value *
+value_of_user_reg (int regnum, struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ int maxregs = (gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch));
+ struct user_reg *reg = usernum_to_user_reg (gdbarch, regnum - maxregs);
+ gdb_assert (reg != NULL);
+ return reg->read (frame);
+}
+
+extern initialize_file_ftype _initialize_user_regs; /* -Wmissing-prototypes */
+
+void
+_initialize_user_regs (void)
+{
+ user_regs_data = register_gdbarch_data (user_regs_init);
+}
diff --git a/contrib/gdb/gdb/user-regs.h b/contrib/gdb/gdb/user-regs.h
new file mode 100644
index 0000000..d845c8a
--- /dev/null
+++ b/contrib/gdb/gdb/user-regs.h
@@ -0,0 +1,71 @@
+/* Per-frame user registers, for GDB, the GNU debugger.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 USER_REGS_H
+#define USER_REGS_H
+
+/* Implement both builtin, and architecture specific, per-frame user
+ visible registers.
+
+ Builtin registers apply to all architectures, where as architecture
+ specific registers are present when the architecture is selected.
+
+ These registers are assigned register numbers outside the
+ architecture's register range [0 .. NUM_REGS + NUM_PSEUDO_REGS).
+ Their values should be constructed using per-frame information. */
+
+/* TODO: cagney/2003-06-27: Need to think more about how these
+ registers are added, read, and modified. At present they are kind
+ of assumed to be read-only. Should it, for instance, return a
+ register descriptor that contains all the relvent access methods. */
+
+struct frame_info;
+struct gdbarch;
+
+/* Given an architecture, map a user visible register name onto its
+ index. */
+
+extern int user_reg_map_name_to_regnum (struct gdbarch *gdbarch,
+ const char *str, int len);
+
+extern const char *user_reg_map_regnum_to_name (struct gdbarch *gdbarch,
+ int regnum);
+
+/* Return the value of the frame register in the specified frame.
+
+ Note; These methods return a "struct value" instead of the raw
+ bytes as, at the time the register is being added, the type needed
+ to describe the register has not bee initialized. */
+
+typedef struct value *(user_reg_read_ftype) (struct frame_info *frame);
+extern struct value *value_of_user_reg (int regnum, struct frame_info *frame);
+
+/* Add a builtin register (present in all architectures). */
+extern void user_reg_add_builtin (const char *name,
+ user_reg_read_ftype *read);
+
+/* Add a per-architecture frame register. */
+extern void user_reg_add (struct gdbarch *gdbarch, const char *name,
+ user_reg_read_ftype *read);
+
+#endif
diff --git a/contrib/gdb/gdb/utils.c b/contrib/gdb/gdb/utils.c
new file mode 100644
index 0000000..30ccebe
--- /dev/null
+++ b/contrib/gdb/gdb/utils.c
@@ -0,0 +1,3059 @@
+/* General utility routines for GDB, the GNU debugger.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_assert.h"
+#include <ctype.h>
+#include "gdb_string.h"
+#include "event-top.h"
+
+#ifdef TUI
+#include "tui/tui.h" /* For tui_get_command_dimension. */
+#endif
+
+#ifdef __GO32__
+#include <pc.h>
+#endif
+
+/* SunOS's curses.h has a '#define reg register' in it. Thank you Sun. */
+#ifdef reg
+#undef reg
+#endif
+
+#include <signal.h>
+#include "gdbcmd.h"
+#include "serial.h"
+#include "bfd.h"
+#include "target.h"
+#include "demangle.h"
+#include "expression.h"
+#include "language.h"
+#include "charset.h"
+#include "annotate.h"
+#include "filenames.h"
+
+#include "inferior.h" /* for signed_pointer_to_address */
+
+#include <sys/param.h> /* For MAXPATHLEN */
+
+#ifdef HAVE_CURSES_H
+#include <curses.h>
+#endif
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
+
+#include "readline/readline.h"
+
+#ifdef NEED_DECLARATION_MALLOC
+extern PTR malloc (); /* OK: PTR */
+#endif
+#ifdef NEED_DECLARATION_REALLOC
+extern PTR realloc (); /* OK: PTR */
+#endif
+#ifdef NEED_DECLARATION_FREE
+extern void free ();
+#endif
+/* Actually, we'll never have the decl, since we don't define _GNU_SOURCE. */
+#if defined(HAVE_CANONICALIZE_FILE_NAME) \
+ && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
+extern char *canonicalize_file_name (const char *);
+#endif
+
+/* readline defines this. */
+#undef savestring
+
+void (*error_begin_hook) (void);
+
+/* Holds the last error message issued by gdb */
+
+static struct ui_file *gdb_lasterr;
+
+/* Prototypes for local functions */
+
+static void vfprintf_maybe_filtered (struct ui_file *, const char *,
+ va_list, int);
+
+static void fputs_maybe_filtered (const char *, struct ui_file *, int);
+
+static void do_my_cleanups (struct cleanup **, struct cleanup *);
+
+static void prompt_for_continue (void);
+
+static void set_screen_size (void);
+static void set_width (void);
+
+/* Chain of cleanup actions established with make_cleanup,
+ to be executed if an error happens. */
+
+static struct cleanup *cleanup_chain; /* cleaned up after a failed command */
+static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */
+static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */
+static struct cleanup *exec_cleanup_chain; /* cleaned up on each execution command */
+/* cleaned up on each error from within an execution command */
+static struct cleanup *exec_error_cleanup_chain;
+
+/* Pointer to what is left to do for an execution command after the
+ target stops. Used only in asynchronous mode, by targets that
+ support async execution. The finish and until commands use it. So
+ does the target extended-remote command. */
+struct continuation *cmd_continuation;
+struct continuation *intermediate_continuation;
+
+/* 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++/ObjC names should be printed out in their
+ C++/ObjC form rather than raw. */
+
+int demangle = 1;
+
+/* Nonzero means that encoded C++/ObjC names should be printed out in their
+ C++/ObjC 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: ";
+
+int pagination_enabled = 1;
+
+
+/* Add a new cleanup to the cleanup_chain,
+ and return the previous chain pointer
+ to be passed later to do_cleanups or discard_cleanups.
+ Args are FUNCTION to clean up with, and ARG to pass to it. */
+
+struct cleanup *
+make_cleanup (make_cleanup_ftype *function, void *arg)
+{
+ return make_my_cleanup (&cleanup_chain, function, arg);
+}
+
+struct cleanup *
+make_final_cleanup (make_cleanup_ftype *function, void *arg)
+{
+ return make_my_cleanup (&final_cleanup_chain, function, arg);
+}
+
+struct cleanup *
+make_run_cleanup (make_cleanup_ftype *function, void *arg)
+{
+ return make_my_cleanup (&run_cleanup_chain, function, arg);
+}
+
+struct cleanup *
+make_exec_cleanup (make_cleanup_ftype *function, void *arg)
+{
+ return make_my_cleanup (&exec_cleanup_chain, function, arg);
+}
+
+struct cleanup *
+make_exec_error_cleanup (make_cleanup_ftype *function, void *arg)
+{
+ return make_my_cleanup (&exec_error_cleanup_chain, function, arg);
+}
+
+static void
+do_freeargv (void *arg)
+{
+ freeargv ((char **) arg);
+}
+
+struct cleanup *
+make_cleanup_freeargv (char **arg)
+{
+ return make_my_cleanup (&cleanup_chain, do_freeargv, arg);
+}
+
+static void
+do_bfd_close_cleanup (void *arg)
+{
+ bfd_close (arg);
+}
+
+struct cleanup *
+make_cleanup_bfd_close (bfd *abfd)
+{
+ return make_cleanup (do_bfd_close_cleanup, abfd);
+}
+
+static void
+do_close_cleanup (void *arg)
+{
+ int *fd = arg;
+ close (*fd);
+ xfree (fd);
+}
+
+struct cleanup *
+make_cleanup_close (int fd)
+{
+ int *saved_fd = xmalloc (sizeof (fd));
+ *saved_fd = fd;
+ return make_cleanup (do_close_cleanup, saved_fd);
+}
+
+static void
+do_ui_file_delete (void *arg)
+{
+ ui_file_delete (arg);
+}
+
+struct cleanup *
+make_cleanup_ui_file_delete (struct ui_file *arg)
+{
+ return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg);
+}
+
+struct cleanup *
+make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
+ void *arg)
+{
+ struct cleanup *new
+ = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+ struct cleanup *old_chain = *pmy_chain;
+
+ new->next = *pmy_chain;
+ new->function = function;
+ new->arg = arg;
+ *pmy_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 (struct cleanup *old_chain)
+{
+ do_my_cleanups (&cleanup_chain, old_chain);
+}
+
+void
+do_final_cleanups (struct cleanup *old_chain)
+{
+ do_my_cleanups (&final_cleanup_chain, old_chain);
+}
+
+void
+do_run_cleanups (struct cleanup *old_chain)
+{
+ do_my_cleanups (&run_cleanup_chain, old_chain);
+}
+
+void
+do_exec_cleanups (struct cleanup *old_chain)
+{
+ do_my_cleanups (&exec_cleanup_chain, old_chain);
+}
+
+void
+do_exec_error_cleanups (struct cleanup *old_chain)
+{
+ do_my_cleanups (&exec_error_cleanup_chain, old_chain);
+}
+
+static void
+do_my_cleanups (struct cleanup **pmy_chain,
+ struct cleanup *old_chain)
+{
+ struct cleanup *ptr;
+ while ((ptr = *pmy_chain) != old_chain)
+ {
+ *pmy_chain = ptr->next; /* Do this first incase recursion */
+ (*ptr->function) (ptr->arg);
+ xfree (ptr);
+ }
+}
+
+/* Discard cleanups, not doing the actions they describe,
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+discard_cleanups (struct cleanup *old_chain)
+{
+ discard_my_cleanups (&cleanup_chain, old_chain);
+}
+
+void
+discard_final_cleanups (struct cleanup *old_chain)
+{
+ discard_my_cleanups (&final_cleanup_chain, old_chain);
+}
+
+void
+discard_exec_error_cleanups (struct cleanup *old_chain)
+{
+ discard_my_cleanups (&exec_error_cleanup_chain, old_chain);
+}
+
+void
+discard_my_cleanups (struct cleanup **pmy_chain,
+ struct cleanup *old_chain)
+{
+ struct cleanup *ptr;
+ while ((ptr = *pmy_chain) != old_chain)
+ {
+ *pmy_chain = ptr->next;
+ xfree (ptr);
+ }
+}
+
+/* Set the cleanup_chain to 0, and return the old cleanup chain. */
+struct cleanup *
+save_cleanups (void)
+{
+ return save_my_cleanups (&cleanup_chain);
+}
+
+struct cleanup *
+save_final_cleanups (void)
+{
+ return save_my_cleanups (&final_cleanup_chain);
+}
+
+struct cleanup *
+save_my_cleanups (struct cleanup **pmy_chain)
+{
+ struct cleanup *old_chain = *pmy_chain;
+
+ *pmy_chain = 0;
+ return old_chain;
+}
+
+/* Restore the cleanup chain from a previously saved chain. */
+void
+restore_cleanups (struct cleanup *chain)
+{
+ restore_my_cleanups (&cleanup_chain, chain);
+}
+
+void
+restore_final_cleanups (struct cleanup *chain)
+{
+ restore_my_cleanups (&final_cleanup_chain, chain);
+}
+
+void
+restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain)
+{
+ *pmy_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 (void *ptr)
+{
+ void **location = ptr;
+ if (location == NULL)
+ internal_error (__FILE__, __LINE__,
+ "free_current_contents: NULL pointer");
+ if (*location != NULL)
+ {
+ xfree (*location);
+ *location = NULL;
+ }
+}
+
+/* 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. */
+
+void
+null_cleanup (void *arg)
+{
+}
+
+/* Add a continuation to the continuation list, the global list
+ cmd_continuation. The new continuation will be added at the front.*/
+void
+add_continuation (void (*continuation_hook) (struct continuation_arg *),
+ struct continuation_arg *arg_list)
+{
+ struct continuation *continuation_ptr;
+
+ continuation_ptr =
+ (struct continuation *) xmalloc (sizeof (struct continuation));
+ continuation_ptr->continuation_hook = continuation_hook;
+ continuation_ptr->arg_list = arg_list;
+ continuation_ptr->next = cmd_continuation;
+ cmd_continuation = continuation_ptr;
+}
+
+/* Walk down the cmd_continuation list, and execute all the
+ continuations. There is a problem though. In some cases new
+ continuations may be added while we are in the middle of this
+ loop. If this happens they will be added in the front, and done
+ before we have a chance of exhausting those that were already
+ there. We need to then save the beginning of the list in a pointer
+ and do the continuations from there on, instead of using the
+ global beginning of list as our iteration pointer.*/
+void
+do_all_continuations (void)
+{
+ struct continuation *continuation_ptr;
+ struct continuation *saved_continuation;
+
+ /* Copy the list header into another pointer, and set the global
+ list header to null, so that the global list can change as a side
+ effect of invoking the continuations and the processing of
+ the preexisting continuations will not be affected. */
+ continuation_ptr = cmd_continuation;
+ cmd_continuation = NULL;
+
+ /* Work now on the list we have set aside. */
+ while (continuation_ptr)
+ {
+ (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+ saved_continuation = continuation_ptr;
+ continuation_ptr = continuation_ptr->next;
+ xfree (saved_continuation);
+ }
+}
+
+/* Walk down the cmd_continuation list, and get rid of all the
+ continuations. */
+void
+discard_all_continuations (void)
+{
+ struct continuation *continuation_ptr;
+
+ while (cmd_continuation)
+ {
+ continuation_ptr = cmd_continuation;
+ cmd_continuation = continuation_ptr->next;
+ xfree (continuation_ptr);
+ }
+}
+
+/* Add a continuation to the continuation list, the global list
+ intermediate_continuation. The new continuation will be added at the front.*/
+void
+add_intermediate_continuation (void (*continuation_hook)
+ (struct continuation_arg *),
+ struct continuation_arg *arg_list)
+{
+ struct continuation *continuation_ptr;
+
+ continuation_ptr =
+ (struct continuation *) xmalloc (sizeof (struct continuation));
+ continuation_ptr->continuation_hook = continuation_hook;
+ continuation_ptr->arg_list = arg_list;
+ continuation_ptr->next = intermediate_continuation;
+ intermediate_continuation = continuation_ptr;
+}
+
+/* Walk down the cmd_continuation list, and execute all the
+ continuations. There is a problem though. In some cases new
+ continuations may be added while we are in the middle of this
+ loop. If this happens they will be added in the front, and done
+ before we have a chance of exhausting those that were already
+ there. We need to then save the beginning of the list in a pointer
+ and do the continuations from there on, instead of using the
+ global beginning of list as our iteration pointer.*/
+void
+do_all_intermediate_continuations (void)
+{
+ struct continuation *continuation_ptr;
+ struct continuation *saved_continuation;
+
+ /* Copy the list header into another pointer, and set the global
+ list header to null, so that the global list can change as a side
+ effect of invoking the continuations and the processing of
+ the preexisting continuations will not be affected. */
+ continuation_ptr = intermediate_continuation;
+ intermediate_continuation = NULL;
+
+ /* Work now on the list we have set aside. */
+ while (continuation_ptr)
+ {
+ (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+ saved_continuation = continuation_ptr;
+ continuation_ptr = continuation_ptr->next;
+ xfree (saved_continuation);
+ }
+}
+
+/* Walk down the cmd_continuation list, and get rid of all the
+ continuations. */
+void
+discard_all_intermediate_continuations (void)
+{
+ struct continuation *continuation_ptr;
+
+ while (intermediate_continuation)
+ {
+ continuation_ptr = intermediate_continuation;
+ intermediate_continuation = continuation_ptr->next;
+ xfree (continuation_ptr);
+ }
+}
+
+
+
+/* Print a warning message. The first argument STRING is the warning
+ message, used as an fprintf format string, the second is the
+ va_list of arguments for that string. A warning is unfiltered (not
+ paginated) so that the user does not need to page through each
+ screen full of warnings when there are lots of them. */
+
+void
+vwarning (const char *string, va_list args)
+{
+ if (warning_hook)
+ (*warning_hook) (string, args);
+ else
+ {
+ target_terminal_ours ();
+ wrap_here (""); /* Force out any buffered output */
+ gdb_flush (gdb_stdout);
+ if (warning_pre_print)
+ fputs_unfiltered (warning_pre_print, gdb_stderr);
+ vfprintf_unfiltered (gdb_stderr, string, args);
+ fprintf_unfiltered (gdb_stderr, "\n");
+ va_end (args);
+ }
+}
+
+/* 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. */
+
+void
+warning (const char *string, ...)
+{
+ va_list args;
+ va_start (args, string);
+ vwarning (string, args);
+ va_end (args);
+}
+
+/* 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. */
+
+NORETURN void
+verror (const char *string, va_list args)
+{
+ struct ui_file *tmp_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_stream);
+ vfprintf_unfiltered (tmp_stream, string, args);
+ error_stream (tmp_stream);
+}
+
+NORETURN void
+error (const char *string, ...)
+{
+ va_list args;
+ va_start (args, string);
+ verror (string, args);
+ va_end (args);
+}
+
+static void
+do_write (void *data, const char *buffer, long length_buffer)
+{
+ ui_file_write (data, buffer, length_buffer);
+}
+
+/* Cause a silent error to occur. Any error message is recorded
+ though it is not issued. */
+NORETURN void
+error_silent (const char *string, ...)
+{
+ va_list args;
+ struct ui_file *tmp_stream = mem_fileopen ();
+ va_start (args, string);
+ make_cleanup_ui_file_delete (tmp_stream);
+ vfprintf_unfiltered (tmp_stream, string, args);
+ /* Copy the stream into the GDB_LASTERR buffer. */
+ ui_file_rewind (gdb_lasterr);
+ ui_file_put (tmp_stream, do_write, gdb_lasterr);
+ va_end (args);
+
+ throw_exception (RETURN_ERROR);
+}
+
+/* Output an error message including any pre-print text to gdb_stderr. */
+void
+error_output_message (char *pre_print, char *msg)
+{
+ target_terminal_ours ();
+ wrap_here (""); /* Force out any buffered output */
+ gdb_flush (gdb_stdout);
+ annotate_error_begin ();
+ if (pre_print)
+ fputs_filtered (pre_print, gdb_stderr);
+ fputs_filtered (msg, gdb_stderr);
+ fprintf_filtered (gdb_stderr, "\n");
+}
+
+NORETURN void
+error_stream (struct ui_file *stream)
+{
+ if (error_begin_hook)
+ error_begin_hook ();
+
+ /* Copy the stream into the GDB_LASTERR buffer. */
+ ui_file_rewind (gdb_lasterr);
+ ui_file_put (stream, do_write, gdb_lasterr);
+
+ /* Write the message plus any error_pre_print to gdb_stderr. */
+ target_terminal_ours ();
+ wrap_here (""); /* Force out any buffered output */
+ gdb_flush (gdb_stdout);
+ annotate_error_begin ();
+ if (error_pre_print)
+ fputs_filtered (error_pre_print, gdb_stderr);
+ ui_file_put (stream, do_write, gdb_stderr);
+ fprintf_filtered (gdb_stderr, "\n");
+
+ throw_exception (RETURN_ERROR);
+}
+
+/* Get the last error message issued by gdb */
+
+char *
+error_last_message (void)
+{
+ long len;
+ return ui_file_xstrdup (gdb_lasterr, &len);
+}
+
+/* This is to be called by main() at the very beginning */
+
+void
+error_init (void)
+{
+ gdb_lasterr = mem_fileopen ();
+}
+
+/* Print a message reporting an internal error/warning. Ask the user
+ if they want to continue, dump core, or just exit. Return
+ something to indicate a quit. */
+
+struct internal_problem
+{
+ const char *name;
+ /* FIXME: cagney/2002-08-15: There should be ``maint set/show''
+ commands available for controlling these variables. */
+ enum auto_boolean should_quit;
+ enum auto_boolean should_dump_core;
+};
+
+/* Report a problem, internal to GDB, to the user. Once the problem
+ has been reported, and assuming GDB didn't quit, the caller can
+ either allow execution to resume or throw an error. */
+
+static void
+internal_vproblem (struct internal_problem *problem,
+ const char *file, int line, const char *fmt, va_list ap)
+{
+ static int dejavu;
+ int quit_p;
+ int dump_core_p;
+ char *reason;
+
+ /* Don't allow infinite error/warning recursion. */
+ {
+ static char msg[] = "Recursive internal problem.\n";
+ switch (dejavu)
+ {
+ case 0:
+ dejavu = 1;
+ break;
+ case 1:
+ dejavu = 2;
+ fputs_unfiltered (msg, gdb_stderr);
+ abort (); /* NOTE: GDB has only three calls to abort(). */
+ default:
+ dejavu = 3;
+ write (STDERR_FILENO, msg, sizeof (msg));
+ exit (1);
+ }
+ }
+
+ /* Try to get the message out and at the start of a new line. */
+ target_terminal_ours ();
+ begin_line ();
+
+ /* Create a string containing the full error/warning message. Need
+ to call query with this full string, as otherwize the reason
+ (error/warning) and question become separated. Format using a
+ style similar to a compiler error message. Include extra detail
+ so that the user knows that they are living on the edge. */
+ {
+ char *msg;
+ xvasprintf (&msg, fmt, ap);
+ xasprintf (&reason, "\
+%s:%d: %s: %s\n\
+A problem internal to GDB has been detected,\n\
+further debugging may prove unreliable.", file, line, problem->name, msg);
+ xfree (msg);
+ make_cleanup (xfree, reason);
+ }
+
+ switch (problem->should_quit)
+ {
+ case AUTO_BOOLEAN_AUTO:
+ /* Default (yes/batch case) is to quit GDB. When in batch mode
+ this lessens the likelhood of GDB going into an infinate
+ loop. */
+ quit_p = query ("%s\nQuit this debugging session? ", reason);
+ break;
+ case AUTO_BOOLEAN_TRUE:
+ quit_p = 1;
+ break;
+ case AUTO_BOOLEAN_FALSE:
+ quit_p = 0;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ switch (problem->should_dump_core)
+ {
+ case AUTO_BOOLEAN_AUTO:
+ /* Default (yes/batch case) is to dump core. This leaves a GDB
+ `dropping' so that it is easier to see that something went
+ wrong in GDB. */
+ dump_core_p = query ("%s\nCreate a core file of GDB? ", reason);
+ break;
+ break;
+ case AUTO_BOOLEAN_TRUE:
+ dump_core_p = 1;
+ break;
+ case AUTO_BOOLEAN_FALSE:
+ dump_core_p = 0;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ if (quit_p)
+ {
+ if (dump_core_p)
+ abort (); /* NOTE: GDB has only three calls to abort(). */
+ else
+ exit (1);
+ }
+ else
+ {
+ if (dump_core_p)
+ {
+ if (fork () == 0)
+ abort (); /* NOTE: GDB has only three calls to abort(). */
+ }
+ }
+
+ dejavu = 0;
+}
+
+static struct internal_problem internal_error_problem = {
+ "internal-error", AUTO_BOOLEAN_AUTO, AUTO_BOOLEAN_AUTO
+};
+
+NORETURN void
+internal_verror (const char *file, int line, const char *fmt, va_list ap)
+{
+ internal_vproblem (&internal_error_problem, file, line, fmt, ap);
+ throw_exception (RETURN_ERROR);
+}
+
+NORETURN void
+internal_error (const char *file, int line, const char *string, ...)
+{
+ va_list ap;
+ va_start (ap, string);
+ internal_verror (file, line, string, ap);
+ va_end (ap);
+}
+
+static struct internal_problem internal_warning_problem = {
+ "internal-error", AUTO_BOOLEAN_AUTO, AUTO_BOOLEAN_AUTO
+};
+
+void
+internal_vwarning (const char *file, int line, const char *fmt, va_list ap)
+{
+ internal_vproblem (&internal_warning_problem, file, line, fmt, ap);
+}
+
+void
+internal_warning (const char *file, int line, const char *string, ...)
+{
+ va_list ap;
+ va_start (ap, string);
+ internal_vwarning (file, line, string, ap);
+ va_end (ap);
+}
+
+/* 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 (int errnum)
+{
+ char *msg;
+ static char buf[32];
+
+ msg = strerror (errnum);
+ if (msg == NULL)
+ {
+ sprintf (buf, "(undocumented errno %d)", errnum);
+ 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. */
+
+NORETURN void
+perror_with_name (const 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 (const 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 (void)
+{
+ struct serial *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_drain_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)
+ fputs_unfiltered (quit_pre_print, gdb_stderr);
+
+#ifdef __MSDOS__
+ /* No steenking SIGINT will ever be coming our way when the
+ program is resumed. Don't lie. */
+ fprintf_unfiltered (gdb_stderr, "Quit\n");
+#else
+ 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");
+#endif
+ throw_exception (RETURN_QUIT);
+}
+
+/* Control C comes here */
+void
+request_quit (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);
+
+ if (immediate_quit)
+ quit ();
+}
+
+/* Memory management stuff (malloc friends). */
+
+static void *
+mmalloc (void *md, size_t size)
+{
+ return malloc (size); /* NOTE: GDB's only call to malloc() */
+}
+
+static void *
+mrealloc (void *md, void *ptr, size_t size)
+{
+ if (ptr == 0) /* Guard against old realloc's */
+ return mmalloc (md, size);
+ else
+ return realloc (ptr, size); /* NOTE: GDB's only call to ralloc() */
+}
+
+static void *
+mcalloc (void *md, size_t number, size_t size)
+{
+ return calloc (number, size); /* NOTE: GDB's only call to calloc() */
+}
+
+static void
+mfree (void *md, void *ptr)
+{
+ free (ptr); /* NOTE: GDB's only call to free() */
+}
+
+/* This used to do something interesting with USE_MMALLOC.
+ * It can be retired any time. -- chastain 2004-01-19. */
+void
+init_malloc (void *md)
+{
+}
+
+/* Called when a memory allocation fails, with the number of bytes of
+ memory requested in SIZE. */
+
+NORETURN void
+nomem (long size)
+{
+ if (size > 0)
+ {
+ internal_error (__FILE__, __LINE__,
+ "virtual memory exhausted: can't allocate %ld bytes.",
+ size);
+ }
+ else
+ {
+ internal_error (__FILE__, __LINE__, "virtual memory exhausted.");
+ }
+}
+
+/* The xmmalloc() family of memory management routines.
+
+ These are are like the mmalloc() family except that they implement
+ consistent semantics and guard against typical memory management
+ problems: if a malloc fails, an internal error is thrown; if
+ free(NULL) is called, it is ignored; if *alloc(0) is called, NULL
+ is returned.
+
+ All these routines are implemented using the mmalloc() family. */
+
+void *
+xmmalloc (void *md, size_t size)
+{
+ void *val;
+
+ /* See libiberty/xmalloc.c. This function need's to match that's
+ semantics. It never returns NULL. */
+ if (size == 0)
+ size = 1;
+
+ val = mmalloc (md, size);
+ if (val == NULL)
+ nomem (size);
+
+ return (val);
+}
+
+void *
+xmrealloc (void *md, void *ptr, size_t size)
+{
+ void *val;
+
+ /* See libiberty/xmalloc.c. This function need's to match that's
+ semantics. It never returns NULL. */
+ if (size == 0)
+ size = 1;
+
+ if (ptr != NULL)
+ val = mrealloc (md, ptr, size);
+ else
+ val = mmalloc (md, size);
+ if (val == NULL)
+ nomem (size);
+
+ return (val);
+}
+
+void *
+xmcalloc (void *md, size_t number, size_t size)
+{
+ void *mem;
+
+ /* See libiberty/xmalloc.c. This function need's to match that's
+ semantics. It never returns NULL. */
+ if (number == 0 || size == 0)
+ {
+ number = 1;
+ size = 1;
+ }
+
+ mem = mcalloc (md, number, size);
+ if (mem == NULL)
+ nomem (number * size);
+
+ return mem;
+}
+
+void
+xmfree (void *md, void *ptr)
+{
+ if (ptr != NULL)
+ mfree (md, ptr);
+}
+
+/* The xmalloc() (libiberty.h) family of memory management routines.
+
+ These are like the ISO-C malloc() family except that they implement
+ consistent semantics and guard against typical memory management
+ problems. See xmmalloc() above for further information.
+
+ All these routines are wrappers to the xmmalloc() family. */
+
+/* NOTE: These are declared using PTR to ensure consistency with
+ "libiberty.h". xfree() is GDB local. */
+
+PTR /* OK: PTR */
+xmalloc (size_t size)
+{
+ return xmmalloc (NULL, size);
+}
+
+PTR /* OK: PTR */
+xrealloc (PTR ptr, size_t size) /* OK: PTR */
+{
+ return xmrealloc (NULL, ptr, size);
+}
+
+PTR /* OK: PTR */
+xcalloc (size_t number, size_t size)
+{
+ return xmcalloc (NULL, number, size);
+}
+
+void
+xfree (void *ptr)
+{
+ xmfree (NULL, ptr);
+}
+
+
+/* Like asprintf/vasprintf but get an internal_error if the call
+ fails. */
+
+char *
+xstrprintf (const char *format, ...)
+{
+ char *ret;
+ va_list args;
+ va_start (args, format);
+ xvasprintf (&ret, format, args);
+ va_end (args);
+ return ret;
+}
+
+void
+xasprintf (char **ret, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ xvasprintf (ret, format, args);
+ va_end (args);
+}
+
+void
+xvasprintf (char **ret, const char *format, va_list ap)
+{
+ int status = vasprintf (ret, format, ap);
+ /* NULL could be returned due to a memory allocation problem; a
+ badly format string; or something else. */
+ if ((*ret) == NULL)
+ internal_error (__FILE__, __LINE__,
+ "vasprintf returned NULL buffer (errno %d)", errno);
+ /* A negative status with a non-NULL buffer shouldn't never
+ happen. But to be sure. */
+ if (status < 0)
+ internal_error (__FILE__, __LINE__,
+ "vasprintf call failed (errno %d)", errno);
+}
+
+
+/* My replacement for the read system call.
+ Used like `read' but keeps going if `read' returns too soon. */
+
+int
+myread (int desc, char *addr, int len)
+{
+ 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 (const char *ptr, size_t size)
+{
+ char *p = (char *) xmalloc (size + 1);
+ memcpy (p, ptr, size);
+ p[size] = 0;
+ return p;
+}
+
+char *
+msavestring (void *md, const char *ptr, size_t size)
+{
+ char *p = (char *) xmmalloc (md, size + 1);
+ memcpy (p, ptr, size);
+ p[size] = 0;
+ return p;
+}
+
+char *
+mstrsave (void *md, const char *ptr)
+{
+ return (msavestring (md, ptr, strlen (ptr)));
+}
+
+void
+print_spaces (int n, struct ui_file *file)
+{
+ fputs_unfiltered (n_spaces (n), file);
+}
+
+/* Print a host address. */
+
+void
+gdb_print_host_address (const void *addr, struct ui_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
+query (const char *ctlstr, ...)
+{
+ va_list args;
+ int answer;
+ int ans2;
+ int retval;
+
+ va_start (args, ctlstr);
+
+ 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;
+
+ 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");
+
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer == EOF) /* C-d */
+ {
+ retval = 1;
+ break;
+ }
+ /* Eat rest of input line, to EOF or newline */
+ if (answer != '\n')
+ do
+ {
+ ans2 = fgetc (stdin);
+ clearerr (stdin);
+ }
+ while (ans2 != EOF && ans2 != '\n' && ans2 != '\r');
+
+ 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;
+}
+
+
+/* This function supports the nquery() and yquery() functions.
+ Ask user a y-or-n question and return 0 if answer is no, 1 if
+ answer is yes, or default the answer to the specified default.
+ DEFCHAR is either 'y' or 'n' and refers to the default answer.
+ CTLSTR is the control string and should end in "? ". It should
+ not say how to answer, because we do that.
+ ARGS are the arguments passed along with the CTLSTR argument to
+ printf. */
+
+static int
+defaulted_query (const char *ctlstr, const char defchar, va_list args)
+{
+ int answer;
+ int ans2;
+ int retval;
+ int def_value;
+ char def_answer, not_def_answer;
+ char *y_string, *n_string;
+
+ /* Set up according to which answer is the default. */
+ if (defchar == 'y')
+ {
+ def_value = 1;
+ def_answer = 'Y';
+ not_def_answer = 'N';
+ y_string = "[y]";
+ n_string = "n";
+ }
+ else
+ {
+ def_value = 0;
+ def_answer = 'N';
+ not_def_answer = 'Y';
+ y_string = "y";
+ n_string = "[n]";
+ }
+
+ if (query_hook)
+ {
+ return query_hook (ctlstr, args);
+ }
+
+ /* Automatically answer default value if input is not from a terminal. */
+ if (!input_from_terminal_p ())
+ return def_value;
+
+ 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 ("(%s or %s) ", y_string, n_string);
+
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032query\n");
+
+ wrap_here ("");
+ gdb_flush (gdb_stdout);
+
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer == EOF) /* C-d */
+ {
+ retval = def_value;
+ break;
+ }
+ /* Eat rest of input line, to EOF or newline */
+ if (answer != '\n')
+ do
+ {
+ ans2 = fgetc (stdin);
+ clearerr (stdin);
+ }
+ while (ans2 != EOF && ans2 != '\n' && ans2 != '\r');
+
+ if (answer >= 'a')
+ answer -= 040;
+ /* Check answer. For the non-default, the user must specify
+ the non-default explicitly. */
+ if (answer == not_def_answer)
+ {
+ retval = !def_value;
+ break;
+ }
+ /* Otherwise, for the default, the user may either specify
+ the required input or have it default by entering nothing. */
+ if (answer == def_answer || answer == '\n' ||
+ answer == '\r' || answer == EOF)
+ {
+ retval = def_value;
+ break;
+ }
+ /* Invalid entries are not defaulted and require another selection. */
+ printf_filtered ("Please answer %s or %s.\n",
+ y_string, n_string);
+ }
+
+ if (annotation_level > 1)
+ printf_filtered ("\n\032\032post-query\n");
+ return retval;
+}
+
+
+/* Ask user a y-or-n question and return 0 if answer is no, 1 if
+ answer is yes, or 0 if answer is defaulted.
+ 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. */
+
+int
+nquery (const char *ctlstr, ...)
+{
+ va_list args;
+
+ va_start (args, ctlstr);
+ return defaulted_query (ctlstr, 'n', args);
+ va_end (args);
+}
+
+/* Ask user a y-or-n question and return 0 if answer is no, 1 if
+ answer is yes, or 1 if answer is defaulted.
+ 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. */
+
+int
+yquery (const char *ctlstr, ...)
+{
+ va_list args;
+
+ va_start (args, ctlstr);
+ return defaulted_query (ctlstr, 'y', args);
+ va_end (args);
+}
+
+/* Print an error message saying that we couldn't make sense of a
+ \^mumble sequence in a string or character constant. START and END
+ indicate a substring of some larger string that contains the
+ erroneous backslash sequence, missing the initial backslash. */
+static NORETURN int
+no_control_char_error (const char *start, const char *end)
+{
+ int len = end - start;
+ char *copy = alloca (end - start + 1);
+
+ memcpy (copy, start, len);
+ copy[len] = '\0';
+
+ error ("There is no control character `\\%s' in the `%s' character set.",
+ copy, target_charset ());
+}
+
+/* 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 (char **string_ptr)
+{
+ int target_char;
+ int c = *(*string_ptr)++;
+ if (c_parse_backslash (c, &target_char))
+ return target_char;
+ else
+ switch (c)
+ {
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ {
+ /* Remember where this escape sequence started, for reporting
+ errors. */
+ char *sequence_start_pos = *string_ptr - 1;
+
+ c = *(*string_ptr)++;
+
+ if (c == '?')
+ {
+ /* XXXCHARSET: What is `delete' in the host character set? */
+ c = 0177;
+
+ if (!host_char_to_target (c, &target_char))
+ error ("There is no character corresponding to `Delete' "
+ "in the target character set `%s'.", host_charset ());
+
+ return target_char;
+ }
+ else if (c == '\\')
+ target_char = parse_escape (string_ptr);
+ else
+ {
+ if (!host_char_to_target (c, &target_char))
+ no_control_char_error (sequence_start_pos, *string_ptr);
+ }
+
+ /* Now target_char is something like `c', and we want to find
+ its control-character equivalent. */
+ if (!target_char_to_control_char (target_char, &target_char))
+ no_control_char_error (sequence_start_pos, *string_ptr);
+
+ return target_char;
+ }
+
+ /* XXXCHARSET: we need to use isdigit and value-of-digit
+ methods of the host character set here. */
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int i = c - '0';
+ int count = 0;
+ while (++count < 3)
+ {
+ c = (**string_ptr);
+ if (c >= '0' && c <= '7')
+ {
+ (*string_ptr)++;
+ i *= 8;
+ i += c - '0';
+ }
+ else
+ {
+ break;
+ }
+ }
+ return i;
+ }
+ default:
+ if (!host_char_to_target (c, &target_char))
+ error
+ ("The escape sequence `\%c' is equivalent to plain `%c', which"
+ " has no equivalent\n" "in the `%s' character set.", c, c,
+ target_charset ());
+ return target_char;
+ }
+}
+
+/* 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. */
+
+static void
+printchar (int c, void (*do_fputs) (const char *, struct ui_file *),
+ void (*do_fprintf) (struct ui_file *, const char *, ...),
+ struct ui_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':
+ do_fputs ("\\n", stream);
+ break;
+ case '\b':
+ do_fputs ("\\b", stream);
+ break;
+ case '\t':
+ do_fputs ("\\t", stream);
+ break;
+ case '\f':
+ do_fputs ("\\f", stream);
+ break;
+ case '\r':
+ do_fputs ("\\r", stream);
+ break;
+ case '\033':
+ do_fputs ("\\e", stream);
+ break;
+ case '\007':
+ do_fputs ("\\a", stream);
+ break;
+ default:
+ do_fprintf (stream, "\\%.3o", (unsigned int) c);
+ break;
+ }
+ }
+ else
+ {
+ if (c == '\\' || c == quoter)
+ do_fputs ("\\", stream);
+ do_fprintf (stream, "%c", c);
+ }
+}
+
+/* Print the character C on STREAM as part of the contents of a
+ literal string whose delimiter is QUOTER. Note that these routines
+ should only be call for printing things which are independent of
+ the language of the program being debugged. */
+
+void
+fputstr_filtered (const char *str, int quoter, struct ui_file *stream)
+{
+ while (*str)
+ printchar (*str++, fputs_filtered, fprintf_filtered, stream, quoter);
+}
+
+void
+fputstr_unfiltered (const char *str, int quoter, struct ui_file *stream)
+{
+ while (*str)
+ printchar (*str++, fputs_unfiltered, fprintf_unfiltered, stream, quoter);
+}
+
+void
+fputstrn_unfiltered (const char *str, int n, int quoter,
+ struct ui_file *stream)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ printchar (str[i], fputs_unfiltered, fprintf_unfiltered, stream, quoter);
+}
+
+
+/* Number of lines per page or UINT_MAX if paging is disabled. */
+static unsigned int lines_per_page;
+
+/* Number of chars per line or UINT_MAX if 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;
+
+
+/* Inialize the number of lines per page and chars per line. */
+
+void
+init_page_info (void)
+{
+#if defined(TUI)
+ if (!tui_get_command_dimension (&chars_per_line, &lines_per_page))
+#endif
+ {
+ int rows, cols;
+
+#if defined(__GO32__)
+ rows = ScreenRows ();
+ cols = ScreenCols ();
+ lines_per_page = rows;
+ chars_per_line = cols;
+#else
+ /* Make sure Readline has initialized its terminal settings. */
+ rl_reset_terminal (NULL);
+
+ /* Get the screen size from Readline. */
+ rl_get_screen_size (&rows, &cols);
+ lines_per_page = rows;
+ chars_per_line = cols;
+
+ /* Readline should have fetched the termcap entry for us. */
+ if (tgetnum ("li") < 0 || getenv ("EMACS"))
+ {
+ /* 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;
+ }
+
+ /* FIXME: Get rid of this junk. */
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+ SIGWINCH_HANDLER (SIGWINCH);
+#endif
+
+ /* If the output is not a terminal, don't paginate it. */
+ if (!ui_file_isatty (gdb_stdout))
+ lines_per_page = UINT_MAX;
+#endif
+ }
+
+ set_screen_size ();
+ set_width ();
+}
+
+/* Set the screen size based on LINES_PER_PAGE and CHARS_PER_LINE. */
+
+static void
+set_screen_size (void)
+{
+ int rows = lines_per_page;
+ int cols = chars_per_line;
+
+ if (rows <= 0)
+ rows = INT_MAX;
+
+ if (cols <= 0)
+ rl_get_screen_size (NULL, &cols);
+
+ /* Update Readline's idea of the terminal size. */
+ rl_set_screen_size (rows, cols);
+}
+
+/* Reinitialize WRAP_BUFFER according to the current value of
+ CHARS_PER_LINE. */
+
+static void
+set_width (void)
+{
+ if (chars_per_line == 0)
+ init_page_info ();
+
+ 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. */
+}
+
+static void
+set_width_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_screen_size ();
+ set_width ();
+}
+
+static void
+set_height_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_screen_size ();
+}
+
+/* Wait, so the user can read what's on the screen. Prompt the user
+ to continue by pressing RETURN. */
+
+static void
+prompt_for_continue (void)
+{
+ char *ignore;
+ char cont_prompt[120];
+
+ if (annotation_level > 1)
+ printf_unfiltered ("\n\032\032pre-prompt-for-continue\n");
+
+ strcpy (cont_prompt,
+ "---Type <return> to continue, or q <return> 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 = gdb_readline_wrapper (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')
+ {
+ if (!event_loop_p)
+ request_quit (SIGINT);
+ else
+ async_request_quit (0);
+ }
+ xfree (ignore);
+ }
+ immediate_quit--;
+
+ /* Now we have to do this again, so that GDB will know that it doesn't
+ need to save the ---Type <return>--- 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 (void)
+{
+ 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 (char *indent)
+{
+ /* This should have been allocated, but be paranoid anyway. */
+ if (!wrap_buffer)
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ 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;
+ }
+}
+
+/* Print input string to gdb_stdout, filtered, with wrap,
+ arranging strings in columns of n chars. String can be
+ right or left justified in the column. Never prints
+ trailing spaces. String should never be longer than
+ width. FIXME: this could be useful for the EXAMINE
+ command, which currently doesn't tabulate very well */
+
+void
+puts_filtered_tabular (char *string, int width, int right)
+{
+ int spaces = 0;
+ int stringlen;
+ char *spacebuf;
+
+ gdb_assert (chars_per_line > 0);
+ if (chars_per_line == UINT_MAX)
+ {
+ fputs_filtered (string, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ return;
+ }
+
+ if (((chars_printed - 1) / width + 2) * width >= chars_per_line)
+ fputs_filtered ("\n", gdb_stdout);
+
+ if (width >= chars_per_line)
+ width = chars_per_line - 1;
+
+ stringlen = strlen (string);
+
+ if (chars_printed > 0)
+ spaces = width - (chars_printed - 1) % width - 1;
+ if (right)
+ spaces += width - stringlen;
+
+ spacebuf = alloca (spaces + 1);
+ spacebuf[spaces] = '\0';
+ while (spaces--)
+ spacebuf[spaces] = ' ';
+
+ fputs_filtered (spacebuf, gdb_stdout);
+ fputs_filtered (string, gdb_stdout);
+}
+
+
+/* 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 (void)
+{
+ if (chars_printed > 0)
+ {
+ puts_filtered ("\n");
+ }
+}
+
+
+/* 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 (const char *linebuffer, struct ui_file *stream,
+ int filter)
+{
+ const char *lineptr;
+
+ if (linebuffer == 0)
+ return;
+
+ /* Don't do any filtering if it is disabled. */
+ if ((stream != gdb_stdout) || !pagination_enabled
+ || (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 (const char *linebuffer, struct ui_file *stream)
+{
+ fputs_maybe_filtered (linebuffer, stream, 1);
+}
+
+int
+putchar_unfiltered (int c)
+{
+ char buf = c;
+ ui_file_write (gdb_stdout, &buf, 1);
+ return c;
+}
+
+/* Write character C to gdb_stdout using GDB's paging mechanism and return C.
+ May return nonlocally. */
+
+int
+putchar_filtered (int c)
+{
+ return fputc_filtered (c, gdb_stdout);
+}
+
+int
+fputc_unfiltered (int c, struct ui_file *stream)
+{
+ char buf = c;
+ ui_file_write (stream, &buf, 1);
+ return c;
+}
+
+int
+fputc_filtered (int c, struct ui_file *stream)
+{
+ char buf[2];
+
+ buf[0] = c;
+ buf[1] = 0;
+ fputs_filtered (buf, stream);
+ return c;
+}
+
+/* puts_debug is like fputs_unfiltered, except it prints special
+ characters in printable fashion. */
+
+void
+puts_debug (char *prefix, char *string, char *suffix)
+{
+ int ch;
+
+ /* Print prefix and suffix after each line. */
+ static int new_line = 1;
+ static int return_p = 0;
+ static char *prev_prefix = "";
+ static char *prev_suffix = "";
+
+ if (*string == '\n')
+ return_p = 0;
+
+ /* If the prefix is changing, print the previous suffix, a new line,
+ and the new prefix. */
+ if ((return_p || (strcmp (prev_prefix, prefix) != 0)) && !new_line)
+ {
+ fputs_unfiltered (prev_suffix, gdb_stdlog);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ fputs_unfiltered (prefix, gdb_stdlog);
+ }
+
+ /* Print prefix if we printed a newline during the previous call. */
+ if (new_line)
+ {
+ new_line = 0;
+ fputs_unfiltered (prefix, gdb_stdlog);
+ }
+
+ prev_prefix = prefix;
+ prev_suffix = suffix;
+
+ /* Output characters in a printable format. */
+ while ((ch = *string++) != '\0')
+ {
+ switch (ch)
+ {
+ default:
+ if (isprint (ch))
+ fputc_unfiltered (ch, gdb_stdlog);
+
+ else
+ fprintf_unfiltered (gdb_stdlog, "\\x%02x", ch & 0xff);
+ break;
+
+ case '\\':
+ fputs_unfiltered ("\\\\", gdb_stdlog);
+ break;
+ case '\b':
+ fputs_unfiltered ("\\b", gdb_stdlog);
+ break;
+ case '\f':
+ fputs_unfiltered ("\\f", gdb_stdlog);
+ break;
+ case '\n':
+ new_line = 1;
+ fputs_unfiltered ("\\n", gdb_stdlog);
+ break;
+ case '\r':
+ fputs_unfiltered ("\\r", gdb_stdlog);
+ break;
+ case '\t':
+ fputs_unfiltered ("\\t", gdb_stdlog);
+ break;
+ case '\v':
+ fputs_unfiltered ("\\v", gdb_stdlog);
+ break;
+ }
+
+ return_p = ch == '\r';
+ }
+
+ /* Print suffix if we printed a newline. */
+ if (new_line)
+ {
+ fputs_unfiltered (suffix, gdb_stdlog);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ }
+}
+
+
+/* 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 (struct ui_file *stream, const char *format,
+ va_list args, int filter)
+{
+ char *linebuffer;
+ struct cleanup *old_cleanups;
+
+ xvasprintf (&linebuffer, format, args);
+ old_cleanups = make_cleanup (xfree, linebuffer);
+ fputs_maybe_filtered (linebuffer, stream, filter);
+ do_cleanups (old_cleanups);
+}
+
+
+void
+vfprintf_filtered (struct ui_file *stream, const char *format, va_list args)
+{
+ vfprintf_maybe_filtered (stream, format, args, 1);
+}
+
+void
+vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args)
+{
+ char *linebuffer;
+ struct cleanup *old_cleanups;
+
+ xvasprintf (&linebuffer, format, args);
+ old_cleanups = make_cleanup (xfree, linebuffer);
+ fputs_unfiltered (linebuffer, stream);
+ do_cleanups (old_cleanups);
+}
+
+void
+vprintf_filtered (const char *format, va_list args)
+{
+ vfprintf_maybe_filtered (gdb_stdout, format, args, 1);
+}
+
+void
+vprintf_unfiltered (const char *format, va_list args)
+{
+ vfprintf_unfiltered (gdb_stdout, format, args);
+}
+
+void
+fprintf_filtered (struct ui_file *stream, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+}
+
+void
+fprintf_unfiltered (struct ui_file *stream, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ vfprintf_unfiltered (stream, format, args);
+ va_end (args);
+}
+
+/* Like fprintf_filtered, but prints its result indented.
+ Called as fprintfi_filtered (spaces, stream, format, ...); */
+
+void
+fprintfi_filtered (int spaces, struct ui_file *stream, const char *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ print_spaces_filtered (spaces, stream);
+
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+}
+
+
+void
+printf_filtered (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ vfprintf_filtered (gdb_stdout, format, args);
+ va_end (args);
+}
+
+
+void
+printf_unfiltered (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ vfprintf_unfiltered (gdb_stdout, format, args);
+ va_end (args);
+}
+
+/* Like printf_filtered, but prints it's result indented.
+ Called as printfi_filtered (spaces, format, ...); */
+
+void
+printfi_filtered (int spaces, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ 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 (const char *string)
+{
+ fputs_filtered (string, gdb_stdout);
+}
+
+void
+puts_unfiltered (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 (int n)
+{
+ char *t;
+ static char *spaces = 0;
+ static int max_spaces = -1;
+
+ if (n > max_spaces)
+ {
+ if (spaces)
+ xfree (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 (int n, struct ui_file *stream)
+{
+ fputs_filtered (n_spaces (n), stream);
+}
+
+/* C++/ObjC 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 (struct ui_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
+ {
+ demangled = language_demangle (language_def (lang), name, arg_mode);
+ fputs_filtered (demangled ? demangled : name, stream);
+ if (demangled != NULL)
+ {
+ xfree (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 (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');
+}
+
+/* This is like strcmp except that it ignores whitespace and treats
+ '(' as the first non-NULL character in terms of ordering. Like
+ strcmp (and unlike strcmp_iw), it returns negative if STRING1 <
+ STRING2, 0 if STRING2 = STRING2, and positive if STRING1 > STRING2
+ according to that ordering.
+
+ If a list is sorted according to this function and if you want to
+ find names in the list that match some fixed NAME according to
+ strcmp_iw(LIST_ELT, NAME), then the place to start looking is right
+ where this function would put NAME.
+
+ Here are some examples of why using strcmp to sort is a bad idea:
+
+ Whitespace example:
+
+ Say your partial symtab contains: "foo<char *>", "goo". Then, if
+ we try to do a search for "foo<char*>", strcmp will locate this
+ after "foo<char *>" and before "goo". Then lookup_partial_symbol
+ will start looking at strings beginning with "goo", and will never
+ see the correct match of "foo<char *>".
+
+ Parenthesis example:
+
+ In practice, this is less like to be an issue, but I'll give it a
+ shot. Let's assume that '$' is a legitimate character to occur in
+ symbols. (Which may well even be the case on some systems.) Then
+ say that the partial symbol table contains "foo$" and "foo(int)".
+ strcmp will put them in this order, since '$' < '('. Now, if the
+ user searches for "foo", then strcmp will sort "foo" before "foo$".
+ Then lookup_partial_symbol will notice that strcmp_iw("foo$",
+ "foo") is false, so it won't proceed to the actual match of
+ "foo(int)" with "foo". */
+
+int
+strcmp_iw_ordered (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++;
+ }
+ }
+
+ switch (*string1)
+ {
+ /* Characters are non-equal unless they're both '\0'; we want to
+ make sure we get the comparison right according to our
+ comparison in the cases where one of them is '\0' or '('. */
+ case '\0':
+ if (*string2 == '\0')
+ return 0;
+ else
+ return -1;
+ case '(':
+ if (*string2 == '\0')
+ return 1;
+ else
+ return -1;
+ default:
+ if (*string2 == '(')
+ return 1;
+ else
+ return *string1 - *string2;
+ }
+}
+
+/* A simple comparison function with opposite semantics to strcmp. */
+
+int
+streq (const char *lhs, const char *rhs)
+{
+ return !strcmp (lhs, rhs);
+}
+
+
+/*
+ ** subset_compare()
+ ** Answer whether string_to_compare is a full or partial match to
+ ** template_string. The partial match must be in sequence starting
+ ** at index 0.
+ */
+int
+subset_compare (char *string_to_compare, char *template_string)
+{
+ int match;
+ if (template_string != (char *) NULL && string_to_compare != (char *) NULL
+ && strlen (string_to_compare) <= strlen (template_string))
+ match =
+ (strncmp
+ (template_string, string_to_compare, strlen (string_to_compare)) == 0);
+ else
+ match = 0;
+ return match;
+}
+
+
+static void pagination_on_command (char *arg, int from_tty);
+static void
+pagination_on_command (char *arg, int from_tty)
+{
+ pagination_enabled = 1;
+}
+
+static void pagination_on_command (char *arg, int from_tty);
+static void
+pagination_off_command (char *arg, int from_tty)
+{
+ pagination_enabled = 0;
+}
+
+
+void
+initialize_utils (void)
+{
+ struct cmd_list_element *c;
+
+ c = add_set_cmd ("width", class_support, var_uinteger, &chars_per_line,
+ "Set number of characters gdb thinks are in a line.",
+ &setlist);
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_width_command);
+
+ c = add_set_cmd ("height", class_support, var_uinteger, &lines_per_page,
+ "Set number of lines gdb thinks are in a page.", &setlist);
+ add_show_from_set (c, &showlist);
+ set_cmd_sfunc (c, set_height_command);
+
+ init_page_info ();
+
+ add_show_from_set
+ (add_set_cmd ("demangle", class_support, var_boolean,
+ (char *) &demangle,
+ "Set demangling of encoded C++/ObjC names when displaying symbols.",
+ &setprintlist), &showprintlist);
+
+ add_show_from_set
+ (add_set_cmd ("pagination", class_support,
+ var_boolean, (char *) &pagination_enabled,
+ "Set state of pagination.", &setlist), &showlist);
+
+ if (xdb_commands)
+ {
+ add_com ("am", class_support, pagination_on_command,
+ "Enable pagination");
+ add_com ("sm", class_support, pagination_off_command,
+ "Disable pagination");
+ }
+
+ 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++/ObjC names in disassembly listings.",
+ &setprintlist), &showprintlist);
+}
+
+/* Machine specific function to handle SIGWINCH signal. */
+
+#ifdef SIGWINCH_HANDLER_BODY
+SIGWINCH_HANDLER_BODY
+#endif
+/* print routines to handle variable size regs, etc. */
+/* temporary storage using circular buffer */
+#define NUMCELLS 16
+#define CELLSIZE 32
+static char *
+get_cell (void)
+{
+ static char buf[NUMCELLS][CELLSIZE];
+ static int cell = 0;
+ if (++cell >= NUMCELLS)
+ cell = 0;
+ return buf[cell];
+}
+
+int
+strlen_paddr (void)
+{
+ return (TARGET_ADDR_BIT / 8 * 2);
+}
+
+char *
+paddr (CORE_ADDR addr)
+{
+ return phex (addr, TARGET_ADDR_BIT / 8);
+}
+
+char *
+paddr_nz (CORE_ADDR addr)
+{
+ return phex_nz (addr, TARGET_ADDR_BIT / 8);
+}
+
+static void
+decimal2str (char *paddr_str, char *sign, ULONGEST addr)
+{
+ /* steal code from valprint.c:print_decimal(). Should this worry
+ about the real size of addr as the above does? */
+ unsigned long temp[3];
+ int i = 0;
+ do
+ {
+ temp[i] = addr % (1000 * 1000 * 1000);
+ addr /= (1000 * 1000 * 1000);
+ i++;
+ }
+ while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0])));
+ switch (i)
+ {
+ case 1:
+ sprintf (paddr_str, "%s%lu", sign, temp[0]);
+ break;
+ case 2:
+ sprintf (paddr_str, "%s%lu%09lu", sign, temp[1], temp[0]);
+ break;
+ case 3:
+ sprintf (paddr_str, "%s%lu%09lu%09lu", sign, temp[2], temp[1], temp[0]);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "failed internal consistency check");
+ }
+}
+
+char *
+paddr_u (CORE_ADDR addr)
+{
+ char *paddr_str = get_cell ();
+ decimal2str (paddr_str, "", addr);
+ return paddr_str;
+}
+
+char *
+paddr_d (LONGEST addr)
+{
+ char *paddr_str = get_cell ();
+ if (addr < 0)
+ decimal2str (paddr_str, "-", -addr);
+ else
+ decimal2str (paddr_str, "", addr);
+ return paddr_str;
+}
+
+/* eliminate warning from compiler on 32-bit systems */
+static int thirty_two = 32;
+
+char *
+phex (ULONGEST l, int sizeof_l)
+{
+ char *str;
+ switch (sizeof_l)
+ {
+ case 8:
+ str = get_cell ();
+ sprintf (str, "%08lx%08lx",
+ (unsigned long) (l >> thirty_two),
+ (unsigned long) (l & 0xffffffff));
+ break;
+ case 4:
+ str = get_cell ();
+ sprintf (str, "%08lx", (unsigned long) l);
+ break;
+ case 2:
+ str = get_cell ();
+ sprintf (str, "%04x", (unsigned short) (l & 0xffff));
+ break;
+ default:
+ str = phex (l, sizeof (l));
+ break;
+ }
+ return str;
+}
+
+char *
+phex_nz (ULONGEST l, int sizeof_l)
+{
+ char *str;
+ switch (sizeof_l)
+ {
+ case 8:
+ {
+ unsigned long high = (unsigned long) (l >> thirty_two);
+ str = get_cell ();
+ if (high == 0)
+ sprintf (str, "%lx", (unsigned long) (l & 0xffffffff));
+ else
+ sprintf (str, "%lx%08lx", high, (unsigned long) (l & 0xffffffff));
+ break;
+ }
+ case 4:
+ str = get_cell ();
+ sprintf (str, "%lx", (unsigned long) l);
+ break;
+ case 2:
+ str = get_cell ();
+ sprintf (str, "%x", (unsigned short) (l & 0xffff));
+ break;
+ default:
+ str = phex_nz (l, sizeof (l));
+ break;
+ }
+ return str;
+}
+
+
+/* Convert a CORE_ADDR into a string. */
+const char *
+core_addr_to_string (const CORE_ADDR addr)
+{
+ char *str = get_cell ();
+ strcpy (str, "0x");
+ strcat (str, phex (addr, sizeof (addr)));
+ return str;
+}
+
+const char *
+core_addr_to_string_nz (const CORE_ADDR addr)
+{
+ char *str = get_cell ();
+ strcpy (str, "0x");
+ strcat (str, phex_nz (addr, sizeof (addr)));
+ return str;
+}
+
+/* Convert a string back into a CORE_ADDR. */
+CORE_ADDR
+string_to_core_addr (const char *my_string)
+{
+ CORE_ADDR addr = 0;
+ if (my_string[0] == '0' && tolower (my_string[1]) == 'x')
+ {
+ /* Assume that it is in decimal. */
+ int i;
+ for (i = 2; my_string[i] != '\0'; i++)
+ {
+ if (isdigit (my_string[i]))
+ addr = (my_string[i] - '0') + (addr * 16);
+ else if (isxdigit (my_string[i]))
+ addr = (tolower (my_string[i]) - 'a' + 0xa) + (addr * 16);
+ else
+ internal_error (__FILE__, __LINE__, "invalid hex");
+ }
+ }
+ else
+ {
+ /* Assume that it is in decimal. */
+ int i;
+ for (i = 0; my_string[i] != '\0'; i++)
+ {
+ if (isdigit (my_string[i]))
+ addr = (my_string[i] - '0') + (addr * 10);
+ else
+ internal_error (__FILE__, __LINE__, "invalid decimal");
+ }
+ }
+ return addr;
+}
+
+char *
+gdb_realpath (const char *filename)
+{
+ /* Method 1: The system has a compile time upper bound on a filename
+ path. Use that and realpath() to canonicalize the name. This is
+ the most common case. Note that, if there isn't a compile time
+ upper bound, you want to avoid realpath() at all costs. */
+#if defined(HAVE_REALPATH)
+ {
+# if defined (PATH_MAX)
+ char buf[PATH_MAX];
+# define USE_REALPATH
+# elif defined (MAXPATHLEN)
+ char buf[MAXPATHLEN];
+# define USE_REALPATH
+# endif
+# if defined (USE_REALPATH)
+ const char *rp = realpath (filename, buf);
+ if (rp == NULL)
+ rp = filename;
+ return xstrdup (rp);
+# endif
+ }
+#endif /* HAVE_REALPATH */
+
+ /* Method 2: The host system (i.e., GNU) has the function
+ canonicalize_file_name() which malloc's a chunk of memory and
+ returns that, use that. */
+#if defined(HAVE_CANONICALIZE_FILE_NAME)
+ {
+ char *rp = canonicalize_file_name (filename);
+ if (rp == NULL)
+ return xstrdup (filename);
+ else
+ return rp;
+ }
+#endif
+
+ /* FIXME: cagney/2002-11-13:
+
+ Method 2a: Use realpath() with a NULL buffer. Some systems, due
+ to the problems described in in method 3, have modified their
+ realpath() implementation so that it will allocate a buffer when
+ NULL is passed in. Before this can be used, though, some sort of
+ configure time test would need to be added. Otherwize the code
+ will likely core dump. */
+
+ /* Method 3: Now we're getting desperate! The system doesn't have a
+ compile time buffer size and no alternative function. Query the
+ OS, using pathconf(), for the buffer limit. Care is needed
+ though, some systems do not limit PATH_MAX (return -1 for
+ pathconf()) making it impossible to pass a correctly sized buffer
+ to realpath() (it could always overflow). On those systems, we
+ skip this. */
+#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) && defined(HAVE_ALLOCA)
+ {
+ /* Find out the max path size. */
+ long path_max = pathconf ("/", _PC_PATH_MAX);
+ if (path_max > 0)
+ {
+ /* PATH_MAX is bounded. */
+ char *buf = alloca (path_max);
+ char *rp = realpath (filename, buf);
+ return xstrdup (rp ? rp : filename);
+ }
+ }
+#endif
+
+ /* This system is a lost cause, just dup the buffer. */
+ return xstrdup (filename);
+}
+
+/* Return a copy of FILENAME, with its directory prefix canonicalized
+ by gdb_realpath. */
+
+char *
+xfullpath (const char *filename)
+{
+ const char *base_name = lbasename (filename);
+ char *dir_name;
+ char *real_path;
+ char *result;
+
+ /* Extract the basename of filename, and return immediately
+ a copy of filename if it does not contain any directory prefix. */
+ if (base_name == filename)
+ return xstrdup (filename);
+
+ dir_name = alloca ((size_t) (base_name - filename + 2));
+ /* Allocate enough space to store the dir_name + plus one extra
+ character sometimes needed under Windows (see below), and
+ then the closing \000 character */
+ strncpy (dir_name, filename, base_name - filename);
+ dir_name[base_name - filename] = '\000';
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ /* We need to be careful when filename is of the form 'd:foo', which
+ is equivalent of d:./foo, which is totally different from d:/foo. */
+ if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':')
+ {
+ dir_name[2] = '.';
+ dir_name[3] = '\000';
+ }
+#endif
+
+ /* Canonicalize the directory prefix, and build the resulting
+ filename. If the dirname realpath already contains an ending
+ directory separator, avoid doubling it. */
+ real_path = gdb_realpath (dir_name);
+ if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1]))
+ result = concat (real_path, base_name, NULL);
+ else
+ result = concat (real_path, SLASH_STRING, base_name, NULL);
+
+ xfree (real_path);
+ return result;
+}
+
+
+/* This is the 32-bit CRC function used by the GNU separate debug
+ facility. An executable may contain a section named
+ .gnu_debuglink, which holds the name of a separate executable file
+ containing its debug info, and a checksum of that file's contents,
+ computed using this function. */
+unsigned long
+gnu_debuglink_crc32 (unsigned long crc, unsigned char *buf, size_t len)
+{
+ static const unsigned long crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ };
+ unsigned char *end;
+
+ crc = ~crc & 0xffffffff;
+ for (end = buf + len; buf < end; ++buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc & 0xffffffff;;
+}
+
+ULONGEST
+align_up (ULONGEST v, int n)
+{
+ /* Check that N is really a power of two. */
+ gdb_assert (n && (n & (n-1)) == 0);
+ return (v + n - 1) & -n;
+}
+
+ULONGEST
+align_down (ULONGEST v, int n)
+{
+ /* Check that N is really a power of two. */
+ gdb_assert (n && (n & (n-1)) == 0);
+ return (v & -n);
+}
diff --git a/contrib/gdb/gdb/uw-thread.c b/contrib/gdb/gdb/uw-thread.c
new file mode 100755
index 0000000..cc6ed6d
--- /dev/null
+++ b/contrib/gdb/gdb/uw-thread.c
@@ -0,0 +1,1067 @@
+/* Low level interface for debugging UnixWare user-mode threads for
+ GDB, the GNU debugger.
+
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+ Written by Nick Duffek <nsd@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. */
+
+
+/* Like many systems, UnixWare implements two classes of threads:
+ kernel-mode threads, which are scheduled by the kernel; and
+ user-mode threads, which are scheduled by a library. UnixWare
+ calls these two classes lightweight processes (LWPs) and threads,
+ respectively.
+
+ This module deals with user-mode threads. It calls procfs_ops
+ functions to deal with LWPs and processes and core_ops functions to
+ deal with core files.
+
+ As of this writing, the user-mode thread debugging interface is not
+ documented beyond the comments in <thread.h>. The following
+ description has been gleaned from experience and from information
+ provided by SCO.
+
+ libthread.so, against which all UnixWare user-mode thread programs
+ link, provides a global thread_debug structure named _thr_debug.
+ It has three fields:
+
+ (1) thr_map is a pointer to a pointer to an element of a
+ thread_map ring. A thread_map contains a single thread's id
+ number, state, LWP pointer, recent register state, and other
+ useful information.
+
+ (2) thr_brk is a pointer to a stub function that libthread.so
+ calls when it changes a thread's state, e.g. by creating it,
+ switching it to an LWP, or causing it to exit.
+
+ (3) thr_debug_on controls whether libthread.so calls thr_brk().
+
+ Debuggers are able to track thread activity by setting a private
+ breakpoint on thr_brk() and setting thr_debug_on to 1.
+
+ thr_brk() receives two arguments:
+
+ (1) a pointer to a thread_map describing the thread being
+ changed; and
+
+ (2) an enum thread_change specifying one of the following
+ changes:
+
+ invalid unknown
+ thread_create thread has just been created
+ thread_exit thread has just exited
+ switch_begin thread will be switched to an LWP
+ switch_complete thread has been switched to an LWP
+ cancel_complete thread wasn't switched to an LWP
+ thread_suspend thread has been thr_suspend()ed
+ thread_suspend_pending thread will be thr_suspend()ed
+ thread_continue thread has been thr_continue()d
+
+ The thread_map argument to thr_brk() is NULL under the following
+ circumstances:
+
+ - The main thread is being acted upon. The main thread always
+ has id 1, so its thread_map is easy to find by scanning through
+ _thr_debug.thr_map.
+
+ - A "switch_complete" change is occurring, which means that the
+ thread specified in the most recent "switch_begin" change has
+ moved to an LWP.
+
+ - A "cancel_complete" change is occurring, which means that the
+ thread specified in the most recent "switch_begin" change has
+ not moved to an LWP after all.
+
+ - A spurious "switch_begin" change is occurring after a
+ "thread_exit" change.
+
+ Between switch_begin and switch_complete or cancel_complete, the
+ affected thread's LWP pointer is not reliable. It is possible that
+ other parts of the thread's thread_map are also unreliable during
+ that time. */
+
+
+#include "defs.h"
+#include "gdbthread.h"
+#include "target.h"
+#include "inferior.h"
+#include "regcache.h"
+#include <fcntl.h>
+
+/* <thread.h> includes <sys/priocntl.h>, which requires boolean_t from
+ <sys/types.h>, which doesn't typedef boolean_t with gcc. */
+
+#define boolean_t int
+#include <thread.h>
+#undef boolean_t
+
+#include <synch.h> /* for UnixWare 2.x */
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* Offset from SP to first arg on stack at first instruction of a
+ function. We provide a default here that's right for most, if not
+ all, targets that use this file. */
+
+#ifndef SP_ARG0
+#define SP_ARG0 (1 * 4)
+#endif
+
+/* Whether to emit debugging output. */
+
+#define DEBUG 0
+
+/* Default debugging output file, overridden by envvar UWTHR_DEBUG. */
+
+#define DEBUG_FILE "/dev/tty"
+
+/* #if DEBUG, write string S to the debugging output channel. */
+
+#if !DEBUG
+# define DBG(fmt_and_args)
+# define DBG2(fmt_and_args)
+#else
+# define DBG(fmt_and_args) dbg fmt_and_args
+# define DBG2(fmt_and_args)
+#endif
+
+/* Back end to CALL_BASE() and TRY_BASE(): evaluate CALL, then convert
+ inferior_ptid to a composite thread/process id. */
+
+#define CALL_BASE_1(call) \
+do { \
+ DBG2(("CALL_BASE(" #call ")")); \
+ call; \
+ do_cleanups (infpid_cleanup); \
+} while (0)
+
+/* If inferior_ptid can be converted to a composite lwp/process id, do so,
+ evaluate base_ops function CALL, and then convert inferior_ptid back to a
+ composite thread/process id.
+
+ Otherwise, issue an error message and return nonlocally. */
+
+#define CALL_BASE(call) \
+do { \
+ if (!lwp_infpid ()) \
+ error ("uw-thread: no lwp"); \
+ CALL_BASE_1 (call); \
+} while (0)
+
+/* Like CALL_BASE(), but instead of returning nonlocally on error, set
+ *CALLED to whether the inferior_ptid conversion was successful. */
+
+#define TRY_BASE(call, called) \
+do { \
+ if ((*(called) = lwp_infpid ())) \
+ CALL_BASE_1 (call); \
+} while (0)
+
+/* Information passed by thread_iter() to its callback parameter. */
+
+typedef struct {
+ struct thread_map map;
+ __lwp_desc_t lwp;
+ CORE_ADDR mapp;
+} iter_t;
+
+/* Private thread data for the thread_info struct. */
+
+struct private_thread_info {
+ int stable; /* 0 if libthread.so is modifying thread map */
+ int thrid; /* thread id assigned by libthread.so */
+ int lwpid; /* thread's lwp if .stable, 0 means no lwp */
+ CORE_ADDR mapp; /* address of thread's map structure */
+};
+
+
+/* procfs.c's target-specific operations. */
+extern struct target_ops procfs_ops;
+
+/* Flag to prevent procfs.c from starting inferior processes. */
+extern int procfs_suppress_run;
+
+/* This module's target-specific operations. */
+static struct target_ops uw_thread_ops;
+
+/* Copy of the target over which uw_thread_ops is pushed. This is
+ more convenient than a pointer to procfs_ops or core_ops, because
+ they lack current_target's default callbacks. */
+static struct target_ops base_ops;
+
+/* Saved pointer to previous owner of target_new_objfile_hook. */
+static void (*target_new_objfile_chain)(struct objfile *);
+
+/* Whether we are debugging a user-space thread program. This isn't
+ set until after libthread.so is loaded by the program being
+ debugged.
+
+ Except for module one-time intialization and where otherwise
+ documented, no functions in this module get called when
+ !uw_thread_active. */
+static int uw_thread_active;
+
+/* For efficiency, cache the addresses of libthread.so's _thr_debug
+ structure, its thr_brk stub function, and the main thread's map. */
+static CORE_ADDR thr_debug_addr;
+static CORE_ADDR thr_brk_addr;
+static CORE_ADDR thr_map_main;
+
+/* Remember the thread most recently marked as switching. Necessary because
+ libthread.so passes null map when calling stub with tc_*_complete. */
+static struct thread_info *switchto_thread;
+
+/* Cleanup chain for safely restoring inferior_ptid after CALL_BASE. */
+static struct cleanup *infpid_cleanup;
+
+
+#if DEBUG
+/* Helper function for DBG() macro: if printf-style FMT is non-null, format it
+ with args and display the result on the debugging output channel. */
+
+static void
+dbg (char *fmt, ...)
+{
+ static int fd = -1, len;
+ va_list args;
+ char buf[1024];
+ char *path;
+
+ if (!fmt)
+ return;
+
+ if (fd < 0)
+ {
+ path = getenv ("UWTHR_DEBUG");
+ if (!path)
+ path = DEBUG_FILE;
+ if ((fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, 0664)) < 0)
+ error ("can't open %s\n", path);
+ }
+
+ va_start (args, fmt);
+ vsprintf (buf, fmt, args);
+ va_end (args);
+
+ len = strlen (buf);
+ buf[len] = '\n';
+ (void)write (fd, buf, len + 1);
+}
+
+#if 0
+/* Return a string representing composite PID's components. */
+
+static char *
+dbgpid (ptid_t ptid)
+{
+ static char *buf, buf1[80], buf2[80];
+ if (!buf || buf == buf2)
+ buf = buf1;
+ else
+ buf = buf2;
+
+ if (PIDGET (ptid) <= 0)
+ sprintf (buf, "%d", PIDGET (ptid));
+ else
+ sprintf (buf, "%s %ld/%d", ISTID (pid) ? "thr" : "lwp",
+ TIDGET (pid), PIDGET (pid));
+
+ return buf;
+}
+
+/* Return a string representing thread state CHANGE. */
+
+static char *
+dbgchange (enum thread_change change)
+{
+ switch (change) {
+ case tc_invalid: return "invalid";
+ case tc_thread_create: return "thread_create";
+ case tc_thread_exit: return "thread_exit";
+ case tc_switch_begin: return "switch_begin";
+ case tc_switch_complete: return "switch_complete";
+ case tc_cancel_complete: return "cancel_complete";
+ case tc_thread_suspend: return "thread_suspend";
+ case tc_thread_suspend_pending: return "thread_suspend_pending";
+ case tc_thread_continue: return "thread_continue";
+ default: return "unknown";
+ }
+}
+
+/* Return a string representing thread STATE. */
+
+static char *
+dbgstate (int state)
+{
+ switch (state) {
+ case TS_ONPROC: return "running";
+ case TS_SLEEP: return "sleeping";
+ case TS_RUNNABLE: return "runnable";
+ case TS_ZOMBIE: return "zombie";
+ case TS_SUSPENDED: return "suspended";
+#ifdef TS_FORK
+ case TS_FORK: return "forking";
+#endif
+ default: return "confused";
+ }
+}
+#endif /* 0 */
+#endif /* DEBUG */
+
+
+/* Read the contents of _thr_debug into *DEBUGP. Return success. */
+
+static int
+read_thr_debug (struct thread_debug *debugp)
+{
+ return base_ops.to_xfer_memory (thr_debug_addr, (char *)debugp,
+ sizeof (*debugp), 0, NULL, &base_ops);
+}
+
+/* Read into MAP the contents of the thread map at inferior process address
+ MAPP. Return success. */
+
+static int
+read_map (CORE_ADDR mapp, struct thread_map *map)
+{
+ return base_ops.to_xfer_memory ((CORE_ADDR)THR_MAP (mapp), (char *)map,
+ sizeof (*map), 0, NULL, &base_ops);
+}
+
+/* Read into LWP the contents of the lwp decriptor at inferior process address
+ LWPP. Return success. */
+
+static int
+read_lwp (CORE_ADDR lwpp, __lwp_desc_t *lwp)
+{
+ return base_ops.to_xfer_memory (lwpp, (char *)lwp,
+ sizeof (*lwp), 0, NULL, &base_ops);
+}
+
+/* Iterate through all user threads, applying FUNC(<map>, <lwp>, DATA) until
+ (a) FUNC returns nonzero,
+ (b) FUNC has been applied to all threads, or
+ (c) an error occurs,
+ where <map> is the thread's struct thread_map and <lwp> if non-null is the
+ thread's current __lwp_desc_t.
+
+ If a call to FUNC returns nonzero, return that value; otherwise, return 0. */
+
+static int
+thread_iter (int (*func)(iter_t *, void *), void *data)
+{
+ struct thread_debug debug;
+ CORE_ADDR first, mapp;
+ iter_t iter;
+ int ret;
+
+ if (!read_thr_debug (&debug))
+ return 0;
+ if (!base_ops.to_xfer_memory ((CORE_ADDR)debug.thr_map, (char *)&mapp,
+ sizeof (mapp), 0, NULL, &base_ops))
+ return 0;
+ if (!mapp)
+ return 0;
+
+ for (first = mapp;;)
+ {
+ if (!read_map (mapp, &iter.map))
+ return 0;
+
+ if (iter.map.thr_lwpp)
+ if (!read_lwp ((CORE_ADDR)iter.map.thr_lwpp, &iter.lwp))
+ return 0;
+
+ iter.mapp = mapp;
+ if ((ret = func (&iter, data)))
+ return ret;
+
+ mapp = (CORE_ADDR)iter.map.thr_next;
+ if (mapp == first)
+ return 0;
+ }
+}
+
+/* Deactivate user-mode thread support. */
+
+static void
+deactivate_uw_thread (void)
+{
+ remove_thread_event_breakpoints ();
+ uw_thread_active = 0;
+ unpush_target (&uw_thread_ops);
+}
+
+/* Return the composite lwp/process id corresponding to composite
+ id PID. If PID is a thread with no lwp, return 0. */
+
+static ptid_t
+thr_to_lwp (ptid_t ptid)
+{
+ struct thread_info *info;
+ ptid_t lid;
+
+ if (!ISTID (ptid))
+ lid = ptid;
+ else if (!(info = find_thread_pid (ptid)))
+ lid = null_ptid;
+ else if (!info->private->lwpid)
+ lid = null_ptid;
+ else
+ lid = MKLID (PIDGET (ptid), info->private->lwpid);
+
+ DBG2((" thr_to_lwp(%s) = %s", dbgpid (pid), dbgpid (lid)));
+ return lid;
+}
+
+/* find_thread_lwp() callback: return whether TP describes a thread
+ associated with lwp id DATA. */
+
+static int
+find_thread_lwp_callback (struct thread_info *tp, void *data)
+{
+ int lwpid = (int)data;
+
+ if (!ISTID (tp->ptid))
+ return 0;
+ if (!tp->private->stable)
+ return 0;
+ if (lwpid != tp->private->lwpid)
+ return 0;
+
+ /* match */
+ return 1;
+}
+
+/* If a thread is associated with lwp id LWPID, return the corresponding
+ member of the global thread list; otherwise, return null. */
+
+static struct thread_info *
+find_thread_lwp (int lwpid)
+{
+ return iterate_over_threads (find_thread_lwp_callback, (void *)lwpid);
+}
+
+/* Return the composite thread/process id corresponding to composite
+ id PID. If PID is an lwp with no thread, return PID. */
+
+static ptid_t
+lwp_to_thr (ptid_t ptid)
+{
+ struct thread_info *info;
+ int lwpid;
+ ptid_t tid = ptid;
+
+ if (ISTID (ptid))
+ goto done;
+ if (!(lwpid = LIDGET (ptid)))
+ goto done;
+ if (!(info = find_thread_lwp (lwpid)))
+ goto done;
+ tid = MKTID (PIDGET (ptid), info->private->thrid);
+
+ done:
+ DBG2((ISTID (tid) ? NULL : "lwp_to_thr: no thr for %s", dbgpid (ptid)));
+ return tid;
+}
+
+/* do_cleanups() callback: convert inferior_ptid to a composite
+ thread/process id after having made a procfs call. */
+
+static void
+thr_infpid (void *unused)
+{
+ ptid_t ptid = lwp_to_thr (inferior_ptid);
+ DBG2((" inferior_ptid from procfs: %s => %s",
+ dbgpid (inferior_ptid), dbgpid (ptid)));
+ inferior_ptid = ptid;
+}
+
+/* If possible, convert inferior_ptid to a composite lwp/process id in
+ preparation for making a procfs call. Return success. */
+
+static int
+lwp_infpid (void)
+{
+ ptid_t ptid = thr_to_lwp (inferior_ptid);
+ DBG2((" inferior_ptid to procfs: %s => %s",
+ dbgpid (inferior_ptid), dbgpid (ptid)));
+
+ if (ptid_equal (ptid, null_ptid))
+ return 0;
+
+ inferior_ptid = ptid;
+ infpid_cleanup = make_cleanup (thr_infpid, NULL);
+ return 1;
+}
+
+/* Add to the global thread list a new user-mode thread with system id THRID,
+ lwp id LWPID, map address MAPP, and composite thread/process PID. */
+
+static void
+add_thread_uw (int thrid, int lwpid, CORE_ADDR mapp, ptid_t ptid)
+{
+ struct thread_info *newthread;
+
+ if ((newthread = add_thread (ptid)) == NULL)
+ error ("failed to create new thread structure");
+
+ newthread->private = xmalloc (sizeof (struct private_thread_info));
+ newthread->private->stable = 1;
+ newthread->private->thrid = thrid;
+ newthread->private->lwpid = lwpid;
+ newthread->private->mapp = mapp;
+
+ if (target_has_execution)
+ printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid));
+}
+
+/* notice_threads() and find_main() callback: if the thread list doesn't
+ already contain the thread described by ITER, add it if it's the main
+ thread or if !DATA. */
+
+static int
+notice_thread (iter_t *iter, void *data)
+{
+ int thrid = iter->map.thr_tid;
+ int lwpid = !iter->map.thr_lwpp ? 0 : iter->lwp.lwp_id;
+ ptid_t ptid = MKTID (PIDGET (inferior_ptid), thrid);
+
+ if (!find_thread_pid (ptid) && (!data || thrid == 1))
+ add_thread_uw (thrid, lwpid, iter->mapp, ptid);
+
+ return 0;
+}
+
+/* Add to the thread list any threads it doesn't already contain. */
+
+static void
+notice_threads (void)
+{
+ thread_iter (notice_thread, NULL);
+}
+
+/* Return the address of the main thread's map. On error, return 0. */
+
+static CORE_ADDR
+find_main (void)
+{
+ if (!thr_map_main)
+ {
+ struct thread_info *info;
+ thread_iter (notice_thread, (void *)1);
+ if ((info = find_thread_pid (MKTID (PIDGET (inferior_ptid), 1))))
+ thr_map_main = info->private->mapp;
+ }
+ return thr_map_main;
+}
+
+/* Attach to process specified by ARGS, then initialize for debugging it
+ and wait for the trace-trap that results from attaching.
+
+ This function only gets called with uw_thread_active == 0. */
+
+static void
+uw_thread_attach (char *args, int from_tty)
+{
+ procfs_ops.to_attach (args, from_tty);
+ if (uw_thread_active)
+ thr_infpid (NULL);
+}
+
+/* Detach from the process attached to by uw_thread_attach(). */
+
+static void
+uw_thread_detach (char *args, int from_tty)
+{
+ deactivate_uw_thread ();
+ base_ops.to_detach (args, from_tty);
+}
+
+/* Tell the inferior process to continue running thread PID if >= 0
+ and all threads otherwise. */
+
+static void
+uw_thread_resume (ptid_t ptid, int step, enum target_signal signo)
+{
+ if (PIDGET (ptid) > 0)
+ {
+ ptid = thr_to_lwp (ptid);
+ if (ptid_equal (ptid, null_ptid))
+ ptid = pid_to_ptid (-1);
+ }
+
+ CALL_BASE (base_ops.to_resume (ptid, step, signo));
+}
+
+/* If the trap we just received from lwp PID was due to a breakpoint
+ on the libthread.so debugging stub, update this module's state
+ accordingly. */
+
+static void
+libthread_stub (ptid_t ptid)
+{
+ CORE_ADDR sp, mapp, mapp_main;
+ enum thread_change change;
+ struct thread_map map;
+ __lwp_desc_t lwp;
+ int lwpid;
+ ptid_t tid = null_ptid;
+ struct thread_info *info;
+
+ /* Check for stub breakpoint. */
+ if (read_pc_pid (ptid) - DECR_PC_AFTER_BREAK != thr_brk_addr)
+ return;
+
+ /* Retrieve stub args. */
+ sp = read_register_pid (SP_REGNUM, ptid);
+ if (!base_ops.to_xfer_memory (sp + SP_ARG0, (char *)&mapp,
+ sizeof (mapp), 0, NULL, &base_ops))
+ goto err;
+ if (!base_ops.to_xfer_memory (sp + SP_ARG0 + sizeof (mapp), (char *)&change,
+ sizeof (change), 0, NULL, &base_ops))
+ goto err;
+
+ /* create_inferior() may not have finished yet, so notice the main
+ thread to ensure that it's displayed first by add_thread(). */
+ mapp_main = find_main ();
+
+ /* Notice thread creation, deletion, or stability change. */
+ switch (change) {
+ case tc_switch_begin:
+ if (!mapp) /* usually means main thread */
+ mapp = mapp_main;
+ /* fall through */
+
+ case tc_thread_create:
+ case tc_thread_exit:
+ if (!mapp)
+ break;
+ if (!read_map (mapp, &map))
+ goto err;
+ tid = MKTID (PIDGET (ptid), map.thr_tid);
+
+ switch (change) {
+ case tc_thread_create: /* new thread */
+ if (!map.thr_lwpp)
+ lwpid = 0;
+ else if (!read_lwp ((CORE_ADDR)map.thr_lwpp, &lwp))
+ goto err;
+ else
+ lwpid = lwp.lwp_id;
+ add_thread_uw (map.thr_tid, lwpid, mapp, tid);
+ break;
+
+ case tc_thread_exit: /* thread has exited */
+ printf_unfiltered ("[Exited %s]\n", target_pid_to_str (tid));
+ delete_thread (tid);
+ if (ptid_equal (tid, inferior_ptid))
+ inferior_ptid = ptid;
+ break;
+
+ case tc_switch_begin: /* lwp is switching threads */
+ if (switchto_thread)
+ goto err;
+ if (!(switchto_thread = find_thread_pid (tid)))
+ goto err;
+ switchto_thread->private->stable = 0;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case tc_switch_complete: /* lwp has switched threads */
+ case tc_cancel_complete: /* lwp didn't switch threads */
+ if (!switchto_thread)
+ goto err;
+
+ if (change == tc_switch_complete)
+ {
+ /* If switchto_thread is the main thread, then (a) the corresponding
+ tc_switch_begin probably received a null map argument and therefore
+ (b) it may have been a spurious switch following a tc_thread_exit.
+
+ Therefore, explicitly query the thread's lwp before caching it in
+ its thread list entry. */
+
+ if (!read_map (switchto_thread->private->mapp, &map))
+ goto err;
+ if (map.thr_lwpp)
+ {
+ if (!read_lwp ((CORE_ADDR)map.thr_lwpp, &lwp))
+ goto err;
+ if ((info = find_thread_lwp (lwp.lwp_id)))
+ info->private->lwpid = 0;
+ switchto_thread->private->lwpid = lwp.lwp_id;
+ }
+ }
+
+ switchto_thread->private->stable = 1;
+ switchto_thread = NULL;
+ break;
+
+ case tc_invalid:
+ case tc_thread_suspend:
+ case tc_thread_suspend_pending:
+ case tc_thread_continue:
+ err:
+ DBG(("unexpected condition in libthread_stub()"));
+ break;
+ }
+
+ DBG2(("libthread_stub(%s): %s %s %s", dbgpid (pid), dbgpid (tid),
+ dbgchange (change), tid ? dbgstate (map.thr_state) : ""));
+}
+
+/* Wait for thread/lwp/process ID if >= 0 or for any thread otherwise. */
+
+static ptid_t
+uw_thread_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ if (PIDGET (ptid) > 0)
+ ptid = thr_to_lwp (ptid);
+ if (PIDGET (ptid) <= 0)
+ ptid = pid_to_ptid (-1);
+
+ CALL_BASE (ptid = base_ops.to_wait (ptid, status));
+
+ if (status->kind == TARGET_WAITKIND_STOPPED &&
+ status->value.sig == TARGET_SIGNAL_TRAP)
+ libthread_stub (ptid);
+
+ return lwp_to_thr (ptid);
+}
+
+/* Tell gdb about the registers in the thread/lwp/process specified by
+ inferior_ptid. */
+
+static void
+uw_thread_fetch_registers (int regno)
+{
+ int called;
+ struct thread_info *info;
+ struct thread_map map;
+
+ TRY_BASE (base_ops.to_fetch_registers (regno), &called);
+ if (called)
+ return;
+
+ if (!(info = find_thread_pid (inferior_ptid)))
+ return;
+ if (!read_map (info->private->mapp, &map))
+ return;
+
+ supply_gregset (&map.thr_ucontext.uc_mcontext.gregs);
+ supply_fpregset (&map.thr_ucontext.uc_mcontext.fpregs);
+}
+
+/* Store gdb's current view of the register set into the thread/lwp/process
+ specified by inferior_ptid. */
+
+static void
+uw_thread_store_registers (int regno)
+{
+ CALL_BASE (base_ops.to_store_registers (regno));
+}
+
+/* Prepare to modify the registers array. */
+
+static void
+uw_thread_prepare_to_store (void)
+{
+ CALL_BASE (base_ops.to_prepare_to_store ());
+}
+
+/* Fork an inferior process and start debugging it.
+
+ This function only gets called with uw_thread_active == 0. */
+
+static void
+uw_thread_create_inferior (char *exec_file, char *allargs, char **env)
+{
+ if (uw_thread_active)
+ deactivate_uw_thread ();
+
+ procfs_ops.to_create_inferior (exec_file, allargs, env);
+ if (uw_thread_active)
+ {
+ find_main ();
+ thr_infpid (NULL);
+ }
+}
+
+/* Kill and forget about the inferior process. */
+
+static void
+uw_thread_kill (void)
+{
+ base_ops.to_kill ();
+}
+
+/* Clean up after the inferior exits. */
+
+static void
+uw_thread_mourn_inferior (void)
+{
+ deactivate_uw_thread ();
+ base_ops.to_mourn_inferior ();
+}
+
+/* Return whether this module can attach to and run processes.
+
+ This function only gets called with uw_thread_active == 0. */
+
+static int
+uw_thread_can_run (void)
+{
+ return procfs_suppress_run;
+}
+
+/* Return whether thread PID is still valid. */
+
+static int
+uw_thread_alive (ptid_t ptid)
+{
+ if (!ISTID (ptid))
+ return base_ops.to_thread_alive (ptid);
+
+ /* If it's in the thread list, it's valid, because otherwise
+ libthread_stub() would have deleted it. */
+ return in_thread_list (ptid);
+}
+
+/* Add to the thread list any threads and lwps it doesn't already contain. */
+
+static void
+uw_thread_find_new_threads (void)
+{
+ CALL_BASE (if (base_ops.to_find_new_threads)
+ base_ops.to_find_new_threads ());
+ notice_threads ();
+}
+
+/* Return a string for pretty-printing PID in "info threads" output.
+ This may be called by either procfs.c or by generic gdb. */
+
+static char *
+uw_thread_pid_to_str (ptid_t ptid)
+{
+#define FMT "Thread %ld"
+ static char buf[sizeof (FMT) + 3 * sizeof (long)];
+
+ if (!ISTID (ptid))
+ /* core_ops says "process foo", so call procfs_ops explicitly. */
+ return procfs_ops.to_pid_to_str (ptid);
+
+ sprintf (buf, FMT, TIDGET (ptid));
+#undef FMT
+ return buf;
+}
+
+/* Return a string displaying INFO state information in "info threads"
+ output. */
+
+static char *
+uw_extra_thread_info (struct thread_info *info)
+{
+ static char buf[80];
+ struct thread_map map;
+ __lwp_desc_t lwp;
+ int lwpid;
+ char *name;
+
+ if (!ISTID (info->ptid))
+ return NULL;
+
+ if (!info->private->stable)
+ return "switching";
+
+ if (!read_map (info->private->mapp, &map))
+ return NULL;
+
+ if (!map.thr_lwpp || !read_lwp ((CORE_ADDR)map.thr_lwpp, &lwp))
+ lwpid = 0;
+ else
+ lwpid = lwp.lwp_id;
+
+ switch (map.thr_state) {
+ case TS_ONPROC: name = "running"; break;
+ case TS_SLEEP: name = "sleeping"; break;
+ case TS_RUNNABLE: name = "runnable"; break;
+ case TS_ZOMBIE: name = "zombie"; break;
+ case TS_SUSPENDED: name = "suspended"; break;
+#ifdef TS_FORK
+ case TS_FORK: name = "forking"; break;
+#endif
+ default: name = "confused"; break;
+ }
+
+ if (!lwpid)
+ return name;
+
+ sprintf (buf, "%s, LWP %d", name, lwpid);
+ return buf;
+}
+
+/* Check whether libthread.so has just been loaded, and if so, try to
+ initialize user-space thread debugging support.
+
+ libthread.so loading happens while (a) an inferior process is being
+ started by procfs and (b) a core image is being loaded.
+
+ This function often gets called with uw_thread_active == 0. */
+
+static void
+libthread_init (void)
+{
+ struct minimal_symbol *ms;
+ struct thread_debug debug;
+ CORE_ADDR onp;
+ struct breakpoint *b;
+ int one = 1;
+
+ /* Don't initialize twice. */
+ if (uw_thread_active)
+ return;
+
+ /* Check whether libthread.so has been loaded. */
+ if (!(ms = lookup_minimal_symbol ("_thr_debug", NULL, NULL)))
+ return;
+
+ /* Cache _thr_debug's address. */
+ if (!(thr_debug_addr = SYMBOL_VALUE_ADDRESS (ms)))
+ return;
+
+ /* Initialize base_ops.to_xfer_memory(). */
+ base_ops = current_target;
+
+ /* Load _thr_debug's current contents. */
+ if (!read_thr_debug (&debug))
+ return;
+
+ /* User code (e.g. my test programs) may dereference _thr_debug,
+ making it availble to GDB before shared libs are loaded. */
+ if (!debug.thr_map)
+ return;
+
+ /* libthread.so has been loaded, and the current_target should now
+ reflect core_ops or procfs_ops. */
+ push_target (&uw_thread_ops); /* must precede notice_threads() */
+ uw_thread_active = 1;
+
+ if (!target_has_execution)
+
+ /* Locate threads in core file. */
+ notice_threads ();
+
+ else
+ {
+ /* Set a breakpoint on the stub function provided by libthread.so. */
+ thr_brk_addr = (CORE_ADDR)debug.thr_brk;
+ if (!(b = create_thread_event_breakpoint (thr_brk_addr)))
+ goto err;
+
+ /* Activate the stub function. */
+ onp = (CORE_ADDR)&((struct thread_debug *)thr_debug_addr)->thr_debug_on;
+ if (!base_ops.to_xfer_memory ((CORE_ADDR)onp, (char *)&one,
+ sizeof (one), 1, NULL, &base_ops))
+ {
+ delete_breakpoint (b);
+ goto err;
+ }
+
+ /* Prepare for finding the main thread, which doesn't yet exist. */
+ thr_map_main = 0;
+ }
+
+ return;
+
+ err:
+ warning ("uw-thread: unable to initialize user-mode thread debugging\n");
+ deactivate_uw_thread ();
+}
+
+/* target_new_objfile_hook callback.
+
+ If OBJFILE is non-null, check whether libthread.so was just loaded,
+ and if so, prepare for user-mode thread debugging.
+
+ If OBJFILE is null, libthread.so has gone away, so stop debugging
+ user-mode threads.
+
+ This function often gets called with uw_thread_active == 0. */
+
+static void
+uw_thread_new_objfile (struct objfile *objfile)
+{
+ if (objfile)
+ libthread_init ();
+
+ else if (uw_thread_active)
+ deactivate_uw_thread ();
+
+ if (target_new_objfile_chain)
+ target_new_objfile_chain (objfile);
+}
+
+/* Initialize uw_thread_ops. */
+
+static void
+init_uw_thread_ops (void)
+{
+ uw_thread_ops.to_shortname = "unixware-threads";
+ uw_thread_ops.to_longname = "UnixWare threads and pthread.";
+ uw_thread_ops.to_doc = "UnixWare threads and pthread support.";
+ uw_thread_ops.to_attach = uw_thread_attach;
+ uw_thread_ops.to_detach = uw_thread_detach;
+ uw_thread_ops.to_resume = uw_thread_resume;
+ uw_thread_ops.to_wait = uw_thread_wait;
+ uw_thread_ops.to_fetch_registers = uw_thread_fetch_registers;
+ uw_thread_ops.to_store_registers = uw_thread_store_registers;
+ uw_thread_ops.to_prepare_to_store = uw_thread_prepare_to_store;
+ uw_thread_ops.to_create_inferior = uw_thread_create_inferior;
+ uw_thread_ops.to_kill = uw_thread_kill;
+ uw_thread_ops.to_mourn_inferior = uw_thread_mourn_inferior;
+ uw_thread_ops.to_can_run = uw_thread_can_run;
+ uw_thread_ops.to_thread_alive = uw_thread_alive;
+ uw_thread_ops.to_find_new_threads = uw_thread_find_new_threads;
+ uw_thread_ops.to_pid_to_str = uw_thread_pid_to_str;
+ uw_thread_ops.to_extra_thread_info = uw_extra_thread_info;
+ uw_thread_ops.to_stratum = thread_stratum;
+ uw_thread_ops.to_magic = OPS_MAGIC;
+}
+
+/* Module startup initialization function, automagically called by
+ init.c. */
+
+void
+_initialize_uw_thread (void)
+{
+ init_uw_thread_ops ();
+ add_target (&uw_thread_ops);
+
+ procfs_suppress_run = 1;
+
+ /* Notice when libthread.so gets loaded. */
+ target_new_objfile_chain = target_new_objfile_hook;
+ target_new_objfile_hook = uw_thread_new_objfile;
+}
diff --git a/contrib/gdb/gdb/valarith.c b/contrib/gdb/gdb/valarith.c
new file mode 100644
index 0000000..03282ea
--- /dev/null
+++ b/contrib/gdb/gdb/valarith.c
@@ -0,0 +1,1419 @@
+/* Perform arithmetic and other operations on values, for GDB.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdb_string.h"
+#include "doublest.h"
+#include <math.h>
+#include "infcall.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 struct value *value_subscripted_rvalue (struct value *, struct value *, int);
+
+void _initialize_valarith (void);
+
+
+/* Given a pointer, return the size of its target.
+ If the pointer type is void *, then return 1.
+ If the target type is incomplete, then error out.
+ This isn't a general purpose function, but just a
+ helper for value_sub & value_add.
+*/
+
+static LONGEST
+find_size_for_pointer_math (struct type *ptr_type)
+{
+ LONGEST sz = -1;
+ struct type *ptr_target;
+
+ ptr_target = check_typedef (TYPE_TARGET_TYPE (ptr_type));
+
+ sz = TYPE_LENGTH (ptr_target);
+ if (sz == 0)
+ {
+ if (TYPE_CODE (ptr_type) == TYPE_CODE_VOID)
+ sz = 1;
+ else
+ {
+ char *name;
+
+ name = TYPE_NAME (ptr_target);
+ if (name == NULL)
+ name = TYPE_TAG_NAME (ptr_target);
+ if (name == NULL)
+ error ("Cannot perform pointer math on incomplete types, "
+ "try casting to a known type, or void *.");
+ else
+ error ("Cannot perform pointer math on incomplete type \"%s\", "
+ "try casting to a known type, or void *.", name);
+ }
+ }
+ return sz;
+}
+
+struct value *
+value_add (struct value *arg1, struct value *arg2)
+{
+ struct value *valint;
+ struct value *valptr;
+ LONGEST sz;
+ 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. */
+ {
+ struct value *retval;
+
+ if (TYPE_CODE (type1) == TYPE_CODE_PTR)
+ {
+ valptr = arg1;
+ valint = arg2;
+ valptrtype = type1;
+ }
+ else
+ {
+ valptr = arg2;
+ valint = arg1;
+ valptrtype = type2;
+ }
+
+ sz = find_size_for_pointer_math (valptrtype);
+
+ retval = value_from_pointer (valptrtype,
+ value_as_address (valptr)
+ + (sz * value_as_long (valint)));
+ VALUE_BFD_SECTION (retval) = VALUE_BFD_SECTION (valptr);
+ return retval;
+ }
+
+ return value_binop (arg1, arg2, BINOP_ADD);
+}
+
+struct value *
+value_sub (struct value *arg1, struct value *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 = find_size_for_pointer_math (type1);
+
+ return value_from_pointer (type1,
+ (value_as_address (arg1)
+ - (sz * value_as_long (arg2))));
+ }
+ else if (TYPE_CODE (type2) == TYPE_CODE_PTR
+ && TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type1)))
+ == TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type2))))
+ {
+ /* pointer to <type x> - pointer to <type x>. */
+ 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). */
+
+struct value *
+value_subscript (struct value *array, struct value *idx)
+{
+ struct value *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);
+ struct value *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 struct value *
+value_subscripted_rvalue (struct value *array, struct value *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);
+ struct value *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_REGNO (v) = VALUE_REGNO (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 (enum exp_opcode op, struct value *arg1, struct value *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 (enum exp_opcode op, struct value *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. */
+
+struct value *
+value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
+ enum exp_opcode otherop, enum noside noside)
+{
+ struct value **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 = (struct value **) alloca (sizeof (struct value *) * 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_MAX:
+ 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++;
+ }
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct type *return_type;
+ return_type
+ = TYPE_TARGET_TYPE (check_typedef (VALUE_TYPE (argvec[0])));
+ return value_zero (return_type, VALUE_LVAL (arg1));
+ }
+ 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++). */
+
+struct value *
+value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
+{
+ struct value **argvec;
+ char *ptr, *mangle_ptr;
+ char tstr[13], mangle_tstr[13];
+ int static_memfuncp, nargs;
+
+ 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 = (struct value **) alloca (sizeof (struct value *) * 4);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = 0;
+
+ nargs = 1;
+
+ /* 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, "++");
+ argvec[2] = value_from_longest (builtin_type_int, 0);
+ argvec[3] = 0;
+ nargs ++;
+ break;
+ case UNOP_POSTDECREMENT:
+ strcpy (ptr, "--");
+ argvec[2] = value_from_longest (builtin_type_int, 0);
+ argvec[3] = 0;
+ nargs ++;
+ break;
+ case UNOP_LOGICAL_NOT:
+ strcpy (ptr, "!");
+ break;
+ case UNOP_COMPLEMENT:
+ strcpy (ptr, "~");
+ break;
+ case UNOP_NEG:
+ strcpy (ptr, "-");
+ break;
+ case UNOP_IND:
+ strcpy (ptr, "*");
+ break;
+ default:
+ error ("Invalid unary operation specified.");
+ }
+
+ argvec[0] = value_struct_elt (&arg1, argvec + 1, tstr, &static_memfuncp, "structure");
+
+ if (argvec[0])
+ {
+ if (static_memfuncp)
+ {
+ argvec[1] = argvec[0];
+ nargs --;
+ argvec++;
+ }
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct type *return_type;
+ return_type
+ = TYPE_TARGET_TYPE (check_typedef (VALUE_TYPE (argvec[0])));
+ return value_zero (return_type, VALUE_LVAL (arg1));
+ }
+ return call_function_by_hand (argvec[0], nargs, 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.
+ */
+
+struct value *
+value_concat (struct value *arg1, struct value *arg2)
+{
+ struct value *inval1;
+ struct value *inval2;
+ struct value *outval = NULL;
+ 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. */
+
+struct value *
+value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
+{
+ struct value *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 = 0;
+ 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;
+
+ case BINOP_EXP:
+ v = pow (v1, v2);
+ if (errno)
+ error ("Cannot perform exponentiation: %s", safe_strerror (errno));
+ 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_typed_floating (VALUE_CONTENTS_RAW (val), VALUE_TYPE (val), v);
+ }
+ else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
+ &&
+ TYPE_CODE (type2) == TYPE_CODE_BOOL)
+ {
+ LONGEST v1, v2, v = 0;
+ 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;
+
+ case BINOP_EQUAL:
+ v = v1 == v2;
+ break;
+
+ case BINOP_NOTEQUAL:
+ 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 (the deleted) 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)
+ {
+ ULONGEST v1, v2, v = 0;
+ v1 = (ULONGEST) value_as_long (arg1);
+ v2 = (ULONGEST) value_as_long (arg2);
+
+ /* Truncate values to the type length of the result. */
+ if (result_len < sizeof (ULONGEST))
+ {
+ 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_EXP:
+ v = pow (v1, v2);
+ if (errno)
+ error ("Cannot perform exponentiation: %s", safe_strerror (errno));
+ 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. */
+ 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_NOTEQUAL:
+ 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 = 0;
+ 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_EXP:
+ v = pow (v1, v2);
+ if (errno)
+ error ("Cannot perform exponentiation: %s", safe_strerror (errno));
+ 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. */
+ 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 (struct value *arg1)
+{
+ int len;
+ 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;
+}
+
+/* Perform a comparison on two string values (whose content are not
+ necessarily null terminated) based on their length */
+
+static int
+value_strcmp (struct value *arg1, struct value *arg2)
+{
+ int len1 = TYPE_LENGTH (VALUE_TYPE (arg1));
+ int len2 = TYPE_LENGTH (VALUE_TYPE (arg2));
+ char *s1 = VALUE_CONTENTS (arg1);
+ char *s2 = VALUE_CONTENTS (arg2);
+ int i, len = len1 < len2 ? len1 : len2;
+
+ for (i = 0; i < len; i++)
+ {
+ if (s1[i] < s2[i])
+ return -1;
+ else if (s1[i] > s2[i])
+ return 1;
+ else
+ continue;
+ }
+
+ if (len1 < len2)
+ return -1;
+ else if (len1 > len2)
+ return 1;
+ else
+ return 0;
+}
+
+/* Simulate the C operator == by returning a 1
+ iff ARG1 and ARG2 have equal contents. */
+
+int
+value_equal (struct value *arg1, struct value *arg2)
+{
+ int len;
+ 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 || code1 == TYPE_CODE_BOOL) &&
+ (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_BOOL))
+ return longest_to_int (value_as_long (value_binop (arg1, arg2,
+ BINOP_EQUAL)));
+ else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT || code1 == TYPE_CODE_BOOL)
+ && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT || code2 == TYPE_CODE_BOOL))
+ 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 || code2 == TYPE_CODE_BOOL))
+ return value_as_address (arg1) == (CORE_ADDR) value_as_long (arg2);
+ else if (code2 == TYPE_CODE_PTR && (code1 == TYPE_CODE_INT || code1 == TYPE_CODE_BOOL))
+ return (CORE_ADDR) value_as_long (arg1) == value_as_address (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 if (code1 == TYPE_CODE_STRING && code2 == TYPE_CODE_STRING)
+ {
+ return value_strcmp (arg1, arg2) == 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 (struct value *arg1, struct value *arg2)
+{
+ enum type_code code1;
+ 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 || code1 == TYPE_CODE_BOOL) &&
+ (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_BOOL))
+ return longest_to_int (value_as_long (value_binop (arg1, arg2,
+ BINOP_LESS)));
+ else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT || code1 == TYPE_CODE_BOOL)
+ && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT || code2 == TYPE_CODE_BOOL))
+ return value_as_double (arg1) < value_as_double (arg2);
+ else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+ return value_as_address (arg1) < value_as_address (arg2);
+
+ /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever
+ is bigger. */
+ else if (code1 == TYPE_CODE_PTR && (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_BOOL))
+ return value_as_address (arg1) < (CORE_ADDR) value_as_long (arg2);
+ else if (code2 == TYPE_CODE_PTR && (code1 == TYPE_CODE_INT || code1 == TYPE_CODE_BOOL))
+ return (CORE_ADDR) value_as_long (arg1) < value_as_address (arg2);
+ else if (code1 == TYPE_CODE_STRING && code2 == TYPE_CODE_STRING)
+ return value_strcmp (arg1, arg2) < 0;
+ else
+ {
+ error ("Invalid type combination in ordering comparison.");
+ return 0;
+ }
+}
+
+/* The unary operators - and ~. Both free the argument ARG1. */
+
+struct value *
+value_neg (struct value *arg1)
+{
+ struct type *type;
+ struct type *result_type = VALUE_TYPE (arg1);
+
+ COERCE_REF (arg1);
+ COERCE_ENUM (arg1);
+
+ type = check_typedef (VALUE_TYPE (arg1));
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ return value_from_double (result_type, -value_as_double (arg1));
+ else if (TYPE_CODE (type) == TYPE_CODE_INT || TYPE_CODE (type) == TYPE_CODE_BOOL)
+ {
+ /* Perform integral promotion for ANSI C/C++. FIXME: What about
+ FORTRAN and (the deleted) chill ? */
+ if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+ result_type = builtin_type_int;
+
+ return value_from_longest (result_type, -value_as_long (arg1));
+ }
+ else
+ {
+ error ("Argument to negate operation not a number.");
+ return 0; /* For lint -- never reached */
+ }
+}
+
+struct value *
+value_complement (struct value *arg1)
+{
+ struct type *type;
+ struct type *result_type = VALUE_TYPE (arg1);
+ int typecode;
+
+ COERCE_REF (arg1);
+ COERCE_ENUM (arg1);
+
+ type = check_typedef (VALUE_TYPE (arg1));
+
+ typecode = TYPE_CODE (type);
+ if ((typecode != TYPE_CODE_INT) && (typecode != TYPE_CODE_BOOL))
+ error ("Argument to complement operation not an integer or boolean.");
+
+ /* Perform integral promotion for ANSI C/C++.
+ FIXME: What about FORTRAN ? */
+ if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+ result_type = builtin_type_int;
+
+ return value_from_longest (result_type, ~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 (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;
+}
+
+struct value *
+value_in (struct value *element, struct value *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 (void)
+{
+}
diff --git a/contrib/gdb/gdb/valops.c b/contrib/gdb/gdb/valops.c
new file mode 100644
index 0000000..6042277
--- /dev/null
+++ b/contrib/gdb/gdb/valops.c
@@ -0,0 +1,2934 @@
+/* Perform non-arithmetic operations on values, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "gdbcmd.h"
+#include "regcache.h"
+#include "cp-abi.h"
+#include "block.h"
+#include "infcall.h"
+#include "dictionary.h"
+#include "cp-support.h"
+
+#include <errno.h>
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "cp-support.h"
+
+/* Flag indicating HP compilers were used; needed to correctly handle some
+ value operations with HP aCC code/runtime. */
+extern int hp_som_som_object_present;
+
+extern int overload_debug;
+/* Local functions. */
+
+static int typecmp (int staticp, int varargs, int nargs,
+ struct field t1[], struct value *t2[]);
+
+static CORE_ADDR value_push (CORE_ADDR, struct value *);
+
+static struct value *search_struct_field (char *, struct value *, int,
+ struct type *, int);
+
+static struct value *search_struct_method (char *, struct value **,
+ struct value **,
+ int, int *, struct type *);
+
+static int find_oload_champ_namespace (struct type **arg_types, int nargs,
+ const char *func_name,
+ const char *qualified_name,
+ struct symbol ***oload_syms,
+ struct badness_vector **oload_champ_bv);
+
+static
+int find_oload_champ_namespace_loop (struct type **arg_types, int nargs,
+ const char *func_name,
+ const char *qualified_name,
+ int namespace_len,
+ struct symbol ***oload_syms,
+ struct badness_vector **oload_champ_bv,
+ int *oload_champ);
+
+static int find_oload_champ (struct type **arg_types, int nargs, int method,
+ int num_fns,
+ struct fn_field *fns_ptr,
+ struct symbol **oload_syms,
+ struct badness_vector **oload_champ_bv);
+
+static int oload_method_static (int method, struct fn_field *fns_ptr,
+ int index);
+
+enum oload_classification { STANDARD, NON_STANDARD, INCOMPATIBLE };
+
+static enum
+oload_classification classify_oload_match (struct badness_vector
+ * oload_champ_bv,
+ int nargs,
+ int static_offset);
+
+static int check_field_in (struct type *, const char *);
+
+static struct value *value_struct_elt_for_reference (struct type *domain,
+ int offset,
+ struct type *curtype,
+ char *name,
+ struct type *intype,
+ enum noside noside);
+
+static struct value *value_namespace_elt (const struct type *curtype,
+ char *name,
+ enum noside noside);
+
+static struct value *value_maybe_namespace_elt (const struct type *curtype,
+ char *name,
+ enum noside noside);
+
+static CORE_ADDR allocate_space_in_inferior (int);
+
+static struct value *cast_into_complex (struct type *, struct value *);
+
+static struct fn_field *find_method_list (struct value ** argp, char *method,
+ int offset,
+ struct type *type, int *num_fns,
+ struct type **basetype,
+ int *boffset);
+
+void _initialize_valops (void);
+
+/* Flag for whether we want to abandon failed expression evals by default. */
+
+#if 0
+static int auto_abandon = 0;
+#endif
+
+int overload_resolution = 0;
+
+/* Find the address of function name NAME in the inferior. */
+
+struct value *
+find_function_in_inferior (const char *name)
+{
+ struct symbol *sym;
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 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;
+ CORE_ADDR maddr;
+ type = lookup_pointer_type (builtin_type_char);
+ type = lookup_function_type (type);
+ type = lookup_pointer_type (type);
+ maddr = SYMBOL_VALUE_ADDRESS (msymbol);
+ return value_from_pointer (type, maddr);
+ }
+ else
+ {
+ if (!target_has_execution)
+ error ("evaluation of this expression requires the target program to be active");
+ 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. */
+
+struct value *
+value_allocate_space_in_inferior (int len)
+{
+ struct value *blocklen;
+ struct value *val = find_function_in_inferior (NAME_OF_MALLOC);
+
+ blocklen = value_from_longest (builtin_type_int, (LONGEST) len);
+ val = call_function_by_hand (val, 1, &blocklen);
+ if (value_logical_not (val))
+ {
+ if (!target_has_execution)
+ error ("No memory available to program now: you need to start the target first");
+ else
+ error ("No memory available to program: call to malloc failed");
+ }
+ return val;
+}
+
+static CORE_ADDR
+allocate_space_in_inferior (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. */
+
+struct value *
+value_cast (struct type *type, struct value *arg2)
+{
+ enum type_code code1;
+ enum type_code code2;
+ int scalar;
+ struct type *type2;
+
+ int convert_to_boolean = 0;
+
+ 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_INT;
+ convert_to_boolean = 1;
+ }
+ if (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. */
+ struct value *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))
+ {
+ LONGEST longest;
+
+ if (hp_som_som_object_present && /* if target compiled by HP aCC */
+ (code2 == TYPE_CODE_PTR))
+ {
+ unsigned int *ptr;
+ struct value *retvalp;
+
+ switch (TYPE_CODE (TYPE_TARGET_TYPE (type2)))
+ {
+ /* With HP aCC, pointers to data members have a bias */
+ case TYPE_CODE_MEMBER:
+ retvalp = value_from_longest (type, value_as_long (arg2));
+ /* force evaluation */
+ ptr = (unsigned int *) VALUE_CONTENTS (retvalp);
+ *ptr &= ~0x20000000; /* zap 29th bit to remove bias */
+ return retvalp;
+
+ /* While pointers to methods don't really point to a function */
+ case TYPE_CODE_METHOD:
+ error ("Pointers to methods not supported with HP aCC");
+
+ default:
+ break; /* fall out and go to normal handling */
+ }
+ }
+
+ /* When we cast pointers to integers, we mustn't use
+ POINTER_TO_ADDRESS to find the address the pointer
+ represents, as value_as_long would. GDB should evaluate
+ expressions just as the compiler would --- and the compiler
+ sees a cast as a simple reinterpretation of the pointer's
+ bits. */
+ if (code2 == TYPE_CODE_PTR)
+ longest = extract_unsigned_integer (VALUE_CONTENTS (arg2),
+ TYPE_LENGTH (type2));
+ else
+ longest = value_as_long (arg2);
+ return value_from_longest (type, convert_to_boolean ?
+ (LONGEST) (longest ? 1 : 0) : longest);
+ }
+ else if (code1 == TYPE_CODE_PTR && (code2 == TYPE_CODE_INT ||
+ code2 == TYPE_CODE_ENUM ||
+ code2 == TYPE_CODE_RANGE))
+ {
+ /* TYPE_LENGTH (type) is the length of a pointer, but we really
+ want the length of an address! -- we are really dealing with
+ addresses (i.e., gdb representations) not pointers (i.e.,
+ target representations) here.
+
+ This allows things like "print *(int *)0x01000234" to work
+ without printing a misleading message -- which would
+ otherwise occur when dealing with a target having two byte
+ pointers and four byte addresses. */
+
+ int addr_bit = TARGET_ADDR_BIT;
+
+ LONGEST longest = value_as_long (arg2);
+ if (addr_bit < sizeof (LONGEST) * HOST_CHAR_BIT)
+ {
+ if (longest >= ((LONGEST) 1 << addr_bit)
+ || longest <= -((LONGEST) 1 << addr_bit))
+ warning ("value truncated");
+ }
+ return value_from_longest (type, longest);
+ }
+ else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2))
+ {
+ if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+ {
+ 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
+ && !value_logical_not (arg2))
+ {
+ struct value *v;
+
+ /* 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. */
+ if (TYPE_NAME (t1) != NULL)
+ {
+ 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;
+ }
+ }
+
+ /* Look in the type of the target to see if it contains the
+ type of the source as a superclass. If so, we'll need to
+ offset the pointer rather than just change its type.
+ FIXME: This fails silently with virtual inheritance. */
+ if (TYPE_NAME (t2) != NULL)
+ {
+ v = search_struct_field (type_name_no_tag (t2),
+ value_zero (t1, not_lval), 0, t1, 1);
+ if (v)
+ {
+ CORE_ADDR addr2 = value_as_address (arg2);
+ addr2 -= (VALUE_ADDRESS (v)
+ + VALUE_OFFSET (v)
+ + VALUE_EMBEDDED_OFFSET (v));
+ return value_from_pointer (type, addr2);
+ }
+ }
+ }
+ /* No superclass found, just fall through to change ptr type. */
+ }
+ VALUE_TYPE (arg2) = type;
+ arg2 = value_change_enclosing_type (arg2, type);
+ VALUE_POINTED_TO_OFFSET (arg2) = 0; /* pai: chk_val */
+ return arg2;
+ }
+ else if (VALUE_LVAL (arg2) == lval_memory)
+ {
+ return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2),
+ VALUE_BFD_SECTION (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. */
+
+struct value *
+value_zero (struct type *type, enum lval_type lv)
+{
+ struct value *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.
+
+ Note: value_at does *NOT* handle embedded offsets; perform such
+ adjustments before or after calling it. */
+
+struct value *
+value_at (struct type *type, CORE_ADDR addr, asection *sect)
+{
+ struct value *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_ALL_RAW (val), TYPE_LENGTH (type));
+
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+ VALUE_BFD_SECTION (val) = sect;
+
+ return val;
+}
+
+/* Return a lazy value with type TYPE located at ADDR (cf. value_at). */
+
+struct value *
+value_at_lazy (struct type *type, CORE_ADDR addr, asection *sect)
+{
+ struct value *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;
+ VALUE_BFD_SECTION (val) = sect;
+
+ return val;
+}
+
+/* Called only from the VALUE_CONTENTS and VALUE_CONTENTS_ALL macros,
+ 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 (struct value *val)
+{
+ CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val);
+ int length = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (val));
+
+ struct type *type = VALUE_TYPE (val);
+ if (length)
+ read_memory (addr, VALUE_CONTENTS_ALL_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. */
+
+struct value *
+value_assign (struct value *toval, struct value *fromval)
+{
+ struct type *type;
+ struct value *val;
+ char raw_buffer[MAX_REGISTER_SIZE];
+ int use_buffer = 0;
+ struct frame_id old_frame;
+
+ 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);
+
+ /* Since modifying a register can trash the frame chain, and modifying memory
+ can trash the frame cache, we save the old frame and then restore the new
+ frame afterwards. */
+ old_frame = get_frame_id (deprecated_selected_frame);
+
+ switch (VALUE_LVAL (toval))
+ {
+ case lval_internalvar:
+ set_internalvar (VALUE_INTERNALVAR (toval), fromval);
+ val = value_copy (VALUE_INTERNALVAR (toval)->value);
+ val = value_change_enclosing_type (val, VALUE_ENCLOSING_TYPE (fromval));
+ VALUE_EMBEDDED_OFFSET (val) = VALUE_EMBEDDED_OFFSET (fromval);
+ VALUE_POINTED_TO_OFFSET (val) = VALUE_POINTED_TO_OFFSET (fromval);
+ return val;
+
+ case lval_internalvar_component:
+ set_internalvar_component (VALUE_INTERNALVAR (toval),
+ VALUE_OFFSET (toval),
+ VALUE_BITPOS (toval),
+ VALUE_BITSIZE (toval),
+ fromval);
+ break;
+
+ case lval_memory:
+ {
+ char *dest_buffer;
+ CORE_ADDR changed_addr;
+ int changed_len;
+
+ 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? */
+ changed_len = (VALUE_BITPOS (toval)
+ + VALUE_BITSIZE (toval)
+ + HOST_CHAR_BIT - 1)
+ / HOST_CHAR_BIT;
+
+ if (changed_len > (int) sizeof (LONGEST))
+ error ("Can't handle bitfields which don't fit in a %d bit word.",
+ (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+
+ read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ buffer, changed_len);
+ modify_field (buffer, value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ changed_addr = VALUE_ADDRESS (toval) + VALUE_OFFSET (toval);
+ dest_buffer = buffer;
+ }
+ else if (use_buffer)
+ {
+ changed_addr = VALUE_ADDRESS (toval) + VALUE_OFFSET (toval);
+ changed_len = use_buffer;
+ dest_buffer = raw_buffer;
+ }
+ else
+ {
+ changed_addr = VALUE_ADDRESS (toval) + VALUE_OFFSET (toval);
+ changed_len = TYPE_LENGTH (type);
+ dest_buffer = VALUE_CONTENTS (fromval);
+ }
+
+ write_memory (changed_addr, dest_buffer, changed_len);
+ if (memory_changed_hook)
+ memory_changed_hook (changed_addr, changed_len);
+ target_changed_event ();
+ }
+ break;
+
+ case lval_reg_frame_relative:
+ case lval_register:
+ {
+ struct frame_info *frame;
+ int value_reg;
+
+ /* Figure out which frame this is in currently. */
+ if (VALUE_LVAL (toval) == lval_register)
+ {
+ frame = get_current_frame ();
+ value_reg = VALUE_REGNO (toval);
+ }
+ else
+ {
+ frame = frame_find_by_id (VALUE_FRAME_ID (toval));
+ value_reg = VALUE_FRAME_REGNUM (toval);
+ }
+
+ if (!frame)
+ error ("Value being assigned to is no longer active.");
+
+ if (VALUE_LVAL (toval) == lval_reg_frame_relative
+ && CONVERT_REGISTER_P (VALUE_FRAME_REGNUM (toval), type))
+ {
+ /* If TOVAL is a special machine register requiring
+ conversion of program values to a special raw format. */
+ VALUE_TO_REGISTER (frame, VALUE_FRAME_REGNUM (toval),
+ type, VALUE_CONTENTS (fromval));
+ }
+ else
+ {
+ /* TOVAL 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_copied;
+ int amount_to_copy;
+ char *buffer;
+ int reg_offset;
+ int byte_offset;
+ int regno;
+
+ /* Locate the first register that falls in the value that
+ needs to be transfered. Compute the offset of the
+ value in that register. */
+ {
+ int offset;
+ for (reg_offset = value_reg, offset = 0;
+ offset + DEPRECATED_REGISTER_RAW_SIZE (reg_offset) <= VALUE_OFFSET (toval);
+ reg_offset++);
+ byte_offset = VALUE_OFFSET (toval) - offset;
+ }
+
+ /* Compute the number of register aligned values that need
+ to be copied. */
+ if (VALUE_BITSIZE (toval))
+ amount_to_copy = byte_offset + 1;
+ else
+ amount_to_copy = byte_offset + TYPE_LENGTH (type);
+
+ /* And a bounce buffer. Be slightly over generous. */
+ buffer = (char *) alloca (amount_to_copy + MAX_REGISTER_SIZE);
+
+ /* Copy it in. */
+ for (regno = reg_offset, amount_copied = 0;
+ amount_copied < amount_to_copy;
+ amount_copied += DEPRECATED_REGISTER_RAW_SIZE (regno), regno++)
+ frame_register_read (frame, regno, buffer + amount_copied);
+
+ /* 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 + VALUE_OFFSET (toval), raw_buffer, use_buffer);
+ else
+ memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
+ TYPE_LENGTH (type));
+
+ /* Copy it out. */
+ for (regno = reg_offset, amount_copied = 0;
+ amount_copied < amount_to_copy;
+ amount_copied += DEPRECATED_REGISTER_RAW_SIZE (regno), regno++)
+ put_frame_register (frame, regno, buffer + amount_copied);
+
+ }
+ if (register_changed_hook)
+ register_changed_hook (-1);
+ target_changed_event ();
+ break;
+ }
+
+ default:
+ error ("Left operand of assignment is not an lvalue.");
+ }
+
+ /* 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. Assigning to memory
+ also can. We just do this on all assignments to registers or
+ memory, for simplicity's sake; I doubt the slowdown matters. */
+ switch (VALUE_LVAL (toval))
+ {
+ case lval_memory:
+ case lval_register:
+ case lval_reg_frame_relative:
+
+ reinit_frame_cache ();
+
+ /* Having destoroyed the frame cache, restore the selected frame. */
+
+ /* FIXME: cagney/2002-11-02: There has to be a better way of
+ doing this. Instead of constantly saving/restoring the
+ frame. Why not create a get_selected_frame() function that,
+ having saved the selected frame's ID can automatically
+ re-find the previously selected frame automatically. */
+
+ {
+ struct frame_info *fi = frame_find_by_id (old_frame);
+ if (fi != NULL)
+ select_frame (fi);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ /* 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 = (((ULONGEST) 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;
+ val = value_change_enclosing_type (val, VALUE_ENCLOSING_TYPE (fromval));
+ VALUE_EMBEDDED_OFFSET (val) = VALUE_EMBEDDED_OFFSET (fromval);
+ VALUE_POINTED_TO_OFFSET (val) = VALUE_POINTED_TO_OFFSET (fromval);
+
+ return val;
+}
+
+/* Extend a value VAL to COUNT repetitions of its type. */
+
+struct value *
+value_repeat (struct value *arg1, int count)
+{
+ struct value *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_ENCLOSING_TYPE (arg1), count);
+
+ read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1),
+ VALUE_CONTENTS_ALL_RAW (val),
+ TYPE_LENGTH (VALUE_ENCLOSING_TYPE (val)));
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1);
+
+ return val;
+}
+
+struct value *
+value_of_variable (struct symbol *var, struct block *b)
+{
+ struct value *val;
+ struct frame_info *frame = NULL;
+
+ if (!b)
+ frame = NULL; /* Use selected frame. */
+ else if (symbol_read_needs_frame (var))
+ {
+ frame = block_innermost_frame (b);
+ if (!frame)
+ {
+ if (BLOCK_FUNCTION (b)
+ && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)))
+ error ("No frame is currently executing in block %s.",
+ SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)));
+ else
+ error ("No frame is currently executing in specified block");
+ }
+ }
+
+ val = read_var_value (var, frame);
+ if (!val)
+ error ("Address of symbol \"%s\" is unknown.", SYMBOL_PRINT_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.
+ */
+
+struct value *
+value_coerce_array (struct value *arg1)
+{
+ 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_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Given a value which is a function, return a value which is a pointer
+ to it. */
+
+struct value *
+value_coerce_function (struct value *arg1)
+{
+ struct value *retval;
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ retval = value_from_pointer (lookup_pointer_type (VALUE_TYPE (arg1)),
+ (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+ VALUE_BFD_SECTION (retval) = VALUE_BFD_SECTION (arg1);
+ return retval;
+}
+
+/* Return a pointer value for the object for which ARG1 is the contents. */
+
+struct value *
+value_addr (struct value *arg1)
+{
+ struct value *arg2;
+
+ 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. */
+ 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.");
+
+ /* Get target memory address */
+ arg2 = value_from_pointer (lookup_pointer_type (VALUE_TYPE (arg1)),
+ (VALUE_ADDRESS (arg1)
+ + VALUE_OFFSET (arg1)
+ + VALUE_EMBEDDED_OFFSET (arg1)));
+
+ /* This may be a pointer to a base subobject; so remember the
+ full derived object's type ... */
+ arg2 = value_change_enclosing_type (arg2, lookup_pointer_type (VALUE_ENCLOSING_TYPE (arg1)));
+ /* ... and also the relative position of the subobject in the full object */
+ VALUE_POINTED_TO_OFFSET (arg2) = VALUE_EMBEDDED_OFFSET (arg1);
+ VALUE_BFD_SECTION (arg2) = VALUE_BFD_SECTION (arg1);
+ return arg2;
+}
+
+/* Given a value of a pointer type, apply the C unary * operator to it. */
+
+struct value *
+value_ind (struct value *arg1)
+{
+ struct type *base_type;
+ struct value *arg2;
+
+ COERCE_ARRAY (arg1);
+
+ base_type = check_typedef (VALUE_TYPE (arg1));
+
+ if (TYPE_CODE (base_type) == 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 (base_type) == TYPE_CODE_INT)
+ return value_at_lazy (builtin_type_int,
+ (CORE_ADDR) value_as_long (arg1),
+ VALUE_BFD_SECTION (arg1));
+ else if (TYPE_CODE (base_type) == TYPE_CODE_PTR)
+ {
+ struct type *enc_type;
+ /* We may be pointing to something embedded in a larger object */
+ /* Get the real type of the enclosing object */
+ enc_type = check_typedef (VALUE_ENCLOSING_TYPE (arg1));
+ enc_type = TYPE_TARGET_TYPE (enc_type);
+ /* Retrieve the enclosing object pointed to */
+ arg2 = value_at_lazy (enc_type,
+ value_as_address (arg1) - VALUE_POINTED_TO_OFFSET (arg1),
+ VALUE_BFD_SECTION (arg1));
+ /* Re-adjust type */
+ VALUE_TYPE (arg2) = TYPE_TARGET_TYPE (base_type);
+ /* Add embedding info */
+ arg2 = value_change_enclosing_type (arg2, enc_type);
+ VALUE_EMBEDDED_OFFSET (arg2) = VALUE_POINTED_TO_OFFSET (arg1);
+
+ /* We may be pointing to an object of some derived type */
+ arg2 = value_full_object (arg2, NULL, 0, 0, 0);
+ return arg2;
+ }
+
+ 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 (CORE_ADDR sp, ULONGEST word)
+{
+ int len = DEPRECATED_REGISTER_SIZE;
+ char buffer[MAX_REGISTER_SIZE];
+
+ store_unsigned_integer (buffer, len, word);
+ if (INNER_THAN (1, 2))
+ {
+ /* stack grows downward */
+ sp -= len;
+ write_memory (sp, buffer, len);
+ }
+ else
+ {
+ /* stack grows upward */
+ write_memory (sp, buffer, len);
+ sp += len;
+ }
+
+ return sp;
+}
+
+/* Push LEN bytes with data at BUFFER. */
+
+CORE_ADDR
+push_bytes (CORE_ADDR sp, char *buffer, int len)
+{
+ if (INNER_THAN (1, 2))
+ {
+ /* stack grows downward */
+ sp -= len;
+ write_memory (sp, buffer, len);
+ }
+ else
+ {
+ /* stack grows upward */
+ write_memory (sp, buffer, len);
+ sp += len;
+ }
+
+ return sp;
+}
+
+#ifndef PARM_BOUNDARY
+#define PARM_BOUNDARY (0)
+#endif
+
+/* Push onto the stack the specified value VALUE. Pad it correctly for
+ it to be an argument to a function. */
+
+static CORE_ADDR
+value_push (CORE_ADDR sp, struct value *arg)
+{
+ int len = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg));
+ int container_len = len;
+ int offset;
+
+ /* How big is the container we're going to put this value in? */
+ if (PARM_BOUNDARY)
+ container_len = ((len + PARM_BOUNDARY / TARGET_CHAR_BIT - 1)
+ & ~(PARM_BOUNDARY / TARGET_CHAR_BIT - 1));
+
+ /* Are we going to put it at the high or low end of the container? */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = container_len - len;
+ else
+ offset = 0;
+
+ if (INNER_THAN (1, 2))
+ {
+ /* stack grows downward */
+ sp -= container_len;
+ write_memory (sp + offset, VALUE_CONTENTS_ALL (arg), len);
+ }
+ else
+ {
+ /* stack grows upward */
+ write_memory (sp + offset, VALUE_CONTENTS_ALL (arg), len);
+ sp += container_len;
+ }
+
+ return sp;
+}
+
+CORE_ADDR
+legacy_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ /* ASSERT ( !struct_return); */
+ int i;
+ for (i = nargs - 1; i >= 0; i--)
+ sp = value_push (sp, args[i]);
+ return sp;
+}
+
+/* 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). */
+
+struct value *
+value_array (int lowbound, int highbound, struct value **elemvec)
+{
+ int nelem;
+ int idx;
+ unsigned int typelength;
+ struct value *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_ENCLOSING_TYPE (elemvec[0]));
+ for (idx = 1; idx < nelem; idx++)
+ {
+ if (TYPE_LENGTH (VALUE_ENCLOSING_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_ENCLOSING_TYPE (elemvec[0]), rangetype);
+
+ if (!current_language->c_style_arrays)
+ {
+ val = allocate_value (arraytype);
+ for (idx = 0; idx < nelem; idx++)
+ {
+ memcpy (VALUE_CONTENTS_ALL_RAW (val) + (idx * typelength),
+ VALUE_CONTENTS_ALL (elemvec[idx]),
+ typelength);
+ }
+ VALUE_BFD_SECTION (val) = VALUE_BFD_SECTION (elemvec[0]);
+ 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_ALL (elemvec[idx]),
+ typelength);
+ }
+
+ /* Create the array type and set up an array value to be evaluated lazily. */
+
+ val = value_at_lazy (arraytype, addr, VALUE_BFD_SECTION (elemvec[0]));
+ 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. */
+
+struct value *
+value_string (char *ptr, int len)
+{
+ struct value *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, NULL);
+ return (val);
+}
+
+struct value *
+value_bitstring (char *ptr, int len)
+{
+ struct value *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. T1 is a list of NARGS arguments, and T2 is a NULL-terminated
+ vector. 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. T2 will still include the ``this'' pointer,
+ but it will be skipped.
+
+ 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 (int staticp, int varargs, int nargs,
+ struct field t1[], struct value *t2[])
+{
+ int i;
+
+ if (t2 == 0)
+ internal_error (__FILE__, __LINE__, "typecmp: no argument list");
+
+ /* Skip ``this'' argument if applicable. T2 will always include THIS. */
+ if (staticp)
+ t2 ++;
+
+ for (i = 0;
+ (i < nargs) && TYPE_CODE (t1[i].type) != TYPE_CODE_VOID;
+ i++)
+ {
+ struct type *tt1, *tt2;
+
+ if (!t2[i])
+ return i + 1;
+
+ tt1 = check_typedef (t1[i].type);
+ 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;
+ }
+
+ /* djb - 20000715 - Until the new type structure is in the
+ place, and we can attempt things like implicit conversions,
+ we need to do this so you can take something like a map<const
+ char *>, and properly access map["hello"], because the
+ argument to [] will be a reference to a pointer to a char,
+ and the argument will be a pointer to a char. */
+ while ( TYPE_CODE(tt1) == TYPE_CODE_REF ||
+ TYPE_CODE (tt1) == TYPE_CODE_PTR)
+ {
+ tt1 = check_typedef( TYPE_TARGET_TYPE(tt1) );
+ }
+ while ( TYPE_CODE(tt2) == TYPE_CODE_ARRAY ||
+ TYPE_CODE(tt2) == TYPE_CODE_PTR ||
+ TYPE_CODE(tt2) == TYPE_CODE_REF)
+ {
+ 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) != TYPE_CODE (VALUE_TYPE (t2[i])))
+ return i + 1;
+ }
+ if (varargs || t2[i] == NULL)
+ return 0;
+ return i + 1;
+}
+
+/* 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 struct value *
+search_struct_field (char *name, struct value *arg1, int offset,
+ struct type *type, int looking_for_baseclass)
+{
+ int i;
+ int nbases = TYPE_N_BASECLASSES (type);
+
+ CHECK_TYPEDEF (type);
+
+ if (!looking_for_baseclass)
+ for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+ if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
+ {
+ struct value *v;
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ v = value_static_field (type, i);
+ if (v == 0)
+ error ("field %s is nonexistent or has been optimised out",
+ name);
+ }
+ 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
+ && (strcmp_iw (t_field_name, "else") == 0))))
+ {
+ 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 (now deleted from GDB)
+ implementation of variant record types, each
+ <alternative field> has an (anonymous) union type,
+ each member of the union represents a <variant
+ alternative>. Each <variant alternative> is
+ represented as a struct, with a member for each
+ <variant field>. */
+
+ struct value *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 (now deleted
+ from GDB) 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 = 0; i < nbases; i++)
+ {
+ struct value *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
+ && (strcmp_iw (name, TYPE_BASECLASS_NAME (type, i)) == 0));
+
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ int boffset;
+ struct value *v2 = allocate_value (basetype);
+
+ boffset = baseclass_offset (type, i,
+ VALUE_CONTENTS (arg1) + offset,
+ VALUE_ADDRESS (arg1)
+ + VALUE_OFFSET (arg1) + offset);
+ if (boffset == -1)
+ error ("virtual baseclass botch");
+
+ /* The virtual base class pointer might have been clobbered by the
+ user program. Make sure that it still points to a valid memory
+ location. */
+
+ boffset += offset;
+ if (boffset < 0 || boffset >= TYPE_LENGTH (type))
+ {
+ CORE_ADDR base_addr;
+
+ base_addr = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1) + boffset;
+ if (target_read_memory (base_addr, VALUE_CONTENTS_RAW (v2),
+ TYPE_LENGTH (basetype)) != 0)
+ error ("virtual baseclass botch");
+ VALUE_LVAL (v2) = lval_memory;
+ VALUE_ADDRESS (v2) = base_addr;
+ }
+ else
+ {
+ VALUE_LVAL (v2) = VALUE_LVAL (arg1);
+ VALUE_ADDRESS (v2) = VALUE_ADDRESS (arg1);
+ VALUE_OFFSET (v2) = VALUE_OFFSET (arg1) + boffset;
+ if (VALUE_LAZY (arg1))
+ VALUE_LAZY (v2) = 1;
+ else
+ memcpy (VALUE_CONTENTS_RAW (v2),
+ VALUE_CONTENTS_RAW (arg1) + boffset,
+ TYPE_LENGTH (basetype));
+ }
+
+ if (found_baseclass)
+ return v2;
+ v = search_struct_field (name, v2, 0, 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;
+}
+
+
+/* Return the offset (in bytes) of the virtual base of type BASETYPE
+ * in an object pointed to by VALADDR (on the host), assumed to be of
+ * type TYPE. OFFSET is number of bytes beyond start of ARG to start
+ * looking (in case VALADDR is the contents of an enclosing object).
+ *
+ * This routine recurses on the primary base of the derived class because
+ * the virtual base entries of the primary base appear before the other
+ * virtual base entries.
+ *
+ * If the virtual base is not found, a negative integer is returned.
+ * The magnitude of the negative integer is the number of entries in
+ * the virtual table to skip over (entries corresponding to various
+ * ancestral classes in the chain of primary bases).
+ *
+ * Important: This assumes the HP / Taligent C++ runtime
+ * conventions. Use baseclass_offset() instead to deal with g++
+ * conventions. */
+
+void
+find_rt_vbase_offset (struct type *type, struct type *basetype, char *valaddr,
+ int offset, int *boffset_p, int *skip_p)
+{
+ int boffset; /* offset of virtual base */
+ int index; /* displacement to use in virtual table */
+ int skip;
+
+ struct value *vp;
+ CORE_ADDR vtbl; /* the virtual table pointer */
+ struct type *pbc; /* the primary base class */
+
+ /* Look for the virtual base recursively in the primary base, first.
+ * This is because the derived class object and its primary base
+ * subobject share the primary virtual table. */
+
+ boffset = 0;
+ pbc = TYPE_PRIMARY_BASE (type);
+ if (pbc)
+ {
+ find_rt_vbase_offset (pbc, basetype, valaddr, offset, &boffset, &skip);
+ if (skip < 0)
+ {
+ *boffset_p = boffset;
+ *skip_p = -1;
+ return;
+ }
+ }
+ else
+ skip = 0;
+
+
+ /* Find the index of the virtual base according to HP/Taligent
+ runtime spec. (Depth-first, left-to-right.) */
+ index = virtual_base_index_skip_primaries (basetype, type);
+
+ if (index < 0)
+ {
+ *skip_p = skip + virtual_base_list_length_skip_primaries (type);
+ *boffset_p = 0;
+ return;
+ }
+
+ /* pai: FIXME -- 32x64 possible problem */
+ /* First word (4 bytes) in object layout is the vtable pointer */
+ vtbl = *(CORE_ADDR *) (valaddr + offset);
+
+ /* Before the constructor is invoked, things are usually zero'd out. */
+ if (vtbl == 0)
+ error ("Couldn't find virtual table -- object may not be constructed yet.");
+
+
+ /* Find virtual base's offset -- jump over entries for primary base
+ * ancestors, then use the index computed above. But also adjust by
+ * HP_ACC_VBASE_START for the vtable slots before the start of the
+ * virtual base entries. Offset is negative -- virtual base entries
+ * appear _before_ the address point of the virtual table. */
+
+ /* pai: FIXME -- 32x64 problem, if word = 8 bytes, change multiplier
+ & use long type */
+
+ /* epstein : FIXME -- added param for overlay section. May not be correct */
+ vp = value_at (builtin_type_int, vtbl + 4 * (-skip - index - HP_ACC_VBASE_START), NULL);
+ boffset = value_as_long (vp);
+ *skip_p = -1;
+ *boffset_p = boffset;
+ return;
+}
+
+
+/* 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 struct value *
+search_struct_method (char *name, struct value **arg1p,
+ struct value **args, int offset,
+ int *static_memfuncp, struct type *type)
+{
+ int i;
+ struct value *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);
+ /* FIXME! May need to check for ARM demangling here */
+ 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 && (strcmp_iw (t_field_name, name) == 0))
+ {
+ int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ name_matched = 1;
+
+ check_stub_method_group (type, i);
+ if (j > 0 && args == 0)
+ error ("cannot resolve overloaded method `%s': no arguments supplied", name);
+ else if (j == 0 && args == 0)
+ {
+ v = value_fn_field (arg1p, f, j, type, offset);
+ if (v != NULL)
+ return v;
+ }
+ else
+ while (j >= 0)
+ {
+ if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j),
+ TYPE_VARARGS (TYPE_FN_FIELD_TYPE (f, j)),
+ TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (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))
+ {
+ if (TYPE_HAS_VTABLE (type))
+ {
+ /* HP aCC compiled type, search for virtual base offset
+ according to HP/Taligent runtime spec. */
+ int skip;
+ find_rt_vbase_offset (type, TYPE_BASECLASS (type, i),
+ VALUE_CONTENTS_ALL (*arg1p),
+ offset + VALUE_EMBEDDED_OFFSET (*arg1p),
+ &base_offset, &skip);
+ if (skip >= 0)
+ error ("Virtual base class offset not found in vtable");
+ }
+ else
+ {
+ struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
+ char *base_valaddr;
+
+ /* The virtual base class pointer might have been clobbered by the
+ user program. Make sure that it still points to a valid memory
+ location. */
+
+ if (offset < 0 || offset >= TYPE_LENGTH (type))
+ {
+ base_valaddr = (char *) alloca (TYPE_LENGTH (baseclass));
+ if (target_read_memory (VALUE_ADDRESS (*arg1p)
+ + VALUE_OFFSET (*arg1p) + offset,
+ base_valaddr,
+ TYPE_LENGTH (baseclass)) != 0)
+ error ("virtual baseclass botch");
+ }
+ else
+ base_valaddr = VALUE_CONTENTS (*arg1p) + offset;
+
+ base_offset =
+ baseclass_offset (type, i, base_valaddr,
+ VALUE_ADDRESS (*arg1p)
+ + VALUE_OFFSET (*arg1p) + 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 == (struct value *) - 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 (struct value *) - 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. */
+
+struct value *
+value_struct_elt (struct value **argp, struct value **args,
+ char *name, int *static_memfuncp, char *err)
+{
+ struct type *t;
+ struct value *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 == (struct value *) - 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. */
+ int m_index, f_index;
+
+ v = NULL;
+ if (get_destructor_fn_field (t, &m_index, &f_index))
+ {
+ v = value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, m_index),
+ f_index, NULL, 0);
+ }
+ if (v == NULL)
+ 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 == (struct value *) - 1)
+ {
+ error ("One of the arguments you tried to pass to %s could not be converted to what the function wants.", 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;
+}
+
+/* Search through the methods of an object (and its bases)
+ * to find a specified method. Return the pointer to the
+ * fn_field list of overloaded instances.
+ * Helper function for value_find_oload_list.
+ * ARGP is a pointer to a pointer to a value (the object)
+ * METHOD is a string containing the method name
+ * OFFSET is the offset within the value
+ * TYPE is the assumed type of the object
+ * NUM_FNS is the number of overloaded instances
+ * BASETYPE is set to the actual type of the subobject where the method is found
+ * BOFFSET is the offset of the base subobject where the method is found */
+
+static struct fn_field *
+find_method_list (struct value **argp, char *method, int offset,
+ struct type *type, int *num_fns,
+ struct type **basetype, int *boffset)
+{
+ int i;
+ struct fn_field *f;
+ CHECK_TYPEDEF (type);
+
+ *num_fns = 0;
+
+ /* First check in object itself */
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+ {
+ /* pai: FIXME What about operators and type conversions? */
+ char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
+ {
+ int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+
+ *num_fns = len;
+ *basetype = type;
+ *boffset = offset;
+
+ /* Resolve any stub methods. */
+ check_stub_method_group (type, i);
+
+ return f;
+ }
+ }
+
+ /* Not found in object, check in base subobjects */
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ int base_offset;
+ if (BASETYPE_VIA_VIRTUAL (type, i))
+ {
+ if (TYPE_HAS_VTABLE (type))
+ {
+ /* HP aCC compiled type, search for virtual base offset
+ * according to HP/Taligent runtime spec. */
+ int skip;
+ find_rt_vbase_offset (type, TYPE_BASECLASS (type, i),
+ VALUE_CONTENTS_ALL (*argp),
+ offset + VALUE_EMBEDDED_OFFSET (*argp),
+ &base_offset, &skip);
+ if (skip >= 0)
+ error ("Virtual base class offset not found in vtable");
+ }
+ else
+ {
+ /* probably g++ runtime model */
+ base_offset = VALUE_OFFSET (*argp) + offset;
+ base_offset =
+ baseclass_offset (type, i,
+ VALUE_CONTENTS (*argp) + base_offset,
+ VALUE_ADDRESS (*argp) + base_offset);
+ if (base_offset == -1)
+ error ("virtual baseclass botch");
+ }
+ }
+ else
+ /* non-virtual base, simply use bit position from debug info */
+ {
+ base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
+ }
+ f = find_method_list (argp, method, base_offset + offset,
+ TYPE_BASECLASS (type, i), num_fns, basetype,
+ boffset);
+ if (f)
+ return f;
+ }
+ return NULL;
+}
+
+/* Return the list of overloaded methods of a specified name.
+ * ARGP is a pointer to a pointer to a value (the object)
+ * METHOD is the method name
+ * OFFSET is the offset within the value contents
+ * NUM_FNS is the number of overloaded instances
+ * BASETYPE is set to the type of the base subobject that defines the method
+ * BOFFSET is the offset of the base subobject which defines the method */
+
+struct fn_field *
+value_find_oload_method_list (struct value **argp, char *method, int offset,
+ int *num_fns, struct type **basetype,
+ int *boffset)
+{
+ struct type *t;
+
+ t = check_typedef (VALUE_TYPE (*argp));
+
+ /* code snarfed from value_struct_elt */
+ 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_find_oload_lis");
+
+ 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 struct or union");
+
+ return find_method_list (argp, method, 0, t, num_fns, basetype, boffset);
+}
+
+/* Given an array of argument types (ARGTYPES) (which includes an
+ entry for "this" in the case of C++ methods), the number of
+ arguments NARGS, the NAME of a function whether it's a method or
+ not (METHOD), and the degree of laxness (LAX) in conforming to
+ overload resolution rules in ANSI C++, find the best function that
+ matches on the argument types according to the overload resolution
+ rules.
+
+ In the case of class methods, the parameter OBJ is an object value
+ in which to search for overloaded methods.
+
+ In the case of non-method functions, the parameter FSYM is a symbol
+ corresponding to one of the overloaded functions.
+
+ Return value is an integer: 0 -> good match, 10 -> debugger applied
+ non-standard coercions, 100 -> incompatible.
+
+ If a method is being searched for, VALP will hold the value.
+ If a non-method is being searched for, SYMP will hold the symbol for it.
+
+ If a method is being searched for, and it is a static method,
+ then STATICP will point to a non-zero value.
+
+ Note: This function does *not* check the value of
+ overload_resolution. Caller must check it to see whether overload
+ resolution is permitted.
+ */
+
+int
+find_overload_match (struct type **arg_types, int nargs, char *name, int method,
+ int lax, struct value **objp, struct symbol *fsym,
+ struct value **valp, struct symbol **symp, int *staticp)
+{
+ struct value *obj = (objp ? *objp : NULL);
+
+ int oload_champ; /* Index of best overloaded function */
+
+ struct badness_vector *oload_champ_bv = NULL; /* The measure for the current best match */
+
+ struct value *temp = obj;
+ struct fn_field *fns_ptr = NULL; /* For methods, the list of overloaded methods */
+ struct symbol **oload_syms = NULL; /* For non-methods, the list of overloaded function symbols */
+ int num_fns = 0; /* Number of overloaded instances being considered */
+ struct type *basetype = NULL;
+ int boffset;
+ int ix;
+ int static_offset;
+ struct cleanup *old_cleanups = NULL;
+
+ const char *obj_type_name = NULL;
+ char *func_name = NULL;
+ enum oload_classification match_quality;
+
+ /* Get the list of overloaded methods or functions */
+ if (method)
+ {
+ obj_type_name = TYPE_NAME (VALUE_TYPE (obj));
+ /* Hack: evaluate_subexp_standard often passes in a pointer
+ value rather than the object itself, so try again */
+ if ((!obj_type_name || !*obj_type_name) &&
+ (TYPE_CODE (VALUE_TYPE (obj)) == TYPE_CODE_PTR))
+ obj_type_name = TYPE_NAME (TYPE_TARGET_TYPE (VALUE_TYPE (obj)));
+
+ fns_ptr = value_find_oload_method_list (&temp, name, 0,
+ &num_fns,
+ &basetype, &boffset);
+ if (!fns_ptr || !num_fns)
+ error ("Couldn't find method %s%s%s",
+ obj_type_name,
+ (obj_type_name && *obj_type_name) ? "::" : "",
+ name);
+ /* If we are dealing with stub method types, they should have
+ been resolved by find_method_list via value_find_oload_method_list
+ above. */
+ gdb_assert (TYPE_DOMAIN_TYPE (fns_ptr[0].type) != NULL);
+ oload_champ = find_oload_champ (arg_types, nargs, method, num_fns,
+ fns_ptr, oload_syms, &oload_champ_bv);
+ }
+ else
+ {
+ const char *qualified_name = SYMBOL_CPLUS_DEMANGLED_NAME (fsym);
+ func_name = cp_func_name (qualified_name);
+
+ /* If the name is NULL this must be a C-style function.
+ Just return the same symbol. */
+ if (func_name == NULL)
+ {
+ *symp = fsym;
+ return 0;
+ }
+
+ old_cleanups = make_cleanup (xfree, func_name);
+ make_cleanup (xfree, oload_syms);
+ make_cleanup (xfree, oload_champ_bv);
+
+ oload_champ = find_oload_champ_namespace (arg_types, nargs,
+ func_name,
+ qualified_name,
+ &oload_syms,
+ &oload_champ_bv);
+ }
+
+ /* Check how bad the best match is. */
+
+ match_quality
+ = classify_oload_match (oload_champ_bv, nargs,
+ oload_method_static (method, fns_ptr,
+ oload_champ));
+
+ if (match_quality == INCOMPATIBLE)
+ {
+ if (method)
+ error ("Cannot resolve method %s%s%s to any overloaded instance",
+ obj_type_name,
+ (obj_type_name && *obj_type_name) ? "::" : "",
+ name);
+ else
+ error ("Cannot resolve function %s to any overloaded instance",
+ func_name);
+ }
+ else if (match_quality == NON_STANDARD)
+ {
+ if (method)
+ warning ("Using non-standard conversion to match method %s%s%s to supplied arguments",
+ obj_type_name,
+ (obj_type_name && *obj_type_name) ? "::" : "",
+ name);
+ else
+ warning ("Using non-standard conversion to match function %s to supplied arguments",
+ func_name);
+ }
+
+ if (method)
+ {
+ if (staticp != NULL)
+ *staticp = oload_method_static (method, fns_ptr, oload_champ);
+ if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, oload_champ))
+ *valp = value_virtual_fn_field (&temp, fns_ptr, oload_champ, basetype, boffset);
+ else
+ *valp = value_fn_field (&temp, fns_ptr, oload_champ, basetype, boffset);
+ }
+ else
+ {
+ *symp = oload_syms[oload_champ];
+ }
+
+ if (objp)
+ {
+ if (TYPE_CODE (VALUE_TYPE (temp)) != TYPE_CODE_PTR
+ && TYPE_CODE (VALUE_TYPE (*objp)) == TYPE_CODE_PTR)
+ {
+ temp = value_addr (temp);
+ }
+ *objp = temp;
+ }
+ if (old_cleanups != NULL)
+ do_cleanups (old_cleanups);
+
+ switch (match_quality)
+ {
+ case INCOMPATIBLE:
+ return 100;
+ case NON_STANDARD:
+ return 10;
+ default: /* STANDARD */
+ return 0;
+ }
+}
+
+/* Find the best overload match, searching for FUNC_NAME in namespaces
+ contained in QUALIFIED_NAME until it either finds a good match or
+ runs out of namespaces. It stores the overloaded functions in
+ *OLOAD_SYMS, and the badness vector in *OLOAD_CHAMP_BV. The
+ calling function is responsible for freeing *OLOAD_SYMS and
+ *OLOAD_CHAMP_BV. */
+
+static int
+find_oload_champ_namespace (struct type **arg_types, int nargs,
+ const char *func_name,
+ const char *qualified_name,
+ struct symbol ***oload_syms,
+ struct badness_vector **oload_champ_bv)
+{
+ int oload_champ;
+
+ find_oload_champ_namespace_loop (arg_types, nargs,
+ func_name,
+ qualified_name, 0,
+ oload_syms, oload_champ_bv,
+ &oload_champ);
+
+ return oload_champ;
+}
+
+/* Helper function for find_oload_champ_namespace; NAMESPACE_LEN is
+ how deep we've looked for namespaces, and the champ is stored in
+ OLOAD_CHAMP. The return value is 1 if the champ is a good one, 0
+ if it isn't.
+
+ It is the caller's responsibility to free *OLOAD_SYMS and
+ *OLOAD_CHAMP_BV. */
+
+static int
+find_oload_champ_namespace_loop (struct type **arg_types, int nargs,
+ const char *func_name,
+ const char *qualified_name,
+ int namespace_len,
+ struct symbol ***oload_syms,
+ struct badness_vector **oload_champ_bv,
+ int *oload_champ)
+{
+ int next_namespace_len = namespace_len;
+ int searched_deeper = 0;
+ int num_fns = 0;
+ struct cleanup *old_cleanups;
+ int new_oload_champ;
+ struct symbol **new_oload_syms;
+ struct badness_vector *new_oload_champ_bv;
+ char *new_namespace;
+
+ if (next_namespace_len != 0)
+ {
+ gdb_assert (qualified_name[next_namespace_len] == ':');
+ next_namespace_len += 2;
+ }
+ next_namespace_len
+ += cp_find_first_component (qualified_name + next_namespace_len);
+
+ /* Initialize these to values that can safely be xfree'd. */
+ *oload_syms = NULL;
+ *oload_champ_bv = NULL;
+
+ /* First, see if we have a deeper namespace we can search in. If we
+ get a good match there, use it. */
+
+ if (qualified_name[next_namespace_len] == ':')
+ {
+ searched_deeper = 1;
+
+ if (find_oload_champ_namespace_loop (arg_types, nargs,
+ func_name, qualified_name,
+ next_namespace_len,
+ oload_syms, oload_champ_bv,
+ oload_champ))
+ {
+ return 1;
+ }
+ };
+
+ /* If we reach here, either we're in the deepest namespace or we
+ didn't find a good match in a deeper namespace. But, in the
+ latter case, we still have a bad match in a deeper namespace;
+ note that we might not find any match at all in the current
+ namespace. (There's always a match in the deepest namespace,
+ because this overload mechanism only gets called if there's a
+ function symbol to start off with.) */
+
+ old_cleanups = make_cleanup (xfree, *oload_syms);
+ old_cleanups = make_cleanup (xfree, *oload_champ_bv);
+ new_namespace = alloca (namespace_len + 1);
+ strncpy (new_namespace, qualified_name, namespace_len);
+ new_namespace[namespace_len] = '\0';
+ new_oload_syms = make_symbol_overload_list (func_name,
+ new_namespace);
+ while (new_oload_syms[num_fns])
+ ++num_fns;
+
+ new_oload_champ = find_oload_champ (arg_types, nargs, 0, num_fns,
+ NULL, new_oload_syms,
+ &new_oload_champ_bv);
+
+ /* Case 1: We found a good match. Free earlier matches (if any),
+ and return it. Case 2: We didn't find a good match, but we're
+ not the deepest function. Then go with the bad match that the
+ deeper function found. Case 3: We found a bad match, and we're
+ the deepest function. Then return what we found, even though
+ it's a bad match. */
+
+ if (new_oload_champ != -1
+ && classify_oload_match (new_oload_champ_bv, nargs, 0) == STANDARD)
+ {
+ *oload_syms = new_oload_syms;
+ *oload_champ = new_oload_champ;
+ *oload_champ_bv = new_oload_champ_bv;
+ do_cleanups (old_cleanups);
+ return 1;
+ }
+ else if (searched_deeper)
+ {
+ xfree (new_oload_syms);
+ xfree (new_oload_champ_bv);
+ discard_cleanups (old_cleanups);
+ return 0;
+ }
+ else
+ {
+ gdb_assert (new_oload_champ != -1);
+ *oload_syms = new_oload_syms;
+ *oload_champ = new_oload_champ;
+ *oload_champ_bv = new_oload_champ_bv;
+ discard_cleanups (old_cleanups);
+ return 0;
+ }
+}
+
+/* Look for a function to take NARGS args of types ARG_TYPES. Find
+ the best match from among the overloaded methods or functions
+ (depending on METHOD) given by FNS_PTR or OLOAD_SYMS, respectively.
+ The number of methods/functions in the list is given by NUM_FNS.
+ Return the index of the best match; store an indication of the
+ quality of the match in OLOAD_CHAMP_BV.
+
+ It is the caller's responsibility to free *OLOAD_CHAMP_BV. */
+
+static int
+find_oload_champ (struct type **arg_types, int nargs, int method,
+ int num_fns, struct fn_field *fns_ptr,
+ struct symbol **oload_syms,
+ struct badness_vector **oload_champ_bv)
+{
+ int ix;
+ struct badness_vector *bv; /* A measure of how good an overloaded instance is */
+ int oload_champ = -1; /* Index of best overloaded function */
+ int oload_ambiguous = 0; /* Current ambiguity state for overload resolution */
+ /* 0 => no ambiguity, 1 => two good funcs, 2 => incomparable funcs */
+
+ *oload_champ_bv = NULL;
+
+ /* Consider each candidate in turn */
+ for (ix = 0; ix < num_fns; ix++)
+ {
+ int jj;
+ int static_offset = oload_method_static (method, fns_ptr, ix);
+ int nparms;
+ struct type **parm_types;
+
+ if (method)
+ {
+ nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
+ }
+ else
+ {
+ /* If it's not a method, this is the proper place */
+ nparms=TYPE_NFIELDS(SYMBOL_TYPE(oload_syms[ix]));
+ }
+
+ /* Prepare array of parameter types */
+ parm_types = (struct type **) xmalloc (nparms * (sizeof (struct type *)));
+ for (jj = 0; jj < nparms; jj++)
+ parm_types[jj] = (method
+ ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
+ : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]), jj));
+
+ /* Compare parameter types to supplied argument types. Skip THIS for
+ static methods. */
+ bv = rank_function (parm_types, nparms, arg_types + static_offset,
+ nargs - static_offset);
+
+ if (!*oload_champ_bv)
+ {
+ *oload_champ_bv = bv;
+ oload_champ = 0;
+ }
+ else
+ /* See whether current candidate is better or worse than previous best */
+ switch (compare_badness (bv, *oload_champ_bv))
+ {
+ case 0:
+ oload_ambiguous = 1; /* top two contenders are equally good */
+ break;
+ case 1:
+ oload_ambiguous = 2; /* incomparable top contenders */
+ break;
+ case 2:
+ *oload_champ_bv = bv; /* new champion, record details */
+ oload_ambiguous = 0;
+ oload_champ = ix;
+ break;
+ case 3:
+ default:
+ break;
+ }
+ xfree (parm_types);
+ if (overload_debug)
+ {
+ if (method)
+ fprintf_filtered (gdb_stderr,"Overloaded method instance %s, # of parms %d\n", fns_ptr[ix].physname, nparms);
+ else
+ fprintf_filtered (gdb_stderr,"Overloaded function instance %s # of parms %d\n", SYMBOL_DEMANGLED_NAME (oload_syms[ix]), nparms);
+ for (jj = 0; jj < nargs - static_offset; jj++)
+ fprintf_filtered (gdb_stderr,"...Badness @ %d : %d\n", jj, bv->rank[jj]);
+ fprintf_filtered (gdb_stderr,"Overload resolution champion is %d, ambiguous? %d\n", oload_champ, oload_ambiguous);
+ }
+ }
+
+ return oload_champ;
+}
+
+/* Return 1 if we're looking at a static method, 0 if we're looking at
+ a non-static method or a function that isn't a method. */
+
+static int
+oload_method_static (int method, struct fn_field *fns_ptr, int index)
+{
+ if (method && TYPE_FN_FIELD_STATIC_P (fns_ptr, index))
+ return 1;
+ else
+ return 0;
+}
+
+/* Check how good an overload match OLOAD_CHAMP_BV represents. */
+
+static enum oload_classification
+classify_oload_match (struct badness_vector *oload_champ_bv,
+ int nargs,
+ int static_offset)
+{
+ int ix;
+
+ for (ix = 1; ix <= nargs - static_offset; ix++)
+ {
+ if (oload_champ_bv->rank[ix] >= 100)
+ return INCOMPATIBLE; /* truly mismatched types */
+ else if (oload_champ_bv->rank[ix] >= 10)
+ return NON_STANDARD; /* non-standard type conversions needed */
+ }
+
+ return STANDARD; /* Only standard conversions needed. */
+}
+
+/* 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 (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 || strncmp (dname, name + 1, len) != 0)
+ 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 (struct type *type, const char *name)
+{
+ 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 && (strcmp_iw (t_field_name, name) == 0))
+ 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))
+ {
+ int m_index, f_index;
+
+ return get_destructor_fn_field (type, &m_index, &f_index);
+ }
+
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
+ {
+ if (strcmp_iw (TYPE_FN_FIELDLIST_NAME (type, i), name) == 0)
+ 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 (struct value *arg1, const char *name)
+{
+ 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 appropriate member. This function is used to resolve
+ user expressions of the form "DOMAIN::NAME". For more details on
+ what happens, see the comment before
+ value_struct_elt_for_reference. */
+
+struct value *
+value_aggregate_elt (struct type *curtype,
+ char *name,
+ enum noside noside)
+{
+ switch (TYPE_CODE (curtype))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return value_struct_elt_for_reference (curtype, 0, curtype, name, NULL,
+ noside);
+ case TYPE_CODE_NAMESPACE:
+ return value_namespace_elt (curtype, name, noside);
+ default:
+ internal_error (__FILE__, __LINE__,
+ "non-aggregate type in value_aggregate_elt");
+ }
+}
+
+/* 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". */
+
+static struct value *
+value_struct_elt_for_reference (struct type *domain, int offset,
+ struct type *curtype, char *name,
+ struct type *intype,
+ enum noside noside)
+{
+ struct type *t = curtype;
+ int i;
+ struct value *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 && strcmp (t_field_name, name) == 0)
+ {
+ if (TYPE_FIELD_STATIC (t, i))
+ {
+ v = value_static_field (t, i);
+ if (v == NULL)
+ error ("static field %s has been optimized out",
+ name);
+ return v;
+ }
+ 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 && strcmp (t_field_name, name) == 0)
+ {
+ int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ check_stub_method_group (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_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_DOMAIN, 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--)
+ {
+ struct value *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,
+ noside);
+ if (v)
+ return v;
+ }
+
+ /* As a last chance, pretend that CURTYPE is a namespace, and look
+ it up that way; this (frequently) works for types nested inside
+ classes. */
+
+ return value_maybe_namespace_elt (curtype, name, noside);
+}
+
+/* C++: Return the member NAME of the namespace given by the type
+ CURTYPE. */
+
+static struct value *
+value_namespace_elt (const struct type *curtype,
+ char *name,
+ enum noside noside)
+{
+ struct value *retval = value_maybe_namespace_elt (curtype, name,
+ noside);
+
+ if (retval == NULL)
+ error ("No symbol \"%s\" in namespace \"%s\".", name,
+ TYPE_TAG_NAME (curtype));
+
+ return retval;
+}
+
+/* A helper function used by value_namespace_elt and
+ value_struct_elt_for_reference. It looks up NAME inside the
+ context CURTYPE; this works if CURTYPE is a namespace or if CURTYPE
+ is a class and NAME refers to a type in CURTYPE itself (as opposed
+ to, say, some base class of CURTYPE). */
+
+static struct value *
+value_maybe_namespace_elt (const struct type *curtype,
+ char *name,
+ enum noside noside)
+{
+ const char *namespace_name = TYPE_TAG_NAME (curtype);
+ struct symbol *sym;
+
+ sym = cp_lookup_symbol_namespace (namespace_name, name, NULL,
+ get_selected_block (0), VAR_DOMAIN,
+ NULL);
+
+ if (sym == NULL)
+ return NULL;
+ else if ((noside == EVAL_AVOID_SIDE_EFFECTS)
+ && (SYMBOL_CLASS (sym) == LOC_TYPEDEF))
+ return allocate_value (SYMBOL_TYPE (sym));
+ else
+ return value_of_variable (sym, get_selected_block (0));
+}
+
+/* Given a pointer value V, find the real (RTTI) type
+ of the object it points to.
+ Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
+ and refer to the values computed for the object pointed to. */
+
+struct type *
+value_rtti_target_type (struct value *v, int *full, int *top, int *using_enc)
+{
+ struct value *target;
+
+ target = value_ind (v);
+
+ return value_rtti_type (target, full, top, using_enc);
+}
+
+/* Given a value pointed to by ARGP, check its real run-time type, and
+ if that is different from the enclosing type, create a new value
+ using the real run-time type as the enclosing type (and of the same
+ type as ARGP) and return it, with the embedded offset adjusted to
+ be the correct offset to the enclosed object
+ RTYPE is the type, and XFULL, XTOP, and XUSING_ENC are the other
+ parameters, computed by value_rtti_type(). If these are available,
+ they can be supplied and a second call to value_rtti_type() is avoided.
+ (Pass RTYPE == NULL if they're not available */
+
+struct value *
+value_full_object (struct value *argp, struct type *rtype, int xfull, int xtop,
+ int xusing_enc)
+{
+ struct type *real_type;
+ int full = 0;
+ int top = -1;
+ int using_enc = 0;
+ struct value *new_val;
+
+ if (rtype)
+ {
+ real_type = rtype;
+ full = xfull;
+ top = xtop;
+ using_enc = xusing_enc;
+ }
+ else
+ real_type = value_rtti_type (argp, &full, &top, &using_enc);
+
+ /* If no RTTI data, or if object is already complete, do nothing */
+ if (!real_type || real_type == VALUE_ENCLOSING_TYPE (argp))
+ return argp;
+
+ /* If we have the full object, but for some reason the enclosing
+ type is wrong, set it *//* pai: FIXME -- sounds iffy */
+ if (full)
+ {
+ argp = value_change_enclosing_type (argp, real_type);
+ return argp;
+ }
+
+ /* Check if object is in memory */
+ if (VALUE_LVAL (argp) != lval_memory)
+ {
+ warning ("Couldn't retrieve complete object of RTTI type %s; object may be in register(s).", TYPE_NAME (real_type));
+
+ return argp;
+ }
+
+ /* All other cases -- retrieve the complete object */
+ /* Go back by the computed top_offset from the beginning of the object,
+ adjusting for the embedded offset of argp if that's what value_rtti_type
+ used for its computation. */
+ new_val = value_at_lazy (real_type, VALUE_ADDRESS (argp) - top +
+ (using_enc ? 0 : VALUE_EMBEDDED_OFFSET (argp)),
+ VALUE_BFD_SECTION (argp));
+ VALUE_TYPE (new_val) = VALUE_TYPE (argp);
+ VALUE_EMBEDDED_OFFSET (new_val) = using_enc ? top + VALUE_EMBEDDED_OFFSET (argp) : top;
+ return new_val;
+}
+
+
+
+
+/* Return the value of the local variable, if one exists.
+ Flag COMPLAIN signals an error if the request is made in an
+ inappropriate context. */
+
+struct value *
+value_of_local (const char *name, int complain)
+{
+ struct symbol *func, *sym;
+ struct block *b;
+ struct value * ret;
+
+ if (deprecated_selected_frame == 0)
+ {
+ if (complain)
+ error ("no frame selected");
+ else
+ return 0;
+ }
+
+ func = get_frame_function (deprecated_selected_frame);
+ if (!func)
+ {
+ if (complain)
+ error ("no `%s' in nameless context", name);
+ else
+ return 0;
+ }
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ if (dict_empty (BLOCK_DICT (b)))
+ {
+ if (complain)
+ error ("no args, no `%s'", name);
+ 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, name, NULL, VAR_DOMAIN);
+ if (sym == NULL)
+ {
+ if (complain)
+ error ("current stack frame does not contain a variable named `%s'", name);
+ else
+ return NULL;
+ }
+
+ ret = read_var_value (sym, deprecated_selected_frame);
+ if (ret == 0 && complain)
+ error ("`%s' argument unreadable", name);
+ return ret;
+}
+
+/* C++/Objective-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. */
+
+struct value *
+value_of_this (int complain)
+{
+ if (current_language->la_language == language_objc)
+ return value_of_local ("self", complain);
+ else
+ return value_of_local ("this", complain);
+}
+
+/* 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. */
+
+struct value *
+value_slice (struct value *array, int lowbound, int length)
+{
+ struct type *slice_range_type, *slice_type, *range_type;
+ LONGEST lowerbound, upperbound;
+ struct value *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)
+ error ("slice out of range");
+ /* FIXME-type-allocation: need a way to free this type when we are
+ done with it. */
+ slice_range_type = create_range_type ((struct type *) NULL,
+ TYPE_TARGET_TYPE (range_type),
+ lowbound, lowbound + 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);
+ LONGEST 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;
+}
+
+/* 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 */
+
+struct value *
+value_literal_complex (struct value *arg1, struct value *arg2, struct type *type)
+{
+ struct value *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 struct value *
+cast_into_complex (struct type *type, struct value *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));
+ struct value *re_val = allocate_value (val_real_type);
+ struct value *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 (void)
+{
+#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
+
+ add_show_from_set
+ (add_set_cmd ("overload-resolution", class_support, var_boolean, (char *) &overload_resolution,
+ "Set overload resolution in evaluating C++ functions.",
+ &setlist),
+ &showlist);
+ overload_resolution = 1;
+}
diff --git a/contrib/gdb/gdb/valprint.c b/contrib/gdb/gdb/valprint.c
new file mode 100644
index 0000000..294e09f
--- /dev/null
+++ b/contrib/gdb/gdb/valprint.c
@@ -0,0 +1,1445 @@
+/* Print values for GDB, the GNU debugger.
+
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "language.h"
+#include "annotate.h"
+#include "valprint.h"
+#include "floatformat.h"
+#include "doublest.h"
+
+#include <errno.h>
+
+/* Prototypes for local functions */
+
+static int partial_memory_read (CORE_ADDR memaddr, char *myaddr,
+ int len, int *errnoptr);
+
+static void show_print (char *, int);
+
+static void set_print (char *, int);
+
+static void set_radix (char *, int);
+
+static void show_radix (char *, int);
+
+static void set_input_radix (char *, int, struct cmd_list_element *);
+
+static void set_input_radix_1 (int, unsigned);
+
+static void set_output_radix (char *, int, struct cmd_list_element *);
+
+static void set_output_radix_1 (int, unsigned);
+
+void _initialize_valprint (void);
+
+/* 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 (struct type *type, char *valaddr, int embedded_offset,
+ CORE_ADDR address, struct ui_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_STUB (real_type))
+ {
+ fprintf_filtered (stream, "<incomplete type>");
+ gdb_flush (stream);
+ return (0);
+ }
+
+ return (LA_VAL_PRINT (type, valaddr, embedded_offset, 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 (struct value *val, struct ui_file *stream, int format,
+ enum val_prettyprint pretty)
+{
+ if (val == 0)
+ {
+ printf_filtered ("<address of value unknown>");
+ return 0;
+ }
+ if (VALUE_OPTIMIZED_OUT (val))
+ {
+ printf_filtered ("<value optimized out>");
+ return 0;
+ }
+ return LA_VALUE_PRINT (val, stream, format, pretty);
+}
+
+/* Called by various <lang>_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 (struct type *type, char *valaddr,
+ struct ui_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
+ {
+ print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0,
+ unpack_long (type, valaddr));
+ }
+}
+
+/* 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 representable as either a signed or
+ unsigned long, depending upon what format is desired, 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).
+ */
+
+#if defined (CC_HAS_LONG_LONG) && !defined (PRINTF_HAS_LONG_LONG)
+static void print_decimal (struct ui_file * stream, char *sign,
+ int use_local, ULONGEST val_ulong);
+static void
+print_decimal (struct ui_file *stream, char *sign, int use_local,
+ ULONGEST val_ulong)
+{
+ unsigned long temp[3];
+ int i = 0;
+ do
+ {
+ temp[i] = val_ulong % (1000 * 1000 * 1000);
+ val_ulong /= (1000 * 1000 * 1000);
+ i++;
+ }
+ while (val_ulong != 0 && i < (sizeof (temp) / sizeof (temp[0])));
+ switch (i)
+ {
+ case 1:
+ fprintf_filtered (stream, "%s%lu",
+ sign, temp[0]);
+ break;
+ case 2:
+ fprintf_filtered (stream, "%s%lu%09lu",
+ sign, temp[1], temp[0]);
+ break;
+ case 3:
+ fprintf_filtered (stream, "%s%lu%09lu%09lu",
+ sign, temp[2], temp[1], temp[0]);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ return;
+}
+#endif
+
+void
+print_longest (struct ui_file *stream, int format, int use_local,
+ LONGEST val_long)
+{
+#if defined (CC_HAS_LONG_LONG) && !defined (PRINTF_HAS_LONG_LONG)
+ if (sizeof (long) < sizeof (LONGEST))
+ {
+ switch (format)
+ {
+ case 'd':
+ {
+ /* Print a signed value, that doesn't fit in a long */
+ if ((long) val_long != val_long)
+ {
+ if (val_long < 0)
+ print_decimal (stream, "-", use_local, -val_long);
+ else
+ print_decimal (stream, "", use_local, val_long);
+ return;
+ }
+ break;
+ }
+ case 'u':
+ {
+ /* Print an unsigned value, that doesn't fit in a long */
+ if ((unsigned long) val_long != (ULONGEST) val_long)
+ {
+ print_decimal (stream, "", use_local, val_long);
+ return;
+ }
+ break;
+ }
+ case 'x':
+ case 'o':
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ /* Print as unsigned value, must fit completely in unsigned long */
+ {
+ unsigned long temp = val_long;
+ if (temp != val_long)
+ {
+ /* Urk, can't represent value in long so print in hex.
+ Do shift in two operations so that if sizeof (long)
+ == sizeof (LONGEST) we can avoid warnings from
+ picky compilers about shifts >= the size of the
+ shiftee in bits */
+ unsigned long vbot = (unsigned long) val_long;
+ LONGEST temp = (val_long >> (sizeof (long) * HOST_CHAR_BIT - 1));
+ unsigned long vtop = temp >> 1;
+ fprintf_filtered (stream, "0x%lx%08lx", vtop, vbot);
+ return;
+ }
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+ switch (format)
+ {
+ case 'd':
+ fprintf_filtered (stream,
+ use_local ? local_decimal_format_custom ("ll")
+ : "%lld",
+ (long long) val_long);
+ break;
+ case 'u':
+ fprintf_filtered (stream, "%llu", (long long) val_long);
+ break;
+ case 'x':
+ fprintf_filtered (stream,
+ use_local ? local_hex_format_custom ("ll")
+ : "%llx",
+ (unsigned long long) val_long);
+ break;
+ case 'o':
+ fprintf_filtered (stream,
+ use_local ? local_octal_format_custom ("ll")
+ : "%llo",
+ (unsigned long long) 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:
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+#else /* !CC_HAS_LONG_LONG || !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",
+ (unsigned long) val_long);
+ break;
+ case 'o':
+ fprintf_filtered (stream,
+ use_local ? local_octal_format_custom ("l")
+ : "%lo",
+ (unsigned long) val_long);
+ break;
+ case 'b':
+ fprintf_filtered (stream, local_hex_format_custom ("02l"),
+ (unsigned long) val_long);
+ break;
+ case 'h':
+ fprintf_filtered (stream, local_hex_format_custom ("04l"),
+ (unsigned long) val_long);
+ break;
+ case 'w':
+ fprintf_filtered (stream, local_hex_format_custom ("08l"),
+ (unsigned long) val_long);
+ break;
+ case 'g':
+ fprintf_filtered (stream, local_hex_format_custom ("016l"),
+ (unsigned long) val_long);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+#endif /* CC_HAS_LONG_LONG || 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 (LONGEST arg)
+{
+ /* Let the compiler do the work */
+ int rtnval = (int) arg;
+
+ /* Check for overflows or underflows */
+ if (sizeof (LONGEST) > sizeof (int))
+ {
+ if (rtnval != arg)
+ {
+ error ("Value out of range.");
+ }
+ }
+ return (rtnval);
+}
+
+/* Print a floating point value of type TYPE (not always a
+ TYPE_CODE_FLT), pointed to in GDB by VALADDR, on STREAM. */
+
+void
+print_floating (char *valaddr, struct type *type, struct ui_file *stream)
+{
+ DOUBLEST doub;
+ int inv;
+ const struct floatformat *fmt = NULL;
+ unsigned len = TYPE_LENGTH (type);
+
+ /* If it is a floating-point, check for obvious problems. */
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ fmt = floatformat_from_type (type);
+ if (fmt != NULL && floatformat_is_nan (fmt, valaddr))
+ {
+ if (floatformat_is_negative (fmt, valaddr))
+ fprintf_filtered (stream, "-");
+ fprintf_filtered (stream, "nan(");
+ fputs_filtered (local_hex_format_prefix (), stream);
+ fputs_filtered (floatformat_mantissa (fmt, valaddr), stream);
+ fputs_filtered (local_hex_format_suffix (), stream);
+ fprintf_filtered (stream, ")");
+ return;
+ }
+
+ /* NOTE: cagney/2002-01-15: The TYPE passed into print_floating()
+ isn't necessarily a TYPE_CODE_FLT. Consequently, unpack_double
+ needs to be used as that takes care of any necessary type
+ conversions. Such conversions are of course direct to DOUBLEST
+ and disregard any possible target floating point limitations.
+ For instance, a u64 would be converted and displayed exactly on a
+ host with 80 bit DOUBLEST but with loss of information on a host
+ with 64 bit DOUBLEST. */
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ {
+ fprintf_filtered (stream, "<invalid float value>");
+ return;
+ }
+
+ /* FIXME: kettenis/2001-01-20: The following code makes too much
+ assumptions about the host and target floating point format. */
+
+ /* NOTE: cagney/2002-02-03: Since the TYPE of what was passed in may
+ not necessarially be a TYPE_CODE_FLT, the below ignores that and
+ instead uses the type's length to determine the precision of the
+ floating-point value being printed. */
+
+ 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
+}
+
+void
+print_binary_chars (struct ui_file *stream, unsigned char *valaddr,
+ unsigned len)
+{
+
+#define BITS_IN_BYTES 8
+
+ unsigned char *p;
+ unsigned int i;
+ int b;
+
+ /* Declared "int" so it will be signed.
+ * This ensures that right shift will shift in zeros.
+ */
+ const int mask = 0x080;
+
+ /* FIXME: We should be not printing leading zeroes in most cases. */
+
+ fputs_filtered (local_binary_format_prefix (), stream);
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ for (p = valaddr;
+ p < valaddr + len;
+ p++)
+ {
+ /* Every byte has 8 binary characters; peel off
+ * and print from the MSB end.
+ */
+ for (i = 0; i < (BITS_IN_BYTES * sizeof (*p)); i++)
+ {
+ if (*p & (mask >> i))
+ b = 1;
+ else
+ b = 0;
+
+ fprintf_filtered (stream, "%1d", b);
+ }
+ }
+ }
+ else
+ {
+ for (p = valaddr + len - 1;
+ p >= valaddr;
+ p--)
+ {
+ for (i = 0; i < (BITS_IN_BYTES * sizeof (*p)); i++)
+ {
+ if (*p & (mask >> i))
+ b = 1;
+ else
+ b = 0;
+
+ fprintf_filtered (stream, "%1d", b);
+ }
+ }
+ }
+ fputs_filtered (local_binary_format_suffix (), stream);
+}
+
+/* VALADDR points to an integer of LEN bytes.
+ * Print it in octal on stream or format it in buf.
+ */
+void
+print_octal_chars (struct ui_file *stream, unsigned char *valaddr, unsigned len)
+{
+ unsigned char *p;
+ unsigned char octa1, octa2, octa3, carry;
+ int cycle;
+
+ /* FIXME: We should be not printing leading zeroes in most cases. */
+
+
+ /* Octal is 3 bits, which doesn't fit. Yuk. So we have to track
+ * the extra bits, which cycle every three bytes:
+ *
+ * Byte side: 0 1 2 3
+ * | | | |
+ * bit number 123 456 78 | 9 012 345 6 | 78 901 234 | 567 890 12 |
+ *
+ * Octal side: 0 1 carry 3 4 carry ...
+ *
+ * Cycle number: 0 1 2
+ *
+ * But of course we are printing from the high side, so we have to
+ * figure out where in the cycle we are so that we end up with no
+ * left over bits at the end.
+ */
+#define BITS_IN_OCTAL 3
+#define HIGH_ZERO 0340
+#define LOW_ZERO 0016
+#define CARRY_ZERO 0003
+#define HIGH_ONE 0200
+#define MID_ONE 0160
+#define LOW_ONE 0016
+#define CARRY_ONE 0001
+#define HIGH_TWO 0300
+#define MID_TWO 0070
+#define LOW_TWO 0007
+
+ /* For 32 we start in cycle 2, with two bits and one bit carry;
+ * for 64 in cycle in cycle 1, with one bit and a two bit carry.
+ */
+ cycle = (len * BITS_IN_BYTES) % BITS_IN_OCTAL;
+ carry = 0;
+
+ fputs_filtered (local_octal_format_prefix (), stream);
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ for (p = valaddr;
+ p < valaddr + len;
+ p++)
+ {
+ switch (cycle)
+ {
+ case 0:
+ /* No carry in, carry out two bits.
+ */
+ octa1 = (HIGH_ZERO & *p) >> 5;
+ octa2 = (LOW_ZERO & *p) >> 2;
+ carry = (CARRY_ZERO & *p);
+ fprintf_filtered (stream, "%o", octa1);
+ fprintf_filtered (stream, "%o", octa2);
+ break;
+
+ case 1:
+ /* Carry in two bits, carry out one bit.
+ */
+ octa1 = (carry << 1) | ((HIGH_ONE & *p) >> 7);
+ octa2 = (MID_ONE & *p) >> 4;
+ octa3 = (LOW_ONE & *p) >> 1;
+ carry = (CARRY_ONE & *p);
+ fprintf_filtered (stream, "%o", octa1);
+ fprintf_filtered (stream, "%o", octa2);
+ fprintf_filtered (stream, "%o", octa3);
+ break;
+
+ case 2:
+ /* Carry in one bit, no carry out.
+ */
+ octa1 = (carry << 2) | ((HIGH_TWO & *p) >> 6);
+ octa2 = (MID_TWO & *p) >> 3;
+ octa3 = (LOW_TWO & *p);
+ carry = 0;
+ fprintf_filtered (stream, "%o", octa1);
+ fprintf_filtered (stream, "%o", octa2);
+ fprintf_filtered (stream, "%o", octa3);
+ break;
+
+ default:
+ error ("Internal error in octal conversion;");
+ }
+
+ cycle++;
+ cycle = cycle % BITS_IN_OCTAL;
+ }
+ }
+ else
+ {
+ for (p = valaddr + len - 1;
+ p >= valaddr;
+ p--)
+ {
+ switch (cycle)
+ {
+ case 0:
+ /* Carry out, no carry in */
+ octa1 = (HIGH_ZERO & *p) >> 5;
+ octa2 = (LOW_ZERO & *p) >> 2;
+ carry = (CARRY_ZERO & *p);
+ fprintf_filtered (stream, "%o", octa1);
+ fprintf_filtered (stream, "%o", octa2);
+ break;
+
+ case 1:
+ /* Carry in, carry out */
+ octa1 = (carry << 1) | ((HIGH_ONE & *p) >> 7);
+ octa2 = (MID_ONE & *p) >> 4;
+ octa3 = (LOW_ONE & *p) >> 1;
+ carry = (CARRY_ONE & *p);
+ fprintf_filtered (stream, "%o", octa1);
+ fprintf_filtered (stream, "%o", octa2);
+ fprintf_filtered (stream, "%o", octa3);
+ break;
+
+ case 2:
+ /* Carry in, no carry out */
+ octa1 = (carry << 2) | ((HIGH_TWO & *p) >> 6);
+ octa2 = (MID_TWO & *p) >> 3;
+ octa3 = (LOW_TWO & *p);
+ carry = 0;
+ fprintf_filtered (stream, "%o", octa1);
+ fprintf_filtered (stream, "%o", octa2);
+ fprintf_filtered (stream, "%o", octa3);
+ break;
+
+ default:
+ error ("Internal error in octal conversion;");
+ }
+
+ cycle++;
+ cycle = cycle % BITS_IN_OCTAL;
+ }
+ }
+
+ fputs_filtered (local_octal_format_suffix (), stream);
+}
+
+/* VALADDR points to an integer of LEN bytes.
+ * Print it in decimal on stream or format it in buf.
+ */
+void
+print_decimal_chars (struct ui_file *stream, unsigned char *valaddr,
+ unsigned len)
+{
+#define TEN 10
+#define TWO_TO_FOURTH 16
+#define CARRY_OUT( x ) ((x) / TEN) /* extend char to int */
+#define CARRY_LEFT( x ) ((x) % TEN)
+#define SHIFT( x ) ((x) << 4)
+#define START_P \
+ ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) ? valaddr : valaddr + len - 1)
+#define NOT_END_P \
+ ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) ? (p < valaddr + len) : (p >= valaddr))
+#define NEXT_P \
+ ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) ? p++ : p-- )
+#define LOW_NIBBLE( x ) ( (x) & 0x00F)
+#define HIGH_NIBBLE( x ) (((x) & 0x0F0) >> 4)
+
+ unsigned char *p;
+ unsigned char *digits;
+ int carry;
+ int decimal_len;
+ int i, j, decimal_digits;
+ int dummy;
+ int flip;
+
+ /* Base-ten number is less than twice as many digits
+ * as the base 16 number, which is 2 digits per byte.
+ */
+ decimal_len = len * 2 * 2;
+ digits = xmalloc (decimal_len);
+
+ for (i = 0; i < decimal_len; i++)
+ {
+ digits[i] = 0;
+ }
+
+ fputs_filtered (local_decimal_format_prefix (), stream);
+
+ /* Ok, we have an unknown number of bytes of data to be printed in
+ * decimal.
+ *
+ * Given a hex number (in nibbles) as XYZ, we start by taking X and
+ * decemalizing it as "x1 x2" in two decimal nibbles. Then we multiply
+ * the nibbles by 16, add Y and re-decimalize. Repeat with Z.
+ *
+ * The trick is that "digits" holds a base-10 number, but sometimes
+ * the individual digits are > 10.
+ *
+ * Outer loop is per nibble (hex digit) of input, from MSD end to
+ * LSD end.
+ */
+ decimal_digits = 0; /* Number of decimal digits so far */
+ p = START_P;
+ flip = 0;
+ while (NOT_END_P)
+ {
+ /*
+ * Multiply current base-ten number by 16 in place.
+ * Each digit was between 0 and 9, now is between
+ * 0 and 144.
+ */
+ for (j = 0; j < decimal_digits; j++)
+ {
+ digits[j] = SHIFT (digits[j]);
+ }
+
+ /* Take the next nibble off the input and add it to what
+ * we've got in the LSB position. Bottom 'digit' is now
+ * between 0 and 159.
+ *
+ * "flip" is used to run this loop twice for each byte.
+ */
+ if (flip == 0)
+ {
+ /* Take top nibble.
+ */
+ digits[0] += HIGH_NIBBLE (*p);
+ flip = 1;
+ }
+ else
+ {
+ /* Take low nibble and bump our pointer "p".
+ */
+ digits[0] += LOW_NIBBLE (*p);
+ NEXT_P;
+ flip = 0;
+ }
+
+ /* Re-decimalize. We have to do this often enough
+ * that we don't overflow, but once per nibble is
+ * overkill. Easier this way, though. Note that the
+ * carry is often larger than 10 (e.g. max initial
+ * carry out of lowest nibble is 15, could bubble all
+ * the way up greater than 10). So we have to do
+ * the carrying beyond the last current digit.
+ */
+ carry = 0;
+ for (j = 0; j < decimal_len - 1; j++)
+ {
+ digits[j] += carry;
+
+ /* "/" won't handle an unsigned char with
+ * a value that if signed would be negative.
+ * So extend to longword int via "dummy".
+ */
+ dummy = digits[j];
+ carry = CARRY_OUT (dummy);
+ digits[j] = CARRY_LEFT (dummy);
+
+ if (j >= decimal_digits && carry == 0)
+ {
+ /*
+ * All higher digits are 0 and we
+ * no longer have a carry.
+ *
+ * Note: "j" is 0-based, "decimal_digits" is
+ * 1-based.
+ */
+ decimal_digits = j + 1;
+ break;
+ }
+ }
+ }
+
+ /* Ok, now "digits" is the decimal representation, with
+ * the "decimal_digits" actual digits. Print!
+ */
+ for (i = decimal_digits - 1; i >= 0; i--)
+ {
+ fprintf_filtered (stream, "%1d", digits[i]);
+ }
+ xfree (digits);
+
+ fputs_filtered (local_decimal_format_suffix (), stream);
+}
+
+/* VALADDR points to an integer of LEN bytes. Print it in hex on stream. */
+
+void
+print_hex_chars (struct ui_file *stream, unsigned char *valaddr, unsigned len)
+{
+ unsigned char *p;
+
+ /* FIXME: We should be not printing leading zeroes in most cases. */
+
+ fputs_filtered (local_hex_format_prefix (), stream);
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ 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);
+ }
+ }
+ fputs_filtered (local_hex_format_suffix (), stream);
+}
+
+/* VALADDR points to a char integer of LEN bytes. Print it out in appropriate language form on stream.
+ Omit any leading zero chars. */
+
+void
+print_char_chars (struct ui_file *stream, unsigned char *valaddr, unsigned len)
+{
+ unsigned char *p;
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ p = valaddr;
+ while (p < valaddr + len - 1 && *p == 0)
+ ++p;
+
+ while (p < valaddr + len)
+ {
+ LA_EMIT_CHAR (*p, stream, '\'');
+ ++p;
+ }
+ }
+ else
+ {
+ p = valaddr + len - 1;
+ while (p > valaddr && *p == 0)
+ --p;
+
+ while (p >= valaddr)
+ {
+ LA_EMIT_CHAR (*p, stream, '\'');
+ --p;
+ }
+ }
+}
+
+/* Called by various <lang>_val_print routines to print elements of an
+ array in the form "<elem1>, <elem2>, <elem3>, ...".
+
+ (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 (struct type *type, char *valaddr, CORE_ADDR address,
+ struct ui_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, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ annotate_elt_rep (reps);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ annotate_elt_rep_end ();
+
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ }
+ else
+ {
+ val_print (elttype, valaddr + i * eltlen, 0, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ annotate_elt ();
+ things_printed++;
+ }
+ }
+ annotate_array_section_end ();
+ if (i < len)
+ {
+ fprintf_filtered (stream, "...");
+ }
+}
+
+/* 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. */
+
+/* FIXME: cagney/1999-10-14: Only used by val_print_string. Can this
+ function be eliminated. */
+
+static int
+partial_memory_read (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_read_memory (memaddr, myaddr, len);
+ 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_read_memory (memaddr++, myaddr++, 1);
+ }
+ /* If an error, the last read was unsuccessful, so adjust count. */
+ if (errcode != 0)
+ {
+ nread--;
+ }
+ }
+ if (errnoptr != NULL)
+ {
+ *errnoptr = errcode;
+ }
+ return (nread);
+}
+
+/* Print a string from the inferior, starting at ADDR and printing up to LEN
+ characters, of WIDTH bytes a piece, to STREAM. If LEN is -1, 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: Use target_read_string. */
+
+int
+val_print_string (CORE_ADDR addr, int len, int width, struct ui_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 chars to print. */
+ unsigned int nfetch; /* Chars to fetch / chars fetched. */
+ unsigned int chunksize; /* Size of each fetch, in chars. */
+ 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. */
+ int found_nul; /* Non-zero if we found the nul 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 >= zero, then the limit is the minimum of LEN and print_max. If
+ LEN is -1, 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 == -1 ? 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 >= zero, then we want fetchlimit chars,
+ so we might as well read them all in one operation. If LEN is -1, 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 == -1 ? 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. */
+
+ found_nul = 0;
+ old_chain = make_cleanup (null_cleanup, 0);
+
+ if (len > 0)
+ {
+ buffer = (char *) xmalloc (len * width);
+ bufptr = buffer;
+ old_chain = make_cleanup (xfree, buffer);
+
+ nfetch = partial_memory_read (addr, bufptr, len * width, &errcode)
+ / width;
+ addr += nfetch * width;
+ bufptr += nfetch * width;
+ }
+ else if (len == -1)
+ {
+ unsigned long bufsize = 0;
+ do
+ {
+ QUIT;
+ nfetch = min (chunksize, fetchlimit - bufsize);
+
+ if (buffer == NULL)
+ buffer = (char *) xmalloc (nfetch * width);
+ else
+ {
+ discard_cleanups (old_chain);
+ buffer = (char *) xrealloc (buffer, (nfetch + bufsize) * width);
+ }
+
+ old_chain = make_cleanup (xfree, buffer);
+ bufptr = buffer + bufsize * width;
+ bufsize += nfetch;
+
+ /* Read as much as we can. */
+ nfetch = partial_memory_read (addr, bufptr, nfetch * width, &errcode)
+ / width;
+
+ /* 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 * width;
+ while (bufptr < limit)
+ {
+ unsigned long c;
+
+ c = extract_unsigned_integer (bufptr, width);
+ addr += width;
+ bufptr += width;
+ if (c == 0)
+ {
+ /* We don't care about any error which happened after
+ the NULL terminator. */
+ errcode = 0;
+ found_nul = 1;
+ break;
+ }
+ }
+ }
+ while (errcode == 0 /* no error */
+ && bufptr - buffer < fetchlimit * width /* no overrun */
+ && !found_nul); /* haven't found nul yet */
+ }
+ else
+ { /* length of string is really 0! */
+ buffer = bufptr = NULL;
+ errcode = 0;
+ }
+
+ /* 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 char when LEN is -1. */
+
+ if (len == -1 && !found_nul)
+ {
+ char *peekbuf;
+
+ /* 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. */
+
+ peekbuf = (char *) alloca (width);
+
+ if (target_read_memory (addr, peekbuf, width) == 0
+ && extract_unsigned_integer (peekbuf, width) != 0)
+ force_ellipsis = 1;
+ }
+ else if ((len >= 0 && errcode != 0) || (len > (bufptr - buffer) / width))
+ {
+ /* 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) / width, width, force_ellipsis);
+ }
+
+ if (errcode != 0)
+ {
+ if (errcode == EIO)
+ {
+ fprintf_filtered (stream, " <Address ");
+ print_address_numeric (addr, 1, stream);
+ fprintf_filtered (stream, " out of bounds>");
+ }
+ else
+ {
+ fprintf_filtered (stream, " <Error reading address ");
+ print_address_numeric (addr, 1, stream);
+ fprintf_filtered (stream, ": %s>", safe_strerror (errcode));
+ }
+ }
+ gdb_flush (stream);
+ do_cleanups (old_chain);
+ return ((bufptr - buffer) / width);
+}
+
+
+/* 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! */
+
+static void
+set_input_radix (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_input_radix_1 (from_tty, input_radix);
+}
+
+static void
+set_input_radix_1 (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)
+ {
+ /* FIXME: cagney/2002-03-17: This needs to revert the bad radix
+ value. */
+ 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);
+ }
+}
+
+static void
+set_output_radix (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_output_radix_1 (from_tty, output_radix);
+}
+
+static void
+set_output_radix_1 (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:
+ /* FIXME: cagney/2002-03-17: This needs to revert the bad radix
+ value. */
+ 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 (char *arg, int from_tty)
+{
+ unsigned radix;
+
+ radix = (arg == NULL) ? 10 : parse_and_eval_long (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. */
+
+static void
+show_radix (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);
+ }
+ }
+}
+
+
+static void
+set_print (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);
+}
+
+static void
+show_print (char *args, int from_tty)
+{
+ cmd_show_list (showprintlist, from_tty, "");
+}
+
+void
+_initialize_valprint (void)
+{
+ 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);
+ set_cmd_sfunc (c, 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);
+ set_cmd_sfunc (c, 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 0000000..647b4bd
--- /dev/null
+++ b/contrib/gdb/gdb/valprint.h
@@ -0,0 +1,72 @@
+/* Declarations for value printing routines for GDB, the GNU debugger.
+ Copyright 1986, 1988, 1989, 1991-1994, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 VALPRINT_H
+#define VALPRINT_H
+
+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 */
+
+/* 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. */
+extern int inspect_it;
+
+/* 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. */
+extern unsigned int repeat_count_threshold;
+
+extern int output_format;
+
+extern int stop_print_at_null; /* Stop printing at null char? */
+
+extern void val_print_array_elements (struct type *, char *, CORE_ADDR,
+ struct ui_file *, int, int, int,
+ enum val_prettyprint, unsigned int);
+
+extern void val_print_type_code_int (struct type *, char *,
+ struct ui_file *);
+
+extern void print_binary_chars (struct ui_file *, unsigned char *,
+ unsigned int);
+
+extern void print_octal_chars (struct ui_file *, unsigned char *,
+ unsigned int);
+
+extern void print_decimal_chars (struct ui_file *, unsigned char *,
+ unsigned int);
+
+extern void print_hex_chars (struct ui_file *, unsigned char *,
+ unsigned int);
+
+extern void print_char_chars (struct ui_file *, unsigned char *,
+ unsigned int);
+#endif
diff --git a/contrib/gdb/gdb/value.h b/contrib/gdb/gdb/value.h
new file mode 100644
index 0000000..690edb9
--- /dev/null
+++ b/contrib/gdb/gdb/value.h
@@ -0,0 +1,569 @@
+/* Definitions for values of C expressions, for GDB.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+#include "doublest.h"
+#include "frame.h" /* For struct frame_id. */
+
+struct block;
+struct expression;
+struct regcache;
+struct symbol;
+struct type;
+struct ui_file;
+
+/* 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 (i.e. to be put into the history list or an internal
+ variable). */
+
+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
+ {
+ /* If lval == lval_memory, this is the address in the inferior.
+ If lval == lval_register, this is the byte offset into the
+ 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 of a structure in bytes.
+ If lval == lval_memory, this is an offset to the address.
+ If lval == lval_register, this is a further offset from
+ location.address within the registers structure.
+ Note also the member embedded_offset below. */
+ 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 ID 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". */
+ struct frame_id frame_id;
+
+ /* Type of the value. */
+ struct type *type;
+
+ /* If a value represents a C++ object, then the `type' field gives
+ the object's compile-time type. If the object actually belongs
+ to some class derived from `type', perhaps with other base
+ classes and additional members, then `type' is just a subobject
+ of the real thing, and the full object is probably larger than
+ `type' would suggest.
+
+ If `type' is a dynamic class (i.e. one with a vtable), then GDB
+ can actually determine the object's run-time type by looking at
+ the run-time type information in the vtable. When this
+ information is available, we may elect to read in the entire
+ object, for several reasons:
+
+ - When printing the value, the user would probably rather see the
+ full object, not just the limited portion apparent from the
+ compile-time type.
+
+ - If `type' has virtual base classes, then even printing `type'
+ alone may require reaching outside the `type' portion of the
+ object to wherever the virtual base class has been stored.
+
+ When we store the entire object, `enclosing_type' is the run-time
+ type -- the complete object -- and `embedded_offset' is the
+ offset of `type' within that larger type, in bytes. The
+ VALUE_CONTENTS macro takes `embedded_offset' into account, so
+ most GDB code continues to see the `type' portion of the value,
+ just as the inferior would.
+
+ If `type' is a pointer to an object, then `enclosing_type' is a
+ pointer to the object's run-time type, and `pointed_to_offset' is
+ the offset in bytes from the full object to the pointed-to object
+ -- that is, the value `embedded_offset' would have if we
+ followed the pointer and fetched the complete object. (I don't
+ really see the point. Why not just determine the run-time type
+ when you indirect, and avoid the special case? The contents
+ don't matter until you indirect anyway.)
+
+ If we're not doing anything fancy, `enclosing_type' is equal to
+ `type', and `embedded_offset' is zero, so everything works
+ normally. */
+ struct type *enclosing_type;
+ int embedded_offset;
+ int pointed_to_offset;
+
+ /* 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;
+
+ /* Register number if the value is from a register. */
+ 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).
+
+ WARNING: This field is used by the code which handles
+ watchpoints (see breakpoint.c) to decide whether a particular
+ value can be watched by hardware watchpoints. If the lazy flag
+ is set for some member of a value chain, it is assumed that
+ this member of the chain doesn't need to be watched as part of
+ watching the value itself. This is how GDB avoids watching the
+ entire struct or array when the user wants to watch a single
+ struct member or array element. If you ever change the way
+ lazy flag is set and reset, be sure to consider this use as
+ well! */
+ char lazy;
+
+ /* If nonzero, this is the value of a variable which does not
+ actually exist in the program. */
+ char optimized_out;
+
+ /* The BFD section associated with this value. */
+ asection *bfd_section;
+
+ /* 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. Note that a value therefore extends beyond
+ what is declared here. */
+ union
+ {
+ long contents[1];
+ DOUBLEST force_doublest_align;
+ LONGEST force_longest_align;
+ CORE_ADDR force_core_addr_align;
+ void *force_pointer_align;
+ } aligner;
+ /* Do not add any new members here -- contents above will trash them. */
+};
+
+#define VALUE_TYPE(val) (val)->type
+#define VALUE_ENCLOSING_TYPE(val) (val)->enclosing_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.
+
+ Note: The contents pointer is adjusted by the offset required to
+ get to the real subobject, if the value happens to represent
+ something embedded in a larger run-time object. */
+
+#define VALUE_CONTENTS_RAW(val) \
+ ((char *) (val)->aligner.contents + (val)->embedded_offset)
+#define VALUE_CONTENTS(val) \
+ ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)), VALUE_CONTENTS_RAW(val))
+
+/* The ALL variants of the above two macros do not adjust the returned
+ pointer by the embedded_offset value. */
+
+#define VALUE_CONTENTS_ALL_RAW(val) ((char *) (val)->aligner.contents)
+#define VALUE_CONTENTS_ALL(val) \
+ ((void) (VALUE_LAZY(val) && value_fetch_lazy(val)), \
+ VALUE_CONTENTS_ALL_RAW(val))
+
+extern int value_fetch_lazy (struct value *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_ID(val) ((val)->frame_id)
+#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)
+#define VALUE_EMBEDDED_OFFSET(val) ((val)->embedded_offset)
+#define VALUE_POINTED_TO_OFFSET(val) ((val)->pointed_to_offset)
+#define VALUE_BFD_SECTION(val) ((val)->bfd_section)
+
+/* Convert a REF to the object referenced. */
+
+#define COERCE_REF(arg) \
+ do { \
+ struct type *value_type_arg_tmp = check_typedef (VALUE_TYPE (arg)); \
+ if (TYPE_CODE (value_type_arg_tmp) == TYPE_CODE_REF) \
+ arg = value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp), \
+ unpack_pointer (VALUE_TYPE (arg), \
+ VALUE_CONTENTS (arg)), \
+ VALUE_BFD_SECTION (arg)); \
+ } while (0)
+
+/* 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)
+
+/* NOTE: cagney/2002-12-17: This macro was handling a chill language
+ problem but that language has gone away. */
+#define COERCE_VARYING_ARRAY(arg, real_arg_type)
+
+/* If ARG is an enum, convert it to an integer. */
+
+#define COERCE_ENUM(arg) \
+ do { \
+ if (TYPE_CODE (check_typedef (VALUE_TYPE (arg))) == TYPE_CODE_ENUM) \
+ arg = value_cast (builtin_type_unsigned_int, arg); \
+ } while (0)
+
+/* Internal variables (variables for convenience of use of debugger)
+ are recorded as a chain of these structures. */
+
+struct internalvar
+{
+ struct internalvar *next;
+ char *name;
+ struct value *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"
+
+struct frame_info;
+struct fn_field;
+
+extern void print_address_demangle (CORE_ADDR, struct ui_file *, int);
+
+extern LONGEST value_as_long (struct value *val);
+extern DOUBLEST value_as_double (struct value *val);
+extern CORE_ADDR value_as_address (struct value *val);
+
+extern LONGEST unpack_long (struct type *type, const char *valaddr);
+extern DOUBLEST unpack_double (struct type *type, const char *valaddr,
+ int *invp);
+extern CORE_ADDR unpack_pointer (struct type *type, const char *valaddr);
+extern LONGEST unpack_field_as_long (struct type *type, const char *valaddr,
+ int fieldno);
+
+extern struct value *value_from_longest (struct type *type, LONGEST num);
+extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr);
+extern struct value *value_from_double (struct type *type, DOUBLEST num);
+extern struct value *value_from_string (char *string);
+
+extern struct value *value_at (struct type *type, CORE_ADDR addr,
+ asection * sect);
+extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr,
+ asection * sect);
+
+extern struct value *value_from_register (struct type *type, int regnum,
+ struct frame_info *frame);
+
+extern struct value *value_of_variable (struct symbol *var, struct block *b);
+
+extern struct value *value_of_register (int regnum,
+ struct frame_info *frame);
+
+extern int symbol_read_needs_frame (struct symbol *);
+
+extern struct value *read_var_value (struct symbol *var,
+ struct frame_info *frame);
+
+extern struct value *locate_var_value (struct symbol *var,
+ struct frame_info *frame);
+
+extern struct value *allocate_value (struct type *type);
+
+extern struct value *allocate_repeat_value (struct type *type, int count);
+
+extern struct value *value_change_enclosing_type (struct value *val,
+ struct type *new_type);
+
+extern struct value *value_mark (void);
+
+extern void value_free_to_mark (struct value *mark);
+
+extern struct value *value_string (char *ptr, int len);
+extern struct value *value_bitstring (char *ptr, int len);
+
+extern struct value *value_array (int lowbound, int highbound,
+ struct value ** elemvec);
+
+extern struct value *value_concat (struct value *arg1, struct value *arg2);
+
+extern struct value *value_binop (struct value *arg1, struct value *arg2,
+ enum exp_opcode op);
+
+extern struct value *value_add (struct value *arg1, struct value *arg2);
+
+extern struct value *value_sub (struct value *arg1, struct value *arg2);
+
+extern struct value *value_coerce_array (struct value *arg1);
+
+extern struct value *value_coerce_function (struct value *arg1);
+
+extern struct value *value_ind (struct value *arg1);
+
+extern struct value *value_addr (struct value *arg1);
+
+extern struct value *value_assign (struct value *toval, struct value *fromval);
+
+extern struct value *value_neg (struct value *arg1);
+
+extern struct value *value_complement (struct value *arg1);
+
+extern struct value *value_struct_elt (struct value **argp,
+ struct value **args,
+ char *name, int *static_memfuncp,
+ char *err);
+
+extern struct value *value_aggregate_elt (struct type *curtype,
+ char *name,
+ enum noside noside);
+
+extern struct value *value_static_field (struct type *type, int fieldno);
+
+extern struct fn_field *value_find_oload_method_list (struct value **, char *,
+ int, int *,
+ struct type **, int *);
+
+extern int find_overload_match (struct type **arg_types, int nargs,
+ char *name, int method, int lax,
+ struct value **objp, struct symbol *fsym,
+ struct value **valp, struct symbol **symp,
+ int *staticp);
+
+extern struct value *value_field (struct value *arg1, int fieldno);
+
+extern struct value *value_primitive_field (struct value *arg1, int offset,
+ int fieldno,
+ struct type *arg_type);
+
+
+extern struct type *value_rtti_target_type (struct value *, int *, int *,
+ int *);
+
+extern struct value *value_full_object (struct value *, struct type *, int,
+ int, int);
+
+extern struct value *value_cast (struct type *type, struct value *arg2);
+
+extern struct value *value_zero (struct type *type, enum lval_type lv);
+
+extern struct value *value_repeat (struct value *arg1, int count);
+
+extern struct value *value_subscript (struct value *array, struct value *idx);
+
+extern struct value *register_value_being_returned (struct type *valtype,
+ struct regcache *retbuf);
+
+extern struct value *value_in (struct value *element, struct value *set);
+
+extern int value_bit_index (struct type *type, char *addr, int index);
+
+extern int using_struct_return (struct type *value_type, int gcc_p);
+
+extern struct value *evaluate_expression (struct expression *exp);
+
+extern struct value *evaluate_type (struct expression *exp);
+
+extern struct value *evaluate_subexp_with_coercion (struct expression *,
+ int *, enum noside);
+
+extern struct value *parse_and_eval (char *exp);
+
+extern struct value *parse_to_comma_and_eval (char **expp);
+
+extern struct type *parse_and_eval_type (char *p, int length);
+
+extern CORE_ADDR parse_and_eval_address (char *exp);
+
+extern CORE_ADDR parse_and_eval_address_1 (char **expptr);
+
+extern LONGEST parse_and_eval_long (char *exp);
+
+extern struct value *access_value_history (int num);
+
+extern struct value *value_of_internalvar (struct internalvar *var);
+
+extern void set_internalvar (struct internalvar *var, struct value *val);
+
+extern void set_internalvar_component (struct internalvar *var,
+ int offset,
+ int bitpos, int bitsize,
+ struct value *newvalue);
+
+extern struct internalvar *lookup_internalvar (char *name);
+
+extern int value_equal (struct value *arg1, struct value *arg2);
+
+extern int value_less (struct value *arg1, struct value *arg2);
+
+extern int value_logical_not (struct value *arg1);
+
+/* C++ */
+
+extern struct value *value_of_this (int complain);
+
+extern struct value *value_x_binop (struct value *arg1, struct value *arg2,
+ enum exp_opcode op,
+ enum exp_opcode otherop,
+ enum noside noside);
+
+extern struct value *value_x_unop (struct value *arg1, enum exp_opcode op,
+ enum noside noside);
+
+extern struct value *value_fn_field (struct value ** arg1p, struct fn_field *f,
+ int j, struct type *type, int offset);
+
+extern int binop_user_defined_p (enum exp_opcode op, struct value *arg1,
+ struct value *arg2);
+
+extern int unop_user_defined_p (enum exp_opcode op, struct value *arg1);
+
+extern int destructor_name_p (const char *name, const struct type *type);
+
+#define value_free(val) xfree (val)
+
+extern void free_all_values (void);
+
+extern void release_value (struct value *val);
+
+extern int record_latest_value (struct value *val);
+
+extern void modify_field (char *addr, LONGEST fieldval, int bitpos,
+ int bitsize);
+
+extern void type_print (struct type * type, char *varstring,
+ struct ui_file * stream, int show);
+
+extern char *baseclass_addr (struct type *type, int index, char *valaddr,
+ struct value **valuep, int *errp);
+
+extern void print_longest (struct ui_file * stream, int format,
+ int use_local, LONGEST val);
+
+extern void print_floating (char *valaddr, struct type * type,
+ struct ui_file * stream);
+
+extern int value_print (struct value *val, struct ui_file *stream, int format,
+ enum val_prettyprint pretty);
+
+extern void value_print_array_elements (struct value *val,
+ struct ui_file *stream, int format,
+ enum val_prettyprint pretty);
+
+extern struct value *value_release_to_mark (struct value *mark);
+
+extern int val_print (struct type * type, char *valaddr,
+ int embedded_offset, CORE_ADDR address,
+ struct ui_file * stream, int format,
+ int deref_ref, int recurse,
+ enum val_prettyprint pretty);
+
+extern int val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream);
+
+extern void print_variable_value (struct symbol * var,
+ struct frame_info * frame,
+ struct ui_file *stream);
+
+extern int check_field (struct value *, const char *);
+
+extern void typedef_print (struct type * type, struct symbol * news,
+ struct ui_file * stream);
+
+extern char *internalvar_name (struct internalvar *var);
+
+extern void clear_value_history (void);
+
+extern void clear_internalvars (void);
+
+/* From values.c */
+
+extern struct value *value_copy (struct value *);
+
+/* From valops.c */
+
+extern struct value *varying_to_slice (struct value *);
+
+extern struct value *value_slice (struct value *, int, int);
+
+extern struct value *value_literal_complex (struct value *, struct value *,
+ struct type *);
+
+extern void find_rt_vbase_offset (struct type *, struct type *, char *, int,
+ int *, int *);
+
+extern struct value *find_function_in_inferior (const char *);
+
+extern struct value *value_allocate_space_in_inferior (int);
+
+extern CORE_ADDR legacy_push_arguments (int nargs, struct value ** args,
+ CORE_ADDR sp, int struct_return,
+ CORE_ADDR struct_addr);
+
+extern struct value *value_of_local (const char *name, int complain);
+
+#endif /* !defined (VALUE_H) */
diff --git a/contrib/gdb/gdb/values.c b/contrib/gdb/gdb/values.c
new file mode 100644
index 0000000..87baf21
--- /dev/null
+++ b/contrib/gdb/gdb/values.c
@@ -0,0 +1,1329 @@
+/* Low level packing and unpacking of values for GDB, the GNU Debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "command.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "language.h"
+#include "scm-lang.h"
+#include "demangle.h"
+#include "doublest.h"
+#include "gdb_assert.h"
+#include "regcache.h"
+#include "block.h"
+
+/* Prototypes for exported functions. */
+
+void _initialize_values (void);
+
+/* Prototypes for local functions. */
+
+static void show_values (char *, int);
+
+static void show_convenience (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;
+ struct value *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 struct value *all_values;
+
+/* Allocate a value that has the correct length for type TYPE. */
+
+struct value *
+allocate_value (struct type *type)
+{
+ struct value *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_ENCLOSING_TYPE (val) = type;
+ VALUE_LVAL (val) = not_lval;
+ VALUE_ADDRESS (val) = 0;
+ VALUE_FRAME_ID (val) = null_frame_id;
+ 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;
+ VALUE_BFD_SECTION (val) = NULL;
+ VALUE_EMBEDDED_OFFSET (val) = 0;
+ VALUE_POINTED_TO_OFFSET (val) = 0;
+ val->modifiable = 1;
+ return val;
+}
+
+/* Allocate a value that has the correct length
+ for COUNT repetitions type TYPE. */
+
+struct value *
+allocate_repeat_value (struct type *type, int count)
+{
+ int low_bound = current_language->string_lower_bound; /* ??? */
+ /* FIXME-type-allocation: need a way to free this type when we are
+ done with it. */
+ struct type *range_type
+ = create_range_type ((struct type *) NULL, builtin_type_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. */
+struct value *
+value_mark (void)
+{
+ return all_values;
+}
+
+/* Free all values allocated since MARK was obtained by value_mark
+ (except for those released). */
+void
+value_free_to_mark (struct value *mark)
+{
+ struct value *val;
+ struct value *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 (void)
+{
+ struct value *val;
+ struct value *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 (struct value *val)
+{
+ struct value *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 */
+struct value *
+value_release_to_mark (struct value *mark)
+{
+ struct value *val;
+ struct value *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. */
+
+struct value *
+value_copy (struct value *arg)
+{
+ struct type *encl_type = VALUE_ENCLOSING_TYPE (arg);
+ struct value *val = allocate_value (encl_type);
+ VALUE_TYPE (val) = VALUE_TYPE (arg);
+ 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_ID (val) = VALUE_FRAME_ID (arg);
+ VALUE_REGNO (val) = VALUE_REGNO (arg);
+ VALUE_LAZY (val) = VALUE_LAZY (arg);
+ VALUE_OPTIMIZED_OUT (val) = VALUE_OPTIMIZED_OUT (arg);
+ VALUE_EMBEDDED_OFFSET (val) = VALUE_EMBEDDED_OFFSET (arg);
+ VALUE_POINTED_TO_OFFSET (val) = VALUE_POINTED_TO_OFFSET (arg);
+ VALUE_BFD_SECTION (val) = VALUE_BFD_SECTION (arg);
+ val->modifiable = arg->modifiable;
+ if (!VALUE_LAZY (val))
+ {
+ memcpy (VALUE_CONTENTS_ALL_RAW (val), VALUE_CONTENTS_ALL_RAW (arg),
+ TYPE_LENGTH (VALUE_ENCLOSING_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 (struct value *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)
+ {
+ 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. */
+
+struct value *
+access_value_history (int num)
+{
+ struct value_history_chunk *chunk;
+ int i;
+ 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 (void)
+{
+ struct value_history_chunk *next;
+ int i;
+ struct value *val;
+
+ while (value_history_chain)
+ {
+ for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
+ if ((val = value_history_chain->values[i]) != NULL)
+ xfree (val);
+ next = value_history_chain->next;
+ xfree (value_history_chain);
+ value_history_chain = next;
+ }
+ value_history_count = 0;
+}
+
+static void
+show_values (char *num_exp, int from_tty)
+{
+ int i;
+ struct value *val;
+ static int num = 1;
+
+ if (num_exp)
+ {
+ /* "info history +" should print from the stored position.
+ "info history <exp>" should print around value number <exp>. */
+ if (num_exp[0] != '+' || num_exp[1] != '\0')
+ num = parse_and_eval_long (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 (char *name)
+{
+ struct internalvar *var;
+
+ for (var = internalvars; var; var = var->next)
+ if (strcmp (var->name, name) == 0)
+ 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;
+}
+
+struct value *
+value_of_internalvar (struct internalvar *var)
+{
+ struct value *val;
+
+ 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 (struct internalvar *var, int offset, int bitpos,
+ int bitsize, struct value *newval)
+{
+ char *addr = VALUE_CONTENTS (var->value) + offset;
+
+ 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 (struct internalvar *var, struct value *val)
+{
+ struct value *newval;
+
+ 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. */
+ xfree (var->value);
+ var->value = newval;
+ release_value (newval);
+ /* End code which must not call error(). */
+}
+
+char *
+internalvar_name (struct internalvar *var)
+{
+ return var->name;
+}
+
+/* Free all internalvars. Done when new symtabs are loaded,
+ because that makes the values invalid. */
+
+void
+clear_internalvars (void)
+{
+ struct internalvar *var;
+
+ while (internalvars)
+ {
+ var = internalvars;
+ internalvars = var->next;
+ xfree (var->name);
+ xfree (var->value);
+ xfree (var);
+ }
+}
+
+static void
+show_convenience (char *ignore, int from_tty)
+{
+ struct internalvar *var;
+ int varseen = 0;
+
+ for (var = internalvars; var; var = var->next)
+ {
+ 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 (struct value *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 (struct value *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.
+ Note that val's type may not actually be a pointer; value_as_long
+ handles all the cases. */
+CORE_ADDR
+value_as_address (struct value *val)
+{
+ /* 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
+
+ /* There are several targets (IA-64, PowerPC, and others) which
+ don't represent pointers to functions as simply the address of
+ the function's entry point. For example, on the IA-64, a
+ function pointer points to a two-word descriptor, generated by
+ the linker, which contains the function's entry point, and the
+ value the IA-64 "global pointer" register should have --- to
+ support position-independent code. The linker generates
+ descriptors only for those functions whose addresses are taken.
+
+ On such targets, it's difficult for GDB to convert an arbitrary
+ function address into a function pointer; it has to either find
+ an existing descriptor for that function, or call malloc and
+ build its own. On some targets, it is impossible for GDB to
+ build a descriptor at all: the descriptor must contain a jump
+ instruction; data memory cannot be executed; and code memory
+ cannot be modified.
+
+ Upon entry to this function, if VAL is a value of type `function'
+ (that is, TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC), then
+ VALUE_ADDRESS (val) is the address of the function. This is what
+ you'll get if you evaluate an expression like `main'. The call
+ to COERCE_ARRAY below actually does all the usual unary
+ conversions, which includes converting values of type `function'
+ to `pointer to function'. This is the challenging conversion
+ discussed above. Then, `unpack_long' will convert that pointer
+ back into an address.
+
+ So, suppose the user types `disassemble foo' on an architecture
+ with a strange function pointer representation, on which GDB
+ cannot build its own descriptors, and suppose further that `foo'
+ has no linker-built descriptor. The address->pointer conversion
+ will signal an error and prevent the command from running, even
+ though the next step would have been to convert the pointer
+ directly back into the same address.
+
+ The following shortcut avoids this whole mess. If VAL is a
+ function, just return its address directly. */
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_METHOD)
+ return VALUE_ADDRESS (val);
+
+ COERCE_ARRAY (val);
+
+ /* Some architectures (e.g. Harvard), map instruction and data
+ addresses onto a single large unified address space. For
+ instance: An architecture may consider a large integer in the
+ range 0x10000000 .. 0x1000ffff to already represent a data
+ addresses (hence not need a pointer to address conversion) while
+ a small integer would still need to be converted integer to
+ pointer to address. Just assume such architectures handle all
+ integer conversions in a single function. */
+
+ /* JimB writes:
+
+ I think INTEGER_TO_ADDRESS is a good idea as proposed --- but we
+ must admonish GDB hackers to make sure its behavior matches the
+ compiler's, whenever possible.
+
+ In general, I think GDB should evaluate expressions the same way
+ the compiler does. When the user copies an expression out of
+ their source code and hands it to a `print' command, they should
+ get the same value the compiler would have computed. Any
+ deviation from this rule can cause major confusion and annoyance,
+ and needs to be justified carefully. In other words, GDB doesn't
+ really have the freedom to do these conversions in clever and
+ useful ways.
+
+ AndrewC pointed out that users aren't complaining about how GDB
+ casts integers to pointers; they are complaining that they can't
+ take an address from a disassembly listing and give it to `x/i'.
+ This is certainly important.
+
+ Adding an architecture method like INTEGER_TO_ADDRESS certainly
+ makes it possible for GDB to "get it right" in all circumstances
+ --- the target has complete control over how things get done, so
+ people can Do The Right Thing for their target without breaking
+ anyone else. The standard doesn't specify how integers get
+ converted to pointers; usually, the ABI doesn't either, but
+ ABI-specific code is a more reasonable place to handle it. */
+
+ if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_PTR
+ && TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_REF
+ && INTEGER_TO_ADDRESS_P ())
+ return INTEGER_TO_ADDRESS (VALUE_TYPE (val), VALUE_CONTENTS (val));
+
+ return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (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 (struct type *type, const char *valaddr)
+{
+ enum type_code code = TYPE_CODE (type);
+ int len = TYPE_LENGTH (type);
+ 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_typed_floating (valaddr, type);
+
+ 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_typed_address (valaddr, type);
+
+ 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 (struct type *type, const char *valaddr, int *invp)
+{
+ enum type_code code;
+ int len;
+ int nosign;
+
+ *invp = 0; /* Assume valid. */
+ CHECK_TYPEDEF (type);
+ code = TYPE_CODE (type);
+ len = TYPE_LENGTH (type);
+ nosign = TYPE_UNSIGNED (type);
+ if (code == TYPE_CODE_FLT)
+ {
+ /* NOTE: cagney/2002-02-19: There was a test here to see if the
+ floating-point value was valid (using the macro
+ INVALID_FLOAT). That test/macro have been removed.
+
+ It turns out that only the VAX defined this macro and then
+ only in a non-portable way. Fixing the portability problem
+ wouldn't help since the VAX floating-point code is also badly
+ bit-rotten. The target needs to add definitions for the
+ methods TARGET_FLOAT_FORMAT and TARGET_DOUBLE_FORMAT - these
+ exactly describe the target floating-point format. The
+ problem here is that the corresponding floatformat_vax_f and
+ floatformat_vax_d values these methods should be set to are
+ also not defined either. Oops!
+
+ Hopefully someone will add both the missing floatformat
+ definitions and the new cases for floatformat_is_valid (). */
+
+ if (!floatformat_is_valid (floatformat_from_type (type), valaddr))
+ {
+ *invp = 1;
+ return 0.0;
+ }
+
+ return extract_typed_floating (valaddr, type);
+ }
+ else if (nosign)
+ {
+ /* Unsigned -- be sure we compensate for signed LONGEST. */
+ return (ULONGEST) 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_address() 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 (struct type *type, const 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);
+}
+
+
+/* Get the value of the FIELDN'th field (which must be static) of
+ TYPE. Return NULL if the field doesn't exist or has been
+ optimized out. */
+
+struct value *
+value_static_field (struct type *type, int fieldno)
+{
+ struct value *retval;
+
+ if (TYPE_FIELD_STATIC_HAS_ADDR (type, fieldno))
+ {
+ retval = value_at (TYPE_FIELD_TYPE (type, fieldno),
+ TYPE_FIELD_STATIC_PHYSADDR (type, fieldno),
+ NULL);
+ }
+ else
+ {
+ char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
+ struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0, NULL);
+ if (sym == NULL)
+ {
+ /* With some compilers, e.g. HP aCC, static data members are reported
+ as non-debuggable symbols */
+ struct minimal_symbol *msym = lookup_minimal_symbol (phys_name, NULL, NULL);
+ if (!msym)
+ return NULL;
+ else
+ {
+ retval = value_at (TYPE_FIELD_TYPE (type, fieldno),
+ SYMBOL_VALUE_ADDRESS (msym),
+ SYMBOL_BFD_SECTION (msym));
+ }
+ }
+ else
+ {
+ /* SYM should never have a SYMBOL_CLASS which will require
+ read_var_value to use the FRAME parameter. */
+ if (symbol_read_needs_frame (sym))
+ warning ("static field's value depends on the current "
+ "frame - bad debug info?");
+ retval = read_var_value (sym, NULL);
+ }
+ if (retval && VALUE_LVAL (retval) == lval_memory)
+ SET_FIELD_PHYSADDR (TYPE_FIELD (type, fieldno),
+ VALUE_ADDRESS (retval));
+ }
+ return retval;
+}
+
+/* Change the enclosing type of a value object VAL to NEW_ENCL_TYPE.
+ You have to be careful here, since the size of the data area for the value
+ is set by the length of the enclosing type. So if NEW_ENCL_TYPE is bigger
+ than the old enclosing type, you have to allocate more space for the data.
+ The return value is a pointer to the new version of this value structure. */
+
+struct value *
+value_change_enclosing_type (struct value *val, struct type *new_encl_type)
+{
+ if (TYPE_LENGTH (new_encl_type) <= TYPE_LENGTH (VALUE_ENCLOSING_TYPE (val)))
+ {
+ VALUE_ENCLOSING_TYPE (val) = new_encl_type;
+ return val;
+ }
+ else
+ {
+ struct value *new_val;
+ struct value *prev;
+
+ new_val = (struct value *) xrealloc (val, sizeof (struct value) + TYPE_LENGTH (new_encl_type));
+
+ VALUE_ENCLOSING_TYPE (new_val) = new_encl_type;
+
+ /* We have to make sure this ends up in the same place in the value
+ chain as the original copy, so it's clean-up behavior is the same.
+ If the value has been released, this is a waste of time, but there
+ is no way to tell that in advance, so... */
+
+ if (val != all_values)
+ {
+ for (prev = all_values; prev != NULL; prev = prev->next)
+ {
+ if (prev->next == val)
+ {
+ prev->next = new_val;
+ break;
+ }
+ }
+ }
+
+ return new_val;
+ }
+}
+
+/* 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 (non-static) fields.
+ FIELDNO says which field. */
+
+struct value *
+value_primitive_field (struct value *arg1, int offset,
+ int fieldno, struct type *arg_type)
+{
+ struct value *v;
+ struct type *type;
+
+ CHECK_TYPEDEF (arg_type);
+ type = TYPE_FIELD_TYPE (arg_type, fieldno);
+
+ /* Handle packed fields */
+
+ if (TYPE_FIELD_BITSIZE (arg_type, fieldno))
+ {
+ v = value_from_longest (type,
+ unpack_field_as_long (arg_type,
+ VALUE_CONTENTS (arg1)
+ + offset,
+ fieldno));
+ VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8;
+ VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (arg_type, fieldno);
+ VALUE_OFFSET (v) = VALUE_OFFSET (arg1) + offset
+ + TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
+ }
+ else if (fieldno < TYPE_N_BASECLASSES (arg_type))
+ {
+ /* This field is actually a base subobject, so preserve the
+ entire object's contents for later references to virtual
+ bases, etc. */
+ v = allocate_value (VALUE_ENCLOSING_TYPE (arg1));
+ VALUE_TYPE (v) = type;
+ if (VALUE_LAZY (arg1))
+ VALUE_LAZY (v) = 1;
+ else
+ memcpy (VALUE_CONTENTS_ALL_RAW (v), VALUE_CONTENTS_ALL_RAW (arg1),
+ TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg1)));
+ VALUE_OFFSET (v) = VALUE_OFFSET (arg1);
+ VALUE_EMBEDDED_OFFSET (v)
+ = offset +
+ VALUE_EMBEDDED_OFFSET (arg1) +
+ TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
+ }
+ else
+ {
+ /* Plain old data member */
+ offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
+ 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_OFFSET (v) = VALUE_OFFSET (arg1) + offset
+ + VALUE_EMBEDDED_OFFSET (arg1);
+ }
+ 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_REGNO (v) = VALUE_REGNO (arg1);
+/* VALUE_OFFSET (v) = VALUE_OFFSET (arg1) + offset
+ + TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; */
+ return v;
+}
+
+/* Given a value ARG1 of a struct or union type,
+ extract and return the value of one of its (non-static) fields.
+ FIELDNO says which field. */
+
+struct value *
+value_field (struct value *arg1, 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.
+
+ We only use the symbol for its address, so be happy with either a
+ full symbol or a minimal symbol.
+ */
+
+struct value *
+value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *type,
+ int offset)
+{
+ struct value *v;
+ struct type *ftype = TYPE_FN_FIELD_TYPE (f, j);
+ char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
+ struct symbol *sym;
+ struct minimal_symbol *msym;
+
+ sym = lookup_symbol (physname, 0, VAR_DOMAIN, 0, NULL);
+ if (sym != NULL)
+ {
+ msym = NULL;
+ }
+ else
+ {
+ gdb_assert (sym == NULL);
+ msym = lookup_minimal_symbol (physname, NULL, NULL);
+ if (msym == NULL)
+ return NULL;
+ }
+
+ v = allocate_value (ftype);
+ if (sym)
+ {
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ }
+ else
+ {
+ VALUE_ADDRESS (v) = SYMBOL_VALUE_ADDRESS (msym);
+ }
+
+ 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;
+}
+
+
+/* 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 (struct type *type, const char *valaddr, int fieldno)
+{
+ ULONGEST val;
+ ULONGEST valmask;
+ int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
+ int bitsize = TYPE_FIELD_BITSIZE (type, fieldno);
+ int lsbcount;
+ struct type *field_type;
+
+ val = extract_unsigned_integer (valaddr + bitpos / 8, sizeof (val));
+ field_type = TYPE_FIELD_TYPE (type, fieldno);
+ CHECK_TYPEDEF (field_type);
+
+ /* 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 = (((ULONGEST) 1) << bitsize) - 1;
+ val &= valmask;
+ if (!TYPE_UNSIGNED (field_type))
+ {
+ 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 (char *addr, LONGEST fieldval, int bitpos, int 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 << bitsize) - 1)))
+ {
+ /* FIXME: would like to include fieldval in the message, but
+ we don't have a sprintf_longest. */
+ warning ("Value does not fit in %d bits.", bitsize);
+
+ /* Truncate it, otherwise adjoining fields may be corrupted. */
+ fieldval = fieldval & ((1 << bitsize) - 1);
+ }
+
+ oword = extract_signed_integer (addr, sizeof oword);
+
+ /* Shifting for bit field depends on endianness of the target machine. */
+ if (BITS_BIG_ENDIAN)
+ bitpos = sizeof (oword) * 8 - bitpos - bitsize;
+
+ /* Mask out old value, while avoiding shifts >= size of oword */
+ if (bitsize < 8 * (int) sizeof (oword))
+ oword &= ~(((((ULONGEST) 1) << bitsize) - 1) << bitpos);
+ else
+ oword &= ~((~(ULONGEST) 0) << bitpos);
+ oword |= fieldval << bitpos;
+
+ store_signed_integer (addr, sizeof oword, oword);
+}
+
+/* Convert C numbers into newly allocated values */
+
+struct value *
+value_from_longest (struct type *type, LONGEST num)
+{
+ struct value *val = allocate_value (type);
+ enum type_code code;
+ 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:
+ store_typed_address (VALUE_CONTENTS_RAW (val), type, (CORE_ADDR) num);
+ break;
+
+ default:
+ error ("Unexpected type (%d) encountered for integer constant.", code);
+ }
+ return val;
+}
+
+
+/* Create a value representing a pointer of type TYPE to the address
+ ADDR. */
+struct value *
+value_from_pointer (struct type *type, CORE_ADDR addr)
+{
+ struct value *val = allocate_value (type);
+ store_typed_address (VALUE_CONTENTS_RAW (val), type, addr);
+ return val;
+}
+
+
+/* Create a value for a string constant to be stored locally
+ (not in the inferior's memory space, but in GDB memory).
+ This is analogous to value_from_longest, which also does not
+ use inferior memory. String shall NOT contain embedded nulls. */
+
+struct value *
+value_from_string (char *ptr)
+{
+ struct value *val;
+ int len = strlen (ptr);
+ 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_array_type ((struct type *) NULL,
+ *current_language->string_char_type,
+ rangetype);
+
+ val = allocate_value (stringtype);
+ memcpy (VALUE_CONTENTS_RAW (val), ptr, len);
+ return val;
+}
+
+struct value *
+value_from_double (struct type *type, DOUBLEST num)
+{
+ struct value *val = allocate_value (type);
+ struct type *base_type = check_typedef (type);
+ enum type_code code = TYPE_CODE (base_type);
+ int len = TYPE_LENGTH (base_type);
+
+ if (code == TYPE_CODE_FLT)
+ {
+ store_typed_floating (VALUE_CONTENTS_RAW (val), base_type, num);
+ }
+ else
+ error ("Unexpected type encountered for floating constant.");
+
+ return val;
+}
+
+/* Deal with the return-value of a function that has "just returned".
+
+ Extract the return-value (as a "struct value") that a function,
+ using register convention, has just returned to its caller. Assume
+ that the type of the function is VALTYPE, and that the "just
+ returned" register state is found in RETBUF.
+
+ The function has "just returned" because GDB halts a returning
+ function by setting a breakpoint at the return address (in the
+ caller), and not the return instruction (in the callee).
+
+ Because, in the case of a return from an inferior function call,
+ GDB needs to restore the inferiors registers, RETBUF is normally a
+ copy of the inferior's registers. */
+
+struct value *
+register_value_being_returned (struct type *valtype, struct regcache *retbuf)
+{
+ struct value *val = allocate_value (valtype);
+
+ /* If the function returns void, don't bother fetching the return
+ value. See also "using_struct_return". */
+ if (TYPE_CODE (valtype) == TYPE_CODE_VOID)
+ return val;
+
+ if (!gdbarch_return_value_p (current_gdbarch))
+ {
+ /* NOTE: cagney/2003-10-20: Unlike "gdbarch_return_value", the
+ EXTRACT_RETURN_VALUE and USE_STRUCT_CONVENTION methods do not
+ handle the edge case of a function returning a small
+ structure / union in registers. */
+ CHECK_TYPEDEF (valtype);
+ EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val));
+ return val;
+ }
+
+ /* This function only handles "register convention". */
+ gdb_assert (gdbarch_return_value (current_gdbarch, valtype,
+ NULL, NULL, NULL)
+ == RETURN_VALUE_REGISTER_CONVENTION);
+ gdbarch_return_value (current_gdbarch, valtype, retbuf,
+ VALUE_CONTENTS_RAW (val) /*read*/, NULL /*write*/);
+ return val;
+}
+
+/* Should we use DEPRECATED_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. */
+
+int
+generic_use_struct_convention (int gcc_p, struct type *value_type)
+{
+ return !((gcc_p == 1)
+ && (TYPE_LENGTH (value_type) == 1
+ || TYPE_LENGTH (value_type) == 2
+ || TYPE_LENGTH (value_type) == 4
+ || TYPE_LENGTH (value_type) == 8));
+}
+
+/* Return true if the function returning the specified type is using
+ the convention of returning structures in memory (passing in the
+ address as a hidden first parameter). GCC_P is nonzero if compiled
+ with GCC. */
+
+int
+using_struct_return (struct type *value_type, int gcc_p)
+{
+ enum type_code code = TYPE_CODE (value_type);
+
+ if (code == TYPE_CODE_ERROR)
+ error ("Function return type unknown.");
+
+ if (code == TYPE_CODE_VOID)
+ /* A void return value is never in memory. See also corresponding
+ code in "register_value_being_returned". */
+ return 0;
+
+ if (!gdbarch_return_value_p (current_gdbarch))
+ {
+ /* FIXME: cagney/2003-10-01: The below is dead. Instead an
+ architecture should implement "gdbarch_return_value". Using
+ that new function it is possible to exactly specify the ABIs
+ "struct return" vs "register return" conventions. */
+ 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);
+ else
+ return 0;
+ }
+
+ /* Probe the architecture for the return-value convention. */
+ return (gdbarch_return_value (current_gdbarch, value_type,
+ NULL, NULL, NULL)
+ == RETURN_VALUE_STRUCT_CONVENTION);
+}
+
+void
+_initialize_values (void)
+{
+ 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/varobj.c b/contrib/gdb/gdb/varobj.c
new file mode 100644
index 0000000..c662518
--- /dev/null
+++ b/contrib/gdb/gdb/varobj.c
@@ -0,0 +1,2564 @@
+/* Implementation of the GDB variable objects API.
+ Copyright 1999, 2000, 2001 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 "value.h"
+#include "expression.h"
+#include "frame.h"
+#include "language.h"
+#include "wrapper.h"
+#include "gdbcmd.h"
+#include "gdb_string.h"
+#include <math.h>
+
+#include "varobj.h"
+
+/* Non-zero if we want to see trace of varobj level stuff. */
+
+int varobjdebug = 0;
+
+/* String representations of gdb's format codes */
+char *varobj_format_string[] =
+ { "natural", "binary", "decimal", "hexadecimal", "octal" };
+
+/* String representations of gdb's known languages */
+char *varobj_language_string[] = { "unknown", "C", "C++", "Java" };
+
+/* Data structures */
+
+/* Every root variable has one of these structures saved in its
+ varobj. Members which must be free'd are noted. */
+struct varobj_root
+{
+
+ /* Alloc'd expression for this parent. */
+ struct expression *exp;
+
+ /* Block for which this expression is valid */
+ struct block *valid_block;
+
+ /* The frame for this expression */
+ struct frame_id frame;
+
+ /* If 1, "update" always recomputes the frame & valid block
+ using the currently selected frame. */
+ int use_selected_frame;
+
+ /* Language info for this variable and its children */
+ struct language_specific *lang;
+
+ /* The varobj for this root node. */
+ struct varobj *rootvar;
+
+ /* Next root variable */
+ struct varobj_root *next;
+};
+
+/* Every variable in the system has a structure of this type defined
+ for it. This structure holds all information necessary to manipulate
+ a particular object variable. Members which must be freed are noted. */
+struct varobj
+{
+
+ /* Alloc'd name of the variable for this object.. If this variable is a
+ child, then this name will be the child's source name.
+ (bar, not foo.bar) */
+ /* NOTE: This is the "expression" */
+ char *name;
+
+ /* The alloc'd name for this variable's object. This is here for
+ convenience when constructing this object's children. */
+ char *obj_name;
+
+ /* Index of this variable in its parent or -1 */
+ int index;
+
+ /* The type of this variable. This may NEVER be NULL. */
+ struct type *type;
+
+ /* The value of this expression or subexpression. This may be NULL. */
+ struct value *value;
+
+ /* Did an error occur evaluating the expression or getting its value? */
+ int error;
+
+ /* The number of (immediate) children this variable has */
+ int num_children;
+
+ /* If this object is a child, this points to its immediate parent. */
+ struct varobj *parent;
+
+ /* A list of this object's children */
+ struct varobj_child *children;
+
+ /* Description of the root variable. Points to root variable for children. */
+ struct varobj_root *root;
+
+ /* The format of the output for this object */
+ enum varobj_display_formats format;
+
+ /* Was this variable updated via a varobj_set_value operation */
+ int updated;
+};
+
+/* Every variable keeps a linked list of its children, described
+ by the following structure. */
+/* FIXME: Deprecated. All should use vlist instead */
+
+struct varobj_child
+{
+
+ /* Pointer to the child's data */
+ struct varobj *child;
+
+ /* Pointer to the next child */
+ struct varobj_child *next;
+};
+
+/* A stack of varobjs */
+/* FIXME: Deprecated. All should use vlist instead */
+
+struct vstack
+{
+ struct varobj *var;
+ struct vstack *next;
+};
+
+struct cpstack
+{
+ char *name;
+ struct cpstack *next;
+};
+
+/* A list of varobjs */
+
+struct vlist
+{
+ struct varobj *var;
+ struct vlist *next;
+};
+
+/* Private function prototypes */
+
+/* Helper functions for the above subcommands. */
+
+static int delete_variable (struct cpstack **, struct varobj *, int);
+
+static void delete_variable_1 (struct cpstack **, int *,
+ struct varobj *, int, int);
+
+static int install_variable (struct varobj *);
+
+static void uninstall_variable (struct varobj *);
+
+static struct varobj *child_exists (struct varobj *, char *);
+
+static struct varobj *create_child (struct varobj *, int, char *);
+
+static void save_child_in_parent (struct varobj *, struct varobj *);
+
+static void remove_child_from_parent (struct varobj *, struct varobj *);
+
+/* Utility routines */
+
+static struct varobj *new_variable (void);
+
+static struct varobj *new_root_variable (void);
+
+static void free_variable (struct varobj *var);
+
+static struct cleanup *make_cleanup_free_variable (struct varobj *var);
+
+static struct type *get_type (struct varobj *var);
+
+static struct type *get_type_deref (struct varobj *var);
+
+static struct type *get_target_type (struct type *);
+
+static enum varobj_display_formats variable_default_display (struct varobj *);
+
+static int my_value_equal (struct value *, struct value *, int *);
+
+static void vpush (struct vstack **pstack, struct varobj *var);
+
+static struct varobj *vpop (struct vstack **pstack);
+
+static void cppush (struct cpstack **pstack, char *name);
+
+static char *cppop (struct cpstack **pstack);
+
+/* Language-specific routines. */
+
+static enum varobj_languages variable_language (struct varobj *var);
+
+static int number_of_children (struct varobj *);
+
+static char *name_of_variable (struct varobj *);
+
+static char *name_of_child (struct varobj *, int);
+
+static struct value *value_of_root (struct varobj **var_handle, int *);
+
+static struct value *value_of_child (struct varobj *parent, int index);
+
+static struct type *type_of_child (struct varobj *var);
+
+static int variable_editable (struct varobj *var);
+
+static char *my_value_of_variable (struct varobj *var);
+
+static int type_changeable (struct varobj *var);
+
+/* C implementation */
+
+static int c_number_of_children (struct varobj *var);
+
+static char *c_name_of_variable (struct varobj *parent);
+
+static char *c_name_of_child (struct varobj *parent, int index);
+
+static struct value *c_value_of_root (struct varobj **var_handle);
+
+static struct value *c_value_of_child (struct varobj *parent, int index);
+
+static struct type *c_type_of_child (struct varobj *parent, int index);
+
+static int c_variable_editable (struct varobj *var);
+
+static char *c_value_of_variable (struct varobj *var);
+
+/* C++ implementation */
+
+static int cplus_number_of_children (struct varobj *var);
+
+static void cplus_class_num_children (struct type *type, int children[3]);
+
+static char *cplus_name_of_variable (struct varobj *parent);
+
+static char *cplus_name_of_child (struct varobj *parent, int index);
+
+static struct value *cplus_value_of_root (struct varobj **var_handle);
+
+static struct value *cplus_value_of_child (struct varobj *parent, int index);
+
+static struct type *cplus_type_of_child (struct varobj *parent, int index);
+
+static int cplus_variable_editable (struct varobj *var);
+
+static char *cplus_value_of_variable (struct varobj *var);
+
+/* Java implementation */
+
+static int java_number_of_children (struct varobj *var);
+
+static char *java_name_of_variable (struct varobj *parent);
+
+static char *java_name_of_child (struct varobj *parent, int index);
+
+static struct value *java_value_of_root (struct varobj **var_handle);
+
+static struct value *java_value_of_child (struct varobj *parent, int index);
+
+static struct type *java_type_of_child (struct varobj *parent, int index);
+
+static int java_variable_editable (struct varobj *var);
+
+static char *java_value_of_variable (struct varobj *var);
+
+/* The language specific vector */
+
+struct language_specific
+{
+
+ /* The language of this variable */
+ enum varobj_languages language;
+
+ /* The number of children of PARENT. */
+ int (*number_of_children) (struct varobj * parent);
+
+ /* The name (expression) of a root varobj. */
+ char *(*name_of_variable) (struct varobj * parent);
+
+ /* The name of the INDEX'th child of PARENT. */
+ char *(*name_of_child) (struct varobj * parent, int index);
+
+ /* The ``struct value *'' of the root variable ROOT. */
+ struct value *(*value_of_root) (struct varobj ** root_handle);
+
+ /* The ``struct value *'' of the INDEX'th child of PARENT. */
+ struct value *(*value_of_child) (struct varobj * parent, int index);
+
+ /* The type of the INDEX'th child of PARENT. */
+ struct type *(*type_of_child) (struct varobj * parent, int index);
+
+ /* Is VAR editable? */
+ int (*variable_editable) (struct varobj * var);
+
+ /* The current value of VAR. */
+ char *(*value_of_variable) (struct varobj * var);
+};
+
+/* Array of known source language routines. */
+static struct language_specific
+ languages[vlang_end][sizeof (struct language_specific)] = {
+ /* Unknown (try treating as C */
+ {
+ vlang_unknown,
+ c_number_of_children,
+ c_name_of_variable,
+ c_name_of_child,
+ c_value_of_root,
+ c_value_of_child,
+ c_type_of_child,
+ c_variable_editable,
+ c_value_of_variable}
+ ,
+ /* C */
+ {
+ vlang_c,
+ c_number_of_children,
+ c_name_of_variable,
+ c_name_of_child,
+ c_value_of_root,
+ c_value_of_child,
+ c_type_of_child,
+ c_variable_editable,
+ c_value_of_variable}
+ ,
+ /* C++ */
+ {
+ vlang_cplus,
+ cplus_number_of_children,
+ cplus_name_of_variable,
+ cplus_name_of_child,
+ cplus_value_of_root,
+ cplus_value_of_child,
+ cplus_type_of_child,
+ cplus_variable_editable,
+ cplus_value_of_variable}
+ ,
+ /* Java */
+ {
+ vlang_java,
+ java_number_of_children,
+ java_name_of_variable,
+ java_name_of_child,
+ java_value_of_root,
+ java_value_of_child,
+ java_type_of_child,
+ java_variable_editable,
+ java_value_of_variable}
+};
+
+/* A little convenience enum for dealing with C++/Java */
+enum vsections
+{
+ v_public = 0, v_private, v_protected
+};
+
+/* Private data */
+
+/* Mappings of varobj_display_formats enums to gdb's format codes */
+static int format_code[] = { 0, 't', 'd', 'x', 'o' };
+
+/* Header of the list of root variable objects */
+static struct varobj_root *rootlist;
+static int rootcount = 0; /* number of root varobjs in the list */
+
+/* Prime number indicating the number of buckets in the hash table */
+/* A prime large enough to avoid too many colisions */
+#define VAROBJ_TABLE_SIZE 227
+
+/* Pointer to the varobj hash table (built at run time) */
+static struct vlist **varobj_table;
+
+/* Is the variable X one of our "fake" children? */
+#define CPLUS_FAKE_CHILD(x) \
+((x) != NULL && (x)->type == NULL && (x)->value == NULL)
+
+
+/* API Implementation */
+
+/* Creates a varobj (not its children) */
+
+/* Return the full FRAME which corresponds to the given CORE_ADDR
+ or NULL if no FRAME on the chain corresponds to CORE_ADDR. */
+
+static struct frame_info *
+find_frame_addr_in_frame_chain (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 (get_frame_base_address (frame) == frame_addr)
+ return frame;
+ }
+}
+
+struct varobj *
+varobj_create (char *objname,
+ char *expression, CORE_ADDR frame, enum varobj_type type)
+{
+ struct varobj *var;
+ struct frame_info *fi;
+ struct frame_info *old_fi = NULL;
+ struct block *block;
+ struct cleanup *old_chain;
+
+ /* Fill out a varobj structure for the (root) variable being constructed. */
+ var = new_root_variable ();
+ old_chain = make_cleanup_free_variable (var);
+
+ if (expression != NULL)
+ {
+ char *p;
+ enum varobj_languages lang;
+
+ /* Parse and evaluate the expression, filling in as much
+ of the variable's data as possible */
+
+ /* Allow creator to specify context of variable */
+ if ((type == USE_CURRENT_FRAME) || (type == USE_SELECTED_FRAME))
+ fi = deprecated_selected_frame;
+ else
+ /* FIXME: cagney/2002-11-23: This code should be doing a
+ lookup using the frame ID and not just the frame's
+ ``address''. This, of course, means an interface change.
+ However, with out that interface change ISAs, such as the
+ ia64 with its two stacks, won't work. Similar goes for the
+ case where there is a frameless function. */
+ fi = find_frame_addr_in_frame_chain (frame);
+
+ /* frame = -2 means always use selected frame */
+ if (type == USE_SELECTED_FRAME)
+ var->root->use_selected_frame = 1;
+
+ block = NULL;
+ if (fi != NULL)
+ block = get_frame_block (fi, 0);
+
+ p = expression;
+ innermost_block = NULL;
+ /* Wrap the call to parse expression, so we can
+ return a sensible error. */
+ if (!gdb_parse_exp_1 (&p, block, 0, &var->root->exp))
+ {
+ return NULL;
+ }
+
+ /* Don't allow variables to be created for types. */
+ if (var->root->exp->elts[0].opcode == OP_TYPE)
+ {
+ do_cleanups (old_chain);
+ fprintf_unfiltered (gdb_stderr,
+ "Attempt to use a type name as an expression.");
+ return NULL;
+ }
+
+ var->format = variable_default_display (var);
+ var->root->valid_block = innermost_block;
+ var->name = savestring (expression, strlen (expression));
+
+ /* When the frame is different from the current frame,
+ we must select the appropriate frame before parsing
+ the expression, otherwise the value will not be current.
+ Since select_frame is so benign, just call it for all cases. */
+ if (fi != NULL)
+ {
+ var->root->frame = get_frame_id (fi);
+ old_fi = deprecated_selected_frame;
+ select_frame (fi);
+ }
+
+ /* We definitively need to catch errors here.
+ If evaluate_expression succeeds we got the value we wanted.
+ But if it fails, we still go on with a call to evaluate_type() */
+ if (gdb_evaluate_expression (var->root->exp, &var->value))
+ {
+ /* no error */
+ release_value (var->value);
+ if (VALUE_LAZY (var->value))
+ gdb_value_fetch_lazy (var->value);
+ }
+ else
+ var->value = evaluate_type (var->root->exp);
+
+ var->type = VALUE_TYPE (var->value);
+
+ /* Set language info */
+ lang = variable_language (var);
+ var->root->lang = languages[lang];
+
+ /* Set ourselves as our root */
+ var->root->rootvar = var;
+
+ /* Reset the selected frame */
+ if (fi != NULL)
+ select_frame (old_fi);
+ }
+
+ /* If the variable object name is null, that means this
+ is a temporary variable, so don't install it. */
+
+ if ((var != NULL) && (objname != NULL))
+ {
+ var->obj_name = savestring (objname, strlen (objname));
+
+ /* If a varobj name is duplicated, the install will fail so
+ we must clenup */
+ if (!install_variable (var))
+ {
+ do_cleanups (old_chain);
+ return NULL;
+ }
+ }
+
+ discard_cleanups (old_chain);
+ return var;
+}
+
+/* Generates an unique name that can be used for a varobj */
+
+char *
+varobj_gen_name (void)
+{
+ static int id = 0;
+ char *obj_name;
+
+ /* generate a name for this object */
+ id++;
+ xasprintf (&obj_name, "var%d", id);
+
+ return obj_name;
+}
+
+/* Given an "objname", returns the pointer to the corresponding varobj
+ or NULL if not found */
+
+struct varobj *
+varobj_get_handle (char *objname)
+{
+ struct vlist *cv;
+ const char *chp;
+ unsigned int index = 0;
+ unsigned int i = 1;
+
+ for (chp = objname; *chp; chp++)
+ {
+ index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+ }
+
+ cv = *(varobj_table + index);
+ while ((cv != NULL) && (strcmp (cv->var->obj_name, objname) != 0))
+ cv = cv->next;
+
+ if (cv == NULL)
+ error ("Variable object not found");
+
+ return cv->var;
+}
+
+/* Given the handle, return the name of the object */
+
+char *
+varobj_get_objname (struct varobj *var)
+{
+ return var->obj_name;
+}
+
+/* Given the handle, return the expression represented by the object */
+
+char *
+varobj_get_expression (struct varobj *var)
+{
+ return name_of_variable (var);
+}
+
+/* Deletes a varobj and all its children if only_children == 0,
+ otherwise deletes only the children; returns a malloc'ed list of all the
+ (malloc'ed) names of the variables that have been deleted (NULL terminated) */
+
+int
+varobj_delete (struct varobj *var, char ***dellist, int only_children)
+{
+ int delcount;
+ int mycount;
+ struct cpstack *result = NULL;
+ char **cp;
+
+ /* Initialize a stack for temporary results */
+ cppush (&result, NULL);
+
+ if (only_children)
+ /* Delete only the variable children */
+ delcount = delete_variable (&result, var, 1 /* only the children */ );
+ else
+ /* Delete the variable and all its children */
+ delcount = delete_variable (&result, var, 0 /* parent+children */ );
+
+ /* We may have been asked to return a list of what has been deleted */
+ if (dellist != NULL)
+ {
+ *dellist = xmalloc ((delcount + 1) * sizeof (char *));
+
+ cp = *dellist;
+ mycount = delcount;
+ *cp = cppop (&result);
+ while ((*cp != NULL) && (mycount > 0))
+ {
+ mycount--;
+ cp++;
+ *cp = cppop (&result);
+ }
+
+ if (mycount || (*cp != NULL))
+ warning ("varobj_delete: assertion failed - mycount(=%d) <> 0",
+ mycount);
+ }
+
+ return delcount;
+}
+
+/* Set/Get variable object display format */
+
+enum varobj_display_formats
+varobj_set_display_format (struct varobj *var,
+ enum varobj_display_formats format)
+{
+ switch (format)
+ {
+ case FORMAT_NATURAL:
+ case FORMAT_BINARY:
+ case FORMAT_DECIMAL:
+ case FORMAT_HEXADECIMAL:
+ case FORMAT_OCTAL:
+ var->format = format;
+ break;
+
+ default:
+ var->format = variable_default_display (var);
+ }
+
+ return var->format;
+}
+
+enum varobj_display_formats
+varobj_get_display_format (struct varobj *var)
+{
+ return var->format;
+}
+
+int
+varobj_get_num_children (struct varobj *var)
+{
+ if (var->num_children == -1)
+ var->num_children = number_of_children (var);
+
+ return var->num_children;
+}
+
+/* Creates a list of the immediate children of a variable object;
+ the return code is the number of such children or -1 on error */
+
+int
+varobj_list_children (struct varobj *var, struct varobj ***childlist)
+{
+ struct varobj *child;
+ char *name;
+ int i;
+
+ /* sanity check: have we been passed a pointer? */
+ if (childlist == NULL)
+ return -1;
+
+ *childlist = NULL;
+
+ if (var->num_children == -1)
+ var->num_children = number_of_children (var);
+
+ /* List of children */
+ *childlist = xmalloc ((var->num_children + 1) * sizeof (struct varobj *));
+
+ for (i = 0; i < var->num_children; i++)
+ {
+ /* Mark as the end in case we bail out */
+ *((*childlist) + i) = NULL;
+
+ /* check if child exists, if not create */
+ name = name_of_child (var, i);
+ child = child_exists (var, name);
+ if (child == NULL)
+ child = create_child (var, i, name);
+
+ *((*childlist) + i) = child;
+ }
+
+ /* End of list is marked by a NULL pointer */
+ *((*childlist) + i) = NULL;
+
+ return var->num_children;
+}
+
+/* Obtain the type of an object Variable as a string similar to the one gdb
+ prints on the console */
+
+char *
+varobj_get_type (struct varobj *var)
+{
+ struct value *val;
+ struct cleanup *old_chain;
+ struct ui_file *stb;
+ char *thetype;
+ long length;
+
+ /* For the "fake" variables, do not return a type. (It's type is
+ NULL, too.) */
+ if (CPLUS_FAKE_CHILD (var))
+ return NULL;
+
+ stb = mem_fileopen ();
+ old_chain = make_cleanup_ui_file_delete (stb);
+
+ /* To print the type, we simply create a zero ``struct value *'' and
+ cast it to our type. We then typeprint this variable. */
+ val = value_zero (var->type, not_lval);
+ type_print (VALUE_TYPE (val), "", stb, -1);
+
+ thetype = ui_file_xstrdup (stb, &length);
+ do_cleanups (old_chain);
+ return thetype;
+}
+
+enum varobj_languages
+varobj_get_language (struct varobj *var)
+{
+ return variable_language (var);
+}
+
+int
+varobj_get_attributes (struct varobj *var)
+{
+ int attributes = 0;
+
+ if (variable_editable (var))
+ /* FIXME: define masks for attributes */
+ attributes |= 0x00000001; /* Editable */
+
+ return attributes;
+}
+
+char *
+varobj_get_value (struct varobj *var)
+{
+ return my_value_of_variable (var);
+}
+
+/* Set the value of an object variable (if it is editable) to the
+ value of the given expression */
+/* Note: Invokes functions that can call error() */
+
+int
+varobj_set_value (struct varobj *var, char *expression)
+{
+ struct value *val;
+ int error;
+ int offset = 0;
+
+ /* The argument "expression" contains the variable's new value.
+ We need to first construct a legal expression for this -- ugh! */
+ /* Does this cover all the bases? */
+ struct expression *exp;
+ struct value *value;
+ int saved_input_radix = input_radix;
+
+ if (var->value != NULL && variable_editable (var) && !var->error)
+ {
+ char *s = expression;
+ int i;
+
+ input_radix = 10; /* ALWAYS reset to decimal temporarily */
+ if (!gdb_parse_exp_1 (&s, 0, 0, &exp))
+ /* We cannot proceed without a well-formed expression. */
+ return 0;
+ if (!gdb_evaluate_expression (exp, &value))
+ {
+ /* We cannot proceed without a valid expression. */
+ xfree (exp);
+ return 0;
+ }
+
+ if (!my_value_equal (var->value, value, &error))
+ var->updated = 1;
+ if (!gdb_value_assign (var->value, value, &val))
+ return 0;
+ value_free (var->value);
+ release_value (val);
+ var->value = val;
+ input_radix = saved_input_radix;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns a malloc'ed list with all root variable objects */
+int
+varobj_list (struct varobj ***varlist)
+{
+ struct varobj **cv;
+ struct varobj_root *croot;
+ int mycount = rootcount;
+
+ /* Alloc (rootcount + 1) entries for the result */
+ *varlist = xmalloc ((rootcount + 1) * sizeof (struct varobj *));
+
+ cv = *varlist;
+ croot = rootlist;
+ while ((croot != NULL) && (mycount > 0))
+ {
+ *cv = croot->rootvar;
+ mycount--;
+ cv++;
+ croot = croot->next;
+ }
+ /* Mark the end of the list */
+ *cv = NULL;
+
+ if (mycount || (croot != NULL))
+ warning
+ ("varobj_list: assertion failed - wrong tally of root vars (%d:%d)",
+ rootcount, mycount);
+
+ return rootcount;
+}
+
+/* Update the values for a variable and its children. This is a
+ two-pronged attack. First, re-parse the value for the root's
+ expression to see if it's changed. Then go all the way
+ through its children, reconstructing them and noting if they've
+ changed.
+ Return value:
+ -1 if there was an error updating the varobj
+ -2 if the type changed
+ Otherwise it is the number of children + parent changed
+
+ Only root variables can be updated...
+
+ NOTE: This function may delete the caller's varobj. If it
+ returns -2, then it has done this and VARP will be modified
+ to point to the new varobj. */
+
+int
+varobj_update (struct varobj **varp, struct varobj ***changelist)
+{
+ int changed = 0;
+ int type_changed;
+ int i;
+ int vleft;
+ int error2;
+ struct varobj *v;
+ struct varobj **cv;
+ struct varobj **templist = NULL;
+ struct value *new;
+ struct vstack *stack = NULL;
+ struct vstack *result = NULL;
+ struct frame_id old_fid;
+ struct frame_info *fi;
+
+ /* sanity check: have we been passed a pointer? */
+ if (changelist == NULL)
+ return -1;
+
+ /* Only root variables can be updated... */
+ if ((*varp)->root->rootvar != *varp)
+ /* Not a root var */
+ return -1;
+
+ /* Save the selected stack frame, since we will need to change it
+ in order to evaluate expressions. */
+ old_fid = get_frame_id (deprecated_selected_frame);
+
+ /* Update the root variable. value_of_root can return NULL
+ if the variable is no longer around, i.e. we stepped out of
+ the frame in which a local existed. We are letting the
+ value_of_root variable dispose of the varobj if the type
+ has changed. */
+ type_changed = 1;
+ new = value_of_root (varp, &type_changed);
+ if (new == NULL)
+ {
+ (*varp)->error = 1;
+ return -1;
+ }
+
+ /* Initialize a stack for temporary results */
+ vpush (&result, NULL);
+
+ /* If this is a "use_selected_frame" varobj, and its type has changed,
+ them note that it's changed. */
+ if (type_changed)
+ {
+ vpush (&result, *varp);
+ changed++;
+ }
+ /* If values are not equal, note that it's changed.
+ There a couple of exceptions here, though.
+ We don't want some types to be reported as "changed". */
+ else if (type_changeable (*varp) &&
+ ((*varp)->updated || !my_value_equal ((*varp)->value, new, &error2)))
+ {
+ vpush (&result, *varp);
+ (*varp)->updated = 0;
+ changed++;
+ /* error2 replaces var->error since this new value
+ WILL replace the old one. */
+ (*varp)->error = error2;
+ }
+
+ /* We must always keep around the new value for this root
+ variable expression, or we lose the updated children! */
+ value_free ((*varp)->value);
+ (*varp)->value = new;
+
+ /* Initialize a stack */
+ vpush (&stack, NULL);
+
+ /* Push the root's children */
+ if ((*varp)->children != NULL)
+ {
+ struct varobj_child *c;
+ for (c = (*varp)->children; c != NULL; c = c->next)
+ vpush (&stack, c->child);
+ }
+
+ /* Walk through the children, reconstructing them all. */
+ v = vpop (&stack);
+ while (v != NULL)
+ {
+ /* Push any children */
+ if (v->children != NULL)
+ {
+ struct varobj_child *c;
+ for (c = v->children; c != NULL; c = c->next)
+ vpush (&stack, c->child);
+ }
+
+ /* Update this variable */
+ new = value_of_child (v->parent, v->index);
+ if (type_changeable (v) &&
+ (v->updated || !my_value_equal (v->value, new, &error2)))
+ {
+ /* Note that it's changed */
+ vpush (&result, v);
+ v->updated = 0;
+ changed++;
+ }
+ /* error2 replaces v->error since this new value
+ WILL replace the old one. */
+ v->error = error2;
+
+ /* We must always keep new values, since children depend on it. */
+ if (v->value != NULL)
+ value_free (v->value);
+ v->value = new;
+
+ /* Get next child */
+ v = vpop (&stack);
+ }
+
+ /* Alloc (changed + 1) list entries */
+ /* FIXME: add a cleanup for the allocated list(s)
+ because one day the select_frame called below can longjump */
+ *changelist = xmalloc ((changed + 1) * sizeof (struct varobj *));
+ if (changed > 1)
+ {
+ templist = xmalloc ((changed + 1) * sizeof (struct varobj *));
+ cv = templist;
+ }
+ else
+ cv = *changelist;
+
+ /* Copy from result stack to list */
+ vleft = changed;
+ *cv = vpop (&result);
+ while ((*cv != NULL) && (vleft > 0))
+ {
+ vleft--;
+ cv++;
+ *cv = vpop (&result);
+ }
+ if (vleft)
+ warning ("varobj_update: assertion failed - vleft <> 0");
+
+ if (changed > 1)
+ {
+ /* Now we revert the order. */
+ for (i = 0; i < changed; i++)
+ *(*changelist + i) = *(templist + changed - 1 - i);
+ *(*changelist + changed) = NULL;
+ }
+
+ /* Restore selected frame */
+ fi = frame_find_by_id (old_fid);
+ if (fi)
+ select_frame (fi);
+
+ if (type_changed)
+ return -2;
+ else
+ return changed;
+}
+
+
+/* Helper functions */
+
+/*
+ * Variable object construction/destruction
+ */
+
+static int
+delete_variable (struct cpstack **resultp, struct varobj *var,
+ int only_children_p)
+{
+ int delcount = 0;
+
+ delete_variable_1 (resultp, &delcount, var,
+ only_children_p, 1 /* remove_from_parent_p */ );
+
+ return delcount;
+}
+
+/* Delete the variable object VAR and its children */
+/* IMPORTANT NOTE: If we delete a variable which is a child
+ and the parent is not removed we dump core. It must be always
+ initially called with remove_from_parent_p set */
+static void
+delete_variable_1 (struct cpstack **resultp, int *delcountp,
+ struct varobj *var, int only_children_p,
+ int remove_from_parent_p)
+{
+ struct varobj_child *vc;
+ struct varobj_child *next;
+
+ /* Delete any children of this variable, too. */
+ for (vc = var->children; vc != NULL; vc = next)
+ {
+ if (!remove_from_parent_p)
+ vc->child->parent = NULL;
+ delete_variable_1 (resultp, delcountp, vc->child, 0, only_children_p);
+ next = vc->next;
+ xfree (vc);
+ }
+
+ /* if we were called to delete only the children we are done here */
+ if (only_children_p)
+ return;
+
+ /* Otherwise, add it to the list of deleted ones and proceed to do so */
+ /* If the name is null, this is a temporary variable, that has not
+ yet been installed, don't report it, it belongs to the caller... */
+ if (var->obj_name != NULL)
+ {
+ cppush (resultp, xstrdup (var->obj_name));
+ *delcountp = *delcountp + 1;
+ }
+
+ /* If this variable has a parent, remove it from its parent's list */
+ /* OPTIMIZATION: if the parent of this variable is also being deleted,
+ (as indicated by remove_from_parent_p) we don't bother doing an
+ expensive list search to find the element to remove when we are
+ discarding the list afterwards */
+ if ((remove_from_parent_p) && (var->parent != NULL))
+ {
+ remove_child_from_parent (var->parent, var);
+ }
+
+ if (var->obj_name != NULL)
+ uninstall_variable (var);
+
+ /* Free memory associated with this variable */
+ free_variable (var);
+}
+
+/* Install the given variable VAR with the object name VAR->OBJ_NAME. */
+static int
+install_variable (struct varobj *var)
+{
+ struct vlist *cv;
+ struct vlist *newvl;
+ const char *chp;
+ unsigned int index = 0;
+ unsigned int i = 1;
+
+ for (chp = var->obj_name; *chp; chp++)
+ {
+ index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+ }
+
+ cv = *(varobj_table + index);
+ while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0))
+ cv = cv->next;
+
+ if (cv != NULL)
+ error ("Duplicate variable object name");
+
+ /* Add varobj to hash table */
+ newvl = xmalloc (sizeof (struct vlist));
+ newvl->next = *(varobj_table + index);
+ newvl->var = var;
+ *(varobj_table + index) = newvl;
+
+ /* If root, add varobj to root list */
+ if (var->root->rootvar == var)
+ {
+ /* Add to list of root variables */
+ if (rootlist == NULL)
+ var->root->next = NULL;
+ else
+ var->root->next = rootlist;
+ rootlist = var->root;
+ rootcount++;
+ }
+
+ return 1; /* OK */
+}
+
+/* Unistall the object VAR. */
+static void
+uninstall_variable (struct varobj *var)
+{
+ struct vlist *cv;
+ struct vlist *prev;
+ struct varobj_root *cr;
+ struct varobj_root *prer;
+ const char *chp;
+ unsigned int index = 0;
+ unsigned int i = 1;
+
+ /* Remove varobj from hash table */
+ for (chp = var->obj_name; *chp; chp++)
+ {
+ index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+ }
+
+ cv = *(varobj_table + index);
+ prev = NULL;
+ while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0))
+ {
+ prev = cv;
+ cv = cv->next;
+ }
+
+ if (varobjdebug)
+ fprintf_unfiltered (gdb_stdlog, "Deleting %s\n", var->obj_name);
+
+ if (cv == NULL)
+ {
+ warning
+ ("Assertion failed: Could not find variable object \"%s\" to delete",
+ var->obj_name);
+ return;
+ }
+
+ if (prev == NULL)
+ *(varobj_table + index) = cv->next;
+ else
+ prev->next = cv->next;
+
+ xfree (cv);
+
+ /* If root, remove varobj from root list */
+ if (var->root->rootvar == var)
+ {
+ /* Remove from list of root variables */
+ if (rootlist == var->root)
+ rootlist = var->root->next;
+ else
+ {
+ prer = NULL;
+ cr = rootlist;
+ while ((cr != NULL) && (cr->rootvar != var))
+ {
+ prer = cr;
+ cr = cr->next;
+ }
+ if (cr == NULL)
+ {
+ warning
+ ("Assertion failed: Could not find varobj \"%s\" in root list",
+ var->obj_name);
+ return;
+ }
+ if (prer == NULL)
+ rootlist = NULL;
+ else
+ prer->next = cr->next;
+ }
+ rootcount--;
+ }
+
+}
+
+/* Does a child with the name NAME exist in VAR? If so, return its data.
+ If not, return NULL. */
+static struct varobj *
+child_exists (struct varobj *var, char *name)
+{
+ struct varobj_child *vc;
+
+ for (vc = var->children; vc != NULL; vc = vc->next)
+ {
+ if (strcmp (vc->child->name, name) == 0)
+ return vc->child;
+ }
+
+ return NULL;
+}
+
+/* Create and install a child of the parent of the given name */
+static struct varobj *
+create_child (struct varobj *parent, int index, char *name)
+{
+ struct varobj *child;
+ char *childs_name;
+
+ child = new_variable ();
+
+ /* name is allocated by name_of_child */
+ child->name = name;
+ child->index = index;
+ child->value = value_of_child (parent, index);
+ if ((!CPLUS_FAKE_CHILD (child) && child->value == NULL) || parent->error)
+ child->error = 1;
+ child->parent = parent;
+ child->root = parent->root;
+ xasprintf (&childs_name, "%s.%s", parent->obj_name, name);
+ child->obj_name = childs_name;
+ install_variable (child);
+
+ /* Save a pointer to this child in the parent */
+ save_child_in_parent (parent, child);
+
+ /* Note the type of this child */
+ child->type = type_of_child (child);
+
+ return child;
+}
+
+/* FIXME: This should be a generic add to list */
+/* Save CHILD in the PARENT's data. */
+static void
+save_child_in_parent (struct varobj *parent, struct varobj *child)
+{
+ struct varobj_child *vc;
+
+ /* Insert the child at the top */
+ vc = parent->children;
+ parent->children =
+ (struct varobj_child *) xmalloc (sizeof (struct varobj_child));
+
+ parent->children->next = vc;
+ parent->children->child = child;
+}
+
+/* FIXME: This should be a generic remove from list */
+/* Remove the CHILD from the PARENT's list of children. */
+static void
+remove_child_from_parent (struct varobj *parent, struct varobj *child)
+{
+ struct varobj_child *vc, *prev;
+
+ /* Find the child in the parent's list */
+ prev = NULL;
+ for (vc = parent->children; vc != NULL;)
+ {
+ if (vc->child == child)
+ break;
+ prev = vc;
+ vc = vc->next;
+ }
+
+ if (prev == NULL)
+ parent->children = vc->next;
+ else
+ prev->next = vc->next;
+
+}
+
+
+/*
+ * Miscellaneous utility functions.
+ */
+
+/* Allocate memory and initialize a new variable */
+static struct varobj *
+new_variable (void)
+{
+ struct varobj *var;
+
+ var = (struct varobj *) xmalloc (sizeof (struct varobj));
+ var->name = NULL;
+ var->obj_name = NULL;
+ var->index = -1;
+ var->type = NULL;
+ var->value = NULL;
+ var->error = 0;
+ var->num_children = -1;
+ var->parent = NULL;
+ var->children = NULL;
+ var->format = 0;
+ var->root = NULL;
+ var->updated = 0;
+
+ return var;
+}
+
+/* Allocate memory and initialize a new root variable */
+static struct varobj *
+new_root_variable (void)
+{
+ struct varobj *var = new_variable ();
+ var->root = (struct varobj_root *) xmalloc (sizeof (struct varobj_root));;
+ var->root->lang = NULL;
+ var->root->exp = NULL;
+ var->root->valid_block = NULL;
+ var->root->frame = null_frame_id;
+ var->root->use_selected_frame = 0;
+ var->root->rootvar = NULL;
+
+ return var;
+}
+
+/* Free any allocated memory associated with VAR. */
+static void
+free_variable (struct varobj *var)
+{
+ /* Free the expression if this is a root variable. */
+ if (var->root->rootvar == var)
+ {
+ free_current_contents ((char **) &var->root->exp);
+ xfree (var->root);
+ }
+
+ xfree (var->name);
+ xfree (var->obj_name);
+ xfree (var);
+}
+
+static void
+do_free_variable_cleanup (void *var)
+{
+ free_variable (var);
+}
+
+static struct cleanup *
+make_cleanup_free_variable (struct varobj *var)
+{
+ return make_cleanup (do_free_variable_cleanup, var);
+}
+
+/* This returns the type of the variable. It also skips past typedefs
+ to return the real type of the variable.
+
+ NOTE: TYPE_TARGET_TYPE should NOT be used anywhere in this file
+ except within get_target_type and get_type. */
+static struct type *
+get_type (struct varobj *var)
+{
+ struct type *type;
+ type = var->type;
+
+ if (type != NULL)
+ type = check_typedef (type);
+
+ return type;
+}
+
+/* This returns the type of the variable, dereferencing pointers, too. */
+static struct type *
+get_type_deref (struct varobj *var)
+{
+ struct type *type;
+
+ type = get_type (var);
+
+ if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF))
+ type = get_target_type (type);
+
+ return type;
+}
+
+/* This returns the target type (or NULL) of TYPE, also skipping
+ past typedefs, just like get_type ().
+
+ NOTE: TYPE_TARGET_TYPE should NOT be used anywhere in this file
+ except within get_target_type and get_type. */
+static struct type *
+get_target_type (struct type *type)
+{
+ if (type != NULL)
+ {
+ type = TYPE_TARGET_TYPE (type);
+ if (type != NULL)
+ type = check_typedef (type);
+ }
+
+ return type;
+}
+
+/* What is the default display for this variable? We assume that
+ everything is "natural". Any exceptions? */
+static enum varobj_display_formats
+variable_default_display (struct varobj *var)
+{
+ return FORMAT_NATURAL;
+}
+
+/* This function is similar to gdb's value_equal, except that this
+ one is "safe" -- it NEVER longjmps. It determines if the VAR's
+ value is the same as VAL2. */
+static int
+my_value_equal (struct value *val1, struct value *val2, int *error2)
+{
+ int r, err1, err2;
+
+ *error2 = 0;
+ /* Special case: NULL values. If both are null, say
+ they're equal. */
+ if (val1 == NULL && val2 == NULL)
+ return 1;
+ else if (val1 == NULL || val2 == NULL)
+ return 0;
+
+ /* This is bogus, but unfortunately necessary. We must know
+ exactly what caused an error -- reading val1 or val2 -- so
+ that we can really determine if we think that something has changed. */
+ err1 = 0;
+ err2 = 0;
+ /* We do need to catch errors here because the whole purpose
+ is to test if value_equal() has errored */
+ if (!gdb_value_equal (val1, val1, &r))
+ err1 = 1;
+
+ if (!gdb_value_equal (val2, val2, &r))
+ *error2 = err2 = 1;
+
+ if (err1 != err2)
+ return 0;
+
+ if (!gdb_value_equal (val1, val2, &r))
+ {
+ /* An error occurred, this could have happened if
+ either val1 or val2 errored. ERR1 and ERR2 tell
+ us which of these it is. If both errored, then
+ we assume nothing has changed. If one of them is
+ valid, though, then something has changed. */
+ if (err1 == err2)
+ {
+ /* both the old and new values caused errors, so
+ we say the value did not change */
+ /* This is indeterminate, though. Perhaps we should
+ be safe and say, yes, it changed anyway?? */
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ return r;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static void
+vpush (struct vstack **pstack, struct varobj *var)
+{
+ struct vstack *s;
+
+ s = (struct vstack *) xmalloc (sizeof (struct vstack));
+ s->var = var;
+ s->next = *pstack;
+ *pstack = s;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static struct varobj *
+vpop (struct vstack **pstack)
+{
+ struct vstack *s;
+ struct varobj *v;
+
+ if ((*pstack)->var == NULL && (*pstack)->next == NULL)
+ return NULL;
+
+ s = *pstack;
+ v = s->var;
+ *pstack = (*pstack)->next;
+ xfree (s);
+
+ return v;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static void
+cppush (struct cpstack **pstack, char *name)
+{
+ struct cpstack *s;
+
+ s = (struct cpstack *) xmalloc (sizeof (struct cpstack));
+ s->name = name;
+ s->next = *pstack;
+ *pstack = s;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static char *
+cppop (struct cpstack **pstack)
+{
+ struct cpstack *s;
+ char *v;
+
+ if ((*pstack)->name == NULL && (*pstack)->next == NULL)
+ return NULL;
+
+ s = *pstack;
+ v = s->name;
+ *pstack = (*pstack)->next;
+ xfree (s);
+
+ return v;
+}
+
+/*
+ * Language-dependencies
+ */
+
+/* Common entry points */
+
+/* Get the language of variable VAR. */
+static enum varobj_languages
+variable_language (struct varobj *var)
+{
+ enum varobj_languages lang;
+
+ switch (var->root->exp->language_defn->la_language)
+ {
+ default:
+ case language_c:
+ lang = vlang_c;
+ break;
+ case language_cplus:
+ lang = vlang_cplus;
+ break;
+ case language_java:
+ lang = vlang_java;
+ break;
+ }
+
+ return lang;
+}
+
+/* Return the number of children for a given variable.
+ The result of this function is defined by the language
+ implementation. The number of children returned by this function
+ is the number of children that the user will see in the variable
+ display. */
+static int
+number_of_children (struct varobj *var)
+{
+ return (*var->root->lang->number_of_children) (var);;
+}
+
+/* What is the expression for the root varobj VAR? Returns a malloc'd string. */
+static char *
+name_of_variable (struct varobj *var)
+{
+ return (*var->root->lang->name_of_variable) (var);
+}
+
+/* What is the name of the INDEX'th child of VAR? Returns a malloc'd string. */
+static char *
+name_of_child (struct varobj *var, int index)
+{
+ return (*var->root->lang->name_of_child) (var, index);
+}
+
+/* What is the ``struct value *'' of the root variable VAR?
+ TYPE_CHANGED controls what to do if the type of a
+ use_selected_frame = 1 variable changes. On input,
+ TYPE_CHANGED = 1 means discard the old varobj, and replace
+ it with this one. TYPE_CHANGED = 0 means leave it around.
+ NB: In both cases, var_handle will point to the new varobj,
+ so if you use TYPE_CHANGED = 0, you will have to stash the
+ old varobj pointer away somewhere before calling this.
+ On return, TYPE_CHANGED will be 1 if the type has changed, and
+ 0 otherwise. */
+static struct value *
+value_of_root (struct varobj **var_handle, int *type_changed)
+{
+ struct varobj *var;
+
+ if (var_handle == NULL)
+ return NULL;
+
+ var = *var_handle;
+
+ /* This should really be an exception, since this should
+ only get called with a root variable. */
+
+ if (var->root->rootvar != var)
+ return NULL;
+
+ if (var->root->use_selected_frame)
+ {
+ struct varobj *tmp_var;
+ char *old_type, *new_type;
+ old_type = varobj_get_type (var);
+ tmp_var = varobj_create (NULL, var->name, (CORE_ADDR) 0,
+ USE_SELECTED_FRAME);
+ if (tmp_var == NULL)
+ {
+ return NULL;
+ }
+ new_type = varobj_get_type (tmp_var);
+ if (strcmp (old_type, new_type) == 0)
+ {
+ varobj_delete (tmp_var, NULL, 0);
+ *type_changed = 0;
+ }
+ else
+ {
+ if (*type_changed)
+ {
+ tmp_var->obj_name =
+ savestring (var->obj_name, strlen (var->obj_name));
+ varobj_delete (var, NULL, 0);
+ }
+ else
+ {
+ tmp_var->obj_name = varobj_gen_name ();
+ }
+ install_variable (tmp_var);
+ *var_handle = tmp_var;
+ var = *var_handle;
+ *type_changed = 1;
+ }
+ }
+ else
+ {
+ *type_changed = 0;
+ }
+
+ return (*var->root->lang->value_of_root) (var_handle);
+}
+
+/* What is the ``struct value *'' for the INDEX'th child of PARENT? */
+static struct value *
+value_of_child (struct varobj *parent, int index)
+{
+ struct value *value;
+
+ value = (*parent->root->lang->value_of_child) (parent, index);
+
+ /* If we're being lazy, fetch the real value of the variable. */
+ if (value != NULL && VALUE_LAZY (value))
+ {
+ /* If we fail to fetch the value of the child, return
+ NULL so that callers notice that we're leaving an
+ error message. */
+ if (!gdb_value_fetch_lazy (value))
+ value = NULL;
+ }
+
+ return value;
+}
+
+/* What is the type of VAR? */
+static struct type *
+type_of_child (struct varobj *var)
+{
+
+ /* If the child had no evaluation errors, var->value
+ will be non-NULL and contain a valid type. */
+ if (var->value != NULL)
+ return VALUE_TYPE (var->value);
+
+ /* Otherwise, we must compute the type. */
+ return (*var->root->lang->type_of_child) (var->parent, var->index);
+}
+
+/* Is this variable editable? Use the variable's type to make
+ this determination. */
+static int
+variable_editable (struct varobj *var)
+{
+ return (*var->root->lang->variable_editable) (var);
+}
+
+/* GDB already has a command called "value_of_variable". Sigh. */
+static char *
+my_value_of_variable (struct varobj *var)
+{
+ return (*var->root->lang->value_of_variable) (var);
+}
+
+/* Is VAR something that can change? Depending on language,
+ some variable's values never change. For example,
+ struct and unions never change values. */
+static int
+type_changeable (struct varobj *var)
+{
+ int r;
+ struct type *type;
+
+ if (CPLUS_FAKE_CHILD (var))
+ return 0;
+
+ type = get_type (var);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ARRAY:
+ r = 0;
+ break;
+
+ default:
+ r = 1;
+ }
+
+ return r;
+}
+
+/* C */
+static int
+c_number_of_children (struct varobj *var)
+{
+ struct type *type;
+ struct type *target;
+ int children;
+
+ type = get_type (var);
+ target = get_target_type (type);
+ children = 0;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (target) > 0
+ && TYPE_ARRAY_UPPER_BOUND_TYPE (type) != BOUND_CANNOT_BE_DETERMINED)
+ children = TYPE_LENGTH (type) / TYPE_LENGTH (target);
+ else
+ children = -1;
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ children = TYPE_NFIELDS (type);
+ break;
+
+ case TYPE_CODE_PTR:
+ /* This is where things get compilcated. All pointers have one child.
+ Except, of course, for struct and union ptr, which we automagically
+ dereference for the user and function ptrs, which have no children.
+ We also don't dereference void* as we don't know what to show.
+ We can show char* so we allow it to be dereferenced. If you decide
+ to test for it, please mind that a little magic is necessary to
+ properly identify it: char* has TYPE_CODE == TYPE_CODE_INT and
+ TYPE_NAME == "char" */
+
+ switch (TYPE_CODE (target))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ children = TYPE_NFIELDS (target);
+ break;
+
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_VOID:
+ children = 0;
+ break;
+
+ default:
+ children = 1;
+ }
+ break;
+
+ default:
+ /* Other types have no children */
+ break;
+ }
+
+ return children;
+}
+
+static char *
+c_name_of_variable (struct varobj *parent)
+{
+ return savestring (parent->name, strlen (parent->name));
+}
+
+static char *
+c_name_of_child (struct varobj *parent, int index)
+{
+ struct type *type;
+ struct type *target;
+ char *name;
+ char *string;
+
+ type = get_type (parent);
+ target = get_target_type (type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ xasprintf (&name, "%d", index);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ string = TYPE_FIELD_NAME (type, index);
+ name = savestring (string, strlen (string));
+ break;
+
+ case TYPE_CODE_PTR:
+ switch (TYPE_CODE (target))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ string = TYPE_FIELD_NAME (target, index);
+ name = savestring (string, strlen (string));
+ break;
+
+ default:
+ xasprintf (&name, "*%s", parent->name);
+ break;
+ }
+ break;
+
+ default:
+ /* This should not happen */
+ name = xstrdup ("???");
+ }
+
+ return name;
+}
+
+static struct value *
+c_value_of_root (struct varobj **var_handle)
+{
+ struct value *new_val;
+ struct varobj *var = *var_handle;
+ struct frame_info *fi;
+ int within_scope;
+
+ /* Only root variables can be updated... */
+ if (var->root->rootvar != var)
+ /* Not a root var */
+ return NULL;
+
+
+ /* Determine whether the variable is still around. */
+ if (var->root->valid_block == NULL)
+ within_scope = 1;
+ else
+ {
+ reinit_frame_cache ();
+ fi = frame_find_by_id (var->root->frame);
+ within_scope = fi != NULL;
+ /* FIXME: select_frame could fail */
+ if (within_scope)
+ select_frame (fi);
+ }
+
+ if (within_scope)
+ {
+ /* We need to catch errors here, because if evaluate
+ expression fails we just want to make val->error = 1 and
+ go on */
+ if (gdb_evaluate_expression (var->root->exp, &new_val))
+ {
+ if (VALUE_LAZY (new_val))
+ {
+ /* We need to catch errors because if
+ value_fetch_lazy fails we still want to continue
+ (after making val->error = 1) */
+ /* FIXME: Shouldn't be using VALUE_CONTENTS? The
+ comment on value_fetch_lazy() says it is only
+ called from the macro... */
+ if (!gdb_value_fetch_lazy (new_val))
+ var->error = 1;
+ else
+ var->error = 0;
+ }
+ }
+ else
+ var->error = 1;
+
+ release_value (new_val);
+ return new_val;
+ }
+
+ return NULL;
+}
+
+static struct value *
+c_value_of_child (struct varobj *parent, int index)
+{
+ struct value *value;
+ struct value *temp;
+ struct value *indval;
+ struct type *type, *target;
+ char *name;
+
+ type = get_type (parent);
+ target = get_target_type (type);
+ name = name_of_child (parent, index);
+ temp = parent->value;
+ value = NULL;
+
+ if (temp != NULL)
+ {
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+#if 0
+ /* This breaks if the array lives in a (vector) register. */
+ value = value_slice (temp, index, 1);
+ temp = value_coerce_array (value);
+ gdb_value_ind (temp, &value);
+#else
+ indval = value_from_longest (builtin_type_int, (LONGEST) index);
+ gdb_value_subscript (temp, indval, &value);
+#endif
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ gdb_value_struct_elt (NULL, &value, &temp, NULL, name, NULL,
+ "vstructure");
+ break;
+
+ case TYPE_CODE_PTR:
+ switch (TYPE_CODE (target))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ gdb_value_struct_elt (NULL, &value, &temp, NULL, name, NULL,
+ "vstructure");
+ break;
+
+ default:
+ gdb_value_ind (temp, &value);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (value != NULL)
+ release_value (value);
+
+ xfree (name);
+ return value;
+}
+
+static struct type *
+c_type_of_child (struct varobj *parent, int index)
+{
+ struct type *type;
+ char *name = name_of_child (parent, index);
+
+ switch (TYPE_CODE (parent->type))
+ {
+ case TYPE_CODE_ARRAY:
+ type = get_target_type (parent->type);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ type = lookup_struct_elt_type (parent->type, name, 0);
+ break;
+
+ case TYPE_CODE_PTR:
+ switch (TYPE_CODE (get_target_type (parent->type)))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ type = lookup_struct_elt_type (parent->type, name, 0);
+ break;
+
+ default:
+ type = get_target_type (parent->type);
+ break;
+ }
+ break;
+
+ default:
+ /* This should not happen as only the above types have children */
+ warning ("Child of parent whose type does not allow children");
+ /* FIXME: Can we still go on? */
+ type = NULL;
+ break;
+ }
+
+ xfree (name);
+ return type;
+}
+
+static int
+c_variable_editable (struct varobj *var)
+{
+ switch (TYPE_CODE (get_type (var)))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_METHOD:
+ return 0;
+ break;
+
+ default:
+ return 1;
+ break;
+ }
+}
+
+static char *
+c_value_of_variable (struct varobj *var)
+{
+ /* BOGUS: if val_print sees a struct/class, it will print out its
+ children instead of "{...}" */
+
+ switch (TYPE_CODE (get_type (var)))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return xstrdup ("{...}");
+ /* break; */
+
+ case TYPE_CODE_ARRAY:
+ {
+ char *number;
+ xasprintf (&number, "[%d]", var->num_children);
+ return (number);
+ }
+ /* break; */
+
+ default:
+ {
+ if (var->value == NULL)
+ {
+ /* This can happen if we attempt to get the value of a struct
+ member when the parent is an invalid pointer. This is an
+ error condition, so we should tell the caller. */
+ return NULL;
+ }
+ else
+ {
+ long dummy;
+ struct ui_file *stb = mem_fileopen ();
+ struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
+ char *thevalue;
+
+ if (VALUE_LAZY (var->value))
+ gdb_value_fetch_lazy (var->value);
+ val_print (VALUE_TYPE (var->value),
+ VALUE_CONTENTS_RAW (var->value), 0,
+ VALUE_ADDRESS (var->value), stb,
+ format_code[(int) var->format], 1, 0, 0);
+ thevalue = ui_file_xstrdup (stb, &dummy);
+ do_cleanups (old_chain);
+ return thevalue;
+ }
+ }
+ }
+}
+
+
+/* C++ */
+
+static int
+cplus_number_of_children (struct varobj *var)
+{
+ struct type *type;
+ int children, dont_know;
+
+ dont_know = 1;
+ children = 0;
+
+ if (!CPLUS_FAKE_CHILD (var))
+ {
+ type = get_type_deref (var);
+
+ if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
+ ((TYPE_CODE (type)) == TYPE_CODE_UNION))
+ {
+ int kids[3];
+
+ cplus_class_num_children (type, kids);
+ if (kids[v_public] != 0)
+ children++;
+ if (kids[v_private] != 0)
+ children++;
+ if (kids[v_protected] != 0)
+ children++;
+
+ /* Add any baseclasses */
+ children += TYPE_N_BASECLASSES (type);
+ dont_know = 0;
+
+ /* FIXME: save children in var */
+ }
+ }
+ else
+ {
+ int kids[3];
+
+ type = get_type_deref (var->parent);
+
+ cplus_class_num_children (type, kids);
+ if (strcmp (var->name, "public") == 0)
+ children = kids[v_public];
+ else if (strcmp (var->name, "private") == 0)
+ children = kids[v_private];
+ else
+ children = kids[v_protected];
+ dont_know = 0;
+ }
+
+ if (dont_know)
+ children = c_number_of_children (var);
+
+ return children;
+}
+
+/* Compute # of public, private, and protected variables in this class.
+ That means we need to descend into all baseclasses and find out
+ how many are there, too. */
+static void
+cplus_class_num_children (struct type *type, int children[3])
+{
+ int i;
+
+ children[v_public] = 0;
+ children[v_private] = 0;
+ children[v_protected] = 0;
+
+ for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++)
+ {
+ /* If we have a virtual table pointer, omit it. */
+ if (TYPE_VPTR_BASETYPE (type) == type && TYPE_VPTR_FIELDNO (type) == i)
+ continue;
+
+ if (TYPE_FIELD_PROTECTED (type, i))
+ children[v_protected]++;
+ else if (TYPE_FIELD_PRIVATE (type, i))
+ children[v_private]++;
+ else
+ children[v_public]++;
+ }
+}
+
+static char *
+cplus_name_of_variable (struct varobj *parent)
+{
+ return c_name_of_variable (parent);
+}
+
+static char *
+cplus_name_of_child (struct varobj *parent, int index)
+{
+ char *name;
+ struct type *type;
+
+ if (CPLUS_FAKE_CHILD (parent))
+ {
+ /* Looking for children of public, private, or protected. */
+ type = get_type_deref (parent->parent);
+ }
+ else
+ type = get_type_deref (parent);
+
+ name = NULL;
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ if (CPLUS_FAKE_CHILD (parent))
+ {
+ /* The fields of the class type are ordered as they
+ appear in the class. We are given an index for a
+ particular access control type ("public","protected",
+ or "private"). We must skip over fields that don't
+ have the access control we are looking for to properly
+ find the indexed field. */
+ int type_index = TYPE_N_BASECLASSES (type);
+ if (strcmp (parent->name, "private") == 0)
+ {
+ while (index >= 0)
+ {
+ if (TYPE_VPTR_BASETYPE (type) == type
+ && type_index == TYPE_VPTR_FIELDNO (type))
+ ; /* ignore vptr */
+ else if (TYPE_FIELD_PRIVATE (type, type_index))
+ --index;
+ ++type_index;
+ }
+ --type_index;
+ }
+ else if (strcmp (parent->name, "protected") == 0)
+ {
+ while (index >= 0)
+ {
+ if (TYPE_VPTR_BASETYPE (type) == type
+ && type_index == TYPE_VPTR_FIELDNO (type))
+ ; /* ignore vptr */
+ else if (TYPE_FIELD_PROTECTED (type, type_index))
+ --index;
+ ++type_index;
+ }
+ --type_index;
+ }
+ else
+ {
+ while (index >= 0)
+ {
+ if (TYPE_VPTR_BASETYPE (type) == type
+ && type_index == TYPE_VPTR_FIELDNO (type))
+ ; /* ignore vptr */
+ else if (!TYPE_FIELD_PRIVATE (type, type_index) &&
+ !TYPE_FIELD_PROTECTED (type, type_index))
+ --index;
+ ++type_index;
+ }
+ --type_index;
+ }
+
+ name = TYPE_FIELD_NAME (type, type_index);
+ }
+ else if (index < TYPE_N_BASECLASSES (type))
+ /* We are looking up the name of a base class */
+ name = TYPE_FIELD_NAME (type, index);
+ else
+ {
+ int children[3];
+ cplus_class_num_children(type, children);
+
+ /* Everything beyond the baseclasses can
+ only be "public", "private", or "protected"
+
+ The special "fake" children are always output by varobj in
+ this order. So if INDEX == 2, it MUST be "protected". */
+ index -= TYPE_N_BASECLASSES (type);
+ switch (index)
+ {
+ case 0:
+ if (children[v_public] > 0)
+ name = "public";
+ else if (children[v_private] > 0)
+ name = "private";
+ else
+ name = "protected";
+ break;
+ case 1:
+ if (children[v_public] > 0)
+ {
+ if (children[v_private] > 0)
+ name = "private";
+ else
+ name = "protected";
+ }
+ else if (children[v_private] > 0)
+ name = "protected";
+ break;
+ case 2:
+ /* Must be protected */
+ name = "protected";
+ break;
+ default:
+ /* error! */
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (name == NULL)
+ return c_name_of_child (parent, index);
+ else
+ {
+ if (name != NULL)
+ name = savestring (name, strlen (name));
+ }
+
+ return name;
+}
+
+static struct value *
+cplus_value_of_root (struct varobj **var_handle)
+{
+ return c_value_of_root (var_handle);
+}
+
+static struct value *
+cplus_value_of_child (struct varobj *parent, int index)
+{
+ struct type *type;
+ struct value *value;
+
+ if (CPLUS_FAKE_CHILD (parent))
+ type = get_type_deref (parent->parent);
+ else
+ type = get_type_deref (parent);
+
+ value = NULL;
+
+ if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
+ ((TYPE_CODE (type)) == TYPE_CODE_UNION))
+ {
+ if (CPLUS_FAKE_CHILD (parent))
+ {
+ char *name;
+ struct value *temp = parent->parent->value;
+
+ if (temp == NULL)
+ return NULL;
+
+ name = name_of_child (parent, index);
+ gdb_value_struct_elt (NULL, &value, &temp, NULL, name, NULL,
+ "cplus_structure");
+ if (value != NULL)
+ release_value (value);
+
+ xfree (name);
+ }
+ else if (index >= TYPE_N_BASECLASSES (type))
+ {
+ /* public, private, or protected */
+ return NULL;
+ }
+ else
+ {
+ /* Baseclass */
+ if (parent->value != NULL)
+ {
+ struct value *temp = NULL;
+
+ if (TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_REF)
+ {
+ if (!gdb_value_ind (parent->value, &temp))
+ return NULL;
+ }
+ else
+ temp = parent->value;
+
+ if (temp != NULL)
+ {
+ value = value_cast (TYPE_FIELD_TYPE (type, index), temp);
+ release_value (value);
+ }
+ else
+ {
+ /* We failed to evaluate the parent's value, so don't even
+ bother trying to evaluate this child. */
+ return NULL;
+ }
+ }
+ }
+ }
+
+ if (value == NULL)
+ return c_value_of_child (parent, index);
+
+ return value;
+}
+
+static struct type *
+cplus_type_of_child (struct varobj *parent, int index)
+{
+ struct type *type, *t;
+
+ if (CPLUS_FAKE_CHILD (parent))
+ {
+ /* Looking for the type of a child of public, private, or protected. */
+ t = get_type_deref (parent->parent);
+ }
+ else
+ t = get_type_deref (parent);
+
+ type = NULL;
+ switch (TYPE_CODE (t))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ if (CPLUS_FAKE_CHILD (parent))
+ {
+ char *name = cplus_name_of_child (parent, index);
+ type = lookup_struct_elt_type (t, name, 0);
+ xfree (name);
+ }
+ else if (index < TYPE_N_BASECLASSES (t))
+ type = TYPE_FIELD_TYPE (t, index);
+ else
+ {
+ /* special */
+ return NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (type == NULL)
+ return c_type_of_child (parent, index);
+
+ return type;
+}
+
+static int
+cplus_variable_editable (struct varobj *var)
+{
+ if (CPLUS_FAKE_CHILD (var))
+ return 0;
+
+ return c_variable_editable (var);
+}
+
+static char *
+cplus_value_of_variable (struct varobj *var)
+{
+
+ /* If we have one of our special types, don't print out
+ any value. */
+ if (CPLUS_FAKE_CHILD (var))
+ return xstrdup ("");
+
+ return c_value_of_variable (var);
+}
+
+/* Java */
+
+static int
+java_number_of_children (struct varobj *var)
+{
+ return cplus_number_of_children (var);
+}
+
+static char *
+java_name_of_variable (struct varobj *parent)
+{
+ char *p, *name;
+
+ name = cplus_name_of_variable (parent);
+ /* If the name has "-" in it, it is because we
+ needed to escape periods in the name... */
+ p = name;
+
+ while (*p != '\000')
+ {
+ if (*p == '-')
+ *p = '.';
+ p++;
+ }
+
+ return name;
+}
+
+static char *
+java_name_of_child (struct varobj *parent, int index)
+{
+ char *name, *p;
+
+ name = cplus_name_of_child (parent, index);
+ /* Escape any periods in the name... */
+ p = name;
+
+ while (*p != '\000')
+ {
+ if (*p == '.')
+ *p = '-';
+ p++;
+ }
+
+ return name;
+}
+
+static struct value *
+java_value_of_root (struct varobj **var_handle)
+{
+ return cplus_value_of_root (var_handle);
+}
+
+static struct value *
+java_value_of_child (struct varobj *parent, int index)
+{
+ return cplus_value_of_child (parent, index);
+}
+
+static struct type *
+java_type_of_child (struct varobj *parent, int index)
+{
+ return cplus_type_of_child (parent, index);
+}
+
+static int
+java_variable_editable (struct varobj *var)
+{
+ return cplus_variable_editable (var);
+}
+
+static char *
+java_value_of_variable (struct varobj *var)
+{
+ return cplus_value_of_variable (var);
+}
+
+extern void _initialize_varobj (void);
+void
+_initialize_varobj (void)
+{
+ int sizeof_table = sizeof (struct vlist *) * VAROBJ_TABLE_SIZE;
+
+ varobj_table = xmalloc (sizeof_table);
+ memset (varobj_table, 0, sizeof_table);
+
+ add_show_from_set (add_set_cmd ("debugvarobj", class_maintenance, var_zinteger, (char *) &varobjdebug, "Set varobj debugging.\n\
+When non-zero, varobj debugging is enabled.", &setlist),
+ &showlist);
+}
diff --git a/contrib/gdb/gdb/varobj.h b/contrib/gdb/gdb/varobj.h
new file mode 100644
index 0000000..cd30233
--- /dev/null
+++ b/contrib/gdb/gdb/varobj.h
@@ -0,0 +1,100 @@
+/* GDB variable objects API.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef VAROBJ_H
+#define VAROBJ_H 1
+
+#include "symtab.h"
+#include "gdbtypes.h"
+
+/* Enumeration for the format types */
+enum varobj_display_formats
+ {
+ FORMAT_NATURAL, /* What gdb actually calls 'natural' */
+ FORMAT_BINARY, /* Binary display */
+ FORMAT_DECIMAL, /* Decimal display */
+ FORMAT_HEXADECIMAL, /* Hex display */
+ FORMAT_OCTAL /* Octal display */
+ };
+
+enum varobj_type
+ {
+ USE_SPECIFIED_FRAME, /* Use the frame passed to varobj_create */
+ USE_CURRENT_FRAME, /* Use the current frame */
+ USE_SELECTED_FRAME /* Always reevaluate in selected frame */
+ };
+
+/* String representations of gdb's format codes (defined in varobj.c) */
+extern char *varobj_format_string[];
+
+/* Languages supported by this variable objects system. */
+enum varobj_languages
+ {
+ vlang_unknown = 0, vlang_c, vlang_cplus, vlang_java, vlang_end
+ };
+
+/* String representations of gdb's known languages (defined in varobj.c) */
+extern char *varobj_language_string[];
+
+/* Struct thar describes a variable object instance */
+struct varobj;
+
+/* API functions */
+
+extern struct varobj *varobj_create (char *objname,
+ char *expression, CORE_ADDR frame,
+ enum varobj_type type);
+
+extern char *varobj_gen_name (void);
+
+extern struct varobj *varobj_get_handle (char *name);
+
+extern char *varobj_get_objname (struct varobj *var);
+
+extern char *varobj_get_expression (struct varobj *var);
+
+extern int varobj_delete (struct varobj *var, char ***dellist,
+ int only_children);
+
+extern enum varobj_display_formats varobj_set_display_format (
+ struct varobj *var,
+ enum varobj_display_formats format);
+
+extern enum varobj_display_formats varobj_get_display_format (
+ struct varobj *var);
+
+extern int varobj_get_num_children (struct varobj *var);
+
+extern int varobj_list_children (struct varobj *var,
+ struct varobj ***childlist);
+
+extern char *varobj_get_type (struct varobj *var);
+
+extern enum varobj_languages varobj_get_language (struct varobj *var);
+
+extern int varobj_get_attributes (struct varobj *var);
+
+extern char *varobj_get_value (struct varobj *var);
+
+extern int varobj_set_value (struct varobj *var, char *expression);
+
+extern int varobj_list (struct varobj ***rootlist);
+
+extern int varobj_update (struct varobj **varp, struct varobj ***changelist);
+
+#endif /* VAROBJ_H */
diff --git a/contrib/gdb/gdb/version.h b/contrib/gdb/gdb/version.h
new file mode 100644
index 0000000..b324af9
--- /dev/null
+++ b/contrib/gdb/gdb/version.h
@@ -0,0 +1,33 @@
+/* Version information for GDB.
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef VERSION_H
+#define VERSION_H
+
+/* Version number of GDB, as a string. */
+extern const char version[];
+
+/* Canonical host name as a string. */
+extern const char host_name[];
+
+/* Canonical target name as a string. */
+extern const char target_name[];
+
+#endif /* #ifndef VERSION_H */
diff --git a/contrib/gdb/gdb/version.in b/contrib/gdb/gdb/version.in
new file mode 100644
index 0000000..f3b5af3
--- /dev/null
+++ b/contrib/gdb/gdb/version.in
@@ -0,0 +1 @@
+6.1.1
diff --git a/contrib/gdb/gdb/win32-nat.c b/contrib/gdb/gdb/win32-nat.c
new file mode 100644
index 0000000..8b26916
--- /dev/null
+++ b/contrib/gdb/gdb/win32-nat.c
@@ -0,0 +1,2460 @@
+/* Target-vector operations for controlling win32 child processes, for GDB.
+
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free
+ Software Foundation, Inc.
+
+ Contributed by Cygnus Solutions, A Red Hat Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Originally by Steve Chamberlain, sac@cygnus.com */
+
+/* We assume we're being built with and will be used for cygwin. */
+
+#include "defs.h"
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "completer.h"
+#include "regcache.h"
+#include "top.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <imagehlp.h>
+#include <sys/cygwin.h>
+
+#include "buildsym.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h"
+#include "gdbthread.h"
+#include "gdbcmd.h"
+#include <sys/param.h>
+#include <unistd.h>
+#include "exec.h"
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+
+/* The ui's event loop. */
+extern int (*ui_loop_hook) (int signo);
+
+/* If we're not using the old Cygwin header file set, define the
+ following which never should have been in the generic Win32 API
+ headers in the first place since they were our own invention... */
+#ifndef _GNU_H_WINDOWS_H
+enum
+ {
+ FLAG_TRACE_BIT = 0x100,
+ CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
+ };
+#endif
+#include <sys/procfs.h>
+#include <psapi.h>
+
+#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
+ | CONTEXT_EXTENDED_REGISTERS
+
+static unsigned dr[8];
+static int debug_registers_changed;
+static int debug_registers_used;
+
+/* The string sent by cygwin when it processes a signal.
+ FIXME: This should be in a cygwin include file. */
+#define CYGWIN_SIGNAL_STRING "cygwin: signal"
+
+#define CHECK(x) check (x, __FILE__,__LINE__)
+#define DEBUG_EXEC(x) if (debug_exec) printf_unfiltered x
+#define DEBUG_EVENTS(x) if (debug_events) printf_unfiltered x
+#define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x
+#define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x
+
+/* Forward declaration */
+extern struct target_ops child_ops;
+
+static void child_stop (void);
+static int win32_child_thread_alive (ptid_t);
+void child_kill_inferior (void);
+
+static enum target_signal last_sig = TARGET_SIGNAL_0;
+/* Set if a signal was received from the debugged process */
+
+/* Thread information structure used to track information that is
+ not available in gdb's thread structure. */
+typedef struct thread_info_struct
+ {
+ struct thread_info_struct *next;
+ DWORD id;
+ HANDLE h;
+ char *name;
+ int suspend_count;
+ int reload_context;
+ CONTEXT context;
+ STACKFRAME sf;
+ }
+thread_info;
+
+static thread_info thread_head;
+
+/* The process and thread handles for the above context. */
+
+static DEBUG_EVENT current_event; /* The current debug event from
+ WaitForDebugEvent */
+static HANDLE current_process_handle; /* Currently executing process */
+static thread_info *current_thread; /* Info on currently selected thread */
+static DWORD main_thread_id; /* Thread ID of the main thread */
+
+/* Counts of things. */
+static int exception_count = 0;
+static int event_count = 0;
+static int saw_create;
+
+/* User options. */
+static int new_console = 0;
+static int new_group = 1;
+static int debug_exec = 0; /* show execution */
+static int debug_events = 0; /* show events from kernel */
+static int debug_memory = 0; /* show target memory accesses */
+static int debug_exceptions = 0; /* show target exceptions */
+static int useshell = 0; /* use shell for subprocesses */
+
+/* This vector maps GDB's idea of a register's number into an address
+ in the win32 exception context vector.
+
+ It also contains the bit mask needed to load the register in question.
+
+ One day we could read a reg, we could inspect the context we
+ already have loaded, if it doesn't have the bit set that we need,
+ we read that set of registers in using GetThreadContext. If the
+ context already contains what we need, we just unpack it. Then to
+ write a register, first we have to ensure that the context contains
+ the other regs of the group, and then we copy the info in and set
+ out bit. */
+
+#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
+static const int mappings[] =
+{
+ context_offset (Eax),
+ context_offset (Ecx),
+ context_offset (Edx),
+ context_offset (Ebx),
+ context_offset (Esp),
+ context_offset (Ebp),
+ context_offset (Esi),
+ context_offset (Edi),
+ context_offset (Eip),
+ context_offset (EFlags),
+ context_offset (SegCs),
+ context_offset (SegSs),
+ context_offset (SegDs),
+ context_offset (SegEs),
+ context_offset (SegFs),
+ context_offset (SegGs),
+ context_offset (FloatSave.RegisterArea[0 * 10]),
+ context_offset (FloatSave.RegisterArea[1 * 10]),
+ context_offset (FloatSave.RegisterArea[2 * 10]),
+ context_offset (FloatSave.RegisterArea[3 * 10]),
+ context_offset (FloatSave.RegisterArea[4 * 10]),
+ context_offset (FloatSave.RegisterArea[5 * 10]),
+ context_offset (FloatSave.RegisterArea[6 * 10]),
+ context_offset (FloatSave.RegisterArea[7 * 10]),
+ context_offset (FloatSave.ControlWord),
+ context_offset (FloatSave.StatusWord),
+ context_offset (FloatSave.TagWord),
+ context_offset (FloatSave.ErrorSelector),
+ context_offset (FloatSave.ErrorOffset),
+ context_offset (FloatSave.DataSelector),
+ context_offset (FloatSave.DataOffset),
+ context_offset (FloatSave.ErrorSelector)
+ /* XMM0-7 */ ,
+ context_offset (ExtendedRegisters[10*16]),
+ context_offset (ExtendedRegisters[11*16]),
+ context_offset (ExtendedRegisters[12*16]),
+ context_offset (ExtendedRegisters[13*16]),
+ context_offset (ExtendedRegisters[14*16]),
+ context_offset (ExtendedRegisters[15*16]),
+ context_offset (ExtendedRegisters[16*16]),
+ context_offset (ExtendedRegisters[17*16]),
+ /* MXCSR */
+ context_offset (ExtendedRegisters[24])
+};
+
+#undef context_offset
+
+/* This vector maps the target's idea of an exception (extracted
+ from the DEBUG_EVENT structure) to GDB's idea. */
+
+struct xlate_exception
+ {
+ int them;
+ enum target_signal us;
+ };
+
+static const struct xlate_exception
+ xlate[] =
+{
+ {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV},
+ {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV},
+ {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP},
+ {DBG_CONTROL_C, TARGET_SIGNAL_INT},
+ {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
+ {STATUS_FLOAT_DIVIDE_BY_ZERO, TARGET_SIGNAL_FPE},
+ {-1, -1}};
+
+static void
+check (BOOL ok, const char *file, int line)
+{
+ if (!ok)
+ printf_filtered ("error return %s:%d was %lu\n", file, line,
+ GetLastError ());
+}
+
+/* Find a thread record given a thread id.
+ If get_context then also retrieve the context for this
+ thread. */
+static thread_info *
+thread_rec (DWORD id, int get_context)
+{
+ thread_info *th;
+
+ for (th = &thread_head; (th = th->next) != NULL;)
+ if (th->id == id)
+ {
+ if (!th->suspend_count && get_context)
+ {
+ if (get_context > 0 && id != current_event.dwThreadId)
+ th->suspend_count = SuspendThread (th->h) + 1;
+ else if (get_context < 0)
+ th->suspend_count = -1;
+ th->reload_context = 1;
+ }
+ return th;
+ }
+
+ return NULL;
+}
+
+/* Add a thread to the thread list */
+static thread_info *
+child_add_thread (DWORD id, HANDLE h)
+{
+ thread_info *th;
+
+ if ((th = thread_rec (id, FALSE)))
+ return th;
+
+ th = (thread_info *) xmalloc (sizeof (*th));
+ memset (th, 0, sizeof (*th));
+ th->id = id;
+ th->h = h;
+ th->next = thread_head.next;
+ thread_head.next = th;
+ add_thread (pid_to_ptid (id));
+ /* Set the debug registers for the new thread in they are used. */
+ if (debug_registers_used)
+ {
+ /* Only change the value of the debug registers. */
+ th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ CHECK (GetThreadContext (th->h, &th->context));
+ th->context.Dr0 = dr[0];
+ th->context.Dr1 = dr[1];
+ th->context.Dr2 = dr[2];
+ th->context.Dr3 = dr[3];
+ /* th->context.Dr6 = dr[6];
+ FIXME: should we set dr6 also ?? */
+ th->context.Dr7 = dr[7];
+ CHECK (SetThreadContext (th->h, &th->context));
+ th->context.ContextFlags = 0;
+ }
+ return th;
+}
+
+/* Clear out any old thread list and reintialize it to a
+ pristine state. */
+static void
+child_init_thread_list (void)
+{
+ thread_info *th = &thread_head;
+
+ DEBUG_EVENTS (("gdb: child_init_thread_list\n"));
+ init_thread_list ();
+ while (th->next != NULL)
+ {
+ thread_info *here = th->next;
+ th->next = here->next;
+ (void) CloseHandle (here->h);
+ xfree (here);
+ }
+}
+
+/* Delete a thread from the list of threads */
+static void
+child_delete_thread (DWORD id)
+{
+ thread_info *th;
+
+ if (info_verbose)
+ printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (pid_to_ptid (id)));
+ delete_thread (pid_to_ptid (id));
+
+ for (th = &thread_head;
+ th->next != NULL && th->next->id != id;
+ th = th->next)
+ continue;
+
+ if (th->next != NULL)
+ {
+ thread_info *here = th->next;
+ th->next = here->next;
+ CloseHandle (here->h);
+ xfree (here);
+ }
+}
+
+static void
+do_child_fetch_inferior_registers (int r)
+{
+ char *context_offset = ((char *) &current_thread->context) + mappings[r];
+ long l;
+
+ if (!current_thread)
+ return; /* Windows sometimes uses a non-existent thread id in its
+ events */
+
+ if (current_thread->reload_context)
+ {
+ thread_info *th = current_thread;
+ th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
+ GetThreadContext (th->h, &th->context);
+ /* Copy dr values from that thread. */
+ dr[0] = th->context.Dr0;
+ dr[1] = th->context.Dr1;
+ dr[2] = th->context.Dr2;
+ dr[3] = th->context.Dr3;
+ dr[6] = th->context.Dr6;
+ dr[7] = th->context.Dr7;
+ current_thread->reload_context = 0;
+ }
+
+#define I387_ST0_REGNUM I386_ST0_REGNUM
+
+ if (r == I387_FISEG_REGNUM)
+ {
+ l = *((long *) context_offset) & 0xffff;
+ supply_register (r, (char *) &l);
+ }
+ else if (r == I387_FOP_REGNUM)
+ {
+ l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
+ supply_register (r, (char *) &l);
+ }
+ else if (r >= 0)
+ supply_register (r, context_offset);
+ else
+ {
+ for (r = 0; r < NUM_REGS; r++)
+ do_child_fetch_inferior_registers (r);
+ }
+
+#undef I387_ST0_REGNUM
+}
+
+static void
+child_fetch_inferior_registers (int r)
+{
+ current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
+ /* Check if current_thread exists. Windows sometimes uses a non-existent
+ thread id in its events */
+ if (current_thread)
+ do_child_fetch_inferior_registers (r);
+}
+
+static void
+do_child_store_inferior_registers (int r)
+{
+ if (!current_thread)
+ /* Windows sometimes uses a non-existent thread id in its events */;
+ else if (r >= 0)
+ regcache_collect (r, ((char *) &current_thread->context) + mappings[r]);
+ else
+ {
+ for (r = 0; r < NUM_REGS; r++)
+ do_child_store_inferior_registers (r);
+ }
+}
+
+/* Store a new register value into the current thread context */
+static void
+child_store_inferior_registers (int r)
+{
+ current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
+ /* Check if current_thread exists. Windows sometimes uses a non-existent
+ thread id in its events */
+ if (current_thread)
+ do_child_store_inferior_registers (r);
+}
+
+static int psapi_loaded = 0;
+static HMODULE psapi_module_handle = NULL;
+static BOOL WINAPI (*psapi_EnumProcessModules) (HANDLE, HMODULE *, DWORD, LPDWORD) = NULL;
+static BOOL WINAPI (*psapi_GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, DWORD) = NULL;
+static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, DWORD) = NULL;
+
+int
+psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
+{
+ DWORD len;
+ MODULEINFO mi;
+ int i;
+ HMODULE dh_buf[1];
+ HMODULE *DllHandle = dh_buf;
+ DWORD cbNeeded;
+ BOOL ok;
+
+ if (!psapi_loaded ||
+ psapi_EnumProcessModules == NULL ||
+ psapi_GetModuleInformation == NULL ||
+ psapi_GetModuleFileNameExA == NULL)
+ {
+ if (psapi_loaded)
+ goto failed;
+ psapi_loaded = 1;
+ psapi_module_handle = LoadLibrary ("psapi.dll");
+ if (!psapi_module_handle)
+ {
+ /* printf_unfiltered ("error loading psapi.dll: %u", GetLastError ()); */
+ goto failed;
+ }
+ psapi_EnumProcessModules = GetProcAddress (psapi_module_handle, "EnumProcessModules");
+ psapi_GetModuleInformation = GetProcAddress (psapi_module_handle, "GetModuleInformation");
+ psapi_GetModuleFileNameExA = (void *) GetProcAddress (psapi_module_handle,
+ "GetModuleFileNameExA");
+ if (psapi_EnumProcessModules == NULL ||
+ psapi_GetModuleInformation == NULL ||
+ psapi_GetModuleFileNameExA == NULL)
+ goto failed;
+ }
+
+ cbNeeded = 0;
+ ok = (*psapi_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ sizeof (HMODULE),
+ &cbNeeded);
+
+ if (!ok || !cbNeeded)
+ goto failed;
+
+ DllHandle = (HMODULE *) alloca (cbNeeded);
+ if (!DllHandle)
+ goto failed;
+
+ ok = (*psapi_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ cbNeeded,
+ &cbNeeded);
+ if (!ok)
+ goto failed;
+
+ for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++)
+ {
+ if (!(*psapi_GetModuleInformation) (current_process_handle,
+ DllHandle[i],
+ &mi,
+ sizeof (mi)))
+ error ("Can't get module info");
+
+ len = (*psapi_GetModuleFileNameExA) (current_process_handle,
+ DllHandle[i],
+ dll_name_ret,
+ MAX_PATH);
+ if (len == 0)
+ error ("Error getting dll name: %u\n", (unsigned) GetLastError ());
+
+ if ((DWORD) (mi.lpBaseOfDll) == BaseAddress)
+ return 1;
+ }
+
+failed:
+ dll_name_ret[0] = '\0';
+ return 0;
+}
+
+/* Encapsulate the information required in a call to
+ symbol_file_add_args */
+struct safe_symbol_file_add_args
+{
+ char *name;
+ int from_tty;
+ struct section_addr_info *addrs;
+ int mainline;
+ int flags;
+ struct ui_file *err, *out;
+ struct objfile *ret;
+};
+
+/* Maintain a linked list of "so" information. */
+struct so_stuff
+{
+ struct so_stuff *next;
+ DWORD load_addr;
+ DWORD end_addr;
+ int loaded;
+ struct objfile *objfile;
+ char name[1];
+} solib_start, *solib_end;
+
+/* Call symbol_file_add with stderr redirected. We don't care if there
+ are errors. */
+static int
+safe_symbol_file_add_stub (void *argv)
+{
+#define p ((struct safe_symbol_file_add_args *)argv)
+ struct so_stuff *so = &solib_start;
+
+ while ((so = so->next))
+ if (so->loaded && strcasecmp (so->name, p->name) == 0)
+ return 0;
+ p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags);
+ return !!p->ret;
+#undef p
+}
+
+/* Restore gdb's stderr after calling symbol_file_add */
+static void
+safe_symbol_file_add_cleanup (void *p)
+{
+#define sp ((struct safe_symbol_file_add_args *)p)
+ gdb_flush (gdb_stderr);
+ gdb_flush (gdb_stdout);
+ ui_file_delete (gdb_stderr);
+ ui_file_delete (gdb_stdout);
+ gdb_stderr = sp->err;
+ gdb_stdout = sp->out;
+#undef sp
+}
+
+/* symbol_file_add wrapper that prevents errors from being displayed. */
+static struct objfile *
+safe_symbol_file_add (char *name, int from_tty,
+ struct section_addr_info *addrs,
+ int mainline, int flags)
+{
+ struct safe_symbol_file_add_args p;
+ struct cleanup *cleanup;
+
+ cleanup = make_cleanup (safe_symbol_file_add_cleanup, &p);
+
+ p.err = gdb_stderr;
+ p.out = gdb_stdout;
+ gdb_flush (gdb_stderr);
+ gdb_flush (gdb_stdout);
+ gdb_stderr = ui_file_new ();
+ gdb_stdout = ui_file_new ();
+ p.name = name;
+ p.from_tty = from_tty;
+ p.addrs = addrs;
+ p.mainline = mainline;
+ p.flags = flags;
+ catch_errors (safe_symbol_file_add_stub, &p, "", RETURN_MASK_ERROR);
+
+ do_cleanups (cleanup);
+ return p.ret;
+}
+
+/* Remember the maximum DLL length for printing in info dll command. */
+int max_dll_name_len;
+
+static void
+register_loaded_dll (const char *name, DWORD load_addr)
+{
+ struct so_stuff *so;
+ char ppath[MAX_PATH + 1];
+ char buf[MAX_PATH + 1];
+ char cwd[MAX_PATH + 1];
+ char *p;
+ WIN32_FIND_DATA w32_fd;
+ HANDLE h = FindFirstFile(name, &w32_fd);
+ MEMORY_BASIC_INFORMATION m;
+ size_t len;
+
+ if (h == INVALID_HANDLE_VALUE)
+ strcpy (buf, name);
+ else
+ {
+ FindClose (h);
+ strcpy (buf, name);
+ if (GetCurrentDirectory (MAX_PATH + 1, cwd))
+ {
+ p = strrchr (buf, '\\');
+ if (p)
+ p[1] = '\0';
+ SetCurrentDirectory (buf);
+ GetFullPathName (w32_fd.cFileName, MAX_PATH, buf, &p);
+ SetCurrentDirectory (cwd);
+ }
+ }
+
+ cygwin_conv_to_posix_path (buf, ppath);
+ so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (ppath) + 8 + 1);
+ so->loaded = 0;
+ so->load_addr = load_addr;
+ if (VirtualQueryEx (current_process_handle, (void *) load_addr, &m,
+ sizeof (m)))
+ so->end_addr = (DWORD) m.AllocationBase + m.RegionSize;
+ else
+ so->end_addr = load_addr + 0x2000; /* completely arbitrary */
+
+ so->next = NULL;
+ so->objfile = NULL;
+ strcpy (so->name, ppath);
+
+ solib_end->next = so;
+ solib_end = so;
+ len = strlen (ppath);
+ if (len > max_dll_name_len)
+ max_dll_name_len = len;
+}
+
+char *
+get_image_name (HANDLE h, void *address, int unicode)
+{
+ static char buf[(2 * MAX_PATH) + 1];
+ DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
+ char *address_ptr;
+ int len = 0;
+ char b[2];
+ DWORD done;
+
+ /* Attempt to read the name of the dll that was detected.
+ This is documented to work only when actively debugging
+ a program. It will not work for attached processes. */
+ if (address == NULL)
+ return NULL;
+
+ /* See if we could read the address of a string, and that the
+ address isn't null. */
+ if (!ReadProcessMemory (h, address, &address_ptr, sizeof (address_ptr), &done)
+ || done != sizeof (address_ptr) || !address_ptr)
+ return NULL;
+
+ /* Find the length of the string */
+ while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
+ && (b[0] != 0 || b[size - 1] != 0) && done == size)
+ continue;
+
+ if (!unicode)
+ ReadProcessMemory (h, address_ptr, buf, len, &done);
+ else
+ {
+ WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
+ ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
+ &done);
+
+ WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0);
+ }
+
+ return buf;
+}
+
+/* Wait for child to do something. Return pid of child, or -1 in case
+ of error; store status through argument pointer OURSTATUS. */
+static int
+handle_load_dll (void *dummy)
+{
+ LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
+ char dll_buf[MAX_PATH + 1];
+ char *dll_name = NULL;
+ char *p;
+
+ dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+
+ if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
+ dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+
+ dll_name = dll_buf;
+
+ if (*dll_name == '\0')
+ dll_name = get_image_name (current_process_handle, event->lpImageName, event->fUnicode);
+ if (!dll_name)
+ return 1;
+
+ register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000);
+
+ return 1;
+}
+
+static int
+handle_unload_dll (void *dummy)
+{
+ DWORD lpBaseOfDll = (DWORD) current_event.u.UnloadDll.lpBaseOfDll + 0x1000;
+ struct so_stuff *so;
+
+ for (so = &solib_start; so->next != NULL; so = so->next)
+ if (so->next->load_addr == lpBaseOfDll)
+ {
+ struct so_stuff *sodel = so->next;
+ so->next = sodel->next;
+ if (!so->next)
+ solib_end = so;
+ if (sodel->objfile)
+ free_objfile (sodel->objfile);
+ xfree(sodel);
+ return 1;
+ }
+ error ("Error: dll starting at 0x%lx not found.\n", (DWORD) lpBaseOfDll);
+
+ return 0;
+}
+
+char *
+solib_address (CORE_ADDR address)
+{
+ struct so_stuff *so;
+ for (so = &solib_start; so->next != NULL; so = so->next)
+ if (address >= so->load_addr && address <= so->end_addr)
+ return so->name;
+ return NULL;
+}
+
+/* Return name of last loaded DLL. */
+char *
+child_solib_loaded_library_pathname (int pid)
+{
+ return !solib_end || !solib_end->name[0] ? NULL : solib_end->name;
+}
+
+/* Clear list of loaded DLLs. */
+void
+child_clear_solibs (void)
+{
+ struct so_stuff *so, *so1 = solib_start.next;
+
+ while ((so = so1) != NULL)
+ {
+ so1 = so->next;
+ xfree (so);
+ }
+
+ solib_start.next = NULL;
+ solib_start.objfile = NULL;
+ solib_end = &solib_start;
+ max_dll_name_len = sizeof ("DLL Name") - 1;
+}
+
+/* Get the loaded address of all sections, given that .text was loaded
+ at text_load. Assumes that all sections are subject to the same
+ relocation offset. Returns NULL if problems occur or if the
+ sections were not relocated. */
+
+static struct section_addr_info *
+get_relocated_section_addrs (bfd *abfd, CORE_ADDR text_load)
+{
+ struct section_addr_info *result = NULL;
+ int section_count = bfd_count_sections (abfd);
+ asection *text_section = bfd_get_section_by_name (abfd, ".text");
+ CORE_ADDR text_vma;
+
+ if (!text_section)
+ {
+ /* Couldn't get the .text section. Weird. */
+ }
+
+ else if (text_load == (text_vma = bfd_get_section_vma (abfd, text_section)))
+ {
+ /* DLL wasn't relocated. */
+ }
+
+ else
+ {
+ /* Figure out all sections' loaded addresses. The offset here is
+ such that taking a bfd_get_section_vma() result and adding
+ offset will give the real load address of the section. */
+
+ CORE_ADDR offset = text_load - text_vma;
+
+ struct section_table *table_start = NULL;
+ struct section_table *table_end = NULL;
+ struct section_table *iter = NULL;
+
+ build_section_table (abfd, &table_start, &table_end);
+
+ for (iter = table_start; iter < table_end; ++iter)
+ {
+ /* Relocated addresses. */
+ iter->addr += offset;
+ iter->endaddr += offset;
+ }
+
+ result = build_section_addr_info_from_section_table (table_start,
+ table_end);
+
+ xfree (table_start);
+ }
+
+ return result;
+}
+
+/* Add DLL symbol information. */
+static struct objfile *
+solib_symbols_add (char *name, int from_tty, CORE_ADDR load_addr)
+{
+ struct section_addr_info *addrs = NULL;
+ static struct objfile *result = NULL;
+ bfd *abfd = NULL;
+
+ /* The symbols in a dll are offset by 0x1000, which is the
+ the offset from 0 of the first byte in an image - because
+ of the file header and the section alignment. */
+
+ if (!name || !name[0])
+ return NULL;
+
+ abfd = bfd_openr (name, "pei-i386");
+
+ if (!abfd)
+ {
+ /* pei failed - try pe */
+ abfd = bfd_openr (name, "pe-i386");
+ }
+
+ if (abfd)
+ {
+ if (bfd_check_format (abfd, bfd_object))
+ {
+ addrs = get_relocated_section_addrs (abfd, load_addr);
+ }
+
+ bfd_close (abfd);
+ }
+
+ if (addrs)
+ {
+ result = safe_symbol_file_add (name, from_tty, addrs, 0, OBJF_SHARED);
+ free_section_addr_info (addrs);
+ }
+ else
+ {
+ /* Fallback on handling just the .text section. */
+ struct cleanup *my_cleanups;
+
+ addrs = alloc_section_addr_info (1);
+ my_cleanups = make_cleanup (xfree, addrs);
+ addrs->other[0].name = ".text";
+ addrs->other[0].addr = load_addr;
+
+ result = safe_symbol_file_add (name, from_tty, addrs, 0, OBJF_SHARED);
+ do_cleanups (my_cleanups);
+ }
+
+ return result;
+}
+
+/* Load DLL symbol info. */
+void
+dll_symbol_command (char *args, int from_tty)
+{
+ int n;
+ dont_repeat ();
+
+ if (args == NULL)
+ error ("dll-symbols requires a file name");
+
+ n = strlen (args);
+ if (n > 4 && strcasecmp (args + n - 4, ".dll") != 0)
+ {
+ char *newargs = (char *) alloca (n + 4 + 1);
+ strcpy (newargs, args);
+ strcat (newargs, ".dll");
+ args = newargs;
+ }
+
+ safe_symbol_file_add (args, from_tty, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
+}
+
+/* List currently loaded DLLs. */
+void
+info_dll_command (char *ignore, int from_tty)
+{
+ struct so_stuff *so = &solib_start;
+
+ if (!so->next)
+ return;
+
+ printf_filtered ("%*s Load Address\n", -max_dll_name_len, "DLL Name");
+ while ((so = so->next) != NULL)
+ printf_filtered ("%*s %08lx\n", -max_dll_name_len, so->name, so->load_addr);
+
+ return;
+}
+
+/* Handle DEBUG_STRING output from child process.
+ Cygwin prepends its messages with a "cygwin:". Interpret this as
+ a Cygwin signal. Otherwise just print the string as a warning. */
+static int
+handle_output_debug_string (struct target_waitstatus *ourstatus)
+{
+ char *s;
+ int gotasig = FALSE;
+
+ if (!target_read_string
+ ((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0)
+ || !s || !*s)
+ return gotasig;
+
+ if (strncmp (s, CYGWIN_SIGNAL_STRING, sizeof (CYGWIN_SIGNAL_STRING) - 1) != 0)
+ {
+ if (strncmp (s, "cYg", 3) != 0)
+ warning ("%s", s);
+ }
+ else
+ {
+ char *p;
+ int sig = strtol (s + sizeof (CYGWIN_SIGNAL_STRING) - 1, &p, 0);
+ gotasig = target_signal_from_host (sig);
+ ourstatus->value.sig = gotasig;
+ if (gotasig)
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ }
+
+ xfree (s);
+ return gotasig;
+}
+
+static int
+display_selector (HANDLE thread, DWORD sel)
+{
+ LDT_ENTRY info;
+ if (GetThreadSelectorEntry (thread, sel, &info))
+ {
+ int base, limit;
+ printf_filtered ("0x%03lx: ", sel);
+ if (!info.HighWord.Bits.Pres)
+ {
+ puts_filtered ("Segment not present\n");
+ return 0;
+ }
+ base = (info.HighWord.Bits.BaseHi << 24) +
+ (info.HighWord.Bits.BaseMid << 16)
+ + info.BaseLow;
+ limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
+ if (info.HighWord.Bits.Granularity)
+ limit = (limit << 12) | 0xfff;
+ printf_filtered ("base=0x%08x limit=0x%08x", base, limit);
+ if (info.HighWord.Bits.Default_Big)
+ puts_filtered(" 32-bit ");
+ else
+ puts_filtered(" 16-bit ");
+ switch ((info.HighWord.Bits.Type & 0xf) >> 1)
+ {
+ case 0:
+ puts_filtered ("Data (Read-Only, Exp-up");
+ break;
+ case 1:
+ puts_filtered ("Data (Read/Write, Exp-up");
+ break;
+ case 2:
+ puts_filtered ("Unused segment (");
+ break;
+ case 3:
+ puts_filtered ("Data (Read/Write, Exp-down");
+ break;
+ case 4:
+ puts_filtered ("Code (Exec-Only, N.Conf");
+ break;
+ case 5:
+ puts_filtered ("Code (Exec/Read, N.Conf");
+ break;
+ case 6:
+ puts_filtered ("Code (Exec-Only, Conf");
+ break;
+ case 7:
+ puts_filtered ("Code (Exec/Read, Conf");
+ break;
+ default:
+ printf_filtered ("Unknown type 0x%x",info.HighWord.Bits.Type);
+ }
+ if ((info.HighWord.Bits.Type & 0x1) == 0)
+ puts_filtered(", N.Acc");
+ puts_filtered (")\n");
+ if ((info.HighWord.Bits.Type & 0x10) == 0)
+ puts_filtered("System selector ");
+ printf_filtered ("Priviledge level = %d. ", info.HighWord.Bits.Dpl);
+ if (info.HighWord.Bits.Granularity)
+ puts_filtered ("Page granular.\n");
+ else
+ puts_filtered ("Byte granular.\n");
+ return 1;
+ }
+ else
+ {
+ printf_filtered ("Invalid selector 0x%lx.\n",sel);
+ return 0;
+ }
+}
+
+static void
+display_selectors (char * args, int from_tty)
+{
+ if (!current_thread)
+ {
+ puts_filtered ("Impossible to display selectors now.\n");
+ return;
+ }
+ if (!args)
+ {
+
+ puts_filtered ("Selector $cs\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegCs);
+ puts_filtered ("Selector $ds\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegDs);
+ puts_filtered ("Selector $es\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegEs);
+ puts_filtered ("Selector $ss\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegSs);
+ puts_filtered ("Selector $fs\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegFs);
+ puts_filtered ("Selector $gs\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegGs);
+ }
+ else
+ {
+ int sel;
+ sel = parse_and_eval_long (args);
+ printf_filtered ("Selector \"%s\"\n",args);
+ display_selector (current_thread->h, sel);
+ }
+}
+
+static struct cmd_list_element *info_w32_cmdlist = NULL;
+
+static void
+info_w32_command (char *args, int from_tty)
+{
+ help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout);
+}
+
+
+#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
+ printf_unfiltered ("gdb: Target exception %s at 0x%08lx\n", x, \
+ (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)
+
+static int
+handle_exception (struct target_waitstatus *ourstatus)
+{
+ thread_info *th;
+ DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
+
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+
+ /* Record the context of the current thread */
+ th = thread_rec (current_event.dwThreadId, -1);
+
+ switch (code)
+ {
+ case EXCEPTION_ACCESS_VIOLATION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
+ ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ break;
+ case STATUS_STACK_OVERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
+ ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ break;
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_INEXACT_RESULT:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_INVALID_OPERATION:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_OVERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_STACK_CHECK:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_UNDERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case STATUS_INTEGER_OVERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
+ ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ break;
+ case EXCEPTION_BREAKPOINT:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ case DBG_CONTROL_C:
+ DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
+ ourstatus->value.sig = TARGET_SIGNAL_INT;
+ break;
+ case DBG_CONTROL_BREAK:
+ DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
+ ourstatus->value.sig = TARGET_SIGNAL_INT;
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP");
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
+ ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
+ ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ break;
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
+ ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ break;
+ default:
+ if (current_event.u.Exception.dwFirstChance)
+ return 0;
+ printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n",
+ current_event.u.Exception.ExceptionRecord.ExceptionCode,
+ (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress);
+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ break;
+ }
+ exception_count++;
+ last_sig = ourstatus->value.sig;
+ return 1;
+}
+
+/* Resume all artificially suspended threads if we are continuing
+ execution */
+static BOOL
+child_continue (DWORD continue_status, int id)
+{
+ int i;
+ thread_info *th;
+ BOOL res;
+
+ DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, %s);\n",
+ current_event.dwProcessId, current_event.dwThreadId,
+ continue_status == DBG_CONTINUE ?
+ "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED"));
+ res = ContinueDebugEvent (current_event.dwProcessId,
+ current_event.dwThreadId,
+ continue_status);
+ continue_status = 0;
+ if (res)
+ for (th = &thread_head; (th = th->next) != NULL;)
+ if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
+ {
+
+ for (i = 0; i < th->suspend_count; i++)
+ (void) ResumeThread (th->h);
+ th->suspend_count = 0;
+ if (debug_registers_changed)
+ {
+ /* Only change the value of the debug registers */
+ th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ th->context.Dr0 = dr[0];
+ th->context.Dr1 = dr[1];
+ th->context.Dr2 = dr[2];
+ th->context.Dr3 = dr[3];
+ /* th->context.Dr6 = dr[6];
+ FIXME: should we set dr6 also ?? */
+ th->context.Dr7 = dr[7];
+ CHECK (SetThreadContext (th->h, &th->context));
+ th->context.ContextFlags = 0;
+ }
+ }
+
+ debug_registers_changed = 0;
+ return res;
+}
+
+/* Called in pathological case where Windows fails to send a
+ CREATE_PROCESS_DEBUG_EVENT after an attach. */
+DWORD
+fake_create_process (void)
+{
+ current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE,
+ current_event.dwProcessId);
+ main_thread_id = current_event.dwThreadId;
+ current_thread = child_add_thread (main_thread_id,
+ current_event.u.CreateThread.hThread);
+ return main_thread_id;
+}
+
+/* Get the next event from the child. Return 1 if the event requires
+ handling by WFI (or whatever).
+ */
+static int
+get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
+{
+ BOOL debug_event;
+ DWORD continue_status, event_code;
+ thread_info *th;
+ static thread_info dummy_thread_info;
+ int retval = 0;
+
+ last_sig = TARGET_SIGNAL_0;
+
+ if (!(debug_event = WaitForDebugEvent (&current_event, 1000)))
+ goto out;
+
+ event_count++;
+ continue_status = DBG_CONTINUE;
+
+ event_code = current_event.dwDebugEventCode;
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ th = NULL;
+
+ switch (event_code)
+ {
+ case CREATE_THREAD_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "CREATE_THREAD_DEBUG_EVENT"));
+ if (saw_create != 1)
+ {
+ if (!saw_create && attach_flag)
+ {
+ /* Kludge around a Windows bug where first event is a create
+ thread event. Caused when attached process does not have
+ a main thread. */
+ retval = ourstatus->value.related_pid = fake_create_process ();
+ saw_create++;
+ }
+ break;
+ }
+ /* Record the existence of this thread */
+ th = child_add_thread (current_event.dwThreadId,
+ current_event.u.CreateThread.hThread);
+ if (info_verbose)
+ printf_unfiltered ("[New %s]\n",
+ target_pid_to_str (
+ pid_to_ptid (current_event.dwThreadId)));
+ retval = current_event.dwThreadId;
+ break;
+
+ case EXIT_THREAD_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXIT_THREAD_DEBUG_EVENT"));
+ if (current_event.dwThreadId != main_thread_id)
+ {
+ child_delete_thread (current_event.dwThreadId);
+ th = &dummy_thread_info;
+ }
+ break;
+
+ case CREATE_PROCESS_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "CREATE_PROCESS_DEBUG_EVENT"));
+ CloseHandle (current_event.u.CreateProcessInfo.hFile);
+ if (++saw_create != 1)
+ {
+ CloseHandle (current_event.u.CreateProcessInfo.hProcess);
+ break;
+ }
+
+ current_process_handle = current_event.u.CreateProcessInfo.hProcess;
+ if (main_thread_id)
+ child_delete_thread (main_thread_id);
+ main_thread_id = current_event.dwThreadId;
+ /* Add the main thread */
+ th = child_add_thread (main_thread_id,
+ current_event.u.CreateProcessInfo.hThread);
+ retval = ourstatus->value.related_pid = current_event.dwThreadId;
+ break;
+
+ case EXIT_PROCESS_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXIT_PROCESS_DEBUG_EVENT"));
+ if (saw_create != 1)
+ break;
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
+ CloseHandle (current_process_handle);
+ retval = main_thread_id;
+ break;
+
+ case LOAD_DLL_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "LOAD_DLL_DEBUG_EVENT"));
+ CloseHandle (current_event.u.LoadDll.hFile);
+ if (saw_create != 1)
+ break;
+ catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
+ registers_changed (); /* mark all regs invalid */
+ ourstatus->kind = TARGET_WAITKIND_LOADED;
+ ourstatus->value.integer = 0;
+ retval = main_thread_id;
+ re_enable_breakpoints_in_shlibs ();
+ break;
+
+ case UNLOAD_DLL_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "UNLOAD_DLL_DEBUG_EVENT"));
+ if (saw_create != 1)
+ break;
+ catch_errors (handle_unload_dll, NULL, (char *) "", RETURN_MASK_ALL);
+ registers_changed (); /* mark all regs invalid */
+ /* ourstatus->kind = TARGET_WAITKIND_UNLOADED;
+ does not exist yet. */
+ break;
+
+ case EXCEPTION_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXCEPTION_DEBUG_EVENT"));
+ if (saw_create != 1)
+ break;
+ if (handle_exception (ourstatus))
+ retval = current_event.dwThreadId;
+ break;
+
+ case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "OUTPUT_DEBUG_STRING_EVENT"));
+ if (saw_create != 1)
+ break;
+ if (handle_output_debug_string (ourstatus))
+ retval = main_thread_id;
+ break;
+
+ default:
+ if (saw_create != 1)
+ break;
+ printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n",
+ (DWORD) current_event.dwProcessId,
+ (DWORD) current_event.dwThreadId);
+ printf_unfiltered (" unknown event code %ld\n",
+ current_event.dwDebugEventCode);
+ break;
+ }
+
+ if (!retval || saw_create != 1)
+ CHECK (child_continue (continue_status, -1));
+ else
+ {
+ inferior_ptid = pid_to_ptid (retval);
+ current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
+ }
+
+out:
+ return retval;
+}
+
+/* Wait for interesting events to occur in the target process. */
+static ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ int pid = PIDGET (ptid);
+
+ /* We loop when we get a non-standard exception rather than return
+ with a SPURIOUS because resume can try and step or modify things,
+ which needs a current_thread->h. But some of these exceptions mark
+ the birth or death of threads, which mean that the current thread
+ isn't necessarily what you think it is. */
+
+ while (1)
+ {
+ int retval = get_child_debug_event (pid, ourstatus);
+ if (retval)
+ return pid_to_ptid (retval);
+ else
+ {
+ int detach = 0;
+
+ if (ui_loop_hook != NULL)
+ detach = ui_loop_hook (0);
+
+ if (detach)
+ child_kill_inferior ();
+ }
+ }
+}
+
+static void
+do_initial_child_stuff (DWORD pid)
+{
+ extern int stop_after_trap;
+ int i;
+
+ last_sig = TARGET_SIGNAL_0;
+ event_count = 0;
+ exception_count = 0;
+ debug_registers_changed = 0;
+ debug_registers_used = 0;
+ for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++)
+ dr[i] = 0;
+ current_event.dwProcessId = pid;
+ memset (&current_event, 0, sizeof (current_event));
+ push_target (&child_ops);
+ child_init_thread_list ();
+ disable_breakpoints_in_shlibs (1);
+ child_clear_solibs ();
+ clear_proceed_status ();
+ init_wait_for_inferior ();
+
+ target_terminal_init ();
+ target_terminal_inferior ();
+
+ while (1)
+ {
+ stop_after_trap = 1;
+ wait_for_inferior ();
+ if (stop_signal != TARGET_SIGNAL_TRAP)
+ resume (0, stop_signal);
+ else
+ break;
+ }
+ stop_after_trap = 0;
+ return;
+}
+
+/* Since Windows XP, detaching from a process is supported by Windows.
+ The following code tries loading the appropriate functions dynamically.
+ If loading these functions succeeds use them to actually detach from
+ the inferior process, otherwise behave as usual, pretending that
+ detach has worked. */
+static BOOL WINAPI (*DebugSetProcessKillOnExit)(BOOL);
+static BOOL WINAPI (*DebugActiveProcessStop)(DWORD);
+
+static int
+has_detach_ability (void)
+{
+ static HMODULE kernel32 = NULL;
+
+ if (!kernel32)
+ kernel32 = LoadLibrary ("kernel32.dll");
+ if (kernel32)
+ {
+ if (!DebugSetProcessKillOnExit)
+ DebugSetProcessKillOnExit = GetProcAddress (kernel32,
+ "DebugSetProcessKillOnExit");
+ if (!DebugActiveProcessStop)
+ DebugActiveProcessStop = GetProcAddress (kernel32,
+ "DebugActiveProcessStop");
+ if (DebugSetProcessKillOnExit && DebugActiveProcessStop)
+ return 1;
+ }
+ return 0;
+}
+
+/* Try to set or remove a user privilege to the current process. Return -1
+ if that fails, the previous setting of that privilege otherwise.
+
+ This code is copied from the Cygwin source code and rearranged to allow
+ dynamically loading of the needed symbols from advapi32 which is only
+ available on NT/2K/XP. */
+static int
+set_process_privilege (const char *privilege, BOOL enable)
+{
+ static HMODULE advapi32 = NULL;
+ static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE);
+ static BOOL WINAPI (*LookupPrivilegeValue)(LPCSTR, LPCSTR, PLUID);
+ static BOOL WINAPI (*AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES,
+ DWORD, PTOKEN_PRIVILEGES, PDWORD);
+
+ HANDLE token_hdl = NULL;
+ LUID restore_priv;
+ TOKEN_PRIVILEGES new_priv, orig_priv;
+ int ret = -1;
+ DWORD size;
+
+ if (GetVersion () >= 0x80000000) /* No security availbale on 9x/Me */
+ return 0;
+
+ if (!advapi32)
+ {
+ if (!(advapi32 = LoadLibrary ("advapi32.dll")))
+ goto out;
+ if (!OpenProcessToken)
+ OpenProcessToken = GetProcAddress (advapi32, "OpenProcessToken");
+ if (!LookupPrivilegeValue)
+ LookupPrivilegeValue = GetProcAddress (advapi32,
+ "LookupPrivilegeValueA");
+ if (!AdjustTokenPrivileges)
+ AdjustTokenPrivileges = GetProcAddress (advapi32,
+ "AdjustTokenPrivileges");
+ if (!OpenProcessToken || !LookupPrivilegeValue || !AdjustTokenPrivileges)
+ {
+ advapi32 = NULL;
+ goto out;
+ }
+ }
+
+ if (!OpenProcessToken (GetCurrentProcess (),
+ TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+ &token_hdl))
+ goto out;
+
+ if (!LookupPrivilegeValue (NULL, privilege, &restore_priv))
+ goto out;
+
+ new_priv.PrivilegeCount = 1;
+ new_priv.Privileges[0].Luid = restore_priv;
+ new_priv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
+
+ if (!AdjustTokenPrivileges (token_hdl, FALSE, &new_priv,
+ sizeof orig_priv, &orig_priv, &size))
+ goto out;
+#if 0
+ /* Disabled, otherwise every `attach' in an unprivileged user session
+ would raise the "Failed to get SE_DEBUG_NAME privilege" warning in
+ child_attach(). */
+ /* AdjustTokenPrivileges returns TRUE even if the privilege could not
+ be enabled. GetLastError () returns an correct error code, though. */
+ if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED)
+ goto out;
+#endif
+
+ ret = orig_priv.Privileges[0].Attributes == SE_PRIVILEGE_ENABLED ? 1 : 0;
+
+out:
+ if (token_hdl)
+ CloseHandle (token_hdl);
+
+ return ret;
+}
+
+/* Attach to process PID, then initialize for debugging it. */
+static void
+child_attach (char *args, int from_tty)
+{
+ BOOL ok;
+ DWORD pid;
+
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+ if (set_process_privilege (SE_DEBUG_NAME, TRUE) < 0)
+ {
+ printf_unfiltered ("Warning: Failed to get SE_DEBUG_NAME privilege\n");
+ printf_unfiltered ("This can cause attach to fail on Windows NT/2K/XP\n");
+ }
+
+ pid = strtoul (args, 0, 0); /* Windows pid */
+
+ ok = DebugActiveProcess (pid);
+ saw_create = 0;
+
+ if (!ok)
+ {
+ /* Try fall back to Cygwin pid */
+ pid = cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid);
+
+ if (pid > 0)
+ ok = DebugActiveProcess (pid);
+
+ if (!ok)
+ error ("Can't attach to process.");
+ }
+
+ if (has_detach_ability ())
+ DebugSetProcessKillOnExit (FALSE);
+
+ attach_flag = 1;
+
+ if (from_tty)
+ {
+ char *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_to_ptid (pid)));
+ else
+ printf_unfiltered ("Attaching to %s\n",
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ gdb_flush (gdb_stdout);
+ }
+
+ do_initial_child_stuff (pid);
+ target_terminal_ours ();
+}
+
+static void
+child_detach (char *args, int from_tty)
+{
+ int detached = 1;
+
+ if (has_detach_ability ())
+ {
+ delete_command (NULL, 0);
+ child_continue (DBG_CONTINUE, -1);
+ if (!DebugActiveProcessStop (current_event.dwProcessId))
+ {
+ error ("Can't detach process %lu (error %lu)",
+ current_event.dwProcessId, GetLastError ());
+ detached = 0;
+ }
+ DebugSetProcessKillOnExit (FALSE);
+ }
+ if (detached && from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf_unfiltered ("Detaching from program: %s, Pid %lu\n", exec_file,
+ current_event.dwProcessId);
+ gdb_flush (gdb_stdout);
+ }
+ inferior_ptid = null_ptid;
+ unpush_target (&child_ops);
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+child_files_info (struct target_ops *ignore)
+{
+ printf_unfiltered ("\tUsing the running image of %s %s.\n",
+ attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
+}
+
+static void
+child_open (char *arg, int from_tty)
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
+
+/* Start an inferior win32 child process and sets inferior_ptid 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 (char *exec_file, char *allargs, char **env)
+{
+ char *winenv;
+ char *temp;
+ int envlen;
+ int i;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ BOOL ret;
+ DWORD flags;
+ char *args;
+ char real_path[MAXPATHLEN];
+ char *toexec;
+ char shell[MAX_PATH + 1]; /* Path to shell */
+ const char *sh;
+ int tty;
+ int ostdin, ostdout, ostderr;
+
+ if (!exec_file)
+ error ("No executable specified, use `target exec'.\n");
+
+ memset (&si, 0, sizeof (si));
+ si.cb = sizeof (si);
+
+ if (!useshell)
+ {
+ flags = DEBUG_ONLY_THIS_PROCESS;
+ cygwin_conv_to_win32_path (exec_file, real_path);
+ toexec = real_path;
+ }
+ else
+ {
+ char *newallargs;
+ sh = getenv ("SHELL");
+ if (!sh)
+ sh = "/bin/sh";
+ cygwin_conv_to_win32_path (sh, shell);
+ newallargs = alloca (sizeof (" -c 'exec '") + strlen (exec_file)
+ + strlen (allargs) + 2);
+ sprintf (newallargs, " -c 'exec %s %s'", exec_file, allargs);
+ allargs = newallargs;
+ toexec = shell;
+ flags = DEBUG_PROCESS;
+ }
+
+ if (new_group)
+ flags |= CREATE_NEW_PROCESS_GROUP;
+
+ if (new_console)
+ flags |= CREATE_NEW_CONSOLE;
+
+ attach_flag = 0;
+
+ args = alloca (strlen (toexec) + strlen (allargs) + 2);
+ strcpy (args, toexec);
+ strcat (args, " ");
+ strcat (args, allargs);
+
+ /* Prepare the environment vars for CreateProcess. */
+ {
+ /* This code used to assume all env vars were file names and would
+ translate them all to win32 style. That obviously doesn't work in the
+ general case. The current rule is that we only translate PATH.
+ We need to handle PATH because we're about to call CreateProcess and
+ it uses PATH to find DLL's. Fortunately PATH has a well-defined value
+ in both posix and win32 environments. cygwin.dll will change it back
+ to posix style if necessary. */
+
+ static const char *conv_path_names[] =
+ {
+ "PATH=",
+ 0
+ };
+
+ /* CreateProcess takes the environment list as a null terminated set of
+ strings (i.e. two nulls terminate the list). */
+
+ /* Get total size for env strings. */
+ for (envlen = 0, i = 0; env[i] && *env[i]; i++)
+ {
+ int j, len;
+
+ for (j = 0; conv_path_names[j]; j++)
+ {
+ len = strlen (conv_path_names[j]);
+ if (strncmp (conv_path_names[j], env[i], len) == 0)
+ {
+ if (cygwin_posix_path_list_p (env[i] + len))
+ envlen += len
+ + cygwin_posix_to_win32_path_list_buf_size (env[i] + len);
+ else
+ envlen += strlen (env[i]) + 1;
+ break;
+ }
+ }
+ if (conv_path_names[j] == NULL)
+ envlen += strlen (env[i]) + 1;
+ }
+
+ winenv = alloca (envlen + 1);
+
+ /* Copy env strings into new buffer. */
+ for (temp = winenv, i = 0; env[i] && *env[i]; i++)
+ {
+ int j, len;
+
+ for (j = 0; conv_path_names[j]; j++)
+ {
+ len = strlen (conv_path_names[j]);
+ if (strncmp (conv_path_names[j], env[i], len) == 0)
+ {
+ if (cygwin_posix_path_list_p (env[i] + len))
+ {
+ memcpy (temp, env[i], len);
+ cygwin_posix_to_win32_path_list (env[i] + len, temp + len);
+ }
+ else
+ strcpy (temp, env[i]);
+ break;
+ }
+ }
+ if (conv_path_names[j] == NULL)
+ strcpy (temp, env[i]);
+
+ temp += strlen (temp) + 1;
+ }
+
+ /* Final nil string to terminate new env. */
+ *temp = 0;
+ }
+
+ if (!inferior_io_terminal)
+ tty = ostdin = ostdout = ostderr = -1;
+ else
+ {
+ tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY);
+ if (tty < 0)
+ {
+ print_sys_errmsg (inferior_io_terminal, errno);
+ ostdin = ostdout = ostderr = -1;
+ }
+ else
+ {
+ ostdin = dup (0);
+ ostdout = dup (1);
+ ostderr = dup (2);
+ dup2 (tty, 0);
+ dup2 (tty, 1);
+ dup2 (tty, 2);
+ }
+ }
+
+ ret = CreateProcess (0,
+ args, /* command line */
+ NULL, /* Security */
+ NULL, /* thread */
+ TRUE, /* inherit handles */
+ flags, /* start flags */
+ winenv,
+ NULL, /* current directory */
+ &si,
+ &pi);
+ if (tty >= 0)
+ {
+ close (tty);
+ dup2 (ostdin, 0);
+ dup2 (ostdout, 1);
+ dup2 (ostderr, 2);
+ close (ostdin);
+ close (ostdout);
+ close (ostderr);
+ }
+
+ if (!ret)
+ error ("Error creating process %s, (error %d)\n", exec_file, (unsigned) GetLastError ());
+
+ CloseHandle (pi.hThread);
+ CloseHandle (pi.hProcess);
+
+ if (useshell && shell[0] != '\0')
+ saw_create = -1;
+ else
+ saw_create = 0;
+
+ do_initial_child_stuff (pi.dwProcessId);
+
+ /* child_continue (DBG_CONTINUE, -1); */
+ proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
+}
+
+static void
+child_mourn_inferior (void)
+{
+ (void) child_continue (DBG_CONTINUE, -1);
+ i386_cleanup_dregs();
+ unpush_target (&child_ops);
+ generic_mourn_inferior ();
+}
+
+/* Send a SIGINT to the process group. This acts just like the user typed a
+ ^C on the controlling terminal. */
+
+static void
+child_stop (void)
+{
+ DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n"));
+ CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId));
+ registers_changed (); /* refresh register state */
+}
+
+int
+child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
+ int write, struct mem_attrib *mem,
+ struct target_ops *target)
+{
+ DWORD done = 0;
+ if (write)
+ {
+ DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08lx\n",
+ len, (DWORD) memaddr));
+ if (!WriteProcessMemory (current_process_handle, (LPVOID) memaddr, our,
+ len, &done))
+ done = 0;
+ FlushInstructionCache (current_process_handle, (LPCVOID) memaddr, len);
+ }
+ else
+ {
+ DEBUG_MEM (("gdb: read target memory, %d bytes at 0x%08lx\n",
+ len, (DWORD) memaddr));
+ if (!ReadProcessMemory (current_process_handle, (LPCVOID) memaddr, our,
+ len, &done))
+ done = 0;
+ }
+ return done;
+}
+
+void
+child_kill_inferior (void)
+{
+ CHECK (TerminateProcess (current_process_handle, 0));
+
+ for (;;)
+ {
+ if (!child_continue (DBG_CONTINUE, -1))
+ break;
+ if (!WaitForDebugEvent (&current_event, INFINITE))
+ break;
+ if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
+ break;
+ }
+
+ CHECK (CloseHandle (current_process_handle));
+
+ /* this may fail in an attached process so don't check. */
+ if (current_thread && current_thread->h)
+ (void) CloseHandle (current_thread->h);
+ target_mourn_inferior (); /* or just child_mourn_inferior? */
+}
+
+void
+child_resume (ptid_t ptid, int step, enum target_signal sig)
+{
+ thread_info *th;
+ DWORD continue_status = DBG_CONTINUE;
+
+ int pid = PIDGET (ptid);
+
+ if (sig != TARGET_SIGNAL_0)
+ {
+ if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
+ {
+ DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
+ }
+ else if (sig == last_sig)
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
+ else
+#if 0
+/* This code does not seem to work, because
+ the kernel does probably not consider changes in the ExceptionRecord
+ structure when passing the exception to the inferior.
+ Note that this seems possible in the exception handler itself. */
+ {
+ int i;
+ for (i = 0; xlate[i].them != -1; i++)
+ if (xlate[i].us == sig)
+ {
+ current_event.u.Exception.ExceptionRecord.ExceptionCode =
+ xlate[i].them;
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
+ break;
+ }
+ if (continue_status == DBG_CONTINUE)
+ {
+ DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
+ }
+ }
+#endif
+ DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
+ last_sig));
+ }
+
+ last_sig = TARGET_SIGNAL_0;
+
+ DEBUG_EXEC (("gdb: child_resume (pid=%d, step=%d, sig=%d);\n",
+ pid, step, sig));
+
+ /* Get context for currently selected thread */
+ th = thread_rec (current_event.dwThreadId, FALSE);
+ if (th)
+ {
+ if (step)
+ {
+ /* Single step by setting t bit */
+ child_fetch_inferior_registers (PS_REGNUM);
+ th->context.EFlags |= FLAG_TRACE_BIT;
+ }
+
+ if (th->context.ContextFlags)
+ {
+ if (debug_registers_changed)
+ {
+ th->context.Dr0 = dr[0];
+ th->context.Dr1 = dr[1];
+ th->context.Dr2 = dr[2];
+ th->context.Dr3 = dr[3];
+ /* th->context.Dr6 = dr[6];
+ FIXME: should we set dr6 also ?? */
+ th->context.Dr7 = dr[7];
+ }
+ CHECK (SetThreadContext (th->h, &th->context));
+ th->context.ContextFlags = 0;
+ }
+ }
+
+ /* Allow continuing with the same signal that interrupted us.
+ Otherwise complain. */
+
+ child_continue (continue_status, pid);
+}
+
+static void
+child_prepare_to_store (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static int
+child_can_run (void)
+{
+ return 1;
+}
+
+static void
+child_close (int x)
+{
+ DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n",
+ PIDGET (inferior_ptid)));
+}
+
+struct target_ops child_ops;
+
+static void
+init_child_ops (void)
+{
+ child_ops.to_shortname = "child";
+ child_ops.to_longname = "Win32 child process";
+ child_ops.to_doc = "Win32 child process (started by the \"run\" command).";
+ child_ops.to_open = child_open;
+ child_ops.to_close = child_close;
+ child_ops.to_attach = child_attach;
+ child_ops.to_detach = child_detach;
+ child_ops.to_resume = child_resume;
+ child_ops.to_wait = child_wait;
+ child_ops.to_fetch_registers = child_fetch_inferior_registers;
+ child_ops.to_store_registers = child_store_inferior_registers;
+ child_ops.to_prepare_to_store = child_prepare_to_store;
+ child_ops.to_xfer_memory = child_xfer_memory;
+ child_ops.to_files_info = child_files_info;
+ child_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ child_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ child_ops.to_terminal_init = terminal_init_inferior;
+ child_ops.to_terminal_inferior = terminal_inferior;
+ child_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ child_ops.to_terminal_ours = terminal_ours;
+ child_ops.to_terminal_save_ours = terminal_save_ours;
+ child_ops.to_terminal_info = child_terminal_info;
+ child_ops.to_kill = child_kill_inferior;
+ child_ops.to_create_inferior = child_create_inferior;
+ child_ops.to_mourn_inferior = child_mourn_inferior;
+ child_ops.to_can_run = child_can_run;
+ child_ops.to_thread_alive = win32_child_thread_alive;
+ child_ops.to_pid_to_str = cygwin_pid_to_str;
+ child_ops.to_stop = child_stop;
+ child_ops.to_stratum = process_stratum;
+ child_ops.to_has_all_memory = 1;
+ child_ops.to_has_memory = 1;
+ child_ops.to_has_stack = 1;
+ child_ops.to_has_registers = 1;
+ child_ops.to_has_execution = 1;
+ child_ops.to_magic = OPS_MAGIC;
+}
+
+void
+_initialize_win32_nat (void)
+{
+ struct cmd_list_element *c;
+
+ init_child_ops ();
+
+ c = add_com ("dll-symbols", class_files, dll_symbol_command,
+ "Load dll library symbols from FILE.");
+ set_cmd_completer (c, filename_completer);
+
+ add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
+
+ add_show_from_set (add_set_cmd ("shell", class_support, var_boolean,
+ (char *) &useshell,
+ "Set use of shell to start subprocess.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
+ (char *) &new_console,
+ "Set creation of new console when creating child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean,
+ (char *) &new_group,
+ "Set creation of new group when creating child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean,
+ (char *) &debug_exec,
+ "Set whether to display execution in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean,
+ (char *) &debug_events,
+ "Set whether to display kernel events in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean,
+ (char *) &debug_memory,
+ "Set whether to display memory accesses in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean,
+ (char *) &debug_exceptions,
+ "Set whether to display kernel exceptions in child process.",
+ &setlist),
+ &showlist);
+
+ add_info ("dll", info_dll_command, "Status of loaded DLLs.");
+ add_info_alias ("sharedlibrary", "dll", 1);
+
+ add_prefix_cmd ("w32", class_info, info_w32_command,
+ "Print information specific to Win32 debugging.",
+ &info_w32_cmdlist, "info w32 ", 0, &infolist);
+
+ add_cmd ("selector", class_info, display_selectors,
+ "Display selectors infos.",
+ &info_w32_cmdlist);
+
+ add_target (&child_ops);
+}
+
+/* Hardware watchpoint support, adapted from go32-nat.c code. */
+
+/* Pass the address ADDR to the inferior in the I'th debug register.
+ Here we just store the address in dr array, the registers will be
+ actually set up when child_continue is called. */
+void
+cygwin_set_dr (int i, CORE_ADDR addr)
+{
+ if (i < 0 || i > 3)
+ internal_error (__FILE__, __LINE__,
+ "Invalid register %d in cygwin_set_dr.\n", i);
+ dr[i] = (unsigned) addr;
+ debug_registers_changed = 1;
+ debug_registers_used = 1;
+}
+
+/* Pass the value VAL to the inferior in the DR7 debug control
+ register. Here we just store the address in D_REGS, the watchpoint
+ will be actually set up in child_wait. */
+void
+cygwin_set_dr7 (unsigned val)
+{
+ dr[7] = val;
+ debug_registers_changed = 1;
+ debug_registers_used = 1;
+}
+
+/* Get the value of the DR6 debug status register from the inferior.
+ Here we just return the value stored in dr[6]
+ by the last call to thread_rec for current_event.dwThreadId id. */
+unsigned
+cygwin_get_dr6 (void)
+{
+ return dr[6];
+}
+
+/* Determine if the thread referenced by "pid" is alive
+ by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
+ it means that the pid has died. Otherwise it is assumed to be alive. */
+static int
+win32_child_thread_alive (ptid_t ptid)
+{
+ int pid = PIDGET (ptid);
+
+ return WaitForSingleObject (thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ?
+ FALSE : TRUE;
+}
+
+/* Convert pid to printable format. */
+char *
+cygwin_pid_to_str (ptid_t ptid)
+{
+ static char buf[80];
+ int pid = PIDGET (ptid);
+
+ if ((DWORD) pid == current_event.dwProcessId)
+ sprintf (buf, "process %d", pid);
+ else
+ sprintf (buf, "thread %ld.0x%x", current_event.dwProcessId, pid);
+ return buf;
+}
+
+static int
+core_dll_symbols_add (char *dll_name, DWORD base_addr)
+{
+ struct objfile *objfile;
+ char *objfile_basename;
+ const char *dll_basename;
+
+ if (!(dll_basename = strrchr (dll_name, '/')))
+ dll_basename = dll_name;
+ else
+ dll_basename++;
+
+ ALL_OBJFILES (objfile)
+ {
+ objfile_basename = strrchr (objfile->name, '/');
+
+ if (objfile_basename &&
+ strcmp (dll_basename, objfile_basename + 1) == 0)
+ {
+ printf_unfiltered ("%08lx:%s (symbols previously loaded)\n",
+ base_addr, dll_name);
+ goto out;
+ }
+ }
+
+ register_loaded_dll (dll_name, base_addr + 0x1000);
+ solib_symbols_add (dll_name, 0, (CORE_ADDR) base_addr + 0x1000);
+
+ out:
+ return 1;
+ }
+
+ typedef struct
+ {
+ struct target_ops *target;
+ bfd_vma addr;
+ } map_code_section_args;
+
+ static void
+ map_single_dll_code_section (bfd * abfd, asection * sect, void *obj)
+ {
+ int old;
+ int update_coreops;
+ struct section_table *new_target_sect_ptr;
+
+ map_code_section_args *args = (map_code_section_args *) obj;
+ struct target_ops *target = args->target;
+ if (sect->flags & SEC_CODE)
+ {
+ update_coreops = core_ops.to_sections == target->to_sections;
+
+ 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)) * (1 + old));
+ }
+ else
+ {
+ old = 0;
+ target->to_sections = (struct section_table *)
+ xmalloc ((sizeof (struct section_table)));
+ }
+ target->to_sections_end = target->to_sections + (1 + 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;
+ }
+ new_target_sect_ptr = target->to_sections + old;
+ new_target_sect_ptr->addr = args->addr + bfd_section_vma (abfd, sect);
+ new_target_sect_ptr->endaddr = args->addr + bfd_section_vma (abfd, sect) +
+ bfd_section_size (abfd, sect);;
+ new_target_sect_ptr->the_bfd_section = sect;
+ new_target_sect_ptr->bfd = abfd;
+ }
+ }
+
+ static int
+ dll_code_sections_add (const char *dll_name, int base_addr, struct target_ops *target)
+{
+ bfd *dll_bfd;
+ map_code_section_args map_args;
+ asection *lowest_sect;
+ char *name;
+ if (dll_name == NULL || target == NULL)
+ return 0;
+ name = xstrdup (dll_name);
+ dll_bfd = bfd_openr (name, "pei-i386");
+ if (dll_bfd == NULL)
+ return 0;
+
+ if (bfd_check_format (dll_bfd, bfd_object))
+ {
+ lowest_sect = bfd_get_section_by_name (dll_bfd, ".text");
+ if (lowest_sect == NULL)
+ return 0;
+ map_args.target = target;
+ map_args.addr = base_addr - bfd_section_vma (dll_bfd, lowest_sect);
+
+ bfd_map_over_sections (dll_bfd, &map_single_dll_code_section, (void *) (&map_args));
+ }
+
+ return 1;
+}
+
+static void
+core_section_load_dll_symbols (bfd * abfd, asection * sect, void *obj)
+{
+ struct target_ops *target = (struct target_ops *) obj;
+
+ DWORD base_addr;
+
+ int dll_name_size;
+ char *dll_name = NULL;
+ char *buf = NULL;
+ struct win32_pstatus *pstatus;
+ char *p;
+
+ if (strncmp (sect->name, ".module", 7))
+ return;
+
+ buf = (char *) xmalloc (sect->_raw_size + 1);
+ if (!buf)
+ {
+ printf_unfiltered ("memory allocation failed for %s\n", sect->name);
+ goto out;
+ }
+ if (!bfd_get_section_contents (abfd, sect, buf, 0, sect->_raw_size))
+ goto out;
+
+ pstatus = (struct win32_pstatus *) buf;
+
+ memmove (&base_addr, &(pstatus->data.module_info.base_address), sizeof (base_addr));
+ dll_name_size = pstatus->data.module_info.module_name_size;
+ if (offsetof (struct win32_pstatus, data.module_info.module_name) + dll_name_size > sect->_raw_size)
+ goto out;
+
+ dll_name = (char *) xmalloc (dll_name_size + 1);
+ if (!dll_name)
+ {
+ printf_unfiltered ("memory allocation failed for %s\n", sect->name);
+ goto out;
+ }
+ strncpy (dll_name, pstatus->data.module_info.module_name, dll_name_size);
+
+ while ((p = strchr (dll_name, '\\')))
+ *p = '/';
+
+ if (!core_dll_symbols_add (dll_name, (DWORD) base_addr))
+ printf_unfiltered ("%s: Failed to load dll symbols.\n", dll_name);
+
+ if (!dll_code_sections_add (dll_name, (DWORD) base_addr + 0x1000, target))
+ printf_unfiltered ("%s: Failed to map dll code sections.\n", dll_name);
+
+out:
+ if (buf)
+ xfree (buf);
+ if (dll_name)
+ xfree (dll_name);
+ return;
+}
+
+void
+child_solib_add (char *filename, int from_tty, struct target_ops *target,
+ int readsyms)
+{
+ if (!readsyms)
+ return;
+ if (core_bfd)
+ {
+ child_clear_solibs ();
+ bfd_map_over_sections (core_bfd, &core_section_load_dll_symbols, target);
+ }
+ else
+ {
+ if (solib_end && solib_end->name)
+ solib_end->objfile = solib_symbols_add (solib_end->name, from_tty,
+ solib_end->load_addr);
+ }
+}
+
+static void
+fetch_elf_core_registers (char *core_reg_sect,
+ unsigned core_reg_size,
+ int which,
+ CORE_ADDR reg_addr)
+{
+ int r;
+ if (core_reg_size < sizeof (CONTEXT))
+ {
+ error ("Core file register section too small (%u bytes).", core_reg_size);
+ return;
+ }
+ for (r = 0; r < NUM_REGS; r++)
+ supply_register (r, core_reg_sect + mappings[r]);
+}
+
+static struct core_fns win32_elf_core_fns =
+{
+ bfd_target_elf_flavour,
+ default_check_format,
+ default_core_sniffer,
+ fetch_elf_core_registers,
+ NULL
+};
+
+void
+_initialize_core_win32 (void)
+{
+ add_core_fns (&win32_elf_core_fns);
+}
+
+void
+_initialize_check_for_gdb_ini (void)
+{
+ char *homedir;
+ if (inhibit_gdbinit)
+ return;
+
+ homedir = getenv ("HOME");
+ if (homedir)
+ {
+ char *p;
+ char *oldini = (char *) alloca (strlen (homedir) +
+ sizeof ("/gdb.ini"));
+ strcpy (oldini, homedir);
+ p = strchr (oldini, '\0');
+ if (p > oldini && p[-1] != '/')
+ *p++ = '/';
+ strcpy (p, "gdb.ini");
+ if (access (oldini, 0) == 0)
+ {
+ int len = strlen (oldini);
+ char *newini = alloca (len + 1);
+ sprintf (newini, "%.*s.gdbinit",
+ (int) (len - (sizeof ("gdb.ini") - 1)), oldini);
+ warning ("obsolete '%s' found. Rename to '%s'.", oldini, newini);
+ }
+ }
+}
diff --git a/contrib/gdb/gdb/wince-stub.c b/contrib/gdb/gdb/wince-stub.c
new file mode 100644
index 0000000..ce872d8
--- /dev/null
+++ b/contrib/gdb/gdb/wince-stub.c
@@ -0,0 +1,592 @@
+/* wince-stub.c -- debugging stub for a Windows CE device
+
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions, A Red Hat Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/* by Christopher Faylor (cgf@cygnus.com) */
+
+#include <stdarg.h>
+#include <windows.h>
+#include <winsock.h>
+#include "wince-stub.h"
+
+#define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, (UINT)(n))
+#define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE)
+#define FREE(s) LocalFree ((HLOCAL)(s))
+
+static int skip_next_id = 0; /* Don't read next API code from socket */
+
+/* v-style interface for handling varying argument list error messages.
+ Displays the error message in a dialog box and exits when user clicks
+ on OK. */
+static void
+vstub_error (LPCWSTR fmt, va_list args)
+{
+ WCHAR buf[4096];
+ wvsprintfW (buf, fmt, args);
+
+ MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
+ WSACleanup ();
+ ExitThread (1);
+}
+
+/* The standard way to display an error message and exit. */
+static void
+stub_error (LPCWSTR fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vstub_error (fmt, args);
+}
+
+/* Allocate a limited pool of memory, reallocating over unused
+ buffers. This assumes that there will never be more than four
+ "buffers" required which, so far, is a safe assumption. */
+static LPVOID
+mempool (unsigned int len)
+{
+ static int outn = -1;
+ static LPWSTR outs[4] = {NULL, NULL, NULL, NULL};
+
+ if (++outn >= (sizeof (outs) / sizeof (outs[0])))
+ outn = 0;
+
+ /* Allocate space for the converted string, reusing any previously allocated
+ space, if applicable. */
+ if (outs[outn])
+ FREE (outs[outn]);
+ outs[outn] = (LPWSTR) MALLOC (len);
+
+ return outs[outn];
+}
+
+/* Standard "oh well" can't communicate error. Someday this might attempt
+ synchronization. */
+static void
+attempt_resync (LPCWSTR huh, int s)
+{
+ stub_error (L"lost synchronization with host attempting %s. Error %d", huh, WSAGetLastError ());
+}
+
+/* Read arbitrary stuff from a socket. */
+static int
+sockread (LPCWSTR huh, int s, void *str, size_t n)
+{
+ for (;;)
+ {
+ if (recv (s, str, n, 0) == (int) n)
+ return n;
+ attempt_resync (huh, s);
+ }
+}
+
+/* Write arbitrary stuff to a socket. */
+static int
+sockwrite (LPCWSTR huh, int s, const void *str, size_t n)
+{
+ for (;;)
+ {
+ if (send (s, str, n, 0) == (int) n)
+ return n;
+ attempt_resync (huh, s);
+ }
+}
+
+/* Get a an ID (possibly) and a DWORD from the host gdb.
+ Don't bother with the id if the main loop has already
+ read it. */
+static DWORD
+getdword (LPCWSTR huh, int s, gdb_wince_id what_this)
+{
+ DWORD n;
+ gdb_wince_id what;
+
+ if (skip_next_id)
+ skip_next_id = 0;
+ else
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error getting %s from host.", huh);
+
+ return n;
+}
+
+/* Get a an ID (possibly) and a WORD from the host gdb.
+ Don't bother with the id if the main loop has already
+ read it. */
+static WORD
+getword (LPCWSTR huh, int s, gdb_wince_id what_this)
+{
+ WORD n;
+ gdb_wince_id what;
+
+ if (skip_next_id)
+ skip_next_id = 0;
+ else
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error getting %s from host.", huh);
+
+ return n;
+}
+
+/* Handy defines for getting various types of values. */
+#define gethandle(huh, s, what) (HANDLE) getdword ((huh), (s), (what))
+#define getpvoid(huh, s, what) (LPVOID) getdword ((huh), (s), (what))
+#define getlen(huh, s, what) (gdb_wince_len) getword ((huh), (s), (what))
+
+/* Get an arbitrary block of memory from the gdb host. This comes in
+ two chunks an id/dword representing the length and the stream of memory
+ itself. Returns a pointer, allocated via mempool, to a memory buffer. */
+static LPWSTR
+getmemory (LPCWSTR huh, int s, gdb_wince_id what, gdb_wince_len *inlen)
+{
+ LPVOID p;
+ gdb_wince_len dummy;
+
+ if (!inlen)
+ inlen = &dummy;
+
+ *inlen = getlen (huh, s, what);
+
+ p = mempool ((unsigned int) *inlen); /* FIXME: check for error */
+
+ if ((gdb_wince_len) sockread (huh, s, p, *inlen) != *inlen)
+ stub_error (L"error getting string from host.");
+
+ return p;
+}
+
+/* Output an id/dword to the host */
+static void
+putdword (LPCWSTR huh, int s, gdb_wince_id what, DWORD n)
+{
+ if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error writing record id for %s to host.", huh);
+ if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error writing %s to host.", huh);
+}
+
+/* Output an id/word to the host */
+static void
+putword (LPCWSTR huh, int s, gdb_wince_id what, WORD n)
+{
+ if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error writing record id for %s to host.", huh);
+ if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error writing %s to host.", huh);
+}
+
+/* Convenience define for outputting a "gdb_wince_len" type. */
+#define putlen(huh, s, what, n) putword ((huh), (s), (what), (gdb_wince_len) (n))
+
+/* Put an arbitrary block of memory to the gdb host. This comes in
+ two chunks an id/dword representing the length and the stream of memory
+ itself. */
+static void
+putmemory (LPCWSTR huh, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
+{
+ putlen (huh, s, what, len);
+ if (((short) len > 0) && (gdb_wince_len) sockwrite (huh, s, mem, len) != len)
+ stub_error (L"error writing memory to host.");
+}
+
+/* Output the result of an operation to the host. If res != 0, sends a block of
+ memory starting at mem of len bytes. If res == 0, sends -GetLastError () and
+ avoids sending the mem. */
+static void
+putresult (LPCWSTR huh, gdb_wince_result res, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
+{
+ if (!res)
+ len = -(int) GetLastError ();
+ putmemory (huh, s, what, mem, len);
+}
+
+static HANDLE curproc; /* Currently unused, but nice for debugging */
+
+/* Emulate CreateProcess. Returns &pi if no error. */
+static void
+create_process (int s)
+{
+ LPWSTR exec_file = getmemory (L"CreateProcess exec_file", s, GDB_CREATEPROCESS, NULL);
+ LPWSTR args = getmemory (L"CreateProcess args", s, GDB_CREATEPROCESS, NULL);
+ DWORD flags = getdword (L"CreateProcess flags", s, GDB_CREATEPROCESS);
+ PROCESS_INFORMATION pi;
+ gdb_wince_result res;
+
+ res = CreateProcessW (exec_file,
+ args, /* command line */
+ NULL, /* Security */
+ NULL, /* thread */
+ FALSE, /* inherit handles */
+ flags, /* start flags */
+ NULL,
+ NULL, /* current directory */
+ NULL,
+ &pi);
+ putresult (L"CreateProcess", res, s, GDB_CREATEPROCESS, &pi, sizeof (pi));
+ curproc = pi.hProcess;
+}
+
+/* Emulate TerminateProcess. Returns return value of TerminateProcess if
+ no error.
+ *** NOTE: For some unknown reason, TerminateProcess seems to always return
+ an ACCESS_DENIED (on Windows CE???) error. So, force a TRUE value for now. */
+static void
+terminate_process (int s)
+{
+ gdb_wince_result res;
+ HANDLE h = gethandle (L"TerminateProcess handle", s, GDB_TERMINATEPROCESS);
+
+ res = TerminateProcess (h, 0) || 1; /* Doesn't seem to work on SH so default to TRUE */
+ putresult (L"Terminate process result", res, s, GDB_TERMINATEPROCESS,
+ &res, sizeof (res));
+}
+
+static int stepped = 0;
+/* Handle single step instruction. FIXME: unneded? */
+static void
+flag_single_step (int s)
+{
+ stepped = 1;
+ skip_next_id = 0;
+}
+
+struct skipper
+{
+ wchar_t *s;
+ int nskip;
+} skippy[] =
+{
+ {L"Undefined Instruction:", 1},
+ {L"Data Abort:", 2},
+ {NULL, 0}
+};
+
+static int
+skip_message (DEBUG_EVENT *ev)
+{
+ char s[80];
+ DWORD nread;
+ struct skipper *skp;
+ int nbytes = ev->u.DebugString.nDebugStringLength;
+
+ if (nbytes > sizeof(s))
+ nbytes = sizeof(s);
+
+ memset (s, 0, sizeof (s));
+ if (!ReadProcessMemory (curproc, ev->u.DebugString.lpDebugStringData,
+ s, nbytes, &nread))
+ return 0;
+
+ for (skp = skippy; skp->s != NULL; skp++)
+ if (wcsncmp ((wchar_t *) s, skp->s, wcslen (skp->s)) == 0)
+ return skp->nskip;
+
+ return 0;
+}
+
+/* Emulate WaitForDebugEvent. Returns the debug event on success. */
+static void
+wait_for_debug_event (int s)
+{
+ DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT);
+ gdb_wince_result res;
+ DEBUG_EVENT ev;
+ static int skip_next = 0;
+
+ for (;;)
+ {
+ res = WaitForDebugEvent (&ev, ms);
+
+ if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
+ {
+ if (skip_next)
+ {
+ skip_next--;
+ goto ignore;
+ }
+ if (skip_next = skip_message (&ev))
+ goto ignore;
+ }
+
+ putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
+ &ev, sizeof (ev));
+ break;
+
+ ignore:
+ ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+ }
+
+ return;
+}
+
+/* Emulate GetThreadContext. Returns CONTEXT structure on success. */
+static void
+get_thread_context (int s)
+{
+ CONTEXT c;
+ HANDLE h = gethandle (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT);
+ gdb_wince_result res;
+
+ memset (&c, 0, sizeof (c));
+ c.ContextFlags = getdword (L"GetThreadContext flags", s, GDB_GETTHREADCONTEXT);
+
+ res = (gdb_wince_result) GetThreadContext (h, &c);
+ putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT,
+ &c, sizeof (c));
+}
+
+/* Emulate GetThreadContext. Returns success of SetThreadContext. */
+static void
+set_thread_context (int s)
+{
+ gdb_wince_result res;
+ HANDLE h = gethandle (L"SetThreadContext handle", s, GDB_SETTHREADCONTEXT);
+ LPCONTEXT pc = (LPCONTEXT) getmemory (L"SetThreadContext context", s,
+ GDB_SETTHREADCONTEXT, NULL);
+
+ res = SetThreadContext (h, pc);
+ putresult (L"SetThreadContext result", res, s, GDB_SETTHREADCONTEXT,
+ &res, sizeof (res));
+}
+
+/* Emulate ReadProcessMemory. Returns memory read on success. */
+static void
+read_process_memory (int s)
+{
+ HANDLE h = gethandle (L"ReadProcessMemory handle", s, GDB_READPROCESSMEMORY);
+ LPVOID p = getpvoid (L"ReadProcessMemory base", s, GDB_READPROCESSMEMORY);
+ gdb_wince_len len = getlen (L"ReadProcessMemory size", s, GDB_READPROCESSMEMORY);
+ LPVOID buf = mempool ((unsigned int) len);
+ DWORD outlen;
+ gdb_wince_result res;
+
+ outlen = 0;
+ res = (gdb_wince_result) ReadProcessMemory (h, p, buf, len, &outlen);
+ putresult (L"ReadProcessMemory data", res, s, GDB_READPROCESSMEMORY,
+ buf, (gdb_wince_len) outlen);
+}
+
+/* Emulate WriteProcessMemory. Returns WriteProcessMemory success. */
+static void
+write_process_memory (int s)
+{
+ HANDLE h = gethandle (L"WriteProcessMemory handle", s, GDB_WRITEPROCESSMEMORY);
+ LPVOID p = getpvoid (L"WriteProcessMemory base", s, GDB_WRITEPROCESSMEMORY);
+ gdb_wince_len len;
+ LPVOID buf = getmemory (L"WriteProcessMemory buf", s, GDB_WRITEPROCESSMEMORY, &len);
+ DWORD outlen;
+ gdb_wince_result res;
+
+ outlen = 0;
+ res = WriteProcessMemory (h, p, buf, (DWORD) len, &outlen);
+ putresult (L"WriteProcessMemory data", res, s, GDB_WRITEPROCESSMEMORY,
+ (gdb_wince_len *) & outlen, sizeof (gdb_wince_len));
+}
+
+/* Return non-zero to gdb host if given thread is alive. */
+static void
+thread_alive (int s)
+{
+ HANDLE h = gethandle (L"ThreadAlive handle", s, GDB_THREADALIVE);
+ gdb_wince_result res;
+
+ res = WaitForSingleObject (h, 0) == WAIT_OBJECT_0 ? 1 : 0;
+ putresult (L"WriteProcessMemory data", res, s, GDB_THREADALIVE,
+ &res, sizeof (res));
+}
+
+/* Emulate SuspendThread. Returns value returned from SuspendThread. */
+static void
+suspend_thread (int s)
+{
+ DWORD res;
+ HANDLE h = gethandle (L"SuspendThread handle", s, GDB_SUSPENDTHREAD);
+ res = SuspendThread (h);
+ putdword (L"SuspendThread result", s, GDB_SUSPENDTHREAD, res);
+}
+
+/* Emulate ResumeThread. Returns value returned from ResumeThread. */
+static void
+resume_thread (int s)
+{
+ DWORD res;
+ HANDLE h = gethandle (L"ResumeThread handle", s, GDB_RESUMETHREAD);
+ res = ResumeThread (h);
+ putdword (L"ResumeThread result", s, GDB_RESUMETHREAD, res);
+}
+
+/* Emulate ContinueDebugEvent. Returns ContinueDebugEvent success. */
+static void
+continue_debug_event (int s)
+{
+ gdb_wince_result res;
+ DWORD pid = getdword (L"ContinueDebugEvent pid", s, GDB_CONTINUEDEBUGEVENT);
+ DWORD tid = getdword (L"ContinueDebugEvent tid", s, GDB_CONTINUEDEBUGEVENT);
+ DWORD status = getdword (L"ContinueDebugEvent status", s, GDB_CONTINUEDEBUGEVENT);
+ res = (gdb_wince_result) ContinueDebugEvent (pid, tid, status);
+ putresult (L"ContinueDebugEvent result", res, s, GDB_CONTINUEDEBUGEVENT, &res, sizeof (res));
+}
+
+/* Emulate CloseHandle. Returns CloseHandle success. */
+static void
+close_handle (int s)
+{
+ gdb_wince_result res;
+ HANDLE h = gethandle (L"CloseHandle handle", s, GDB_CLOSEHANDLE);
+ res = (gdb_wince_result) CloseHandle (h);
+ putresult (L"CloseHandle result", res, s, GDB_CLOSEHANDLE, &res, sizeof (res));
+}
+
+/* Main loop for reading requests from gdb host on the socket. */
+static void
+dispatch (int s)
+{
+ gdb_wince_id id;
+
+ /* Continue reading from socket until receive a GDB_STOPSUB. */
+ while (sockread (L"Dispatch", s, &id, sizeof (id)) > 0)
+ {
+ skip_next_id = 1;
+ switch (id)
+ {
+ case GDB_CREATEPROCESS:
+ create_process (s);
+ break;
+ case GDB_TERMINATEPROCESS:
+ terminate_process (s);
+ break;
+ case GDB_WAITFORDEBUGEVENT:
+ wait_for_debug_event (s);
+ break;
+ case GDB_GETTHREADCONTEXT:
+ get_thread_context (s);
+ break;
+ case GDB_SETTHREADCONTEXT:
+ set_thread_context (s);
+ break;
+ case GDB_READPROCESSMEMORY:
+ read_process_memory (s);
+ break;
+ case GDB_WRITEPROCESSMEMORY:
+ write_process_memory (s);
+ break;
+ case GDB_THREADALIVE:
+ thread_alive (s);
+ break;
+ case GDB_SUSPENDTHREAD:
+ suspend_thread (s);
+ break;
+ case GDB_RESUMETHREAD:
+ resume_thread (s);
+ break;
+ case GDB_CONTINUEDEBUGEVENT:
+ continue_debug_event (s);
+ break;
+ case GDB_CLOSEHANDLE:
+ close_handle (s);
+ break;
+ case GDB_STOPSTUB:
+ terminate_process (s);
+ return;
+ case GDB_SINGLESTEP:
+ flag_single_step (s);
+ break;
+ default:
+ {
+ WCHAR buf[80];
+ wsprintfW (buf, L"Invalid command id received: %d", id);
+ MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
+ skip_next_id = 0;
+ }
+ }
+ }
+}
+
+/* The Windows Main entry point */
+int WINAPI
+WinMain (HINSTANCE hi, HINSTANCE hp, LPWSTR cmd, int show)
+{
+ struct hostent *h;
+ int s;
+ struct WSAData wd;
+ struct sockaddr_in sin;
+ int tmp;
+ LPWSTR whost;
+ char host[80];
+
+ whost = wcschr (cmd, L' '); /* Look for argument. */
+
+ /* If no host is specified, just use default */
+ if (whost)
+ {
+ /* Eat any spaces. */
+ while (*whost == L' ' || *whost == L'\t')
+ whost++;
+
+ wcstombs (host, whost, 80); /* Convert from UNICODE to ascii */
+ }
+
+ /* Winsock initialization. */
+ if (WSAStartup (MAKEWORD (1, 1), &wd))
+ stub_error (L"Couldn't initialize WINSOCK.");
+
+ /* If whost was specified, first try it. If it was not specified or the
+ host lookup failed, try the Windows CE magic ppp_peer lookup. ppp_peer
+ is supposed to be the Windows host sitting on the other end of the
+ serial cable. */
+ if (whost && *whost && (h = gethostbyname (host)) != NULL)
+ /* nothing to do */ ;
+ else if ((h = gethostbyname ("ppp_peer")) == NULL)
+ stub_error (L"Couldn't get IP address of host system. Error %d", WSAGetLastError ());
+
+ /* Get a socket. */
+ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ stub_error (L"Couldn't connect to host system. Error %d", WSAGetLastError ());
+
+ /* Allow rapid reuse of the port. */
+ tmp = 1;
+ setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
+
+ /* Set up the information for connecting to the host gdb process. */
+ memset (&sin, 0, sizeof (sin));
+ sin.sin_family = h->h_addrtype;
+ memcpy (&sin.sin_addr, h->h_addr, h->h_length);
+ sin.sin_port = htons (7000); /* FIXME: This should be configurable */
+
+ /* Connect to host */
+ if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
+ stub_error (L"Couldn't connect to host gdb.");
+
+ /* Read from socket until told to exit. */
+ dispatch (s);
+ WSACleanup ();
+ return 0;
+}
diff --git a/contrib/gdb/gdb/wince-stub.h b/contrib/gdb/gdb/wince-stub.h
new file mode 100644
index 0000000..21e9002
--- /dev/null
+++ b/contrib/gdb/gdb/wince-stub.h
@@ -0,0 +1,48 @@
+/* wince-stub.h -- Definitions for commnicating with the WinCE stub.
+
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions, A Red Hat Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/* by Christopher Faylor (cgf@cygnus.com) */
+
+enum win_func
+ {
+ GDB_CREATEPROCESS = 42,
+ GDB_TERMINATEPROCESS,
+ GDB_WAITFORDEBUGEVENT,
+ GDB_GETTHREADCONTEXT,
+ GDB_SETTHREADCONTEXT,
+ GDB_READPROCESSMEMORY,
+ GDB_WRITEPROCESSMEMORY,
+ GDB_THREADALIVE,
+ GDB_SUSPENDTHREAD,
+ GDB_RESUMETHREAD,
+ GDB_CONTINUEDEBUGEVENT,
+ GDB_CLOSEHANDLE,
+ GDB_STOPSTUB,
+ GDB_SINGLESTEP,
+ GDB_SETBREAK,
+ GDB_INVALID
+ };
+
+typedef unsigned char gdb_wince_id;
+typedef unsigned short gdb_wince_len;
+typedef short gdb_wince_result;
diff --git a/contrib/gdb/gdb/wince.c b/contrib/gdb/gdb/wince.c
new file mode 100644
index 0000000..f15bbd4
--- /dev/null
+++ b/contrib/gdb/gdb/wince.c
@@ -0,0 +1,2049 @@
+/* Target-vector operations for controlling Windows CE child processes, for GDB.
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions, A Red Hat Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/* by Christopher Faylor (cgf@cygnus.com) */
+
+/* We assume we're being built with and will be used for cygwin. */
+
+#ifdef SHx
+#undef SH4
+#define SH4 /* Just to get all of the CONTEXT defines. */
+#endif
+
+#include "defs.h"
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "command.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <windows.h>
+#include <rapi.h>
+#include <netdb.h>
+#include <cygwin/in.h>
+#include <cygwin/socket.h>
+
+#include "buildsym.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h"
+#include "gdbthread.h"
+#include "gdbcmd.h"
+#include <sys/param.h>
+#include "wince-stub.h"
+#include <time.h>
+#include "regcache.h"
+#ifdef MIPS
+#include "mips-tdep.h"
+#endif
+
+/* The ui's event loop. */
+extern int (*ui_loop_hook) (int signo);
+
+/* If we're not using the old Cygwin header file set, define the
+ following which never should have been in the generic Win32 API
+ headers in the first place since they were our own invention... */
+#ifndef _GNU_H_WINDOWS_H
+#define FLAG_TRACE_BIT 0x100
+#ifdef CONTEXT_FLOATING_POINT
+#define CONTEXT_DEBUGGER0 (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
+#else
+#define CONTEXT_DEBUGGER0 (CONTEXT_FULL)
+#endif
+#endif
+
+#ifdef SH4
+#define CONTEXT_DEBUGGER ((CONTEXT_DEBUGGER0 & ~(CONTEXT_SH4 | CONTEXT_FLOATING_POINT)) | CONTEXT_SH3)
+#else
+#define CONTEXT_DEBUGGER CONTEXT_DEBUGGER0
+#endif
+/* The string sent by cygwin when it processes a signal.
+ FIXME: This should be in a cygwin include file. */
+#define CYGWIN_SIGNAL_STRING "cygwin: signal"
+
+#define CHECK(x) check (x, __FILE__,__LINE__)
+#define DEBUG_EXEC(x) if (debug_exec) printf x
+#define DEBUG_EVENTS(x) if (debug_events) printf x
+#define DEBUG_MEM(x) if (debug_memory) printf x
+#define DEBUG_EXCEPT(x) if (debug_exceptions) printf x
+
+static int connection_initialized = 0; /* True if we've initialized a RAPI session. */
+
+/* The directory where the stub and executable files are uploaded. */
+static const char *remote_directory = "\\gdb";
+
+/* The types automatic upload available. */
+static enum
+ {
+ UPLOAD_ALWAYS = 0,
+ UPLOAD_NEWER = 1,
+ UPLOAD_NEVER = 2
+ }
+upload_when = UPLOAD_NEWER;
+
+/* Valid options for 'set remoteupload'. Note that options
+ must track upload_when enum. */
+static struct opts
+ {
+ const char *name;
+ int abbrev;
+ }
+upload_options[3] =
+{
+ {
+ "always", 1
+ }
+ ,
+ {
+ "newer", 3
+ }
+ ,
+ {
+ "never", 3
+ }
+};
+
+static char *remote_upload = NULL; /* Set by set remoteupload */
+static int remote_add_host = 0;
+
+/* Forward declaration */
+extern struct target_ops child_ops;
+
+static int win32_child_thread_alive (ptid_t);
+void child_kill_inferior (void);
+
+static int last_sig = 0; /* Set if a signal was received from the
+ debugged process */
+
+/* Thread information structure used to track information that is
+ not available in gdb's thread structure. */
+typedef struct thread_info_struct
+ {
+ struct thread_info_struct *next;
+ DWORD id;
+ HANDLE h;
+ char *name;
+ int suspend_count;
+ int stepped; /* True if stepped. */
+ CORE_ADDR step_pc;
+ unsigned long step_prev;
+ CONTEXT context;
+ }
+thread_info;
+
+static thread_info thread_head =
+{NULL};
+static thread_info * thread_rec (DWORD id, int get_context);
+
+/* The process and thread handles for the above context. */
+
+static DEBUG_EVENT current_event; /* The current debug event from
+ WaitForDebugEvent */
+static HANDLE current_process_handle; /* Currently executing process */
+static thread_info *current_thread; /* Info on currently selected thread */
+static thread_info *this_thread; /* Info on thread returned by wait_for_debug_event */
+static DWORD main_thread_id; /* Thread ID of the main thread */
+
+/* Counts of things. */
+static int exception_count = 0;
+static int event_count = 0;
+
+/* User options. */
+static int debug_exec = 0; /* show execution */
+static int debug_events = 0; /* show events from kernel */
+static int debug_memory = 0; /* show target memory accesses */
+static int debug_exceptions = 0; /* show target exceptions */
+
+/* An array of offset mappings into a Win32 Context structure.
+ This is a one-to-one mapping which is indexed by gdb's register
+ numbers. It retrieves an offset into the context structure where
+ the 4 byte register is located.
+ An offset value of -1 indicates that Win32 does not provide this
+ register in it's CONTEXT structure. regptr will return zero for this
+ register.
+
+ This is used by the regptr function. */
+#define context_offset(x) ((int)&(((PCONTEXT)NULL)->x))
+static const int mappings[NUM_REGS + 1] =
+{
+#ifdef __i386__
+ context_offset (Eax),
+ context_offset (Ecx),
+ context_offset (Edx),
+ context_offset (Ebx),
+ context_offset (Esp),
+ context_offset (Ebp),
+ context_offset (Esi),
+ context_offset (Edi),
+ context_offset (Eip),
+ context_offset (EFlags),
+ context_offset (SegCs),
+ context_offset (SegSs),
+ context_offset (SegDs),
+ context_offset (SegEs),
+ context_offset (SegFs),
+ context_offset (SegGs),
+ context_offset (FloatSave.RegisterArea[0 * 10]),
+ context_offset (FloatSave.RegisterArea[1 * 10]),
+ context_offset (FloatSave.RegisterArea[2 * 10]),
+ context_offset (FloatSave.RegisterArea[3 * 10]),
+ context_offset (FloatSave.RegisterArea[4 * 10]),
+ context_offset (FloatSave.RegisterArea[5 * 10]),
+ context_offset (FloatSave.RegisterArea[6 * 10]),
+ context_offset (FloatSave.RegisterArea[7 * 10]),
+#elif defined(SHx)
+ context_offset (R0),
+ context_offset (R1),
+ context_offset (R2),
+ context_offset (R3),
+ context_offset (R4),
+ context_offset (R5),
+ context_offset (R6),
+ context_offset (R7),
+ context_offset (R8),
+ context_offset (R9),
+ context_offset (R10),
+ context_offset (R11),
+ context_offset (R12),
+ context_offset (R13),
+ context_offset (R14),
+ context_offset (R15),
+ context_offset (Fir),
+ context_offset (PR), /* Procedure Register */
+ context_offset (GBR), /* Global Base Register */
+ context_offset (MACH), /* Accumulate */
+ context_offset (MACL), /* Multiply */
+ context_offset (Psr),
+ context_offset (Fpul),
+ context_offset (Fpscr),
+ context_offset (FRegs[0]),
+ context_offset (FRegs[1]),
+ context_offset (FRegs[2]),
+ context_offset (FRegs[3]),
+ context_offset (FRegs[4]),
+ context_offset (FRegs[5]),
+ context_offset (FRegs[6]),
+ context_offset (FRegs[7]),
+ context_offset (FRegs[8]),
+ context_offset (FRegs[9]),
+ context_offset (FRegs[10]),
+ context_offset (FRegs[11]),
+ context_offset (FRegs[12]),
+ context_offset (FRegs[13]),
+ context_offset (FRegs[14]),
+ context_offset (FRegs[15]),
+ context_offset (xFRegs[0]),
+ context_offset (xFRegs[1]),
+ context_offset (xFRegs[2]),
+ context_offset (xFRegs[3]),
+ context_offset (xFRegs[4]),
+ context_offset (xFRegs[5]),
+ context_offset (xFRegs[6]),
+ context_offset (xFRegs[7]),
+ context_offset (xFRegs[8]),
+ context_offset (xFRegs[9]),
+ context_offset (xFRegs[10]),
+ context_offset (xFRegs[11]),
+ context_offset (xFRegs[12]),
+ context_offset (xFRegs[13]),
+ context_offset (xFRegs[14]),
+ context_offset (xFRegs[15]),
+#elif defined(MIPS)
+ context_offset (IntZero),
+ context_offset (IntAt),
+ context_offset (IntV0),
+ context_offset (IntV1),
+ context_offset (IntA0),
+ context_offset (IntA1),
+ context_offset (IntA2),
+ context_offset (IntA3),
+ context_offset (IntT0),
+ context_offset (IntT1),
+ context_offset (IntT2),
+ context_offset (IntT3),
+ context_offset (IntT4),
+ context_offset (IntT5),
+ context_offset (IntT6),
+ context_offset (IntT7),
+ context_offset (IntS0),
+ context_offset (IntS1),
+ context_offset (IntS2),
+ context_offset (IntS3),
+ context_offset (IntS4),
+ context_offset (IntS5),
+ context_offset (IntS6),
+ context_offset (IntS7),
+ context_offset (IntT8),
+ context_offset (IntT9),
+ context_offset (IntK0),
+ context_offset (IntK1),
+ context_offset (IntGp),
+ context_offset (IntSp),
+ context_offset (IntS8),
+ context_offset (IntRa),
+ context_offset (Psr),
+ context_offset (IntLo),
+ context_offset (IntHi),
+ -1, /* bad */
+ -1, /* cause */
+ context_offset (Fir),
+ context_offset (FltF0),
+ context_offset (FltF1),
+ context_offset (FltF2),
+ context_offset (FltF3),
+ context_offset (FltF4),
+ context_offset (FltF5),
+ context_offset (FltF6),
+ context_offset (FltF7),
+ context_offset (FltF8),
+ context_offset (FltF9),
+ context_offset (FltF10),
+ context_offset (FltF11),
+ context_offset (FltF12),
+ context_offset (FltF13),
+ context_offset (FltF14),
+ context_offset (FltF15),
+ context_offset (FltF16),
+ context_offset (FltF17),
+ context_offset (FltF18),
+ context_offset (FltF19),
+ context_offset (FltF20),
+ context_offset (FltF21),
+ context_offset (FltF22),
+ context_offset (FltF23),
+ context_offset (FltF24),
+ context_offset (FltF25),
+ context_offset (FltF26),
+ context_offset (FltF27),
+ context_offset (FltF28),
+ context_offset (FltF29),
+ context_offset (FltF30),
+ context_offset (FltF31),
+ context_offset (Fsr),
+ context_offset (Fir),
+ -1, /* fp */
+#elif defined(ARM)
+ context_offset (R0),
+ context_offset (R1),
+ context_offset (R2),
+ context_offset (R3),
+ context_offset (R4),
+ context_offset (R5),
+ context_offset (R6),
+ context_offset (R7),
+ context_offset (R8),
+ context_offset (R9),
+ context_offset (R10),
+ context_offset (R11),
+ context_offset (R12),
+ context_offset (Sp),
+ context_offset (Lr),
+ context_offset (Pc),
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ context_offset (Psr),
+#endif
+ -1
+};
+
+/* Return a pointer into a CONTEXT field indexed by gdb register number.
+ Return a pointer to an address pointing to zero if there is no
+ corresponding CONTEXT field for the given register number.
+ */
+static ULONG *
+regptr (LPCONTEXT c, int r)
+{
+ static ULONG zero = 0;
+ ULONG *p;
+ if (mappings[r] < 0)
+ p = &zero;
+ else
+ p = (ULONG *) (((char *) c) + mappings[r]);
+ return p;
+}
+
+/******************** Beginning of stub interface ********************/
+
+/* Stub interface description:
+
+ The Windows CE stub implements a crude RPC. The hand-held device
+ connects to gdb using port 7000. gdb and the stub then communicate
+ using packets where:
+
+ byte 0: command id (e.g. Create Process)
+
+ byte 1-4: DWORD
+
+ byte 1-2: WORD
+
+ byte 1-2: length
+ byte 3-n: arbitrary memory.
+
+ The interface is deterministic, i.e., if the stub expects a DWORD then
+ the gdb server should send a DWORD.
+ */
+
+/* Note: In the functions below, the `huh' parameter is a string passed from the
+ function containing a descriptive string concerning the current operation.
+ This is used for error reporting.
+
+ The 'what' parameter is a command id as found in wince-stub.h.
+
+ Hopefully, the rest of the parameters are self-explanatory.
+ */
+
+static int s; /* communication socket */
+
+/* v-style interface for handling varying argyment list error messages.
+ Displays the error message in a dialog box and exits when user clicks
+ on OK. */
+static void
+vstub_error (LPCSTR fmt, va_list * args)
+{
+ char buf[4096];
+ vsprintf (buf, fmt, args);
+ s = -1;
+ error ("%s", buf);
+}
+
+/* The standard way to display an error message and exit. */
+static void
+stub_error (LPCSTR fmt,...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vstub_error (fmt, args);
+}
+
+/* Standard "oh well" can't communicate error. Someday this might attempt
+ synchronization. */
+static void
+attempt_resync (LPCSTR huh, int s)
+{
+ stub_error ("lost synchronization with target attempting %s", huh);
+}
+
+/* Read arbitrary stuff from a socket. */
+static int
+sockread (LPCSTR huh, int s, void *str, size_t n)
+{
+ for (;;)
+ {
+ if (recv (s, str, n, 0) == n)
+ return n;
+ attempt_resync (huh, s);
+ }
+}
+
+/* Write arbitrary stuff to a socket. */
+static int
+sockwrite (LPCSTR huh, const void *str, size_t n)
+{
+ for (;;)
+ {
+ if (send (s, str, n, 0) == n)
+ return n;
+ attempt_resync (huh, s);
+ }
+}
+
+/* Output an id/dword to the host */
+static void
+putdword (LPCSTR huh, gdb_wince_id what, DWORD n)
+{
+ if (sockwrite (huh, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error writing record id to host for %s", huh);
+ if (sockwrite (huh, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error writing %s to host.", huh);
+}
+
+/* Output an id/word to the host */
+static void
+putword (LPCSTR huh, gdb_wince_id what, WORD n)
+{
+ if (sockwrite (huh, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error writing record id to host for %s", huh);
+ if (sockwrite (huh, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error writing %s host.", huh);
+}
+
+/* Convenience define for outputting a "gdb_wince_len" type. */
+#define putlen(huh, what, n) putword((huh), (what), (gdb_wince_len) (n))
+
+/* Put an arbitrary block of memory to the gdb host. This comes in
+ two chunks an id/dword representing the length and the stream of memory
+ itself. */
+static void
+putmemory (LPCSTR huh, gdb_wince_id what, const void *mem, gdb_wince_len len)
+{
+ putlen (huh, what, len);
+ if (((short) len > 0) && sockwrite (huh, mem, len) != len)
+ stub_error ("error writing %s to host.", huh);
+}
+
+/* Output the result of an operation to the host. If res != 0, sends a block of
+ memory starting at mem of len bytes. If res == 0, sends -GetLastError () and
+ avoids sending the mem. */
+static DWORD
+getdword (LPCSTR huh, gdb_wince_id what_this)
+{
+ DWORD n;
+ gdb_wince_id what;
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error getting %s from host.", huh);
+
+ return n;
+}
+
+/* Get a an ID (possibly) and a WORD from the host gdb.
+ Don't bother with the id if the main loop has already
+ read it. */
+static WORD
+getword (LPCSTR huh, gdb_wince_id what_this)
+{
+ WORD n;
+ gdb_wince_id what;
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error getting %s from host.", huh);
+
+ return n;
+}
+
+/* Handy defines for getting/putting various types of values. */
+#define gethandle(huh, what) (HANDLE) getdword ((huh), (what))
+#define getpvoid(huh, what) (LPVOID) getdword ((huh), (what))
+#define getlen(huh, what) (gdb_wince_len) getword ((huh), (what))
+#define puthandle(huh, what, h) putdword ((huh), (what), (DWORD) (h))
+#define putpvoid(huh, what, p) putdword ((huh), (what), (DWORD) (p))
+
+/* Retrieve the result of an operation from the stub. If nbytes < 0) then nbytes
+ is actually an error and nothing else follows. Use SetLastError to remember this.
+ if nbytes > 0, retrieve a block of *nbytes into buf.
+ */
+int
+getresult (LPCSTR huh, gdb_wince_id what, LPVOID buf, gdb_wince_len * nbytes)
+{
+ gdb_wince_len dummy;
+ if (nbytes == NULL)
+ nbytes = &dummy;
+
+ *nbytes = getlen (huh, what);
+
+ if ((short) *nbytes < 0)
+ {
+ SetLastError (-(short) *nbytes);
+ return 0;
+ }
+
+ if ((gdb_wince_len) sockread (huh, s, buf, *nbytes) != *nbytes)
+ stub_error ("couldn't read information from wince stub - %s", huh);
+
+ return 1;
+}
+
+/* Convert "narrow" string to "wide". Manipulates a buffer ring of 8
+ buffers which hold the translated string. This is an arbitrary limit
+ but it is approximately double the current needs of this module.
+ */
+LPWSTR
+towide (const char *s, gdb_wince_len * out_len)
+{
+ static int n = -1;
+ static LPWSTR outs[8] =
+ {NULL /*, NULL, etc. */ };
+ gdb_wince_len dummy;
+
+ if (!out_len)
+ out_len = &dummy;
+
+ /* First determine the length required to hold the converted string. */
+ *out_len = sizeof (WCHAR) * MultiByteToWideChar (CP_ACP, 0, s, -1, NULL, 0);
+ if (!*out_len)
+ return NULL; /* The conversion failed */
+
+ if (++n >= (sizeof (outs) / sizeof (outs[0])))
+ n = 0; /* wrap */
+
+ /* Allocate space for the converted string, reusing any previously allocated
+ space, if applicable. Note that if outs[n] is NULL, xrealloc will act as
+ a malloc (under cygwin, at least).
+ */
+ outs[n] = (LPWSTR) xrealloc (outs[n], *out_len);
+ memset (outs[n], 0, *out_len);
+ (void) MultiByteToWideChar (CP_ACP, 0, s, -1, outs[n], *out_len);
+ return outs[n];
+}
+
+/******************** Emulation routines start here. ********************
+
+ The functions below are modelled after their Win32 counterparts. They are named
+ similarly to Win32 and take exactly the same arguments except where otherwise noted.
+ They communicate with the stub on the hand-held device by sending their arguments
+ over the socket and waiting for results from the socket.
+
+ There is one universal change. In cases where a length is expected to be returned
+ in a DWORD, we use a gdb_wince_len type instead. Currently this is an unsigned short
+ which is smaller than the standard Win32 DWORD. This is done to minimize unnecessary
+ traffic since the connection to Windows CE can be slow. To change this, modify the
+ typedef in wince-stub.h and change the putlen/getlen macros in this file and in
+ the stub.
+*/
+
+static int
+create_process (LPSTR exec_file, LPSTR args, DWORD flags, PROCESS_INFORMATION * pi)
+{
+ gdb_wince_len len;
+ LPWSTR buf;
+
+ buf = towide (exec_file, &len);
+ putmemory ("CreateProcess exec_file", GDB_CREATEPROCESS, buf, len);
+ buf = towide (args, &len);
+ putmemory ("CreateProcess args", GDB_CREATEPROCESS, buf, len);
+ putdword ("CreateProcess flags", GDB_CREATEPROCESS, flags);
+ return getresult ("CreateProcess result", GDB_CREATEPROCESS, pi, NULL);
+}
+
+/* Emulate TerminateProcess. Don't bother with the second argument since CE
+ ignores it.
+ */
+static int
+terminate_process (HANDLE h)
+{
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("TerminateProcess handle", GDB_TERMINATEPROCESS, h);
+ return getresult ("TerminateProcess result", GDB_TERMINATEPROCESS, &res, NULL);
+}
+
+static int
+wait_for_debug_event (DEBUG_EVENT * ev, DWORD ms)
+{
+ if (s < 0)
+ return 1;
+ putdword ("WaitForDebugEvent ms", GDB_WAITFORDEBUGEVENT, ms);
+ return getresult ("WaitForDebugEvent event", GDB_WAITFORDEBUGEVENT, ev, NULL);
+}
+
+static int
+get_thread_context (HANDLE h, CONTEXT * c)
+{
+ if (s < 0)
+ return 1;
+ puthandle ("GetThreadContext handle", GDB_GETTHREADCONTEXT, h);
+ putdword ("GetThreadContext flags", GDB_GETTHREADCONTEXT, c->ContextFlags);
+ return getresult ("GetThreadContext context", GDB_GETTHREADCONTEXT, c, NULL);
+}
+
+static int
+set_thread_context (HANDLE h, CONTEXT * c)
+{
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("SetThreadContext handle", GDB_SETTHREADCONTEXT, h);
+ putmemory ("SetThreadContext context", GDB_SETTHREADCONTEXT, c, sizeof (*c));
+ return getresult ("SetThreadContext context", GDB_SETTHREADCONTEXT, &res, NULL);
+}
+
+static int
+read_process_memory (HANDLE h, LPCVOID where, LPVOID buf, gdb_wince_len len, gdb_wince_len * nbytes)
+{
+ if (s < 0)
+ return 1;
+ puthandle ("ReadProcessMemory handle", GDB_READPROCESSMEMORY, h);
+ putpvoid ("ReadProcessMemory location", GDB_READPROCESSMEMORY, where);
+ putlen ("ReadProcessMemory size", GDB_READPROCESSMEMORY, len);
+
+ return getresult ("ReadProcessMemory buf", GDB_READPROCESSMEMORY, buf, nbytes);
+}
+
+static int
+write_process_memory (HANDLE h, LPCVOID where, LPCVOID buf, gdb_wince_len len, gdb_wince_len * nbytes)
+{
+ if (s < 0)
+ return 1;
+ puthandle ("WriteProcessMemory handle", GDB_WRITEPROCESSMEMORY, h);
+ putpvoid ("WriteProcessMemory location", GDB_WRITEPROCESSMEMORY, where);
+ putmemory ("WriteProcProcessMemory buf", GDB_WRITEPROCESSMEMORY, buf, len);
+
+ return getresult ("WriteProcessMemory result", GDB_WRITEPROCESSMEMORY, nbytes, NULL);
+}
+
+static int
+remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ gdb_wince_len nbytes;
+ if (!read_process_memory (current_process_handle, (LPCVOID) memaddr,
+ (LPVOID) myaddr, len, &nbytes))
+ return -1;
+ return nbytes;
+}
+
+static int
+remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ gdb_wince_len nbytes;
+ if (!write_process_memory (current_process_handle, (LPCVOID) memaddr,
+ (LPCVOID) myaddr, len, &nbytes))
+ return -1;
+ return nbytes;
+}
+
+/* This is not a standard Win32 function. It instructs the stub to return TRUE
+ if the thread referenced by HANDLE h is alive.
+ */
+static int
+thread_alive (HANDLE h)
+{
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("ThreadAlive handle", GDB_THREADALIVE, h);
+ return getresult ("ThreadAlive result", GDB_THREADALIVE, &res, NULL);
+}
+
+static int
+suspend_thread (HANDLE h)
+{
+ if (s < 0)
+ return 1;
+ puthandle ("SuspendThread handle", GDB_SUSPENDTHREAD, h);
+ return (int) getdword ("SuspendThread result", GDB_SUSPENDTHREAD);
+}
+
+static int
+resume_thread (HANDLE h)
+{
+ if (s < 0)
+ return 1;
+ puthandle ("ResumeThread handle", GDB_RESUMETHREAD, h);
+ return (int) getdword ("SuspendThread result", GDB_RESUMETHREAD);
+}
+
+static int
+continue_debug_event (DWORD pid, DWORD tid, DWORD status)
+{
+ gdb_wince_result res;
+ if (s < 0)
+ return 0;
+ putdword ("ContinueDebugEvent pid", GDB_CONTINUEDEBUGEVENT, pid);
+ putdword ("ContinueDebugEvent tid", GDB_CONTINUEDEBUGEVENT, tid);
+ putdword ("ContinueDebugEvent status", GDB_CONTINUEDEBUGEVENT, status);
+ return getresult ("ContinueDebugEvent result", GDB_CONTINUEDEBUGEVENT, &res, NULL);
+}
+
+static int
+close_handle (HANDLE h)
+{
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("CloseHandle handle", GDB_CLOSEHANDLE, h);
+ return (int) getresult ("CloseHandle result", GDB_CLOSEHANDLE, &res, NULL);
+}
+
+/* This is not a standard Win32 interface. This function tells the stub
+ to terminate.
+ */
+static void
+stop_stub (void)
+{
+ if (s < 0)
+ return;
+ (void) putdword ("Stopping gdb stub", GDB_STOPSTUB, 0);
+ s = -1;
+}
+
+/******************** End of emulation routines. ********************/
+/******************** End of stub interface ********************/
+
+#define check_for_step(a, x) (x)
+
+#ifdef MIPS
+static void
+undoSStep (thread_info * th)
+{
+ if (th->stepped)
+ {
+ memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
+ th->stepped = 0;
+ }
+}
+
+void
+wince_software_single_step (enum target_signal ignore,
+ int insert_breakpoints_p)
+{
+ unsigned long pc;
+ thread_info *th = current_thread; /* Info on currently selected thread */
+ CORE_ADDR mips_next_pc (CORE_ADDR pc);
+
+ if (!insert_breakpoints_p)
+ {
+ undoSStep (th);
+ return;
+ }
+
+ th->stepped = 1;
+ pc = read_register (PC_REGNUM);
+ th->step_pc = mips_next_pc (pc);
+ th->step_prev = 0;
+ memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
+ return;
+}
+#elif SHx
+/* Renesas SH architecture instruction encoding masks */
+
+#define COND_BR_MASK 0xff00
+#define UCOND_DBR_MASK 0xe000
+#define UCOND_RBR_MASK 0xf0df
+#define TRAPA_MASK 0xff00
+
+#define COND_DISP 0x00ff
+#define UCOND_DISP 0x0fff
+#define UCOND_REG 0x0f00
+
+/* Renesas SH instruction opcodes */
+
+#define BF_INSTR 0x8b00
+#define BT_INSTR 0x8900
+#define BRA_INSTR 0xa000
+#define BSR_INSTR 0xb000
+#define JMP_INSTR 0x402b
+#define JSR_INSTR 0x400b
+#define RTS_INSTR 0x000b
+#define RTE_INSTR 0x002b
+#define TRAPA_INSTR 0xc300
+#define SSTEP_INSTR 0xc3ff
+
+
+#define T_BIT_MASK 0x0001
+
+static CORE_ADDR
+sh_get_next_pc (CONTEXT *c)
+{
+ short *instrMem;
+ int displacement;
+ int reg;
+ unsigned short opcode;
+
+ instrMem = (short *) c->Fir;
+
+ opcode = read_memory_integer ((CORE_ADDR) c->Fir, sizeof (opcode));
+
+ if ((opcode & COND_BR_MASK) == BT_INSTR)
+ {
+ if (c->Psr & T_BIT_MASK)
+ {
+ displacement = (opcode & COND_DISP) << 1;
+ if (displacement & 0x80)
+ displacement |= 0xffffff00;
+ /*
+ * Remember PC points to second instr.
+ * after PC of branch ... so add 4
+ */
+ instrMem = (short *) (c->Fir + displacement + 4);
+ }
+ else
+ instrMem += 1;
+ }
+ else if ((opcode & COND_BR_MASK) == BF_INSTR)
+ {
+ if (c->Psr & T_BIT_MASK)
+ instrMem += 1;
+ else
+ {
+ displacement = (opcode & COND_DISP) << 1;
+ if (displacement & 0x80)
+ displacement |= 0xffffff00;
+ /*
+ * Remember PC points to second instr.
+ * after PC of branch ... so add 4
+ */
+ instrMem = (short *) (c->Fir + displacement + 4);
+ }
+ }
+ else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR)
+ {
+ displacement = (opcode & UCOND_DISP) << 1;
+ if (displacement & 0x0800)
+ displacement |= 0xfffff000;
+
+ /*
+ * Remember PC points to second instr.
+ * after PC of branch ... so add 4
+ */
+ instrMem = (short *) (c->Fir + displacement + 4);
+ }
+ else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR)
+ {
+ reg = (char) ((opcode & UCOND_REG) >> 8);
+
+ instrMem = (short *) *regptr (c, reg);
+ }
+ else if (opcode == RTS_INSTR)
+ instrMem = (short *) c->PR;
+ else if (opcode == RTE_INSTR)
+ instrMem = (short *) *regptr (c, 15);
+ else if ((opcode & TRAPA_MASK) == TRAPA_INSTR)
+ instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2);
+ else
+ instrMem += 1;
+
+ return (CORE_ADDR) instrMem;
+}
+/* Single step (in a painstaking fashion) by inspecting the current
+ instruction and setting a breakpoint on the "next" instruction
+ which would be executed. This code hails from sh-stub.c.
+ */
+static void
+undoSStep (thread_info * th)
+{
+ if (th->stepped)
+ {
+ memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
+ th->stepped = 0;
+ }
+ return;
+}
+
+/* Single step (in a painstaking fashion) by inspecting the current
+ instruction and setting a breakpoint on the "next" instruction
+ which would be executed. This code hails from sh-stub.c.
+ */
+void
+wince_software_single_step (enum target_signal ignore,
+ int insert_breakpoints_p)
+{
+ thread_info *th = current_thread; /* Info on currently selected thread */
+
+ if (!insert_breakpoints_p)
+ {
+ undoSStep (th);
+ return;
+ }
+
+ th->stepped = 1;
+ th->step_pc = sh_get_next_pc (&th->context);
+ th->step_prev = 0;
+ memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
+ return;
+}
+#elif defined (ARM)
+#undef check_for_step
+
+static enum target_signal
+check_for_step (DEBUG_EVENT *ev, enum target_signal x)
+{
+ thread_info *th = thread_rec (ev->dwThreadId, 1);
+
+ if (th->stepped &&
+ th->step_pc == (CORE_ADDR) ev->u.Exception.ExceptionRecord.ExceptionAddress)
+ return TARGET_SIGNAL_TRAP;
+ else
+ return x;
+}
+
+/* Single step (in a painstaking fashion) by inspecting the current
+ instruction and setting a breakpoint on the "next" instruction
+ which would be executed. This code hails from sh-stub.c.
+ */
+static void
+undoSStep (thread_info * th)
+{
+ if (th->stepped)
+ {
+ memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
+ th->stepped = 0;
+ }
+}
+
+void
+wince_software_single_step (enum target_signal ignore,
+ int insert_breakpoints_p)
+{
+ unsigned long pc;
+ thread_info *th = current_thread; /* Info on currently selected thread */
+ CORE_ADDR mips_next_pc (CORE_ADDR pc);
+
+ if (!insert_breakpoints_p)
+ {
+ undoSStep (th);
+ return;
+ }
+
+ th->stepped = 1;
+ pc = read_register (PC_REGNUM);
+ th->step_pc = arm_get_next_pc (pc);
+ th->step_prev = 0;
+ memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
+ return;
+}
+#endif
+
+/* Find a thread record given a thread id.
+ If get_context then also retrieve the context for this
+ thread. */
+static thread_info *
+thread_rec (DWORD id, int get_context)
+{
+ thread_info *th;
+
+ for (th = &thread_head; (th = th->next) != NULL;)
+ if (th->id == id)
+ {
+ if (!th->suspend_count && get_context)
+ {
+ if (get_context > 0 && th != this_thread)
+ th->suspend_count = suspend_thread (th->h) + 1;
+ else if (get_context < 0)
+ th->suspend_count = -1;
+
+ th->context.ContextFlags = CONTEXT_DEBUGGER;
+ get_thread_context (th->h, &th->context);
+ }
+ return th;
+ }
+
+ return NULL;
+}
+
+/* Add a thread to the thread list */
+static thread_info *
+child_add_thread (DWORD id, HANDLE h)
+{
+ thread_info *th;
+
+ if ((th = thread_rec (id, FALSE)))
+ return th;
+
+ th = (thread_info *) xmalloc (sizeof (*th));
+ memset (th, 0, sizeof (*th));
+ th->id = id;
+ th->h = h;
+ th->next = thread_head.next;
+ thread_head.next = th;
+ add_thread (id);
+ return th;
+}
+
+/* Clear out any old thread list and reintialize it to a
+ pristine state. */
+static void
+child_init_thread_list (void)
+{
+ thread_info *th = &thread_head;
+
+ DEBUG_EVENTS (("gdb: child_init_thread_list\n"));
+ init_thread_list ();
+ while (th->next != NULL)
+ {
+ thread_info *here = th->next;
+ th->next = here->next;
+ (void) close_handle (here->h);
+ xfree (here);
+ }
+}
+
+/* Delete a thread from the list of threads */
+static void
+child_delete_thread (DWORD id)
+{
+ thread_info *th;
+
+ if (info_verbose)
+ printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (id));
+ delete_thread (id);
+
+ for (th = &thread_head;
+ th->next != NULL && th->next->id != id;
+ th = th->next)
+ continue;
+
+ if (th->next != NULL)
+ {
+ thread_info *here = th->next;
+ th->next = here->next;
+ close_handle (here->h);
+ xfree (here);
+ }
+}
+
+static void
+check (BOOL ok, const char *file, int line)
+{
+ if (!ok)
+ printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
+}
+
+static void
+do_child_fetch_inferior_registers (int r)
+{
+ if (r >= 0)
+ {
+ supply_register (r, (char *) regptr (&current_thread->context, r));
+ }
+ else
+ {
+ for (r = 0; r < NUM_REGS; r++)
+ do_child_fetch_inferior_registers (r);
+ }
+}
+
+static void
+child_fetch_inferior_registers (int r)
+{
+ current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
+ do_child_fetch_inferior_registers (r);
+}
+
+static void
+do_child_store_inferior_registers (int r)
+{
+ if (r >= 0)
+ deprecated_read_register_gen (r, ((char *) &current_thread->context) + mappings[r]);
+ else
+ {
+ for (r = 0; r < NUM_REGS; r++)
+ do_child_store_inferior_registers (r);
+ }
+}
+
+/* Store a new register value into the current thread context */
+static void
+child_store_inferior_registers (int r)
+{
+ current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
+ do_child_store_inferior_registers (r);
+}
+
+/* Wait for child to do something. Return pid of child, or -1 in case
+ of error; store status through argument pointer OURSTATUS. */
+
+static int
+handle_load_dll (void *dummy)
+{
+ LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
+ char dll_buf[MAX_PATH + 1];
+ char *p, *bufp, *imgp, *dll_name, *dll_basename;
+ int len;
+
+ dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+ if (!event->lpImageName)
+ return 1;
+
+ len = 0;
+ for (bufp = dll_buf, imgp = event->lpImageName;
+ bufp < dll_buf + sizeof (dll_buf);
+ bufp += 16, imgp += 16)
+ {
+ gdb_wince_len nbytes = 0;
+ (void) read_process_memory (current_process_handle,
+ imgp, bufp, 16, &nbytes);
+
+ if (!nbytes && bufp == dll_buf)
+ return 1; /* couldn't read it */
+ for (p = bufp; p < bufp + nbytes; p++)
+ {
+ len++;
+ if (*p == '\0')
+ goto out;
+ if (event->fUnicode)
+ p++;
+ }
+ if (!nbytes)
+ break;
+ }
+
+out:
+ if (!len)
+ return 1;
+#if 0
+ dll_buf[len] = '\0';
+#endif
+ dll_name = alloca (len);
+
+ if (!dll_name)
+ return 1;
+
+ if (!event->fUnicode)
+ memcpy (dll_name, dll_buf, len);
+ else
+ WideCharToMultiByte (CP_ACP, 0, (LPCWSTR) dll_buf, len,
+ dll_name, len, 0, 0);
+
+ while ((p = strchr (dll_name, '\\')))
+ *p = '/';
+
+ /* FIXME!! It would be nice to define one symbol which pointed to the
+ front of the dll if we can't find any symbols. */
+
+ if (!(dll_basename = strrchr (dll_name, '/')))
+ dll_basename = dll_name;
+ else
+ dll_basename++;
+
+ /* The symbols in a dll are offset by 0x1000, which is the
+ the offset from 0 of the first byte in an image - because
+ of the file header and the section alignment.
+
+ FIXME: Is this the real reason that we need the 0x1000 ? */
+
+ printf_unfiltered ("%x:%s", event->lpBaseOfDll, dll_name);
+ printf_unfiltered ("\n");
+
+ return 1;
+}
+
+/* Handle DEBUG_STRING output from child process. */
+static void
+handle_output_debug_string (struct target_waitstatus *ourstatus)
+{
+ char p[256];
+ char s[255];
+ char *q;
+ gdb_wince_len nbytes_read;
+ gdb_wince_len nbytes = current_event.u.DebugString.nDebugStringLength;
+
+ if (nbytes > 255)
+ nbytes = 255;
+
+ memset (p, 0, sizeof (p));
+ if (!read_process_memory (current_process_handle,
+ current_event.u.DebugString.lpDebugStringData,
+ &p, nbytes, &nbytes_read)
+ || !*p)
+ return;
+
+ memset (s, 0, sizeof (s));
+ WideCharToMultiByte (CP_ACP, 0, (LPCWSTR) p, (int) nbytes_read, s,
+ sizeof (s) - 1, NULL, NULL);
+ q = strchr (s, '\n');
+ if (q != NULL)
+ {
+ *q = '\0';
+ if (*--q = '\r')
+ *q = '\0';
+ }
+
+ warning (s);
+
+ return;
+}
+
+/* Handle target exceptions. */
+static int
+handle_exception (struct target_waitstatus *ourstatus)
+{
+#if 0
+ if (current_event.u.Exception.dwFirstChance)
+ return 0;
+#endif
+
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+
+ switch (current_event.u.Exception.ExceptionRecord.ExceptionCode)
+ {
+ case EXCEPTION_ACCESS_VIOLATION:
+ DEBUG_EXCEPT (("gdb: Target exception ACCESS_VIOLATION at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ break;
+ case STATUS_STACK_OVERFLOW:
+ DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ break;
+ case EXCEPTION_BREAKPOINT:
+ DEBUG_EXCEPT (("gdb: Target exception BREAKPOINT at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ case DBG_CONTROL_C:
+ DEBUG_EXCEPT (("gdb: Target exception CONTROL_C at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_INT;
+ /* User typed CTRL-C. Continue with this status */
+ last_sig = SIGINT; /* FIXME - should check pass state */
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ DEBUG_EXCEPT (("gdb: Target exception SINGLE_ILL at 0x%08x\n",
+ current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = check_for_step (&current_event, TARGET_SIGNAL_ILL);
+ break;
+ default:
+ /* This may be a structured exception handling exception. In
+ that case, we want to let the program try to handle it, and
+ only break if we see the exception a second time. */
+
+ printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n",
+ current_event.u.Exception.ExceptionRecord.ExceptionCode,
+ current_event.u.Exception.ExceptionRecord.ExceptionAddress);
+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ break;
+ }
+ exception_count++;
+ return 1;
+}
+
+/* Resume all artificially suspended threads if we are continuing
+ execution */
+static BOOL
+child_continue (DWORD continue_status, int id)
+{
+ int i;
+ thread_info *th;
+ BOOL res;
+
+ DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=%d, DBG_CONTINUE);\n",
+ (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId));
+ res = continue_debug_event (current_event.dwProcessId,
+ current_event.dwThreadId,
+ continue_status);
+ if (res)
+ for (th = &thread_head; (th = th->next) != NULL;)
+ if (((id == -1) || (id == th->id)) && th->suspend_count)
+ {
+ for (i = 0; i < th->suspend_count; i++)
+ (void) resume_thread (th->h);
+ th->suspend_count = 0;
+ }
+
+ return res;
+}
+
+/* Get the next event from the child. Return 1 if the event requires
+ handling by WFI (or whatever).
+ */
+static int
+get_child_debug_event (int pid, struct target_waitstatus *ourstatus,
+ DWORD target_event_code, int *retval)
+{
+ int breakout = 0;
+ BOOL debug_event;
+ DWORD continue_status, event_code;
+ thread_info *th = NULL;
+ static thread_info dummy_thread_info;
+
+ if (!(debug_event = wait_for_debug_event (&current_event, 1000)))
+ {
+ *retval = 0;
+ goto out;
+ }
+
+ event_count++;
+ continue_status = DBG_CONTINUE;
+ *retval = 0;
+
+ event_code = current_event.dwDebugEventCode;
+ breakout = event_code == target_event_code;
+
+ switch (event_code)
+ {
+ case CREATE_THREAD_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "CREATE_THREAD_DEBUG_EVENT"));
+ /* Record the existence of this thread */
+ th = child_add_thread (current_event.dwThreadId,
+ current_event.u.CreateThread.hThread);
+ if (info_verbose)
+ printf_unfiltered ("[New %s]\n",
+ target_pid_to_str (current_event.dwThreadId));
+ break;
+
+ case EXIT_THREAD_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXIT_THREAD_DEBUG_EVENT"));
+ child_delete_thread (current_event.dwThreadId);
+ th = &dummy_thread_info;
+ break;
+
+ case CREATE_PROCESS_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "CREATE_PROCESS_DEBUG_EVENT"));
+ current_process_handle = current_event.u.CreateProcessInfo.hProcess;
+
+ main_thread_id = current_event.dwThreadId;
+ inferior_ptid = pid_to_ptid (main_thread_id);
+ /* Add the main thread */
+ th = child_add_thread (PIDGET (inferior_ptid),
+ current_event.u.CreateProcessInfo.hThread);
+ break;
+
+ case EXIT_PROCESS_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXIT_PROCESS_DEBUG_EVENT"));
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
+ close_handle (current_process_handle);
+ *retval = current_event.dwProcessId;
+ breakout = 1;
+ break;
+
+ case LOAD_DLL_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "LOAD_DLL_DEBUG_EVENT"));
+ catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
+ registers_changed (); /* mark all regs invalid */
+ break;
+
+ case UNLOAD_DLL_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "UNLOAD_DLL_DEBUG_EVENT"));
+ break; /* FIXME: don't know what to do here */
+
+ case EXCEPTION_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXCEPTION_DEBUG_EVENT"));
+ if (handle_exception (ourstatus))
+ *retval = current_event.dwThreadId;
+ else
+ {
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
+ breakout = 0;
+ }
+ break;
+
+ case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "OUTPUT_DEBUG_STRING_EVENT"));
+ handle_output_debug_string ( ourstatus);
+ break;
+ default:
+ printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n",
+ current_event.dwProcessId,
+ current_event.dwThreadId);
+ printf_unfiltered (" unknown event code %d\n",
+ current_event.dwDebugEventCode);
+ break;
+ }
+
+ if (breakout)
+ this_thread = current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
+ else
+ CHECK (child_continue (continue_status, -1));
+
+out:
+ return breakout;
+}
+
+/* Wait for interesting events to occur in the target process. */
+static ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ DWORD event_code;
+ int retval;
+ int pid = PIDGET (ptid);
+
+ /* We loop when we get a non-standard exception rather than return
+ with a SPURIOUS because resume can try and step or modify things,
+ which needs a current_thread->h. But some of these exceptions mark
+ the birth or death of threads, which mean that the current thread
+ isn't necessarily what you think it is. */
+
+ while (1)
+ if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
+ return pid_to_ptid (retval);
+ else
+ {
+ int detach = 0;
+
+ if (ui_loop_hook != NULL)
+ detach = ui_loop_hook (0);
+
+ if (detach)
+ child_kill_inferior ();
+ }
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+child_files_info (struct target_ops *ignore)
+{
+ printf_unfiltered ("\tUsing the running image of child %s.\n",
+ target_pid_to_str (inferior_ptid));
+}
+
+static void
+child_open (char *arg, int from_tty)
+{
+ error ("Use the \"run\" command to start a child process.");
+}
+
+#define FACTOR (0x19db1ded53ea710LL)
+#define NSPERSEC 10000000
+
+/* Convert a Win32 time to "UNIX" format. */
+long
+to_time_t (FILETIME * ptr)
+{
+ /* A file time is the number of 100ns since jan 1 1601
+ stuffed into two long words.
+ A time_t is the number of seconds since jan 1 1970. */
+
+ long rem;
+ long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned) ptr->dwLowDateTime);
+ x -= FACTOR; /* number of 100ns between 1601 and 1970 */
+ rem = x % ((long long) NSPERSEC);
+ rem += (NSPERSEC / 2);
+ x /= (long long) NSPERSEC; /* number of 100ns in a second */
+ x += (long long) (rem / NSPERSEC);
+ return x;
+}
+
+/* Upload a file to the remote device depending on the user's
+ 'set remoteupload' specification. */
+char *
+upload_to_device (const char *to, const char *from)
+{
+ HANDLE h;
+ const char *dir = remote_directory ?: "\\gdb";
+ int len;
+ static char *remotefile = NULL;
+ LPWSTR wstr;
+ char *p;
+ DWORD err;
+ const char *in_to = to;
+ FILETIME crtime, actime, wrtime;
+ time_t utime;
+ struct stat st;
+ int fd;
+
+ /* Look for a path separator and only use trailing part. */
+ while ((p = strpbrk (to, "/\\")) != NULL)
+ to = p + 1;
+
+ if (!*to)
+ error ("no filename found to upload - %s.", in_to);
+
+ len = strlen (dir) + strlen (to) + 2;
+ remotefile = (char *) xrealloc (remotefile, len);
+ strcpy (remotefile, dir);
+ strcat (remotefile, "\\");
+ strcat (remotefile, to);
+
+ if (upload_when == UPLOAD_NEVER)
+ return remotefile; /* Don't bother uploading. */
+
+ /* Open the source. */
+ if ((fd = openp (getenv ("PATH"), TRUE, (char *) from, O_RDONLY, 0, NULL)) < 0)
+ error ("couldn't open %s", from);
+
+ /* Get the time for later comparison. */
+ if (fstat (fd, &st))
+ st.st_mtime = (time_t) - 1;
+
+ /* Always attempt to create the directory on the remote system. */
+ wstr = towide (dir, NULL);
+ (void) CeCreateDirectory (wstr, NULL);
+
+ /* Attempt to open the remote file, creating it if it doesn't exist. */
+ wstr = towide (remotefile, NULL);
+ h = CeCreateFile (wstr, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ /* Some kind of problem? */
+ err = CeGetLastError ();
+ if (h == NULL || h == INVALID_HANDLE_VALUE)
+ error ("error opening file \"%s\". Windows error %d.",
+ remotefile, err);
+
+ CeGetFileTime (h, &crtime, &actime, &wrtime);
+ utime = to_time_t (&wrtime);
+#if 0
+ if (utime < st.st_mtime)
+ {
+ char buf[80];
+ strcpy (buf, ctime(&utime));
+ printf ("%s < %s\n", buf, ctime(&st.st_mtime));
+ }
+#endif
+ /* See if we need to upload the file. */
+ if (upload_when == UPLOAD_ALWAYS ||
+ err != ERROR_ALREADY_EXISTS ||
+ !CeGetFileTime (h, &crtime, &actime, &wrtime) ||
+ to_time_t (&wrtime) < st.st_mtime)
+ {
+ DWORD nbytes;
+ char buf[4096];
+ int n;
+
+ /* Upload the file. */
+ while ((n = read (fd, buf, sizeof (buf))) > 0)
+ if (!CeWriteFile (h, buf, (DWORD) n, &nbytes, NULL))
+ error ("error writing to remote device - %d.",
+ CeGetLastError ());
+ }
+
+ close (fd);
+ if (!CeCloseHandle (h))
+ error ("error closing remote file - %d.", CeGetLastError ());
+
+ return remotefile;
+}
+
+/* Initialize the connection to the remote device. */
+static void
+wince_initialize (void)
+{
+ int tmp;
+ char args[256];
+ char *hostname;
+ struct sockaddr_in sin;
+ char *stub_file_name;
+ int s0;
+ PROCESS_INFORMATION pi;
+
+ if (!connection_initialized)
+ switch (CeRapiInit ())
+ {
+ case 0:
+ connection_initialized = 1;
+ break;
+ default:
+ CeRapiUninit ();
+ error ("Can't initialize connection to remote device.\n");
+ break;
+ }
+
+ /* Upload the stub to the handheld device. */
+ stub_file_name = upload_to_device ("wince-stub.exe", WINCE_STUB);
+ strcpy (args, stub_file_name);
+
+ if (remote_add_host)
+ {
+ strcat (args, " ");
+ hostname = strchr (args, '\0');
+ if (gethostname (hostname, sizeof (args) - strlen (args)))
+ error ("couldn't get hostname of this system.");
+ }
+
+ /* Get a socket. */
+ if ((s0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ stub_error ("Couldn't connect to host system.");
+
+ /* Allow rapid reuse of the port. */
+ tmp = 1;
+ (void) setsockopt (s0, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
+
+
+ /* Set up the information for connecting to the host gdb process. */
+ memset (&sin, 0, sizeof (sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons (7000); /* FIXME: This should be configurable */
+
+ if (bind (s0, (struct sockaddr *) &sin, sizeof (sin)))
+ error ("couldn't bind socket");
+
+ if (listen (s0, 1))
+ error ("Couldn't open socket for listening.\n");
+
+ /* Start up the stub on the remote device. */
+ if (!CeCreateProcess (towide (stub_file_name, NULL), towide (args, NULL),
+ NULL, NULL, 0, 0, NULL, NULL, NULL, &pi))
+ error ("Unable to start remote stub '%s'. Windows CE error %d.",
+ stub_file_name, CeGetLastError ());
+
+ /* Wait for a connection */
+
+ if ((s = accept (s0, NULL, NULL)) < 0)
+ error ("couldn't set up server for connection.");
+
+ close (s0);
+}
+
+/* Start an inferior win32 child process and sets inferior_ptid 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 (char *exec_file, char *args, char **env)
+{
+ PROCESS_INFORMATION pi;
+ struct target_waitstatus dummy;
+ int ret;
+ DWORD flags, event_code;
+ char *exec_and_args;
+
+ if (!exec_file)
+ error ("No executable specified, use `target exec'.\n");
+
+ flags = DEBUG_PROCESS;
+
+ wince_initialize (); /* Make sure we've got a connection. */
+
+ exec_file = upload_to_device (exec_file, exec_file);
+
+ while (*args == ' ')
+ args++;
+
+ /* Allocate space for "command<sp>args" */
+ if (*args == '\0')
+ {
+ exec_and_args = alloca (strlen (exec_file) + 1);
+ strcpy (exec_and_args, exec_file);
+ }
+ else
+ {
+ exec_and_args = alloca (strlen (exec_file + strlen (args) + 2));
+ sprintf (exec_and_args, "%s %s", exec_file, args);
+ }
+
+ memset (&pi, 0, sizeof (pi));
+ /* Execute the process */
+ if (!create_process (exec_file, exec_and_args, flags, &pi))
+ error ("Error creating process %s, (error %d)\n", exec_file, GetLastError ());
+
+ exception_count = 0;
+ event_count = 0;
+
+ current_process_handle = pi.hProcess;
+ current_event.dwProcessId = pi.dwProcessId;
+ memset (&current_event, 0, sizeof (current_event));
+ current_event.dwThreadId = pi.dwThreadId;
+ inferior_ptid = pid_to_ptid (current_event.dwThreadId);
+ push_target (&child_ops);
+ child_init_thread_list ();
+ child_add_thread (pi.dwThreadId, pi.hThread);
+ init_wait_for_inferior ();
+ clear_proceed_status ();
+ target_terminal_init ();
+ target_terminal_inferior ();
+
+ /* Run until process and threads are loaded */
+ while (!get_child_debug_event (PIDGET (inferior_ptid), &dummy,
+ CREATE_PROCESS_DEBUG_EVENT, &ret))
+ continue;
+
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+}
+
+/* Chile has gone bye-bye. */
+static void
+child_mourn_inferior (void)
+{
+ (void) child_continue (DBG_CONTINUE, -1);
+ unpush_target (&child_ops);
+ stop_stub ();
+ CeRapiUninit ();
+ connection_initialized = 0;
+ generic_mourn_inferior ();
+}
+
+/* Move memory from child to/from gdb. */
+int
+child_xfer_memory (CORE_ADDR memaddr, char *our, int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ if (len <= 0)
+ return 0;
+
+ if (write)
+ res = remote_write_bytes (memaddr, our, len);
+ else
+ res = remote_read_bytes (memaddr, our, len);
+
+ return res;
+}
+
+/* Terminate the process and wait for child to tell us it has completed. */
+void
+child_kill_inferior (void)
+{
+ CHECK (terminate_process (current_process_handle));
+
+ for (;;)
+ {
+ if (!child_continue (DBG_CONTINUE, -1))
+ break;
+ if (!wait_for_debug_event (&current_event, INFINITE))
+ break;
+ if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
+ break;
+ }
+
+ CHECK (close_handle (current_process_handle));
+ close_handle (current_thread->h);
+ target_mourn_inferior (); /* or just child_mourn_inferior? */
+}
+
+/* Resume the child after an exception. */
+void
+child_resume (ptid_t ptid, int step, enum target_signal sig)
+{
+ thread_info *th;
+ DWORD continue_status = last_sig > 0 && last_sig < NSIG ?
+ DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
+ int pid = PIDGET (ptid);
+
+ DEBUG_EXEC (("gdb: child_resume (pid=%d, step=%d, sig=%d);\n",
+ pid, step, sig));
+
+ /* Get context for currently selected thread */
+ th = thread_rec (current_event.dwThreadId, FALSE);
+
+ if (th->context.ContextFlags)
+ {
+ CHECK (set_thread_context (th->h, &th->context));
+ th->context.ContextFlags = 0;
+ }
+
+ /* Allow continuing with the same signal that interrupted us.
+ Otherwise complain. */
+ if (sig && sig != last_sig)
+ fprintf_unfiltered (gdb_stderr, "Can't send signals to the child. signal %d\n", sig);
+
+ last_sig = 0;
+ child_continue (continue_status, pid);
+}
+
+static void
+child_prepare_to_store (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static int
+child_can_run (void)
+{
+ return 1;
+}
+
+static void
+child_close (void)
+{
+ DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n",
+ PIDGET (inferior_ptid)));
+}
+
+/* Explicitly upload file to remotedir */
+
+static void
+child_load (char *file, int from_tty)
+{
+ upload_to_device (file, file);
+}
+
+struct target_ops child_ops;
+
+static void
+init_child_ops (void)
+{
+ memset (&child_ops, 0, sizeof (child_ops));
+ child_ops.to_shortname = (char *) "child";
+ child_ops.to_longname = (char *) "Windows CE process";
+ child_ops.to_doc = (char *) "Windows CE process (started by the \"run\" command).";
+ child_ops.to_open = child_open;
+ child_ops.to_close = child_close;
+ child_ops.to_resume = child_resume;
+ child_ops.to_wait = child_wait;
+ child_ops.to_fetch_registers = child_fetch_inferior_registers;
+ child_ops.to_store_registers = child_store_inferior_registers;
+ child_ops.to_prepare_to_store = child_prepare_to_store;
+ child_ops.to_xfer_memory = child_xfer_memory;
+ child_ops.to_files_info = child_files_info;
+ child_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ child_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ child_ops.to_terminal_init = terminal_init_inferior;
+ child_ops.to_terminal_inferior = terminal_inferior;
+ child_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ child_ops.to_terminal_ours = terminal_ours;
+ child_ops.to_terminal_save_ours = terminal_save_ours;
+ child_ops.to_terminal_info = child_terminal_info;
+ child_ops.to_kill = child_kill_inferior;
+ child_ops.to_load = child_load;
+ child_ops.to_create_inferior = child_create_inferior;
+ child_ops.to_mourn_inferior = child_mourn_inferior;
+ child_ops.to_can_run = child_can_run;
+ child_ops.to_thread_alive = win32_child_thread_alive;
+ child_ops.to_stratum = process_stratum;
+ child_ops.to_has_all_memory = 1;
+ child_ops.to_has_memory = 1;
+ child_ops.to_has_stack = 1;
+ child_ops.to_has_registers = 1;
+ child_ops.to_has_execution = 1;
+ child_ops.to_magic = OPS_MAGIC;
+}
+
+
+/* Handle 'set remoteupload' parameter. */
+
+#define replace_upload(what) \
+ upload_when = what; \
+ remote_upload = xrealloc (remote_upload, strlen (upload_options[upload_when].name) + 1); \
+ strcpy (remote_upload, upload_options[upload_when].name);
+
+static void
+set_upload_type (char *ignore, int from_tty)
+{
+ int i, len;
+ char *bad_option;
+
+ if (!remote_upload || !remote_upload[0])
+ {
+ replace_upload (UPLOAD_NEWER);
+ if (from_tty)
+ printf_unfiltered ("Upload upload_options are: always, newer, never.\n");
+ return;
+ }
+
+ len = strlen (remote_upload);
+ for (i = 0; i < (sizeof (upload_options) / sizeof (upload_options[0])); i++)
+ if (len >= upload_options[i].abbrev &&
+ strncasecmp (remote_upload, upload_options[i].name, len) == 0)
+ {
+ replace_upload (i);
+ return;
+ }
+
+ bad_option = remote_upload;
+ replace_upload (UPLOAD_NEWER);
+ error ("Unknown upload type: %s.", bad_option);
+}
+
+void
+_initialize_wince (void)
+{
+ struct cmd_list_element *set;
+ init_child_ops ();
+
+ add_show_from_set
+ (add_set_cmd ((char *) "remotedirectory", no_class,
+ var_string_noescape, (char *) &remote_directory,
+ (char *) "Set directory for remote upload.\n",
+ &setlist),
+ &showlist);
+ remote_directory = xstrdup (remote_directory);
+
+ set = add_set_cmd ((char *) "remoteupload", no_class,
+ var_string_noescape, (char *) &remote_upload,
+ (char *) "Set how to upload executables to remote device.\n",
+ &setlist);
+ add_show_from_set (set, &showlist);
+ set_cmd_cfunc (set, set_upload_type);
+ set_upload_type (NULL, 0);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugexec", class_support, var_boolean,
+ (char *) &debug_exec,
+ (char *) "Set whether to display execution in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "remoteaddhost", class_support, var_boolean,
+ (char *) &remote_add_host,
+ (char *) "\
+Set whether to add this host to remote stub arguments for\n\
+debugging over a network.", &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugevents", class_support, var_boolean,
+ (char *) &debug_events,
+ (char *) "Set whether to display kernel events in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugmemory", class_support, var_boolean,
+ (char *) &debug_memory,
+ (char *) "Set whether to display memory accesses in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugexceptions", class_support, var_boolean,
+ (char *) &debug_exceptions,
+ (char *) "Set whether to display kernel exceptions in child process.",
+ &setlist),
+ &showlist);
+
+ add_target (&child_ops);
+}
+
+/* Determine if the thread referenced by "pid" is alive
+ by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
+ it means that the pid has died. Otherwise it is assumed to be alive. */
+static int
+win32_child_thread_alive (ptid_t ptid)
+{
+ int pid = PIDGET (ptid);
+ return thread_alive (thread_rec (pid, FALSE)->h);
+}
+
+/* Convert pid to printable format. */
+char *
+cygwin_pid_to_str (int pid)
+{
+ static char buf[80];
+ if (pid == current_event.dwProcessId)
+ sprintf (buf, "process %d", pid);
+ else
+ sprintf (buf, "thread %d.0x%x", (unsigned) current_event.dwProcessId, pid);
+ return buf;
+}
diff --git a/contrib/gdb/gdb/wrapper.c b/contrib/gdb/gdb/wrapper.c
new file mode 100644
index 0000000..6c9c6d6
--- /dev/null
+++ b/contrib/gdb/gdb/wrapper.c
@@ -0,0 +1,333 @@
+/* Longjump free calls to gdb internal routines.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "value.h"
+#include "wrapper.h"
+
+/* Use this struct to pass arguments to wrapper routines. We assume
+ (arbitrarily) that no gdb function takes more than ten arguments. */
+struct gdb_wrapper_arguments
+ {
+
+ /* Pointer to some result from the gdb function call, if any */
+ union wrapper_results
+ {
+ int integer;
+ void *pointer;
+ } result;
+
+
+ /* The list of arguments. */
+ union wrapper_args
+ {
+ int integer;
+ void *pointer;
+ } args[10];
+ };
+
+struct captured_value_struct_elt_args
+{
+ struct value **argp;
+ struct value **args;
+ char *name;
+ int *static_memfuncp;
+ char *err;
+ struct value **result_ptr;
+};
+
+static int wrap_parse_exp_1 (char *);
+
+static int wrap_evaluate_expression (char *);
+
+static int wrap_value_fetch_lazy (char *);
+
+static int wrap_value_equal (char *);
+
+static int wrap_value_assign (char *);
+
+static int wrap_value_subscript (char *);
+
+static int wrap_value_ind (char *opaque_arg);
+
+static int do_captured_value_struct_elt (struct ui_out *uiout, void *data);
+
+static int wrap_parse_and_eval_type (char *);
+
+int
+gdb_parse_exp_1 (char **stringptr, struct block *block, int comma,
+ struct expression **expression)
+{
+ struct gdb_wrapper_arguments args;
+ args.args[0].pointer = stringptr;
+ args.args[1].pointer = block;
+ args.args[2].integer = comma;
+
+ if (!catch_errors ((catch_errors_ftype *) wrap_parse_exp_1, &args,
+ "", RETURN_MASK_ERROR))
+ {
+ /* An error occurred */
+ return 0;
+ }
+
+ *expression = (struct expression *) args.result.pointer;
+ return 1;
+
+}
+
+static int
+wrap_parse_exp_1 (char *argptr)
+{
+ struct gdb_wrapper_arguments *args
+ = (struct gdb_wrapper_arguments *) argptr;
+ args->result.pointer = parse_exp_1((char **) args->args[0].pointer,
+ (struct block *) args->args[1].pointer,
+ args->args[2].integer);
+ return 1;
+}
+
+int
+gdb_evaluate_expression (struct expression *exp, struct value **value)
+{
+ struct gdb_wrapper_arguments args;
+ args.args[0].pointer = exp;
+
+ if (!catch_errors ((catch_errors_ftype *) wrap_evaluate_expression, &args,
+ "", RETURN_MASK_ERROR))
+ {
+ /* An error occurred */
+ return 0;
+ }
+
+ *value = (struct value *) args.result.pointer;
+ return 1;
+}
+
+static int
+wrap_evaluate_expression (char *a)
+{
+ struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+
+ (args)->result.pointer =
+ (char *) evaluate_expression ((struct expression *) args->args[0].pointer);
+ return 1;
+}
+
+int
+gdb_value_fetch_lazy (struct value *value)
+{
+ struct gdb_wrapper_arguments args;
+
+ args.args[0].pointer = value;
+ return catch_errors ((catch_errors_ftype *) wrap_value_fetch_lazy, &args,
+ "", RETURN_MASK_ERROR);
+}
+
+static int
+wrap_value_fetch_lazy (char *a)
+{
+ struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+
+ value_fetch_lazy ((struct value *) (args)->args[0].pointer);
+ return 1;
+}
+
+int
+gdb_value_equal (struct value *val1, struct value *val2, int *result)
+{
+ struct gdb_wrapper_arguments args;
+
+ args.args[0].pointer = val1;
+ args.args[1].pointer = val2;
+
+ if (!catch_errors ((catch_errors_ftype *) wrap_value_equal, &args,
+ "", RETURN_MASK_ERROR))
+ {
+ /* An error occurred */
+ return 0;
+ }
+
+ *result = args.result.integer;
+ return 1;
+}
+
+static int
+wrap_value_equal (char *a)
+{
+ struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+ struct value *val1;
+ struct value *val2;
+
+ val1 = (struct value *) (args)->args[0].pointer;
+ val2 = (struct value *) (args)->args[1].pointer;
+
+ (args)->result.integer = value_equal (val1, val2);
+ return 1;
+}
+
+int
+gdb_value_assign (struct value *val1, struct value *val2, struct value **result)
+{
+ struct gdb_wrapper_arguments args;
+
+ args.args[0].pointer = val1;
+ args.args[1].pointer = val2;
+
+ if (!catch_errors ((catch_errors_ftype *) wrap_value_assign, &args,
+ "", RETURN_MASK_ERROR))
+ {
+ /* An error occurred */
+ return 0;
+ }
+
+ *result = (struct value *) args.result.pointer;
+ return 1;
+}
+
+static int
+wrap_value_assign (char *a)
+{
+ struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+ struct value *val1;
+ struct value *val2;
+
+ val1 = (struct value *) (args)->args[0].pointer;
+ val2 = (struct value *) (args)->args[1].pointer;
+
+ (args)->result.pointer = value_assign (val1, val2);
+ return 1;
+}
+
+int
+gdb_value_subscript (struct value *val1, struct value *val2, struct value **rval)
+{
+ struct gdb_wrapper_arguments args;
+
+ args.args[0].pointer = val1;
+ args.args[1].pointer = val2;
+
+ if (!catch_errors ((catch_errors_ftype *) wrap_value_subscript, &args,
+ "", RETURN_MASK_ERROR))
+ {
+ /* An error occurred */
+ return 0;
+ }
+
+ *rval = (struct value *) args.result.pointer;
+ return 1;
+}
+
+static int
+wrap_value_subscript (char *a)
+{
+ struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+ struct value *val1;
+ struct value *val2;
+
+ val1 = (struct value *) (args)->args[0].pointer;
+ val2 = (struct value *) (args)->args[1].pointer;
+
+ (args)->result.pointer = value_subscript (val1, val2);
+ return 1;
+}
+
+int
+gdb_value_ind (struct value *val, struct value **rval)
+{
+ struct gdb_wrapper_arguments args;
+
+ args.args[0].pointer = val;
+
+ if (!catch_errors ((catch_errors_ftype *) wrap_value_ind, &args,
+ "", RETURN_MASK_ERROR))
+ {
+ /* An error occurred */
+ return 0;
+ }
+
+ *rval = (struct value *) args.result.pointer;
+ return 1;
+}
+
+static int
+wrap_value_ind (char *opaque_arg)
+{
+ struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) opaque_arg;
+ struct value *val;
+
+ val = (struct value *) (args)->args[0].pointer;
+ (args)->result.pointer = value_ind (val);
+ return 1;
+}
+
+int
+gdb_parse_and_eval_type (char *p, int length, struct type **type)
+{
+ struct gdb_wrapper_arguments args;
+ args.args[0].pointer = p;
+ args.args[1].integer = length;
+
+ if (!catch_errors ((catch_errors_ftype *) wrap_parse_and_eval_type, &args,
+ "", RETURN_MASK_ALL))
+ {
+ /* An error occurred */
+ return 0;
+ }
+
+ *type = (struct type *) args.result.pointer;
+ return 1;
+}
+
+static int
+wrap_parse_and_eval_type (char *a)
+{
+ struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+
+ char *p = (char *) args->args[0].pointer;
+ int length = args->args[1].integer;
+
+ args->result.pointer = (char *) parse_and_eval_type (p, length);
+
+ return 1;
+}
+
+enum gdb_rc
+gdb_value_struct_elt (struct ui_out *uiout, struct value **result, struct value **argp,
+ struct value **args, char *name, int *static_memfuncp,
+ char *err)
+{
+ struct captured_value_struct_elt_args cargs;
+ cargs.argp = argp;
+ cargs.args = args;
+ cargs.name = name;
+ cargs.static_memfuncp = static_memfuncp;
+ cargs.err = err;
+ cargs.result_ptr = result;
+ return catch_exceptions (uiout, do_captured_value_struct_elt, &cargs,
+ NULL, RETURN_MASK_ALL);
+}
+
+static int
+do_captured_value_struct_elt (struct ui_out *uiout, void *data)
+{
+ struct captured_value_struct_elt_args *cargs = data;
+ *cargs->result_ptr = value_struct_elt (cargs->argp, cargs->args, cargs->name,
+ cargs->static_memfuncp, cargs->err);
+ return GDB_RC_OK;
+}
+
diff --git a/contrib/gdb/gdb/wrapper.h b/contrib/gdb/gdb/wrapper.h
new file mode 100644
index 0000000..b287b29
--- /dev/null
+++ b/contrib/gdb/gdb/wrapper.h
@@ -0,0 +1,51 @@
+/* Longjump free calls to gdb internal routines.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef WRAPPER_H
+#define WRAPPER_H 1
+#include "gdb.h"
+
+struct value;
+struct expression;
+struct block;
+
+/* Use this struct to pass arguments to wrapper routines. */
+struct gdb_wrapper_arguments;
+
+extern int gdb_parse_exp_1 (char **, struct block *,
+ int, struct expression **);
+
+extern int gdb_evaluate_expression (struct expression *, struct value **);
+
+extern int gdb_value_fetch_lazy (struct value *);
+
+extern int gdb_value_equal (struct value *, struct value *, int *);
+
+extern int gdb_value_assign (struct value *, struct value *, struct value **);
+
+extern int gdb_value_subscript (struct value *, struct value *, struct value **);
+
+extern enum gdb_rc gdb_value_struct_elt (struct ui_out *uiout, struct value **result_ptr,
+ struct value **argp, struct value **args,
+ char *name, int *static_memfuncp, char *err);
+
+extern int gdb_value_ind (struct value *val, struct value ** rval);
+
+extern int gdb_parse_and_eval_type (char *, int, struct type **);
+
+#endif /* WRAPPER_H */
diff --git a/contrib/gdb/gdb/xcoffread.c b/contrib/gdb/gdb/xcoffread.c
new file mode 100644
index 0000000..759dfcb
--- /dev/null
+++ b/contrib/gdb/gdb/xcoffread.c
@@ -0,0 +1,3033 @@
+/* Read AIX xcoff symbol tables and convert to internal format, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ 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. */
+
+#include "defs.h"
+#include "bfd.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include "gdb_string.h"
+
+#include <sys/param.h>
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include "gdb_stat.h"
+
+#include "coff/internal.h"
+#include "libcoff.h" /* FIXME, internal data from BFD */
+#include "coff/xcoff.h"
+#include "libxcoff.h"
+#include "coff/rs6000.h"
+
+#include "symtab.h"
+#include "gdbtypes.h"
+/* FIXME: ezannoni/2004-02-13 Verify if the include below is really needed. */
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "expression.h"
+#include "complaints.h"
+
+#include "gdb-stabs.h"
+
+/* For interface with stabsread.c. */
+#include "aout/stab_gnu.h"
+
+
+/* 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;
+
+ /* Offset in data section to TOC anchor. */
+ CORE_ADDR toc_offset;
+ };
+
+static void
+bf_notfound_complaint (void)
+{
+ complaint (&symfile_complaints, "line numbers off, `.bf' symbol not found");
+}
+
+static void
+ef_complaint (int arg1)
+{
+ complaint (&symfile_complaints,
+ "Mismatched .ef symbol ignored starting at symnum %d", arg1);
+}
+
+static void
+eb_complaint (int arg1)
+{
+ complaint (&symfile_complaints,
+ "Mismatched .eb symbol ignored starting at symnum %d", arg1);
+}
+
+static void xcoff_initial_scan (struct objfile *, int);
+
+static void scan_xcoff_symtab (struct objfile *);
+
+static char *xcoff_next_symbol_text (struct objfile *);
+
+static void record_include_begin (struct coff_symbol *);
+
+static void
+enter_line_range (struct subfile *, unsigned, unsigned,
+ CORE_ADDR, CORE_ADDR, unsigned *);
+
+static void init_stringtab (bfd *, file_ptr, struct objfile *);
+
+static void xcoff_symfile_init (struct objfile *);
+
+static void xcoff_new_init (struct objfile *);
+
+static void xcoff_symfile_finish (struct objfile *);
+
+static void xcoff_symfile_offsets (struct objfile *,
+ struct section_addr_info *addrs);
+
+static char *coff_getfilename (union internal_auxent *, struct objfile *);
+
+static void read_symbol (struct internal_syment *, int);
+
+static int read_symbol_lineno (int);
+
+static CORE_ADDR read_symbol_nvalue (int);
+
+static struct symbol *process_xcoff_symbol (struct coff_symbol *,
+ struct objfile *);
+
+static void read_xcoff_symtab (struct partial_symtab *);
+
+#if 0
+static void add_stab_to_list (char *, struct pending_stabs **);
+#endif
+
+static int compare_lte (const void *, const void *);
+
+static struct linetable *arrange_linetable (struct linetable *);
+
+static void record_include_end (struct coff_symbol *);
+
+static void process_linenos (CORE_ADDR, CORE_ADDR);
+
+
+/* Translate from a COFF section number (target_index) to a SECT_OFF_*
+ code. */
+static int secnum_to_section (int, struct objfile *);
+static asection *secnum_to_bfd_section (int, struct objfile *);
+
+struct find_targ_sec_arg
+ {
+ int targ_index;
+ int *resultp;
+ asection **bfd_sect;
+ struct objfile *objfile;
+ };
+
+static void find_targ_sec (bfd *, asection *, void *);
+
+static void
+find_targ_sec (bfd *abfd, asection *sect, void *obj)
+{
+ struct find_targ_sec_arg *args = (struct find_targ_sec_arg *) obj;
+ struct objfile *objfile = args->objfile;
+ 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 (objfile);
+ else if (bfd_get_section_flags (abfd, sect) & SEC_LOAD)
+ *args->resultp = SECT_OFF_DATA (objfile);
+ else
+ *args->resultp = sect->index;
+ *args->bfd_sect = sect;
+ }
+}
+
+/* Return the section number (SECT_OFF_*) that CS points to. */
+static int
+secnum_to_section (int secnum, struct objfile *objfile)
+{
+ int off = SECT_OFF_TEXT (objfile);
+ asection *sect = NULL;
+ struct find_targ_sec_arg args;
+ args.targ_index = secnum;
+ args.resultp = &off;
+ args.bfd_sect = &sect;
+ args.objfile = objfile;
+ bfd_map_over_sections (objfile->obfd, find_targ_sec, &args);
+ return off;
+}
+
+/* Return the BFD section that CS points to. */
+static asection *
+secnum_to_bfd_section (int secnum, struct objfile *objfile)
+{
+ int off = SECT_OFF_TEXT (objfile);
+ asection *sect = NULL;
+ struct find_targ_sec_arg args;
+ args.targ_index = secnum;
+ args.resultp = &off;
+ args.bfd_sect = &sect;
+ args.objfile = objfile;
+ bfd_map_over_sections (objfile->obfd, find_targ_sec, &args);
+ return sect;
+}
+
+/* add a given stab string into given stab vector. */
+
+#if 0
+
+static void
+add_stab_to_list (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;
+}
+
+#endif
+ /* *INDENT-OFF* */
+/* 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. */
+/* *INDENT-ON* */
+
+
+
+/* compare line table entry addresses. */
+
+static int
+compare_lte (const void *lte1p, const void *lte2p)
+{
+ struct linetable_entry *lte1 = (struct linetable_entry *) lte1p;
+ struct linetable_entry *lte2 = (struct linetable_entry *) lte2p;
+ return lte1->pc - lte2->pc;
+}
+
+/* Given a line table with function entries are marked, arrange its functions
+ in ascending 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 (struct linetable *oldLineTb)
+{
+ 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 < oldLineTb->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)
+ {
+ xfree (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];
+ }
+ xfree (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 (void);
+
+static void
+record_include_begin (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. */
+ complaint (&symfile_complaints, "Nested C_BINCL symbols");
+ }
+ ++inclDepth;
+
+ allocate_include_entry ();
+
+ inclTable[inclIndx].name = cs->c_name;
+ inclTable[inclIndx].begin = cs->c_value;
+}
+
+static void
+record_include_end (struct coff_symbol *cs)
+{
+ InclTable *pTbl;
+
+ if (inclDepth == 0)
+ {
+ complaint (&symfile_complaints, "Mismatched C_BINCL/C_EINCL pair");
+ }
+
+ allocate_include_entry ();
+
+ pTbl = &inclTable[inclIndx];
+ pTbl->end = cs->c_value;
+
+ --inclDepth;
+ ++inclIndx;
+}
+
+static void
+allocate_include_entry (void)
+{
+ 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 (CORE_ADDR start, CORE_ADDR 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. */
+
+ int linesz =
+ coff_data (this_symtab_psymtab->objfile->obfd)->local_linesz;
+ 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
+ {
+ xfree (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);
+ xfree (current_subfile->name);
+ }
+ current_subfile->name = xstrdup (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
+ {
+ xfree (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 (void)
+{
+ /* 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 (struct subfile *subfile, unsigned beginoffset, unsigned endoffset, /* offsets to line table */
+ CORE_ADDR startaddr, /* offsets to line table */
+ CORE_ADDR endaddr, unsigned *firstLine)
+{
+ unsigned int curoffset;
+ CORE_ADDR addr;
+ void *ext_lnno;
+ struct internal_lineno int_lnno;
+ unsigned int limit_offset;
+ bfd *abfd;
+ int linesz;
+
+ 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)
+ {
+ complaint (&symfile_complaints,
+ "Bad line table offset in C_EINCL directive");
+ return;
+ }
+ limit_offset = endoffset;
+ }
+ else
+ limit_offset -= 1;
+
+ abfd = this_symtab_psymtab->objfile->obfd;
+ linesz = coff_data (abfd)->local_linesz;
+ ext_lnno = alloca (linesz);
+
+ while (curoffset <= limit_offset)
+ {
+ bfd_seek (abfd, curoffset, SEEK_SET);
+ bfd_bread (ext_lnno, linesz, 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 (this_symtab_psymtab->objfile));
+
+ 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), (asection *)NULL, (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 (struct objfile *objfile)
+{
+ struct internal_syment symbol;
+ 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)
+ {
+ complaint (&symfile_complaints, "Unexpected symbol continuation");
+
+ /* 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
+ {
+ complaint (&symfile_complaints, "Unexpected symbol continuation");
+
+ /* 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 (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;
+ char *debugfmt = bfd_xcoff_is_xcoff64 (abfd) ? "XCOFF64" : "XCOFF";
+
+ 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);
+ record_debugformat (debugfmt);
+ 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->objfile_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 += 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 (objfile));
+ end_stabs ();
+ }
+
+ start_stabs ();
+ start_symtab ("_globals_", (char *) NULL, (CORE_ADDR) 0);
+ record_debugformat (debugfmt);
+ cur_src_end_addr = first_object_file_end;
+ /* done with all files, everything from here on is globals */
+ }
+
+ 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 (objfile));
+ end_stabs ();
+ start_stabs ();
+ /* Give all csects for this source file the same
+ name. */
+ start_symtab (filestring, NULL, (CORE_ADDR) 0);
+ record_debugformat (debugfmt);
+ }
+
+ /* 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 (objfile));
+ file_end_addr = file_start_addr + CSECT_LEN (&main_aux);
+
+ if (cs->c_name && (cs->c_name[0] == '.'
+ || 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;
+ }
+ }
+
+ /* If explicitly specified as a function, treat is as one. This check
+ evaluates to true for @FIX* bigtoc CSECT symbols, so it must occur
+ after the above CSECT check. */
+ 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;
+ }
+
+ 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 (objfile));
+ 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);
+ record_debugformat (debugfmt);
+ 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 (DEPRECATED_STREQ (cs->c_name, ".bf"))
+ {
+ CORE_ADDR off = ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile));
+ 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 (objfile);
+ }
+ else if (DEPRECATED_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 */
+ ef_complaint (cs->c_symnum);
+ within_function = 0;
+ break;
+ }
+ new = pop_context ();
+ /* Stack must be empty now. */
+ if (context_stack_depth > 0 || new == NULL)
+ {
+ 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))),
+ 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:
+ {
+ complaint (&symfile_complaints, "Unrecognized storage class %d.",
+ 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 (DEPRECATED_STREQ (cs->c_name, ".bb"))
+ {
+ depth++;
+ new = push_context (depth,
+ (cs->c_value
+ + ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile))));
+ }
+ else if (DEPRECATED_STREQ (cs->c_name, ".eb"))
+ {
+ if (context_stack_depth <= 0)
+ { /* We attempted to pop an empty context stack */
+ eb_complaint (cs->c_symnum);
+ break;
+ }
+ new = pop_context ();
+ if (depth-- != new->depth)
+ {
+ 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))),
+ 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 (objfile));
+ /* 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->objfile_obstack, sizeof (struct symbol)); \
+ *(SYMBOL2) = *(SYMBOL1);
+
+
+#define SYMNAME_ALLOC(NAME, ALLOCED) \
+ (ALLOCED) ? (NAME) : obsavestring ((NAME), strlen (NAME), &objfile->objfile_obstack);
+
+
+static struct type *func_symbol_type;
+static struct type *var_symbol_type;
+
+/* process one xcoff symbol. */
+
+static struct symbol *
+process_xcoff_symbol (struct coff_symbol *cs, struct objfile *objfile)
+{
+ struct symbol onesymbol;
+ 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_ADDRESS (sym) = cs->c_value + off;
+ SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+ 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. */
+
+ DEPRECATED_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:
+ complaint (&symfile_complaints, "Unexpected storage class: %d",
+ 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_ADDRESS (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.
+ Result is in static storage and is only good for temporary use. */
+
+static char *
+coff_getfilename (union internal_auxent *aux_entry, struct objfile *objfile)
+{
+ static char buffer[BUFSIZ];
+
+ 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';
+ }
+ return (buffer);
+}
+
+/* Set *SYMBOL to symbol number symno in symtbl. */
+static void
+read_symbol (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)
+ {
+ complaint (&symfile_complaints, "Invalid symbol offset");
+ 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 CORE_ADDR
+read_symbol_nvalue (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 (int symno)
+{
+ struct objfile *objfile = this_symtab_psymtab->objfile;
+ int xcoff64 = bfd_xcoff_is_xcoff64 (objfile->obfd);
+
+ struct coff_symfile_info *info =
+ (struct coff_symfile_info *)objfile->sym_private;
+ int nsyms = info->symtbl_num_syms;
+ char *stbl = info->symtbl;
+ char *strtbl = info->strtbl;
+
+ struct internal_syment symbol[1];
+ union internal_auxent main_aux[1];
+
+ if (symno < 0)
+ {
+ 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)
+ {
+ char *name = xcoff64 ? strtbl + symbol->n_offset : symbol->n_name;
+ if (DEPRECATED_STREQ (name, ".bf"))
+ goto gotit;
+ }
+ symno += symbol->n_numaux + 1;
+ }
+
+ bf_notfound_complaint ();
+ return 0;
+
+gotit:
+ /* take aux entry and return its lineno */
+ symno++;
+ bfd_coff_swap_aux_in (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 (struct bfd *abfd, struct bfd_section *asect, void *vpinfo)
+{
+ struct coff_symfile_info *info;
+ int size, count;
+ file_ptr offset, maxoff;
+
+ count = asect->lineno_count;
+
+ if (!DEPRECATED_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 (struct partial_symtab *);
+
+static void
+xcoff_psymtab_to_symtab_1 (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);
+
+ do_cleanups (old_chain);
+ }
+
+ pst->readin = 1;
+}
+
+static void xcoff_psymtab_to_symtab (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 (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 (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 (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 (struct objfile *objfile)
+{
+ if (objfile->sym_private != NULL)
+ {
+ xmfree (objfile->md, objfile->sym_private);
+ }
+
+ /* Start with a fresh include table for the next objfile. */
+ if (inclTable)
+ {
+ xfree (inclTable);
+ inclTable = NULL;
+ }
+ inclIndx = inclLength = inclDepth = 0;
+}
+
+
+static void
+init_stringtab (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_bread ((char *) lengthbuf, 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 objfile_obstack. We will need this table
+ as long as we have its symbol table around. */
+
+ strtbl = (char *) obstack_alloc (&objfile->objfile_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_bread (strtbl + sizeof lengthbuf, 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
+ (struct objfile *, 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 (struct objfile *objfile, char *filename, int first_symnum,
+ struct partial_symbol **global_syms,
+ struct partial_symbol **static_syms)
+{
+ struct partial_symtab *result =
+ start_psymtab_common (objfile, objfile->section_offsets,
+ filename,
+ /* We fill in textlow later. */
+ 0,
+ global_syms, static_syms);
+
+ result->read_symtab_private = (char *)
+ obstack_alloc (&objfile->objfile_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
+ (struct partial_symtab *, char **, int, int,
+ struct partial_symtab **, int, 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 (struct partial_symtab *pst, char **include_list,
+ int num_includes, int capping_symbol_number,
+ struct partial_symtab **dependency_list,
+ int number_dependencies, int textlow_not_set)
+{
+ 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->objfile_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->objfile_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->objfile_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. */
+
+ discard_psymtab (pst);
+
+ /* Indicate that psymtab was thrown away. */
+ pst = (struct partial_symtab *) NULL;
+ }
+ return pst;
+}
+
+static void swap_sym (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 (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->objfile_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
+function_outside_compilation_unit_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints,
+ "function `%s' appears to be defined outside of all compilation units",
+ arg1);
+}
+
+static void
+scan_xcoff_symtab (struct objfile *objfile)
+{
+ CORE_ADDR toc_offset = 0; /* toc offset value in data section. */
+ char *filestring = NULL;
+
+ char *namestring;
+ int past_first_source_file = 0;
+ bfd *abfd;
+ asection *bfd_sect;
+ 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[5];
+ 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 */
+ int textlow_not_set = 1;
+
+ 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;
+
+ QUIT;
+
+ bfd_coff_swap_sym_in (abfd, sraw_symbol, &symbol);
+ sclass = symbol.n_sclass;
+
+ 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[0], &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[0];
+
+ /* 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, textlow_not_set);
+ includes_used = 0;
+ dependencies_used = 0;
+ /* Give all psymtabs for this source file the same
+ name. */
+ pst = xcoff_start_psymtab
+ (objfile,
+ filestring,
+ symnum_before,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ }
+ }
+ /* Activate the misc_func_recorded mechanism for
+ compiler- and linker-generated CSECTs like ".strcmp"
+ and "@FIX1". */
+ if (namestring && (namestring[0] == '.'
+ || 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:
+ case XMC_TD:
+ /* 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),
+ NULL, objfile);
+ break;
+
+ case XMC_TC0:
+ if (toc_offset)
+ warning ("More than one XMC_TC0 symbol found.");
+ toc_offset = symbol.n_value;
+
+ /* Make TOC offset relative to start address of section. */
+ bfd_sect = secnum_to_bfd_section (symbol.n_scnum, objfile);
+ if (bfd_sect)
+ toc_offset -= bfd_section_vma (objfile->obfd, bfd_sect);
+ 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[0].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),
+ NULL, 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),
+ NULL, objfile);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+ case C_FILE:
+ {
+ unsigned int symnum_before;
+
+ symnum_before = ssymnum;
+ swap_sym (&symbol, &main_aux[0], &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, textlow_not_set);
+ 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[0], objfile);
+ }
+ else
+ filestring = namestring;
+
+ pst = xcoff_start_psymtab (objfile,
+ filestring,
+ symnum_before,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ last_csect_name = NULL;
+ }
+ break;
+
+ default:
+ {
+ complaint (&symfile_complaints,
+ "Storage class %d not recognized during scan", 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 = symbol.n_numaux + 1;
+ ssymnum += naux1;
+ sraw_symbol += bfd_coff_symesz (abfd) * naux1;
+ }
+ break;
+
+ case C_BINCL:
+ {
+ /* Mark down an include file in the current psymtab */
+ enum language tmp_language;
+ swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol,
+ &ssymnum, objfile);
+
+ 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 && DEPRECATED_STREQ (namestring, pst->filename))
+ continue;
+ {
+ int i;
+ for (i = 0; i < includes_used; i++)
+ if (DEPRECATED_STREQ (namestring, psymtab_include_list[i]))
+ {
+ i = -1;
+ break;
+ }
+ if (i == -1)
+ continue;
+ }
+ 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 (psymtab_include_list, orig,
+ includes_used * sizeof (char *));
+ }
+ continue;
+ }
+ 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:
+ {
+ char *p;
+ swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol,
+ &ssymnum, objfile);
+
+ 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':
+ symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+#ifdef STATIC_TRANSFORM_NAME
+ namestring = STATIC_TRANSFORM_NAME (namestring);
+#endif
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_STATIC,
+ &objfile->static_psymbols,
+ 0, symbol.n_value,
+ psymtab_language, objfile);
+ continue;
+
+ case 'G':
+ symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));
+ /* 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_DOMAIN, LOC_STATIC,
+ &objfile->global_psymbols,
+ 0, symbol.n_value,
+ psymtab_language, objfile);
+ continue;
+
+ case 'T':
+ /* When a 'T' entry is defining an anonymous enum, it
+ may have a name which is the empty string, or a
+ single space. Since they're not really defining a
+ symbol, those shouldn't go in the partial symbol
+ table. We do pick up the elements of such enums at
+ 'check_enum:', below. */
+ if (p >= namestring + 2
+ || (p == namestring + 1
+ && namestring[0] != ' '))
+ {
+ add_psymbol_to_list (namestring, p - namestring,
+ STRUCT_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ symbol.n_value, 0,
+ psymtab_language, objfile);
+ if (p[2] == 't')
+ {
+ /* Also a typedef with the same name. */
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ symbol.n_value, 0,
+ psymtab_language, objfile);
+ p += 1;
+ }
+ }
+ goto check_enum;
+
+ case 't':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ symbol.n_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
+ <name> ":" ("t" | "T") [<number> "="] "e"
+ {<constant> ":" <value> ","} ";". */
+
+ /* 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_DOMAIN, 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_DOMAIN, LOC_CONST,
+ &objfile->static_psymbols, symbol.n_value,
+ 0, psymtab_language, objfile);
+ continue;
+
+ case 'f':
+ if (! pst)
+ {
+ int name_len = p - namestring;
+ char *name = xmalloc (name_len + 1);
+ memcpy (name, namestring, name_len);
+ name[name_len] = '\0';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->static_psymbols,
+ 0, symbol.n_value,
+ 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':
+ if (! pst)
+ {
+ int name_len = p - namestring;
+ char *name = xmalloc (name_len + 1);
+ memcpy (name, namestring, name_len);
+ name[name_len] = '\0';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, LOC_BLOCK,
+ &objfile->global_psymbols,
+ 0, symbol.n_value,
+ 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 '-':
+ case '#': /* for symbol identification (used in live ranges) */
+ 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. */
+
+ complaint (&symfile_complaints,
+ "unknown symbol descriptor `%c'", p[1]);
+
+ /* Ignore it; perhaps it is an extension that we don't
+ know about. */
+ continue;
+ }
+ }
+ }
+ }
+
+ if (pst)
+ {
+ xcoff_end_psymtab (pst, psymtab_include_list, includes_used,
+ ssymnum, dependency_list,
+ dependencies_used, textlow_not_set);
+ }
+
+ /* Record the toc offset value of this symbol table into objfile structure.
+ If no XMC_TC0 is found, toc_offset should be zero. Another place to obtain
+ this information would be file auxiliary header. */
+
+ ((struct coff_symfile_info *) objfile->sym_private)->toc_offset = toc_offset;
+}
+
+/* Return the toc offset value for a given objfile. */
+
+CORE_ADDR
+get_toc_offset (struct objfile *objfile)
+{
+ if (objfile)
+ return ((struct coff_symfile_info *) objfile->sym_private)->toc_offset;
+ return 0;
+}
+
+/* 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 (struct objfile *objfile, int mainline)
+{
+ 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;
+
+ 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. */
+ {
+ struct bfd_section *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->objfile_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->objfile_obstack, size);
+ ((struct coff_symfile_info *) objfile->sym_private)->symtbl_num_syms =
+ num_symbols;
+
+ val = bfd_bread (((struct coff_symfile_info *) objfile->sym_private)->symtbl,
+ size, 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);
+
+ free_pending_blocks ();
+ back_to = make_cleanup (really_free_pendings, 0);
+
+ init_minimal_symbol_collection ();
+ make_cleanup_discard_minimal_symbols ();
+
+ /* Now that the symbol table data of the executable file are all in core,
+ process them and define symbols accordingly. */
+
+ scan_xcoff_symtab (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 void
+xcoff_symfile_offsets (struct objfile *objfile, struct section_addr_info *addrs)
+{
+ asection *sect = NULL;
+ int i;
+
+ objfile->num_sections = bfd_count_sections (objfile->obfd);
+ objfile->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ /* Initialize the section indexes for future use. */
+ sect = bfd_get_section_by_name (objfile->obfd, ".text");
+ if (sect)
+ objfile->sect_index_text = sect->index;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".data");
+ if (sect)
+ objfile->sect_index_data = sect->index;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".bss");
+ if (sect)
+ objfile->sect_index_bss = sect->index;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".rodata");
+ if (sect)
+ objfile->sect_index_rodata = sect->index;
+
+ for (i = 0; i < objfile->num_sections; ++i)
+ {
+ /* 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. */
+ (objfile->section_offsets)->offsets[i] = 0;
+ }
+}
+
+/* Register our ability to parse symbols for xcoff BFD files. */
+
+static struct sym_fns xcoff_sym_fns =
+{
+
+ /* 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). */
+
+ bfd_target_xcoff_flavour,
+
+ 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 (void)
+{
+ add_symtab_fns (&xcoff_sym_fns);
+
+ func_symbol_type = init_type (TYPE_CODE_FUNC, 1, 0,
+ "<function, no debug info>", 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,
+ "<variable, no debug info>", NULL);
+}
diff --git a/contrib/gdb/gdb/xcoffsolib.c b/contrib/gdb/gdb/xcoffsolib.c
new file mode 100644
index 0000000..99d2cc8
--- /dev/null
+++ b/contrib/gdb/gdb/xcoffsolib.c
@@ -0,0 +1,196 @@
+/* Shared library support for RS/6000 (xcoff) object files, for GDB.
+ Copyright 1991, 1992, 1995, 1996, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+ 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. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "xcoffsolib.h"
+#include "inferior.h"
+#include "gdbcmd.h"
+#include "symfile.h"
+#include "frame.h"
+#include "gdb_regex.h"
+
+
+/* If ADDR lies in a shared library, return its name.
+ Note that returned name points to static data whose content is overwritten
+ by each call. */
+
+char *
+xcoff_solib_address (CORE_ADDR addr)
+{
+ static char *buffer = NULL;
+ struct vmap *vp = vmap;
+
+ /* The first vmap entry is for the exec file. */
+
+ if (vp == NULL)
+ return NULL;
+ for (vp = vp->nxt; vp; vp = vp->nxt)
+ if (vp->tstart <= addr && addr < vp->tend)
+ {
+ xfree (buffer);
+ xasprintf (&buffer, "%s%s%s%s",
+ vp->name,
+ *vp->member ? "(" : "",
+ vp->member,
+ *vp->member ? ")" : "");
+ return buffer;
+ }
+ return NULL;
+}
+
+static void solib_info (char *, int);
+static void sharedlibrary_command (char *pattern, int from_tty);
+
+static void
+solib_info (char *args, int from_tty)
+{
+ struct vmap *vp = vmap;
+
+ /* Check for new shared libraries loaded with load (). */
+ if (! ptid_equal (inferior_ptid, null_ptid))
+ xcoff_relocate_symtab (PIDGET (inferior_ptid));
+
+ 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%s-0x%s 0x%s-0x%s %s %s%s%s%s\n",
+ paddr (vp->tstart),paddr (vp->tend),
+ paddr (vp->dstart), paddr (vp->dend),
+ vp->loaded ? "Yes" : "No ",
+ vp->name,
+ *vp->member ? "(" : "",
+ vp->member,
+ *vp->member ? ")" : "");
+ }
+}
+
+static void
+sharedlibrary_command (char *pattern, int from_tty)
+{
+ dont_repeat ();
+
+ /* Check for new shared libraries loaded with load (). */
+ if (! ptid_equal (inferior_ptid, null_ptid))
+ xcoff_relocate_symtab (PIDGET (inferior_ptid));
+
+ if (pattern)
+ {
+ char *re_err = re_comp (pattern);
+
+ if (re_err)
+ error ("Invalid regexp: %s", re_err);
+ }
+
+ /* Walk the list of currently loaded shared libraries, and read
+ symbols for any that match the pattern --- or any whose symbols
+ aren't already loaded, if no pattern was given. */
+ {
+ int any_matches = 0;
+ int loaded_any_symbols = 0;
+ struct vmap *vp = vmap;
+
+ if (!vp)
+ return;
+
+ /* skip over the first vmap, it is the main program, always loaded. */
+ for (vp = vp->nxt; vp; vp = vp->nxt)
+ if (! pattern
+ || re_exec (vp->name)
+ || (*vp->member && re_exec (vp->member)))
+ {
+ any_matches = 1;
+
+ if (vp->loaded)
+ {
+ if (from_tty)
+ printf_unfiltered ("Symbols already loaded for %s\n",
+ vp->name);
+ }
+ else
+ {
+ if (vmap_add_symbols (vp))
+ loaded_any_symbols = 1;
+ }
+ }
+
+ if (from_tty && pattern && ! any_matches)
+ printf_unfiltered
+ ("No loaded shared libraries match the pattern `%s'.\n", pattern);
+
+ if (loaded_any_symbols)
+ {
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ reinit_frame_cache ();
+ }
+ }
+}
+
+/* LOCAL FUNCTION
+
+ no_shared_libraries -- handle command to explicitly discard symbols
+ from shared libraries.
+
+ DESCRIPTION
+
+ Implements the command "nosharedlibrary", which discards symbols
+ that have been auto-loaded from shared libraries. Symbols from
+ shared libraries that were added by explicit request of the user
+ are not discarded. Also called from remote.c. */
+
+void
+no_shared_libraries (char *ignored, int from_tty)
+{
+ /* FIXME */
+}
+
+void
+_initialize_xcoffsolib (void)
+{
+ 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");
+
+ add_show_from_set
+ (add_set_cmd ("auto-solib-add", class_support, var_boolean,
+ (char *) &auto_solib_add,
+ "Set autoloading of shared library symbols.\n\
+If \"on\", symbols from all shared object libraries will be loaded\n\
+automatically when the inferior begins execution, when the dynamic linker\n\
+informs gdb that a new library has been loaded, or when attaching to the\n\
+inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.",
+ &setlist),
+ &showlist);
+}
diff --git a/contrib/gdb/gdb/xcoffsolib.h b/contrib/gdb/gdb/xcoffsolib.h
new file mode 100644
index 0000000..d8370fa
--- /dev/null
+++ b/contrib/gdb/gdb/xcoffsolib.h
@@ -0,0 +1,66 @@
+/* Data structures for RS/6000 shared libraries, for GDB.
+ Copyright 1991, 1992, 1993, 1994, 1996, 1997, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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. */
+
+#ifndef XCOFFSOLIB_H
+#define XCOFFSOLIB_H
+
+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 tvma; /* virtual addr of text section in object file */
+ CORE_ADDR toffs; /* offset of text section in object file */
+ CORE_ADDR dstart; /* virtual address of data start */
+ CORE_ADDR dend; /* virtual address of data end */
+ CORE_ADDR dvma; /* virtual addr of data section in object file */
+
+ /* 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;
+
+/* Add symbols for a vmap. */
+extern int vmap_add_symbols (struct vmap *vp);
+
+#endif
diff --git a/contrib/gdb/gdb/xmodem.c b/contrib/gdb/gdb/xmodem.c
new file mode 100644
index 0000000..7b8d77d
--- /dev/null
+++ b/contrib/gdb/gdb/xmodem.c
@@ -0,0 +1,275 @@
+/* XMODEM support for GDB, the GNU debugger.
+ Copyright 1995, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (struct serial *desc, int timeout)
+{
+ int c;
+
+ c = serial_readchar (desc, timeout);
+
+ if (remote_debug > 0)
+ fputc_unfiltered (c, gdb_stdlog);
+
+ 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 (void)
+{
+ 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 (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 (struct serial *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 (struct serial *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
+ internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* 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 (struct serial *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 0000000..83aa24f
--- /dev/null
+++ b/contrib/gdb/gdb/xmodem.h
@@ -0,0 +1,32 @@
+/* XMODEM support for GDB, the GNU debugger.
+ Copyright 1995, 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 serial;
+
+int xmodem_init_xfer (struct serial *desc);
+void send_xmodem_packet (struct serial *desc, unsigned char *packet, int len,
+ int hashmark);
+void xmodem_finish_xfer (struct serial *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/gettext.m4 b/contrib/gdb/gettext.m4
new file mode 100644
index 0000000..6735696
--- /dev/null
+++ b/contrib/gdb/gettext.m4
@@ -0,0 +1,344 @@
+# This file is derived from `gettext.m4'. The difference is that the
+# included macros assume Cygnus-style source and build trees.
+
+# Macro to add for using GNU gettext.
+# Ulrich Drepper <drepper@cygnus.com>, 1995.
+#
+# This file file be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 3
+
+AC_DEFUN([CY_WITH_NLS],
+ [AC_MSG_CHECKING([whether NLS is requested])
+ dnl Default is enabled NLS
+ AC_ARG_ENABLE(nls,
+ [ --disable-nls do not use Native Language Support],
+ USE_NLS=$enableval, USE_NLS=yes)
+ AC_MSG_RESULT($USE_NLS)
+ AC_SUBST(USE_NLS)
+
+ USE_INCLUDED_LIBINTL=no
+
+ dnl If we use NLS figure out what method
+ if test "$USE_NLS" = "yes"; then
+ AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if NLS is requested])
+ AC_MSG_CHECKING([whether included gettext is requested])
+ AC_ARG_WITH(included-gettext,
+ [ --with-included-gettext use the GNU gettext library included here],
+ nls_cv_force_use_gnu_gettext=$withval,
+ nls_cv_force_use_gnu_gettext=no)
+ AC_MSG_RESULT($nls_cv_force_use_gnu_gettext)
+
+ nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
+ if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
+ dnl User does not insist on using GNU NLS library. Figure out what
+ dnl to use. If gettext or catgets are available (in this order) we
+ dnl use this. Else we have to fall back to GNU NLS library.
+ dnl catgets is only used if permitted by option --with-catgets.
+ nls_cv_header_intl=
+ nls_cv_header_libgt=
+ CATOBJEXT=NONE
+
+ AC_CHECK_HEADER(libintl.h,
+ [AC_CACHE_CHECK([for gettext in libc], gt_cv_func_gettext_libc,
+ [AC_TRY_LINK([#include <libintl.h>], [return (int) gettext ("")],
+ gt_cv_func_gettext_libc=yes, gt_cv_func_gettext_libc=no)])
+
+ if test "$gt_cv_func_gettext_libc" != "yes"; then
+ AC_CHECK_LIB(intl, bindtextdomain,
+ [AC_CACHE_CHECK([for gettext in libintl],
+ gt_cv_func_gettext_libintl,
+ [AC_TRY_LINK([], [return (int) gettext ("")],
+ gt_cv_func_gettext_libintl=yes,
+ gt_cv_func_gettext_libintl=no)])])
+ fi
+
+ if test "$gt_cv_func_gettext_libc" = "yes" \
+ || test "$gt_cv_func_gettext_libintl" = "yes"; then
+ AC_DEFINE(HAVE_GETTEXT, 1,
+ [Define as 1 if you have gettext and don't want to use GNU gettext.])
+ AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl
+ if test "$MSGFMT" != "no"; then
+ AC_CHECK_FUNCS(dcgettext)
+ AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+ AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+ AC_TRY_LINK(, [extern int _nl_msg_cat_cntr;
+ return _nl_msg_cat_cntr],
+ [CATOBJEXT=.gmo
+ DATADIRNAME=share],
+ [CATOBJEXT=.mo
+ DATADIRNAME=lib])
+ INSTOBJEXT=.mo
+ fi
+ fi
+ ])
+
+ dnl In the standard gettext, we would now check for catgets.
+ dnl However, we never want to use catgets for our releases.
+
+ if test "$CATOBJEXT" = "NONE"; then
+ dnl Neither gettext nor catgets in included in the C library.
+ dnl Fall back on GNU gettext library.
+ nls_cv_use_gnu_gettext=yes
+ fi
+ fi
+
+ if test "$nls_cv_use_gnu_gettext" = "yes"; then
+ dnl Mark actions used to generate GNU NLS library.
+ INTLOBJS="\$(GETTOBJS)"
+ AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt)
+ AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+ AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+ AC_SUBST(MSGFMT)
+ USE_INCLUDED_LIBINTL=yes
+ CATOBJEXT=.gmo
+ INSTOBJEXT=.mo
+ DATADIRNAME=share
+ INTLDEPS='$(top_builddir)/../intl/libintl.a'
+ INTLLIBS=$INTLDEPS
+ LIBS=`echo $LIBS | sed -e 's/-lintl//'`
+ nls_cv_header_intl=libintl.h
+ nls_cv_header_libgt=libgettext.h
+ fi
+
+ dnl Test whether we really found GNU xgettext.
+ if test "$XGETTEXT" != ":"; then
+ dnl If it is no GNU xgettext we define it as : so that the
+ dnl Makefiles still can work.
+ if $XGETTEXT --omit-header /dev/null 2> /dev/null; then
+ : ;
+ else
+ AC_MSG_RESULT(
+ [found xgettext programs is not GNU xgettext; ignore it])
+ XGETTEXT=":"
+ fi
+ fi
+
+ # We need to process the po/ directory.
+ POSUB=po
+ else
+ DATADIRNAME=share
+ nls_cv_header_intl=libintl.h
+ nls_cv_header_libgt=libgettext.h
+ fi
+
+ # If this is used in GNU gettext we have to set USE_NLS to `yes'
+ # because some of the sources are only built for this goal.
+ if test "$PACKAGE" = gettext; then
+ USE_NLS=yes
+ USE_INCLUDED_LIBINTL=yes
+ fi
+
+ dnl These rules are solely for the distribution goal. While doing this
+ dnl we only have to keep exactly one list of the available catalogs
+ dnl in configure.in.
+ for lang in $ALL_LINGUAS; do
+ GMOFILES="$GMOFILES $lang.gmo"
+ POFILES="$POFILES $lang.po"
+ done
+
+ dnl Make all variables we use known to autoconf.
+ AC_SUBST(USE_INCLUDED_LIBINTL)
+ AC_SUBST(CATALOGS)
+ AC_SUBST(CATOBJEXT)
+ AC_SUBST(DATADIRNAME)
+ AC_SUBST(GMOFILES)
+ AC_SUBST(INSTOBJEXT)
+ AC_SUBST(INTLDEPS)
+ AC_SUBST(INTLLIBS)
+ AC_SUBST(INTLOBJS)
+ AC_SUBST(POFILES)
+ AC_SUBST(POSUB)
+ ])
+
+AC_DEFUN([CY_GNU_GETTEXT],
+ [AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+ AC_REQUIRE([AC_PROG_CC])dnl
+ AC_REQUIRE([AC_PROG_RANLIB])dnl
+ AC_REQUIRE([AC_ISC_POSIX])dnl
+ AC_REQUIRE([AC_HEADER_STDC])dnl
+ AC_REQUIRE([AC_C_CONST])dnl
+ AC_REQUIRE([AC_C_INLINE])dnl
+ AC_REQUIRE([AC_TYPE_OFF_T])dnl
+ AC_REQUIRE([AC_TYPE_SIZE_T])dnl
+ AC_REQUIRE([AC_FUNC_ALLOCA])dnl
+ AC_REQUIRE([AC_FUNC_MMAP])dnl
+
+ AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h string.h \
+unistd.h values.h sys/param.h])
+ AC_CHECK_FUNCS([getcwd munmap putenv setenv setlocale strchr strcasecmp \
+__argz_count __argz_stringify __argz_next])
+
+ if test "${ac_cv_func_stpcpy+set}" != "set"; then
+ AC_CHECK_FUNCS(stpcpy)
+ fi
+ if test "${ac_cv_func_stpcpy}" = "yes"; then
+ AC_DEFINE(HAVE_STPCPY, 1, [Define if you have the stpcpy function])
+ fi
+
+ AM_LC_MESSAGES
+ CY_WITH_NLS
+
+ if test "x$CATOBJEXT" != "x"; then
+ if test "x$ALL_LINGUAS" = "x"; then
+ LINGUAS=
+ else
+ AC_MSG_CHECKING(for catalogs to be installed)
+ NEW_LINGUAS=
+ for lang in ${LINGUAS=$ALL_LINGUAS}; do
+ case "$ALL_LINGUAS" in
+ *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;;
+ esac
+ done
+ LINGUAS=$NEW_LINGUAS
+ AC_MSG_RESULT($LINGUAS)
+ fi
+
+ dnl Construct list of names of catalog files to be constructed.
+ if test -n "$LINGUAS"; then
+ for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done
+ fi
+ fi
+
+ dnl The reference to <locale.h> in the installed <libintl.h> file
+ dnl must be resolved because we cannot expect the users of this
+ dnl to define HAVE_LOCALE_H.
+ if test $ac_cv_header_locale_h = yes; then
+ INCLUDE_LOCALE_H="#include <locale.h>"
+ else
+ INCLUDE_LOCALE_H="\
+/* The system does not provide the header <locale.h>. Take care yourself. */"
+ fi
+ AC_SUBST(INCLUDE_LOCALE_H)
+
+ dnl Determine which catalog format we have (if any is needed)
+ dnl For now we know about two different formats:
+ dnl Linux libc-5 and the normal X/Open format
+ if test -f $srcdir/po2tbl.sed.in; then
+ if test "$CATOBJEXT" = ".cat"; then
+ AC_CHECK_HEADER(linux/version.h, msgformat=linux, msgformat=xopen)
+
+ dnl Transform the SED scripts while copying because some dumb SEDs
+ dnl cannot handle comments.
+ sed -e '/^#/d' $srcdir/$msgformat-msg.sed > po2msg.sed
+ fi
+ dnl po2tbl.sed is always needed.
+ sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \
+ $srcdir/po2tbl.sed.in > po2tbl.sed
+ fi
+
+ dnl In the intl/Makefile.in we have a special dependency which makes
+ dnl only sense for gettext. We comment this out for non-gettext
+ dnl packages.
+ if test "$PACKAGE" = "gettext"; then
+ GT_NO="#NO#"
+ GT_YES=
+ else
+ GT_NO=
+ GT_YES="#YES#"
+ fi
+ AC_SUBST(GT_NO)
+ AC_SUBST(GT_YES)
+
+ MKINSTALLDIRS="\$(srcdir)/../../mkinstalldirs"
+ AC_SUBST(MKINSTALLDIRS)
+
+ dnl *** For now the libtool support in intl/Makefile is not for real.
+ l=
+ AC_SUBST(l)
+
+ dnl Generate list of files to be processed by xgettext which will
+ dnl be included in po/Makefile. But only do this if the po directory
+ dnl exists in srcdir and contains POTFILES.in.
+ if test -f $srcdir/po/POTFILES.in; then
+ test -d po || mkdir po
+ if test "x$srcdir" != "x."; then
+ if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then
+ posrcprefix="$srcdir/"
+ else
+ posrcprefix="../$srcdir/"
+ fi
+ else
+ posrcprefix="../"
+ fi
+ rm -f po/POTFILES
+ sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \
+ < $srcdir/po/POTFILES.in > po/POTFILES
+ fi
+ ])
+
+# Search path for a program which passes the given test.
+# Ulrich Drepper <drepper@cygnus.com>, 1996.
+#
+# This file file be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 1
+
+dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+AC_DEFUN([AM_PATH_PROG_WITH_TEST],
+[# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+ /*)
+ ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in ifelse([$5], , $PATH, [$5]); do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if [$3]; then
+ ac_cv_path_$1="$ac_dir/$ac_word"
+ break
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+ ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test -n "[$]$1"; then
+ AC_MSG_RESULT([$]$1)
+else
+ AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
+
+# Check whether LC_MESSAGES is available in <locale.h>.
+# Ulrich Drepper <drepper@cygnus.com>, 1995.
+#
+# This file file be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 1
+
+AC_DEFUN([AM_LC_MESSAGES],
+ [if test $ac_cv_header_locale_h = yes; then
+ AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES,
+ [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES],
+ am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)])
+ if test $am_cv_val_LC_MESSAGES = yes; then
+ AC_DEFINE(HAVE_LC_MESSAGES, 1,
+ [Define if your locale.h file contains LC_MESSAGES.])
+ fi
+ fi])
diff --git a/contrib/gdb/include/COPYING b/contrib/gdb/include/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/contrib/gdb/include/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) year 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.
+
+ <signature of Ty Coon>, 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/MAINTAINERS b/contrib/gdb/include/MAINTAINERS
new file mode 100644
index 0000000..d59a3bd
--- /dev/null
+++ b/contrib/gdb/include/MAINTAINERS
@@ -0,0 +1 @@
+See ../binutils/MAINTAINERS
diff --git a/contrib/gdb/include/alloca-conf.h b/contrib/gdb/include/alloca-conf.h
new file mode 100644
index 0000000..9c3eea3
--- /dev/null
+++ b/contrib/gdb/include/alloca-conf.h
@@ -0,0 +1,24 @@
+#include "config.h"
+
+#if defined(__GNUC__) && !defined(C_ALLOCA)
+# ifndef alloca
+# define alloca __builtin_alloca
+# endif
+#else /* ! defined (__GNUC__) */
+# ifdef _AIX
+ #pragma alloca
+# else
+# if defined(HAVE_ALLOCA_H) && !defined(C_ALLOCA)
+# include <alloca.h>
+# else /* ! defined (HAVE_ALLOCA_H) */
+# ifdef __STDC__
+extern PTR alloca (size_t);
+# else /* ! defined (__STDC__) */
+extern PTR alloca ();
+# endif /* ! defined (__STDC__) */
+# endif /* ! defined (HAVE_ALLOCA_H) */
+# ifdef _WIN32
+# include <malloc.h>
+# endif
+# endif /* ! defined (_AIX) */
+#endif /* ! defined (__GNUC__) */
diff --git a/contrib/gdb/include/ansidecl.h b/contrib/gdb/include/ansidecl.h
new file mode 100644
index 0000000..d2c8776
--- /dev/null
+++ b/contrib/gdb/include/ansidecl.h
@@ -0,0 +1,315 @@
+/* ANSI and traditional C compatability macros
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+ 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
+ ----- ---- - ---------- ----------- - ----------
+ ANSI_PROTOTYPES 1 not defined
+ PTR `void *' `char *'
+ PTRCONST `void *const' `char *'
+ LONG_DOUBLE `long double' `double'
+ const not defined `'
+ volatile not defined `'
+ signed not defined `'
+ VA_START(ap, var) va_start(ap, var) va_start(ap)
+
+ Note that it is safe to write "void foo();" indicating a function
+ with no return value, in all K+R compilers we have been able to test.
+
+ For declaring functions with prototypes, we also provide these:
+
+ PARAMS ((prototype))
+ -- for functions which take a fixed number of arguments. Use this
+ when declaring the function. When defining the function, write a
+ K+R style argument list. For example:
+
+ char *strcpy PARAMS ((char *dest, char *source));
+ ...
+ char *
+ strcpy (dest, source)
+ char *dest;
+ char *source;
+ { ... }
+
+
+ VPARAMS ((prototype, ...))
+ -- for functions which take a variable number of arguments. Use
+ PARAMS to declare the function, VPARAMS to define it. For example:
+
+ int printf PARAMS ((const char *format, ...));
+ ...
+ int
+ printf VPARAMS ((const char *format, ...))
+ {
+ ...
+ }
+
+ For writing functions which take variable numbers of arguments, we
+ also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These
+ hide the differences between K+R <varargs.h> and C89 <stdarg.h> more
+ thoroughly than the simple VA_START() macro mentioned above.
+
+ VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end.
+ Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls
+ corresponding to the list of fixed arguments. Then use va_arg
+ normally to get the variable arguments, or pass your va_list object
+ around. You do not declare the va_list yourself; VA_OPEN does it
+ for you.
+
+ Here is a complete example:
+
+ int
+ printf VPARAMS ((const char *format, ...))
+ {
+ int result;
+
+ VA_OPEN (ap, format);
+ VA_FIXEDARG (ap, const char *, format);
+
+ result = vfprintf (stdout, format, ap);
+ VA_CLOSE (ap);
+
+ return result;
+ }
+
+
+ You can declare variables either before or after the VA_OPEN,
+ VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning
+ and end of a block. They must appear at the same nesting level,
+ and any variables declared after VA_OPEN go out of scope at
+ VA_CLOSE. Unfortunately, with a K+R compiler, that includes the
+ argument list. You can have multiple instances of VA_OPEN/VA_CLOSE
+ pairs in a single function in case you need to traverse the
+ argument list more than once.
+
+ For ease of writing code which uses GCC extensions but needs to be
+ portable to other compilers, we provide the GCC_VERSION macro that
+ simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
+ wrappers around __attribute__. Also, __extension__ will be #defined
+ to nothing if it doesn't work. See below.
+
+ This header also defines a lot of obsolete macros:
+ CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID,
+ AND, DOTS, NOARGS. Don't use them. */
+
+#ifndef _ANSIDECL_H
+#define _ANSIDECL_H 1
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+/* Using MACRO(x,y) in cpp #if conditionals does not work with some
+ older preprocessors. Thus we can't define something like this:
+
+#define HAVE_GCC_VERSION(MAJOR, MINOR) \
+ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
+
+and then test "#if HAVE_GCC_VERSION(2,7)".
+
+So instead we use the macro below and test it against specific values. */
+
+/* This macro simplifies testing whether we are using gcc, and if it
+ is of a particular minimum version. (Both major & minor numbers are
+ significant.) This macro will evaluate to 0 if we are not using
+ gcc at all. */
+#ifndef GCC_VERSION
+#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif /* GCC_VERSION */
+
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus))
+/* 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__. */
+/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
+ C++ compilers, does not define __STDC__, though it acts as if this
+ was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
+
+#define ANSI_PROTOTYPES 1
+#define PTR void *
+#define PTRCONST void *const
+#define LONG_DOUBLE long double
+
+#define PARAMS(ARGS) ARGS
+#define VPARAMS(ARGS) ARGS
+#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR)
+
+/* variadic function helper macros */
+/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's
+ use without inhibiting further decls and without declaring an
+ actual variable. */
+#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy
+#define VA_CLOSE(AP) } va_end(AP); }
+#define VA_FIXEDARG(AP, T, N) struct Qdmy
+
+#undef const
+#undef volatile
+#undef signed
+
+/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
+ it too, but it's not in C89. */
+#undef inline
+#if __STDC_VERSION__ > 199901L
+/* it's a keyword */
+#else
+# if GCC_VERSION >= 2007
+# define inline __inline__ /* __inline__ prevents -pedantic warnings */
+# else
+# define inline /* nothing */
+# endif
+#endif
+
+/* These are obsolete. Do not use. */
+#ifndef IN_GCC
+#define CONST const
+#define VOLATILE volatile
+#define SIGNED signed
+
+#define PROTO(type, name, arglist) type name arglist
+#define EXFUN(name, proto) name proto
+#define DEFUN(name, arglist, args) name(args)
+#define DEFUN_VOID(name) name(void)
+#define AND ,
+#define DOTS , ...
+#define NOARGS void
+#endif /* ! IN_GCC */
+
+#else /* Not ANSI C. */
+
+#undef ANSI_PROTOTYPES
+#define PTR char *
+#define PTRCONST PTR
+#define LONG_DOUBLE double
+
+#define PARAMS(args) ()
+#define VPARAMS(args) (va_alist) va_dcl
+#define VA_START(va_list, var) va_start(va_list)
+
+#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy
+#define VA_CLOSE(AP) } va_end(AP); }
+#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE)
+
+/* some systems define these in header files for non-ansi mode */
+#undef const
+#undef volatile
+#undef signed
+#undef inline
+#define const
+#define volatile
+#define signed
+#define inline
+
+#ifndef IN_GCC
+#define CONST
+#define VOLATILE
+#define SIGNED
+
+#define PROTO(type, name, arglist) type name ()
+#define EXFUN(name, proto) name()
+#define DEFUN(name, arglist, args) name arglist args;
+#define DEFUN_VOID(name) name()
+#define AND ;
+#define DOTS
+#define NOARGS
+#endif /* ! IN_GCC */
+
+#endif /* ANSI C. */
+
+/* Define macros for some gcc attributes. This permits us to use the
+ macros freely, and know that they will come into play for the
+ version of gcc in which they are supported. */
+
+#if (GCC_VERSION < 2007)
+# define __attribute__(x)
+#endif
+
+/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
+#ifndef ATTRIBUTE_MALLOC
+# if (GCC_VERSION >= 2096)
+# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+# else
+# define ATTRIBUTE_MALLOC
+# endif /* GNUC >= 2.96 */
+#endif /* ATTRIBUTE_MALLOC */
+
+/* Attributes on labels were valid as of gcc 2.93. */
+#ifndef ATTRIBUTE_UNUSED_LABEL
+# if (GCC_VERSION >= 2093)
+# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
+# else
+# define ATTRIBUTE_UNUSED_LABEL
+# endif /* GNUC >= 2.93 */
+#endif /* ATTRIBUTE_UNUSED_LABEL */
+
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+
+#ifndef ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#endif /* ATTRIBUTE_NORETURN */
+
+/* Attribute `nonnull' was valid as of gcc 3.3. */
+#ifndef ATTRIBUTE_NONNULL
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
+# else
+# define ATTRIBUTE_NONNULL(m)
+# endif /* GNUC >= 3.3 */
+#endif /* ATTRIBUTE_NONNULL */
+
+/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
+ This was the case for the `printf' format attribute by itself
+ before GCC 3.3, but as of 3.3 we need to add the `nonnull'
+ attribute to retain this behavior. */
+#ifndef ATTRIBUTE_PRINTF
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
+#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
+#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
+#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
+#endif /* ATTRIBUTE_PRINTF */
+
+/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
+ NULL format specifier was allowed as of gcc 3.3. */
+#ifndef ATTRIBUTE_NULL_PRINTF
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
+# else
+# define ATTRIBUTE_NULL_PRINTF(m, n)
+# endif /* GNUC >= 3.3 */
+# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
+# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
+# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
+# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
+# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
+#endif /* ATTRIBUTE_NULL_PRINTF */
+
+/* We use __extension__ in some places to suppress -pedantic warnings
+ about GCC extensions. This feature didn't work properly before
+ gcc 2.8. */
+#if GCC_VERSION < 2008
+#define __extension__
+#endif
+
+#endif /* ansidecl.h */
diff --git a/contrib/gdb/include/bfdlink.h b/contrib/gdb/include/bfdlink.h
new file mode 100644
index 0000000..a989f64
--- /dev/null
+++ b/contrib/gdb/include/bfdlink.h
@@ -0,0 +1,686 @@
+/* bfdlink.h -- header file for BFD link routines
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003
+ 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_sec_merge, /* Discard local temporary symbols in SEC_MERGE
+ sections. */
+ discard_none, /* Don't discard any locals. */
+ discard_l, /* Discard local temporary symbols. */
+ discard_all /* Discard all locals. */
+};
+
+/* Describes the type of hash table entry structure being used.
+ Different hash table structure have different fields and so
+ support different linking features. */
+enum bfd_link_hash_table_type
+ {
+ bfd_link_generic_hash_table,
+ bfd_link_elf_hash_table
+ };
+
+/* 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. */
+};
+
+enum bfd_link_common_skip_ar_aymbols
+{
+ bfd_link_common_skip_none,
+ bfd_link_common_skip_text,
+ bfd_link_common_skip_data,
+ bfd_link_common_skip_all
+};
+
+/* 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 *und_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;
+ /* The type of the link hash table. */
+ enum bfd_link_hash_table_type type;
+};
+
+/* 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
+ (struct bfd_link_hash_table *, const char *, bfd_boolean create,
+ bfd_boolean copy, bfd_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
+ (bfd *, struct bfd_link_info *, const char *, bfd_boolean,
+ bfd_boolean, bfd_boolean);
+
+/* Traverse a link hash table. */
+extern void bfd_link_hash_traverse
+ (struct bfd_link_hash_table *,
+ bfd_boolean (*) (struct bfd_link_hash_entry *, void *),
+ void *);
+
+/* Add an entry to the undefs list. */
+extern void bfd_link_add_undef
+ (struct bfd_link_hash_table *, struct bfd_link_hash_entry *);
+
+struct bfd_sym_chain
+{
+ struct bfd_sym_chain *next;
+ const char *name;
+};
+
+/* How to handle unresolved symbols.
+ There are four possibilities which are enumerated below: */
+enum report_method
+{
+ /* This is the initial value when then link_info structure is created.
+ It allows the various stages of the linker to determine whether they
+ allowed to set the value. */
+ RM_NOT_YET_SET = 0,
+ RM_IGNORE,
+ RM_GENERATE_WARNING,
+ RM_GENERATE_ERROR
+};
+
+/* This structure holds all the information needed to communicate
+ between BFD and the linker when doing a link. */
+
+struct bfd_link_info
+{
+ /* TRUE if BFD should generate a relocatable object file. */
+ unsigned int relocatable: 1;
+
+ /* TRUE if BFD should generate relocation information in the final
+ executable. */
+ unsigned int emitrelocations: 1;
+
+ /* TRUE if BFD should generate a "task linked" object file,
+ similar to relocatable but also with globals converted to
+ statics. */
+ unsigned int task_link: 1;
+
+ /* TRUE if BFD should generate a shared object. */
+ unsigned int shared: 1;
+
+ /* TRUE if BFD should pre-bind symbols in a shared object. */
+ unsigned int symbolic: 1;
+
+ /* TRUE if BFD should export all symbols in the dynamic symbol table
+ of an executable, rather than only those used. */
+ unsigned int export_dynamic: 1;
+
+ /* TRUE if shared objects should be linked directly, not shared. */
+ unsigned int static_link: 1;
+
+ /* TRUE if the output file should be in a traditional format. This
+ is equivalent to the setting of the BFD_TRADITIONAL_FORMAT flag
+ on the output file, but may be checked when reading the input
+ files. */
+ unsigned int traditional_format: 1;
+
+ /* TRUE if we want to produced optimized output files. This might
+ need much more time and therefore must be explicitly selected. */
+ unsigned int optimize: 1;
+
+ /* TRUE if ok to have multiple definition. */
+ unsigned int allow_multiple_definition: 1;
+
+ /* TRUE if ok to have version with no definition. */
+ unsigned int allow_undefined_version: 1;
+
+ /* TRUE if symbols should be retained in memory, FALSE if they
+ should be freed and reread. */
+ unsigned int keep_memory: 1;
+
+ /* TRUE if every symbol should be reported back via the notice
+ callback. */
+ unsigned int notice_all: 1;
+
+ /* TRUE if executable should not contain copy relocs.
+ Setting this true may result in a non-sharable text segment. */
+ unsigned int nocopyreloc: 1;
+
+ /* TRUE if the new ELF dynamic tags are enabled. */
+ unsigned int new_dtags: 1;
+
+ /* TRUE if non-PLT relocs should be merged into one reloc section
+ and sorted so that relocs against the same symbol come together. */
+ unsigned int combreloc: 1;
+
+ /* TRUE if .eh_frame_hdr section and PT_GNU_EH_FRAME ELF segment
+ should be created. */
+ unsigned int eh_frame_hdr: 1;
+
+ /* TRUE if global symbols in discarded sections should be stripped. */
+ unsigned int strip_discarded: 1;
+
+ /* TRUE if the final relax pass is needed. */
+ unsigned int need_relax_finalize: 1;
+
+ /* TRUE if generating a position independent executable. */
+ unsigned int pie: 1;
+
+ /* TRUE if generating an executable, position independent or not. */
+ unsigned int executable : 1;
+
+ /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W|PF_X
+ flags. */
+ unsigned int execstack: 1;
+
+ /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W
+ flags. */
+ unsigned int noexecstack: 1;
+
+ /* What to do with unresolved symbols in an object file.
+ When producing static binaries the default is GENERATE_ERROR.
+ When producing dynamic binaries the default is IGNORE. The
+ assumption with dynamic binaries is that the reference will be
+ resolved at load/execution time. */
+ enum report_method unresolved_syms_in_objects;
+
+ /* What to do with unresolved symbols in a shared library.
+ The same defaults apply. */
+ enum report_method unresolved_syms_in_shared_libs;
+
+ /* Which symbols to strip. */
+ enum bfd_link_strip strip;
+
+ /* Which local symbols to discard. */
+ enum bfd_link_discard discard;
+
+ /* Criteria for skipping symbols when detemining
+ whether to include an object from an archive. */
+ enum bfd_link_common_skip_ar_aymbols common_skip_ar_aymbols;
+
+ /* Function callbacks. */
+ const struct bfd_link_callbacks *callbacks;
+
+ /* 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 the notice callback. If
+ this is NULL, and notice_all is FALSE, then 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;
+
+ /* 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;
+
+ /* List of global symbol names that are starting points for marking
+ sections against garbage collection. */
+ struct bfd_sym_chain *gc_sym_list;
+
+ /* If a base output file is wanted, then this points to it */
+ void *base_file;
+
+ /* The function to call when the executable or shared object is
+ loaded. */
+ const char *init_function;
+
+ /* The function to call when the executable or shared object is
+ unloaded. */
+ const char *fini_function;
+
+ /* Non-zero if auto-import thunks for DATA items in pei386 DLLs
+ should be generated/linked against. Set to 1 if this feature
+ is explicitly requested by the user, -1 if enabled by default. */
+ int pei386_auto_import;
+
+ /* Non-zero if runtime relocs for DATA items with non-zero addends
+ in pei386 DLLs should be generated. Set to 1 if this feature
+ is explicitly requested by the user, -1 if enabled by default. */
+ int pei386_runtime_pseudo_reloc;
+
+ /* How many spare .dynamic DT_NULL entries should be added? */
+ unsigned int spare_dynamic_tags;
+
+ /* May be used to set DT_FLAGS for ELF. */
+ bfd_vma flags;
+
+ /* May be used to set DT_FLAGS_1 for ELF. */
+ bfd_vma flags_1;
+};
+
+/* 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. */
+ bfd_boolean (*add_archive_element)
+ (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. */
+ bfd_boolean (*multiple_definition)
+ (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. */
+ bfd_boolean (*multiple_common)
+ (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 relocatable 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. */
+ bfd_boolean (*add_to_set)
+ (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
+ relocatable file. NAME is the name of the symbol found. ABFD,
+ SECTION and VALUE are the value of the symbol. */
+ bfd_boolean (*constructor)
+ (struct bfd_link_info *, bfd_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. */
+ bfd_boolean (*warning)
+ (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. FATAL indicates whether an undefined symbol is
+ a fatal error or not. In some cases SECTION may be NULL. */
+ bfd_boolean (*undefined_symbol)
+ (struct bfd_link_info *, const char *name, bfd *abfd,
+ asection *section, bfd_vma address, bfd_boolean fatal);
+ /* 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. */
+ bfd_boolean (*reloc_overflow)
+ (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. */
+ bfd_boolean (*reloc_dangerous)
+ (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. */
+ bfd_boolean (*unattached_reloc)
+ (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. */
+ bfd_boolean (*notice)
+ (struct bfd_link_info *, const char *name,
+ bfd *abfd, asection *section, bfd_vma address);
+ /* A function which is called for reporting a linker error. ID is the
+ error identifier. The remaining input is the same as einfo () in
+ ld. */
+ bfd_boolean (*error_handler)
+ (int id, const char *fmt, ...);
+
+/* Identifiers of linker error messages used by error_handler. */
+#define LD_DEFINITION_IN_DISCARDED_SECTION 1
+};
+
+/* 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_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
+ {
+ /* Size of contents, or zero when contents size == size
+ within output section.
+ A non-zero value allows filling of the output section
+ with an arbitrary repeated pattern. */
+ unsigned int size;
+ /* Data to put into file. */
+ 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 (bfd *, asection *);
+
+/* These structures are used to describe version information for the
+ ELF linker. These structures could be manipulated entirely inside
+ BFD, but it would be a pain. Instead, the regular linker sets up
+ these structures, and then passes them into BFD. */
+
+/* Glob pattern for a version. */
+
+struct bfd_elf_version_expr
+{
+ /* Next glob pattern for this version. */
+ struct bfd_elf_version_expr *next;
+ /* Glob pattern. */
+ const char *pattern;
+ /* NULL for a glob pattern, otherwise a straight symbol. */
+ const char *symbol;
+ /* Defined by ".symver". */
+ unsigned int symver : 1;
+ /* Defined by version script. */
+ unsigned int script : 1;
+ /* Pattern type. */
+#define BFD_ELF_VERSION_C_TYPE 1
+#define BFD_ELF_VERSION_CXX_TYPE 2
+#define BFD_ELF_VERSION_JAVA_TYPE 4
+ unsigned int mask : 3;
+};
+
+struct bfd_elf_version_expr_head
+{
+ /* List of all patterns, both wildcards and non-wildcards. */
+ struct bfd_elf_version_expr *list;
+ /* Hash table for non-wildcards. */
+ void *htab;
+ /* Remaining patterns. */
+ struct bfd_elf_version_expr *remaining;
+ /* What kind of pattern types are present in list (bitmask). */
+ unsigned int mask;
+};
+
+/* Version dependencies. */
+
+struct bfd_elf_version_deps
+{
+ /* Next dependency for this version. */
+ struct bfd_elf_version_deps *next;
+ /* The version which this version depends upon. */
+ struct bfd_elf_version_tree *version_needed;
+};
+
+/* A node in the version tree. */
+
+struct bfd_elf_version_tree
+{
+ /* Next version. */
+ struct bfd_elf_version_tree *next;
+ /* Name of this version. */
+ const char *name;
+ /* Version number. */
+ unsigned int vernum;
+ /* Regular expressions for global symbols in this version. */
+ struct bfd_elf_version_expr_head globals;
+ /* Regular expressions for local symbols in this version. */
+ struct bfd_elf_version_expr_head locals;
+ /* List of versions which this version depends upon. */
+ struct bfd_elf_version_deps *deps;
+ /* Index of the version name. This is used within BFD. */
+ unsigned int name_indx;
+ /* Whether this version tree was used. This is used within BFD. */
+ int used;
+ /* Matching hook. */
+ struct bfd_elf_version_expr *(*match)
+ (struct bfd_elf_version_expr_head *head,
+ struct bfd_elf_version_expr *prev, const char *sym);
+};
+
+#endif
diff --git a/contrib/gdb/include/bin-bugs.h b/contrib/gdb/include/bin-bugs.h
new file mode 100644
index 0000000..3c97715
--- /dev/null
+++ b/contrib/gdb/include/bin-bugs.h
@@ -0,0 +1,3 @@
+#ifndef REPORT_BUGS_TO
+#define REPORT_BUGS_TO "bug-binutils@gnu.org"
+#endif
diff --git a/contrib/gdb/include/bout.h b/contrib/gdb/include/bout.h
new file mode 100644
index 0000000..a69e280
--- /dev/null
+++ b/contrib/gdb/include/bout.h
@@ -0,0 +1,191 @@
+/* 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).
+
+ Copyright 2001 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. */
+
+/* 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/demangle.h b/contrib/gdb/include/demangle.h
new file mode 100644
index 0000000..6e995e4
--- /dev/null
+++ b/contrib/gdb/include/demangle.h
@@ -0,0 +1,533 @@
+/* Defs for interface to demanglers.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002,
+ 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+#include "libiberty.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* 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_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
+#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+#define DMGL_HP (1 << 12) /* For the HP aCC compiler;
+ same as ARM except for
+ template arguments, etc. */
+#define DMGL_EDG (1 << 13)
+#define DMGL_GNU_V3 (1 << 14)
+#define DMGL_GNAT (1 << 15)
+
+/* 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|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT)
+
+/* 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
+{
+ no_demangling = -1,
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM,
+ hp_demangling = DMGL_HP,
+ edg_demangling = DMGL_EDG,
+ gnu_v3_demangling = DMGL_GNU_V3,
+ java_demangling = DMGL_JAVA,
+ gnat_demangling = DMGL_GNAT
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define NO_DEMANGLING_STYLE_STRING "none"
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+#define HP_DEMANGLING_STYLE_STRING "hp"
+#define EDG_DEMANGLING_STYLE_STRING "edg"
+#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3"
+#define JAVA_DEMANGLING_STYLE_STRING "java"
+#define GNAT_DEMANGLING_STYLE_STRING "gnat"
+
+/* 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 (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM)
+#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP)
+#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG)
+#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
+#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
+#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
+
+/* Provide information about the available demangle styles. This code is
+ pulled from gdb into libiberty because it is useful to binutils also. */
+
+extern const struct demangler_engine
+{
+ const char *const demangling_style_name;
+ const enum demangling_styles demangling_style;
+ const char *const demangling_style_doc;
+} libiberty_demanglers[];
+
+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));
+
+extern enum demangling_styles
+cplus_demangle_set_style PARAMS ((enum demangling_styles style));
+
+extern enum demangling_styles
+cplus_demangle_name_to_style PARAMS ((const char *name));
+
+/* V3 ABI demangling entry points, defined in cp-demangle.c. */
+extern char*
+cplus_demangle_v3 PARAMS ((const char* mangled, int options));
+
+extern char*
+java_demangle_v3 PARAMS ((const char* mangled));
+
+
+enum gnu_v3_ctor_kinds {
+ gnu_v3_complete_object_ctor = 1,
+ gnu_v3_base_object_ctor,
+ gnu_v3_complete_object_allocating_ctor
+};
+
+/* Return non-zero iff NAME is the mangled form of a constructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_ctor_kinds' value indicating what kind of constructor
+ it is. */
+extern enum gnu_v3_ctor_kinds
+ is_gnu_v3_mangled_ctor PARAMS ((const char *name));
+
+
+enum gnu_v3_dtor_kinds {
+ gnu_v3_deleting_dtor = 1,
+ gnu_v3_complete_object_dtor,
+ gnu_v3_base_object_dtor
+};
+
+/* Return non-zero iff NAME is the mangled form of a destructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_dtor_kinds' value, indicating what kind of destructor
+ it is. */
+extern enum gnu_v3_dtor_kinds
+ is_gnu_v3_mangled_dtor PARAMS ((const char *name));
+
+/* The V3 demangler works in two passes. The first pass builds a tree
+ representation of the mangled name, and the second pass turns the
+ tree representation into a demangled string. Here we define an
+ interface to permit a caller to build their own tree
+ representation, which they can pass to the demangler to get a
+ demangled string. This can be used to canonicalize user input into
+ something which the demangler might output. It could also be used
+ by other demanglers in the future. */
+
+/* These are the component types which may be found in the tree. Many
+ component types have one or two subtrees, referred to as left and
+ right (a component type with only one subtree puts it in the left
+ subtree). */
+
+enum demangle_component_type
+{
+ /* A name, with a length and a pointer to a string. */
+ DEMANGLE_COMPONENT_NAME,
+ /* A qualified name. The left subtree is a class or namespace or
+ some such thing, and the right subtree is a name qualified by
+ that class. */
+ DEMANGLE_COMPONENT_QUAL_NAME,
+ /* A local name. The left subtree describes a function, and the
+ right subtree is a name which is local to that function. */
+ DEMANGLE_COMPONENT_LOCAL_NAME,
+ /* A typed name. The left subtree is a name, and the right subtree
+ describes that name as a function. */
+ DEMANGLE_COMPONENT_TYPED_NAME,
+ /* A template. The left subtree is a template name, and the right
+ subtree is a template argument list. */
+ DEMANGLE_COMPONENT_TEMPLATE,
+ /* A template parameter. This holds a number, which is the template
+ parameter index. */
+ DEMANGLE_COMPONENT_TEMPLATE_PARAM,
+ /* A constructor. This holds a name and the kind of
+ constructor. */
+ DEMANGLE_COMPONENT_CTOR,
+ /* A destructor. This holds a name and the kind of destructor. */
+ DEMANGLE_COMPONENT_DTOR,
+ /* A vtable. This has one subtree, the type for which this is a
+ vtable. */
+ DEMANGLE_COMPONENT_VTABLE,
+ /* A VTT structure. This has one subtree, the type for which this
+ is a VTT. */
+ DEMANGLE_COMPONENT_VTT,
+ /* A construction vtable. The left subtree is the type for which
+ this is a vtable, and the right subtree is the derived type for
+ which this vtable is built. */
+ DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
+ /* A typeinfo structure. This has one subtree, the type for which
+ this is the tpeinfo structure. */
+ DEMANGLE_COMPONENT_TYPEINFO,
+ /* A typeinfo name. This has one subtree, the type for which this
+ is the typeinfo name. */
+ DEMANGLE_COMPONENT_TYPEINFO_NAME,
+ /* A typeinfo function. This has one subtree, the type for which
+ this is the tpyeinfo function. */
+ DEMANGLE_COMPONENT_TYPEINFO_FN,
+ /* A thunk. This has one subtree, the name for which this is a
+ thunk. */
+ DEMANGLE_COMPONENT_THUNK,
+ /* A virtual thunk. This has one subtree, the name for which this
+ is a virtual thunk. */
+ DEMANGLE_COMPONENT_VIRTUAL_THUNK,
+ /* A covariant thunk. This has one subtree, the name for which this
+ is a covariant thunk. */
+ DEMANGLE_COMPONENT_COVARIANT_THUNK,
+ /* A Java class. This has one subtree, the type. */
+ DEMANGLE_COMPONENT_JAVA_CLASS,
+ /* A guard variable. This has one subtree, the name for which this
+ is a guard variable. */
+ DEMANGLE_COMPONENT_GUARD,
+ /* A reference temporary. This has one subtree, the name for which
+ this is a temporary. */
+ DEMANGLE_COMPONENT_REFTEMP,
+ /* A standard substitution. This holds the name of the
+ substitution. */
+ DEMANGLE_COMPONENT_SUB_STD,
+ /* The restrict qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT,
+ /* The volatile qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE,
+ /* The const qualifier. The one subtree is the type which is being
+ qualified. */
+ DEMANGLE_COMPONENT_CONST,
+ /* The restrict qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT_THIS,
+ /* The volatile qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE_THIS,
+ /* The const qualifier modifying a member function. The one subtree
+ is the type which is being qualified. */
+ DEMANGLE_COMPONENT_CONST_THIS,
+ /* A vendor qualifier. The left subtree is the type which is being
+ qualified, and the right subtree is the name of the
+ qualifier. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ /* A pointer. The one subtree is the type which is being pointed
+ to. */
+ DEMANGLE_COMPONENT_POINTER,
+ /* A reference. The one subtree is the type which is being
+ referenced. */
+ DEMANGLE_COMPONENT_REFERENCE,
+ /* A complex type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_COMPLEX,
+ /* An imaginary type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_IMAGINARY,
+ /* A builtin type. This holds the builtin type information. */
+ DEMANGLE_COMPONENT_BUILTIN_TYPE,
+ /* A vendor's builtin type. This holds the name of the type. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE,
+ /* A function type. The left subtree is the return type. The right
+ subtree is a list of ARGLIST nodes. Either or both may be
+ NULL. */
+ DEMANGLE_COMPONENT_FUNCTION_TYPE,
+ /* An array type. The left subtree is the dimension, which may be
+ NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an
+ expression. The right subtree is the element type. */
+ DEMANGLE_COMPONENT_ARRAY_TYPE,
+ /* A pointer to member type. The left subtree is the class type,
+ and the right subtree is the member type. CV-qualifiers appear
+ on the latter. */
+ DEMANGLE_COMPONENT_PTRMEM_TYPE,
+ /* An argument list. The left subtree is the current argument, and
+ the right subtree is either NULL or another ARGLIST node. */
+ DEMANGLE_COMPONENT_ARGLIST,
+ /* A template argument list. The left subtree is the current
+ template argument, and the right subtree is either NULL or
+ another TEMPLATE_ARGLIST node. */
+ DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
+ /* An operator. This holds information about a standard
+ operator. */
+ DEMANGLE_COMPONENT_OPERATOR,
+ /* An extended operator. This holds the number of arguments, and
+ the name of the extended operator. */
+ DEMANGLE_COMPONENT_EXTENDED_OPERATOR,
+ /* A typecast, represented as a unary operator. The one subtree is
+ the type to which the argument should be cast. */
+ DEMANGLE_COMPONENT_CAST,
+ /* A unary expression. The left subtree is the operator, and the
+ right subtree is the single argument. */
+ DEMANGLE_COMPONENT_UNARY,
+ /* A binary expression. The left subtree is the operator, and the
+ right subtree is a BINARY_ARGS. */
+ DEMANGLE_COMPONENT_BINARY,
+ /* Arguments to a binary expression. The left subtree is the first
+ argument, and the right subtree is the second argument. */
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ /* A trinary expression. The left subtree is the operator, and the
+ right subtree is a TRINARY_ARG1. */
+ DEMANGLE_COMPONENT_TRINARY,
+ /* Arguments to a trinary expression. The left subtree is the first
+ argument, and the right subtree is a TRINARY_ARG2. */
+ DEMANGLE_COMPONENT_TRINARY_ARG1,
+ /* More arguments to a trinary expression. The left subtree is the
+ second argument, and the right subtree is the third argument. */
+ DEMANGLE_COMPONENT_TRINARY_ARG2,
+ /* A literal. The left subtree is the type, and the right subtree
+ is the value, represented as a DEMANGLE_COMPONENT_NAME. */
+ DEMANGLE_COMPONENT_LITERAL,
+ /* A negative literal. Like LITERAL, but the value is negated.
+ This is a minor hack: the NAME used for LITERAL points directly
+ to the mangled string, but since negative numbers are mangled
+ using 'n' instead of '-', we want a way to indicate a negative
+ number which involves neither modifying the mangled string nor
+ allocating a new copy of the literal in memory. */
+ DEMANGLE_COMPONENT_LITERAL_NEG
+};
+
+/* Types which are only used internally. */
+
+struct demangle_operator_info;
+struct demangle_builtin_type_info;
+
+/* A node in the tree representation is an instance of a struct
+ demangle_component. Note that the field names of the struct are
+ not well protected against macros defined by the file including
+ this one. We can fix this if it ever becomes a problem. */
+
+struct demangle_component
+{
+ /* The type of this component. */
+ enum demangle_component_type type;
+
+ union
+ {
+ /* For DEMANGLE_COMPONENT_NAME. */
+ struct
+ {
+ /* A pointer to the name (which need not NULL terminated) and
+ its length. */
+ const char *s;
+ int len;
+ } s_name;
+
+ /* For DEMANGLE_COMPONENT_OPERATOR. */
+ struct
+ {
+ /* Operator. */
+ const struct demangle_operator_info *op;
+ } s_operator;
+
+ /* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
+ struct
+ {
+ /* Number of arguments. */
+ int args;
+ /* Name. */
+ struct demangle_component *name;
+ } s_extended_operator;
+
+ /* For DEMANGLE_COMPONENT_CTOR. */
+ struct
+ {
+ /* Kind of constructor. */
+ enum gnu_v3_ctor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_ctor;
+
+ /* For DEMANGLE_COMPONENT_DTOR. */
+ struct
+ {
+ /* Kind of destructor. */
+ enum gnu_v3_dtor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_dtor;
+
+ /* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */
+ struct
+ {
+ /* Builtin type. */
+ const struct demangle_builtin_type_info *type;
+ } s_builtin;
+
+ /* For DEMANGLE_COMPONENT_SUB_STD. */
+ struct
+ {
+ /* Standard substitution string. */
+ const char* string;
+ /* Length of string. */
+ int len;
+ } s_string;
+
+ /* For DEMANGLE_COMPONENT_TEMPLATE_PARAM. */
+ struct
+ {
+ /* Template parameter index. */
+ long number;
+ } s_number;
+
+ /* For other types. */
+ struct
+ {
+ /* Left (or only) subtree. */
+ struct demangle_component *left;
+ /* Right subtree. */
+ struct demangle_component *right;
+ } s_binary;
+
+ } u;
+};
+
+/* People building mangled trees are expected to allocate instances of
+ struct demangle_component themselves. They can then call one of
+ the following functions to fill them in. */
+
+/* Fill in most component types with a left subtree and a right
+ subtree. Returns non-zero on success, zero on failure, such as an
+ unrecognized or inappropriate component type. */
+
+extern int
+cplus_demangle_fill_component PARAMS ((struct demangle_component *fill,
+ enum demangle_component_type,
+ struct demangle_component *left,
+ struct demangle_component *right));
+
+/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_name PARAMS ((struct demangle_component *fill,
+ const char *, int));
+
+/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the
+ builtin type (e.g., "int", etc.). Returns non-zero on success,
+ zero if the type is not recognized. */
+
+extern int
+cplus_demangle_fill_builtin_type PARAMS ((struct demangle_component *fill,
+ const char *typename));
+
+/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the
+ operator and the number of arguments which it takes (the latter is
+ used to disambiguate operators which can be both binary and unary,
+ such as '-'). Returns non-zero on success, zero if the operator is
+ not recognized. */
+
+extern int
+cplus_demangle_fill_operator PARAMS ((struct demangle_component *fill,
+ const char *opname, int args));
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the
+ number of arguments and the name. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_extended_operator PARAMS ((struct demangle_component *fill,
+ int numargs,
+ struct demangle_component *nm));
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_ctor PARAMS ((struct demangle_component *fill,
+ enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name));
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_dtor PARAMS ((struct demangle_component *fill,
+ enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name));
+
+/* This function translates a mangled name into a struct
+ demangle_component tree. The first argument is the mangled name.
+ The second argument is DMGL_* options. This returns a pointer to a
+ tree on success, or NULL on failure. On success, the third
+ argument is set to a block of memory allocated by malloc. This
+ block should be passed to free when the tree is no longer
+ needed. */
+
+extern struct demangle_component *
+cplus_demangle_v3_components PARAMS ((const char *mangled,
+ int options,
+ void **mem));
+
+/* This function takes a struct demangle_component tree and returns
+ the corresponding demangled string. The first argument is DMGL_*
+ options. The second is the tree to demangle. The third is a guess
+ at the length of the demangled string, used to initially allocate
+ the return buffer. The fourth is a pointer to a size_t. On
+ success, this function returns a buffer allocated by malloc(), and
+ sets the size_t pointed to by the fourth argument to the size of
+ the allocated buffer (not the length of the returned string). On
+ failure, this function returns NULL, and sets the size_t pointed to
+ by the fourth argument to 0 for an invalid tree, or to 1 for a
+ memory allocation error. */
+
+extern char *
+cplus_demangle_print PARAMS ((int options,
+ const struct demangle_component *tree,
+ int estimated_length,
+ size_t *p_allocated_size));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* DEMANGLE_H */
diff --git a/contrib/gdb/include/dis-asm.h b/contrib/gdb/include/dis-asm.h
new file mode 100644
index 0000000..3670c51
--- /dev/null
+++ b/contrib/gdb/include/dis-asm.h
@@ -0,0 +1,317 @@
+/* Interface between the opcode library and its callers.
+
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "bfd.h"
+
+typedef int (*fprintf_ftype) (void *, 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;
+ void *stream;
+ void *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_flavour. This can be bfd_target_unknown_flavour. */
+ enum bfd_flavour flavour;
+ /* 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;
+ /* An arch/mach-specific bitmask of selected instruction subsets, mainly
+ for processors with run-time-switchable instruction sets. The default,
+ zero, means that there is no constraint. CGEN-based opcodes ports
+ may use ISA_foo masks. */
+ unsigned long insn_sets;
+
+ /* Some targets need information about the current section to accurately
+ display insns. If this is NULL, the target disassembler function
+ will have to make its best guess. */
+ asection *section;
+
+ /* An array of pointers to symbols either at the location being disassembled
+ or at the start of the function being disassembled. The array is sorted
+ so that the first symbol is intended to be the one used. The others are
+ present for any misc. purposes. This is not set reliably, but if it is
+ not NULL, it is correct. */
+ asymbol **symbols;
+ /* Number of symbols in array. */
+ int num_symbols;
+
+ /* 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;
+#define INSN_HAS_RELOC 0x80000000
+ void *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)
+ (bfd_vma memaddr, bfd_byte *myaddr, unsigned 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)
+ (int status, bfd_vma memaddr, struct disassemble_info *info);
+
+ /* Function called to print ADDR. */
+ void (*print_address_func)
+ (bfd_vma addr, struct disassemble_info *info);
+
+ /* Function called to determine if there is a symbol at the given ADDR.
+ If there is, the function returns 1, otherwise it returns 0.
+ This is used by ports which support an overlay manager where
+ the overlay number is held in the top part of an address. In
+ some circumstances we want to include the overlay number in the
+ address, (normally because there is a symbol associated with
+ that address), but sometimes we want to mask out the overlay bits. */
+ int (* symbol_at_address_func)
+ (bfd_vma addr, struct disassemble_info * info);
+
+ /* Function called to check if a SYMBOL is can be displayed to the user.
+ This is used by some ports that want to hide special symbols when
+ displaying debugging outout. */
+ bfd_boolean (* symbol_is_valid)
+ (asymbol *, struct disassemble_info * info);
+
+ /* These are for buffer_read_memory. */
+ bfd_byte *buffer;
+ bfd_vma buffer_vma;
+ unsigned int buffer_length;
+
+ /* This variable may be set by the instruction decoder. It suggests
+ the number of bytes objdump should display on a single line. If
+ the instruction decoder sets this, it should always set it to
+ the same value in order to get reasonable looking output. */
+ int bytes_per_line;
+
+ /* The next two variables control the way objdump displays the raw data. */
+ /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
+ /* output will look like this:
+ 00: 00000000 00000000
+ with the chunks displayed according to "display_endian". */
+ int bytes_per_chunk;
+ enum bfd_endian display_endian;
+
+ /* Number of octets per incremented target address
+ Normally one, but some DSPs have byte sizes of 16 or 32 bits. */
+ unsigned int octets_per_byte;
+
+ /* 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 */
+
+ /* Command line options specific to the target disassembler. */
+ char * disassembler_options;
+
+} disassemble_info;
+
+
+/* Standard disassemblers. Disassemble one instruction at the given
+ target address. Return number of octets processed. */
+typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
+
+extern int print_insn_big_mips (bfd_vma, disassemble_info *);
+extern int print_insn_little_mips (bfd_vma, disassemble_info *);
+extern int print_insn_i386 (bfd_vma, disassemble_info *);
+extern int print_insn_i386_att (bfd_vma, disassemble_info *);
+extern int print_insn_i386_intel (bfd_vma, disassemble_info *);
+extern int print_insn_ia64 (bfd_vma, disassemble_info *);
+extern int print_insn_i370 (bfd_vma, disassemble_info *);
+extern int print_insn_m68hc11 (bfd_vma, disassemble_info *);
+extern int print_insn_m68hc12 (bfd_vma, disassemble_info *);
+extern int print_insn_m68k (bfd_vma, disassemble_info *);
+extern int print_insn_z8001 (bfd_vma, disassemble_info *);
+extern int print_insn_z8002 (bfd_vma, disassemble_info *);
+extern int print_insn_h8300 (bfd_vma, disassemble_info *);
+extern int print_insn_h8300h (bfd_vma, disassemble_info *);
+extern int print_insn_h8300s (bfd_vma, disassemble_info *);
+extern int print_insn_h8500 (bfd_vma, disassemble_info *);
+extern int print_insn_alpha (bfd_vma, disassemble_info *);
+extern int print_insn_big_arm (bfd_vma, disassemble_info *);
+extern int print_insn_little_arm (bfd_vma, disassemble_info *);
+extern int print_insn_sparc (bfd_vma, disassemble_info *);
+extern int print_insn_big_a29k (bfd_vma, disassemble_info *);
+extern int print_insn_little_a29k (bfd_vma, disassemble_info *);
+extern int print_insn_avr (bfd_vma, disassemble_info *);
+extern int print_insn_d10v (bfd_vma, disassemble_info *);
+extern int print_insn_d30v (bfd_vma, disassemble_info *);
+extern int print_insn_dlx (bfd_vma, disassemble_info *);
+extern int print_insn_fr30 (bfd_vma, disassemble_info *);
+extern int print_insn_hppa (bfd_vma, disassemble_info *);
+extern int print_insn_i860 (bfd_vma, disassemble_info *);
+extern int print_insn_i960 (bfd_vma, disassemble_info *);
+extern int print_insn_ip2k (bfd_vma, disassemble_info *);
+extern int print_insn_m32r (bfd_vma, disassemble_info *);
+extern int print_insn_m88k (bfd_vma, disassemble_info *);
+extern int print_insn_mcore (bfd_vma, disassemble_info *);
+extern int print_insn_mmix (bfd_vma, disassemble_info *);
+extern int print_insn_mn10200 (bfd_vma, disassemble_info *);
+extern int print_insn_mn10300 (bfd_vma, disassemble_info *);
+extern int print_insn_msp430 (bfd_vma, disassemble_info *);
+extern int print_insn_ns32k (bfd_vma, disassemble_info *);
+extern int print_insn_openrisc (bfd_vma, disassemble_info *);
+extern int print_insn_big_or32 (bfd_vma, disassemble_info *);
+extern int print_insn_little_or32 (bfd_vma, disassemble_info *);
+extern int print_insn_pdp11 (bfd_vma, disassemble_info *);
+extern int print_insn_pj (bfd_vma, disassemble_info *);
+extern int print_insn_big_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_little_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_rs6000 (bfd_vma, disassemble_info *);
+extern int print_insn_s390 (bfd_vma, disassemble_info *);
+extern int print_insn_sh (bfd_vma, disassemble_info *);
+extern int print_insn_tic30 (bfd_vma, disassemble_info *);
+extern int print_insn_tic4x (bfd_vma, disassemble_info *);
+extern int print_insn_tic54x (bfd_vma, disassemble_info *);
+extern int print_insn_tic80 (bfd_vma, disassemble_info *);
+extern int print_insn_v850 (bfd_vma, disassemble_info *);
+extern int print_insn_vax (bfd_vma, disassemble_info *);
+extern int print_insn_w65 (bfd_vma, disassemble_info *);
+extern int print_insn_xstormy16 (bfd_vma, disassemble_info *);
+extern int print_insn_xtensa (bfd_vma, disassemble_info *);
+extern int print_insn_sh64 (bfd_vma, disassemble_info *);
+extern int print_insn_sh64x_media (bfd_vma, disassemble_info *);
+extern int print_insn_frv (bfd_vma, disassemble_info *);
+extern int print_insn_iq2000 (bfd_vma, disassemble_info *);
+
+extern disassembler_ftype arc_get_disassembler (void *);
+extern disassembler_ftype cris_get_disassembler (bfd *);
+
+extern void print_mips_disassembler_options (FILE *);
+extern void print_ppc_disassembler_options (FILE *);
+extern void print_arm_disassembler_options (FILE *);
+extern void parse_arm_disassembler_option (char *);
+extern int get_arm_regname_num_options (void);
+extern int set_arm_regname_option (int);
+extern int get_arm_regnames (int, const char **, const char **, const char ***);
+extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
+
+/* Fetch the disassembler for a given BFD, if that support is available. */
+extern disassembler_ftype disassembler (bfd *);
+
+/* Amend the disassemble_info structure as necessary for the target architecture.
+ Should only be called after initialising the info->arch field. */
+extern void disassemble_init_for_target (struct disassemble_info * info);
+
+/* Document any target specific options available from the disassembler. */
+extern void disassembler_usage (FILE *);
+
+
+/* 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
+ (bfd_vma, bfd_byte *, unsigned 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 (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
+ (bfd_vma, struct disassemble_info *);
+
+/* Always true. */
+extern int generic_symbol_at_address
+ (bfd_vma, struct disassemble_info *);
+
+/* Also always true. */
+extern bfd_boolean generic_symbol_is_valid
+ (asymbol *, struct disassemble_info *);
+
+/* Method to initialize a disassemble_info struct. This should be
+ called by all applications creating such a struct. */
+extern void init_disassemble_info (struct disassemble_info *info, void *stream,
+ fprintf_ftype fprintf_func);
+
+/* For compatibility with existing code. */
+#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
+ init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC))
+#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
+ init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! defined (DIS_ASM_H) */
diff --git a/contrib/gdb/include/dyn-string.h b/contrib/gdb/include/dyn-string.h
new file mode 100644
index 0000000..85f88b1
--- /dev/null
+++ b/contrib/gdb/include/dyn-string.h
@@ -0,0 +1,63 @@
+/* An abstract string datatype.
+ Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
+ Contributed by Mark Mitchell (mark@markmitchell.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute 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.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+typedef struct dyn_string
+{
+ int allocated; /* The amount of space allocated for the string. */
+ int length; /* The actual length of the string. */
+ char *s; /* The string itself, NUL-terminated. */
+}* dyn_string_t;
+
+/* The length STR, in bytes, not including the terminating NUL. */
+#define dyn_string_length(STR) \
+ ((STR)->length)
+
+/* The NTBS in which the contents of STR are stored. */
+#define dyn_string_buf(STR) \
+ ((STR)->s)
+
+/* Compare DS1 to DS2 with strcmp. */
+#define dyn_string_compare(DS1, DS2) \
+ (strcmp ((DS1)->s, (DS2)->s))
+
+
+extern int dyn_string_init PARAMS ((struct dyn_string *, int));
+extern dyn_string_t dyn_string_new PARAMS ((int));
+extern void dyn_string_delete PARAMS ((dyn_string_t));
+extern char *dyn_string_release PARAMS ((dyn_string_t));
+extern dyn_string_t dyn_string_resize PARAMS ((dyn_string_t, int));
+extern void dyn_string_clear PARAMS ((dyn_string_t));
+extern int dyn_string_copy PARAMS ((dyn_string_t, dyn_string_t));
+extern int dyn_string_copy_cstr PARAMS ((dyn_string_t, const char *));
+extern int dyn_string_prepend PARAMS ((dyn_string_t, dyn_string_t));
+extern int dyn_string_prepend_cstr PARAMS ((dyn_string_t, const char *));
+extern int dyn_string_insert PARAMS ((dyn_string_t, int,
+ dyn_string_t));
+extern int dyn_string_insert_cstr PARAMS ((dyn_string_t, int,
+ const char *));
+extern int dyn_string_insert_char PARAMS ((dyn_string_t, int, int));
+extern int dyn_string_append PARAMS ((dyn_string_t, dyn_string_t));
+extern int dyn_string_append_cstr PARAMS ((dyn_string_t, const char *));
+extern int dyn_string_append_char PARAMS ((dyn_string_t, int));
+extern int dyn_string_substring PARAMS ((dyn_string_t,
+ dyn_string_t, int, int));
+extern int dyn_string_eq PARAMS ((dyn_string_t, dyn_string_t));
diff --git a/contrib/gdb/include/fibheap.h b/contrib/gdb/include/fibheap.h
new file mode 100644
index 0000000..4eebaf1
--- /dev/null
+++ b/contrib/gdb/include/fibheap.h
@@ -0,0 +1,86 @@
+/* A Fibonacci heap datatype.
+ Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by Daniel Berlin (dan@cgsoftware.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute 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.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Fibonacci heaps are somewhat complex, but, there's an article in
+ DDJ that explains them pretty well:
+
+ http://www.ddj.com/articles/1997/9701/9701o/9701o.htm?topic=algoritms
+
+ Introduction to algorithms by Corman and Rivest also goes over them.
+
+ The original paper that introduced them is "Fibonacci heaps and their
+ uses in improved network optimization algorithms" by Tarjan and
+ Fredman (JACM 34(3), July 1987).
+
+ Amortized and real worst case time for operations:
+
+ ExtractMin: O(lg n) amortized. O(n) worst case.
+ DecreaseKey: O(1) amortized. O(lg n) worst case.
+ Insert: O(2) amortized. O(1) actual.
+ Union: O(1) amortized. O(1) actual. */
+
+#ifndef _FIBHEAP_H_
+#define _FIBHEAP_H_
+
+#include "ansidecl.h"
+
+typedef long fibheapkey_t;
+
+typedef struct fibheap
+{
+ size_t nodes;
+ struct fibnode *min;
+ struct fibnode *root;
+} *fibheap_t;
+
+typedef struct fibnode
+{
+ struct fibnode *parent;
+ struct fibnode *child;
+ struct fibnode *left;
+ struct fibnode *right;
+ fibheapkey_t key;
+ void *data;
+#ifdef __GNUC__
+ __extension__ unsigned long int degree : 31;
+ __extension__ unsigned long int mark : 1;
+#else
+ unsigned int degree : 31;
+ unsigned int mark : 1;
+#endif
+} *fibnode_t;
+
+extern fibheap_t fibheap_new PARAMS ((void));
+extern fibnode_t fibheap_insert PARAMS ((fibheap_t, fibheapkey_t, void *));
+extern int fibheap_empty PARAMS ((fibheap_t));
+extern fibheapkey_t fibheap_min_key PARAMS ((fibheap_t));
+extern fibheapkey_t fibheap_replace_key PARAMS ((fibheap_t, fibnode_t,
+ fibheapkey_t));
+extern void *fibheap_replace_key_data PARAMS ((fibheap_t, fibnode_t,
+ fibheapkey_t, void *));
+extern void *fibheap_extract_min PARAMS ((fibheap_t));
+extern void *fibheap_min PARAMS ((fibheap_t));
+extern void *fibheap_replace_data PARAMS ((fibheap_t, fibnode_t, void *));
+extern void *fibheap_delete_node PARAMS ((fibheap_t, fibnode_t));
+extern void fibheap_delete PARAMS ((fibheap_t));
+extern fibheap_t fibheap_union PARAMS ((fibheap_t, fibheap_t));
+
+#endif /* _FIBHEAP_H_ */
diff --git a/contrib/gdb/include/filenames.h b/contrib/gdb/include/filenames.h
new file mode 100644
index 0000000..ca9e273
--- /dev/null
+++ b/contrib/gdb/include/filenames.h
@@ -0,0 +1,51 @@
+/* Macros for taking apart, interpreting and processing file names.
+
+ These are here because some non-Posix (a.k.a. DOSish) systems have
+ drive letter brain-damage at the beginning of an absolute file name,
+ use forward- and back-slash in path names interchangeably, and
+ some of them have case-insensitive file names.
+
+ Copyright 2000, 2001 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. */
+
+#ifndef FILENAMES_H
+#define FILENAMES_H
+
+#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__)
+
+#ifndef HAVE_DOS_BASED_FILE_SYSTEM
+#define HAVE_DOS_BASED_FILE_SYSTEM 1
+#endif
+
+#define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\')
+/* Note that IS_ABSOLUTE_PATH accepts d:foo as well, although it is
+ only semi-absolute. This is because the users of IS_ABSOLUTE_PATH
+ want to know whether to prepend the current working directory to
+ a file name, which should not be done with a name like d:foo. */
+#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || (((f)[0]) && ((f)[1] == ':')))
+#define FILENAME_CMP(s1, s2) strcasecmp(s1, s2)
+
+#else /* not DOSish */
+
+#define IS_DIR_SEPARATOR(c) ((c) == '/')
+#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]))
+#define FILENAME_CMP(s1, s2) strcmp(s1, s2)
+
+#endif /* not DOSish */
+
+#endif /* FILENAMES_H */
diff --git a/contrib/gdb/include/floatformat.h b/contrib/gdb/include/floatformat.h
new file mode 100644
index 0000000..a8244ad
--- /dev/null
+++ b/contrib/gdb/include/floatformat.h
@@ -0,0 +1,133 @@
+/* IEEE floating point support declarations, for GDB, the GNU Debugger.
+ Copyright 1991, 1994, 1995, 1997, 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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. */
+
+/* What is the order of the bytes. */
+
+enum floatformat_byteorders {
+
+ /* Standard little endian byte order.
+ EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */
+
+ floatformat_little,
+
+ /* Standard big endian byte order.
+ EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */
+
+ floatformat_big,
+
+ /* Little endian byte order but big endian word order.
+ EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */
+
+ floatformat_littlebyte_bigword
+
+};
+
+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;
+ /* Bias added to a "true" exponent to form the biased exponent. It
+ is intentionally signed as, otherwize, -exp_bias can turn into a
+ very large number (e.g., given the exp_bias of 0x3fff and a 64
+ bit long, the equation (long)(1 - exp_bias) evaluates to
+ 4294950914) instead of -16382). */
+ 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;
+
+ /* Internal name for debugging. */
+ const char *name;
+
+ /* Validator method. */
+ int (*is_valid) PARAMS ((const struct floatformat *fmt, const char *from));
+};
+
+/* 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;
+
+/* floatformat for ARM IEEE double, little endian bytes and big endian words */
+
+extern const struct floatformat floatformat_ieee_double_littlebyte_bigword;
+
+/* 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_m88110_harris_ext;
+extern const struct floatformat floatformat_arm_ext_big;
+extern const struct floatformat floatformat_arm_ext_littlebyte_bigword;
+/* IA-64 Floating Point register spilt into memory. */
+extern const struct floatformat floatformat_ia64_spill_big;
+extern const struct floatformat floatformat_ia64_spill_little;
+extern const struct floatformat floatformat_ia64_quad_big;
+extern const struct floatformat floatformat_ia64_quad_little;
+
+/* 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 *, const char *, double *));
+
+/* The converse: convert the double *FROM to FMT
+ and store where TO points. */
+
+extern void
+floatformat_from_double PARAMS ((const struct floatformat *,
+ const double *, char *));
+
+/* Return non-zero iff the data at FROM is a valid number in format FMT. */
+
+extern int
+floatformat_is_valid PARAMS ((const struct floatformat *fmt, const char *from));
+
+#endif /* defined (FLOATFORMAT_H) */
diff --git a/contrib/gdb/include/fnmatch.h b/contrib/gdb/include/fnmatch.h
new file mode 100644
index 0000000..37d23ee
--- /dev/null
+++ b/contrib/gdb/include/fnmatch.h
@@ -0,0 +1,70 @@
+/* Copyright 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+This program is free software; you can redistribute 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, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _FNMATCH_H
+
+#define _FNMATCH_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define __P(args) args
+#else /* Not C++ or ANSI C. */
+#undef __P
+#define __P(args) ()
+/* We can get away without defining `const' here only because in this file
+ it is used only inside the prototype for `fnmatch', which is elided in
+ non-ANSI C where `const' is problematical. */
+#endif /* C++ or ANSI C. */
+
+
+/* We #undef these before defining them because some losing systems
+ (HP-UX A.08.07 for example) define these in <unistd.h>. */
+#undef FNM_PATHNAME
+#undef FNM_NOESCAPE
+#undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
+#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
+#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+#define FNM_NOMATCH 1
+
+/* Match STRING against the filename pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+extern int fnmatch __P ((const char *__pattern, const char *__string,
+ int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/contrib/gdb/include/fopen-bin.h b/contrib/gdb/include/fopen-bin.h
new file mode 100644
index 0000000..b868f63
--- /dev/null
+++ b/contrib/gdb/include/fopen-bin.h
@@ -0,0 +1,27 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ 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 0000000..0f37529
--- /dev/null
+++ b/contrib/gdb/include/fopen-same.h
@@ -0,0 +1,27 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ 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/fopen-vms.h b/contrib/gdb/include/fopen-vms.h
new file mode 100644
index 0000000..da76b7f
--- /dev/null
+++ b/contrib/gdb/include/fopen-vms.h
@@ -0,0 +1,24 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ This version is for VMS systems, where text and binary files are
+ different.
+ 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","rfm=var"
+#define FOPEN_WB "wb","rfm=var"
+#define FOPEN_AB "ab","rfm=var"
+#define FOPEN_RUB "r+b","rfm=var"
+#define FOPEN_WUB "w+b","rfm=var"
+#define FOPEN_AUB "a+b","rfm=var"
+
+#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/gdb/callback.h b/contrib/gdb/include/gdb/callback.h
new file mode 100644
index 0000000..3fa4191
--- /dev/null
+++ b/contrib/gdb/include/gdb/callback.h
@@ -0,0 +1,272 @@
+/* Remote target system call callback support.
+ Copyright 1997 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 interface isn't intended to be specific to any particular kind
+ of remote (hardware, simulator, whatever). As such, support for it
+ (e.g. sim/common/callback.c) should *not* live in the simulator source
+ tree, nor should it live in the gdb source tree. */
+
+/* There are various ways to handle system calls:
+
+ 1) Have a simulator intercept the appropriate trap instruction and
+ directly perform the system call on behalf of the target program.
+ This is the typical way of handling system calls for embedded targets.
+ [Handling system calls for embedded targets isn't that much of an
+ oxymoron as running compiler testsuites make use of the capability.]
+
+ This method of system call handling is done when STATE_ENVIRONMENT
+ is ENVIRONMENT_USER.
+
+ 2) Have a simulator emulate the hardware as much as possible.
+ If the program running on the real hardware communicates with some sort
+ of target manager, one would want to be able to run this program on the
+ simulator as well.
+
+ This method of system call handling is done when STATE_ENVIRONMENT
+ is ENVIRONMENT_OPERATING.
+*/
+
+#ifndef CALLBACK_H
+#define CALLBACK_H
+
+/* ??? The reason why we check for va_start here should be documented. */
+
+#ifndef va_start
+#include <ansidecl.h>
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#endif
+
+/* Mapping of host/target values. */
+/* ??? For debugging purposes, one might want to add a string of the
+ name of the symbol. */
+
+typedef struct {
+ int host_val;
+ int target_val;
+} CB_TARGET_DEFS_MAP;
+
+#define MAX_CALLBACK_FDS 10
+
+/* Forward decl for stat/fstat. */
+struct stat;
+
+typedef struct host_callback_struct host_callback;
+
+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));
+ void (*flush_stdout) PARAMS ((host_callback *));
+ int (*write_stderr) PARAMS ((host_callback *, const char *, int));
+ void (*flush_stderr) PARAMS ((host_callback *));
+ int (*stat) PARAMS ((host_callback *, const char *, struct stat *));
+ int (*fstat) PARAMS ((host_callback *, int, struct stat *));
+ int (*ftruncate) PARAMS ((host_callback *, int, long));
+ int (*truncate) PARAMS ((host_callback *, const char *, long));
+
+ /* When present, call to the client to give it the oportunity to
+ poll any io devices for a request to quit (indicated by a nonzero
+ return value). */
+ int (*poll_quit) PARAMS ((host_callback *));
+
+ /* 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 *));
+
+ /* depreciated, use vprintf_filtered - Talk to the user on a console. */
+ void (*printf_filtered) PARAMS ((host_callback *, const char *, ...));
+
+ /* Talk to the user on a console. */
+ void (*vprintf_filtered) PARAMS ((host_callback *, const char *, va_list));
+
+ /* Same as vprintf_filtered but to stderr. */
+ void (*evprintf_filtered) PARAMS ((host_callback *, const char *, va_list));
+
+ /* Print an error message and "exit".
+ In the case of gdb "exiting" means doing a longjmp back to the main
+ command loop. */
+ void (*error) 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];
+
+ /* System call numbers. */
+ CB_TARGET_DEFS_MAP *syscall_map;
+ /* Errno values. */
+ CB_TARGET_DEFS_MAP *errno_map;
+ /* Flags to the open system call. */
+ CB_TARGET_DEFS_MAP *open_map;
+ /* Signal numbers. */
+ CB_TARGET_DEFS_MAP *signal_map;
+ /* Layout of `stat' struct.
+ The format is a series of "name,length" pairs separated by colons.
+ Empty space is indicated with a `name' of "space".
+ All padding must be explicitly mentioned.
+ Lengths are in bytes. If this needs to be extended to bits,
+ use "name.bits".
+ Example: "st_dev,4:st_ino,4:st_mode,4:..." */
+ const char *stat_map;
+
+ /* Marker for those wanting to do sanity checks.
+ This should remain the last member of this struct to help catch
+ miscompilation errors. */
+#define HOST_CALLBACK_MAGIC 4705 /* teds constant */
+ int magic;
+};
+
+extern host_callback default_callback;
+
+/* Canonical versions of system call numbers.
+ It's not intended to willy-nilly throw every system call ever heard
+ of in here. Only include those that have an important use.
+ ??? One can certainly start a discussion over the ones that are currently
+ here, but that will always be true. */
+
+/* These are used by the ANSI C support of libc. */
+#define CB_SYS_exit 1
+#define CB_SYS_open 2
+#define CB_SYS_close 3
+#define CB_SYS_read 4
+#define CB_SYS_write 5
+#define CB_SYS_lseek 6
+#define CB_SYS_unlink 7
+#define CB_SYS_getpid 8
+#define CB_SYS_kill 9
+#define CB_SYS_fstat 10
+/*#define CB_SYS_sbrk 11 - not currently a system call, but reserved. */
+
+/* ARGV support. */
+#define CB_SYS_argvlen 12
+#define CB_SYS_argv 13
+
+/* These are extras added for one reason or another. */
+#define CB_SYS_chdir 14
+#define CB_SYS_stat 15
+#define CB_SYS_chmod 16
+#define CB_SYS_utime 17
+#define CB_SYS_time 18
+
+/* Struct use to pass and return information necessary to perform a
+ system call. */
+/* FIXME: Need to consider target word size. */
+
+typedef struct cb_syscall {
+ /* The target's value of what system call to perform. */
+ int func;
+ /* The arguments to the syscall. */
+ long arg1, arg2, arg3, arg4;
+
+ /* The result. */
+ long result;
+ /* Some system calls have two results. */
+ long result2;
+ /* The target's errno value, or 0 if success.
+ This is converted to the target's value with host_to_target_errno. */
+ int errcode;
+
+ /* Working space to be used by memory read/write callbacks. */
+ PTR p1;
+ PTR p2;
+ long x1,x2;
+
+ /* Callbacks for reading/writing memory (e.g. for read/write syscalls).
+ ??? long or unsigned long might be better to use for the `count'
+ argument here. We mimic sim_{read,write} for now. Be careful to
+ test any changes with -Wall -Werror, mixed signed comparisons
+ will get you. */
+ int (*read_mem) PARAMS ((host_callback * /*cb*/, struct cb_syscall * /*sc*/,
+ unsigned long /*taddr*/, char * /*buf*/,
+ int /*bytes*/));
+ int (*write_mem) PARAMS ((host_callback * /*cb*/, struct cb_syscall * /*sc*/,
+ unsigned long /*taddr*/, const char * /*buf*/,
+ int /*bytes*/));
+
+ /* For sanity checking, should be last entry. */
+ int magic;
+} CB_SYSCALL;
+
+/* Magic number sanity checker. */
+#define CB_SYSCALL_MAGIC 0x12344321
+
+/* Macro to initialize CB_SYSCALL. Called first, before filling in
+ any fields. */
+#define CB_SYSCALL_INIT(sc) \
+do { \
+ memset ((sc), 0, sizeof (*(sc))); \
+ (sc)->magic = CB_SYSCALL_MAGIC; \
+} while (0)
+
+/* Return codes for various interface routines. */
+
+typedef enum {
+ CB_RC_OK = 0,
+ /* generic error */
+ CB_RC_ERR,
+ /* either file not found or no read access */
+ CB_RC_ACCESS,
+ CB_RC_NO_MEM
+} CB_RC;
+
+/* Read in target values for system call numbers, errno values, signals. */
+CB_RC cb_read_target_syscall_maps PARAMS ((host_callback *, const char *));
+
+/* Translate target to host syscall function numbers. */
+int cb_target_to_host_syscall PARAMS ((host_callback *, int));
+
+/* Translate host to target errno value. */
+int cb_host_to_target_errno PARAMS ((host_callback *, int));
+
+/* Translate target to host open flags. */
+int cb_target_to_host_open PARAMS ((host_callback *, int));
+
+/* Translate target signal number to host. */
+int cb_target_to_host_signal PARAMS ((host_callback *, int));
+
+/* Translate host signal number to target. */
+int cb_host_to_target_signal PARAMS ((host_callback *, int));
+
+/* Translate host stat struct to target.
+ If stat struct ptr is NULL, just compute target stat struct size.
+ Result is size of target stat struct or 0 if error. */
+int cb_host_to_target_stat PARAMS ((host_callback *, const struct stat *, PTR));
+
+/* Perform a system call. */
+CB_RC cb_syscall PARAMS ((host_callback *, CB_SYSCALL *));
+
+#endif
diff --git a/contrib/gdb/include/gdb/fileio.h b/contrib/gdb/include/gdb/fileio.h
new file mode 100644
index 0000000..d844781
--- /dev/null
+++ b/contrib/gdb/include/gdb/fileio.h
@@ -0,0 +1,146 @@
+/* Hosted File I/O interface definitions, for GDB, the GNU Debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#ifndef GDB_FILEIO_H_
+#define GDB_FILEIO_H_
+
+/* The following flags are defined to be independent of the host
+ as well as the target side implementation of these constants.
+ All constants are defined with a leading FILEIO_ in the name
+ to allow the usage of these constants together with the
+ corresponding implementation dependent constants in one module. */
+
+/* open(2) flags */
+#define FILEIO_O_RDONLY 0x0
+#define FILEIO_O_WRONLY 0x1
+#define FILEIO_O_RDWR 0x2
+#define FILEIO_O_APPEND 0x8
+#define FILEIO_O_CREAT 0x200
+#define FILEIO_O_TRUNC 0x400
+#define FILEIO_O_EXCL 0x800
+#define FILEIO_O_SUPPORTED (FILEIO_O_RDONLY | FILEIO_O_WRONLY| \
+ FILEIO_O_RDWR | FILEIO_O_APPEND| \
+ FILEIO_O_CREAT | FILEIO_O_TRUNC| \
+ FILEIO_O_EXCL)
+
+/* mode_t bits */
+#define FILEIO_S_IFREG 0100000
+#define FILEIO_S_IFDIR 040000
+#define FILEIO_S_IFCHR 020000
+#define FILEIO_S_IRUSR 0400
+#define FILEIO_S_IWUSR 0200
+#define FILEIO_S_IXUSR 0100
+#define FILEIO_S_IRWXU 0700
+#define FILEIO_S_IRGRP 040
+#define FILEIO_S_IWGRP 020
+#define FILEIO_S_IXGRP 010
+#define FILEIO_S_IRWXG 070
+#define FILEIO_S_IROTH 04
+#define FILEIO_S_IWOTH 02
+#define FILEIO_S_IXOTH 01
+#define FILEIO_S_IRWXO 07
+#define FILEIO_S_SUPPORTED (FILEIO_S_IFREG|FILEIO_S_IFDIR| \
+ FILEIO_S_IRWXU|FILEIO_S_IRWXG| \
+ FILEIO_S_IRWXO)
+
+/* lseek(2) flags */
+#define FILEIO_SEEK_SET 0
+#define FILEIO_SEEK_CUR 1
+#define FILEIO_SEEK_END 2
+
+/* errno values */
+#define FILEIO_EPERM 1
+#define FILEIO_ENOENT 2
+#define FILEIO_EINTR 4
+#define FILEIO_EIO 5
+#define FILEIO_EBADF 9
+#define FILEIO_EACCES 13
+#define FILEIO_EFAULT 14
+#define FILEIO_EBUSY 16
+#define FILEIO_EEXIST 17
+#define FILEIO_ENODEV 19
+#define FILEIO_ENOTDIR 20
+#define FILEIO_EISDIR 21
+#define FILEIO_EINVAL 22
+#define FILEIO_ENFILE 23
+#define FILEIO_EMFILE 24
+#define FILEIO_EFBIG 27
+#define FILEIO_ENOSPC 28
+#define FILEIO_ESPIPE 29
+#define FILEIO_EROFS 30
+#define FILEIO_ENOSYS 88
+#define FILEIO_ENAMETOOLONG 91
+#define FILEIO_EUNKNOWN 9999
+
+/* limits */
+#define FILEIO_INT_MIN -2147483648L
+#define FILEIO_INT_MAX 2147483647L
+#define FILEIO_UINT_MAX 4294967295UL
+#define FILEIO_LONG_MIN -9223372036854775808LL
+#define FILEIO_LONG_MAX 9223372036854775807LL
+#define FILEIO_ULONG_MAX 18446744073709551615ULL
+
+/* Integral types as used in protocol. */
+#if 0
+typedef __int32_t fio_int_t;
+typedef __uint32_t fio_uint_t, fio_mode_t, fio_time_t;
+typedef __int64_t fio_long_t;
+typedef __uint64_t fio_ulong_t;
+#endif
+
+#define FIO_INT_LEN 4
+#define FIO_UINT_LEN 4
+#define FIO_MODE_LEN 4
+#define FIO_TIME_LEN 4
+#define FIO_LONG_LEN 8
+#define FIO_ULONG_LEN 8
+
+typedef char fio_int_t[FIO_INT_LEN];
+typedef char fio_uint_t[FIO_UINT_LEN];
+typedef char fio_mode_t[FIO_MODE_LEN];
+typedef char fio_time_t[FIO_TIME_LEN];
+typedef char fio_long_t[FIO_LONG_LEN];
+typedef char fio_ulong_t[FIO_ULONG_LEN];
+
+/* Struct stat as used in protocol. For complete independence
+ of host/target systems, it's defined as an array with offsets
+ to the members. */
+
+struct fio_stat {
+ fio_uint_t fst_dev;
+ fio_uint_t fst_ino;
+ fio_mode_t fst_mode;
+ fio_uint_t fst_nlink;
+ fio_uint_t fst_uid;
+ fio_uint_t fst_gid;
+ fio_uint_t fst_rdev;
+ fio_ulong_t fst_size;
+ fio_ulong_t fst_blksize;
+ fio_ulong_t fst_blocks;
+ fio_time_t fst_atime;
+ fio_time_t fst_mtime;
+ fio_time_t fst_ctime;
+};
+
+struct fio_timeval {
+ fio_time_t ftv_sec;
+ fio_long_t ftv_usec;
+};
+
+#endif /* GDB_FILEIO_H_ */
diff --git a/contrib/gdb/include/gdb/remote-sim.h b/contrib/gdb/include/gdb/remote-sim.h
new file mode 100644
index 0000000..a49ba1a
--- /dev/null
+++ b/contrib/gdb/include/gdb/remote-sim.h
@@ -0,0 +1,282 @@
+/* This file defines the interface between the simulator and gdb.
+
+ Copyright 1993, 1994, 1996, 1997, 1998, 2000, 2002 Free Software
+ Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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
+
+
+/* Semi-opaque type used as result of sim_open and passed back to all
+ other routines. "desc" is short for "descriptor".
+ It is up to each simulator to define `sim_state'. */
+
+typedef struct sim_state *SIM_DESC;
+
+
+/* Values for `kind' arg to sim_open. */
+
+typedef enum {
+ SIM_OPEN_STANDALONE, /* simulator used standalone (run.c) */
+ SIM_OPEN_DEBUG /* simulator used by debugger (gdb) */
+} SIM_OPEN_KIND;
+
+
+/* Return codes from various functions. */
+
+typedef enum {
+ SIM_RC_FAIL = 0,
+ SIM_RC_OK = 1
+} SIM_RC;
+
+
+/* The bfd struct, as an opaque type. */
+
+struct bfd;
+
+
+/* Main simulator entry points. */
+
+
+/* Create a fully initialized simulator instance.
+
+ (This function is called when the simulator is selected from the
+ gdb command line.)
+
+ KIND specifies how the simulator shall be used. Currently there
+ are only two kinds: stand-alone and debug.
+
+ CALLBACK specifies a standard host callback (defined in callback.h).
+
+ ABFD, when non NULL, designates a target program. The program is
+ not loaded.
+
+ ARGV is a standard ARGV pointer such as that passed from the
+ command line. The syntax of the argument list is is assumed to be
+ ``SIM-PROG { SIM-OPTION } [ TARGET-PROGRAM { TARGET-OPTION } ]''.
+ The trailing TARGET-PROGRAM and args are only valid for a
+ stand-alone simulator.
+
+ On success, the result is a non NULL descriptor that shall be
+ passed to the other sim_foo functions. While the simulator
+ configuration can be parameterized by (in decreasing precedence)
+ ARGV's SIM-OPTION, ARGV's TARGET-PROGRAM and the ABFD argument, the
+ successful creation of the simulator shall not dependent on the
+ presence of any of these arguments/options.
+
+ Hardware simulator: The created simulator shall be sufficiently
+ initialized to handle, with out restrictions any client requests
+ (including memory reads/writes, register fetch/stores and a
+ resume).
+
+ Process simulator: that process is not created until a call to
+ sim_create_inferior. FIXME: What should the state of the simulator
+ be? */
+
+SIM_DESC sim_open PARAMS ((SIM_OPEN_KIND kind, struct host_callback_struct *callback, struct bfd *abfd, char **argv));
+
+
+/* Destory a simulator instance.
+
+ QUITTING is non-zero if we cannot hang on errors.
+
+ This may involve freeing target memory and closing any open files
+ and mmap'd areas. You cannot assume sim_kill has already been
+ called. */
+
+void sim_close PARAMS ((SIM_DESC sd, int quitting));
+
+
+/* Load program PROG into the simulators memory.
+
+ If ABFD is non-NULL, the bfd for the file has already been opened.
+ The result is a return code indicating success.
+
+ Hardware simulator: Normally, each program section is written into
+ memory according to that sections LMA using physical (direct)
+ addressing. The exception being systems, such as PPC/CHRP, which
+ support more complicated program loaders. A call to this function
+ should not effect the state of the processor registers. Multiple
+ calls to this function are permitted and have an accumulative
+ effect.
+
+ Process simulator: Calls to this function may be ignored.
+
+ FIXME: Most hardware simulators load the image at the VMA using
+ virtual addressing.
+
+ FIXME: For some hardware targets, before a loaded program can be
+ executed, it requires the manipulation of VM registers and tables.
+ Such manipulation should probably (?) occure in
+ sim_create_inferior. */
+
+SIM_RC sim_load PARAMS ((SIM_DESC sd, char *prog, struct bfd *abfd, int from_tty));
+
+
+/* Prepare to run the simulated program.
+
+ ABFD, if not NULL, provides initial processor state information.
+ ARGV and ENV, if non NULL, are NULL terminated lists of pointers.
+
+ Hardware simulator: This function shall initialize the processor
+ registers to a known value. The program counter and possibly stack
+ pointer shall be set using information obtained from ABFD (or
+ hardware reset defaults). ARGV and ENV, dependant on the target
+ ABI, may be written to memory.
+
+ Process simulator: After a call to this function, a new process
+ instance shall exist. The TEXT, DATA, BSS and stack regions shall
+ all be initialized, ARGV and ENV shall be written to process
+ address space (according to the applicable ABI) and the program
+ counter and stack pointer set accordingly. */
+
+SIM_RC sim_create_inferior PARAMS ((SIM_DESC sd, struct bfd *abfd, char **argv, char **env));
+
+
+/* Fetch LENGTH bytes of the simulated program's memory. Start fetch
+ at virtual address MEM and store in BUF. Result is number of bytes
+ read, or zero if error. */
+
+int sim_read PARAMS ((SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length));
+
+
+/* Store LENGTH bytes from BUF into the simulated program's
+ memory. Store bytes starting at virtual address MEM. Result is
+ number of bytes write, or zero if error. */
+
+int sim_write PARAMS ((SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length));
+
+
+/* Fetch register REGNO storing its raw (target endian) value in the
+ LENGTH byte buffer BUF. Return the actual size of the register or
+ zero if REGNO is not applicable.
+
+ Legacy implementations ignore LENGTH and always return -1.
+
+ If LENGTH does not match the size of REGNO no data is transfered
+ (the actual register size is still returned). */
+
+int sim_fetch_register PARAMS ((SIM_DESC sd, int regno, unsigned char *buf, int length));
+
+
+/* Store register REGNO from the raw (target endian) value in BUF.
+ Return the actual size of the register or zero if REGNO is not
+ applicable.
+
+ Legacy implementations ignore LENGTH and always return -1.
+
+ If LENGTH does not match the size of REGNO no data is transfered
+ (the actual register size is still returned). */
+
+int sim_store_register PARAMS ((SIM_DESC sd, int regno, unsigned char *buf, int length));
+
+
+/* Print whatever statistics the simulator has collected.
+
+ VERBOSE is currently unused and must always be zero. */
+
+void sim_info PARAMS ((SIM_DESC sd, int verbose));
+
+
+/* Run (or resume) the simulated program.
+
+ STEP, when non-zero indicates that only a single simulator cycle
+ should be emulated.
+
+ SIGGNAL, if non-zero is a (HOST) SIGRC value indicating the type of
+ event (hardware interrupt, signal) to be delivered to the simulated
+ program.
+
+ Hardware simulator: If the SIGRC value returned by
+ sim_stop_reason() is passed back to the simulator via SIGGNAL then
+ the hardware simulator shall correctly deliver the hardware event
+ indicated by that signal. If a value of zero is passed in then the
+ simulation will continue as if there were no outstanding signal.
+ The effect of any other SIGGNAL value is is implementation
+ dependant.
+
+ Process simulator: If SIGRC is non-zero then the corresponding
+ signal is delivered to the simulated program and execution is then
+ continued. A zero SIGRC value indicates that the program should
+ continue as normal. */
+
+void sim_resume PARAMS ((SIM_DESC sd, int step, int siggnal));
+
+
+/* Asynchronous request to stop the simulation.
+ A nonzero return indicates that the simulator is able to handle
+ the request */
+
+int sim_stop PARAMS ((SIM_DESC sd));
+
+
+/* Fetch the REASON why the program stopped.
+
+ SIM_EXITED: The program has terminated. SIGRC indicates the target
+ dependant exit status.
+
+ SIM_STOPPED: The program has stopped. SIGRC uses the host's signal
+ numbering as a way of identifying the reaon: program interrupted by
+ user via a sim_stop request (SIGINT); a breakpoint instruction
+ (SIGTRAP); a completed single step (SIGTRAP); an internal error
+ condition (SIGABRT); an illegal instruction (SIGILL); Access to an
+ undefined memory region (SIGSEGV); Mis-aligned memory access
+ (SIGBUS). For some signals information in addition to the signal
+ number may be retained by the simulator (e.g. offending address),
+ that information is not directly accessable via this interface.
+
+ SIM_SIGNALLED: The program has been terminated by a signal. The
+ simulator has encountered target code that causes the the program
+ to exit with signal SIGRC.
+
+ SIM_RUNNING, SIM_POLLING: The return of one of these values
+ indicates a problem internal to the simulator. */
+
+enum sim_stop { sim_running, sim_polling, sim_exited, sim_stopped, sim_signalled };
+
+void sim_stop_reason PARAMS ((SIM_DESC sd, enum sim_stop *reason, int *sigrc));
+
+
+/* Passthru for other commands that the simulator might support.
+ Simulators should be prepared to deal with any combination of NULL
+ or empty CMD. */
+
+void sim_do_command PARAMS ((SIM_DESC sd, char *cmd));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined (REMOTE_SIM_H) */
diff --git a/contrib/gdb/include/gdb/signals.h b/contrib/gdb/include/gdb/signals.h
new file mode 100644
index 0000000..b6f5d48
--- /dev/null
+++ b/contrib/gdb/include/gdb/signals.h
@@ -0,0 +1,237 @@
+/* Target signal numbers for GDB and the GDB remote protocol.
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 GDB_SIGNALS_H
+#define GDB_SIGNALS_H
+
+/* 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.
+
+ Since these numbers have actually made it out into other software
+ (stubs, etc.), you mustn't disturb the assigned numbering. If you
+ need to add new signals here, add them to the end of the explicitly
+ numbered signals, at the comment marker. Add them unconditionally,
+ not within any #if or #ifdef.
+
+ 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,
+
+ /* Used internally by Solaris threads. See signal(5) on Solaris. */
+ TARGET_SIGNAL_CANCEL = 76,
+
+ /* Yes, this pains me, too. But LynxOS didn't have SIG32, and now
+ GNU/Linux does, and we can't disturb the numbering, since it's
+ part of the remote protocol. Note that in some GDB's
+ TARGET_SIGNAL_REALTIME_32 is number 76. */
+ TARGET_SIGNAL_REALTIME_32,
+ /* Yet another pain, IRIX 6 has SIG64. */
+ TARGET_SIGNAL_REALTIME_64,
+ /* Yet another pain, GNU/Linux MIPS might go up to 128. */
+ TARGET_SIGNAL_REALTIME_65,
+ TARGET_SIGNAL_REALTIME_66,
+ TARGET_SIGNAL_REALTIME_67,
+ TARGET_SIGNAL_REALTIME_68,
+ TARGET_SIGNAL_REALTIME_69,
+ TARGET_SIGNAL_REALTIME_70,
+ TARGET_SIGNAL_REALTIME_71,
+ TARGET_SIGNAL_REALTIME_72,
+ TARGET_SIGNAL_REALTIME_73,
+ TARGET_SIGNAL_REALTIME_74,
+ TARGET_SIGNAL_REALTIME_75,
+ TARGET_SIGNAL_REALTIME_76,
+ TARGET_SIGNAL_REALTIME_77,
+ TARGET_SIGNAL_REALTIME_78,
+ TARGET_SIGNAL_REALTIME_79,
+ TARGET_SIGNAL_REALTIME_80,
+ TARGET_SIGNAL_REALTIME_81,
+ TARGET_SIGNAL_REALTIME_82,
+ TARGET_SIGNAL_REALTIME_83,
+ TARGET_SIGNAL_REALTIME_84,
+ TARGET_SIGNAL_REALTIME_85,
+ TARGET_SIGNAL_REALTIME_86,
+ TARGET_SIGNAL_REALTIME_87,
+ TARGET_SIGNAL_REALTIME_88,
+ TARGET_SIGNAL_REALTIME_89,
+ TARGET_SIGNAL_REALTIME_90,
+ TARGET_SIGNAL_REALTIME_91,
+ TARGET_SIGNAL_REALTIME_92,
+ TARGET_SIGNAL_REALTIME_93,
+ TARGET_SIGNAL_REALTIME_94,
+ TARGET_SIGNAL_REALTIME_95,
+ TARGET_SIGNAL_REALTIME_96,
+ TARGET_SIGNAL_REALTIME_97,
+ TARGET_SIGNAL_REALTIME_98,
+ TARGET_SIGNAL_REALTIME_99,
+ TARGET_SIGNAL_REALTIME_100,
+ TARGET_SIGNAL_REALTIME_101,
+ TARGET_SIGNAL_REALTIME_102,
+ TARGET_SIGNAL_REALTIME_103,
+ TARGET_SIGNAL_REALTIME_104,
+ TARGET_SIGNAL_REALTIME_105,
+ TARGET_SIGNAL_REALTIME_106,
+ TARGET_SIGNAL_REALTIME_107,
+ TARGET_SIGNAL_REALTIME_108,
+ TARGET_SIGNAL_REALTIME_109,
+ TARGET_SIGNAL_REALTIME_110,
+ TARGET_SIGNAL_REALTIME_111,
+ TARGET_SIGNAL_REALTIME_112,
+ TARGET_SIGNAL_REALTIME_113,
+ TARGET_SIGNAL_REALTIME_114,
+ TARGET_SIGNAL_REALTIME_115,
+ TARGET_SIGNAL_REALTIME_116,
+ TARGET_SIGNAL_REALTIME_117,
+ TARGET_SIGNAL_REALTIME_118,
+ TARGET_SIGNAL_REALTIME_119,
+ TARGET_SIGNAL_REALTIME_120,
+ TARGET_SIGNAL_REALTIME_121,
+ TARGET_SIGNAL_REALTIME_122,
+ TARGET_SIGNAL_REALTIME_123,
+ TARGET_SIGNAL_REALTIME_124,
+ TARGET_SIGNAL_REALTIME_125,
+ TARGET_SIGNAL_REALTIME_126,
+ TARGET_SIGNAL_REALTIME_127,
+
+ TARGET_SIGNAL_INFO,
+
+ /* 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,
+
+ /* Mach exceptions. In versions of GDB before 5.2, these were just before
+ TARGET_SIGNAL_INFO if you were compiling on a Mach host (and missing
+ otherwise). */
+ TARGET_EXC_BAD_ACCESS,
+ TARGET_EXC_BAD_INSTRUCTION,
+ TARGET_EXC_ARITHMETIC,
+ TARGET_EXC_EMULATION,
+ TARGET_EXC_SOFTWARE,
+ TARGET_EXC_BREAKPOINT,
+
+ /* If you are adding a new signal, add it just above this comment. */
+
+ /* Last and unused enum value, for sizing arrays, etc. */
+ TARGET_SIGNAL_LAST
+ };
+
+#endif /* #ifndef GDB_SIGNALS_H */
diff --git a/contrib/gdb/include/gdb/sim-arm.h b/contrib/gdb/include/gdb/sim-arm.h
new file mode 100644
index 0000000..5598f73
--- /dev/null
+++ b/contrib/gdb/include/gdb/sim-arm.h
@@ -0,0 +1,114 @@
+/* This file defines the interface between the Arm simulator and GDB.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (SIM_ARM_H)
+#define SIM_ARM_H
+
+#ifdef __cplusplus
+extern "C" { // }
+#endif
+
+enum sim_arm_regs
+{
+ SIM_ARM_R0_REGNUM,
+ SIM_ARM_R1_REGNUM,
+ SIM_ARM_R2_REGNUM,
+ SIM_ARM_R3_REGNUM,
+ SIM_ARM_R4_REGNUM,
+ SIM_ARM_R5_REGNUM,
+ SIM_ARM_R6_REGNUM,
+ SIM_ARM_R7_REGNUM,
+ SIM_ARM_R8_REGNUM,
+ SIM_ARM_R9_REGNUM,
+ SIM_ARM_R10_REGNUM,
+ SIM_ARM_R11_REGNUM,
+ SIM_ARM_R12_REGNUM,
+ SIM_ARM_R13_REGNUM,
+ SIM_ARM_R14_REGNUM,
+ SIM_ARM_R15_REGNUM, /* PC */
+ SIM_ARM_FP0_REGNUM,
+ SIM_ARM_FP1_REGNUM,
+ SIM_ARM_FP2_REGNUM,
+ SIM_ARM_FP3_REGNUM,
+ SIM_ARM_FP4_REGNUM,
+ SIM_ARM_FP5_REGNUM,
+ SIM_ARM_FP6_REGNUM,
+ SIM_ARM_FP7_REGNUM,
+ SIM_ARM_FPS_REGNUM,
+ SIM_ARM_PS_REGNUM,
+ SIM_ARM_MAVERIC_COP0R0_REGNUM,
+ SIM_ARM_MAVERIC_COP0R1_REGNUM,
+ SIM_ARM_MAVERIC_COP0R2_REGNUM,
+ SIM_ARM_MAVERIC_COP0R3_REGNUM,
+ SIM_ARM_MAVERIC_COP0R4_REGNUM,
+ SIM_ARM_MAVERIC_COP0R5_REGNUM,
+ SIM_ARM_MAVERIC_COP0R6_REGNUM,
+ SIM_ARM_MAVERIC_COP0R7_REGNUM,
+ SIM_ARM_MAVERIC_COP0R8_REGNUM,
+ SIM_ARM_MAVERIC_COP0R9_REGNUM,
+ SIM_ARM_MAVERIC_COP0R10_REGNUM,
+ SIM_ARM_MAVERIC_COP0R11_REGNUM,
+ SIM_ARM_MAVERIC_COP0R12_REGNUM,
+ SIM_ARM_MAVERIC_COP0R13_REGNUM,
+ SIM_ARM_MAVERIC_COP0R14_REGNUM,
+ SIM_ARM_MAVERIC_COP0R15_REGNUM,
+ SIM_ARM_MAVERIC_DSPSC_REGNUM,
+ SIM_ARM_IWMMXT_COP0R0_REGNUM,
+ SIM_ARM_IWMMXT_COP0R1_REGNUM,
+ SIM_ARM_IWMMXT_COP0R2_REGNUM,
+ SIM_ARM_IWMMXT_COP0R3_REGNUM,
+ SIM_ARM_IWMMXT_COP0R4_REGNUM,
+ SIM_ARM_IWMMXT_COP0R5_REGNUM,
+ SIM_ARM_IWMMXT_COP0R6_REGNUM,
+ SIM_ARM_IWMMXT_COP0R7_REGNUM,
+ SIM_ARM_IWMMXT_COP0R8_REGNUM,
+ SIM_ARM_IWMMXT_COP0R9_REGNUM,
+ SIM_ARM_IWMMXT_COP0R10_REGNUM,
+ SIM_ARM_IWMMXT_COP0R11_REGNUM,
+ SIM_ARM_IWMMXT_COP0R12_REGNUM,
+ SIM_ARM_IWMMXT_COP0R13_REGNUM,
+ SIM_ARM_IWMMXT_COP0R14_REGNUM,
+ SIM_ARM_IWMMXT_COP0R15_REGNUM,
+ SIM_ARM_IWMMXT_COP1R0_REGNUM,
+ SIM_ARM_IWMMXT_COP1R1_REGNUM,
+ SIM_ARM_IWMMXT_COP1R2_REGNUM,
+ SIM_ARM_IWMMXT_COP1R3_REGNUM,
+ SIM_ARM_IWMMXT_COP1R4_REGNUM,
+ SIM_ARM_IWMMXT_COP1R5_REGNUM,
+ SIM_ARM_IWMMXT_COP1R6_REGNUM,
+ SIM_ARM_IWMMXT_COP1R7_REGNUM,
+ SIM_ARM_IWMMXT_COP1R8_REGNUM,
+ SIM_ARM_IWMMXT_COP1R9_REGNUM,
+ SIM_ARM_IWMMXT_COP1R10_REGNUM,
+ SIM_ARM_IWMMXT_COP1R11_REGNUM,
+ SIM_ARM_IWMMXT_COP1R12_REGNUM,
+ SIM_ARM_IWMMXT_COP1R13_REGNUM,
+ SIM_ARM_IWMMXT_COP1R14_REGNUM,
+ SIM_ARM_IWMMXT_COP1R15_REGNUM
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/gdb/include/gdb/sim-d10v.h b/contrib/gdb/include/gdb/sim-d10v.h
new file mode 100644
index 0000000..8294b14
--- /dev/null
+++ b/contrib/gdb/include/gdb/sim-d10v.h
@@ -0,0 +1,142 @@
+/* This file defines the interface between the d10v simulator and gdb.
+
+ Copyright 1999, 2002 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 (SIM_D10V_H)
+#define SIM_D10V_H
+
+#ifdef __cplusplus
+extern "C" { // }
+#endif
+
+/* GDB interprets addresses as:
+
+ 0x00xxxxxx: Physical unified memory segment (Unified memory)
+ 0x01xxxxxx: Physical instruction memory segment (On-chip insn memory)
+ 0x02xxxxxx: Physical data memory segment (On-chip data memory)
+ 0x10xxxxxx: Logical data address segment (DMAP translated memory)
+ 0x11xxxxxx: Logical instruction address segment (IMAP translated memory)
+
+ The remote d10v board interprets addresses as:
+
+ 0x00xxxxxx: Physical unified memory segment (Unified memory)
+ 0x01xxxxxx: Physical instruction memory segment (On-chip insn memory)
+ 0x02xxxxxx: Physical data memory segment (On-chip data memory)
+
+ The following translate a virtual DMAP/IMAP offset into a physical
+ memory segment assigning the translated address to PHYS. Since a
+ memory access may cross a page boundrary the number of bytes for
+ which the translation is applicable (or 0 for an invalid virtual
+ offset) is returned. */
+
+enum
+ {
+ SIM_D10V_MEMORY_UNIFIED = 0x00000000,
+ SIM_D10V_MEMORY_INSN = 0x01000000,
+ SIM_D10V_MEMORY_DATA = 0x02000000,
+ SIM_D10V_MEMORY_DMAP = 0x10000000,
+ SIM_D10V_MEMORY_IMAP = 0x11000000
+ };
+
+extern unsigned long sim_d10v_translate_dmap_addr
+ (unsigned long offset,
+ int nr_bytes,
+ unsigned long *phys,
+ void *regcache,
+ unsigned long (*dmap_register) (void *regcache, int reg_nr));
+
+extern unsigned long sim_d10v_translate_imap_addr
+ (unsigned long offset,
+ int nr_bytes,
+ unsigned long *phys,
+ void *regcache,
+ unsigned long (*imap_register) (void *regcache, int reg_nr));
+
+extern unsigned long sim_d10v_translate_addr
+ (unsigned long vaddr,
+ int nr_bytes,
+ unsigned long *phys,
+ void *regcache,
+ unsigned long (*dmap_register) (void *regcache, int reg_nr),
+ unsigned long (*imap_register) (void *regcache, int reg_nr));
+
+
+/* The simulator makes use of the following register information. */
+
+enum sim_d10v_regs
+{
+ SIM_D10V_R0_REGNUM,
+ SIM_D10V_R1_REGNUM,
+ SIM_D10V_R2_REGNUM,
+ SIM_D10V_R3_REGNUM,
+ SIM_D10V_R4_REGNUM,
+ SIM_D10V_R5_REGNUM,
+ SIM_D10V_R6_REGNUM,
+ SIM_D10V_R7_REGNUM,
+ SIM_D10V_R8_REGNUM,
+ SIM_D10V_R9_REGNUM,
+ SIM_D10V_R10_REGNUM,
+ SIM_D10V_R11_REGNUM,
+ SIM_D10V_R12_REGNUM,
+ SIM_D10V_R13_REGNUM,
+ SIM_D10V_R14_REGNUM,
+ SIM_D10V_R15_REGNUM,
+ SIM_D10V_CR0_REGNUM,
+ SIM_D10V_CR1_REGNUM,
+ SIM_D10V_CR2_REGNUM,
+ SIM_D10V_CR3_REGNUM,
+ SIM_D10V_CR4_REGNUM,
+ SIM_D10V_CR5_REGNUM,
+ SIM_D10V_CR6_REGNUM,
+ SIM_D10V_CR7_REGNUM,
+ SIM_D10V_CR8_REGNUM,
+ SIM_D10V_CR9_REGNUM,
+ SIM_D10V_CR10_REGNUM,
+ SIM_D10V_CR11_REGNUM,
+ SIM_D10V_CR12_REGNUM,
+ SIM_D10V_CR13_REGNUM,
+ SIM_D10V_CR14_REGNUM,
+ SIM_D10V_CR15_REGNUM,
+ SIM_D10V_A0_REGNUM,
+ SIM_D10V_A1_REGNUM,
+ SIM_D10V_SPI_REGNUM,
+ SIM_D10V_SPU_REGNUM,
+ SIM_D10V_IMAP0_REGNUM,
+ SIM_D10V_IMAP1_REGNUM,
+ SIM_D10V_DMAP0_REGNUM,
+ SIM_D10V_DMAP1_REGNUM,
+ SIM_D10V_DMAP2_REGNUM,
+ SIM_D10V_DMAP3_REGNUM,
+ SIM_D10V_TS2_DMAP_REGNUM
+};
+
+enum
+{
+ SIM_D10V_NR_R_REGS = 16,
+ SIM_D10V_NR_A_REGS = 2,
+ SIM_D10V_NR_IMAP_REGS = 2,
+ SIM_D10V_NR_DMAP_REGS = 4,
+ SIM_D10V_NR_CR_REGS = 16
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/gdb/include/gdb/sim-frv.h b/contrib/gdb/include/gdb/sim-frv.h
new file mode 100644
index 0000000..0a1e021
--- /dev/null
+++ b/contrib/gdb/include/gdb/sim-frv.h
@@ -0,0 +1,53 @@
+/* This file defines the interface between the FR-V simulator and GDB.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 (SIM_FRV_H)
+#define SIM_FRV_H
+
+#ifdef __cplusplus
+extern "C" { // }
+#endif
+
+enum sim_frv_regs
+{
+ SIM_FRV_GR0_REGNUM = 0,
+ SIM_FRV_GR63_REGNUM = 63,
+ SIM_FRV_FR0_REGNUM = 64,
+ SIM_FRV_FR63_REGNUM = 127,
+ SIM_FRV_PC_REGNUM = 128,
+
+ /* An FR-V architecture may have up to 4096 special purpose registers
+ (SPRs). In order to determine a specific constant used to access
+ a particular SPR, one of the H_SPR_ prefixed offsets defined in
+ opcodes/frv-desc.h should be added to SIM_FRV_SPR0_REGNUM. So,
+ for example, the number that GDB uses to fetch the link register
+ from the simulator is (SIM_FRV_SPR0_REGNUM + H_SPR_LR). */
+ SIM_FRV_SPR0_REGNUM = 129,
+ SIM_FRV_SPR4095_REGNUM = SIM_FRV_SPR0_REGNUM + 4095
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/gdb/include/gdb/sim-h8300.h b/contrib/gdb/include/gdb/sim-h8300.h
new file mode 100644
index 0000000..246370a
--- /dev/null
+++ b/contrib/gdb/include/gdb/sim-h8300.h
@@ -0,0 +1,78 @@
+/* This file defines the interface between the h8300 simulator and gdb.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 (SIM_H8300_H)
+#define SIM_H8300_H
+
+#ifdef __cplusplus
+extern "C" { //}
+#endif
+
+/* The simulator makes use of the following register information. */
+
+ enum sim_h8300_regs
+ {
+ /* Registers common to all the H8 variants. */
+ /* Start here: */
+ SIM_H8300_R0_REGNUM,
+ SIM_H8300_R1_REGNUM,
+ SIM_H8300_R2_REGNUM,
+ SIM_H8300_R3_REGNUM,
+ SIM_H8300_R4_REGNUM,
+ SIM_H8300_R5_REGNUM,
+ SIM_H8300_R6_REGNUM,
+ SIM_H8300_R7_REGNUM,
+
+ SIM_H8300_CCR_REGNUM, /* Contains processor status */
+ SIM_H8300_PC_REGNUM, /* Contains program counter */
+ /* End here */
+
+ SIM_H8300_EXR_REGNUM, /* Contains extended processor status
+ H8S and higher */
+ SIM_H8300_MACL_REGNUM, /* Lower part of MAC register (26xx only)*/
+ SIM_H8300_MACH_REGNUM, /* High part of MAC register (26xx only) */
+
+ SIM_H8300_CYCLE_REGNUM,
+ SIM_H8300_INST_REGNUM,
+ SIM_H8300_TICK_REGNUM
+ };
+
+ enum
+ {
+ SIM_H8300_ARG_FIRST_REGNUM = SIM_H8300_R0_REGNUM, /* first reg in which an arg
+ may be passed */
+ SIM_H8300_ARG_LAST_REGNUM = SIM_H8300_R3_REGNUM, /* last reg in which an arg
+ may be passed */
+ SIM_H8300_FP_REGNUM = SIM_H8300_R6_REGNUM, /* Contain address of executing
+ stack frame */
+ SIM_H8300_SP_REGNUM = SIM_H8300_R7_REGNUM /* Contains address of top of stack */
+ };
+
+ enum
+ {
+ SIM_H8300_NUM_COMMON_REGS = 10,
+ SIM_H8300_S_NUM_REGS = 13,
+ SIM_H8300_NUM_REGS = 16
+ };
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_H8300_H */
diff --git a/contrib/gdb/include/gdb/sim-sh.h b/contrib/gdb/include/gdb/sim-sh.h
new file mode 100644
index 0000000..ec0d6276
--- /dev/null
+++ b/contrib/gdb/include/gdb/sim-sh.h
@@ -0,0 +1,161 @@
+/* This file defines the interface between the sh simulator and gdb.
+ Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public 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 (SIM_SH_H)
+#define SIM_SH_H
+
+#ifdef __cplusplus
+extern "C" { // }
+#endif
+
+/* The simulator makes use of the following register information. */
+
+enum
+{
+ SIM_SH_R0_REGNUM = 0,
+ SIM_SH_R1_REGNUM,
+ SIM_SH_R2_REGNUM,
+ SIM_SH_R3_REGNUM,
+ SIM_SH_R4_REGNUM,
+ SIM_SH_R5_REGNUM,
+ SIM_SH_R6_REGNUM,
+ SIM_SH_R7_REGNUM,
+ SIM_SH_R8_REGNUM,
+ SIM_SH_R9_REGNUM,
+ SIM_SH_R10_REGNUM,
+ SIM_SH_R11_REGNUM,
+ SIM_SH_R12_REGNUM,
+ SIM_SH_R13_REGNUM,
+ SIM_SH_R14_REGNUM,
+ SIM_SH_R15_REGNUM,
+ SIM_SH_PC_REGNUM,
+ SIM_SH_PR_REGNUM,
+ SIM_SH_GBR_REGNUM,
+ SIM_SH_VBR_REGNUM,
+ SIM_SH_MACH_REGNUM,
+ SIM_SH_MACL_REGNUM,
+ SIM_SH_SR_REGNUM,
+ SIM_SH_FPUL_REGNUM,
+ SIM_SH_FPSCR_REGNUM,
+ SIM_SH_FR0_REGNUM, /* FRn registers: sh3e / sh4 */
+ SIM_SH_FR1_REGNUM,
+ SIM_SH_FR2_REGNUM,
+ SIM_SH_FR3_REGNUM,
+ SIM_SH_FR4_REGNUM,
+ SIM_SH_FR5_REGNUM,
+ SIM_SH_FR6_REGNUM,
+ SIM_SH_FR7_REGNUM,
+ SIM_SH_FR8_REGNUM,
+ SIM_SH_FR9_REGNUM,
+ SIM_SH_FR10_REGNUM,
+ SIM_SH_FR11_REGNUM,
+ SIM_SH_FR12_REGNUM,
+ SIM_SH_FR13_REGNUM,
+ SIM_SH_FR14_REGNUM,
+ SIM_SH_FR15_REGNUM,
+ SIM_SH_SSR_REGNUM, /* sh3{,e,-dsp}, sh4 */
+ SIM_SH_SPC_REGNUM, /* sh3{,e,-dsp}, sh4 */
+ SIM_SH_R0_BANK0_REGNUM, /* SIM_SH_Rn_BANKm_REGNUM: sh3[e] / sh4 */
+ SIM_SH_R1_BANK0_REGNUM,
+ SIM_SH_R2_BANK0_REGNUM,
+ SIM_SH_R3_BANK0_REGNUM,
+ SIM_SH_R4_BANK0_REGNUM,
+ SIM_SH_R5_BANK0_REGNUM,
+ SIM_SH_R6_BANK0_REGNUM,
+ SIM_SH_R7_BANK0_REGNUM,
+ SIM_SH_R0_BANK1_REGNUM,
+ SIM_SH_R1_BANK1_REGNUM,
+ SIM_SH_R2_BANK1_REGNUM,
+ SIM_SH_R3_BANK1_REGNUM,
+ SIM_SH_R4_BANK1_REGNUM,
+ SIM_SH_R5_BANK1_REGNUM,
+ SIM_SH_R6_BANK1_REGNUM,
+ SIM_SH_R7_BANK1_REGNUM,
+ SIM_SH_XF0_REGNUM,
+ SIM_SH_XF1_REGNUM,
+ SIM_SH_XF2_REGNUM,
+ SIM_SH_XF3_REGNUM,
+ SIM_SH_XF4_REGNUM,
+ SIM_SH_XF5_REGNUM,
+ SIM_SH_XF6_REGNUM,
+ SIM_SH_XF7_REGNUM,
+ SIM_SH_XF8_REGNUM,
+ SIM_SH_XF9_REGNUM,
+ SIM_SH_XF10_REGNUM,
+ SIM_SH_XF11_REGNUM,
+ SIM_SH_XF12_REGNUM,
+ SIM_SH_XF13_REGNUM,
+ SIM_SH_XF14_REGNUM,
+ SIM_SH_XF15_REGNUM,
+ SIM_SH_SGR_REGNUM,
+ SIM_SH_DBR_REGNUM,
+ SIM_SH4_NUM_REGS, /* 77 */
+
+ /* sh[3]-dsp */
+ SIM_SH_DSR_REGNUM,
+ SIM_SH_A0G_REGNUM,
+ SIM_SH_A0_REGNUM,
+ SIM_SH_A1G_REGNUM,
+ SIM_SH_A1_REGNUM,
+ SIM_SH_M0_REGNUM,
+ SIM_SH_M1_REGNUM,
+ SIM_SH_X0_REGNUM,
+ SIM_SH_X1_REGNUM,
+ SIM_SH_Y0_REGNUM,
+ SIM_SH_Y1_REGNUM,
+ SIM_SH_MOD_REGNUM,
+ SIM_SH_RS_REGNUM,
+ SIM_SH_RE_REGNUM,
+ SIM_SH_R0_BANK_REGNUM,
+ SIM_SH_R1_BANK_REGNUM,
+ SIM_SH_R2_BANK_REGNUM,
+ SIM_SH_R3_BANK_REGNUM,
+ SIM_SH_R4_BANK_REGNUM,
+ SIM_SH_R5_BANK_REGNUM,
+ SIM_SH_R6_BANK_REGNUM,
+ SIM_SH_R7_BANK_REGNUM
+ /* 100..127: room for expansion. */
+};
+
+enum
+{
+ SIM_SH64_R0_REGNUM = 0,
+ SIM_SH64_SP_REGNUM = 15,
+ SIM_SH64_PC_REGNUM = 64,
+ SIM_SH64_SR_REGNUM = 65,
+ SIM_SH64_SSR_REGNUM = 66,
+ SIM_SH64_SPC_REGNUM = 67,
+ SIM_SH64_TR0_REGNUM = 68,
+ SIM_SH64_FPCSR_REGNUM = 76,
+ SIM_SH64_FR0_REGNUM = 77
+};
+
+enum
+{
+ SIM_SH64_NR_REGS = 141, /* total number of architectural registers */
+ SIM_SH64_NR_R_REGS = 64, /* number of general registers */
+ SIM_SH64_NR_TR_REGS = 8, /* number of target registers */
+ SIM_SH64_NR_FP_REGS = 64 /* number of floating point registers */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/gdb/include/gdbm.h b/contrib/gdb/include/gdbm.h
new file mode 100644
index 0000000..3ebc26d
--- /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 0000000..a99a229
--- /dev/null
+++ b/contrib/gdb/include/getopt.h
@@ -0,0 +1,144 @@
+/* Declarations for getopt.
+ Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 2000,
+ 2002 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
+
+ This program is free software; you can redistribute 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. */
+
+#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 -1, 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 defined (__STDC__) && __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 defined (__STDC__) && __STDC__
+/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
+ undefined, we haven't run the autoconf check so provide the
+ declaration without arguments. If it is 0, we checked and failed
+ to find the declaration so provide a fully prototyped one. If it
+ is 1, we found it so don't provide any declaration at all. */
+#if !HAVE_DECL_GETOPT
+#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in unistd.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
+#ifndef __cplusplus
+extern int getopt ();
+#endif /* __cplusplus */
+#endif
+#endif /* !HAVE_DECL_GETOPT */
+
+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 /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* getopt.h */
diff --git a/contrib/gdb/include/hashtab.h b/contrib/gdb/include/hashtab.h
new file mode 100644
index 0000000..f7bd4ae
--- /dev/null
+++ b/contrib/gdb/include/hashtab.h
@@ -0,0 +1,195 @@
+/* An expandable hash tables datatype.
+ Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Vladimir Makarov (vmakarov@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. */
+
+/* This package implements basic hash table functionality. It is possible
+ to search for an entry, create an entry and destroy an entry.
+
+ Elements in the table are generic pointers.
+
+ The size of the table is not fixed; if the occupancy of the table
+ grows too high the hash table will be expanded.
+
+ The abstract data implementation is based on generalized Algorithm D
+ from Knuth's book "The art of computer programming". Hash table is
+ expanded by creation of new hash table and transferring elements from
+ the old table to the new table. */
+
+#ifndef __HASHTAB_H__
+#define __HASHTAB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "ansidecl.h"
+
+#ifndef GTY
+#define GTY(X)
+#endif
+
+/* The type for a hash code. */
+typedef unsigned int hashval_t;
+
+/* Callback function pointer types. */
+
+/* Calculate hash of a table entry. */
+typedef hashval_t (*htab_hash) PARAMS ((const void *));
+
+/* Compare a table entry with a possible entry. The entry already in
+ the table always comes first, so the second element can be of a
+ different type (but in this case htab_find and htab_find_slot
+ cannot be used; instead the variants that accept a hash value
+ must be used). */
+typedef int (*htab_eq) PARAMS ((const void *, const void *));
+
+/* Cleanup function called whenever a live element is removed from
+ the hash table. */
+typedef void (*htab_del) PARAMS ((void *));
+
+/* Function called by htab_traverse for each live element. The first
+ arg is the slot of the element (which can be passed to htab_clear_slot
+ if desired), the second arg is the auxiliary pointer handed to
+ htab_traverse. Return 1 to continue scan, 0 to stop. */
+typedef int (*htab_trav) PARAMS ((void **, void *));
+
+/* Memory-allocation function, with the same functionality as calloc().
+ Iff it returns NULL, the hash table implementation will pass an error
+ code back to the user, so if your code doesn't handle errors,
+ best if you use xcalloc instead. */
+typedef PTR (*htab_alloc) PARAMS ((size_t, size_t));
+
+/* We also need a free() routine. */
+typedef void (*htab_free) PARAMS ((PTR));
+
+/* Memory allocation and deallocation; variants which take an extra
+ argument. */
+typedef PTR (*htab_alloc_with_arg) PARAMS ((void *, size_t, size_t));
+typedef void (*htab_free_with_arg) PARAMS ((void *, void *));
+
+/* Hash tables are of the following type. The structure
+ (implementation) of this type is not needed for using the hash
+ tables. All work with hash table should be executed only through
+ functions mentioned below. The size of this structure is subject to
+ change. */
+
+struct htab GTY(())
+{
+ /* Pointer to hash function. */
+ htab_hash hash_f;
+
+ /* Pointer to comparison function. */
+ htab_eq eq_f;
+
+ /* Pointer to cleanup function. */
+ htab_del del_f;
+
+ /* Table itself. */
+ PTR * GTY ((use_param (""), length ("%h.size"))) entries;
+
+ /* Current size (in entries) of the hash table */
+ size_t size;
+
+ /* Current number of elements including also deleted elements */
+ size_t n_elements;
+
+ /* Current number of deleted elements in the table */
+ size_t n_deleted;
+
+ /* The following member is used for debugging. Its value is number
+ of all calls of `htab_find_slot' for the hash table. */
+ unsigned int searches;
+
+ /* The following member is used for debugging. Its value is number
+ of collisions fixed for time of work with the hash table. */
+ unsigned int collisions;
+
+ /* Pointers to allocate/free functions. */
+ htab_alloc alloc_f;
+ htab_free free_f;
+
+ /* Alternate allocate/free functions, which take an extra argument. */
+ PTR GTY((skip (""))) alloc_arg;
+ htab_alloc_with_arg alloc_with_arg_f;
+ htab_free_with_arg free_with_arg_f;
+};
+
+typedef struct htab *htab_t;
+
+/* An enum saying whether we insert into the hash table or not. */
+enum insert_option {NO_INSERT, INSERT};
+
+/* The prototypes of the package functions. */
+
+extern htab_t htab_create_alloc PARAMS ((size_t, htab_hash,
+ htab_eq, htab_del,
+ htab_alloc, htab_free));
+
+extern htab_t htab_create_alloc_ex PARAMS ((size_t, htab_hash,
+ htab_eq, htab_del,
+ PTR, htab_alloc_with_arg,
+ htab_free_with_arg));
+
+/* Backward-compatibility functions. */
+extern htab_t htab_create PARAMS ((size_t, htab_hash, htab_eq, htab_del));
+extern htab_t htab_try_create PARAMS ((size_t, htab_hash, htab_eq, htab_del));
+
+extern void htab_set_functions_ex PARAMS ((htab_t, htab_hash,
+ htab_eq, htab_del,
+ PTR, htab_alloc_with_arg,
+ htab_free_with_arg));
+
+extern void htab_delete PARAMS ((htab_t));
+extern void htab_empty PARAMS ((htab_t));
+
+extern PTR htab_find PARAMS ((htab_t, const void *));
+extern PTR *htab_find_slot PARAMS ((htab_t, const void *,
+ enum insert_option));
+extern PTR htab_find_with_hash PARAMS ((htab_t, const void *,
+ hashval_t));
+extern PTR *htab_find_slot_with_hash PARAMS ((htab_t, const void *,
+ hashval_t,
+ enum insert_option));
+extern void htab_clear_slot PARAMS ((htab_t, void **));
+extern void htab_remove_elt PARAMS ((htab_t, void *));
+
+extern void htab_traverse PARAMS ((htab_t, htab_trav, void *));
+extern void htab_traverse_noresize PARAMS ((htab_t, htab_trav, void *));
+
+extern size_t htab_size PARAMS ((htab_t));
+extern size_t htab_elements PARAMS ((htab_t));
+extern double htab_collisions PARAMS ((htab_t));
+
+/* A hash function for pointers. */
+extern htab_hash htab_hash_pointer;
+
+/* An equality function for pointers. */
+extern htab_eq htab_eq_pointer;
+
+/* A hash function for null-terminated strings. */
+extern hashval_t htab_hash_string PARAMS ((const PTR));
+
+/* An iterative hash function for arbitrary data. */
+extern hashval_t iterative_hash PARAMS ((const PTR, size_t, hashval_t));
+/* Shorthand for hashing something with an intrinsic size. */
+#define iterative_hash_object(OB,INIT) iterative_hash (&OB, sizeof (OB), INIT)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __HASHTAB_H */
diff --git a/contrib/gdb/include/hp-symtab.h b/contrib/gdb/include/hp-symtab.h
new file mode 100644
index 0000000..6267d55
--- /dev/null
+++ b/contrib/gdb/include/hp-symtab.h
@@ -0,0 +1,1866 @@
+/* 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, 1995, 1998, 1999, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef HP_SYMTAB_INCLUDED
+#define HP_SYMTAB_INCLUDED
+
+/* General information:
+
+ This header file defines and describes only the data structures
+ necessary to read debug symbols produced by the HP C compiler,
+ HP ANSI C++ compiler, and HP FORTRAN 90 compiler using the
+ SOM object file format.
+ (For a full description of the debug format, ftp hpux-symtab.h from
+ jaguar.cs.utah.edu:/dist).
+
+ Additional notes (Rich Title)
+ This file is a reverse-engineered version of a file called
+ "symtab.h" which exists internal to HP's Computer Languages Organization
+ in /CLO/Components/DDE/obj/som/symtab.h. Because HP's version of
+ the file is copyrighted and not distributed, it is necessary for
+ GDB to use the reverse-engineered version that follows.
+ Work was done by Cygnus to reverse-engineer the C subset of symtab.h.
+ The WDB project has extended this to also contain the C++
+ symbol definitions, the F90 symbol definitions,
+ and the DOC (debugging-optimized-code) symbol definitions.
+ In some cases (the C++ symbol definitions)
+ I have added internal documentation here that
+ goes beyond what is supplied in HP's symtab.h. If we someday
+ unify these files again, the extra comments should be merged back
+ into HP's symtab.h.
+
+ -------------------------------------------------------------------
+
+ 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_FORTRAN,
+ HP_LANGUAGE_F77 = HP_LANGUAGE_FORTRAN,
+ HP_LANGUAGE_PASCAL,
+ HP_LANGUAGE_MODCAL,
+ HP_LANGUAGE_COBOL,
+ HP_LANGUAGE_BASIC,
+ HP_LANGUAGE_ADA,
+ HP_LANGUAGE_CPLUSPLUS,
+ HP_LANGUAGE_DMPASCAL
+};
+
+
+/* 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, /* 0 */
+ HP_TYPE_BOOLEAN, /* 1 */
+ HP_TYPE_CHAR, /* 2 */
+ HP_TYPE_INT, /* 3 */
+ HP_TYPE_UNSIGNED_INT, /* 4 */
+ HP_TYPE_REAL, /* 5 */
+ HP_TYPE_COMPLEX, /* 6 */
+ HP_TYPE_STRING200, /* 7 */
+ HP_TYPE_LONGSTRING200, /* 8 */
+ HP_TYPE_TEXT, /* 9 */
+ HP_TYPE_FLABEL, /* 10 */
+ HP_TYPE_FTN_STRING_SPEC, /* 11 */
+ HP_TYPE_MOD_STRING_SPEC, /* 12 */
+ HP_TYPE_PACKED_DECIMAL, /* 13 */
+ HP_TYPE_REAL_3000, /* 14 */
+ HP_TYPE_MOD_STRING_3000, /* 15 */
+ HP_TYPE_ANYPOINTER, /* 16 */
+ HP_TYPE_GLOBAL_ANYPOINTER, /* 17 */
+ HP_TYPE_LOCAL_ANYPOINTER, /* 18 */
+ HP_TYPE_COMPLEXS3000, /* 19 */
+ HP_TYPE_FTN_STRING_S300_COMPAT, /* 20 */
+ HP_TYPE_FTN_STRING_VAX_COMPAT, /* 21 */
+ HP_TYPE_BOOLEAN_S300_COMPAT, /* 22 */
+ HP_TYPE_BOOLEAN_VAX_COMPAT, /* 23 */
+ HP_TYPE_WIDE_CHAR, /* 24 */
+ HP_TYPE_LONG, /* 25 */
+ HP_TYPE_UNSIGNED_LONG, /* 26 */
+ HP_TYPE_DOUBLE, /* 27 */
+ HP_TYPE_TEMPLATE_ARG, /* 28 */
+ HP_TYPE_VOID /* 29 */
+};
+
+/* 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;
+
+/* Index into DOC (= "Debugging Optimized Code") line table. */
+#define LTNIL (-1)
+typedef int ltpointer;
+
+/* Index into context table. */
+#define CTXTNIL (-1)
+typedef int ctxtpointer;
+
+/* 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_DYN_ARRAY_DESC,
+ DNTT_TYPE_DESC_SUBRANGE,
+ DNTT_TYPE_BEGIN_EXT,
+ DNTT_TYPE_INLN,
+ DNTT_TYPE_INLN_LIST,
+ DNTT_TYPE_ALIAS,
+ DNTT_TYPE_DOC_FUNCTION,
+ DNTT_TYPE_DOC_MEMFUNC,
+ 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; /* DNTT_TYPE_SRCFILE */
+ 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. A module indicates a compilation unit
+ for name-scoping purposes; in that regard there should be
+ a 1-1 correspondence between GDB "symtab"'s and MODULE symbol records.
+
+ 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; /* DNTT_TYPE_MODULE */
+ unsigned int unused: 21;
+ vtpointer name;
+ vtpointer alias;
+ dnttpointer unused2;
+ sltpointer address;
+};
+
+/* DNTT_TYPE_FUNCTION,
+ DNTT_TYPE_ENTRY,
+ DNTT_TYPE_BLOCKDATA,
+ DNTT_TYPE_MEMFUNC:
+
+ 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.
+ A DNTT_TYPE_BLOCKDATA symbol is emitted ...?
+ A DNTT_TYPE_MEMFUNC symbol is emitted for inlined member functions (C++).
+
+ Each of 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 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; /* DNTT_TYPE_FUNCTION,
+ DNTT_TYPE_ENTRY,
+ DNTT_TYPE_BLOCKDATA
+ or DNTT_TYPE_MEMFUNC */
+ 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, DNTT_TYPE_WITH,
+ DNTT_TYPE_COMMON, DNTT_TYPE_BEGIN, and DNTT_TYPE_CLASS_SCOPE symbols.
+
+ ENDKIND describes what type of scope the DNTT_TYPE_END is closing
+ (one of the above 6 kinds).
+
+ 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 doc_ranges: 1;
+ unsigned int misc_kind: 1;
+ unsigned int unused: 14;
+ vtpointer name;
+ CORE_ADDR 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 unused1: 1;
+ unsigned int thread_specific: 1;
+ unsigned int unused2: 14;
+ 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 location_type: 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.
+ Also they are associated with C++ "class" tags, which implicitly have
+ the same name as the class type.
+
+ 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; /* DNTT_TYPE_TYPEDEF or
+ DNTT_TYPE_TAGDEF. */
+ unsigned int global: 1;
+ unsigned int typeinfo: 1;
+ unsigned int unused: 19;
+ vtpointer name;
+ dnttpointer type; /* Underlying type, which for TAGDEF's may be
+ DNTT_TYPE_STRUCT, DNTT_TYPE_UNION,
+ DNTT_TYPE_ENUM, or DNTT_TYPE_CLASS.
+ For TYPEDEF's other underlying types
+ are also possible. */
+};
+
+/* 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
+
+ Used to describe PASCAL "set" type.
+
+ 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
+
+ Used to describe subrange type.
+
+ 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
+ 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
+
+ Used to describe an array type.
+
+ 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
+ or C++ class.
+
+ 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_FUNCTYPE
+
+ I think this is used to describe a function type (e.g., would
+ be emitted as part of a function-pointer description).
+
+ 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 emitted by C++ to indicate "with" scoping semantics.
+ (Probably also emitted by PASCAL to support "with"...).
+
+ C++ example: Say "memfunc" is a method of class "c", and say
+ "m" is a data member of class "c". Then from within "memfunc",
+ it is legal to reference "m" directly (e.g. you don't have to
+ say "this->m". The symbol table indicates
+ this by emitting a DNTT_TYPE_WITH symbol within the function "memfunc",
+ pointing to the type symbol for class "c".
+
+ In GDB, this symbol record is unnecessary,
+ because GDB's symbol lookup algorithm
+ infers the "with" semantics when it sees a "this" argument to the member
+ function. So GDB can safely ignore the DNTT_TYPE_WITH record.
+
+ A DNTT_TYPE_WITH has a matching DNTT_TYPE_END symbol. */
+
+struct dntt_type_with
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_WITH */
+ unsigned int addrtype: 2; /* 0 => STATTYPE */
+ /* 1 => DYNTYPE */
+ /* 2 => REGTYPE */
+ unsigned int indirect: 1; /* 1 => pointer to object */
+ unsigned int longaddr: 1; /* 1 => in long pointer space */
+ unsigned int nestlevel: 6; /* # of nesting levels back */
+ unsigned int doc_ranges: 1; /* 1 => location is range list */
+ unsigned int unused: 10;
+ long location; /* where stored (allocated) */
+ sltpointer address;
+ dnttpointer type; /* type of with expression */
+ vtpointer name; /* name of with expression */
+ unsigned long offset; /* byte offset from location */
+};
+
+/* DNTT_TYPE_COMMON is unsupported by GDB. */
+/* A DNTT_TYPE_COMMON symbol must have a matching DNTT_TYPE_END symbol */
+
+/* DNTT_TYPE_COBSTRUCT is unsupported by GDB. */
+/* DNTT_TYPE_XREF is unsupported by GDB. */
+/* DNTT_TYPE_SA is unsupported by GDB. */
+/* DNTT_TYPE_MACRO is unsupported by GDB */
+
+/* DNTT_TYPE_BLOCKDATA has the same structure as DNTT_TYPE_FUNCTION */
+
+/* The following are the C++ specific SOM records */
+
+/* The purpose of the DNTT_TYPE_CLASS_SCOPE is to bracket C++ methods
+ and indicate the method name belongs in the "class scope" rather
+ than in the module they are being defined in. For example:
+
+ class c {
+ ...
+ void memfunc(); // member function
+ };
+
+ void c::memfunc() // definition of class c's "memfunc"
+ {
+ ...
+ }
+
+ main()
+ {
+ ...
+ }
+
+ In the above, the name "memfunc" is not directly visible from "main".
+ I.e., you have to say "break c::memfunc".
+ If it were a normal function (not a method), it would be visible
+ via the simple "break memfunc". Since "memfunc" otherwise looks
+ like a normal FUNCTION in the symbol table, the bracketing
+ CLASS_SCOPE is what is used to indicate it is really a method.
+
+
+ A DNTT_TYPE_CLASS_SCOPE symbol must have a matching DNTT_TYPE_END symbol. */
+
+struct dntt_type_class_scope
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_CLASS_SCOPE. */
+ unsigned int unused: 21;
+ sltpointer address ; /* Pointer to SLT entry. */
+ dnttpointer type ; /* Pointer to class type DNTT. */
+};
+
+/* C++ reference parameter.
+ The structure of this record is the same as DNTT_TYPE_POINTER -
+ refer to struct dntt_type_pointer. */
+
+/* The next two describe C++ pointer-to-data-member type, and
+ pointer-to-member-function type, respectively.
+ DNTT_TYPE_PTRMEM and DNTT_TYPE_PTRMEMFUNC have the same structure. */
+
+struct dntt_type_ptrmem
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_PTRMEM. */
+ unsigned int unused: 21;
+ dnttpointer pointsto ; /* Pointer to class DNTT. */
+ dnttpointer memtype ; /* Type of member. */
+};
+
+struct dntt_type_ptrmemfunc
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_PTRMEMFUNC. */
+ unsigned int unused: 21;
+ dnttpointer pointsto ; /* Pointer to class DNTT. */
+ dnttpointer memtype ; /* Type of member. */
+};
+
+/* The DNTT_TYPE_CLASS symbol is emitted to describe a class type.
+ "memberlist" points to a chained list of FIELD or GENFIELD records
+ indicating the class members. "parentlist" points to a chained list
+ of INHERITANCE records indicating classes from which we inherit
+ fields. */
+
+struct dntt_type_class
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_CLASS. */
+ unsigned int abstract: 1; /* Is this an abstract class? */
+ unsigned int class_decl: 2; /* 0=class,1=union,2=struct. */
+ unsigned int expansion: 1; /* 1=template expansion. */
+ unsigned int unused: 17;
+ dnttpointer memberlist ; /* Ptr to chain of [GEN]FIELDs. */
+ unsigned long vtbl_loc ; /* Offset in obj of ptr to vtbl. */
+ dnttpointer parentlist ; /* Ptr to K_INHERITANCE list. */
+ unsigned long bitlength ; /* Total at this level. */
+ dnttpointer identlist ; /* Ptr to chain of class ident's. */
+ dnttpointer friendlist ; /* Ptr to K_FRIEND list. */
+ dnttpointer templateptr ; /* Ptr to template. */
+ dnttpointer nextexp ; /* Ptr to next expansion. */
+};
+
+/* Class members are indicated via either the FIELD record (for
+ data members, same as for C struct fields), or by the GENFIELD record
+ (for member functions). */
+
+struct dntt_type_genfield
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_GENFIELD. */
+ unsigned int visibility: 2; /* Pub = 0, prot = 1, priv = 2. */
+ unsigned int a_union: 1; /* 1 => anonymous union member. */
+ unsigned int unused: 18;
+ dnttpointer field ; /* Pointer to field or qualifier. */
+ dnttpointer nextfield ; /* Pointer to next field. */
+};
+
+/* C++ virtual functions. */
+
+struct dntt_type_vfunc
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_VFUNC */
+ unsigned int pure: 1; /* pure virtual function ? */
+ unsigned int unused: 20;
+ dnttpointer funcptr ; /* points to FUNCTION symbol */
+ unsigned long vtbl_offset ; /* offset into vtbl for virtual */
+};
+
+/* Not precisely sure what this is intended for - DDE ignores it. */
+
+struct dntt_type_memaccess
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_MEMACCESS */
+ unsigned int unused: 21;
+ dnttpointer classptr ; /* pointer to base class */
+ dnttpointer field ; /* pointer field */
+};
+
+/* The DNTT_TYPE_INHERITANCE record describes derived classes.
+ In particular, the "parentlist" field of the CLASS record points
+ to a list of INHERITANCE records for classes from which we
+ inherit members. */
+
+struct dntt_type_inheritance
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_INHERITANCE */
+ unsigned int Virtual: 1; /* virtual base class ? */
+ unsigned int visibility: 2; /* pub = 0, prot = 1, priv = 2 */
+ unsigned int unused: 18;
+ dnttpointer classname ; /* first parent class, if any */
+ unsigned long offset ; /* offset to start of base class */
+ dnttpointer next ; /* pointer to next K_INHERITANCE */
+ unsigned long future[2] ; /* padding to 3-word block end */
+};
+
+/* C++ "friend" classes ... */
+
+struct dntt_type_friend_class
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_FRIEND_CLASS */
+ unsigned int unused: 21;
+ dnttpointer classptr ; /* pointer to class DNTT */
+ dnttpointer next ; /* next DNTT_FRIEND */
+};
+
+struct dntt_type_friend_func
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_FRIEND_FUNC */
+ unsigned int unused: 21;
+ dnttpointer funcptr ; /* pointer to function */
+ dnttpointer classptr ; /* pointer to class DNTT */
+ dnttpointer next ; /* next DNTT_FRIEND */
+ unsigned long future[2] ; /* padding to 3-word block end */
+};
+
+/* DDE appears to ignore the DNTT_TYPE_MODIFIER record.
+ It could perhaps be used to give better "ptype" output in GDB;
+ otherwise it is probably safe for GDB to ignore it also. */
+
+struct dntt_type_modifier
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_MODIFIER */
+ unsigned int m_const: 1; /* const */
+ unsigned int m_static: 1; /* static */
+ unsigned int m_void: 1; /* void */
+ unsigned int m_volatile: 1; /* volatile */
+ unsigned int m_duplicate: 1; /* duplicate */
+ unsigned int unused: 16;
+ dnttpointer type ; /* subtype */
+ unsigned long future ; /* padding to 3-word block end */
+};
+
+/* I'm not sure what this was intended for - DDE ignores it. */
+
+struct dntt_type_object_id
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_OBJECT_ID */
+ unsigned int indirect: 1; /* Is object_ident addr of addr? */
+ unsigned int unused: 20;
+ unsigned long object_ident ; /* object identifier */
+ unsigned long offset ; /* offset to start of base class */
+ dnttpointer next ; /* pointer to next K_OBJECT_ID */
+ unsigned long segoffset ; /* for linker fixup */
+ unsigned long future ; /* padding to 3-word block end */
+};
+
+/* No separate dntt_type_memfunc; same as dntt_type_func */
+
+/* Symbol records to support templates. These only get used
+ in DDE's "describe" output (like GDB's "ptype"). */
+
+/* The TEMPLATE record is the header for a template-class.
+ Like the CLASS record, a TEMPLATE record has a memberlist that
+ points to a list of template members. It also has an arglist
+ pointing to a list of TEMPLATE_ARG records. */
+
+struct dntt_type_template
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_TEMPLATE */
+ unsigned int abstract: 1; /* is this an abstract class? */
+ unsigned int class_decl: 2; /* 0=class,1=union,2=struct */
+ unsigned int unused: 18;
+ dnttpointer memberlist ; /* ptr to chain of K_[GEN]FIELDs */
+ long unused2 ; /* offset in obj of ptr to vtbl */
+ dnttpointer parentlist ; /* ptr to K_INHERITANCE list */
+ unsigned long bitlength ; /* total at this level */
+ dnttpointer identlist ; /* ptr to chain of class ident's */
+ dnttpointer friendlist ; /* ptr to K_FRIEND list */
+ dnttpointer arglist ; /* ptr to argument list */
+ dnttpointer expansions ; /* ptr to expansion list */
+};
+
+/* Template-class arguments are a list of TEMPL_ARG records
+ chained together. The "name" field is the name of the formal.
+ E.g.:
+
+ template <class T> class q { ... };
+
+ Then "T" is the name of the formal argument. */
+
+struct dntt_type_templ_arg
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_TEMPL_ARG */
+ unsigned int usagetype: 1; /* 0 type-name 1 expression */
+ unsigned int unused: 20;
+ vtpointer name ; /* name of argument */
+ dnttpointer type ; /* for non type arguments */
+ dnttpointer nextarg ; /* Next argument if any */
+ long future[2] ; /* padding to 3-word block end */
+};
+
+/* FUNC_TEMPLATE records are sort of like FUNCTION, but are emitted
+ for template member functions. E.g.,
+
+ template <class T> class q
+ {
+ ...
+ void f();
+ ...
+ };
+
+ Within the list of FIELDs/GENFIELDs defining the member list
+ of the template "q", "f" would appear as a FUNC_TEMPLATE.
+ We'll also see instances of FUNCTION "f" records for each
+ instantiation of the template. */
+
+struct dntt_type_func_template
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_FUNC_TEMPLATE */
+ unsigned int public: 1; /* 1 => globally visible */
+ unsigned int language: 4; /* type of language */
+ unsigned int level: 5; /* nesting level (top level = 0)*/
+ unsigned int optimize: 2; /* level of optimization */
+ unsigned int varargs: 1; /* ellipses. Pascal/800 later */
+ unsigned int info: 4; /* lang-specific stuff; F_xxxx */
+ unsigned int inlined: 1;
+ unsigned int localloc: 1; /* 0 at top, 1 at end of block */
+ unsigned int unused: 2;
+ vtpointer name ; /* name of function */
+ vtpointer alias ; /* alternate name, if any */
+ dnttpointer firstparam ; /* first FPARAM, if any */
+ dnttpointer retval ; /* return type, if any */
+ dnttpointer arglist ; /* ptr to argument list */
+};
+
+/* LINK is apparently intended to link together function template
+ definitions with their instantiations. However, it is not clear
+ why this would be needed, except to provide the information on
+ a "ptype" command. And as far as I can tell, aCC does not
+ generate this record. */
+
+struct dntt_type_link
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_LINK */
+ unsigned int linkKind: 4; /* always LINK_UNKNOWN */
+ unsigned int unused: 17;
+ long future1 ; /* expansion */
+ dnttpointer ptr1 ; /* link from template */
+ dnttpointer ptr2 ; /* to expansion */
+ long future[2] ; /* padding to 3-word block end */
+};
+
+/* end of C++ specific SOM's. */
+
+/* DNTT_TYPE_DYN_ARRAY_DESC is unused by GDB */
+/* DNTT_TYPE_DESC_SUBRANGE is unused by GDB */
+/* DNTT_TYPE_BEGIN_EXT is unused by GDB */
+/* DNTT_TYPE_INLN is unused by GDB */
+/* DNTT_TYPE_INLN_LIST is unused by GDB */
+/* DNTT_TYPE_ALIAS is unused by GDB */
+
+struct dntt_type_doc_function
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* K_DOC_FUNCTION or */
+ /* K_DOC_MEMFUNC */
+ unsigned int global: 1; /* 1 => globally visible */
+ unsigned int language: 4; /* type of language */
+ unsigned int level: 5; /* nesting level (top level = 0)*/
+ unsigned int optimize: 2; /* level of optimization */
+ unsigned int varargs: 1; /* ellipses. Pascal/800 later */
+ unsigned int info: 4; /* lang-specific stuff; F_xxxx */
+ unsigned int inlined: 1;
+ unsigned int localloc: 1; /* 0 at top, 1 at end of block */
+ unsigned int expansion: 1; /* 1 = function expansion */
+ unsigned int doc_clone: 1;
+ vtpointer name; /* name of function */
+ vtpointer alias; /* alternate name, if any */
+ dnttpointer firstparam; /* first FPARAM, if any */
+ sltpointer address; /* code and text locations */
+ CORE_ADDR entryaddr; /* address of entry point */
+ dnttpointer retval; /* return type, if any */
+ CORE_ADDR lowaddr; /* lowest address of function */
+ CORE_ADDR hiaddr; /* highest address of function */
+ dnttpointer inline_list; /* pointer to first inline */
+ ltpointer lt_offset; /* start of frag/cp line table */
+ ctxtpointer ctxt_offset; /* start of context table for this routine */
+};
+
+/* DNTT_TYPE_DOC_MEMFUNC 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).
+ This is a union of the above 60 or so structure definitions. */
+
+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_with dwith;
+ struct dntt_type_function dblockdata;
+ struct dntt_type_class_scope dclass_scope;
+ struct dntt_type_pointer dreference;
+ struct dntt_type_ptrmem dptrmem;
+ struct dntt_type_ptrmemfunc dptrmemfunc;
+ struct dntt_type_class dclass;
+ struct dntt_type_genfield dgenfield;
+ struct dntt_type_vfunc dvfunc;
+ struct dntt_type_memaccess dmemaccess;
+ struct dntt_type_inheritance dinheritance;
+ struct dntt_type_friend_class dfriend_class;
+ struct dntt_type_friend_func dfriend_func;
+ struct dntt_type_modifier dmodifier;
+ struct dntt_type_object_id dobject_id;
+ struct dntt_type_template dtemplate;
+ struct dntt_type_templ_arg dtempl_arg;
+ struct dntt_type_func_template dfunc_template;
+ struct dntt_type_link dlink;
+ struct dntt_type_doc_function ddocfunc;
+ 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,
+ SLT_CLASS_SCOPE,
+ SLT_INLN,
+ SLT_NORMAL_OFFSET,
+};
+
+/* 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;
+};
+
+struct slt_normal_off
+{
+ unsigned int sltdesc: 4;
+ unsigned int offset: 6;
+ unsigned int line: 22;
+ 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_normal_off snormoff;
+ struct slt_special sspec;
+ struct slt_assist sasst;
+ struct slt_generic sgeneric;
+};
+
+/* $LINES$ declarations
+ This is the line table used for optimized code, which is only present
+ in the new $PROGRAM_INFO$ debug space. */
+
+#define DST_LN_ESCAPE_FLAG1 15
+#define DST_LN_ESCAPE_FLAG2 14
+#define DST_LN_CTX_SPEC1 13
+#define DST_LN_CTX_SPEC2 12
+
+/* Escape function codes: */
+
+typedef enum
+{
+ dst_ln_pad, /* pad byte */
+ dst_ln_escape_1, /* reserved */
+ dst_ln_dpc1_dln1, /* 1 byte line delta, 1 byte pc delta */
+ dst_ln_dpc2_dln2, /* 2 bytes line delta, 2 bytes pc delta */
+ dst_ln_pc4_ln4, /* 4 bytes ABSOLUTE line number, 4 bytes ABSOLUTE pc */
+ dst_ln_dpc0_dln1, /* 1 byte line delta, pc delta = 0 */
+ dst_ln_ln_off_1, /* statement escape, stmt # = 1 (2nd stmt on line) */
+ dst_ln_ln_off, /* statement escape, stmt # = next byte */
+ dst_ln_entry, /* entry escape, next byte is entry number */
+ dst_ln_exit, /* exit escape */
+ dst_ln_stmt_end, /* gap escape, 4 bytes pc delta */
+ dst_ln_stmt_cp, /* current stmt is a critical point */
+ dst_ln_escape_12, /* reserved */
+ dst_ln_escape_13, /* this is an exception site record */
+ dst_ln_nxt_byte, /* next byte contains the real escape code */
+ dst_ln_end, /* end escape, final entry follows */
+ dst_ln_escape1_END_OF_ENUM
+}
+dst_ln_escape1_t;
+
+typedef enum
+{
+ dst_ln_ctx_1, /* next byte describes context switch with 5-bit */
+ /* index into the image table and 3-bit run length. */
+ /* If run length is 0, end with another cxt specifier or ctx_end */
+ dst_ln_ctx_2, /* next 2 bytes switch context: 13 bit index, 3 bit run length */
+ dst_ln_ctx_4, /* next 4 bytes switch context: 29 bit index, 3 bit run length */
+ dst_ln_ctx_end, /* end current context */
+ dst_ln_col_run_1, /* next byte is column position of start of next statement, */
+ /* following byte is length of statement */
+ dst_ln_col_run_2, /* next 2 bytes is column position of start of next statement, */
+ /* following 2 bytes is length of statement */
+ dst_ln_init_base1, /* next 4 bytes are absolute PC, followed by 1 byte of line number */
+ dst_ln_init_base2, /* next 4 bytes are absolute PC, followed by 2 bytes of line number */
+ dst_ln_init_base3, /* next 4 bytes are absolute PC, followed by 3 bytes of line number */
+ dst_ln_escape2_END_OF_ENUM
+}
+dst_ln_escape2_t;
+
+typedef union
+{
+ struct
+ {
+ unsigned int pc_delta : 4; /* 4 bit pc delta */
+ int ln_delta : 4; /* 4 bit line number delta */
+ }
+ delta;
+
+ struct
+ {
+ unsigned int esc_flag : 4; /* alias for pc_delta */
+ unsigned int esc_code : 4; /* escape function code (dst_ln_escape1_t, or ...2_t */
+ }
+ esc;
+
+ struct
+ {
+ unsigned int esc_flag : 4; /* dst_ln_ctx_spec1, or dst_ln_ctx_spec2 */
+ unsigned int run_length : 2;
+ unsigned int ctx_index : 2; /* ...spec2 contains index; ...spec1, index - 4 */
+ }
+ ctx_spec;
+
+ char sdata; /* signed data byte */
+ unsigned char udata; /* unsigned data byte */
+}
+dst_ln_entry_t,
+ * dst_ln_entry_ptr_t;
+
+/* Warning: although the above union occupies only 1 byte the compiler treats
+ it as having size 2 (the minimum size of a struct). Therefore a sequence of
+ dst_ln_entry_t's cannot be described as an array, and walking through such a
+ sequence requires convoluted code such as
+ ln_ptr = (dst_ln_entry_ptr_t) (char*) ln_ptr + 1
+ We regret the inconvenience. */
+
+/* Structure for interpreting the byte following a dst_ln_ctx1 entry. */
+typedef struct
+{
+ unsigned int ctx1_index : 5; /* 5 bit index into context table */
+ unsigned int ctx1_run_length : 3; /* 3 bit run length */
+} dst_ln_ctx1_t,
+ *dst_ln_ctx1_ptr_t;
+
+/* Structure for interpreting the bytes following a dst_ln_ctx2 entry. */
+typedef struct
+{
+ unsigned int ctx2_index : 13; /* 13 bit index into context table */
+ unsigned int ctx2_run_length : 3; /* 3 bit run length */
+} dst_ln_ctx2_t,
+ *dst_ln_ctx2_ptr_t;
+
+/* Structure for interpreting the bytes following a dst_ln_ctx4 entry. */
+typedef struct
+{
+ unsigned int ctx4_index : 29; /* 29 bit index into context table */
+ unsigned int ctx4_run_length : 3; /* 3 bit run length */
+} dst_ln_ctx4_t,
+ *dst_ln_ctx4_ptr_t;
+
+
+/* PXDB definitions.
+
+ PXDB is a post-processor which takes the executable file
+ and massages the debug information so that the debugger may
+ start up and run more efficiently. Some of the tasks
+ performed by PXDB are:
+
+ o Remove duplicate global type and variable information
+ from the GNTT,
+
+ o Append the GNTT onto the end of the LNTT and place both
+ back in the LNTT section,
+
+ o Build quick look-up tables (description follows) for
+ files, procedures, modules, and paragraphs (for Cobol),
+ placing these in the GNTT section,
+
+ o Reconstruct the header appearing in the header section
+ to access this information.
+
+ The "quick look-up" tables are in the $GNTT$ sub-space, in
+ the following order:
+
+ Procedures -sorted by address
+ Source files -sorted by address (of the
+ generated code from routines)
+ Modules -sorted by address
+ Classes -<unsorted?>
+ Address Alias -sorted by index <?>
+ Object IDs -sorted by object identifier
+
+ Most quick entries have (0-based) indices into the LNTT tables to
+ the full entries for the item it describes.
+
+ The post-PXDB header is in the $HEADER$ sub-space. Alas, it
+ occurs in different forms, depending on the optimization level
+ in the compilation step and whether PXDB was run or not. The
+ worst part is the forms aren't self-describing, so we'll have
+ to grovel in the bits to figure out what kind we're looking at
+ (see hp_get_header in hp-psymtab-read.c). */
+
+/* PXDB versions. */
+
+#define PXDB_VERSION_CPLUSPLUS 1
+#define PXDB_VERSION_7_4 2
+#define PXDB_VERSION_CPP_30 3
+#define PXDB_VERSION_DDE_3_2A 4
+#define PXDB_VERSION_DDE_3_2 5
+#define PXDB_VERSION_DDE_4_0 6
+
+#define PXDB_VERSION_2_1 1
+
+/* Header version for the case that there is no DOC info
+ but the executable has been processed by pxdb (the easy
+ case, from "cc -g"). */
+
+typedef struct PXDB_struct
+{
+ int pd_entries; /* # of entries in function look-up table */
+ int fd_entries; /* # of entries in file look-up table */
+ int md_entries; /* # of entries in module look-up table */
+ unsigned int pxdbed : 1; /* 1 => file has been preprocessed */
+ unsigned int bighdr : 1; /* 1 => this header contains 'time' word */
+ unsigned int sa_header : 1;/* 1 => created by SA version of pxdb */
+ /* used for version check in xdb */
+ unsigned int inlined: 1; /* one or more functions have been inlined */
+ unsigned int spare:12;
+ short version; /* pxdb header version */
+ int globals; /* index into the DNTT where GNTT begins */
+ unsigned int time; /* modify time of file before being pxdbed */
+ int pg_entries; /* # of entries in label look-up table */
+ int functions; /* actual number of functions */
+ int files; /* actual number of files */
+ int cd_entries; /* # of entries in class look-up table */
+ int aa_entries; /* # of entries in addr alias look-up table */
+ int oi_entries; /* # of entries in object id look-up table */
+} PXDB_header, *PXDB_header_ptr;
+
+/* Header version for the case that there is no DOC info and the
+ executable has NOT been processed by pxdb. */
+
+typedef struct XDB_header_struct
+{
+ long gntt_length;
+ long lntt_length;
+ long slt_length;
+ long vt_length;
+ long xt_length;
+} XDB_header;
+
+/* Header version for the case that there is DOC info and the
+ executable has been processed by pxdb. */
+
+typedef struct DOC_info_PXDB_header_struct
+{
+ unsigned int xdb_header: 1; /* bit set if this is post-3.1 xdb */
+ unsigned int doc_header: 1; /* bit set if this is doc-style header */
+ unsigned int version: 8; /* version of pxdb see defines
+ PXDB_VERSION_* in this file. */
+ unsigned int reserved_for_flags: 16;/* for future use; -- must be
+ set to zero. */
+ unsigned int has_aux_pd_table: 1; /* $GNTT$ has aux PD table */
+ unsigned int has_expr_table: 1; /* space has $EXPR$ */
+ unsigned int has_range_table: 1; /* space has $RANGE$ */
+ unsigned int has_context_table: 1; /* space has $SRC_CTXT$ */
+ unsigned int has_lines_table: 1; /* space contains a $LINES$
+ subspace for line tables. */
+ unsigned int has_lt_offset_map: 1; /* space contains an lt_offset
+ subspace for line table mapping. */
+ /* The following fields are the same as those in the PXDB_header in $DEBUG$ */
+ int pd_entries; /* # of entries in function look-up table */
+ int fd_entries; /* # of entries in file look-up table */
+ int md_entries; /* # of entries in module look-up table */
+ unsigned int pxdbed : 1; /* 1 => file has been preprocessed */
+ unsigned int bighdr : 1; /* 1 => this header contains 'time' word */
+ unsigned int sa_header : 1;/* 1 => created by SA version of pxdb */
+ /* used for version check in xdb */
+ unsigned int inlined: 1; /* one or more functions have been inlined */
+ unsigned int spare : 28;
+ int globals; /* index into the DNTT where GNTT begins */
+ unsigned int time; /* modify time of file before being pxdbed */
+ int pg_entries; /* # of entries in label look-up table */
+ int functions; /* actual number of functions */
+ int files; /* actual number of files */
+ int cd_entries; /* # of entries in class look-up table */
+ int aa_entries; /* # of entries in addr alias look-up table */
+ int oi_entries; /* # of entries in object id look-up table */
+} DOC_info_PXDB_header;
+
+/* Header version for the case that there is DOC info and the
+ executable has NOT been processed by pxdb. */
+
+typedef struct DOC_info_header_struct
+{
+ unsigned int xdb_header: 1; /* bit set if this is post-3.1 xdb */
+ unsigned int doc_header: 1; /* bit set if this is doc-style header*/
+ unsigned int version: 8; /* version of debug/header
+ format. For 10.0 the value
+ will be 1. For "Davis" the value is 2. */
+ unsigned int reserved_for_flags: 18; /* for future use; -- must be set to zero. */
+ unsigned int has_range_table: 1; /* space contains a $RANGE$ subspace for variable ranges. */
+ unsigned int has_context_table: 1; /* space contains a $CTXT$ subspace for context/inline table. */
+ unsigned int has_lines_table: 1; /* space contains a $LINES$ subspace for line tables. */
+ unsigned int has_lt_offset_map: 1; /* space contains an lt_offset subspace for line table mapping. */
+
+ long gntt_length; /* same as old header */
+ long lntt_length; /* same as old header */
+ long slt_length; /* same as old header */
+ long vt_length; /* same as old header */
+ long xt_length; /* same as old header */
+ long ctxt_length; /* present only if version >= 2 */
+ long range_length; /* present only if version >= 2 */
+ long expr_length; /* present only if version >= 2 */
+
+} DOC_info_header;
+
+typedef union GenericDebugHeader_union
+{
+ PXDB_header no_doc;
+ DOC_info_PXDB_header doc;
+ XDB_header no_pxdb_no_doc;
+ DOC_info_header no_pxdb_doc;
+} GenericDebugHeader;
+
+
+/* Procedure Descriptor:
+ An element of the procedure quick look-up table. */
+
+typedef struct quick_procedure
+{
+ long isym; /* 0-based index of first symbol
+ for procedure in $LNTT$,
+ i.e. the procedure itself. */
+ CORE_ADDR adrStart; /* memory adr of start of proc */
+ CORE_ADDR adrEnd; /* memory adr of end of proc */
+ char *sbAlias; /* alias name of procedure */
+ char *sbProc; /* real name of procedure */
+ CORE_ADDR adrBp; /* address of entry breakpoint */
+ CORE_ADDR adrExitBp; /* address of exit breakpoint */
+ int icd; /* member of this class (index) */
+ unsigned int ipd; /* index of template for this */
+ /* function (index) */
+ unsigned int unused: 5;
+ unsigned int no_lt_offset: 1;/* no entry in lt_offset table */
+ unsigned int fTemplate: 1; /* function template */
+ unsigned int fExpansion: 1; /* function expansion */
+ unsigned int linked : 1; /* linked with other expansions */
+ unsigned int duplicate: 1; /* clone of another procedure */
+ unsigned int overloaded:1; /* overloaded function */
+ unsigned int member: 1; /* class member function */
+ unsigned int constructor:1; /* constructor function */
+ unsigned int destructor:1; /* destructor function */
+ unsigned int Static: 1; /* static function */
+ unsigned int Virtual: 1; /* virtual function */
+ unsigned int constant: 1; /* constant function */
+ unsigned int pure: 1; /* pure (virtual) function */
+ unsigned int language: 4; /* procedure's language */
+ unsigned int inlined: 1; /* function has been inlined */
+ unsigned int Operator: 1; /* operator function */
+ unsigned int stub: 1; /* bodyless function */
+ unsigned int optimize: 2; /* optimization level */
+ unsigned int level: 5; /* nesting level (top=0) */
+} quick_procedure_entry, *quick_procedure_entry_ptr;
+
+/* Source File Descriptor:
+ An element of the source file quick look-up table. */
+
+typedef struct quick_source
+{
+ long isym; /* 0-based index in $LNTT$ of
+ first symbol for this file. */
+ CORE_ADDR adrStart; /* mem adr of start of file's code */
+ CORE_ADDR adrEnd; /* mem adr of end of file's code */
+ char *sbFile; /* name of source file */
+ unsigned int fHasDecl: 1; /* do we have a .d file? */
+ unsigned int fWarned: 1; /* have warned about age problems? */
+ unsigned int fSrcfile: 1; /* 0 => include 1=> source */
+ unsigned short ilnMac; /* lines in file (0 if don't know) */
+ int ipd; /* 0-based index of first procedure
+ in this file, in the quick
+ look-up table of procedures. */
+ unsigned int *rgLn; /* line pointer array, if any */
+} quick_file_entry, *quick_file_entry_ptr;
+
+/* Module Descriptor:
+ An element of the module quick reference table. */
+
+typedef struct quick_module
+{
+ long isym; /* 0-based index of first
+ symbol for module. */
+ CORE_ADDR adrStart; /* adr of start of mod. */
+ CORE_ADDR adrEnd; /* adr of end of mod. */
+ char *sbAlias; /* alias name of module */
+ char *sbMod; /* real name of module */
+ unsigned int imports: 1; /* module have any imports? */
+ unsigned int vars_in_front: 1; /* module globals in front? */
+ unsigned int vars_in_gaps: 1; /* module globals in gaps? */
+ unsigned int language: 4; /* type of language */
+ unsigned int unused : 25;
+ unsigned int unused2; /* space for future stuff */
+} quick_module_entry, *quick_module_entry_ptr;
+
+/* Auxiliary Procedure Descriptor:
+ An element of the auxiliary procedure quick look-up table. */
+
+typedef struct quick_aux_procedure
+{
+ long isym_inln; /* start on inline list for proc */
+ long spare;
+} quick_aux_procedure_entry, *quick_aux_procedure_entry_ptr;
+
+/* Paragraph Descriptor:
+ An element of the paragraph quick look-up table. */
+
+typedef struct quick_paragraph
+{
+ long isym; /* first symbol for label (index) */
+ CORE_ADDR adrStart; /* memory adr of start of label */
+ CORE_ADDR adrEnd; /* memory adr of end of label */
+ char *sbLab; /* name of label */
+ unsigned int inst; /* Used in xdb to store inst @ bp */
+ unsigned int sect: 1; /* true = section, false = parag. */
+ unsigned int unused: 31; /* future use */
+} quick_paragraph_entry, *quick_paragraph_entry_ptr;
+
+/* Class Descriptor:
+ An element of the class quick look-up table. */
+
+typedef struct quick_class
+{
+ char *sbClass; /* name of class */
+ long isym; /* class symbol (tag) */
+ unsigned int type : 2; /* 0=class, 1=union, 2=struct */
+ unsigned int fTemplate : 1;/* class template */
+ unsigned int expansion : 1;/* template expansion */
+ unsigned int unused :28;
+ sltpointer lowscope; /* beginning of defined scope */
+ sltpointer hiscope; /* end of defined scope */
+} quick_class_entry, *quick_class_entry_ptr;
+
+/* Address Alias Entry
+ An element of the address alias quick look-up table. */
+
+typedef struct quick_alias
+{
+ CORE_ADDR low;
+ CORE_ADDR high;
+ int index;
+ unsigned int unused : 31;
+ unsigned int alternate : 1; /* alternate unnamed aliases? */
+} quick_alias_entry, *quick_alias_entry_ptr;
+
+/* Object Identification Entry
+ An element of the object identification quick look-up table. */
+
+typedef struct quick_obj_ID
+{
+ CORE_ADDR obj_ident; /* class identifier */
+ long isym; /* class symbol */
+ long offset; /* offset to object start */
+} quick_obj_ID_entry, *quick_obj_ID_entry_ptr;
+
+#endif /* HP_SYMTAB_INCLUDED */
diff --git a/contrib/gdb/include/ieee.h b/contrib/gdb/include/ieee.h
new file mode 100644
index 0000000..5abc32b
--- /dev/null
+++ b/contrib/gdb/include/ieee.h
@@ -0,0 +1,165 @@
+/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file
+
+ Copyright 2001 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.
+
+ 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 0000000..761b2cf
--- /dev/null
+++ b/contrib/gdb/include/libiberty.h
@@ -0,0 +1,335 @@
+/* Function declarations for libiberty.
+
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
+ Note - certain prototypes declared in this header file are for
+ functions whoes implementation copyright does not belong to the
+ FSF. Those prototypes are present in this file for reference
+ purposes only and their presence in this file should not construed
+ as an indication of ownership by the FSF of the implementation of
+ those functions in any way or form whatsoever.
+
+ This program is free software; you can redistribute 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.
+
+ 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ansidecl.h"
+
+#ifdef ANSI_PROTOTYPES
+/* Get a definition for size_t. */
+#include <stddef.h>
+/* Get a definition for va_list. */
+#include <stdarg.h>
+#endif
+
+/* Build an argument vector from a string. Allocates memory using
+ malloc. Use freeargv to free the vector. */
+
+extern char **buildargv PARAMS ((const char *)) ATTRIBUTE_MALLOC;
+
+/* Free a vector returned by buildargv. */
+
+extern void freeargv PARAMS ((char **));
+
+/* Duplicate an argument vector. Allocates memory using malloc. Use
+ freeargv to free the vector. */
+
+extern char **dupargv PARAMS ((char **)) ATTRIBUTE_MALLOC;
+
+
+/* Return the last component of a path name. Note that we can't use a
+ prototype here because the parameter is declared inconsistently
+ across different systems, sometimes as "char *" and sometimes as
+ "const char *" */
+
+/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
+ undefined, we haven't run the autoconf check so provide the
+ declaration without arguments. If it is 0, we checked and failed
+ to find the declaration so provide a fully prototyped one. If it
+ is 1, we found it so don't provide any declaration at all. */
+#if !HAVE_DECL_BASENAME
+#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (HAVE_DECL_BASENAME)
+extern char *basename PARAMS ((const char *));
+#else
+extern char *basename ();
+#endif
+#endif
+
+/* A well-defined basename () that is always compiled in. */
+
+extern const char *lbasename PARAMS ((const char *));
+
+/* A well-defined realpath () that is always compiled in. */
+
+extern char *lrealpath PARAMS ((const char *));
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. */
+
+extern char *concat PARAMS ((const char *, ...)) ATTRIBUTE_MALLOC;
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. The first argument is
+ not one of the strings to be concatenated, but if not NULL is a
+ pointer to be freed after the new string is created, similar to the
+ way xrealloc works. */
+
+extern char *reconcat PARAMS ((char *, const char *, ...)) ATTRIBUTE_MALLOC;
+
+/* Determine the length of concatenating an arbitrary number of
+ strings. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. */
+
+extern unsigned long concat_length PARAMS ((const char *, ...));
+
+/* Concatenate an arbitrary number of strings into a SUPPLIED area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy PARAMS ((char *, const char *, ...));
+
+/* Concatenate an arbitrary number of strings into a GLOBAL area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy2 PARAMS ((const char *, ...));
+
+/* This is the global area used by concat_copy2. */
+
+extern char *libiberty_concat_ptr;
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using alloca. The arguments are
+ evaluated twice! */
+#define ACONCAT(ACONCAT_PARAMS) \
+ (libiberty_concat_ptr = alloca (concat_length ACONCAT_PARAMS + 1), \
+ concat_copy2 ACONCAT_PARAMS)
+
+/* Check whether two file descriptors refer to the same file. */
+
+extern int fdmatch PARAMS ((int fd1, int fd2));
+
+/* Get the working directory. The result is cached, so don't call
+ chdir() between calls to getpwd(). */
+
+extern char * getpwd PARAMS ((void));
+
+/* Get the amount of time the process has run, in microseconds. */
+
+extern long get_run_time PARAMS ((void));
+
+/* Generate a relocated path to some installation directory. Allocates
+ return value using malloc. */
+
+extern char *make_relative_prefix PARAMS ((const char *, const char *,
+ const char *));
+
+/* Choose a temporary directory to use for scratch files. */
+
+extern char *choose_temp_base PARAMS ((void)) ATTRIBUTE_MALLOC;
+
+/* Return a temporary file name or NULL if unable to create one. */
+
+extern char *make_temp_file PARAMS ((const char *)) ATTRIBUTE_MALLOC;
+
+/* 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. */
+
+extern void xexit PARAMS ((int status)) ATTRIBUTE_NORETURN;
+
+/* Set the program name used by xmalloc. */
+
+extern void xmalloc_set_program_name PARAMS ((const char *));
+
+/* Report an allocation failure. */
+extern void xmalloc_failed PARAMS ((size_t)) ATTRIBUTE_NORETURN;
+
+/* 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. */
+
+extern PTR xmalloc PARAMS ((size_t)) ATTRIBUTE_MALLOC;
+
+/* Reallocate memory without fail. This works like xmalloc. Note,
+ realloc type functions are not suitable for attribute malloc since
+ they may return the same address across multiple calls. */
+
+extern PTR xrealloc PARAMS ((PTR, size_t));
+
+/* Allocate memory without fail and set it to zero. This works like
+ xmalloc. */
+
+extern PTR xcalloc PARAMS ((size_t, size_t)) ATTRIBUTE_MALLOC;
+
+/* Copy a string into a memory buffer without fail. */
+
+extern char *xstrdup PARAMS ((const char *)) ATTRIBUTE_MALLOC;
+
+/* Copy an existing memory buffer to a new memory buffer without fail. */
+
+extern PTR xmemdup PARAMS ((const PTR, size_t, size_t)) ATTRIBUTE_MALLOC;
+
+/* Physical memory routines. Return values are in BYTES. */
+extern double physmem_total PARAMS ((void));
+extern double physmem_available PARAMS ((void));
+
+/* hex character manipulation routines */
+
+#define _hex_array_size 256
+#define _hex_bad 99
+extern const unsigned 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) ((unsigned int) _hex_value[(unsigned char) (c)])
+
+/* Definitions used by the pexecute routine. */
+
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+
+/* Execute a program. */
+
+extern int pexecute PARAMS ((const char *, char * const *, const char *,
+ const char *, char **, char **, int));
+
+/* Wait for pexecute to finish. */
+
+extern int pwait PARAMS ((int, int *, int));
+
+#if !HAVE_DECL_ASPRINTF
+/* Like sprintf but provides a pointer to malloc'd storage, which must
+ be freed by the caller. */
+
+extern int asprintf PARAMS ((char **, const char *, ...)) ATTRIBUTE_PRINTF_2;
+#endif
+
+#if !HAVE_DECL_VASPRINTF
+/* Like vsprintf but provides a pointer to malloc'd storage, which
+ must be freed by the caller. */
+
+extern int vasprintf PARAMS ((char **, const char *, va_list))
+ ATTRIBUTE_PRINTF(2,0);
+#endif
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+/* Drastically simplified alloca configurator. If we're using GCC,
+ we use __builtin_alloca; otherwise we use the C alloca. The C
+ alloca is always available. You can override GCC by defining
+ USE_C_ALLOCA yourself. The canonical autoconf macro C_ALLOCA is
+ also set/unset as it is often used to indicate whether code needs
+ to call alloca(0). */
+extern PTR C_alloca PARAMS ((size_t)) ATTRIBUTE_MALLOC;
+#undef alloca
+#if GCC_VERSION >= 2000 && !defined USE_C_ALLOCA
+# define alloca(x) __builtin_alloca(x)
+# undef C_ALLOCA
+# define ASTRDUP(X) \
+ (__extension__ ({ const char *const libiberty_optr = (X); \
+ const unsigned long libiberty_len = strlen (libiberty_optr) + 1; \
+ char *const libiberty_nptr = alloca (libiberty_len); \
+ (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len); }))
+#else
+# define alloca(x) C_alloca(x)
+# undef USE_C_ALLOCA
+# define USE_C_ALLOCA 1
+# undef C_ALLOCA
+# define C_ALLOCA 1
+extern const char *libiberty_optr;
+extern char *libiberty_nptr;
+extern unsigned long libiberty_len;
+# define ASTRDUP(X) \
+ (libiberty_optr = (X), \
+ libiberty_len = strlen (libiberty_optr) + 1, \
+ libiberty_nptr = alloca (libiberty_len), \
+ (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ! defined (LIBIBERTY_H) */
diff --git a/contrib/gdb/include/md5.h b/contrib/gdb/include/md5.h
new file mode 100644
index 0000000..ad51f19
--- /dev/null
+++ b/contrib/gdb/include/md5.h
@@ -0,0 +1,142 @@
+/* md5.h - Declaration of functions and data types used for MD5 sum
+ computing library functions.
+ Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute 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. */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+#else
+# define INT_MAX_32_BITS 2147483647
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+ This should be valid for all systems GNU cares about because
+ that doesn't include 16-bit systems, and only modern systems
+ (that certainly have <limits.h>) have 64+-bit integral types. */
+
+# ifndef INT_MAX
+# define INT_MAX INT_MAX_32_BITS
+# endif
+
+# if INT_MAX == INT_MAX_32_BITS
+ typedef unsigned int md5_uint32;
+# else
+# if SHRT_MAX == INT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
+# else
+# if LONG_MAX == INT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error.
+ Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+# endif
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void md5_init_ctx __P ((struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void md5_process_block __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void md5_process_bytes __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+extern int md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
+
+#endif
diff --git a/contrib/gdb/include/oasys.h b/contrib/gdb/include/oasys.h
new file mode 100644
index 0000000..c8f737a
--- /dev/null
+++ b/contrib/gdb/include/oasys.h
@@ -0,0 +1,192 @@
+/* Oasys object format header file for BFD.
+
+ Copyright 2001 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.
+
+ 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/objalloc.h b/contrib/gdb/include/objalloc.h
new file mode 100644
index 0000000..c710647
--- /dev/null
+++ b/contrib/gdb/include/objalloc.h
@@ -0,0 +1,115 @@
+/* objalloc.h -- routines to allocate memory for objects
+ Copyright 1997, 2001 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Cygnus Solutions.
+
+This program is free software; you can redistribute 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, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef OBJALLOC_H
+#define OBJALLOC_H
+
+#include "ansidecl.h"
+
+/* These routines allocate space for an object. The assumption is
+ that the object will want to allocate space as it goes along, but
+ will never want to free any particular block. There is a function
+ to free a block, which also frees all more recently allocated
+ blocks. There is also a function to free all the allocated space.
+
+ This is essentially a specialization of obstacks. The main
+ difference is that a block may not be allocated a bit at a time.
+ Another difference is that these routines are always built on top
+ of malloc, and always pass an malloc failure back to the caller,
+ unlike more recent versions of obstacks. */
+
+/* This is what an objalloc structure looks like. Callers should not
+ refer to these fields, nor should they allocate these structure
+ themselves. Instead, they should only create them via
+ objalloc_init, and only access them via the functions and macros
+ listed below. The structure is only defined here so that we can
+ access it via macros. */
+
+struct objalloc
+{
+ char *current_ptr;
+ unsigned int current_space;
+ PTR chunks;
+};
+
+/* Work out the required alignment. */
+
+struct objalloc_align { char x; double d; };
+
+#if defined (__STDC__) && __STDC__
+#ifndef offsetof
+#include <stddef.h>
+#endif
+#endif
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+#define OBJALLOC_ALIGN offsetof (struct objalloc_align, d)
+
+/* Create an objalloc structure. Returns NULL if malloc fails. */
+
+extern struct objalloc *objalloc_create PARAMS ((void));
+
+/* Allocate space from an objalloc structure. Returns NULL if malloc
+ fails. */
+
+extern PTR _objalloc_alloc PARAMS ((struct objalloc *, unsigned long));
+
+/* The macro version of objalloc_alloc. We only define this if using
+ gcc, because otherwise we would have to evaluate the arguments
+ multiple times, or use a temporary field as obstack.h does. */
+
+#if defined (__GNUC__) && defined (__STDC__) && __STDC__
+
+/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
+ does not implement __extension__. But that compiler doesn't define
+ __GNUC_MINOR__. */
+#if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
+#define __extension__
+#endif
+
+#define objalloc_alloc(o, l) \
+ __extension__ \
+ ({ struct objalloc *__o = (o); \
+ unsigned long __len = (l); \
+ if (__len == 0) \
+ __len = 1; \
+ __len = (__len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1); \
+ (__len <= __o->current_space \
+ ? (__o->current_ptr += __len, \
+ __o->current_space -= __len, \
+ (PTR) (__o->current_ptr - __len)) \
+ : _objalloc_alloc (__o, __len)); })
+
+#else /* ! __GNUC__ */
+
+#define objalloc_alloc(o, l) _objalloc_alloc ((o), (l))
+
+#endif /* ! __GNUC__ */
+
+/* Free an entire objalloc structure. */
+
+extern void objalloc_free PARAMS ((struct objalloc *));
+
+/* Free a block allocated by objalloc_alloc. This also frees all more
+ recently allocated blocks. */
+
+extern void objalloc_free_block PARAMS ((struct objalloc *, PTR));
+
+#endif /* OBJALLOC_H */
diff --git a/contrib/gdb/include/obstack.h b/contrib/gdb/include/obstack.h
new file mode 100644
index 0000000..5496ff2
--- /dev/null
+++ b/contrib/gdb/include/obstack.h
@@ -0,0 +1,611 @@
+/* obstack.h - object stack macros
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+ 1999, 2000
+ Free Software Foundation, Inc.
+
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
+
+ This program is free software; you can redistribute 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. */
+
+/* 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 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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. If __PTRDIFF_TYPE__ is
+ defined, as with GNU C, use that; that way we don't pollute the
+ namespace with <stddef.h>'s symbols. Otherwise, if <stddef.h> is
+ available, include it and use ptrdiff_t. In traditional C, long is
+ the best that we can do. */
+
+#ifdef __PTRDIFF_TYPE__
+# define PTR_INT_TYPE __PTRDIFF_TYPE__
+#else
+# ifdef HAVE_STDDEF_H
+# include <stddef.h>
+# define PTR_INT_TYPE ptrdiff_t
+# else
+# define PTR_INT_TYPE long
+# endif
+#endif
+
+#if defined _LIBC || defined HAVE_STRING_H
+# include <string.h>
+# if defined __STDC__ && __STDC__
+# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N))
+# else
+# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N))
+# endif
+#else
+# ifdef memcpy
+# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N))
+# else
+# define _obstack_memcpy(To, From, N) bcopy ((char *)(From), (To), (N))
+# endif
+#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. */
+#if defined __STDC__ && __STDC__
+ /* These prototypes vary based on `use_extra_arg', and we use
+ casts to the prototypeless function type in all assignments,
+ but having prototypes here quiets -Wstrict-prototypes. */
+ struct _obstack_chunk *(*chunkfun) (void *, long);
+ void (*freefun) (void *, struct _obstack_chunk *);
+ void *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+#else
+ 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 */
+#endif
+ 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; /* No longer used, as we now call the failed
+ handler on error, but retained for binary
+ compatibility. */
+};
+
+/* Declare the external functions we use; they are in obstack.c. */
+
+#if defined __STDC__ && __STDC__
+extern void _obstack_newchunk (struct obstack *, int);
+extern void _obstack_free (struct obstack *, void *);
+extern int _obstack_begin (struct obstack *, int, int,
+ void *(*) (long), void (*) (void *));
+extern int _obstack_begin_1 (struct obstack *, int, int,
+ void *(*) (void *, long),
+ void (*) (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
+
+#if defined __STDC__ && __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_make_room (struct obstack *obstack, int size);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_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. */
+
+/* Error handler called when `obstack_chunk_alloc' failed to allocate
+ more memory. This can be set to a user defined function. The
+ default action is to print a message and abort. */
+#if defined __STDC__ && __STDC__
+extern void (*obstack_alloc_failed_handler) (void);
+#else
+extern void (*obstack_alloc_failed_handler) ();
+#endif
+
+/* Exit value used when `print_and_abort' is used. */
+extern int obstack_exit_failure;
+
+/* 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)->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)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object. */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+/* To prevent prototype warnings provide complete argument list in
+ standard C version. */
+#if defined __STDC__ && __STDC__
+
+# define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) (long)) (chunkfun), (void (*) (void *)) (freefun))
+
+# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) (void *, long)) (chunkfun), \
+ (void (*) (void *, void *)) (freefun), (arg))
+
+# define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
+
+# define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
+
+#else
+
+# 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))
+
+#endif
+
+#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__ && __STDC__
+/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
+ does not implement __extension__. But that compiler doesn't define
+ __GNUC_MINOR__. */
+# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
+# 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); \
+ (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_make_room(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->chunk_limit - __o->next_free < __len) \
+ _obstack_newchunk (__o, __len); \
+ (void) 0; })
+
+# define obstack_empty_p(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (__o->chunk->prev == 0 && __o->next_free - __o->chunk->contents == 0); })
+
+# 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); \
+ _obstack_memcpy (__o->next_free, (where), __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); \
+ _obstack_memcpy (__o->next_free, (where), __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); \
+ obstack_1grow_fast (__o, 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 *)); \
+ obstack_ptr_grow_fast (__o, datum); })
+
+# 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)); \
+ obstack_int_grow_fast (__o, datum); })
+
+# define obstack_ptr_grow_fast(OBSTACK,aptr) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ *(const void **) __o1->next_free = (aptr); \
+ __o1->next_free += sizeof (const void *); \
+ (void) 0; })
+
+# define obstack_int_grow_fast(OBSTACK,aint) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ *(int *) __o1->next_free = (aint); \
+ __o1->next_free += sizeof (int); \
+ (void) 0; })
+
+# 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); \
+ obstack_blank_fast (__o, __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; \
+ 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)->next_free - (h)->object_base)
+
+# define obstack_room(h) \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+# define obstack_empty_p(h) \
+ ((h)->chunk->prev == 0 && (h)->next_free - (h)->chunk->contents == 0)
+
+/* 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_make_room(h,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0))
+
+# define obstack_grow(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ _obstack_memcpy ((h)->next_free, (where), (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), \
+ _obstack_memcpy ((h)->next_free, (where), (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), \
+ obstack_1grow_fast (h, datum))
+
+# define obstack_ptr_grow(h,datum) \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
+ obstack_ptr_grow_fast (h, datum))
+
+# define obstack_int_grow(h,datum) \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
+ obstack_int_grow_fast (h, datum))
+
+# define obstack_ptr_grow_fast(h,aptr) \
+ (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
+
+# define obstack_int_grow_fast(h,aint) \
+ (((int *) ((h)->next_free += sizeof (int)))[-1] = (aptr))
+
+# define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->chunk_limit - (h)->next_free < (h)->temp) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ obstack_blank_fast (h, (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)->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))
+
+# if defined __STDC__ && __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__ */
+
+#ifdef __cplusplus
+} /* C++ */
+#endif
+
+#endif /* obstack.h */
diff --git a/contrib/gdb/include/os9k.h b/contrib/gdb/include/os9k.h
new file mode 100644
index 0000000..596f56d
--- /dev/null
+++ b/contrib/gdb/include/os9k.h
@@ -0,0 +1,181 @@
+/* os9k.h - OS-9000 i386 module header definitions
+ Copyright 2000 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. */
+
+#if !defined(_MODULE_H)
+#define _MODULE_H
+
+#define _MPF386
+
+/* Size of 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 0x4afc /* 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 0x800063 /* 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. */
+ unsigned char m_tylan[2]; /* Type/lang. */
+ unsigned char m_attrev[2]; /* Rev/attr. */
+ unsigned char m_edit[2]; /* Edition. */
+ unsigned char m_needs[4]; /* Module hardware requirements flags. (reserved). */
+ unsigned char m_usage[4]; /* Comment string offset. */
+ unsigned char m_symbol[4]; /* Symbol table offset. */
+ unsigned char m_exec[4]; /* Offset to execution entry point. */
+ unsigned char m_excpt[4]; /* Offset to exception entry point. */
+ unsigned char m_data[4]; /* Data storage requirement. */
+ unsigned char m_stack[4]; /* Stack size. */
+ unsigned char m_idata[4]; /* Offset to initialized data. */
+ unsigned char m_idref[4]; /* Offset to data reference lists. */
+ unsigned char m_init[4]; /* Initialization routine offset. */
+ unsigned char 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 <moddir.h>
+#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/partition.h b/contrib/gdb/include/partition.h
new file mode 100644
index 0000000..5d3623f
--- /dev/null
+++ b/contrib/gdb/include/partition.h
@@ -0,0 +1,85 @@
+/* List implementation of a partition of consecutive integers.
+ Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by CodeSourcery, LLC.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute 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.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This package implements a partition of consecutive integers. The
+ elements are partitioned into classes. Each class is represented
+ by one of its elements, the canonical element, which is chosen
+ arbitrarily from elements in the class. The principal operations
+ on a partition are FIND, which takes an element, determines its
+ class, and returns the canonical element for that class, and UNION,
+ which unites the two classes that contain two given elements into a
+ single class.
+
+ The list implementation used here provides constant-time finds. By
+ storing the size of each class with the class's canonical element,
+ it is able to perform unions over all the classes in the partition
+ in O (N log N) time. */
+
+#ifndef _PARTITION_H
+#define _PARTITION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "ansidecl.h"
+#include <stdio.h>
+
+struct partition_elem
+{
+ /* The canonical element that represents the class containing this
+ element. */
+ int class_element;
+ /* The next element in this class. Elements in each class form a
+ circular list. */
+ struct partition_elem* next;
+ /* The number of elements in this class. Valid only if this is the
+ canonical element for its class. */
+ unsigned class_count;
+};
+
+typedef struct partition_def
+{
+ /* The number of elements in this partition. */
+ int num_elements;
+ /* The elements in the partition. */
+ struct partition_elem elements[1];
+} *partition;
+
+extern partition partition_new PARAMS((int));
+extern void partition_delete PARAMS((partition));
+extern int partition_union PARAMS((partition,
+ int,
+ int));
+extern void partition_print PARAMS((partition,
+ FILE*));
+
+/* Returns the canonical element corresponding to the class containing
+ ELEMENT__ in PARTITION__. */
+
+#define partition_find(partition__, element__) \
+ ((partition__)->elements[(element__)].class_element)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _PARTITION_H */
diff --git a/contrib/gdb/include/progress.h b/contrib/gdb/include/progress.h
new file mode 100644
index 0000000..23b0960
--- /dev/null
+++ b/contrib/gdb/include/progress.h
@@ -0,0 +1,37 @@
+/* Default definitions for progress macros.
+ 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. */
+
+/* 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/safe-ctype.h b/contrib/gdb/include/safe-ctype.h
new file mode 100644
index 0000000..69a3f74
--- /dev/null
+++ b/contrib/gdb/include/safe-ctype.h
@@ -0,0 +1,119 @@
+/* <ctype.h> replacement macros.
+
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Zack Weinberg <zackw@stanford.edu>.
+
+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 is a compatible replacement of the standard C library's <ctype.h>
+ with the following properties:
+
+ - Implements all isxxx() macros required by C99.
+ - Also implements some character classes useful when
+ parsing C-like languages.
+ - Does not change behavior depending on the current locale.
+ - Behaves properly for all values in the range of a signed or
+ unsigned char.
+
+ To avoid conflicts, this header defines the isxxx functions in upper
+ case, e.g. ISALPHA not isalpha. */
+
+#ifndef SAFE_CTYPE_H
+#define SAFE_CTYPE_H
+
+#ifdef isalpha
+ #error "safe-ctype.h and ctype.h may not be used simultaneously"
+#endif
+
+/* Determine host character set. */
+#define HOST_CHARSET_UNKNOWN 0
+#define HOST_CHARSET_ASCII 1
+#define HOST_CHARSET_EBCDIC 2
+
+#if '\n' == 0x0A && ' ' == 0x20 && '0' == 0x30 \
+ && 'A' == 0x41 && 'a' == 0x61 && '!' == 0x21
+# define HOST_CHARSET HOST_CHARSET_ASCII
+#else
+# if '\n' == 0x15 && ' ' == 0x40 && '0' == 0xF0 \
+ && 'A' == 0xC1 && 'a' == 0x81 && '!' == 0x5A
+# define HOST_CHARSET HOST_CHARSET_EBCDIC
+# else
+# define HOST_CHARSET HOST_CHARSET_UNKNOWN
+# endif
+#endif
+
+/* Categories. */
+
+enum {
+ /* In C99 */
+ _sch_isblank = 0x0001, /* space \t */
+ _sch_iscntrl = 0x0002, /* nonprinting characters */
+ _sch_isdigit = 0x0004, /* 0-9 */
+ _sch_islower = 0x0008, /* a-z */
+ _sch_isprint = 0x0010, /* any printing character including ' ' */
+ _sch_ispunct = 0x0020, /* all punctuation */
+ _sch_isspace = 0x0040, /* space \t \n \r \f \v */
+ _sch_isupper = 0x0080, /* A-Z */
+ _sch_isxdigit = 0x0100, /* 0-9A-Fa-f */
+
+ /* Extra categories useful to cpplib. */
+ _sch_isidst = 0x0200, /* A-Za-z_ */
+ _sch_isvsp = 0x0400, /* \n \r */
+ _sch_isnvsp = 0x0800, /* space \t \f \v \0 */
+
+ /* Combinations of the above. */
+ _sch_isalpha = _sch_isupper|_sch_islower, /* A-Za-z */
+ _sch_isalnum = _sch_isalpha|_sch_isdigit, /* A-Za-z0-9 */
+ _sch_isidnum = _sch_isidst|_sch_isdigit, /* A-Za-z0-9_ */
+ _sch_isgraph = _sch_isalnum|_sch_ispunct, /* isprint and not space */
+ _sch_iscppsp = _sch_isvsp|_sch_isnvsp, /* isspace + \0 */
+ _sch_isbasic = _sch_isprint|_sch_iscppsp /* basic charset of ISO C
+ (plus ` and @) */
+};
+
+/* Character classification. */
+extern const unsigned short _sch_istable[256];
+
+#define _sch_test(c, bit) (_sch_istable[(c) & 0xff] & (unsigned short)(bit))
+
+#define ISALPHA(c) _sch_test(c, _sch_isalpha)
+#define ISALNUM(c) _sch_test(c, _sch_isalnum)
+#define ISBLANK(c) _sch_test(c, _sch_isblank)
+#define ISCNTRL(c) _sch_test(c, _sch_iscntrl)
+#define ISDIGIT(c) _sch_test(c, _sch_isdigit)
+#define ISGRAPH(c) _sch_test(c, _sch_isgraph)
+#define ISLOWER(c) _sch_test(c, _sch_islower)
+#define ISPRINT(c) _sch_test(c, _sch_isprint)
+#define ISPUNCT(c) _sch_test(c, _sch_ispunct)
+#define ISSPACE(c) _sch_test(c, _sch_isspace)
+#define ISUPPER(c) _sch_test(c, _sch_isupper)
+#define ISXDIGIT(c) _sch_test(c, _sch_isxdigit)
+
+#define ISIDNUM(c) _sch_test(c, _sch_isidnum)
+#define ISIDST(c) _sch_test(c, _sch_isidst)
+#define IS_ISOBASIC(c) _sch_test(c, _sch_isbasic)
+#define IS_VSPACE(c) _sch_test(c, _sch_isvsp)
+#define IS_NVSPACE(c) _sch_test(c, _sch_isnvsp)
+#define IS_SPACE_OR_NUL(c) _sch_test(c, _sch_iscppsp)
+
+/* Character transformation. */
+extern const unsigned char _sch_toupper[256];
+extern const unsigned char _sch_tolower[256];
+#define TOUPPER(c) _sch_toupper[(c) & 0xff]
+#define TOLOWER(c) _sch_tolower[(c) & 0xff]
+
+#endif /* SAFE_CTYPE_H */
diff --git a/contrib/gdb/include/sort.h b/contrib/gdb/include/sort.h
new file mode 100644
index 0000000..3f3a92f
--- /dev/null
+++ b/contrib/gdb/include/sort.h
@@ -0,0 +1,48 @@
+/* Sorting algorithms.
+ Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+ Contributed by Mark Mitchell <mark@codesourcery.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute 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.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef SORT_H
+#define SORT_H
+
+#include <sys/types.h> /* For size_t */
+#ifdef __STDC__
+#include <stddef.h>
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "ansidecl.h"
+
+/* Sort an array of pointers. */
+
+extern void sort_pointers PARAMS ((size_t, void **, void **));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SORT_H */
+
+
+
+
diff --git a/contrib/gdb/include/splay-tree.h b/contrib/gdb/include/splay-tree.h
new file mode 100644
index 0000000..86707fc
--- /dev/null
+++ b/contrib/gdb/include/splay-tree.h
@@ -0,0 +1,159 @@
+/* A splay-tree datatype.
+ Copyright 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
+ Contributed by Mark Mitchell (mark@markmitchell.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute 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.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* For an easily readable description of splay-trees, see:
+
+ Lewis, Harry R. and Denenberg, Larry. Data Structures and Their
+ Algorithms. Harper-Collins, Inc. 1991.
+
+ The major feature of splay trees is that all basic tree operations
+ are amortized O(log n) time for a tree with n nodes. */
+
+#ifndef _SPLAY_TREE_H
+#define _SPLAY_TREE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "ansidecl.h"
+
+#ifndef GTY
+#define GTY(X)
+#endif
+
+/* Use typedefs for the key and data types to facilitate changing
+ these types, if necessary. These types should be sufficiently wide
+ that any pointer or scalar can be cast to these types, and then
+ cast back, without loss of precision. */
+typedef unsigned long int splay_tree_key;
+typedef unsigned long int splay_tree_value;
+
+/* Forward declaration for a node in the tree. */
+typedef struct splay_tree_node_s *splay_tree_node;
+
+/* The type of a function which compares two splay-tree keys. The
+ function should return values as for qsort. */
+typedef int (*splay_tree_compare_fn) PARAMS((splay_tree_key, splay_tree_key));
+
+/* The type of a function used to deallocate any resources associated
+ with the key. */
+typedef void (*splay_tree_delete_key_fn) PARAMS((splay_tree_key));
+
+/* The type of a function used to deallocate any resources associated
+ with the value. */
+typedef void (*splay_tree_delete_value_fn) PARAMS((splay_tree_value));
+
+/* The type of a function used to iterate over the tree. */
+typedef int (*splay_tree_foreach_fn) PARAMS((splay_tree_node, void*));
+
+/* The type of a function used to allocate memory for tree root and
+ node structures. The first argument is the number of bytes needed;
+ the second is a data pointer the splay tree functions pass through
+ to the allocator. This function must never return zero. */
+typedef PTR (*splay_tree_allocate_fn) PARAMS((int, void *));
+
+/* The type of a function used to free memory allocated using the
+ corresponding splay_tree_allocate_fn. The first argument is the
+ memory to be freed; the latter is a data pointer the splay tree
+ functions pass through to the freer. */
+typedef void (*splay_tree_deallocate_fn) PARAMS((void *, void *));
+
+/* The nodes in the splay tree. */
+struct splay_tree_node_s GTY(())
+{
+ /* The key. */
+ splay_tree_key GTY ((use_param1 (""))) key;
+
+ /* The value. */
+ splay_tree_value GTY ((use_param2 (""))) value;
+
+ /* The left and right children, respectively. */
+ splay_tree_node GTY ((use_params (""))) left;
+ splay_tree_node GTY ((use_params (""))) right;
+};
+
+/* The splay tree itself. */
+struct splay_tree_s GTY(())
+{
+ /* The root of the tree. */
+ splay_tree_node GTY ((use_params (""))) root;
+
+ /* The comparision function. */
+ splay_tree_compare_fn comp;
+
+ /* The deallocate-key function. NULL if no cleanup is necessary. */
+ splay_tree_delete_key_fn delete_key;
+
+ /* The deallocate-value function. NULL if no cleanup is necessary. */
+ splay_tree_delete_value_fn delete_value;
+
+ /* Allocate/free functions, and a data pointer to pass to them. */
+ splay_tree_allocate_fn allocate;
+ splay_tree_deallocate_fn deallocate;
+ PTR GTY((skip (""))) allocate_data;
+
+};
+typedef struct splay_tree_s *splay_tree;
+
+extern splay_tree splay_tree_new PARAMS((splay_tree_compare_fn,
+ splay_tree_delete_key_fn,
+ splay_tree_delete_value_fn));
+extern splay_tree splay_tree_new_with_allocator
+ PARAMS((splay_tree_compare_fn,
+ splay_tree_delete_key_fn,
+ splay_tree_delete_value_fn,
+ splay_tree_allocate_fn,
+ splay_tree_deallocate_fn,
+ void *));
+extern void splay_tree_delete PARAMS((splay_tree));
+extern splay_tree_node splay_tree_insert
+ PARAMS((splay_tree,
+ splay_tree_key,
+ splay_tree_value));
+extern void splay_tree_remove PARAMS((splay_tree,
+ splay_tree_key));
+extern splay_tree_node splay_tree_lookup
+ PARAMS((splay_tree,
+ splay_tree_key));
+extern splay_tree_node splay_tree_predecessor
+ PARAMS((splay_tree,
+ splay_tree_key));
+extern splay_tree_node splay_tree_successor
+ PARAMS((splay_tree,
+ splay_tree_key));
+extern splay_tree_node splay_tree_max
+ PARAMS((splay_tree));
+extern splay_tree_node splay_tree_min
+ PARAMS((splay_tree));
+extern int splay_tree_foreach PARAMS((splay_tree,
+ splay_tree_foreach_fn,
+ void*));
+extern int splay_tree_compare_ints PARAMS((splay_tree_key,
+ splay_tree_key));
+extern int splay_tree_compare_pointers PARAMS((splay_tree_key,
+ splay_tree_key));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _SPLAY_TREE_H */
diff --git a/contrib/gdb/include/symcat.h b/contrib/gdb/include/symcat.h
new file mode 100644
index 0000000..61ce1e9
--- /dev/null
+++ b/contrib/gdb/include/symcat.h
@@ -0,0 +1,49 @@
+/* Symbol concatenation utilities.
+
+ Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef SYM_CAT_H
+#define SYM_CAT_H
+
+#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE)
+#define CONCAT2(a,b) a##b
+#define CONCAT3(a,b,c) a##b##c
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define STRINGX(s) #s
+#else
+/* Note one should never pass extra whitespace to the CONCATn macros,
+ e.g. CONCAT2(foo, bar) because traditonal C will keep the space between
+ the two labels instead of concatenating them. Instead, make sure to
+ write CONCAT2(foo,bar). */
+#define CONCAT2(a,b) a/**/b
+#define CONCAT3(a,b,c) a/**/b/**/c
+#define CONCAT4(a,b,c,d) a/**/b/**/c/**/d
+#define STRINGX(s) "s"
+#endif
+
+#define XCONCAT2(a,b) CONCAT2(a,b)
+#define XCONCAT3(a,b,c) CONCAT3(a,b,c)
+#define XCONCAT4(a,b,c,d) CONCAT4(a,b,c,d)
+
+/* Note the layer of indirection here is typically used to allow
+ stringification of the expansion of macros. I.e. "#define foo
+ bar", "XSTRING(foo)", to yield "bar". Be aware that this only
+ works for __STDC__, not for traditional C which will still resolve
+ to "foo". */
+#define XSTRING(s) STRINGX(s)
+
+#endif /* SYM_CAT_H */
diff --git a/contrib/gdb/include/ternary.h b/contrib/gdb/include/ternary.h
new file mode 100644
index 0000000..40d442e
--- /dev/null
+++ b/contrib/gdb/include/ternary.h
@@ -0,0 +1,51 @@
+/* ternary.h - Ternary Search Trees
+ Copyright 2001 Free Software Foundation, Inc.
+
+ Contributed by Daniel Berlin (dan@cgsoftware.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, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TERNARY_H_
+#define TERNARY_H_
+/* Ternary search trees */
+
+typedef struct ternary_node_def *ternary_tree;
+
+typedef struct ternary_node_def
+{
+ char splitchar;
+ ternary_tree lokid;
+ ternary_tree eqkid;
+ ternary_tree hikid;
+}
+ternary_node;
+
+/* Insert string S into tree P, associating it with DATA.
+ Return the data in the tree associated with the string if it's
+ already there, and replace is 0.
+ Otherwise, replaces if it it exists, inserts if it doesn't, and
+ returns the data you passed in. */
+PTR ternary_insert PARAMS ((ternary_tree *p, const char *s,
+ PTR data, int replace));
+
+/* Delete the ternary search tree rooted at P.
+ Does NOT delete the data you associated with the strings. */
+void ternary_cleanup PARAMS ((ternary_tree p));
+
+/* Search the ternary tree for string S, returning the data associated
+ with it if found. */
+PTR ternary_search PARAMS ((const ternary_node *p, const char *s));
+#endif
diff --git a/contrib/gdb/include/xregex.h b/contrib/gdb/include/xregex.h
new file mode 100644
index 0000000..645195b
--- /dev/null
+++ b/contrib/gdb/include/xregex.h
@@ -0,0 +1,28 @@
+/* This file redefines all regex external names before including
+ a renamed copy of glibc's regex.h. */
+
+#ifndef _XREGEX_H
+#define _XREGEX_H 1
+
+# define regfree xregfree
+# define regexec xregexec
+# define regcomp xregcomp
+# define regerror xregerror
+# define re_set_registers xre_set_registers
+# define re_match_2 xre_match_2
+# define re_match xre_match
+# define re_search xre_search
+# define re_compile_pattern xre_compile_pattern
+# define re_set_syntax xre_set_syntax
+# define re_search_2 xre_search_2
+# define re_compile_fastmap xre_compile_fastmap
+# define re_syntax_options xre_syntax_options
+# define re_max_failures xre_max_failures
+
+# define _REGEX_RE_COMP
+# define re_comp xre_comp
+# define re_exec xre_exec
+
+#include "xregex2.h"
+
+#endif /* xregex.h */
diff --git a/contrib/gdb/include/xregex2.h b/contrib/gdb/include/xregex2.h
new file mode 100644
index 0000000..2991daf
--- /dev/null
+++ b/contrib/gdb/include/xregex2.h
@@ -0,0 +1,571 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+ Copyright (C) 1985,1989-1993,1995-1998, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library. Its master source is NOT part of
+ the C library, however. The master source lives in /gd/gnu/lib.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+/* Allow the use in C++ code. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+# include <stddef.h>
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+ wide enough to hold a value of a pointer. For most ANSI compilers
+ ptrdiff_t and size_t should be likely OK. Still size of these two
+ types is 2 for Microsoft C. Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+ If not set, and debugging was on, turn it off.
+ This only works if regex.c is compiled -DDEBUG.
+ We define this bit always, so that all that's needed to turn on
+ debugging is to recompile regex.c; the calling code can always have
+ this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* If this bit is set, a syntactically invalid interval is treated as
+ a string of ordinary characters. For example, the ERE 'a{1' is
+ treated as 'a\{1'. */
+#define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK \
+ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \
+ & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS))
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
+ | RE_INTERVALS | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \
+ | RE_INVALID_INTERVAL_ORD)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
+ removed and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+# undef RE_DUP_MAX
+#endif
+/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+#ifdef _XOPEN_SOURCE
+ REG_ENOSYS = -1, /* This will never happen for this implementation. */
+#endif
+
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+#ifndef RE_TRANSLATE_TYPE
+# define RE_TRANSLATE_TYPE char *
+#endif
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long int allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long int used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ RE_TRANSLATE_TYPE translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+# define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+# define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+# define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, size_t length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+# ifndef _CRAY
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+# endif
+#endif
+
+/* GCC 2.95 and later have "__restrict"; C99 compilers have
+ "restrict", and "configure" may have defined "restrict". */
+#ifndef __restrict
+# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
+# if defined restrict || 199901L <= __STDC_VERSION__
+# define __restrict restrict
+# else
+# define __restrict
+# endif
+# endif
+#endif
+
+/* GCC 3.1 and later support declaring arrays as non-overlapping
+ using the syntax array_name[restrict] */
+#ifndef __restrict_arr
+# if ! (3 < __GNUC__ || (3 == __GNUC__ && 1 <= __GNUC_MINOR__)) || defined (__GNUG__)
+# define __restrict_arr
+# else
+# define __restrict_arr __restrict
+# endif
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *__restrict __preg,
+ const char *__restrict __pattern,
+ int __cflags));
+
+extern int regexec _RE_ARGS ((const regex_t *__restrict __preg,
+ const char *__restrict __string, size_t __nmatch,
+ regmatch_t __pmatch[__restrict_arr],
+ int __eflags));
+
+extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
+ char *__errbuf, size_t __errbuf_size));
+
+extern void regfree _RE_ARGS ((regex_t *__preg));
+
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
+
+#endif /* regex.h */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/contrib/gdb/include/xtensa-isa-internal.h b/contrib/gdb/include/xtensa-isa-internal.h
new file mode 100644
index 0000000..7f221ea
--- /dev/null
+++ b/contrib/gdb/include/xtensa-isa-internal.h
@@ -0,0 +1,114 @@
+/* Internal definitions for configurable Xtensa ISA support.
+ Copyright 2003 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. */
+
+/* Use the statically-linked version for the GNU tools. */
+#define STATIC_LIBISA 1
+
+#define ISA_INTERFACE_VERSION 3
+
+struct config_struct
+{
+ char *param_name;
+ char *param_value;
+};
+
+/* Encode/decode function types for immediate operands. */
+typedef uint32 (*xtensa_immed_decode_fn) (uint32);
+typedef xtensa_encode_result (*xtensa_immed_encode_fn) (uint32 *);
+
+/* Field accessor function types. */
+typedef uint32 (*xtensa_get_field_fn) (const xtensa_insnbuf);
+typedef void (*xtensa_set_field_fn) (xtensa_insnbuf, uint32);
+
+/* PC-relative relocation function types. */
+typedef uint32 (*xtensa_do_reloc_fn) (uint32, uint32);
+typedef uint32 (*xtensa_undo_reloc_fn) (uint32, uint32);
+
+/* Instruction decode function type. */
+typedef int (*xtensa_insn_decode_fn) (const xtensa_insnbuf);
+
+/* Instruction encoding template function type (each of these functions
+ returns a constant template; they exist only to make it easier for the
+ TIE compiler to generate endian-independent DLLs). */
+typedef xtensa_insnbuf (*xtensa_encoding_template_fn) (void);
+
+
+typedef struct xtensa_operand_internal_struct
+{
+ char *operand_kind; /* e.g., "a", "f", "i", "l".... */
+ char inout; /* '<', '>', or '='. */
+ char isPCRelative; /* Is this a PC-relative offset? */
+ xtensa_get_field_fn get_field; /* Get encoded value of the field. */
+ xtensa_set_field_fn set_field; /* Set field with an encoded value. */
+ xtensa_immed_encode_fn encode; /* Encode the operand value. */
+ xtensa_immed_decode_fn decode; /* Decode the value from the field. */
+ xtensa_do_reloc_fn do_reloc; /* Perform a PC-relative relocation. */
+ xtensa_undo_reloc_fn undo_reloc; /* Undo a PC-relative relocation. */
+} xtensa_operand_internal;
+
+
+typedef struct xtensa_iclass_internal_struct
+{
+ int num_operands; /* Size of "operands" array. */
+ xtensa_operand_internal **operands; /* Array of operand structures. */
+} xtensa_iclass_internal;
+
+
+typedef struct xtensa_opcode_internal_struct
+{
+ const char *name; /* Opcode mnemonic. */
+ int length; /* Length in bytes of the insn. */
+ xtensa_encoding_template_fn template; /* Fn returning encoding template. */
+ xtensa_iclass_internal *iclass; /* Iclass for this opcode. */
+} xtensa_opcode_internal;
+
+
+typedef struct opname_lookup_entry_struct
+{
+ const char *key; /* Opcode mnemonic. */
+ xtensa_opcode opcode; /* Internal opcode number. */
+} opname_lookup_entry;
+
+
+typedef struct xtensa_isa_internal_struct
+{
+ int is_big_endian; /* Endianness. */
+ int insn_size; /* Maximum length in bytes. */
+ int insnbuf_size; /* Number of insnbuf_words. */
+ int num_opcodes; /* Total number for all modules. */
+ xtensa_opcode_internal **opcode_table;/* Indexed by internal opcode #. */
+ int num_modules; /* Number of modules (DLLs) loaded. */
+ int *module_opcode_base; /* Starting opcode # for each module. */
+ xtensa_insn_decode_fn *module_decode_fn; /* Decode fn for each module. */
+ opname_lookup_entry *opname_lookup_table; /* Lookup table for each module. */
+ struct config_struct *config; /* Table of configuration parameters. */
+ int has_density; /* Is density option available? */
+} xtensa_isa_internal;
+
+
+typedef struct xtensa_isa_module_struct
+{
+ int (*get_num_opcodes_fn) (void);
+ xtensa_opcode_internal **(*get_opcodes_fn) (void);
+ int (*decode_insn_fn) (const xtensa_insnbuf);
+ struct config_struct *(*get_config_table_fn) (void);
+} xtensa_isa_module;
+
+extern xtensa_isa_module xtensa_isa_modules[];
+
diff --git a/contrib/gdb/include/xtensa-isa.h b/contrib/gdb/include/xtensa-isa.h
new file mode 100644
index 0000000..54f750c
--- /dev/null
+++ b/contrib/gdb/include/xtensa-isa.h
@@ -0,0 +1,230 @@
+/* Interface definition for configurable Xtensa ISA support.
+ Copyright 2003 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. */
+
+#ifndef XTENSA_LIBISA_H
+#define XTENSA_LIBISA_H
+
+/* Use the statically-linked version for the GNU tools. */
+#define STATIC_LIBISA 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef uint32
+#define uint32 unsigned int
+#endif
+
+/* This file defines the interface to the Xtensa ISA library. This library
+ contains most of the ISA-specific information for a particular Xtensa
+ processor. For example, the set of valid instructions, their opcode
+ encodings and operand fields are all included here. To support Xtensa's
+ configurability and user-defined instruction extensions (i.e., TIE), the
+ library is initialized by loading one or more dynamic libraries; only a
+ small set of interface code is present in the statically-linked portion
+ of the library.
+
+ This interface basically defines four abstract data types.
+
+ . an instruction buffer - for holding the raw instruction bits
+ . ISA info - information about the ISA as a whole
+ . opcode info - information about individual instructions
+ . operand info - information about specific instruction operands
+
+ It would be nice to implement these as classes in C++, but the library is
+ implemented in C to match the expectations of the GNU tools.
+ Instead, the interface defines a set of functions to access each data
+ type. With the exception of the instruction buffer, the internal
+ representations of the data structures are hidden. All accesses must be
+ made through the functions defined here. */
+
+typedef void* xtensa_isa;
+typedef void* xtensa_operand;
+
+
+/* Opcodes are represented here using sequential integers beginning with 0.
+ The specific value used for a particular opcode is only fixed for a
+ particular instantiation of an xtensa_isa structure, so these values
+ should only be used internally. */
+typedef int xtensa_opcode;
+
+/* Define a unique value for undefined opcodes ("static const int" doesn't
+ seem to work for this because EGCS 1.0.3 on i686-Linux without -O won't
+ allow it to be used as an initializer). */
+#define XTENSA_UNDEFINED -1
+
+
+typedef int libisa_module_specifier;
+
+extern xtensa_isa xtensa_isa_init (void);
+
+
+/* Instruction buffers. */
+
+typedef uint32 xtensa_insnbuf_word;
+typedef xtensa_insnbuf_word *xtensa_insnbuf;
+
+/* Get the size in words of the xtensa_insnbuf array. */
+extern int xtensa_insnbuf_size (xtensa_isa);
+
+/* Allocate (with malloc) an xtensa_insnbuf of the right size. */
+extern xtensa_insnbuf xtensa_insnbuf_alloc (xtensa_isa);
+
+/* Release (with free) an xtensa_insnbuf of the right size. */
+extern void xtensa_insnbuf_free (xtensa_insnbuf);
+
+/* Inward and outward conversion from memory images (byte streams) to our
+ internal instruction representation. */
+extern void xtensa_insnbuf_to_chars (xtensa_isa, const xtensa_insnbuf,
+ char *);
+
+extern void xtensa_insnbuf_from_chars (xtensa_isa, xtensa_insnbuf,
+ const char *);
+
+
+/* ISA information. */
+
+/* Load the ISA information from a shared library. If successful, this returns
+ a value which identifies the ISA for use in subsequent calls to the ISA
+ library; otherwise, it returns NULL. Multiple ISAs can be loaded to support
+ heterogeneous multiprocessor systems. */
+extern xtensa_isa xtensa_load_isa (libisa_module_specifier);
+
+/* Extend an existing set of ISA information by loading an additional shared
+ library of ISA information. This is primarily intended for loading TIE
+ extensions. If successful, the return value is non-zero. */
+extern int xtensa_extend_isa (xtensa_isa, libisa_module_specifier);
+
+/* The default ISA. This variable is set automatically to the ISA most
+ recently loaded and is provided as a convenience. An exception is the GNU
+ opcodes library, where there is a fixed interface that does not allow
+ passing the ISA as a parameter and the ISA must be taken from this global
+ variable. (Note: Since this variable is just a convenience, it is not
+ exported when libisa is built as a DLL, due to the hassle of dealing with
+ declspecs.) */
+extern xtensa_isa xtensa_default_isa;
+
+
+/* Deallocate an xtensa_isa structure. */
+extern void xtensa_isa_free (xtensa_isa);
+
+/* Get the maximum instruction size in bytes. */
+extern int xtensa_insn_maxlength (xtensa_isa);
+
+/* Get the total number of opcodes for this processor. */
+extern int xtensa_num_opcodes (xtensa_isa);
+
+/* Translate a mnemonic name to an opcode. Returns XTENSA_UNDEFINED if
+ the name is not a valid opcode mnemonic. */
+extern xtensa_opcode xtensa_opcode_lookup (xtensa_isa, const char *);
+
+/* Decode a binary instruction buffer. Returns the opcode or
+ XTENSA_UNDEFINED if the instruction is illegal. */
+extern xtensa_opcode xtensa_decode_insn (xtensa_isa, const xtensa_insnbuf);
+
+
+/* Opcode information. */
+
+/* Set the opcode field(s) in a binary instruction buffer. The operand
+ fields are set to zero. */
+extern void xtensa_encode_insn (xtensa_isa, xtensa_opcode, xtensa_insnbuf);
+
+/* Get the mnemonic name for an opcode. */
+extern const char * xtensa_opcode_name (xtensa_isa, xtensa_opcode);
+
+/* Find the length (in bytes) of an instruction. */
+extern int xtensa_insn_length (xtensa_isa, xtensa_opcode);
+
+/* Find the length of an instruction by looking only at the first byte. */
+extern int xtensa_insn_length_from_first_byte (xtensa_isa, char);
+
+/* Find the number of operands for an instruction. */
+extern int xtensa_num_operands (xtensa_isa, xtensa_opcode);
+
+/* Get the information about operand number "opnd" of a particular opcode. */
+extern xtensa_operand xtensa_get_operand (xtensa_isa, xtensa_opcode, int);
+
+/* Operand information. */
+
+/* Find the kind of operand. There are three possibilities:
+ 1) PC-relative immediates (e.g., "l", "L"). These can be identified with
+ the xtensa_operand_isPCRelative function.
+ 2) non-PC-relative immediates ("i").
+ 3) register-file short names (e.g., "a", "b", "m" and others defined
+ via TIE). */
+extern char * xtensa_operand_kind (xtensa_operand);
+
+/* Check if an operand is an input ('<'), output ('>'), or inout ('=')
+ operand. Note: The output operand of a conditional assignment
+ (e.g., movnez) appears here as an inout ('=') even if it is declared
+ in the TIE code as an output ('>'); this allows the compiler to
+ properly handle register allocation for conditional assignments. */
+extern char xtensa_operand_inout (xtensa_operand);
+
+/* Get and set the raw (encoded) value of the field for the specified
+ operand. The "set" function does not check if the value fits in the
+ field; that is done by the "encode" function below. */
+extern uint32 xtensa_operand_get_field (xtensa_operand, const xtensa_insnbuf);
+
+extern void xtensa_operand_set_field (xtensa_operand, xtensa_insnbuf, uint32);
+
+
+/* Encode and decode operands. The raw bits in the operand field
+ may be encoded in a variety of different ways. These functions hide the
+ details of that encoding. The encode function has a special return type
+ (xtensa_encode_result) to indicate success or the reason for failure; the
+ encoded value is returned through the argument pointer. The decode function
+ has no possibility of failure and returns the decoded value. */
+
+typedef enum
+{
+ xtensa_encode_result_ok,
+ xtensa_encode_result_align,
+ xtensa_encode_result_not_in_table,
+ xtensa_encode_result_too_low,
+ xtensa_encode_result_too_high,
+ xtensa_encode_result_not_ok,
+ xtensa_encode_result_max = xtensa_encode_result_not_ok
+} xtensa_encode_result;
+
+extern xtensa_encode_result xtensa_operand_encode (xtensa_operand, uint32 *);
+
+extern uint32 xtensa_operand_decode (xtensa_operand, uint32);
+
+
+/* For PC-relative offset operands, the interpretation of the offset may vary
+ between opcodes, e.g., is it relative to the current PC or that of the next
+ instruction? The following functions are defined to perform PC-relative
+ relocations and to undo them (as in the disassembler). The first function
+ takes the desired address and the PC of the current instruction and returns
+ the unencoded value to be stored in the offset field. The second function
+ takes the unencoded offset value and the current PC and returns the address.
+ Note that these functions do not replace the encode/decode functions; the
+ operands must be encoded/decoded separately. */
+
+extern int xtensa_operand_isPCRelative (xtensa_operand);
+
+extern uint32 xtensa_operand_do_reloc (xtensa_operand, uint32, uint32);
+
+extern uint32 xtensa_operand_undo_reloc (xtensa_operand, uint32, uint32);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* XTENSA_LIBISA_H */
diff --git a/contrib/gdb/install-sh b/contrib/gdb/install-sh
new file mode 100755
index 0000000..77bc381
--- /dev/null
+++ b/contrib/gdb/install-sh
@@ -0,0 +1,316 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2004-02-15.20
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=
+transform_arg=
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+
+usage="Usage: $0 [OPTION]... SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 -d DIRECTORIES...
+
+In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default.
+In the second, create the directory path DIR.
+
+Options:
+-b=TRANSFORMBASENAME
+-c copy source (using $cpprog) instead of moving (using $mvprog).
+-d create directories instead of installing files.
+-g GROUP $chgrp installed files to GROUP.
+-m MODE $chmod installed files to MODE.
+-o USER $chown installed files to USER.
+-s strip installed files (using $stripprog).
+-t=TRANSFORM
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+ case $1 in
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ -c) instcmd=$cpprog
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit 0;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit 0;;
+
+ *) # When -d is used, all remaining arguments are directories to create.
+ test -n "$dir_arg" && break
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+ break;;
+ esac
+done
+
+if test -z "$1"; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ src=
+
+ if test -d "$dst"; then
+ instcmd=:
+ chmodcmd=
+ else
+ instcmd=$mkdirprog
+ fi
+ else
+ # Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ dst=$dst/`basename "$src"`
+ fi
+ fi
+
+ # This sed command emulates the dirname command.
+ dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+ # Make sure that the destination directory exists.
+
+ # Skip lots of stat calls in the usual case.
+ if test ! -d "$dstdir"; then
+ defaultIFS='
+ '
+ IFS="${IFS-$defaultIFS}"
+
+ oIFS=$IFS
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+ IFS=$oIFS
+
+ pathcomp=
+
+ while test $# -ne 0 ; do
+ pathcomp=$pathcomp$1
+ shift
+ if test ! -d "$pathcomp"; then
+ $mkdirprog "$pathcomp" || lasterr=$?
+ # mkdir can fail with a `File exist' error in case several
+ # install-sh are creating the directory concurrently. This
+ # is OK.
+ test ! -d "$pathcomp" && { (exit ${lasterr-1}); exit; }
+ fi
+ pathcomp=$pathcomp/
+ done
+ fi
+
+ if test -n "$dir_arg"; then
+ $doit $instcmd "$dst" \
+ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+ else
+ # If we're going to rename the final executable, determine the name now.
+ if test -z "$transformarg"; then
+ dstfile=`basename "$dst"`
+ else
+ dstfile=`basename "$dst" $transformbasename \
+ | sed $transformarg`$transformbasename
+ fi
+
+ # don't allow the sed command to completely eliminate the filename.
+ test -z "$dstfile" && dstfile=`basename "$dst"`
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Move or copy the file name to the temp name
+ $doit $instcmd "$src" "$dsttmp" &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $instcmd $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+ # Now remove or move aside any old file at destination location. We
+ # try this two ways since rm can't unlink itself on some systems and
+ # the destination file might be busy for other reasons. In this case,
+ # the final cleanup might fail but the new file should still install
+ # successfully.
+ {
+ if test -f "$dstdir/$dstfile"; then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+ || {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+ fi || { (exit 1); exit; }
+done
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+ (exit 0); exit
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/contrib/gdb/libtool.m4 b/contrib/gdb/libtool.m4
new file mode 100644
index 0000000..d2e3608
--- /dev/null
+++ b/contrib/gdb/libtool.m4
@@ -0,0 +1,893 @@
+## libtool.m4 - Configure libtool for the host system. -*-Shell-script-*-
+## Copyright 1996, 1997, 1998, 1999, 2000, 2001
+## Free Software Foundation, Inc.
+## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+##
+## As a special exception to the GNU General Public License, if you
+## distribute this file as part of a program that contains a
+## configuration script generated by Autoconf, you may include it under
+## the same distribution terms that you use for the rest of that program.
+
+# serial 46 AC_PROG_LIBTOOL
+AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+ AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [AC_LIBTOOL_CXX],
+ [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+ AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [ifdef([AC_PROG_GCJ],
+ [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ
+])])
+ ifdef([A][M_PROG_GCJ],
+ [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ
+])])
+ ifdef([LT_AC_PROG_GCJ],
+ [define([LT_AC_PROG_GCJ], defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ
+])])])])])])
+
+AC_DEFUN([_AC_PROG_LIBTOOL],
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
+
+# Save cache, so that ltconfig can load it
+AC_CACHE_SAVE
+
+# Actually configure libtool. ac_aux_dir is where install-sh is found.
+AR="$AR" LTCC="$CC" CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
+LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \
+AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \
+objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \
+deplibs_check_method="$deplibs_check_method" file_magic_cmd="$file_magic_cmd" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \
+$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \
+|| AC_MSG_ERROR([libtool configure failed])
+
+# Reload cache, that may have been modified by ltconfig
+AC_CACHE_LOAD
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh $ac_aux_dir/ltcf-c.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Redirect the config.log output again, so that the ltconfig log is not
+# clobbered by the next message.
+exec 5>>./config.log
+])
+
+AC_DEFUN([AC_LIBTOOL_SETUP],
+[AC_PREREQ(2.13)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+AC_REQUIRE([AC_OBJEXT])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+dnl
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ AC_PATH_MAGIC
+ fi
+ ;;
+esac
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags="--cache-file=$cache_file"
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install"
+test "$GCC" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$lt_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN],
+[libtool_flags="$libtool_flags --enable-dlopen"])
+ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
+[libtool_flags="$libtool_flags --enable-win32-dll"])
+AC_ARG_ENABLE(libtool-lock,
+ [ --disable-libtool-lock avoid locking (might break parallel builds)])
+test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock"
+test x"$silent" = xyes && libtool_flags="$libtool_flags --silent"
+
+AC_ARG_WITH(pic,
+ [ --with-pic try to use only PIC/non-PIC objects [default=use both]],
+ pic_mode="$withval", pic_mode=default)
+test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic"
+test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case "`/usr/bin/file conftest.o`" in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_SAVE
+ AC_LANG_C
+ AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_RESTORE])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+
+ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+
+ # recent cygwin and mingw systems supply a stub DllMain which the user
+ # can override, but on older systems we have to supply one
+ AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain,
+ [AC_TRY_LINK([],
+ [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*);
+ DllMain (0, 0, 0);],
+ [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])])
+
+ case $host/$CC in
+ *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*)
+ # old mingw systems require "-dll" to link a DLL, while more recent ones
+ # require "-mdll"
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -mdll"
+ AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch,
+ [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])])
+ CFLAGS="$SAVE_CFLAGS" ;;
+ *-*-cygwin* | *-*-pw32*)
+ # cygwin systems need to pass --dll to the linker, and not link
+ # crt.o which will require a WinMain@16 definition.
+ lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;;
+ esac
+ ;;
+ ])
+esac
+])
+
+# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
+
+# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
+
+# AC_ENABLE_SHARED - implement the --enable-shared flag
+# Usage: AC_ENABLE_SHARED[(DEFAULT)]
+# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+# `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(shared,
+changequote(<<, >>)dnl
+<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case $enableval in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
+])
+
+# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)])
+
+# AC_ENABLE_STATIC - implement the --enable-static flag
+# Usage: AC_ENABLE_STATIC[(DEFAULT)]
+# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+# `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(static,
+changequote(<<, >>)dnl
+<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case $enableval in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
+])
+
+# AC_DISABLE_STATIC - set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)])
+
+
+# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
+# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
+# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+# `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(fast-install,
+changequote(<<, >>)dnl
+<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case $enableval in
+yes) enable_fast_install=yes ;;
+no) enable_fast_install=no ;;
+*)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
+])
+
+# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)])
+
+# AC_LIBTOOL_PICMODE - implement the --with-pic flag
+# Usage: AC_LIBTOOL_PICMODE[(MODE)]
+# Where MODE is either `yes' or `no'. If omitted, it defaults to
+# `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)])
+
+
+# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+ /*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
+ ;;
+ *)
+ ac_save_MAGIC_CMD="$MAGIC_CMD"
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="ifelse([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ egrep "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ MAGIC_CMD="$ac_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+])
+
+
+# AC_PATH_MAGIC - find a file program which can recognise a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl
+AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])
+
+
+# AC_PROG_LD - find the path to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by GCC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]* | [A-Za-z]:[\\/]*)]
+ re_direlt=['/[^/][^/]*/\.\./']
+ # Canonicalize the path of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+ test "$with_gnu_ld" != no && break
+ else
+ test "$with_gnu_ld" != yes && break
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])
+
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+ lt_cv_prog_gnu_ld=yes
+else
+ lt_cv_prog_gnu_ld=no
+fi])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])
+
+# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag,
+[lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+test -n "$reload_flag" && reload_flag=" $reload_flag"
+])
+
+# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognise dependant libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [regex]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given egrep regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi4*)
+ lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)']
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin* | mingw* |pw32*)
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ lt_cv_file_magic_test_file='/System/Library/Frameworks/System.framework/System'
+ ;;
+ *) # Darwin 1.3 on
+ lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib'
+ ;;
+ esac
+ ;;
+
+freebsd* )
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method=['file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library']
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20*|hpux11*)
+ case $host_cpu in
+ hppa*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library']
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ ia64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64']
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ esac
+ ;;
+
+irix5* | irix6*)
+ case $host_os in
+ irix5*)
+ # this will be overridden with pass_all, but let us keep it just in case
+ lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
+ ;;
+ *)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ # this will be overridden with pass_all, but let us keep it just in case
+ lt_cv_deplibs_check_method=["file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"]
+ ;;
+ esac
+ lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*`
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux-gnu*)
+ case $host_cpu in
+ alpha* | mips* | hppa* | i*86 | powerpc* | sparc* | ia64* )
+ lt_cv_deplibs_check_method=pass_all ;;
+ *)
+ # glibc up to 2.1.1 does not perform some relocations on ARM
+ lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'] ;;
+ esac
+ lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$']
+ else
+ [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$']
+ fi
+ ;;
+
+newsos6)
+ [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)']
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+osf3* | osf4* | osf5*)
+ # this will be overridden with pass_all, but let us keep it just in case
+ lt_cv_deplibs_check_method='file_magic COFF format alpha shared library'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sco3.2v5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+
+[sysv5uw[78]* | sysv4*uw2*)]
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ case $host_vendor in
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ motorola)
+ lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]']
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ esac
+ ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+])
+
+
+# AC_PROG_NM - find the path to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_MSG_CHECKING([for BSD-compatible nm])
+AC_CACHE_VAL(lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm=$ac_dir/${ac_tool_prefix}nm
+ if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ else
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+AC_MSG_RESULT([$NM])
+])
+
+# AC_CHECK_LIBM - check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32*)
+ # These system don't have libm
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, main, LIBM="-lm")
+ ;;
+esac
+])
+
+# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
+# the libltdl convenience library and INCLTDL to the include flags for
+# the libltdl header and adds --enable-ltdl-convenience to the
+# configure arguments. Note that LIBLTDL and INCLTDL are not
+# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not
+# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed
+# with '${top_builddir}/' and INCLTDL will be prefixed with
+# '${top_srcdir}/' (note the single quotes!). If your package is not
+# flat and you're not using automake, define top_builddir and
+# top_srcdir appropriately in the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ case $enable_ltdl_convenience in
+ no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+ "") enable_ltdl_convenience=yes
+ ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+ esac
+ LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+ INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+])
+
+# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
+# the libltdl installable library and INCLTDL to the include flags for
+# the libltdl header and adds --enable-ltdl-install to the configure
+# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is
+# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed
+# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will
+# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed
+# with '${top_srcdir}/' (note the single quotes!). If your package is
+# not flat and you're not using automake, define top_builddir and
+# top_srcdir appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ AC_CHECK_LIB(ltdl, main,
+ [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+ [if test x"$enable_ltdl_install" = xno; then
+ AC_MSG_WARN([libltdl not installed, but installation disabled])
+ else
+ enable_ltdl_install=yes
+ fi
+ ])
+ if test x"$enable_ltdl_install" = x"yes"; then
+ ac_configure_args="$ac_configure_args --enable-ltdl-install"
+ LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+ INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+ else
+ ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+ LIBLTDL="-lltdl"
+ INCLTDL=
+ fi
+])
+
+# If this macro is not defined by Autoconf, define it here.
+ifdef([AC_PROVIDE_IFELSE],
+ [],
+ [define([AC_PROVIDE_IFELSE],
+ [ifdef([AC_PROVIDE_$1],
+ [$2], [$3])])])
+
+# AC_LIBTOOL_CXX - enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX], [AC_REQUIRE([_AC_LIBTOOL_CXX])])
+
+AC_DEFUN([_AC_LIBTOOL_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([AC_PROG_CXXCPP])
+LIBTOOL_DEPS=$LIBTOOL_DEPS" $ac_aux_dir/ltcf-cxx.sh"
+lt_save_CC="$CC"
+lt_save_CFLAGS="$CFLAGS"
+dnl Make sure LTCC is set to the C compiler, i.e. set LTCC before CC
+dnl is set to the C++ compiler.
+AR="$AR" LTCC="$CC" CC="$CXX" CXX="$CXX" CFLAGS="$CXXFLAGS" CPPFLAGS="$CPPFLAGS" \
+MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
+LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \
+AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \
+objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \
+deplibs_check_method="$deplibs_check_method" \
+file_magic_cmd="$file_magic_cmd" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig -o libtool $libtool_flags \
+--build="$build" --add-tag=CXX $ac_aux_dir/ltcf-cxx.sh $host \
+|| AC_MSG_ERROR([libtool tag configuration failed])
+CC="$lt_save_CC"
+CFLAGS="$lt_save_CFLAGS"
+
+# Redirect the config.log output again, so that the ltconfig log is not
+# clobbered by the next message.
+exec 5>>./config.log
+])
+
+# AC_LIBTOOL_GCJ - enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],[AC_REQUIRE([_AC_LIBTOOL_GCJ])])
+
+AC_DEFUN([_AC_LIBTOOL_GCJ],
+[AC_REQUIRE([AC_PROG_LIBTOOL])
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+ [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+ [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+ [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+ [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+LIBTOOL_DEPS=$LIBTOOL_DEPS" $ac_aux_dir/ltcf-gcj.sh"
+lt_save_CC="$CC"
+lt_save_CFLAGS="$CFLAGS"
+dnl Make sure LTCC is set to the C compiler, i.e. set LTCC before CC
+dnl is set to the C++ compiler.
+AR="$AR" LTCC="$CC" CC="$GCJ" CFLAGS="$GCJFLAGS" CPPFLAGS="$CPPFLAGS" \
+MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
+LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \
+AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \
+objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \
+deplibs_check_method="$deplibs_check_method" \
+file_magic_cmd="$file_magic_cmd" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig -o libtool $libtool_flags \
+--build="$build" --add-tag=GCJ $ac_aux_dir/ltcf-gcj.sh $host \
+|| AC_MSG_ERROR([libtool tag configuration failed])
+CC="$lt_save_CC"
+CFLAGS="$lt_save_CFLAGS"
+
+# Redirect the config.log output again, so that the ltconfig log is not
+# clobbered by the next message.
+exec 5>>./config.log
+])
+
+dnl old names
+AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL])
+AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+AC_DEFUN([AM_PROG_LD], [AC_PROG_LD])
+AC_DEFUN([AM_PROG_NM], [AC_PROG_NM])
+
+dnl This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])dnl
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)
+])
diff --git a/contrib/gdb/ltcf-c.sh b/contrib/gdb/ltcf-c.sh
new file mode 100644
index 0000000..d60a3ba
--- /dev/null
+++ b/contrib/gdb/ltcf-c.sh
@@ -0,0 +1,824 @@
+#### This script is meant to be sourced by ltconfig.
+
+# ltcf-c.sh - Create a C compiler specific configuration
+#
+# Copyright (C) 1996-2000, 2001 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='main(){return(0);}'
+
+## Linker Characteristics
+case $host_os in
+cygwin* | mingw*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$with_gcc" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can use
+ # them.
+ ld_shlibs=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw*)
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+
+ extract_expsyms_cmds='test -f $output_objdir/impgen.c || \
+ sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //; p; }" -e d < $0 > $output_objdir/impgen.c~
+ test -f $output_objdir/impgen.exe || (cd $output_objdir && \
+ if test "x$BUILD_CC" != "x" ; then $BUILD_CC -o impgen impgen.c ; \
+ else $CC -o impgen impgen.c ; fi)~
+ $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def'
+
+ old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib'
+
+ # cygwin and mingw dlls have different entry points and sets of symbols
+ # to exclude.
+ # FIXME: what about values for MSVC?
+ dll_entry=__cygwin_dll_entry@12
+ dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~
+ case $host_os in
+ mingw*)
+ # mingw values
+ dll_entry=_DllMainCRTStartup@12
+ dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~
+ ;;
+ esac
+
+ # mingw and cygwin differ, and it's simplest to just exclude the union
+ # of the two symbol sets.
+ dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12
+
+ # recent cygwin and mingw systems supply a stub DllMain which the user
+ # can override, but on older systems we have to supply one (in ltdll.c)
+ if test "x$lt_cv_need_dllmain" = "xyes"; then
+ ltdll_obj='$output_objdir/$soname-ltdll.'"$objext "
+ ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $output_objdir/$soname-ltdll.c~
+ test -f $output_objdir/$soname-ltdll.$objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~'
+ else
+ ltdll_obj=
+ ltdll_cmds=
+ fi
+
+ # Extract the symbol export list from an `--export-all' def file,
+ # then regenerate the def file from the symbol export list, so that
+ # the compiled dll only exports the symbol export list.
+ # Be careful not to strip the DATA tag left be newer dlltools.
+ export_symbols_cmds="$ltdll_cmds"'
+ $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~
+ sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols'
+
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is.
+ # If DATA tags from a recent dlltool are present, honour them!
+ archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname-def;
+ else
+ echo EXPORTS > $output_objdir/$soname-def;
+ _lt_hint=1;
+ cat $export_symbols | while read symbol; do
+ set dummy \$symbol;
+ case \[$]# in
+ 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;;
+ *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;;
+ esac;
+ _lt_hint=`expr 1 + \$_lt_hint`;
+ done;
+ fi~
+ '"$ltdll_cmds"'
+ $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
+ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~
+ $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
+ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~
+ $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags'
+ ;;
+
+ darwin* | rhapsody*)
+ allow_undefined_flag='-undefined suppress'
+ archive_cmds='$CC `test .$module = .yes && echo -bundle || echo -dynamiclib` $allow_undefined_flag -o $lib $libobjs $deplibs $linkopts -install_name $rpath/$soname `test -n "$verstring" -a x$verstring != x0.0 && echo $verstring`'
+ # We need to add '_' to the symbols in $export_symbols first
+ #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ whole_archive_flag_spec='-all_load $convenience'
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ case $host_os in
+ cygwin* | mingw*)
+ # dlltool doesn't understand --whole-archive et. al.
+ whole_archive_flag_spec=
+ ;;
+ *)
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ ;;
+ esac
+ fi
+else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$with_gcc" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+ if test "$with_gcc" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ if test $with_gnu_ld = no; then
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ fi
+ else
+ # Test if we are trying to use run time linking, or normal AIX style linking.
+ # If -brtl is somewhere in LDFLAGS, we need to do run time linking.
+ aix_use_runtimelinking=no
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl" ); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other run time loading flags (-brtl), -berok will
+ # link without error, but may produce a broken library.
+ allow_undefined_flag=' ${wl}-berok'
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ if test "$host_cpu" = ia64; then
+ if test $with_gnu_ld = no; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ fi
+ else
+ allow_undefined_flag=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec=' '
+ build_libtool_need_lc=yes
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+
+ cygwin* | mingw*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ case "$host_cpu" in
+ ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir' ;;
+ *)
+ if test $with_gcc = yes; then
+ case "$host_os" in
+ hpux9*) archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
+ *) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;;
+ esac
+ else
+ case $host_os in
+ hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
+ *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_minus_L=yes # Not in the search PATH, but as the default
+ # location of the library.
+ ;;
+ esac
+ export_dynamic_flag_spec='${wl}-E'
+ hardcode_direct=yes
+ ;;
+
+ irix5* | irix6*)
+ if test "$with_gcc" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ openbsd*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$with_gcc" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$with_gcc" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # cc supports -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$with_gcc" = yes; then
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv5*)
+ no_undefined_flag=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec=
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5uw7* | unixware7*)
+ no_undefined_flag='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+fi
+
+## Compiler Characteristics: PIC flags, static flags, etc
+if test "X${ac_cv_prog_cc_pic+set}" = Xset; then
+ :
+else
+ ac_cv_prog_cc_pic=
+ ac_cv_prog_cc_shlib=
+ ac_cv_prog_cc_wl=
+ ac_cv_prog_cc_static=
+ ac_cv_prog_cc_no_builtin=
+ ac_cv_prog_cc_can_build_shared=$can_build_shared
+
+ if test "$with_gcc" = yes; then
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_cv_prog_cc_static='-Bstatic'
+ else
+ lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ ac_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ beos* | irix5* | irix6* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ cygwin* | mingw* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ ac_cv_prog_cc_pic='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_cv_prog_cc_pic='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ ac_cv_prog_cc_pic=
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ ac_cv_prog_cc_pic=-Kconform_pic
+ fi
+ ;;
+ *)
+ ac_cv_prog_cc_pic='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for PIC flags for the system compiler.
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ ac_cv_prog_cc_static="$ac_cv_prog_cc_static ${ac_cv_prog_cc_wl}-lC"
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ # Is there a better ac_cv_prog_cc_static that works with the bundled CC?
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ ac_cv_prog_cc_pic='+Z'
+ ;;
+
+ irix5* | irix6*)
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static='-non_shared'
+ # PIC (with -KPIC) is the default.
+ ;;
+
+ cygwin* | mingw* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ ac_cv_prog_cc_pic='-DDLL_EXPORT'
+ ;;
+
+ newsos6)
+ ac_cv_prog_cc_pic='-KPIC'
+ ac_cv_prog_cc_static='-Bstatic'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ # All OSF/1 code is PIC.
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ ac_cv_prog_cc_pic='-Kpic'
+ ac_cv_prog_cc_static='-dn'
+ ac_cv_prog_cc_shlib='-belf'
+ ;;
+
+ solaris*)
+ ac_cv_prog_cc_pic='-KPIC'
+ ac_cv_prog_cc_static='-Bstatic'
+ ac_cv_prog_cc_wl='-Wl,'
+ ;;
+
+ sunos4*)
+ ac_cv_prog_cc_pic='-PIC'
+ ac_cv_prog_cc_static='-Bstatic'
+ ac_cv_prog_cc_wl='-Qoption ld '
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ ac_cv_prog_cc_pic='-KPIC'
+ ac_cv_prog_cc_static='-Bstatic'
+ ac_cv_prog_cc_wl='-Wl,'
+ ;;
+
+ uts4*)
+ ac_cv_prog_cc_pic='-pic'
+ ac_cv_prog_cc_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ ac_cv_prog_cc_pic='-Kconform_pic'
+ ac_cv_prog_cc_static='-Bstatic'
+ fi
+ ;;
+
+ *)
+ ac_cv_prog_cc_can_build_shared=no
+ ;;
+ esac
+ fi
+ case "$host_os" in
+ # Platforms which do not suport PIC and -DPIC is meaningless
+ # on them:
+ *djgpp*)
+ ac_cv_prog_cc_pic=
+ ;;
+ *)
+ ac_cv_prog_cc_pic="$ac_cv_prog_cc_pic -DPIC"
+ ;;
+ esac
+fi
+
+need_lc=yes
+if test "$enable_shared" = yes && test "$with_gcc" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo $ac_n "checking whether -lc should be explicitly linked in... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_archive_cmds_needs_lc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+ need_lc=$ac_cv_archive_cmds_needs_lc
+ else
+ $rm conftest*
+ echo "static int dummy;" > conftest.$ac_ext
+ if { (eval echo ltcf-c.sh:need_lc: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then
+ # Append any warnings to the config.log.
+ cat conftest.err 1>&5
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$objext
+ deplibs=
+ wl=$ac_cv_prog_cc_wl
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { (eval echo ltcf-c.sh:need_lc: \"$archive_cmds\") 1>&5; (eval $archive_cmds) 2>&1 | grep " -lc " 1>&5 ; }; then
+ need_lc=no
+ fi
+ allow_undefined_flag=$save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ fi
+ $rm conftest*
+ echo "$ac_t$need_lc" 1>&6
+ ;;
+ esac
+fi
+ac_cv_archive_cmds_needs_lc=$need_lc
diff --git a/contrib/gdb/ltcf-cxx.sh b/contrib/gdb/ltcf-cxx.sh
new file mode 100644
index 0000000..9059b1a
--- /dev/null
+++ b/contrib/gdb/ltcf-cxx.sh
@@ -0,0 +1,1021 @@
+#### This script is meant to be sourced by ltconfig.
+
+# ltcf-cxx.sh - Create a C++ compiler specific configuration
+#
+# Copyright (C) 1996-1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# Original C++ support by:Gary V. Vaughan <gvv@techie.com>
+# Alexandre Oliva <oliva@lsd.ic.unicamp.br>
+# Ossama Othman <ossama@debian.org>
+# Thomas Thanner <tanner@gmx.de>
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Source file extension for C++ test sources.
+ac_ext=cc
+
+# Object file extension for compiled C++ test sources.
+objext=o
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[]) { return (0); }'
+
+# C++ compiler
+CXX=${CXX-c++}
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+CC=${CC-"$CXX"}
+CFLAGS=${CFLAGS-"$CXXFLAGS"}
+
+# Allow CC to be a program name with arguments.
+set dummy $CC
+compiler=$2
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+# Check if we are using GNU gcc (taken/adapted from configure script)
+# We need to check here since "--with-gcc" is set at configure time,
+# not ltconfig time!
+cat > conftest.$ac_ext <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-c++} -E conftest.$ac_ext'; { (eval echo \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ with_gcc=yes
+
+ # Set up default GNU C++ configuration
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used. The
+ # assumption here is that the linker is going to be the same as that
+ # used by the C compiler. For the purposes of GCC, this is ok, but
+ # if someone uses g++ along with a non-GNU C compiler that doesn't
+ # use GNU ld, we may lose. This is ok for the toolchain tree, since
+ # the only users of ltcf-cxx.sh are libstdc++-v3 and libjava,
+ # anyway, and those use both gcc and g++, so the settings are bound
+ # to be the same.
+
+ if test "$with_gnu_ld" = yes; then
+ archive_cmds='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+ egrep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ else
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ archive_cmds='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep "\-L"'
+
+else
+ with_gcc=no
+ wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ aix4* | aix5*)
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+ if test "$with_gcc" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ if test $with_gnu_ld = no; then
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ fi
+ else
+ # Test if we are trying to use run time linking, or normal AIX style linking.
+ # If -brtl is somewhere in LDFLAGS, we need to do run time linking.
+ aix_use_runtimelinking=no
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl" ); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
+ allow_undefined_flag=' -Wl,-G'
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}-brtl \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ if test "$host_cpu" = ia64; then
+ if test $with_gnu_ld = no; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ fi
+ else
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
+ # Warning - without using the other run time loading flags, -berok will
+ # link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bnoerok'
+ allow_undefined_flag=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec=' '
+ build_libtool_need_lc=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ esac
+ ;;
+ freebsd[12]*)
+ # C++ shared libraries reported to be fairly broken before switch to ELF
+ ld_shlibs=no
+ ;;
+ freebsd*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ ld_shlibs=yes
+ ;;
+ gnu*)
+ ;;
+ hpux*)
+ if test $with_gnu_ld = no; then
+ case "$host_cpu" in
+ ia64*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' ;;
+ esac
+ hardcode_direct=yes
+ hardcode_libdir_separator=:
+ export_dynamic_flag_spec='${wl}-E'
+ fi
+ hardcode_minus_L=yes # Not in the search PATH, but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ aCC)
+ case $host_os in
+ hpux9*) archive_cmds='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
+ *) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test $with_gcc = yes; then
+ if test $with_gnu_ld = no; then
+ case "$host_os" in
+ hpux9*) archive_cmds='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
+ *)
+ case "$host_cpu" in
+ ia64*)
+ archive_cmds='$LD -b +h $soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' ;;
+ *)
+ archive_cmds='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;;
+ esac
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC)
+ # SGI C++
+ archive_cmds='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$with_gcc" = yes; then
+ if test "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ archive_cmds='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -o $lib'
+ fi
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ link_all_deplibs=yes
+ ;;
+ esac
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_expsym_cmds='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest.so 2>&1 | egrep "ld"`; rm -f libconftest.so; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ hardcode_libdir_flag_spec='${wl}--rpath,$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ cxx)
+ # Compaq C++
+ archive_cmds='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ hardcode_libdir_separator=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | sed "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ esac
+ ;;
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ m88k*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ esac
+ ;;
+ netbsd*)
+ # NetBSD uses g++ - do we need to do anything?
+ ;;
+ osf3*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ hardcode_libdir_separator=:
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds='$CC -Bstatic -o $oldlib $oldobjs'
+
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ cxx)
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | sed "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$with_gcc" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep "\-L"'
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+ osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ hardcode_libdir_separator=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ old_archive_cmds='$CC -o $oldlib $oldobjs'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ cxx)
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~
+ $rm $lib.exp'
+
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ hardcode_libdir_separator=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | sed "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$with_gcc" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep "\-L"'
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+ psos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ sco*)
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ lcc)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ no_undefined_flag=' -zdefs'
+ archive_cmds='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The C++ compiler is used as linker so we must use $wl
+ # flag to pass the commands to the underlying system
+ # linker.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ link_all_deplibs=yes
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | egrep "\-R|\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ archive_cmds='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ old_archive_cmds='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$with_gcc" = yes && test "$with_gnu_ld" = no; then
+ no_undefined_flag=' ${wl}-z ${wl}defs'
+ if $CC --version | egrep -v '^2\.7' > /dev/null; then
+ archive_cmds='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep \"\-L\""
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ archive_cmds='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | egrep \"\-L\""
+ fi
+
+ hardcode_libdir_flag_spec='${wl}-R $wl$libdir'
+ fi
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ esac
+ ;;
+ unixware*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs=no
+ ;;
+esac
+
+
+## Compiler Characteristics: PIC flags, static flags, etc
+
+# We don't use cached values here since only the C compiler
+# characteristics should be cached.
+ac_cv_prog_cc_pic=
+ac_cv_prog_cc_shlib=
+ac_cv_prog_cc_wl=
+ac_cv_prog_cc_static=
+ac_cv_prog_cc_no_builtin=
+ac_cv_prog_cc_can_build_shared=$can_build_shared
+
+ac_cv_prog_cc_pic_works=
+ac_cv_prog_cc_static_works=
+
+if test "$with_gcc" = yes; then
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_cv_prog_cc_static='-Bstatic'
+ else
+ lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ ac_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ beos* | irix5* | irix6* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ cygwin* | mingw* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ ac_cv_prog_cc_pic='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_cv_prog_cc_pic='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ ac_cv_prog_cc_pic=
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ ac_cv_prog_cc_pic=-Kconform_pic
+ fi
+ ;;
+ *)
+ ac_cv_prog_cc_pic='-fPIC'
+ ;;
+ esac
+else
+ case $host_os in
+ aix4* | aix5*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_cv_prog_cc_static='-Bstatic'
+ else
+ lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68)
+ # Green Hills C++ Compiler
+ # ac_cv_prog_cc_static="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++)
+ ac_cv_prog_cc_pic='-KPIC'
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ ac_cv_prog_cc_pic='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd*)
+ # FreeBSD uses GNU C++
+ ;;
+ gnu*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC)
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ ac_cv_prog_cc_pic='+Z'
+ ;;
+ aCC)
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ ac_cv_prog_cc_pic='+Z'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC)
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static='-non_shared'
+ ac_cv_prog_cc_pic='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # KAI C++ Compiler
+ ac_cv_prog_cc_wl='--backend -Wl,'
+ ac_cv_prog_cc_pic='-fPIC'
+ ;;
+ cxx)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ ac_cv_prog_cc_pic=
+ ac_cv_prog_cc_static='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ ac_cv_prog_cc_pic='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ ac_cv_prog_cc_wl='--backend -Wl,'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ ac_cv_prog_cc_pic='-pic'
+ ;;
+ cxx)
+ # Digital/Compaq C++
+ ac_cv_prog_cc_wl='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ ac_cv_prog_cc_pic=
+ ac_cv_prog_cc_static='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ sco*)
+ case $cc_basename in
+ CC)
+ ac_cv_prog_cc_pic='-fPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ ac_cv_prog_cc_pic='-KPIC'
+ ac_cv_prog_cc_static='-Bstatic'
+ ac_cv_prog_cc_wl='-Qoption ld '
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ ac_cv_prog_cc_pic='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ ac_cv_prog_cc_pic='-pic'
+ ac_cv_prog_cc_static='-Bstatic'
+ ;;
+ lcc)
+ # Lucid
+ ac_cv_prog_cc_pic='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ ac_cv_prog_cc_pic='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ unixware*)
+ ;;
+ vxworks*)
+ ;;
+ *)
+ ac_cv_prog_cc_can_build_shared=no
+ ;;
+ esac
+fi
+
+case "$host_os" in
+ # Platforms which do not suport PIC and -DPIC is meaningless
+ # on them:
+ *djgpp*)
+ ac_cv_prog_cc_pic=
+ ;;
+ *)
+ ac_cv_prog_cc_pic="$ac_cv_prog_cc_pic -DPIC"
+ ;;
+esac
+
+
+# Figure out "hidden" C++ library dependencies from verbose
+# compiler output whening linking a shared library.
+cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+EOF
+
+
+if (eval $ac_compile) 2>&5; then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval $output_verbose_link_cmd`; do
+
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" \
+ || test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$compiler_lib_search_path"; then
+ compiler_lib_search_path="${prev}${p}"
+ else
+ compiler_lib_search_path="${compiler_lib_search_path} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$postdeps"; then
+ postdeps="${prev}${p}"
+ else
+ postdeps="${postdeps} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$predep_objects"; then
+ predep_objects="$p"
+ else
+ predep_objects="$predep_objects $p"
+ fi
+ else
+ if test -z "$postdep_objects"; then
+ postdep_objects="$p"
+ else
+ postdep_objects="$postdep_objects $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out
+else
+ echo "ltcf-cxx.sh: error: problem compiling test program"
+fi
+
+$rm -f confest.$objext
+
+case " $postdeps " in
+*" -lc "*) need_lc=no ;;
+*) need_lc=yes ;;
+esac
diff --git a/contrib/gdb/ltcf-gcj.sh b/contrib/gdb/ltcf-gcj.sh
new file mode 100644
index 0000000..2d70497
--- /dev/null
+++ b/contrib/gdb/ltcf-gcj.sh
@@ -0,0 +1,651 @@
+#### This script is meant to be sourced by ltconfig.
+
+# ltcf-gcj.sh - Create a GCJ compiler specific configuration
+#
+# Copyright (C) 1996-1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# Original GCJ support by:
+# Alexandre Oliva <oliva@lsd.ic.unicamp.br>
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }'
+
+## Linker Characteristics
+case $host_os in
+cygwin* | mingw*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$with_gcc" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can use
+ # them.
+ ld_shlibs=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw*)
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+
+ extract_expsyms_cmds='test -f $output_objdir/impgen.c || \
+ sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //; p; }" -e d < $0 > $output_objdir/impgen.c~
+ test -f $output_objdir/impgen.exe || (cd $output_objdir && \
+ if test "x$BUILD_CC" != "x" ; then $BUILD_CC -o impgen impgen.c ; \
+ else $CC -o impgen impgen.c ; fi)~
+ $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def'
+
+ old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib'
+
+ # cygwin and mingw dlls have different entry points and sets of symbols
+ # to exclude.
+ # FIXME: what about values for MSVC?
+ dll_entry=__cygwin_dll_entry@12
+ dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~
+ case $host_os in
+ mingw*)
+ # mingw values
+ dll_entry=_DllMainCRTStartup@12
+ dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~
+ ;;
+ esac
+
+ # mingw and cygwin differ, and it's simplest to just exclude the union
+ # of the two symbol sets.
+ dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12
+
+ # recent cygwin and mingw systems supply a stub DllMain which the user
+ # can override, but on older systems we have to supply one (in ltdll.c)
+ if test "x$lt_cv_need_dllmain" = "xyes"; then
+ ltdll_obj='$output_objdir/$soname-ltdll.'"$objext "
+ ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $output_objdir/$soname-ltdll.c~
+ test -f $output_objdir/$soname-ltdll.$objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~'
+ else
+ ltdll_obj=
+ ltdll_cmds=
+ fi
+
+ # Extract the symbol export list from an `--export-all' def file,
+ # then regenerate the def file from the symbol export list, so that
+ # the compiled dll only exports the symbol export list.
+ # Be careful not to strip the DATA tag left be newer dlltools.
+ export_symbols_cmds="$ltdll_cmds"'
+ $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~
+ sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols'
+
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is.
+ # If DATA tags from a recent dlltool are present, honour them!
+ archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname-def;
+ else
+ echo EXPORTS > $output_objdir/$soname-def;
+ _lt_hint=1;
+ cat $export_symbols | while read symbol; do
+ set dummy \$symbol;
+ case \[$]# in
+ 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;;
+ *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;;
+ esac;
+ _lt_hint=`expr 1 + \$_lt_hint`;
+ done;
+ fi~
+ '"$ltdll_cmds"'
+ $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
+ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~
+ $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
+ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~
+ $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags'
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ case $host_os in
+ cygwin* | mingw*)
+ # dlltool doesn't understand --whole-archive et. al.
+ whole_archive_flag_spec=
+ ;;
+ *)
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ ;;
+ esac
+ fi
+else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$with_gcc" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+ if test "$with_gcc" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ if test $with_gnu_ld = no; then
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ fi
+ else
+ # Test if we are trying to use run time linking, or normal AIX style linking.
+ # If -brtl is somewhere in LDFLAGS, we need to do run time linking.
+ aix_use_runtimelinking=no
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl" ); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other run time loading flags (-brtl), -berok will
+ # link without error, but may produce a broken library.
+ allow_undefined_flag=' ${wl}-berok'
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ if test "$host_cpu" = ia64; then
+ if test $with_gnu_ld = no; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ fi
+ else
+ allow_undefined_flag=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec=' '
+ build_libtool_need_lc=yes
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+
+ cygwin* | mingw*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ case $host_os in
+ hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
+ *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;;
+ esac
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_minus_L=yes # Not in the search PATH, but as the default
+ # location of the library.
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ irix5* | irix6*)
+ if test "$with_gcc" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -nodefaultlibs -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='${wl}-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ openbsd*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$with_gcc" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$with_gcc" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag=' ${wl}-z ${wl}defs'
+ archive_cmds='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmds="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep \"\-L\""
+
+ hardcode_libdir_flag_spec='${wl}-R $wl$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv5*)
+ no_undefined_flag=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec=
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5uw7* | unixware7*)
+ no_undefined_flag='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+fi
+
+## Compiler Characteristics: PIC flags, static flags, etc
+
+# We don't use cached values here since only the C compiler
+# characteristics should be cached.
+ ac_cv_prog_cc_pic=
+ ac_cv_prog_cc_shlib=
+ ac_cv_prog_cc_wl=
+ ac_cv_prog_cc_static=
+ ac_cv_prog_cc_no_builtin=
+ ac_cv_prog_cc_can_build_shared=$can_build_shared
+
+ ac_cv_prog_cc_wl='-Wl,'
+ ac_cv_prog_cc_static='-static'
+
+ case $host_os in
+ beos* | irix5* | irix6* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ aix*)
+ # Below there is a dirty hack to force normal static linking with -ldl
+ # The problem is because libdl dynamically linked with both libc and
+ # libC (AIX C++ library), which obviously doesn't included in libraries
+ # list by gcc. This cause undefined symbols with -static flags.
+ # This hack allows C programs to be linked with "-static -ldl", but
+ # we not sure about C++ programs.
+ ac_cv_prog_cc_static="$ac_cv_prog_cc_static ${ac_cv_prog_cc_wl}-lC"
+ ;;
+ *djgpp*)
+ # DJGPP does not suppot shared libraries at all
+ ac_cv_prog_cc_pic=
+ ;;
+ cygwin* | mingw* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ ac_cv_prog_cc_pic='-DDLL_EXPORT'
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ ac_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ ac_cv_prog_cc_pic=-Kconform_pic
+ fi
+ ;;
+ *)
+ ac_cv_prog_cc_pic='-fPIC'
+ ;;
+ esac
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+need_lc=no
+
+# All existing releases of GCJ support `-c -o'.
+lt_cv_compiler_c_o=yes
diff --git a/contrib/gdb/ltconfig b/contrib/gdb/ltconfig
new file mode 100755
index 0000000..0a8c7d2
--- /dev/null
+++ b/contrib/gdb/ltconfig
@@ -0,0 +1,2833 @@
+#! /bin/sh
+
+# ltconfig - Create a system-specific libtool.
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A lot of this script is taken from autoconf-2.10.
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+echo=echo
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell.
+ exec "$SHELL" "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# Find the correct PATH separator. Usually this is `:', but
+# DJGPP uses `;' like DOS.
+if test "X${PATH_SEPARATOR+set}" != Xset; then
+ UNAME=${UNAME-`uname 2>/dev/null`}
+ case X$UNAME in
+ *-DOS) PATH_SEPARATOR=';' ;;
+ *) PATH_SEPARATOR=':' ;;
+ esac
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+if test "X${echo_test_string+set}" != Xset; then
+ # find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+ echo_test_string="`eval $cmd`" &&
+ (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then
+ break
+ fi
+ done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+ for dir in $PATH /usr/ucb; do
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$dir/echo"
+ break
+ fi
+ done
+ IFS="$save_ifs"
+
+ if test "X$echo" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ echo='print -r'
+ elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running ltconfig again with it.
+ ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}"
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"}
+ else
+ # Try using printf.
+ echo='printf %s\n'
+ if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL"
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ elif echo_testing_string=`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+ if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "$0"'; then
+ echo_test_string=`eval $prev`
+
+ export echo_test_string
+ exec "${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}}" "$0" ${1+"$@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ echo=echo
+ fi
+ fi
+ fi
+ fi
+fi
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# The name of this program.
+progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'`
+
+# Constants:
+PROGRAM=ltconfig
+PACKAGE=libtool
+VERSION=1.4a-GCC3.0
+TIMESTAMP=" (1.641.2.256 2001/05/28 20:09:07 with GCC-local changes)"
+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'
+rm="rm -f"
+
+help="Try \`$progname --help' for more information."
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+enable_shared=yes
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+enable_static=yes
+enable_fast_install=yes
+enable_dlopen=unknown
+enable_win32_dll=no
+pic_mode=default
+ltmain=
+silent=
+srcdir=
+ac_config_guess=
+ac_config_sub=
+host=
+build=NONE
+nonopt=NONE
+ofile="$default_ofile"
+verify_host=yes
+tagname=
+with_gcc=no
+with_gnu_ld=no
+need_locks=yes
+ac_ext=c
+libext=a
+cache_file=
+max_cmd_len=
+
+## Dependencies to place before and after the object being linked:
+predep_objects=
+postdep_objects=
+predeps=
+postdeps=
+compiler_lib_search_path=
+
+## Link characteristics:
+allow_undefined_flag=
+no_undefined_flag=
+need_lib_prefix=unknown
+need_version=unknown
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+archive_cmds=
+archive_expsym_cmds=
+old_archive_from_new_cmds=
+old_archive_from_expsyms_cmds=
+striplib=
+old_striplib=
+export_dynamic_flag_spec=
+whole_archive_flag_spec=
+thread_safe_flag_spec=
+hardcode_into_libs=no
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+hardcode_shlibpath_var=unsupported
+runpath_var=
+link_all_deplibs=unknown
+always_export_symbols=no
+export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
+# include_expsyms should be a list of space-separated symbols to be *always*
+# included in the symbol list
+include_expsyms=
+# exclude_expsyms can be an egrep regular expression of symbols to exclude
+# it will be wrapped by ` (' and `)$', so one must not match beginning or
+# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+# as well as any symbol that contains `d'.
+exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+# platforms (ab)use it in PIC code, but their linkers get confused if
+# the symbol is explicitly referenced. Since portable code cannot
+# rely on this symbol name, it's probably fine to never include it in
+# preloaded symbol tables.
+extract_expsyms_cmds=
+
+## Tools:
+old_AR="$AR"
+old_AR_FLAGS="$AR_FLAGS"
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
+old_LDFLAGS="$LDFLAGS"
+old_LIBS="$LIBS"
+old_MAGIC_CMD="$MAGIC_CMD"
+old_LD="$LD"
+old_LN_S="$LN_S"
+old_LTCC="$LTCC"
+old_NM="$NM"
+old_RANLIB="$RANLIB"
+old_STRIP="$STRIP"
+old_AS="$AS"
+old_DLLTOOL="$DLLTOOL"
+old_OBJDUMP="$OBJDUMP"
+old_OBJEXT="$OBJEXT"
+old_EXEEXT="$EXEEXT"
+old_reload_flag="$reload_flag"
+old_deplibs_check_method="$deplibs_check_method"
+old_file_magic_cmd="$file_magic_cmd"
+
+# Parse the command line options.
+args=
+prev=
+for option
+do
+ case $option in
+ -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ eval "$prev=\$option"
+ prev=
+ continue
+ fi
+
+ case $option in
+ --help) cat <<EOM
+Usage: $progname [OPTION]... LTMAIN [HOST]
+
+Generate a system-specific libtool script.
+
+ --build configure for building on BUILD [BUILD=HOST]
+ --debug enable verbose shell tracing
+ --disable-shared do not build shared libraries
+ --disable-static do not build static libraries
+ --disable-fast-install do not optimize for fast installation
+ --enable-dlopen enable dlopen support
+ --enable-win32-dll enable building dlls on win32 hosts
+ --help display this help and exit
+ --no-verify do not verify that HOST is a valid host type
+-o, --output=FILE specify the output file [default=$default_ofile]
+ --quiet same as \`--silent'
+ --silent do not print informational messages
+ --srcdir=DIR find \`config.guess' in DIR
+ --version output version information and exit
+ --add-tag=TAG append an alternate configuration
+ --with-gcc assume that the GNU C compiler will be used
+ --with-gnu-ld assume that the C compiler uses the GNU linker
+ --prefer-pic try to use only PIC objects
+ --prefer-non-pic try to use only non-PIC objects
+ --disable-lock disable file locking
+ --cache-file=FILE configure cache file
+
+LTMAIN is the \`ltmain.sh' shell script fragment or \`ltmain.c' program
+that provides basic libtool functionality.
+
+HOST is the canonical host system name [default=guessed].
+EOM
+ exit 0
+ ;;
+
+ --build) prev=build ;;
+ --build=*) build="$optarg" ;;
+
+ --debug)
+ echo "$progname: enabling shell trace mode"
+ set -x
+ ;;
+
+ --disable-shared) enable_shared=no ;;
+
+ --disable-static) enable_static=no ;;
+
+ --disable-fast-install) enable_fast_install=no ;;
+
+ --enable-dlopen) enable_dlopen=yes ;;
+
+ --enable-win32-dll) enable_win32_dll=yes ;;
+
+ --quiet | --silent) silent=yes ;;
+
+ --srcdir) prev=srcdir ;;
+ --srcdir=*) srcdir="$optarg" ;;
+
+ --no-verify) verify_host=no ;;
+
+ --output | -o) prev=ofile ;;
+ --output=*) ofile="$optarg" ;;
+
+ --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"; exit 0 ;;
+
+ --add-tag) prev=tagname ;;
+ --add-tag=*) tagname="$optarg" ;;
+
+ --with-gcc) with_gcc=yes ;;
+ --with-gnu-ld) with_gnu_ld=yes ;;
+
+ --prefer-pic) pic_mode=yes ;;
+ --prefer-non-pic) pic_mode=no ;;
+
+ --disable-lock) need_locks=no ;;
+
+ --cache-file=*) cache_file="$optarg" ;;
+
+ -*)
+ echo "$progname: unrecognized option \`$option'" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ ;;
+
+ *)
+ if test -z "$ltmain"; then
+ ltmain="$option"
+ elif test -z "$host"; then
+# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1
+# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then
+# echo "$progname: warning \`$option' is not a valid host type" 1>&2
+# fi
+ host="$option"
+ else
+ echo "$progname: too many arguments" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi ;;
+ esac
+done
+
+if test -z "$ltmain"; then
+ echo "$progname: you must specify a LTMAIN file" 1>&2
+ echo "$help" 1>&2
+ exit 1
+fi
+
+if test ! -f "$ltmain"; then
+ echo "$progname: \`$ltmain' does not exist" 1>&2
+ echo "$help" 1>&2
+ exit 1
+fi
+
+if test -n "$tagname"; then
+ # Check whether tagname contains only valid characters
+ case `$echo "X$tagname" | $Xsed -e 's/[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]//g'` in
+ "") ;;
+ *)
+ echo "$progname: invalid tag name: $tagname" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if grep "^### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$ofile" > /dev/null; then
+ echo "$progname: tag name $tagname already exists" 1>&2
+ exit 1
+ fi
+
+ if test ! -f "$ofile"; then
+ echo "$progname: warning: output file \`$ofile' does not exist" 1>&2
+ fi
+
+ if test -z "$LTCC"; then
+ eval "`$SHELL $ofile --config | grep '^LTCC='`"
+ if test -z "$LTCC"; then
+ echo "$progname: warning: output file \`$ofile' does not look like a libtool script" 1>&2
+ else
+ echo "$progname: warning: using \`LTCC=$LTCC', extracted from \`$ofile'" 1>&2
+ fi
+ fi
+fi
+
+# Quote any args containing shell metacharacters.
+ltconfig_args=
+for arg
+do
+ case $arg in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ltconfig_args="$ltconfig_args '$arg'" ;;
+ *) ltconfig_args="$ltconfig_args $arg" ;;
+ esac
+done
+
+# A relevant subset of AC_INIT.
+
+# 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
+# 5 compiler messages saved in config.log
+# 6 checking for... messages and results
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>>./config.log
+
+# 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 "X${LC_ALL+set}" = Xset; then LC_ALL=C; export LC_ALL; fi
+if test "X${LANG+set}" = Xset; then LANG=C; export LANG; fi
+
+if test -n "$cache_file" && test -r "$cache_file" && test -f "$cache_file"; then
+ echo "loading cache $cache_file within ltconfig"
+ . $cache_file
+fi
+
+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
+
+if test -z "$srcdir"; then
+ # Assume the source directory is the same one as the path to LTMAIN.
+ srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'`
+ test "$srcdir" = "$ltmain" && srcdir=.
+fi
+
+trap "$rm conftest*; exit 1" 1 2 15
+if test "$verify_host" = yes; then
+ # Check for config.guess and config.sub.
+ ac_aux_dir=
+ for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/config.guess; then
+ ac_aux_dir=$ac_dir
+ break
+ fi
+ done
+ if test -z "$ac_aux_dir"; then
+ echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi
+ ac_config_guess=$ac_aux_dir/config.guess
+ ac_config_sub=$ac_aux_dir/config.sub
+
+ # Make sure we can run config.sub.
+ if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then :
+ else
+ echo "$progname: cannot run $ac_config_sub" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi
+
+ echo $ac_n "checking host system type""... $ac_c" 1>&6
+
+ host_alias=$host
+ case $host_alias in
+ "")
+ # Force config.guess to use the C compiler.
+ # CC_FOR_BUILD overrides the CC variable in config.guess but I had
+ # problems with it so do it this way for now.
+ CC="$LTCC"
+
+ if host_alias=`$SHELL $ac_config_guess`; then :
+ else
+ echo "$progname: cannot guess host type; you must specify one" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Restore the C compiler.
+ CC="$old_CC"
+ ;;
+ esac
+ host=`$SHELL $ac_config_sub $host_alias`
+ echo "$ac_t$host" 1>&6
+
+ # Make sure the host verified.
+ test -z "$host" && exit 1
+
+ # Check for the build system type
+ 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=`$SHELL $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
+
+elif test -z "$host"; then
+ echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2
+ echo "$help" 1>&2
+ exit 1
+else
+ host_alias=$host
+ build_alias=$host_alias
+ build=$host
+fi
+
+if test x"$host" != x"$build"; then
+ ac_tool_prefix=${host_alias}-
+else
+ ac_tool_prefix=
+fi
+
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
+case $host_os in
+linux-gnu*) ;;
+linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
+esac
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+ old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+fi
+
+# Source the script associated with the $tagname tag configuration.
+if test -n "$tagname"; then
+ . $ltmain
+else
+ # FIXME: We should use a variable here
+ # Configure for a C compiler
+ . $srcdir/ltcf-c.sh
+fi
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$NM" && NM=nm
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$objext" && objext=o
+
+echo $ac_n "checking for objdir... $ac_c" 1>&6
+rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+echo "$ac_t$objdir" 1>&6
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+set dummy $CC
+compiler="$2"
+
+# We assume here that the value for ac_cv_prog_cc_pic will not be cached
+# in isolation, and that seeing it set (from the cache) indicates that
+# the associated values are set (in the cache) correctly too.
+echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6
+echo "$progname:678:checking for $compiler option to produce PIC" 1>&5
+
+if test -z "$ac_cv_prog_cc_pic"; then
+ echo "$ac_t"none 1>&6
+else
+ echo "$ac_t""$ac_cv_prog_cc_pic" 1>&6
+
+ # Check to make sure the pic_flag actually works.
+ echo $ac_n "checking if $compiler PIC flag $ac_cv_prog_cc_pic works... $ac_c" 1>&6
+ echo "$progname:687:checking that $compiler PIC flag $ac_cv_prog_cc_pic works." 1>&5
+ if test "X${ac_cv_prog_cc_pic_works+set}" = Xset && \
+ test "X${ac_cv_prog_cc_pic_works}" != X; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+ else
+ ac_cv_prog_cc_pic_works=yes
+ $rm conftest*
+ echo $lt_simple_compile_test_code > conftest.$ac_ext
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $ac_cv_prog_cc_pic -DPIC"
+ if { (eval echo $progname:697: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then
+ # Append any warnings to the config.log.
+ cat conftest.err 1>&5
+
+ case $host_os in
+ hpux9* | hpux10* | hpux11*)
+ # On HP-UX, both CC and GCC only warn that PIC is supported... then
+ # they create non-PIC objects. So, if there were any warnings, we
+ # assume that PIC is not supported.
+ if test -s conftest.err; then
+ ac_cv_prog_cc_pic_works=no
+ ac_cv_prog_cc_can_build_shared=no
+ ac_cv_prog_cc_pic=
+ else
+ ac_cv_prog_cc_pic_works=yes
+ ac_cv_prog_cc_pic=" $ac_cv_prog_cc_pic"
+ fi
+ ;;
+ *)
+ ac_cv_prog_cc_pic_works=yes
+ ac_cv_prog_cc_pic=" $ac_cv_prog_cc_pic"
+ ;;
+ esac
+ else
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ ac_cv_prog_cc_pic_works=no
+ ac_cv_prog_cc_can_build_shared=no
+ ac_cv_prog_cc_pic=
+ fi
+ CFLAGS="$save_CFLAGS"
+ $rm conftest*
+ fi
+ # Belt *and* braces to stop my trousers falling down:
+ if test "X$ac_cv_prog_cc_pic_works" = Xno; then
+ ac_cv_prog_cc_pic=
+ ac_cv_prog_cc_can_build_shared=no
+ fi
+ echo "$ac_t""$ac_cv_prog_cc_pic_works" 1>&6
+fi
+
+# Check for any special shared library compilation flags.
+if test -n "$ac_cv_prog_cc_shlib"; then
+ echo "$progname: warning: \`$CC' requires \`$ac_cv_prog_cc_shlib' to build shared libraries" 1>&2
+ if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$ac_cv_prog_cc_shlib[ ]" >/dev/null; then :
+ else
+ echo "$progname: add \`$ac_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" 1>&2
+ ac_cv_prog_cc_can_build_shared=no
+ fi
+fi
+
+echo $ac_n "checking if $compiler static flag $ac_cv_prog_cc_static works... $ac_c" 1>&6
+echo "$progname:749: checking if $compiler static flag $ac_cv_prog_cc_static works" >&5
+if test "X${ac_cv_prog_cc_static_works+set}" = Xset && \
+ test "X${ac_cv_prog_cc_static_works}" != X; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ $rm conftest*
+ echo $lt_simple_link_test_code > conftest.$ac_ext
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $ac_cv_prog_cc_static"
+ if { (eval echo $progname:758: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ ac_cv_prog_cc_static_works=yes
+ else
+ ac_cv_prog_cc_static_works=no
+ ac_cv_prog_cc_static=
+ fi
+ LDFLAGS="$save_LDFLAGS"
+ $rm conftest*
+fi
+# Belt *and* braces to stop my trousers falling down:
+if test "X$ac_cv_prog_cc_static_works" = Xno; then
+ ac_cv_prog_cc_static=
+fi
+echo "$ac_t""$ac_cv_prog_cc_static_works" 1>&6
+pic_flag="$ac_cv_prog_cc_pic"
+special_shlib_compile_flags="$ac_cv_prog_cc_shlib"
+wl="$ac_cv_prog_cc_wl"
+link_static_flag="$ac_cv_prog_cc_static"
+no_builtin_flag="$ac_cv_prog_cc_no_builtin"
+can_build_shared="$ac_cv_prog_cc_can_build_shared"
+
+# find the maximum length of command line arguments
+echo "$progname:780: finding the maximum length of command line arguments" 1>&5
+echo $ac_n "finding the maximum length of command line arguments... $ac_c" 1>&6
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ i=0
+ testring="ABCD"
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while test "X"`$CONFIG_SHELL $0 --fallback-echo "X$testring" 2>/dev/null` \
+ = "XX$testring" &&
+ new_result=`expr "X$testring" : ".*" 2>&1` &&
+ lt_cv_sys_max_cmd_len=$new_result &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ testring=$testring$testring
+ done
+ testring=
+ # add a significant safety factor because C++ compilers can tack on massive amounts
+ # of additional arguments before passing them to the linker. 1/4 should be good.
+ len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len - $len`
+fi
+echo "$progname:@lineno@: result: $lt_cv_sys_max_cmd_len" 1>&5
+echo "${ac_t}$lt_cv_sys_max_cmd_len" 1>&6
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ max_cmd_len=$lt_cv_sys_max_cmd_len
+else
+ max_cmd_len=none
+fi
+
+# Check to see if options -o and -c are simultaneously supported by compiler
+echo $ac_n "checking if $compiler supports -c -o file.$objext... $ac_c" 1>&6
+if test "${lt_cv_compiler_c_o+set}" = set; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ $rm conftest*
+ echo $lt_simple_compile_test_code > conftest.$ac_ext
+ mkdir out
+ # According to Tom Tromey, Ian Lance Taylor reported there are C compilers
+ # that will create temporary files in the current directory regardless of
+ # the output directory. Thus, making CWD read-only will cause this test
+ # to fail, enabling locking or at least warning the user not to do parallel
+ # builds.
+ chmod -w .
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -o out/conftest2.$objext"
+ echo "$progname:833: checking if $compiler supports -c -o file.$objext" >&5
+ if { (eval echo $progname:834: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$objext; then
+
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s out/conftest.err; then
+ lt_cv_compiler_c_o=no
+ else
+ lt_cv_compiler_c_o=yes
+ fi
+ else
+ # Append any errors to the config.log.
+ cat out/conftest.err 1>&5
+ lt_cv_compiler_c_o=no
+ fi
+ CFLAGS="$save_CFLAGS"
+ chmod u+w .
+ $rm conftest* out/*
+ rmdir out
+ cd ..
+ rmdir conftest
+ $rm -r conftest 2>/dev/null
+fi
+compiler_c_o=$lt_cv_compiler_c_o
+echo "${ac_t}$compiler_c_o" 1>&6
+
+# Check to see if we can do hard links to lock some files if needed
+hard_links="nottested"
+if test "$compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$ac_t$hard_links" 1>&6
+ $rm conftest*
+ if test "$hard_links" = no; then
+ echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+if test "$with_gcc" = yes; then
+ # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
+ echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6
+ $rm conftest*
+ echo $lt_simple_compile_test_code > conftest.$ac_ext
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext"
+ echo "$progname:887: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+ if { (eval echo $progname:888: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then
+
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ echo "$ac_t"no 1>&6
+ compiler_rtti_exceptions=no
+ else
+ echo "$ac_t"yes 1>&6
+ compiler_rtti_exceptions=yes
+ fi
+ else
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ compiler_rtti_exceptions=no
+ echo "$ac_t"no 1>&6
+ fi
+ CFLAGS="$save_CFLAGS"
+ $rm conftest*
+
+ if test "$compiler_rtti_exceptions" = "yes"; then
+ no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
+ else
+ no_builtin_flag=' -fno-builtin'
+ fi
+
+fi
+
+# See if the linker supports building shared libraries.
+echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6
+
+echo "$ac_t$ld_shlibs" 1>&6
+test "$ld_shlibs" = no && can_build_shared=no
+
+# Check hardcoding attributes.
+echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+ test -n "$runpath_var"; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$hardcode_shlibpath_var" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+echo "$ac_t$hardcode_action" 1>&6
+
+echo $ac_n "checking whether stripping libraries is possible... $ac_c" 1>&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "${ac_t}yes" 1>&6
+else
+ echo "${ac_t}no" 1>&6
+fi
+
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+# PORTME Fill in your ld.so characteristics
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+
+echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}.so$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}.so$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ # We preserve .a as extension for shared libraries though AIX4.2
+ # and later linker supports .so
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so instead of
+ # lib<name>.a to let people know that these are not typical AIX shared libraries.
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ else
+ # We preserve .a as extension for shared libraries though AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}.so$major'
+ fi
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | egrep '(GNU)' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ shlibpath_var=LIBPATH
+ deplibs_check_method=pass_all
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}.so'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+bsdi4*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ export_dynamic_flag_spec=-rdynamic
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ need_version=no
+ need_lib_prefix=no
+ case $with_gcc,$host_os in
+ yes,cygwin*)
+ library_names_spec='$libname.dll.a'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | [sed -e 's/[.]/-/g']`${versuffix}.dll'
+ postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog .libs/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll; $rm \$dlpath'
+ ;;
+ yes,mingw*)
+ library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"`
+ ;;
+ yes,pw32*)
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll'
+;;
+ *)
+ library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}.`test .$module = .yes && echo so || echo dylib` ${libname}${release}${major}.$`test .$module = .yes && echo so || echo dylib` ${libname}.`test .$module = .yes && echo so || echo dylib`'
+ soname_spec='${libname}${release}${major}.`test .$module = .yes && echo so || echo dylib`'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ ;;
+
+freebsd*-gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
+ soname_spec='${libname}${release}.so${major}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU/FreeBSD ld.so'
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
+ need_version=no
+ need_lc=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ *)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
+ soname_spec='${libname}${release}.sl$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6*)
+ if test "$with_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi
+ version_type=irix
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}.so$major'
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so'
+ case $host_os in
+ irix5*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux-gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ need_lib_prefix=no
+ need_version=no
+ version_type=sunos
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
+ soname_spec='${libname}${release}.so$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ need_version=no
+ fi
+ library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+os2*)
+ libname_spec='$name'
+ need_lib_prefix=no
+ library_names_spec='$libname.dll $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_version=no
+ soname_spec='${libname}${release}.so'
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}.so$major'
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
+ soname_spec='$libname.so.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$ac_t$dynamic_linker" 1>&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*) # Its linker distinguishes data from code symbols
+ global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ ;;
+irix*)
+ symcode='[BCDEGRST]'
+ ;;
+solaris* | sysv5*)
+ symcode='[BDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $host_os in
+mingw*)
+ opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
+ symcode='[ABCDGISTW]'
+fi
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Write the raw and C identifiers.
+ global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+ $rm conftest*
+ cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+ echo "$progname:1431: checking if global_symbol_pipe works" >&5
+ if { (eval echo $progname:1432: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { echo "$progname:1435: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then
+
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if egrep ' nm_test_var$' "$nlist" >/dev/null; then
+ if egrep ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+ # Now generate the symbol file.
+ eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext'
+
+ cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{
+EOF
+ sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" >> conftest.$ac_ext
+ cat <<\EOF >> conftest.$ac_ext
+ {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+ # Now try linking the two files.
+ mv conftest.$objext conftstm.$objext
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$objext"
+ CFLAGS="$CFLAGS$no_builtin_flag"
+ if { (eval echo $progname:1487: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ pipe_works=yes
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ LIBS="$save_LIBS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ $rm conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ global_symbol_pipe=
+ fi
+done
+if test "$pipe_works" = yes; then
+ echo "${ac_t}ok" 1>&6
+else
+ echo "${ac_t}failed" 1>&6
+fi
+
+if test -z "$global_symbol_pipe"; then
+ global_symbol_to_cdecl=
+fi
+
+# Report the final consequences.
+echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6
+
+# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in
+# configure.in, otherwise build static only libraries.
+case $host_os in
+cygwin* | mingw* | pw32* | os2*)
+ if test x$can_build_shared = xyes; then
+ test x$enable_win32_dll = xno && can_build_shared=no
+ echo "checking if package supports dlls... $can_build_shared" 1>&6
+ fi
+;;
+esac
+
+echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+aix4*)
+ test "$enable_shared" = yes && enable_static=no
+ ;;
+esac
+
+echo "$ac_t$enable_shared" 1>&6
+
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+
+echo "checking whether to build static libraries... $enable_static" 1>&6
+
+if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$with_gcc" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+# Check whether we must set pic_mode to default
+test -z "$pic_flag" && pic_mode=default
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+if test "X${lt_cv_dlopen+set}" != Xset; then
+ lt_cv_dlopen=no lt_cv_dlopen_libs=
+echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+echo "$progname:1591: checking for dlopen in -ldl" >&5
+if test "X${ac_cv_lib_dl_dlopen+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1598 "ltconfig"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen();
+
+int main() {
+dlopen()
+; return 0; }
+EOF
+if { (eval echo $progname:1611: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if test "X$ac_cv_lib_dl_dlopen" = Xyes; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for dlopen""... $ac_c" 1>&6
+echo "$progname:1630: checking for dlopen" >&5
+if test "X${ac_cv_func_dlopen+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1635 "ltconfig"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen();
+
+int main() {
+
+/* 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_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+dlopen();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo $progname:1660: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_func_dlopen=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_func_dlopen=no
+fi
+rm -f conftest*
+fi
+if test "X$ac_cv_func_dlopen" = Xyes; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="dlopen"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for dlopen in -lsvld""... $ac_c" 1>&6
+echo "$progname:1677: checking for dlopen in -lsvld" >&5
+if test "X${ac_cv_lib_svld_dlopen+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsvld $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1684 "ltconfig"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen();
+
+int main() {
+dlopen()
+; return 0; }
+EOF
+if { (eval echo $progname:1697: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if test "X$ac_cv_lib_svld_dlopen" = Xyes; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6
+echo "$progname:1716: checking for dld_link in -ldld" >&5
+if test "X${ac_cv_lib_dld_dld_link+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldld $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1723 "ltconfig"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link();
+
+int main() {
+dld_link()
+; return 0; }
+EOF
+if { (eval echo $progname:1736: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if test "X$ac_cv_lib_dld_dld_link" = Xyes; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for shl_load""... $ac_c" 1>&6
+echo "$progname:1755: checking for shl_load" >&5
+if test "X${ac_cv_func_shl_load+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1760 "ltconfig"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load();
+
+int main() {
+
+/* 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_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+shl_load();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo $progname:1785: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_func_shl_load=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_func_shl_load=no
+fi
+rm -f conftest*
+fi
+
+if test "X$ac_cv_func_shl_load" = Xyes; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="shl_load"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6
+echo "$progname:1803: checking for shl_load in -ldld" >&5
+if test "X${ac_cv_lib_dld_shl_load+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldld $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1810 "ltconfig"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load();
+
+int main() {
+shl_load()
+; return 0; }
+EOF
+if { (eval echo $progname:1824: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if test "X$ac_cv_lib_dld_shl_load" = Xyes; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+fi
+
+fi
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+for ac_hdr in dlfcn.h; do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "$progname:1871: checking for $ac_hdr" >&5
+if eval "test \"`echo 'X$''{'ac_cv_header_$ac_safe'+set}'`\" = Xset"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1876 "ltconfig"
+#include <$ac_hdr>
+int fnord = 0;
+int main () { return(0); }
+EOF
+ac_try="$ac_compile >/dev/null 2>conftest.out"
+{ (eval echo $progname:1882: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&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
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ if test "x$ac_cv_header_dlfcn_h" = xyes; then
+ CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+ fi
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6
+echo "$progname:1910: checking whether a program can dlopen itself" >&5
+if test "X${lt_cv_dlopen_self+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ lt_cv_dlopen_self=cross
+ else
+ cat > conftest.$ac_ext <<EOF
+#line 1918 "ltconfig"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LTDL_GLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LTDL_GLOBAL DL_GLOBAL
+# else
+# define LTDL_GLOBAL 0
+# endif
+#endif
+
+/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LTDL_LAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LTDL_LAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LTDL_LAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LTDL_LAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LTDL_LAZY_OR_NOW DL_NOW
+# else
+# define LTDL_LAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+void fnord() { int i=42; }
+int main() {
+ void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
+ if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
+ if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); }
+
+EOF
+if { (eval echo $progname:1965: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ lt_cv_dlopen_self=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ lt_cv_dlopen_self=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$lt_cv_dlopen_self" 1>&6
+
+ if test "$lt_cv_dlopen_self" = yes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6
+echo "$progname:1984: checking whether a statically linked program can dlopen itself" >&5
+if test "X${lt_cv_dlopen_self_static+set}" = Xset; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ lt_cv_dlopen_self_static=cross
+ else
+ cat > conftest.$ac_ext <<EOF
+#line 1992 "ltconfig"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LTDL_GLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LTDL_GLOBAL DL_GLOBAL
+# else
+# define LTDL_GLOBAL 0
+# endif
+#endif
+
+/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LTDL_LAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LTDL_LAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LTDL_LAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LTDL_LAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LTDL_LAZY_OR_NOW DL_NOW
+# else
+# define LTDL_LAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+void fnord() { int i=42; }
+int main() {
+ void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
+ if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
+ if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); }
+
+EOF
+if { (eval echo $progname:2039: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ lt_cv_dlopen_self_static=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ lt_cv_dlopen_self_static=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6
+fi
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+# Copy echo and quote the copy, instead of the original, because it is
+# used later.
+ltecho="$echo"
+if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+ ltecho="$CONFIG_SHELL \$0 --fallback-echo"
+fi
+LTSHELL="$SHELL"
+
+LTCONFIG_VERSION="$VERSION"
+
+# Only quote variables if we're using ltmain.sh.
+case $ltmain in
+*.sh)
+ # Now quote all the things that may contain metacharacters.
+ for var in ltecho old_AR old_AR_FLAGS old_CC old_LTCC old_CFLAGS old_CPPFLAGS \
+ old_MAGIC_CMD old_LD old_LDFLAGS old_LIBS \
+ old_LN_S old_NM old_RANLIB old_STRIP \
+ old_AS old_DLLTOOL old_OBJDUMP \
+ old_OBJEXT old_EXEEXT old_reload_flag \
+ old_deplibs_check_method old_file_magic_cmd \
+ AR AR_FLAGS CC LTCC LD LN_S NM LTSHELL LTCONFIG_VERSION \
+ reload_flag reload_cmds wl \
+ pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
+ thread_safe_flag_spec whole_archive_flag_spec libname_spec \
+ library_names_spec soname_spec \
+ RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
+ old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \
+ postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \
+ predep_objects postdep_objects predeps postdeps compiler_lib_search_path \
+ old_striplib striplib file_magic_cmd export_symbols_cmds \
+ deplibs_check_method allow_undefined_flag no_undefined_flag \
+ finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
+ hardcode_libdir_flag_spec hardcode_libdir_separator \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ compiler_c_o need_locks exclude_expsyms include_expsyms; do
+
+ case $var in
+ reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
+ extract_expsyms_cmds | old_archive_from_expsyms_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ### testsuite: skip nested quoting test
+ ;;
+ *)
+ eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ### testsuite: skip nested quoting test
+ ;;
+ esac
+ done
+
+ case $ltecho in
+ *'\$0 --fallback-echo"')
+ ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+ if test -z "$tagname"; then
+ trap "$rm \"$ofile\"; exit 1" 1 2 15
+ echo "creating $ofile"
+ $rm "$ofile"
+ cat <<EOF > "$ofile"
+#! $SHELL
+
+# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh.
+#
+# Copyright (C) 1996-2000 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="sed -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+### BEGIN LIBTOOL CONFIG
+EOF
+ else
+ echo "appending configuration tag \"$tagname\" to $ofile"
+ echo "### BEGIN LIBTOOL TAG CONFIG: $tagname" >> "$ofile"
+ fi
+ cfgfile="$ofile"
+ ;;
+
+*)
+ # Double-quote the variables that need it (for aesthetics).
+ for var in old_AR old_AR_FLAGS old_CC old_LTCC old_CFLAGS old_CPPFLAGS \
+ old_MAGIC_CMD old_LD old_LDFLAGS old_LIBS \
+ old_LN_S old_NM old_RANLIB old_STRIP \
+ old_AS old_DLLTOOL old_OBJDUMP \
+ old_OBJEXT old_EXEEXT old_reload_flag \
+ old_deplibs_check_method old_file_magic_cmd; do
+ eval "$var=\\\"\$var\\\""
+ done
+
+ # Just create a config file.
+ cfgfile="$ofile.cfg"
+ if test -z "$tagname"; then
+ trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+ echo "creating $cfgfile"
+ $rm "$cfgfile"
+ cat <<EOF > "$cfgfile"
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+
+### BEGIN LIBTOOL CONFIG
+EOF
+ else
+ echo "appending to $cfgfile"
+ echo "### BEGIN LIBTOOL TAG CONFIG: $tagname" >> "$ofile"
+ fi
+ ;;
+esac
+
+cat <<EOF >> "$cfgfile"
+# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# AR=$old_AR AR_FLAGS=$old_AR_FLAGS LTCC=$old_LTCC CC=$old_CC \\
+# CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\
+# MAGIC_CMD=$old_MAGIC_CMD LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\
+# LN_S=$old_LN_S NM=$old_NM RANLIB=$old_RANLIB STRIP=$old_STRIP \\
+# AS=$old_AS DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP \\
+# objext=$old_OBJEXT exeext=$old_EXEEXT reload_flag=$old_reload_flag \\
+# deplibs_check_method=$old_deplibs_check_method \\
+# file_magic_cmd=$old_file_magic_cmd \\
+# $0$ltconfig_args
+#
+# Compiler and other test output produced by $progname, useful for
+# debugging $progname, is in ./config.log if it exists.
+
+# The version of $progname that generated this script.
+LTCONFIG_VERSION=$LTCONFIG_VERSION
+
+# Shell to use when invoking shell scripts.
+SHELL=$LTSHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$need_lc
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$ltecho
+
+# The archiver.
+AR=$AR
+AR_FLAGS=$AR_FLAGS
+
+# A C compiler.
+LTCC=$LTCC
+
+# A language-specific compiler.
+CC=$CC
+
+# Is the compiler the GNU C compiler?
+with_gcc=$with_gcc
+
+# The linker used to build libraries.
+LD=$LD
+
+# Whether we need hard or soft links.
+LN_S=$LN_S
+
+# A BSD-compatible nm program.
+NM=$NM
+
+# A symbol stripping program
+STRIP=$STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$reload_flag
+reload_cmds=$reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$wl
+
+# Object file suffix (normally "o").
+objext="$objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$pic_flag
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$compiler_c_o
+
+# Must we lock files when doing compilation ?
+need_locks=$need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$link_static_flag
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$no_builtin_flag
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$whole_archive_flag_spec
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$thread_safe_flag_spec
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$RANLIB
+old_archive_cmds=$old_archive_cmds
+old_postinstall_cmds=$old_postinstall_cmds
+old_postuninstall_cmds=$old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$old_archive_from_expsyms_cmds
+
+# Commands used to build and install a shared archive.
+archive_cmds=$archive_cmds
+archive_expsym_cmds=$archive_expsym_cmds
+postinstall_cmds=$postinstall_cmds
+postuninstall_cmds=$postuninstall_cmds
+
+# Commands to strip libraries.
+old_striplib=$old_striplib
+striplib=$striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$predep_objects
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$postdep_objects
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$predeps
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$compiler_lib_search_path
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$allow_undefined_flag
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$no_undefined_flag
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$global_symbol_to_cdecl
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$hardcode_libdir_separator
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$export_symbols_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$include_expsyms
+
+EOF
+
+if test -z "$tagname"; then
+ echo '### END LIBTOOL CONFIG' >> "$ofile"
+else
+ echo "### END LIBTOOL TAG CONFIG: $tagname" >> "$ofile"
+fi
+
+case $ltmain in
+*.sh)
+ echo >> "$ofile"
+ if test -z "$tagname"; then
+ case $host_os in
+ aix3*)
+ cat <<\EOF >> "$ofile"
+
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+EOF
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ cat <<'EOF' >> "$ofile"
+ # This is a source program that is used to create dlls on Windows
+ # Don't remove nor modify the starting and closing comments
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# # ifdef __CYGWIN32__
+# # define __CYGWIN__ __CYGWIN32__
+# # endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+# __hDllInstance_base = hInst;
+# return TRUE;
+# }
+# /* ltdll.c ends here */
+ # This is a source program that is used to create import libraries
+ # on Windows for dlls which lack them. Don't remove nor modify the
+ # starting and closing comments
+# /* impgen.c starts here */
+# /* Copyright (C) 1999-2000 Free Software Foundation, Inc.
+#
+# This file is part of GNU libtool.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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 <stdio.h> /* for printf() */
+# #include <unistd.h> /* for open(), lseek(), read() */
+# #include <fcntl.h> /* for O_RDONLY, O_BINARY */
+# #include <string.h> /* for strdup() */
+#
+# /* O_BINARY isn't required (or even defined sometimes) under Unix */
+# #ifndef O_BINARY
+# #define O_BINARY 0
+# #endif
+#
+# static unsigned int
+# pe_get16 (fd, offset)
+# int fd;
+# int offset;
+# {
+# unsigned char b[2];
+# lseek (fd, offset, SEEK_SET);
+# read (fd, b, 2);
+# return b[0] + (b[1]<<8);
+# }
+#
+# static unsigned int
+# pe_get32 (fd, offset)
+# int fd;
+# int offset;
+# {
+# unsigned char b[4];
+# lseek (fd, offset, SEEK_SET);
+# read (fd, b, 4);
+# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
+# }
+#
+# static unsigned int
+# pe_as32 (ptr)
+# void *ptr;
+# {
+# unsigned char *b = ptr;
+# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
+# }
+#
+# int
+# main (argc, argv)
+# int argc;
+# char *argv[];
+# {
+# int dll;
+# unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
+# unsigned long export_rva, export_size, nsections, secptr, expptr;
+# unsigned long name_rvas, nexp;
+# unsigned char *expdata, *erva;
+# char *filename, *dll_name;
+#
+# filename = argv[1];
+#
+# dll = open(filename, O_RDONLY|O_BINARY);
+# if (dll < 1)
+# return 1;
+#
+# dll_name = filename;
+#
+# for (i=0; filename[i]; i++)
+# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':')
+# dll_name = filename + i +1;
+#
+# pe_header_offset = pe_get32 (dll, 0x3c);
+# opthdr_ofs = pe_header_offset + 4 + 20;
+# num_entries = pe_get32 (dll, opthdr_ofs + 92);
+#
+# if (num_entries < 1) /* no exports */
+# return 1;
+#
+# export_rva = pe_get32 (dll, opthdr_ofs + 96);
+# export_size = pe_get32 (dll, opthdr_ofs + 100);
+# nsections = pe_get16 (dll, pe_header_offset + 4 +2);
+# secptr = (pe_header_offset + 4 + 20 +
+# pe_get16 (dll, pe_header_offset + 4 + 16));
+#
+# expptr = 0;
+# for (i = 0; i < nsections; i++)
+# {
+# char sname[8];
+# unsigned long secptr1 = secptr + 40 * i;
+# unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
+# unsigned long vsize = pe_get32 (dll, secptr1 + 16);
+# unsigned long fptr = pe_get32 (dll, secptr1 + 20);
+# lseek(dll, secptr1, SEEK_SET);
+# read(dll, sname, 8);
+# if (vaddr <= export_rva && vaddr+vsize > export_rva)
+# {
+# expptr = fptr + (export_rva - vaddr);
+# if (export_rva + export_size > vaddr + vsize)
+# export_size = vsize - (export_rva - vaddr);
+# break;
+# }
+# }
+#
+# expdata = (unsigned char*)malloc(export_size);
+# lseek (dll, expptr, SEEK_SET);
+# read (dll, expdata, export_size);
+# erva = expdata - export_rva;
+#
+# nexp = pe_as32 (expdata+24);
+# name_rvas = pe_as32 (expdata+32);
+#
+# printf ("EXPORTS\n");
+# for (i = 0; i<nexp; i++)
+# {
+# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
+# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
+# }
+#
+# return 0;
+# }
+# /* impgen.c ends here */
+
+EOF
+ ;;
+ esac
+
+
+ # Append the ltmain.sh script.
+ sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1)
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+
+ chmod +x "$ofile"
+ fi
+ ;;
+
+*)
+ # Compile the libtool program.
+ echo "FIXME: would compile $ltmain"
+ ;;
+esac
+
+# Update the list of available tags.
+if test -n "$tagname"; then
+
+ # Extract list of available tagged configurations in $ofile.
+ # Note that this assumes the entire list is on one line.
+ available_tags=`grep "^available_tags=" $ofile | sed -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+ # Append the new tag name to the list of available tags.
+ available_tags="$available_tags $tagname"
+
+ # Now substitute the updated of available tags.
+ if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' ${ofile} > ${ofile}.new"; then
+ mv ${ofile}.new ${ofile}
+ chmod +x "$ofile"
+ else
+ rm -f ${ofile}.new
+ echo "$progname: unable to update list of available tagged configurations."
+ exit 1
+ fi
+fi
+
+# Don't cache tagged configuration!
+test -n "$cache_file" && test -z "$tagname" || exit 0
+
+# AC_CACHE_SAVE
+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
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# 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 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> 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
+
+exit 0
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/contrib/gdb/ltmain.sh b/contrib/gdb/ltmain.sh
new file mode 100644
index 0000000..c3547e5
--- /dev/null
+++ b/contrib/gdb/ltmain.sh
@@ -0,0 +1,5469 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun ltconfig.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell, and then maybe $echo will work.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# The name of this program.
+progname=`$echo "$0" | sed 's%^.*/%%'`
+modename="$progname"
+
+# Constants.
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.4a-GCC3.0
+TIMESTAMP=" (1.641.2.256 2001/05/28 20:09:07 with GCC-local changes)"
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+SP2NL='tr \040 \012'
+NL2SP='tr \015\012 \040\040'
+
+# 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).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+ save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+ save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+if test "$LTCONFIG_VERSION" != "$VERSION"; then
+ echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2
+ echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+fi
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ echo "$modename: not configured to build any kind of library" 1>&2
+ echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+taglist=
+
+# Parse our command line options once, thoroughly.
+while test $# -gt 0
+do
+ arg="$1"
+ shift
+
+ case $arg in
+ -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ execute_dlfiles)
+ execute_dlfiles="$execute_dlfiles $arg"
+ ;;
+ tag)
+ tagname="$arg"
+
+ # Check whether tagname contains only valid characters
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ echo "$progname: invalid tag name: $tagname" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $tagname in
+ CC)
+ # Don't test for the "default" C tag, as we know, it's there, but
+ # not specially marked.
+ taglist="$taglist $tagname"
+ ;;
+ *)
+ if grep "^### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$0" > /dev/null; then
+ taglist="$taglist $tagname"
+ # Evaluate the configuration.
+ eval "`sed -n -e '/^### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $0`"
+ else
+ echo "$progname: ignoring unknown tag $tagname" 1>&2
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ eval "$prev=\$arg"
+ ;;
+ esac
+
+ prev=
+ prevopt=
+ continue
+ fi
+
+ # Have we seen a non-optional argument yet?
+ case $arg in
+ --help)
+ show_help=yes
+ ;;
+
+ --version)
+ echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+ exit 0
+ ;;
+
+ --config)
+ sed -n -e '/^### BEGIN LIBTOOL CONFIG/,/^### END LIBTOOL CONFIG/p' < "$0"
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ sed -n -e "/^### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^### END LIBTOOL TAG CONFIG: $tagname$/p" < "$0"
+ done
+ exit 0
+ ;;
+
+ --debug)
+ echo "$progname: enabling shell trace mode"
+ set -x
+ ;;
+
+ --dry-run | -n)
+ run=:
+ ;;
+
+ --features)
+ echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+ exit 0
+ ;;
+
+ --finish) mode="finish" ;;
+
+ --mode) prevopt="--mode" prev=mode ;;
+ --mode=*) mode="$optarg" ;;
+
+ --quiet | --silent)
+ show=:
+ ;;
+
+ --tag) prevopt="--tag" prev=tag ;;
+ --tag=*)
+ set tag "$optarg" ${1+"$@"}
+ shift
+ prev=tag
+ ;;
+
+ -dlopen)
+ prevopt="-dlopen"
+ prev=execute_dlfiles
+ ;;
+
+ -*)
+ $echo "$modename: unrecognized option \`$arg'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+
+ *)
+ nonopt="$arg"
+ break
+ ;;
+ esac
+done
+
+if test -n "$prevopt"; then
+ $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+fi
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+ # Infer the operation mode.
+ if test -z "$mode"; then
+ case $nonopt in
+ *cc | *++ | gcc* | *-gcc*)
+ mode=link
+ for arg
+ do
+ case $arg in
+ -c)
+ mode=compile
+ break
+ ;;
+ esac
+ done
+ ;;
+ *db | *dbx | *strace | *truss)
+ mode=execute
+ ;;
+ *install*|cp|mv)
+ mode=install
+ ;;
+ *rm)
+ mode=uninstall
+ ;;
+ *)
+ # If we have no mode, but dlfiles were specified, then do execute mode.
+ test -n "$execute_dlfiles" && mode=execute
+
+ # Just use the default operation mode.
+ if test -z "$mode"; then
+ if test -n "$nonopt"; then
+ $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+ else
+ $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+ fi
+ fi
+ ;;
+ esac
+ fi
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$modename --help --mode=$mode' for more information."
+
+ # These modes are in order of execution frequency so that they run quickly.
+ case $mode in
+ # libtool compile mode
+ compile)
+ modename="$modename: compile"
+ # Get the compilation command and the source file.
+ base_compile=
+ prev=
+ lastarg=
+ srcfile="$nonopt"
+ suppress_output=
+
+ user_target=no
+ for arg
+ do
+ case $prev in
+ "") ;;
+ xcompiler)
+ # Aesthetically quote the previous argument.
+ prev=
+ lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+
+ case $arg in
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+
+ # Add the previous argument to base_compile.
+ if test -z "$base_compile"; then
+ base_compile="$lastarg"
+ else
+ base_compile="$base_compile $lastarg"
+ fi
+ continue
+ ;;
+ esac
+
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ if test "$user_target" != "no"; then
+ $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+ exit 1
+ fi
+ user_target=next
+ ;;
+
+ -static)
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+ lastarg=
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ lastarg="$lastarg $arg"
+ done
+ IFS="$save_ifs"
+ lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+ # Add the arguments to base_compile.
+ if test -z "$base_compile"; then
+ base_compile="$lastarg"
+ else
+ base_compile="$base_compile $lastarg"
+ fi
+ continue
+ ;;
+ esac
+
+ case $user_target in
+ next)
+ # The next one is the -o target name
+ user_target=yes
+ continue
+ ;;
+ yes)
+ # We got the output file
+ user_target=set
+ libobj="$arg"
+ continue
+ ;;
+ esac
+
+ # Accept the current argument as the source file.
+ lastarg="$srcfile"
+ srcfile="$arg"
+
+ # Aesthetically quote the previous argument.
+
+ # Backslashify any backslashes, double quotes, and dollar signs.
+ # These are the only characters that are still specially
+ # interpreted inside of double-quoted scrings.
+ lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ case $lastarg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ lastarg="\"$lastarg\""
+ ;;
+ esac
+
+ # Add the previous argument to base_compile.
+ if test -z "$base_compile"; then
+ base_compile="$lastarg"
+ else
+ base_compile="$base_compile $lastarg"
+ fi
+ done
+
+ case $user_target in
+ set)
+ ;;
+ no)
+ # Get the name of the library object.
+ libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+ ;;
+ *)
+ $echo "$modename: you must specify a target with \`-o'" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ xform='[cCFSfmso]'
+ case $libobj in
+ *.ada) xform=ada ;;
+ *.adb) xform=adb ;;
+ *.ads) xform=ads ;;
+ *.asm) xform=asm ;;
+ *.c++) xform=c++ ;;
+ *.cc) xform=cc ;;
+ *.class) xform=class ;;
+ *.cpp) xform=cpp ;;
+ *.cxx) xform=cxx ;;
+ *.f90) xform=f90 ;;
+ *.for) xform=for ;;
+ *.java) xform=java ;;
+ esac
+
+ libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+ case $libobj in
+ *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+ *)
+ $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Infer tagged configuration to use if any are available and
+ # if one wasn't chosen via the "--tag" command line option.
+ # Only attempt this if the compiler in the base compile
+ # command doesn't match the default compiler.
+ if test -n "$available_tags" && test -z "$tagname"; then
+ case $base_compile in
+ "$CC "*) ;;
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when ltconfig was run.
+ "`$echo $CC` "*) ;;
+ *)
+ for z in $available_tags; do
+ if grep "^### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`sed -n -e '/^### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
+ case $base_compile in
+ "$CC "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ "`$echo $CC` "*)
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ echo "$modename: unable to infer tagged configuration"
+ echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit 1
+# else
+# echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+
+ objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$obj"; then
+ xdir=
+ else
+ xdir=$xdir/
+ fi
+ lobj=${xdir}$objdir/$objname
+
+ if test -z "$base_compile"; then
+ $echo "$modename: you must specify a compilation command" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ $run $rm $removelist
+ trap "$run $rm $removelist; exit 1" 1 2 15
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2*)
+ pic_mode=default
+ ;;
+ esac
+ if test $pic_mode = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ removelist="$removelist $output_obj $lockfile"
+ trap "$run $rm $removelist; exit 1" 1 2 15
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $run ln "$0" "$lockfile" 2>/dev/null; do
+ $show "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+ echo $srcfile > "$lockfile"
+ fi
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+
+ $run $rm "$libobj" "${libobj}T"
+
+ # Create a libtool object file (analogous to a ".la" file),
+ # but don't create it if we're doing a dry run.
+ test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $srcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $srcfile"
+ fi
+
+ if test ! -d ${xdir}$objdir; then
+ $show "$mkdir ${xdir}$objdir"
+ $run $mkdir ${xdir}$objdir
+ status=$?
+ if test $status -ne 0 && test ! -d ${xdir}$objdir; then
+ exit $status
+ fi
+ fi
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ $run $rm "$lobj" "$output_obj"
+
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ test -n "$output_obj" && $run $rm $removelist
+ exit 1
+ fi
+
+ if test "$need_locks" = warn &&
+ test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
+ echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "x$output_obj" != "x$lobj"; then
+ $show "$mv $output_obj $lobj"
+ if $run $mv $output_obj $lobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the PIC object to the libtool object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+ # Allow error messages only from the first compilation.
+ suppress_output=' >/dev/null 2>&1'
+ else
+ # No PIC object so indicate it doesn't exist in the libtool
+ # object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $srcfile"
+ else
+ command="$base_compile $srcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ $run $rm "$obj" "$output_obj"
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ $run $rm $removelist
+ exit 1
+ fi
+
+ if test "$need_locks" = warn &&
+ test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
+ echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "x$output_obj" != "x$obj"; then
+ $show "$mv $output_obj $obj"
+ if $run $mv $output_obj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+ else
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+ fi
+
+ $run $mv "${libobj}T" "${libobj}"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ $run $rm "$lockfile"
+ fi
+
+ exit 0
+ ;;
+
+ # libtool link mode
+ link | relink)
+ modename="$modename: link"
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invokation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args="$nonopt"
+ base_compile="$nonopt"
+ compile_command="$nonopt"
+ finalize_command="$nonopt"
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+
+ avoid_version=no
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -all-static | -static)
+ if test "X$arg" = "X-all-static"; then
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ else
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ fi
+ build_libtool_libs=no
+ build_old_libs=yes
+ prefer_static_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test $# -gt 0; do
+ arg="$1"
+ base_compile="$base_compile $arg"
+ shift
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+ ;;
+ *) qarg=$arg ;;
+ esac
+ libtool_args="$libtool_args $qarg"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ compile_command="$compile_command @OUTPUT@"
+ finalize_command="$finalize_command @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ compile_command="$compile_command @SYMFILE@"
+ finalize_command="$finalize_command @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ if test ! -f "$arg"; then
+ $echo "$modename: symbol file \`$arg' does not exist"
+ exit 1
+ fi
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat $save_arg`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit 1
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ done
+ else
+ $echo "$modename: link input file \`$save_arg' does not exist"
+ exit 1
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ compile_command="$compile_command $wl$qarg"
+ finalize_command="$finalize_command $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n $prev
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+ continue
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: more than one -exported-symbols argument is not allowed"
+ exit 1
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix*)
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+ exit 1
+ fi
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-pw32* | *-*-beos*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-mingw* | *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # in order for the loader to find any dlls it needs.
+ $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+ $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -static)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+ arg=
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Wl,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+ arg=
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $wl$flag"
+ linker_flags="$linker_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit 1
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+ done # argument parsing loop
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Infer tagged configuration to use if any are available and
+ # if one wasn't chosen via the "--tag" command line option.
+ # Only attempt this if the compiler in the base link
+ # command doesn't match the default compiler.
+ if test -n "$available_tags" && test -z "$tagname"; then
+ case $base_compile in
+ "$CC "*) ;;
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when ltconfig was run.
+ "`$echo $CC` "*) ;;
+ *)
+ for z in $available_tags; do
+ if grep "^### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`sed -n -e '/^### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
+ case $base_compile in
+ "$CC "*)
+ # The compiler in $compile_command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ "`$echo $CC` "*)
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ echo "$modename: unable to infer tagged configuration"
+ echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit 1
+# else
+# echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+
+ # calculate the name of the file, without its directory
+ outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+ # Create the object directory.
+ if test ! -d $output_objdir; then
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ status=$?
+ if test $status -ne 0 && test ! -d $output_objdir; then
+ exit $status
+ fi
+ fi
+
+ # Determine the type of output
+ case $output in
+ "")
+ $echo "$modename: you must specify an output file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ libs="$libs $deplib"
+ done
+
+ if test $linkmode = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+ case $linkmode in
+ lib)
+ passes="conv link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+ for pass in $passes; do
+ if test $linkmode = prog; then
+ # Determine which files to process
+ case $pass in
+ dlopen)
+ libs="$dlfiles"
+ save_deplibs="$deplibs" # Collect dlpreopened libraries
+ deplibs=
+ ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -l*)
+ if test $linkmode = oldlib && test $linkmode = obj; then
+ $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2
+ continue
+ fi
+ if test $pass = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+ for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}.la"
+ if test -f "$lib"; then
+ found=yes
+ break
+ fi
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ ;; # -l
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test $pass = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ prog)
+ if test $pass = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test $pass = scan; then
+ deplibs="$deplib $deplibs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ ;;
+ *)
+ $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test $pass = link; then
+ dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test $pass = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ if test "$deplibs_check_method" != pass_all; then
+ echo
+ echo "*** Warning: This library needs some functionality provided by $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ else
+ echo
+ echo "*** Warning: Linking the shared library $output against the"
+ echo "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ prog)
+ if test $pass != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+ if test $found = yes || test -f "$lib"; then :
+ else
+ $echo "$modename: cannot find the library \`$lib'" 1>&2
+ exit 1
+ fi
+
+ # Check to see that this really is a libtool archive.
+ if (sed -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variable installed.
+ installed=yes
+
+ # Read the .la file
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test $linkmode = oldlib && test $linkmode = obj; }; then
+ # Add dl[pre]opened files of deplib
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test $pass = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit 1
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ tmp_libs="$tmp_libs $deplib"
+ done
+ elif test $linkmode != prog && test $linkmode != lib; then
+ $echo "$modename: \`$lib' is not a convenience library" 1>&2
+ exit 1
+ fi
+ continue
+ fi # $pass = conv
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit 1
+ fi
+
+ # This library was specified with -dlopen.
+ if test $pass = dlopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+ exit 1
+ fi
+ if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload.
+ dlprefiles="$dlprefiles $lib"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ $echo "$modename: warning: library \`$lib' was moved." 1>&2
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi # $installed = yes
+ name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+ # This library was specified with -dlpreopen.
+ if test $pass = dlpreopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+ exit 1
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test $linkmode = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs"
+ fi
+ continue
+ fi
+
+ if test $linkmode = prog && test $pass != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+ esac
+ # Need to link against all dependency_libs?
+ if test $linkalldeplibs = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ link_static=no # Whether the deplib will be linked statically
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ # Link against this shared library
+
+ if test "$linkmode,$pass" = "prog,link" ||
+ { test $linkmode = lib && test $hardcode_into_libs = yes; }; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ if test $linkmode = prog; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var"; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath " in
+ *" $dir "*) ;;
+ *" $absdir "*) ;;
+ *) temp_rpath="$temp_rpath $dir" ;;
+ esac
+ fi
+ fi
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+ libname=`eval \\$echo \"$libname_spec\"`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin*)
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ soname=`echo $soroot | sed -e 's/^.*\///'`
+ newlib="libimp-`echo $soname | sed 's/^lib//;s/\.dll$//'`.a"
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ $show "extracting exported symbol list from \`$soname'"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ eval cmds=\"$extract_expsyms_cmds\"
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ $show "generating import library for \`$soname'"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ eval cmds=\"$old_archive_from_expsyms_cmds\"
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n $old_archive_from_expsyms_cmds
+
+ if test $linkmode = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ $echo "$modename: configuration error: unsupported hardcode properties"
+ exit 1
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test $linkmode = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes && \
+ test "$hardcode_minus_L" != yes && \
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test $linkmode = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ add="-l$name"
+ fi
+
+ if test $linkmode = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test $linkmode = prog; then
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+
+ # Try to link the static library
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ echo "*** Warning: This library needs some functionality provided by $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ echo "*** Therefore, libtool will create a static module, that should work "
+ echo "*** as long as the dlopening application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ convenience="$convenience $dir/$old_library"
+ old_convenience="$old_convenience $dir/$old_library"
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test $linkmode = lib; then
+ if test -n "$dependency_libs" &&
+ { test $hardcode_into_libs != yes || test $build_old_libs = yes ||
+ test $link_static = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test $link_all_deplibs != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$deplib" && dir="."
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if grep "^installed=no" $deplib > /dev/null; then
+ path="-L$absdir/$objdir"
+ else
+ eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ if test "$absdir" != "$libdir"; then
+ $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+ fi
+ path="-L$absdir"
+ fi
+ ;;
+ *) continue ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test $pass = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test $pass != dlopen; then
+ test $pass != scan && dependency_libs="$newdependency_libs"
+ if test $pass != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ if test "$pass" = "conv" &&
+ { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then
+ libs="$deplibs" # reset libs
+ deplibs=
+ fi
+ done # for pass
+ if test $linkmode = prog; then
+ dlfiles="$newdlfiles"
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+ fi
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ if test "$module" = no; then
+ $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ eval libname=\"$libname_spec\"
+ else
+ libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+ exit 1
+ else
+ echo
+ echo "*** Warning: Linking the shared library $output against the non-libtool"
+ echo "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ if test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+ fi
+
+ set dummy $rpath
+ if test $# -gt 2; then
+ $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+ fi
+ install_libdir="$2"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+ fi
+ else
+
+ # Parse the version information argument.
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ IFS="$save_ifs"
+
+ if test -n "$8"; then
+ $echo "$modename: too many parameters to \`-version-info'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ current="$2"
+ revision="$3"
+ age="$4"
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $revision in
+ 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $age in
+ 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test $age -gt $current; then
+ $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ minor_current=`expr $current + 1`
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current";
+ ;;
+
+ irix)
+ major=`expr $current - $age + 1`
+ verstring="sgi$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test $loop != 0; do
+ iface=`expr $revision - $loop`
+ loop=`expr $loop - 1`
+ verstring="sgi$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ major=`expr $current - $age`
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test $loop != 0; do
+ iface=`expr $current - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ verstring="0.0"
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+ fi
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`echo "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ if test -n "$removelist"; then
+ $show "${rm}r $removelist"
+ $run ${rm}r $removelist
+ fi
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ for path in $notinst_path; do
+ lib_search_path=`echo "$lib_search_path " | sed -e 's% $path % %g'`
+ deplibs=`echo "$deplibs " | sed -e 's% -L$path % %g'`
+ dependency_libs=`echo "$dependency_libs " | sed -e 's% -L$path % %g'`
+ done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test $hardcode_into_libs != yes || test $build_old_libs = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs -framework System"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test $build_libtool_need_lc = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behaviour.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $rm conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $rm conftest
+ $LTCC -o conftest conftest.c $deplibs
+ if test $? -eq 0 ; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ echo "*** Warning: This library needs some functionality provided by $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ else
+ # Error occured in the first compile. Let's try to salvage the situation:
+ # Compile a seperate program for each library.
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ $rm conftest
+ $LTCC -o conftest conftest.c $i
+ # Did it work?
+ if test $? -eq 0 ; then
+ ldd_output=`ldd conftest`
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ echo "*** Warning: This library needs some functionality provided by $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ fi
+ else
+ droppeddeps=yes
+ echo
+ echo "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method
+ file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null \
+ | grep " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | sed 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+ | sed 10q \
+ | egrep "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ echo "*** Warning: This library needs some functionality provided by $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ if eval echo \"$potent_lib\" 2>/dev/null \
+ | sed 10q \
+ | egrep "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ echo "*** Warning: This library needs some functionality provided by $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+ -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' |
+ grep . >/dev/null; then
+ echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ echo "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test $allow_undefined = no; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test $hardcode_into_libs = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ test -z "$dlname" && dlname=$soname
+
+ lib="$output_objdir/$realname"
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+# # Ensure that we have .o objects for linkers which dislike .lo
+# # (e.g. aix) in case we are running --disable-static
+# for obj in $libobjs; do
+# xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+# if test "X$xdir" = "X$obj"; then
+# xdir="."
+# else
+# xdir="$xdir"
+# fi
+# baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+# oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
+# if test ! -f $xdir/$oldobj && test "$baseobj" != "$oldobj"; then
+# $show "(cd $xdir && ${LN_S} $baseobj $oldobj)"
+# $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $?
+# fi
+# done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ eval cmds=\"$export_symbols_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex"; then
+ $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+ $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+ $run eval '$mv "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+ fi
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test $status -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test $status -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+ libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval cmds=\"$archive_expsym_cmds\"
+ else
+ eval cmds=\"$archive_cmds\"
+ fi
+ if len=`expr "X$cmds" : ".*"` &&
+ test $len -le $max_cmd_len; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise.
+ $echo "creating reloadable object files..."
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ delfiles=
+ last_robj=
+ k=1
+ output=$output_objdir/$save_output-${k}.$objext
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+ if test "X$objlist" = X ||
+ { len=`expr "X$test_cmds" : ".*"` &&
+ test $len -le $max_cmd_len; }; then
+ objlist="$objlist $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test $k -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+ fi
+ last_robj=$output_objdir/$save_output-${k}.$objext
+ k=`expr $k + 1`
+ output=$output_objdir/$save_output-${k}.$objext
+ objlist=$obj
+ len=1
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+ # Set up a command to remove the reloadale object files
+ # after they are used.
+ i=0
+ while test $i -lt $k
+ do
+ i=`expr $i + 1`
+ delfiles="$delfiles $output_objdir/$save_output-${i}.$objext"
+ done
+
+ $echo "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval cmds=\"$archive_expsym_cmds\"
+ else
+ eval cmds=\"$archive_cmds\"
+ fi
+
+ # Append the command to remove the reloadable object files
+ # to the just-reset $cmds.
+ eval cmds=\"\$cmds~$rm $delfiles\"
+ fi
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+ exit 0
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+ fi
+
+ case $output in
+ *.lo)
+ if test -n "$objs$old_deplibs"; then
+ $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+ exit 1
+ fi
+ libobj="$output"
+ obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $run $rm $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${obj}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test $status -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test $status -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+ reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ eval cmds=\"$reload_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $run eval "echo timestamp > $libobj" || exit $?
+ exit 0
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ eval cmds=\"$reload_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+# else
+# # Just create a symlink.
+# $show $rm $libobj
+# $run $rm $libobj
+# xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
+# if test "X$xdir" = "X$libobj"; then
+# xdir="."
+# else
+# xdir="$xdir"
+# fi
+# baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
+# oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
+# $show "(cd $xdir && $LN_S $oldobj $baseobj)"
+# $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $?
+ fi
+
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) output=`echo $output | sed -e 's,.exe$,,;s,$,.exe,'` ;;
+ esac
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+ fi
+
+ if test "$preload" = yes; then
+ if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+ test "$dlopen_self_static" = unknown; then
+ $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+ fi
+ fi
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ dlsyms=
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ dlsyms="${outputname}S.c"
+ else
+ $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+ fi
+ fi
+
+ if test -n "$dlsyms"; then
+ case $dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${outputname}.nm"
+
+ $show "$rm $nlist ${nlist}S ${nlist}T"
+ $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+ # Parse the name list into a source file.
+ $show "creating $output_objdir/$dlsyms"
+
+ test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ $show "generating symbol list for \`$output'"
+
+ test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles="$objs$old_deplibs"
+ for arg in $progfiles; do
+ $show "extracting global C symbols from \`$arg'"
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$output.exp"
+ $run $rm $export_symbols
+ $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ else
+ $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
+ $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+ $run eval 'mv "$nlist"T "$nlist"'
+ fi
+ fi
+
+ for arg in $dlprefiles; do
+ $show "extracting global C symbols from \`$arg'"
+ name=`echo "$arg" | sed -e 's%^.*/%%'`
+ $run eval 'echo ": $name " >> "$nlist"'
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -z "$run"; then
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $mv "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then
+ :
+ else
+ grep -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$dlsyms"
+ fi
+
+ $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+ sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \
+ -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \
+ < "$nlist" >> "$output_objdir/$dlsyms"
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ {0, (lt_ptr_t) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ fi
+
+ pic_flag_for_symtable=
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+ esac;;
+ *-*-hpux*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag";;
+ esac
+ esac
+
+ # Now compile the dynamic symbol file.
+ $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+ # Clean up the generated files.
+ $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+ $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+ # Transform the symbol file into the correct name.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ ;;
+ *)
+ $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+ exit 1
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+ fi
+
+ if test $need_relink = no || test "$build_libtool_libs" != yes; then
+ # Replace the output file specification.
+ compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ $show "$link_command"
+ $run eval "$link_command"
+ status=$?
+
+ # Delete the generated files.
+ if test -n "$dlsyms"; then
+ $show "$rm $output_objdir/${outputname}S.${objext}"
+ $run $rm "$output_objdir/${outputname}S.${objext}"
+ fi
+
+ exit $status
+ fi
+
+ if test -n "$shlibpath_var"; then
+ # We should set the shlibpath_var
+ rpath=
+ for dir in $temp_rpath; do
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*)
+ # Absolute path.
+ rpath="$rpath$dir:"
+ ;;
+ *)
+ # Relative path: add a thisdir entry.
+ rpath="$rpath\$thisdir/$dir:"
+ ;;
+ esac
+ done
+ temp_rpath="$rpath"
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $run $rm $output
+ # Link the executable and exit
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+ exit 0
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+ $echo "$modename: \`$output' will be relinked during installation" 1>&2
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+
+ # Now create the wrapper script.
+ $show "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ relink_command="cd `pwd`; $relink_command"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Quote $echo for shipping.
+ if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
+ case $0 in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
+ esac
+ qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if our run command is non-null.
+ if test -z "$run"; then
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) output=`echo $output|sed 's,.exe$,,'` ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*) exeext=.exe ;;
+ *) exeext= ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit 1" 1 2 15
+
+ $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variable:
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$echo are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ echo=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$echo works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$echo will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $echo >> $output "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\`
+ done
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ echo >> $output "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" || \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $mkdir \"\$progdir\"
+ else
+ $rm \"\$progdir/\$file\"
+ fi"
+
+ echo >> $output "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $echo \"\$relink_command_output\" >&2
+ $rm \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $rm \"\$progdir/\$program\";
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $rm \"\$progdir/\$file\"
+ fi"
+ else
+ echo >> $output "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ echo >> $output "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $echo >> $output "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $echo >> $output "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $echo >> $output "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # win32 systems need to use the prog path for dll
+ # lookup to work
+ *-*-cygwin* | *-*-pw32*)
+ $echo >> $output "\
+ exec \$progdir/\$program \${1+\"\$@\"}
+"
+ ;;
+
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2*)
+ $echo >> $output "\
+ exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $echo >> $output "\
+ # Export the path to the program.
+ PATH=\"\$progdir:\$PATH\"
+ export PATH
+
+ exec \$program \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $echo >> $output "\
+ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+ exit 1
+ fi
+ else
+ # The program doesn't exist.
+ \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+ \$echo \"This script is just a wrapper for \$program.\" 1>&2
+ echo \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+ chmod +x $output
+ fi
+ exit 0
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$objs$old_deplibs $non_pic_objects"
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test $status -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ # Add in members from convenience archives.
+ for xlib in $addlibs; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test $status -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+ oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print | $NL2SP`
+ done
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ eval cmds=\"$old_archive_from_new_cmds\"
+ else
+# # Ensure that we have .o objects in place in case we decided
+# # not to build a shared library, and have fallen back to building
+# # static libs even though --disable-static was passed!
+# for oldobj in $oldobjs; do
+# if test ! -f $oldobj; then
+# xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'`
+# if test "X$xdir" = "X$oldobj"; then
+# xdir="."
+# else
+# xdir="$xdir"
+# fi
+# baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'`
+# obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"`
+# $show "(cd $xdir && ${LN_S} $obj $baseobj)"
+# $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $?
+# fi
+# done
+
+ eval cmds=\"$old_archive_cmds\"
+
+ if len=`expr "X$cmds" : ".*"` &&
+ test $len -le $max_cmd_len; then
+ :
+ else
+ # the command line is too long to link in one step, link in parts
+ $echo "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ for obj in $save_oldobjs
+ do
+ oldobjs="$objlist $obj"
+ objlist="$objlist $obj"
+ eval test_cmds=\"$old_archive_cmds\"
+ if len=`expr "X$test_cmds" : ".*"` &&
+ test $len -le $max_cmd_len; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ eval cmds=\"\$concat_cmds~$old_archive_cmds\"
+ fi
+ fi
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$generated"; then
+ $show "${rm}r$generated"
+ $run ${rm}r$generated
+ fi
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ $show "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ tagopts=
+ for tag in $taglist; do
+ tagopts="$tagopts --tag $tag"
+ done
+ relink_command="(cd `pwd`; $SHELL $0$tagopts --mode=relink $libtool_args)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+
+ # Only create the output if not a dry run.
+ if test -z "$run"; then
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+ for lib in $dlfiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdlfiles="$newdlfiles $libdir/$name"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $rm $output
+ # place dlname in correct position for cygwin
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+ esac
+ $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test $need_relink = yes; then
+ $echo >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ fi
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+ $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+ ;;
+ esac
+ exit 0
+ ;;
+
+ # libtool install mode
+ install)
+ modename="$modename: install"
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
+ # Aesthetically quote it.
+ arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$arg "
+ arg="$1"
+ shift
+ else
+ install_prog=
+ arg="$nonopt"
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog$arg"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest="$arg"
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f) prev="-f" ;;
+ -g) prev="-g" ;;
+ -m) prev="-m" ;;
+ -o) prev="-o" ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*) ;;
+
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest="$arg"
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog $arg"
+ done
+
+ if test -z "$install_prog"; then
+ $echo "$modename: you must specify an install program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prev' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ $echo "$modename: no file or destination specified" 1>&2
+ else
+ $echo "$modename: you must specify a destination" 1>&2
+ fi
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Strip any trailing slash from the destination.
+ dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$destdir" = "X$dest" && destdir=.
+ destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files
+ if test $# -gt 2; then
+ $echo "$modename: \`$dest' is not a directory" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ library_names=
+ old_library=
+ relink_command=
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+ test "X$dir" = "X$file/" && dir=
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ $echo "$modename: warning: relinking \`$file'" 1>&2
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ exit 1
+ fi
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names
+ if test -n "$2"; then
+ realname="$2"
+ shift
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ $show "$install_prog $dir/$srcname $destdir/$realname"
+ $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$striplib $destdir/$realname"
+ $run eval "$striplib $destdir/$realname" || exit $?
+ fi
+
+ if test $# -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ for linkname
+ do
+ if test "$linkname" != "$realname"; then
+ $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ fi
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ eval cmds=\"$postinstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Install the pseudo-library for information purposes.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ instname="$dir/$name"i
+ $show "$install_prog $instname $destdir/$name"
+ $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ if test -n "$destfile"; then
+ $show "$install_prog $file $destfile"
+ $run eval "$install_prog $file $destfile" || exit $?
+ fi
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+ $show "$install_prog $staticobj $staticdest"
+ $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+ fi
+ exit 0
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Do a test to see if this is really a libtool program.
+ if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ notinst_deplibs=
+ relink_command=
+
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Check the variables that should have been set.
+ if test -z "$notinst_deplibs"; then
+ $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2
+ exit 1
+ fi
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ # If there is no directory component, then add one.
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ fi
+ libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ if test "$finalize" = yes && test -z "$run"; then
+ tmpdir="/tmp"
+ test -n "$TMPDIR" && tmpdir="$TMPDIR"
+ tmpdir="$tmpdir/libtool-$$"
+ if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then :
+ else
+ $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+ continue
+ fi
+ file=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ ${rm}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ $echo "$modename: warning: cannot relink \`$file'" 1>&2
+ fi
+ else
+ # Install the binary that we compiled earlier.
+ file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyways
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ destfile=`echo $destfile | sed -e 's,.exe$,,'`
+ ;;
+ esac
+ ;;
+ esac
+
+ $show "$install_prog$stripme $file $destfile"
+ $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+ test -n "$outputname" && ${rm}r "$tmpdir"
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ $show "$install_prog $file $oldlib"
+ $run eval "$install_prog \$file \$oldlib" || exit $?
+
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$old_striplib $oldlib"
+ $run eval "$old_striplib $oldlib" || exit $?
+ fi
+
+ # Do each command in the postinstall commands.
+ eval cmds=\"$old_postinstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$future_libdirs"; then
+ $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+ fi
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ test -n "$run" && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $0 --finish$current_libdirs'
+ else
+ exit 0
+ fi
+ ;;
+
+ # libtool finish mode
+ finish)
+ modename="$modename: finish"
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ eval cmds=\"$finish_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || admincmds="$admincmds
+ $cmd"
+ done
+ IFS="$save_ifs"
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $run eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ test "$show" = ":" && exit 0
+
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ echo " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ echo " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ echo " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ echo
+ echo "See any operating system documentation about shared libraries for"
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ echo "----------------------------------------------------------------------"
+ exit 0
+ ;;
+
+ # libtool execute mode
+ execute)
+ modename="$modename: execute"
+
+ # The first argument is the command name.
+ cmd="$nonopt"
+ if test -z "$cmd"; then
+ $echo "$modename: you must specify a COMMAND" 1>&2
+ $echo "$help"
+ exit 1
+ fi
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ if test ! -f "$file"; then
+ $echo "$modename: \`$file' is not a file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+ exit 1
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ ;;
+
+ *)
+ $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+ args="$args \"$file\""
+ done
+
+ if test -z "$run"; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved enviroment variables
+ if test "${save_LC_ALL+set}" = set; then
+ LC_ALL="$save_LC_ALL"; export LC_ALL
+ fi
+ if test "${save_LANG+set}" = set; then
+ LANG="$save_LANG"; export LANG
+ fi
+
+ # Now prepare to actually exec the command.
+ exec_cmd='"$cmd"$args'
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+ $echo "export $shlibpath_var"
+ fi
+ $echo "$cmd$args"
+ exit 0
+ fi
+ ;;
+
+ # libtool clean and uninstall mode
+ clean | uninstall)
+ modename="$modename: $mode"
+ rm="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) rm="$rm $arg"; rmforce=yes ;;
+ -*) rm="$rm $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ if test -z "$rm"; then
+ $echo "$modename: you must specify an RM program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ rmdirs=
+
+ for file in $files; do
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$file"; then
+ dir=.
+ objdir="$objdir"
+ else
+ objdir="$dir/$objdir"
+ fi
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ test $mode = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test $mode = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if (test -L "$file") >/dev/null 2>&1 \
+ || (test -h "$file") >/dev/null 2>&1 \
+ || test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ . $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+ test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+
+ if test $mode = uninstall; then
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ eval cmds=\"$postuninstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test $? != 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ eval cmds=\"$old_postuninstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test $? != 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+ # Read the .lo file
+ . $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" \
+ && test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" \
+ && test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ # Do a test to see if this is a libtool program.
+ if test $mode = clean &&
+ (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ relink_command=
+ . $dir/$file
+
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ fi
+ ;;
+ esac
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles || exit_status=1
+ done
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ $show "rmdir $dir"
+ $run rmdir $dir >/dev/null 2>&1
+ fi
+ done
+
+ exit $exit_status
+ ;;
+
+ "")
+ $echo "$modename: you must specify a MODE" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test -z "$exec_cmd"; then
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+ fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+ eval exec $exec_cmd
+ exit 1
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+-n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --finish same as \`--mode=finish'
+ --help display this help message and exit
+ --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
+ --quiet same as \`--silent'
+ --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ --version print version information
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE."
+ exit 0
+ ;;
+
+clean)
+ $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+compile)
+ $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -static always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+execute)
+ $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+finish)
+ $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+install)
+ $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+link)
+ $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -static do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+uninstall)
+ $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+*)
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+esac
+
+echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit 0
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+### END LIBTOOL TAG CONFIG: disable-shared
+
+### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/contrib/gdb/md5.sum b/contrib/gdb/md5.sum
new file mode 100644
index 0000000..5348d5f
--- /dev/null
+++ b/contrib/gdb/md5.sum
@@ -0,0 +1,5330 @@
+0636e73ff0215e8d672dc4c32c317bb3 COPYING
+f30a9716ef3762e3467a2f62bf790f0a COPYING.LIB
+01b56d00067e222fa90de4ad0c8b0bab Makefile.def
+a2362771d50b4a6940ed689988368915 Makefile.in
+857b2349378408c5f0cf3d4ee6eaed47 Makefile.tpl
+07c33a285703b40cd6f93a478e97e03b README
+ceab81aa1f02825092808fdafba0239d bfd/COPYING
+ddb9e929c08f79992b3cab4a7ef7fd18 bfd/ChangeLog
+daabeea83b81f2707d48d2c04dcc37c4 bfd/ChangeLog-0001
+258372f0002edcee47f582f172db1b3c bfd/ChangeLog-0203
+8dcb7ce2e45911e21ceb6e457e69eacf bfd/ChangeLog-9193
+6d37ec6ee5f57a1188a0717f2fa5deb0 bfd/ChangeLog-9495
+b7ad288235bf6a3e015e01cb6096cbe7 bfd/ChangeLog-9697
+dbb0d89c90d6c0ec79eb003a5b63f923 bfd/ChangeLog-9899
+d618facc3e8ce8bf3d02ba452e1be6ab bfd/MAINTAINERS
+ae6fc11266155eb05e6b1833c60e8a56 bfd/Makefile.am
+c4519eb4e3ebc32fe734e20562e6577e bfd/Makefile.in
+6455e3c85b31e588ecb75f7d3c945c8d bfd/PORTING
+2d6a5be3f5d1b33251fe9a8570e943d8 bfd/README
+cd26654c6eb30680694867e434e40044 bfd/TODO
+95b37f5a8b37019a0ae21e25a9df8943 bfd/acinclude.m4
+c2c720e6830eb31a7c9fe961f3708643 bfd/aclocal.m4
+f9c82c819ae27c28980b9b4feaf2bc16 bfd/aix386-core.c
+56c6a28898034cf5a2f788b879c058f8 bfd/aix5ppc-core.c
+cdfcd10f565dc089740f1767afde4a99 bfd/aout-adobe.c
+a086890accd499e2cfcbfdec741e6f0c bfd/aout-arm.c
+2d02ebe9d3ccfa281e766434a34dbaf9 bfd/aout-cris.c
+5bf71068402124e456fa8e7ce67a2bed bfd/aout-encap.c
+6f39a856277e0c7ab9ca3d5e951a20f8 bfd/aout-ns32k.c
+e5462c5655e858dd98c46e362a87d39a bfd/aout-sparcle.c
+e34f2112b40dfb78b88f6cc36e1f9efd bfd/aout-target.h
+9157bbb7045a28e9c75ba785197c95cc bfd/aout-tic30.c
+b7d0f371ad6ceb36548dcbad20e17859 bfd/aout0.c
+710ff75a0a234773691c069654dd8ba6 bfd/aout32.c
+cae169ce11deb6f450104c569c23c853 bfd/aout64.c
+7d60016ff69bd848e9dfa548841f835b bfd/aoutf1.h
+1ff426e7d0cd60b79f8f42246b5fb5c7 bfd/aoutx.h
+b6b8cab99a4e0177241839a45bb85672 bfd/archive.c
+06dbd5afe5d36755a172507b6c559fc1 bfd/archive64.c
+f36760f48ecda411b5aa7a3a44fe0909 bfd/archures.c
+7355fa1829188da840a37bc85c39b737 bfd/armnetbsd.c
+c8d8eca8b4e908b100434934502f698c bfd/bfd-in.h
+ae3b4128551b1af0da2c464c44f917ba bfd/bfd-in2.h
+15ec69d5a6d895f969f58f260b2ec814 bfd/bfd.c
+3f968067c77722717f149f143d3f8c19 bfd/bfdio.c
+d7491728b7a204e534ab0adb45c46b5a bfd/bfdwin.c
+44c3865a37a4a0e66d26f7e560127b74 bfd/binary.c
+42b962329287e46ca79d8cb8d53ad7a7 bfd/bout.c
+d5aff65092c9d720c4c03894946b12e5 bfd/cache.c
+6d3c1b378bc7ed685664fe6eca297523 bfd/cf-i386lynx.c
+545c111611d3dddaae8c666293aac89b bfd/cf-m68klynx.c
+09a8617f3c790897c5ac230aa7c9e683 bfd/cf-sparclynx.c
+70d403922007ecd1e12768a941a1ca4b bfd/cisco-core.c
+c5759e7cc48faca87b33154ed1be2240 bfd/coff-a29k.c
+24f4ff12b1912cbafaa396ea48ec68a2 bfd/coff-alpha.c
+ed5b46a86e1b44f2d30b43a540f2ccca bfd/coff-apollo.c
+d29b52a4c23bce50c9acd3e72cb64e8e bfd/coff-arm.c
+8059bbea66752b7c96719dd935da545e bfd/coff-aux.c
+b7572dbbd820acf00c9d5571af08f2e5 bfd/coff-go32.c
+a067a43cc2184b463beda82740386230 bfd/coff-h8300.c
+8036e3eb44b0885a377ed963d5a8e2dd bfd/coff-h8500.c
+97f4f9ac464fd52d0941811e8e741256 bfd/coff-i386.c
+fa6c489482cb4abdede4a60a16e415af bfd/coff-i860.c
+e9e0ac6ef4f1b9a6e0c091348a0abc3a bfd/coff-i960.c
+3743199a9b010f682e0002fe0896aae8 bfd/coff-ia64.c
+37adbd3ad6583bdf182b8c79d0a09497 bfd/coff-m68k.c
+e7cd4503d04fbf49fb5283b26f52ebba bfd/coff-m88k.c
+08b0ca5de3fb97f57e83d3ab6f7ebb23 bfd/coff-mcore.c
+72cbac7f5701cbc2baaa65a5fb7a0eec bfd/coff-mips.c
+866c505604722466b2f17d8c81a92b2c bfd/coff-or32.c
+0fe98f356a19d05611fa133c217e77e5 bfd/coff-pmac.c
+4be03c7038009a13af548604d7ec4bbc bfd/coff-ppc.c
+38de8920d47aa9eb553984d60087a293 bfd/coff-rs6000.c
+d45c75a567e771e67c4a36a12c9c2b92 bfd/coff-sh.c
+e62fbc5f8a3dd5662a059b60adad11c2 bfd/coff-sparc.c
+1ed0e24cda15ce0fbc0c907703622d72 bfd/coff-stgo32.c
+0a6bcb90289a5f62cb39fb0ec0858560 bfd/coff-svm68k.c
+3daee2f40d2b787308e9a1d709aca805 bfd/coff-tic30.c
+d1a0fb769c7f69895d7bf8109e72a510 bfd/coff-tic4x.c
+6760e615015a480a9d9cc7260e59658b bfd/coff-tic54x.c
+cd9a56d38f1a450f4ecdb7cc7bab5aba bfd/coff-tic80.c
+f8c6308a039c92faded1d165112668a2 bfd/coff-u68k.c
+b8a401b68f742b58596a8fe4e3c0160b bfd/coff-w65.c
+61d5c4ba4236dca72fe7a7b04679c548 bfd/coff-we32k.c
+f0e47a0c5b5f217148ab8af737e13571 bfd/coff-z8k.c
+0a457ba20592d35dd3e5d6f5b5191a23 bfd/coff64-rs6000.c
+f2221a9bb0b95569ef24b4655587655f bfd/coffcode.h
+31f6379e9b9fef8fa518c46427f19a12 bfd/coffgen.c
+4b41f2bf4937575625d75541e86b4652 bfd/cofflink.c
+eb4672541cca282f98893fa0e72a9b6d bfd/coffswap.h
+f1d700ad46f2ed115e4ddb02a6c15858 bfd/config.bfd
+f83ff421796cffa5b1544eec5e6f9cf4 bfd/config.in
+0651a21130e58b3884778d44a64281dd bfd/configure
+a8485b69f68d81f4ef2f29b51bb36d85 bfd/configure.com
+2eda4de56a20d2079c1e2b8fc82fd303 bfd/configure.host
+cbe67e4ed47f62019ce9ff884bb5a4a6 bfd/configure.in
+ce0b415790c25f1bcfa1008a252bbe76 bfd/corefile.c
+5c0d89447ec9068a82206617864bb57c bfd/cpu-a29k.c
+a856235ca2eb870387b078ccd1084733 bfd/cpu-alpha.c
+38d8b50602f459cf46c67bffc9da2646 bfd/cpu-arc.c
+c05b041b2241758f209e9fb3153f7e3d bfd/cpu-arm.c
+8670a746d84a73a96a33ea674d44753e bfd/cpu-avr.c
+073416090cf1d506b6dd77023836cd5c bfd/cpu-cris.c
+6855298754b13705dd165a7f66730b27 bfd/cpu-d10v.c
+31a29cb2eb7bf274d02ad6e31bc94ebb bfd/cpu-d30v.c
+75333587061ce9eaec79515b6e61b80a bfd/cpu-dlx.c
+b0ca824687840d64ed72e95008b6696e bfd/cpu-fr30.c
+b340406eb6f6aa43c466d969c9707f2d bfd/cpu-frv.c
+d24bc250ce24cdd65be95e1ea80fa02b bfd/cpu-h8300.c
+6d8f7e09ca549a791d6e0604cd30bf71 bfd/cpu-h8500.c
+ad8dac130e4165ee8da68f554223e615 bfd/cpu-hppa.c
+8afc9dfed1753f4e8ddcd59f7ed51bfc bfd/cpu-i370.c
+5984ec8fa236636b1c16c555c873c650 bfd/cpu-i386.c
+32e8b88620f294fd92d9fa24389458c3 bfd/cpu-i860.c
+059eacc0c428a5cc9aa957375599aaab bfd/cpu-i960.c
+4a6b4dde5d3182ef76e43d49956e26e2 bfd/cpu-ia64-opc.c
+b1b262009e59a8f0c79da9c9289a95fc bfd/cpu-ia64.c
+d64dd87b24efe5b86695ffbc4ef85c3e bfd/cpu-ip2k.c
+5fc83c8be02e0e57d85d76ac96346f34 bfd/cpu-iq2000.c
+55e75d011da4e793fa903eb588e971f5 bfd/cpu-m10200.c
+926dba983091df956a20d5ac2d03511c bfd/cpu-m10300.c
+1361b70e7b455b0f54fa1b1f172eba7c bfd/cpu-m32r.c
+a3600f2fa5f5279c65c53fa9b2071535 bfd/cpu-m68hc11.c
+0f263fd8bdf74135b519d82f50f2b954 bfd/cpu-m68hc12.c
+5a51d7542ae8054e1ca9fb2c41976ed1 bfd/cpu-m68k.c
+13d35f4c96e2d81d61040acb3c89b5e8 bfd/cpu-m88k.c
+15675fc1f00d26428fdd5ce42e15cf87 bfd/cpu-mcore.c
+3db5c0679216eaa5656974d7c2babbae bfd/cpu-mips.c
+dcc2f3d6c61b634e6df985262b698695 bfd/cpu-mmix.c
+b44e2935dd2f75d62a7ea83f4f031308 bfd/cpu-msp430.c
+2519296ad9ba616914f4795876ebe98d bfd/cpu-ns32k.c
+78e0773fce06924c1822036726ea15c1 bfd/cpu-openrisc.c
+16969a34418aa358869b6f3b0fc09e03 bfd/cpu-or32.c
+fb7ee1fa345060daece22d8cb7e14ebf bfd/cpu-pdp11.c
+7945d7fc4016ed304fd38a7427401b9d bfd/cpu-pj.c
+61d80887a1a812d2d04870993de06711 bfd/cpu-powerpc.c
+86b67838bec7ced639aba6d44b459554 bfd/cpu-rs6000.c
+f214ca1c10a452ac3990275a5536364c bfd/cpu-s390.c
+ce48f5d9ed1a3c19a57c118a245c204b bfd/cpu-sh.c
+1341cb777ccfc53c805e7427a0efb8b2 bfd/cpu-sparc.c
+4f3420afcf9cb5665b8f91290f9231c3 bfd/cpu-tic30.c
+99abf59d00537ba03be5ff5d6b9c40a9 bfd/cpu-tic4x.c
+d3feadb829b55be9f231f5374b4ab0f5 bfd/cpu-tic54x.c
+63ca1b136f3eb9e42b387e18ed07ec4d bfd/cpu-tic80.c
+03eac88302f1e6b9939e0e70cb6895f6 bfd/cpu-v850.c
+cafc0a276c6fe6f77003c66e9d84dfbc bfd/cpu-vax.c
+1eba036739554133ab48c605983638e6 bfd/cpu-w65.c
+3369bd707089438cb61a399b51712ad6 bfd/cpu-we32k.c
+5ea7e7adb4e971a0efa3adcbdc1c511a bfd/cpu-xstormy16.c
+f3353acce243bdf49f229f65c80be082 bfd/cpu-xtensa.c
+38bdf1a8b5d9eb2381786e747b623e7a bfd/cpu-z8k.c
+e03c6141f7dfc11bf97d902b02c543f8 bfd/demo64.c
+15ea8c60509b116547b6aa31e81c9613 bfd/dep-in.sed
+5a1ea97d362ce577b9d2ed82a25f77e4 bfd/dwarf1.c
+b5b58df49cf8d8fdce3120c98a46deae bfd/dwarf2.c
+91fbda4c532224d62f59046ba2a4178f bfd/ecoff.c
+9e4ddbd6ed8be774ca8f2349e59b1e55 bfd/ecofflink.c
+d4ad21eeaea85cd04f9c275a4a524652 bfd/ecoffswap.h
+fea84b9c79e99275ad3a20612d264929 bfd/efi-app-ia32.c
+87806770ec6a23866701b7662638ba96 bfd/efi-app-ia64.c
+14479130d0498e27cdcf14ae8badabfe bfd/elf-bfd.h
+f3962ec98ce9fd6bdc301d4b7e398089 bfd/elf-eh-frame.c
+8b272d79099e36fc1ee93bbcaee39720 bfd/elf-hppa.h
+ff2ff5cb72a156a60fade8e9f9eea2b2 bfd/elf-m10200.c
+9e84e766effda7bf3ca1af90500d14c9 bfd/elf-m10300.c
+ddd2eade9caa8aca9f1734fc92d82b6e bfd/elf-strtab.c
+cf3c4bd4b757f1feab442453a71c4a4b bfd/elf.c
+ce6b2e95b1ceecc5174e92b44e04827b bfd/elf32-am33lin.c
+fa56312cdca619fd096e4d887aa2c514 bfd/elf32-arc.c
+d03e5937a1e3a7313dc58b1b07fa5ace bfd/elf32-arm.h
+c780a734b5befa7d38847a91e650d5c3 bfd/elf32-avr.c
+2ec1fc1a2a7fbc540102bfaeb2deca6d bfd/elf32-cris.c
+6dbc6be073a31d93696922cefbfbe4bf bfd/elf32-d10v.c
+4bfbd76fbced7646457d1ab36d17eefd bfd/elf32-d30v.c
+35b57cd828093e8808a58a537a2f8bcc bfd/elf32-dlx.c
+94bfb2b97c0184e4e245151f666980d6 bfd/elf32-fr30.c
+36433103fa4291ea0e429691f1af8aab bfd/elf32-frv.c
+9d9a8056e6d01e8196156b8d0d38ec83 bfd/elf32-gen.c
+408f8469fdce94d0a70ae1c4c8d2be8e bfd/elf32-h8300.c
+fc5f0170bc7016c730e61f0eadfd581b bfd/elf32-hppa.c
+31c2c588dfd4812995b742742a1bdc86 bfd/elf32-hppa.h
+58469fb57c893c90cbd824b98ec9519a bfd/elf32-i370.c
+1057cd88eea1c27f4e1e1b433d23232e bfd/elf32-i386.c
+11fcc50089679d494433434b54fb841e bfd/elf32-i860.c
+3387b5c4a92adcf7ac7161b71e9d1e0e bfd/elf32-i960.c
+c3987c253f3cc62ba059a289b1f6a423 bfd/elf32-ip2k.c
+c4d368e7ff252fea7ff6dd5f627b199e bfd/elf32-iq2000.c
+b8b9ab48eb6343ec3c398d1a2311de4b bfd/elf32-m32r.c
+455f4bae98b6260374be7378e6cf1dc3 bfd/elf32-m68hc11.c
+4c2866cc197a16648d83bd1962c0d7b1 bfd/elf32-m68hc12.c
+5efc141dabb7c3684ef201dd3e7d8e2d bfd/elf32-m68hc1x.c
+db22ff75b4183d38ac0afebd6a852bff bfd/elf32-m68hc1x.h
+8ceb93ad1cc7250297d53ca47a391562 bfd/elf32-m68k.c
+6d08a2b4a53db400e322f8f712aa9498 bfd/elf32-m88k.c
+a57d36b03e78461381dcffaf8f0cd2dd bfd/elf32-mcore.c
+e64e3dac81b71cd2474e0727fb2cf7e0 bfd/elf32-mips.c
+cf4e6321a70989dc93501a935188f7ae bfd/elf32-msp430.c
+e6a216ccbcae2ed24232df82bf3d8768 bfd/elf32-openrisc.c
+1f732f2c3af63b47edef956264130b83 bfd/elf32-or32.c
+f88946084255132c58a6db634f59bb95 bfd/elf32-pj.c
+51d42c9fa470165a7d91cc4a7c9d0a81 bfd/elf32-ppc.c
+177ef4609724779d4ed55850cbfa99b1 bfd/elf32-ppc.h
+80935d9d1b137a664639c45343b0120e bfd/elf32-s390.c
+2474a2d45e8fd8280dab89c0f987dc5b bfd/elf32-sh.c
+1af6d1ccf6330e120779a66ecfeaf11b bfd/elf32-sh64-com.c
+dc0a382a0c88ec81e2fcc3056387d25f bfd/doc/ChangeLog
+42b5ebab441fcbf65e95c2aa31262147 bfd/doc/ChangeLog-9103
+23ef21a07d973a0d6809a8f53bcd1675 bfd/doc/Makefile.am
+16f39b337cc1b1f9c5dce2644be9ef9f bfd/doc/Makefile.in
+e0e91b07018f1d9722268692f0e7b0ce bfd/doc/bfd.texinfo
+0f69cf6ca021b3c9e507ee615c710f9d bfd/doc/bfdint.texi
+5ee7f8ae8b0ec33c7baf2e004084aaa1 bfd/doc/bfdsumm.texi
+c12d7a1841284def3367de9759831490 bfd/doc/chew.c
+e67d8b07516154c4ddbee2e3bab3d75e bfd/doc/doc.str
+1cc3fb2ac1b5311b7639908a78232dd6 bfd/doc/fdl.texi
+39f61ac0fb56eced56e6894e7bc47cef bfd/doc/header.sed
+5fa24958e8a60b2f879af658e615ccc0 bfd/doc/makefile.vms
+d7a37304ccd7b245f93df4be02797477 bfd/doc/proto.str
+551e63b0eb7692e8b20711d1d2e58982 bfd/doc/aoutx.texi
+522217c56d19e9cf9fc34c3afbf64768 bfd/doc/archive.texi
+a31779a4ed5b4570221dc7ae178174d4 bfd/doc/archures.texi
+fbd9578afabb5003c84523423b06fd02 bfd/doc/bfdt.texi
+aaec20ba5c590e39f0f20a658a43dd95 bfd/doc/cache.texi
+956d852bf8e50e1e0e44c596568b488d bfd/doc/coffcode.texi
+a4d505981c9abe2add4ac13692fac080 bfd/doc/core.texi
+edddb27f6970dc93153be948b619b001 bfd/doc/elf.texi
+d41d8cd98f00b204e9800998ecf8427e bfd/doc/elfcode.texi
+1208bdf175c700f865a7e348583c8ccd bfd/doc/format.texi
+4c3b9427f5569a148768b9eb8876806c bfd/doc/libbfd.texi
+236e856bb13ee47adc5d7d253037640d bfd/doc/bfdwin.texi
+9e85fd141105d249ff2585a08af70761 bfd/doc/bfdio.texi
+0efeea0c247a9899aed4cee86e8db2d2 bfd/doc/opncls.texi
+c5af7ac43685cae4827cd35aaee9928c bfd/doc/reloc.texi
+83c5b66aea72852dcadaf4fcab5cf0d5 bfd/doc/section.texi
+f7dc7a07291373d93eeb964dfd84e685 bfd/doc/syms.texi
+01bf23430b0c0922024081a024786a86 bfd/doc/targets.texi
+72bc7195c38b3f966acfa5b670e47868 bfd/doc/init.texi
+f7070c1179b4cf5375fd0a1f3db81ee7 bfd/doc/hash.texi
+6db897ac372d7671a8475590413ba311 bfd/doc/linker.texi
+4b178141d4ecb16c4fd528a79a4e7d93 bfd/doc/mmo.texi
+ebf7ecf4a89ad34d85890ec5feef770e bfd/doc/bfd.info
+0004178dcc5a2d50254f54f9ca7ebada bfd/doc/bfd.info-1
+ee5f7054e7e25a79d7c748ffbaf83d49 bfd/doc/bfd.info-2
+c0dcf8d06801e64d94a10e1b36ccb807 bfd/elf32-sh64.c
+3f5def74504dc7c1041fb8a5e92129ba bfd/elf32-sh64.h
+5344c27413152ec06bd5758c03ff0e19 bfd/elf32-sparc.c
+19f878dfaadfb6080770e7b6a6fda1ae bfd/elf32-v850.c
+568208c36e302a7543067ff3c912f286 bfd/elf32-vax.c
+085619a0523ec49b741a0a69740f5a07 bfd/elf32-xstormy16.c
+cbd74477aa0d34ffbbb4899a9b464f15 bfd/elf32-xtensa.c
+ed57bd460ee2d4a61a5c445f280f295c bfd/elf32.c
+e0abc4acea14de809f1dac79fe0645bc bfd/elf64-alpha.c
+e7a6233c4ce3edd549eb0f3edd022ef3 bfd/elf64-gen.c
+57dd6dfe24200a3805e56b038192ba0c bfd/elf64-hppa.c
+fbf7f46376d56c745331fa9e25e19042 bfd/elf64-hppa.h
+a618209156ba8d18f8b3f5b084850d7e bfd/elf64-mips.c
+43cf4dee5b53fb37eba7da09e2c15b77 bfd/elf64-mmix.c
+e89898b60ed34c8ab64871e23237b8ca bfd/elf64-ppc.c
+16f5cffa79d09624ec3d26dfeb961856 bfd/elf64-ppc.h
+d30e21349fa2f8da16d4dc65977eb5e6 bfd/elf64-s390.c
+4937483eb68671466625dc8f8681182a bfd/elf64-sh64.c
+d2b71d2e5c52fe5dc34572d57366056c bfd/elf64-sparc.c
+65f166c82b9342fe91fb8412eeecfb98 bfd/elf64-x86-64.c
+0df4bff9f99908d451625f14be3dc667 bfd/elf64.c
+b1f33b4d5a4c137eb87216b322f40eee bfd/elfarm-nabi.c
+68b78b6d8e1ec8c802c17fbcda6c63b4 bfd/elfarm-oabi.c
+830469c13c89794aae5473da46704edc bfd/elfcode.h
+a9adb9386fb590b64711de5171d959ed bfd/elfcore.h
+9f9d828762a67edb0c3c9d53b075cb5a bfd/elflink.c
+00d0b8a0438bfd866c4401957a967443 bfd/elflink.h
+1a440c3d428972f41eb7c3aed175e11e bfd/elfn32-mips.c
+e11a015870d22916b8ac2d760e70a621 bfd/elfxx-ia64.c
+f48ef0a2235ce927f5bdad067530dea4 bfd/elfxx-mips.c
+4ea9b73a32192a4a8853ae1f9957b451 bfd/elfxx-mips.h
+daa35912abef252d7a06c88cc709f877 bfd/elfxx-target.h
+5f9b71e52009091cb901280cbe42283c bfd/epoc-pe-arm.c
+c9f006f05a9b9f4d6be5fa84dcad8b6a bfd/epoc-pei-arm.c
+a05bd2a535bb4cf02f221ec9457b2bd6 bfd/format.c
+eefe1c434d60657e776122f5c55c3d8f bfd/freebsd.h
+9905ea394a339286cb593f88d7758727 bfd/gen-aout.c
+5236b7eff1c5828c67db80d134ff2f66 bfd/genlink.h
+663a6979bd331c91d1385445edeca7b0 bfd/go32stub.h
+f8f22d70aba0ca01013719e50b137007 bfd/hash.c
+fa6b45528f762b75af43bcacc6acd8cb bfd/host-aout.c
+531b1bcee0e49314fce6cca36c2f335e bfd/hp300bsd.c
+04bdcf12654495a35ac354c0d5c725ff bfd/hp300hpux.c
+ade09540811efef1e31ad49819d729fd bfd/hppabsd-core.c
+ecd4853d4923d82823d899f0b347bf3a bfd/hpux-core.c
+57c936e8a3adfd68e7758aa598e8573d bfd/i386aout.c
+5b01cdc5ee8b0e9cd3fa57cfa577d57e bfd/i386bsd.c
+28ae231f375a6a503a0c3f82fab60b5f bfd/i386dynix.c
+c91f2b6fb802a0bf53bcd57c3faaccbf bfd/i386freebsd.c
+15c32e538d1a3d16670aad2de5564617 bfd/i386linux.c
+0f869e062010b8d3eeeca4f38753f4c9 bfd/i386lynx.c
+30cc7aa91bbf2d13677c1f72369b3f07 bfd/i386mach3.c
+c5b5aff9afa6f984a1fc2b3f34f17af9 bfd/i386msdos.c
+82991f62026cee0823a00ec99fffafc3 bfd/i386netbsd.c
+176197175927b7790a70415b95e63d61 bfd/i386os9k.c
+153bdc004a483472e76def7d40c1ae00 bfd/ieee.c
+709689da143822546add1d89c869c9e2 bfd/ihex.c
+586e6bd414ac178ab785a5f9965551c4 bfd/init.c
+180c2cb199d2fc7a407f0b59fa1745fb bfd/irix-core.c
+46cbfd585deee91db7dba527d5c0ce24 bfd/libaout.h
+0a2d4b73e5f38776396a3f3597bdb02c bfd/libbfd-in.h
+7265323cf6099483159852928d7b6fe1 bfd/libbfd.c
+2ffd243d372a207ce661e62a0453b665 bfd/libbfd.h
+9b9174f2cb9e5133f0deeee1a861bf45 bfd/libcoff-in.h
+b4773f89004edf4e1dcf024e6c3fae8f bfd/libcoff.h
+0d924fec5779723a72e46e715b8781ee bfd/libecoff.h
+bfd2fb804a3974b4e5ced4a16c308396 bfd/libhppa.h
+920cd61e1b6eef0bfacc3e6b1bf3057f bfd/libieee.h
+ec8a33230f7f0be0d900d2589e63a330 bfd/libnlm.h
+c9e76633b8cf7d2a676fbcc1aff5ad28 bfd/liboasys.h
+1a35f51f7169ed649b3bfb7708c34e76 bfd/libpei.h
+c021a4bf3e31a71731a1e9ac0d683321 bfd/libxcoff.h
+825c25c05a5e7de721136b7b7301855b bfd/linker.c
+a94e935b575e1815ef7af85f91d336d0 bfd/lynx-core.c
+a00d38276fdf8f0a76eb6a1203a8d4ff bfd/m68k4knetbsd.c
+6af8fc69de77ea2794e164ca76582751 bfd/m68klinux.c
+1c7fc5738825df3c8f55547c24f0e692 bfd/m68klynx.c
+f4e07f122ca03610fb6b9d76e2746dfb bfd/m68knetbsd.c
+873908a5fd292c77ca7a29e01db780ac bfd/m88kmach3.c
+cb4dbe2cce88b787643737cd05084d95 bfd/mach-o-target.c
+2a6293df12f54ec979911547a1f8ee35 bfd/mach-o.c
+ccfb3c1a456dd4300f25919f0d122f42 bfd/mach-o.h
+5de4da6a9169effb512e6ba4d014d420 bfd/makefile.vms
+b959394e47b356e8bf9e961ac5b1755d bfd/merge.c
+4a47ee157c9cda06a4df2f8d3a271e46 bfd/mipsbsd.c
+a53a4d0b7dfea8efc3c820a0a388f94f bfd/mmo.c
+5971cd61d7c10702978519aa5ed41474 bfd/mpw-config.in
+85bd791a2ac9c9d7c2bea1932665d568 bfd/mpw-make.sed
+0a05a7fcb22ce5e250425f7492924449 bfd/netbsd-core.c
+8528926a5dcc628f8c7b4a08b5e61f4b bfd/netbsd.h
+1581bb81823ec6ac33abb92c51b7b74e bfd/newsos3.c
+7a600ebb6dbaf147bdb8161b187a78a7 bfd/nlm-target.h
+4e45b4706a1e6ff1bd060647ca0edabe bfd/nlm.c
+44b970bb202376a27b0b2563fea16e68 bfd/nlm32-alpha.c
+5566bd19ab252ad17a78307d30866b7e bfd/nlm32-i386.c
+e05bbe04070cb3c7b5a44904b06805a1 bfd/nlm32-ppc.c
+af4856cbf1096e3323103ab5d3d4d45d bfd/nlm32-sparc.c
+ad09e68167b48df24f238e874a31a152 bfd/nlm32.c
+7d6920efa240ddfe625a9d076cd6510e bfd/nlm64.c
+9a7d23c9bbc084616d77314b70af7141 bfd/nlmcode.h
+157552f266a8853bdbf87b7c98acf825 bfd/nlmswap.h
+7d82893086041edcb2e9d5119d1d4802 bfd/ns32k.h
+fcba40f08d811e466c0c8f56bcc1f3dd bfd/ns32knetbsd.c
+cdb636036107872f6c4ed9c93db59f2a bfd/oasys.c
+d9c18f6831463a22db0e9ea42d17bf1f bfd/opncls.c
+64e6fd9c3810466bee8ae998ed68af41 bfd/osf-core.c
+280633df6d7c82ef1d0aa89f49c8b6f5 bfd/pc532-mach.c
+2b672107aa3308281b6a9d4eb5e379f6 bfd/pdp11.c
+8a141c46ec11672e4c3177b0d1fc0a46 bfd/pe-arm.c
+b429f4677696b2cd729ecc4dd616d91e bfd/pe-i386.c
+b6316514027908b40a8af4eafdbc306d bfd/pe-mcore.c
+598c8a8ab601080b5cae8ab42e82602c bfd/pe-mips.c
+2408372ef3e1635e1f21849c2df91516 bfd/pe-ppc.c
+4634b622d18f05d56e672cdef673dd72 bfd/pe-sh.c
+c817336d8f353bd59f38d42140f91050 bfd/peXXigen.c
+330199c7b8c4a19b30f2c587cc55ad5a bfd/pef-traceback.h
+c870c1b73e15d45920b1a54deafce168 bfd/pef.c
+7f525c89ec9a288a9d6b87fa3bb3e1a7 bfd/pef.h
+5bd98afdabed67da15460a8a39bed305 bfd/pei-arm.c
+cf2fd29cf4e9bc738f7529344c9e1a48 bfd/pei-i386.c
+f387c2799ec662d304422d3e67cc364f bfd/pei-mcore.c
+22db443681ead074ab0c5161ddf84b77 bfd/pei-mips.c
+f15a63befa27efcdbcd3711ecddd89a2 bfd/pei-ppc.c
+01f7c14bb6b07af2300c0d321ec8f823 bfd/pei-sh.c
+45dd8c3c634f189b212b4cee863b403a bfd/peicode.h
+630db51db4ebd32eda4736f14030ab01 bfd/ppcboot.c
+310fce924b7b29ebcfdf690e30a2aaf5 bfd/ptrace-core.c
+a39af63f63f1fa73a68d51eee08d6f0a bfd/reloc.c
+a74f7d6ebb8def3697451372bac9937a bfd/reloc16.c
+d774422a7bb83b8aa0433095dc97d304 bfd/riscix.c
+2a3e4cae47c61a4584804ea2b2cae49f bfd/rs6000-core.c
+867cfe30d33b4386af60d441a2f4d313 bfd/sco5-core.c
+38f8ae87bb9a35c262457e00720a782e bfd/section.c
+25a737999e92bd117e14b04d84f0ccb2 bfd/simple.c
+5cb88edecb2ec76da025658e6b151022 bfd/som.c
+9d67c54f60826e90cf939da4b6cbddf6 bfd/som.h
+20770d513289ed2f47247910f7789f5e bfd/sparclinux.c
+2261db74c28e00f78ce80025a0fcbcd5 bfd/sparclynx.c
+daea7ae2be94e245530a7df8f7a4219a bfd/sparcnetbsd.c
+ccca11062ee53332a665ecb74ae5434d bfd/srec.c
+891289f18ef687556cab8f090331e3fe bfd/stab-syms.c
+a9a86441cf4b994d4352f70251664c68 bfd/stabs.c
+1ded054093de910d9786c62bc4fe8cc6 bfd/stamp-h.in
+44fac4354106eea23189597728665882 bfd/sunos.c
+6dd19dd2de9d8006d5bb8cfddeae791c bfd/syms.c
+071010ad33a66b97d7f737c46ef8b2ab bfd/sysdep.h
+91c7d336f9a0e2beaaf095cc2d8f50ce bfd/targets.c
+53357a9b87dd158b90cf790c316fd438 bfd/targmatch.sed
+28db0127ebb4ad457152f56ab5cef598 bfd/tekhex.c
+00c3b5c6f8709ed54ae5b0d8da305f00 bfd/ticoff.h
+cb6bdd284510fdc060d456b9eafdfb68 bfd/trad-core.c
+ea8d625b4832344a89641e9b00cd9a2d bfd/vax1knetbsd.c
+775c0abfcf0027ff641997024ed1a54c bfd/vaxbsd.c
+cf93f1ed7a1b7cb96e2ae5be9c08d149 bfd/vaxnetbsd.c
+01ed7ef4d31595c5d9c3f9d7d34de2c0 bfd/versados.c
+cfbbe4bd708dfc28786ff0f3b9500dac bfd/version.h
+ae350ae719e0b1452519a7319cca467a bfd/vms-gsd.c
+baa6a7eb36fb2ab02df90d7f9748ab70 bfd/vms-hdr.c
+e1b412047b23b9cb0294448e27e0f0dd bfd/vms-misc.c
+3af8b9361012532efa66fe4390faa75c bfd/vms-tir.c
+1c1d4b145a89457e8f6c9d30a9229ce8 bfd/vms.c
+788714f4de9491b4665248bbd95458b8 bfd/vms.h
+ed2169f763a33558e638735d281c3583 bfd/xcoff-target.h
+2313eb7efbaabcbb0f15ac7522709306 bfd/xcofflink.c
+db3a8b04e6d055712ab5480e68a16406 bfd/xsym.c
+aeeb43cb5193b3b8d66b5feeb7a3c763 bfd/xsym.h
+f0edc5b6ff0b89fd9805ff2ccdd56ab9 bfd/xtensa-isa.c
+d99fd7072f0b4f4832333334bdbe6c62 bfd/xtensa-modules.c
+74b9e8377ce5ef7f2ad8914ad5e1dd41 bfd/hosts/alphalinux.h
+edf185d0ea2cb0350a58f4224a0d7ccb bfd/hosts/alphavms.h
+70e1a59995604c3b804469fa27b92d94 bfd/hosts/decstation.h
+7f90b6f7c21bcc67525386bdb9399540 bfd/hosts/delta68.h
+5a75f0a8518cdf994c6837632317650a bfd/hosts/dpx2.h
+6d9ebd0f91f9085690638821e2ce67e0 bfd/hosts/hp300bsd.h
+50735617194ee653f1cf99af40a7dbc9 bfd/hosts/i386bsd.h
+c3d90b1a06731c814d89371f91583bb9 bfd/hosts/i386linux.h
+90fa9751fedd9623f399b8bcd6a646b3 bfd/hosts/i386mach3.h
+09a90ebd4e56bce95e72a93c6274997e bfd/hosts/i386sco.h
+1d13cbc7201d1b35dfd2353027122d33 bfd/hosts/i860mach3.h
+779197139aaf874e61ef9339cdf7df30 bfd/hosts/m68kaux.h
+c40f7966cbdb0fac0b4366c9c61eac06 bfd/hosts/m68klinux.h
+2563c4d1fef8234619b1c2007dfdaf90 bfd/hosts/m88kmach3.h
+8fbd4bfd38ea85aeedac03e1962242dc bfd/hosts/mipsbsd.h
+f61dc4a9a9a665ab9fba6861214bdea3 bfd/hosts/mipsmach3.h
+d4e865701ae3a5149a05ff92b2542e94 bfd/hosts/news-mips.h
+2a46cd81291f56275932a241e022f567 bfd/hosts/news.h
+21af1454d516fbfd996f6d6bc3b8db9b bfd/hosts/pc532mach.h
+2440e7cdd4e85ead6516650e1329bd0f bfd/hosts/riscos.h
+31fe7c1b8aaaf0174c5fe2ef83298ca9 bfd/hosts/symmetry.h
+627775bbea4f1d59b97edfa80e81a259 bfd/hosts/tahoe.h
+1214020ec5befbef1dda50900deb4740 bfd/hosts/vaxbsd.h
+9b476271b3bc5815a37f6b887c092090 bfd/hosts/vaxult.h
+9b476271b3bc5815a37f6b887c092090 bfd/hosts/vaxult2.h
+9783b7a5b508bdb3cbbcfd352723873f bfd/po/BLD-POTFILES.in
+2268acdca71084336f94fc195d4549ea bfd/po/Make-in
+d4344dee14c296d35fe704953ffe9fa1 bfd/po/SRC-POTFILES.in
+4f233961e16da13e8aafc02a5d6a5439 bfd/po/bfd.pot
+3aae148fb9018854c2d708a4ef931674 bfd/po/da.po
+4f5a10257ac1b0141951e913ec332bbd bfd/po/es.po
+20247f61a7fd04810374ba60aef37bbe bfd/po/fr.po
+73b8653e71ee27028caea3884743f7de bfd/po/ja.po
+8fc4e95db5a00f800bc30c65a30f8a8a bfd/po/ro.po
+dfe82e26118652583a47b8f4771e7e1c bfd/po/sv.po
+95bcedd50b1016d3de8c9f543c6b2bb9 bfd/po/tr.po
+759dbab8d78320662dd19d5c9dc5bfa0 bfd/po/zh_CN.po
+35a4480c592584b75a828838b20938a0 bfd/po/da.gmo
+64ce98e2556430a9301dbe0c1c6caba1 bfd/po/es.gmo
+e1d625574ad79a3927294e3689741aa3 bfd/po/fr.gmo
+95a86001b071eb80f4745adba10a289a bfd/po/ja.gmo
+844c1ea598f9bcc47870ecf122b15e7d bfd/po/ro.gmo
+b04862da8728ddf3c4c8a45b18ee35f7 bfd/po/sv.gmo
+495dc4f4a2e82ea81d7226370e07294f bfd/po/tr.gmo
+ee7366f8bf4f4bca0d82e3143893174d bfd/po/zh_CN.gmo
+9866e9425ea31221e3dc5d4410bbf5db config/ChangeLog
+1eaed99306a232c1f2579d48c964f565 config/accross.m4
+6c7b0890dc93bdd97ec3e90d8436b384 config/acinclude.m4
+a1b1540fda3bb91674c5ac1ed659b9c8 config/acx.m4
+ed78e916ef1ee530d9e2f35765cbebd8 config/gettext.m4
+9b65dc7f50a7134932aa278ac0378703 config/mh-armpic
+7b266c44c8a74cfd3aa47c7408b1d9d5 config/mh-cxux
+85f96b330d9ccaefa3b09568acdae202 config/mh-cygwin
+1a368defd90f5893cad171786ee20569 config/mh-decstation
+8b594c219d32fc33f367d70ea30239a1 config/mh-dgux386
+625bacc09b9992290d94831bd7506bd0 config/mh-djgpp
+9b65dc7f50a7134932aa278ac0378703 config/mh-elfalphapic
+9b65dc7f50a7134932aa278ac0378703 config/mh-i370pic
+740855ebe34cb2d01fba1f1bcb4264cf config/mh-ia64pic
+9240a2b84d379e3feff49d8311072dc7 config/mh-interix
+4025142ef79311b861a05eed3e417a4a config/mh-lynxrs6k
+740855ebe34cb2d01fba1f1bcb4264cf config/mh-m68kpic
+d2eccbc26e9ac85d25fad721ba9264aa config/mh-mingw32
+1970cc16887b91d667b9bbfb0f6e67af config/mh-ncr3000
+fb9d7448a6dab87d4da003658fb4d66d config/mh-necv4
+9b65dc7f50a7134932aa278ac0378703 config/mh-papic
+9b65dc7f50a7134932aa278ac0378703 config/mh-ppcpic
+740855ebe34cb2d01fba1f1bcb4264cf config/mh-s390pic
+ecf7a936c35e3c5a0e8d2b0721243b85 config/mh-sco
+e4353fd5127f79d601d85fde3925ac76 config/mh-solaris
+fa84a282ce7cd6876d1eac368a31a368 config/mh-sparcpic
+2415a4da9726792701f226bdb0e5ac3f config/mh-sysv4
+2415a4da9726792701f226bdb0e5ac3f config/mh-sysv5
+740855ebe34cb2d01fba1f1bcb4264cf config/mh-x86pic
+3755b5b077053b5de54ff0f781ca9295 config/mt-alphaieee
+96289d06809692c31d71e69c4bedb6d7 config/mt-d30v
+945f54294ca11fd14c1aaaecde3ce7da config/mt-linux
+2067ce86494ccb89791fe169eee8c198 config/mt-netware
+5aa8f75c6588d513ce199e2e44c206e2 config/mt-ospace
+9c67d61b28da389337cfaba76ac581ee config/mt-v810
+12b3030d3d59526c374c15af4f5944dd config/mt-wince
+b963319bdff419a7b32cb107b047433d config/no-executables.m4
+d3cecf02bb97035177818aefbb0e0833 config/progtest.m4
+b1f75000fa90c6bd41148c49280e5dc6 config-ml.in
+dd4451f9cdfc36cdb86703965f758ec2 config.guess
+d41fc4b87cd95b533ca5abf5b4254969 config.if
+6cdae8120da06ebd9981c7a5a813550b config.sub
+ba0e4f8aa35567f8f24cddaabf3a854d configure
+23d6f11e4cfb005d1003d2d9f5cdcd73 configure.in
+62b488e5f959e052d18496e90786ace0 etc/Makefile.in
+213e80930c0be010bb250612af54775f etc/configure
+e9b828169fe54bf6414ec1f4376af077 etc/configure.in
+82ec227ba1633285a14da92fc105067d etc/standards.texi
+93a1c838358f13ed5e4bf98d07a173a4 etc/make-stds.texi
+ad362ccfa3df560286703d75b5074e3f etc/standards.info
+6614900e6bd390888e699c2cb431fb23 etc/configure.texi
+2586359a28271600453b7485314dfcbc etc/configure.info
+a20b40a0a5d3282f6a97c627be1e38c6 etc/configbuild.ein
+570746cd93c4dae506cf2a6153a2a1b3 etc/configbuild.fig
+f97ac2d5e05edeb335b73f8b6beef581 etc/configbuild.jin
+b2851bb6d77822adc89ffc6d323b5fea etc/configbuild.tin
+e67b330b1ad623f1bd3850483cd4666f etc/configdev.ein
+c1f7c41d3e596256ab5f5f933a66293f etc/configdev.fig
+8e14386548b8da4c5072aa2abea55886 etc/configdev.jin
+32fc10cbdbf679bd0ffc8857cf069b43 etc/configdev.tin
+97ca8794237456a3774a2d7672b74076 etc/fdl.texi
+bb43814657829ae64a1f39d540a262fa etc/texi2pod.pl
+8463bc5509db00792972ec6d4773003d gdb/CONTRIBUTE
+0636e73ff0215e8d672dc4c32c317bb3 gdb/COPYING
+1a6967f096f4e9bf5a6a3fe5961744f1 gdb/ChangeLog
+42b9f7c51223e595f66c2210064be682 gdb/ChangeLog-1990
+8f5a03c189727d347a330548f3ea9c98 gdb/ChangeLog-1991
+51d2fa6ce8618d5c87150c7c576f1f6d gdb/ChangeLog-1992
+f971d36e35ec0c3fce64b819d7891f15 gdb/ChangeLog-1993
+526536cf30b137dcebfaaa604fa55615 gdb/ChangeLog-1994
+e5e589fe4f10abb8957a8c2e4cddb7f8 gdb/ChangeLog-1995
+349b188907736d3ac349e30e509f4e37 gdb/ChangeLog-1996
+90e56dea65beb67443d6c83cbc5fed7f gdb/ChangeLog-1997
+5ec8a13039f178b86804ff04e7cbdf99 gdb/ChangeLog-1998
+5052b57de2fd8b3515777bb814bcd394 gdb/ChangeLog-1999
+da71c479b68a4d95a79d36640b93c9c3 gdb/ChangeLog-2000
+c923fbcaa47240f82d7ef756c59c87ba gdb/ChangeLog-2001
+ac17bd8138ae5a3ecabcc1258cdc28e0 gdb/ChangeLog-2002
+5652294b4864dfc7241196198f4a8ad6 gdb/ChangeLog-2003
+1f68d3272b33b380724fe731f1716f7b gdb/ChangeLog-3.x
+3ee36d9037c272d3b4f8a7c79961d791 gdb/MAINTAINERS
+92d82043d4463360d4c7687cd5ebc83f gdb/Makefile.in
+61e0eb782011ddfe4824bb33160fc618 gdb/NEWS
+79802c38e98a7dd45ce93d9310655fb1 gdb/PROBLEMS
+431713a59d8502901420ff54dc93bdd5 gdb/README
+d3ac054697897095f9382b64cb2ad396 gdb/TODO
+42b66b05e536cb1d1cd2a9b46005a64b gdb/abug-rom.c
+5c083e811564a1e6bad18954c89f60ac gdb/acconfig.h
+b9810659c00821aef3adeea8e0e6b45b gdb/acinclude.m4
+343bbe4bc8a62c781b67bd120c518a7c gdb/aclocal.m4
+8d8cf6b043079aff553c873c64088b86 gdb/ada-exp.y
+0924104c3a07383c9237c9a42b54f37f gdb/ada-lang.c
+abeb4fcd908e052c60f8329227fca1e0 gdb/ada-lang.h
+d18719f7e442c781dead5e18311f71fa gdb/ada-lex.l
+f74f099fc13ece2e1ca0edcde595948b gdb/ada-tasks.c
+779d537bcd45814df5e9b8caff595802 gdb/ada-typeprint.c
+67c35223206a86c590a1a2b1c5f481d7 gdb/ada-valprint.c
+300a07de612e26f163378c5a43ce0c8b gdb/aix-thread.c
+169985b8ca2c692705e792ed2509b2cb gdb/alpha-linux-tdep.c
+6ccb822b40ced578f9a0338774bc7451 gdb/alpha-mdebug-tdep.c
+3314eab39eb296c34337d42467101d57 gdb/alpha-nat.c
+11f936f89f001248ef4ebbaf3083a7ed gdb/alpha-osf1-tdep.c
+0968bfe12c4657bd9b4ceb1aa1431518 gdb/alpha-tdep.c
+e7db74fa2ed0302b0928e29b68274a52 gdb/alpha-tdep.h
+af00914ee90f724a36cd4402c8ba3189 gdb/alphabsd-nat.c
+aad2b19c36fa65173adc7b6e50756fc8 gdb/alphabsd-tdep.c
+911ada28badf929d485cc5e4ba03e8f7 gdb/alphabsd-tdep.h
+8aa4f09d06c4e8138f0eaa340c700652 gdb/alphafbsd-tdep.c
+67cc33cc7ef8d7374a017f24ef7032c6 gdb/alphanbsd-tdep.c
+26b6eb2b6f053aad600a2d211034982d gdb/amd64-linux-nat.c
+d8989251a8151730d86df30792797a4c gdb/amd64-linux-tdep.c
+9a61ca201c22e5c4db359e0892263257 gdb/amd64-linux-tdep.h
+f382150932d298dbc31c0ee4f36a1921 gdb/amd64-nat.c
+d62df996a5b10c3971ca31533ac4b64b gdb/amd64-nat.h
+b79fb3c9f6ddca0352dc285721c99886 gdb/amd64-tdep.c
+96d3b45edbccb5b14dd27b589a85a430 gdb/amd64-tdep.h
+2238f88d8163b0d370ec1d3318120fba gdb/amd64bsd-nat.c
+9988606ccc44723efa802889e862ec0e gdb/amd64fbsd-nat.c
+527ac8ce55c96ed9131f9a27f5ad8bf4 gdb/amd64fbsd-tdep.c
+44610b0d73c81e3e0b17d88f09d4b0a7 gdb/amd64nbsd-nat.c
+942e5a6c76a550fadb39180fd66c45fb gdb/amd64nbsd-tdep.c
+8c7030f92c0feb837e19e2ad0c2166b6 gdb/amd64obsd-nat.c
+85a23a8c5279fa33cc17bd9c9a37190a gdb/amd64obsd-tdep.c
+d947a07a440c6946dfdc872eba2d2b72 gdb/annotate.c
+080a525c2bda6e56dfa98f8aaebc7eb9 gdb/annotate.h
+496fb22cd6c9af90a40c35452bbcf92e gdb/arch-utils.c
+a60210afbe81bac521522d2b767fa04a gdb/arch-utils.h
+d28d2abc6d1c5bba1488e36ab027f708 gdb/arm-linux-nat.c
+9ff54a9d3f32f1899d7f4485620b7f87 gdb/arm-linux-tdep.c
+5552cb3bfaba9c9e042a1caaf5b722a8 gdb/arm-tdep.c
+ffc980e6bff20197fd797db961026843 gdb/arm-tdep.h
+24a8f7f0beb33cc0873360fc6815f7b3 gdb/armnbsd-nat.c
+907da3174dbb366e5a0c547986bac6e7 gdb/armnbsd-tdep.c
+8b99251c0a8f39e7617ab95b4866d03b gdb/auxv.c
+d36b30e423736bb435b84f56db5e7a1b gdb/auxv.h
+18ae66b72bfafc474f3e864127c8d894 gdb/avr-tdep.c
+918dfebcb630956dfcc8a7d7495a371a gdb/ax-gdb.c
+50b7d2540035e5b1329e7f76ec2167c4 gdb/ax-gdb.h
+39ce9c9c59340691bf77fa7c2c72b4da gdb/ax-general.c
+3e6df9c00077763250cb7c4c38b50ad8 gdb/ax.h
+a10ead74084b65b4b0056d5bb80341bc gdb/bcache.c
+51af669999ec737922b29d63a2dff65f gdb/bcache.h
+fcaf8094d30feefbadaad17974e8595d gdb/bfd-target.c
+c8da03b16cfd091e9f0cee9a71f93297 gdb/bfd-target.h
+16cb12116f5ec56c2669ed80144fdc9c gdb/block.c
+21a82a73866c3ee1264cc17bd9aa8a24 gdb/block.h
+05ba3cd3246197775b22bfb2ee352c29 gdb/blockframe.c
+8504522d395f5ee8c98aafcee7726994 gdb/breakpoint.c
+35a278024cda3db7ec8e0b00e6ceb929 gdb/breakpoint.h
+9584e70bf9fb8227eb494dcdcc3f3158 gdb/buildsym.c
+714c8ef6870dde58afac072509200ec2 gdb/buildsym.h
+f08076d72a8857b31489513946dcd38a gdb/c-exp.y
+0471fa9776ad48757851bb7a279a7cd4 gdb/c-lang.c
+b0c37bdef2805d541c08d7528fe4c441 gdb/c-lang.h
+121e47fb1bf53c273c6eef1c62aa40fe gdb/c-typeprint.c
+bffff67b36ca862c51d0ffbef4e99a67 gdb/c-valprint.c
+78da04b3aa3a9010d304051aa808b00d gdb/call-cmds.h
+d75aa86cecf814fe9f6ec4a81afbf72c gdb/charset.c
+7760560f7035893b469ff32a114c8e0a gdb/charset.h
+edfd5b651119cf3cddc2183f9d0b2f73 gdb/cli-out.c
+a9f3eff8bc4baacbbacaa2cd39bad701 gdb/cli-out.h
+ee81ad6502cad17f69623d1b4ed3f8cb gdb/coff-pe-read.c
+2dc71de29a7af3cad46244b3b2d88003 gdb/coff-pe-read.h
+fe442680d8a2a9d5d0432ffa6139314a gdb/coff-solib.c
+64869f1717013ecd514776434c4c02d0 gdb/coff-solib.h
+3984c093c64993293dffa24aba37979e gdb/coffread.c
+e02c5514545c211221634194c5aa9d65 gdb/command.h
+aa8c2b31fbb7d3eb27b04520cf14e558 gdb/complaints.c
+bacdc6e898b4a677ff1123b76df1d6d6 gdb/complaints.h
+f622b3747d483055dd47962451a44414 gdb/completer.c
+90142ed312eb420707d50ccffb2473ac gdb/completer.h
+9e399235f2ad0502627ca24f94cf3af4 gdb/config.in
+69bf2ed0ce9a6b34872478585c219672 gdb/configure
+1bc4fbbae4111ce99ed0e7d3308daae7 gdb/configure.host
+c7c1387d7b3c9f02b663912f9dae763c gdb/configure.in
+b910553983c5c3045b59a1bb754572a8 gdb/configure.tgt
+273edc4b2f644f8bb24cc2b3a34a7df8 gdb/copying.awk
+1b2a827eb0fe30e3019f308f1353997f gdb/copying.c
+d413a951fd3f4870207304b06cbe5703 gdb/core-aout.c
+d29d0ea85c054719b0450da279a1a447 gdb/core-regset.c
+e37f359055bafab66b0312cdf05048b5 gdb/corefile.c
+02c2cafa9a9fce0ea1b1d0ab1a162f8e gdb/corelow.c
+e56628e3066834fb34b59f9a66d7fc36 gdb/cp-abi.c
+afa9a50902898ca67d66435238c7d79f gdb/cp-abi.h
+83b244ff7b89134d81732dd79296a431 gdb/cp-namespace.c
+921cafa61dd4ca25acea0463499e3879 gdb/cp-support.c
+3a30a6b6fdc6df3a0218c2c2bd2be92c gdb/cp-support.h
+94bfdc0a762a300805427b8e3698e7f3 gdb/cp-valprint.c
+85fa3b16a93fdb081021f9588147093d gdb/cpu32bug-rom.c
+6a43fc33ed0a9c64a0c925e0e6a246a8 gdb/cris-tdep.c
+3fe0a3d794193876e00e2abbc2ec0026 gdb/d10v-tdep.c
+92ae08e33851a4045861b7d9bfcaf17e gdb/dbug-rom.c
+bcbb7a24b1e8eacc099458e062c23f64 gdb/dbxread.c
+17727ead88c17f8c77f56bddc0b5a65e gdb/dcache.c
+907d3c67a5640d8d89ac6297256894ed gdb/dcache.h
+57a8a71605ae19ab0dcc2615bf95185b gdb/defs.h
+6a03fb71e88ce73a42b32052dad06839 gdb/delta68-nat.c
+c9402684f3c31e30eec156fcfad53820 gdb/demangle.c
+44e93797a20f3781c685eef37fde7657 gdb/dictionary.c
+c155ec3df44742ccd79316aae3d48697 gdb/dictionary.h
+05c146620d715addfb054b42e60468aa gdb/dink32-rom.c
+a382505cdad0d4a3f5ffbeb8c888c4b7 gdb/disasm.c
+ae50c8ac449fae0943d5464e4c400b10 gdb/disasm.h
+638cc5f08980215141b95ce66e94d0d6 gdb/doublest.c
+6a781094fcd994ee60943758adb07c8b gdb/doublest.h
+b7a1d94256a83e22f8136e91931ea127 gdb/dpx2-nat.c
+347976a1e28c6c46a6631cf54054b9f5 gdb/dsrec.c
+3e82183d1ee94c17cac69852f334ecf8 gdb/dummy-frame.c
+aae5b04b2db47e36211509cda09eb095 gdb/dummy-frame.h
+fe63f2c1e0ace00ef3257758926a8f18 gdb/dve3900-rom.c
+b7d5cfeabb5b76e56d9114d44de8f1ab gdb/dwarf2-frame.c
+95350d57a9d89084356ffae43165cb1a gdb/dwarf2-frame.h
+6d97a1b7597a3d5109a54c6e8d1a23d3 gdb/dwarf2expr.c
+75ebfde2fc4299da200aaec76bab66f6 gdb/dwarf2expr.h
+afbce3c417497992453f009d6a6c0eab gdb/dwarf2loc.c
+85ac8fa77b535fbd2f309f861a5dc163 gdb/dwarf2loc.h
+3acaed8ac44beb0fe1d362ca42d87a6a gdb/dwarf2read.c
+3b3788b7f1a627ea173adbe2eccffffe gdb/dwarfread.c
+db2c46c8c88dc10b52feebc4cf614c47 gdb/elfread.c
+f572575eb8f948101aa5b8ad18536f25 gdb/environ.c
+49fac9ef419185b288a708448101c3c5 gdb/environ.h
+26efb41a66c5cea87a3cf3eb016cd21c gdb/eval.c
+c65ecfdd1c3dbf513a8f8f1a88151a13 gdb/event-loop.c
+bddeb19b9f2738c6412b19e218e26ada gdb/event-loop.h
+2480d54e82c2abbe38cde78c86a51ae3 gdb/event-top.c
+21a0616517901e9dc9ef3b95143f44fd gdb/event-top.h
+1f6b545be0b6822eca215d0b5f1edfc2 gdb/exc_request.defs
+42b0d1c067db44fb387de7719b64e0f1 gdb/exec.c
+f62166575e2c70ed616b8cc701f27061 gdb/exec.h
+dd780e5e580e52376bc6eee9ba089d18 gdb/expprint.c
+24fe7e83215c416f15704f97c3b3e4d0 gdb/expression.h
+d950d512defdfc28c6bf7d070a243b5a gdb/f-exp.y
+f3a3773cde05de5b06b97158272be5e6 gdb/f-lang.c
+114b4d60638829bbea5c8335eb6d4d08 gdb/f-lang.h
+7155843f94f03fa187ed1cd8d4440ae6 gdb/f-typeprint.c
+63ac2450beec2e1b316fb6ddc69bed55 gdb/f-valprint.c
+2482b24563cfc7556a020a44b7ab89c1 gdb/fbsd-proc.c
+d65d48a20de6af0c568f859577c2acd9 gdb/findvar.c
+b686aed81807a8bf4ac318ed9184b728 gdb/fork-child.c
+ac9d1596eab67a46021c0732cec9fda4 gdb/frame-base.c
+3caa2317e7af9f690e0bb68c6beed9ae gdb/frame-base.h
+bb7cf84507c99d2b91b62fea93fe9d07 gdb/frame-unwind.c
+f3a610ae320f9425f477cff2b5bc7044 gdb/frame-unwind.h
+4d578eedbd85454937445665fe6b5474 gdb/frame.c
+771270e6961d4f26fed2d3f8d2f818cc gdb/frame.h
+984455d92c4b8ca102ef881fbb5abfb9 gdb/frv-tdep.c
+0515c04e14b22a47bf808d29d8eccd0d gdb/gcore.c
+9cde0107eed168d77312fa2def688909 gdb/gdb-events.c
+21137e686b6eaa784b595c8b62a01928 gdb/gdb-events.h
+60f9576b88f3b5c8ff867cdad5016615 gdb/gdb-events.sh
+c2f5f21027e618072b482a31389db3e4 gdb/gdb-stabs.h
+cf3fdf014a0f08833a0a6d7ae4c28a5e gdb/gdb.1
+354ff171a08d2f10cca6985ae3da2239 gdb/gdb.c
+9198f7b1807c968098814aa2a3901aee gdb/gdb.gdb
+21fd8c994041d89aa5d0ad5f6709097f gdb/gdb.h
+a13266ccde3d767d10865cdc53dfbb85 gdb/gdb_assert.h
+bbe3560e3f9e0593a2607f2a0e6e9b5a gdb/gdb_curses.h
+1c2833d25129de84f7bc6d3002d6ba3e gdb/gdb_dirent.h
+bd1f7513d1ed0e0a6edf94c2f8ceea31 gdb/gdb_gcore.sh
+874997c5f40dd0b01aea3adda5ab511c gdb/gdb_indent.sh
+060abcf7a16e4987b4a67be040993f77 gdb/gdb_locale.h
+f93e5f98bfebc719a6936c5fc0547e8c gdb/gdb_mbuild.sh
+afd4a770044ff9bfa7c94ce88ec3fd70 gdb/gdb_obstack.h
+4a59bd462fe6287169b72c6dd0698760 gdb/gdb_proc_service.h
+84d0de1de8183237a32e8b0cc1e2243e gdb/gdb_regex.h
+99bc97996397a191cdb39c97a0c0e0d1 gdb/gdb_stat.h
+0ad71a497d1fafa44f09c9b8b5b73180 gdb/gdb_string.h
+aec98c443c614bcf7d145b601446e45f gdb/gdb_thread_db.h
+1ec38b798feed7efea6231951fee1a50 gdb/gdb_vfork.h
+170beb577d78482306f4d3457a8f2d2b gdb/gdb_wait.h
+769abe174e2564863bad3a9717d6b2d0 gdb/gdbarch.c
+11de6e151d7d0e2afeeb9acab1b78fd4 gdb/gdbarch.h
+17563a5995e010a8e30acd1ff32ac0cb gdb/gdbarch.sh
+aad6218245419fa85a80d2ff66610491 gdb/gdbcmd.h
+f889ab1048a9dbcf888f2d0bf7d760ee gdb/gdbcore.h
+fc3a24041b070e4d007c5847e3ce3b69 gdb/gdbinit.in
+03d2757e017543b63e199a7acf020b44 gdb/gdbthread.h
+8c2277d74f1af71937df5bc3dd85af2c gdb/gdbtypes.c
+3ce6f93cba59430b2cbe20f2468bbf4d gdb/gdbtypes.h
+a36a62dde42f59c47ad94c85df72959d gdb/glibc-tdep.c
+d20f09fae4a5df7ebaab2d15479517b6 gdb/glibc-tdep.h
+0a150bce76ed7ff1c62133e2ee7ee4fa gdb/gnu-nat.c
+4cd514c067cb6d8880da54982c095420 gdb/gnu-nat.h
+06549dbf519eb86a578c86336d0b6f91 gdb/gnu-v2-abi.c
+f4e12a18e9f90a71bdcfaa51a3289d5d gdb/gnu-v3-abi.c
+e90212e188e5f2b0a1509fefc2653fef gdb/go32-nat.c
+0fc1faa3a7f5f967c3b89fc9a2d2212e gdb/gregset.h
+54db1957245091eb1a96155d087dcfa6 gdb/h8300-tdep.c
+826b2d1a6bf4c146254cf4531c37659f gdb/hpacc-abi.c
+12e30c5c3db3ae0cc433d148a43d3d39 gdb/hppa-hpux-tdep.c
+df75f02335289974396d319ecada4749 gdb/hppa-tdep.c
+d62e4755fe9dabe0ef0dd0ccba827905 gdb/hppa-tdep.h
+c28ce8bd32b2a2dbee2c63fb5ac62cd0 gdb/hppah-nat.c
+99b837b524cd3a7b45b7ad585f0f1838 gdb/hpread.c
+f501f3dbfc07b203e34a6de331034b09 gdb/hpux-thread.c
+06e140e8d95525e8b8da2d139729a4ac gdb/i386-cygwin-tdep.c
+c80d8f61d9bf860235e84b600907d964 gdb/i386-interix-nat.c
+eeaae0c3595f010dbcc4d76f6fbf23d9 gdb/i386-interix-tdep.c
+d5d90be62057c0a6338751e203e24793 gdb/i386-linux-nat.c
+dc79662e20e9d19e135809e00764f8c5 gdb/i386-linux-tdep.c
+a10884afab61969fd0bb9f650614863d gdb/i386-linux-tdep.h
+b652ea6f206738d14681ce628b36555b gdb/i386-nat.c
+f6b4f006e51e02b379ba3a66ef36faf6 gdb/i386-nto-tdep.c
+678fc40ff8037830756f0992250dbe6b gdb/i386-sol2-tdep.c
+2ae1192deecd340023c63facbc29575f gdb/i386-stub.c
+a16f64889070df1c4c9eb4cfe4f59540 gdb/i386-tdep.c
+fdc1bc51c796d26123a3002539b3bb43 gdb/i386-tdep.h
+d301feaeaeecd5fd86144eb4992cc408 gdb/i386bsd-nat.c
+e5fdfea78b74261dc52e1159619f45c5 gdb/i386bsd-tdep.c
+ef6a4ff12d7339e8f88545199a44a9a8 gdb/i386fbsd-nat.c
+bb4d8fc6b41f67597dc83e51197d62ac gdb/i386fbsd-tdep.c
+1ef9a1c264c6f4d9d2d18faa0830692f gdb/i386gnu-nat.c
+75fcd1cb7bee95046fb866528a48765a gdb/i386gnu-tdep.c
+dd0decb51a6e9467e960ab17fb06ca88 gdb/i386ly-tdep.c
+a03aa0d03135aac616822a40cb6c26bf gdb/i386nbsd-tdep.c
+bb15cc507f5f009b1427b2ce0c931884 gdb/i386obsd-nat.c
+307f7aeabacb280dc061aaede78eef4f gdb/i386obsd-tdep.c
+9ec28d7590a9c374e709d46e464b9434 gdb/i386v-nat.c
+65b54ee8f84e3a9afc00b95a53e2396c gdb/i386v4-nat.c
+c69f606c016afd8bdff0f09557de7216 gdb/i387-tdep.c
+f6c8381c090fd4c289cf09dc0983387e gdb/i387-tdep.h
+f488fd50068bba1f1b91df89a3a99e8b gdb/ia64-aix-nat.c
+6cf1eb85fa9d83629ef934c30ff904d0 gdb/ia64-aix-tdep.c
+072f3e408251636827f2723f2b8e0eec gdb/ia64-linux-nat.c
+a1fbb140749309bf29545ace3b471c1f gdb/ia64-linux-tdep.c
+e19155f0dd708d987c7e6b69b5a399c1 gdb/ia64-tdep.c
+1bf6328448b1313dd8ebab710ba31d16 gdb/ia64-tdep.h
+3de10d3601f67cef85b449e82ad0a443 gdb/inf-loop.c
+96d9de3ee8d6fb1af3195714b833933e gdb/inf-loop.h
+6678f5c400a7022c73f721bc5c0209ff gdb/infcall.c
+28d3925d02b4770c801f2beb106e90b1 gdb/infcall.h
+3fe1c83f4a6a0b3d561861ebfb9cca76 gdb/infcmd.c
+995b9bb47c5596d16bd225cae0029a31 gdb/inferior.h
+99ab08f0f52ec838e35b04731056ee3a gdb/inflow.c
+2ad0d8045158a16f23791288757b6c37 gdb/inflow.h
+2391ecd084c5ecc588cbebacff721544 gdb/infptrace.c
+bbce9f9d3cf52c89bf86a945bc4e9698 gdb/infrun.c
+ed57f2a6a77f1c9eab42e00fed1100b0 gdb/inftarg.c
+2c5c88bc6ce03d1412303d769b2c8245 gdb/infttrace.c
+e75e773b3770b13462872245d00b9dc9 gdb/infttrace.h
+4a40492bb34cbfc2a38d8d1cf0866259 gdb/interps.c
+8a206faf1ea6622b793f4b0400227ad7 gdb/interps.h
+392869faf877bfa089605f270d988257 gdb/irix5-nat.c
+865b109e2412c8f1ae6c9252db3ee355 gdb/jv-exp.y
+2417ce41bb1ffdcad7fc00455d3fc70d gdb/jv-lang.c
+4adf0130b26f3a78f1ee7b24077b4afa gdb/jv-lang.h
+1e66971a543ffa60d5fa1e6d80204b0e gdb/jv-typeprint.c
+cf88df71a2f52be4c217f2824d96aa32 gdb/jv-valprint.c
+a7726a98a2faeb2348eba1c9ef21aa37 gdb/kod-cisco.c
+78ad6bd72f281062072ebd5c6d3ba7d4 gdb/kod.c
+42348651a6ecef51134f250d60355f83 gdb/kod.h
+93522420b27deef6030553c85a6737c7 gdb/language.c
+aac3091c153a374ac87d74b346f93080 gdb/language.h
+41616334b4883b0c7fec4920b1e91f05 gdb/libunwind-frame.c
+d069e6348ffadb62bc0d196fc110310c gdb/libunwind-frame.h
+fe88cc70b185192710fa7e58971699e4 gdb/lin-lwp.c
+c7dbfa86fc447d387ce5483563b54ec7 gdb/linespec.c
+c356ea97db57180abed480346fef1d40 gdb/linespec.h
+5a80346cd00551ad30abe88c8dfd3f56 gdb/linux-nat.c
+a3035094953016d63e94355efc232720 gdb/linux-nat.h
+3383c4bf55250ada0b3cdb8cc26584a4 gdb/linux-proc.c
+2e2349fccd86fd34e59f97a5de48a190 gdb/lynx-nat.c
+14a3cfede2d11ff5fd90722310523b92 gdb/m2-exp.y
+380c2bbce86e0dcf89a4496d2be7bd26 gdb/m2-lang.c
+c14f85068d027cb2ef715a4c40699d40 gdb/m2-lang.h
+ac8ebee0b47fb44330310532c3bdecbc gdb/m2-typeprint.c
+b887d0e70650a9640dbce0eb719c92d2 gdb/m2-valprint.c
+bdc88c73de42e1700edca8119acf3297 gdb/m32r-rom.c
+250bff7fcef5fcafbefdd52602b5f627 gdb/m32r-stub.c
+5c501304f5022c2e9e15e53225d8d635 gdb/m32r-tdep.c
+11d584c8e4cf984dc998fda794575be4 gdb/m68hc11-tdep.c
+192582fc2dac4ee1295f2703b4534e4d gdb/m68k-stub.c
+1303ab976677de3029f5cc810f6fc6b9 gdb/m68k-tdep.c
+74c953235236917b262eda77bddeb565 gdb/m68k-tdep.h
+7479f3854117994d44d55ed2f25b4c99 gdb/m68klinux-nat.c
+a7d30fda1cd80917f19dd204b12c5c26 gdb/m68klinux-tdep.c
+7b106221e514d57c7cc8c934c3a6199e gdb/m68knbsd-nat.c
+911f50b4fbfb86a77b2412d53c71f204 gdb/m68knbsd-tdep.c
+910706b2cb79e83c456c7047c625ca79 gdb/macrocmd.c
+823260ea0987d63072a89dc77f152b9f gdb/macroexp.c
+fb789cac78fdadd513ca2b7fd37f392a gdb/macroexp.h
+d421cb80b3a850b83446897c2d14c592 gdb/macroscope.c
+04bc33d129fd0e9d4c9dd0aa29bb7585 gdb/macroscope.h
+90941f96f5507924a5154c75233fd91f gdb/macrotab.c
+7f5e5cc28b9d115b00b05215909dad67 gdb/macrotab.h
+c5923481fc1422789e94037af862fa19 gdb/main.c
+61bf476ab86f94245f3db2a7963601a0 gdb/main.h
+707ce82520910f2a321b1cacd3ac4495 gdb/maint.c
+fd5d2c5aa8fa47de798cee22d53fb0d4 gdb/mcore-rom.c
+c634aa9040f4f3c88bc173dc5d32c092 gdb/mcore-tdep.c
+eb1296971c86407dbd96b7fe6cf56ae2 gdb/mdebugread.c
+cfafa5d41facd4af0d5fd3378eccc74a gdb/mem-break.c
+0411a61780dee4de28b74a4b0a7d2a84 gdb/memattr.c
+d928e3b5e40aaacbb36ba05218c4fb50 gdb/memattr.h
+566d19c75db1535d81afac237fda7aa7 gdb/minimon.h
+a4fb9904ebfc7d2d5fa8624f792f1756 gdb/minsyms.c
+774b93894f4964d83ab49ee0d481216d gdb/mips-irix-tdep.c
+f1382933780d5b4fa14c5ac5601acdd7 gdb/mips-linux-nat.c
+c4ee4bc5ede672ed8d428a4e76d1597a gdb/mips-linux-tdep.c
+1445cfbf5ee38232d769128a07087610 gdb/mips-nat.c
+3ee9695bf13f5b4c136cd4a83ba2c18c gdb/mips-tdep.c
+f5b5a9124541aa927c514dcff1d5246d gdb/mips-tdep.h
+dbf53f6c90b0c0b5b83addc8c4af66e3 gdb/mipsnbsd-nat.c
+d2c1124267f31aa7232736e04e305f68 gdb/mipsnbsd-tdep.c
+43d8b62f57b2b9326d43479c35167afa gdb/mipsnbsd-tdep.h
+5353ac7561f99790d9bec6547798eb47 gdb/mipsread.c
+9babd5eb3dbd3a36bcb651eb04b97dc6 gdb/mipsv4-nat.c
+f84bbfd52a850297dd08af9a78a8ef7f gdb/mn10300-tdep.c
+0798e2c9cc68b95766d1631644fc0cc2 gdb/monitor.c
+b88df05c557430b204873b8a05d865b1 gdb/monitor.h
+31c83b4bb1c5c9c771fe8e1ec3f1e9ba gdb/msg.defs
+24096aca3294cab3717506c2c69a7272 gdb/msg_reply.defs
+dc35c263a6f38a457db45450afbb9a09 gdb/nbsd-tdep.c
+b8b1bd58b1faa7b9b31888555534a494 gdb/nbsd-tdep.h
+132db48daba54bea91a286e7afa2dc7f gdb/nlmread.c
+21b85dc2ed09d1125c8ab4fbdb043c7a gdb/notify.defs
+26a45351b32b92da49f9e9e2726b5391 gdb/ns32k-tdep.c
+29069f66b7b3ff809855b87fa0f2cb98 gdb/ns32k-tdep.h
+4b7e1e69fe47967430d230570f8ea1ad gdb/ns32knbsd-nat.c
+a2bb70f9271ecb80d98a489067dfa73c gdb/ns32knbsd-tdep.c
+dd57d8a70b7491b3f1d76e42edbd76f0 gdb/nto-procfs.c
+4c01cb3bb5a9df040abe0bc7c2fbbf5a gdb/nto-tdep.c
+bc9f2bce5d3328d93427842534cc9d81 gdb/nto-tdep.h
+93c5ac0c3d4830a121c2b9f3fa0c9afc gdb/objc-exp.y
+e58af207f7a2f104c59bd9ec940754ee gdb/objc-lang.c
+dcd89a207a844435b4cdab0a6968f993 gdb/objc-lang.h
+87540ef1991c4ae015e13916370ba5a4 gdb/objfiles.c
+8d8b7fd0d6fb3e07c730fe30ef73b753 gdb/objfiles.h
+5f63c6dada2382f82b1d26fdc2afd637 gdb/observer.c
+405572b6f0c01f30a5f2c09d3f868c96 gdb/observer.h
+ec912b647a8c58b2bbe4543f5d214649 gdb/ocd.c
+13cf42994dfddc5421bb7e345d7c1b51 gdb/ocd.h
+1ad97893aa4d11a827bec3dd4a5384fe gdb/osabi.c
+5e876a14e11342915e66ebdac71b96c9 gdb/osabi.h
+4c38d42aa946e8823ac26d053b317a36 gdb/p-exp.y
+4fcc79029a6d24fb099615c9ab906790 gdb/p-lang.c
+dd0d8c85c017b8ff00efadf81ba9eb7a gdb/p-lang.h
+49884673264254a967249a5f6c75e858 gdb/p-typeprint.c
+01a4816b69efdc69d68941e9dddc177b gdb/p-valprint.c
+1e2220299e2cbf9162b884676817ea98 gdb/pa64solib.c
+6f31b3a4e988353b1e3025da46cca145 gdb/pa64solib.h
+11cab060bae9f7f8b2a7545160a7ade8 gdb/parse.c
+5e31b257dc15d860728dd3a1bb34153f gdb/parser-defs.h
+da94147104dca1e2a0d6f1f260dd5a92 gdb/ppc-bdm.c
+bf93c68349e5d733d274de5d5ff7d122 gdb/ppc-linux-nat.c
+6bf236db3fa067d020fbdde947456988 gdb/ppc-linux-tdep.c
+1c928f5cfc6602da66d25a0cc5aea648 gdb/ppc-sysv-tdep.c
+5e24b7aa886f2bb2950d1ed0b69ee807 gdb/ppc-tdep.h
+be9fffca93b100a02189878657bf0e88 gdb/ppcbug-rom.c
+082c00c1b5401650c8ea21fbd431cc22 gdb/ppcnbsd-nat.c
+d2dad4af6d4f4a7d62ad4985b2189080 gdb/ppcnbsd-tdep.c
+c10a942d68d9fefa3ad15a800e22f409 gdb/ppcnbsd-tdep.h
+ef6cbac8c46d2bdaaaf8878c0f298ca3 gdb/printcmd.c
+c76afacc2e26c45fe0b376af280ffff4 gdb/proc-api.c
+ddff55f35d2b59960074766ec8d194a9 gdb/proc-events.c
+628246839371a69134e66a53c142d495 gdb/cli/cli-cmds.c
+c8c6f3b4f2ac899a1e5fe3fa3e91a454 gdb/cli/cli-cmds.h
+8dc75a05b96f795af14930c75c988488 gdb/cli/cli-decode.c
+edcfedad9b28724c7ce9782257a23351 gdb/cli/cli-decode.h
+a8f6f4d06c7ceffed082dbeddf8fd95d gdb/cli/cli-dump.c
+e4806fcd758cff138b6ad1effadee038 gdb/cli/cli-dump.h
+2e98b693111e4aa66c39db3883f24e35 gdb/cli/cli-interp.c
+0a815fad0a31e5e03a8c417a374e775d gdb/cli/cli-logging.c
+5da58990491fc2c21d7bb8799d871a7c gdb/cli/cli-script.c
+351eb45c5d48e6b764f3e088c6479d56 gdb/cli/cli-script.h
+b4228836018c2aef413ebb3a13f810ef gdb/cli/cli-setshow.c
+e682e9b77099c61581b706e5fe644c81 gdb/cli/cli-setshow.h
+2d36fe886cbca38d6ff1b960e340ec5c gdb/cli/cli-utils.c
+6a72da1c3d3e1369ac998379dbb03cb1 gdb/cli/cli-utils.h
+8ec1a8b253eb4ff4d2be3336f5db3706 gdb/proc-flags.c
+d2f4507e12dce5ec102631ae6c05dd03 gdb/proc-service.c
+b98c8632ebd98a660263fc0015408372 gdb/proc-utils.h
+c6400943b4afe5c80b3c7b4e7c796221 gdb/proc-why.c
+1de2e2c8bd6fc22a95d8484cbf584e4d gdb/process_reply.defs
+7455e345a20c2d562509f4ec6429bd9b gdb/procfs.c
+d673af0d8d0735bbd8347cae9de94419 gdb/regcache.c
+e235228cd70475bf00a01e2add0949c5 gdb/regcache.h
+aa39d75923e7d5561a2410b0bcaaf4bb gdb/reggroups.c
+b5c13145491c4bcb4cf26e3600740909 gdb/reggroups.h
+5306cbefc65a620ab6c65ab4ff711772 gdb/regset.h
+e9a1198575021d4ee43501c735a87ad2 gdb/remote-e7000.c
+b863f547bcbc6fb53bfb231a072c8b01 gdb/remote-est.c
+487249ec2bc6a3c65e069bc9c5fb6544 gdb/remote-fileio.c
+66be4ab4711a2dc22f0c385ba65c9ea1 gdb/remote-fileio.h
+af0f501486512cf57ba080052792db18 gdb/remote-hms.c
+09820de56d6433c8a463d334d0a52284 gdb/remote-m32r-sdi.c
+a7254bc42efb9846c19d68868a5184fc gdb/remote-mips.c
+64d6262412e17a6c1ddae2ee65a87bb8 gdb/remote-rdi.c
+a18e1018e436b3a303b5df863c56510f gdb/remote-rdp.c
+6090219b2d50d828cb5cf44318597935 gdb/remote-sds.c
+f9091e979a4b5b37ffb8f2191092980b gdb/remote-sim.c
+35b8dbdb476aa1c56cc1981edde07e64 gdb/remote-st.c
+90ff66718c583b664923892d324283b2 gdb/remote-utils.c
+0c7f9f249f0aaa5d67ba621a4f54188e gdb/remote-utils.h
+3893c10505ff5fedcbdaf4a4e912d056 gdb/remote-vx.c
+d2c6758b39b44b2222fe4224b3031ec2 gdb/remote-vx68.c
+6a045b5fd0549057a1cca14554ce2bfe gdb/remote-vxmips.c
+e7940d51fabcf2ab3da5fa135291ebe7 gdb/remote-vxsparc.c
+394d335c712e8e3d3ff863b24de4b50f gdb/remote.c
+d5a9b4414f24cdf526521923d96054f1 gdb/remote.h
+0b4a7d1a4eddc92eec11f3f255a00762 gdb/reply_mig_hack.awk
+cc5e206ff764e2f7cd5f428b2cf560ce gdb/rom68k-rom.c
+0704e12e3fffe12ab16b502731dddcd7 gdb/rs6000-nat.c
+45c69ed441d84bc3a6d8b6f07e8cd16e gdb/rs6000-tdep.c
+10b21b9e9189698191a9f973b3e6e8fb gdb/s390-nat.c
+e7136e078430d3fadb6e3ba846a63913 gdb/s390-tdep.c
+9c44496d10224f6225654132b5664f6b gdb/s390-tdep.h
+2ccbab0b3b9aeaf8a81cd791701d974b gdb/scm-exp.c
+28a02e8e9135d23287da61bdc37142c4 gdb/scm-lang.c
+0e5cdb3cfd372545d7e234e1c5d80b0a gdb/scm-lang.h
+780ab8a36ed44be775dd68f1bda7fd6f gdb/scm-tags.h
+c0ebd6063289f2cccf2e8c4de0228c1f gdb/scm-valprint.c
+262b4c69f293505043d80a20b402909a gdb/sentinel-frame.c
+22b2eb4b470698e93db1b02ceba13a0f gdb/sentinel-frame.h
+2aad56f06c4f31f7fd54356cbd5f746e gdb/ser-e7kpc.c
+97d850e51e2cc6664a7c8329a921f03c gdb/ser-go32.c
+25ba6e488040182afd4f92af49bce66f gdb/ser-pipe.c
+fb37b2c7f24281890bdd228131a2d0dd gdb/ser-tcp.c
+4530ba6820b4a9da95d241e7513372f6 gdb/ser-unix.c
+6e9530daffdd50fd3e511276934a2e79 gdb/ser-unix.h
+47f86e9dab60d839e4ce0936ef139cba gdb/serial.c
+6c059afcef4d1fc90ec5ca6ca33df26b gdb/serial.h
+605bb4f615349c3f37f31b55483ac770 gdb/sh-stub.c
+fded98bd4d8c3d38fc7b228b7a730c56 gdb/sh-tdep.c
+ac5adba2c4355407492f3543167bb0e7 gdb/sh-tdep.h
+04bbe286ddb0c649a7008a9972ceb0ac gdb/sh3-rom.c
+8b9bcbb54152560c5e850d233e103a16 gdb/sh64-tdep.c
+22b0f594ccc8fd9dce1ad951cd0c6b34 gdb/shnbsd-nat.c
+e65c81b386e8e4470c8165a4f4e82801 gdb/shnbsd-tdep.c
+bd05f2f8197d7e9c333fc974fcce2536 gdb/shnbsd-tdep.h
+64b60e671780f77b2c47d36f10424e3f gdb/sim-regno.h
+927dc09d94cabfba09da782aa2b63f70 gdb/sol-thread.c
+487afab377d491bc395fc3d7024463b1 gdb/solib-aix5.c
+3332c92dc9b9d7f0c48975f55873ee28 gdb/solib-irix.c
+7e854a6606ebf32541ba24012343f420 gdb/solib-legacy.c
+bdc5383f891022ae5843e534efbaa5f4 gdb/solib-osf.c
+5ea4db92a92e6568ac6d413d199e91ee gdb/solib-sunos.c
+ae0759fde67f1a9b16041cb6ade5ed4f gdb/solib-svr4.c
+ee3cb624f3a8fbdd08825d5d438568fa gdb/solib-svr4.h
+340521b0f7aea2d934bcca6ce11de3b6 gdb/solib.c
+4f1ea26aca0bf810e04d3d5910897551 gdb/solib.h
+09bcfbedbbc35b128a0bdfc1b0dcd436 gdb/solist.h
+6a40a0a2d9ef3084942de4e3bda6367e gdb/somread.c
+3896d582919d74b02b5500ffff50b08d gdb/somsolib.c
+ee24247c676d85624a01a524dc08ecbb gdb/somsolib.h
+278b0197bdcfb621ec1f94fe35e8e365 gdb/source.c
+9c1ba70f8e1f3f320026aa6ce0993e29 gdb/source.h
+fd7d23865272c3063354dcd85254f936 gdb/sparc-linux-tdep.c
+cdf63a7c1673e8edc9f839b8b9bcc136 gdb/sparc-nat.c
+5b092841f65dd048bbbef11bcbdffe89 gdb/sparc-nat.h
+6232b5532b9b311e2460d5b826ffb484 gdb/sparc-sol2-nat.c
+5fa7b620c0efcaaba98520846130ccea gdb/sparc-sol2-tdep.c
+cb4e0508c08ed0f0a23a7bdf1c673a9e gdb/sparc-stub.c
+05f21ef775dd72ecc9d8ab988565459b gdb/sparc-tdep.c
+6d7c48a8efd42e9c93fd4a0ba2c53c5b gdb/sparc-tdep.h
+da35edc7c976e5979fc9c16c9863a5a1 gdb/sparc64-linux-nat.c
+41947626782d4208e3e97687a46832d5 gdb/sparc64-linux-tdep.c
+a8cf9a3892a3392d51125fe4aee5ea3e gdb/sparc64-nat.c
+409d1405c2037abb568d4d6c4b8736ec gdb/sparc64-sol2-tdep.c
+97757548ee1e63f6371a817999aac4d8 gdb/sparc64-tdep.c
+cda04cbefebdab0002f02f230e3de7c8 gdb/sparc64-tdep.h
+0e5f088019bd0c6f989b0cd35901c588 gdb/sparc64fbsd-nat.c
+7bc4c24da60d6330dd4b0e9c8fa11058 gdb/sparc64fbsd-tdep.c
+562bf6f4e607b1351ddf09e44f89192b gdb/sparc64nbsd-nat.c
+30c7fc268239f09cd7e036e1ac2ca406 gdb/sparc64nbsd-tdep.c
+e8e087b1c1fb9d92bc2425dbdad2acef gdb/sparc64obsd-tdep.c
+6020c37b57486ca9bd2b9721b64baded gdb/sparcnbsd-nat.c
+fabb89710f59311ac29a1a0c3d60e3d4 gdb/sparcnbsd-tdep.c
+1b56b88fdd84479997bb8ccb90824b23 gdb/sparcobsd-tdep.c
+6743adfecb5d0b244089bd81133b7431 gdb/srec.h
+1d0f9beee8d622ec36d178ce19bee00f gdb/stabsread.c
+cd70270ea2c0144f5ef29a0837455671 gdb/stabsread.h
+c6b842c6ca32bcdb45544a15a924d46b gdb/stack.c
+ee70021046bcc1f0deb926d307fba3dc gdb/stack.h
+921d0bc71380043118d6e5bdddfb8ddd gdb/standalone.c
+02d6bcc267ce960f167ec7559621f544 gdb/std-regs.c
+daad9f61b58034d486354eae7307be09 gdb/stop-gdb.c
+dd003de6a4c7416507566381253af497 gdb/sun3-nat.c
+c0ef27bd3b02ae5fe88645ffcaa31f06 gdb/symfile.c
+312d95519b2fa8dd5bae414a507bc2f9 gdb/symfile.h
+5b456266b0f4eb84508166c3b5877496 gdb/symmisc.c
+f6839b30f1414b0a0d156cb9a95f7740 gdb/symtab.c
+743633fd25ed6add79fdd637eb612411 gdb/symtab.h
+f1c951f8d36ce608e3231d3f03e531e5 gdb/target.c
+c8578de19d41baa6aef2ff6487c84f7d gdb/target.h
+1d4841e3a035dd8d3db8afd67684f48a gdb/terminal.h
+0cc20bf51afaa586ec69da18280a7621 gdb/thread-db.c
+e95f48af185799c82bf6b8de09ad75d8 gdb/thread.c
+b63299897ff4d63b0a73706b6a02ba34 gdb/top.c
+e7ad0cd2f8fe038f67d6ade745e4ff23 gdb/top.h
+9bf0d544fed6a3878f84fa9935ffab6e gdb/tracepoint.c
+aa9a293afc99704b0a6ffbf43ef5bf12 gdb/tracepoint.h
+90c27d2b417ae4c5b5486b18736b20ed gdb/trad-frame.c
+17ce436b755a183707ca37ec442a4f33 gdb/trad-frame.h
+ed67464be27a2b6bede1d659edba0cbb gdb/typeprint.c
+43bb17504e9f9b98e2d8e477ce63194e gdb/typeprint.h
+06a137b1adcfa46bbbc526a80b84d163 gdb/ui-file.c
+0ff5068c3ecd7773c3d7228ed65eedff gdb/ui-file.h
+4026070bb24e652fdb2770fb2692fd51 gdb/ui-out.c
+7ba75f886e93ea5e305ab9b70da63177 gdb/ui-out.h
+d95d417b30ab40fefac49eff245b225d gdb/user-regs.c
+70eaad1c970cead8936a8655e239af7a gdb/user-regs.h
+d18eb22ad4f172b7bc4fd123474d527b gdb/utils.c
+a70cc73e2008180a3628b0fb3bfc18fa gdb/uw-thread.c
+8aad69becfe351ab7a0d38a1b844e9f7 gdb/v850-tdep.c
+a4167e4f7918130f0b9439261d61da69 gdb/v850ice.c
+edf9983bd28ae0a49f95675885aa047a gdb/valarith.c
+706ffa082188759848e2e1852ff4c5a0 gdb/valops.c
+d8eef351317cdcb8a996d692a61daa79 gdb/valprint.c
+7d58a37805d3bf14a0578650428751bb gdb/valprint.h
+a5bbd7bc433948c3d9298859e3f06a6a gdb/value.h
+0baa5a2489aca53a5f431d27fd1d0fe0 gdb/values.c
+171330ee095fd7f120cc5dc513f96648 gdb/varobj.c
+d9088ad2a3a7fb5d5761dd7414c43872 gdb/varobj.h
+ebf85474e0d5c5c3ed23fb3dbc5cd9e1 gdb/vax-tdep.c
+427cb114230d6125740b4bed90731fbe gdb/vax-tdep.h
+5c5ded2e342d683a80ee1baef14bb084 gdb/version.h
+401718b61199e799c9879210e445d03d gdb/version.in
+3527601469d3d9a679df93220ace87b0 gdb/win32-nat.c
+1a267d78ee44ed553e1482752a74f676 gdb/wince-stub.c
+92205b0e2c12af1b9061628692856da8 gdb/wince-stub.h
+add34ed008797b0b466c9312219b81d4 gdb/wince.c
+89ad2bf4a89e2a139338f8ea9c7608d1 gdb/wrapper.c
+b8a2216ebdd88ac3e55877e5776cd4c4 gdb/wrapper.h
+471e7c3fff17ccaf36ffd9811d1f6540 gdb/xcoffread.c
+e827605916f87a4d36b337ccf3128ee2 gdb/xcoffsolib.c
+8e4726e461ff59558bc715a42548303e gdb/xcoffsolib.h
+ca1460bc1dd14303a93a3a8e358cd90a gdb/xmodem.c
+525a1aaf9520314cbbc806b2752c55c8 gdb/xmodem.h
+be6bcbe9ce7b8a53886c04579e2a2bbc gdb/xstormy16-tdep.c
+eea89d12926233c778bb18194ad61851 gdb/config/nm-gnu.h
+fcc789529f405e860329add77610f7e3 gdb/config/nm-linux.h
+6557d38d91a421322da9be5883066253 gdb/config/nm-lynx.h
+10a36c3f4009c0343c48fa9c9e221083 gdb/config/nm-nbsd.h
+62a433de8fb11884abb9d901115b2a24 gdb/config/nm-nbsdaout.h
+341eba9a3c5ef7e0cedf64ab079cee9a gdb/config/nm-sysv4.h
+e68e7c1e84ee0bb9cfbdfb5f2fe2f229 gdb/config/tm-linux.h
+1eb5850a19e5f45a7ca7078632960855 gdb/config/tm-lynx.h
+1d146053290f3a39f9b417b8270f685c gdb/config/tm-nto.h
+54e1465797cac5e15d5cd6ed6ad3dc16 gdb/config/tm-sunos.h
+b8126f5423809b310764ca3a4afad5b2 gdb/config/tm-sysv4.h
+3a35d2c92abe256f9a60b5020115754f gdb/config/tm-vxworks.h
+679a32d2142651f89d5306454b2264f9 gdb/config/xm-aix4.h
+db14fba7d3f1dc288c44c69e2e45ad11 gdb/config/xm-nbsd.h
+3b90af63ffa6d35ce6fc1552150e3f4f gdb/config/xm-sysv4.h
+1dd7c70b3aa59ade535903c6ff70659b gdb/config/alpha/alpha-linux.mh
+b1d1a3bcd89d9f1aedc5ea2c10c0f852 gdb/config/alpha/alpha-linux.mt
+0f69c254ad910566266f4c05da7a2f7d gdb/config/alpha/alpha-osf1.mh
+6716d3f8dbf2144370c7c53ee2ba114f gdb/config/alpha/alpha-osf1.mt
+7b40623ad554b6b4bdebafd07cd98a25 gdb/config/alpha/alpha-osf2.mh
+564d3111dbfdbac990a2ddd48919e59d gdb/config/alpha/alpha-osf3.mh
+80b6f424cce3ece0ddac1598ad18d1e1 gdb/config/alpha/alpha.mt
+f44c7cb3525e5641bc636a2944871e6d gdb/config/alpha/fbsd.mh
+1a9de712b0d4e73d4c5e2ac7d9fbe4c0 gdb/config/alpha/fbsd.mt
+99f2372f9fa12271545932d9855bd772 gdb/config/alpha/nbsd.mh
+6dc4aebb4ffaaa3789c36b3c4b766c46 gdb/config/alpha/nbsd.mt
+6f8e9c4d86a0f9ec0bdf35f891a8654f gdb/config/alpha/nm-fbsd.h
+ba68e21924c7482910a4440fdf264322 gdb/config/alpha/nm-linux.h
+06ab2c60b749a50e644b2e7ba992d3f6 gdb/config/alpha/nm-nbsd.h
+851c1cffed2cfaa83d73a281c3bdf30e gdb/config/alpha/nm-osf.h
+1d208e999b97a08db0bce975160c32f1 gdb/config/alpha/nm-osf2.h
+52102103f2d448a89cbf63e199c3f7c1 gdb/config/alpha/nm-osf3.h
+de34c58734eb68a546435b2a4e02170f gdb/config/alpha/tm-alpha.h
+a2eece8be1fd76f49c6cdb66a3bda74f gdb/config/alpha/tm-alphalinux.h
+3fa4256777415af5a2e6d0d2fc293ac1 gdb/config/alpha/tm-fbsd.h
+41c67a9edcb41c4e35ea82dbdb03f785 gdb/config/alpha/tm-nbsd.h
+64e8c7536b0521860ba277d6804ac7ba gdb/config/alpha/xm-alphalinux.h
+129f045275e709bb9b900df448d5810f gdb/config/alpha/xm-alphaosf.h
+b68f286a110d3dae31fe9835b5147d4d gdb/config/arm/embed.mt
+c1c79aa424e3f2bdcbc7c42bfabea61a gdb/config/arm/linux.mh
+9cbd2841cc28f459a275bd4d79a4caa4 gdb/config/arm/linux.mt
+f002892a12441162402e508d169e7ce5 gdb/config/arm/nbsd.mt
+fbb7587bbadd17ba34a228c5db309e2a gdb/config/arm/nbsdaout.mh
+d02a4d65adee7c4c31bfab945765530d gdb/config/arm/nbsdelf.mh
+8bc8a5abb4aa2a467a53bc2a9ffc820f gdb/config/arm/nm-linux.h
+0001241cd3eb272e720af8bed910b83a gdb/config/arm/nm-nbsd.h
+b983efa12efc72a63314fd20ff7b9960 gdb/config/arm/nm-nbsdaout.h
+463d6ad7488b768119e0a031987bd551 gdb/config/arm/tm-arm.h
+16b72f987cde22cfabaee17ee91c35df gdb/config/arm/tm-embed.h
+9166eadf8b0023be758145889af10bc9 gdb/config/arm/tm-linux.h
+234ccf35cf8e3614e6b35fddeaac0423 gdb/config/arm/tm-nbsd.h
+f941ff2e9a95fac9fba6e35af54f70ad gdb/config/arm/tm-wince.h
+f4819d225088a1615e9a5d0848d55b2d gdb/config/arm/wince.mt
+9ba0b88ee457be15892a48d2dbfdb64d gdb/config/arm/xm-linux.h
+cd5c66d79623e661af1a4f82c056931b gdb/config/arm/xm-nbsd.h
+bc093ce94c64afb6bb77b0915543e5cf gdb/config/avr/avr.mt
+f5af76d1ffa289126d8b13f097f568a9 gdb/config/cris/cris.mt
+d1aea4fc41d30c388992384f4b09192b gdb/config/cris/tm-cris.h
+63836a0ee92090969839372e8970e058 gdb/config/d10v/d10v.mt
+765a75b25b6c1c4c93a38a25bfff3793 gdb/config/djgpp/README
+86f542deefe67cd0201ef93406cd7ce0 gdb/config/djgpp/config.sed
+0e81c0d814454405b9e032e50363dd3b gdb/config/djgpp/djcheck.sh
+5178351d05c57ef7d8148346e6983169 gdb/config/djgpp/djconfig.sh
+39021bb1360c16dc2fd500edce3267e5 gdb/config/djgpp/fnchange.lst
+3daacc80013b23a9a6c28302fa5082b2 gdb/config/frv/frv.mt
+e9933ef58367044d74e6a5d5f6cc05cf gdb/config/frv/tm-frv.h
+c950b9ebcb7142942edf3ba6880aa7f4 gdb/config/h8300/h8300.mt
+74694e6ae76e15a3b7ab90dc316b0755 gdb/config/h8300/tm-h8300.h
+24ac3d5adfc9e224e1c03e501e72d949 gdb/config/i386/cygwin.mh
+fa43e7b947b0a3d4d66c7f0d728990dd gdb/config/i386/cygwin.mt
+0e437ea51e599fce67d064d0bf681cca gdb/config/i386/embed.mt
+cb5c1d2bd308c9911a90c4a16de2d2cc gdb/config/i386/fbsd.mh
+238f8c68fa6e69db3da764ba2cdad76f gdb/config/i386/fbsd.mt
+19ba68eee29a2ad6ce44e7a64d2290ba gdb/config/i386/fbsd64.mh
+4b6ce12a571ad7128a9acc4a3f9a828d gdb/config/i386/fbsd64.mt
+12eaf2ad73834ecc9860a0e9cdf68906 gdb/config/i386/go32.mh
+0ace5df771303cdf5bf9d618a7137663 gdb/config/i386/go32.mt
+5d559a38db40fb10d3049f6598ccb68c gdb/config/i386/i386aout.mt
+f44e277d1dba65000f2974939e7c73a6 gdb/config/i386/i386gnu.mh
+95990f32fb0da4d988ce9e5d698c4e7d gdb/config/i386/i386gnu.mt
+fdc2ef618c4c254d9c43391f8d6bac51 gdb/config/i386/i386lynx.mh
+714beb14b44265fa5439faaa1ffa44be gdb/config/i386/i386lynx.mt
+9fe88d3bf7ca56123c87cffc2a79b7fb gdb/config/i386/i386nw.mt
+1d90a49b33552cbc9ecf8f02d24cc9aa gdb/config/i386/i386sco.mh
+be88bd41568cdf03e657a78a90cad6a2 gdb/config/i386/i386sco4.mh
+08bbcede7bf9c79a3fea0c22166b4eee gdb/config/i386/i386sco5.mh
+636b3be223df6069949df96798af40cd gdb/config/i386/i386sol2.mh
+ddf92ff3ece944d0aa602e3e34dd4cfe gdb/config/i386/i386sol2.mt
+882e46bf6218ee0a881663ae01341982 gdb/config/i386/i386v.mh
+4cc1e882b70a935afbf65a0d04defb58 gdb/config/i386/i386v.mt
+ae5fb6952ddd2a9a69a833405a2cf6a9 gdb/config/i386/i386v4.mh
+cfdd395736c65c7330b420fb74b891de gdb/config/i386/i386v42mp.mh
+13149e07640d87cdb88ca71238fb161d gdb/config/i386/interix.mh
+70abed3d38d1d01abc1b9fd6a968ea1e gdb/config/i386/interix.mt
+7488da16bf9c4e1815b5ca9c599709c6 gdb/config/i386/linux.mh
+b0e1ae3878504e213a4d7cd3544aa9a0 gdb/config/i386/linux.mt
+eb2348dc721f0d22a0d5aee54d09eb3f gdb/config/i386/linux64.mh
+0142176dc07e508a95fab4287d68a1c4 gdb/config/i386/linux64.mt
+1be1185f6b8ed8c41959bb14b08b6994 gdb/config/i386/nbsd.mt
+aa4be232902945dd0ce645e262e008f1 gdb/config/i386/nbsd64.mh
+5f7313b419d321c7ea278271371d22e9 gdb/config/i386/nbsd64.mt
+c1233e56a57afb7b8b23c3adf1d41020 gdb/config/i386/nbsdaout.mh
+e7168245a93bc542777524a58fcff82f gdb/config/i386/nbsdelf.mh
+09fb6c4d88d0f7c3774dff9bc785cfb0 gdb/config/i386/ncr3000.mh
+72be0094aa241133e0fa2761be42e2f1 gdb/config/i386/ncr3000.mt
+9025cf2e7f81d8d67741f4fa7dcd58e9 gdb/config/i386/nm-cygwin.h
+956c5878668a50ef0a241085d211bc96 gdb/config/i386/nm-fbsd.h
+cf7846d89966e4bd70d0eab41ec12844 gdb/config/i386/nm-fbsd64.h
+572ba0754bdb619af5344948d355c778 gdb/config/i386/nm-go32.h
+b528dce2b9b5779091cac6843f1fc14d gdb/config/i386/nm-i386.h
+97a8636eeca3049c5cb1d086d1190c21 gdb/config/i386/nm-i386gnu.h
+eb0a2f645c42fe73c6eff14979d52de6 gdb/config/i386/nm-i386lynx.h
+9f76883d7b0156740957ef92565db9b7 gdb/config/i386/nm-i386sco.h
+759255175d60e8fe29597691f147f09c gdb/config/i386/nm-i386sco4.h
+28eb65ba384a288b716a68621d3cb8c2 gdb/config/i386/nm-i386sco5.h
+9a76327ae2e7f8bc51a0fa8c8d8f8171 gdb/config/i386/nm-i386sol2.h
+8d8f66f817e584bf4f8939d1702d423b gdb/config/i386/nm-i386v.h
+dddc55dc8d91151b3d35113d58471e75 gdb/config/i386/nm-i386v4.h
+709f612696ee326f1d21162233f9420d gdb/config/i386/nm-i386v42mp.h
+1a5ffd5040038ba1f2b23c1c655d4abc gdb/config/i386/nm-interix.h
+9abb531ba4b73c917268959c00d8ab2e gdb/config/i386/nm-linux.h
+5c9cc1332c47627dda7a4fb5e1309041 gdb/config/i386/nm-linux64.h
+be8697001b6eacb19c14a2d1d87ab291 gdb/config/i386/nm-nbsd.h
+72ffe8d96dc07f47b32643ea51722e7c gdb/config/i386/nm-nbsdaout.h
+ce0aeb4815e6dc09f6ae943cd2de547a gdb/config/i386/nm-nto.h
+de21266e849ae26d2b790c4b502c8880 gdb/config/i386/nm-obsd.h
+b8b927eaff97eba8b98e581988024a62 gdb/config/i386/nto.mh
+cbcc159ad2bc0e00430d62d43c55de90 gdb/config/i386/nto.mt
+a370afe5ce52a5c30a2ecc78ac758eb0 gdb/config/i386/obsd.mh
+5533a8df6200b0ad63928f7f07e19fbc gdb/config/i386/obsd.mt
+a74b09d6f22cdd4eb15ce12e1fc63f30 gdb/config/i386/obsd64.mh
+a9d2ef1c7493b0911acd6bd024408020 gdb/config/i386/obsd64.mt
+23e9a40999f97ad01a3dd4c67a682345 gdb/config/i386/obsdaout.mh
+4e26af8c9b8337f467da9ddbc0642c75 gdb/config/i386/tm-cygwin.h
+a9b5c029da51cbd0c1418ed84a100d84 gdb/config/i386/tm-fbsd.h
+7aedd62a1ed8a2cce6290476df836155 gdb/config/i386/tm-go32.h
+3047bfada1a357df8b052357df6586b0 gdb/config/i386/tm-i386.h
+beb84e8e343e3a5c4e18f0e90a14098b gdb/config/i386/tm-i386lynx.h
+6f224bcccb0b46fa3b17d91d42b8db39 gdb/config/i386/tm-i386sol2.h
+76b01a728d376a572f4ac70aaa973328 gdb/config/i386/tm-linux.h
+17caab706ae100df959f22e22e398ad0 gdb/config/i386/tm-linux64.h
+76dd1eeea5a9e540d98ee533c94d5642 gdb/config/i386/tm-nbsd.h
+7a97bde1be4491fef49596d30ad8d2dd gdb/config/i386/tm-nto.h
+b40033e9f233947900ab7bc46b91b5a0 gdb/config/i386/tm-vxworks.h
+a4cd737f1731ba01023b05012364fe7c gdb/config/i386/vxworks.mt
+fed05ece90644771eeb13fb989fa1eca gdb/config/i386/xm-cygwin.h
+4b74de65f19059ebb929cc0cf2f7bcaa gdb/config/i386/xm-go32.h
+195e8b0fca2b6c86a86a40c8c60715fc gdb/config/i386/xm-i386.h
+146d93d6cc2e0df783b025644f34ad6b gdb/config/i386/xm-i386sco.h
+8a06341cfb7265f37123768306a12259 gdb/config/i386/xm-i386v.h
+263b8714278f397974d79ca97c69d282 gdb/config/i386/xm-i386v4.h
+7b2f297747c69555205a355dc474915e gdb/config/i386/xm-nbsd.h
+2b3143cf706d48f938900d65a9c4dc84 gdb/config/ia64/aix.mh
+7b9c81f6e8b8f4df5fe019bffc9ec984 gdb/config/ia64/aix.mt
+1f5c672e3a2c1726a722b1b65028bfbc gdb/config/ia64/ia64.mt
+b9788df4cfab91c3f94320735d667161 gdb/config/ia64/linux.mh
+0e60bade33357bab04a939776b3a0874 gdb/config/ia64/linux.mt
+77c090800dc7f47e89e5b44dbff8236c gdb/config/ia64/nm-aix.h
+aee48cf078aa797f966fbd9badb90759 gdb/config/ia64/nm-linux.h
+1876be383903c32c81ff708c0c72ed8a gdb/config/ia64/tm-aix.h
+908029f469a619dbb30b799f95eba4c7 gdb/config/ia64/tm-ia64.h
+50ecf1d32cb31450cf02f9c470d62a34 gdb/config/ia64/tm-linux.h
+612a8247971578c099c8c0e198394486 gdb/config/ia64/xm-aix.h
+3e4e58a4b81d30002721a37e50a416e8 gdb/config/ia64/xm-linux.h
+678c5f8cbe8c2f93f08a136fd0ddd7e9 gdb/config/m32r/m32r.mt
+96353f9ece42e435b490b5cb98669e0a gdb/config/m68hc11/m68hc11.mt
+72f9696980c7cd894d2a899c0acb21cf gdb/config/m68k/3b1.mh
+40532c0fe8f523d595a82690864c31e6 gdb/config/m68k/3b1.mt
+4526194c2be2b2bd87b9b59c1f8f08be gdb/config/m68k/cisco.mt
+f69a26f027ef6fcd8ef914be92c8d02f gdb/config/m68k/delta68.mh
+57f0f706905ccf7eab0c02ddfd260758 gdb/config/m68k/delta68.mt
+1f7ccc2c7369a176445cbc588cc7cabe gdb/config/m68k/dpx2.mh
+ed01cd707d3000643e7a915242f44e9e gdb/config/m68k/dpx2.mt
+8e0e841b049ec704df629621dffe8d14 gdb/config/m68k/linux.mh
+a27516472896d107c389a1515f1720de gdb/config/m68k/linux.mt
+150a251eae11e32b195fbc175b64936b gdb/config/m68k/m68klynx.mh
+1f26708d50172751551f36affbb13507 gdb/config/m68k/m68klynx.mt
+d773bd450b3da20ae5c7bcbe81865e37 gdb/config/m68k/m68kv4.mh
+8afe3be53cfb1b04e7efd3c954fe2e44 gdb/config/m68k/m68kv4.mt
+03fc208af45cb5161914274fe9447ee7 gdb/config/m68k/monitor.mt
+41e49d9f0462e875b3ad2396541c6565 gdb/config/m68k/nbsdaout.mh
+beec0846290691fb5e9b0c6a192ce20a gdb/config/m68k/nbsdaout.mt
+11a25df41c5cd868de7f110dce49be98 gdb/config/m68k/nm-delta68.h
+a30a3423fd949f2d680dc647282a7fea gdb/config/m68k/nm-dpx2.h
+5152232d6693147ec13e842c36020831 gdb/config/m68k/nm-linux.h
+ac9fcbef3e6be8b052e6a2208613df47 gdb/config/m68k/nm-m68klynx.h
+8fbcb211283c186f50b719182fa72957 gdb/config/m68k/nm-nbsd.h
+6728f61e40a0f443e8e28d3823018ef3 gdb/config/m68k/nm-nbsdaout.h
+49b9707bfd6babf6bcbab7b255928035 gdb/config/m68k/nm-sun2.h
+487ded8c623ba0e188dd7007f81e9dcb gdb/config/m68k/nm-sun3.h
+de54a558ef51e7b262b7629d85b33010 gdb/config/m68k/nm-sysv4.h
+4fe0f38c11786f90906c1edb3e3178ea gdb/config/m68k/os68k.mt
+7e1cc3b54949240e629f214781feaf8c gdb/config/m68k/st2000.mt
+cf18e6b138cf9494678c275cba992edc gdb/config/m68k/sun2os3.mh
+9bf05eb5a714e743e9ed4f08365750ae gdb/config/m68k/sun2os3.mt
+214c10b16dee554aaf6c6b33b1d4cc58 gdb/config/m68k/sun2os4.mh
+e3efaa99d908d869c22e1eaaade6272b gdb/config/m68k/sun2os4.mt
+458da4f888829b318f236f73c9e95957 gdb/config/m68k/sun3os3.mh
+10dae17670b7e968e01c6e05c3f2136e gdb/config/m68k/sun3os3.mt
+2a5f43a0be2606c7f81264d0ef83115a gdb/config/m68k/sun3os4.mh
+b4f53cafa5868d6ed3e5c61665423d5d gdb/config/m68k/sun3os4.mt
+45945c00e6727c19b49da3c60e891dcd gdb/config/m68k/tm-3b1.h
+3420c7098e19c39f76116240714475c4 gdb/config/m68k/tm-cisco.h
+720fff75553cbb65a50e82b78812aa02 gdb/config/m68k/tm-delta68.h
+df8a5ae6e1bf101457c9022537712845 gdb/config/m68k/tm-dpx2.h
+1dc0fb0f2b18b3b0045c04b0e48d31df gdb/config/m68k/tm-linux.h
+02a1c9a29dfca95ba018922268e7cdc0 gdb/config/m68k/tm-m68k.h
+e30efcc48d539ea15e63cad700412c12 gdb/config/m68k/tm-m68klynx.h
+f75cfd835151e324053931054680c772 gdb/config/m68k/tm-m68kv4.h
+1bb79455d3762ade4a185a3aaffc0eeb gdb/config/m68k/tm-monitor.h
+ee969651479e3c67ec4cfea3c370b56c gdb/config/m68k/tm-nbsd.h
+3290f7a90c158afe710a61e0a922b36c gdb/config/m68k/tm-os68k.h
+d18374be0d9f663433b0fc03bb5b2848 gdb/config/m68k/tm-st2000.h
+c530307945e0f83a6b9db4aff29b4d4d gdb/config/m68k/tm-sun2.h
+0145e30c6cbb41a7c484db8875396115 gdb/config/m68k/tm-sun2os4.h
+125d8da91b8c62a17fabe3bb8e7d30c6 gdb/config/m68k/tm-sun3.h
+447c31715bf9731f5bd3b358a7a2a670 gdb/config/m68k/tm-sun3os4.h
+cf045a209110bcd3f411391404ec24aa gdb/config/m68k/tm-vx68.h
+f7f39b06912d7d776f3f4e914da9a94a gdb/config/m68k/vxworks68.mt
+3c6734f25427255f8fc6d7a9e5b09af3 gdb/config/m68k/xm-3b1.h
+68ba35dcb8c246507681b9c1e859652e gdb/config/m68k/xm-delta68.h
+286fee3d35cb6633574eac149e9b46f0 gdb/config/m68k/xm-dpx2.h
+6fc3a957ce7cf729b6539f9cc2247584 gdb/config/m68k/xm-linux.h
+c18a612e40b7779e223467d9df14ee21 gdb/config/m68k/xm-m68k.h
+bd091b9c02266b9f499c27cd1d2c0736 gdb/config/m68k/xm-m68kv4.h
+05838b49e57780ad87ad2883d556e156 gdb/config/m68k/xm-nbsd.h
+409e32dfd90bfd6f534ac93fb3d12b82 gdb/config/m68k/xm-sun2.h
+b77d77b4fd3bf74b21583d6c2228c0d5 gdb/config/m68k/xm-sun3.h
+84d66171ac52cb7a273b03db37938205 gdb/config/m68k/xm-sun3os4.h
+71aa532725f69af3b80f41c464be5290 gdb/config/mcore/mcore.mt
+f8b68218e0f0d503b82da72fd6946654 gdb/config/mips/decstation.mh
+1b6971a669fe8e0549febb7b3d307f90 gdb/config/mips/embed.mt
+842922f76cb21c5d68171ee96cb93253 gdb/config/mips/irix5.mh
+3143ad9c618670f3b66c12d870aa3f92 gdb/config/mips/irix5.mt
+e2dc585a9a283ddef1aa7568f09c56d1 gdb/config/mips/irix6.mh
+e61f438e2fac9b9e28ef5aaa88870b93 gdb/config/mips/irix6.mt
+0d16a6e300459249adc7e6bfea5d4f6a gdb/config/mips/linux.mh
+6a28ced965a4da4e04703ce82fe3c17a gdb/config/mips/linux.mt
+7421221d6daa27dc14e3b09f7b371765 gdb/config/mips/littlemips.mh
+cf472622748e7514e862404df1fcea4b gdb/config/mips/mipsv4.mh
+f27fe24905bb8b2f22a2963eb5ca93df gdb/config/mips/mipsv4.mt
+f5ed02ea94274da5bb61e10b1b7e3c65 gdb/config/mips/nbsd.mh
+0d4e0205fbe4ba67f27864f3ab44b482 gdb/config/mips/nbsd.mt
+f82f86577a2f8c6756d0b8060c38823c gdb/config/mips/news-mips.mh
+c9085045097978a3c8b03e47cab335e5 gdb/config/mips/nm-irix5.h
+6f0115121662686647e35dffb0058686 gdb/config/mips/nm-linux.h
+97b35fa0917e824dd0ab7da3fda21c6d gdb/config/mips/nm-mips.h
+6026e58d3e70692fe83bb32d32f359c6 gdb/config/mips/nm-nbsd.h
+63b7d25f25906c6bec48c8b09cac67b4 gdb/config/mips/nm-news-mips.h
+1595b8611c7837a26e36267412aafe26 gdb/config/mips/nm-riscos.h
+efa4509c30851bd24fd956af7f4df03f gdb/config/mips/riscos.mh
+8e0a0ab66ddcd4ae774b525b66350e4c gdb/config/mips/tm-irix5.h
+8b76f43d724ba2ff497e5be9d8613b4b gdb/config/mips/tm-irix6.h
+3e0030df1ad2bd521485cad49f8b0a9a gdb/config/mips/tm-linux.h
+b84ca5e934807e023830108cf3c030ce gdb/config/mips/tm-mips.h
+6b6ef3ec72245ffbbfed6cb6972ee913 gdb/config/mips/tm-mipsv4.h
+07fbcbae65ca33ca30aa889fef9c7280 gdb/config/mips/tm-nbsd.h
+d974c862b0aae440e8cde554f89a6d82 gdb/config/mips/tm-vxmips.h
+edcae62c487b8905850e380e543a3fce gdb/config/mips/tm-wince.h
+3cfc3247359e918baebea77620aee126 gdb/config/mips/vxmips.mt
+3d16c23c19b724d4379d519fb842e300 gdb/config/mips/wince.mt
+1f87dd5333e7917c12465f211aa78fbe gdb/config/mips/xm-irix5.h
+3bce32daad8d9cb7b1b811d8325f86ba gdb/config/mips/xm-mips.h
+e3678325d7d5f56d2dc61d7e81ba65e3 gdb/config/mips/xm-mipsv4.h
+6219c25655021bf26f40ae94dc84a315 gdb/config/mips/xm-riscos.h
+96552f44614c69dbc1b02017927dee93 gdb/config/mn10300/mn10300.mt
+7151ebfc548ee5c9024cca42ce725314 gdb/config/ns32k/nbsdaout.mh
+1e8f917ebe66f6f1228564edf2d39ea0 gdb/config/ns32k/nbsdaout.mt
+18c121ccec89069b3660eeaf015f9a80 gdb/config/ns32k/nm-nbsd.h
+93112703e43194ec3a5ea06e281b125c gdb/config/ns32k/nm-nbsdaout.h
+2d21bfb5946b7a6bcba6d32013cca766 gdb/config/ns32k/tm-ns32k.h
+bbdc023335f173dd1d6badcdb3536015 gdb/config/ns32k/xm-nbsd.h
+bdf1e1e135b038e3dc97971469f691eb gdb/config/pa/hppa.mt
+b3ea8b6e63e406a01edbf74fffcbd51d gdb/config/pa/hppa64.mt
+b88ff9689a0e6752a8f82e253690fdc5 gdb/config/pa/hppahpux.mh
+bf941a62928e5738c01f9dcc26a476a0 gdb/config/pa/hppahpux.mt
+183a9b16fb387937650c7a7c1f5a0626 gdb/config/pa/hpux1020.mh
+849c7ff5d1b215e5239dead2360db060 gdb/config/pa/hpux11.mh
+81df270fda8075594a3cb945667fc707 gdb/config/pa/hpux11w.mh
+204a998c1b37e5c15fa49fa8bbfb1003 gdb/config/pa/nm-hppah.h
+2c39dba06539c43d093dca3d316e0da2 gdb/config/pa/nm-hppah11.h
+9df66a39943d97846c2864c52c6a6800 gdb/config/pa/tm-hppa.h
+3b35c1e5236cdff73fddfa452a1cd821 gdb/config/pa/tm-hppa64.h
+f6504cfbb4f40733efda1cb97e5fa89d gdb/config/pa/tm-hppah.h
+a08da4715dc7e935dbd54153c60f1484 gdb/config/pa/xm-hppah.h
+bd15533c36b749cec68ae84d3583bb63 gdb/config/powerpc/aix.mh
+031169bc9b7bea0b2be5a85bd34b9181 gdb/config/powerpc/aix.mt
+d5a4d6941fa3ef8240bbb9235dda0491 gdb/config/powerpc/aix432.mh
+23e0d267895411879dfab40c9857296a gdb/config/powerpc/linux.mh
+2f50519baba5ee996a59d4bfa044f094 gdb/config/powerpc/linux.mt
+ffbf544ae166a905192060ad86c524ec gdb/config/powerpc/nbsd.mh
+2e925622afcda0e7dc776ac9fa05c55f gdb/config/powerpc/nbsd.mt
+375265e55487151128698bdc6b2eae34 gdb/config/powerpc/nm-aix.h
+4f51aba02ba960b90db6d3bd5f4650cd gdb/config/powerpc/nm-linux.h
+67981886848d4de5a1d8b137979ea414 gdb/config/powerpc/nm-nbsd.h
+8870e48577208a5fbf06872a8ed47da2 gdb/config/powerpc/nm-ppc64-linux.h
+29f5edb803138c0c270ddaa0a3eb80d1 gdb/config/powerpc/ppc-eabi.mt
+02e78a5ad96f597e427eab14b53d18cd gdb/config/powerpc/ppc-sim.mt
+8236a1a67ec222b444131de3a8db2364 gdb/config/powerpc/ppc64-linux.mh
+6a78567036ea92bd8fffb24de3e4054d gdb/config/powerpc/tm-linux.h
+9cc7bb7e239286577bd3c5d6a08ab4cb gdb/config/powerpc/tm-nbsd.h
+af516f198e0ecb8c5f5875586c4be19c gdb/config/powerpc/tm-ppc-aix.h
+1ef37cf5d676f0a41050c9f6f3bd5610 gdb/config/powerpc/tm-ppc-eabi.h
+92a3f29b9c88a4353295351b9b61cb00 gdb/config/powerpc/tm-ppcle-eabi.h
+c35fb4f5df5c4139168bfe23ecc0b9d4 gdb/config/powerpc/tm-ppcle-sim.h
+a68e950f5078b67c9c222fdbf8045f5b gdb/config/powerpc/tm-vxworks.h
+b11247977f2f0f6112f426733889096d gdb/config/powerpc/vxworks.mt
+a8f6aa2f32f4d6179ec90f7fe3025db5 gdb/config/powerpc/xm-aix.h
+6bd1f25074b27a551534ae44f1412b02 gdb/config/powerpc/xm-linux.h
+3dce094cb2c938bb30a33483b8ad27a3 gdb/config/rs6000/aix4.mh
+2352f79f2f09cb4fa42d1dcd2aaead6b gdb/config/rs6000/aix4.mt
+a3485342495d8666c0f1f819d208ef6d gdb/config/rs6000/nm-rs6000.h
+f10402d5958d8319c706aec5391d7ecd gdb/config/rs6000/nm-rs6000ly.h
+9ab7aee89e8e2bb6121efbc5d64168b5 gdb/config/rs6000/rs6000.mh
+8f4d92a7eae6d315c8a2b0a5849d5df8 gdb/config/rs6000/rs6000.mt
+a0b406ad151661f9e7038df6a1eb66ca gdb/config/rs6000/rs6000lynx.mh
+e28f9b98281d6bd426f99f6a13c7fa2c gdb/config/rs6000/rs6000lynx.mt
+0df3aa94054e7409c6dbcba6503051b8 gdb/config/rs6000/tm-rs6000-aix4.h
+e01c9a58ebc977c2bd466bc0835826f7 gdb/config/rs6000/tm-rs6000.h
+dfdf2da79fcc37c773984728dcc3b0cf gdb/config/rs6000/tm-rs6000ly.h
+d428f3c7d971b58a37b2c35995af7fae gdb/config/rs6000/xm-aix4.h
+47f155abe2afabec9b7b6dcde872d269 gdb/config/rs6000/xm-rs6000.h
+97b594b7942dfb1edec7a631f0e72473 gdb/config/s390/nm-linux.h
+12ef4e7aa6d310d36b260ccd3d058a6f gdb/config/s390/s390.mh
+92571fb6f6e5d2e2a67a047770db4ede gdb/config/s390/s390.mt
+7de163c76a82cfe89e03fe9a160f5ca2 gdb/config/s390/tm-linux.h
+7efc40cd229de32d6657cee07cadd963 gdb/config/sh/embed.mt
+5bc230851739a3506e0246b84b219721 gdb/config/sh/linux.mt
+07a71b12f6186f3de88f18d7cf33d969 gdb/config/sh/nbsd.mh
+fd34f84ba64c99d7ee64d884abcb759c gdb/config/sh/nbsd.mt
+669db4870078c12b2ad2d3d57d8bdd9e gdb/config/sh/nm-nbsd.h
+ac21dd8d358c4f0126f1d7a9c3c1d8e5 gdb/config/sh/tm-linux.h
+6c7ce4d0dc64774369fda86bca23b124 gdb/config/sh/tm-nbsd.h
+af93ba3cce05bb99f5a4cefbce0ee488 gdb/config/sh/tm-sh.h
+9653759501da51f6a900738a7f4079df gdb/config/sh/tm-wince.h
+0cccf0bc91ac31c64feca92b2dfcdbfc gdb/config/sh/wince.mt
+f09fa41be0793d611acf58bace9a3d2d gdb/config/sparc/fbsd.mh
+e925dcd66379efca9c93fb5d2395e6cf gdb/config/sparc/fbsd.mt
+78a61badbdf1d99b799a62dd3b9f9984 gdb/config/sparc/linux.mh
+a323cdaa9de5ec0865ac12e0ab9eaab4 gdb/config/sparc/linux.mt
+16d4eb0dbd20b9504812113f1f8906c5 gdb/config/sparc/linux64.mh
+635b60604bd0d4e728c1c559ae017ad0 gdb/config/sparc/linux64.mt
+3cc5fac4e1f7ff5e2cea227e9e060fbf gdb/config/sparc/nbsd.mt
+939be582ad6c77b766ada019587640d4 gdb/config/sparc/nbsd64.mh
+509891eb35cde77d2d8e3d77a4af554e gdb/config/sparc/nbsd64.mt
+00e75d4bcf5c5427ffe88fc3a0c52d48 gdb/config/sparc/nbsdaout.mh
+98710ed82086e740b9857f5e07d41d45 gdb/config/sparc/nbsdelf.mh
+1445fbb72ead6c6e70a62538ea185ecd gdb/config/sparc/nm-fbsd.h
+450a1c44af1d2ab5ae18c1db6da1199e gdb/config/sparc/nm-linux.h
+11f9feeadfe4e9bd25e79b150f9e3021 gdb/config/sparc/nm-nbsd.h
+c939fda939545e22aeedb8d86ef61a68 gdb/config/sparc/nm-nbsdaout.h
+4962783cb7388ac87de703103e1ffa81 gdb/config/sparc/nm-sol2.h
+bbd2dc492142df5324326c9a9a9ffa60 gdb/config/sparc/obsd.mt
+e298512af5089652484fb7900853b1e9 gdb/config/sparc/obsd64.mt
+cfbcbd4f95df88c6c880ae5a8661026b gdb/config/sparc/sol2-64.mt
+b0b94f2b012713a411a9adcb895d82f3 gdb/config/sparc/sol2.mh
+763a1ea818b1089b3e761600cce4de69 gdb/config/sparc/sol2.mt
+e5dcdec0242fe5d99f8d7894001e4857 gdb/config/sparc/sparc.mt
+fcab4101a1d511bbafd504bd25528610 gdb/config/sparc/sparc64.mt
+a10c94f7ed782adec375144890afd33c gdb/config/sparc/tm-fbsd.h
+7d520b5a3ce9829b31384cd85d1c8f3a gdb/config/sparc/tm-linux.h
+579f627f455a558c11ec67c96e4a3a18 gdb/config/sparc/tm-nbsd.h
+21028109907f896ad9ffaf9cad748bea gdb/config/sparc/tm-nbsd64.h
+d0f148da55fdba8384a4041f7864704c gdb/config/sparc/tm-sol2.h
+e1895b08602453c9874e528cbd9df36f gdb/config/sparc/tm-vxworks.h
+037eb831901f8937ae3c0b2fd6b0a4fc gdb/config/sparc/vxworks.mt
+39fe5a891bfc2524ea91063107a129b1 gdb/config/v850/v850.mt
+677f6046d6881229c86bb9df56115b06 gdb/config/vax/nm-vax.h
+1d9c8d332f92dc2d07b3276f9eab2905 gdb/config/vax/tm-vaxbsd.h
+615b909785f30bb1ce5f6bb5505e80ef gdb/config/vax/vax.mt
+19c9adb3733ba81f65106841d6641905 gdb/config/vax/vaxbsd.mh
+e96b5a3dda05764ee850443d538089e3 gdb/config/vax/vaxult.mh
+6b248ab9672c06272946df62d5712977 gdb/config/vax/vaxult2.mh
+ea637049a1663067a9e607d754aacf40 gdb/config/vax/xm-vax.h
+c1d1a96ae852821d4a09c335e4e36dd4 gdb/config/vax/xm-vaxbsd.h
+df9d5cc6576947ae2ea3b59f14a73ebf gdb/config/vax/xm-vaxult.h
+1b13ab4adce8924a6b422eb24f936e79 gdb/config/vax/xm-vaxult2.h
+26e0262141fc8b59df7148e46140da73 gdb/config/xstormy16/xstormy16.mt
+157ab2011d66651a4d4ce98dcf19ac08 gdb/doc/ChangeLog
+cde55cb7bff1f00bd1c4b1ec0336c922 gdb/doc/LRS
+9af0a707aa6db6fa9c3248ac51fbf71d gdb/doc/Makefile.in
+d5d06eaf9b4d44aa442a4a281aa9aea4 gdb/doc/a4rc.sed
+03edd134f767997d637c48af564d5fd4 gdb/doc/agentexpr.texi
+20980a01b4d2dd320bbe7f9614e34d22 gdb/doc/all-cfg.texi
+d9f59b950243f20762364cb59c0349d0 gdb/doc/annotate.texinfo
+c85dc4fe72550dbbfb1a4af9013cf5d4 gdb/doc/configure
+212f597fd98e318a7cec3a59db82c672 gdb/doc/configure.in
+de7610c73bda71d4e1ad08af82989c2f gdb/doc/fdl.texi
+78c4d48aefad6520bd1cfaca31e87c9a gdb/doc/gdb.texinfo
+ddcf175c8a199b36f81f81bb8ee60d7d gdb/doc/gdbint.texinfo
+7f32ddf5cf96243f4927998a92a47475 gdb/doc/gpl.texi
+73ec71cd3b2e7f61bc530f19d4b35056 gdb/doc/lpsrc.sed
+e5f5af6283e0aa150e569d3e3b48dd1b gdb/doc/observer.texi
+8108dd8f906f2654fecc74958cf383db gdb/doc/psrc.sed
+fbcc30e4dc903f23065f01d9d1328e4a gdb/doc/refcard.tex
+987395a23fca3089964de0f43b44ff5a gdb/doc/stabs.texinfo
+c619c0c50e9c49779ca36a1b6a32f84e gdb/doc/gdb.info
+2fb19f201b72dffbf29201829de8bc09 gdb/doc/GDBvn.texi
+67cd5e3952b99fde483b6d54b8915948 gdb/doc/gdb.info-1
+d6122feae2964f867a91a9d6be8fa378 gdb/doc/gdb.info-2
+dd160b7dd4c3e8e9587915746a46fea1 gdb/doc/gdb.info-3
+24e9218260a77fda7bd3194f94de3be0 gdb/doc/gdbint.info
+dc0f4e884b8a90d4ce10096777921db2 gdb/doc/stabs.info
+b6eec4de042c13c295d1820e3ea7c9ce gdb/doc/annotate.info
+c05455598e50d719af6541096a95dced gdb/gdbserver/ChangeLog
+5c2319b6ac70f05d21f74afa311518e8 gdb/gdbserver/Makefile.in
+b588b07be2b25b286aa970edb2f756e9 gdb/gdbserver/README
+de8ee59fc168a4bc837d9d6dcd6ec68c gdb/gdbserver/acconfig.h
+c656d043d3adf90affcacea01d0fbb83 gdb/gdbserver/acinclude.m4
+b540a936ba5cad8663d09573ac386d32 gdb/gdbserver/aclocal.m4
+263114c5eaa19c910a64b178340f9000 gdb/gdbserver/config.in
+ae2279e05808bd0915860e412a5faf07 gdb/gdbserver/configure
+a47cbe088ef68ee2e1a7a18398b426e4 gdb/gdbserver/configure.in
+e7b1f7b19f97ab1d33027b2e9e7bead1 gdb/gdbserver/configure.srv
+237971ce6e96771488a57da8c88a0788 gdb/gdbserver/gdbreplay.c
+c3c02b21d22cec088d7e185ba23dbb90 gdb/gdbserver/gdbserver.1
+ec54af5eb2a4df38c85e82b8a9e1690e gdb/gdbserver/i387-fp.c
+4d2d0ce45180b1b69e6ae97623e7c108 gdb/gdbserver/i387-fp.h
+21464336059178040e63418622b0e91a gdb/gdbserver/inferiors.c
+39935bc45b8a3693ca779dd541a4cf90 gdb/gdbserver/linux-arm-low.c
+035a666c446e2204c40504debfaf4ab6 gdb/gdbserver/linux-i386-low.c
+a86bf22ec3ee23729b2cc916beadfea2 gdb/gdbserver/linux-ia64-low.c
+66ec921ee12520ac6c4ae7cd86f2df6e gdb/gdbserver/linux-low.c
+f9c4bf1877a9b778f71b27fc43c8ac3d gdb/gdbserver/linux-low.h
+f45f3678e89a448f8cf0f91f69b85862 gdb/gdbserver/linux-m68k-low.c
+7634008a8b75d93b32fd6c3d5ebee456 gdb/gdbserver/linux-mips-low.c
+3907cf240adb65ef45d3ad580d7345f3 gdb/gdbserver/linux-ppc-low.c
+8a618f2c2dfe4bbaaf91e65a58d30aac gdb/gdbserver/linux-s390-low.c
+ab683f9ef601102bb7e5e0dc688b467d gdb/gdbserver/linux-sh-low.c
+0e323f92da11b69cdd7694bf5cafeb6a gdb/gdbserver/linux-x86-64-low.c
+31f0092435cd3b8d454735f094582f73 gdb/gdbserver/mem-break.c
+2b45da328cb71d9f0af8a3cc5f99caac gdb/gdbserver/mem-break.h
+4e4000a60ac00275d96647a7be53b88b gdb/gdbserver/proc-service.c
+76a62e1693bb2c35774548db3af0fcbb gdb/gdbserver/regcache.c
+e33dc5007beb3563c2513d92c6e93079 gdb/gdbserver/regcache.h
+2826063f048775b503f4174b632875c0 gdb/gdbserver/remote-utils.c
+7ad637799056f5f2752ac0a726e6004d gdb/gdbserver/server.c
+262111005195e166b4cca1cc6a9284e3 gdb/gdbserver/server.h
+806ae4df8dfd08ddce2c557e2af4fead gdb/gdbserver/target.c
+89cbbb9ec4d570435a1ea5e3127d0f7e gdb/gdbserver/target.h
+e544c0adfd23a97ed22acd971089fa35 gdb/gdbserver/terminal.h
+195788d8df2dce6c60ee2ff7a40a1841 gdb/gdbserver/thread-db.c
+e80da11d27b1789f6b61592e849c9497 gdb/gdbserver/utils.c
+90b81f951a2351c88c1b4a1fedbb492f gdb/mi/ChangeLog-1999-2003
+7673f1fcadc1356354ac0bf834a32f1f gdb/mi/mi-cmd-break.c
+31748546a8c9ada695f75089906fb1b0 gdb/mi/mi-cmd-disas.c
+321b6d4c3463ff21850e80195884bbb9 gdb/mi/mi-cmd-env.c
+9c45c89b27c23bd1a5e50ab8525bce7f gdb/mi/mi-cmd-file.c
+d463f6758c8d257948aa59d8e97fcacb gdb/mi/mi-cmd-stack.c
+9c4e5da1a9ffd8fb21198b8e45adcafa gdb/mi/mi-cmd-var.c
+e67b53a1d8a7b1fa667c82d7fc260f33 gdb/mi/mi-cmds.c
+32563ba48de6b6e4b6347e2d39d6ef79 gdb/mi/mi-cmds.h
+6deebccbb622b1ddfe1b72d03d9164ab gdb/mi/mi-console.c
+ec733c79189cc33ee80389c366b8ee4d gdb/mi/mi-console.h
+876d29d88b9e1915ed7ea0f14f27b5c9 gdb/mi/mi-getopt.c
+ac8daeb67a457013cda0be842a0f1559 gdb/mi/mi-getopt.h
+d390e6bb89f268062788bc24fc3246ac gdb/mi/mi-interp.c
+a1749766ca906651c6e91aaaa7b785a5 gdb/mi/mi-main.c
+418106d3921c0aae25d8531598f48aea gdb/mi/mi-main.h
+dbeb8553e048c982e6481d9eec2ca416 gdb/mi/mi-out.c
+ea1af536fa7008e4cb819442c647d10e gdb/mi/mi-out.h
+9f46191fe5c36459769faedf85b1c7bb gdb/mi/mi-parse.c
+94825d70f2f9ac43cb9769723dfa4730 gdb/mi/mi-parse.h
+afe7ede1e28847e4a2a5db2ceb259a8d gdb/mi/mi-symbol-cmds.c
+12254ac99d0cc5ea4d8c6da067b0c8b8 gdb/nlm/Makefile.in
+20e829dbd87c5951a051a37f1a848e78 gdb/nlm/configure
+ca1cebf34e2612b18ed15be1eb2ce17e gdb/nlm/configure.in
+2e47ff727d3f10c0c934dfff78a081d5 gdb/nlm/gdbserve.c
+f973c5c42c764609d5cd63925128c869 gdb/nlm/gdbserve.def
+2023c3d27a792299427a4592be4fed15 gdb/nlm/i386.c
+ec1a5ddfdc20b8668b1c383a2d31d5e3 gdb/nlm/i386.h
+af7998b7c344d030d53a0df3c775d52e gdb/nlm/ppc.c
+e65cc68e428afd3b24cbf62f52eb5d1f gdb/nlm/ppc.h
+192c4bacc20346b4bc0ff02b77a91105 gdb/nlm/prelude.c
+912ea9d855fcc23de552c2d674d37812 gdb/osf-share/README
+314092b3f105af13bbccc4fc39481123 gdb/osf-share/cma_attr.h
+ec11d7d3ff9dbfa4d20d96c6ecea4aea gdb/osf-share/cma_deb_core.h
+531f430005d3dfefbbe460e835dd4011 gdb/osf-share/cma_debug_client.h
+b2dbbcf3ce19d6aac60aabe2461688f5 gdb/osf-share/cma_errors.h
+509c48bb5521057f577d861d34415db0 gdb/osf-share/cma_handle.h
+9347ef23e2404f0ee033107934ae0cdb gdb/osf-share/cma_init.h
+5c6c1190b6d93f82d69a7c24a243e17d gdb/osf-share/cma_list.h
+4e1ef48ceb062c4de2d02498037e7d27 gdb/osf-share/cma_mutex.h
+aa4922b22db6dcb97919aefdf6611ff3 gdb/osf-share/cma_sched.h
+e543eac7a41953f1de602b9abf91c3b0 gdb/osf-share/cma_semaphore_defs.h
+c1f9f7112e573c94a6a72bfef19e8c9a gdb/osf-share/cma_sequence.h
+5c6ed620494d12976faee79e8a8be4c9 gdb/osf-share/cma_stack.h
+987386e076ca49cc3407fc4ee3a4290e gdb/osf-share/cma_stack_int.h
+a51385c695f3a215a2b71e98d6bea995 gdb/osf-share/cma_tcb_defs.h
+c20fd87765652ad7ba50f43a0ec95088 gdb/osf-share/cma_util.h
+77b2f029b50b47ab8989da00b35b9438 gdb/osf-share/AT386/cma_thread_io.h
+7cd3745f37bbbfcd24086735939ead52 gdb/osf-share/HP800/cma_thread_io.h
+36cb16e3cf86ddd4609d275a6a3052f5 gdb/osf-share/RIOS/cma_thread_io.h
+acbd9a81065b26e61ad48b0b032ed9f9 gdb/rdi-share/Makefile.am
+9e4e1f578d17bb99b075896be54200b2 gdb/rdi-share/Makefile.in
+14eed8248957fe4acfd7d076e5cc1560 gdb/rdi-share/README.CYGNUS
+90a45de863805a37425c7d25f5b6ddd3 gdb/rdi-share/aclocal.m4
+44f827f3c04c4fc3193ae1bcc34e1078 gdb/rdi-share/adp.h
+423052688a03ca25efe3031c10c4a2c8 gdb/rdi-share/adperr.h
+bfe71729167f48725ae4d507ed7a9605 gdb/rdi-share/angel.h
+545fc079550aab5b8a86002db3e288a5 gdb/rdi-share/angel_bytesex.c
+f609c420e432a9dccf9bdb3d399bec77 gdb/rdi-share/angel_bytesex.h
+e46ae6eb86b7b1f97d31026cba662fcc gdb/rdi-share/angel_endian.h
+a23f9550b49e345e3419ad235c681425 gdb/rdi-share/ardi.c
+049620066f85205f7a48f60e62ac81e0 gdb/rdi-share/ardi.h
+c6d1b9800befce2b67d1c505568608c7 gdb/rdi-share/armdbg.h
+303b1ae6381ffb45fc26303c44f51eaa gdb/rdi-share/buffers.h
+a87a0b9fab996559c6c656fc33d9d18d gdb/rdi-share/chandefs.h
+01c6eac19e7030820c8ddd1a19c42213 gdb/rdi-share/channels.h
+c0cbfc17c4553a5a4200bbdd0e4248bc gdb/rdi-share/chanpriv.h
+5b6a8ae61ef3b66d9805bc1389cb2d24 gdb/rdi-share/configure
+7a1167306adcdd49c1df9249a1614a59 gdb/rdi-share/configure.in
+6766f813b65cd8bfdf92cd29da36169a gdb/rdi-share/crc.c
+13c90616d2bfe9015c26c1be871a40f1 gdb/rdi-share/crc.h
+d6a6c544909c2b8bab64ff2118198141 gdb/rdi-share/dbg_conf.h
+c808afaf48e2d8f13a7d94d0ac6a6611 gdb/rdi-share/dbg_cp.h
+90785272af227f117b580089656c023b gdb/rdi-share/dbg_hif.h
+621ee5352ad5c75e2e0828446c7888ec gdb/rdi-share/dbg_rdi.h
+34a6e9e24c5c58b7fdb32e4eccb7e002 gdb/rdi-share/devclnt.h
+0bfbeb04620da2fafa9190929ae18d3b gdb/rdi-share/devices.h
+0771db2707377b527718bb44a3c18371 gdb/rdi-share/devsw.c
+d559914c40c17b6a03e507a4749de879 gdb/rdi-share/devsw.h
+f98c9c9ad7cfd0c789a27aee6323eb2b gdb/rdi-share/drivers.c
+7645fb2993d1bc3841f45607c38a26cf gdb/rdi-share/drivers.h
+4f4f67579a2215d8662698f29a81c61f gdb/rdi-share/etherdrv.c
+d8e5f0d8e5e7559b1f30e94b35a7551e gdb/rdi-share/ethernet.h
+6c7c85c9d3833b900230854bfb5a81fe gdb/rdi-share/host.h
+96fd8e4db2ab0c64317674ec848eb6c4 gdb/rdi-share/hostchan.c
+523f95bfa31306e23c377b37c63fa05c gdb/rdi-share/hostchan.h
+78948f052f1bff4278717c5d3401fc0d gdb/rdi-share/hsys.c
+cc8de9ad50d3a4c5217ff58769cd41fd gdb/rdi-share/hsys.h
+3d7d9a085d25a4d27c1ab792a37f17ce gdb/rdi-share/logging.c
+466436e31de53162d99197db8cd38ba9 gdb/rdi-share/logging.h
+ff3e0cc9714806049673a050ca348941 gdb/rdi-share/msgbuild.c
+0e13b39bf04d127519f8ed41f720c6fb gdb/rdi-share/msgbuild.h
+b69f395f07fcd91fc575554d1783603b gdb/rdi-share/params.c
+a73f6cdd9c937c3b8d30a97fbe0abd50 gdb/rdi-share/params.h
+43dbc046859f7d4e50dd071c927081aa gdb/rdi-share/rx.c
+46a32878855b8bf2eb8d9023c4b329c7 gdb/rdi-share/rxtx.h
+1a0719cca18cb894a3aaca732e2301ff gdb/rdi-share/serdrv.c
+72239d1d8af5c802e2971727ae1716d6 gdb/rdi-share/serpardr.c
+e7512f7bf4865b638cddfbe97db3d466 gdb/rdi-share/sys.h
+4f520646d479207ed538955715caa06b gdb/rdi-share/tx.c
+3ff8e0761b4bf62bb5c2d9a8f2c4c634 gdb/rdi-share/unixcomm.c
+6002c66173a3c4f6001979896c888e2c gdb/rdi-share/unixcomm.h
+9ed735c435a35313ad491c309fd32cf6 gdb/regformats/reg-arm.dat
+8936fb07afdc018021e787498e8fbe81 gdb/regformats/reg-i386-linux.dat
+22247e6f668678c70523438e2602e99e gdb/regformats/reg-i386.dat
+eb508b601fa0e05022067d7a7b48a8b9 gdb/regformats/reg-ia64.dat
+767b3762219584b4953a737251b6347f gdb/regformats/reg-m68k.dat
+958e700ab062f4ec5a1bec04860033bb gdb/regformats/reg-mips.dat
+89725b9eb486c038a497e375ea8aabfd gdb/regformats/reg-ppc.dat
+e337d7dff9b66f4ecb3813b1fa8b53f9 gdb/regformats/reg-s390.dat
+d3e9824914e44c31e310e78047754192 gdb/regformats/reg-s390x.dat
+657ed262c66093acacf0ccf85f97c55c gdb/regformats/reg-sh.dat
+8c71b67411765da5ab92789a60f27516 gdb/regformats/reg-x86-64.dat
+a15e17e5899c5d3a3ec176bbe8a376f5 gdb/regformats/regdat.sh
+cce9a607a770dfe505270736e1a32fa7 gdb/regformats/regdef.h
+bf3bd6ad756f2c7ec96759893a0a4517 gdb/signals/signals.c
+32b68d52cb813a01f3eac71017f56d2e gdb/testsuite/.gdbinit
+25ed8adfefee4cab096fc062bec1f8f2 gdb/testsuite/ChangeLog
+8fe4298462566117e49f79e5a5b97a3c gdb/testsuite/Makefile.in
+1b9bb551736dbc95577c91620b81fb6c gdb/testsuite/TODO
+a4cf76282f558aaf126217a96d77dec6 gdb/testsuite/aclocal.m4
+ef3256f0546af678e3c9a37a6204b3f4 gdb/testsuite/configure
+b0ba48010171ad597acb4641ae805961 gdb/testsuite/configure.in
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/abug.exp
+fee369d654e97f06fe1c1e5a6680a672 gdb/testsuite/config/arm-ice.exp
+32bd0508363fae0bd08a72ded1a1ae0d gdb/testsuite/config/cfdbug.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/cpu32bug.exp
+fee369d654e97f06fe1c1e5a6680a672 gdb/testsuite/config/cygmon.exp
+13af1823246a3eb438b1b3b019e64615 gdb/testsuite/config/d10v.exp
+3584f38640f55d3a6c83e3ae35fb0a82 gdb/testsuite/config/dve.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/est.exp
+7bab63ea0812701b5b397cc80f62e894 gdb/testsuite/config/gdbserver.exp
+fee369d654e97f06fe1c1e5a6680a672 gdb/testsuite/config/h8300.exp
+e3dd7802ac4a65da64353fc27a039fee gdb/testsuite/config/hmsirom.exp
+6531bba8668e2c92d81955a13551693b gdb/testsuite/config/hppro.exp
+e4708e4b23e4e6ddd07c7245736d37b3 gdb/testsuite/config/i386-bozo.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/i960.exp
+50f6a13c0fd1efa871f0b7c0dc273e0d gdb/testsuite/config/m32r-stub.exp
+ed9b2866854fb841a339c72ab2fe4807 gdb/testsuite/config/m32r.exp
+3b4962b783a530746573abd6b4e2bd9b gdb/testsuite/config/m68k-emc.exp
+b768f8929ee37be60d06c5d4bc68338e gdb/testsuite/config/mips-idt.exp
+b768f8929ee37be60d06c5d4bc68338e gdb/testsuite/config/mips.exp
+3584f38640f55d3a6c83e3ae35fb0a82 gdb/testsuite/config/mn10300-eval.exp
+806f817346aa75f71dbe63cbb3181951 gdb/testsuite/config/monitor.exp
+b4f7b351e4d72b3f5a7ce57c944a2e43 gdb/testsuite/config/netware.exp
+52318b40e559b38730204f551a706cd6 gdb/testsuite/config/nind.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/proelf.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/rom68k.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/sh.exp
+f11bbd2b680602eec832c7d9c1c65e15 gdb/testsuite/config/sid.exp
+b2359c524273c898f41c76addbe8ec67 gdb/testsuite/config/sim.exp
+f3615f8a1eb7b7e32338b7159ad1cdfc gdb/testsuite/config/slite.exp
+67a2e8c61a226a4437fd7b94a90d5dae gdb/testsuite/config/sparclet.exp
+2bf98b1738dabf1d05965a94c522301e gdb/testsuite/config/udi.exp
+e4c58b54d7ff81dbc51d97347e994827 gdb/testsuite/config/unix.exp
+6230016d4a95b38beaefc02a190196ac gdb/testsuite/config/unknown.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/vr4300.exp
+5778cc39113ae688a315eb482579c9ef gdb/testsuite/config/vr5000.exp
+3d29268e9f092c9bd5193a9d4bef9514 gdb/testsuite/config/vx.exp
+5d234db137378e9f144ae0b2ef55e31c gdb/testsuite/config/vxworks.exp
+2b0a0fbf59c988aa7247e14edb13a1e2 gdb/testsuite/config/vxworks29k.exp
+f6c31f326a6a8a5fe922841a22e861cb gdb/testsuite/gdb.arch/Makefile.in
+8512d3cf77bca3f120284ed9cfb3f64a gdb/testsuite/gdb.arch/altivec-abi.c
+80ebb5a77c62c98d3cba9b8ea837c58e gdb/testsuite/gdb.arch/altivec-abi.exp
+a4b44663a9c9d2ac554ea371750489cf gdb/testsuite/gdb.arch/altivec-regs.c
+995b547b55190ba6dcfadf1b131e247b gdb/testsuite/gdb.arch/altivec-regs.exp
+11389013dfeba005022a1d910728c9d7 gdb/testsuite/gdb.arch/e500-abi.c
+f6b0caebb0c552636c28219dd2829b07 gdb/testsuite/gdb.arch/e500-abi.exp
+fcd0dd3432e917999e1b351b9467f52f gdb/testsuite/gdb.arch/e500-regs.c
+6005db01e75e05b21ee4d173e0657311 gdb/testsuite/gdb.arch/e500-regs.exp
+610adaeec31b12d5058382bbb879dffa gdb/testsuite/gdb.arch/gdb1291.exp
+894ef9bf1398451f672da587e0de601c gdb/testsuite/gdb.arch/gdb1291.s
+77a0d5ff18e4eb9946adfc73e72925e4 gdb/testsuite/gdb.arch/gdb1431.exp
+8f138551370f353d62af0a66fd916109 gdb/testsuite/gdb.arch/gdb1431.s
+03e1299995e692fd14be6d3074762614 gdb/testsuite/gdb.arch/gdb1558.c
+90d03378a7b2da90c619821d2a7024df gdb/testsuite/gdb.arch/gdb1558.exp
+a4fdd6dc2a5d5f881b4ebe8165b4f95d gdb/testsuite/gdb.arch/i386-prologue.c
+c43757ac618fef5c7ac3d85636830c71 gdb/testsuite/gdb.arch/i386-prologue.exp
+805e621a37c4e3d991b51b6f6168ed50 gdb/testsuite/gdb.arch/i386-unwind.c
+2fe2a6b0ee998ba93f54e216b58694b5 gdb/testsuite/gdb.arch/i386-unwind.exp
+f2e003c28af0ab5d01be9fc57e01b1cb gdb/testsuite/gdb.asm/Makefile.in
+5c938c065a5b5c92a9c605397508d57e gdb/testsuite/gdb.asm/alpha.inc
+73f28b814430e5f1534678ff549c32cc gdb/testsuite/gdb.asm/arm.inc
+93e4d5b2e372c1a0c82b844d252f3027 gdb/testsuite/gdb.asm/asm-source.exp
+9aeaf0c0a1892ef0119d1db1bed81ad9 gdb/testsuite/gdb.asm/asmsrc1.s
+6d621f0d5b835ebe361d6f72dfd0bf3e gdb/testsuite/gdb.asm/asmsrc2.s
+88599ba05a4590c4e5571eb37e80623b gdb/testsuite/gdb.asm/common.inc
+b7ffb6852499fbf15bcd68536bec63bd gdb/testsuite/gdb.asm/d10v.inc
+b3f11b21e5921c419a43f93720dedf85 gdb/testsuite/gdb.asm/empty.inc
+2778e941fd6f043a75d17361362e5c0d gdb/testsuite/gdb.asm/frv.inc
+05568e93b7a8ffb65984793527e01bb7 gdb/testsuite/gdb.asm/i386.inc
+600540c3b6eda05395ca94bf7d5b10cb gdb/testsuite/gdb.asm/ia64.inc
+7aab094990e39f5827eb3942d43a8e8e gdb/testsuite/gdb.asm/m32r.inc
+b1f873697325c1c26af06371042e3bf7 gdb/testsuite/gdb.asm/m68hc11.inc
+a3b2dce54f8645b4897e0a89118b47ec gdb/testsuite/gdb.asm/m68k.inc
+2f0be533d5222ff80ace7e7757d52817 gdb/testsuite/gdb.asm/mips.inc
+c4d2ba6404c6cf567a68a9e710a973a0 gdb/testsuite/gdb.asm/netbsd.inc
+b0cbb2f3906881df1c592b02c52f33ae gdb/testsuite/gdb.asm/openbsd.inc
+7a37c838ea49e38f4542b1ee152de56e gdb/testsuite/gdb.asm/powerpc.inc
+c504c2fe18f66d3eda109861b56cb56c gdb/testsuite/gdb.asm/s390.inc
+24bf42e27e2b37933c2142f82a790128 gdb/testsuite/gdb.asm/s390x.inc
+a90c51629d5c564b1acf32b681850865 gdb/testsuite/gdb.asm/sh.inc
+004e3184dcbd00cdedc9969b1a860626 gdb/testsuite/gdb.asm/sparc.inc
+bef01819157e0cca7af4ba8058f5eaab gdb/testsuite/gdb.asm/sparc64.inc
+e3c5be9e840a34c66a75b0204fe24a05 gdb/testsuite/gdb.asm/v850.inc
+d9c5367584eaf2d30d4e55f545cf7d8f gdb/testsuite/gdb.asm/x86_64.inc
+425d8b8ae6d12133808165dd066a3f6c gdb/testsuite/gdb.asm/xstormy16.inc
+4009b43c0b4ee5a6d0ae5ddcefac64ce gdb/testsuite/gdb.base/Makefile.in
+ed3dc8bc6fbc3b7c4f74464eb900f404 gdb/testsuite/gdb.base/a2-run.exp
+006e8779c9e23af3419a58591b7eab7e gdb/testsuite/gdb.base/advance.c
+b5ccf780e1c1f2f629cabd8750e778ba gdb/testsuite/gdb.base/advance.exp
+42d593b5c24fba70246c5cf9c68d3b36 gdb/testsuite/gdb.base/all-bin.exp
+7a6a57ab31ce1cf79d80fe6b690ba253 gdb/testsuite/gdb.base/all-types.c
+f76f09cd7572a5024b5ec2307f4f7a9b gdb/testsuite/gdb.base/annota1.c
+8cd0cd8641afd01f4c935243c1197fc0 gdb/testsuite/gdb.base/annota1.exp
+f76f09cd7572a5024b5ec2307f4f7a9b gdb/testsuite/gdb.base/annota3.c
+16f403c0b7440c56ef05c4a1232361be gdb/testsuite/gdb.base/annota3.exp
+8c75ba989aa918790b50c810f5304737 gdb/testsuite/gdb.base/args.c
+9fb653010e52acc3834813932f7e2c24 gdb/testsuite/gdb.base/args.exp
+93afdd2e5026fe7727e196f13e02995f gdb/testsuite/gdb.base/arithmet.exp
+ee9bc8fb86c00f2a69afa4c2ae0b477a gdb/testsuite/gdb.base/assign.exp
+7c164cbba3852ca6d8407f5461733f76 gdb/testsuite/gdb.base/async.c
+39b88a45d83998559d429d98912ad249 gdb/testsuite/gdb.base/async.exp
+67f370c8661ab05209185c9be1b1266f gdb/testsuite/gdb.base/attach.c
+8bfb2ef79095ac2aa2d432b45ef6107c gdb/testsuite/gdb.base/attach.exp
+40ea0b637bee041d22c72ad5ce356d17 gdb/testsuite/gdb.base/attach2.c
+d8f766041b8c03338b5833d6c37c5008 gdb/testsuite/gdb.base/average.c
+872a00e3c46112465087bf0aaaedebfd gdb/testsuite/gdb.base/bang.exp
+94c1f1818c9234b5e8e7669b457865c1 gdb/testsuite/gdb.base/bar.c
+875a150f7fd4db096ea08b9acd105dae gdb/testsuite/gdb.base/baz.c
+3181c808c72953c27e8a29ae3afcf22c gdb/testsuite/gdb.base/bigcore.c
+36863f2f42584e542231f41e82d44a84 gdb/testsuite/gdb.base/bigcore.exp
+22193e74f9a52aac8fe5375e117ac5de gdb/testsuite/gdb.base/bitfields.c
+015fdf4c0afbd372df11c23ffe0c2062 gdb/testsuite/gdb.base/bitfields.exp
+3ba4ad95b3f5c2c0b1abedf3b5846c53 gdb/testsuite/gdb.base/bitops.exp
+601f4ed2b5be1d234ba175e76d7bba62 gdb/testsuite/gdb.base/branches.c
+2072198680ebcf20f2dcbce969384927 gdb/testsuite/gdb.base/break.c
+cc466009ba3781ecf76714e2c146bfb5 gdb/testsuite/gdb.base/break.exp
+0911aa8f8bd7838fcdca5a823e18d4bc gdb/testsuite/gdb.base/break1.c
+00423b6818e5837317fd66f9609d152b gdb/testsuite/gdb.base/call-ar-st.c
+50eb8085571c77c0415dded8a60499aa gdb/testsuite/gdb.base/call-ar-st.exp
+868c4632e7860280ad3ddd0c7713c819 gdb/testsuite/gdb.base/call-rt-st.c
+c6ef05df7be59aa77bb3e56b507978b3 gdb/testsuite/gdb.base/call-rt-st.exp
+0903784a2f2f16faef989543e584e31e gdb/testsuite/gdb.base/call-strs.c
+824fdfbfe47a90c63cc9de1ea2b578a4 gdb/testsuite/gdb.base/call-strs.exp
+fce99e37c5d54bdb6668864d2cd9c1d0 gdb/testsuite/gdb.base/callfuncs.c
+7960181a9746bd095d464c0a304d7c43 gdb/testsuite/gdb.base/callfuncs.exp
+71babf1dd57d05e9d200883f6ac4bb5d gdb/testsuite/gdb.base/charset.c
+938b6e3cfd4d1b2707a937fb516d993a gdb/testsuite/gdb.base/charset.exp
+91a9797c36773f25d2961a2478d37c89 gdb/testsuite/gdb.base/chng-syms.c
+91dbe3696c7e00c1e504340ef9ff26cd gdb/testsuite/gdb.base/chng-syms.exp
+30c83b012547439baf0bdc2e434ca2aa gdb/testsuite/gdb.base/code-expr.exp
+00ef696480a9fdcb085cdf98561f29b6 gdb/testsuite/gdb.base/commands.exp
+488b024dd9948ec46181a20cb45758dd gdb/testsuite/gdb.base/completion.exp
+df7ab9e8669eed8b605d3f815f61c36d gdb/testsuite/gdb.base/complex.c
+a63f285778c17a9d453af01b4ff7a973 gdb/testsuite/gdb.base/complex.exp
+651119d1f6861763b0af972709fd9698 gdb/testsuite/gdb.base/cond-expr.exp
+def4010769f7f492e653c90ba8272b1f gdb/testsuite/gdb.base/condbreak.exp
+0a38768b03d77eda97cc0c83af11699d gdb/testsuite/gdb.base/consecutive.c
+1130760ccbabb0197daa4e224d88d1d9 gdb/testsuite/gdb.base/consecutive.exp
+610d0ec5dc0ae6317e3f9454b8300660 gdb/testsuite/gdb.base/constvars.c
+84a7fa577e209a4d4a40453593b16dc1 gdb/testsuite/gdb.base/constvars.exp
+50e877cf09415173722b8c21eed9a378 gdb/testsuite/gdb.base/corefile.exp
+427760e8de2aab3cd02962aafdb99481 gdb/testsuite/gdb.base/coremaker.c
+5b80768aac60f433336ef045b5fe503a gdb/testsuite/gdb.base/coremaker2.c
+f92cf37b9849545e7ce2ba344ebd56bb gdb/testsuite/gdb.base/cvexpr.c
+66a6cc7779c88715c6aba9beae59086b gdb/testsuite/gdb.base/cvexpr.exp
+c8b29ef2ecb662f50ea8aa7966c163f8 gdb/testsuite/gdb.base/d10v.ld
+35ce0d1e8a6cc6a278649ec7464d8a1c gdb/testsuite/gdb.base/d10vovly.c
+96972aa560dc9ae7bf4aa451089dd652 gdb/testsuite/gdb.base/dbx.exp
+58769d0e980e244d5efee1f8f48e88c7 gdb/testsuite/gdb.base/default.exp
+d75072033b5aa6a428ecebb54901b110 gdb/testsuite/gdb.base/define.exp
+e17c89ad0316df1b06b891ef7a55c2a7 gdb/testsuite/gdb.base/detach.exp
+6cd78185592d6b4044a13581688e6cf8 gdb/testsuite/gdb.base/display.c
+29a0bfb1ac83eaa5afc10efeedfc413c gdb/testsuite/gdb.base/display.exp
+ca9ff510856000f9ee111095ef00f913 gdb/testsuite/gdb.base/dump.c
+af920ca32a6573d11568cdac8f4dea88 gdb/testsuite/gdb.base/dump.exp
+9075c0d3ec951a0abe5676b1ef96ec48 gdb/testsuite/gdb.base/echo.exp
+ecbc80201eeced19112ea5573027f051 gdb/testsuite/gdb.base/ena-dis-br.exp
+b9638337fbfa28806436681d540a2311 gdb/testsuite/gdb.base/ending-run.c
+fb77ce2f143c4b0f379f1b6252f2258f gdb/testsuite/gdb.base/ending-run.exp
+81c3b4c3fcb5a022955c9ef9d469c4b5 gdb/testsuite/gdb.base/environ.exp
+211ec4f59e5be497d413e019bcecfc17 gdb/testsuite/gdb.base/eval-skip.exp
+fe778e4ca9af81e067b376479c5f876d gdb/testsuite/gdb.base/execd-prog.c
+2d5e42c7a5399e6b0e5088388b4cfcc0 gdb/testsuite/gdb.base/exprs.c
+55a20d2ea634f35e3a72ce9974c4a70d gdb/testsuite/gdb.base/exprs.exp
+0a295f41f0583ed9b21670c4788e416d gdb/testsuite/gdb.base/fileio.c
+bb5612c8d001e8144111a9e8ed0eb51c gdb/testsuite/gdb.base/fileio.exp
+c91a165e1f3c3fa15a1e255286b8cae5 gdb/testsuite/gdb.base/finish.exp
+d7304fcc209574d8e454c348a8fa942f gdb/testsuite/gdb.base/float.exp
+5acfdd7a2dd0575778a59acf1e3e899e gdb/testsuite/gdb.base/foll-exec.c
+eefd76aaa3fd774ba882caeb8b5a7890 gdb/testsuite/gdb.base/foll-exec.exp
+9ab04e56d1356b09f45c460f3338996f gdb/testsuite/gdb.base/foll-fork.c
+be056e486518a4e214f569365159a062 gdb/testsuite/gdb.base/foll-fork.exp
+a7ea93bfb6e477f12e7a3c6404410b88 gdb/testsuite/gdb.base/foll-vfork.c
+97afa991b7f063aa7c46d74a42f92d0c gdb/testsuite/gdb.base/foll-vfork.exp
+c6a16edc9359f0384e9bb01cc216272c gdb/testsuite/gdb.base/foo.c
+9e1e774f5531e477af9498e0b4a52be5 gdb/testsuite/gdb.base/freebpcmd.c
+2ff49eaf4db0985b256e79e03ab8209d gdb/testsuite/gdb.base/freebpcmd.exp
+e263d03bb6f3616f05e38769be7a0c5d gdb/testsuite/gdb.base/funcargs.c
+1e3db7de8522d3b2cc3c28625c7e7962 gdb/testsuite/gdb.base/funcargs.exp
+d9b2a9d592f70524f1b24394c262d9cf gdb/testsuite/gdb.base/gcore.c
+e5d420875950e9837bed75520e62aa4f gdb/testsuite/gdb.base/gcore.exp
+201b1e7cda5fe07f2ec0588491870476 gdb/testsuite/gdb.base/gdb1056.exp
+7354dab51e84c82dbd7e5d8aab734be8 gdb/testsuite/gdb.base/gdb1090.c
+f593204485765887caef1fab43b56a3a gdb/testsuite/gdb.base/gdb1090.exp
+151b3327206fa8d34e59210f4c9d492f gdb/testsuite/gdb.base/gdb1250.c
+8273e1b9b96551105d11fc7c359a24cc gdb/testsuite/gdb.base/gdb1250.exp
+9546d8e111806b5ad1889cfc3efdc982 gdb/testsuite/gdb.base/gdb1476.c
+1eca46287cacb0a0159271c1af723b9e gdb/testsuite/gdb.base/gdb1476.exp
+4232da6d5581c0fa4c44da546289de93 gdb/testsuite/gdb.base/gdb1555-main.c
+e3c60ed457773040ca69854ec22ec8bd gdb/testsuite/gdb.base/gdb1555.c
+25ff15e1b3a612addb1143b90ecb55a4 gdb/testsuite/gdb.base/gdb1555.exp
+a2bfa5dea845c91374b0ca3348d5fe1c gdb/testsuite/gdb.base/gdb_history
+bcecd23b18e6167cbe3e0389bfb37fd0 gdb/testsuite/gdb.base/gdbvars.exp
+9cd4ef136dfbee149a4056477283fa41 gdb/testsuite/gdb.base/grbx.c
+e04603d844309e85e3e34d3b30700027 gdb/testsuite/gdb.base/help.exp
+f5084bccca9af02ac220b5399253c9a8 gdb/testsuite/gdb.base/huge.c
+8a73e9b5254bf4649fdc49af449ed9b5 gdb/testsuite/gdb.base/huge.exp
+f987247ada9c599f12b526ce2f3b6e2e gdb/testsuite/gdb.base/info-proc.exp
+55bbb1088e1173143dd23818588c559c gdb/testsuite/gdb.base/int-type.c
+57e887f3379fccaae0cdaeb9f2a5a400 gdb/testsuite/gdb.base/interrupt.c
+c6643f7d431ab97838867df2a15b28e9 gdb/testsuite/gdb.base/interrupt.exp
+5fefadea13c06424265ee8e5dbf68dd6 gdb/testsuite/gdb.base/jump.c
+5ded83121a71b46fb6d7eb5430db2d5f gdb/testsuite/gdb.base/jump.exp
+2a15b07c2dcc5fa0a53bc4717b0d7b42 gdb/testsuite/gdb.base/langs.exp
+a7fcf828c54dbdc1100d525500c41a4c gdb/testsuite/gdb.base/langs0.c
+2d0b8bc2c2b4eb4f8a28b7cb39ce5dca gdb/testsuite/gdb.base/langs1.c
+823ccdf3ec56d8acb08d21598d0f1d8e gdb/testsuite/gdb.base/langs1.f
+c62aebd49fcf2ece63ec68610c644c0e gdb/testsuite/gdb.base/langs2.c
+c90e022fb5ef3df8a5639df233f9c350 gdb/testsuite/gdb.base/langs2.cxx
+23a9d320d2c8ac0836c97967984bd51d gdb/testsuite/gdb.base/list.exp
+e7d4aa964e0ac3b22a0ecfeef466c437 gdb/testsuite/gdb.base/list0.c
+d98c219c48dd073b09144e6cdb9de268 gdb/testsuite/gdb.base/list0.h
+8b38bf10b14906aeede912d147c23b43 gdb/testsuite/gdb.base/list1.c
+b589461aa6a9c9e419c082b7014c237f gdb/testsuite/gdb.base/logical.exp
+a54639191cb3e89e3b547b86c0aef0cd gdb/testsuite/gdb.base/long_long.c
+23be93503a8f2ef7d0c978d1113f45e8 gdb/testsuite/gdb.base/long_long.exp
+d89474265b62f35df0c23a47bf1cc11a gdb/testsuite/gdb.base/m32r.ld
+35ce0d1e8a6cc6a278649ec7464d8a1c gdb/testsuite/gdb.base/m32rovly.c
+316f3fbf32b8b180129717ecb4633aa1 gdb/testsuite/gdb.base/macscp.exp
+3f678def3cc5c8c57803f411fd798d0d gdb/testsuite/gdb.base/macscp1.c
+256625bcc48a090ec4e5b85d1affa9bc gdb/testsuite/gdb.base/macscp2.h
+bbd68c316d4ba5e21f8aac02eb605fa4 gdb/testsuite/gdb.base/macscp3.h
+dc1c7b2d0d97de5e07f0046fca14d586 gdb/testsuite/gdb.base/macscp4.h
+bfbb0d654ee247fe755f9ee1be514e8f gdb/testsuite/gdb.base/maint.exp
+c779221fb70a0e5b29aa0fffeb4b46b2 gdb/testsuite/gdb.base/mips_pro.c
+8fd94258da79333e73ac9ad4faafc5bf gdb/testsuite/gdb.base/mips_pro.exp
+643671e20fe8eff654f14011ab332137 gdb/testsuite/gdb.base/miscexprs.c
+a53db384f24cc2f13b54641e8484463d gdb/testsuite/gdb.base/miscexprs.exp
+b7d340c5410e83eab50f73e499be0759 gdb/testsuite/gdb.base/nodebug.c
+96cf7e971da487ba62c8e1c94e8fb60e gdb/testsuite/gdb.base/nodebug.exp
+469b90b7b48e01734bee63a6321e2faf gdb/testsuite/gdb.base/opaque.exp
+52ba3d967b2b82fff0684a32c9306380 gdb/testsuite/gdb.base/opaque0.c
+177d0aa2dc05a0887607543ae7a63ae4 gdb/testsuite/gdb.base/opaque1.c
+cc19ee1eb79fe010ad5bab989640c407 gdb/testsuite/gdb.base/overlays.c
+faa750cd2900fbbbd609ea743fd1d038 gdb/testsuite/gdb.base/overlays.exp
+6fa3516a413a089a2bed7b00775ed95b gdb/testsuite/gdb.base/ovlymgr.c
+beb7ddd8ac440e541b4ff7458987281f gdb/testsuite/gdb.base/ovlymgr.h
+5fe30c7d9c3428cf65e02db149b3c852 gdb/testsuite/gdb.base/page.exp
+0fec50da02e7cd3be0581d9269e8b27b gdb/testsuite/gdb.base/pc-fp.c
+acf02b54a7cd478c1f770df64166408a gdb/testsuite/gdb.base/pc-fp.exp
+e366a3658e7a4581fd1f0f28b7c689e3 gdb/testsuite/gdb.base/pending.c
+3eeab53be35c2e2241520478f2d59a27 gdb/testsuite/gdb.base/pending.exp
+e5661fce945960702d34e188dc137490 gdb/testsuite/gdb.base/pendshr.c
+8d268468e492f058d3ca8b553a0cfc54 gdb/testsuite/gdb.base/pointers.c
+2e3d53cd90ed8564c46f911eeb0763b8 gdb/testsuite/gdb.base/pointers.exp
+20a5cda7d951262d0e36cb599fdb8857 gdb/testsuite/gdb.base/printcmds.c
+89afc92c569b3f71df27409279a0ea27 gdb/testsuite/gdb.base/printcmds.exp
+a0de2136d2a31c14df5ca43acfb185d2 gdb/testsuite/gdb.base/psymtab.exp
+b263e085b920ccae2568157fcc33189f gdb/testsuite/gdb.base/psymtab1.c
+f356ff50643e59000ef3d9f24089698b gdb/testsuite/gdb.base/psymtab2.c
+05524755778cd48d384594d06c45b463 gdb/testsuite/gdb.base/ptype.c
+bbea5bb5ba851bfd7b82d3aaa538d4c4 gdb/testsuite/gdb.base/ptype.exp
+a7acac6fdc62c0efb806906436a5100d gdb/testsuite/gdb.base/radix.exp
+d0af9180f489613bd0f46b425b99bad6 gdb/testsuite/gdb.base/readline.exp
+b7c0b9263a943f4e519a0f797e126317 gdb/testsuite/gdb.base/recurse.c
+bb51a80d999f218749eebd66efc62524 gdb/testsuite/gdb.base/recurse.exp
+2c0669f4c38e5ccfbe2c806e1a753df5 gdb/testsuite/gdb.base/regs.exp
+684697d0d7067fdcdfe5d748511e5357 gdb/testsuite/gdb.base/relational.exp
+686dfafae5faded4434b5c7aecfeaa14 gdb/testsuite/gdb.base/relocate.c
+f02bbbb3fa3f3d014be89bff9acb4bb1 gdb/testsuite/gdb.base/relocate.exp
+79696e315e518bcff76ca31d67e55856 gdb/testsuite/gdb.base/remote.c
+9d053b91f9b3e58f5a9932be0be0b84b gdb/testsuite/gdb.base/remote.exp
+27894b27c524e566e4d42589ade0cf8f gdb/testsuite/gdb.base/reread.exp
+b27553d250bc9c1302b8081e241e4630 gdb/testsuite/gdb.base/reread1.c
+a3e9015380f0b2b958c6387b733901ab gdb/testsuite/gdb.base/reread2.c
+ca133757968b4ebea39a4d1e62aba91f gdb/testsuite/gdb.base/restore.c
+e491ec9199c1ed67de25dc40bd92808a gdb/testsuite/gdb.base/restore.exp
+a8afc935fcccb233c94780a5db339e1b gdb/testsuite/gdb.base/return.c
+13a079a77310dbe445c45c0e621c3f17 gdb/testsuite/gdb.base/return.exp
+a083d8d4881ea947f4ec0a7af80e02e8 gdb/testsuite/gdb.base/return2.c
+10c8b7f92f911fb4c553fa74cec6cc62 gdb/testsuite/gdb.base/return2.exp
+d9eeb3be3ebabd9f01a38401b6df8314 gdb/testsuite/gdb.base/run.c
+a2a79551e1b98c1dd032f04465f048dc gdb/testsuite/gdb.base/scope.exp
+a2b39c6753b63d36e9076b2bc12609ea gdb/testsuite/gdb.base/scope0.c
+f3b699a47e41a789efbd9f2bf3192364 gdb/testsuite/gdb.base/scope1.c
+8ff9780c746b7d4d3cb76ac45da56ab6 gdb/testsuite/gdb.base/sect-cmd.exp
+2571b152b07c4691f77d64f88958c06c gdb/testsuite/gdb.base/selftest.exp
+ba416b5e08382958d4a43c9c20c05472 gdb/testsuite/gdb.base/sepdebug.c
+f3d1bfd3b413e34d7b3c8864d370b201 gdb/testsuite/gdb.base/sepdebug.exp
+fd21df76b25003cb1b35af07ebac8991 gdb/testsuite/gdb.base/setshow.c
+9f41239b45ecde01004ee202981d37e5 gdb/testsuite/gdb.base/setshow.exp
+366a61f5feeadf4733e79506ff7f4271 gdb/testsuite/gdb.base/setvar.c
+c3d589d2a94dbe7531ce6b4e481ed2a3 gdb/testsuite/gdb.base/setvar.exp
+71f6089eec75294622693f43e606af97 gdb/testsuite/gdb.base/shlib-call.exp
+4417659f325c1872e097516a2b17a031 gdb/testsuite/gdb.base/shmain.c
+ea313b317035fa79cc1ae9bf6ef7d4ca gdb/testsuite/gdb.base/shr1.c
+4c06f99b8d9db6a8a11b0e5474c3b5f5 gdb/testsuite/gdb.base/shr2.c
+3764973c71d5aa701031b4e66fd276d3 gdb/testsuite/gdb.base/shreloc.c
+e432ccf9a88cafdb6d5ed558f6161589 gdb/testsuite/gdb.base/shreloc.exp
+3a2a211e5b6d5888758f26dbd9cd9c23 gdb/testsuite/gdb.base/shreloc1.c
+3b1d57da2ee4cce1781d966f09f8d7fb gdb/testsuite/gdb.base/shreloc2.c
+8ec70b82c42267a8bcdedba8721a7cb3 gdb/testsuite/gdb.base/sigall.c
+4b5b5225fcea41cfd8fec72be906dac6 gdb/testsuite/gdb.base/sigall.exp
+24ddac9178f2f43b2b0f577c77aef032 gdb/testsuite/gdb.base/signals.c
+9d5ecbf1bf101a23d73dcbb63b02344f gdb/testsuite/gdb.base/signals.exp
+2d5b486956a7f497ac3e5969bac13c3f gdb/testsuite/gdb.base/sizeof.c
+3d77ff8355b4d7ea4d307bb066fc96e1 gdb/testsuite/gdb.base/sizeof.exp
+e711a6cfdf17afc08fbd300867145dd6 gdb/testsuite/gdb.base/so-impl-ld.c
+9d24453edc5e49b1da84335dc7883779 gdb/testsuite/gdb.base/so-impl-ld.exp
+1429ffbb9973f67ebe556228ae4dfc66 gdb/testsuite/gdb.base/so-indr-cl.c
+3b86649016dafbeb80fe87007675294e gdb/testsuite/gdb.base/so-indr-cl.exp
+0cdb3ac52471574e63518d04e7490c77 gdb/testsuite/gdb.base/solib.c
+94b46fe7df64f5ba7e817ffefe6d2359 gdb/testsuite/gdb.base/solib.exp
+09b3514ecddad4ca9dd40f06f77ca5cc gdb/testsuite/gdb.base/solib1.c
+c08d6d5da171e08cd8bce11e6ee9ffb5 gdb/testsuite/gdb.base/solib2.c
+25dd3e940b7f381b4985683b64dff8cf gdb/testsuite/gdb.base/ss.h
+d38881228941b667d1352bd915e0a854 gdb/testsuite/gdb.base/step-line.c
+71d30ad481f6195760b808b810273e7f gdb/testsuite/gdb.base/step-line.exp
+7206edd78b2338b2c8a5ad3c3f2fb791 gdb/testsuite/gdb.base/step-line.inp
+9ffc2cd8e384888785a57bd5ed8168d2 gdb/testsuite/gdb.base/step-test.c
+fc747038f51e6fd85a5c2eb1b046ef42 gdb/testsuite/gdb.base/step-test.exp
+1ea088b852b87134ad1b9038b0dd2204 gdb/testsuite/gdb.base/store.c
+7e7d239e7100be5671f2c2990dcf69a3 gdb/testsuite/gdb.base/store.exp
+86167fcd80ed0981793214b2d1ebdfd8 gdb/testsuite/gdb.base/structs.c
+c1fc09c647ec6559877e7a18b65a106d gdb/testsuite/gdb.base/structs.exp
+ea9603592d237a2624d44c1a417ebaef gdb/testsuite/gdb.base/structs2.c
+ee778a669792e153b9a3b5c3a5eca548 gdb/testsuite/gdb.base/structs2.exp
+f979f053e2cd1a61d9630b75d70607ef gdb/testsuite/gdb.base/sum.c
+4b1c9e381a4febb6792520fb20ef6968 gdb/testsuite/gdb.base/term.exp
+e230b8767f5ad5901a40b01435d17089 gdb/testsuite/gdb.base/twice.c
+d39dd7e6c000d2ea53e26dcbb2c78e0b gdb/testsuite/gdb.base/twice.exp
+fc0f0ff540d9196ce79b6bcba912005c gdb/testsuite/gdb.base/until.exp
+27120a964678d7be0acda6d1687f65dc gdb/testsuite/gdb.base/varargs.c
+669009a810c3d43efbd02fab15f262a9 gdb/testsuite/gdb.base/varargs.exp
+1a9fca83cee9e223ab94207b280c403b gdb/testsuite/gdb.base/vforked-prog.c
+0bc669172c8943baf91e1891aacce69b gdb/testsuite/gdb.base/volatile.exp
+2394ca7c0136f073f6ef282624a651d3 gdb/testsuite/gdb.base/watchpoint.c
+d66283988b1fcfbae48c47b6668cdc77 gdb/testsuite/gdb.base/watchpoint.exp
+c7fbe8854040a2bb100a7b6a03d3e5e3 gdb/testsuite/gdb.base/whatis-exp.exp
+249f024a162cae2c7164d2bf5e5ccd7f gdb/testsuite/gdb.base/whatis.c
+c54397df576846b1182483ad4c6fdd39 gdb/testsuite/gdb.base/whatis.exp
+e82f0cae062478832763b121dd33f0d7 gdb/testsuite/gdb.cp/Makefile.in
+fa88dcd56730da0447f3d14fe40a5cd0 gdb/testsuite/gdb.cp/ambiguous.cc
+14555fe9da732a1ca357ef97e1e76635 gdb/testsuite/gdb.cp/ambiguous.exp
+2088f98bb23167ea5e0c8b394c560519 gdb/testsuite/gdb.cp/annota2.cc
+333672bca861a0abb80d8ba3609ea744 gdb/testsuite/gdb.cp/annota2.exp
+2088f98bb23167ea5e0c8b394c560519 gdb/testsuite/gdb.cp/annota3.cc
+e9be2b37996566ebbf12562f12b6b39b gdb/testsuite/gdb.cp/annota3.exp
+582fe010ae6cfa3c16429c65636bd651 gdb/testsuite/gdb.cp/anon-union.cc
+d94735d63db1e1ca15a5cf6eb085bc5b gdb/testsuite/gdb.cp/anon-union.exp
+4f2277628f5e85ec03d09f6801009802 gdb/testsuite/gdb.cp/breakpoint.cc
+911af0f4d20ff59e21546826d7bff11a gdb/testsuite/gdb.cp/breakpoint.exp
+b5fedd23b64d0faeedc3cecdde2e2aca gdb/testsuite/gdb.cp/bs15503.cc
+4ceee57add7b8eda3d07cd17394d905c gdb/testsuite/gdb.cp/bs15503.exp
+49d31866e1b2029326c237b6d0195eb8 gdb/testsuite/gdb.cp/casts.cc
+ea26ef2dff81fff84be88891e0d18f79 gdb/testsuite/gdb.cp/casts.exp
+c6c1fa5dbdc1e32d7ffe734df4ab75e3 gdb/testsuite/gdb.cp/class2.cc
+5e7b9c69153312095eb652cc4efc5314 gdb/testsuite/gdb.cp/class2.exp
+655c2879707d28e377904faba8b7178a gdb/testsuite/gdb.cp/classes.cc
+de413434fab02990bebeaa2fea68dbd7 gdb/testsuite/gdb.cp/classes.exp
+8b5504ea8f47f041cd1e870dd5674f53 gdb/testsuite/gdb.cp/cplusfuncs.cc
+30b00a620bd85c2cb13a184f7b9ac470 gdb/testsuite/gdb.cp/cplusfuncs.exp
+823926fd7d8df26269049cb16f78d140 gdb/testsuite/gdb.cp/ctti.exp
+71a4a9598ab0c57e27a27859bfe24ef0 gdb/testsuite/gdb.cp/cttiadd.cc
+2056b75ba0f6a1dc66b27e84b9971ba5 gdb/testsuite/gdb.cp/cttiadd1.cc
+324fece7cfe77f4c98e2a17e5ae75364 gdb/testsuite/gdb.cp/cttiadd2.cc
+97dc851f1743b769635112fbbb65ff25 gdb/testsuite/gdb.cp/cttiadd3.cc
+1d5c171bb2be3f964e4e8e6e9e08731e gdb/testsuite/gdb.cp/demangle.exp
+d4c5d86832a3728253bb6e303dca8814 gdb/testsuite/gdb.cp/derivation.cc
+3cd363499769e54bbbf6fee711e897d3 gdb/testsuite/gdb.cp/derivation.exp
+9faa8339cfbf015fde876a3e7dc5589f gdb/testsuite/gdb.cp/exception.cc
+03f1a2ebe9c4cfbf03e5ec59bf63a82a gdb/testsuite/gdb.cp/exception.exp
+dcbaddb5552d4990c58221d1ce771d2d gdb/testsuite/gdb.cp/gdb1355.cc
+3ad755aaa7f75e1b7d3c2429689db2f7 gdb/testsuite/gdb.cp/gdb1355.exp
+bec5831953699a0daf2274369c6f1ed1 gdb/testsuite/gdb.cp/hang.H
+089ad038e3a25cf02e7292e54e7211f2 gdb/testsuite/gdb.cp/hang.exp
+22f928abbcff4e8dc10dfac79ea86311 gdb/testsuite/gdb.cp/hang1.C
+221eed5a3233c502015a7f69c71eb693 gdb/testsuite/gdb.cp/hang2.C
+81270652e911c432e26ef4b3bec6bc66 gdb/testsuite/gdb.cp/hang3.C
+149d5a1b17df4ed57efd97702ee6f740 gdb/testsuite/gdb.cp/inherit.exp
+584a50069ae4ae90c745978c0bb994db gdb/testsuite/gdb.cp/local.cc
+e8a628a9de15f536ce0ff50579b2bc91 gdb/testsuite/gdb.cp/local.exp
+010af669f824c8194c82fb921c6c2b2f gdb/testsuite/gdb.cp/m-data.cc
+3118b023dfac90244cee1113a7d5c32c gdb/testsuite/gdb.cp/m-data.exp
+9e481afa71dc8cf8b2876e7735c4d947 gdb/testsuite/gdb.cp/m-static.cc
+2269c827396d7393f1e3c98bbcb32e4a gdb/testsuite/gdb.cp/m-static.exp
+5756b206314b4e9b256a54b794fa5366 gdb/testsuite/gdb.cp/m-static.h
+7844dbfb63d5ee815db3c14cb769c796 gdb/testsuite/gdb.cp/m-static1.cc
+71f85099658141dde529a13d6838dd6f gdb/testsuite/gdb.cp/maint.exp
+954cfee559a88d4939199720a0123b9c gdb/testsuite/gdb.cp/member-ptr.cc
+05f91f7fd4e90ce55933a0c113dd43e1 gdb/testsuite/gdb.cp/member-ptr.exp
+53d65c3b49d4d39b7a1c8ff6d68c8a65 gdb/testsuite/gdb.cp/method.cc
+b677bbd497abff0d335c164cab65bf58 gdb/testsuite/gdb.cp/method.exp
+ddad9ba3b6f6edd4c639d1788a3d1db8 gdb/testsuite/gdb.cp/misc.cc
+9e0aa441f5a8ed6a0ff508d22a2ab375 gdb/testsuite/gdb.cp/misc.exp
+593e2413f186870185480c45ed5efe0f gdb/testsuite/gdb.cp/namespace.cc
+b136304229591cba0d9f151070142acf gdb/testsuite/gdb.cp/namespace.exp
+ea54384eeced12e1450a1347910b6b18 gdb/testsuite/gdb.cp/namespace1.cc
+0a0023c3a8cf474ec7e85481879828d0 gdb/testsuite/gdb.cp/overload.cc
+3746039ed86f1ae89c5fbad53e5301b2 gdb/testsuite/gdb.cp/overload.exp
+1e6ecfe65de278a0c1e062badc9789e3 gdb/testsuite/gdb.cp/ovldbreak.cc
+a33a48dcca8228f761a994f345065097 gdb/testsuite/gdb.cp/ovldbreak.exp
+0a15a0bc517ee0acca862308c89de14b gdb/testsuite/gdb.cp/pr-1023.cc
+cb9d8280a0b7332e8bf9865a42a2a24a gdb/testsuite/gdb.cp/pr-1023.exp
+07fa7f618722031893284e4df11fe13e gdb/testsuite/gdb.cp/pr-1210.cc
+015ff1129bb4cdb5aad3c5ce626661be gdb/testsuite/gdb.cp/pr-1210.exp
+5176d9071bc98b74d5c9cd3d854a7834 gdb/testsuite/gdb.cp/pr-1553.cc
+280f5ce2f340829b63877ddc086259fd gdb/testsuite/gdb.cp/pr-1553.exp
+6d7e902a5c586f3732cdd94108b06ea7 gdb/testsuite/gdb.cp/pr-574.cc
+801f397f557114a002041b4c1dbd991e gdb/testsuite/gdb.cp/pr-574.exp
+5cc27b72c30cc6f7662b0bd905b36aed gdb/testsuite/gdb.cp/printmethod.cc
+8a50ef2995a84842fd0a9ea5e3484d32 gdb/testsuite/gdb.cp/printmethod.exp
+c02d071b4af80b5f7532f378f17c5162 gdb/testsuite/gdb.cp/psmang.exp
+65de6792316a7abdebadcf6c0fee17f5 gdb/testsuite/gdb.cp/psmang1.cc
+9a48c8c1f04b47004135630c12b9972c gdb/testsuite/gdb.cp/psmang2.cc
+511a6f21e5689ee6ce16f02bb8ac8796 gdb/testsuite/gdb.cp/ref-types.cc
+ab245824bd92d2075e80b52ebea938a8 gdb/testsuite/gdb.cp/ref-types.exp
+6e2f550460a7c84e961017dd97e138dd gdb/testsuite/gdb.cp/rtti.exp
+0462d9e14cbb46e835a439262e142259 gdb/testsuite/gdb.cp/rtti.h
+b7fb1cc3a40d3500b995bbefdf762fbb gdb/testsuite/gdb.cp/rtti1.cc
+222fe0be2dc42d29752bb4a5380a3ff0 gdb/testsuite/gdb.cp/rtti2.cc
+1536cc5f65a058b4d13dfcd79fbd8619 gdb/testsuite/gdb.cp/templates.cc
+91b661d9234bba678ff4f194ced11f51 gdb/testsuite/gdb.cp/templates.exp
+d9543839ad23c15eeddd25f990cd272e gdb/testsuite/gdb.cp/try_catch.cc
+4b69b406088f179e7e054cdc95ba1cd6 gdb/testsuite/gdb.cp/try_catch.exp
+a4011385276a102ff481ca6b86f2906d gdb/testsuite/gdb.cp/userdef.cc
+e27d36723379a94609295daa9d4eabc1 gdb/testsuite/gdb.cp/userdef.exp
+945da4ece00b055700a5a322cbee2d19 gdb/testsuite/gdb.cp/virtfunc.cc
+3b019a6e209215b722a30bec7d22ad45 gdb/testsuite/gdb.cp/virtfunc.exp
+7223f89fe13042a716303a40db766767 gdb/testsuite/gdb.disasm/Makefile.in
+357aad7714972445a94a7e58c9743efc gdb/testsuite/gdb.disasm/am33.exp
+9d7ec73ab52e55ec1f83ec9e35523702 gdb/testsuite/gdb.disasm/am33.s
+bade4ffea198a263af262bf6df3f7b28 gdb/testsuite/gdb.disasm/h8300s.exp
+cb76fc798d647b1ee8ba82f8ad9a5584 gdb/testsuite/gdb.disasm/h8300s.s
+056d65b937ef90537213d9317bc259b7 gdb/testsuite/gdb.disasm/hppa.exp
+1531e9f2d8c5fe8c476a72c8621ac6f5 gdb/testsuite/gdb.disasm/hppa.s
+8df48a7abc7ba3009ba5f49d74d3c8f9 gdb/testsuite/gdb.disasm/mn10200.s
+5eba2ab369ad9613a6c6f470647f73d6 gdb/testsuite/gdb.disasm/mn10300.exp
+e02ce2008b0f7cd2c4bd231e78d46c8c gdb/testsuite/gdb.disasm/mn10300.s
+36450ef0babfd3c6f9867a4cf231ddc7 gdb/testsuite/gdb.disasm/sh3.exp
+e546b5aa7eb88708555537439de19900 gdb/testsuite/gdb.disasm/sh3.s
+f41230f8eff93a371b3faf3209e68cd1 gdb/testsuite/gdb.disasm/t01_mov.exp
+73c5cd7ed86e7e6b41d1e576f311eeeb gdb/testsuite/gdb.disasm/t01_mov.s
+039f81886ee6faf2dc8a91e833ddd582 gdb/testsuite/gdb.disasm/t02_mova.exp
+0acc4aeabf1f5d050371011a1e2db775 gdb/testsuite/gdb.disasm/t02_mova.s
+2a5bbcaa4140ee63ebb5661e817a9c11 gdb/testsuite/gdb.disasm/t03_add.exp
+5cf6fb959f1de5dbfa41541a8286a01c gdb/testsuite/gdb.disasm/t03_add.s
+786174a5e3afabf20b062015a6293f6a gdb/testsuite/gdb.disasm/t04_sub.exp
+b9bd060d194d5ce64afbd5c8785b7211 gdb/testsuite/gdb.disasm/t04_sub.s
+167810df60d29277de69bcb2a2b23665 gdb/testsuite/gdb.disasm/t05_cmp.exp
+131ee421fad26db64b6d6bba8368e5bb gdb/testsuite/gdb.disasm/t05_cmp.s
+c372c558382dab5eb7ce6661b054ec96 gdb/testsuite/gdb.disasm/t06_ari2.exp
+85ba3783b07c440f998dd13619a094d3 gdb/testsuite/gdb.disasm/t06_ari2.s
+1b9b94efa363975f861a60a226160c4a gdb/testsuite/gdb.disasm/t07_ari3.exp
+542d50518d01ead485efbb2e32d0f764 gdb/testsuite/gdb.disasm/t07_ari3.s
+5235cee2e07163875862f952606eef53 gdb/testsuite/gdb.disasm/t08_or.exp
+f4968aeae699c13b7a5a1975b3892a33 gdb/testsuite/gdb.disasm/t08_or.s
+217ec8cc6d7588076858dc7f00d8fa83 gdb/testsuite/gdb.disasm/t09_xor.exp
+7a1e51f2713793b0b90600f013077211 gdb/testsuite/gdb.disasm/t09_xor.s
+e8cb627cdbd6cd1640f0dcd74ff1e915 gdb/testsuite/gdb.disasm/t10_and.exp
+d525da6720c1b3b2dcaf13dee122c8e2 gdb/testsuite/gdb.disasm/t10_and.s
+7451149a6c0caeedf18515689001351c gdb/testsuite/gdb.disasm/t11_logs.exp
+bd2239a841782b7e03adf35c797b9602 gdb/testsuite/gdb.disasm/t11_logs.s
+84f6ccde942b89f7cd6af881608ad8a8 gdb/testsuite/gdb.disasm/t12_bit.exp
+7007158a552329abb3b6bc7f604e864a gdb/testsuite/gdb.disasm/t12_bit.s
+3d7b3b073fdd3356a14ddad76c8e7280 gdb/testsuite/gdb.disasm/t13_otr.exp
+d61dbceb528b78f5bb4b4907443afd07 gdb/testsuite/gdb.disasm/t13_otr.s
+db06bdc80566cb5adea26e17530d3eab gdb/testsuite/gdb.fortran/exprs.exp
+a113f784343dafa68685ad81e88d8865 gdb/testsuite/gdb.fortran/types.exp
+484346ad386e8ad232982d613cf683d8 gdb/testsuite/gdb.gdb/complaints.exp
+7ce6998752da86eee302cc5d33d5e731 gdb/testsuite/gdb.gdb/observer.exp
+bfbd14ddf55fdac9c4b2ffc0166a4a0c gdb/testsuite/gdb.gdb/xfullpath.exp
+a904198187ddbad3444244c4ac4352cd gdb/testsuite/gdb.hp/Makefile.in
+7e2ad2824dada941c40e183acc7b2a79 gdb/testsuite/gdb.hp/configure
+cd31fd392240c25cf69d3d30ae9188de gdb/testsuite/gdb.hp/configure.in
+5ea7cc25704c6afa026b129b8211748b gdb/testsuite/gdb.hp/gdb.aCC/Makefile.in
+a0bbe53b7c6f846724f86f1465218d9d gdb/testsuite/gdb.hp/gdb.aCC/configure
+7cc267fd4fda7efc8fda1744a6851f85 gdb/testsuite/gdb.hp/gdb.aCC/configure.in
+45152502f608f30690417f272d8236ed gdb/testsuite/gdb.hp/gdb.aCC/exception.exp
+cc53bf59d2a9c47d276d1aac84bd0f50 gdb/testsuite/gdb.hp/gdb.aCC/optimize.c
+818ec867f3bdb00145d820ac47686021 gdb/testsuite/gdb.hp/gdb.aCC/optimize.exp
+2fefc4288b99b3e947ca1e21a82fc5ce gdb/testsuite/gdb.hp/gdb.aCC/run.c
+2ca1a676119f0d65c39ab1b775d33f7f gdb/testsuite/gdb.hp/gdb.aCC/watch-cmd.exp
+8428aa0ac90cc1baaec1f80269b59295 gdb/testsuite/gdb.hp/gdb.base-hp/Makefile.in
+14c754799fcbf620f6a249cbc446e003 gdb/testsuite/gdb.hp/gdb.base-hp/callfwmall.c
+2920a0b8e81a481a61a045fbafda7b3a gdb/testsuite/gdb.hp/gdb.base-hp/callfwmall.exp
+87d7a6ef5b390f5fc337dbf9a98f5995 gdb/testsuite/gdb.hp/gdb.base-hp/configure
+df306fb67b5a85d536cc36ede39c7745 gdb/testsuite/gdb.hp/gdb.base-hp/configure.in
+aa06298d5aa3e73236eb27c425fa4846 gdb/testsuite/gdb.hp/gdb.base-hp/dollar.c
+f0780b29ef92663f1737944650277059 gdb/testsuite/gdb.hp/gdb.base-hp/dollar.exp
+d26b78129f6ede5217efccfb06f9d80d gdb/testsuite/gdb.hp/gdb.base-hp/genso-thresh.c
+54e77a9296dcc133c8c1e6f11ca3b9e2 gdb/testsuite/gdb.hp/gdb.base-hp/hwwatchbus.c
+37909f0c7c10bcdd0ca197885633de61 gdb/testsuite/gdb.hp/gdb.base-hp/hwwatchbus.exp
+3dea1b9bc2e3aed256501550bf68d4cb gdb/testsuite/gdb.hp/gdb.base-hp/pxdb.c
+0084fbab482e4b55f30175bdb64468c2 gdb/testsuite/gdb.hp/gdb.base-hp/pxdb.exp
+d84fd299a458e5895433ae2c3dfbee29 gdb/testsuite/gdb.hp/gdb.base-hp/reg-pa64.exp
+905458dab9cfbee0df58ed9240e14af1 gdb/testsuite/gdb.hp/gdb.base-hp/reg-pa64.s
+ee6a945ab81a974f44ac63d3d49b108f gdb/testsuite/gdb.hp/gdb.base-hp/reg.exp
+dead9d35aee1ff308fe3522dabedc3b8 gdb/testsuite/gdb.hp/gdb.base-hp/reg.s
+465f43278cc7d0e79520ac7cd4420a02 gdb/testsuite/gdb.hp/gdb.base-hp/sized-enum.c
+035b3f0d72564c9d97205c559d83de06 gdb/testsuite/gdb.hp/gdb.base-hp/sized-enum.exp
+0326797e1ef25ac281e335defb13472d gdb/testsuite/gdb.hp/gdb.base-hp/so-thresh.exp
+826cb85910a25693b5ec8940b9f17f02 gdb/testsuite/gdb.hp/gdb.base-hp/so-thresh.mk
+484344e9489d51e698048e6a91576363 gdb/testsuite/gdb.hp/gdb.base-hp/so-thresh.sh
+f3b9253b314a12126d1438b64f607792 gdb/testsuite/gdb.hp/gdb.compat/Makefile.in
+00f1943eda306eea1225aa67d0716842 gdb/testsuite/gdb.hp/gdb.compat/average.c
+e1c7bd7c6609a38b67e4a9383f5514da gdb/testsuite/gdb.hp/gdb.compat/configure
+32b5056c9568e8f49b60a03707bf148e gdb/testsuite/gdb.hp/gdb.compat/configure.in
+efdc8ddc5dba749425497347498fc5ab gdb/testsuite/gdb.hp/gdb.compat/sum.c
+fbf537e72ce89db0e107c27b0339b49b gdb/testsuite/gdb.hp/gdb.compat/xdb.c
+1d6255c634ec5650bf05e168820e52d6 gdb/testsuite/gdb.hp/gdb.compat/xdb0.c
+87882e6b6268aeb4258a5d999f17c0fe gdb/testsuite/gdb.hp/gdb.compat/xdb0.h
+943ae15521dca9cb0098128efc3b280a gdb/testsuite/gdb.hp/gdb.compat/xdb1.c
+475f987590553eed1ed25a9c11ffa17f gdb/testsuite/gdb.hp/gdb.compat/xdb1.exp
+58ce17fe6da5f73aef6ec537c2e27d06 gdb/testsuite/gdb.hp/gdb.compat/xdb2.exp
+4c9af0ec3ea90b8ed85951b36c7dbf8b gdb/testsuite/gdb.hp/gdb.compat/xdb3.exp
+9710952c98dc8eeefe0b4a1bd211af04 gdb/testsuite/gdb.hp/gdb.defects/Makefile.in
+db822d6cd121c4db2c5386f1b18327d3 gdb/testsuite/gdb.hp/gdb.defects/bs14602.c
+bd2e0786113e62b5acc6ad6291a76f34 gdb/testsuite/gdb.hp/gdb.defects/bs14602.exp
+ad5b3374f11b43b9b407e2c12b36771f gdb/testsuite/gdb.hp/gdb.defects/configure
+72ec8172adb4263d943d3b1969bd3d10 gdb/testsuite/gdb.hp/gdb.defects/configure.in
+408c16c2ba0801d824d0c16563aa93a6 gdb/testsuite/gdb.hp/gdb.defects/solib-d.c
+e15e6c68819e675e3152c4d3b89a23a3 gdb/testsuite/gdb.hp/gdb.defects/solib-d.exp
+2c0a2c964be9bd822394d4c27d94351f gdb/testsuite/gdb.hp/gdb.defects/solib-d1.c
+03f1b83c4f54667b4f0078457b15a52f gdb/testsuite/gdb.hp/gdb.defects/solib-d2.c
+fe1cbe605feca5f78a08210252dfed66 gdb/testsuite/gdb.hp/gdb.objdbg/Makefile.in
+0687fa8867c6ff62c2868ec1115ad5ba gdb/testsuite/gdb.hp/gdb.objdbg/configure
+2b002bd5777ceffd1e2efb38e131fcab gdb/testsuite/gdb.hp/gdb.objdbg/configure.in
+59089dac281ef67bda37958f7f255d2e gdb/testsuite/gdb.hp/gdb.objdbg/objdbg01.exp
+a96dbc772e2273ff024394cb9ec10b86 gdb/testsuite/gdb.hp/gdb.objdbg/objdbg02.exp
+36ee5c5a29d5f2de705b4153dfca881f gdb/testsuite/gdb.hp/gdb.objdbg/objdbg03.exp
+dc406239f235baa4ce28b3bc05b48cb3 gdb/testsuite/gdb.hp/gdb.objdbg/objdbg04.exp
+c12f8a440f9d7eab2053d5fb263d654f gdb/testsuite/gdb.hp/gdb.objdbg/objdbg01/x1.cc
+64a248fedafc6f5f792d6092a904faaa gdb/testsuite/gdb.hp/gdb.objdbg/objdbg01/x2.cc
+dfae478e1d95497e262872ee20047863 gdb/testsuite/gdb.hp/gdb.objdbg/objdbg01/x3.cc
+a9b4b350ab56451624e9364e1e2b6738 gdb/testsuite/gdb.hp/gdb.objdbg/objdbg01/x3.h
+930c3959f1e04319936c5a861682c7d6 gdb/testsuite/gdb.hp/gdb.objdbg/objdbg02/x1.cc
+afaf2237a24a13e7d47ff8dc5358bd2d gdb/testsuite/gdb.hp/gdb.objdbg/objdbg02/x2.cc
+1ac202c7c27f08ce5de62831fe6230fe gdb/testsuite/gdb.hp/gdb.objdbg/objdbg02/x3.cc
+54bba4286fdf72276ee52dba78eeb61e gdb/testsuite/gdb.hp/gdb.objdbg/objdbg03/x1.cc
+b93935b37dba86bc6c49acaae960efa9 gdb/testsuite/gdb.hp/gdb.objdbg/objdbg03/x2.cc
+ab81c17425f162902b2593b2af2965bc gdb/testsuite/gdb.hp/gdb.objdbg/objdbg03/x3.cc
+146898361af7f03a16dfcc18ace2a23f gdb/testsuite/gdb.hp/gdb.objdbg/objdbg04/x.h
+48806746c4205bdf0d050b7c3a32210b gdb/testsuite/gdb.hp/gdb.objdbg/objdbg04/x1.cc
+76af0d0b7dd89e3eb8fdd7dd10334d59 gdb/testsuite/gdb.hp/gdb.objdbg/objdbg04/x2.cc
+37540d440cd0e9f5280d7123f3f963ed gdb/testsuite/gdb.hp/gdb.objdbg/tools/symaddr
+4f3c4e1c924d553e18775df711389e81 gdb/testsuite/gdb.hp/gdb.objdbg/tools/symaddr.pa64
+d1035b543709f23158df094b6d49742b gdb/testsuite/gdb.hp/gdb.objdbg/tools/test-objdbg.cc
+8e84c7c14c0bfef46c0aa768c32904bf gdb/testsuite/gdb.hp/tools/odump
+ef06d8cfb625aa9c73eff51184bb10fd gdb/testsuite/gdb.java/Makefile.in
+f11e6514a4ff5711fe597b249918de83 gdb/testsuite/gdb.java/jmisc.exp
+e3a680cfde66129ed9607ad7c20fd6a0 gdb/testsuite/gdb.java/jmisc.java
+25196521761500b629e0156f769f9dc5 gdb/testsuite/gdb.java/jmisc1.exp
+3962ccaa018569e90a59a8afefffe140 gdb/testsuite/gdb.java/jmisc2.exp
+f3ff9a3bfd8a020b5abf078d96fa30e0 gdb/testsuite/gdb.java/jv-exp.exp
+347bfda3668dabef6efd1a0230dc328e gdb/testsuite/gdb.java/jv-print.exp
+1efe6f6402cbf322cd8aa810521f4b17 gdb/testsuite/gdb.mi/ChangeLog-1999-2003
+a137c3c02589a00e9ec245499b6da025 gdb/testsuite/gdb.mi/Makefile.in
+c81900dcf955c63e8a2bd0e32bc501bc gdb/testsuite/gdb.mi/basics.c
+06a3204e9a327785ece0a420e35301ee gdb/testsuite/gdb.mi/gdb669.exp
+cbd0dd25e371259b7e9b02fdfb5b96c0 gdb/testsuite/gdb.mi/gdb680.exp
+5a1ff3ae7b8cd72760f91dfc87b2f43f gdb/testsuite/gdb.mi/gdb701.c
+4bec8072c80b8549b6e26560b19d5f1c gdb/testsuite/gdb.mi/gdb701.exp
+a57794f9629bee4dc7f3868362e8d4ff gdb/testsuite/gdb.mi/gdb792.cc
+f4c04bf208c56622913b190d03602d05 gdb/testsuite/gdb.mi/gdb792.exp
+77408052d39d40a80029fb6361c26105 gdb/testsuite/gdb.mi/mi-basics.exp
+ec434680f02b054e6de15b2dfa12d795 gdb/testsuite/gdb.mi/mi-break.exp
+56f4bd91dcb31e9aa701ab6345931577 gdb/testsuite/gdb.mi/mi-cli.exp
+2748c57b9ccc6f5d68d793f547c07d42 gdb/testsuite/gdb.mi/mi-console.c
+852f7818afcc5b0f94160fecd71957a7 gdb/testsuite/gdb.mi/mi-console.exp
+96c005a83d0f4611ce038a86e0638ab5 gdb/testsuite/gdb.mi/mi-disassemble.exp
+712aa7331a203acdcc8a2f316ff1cc1c gdb/testsuite/gdb.mi/mi-eval.exp
+81dbb9495eb2c30cd2a251fb8fb373ea gdb/testsuite/gdb.mi/mi-file.exp
+2a6ae6e5fdb562fa2615d386ffe239cf gdb/testsuite/gdb.mi/mi-hack-cli.exp
+bcf7919688b898c368d037f79e31b0ba gdb/testsuite/gdb.mi/mi-pthreads.exp
+d842f3134dbac91b77ca50d320988178 gdb/testsuite/gdb.mi/mi-read-memory.c
+92e73d90611f698038c769534fe88756 gdb/testsuite/gdb.mi/mi-read-memory.exp
+cd5b04c7b45602e3c3f1d1b22c655b90 gdb/testsuite/gdb.mi/mi-regs.exp
+4e856f01c9c7358c981559e35ed57555 gdb/testsuite/gdb.mi/mi-return.exp
+99713d622a8ccf747d8b6a7d6eaf02dc gdb/testsuite/gdb.mi/mi-simplerun.exp
+1a56becdde5ec4456b0d1c6ca2625d83 gdb/testsuite/gdb.mi/mi-stack.exp
+3571e24dbf11aa589734d330f8e3e1f2 gdb/testsuite/gdb.mi/mi-stepi.exp
+036a2f4a4024c9519a6cc18dd84201cd gdb/testsuite/gdb.mi/mi-syn-frame.c
+c1f5684546323f39985647476425b06b gdb/testsuite/gdb.mi/mi-syn-frame.exp
+52c1978545cc7e608343ca81b191f7ee gdb/testsuite/gdb.mi/mi-until.exp
+8ccd9f4ad45dd466a138aff23ce22187 gdb/testsuite/gdb.mi/mi-var-block.exp
+08c0ef3201d4bfaf31e08b7275945cfb gdb/testsuite/gdb.mi/mi-var-child.exp
+a64100dcf41363d68f2a727742b161c2 gdb/testsuite/gdb.mi/mi-var-cmd.exp
+79fa7a2cdf3434e7cc7a34647c7db9d5 gdb/testsuite/gdb.mi/mi-var-display.exp
+2757c741ba0ab82d7761af397e886824 gdb/testsuite/gdb.mi/mi-watch.exp
+7d6e93f3fb3a635d086685aa7ed7bfed gdb/testsuite/gdb.mi/mi2-basics.exp
+556c975ba0f9b12cdade84a490152b4f gdb/testsuite/gdb.mi/mi2-break.exp
+9f5b20575bf8813fa3c535a12a5bd9fe gdb/testsuite/gdb.mi/mi2-cli.exp
+9f0b48701a920ed57300937b8ec25256 gdb/testsuite/gdb.mi/mi2-console.exp
+2d9474ff7919077f5b163b059385e024 gdb/testsuite/gdb.mi/mi2-disassemble.exp
+48ff58ff1e5b198b9e87a61cc116d2a4 gdb/testsuite/gdb.mi/mi2-eval.exp
+76201c65d9bb77d36370f31cbcf503d1 gdb/testsuite/gdb.mi/mi2-file.exp
+2fea9eb9b76679539a167ae99fa33943 gdb/testsuite/gdb.mi/mi2-hack-cli.exp
+cbd96de463e5cba623acf69215ee28ff gdb/testsuite/gdb.mi/mi2-pthreads.exp
+ba4f82681386eb04c7a18f4e342b92a7 gdb/testsuite/gdb.mi/mi2-read-memory.exp
+61e4ff81736f537347679ddf7b052dc3 gdb/testsuite/gdb.mi/mi2-regs.exp
+9d289c33a4a32e8cf56b8d6338938435 gdb/testsuite/gdb.mi/mi2-return.exp
+c4e396245f1a1c5f80db2f917157eaaf gdb/testsuite/gdb.mi/mi2-simplerun.exp
+102ae6939db2e76d36cb4e8ac4a8e970 gdb/testsuite/gdb.mi/mi2-stack.exp
+2931a5ba1e3ece574c348395f9df3f70 gdb/testsuite/gdb.mi/mi2-stepi.exp
+71ccfb19e331ff88802d693f19bdee40 gdb/testsuite/gdb.mi/mi2-syn-frame.exp
+7c12e2e2cd169a80b19f6b7aff785915 gdb/testsuite/gdb.mi/mi2-until.exp
+f302367430952abb7fd0a71768bf1616 gdb/testsuite/gdb.mi/mi2-var-block.exp
+004ef4829935b0bf597e17a509c7726f gdb/testsuite/gdb.mi/mi2-var-child.exp
+9245b5569e2ae3062474387c04443017 gdb/testsuite/gdb.mi/mi2-var-cmd.exp
+ed64bbeec9814314a73f403ad66a918a gdb/testsuite/gdb.mi/mi2-var-display.exp
+a436b3876316ee232b9ae9a81c7a9deb gdb/testsuite/gdb.mi/mi2-watch.exp
+c2611277466d0332b71fe3196fa4f29d gdb/testsuite/gdb.mi/pthreads.c
+6b58acbe5f1fe573c27b67f2e2a2fee1 gdb/testsuite/gdb.mi/testcmds
+e69d1583b75cdf649449a0263d46822f gdb/testsuite/gdb.mi/until.c
+70161b7abdf792774c9f7b64639bdb7c gdb/testsuite/gdb.mi/var-cmd.c
+2985193fddc2986e50caa3b7b1d62063 gdb/testsuite/gdb.objc/Makefile.in
+68c117a857134abb2a5d162b6fc51dba gdb/testsuite/gdb.objc/basicclass.exp
+f0f471d0b077ed32873ec23acd184ae2 gdb/testsuite/gdb.objc/basicclass.m
+33d7d3f36faecd0017296729aa6c3866 gdb/testsuite/gdb.objc/nondebug.exp
+680e14fd32f14cd93c56886bcb05f177 gdb/testsuite/gdb.objc/nondebug.m
+05660f61cb4794190fd4693435969d6c gdb/testsuite/gdb.objc/objcdecode.exp
+5bf9075727dbd558ccbf123d9e11859a gdb/testsuite/gdb.objc/objcdecode.m
+d94fa505fcba6e3a9d0a647b9e6cd938 gdb/testsuite/gdb.stabs/Makefile.in
+85d0360ff6db4270acb85d73092c7de9 gdb/testsuite/gdb.stabs/aout.sed
+3ab1b76d17414351bc1f309e05355b18 gdb/testsuite/gdb.stabs/configure
+f46c99d92567df69af2ff28e2007ce15 gdb/testsuite/gdb.stabs/configure.in
+6fb5c366d78fe2c47f31555c035ddcb3 gdb/testsuite/gdb.stabs/ecoff.sed
+c616dc41c0e3352e3100cec80c2bab68 gdb/testsuite/gdb.stabs/hppa.sed
+2fee77e25d05036cb6fa5a7b28cb6f5e gdb/testsuite/gdb.stabs/weird.def
+da50fdfe62ac5283b850b01e1bf1afed gdb/testsuite/gdb.stabs/weird.exp
+fc215bfd0d5b89f95282f2bd7f807c55 gdb/testsuite/gdb.stabs/xcoff.sed
+5673f18f6ae92e0b3a46e6be53e63362 gdb/testsuite/gdb.threads/Makefile.in
+e368d934ffec610b9e0e4206ba4807aa gdb/testsuite/gdb.threads/gcore-thread.exp
+62cf43ac0d2bba3a2043b8edbe0cf1e3 gdb/testsuite/gdb.threads/killed.c
+b9706515575fac09aec93cb0d82e9aaa gdb/testsuite/gdb.threads/killed.exp
+a60f402187882610e3160c4f6c4dd4b1 gdb/testsuite/gdb.threads/linux-dp.c
+0906f1c5c67f88b6da8d34e03cf66236 gdb/testsuite/gdb.threads/linux-dp.exp
+df82452f754ef15a81d71f46a0892757 gdb/testsuite/gdb.threads/print-threads.c
+d6bf303a6ec7a6d5be345f0d1010f239 gdb/testsuite/gdb.threads/print-threads.exp
+4ae9d1fb5da571a62fcb13bffe5655ab gdb/testsuite/gdb.threads/pthreads.c
+4006f6fc820387c2d4aa8e0c5e6cfe26 gdb/testsuite/gdb.threads/pthreads.exp
+42682b6c1fd80503e8379141c00722b6 gdb/testsuite/gdb.threads/schedlock.c
+2616f01052187aade4eb85c28d2bdf9e gdb/testsuite/gdb.threads/schedlock.exp
+6abe05b4e05fce5d6c228dd5ef8ec9cb gdb/testsuite/gdb.threads/step.c
+74a8ea51bc751ee4e098c5c5811259b7 gdb/testsuite/gdb.threads/step.exp
+9db30290e91c45e998efe6f61b9ad87e gdb/testsuite/gdb.threads/step2.exp
+e5001139f4a6104a95b0e65b8e584edb gdb/testsuite/gdb.threads/switch-threads.c
+a04ed86703e7ba05f3aaca57e5d7a2ee gdb/testsuite/gdb.threads/switch-threads.exp
+523e1ad1a3f525cff9dab02b701e03f6 gdb/testsuite/gdb.threads/thread-specific.c
+c682c53ad502826e407f202a37108138 gdb/testsuite/gdb.threads/thread-specific.exp
+0bc37c048361582d53f69d0700501c98 gdb/testsuite/gdb.threads/tls-main.c
+ca92dcd6537aed1d73f8b67fdf1f766a gdb/testsuite/gdb.threads/tls-shared.c
+d0550fb0da424270aaf5a35874d6a0f1 gdb/testsuite/gdb.threads/tls-shared.exp
+c6fe7b489cd5c7c6944dbe27afdb0e3f gdb/testsuite/gdb.threads/tls.c
+4ee6d4e534226e30e79d49cc5b98a249 gdb/testsuite/gdb.threads/tls.exp
+980f2448cee4484a705fe6a0d292d777 gdb/testsuite/gdb.trace/Makefile.in
+51f9a67e86dd3beecb45253c1322782a gdb/testsuite/gdb.trace/actions.c
+d6b1c686a9f1affc3995fb37cadbb21c gdb/testsuite/gdb.trace/actions.exp
+be14eba4fcaf5b2adc86074a2fba07e9 gdb/testsuite/gdb.trace/backtrace.exp
+d2edd9bfb6b15369a5e3296908d0bf6d gdb/testsuite/gdb.trace/circ.c
+6ba6686c599d810255f3045d7e889e91 gdb/testsuite/gdb.trace/circ.exp
+d22f8c48119d0a899e1e9d6e80f9c016 gdb/testsuite/gdb.trace/collection.c
+90b9a6132a75b43999bbb3a72670f01f gdb/testsuite/gdb.trace/collection.exp
+e289b698f3ff0299d714d1f9dc5a97b1 gdb/testsuite/gdb.trace/deltrace.exp
+b5d2f0e0b4205415517bca254223e8c0 gdb/testsuite/gdb.trace/gdb_c_test.c
+219ee52b956a9bfc0796d0236f578f50 gdb/testsuite/gdb.trace/infotrace.exp
+08512b1543a9be7aff8ac4bb4b0eaf6e gdb/testsuite/gdb.trace/limits.c
+2c15d2c24592ef674906e4dae03c7211 gdb/testsuite/gdb.trace/limits.exp
+9a86b5f4bc513a6e347dac4050523658 gdb/testsuite/gdb.trace/packetlen.exp
+086b67368f3861038df756c0646788ae gdb/testsuite/gdb.trace/passc-dyn.exp
+bc02e63137ee16c4706228cc8041f0e5 gdb/testsuite/gdb.trace/passcount.exp
+4b39b9f9a1d575dcc4d2a84a004746bd gdb/testsuite/gdb.trace/report.exp
+b24a4b63fe84f3a2a49357b6a9db0012 gdb/testsuite/gdb.trace/save-trace.exp
+d8869924fc4b2f20fe8b862603bb9324 gdb/testsuite/gdb.trace/tfind.exp
+3f5a164c595f07a01b59515a9669bd97 gdb/testsuite/gdb.trace/tracecmd.exp
+bd89b16a83a5835733d7054ec428bccd gdb/testsuite/gdb.trace/while-dyn.exp
+5b5cada24d1f1b388c3c70955c7c4d53 gdb/testsuite/gdb.trace/while-stepping.exp
+228dd88b0d4a83af3f8e89bb5224dc06 gdb/testsuite/lib/compiler.c
+7af2d03dab4c1afb5a5d5c9524b0c81d gdb/testsuite/lib/compiler.cc
+48a27665f33817b43a3452988f80966a gdb/testsuite/lib/emc-support.exp
+2867e813c29fe0094df46509b194f656 gdb/testsuite/lib/gdb.exp
+c404eb2e7dac9c1d08051c678300e501 gdb/testsuite/lib/insight-support.exp
+9b7a395721eee00a67d7ed09371fdb34 gdb/testsuite/lib/java.exp
+de0bd70b647f1a2d1ce4d1671e2b10ed gdb/testsuite/lib/mi-support.exp
+c68e4af9b47de335364e755bc9ad7337 gdb/testsuite/lib/trace-support.exp
+0415f3bd7a379430b752618c1e8c7cd4 gdb/tui/ChangeLog-1998-2003
+33164e75763e98ce19ec50c53a214b2a gdb/tui/tui-command.c
+c895c5ecb33340f6b4327df90613829c gdb/tui/tui-command.h
+b1b03124191dc7ec448a8fa1d362fd7f gdb/tui/tui-data.c
+c6de1cc41c5181233532ecad458678e5 gdb/tui/tui-data.h
+2853d84f15cf9726363093f05f9caa8a gdb/tui/tui-disasm.c
+cfe5137e8a2d365a1d50c372c914478b gdb/tui/tui-disasm.h
+31025216449a525a1cc205bdb2bbb2dd gdb/tui/tui-file.c
+22ae3985088c25f460e7e0b3a9fdedc4 gdb/tui/tui-file.h
+654a7a63d0f1a106a498742ceae9b416 gdb/tui/tui-hooks.c
+c8555bcaf6af93bfb94f8c6c14692363 gdb/tui/tui-hooks.h
+5871593d222a13b84ce35b2ac2c74c6d gdb/tui/tui-interp.c
+6e8fdafeccc72d861a7cbdb5876b99e3 gdb/tui/tui-io.c
+3e6ef3e1d320d67eb4a5fbcb41226ce7 gdb/tui/tui-io.h
+8a9ee4b0eee3bb5f3ec06464c1546e2a gdb/tui/tui-layout.c
+21bdbaab291d83f70a58c5c3054b0537 gdb/tui/tui-layout.h
+182a975ab02a3f6d615c6b59806ba9e0 gdb/tui/tui-main.c
+f220a48f82394af2c19d90ae46df6c95 gdb/tui/tui-out.c
+a87f4748cf7971f7029fb85eb32a9c1c gdb/tui/tui-regs.c
+8566417a39c291e1ee287701a3f6a28b gdb/tui/tui-regs.h
+2a124218fe08bbb8f7ea024b06d4f036 gdb/tui/tui-source.c
+c74464f9d78164df8b31f84480f3d412 gdb/tui/tui-source.h
+f2da2056bff10dd8d7b21030b06d6d01 gdb/tui/tui-stack.c
+75b39320dd19763fc136733339605bc9 gdb/tui/tui-stack.h
+0e9d34efa3814982356122203022c090 gdb/tui/tui-win.c
+6bcd65d9971eac6523419e13af86707c gdb/tui/tui-win.h
+55b1b6921d777475fd178d858eded301 gdb/tui/tui-windata.c
+91cf7f5cf2e3f0974c7a1676944f9a9d gdb/tui/tui-windata.h
+b35567d277f1a6334bfb7a70332f3294 gdb/tui/tui-wingeneral.c
+11cf633a46f11e5200c90b080de0ddb7 gdb/tui/tui-wingeneral.h
+cdc2383e271638a41c2b177622e09fdb gdb/tui/tui-winsource.c
+b336fdabe8d77ee65d35cee75beaaf3d gdb/tui/tui-winsource.h
+0953404ddeab24f2a3ba8e24c8ac434b gdb/tui/tui.c
+9f7875316406233dad7401c23363f3de gdb/tui/tui.h
+6fb3c8019cfba5916d9451ab06a8ce3b gdb/vx-share/README
+b103381c5207f96ea87a5a8eb4a86b6a gdb/vx-share/dbgRpcLib.h
+136aa1c8da429aabbfc60353f4407850 gdb/vx-share/ptrace.h
+22567ed471f25a4eccfc1987fb09650f gdb/vx-share/regPacket.h
+a1429e76f00e6b2a44c6c65257783f1d gdb/vx-share/vxTypes.h
+5a7cd744d3a88136d6ca0a21a7954fbd gdb/vx-share/vxWorks.h
+b9e04209ee5ce063aa0dc52778977eb7 gdb/vx-share/wait.h
+5e8c8957908c763889c0133d55a9bedd gdb/vx-share/xdr_ld.c
+ef74612dedfb30f22c2d42c602197bec gdb/vx-share/xdr_ld.h
+117e45abd2330f80c34a5fed2e5e11e4 gdb/vx-share/xdr_ptrace.c
+a93ad05f8f19913070dfc6a46c065603 gdb/vx-share/xdr_ptrace.h
+3b7388f0ba4c77c764a1d4148850efb5 gdb/vx-share/xdr_rdb.c
+68de29665f0b21324a6d6c073e445cfb gdb/vx-share/xdr_rdb.h
+a764dcca06e1e38dff79defb0f47b8a7 gdb/objc-exp.c
+d0882635bcbba0d196dcb721ac2e3f46 gdb/c-exp.c
+2d447ab9a8413958fc768810872c60be gdb/ada-exp.c
+cf0faf4a37b21cb2ea0c7c6fb3d624a1 gdb/jv-exp.c
+d1ef9e69ab23e83ed06df42b43c1e115 gdb/f-exp.c
+19904fe1e3faf83dc2e81a83a4062123 gdb/m2-exp.c
+6e6ef60dc77aaf89003328ef3759311b gdb/p-exp.c
+451fdc157675a8b7f45de000dc2a6d9c gettext.m4
+94d55d512a9ba36caa9b7df079bae19f include/COPYING
+fc1d396ce6abdce8b11f714f0ed603c0 include/ChangeLog
+cf08dfc74c6c5dae7b71eb29911c9004 include/ChangeLog-9103
+d618facc3e8ce8bf3d02ba452e1be6ab include/MAINTAINERS
+de46742edca3a9276eefa5ae8fdee5eb include/alloca-conf.h
+da3682afe5be61c3172bb494398e3b0b include/ansidecl.h
+ff45b5560b5b688bc4b6a28ed090df6d include/bfdlink.h
+e4247635fdf4b4f00f70e8d0fb756cf7 include/bin-bugs.h
+ad23b2f356f60d58833e2256d1601732 include/bout.h
+4f78f9a43bf4555a52c77ed7e95cdefb include/demangle.h
+adb83f5cdc6f751d68b7c9840239392f include/dis-asm.h
+78226edd4be1ddcf9c8e57dae850d449 include/dyn-string.h
+4f0d30283cfd45ddbecfd97a84ad1fc4 include/fibheap.h
+9bd376fdc680c4801bb7e676aa80b2eb include/filenames.h
+41e02028fea8e2eadd52a90caf0376e3 include/floatformat.h
+d54eb7868908574db9965575a16c1819 include/fnmatch.h
+b2cd17a9267bc2e92df461d3170cb15c include/fopen-bin.h
+87444b5c85b3c2bc734f8b86157b15db include/fopen-same.h
+2f3ef0265ac665d61a8721a78c47a79f include/fopen-vms.h
+7b08d623511997558fcc99b0df47efc5 include/gdbm.h
+317b3fc837139b901dfba9292e3576ca include/getopt.h
+89612909a51e056f5b5500c7f83965a4 include/hashtab.h
+06a970d566cdd88ab8bf3ae1fec0cc3b include/hp-symtab.h
+4140d269a4d719013db3beba8f684572 include/ieee.h
+1281513e4c64c4cbaaab169b86dc7a1e include/libiberty.h
+e1b9929975775d9831fb9d726e48230e include/md5.h
+07de9606e88a074c745d5bbcd835c1e2 include/oasys.h
+c14e4868200f00ec814858d3f2e6f824 include/objalloc.h
+8f2b67fd9a1670669af5e5e07959d797 include/obstack.h
+82709f401badc29ca812065155ff60b9 include/os9k.h
+b2ec49c538bbc288540fe1fc2bb7517b include/partition.h
+d011632065e457c8589b28d0c53e5b04 include/progress.h
+2ccf4ca81f396940231fdd26144b9fc2 include/safe-ctype.h
+1309f7f8ff9241b427948c8c5761b316 include/sort.h
+1f39db48d112270c02ce3e01fbfad9cd include/splay-tree.h
+4ebaa58a8bcb2ad62a520447123446ed include/symcat.h
+c38b82bb82381011919906bfc101a973 include/ternary.h
+9e4da3ee24c6f11a47fa7d5cae9a03d0 include/xregex.h
+17eeca2dc8ed2db2505c4aa25bb83cd2 include/xregex2.h
+8b2a2337ea32f559beb243b328db15bc include/xtensa-config.h
+dd1c74e990a977be8981e116567cc824 include/xtensa-isa-internal.h
+b7bdd848ff92c3a8c9f57ab5d923bf30 include/xtensa-isa.h
+7b17708b703cedb9015e8e101137d01b include/aout/ChangeLog
+cc18d2a17ec338312f00622e1fa4692e include/aout/adobe.h
+9efa5517827efca80a9df8a4d20290a0 include/aout/aout64.h
+c6b08000298f64bb35885212da785e44 include/aout/ar.h
+4e9021e94bceaee219b2319759ebe6ba include/aout/dynix3.h
+64818c4cc3aab586e47bc9daa57ed4e2 include/aout/encap.h
+d56e5b7b7841033c99960c96365579c4 include/aout/host.h
+5d9fed058c072b61553cf62174a8e37e include/aout/hp.h
+14c5f23e05dc2b318cd39ac37f3802b7 include/aout/hp300hpux.h
+d82993bf02befd5682dcd44b076ad991 include/aout/hppa.h
+e91c2c24d9be7b5cbfa6047d799cb850 include/aout/ranlib.h
+d06f0176a5098d444f22d53fabc7c2e8 include/aout/reloc.h
+94b2d0db8050c1856a7a9448fd0a56bf include/aout/stab.def
+4fc8401a176b5d472bc2a60e1a0917ab include/aout/stab_gnu.h
+f76759c6246b1e8376e84e0c1d8ef6bc include/aout/sun4.h
+dc0a382a0c88ec81e2fcc3056387d25f include/coff/ChangeLog
+aeb19b6b14f3013e3bf886497586467d include/coff/ChangeLog-9103
+d6fed07c9bd210c51bbc4099ab6417a7 include/coff/a29k.h
+2527181fe68f2013f34bf5cd5917010f include/coff/alpha.h
+bd146d9c208a7b158112321b5cbcb37b include/coff/apollo.h
+90db700a7b6d1376d77c4477e65f604b include/coff/arm.h
+7b2f28b2e4bf9e88bb4a23a3e96e99f6 include/coff/aux-coff.h
+661a9f48cd8853a200d2b67027f9017f include/coff/ecoff.h
+40bf593c55da6810ccbe70fe53577da8 include/coff/external.h
+279bf7cff0288c326b23cafe1acd246f include/coff/go32exe.h
+6deb9e4ece7f61956307de311543cb5b include/coff/h8300.h
+659ebc0e56c5a7723608b56d826e9f49 include/coff/h8500.h
+729f65ea2c44514f59784a9d7ebeb7d3 include/coff/i386.h
+6bd9a0f12754e08b8719c7f6330fa3b9 include/coff/i860.h
+b20325efd24ad29bb13270c0601b6b8b include/coff/i960.h
+c26d4bce0e1a267a01f69162422a0df4 include/coff/ia64.h
+f2d49e0cbd8faddd8e00a60f207016c1 include/coff/internal.h
+a8f58d50b044d0ca3e3cd06677e9bbfb include/coff/m68k.h
+52feae66378c59252549b75ffca1bd84 include/coff/m88k.h
+a497f439d8cd07f952caa06c218a4015 include/coff/mcore.h
+b9c3382114eeb141d78c0c66e50b3f8f include/coff/mips.h
+976edb82f140c4195fc2a811d7ffa7e7 include/coff/mipspe.h
+15637f35eba702f98283910b46aab6a7 include/coff/or32.h
+ebd1a6cd8ed192b0b3339204ef13e4d0 include/coff/pe.h
+7b9f9f5e2557d5f6893af18c00282be4 include/coff/powerpc.h
+64baf4a1cc4991a74414804987eca7fc include/coff/rs6000.h
+48c3bd2c08c09ea66fe0634dc45f7e51 include/coff/rs6k64.h
+51af50b83a45484d395f7fefc0f38e9b include/coff/sh.h
+89fa4862f3ed5af9e9cc4aeefdcd2bb2 include/coff/sparc.h
+49952fda1e759e5aa659f8f78d7e0ba0 include/coff/sym.h
+ac2f6431d01bacf541ecc3e5e8dc5499 include/coff/symconst.h
+f2c42cc8e4fb7ffa80e9647bfd555429 include/coff/ti.h
+b1c8e1630078781f716118e0428af9f3 include/coff/tic30.h
+aac23a54bfc7f1bf13b5aef5d032370f include/coff/tic4x.h
+92858e2331c34bba807c9df1080131f2 include/coff/tic54x.h
+e2e2417f52b6795a4ba92f192eab08f6 include/coff/tic80.h
+8b0324921a2b8a75557c3af66d55305e include/coff/w65.h
+12d77371aa5d25ee7004870805fcb42a include/coff/we32k.h
+f9ff028d1f9a20ce7a7247f21dde1763 include/coff/xcoff.h
+544939a6c1433a4ab78ec38d8c495b95 include/coff/z8k.h
+d5177ac59efda29d334e6721a8e2ca4f include/elf/ChangeLog
+72bf3f83cf27514f0af979203dea6a0c include/elf/ChangeLog-9103
+ca6ae2abf939f3388c6feb2e2ae8ecd6 include/elf/alpha.h
+3bf4ae3474c9c4b8310da4a84aec1dca include/elf/arc.h
+fe9b3c5bfe9640c29127aecf95b47aba include/elf/arm.h
+58a80a77bf1669d85ca0d6095e6e85b4 include/elf/avr.h
+49400f7cefc05b3501c511d6bf078bb5 include/elf/common.h
+42ae390b9bf0b8fed1b40894d288c83a include/elf/cris.h
+f65a19cb8f5a2d53a4c0f71c90bef0e7 include/elf/d10v.h
+e1bbf4eba14b2efe2dd202e9a7038bd1 include/elf/d30v.h
+25823df33f36b14970f1e5365e096875 include/elf/dlx.h
+d350084ff96d123c4ee539745ed1ef2c include/elf/dwarf.h
+260b3f28bbda73b5024f96380af27c3a include/elf/dwarf2.h
+08f953e3e1b593c0578e99d791fb00a5 include/elf/external.h
+2adb44173bb9ba06c13aef464c4701a3 include/elf/fr30.h
+9606b89c1b90c6f32f90bc613602fcd6 include/elf/frv.h
+d62b2d0835fb0fa61f2c6b1279c8f354 include/elf/h8.h
+0899399867f5ede8459434cb58862e61 include/elf/hppa.h
+13e1b1a6be5461690bf6c8f65f27ea22 include/elf/i370.h
+311051280ab6de581d85256e3094ecbf include/elf/i386.h
+6e10443e0f1746964a6cc3fa883215b5 include/elf/i860.h
+4f6c7e8248b9ec284b181a55ff15a17a include/elf/i960.h
+229ad1fa29c4dab924b2f695bba0e864 include/elf/ia64.h
+1a027e232b7e27c8657bfc80361f92f1 include/elf/internal.h
+9742f5458075b7e744b4a9e8ee85a045 include/elf/ip2k.h
+cff6c8729fc7fb0e6e935d8b147b7019 include/elf/iq2000.h
+28b9e559fee32e782b47f39b7e0811a1 include/elf/m32r.h
+152a9c6807959dd25416a2e836006146 include/elf/m68hc11.h
+2127fa4130f4d87a62ed8a1ca82a5171 include/elf/m68k.h
+97ed3477e1b76ff78e6ae3c361506869 include/elf/mcore.h
+abc5acfc5223ece263d32d7ba3b7cf51 include/elf/mips.h
+5881ca2cc0cf6477915716a23c77547b include/elf/mmix.h
+9090a0078b91916eb138a6e96ba1ffab include/elf/mn10200.h
+fe7269fcd0eba251971fbd8f2cbfbb31 include/elf/mn10300.h
+1e8e3b4a20f588db47020029fb01b4f7 include/elf/msp430.h
+bdb6f615e4b56350793dd72e1c7a700c include/elf/openrisc.h
+70eca76b4db6529396e00c375a015bc6 include/elf/or32.h
+f9cffe9859496c157656bbd3a7b7459f include/elf/pj.h
+d448696d53209fda6c9677a0da9f3969 include/elf/ppc.h
+6e05fc6e514274913cf1a89172449e1d include/elf/ppc64.h
+cdf5f2196245bc18733cb60fd2a59db3 include/elf/reloc-macros.h
+b46937d0253d1e91077686d38a7ca343 include/elf/s390.h
+8b4ff2285d6678ba0ef059968ba81a55 include/elf/sh.h
+77d6c2fbc2ffd2750986956a68c692c8 include/elf/sparc.h
+88bbfabfd790d23969e1a9fab3e90434 include/elf/v850.h
+b73d0fb8d195b30eed9e4286a9f957c8 include/elf/vax.h
+d7e7ca630e8e306efa53d1de635f4a0d include/elf/x86-64.h
+005e2cb5d90ce0496f2fa771216baac3 include/elf/xstormy16.h
+3e52ee57589ca3f84d7004a0933930f0 include/elf/xtensa.h
+e4a78c6f386502bb68a0f40029f56e93 include/gdb/ChangeLog
+4228e8b39bcd17b9df14efc85adf2d28 include/gdb/callback.h
+4d601d2080199f02e64fc007082954d0 include/gdb/fileio.h
+f82f523d8986bd2629735dc0168d23ac include/gdb/remote-sim.h
+cffa1864cac9a521d4e676cbfccaec68 include/gdb/signals.h
+ce7a140e30b81d1a5ec659db7c1174a8 include/gdb/sim-arm.h
+d20f0550570881a6fe50970fa97c59ef include/gdb/sim-d10v.h
+c921d95bb01b346a3eb54ca76d013286 include/gdb/sim-frv.h
+afea2e92f0da83e7b29f93cd2d28c2ca include/gdb/sim-h8300.h
+0f3d45abefe6dfda74990fc579a50889 include/gdb/sim-sh.h
+f455b31f23d018ab96236c2010c67991 include/mpw/ChangeLog
+ac05e56eb8acd390d0fa557abc21380d include/mpw/README
+d1c1f4e66376b9ef2e8d4c79446503ba include/mpw/dir.h
+c293cf9a745465e2371edda6e3f700d5 include/mpw/dirent.h
+fd0c0ec6483a6ac794cfe370f323c8e7 include/mpw/fcntl.h
+211595cb825444acd3656a8172a3261c include/mpw/grp.h
+7a2ba7b6e2b168f335e8d53b1003ab24 include/mpw/mpw.h
+32f1e7dc45c3a15418ec5e0998f1f8f3 include/mpw/pwd.h
+55d48ac5e6e6ef01dcad00aeb8b33831 include/mpw/spin.h
+043c8982bc0ff4fd987727abd7341aa9 include/mpw/stat.h
+94cd8a35a9f625ee6a4d19ef2a481042 include/mpw/utime.h
+30ab289a4d9376ba8ec961019e3c291c include/mpw/varargs.h
+6bc56500657f8c3b71b20af4c69e967f include/mpw/sys/file.h
+6bc56500657f8c3b71b20af4c69e967f include/mpw/sys/param.h
+5dbb507e309b9fe20c45d16972bfb936 include/mpw/sys/resource.h
+745d20e08d92b71d289da383e8a47168 include/mpw/sys/stat.h
+99098422e0de596f6a2e552220346da7 include/mpw/sys/time.h
+009a0ee881c63ae879dd80dde06daca5 include/mpw/sys/types.h
+415adee302eb3a50089ad31b5f2d2350 include/nlm/ChangeLog
+ee9fe4c84a50cb6d303eb3848fbd6eba include/nlm/alpha-ext.h
+31b2a480636af2ac2923c5f9e52b2f58 include/nlm/common.h
+3c99c8ba8f85e2cb10829f35e3223113 include/nlm/external.h
+119b651e264af67466b26517fa1ab516 include/nlm/i386-ext.h
+b91fb4ecfdaf34a4c7f05f104c3b52a1 include/nlm/internal.h
+5446642ff3b9fee027d46b00a0cd9383 include/nlm/ppc-ext.h
+12311cd52e4c3cbb45b2f8eb775cc8c4 include/nlm/sparc32-ext.h
+71f18763112e99c043a35a66f65708b1 include/opcode/ChangeLog
+bfbbfdedaac9b97ae578e51ab45a88db include/opcode/ChangeLog-9103
+47825a7cede13679fa6b9c1e281c015d include/opcode/a29k.h
+bbc69c6b56a5cabe2ac8ac814406d723 include/opcode/alpha.h
+7fe28d35743fd6eecf215e993561097a include/opcode/arc.h
+f51724681cb616b8ddaa4ed0aacb67fb include/opcode/arm.h
+4eb7ff859daa08912603fe2cdabfcbdd include/opcode/avr.h
+36fa6c54a37fe1436f5fdcb2c4e2ce28 include/opcode/cgen.h
+2011e5c005224d59c8eedb55c9d4a1d6 include/opcode/convex.h
+2ab1377cac8f960c0bfe679724dea9cc include/opcode/cris.h
+fa6f810163a259a07a94af3d8be00aa8 include/opcode/d10v.h
+a22eb3dad69e7172716aeac99a842537 include/opcode/d30v.h
+97cbeaf0b5fbd006d7ad1444357e8b5f include/opcode/dlx.h
+eaf1c4ac7ea402073dd0c52d1d6b46fb include/opcode/h8300.h
+8f048cd74eaff64156bf9b282e5bce45 include/opcode/hppa.h
+982d6352a8e2b72e658ac3c7be99690a include/opcode/i370.h
+83e754a8c45c8607ece9c9e63cb33d15 include/opcode/i386.h
+ee665444799a6485e0c8142257f7a7fa include/opcode/i860.h
+10654d7ed7402428c40546e33e5f147c include/opcode/i960.h
+17a624409de6e3d092e10c80c8f81925 include/opcode/ia64.h
+11a62929e192383c726ca7c031e044f3 include/opcode/m68hc11.h
+817465d768dd9380765163937b6ce94c include/opcode/m68k.h
+e8f007ed9927cfc27a2b5c42a57d3654 include/opcode/m88k.h
+b8fedc4a383675a905885935a3f6f4b6 include/opcode/mips.h
+5956bcaea67ac09c5f7edf0fe073796a include/opcode/mmix.h
+43e315bf6f41c74ceeb8422191c76ffb include/opcode/mn10200.h
+9190d2f1c6e5c5ac2a78a0540de7e00e include/opcode/mn10300.h
+66ab73f02620a3f0c2e9717c9883da6e include/opcode/msp430.h
+f08f60834808b211b5ea9531e53bfd49 include/opcode/np1.h
+b42886284f9b9a3794fc43fc272bade9 include/opcode/ns32k.h
+a3a09fa7011eda950100d7a7920557ed include/opcode/or32.h
+032d2c766087c96dab75773d6f9b9bb4 include/opcode/pdp11.h
+283d8af92c87a4bf79b2d1d0a5d47354 include/opcode/pj.h
+10a57ede0f7fe1825b0412223edf5852 include/opcode/pn.h
+1c5a34568a3da98870404a5b0ac5b9ab include/opcode/ppc.h
+57b6865994b962b82214d3e543408f2a include/opcode/pyr.h
+44a441c4d2850e0ac0bcd26ab4cb5d9d include/opcode/s390.h
+17e20112947bc48d98e321d4a6069a2d include/opcode/sparc.h
+c69e19287023c929ac20ee5311acfadc include/opcode/tahoe.h
+2b0f365ad336acad633a116537cfd018 include/opcode/tic30.h
+2e5f5a11bdf9c436a555d32b21133a75 include/opcode/tic4x.h
+7e33091a38654fda36432484a44ac7ae include/opcode/tic54x.h
+5b1b9204fac57d73fcb344f2132ee4c5 include/opcode/tic80.h
+3e7e117bdef389bf929e60c6d4207575 include/opcode/v850.h
+e78acf38376a53ce9ac029cdd1c4d560 include/opcode/vax.h
+b32850c3f4cb16b8c66054700970e3a1 install-sh
+8e1f8d191230cc972e09c01686be8d84 intl/ChangeLog
+e824af0ffcae539e52cac31fa3faf1d5 intl/Makefile.in
+ee2ff1244c36ed348643bd1a51001f4f intl/acconfig.h
+6e16646448de7fab92862eefbdcca179 intl/aclocal.m4
+0d0f701f3de2b7d66164cd9dfc174378 intl/bindtextdom.c
+caa3581b00edb0a7d3811a24a3e46c5c intl/cat-compat.c
+bd51dd1c7684c9f15ee4532bfd7bf12f intl/config.in
+2f9be0885ee6447a29fd0550b52c40aa intl/configure
+eb4685d54a1e3da00cab275a5c3fa6c4 intl/configure.in
+cc8f13a4eca50e459ace9fc8dd63febc intl/dcgettext.c
+4ef4d731f96a4c2a4901fa03a97abc60 intl/dgettext.c
+930994e607ac485929753d7caddcb584 intl/explodename.c
+a3604c7c8eb409eb8e9e385096fa099b intl/finddomain.c
+07fdb4d82208430fdcf4e9c57799b742 intl/gettext.c
+c46b419b2ebd68930fcb8491fae2bd32 intl/gettext.h
+2fcb82a7def25bcd2549a394af4cc67d intl/gettextP.h
+b23eb0ee50448b24ec0b942ff382da10 intl/hash-string.h
+93e4ab4b2eba5d2b8a36e1b2380190c5 intl/intl-compat.c
+9e20aa13562136f3fe776fa4ca4485bd intl/intlh.inst.in
+dca9627004c526250d47351899faf37f intl/l10nflist.c
+cbb38948ae7c116ea7aa981874709e73 intl/libgettext.h
+95e38eda6d7e093606d0b73882ddeab4 intl/libintl.glibc
+2fe6232fce14414b9404aa5d62edb61a intl/linux-msg.sed
+eea45725e2601ab7dd122a20871ecf76 intl/loadinfo.h
+2cb45953ee0685f05d4eecf3e5decaec intl/loadmsgcat.c
+432350d759a37ec39245d656d83e27cc intl/localealias.c
+606344532ffc07b36812c0d04acb1f38 intl/po2tbl.sed.in
+9f197f8e4cafdfa82382882bbe04694f intl/textdomain.c
+8d9eedf2444a5fd2a47985f2531e9051 intl/xopen-msg.sed
+7fbc338309ac38fefcd64b04bb903e34 libiberty/COPYING.LIB
+7e107e59465175c57520ece758d226e8 libiberty/ChangeLog
+9a00e551ab980f5d7378135d05b8ada4 libiberty/Makefile.in
+294191545dc71f5ad13229b0a5bfd7b1 libiberty/README
+5b535b62413b3770aeca6d516e0d6325 libiberty/_doprnt.c
+20df91b8434474ebfb22c599f0f9d0e4 libiberty/acconfig.h
+7205cd3b640330a0caee1bb3d7a7076a libiberty/aclocal.m4
+e9ff099df53462f7df5a268e290f39c2 libiberty/alloca.c
+d105d43b25b5a5967d6bdbd3896f3666 libiberty/argv.c
+d7dc1f8a85ce158eb03a1caa6dc4544f libiberty/asprintf.c
+7f287b3ca15a90be56f7c3a16c173765 libiberty/atexit.c
+4c66c13dfbbbb1d40d3df3e372faecc8 libiberty/basename.c
+cbdf255d69208be101da878ed2a52d26 libiberty/bcmp.c
+cdc3e09fe5ca8e250ef3ab38d77e63fa libiberty/bcopy.c
+d09d6a99ec0ae4b43b4f9bd38a65fecf libiberty/bsearch.c
+440895d178199c0a1ce1562d7b19cce3 libiberty/bzero.c
+99712b511be511b380f9561e8f94f251 libiberty/calloc.c
+564e36eb3ffdf2492724309477bdba44 libiberty/choose-temp.c
+7af729f41caa18c07461d9894a4e2a28 libiberty/clock.c
+db12eb172b1675b0ebbff211b9834735 libiberty/concat.c
+fdaf5fdc2a84ff34103604588aea1a3b libiberty/config.h-vms
+f03c6febc565b8c67d88e49a6f2c0ba0 libiberty/config.in
+556411b44a957219c953a1a61e522b78 libiberty/config.table
+a72097c93e1bde1483c8c1c23f0b933f libiberty/configure
+cc4bbe63d9fe28b258cf0cf5c00c8a57 libiberty/configure.ac
+373c5062b80c1f8c030fcefd5bdc9e6c libiberty/copying-lib.texi
+e3dc621adfe4ff6730b6510641537ea4 libiberty/copysign.c
+9f2aa8adef0de529dee3c73d55672ff9 libiberty/cp-demangle.c
+44cbb9761eb3195ec34ee8e521a9325e libiberty/cp-demangle.h
+710711092973e0580e43a93f57d9474e libiberty/cp-demint.c
+6d82f8ac3f2b14d73b18aed0b9397a44 libiberty/cplus-dem.c
+069562b9bb3712513c7a0b017a12f271 libiberty/dyn-string.c
+846c5e5797cff2d03945fdc045c06cd5 libiberty/fdmatch.c
+880a3787b2519407b6b6b6138b627c91 libiberty/ffs.c
+b1ab4811c02803a3d2ed8bf611d44632 libiberty/fibheap.c
+68e7c391a5deb0d1ce33c1832d0567b7 libiberty/floatformat.c
+5a0e7522053fc29b178bcd5ee644aaee libiberty/fnmatch.c
+30a2550d37938d1e3354632161ac1d0b libiberty/fnmatch.txh
+59a3ec37b6a43d649970c642e3175ebc libiberty/functions.texi
+372093196abf4e95605e71908a6b1a41 libiberty/gather-docs
+81053feb399b85f027c34d3f81f803c2 libiberty/getcwd.c
+90ab3f8e537a4a950cb6e33224995e3c libiberty/getopt.c
+5fd11388f488b53ec69eeb3e71161636 libiberty/getopt1.c
+8ff0eec816410579eaba5f8a7d344d16 libiberty/getpagesize.c
+163b78dbb9c54e4309a6e6ad8b75f365 libiberty/getpwd.c
+6b1a3bf9f11deb195411cb3a81367aeb libiberty/getruntime.c
+1d3400b0979bb6e7ba417586215cd48e libiberty/hashtab.c
+b53ab3a588f4bd737eb5dba2b0dbc024 libiberty/hex.c
+5d62866e7afd8f107daa8b78e25ffe6f libiberty/index.c
+6ed63c8ebf03f39587c4e94168c397e1 libiberty/insque.c
+8095916864bd273f9aa6a8ad82835c3e libiberty/lbasename.c
+1046e8b23172200b3f1080ba378f3bc8 libiberty/libiberty.texi
+894ba8399cde70ceb8ce529ca7298f3a libiberty/lrealpath.c
+0fd9f0b3e810378c0119bb0bbfa71418 libiberty/maint-tool
+6fc79a46ae7d6d544a8532ad8a240b08 libiberty/make-relative-prefix.c
+9d92e1eb73e143f9929e5dd2f206c380 libiberty/make-temp-file.c
+e331b31ce1cbf27a44f2fbeb54fa7b17 libiberty/makefile.vms
+f4dfb207df40e10bd11308e0ce3ce6a2 libiberty/md5.c
+779184f152031d9e89e7a2a9a391d0c2 libiberty/memchr.c
+cdbdeda3aa5ead4a36801fadc3f146a8 libiberty/memcmp.c
+24195385014105e131223c01a804f443 libiberty/memcpy.c
+397993b1bae5f3599d20edfa9a83526d libiberty/memmove.c
+b175cc1b085dffa46a41dbe21686ef15 libiberty/mempcpy.c
+80908dce1ac75994099637449014ef87 libiberty/memset.c
+69914c75c045b40f4c6b0fd0055f3773 libiberty/mkstemps.c
+969668698375a7ecf08bc086b9613a31 libiberty/mpw-config.in
+54c65d1bafd7d8d29b9d29761d977020 libiberty/mpw-make.sed
+9de6f56befd6350286f5a42836a8433a libiberty/mpw.c
+7897e43bedd2def4beb6eb73003efa68 libiberty/msdos.c
+9fbb504341d8982f9439a168b9ef825e libiberty/objalloc.c
+0b098dc2e9bb206f6c642981a8306c60 libiberty/obstack.c
+051d336f4d87cf832d5adf343a10cbe0 libiberty/obstacks.texi
+087f5237d8b7fff69418811efec227e6 libiberty/partition.c
+71ca94bfbf061da54968ac1e57b3b92e libiberty/pex-common.h
+316a7c2d1f782c47f715dde7eaa48faf libiberty/pex-djgpp.c
+5949dc1e0a5865570a8c462f794bc88c libiberty/pex-mpw.c
+9016bdcbb5f2f04001165c88178c0c05 libiberty/pex-msdos.c
+dfc59121719c673229b4d57fa6102e7d libiberty/pex-os2.c
+61f42ec64c70d61c15baf9cbd418f1b6 libiberty/pex-unix.c
+ad9b2b17ade58908793f6296ccc60312 libiberty/pex-win32.c
+f45d0f6037219afd14080d7ddd7199f0 libiberty/pexecute.txh
+063fdcd29dc11c6e1b9fa27573075f06 libiberty/physmem.c
+5925c1d64a6e31ffabbe2fd74d65960b libiberty/putenv.c
+504517a55f72370938a142085a4fd57b libiberty/random.c
+ea7c6e3ebb80b75fc26117250db67d9d libiberty/regex.c
+ae878fdfb59df3c8bfba85bb4487543a libiberty/rename.c
+4c0be9f784bf4c61bc89098eebc6e575 libiberty/rindex.c
+ad466048c0305c4348d1580f76acc53e libiberty/safe-ctype.c
+cf9cc42905f451f49e3a24a45bcb77bc libiberty/setenv.c
+56e3dde90b64b261c6ddd7e2da7faeb2 libiberty/sigsetmask.c
+d043445f610b855cf628b72e75e0df3e libiberty/snprintf.c
+bcd38bbff8e80df6e908d7ee57d7b681 libiberty/sort.c
+bef51eff7a41882d4763c4157d06feba libiberty/spaces.c
+d0d349e0b153f5dca03db937262a4e2a libiberty/splay-tree.c
+e1e2c4f1af5569c3e5c98104737bcf76 libiberty/stpcpy.c
+2ebe7af7eb364da1cabfe63fc01100da libiberty/stpncpy.c
+3c49bc872649b875bc538b2eba35673a libiberty/strcasecmp.c
+215e80e7d6c184653c73bd04ba1353e9 libiberty/strchr.c
+6929380bdc5bb0e6c00b6cc71854a3a3 libiberty/strdup.c
+fc91137ce892b48522a5efc28a6c97fa libiberty/strerror.c
+e4c888912855032c9b8f69d6075f10ee libiberty/strncasecmp.c
+7b2896b51c389a6a7d557ea01e8c872a libiberty/strncmp.c
+1ee23798a9223ef8947a376a0b3cfea2 libiberty/strrchr.c
+f8ad09942d5d4edeadf759c5ace93c6b libiberty/strsignal.c
+65f6273a1fb49204f10d98f21904cb90 libiberty/strstr.c
+25fbadcc933dbfa07cb1a249ab97e01e libiberty/strtod.c
+aee79a74ba6f2ec43325737b7e4e86c2 libiberty/strtol.c
+e06d6526f14dcd0834827520331fef16 libiberty/strtoul.c
+63c9e635f440ae8e224846d98bb51f4b libiberty/ternary.c
+70661957f2bc5c40ea102d97ab0bf5c0 libiberty/tmpnam.c
+cda3152399a6665d0e595018d9946ec7 libiberty/vasprintf.c
+0ad8bcaf347187c9147577999d73e9cf libiberty/vfork.c
+49f0de47280a87bb9f87fe2bf517a2e6 libiberty/vfprintf.c
+9a46f8a6bd6b911849f209d09e94b66f libiberty/vmsbuild.com
+300e0b92c4a5f271ba217f5077600323 libiberty/vprintf.c
+3913f665d742eec8aee40fab6823489d libiberty/vsnprintf.c
+947e47f2994c3ece81ff8c57777ef568 libiberty/vsprintf.c
+ec0e1274190167f1f05b8b2eed4f4fed libiberty/waitpid.c
+2f8818cd4649e4dd9891653f15b8e2fc libiberty/xatexit.c
+e416488ce7ad148c9030ed0f54645f30 libiberty/xexit.c
+1bdfb937e0df4543c60ea33babbfb453 libiberty/xmalloc.c
+f3030e6275b76dd6ea06d80a92ccdc27 libiberty/xmemdup.c
+f20e7cc03de67e377c14074ad8117a2d libiberty/xstrdup.c
+3dcfd54ed5da2593e413b5505ecd8bf8 libiberty/xstrerror.c
+4004fdcde347fda58406b4b84a995c66 libiberty/config/mh-aix
+7b65854f594c84e80295173de277b3dc libiberty/config/mh-cxux7
+044204f5b4bcac5eae2face0602129ae libiberty/config/mh-fbsd21
+904bdcd9daf97fa55a9ca8901ffe7435 libiberty/config/mh-openedition
+38e76da568ab25260754fdb9d5080513 libiberty/config/mh-windows
+27e356fc46c6c1fc7c2a73d2f838de37 libiberty/testsuite/Makefile.in
+3d738084dfb24c86b78aa106df02898f libiberty/testsuite/demangle-expected
+628910b2c11e4e04d4b8db2c3d77c4c9 libiberty/testsuite/test-demangle.c
+ebca3703d9896a180df31bf1b4a24e15 libtool.m4
+16f16299b0d7489afcddbfa8399dfe8a ltcf-c.sh
+368ea790e1dfa3d6a2769dbd153fdf19 ltcf-cxx.sh
+33d3f8c62fb77577ea816b81c1f8ff00 ltcf-gcj.sh
+7e42911d61d47efa2e51f31f237a1b53 ltconfig
+37d106abdbbefd48fb089292ac5a5d03 ltmain.sh
+0bc137ffee1670b4ec8592f36aa47419 missing
+cfbd1f0cc32bb4f6feb804354401e61a mkinstalldirs
+55ca817ccb7d5b5b66355690e9abc605 mmalloc/COPYING.LIB
+65711a958e0c2034565e85f6f3555861 mmalloc/ChangeLog
+1280e10e6a92210081d5ba5cb1e9188b mmalloc/MAINTAINERS
+db585eaf26a09e5d92d448a7a1264430 mmalloc/Makefile.in
+ec10f79abad1af6310b3dd6174fcacbd mmalloc/TODO
+61bf8b84a0ccfeecab43057956f3b13a mmalloc/acinclude.m4
+b233d0f45dacdcf0f5bb150ec45021ea mmalloc/aclocal.m4
+5627bccb1b3584c9c0f5bd29602c2972 mmalloc/attach.c
+cad7b1300a3bdcbdc89905966db66878 mmalloc/configure
+d401573232b1c7c8f4cc6fb8b434d6da mmalloc/configure.in
+d5d546f07de784df3e7c13dd690daec0 mmalloc/detach.c
+33f9ea6434117166b57ea7a091242927 mmalloc/keys.c
+a06c5f0944c1b49dbecb94ad5f3a6ec8 mmalloc/mcalloc.c
+858c164d35deb35b59b7451b656d68b6 mmalloc/mfree.c
+8e885ad68e280d567ca59965fe4c3471 mmalloc/mm.c
+34ea386cac892f98efd3337445230062 mmalloc/mmalloc.c
+071137bbe5812e85ba0a29c605a90e6b mmalloc/mmalloc.h
+727b3a53d5fd775f19c429f155da89d8 mmalloc/mmalloc.texi
+29639d12cd53c41d1933fff2332b4bb0 mmalloc/mmap-sup.c
+52455f0b30fb09643cdcabe08292eb2f mmalloc/mmcheck.c
+6ee73cf273416572a9bc2d08d6d79cc9 mmalloc/mmemalign.c
+2e0a59b124063082fd795402f1092952 mmalloc/mmprivate.h
+3e3f87e1c10130e3d6c0a0289344fc52 mmalloc/mmstats.c
+fb806f144f521e1655d829dfccaf7545 mmalloc/mmtrace.awk
+04615ddd4b7f7cea0406cd15a4cf8dee mmalloc/mmtrace.c
+70ef479544294b49af2a3037bd4f8197 mmalloc/mrealloc.c
+261abcbf17ada890e2aee166d9966026 mmalloc/mvalloc.c
+f3b9c1696b8503cee637ce6c1ef09018 mmalloc/sbrk-sup.c
+2cf257cf8a8f879bed4e69834c871102 mmalloc/mmalloc.info
+c71ddf72c059891ca0bd1727f5aa0de1 move-if-change
+642459f0a2056219260229c61f154312 opcodes/ChangeLog
+1b4b8646bdc7ad5a2f9071d8ac8b024e opcodes/ChangeLog-0001
+83ac14eead5eda1862cc926b82d35cea opcodes/ChangeLog-0203
+568db2b4641150f46a18da55529d8d3b opcodes/ChangeLog-9297
+fc3adcd099179b77d2adb79ada21a89c opcodes/ChangeLog-9899
+d618facc3e8ce8bf3d02ba452e1be6ab opcodes/MAINTAINERS
+1bc951e4a53ae1bb7d15b2b251863a11 opcodes/Makefile.am
+f8d110e3944f1add5ad62bdcb1dad83f opcodes/Makefile.in
+9941095a567267c8af6e2847165ef2fa opcodes/a29k-dis.c
+bd5eb3fd0135ccc8fe3f80b61c245322 opcodes/acinclude.m4
+1b00be010221b92771d802cded1643c5 opcodes/aclocal.m4
+d89dfd8cdfd22d6d4e7256cbf738f5e2 opcodes/alpha-dis.c
+7c38f89c5e4beaa9274aa39b4c876f67 opcodes/alpha-opc.c
+d1237155442eaf073a344b41258ce2b3 opcodes/arc-dis.c
+b35daf399df5036ff496742fbc5e08ec opcodes/arc-dis.h
+4648d1a5992f62bb1e5991aee8b3c32b opcodes/arc-ext.c
+2c085be449e338c2bda530572029c8c9 opcodes/arc-ext.h
+2a82fee6975059ddf3eab6e117fb0a49 opcodes/arc-opc.c
+5c965aaef476c11de3933e1cc371d382 opcodes/arm-dis.c
+5ce02872c6dc3aef7e6b1df4da1a4c44 opcodes/arm-opc.h
+a1902cd93726ae865dbb9a7fbcfb83e4 opcodes/avr-dis.c
+0ecb944ba144739d1ef2e6b622867b20 opcodes/cgen-asm.c
+bc264680d95b812ed5d900a02bc177c1 opcodes/cgen-asm.in
+aec02d8fb1ec38e4fca637d214d80c53 opcodes/cgen-dis.c
+92603f3a13c3c7719b48c98007149062 opcodes/cgen-dis.in
+e29a44fcbb2a2a809cbad8b7d55e643f opcodes/cgen-ibld.in
+dd18fcce3992534010714082fb78eaaa opcodes/cgen-opc.c
+9c04535abc91223c5325489d9a6c8a62 opcodes/cgen.sh
+b024616c6675ea3b85d3ffd3fa19fe1d opcodes/config.in
+e7d5b0faa32710121efaff6c45c0b9c0 opcodes/configure
+b66bc3aa5d6e8612dc17902a544669d8 opcodes/configure.in
+182ea56c55f06e99ee1e627781c7a6a4 opcodes/cris-dis.c
+1252380a0061667febf108ef3b0a5d62 opcodes/cris-opc.c
+183b99f0d60896fcfdf0ed17d7b1ef93 opcodes/d10v-dis.c
+ed98e7b763c115a0d4852607571690b3 opcodes/d10v-opc.c
+1fe9373513a310691a268364ed4c8b9d opcodes/d30v-dis.c
+0eebf1cce2cfd05039625773a97b8d40 opcodes/d30v-opc.c
+4fe57e096bcd0ee0b3843ab8a278be8c opcodes/dep-in.sed
+f532bd1f8cae6bd4f17f7f07e6163040 opcodes/dis-buf.c
+864f87f3e57622c62d4afb7104cfdcdd opcodes/dis-init.c
+d2cbdb1139a1d41efec1239f9f9a54da opcodes/disassemble.c
+2f3edb0917f116a080d891784c8bc31a opcodes/dlx-dis.c
+f7b2c4299d7afc4687e131fcdb8ba584 opcodes/fr30-asm.c
+5d96d8e5329805172cff9d831f65fba7 opcodes/fr30-desc.c
+5c57ac35bd0b51d7d568a134b4207110 opcodes/fr30-desc.h
+324d6bdc8f167dc9713424102b505247 opcodes/fr30-dis.c
+cc7e25fa1a3fc163da561eb7842c8e9b opcodes/fr30-ibld.c
+f46a432ee807d8133ecfbf69a88dafa4 opcodes/fr30-opc.c
+215e8e76a271bc24182655abd6aff8de opcodes/fr30-opc.h
+1dec4acb9d17a72b0ad89372b92606fb opcodes/frv-asm.c
+4a5523de1974a11e7e45460d5c6880b2 opcodes/frv-desc.c
+448626fb0d55fd5ff8a876d137798b88 opcodes/frv-desc.h
+0aac9e6bde02fea5b22126eae1ff5317 opcodes/frv-dis.c
+01e78340c1df55a483c7df4f3e0fa338 opcodes/frv-ibld.c
+15cd0b128188d5e69f9d9c2f77e67742 opcodes/frv-opc.c
+6236547af5b713dae8f0db6912c91691 opcodes/frv-opc.h
+9f4edd15383aa1dfd6fd323a1eb78482 opcodes/h8300-dis.c
+7de0cc79a8bb601373b521c9abb2c50b opcodes/h8500-dis.c
+bf8d2780768d86dd48de48b131352dd9 opcodes/h8500-opc.h
+9ed33292bd0f74695dccc2321511c57c opcodes/hppa-dis.c
+dd134274fec4021f3fa0ea08f29b70f6 opcodes/i370-dis.c
+742a917fde7b34a218ae59add2b14d4c opcodes/i370-opc.c
+86a3511bd14324e73e54b2f32ce05873 opcodes/i386-dis.c
+8d648de2b1e74276a29c87bed8c5e8a8 opcodes/i860-dis.c
+756b20d401d0d3d30cb625f266d10700 opcodes/i960-dis.c
+3f26f563c87403a962daa96d396b8aa5 opcodes/ia64-asmtab.c
+4c555d2fbf3bb0d7002a8108f7e28656 opcodes/ia64-asmtab.h
+bdf30cc415a5bcf5f6dd9ce71ed222b7 opcodes/ia64-dis.c
+f8ab0e1c230757e9a42a6396cc3c4ca0 opcodes/ia64-gen.c
+e198da32462463104e95744a25f08e22 opcodes/ia64-ic.tbl
+cf56cf2b9ebe7e74020f759f1ca45b61 opcodes/ia64-opc-a.c
+dffcb60883c34a6fb2a8183a1c9b585e opcodes/ia64-opc-b.c
+67d13d9717835aedab217833eabafb7b opcodes/ia64-opc-d.c
+b620c60d5d283377e0ef629bad7db4fa opcodes/ia64-opc-f.c
+66fa7563d44d579b966b11a4e5fbc25b opcodes/ia64-opc-i.c
+7054a1ff1706aa04eae01f17c295f53b opcodes/ia64-opc-m.c
+a34fd430a730e8bbd9ddea635bee8b1b opcodes/ia64-opc-x.c
+3f84550b5738a724e41a00936e692d7e opcodes/ia64-opc.c
+171abf04ed14a4ed85dc9edde796366b opcodes/ia64-opc.h
+46d9612952650e995998c7ac0871a29b opcodes/ia64-raw.tbl
+b3d7452b4310332b7974b34b09f65a6d opcodes/ia64-war.tbl
+51d601d7177a831c629281f0d03ce940 opcodes/ia64-waw.tbl
+7fc591cf18bafba8205c7068d78d06eb opcodes/ip2k-asm.c
+994a34a1ba1075d6edc6b4d79308394c opcodes/ip2k-desc.c
+8b779e435fcc48657d54e406752dec62 opcodes/ip2k-desc.h
+403504ca6c271f902b39c818d81e59ee opcodes/ip2k-dis.c
+fac15a4271047e78611e6edccc74a1c1 opcodes/ip2k-ibld.c
+bfaa18b0964c956b09cd25ab791023f0 opcodes/ip2k-opc.c
+b133831e263d7ce73a9fe93311dfaeff opcodes/ip2k-opc.h
+769eb6c760554e2a6fc577fc6ce37d75 opcodes/iq2000-asm.c
+eaf045cae6f3c85c4690b7f641fb4990 opcodes/iq2000-desc.c
+08124940d4a99193203e71c606dd24e0 opcodes/iq2000-desc.h
+5260169ee077ca395f86b7103039a183 opcodes/iq2000-dis.c
+02fdeb7001d9fa4c2e6faaa4cd6f6c80 opcodes/iq2000-ibld.c
+033ac537c90ea096dac4ce6b5f61d93f opcodes/iq2000-opc.c
+26ffcca8c6f17dd24768e5f3f217bfdd opcodes/iq2000-opc.h
+a9d541dd9eccd3a1ea0415880b9521a7 opcodes/m10200-dis.c
+cdf93ebf301a6f4b4072b2dfe4b56083 opcodes/m10200-opc.c
+57a4b5cd8b49b400e97d888406bc8877 opcodes/m10300-dis.c
+2424a02b42bc7821ff5011e07668b9a9 opcodes/m10300-opc.c
+e03c7737880a64accae5f936fc2edffa opcodes/m32r-asm.c
+168685cd37eb29cf48a5cd4759b767b0 opcodes/m32r-desc.c
+270161b734aa12ec59f781b9d05d7737 opcodes/m32r-desc.h
+d464ffe8959f56a13ab10a13aabf9562 opcodes/m32r-dis.c
+dc5dee3ebf7d459af0bb26998581f3eb opcodes/m32r-ibld.c
+ad227c4897d269bbe7802f1585813e61 opcodes/m32r-opc.c
+2cf271ad166f28327121b500a3fb997b opcodes/m32r-opc.h
+cf8ed111b3bd970dd219753ea4459da2 opcodes/m32r-opinst.c
+74ba2410f78e6818eb633087c73adc64 opcodes/m68hc11-dis.c
+8d8c14d71076d2526f26e3c11c329153 opcodes/m68hc11-opc.c
+6377e1327ba179a4a4861832bb432c74 opcodes/m68k-dis.c
+951a9d1c4fed3d705b00f202761dcad8 opcodes/m68k-opc.c
+5f0c42248faa120d97b288f04aeeb04c opcodes/m88k-dis.c
+d129eed92c6947db4372b285656ef9a1 opcodes/makefile.vms
+c6aca57ee0df93f584726dcaaac26216 opcodes/mcore-dis.c
+fe2c622e0af6777567843295dacf4e6c opcodes/mcore-opc.h
+395ce519719e84784078b4646fc38726 opcodes/mips-dis.c
+008dbfd422e23be983562ba68924e413 opcodes/mips-opc.c
+c5f2a79141b09a53e3430582f3559b7b opcodes/mips16-opc.c
+008b0311f6fe37664ac553f5710dc7ed opcodes/mmix-dis.c
+a28eee1a261085380892b92df39d665e opcodes/mmix-opc.c
+5de239a139c71421a7cce634f8deca83 opcodes/mpw-config.in
+031902d455df71012bd4603e5d616ca6 opcodes/mpw-make.sed
+28d3c329c3f1ab2b7b93742e28100bf7 opcodes/msp430-dis.c
+1903d4548455a41e5fc83e0d21eedfab opcodes/ns32k-dis.c
+2ba2f33b7280cccf47c76c44bf914ff0 opcodes/openrisc-asm.c
+430e137158ed28b1527e25cdab0b1e26 opcodes/openrisc-desc.c
+ca0c776c11bff05cf8c220a795fcc956 opcodes/openrisc-desc.h
+eee11d50001c32fac10f72d5ec94093e opcodes/openrisc-dis.c
+83538c5396ea7f25a94dc92c8c9f4e5d opcodes/openrisc-ibld.c
+890207b352e9409eeff8b78588e4de25 opcodes/openrisc-opc.c
+b4ba2cc3f10750b1e4784d746954b286 opcodes/openrisc-opc.h
+81a682289129e3eefb7cfd6ce9d10d92 opcodes/opintl.h
+af4929616baa645c821d8efce131eb93 opcodes/or32-dis.c
+42a39b385b3696ae3aeb5ab08b4cb2eb opcodes/or32-opc.c
+69b98498d30589d214ade81f37118d85 opcodes/pdp11-dis.c
+74c71364986215c40dfc680f1bed9d3a opcodes/pdp11-opc.c
+93e9872a6096711dee69bc165d423a7a opcodes/pj-dis.c
+371eac8c21b8b61b0d712e0d1c26f787 opcodes/pj-opc.c
+8664a25bdbb306d1725bc0cd369f3980 opcodes/ppc-dis.c
+1fe03bbdfcea46866df12a7bc875a0bf opcodes/ppc-opc.c
+683721e42ee9e905257cd9a6f33f5469 opcodes/s390-dis.c
+01aadb0bf281e9519ca1477d127ec543 opcodes/s390-mkopc.c
+99f431befa4fe97758c4fd4500b165a2 opcodes/s390-opc.c
+2c3ae0790b8580e0b0219cabb3d7e95d opcodes/s390-opc.txt
+6b929b1d601cd881be5a6899e9a1fbb2 opcodes/sh-dis.c
+afbfe6f26aac30de258db48899a954e7 opcodes/sh-opc.h
+cb0eaf60fa736c8bc9f3a4f2de36fa20 opcodes/sh64-dis.c
+8cf964f73fe8ad566d49e38ad5190766 opcodes/sh64-opc.c
+209cbd91e7a41437384efbe8d415c902 opcodes/sh64-opc.h
+941d97333681360e8be260c9e5ce9ced opcodes/sparc-dis.c
+2a9dfab313c966db78dbfaf392c49d42 opcodes/sparc-opc.c
+1ded054093de910d9786c62bc4fe8cc6 opcodes/stamp-h.in
+8e4842844d864baf1d2056cf0651c2df opcodes/sysdep.h
+e93af673571bd52b817193b4028189d6 opcodes/tic30-dis.c
+b9024a3726fae2c26a9012d11a9f44ab opcodes/tic4x-dis.c
+6e9b2946abe59dc713701f1af4835c7c opcodes/tic54x-dis.c
+bd458a11b32b47de97d716e0ba2fffbc opcodes/tic54x-opc.c
+0bbe03c2f65c1128fd6a0b0916315af3 opcodes/tic80-dis.c
+2225052326dd29b94a99ca86fb0086d8 opcodes/tic80-opc.c
+1ee4e61506d4fd80d5136fb5fc9e5343 opcodes/v850-dis.c
+0617a777a66b4a880bfe6119cfd77151 opcodes/v850-opc.c
+11940019b5b3ed9449fa686ec59ec2ab opcodes/vax-dis.c
+5617ad435c3e7f05af527ebdf4a610ae opcodes/w65-dis.c
+f15e85192b208a59f22ca57220b05728 opcodes/w65-opc.h
+02dc9126d5ffeee4bad38f13ec4b0ba0 opcodes/xstormy16-asm.c
+d94ab0795694f719427f6716947c27fe opcodes/xstormy16-desc.c
+e7464897850f8b7b0f00314d9592e0cd opcodes/xstormy16-desc.h
+8dbf20f8d37020891957a0bd3a9c6e0c opcodes/xstormy16-dis.c
+f7458878ce311368c04d5b6640861629 opcodes/xstormy16-ibld.c
+946fd94dce130ffe83b0d622a878401c opcodes/xstormy16-opc.c
+ec7d55feaa68cbfa72b29a25ae4e6209 opcodes/xstormy16-opc.h
+f53d3f226374a5dc5ed70b471772c019 opcodes/xtensa-dis.c
+5838f65bf6e5688fd32c6214523e7a29 opcodes/z8k-dis.c
+2435cbae8d6b4108d00ea2032bc98650 opcodes/z8k-opc.h
+2a45485bb48273548e787a52a8fd93dd opcodes/z8kgen.c
+d09d0ccd1b7441dcaee9549de0636fd9 opcodes/po/Make-in
+0504c0877e7614d5d8be0960ddf552a2 opcodes/po/POTFILES.in
+6d3b93858658dada9e01f04ea2aa2155 opcodes/po/da.po
+d9c5d53f5447b9fbd27f92ef1ecbbe5f opcodes/po/de.po
+1f1049b96cb50d1c0ff450a2edd02f1b opcodes/po/es.po
+f4dcff36ed8bf89d518fb09f38f45bc9 opcodes/po/fr.po
+195fea77b114bb5405df61cf8bd287db opcodes/po/id.po
+dc0c066b6c080aac377af874ee9a3c79 opcodes/po/nl.po
+075f999775233d7f2eda59a49b1e1694 opcodes/po/opcodes.pot
+30f5fa421474edf39ae99a8985bd42e9 opcodes/po/pt_BR.po
+27e9fec6ee5c546b5d5f4afb80b287ed opcodes/po/ro.po
+cb5047f27d736d066f07a08e33e44884 opcodes/po/sv.po
+8ddcec300546b39bc1d9a13098637b64 opcodes/po/tr.po
+bb1c7be180e128c17ef71889d8e21d40 opcodes/po/da.gmo
+d03d80c52c4e1c3c4542313a0d1b9f46 opcodes/po/de.gmo
+3f4d75b1a4b08db04cd0ce6d14741e5f opcodes/po/es.gmo
+a766be305490174f3142d164e0487185 opcodes/po/fr.gmo
+b6c960d660ea6c9ef46f51a98cd15d76 opcodes/po/id.gmo
+e465c12f6f87300422a7fe4fbda71c49 opcodes/po/nl.gmo
+1b79e075af1926ef6736fa317f054702 opcodes/po/pt_BR.gmo
+e216f1583ca03a04f8849dfb96b59c3f opcodes/po/ro.gmo
+5da56ca1b90b8791c91c7c90f8dfb131 opcodes/po/sv.gmo
+179cd41f0e8af51dd577fd5d7ab36c79 opcodes/po/tr.gmo
+5b5c55fc05cf189ff544e3ced346c957 readline/CHANGELOG
+51ffa89b495619192da06ae4b61df976 readline/CHANGES
+03b36fdd84f74b8d8189a202b980b67f readline/COPYING
+dacb041f1e903b516baedc76d8df6e02 readline/ChangeLog.gdb
+81cc8b4d291fe16825c2a275253c2373 readline/INSTALL
+1d32d53ede16b3202c9809fca59e10ae readline/MANIFEST
+132c5ded866111a1459bdaf54ecf1e11 readline/Makefile.in
+90b0b425dd4cf50f15a89c134fae264a readline/README
+0bb4ff5a1ee6f767d0d1b7ded925a8a3 readline/USAGE
+49b268e63a5d9dc083249de916f6b3b2 readline/acconfig.h
+9e58cd4a908cf2b758e514f71ff09829 readline/aclocal.m4
+5ba16ea9e4b1c5691c974aef544c1061 readline/ansi_stdlib.h
+474b1a3a8efaf34838d59ac2f4e5b8c0 readline/bind.c
+badedfde8238d051d2f7dfe6a373aece readline/callback.c
+ea2d2d0d63c5f6f452ce8cce05e60bf3 readline/chardefs.h
+24752ab06bbbee3765f042d37ab9374b readline/compat.c
+aa5095ae1fad1a1cbc02c95c684b9806 readline/complete.c
+3b524f71b0d544026f63334151451dd9 readline/config.h.bot
+33d8f3b83204473497af0729bedf4222 readline/config.h.in
+cad0501e2d7070cc935545c8825694d1 readline/configure
+a845614b81dedbf7ff96e1d181757584 readline/configure.in
+d2681a490715d682a6b6ddac133de296 readline/display.c
+26474d92637c5c963787d78a32878850 readline/emacs_keymap.c
+c3395fea13acb489044c3e7ecd9249e4 readline/funmap.c
+70d07c63277ae5f29f79b8d32fb96df0 readline/histexpand.c
+9a5f544413075a2108d45d88c1452221 readline/histfile.c
+1cdba3464d48009e931fd4bc5d934213 readline/histlib.h
+d1515be9d60aecb01615310b1fd68453 readline/history.c
+1264cf101004b819d31d83552f540a3a readline/history.h
+54077dfcb93fa93db40e02f5e17542df readline/histsearch.c
+989b28bad9b5e3ac889fd149d0092ad2 readline/input.c
+85152c4bc582b67e2f07f6e75cc1b9ec readline/isearch.c
+ebb0e588ada164c2d80cda2ed9431611 readline/keymaps.c
+38d541623817bd4dc2758068330590a0 readline/keymaps.h
+9c58c77d5880572966c96a4f229c3f9e readline/kill.c
+cb94557483766a522276a98e908cfc04 readline/macro.c
+35742ac3b87d5ba0a95bc564a174d90a readline/mbutil.c
+d0a5e10d6441eb5f607f25622f5e6f5a readline/misc.c
+3bae5c8be4385dc5b157b64fafaf8baf readline/nls.c
+aba3c26aaa8e9bb9f9c6a9eda89befb7 readline/parens.c
+0a313800eea82b7e5fdf3bcd9fbd2b1c readline/posixdir.h
+ba2252d2626050ddb462015bd5598ab9 readline/posixjmp.h
+be2d0a8b9d9c3dc679f13e886caf156e readline/posixstat.h
+6ead2d0ef06796584a0d4fc1c6b3ddb2 readline/readline.c
+28561aeaa84ca63d53135d468a464bb5 readline/readline.h
+09e4df265548342608087435161e41de readline/rlconf.h
+a36ad9d9f7069428425c841249724132 readline/rldefs.h
+15abdb3a635c0bab90b769cd27126cdf readline/rlmbutil.h
+3ab9bc286c284f2a5dc0100ebeeae2da readline/rlprivate.h
+aa300b9013a81a43e35516f679addd24 readline/rlshell.h
+d307cfed49585dc4eb56974ef3255b2d readline/rlstdc.h
+0edad865012a7efbf1acad385901144f readline/rltty.c
+5d2b6d2d6c4a08a7390c335f49233287 readline/rltty.h
+e655c7e47d75825ed3e9c2d75cb3a0b0 readline/rltypedefs.h
+e8cb411d7338299f99b64c3f5d49ac55 readline/rlwinsize.h
+59fe063aa678e53f24fda098ea6e596b readline/savestring.c
+969ab33bb67293ec91fbecdc8407ffb9 readline/search.c
+4828f3fe0b8feac6a47dc972c65d948e readline/shell.c
+0ed53da6ccd155f67ac28776061766bc readline/signals.c
+bb45491aeade9cdfe66512671ca8bafd readline/tcap.h
+afe4f32bd26faf3bd8fb250b587afdf0 readline/terminal.c
+839b3052dcbc461e2a35259f1f342a17 readline/text.c
+4d14b9affde29ad81ba9326e1c367d30 readline/tilde.c
+50cbbcb1898420cad1134e7d17c245fe readline/tilde.h
+d9bf03dc5238b9729686683bf4ed7612 readline/undo.c
+6afe1533692736786bc443756feb40a2 readline/util.c
+0f97e33b6f3c4e5373459236089299a1 readline/vi_keymap.c
+776e938a01615a461319d87ff619bebf readline/vi_mode.c
+75a84e2713d83894f93e2d1e3aa87375 readline/xmalloc.c
+b0779f99427cda84ad6a7e60a0b7cd3a readline/xmalloc.h
+75ad677f6feb3097e69d1431dafd10e6 readline/cross-build/cygwin.cache
+89d9474bb3bfcc8a787cee8b1bc7f965 readline/doc/ChangeLog.gdb
+aaf6ca4a30b4ee66cddd2f566514aebf readline/doc/Makefile.in
+0eb8066ef9b6067b43fe4f63f8f05b6d readline/doc/hist.texinfo
+e41402c08035fee38d1a0dcbce64ca3a readline/doc/history.3
+fa0bb6fd7ff7e1e01e20518c90220d13 readline/doc/hstech.texinfo
+2976408e7a59fcd527e60aa87c06c74a readline/doc/hsuser.texinfo
+2700e383c705103d1ccd5d4bda1b5cdc readline/doc/inc-hist.texinfo
+7b96f5bc113da4b274b809075a090d64 readline/doc/manvers.texinfo
+256ec164a76f49cd5829f8ededede57e readline/doc/readline.3
+eeeb7b1ee984909f404c8a6f08bce3e1 readline/doc/rlman.texinfo
+211bd33b15863ea255cfe83b34e0b2b1 readline/doc/rltech.texinfo
+8be674c1f4df5dfb9a1da1b362515438 readline/doc/rluser.texinfo
+932f2a232c4d669be679cb0c403d95a1 readline/doc/rluserman.texinfo
+f979d2229c3c82ffdfae760f7b3b55be readline/doc/texi2dvi
+1533827bfb0ccf07fdfe9577b4e55a5b readline/doc/texi2html
+0bd93deab351b07d124b49424690dcd5 readline/examples/ChangeLog.gdb
+587fa73058e332ae6e39ef9ad7428e62 readline/examples/Inputrc
+34150954ccffef415dda138b93613b01 readline/examples/Makefile.in
+8666715709699f6e24c7d85af2da595d readline/examples/excallback.c
+4576f906dff3be5f91f6e301eaee5711 readline/examples/fileman.c
+72b51887f790e42c2de9f8f68c8ac87a readline/examples/histexamp.c
+fef6c62715bbcb6b842fa69dd1d51558 readline/examples/manexamp.c
+24b0a86fbc0c767a55657c0eeffe3a33 readline/examples/readlinebuf.h
+633b2c3df52ff11b0807765209fd43fb readline/examples/rl.c
+0bb0f61e933a0b1aec80105f48b57bca readline/examples/rlcat.c
+a2937a422274f83b43ffebd45c01bd05 readline/examples/rlfe.c
+ec131343bdbfe9b79c5cb632965055d8 readline/examples/rltest.c
+4056d443b6f0ba68227697190bf1e94a readline/examples/rlversion.c
+cf45e737e58ef10a2a668d0fd049a30d readline/shlib/Makefile.in
+dd4451f9cdfc36cdb86703965f758ec2 readline/support/config.guess
+6cdae8120da06ebd9981c7a5a813550b readline/support/config.sub
+f01cade8404f87f796fee1a0a296092d readline/support/install.sh
+058be45f92bc8f999144c2c6f5c831a8 readline/support/mkdirs
+b52be3f200cba0442c23371ba15f69c6 readline/support/mkdist
+4db1470ec37357c83b37eaa1cd370836 readline/support/shlib-install
+25de7b51b786eadf4a0a52eccfb12d1b readline/support/shobj-conf
+c58f004fea2277f6e472db636b82e46c readline/support/wcwidth.c
+d10f7c46cbc1305195ac9e8ef218755e sim/ChangeLog
+29600d6c477fd5bcfaf2f36df3374c65 sim/MAINTAINERS
+04b3614a3f5a091aaba40cf5cadb10db sim/Makefile.in
+72ce537cb34d5416875ebff0eab06b9a sim/README-HACKING
+bc96a473e76350011ced3d7488525968 sim/configure
+5cf358fe6eb9eabee188809e5b3bb57d sim/configure.in
+0636e73ff0215e8d672dc4c32c317bb3 sim/arm/COPYING
+7df874753286cf4ab1a6ac86c0303a1e sim/arm/ChangeLog
+8e5a715cda46b66ac93298138ec7b383 sim/arm/Makefile.in
+a62a77605003de7a8ba75d8247fd77b7 sim/arm/README
+c277414b921bc85437478d47aa2ff522 sim/arm/acconfig.h
+a2a3fc0e608c6f69b8e0666321afbc88 sim/arm/armcopro.c
+5cf6a689e4b982aa60949515cb189093 sim/arm/armdefs.h
+f5857e00f91d3042699f269020490ab6 sim/arm/armemu.c
+cb6c018553e6cf12c2ab9897538bca58 sim/arm/armemu.h
+cfb9aa0befafed612ea127d929477e2e sim/arm/armfpe.h
+ceab0c003af7a10826bf9303fb59b598 sim/arm/arminit.c
+99b8409868bab08e646650b1bc1e03a8 sim/arm/armopts.h
+b3e1f5e0043e1d2c8529d9ae37522c7f sim/arm/armos.c
+cfec322e7c65e954b08ea20ff5295807 sim/arm/armos.h
+f01353f284481a4da384f118d7a38618 sim/arm/armrdi.c
+868d0f1690e5f022ac81b3a7463bbfe9 sim/arm/armsupp.c
+fa1897ab0cbb59d7918881acaff8a8d9 sim/arm/armvirt.c
+3b672351d98b99dd459d990f0b212e81 sim/arm/bag.c
+aadb64e2f25be8caa6edb52cd3fd745f sim/arm/bag.h
+92c73b3eb189ddf717d1359b075f1508 sim/arm/communicate.c
+cc63fb53e5e7a3d2f4e4b07112a64ad4 sim/arm/communicate.h
+298f4e880e70c371bea1db9c6c7cb9eb sim/arm/config.in
+f35c5c3e1c83ae0b9262355bc1105720 sim/arm/configure
+6ac0cd3e7e8f13839765af8300390afe sim/arm/configure.in
+773753e83d24e716712dd6070dab3a91 sim/arm/dbg_conf.h
+9d5f53825a2051cc9676f7bd49f50b3e sim/arm/dbg_cp.h
+5b0a3e0b5101b09a6df967d3b316946a sim/arm/dbg_hif.h
+11c48ea5a82a047f8d6034265697d4cf sim/arm/dbg_rdi.h
+fbe3b0248871a2a9dd1bd87b1d4ec563 sim/arm/gdbhost.c
+f2ef4758e0de1f324298c8708f79eb5a sim/arm/gdbhost.h
+ef872ede1daa8ab5bbc4ddd4018717f5 sim/arm/iwmmxt.c
+e8d95d4b5c2e900f87f4e31753c8438b sim/arm/iwmmxt.h
+0d7e1d1be5cb8ced0c65e07197918bcc sim/arm/kid.c
+fa06c996810697a1c8b708223ce7acad sim/arm/main.c
+7a7a08fb0985512b69a606f714ec2e36 sim/arm/maverick.c
+84474f96b09a4d9d72f468531e82bc6b sim/arm/parent.c
+954e1b0a1dc87a295e02d42020117638 sim/arm/tconfig.in
+402810351d9dcedde8fd31599a9a7781 sim/arm/thumbemu.c
+1a1eb8229d1e6157e2c5d84823fdaa8f sim/arm/wrapper.c
+07a99fac9a503ad3daac45cf885704fd sim/common/ChangeLog
+bd57eb33006544376ed00cfe7e82e952 sim/common/Make-common.in
+5848803dfb8f7ef2c3e730653a12cdd0 sim/common/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/common/acconfig.h
+c484c4152f6aaa63325628d18330fc3a sim/common/aclocal.m4
+335073c5fc3053848d19a323ecdf3548 sim/common/callback.c
+794c6e8c2a5a008da07306a22ddf43c8 sim/common/cgen-accfp.c
+796ea72133b71977d61ca66375aa2515 sim/common/cgen-cpu.h
+847163bd5957b6d67cdc0e44b17b8f59 sim/common/cgen-defs.h
+fbe514416cf4b3d5a32f2abfb0bc4c2a sim/common/cgen-engine.h
+ed8b05c07d34977e0e69ce33032d809f sim/common/cgen-fpu.c
+8149048d71beac8331d23655b2ebe540 sim/common/cgen-fpu.h
+cc657a9a86b5f10cedc79e4c04b55513 sim/common/cgen-mem.h
+7b6a854c982812d4147e6b093d204e53 sim/common/cgen-ops.h
+aee7e5cae33b2ce2c56c813ac182ce4b sim/common/cgen-par.c
+a0acc8bc417717e793069bc04a111ce2 sim/common/cgen-par.h
+9495d9df0b2acad950762b18e1d758b1 sim/common/cgen-run.c
+68ebe20e3bb5031f848fd8183f0104b0 sim/common/cgen-scache.c
+1dba6be37e779c52533bc8d4b6353cbb sim/common/cgen-scache.h
+58359f7f1aba415b98d7f6c24100ed50 sim/common/cgen-sim.h
+8470cfa820c29adcc7eee78039746052 sim/common/cgen-trace.c
+7449eed65ac41dcf3dbf85ae91e873e3 sim/common/cgen-trace.h
+0b9d8a4f3fd07f013649edb1fdab442d sim/common/cgen-types.h
+9b1c68faa1bb5ecc302acb231d5bc575 sim/common/cgen-utils.c
+1adaf5a6495421e3864cd820125b6cd0 sim/common/cgen.sh
+33ba305973dc63bc7b9cb19afe140f18 sim/common/config.in
+151dc3c32e6d985f44296e0bfbee6d30 sim/common/configure
+8a66a62b3361b3a1391cbaa9a92b91eb sim/common/configure.in
+68104ebc4ba3307ce3dd728c027fde97 sim/common/dv-core.c
+c6671ada318d70f09a4ebe0e57d17bac sim/common/dv-glue.c
+0d6f766169d902c7d7c4383ef9031110 sim/common/dv-pal.c
+959d37acb4b3ff9b0b50f2457fcd9f7e sim/common/dv-sockser.c
+554bf1f8ce74270c17c62fdb9e651bf8 sim/common/dv-sockser.h
+1a26e2cb381d5bcb0f3f86c52632de4c sim/common/gdbinit.in
+459c9ebddd4c5d1baa3cf0db9953591f sim/common/genmloop.sh
+e0691ba078ee06b3827945ab5cf5091a sim/common/gennltvals.sh
+592084fcb47ee16205a2c64c01451de5 sim/common/gentmap.c
+0cd5aec0350eb378abd59b9e9c5050e3 sim/common/gentvals.sh
+e7aef002715d1bee10b5d145a296d791 sim/common/hw-alloc.c
+7d1a810d7d7dfaadffb977a4d6b8d580 sim/common/hw-alloc.h
+d6182737fb9b1f296b342a3bd49c064d sim/common/hw-base.c
+69e5e0e61d74b6f8f7b4249d847603e7 sim/common/hw-base.h
+db8f0491bdca2927e1561311b371aee7 sim/common/hw-device.c
+4fbcbd59f2e8bea7174797f29a5ea57e sim/common/hw-device.h
+00eda3381f041509e102ae3342428cce sim/common/hw-events.c
+812b4d00d0ca7458f91c906dc6c017a4 sim/common/hw-events.h
+3e10d4a6f3b7e4f4a92918e23bde1b0d sim/common/hw-handles.c
+9f4f1a3a707f84b94ae27febef75f725 sim/common/hw-handles.h
+81589509f9c0c02c217289ebfd0c25a5 sim/common/hw-instances.c
+687e80879fb286ae626c85b5d06246fd sim/common/hw-instances.h
+c00e933e41dcdff8cff3c78a61c13ac3 sim/common/hw-main.h
+42a11c452a78d452155495761f83f921 sim/common/hw-ports.c
+b4e7450ec96d4752f9bd767d2dc98cbc sim/common/hw-ports.h
+566fa5a5f700a19bc9a510d522403ea3 sim/common/hw-properties.c
+178c69ce7f1ba68b00e28f838d3fb71d sim/common/hw-properties.h
+b88fe038fe45ef56e644a7cf46e40b29 sim/common/hw-tree.c
+399bce7ec8cda497fcc50a571bcab475 sim/common/hw-tree.h
+fc555cebdd7df0a92d3b6ec6480a89e6 sim/common/nltvals.def
+3d6d1e939796ea34266da3f0a6269924 sim/common/nrun.c
+1acd8e76db434b00c9434323a99db3f9 sim/common/run-sim.h
+00b96191047c178c25a64b6f2a5a2bf6 sim/common/run.1
+5b5489baed724404431195838ffb51fe sim/common/run.c
+01a66f4e9324575922ca374839dd5a19 sim/common/sim-abort.c
+985391ccff021449e5b4ddc68217242c sim/common/sim-alu.h
+2223ab855959bfbc78e82e2a323a9a77 sim/common/sim-arange.c
+628594cf3099409239adbfa20bb04109 sim/common/sim-arange.h
+55ab2bf3d55a29097ab9bfff98f934fe sim/common/sim-assert.h
+68299281e7b0bbbf0108fcb6dd457399 sim/common/sim-base.h
+e7d97119ac19deeaefd313ca9fcee585 sim/common/sim-basics.h
+673dccaf72a38ecd3cd9488aca02226d sim/common/sim-bits.c
+6dd40057beefb37a3c5c796de50c9beb sim/common/sim-bits.h
+1e5bc09ea0041efc859abf8964d521ff sim/common/sim-config.c
+fe3d8cb9e21da52b169d5c52d2a62640 sim/common/sim-config.h
+7ed410221d79a7e473ff4eb1f8b09750 sim/common/sim-core.c
+b9dbe2b2b06b062c0d3919da2c0a272f sim/common/sim-core.h
+3058e317795b85385c5436896885960d sim/common/sim-cpu.c
+65920de940f14966d09b2f39c250a7cd sim/common/sim-cpu.h
+1ff05b42b14c77e725c88fece4d7b9bd sim/common/sim-endian.c
+7d1a6502338064ccc5269593434b3ff8 sim/common/sim-endian.h
+2744f0bf9f7176264538f86efcd37418 sim/common/sim-engine.c
+364af8f73a9fe7593ba325f08b4141ad sim/common/sim-engine.h
+e4295595a825f2156a12689482f9d206 sim/common/sim-events.c
+6feb23eba7949e90350b2a8a12d8854c sim/common/sim-events.h
+943bfbba77db4f72d8f1167ec48ea3ac sim/common/sim-fpu.c
+b521b59b541630fd9edb080eb0c3791b sim/common/sim-fpu.h
+11f06e8fae65e686b5ecbf62130ea47c sim/common/sim-hload.c
+564fb49c60b8c4fb12a05527bb0c9e9f sim/common/sim-hrw.c
+1ddeffaf97945a97a1d86d0e0fe7e433 sim/common/sim-hw.c
+b1fb1875f15c42d14431b3ba4209c55e sim/common/sim-hw.h
+6bcb53779b5e8f7adb2cb8d04c1bad16 sim/common/sim-info.c
+07284c1e6b4527c48dc5054d05bc41e2 sim/common/sim-inline.c
+ed66c7256d37fba38fc3ed41da6d4d3c sim/common/sim-inline.h
+516bcecf5724556662bf6cfb351b9f27 sim/common/sim-io.c
+39be718345b9a2b1b1c22a65967e4119 sim/common/sim-io.h
+04ec3fa8766ea4560341677e5e7f2f0f sim/common/sim-load.c
+dab6fa02993a62bbb936ded846b177f1 sim/common/sim-memopt.c
+67077d42d023132fd215a2ab18abb678 sim/common/sim-memopt.h
+bf3335ce033f73a5be8c6a0c2a1c47ac sim/common/sim-model.c
+f202bc3df8c6fa5f32fef9e89474ed41 sim/common/sim-model.h
+99cd899dbc76a45fccfb3e9cee122b32 sim/common/sim-module.c
+63de1d375efe9baabfd4f0ef3d8354a1 sim/common/sim-module.h
+7d4793bf7213fbf305559bbf57edf52a sim/common/sim-n-bits.h
+2bfa51f550fd32b5187d9c4bfb9cf0c9 sim/common/sim-n-core.h
+e1db971cf69612cb974822e0b17b3ec9 sim/common/sim-n-endian.h
+e52cb23e5353583347c9193c49835ab3 sim/common/sim-options.c
+f655fec7cb8fe16cc44000b038c73f72 sim/common/sim-options.h
+a46ec8d5aaf717cfe77574f1c27cf4af sim/common/sim-profile.c
+65bbec65f34d78d63ed5f69e485dd216 sim/common/sim-profile.h
+5a8d9d2d9872f892f48c6240a2baa3c8 sim/common/sim-reason.c
+a02f8d2db8c72a0735d8f6834a99b029 sim/common/sim-reg.c
+a73f0bf825ef2e4a6b1e57dc2d1e3b74 sim/common/sim-resume.c
+582d6b475fc63223ad27ae2837c7cc2e sim/common/sim-run.c
+e7ff4729e89d9825ac928aecffa17aa1 sim/common/sim-signal.c
+88d73c8c34abed102e684ba12ee6a7f8 sim/common/sim-signal.h
+0d956d054dff3624715224315de310cb sim/common/sim-stop.c
+a648e4fba65618d182c70da4517c7fdc sim/common/sim-trace.c
+f9fe0d16ab70b1d8eb71359a92ac9355 sim/common/sim-trace.h
+d70a803dbcc8aee2dbab56ba3c0ab64c sim/common/sim-types.h
+021397e35b67a79aebc184abf48b90ef sim/common/sim-utils.c
+207113462a2f4e9c4d4f2c074226b978 sim/common/sim-utils.h
+de3bb67644b46189eee92ce6a18c31e1 sim/common/sim-watch.c
+dc744d214c21a2ecbb2dd79dd6550d3d sim/common/sim-watch.h
+6255114f1333311cfd79e063d44030c8 sim/common/syscall.c
+bd5c87daaac42725e636fe648650fc7c sim/common/tconfig.in
+9446591cbf9a806593440dbde7ab929a sim/d10v/ChangeLog
+77f1d02b57f293d82fa85d904df8e962 sim/d10v/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/d10v/acconfig.h
+298f4e880e70c371bea1db9c6c7cb9eb sim/d10v/config.in
+02ff2e55c3498348dd01b435502490fa sim/d10v/configure
+1b124ee210dd1f4e985fc2bfeec1ae84 sim/d10v/configure.in
+986e8bfc01b0e0cfe1be748f55d862e3 sim/d10v/d10v_sim.h
+7cf4cd44539377c57e6d64f3715397fd sim/d10v/endian.c
+4dda487eecd2318dd4c38275683196c8 sim/d10v/gencode.c
+ffca0265d94f7ad98cdbf39ae347cec2 sim/d10v/interp.c
+be35730e9f08c186e180c980154411b4 sim/d10v/simops.c
+09ede79d54bf92b886ad8208e0fbbdf1 sim/d30v/ChangeLog
+ef2404e8d17289c06833384009f278e8 sim/d30v/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/d30v/acconfig.h
+fda471ff6ffa29239193cabaa5cf4e6c sim/d30v/alu.h
+0fee562cbd64803269a981154f5ed55b sim/d30v/config.in
+f98ac00175488af8e5a8d313ac7df531 sim/d30v/configure
+cf206bfa4486d980ab4d04d88b422d53 sim/d30v/configure.in
+f95651449da0fcb00a32f5be636a03e3 sim/d30v/cpu.c
+f77cd3e0cdb10162c42af53d2574a1fb sim/d30v/cpu.h
+ab753960d5f953b3ede4afe416f774d0 sim/d30v/d30v-insns
+57acc8f6d0a309150ec73c71041ad158 sim/d30v/dc-short
+a48f0d416bb9c76e245de271cf24da23 sim/d30v/engine.c
+409de25b7699f0b304f35d495945493e sim/d30v/ic-d30v
+7891551f8f618e441035f8856756b227 sim/d30v/sim-calls.c
+c3cd55b40757bd34e29652ada7598e5b sim/d30v/sim-main.h
+97ba33b1d7fd99d8cacef0b679271497 sim/d30v/tconfig.in
+b000d9b0a089582665216e66f17cca74 sim/erc32/ChangeLog
+a85b5a2ccd7d7ff2bd1ad01398864fa9 sim/erc32/Makefile.in
+9f2cbd625dfef51b3d1162ba9dbb8a4f sim/erc32/NEWS
+72fececbe452af10d0adb31b037040dc sim/erc32/README.erc32
+ce58de7fe1b8736ff94d663cb47bcf4a sim/erc32/README.gdb
+8d0b5212c0ce4ec7e01d67b407af3ba8 sim/erc32/README.sis
+c277414b921bc85437478d47aa2ff522 sim/erc32/acconfig.h
+298f4e880e70c371bea1db9c6c7cb9eb sim/erc32/config.in
+9045efc77a4220c0bc9cab5a0ee9d3fc sim/erc32/configure
+9c07eff0f5e858ed8377b772941d4808 sim/erc32/configure.in
+fb82f2de8f5ca5a041a8f5a0c8536984 sim/erc32/end.c
+5f964603ecf383d79bf916cd00e3c524 sim/erc32/erc32.c
+1afa3a18ae4d56a3d4cc4127bc5562a7 sim/erc32/exec.c
+c70f15cbd85894f4879fd49f1729da79 sim/erc32/float.c
+470a781dea42dd4ed60734f97f0fecb8 sim/erc32/func.c
+5d55e685281806e6fb65aae7ea51a36e sim/erc32/help.c
+68bad97faa11ebff4fb3af241fa9e026 sim/erc32/interf.c
+159d7b654fb2fe310e0eced630bb87de sim/erc32/sis.c
+4e9b2b2599387377b967a67f46bb6f6a sim/erc32/sis.h
+e7a02f18ba69be1512d680e05b4c44da sim/erc32/startsim
+91cfdd3b348862331438164115946bee sim/fr30/ChangeLog
+6c2955174eb0124514bc5ebe5f282153 sim/fr30/Makefile.in
+96a66b845d0fe0898cebd3b18046df90 sim/fr30/README
+00d02dc1cfedc02f32f38cfb5cbc548b sim/fr30/TODO
+0f339763ce538919da205797dd43de48 sim/fr30/arch.c
+e039d8110cd0911f807dbb86ad98e3b7 sim/fr30/arch.h
+0fee562cbd64803269a981154f5ed55b sim/fr30/config.in
+d41d8cd98f00b204e9800998ecf8427e sim/fr30/configure
+affb4771fb6296be9abc2b067ece92f4 sim/fr30/configure.in
+1262f25d232f7af7f34dcf938011f83a sim/fr30/cpu.c
+1cf92d8d0714e9a4a26c6ebcdb534b79 sim/fr30/cpu.h
+c2860e8016eca83676ec4b8d2e496778 sim/fr30/cpuall.h
+a3cb9c589585838ed82a99af4ea8846a sim/fr30/decode.c
+6e771325f26c31bd5f118b573077af5a sim/fr30/decode.h
+a00dde52f6c8e19cbec3d8f73859c216 sim/fr30/devices.c
+24a2441a93219b159067c616fbb750c7 sim/fr30/fr30-sim.h
+ddd5c7e81605aaec32cca9539124c694 sim/fr30/fr30.c
+1280b998340053ea8d1a584cca95c007 sim/fr30/mloop.in
+609b9be03755fc679f70f59464cca99e sim/fr30/model.c
+c6e2caf669d7ca3783c534b5a7c80ad2 sim/fr30/sem-switch.c
+c7ea26d1b17dab34d5399bceaf3adfe8 sim/fr30/sem.c
+8201cbf7cfb2640d1161166bed14c305 sim/fr30/sim-if.c
+50d18a952ac0f5263155d343355c8b34 sim/fr30/sim-main.h
+c956f3357b764d727169600488a06226 sim/fr30/tconfig.in
+80843e0199a956021787265617353e34 sim/fr30/traps.c
+d94280f664355697d14ba2a5a80315f3 sim/frv/ChangeLog
+dcee34352c01725233bcdf8e0b1ea9b8 sim/frv/Makefile.in
+1dcb16936dd94db21e5b82f208506a6a sim/frv/README
+4327df77a7932a933cf53cd14051fdc0 sim/frv/TODO
+a94ca5f528402cd69460f634bf101c86 sim/frv/arch.c
+dccfd2d39c96012ca0eae69d6a166409 sim/frv/arch.h
+5fd95500bbdf23126eea572fc2e51bfa sim/frv/cache.c
+b04caefad8fd5b977599e0466867e3bc sim/frv/cache.h
+0fee562cbd64803269a981154f5ed55b sim/frv/config.in
+ae0a886300ce47f7d0809da206a68c73 sim/frv/configure
+437469979dc814cde94dcd8467f1558e sim/frv/configure.in
+54bb3c2594c112dc7f1c94a82cc78b94 sim/frv/cpu.c
+31d234984d077def385a98a21c7ae640 sim/frv/cpu.h
+79d435f7c81cd606c3fb256a87f31bc9 sim/frv/cpuall.h
+a23718ec59d7a54d9612de1337a88313 sim/frv/decode.c
+2c327e24e0a2f5f354ee3a1e71552165 sim/frv/decode.h
+b88b43b621769c8a9227a9fccfd3367d sim/frv/devices.c
+cae334018f11961982bc58933c6a74d0 sim/frv/frv-sim.h
+b4263349e06a31fbf63b0bd1e9ea7dd8 sim/frv/frv.c
+09c821f59eaae193268ccff81a6e1861 sim/frv/interrupts.c
+9baf6c0b70d657aac79520d12e762c55 sim/frv/memory.c
+49f6a4904fe580710be329a12b99fa53 sim/frv/mloop.in
+67bd1b5a82d0d33db2db7dcd6e01ae15 sim/frv/model.c
+58f9f6b71ec446179eef410cd656ce87 sim/frv/options.c
+d605a6b470b3d607a5c072c1bef1195e sim/frv/pipeline.c
+d6b0002fd07cc49efd90aec3a63f6c74 sim/frv/profile-fr400.c
+91665b85808e528cc28e1c554622f952 sim/frv/profile-fr400.h
+f03ec9e566dcb0eb931119bfc7fcaee0 sim/frv/profile-fr500.c
+0c2c41ea9d45da288d6e9244c74d90e1 sim/frv/profile-fr500.h
+93e7866d46241608d3062efe0b87e392 sim/frv/profile-fr550.c
+b1ed355936600f58ceb01670202b9853 sim/frv/profile-fr550.h
+9282b4d2f7d1f7ee246f3c6a6f7bc5a1 sim/frv/profile.c
+b4751634e44ce7a2e04c5ec256d80b19 sim/frv/profile.h
+15b3ef525e95048ea1aaa2ae4e4138a9 sim/frv/registers.c
+4685f68d96a65710041561c7f4c06a91 sim/frv/registers.h
+72e74cb9790325b6ae59ce9a3aa767ae sim/frv/reset.c
+8576c5f90e7f8a75513a82135ed896df sim/frv/sem.c
+178a4f29d1fe5e63fbe49770786d95f9 sim/frv/sim-if.c
+81dd638958b042eec526ec15799a57c7 sim/frv/sim-main.h
+87e1b2f71a8938597514fda93676e466 sim/frv/tconfig.in
+9fc487c300aac79319bf38f5e2915407 sim/frv/traps.c
+14b5ab412536790ba49e1566affa55a3 sim/h8300/ChangeLog
+b261a58938986fa4bbd0b26d7c423bb4 sim/h8300/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/h8300/acconfig.h
+bbf1890e065354abfec80271ae333444 sim/h8300/compile.c
+298f4e880e70c371bea1db9c6c7cb9eb sim/h8300/config.in
+f31819458845d3f8eacf97fdae917c13 sim/h8300/configure
+323584913b59655b40d8f0efb7e997f2 sim/h8300/configure.in
+c5fc0ac18cf227f20bd9e218f219d811 sim/h8300/inst.h
+57ddd7ec6dc75f46110af89cca60a0a9 sim/h8300/sim-main.h
+f180a66ef231f5eabfe450962b4225cf sim/h8300/tconfig.in
+5a198f6b19aed858570b289330bf44f2 sim/h8300/writecode.c
+7b6447efdcb1b5c2d72ca3c7405cac78 sim/h8500/ChangeLog
+aac6595692b0a6efa78aa1acd59a1b5b sim/h8500/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/h8500/acconfig.h
+9e2ecfe208b1e193db410e07891f1f0e sim/h8500/compile.c
+298f4e880e70c371bea1db9c6c7cb9eb sim/h8500/config.in
+fc41f130bb89e1aaab815985a7d3bc3e sim/h8500/configure
+91220a453f328d82b56e45f08827aeb1 sim/h8500/configure.in
+d93db14051811ec8ba02a3ae659f26bb sim/h8500/inst.h
+9a6f06f52b6a2ba3726019fd216bd80f sim/h8500/tconfig.in
+abd42a055894c38591ce543a15212ea0 sim/i960/ChangeLog
+3d77563ed40880c9cd05d75ad9345ccf sim/i960/Makefile.in
+a40c966863637436fe3a4acf947dd0c7 sim/i960/README
+5c175f35c400439178181de5c6c338f0 sim/i960/TODO
+c277414b921bc85437478d47aa2ff522 sim/i960/acconfig.h
+fdb273abc49f05e945488a5cd1203324 sim/i960/arch.c
+4aa5b6c85457d671d9309c160b7463e7 sim/i960/arch.h
+0fee562cbd64803269a981154f5ed55b sim/i960/config.in
+1a3f8fa5d2e3e5c2d1242ba85a77a872 sim/i960/configure
+ca0be5b63820bc94b25fdd8573fbf767 sim/i960/configure.in
+43e2d85b7da0385b2251518a04cb9d3a sim/i960/cpu.c
+5b477b6ec1ffc3fd9722e52740477c8a sim/i960/cpu.h
+5b7427bfa18f5a0d35a203bd49b32e5d sim/i960/cpuall.h
+f13eb3aeec4d3e80fea3141cd1569972 sim/i960/decode.c
+5d1a31f263c24055175d13520ed777eb sim/i960/decode.h
+34553cdaffc67e146207e498fb20198b sim/i960/devices.c
+02d782e504f910dae67e743e44f31b88 sim/i960/i960-desc.c
+0e4f799fa7e4fcafaca945a4b36c0613 sim/i960/i960-desc.h
+7617d8109b7ac5be37716cc44e90f1a9 sim/i960/i960-opc.h
+853bede0706d752f3e8805d143a3c1c4 sim/i960/i960-sim.h
+c54b8356d84f0cef23b7bcbb40f2e2fe sim/i960/i960.c
+f7156af46ba360deaf8cd0c29ff1b5b6 sim/i960/mloop.in
+181f7adaae9cc9f684427c87235257f7 sim/i960/model.c
+564ad8b94832c643d21ab4a15c0081aa sim/i960/sem-switch.c
+95b15bd87786d146f652f9fb83cc0413 sim/i960/sem.c
+ae9997acd3cc669b25b97228f62314dc sim/i960/sim-if.c
+4cce3e6b82f6216771c14ed404987586 sim/i960/sim-main.h
+1c6bda214533fb133515f0ede3f91333 sim/i960/tconfig.in
+2e52341ba1ddd648c60fe0991c76e8e2 sim/i960/traps.c
+635eaadc1233b6d392e04ce2efc7465c sim/igen/ChangeLog
+f3b7b7e50b2f2d0e72dbfca12b85f50a sim/igen/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/igen/acconfig.h
+422222ab85ca136ef98c3a169a2bbb00 sim/igen/compare_igen_models
+64cf5a0611ad7aee52e1595e54b30841 sim/igen/config.in
+3bfb0607c4c2a4d41767a4e54e2d65ec sim/igen/configure
+508b72d9370e92ebcc04e8abcd0328da sim/igen/configure.in
+a7ddc265e574c9087232ee5d3275c872 sim/igen/filter.c
+cdaaeb083244280d583a3d4be956ff69 sim/igen/filter.h
+3b6de5be9150ccd04c0095ed082c94f1 sim/igen/filter_host.c
+a68bb92496f910da726685db059affd8 sim/igen/filter_host.h
+608521d5f029e56b81e5485e4cf3d32e sim/igen/gen-engine.c
+8574c19656b4226ab19e22c73a0c079e sim/igen/gen-engine.h
+8b643b4143a38545777f14db336bfb8a sim/igen/gen-icache.c
+0c15aef6804e5b1a4a8b54f3e24dea30 sim/igen/gen-icache.h
+003b2dac367a40fdd0f72787c451aee2 sim/igen/gen-idecode.c
+f63a2c52375a861738f06384ff5fb176 sim/igen/gen-idecode.h
+19ef018c2d7195c8de65e342ca6e8824 sim/igen/gen-itable.c
+07f9217f44da3481a46a6c0d1615a204 sim/igen/gen-itable.h
+45542b4586b0c07373f7967595a020d3 sim/igen/gen-model.c
+98d3496d6cfb8b9ba44f564e69ff4573 sim/igen/gen-model.h
+83768cf0023c15a615cf2595d0da5445 sim/igen/gen-semantics.c
+a281210a4d10c43ce6d2843d052354f2 sim/igen/gen-semantics.h
+7017d947f77588adc4e7abfcc3f87f57 sim/igen/gen-support.c
+dea9d61752587dd0f75fa0bc680c1ce8 sim/igen/gen-support.h
+9f9e328d80e735cfa2748b6ef0d257d5 sim/igen/gen.c
+e5aa8f4a17d224e9d6244acbd91f851b sim/igen/gen.h
+495b00951f547c3ff81f48c707b6158c sim/igen/igen.c
+88d6154df5d156bd381fa33f70f94f29 sim/igen/igen.h
+fb7d0739d93fcc2c585224dbbc7e986b sim/igen/ld-cache.c
+af879a10b93dad0dbc6e27dc7abd3ccb sim/igen/ld-cache.h
+278627569fa6d6ab7845ed89e2a906d6 sim/igen/ld-decode.c
+718fb888c6f19d9a645ea14b58de84bc sim/igen/ld-decode.h
+20bf370217048ec40ba15b58eedc8a21 sim/igen/ld-insn.c
+599a98e625372b77ba4439835fd6fa5b sim/igen/ld-insn.h
+92dd6c4eabc783c7798b1fc23011d5d8 sim/igen/lf.c
+4d29b74cc6459416de9184f8f914f2fe sim/igen/lf.h
+3bc79cacd418c1e60e65f917c8e6f23a sim/igen/misc.c
+5a63050499dad653f12c11557df3d95a sim/igen/misc.h
+e4d2618404646b1897b58a2bb1a61849 sim/igen/table.c
+af7e8a2921fdd031e96b3739d0b207e3 sim/igen/table.h
+12849a1931782a8730c6ac9b8959e357 sim/m32r/ChangeLog
+b40685b2009e7c095fb1321caf74d25d sim/m32r/Makefile.in
+23b6e82d29f42c31a097d431b0f73004 sim/m32r/README
+7aa7d02d4d195447e0ae6c176fc6ceb4 sim/m32r/TODO
+c277414b921bc85437478d47aa2ff522 sim/m32r/acconfig.h
+996f52b08c6341a79cb89970a6e9b7a0 sim/m32r/arch.c
+c9d7ea4c42bb911f8d21f051bd8bdf44 sim/m32r/arch.h
+0fee562cbd64803269a981154f5ed55b sim/m32r/config.in
+97f2c88de68238f84990ef1d99ea8aa3 sim/m32r/configure
+87bd1b3fdf0bca0ccea3a96c2f506c81 sim/m32r/configure.in
+a2e6c9fa39ed2445d3b15fb5486280cb sim/m32r/cpu.c
+3f4414a18de15b9f1a6a5a7a40a5440e sim/m32r/cpu.h
+5fd78fde39ed741b1e792312bc31c0a4 sim/m32r/cpu2.c
+6308de37e93f389b5cea1abdd27333f9 sim/m32r/cpu2.h
+a1e6805774e092c6f1674c68b3ab49db sim/m32r/cpuall.h
+49e4a17460d576ef9edf9dd7cf8c781e sim/m32r/cpux.c
+8889d2dbab2a9b7da7eaea529fbe1af2 sim/m32r/cpux.h
+b73750c1798f1ca5a897ac63191c2b65 sim/m32r/decode.c
+8539bde44ade91f27698b4b05b014831 sim/m32r/decode.h
+1b3f40a25e4cff9f8cba792b0f424437 sim/m32r/decode2.c
+5e98e3718b6d6d31b2c60df199483a2f sim/m32r/decode2.h
+22b8b4f133923266e8857233e1a393b2 sim/m32r/decodex.c
+926c182dd094f306984766b4e1b5707c sim/m32r/decodex.h
+7788a7c57f7884be7c37d25bb4d86233 sim/m32r/devices.c
+e051bef0f6697dff11f576592b87c470 sim/m32r/m32r-sim.h
+3411b3004ac4386c233e19469b0b3fda sim/m32r/m32r.c
+a3802a004168beb1299bda0c59693f3a sim/m32r/m32r2.c
+4169446d172632a917d4cd0037b1931e sim/m32r/m32rx.c
+c34a4a213ae34afbc938148fc40238f1 sim/m32r/mloop.in
+896d3c80cfc14d62fd51a094b9ccc13a sim/m32r/mloop2.in
+d40cb9b256777840bf815680a1d39ac7 sim/m32r/mloopx.in
+587b6177abad21e50044d69348716a0e sim/m32r/model.c
+54a4745aa3a167d2693966688bbda455 sim/m32r/model2.c
+ff51ea5bf669af6d988ef6be227c912e sim/m32r/modelx.c
+6692a9702241b4499f75a4c9d23c7fd2 sim/m32r/sem-switch.c
+7bc2814a06f295e62c039afc76c4eb2c sim/m32r/sem.c
+f0841e2822cccd6568bab2217274ee80 sim/m32r/sem2-switch.c
+6a15a40b8d9f5708faf22b1714dd2408 sim/m32r/semx-switch.c
+ffd2718e234371cb2ca2d0b99ff00240 sim/m32r/sim-if.c
+a24af2c954c1781817ac3519604b8e37 sim/m32r/sim-main.h
+45a0108d5b20ee6c8b06c05f0b2db833 sim/m32r/syscall.h
+e962644fafd12290fbf81ebc5bf75941 sim/m32r/tconfig.in
+14ca824124e46571c55943993c4fcf5d sim/m32r/traps-linux.c
+6cf4831571c7040345069124587f704f sim/m32r/traps.c
+c17abb369524f87498fb8098d8554a58 sim/m68hc11/ChangeLog
+759275b1a5e4073c82a64eee0290df81 sim/m68hc11/Makefile.in
+7216ccc164e27ed244a88fa920621c28 sim/m68hc11/config.in
+60312156da8fcfd2b5a43f57888c61e3 sim/m68hc11/configure
+a442aff0717d6b743f45c305a56a81b3 sim/m68hc11/configure.in
+6306b0d52de502b09c735c8536445869 sim/m68hc11/dv-m68hc11.c
+86f7f1ef15e23744e1e12f7189ead722 sim/m68hc11/dv-m68hc11eepr.c
+66def3567515023a2623fe6ddbd7ac6c sim/m68hc11/dv-m68hc11sio.c
+0eeea9cf3fd07809bdceb3bc2e2f1c7f sim/m68hc11/dv-m68hc11spi.c
+5740ce8db5af3406ecd705d9a40dde88 sim/m68hc11/dv-m68hc11tim.c
+8af43034356f916cf60db7029715a6c3 sim/m68hc11/dv-nvram.c
+e189d6f6562000c5fc7308391ad7bac8 sim/m68hc11/emulos.c
+c42b2ba01baca551610c5780831fbb2b sim/m68hc11/gencode.c
+faf3881415f9b4ee93601c14782a6f7d sim/m68hc11/interp.c
+d8bfc1fce8ff8674776f00d9c247edd9 sim/m68hc11/interrupts.c
+dbaa2b61ba2abe66b6456612c3bd24e0 sim/m68hc11/interrupts.h
+e116a2ceb1bfdfda286e145b3749ea9b sim/m68hc11/m68hc11_sim.c
+8e1e56a9385d767aabd3654ffbef4611 sim/m68hc11/sim-main.h
+aea1847f61511e6c88a36e41988a02e3 sim/mcore/ChangeLog
+7a419dcb91f3a385263b94390e380373 sim/mcore/Makefile.in
+7a0ac25f6a6527e94daf604368008af7 sim/mcore/config.in
+8653a595c12f9577cbbf0d1d7a88faa0 sim/mcore/configure
+0a4ea962282f282a0cea4091d7853ebc sim/mcore/configure.in
+7e402acbcfdb4c9fc7051e273f808f4e sim/mcore/interp.c
+f36379389e336917d707165f92b5e0de sim/mcore/sysdep.h
+a813810ab5324f4ad1452a88188be363 sim/mips/ChangeLog
+07909736600a2df706f59d757b340c11 sim/mips/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/mips/acconfig.h
+7216ccc164e27ed244a88fa920621c28 sim/mips/config.in
+dfec119316c2c633b516a43e62a4ab65 sim/mips/configure
+a08a1d176bf11e53b7d3a753d16af356 sim/mips/configure.in
+690bb341293d988336f0a3229858411b sim/mips/cp1.c
+cfd93ed6e20f222ba7b8f5cc0a2d1626 sim/mips/cp1.h
+48313bab48ed7001558227bb55427cd1 sim/mips/dv-tx3904cpu.c
+ea6a03fe8459556b03582d1a047c2b69 sim/mips/dv-tx3904irc.c
+ff7aec055766868c712979c75248fcdd sim/mips/dv-tx3904sio.c
+7bd6c90f4266d6b5e82db4245fa5b71a sim/mips/dv-tx3904tmr.c
+d8dcbd03a41a7be1e765e64539fdb28c sim/mips/interp.c
+61566dc2819979301d3d92473a37bbc3 sim/mips/m16.dc
+a2b7ff4fd8c66926c4d7f9c908660770 sim/mips/m16.igen
+383c97095ceeb7131e415af4e6089bec sim/mips/m16run.c
+7904bf22efbdc475cf1594fad60512b6 sim/mips/mdmx.c
+016146452a32f25514afbc560f00088a sim/mips/mdmx.igen
+0cc85f54d1aaffc21fa0a619b2e23020 sim/mips/mips.dc
+dabf74d62cdf37a1ba428aba665426b5 sim/mips/mips.igen
+eb2f600f9761977db8d3feea4b65e04e sim/mips/mips3d.igen
+a1271a930f1d21b88dba16a50c0ee756 sim/mips/sb1.igen
+7dab3d41ec64a57cdc85cba9f9e191a3 sim/mips/sim-main.c
+10d59a5c3e8237ac550843a7391c6b65 sim/mips/sim-main.h
+926a84abe029a2f84db15716688266ca sim/mips/tconfig.in
+e90e73eee445d44f164749dc8d8c0a4d sim/mips/tx.igen
+ba62602283b3852a0e0be5ca7c31f6c5 sim/mips/vr.igen
+46c8a94f60ac12ff17f7ba9708923223 sim/mn10200/ChangeLog
+9f141b8dd47f317190cdc9a3ce984d53 sim/mn10200/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/mn10200/acconfig.h
+298f4e880e70c371bea1db9c6c7cb9eb sim/mn10200/config.in
+8653a595c12f9577cbbf0d1d7a88faa0 sim/mn10200/configure
+0a4ea962282f282a0cea4091d7853ebc sim/mn10200/configure.in
+eb1b39921b51cdfb00709c9a18d3b2eb sim/mn10200/gencode.c
+a3eb57c673f94a9c483604fb4343c910 sim/mn10200/interp.c
+a44842feda9ae70fbbb834eb0680719f sim/mn10200/mn10200_sim.h
+479d6c9ea43b90d1a9cd4298c6284f6c sim/mn10200/simops.c
+b1f46ec47e1a31623ca0bf87114bb5e9 sim/mn10300/ChangeLog
+8b70ca01f08cfd84fb7a1a90870f8ae6 sim/mn10300/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/mn10300/acconfig.h
+f2d47ad14aeba7bff0ed3d22edd3b6d2 sim/mn10300/am33.igen
+dc553d113147dcc545cf06254dc945cd sim/mn10300/config.in
+02eac39f01f8738f31c1a0fd07b580f4 sim/mn10300/configure
+1f64f042f45eb08a55952212c2eff45f sim/mn10300/configure.in
+c685749cf62929a0240f0e4ae35d609b sim/mn10300/dv-mn103cpu.c
+816316050cd0ae95243c95b47663da8f sim/mn10300/dv-mn103int.c
+db75cdb54357d705e6bdebdcd9e3811e sim/mn10300/dv-mn103iop.c
+bc62aff9064a399af82b70c2666ce058 sim/mn10300/dv-mn103ser.c
+0939bc8de505ea9717bd274b9fdfe292 sim/mn10300/dv-mn103tim.c
+fbe965d4d693ffae4b0bba1166cde6d4 sim/mn10300/gencode.c
+5140f4c6f80e90226f7091e9d3738875 sim/mn10300/interp.c
+a02c306411614c8de463bf278aac5d2e sim/mn10300/mn10300.dc
+7043e91c23dd572d29fc98541a0cebca sim/mn10300/mn10300.igen
+366b67df562313696adbca47a8834a10 sim/mn10300/mn10300_sim.h
+3bcdb8235b340516548f0d3c81d46f56 sim/mn10300/op_utils.c
+9560a29b6c94d4955a447290ab5d050a sim/mn10300/sim-main.c
+b29858ce03067664cc41c6b57c04b31b sim/mn10300/sim-main.h
+95c44ccdcd1db369924ac39bce801d5d sim/mn10300/simops.c
+a123cfe902117497cd3549ffb9746f78 sim/mn10300/tconfig.in
+9386f74bff5fd3a25d4cea3f6cb22bda sim/ppc/.gdbinit
+36407106664516616438a622329f6f1c sim/ppc/BUGS
+0636e73ff0215e8d672dc4c32c317bb3 sim/ppc/COPYING
+55ca817ccb7d5b5b66355690e9abc605 sim/ppc/COPYING.LIB
+b7413ba700088e6158067136b005fe8f sim/ppc/ChangeLog
+1bad061e853e13647aa63e38a9f1001f sim/ppc/ChangeLog.00
+ecd61aaafc1737616ae87c802cc0a8e1 sim/ppc/INSTALL
+9ad182a22baf78b14afadf50a4d026c0 sim/ppc/Makefile.in
+851c77c4a526e09ac6fb7a77cba89b89 sim/ppc/README
+9b98a3220b34ead882ebd988dec298a4 sim/ppc/RUN
+c277414b921bc85437478d47aa2ff522 sim/ppc/acconfig.h
+d41d8cd98f00b204e9800998ecf8427e sim/ppc/aclocal.m4
+f3e930efde135708616e46a2d3949bd5 sim/ppc/altivec.igen
+b6f5d464f7ec0259af422334dde59abc sim/ppc/altivec_expression.h
+c51c1f314cf140ad857550ef88b10470 sim/ppc/altivec_registers.h
+9652d7609f72d7caed40808ebe8fb88e sim/ppc/basics.h
+65f3366c7c3689220435a25a2ba082cf sim/ppc/bits.c
+26ed1de12dff50c6a0519d14c73875eb sim/ppc/bits.h
+4cb3d76f0038ed5a17f3309bda545304 sim/ppc/cap.c
+8f88189396a532d2824fcef2d85db174 sim/ppc/cap.h
+b2463b6e50044deb7e2cb999f38ca027 sim/ppc/config.in
+69daa3cbf424c9399a4b2ba771480e41 sim/ppc/configure
+2899986c46db4227dac5a1a24fa07ce4 sim/ppc/configure.in
+131b92c2bfc60c0a0fa11c7127f01151 sim/ppc/corefile-n.h
+29769d29b23530fc8e7468cb63db2338 sim/ppc/corefile.c
+2ad9c889b2483dc6b2f700cc50d5b5fb sim/ppc/corefile.h
+660e642bfccbe4d4b4b24f8d276f2353 sim/ppc/cpu.c
+89dfdf1a4d8b1700564cc4e5f27a8254 sim/ppc/cpu.h
+d3057ff75f6c17550e153338da749f6d sim/ppc/dc-complex
+7e0b4be2388bf97887228aa76e954bfd sim/ppc/dc-simple
+763cc8428117c5c2bd847cfd06bad1d0 sim/ppc/dc-stupid
+b055ce44c5462421dd15b911a2062f25 sim/ppc/dc-test.01
+f41d30b6b933ba4acab16757fff79de7 sim/ppc/dc-test.02
+a6d011adc9e4de62790722e892b94c97 sim/ppc/debug.c
+40b9eb72287e10011898a3f69ca9a9e8 sim/ppc/debug.h
+67401955dff214152654f4bb80fcebaf sim/ppc/device.c
+fee7a267accd496b6e2c4650b01c9b3d sim/ppc/device.h
+22be58a024fde413f5c3cce2886bb260 sim/ppc/device_table.c
+1f064536d367de4ddd18a25453c994ae sim/ppc/device_table.h
+c2f21558a815c20612b2ed4f41a34197 sim/ppc/dgen.c
+e08cfb709d371ce5e6f9f34d81ac9828 sim/ppc/double.c
+26fba4dddf659d490c8183770049d1cb sim/ppc/dp-bit.c
+778d7f98fb015b8f96b02a7f188ba18e sim/ppc/e500.igen
+101c7fd23d373f9026081875dd7621d1 sim/ppc/e500_expression.h
+a2a58098edf9df5967bd766f7c87a4a5 sim/ppc/e500_registers.h
+d96be9d476f04a86ff09e0bb56ee943f sim/ppc/emul_bugapi.c
+f3d6d8d54f0b5c045c86907af1622bb1 sim/ppc/emul_bugapi.h
+ade49d06e52abba4f8ec33a1fe674c90 sim/ppc/emul_chirp.c
+9ef23ee673b667efd253b033f899761e sim/ppc/emul_chirp.h
+c6d335c965bc9ac0fd8a69490abc036e sim/ppc/emul_generic.c
+ed6d07b7f4e68168b0ac37650d30dce0 sim/ppc/emul_generic.h
+5a5c562ab31b44fb73f9631530dfc99a sim/ppc/emul_netbsd.c
+7b33787dcf41c03863f43b596f3e4a50 sim/ppc/emul_netbsd.h
+14b5605c5c067c9fae8edb40686e6b4b sim/ppc/emul_unix.c
+3f59054ed73fc405d309edc3c0cd58c0 sim/ppc/emul_unix.h
+e0f8bb1f315522473bf26e2561c51239 sim/ppc/events.c
+6cbdba37de3215094841c9436c4a706a sim/ppc/events.h
+f6e4ee2195d564b95790b8b48423ab68 sim/ppc/filter.c
+5d83db32f82407624ef3e44877bfc901 sim/ppc/filter.h
+b0e13975e4c92bc339a5db359eeeaa0f sim/ppc/filter_filename.c
+e19c72f467811559af2500ff99310762 sim/ppc/filter_filename.h
+82c063a4f15c6576229bd0c5a77d0061 sim/ppc/gen-icache.c
+de741bee50e72c9eecf54eb31a57ce18 sim/ppc/gen-icache.h
+7c88da65d2064ea39325546b703797ee sim/ppc/gen-idecode.c
+397ac3ac567e76ac1f4f7eb47f9dfe65 sim/ppc/gen-idecode.h
+382f9371a894b71e4ed2afb83f8512f3 sim/ppc/gen-itable.c
+31313c242173b2fe764f90edd57ce459 sim/ppc/gen-itable.h
+5da7ebf67f12aabf1833e7ada1ac3537 sim/ppc/gen-model.c
+d43fa565ffb41b1c78dd6065ae0845f0 sim/ppc/gen-model.h
+218fb15b91e0b63886b2f201c703fa1c sim/ppc/gen-semantics.c
+dec70a4d4d0f2e04b9eb9c27aa842c79 sim/ppc/gen-semantics.h
+8f683225ed38466273adb6e821a62cb5 sim/ppc/gen-support.c
+125e5cd58b108f5a52c65544d1ba6638 sim/ppc/gen-support.h
+66fff86ce57112322b003c08f8082358 sim/ppc/hw_com.c
+54811845fe3d62433b00e07da46dc594 sim/ppc/hw_core.c
+5abc6e083931e0d458473da276a7c6a4 sim/ppc/hw_cpu.c
+0a5a25a4fecbe3cbbf7f70711c577567 sim/ppc/hw_cpu.h
+121bcfcb4285245e045b8596c3a747f8 sim/ppc/hw_disk.c
+50a89c1f61bf77a7ff0dcb467a0206a4 sim/ppc/hw_eeprom.c
+e6e7b45f07996b30fcddc8e10cae366a sim/ppc/hw_glue.c
+a5cf7634bc0d9a09876c14f194f81e80 sim/ppc/hw_htab.c
+c2b3a77eb45c504654e71b7e16ea2adf sim/ppc/hw_ide.c
+57ecbf831ff4930dcd3b62c09133a427 sim/ppc/hw_init.c
+5fc19100c2410b42430334c970b7026b sim/ppc/hw_iobus.c
+194c545e87c2f690b8949843bbac306c sim/ppc/hw_memory.c
+d4c516dbc656ce6b2b16caf4ee9aebfb sim/ppc/hw_nvram.c
+ba5acc7a95cdafcda3aac022b9b6e0e3 sim/ppc/hw_opic.c
+e492e3614a6bd470ccf9bc24071c32ec sim/ppc/hw_pal.c
+1cfd2049fa85129d72af534948c7244b sim/ppc/hw_phb.c
+0782b28bb03134bea2f77d3e21431333 sim/ppc/hw_phb.h
+789065ef358a2a3dd227c387d481cd4f sim/ppc/hw_register.c
+5d8731168076d37dcd4ad8a2d6b0bcea sim/ppc/hw_trace.c
+b6b91adc2188e28630d543be73c728ae sim/ppc/hw_vm.c
+8ad4143e2bdd2ef9a398710de5877613 sim/ppc/idecode_branch.h
+63e7f1f0dfc6d16de67e47829d6f6750 sim/ppc/idecode_expression.h
+a2a6140315cd3e6453fca3098ea6e0ab sim/ppc/idecode_fields.h
+c8aed2d71502b4d53e12b87f201953cd sim/ppc/igen.c
+1f88347bb2decb1fcd7487967bdca59b sim/ppc/igen.h
+52907d4b0d9210c127a37368437d0ddd sim/ppc/inline.c
+03137ec9c557c5729790f1bb1563fa34 sim/ppc/inline.h
+ae8d0a3696f84324c18d529193e3a0aa sim/ppc/interrupts.c
+d36e61a48bbeb0fc22d6a43502618468 sim/ppc/interrupts.h
+a2376b46e21317f87a63c93cabab96a3 sim/ppc/ld-cache.c
+5c6c90b8dbfdf6f0e8fb8f01a599061b sim/ppc/ld-cache.h
+e8ca4a4c2e2662ef78e50e1516e3bc4e sim/ppc/ld-decode.c
+c96a0234594399abd61c514cf7885206 sim/ppc/ld-decode.h
+ad52b61bb3c6f286d96c54d156a7ea26 sim/ppc/ld-insn.c
+593a5550b97ea2cd864a310b6ee04ec1 sim/ppc/ld-insn.h
+daebea50f263bbad71ae4a076eb048ef sim/ppc/lf.c
+267c9ade5fa517ed0fbc29c776dc3cc9 sim/ppc/lf.h
+d04db63c46f629ef831a4e87a08184b0 sim/ppc/main.c
+685bbe6ed4a3962eda1f367838cb09cf sim/ppc/misc.c
+01dfdfb64f654f8a7501ba41e05a3fa2 sim/ppc/misc.h
+213ccd2e7b903475f306cb61e3de7b25 sim/ppc/mon.c
+3287b3ce2acbf89f0c76939187857022 sim/ppc/mon.h
+af7c9c433b85abb5c5e61673fea77b45 sim/ppc/options.c
+39bcc46ecea434624fdb42fae9ce598d sim/ppc/options.h
+955e62ba48085a359721fc988df0affe sim/ppc/os_emul.c
+ec00d27d9b5b0ee84e478874c7952855 sim/ppc/os_emul.h
+dad3b3f6b9a6e1551b7767d567f2814e sim/ppc/pk_disklabel.c
+dab52f2f241129432e05f4796eea5397 sim/ppc/ppc-instructions
+fea984afca834b59ac7bc3d62d547432 sim/ppc/ppc-spr-table
+7ef1469cfb0809ffbafba1a6f43cc98b sim/ppc/ppc.mt
+4e00a173c2a1427ee913e8bf184ad402 sim/ppc/psim.c
+14dfb8864f8b7f98b5c2a1f2b0cecd7d sim/ppc/psim.h
+3451a21ba5941444fe5ee2960d137449 sim/ppc/psim.texinfo
+edc5e08e83b415d070176ec878fc1b10 sim/ppc/registers.c
+e20c3fefc2cff3ff71658b6cea230773 sim/ppc/registers.h
+27f339dcae5a8605568b933ad52ed9c9 sim/ppc/sim-endian-n.h
+b4fd27207dfbdd0fa5586a006a50b670 sim/ppc/sim-endian.c
+f2864bc7dbfd420dd6bf6ceb87a7e8ac sim/ppc/sim-endian.h
+48c6b8643d82c832a08fc5aad6c182c3 sim/ppc/sim-main.h
+9cc64e896ca9c264032ec0c23d8c956c sim/ppc/sim_callbacks.h
+48e8abc4c6561218b272c232eccce145 sim/ppc/sim_calls.c
+2591babcc19cd684b6fdbfcbd6f7e126 sim/ppc/std-config.h
+e7451d70081236bfb7163f267c854741 sim/ppc/table.c
+393b81b772e44da580c2183af38e50c5 sim/ppc/table.h
+fdd3a949d91eeb278b7c6f411c8709b4 sim/ppc/tree.c
+23e9a034bf895eb2830a71e52cc4b44a sim/ppc/tree.h
+e3af8bab4cb4fccf3b5830b93523c0fb sim/ppc/vm.c
+f5e70f8a845ecb64afee001c9d36535c sim/ppc/vm.h
+ed994e6b649eff89844e1e09fb217d02 sim/ppc/vm_n.h
+0a3e20c2efc205e378d3d55d33929fc6 sim/ppc/words.h
+ace334961586ac7e4e727012b0495793 sim/sh/ChangeLog
+23602cb5409d20d5cb482a046e2771f3 sim/sh/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/sh/acconfig.h
+298f4e880e70c371bea1db9c6c7cb9eb sim/sh/config.in
+8653a595c12f9577cbbf0d1d7a88faa0 sim/sh/configure
+0a4ea962282f282a0cea4091d7853ebc sim/sh/configure.in
+7f048fb4605d9fc88d063e79d1dd0659 sim/sh/gencode.c
+4a969caff2c769d43ee468d9f4074af6 sim/sh/interp.c
+485762a39054bcf5bf3a3ee2a4de586f sim/sh/syscall.h
+d0f4fcd32d377647d675b8d3ef85db09 sim/sh/tconfig.in
+132b90d2280f46c299d1b8e39656b451 sim/testsuite/ChangeLog
+ddd196390b26fc624f607bfd82ff729a sim/testsuite/Makefile.in
+7243c8e0a37d645c04d36b678f902a2c sim/testsuite/configure
+c0ccc959de0e4e5d22b54468c77adcac sim/testsuite/configure.in
+8b1814b871166305ec8fc7a06cc9a84d sim/testsuite/common/Make-common.in
+09db0759c17936e2d8cf6dea6eda8fb1 sim/testsuite/common/Makefile.in
+9980219e011c42205bbd14e46d21fc8f sim/testsuite/common/alu-n-tst.h
+56912c8f1ff672daf4dbab4a0fb12a54 sim/testsuite/common/alu-tst.c
+42cbac0d5c278c9408ec0dca800a01b6 sim/testsuite/common/bits-gen.c
+2c97e49ca99e657e07ca12a6fd5d6f69 sim/testsuite/common/bits-tst.c
+874ac49fc37d49f2822c8b409d285004 sim/testsuite/common/fpu-tst.c
+6f85f5b126eda2839d687ef1b5cc9587 sim/testsuite/config/default.exp
+a3578cc8d27475e1226e45a184b1b810 sim/testsuite/d10v-elf/ChangeLog
+f2e553ee3b71714955057e9f70b32deb sim/testsuite/d10v-elf/Makefile.in
+734efc2fae2a739ad8a8b656f7a46072 sim/testsuite/d10v-elf/configure
+288bd7e91ed8182fa32d11f022d738dd sim/testsuite/d10v-elf/configure.in
+2092af64ed30dac7b430156bd2387770 sim/testsuite/d10v-elf/exit47.s
+df56df219276d06d750e8fb6f6b1581b sim/testsuite/d10v-elf/hello.s
+f9e7c86333f37f05849bb0913d84040e sim/testsuite/d10v-elf/loop.s
+246424eed873ed649d2a32c1de0a12cb sim/testsuite/d10v-elf/t-ae-ld-d.s
+517096aa5ab9c0e44c70c067d41b0536 sim/testsuite/d10v-elf/t-ae-ld-i.s
+1d77729ab41b4cc1ef00c09482ec6715 sim/testsuite/d10v-elf/t-ae-ld-id.s
+266aa2fe095d30aad29b83c25851971e sim/testsuite/d10v-elf/t-ae-ld-im.s
+75cd5a849fb6a73f45b92c5173201ad0 sim/testsuite/d10v-elf/t-ae-ld-ip.s
+880e8e02eb0c803c436bfc733723664c sim/testsuite/d10v-elf/t-ae-ld2w-d.s
+e407a9027a51a971d55c14a9deac7d15 sim/testsuite/d10v-elf/t-ae-ld2w-i.s
+3b139d94efcc709b303318543337cee4 sim/testsuite/d10v-elf/t-ae-ld2w-id.s
+94f087c25d14650e94905d367ac781c8 sim/testsuite/d10v-elf/t-ae-ld2w-im.s
+d35bfeba95637ae41856f6692744cbdb sim/testsuite/d10v-elf/t-ae-ld2w-ip.s
+ccf5bb0090436bc56ae6e5ab152f9be6 sim/testsuite/d10v-elf/t-ae-st-d.s
+c52f1cfa2ba8e7eb55aa93e564a0164f sim/testsuite/d10v-elf/t-ae-st-i.s
+776264e34418e424ca53627692e3170d sim/testsuite/d10v-elf/t-ae-st-id.s
+a25febe699e92863dd860f733c9dd22d sim/testsuite/d10v-elf/t-ae-st-im.s
+6a1e686613656c7345b1feb238e31066 sim/testsuite/d10v-elf/t-ae-st-ip.s
+7edbadafb83e173b875ef37b4728d3f9 sim/testsuite/d10v-elf/t-ae-st-is.s
+f831b90857d7d08faa607a4c5d2fc618 sim/testsuite/d10v-elf/t-ae-st2w-d.s
+2c65c61ce821576fd7642ae775e053ee sim/testsuite/d10v-elf/t-ae-st2w-i.s
+6e39b3ee1a1f446f2aea2265a13e824e sim/testsuite/d10v-elf/t-ae-st2w-id.s
+44c3061ac426dfdcf4a850fe15376b2f sim/testsuite/d10v-elf/t-ae-st2w-im.s
+0492a673d4276924c61d9ce568802546 sim/testsuite/d10v-elf/t-ae-st2w-ip.s
+670f5bcbd96246bf460d84b57bea1102 sim/testsuite/d10v-elf/t-ae-st2w-is.s
+9324e63160953a8b19ec76988361aa95 sim/testsuite/d10v-elf/t-dbt.s
+fcab1b7a79a3a82158f92a79f01fc1b6 sim/testsuite/d10v-elf/t-ld-st.s
+24adce9358d8640ca6ae226ecbeb41c7 sim/testsuite/d10v-elf/t-mac.s
+ace81e2c0d0d2ac060e2172d5fc8e655 sim/testsuite/d10v-elf/t-macros.i
+d028e41377d7e4afcdc3b979f9e026d7 sim/testsuite/d10v-elf/t-mod-ld-pre.s
+ba2eb8bb4b43be12c27308bebccab16d sim/testsuite/d10v-elf/t-msbu.s
+be230dfdf2fc8a9548a086fd285ea00e sim/testsuite/d10v-elf/t-mulxu.s
+c61c5fd4a6a85120020dea1782d72d65 sim/testsuite/d10v-elf/t-mvtac.s
+744e0ee2abcec900b154f72ccf20434f sim/testsuite/d10v-elf/t-mvtc.s
+202b3272059c697b714c5f14d21e8418 sim/testsuite/d10v-elf/t-rac.s
+5850459c815d7a2cea95632d02288d93 sim/testsuite/d10v-elf/t-rachi.s
+d3f2b6a8713945840267c5b38031db57 sim/testsuite/d10v-elf/t-rdt.s
+d68929f5405fbc0fa82b417d61e8389c sim/testsuite/d10v-elf/t-rep.s
+c2989be701fa58229f9d2c51d1d89b9a sim/testsuite/d10v-elf/t-rie-xx.s
+b318831c796a5daf3c008a72a1bcff77 sim/testsuite/d10v-elf/t-rte.s
+2e29d477a767f8c3e7b9806e5061b73a sim/testsuite/d10v-elf/t-sac.s
+34070ba49d956128040f988eb91c46b7 sim/testsuite/d10v-elf/t-sachi.s
+e8c67bf69426a7db6ecb7c2cafcc0a99 sim/testsuite/d10v-elf/t-sadd.s
+ec7bb92d79cec389c2cf4685d0c91150 sim/testsuite/d10v-elf/t-slae.s
+655e71f960343e657e230eba7ecb5f61 sim/testsuite/d10v-elf/t-sp.s
+67a11da95718e0f31001311302fe7743 sim/testsuite/d10v-elf/t-sub.s
+3bf62ddddb5d760ebd4a96790f02efd9 sim/testsuite/d10v-elf/t-sub2w.s
+dd04c4735e06d614b03e76a552d4fcb6 sim/testsuite/d10v-elf/t-subi.s
+b5b7dcb39e5fe37d20f5fbad5c205b6a sim/testsuite/d10v-elf/t-trap.s
+8cba15e47843de592d01561920af7273 sim/testsuite/d30v-elf/ChangeLog
+9d207563a57f64272ac6dc2d50b2ca2f sim/testsuite/d30v-elf/Makefile.in
+e93542ef6c36b1526d49c88c3a0e7e51 sim/testsuite/d30v-elf/br-bra.S
+33307709df7e9e56067a8e0de59bf0d2 sim/testsuite/d30v-elf/br-bratnz.S
+7ae79abf0ec5df4ccdd1e6f44d2c6bf7 sim/testsuite/d30v-elf/br-bratzr.S
+ae790a1cf27ac88e18036478b7d454e1 sim/testsuite/d30v-elf/br-bsr.S
+f27f8166f0e2dccba3841285c579fe0a sim/testsuite/d30v-elf/br-dbra.S
+446dd09e9d804c6583d6db8cd8bb0bca sim/testsuite/d30v-elf/br-djmp.S
+51897cdfa07463eaaf76a8186dfdf0b7 sim/testsuite/d30v-elf/br-djsr.S
+9c6af644b654d2d888e103f33a52ce7b sim/testsuite/d30v-elf/configure
+288bd7e91ed8182fa32d11f022d738dd sim/testsuite/d30v-elf/configure.in
+57a414d0b27c4465d2362c5a9c1e6171 sim/testsuite/d30v-elf/do-2wordops.S
+7bff52c7b4c3536a647a815c787f5362 sim/testsuite/d30v-elf/do-flags.S
+22b5ace3a746e6e8185d327a5a9aef30 sim/testsuite/d30v-elf/do-shifts.S
+f6a9a0cb828c0a11996c863e3172b9e4 sim/testsuite/d30v-elf/em-e0.S
+66042f4711a46f3364fd702877af06f1 sim/testsuite/d30v-elf/em-e47.S
+b4367cba1f71ca0a8312a0e25b23d177 sim/testsuite/d30v-elf/em-pchr.S
+254c18ad72c944ac250995ce33727a3a sim/testsuite/d30v-elf/em-pstr.S
+66042f4711a46f3364fd702877af06f1 sim/testsuite/d30v-elf/exit47.s
+a5c24af71ca0b23aac853ea351fb718e sim/testsuite/d30v-elf/hello.s
+62e9cffcae3042316f06fb8345d3e8cf sim/testsuite/d30v-elf/loop.s
+4d86df9cdd556650520fcb1f8222b5e8 sim/testsuite/d30v-elf/ls-ld2h.S
+34a9e7d3b3a4597adafb1065dcdf54bd sim/testsuite/d30v-elf/ls-ld2w.S
+027ffff597b497bb8abc27a21e803f89 sim/testsuite/d30v-elf/ls-ld4bh.S
+f1c094e548e36239d8ee237be49d6ef1 sim/testsuite/d30v-elf/ls-ld4bhu.S
+b663a826ece0596f78181872c56c3c6e sim/testsuite/d30v-elf/ls-ldb.S
+536f7ad39f43f6445aeb2f38700857bd sim/testsuite/d30v-elf/ls-ldbu.S
+156bf757165f4ca6c2ab93dbca420c5d sim/testsuite/d30v-elf/ls-ldh.S
+62c29bd7f7e51bcd18abcf37be94afb4 sim/testsuite/d30v-elf/ls-ldhh.S
+30156d1558f7eedd2c0fc05b1a9a6715 sim/testsuite/d30v-elf/ls-ldhu.S
+45409a30148cbc3b8e3ec6d053d9c80a sim/testsuite/d30v-elf/ls-ldw.S
+147fce0ff6b95d97af80b1c4d676dd3b sim/testsuite/d30v-elf/ls-modaddr.S
+e5e9bd185eb0debe74944abf679c172c sim/testsuite/d30v-elf/ls-moddec.S
+99e98e937cec5ac83e337ad8a789d0d1 sim/testsuite/d30v-elf/ls-modinc.S
+f4741aadd909e9ad323682bcf964e9fe sim/testsuite/d30v-elf/ls-st2h.S
+d435cc05cbd9c228a8c170ba64c8fb77 sim/testsuite/d30v-elf/ls-st2w.S
+d553332d34db320891f8b982d8aca88f sim/testsuite/d30v-elf/ls-st4hb.S
+000107339afefa58336120a39570555a sim/testsuite/d30v-elf/ls-stb.S
+1ee1036a06d0b97ca340e25224a98f9d sim/testsuite/d30v-elf/ls-sth.S
+c6ee4e543628014104812e4daa3eb965 sim/testsuite/d30v-elf/ls-sthh.S
+7f63c22821b1406c7505574fd3f6edb8 sim/testsuite/d30v-elf/ls-stw.S
+5720eb7587f98e617d1080075104482b sim/testsuite/d30v-elf/os-dbt.S
+d4a3477b80f59ab26730dc52cd482893 sim/testsuite/d30v-elf/tick.s
+e8d6ffe1c8ded0f14bc6a7972b3ab68c sim/testsuite/d30v-elf/trap.S
+5348180e030d01447f84b2e834599a56 sim/testsuite/fr30-elf/ChangeLog
+6f86e172c388289a1e79c3e1cf0f8507 sim/testsuite/fr30-elf/Makefile.in
+cd954db176c3c6c49d4c2ed079de0561 sim/testsuite/fr30-elf/configure
+288bd7e91ed8182fa32d11f022d738dd sim/testsuite/fr30-elf/configure.in
+1b9331844e5edb27a4681212f8a8373d sim/testsuite/fr30-elf/exit47.s
+bba20ead85e5cedd8bf70c640d2968eb sim/testsuite/fr30-elf/hello.s
+689fc85c7b927bf3ad2ac2f6cbfe2140 sim/testsuite/fr30-elf/loop.s
+f7e8fed66f264a2e4fb14d106c435e57 sim/testsuite/frv-elf/ChangeLog
+0b48ee82e4c413029db432faf43af83c sim/testsuite/frv-elf/Makefile.in
+ad3cb74cb4f5e1145c323d436230b3f4 sim/testsuite/frv-elf/cache.s
+9c6af644b654d2d888e103f33a52ce7b sim/testsuite/frv-elf/configure
+288bd7e91ed8182fa32d11f022d738dd sim/testsuite/frv-elf/configure.in
+70ca72190bc26acee97deb6d5974053f sim/testsuite/frv-elf/exit47.s
+e30b4c8b1165f133ffd45b28034a33a7 sim/testsuite/frv-elf/grloop.s
+cc16675e19f20d246b81ba1aa64e2c05 sim/testsuite/frv-elf/hello.s
+02ebc2d23f1397660d56c21d6a0866c6 sim/testsuite/frv-elf/loop.s
+7d589ac801d3f4bea4bbeaa863107860 sim/testsuite/lib/sim-defs.exp
+ed9984b92a4b91f7231f26675b5270d4 sim/testsuite/m32r-elf/ChangeLog
+f606ee0a98576833f097c79fec2994a7 sim/testsuite/m32r-elf/Makefile.in
+cd954db176c3c6c49d4c2ed079de0561 sim/testsuite/m32r-elf/configure
+288bd7e91ed8182fa32d11f022d738dd sim/testsuite/m32r-elf/configure.in
+fdcd1bf835b2c2a0ce2ec539624e2a6c sim/testsuite/m32r-elf/exit47.s
+d855cd1f7a63aa5913126e4c9cbbdca4 sim/testsuite/m32r-elf/hello.s
+61aac381a61d722e21e84faa6146d7be sim/testsuite/m32r-elf/loop.s
+58dff76723704b72ace4023caa129a54 sim/testsuite/mips64el-elf/ChangeLog
+8e706361883bd83f8d6746f201595a45 sim/testsuite/mips64el-elf/Makefile.in
+bff3eea383aaf966899c9d6ff0410fec sim/testsuite/mips64el-elf/configure
+288bd7e91ed8182fa32d11f022d738dd sim/testsuite/mips64el-elf/configure.in
+5477dc224f249d5d847bb14b5809df81 sim/testsuite/sim/arm/adc.cgs
+1c290ff406eb9de96060785ccfb36a33 sim/testsuite/sim/arm/add.cgs
+a3aa42f1d4d1630a0f42c3e640f6ee0d sim/testsuite/sim/arm/allinsn.exp
+58ac8d4d5ea2fe8c946251b4592629c6 sim/testsuite/sim/arm/and.cgs
+99933c6f18e0fe8c3cbfeea3222bc270 sim/testsuite/sim/arm/b.cgs
+8e130c393453b06b0c4f168915320147 sim/testsuite/sim/arm/bic.cgs
+d3676059d440e43421abe9377b45644e sim/testsuite/sim/arm/bl.cgs
+d8cbbc37fbab2579e37ca9ed2c82d6e3 sim/testsuite/sim/arm/bx.cgs
+d80faf2d614f5b40636508bb03f723ff sim/testsuite/sim/arm/cmn.cgs
+514c9855ea49dbd189076992160d290a sim/testsuite/sim/arm/cmp.cgs
+5b1a485b23f4ada997bc9c482f4b142d sim/testsuite/sim/arm/eor.cgs
+e7ed4d8b65d61b3addaa13b237d5d630 sim/testsuite/sim/arm/hello.ms
+7b279b86516c39f3610fd701192e55da sim/testsuite/sim/arm/ldm.cgs
+93e27d311dd9c978b5fd3238d8a96ff7 sim/testsuite/sim/arm/ldr.cgs
+2f129d54e1238525995fbb61345511b6 sim/testsuite/sim/arm/ldrb.cgs
+3d8cacbe82b517293ac2230f4947d142 sim/testsuite/sim/arm/ldrh.cgs
+bef5c11ab14ef76a4adf86bdb29f3fa7 sim/testsuite/sim/arm/ldrsb.cgs
+b70b6932231ba7b22b55aa6b0dabd2da sim/testsuite/sim/arm/ldrsh.cgs
+248009f835f984c6659530b0d8ac3d6b sim/testsuite/sim/arm/misaligned1.ms
+e094567de77b483869bfaa906a58c5f0 sim/testsuite/sim/arm/misaligned2.ms
+61d1b5a430c450fa09d944dac4f6e9e9 sim/testsuite/sim/arm/misaligned3.ms
+c0491db4475978a5556ce7e8d3940329 sim/testsuite/sim/arm/misc.exp
+7c8eb7b1180e26892ff171384548e3df sim/testsuite/sim/arm/mla.cgs
+cae028721a4860ba721bb0b6a45e28de sim/testsuite/sim/arm/mov.cgs
+138b2c1c179325a81f413db374952dda sim/testsuite/sim/arm/mrs.cgs
+5f5776bf35261a0924e7314d31bbec74 sim/testsuite/sim/arm/msr.cgs
+0ad30943dc3310c090723d102d0c0c72 sim/testsuite/sim/arm/mul.cgs
+28a00b5d6dacadae53e6f32c439dd867 sim/testsuite/sim/arm/mvn.cgs
+e36fa83cfe6f8c23c2c4a874d15d6bb5 sim/testsuite/sim/arm/orr.cgs
+0b54dec83ea8c2148335d0c9411f827a sim/testsuite/sim/arm/rsb.cgs
+2db4b0c1e930d96e870724d2ecb71ec1 sim/testsuite/sim/arm/rsc.cgs
+24953ef6d2f93fbc574722cfeb6f0508 sim/testsuite/sim/arm/sbc.cgs
+424eae0aeb212b99a0423296d92432f9 sim/testsuite/sim/arm/smlal.cgs
+5daa27aad0853ba541927ca858d54e0e sim/testsuite/sim/arm/smull.cgs
+7caaf16bdd001c1cfdc6d204be0595d5 sim/testsuite/sim/arm/stm.cgs
+510262d467a1cf529e9ebf863f5510bc sim/testsuite/sim/arm/str.cgs
+bb3da4ab25011ccabcc1c8437f907d7d sim/testsuite/sim/arm/strb.cgs
+982a00c19684480239a8d14ca04bd9e5 sim/testsuite/sim/arm/strh.cgs
+1be7d9195c233759510ea7aea222287f sim/testsuite/sim/arm/sub.cgs
+7853156003daa0909a44ee8c2b159869 sim/testsuite/sim/arm/swi.cgs
+05ae9969a70c8f236c50630fd2f7d113 sim/testsuite/sim/arm/swp.cgs
+f38f5ed68bbf76a6bb802723f8e111ac sim/testsuite/sim/arm/swpb.cgs
+2f52c300639b0dccd15ed3b15bf2949b sim/testsuite/sim/arm/teq.cgs
+f0a99de3c5c47c3aa91c95c25879b41f sim/testsuite/sim/arm/testutils.inc
+853c04dea43ce219f8fbb2d4dda8f96c sim/testsuite/sim/arm/tst.cgs
+a06bb01624f0127d797df273c0f0ae39 sim/testsuite/sim/arm/umlal.cgs
+da2138a738648ab058990d5e495fb407 sim/testsuite/sim/arm/umull.cgs
+fff690cc3c0b4cab7f417d747f0b6274 sim/testsuite/sim/arm/iwmmxt/iwmmxt.exp
+cb91cfc8d87632674bb08655b37257af sim/testsuite/sim/arm/iwmmxt/tbcst.cgs
+f0a99de3c5c47c3aa91c95c25879b41f sim/testsuite/sim/arm/iwmmxt/testutils.inc
+fd328a7cecef16b062706133bd86a185 sim/testsuite/sim/arm/iwmmxt/textrm.cgs
+676c13c4e65bd1da95adcdacc048ee0d sim/testsuite/sim/arm/iwmmxt/tinsr.cgs
+27a5dff0fce99446ea9b92149fd87aad sim/testsuite/sim/arm/iwmmxt/tmia.cgs
+b87db8b330bbfc39e8cc5c193bfd6752 sim/testsuite/sim/arm/iwmmxt/tmiaph.cgs
+7f91c1c6ee07a5fa069f79687e6d3b18 sim/testsuite/sim/arm/iwmmxt/tmiaxy.cgs
+e3314ba0fb5456272846893666ca6076 sim/testsuite/sim/arm/iwmmxt/tmovmsk.cgs
+7a8797138da5f79dd25a529ca6aafda9 sim/testsuite/sim/arm/iwmmxt/wacc.cgs
+aade4be67b5af16a82727edd01ff01a5 sim/testsuite/sim/arm/iwmmxt/wadd.cgs
+88c71104de87e83e76badb90eee05b15 sim/testsuite/sim/arm/iwmmxt/waligni.cgs
+e40211a7420484d7931c301a38d87629 sim/testsuite/sim/arm/iwmmxt/walignr.cgs
+6f34dbce9217355b0034e980065123b2 sim/testsuite/sim/arm/iwmmxt/wand.cgs
+1eeac0b2b5efecd25602ca32932a301e sim/testsuite/sim/arm/iwmmxt/wandn.cgs
+b468e9e418a1e1a91063cde9f01a5b65 sim/testsuite/sim/arm/iwmmxt/wavg2.cgs
+23189fcb39a2352d1f2aebd9fa472b86 sim/testsuite/sim/arm/iwmmxt/wcmpeq.cgs
+ade7f421e7229ac22b99232d633506d8 sim/testsuite/sim/arm/iwmmxt/wcmpgt.cgs
+f0f803cfe86027c9376da8bd15d603dc sim/testsuite/sim/arm/iwmmxt/wmac.cgs
+bf292aeb577d786f1a5d93be72786c39 sim/testsuite/sim/arm/iwmmxt/wmadd.cgs
+3d4113ef895254186382634bb9654300 sim/testsuite/sim/arm/iwmmxt/wmax.cgs
+154a974a65e03d5b99e084a97aae5048 sim/testsuite/sim/arm/iwmmxt/wmin.cgs
+7f2e2adae5b6face7645ef4d178af158 sim/testsuite/sim/arm/iwmmxt/wmov.cgs
+7155fabca12e398a7ae30604e6010df6 sim/testsuite/sim/arm/iwmmxt/wmul.cgs
+d3866e29becc0eb004bf50d7adcf21bc sim/testsuite/sim/arm/iwmmxt/wor.cgs
+7cbe9df76667e549020ee9154febcb84 sim/testsuite/sim/arm/iwmmxt/wpack.cgs
+da03e694abbabd2571357cc9ed058c70 sim/testsuite/sim/arm/iwmmxt/wror.cgs
+81f8cb5a71451f972f4e040b980f6606 sim/testsuite/sim/arm/iwmmxt/wsad.cgs
+538bf57041e5e509121767d9ead1147e sim/testsuite/sim/arm/iwmmxt/wshufh.cgs
+182edb4dbe3c5f16e8bbc90c344f5958 sim/testsuite/sim/arm/iwmmxt/wsll.cgs
+648dcf66cfd2ce5849d2cbb42c74e3ef sim/testsuite/sim/arm/iwmmxt/wsra.cgs
+372409901bb2e34b4370c142151e635c sim/testsuite/sim/arm/iwmmxt/wsrl.cgs
+b759e1c2be6dc0fb3b9656e41302b73c sim/testsuite/sim/arm/iwmmxt/wsub.cgs
+966e30e2028caa8495f566e530a4e4d2 sim/testsuite/sim/arm/iwmmxt/wunpckeh.cgs
+33dad8b13e3c06ffd72fefbae3ae328c sim/testsuite/sim/arm/iwmmxt/wunpckel.cgs
+2ece72d7f9fed70851599aeafeb8fd75 sim/testsuite/sim/arm/iwmmxt/wunpckih.cgs
+d4cf1dd1687b956976c326aa10e0da93 sim/testsuite/sim/arm/iwmmxt/wunpckil.cgs
+37722d747ac7f2623a99bd2d5d04c319 sim/testsuite/sim/arm/iwmmxt/wxor.cgs
+7f8a6603491a9bdea9261b3aefecd67a sim/testsuite/sim/arm/iwmmxt/wzero.cgs
+f39dfdec26af7f089c85d0156d96f853 sim/testsuite/sim/arm/thumb/adc.cgs
+a3a364cbdc5b492650e011da6f9c6de2 sim/testsuite/sim/arm/thumb/add-hd-hs.cgs
+0c8a4f0432c4d3abeea38a2f31a8fed2 sim/testsuite/sim/arm/thumb/add-hd-rs.cgs
+65de2dbbc1d1963e22a7ed146018c9cf sim/testsuite/sim/arm/thumb/add-rd-hs.cgs
+3b1245f3b53f4f2fd1788169d9d1e5a5 sim/testsuite/sim/arm/thumb/add-sp.cgs
+44fc3fa4d4212c68997074146cd2081d sim/testsuite/sim/arm/thumb/add.cgs
+34994f81445d814b87b6aebce14a53c9 sim/testsuite/sim/arm/thumb/addi.cgs
+d9a906c124e9554e0980cc53b336b377 sim/testsuite/sim/arm/thumb/addi8.cgs
+7fecc3e47bed5457f394e92e9c496247 sim/testsuite/sim/arm/thumb/allthumb.exp
+995d38ff3ed038c4f5cbcad2d78e0207 sim/testsuite/sim/arm/thumb/and.cgs
+a1eda67b5040ebb08367e07d0624ee8a sim/testsuite/sim/arm/thumb/asr.cgs
+4dd23bc630fc11c4eca7cbea9fc36231 sim/testsuite/sim/arm/thumb/b.cgs
+05d4b004a36c86c46a3ba8f3a485c488 sim/testsuite/sim/arm/thumb/bcc.cgs
+9679a91ccf07238a1c0161cde847fe85 sim/testsuite/sim/arm/thumb/bcs.cgs
+e162af7a697a2fa2e10ecc1a56b45be1 sim/testsuite/sim/arm/thumb/beq.cgs
+359c1c1f673e082a73606aea537c22ce sim/testsuite/sim/arm/thumb/bge.cgs
+cc9025ac9679ebfbd9e3fc340edbc697 sim/testsuite/sim/arm/thumb/bgt.cgs
+244babd31dcba228ef3637cbcca9c16b sim/testsuite/sim/arm/thumb/bhi.cgs
+4a2f10cac1edd904293441d716cad0f1 sim/testsuite/sim/arm/thumb/bic.cgs
+6ed6d54faafbb0319c1604112b0c16c4 sim/testsuite/sim/arm/thumb/bl-hi.cgs
+a8c07a4b4764c4cc4c88cd2633394160 sim/testsuite/sim/arm/thumb/bl-lo.cgs
+f25edf66e54fa2c53957abc6aa807d00 sim/testsuite/sim/arm/thumb/ble.cgs
+ead31b659b0f0e78ca8054010fc195a9 sim/testsuite/sim/arm/thumb/bls.cgs
+b1866a0b3f4e1244f6f32c7890b4623f sim/testsuite/sim/arm/thumb/blt.cgs
+ec7f950054226d26fe7c00da759b2c4e sim/testsuite/sim/arm/thumb/bmi.cgs
+5ae8870812f676720ebfc69b48c04ebb sim/testsuite/sim/arm/thumb/bne.cgs
+03a9889899898201a14082970138178d sim/testsuite/sim/arm/thumb/bpl.cgs
+cd68a29c2b8bdaf0c8aed77438819e18 sim/testsuite/sim/arm/thumb/bvc.cgs
+5ea6bc2fd59bbd0f3a4bd46fd117a8be sim/testsuite/sim/arm/thumb/bvs.cgs
+fcaed4c8608ce095dc4625f37383b515 sim/testsuite/sim/arm/thumb/bx-hs.cgs
+23d58ec2e23ff3bed4784642cc48aa06 sim/testsuite/sim/arm/thumb/bx-rs.cgs
+2588c865bab15990f4bd3546b3d82fe7 sim/testsuite/sim/arm/thumb/cmn.cgs
+189891b42b0a10d5895c36ed13267a7e sim/testsuite/sim/arm/thumb/cmp-hd-hs.cgs
+6c4154b82d1b8a3579a0f42b4142aad5 sim/testsuite/sim/arm/thumb/cmp-hd-rs.cgs
+bc1c96814fecd239a7955bc76320fae5 sim/testsuite/sim/arm/thumb/cmp-rd-hs.cgs
+9e9f7b260681e86c6c0b7e0006cd2154 sim/testsuite/sim/arm/thumb/cmp.cgs
+b44832f5d79102e7efeee45f69462a66 sim/testsuite/sim/arm/thumb/eor.cgs
+7bceba1198328ea2930942d76eca4da4 sim/testsuite/sim/arm/thumb/lda-pc.cgs
+b0b760fd79039fbf1125dc0a526be229 sim/testsuite/sim/arm/thumb/lda-sp.cgs
+a25b0fe3d7a82e5a2f7605f685e15f46 sim/testsuite/sim/arm/thumb/ldmia.cgs
+3896f647e72d591e262a40e5af29adf9 sim/testsuite/sim/arm/thumb/ldr-imm.cgs
+f558e4e07d5886e42d8da753f5adc9c2 sim/testsuite/sim/arm/thumb/ldr-pc.cgs
+c41ea1558f80aa2acb0eabcfda617729 sim/testsuite/sim/arm/thumb/ldr-sprel.cgs
+4aebea08153a18c59cb89377cd0cd6e6 sim/testsuite/sim/arm/thumb/ldr.cgs
+ed9f50e3848ffa46f1f6918df9be8d9e sim/testsuite/sim/arm/thumb/ldrb-imm.cgs
+8575173ee07cb511f33d4ba01c67152a sim/testsuite/sim/arm/thumb/ldrb.cgs
+4983cedc4b15f2b1ff5dec0e01ec8705 sim/testsuite/sim/arm/thumb/ldrh-imm.cgs
+674db4c1215bd277651130d87a64a915 sim/testsuite/sim/arm/thumb/ldrh.cgs
+91148c7f6657e7dd4e227a43f6ec7cfc sim/testsuite/sim/arm/thumb/ldsb.cgs
+a2f21e7ede5faef4d9cee034a88928ae sim/testsuite/sim/arm/thumb/ldsh.cgs
+0054af714a4db9a939abde5126dabe11 sim/testsuite/sim/arm/thumb/lsl.cgs
+15cd5436a6e963ccd32b54e22c7a8b21 sim/testsuite/sim/arm/thumb/lsr.cgs
+5e5452b3461b69cffd6b8f23f4e7140c sim/testsuite/sim/arm/thumb/mov-hd-hs.cgs
+a11035d426ce96b9dd0c5b94664abcc1 sim/testsuite/sim/arm/thumb/mov-hd-rs.cgs
+b4f45a3bb387a75a6db056bef516b07b sim/testsuite/sim/arm/thumb/mov-rd-hs.cgs
+eb4d0f5b458b6c6e2a847d5c8673e3e6 sim/testsuite/sim/arm/thumb/mov.cgs
+13116b55efce4632651233f650d7dc78 sim/testsuite/sim/arm/thumb/mul.cgs
+70faca670e6c72adda93fb641c480b1f sim/testsuite/sim/arm/thumb/mvn.cgs
+8bcf6d16383ab1c7ef09466857afbc37 sim/testsuite/sim/arm/thumb/neg.cgs
+6cf3e8b7ef426b8914b47d8f7ec0a456 sim/testsuite/sim/arm/thumb/orr.cgs
+0250cdbde1a106526ec9f3b4861b8d4a sim/testsuite/sim/arm/thumb/pop-pc.cgs
+2f5ae83cda2f549b102b57569f78f8d9 sim/testsuite/sim/arm/thumb/pop.cgs
+fa00d6fb1a2926732b0eb28ae0c77c47 sim/testsuite/sim/arm/thumb/push-lr.cgs
+6656596a7ff9c3b412deae76b7e38624 sim/testsuite/sim/arm/thumb/push.cgs
+8c2c133f6c72015561ac976d7438ebe9 sim/testsuite/sim/arm/thumb/ror.cgs
+56f88f8627fec54cd96656de2828c1f2 sim/testsuite/sim/arm/thumb/sbc.cgs
+e89c8dd1ff6ae4faa4b4dff6b626a850 sim/testsuite/sim/arm/thumb/stmia.cgs
+1d8dd64ff6c23b570bbaa4d7afff968e sim/testsuite/sim/arm/thumb/str-imm.cgs
+c5c60347531697a069a2800842ee3902 sim/testsuite/sim/arm/thumb/str-sprel.cgs
+f9d716a1d842d091c8ed298f1b5b1ae9 sim/testsuite/sim/arm/thumb/str.cgs
+06e7eb2e9fd2173cafaaf5cbd62eac9b sim/testsuite/sim/arm/thumb/strb-imm.cgs
+10371b41438911cf843b9cec25c67e1d sim/testsuite/sim/arm/thumb/strb.cgs
+ca60a519f04c50e1e8b316b49a7e4e9d sim/testsuite/sim/arm/thumb/strh-imm.cgs
+62c721a2ca73cdae002eba9841199014 sim/testsuite/sim/arm/thumb/strh.cgs
+c1a57f0215877e8992c61e54d2446278 sim/testsuite/sim/arm/thumb/sub-sp.cgs
+acb920479677a598ba5544db15addd06 sim/testsuite/sim/arm/thumb/sub.cgs
+1e72cd9a9e01d015ac44deadf9a8eb0d sim/testsuite/sim/arm/thumb/subi.cgs
+4ed486b285f8dd6272168154f0e7df58 sim/testsuite/sim/arm/thumb/subi8.cgs
+84459a09af60b4a3de23776a8bf0adcc sim/testsuite/sim/arm/thumb/swi.cgs
+93c6ea09186e29b651ae931a0ba07760 sim/testsuite/sim/arm/thumb/testutils.inc
+c45fc39f2f692299fe4bf891668833d8 sim/testsuite/sim/arm/thumb/tst.cgs
+f2c30ed356d350356f1edcb1484c6f57 sim/testsuite/sim/arm/xscale/blx.cgs
+64304cffe7caf82616cedaf41498ac45 sim/testsuite/sim/arm/xscale/mia.cgs
+03c925a228ba4258f15e01eef3fceb5b sim/testsuite/sim/arm/xscale/miaph.cgs
+ff267c0f1ed5b05d883ec3584f8bb6f9 sim/testsuite/sim/arm/xscale/miaxy.cgs
+0a98c2c1558ae770328e84c180ac3616 sim/testsuite/sim/arm/xscale/mra.cgs
+f0a99de3c5c47c3aa91c95c25879b41f sim/testsuite/sim/arm/xscale/testutils.inc
+c041e18e1c56fcb743b7e2c2d8ca5ec5 sim/testsuite/sim/arm/xscale/xscale.exp
+503d6096668d67d46c257e7895d84d31 sim/testsuite/sim/fr30/add.cgs
+692e2c452c77ecbc6b74405fbfb8764f sim/testsuite/sim/fr30/add.ms
+726473e3a587a7dc454557dc8b4c43db sim/testsuite/sim/fr30/add2.cgs
+ae7aebd1064ea16900d3b009feddd60d sim/testsuite/sim/fr30/addc.cgs
+9d0cb44436f746f3c9888587a0705941 sim/testsuite/sim/fr30/addn.cgs
+030942418ed8e981370a1d4e1489b9b2 sim/testsuite/sim/fr30/addn2.cgs
+8f9d88e4c545aca64898cbd90c3d16a4 sim/testsuite/sim/fr30/addsp.cgs
+78fc35acbc4a167797bd863fd991a785 sim/testsuite/sim/fr30/allinsn.exp
+8987709e3323037c23eb5559a2a05b79 sim/testsuite/sim/fr30/and.cgs
+5948be319fc5808a6b19793d9e5bbc7d sim/testsuite/sim/fr30/andb.cgs
+85c3eb5c04a5558fa911df3e30e3679b sim/testsuite/sim/fr30/andccr.cgs
+d33f46c321f6a6972442f4bade06656a sim/testsuite/sim/fr30/andh.cgs
+3daf2597d21b8195e0c0a1650be412df sim/testsuite/sim/fr30/asr.cgs
+6cc8644c6594267688e0cfa178a7bd73 sim/testsuite/sim/fr30/asr2.cgs
+63da4dc66d15a7647a2b0612f35a8564 sim/testsuite/sim/fr30/bandh.cgs
+3838077d837c2b8656d8a398cbf96482 sim/testsuite/sim/fr30/bandl.cgs
+c2961d1998d0f226e73fb2f0c8b37746 sim/testsuite/sim/fr30/bc.cgs
+fd0034e39e50a5ad93071dbc6718e3b6 sim/testsuite/sim/fr30/beorh.cgs
+0c254917d1438ef4f7cb6dbd5683cf75 sim/testsuite/sim/fr30/beorl.cgs
+e76365e82b93ee554e15a75585b0c27c sim/testsuite/sim/fr30/beq.cgs
+528b0bd224d9631b14de438842a363c4 sim/testsuite/sim/fr30/bge.cgs
+8656edc8211fb004093f703158a7c9ee sim/testsuite/sim/fr30/bgt.cgs
+29f7caeaad4350f3f89236f16849b148 sim/testsuite/sim/fr30/bhi.cgs
+825b7df0d31175f17fb30a27a90d6f05 sim/testsuite/sim/fr30/ble.cgs
+fa428bc4576d35a4d06fe83db66f1e20 sim/testsuite/sim/fr30/bls.cgs
+107058d96ac7c888d901300eb006d5c3 sim/testsuite/sim/fr30/blt.cgs
+11ca26e18c1fa7c05d9980f28911fc84 sim/testsuite/sim/fr30/bn.cgs
+f419d8740920121331afb15e71725c80 sim/testsuite/sim/fr30/bnc.cgs
+b4e156196e642664ce263f393a7f53be sim/testsuite/sim/fr30/bne.cgs
+78f28bc2aa59a4a6dc4cdd7971e98108 sim/testsuite/sim/fr30/bno.cgs
+00ced4e4a8d48e061be334729bcf9972 sim/testsuite/sim/fr30/bnv.cgs
+93d8f4110bc336023847d2e425d27fac sim/testsuite/sim/fr30/borh.cgs
+51632bbf7fcc2d274e4b7d4ee75b9786 sim/testsuite/sim/fr30/borl.cgs
+5f0977ee9d55754ffceaf3dc2242781d sim/testsuite/sim/fr30/bp.cgs
+118242b7ecdaa35cdce8a8504e75b4be sim/testsuite/sim/fr30/bra.cgs
+50c15ddbc5bfffd5f9b4784313984dd1 sim/testsuite/sim/fr30/btsth.cgs
+c0e8ab52947ed9bccc6646be37f2b82e sim/testsuite/sim/fr30/btstl.cgs
+b3436c5fa08665c3fd9b9d103bbfd4ca sim/testsuite/sim/fr30/bv.cgs
+1fb7a6a1cbbdff7ba6882c47dc8b3071 sim/testsuite/sim/fr30/call.cgs
+d5c3720a8d9a8fa88fb45d97681466d2 sim/testsuite/sim/fr30/cmp.cgs
+5fc1b6eee6a98d786ad146de39bee17e sim/testsuite/sim/fr30/cmp2.cgs
+92b6ed80cfaf734393514a354f558e12 sim/testsuite/sim/fr30/copld.cgs
+68e0c1e7bd73024e03d90e17d1b479e7 sim/testsuite/sim/fr30/copop.cgs
+d82e1c778335479eb3257be5f4027f60 sim/testsuite/sim/fr30/copst.cgs
+8f3d3ac55197c8d27a1bb6022ce7ab9c sim/testsuite/sim/fr30/copsv.cgs
+1986f8b31251f3fcfead747f2fbc2067 sim/testsuite/sim/fr30/div.ms
+8bca5d07304281074232cf501f58d578 sim/testsuite/sim/fr30/div0s.cgs
+9497d9229865b30c86f4e77508a9a406 sim/testsuite/sim/fr30/div0u.cgs
+42628131079d04c855f5e218a162c210 sim/testsuite/sim/fr30/div1.cgs
+2d45aaaebfe96a478d94442f475255dd sim/testsuite/sim/fr30/div2.cgs
+82b175871b9a3802f2b0141fdbd69314 sim/testsuite/sim/fr30/div3.cgs
+2ae5a90062cafe57f759112f5b2f3b06 sim/testsuite/sim/fr30/div4s.cgs
+18a90aaef63c891698afe734d2152d18 sim/testsuite/sim/fr30/dmov.cgs
+55b2418400196e2f3a85b8e6b696a252 sim/testsuite/sim/fr30/dmovb.cgs
+1a350c8e3f57a176585fc796b07bfc7d sim/testsuite/sim/fr30/dmovh.cgs
+1df39f183df8aeeb7fa41d92384a0ad9 sim/testsuite/sim/fr30/enter.cgs
+bc265d868045395c100b7c74d441979a sim/testsuite/sim/fr30/eor.cgs
+63ca215997d767d234ca89fcd3e11968 sim/testsuite/sim/fr30/eorb.cgs
+9f77138b83e182472a14212e5bb72352 sim/testsuite/sim/fr30/eorh.cgs
+67ece84ba59ec30e07e99a8dfb888f56 sim/testsuite/sim/fr30/extsb.cgs
+98f0923dc897604e64e47dd027c2fab1 sim/testsuite/sim/fr30/extsh.cgs
+006acd8b3fbfdfdc9cf751d3551da65b sim/testsuite/sim/fr30/extub.cgs
+6b9b96096efcac0f5ee86ff1b1327da4 sim/testsuite/sim/fr30/extuh.cgs
+76cd07dd7c78722fbbfa49bd94b5c61b sim/testsuite/sim/fr30/hello.ms
+a447d626d0829c31c4cc72b9aca610bc sim/testsuite/sim/fr30/int.cgs
+c7f3e31654d7134dfec197a23c612f8d sim/testsuite/sim/fr30/inte.cgs
+a92cc956b699bbdead9c1e8ea21b7d85 sim/testsuite/sim/fr30/jmp.cgs
+bd02ed7b7c8470f6853a555a57818cb3 sim/testsuite/sim/fr30/ld.cgs
+d9bcff3a1f3a6885615cb81215deb73d sim/testsuite/sim/fr30/ldi20.cgs
+5c29b0babb4c478e18950a01250bacdf sim/testsuite/sim/fr30/ldi32.cgs
+05c014e0472c8041119ea95bda37df65 sim/testsuite/sim/fr30/ldi8.cgs
+291df7a8065e554654d635d4319a6e07 sim/testsuite/sim/fr30/ldm0.cgs
+40b06cc66fd096915a199de617efa043 sim/testsuite/sim/fr30/ldm1.cgs
+980de17f49e0206c409122a710bd9660 sim/testsuite/sim/fr30/ldres.cgs
+cd540be2b820c7304d49a2cd4c804ebc sim/testsuite/sim/fr30/ldub.cgs
+7f827594dfa2a9ea9cbdb822808bb96e sim/testsuite/sim/fr30/lduh.cgs
+f4b6c297ead375254a31836c88c758db sim/testsuite/sim/fr30/leave.cgs
+ff01a6642b097f295e29b8aad506bf20 sim/testsuite/sim/fr30/lsl.cgs
+e5b073abade7a63209ab21e8757714e5 sim/testsuite/sim/fr30/lsl2.cgs
+fac808112158b0d7c9a972b5c1e51ad9 sim/testsuite/sim/fr30/lsr.cgs
+8fb50d3723a8e4fda2cca68f8138fc68 sim/testsuite/sim/fr30/lsr2.cgs
+58553f1bced962c2d9f26ff2f53aecfc sim/testsuite/sim/fr30/misc.exp
+cd116a2a1dac5e397ecc2f7456053564 sim/testsuite/sim/fr30/mov.cgs
+e6e56816b0dcb650c26b46a33cb1ffac sim/testsuite/sim/fr30/mul.cgs
+4e62467dd71697f7cf6d64cebf2531e8 sim/testsuite/sim/fr30/mulh.cgs
+201ea7a49f59a0a5e628e9b549bfb5b8 sim/testsuite/sim/fr30/mulu.cgs
+ee0c0d6979b1682c427b387664c204a8 sim/testsuite/sim/fr30/muluh.cgs
+68d1886400abacb8a7f24d72bda2a966 sim/testsuite/sim/fr30/nop.cgs
+c8347c5b0effef1e42f0249483e5ac6a sim/testsuite/sim/fr30/or.cgs
+2cf5b46fe78a0e966c03c134642e61c6 sim/testsuite/sim/fr30/orb.cgs
+d01fa8a22cb8df995a868145d71bbf94 sim/testsuite/sim/fr30/orccr.cgs
+8557874b84d96137c9d2163f29a20473 sim/testsuite/sim/fr30/orh.cgs
+89bf2353814e13f2d5a94d209ace80f3 sim/testsuite/sim/fr30/ret.cgs
+16372b76ce969bd0041202b277ab1aae sim/testsuite/sim/fr30/reti.cgs
+ae8fa268a41ffb274a7a89b9f7344ac3 sim/testsuite/sim/fr30/st.cgs
+6c4bf429941803c250acd9ed35221ec8 sim/testsuite/sim/fr30/stb.cgs
+32b42ce0a2b13161bf8e4d8cab413410 sim/testsuite/sim/fr30/sth.cgs
+5e026ff1027b8aa7cb374c51b5c4b9e8 sim/testsuite/sim/fr30/stilm.cgs
+fae958eef826c19e4e7640eb0378c0c9 sim/testsuite/sim/fr30/stm0.cgs
+5f28ff21c8db4465c66df254b3a6d631 sim/testsuite/sim/fr30/stm1.cgs
+546a174bd7aa7dfa4f54ba99e5b2d617 sim/testsuite/sim/fr30/stres.cgs
+3ad5b0fdc53e83258fadc664f63c6a82 sim/testsuite/sim/fr30/sub.cgs
+f32638a3919a1385e630a7e29518e0ed sim/testsuite/sim/fr30/subc.cgs
+da584f1cf2dcd0f85046a64bc5d9ba5e sim/testsuite/sim/fr30/subn.cgs
+c174cd3fd5b8667dbc7b7741ec7449e3 sim/testsuite/sim/fr30/testutils.inc
+9d0e5f42019df498994f84948f9de403 sim/testsuite/sim/fr30/xchb.cgs
+9f35e5c8475a3dce4d3d1f86192b757f sim/testsuite/sim/frv/add.cgs
+24091903403ffb172b0b81cfbb3f331e sim/testsuite/sim/frv/add.pcgs
+0328850bbb204540e39224902cea7437 sim/testsuite/sim/frv/addcc.cgs
+1e7f2deead6fb5c78f146ae3eb2fc6be sim/testsuite/sim/frv/addi.cgs
+30964df0b57f2b91f67fc38a30d8e814 sim/testsuite/sim/frv/addicc.cgs
+d2ab686875a7fa6635f150cf02ff06f9 sim/testsuite/sim/frv/addx.cgs
+0946412ade0a468bd29c482a88af3c60 sim/testsuite/sim/frv/addxcc.cgs
+bb0118ec08792d6499ce7742161f206f sim/testsuite/sim/frv/addxi.cgs
+02991b6e743da14fcd82acaa74ad2de3 sim/testsuite/sim/frv/addxicc.cgs
+72be282014f29ceb549bafd72ca6590c sim/testsuite/sim/frv/allinsn.exp
+fe0ecb3cd4f9a5a2a8cd1b994f8e8ae2 sim/testsuite/sim/frv/and.cgs
+558c0693de0aa42e5ba756ef35228332 sim/testsuite/sim/frv/andcc.cgs
+7436eebb11c6129d8a06aa52d0641d19 sim/testsuite/sim/frv/andcr.cgs
+2fdea54dc1608b57111f0b1d657b3daa sim/testsuite/sim/frv/andi.cgs
+54e056f54d116cde6e23ee7dee9a9c8b sim/testsuite/sim/frv/andicc.cgs
+4a13d5d2947c3543c94581ba88ec7fc4 sim/testsuite/sim/frv/andncr.cgs
+cf73edecc782c3ef0b7548f1acb34cd5 sim/testsuite/sim/frv/bar.cgs
+b03ca91fbf4d98089e108f2fe411eecb sim/testsuite/sim/frv/bc.cgs
+36d2a277daae79b65a1fe73b38c101ba sim/testsuite/sim/frv/bcclr.cgs
+4fe0320394ce9fd521b0b903b37a44de sim/testsuite/sim/frv/bceqlr.cgs
+17b1b6dc979b707b15d4d415b6a8c50a sim/testsuite/sim/frv/bcgelr.cgs
+ad6bad34a15a4f2986566b50e2af52b8 sim/testsuite/sim/frv/bcgtlr.cgs
+9b2a570d81405ae96edd05841a00340c sim/testsuite/sim/frv/bchilr.cgs
+bd1949fa6a0cbbd0faee3d33a7d2ed7b sim/testsuite/sim/frv/bclelr.cgs
+8a77e7659d777d6c0d67e89e341cf17c sim/testsuite/sim/frv/bclr.cgs
+e3f8edcf3d2202102c308c006b574282 sim/testsuite/sim/frv/bclslr.cgs
+73a5313d89e6d5975be48f3e2522c1a2 sim/testsuite/sim/frv/bcltlr.cgs
+62439f50d31a64a7d77bfe8d242d68c2 sim/testsuite/sim/frv/bcnclr.cgs
+45750ad0543745a1b21a7b795a774105 sim/testsuite/sim/frv/bcnelr.cgs
+5032a5008a230358b8434e010fa7aa66 sim/testsuite/sim/frv/bcnlr.cgs
+e9aafacc4f7c85928dd1c32c5c79fc5a sim/testsuite/sim/frv/bcnolr.cgs
+b0d3f8840cbd815c5cf1fed7f60b95ac sim/testsuite/sim/frv/bcnvlr.cgs
+34c1f1091b4c9bebc5fd6e10d045f570 sim/testsuite/sim/frv/bcplr.cgs
+318cb22eb343ae2ba7c0a11ec86755f3 sim/testsuite/sim/frv/bcralr.cgs
+93142a00f792c55ff26c67e4495c3ee8 sim/testsuite/sim/frv/bctrlr.cgs
+37f80752cbc102b0e3eebab206a7e851 sim/testsuite/sim/frv/bcvlr.cgs
+5f883fbcb2224a26bc0e0d7eb91fd2de sim/testsuite/sim/frv/beq.cgs
+a49be0c11999c9c5fe7164a2d478236c sim/testsuite/sim/frv/beqlr.cgs
+d2ca7d2383745ede57de7cf3a71b250b sim/testsuite/sim/frv/bge.cgs
+0d8bd8099d69931cea52745c2fd79b8b sim/testsuite/sim/frv/bgelr.cgs
+df584e46e6bbe3d1636c1fbaa73ca746 sim/testsuite/sim/frv/bgt.cgs
+7e5adf4d17b96ce4a3b36beea51aadc6 sim/testsuite/sim/frv/bgtlr.cgs
+894db98a371eaba135a686990f22f504 sim/testsuite/sim/frv/bhi.cgs
+58728788baa01be3e6482ab14b5fde4f sim/testsuite/sim/frv/bhilr.cgs
+3da93d4f6c18f18193c0441a79758bcc sim/testsuite/sim/frv/ble.cgs
+e54bc9be577ed53f98a7256e02292a9f sim/testsuite/sim/frv/blelr.cgs
+313bac7f8246cca4710202da37d93d37 sim/testsuite/sim/frv/bls.cgs
+b04e822dac50d26e600e9af54cc86907 sim/testsuite/sim/frv/blslr.cgs
+aeccfedc8dc931ff8b70da7c99c2236a sim/testsuite/sim/frv/blt.cgs
+b32fc8a8e6bba1b163e798c7a6b2998a sim/testsuite/sim/frv/bltlr.cgs
+851005c4ef6143a0dc488d4a100b97f7 sim/testsuite/sim/frv/bn.cgs
+a26faa5267491071d341abedcc58aa36 sim/testsuite/sim/frv/bnc.cgs
+f91ccc0eb4e839737d94f68601bf130f sim/testsuite/sim/frv/bnclr.cgs
+8b544d33708f95c5fe86075bfc046ba3 sim/testsuite/sim/frv/bne.cgs
+da1d1539bcb135ec8ce2fa2df168cd18 sim/testsuite/sim/frv/bnelr.cgs
+31e7cd50ae42d84c7edbb16ec1824569 sim/testsuite/sim/frv/bnlr.cgs
+3014022934a14b3431fdacf8e86dd3eb sim/testsuite/sim/frv/bno.cgs
+8f07983738e8be6e8f294385e90a83f1 sim/testsuite/sim/frv/bnolr.cgs
+480ed9fb8591ba5cba8c36bbf8fac25b sim/testsuite/sim/frv/bnv.cgs
+078c55334418476eb782ff3b071fc106 sim/testsuite/sim/frv/bnvlr.cgs
+6e0ed99106e53f1ae7c54bd6a15d2a7d sim/testsuite/sim/frv/bp.cgs
+af01f45076997b2efc4cbed1bfbeb90f sim/testsuite/sim/frv/bplr.cgs
+7d76bf8128cc9482f2de7d01e2bde23a sim/testsuite/sim/frv/bra.cgs
+36ccbee5f8a7659d1403b57bda54a1cf sim/testsuite/sim/frv/bralr.cgs
+1faedf52637eb93c36507f38fd31fea3 sim/testsuite/sim/frv/branch.pcgs
+67b49f46f325d357092e83a5af86ffe8 sim/testsuite/sim/frv/break.cgs
+9868adbc8297b59031bb110c1104e524 sim/testsuite/sim/frv/bv.cgs
+1506bd2f46dbdf8b5580412cc36cc631 sim/testsuite/sim/frv/bvlr.cgs
+54b2d852374130520e29e72dc46923e0 sim/testsuite/sim/frv/cadd.cgs
+9ebd87890c8a7abc680822709889778c sim/testsuite/sim/frv/caddcc.cgs
+36b77ec6afe8955468cfc59058d7e96a sim/testsuite/sim/frv/call.cgs
+05a1ec4efd6909bce7ced2cff0a0d8c8 sim/testsuite/sim/frv/call.pcgs
+6c696a162425d51ed1a198eadc9e8ec6 sim/testsuite/sim/frv/callil.cgs
+5900af0d1f33281e6a8d166d3cabe74a sim/testsuite/sim/frv/calll.cgs
+6833a0f9a6a97eca6ec71259ea075028 sim/testsuite/sim/frv/cand.cgs
+35609b2536c1c21599e2d70a762854f6 sim/testsuite/sim/frv/candcc.cgs
+794be640f3ea38845a7fb677c250fe48 sim/testsuite/sim/frv/ccalll.cgs
+61d311d36b7dec576d8be1a6a047278d sim/testsuite/sim/frv/cckc.cgs
+e7a1ad746f682025747fa48379b5db6f sim/testsuite/sim/frv/cckeq.cgs
+21793c07586326f7d5b7caeb20faf21b sim/testsuite/sim/frv/cckge.cgs
+511bee637d7a77e1f4ead6e790993d68 sim/testsuite/sim/frv/cckgt.cgs
+ad7585e6f6dbc249f1e67deba9847034 sim/testsuite/sim/frv/cckhi.cgs
+1f8696a6d62df0c7ee21c40e74d2af30 sim/testsuite/sim/frv/cckle.cgs
+2974e1e8788d707888a2c3ff248a0d82 sim/testsuite/sim/frv/cckls.cgs
+5393775815f48e4a5a811b3a06ff8503 sim/testsuite/sim/frv/ccklt.cgs
+91e3dc0afab2fdfca7731c7e1f37e33f sim/testsuite/sim/frv/cckn.cgs
+a659a5c06a90b61548ad0d23636f740b sim/testsuite/sim/frv/ccknc.cgs
+40115dcc72d0b6f1b5b4701a63e94c83 sim/testsuite/sim/frv/cckne.cgs
+da2ea0628931ee759747b3b1568f9e95 sim/testsuite/sim/frv/cckno.cgs
+1516ca30ed3dda235da364d46c38d2a1 sim/testsuite/sim/frv/ccknv.cgs
+dd7b86dd559bc919891c419cc5b9eb45 sim/testsuite/sim/frv/cckp.cgs
+b0b3ba45dce79cce5d0db607ed12fbfe sim/testsuite/sim/frv/cckra.cgs
+0c3aa7b3b5fd1c05678011c190e83144 sim/testsuite/sim/frv/cckv.cgs
+999bafc99f41d16b6bd3b925cf296de0 sim/testsuite/sim/frv/ccmp.cgs
+ffdac6d343d018ba34d4952027680104 sim/testsuite/sim/frv/cfabss.cgs
+7b8111a1958ac7ac0609e3ec19946402 sim/testsuite/sim/frv/cfadds.cgs
+a557f55cfe20662991a594673e5a877b sim/testsuite/sim/frv/cfckeq.cgs
+ccbed047cb7e704f8caefbf30b21d58e sim/testsuite/sim/frv/cfckge.cgs
+7b350a57e6efb69056eeffc36aa0cac4 sim/testsuite/sim/frv/cfckgt.cgs
+34a484991db89cb85939b4735fd01d7d sim/testsuite/sim/frv/cfckle.cgs
+055fa9b5ef1f3c1f955737457b0f3430 sim/testsuite/sim/frv/cfcklg.cgs
+c3fbed74046a3c4d5d74af309a283001 sim/testsuite/sim/frv/cfcklt.cgs
+42256da6637466abfe0f07b1103c7139 sim/testsuite/sim/frv/cfckne.cgs
+bff6dd1636bea003ff556d16f1e3f843 sim/testsuite/sim/frv/cfckno.cgs
+d8c97eebc3c3db0b2962b1d7181cc6c6 sim/testsuite/sim/frv/cfcko.cgs
+124ee6149a335aca9a615e6e9e9521ff sim/testsuite/sim/frv/cfckra.cgs
+6dd0a3407bccbe944de3004234e1ee11 sim/testsuite/sim/frv/cfcku.cgs
+d0ac23eed64316704af3b22028e3e476 sim/testsuite/sim/frv/cfckue.cgs
+506b3aaeb2f55f7313b18756c9ea8897 sim/testsuite/sim/frv/cfckug.cgs
+c0d65d42e391ceb55e2d6eed4954f643 sim/testsuite/sim/frv/cfckuge.cgs
+2dce4079bac9e873cc2f7466bbdbc0bd sim/testsuite/sim/frv/cfckul.cgs
+697ec5d0eb83f0aa0c438264e7dacf74 sim/testsuite/sim/frv/cfckule.cgs
+4ae9085c410dd43f5a03a680a8ef06f0 sim/testsuite/sim/frv/cfcmps.cgs
+255041537a2ba5cddbc94a66463c52ab sim/testsuite/sim/frv/cfdivs.cgs
+d8e85f1e2dfaa87480b812c7c03ee19b sim/testsuite/sim/frv/cfitos.cgs
+241fa1bef3f4eb4e60aebeaa3a5e5d8e sim/testsuite/sim/frv/cfmadds.cgs
+4fa1060d3ea708c05623eaa8fa23a4fd sim/testsuite/sim/frv/cfmas.cgs
+b69a810fc6f3f907c57797a5721333fd sim/testsuite/sim/frv/cfmovs.cgs
+258db7edbd93cc7f09cde29e3522194e sim/testsuite/sim/frv/cfmss.cgs
+8efb2a5d93915406532ba43d46c08545 sim/testsuite/sim/frv/cfmsubs.cgs
+ccde36a3a60f282ea7e7581d6ddbe200 sim/testsuite/sim/frv/cfmuls.cgs
+0eb9d6f24940fa1b3a290ee7f83529e6 sim/testsuite/sim/frv/cfnegs.cgs
+e6cce9c3b04ed7fd801dafb45bcdd866 sim/testsuite/sim/frv/cfsqrts.cgs
+654e92ca5c279eff83c44a07b5a4f8bd sim/testsuite/sim/frv/cfstoi.cgs
+d6e2c99d07b9c1a5fb5869dd9aecc1a4 sim/testsuite/sim/frv/cfsubs.cgs
+11bfcfb4b6f70c5075adaa4f37dca943 sim/testsuite/sim/frv/cjmpl.cgs
+e3edb4635dd416fa50ea0e1628a69aea sim/testsuite/sim/frv/ckc.cgs
+bd306d227534038e358e212748f86d46 sim/testsuite/sim/frv/ckeq.cgs
+6829b406203cc09d6ac699fec2378bad sim/testsuite/sim/frv/ckge.cgs
+c32d71a426bc21b198975069f0bc3503 sim/testsuite/sim/frv/ckgt.cgs
+8496d10703a6df931f2b4ea768c69356 sim/testsuite/sim/frv/ckhi.cgs
+5efca9c9c6f6785859bd2ed1ab619325 sim/testsuite/sim/frv/ckle.cgs
+2f2d7f51d4276d8bc6c7a559cf40358f sim/testsuite/sim/frv/ckls.cgs
+325a426583fc25d49f02863c763aeb84 sim/testsuite/sim/frv/cklt.cgs
+5724440a0342cfb9923003f93f4e9c28 sim/testsuite/sim/frv/ckn.cgs
+b0fa5261302915fed6a0abb4165bdb3e sim/testsuite/sim/frv/cknc.cgs
+2377457fe2384816953905fda6c3d04b sim/testsuite/sim/frv/ckne.cgs
+1cbff10c95fb9390a7cc4d56fef5f794 sim/testsuite/sim/frv/ckno.cgs
+ad9476d15f761b15a7243c9030efa135 sim/testsuite/sim/frv/cknv.cgs
+6b8470231d2eb04c58135b6a02fd63cb sim/testsuite/sim/frv/ckp.cgs
+5c41b0e945d708f91752456b93ca9c8d sim/testsuite/sim/frv/ckra.cgs
+d0cadfc6114ffc4c49bd0b7cf87984dc sim/testsuite/sim/frv/ckv.cgs
+eedecfb8fe25588cda9c858cec87c9e4 sim/testsuite/sim/frv/cld.cgs
+82952c2b9fbbc99ed421717e4ca1e9be sim/testsuite/sim/frv/cldbf.cgs
+b61f258f8679789df4df0f96f085ed27 sim/testsuite/sim/frv/cldbfu.cgs
+bfc76c12370aafb393d878212832d3e3 sim/testsuite/sim/frv/cldd.cgs
+c466ade998b308dc18869d2a2d2f3ae5 sim/testsuite/sim/frv/clddf.cgs
+4494a0e9c7fd903a3280a5baec16e6db sim/testsuite/sim/frv/clddfu.cgs
+1dbf3b1f587b8fde305387c2a6d7488c sim/testsuite/sim/frv/clddu.cgs
+d7fefcc42f8ee556fc3e29e07866f54a sim/testsuite/sim/frv/cldf.cgs
+01c147956ed40b80f7f01399bd71f33f sim/testsuite/sim/frv/cldfu.cgs
+7f272aa06c9d1d01570e93ccfc3bed5d sim/testsuite/sim/frv/cldhf.cgs
+1147cc9e693e642971e9920b10936733 sim/testsuite/sim/frv/cldhfu.cgs
+00bb5f98862bbebc770fac0fa658bf27 sim/testsuite/sim/frv/cldq.cgs
+cbf21bfce7b3ce694a9a0ffbecdd5edf sim/testsuite/sim/frv/cldqu.cgs
+60dfef5c59d307cd1efd15c4403530ad sim/testsuite/sim/frv/cldsb.cgs
+2311d8e2e1155bc0747ab69d1d80020c sim/testsuite/sim/frv/cldsbu.cgs
+76fcbc22cb7f93f51d833bd012609086 sim/testsuite/sim/frv/cldsh.cgs
+218e7bf5cef1de12c72a7b41e0734233 sim/testsuite/sim/frv/cldshu.cgs
+91fd679b72e10313567ecee40d839288 sim/testsuite/sim/frv/cldu.cgs
+2b92477d71c35dbc5340bf6cf73436c4 sim/testsuite/sim/frv/cldub.cgs
+59af60628ef7e7f6c89aa5b2fa0c34c2 sim/testsuite/sim/frv/cldubu.cgs
+b3a1a12789fd5e052662744d3bd0a912 sim/testsuite/sim/frv/clduh.cgs
+f7adffe89325460b83af4ef27b83a02e sim/testsuite/sim/frv/clduhu.cgs
+7640dbf388ab7b7e4462b20d93ca0dca sim/testsuite/sim/frv/clrfa.cgs
+1ff43ea60f446681dd0636f4abf0afaf sim/testsuite/sim/frv/clrfr.cgs
+1162b46f1c6271d41d44fd0376fd0abd sim/testsuite/sim/frv/clrga.cgs
+3a258f66b006c6af176013d28706f114 sim/testsuite/sim/frv/clrgr.cgs
+6a19cdc6d3c89ca5145cd888160feea0 sim/testsuite/sim/frv/cmaddhss.cgs
+f552807622d2ead6a4c3c72b6ab6ea1c sim/testsuite/sim/frv/cmaddhus.cgs
+b0ae2b6d72c1546e70b77d0f906ca816 sim/testsuite/sim/frv/cmand.cgs
+054aeba615c6c341369854f1405d85d8 sim/testsuite/sim/frv/cmbtoh.cgs
+c006cffe51ad60e2d97bfe726e6efc27 sim/testsuite/sim/frv/cmbtohe.cgs
+e322b79b6193bc8b98fdf7d2164e1242 sim/testsuite/sim/frv/cmcpxis.cgs
+2d2b7584e0bb578df1f9589e4e90bce6 sim/testsuite/sim/frv/cmcpxiu.cgs
+fb274f110b2b0e732c8ab6b0567641da sim/testsuite/sim/frv/cmcpxrs.cgs
+2a371679272b85c51ff58344a6870ef8 sim/testsuite/sim/frv/cmcpxru.cgs
+f8de97a7353abe4fe732d79898771e06 sim/testsuite/sim/frv/cmexpdhd.cgs
+c0b5d47d5b02cc1f2017b7642a70d544 sim/testsuite/sim/frv/cmexpdhw.cgs
+031b21c3201bce5ff37ac1d2087209c8 sim/testsuite/sim/frv/cmhtob.cgs
+4907fd3e32af4b4b10ed57c593639002 sim/testsuite/sim/frv/cmmachs.cgs
+12c4a175cb447af16dd27310f13fe496 sim/testsuite/sim/frv/cmmachu.cgs
+f394652f9ebf77a1d90b8a114793c2cb sim/testsuite/sim/frv/cmmulhs.cgs
+509ea4a10500e161ed7a4c16dca03eed sim/testsuite/sim/frv/cmmulhu.cgs
+fe9af3628dda1a7e0478b27afcb4a903 sim/testsuite/sim/frv/cmnot.cgs
+d23dcfb1cdc685b13e28f46e60297128 sim/testsuite/sim/frv/cmor.cgs
+c23d94eb48818d1a8830ea6d0edc3260 sim/testsuite/sim/frv/cmov.cgs
+50823aeb4369412ff15e1c422ea6d8f7 sim/testsuite/sim/frv/cmovfg.cgs
+294f97c82070648f417c81cefbf0d68e sim/testsuite/sim/frv/cmovfgd.cgs
+a92e4825d2c41be84a96f2f6db7de29b sim/testsuite/sim/frv/cmovgf.cgs
+0772a396d1b99a6fc342b4f3d355d18c sim/testsuite/sim/frv/cmovgfd.cgs
+fb9380da5f21f1be28670b94115e7cb2 sim/testsuite/sim/frv/cmp.cgs
+bd0fbf9e7faa375603574f1a40665865 sim/testsuite/sim/frv/cmpb.cgs
+0b2e49d6ce9f4d51307d7a0c0884c357 sim/testsuite/sim/frv/cmpba.cgs
+3b2a2c6753bd7ff55bc524a863d3a3cb sim/testsuite/sim/frv/cmpi.cgs
+72215397d3a25089fcadc96d0449fa9d sim/testsuite/sim/frv/cmqmachs.cgs
+891b8ae9013d787e9abf3f3980a93682 sim/testsuite/sim/frv/cmqmachu.cgs
+7e7ca53ba30cdcc99c94cd76e31edbfd sim/testsuite/sim/frv/cmqmulhs.cgs
+9a28ed90097013dbe6c10888f811edec sim/testsuite/sim/frv/cmqmulhu.cgs
+a030edea39f27d8535b72eab791a946c sim/testsuite/sim/frv/cmsubhss.cgs
+571559015608fda8e86c36266d8aba4c sim/testsuite/sim/frv/cmsubhus.cgs
+8b11d75d92bff2f80d736079756072af sim/testsuite/sim/frv/cmxor.cgs
+d8c6afc2ab9d2f02351d88640635698f sim/testsuite/sim/frv/cnot.cgs
+2521bd2ee748d58fdae65f585b453033 sim/testsuite/sim/frv/commitfa.cgs
+9f7ea5df90e576f10d78cdac9cc6ef50 sim/testsuite/sim/frv/commitfr.cgs
+122ad6f12a5ab84bec5262e1af02c9f1 sim/testsuite/sim/frv/commitga.cgs
+1abb897f3ac03712dcaf0fa415a85bb3 sim/testsuite/sim/frv/commitgr.cgs
+d68f7809049059eb9fdbdaef18d03edd sim/testsuite/sim/frv/cop1.cgs
+048a96dcaad276073b908e6c8f4d9189 sim/testsuite/sim/frv/cop2.cgs
+50daedd569566b5f5fd6030c9c961735 sim/testsuite/sim/frv/cor.cgs
+b1bfeba9317d62d449126bee0f7fa720 sim/testsuite/sim/frv/corcc.cgs
+ed7de1b15d6c5535e9d56ff902749a49 sim/testsuite/sim/frv/cscan.cgs
+7482a3b75fcf89d6eac98c42d36722e9 sim/testsuite/sim/frv/csdiv.cgs
+6cc09cbce0f4709083b896f39eb8788b sim/testsuite/sim/frv/csll.cgs
+f58b45613ae0cc85e07099e0b176a130 sim/testsuite/sim/frv/csllcc.cgs
+0e6828ab5a28105f1606bfcea5961a53 sim/testsuite/sim/frv/csmul.cgs
+97562af5611f19959e068464c8b152c0 sim/testsuite/sim/frv/csmulcc.cgs
+8916d2cace8900da8a1d671e9a0ea2b7 sim/testsuite/sim/frv/csra.cgs
+bff2fec4c10ff1cc52f6708fa1cd9e5a sim/testsuite/sim/frv/csracc.cgs
+eb2f7e79db41af0b45c8182f92563397 sim/testsuite/sim/frv/csrl.cgs
+d18c2b792211080ccc434210ebb67ba9 sim/testsuite/sim/frv/csrlcc.cgs
+05e30ee19e5c52285f897986f1d22634 sim/testsuite/sim/frv/cst.cgs
+fea6bcd449bfa45bc4f7811913f3bc14 sim/testsuite/sim/frv/cstb.cgs
+29bcdb426188a5bb155dbee07ea1e527 sim/testsuite/sim/frv/cstbf.cgs
+699c2363b47a8ac1c7fdd3607503f872 sim/testsuite/sim/frv/cstbfu.cgs
+9d42de2773bcddcd37eafe1bf37aba97 sim/testsuite/sim/frv/cstbu.cgs
+c0fa479773c62b0865cf7f6646562284 sim/testsuite/sim/frv/cstd.cgs
+4dd6b1d7898b43e9ec3d140c49342862 sim/testsuite/sim/frv/cstdf.cgs
+785f29fcfbdef6e93f772f32635daec4 sim/testsuite/sim/frv/cstdfu.cgs
+91bdb77382d1406d5f98e2331c7a4ff5 sim/testsuite/sim/frv/cstdu.cgs
+bc2f5ebb5a8ed58952e9c92d80b5e5ea sim/testsuite/sim/frv/cstf.cgs
+4659f8e9e4a139ab3d797621c23c6adf sim/testsuite/sim/frv/cstfu.cgs
+46c386b55d7d762b12cf33a832c34e33 sim/testsuite/sim/frv/csth.cgs
+d7a05e22c19ec54237285333c21ab720 sim/testsuite/sim/frv/csthf.cgs
+c606963198b1685341b32e14a3384700 sim/testsuite/sim/frv/csthfu.cgs
+a7939f361fa8a4d7152833d17bf9242f sim/testsuite/sim/frv/csthu.cgs
+94b3e5d6bcfbca96e1d45b116852ee46 sim/testsuite/sim/frv/cstq.cgs
+bb9428edb53dbe935f3f5d3295c296f6 sim/testsuite/sim/frv/cstu.cgs
+4f261153dda57be2acd2d50974b2157a sim/testsuite/sim/frv/csub.cgs
+46a9440b74727f04cf647f1904d566fd sim/testsuite/sim/frv/csubcc.cgs
+d59526db81b54d2c091ae65e844abba6 sim/testsuite/sim/frv/cswap.cgs
+6ff863c8f3f5b0a6c8d4e2ba179e7b46 sim/testsuite/sim/frv/cudiv.cgs
+9ca0539cd8fde544f4023712395cfce5 sim/testsuite/sim/frv/cxor.cgs
+ce8352f2c405c5128184546ff69e67e3 sim/testsuite/sim/frv/cxorcc.cgs
+e045ac944c8eccc986873c525e9996fc sim/testsuite/sim/frv/dcef.cgs
+9bd0746e07695fc69099806146e177fd sim/testsuite/sim/frv/dcei.cgs
+a1ff6a0459e013e3978913eca23570ca sim/testsuite/sim/frv/dcf.cgs
+16483dc53cf562ff67a40716ddad4cee sim/testsuite/sim/frv/dci.cgs
+a95c4bac5e72fe8a7d36b1b822acc3c6 sim/testsuite/sim/frv/fabsd.cgs
+26c749327e953defb5a5af911e83e615 sim/testsuite/sim/frv/fabss.cgs
+9baf3938276561eaa3ae2cd20fcaef2b sim/testsuite/sim/frv/faddd.cgs
+c50d08df925d5ebe6235a744f5aa2838 sim/testsuite/sim/frv/fadds.cgs
+e82570b7a76dda7f7c8c4c4499b70113 sim/testsuite/sim/frv/fbeq.cgs
+9afa238bffc2569cab1b6c55a3dc8719 sim/testsuite/sim/frv/fbeqlr.cgs
+bc2783dc8045f8376c62a623d04bc452 sim/testsuite/sim/frv/fbge.cgs
+c89a2bf5e53afd9b92868ba2b7233f73 sim/testsuite/sim/frv/fbgelr.cgs
+da685784eb930e42a55444b9982c35f1 sim/testsuite/sim/frv/fbgt.cgs
+32ab332e05431f49f037d528b657d8e5 sim/testsuite/sim/frv/fbgtlr.cgs
+3550e78fee67575b3e364e279299a11e sim/testsuite/sim/frv/fble.cgs
+d1c296f375a94a01c76d3ab5d7e095e9 sim/testsuite/sim/frv/fblelr.cgs
+bee17829c104e8e5901d5218f8da3030 sim/testsuite/sim/frv/fblg.cgs
+0dfa108dc10c10107281add62d6ca5ff sim/testsuite/sim/frv/fblglr.cgs
+bb12ea3ce3769e468d058aeacea5e6d6 sim/testsuite/sim/frv/fblt.cgs
+8a304334e1341487c78471b20f879ecd sim/testsuite/sim/frv/fbltlr.cgs
+0e297dc071234a78bd595a57838d5adc sim/testsuite/sim/frv/fbne.cgs
+bf2c13262ac9d57aa021ce80e4dbf5a0 sim/testsuite/sim/frv/fbnelr.cgs
+53d642fd09d91db1bfef8cafa2d8c864 sim/testsuite/sim/frv/fbno.cgs
+145a02c3e9ec1831696933a5f22aa31d sim/testsuite/sim/frv/fbnolr.cgs
+4aabea39aa800e2eab4188a00b9ba7b3 sim/testsuite/sim/frv/fbo.cgs
+ce189b743a628565f7ae69ef124e050e sim/testsuite/sim/frv/fbolr.cgs
+5f05aa8ededad20eccd884443cd8ee28 sim/testsuite/sim/frv/fbra.cgs
+7b12e32c5f9c78b47dec5eb157449ab8 sim/testsuite/sim/frv/fbralr.cgs
+f5619a1966d02c7c8e4bd23503a40c49 sim/testsuite/sim/frv/fbu.cgs
+e97d9af6760367447c6863fb5e7fb5b0 sim/testsuite/sim/frv/fbue.cgs
+119fa9c79d98e20cd89f8deea6e78dd1 sim/testsuite/sim/frv/fbuelr.cgs
+2145d16c1548268652bcfdc0a032144b sim/testsuite/sim/frv/fbug.cgs
+c8dca0748024ed82b9c614ccd0579c61 sim/testsuite/sim/frv/fbuge.cgs
+7b549ad8f8a930a4e61411e41d6df7d0 sim/testsuite/sim/frv/fbugelr.cgs
+99c4ae4bd4eb760d9274117748672094 sim/testsuite/sim/frv/fbuglr.cgs
+182d8d5e906c1fe63b1ec15953fbbf0a sim/testsuite/sim/frv/fbul.cgs
+b6c34d73b6a6bbc7b1547986526a8d60 sim/testsuite/sim/frv/fbule.cgs
+9c00d18bfe2d4a8f3c5221ace6ce38bb sim/testsuite/sim/frv/fbulelr.cgs
+d1b0b6638a07909bf45f65b454893510 sim/testsuite/sim/frv/fbullr.cgs
+3ddb83bbd7a429a77b68790480613591 sim/testsuite/sim/frv/fbulr.cgs
+6e5cfae9c6ca85c94d69dd30861553e1 sim/testsuite/sim/frv/fcbeqlr.cgs
+e50b5ddbb0d1b0554408f8db8f7da8a4 sim/testsuite/sim/frv/fcbgelr.cgs
+d5e28bf29b3ce725457862f002b4ba2d sim/testsuite/sim/frv/fcbgtlr.cgs
+f8809a99276af73a606645ea3782eaa4 sim/testsuite/sim/frv/fcblelr.cgs
+ef5f527028300499462fd5457798f5f2 sim/testsuite/sim/frv/fcblglr.cgs
+da932dece8c1932a8e4b322ae96bb5d0 sim/testsuite/sim/frv/fcbltlr.cgs
+2e537bc555c2ad4796ded84bfd87d976 sim/testsuite/sim/frv/fcbnelr.cgs
+be2f0506fae9889d33fdeadc7910e5e5 sim/testsuite/sim/frv/fcbnolr.cgs
+8811726c9441dd7b9f70a3bf6f8ab4fb sim/testsuite/sim/frv/fcbolr.cgs
+ed61ab14ca73c4d78de8d0e432820ff6 sim/testsuite/sim/frv/fcbralr.cgs
+90d5802ce49387d77932ca25262923af sim/testsuite/sim/frv/fcbuelr.cgs
+719ef7eb905c6a71373cba4137767d8a sim/testsuite/sim/frv/fcbugelr.cgs
+a96d3d1ca3ffa9a8c975ff08bcf77a2d sim/testsuite/sim/frv/fcbuglr.cgs
+e34e76144ebb7dd885f027a37c38ae79 sim/testsuite/sim/frv/fcbulelr.cgs
+8570296a139952dc9cf976d500d2f827 sim/testsuite/sim/frv/fcbullr.cgs
+86c530fd6445d3f516387550e7172fa5 sim/testsuite/sim/frv/fcbulr.cgs
+956c2a9363667d599f0ad75bd639805b sim/testsuite/sim/frv/fckeq.cgs
+fcf411b3b36ddc44d1d61f595d1730f3 sim/testsuite/sim/frv/fckge.cgs
+a5c4254bb5fb67e6553d7b4245facb4d sim/testsuite/sim/frv/fckgt.cgs
+702fcbc546ef09f48a9809774f8fec26 sim/testsuite/sim/frv/fckle.cgs
+8335d3357e6e879a7501b1635ce4f821 sim/testsuite/sim/frv/fcklg.cgs
+2fd5797e8c20d9d7b340e095633f2ff6 sim/testsuite/sim/frv/fcklt.cgs
+082bcd35a3b7969bc5b37731b9db0243 sim/testsuite/sim/frv/fckne.cgs
+e05358b9a392f47c2ab2ccebc1dff681 sim/testsuite/sim/frv/fckno.cgs
+09025c57960cb3245c45b229551573d1 sim/testsuite/sim/frv/fcko.cgs
+4aa3a5fba828d2c29dff1b6f57d59678 sim/testsuite/sim/frv/fckra.cgs
+2ba0a93a9c8332f36a0800263efc0511 sim/testsuite/sim/frv/fcku.cgs
+fd10c5f2ffffd0583a7da981ddeca855 sim/testsuite/sim/frv/fckue.cgs
+d025a5adc03c1fa97688e776798e6508 sim/testsuite/sim/frv/fckug.cgs
+935a9c4cf686aaa2f4c480791181b2c9 sim/testsuite/sim/frv/fckuge.cgs
+33411cb293d5fc422c7990104604db74 sim/testsuite/sim/frv/fckul.cgs
+334619e30c816f5a6286de42eff58ebf sim/testsuite/sim/frv/fckule.cgs
+26a2849fb8c805ffcb118c47ef7bf006 sim/testsuite/sim/frv/fcmpd.cgs
+9d2e37d0bea30c9a00cac2518ddd5947 sim/testsuite/sim/frv/fcmps.cgs
+ebae9cb1aaa0ceb6dbf6976f06d735c7 sim/testsuite/sim/frv/fdabss.cgs
+a1081abe7c71411a62d3f8467141fdbb sim/testsuite/sim/frv/fdadds.cgs
+7461f81658de5eada83b19dbf47f1c28 sim/testsuite/sim/frv/fdcmps.cgs
+7b12d84395556d02cee66d9a1a5c991a sim/testsuite/sim/frv/fddivs.cgs
+41eb8f2c4c39e3f8b7914f9a7910eac7 sim/testsuite/sim/frv/fditos.cgs
+66f358e165d3d3c59afa716dc67d1788 sim/testsuite/sim/frv/fdivd.cgs
+444fdecb0192342ea5f61cfd80e48b61 sim/testsuite/sim/frv/fdivs.cgs
+8d77d790c0894ddb71a64a0a13e2e106 sim/testsuite/sim/frv/fdmadds.cgs
+ff1044b90e19b2451b0c3f0233ee3d70 sim/testsuite/sim/frv/fdmas.cgs
+fa4d51b6701d40a568e60a35d730a09c sim/testsuite/sim/frv/fdmovs.cgs
+d558b5c8f62773391401afa4258ec585 sim/testsuite/sim/frv/fdmss.cgs
+50d1ce458d38dfa7f69fd4f3c0b08419 sim/testsuite/sim/frv/fdmulcs.cgs
+346e48b77e9a031f3f955ecefbd4019f sim/testsuite/sim/frv/fdmuls.cgs
+b4bfdcbeb1d5db33d9166dc9f77da383 sim/testsuite/sim/frv/fdnegs.cgs
+0ee8af42152ab4d5632be0dba1c8345d sim/testsuite/sim/frv/fdsads.cgs
+60319f32e98f86da38ff2c3c5212d862 sim/testsuite/sim/frv/fdsqrts.cgs
+ab9fb811cf16eb0998d83984e0cbc430 sim/testsuite/sim/frv/fdstoi.cgs
+42cdb4f8bb24ee39032c4c32ca61b709 sim/testsuite/sim/frv/fdsubs.cgs
+694f1d17123f4bb9c03260c1fe669aac sim/testsuite/sim/frv/fdtoi.cgs
+c5163110cf891849bed86c0f453b8e02 sim/testsuite/sim/frv/fitod.cgs
+6c26a616dd6fed8bd7e159e371fe4fe4 sim/testsuite/sim/frv/fitos.cgs
+6ea38598142f8f6d50283bafdaf0a0f7 sim/testsuite/sim/frv/fmad.cgs
+82fe9144d5b80fbfd5b4582ca5246df4 sim/testsuite/sim/frv/fmaddd.cgs
+b9ae3c5d73a84096df40cbc04f28abbe sim/testsuite/sim/frv/fmadds.cgs
+47f01f4c8f9a72792359daab3c1e9212 sim/testsuite/sim/frv/fmas.cgs
+f59368c3bae1aa62bdb68b1edf299c9e sim/testsuite/sim/frv/fmovd.cgs
+6f5746330962303a04eb519a4b05fa23 sim/testsuite/sim/frv/fmovs.cgs
+f423c77b0989e36e0e8829e450d94c74 sim/testsuite/sim/frv/fmsd.cgs
+7068101bb16125bf823c54313efc9c88 sim/testsuite/sim/frv/fmss.cgs
+38e18b11776fdecb14fcc94311d95b20 sim/testsuite/sim/frv/fmsubd.cgs
+a761e98378b236d13867be6741e673bd sim/testsuite/sim/frv/fmsubs.cgs
+8dda215c5c85e94e1a385d685127d850 sim/testsuite/sim/frv/fmuld.cgs
+3b5c5fa1e5977ed20ec3d4474eb79431 sim/testsuite/sim/frv/fmuls.cgs
+0553d530d16ef1a9889895d233bd1a23 sim/testsuite/sim/frv/fnegd.cgs
+36024f7e3058972d0b99742ee87119cd sim/testsuite/sim/frv/fnegs.cgs
+a2266c24dffd8d4a696b3619a897269f sim/testsuite/sim/frv/fnop.cgs
+a1394d82fbbcdc7278c8ff7b0b749317 sim/testsuite/sim/frv/fsqrtd.cgs
+09a60ae22f077bfd3491cb02114dc22f sim/testsuite/sim/frv/fsqrts.cgs
+64a8de42436fc5c8f2d468e70c54e9aa sim/testsuite/sim/frv/fstoi.cgs
+8f0dbbf7ad0b329248d951a35e40a01b sim/testsuite/sim/frv/fsubd.cgs
+5761527de2c6413c3f8a07d2189ef92a sim/testsuite/sim/frv/fsubs.cgs
+a7085119fedb3ac3d4e31403309293b1 sim/testsuite/sim/frv/fteq.cgs
+e3482ddd50c998096e309469d49bf60f sim/testsuite/sim/frv/ftge.cgs
+25805dfe75db053034915ba8a5b33ce2 sim/testsuite/sim/frv/ftgt.cgs
+16bf5094b2c7a186f0e11fa373625fb8 sim/testsuite/sim/frv/ftieq.cgs
+b5a71bd3c822c7000929441e7602c329 sim/testsuite/sim/frv/ftige.cgs
+ce965b75b06cd55ef70169b06c863849 sim/testsuite/sim/frv/ftigt.cgs
+1951d6a3f5242b6e26d9fdb55b1bf1ca sim/testsuite/sim/frv/ftile.cgs
+80d04d00a7e92cc4c32af000081d5cd4 sim/testsuite/sim/frv/ftilg.cgs
+e913757697385f676de531dc9055b78d sim/testsuite/sim/frv/ftilt.cgs
+f48f14696dde175e869c7c04abc8573b sim/testsuite/sim/frv/ftine.cgs
+c2b0345fa9da69b5322eaf83e9506cab sim/testsuite/sim/frv/ftino.cgs
+f3562f7c11ed638cffff5fb8afd74b8c sim/testsuite/sim/frv/ftio.cgs
+e2bbc311eb90229f9eb63b3ea456aa51 sim/testsuite/sim/frv/ftira.cgs
+fbd58be2c1178ffbda7cbe566dda3bb4 sim/testsuite/sim/frv/ftiu.cgs
+7aa4b56189a14f023e26984163cb0b4e sim/testsuite/sim/frv/ftiue.cgs
+821d3e5a5535a52948ced4d48cf4491d sim/testsuite/sim/frv/ftiug.cgs
+bea6c33251489ce5246ed3d6bf5ac702 sim/testsuite/sim/frv/ftiuge.cgs
+f60030141346c133b53f259287743291 sim/testsuite/sim/frv/ftiul.cgs
+8a5f013616cf1e6db319200b9db548cd sim/testsuite/sim/frv/ftle.cgs
+680e346877ec40599ab486d183890983 sim/testsuite/sim/frv/ftlg.cgs
+cc345f4d17b80808ee251d600fbbc6b9 sim/testsuite/sim/frv/ftlt.cgs
+47b041b440463afa7c2f9adc16bc48db sim/testsuite/sim/frv/ftne.cgs
+9ac0ca5fc78d29c5cb125f7f0232ab24 sim/testsuite/sim/frv/ftno.cgs
+0cfc1cccecd9264a187a4fde5a4e1b92 sim/testsuite/sim/frv/fto.cgs
+7f0e3223aefe0347e86016999b785689 sim/testsuite/sim/frv/ftra.cgs
+7e08ead385d09b81452d7e494e24003b sim/testsuite/sim/frv/ftu.cgs
+7eb6a791ed88c6c8794db6e2d7d1c4cd sim/testsuite/sim/frv/ftue.cgs
+798fee14d0226828590f274a847fb587 sim/testsuite/sim/frv/ftug.cgs
+b1b5fbe7e86fcaa6a8cb5246c1105383 sim/testsuite/sim/frv/ftuge.cgs
+18c32597076e6690eca21bdaa9b70083 sim/testsuite/sim/frv/ftul.cgs
+b38f99b4027aa8bc54b81cd44830ff0c sim/testsuite/sim/frv/ftule.cgs
+9b2b24b2080b3778404da0e73b2f4c45 sim/testsuite/sim/frv/icei.cgs
+57b3c53e5a537bbcdd2bbd8bda51c584 sim/testsuite/sim/frv/ici.cgs
+520e9f58107f1a7407724d2b52bbe214 sim/testsuite/sim/frv/icpl.cgs
+28f0887ee88db223fdd12b2024131872 sim/testsuite/sim/frv/icul.cgs
+94f5c3abf0cf2118f97e0a95f79f9dd5 sim/testsuite/sim/frv/interrupts.exp
+6d82b9a4957b0fefdf4b9bd93f868b12 sim/testsuite/sim/frv/jmpil.cgs
+7acb4d8fcf1961a11eb5f86da60a0804 sim/testsuite/sim/frv/jmpl.cgs
+5331aae1c37403328b45cbda9aef7b4b sim/testsuite/sim/frv/jmpl.pcgs
+fe0935479403ab62bd07f75bc6974752 sim/testsuite/sim/frv/ld.cgs
+2a756ad9c98638728516c303deb87eb0 sim/testsuite/sim/frv/ldbf.cgs
+7907b41ac563ea2be426de33f8910f66 sim/testsuite/sim/frv/ldbfi.cgs
+f77f7688f51f87c5e93a3e56bd0fbc96 sim/testsuite/sim/frv/ldbfu.cgs
+3a18c58e47703c059520340b1b1c3051 sim/testsuite/sim/frv/ldc.cgs
+dcb10a82d61302543652fed0b13575b2 sim/testsuite/sim/frv/ldcu.cgs
+6e3d68aac7b3fc4b6ed2b5e4d847070b sim/testsuite/sim/frv/ldd.cgs
+20942fb6996945bf7ea82dc541af0991 sim/testsuite/sim/frv/lddc.cgs
+4741f3d629b91d827c5d340249f452c5 sim/testsuite/sim/frv/lddcu.cgs
+f30642deec77165f2dec4409e06fb949 sim/testsuite/sim/frv/lddf.cgs
+a4e3dae18838ea83a10018cf243b37d9 sim/testsuite/sim/frv/lddfi.cgs
+c4fbea8332e5b07b3fd2e18f0fd4fd9f sim/testsuite/sim/frv/lddfu.cgs
+4cf840661cd9ed9ad76e658e996fc2fb sim/testsuite/sim/frv/lddi.cgs
+117ef9aa94aacbff810bdc764cce2f12 sim/testsuite/sim/frv/lddu.cgs
+c613f1a55c9e79f62abbd91eee7fde9d sim/testsuite/sim/frv/ldf.cgs
+2426e56c573364d455e06cf511aa1c1f sim/testsuite/sim/frv/ldfi.cgs
+873badad1ba22ab85ceded1032e76d7a sim/testsuite/sim/frv/ldfu.cgs
+e7c1a6655a0477c4a36ead53e726fb48 sim/testsuite/sim/frv/ldhf.cgs
+358001b036e18ae3c266a2d8f245022e sim/testsuite/sim/frv/ldhfi.cgs
+26d92ac47d2a85071f1c0c26d721e2cc sim/testsuite/sim/frv/ldhfu.cgs
+003fcd3e132470d58c6ceb7177806c5b sim/testsuite/sim/frv/ldi.cgs
+e4ece86a7c055e9d7e99ecec010c71ae sim/testsuite/sim/frv/ldq.cgs
+1b5c559ac60b1eb35f51ca0e4bb70acf sim/testsuite/sim/frv/ldqc.cgs
+b0a584edcb6525f7880b1f45497c9a2e sim/testsuite/sim/frv/ldqcu.cgs
+8c87a49e58f46e85f154cc3871f5aff6 sim/testsuite/sim/frv/ldqf.cgs
+84cacbc7723416a4ab6bd038d71dac9b sim/testsuite/sim/frv/ldqfi.cgs
+747342519c94e5f3d6e4153d144a3774 sim/testsuite/sim/frv/ldqfu.cgs
+7f6546bcb393b36f1e1a1f1552c53160 sim/testsuite/sim/frv/ldqi.cgs
+90cebd7ff7dc2106afca60b9a5a26bed sim/testsuite/sim/frv/ldqu.cgs
+9ba5b89fa11ddec7e98787ca73fa0115 sim/testsuite/sim/frv/ldsb.cgs
+91548ae1c6a13b8dcdc27ee53cf2c8cd sim/testsuite/sim/frv/ldsbi.cgs
+fe18fae6d95afe023a4f3c12ee809a7d sim/testsuite/sim/frv/ldsbu.cgs
+7bff63bb7f11db3619daa65ba575eb4b sim/testsuite/sim/frv/ldsh.cgs
+04ebe641dcc2681cb7085e49e4b8787d sim/testsuite/sim/frv/ldshi.cgs
+2578eab56c9efe85e875334d9be745a5 sim/testsuite/sim/frv/ldshu.cgs
+0fcf16c6304ddf56ba06882bf077c739 sim/testsuite/sim/frv/ldu.cgs
+b4281f11b7f00e191f158b23a2115556 sim/testsuite/sim/frv/ldub.cgs
+ce9abd48c84d1abd4b05d248d4e9067e sim/testsuite/sim/frv/ldubi.cgs
+f3f076fc173ea772baff44f55775ca03 sim/testsuite/sim/frv/ldubu.cgs
+c9e8808a1431699f65ca45e1d96ccb40 sim/testsuite/sim/frv/lduh.cgs
+6839b4b27f67afcd7af9dcbeba8e54e6 sim/testsuite/sim/frv/lduhi.cgs
+e470390ff6d0df7541ce5455d765a606 sim/testsuite/sim/frv/lduhu.cgs
+861233cc66075168ec7d72a804bbffae sim/testsuite/sim/frv/lrbranch.pcgs
+358b9c46cd5cb979fdaf717f46764b5a sim/testsuite/sim/frv/mabshs.cgs
+7174dbd57607dbdc45c4243fb7f02aa7 sim/testsuite/sim/frv/maddhss.cgs
+8aa28a7f77fd8f94f1f8d4441330d2de sim/testsuite/sim/frv/maddhus.cgs
+2e1fd77e3c7dc410824bb62d86c12fa5 sim/testsuite/sim/frv/mand.cgs
+2caa34c2c4802ea92661e98ac6af667f sim/testsuite/sim/frv/maveh.cgs
+89a846533bf6d66afa6dc6a610bee4de sim/testsuite/sim/frv/mbtoh.cgs
+be7bc8f47af7ec401ae8edc5735ae83f sim/testsuite/sim/frv/mbtohe.cgs
+5890a645af954362f462a536301ab07a sim/testsuite/sim/frv/mclracc.cgs
+4df2335c339344cb1ab773c28eac7047 sim/testsuite/sim/frv/mcmpsh.cgs
+0202236564d839929bc185b5b363483b sim/testsuite/sim/frv/mcmpuh.cgs
+75f2c544b8e80d583bfc78a32fce7f9f sim/testsuite/sim/frv/mcop1.cgs
+eac5267f2219d176a231a4394b8a7dbe sim/testsuite/sim/frv/mcop2.cgs
+0511aebe3ab974e7a9e5fdfa895d9aeb sim/testsuite/sim/frv/mcplhi.cgs
+dae087e8f55a8ecbfe85b2476c9267e2 sim/testsuite/sim/frv/mcpli.cgs
+40aac5235a3696c45134d86e1e79c5d9 sim/testsuite/sim/frv/mcpxis.cgs
+bf8b42298ba9d65e9cbfb7f621ede0df sim/testsuite/sim/frv/mcpxiu.cgs
+da93993782224f234cfa217c4c2de3cb sim/testsuite/sim/frv/mcpxrs.cgs
+2e3efdb33b16bdf036e34506be43620a sim/testsuite/sim/frv/mcpxru.cgs
+2e85d413681ca26660d8f9691a5c9ab2 sim/testsuite/sim/frv/mcut.cgs
+6f24d372cfa857010330fd99b9ceaa3f sim/testsuite/sim/frv/mcuti.cgs
+58aae8e7b29223770991f01723b7dd98 sim/testsuite/sim/frv/mcutss.cgs
+d94022526f601563a7d06cde8c8461d5 sim/testsuite/sim/frv/mcutssi.cgs
+c75ed78a7566a8628cf0a0339c5dcf21 sim/testsuite/sim/frv/mdaddaccs.cgs
+5034792548b761b0fe9ad80d44958b6e sim/testsuite/sim/frv/mdasaccs.cgs
+e81006aee4bbd0e3671448585ab45d5d sim/testsuite/sim/frv/mdcutssi.cgs
+4ced60215e6ef89c35488866f38fd3c0 sim/testsuite/sim/frv/mdpackh.cgs
+00c2e418966af14d3cc048573279d6fc sim/testsuite/sim/frv/mdrotli.cgs
+bbe41f9762adbc1e38c19904af9a4622 sim/testsuite/sim/frv/mdsubaccs.cgs
+edb5aa56bcd8e8bca69cf259f36e465f sim/testsuite/sim/frv/mdunpackh.cgs
+32dde2fe5a74ba57fb63ca5a91948b13 sim/testsuite/sim/frv/membar.cgs
+7351ae1c949d0e80e4c9cac3adb238c0 sim/testsuite/sim/frv/mexpdhd.cgs
+8be433c05488391e44e6d0fd1a0663a5 sim/testsuite/sim/frv/mexpdhw.cgs
+bfc4a4f409782a01b12aafa73820d4a7 sim/testsuite/sim/frv/mhdseth.cgs
+5530ac8f622c5b86676418a439d31062 sim/testsuite/sim/frv/mhdsets.cgs
+6e9d7ee79258240c2e9f8490187d2d1b sim/testsuite/sim/frv/mhsethih.cgs
+0286e694b02e66084d5fb2649c171379 sim/testsuite/sim/frv/mhsethis.cgs
+889eccff241ad187bd577cfe2fcc0ddc sim/testsuite/sim/frv/mhsetloh.cgs
+500ddf7a9ca8ca47e62e62cf4257a675 sim/testsuite/sim/frv/mhsetlos.cgs
+a861d845633062758e032a27d5fab174 sim/testsuite/sim/frv/mhtob.cgs
+e326ecc782170966595a854ea64b2786 sim/testsuite/sim/frv/mmachs.cgs
+052b5f3d0e3a1fca5894d9655353d7e3 sim/testsuite/sim/frv/mmachu.cgs
+985bedf1c0cc65d298ccc789ebc69179 sim/testsuite/sim/frv/mmrdhs.cgs
+cf37e0de21739109f45bc6903faef9ff sim/testsuite/sim/frv/mmrdhu.cgs
+b813da728e948bf7f3d0a70e28fd56de sim/testsuite/sim/frv/mmulhs.cgs
+20f4895c822bcecaa711c3508043ced9 sim/testsuite/sim/frv/mmulhu.cgs
+5970b5e8ca637b383803588fb78206d8 sim/testsuite/sim/frv/mmulxhs.cgs
+e6ac3d3a2b75c748d32f1dff04690c18 sim/testsuite/sim/frv/mmulxhu.cgs
+73a36ac7ddbc3eb5f02e23e556757534 sim/testsuite/sim/frv/mnop.cgs
+d7e3785dd9d822d3c98edf4a7ca1e462 sim/testsuite/sim/frv/mnot.cgs
+787ba5a828f2060d5163f4dd6493bdfc sim/testsuite/sim/frv/mor.cgs
+e15b13b9790cd957ef7c1174a414fc91 sim/testsuite/sim/frv/mov.cgs
+e267cd40e466ef09766bb5af7f3ea525 sim/testsuite/sim/frv/movfg.cgs
+1de01bb11a8e27d051b6d84fdf37cbff sim/testsuite/sim/frv/movfgd.cgs
+b671fcc6ddd6daa079fd31a468749b0e sim/testsuite/sim/frv/movfgq.cgs
+1f93a0d7fca1cd46156bd7a0c7f3c59f sim/testsuite/sim/frv/movgf.cgs
+6a708919bfd6e9a6a3b0a1872c48290f sim/testsuite/sim/frv/movgfd.cgs
+490b859435e3a616aa2c844b9dbed8d6 sim/testsuite/sim/frv/movgfq.cgs
+d2a4394753db3dfcbe7e384ee21e2202 sim/testsuite/sim/frv/movgs.cgs
+5df092435661dcba49b26ede1ae30c8d sim/testsuite/sim/frv/movsg.cgs
+1e471deced4a3635b4468bd2d1ff88cb sim/testsuite/sim/frv/mpackh.cgs
+de1b6d1ff997e66d64111e7a69c3f749 sim/testsuite/sim/frv/mqcpxis.cgs
+ddd0fdd0602cb85ada820445cf505820 sim/testsuite/sim/frv/mqcpxiu.cgs
+dc5c412a280bacbbb5fd6a56a6fe53ff sim/testsuite/sim/frv/mqcpxrs.cgs
+e92162146f80eacb87cc88e02de63d26 sim/testsuite/sim/frv/mqcpxru.cgs
+a016768b6c2c21cc9c4354d7cc7f9628 sim/testsuite/sim/frv/mqmachs.cgs
+317e00e7d2fc4d994400b3435e38deba sim/testsuite/sim/frv/mqmachu.cgs
+bf4cfe49b9af48954b1a4495db0bcb6f sim/testsuite/sim/frv/mqmacxhs.cgs
+d79cc37be001047a062fd1b16bf5e34e sim/testsuite/sim/frv/mqmulhs.cgs
+26f559df23ae04f9a1576f793e340163 sim/testsuite/sim/frv/mqmulhu.cgs
+5c07a1afebe94dfc4e0132d66d8c28ea sim/testsuite/sim/frv/mqmulxhs.cgs
+8674ff984bcbe2b1460d51e69db27c7b sim/testsuite/sim/frv/mqmulxhu.cgs
+352d41aa9b03ec2820009d90f569a60a sim/testsuite/sim/frv/mqsaths.cgs
+b1cf84b60cf3a908c49512b100a3cf65 sim/testsuite/sim/frv/mqxmachs.cgs
+48ee9ffc570edbbfe8169afd5f2bacee sim/testsuite/sim/frv/mqxmacxhs.cgs
+d3412bc4c0b67f6c78449fd684463b9b sim/testsuite/sim/frv/mrdacc.cgs
+cc6399ec148be0f20332c2aeadef5990 sim/testsuite/sim/frv/mrdaccg.cgs
+f428dd31a13e708566a12b6eb23e75aa sim/testsuite/sim/frv/mrotli.cgs
+a05d5c0d7e028af3383c1e9b237ef156 sim/testsuite/sim/frv/mrotri.cgs
+9b134f75e539c10de4195ec1e51ee136 sim/testsuite/sim/frv/msaths.cgs
+326669d1c76ef080e2d2ddf8c2ee6e6f sim/testsuite/sim/frv/msathu.cgs
+475e50c7c92b7357b020583b574726a8 sim/testsuite/sim/frv/msllhi.cgs
+5e7cbd14acb0fd1a1bdc89e068e9803d sim/testsuite/sim/frv/msrahi.cgs
+90c1d817bd4dce7d539e4e9dacb35e90 sim/testsuite/sim/frv/msrlhi.cgs
+f3f08211769783c8fad2413b5f4419a5 sim/testsuite/sim/frv/msubhss.cgs
+c171d116ab1a2be2bd6fe89d40046466 sim/testsuite/sim/frv/msubhus.cgs
+6f29112e0458cbb1fe8d3a0403ed85d7 sim/testsuite/sim/frv/mtrap.cgs
+80d2065efb7d0769f11b1c4881e20500 sim/testsuite/sim/frv/munpackh.cgs
+5f0be0ef1415763840683d1a66cf6b67 sim/testsuite/sim/frv/mwcut.cgs
+28b4f2f9ac438caaebbf3d5fe7b8b9f3 sim/testsuite/sim/frv/mwcuti.cgs
+68b4157ad30443488a491d75a0ddc05f sim/testsuite/sim/frv/mwtacc.cgs
+82d5838a4cbf516a93892bafbf64af95 sim/testsuite/sim/frv/mwtaccg.cgs
+754cf046515e94f61db9e81c57bbef98 sim/testsuite/sim/frv/mxor.cgs
+ea152c37492f744e98208e25538591cc sim/testsuite/sim/frv/nandcr.cgs
+9bd25bbc9331a8a7a764970163f8a3c2 sim/testsuite/sim/frv/nandncr.cgs
+5645677fd61cac055a6989382352af7e sim/testsuite/sim/frv/nfadds.cgs
+f6656b60bec315c613ad5092d5bba892 sim/testsuite/sim/frv/nfdadds.cgs
+6f912abf4768c8b66831a8ce4a5ab658 sim/testsuite/sim/frv/nfdcmps.cgs
+f72cfcf1db3b542e40ae4d24754a8648 sim/testsuite/sim/frv/nfddivs.cgs
+ac7e485b7fc2228e78885a3580c40684 sim/testsuite/sim/frv/nfditos.cgs
+0e30127c5ef9ca2d27a6bf7790128b65 sim/testsuite/sim/frv/nfdivs.cgs
+2d6cd85e83c408920463b9e326312c1d sim/testsuite/sim/frv/nfdmadds.cgs
+fdd8bd1799f969d718f27d5140c561e1 sim/testsuite/sim/frv/nfdmas.cgs
+75d93040b8b11cd80e200e83f9c3b423 sim/testsuite/sim/frv/nfdmss.cgs
+9564e9d1067be24d75f69103b57a85dc sim/testsuite/sim/frv/nfdmulcs.cgs
+96c1cae5bdbbfd68972a26ded76a6653 sim/testsuite/sim/frv/nfdmuls.cgs
+60b73bc5cde0341f993a4d3fa218363f sim/testsuite/sim/frv/nfdsads.cgs
+ccf1387db46bf4985328d9b58f89085e sim/testsuite/sim/frv/nfdsqrts.cgs
+08bb1af48f043b2ec22ede0e6a2a63c0 sim/testsuite/sim/frv/nfdstoi.cgs
+c76e1c140c00dea2137868c13de73686 sim/testsuite/sim/frv/nfdsubs.cgs
+4f526f2f27056051f986c47b44c9b1ff sim/testsuite/sim/frv/nfitos.cgs
+5c7a02887eb56676fc4f267dff41f169 sim/testsuite/sim/frv/nfmadds.cgs
+3de97f087ebc932501f95bc2bd775d5f sim/testsuite/sim/frv/nfmas.cgs
+de42c23dfd886e1e9150e93cfa7a0e30 sim/testsuite/sim/frv/nfmss.cgs
+c133078967d4e2c08e05c0c211483593 sim/testsuite/sim/frv/nfmsubs.cgs
+40981f85eeb4a396327c4e11f7ca792d sim/testsuite/sim/frv/nfmuls.cgs
+c73e0f9186dae498050376d33b40c1c6 sim/testsuite/sim/frv/nfsqrts.cgs
+a9c95b2f342640586e4acb9faad49772 sim/testsuite/sim/frv/nfstoi.cgs
+147619970eca1511cbd9f636e8aaeeb7 sim/testsuite/sim/frv/nfsubs.cgs
+849a1c54f6b7fc29b1fea32e1adffb98 sim/testsuite/sim/frv/nld.cgs
+cec99b8b35d4fdcdb377d9a66ea62009 sim/testsuite/sim/frv/nldbf.cgs
+285f247c378146a1e4a5a8134ab4c06f sim/testsuite/sim/frv/nldbfi.cgs
+62fbafc1c264ff3ffa2f95d455138a29 sim/testsuite/sim/frv/nldbfu.cgs
+3cf41818d7d43998028a6204c6d3d1cc sim/testsuite/sim/frv/nldd.cgs
+484f52adb8fc411974f97082db9d5dbc sim/testsuite/sim/frv/nlddf.cgs
+2bb049f287b76c978273eaf5c312a4d1 sim/testsuite/sim/frv/nlddfi.cgs
+b21df75a0fc0a38539d562c017b4b670 sim/testsuite/sim/frv/nlddfu.cgs
+903edfdf254dfa703f606ad9ccda17ad sim/testsuite/sim/frv/nlddi.cgs
+2c42865e66cdf52327e926c6430af676 sim/testsuite/sim/frv/nlddu.cgs
+36d1b5e9f74e8641f51abe8a472c6860 sim/testsuite/sim/frv/nldf.cgs
+4ee6d04ba074cd859443fa0bf726dc3f sim/testsuite/sim/frv/nldfi.cgs
+ae737e209ef8a22261025cd8102d7861 sim/testsuite/sim/frv/nldfu.cgs
+4f3c2f0fc2e3ed5b6c87cd135a6bbd00 sim/testsuite/sim/frv/nldhf.cgs
+b12b404167348112b47f3650d80a49a1 sim/testsuite/sim/frv/nldhfi.cgs
+23dbb5a7d7175564285ef8cbbafdf4d7 sim/testsuite/sim/frv/nldhfu.cgs
+323956db2a566de88fcd530490661356 sim/testsuite/sim/frv/nldi.cgs
+7e182fb1f729214fcc4e500b45b28c67 sim/testsuite/sim/frv/nldq.cgs
+f0900597e5ab5ecf6b5c7a7767e62980 sim/testsuite/sim/frv/nldqf.cgs
+ad1fb24311a078779b253206335fb321 sim/testsuite/sim/frv/nldqfi.cgs
+6158542e4b6f47593521af161cbefcc4 sim/testsuite/sim/frv/nldqfu.cgs
+27c8a87945ccd5906ecb831c022a2cae sim/testsuite/sim/frv/nldqu.cgs
+86f2d4d2d5077458a84b7b7717ae2841 sim/testsuite/sim/frv/nldsb.cgs
+6cb71382953aaa573377ba9365cf47c8 sim/testsuite/sim/frv/nldsbi.cgs
+94382ca860759734f699db2c4030a586 sim/testsuite/sim/frv/nldsbu.cgs
+769125b26bae4afc675b0f4ecba3476b sim/testsuite/sim/frv/nldsh.cgs
+512f6ab69b17ee51ff97983b35376396 sim/testsuite/sim/frv/nldshi.cgs
+288041bebf2361e4e1b14d5487134199 sim/testsuite/sim/frv/nldshu.cgs
+fcdd282d23082a3f4baf0861979ef5bb sim/testsuite/sim/frv/nldu.cgs
+21e414ff661565b6aa03208928648853 sim/testsuite/sim/frv/nldub.cgs
+4dbc3bfa2a0abb00d11e913ffe7dbfdf sim/testsuite/sim/frv/nldubi.cgs
+7a14b1a4b9c264ad6fe9fee43a34053c sim/testsuite/sim/frv/nldubu.cgs
+606377e169feb767df3ada199efb6756 sim/testsuite/sim/frv/nlduh.cgs
+29e215193143b4309c76dec515f0ffb9 sim/testsuite/sim/frv/nlduhi.cgs
+8e6934cc5df77f17ded11b0e56344cc1 sim/testsuite/sim/frv/nlduhu.cgs
+55a7762fcf4065ee0e1e89c09894296b sim/testsuite/sim/frv/nop.cgs
+c82aab8314691de50e4eb1b4d2deee7f sim/testsuite/sim/frv/norcr.cgs
+1d754b9b7c803178ecc07bed29a6226c sim/testsuite/sim/frv/norncr.cgs
+877b1bf25d820494dfcd5c8e060ee0a5 sim/testsuite/sim/frv/not.cgs
+937c6181f24f15a85ce59e24a746f6da sim/testsuite/sim/frv/notcr.cgs
+9711b61b6a23527c5cde41eaac4eb112 sim/testsuite/sim/frv/nsdiv.cgs
+e7a86181d00e8f0c9684753e86508c74 sim/testsuite/sim/frv/nsdivi.cgs
+6b19d157804a7fa854e78b49a095a638 sim/testsuite/sim/frv/nudiv.cgs
+da4a0f53d7d03d30ce9cca0bf34a2ece sim/testsuite/sim/frv/nudivi.cgs
+371a4f289d0bc38fee546e49ad327952 sim/testsuite/sim/frv/or.cgs
+5c2413abe5cf30fb4cdd0d5e3c30dbab sim/testsuite/sim/frv/orcc.cgs
+56f5fdf1970e4a477ff5bcd70ad6128d sim/testsuite/sim/frv/orcr.cgs
+67bd729e92a8ccbb0ef66f5053e9c7c9 sim/testsuite/sim/frv/ori.cgs
+e1e57ef45323b229f0811de476eadaa8 sim/testsuite/sim/frv/oricc.cgs
+9fc100ac9932ce7d023e9d73fe027dd7 sim/testsuite/sim/frv/orncr.cgs
+6aa3407819f0ab3db9441490901c1c20 sim/testsuite/sim/frv/parallel.exp
+54abbae4f460a1ac2f0f979b48cff91f sim/testsuite/sim/frv/ret.cgs
+102c16fad8d7c1990921e4b171f62531 sim/testsuite/sim/frv/rett.cgs
+dcdd60cb6a74a2fdf05c27542ce87c00 sim/testsuite/sim/frv/scan.cgs
+a0d99a5f1ae6d699d7551ec0c91ad1f9 sim/testsuite/sim/frv/scani.cgs
+8cfaaa6f7d9be0c7164bd6b95f781486 sim/testsuite/sim/frv/sdiv.cgs
+a0bc228cfda1d7113cd087bfc0298020 sim/testsuite/sim/frv/sdivi.cgs
+0eaa5642821eed78cc9e2c144fe34a92 sim/testsuite/sim/frv/sethi.cgs
+d3a8b5ed0ad285696200a176e326a55b sim/testsuite/sim/frv/sethilo.pcgs
+6eafdd537ba1f28305cee77fe68ff5fd sim/testsuite/sim/frv/setlo.cgs
+bb74161afeebbd175cc9296446d7ff46 sim/testsuite/sim/frv/setlos.cgs
+dc65593014b3881fdcff036075e5dad0 sim/testsuite/sim/frv/sll.cgs
+ee34b84c6bf75a9babe137a04ac4b75a sim/testsuite/sim/frv/sllcc.cgs
+35c7aae3b090f125993fef390d76906f sim/testsuite/sim/frv/slli.cgs
+8700acd6ed03f5cbac0ad536383ed3c8 sim/testsuite/sim/frv/sllicc.cgs
+0814d3851a44b4bce8357863eec8e600 sim/testsuite/sim/frv/smul.cgs
+8692050bdf66cc6ad2d401c4a4684cef sim/testsuite/sim/frv/smulcc.cgs
+89a51e07a40a4e8f76ac296cacbb8363 sim/testsuite/sim/frv/smuli.cgs
+2eb6969a0c7a4eb4fff85aac9727721a sim/testsuite/sim/frv/smulicc.cgs
+2d31dcb15e8a6877017dd3d148b0bf2b sim/testsuite/sim/frv/sra.cgs
+d41729b132c64711d5d230c8be3b4332 sim/testsuite/sim/frv/sracc.cgs
+1d5380689e9dae36a5ab8b5436118c9e sim/testsuite/sim/frv/srai.cgs
+3ba660d7dcfb108e50618445716bb95b sim/testsuite/sim/frv/sraicc.cgs
+204db103ce94f9da0c1f28ed0cd60ba0 sim/testsuite/sim/frv/srl.cgs
+5aceef24e6a30dc790c1cd482bfa40f8 sim/testsuite/sim/frv/srlcc.cgs
+59498912961c5a2bfe37d5631fc3802c sim/testsuite/sim/frv/srli.cgs
+59addb4ff5949cfea9664343d9f81a38 sim/testsuite/sim/frv/srlicc.cgs
+cc2f98b9ebe473e853c879e903f2f4bd sim/testsuite/sim/frv/st.cgs
+7da5b6117008820095468c44c991bba7 sim/testsuite/sim/frv/stb.cgs
+038ed75fefa3a9b991855a5b60b5046c sim/testsuite/sim/frv/stbf.cgs
+ddf4ff091a5b6c5cf352c04d236e2fcc sim/testsuite/sim/frv/stbfi.cgs
+9fc9892f699a1d3ddc62ae7524e9ce82 sim/testsuite/sim/frv/stbfu.cgs
+e038da35c3e2553c4431a03fe542c5dc sim/testsuite/sim/frv/stbi.cgs
+fb8002b4e6861b77f536c7629c7bf622 sim/testsuite/sim/frv/stbu.cgs
+64efd173f19902d6a2005148cb3d4831 sim/testsuite/sim/frv/stc.cgs
+c8327289e084ae64868b9257b8646e11 sim/testsuite/sim/frv/stcu.cgs
+791afd243b5e7ed1e6aa29ad1113f218 sim/testsuite/sim/frv/std.cgs
+d34e0187f000a733eaf4b2730118ae03 sim/testsuite/sim/frv/std.pcgs
+04f8995f9af5c9a6d61eb1ab60b34ba0 sim/testsuite/sim/frv/stdc.cgs
+ca358dddc54a8ba43c916ac2a6b45812 sim/testsuite/sim/frv/stdc.pcgs
+285195010d47ac9191d9c97aca80f0e6 sim/testsuite/sim/frv/stdcu.cgs
+b9b610f3e0c8243a5d9e261844251ed7 sim/testsuite/sim/frv/stdf.cgs
+8a296ea605f6ea7504e25318c38b44c4 sim/testsuite/sim/frv/stdf.pcgs
+cdb16f4dfab32f15e7a55fba16afd880 sim/testsuite/sim/frv/stdfi.cgs
+14194ebf318b1a64b5cbc27e067b5110 sim/testsuite/sim/frv/stdfu.cgs
+43e07345873b79b52184a1785a5ce422 sim/testsuite/sim/frv/stdi.cgs
+c1916f813f831be331a1dbc2312fd4bb sim/testsuite/sim/frv/stdu.cgs
+74d71e1f6d2aa891e6e9cb32cd44e036 sim/testsuite/sim/frv/stf.cgs
+8c68b4f09d376aac18a160f70bbb24c0 sim/testsuite/sim/frv/stfi.cgs
+ef17532bed029b8034a943091bcc8d3a sim/testsuite/sim/frv/stfu.cgs
+c458c9df8008e8b3f7761d31df5e912d sim/testsuite/sim/frv/sth.cgs
+8a3789cf60dd4331ea1a6f6e994b76e8 sim/testsuite/sim/frv/sthf.cgs
+8bcf588029874b3f33885374cc496306 sim/testsuite/sim/frv/sthfi.cgs
+4f069f49b6bc39f94f78adf156ce0f43 sim/testsuite/sim/frv/sthfu.cgs
+84ffdd51531190b3f7ab0bd433a36036 sim/testsuite/sim/frv/sthi.cgs
+8ccbca9bbf069a03a4d929333916d88c sim/testsuite/sim/frv/sthu.cgs
+250d78cd5a5807bcacccc649f4e5d0ad sim/testsuite/sim/frv/sti.cgs
+5e9fe07f66519bb28e80b540c91d7270 sim/testsuite/sim/frv/stq.cgs
+3a29b1dd11046f8f4dd5c27edc2a8d6f sim/testsuite/sim/frv/stq.pcgs
+aa46f6b377cfc62824b0be2e6fc1c326 sim/testsuite/sim/frv/stqc.cgs
+73fa8ef52f05985daec1d8a01dbbc29f sim/testsuite/sim/frv/stqc.pcgs
+e7569bf70d9017f69182cfa2622ebfbf sim/testsuite/sim/frv/stqcu.cgs
+27da4c018deec302d0e3d6b8c89c9909 sim/testsuite/sim/frv/stqf.cgs
+244caf04384a0a05c44c7299059e0a1e sim/testsuite/sim/frv/stqf.pcgs
+31598ac83baef878c73a4ac875783821 sim/testsuite/sim/frv/stqfi.cgs
+099e806e30801140def329d0fc74d8f3 sim/testsuite/sim/frv/stqfu.cgs
+01a00c462bcea5bf16545bc7e56ab416 sim/testsuite/sim/frv/stqi.cgs
+3664a976c54024aeb5afceea3da50af6 sim/testsuite/sim/frv/stqu.cgs
+7a55c30063f85e2d54e1cc2841ee7a63 sim/testsuite/sim/frv/stu.cgs
+2faf06039d62d7df322e435075a72433 sim/testsuite/sim/frv/sub.cgs
+7844ed84fbc9b4ee3a16338a630a6b99 sim/testsuite/sim/frv/subcc.cgs
+8c0c31883700925b3a024a0ef3d6e4db sim/testsuite/sim/frv/subi.cgs
+3a686d8663268c0def363c90e28b1376 sim/testsuite/sim/frv/subicc.cgs
+87cef6e1007d13b030a257ac5991b6e0 sim/testsuite/sim/frv/subx.cgs
+6c55773b2d52d6ed53ba61e9150a8c88 sim/testsuite/sim/frv/subxcc.cgs
+ccb0533eb0f55d739ea829ea6061fd7e sim/testsuite/sim/frv/subxi.cgs
+0bd2bac2e1c8b477c6ca6c96a9c0d2ec sim/testsuite/sim/frv/subxicc.cgs
+8aa6fce072b5f76aed92908d9cb37534 sim/testsuite/sim/frv/swap.cgs
+c8282a4995f3299c881dda28d1a95fe6 sim/testsuite/sim/frv/swapi.cgs
+23522584d66a3f774c033e074adf7612 sim/testsuite/sim/frv/tc.cgs
+7ffb238a56ea272bda7a212d95f41684 sim/testsuite/sim/frv/teq.cgs
+2505dee1a39d2cde6c4c38408239b7c0 sim/testsuite/sim/frv/testutils.inc
+a7bdf9822718f81fe29124a9f8da86e6 sim/testsuite/sim/frv/tge.cgs
+04aeccbcf90bc8f88178560c2910dfc7 sim/testsuite/sim/frv/tgt.cgs
+190947262baf5a431a603a9057bd38a6 sim/testsuite/sim/frv/thi.cgs
+d62ead6b5942f8e2a83a67ef8db006bf sim/testsuite/sim/frv/tic.cgs
+a913dea5c58bfd33d54ec66ebe5abdf3 sim/testsuite/sim/frv/tieq.cgs
+6326a374397a88a326f50a1c5bc7ffe2 sim/testsuite/sim/frv/tige.cgs
+98be2afbdc22e83e7ed60607d14d3586 sim/testsuite/sim/frv/tigt.cgs
+336b596245297750b95b8a77073f7966 sim/testsuite/sim/frv/tihi.cgs
+15b4d16b3eae3485cb76eede88794bbe sim/testsuite/sim/frv/tile.cgs
+100c61ae3fb0dca4723d52d915d79b03 sim/testsuite/sim/frv/tils.cgs
+ce558734ad2bc060917be3c4618d3552 sim/testsuite/sim/frv/tilt.cgs
+ca0a7cd8b619ec89e936a27126c5809d sim/testsuite/sim/frv/tin.cgs
+49bc7107d499c26ff0c4f28999dc36ed sim/testsuite/sim/frv/tinc.cgs
+301a4bafaa39d4e1ab111b7fd38291e9 sim/testsuite/sim/frv/tine.cgs
+51afec41d7406196f09ae12d2ec0db03 sim/testsuite/sim/frv/tino.cgs
+e85d17ee566b10c9e3caeea7e430922e sim/testsuite/sim/frv/tinv.cgs
+4dcd5dd9170ea1b0782fc5ec7bce6e58 sim/testsuite/sim/frv/tip.cgs
+a01a5cb5837ff3029820691d608c0fe3 sim/testsuite/sim/frv/tira.cgs
+4a3754ff5d07a1bff25b091c6475abad sim/testsuite/sim/frv/tiv.cgs
+0852100fd0d41a5575a5d49b4b43537e sim/testsuite/sim/frv/tle.cgs
+e77e2e2eb284cae56dede5c4e7b16bbe sim/testsuite/sim/frv/tls.cgs
+4a9afe4a49c80157e0738e27bd5f3a52 sim/testsuite/sim/frv/tlt.cgs
+eb0c622a60c8bb2159d3a20ddaf72563 sim/testsuite/sim/frv/tn.cgs
+a58b7d334a64b2f17d8110d347c1fcbe sim/testsuite/sim/frv/tnc.cgs
+ec7dfbef9d8c3fcfbd2a205998b43499 sim/testsuite/sim/frv/tne.cgs
+533ecf4107a99d0372bd32229bb091ae sim/testsuite/sim/frv/tno.cgs
+cad1a26e6f61be6236cdf19c6f330241 sim/testsuite/sim/frv/tnv.cgs
+5702a40a3528f6faf8e82e13564087ac sim/testsuite/sim/frv/tp.cgs
+ecca874070d3e9425aeb8088c8a60d30 sim/testsuite/sim/frv/tra.cgs
+41358b18cb9bba0fa299b05270c44629 sim/testsuite/sim/frv/tv.cgs
+d8ef8851170116f7cc0700416b84aa6a sim/testsuite/sim/frv/udiv.cgs
+8cb511e7ba50142c3d082aaedf99e2d4 sim/testsuite/sim/frv/udivi.cgs
+9b3fe3689386f452b6a4efa05a509b8c sim/testsuite/sim/frv/umul.cgs
+77681bcd415a24cb17bbdf0f77eb260b sim/testsuite/sim/frv/umulcc.cgs
+f6e8f7472bf3297a7b540ebaabc0c1f2 sim/testsuite/sim/frv/umuli.cgs
+9797e25ce9dc0b46d586cd0d92620735 sim/testsuite/sim/frv/umulicc.cgs
+0edd78565b6001f524f716ab9d2d96c0 sim/testsuite/sim/frv/xor.cgs
+9be8c0bf0141c153cf179aa9b42ee2d1 sim/testsuite/sim/frv/xorcc.cgs
+04132b96881a20ec0effc93a6a586ea9 sim/testsuite/sim/frv/xorcr.cgs
+738a395cb2d18169d1b0c2027636cf1b sim/testsuite/sim/frv/xori.cgs
+887a01bed2d74acf834781ed7fa9f560 sim/testsuite/sim/frv/xoricc.cgs
+3e48a7675e041e56f1aff0fe96c45a4c sim/testsuite/sim/frv/fr400/addss.cgs
+072a0a143c04db0a6ce34d56ecc749d8 sim/testsuite/sim/frv/fr400/allinsn.exp
+07bb80901aaaa29c4ef20dbef3debb70 sim/testsuite/sim/frv/fr400/csdiv.cgs
+dc7862c2d91981e56cddc36314f0c630 sim/testsuite/sim/frv/fr400/maddaccs.cgs
+4cc9052cb05275a67396e5ea46d54af6 sim/testsuite/sim/frv/fr400/masaccs.cgs
+2039d3b5260700c8371efd1a6ab21552 sim/testsuite/sim/frv/fr400/maveh.cgs
+4ac0a330e6fa287d0f2f2f8500453afc sim/testsuite/sim/frv/fr400/mclracc.cgs
+285f596d7467307f369b18d453abe1ea sim/testsuite/sim/frv/fr400/mhdseth.cgs
+5e1be1e0297eb84b961c6dc29d4cce8c sim/testsuite/sim/frv/fr400/mhdsets.cgs
+9bb2a41f38271c359451454b6d2a79dc sim/testsuite/sim/frv/fr400/mhsethih.cgs
+dac84369f283aabc0e0c8d6188130e92 sim/testsuite/sim/frv/fr400/mhsethis.cgs
+538622163aded8a4e8f1d47d61db8b5c sim/testsuite/sim/frv/fr400/mhsetloh.cgs
+a808c8a95fde4532828d00e281c1322c sim/testsuite/sim/frv/fr400/mhsetlos.cgs
+a1032b0fb6b6923000282a43d3f85a7a sim/testsuite/sim/frv/fr400/movgs.cgs
+0f2cd9ab4e36a741a77488033a0ceeb0 sim/testsuite/sim/frv/fr400/movsg.cgs
+e4644c48c06766cd34578d5ce34680dd sim/testsuite/sim/frv/fr400/msubaccs.cgs
+ba109065c4434a5d494a8270aaa91e7b sim/testsuite/sim/frv/fr400/scutss.cgs
+daad245fe005a9a6394bb569733c9aed sim/testsuite/sim/frv/fr400/sdiv.cgs
+b90754c53de9e9744ee927d4993920fc sim/testsuite/sim/frv/fr400/sdivi.cgs
+2eba80fdfa94ab8c80ac014b8bce4c94 sim/testsuite/sim/frv/fr400/slass.cgs
+b6607c22a2cff244b1720df63e9c149b sim/testsuite/sim/frv/fr400/smass.cgs
+7dcecbc0d78a0b067e70fc750c890f49 sim/testsuite/sim/frv/fr400/smsss.cgs
+d552b09ce35ed9fb50c5cff2166faf35 sim/testsuite/sim/frv/fr400/smu.cgs
+fbfe45803aaf124fcda55a7bea2a97ea sim/testsuite/sim/frv/fr400/subss.cgs
+621cd869aa5b032b34294f31f3e4a702 sim/testsuite/sim/frv/fr400/udiv.cgs
+146cea8d68ddb592d231ab14478a8d0b sim/testsuite/sim/frv/fr400/udivi.cgs
+bf7e8ae5fa9de937c99e7e09f42bbac5 sim/testsuite/sim/frv/fr500/allinsn.exp
+9fdc5172e86b3be5621a6faf3f07db74 sim/testsuite/sim/frv/fr500/cmqaddhss.cgs
+1de69657638007870281ce9da005db7f sim/testsuite/sim/frv/fr500/cmqaddhus.cgs
+76820a559b8411a4ae43b6a383d65b0d sim/testsuite/sim/frv/fr500/cmqsubhss.cgs
+dc65c316119a5c8162d829bbd7c0223a sim/testsuite/sim/frv/fr500/cmqsubhus.cgs
+16004a850f6c18d31c7430fbab31f79d sim/testsuite/sim/frv/fr500/dcpl.cgs
+54a02614046bab2457214898aff37526 sim/testsuite/sim/frv/fr500/dcul.cgs
+99e08a053ed3e5abb1c4bf9c6a64fbc1 sim/testsuite/sim/frv/fr500/mclracc.cgs
+fe34b6bddc9686a443e9025451c3ac88 sim/testsuite/sim/frv/fr500/mqaddhss.cgs
+b113a28c5f41f7ab598d39fab2d5e21f sim/testsuite/sim/frv/fr500/mqaddhus.cgs
+35285cc52bbb31d9b25d6144f54fa5b5 sim/testsuite/sim/frv/fr500/mqsubhss.cgs
+d5b43c22363018a3259eb6849019a024 sim/testsuite/sim/frv/fr500/mqsubhus.cgs
+d35335c0a9a7da8ef8224e724dc95c81 sim/testsuite/sim/frv/fr550/allinsn.exp
+091a034f51a640f3113ea17c26e3b296 sim/testsuite/sim/frv/fr550/cmaddhss.cgs
+ddaf6b5840f92b8d37a897bac56b86b0 sim/testsuite/sim/frv/fr550/cmaddhus.cgs
+c41c0de91e307c8506c8c5275940f7ea sim/testsuite/sim/frv/fr550/cmcpxiu.cgs
+9b75556c75c9bfb61102e93aa0b85be4 sim/testsuite/sim/frv/fr550/cmcpxru.cgs
+14be5a3d28703927ea3b168b6140855d sim/testsuite/sim/frv/fr550/cmmachs.cgs
+df6f7d84607830c79a2f338b8b6160f6 sim/testsuite/sim/frv/fr550/cmmachu.cgs
+dea84ff288f50a75076a9c6df51682c6 sim/testsuite/sim/frv/fr550/cmqaddhss.cgs
+d20b77015f938e4bcf50ebffae74fc6b sim/testsuite/sim/frv/fr550/cmqaddhus.cgs
+d6946f604c4c119692ac621e5cdf0a92 sim/testsuite/sim/frv/fr550/cmqmachs.cgs
+c28cd342558f4cc6ad9b33d7c80b45aa sim/testsuite/sim/frv/fr550/cmqmachu.cgs
+9f27020e63e8992a63456f9092967d34 sim/testsuite/sim/frv/fr550/cmqsubhss.cgs
+b13883bf53e547a18365378a79b4ff9a sim/testsuite/sim/frv/fr550/cmqsubhus.cgs
+cae62d22839ef1abf864fd44a1087197 sim/testsuite/sim/frv/fr550/cmsubhss.cgs
+1b1c3f8892f5ff1108650006f4f2318a sim/testsuite/sim/frv/fr550/cmsubhus.cgs
+f564e7d684efbe7a682ba9aa24cf39ab sim/testsuite/sim/frv/fr550/dcpl.cgs
+0bfbdf1314d6a04afa36ce4404a81bf2 sim/testsuite/sim/frv/fr550/dcul.cgs
+cd733adfb1ef5d2f7d93d57183587d7a sim/testsuite/sim/frv/fr550/mabshs.cgs
+55c8d941be619469d2bf80f7eba5a3cf sim/testsuite/sim/frv/fr550/maddaccs.cgs
+269e14aaffa3452b360e1f0ddb12df93 sim/testsuite/sim/frv/fr550/maddhss.cgs
+ffbb77202774953b6eb98f6329c3221c sim/testsuite/sim/frv/fr550/maddhus.cgs
+aed0b1242d7c5a0eada01cb581ef44ab sim/testsuite/sim/frv/fr550/masaccs.cgs
+594c6a9c3278bcc019e98aa44a86c22a sim/testsuite/sim/frv/fr550/mdaddaccs.cgs
+7cdef8608795f0ed222e67db1343a635 sim/testsuite/sim/frv/fr550/mdasaccs.cgs
+14183fbd685848d558ab84952c1271b1 sim/testsuite/sim/frv/fr550/mdsubaccs.cgs
+85c318f9489df3a78af9171868d9e789 sim/testsuite/sim/frv/fr550/mmachs.cgs
+7c4ba31a4b54c5449d932fceeeb3aa1d sim/testsuite/sim/frv/fr550/mmachu.cgs
+f105b296560b5b75436069679f4d6dfd sim/testsuite/sim/frv/fr550/mmrdhs.cgs
+5ade21b6577e4102c74e56fd9ac67d5d sim/testsuite/sim/frv/fr550/mmrdhu.cgs
+252cdd83e9dd8de140e437bcc84a45a6 sim/testsuite/sim/frv/fr550/mqaddhss.cgs
+4938bf73cdf15f5d4a195ccc1bc1a426 sim/testsuite/sim/frv/fr550/mqaddhus.cgs
+7ccfed47ea8ad55515dab94b96d6babf sim/testsuite/sim/frv/fr550/mqmachs.cgs
+aef3c4befd6509d86b1532ddbf3fb4a9 sim/testsuite/sim/frv/fr550/mqmachu.cgs
+76e79dccff8084f4921e771c099fdbe0 sim/testsuite/sim/frv/fr550/mqmacxhs.cgs
+a73a09a1e4d5df6332355e6558054066 sim/testsuite/sim/frv/fr550/mqsubhss.cgs
+e3ef857df51606a95b919b802bc62434 sim/testsuite/sim/frv/fr550/mqsubhus.cgs
+f7992a1f5e0512afb72f4ea8abf785ed sim/testsuite/sim/frv/fr550/mqxmachs.cgs
+1d35c09a8a300edc364a00ba655ca259 sim/testsuite/sim/frv/fr550/mqxmacxhs.cgs
+60a0aa6675f9b1d37f0b6b58e04e6aba sim/testsuite/sim/frv/fr550/msubaccs.cgs
+26acdfc92872c06ef0f3750cda5f6f75 sim/testsuite/sim/frv/fr550/msubhss.cgs
+90677e8af5e1904d14d9bfd3e562fcbb sim/testsuite/sim/frv/fr550/msubhus.cgs
+45902a95cfa0b6432a1cbb6db50830b6 sim/testsuite/sim/frv/fr550/mtrap.cgs
+57f7099366dbf0b511896d03b5343808 sim/testsuite/sim/frv/fr550/udiv.cgs
+55cd07e74cc057a786a2a9c43ed5d8dc sim/testsuite/sim/frv/fr550/udivi.cgs
+c6ab746acfbb43a0b62848e6626307be sim/testsuite/sim/frv/interrupts/Ipipe-fr400.cgs
+fad5307c32c5fd7792da21d6fa8034a4 sim/testsuite/sim/frv/interrupts/Ipipe-fr500.cgs
+1442aef29a1429ad5b417d6e072f0bed sim/testsuite/sim/frv/interrupts/badalign-fr550.cgs
+bb56d8cd61856a2eceb509be16a37354 sim/testsuite/sim/frv/interrupts/badalign.cgs
+ba84baad2c0fbc0fb425f3042fa91e04 sim/testsuite/sim/frv/interrupts/compound-fr550.cgs
+e7920163cd59bc2dd0f5d977fc7566bd sim/testsuite/sim/frv/interrupts/compound.cgs
+2a80a2eee2d47ba494278b13a0eae8e7 sim/testsuite/sim/frv/interrupts/data_store_error-fr550.cgs
+3b7c9b823a6bdae97b790110baa1cd1b sim/testsuite/sim/frv/interrupts/data_store_error.cgs
+dfeabfd77b473aa8a95f7049b362944d sim/testsuite/sim/frv/interrupts/fp_exception-fr550.cgs
+26c8314f6b8c8534a84f9a98701aca07 sim/testsuite/sim/frv/interrupts/fp_exception.cgs
+9dc2f73112811f25a5a15f53a6be64e2 sim/testsuite/sim/frv/interrupts/illinsn.cgs
+be93394d8610eb7a13b316901ad8a9b5 sim/testsuite/sim/frv/interrupts/insn_access_error-fr550.cgs
+bc6228cbbffde88aba638f1e9ef39ad5 sim/testsuite/sim/frv/interrupts/insn_access_error.cgs
+d3bf79293e8377be411d124f213784e1 sim/testsuite/sim/frv/interrupts/mp_exception.cgs
+d78319cc00e420d2ea14a943bacb5b73 sim/testsuite/sim/frv/interrupts/privileged_instruction.cgs
+4dcb6ae1f3af2a946fccc0349454555e sim/testsuite/sim/frv/interrupts/regalign.cgs
+a03ea7e55879465603afc8e54e656577 sim/testsuite/sim/frv/interrupts/reset.cgs
+90377ce05b3a5bfdde34c7349008e3d3 sim/testsuite/sim/frv/interrupts/shadow_regs.cgs
+026ab0d2d0845245adbc296619cc9d46 sim/testsuite/sim/frv/interrupts/timer.cgs
+7e9bf038c823c2726a964b26f9a4671f sim/testsuite/sim/h8300/ChangeLog
+ce415b253063a7fe5cf02f17fb48faab sim/testsuite/sim/h8300/addb.s
+399b6e09a2ae39da12b2321cd0965b91 sim/testsuite/sim/h8300/addl.s
+2dad02e99bd1422af83cb4353b7e63c0 sim/testsuite/sim/h8300/adds.s
+9766c17a5c5cc1408ada3b9cc437ba28 sim/testsuite/sim/h8300/addw.s
+8cbc4afc2f6b11b850e0aec04ed1a473 sim/testsuite/sim/h8300/addx.s
+1b1082501d2ae954bf8cfe0ef39b83c2 sim/testsuite/sim/h8300/allinsn.exp
+90637fa47d75134bb5869022a29f120c sim/testsuite/sim/h8300/andb.s
+6fdb213d98f348f1c02d48ffcfd806e5 sim/testsuite/sim/h8300/andl.s
+376c12070675b9d7dd2c58e70ee98842 sim/testsuite/sim/h8300/andw.s
+6902ac6642088250609f8e019c17c156 sim/testsuite/sim/h8300/band.s
+fce577f47862442fa9b2da616615c1d2 sim/testsuite/sim/h8300/bfld.s
+363c9b0e04241d42714a73ac65312b9a sim/testsuite/sim/h8300/biand.s
+0412ca2321a01a8b7c32897e3f32dd37 sim/testsuite/sim/h8300/bra.s
+e2433fc36981757f93eb5bb4f1b039ac sim/testsuite/sim/h8300/brabc.s
+c43286a0003746027f1e57893e29b060 sim/testsuite/sim/h8300/bset.s
+dd6fabe64292ad56b43ca5532e790417 sim/testsuite/sim/h8300/cmpb.s
+5d4de83de24b934dbec418f81b0fbc02 sim/testsuite/sim/h8300/cmpl.s
+16151c89821d742e389f60a77a9c4214 sim/testsuite/sim/h8300/cmpw.s
+4c711137a90bb2ba4b2f44ad3ef33ba7 sim/testsuite/sim/h8300/daa.s
+7032f158ede5e9c1fe95569152aac2a7 sim/testsuite/sim/h8300/das.s
+7038c79de7fb4f02cd5ef969e2cffd30 sim/testsuite/sim/h8300/dec.s
+882cd22437078ea48acb50bb803cbbd5 sim/testsuite/sim/h8300/div.s
+caa5a5b27cbcbfaea63298e864279ae4 sim/testsuite/sim/h8300/extl.s
+a159e301d3202b02c3d6ac416aeedcf6 sim/testsuite/sim/h8300/extw.s
+388f4ab3999f0a563801fbdec2667f71 sim/testsuite/sim/h8300/inc.s
+c5cc1774fded69045dd1d5a31e4eecc7 sim/testsuite/sim/h8300/jmp.s
+5745f4f097642a8d3aa1e6f949b20d72 sim/testsuite/sim/h8300/ldc.s
+677c2ca0cf5c9c3c593a7a9274859bba sim/testsuite/sim/h8300/ldm.s
+63a01cd1ac69acaa0cb441c4f1ef5b89 sim/testsuite/sim/h8300/mac.s
+4e839f3223289908cd6e2ba525776dec sim/testsuite/sim/h8300/mova.s
+7cf771780ab43e6a7a25ed05f8a17ee7 sim/testsuite/sim/h8300/movb.s
+abfa7675b179fc4254e14cec675be772 sim/testsuite/sim/h8300/movl.s
+c0f7ecf275c71ba8ba57b2098887abf4 sim/testsuite/sim/h8300/movmd.s
+637fafb5b7e807abbb1f528bca9cc697 sim/testsuite/sim/h8300/movsd.s
+8bfd3316d1c16f85273138771fdbbbf0 sim/testsuite/sim/h8300/movw.s
+4925d8fc7e47b2223de921e76eefc6c0 sim/testsuite/sim/h8300/mul.s
+2373f3011c78310592feef6fe9432f0a sim/testsuite/sim/h8300/neg.s
+99f82cb39a007343d1a5bd8c71960fcb sim/testsuite/sim/h8300/nop.s
+a1ed4f63b96068eaa77495745494ffea sim/testsuite/sim/h8300/not.s
+a938731b6a18a4e389d565b373fdb164 sim/testsuite/sim/h8300/orb.s
+62d2fe5825e86377f04ad0167a214c62 sim/testsuite/sim/h8300/orl.s
+5d42a1f9b287e529549796fef4c879c8 sim/testsuite/sim/h8300/orw.s
+b99bd4670fdfe75f10e37ea480d537f0 sim/testsuite/sim/h8300/rotl.s
+f75f1bed46894927fbb7773bc84081fc sim/testsuite/sim/h8300/rotr.s
+3b4dfe0168e63c6e80583c262c5de759 sim/testsuite/sim/h8300/rotxl.s
+4eecc1e3c8c3ef39f35071a0d35c126e sim/testsuite/sim/h8300/rotxr.s
+ffef0a19e06ed3716630c870e2c78e97 sim/testsuite/sim/h8300/shal.s
+0b8a477e0fbf76499733fc12811aa4c6 sim/testsuite/sim/h8300/shar.s
+0f85e20fbab15124e67dde283ee4b159 sim/testsuite/sim/h8300/shll.s
+3b3ad8e7276c6719c8adfa92951bef0b sim/testsuite/sim/h8300/shlr.s
+e1a2e3252f570905ffbdc48d6a44089d sim/testsuite/sim/h8300/stack.s
+ebd21badf420c5cee8b0d88a08868304 sim/testsuite/sim/h8300/stc.s
+9b63ff9fbde1e63acd708924198b7242 sim/testsuite/sim/h8300/subb.s
+a63920fd12f48e551687aacc6bfae557 sim/testsuite/sim/h8300/subl.s
+c55d9e46ef6b31eb575f129340b18dce sim/testsuite/sim/h8300/subs.s
+db0176e7c9b6cb42862f2377e55312f5 sim/testsuite/sim/h8300/subw.s
+e0e2129ddb10014bc62124746c911369 sim/testsuite/sim/h8300/subx.s
+81e2e460e06fcf47b7ed621287bfbafa sim/testsuite/sim/h8300/tas.s
+e889ba6121bfc3b32c11372b6d4c9dcd sim/testsuite/sim/h8300/testutils.inc
+307b4b54b70c077beb6b886ed1dadc9d sim/testsuite/sim/h8300/xorb.s
+8ea8bfb6cddf05ef11ea7fb068e218e6 sim/testsuite/sim/h8300/xorl.s
+c2e57a11d5e455cef19248c2a0fb26b0 sim/testsuite/sim/h8300/xorw.s
+16834904d188192c7fbb15f488c53087 sim/testsuite/sim/m32r/add.cgs
+e9adf1458ab377d5d90d1678d2292bd5 sim/testsuite/sim/m32r/add3.cgs
+8cf9213ee7ef813787645bc4c9e12727 sim/testsuite/sim/m32r/addi.cgs
+a7b10e6f679c84fe5b2db48164037526 sim/testsuite/sim/m32r/addv.cgs
+30cfed398315d692a3de98e4c67f90af sim/testsuite/sim/m32r/addv3.cgs
+690ba3d9db8db10a35899c8eac122f65 sim/testsuite/sim/m32r/addx.cgs
+787a6f21f2739736e0a79118443e311a sim/testsuite/sim/m32r/allinsn.exp
+7d5b3e41f7f293b573606e13d0a5c301 sim/testsuite/sim/m32r/and.cgs
+29e08614d0fde06b6322dad1cc619d93 sim/testsuite/sim/m32r/and3.cgs
+f57a1ae6784adef83a83d0fc96e627d3 sim/testsuite/sim/m32r/bc24.cgs
+b5eba276aa402a66811d04183ae7da9b sim/testsuite/sim/m32r/bc8.cgs
+43914dad0473cf29fa8ba7483fcc42a1 sim/testsuite/sim/m32r/beq.cgs
+aa647bf776c6497768956dd13b1bc0e6 sim/testsuite/sim/m32r/beqz.cgs
+bcd9f3fee3d28ed1096a5ef6514c0538 sim/testsuite/sim/m32r/bgez.cgs
+61391eba2b47c3b035c549673a100135 sim/testsuite/sim/m32r/bgtz.cgs
+9041e76bd9e52d5245b6485c481ce1e3 sim/testsuite/sim/m32r/bl24.cgs
+9be91c4daa50b174585b34804fadde45 sim/testsuite/sim/m32r/bl8.cgs
+a38ca2fe69cd52716f929b7be6ee5690 sim/testsuite/sim/m32r/blez.cgs
+b30f0ad9c59b0374e5b52f24e549ae36 sim/testsuite/sim/m32r/bltz.cgs
+1b3b8a230f2693ae45a566995a0b9775 sim/testsuite/sim/m32r/bnc24.cgs
+ae67e7de7ffee3af12ef63c7770eb6be sim/testsuite/sim/m32r/bnc8.cgs
+7a9b903b84abb5fead9cdfdde1804492 sim/testsuite/sim/m32r/bne.cgs
+2bd489b3cdd376a0a6b2de5f4a26712f sim/testsuite/sim/m32r/bnez.cgs
+ae803eba46d3c6a6aa1c741aec2783be sim/testsuite/sim/m32r/bra24.cgs
+0ebb2e3161db55a3203b65392361b6bd sim/testsuite/sim/m32r/bra8.cgs
+d863c2fc17c8b7509aa0996e8a3f15b4 sim/testsuite/sim/m32r/cmp.cgs
+7d8da1455d2cd44a51707b07b4b00977 sim/testsuite/sim/m32r/cmpi.cgs
+1e2a8c3e0cc7b5988cef7334bf2e14bf sim/testsuite/sim/m32r/cmpu.cgs
+0e4b1ac17d86c08b1d98e90ee379e7c8 sim/testsuite/sim/m32r/cmpui.cgs
+42509b9f2bc28c62f815e3094e75f4ea sim/testsuite/sim/m32r/div.cgs
+fc14b150efe66c251e584a8490ab411c sim/testsuite/sim/m32r/divu.cgs
+f3f4a05a6d442fdb1a2dbe82fbc22d5e sim/testsuite/sim/m32r/hello.ms
+62c53b4fa4929b659e1b8f3dce7ed101 sim/testsuite/sim/m32r/hw-trap.ms
+72ae1c84434e74d7a53d09e002ab9830 sim/testsuite/sim/m32r/jl.cgs
+3f2b2701b3579de8839bd35d25076d03 sim/testsuite/sim/m32r/jmp.cgs
+34c7f8c3e919f9ba0f0b3c7caa68f237 sim/testsuite/sim/m32r/ld-d.cgs
+e0e5a244234e059b9099534cde98fd29 sim/testsuite/sim/m32r/ld-plus.cgs
+dcbcafa8b504f5c1750e3a7f33d06b04 sim/testsuite/sim/m32r/ld.cgs
+a1584b288866f94579bbf2981c7d812e sim/testsuite/sim/m32r/ld24.cgs
+8e71d37539927768d17f19c43cfe41bf sim/testsuite/sim/m32r/ldb-d.cgs
+31a4c374f7d38d4214300cb58342cb7e sim/testsuite/sim/m32r/ldb.cgs
+55e96d8c138d454b947b0c627268410a sim/testsuite/sim/m32r/ldh-d.cgs
+101e467bd8d9570809bd743b775e657d sim/testsuite/sim/m32r/ldh.cgs
+29dd50ce15ab9c0d67791901e45a791d sim/testsuite/sim/m32r/ldi16.cgs
+ddcce0a4e903b1df7a8d3f9d07b133b4 sim/testsuite/sim/m32r/ldi8.cgs
+5422abf5a05ea36c524bac97c177f79a sim/testsuite/sim/m32r/ldub-d.cgs
+b464f9a46248faed5a856867decd109b sim/testsuite/sim/m32r/ldub.cgs
+38f45019c0a3b58549b0dba4f6595f20 sim/testsuite/sim/m32r/lduh-d.cgs
+d0c711109b91fb82235f2c7de6be93e0 sim/testsuite/sim/m32r/lduh.cgs
+17eccc048da153abc362bee34fe42579 sim/testsuite/sim/m32r/lock.cgs
+a249bb8bdbaad16488d816dbd85eb1a1 sim/testsuite/sim/m32r/machi.cgs
+7d3d647734fda959f3b1e738c2b90222 sim/testsuite/sim/m32r/maclo.cgs
+42e2898d542715203fac38dbabe95593 sim/testsuite/sim/m32r/macwhi.cgs
+606cf06f01516f620ade2833b6f4272f sim/testsuite/sim/m32r/macwlo.cgs
+17924a13af249ae4d0a6df996e622124 sim/testsuite/sim/m32r/misc.exp
+497cfa2e1bc18e2fadb92c99fbcadcab sim/testsuite/sim/m32r/mul.cgs
+0ea66074ee25fd61d52074d38b4358e6 sim/testsuite/sim/m32r/mulhi.cgs
+951d325ba4e7036401fa243439c0f27f sim/testsuite/sim/m32r/mullo.cgs
+518d60a9ec3ed23e3da2aff0b1456ac0 sim/testsuite/sim/m32r/mulwhi.cgs
+fbed9d4fe93ebbb695228b4a94655dd5 sim/testsuite/sim/m32r/mulwlo.cgs
+ecaba0191d387d8875378bf790693bbe sim/testsuite/sim/m32r/mv.cgs
+60ce74d2420a29592309f2f3cbf0bb27 sim/testsuite/sim/m32r/mvfachi.cgs
+ab51940820c840824c1309f87b0c7430 sim/testsuite/sim/m32r/mvfaclo.cgs
+9c2236dea1f22183f110260aac6e7821 sim/testsuite/sim/m32r/mvfacmi.cgs
+aa1ec114448f408800129388f774de40 sim/testsuite/sim/m32r/mvfc.cgs
+ee8c3058b6a4fc408f0725c7e0027956 sim/testsuite/sim/m32r/mvtachi.cgs
+8cfc6346c5ce5f4e7464057b25ec31b7 sim/testsuite/sim/m32r/mvtaclo.cgs
+8f0cac941aa884623e680f3e4ac0c8b1 sim/testsuite/sim/m32r/mvtc.cgs
+98c363f615a992eebb741216c4b99238 sim/testsuite/sim/m32r/neg.cgs
+57368ba4c4be662e4d7e09c2fbf73007 sim/testsuite/sim/m32r/nop.cgs
+b0703d4f2678b98efa516375d14989d8 sim/testsuite/sim/m32r/not.cgs
+9778769d1c0af0c0fc330032708ff835 sim/testsuite/sim/m32r/or.cgs
+4adb31d9941df9283e7d046457611c97 sim/testsuite/sim/m32r/or3.cgs
+9171592763b85a01ee783cc5c814c696 sim/testsuite/sim/m32r/rac.cgs
+ec2520e6aae9332a6671d4c8a8e5b045 sim/testsuite/sim/m32r/rach.cgs
+241464dd5ebda3e9291399db7f07fde6 sim/testsuite/sim/m32r/rem.cgs
+79728809577a7966c7f6d3e74eeeab11 sim/testsuite/sim/m32r/remu.cgs
+e200d0626a3a782b1ba827d77008622c sim/testsuite/sim/m32r/rte.cgs
+966058aa7f21ef4a7874f1a0d9888543 sim/testsuite/sim/m32r/seth.cgs
+672b4886a81c13ca0bf05d1df568df5f sim/testsuite/sim/m32r/sll.cgs
+37da8b574adf3cb6f65a7119fab322a7 sim/testsuite/sim/m32r/sll3.cgs
+8a79f97b82a93537f9d0afd46d1ce63e sim/testsuite/sim/m32r/slli.cgs
+b29c344695a538384d37acf2acf3f974 sim/testsuite/sim/m32r/sra.cgs
+237457a459b83e66c0a0f95ba0842910 sim/testsuite/sim/m32r/sra3.cgs
+c86fb3aef80e809c5161380443aec696 sim/testsuite/sim/m32r/srai.cgs
+cda1698f1a6d640498ce3e6cd47add4f sim/testsuite/sim/m32r/srl.cgs
+806b43d4fd12897c2b02e9b2f876b308 sim/testsuite/sim/m32r/srl3.cgs
+e43074ac62cc10354b7a7759fe2fe869 sim/testsuite/sim/m32r/srli.cgs
+15a9f901cebcbc565c224f6c61c07326 sim/testsuite/sim/m32r/st-d.cgs
+88d455c342dfa2947283cd4e7b82f3a1 sim/testsuite/sim/m32r/st-minus.cgs
+c66238280149c9f42dd1e19852afd136 sim/testsuite/sim/m32r/st-plus.cgs
+a79a2f93fa80d613b872cc172ef3e9e8 sim/testsuite/sim/m32r/st.cgs
+81e73b1946f04046a562428a766077ec sim/testsuite/sim/m32r/stb-d.cgs
+d6a79a79477689d7e9bf45ff48a1d65c sim/testsuite/sim/m32r/stb.cgs
+5b9e264b3d7e3e123150e7933e9776bf sim/testsuite/sim/m32r/sth-d.cgs
+cc4e95eb280ae19c0d22b639bc9fc601 sim/testsuite/sim/m32r/sth.cgs
+faf25008374bb5be6c2d003c079b6b62 sim/testsuite/sim/m32r/sub.cgs
+8a180be9e21c1fcadb9dbbc751093bb2 sim/testsuite/sim/m32r/subv.cgs
+9bd48d851532a2d84c1edf2872c9a66e sim/testsuite/sim/m32r/subx.cgs
+45e6e4177ecd2fe6a1ecde8fcb839662 sim/testsuite/sim/m32r/testutils.inc
+54efa34ea2ee72560aa9d26f7f557879 sim/testsuite/sim/m32r/trap.cgs
+cfd913f0a5ee4bd41656b5e4283c96d1 sim/testsuite/sim/m32r/unlock.cgs
+faf23b2f12b51357e3e72b13e79ecc7c sim/testsuite/sim/m32r/uread16.ms
+9c7bdcfc3ad3791fa0248573c2307cf9 sim/testsuite/sim/m32r/uread32.ms
+6df2ea19b2030cc2ad6f1631641587a6 sim/testsuite/sim/m32r/uwrite16.ms
+749a9149d30e113900b3f089779740ed sim/testsuite/sim/m32r/uwrite32.ms
+6f6c3fdb3474157358c545914bf2c510 sim/testsuite/sim/m32r/xor.cgs
+3795134a6b03341f5a6480f66e7c29f1 sim/testsuite/sim/m32r/xor3.cgs
+2303ec0b7c85c4dae0a176a8fb013a23 sim/testsuite/sim/mips/ChangeLog
+db173789cf837f57257b44c19e0b915b sim/testsuite/sim/mips/basic.exp
+b19e0c53b685c87920887bc87dba4579 sim/testsuite/sim/mips/sanity.s
+457ea0e4004e3c71d5233f89df113f8c sim/testsuite/sim/mips/testutils.inc
+39ec50dfc186bd1d1ca11891f351a9bb sim/testsuite/sim/sh/ChangeLog
+282a3539572ea760a8d7a480a27800d4 sim/testsuite/sim/sh/add.s
+2e32e434523a02fba516046b4cbed5e8 sim/testsuite/sim/sh/allinsn.exp
+f8dca2ef83e73c5c462ef000c13478bb sim/testsuite/sim/sh/and.s
+69150191761fac26b8276af2f85efd90 sim/testsuite/sim/sh/dmxy.s
+e4e686dacc645b9fc1114279b13b460b sim/testsuite/sim/sh/fabs.s
+7fcd022e6881b031f0deee8c6816a79a sim/testsuite/sim/sh/fadd.s
+22f8beefa505dc232a3593e167d51b2b sim/testsuite/sim/sh/fcmpeq.s
+f98492eeeab950ed63e6c2d52a3c57d8 sim/testsuite/sim/sh/fcmpgt.s
+45e3b96fa5b2e581805f106c3d99f968 sim/testsuite/sim/sh/fcnvds.s
+7f6673539421b7915a57f34826612d75 sim/testsuite/sim/sh/fcnvsd.s
+ea612dc8f08a57ade93a63b0b6563e5c sim/testsuite/sim/sh/fdiv.s
+f008ac5e491f8ceab68b9f59056e9b16 sim/testsuite/sim/sh/fipr.s
+b43309a7445615ae8abafb4900d4f3e7 sim/testsuite/sim/sh/fldi0.s
+5fdca3286426034467b63b36d3a3c5e2 sim/testsuite/sim/sh/fldi1.s
+47831a2ea8e21901de14ee85de649e42 sim/testsuite/sim/sh/flds.s
+47a2df7f664eaff06846045d7e64b5ce sim/testsuite/sim/sh/float.s
+04ba23f9a7e46a261c68dc833abac5a3 sim/testsuite/sim/sh/fmac.s
+6074ab626f6f749947d90dad804223a8 sim/testsuite/sim/sh/fmov.s
+c3b63bb6fbe1f996d7e66e6ed5ef9f32 sim/testsuite/sim/sh/fmul.s
+e548ee358487284309e5b5717cabf0f9 sim/testsuite/sim/sh/fneg.s
+0b43bcfde07c09c6103965070e9046ae sim/testsuite/sim/sh/fpchg.s
+9b040b83149755d82c2328509c12535e sim/testsuite/sim/sh/frchg.s
+cd42365d5bc0d1bb4979cdfd320ce433 sim/testsuite/sim/sh/fschg.s
+f5d3cc68031f17d500295fbcd18bb1f7 sim/testsuite/sim/sh/fsqrt.s
+92f8a202d1e874f537d74831851dba46 sim/testsuite/sim/sh/fsub.s
+ed2aa1abfc2026579333e2253c838294 sim/testsuite/sim/sh/ftrc.s
+b1d24d30151886ff5bf5bc86758709b1 sim/testsuite/sim/sh/ldrc.s
+954b6cdc60b0808db2732f2f65d65983 sim/testsuite/sim/sh/loop.s
+d0c8446d0ede1ebe79245b96cb002c8d sim/testsuite/sim/sh/macl.s
+48d214fbad43f9efc8c0cc2014239984 sim/testsuite/sim/sh/macw.s
+ac143ce8d55a865d8b4946d30368e814 sim/testsuite/sim/sh/movi.s
+b07d68ae2523ae371be0b115d5cc9253 sim/testsuite/sim/sh/movli.s
+7c4dae24fda79de6de7776bcbe4f21b0 sim/testsuite/sim/sh/movua.s
+0c12a523abb2532f2abb3eeeff95cfce sim/testsuite/sim/sh/movxy.s
+fcad598d555a1a24eaa76710c494e71b sim/testsuite/sim/sh/pabs.s
+d8c8b220768728a015ad5b9fbb9d2c90 sim/testsuite/sim/sh/padd.s
+8f6a40a17e345540ee1f269d29aa5d9a sim/testsuite/sim/sh/paddc.s
+be1710af076cee30f8262a7bef8685ab sim/testsuite/sim/sh/pand.s
+532a7fc5abd000fbfcdfa409da20f0fa sim/testsuite/sim/sh/pclr.s
+4152aee3945ac6afc68b16dd206f851a sim/testsuite/sim/sh/pdec.s
+c3726f7efa272c1305bc3a7ad9225e5b sim/testsuite/sim/sh/pdmsb.s
+6ee03b6e9943d9a05f82c8206ce794cf sim/testsuite/sim/sh/pinc.s
+e7a32d44b0b0d9d4309d241eaf991fcf sim/testsuite/sim/sh/pmuls.s
+dc3cb25df84ca51ea42371f6a4dec6aa sim/testsuite/sim/sh/prnd.s
+e8ca39483f9c71cfdb1b1b03069df2bc sim/testsuite/sim/sh/pshai.s
+81c176582a8667af8f6c72a2728737ab sim/testsuite/sim/sh/pshar.s
+1f420e9b6f74d6d03ae952bdffbd8799 sim/testsuite/sim/sh/pshli.s
+eed4f3e2827f2bdcff0fd693f4be62d0 sim/testsuite/sim/sh/pshlr.s
+698d502e8fcf6a8e8193fee2a1274e94 sim/testsuite/sim/sh/psub.s
+40b3372c773573dc611cbd9c64efa162 sim/testsuite/sim/sh/pswap.s
+73bee7558210c5db604fb0929091597e sim/testsuite/sim/sh/sett.s
+19200c14eefed0db8e7e3f7b7df9a7da sim/testsuite/sim/sh/shll.s
+c56c6a1871d8e035a8eb50e2c1cb89f0 sim/testsuite/sim/sh/shll16.s
+12c9ce87dbd160a77d59f6aa29ddd375 sim/testsuite/sim/sh/shll2.s
+bd6af3c86e2f58147320c9b2961781cd sim/testsuite/sim/sh/shll8.s
+9c9f493d16eacff7f4315bd95a0c8b18 sim/testsuite/sim/sh/shlr.s
+f379912c20dda0ba7cd86cecc19eca47 sim/testsuite/sim/sh/shlr16.s
+ddfdbd007dc52a5ecc5e1981dc705462 sim/testsuite/sim/sh/shlr2.s
+eff7f8091a30f489f6cf9bb2c8aeac8d sim/testsuite/sim/sh/shlr8.s
+5fb60364b4fd1e6b5d37ccdd4c3f4540 sim/testsuite/sim/sh/swap.s
+84db70d9d853cc339ac12070acdfb063 sim/testsuite/sim/sh/testutils.inc
+33ade97f3bd72f515783037150efae9c sim/v850/ChangeLog
+5155b7f1ab78c062f466a9d5462058d4 sim/v850/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/v850/acconfig.h
+dc553d113147dcc545cf06254dc945cd sim/v850/config.in
+6ab57e58e6db8fa8c9dd7fee520f44eb sim/v850/configure
+fa12dcce375574441b85dfd39d7fffd9 sim/v850/configure.in
+d8b6b349332fde351e242d3735926144 sim/v850/interp.c
+5c6de75cf871f9762d4a7c341dcd4afc sim/v850/sim-main.h
+a80e2ec5e4a78870d477bc970b793381 sim/v850/simops.c
+bee4a6a9ecb7e78bab13c75961a998e9 sim/v850/simops.h
+61a55a15e7ef4e104adb33aaa7f55b66 sim/v850/v850-dc
+42de87877c720a7cd8995343b08d549d sim/v850/v850.igen
+ec996f52079c4afb02cb86bdd2fd188f sim/v850/v850_sim.h
+5df75b029b7d11dbf2a51b9db06a5f73 sim/z8k/ChangeLog
+faadde8183eda0d559355f657629b68a sim/z8k/Makefile.in
+c277414b921bc85437478d47aa2ff522 sim/z8k/acconfig.h
+d364e878ba599e906e2853a08b98d8a6 sim/z8k/comped1.c
+9c799b41905ed7c5d0cfae2459460b9a sim/z8k/comped2.c
+94d11974a649742abd5ecc2b858349a0 sim/z8k/comped3.c
+6c3a315eb92e8aff644d8bbf7a37f20c sim/z8k/compedb3.c
+a95a70664e413801a597fa28256576f9 sim/z8k/config.in
+8a49a1c85c9396bc86c99d065816d8a1 sim/z8k/configure
+b45960de07956b3c81ae57be85df9a7f sim/z8k/configure.in
+5f389e133935b7e2861258cb13ad9d8f sim/z8k/iface.c
+e0a7f1a5307479cfd2aaf1636797b4d1 sim/z8k/inlines.h
+987ebce1db18d972c3ec54932fa4dfec sim/z8k/mem.c
+c4853bc5877f542f6cbd6faca324fdc8 sim/z8k/mem.h
+ff528a4e4622b0cdd7a063d2c700da80 sim/z8k/quick.c
+a9976641e44d799afcf81c16c8a51aeb sim/z8k/sim.h
+0db0b761c5d2d2a3c88f26fcd128f783 sim/z8k/support.c
+ad0459fe42ddc739f638464c2e247a30 sim/z8k/syscall.h
+1b9ee9eab7ed5ca759bce92d8c328ab3 sim/z8k/tconfig.in
+96aa639f2f92f44e518dd98789cc024c sim/z8k/tm.h
+57df594ab355b7927903348b3e82285a sim/z8k/writecode.c
+70672a8bf938cfcb57c23c528341ab88 src-release
+e8b74bd777dcff9aa7eaff1cff0208f7 symlink-tree
+b97f1c282c19b00608b1680ad02ae227 texinfo/texinfo.tex
+05b44465f4af35156e0c7a8488e81a26 utils/ChangeLog
+77c78f52a1a36f45522d1ca8abe2d20f utils/Makefile.def
+89fd5f3c7be25e891dc0b8e421194f5c utils/Makefile.in
+f310368ddfe659241ee0a9521987e2d2 utils/Makefile.tpl
+098272ad15083d8dfe61063a7806718b utils/configure
+9303c3616d18758b7ea724270d75b842 utils/configure.in
+a6c3ed07cc948867dda4df4b54ac95c7 utils/misc/Makefile.in
+725839ceb46028560086f2838a0bd721 utils/misc/configure.in
+1713db4c79349e46bb17ce622b0a4391 utils/misc/doschk/ChangeLog
+b073a668d04466111b835be54a70f94d utils/misc/doschk/Makefile.in
+856cd577c4065b6a88bfe22b972f369c utils/misc/doschk/README
+8f92e4be8aa509042df8306472702b4a utils/misc/doschk/configure
+6d789396da7ce75cf11c71652cc2527e utils/misc/doschk/configure.in
+4b947c6ce6448071cd34af078be1bf38 utils/misc/doschk/doschk.c
+074fc3e1b6f02aa19f2b2a5000a6c80a utils/sparclite/ChangeLog
+a7eab8e0f7767eb222535d3b2be6cb98 utils/sparclite/Makefile.in
+cf263682d341fd6fc4ec46522ef82918 utils/sparclite/README
+a0d6d909da1925163b08e0c5903f2ac8 utils/sparclite/aload.c
+9835dec4cf0cea9d3bdcfc2bcb2842aa utils/sparclite/configure
+2e793a5a9ee3ead3235d3fd0597f3025 utils/sparclite/configure.in
+0666e31023bf6c528ffc76d10d5e76ec utils/sparclite/eload.c
+1332cd1f56dbc282007e210a4604a314 utils/sparclite/Makefile
+42a5e31a79435eb362018fa564cd9751 utils/sparclite/config.status
+43004c6e4ddfd3c408c5edc905c470b2 utils/spu/ChangeLog
+d40779a37117b757874d8e683178f55b utils/spu/Makefile.in
+70c7d7e8a8e7afce3c0e579af2b00a1e utils/spu/README
+8266b864db4e3050a104f9d7e89e4509 utils/spu/configure
+325f4f18f23ec8f6ee7592f9d62e5687 utils/spu/configure.in
+57e4dc6faccea960276253043ef8f777 utils/spu/spu.c
+e9b8f681b1d1ee9fae2602f84d81f737 utils/wince/ChangeLog
+17009faf740fe6a6c16cd11e6e850c75 utils/wince/Makefile.in
+beab589fc6063ab45deaec34a4545995 utils/wince/cesetup.c
+5ffb0d64070cd6e985ad40841c497c5c utils/wince/configure
+d26d2917a7be8a0b4afded813cca167f utils/wince/configure.in
+fed14eeefb89ace86cef8e5bb5ddc3c3 utils/wince/config.status
+5549a1e050058444e22fbb0a80fd32f0 utils/wince/Makefile
+7588c5103af27cc93537977f059f52dc ylwrap
diff --git a/contrib/gdb/missing b/contrib/gdb/missing
new file mode 100755
index 0000000..25c9667
--- /dev/null
+++ b/contrib/gdb/missing
@@ -0,0 +1,336 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing 0.4 - GNU automake"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+ # We have makeinfo, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ fi
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/contrib/gdb/mkinstalldirs b/contrib/gdb/mkinstalldirs
new file mode 100755
index 0000000..6fbe5e1
--- /dev/null
+++ b/contrib/gdb/mkinstalldirs
@@ -0,0 +1,150 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+
+scriptversion=2004-02-15.20
+
+# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain.
+#
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+errstatus=0
+dirmode=""
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
+
+Create each directory DIR (with mode MODE, if specified), including all
+leading file name components.
+
+Report bugs to <bug-automake@gnu.org>."
+
+# process command line arguments
+while test $# -gt 0 ; do
+ case $1 in
+ -h | --help | --h*) # -h for help
+ echo "$usage"
+ exit 0
+ ;;
+ -m) # -m PERM arg
+ shift
+ test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+ dirmode=$1
+ shift
+ ;;
+ --version)
+ echo "$0 $scriptversion"
+ exit 0
+ ;;
+ --) # stop option processing
+ shift
+ break
+ ;;
+ -*) # unknown option
+ echo "$usage" 1>&2
+ exit 1
+ ;;
+ *) # first non-opt arg
+ break
+ ;;
+ esac
+done
+
+for file
+do
+ if test -d "$file"; then
+ shift
+ else
+ break
+ fi
+done
+
+case $# in
+ 0) exit 0 ;;
+esac
+
+# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and
+# mkdir -p a/c at the same time, both will detect that a is missing,
+# one will create a, then the other will try to create a and die with
+# a "File exists" error. This is a problem when calling mkinstalldirs
+# from a parallel make. We use --version in the probe to restrict
+# ourselves to GNU mkdir, which is thread-safe.
+case $dirmode in
+ '')
+ if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ echo "mkdir -p -- $*"
+ exec mkdir -p -- "$@"
+ else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ test -d ./-p && rmdir ./-p
+ test -d ./--version && rmdir ./--version
+ fi
+ ;;
+ *)
+ if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
+ test ! -d ./--version; then
+ echo "mkdir -m $dirmode -p -- $*"
+ exec mkdir -m "$dirmode" -p -- "$@"
+ else
+ # Clean up after NextStep and OpenStep mkdir.
+ for d in ./-m ./-p ./--version "./$dirmode";
+ do
+ test -d $d && rmdir $d
+ done
+ fi
+ ;;
+esac
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case $pathcomp in
+ -*) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ else
+ if test ! -z "$dirmode"; then
+ echo "chmod $dirmode $pathcomp"
+ lasterr=""
+ chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+ if test ! -z "$lasterr"; then
+ errstatus=$lasterr
+ fi
+ fi
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/contrib/gdb/move-if-change b/contrib/gdb/move-if-change
new file mode 100755
index 0000000..ee1b348
--- /dev/null
+++ b/contrib/gdb/move-if-change
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Copyright (C) 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+if
+test -r $2
+then
+if
+cmp $1 $2 > /dev/null
+then
+echo $2 is unchanged
+rm -f $1
+else
+mv -f $1 $2
+fi
+else
+mv -f $1 $2
+fi
diff --git a/contrib/gdb/src-release b/contrib/gdb/src-release
new file mode 100644
index 0000000..42d5c20
--- /dev/null
+++ b/contrib/gdb/src-release
@@ -0,0 +1,336 @@
+# Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+# 1999, 2000, 2001, 2002, 2003, 2004 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.
+#
+
+# This Makefile contains release scripts for gdb, binutils, and other
+# packages which live in src. It used to be part of the top level Makefile,
+# but that turned out to be very messy and hard to maintain.
+
+# This stuff really ought to be cleaned up and turned into something other
+# than a Makefile. As it is it's heavily recursive.
+
+# This is the name of this script (!). Needed due to horrible recursion.
+SELF = src-release
+
+SHELL = /bin/sh
+
+BZIPPROG = bzip2
+MD5PROG = md5sum
+
+# pwd command to use. Allow user to override default by setting PWDCMD in
+# the environment to account for automounters. The make variable must not
+# be called PWDCMD, otherwise the value set here is passed to make
+# subprocesses and overrides the setting from the user's environment.
+PWD = $${PWDCMD-pwd}
+
+#
+# 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.if config.sub config move-if-change \
+ COPYING COPYING.LIB install-sh config-ml.in symlink-tree \
+ mkinstalldirs ltconfig ltmain.sh missing ylwrap \
+ libtool.m4 gettext.m4 ltcf-c.sh ltcf-cxx.sh ltcf-gcj.sh \
+ Makefile.def Makefile.tpl src-release
+
+# 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 configure configure.in standards.texi \
+ make-stds.texi standards.info* configure.texi configure.info* \
+ configbuild.* configdev.* fdl.texi texi2pod.pl
+
+
+# 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
+
+# NOTE: No double quotes in the below. It is used within shell script
+# as VER="$(VER)"
+VER = ` if grep 'AM_INIT_AUTOMAKE.*BFD_VERSION' $(TOOL)/configure.in >/dev/null 2>&1; then \
+ sed < bfd/configure.in -n 's/AM_INIT_AUTOMAKE[^,]*, *\([^)]*\))/\1/p'; \
+ elif grep AM_INIT_AUTOMAKE $(TOOL)/configure.in >/dev/null 2>&1; then \
+ sed < $(TOOL)/configure.in -n 's/AM_INIT_AUTOMAKE[^,]*, *\([^)]*\))/\1/p'; \
+ elif test -f $(TOOL)/version.in; then \
+ head -1 $(TOOL)/version.in; \
+ elif grep VERSION $(TOOL)/Makefile.in > /dev/null 2>&1; then \
+ sed < $(TOOL)/Makefile.in -n 's/^VERSION *= *//p'; \
+ else \
+ echo VERSION; \
+ fi`
+PACKAGE = $(TOOL)
+
+.PHONY: taz
+taz: $(DEVO_SUPPORT) $(SUPPORT_FILES) texinfo/texinfo.tex
+ $(MAKE) -f $(SELF) do-proto-toplev \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-md5sum \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-tar \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-bz2 \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+
+.PHONY: gdb-tar
+gdb-tar: $(DEVO_SUPPORT) $(SUPPORT_FILES) texinfo/texinfo.tex
+ $(MAKE) -f $(SELF) do-proto-toplev \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-md5sum \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-djunpack \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-tar \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+
+.PHONY: gdb-taz
+gdb-taz: gdb-tar $(DEVO_SUPPORT) $(SUPPORT_FILES) texinfo/texinfo.tex
+ $(MAKE) -f $(SELF) gdb-tar \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-bz2 \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+
+.PHONY: do-proto-toplev
+do-proto-toplev: $(DEVO_SUPPORT) $(SUPPORT_FILES) texinfo/texinfo.tex
+ echo "==> Making $(PACKAGE)-$(VER)/"
+ # Take out texinfo from a few places.
+ sed -e '/^all\.normal: /s/\all-texinfo //' \
+ -e '/^ install-texinfo /d' \
+ <Makefile.in >tmp
+ mv -f tmp Makefile.in
+ #
+ ./configure i686-pc-linux-gnu
+ $(MAKE) configure-host configure-target \
+ ALL_GCC="" ALL_GCC_C="" ALL_GCC_CXX="" \
+ 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
+ # Kludge for pr gdb/708. 'configure' configures in
+ # dejagnu/example/calc, but 'make distclean' does not clean in
+ # dejagnu/example. Someday somebody might fix this in dejagnu,
+ # and then import a new dejagnu into sourceware. Right now, a
+ # couple of 'rm' commands will get the gdb snapshots working
+ # again. -- chastain 2003-08-15
+ rm -f dejagnu/example/calc/config.status
+ rm -f dejagnu/example/calc/config.log
+ # Kludge for pr gdb/857. intl/Makefile.in lacks a couple
+ # of files in the distclean rule. Zack W is planning to make
+ # the gcc version of intl/ the master version and then push
+ # that version to src soon. See:
+ # http://sources.redhat.com/ml/binutils/2003-07/msg00032.html
+ # After the src version of intl/ is upgraded, we can look at
+ # moving this logic into intl/Makefile.in distclean rule
+ # if it is still needed. -- chastain 2003-09-12
+ rm -f intl/config.cache
+ rm -f intl/config.status
+ rm -f intl/config.h
+ rm -f intl/stamp-h
+ #
+ 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 //' \
+ <configure.in >proto-toplev/configure.in
+ #
+ mkdir proto-toplev/texinfo
+ ln -s ../../texinfo/texinfo.tex proto-toplev/texinfo/
+ if test -r texinfo/util/tex3patch ; then \
+ mkdir proto-toplev/texinfo/util && \
+ ln -s ../../../texinfo/util/tex3patch proto-toplev/texinfo/util ; \
+ else true; fi
+ chmod -R og=u . || chmod og=u `find . -print`
+ #
+ # Create .gmo files from .po files.
+ for f in `find . -name '*.po' -type f -print`; do \
+ msgfmt -o `echo $$f | sed -e 's/\.po$$/.gmo/'` $$f ; \
+ done
+ #
+ -rm -f $(PACKAGE)-$(VER)
+ ln -s proto-toplev $(PACKAGE)-$(VER)
+
+CVS_NAMES= \( -name CVS -o -name '.cvsignore' \)
+
+.PHONY: do-tar
+do-tar:
+ echo "==> Making $(PACKAGE)-$(VER).tar"
+ -rm -f $(PACKAGE)-$(VER).tar
+ find $(PACKAGE)-$(VER) -follow $(CVS_NAMES) -prune \
+ -o -type f -print \
+ | tar cTfh - $(PACKAGE)-$(VER).tar
+
+.PHONY: do-bz2
+do-bz2:
+ echo "==> Bzipping $(PACKAGE)-$(VER).tar.bz2"
+ -rm -f $(PACKAGE)-$(VER).tar.bz2
+ $(BZIPPROG) -v -9 $(PACKAGE)-$(VER).tar
+
+.PHONY: do-md5sum
+do-md5sum:
+ echo "==> Adding md5 checksum to top-level directory"
+ cd proto-toplev && find * -follow $(CVS_NAMES) -prune \
+ -o -type f -print \
+ | xargs $(MD5PROG) > ../md5.sum
+ mv md5.sum proto-toplev
+
+.PHONY: do-djunpack
+do-djunpack:
+ echo "==> Adding updated djunpack.bat to top-level directory"
+ echo - 's /gdb-[0-9\.]*/$(PACKAGE)-'"$(VER)"'/'
+ sed < djunpack.bat > djunpack.new \
+ -e 's/gdb-[0-9][0-9\.]*/$(PACKAGE)-'"$(VER)"'/'
+ mv djunpack.new djunpack.bat
+ -rm -f proto-toplev/djunpack.bat
+ ln -s ../djunpack.bat proto-toplev/djunpack.bat
+
+TEXINFO_SUPPORT= texinfo/texinfo.tex
+DIST_SUPPORT= $(DEVO_SUPPORT) $(TEXINFO_SUPPORT)
+
+.PHONY: gas.tar.bz2
+GAS_SUPPORT_DIRS= bfd include libiberty opcodes intl setup.com makefile.vms mkdep
+gas.tar.bz2: $(DIST_SUPPORT) $(GAS_SUPPORT_DIRS) gas
+ $(MAKE) -f $(SELF) taz TOOL=gas \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GAS_SUPPORT_DIRS)"
+
+# The FSF "binutils" release includes gprof and ld.
+.PHONY: binutils.tar.bz2
+BINUTILS_SUPPORT_DIRS= bfd gas include libiberty opcodes ld gprof intl setup.com makefile.vms mkdep cpu
+binutils.tar.bz2: $(DIST_SUPPORT) $(BINUTILS_SUPPORT_DIRS) binutils
+ $(MAKE) -f $(SELF) taz TOOL=binutils \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(BINUTILS_SUPPORT_DIRS)"
+
+.PHONY: gas+binutils.tar.bz2
+GASB_SUPPORT_DIRS= $(GAS_SUPPORT_DIRS) binutils ld gprof
+gas+binutils.tar.bz2: $(DIST_SUPPORT) $(GASB_SUPPORT_DIRS) gas
+ $(MAKE) -f $(SELF) taz TOOL=gas \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GASB_SUPPORT_DIRS)"
+
+GNATS_SUPPORT_DIRS=include libiberty send-pr
+gnats.tar.bz2: $(DIST_SUPPORT) $(GNATS_SUPPORT_DIRS) gnats
+ $(MAKE) -f $(SELF) taz TOOL=gnats \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GNATS_SUPPORT_DIRS)"
+
+.PHONY: gdb.tar.bz2
+GDB_SUPPORT_DIRS= bfd include libiberty mmalloc opcodes readline sim utils intl
+gdb.tar.bz2: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-taz TOOL=gdb \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GDB_SUPPORT_DIRS)"
+.PHONY: gdb.tar
+gdb.tar: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-tar TOOL=gdb \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GDB_SUPPORT_DIRS)"
+
+DEJAGNU_SUPPORT_DIRS= tcl expect libiberty
+.PHONY: dejagnu.tar.bz2
+dejagnu.tar.bz2: $(DIST_SUPPORT) $(DEJAGNU_SUPPORT_DIRS) dejagnu
+ $(MAKE) -f $(SELF) gdb-taz TOOL=dejagnu \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(DEJAGNU_SUPPORT_DIRS)"
+.PHONY: dejagnu.tar
+dejagnu.tar: $(DIST_SUPPORT) $(DEJAGNU_SUPPORT_DIRS) dejagnu
+ $(MAKE) -f $(SELF) gdb-tar TOOL=dejagnu \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(DEJAGNU_SUPPORT_DIRS)"
+
+.PHONY: gdb+dejagnu.tar.bz2
+GDBD_SUPPORT_DIRS= $(GDB_SUPPORT_DIRS) tcl expect dejagnu
+gdb+dejagnu.tar.bz2: $(DIST_SUPPORT) $(GDBD_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-taz TOOL=gdb PACKAGE=gdb+dejagnu \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GDBD_SUPPORT_DIRS)"
+.PHONY: gdb+dejagnu.tar
+gdb+dejagnu.tar: $(DIST_SUPPORT) $(GDBD_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-tar TOOL=gdb PACKAGE=gdb+dejagnu \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GDBD_SUPPORT_DIRS)"
+
+.PHONY: insight.tar.bz2
+INSIGHT_SUPPORT_DIRS= $(GDB_SUPPORT_DIRS) tcl tk itcl tix libgui
+insight.tar.bz2: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-taz TOOL=gdb PACKAGE=insight \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(INSIGHT_SUPPORT_DIRS)"
+.PHONY: insight.tar
+insight.tar: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-tar TOOL=gdb PACKAGE=insight \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(INSIGHT_SUPPORT_DIRS)"
+
+.PHONY: insight+dejagnu.tar.bz2
+INSIGHTD_SUPPORT_DIRS= $(INSIGHT_SUPPORT_DIRS) expect dejagnu
+insight+dejagnu.tar.bz2: $(DIST_SUPPORT) $(INSIGHTD_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-taz TOOL=gdb PACKAGE="insight+dejagnu" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(INSIGHTD_SUPPORT_DIRS)"
+.PHONY: insight+dejagnu.tar
+insight+dejagnu.tar: $(DIST_SUPPORT) $(INSIGHTD_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-tar TOOL=gdb PACKAGE="insight+dejagnu" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(INSIGHTD_SUPPORT_DIRS)"
+
+.NOEXPORT:
+MAKEOVERRIDES=
diff --git a/contrib/gdb/symlink-tree b/contrib/gdb/symlink-tree
new file mode 100755
index 0000000..22132c7
--- /dev/null
+++ b/contrib/gdb/symlink-tree
@@ -0,0 +1,78 @@
+#!/bin/sh
+# Create a symlink tree.
+#
+# Copyright (C) 1995, 2000, 2003 Free Software Foundation, Inc.
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+#
+# Please report bugs to <gcc-bugs@gnu.org>
+# and send patches to <gcc-patches@gnu.org>.
+
+# Syntax: symlink-tree srcdir "ignore1 ignore2 ..."
+#
+# where srcdir is the directory to create a symlink tree to,
+# and "ignoreN" is a list of files/directories to ignore.
+
+prog=$0
+srcdir=$1
+ignore="$2"
+
+if test $# -lt 1; then
+ echo "symlink-tree error: Usage: symlink-tree srcdir \"ignore1 ignore2 ...\""
+ exit 1
+fi
+
+ignore_additional=". .. CVS"
+
+# If we were invoked with a relative path name, adjust ${prog} to work
+# in subdirs.
+case ${prog} in
+/* | [A-Za-z]:[\\/]*) ;;
+*) prog=../${prog} ;;
+esac
+
+# Set newsrcdir to something subdirectories can use.
+case ${srcdir} in
+/* | [A-Za-z]:[\\/]*) newsrcdir=${srcdir} ;;
+*) newsrcdir=../${srcdir} ;;
+esac
+
+for f in `ls -a ${srcdir}`; do
+ if [ -d ${srcdir}/$f ]; then
+ found=
+ for i in ${ignore} ${ignore_additional}; do
+ if [ "$f" = "$i" ]; then
+ found=yes
+ fi
+ done
+ if [ -z "${found}" ]; then
+ echo "$f ..working in"
+ if [ -d $f ]; then true; else mkdir $f; fi
+ (cd $f; ${prog} ${newsrcdir}/$f "${ignore}")
+ fi
+ else
+ echo "$f ..linked"
+ rm -f $f
+ ln -s ${srcdir}/$f .
+ fi
+done
+
+exit 0
diff --git a/contrib/gdb/ylwrap b/contrib/gdb/ylwrap
new file mode 100755
index 0000000..2288ccd
--- /dev/null
+++ b/contrib/gdb/ylwrap
@@ -0,0 +1,123 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@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, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Usage:
+# ylwrap PROGRAM INPUT [OUTPUT DESIRED]... -- [ARGS]...
+# * PROGRAM is program to run.
+# * INPUT is the input file
+# * OUTPUT is file PROG generates
+# * DESIRED is file we actually want
+# * ARGS are passed to PROG
+# Any number of OUTPUT,DESIRED pairs may be used.
+
+# The program to run.
+prog="$1"
+shift
+# Make any relative path in $prog absolute.
+case "$prog" in
+ /* | [A-Za-z]:\\*) ;;
+ */*) prog="`pwd`/$prog" ;;
+esac
+
+# The input.
+input="$1"
+shift
+case "$input" in
+ /* | [A-Za-z]:\\*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Relative path. Make it absolute. Why? Because otherwise any
+ # debugging info in the generated file will point to the wrong
+ # place. This is really gross.
+ input="`pwd`/$input"
+ ;;
+esac
+
+# We don't want to use the absolute path if the input in the current
+# directory like when making a tar ball.
+input_base=`echo $input | sed -e 's|.*/||'`
+if test -f $input_base && cmp $input_base $input >/dev/null 2>&1; then
+ input=$input_base
+fi
+
+pairlist=
+while test "$#" -ne 0; do
+ if test "$1" = "--"; then
+ shift
+ break
+ fi
+ pairlist="$pairlist $1"
+ shift
+done
+
+# FIXME: add hostname here for parallel makes that run commands on
+# other machines. But that might take us over the 14-char limit.
+dirname=ylwrap$$
+trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15
+mkdir $dirname || exit 1
+
+cd $dirname
+case "$input" in
+ /* | [A-Za-z]:\\*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Make a symbolic link, hard link or hardcopy.
+ ln -s ../"$input" . > /dev/null 2>&1 || ln ../"$input" . > /dev/null 2>&1 || cp ../"$input" .
+ ;;
+esac
+$prog ${1+"$@"} "$input"
+status=$?
+
+if test $status -eq 0; then
+ set X $pairlist
+ shift
+ first=yes
+ while test "$#" -ne 0; do
+ if test -f "$1"; then
+ # If $2 is an absolute path name, then just use that,
+ # otherwise prepend `../'.
+ case "$2" in
+ /* | [A-Za-z]:\\*) target="$2";;
+ *) target="../$2";;
+ esac
+ mv "$1" "$target" || status=$?
+ else
+ # A missing file is only an error for the first file. This
+ # is a blatant hack to let us support using "yacc -d". If -d
+ # is not specified, we don't want an error when the header
+ # file is "missing".
+ if test $first = yes; then
+ status=1
+ fi
+ fi
+ shift
+ shift
+ first=no
+ done
+else
+ status=$?
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $status
OpenPOWER on IntegriCloud